diff --git a/.ci/merge-fixes.sh b/.ci/merge-fixes.sh new file mode 100755 index 00000000000..1fb8267df0e --- /dev/null +++ b/.ci/merge-fixes.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# Merge open PRs from sagemath/sage labeled "blocker". +REPO="sagemath/sage" +GH="gh -R $REPO" +PRs="$($GH pr list --label "p: blocker / 1" --json number --jq '.[].number')" +if [ -z "$PRs" ]; then + echo 'Nothing to do: Found no open PRs with "blocker" status.' +else + echo "Found PRs: " $PRs + export GIT_AUTHOR_NAME="ci-sage workflow" + export GIT_AUTHOR_EMAIL="ci-sage@example.com" + export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME" + export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL" + git tag -f test_base + git commit -q -m "Uncommitted changes" --no-allow-empty -a + for a in $PRs; do + echo "::group::Merging PR https://github.com/$REPO/pull/$a" + git tag -f test_head + $GH pr checkout -b pr-$a $a + git fetch --unshallow --all + git checkout -q test_head + if git merge --no-edit --squash -q pr-$a; then + echo "::endgroup::" + if git commit -q -m "Merge https://github.com/$REPO/pull/$a" -a --no-allow-empty; then + echo "Merged #$a" + else + echo "Empty, skipped" + fi + else + echo "::endgroup::" + echo "Failure merging #$a, resetting" + git reset --hard + fi + done + git log test_base..HEAD +fi diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 00000000000..1da1161f548 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,19 @@ +# https://docs.codecov.com/docs/pull-request-comments#disable-comment +comment: false +# https://docs.codecov.com/docs/codecovyml-reference#codecov +codecov: + require_ci_to_pass: false +# https://docs.codecov.com/docs/commit-status +coverage: + status: + project: + default: + target: auto + threshold: 0% + base: auto + informational: true + patch: + default: + target: auto + threshold: 0% + base: auto diff --git a/.devcontainer/portability-Dockerfile b/.devcontainer/portability-Dockerfile index 532a1854258..777c6b178d5 100644 --- a/.devcontainer/portability-Dockerfile +++ b/.devcontainer/portability-Dockerfile @@ -5,4 +5,4 @@ ARG SYSTEM_FACTOR="ubuntu-jammy" ARG PACKAGE_FACTOR="standard" ARG DOCKER_TARGET="with-system-packages" ARG DOCKER_TAG="dev" -FROM ghcr.io/sagemath/sage/sage-docker-${SYSTEM_FACTOR}-${PACKAGE_FACTOR}-${DOCKER_TARGET}:${DOCKER_TAG} +FROM ghcr.io/sagemath/sage/sage-${SYSTEM_FACTOR}-${PACKAGE_FACTOR}-${DOCKER_TARGET}:${DOCKER_TAG} diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f4ce719dcb8..3d69721d33b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -3,33 +3,11 @@ description: Report a bug title: "" labels: "t: bug" body: - - type: checkboxes - attributes: - label: Is there an existing issue for this? - description: Please search to see if an issue already exists for the bug you encountered. - options: - - label: I have searched the existing issues for a bug report that matches the one I want to file, without success. - required: true - - type: checkboxes - attributes: - label: Did you read the documentation and troubleshoot guide? - description: Please read [README.md](https://github.com/sagemath/sage/blob/develop/README.md) and [the Troubleshooting section in the Installation Guide](https://doc.sagemath.org/html/en/installation/troubles.html). - options: - - label: I have read the documentation and troubleshoot guide - required: true - - type: textarea + - type: markdown attributes: - label: Environment - description: | - examples: - - **OS**: Ubuntu 20.04 - - Sage Version: 9.2 value: | - - **OS**: - - **Sage Version**: - render: markdown - validations: - required: true + * Please search to see if an issue already exists for the bug you encountered. + * Please read [README.md](https://github.com/sagemath/sage/blob/develop/README.md) and [the Troubleshooting section in the Installation Guide](https://doc.sagemath.org/html/en/installation/troubles.html). - type: textarea attributes: label: Steps To Reproduce @@ -60,3 +38,24 @@ body: Links? References? Anything that will give us more context about the issue you are encountering! validations: required: false + - type: textarea + attributes: + label: Environment + description: | + examples: + - **OS**: Ubuntu 20.04 + - Sage Version: 9.2 + value: | + - **OS**: + - **Sage Version**: + render: markdown + validations: + required: true + - type: checkboxes + attributes: + label: Checklist + options: + - label: I have searched the existing issues for a bug report that matches the one I want to file, without success. + required: true + - label: I have read the documentation and troubleshoot guide + required: true diff --git a/.github/ISSUE_TEMPLATE/failure_building_from_source.yml b/.github/ISSUE_TEMPLATE/failure_building_from_source.yml index afe651bf14d..2575f5c9a10 100644 --- a/.github/ISSUE_TEMPLATE/failure_building_from_source.yml +++ b/.github/ISSUE_TEMPLATE/failure_building_from_source.yml @@ -4,20 +4,11 @@ title: "<title>" labels: ['c: build', 't: bug'] assignees: [] body: - - type: checkboxes + - type: markdown attributes: - label: Is there an existing issue for this? - description: Please search to see if an issue already exists for the bug you encountered. - options: - - label: I have searched the existing issues for a bug report that matches the one I want to file, without success. - required: true - - type: checkboxes - attributes: - label: Did you read the documentation and troubleshoot guide? - description: Please read [README.md](https://github.com/sagemath/sage/blob/develop/README.md) and [the Troubleshooting sectionin the Installation Guide](https://doc.sagemath.org/html/en/installation/troubles.html). - options: - - label: I have read the documentation and troubleshoot guide - required: true + value: | + * Please search to see if an issue already exists for the bug you encountered. + * Please read [README.md](https://github.com/sagemath/sage/blob/develop/README.md) and [the Troubleshooting section in the Installation Guide](https://doc.sagemath.org/html/en/installation/troubles.html). - type: textarea attributes: label: Environment @@ -65,3 +56,11 @@ body: Links? References? Anything that will give us more context about the issue you are encountering! validations: required: false + - type: checkboxes + attributes: + label: Checklist + options: + - label: I have searched the existing issues for a bug report that matches the one I want to file, without success. + required: true + - label: I have read the documentation and troubleshoot guide + required: true diff --git a/.github/ISSUE_TEMPLATE/feature_report.yml b/.github/ISSUE_TEMPLATE/feature_report.yml index 5505a45143a..9f291204fd3 100644 --- a/.github/ISSUE_TEMPLATE/feature_report.yml +++ b/.github/ISSUE_TEMPLATE/feature_report.yml @@ -3,13 +3,10 @@ description: Suggest an idea title: "<title>" labels: "t: enhancement" body: - - type: checkboxes + - type: markdown attributes: - label: Is there an existing issue for this? - description: Please search to see if an issue already exists for the bug you encountered. - options: - - label: I have searched the existing issues for a bug report that matches the one I want to file, without success. - required: true + value: | + * Please search to see if an issue already exists for the bug you encountered. - type: textarea attributes: label: Problem Description @@ -34,3 +31,9 @@ body: description: Add any other context about the problem here. validations: required: false + - type: checkboxes + attributes: + label: Is there an existing issue for this? + options: + - label: I have searched the existing issues for a bug report that matches the one I want to file, without success. + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0ba5857b820..40283ac39fe 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,27 +3,30 @@ Please provide a concise, informative and self-explanatory title. Don't put issue numbers in there, do this in the PR body below. For example, instead of "Fixes #1234" use "Introduce new method to calculate 1+1" --> -### ๐Ÿ“š Description - <!-- Describe your changes here in detail --> + <!-- Why is this change required? What problem does it solve? --> -<!-- If it resolves an open issue, please link to the issue here. For example "Closes #1337" --> +<!-- If this PR resolves an open issue, please link to it here. For example "Fixes #12345". --> +<!-- If your change requires a documentation PR, please link it appropriately. --> -### ๐Ÿ“ Checklist +### :memo: Checklist <!-- Put an `x` in all the boxes that apply. --> <!-- If your change requires a documentation PR, please link it appropriately --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> +<!-- Feel free to remove irrelevant items. --> -- [ ] I have made sure that the title is self-explanatory and the description concisely explains the PR. -- [ ] I have linked an issue or discussion. +- [ ] The title is concise, informative, and self-explanatory. +- [ ] The description explains in detail what this PR is about. +- [ ] I have linked a relevant issue or discussion. - [ ] I have created tests covering the changes. - [ ] I have updated the documentation accordingly. -### โŒ› Dependencies -<!-- List all open pull requests that this PR logically depends on --> -<!-- -- #xyz: short description why this is a dependency -- #abc: ... +### :hourglass: Dependencies + +<!-- List all open PRs that this PR logically depends on +- #12345: short description why this is a dependency +- #34567: ... --> +<!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..a279ad0bda2 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +# Documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/sync_labels.py b/.github/sync_labels.py new file mode 100755 index 00000000000..799b4985c5d --- /dev/null +++ b/.github/sync_labels.py @@ -0,0 +1,903 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +r""" +Python script to sync status and priority labels. +For more information see https://github.com/sagemath/sage/pull/35172 +""" + +############################################################################## +# Copyright (C) 2023 Sebastian Oehms <seb.oehms@gmail.com> +# +# 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. +# http://www.gnu.org/licenses/ +############################################################################## + +import os +import sys +from logging import info, warning, debug, getLogger, INFO, DEBUG, WARNING +from json import loads +from enum import Enum +from datetime import datetime, timedelta +from subprocess import check_output, CalledProcessError + +datetime_format = '%Y-%m-%dT%H:%M:%SZ' + + +class Action(Enum): + r""" + Enum for GitHub event ``action``. + """ + opened = 'opened' + reopened = 'reopened' + closed = 'closed' + labeled = 'labeled' + unlabeled = 'unlabeled' + ready_for_review = 'ready_for_review' + synchronize = 'synchronize' + review_requested = 'review_requested' + converted_to_draft = 'converted_to_draft' + submitted = 'submitted' + +class RevState(Enum): + r""" + Enum for GitHub event ``review_state``. + """ + commented = 'commented' + approved = 'approved' + changes_requested = 'changes_requested' + +class ReviewDecision(Enum): + r""" + Enum for ``gh pr view`` results for ``reviewDecision``. + """ + changes_requested = 'CHANGES_REQUESTED' + approved = 'APPROVED' + unclear = 'UNCLEAR' + +class Priority(Enum): + r""" + Enum for priority labels. + """ + blocker = 'p: blocker /1' + critical = 'p: critical /2' + major = 'p: major /3' + minor = 'p: minor /4' + trivial = 'p: trivial /5' + +class State(Enum): + r""" + Enum for state labels. + """ + positive_review = 's: positive review' + needs_work = 's: needs work' + needs_review = 's: needs review' + needs_info = 's: needs info' + +class Resolution(Enum): + r""" + Enum for resolution labels. + """ + duplicate = 'r: duplicate' + invalid = 'r: invalid' + wontfix = 'r: wontfix' + worksforme = 'r: worksforme' + +def selection_list(label): + r""" + Return the selection list to which ``label`` belongs to. + """ + for sel_list in [Priority, State, Resolution]: + for item in sel_list: + if label == item.value: + return sel_list + return None + +class GhLabelSynchronizer: + r""" + Handler for access to GitHub issue via the ``gh`` in the bash command line + of the GitHub runner. + """ + def __init__(self, url, actor): + r""" + Python constructor sets the issue / PR url and list of active labels. + """ + self._url = url + self._actor = actor + self._warning_prefix = 'Label Sync Warning:' + self._labels = None + self._author = None + self._draft = None + self._open = None + self._review_decision = None + self._reviews = None + self._commits = None + self._commit_date = None + + number = os.path.basename(url) + self._pr = True + self._issue = 'pull request #%s' % number + if url.rfind('issue') != -1: + self._issue = 'issue #%s' % number + self._pr = False + info('Create label handler for %s and actor %s' % (self._issue, self._actor)) + self.clean_warnings() + + # ------------------------------------------------------------------------- + # methods to obtain properties of the issue + # ------------------------------------------------------------------------- + def is_pull_request(self): + r""" + Return if we are treating a pull request. + """ + return self._pr + + def reset_view(self): + r""" + Reset cache of ``gh view`` results. + """ + self._labels = None + self._author = None + self._draft = None + self._open = None + self._review_decision = None + self._reviews = None + self._commits = None + self._commit_date = None + + def rest_api(self, path_args, method=None, query=''): + r""" + Return data obtained from ``gh`` command ``api``. + """ + meth = '-X GET' + if method: + meth='-X %s' % method + cmd = 'gh api %s -H \"Accept: application/vnd.github+json\" %s %s' % (meth, path_args, query) + debug('Execute command: %s' % cmd) + if method: + return check_output(cmd, shell=True) + return loads(check_output(cmd, shell=True)) + + def view(self, key): + r""" + Return data obtained from ``gh`` command ``view``. + """ + issue = 'issue' + if self._pr: + issue = 'pr' + cmd = 'gh %s view %s --json %s' % (issue, self._url, key) + debug('Execute command: %s' % cmd) + return loads(check_output(cmd, shell=True))[key] + + def is_open(self): + r""" + Return ``True`` if the issue res. PR is open. + """ + if self._open is not None: + return self._open + if self.view('state') == 'OPEN': + self._open = True + else: + self._open = False + info('Issue %s is open %s' % (self._issue, self._open)) + return self._open + + def is_draft(self): + r""" + Return ``True`` if the PR is a draft. + """ + if self._draft is not None: + return self._draft + if self.is_pull_request(): + self._draft = self.view('isDraft') + else: + self._draft = False + info('Issue %s is draft %s' % (self._issue, self._draft)) + return self._draft + + def is_auth_team_member(self, login): + r""" + Return ``True`` if the user with given login belongs to an authorized + team. + """ + def verify_membership(team): + path_args = '/orgs/sagemath/teams/%s/memberships/%s' % (team, login) + try: + res = self.rest_api(path_args) + if res['state'] == 'active' and res['role'] == 'member': + info('User %s is a member of %s' % (login, team)) + return True + except CalledProcessError: + pass + + info('User %s is not a member of %s' % (login, team)) + return False + + # check for the Triage team + if verify_membership('triage'): + return True + + return False + + def actor_authorized(self): + r""" + Return ``True`` if the actor belongs to an authorized team. + """ + return self.is_auth_team_member(self._actor) + + def clean_warnings(self): + r""" + Remove all warnings that have been posted by ``GhLabelSynchronizer`` + more than ``warning_lifetime`` ago. + """ + warning_lifetime = timedelta(minutes=5) + time_frame = timedelta(minutes=730) # timedelta to search for comments including 10 minutes overlap with cron-cycle + per_page = 100 + today = datetime.today() + since = today - time_frame + query = '-F per_page=%s -F page={} -f since=%s' % (per_page, since.strftime(datetime_format)) + s = self._url.split('/') + owner = s[3] + repo = s[4] + path_args = '/repos/%s/%s/issues/comments' % (owner, repo) + page = 1 + comments = [] + while True: + comments_page = self.rest_api(path_args, query=query.format(page)) + comments += comments_page + if len(comments_page) < per_page: + break + page += 1 + + info('Cleaning warning comments since %s (total found %s)' % (since, len(comments))) + + for c in comments: + login = c['user']['login'] + body = c['body'] + comment_id = c['id'] + issue = c['issue_url'].split('/').pop() + created_at = c['created_at'] + if login.startswith('github-actions'): + debug('github-actions comment %s created at %s on issue %s found' % (comment_id, created_at, issue)) + if body.startswith(self._warning_prefix): + created = datetime.strptime(created_at, datetime_format) + lifetime = today - created + debug('github-actions %s %s is %s old' % (self._warning_prefix, comment_id, lifetime)) + if lifetime > warning_lifetime: + try: + self.rest_api('%s/%s' % (path_args, comment_id), method='DELETE') + info('Comment %s on issue %s deleted' % (comment_id, issue)) + except CalledProcessError: + # the comment may have been deleted by a bot running in parallel + info('Comment %s on issue %s has been deleted already' % (comment_id, issue)) + + def get_labels(self): + r""" + Return the list of labels of the issue resp. PR. + """ + if self._labels is not None: + return self._labels + data = self.view('labels') + self._labels = [l['name'] for l in data] + info('List of labels for %s: %s' % (self._issue, self._labels)) + return self._labels + + def get_author(self): + r""" + Return the author of the issue resp. PR. + """ + if self._author is not None: + return self._author + data = self.view('author') + self._author = self.view('author')['login'] + info('Author of %s: %s' % (self._issue, self._author)) + return self._author + + def get_commits(self): + r""" + Return the list of commits of the PR. + """ + if not self.is_pull_request(): + return None + + if self._commits is not None: + return self._commits + + self._commits = self.view('commits') + self._commit_date = max( com['committedDate'] for com in self._commits ) + info('Commits until %s for %s: %s' % (self._commit_date, self._issue, self._commits)) + return self._commits + + def get_review_decision(self): + r""" + Return the reviewDecision of the PR. + """ + if not self.is_pull_request(): + return None + + if self._review_decision is not None: + if self._review_decision == ReviewDecision.unclear: + return None + return self._review_decision + + data = self.view('reviewDecision') + if data: + self._review_decision = ReviewDecision(data) + else: + # To separate a not supplied value from not cached (see https://github.com/sagemath/sage/pull/36177#issuecomment-1704022893 ff) + self._review_decision = ReviewDecision.unclear + info('Review decision for %s: %s' % (self._issue, self._review_decision.value)) + return self._review_decision + + def get_reviews(self, complete=False): + r""" + Return the list of reviews of the PR. Per default only those proper reviews + are returned which have been submitted after the most recent commit. Use + keyword ``complete`` to get them all. + """ + if not self.is_pull_request(): + return None + + if self._reviews is None: + self._reviews = self.view('reviews') + debug('Reviews for %s: %s' % (self._issue, self._reviews)) + + if complete or not self._reviews: + return self._reviews + + if self._commit_date is None: + self.get_commits() + + date = self._commit_date + unproper_rev = RevState.commented.value + new_revs = [rev for rev in self._reviews if rev['submittedAt'] > date] + proper_new_revs = [rev for rev in new_revs if rev['state'] != unproper_rev] + info('Proper reviews after %s for %s: %s' % (date, self._issue, proper_new_revs)) + return proper_new_revs + + def active_partners(self, item): + r""" + Return the list of other labels from the selection list + of the given one that are already present on the issue / PR. + """ + sel_list = type(item) + partners = [i for i in sel_list if i != item and i.value in self.get_labels()] + info('Active partners of %s: %s' % (item, partners)) + return partners + + # ------------------------------------------------------------------------- + # methods to validate the issue state + # ------------------------------------------------------------------------- + def review_comment_to_state(self): + r""" + Return a State label if the most recent review comment + starts with its value. + """ + revs = self.get_reviews(complete=True) + date = max(rev['submittedAt'] for rev in revs) + + for rev in revs: + if rev['submittedAt'] == date: + for stat in State: + body = rev['body'] + if body.startswith(stat.value): + return stat + return None + + def needs_work_valid(self): + r""" + Return ``True`` if the PR needs work. This is the case if + there are reviews more recent than any commit and the review + decision requests changes or if there is any review reqesting + changes. + """ + revs = self.get_reviews() + if not revs: + # no proper review since most recent commit. + return False + + ch_req = ReviewDecision.changes_requested + rev_dec = self.get_review_decision() + if rev_dec: + if rev_dec == ch_req: + info('PR %s needs work (by decision)' % self._issue) + return True + else: + info('PR %s doesn\'t need work (by decision)' % self._issue) + return False + + if any(rev['state'] == ch_req.value for rev in revs): + info('PR %s needs work' % self._issue) + return True + info('PR %s doesn\'t need work' % self._issue) + return False + + def positive_review_valid(self): + r""" + Return ``True`` if the PR has positive review. This is the + case if there are reviews more recent than any commit and the + review decision is approved or if there is any approved review + but no changes requesting one. + """ + revs = self.get_reviews() + if not revs: + # no proper review since most recent commit. + return False + + appr = ReviewDecision.approved + rev_dec = self.get_review_decision() + if rev_dec: + if rev_dec == appr: + info('PR %s has positve review (by decision)' % self._issue) + return True + else: + info('PR %s doesn\'t have positve review (by decision)' % self._issue) + return False + + if all(rev['state'] == appr.value for rev in revs): + info('PR %s has positve review' % self._issue) + return True + info('PR %s doesn\'t have positve review' % self._issue) + return False + + def needs_review_valid(self): + r""" + Return ``True`` if the PR needs review. This is the case if + all proper reviews are older than the youngest commit. + """ + if self.is_draft(): + return False + + if self.needs_work_valid(): + info('PR %s already under review (needs work)' % self._issue) + return False + + if self.positive_review_valid(): + info('PR %s already reviewed' % self._issue) + return False + + info('PR %s needs review' % self._issue) + return True + + def approve_allowed(self): + r""" + Return if the actor has permission to approve this PR. + """ + revs = self.get_reviews() + revs = [rev for rev in revs if rev['author']['login'] != self._actor] + ch_req = ReviewDecision.changes_requested + if any(rev['state'] == ch_req.value for rev in revs): + info('PR %s can\'t be approved by %s since others reqest changes' % (self._issue, self._actor)) + return False + + return self.actor_valid() + + def actor_valid(self): + r""" + Return if the actor has permission to approve this PR. + """ + author = self.get_author() + + if author != self._actor: + info('PR %s can be approved by %s' % (self._issue, self._actor)) + return True + + revs = self.get_reviews() + revs = [rev for rev in revs if rev['author']['login'] != 'github-actions'] + if not revs: + info('PR %s can\'t be approved by the author %s since no other person reviewed it' % (self._issue, self._actor)) + return False + + coms = self.get_commits() + authors = sum(com['authors'] for com in coms) + authors = [auth for auth in authors if not auth['login'] in (self._actor, 'github-actions')] + if not authors: + info('PR %s can\'t be approved by the author %s since no other person commited to it' % (self._issue, self._actor)) + return False + + info('PR %s can be approved by the author %s as co-author' % (self._issue, self._actor)) + return True + + # ------------------------------------------------------------------------- + # methods to change the issue + # ------------------------------------------------------------------------- + def gh_cmd(self, cmd, arg, option): + r""" + Perform a system call to ``gh`` for ``cmd`` to an isuue resp. PR. + """ + issue = 'issue' + if self._pr: + issue = 'pr' + cmd_str = 'gh %s %s %s %s "%s"' % (issue, cmd, self._url, option, arg) + debug('Execute command: %s' % cmd_str) + ex_code = os.system(cmd_str) + if ex_code: + warning('Execution of %s failed with exit code: %s' % (cmd_str, ex_code)) + + def edit(self, arg, option): + r""" + Perform a system call to ``gh`` to edit an issue resp. PR. + """ + self.gh_cmd('edit', arg, option) + + def mark_as_ready(self): + r""" + Perform a system call to ``gh`` to mark a PR as ready for review. + """ + self.gh_cmd('ready', '', '') + + def review(self, arg, text): + r""" + Perform a system call to ``gh`` to review a PR. + """ + self.gh_cmd('review', arg, '-b \"%s\"' % text) + + def approve(self): + r""" + Approve the PR by the actor. + """ + self.review('--approve', '%s approved this PR' % self._actor) + info('PR %s approved by %s' % (self._issue, self._actor)) + + def request_changes(self): + r""" + Request changes for this PR by the actor. + """ + self.review('--request-changes', '%s requested changes for this PR' % self._actor) + info('Changes requested for PR %s by %s' % (self._issue, self._actor)) + + def review_comment(self, text): + r""" + Add a review comment. + """ + self.review('--comment', text) + info('Add review comment for PR %s: %s' % (self._issue, text)) + + def add_comment(self, text): + r""" + Perform a system call to ``gh`` to add a comment to an issue or PR. + """ + self.gh_cmd('comment', text, '-b') + info('Add comment to %s: %s' % (self._issue, text)) + + def add_warning(self, text): + r""" + Perform a system call to ``gh`` to add a warning to an issue or PR. + """ + self.add_comment('%s %s' % (self._warning_prefix, text)) + + def add_label(self, label): + r""" + Add the given label to the issue or PR. + """ + if not label in self.get_labels(): + self.edit(label, '--add-label') + info('Add label to %s: %s' % (self._issue, label)) + + def add_default_label(self, item): + r""" + Add the given label if there is no active partner. + """ + if not self.active_partners(item): + self.add_label(item.value) + + def select_label(self, item): + r""" + Add the given label and remove all others. + """ + self.add_label(item.value) + sel_list = type(item) + for other in sel_list: + if other != item: + self.remove_label(other.value) + + def remove_label(self, label): + r""" + Remove the given label from the issue or PR of the handler. + """ + if label in self.get_labels(): + self.edit(label, '--remove-label') + info('Remove label from %s: %s' % (self._issue, label)) + + def reject_label_addition(self, item): + r""" + Post a comment that the given label can not be added and select + a corresponding other one. + """ + if not self.is_pull_request(): + self.add_warning('Label *%s* can not be added to an issue. Please use it on the corresponding PR' % item.value) + elif item is State.needs_review: + self.add_warning('Label *%s* can not be added, since there are unresolved reviews' % item.value) + else: + self.add_warning('Label *%s* can not be added. Please use the GitHub review functionality' % item.value) + self.remove_label(item.value) + return + + def reject_label_removal(self, item): + r""" + Post a comment that the given label can not be removed and select + a corresponding other one. + """ + if type(item) == State: + sel_list = 'state' + else: + sel_list = 'priority' + self.add_warning('Label *%s* can not be removed. Please add the %s-label which should replace it' % (item.value, sel_list)) + self.add_label(item.value) + return + + # ------------------------------------------------------------------------- + # methods to act on events + # ------------------------------------------------------------------------- + def on_label_add(self, label): + r""" + Check if the given label belongs to a selection list. If so, remove + all other labels of that list. In case of a state label reviews are + booked accordingly. + """ + sel_list = selection_list(label) + if not sel_list: + return + + item = sel_list(label) + if label not in self.get_labels(): + # this is possible if two labels of the same selection list + # have been added in one step (via multiple selection in the + # pull down menue). In this case `label` has been removed + # on the `on_label_add` of the first of the two labels + partn = self.active_partners(item) + if partn: + self.add_warning('Label *%s* can not be added due to *%s*!' % (label, partn[0].value)) + else: + warning('Label %s of %s not found!' % (label, self._issue)) + return + + if sel_list is State: + if not self.is_pull_request(): + if item != State.needs_info: + self.reject_label_addition(item) + return + + if item == State.needs_review: + if self.needs_review_valid(): + # here we come for example after a sequence: + # needs review -> needs info -> needs review + pass + elif self.is_draft(): + self.mark_as_ready() + else: + self.reject_label_addition(item) + return + + if item == State.needs_work: + if self.needs_work_valid(): + # here we come for example after a sequence: + # needs work -> needs info -> needs work + pass + elif not self.is_draft(): + self.request_changes() + else: + self.reject_label_addition(item) + return + + if item == State.positive_review: + if self.positive_review_valid(): + # here we come for example after a sequence: + # positive review -> needs info -> positive review + pass + elif self.approve_allowed(): + self.approve() + else: + self.reject_label_addition(item) + return + + if sel_list is Resolution: + self.remove_all_labels_of_sel_list(Priority) + + for other in sel_list: + if other != item: + self.remove_label(other.value) + + def on_label_removal(self, label): + r""" + Check if the given label belongs to a selection list. If so, the + removement is rejected and a comment is posted to instead add a + replacement for ``label`` from the list. Exceptions are State labels + on issues and State.needs_info on a PR. + """ + sel_list = selection_list(label) + if not sel_list: + return + + item = sel_list(label) + if sel_list is State: + if self.is_pull_request(): + if item != State.needs_info: + self.reject_label_removal(item) + elif sel_list is Priority: + self.reject_label_removal(item) + return + + def on_review_comment(self): + r""" + Check if the text of the most recent review begins with a + specific label name. In this case, simulate the corresponding + label addition. This feature is needed for people who don't + have permission to add labels (i.e. aren't a member of the + Triage team). + """ + rev_state = self.review_comment_to_state() + if rev_state in (State.needs_info, State.needs_review): + self.select_label(rev_state) + self.run(Action.labeled, label=rev_state.value) + + def remove_all_labels_of_sel_list(self, sel_list): + r""" + Remove all labels of given selection list. + """ + for item in sel_list: + self.remove_label(item.value) + + def run(self, action, label=None, rev_state=None): + r""" + Run the given action. + """ + self.reset_view() # this is just needed for run_tests + + if action is Action.opened and self.is_pull_request(): + if not self.is_draft(): + self.add_default_label(State.needs_review) + + if action in (Action.closed, Action.reopened, Action.converted_to_draft): + self.remove_all_labels_of_sel_list(State) + + if action is Action.labeled: + self.on_label_add(label) + + if action is Action.unlabeled: + self.on_label_removal(label) + + if action in (Action.ready_for_review, Action.synchronize): + if self.needs_review_valid(): + self.select_label(State.needs_review) + + if action is Action.review_requested: + self.select_label(State.needs_review) + + if action is Action.submitted: + rev_state = RevState(rev_state) + if rev_state is RevState.approved: + if self.actor_authorized() and self.positive_review_valid(): + self.select_label(State.positive_review) + + if rev_state is RevState.changes_requested: + if self.needs_work_valid(): + self.select_label(State.needs_work) + + if rev_state is RevState.commented: + self.on_review_comment() + + def run_tests(self): + r""" + Simulative run over all posibble events. + + This is not intended to validate all functionality. It just + tests for bugs on invoking the methods. The result in the + issue or PR depends on timing. Note that the GitHub action runner + may run in parallel on the triggered events possibly on an other + version of the code. + """ + self.add_comment('Starting tests for sync_labels') + for action in Action: + self.add_comment('Test action %s' % action.value) + if action in (Action.labeled, Action.unlabeled): + for stat in State: + if action is Action.labeled: + self.add_label(stat.value) + else: + self.remove_label(stat.value) + self.run(action, label=stat.value) + for prio in Priority: + if action is Action.labeled: + self.add_label(prio.value) + else: + self.remove_label(prio.value) + self.run(action, label=prio.value) + res = Resolution.worksforme + if action is Action.labeled: + self.add_label(res.value) + self.run(action, label=prio.value) + elif action == Action.submitted and self.is_pull_request(): + for rev_stat in RevState: + if rev_stat is RevState.approved: + self.approve() + self.run(action, rev_state=rev_stat.value) + elif rev_stat is RevState.changes_requested: + self.request_changes() + self.run(action, rev_state=rev_stat.value) + elif rev_stat is RevState.commented: + for stat in State: + self.review_comment(stat.value) + self.run(action, rev_state=rev_stat.value) + elif self.is_pull_request(): + self.run(action) + + +############################################################################### +# Main +############################################################################### +last_arg = None +run_tests = False +default_actor = 'sagetrac-github-bot' +cmdline_args = sys.argv[1:] +num_args = len(cmdline_args) + +if num_args: + last_arg = cmdline_args[num_args-1] + +if last_arg in ('-t', '--test'): + getLogger().setLevel(DEBUG) + cmdline_args.pop() + run_tests = True +elif last_arg in ('-d', '--debug'): + getLogger().setLevel(DEBUG) + cmdline_args.pop() +elif last_arg in ('-i', '--info'): + getLogger().setLevel(INFO) + cmdline_args.pop() +elif last_arg in ('-w', '--warning'): + getLogger().setLevel(INFO) + info('cmdline_args (%s) %s' % (num_args, cmdline_args)) + getLogger().setLevel(WARNING) + cmdline_args.pop() +else: + getLogger().setLevel(DEBUG) + +num_args = len(cmdline_args) +info('cmdline_args (%s) %s' % (num_args, cmdline_args)) + +if run_tests and num_args in (1,2): + if num_args == 2: + url, actor = cmdline_args + else: + url, = cmdline_args + actor = default_actor + + info('url: %s' % url) + info('actor: %s' % actor) + + gh = GhLabelSynchronizer(url, actor) + gh.run_tests() + +elif num_args == 5: + action, url, actor, label, rev_state = cmdline_args + action = Action(action) + + info('action: %s' % action) + info('url: %s' % url) + info('actor: %s' % actor) + info('label: %s' % label) + info('rev_state: %s' % rev_state) + + gh = GhLabelSynchronizer(url, actor) + gh.run(action, label=label, rev_state=rev_state) + +elif num_args == 1: + url, = cmdline_args + + info('url: %s' % url) + + gh = GhLabelSynchronizer(url, default_actor) + +else: + print('Need 5 arguments to synchronize: action, url, actor, label, rev_state') + print('Need 1 argument to clean warning comments: url') + print('Need 1 argument to run tests: url') + print('The following options may be appended:') + print(' -t --test to run the test suite') + print(' -i --info to set the log-level to INFO') + print(' -d --debug to set the log-level to DEBUG (default)') + print(' -w --warning to set the log-level to WARNING') diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 814e410d29f..f8b6b52a890 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,6 +3,9 @@ name: Build & Test on: pull_request: push: + branches: ['**'] + # Ignore pushes on tags to prevent two uploads of codecov reports + tags-ignore: ['**'] workflow_dispatch: # Allow to run manually inputs: @@ -21,60 +24,140 @@ concurrency: cancel-in-progress: true jobs: + get_ci_fixes: + runs-on: ubuntu-latest + steps: + - name: Checkout + id: checkout + uses: actions/checkout@v4 + - name: Merge CI fixes from sagemath/sage + run: | + .ci/merge-fixes.sh + env: + GH_TOKEN: ${{ github.token }} + - name: Store CI fixes in upstream artifact + run: | + mkdir -p upstream + git format-patch --stdout test_base > upstream/ci_fixes.patch + - uses: actions/upload-artifact@v3 + with: + path: upstream + name: upstream + build: runs-on: ubuntu-latest - container: ghcr.io/sagemath/sage/sage-docker-${{ github.event.inputs.platform || 'ubuntu-focal-standard' }}-with-targets:${{ github.event.inputs.docker_tag || 'dev'}} + container: ghcr.io/sagemath/sage/sage-${{ github.event.inputs.platform || 'ubuntu-focal-standard' }}-with-targets:${{ github.event.inputs.docker_tag || 'dev'}} + needs: [get_ci_fixes] steps: - name: Checkout id: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Prepare + - name: Update system packages id: prepare run: | - # Install test tools. - if apt-get update && apt-get install -y git python3-venv; then - # Debian-specific temporary code: - # Installation of python3-venv can be removed as soon as a - # base image with a release including #33822 is available - : - else - export PATH="build/bin:$PATH" - eval $(sage-print-system-package-command auto update) - eval $(sage-print-system-package-command auto --spkg --yes --no-install-recommends install git) + export PATH="build/bin:$PATH" + eval $(sage-print-system-package-command auto update) + eval $(sage-print-system-package-command auto --spkg --yes --no-install-recommends install git) + + - name: Add prebuilt tree as a worktree + id: worktree + run: | + set -ex + git config --global user.email "ci-sage@example.com" + git config --global user.name "Build & Test workflow" + git config --global --add safe.directory $(pwd) + # If actions/checkout downloaded our source tree using the GitHub REST API + # instead of with git (because do not have git installed in our image), + # we first make the source tree a repo. + if [ ! -d .git ]; then git init && git add -A && git commit --quiet -m "new"; fi + # Tag this state of the source tree "new". This is what we want to build and test. + git tag -f new + # Our container image contains a source tree in /sage with a full build of Sage. + # But /sage is not a git repository. + # We make /sage a worktree whose index is at tag "new". + # We then commit the current sources and set the tag "old". (This keeps all mtimes unchanged.) + # Then we update worktree and index with "git reset --hard new". + # (This keeps mtimes of unchanged files unchanged and mtimes of changed files newer than unchanged files.) + # Finally we reset the index to "old". (This keeps all mtimes unchanged.) + # The changed files now show up as uncommitted changes. + # The final "git add -N" makes sure that files that were added in "new" do not show + # as untracked files, which would be removed by "git clean -fx". + git worktree add --detach worktree-image + rm -rf /sage/.git && mv worktree-image/.git /sage/ + rm -rf worktree-image && ln -s /sage worktree-image + if [ ! -f worktree-image/.gitignore ]; then cp .gitignore worktree-image/; fi + (cd worktree-image && git add -A && git commit --quiet --allow-empty -m "old" -a && git tag -f old && git reset --hard new && git reset --quiet old && git add -N . && git status) + + - name: Download upstream artifact + uses: actions/download-artifact@v3 + with: + path: upstream + name: upstream + + - name: Apply CI fixes from sagemath/sage + # After applying the fixes, make sure all changes are marked as uncommitted changes. + run: | + if [ -r upstream/ci_fixes.patch ]; then + (cd worktree-image && git commit -q -m "current changes" --allow-empty -a && git am; git reset --quiet old; git add -N .) < upstream/ci_fixes.patch fi - # Reuse built SAGE_LOCAL contained in the Docker image - ./bootstrap - ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv --enable-editable --enable-download-from-upstream-url - + + - name: Incremental build, test changed files (sage -t --new) + id: incremental + run: | + # Now re-bootstrap and build. The build is incremental because we were careful with the timestamps. + # We run tests with "sage -t --new"; this only tests the uncommitted changes. + ./bootstrap && make build && ./sage -t --new -p2 + working-directory: ./worktree-image + env: + MAKE: make -j2 --output-sync=recurse + SAGE_NUM_THREADS: 2 + - name: Build and test modularized distributions - if: always() && steps.prepare.outcome == 'success' + if: always() && steps.worktree.outcome == 'success' run: make V=0 tox && make pypi-wheels + working-directory: ./worktree-image env: - MAKE: make -j2 + MAKE: make -j2 --output-sync=recurse SAGE_NUM_THREADS: 2 - name: Set up node to install pyright - if: always() && steps.prepare.outcome == 'success' + if: always() && steps.worktree.outcome == 'success' uses: actions/setup-node@v3 with: node-version: '12' - name: Install pyright - if: always() && steps.prepare.outcome == 'success' + if: always() && steps.worktree.outcome == 'success' # Fix to v232 due to bug https://github.com/microsoft/pyright/issues/3239 run: npm install -g pyright@1.1.232 - name: Static code check with pyright - if: always() && steps.prepare.outcome == 'success' - run: pyright - + if: always() && steps.worktree.outcome == 'success' + run: pyright + working-directory: ./worktree-image + + - name: Clean (fallback to non-incremental) + id: clean + if: always() && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success' + run: | + set -ex + ./bootstrap && make doc-clean doc-uninstall sagelib-clean && git clean -fx src/sage && ./config.status + working-directory: ./worktree-image + env: + MAKE: make -j2 + SAGE_NUM_THREADS: 2 + - name: Build + # This step is needed because building the modularized distributions installs some optional packages, + # so the editable install of sagelib needs to build the corresponding optional extension modules. id: build - if: always() && steps.prepare.outcome == 'success' - run: make build + if: always() && (steps.incremental.outcome == 'success' || steps.clean.outcome == 'success') + run: | + make build + working-directory: ./worktree-image env: - MAKE: make -j2 + MAKE: make -j2 --output-sync=recurse SAGE_NUM_THREADS: 2 - name: Pytest @@ -82,17 +165,17 @@ jobs: run: | ../sage -python -m pip install coverage pytest-xdist ../sage -python -m coverage run -m pytest -c tox.ini --doctest-modules || true - working-directory: ./src + working-directory: ./worktree-image/src env: # Increase the length of the lines in the "short summary" COLUMNS: 120 - - name: Test + - name: Test all files (sage -t --all --long) if: always() && steps.build.outcome == 'success' run: | ../sage -python -m pip install coverage - ../sage -python -m coverage run ./bin/sage-runtests --all -p2 - working-directory: ./src + ../sage -python -m coverage run ./bin/sage-runtests --all --long -p2 --random-seed=286735480429121101562228604801325644303 + working-directory: ./worktree-image/src - name: Prepare coverage results if: always() && steps.build.outcome == 'success' @@ -100,9 +183,10 @@ jobs: ./venv/bin/python3 -m coverage combine src/.coverage/ ./venv/bin/python3 -m coverage xml find . -name *coverage* - + working-directory: ./worktree-image + - name: Upload coverage to codecov if: always() && steps.build.outcome == 'success' - uses: codecov/codecov-action@v2 + uses: codecov/codecov-action@v3 with: - files: ./coverage.xml + files: ./worktree-image/coverage.xml diff --git a/.github/workflows/ci-conda.yml b/.github/workflows/ci-conda.yml index bc1f1c5a634..9695dc7ef9a 100644 --- a/.github/workflows/ci-conda.yml +++ b/.github/workflows/ci-conda.yml @@ -6,6 +6,14 @@ on: - '*' branches: - 'public/build/**-runci' + pull_request: + types: + # Defaults + - opened + - synchronize + - reopened + # When a CI label is added + - labeled workflow_dispatch: # Allow to run manually @@ -18,16 +26,36 @@ jobs: test: name: Conda runs-on: ${{ matrix.os }} - + + # Run on push, workflow dispatch and when certain labels are added or are present + if: | + github.event_name != 'pull_request' || + ((github.event.action != 'labeled' && + (contains(github.event.pull_request.labels.*.name, 'c: packages: standard') || + contains(github.event.pull_request.labels.*.name, 'c: packages: optional') || + contains(github.event.pull_request.labels.*.name, 's: run conda ci'))) || + (github.event.action == 'labeled' && + (github.event.label.name == 'c: packages: optional' || + github.event.label.name == 'c: packages: standard' || + github.event.label.name == 's: run conda ci'))) + strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - python: [3.8, 3.9] - conda-env: [environment, environment-optional] + python: ['3.9', '3.10', '3.11'] + # Optional environment is disabled for now as its not yet working + # environment: [environment, environment-optional] + conda-env: [environment] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + + - name: Merge CI fixes from sagemath/sage + run: | + .ci/merge-fixes.sh + env: + GH_TOKEN: ${{ github.token }} - name: Check for Miniconda id: check_conda @@ -45,7 +73,7 @@ jobs: run: ./bootstrap-conda - name: Cache conda packages - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/conda_pkgs_dir key: @@ -73,27 +101,34 @@ jobs: run: | ./bootstrap echo "::add-matcher::.github/workflows/configure-systempackage-problem-matcher.json" - ./configure --enable-build-as-root --with-python=$CONDA_PREFIX/bin/python --prefix=$CONDA_PREFIX $(for pkg in $(./sage -package list :standard: --has-file spkg-configure.m4 --has-file distros/conda.txt); do echo --with-system-$pkg=force; done) + ./configure --enable-build-as-root --with-python=$CONDA_PREFIX/bin/python --prefix=$CONDA_PREFIX $(for pkg in $(./sage -package list :standard: --has-file spkg-configure.m4 --has-file distros/conda.txt --exclude rpy2); do echo --with-system-$pkg=force; done) echo "::remove-matcher owner=configure-system-package-warning::" echo "::remove-matcher owner=configure-system-package-error::" - name: Build shell: bash -l {0} run: | - pip install --no-build-isolation -v -v -e ./pkgs/sage-conf ./pkgs/sage-setup - pip install --no-build-isolation -v -v -e ./src + # Use --no-deps and pip check below to verify that all necessary dependencies are installed via conda. + pip install --no-build-isolation --no-deps -v -v -e ./pkgs/sage-conf ./pkgs/sage-setup + pip install --no-build-isolation --no-deps -v -v -e ./src env: SAGE_NUM_THREADS: 2 + + - name: Verify dependencies + if: success() || failure() + shell: bash -l {0} + run: pip check - name: Test + if: success() || failure() shell: bash -l {0} run: ./sage -t --all -p0 - name: Print logs + if: always() run: | for file in $(find . -type f -name "*.log"); do echo "::group::$file" cat "$file" echo "::endgroup::" done - if: always() diff --git a/.github/workflows/ci-cygwin-standard.yml b/.github/workflows/ci-cygwin-standard.yml index 53c674028ef..326dd62490e 100644 --- a/.github/workflows/ci-cygwin-standard.yml +++ b/.github/workflows/ci-cygwin-standard.yml @@ -39,7 +39,7 @@ jobs: with: stage: ii-b previous_stages: i-* - targets: singular maxima gap pari gfan palp flintqs arb ecm givaro + targets: singular maxima gap pari gfan palp arb ecm givaro needs: [cygwin-stage-i-a, cygwin-stage-i-b] cygwin-stage-ii-c: diff --git a/.github/workflows/ci-linux-incremental.yml b/.github/workflows/ci-linux-incremental.yml new file mode 100644 index 00000000000..a4aa9ae99c7 --- /dev/null +++ b/.github/workflows/ci-linux-incremental.yml @@ -0,0 +1,132 @@ +name: CI Linux incremental + +## This GitHub Actions workflow runs SAGE_ROOT/tox.ini with select environments, +## whenever a GitHub pull request is opened or synchronized in a repository +## where GitHub Actions are enabled. +## +## It builds and checks some sage spkgs as defined in TARGETS. +## +## A job succeeds if there is no error. +## +## The build is run with "make V=0", so the build logs of individual packages are suppressed. +## +## At the end, all package build logs that contain an error are printed out. +## +## After all jobs have finished (or are canceled) and a short delay, +## tar files of all logs are made available as "build artifacts". + +on: + pull_request: + types: + # Defaults + - opened + - synchronize + - reopened + # When a CI label is added + - labeled + workflow_dispatch: + +concurrency: + # Cancel previous runs of this workflow for the same branch + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + packages: write + +jobs: + + changed_files: + runs-on: ubuntu-latest + name: List changed packages + outputs: + uninstall_targets: ${{ steps.build-targets.outputs.uninstall_targets }} + build_targets: ${{ steps.build-targets.outputs.build_targets }} + steps: + - uses: actions/checkout@v4 + - name: Get all packages that have changed + id: changed-packages + uses: tj-actions/changed-files@v38 + with: + files_yaml: | + configures: + - 'build/pkgs/*/spkg-configure.m4' + pkgs: + - 'build/pkgs/**' + - 'pkgs/**' + - name: Determine targets to build + id: build-targets + run: | + echo "uninstall_targets=$(echo $(for a in '' ${{ steps.changed-packages.outputs.configures_all_changed_files }}; do echo $a | sed -E 's,build/pkgs/([_.a-z0-9]*)/spkg-configure[.]m4 *,\1-uninstall,'; done | sort -u))" >> $GITHUB_OUTPUT + echo "build_targets=$(echo $(for a in '' ${{ steps.changed-packages.outputs.pkgs_all_changed_files }}; do echo $a | sed -E 's,-,_,g;s,(build/)?pkgs/([-_.a-z0-9]*)/[^ ]* *,\2-ensure,;'; done | sort -u))" >> $GITHUB_OUTPUT + cat $GITHUB_OUTPUT + + test: + needs: [changed_files] + if: | + github.event_name != 'pull_request' || + ((github.event.action != 'labeled' && + (contains(github.event.pull_request.labels.*.name, 'c: packages: standard') || + contains(github.event.pull_request.labels.*.name, 'c: packages: optional'))) || + (github.event.action == 'labeled' && + (github.event.label.name == 'c: packages: optional' || + github.event.label.name == 'c: packages: standard'))) + uses: ./.github/workflows/docker.yml + with: + # Build incrementally from published Docker image + incremental: true + free_disk_space: true + from_docker_repository: ghcr.io/sagemath/sage/ + from_docker_target: "with-targets" + from_docker_tag: "dev" + docker_targets: "with-targets" + targets: "${{needs.changed_files.outputs.uninstall_targets}} ${{needs.changed_files.outputs.build_targets}} build doc-html ptest" + tox_system_factors: >- + ["ubuntu-focal", + "ubuntu-jammy", + "ubuntu-mantic", + "debian-bullseye", + "debian-bookworm", + "fedora-30", + "fedora-38", + "gentoo-python3.11", + "debian-bullseye-i386"] + tox_packages_factors: >- + ["standard", + "minimal"] + docker_push_repository: ghcr.io/${{ github.repository }}/ + + site: + needs: [changed_files] + if: | + github.event_name != 'pull_request' || + ((github.event.action != 'labeled' && + (contains(github.event.pull_request.labels.*.name, 'c: packages: standard') || + contains(github.event.pull_request.labels.*.name, 'c: packages: optional'))) || + (github.event.action == 'labeled' && + (github.event.label.name == 'c: packages: optional' || + github.event.label.name == 'c: packages: standard'))) + uses: ./.github/workflows/docker.yml + with: + # Build incrementally from published Docker image + incremental: true + free_disk_space: true + from_docker_repository: ghcr.io/sagemath/sage/ + from_docker_target: "with-targets" + from_docker_tag: "dev" + docker_targets: "with-targets" + targets: "${{needs.changed_files.outputs.uninstall_targets}} ${{needs.changed_files.outputs.build_targets}} build doc-html ptest" + # Only test systems with a usable system python (>= 3.9) + tox_system_factors: >- + ["ubuntu-jammy", + "ubuntu-mantic", + "debian-bullseye", + "debian-bookworm", + "fedora-33", + "fedora-38", + "gentoo-python3.11", + "archlinux", + "debian-bullseye-i386"] + tox_packages_factors: >- + ["standard-sitepackages"] + docker_push_repository: ghcr.io/${{ github.repository }}/ diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index aca56f9b49c..665a2a4f0b0 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -29,6 +29,9 @@ env: TARGETS: build doc-html TARGETS_OPTIONAL: ptest +permissions: + packages: write + jobs: standard-pre: @@ -60,6 +63,55 @@ jobs: ["standard"] docker_push_repository: ghcr.io/${{ github.repository }}/ + standard-sitepackages: + if: ${{ success() || failure() }} + needs: [standard-pre] + uses: ./.github/workflows/docker.yml + with: + # Build incrementally from previous stage (pre) + incremental: true + free_disk_space: true + from_docker_repository: ghcr.io/${{ github.repository }}/ + from_docker_target: "with-targets-pre" + docker_targets: "with-targets with-targets-optional" + # FIXME: duplicated from env.TARGETS + targets: build doc-html + targets_optional: ptest + tox_packages_factors: >- + ["standard-sitepackages"] + # Only test systems with a usable system python (>= 3.9) + tox_system_factors: >- + ["ubuntu-jammy", + "ubuntu-lunar", + "ubuntu-mantic", + "debian-bullseye", + "debian-bookworm", + "debian-trixie", + "debian-sid", + "linuxmint-21", + "linuxmint-21.1", + "linuxmint-21.2", + "fedora-33", + "fedora-34", + "fedora-35", + "fedora-36", + "fedora-37", + "fedora-38", + "fedora-39", + "centos-stream-8-python3.9", + "centos-stream-9-python3.9", + "almalinux-8-python3.9", + "gentoo-python3.10", + "gentoo-python3.11", + "archlinux-latest", + "opensuse-15.4-gcc_11-python3.10", + "opensuse-15.5-gcc_11-python3.11", + "opensuse-tumbleweed-python3.10", + "opensuse-tumbleweed", + "debian-bullseye-i386"] + docker_push_repository: ghcr.io/${{ github.repository }}/ + max_parallel: 10 + minimal-pre: if: ${{ success() || failure() }} # It does not really "need" it. diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index c07c6968095..9482eb9632b 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -30,95 +30,46 @@ env: TARGETS_OPTIONAL: ptest jobs: - local-macos: + stage-1: + uses: ./.github/workflows/macos.yml + with: + stage: "1" - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - stage: ["1", "2", "2-optional-0-o", "2-optional-p-z", "2-experimental-0-o", "2-experimental-p-z"] - # python3_xcode is only accepted if enough packages are available from the system - # --> to test "minimal", we would need https://github.com/sagemath/sage/issues/30949 - tox_env: [homebrew-macos-usrlocal-minimal, homebrew-macos-usrlocal-standard, homebrew-macos-usrlocal-maximal, homebrew-macos-usrlocal-python3_xcode-standard, conda-forge-macos-minimal, conda-forge-macos-standard, conda-forge-macos-maximal] - xcode_version_factor: [default] - os: [ macos-11, macos-12 ] - env: - TOX_ENV: local-${{ matrix.tox_env }} - LOCAL_ARTIFACT_NAME: sage-local-commit-${{ github.sha }}-tox-local-${{ matrix.tox_env }}-${{ matrix.os }}-xcode_${{ matrix.xcode_version_factor }} - LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-local-${{ matrix.tox_env }}--${{ matrix.os }}-xcode_${{ matrix.xcode_version_factor }} - steps: - - uses: actions/checkout@v3 - - name: Select Xcode version - run: | - if [ ${{ matrix.xcode_version_factor }} != default ]; then sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode_version_factor }}.app; fi - - name: Install test prerequisites - run: | - brew install tox - - uses: actions/download-artifact@v3 - with: - path: sage-local-artifact - name: ${{ env.LOCAL_ARTIFACT_NAME }} - if: contains(matrix.stage, '2') - - name: Extract sage-local artifact - # This is macOS tar -- cannot use --listed-incremental - run: | - export SAGE_LOCAL=$(pwd)/.tox/$TOX_ENV/local - .github/workflows/extract-sage-local.sh sage-local-artifact/sage-local-*.tar - if: contains(matrix.stage, '2') - - name: Build and test with tox - # We use a high parallelization on purpose in order to catch possible parallelization bugs in the build scripts. - # For doctesting, we use a lower parallelization to avoid timeouts. - run: | - case "${{ matrix.stage }}" in - 1) export TARGETS_PRE="all-sage-local" TARGETS="all-sage-local" TARGETS_OPTIONAL="build/make/Makefile" - ;; - 2) export TARGETS_PRE="all-sage-local" TARGETS="build doc-html" TARGETS_OPTIONAL="ptest" - ;; - 2-optional*) export TARGETS_PRE="build/make/Makefile" TARGETS="build/make/Makefile" - targets_pattern="${{ matrix.stage }}" - targets_pattern="${targets_pattern#2-optional-}" - export TARGETS_OPTIONAL=$( echo $(export PATH=build/bin:$PATH && sage-package list :optional: --has-file 'spkg-install.in|spkg-install|requirements.txt' --no-file huge|has_nonfree_dependencies | grep -v sagemath_doc | grep "^[$targets_pattern]" ) ) - ;; - 2-experimental*) export TARGETS_PRE="build/make/Makefile" TARGETS="build/make/Makefile" - targets_pattern="${{ matrix.stage }}" - targets_pattern="${targets_pattern#2-experimental-}" - export TARGETS_OPTIONAL=$( echo $(export PATH=build/bin:$PATH && sage-package list :experimental: --has-file 'spkg-install.in|spkg-install|requirements.txt' --no-file huge|has_nonfree_dependencies | grep -v sagemath_doc | grep "^[$targets_pattern]" ) ) - ;; - esac - MAKE="make -j12" tox -e $TOX_ENV -- SAGE_NUM_THREADS=4 $TARGETS - - name: Prepare logs artifact - run: | - mkdir -p "artifacts/$LOGS_ARTIFACT_NAME"; cp -r .tox/*/log "artifacts/$LOGS_ARTIFACT_NAME" - if: always() - - uses: actions/upload-artifact@v3 - with: - path: artifacts - name: ${{ env.LOGS_ARTIFACT_NAME }} - if: always() - - name: Print out logs for immediate inspection - # and markup the output with GitHub Actions logging commands - run: | - .github/workflows/scan-logs.sh "artifacts/$LOGS_ARTIFACT_NAME" - if: always() - - name: Prepare sage-local artifact - # This also includes the copies of homebrew or conda installed in the tox environment. - # We use absolute pathnames in the tar file. - # This is macOS tar -- cannot use --remove-files. - # We remove the $SAGE_LOCAL/lib64 link, which will be recreated by the next stage. - run: | - mkdir -p sage-local-artifact && (cd .tox/$TOX_ENV && rm -f "local/lib64" && tar -cf - $(pwd)) > sage-local-artifact/sage-${{ env.TOX_ENV }}-${{ matrix.stage }}.tar - if: contains(matrix.stage, '1') - - uses: actions/upload-artifact@v3 - with: - path: sage-local-artifact/sage-${{ env.TOX_ENV }}-${{ matrix.stage }}.tar - name: ${{ env.LOCAL_ARTIFACT_NAME }} - if: always() + stage-2: + uses: ./.github/workflows/macos.yml + with: + stage: "2" + needs: [stage-1] + + stage-2-optional-0-o: + uses: ./.github/workflows/macos.yml + with: + stage: "2-optional-0-o" + needs: [stage-2] + + stage-2-optional-p-z: + uses: ./.github/workflows/macos.yml + with: + stage: "2-optional-p-z" + needs: [stage-2-optional-0-o] + + stage-2-experimental-0-o: + uses: ./.github/workflows/macos.yml + with: + stage: "2-optional-0-o" + needs: [stage-2-optional-p-z] + + stage-2-experimental-p-z: + uses: ./.github/workflows/macos.yml + with: + stage: "2-experimental-p-z" + needs: [stage-2-experimental-0-o] dist: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 500 - name: fetch tags @@ -160,7 +111,7 @@ jobs: TOX_ENV: local-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-local-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }}-xcode_${{ matrix.xcode_version_factor }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 if: "!contains(matrix.tox_system_factor, 'nobootstrap')" - uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/ci-wsl.yml b/.github/workflows/ci-wsl.yml index e6d4d30cfc3..ae83e1d6a0f 100644 --- a/.github/workflows/ci-wsl.yml +++ b/.github/workflows/ci-wsl.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Configure git run: git config --global core.symlinks true - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Ubuntu 20.04 (in WSL) run: | (New-Object System.Net.WebClient).DownloadFile("https://aka.ms/wslubuntu2004", "Ubuntu.appx") diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml index 0d57bd8440f..26c193dfb2b 100644 --- a/.github/workflows/cygwin.yml +++ b/.github/workflows/cygwin.yml @@ -73,14 +73,14 @@ jobs: choco install git python39 python39-pip --source cygwin - name: Check out SageMath - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ${{ inputs.sage_repo }} ref: ${{ inputs.sage_ref }} fetch-depth: 2000 - name: Check out git-trac-command - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: sagemath/git-trac-command path: git-trac-command diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml index 96aae8fbc1a..3aaecc6a064 100644 --- a/.github/workflows/dist.yml +++ b/.github/workflows/dist.yml @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install bootstrap prerequisites run: | sudo DEBIAN_FRONTEND=noninteractive apt-get update @@ -51,7 +51,7 @@ jobs: env: CAN_DEPLOY: ${{ secrets.SAGEMATH_PYPI_API_TOKEN != '' }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install bootstrap prerequisites run: | sudo DEBIAN_FRONTEND=noninteractive apt-get update @@ -100,13 +100,13 @@ jobs: # CIBW_ARCHS: ${{ matrix.arch }} # https://cibuildwheel.readthedocs.io/en/stable/options/#requires-python - CIBW_PROJECT_REQUIRES_PYTHON: ">=3.8" + CIBW_PROJECT_REQUIRES_PYTHON: ">=3.9" # Environment during wheel build CIBW_ENVIRONMENT: "PATH=$(pwd)/local/bin:$PATH CPATH=$(pwd)/local/include:$CPATH LIBRARY_PATH=$(pwd)/local/lib:$LIBRARY_PATH PKG_CONFIG_PATH=$(pwd)/local/share/pkgconfig:$PKG_CONFIG_PATH ACLOCAL_PATH=/usr/share/aclocal" # Use 'build', not 'pip wheel' CIBW_BUILD_FRONTEND: build steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/doc-build-pdf.yml b/.github/workflows/doc-build-pdf.yml new file mode 100644 index 00000000000..6eacba7fe52 --- /dev/null +++ b/.github/workflows/doc-build-pdf.yml @@ -0,0 +1,57 @@ +name: Build documentation (PDF) + +on: + pull_request: + push: + workflow_dispatch: + # Allow to run manually + +concurrency: + # Cancel previous runs of this workflow for the same branch + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-docs: + runs-on: ubuntu-latest + # Use "maximal" so that texlive is installed + # Use "fedora-31" for build diversity + container: ghcr.io/sagemath/sage/sage-docker-fedora-31-maximal-with-targets:dev + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Merge CI fixes from sagemath/sage + run: | + .ci/merge-fixes.sh + env: + GH_TOKEN: ${{ github.token }} + + - name: Prepare + run: | + apt-get update && apt-get install -y zip + # Reuse built SAGE_LOCAL contained in the Docker image + ./bootstrap + ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv --enable-download-from-upstream-url + + - name: Build + run: make build V=0 && make doc-pdf + env: + MAKE: make -j2 + SAGE_NUM_THREADS: 2 + TEXMFHOME: /sage/texmf + + - name: Copy docs + run: | + # For some reason the deploy step below cannot find /sage/... + # So copy everything from there to local folder + mkdir -p ./docs + cp -r -L /sage/local/share/doc/sage/pdf/en/* ./docs + # Zip everything for increased performance + zip -r docs-pdf.zip docs + + - name: Upload docs + uses: actions/upload-artifact@v3 + with: + name: docs-pdf + path: docs-pdf.zip diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 1cc9cf8cd3f..04ccb2b28fe 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -12,37 +12,141 @@ concurrency: cancel-in-progress: true jobs: + get_ci_fixes: + runs-on: ubuntu-latest + steps: + - name: Checkout + id: checkout + uses: actions/checkout@v4 + - name: Merge CI fixes from sagemath/sage + run: | + .ci/merge-fixes.sh + env: + GH_TOKEN: ${{ github.token }} + - name: Store CI fixes in upstream artifact + run: | + mkdir -p upstream + git format-patch --stdout test_base > upstream/ci_fixes.patch + - uses: actions/upload-artifact@v3 + with: + path: upstream + name: upstream + build-docs: runs-on: ubuntu-latest - container: ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets:dev + container: ghcr.io/sagemath/sage/sage-ubuntu-focal-standard-with-targets:dev + needs: [get_ci_fixes] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 + + - name: Update system packages + run: | + apt-get update && apt-get install -y git zip - - name: Prepare + - name: Add prebuilt tree as a worktree + id: worktree run: | - apt-get update && apt-get install -y zip - # Reuse built SAGE_LOCAL contained in the Docker image - ./bootstrap - ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv --enable-download-from-upstream-url + set -ex + git config --global user.email "ci-sage@example.com" + git config --global user.name "Build & Test workflow" + git config --global --add safe.directory $(pwd) + # If actions/checkout downloaded our source tree using the GitHub REST API + # instead of with git (because do not have git installed in our image), + # we first make the source tree a repo. + if [ ! -d .git ]; then git init && git add -A && git commit --quiet -m "new"; fi + # Tag this state of the source tree "new". This is what we want to build and test. + git tag -f new + # Our container image contains a source tree in /sage with a full build of Sage. + # But /sage is not a git repository. + # We make /sage a worktree whose index is at tag "new". + # We then commit the current sources and set the tag "old". (This keeps all mtimes unchanged.) + # Then we update worktree and index with "git reset --hard new". + # (This keeps mtimes of unchanged files unchanged and mtimes of changed files newer than unchanged files.) + # Finally we reset the index to "old". (This keeps all mtimes unchanged.) + # The changed files now show up as uncommitted changes. + # The final "git add -N" makes sure that files that were added in "new" do not show + # as untracked files, which would be removed by "git clean -fx". + git worktree add --detach worktree-image + rm -rf /sage/.git && mv worktree-image/.git /sage/ + rm -rf worktree-image && ln -s /sage worktree-image + if [ ! -f worktree-image/.gitignore ]; then cp .gitignore worktree-image/; fi + (cd worktree-image && git add -A && git commit --quiet --allow-empty -m "old" -a && git tag -f old && git reset --hard new && git reset --quiet old && git add -N . && git status) + # Keep track of changes to built HTML + new_version=$(cat src/VERSION.txt); (cd /sage/local/share/doc/sage/html/en && find . -name "*.html" | xargs sed -i '/class="sidebar-brand-text"/s/Sage [0-9a-z.]* /Sage '$new_version' /'; git init && (echo "*.svg binary"; echo "*.pdf binary") >> .gitattributes && (echo ".buildinfo"; echo '*.inv'; echo '.git*'; echo '*.svg'; echo '*.pdf'; echo '*.png'; echo 'searchindex.js') > .gitignore; git add -A && git commit --quiet -m "old") - - name: Build - run: make doc-html + - name: Download upstream artifact + uses: actions/download-artifact@v3 + with: + path: upstream + name: upstream + + - name: Apply CI fixes from sagemath/sage + # After applying the fixes, make sure all changes are marked as uncommitted changes. + run: | + if [ -r upstream/ci_fixes.patch ]; then + (cd worktree-image && git commit -q -m "current changes" --allow-empty -a && git am; git reset --quiet old; git add -N .) < upstream/ci_fixes.patch + fi + + - name: Incremental build + id: incremental + run: | + # Now re-bootstrap and build. The build is incremental because we were careful with the timestamps. + ./bootstrap && make build + working-directory: ./worktree-image + env: + MAKE: make -j2 --output-sync=recurse + SAGE_NUM_THREADS: 2 + + - name: Build (fallback to non-incremental) + id: build + if: always() && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success' + run: | + set -ex + make doc-clean doc-uninstall sagelib-clean && git clean -fx src/sage && ./config.status && make build + working-directory: ./worktree-image env: - MAKE: make -j2 + MAKE: make -j2 --output-sync=recurse + SAGE_NUM_THREADS: 2 + + - name: Build docs + id: docbuild + if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success') + # Always non-incremental because of the concern that + # incremental docbuild may introduce broken links (inter-file references) though build succeeds + run: | + set -ex + export SAGE_USE_CDNS=yes + mv /sage/local/share/doc/sage/html/en/.git /sage/.git-doc + make doc-clean doc-uninstall sagelib-clean && git clean -fx src/sage + mkdir -p /sage/local/share/doc/sage/html/en/ && mv /sage/.git-doc /sage/local/share/doc/sage/html/en/.git + ./config.status && make doc-html + working-directory: ./worktree-image + env: + MAKE: make -j2 --output-sync=recurse SAGE_NUM_THREADS: 2 - name: Copy docs + id: copy + if: always() && steps.docbuild.outcome == 'success' run: | + set -ex + mkdir -p ./docs + # Create changelog + echo '## Preview of CHANGES.html' + (cd /sage/local/share/doc/sage/html/en && git diff --name-only) | tee ./docs/CHANGES.txt + (cd /sage/local/share/doc/sage/html/en && git diff; rm -rf .git) > ./docs/html.diff + echo '## Preview of html.diff'; head -n 400 ./docs/html.diff + (echo '<p><a href="html.diff">HTML diff</a>'; sed -E 's,(.*),<p><a href="\1">\1</a>,' ./docs/CHANGES.txt) > ./docs/CHANGES.html # For some reason the deploy step below cannot find /sage/... # So copy everything from there to local folder # We also need to replace the symlinks because netlify is not following them - mkdir -p ./docs cp -r -L /sage/local/share/doc/sage/html/en/* ./docs # Zip everything for increased performance zip -r docs.zip docs - name: Upload docs + if: always() && steps.copy.outcome == 'success' uses: actions/upload-artifact@v3 with: name: docs diff --git a/.github/workflows/doc-publish.yml b/.github/workflows/doc-publish.yml index c7be4a46d3b..14337131420 100644 --- a/.github/workflows/doc-publish.yml +++ b/.github/workflows/doc-publish.yml @@ -1,4 +1,4 @@ -# Triggers after the documentation build has finished, +# Triggers after the documentation build has finished, # taking the artifact and uploading it to netlify name: Publish documentation @@ -28,10 +28,10 @@ jobs: # Once https://github.com/actions/download-artifact/issues/172 and/or https://github.com/actions/download-artifact/issues/60 is implemented, we can use the official download-artifact action # For now use the solution from https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow - name: Download docs - uses: actions/github-script@v3.1.0 + uses: actions/github-script@v6.4.0 with: script: | - var artifacts = await github.actions.listWorkflowRunArtifacts({ + var artifacts = await github.rest.actions.listWorkflowRunArtifacts({ owner: context.repo.owner, repo: context.repo.repo, run_id: ${{github.event.workflow_run.id }}, @@ -39,7 +39,7 @@ jobs: var matchArtifact = artifacts.data.artifacts.filter((artifact) => { return artifact.name == "docs" })[0]; - var download = await github.actions.downloadArtifact({ + var download = await github.rest.actions.downloadArtifact({ owner: context.repo.owner, repo: context.repo.repo, artifact_id: matchArtifact.id, @@ -47,7 +47,7 @@ jobs: }); var fs = require('fs'); fs.writeFileSync('${{github.workspace}}/docs.zip', Buffer.from(download.data)); - + - name: Extract docs run: unzip docs.zip -d docs && unzip docs/docs.zip -d docs/docs @@ -72,11 +72,10 @@ jobs: header: preview-comment recreate: true message: | - [Documentation preview for this PR](${{ steps.deploy-netlify.outputs.NETLIFY_URL }}) is ready! :tada: - Built with commit: ${{ steps.source-run-info.outputs.sourceHeadSha }} - + [Documentation preview for this PR](${{ steps.deploy-netlify.outputs.NETLIFY_URL }}) (built with commit ${{ steps.source-run-info.outputs.sourceHeadSha }}; [changes](${{ steps.deploy-netlify.outputs.NETLIFY_URL }}/CHANGES.html)) is ready! :tada: + - name: Update deployment status PR check - uses: myrotvorets/set-commit-status-action@1.1.6 + uses: myrotvorets/set-commit-status-action@v2.0.0 if: ${{ always() }} env: DEPLOY_SUCCESS: Successfully deployed preview. diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 04c74659c1d..db4896bbd12 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -18,24 +18,23 @@ on: default: >- ["ubuntu-trusty-toolchain-gcc_9", "ubuntu-xenial-toolchain-gcc_9", - "ubuntu-bionic-gcc_8-python3.8", + "ubuntu-bionic-gcc_8", "ubuntu-focal", "ubuntu-jammy", - "ubuntu-kinetic", "ubuntu-lunar", - "debian-buster", + "ubuntu-mantic", + "debian-buster-gcc_spkg", "debian-bullseye", "debian-bookworm", + "debian-trixie", "debian-sid", - "linuxmint-19-gcc_8-python3.8", - "linuxmint-19.3-gcc_8-python3.8", "linuxmint-20.1", "linuxmint-20.2", "linuxmint-20.3", "linuxmint-21", "linuxmint-21.1", - "fedora-29-python3.8", - "fedora-30-python3.8", + "linuxmint-21.2", + "fedora-30", "fedora-31", "fedora-32", "fedora-33", @@ -44,19 +43,23 @@ on: "fedora-36", "fedora-37", "fedora-38", + "fedora-39", "centos-7-devtoolset-gcc_11", "centos-stream-8-python3.9", "centos-stream-9-python3.9", - "gentoo-python3.9", + "almalinux-8-python3.9", + "almalinux-9-python3.11", "gentoo-python3.10", "gentoo-python3.11", "archlinux-latest", "opensuse-15.3-gcc_11-python3.9", "opensuse-15.4-gcc_11-python3.10", + "opensuse-15.5-gcc_11-python3.11", "opensuse-tumbleweed-python3.10", + "opensuse-tumbleweed", "conda-forge", "ubuntu-bionic-gcc_8-i386", - "debian-buster-i386", + "debian-bullseye-i386", ] tox_packages_factors: description: 'Stringified JSON object listing tox packages factors' @@ -71,7 +74,7 @@ on: default: "" max_parallel: type: number - default: 24 + default: 30 free_disk_space: default: false type: boolean @@ -101,7 +104,7 @@ on: default: "$BUILD_TAG" type: string # - # For use in upstream CIs + # For use in upstream CIs. sage_trac_* are now ignored and will be removed later. # upstream_artifact: required: false @@ -142,13 +145,11 @@ jobs: EXTRA_SAGE_PACKAGES: ${{ inputs.extra_sage_packages }} steps: - name: Check out SageMath - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ${{ inputs.sage_repo }} ref: ${{ inputs.sage_ref }} fetch-depth: 10000 - - name: fetch tags - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* - name: free disk space run: | df -h @@ -161,21 +162,6 @@ jobs: sudo apt-get --fix-broken --yes remove $(dpkg-query -f '${Package}\n' -W | grep -E '^(ghc-|google-cloud-sdk|google-chrome|firefox|mysql-server|dotnet-sdk|hhvm|mono)') || echo "(error ignored)" df -h if: inputs.free_disk_space - - name: Check out git-trac-command - uses: actions/checkout@v3 - with: - repository: sagemath/git-trac-command - path: git-trac-command - if: inputs.sage_trac_git != '' - - name: Check out SageMath from trac.sagemath.org - shell: bash {0} - # Random sleep and retry to limit the load on trac.sagemath.org - run: | - git config --global user.email "ci-sage@example.com" - git config --global user.name "ci-sage workflow" - if [ ! -d .git ]; then git init; fi; git remote add trac ${{ inputs.sage_trac_git }} && x=1 && while [ $x -le 5 ]; do x=$(( $x + 1 )); sleep $(( $RANDOM % 60 + 1 )); if git-trac-command/git-trac fetch ${{ inputs.sage_trac_ticket }}; then git merge FETCH_HEAD || echo "(ignored)"; exit 0; fi; sleep 40; done; exit 1 - if: inputs.sage_trac_git != '' - - name: Download upstream artifact uses: actions/download-artifact@v3 with: @@ -193,6 +179,12 @@ jobs: (export PATH=$(pwd)/build/bin:$PATH; (cd upstream && bash -x update-pkgs.sh) && sed -i.bak '/upstream/d' .dockerignore && echo "/:toolchain:/i ADD upstream upstream" | sed -i.bak -f - build/bin/write-dockerfile.sh && git diff) if: inputs.upstream_artifact + - name: Merge CI fixes from sagemath/sage + run: | + .ci/merge-fixes.sh + env: + GH_TOKEN: ${{ github.token }} + - name: Try to login to ghcr.io if: inputs.docker_push_repository != '' # https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 883749e2bf7..b4eebb4ac9e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,11 +13,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 + - name: Merge CI fixes from sagemath/sage + run: | + .ci/merge-fixes.sh + env: + GH_TOKEN: ${{ github.token }} - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 - name: Install pycodestyle run: pip install tox pycodestyle - name: Lint using pycodestyle @@ -27,11 +32,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 + - name: Merge CI fixes from sagemath/sage + run: | + .ci/merge-fixes.sh + env: + GH_TOKEN: ${{ github.token }} - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 - name: Install relint run: pip install tox relint - name: Lint using relint @@ -41,11 +51,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 + - name: Merge CI fixes from sagemath/sage + run: | + .ci/merge-fixes.sh + env: + GH_TOKEN: ${{ github.token }} - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 - name: Install tox run: pip install tox - name: Lint using tox -e rst diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml new file mode 100644 index 00000000000..5b448cec1bb --- /dev/null +++ b/.github/workflows/macos.yml @@ -0,0 +1,159 @@ +name: Reusable workflow for macOS portability CI + +on: + workflow_call: + inputs: + # Either specify a stage + stage: + required: false + type: string + # Or specify targets + targets_pre: + default: build/make/Makefile + type: string + targets: + default: build/make/Makefile + type: string + targets_optional: + default: build/make/Makefile + type: string + # System configuration + osversion_xcodeversion_toxenv_tuples: + description: 'Stringified JSON object' + default: >- + [["latest", "", "homebrew-macos-usrlocal-minimal"], + ["latest", "", "homebrew-macos-usrlocal-standard"], + ["11", "xcode_11.7", "homebrew-macos-usrlocal-standard"], + ["12", "", "homebrew-macos-usrlocal-standard"], + ["13", "xcode_15.0", "homebrew-macos-usrlocal-standard"], + ["latest", "", "homebrew-macos-usrlocal-maximal"], + ["latest", "", "homebrew-macos-usrlocal-python3_xcode-standard"], + ["latest", "", "conda-forge-macos-minimal"], + ["latest", "", "conda-forge-macos-standard"], + ["latest", "", "conda-forge-macos-maximal"]] + type: string + extra_sage_packages: + description: 'Extra Sage packages to install as system packages' + type: string + default: "" + max_parallel: + type: number + default: 10 + free_disk_space: + default: false + type: boolean + # + # For use in upstream CIs. + # + upstream_artifact: + required: false + type: string + sage_repo: + required: false + type: string + sage_ref: + required: false + type: string + +jobs: + local-macos: + + runs-on: macos-${{ matrix.osversion_xcodeversion_toxenv[0] }} + strategy: + fail-fast: false + max-parallel: ${{ inputs.max_parallel }} + matrix: + osversion_xcodeversion_toxenv: ${{ fromJson(inputs.osversion_xcodeversion_toxenv_tuples) }} + env: + TOX_ENV: local-${{ matrix.osversion_xcodeversion_toxenv[2] }}${{ matrix.osversion_xcodeversion_toxenv[1] && format('-{0}', matrix.osversion_xcodeversion_toxenv[1]) }} + LOCAL_ARTIFACT_NAME: sage-local-commit-${{ github.sha }}-tox-local-${{ matrix.osversion_xcodeversion_toxenv[2] }}-macos-${{ matrix.osversion_xcodeversion_toxenv[0] }}${{ matrix.osversion_xcodeversion_toxenv[1] && format('-{0}', matrix.osversion_xcodeversion_toxenv[1]) }} + LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-local-${{ matrix.osversion_xcodeversion_toxenv[2] }}-macos-${{ matrix.osversion_xcodeversion_toxenv[0] }}${{ matrix.osversion_xcodeversion_toxenv[1] && format('-{0}', matrix.osversion_xcodeversion_toxenv[1]) }} + steps: + - name: Check out SageMath + uses: actions/checkout@v4 + with: + repository: ${{ inputs.sage_repo }} + ref: ${{ inputs.sage_ref }} + fetch-depth: 10000 + + - name: Install test prerequisites + run: | + brew install tox + - name: Download upstream artifact + uses: actions/download-artifact@v3 + with: + path: upstream + name: ${{ inputs.upstream_artifact }} + if: inputs.upstream_artifact + - name: Update Sage packages from upstream artifact + run: | + (export PATH=$(pwd)/build/bin:$PATH; (cd upstream && bash -x update-pkgs.sh) && git diff) + if: inputs.upstream_artifact + + - name: Merge CI fixes from sagemath/sage + run: | + .ci/merge-fixes.sh + env: + GH_TOKEN: ${{ github.token }} + + - uses: actions/download-artifact@v3 + with: + path: sage-local-artifact + name: ${{ env.LOCAL_ARTIFACT_NAME }} + if: contains(inputs.stage, '2') + - name: Extract sage-local artifact + # This is macOS tar -- cannot use --listed-incremental + run: | + export SAGE_LOCAL=$(pwd)/.tox/$TOX_ENV/local + .github/workflows/extract-sage-local.sh sage-local-artifact/sage-local-*.tar + if: contains(inputs.stage, '2') + - name: Build and test with tox + # We use a high parallelization on purpose in order to catch possible parallelization bugs in the build scripts. + # For doctesting, we use a lower parallelization to avoid timeouts. + run: | + case "${{ inputs.stage }}" in + 1) export TARGETS_PRE="all-sage-local" TARGETS="all-sage-local" TARGETS_OPTIONAL="build/make/Makefile" + ;; + 2) export TARGETS_PRE="all-sage-local" TARGETS="build doc-html" TARGETS_OPTIONAL="ptest" + ;; + 2-optional*) export TARGETS_PRE="build/make/Makefile" TARGETS="build/make/Makefile" + targets_pattern="${{ inputs.stage }}" + targets_pattern="${targets_pattern#2-optional-}" + export TARGETS_OPTIONAL=$( echo $(export PATH=build/bin:$PATH && sage-package list :optional: --has-file 'spkg-install.in|spkg-install|requirements.txt' --no-file huge|has_nonfree_dependencies | grep -v sagemath_doc | grep "^[$targets_pattern]" ) ) + ;; + 2-experimental*) export TARGETS_PRE="build/make/Makefile" TARGETS="build/make/Makefile" + targets_pattern="${{ inputs.stage }}" + targets_pattern="${targets_pattern#2-experimental-}" + export TARGETS_OPTIONAL=$( echo $(export PATH=build/bin:$PATH && sage-package list :experimental: --has-file 'spkg-install.in|spkg-install|requirements.txt' --no-file huge|has_nonfree_dependencies | grep -v sagemath_doc | grep "^[$targets_pattern]" ) ) + ;; + *) export TARGETS_PRE="${{ inputs.targets_pre }}" TARGETS="${{ inputs.targets }} TARGETS_OPTIONAL="${{ inputs.targets_optional }} + ;; + esac + MAKE="make -j12" tox -e $TOX_ENV -- SAGE_NUM_THREADS=4 $TARGETS + - name: Prepare logs artifact + run: | + mkdir -p "artifacts/$LOGS_ARTIFACT_NAME"; cp -r .tox/*/log "artifacts/$LOGS_ARTIFACT_NAME" + if: always() + - uses: actions/upload-artifact@v3 + with: + path: artifacts + name: ${{ env.LOGS_ARTIFACT_NAME }} + if: always() + - name: Print out logs for immediate inspection + # and markup the output with GitHub Actions logging commands + run: | + .github/workflows/scan-logs.sh "artifacts/$LOGS_ARTIFACT_NAME" + if: always() + - name: Prepare sage-local artifact + # This also includes the copies of homebrew or conda installed in the tox environment. + # We use absolute pathnames in the tar file. + # This is macOS tar -- cannot use --remove-files. + # We remove the $SAGE_LOCAL/lib64 link, which will be recreated by the next stage. + run: | + mkdir -p sage-local-artifact && (cd .tox/$TOX_ENV && rm -f "local/lib64" && tar -cf - $(pwd)) > sage-local-artifact/sage-${{ env.TOX_ENV }}-${{ inputs.stage }}.tar + if: contains(inputs.stage, '1') + - uses: actions/upload-artifact@v3 + with: + path: sage-local-artifact/sage-${{ env.TOX_ENV }}-${{ inputs.stage }}.tar + name: ${{ env.LOCAL_ARTIFACT_NAME }} + if: always() diff --git a/.github/workflows/push_to_docker_hub.yml b/.github/workflows/push_to_docker_hub.yml new file mode 100644 index 00000000000..eb36f3c979a --- /dev/null +++ b/.github/workflows/push_to_docker_hub.yml @@ -0,0 +1,126 @@ +name: Build Docker images and push to DockerHub + +on: + workflow_dispatch: + # Allow to run manually + branches: + - 'develop' + - 'docker_hub_gha' + push: + tags: + # Just create image on pushing a tag + - '*' + +jobs: + sagemath-dev: + name: Build Docker image on target make-build and push to DockerHub sagemath-dev + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set tag + # docker/metadata-action@v4 is not used since we need to distinguish + # between latest and develop tags + id: set_tag + run: | + git fetch --depth=1 origin +refs/tags/*:refs/tags/* + TAG_NAME=$(git tag --sort=v:refname | tail -1) + TAG="sagemath/sagemath-dev:$TAG_NAME" + TAG_LIST="$TAG, sagemath/sagemath-dev:develop" + TAG_LIST="$TAG" # don't tag develop until meaning of sagemath-dev is clear + echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV + echo "TAG=$TAG" >> $GITHUB_ENV + echo "TAG_LIST=$TAG_LIST" >> $GITHUB_ENV + + - name: Update Tag List + id: upd_tag_list + run: | + TAG_LIST="${{ env.TAG_LIST }}, sagemath/sagemath-dev:latest" + TAG_LIST="${{ env.TAG_LIST }}" # don't tag latest until meaning of sagemath-dev is clear + echo "TAG_LIST=$TAG_LIST" >> $GITHUB_ENV + if: "!contains(env.TAG_NAME, 'beta') && !contains(env.TAG_NAME, 'rc')" + + - name: Check env + run: | + echo ${{ env.TAG_NAME }} + echo ${{ env.TAG }} + echo ${{ env.TAG_LIST }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push make-build + uses: docker/build-push-action@v4 + with: + context: . + file: docker/Dockerfile + target: make-build # see the corresponding header-note + push: true + tags: ${{ env.TAG_LIST }} + cache-from: type=gha + cache-to: type=gha,mode=max + + sagemath: + needs: sagemath-dev + name: Build Docker image on target sagemath and push to DockerHub sagemath + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set tag + # docker/metadata-action@v4 is not used since we need to distinguish + # between latest and develop tags + id: set_tag + run: | + git fetch --depth=1 origin +refs/tags/*:refs/tags/* + TAG_NAME=$(git tag --sort=v:refname | tail -1) + TAG="sagemath/sagemath:$TAG_NAME" + TAG_LIST="$TAG, sagemath/sagemath:develop" + BASE="sagemath/sagemath-dev:$TAG_NAME" + echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV + echo "TAG=$TAG" >> $GITHUB_ENV + echo "TAG_LIST=$TAG_LIST" >> $GITHUB_ENV + echo "BASE=$BASE" >> $GITHUB_ENV + + - name: Update Tag List + id: upd_tag_list + run: | + TAG_LIST="${{ env.TAG_LIST }}, sagemath/sagemath:latest" + echo "TAG_LIST=$TAG_LIST" >> $GITHUB_ENV + if: "!contains(env.TAG_NAME, 'beta') && !contains(env.TAG_NAME, 'rc')" + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push sagemath + uses: docker/build-push-action@v4 + with: + context: . + file: docker/Dockerfile + build-args: | + MAKE_BUILD=${{ env.BASE }} + target: sagemath + push: true + tags: ${{ env.TAG_LIST }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/sync_labels.yml b/.github/workflows/sync_labels.yml new file mode 100644 index 00000000000..f9378d1fe9d --- /dev/null +++ b/.github/workflows/sync_labels.yml @@ -0,0 +1,57 @@ +# This workflow synchronizes groups of labels that correspond +# to items of selection list in Trac. It controls that in each +# such case there is just one label of the list present. +# Furthermore in the case of the state it checks the labels +# to coincide with the corresponding review state. + +name: Synchronize labels + +on: + issues: + types: [opened, reopened, closed, labeled, unlabeled] + pull_request_review: + types: [submitted] + pull_request_target: + types: [opened, reopened, closed, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled] + schedule: + # run cleaning of warning comments twice a day + - cron: '00 6,18 * * *' + +jobs: + synchronize: + if: | # check variables from repository settings to suspend the job + vars.SYNC_LABELS_ACTIVE == 'yes' && (! vars.SYNC_LABELS_IGNORE_EVENTS || ! contains(fromJSON(vars.SYNC_LABELS_IGNORE_EVENTS), github.event.action)) + runs-on: ubuntu-latest + steps: + # Checkout the Python script + - name: Checkout files + uses: Bhacaz/checkout-files@v2 + with: + files: .github/sync_labels.py + + # Perform synchronization + - name: Call script for synchronization + if: github.event.schedule == '' + run: | + chmod a+x .github/sync_labels.py + .github/sync_labels.py $ACTION $ISSUE_URL $PR_URL $ACTOR "$LABEL" "$REV_STATE" $LOG_LEVEL + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ACTION: ${{ github.event.action }} + ISSUE_URL: ${{ github.event.issue.html_url }} + PR_URL: ${{ github.event.pull_request.html_url }} + ACTOR: ${{ github.actor }} + LABEL: ${{ github.event.label.name }} + REV_STATE: ${{ github.event.review.state }} + LOG_LEVEL: ${{ vars.SYNC_LABELS_LOG_LEVEL }} # variable from repository settings, values can be "--debug", "--info" or "--warning" + + # Perform cleaning + - name: Call script for cleaning + if: github.event.schedule != '' + run: | + chmod a+x .github/sync_labels.py + .github/sync_labels.py $REPO_URL $LOG_LEVEL + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO_URL: ${{ github.event.repository.html_url }} + LOG_LEVEL: ${{ vars.SYNC_LABELS_LOG_LEVEL }} # variable from repository settings, values can be "--debug", "--info" or "--warning" diff --git a/.gitignore b/.gitignore index 2faf325a44c..efdbfa8f616 100644 --- a/.gitignore +++ b/.gitignore @@ -19,8 +19,10 @@ /config.status /configure /conftest* +/confdefs.h /m4/sage_spkg_configures.m4 +/m4/sage_spkg_versions*.m4 # no longer generated, but may still be in user worktrees /src/lib/pkgconfig @@ -174,14 +176,32 @@ build/bin/sage-build-env-config /pkgs/*/.tox /pkgs/sagemath-objects/setup.cfg +/pkgs/sagemath-bliss/setup.cfg +/pkgs/sagemath-coxeter3/setup.cfg +/pkgs/sagemath-mcqd/setup.cfg +/pkgs/sagemath-meataxe/setup.cfg +/pkgs/sagemath-sirocco/setup.cfg +/pkgs/sagemath-tdlib/setup.cfg /pkgs/sagemath-categories/setup.cfg /pkgs/sagemath-environment/setup.cfg /pkgs/sagemath-repl/setup.cfg /pkgs/sagemath-objects/pyproject.toml +/pkgs/sagemath-bliss/pyproject.toml +/pkgs/sagemath-coxeter3/pyproject.toml +/pkgs/sagemath-mcqd/pyproject.toml +/pkgs/sagemath-meataxe/pyproject.toml +/pkgs/sagemath-sirocco/pyproject.toml +/pkgs/sagemath-tdlib/pyproject.toml /pkgs/sagemath-categories/pyproject.toml /pkgs/sagemath-environment/pyproject.toml /pkgs/sagemath-repl/pyproject.toml /pkgs/sagemath-objects/requirements.txt +/pkgs/sagemath-bliss/requirements.txt +/pkgs/sagemath-coxeter3/requirements.txt +/pkgs/sagemath-mcqd/requirements.txt +/pkgs/sagemath-meataxe/requirements.txt +/pkgs/sagemath-sirocco/requirements.txt +/pkgs/sagemath-tdlib/requirements.txt /pkgs/sagemath-categories/requirements.txt /pkgs/sagemath-environment/requirements.txt /pkgs/sagemath-repl/requirements.txt diff --git a/.vscode/settings.json b/.vscode/settings.json index 58c9bc7af2b..b3079a7c4ee 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -27,7 +27,7 @@ "python.linting.enabled": true, // The following pycodestyle arguments are the same as the pycodestyle-minimal // tox environnment, see the file SAGE_ROOT/src/tox.ini - "python.linting.pycodestyleArgs": ["--select=E111,E306,E401,E701,E702,E703,W291,W391,W605,E711,E712,E713,E721,E722"], + "python.linting.pycodestyleArgs": ["--select= E111,E21,E222,E227,E25,E271,E303,E305,E306,E401,E502,E701,E702,E703,E71,E72,W291,W293,W391,W605"], "cSpell.words": [ "furo", "Conda", diff --git a/.zenodo.json b/.zenodo.json deleted file mode 100644 index 45c935970a7..00000000000 --- a/.zenodo.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "description": "Mirror of the Sage https://sagemath.org/ source tree", - "license": "other-open", - "title": "sagemath/sage: 10.0.beta1", - "version": "10.0.beta1", - "upload_type": "software", - "publication_date": "2023-02-19", - "creators": [ - { - "affiliation": "SageMath.org", - "name": "The SageMath Developers" - } - ], - "access_right": "open", - "related_identifiers": [ - { - "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/10.0.beta1", - "relation": "isSupplementTo" - }, - { - "scheme": "doi", - "identifier": "10.5281/zenodo.593563", - "relation": "isNewVersionOf" - } - ] -} diff --git a/.zenodo.json.in b/.zenodo.json.in deleted file mode 100644 index 744e020705a..00000000000 --- a/.zenodo.json.in +++ /dev/null @@ -1,27 +0,0 @@ -{ - "description": "Mirror of the Sage https://sagemath.org/ source tree", - "license": "other-open", - "title": "sagemath/sage: ${SAGE_VERSION}", - "version": "${SAGE_VERSION}", - "upload_type": "software", - "publication_date": "${SAGE_RELEASE_DATE}", - "creators": [ - { - "affiliation": "SageMath.org", - "name": "The SageMath Developers" - } - ], - "access_right": "open", - "related_identifiers": [ - { - "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/${SAGE_VERSION}", - "relation": "isSupplementTo" - }, - { - "scheme": "doi", - "identifier": "10.5281/zenodo.593563", - "relation": "isNewVersionOf" - } - ] -} diff --git a/CITATION.cff b/CITATION.cff index d97e13cb2cb..7c31fd13f05 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -4,8 +4,8 @@ title: SageMath abstract: SageMath is a free open-source mathematics software system. authors: - name: "The SageMath Developers" -version: 9.5 +version: 10.2.beta5 doi: 10.5281/zenodo.593563 -date-released: 2022-01-18 +date-released: 2023-09-27 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/CITATION.cff.in b/CITATION.cff.in new file mode 100644 index 00000000000..bf7d5d3e58c --- /dev/null +++ b/CITATION.cff.in @@ -0,0 +1,11 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +title: SageMath +abstract: SageMath is a free open-source mathematics software system. +authors: +- name: "The SageMath Developers" +version: ${SAGE_VERSION} +doi: 10.5281/zenodo.593563 +date-released: ${SAGE_RELEASE_DATE} +repository-code: "https://github.com/sagemath/sage" +url: "https://www.sagemath.org/" diff --git a/COPYING.txt b/COPYING.txt index a785477fb4f..d5c28eacead 100644 --- a/COPYING.txt +++ b/COPYING.txt @@ -51,7 +51,6 @@ elliptic_curves None (database) extcode GPLv2+ fflas_ffpack LGPLv2.1+ flint GPLv2+ -flintqs GPLv2+ fplll LGPLv2.1+ freetype FreeType License (similar to BSD; see below) gap GPLv2+ diff --git a/Makefile b/Makefile index 008d6ff2221..11a7b77665a 100644 --- a/Makefile +++ b/Makefile @@ -80,42 +80,6 @@ download: dist: build/make/Makefile ./sage --sdist -pypi-sdists: sage_setup - ./sage --sh build/pkgs/sage_conf/spkg-src - ./sage --sh build/pkgs/sage_sws2rst/spkg-src - ./sage --sh build/pkgs/sage_docbuild/spkg-src - ./sage --sh build/pkgs/sage_setup/spkg-src - ./sage --sh build/pkgs/sagelib/spkg-src - ./sage --sh build/pkgs/sagemath_objects/spkg-src - ./sage --sh build/pkgs/sagemath_categories/spkg-src - ./sage --sh build/pkgs/sagemath_environment/spkg-src - ./sage --sh build/pkgs/sagemath_repl/spkg-src - @echo "Built sdists are in upstream/" - -# Ensuring wheels are present, even for packages that may have been installed -# as editable. Until we have better uninstallation of script packages, we -# just remove the timestamps, which will lead to rebuilds of the packages. -PYPI_WHEEL_PACKAGES = sage_sws2rst sage_setup sagemath_environment sagemath_objects sagemath_repl sagemath_categories -pypi-wheels: - for a in $(PYPI_WHEEL_PACKAGES); do \ - rm -f venv/var/lib/sage/installed/$$a-*; \ - done - for a in $(PYPI_WHEEL_PACKAGES); do \ - $(MAKE) SAGE_EDITABLE=no SAGE_WHEELS=yes $$a; \ - done - @echo "Built wheels are in venv/var/lib/sage/wheels/" - -# sage_docbuild is here, not in PYPI_WHEEL_PACKAGES, because it depends on sagelib -WHEEL_PACKAGES = $(PYPI_WHEEL_PACKAGES) sage_conf sagelib sage_docbuild -wheels: - for a in $(WHEEL_PACKAGES); do \ - rm -f venv/var/lib/sage/installed/$$a-*; \ - done - for a in $(WHEEL_PACKAGES); do \ - $(MAKE) SAGE_EDITABLE=no SAGE_WHEELS=yes $$a; \ - done - @echo "Built wheels are in venv/var/lib/sage/wheels/" - ############################################################################### # Cleaning up ############################################################################### @@ -380,7 +344,6 @@ list: @$(MAKE) --silent -f build/make/Makefile SAGE_PKGCONFIG=dummy $@ .PHONY: default build dist install micro_release \ - pypi-sdists pypi-wheels wheels \ misc-clean bdist-clean distclean bootstrap-clean maintainer-clean \ test check testoptional testall testlong testoptionallong testallong \ ptest ptestoptional ptestall ptestlong ptestoptionallong ptestallong \ diff --git a/README.md b/README.md index 1233f17de73..aee0c3a0fbc 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,16 @@ -<a href="https://sagemath.org"><img src="src/doc/common/themes/sage/static/logo_sagemath_black.svg" height="60" align="right" /></a> +<a href="https://sagemath.org"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="src/doc/common/static/logo_sagemath_white.svg"> + <img src="src/doc/common/static/logo_sagemath_black.svg" height="60" align="left"> + </picture> +</a> # Sage: Open Source Mathematical Software > "Creating a Viable Open Source Alternative to > Magma, Maple, Mathematica, and MATLAB" -> Copyright (C) 2005-2022 The Sage Development Team +> Copyright (C) 2005-2023 The Sage Development Team https://www.sagemath.org @@ -53,12 +58,14 @@ mailing list](https://groups.google.com/group/sage-devel). -------------------------------- The preferred way to run Sage on Windows is using the [Windows Subsystem for -Linux](https://docs.microsoft.com/en-us/windows/wsl/faq), which allows +Linux](https://docs.microsoft.com/en-us/windows/wsl/faq), a.k.a. WSL, which allows you to install a standard Linux distribution such as Ubuntu within -your Windows. Then all instructions for installation in Linux apply. +your Windows. Make sure you allocate WSL sufficient RAM; 5GB is known to work, while +2GB might be not enough for building Sage from source. +Then all instructions for installation in Linux apply. As an alternative, you can also run Linux on Windows using Docker (see -above) or other virtualization solutions. +below) or other virtualization solutions. [macOS] Preparing the Platform ------------------------------ @@ -182,8 +189,8 @@ in the Installation Guide. 3. [Linux, WSL] Install the required minimal build prerequisites. - - Compilers: `gcc`, `gfortran`, `g++` (GCC 8.x to 12.x and recent - versions of Clang (LLVM) are supported). + - Compilers: `gcc`, `gfortran`, `g++` (GCC versions from 8.4.0 to 13.x + and recent versions of Clang (LLVM) are supported). See [build/pkgs/gcc/SPKG.rst](build/pkgs/gcc/SPKG.rst) and [build/pkgs/gfortran/SPKG.rst](build/pkgs/gfortran/SPKG.rst) for a discussion of suitable compilers. @@ -194,7 +201,7 @@ in the Installation Guide. more details. - Python 3.4 or later, or Python 2.7, a full installation including - `urllib`; but ideally version 3.8.x, 3.9.x, or 3.10.x, which + `urllib`; but ideally version 3.9.x, 3.10.x, or 3.11.x, which will avoid having to build Sage's own copy of Python 3. See [build/pkgs/python3/SPKG.rst](build/pkgs/python3/SPKG.rst) for more details. @@ -394,6 +401,32 @@ in the Installation Guide. or JupyterLab installation, as described in [section "Launching SageMath"](https://doc.sagemath.org/html/en/installation/launching.html) in the installation manual. + +Alternative Installation using PyPI +--------------- + +For installation of `sage` in python using `pip` you need to install `sagemath-standard`. First, activate your python virtual environment and follow these steps: + + $ python3 -m pip install sage_conf + $ ls $(sage-config SAGE_SPKG_WHEELS) + $ python3 -m pip install $(sage-config SAGE_SPKG_WHEELS)/*.whl + $ python3 -m pip install sagemath-standard + +You need to install `sage_conf`, a wheelhouse of various python packages. You can list the wheels using `ls $(sage-config SAGE_SPKG_WHEELS)`. After manual installation of these wheels, you can install the sage library, `sagemath-standard`. + +**NOTE:** You can find `sage` and `sagemath` pip packages but with these packages, you will encounter `ModuleNotFoundError`. + +SageMath Docker images +---------------------- + +[![Docker Status](http://dockeri.co/image/sagemath/sagemath)](https://hub.docker.com/r/sagemath/sagemath) + +SageMath is available on Docker Hub and can be downloaded by: +``` bash +docker pull sagemath/sagemath +``` + +Currently, only stable versions are kept up to date. Troubleshooting --------------- diff --git a/VERSION.txt b/VERSION.txt index 8b731a891fa..3b70b866392 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.0.beta1, Release Date: 2023-02-19 +SageMath version 10.2.beta5, Release Date: 2023-09-27 diff --git a/bootstrap b/bootstrap index 48c4801d4b5..aa5755cfc63 100755 --- a/bootstrap +++ b/bootstrap @@ -35,10 +35,16 @@ CONFVERSION=$(cat $PKG/package-version.txt) bootstrap () { - if [ "${BOOTSTRAP_QUIET}" = "no" ]; then - echo "bootstrap:$LINENO: installing 'm4/sage_spkg_configures.m4'" - fi - rm -f m4/sage_spkg_configures.m4 + for a in m4/sage_spkg_configures.m4 m4/sage_spkg_versions.m4 m4/sage_spkg_versions_toml.m4; do + if [ "${BOOTSTRAP_QUIET}" = "no" ]; then + echo "bootstrap:$LINENO: installing '"$a"'" + fi + rm -f $a + echo "# Generated by SAGE_ROOT/bootstrap; do not edit" > $a + done + for a in m4/sage_spkg_versions.m4 m4/sage_spkg_versions_toml.m4; do + echo 'changequote(`>>>'"'"', `<<<'"')dnl" >> $a + done spkg_configures="" # initialize SAGE_ENABLE... options for standard packages for pkgname in $(sage-package list :standard: | sort); do @@ -92,17 +98,26 @@ SAGE_SPKG_CONFIGURE_$(echo ${pkgname} | tr '[a-z]' '[A-Z]')" if test -f "$DIR/requirements.txt" -o -f "$DIR/install-requires.txt"; then # A Python package SPKG_TREE_VAR=SAGE_VENV + echo "define(>>>SPKG_INSTALL_REQUIRES_${pkgname}<<<, >>>$(echo $(ENABLE_SYSTEM_SITE_PACKAGES=yes sage-get-system-packages install-requires ${pkgname}))<<<)dnl" >> m4/sage_spkg_versions.m4 + echo "define(>>>SPKG_INSTALL_REQUIRES_${pkgname}<<<, >>>$(echo $(ENABLE_SYSTEM_SITE_PACKAGES=yes sage-get-system-packages install-requires-toml ${pkgname}))<<<)dnl" >> m4/sage_spkg_versions_toml.m4 fi fi spkg_configures="$spkg_configures SAGE_SPKG_FINALIZE([$pkgname], [$pkgtype], [$SPKG_SOURCE], [$SPKG_TREE_VAR])" done echo "$spkg_configures" >> m4/sage_spkg_configures.m4 + for a in m4/sage_spkg_versions.m4 m4/sage_spkg_versions_toml.m4; do + echo 'changequote(>>>`<<<, >>>'"'"'<<<)dnl' >> $a + done - for pkgname in $(sage-package list --has-file bootstrap); do - (cd build/pkgs/$pkgname && ./bootstrap) || exit 1 + for pkgname in $(sage-package list --has-file bootstrap "$@"); do + (cd build/pkgs/$pkgname && if [ -x bootstrap ]; then ./bootstrap; else echo >&2 "bootstrap:$LINENO: Nothing to do for $pkgname"; fi) || exit 1 done + if [ $# != 0 ]; then + return + fi + # Default to no filter if "-q" was not passed. QUIET_SED_FILTER="" if [ "${BOOTSTRAP_QUIET}" = "yes" ]; then @@ -115,7 +130,6 @@ SAGE_SPKG_FINALIZE([$pkgname], [$pkgtype], [$SPKG_SOURCE], [$SPKG_TREE_VAR])" # stdout alone. Basically we swap the two descriptors using a # third, filter, and then swap them back. ./bootstrap-conda && \ - src/doc/bootstrap && \ aclocal -I m4 && \ automake --add-missing --copy build/make/Makefile-auto 3>&1 1>&2 2>&3 \ | sed "${QUIET_SED_FILTER}" 3>&1 1>&2 2>&3 && \ @@ -225,7 +239,7 @@ save () { usage () { - echo >&2 "Usage: $0 [-d|-D|-s] [-u <URL>] [-h] [-q]" + echo >&2 "Usage: $0 [-d|-D|-s] [-u <URL>] [-h] [-q] [SPKG...]" echo >&2 "" echo >&2 "Options:" echo >&2 " -d fall back to downloading (released versions only)" @@ -258,6 +272,7 @@ do ?) usage; exit 2;; esac done +shift $(($OPTIND - 1)) export BOOTSTRAP_QUIET CONFBALL="upstream/configure-$CONFVERSION.tar.gz" @@ -267,14 +282,22 @@ if [ $DOWNLOAD$SAVE = yesyes ]; then exit 2 fi -# Start cleanly (it's not a problem if this fails) +if [ $# != 0 -a $DOWNLOAD$ALWAYSDOWNLOAD$SAVE != nonono ]; then + echo >&2 "$0: Cannot combine -d, -D, -s, -u with SPKG arguments" + usage + exit 2 +fi + +# Start cleanly when a full bootstrap is happening (it's not a problem if this fails) # POSIX supports two separate incompatible formats for the MAKEFLAGS # variable, so instead of guessing, we simply define our own variable # to optionally pass an "-s" (silent) flag to Make. -MAKE_SILENT="" -[ "${BOOTSTRAP_QUIET}" = "yes" ] && MAKE_SILENT="-s" -$MAKE ${MAKE_SILENT} bootstrap-clean 2>/dev/null -mkdir config 2>/dev/null +if [ $# = 0 ]; then + MAKE_SILENT="" + [ "${BOOTSTRAP_QUIET}" = "yes" ] && MAKE_SILENT="-s" + $MAKE ${MAKE_SILENT} bootstrap-clean 2>/dev/null +fi +mkdir -p config 2>/dev/null if [ $ALWAYSDOWNLOAD = yes ]; then if [ -n "$CONFTARBALL_URL" ]; then @@ -291,7 +314,7 @@ if [ $ALWAYSDOWNLOAD = yes ]; then bootstrap_download || exit $? fi else - bootstrap + bootstrap "$@" fi if [ $SAVE = yes ]; then diff --git a/bootstrap-conda b/bootstrap-conda index 9ba4b50ab6f..ed4bb9e0d08 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -11,14 +11,13 @@ STRIP_COMMENTS="sed s/#.*//;" shopt -s extglob DEVELOP_SPKG_PATTERN="@(_develop$(for a in $(head -n 1 build/pkgs/_develop/dependencies); do echo -n "|"$a; done))" - BOOTSTRAP_PACKAGES=$(echo $(${STRIP_COMMENTS} build/pkgs/_bootstrap/distros/conda.txt)) SYSTEM_PACKAGES= OPTIONAL_SYSTEM_PACKAGES= SAGELIB_SYSTEM_PACKAGES= SAGELIB_OPTIONAL_SYSTEM_PACKAGES= DEVELOP_SYSTEM_PACKAGES= -for PKG_BASE in $(sage-package list --has-file distros/conda.txt); do +for PKG_BASE in $(sage-package list --has-file distros/conda.txt --exclude _sagemath); do PKG_SCRIPTS=build/pkgs/$PKG_BASE SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/distros/conda.txt PKG_TYPE=$(cat $PKG_SCRIPTS/type) @@ -37,10 +36,13 @@ for PKG_BASE in $(sage-package list --has-file distros/conda.txt); do ;; esac else - case "$PKG_TYPE" in - standard) + case "$PKG_BASE:$PKG_TYPE" in + *:standard) SAGELIB_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" ;; + $DEVELOP_SPKG_PATTERN:*) + DEVELOP_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" + ;; *) SAGELIB_OPTIONAL_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" ;; diff --git a/build/bin/sage-build-env-config.in b/build/bin/sage-build-env-config.in index b00fd2a3f99..7d6cd113bf9 100644 --- a/build/bin/sage-build-env-config.in +++ b/build/bin/sage-build-env-config.in @@ -53,9 +53,13 @@ export SAGE_PARI_CFG="@SAGE_PARI_CFG@" export SAGE_GLPK_PREFIX="@SAGE_GLPK_PREFIX@" export SAGE_FREETYPE_PREFIX="@SAGE_FREETYPE_PREFIX@" +export SAGE_PIP_INSTALL_FLAGS="@SAGE_PIP_INSTALL_FLAGS@" export SAGE_SUITESPARSE_PREFIX="@SAGE_SUITESPARSE_PREFIX@" export SAGE_CONFIGURE_FFLAS_FFPACK="@SAGE_CONFIGURE_FFLAS_FFPACK@" export CONFIGURED_SAGE_EDITABLE="@SAGE_EDITABLE@" export CONFIGURED_SAGE_WHEELS="@SAGE_WHEELS@" + +export ENABLE_SYSTEM_SITE_PACKAGES="@ENABLE_SYSTEM_SITE_PACKAGES@" +export PYTHON_MINOR="@PYTHON_MINOR@" diff --git a/build/bin/sage-clone-source b/build/bin/sage-clone-source index 1b71e81999a..65dc1ffa93f 100755 --- a/build/bin/sage-clone-source +++ b/build/bin/sage-clone-source @@ -31,11 +31,13 @@ CONFBALL="$SRC/upstream/configure-$CONFVERSION.tar.gz" rm -rf "$DST" mkdir -p "$DST" -git clone --origin trac "$SRC" "$DST" +git clone --origin upstream "$SRC" "$DST" cd "$DST" -git remote set-url trac "$SAGE_REPO_ANONYMOUS" -git remote set-url --push trac "$SAGE_REPO_AUTHENTICATED" +git remote set-url upstream "$SAGE_REPO_ANONYMOUS" +git remote set-url --push upstream "do not push to upstream" +git remote add trac https://github.com/sagemath/sagetrac-mirror.git +git remote set-url --push trac "do not push to trac" # Save space git gc --aggressive --prune=now diff --git a/build/bin/sage-dist-helpers b/build/bin/sage-dist-helpers index 4eac9626ffa..67a2201d31f 100644 --- a/build/bin/sage-dist-helpers +++ b/build/bin/sage-dist-helpers @@ -325,7 +325,11 @@ sdh_store_wheel() { } sdh_store_and_pip_install_wheel() { - local pip_options="" + # The $SAGE_PIP_INSTALL_FLAGS variable is set by sage-build-env-config. + # We skip sanity checking its contents since you should either let sage + # decide what it contains, or really know what you are doing. + local pip_options="${SAGE_PIP_INSTALL_FLAGS}" + while [ $# -gt 0 ]; do case $1 in -*) pip_options="$pip_options $1" diff --git a/build/bin/sage-get-system-packages b/build/bin/sage-get-system-packages index b5153c53694..c8b9314c3fe 100755 --- a/build/bin/sage-get-system-packages +++ b/build/bin/sage-get-system-packages @@ -1,4 +1,5 @@ #!/bin/sh + SYSTEM=$1 if [ -z "$SYSTEM" ]; then echo >&2 "usage: $0 {auto|debian|arch|conda|pip|...} SPKGS..." @@ -10,18 +11,19 @@ SPKGS="$*" if [ -z "$SAGE_ROOT" ]; then SAGE_ROOT=`pwd` fi + case "$SYSTEM" in install-requires) - # Collect install-requires.txt and output it in the format + # Collect install-requires.txt (falling back to requirements.txt) and output it in the format # needed by setup.cfg [options] install_requires= - SYSTEM_PACKAGES_FILE_NAMES="install-requires.txt" + SYSTEM_PACKAGES_FILE_NAMES="install-requires.txt requirements.txt" STRIP_COMMENTS="sed s/#.*//;/^[[:space:]]*$/d;" COLLECT= ;; install-requires-toml) - # Collect install-requires.txt and output it in the format + # Collect install-requires.txt (falling back to requirements.txt) and output it in the format # needed by pyproject.toml [build-system] requires= - SYSTEM_PACKAGES_FILE_NAMES="install-requires.txt" + SYSTEM_PACKAGES_FILE_NAMES="install-requires.txt requirements.txt" STRIP_COMMENTS="sed s/#.*//;/^[[:space:]]*$/d;s/^/'/;s/$/',/;" COLLECT= ;; @@ -44,6 +46,18 @@ case "$SYSTEM" in ;; esac for PKG_BASE in $SPKGS; do + + # Skip this package if it uses the SAGE_PYTHON_PACKAGE_CHECK + # macro and if --enable-system-site-packages was NOT passed + # to ./configure (or if ./configure has not yet been run). + SPKG_CONFIGURE="${SAGE_ROOT}/build/pkgs/${PKG_BASE}/spkg-configure.m4" + if [ -z "${ENABLE_SYSTEM_SITE_PACKAGES}" ]; then + if grep -q SAGE_PYTHON_PACKAGE_CHECK "${SPKG_CONFIGURE}" 2>/dev/null; + then + continue; + fi + fi + for NAME in $SYSTEM_PACKAGES_FILE_NAMES; do SYSTEM_PACKAGES_FILE="$SAGE_ROOT"/build/pkgs/$PKG_BASE/$NAME if [ -f $SYSTEM_PACKAGES_FILE ]; then diff --git a/build/bin/sage-logger b/build/bin/sage-logger index 1682ccbc079..1d8d92c0c75 100755 --- a/build/bin/sage-logger +++ b/build/bin/sage-logger @@ -89,8 +89,9 @@ else # Redirect stdout and stderr to a subprocess running tee. # We trap SIGINT such that SIGINT interrupts the main process being # run, not the logging. + ( exec 2>&1; eval "$cmd" ) | \ - ( trap '' SIGINT; tee -a "$logfile" | $SED ) + ( trap '' SIGINT; if [ -n "$GITHUB_ACTIONS" -a -n "$prefix" ]; then echo "::group::${logname}"; fi; tee -a "$logfile" | $SED; if [ -n "$GITHUB_ACTIONS" -a -n "$prefix" ]; then echo "::endgroup::"; fi ) pipestatus=(${PIPESTATUS[*]}) diff --git a/build/bin/sage-spkg-info b/build/bin/sage-spkg-info index 4e53139fa7e..e43e516dc5b 100755 --- a/build/bin/sage-spkg-info +++ b/build/bin/sage-spkg-info @@ -9,7 +9,7 @@ PKG_SCRIPTS="$SAGE_ROOT/build/pkgs/$PKG_BASE" for ext in rst txt; do SPKG_FILE="$PKG_SCRIPTS/SPKG.$ext" if [ -f "$SPKG_FILE" ]; then - cat "$SPKG_FILE" + sed "1,3s/^ *Sage: Open Source Mathematics Software:/$PKG_BASE:/" "$SPKG_FILE" break fi done @@ -110,17 +110,19 @@ if [ -z "$system" ]; then echo "(none known)" else echo - if [ -f "$PKG_SCRIPTS"/spkg-configure.m4 ]; then - echo "If the system package is installed, ./configure will check whether it can be used." - else - echo "However, these system packages will not be used for building Sage" - if [ -f "$PKG_SCRIPTS"/install-requires.txt ]; then - echo "because using Python site-packages is not supported by the Sage distribution;" - echo "see https://github.com/sagemath/sage/issues/29023" + SPKG_CONFIGURE="${PKG_SCRIPTS}/spkg-configure.m4" + if [ -f "${SPKG_CONFIGURE}" ]; then + if grep -q SAGE_PYTHON_PACKAGE_CHECK "${SPKG_CONFIGURE}"; then + echo "If the system package is installed and if the (experimental) option" + echo "--enable-system-site-packages is passed to ./configure, then ./configure" + echo "will check if the system package can be used." else - echo "because spkg-configure.m4 has not been written for this package;" - echo "see https://github.com/sagemath/sage/issues/27330" + echo "If the system package is installed, ./configure will check if it can be used." fi + else + echo "However, these system packages will not be used for building Sage" + echo "because spkg-configure.m4 has not been written for this package;" + echo "see https://github.com/sagemath/sage/issues/27330" fi fi echo diff --git a/build/bin/write-dockerfile.sh b/build/bin/write-dockerfile.sh index 14cbaf786eb..6980f6b6e4b 100755 --- a/build/bin/write-dockerfile.sh +++ b/build/bin/write-dockerfile.sh @@ -5,7 +5,7 @@ set -e SYSTEM="${1:-debian}" shopt -s extglob -SAGE_PACKAGE_LIST_ARGS="${2:- --has-file=spkg-configure.m4 :standard:}" +SAGE_PACKAGE_LIST_ARGS="${2:-:standard:}" WITH_SYSTEM_SPKG="${3:-yes}" IGNORE_MISSING_SYSTEM_PACKAGES="${4:-no}" EXTRA_SAGE_PACKAGES="${5:-_bootstrap}" @@ -15,17 +15,13 @@ SAGE_ROOT=. export PATH="$SAGE_ROOT"/build/bin:$PATH SYSTEM_PACKAGES=$EXTRA_SYSTEM_PACKAGES CONFIGURE_ARGS="--enable-option-checking " -for PKG_BASE in $(sage-package list --has-file=distros/$SYSTEM.txt $SAGE_PACKAGE_LIST_ARGS) $EXTRA_SAGE_PACKAGES; do - PKG_SCRIPTS="$SAGE_ROOT"/build/pkgs/$PKG_BASE - if [ -d $PKG_SCRIPTS ]; then - SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/distros/$SYSTEM.txt - PKG_SYSTEM_PACKAGES=$(echo $(${STRIP_COMMENTS} $SYSTEM_PACKAGES_FILE)) - if [ -n "PKG_SYSTEM_PACKAGES" ]; then - SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" - if [ -f $PKG_SCRIPTS/spkg-configure.m4 ]; then - CONFIGURE_ARGS+="--with-system-$PKG_BASE=${WITH_SYSTEM_SPKG} " - fi - fi +for SPKG in $(sage-package list --has-file=spkg-configure.m4 $SAGE_PACKAGE_LIST_ARGS) $EXTRA_SAGE_PACKAGES; do + SYSTEM_PACKAGE=$(sage-get-system-packages $SYSTEM $SPKG | sed 's/${PYTHON_MINOR}/'${PYTHON_MINOR}'/g') + if [ -n "${SYSTEM_PACKAGE}" ]; then + # SYSTEM_PACKAGE can be empty if, for example, the environment + # variable ENABLE_SYSTEM_SITE_PACKAGES is empty. + SYSTEM_PACKAGES+=" ${SYSTEM_PACKAGE}" + CONFIGURE_ARGS+="--with-system-${SPKG}=${WITH_SYSTEM_SPKG} " fi done echo "# Automatically generated by SAGE_ROOT/build/bin/write-dockerfile.sh" diff --git a/build/make/Makefile.in b/build/make/Makefile.in index 84f6f877e3d..cc004d08c3c 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -128,7 +128,29 @@ PIP_PACKAGES = @SAGE_PIP_PACKAGES@ # Packages that use the 'script' package build rules SCRIPT_PACKAGES = @SAGE_SCRIPT_PACKAGES@ - +# Packages for which we build wheels for PyPI +PYPI_WHEEL_PACKAGES = \ + sage_sws2rst \ + sage_setup \ + sagemath_environment \ + sagemath_objects \ + sagemath_repl \ + sagemath_categories \ + sagemath_bliss \ + sagemath_mcqd \ + sagemath_tdlib \ + sagemath_coxeter3 \ + sagemath_sirocco \ + sagemath_meataxe + +# sage_docbuild is here, not in PYPI_WHEEL_PACKAGES, because it depends on sagelib +WHEEL_PACKAGES = $(PYPI_WHEEL_PACKAGES) \ + sage_conf \ + sagelib \ + sage_docbuild + +# Packages for which build sdists for PyPI +PYPI_SDIST_PACKAGES = $(WHEEL_PACKAGES) # Generate the actual inst_<pkgname> variables; for each package that is # actually built this generates a line like: @@ -198,17 +220,20 @@ SAGE_I_TARGETS = sagelib doc # Tell make not to look for files with these names: .PHONY: all all-sage all-toolchain all-build all-sageruntime \ all-start build-start base toolchain toolchain-deps base-toolchain \ + pypi-sdists pypi-wheels wheels \ sagelib \ doc doc-html doc-html-jsmath doc-html-mathjax doc-pdf \ doc-uninstall \ python3_venv _clean-broken-gcc PYTHON_FOR_VENV = @PYTHON_FOR_VENV@ +PYTHON_MINOR = @PYTHON_MINOR@ +SAGE_VENV_FLAGS = @SAGE_VENV_FLAGS@ ifneq ($(PYTHON_FOR_VENV),) # Special rule for making the Python virtualenv from the system Python (Python # 3 only). $(PYTHON) is set in Makefile to python3_venv. -# Thus $(inst_python3_venv) will be the dependency of every Python package. +# Thus $(inst_python3_venv) will an (order-only) dependency of every Python package. # # TODO: If we reconfigure to build our own Python after having used the system # Python, files installed to create the virtualenv should be *removed*. That @@ -216,10 +241,15 @@ ifneq ($(PYTHON_FOR_VENV),) ifeq ($(PYTHON),python3) PYTHON = python3_venv endif -inst_python3_venv = $(SAGE_VENV)/pyvenv.cfg +inst_python3_venv = $(SAGE_VENV)/$(SPKG_INST_RELDIR)/python3_venv-3.$(PYTHON_MINOR)-$(subst /,-,$(PYTHON_FOR_VENV))$(findstring --system-site-packages,$(SAGE_VENV_FLAGS)) + +$(SAGE_VENV)/$(SPKG_INST_RELDIR): + mkdir -p "$@" -$(inst_python3_venv): - $(PYTHON_FOR_VENV) $(SAGE_ROOT)/build/bin/sage-venv "$(SAGE_VENV)" +$(inst_python3_venv): | $(SAGE_VENV)/$(SPKG_INST_RELDIR) + $(PYTHON_FOR_VENV) $(SAGE_ROOT)/build/bin/sage-venv $(SAGE_VENV_FLAGS) "$(SAGE_VENV)" + rm -f "$(SAGE_VENV)/$(SPKG_INST_RELDIR)"/python3_venv-* + touch "$@" endif # Build everything and start Sage. @@ -418,6 +448,25 @@ list-broken-packages: auditwheel_or_delocate echo >&2 "$$fix_broken_packages"; \ fi +pypi-sdists: $(PYPI_SDIST_PACKAGES:%=%-sdist) + @echo "Built sdists are in upstream/" + +# Ensuring wheels are present, even for packages that may have been installed +# as editable. Until we have better uninstallation of script packages, we +# just remove the timestamps, which will lead to rebuilds of the packages. +pypi-wheels: + for a in $(PYPI_WHEEL_PACKAGES); do \ + rm -f $(SAGE_VENV)/var/lib/sage/installed/$$a-*; \ + done + $(MAKE_REC) SAGE_EDITABLE=no SAGE_WHEELS=yes $(PYPI_WHEEL_PACKAGES) + @echo "Built wheels are in venv/var/lib/sage/wheels/" + +wheels: + for a in $(WHEEL_PACKAGES); do \ + rm -f $(SAGE_VENV)/var/lib/sage/installed/$$a-*; \ + done + $(MAKE_REC) SAGE_EDITABLE=no SAGE_WHEELS=yes $(WHEEL_PACKAGES) + @echo "Built wheels are in venv/var/lib/sage/wheels/" #============================================================================== # Setting SAGE_CHECK... variables @@ -549,6 +598,8 @@ $$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2): $(3) $(1): $$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2) +$(1)-ensure: $(inst_$(1)) + $(1)-$(4)-no-deps: +@if [ -z '$$($(4))' ]; then \ echo "Error: The installation tree $(4) has been disabled" 2>&1; \ @@ -607,6 +658,8 @@ $(1)-build-deps: $(2) $(1): $(2) +$(MAKE_REC) $(1)-no-deps +$(1)-ensure: $(inst_$(1)) + $(1)-no-deps: $(AM_V_at)sage-logger -p 'sage --pip install -r "$$(SAGE_ROOT)/build/pkgs/$(1)/requirements.txt"' '$$(SAGE_LOGS)/$(1).log' @@ -663,6 +716,8 @@ $$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2): $(3) $(1): $$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2) +$(1)-ensure: $(inst_$(1)) + $(1)-$(4)-no-deps: $(PLUS)@if [ -z '$$($(4))' ]; then \ echo "Error: The installation tree $(4) has been disabled" 2>&1; \ @@ -711,6 +766,13 @@ $(1)-uninstall: $(1)-$(4)-uninstall $(1)-clean: $(1)-uninstall +$(1)-sdist: FORCE python_build sage_setup cython + $(AM_V_at) cd '$$(SAGE_ROOT)' && \ + . '$$(SAGE_ROOT)/src/bin/sage-src-env-config' && \ + . '$$(SAGE_ROOT)/src/bin/sage-env-config' && \ + . '$$(SAGE_ROOT)/src/bin/sage-env' && \ + '$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-src' + # Recursive tox invocation (note - we do not set the environment here). # Setting SAGE_SPKG_WHEELS is for the benefit of sagelib's tox.ini $(1)-tox-%: FORCE diff --git a/build/pkgs/4ti2/checksums.ini b/build/pkgs/4ti2/checksums.ini index 22971f1bd4d..275cf157a6a 100644 --- a/build/pkgs/4ti2/checksums.ini +++ b/build/pkgs/4ti2/checksums.ini @@ -1,4 +1,5 @@ tarball=4ti2-VERSION.tar.gz -sha1=9a9a6913bcd52b667355a7df7fa954ca101054cb -md5=90def0d6b01a0247e439356777467497 -cksum=439147307 +sha1=3d41f30ea3ef94c293eae30c087494269fc1a6b9 +md5=1215872325ddfc561865ecb22b2bccb2 +cksum=2439180289 +upstream_url=https://github.com/4ti2/4ti2/releases/download/Release_1_6_10/4ti2-1.6.10.tar.gz diff --git a/build/pkgs/4ti2/package-version.txt b/build/pkgs/4ti2/package-version.txt index ba598ce6877..1df3b822c71 100644 --- a/build/pkgs/4ti2/package-version.txt +++ b/build/pkgs/4ti2/package-version.txt @@ -1 +1 @@ -1.6.7.p0 +1.6.10 diff --git a/build/pkgs/_bootstrap/distros/conda.txt b/build/pkgs/_bootstrap/distros/conda.txt index b5d2db8cfb2..5fe960ac3a0 100644 --- a/build/pkgs/_bootstrap/distros/conda.txt +++ b/build/pkgs/_bootstrap/distros/conda.txt @@ -1,2 +1,5 @@ # Packages needed for ./bootstrap -autoconf automake libtool +autoconf +automake +libtool +pkg-config diff --git a/build/pkgs/_bootstrap/distros/slackware.txt b/build/pkgs/_bootstrap/distros/slackware.txt index 4bd0e6e12b5..01f7ebb4e83 100644 --- a/build/pkgs/_bootstrap/distros/slackware.txt +++ b/build/pkgs/_bootstrap/distros/slackware.txt @@ -2,3 +2,4 @@ autoconf automake libtool +pkg-config diff --git a/build/pkgs/_bootstrap/distros/void.txt b/build/pkgs/_bootstrap/distros/void.txt index 159333b4216..6490cf773e7 100644 --- a/build/pkgs/_bootstrap/distros/void.txt +++ b/build/pkgs/_bootstrap/distros/void.txt @@ -1,3 +1,4 @@ # Packages needed for ./bootstrap autoconf automake libtool xtools mk-configure +pkg-config diff --git a/build/pkgs/_prereq/distros/conda.txt b/build/pkgs/_prereq/distros/conda.txt index a02a39e73bf..d76388ce7bb 100644 --- a/build/pkgs/_prereq/distros/conda.txt +++ b/build/pkgs/_prereq/distros/conda.txt @@ -5,4 +5,3 @@ perl python tar bc -pkg-config diff --git a/build/pkgs/_prereq/distros/fedora.txt b/build/pkgs/_prereq/distros/fedora.txt index 79919eef51b..b35d7f64faf 100644 --- a/build/pkgs/_prereq/distros/fedora.txt +++ b/build/pkgs/_prereq/distros/fedora.txt @@ -30,7 +30,6 @@ gcc-c++ # The need for which comes [...] from MPIR's configure script findutils which -# Needed for pcre configure, see https://github.com/sagemath/sage/issues/29129: diffutils # Needed for openssl 3.0 perl-IPC-Cmd diff --git a/build/pkgs/_prereq/distros/slackware.txt b/build/pkgs/_prereq/distros/slackware.txt index 4c2b7080ce8..4c957e45264 100644 --- a/build/pkgs/_prereq/distros/slackware.txt +++ b/build/pkgs/_prereq/distros/slackware.txt @@ -14,6 +14,5 @@ python3 # on slackware-current flex # for https upstream_url downloads ca-certificates -pkg-config libxml2 cyrus-sasl diff --git a/build/pkgs/_prereq/distros/void.txt b/build/pkgs/_prereq/distros/void.txt index da5cd5330ee..552b5a415f2 100644 --- a/build/pkgs/_prereq/distros/void.txt +++ b/build/pkgs/_prereq/distros/void.txt @@ -5,7 +5,6 @@ libgomp-devel m4 make perl -pkg-config python3 tar which diff --git a/build/pkgs/_python3.8/distros/arch.txt b/build/pkgs/_python3.8/distros/arch.txt deleted file mode 100644 index 398ae3228b3..00000000000 --- a/build/pkgs/_python3.8/distros/arch.txt +++ /dev/null @@ -1 +0,0 @@ -python38 diff --git a/build/pkgs/_python3.8/distros/cygwin.txt b/build/pkgs/_python3.8/distros/cygwin.txt deleted file mode 100644 index 398ae3228b3..00000000000 --- a/build/pkgs/_python3.8/distros/cygwin.txt +++ /dev/null @@ -1 +0,0 @@ -python38 diff --git a/build/pkgs/_python3.8/distros/debian.txt b/build/pkgs/_python3.8/distros/debian.txt deleted file mode 100644 index bf46e908ff6..00000000000 --- a/build/pkgs/_python3.8/distros/debian.txt +++ /dev/null @@ -1,4 +0,0 @@ -python3.8 -python3.8-dev -python3.8-distutils -python3.8-venv diff --git a/build/pkgs/_python3.8/distros/fedora.txt b/build/pkgs/_python3.8/distros/fedora.txt deleted file mode 100644 index 1f9ac08ba8e..00000000000 --- a/build/pkgs/_python3.8/distros/fedora.txt +++ /dev/null @@ -1,2 +0,0 @@ -python38 -python38-devel diff --git a/build/pkgs/_python3.8/distros/freebsd.txt b/build/pkgs/_python3.8/distros/freebsd.txt deleted file mode 100644 index 398ae3228b3..00000000000 --- a/build/pkgs/_python3.8/distros/freebsd.txt +++ /dev/null @@ -1 +0,0 @@ -python38 diff --git a/build/pkgs/_python3.8/distros/homebrew.txt b/build/pkgs/_python3.8/distros/homebrew.txt deleted file mode 100644 index ea9989e790c..00000000000 --- a/build/pkgs/_python3.8/distros/homebrew.txt +++ /dev/null @@ -1 +0,0 @@ -python@3.8 diff --git a/build/pkgs/_python3.8/distros/macports.txt b/build/pkgs/_python3.8/distros/macports.txt deleted file mode 100644 index 398ae3228b3..00000000000 --- a/build/pkgs/_python3.8/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -python38 diff --git a/build/pkgs/_python3.8/distros/opensuse.txt b/build/pkgs/_python3.8/distros/opensuse.txt deleted file mode 100644 index 1f9ac08ba8e..00000000000 --- a/build/pkgs/_python3.8/distros/opensuse.txt +++ /dev/null @@ -1,2 +0,0 @@ -python38 -python38-devel diff --git a/build/pkgs/admcycles/dependencies b/build/pkgs/admcycles/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/admcycles/dependencies +++ b/build/pkgs/admcycles/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/alabaster/dependencies b/build/pkgs/alabaster/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/alabaster/dependencies +++ b/build/pkgs/alabaster/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/alabaster/distros/gentoo.txt b/build/pkgs/alabaster/distros/gentoo.txt new file mode 100644 index 00000000000..cffece61b27 --- /dev/null +++ b/build/pkgs/alabaster/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/alabaster diff --git a/build/pkgs/alabaster/distros/opensuse.txt b/build/pkgs/alabaster/distros/opensuse.txt index dcc39f9e849..debe990ce19 100644 --- a/build/pkgs/alabaster/distros/opensuse.txt +++ b/build/pkgs/alabaster/distros/opensuse.txt @@ -1 +1 @@ -python3-alabaster +python3${PYTHON_MINOR}-alabaster diff --git a/build/pkgs/alabaster/spkg-configure.m4 b/build/pkgs/alabaster/spkg-configure.m4 new file mode 100644 index 00000000000..4eca6e05a5f --- /dev/null +++ b/build/pkgs/alabaster/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([alabaster], [SAGE_PYTHON_PACKAGE_CHECK([alabaster])]) diff --git a/build/pkgs/appdirs/dependencies b/build/pkgs/appdirs/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/appdirs/dependencies +++ b/build/pkgs/appdirs/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/appnope/dependencies b/build/pkgs/appnope/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/appnope/dependencies +++ b/build/pkgs/appnope/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/argon2_cffi/dependencies b/build/pkgs/argon2_cffi/dependencies index 70a583a0dbf..920046ab33d 100644 --- a/build/pkgs/argon2_cffi/dependencies +++ b/build/pkgs/argon2_cffi/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) six | $(PYTHON_TOOLCHAIN) cffi + argon2_cffi_bindings | $(PYTHON_TOOLCHAIN) flit_core $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/argon2_cffi/distros/gentoo.txt b/build/pkgs/argon2_cffi/distros/gentoo.txt new file mode 100644 index 00000000000..2f12ca869e4 --- /dev/null +++ b/build/pkgs/argon2_cffi/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/argon2-cffi diff --git a/build/pkgs/argon2_cffi/spkg-configure.m4 b/build/pkgs/argon2_cffi/spkg-configure.m4 new file mode 100644 index 00000000000..03ebc634492 --- /dev/null +++ b/build/pkgs/argon2_cffi/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([argon2_cffi], [SAGE_PYTHON_PACKAGE_CHECK([argon2_cffi])]) diff --git a/build/pkgs/argon2_cffi/spkg-install.in b/build/pkgs/argon2_cffi/spkg-install.in index 359ae695eac..37ac1a53437 100644 --- a/build/pkgs/argon2_cffi/spkg-install.in +++ b/build/pkgs/argon2_cffi/spkg-install.in @@ -1,6 +1,2 @@ cd src -if [ "$SAGE_FAT_BINARY" = "yes" ]; then - # https://argon2-cffi.readthedocs.io/en/stable/installation.html - export ARGON2_CFFI_USE_SSE2=0 -fi sdh_pip_install . diff --git a/build/pkgs/argon2_cffi_bindings/SPKG.rst b/build/pkgs/argon2_cffi_bindings/SPKG.rst new file mode 100644 index 00000000000..3d9a76114f1 --- /dev/null +++ b/build/pkgs/argon2_cffi_bindings/SPKG.rst @@ -0,0 +1,18 @@ +argon2_cffi_bindings: Low-level CFFI bindings for Argon2 +======================================================== + +Description +----------- + +Low-level CFFI bindings for Argon2 + +License +------- + +MIT + +Upstream Contact +---------------- + +https://pypi.org/project/argon2-cffi-bindings/ + diff --git a/build/pkgs/argon2_cffi_bindings/checksums.ini b/build/pkgs/argon2_cffi_bindings/checksums.ini new file mode 100644 index 00000000000..fe2e878a74d --- /dev/null +++ b/build/pkgs/argon2_cffi_bindings/checksums.ini @@ -0,0 +1,5 @@ +tarball=argon2-cffi-bindings-VERSION.tar.gz +sha1=5a9b8906d9ca73c53c2bf0a2f0a8127fda69e965 +md5=f1591e1af7dea9ef3e5b982e2c196c1d +cksum=2420586823 +upstream_url=https://pypi.io/packages/source/a/argon2_cffi_bindings/argon2-cffi-bindings-VERSION.tar.gz diff --git a/build/pkgs/argon2_cffi_bindings/dependencies b/build/pkgs/argon2_cffi_bindings/dependencies new file mode 100644 index 00000000000..4b9d24ccf44 --- /dev/null +++ b/build/pkgs/argon2_cffi_bindings/dependencies @@ -0,0 +1,4 @@ + | $(PYTHON_TOOLCHAIN) cffi setuptools_scm $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/argon2_cffi_bindings/install-requires.txt b/build/pkgs/argon2_cffi_bindings/install-requires.txt new file mode 100644 index 00000000000..50485097375 --- /dev/null +++ b/build/pkgs/argon2_cffi_bindings/install-requires.txt @@ -0,0 +1 @@ +argon2-cffi-bindings diff --git a/build/pkgs/argon2_cffi_bindings/package-version.txt b/build/pkgs/argon2_cffi_bindings/package-version.txt new file mode 100644 index 00000000000..b295a689e74 --- /dev/null +++ b/build/pkgs/argon2_cffi_bindings/package-version.txt @@ -0,0 +1 @@ +21.2.0 diff --git a/build/pkgs/argon2_cffi_bindings/spkg-install.in b/build/pkgs/argon2_cffi_bindings/spkg-install.in new file mode 100644 index 00000000000..359ae695eac --- /dev/null +++ b/build/pkgs/argon2_cffi_bindings/spkg-install.in @@ -0,0 +1,6 @@ +cd src +if [ "$SAGE_FAT_BINARY" = "yes" ]; then + # https://argon2-cffi.readthedocs.io/en/stable/installation.html + export ARGON2_CFFI_USE_SSE2=0 +fi +sdh_pip_install . diff --git a/build/pkgs/backports_zoneinfo/type b/build/pkgs/argon2_cffi_bindings/type similarity index 100% rename from build/pkgs/backports_zoneinfo/type rename to build/pkgs/argon2_cffi_bindings/type diff --git a/build/pkgs/asttokens/dependencies b/build/pkgs/asttokens/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/asttokens/dependencies +++ b/build/pkgs/asttokens/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/asttokens/distros/gentoo.txt b/build/pkgs/asttokens/distros/gentoo.txt new file mode 100644 index 00000000000..4aae3fb6cb4 --- /dev/null +++ b/build/pkgs/asttokens/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/asttokens diff --git a/build/pkgs/asttokens/spkg-configure.m4 b/build/pkgs/asttokens/spkg-configure.m4 new file mode 100644 index 00000000000..2221fabfb2b --- /dev/null +++ b/build/pkgs/asttokens/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([asttokens], [SAGE_PYTHON_PACKAGE_CHECK([asttokens])]) diff --git a/build/pkgs/attrs/dependencies b/build/pkgs/attrs/dependencies index 4361e46ddaf..9be6b4aab7c 100644 --- a/build/pkgs/attrs/dependencies +++ b/build/pkgs/attrs/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) vcversioner | $(PYTHON_TOOLCHAIN) + vcversioner | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/attrs/distros/gentoo.txt b/build/pkgs/attrs/distros/gentoo.txt new file mode 100644 index 00000000000..3b906facd3a --- /dev/null +++ b/build/pkgs/attrs/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/attrs diff --git a/build/pkgs/attrs/spkg-configure.m4 b/build/pkgs/attrs/spkg-configure.m4 new file mode 100644 index 00000000000..ba6a9b71efa --- /dev/null +++ b/build/pkgs/attrs/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([attrs], [SAGE_PYTHON_PACKAGE_CHECK([attrs])]) diff --git a/build/pkgs/auditwheel_or_delocate/dependencies b/build/pkgs/auditwheel_or_delocate/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/auditwheel_or_delocate/dependencies +++ b/build/pkgs/auditwheel_or_delocate/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/awali/dependencies b/build/pkgs/awali/dependencies index b125e2ded92..09b60167a34 100644 --- a/build/pkgs/awali/dependencies +++ b/build/pkgs/awali/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cmake cython nbconvert ncurses + cmake cython nbconvert ncurses | $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/babel/dependencies b/build/pkgs/babel/dependencies index 41462907c20..802e470da86 100644 --- a/build/pkgs/babel/dependencies +++ b/build/pkgs/babel/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) pytz + | $(PYTHON_TOOLCHAIN) pytz $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/babel/distros/arch.txt b/build/pkgs/babel/distros/arch.txt new file mode 100644 index 00000000000..f2d828ccc5c --- /dev/null +++ b/build/pkgs/babel/distros/arch.txt @@ -0,0 +1 @@ +python-babel diff --git a/build/pkgs/babel/distros/debian.txt b/build/pkgs/babel/distros/debian.txt new file mode 100644 index 00000000000..e623eb68a31 --- /dev/null +++ b/build/pkgs/babel/distros/debian.txt @@ -0,0 +1 @@ +python3-babel diff --git a/build/pkgs/babel/distros/fedora.txt b/build/pkgs/babel/distros/fedora.txt new file mode 100644 index 00000000000..98f65931c4c --- /dev/null +++ b/build/pkgs/babel/distros/fedora.txt @@ -0,0 +1 @@ +babel diff --git a/build/pkgs/babel/distros/gentoo.txt b/build/pkgs/babel/distros/gentoo.txt new file mode 100644 index 00000000000..2d2c34fb697 --- /dev/null +++ b/build/pkgs/babel/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/Babel diff --git a/build/pkgs/babel/distros/opensuse.txt b/build/pkgs/babel/distros/opensuse.txt index 70bb05b1327..6372e2e77da 100644 --- a/build/pkgs/babel/distros/opensuse.txt +++ b/build/pkgs/babel/distros/opensuse.txt @@ -1 +1 @@ -python3-Babel +python3${PYTHON_MINOR}-Babel diff --git a/build/pkgs/babel/install-requires.txt b/build/pkgs/babel/install-requires.txt index 1d0d6191bb9..b4db5e907f3 100644 --- a/build/pkgs/babel/install-requires.txt +++ b/build/pkgs/babel/install-requires.txt @@ -1 +1 @@ -babel >=2.6.0 +babel >=2.11.0 diff --git a/build/pkgs/babel/spkg-configure.m4 b/build/pkgs/babel/spkg-configure.m4 new file mode 100644 index 00000000000..d7b9a71c811 --- /dev/null +++ b/build/pkgs/babel/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([babel], [SAGE_PYTHON_PACKAGE_CHECK([babel])]) diff --git a/build/pkgs/backcall/dependencies b/build/pkgs/backcall/dependencies index 902a5feed13..4fedbe70cd1 100644 --- a/build/pkgs/backcall/dependencies +++ b/build/pkgs/backcall/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) flit_core tomli + | $(PYTHON_TOOLCHAIN) flit_core tomli $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/backcall/distros/gentoo.txt b/build/pkgs/backcall/distros/gentoo.txt new file mode 100644 index 00000000000..266a222c558 --- /dev/null +++ b/build/pkgs/backcall/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/backcall diff --git a/build/pkgs/backcall/spkg-configure.m4 b/build/pkgs/backcall/spkg-configure.m4 new file mode 100644 index 00000000000..d6b11c49884 --- /dev/null +++ b/build/pkgs/backcall/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([backcall], [SAGE_PYTHON_PACKAGE_CHECK([backcall])]) diff --git a/build/pkgs/backports_zoneinfo/SPKG.rst b/build/pkgs/backports_zoneinfo/SPKG.rst deleted file mode 100644 index deaed349122..00000000000 --- a/build/pkgs/backports_zoneinfo/SPKG.rst +++ /dev/null @@ -1,18 +0,0 @@ -backports_zoneinfo: Backport of the standard library zoneinfo module -==================================================================== - -Description ------------ - -Backport of the standard library zoneinfo module for Python 3.8 - -License -------- - -Apache-2.0 - -Upstream Contact ----------------- - -https://pypi.org/project/backports.zoneinfo/ - diff --git a/build/pkgs/backports_zoneinfo/checksums.ini b/build/pkgs/backports_zoneinfo/checksums.ini deleted file mode 100644 index 1af2250d48c..00000000000 --- a/build/pkgs/backports_zoneinfo/checksums.ini +++ /dev/null @@ -1,5 +0,0 @@ -tarball=backports.zoneinfo-VERSION.tar.gz -sha1=8015a85e499ceda8b526f907a2a60083f7004aa4 -md5=d51faaaed4a1d5158dcfcef90355e805 -cksum=2001250429 -upstream_url=https://pypi.io/packages/source/b/backports.zoneinfo/backports.zoneinfo-VERSION.tar.gz diff --git a/build/pkgs/backports_zoneinfo/distros/conda.txt b/build/pkgs/backports_zoneinfo/distros/conda.txt deleted file mode 100644 index 5a8be642f33..00000000000 --- a/build/pkgs/backports_zoneinfo/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -backports.zoneinfo diff --git a/build/pkgs/backports_zoneinfo/install-requires.txt b/build/pkgs/backports_zoneinfo/install-requires.txt deleted file mode 100644 index 5a8be642f33..00000000000 --- a/build/pkgs/backports_zoneinfo/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -backports.zoneinfo diff --git a/build/pkgs/backports_zoneinfo/package-version.txt b/build/pkgs/backports_zoneinfo/package-version.txt deleted file mode 100644 index 0c62199f16a..00000000000 --- a/build/pkgs/backports_zoneinfo/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -0.2.1 diff --git a/build/pkgs/backports_zoneinfo/spkg-install.in b/build/pkgs/backports_zoneinfo/spkg-install.in deleted file mode 100644 index 83aff6031e8..00000000000 --- a/build/pkgs/backports_zoneinfo/spkg-install.in +++ /dev/null @@ -1,6 +0,0 @@ -cd src -if python3 -c 'import sys; sys.exit(0 if sys.hexversion < 0x03090000 else 1)'; then - sdh_pip_install . -else - echo >&2 "Skipping install, not needed for Python >= 3.9" -fi diff --git a/build/pkgs/barvinok/SPKG.rst b/build/pkgs/barvinok/SPKG.rst index 32657de16e4..0e0c5bdf6f5 100644 --- a/build/pkgs/barvinok/SPKG.rst +++ b/build/pkgs/barvinok/SPKG.rst @@ -17,4 +17,5 @@ GPL v2 Upstream Contact ---------------- -- http://groups.google.com/group/isl-development +- https://sourceforge.net/projects/barvinok/ +- https://groups.google.com/group/isl-development diff --git a/build/pkgs/barvinok/checksums.ini b/build/pkgs/barvinok/checksums.ini index 1293ccdf34d..fce4148ce81 100644 --- a/build/pkgs/barvinok/checksums.ini +++ b/build/pkgs/barvinok/checksums.ini @@ -1,4 +1,5 @@ -tarball=barvinok-VERSION.tar.bz2 -sha1=31c50d4b2a4cebe049072fd54c6e41ccece5ec1d -md5=60082222a73b2d4fd430da7b770a4072 -cksum=355377045 +tarball=barvinok-VERSION.tar.xz +sha1=1e17e72732f7e96017d9ae0c3394c3c77c185f2e +md5=57066c5aa5628b89345c16ed95f93d7e +cksum=2863920036 +upstream_url=https://sourceforge.net/projects/barvinok/files/barvinok-VERSION.tar.xz diff --git a/build/pkgs/barvinok/distros/freebsd.txt b/build/pkgs/barvinok/distros/freebsd.txt new file mode 100644 index 00000000000..811ed3d1f34 --- /dev/null +++ b/build/pkgs/barvinok/distros/freebsd.txt @@ -0,0 +1 @@ +math/barvinok diff --git a/build/pkgs/barvinok/package-version.txt b/build/pkgs/barvinok/package-version.txt index 9ed317fb462..dbbcc2c2bba 100644 --- a/build/pkgs/barvinok/package-version.txt +++ b/build/pkgs/barvinok/package-version.txt @@ -1 +1 @@ -0.41.1 +0.41.7 diff --git a/build/pkgs/beautifulsoup4/dependencies b/build/pkgs/beautifulsoup4/dependencies index 01af7f65566..c9982dd1882 100644 --- a/build/pkgs/beautifulsoup4/dependencies +++ b/build/pkgs/beautifulsoup4/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) soupsieve | $(PYTHON_TOOLCHAIN) + soupsieve | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/beautifulsoup4/distros/alpine.txt b/build/pkgs/beautifulsoup4/distros/alpine.txt new file mode 100644 index 00000000000..63787cb8abf --- /dev/null +++ b/build/pkgs/beautifulsoup4/distros/alpine.txt @@ -0,0 +1 @@ +py3-beautifulsoup4 diff --git a/build/pkgs/beautifulsoup4/distros/arch.txt b/build/pkgs/beautifulsoup4/distros/arch.txt new file mode 100644 index 00000000000..2e8f9a66b24 --- /dev/null +++ b/build/pkgs/beautifulsoup4/distros/arch.txt @@ -0,0 +1 @@ +python-beautifulsoup4 diff --git a/build/pkgs/beautifulsoup4/distros/debian.txt b/build/pkgs/beautifulsoup4/distros/debian.txt new file mode 100644 index 00000000000..c1f5f713cda --- /dev/null +++ b/build/pkgs/beautifulsoup4/distros/debian.txt @@ -0,0 +1 @@ +beautifulsoup4 diff --git a/build/pkgs/beautifulsoup4/distros/fedora.txt b/build/pkgs/beautifulsoup4/distros/fedora.txt new file mode 100644 index 00000000000..2e8f9a66b24 --- /dev/null +++ b/build/pkgs/beautifulsoup4/distros/fedora.txt @@ -0,0 +1 @@ +python-beautifulsoup4 diff --git a/build/pkgs/beautifulsoup4/distros/gentoo.txt b/build/pkgs/beautifulsoup4/distros/gentoo.txt new file mode 100644 index 00000000000..5bdeb6522ec --- /dev/null +++ b/build/pkgs/beautifulsoup4/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/beautifulsoup4 diff --git a/build/pkgs/beautifulsoup4/distros/opensuse.txt b/build/pkgs/beautifulsoup4/distros/opensuse.txt new file mode 100644 index 00000000000..2e8f9a66b24 --- /dev/null +++ b/build/pkgs/beautifulsoup4/distros/opensuse.txt @@ -0,0 +1 @@ +python-beautifulsoup4 diff --git a/build/pkgs/beautifulsoup4/spkg-configure.m4 b/build/pkgs/beautifulsoup4/spkg-configure.m4 new file mode 100644 index 00000000000..e9298f00ba4 --- /dev/null +++ b/build/pkgs/beautifulsoup4/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([beautifulsoup4], [SAGE_PYTHON_PACKAGE_CHECK([beautifulsoup4])]) diff --git a/build/pkgs/beniget/dependencies b/build/pkgs/beniget/dependencies index d792a85db72..96da9efd5ac 100644 --- a/build/pkgs/beniget/dependencies +++ b/build/pkgs/beniget/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) gast | $(PYTHON_TOOLCHAIN) + gast | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/beniget/distros/gentoo.txt b/build/pkgs/beniget/distros/gentoo.txt new file mode 100644 index 00000000000..1a5972cd23f --- /dev/null +++ b/build/pkgs/beniget/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/beniget diff --git a/build/pkgs/beniget/spkg-configure.m4 b/build/pkgs/beniget/spkg-configure.m4 new file mode 100644 index 00000000000..8ae6101333e --- /dev/null +++ b/build/pkgs/beniget/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([beniget], [SAGE_PYTHON_PACKAGE_CHECK([beniget])]) diff --git a/build/pkgs/bleach/dependencies b/build/pkgs/bleach/dependencies index 4a74f9bfd68..c7ac2e8b3e7 100644 --- a/build/pkgs/bleach/dependencies +++ b/build/pkgs/bleach/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) packaging six webencodings | $(PYTHON_TOOLCHAIN) + packaging six webencodings | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/bleach/distros/arch.txt b/build/pkgs/bleach/distros/arch.txt new file mode 100644 index 00000000000..c5422ccff0c --- /dev/null +++ b/build/pkgs/bleach/distros/arch.txt @@ -0,0 +1 @@ +python-bleach diff --git a/build/pkgs/bleach/distros/debian.txt b/build/pkgs/bleach/distros/debian.txt new file mode 100644 index 00000000000..6d37c4c79f0 --- /dev/null +++ b/build/pkgs/bleach/distros/debian.txt @@ -0,0 +1 @@ +python3-bleach diff --git a/build/pkgs/bleach/distros/fedora.txt b/build/pkgs/bleach/distros/fedora.txt new file mode 100644 index 00000000000..c5422ccff0c --- /dev/null +++ b/build/pkgs/bleach/distros/fedora.txt @@ -0,0 +1 @@ +python-bleach diff --git a/build/pkgs/bleach/distros/gentoo.txt b/build/pkgs/bleach/distros/gentoo.txt new file mode 100644 index 00000000000..b4f9744eee9 --- /dev/null +++ b/build/pkgs/bleach/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/bleach diff --git a/build/pkgs/bleach/distros/opensuse.txt b/build/pkgs/bleach/distros/opensuse.txt new file mode 100644 index 00000000000..0e329f6dd62 --- /dev/null +++ b/build/pkgs/bleach/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-bleach diff --git a/build/pkgs/bleach/spkg-configure.m4 b/build/pkgs/bleach/spkg-configure.m4 new file mode 100644 index 00000000000..3c9bb26bb05 --- /dev/null +++ b/build/pkgs/bleach/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([bleach], [SAGE_PYTHON_PACKAGE_CHECK([bleach])]) diff --git a/build/pkgs/bliss/SPKG.rst b/build/pkgs/bliss/SPKG.rst index 875bc39a2df..77407f16ac7 100644 --- a/build/pkgs/bliss/SPKG.rst +++ b/build/pkgs/bliss/SPKG.rst @@ -10,17 +10,21 @@ canonical forms of graphs. License ------- -LGPL +LGPL3 Upstream Contact ---------------- -Bliss is currently being maintained by Tommi Junttila and Petteri Kaski. +Bliss is currently being maintained by Tommi Junttila at + +https://users.aalto.fi/~tjunttil/bliss/index.html + +Bliss used to be maintained by Tommi Junttila and Petteri Kaski up to version 0.73 at http://www.tcs.tkk.fi/Software/bliss/index.html -We apply patches generated from https://github.com/mkoeppe/bliss (branch -apply_debian_patches) as our upstream. This tracks the patches from the -Debian package, adding an autotools build system and adjusting the -include file locations. +Dependencies +------------ + +None diff --git a/build/pkgs/bliss/checksums.ini b/build/pkgs/bliss/checksums.ini index e97d89587bf..0c1ebf647bc 100644 --- a/build/pkgs/bliss/checksums.ini +++ b/build/pkgs/bliss/checksums.ini @@ -1,4 +1,5 @@ -tarball=bliss-VERSION.tar.gz -sha1=1da8f098046824fbfff4c64c337e28b2a082f74f -md5=452aea8737d3c4ad0d8ff39180be8004 -cksum=2193930007 +tarball=bliss-VERSION.zip +sha1=c91c9dcbc11d66ffbcf6415e09ebe793df37be2a +md5=5707cbfd9fd00980571c64ab3584c505 +cksum=1626493724 +upstream_url=https://users.aalto.fi/~tjunttil/bliss/downloads/bliss-VERSION.zip diff --git a/build/pkgs/bliss/dependencies b/build/pkgs/bliss/dependencies index 4f00de20375..c225c495cc6 100644 --- a/build/pkgs/bliss/dependencies +++ b/build/pkgs/bliss/dependencies @@ -1,4 +1,4 @@ -# no dependencies +| cmake ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/bliss/distros/gentoo.txt b/build/pkgs/bliss/distros/gentoo.txt new file mode 100644 index 00000000000..73add6de49d --- /dev/null +++ b/build/pkgs/bliss/distros/gentoo.txt @@ -0,0 +1 @@ +sci-libs/bliss diff --git a/build/pkgs/bliss/package-version.txt b/build/pkgs/bliss/package-version.txt index e93ee1376fa..9e1e206c410 100644 --- a/build/pkgs/bliss/package-version.txt +++ b/build/pkgs/bliss/package-version.txt @@ -1 +1 @@ -0.73+debian-1+sage-2016-08-02.p0 +0.77 diff --git a/build/pkgs/bliss/patches/bliss-0.77-install.patch b/build/pkgs/bliss/patches/bliss-0.77-install.patch new file mode 100644 index 00000000000..caab14aa40f --- /dev/null +++ b/build/pkgs/bliss/patches/bliss-0.77-install.patch @@ -0,0 +1,32 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 01ed093..cfdb0a6 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -62,3 +62,27 @@ if(USE_GMP) + target_link_libraries(bliss-executable ${GMP_LIBRARIES}) + endif(USE_GMP) + set_target_properties(bliss-executable PROPERTIES OUTPUT_NAME bliss) ++ ++include(GNUInstallDirs) ++ ++set( ++ BLISS_HEADERS ++ src/bliss_C.h ++ src/uintseqhash.hh ++ src/abstractgraph.hh ++ src/stats.hh ++ src/digraph.hh ++ src/defs.hh ++ src/heap.hh ++ src/graph.hh ++ src/partition.hh ++ src/kqueue.hh ++ src/utils.hh ++ src/orbit.hh ++ src/timer.hh ++ src/bignum.hh ++) ++ ++install(TARGETS bliss-executable RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) ++install(TARGETS bliss LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) ++install(FILES ${BLISS_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/bliss) diff --git a/build/pkgs/bliss/spkg-install.in b/build/pkgs/bliss/spkg-install.in index aaf4c3037bc..4124a2338e5 100644 --- a/build/pkgs/bliss/spkg-install.in +++ b/build/pkgs/bliss/spkg-install.in @@ -1,4 +1,4 @@ cd src -sdh_configure --disable-gmp +sdh_cmake -DUSE_GMP=OFF -DCMAKE_VERBOSE_MAKEFILE=ON sdh_make sdh_make_install diff --git a/build/pkgs/bliss/spkg-src b/build/pkgs/bliss/spkg-src deleted file mode 100755 index 90073233b77..00000000000 --- a/build/pkgs/bliss/spkg-src +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# creates the tarball in the current dir, to be moved to ../../../upstream -# -# adapted from cliquer/spkg-src - -die () { - echo >&2 "$@" - exit 1 -} - -rm -rf bliss/ -git clone -b sage_package https://github.com/mkoeppe/bliss.git || die "Failed to git clone" -cd bliss/ - -VERSION=`autoconf --trace='AC_INIT:$2'` -libtoolize || die "Failed to autoreconf" -autoreconf -fi || die "Failed to autoreconf" -automake --add-missing --copy || die "automake failed" -./configure || die "configure failed" - -rm -f bliss-$VERSION.tar.gz -make dist || die "make dist failed" -mv bliss-$VERSION.tar.gz ../ -cd .. -rm -rf bliss/ - - diff --git a/build/pkgs/cachetools/SPKG.rst b/build/pkgs/cachetools/SPKG.rst new file mode 100644 index 00000000000..30035dfd3cd --- /dev/null +++ b/build/pkgs/cachetools/SPKG.rst @@ -0,0 +1,18 @@ +cachetools: Extensible memoizing collections and decorators +=========================================================== + +Description +----------- + +Extensible memoizing collections and decorators + +License +------- + +MIT + +Upstream Contact +---------------- + +https://pypi.org/project/cachetools/ + diff --git a/build/pkgs/cachetools/checksums.ini b/build/pkgs/cachetools/checksums.ini new file mode 100644 index 00000000000..0ffe70b3b2f --- /dev/null +++ b/build/pkgs/cachetools/checksums.ini @@ -0,0 +1,5 @@ +tarball=cachetools-VERSION-py3-none-any.whl +sha1=f7deaa4b10ae6d8955c83b0573e5b80f84e5d87a +md5=7375eb8031ea2c95b91d2406c29e9379 +cksum=3631496040 +upstream_url=https://pypi.io/packages/py3/c/cachetools/cachetools-VERSION-py3-none-any.whl diff --git a/build/pkgs/cachetools/dependencies b/build/pkgs/cachetools/dependencies new file mode 100644 index 00000000000..47296a7bace --- /dev/null +++ b/build/pkgs/cachetools/dependencies @@ -0,0 +1,4 @@ + | $(PYTHON_TOOLCHAIN) $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/cachetools/install-requires.txt b/build/pkgs/cachetools/install-requires.txt new file mode 100644 index 00000000000..50d14084a9b --- /dev/null +++ b/build/pkgs/cachetools/install-requires.txt @@ -0,0 +1 @@ +cachetools diff --git a/build/pkgs/cachetools/package-version.txt b/build/pkgs/cachetools/package-version.txt new file mode 100644 index 00000000000..c7cb1311a64 --- /dev/null +++ b/build/pkgs/cachetools/package-version.txt @@ -0,0 +1 @@ +5.3.1 diff --git a/build/pkgs/cachetools/spkg-configure.m4 b/build/pkgs/cachetools/spkg-configure.m4 new file mode 100644 index 00000000000..1e6c1fb453a --- /dev/null +++ b/build/pkgs/cachetools/spkg-configure.m4 @@ -0,0 +1,7 @@ +SAGE_SPKG_CONFIGURE([cachetools], [ + sage_spkg_install_cachetools=yes + ], [dnl REQUIRED-CHECK + AC_REQUIRE([SAGE_SPKG_CONFIGURE_TOX]) + dnl cachetools is only needed when we cannot use system tox. + AS_VAR_SET([SPKG_REQUIRE], [$sage_spkg_install_tox]) + ]) diff --git a/build/pkgs/flintqs/type b/build/pkgs/cachetools/type similarity index 100% rename from build/pkgs/flintqs/type rename to build/pkgs/cachetools/type diff --git a/build/pkgs/calver/SPKG.rst b/build/pkgs/calver/SPKG.rst new file mode 100644 index 00000000000..ccdf38e3719 --- /dev/null +++ b/build/pkgs/calver/SPKG.rst @@ -0,0 +1,16 @@ +calver: Setuptools extension for CalVer package versions +======================================================== + +Description +----------- + +Setuptools extension for CalVer package versions + +License +------- + +Upstream Contact +---------------- + +https://pypi.org/project/calver/ + diff --git a/build/pkgs/calver/checksums.ini b/build/pkgs/calver/checksums.ini new file mode 100644 index 00000000000..358cbc4cf7b --- /dev/null +++ b/build/pkgs/calver/checksums.ini @@ -0,0 +1,5 @@ +tarball=calver-VERSION-py3-none-any.whl +sha1=4553e3fbfc58908f3be2dd529e5991986f6a46b5 +md5=3c34037d7bd217efd99b738aa1a7744b +cksum=3667684754 +upstream_url=https://pypi.io/packages/py3/c/calver/calver-VERSION-py3-none-any.whl diff --git a/build/pkgs/backports_zoneinfo/dependencies b/build/pkgs/calver/dependencies similarity index 100% rename from build/pkgs/backports_zoneinfo/dependencies rename to build/pkgs/calver/dependencies diff --git a/build/pkgs/calver/install-requires.txt b/build/pkgs/calver/install-requires.txt new file mode 100644 index 00000000000..62948b78bc0 --- /dev/null +++ b/build/pkgs/calver/install-requires.txt @@ -0,0 +1 @@ +calver diff --git a/build/pkgs/calver/package-version.txt b/build/pkgs/calver/package-version.txt new file mode 100644 index 00000000000..42376d1100a --- /dev/null +++ b/build/pkgs/calver/package-version.txt @@ -0,0 +1 @@ +2022.6.26 diff --git a/build/pkgs/html5lib/type b/build/pkgs/calver/type similarity index 100% rename from build/pkgs/html5lib/type rename to build/pkgs/calver/type diff --git a/build/pkgs/certifi/dependencies b/build/pkgs/certifi/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/certifi/dependencies +++ b/build/pkgs/certifi/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/certifi/distros/arch.txt b/build/pkgs/certifi/distros/arch.txt new file mode 100644 index 00000000000..be421c8b4b2 --- /dev/null +++ b/build/pkgs/certifi/distros/arch.txt @@ -0,0 +1 @@ +python-certifi diff --git a/build/pkgs/certifi/distros/debian.txt b/build/pkgs/certifi/distros/debian.txt new file mode 100644 index 00000000000..f585a823bf3 --- /dev/null +++ b/build/pkgs/certifi/distros/debian.txt @@ -0,0 +1 @@ +python3-certifi diff --git a/build/pkgs/certifi/distros/fedora.txt b/build/pkgs/certifi/distros/fedora.txt new file mode 100644 index 00000000000..be421c8b4b2 --- /dev/null +++ b/build/pkgs/certifi/distros/fedora.txt @@ -0,0 +1 @@ +python-certifi diff --git a/build/pkgs/certifi/distros/gentoo.txt b/build/pkgs/certifi/distros/gentoo.txt new file mode 100644 index 00000000000..72e2e91c6ae --- /dev/null +++ b/build/pkgs/certifi/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/certifi diff --git a/build/pkgs/certifi/distros/opensuse.txt b/build/pkgs/certifi/distros/opensuse.txt index f585a823bf3..9f7a6b5c964 100644 --- a/build/pkgs/certifi/distros/opensuse.txt +++ b/build/pkgs/certifi/distros/opensuse.txt @@ -1 +1 @@ -python3-certifi +python3${PYTHON_MINOR}-certifi diff --git a/build/pkgs/certifi/spkg-configure.m4 b/build/pkgs/certifi/spkg-configure.m4 new file mode 100644 index 00000000000..ddd40613514 --- /dev/null +++ b/build/pkgs/certifi/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([certifi], [SAGE_PYTHON_PACKAGE_CHECK([certifi])]) diff --git a/build/pkgs/cffi/dependencies b/build/pkgs/cffi/dependencies index 9e4c266ad69..9af7c6ed3db 100644 --- a/build/pkgs/cffi/dependencies +++ b/build/pkgs/cffi/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) pycparser + | $(PYTHON_TOOLCHAIN) pycparser $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cffi/distros/gentoo.txt b/build/pkgs/cffi/distros/gentoo.txt new file mode 100644 index 00000000000..81eeb8108c7 --- /dev/null +++ b/build/pkgs/cffi/distros/gentoo.txt @@ -0,0 +1 @@ +virtual/python-cffi diff --git a/build/pkgs/cffi/distros/opensuse.txt b/build/pkgs/cffi/distros/opensuse.txt index 68ec4dda5ba..6bce4cd18b5 100644 --- a/build/pkgs/cffi/distros/opensuse.txt +++ b/build/pkgs/cffi/distros/opensuse.txt @@ -1 +1 @@ -python3-cffi +python3${PYTHON_MINOR}-cffi diff --git a/build/pkgs/cffi/spkg-configure.m4 b/build/pkgs/cffi/spkg-configure.m4 new file mode 100644 index 00000000000..dc81875927f --- /dev/null +++ b/build/pkgs/cffi/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([cffi], [SAGE_PYTHON_PACKAGE_CHECK([cffi])]) diff --git a/build/pkgs/chardet/SPKG.rst b/build/pkgs/chardet/SPKG.rst new file mode 100644 index 00000000000..6e5a717cca5 --- /dev/null +++ b/build/pkgs/chardet/SPKG.rst @@ -0,0 +1,18 @@ +chardet: Universal encoding detector for Python 3 +================================================= + +Description +----------- + +Universal encoding detector for Python 3 + +License +------- + +LGPL + +Upstream Contact +---------------- + +https://pypi.org/project/chardet/ + diff --git a/build/pkgs/chardet/checksums.ini b/build/pkgs/chardet/checksums.ini new file mode 100644 index 00000000000..9911b1d139e --- /dev/null +++ b/build/pkgs/chardet/checksums.ini @@ -0,0 +1,5 @@ +tarball=chardet-VERSION-py3-none-any.whl +sha1=2facc0387556aa8a2956ef682d49fc3eae56d30a +md5=b9eda7cd7d1582e269bd8eb7ffc4fcad +cksum=1563594607 +upstream_url=https://pypi.io/packages/py3/c/chardet/chardet-VERSION-py3-none-any.whl diff --git a/build/pkgs/chardet/dependencies b/build/pkgs/chardet/dependencies new file mode 100644 index 00000000000..47296a7bace --- /dev/null +++ b/build/pkgs/chardet/dependencies @@ -0,0 +1,4 @@ + | $(PYTHON_TOOLCHAIN) $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/chardet/install-requires.txt b/build/pkgs/chardet/install-requires.txt new file mode 100644 index 00000000000..79236f25cda --- /dev/null +++ b/build/pkgs/chardet/install-requires.txt @@ -0,0 +1 @@ +chardet diff --git a/build/pkgs/chardet/package-version.txt b/build/pkgs/chardet/package-version.txt new file mode 100644 index 00000000000..91ff57278e3 --- /dev/null +++ b/build/pkgs/chardet/package-version.txt @@ -0,0 +1 @@ +5.2.0 diff --git a/build/pkgs/chardet/spkg-configure.m4 b/build/pkgs/chardet/spkg-configure.m4 new file mode 100644 index 00000000000..2dba4eef338 --- /dev/null +++ b/build/pkgs/chardet/spkg-configure.m4 @@ -0,0 +1,7 @@ +SAGE_SPKG_CONFIGURE([chardet], [ + sage_spkg_install_chardet=yes + ], [dnl REQUIRED-CHECK + AC_REQUIRE([SAGE_SPKG_CONFIGURE_TOX]) + dnl chardet is only needed when we cannot use system tox. + AS_VAR_SET([SPKG_REQUIRE], [$sage_spkg_install_tox]) + ]) diff --git a/build/pkgs/jupyter_packaging/type b/build/pkgs/chardet/type similarity index 100% rename from build/pkgs/jupyter_packaging/type rename to build/pkgs/chardet/type diff --git a/build/pkgs/charset_normalizer/dependencies b/build/pkgs/charset_normalizer/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/charset_normalizer/dependencies +++ b/build/pkgs/charset_normalizer/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/charset_normalizer/distros/gentoo.txt b/build/pkgs/charset_normalizer/distros/gentoo.txt new file mode 100644 index 00000000000..eefeb89e31e --- /dev/null +++ b/build/pkgs/charset_normalizer/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/charset_normalizer diff --git a/build/pkgs/charset_normalizer/spkg-configure.m4 b/build/pkgs/charset_normalizer/spkg-configure.m4 new file mode 100644 index 00000000000..18b18cf32b4 --- /dev/null +++ b/build/pkgs/charset_normalizer/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([charset_normalizer], [ + SAGE_PYTHON_PACKAGE_CHECK([charset_normalizer]) +]) diff --git a/build/pkgs/cmake/checksums.ini b/build/pkgs/cmake/checksums.ini index c89abdf4277..a145b30dfb4 100644 --- a/build/pkgs/cmake/checksums.ini +++ b/build/pkgs/cmake/checksums.ini @@ -1,5 +1,5 @@ tarball=cmake-VERSION.tar.gz -sha1=256d6a57a57fa6ceaacd6a2daf708baefd33850c -md5=226dd564164372f9f7d1e21e38e6e8c5 -cksum=2080281918 +sha1=3e9b980bfb16974f57ca02b5e2b403a2ef2d4eca +md5=7228f5fcc8a858fdeac27e29bda0c144 +cksum=2027526722 upstream_url=https://github.com/Kitware/CMake/releases/download/vVERSION/cmake-VERSION.tar.gz diff --git a/build/pkgs/cmake/package-version.txt b/build/pkgs/cmake/package-version.txt index 693bd59e3e6..a155471fc06 100644 --- a/build/pkgs/cmake/package-version.txt +++ b/build/pkgs/cmake/package-version.txt @@ -1 +1 @@ -3.24.3 +3.27.3 diff --git a/build/pkgs/colorama/SPKG.rst b/build/pkgs/colorama/SPKG.rst new file mode 100644 index 00000000000..3335092e4c7 --- /dev/null +++ b/build/pkgs/colorama/SPKG.rst @@ -0,0 +1,16 @@ +colorama: Cross-platform colored terminal text. +=============================================== + +Description +----------- + +Cross-platform colored terminal text. + +License +------- + +Upstream Contact +---------------- + +https://pypi.org/project/colorama/ + diff --git a/build/pkgs/colorama/checksums.ini b/build/pkgs/colorama/checksums.ini new file mode 100644 index 00000000000..e625d548a68 --- /dev/null +++ b/build/pkgs/colorama/checksums.ini @@ -0,0 +1,5 @@ +tarball=colorama-VERSION-py2.py3-none-any.whl +sha1=d6ab1608850fecfc0e1cf50bf93d743695c04027 +md5=3fc7a89530d68d7ea231ebe779c0db9c +cksum=3297334831 +upstream_url=https://pypi.io/packages/py2.py3/c/colorama/colorama-VERSION-py2.py3-none-any.whl diff --git a/build/pkgs/colorama/dependencies b/build/pkgs/colorama/dependencies new file mode 100644 index 00000000000..47296a7bace --- /dev/null +++ b/build/pkgs/colorama/dependencies @@ -0,0 +1,4 @@ + | $(PYTHON_TOOLCHAIN) $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/colorama/install-requires.txt b/build/pkgs/colorama/install-requires.txt new file mode 100644 index 00000000000..3fcfb51b2ad --- /dev/null +++ b/build/pkgs/colorama/install-requires.txt @@ -0,0 +1 @@ +colorama diff --git a/build/pkgs/colorama/package-version.txt b/build/pkgs/colorama/package-version.txt new file mode 100644 index 00000000000..ef52a648073 --- /dev/null +++ b/build/pkgs/colorama/package-version.txt @@ -0,0 +1 @@ +0.4.6 diff --git a/build/pkgs/colorama/spkg-configure.m4 b/build/pkgs/colorama/spkg-configure.m4 new file mode 100644 index 00000000000..65c88b05ec8 --- /dev/null +++ b/build/pkgs/colorama/spkg-configure.m4 @@ -0,0 +1,7 @@ +SAGE_SPKG_CONFIGURE([colorama], [ + sage_spkg_install_colorama=yes + ], [dnl REQUIRED-CHECK + AC_REQUIRE([SAGE_SPKG_CONFIGURE_TOX]) + dnl colorama is only needed when we cannot use system tox. + AS_VAR_SET([SPKG_REQUIRE], [$sage_spkg_install_tox]) + ]) diff --git a/build/pkgs/pcre/type b/build/pkgs/colorama/type similarity index 100% rename from build/pkgs/pcre/type rename to build/pkgs/colorama/type diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 31e3b035d64..f6feef844de 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=0897c667d1327d2a51ea3d3bd1d9e1a3f5ca2606 -md5=a1f271e5ffcf558d054028839296a072 -cksum=437557471 +sha1=96468a2d2ec8ee319095f3d2abd73e5f1ec7829d +md5=87391217b5c82275e1cb581721877eec +cksum=370856230 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 9462f03cbd2..886c67921da 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -08185d786047228caff879eba88a1f8148a49020 +b01856309bcb0d25e9cf830da19fa1cdd24df2bf diff --git a/build/pkgs/contourpy/dependencies b/build/pkgs/contourpy/dependencies index 0740ab1d4a7..d12b50bf33c 100644 --- a/build/pkgs/contourpy/dependencies +++ b/build/pkgs/contourpy/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) numpy | $(PYTHON_TOOLCHAIN) pybind11 + numpy | $(PYTHON_TOOLCHAIN) pybind11 $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/contourpy/distros/gentoo.txt b/build/pkgs/contourpy/distros/gentoo.txt new file mode 100644 index 00000000000..39774cf783f --- /dev/null +++ b/build/pkgs/contourpy/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/contourpy diff --git a/build/pkgs/contourpy/spkg-configure.m4 b/build/pkgs/contourpy/spkg-configure.m4 new file mode 100644 index 00000000000..f26adf351de --- /dev/null +++ b/build/pkgs/contourpy/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([contourpy], [SAGE_PYTHON_PACKAGE_CHECK([contourpy])]) diff --git a/build/pkgs/conway_polynomials/dependencies b/build/pkgs/conway_polynomials/dependencies index 1700e743d59..6b134137610 100644 --- a/build/pkgs/conway_polynomials/dependencies +++ b/build/pkgs/conway_polynomials/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) +| $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cppy/dependencies b/build/pkgs/cppy/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/cppy/dependencies +++ b/build/pkgs/cppy/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cppy/distros/gentoo.txt b/build/pkgs/cppy/distros/gentoo.txt new file mode 100644 index 00000000000..f66c6eff5ee --- /dev/null +++ b/build/pkgs/cppy/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/cppy diff --git a/build/pkgs/cppy/install-requires.txt b/build/pkgs/cppy/install-requires.txt index 9d2b4aaeee0..42667a30148 100644 --- a/build/pkgs/cppy/install-requires.txt +++ b/build/pkgs/cppy/install-requires.txt @@ -1 +1 @@ -cppy +cppy >=1.2.0 diff --git a/build/pkgs/cppy/spkg-configure.m4 b/build/pkgs/cppy/spkg-configure.m4 new file mode 100644 index 00000000000..2c895d9b070 --- /dev/null +++ b/build/pkgs/cppy/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([cppy], [SAGE_PYTHON_PACKAGE_CHECK([cppy])]) diff --git a/build/pkgs/cryptominisat/dependencies b/build/pkgs/cryptominisat/dependencies index 15e88888b6d..e30473e40f6 100644 --- a/build/pkgs/cryptominisat/dependencies +++ b/build/pkgs/cryptominisat/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) m4ri zlib libpng | cmake boost_cropped + m4ri zlib libpng | cmake boost_cropped $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cvxopt/dependencies b/build/pkgs/cvxopt/dependencies index d47ae01f215..33055fe8bf4 100644 --- a/build/pkgs/cvxopt/dependencies +++ b/build/pkgs/cvxopt/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) numpy $(BLAS) gsl glpk suitesparse | $(PYTHON_TOOLCHAIN) pkgconfig + numpy $(BLAS) gsl glpk suitesparse | $(PYTHON_TOOLCHAIN) pkgconfig $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cvxopt/distros/arch.txt b/build/pkgs/cvxopt/distros/arch.txt new file mode 100644 index 00000000000..f15770f0506 --- /dev/null +++ b/build/pkgs/cvxopt/distros/arch.txt @@ -0,0 +1 @@ +python-cvxopt diff --git a/build/pkgs/cvxopt/distros/debian.txt b/build/pkgs/cvxopt/distros/debian.txt new file mode 100644 index 00000000000..2bb6ad1e834 --- /dev/null +++ b/build/pkgs/cvxopt/distros/debian.txt @@ -0,0 +1 @@ +python3-cvxopt diff --git a/build/pkgs/cvxopt/distros/fedora.txt b/build/pkgs/cvxopt/distros/fedora.txt new file mode 100644 index 00000000000..f15770f0506 --- /dev/null +++ b/build/pkgs/cvxopt/distros/fedora.txt @@ -0,0 +1 @@ +python-cvxopt diff --git a/build/pkgs/cvxopt/distros/gentoo.txt b/build/pkgs/cvxopt/distros/gentoo.txt new file mode 100644 index 00000000000..b3123912bbe --- /dev/null +++ b/build/pkgs/cvxopt/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/cvxopt diff --git a/build/pkgs/cvxopt/distros/opensuse.txt b/build/pkgs/cvxopt/distros/opensuse.txt new file mode 100644 index 00000000000..e254c198706 --- /dev/null +++ b/build/pkgs/cvxopt/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-cvxopt diff --git a/build/pkgs/cvxopt/spkg-configure.m4 b/build/pkgs/cvxopt/spkg-configure.m4 new file mode 100644 index 00000000000..c4aa6198edb --- /dev/null +++ b/build/pkgs/cvxopt/spkg-configure.m4 @@ -0,0 +1,5 @@ +SAGE_SPKG_CONFIGURE([cvxopt], [ + SAGE_SPKG_DEPCHECK([gsl glpk suitesparse], [ + SAGE_PYTHON_PACKAGE_CHECK([cvxopt]) + ]) +]) diff --git a/build/pkgs/cvxpy/SPKG.rst b/build/pkgs/cvxpy/SPKG.rst new file mode 100644 index 00000000000..55998a0d419 --- /dev/null +++ b/build/pkgs/cvxpy/SPKG.rst @@ -0,0 +1,18 @@ +cvxpy: A domain-specific language for modeling convex optimization problems in Python. +====================================================================================== + +Description +----------- + +A domain-specific language for modeling convex optimization problems in Python. + +License +------- + +Apache License, Version 2.0 + +Upstream Contact +---------------- + +https://pypi.org/project/cvxpy/ + diff --git a/build/pkgs/cvxpy/checksums.ini b/build/pkgs/cvxpy/checksums.ini new file mode 100644 index 00000000000..128dcda1602 --- /dev/null +++ b/build/pkgs/cvxpy/checksums.ini @@ -0,0 +1,5 @@ +tarball=cvxpy-VERSION.tar.gz +sha1=8c87f8f8c2177f917ec2fad7d2b510787ffdf72d +md5=408b0a3140750299207f61de95b4ed6e +cksum=3643150234 +upstream_url=https://pypi.io/packages/source/c/cvxpy/cvxpy-VERSION.tar.gz diff --git a/build/pkgs/cvxpy/dependencies b/build/pkgs/cvxpy/dependencies new file mode 100644 index 00000000000..42cfab890cc --- /dev/null +++ b/build/pkgs/cvxpy/dependencies @@ -0,0 +1,4 @@ + numpy scipy glpk cvxopt osqp_python ecos_python scs | $(PYTHON_TOOLCHAIN) $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/cvxpy/distros/conda.txt b/build/pkgs/cvxpy/distros/conda.txt new file mode 100644 index 00000000000..187142bb93e --- /dev/null +++ b/build/pkgs/cvxpy/distros/conda.txt @@ -0,0 +1 @@ +cvxpy diff --git a/build/pkgs/cvxpy/install-requires.txt b/build/pkgs/cvxpy/install-requires.txt new file mode 100644 index 00000000000..187142bb93e --- /dev/null +++ b/build/pkgs/cvxpy/install-requires.txt @@ -0,0 +1 @@ +cvxpy diff --git a/build/pkgs/cvxpy/package-version.txt b/build/pkgs/cvxpy/package-version.txt new file mode 100644 index 00000000000..f0bb29e7638 --- /dev/null +++ b/build/pkgs/cvxpy/package-version.txt @@ -0,0 +1 @@ +1.3.0 diff --git a/build/pkgs/cvxpy/spkg-install.in b/build/pkgs/cvxpy/spkg-install.in new file mode 100644 index 00000000000..a143d1eff96 --- /dev/null +++ b/build/pkgs/cvxpy/spkg-install.in @@ -0,0 +1,3 @@ +cd src +# --no-build-isolation to ignore the numpy version pin in pyproject.toml +sdh_pip_install --no-build-isolation . diff --git a/build/pkgs/pyflakes/type b/build/pkgs/cvxpy/type similarity index 100% rename from build/pkgs/pyflakes/type rename to build/pkgs/cvxpy/type diff --git a/build/pkgs/cycler/dependencies b/build/pkgs/cycler/dependencies index 730af09b339..8a158d645be 100644 --- a/build/pkgs/cycler/dependencies +++ b/build/pkgs/cycler/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) six | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cycler/distros/arch.txt b/build/pkgs/cycler/distros/arch.txt new file mode 100644 index 00000000000..5727259aca6 --- /dev/null +++ b/build/pkgs/cycler/distros/arch.txt @@ -0,0 +1 @@ +python-cycler diff --git a/build/pkgs/cycler/distros/debian.txt b/build/pkgs/cycler/distros/debian.txt new file mode 100644 index 00000000000..c77685dd417 --- /dev/null +++ b/build/pkgs/cycler/distros/debian.txt @@ -0,0 +1 @@ +python3-cycler diff --git a/build/pkgs/cycler/distros/fedora.txt b/build/pkgs/cycler/distros/fedora.txt new file mode 100644 index 00000000000..5727259aca6 --- /dev/null +++ b/build/pkgs/cycler/distros/fedora.txt @@ -0,0 +1 @@ +python-cycler diff --git a/build/pkgs/cycler/distros/freebsd.txt b/build/pkgs/cycler/distros/freebsd.txt new file mode 100644 index 00000000000..6da1dabb333 --- /dev/null +++ b/build/pkgs/cycler/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-cycler diff --git a/build/pkgs/cycler/distros/gentoo.txt b/build/pkgs/cycler/distros/gentoo.txt new file mode 100644 index 00000000000..4b215438e8f --- /dev/null +++ b/build/pkgs/cycler/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/cycler diff --git a/build/pkgs/cycler/distros/opensuse.txt b/build/pkgs/cycler/distros/opensuse.txt new file mode 100644 index 00000000000..6aab7454acb --- /dev/null +++ b/build/pkgs/cycler/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-Cycler diff --git a/build/pkgs/cycler/spkg-configure.m4 b/build/pkgs/cycler/spkg-configure.m4 new file mode 100644 index 00000000000..239571a0f10 --- /dev/null +++ b/build/pkgs/cycler/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([cycler], [SAGE_PYTHON_PACKAGE_CHECK([cycler])]) diff --git a/build/pkgs/cylp/SPKG.rst b/build/pkgs/cylp/SPKG.rst index 1bb0c61738d..10b8192e39c 100644 --- a/build/pkgs/cylp/SPKG.rst +++ b/build/pkgs/cylp/SPKG.rst @@ -9,7 +9,11 @@ A Python interface for CLP, CBC, and CGL License ------- -Eclipse Public License +Eclipse Public License (EPL) version 2 (without a Secondary Licenses Notice). + +Note: This license is incompatible with the GPL according to +https://www.gnu.org/licenses/license-list.html#EPL2; +see also the discussion in :trac:`26511`. Upstream Contact ---------------- diff --git a/build/pkgs/cylp/checksums.ini b/build/pkgs/cylp/checksums.ini index 1b44a7d5faa..0a073c1569a 100644 --- a/build/pkgs/cylp/checksums.ini +++ b/build/pkgs/cylp/checksums.ini @@ -1,5 +1,5 @@ tarball=cylp-VERSION.tar.gz -sha1=54965f2ae9b914df7817dffd53bc34925a6fadd4 -md5=a4f50e6b24a7fcd2e890a9e7e8825437 -cksum=4132703858 +sha1=1c2d20933abc48ed2fefc1ae45d8f9492fc2eef2 +md5=ac0308a916dac5dd84f831dbc0fba5c5 +cksum=1532166313 upstream_url=https://pypi.io/packages/source/c/cylp/cylp-VERSION.tar.gz diff --git a/build/pkgs/cylp/dependencies b/build/pkgs/cylp/dependencies index 3c541129eb9..d2c6405119d 100644 --- a/build/pkgs/cylp/dependencies +++ b/build/pkgs/cylp/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) numpy scipy cbc | $(PYTHON_TOOLCHAIN) cython + numpy scipy cbc | $(PYTHON_TOOLCHAIN) cython $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cylp/package-version.txt b/build/pkgs/cylp/package-version.txt index ad7e0bcae92..1d5e6c02bae 100644 --- a/build/pkgs/cylp/package-version.txt +++ b/build/pkgs/cylp/package-version.txt @@ -1 +1 @@ -0.91.4 +0.91.5 diff --git a/build/pkgs/cylp/patches/e619c4b94e279e96842da0d38ae657f06f1e9415.patch b/build/pkgs/cylp/patches/e619c4b94e279e96842da0d38ae657f06f1e9415.patch deleted file mode 100644 index 295cae02b2c..00000000000 --- a/build/pkgs/cylp/patches/e619c4b94e279e96842da0d38ae657f06f1e9415.patch +++ /dev/null @@ -1,88285 +0,0 @@ -From e619c4b94e279e96842da0d38ae657f06f1e9415 Mon Sep 17 00:00:00 2001 -From: Ted Ralphs <ted@lehigh.edu> -Date: Wed, 15 Dec 2021 18:01:49 -0500 -Subject: [PATCH] Re-generating with Cython 0.29.27 for Python 3.10 - compatibility. Fixes #132 - ---- - cylp/cy/CyCbcModel.cpp | 3071 ++++++-------------- - cylp/cy/CyCbcNode.cpp | 3671 +++++++----------------- - cylp/cy/CyCgl.cpp | 3248 +++++++-------------- - cylp/cy/CyCglCutGeneratorBase.cpp | 3652 +++++++---------------- - cylp/cy/CyCglTreeInfo.cpp | 355 ++- - cylp/cy/CyClpDualRowPivotBase.cpp | 3623 +++++++---------------- - cylp/cy/CyClpPrimalColumnPivotBase.cpp | 3652 +++++++---------------- - cylp/cy/CyClpSimplex.cpp | 2852 +++++------------- - cylp/cy/CyCoinIndexedVector.cpp | 470 ++- - cylp/cy/CyCoinModel.cpp | 3055 +++++--------------- - cylp/cy/CyCoinMpsIO.cpp | 2732 +++++------------- - cylp/cy/CyCoinPackedMatrix.cpp | 3026 +++++-------------- - cylp/cy/CyCutGeneratorPythonBase.cpp | 2994 +++++-------------- - cylp/cy/CyDantzigPivot.cpp | 3217 ++++++--------------- - cylp/cy/CyDualPivotPythonBase.cpp | 3018 ++++++------------- - cylp/cy/CyOsiCuts.cpp | 3040 ++++++-------------- - cylp/cy/CyOsiSolverInterface.cpp | 3037 +++++--------------- - cylp/cy/CyPEPivot.cpp | 3214 ++++++--------------- - cylp/cy/CyPivotPythonBase.cpp | 3174 ++++++-------------- - cylp/cy/CyTest.cpp | 3588 +++++++---------------- - cylp/cy/CyWolfePivot.cpp | 3292 +++++++-------------- - 21 files changed, 17581 insertions(+), 44400 deletions(-) - -diff --git a/cylp/cy/CyCbcModel.cpp b/cylp/cy/CyCbcModel.cpp -index 14b5c2a..c62fd3b 100644 ---- a/cylp/cy/CyCbcModel.cpp -+++ b/cylp/cy/CyCbcModel.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.21 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_21" --#define CYTHON_HEX_VERSION 0x001D15F0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -450,7 +517,11 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) - #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif - #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) - #endif -@@ -556,10 +627,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) -@@ -622,7 +693,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include <string.h> - #include <stdio.h> - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "CglAllDifferent.hpp" - #include "CglClique.hpp" - #include "CglKnapsackCover.hpp" -@@ -650,11 +727,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "IClpDualRowPivotBase.h" - #include "CoinModel.hpp" - #include "ICoinPackedMatrix.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "IClpSimplex.hpp" - #include "ClpSimplex.hpp" -@@ -761,6 +838,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -916,7 +994,7 @@ static const char *__pyx_f[] = { - "cylp/cy/CyCutGeneratorPythonBase.pxd", - }; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":775 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -925,7 +1003,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -934,7 +1012,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -943,7 +1021,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -952,7 +1030,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":782 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -961,7 +1039,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -970,7 +1048,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -979,7 +1057,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -988,7 +1066,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":789 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -997,7 +1075,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -1006,7 +1084,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":799 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -1015,7 +1093,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1024,7 +1102,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1033,7 +1111,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":803 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1042,7 +1120,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1051,7 +1129,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1060,7 +1138,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":807 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1069,7 +1147,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1078,7 +1156,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":810 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1087,7 +1165,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1096,7 +1174,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1162,7 +1240,7 @@ struct __pyx_obj_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase; - struct __pyx_obj_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase; - struct __pyx_obj_4cylp_2cy_10CyCbcModel_CyCbcModel; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":814 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1171,7 +1249,7 @@ struct __pyx_obj_4cylp_2cy_10CyCbcModel_CyCbcModel; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1180,7 +1258,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1189,7 +1267,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":818 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1970,6 +2048,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -1977,6 +2056,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -2192,29 +2272,6 @@ static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) { - #define __Pyx_ListComp_Append(L,x) PyList_Append(L,x) - #endif - --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -2316,11 +2373,10 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); - static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -2420,12 +2476,15 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - #endif - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); - -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+ -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -+ - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -@@ -2542,8 +2601,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyCgl' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_5CyCgl_CyCglCutGenerator = 0; -@@ -2624,8 +2692,6 @@ static PyObject *__pyx_builtin_zip; - static PyObject *__pyx_builtin_AttributeError; - static PyObject *__pyx_builtin_TypeError; - static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_RuntimeError; - static const char __pyx_k_[] = ""; - static const char __pyx_k_zip[] = "zip"; - static const char __pyx_k_dims[] = "dims"; -@@ -2661,7 +2727,6 @@ static const char __pyx_k_itertools[] = "itertools"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; - static const char __pyx_k_whatDepth[] = "whatDepth"; - static const char __pyx_k_CyCbcModel[] = "CyCbcModel"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_atSolution[] = "atSolution"; - static const char __pyx_k_infeasible[] = "infeasible"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; -@@ -2669,7 +2734,6 @@ static const char __pyx_k_ImportError[] = "ImportError"; - static const char __pyx_k_cylp_py_mip[] = "cylp.py.mip"; - static const char __pyx_k_newSolution[] = "newSolution"; - static const char __pyx_k_CyLPSolution[] = "CyLPSolution"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_getVarByName[] = "getVarByName"; - static const char __pyx_k_howOftenInSub[] = "howOftenInSub"; - static const char __pyx_k_problemStatus[] = "problemStatus"; -@@ -2689,29 +2753,18 @@ static const char __pyx_k_relaxation_infeasible[] = "relaxation infeasible"; - static const char __pyx_k_stopped_on_user_event[] = "stopped on user event"; - static const char __pyx_k_pythonCutGeneratorObject[] = "pythonCutGeneratorObject"; - static const char __pyx_k_cylp_py_modeling_CyLPModel[] = "cylp.py.modeling.CyLPModel"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_setNodeCompare_argument_should_b[] = "setNodeCompare argument should be a NodeCompareBase object. Got %s"; - static const char __pyx_k_stopped_on_solutionslinear_relax[] = "stopped on solutionslinear relaxation unbounded"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_kp_s_; - static PyObject *__pyx_n_s_AttributeError; - static PyObject *__pyx_n_s_CyCbcModel; - static PyObject *__pyx_n_s_CyLPSolution; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; - static PyObject *__pyx_n_s_NodeCompareBase; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_addCutGenerator; - static PyObject *__pyx_n_s_append; - static PyObject *__pyx_n_s_atSolution; -@@ -2740,8 +2793,6 @@ static PyObject *__pyx_n_s_keys; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_name; - static PyObject *__pyx_n_s_name_2; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_n_s_newSolution; - static PyObject *__pyx_kp_s_no_default___reduce___due_to_non; - static PyObject *__pyx_n_s_normal; -@@ -2766,7 +2817,6 @@ static PyObject *__pyx_kp_s_stopped_on_solutionslinear_relax; - static PyObject *__pyx_kp_s_stopped_on_time; - static PyObject *__pyx_kp_s_stopped_on_user_event; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_n_s_unset; - static PyObject *__pyx_kp_s_utf_8; - static PyObject *__pyx_n_s_varIndex; -@@ -2813,8 +2863,6 @@ static PyObject *__pyx_pf_4cylp_2cy_10CyCbcModel_10CyCbcModel_16maximumSolutions - static int __pyx_pf_4cylp_2cy_10CyCbcModel_10CyCbcModel_16maximumSolutions_2__set__(struct __pyx_obj_4cylp_2cy_10CyCbcModel_CyCbcModel *__pyx_v_self, PyObject *__pyx_v_value); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_10CyCbcModel_10CyCbcModel_20__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_10CyCbcModel_CyCbcModel *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_10CyCbcModel_10CyCbcModel_22__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_10CyCbcModel_CyCbcModel *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_10CyCbcModel_CyCbcModel(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_int_1; - static PyObject *__pyx_int_neg_1; -@@ -2823,11 +2871,6 @@ static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; - static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; --static PyObject *__pyx_tuple__10; - /* Late includes */ - - /* "cylp/cy/CyCbcModel.pyx":14 -@@ -7397,1939 +7440,331 @@ static PyObject *__pyx_pf_4cylp_2cy_10CyCbcModel_10CyCbcModel_22__setstate_cytho - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t -+ * -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * - */ - --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -+ PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -+ PyObject *__pyx_t_1 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): -+ * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< - * -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): - */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t - * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) - */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":271 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") - */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":275 -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":279 -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. - */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * - */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * - */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef int t - */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< - * -+ * cdef inline tuple PyDataType_SHAPE(dtype d): - */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":820 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * -- * cdef inline object PyArray_MultiIterNew1(a): -- * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 821, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":820 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":823 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 824, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":823 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":826 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 827, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":826 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":829 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 830, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":829 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":832 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 833, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":832 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":835 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -- * else: -- * return () -- */ -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -- __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":839 -- * return <tuple>d.subarray.shape -- * else: -- * return () # <<<<<<<<<<<<<< -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -- */ -- /*else*/ { -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(__pyx_empty_tuple); -- __pyx_r = __pyx_empty_tuple; -- goto __pyx_L0; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":835 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- -- /* function exit code */ -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":841 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":846 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":850 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 850, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 850, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 850, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 852, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":854 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 854, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 854, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 854, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 855, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":854 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":857 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":857 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 859, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 859, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":857 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":869 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 869, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 869, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 869, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":874 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":876 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 877, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 879, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 879, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":882 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 882, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 882, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 882, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":900 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 900, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 900, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 900, __pyx_L1_error) -- } -- __pyx_L15:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ int __pyx_t_1; -+ __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":876 -- * offset[0] += child.itemsize -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ -- goto __pyx_L13; -- } -+ __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -+ if (__pyx_t_1) { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":905 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -+ * else: -+ * return () - */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 905, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -+ __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":850 -- * cdef tuple fields -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ - } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 -+ * return <tuple>d.subarray.shape -+ * else: -+ * return () # <<<<<<<<<<<<<< - * - * - */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -+ /*else*/ { -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(__pyx_empty_tuple); -+ __pyx_r = __pyx_empty_tuple; -+ goto __pyx_L0; -+ } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":841 -- * return () -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ - - /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; - __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -+ __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1021 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -9341,7 +7776,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -9350,7 +7785,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -9359,7 +7794,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1021 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -9371,7 +7806,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1025 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -9386,7 +7821,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -9395,7 +7830,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -9405,7 +7840,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -9416,7 +7851,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -9425,7 +7860,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -9437,7 +7872,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1025 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -9452,12 +7887,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1033 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -9476,11 +7911,11 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -9492,20 +7927,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1035, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -9515,9 +7950,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -9525,32 +7960,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1036, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -9561,12 +7996,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1033 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -9584,7 +8019,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1039 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -9608,7 +8043,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -9624,16 +8059,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1041, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -9647,7 +8082,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -9657,28 +8092,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1042, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -9693,7 +8128,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1039 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -9716,7 +8151,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1045 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -9740,7 +8175,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -9756,16 +8191,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1047, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -9779,69 +8214,246 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1048, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 -+ * -+ * cdef inline int import_ufunc() except -1: -+ * try: # <<<<<<<<<<<<<< -+ * _import_umath() -+ * except Exception: -+ */ -+ __Pyx_XGIVEREF(__pyx_t_1); -+ __Pyx_XGIVEREF(__pyx_t_2); -+ __Pyx_XGIVEREF(__pyx_t_3); -+ __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -+ goto __pyx_L1_error; -+ __pyx_L8_try_end:; -+ } -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 -+ * raise ImportError("numpy.core.umath failed to import") -+ * -+ * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -+ * try: -+ * _import_umath() -+ */ -+ -+ /* function exit code */ -+ __pyx_r = 0; -+ goto __pyx_L0; -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_5); -+ __Pyx_XDECREF(__pyx_t_6); -+ __Pyx_XDECREF(__pyx_t_7); -+ __Pyx_XDECREF(__pyx_t_8); -+ __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = -1; -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: -- * try: # <<<<<<<<<<<<<< -- * _import_umath() -- * except Exception: -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ -- __Pyx_XGIVEREF(__pyx_t_1); -- __Pyx_XGIVEREF(__pyx_t_2); -- __Pyx_XGIVEREF(__pyx_t_3); -- __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -- goto __pyx_L1_error; -- __pyx_L8_try_end:; -- } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1045 -- * raise ImportError("numpy.core.umath failed to import") -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_5); -- __Pyx_XDECREF(__pyx_t_6); -- __Pyx_XDECREF(__pyx_t_7); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; - __pyx_L0:; -- __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - static struct __pyx_vtabstruct_4cylp_2cy_10CyCbcModel_CyCbcModel __pyx_vtable_4cylp_2cy_10CyCbcModel_CyCbcModel; -@@ -10184,6 +8796,9 @@ static PyTypeObject __pyx_type_4cylp_2cy_10CyCbcModel_CyCbcModel = { - #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 - 0, /*tp_print*/ - #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -10236,14 +8851,9 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_AttributeError, __pyx_k_AttributeError, sizeof(__pyx_k_AttributeError), 0, 0, 1, 1}, - {&__pyx_n_s_CyCbcModel, __pyx_k_CyCbcModel, sizeof(__pyx_k_CyCbcModel), 0, 0, 1, 1}, - {&__pyx_n_s_CyLPSolution, __pyx_k_CyLPSolution, sizeof(__pyx_k_CyLPSolution), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, - {&__pyx_n_s_NodeCompareBase, __pyx_k_NodeCompareBase, sizeof(__pyx_k_NodeCompareBase), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_addCutGenerator, __pyx_k_addCutGenerator, sizeof(__pyx_k_addCutGenerator), 0, 0, 1, 1}, - {&__pyx_n_s_append, __pyx_k_append, sizeof(__pyx_k_append), 0, 0, 1, 1}, - {&__pyx_n_s_atSolution, __pyx_k_atSolution, sizeof(__pyx_k_atSolution), 0, 0, 1, 1}, -@@ -10272,8 +8882,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, - {&__pyx_n_s_name_2, __pyx_k_name_2, sizeof(__pyx_k_name_2), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_n_s_newSolution, __pyx_k_newSolution, sizeof(__pyx_k_newSolution), 0, 0, 1, 1}, - {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, - {&__pyx_n_s_normal, __pyx_k_normal, sizeof(__pyx_k_normal), 0, 0, 1, 1}, -@@ -10298,7 +8906,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_kp_s_stopped_on_time, __pyx_k_stopped_on_time, sizeof(__pyx_k_stopped_on_time), 0, 0, 1, 0}, - {&__pyx_kp_s_stopped_on_user_event, __pyx_k_stopped_on_user_event, sizeof(__pyx_k_stopped_on_user_event), 0, 0, 1, 0}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {&__pyx_n_s_unset, __pyx_k_unset, sizeof(__pyx_k_unset), 0, 0, 1, 1}, - {&__pyx_kp_s_utf_8, __pyx_k_utf_8, sizeof(__pyx_k_utf_8), 0, 0, 1, 0}, - {&__pyx_n_s_varIndex, __pyx_k_varIndex, sizeof(__pyx_k_varIndex), 0, 0, 1, 1}, -@@ -10314,8 +8921,6 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_AttributeError = __Pyx_GetBuiltinName(__pyx_n_s_AttributeError); if (!__pyx_builtin_AttributeError) __PYX_ERR(0, 99, __pyx_L1_error) - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 112, __pyx_L1_error) - __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 199, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 855, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -10344,82 +8949,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__3); - __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 879, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1037, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__10 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(2, 1043, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__10); -- __Pyx_GIVEREF(__pyx_tuple__10); -+ __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__5); -+ __Pyx_GIVEREF(__pyx_tuple__5); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -10527,18 +9077,38 @@ static int __Pyx_modinit_type_import_code(void) { - __pyx_ptype_7cpython_7complex_complex = __Pyx_ImportType(__pyx_t_1, __Pyx_BUILTIN_MODULE_NAME, "complex", sizeof(PyComplexObject), __Pyx_ImportType_CheckSize_Warn); - if (!__pyx_ptype_7cpython_7complex_complex) __PYX_ERR(5, 15, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 917, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyCgl"); if (unlikely(!__pyx_t_1)) __PYX_ERR(6, 103, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -10827,11 +9397,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -11097,12 +9665,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_7) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1045 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -11300,7 +9868,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -11672,7 +10240,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -12142,61 +10710,6 @@ static PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject* key) { - } - #endif - --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -12718,7 +11231,7 @@ static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -12815,30 +11328,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -12857,11 +11371,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -12915,68 +11434,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - return (target_type) value;\ - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(long) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(long) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(long) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(long), -- little, !is_unsigned); -- } --} -- - /* Declarations */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus -@@ -13285,40 +11742,16 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { - #endif - #endif - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -13505,9 +11938,92 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - return (int) -1; - } - -+/* CIntToPy */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(int) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); -+ } -+} -+ -+/* CIntToPy */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(long) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(long) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(long) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(long), -+ little, !is_unsigned); -+ } -+} -+ - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -14058,6 +12574,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyCbcNode.cpp b/cylp/cy/CyCbcNode.cpp -index a50a01a..c6b7608 100644 ---- a/cylp/cy/CyCbcNode.cpp -+++ b/cylp/cy/CyCbcNode.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -610,7 +693,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include <string.h> - #include <stdio.h> - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ICbcNode.hpp" - #ifdef _OPENMP - #include <omp.h> -@@ -708,6 +797,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -843,12 +933,12 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyCbcNode.pyx", -+ "cylp/cy/CyCbcNode.pyx", - "__init__.pxd", - "type.pxd", - }; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -857,7 +947,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -866,7 +956,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -875,7 +965,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -884,7 +974,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -893,7 +983,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -902,7 +992,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -911,7 +1001,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -920,7 +1010,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -929,7 +1019,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -938,7 +1028,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -947,7 +1037,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -956,7 +1046,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -965,7 +1055,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -974,7 +1064,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -983,7 +1073,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -992,7 +1082,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1001,7 +1091,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1010,7 +1100,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1019,7 +1109,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1028,7 +1118,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1064,7 +1154,7 @@ static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(do - /*--- Type declarations ---*/ - struct __pyx_obj_4cylp_2cy_9CyCbcNode_CyCbcNode; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1073,7 +1163,7 @@ struct __pyx_obj_4cylp_2cy_9CyCbcNode_CyCbcNode; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1082,7 +1172,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1091,7 +1181,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1261,67 +1351,6 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* PyCFunctionFastCall.proto */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); --#else --#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) --#endif -- --/* PyFunctionFastCall.proto */ --#if CYTHON_FAST_PYCALL --#define __Pyx_PyFunction_FastCall(func, args, nargs)\ -- __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); --#else --#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) --#endif --#define __Pyx_BUILD_ASSERT_EXPR(cond)\ -- (sizeof(char [1 - 2*!(cond)]) - 1) --#ifndef Py_MEMBER_SIZE --#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) --#endif -- static size_t __pyx_pyframe_localsplus_offset = 0; -- #include "frameobject.h" -- #define __Pxy_PyFrame_Initialize_Offsets()\ -- ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ -- (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) -- #define __Pyx_PyFrame_GetLocalsplus(frame)\ -- (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) --#endif -- --/* PyObjectCallMethO.proto */ --#if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); --#endif -- --/* PyObjectCallOneArg.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); -- --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -1371,6 +1400,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -1479,8 +1511,10 @@ static void __Pyx_CppExn2PyErr() { - } - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -1581,10 +1615,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - #endif - - /* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- --/* CIntFromPy.proto */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -@@ -1592,6 +1623,9 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -+/* CIntFromPy.proto */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+ - /* FastTypeChecks.proto */ - #if CYTHON_COMPILING_IN_CPYTHON - #define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -@@ -1639,8 +1673,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyCbcNode' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_9CyCbcNode_CyCbcNode = 0; -@@ -1650,62 +1693,41 @@ int __pyx_module_is_main_cylp__cy__CyCbcNode = 0; - - /* Implementation of 'cylp.cy.CyCbcNode' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_test[] = "__test__"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_reduce[] = "__reduce__"; - static const char __pyx_k_getstate[] = "__getstate__"; - static const char __pyx_k_setstate[] = "__setstate__"; - static const char __pyx_k_CyCbcNode[] = "CyCbcNode"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyCbcNode; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_getstate; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_no_default___reduce___due_to_non; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; - static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static int __pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode___cinit__(struct __pyx_obj_4cylp_2cy_9CyCbcNode_CyCbcNode *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_5depth___get__(struct __pyx_obj_4cylp_2cy_9CyCbcNode_CyCbcNode *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_17numberUnsatisfied___get__(struct __pyx_obj_4cylp_2cy_9CyCbcNode_CyCbcNode *__pyx_v_self); /* proto */ -@@ -1716,18 +1738,11 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_14objectiveValue___get - static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_2breakTie(struct __pyx_obj_4cylp_2cy_9CyCbcNode_CyCbcNode *__pyx_v_self, struct __pyx_obj_4cylp_2cy_9CyCbcNode_CyCbcNode *__pyx_v_y); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_4__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_9CyCbcNode_CyCbcNode *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_6__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_9CyCbcNode_CyCbcNode *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_9CyCbcNode_CyCbcNode(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; --static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; - /* Late includes */ - - /* "cylp/cy/CyCbcNode.pyx":7 -@@ -1758,6 +1773,9 @@ static int __pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode___cinit__(struct __pyx_obj_4 - int __pyx_r; - __Pyx_RefNannyDeclarations - ICbcNode *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCbcNode.pyx":8 -@@ -1868,6 +1886,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_5depth___get__(struct - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCbcNode.pyx":16 -@@ -1928,6 +1949,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_17numberUnsatisfied___ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCbcNode.pyx":20 -@@ -1988,6 +2012,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_18sumInfeasibilities__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCbcNode.pyx":24 -@@ -2048,6 +2075,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_6active___get__(struct - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCbcNode.pyx":28 -@@ -2108,6 +2138,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_6onTree___get__(struct - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCbcNode.pyx":32 -@@ -2168,6 +2201,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_14objectiveValue___get - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCbcNode.pyx":36 -@@ -2214,6 +2250,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_14objectiveValue___get - static PyObject *__pyx_pw_4cylp_2cy_9CyCbcNode_9CyCbcNode_3breakTie(PyObject *__pyx_v_self, PyObject *__pyx_v_y); /*proto*/ - static char __pyx_doc_4cylp_2cy_9CyCbcNode_9CyCbcNode_2breakTie[] = "CyCbcNode.breakTie(self, CyCbcNode y)"; - static PyObject *__pyx_pw_4cylp_2cy_9CyCbcNode_9CyCbcNode_3breakTie(PyObject *__pyx_v_self, PyObject *__pyx_v_y) { -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("breakTie (wrapper)", 0); -@@ -2233,6 +2272,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_2breakTie(struct __pyx - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("breakTie", 0); - - /* "cylp/cy/CyCbcNode.pyx":39 -@@ -2289,6 +2331,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_4__reduce_cython__(CYT - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -2344,6 +2389,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_6__setstate_cython__(C - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -2374,1084 +2422,243 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyCbcNode_9CyCbcNode_6__setstate_cython__(C - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t -+ * -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * - */ - --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -+ PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): -+ * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< - * -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): - */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t - * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) - */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") - */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. - */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * - */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< - * -- * cdef int t -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- * info.obj = self # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * if not PyDataType_HASFIELDS(descr): - */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< - * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -+ * cdef inline tuple PyDataType_SHAPE(dtype d): - */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -- * -- * cdef inline object PyArray_MultiIterNew1(a): -- * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -+ * - */ - - /* function exit code */ -@@ -3465,7 +2672,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -3479,7 +2686,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - int __pyx_t_1; - __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -3489,7 +2696,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): - * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -@@ -3501,7 +2708,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -3510,12 +2717,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 - * return <tuple>d.subarray.shape - * else: - * return () # <<<<<<<<<<<<<< - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -+ * - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); -@@ -3524,768 +2731,22 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - goto __pyx_L0; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- -- /* function exit code */ -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- goto __pyx_L13; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -- */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -- * -- * -- */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ - - /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; - __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -+ __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -4297,7 +2758,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -4306,7 +2767,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -4315,7 +2776,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -4327,7 +2788,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -4342,7 +2803,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -4351,7 +2812,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -4361,7 +2822,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -4372,7 +2833,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -4381,7 +2842,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -4393,7 +2854,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -4408,12 +2869,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -4427,13 +2888,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -4445,20 +2909,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -4468,9 +2932,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -4478,32 +2942,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -4514,12 +2978,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -4537,7 +3001,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -4556,9 +3020,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -4574,16 +3041,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -4597,7 +3064,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -4607,28 +3074,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -4643,7 +3110,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -4666,7 +3133,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -4685,9 +3152,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -4703,16 +3173,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -4726,35 +3196,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -4769,7 +3242,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -4791,6 +3264,180 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} - static struct __pyx_vtabstruct_4cylp_2cy_9CyCbcNode_CyCbcNode __pyx_vtable_4cylp_2cy_9CyCbcNode_CyCbcNode; - - static PyObject *__pyx_tp_new_4cylp_2cy_9CyCbcNode_CyCbcNode(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { -@@ -4867,7 +3514,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_9CyCbcNode_CyCbcNode = { - sizeof(struct __pyx_obj_4cylp_2cy_9CyCbcNode_CyCbcNode), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_9CyCbcNode_CyCbcNode, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -4920,6 +3572,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_9CyCbcNode_CyCbcNode = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -4969,39 +3627,27 @@ static struct PyModuleDef __pyx_moduledef = { - - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyCbcNode, __pyx_k_CyCbcNode, sizeof(__pyx_k_CyCbcNode), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -5030,82 +3676,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -5154,6 +3745,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_vtabptr_4cylp_2cy_9CyCbcNode_CyCbcNode = &__pyx_vtable_4cylp_2cy_9CyCbcNode_CyCbcNode; -@@ -5179,6 +3773,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -5192,18 +3789,38 @@ static int __Pyx_modinit_type_import_code(void) { - __Pyx_ImportType_CheckSize_Warn); - if (!__pyx_ptype_7cpython_4type_type) __PYX_ERR(3, 9, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; -@@ -5230,17 +3847,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -5322,6 +3941,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyCbcNode(PyObject *__pyx_pyinit_m - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -5369,11 +3991,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -5410,15 +4030,15 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ -@@ -5436,12 +4056,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -5605,7 +4225,7 @@ static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *nam - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -5804,263 +4424,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* PyCFunctionFastCall */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { -- PyCFunctionObject *func = (PyCFunctionObject*)func_obj; -- PyCFunction meth = PyCFunction_GET_FUNCTION(func); -- PyObject *self = PyCFunction_GET_SELF(func); -- int flags = PyCFunction_GET_FLAGS(func); -- assert(PyCFunction_Check(func)); -- assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); -- assert(nargs >= 0); -- assert(nargs == 0 || args != NULL); -- /* _PyCFunction_FastCallDict() must not be called with an exception set, -- because it may clear it (directly or indirectly) and so the -- caller loses its exception */ -- assert(!PyErr_Occurred()); -- if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { -- return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); -- } else { -- return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); -- } --} --#endif -- --/* PyFunctionFastCall */ --#if CYTHON_FAST_PYCALL --static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, -- PyObject *globals) { -- PyFrameObject *f; -- PyThreadState *tstate = __Pyx_PyThreadState_Current; -- PyObject **fastlocals; -- Py_ssize_t i; -- PyObject *result; -- assert(globals != NULL); -- /* XXX Perhaps we should create a specialized -- PyFrame_New() that doesn't take locals, but does -- take builtins without sanity checking them. -- */ -- assert(tstate != NULL); -- f = PyFrame_New(tstate, co, globals, NULL); -- if (f == NULL) { -- return NULL; -- } -- fastlocals = __Pyx_PyFrame_GetLocalsplus(f); -- for (i = 0; i < na; i++) { -- Py_INCREF(*args); -- fastlocals[i] = *args++; -- } -- result = PyEval_EvalFrameEx(f,0); -- ++tstate->recursion_depth; -- Py_DECREF(f); -- --tstate->recursion_depth; -- return result; --} --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { -- PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); -- PyObject *globals = PyFunction_GET_GLOBALS(func); -- PyObject *argdefs = PyFunction_GET_DEFAULTS(func); -- PyObject *closure; --#if PY_MAJOR_VERSION >= 3 -- PyObject *kwdefs; --#endif -- PyObject *kwtuple, **k; -- PyObject **d; -- Py_ssize_t nd; -- Py_ssize_t nk; -- PyObject *result; -- assert(kwargs == NULL || PyDict_Check(kwargs)); -- nk = kwargs ? PyDict_Size(kwargs) : 0; -- if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { -- return NULL; -- } -- if ( --#if PY_MAJOR_VERSION >= 3 -- co->co_kwonlyargcount == 0 && --#endif -- likely(kwargs == NULL || nk == 0) && -- co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { -- if (argdefs == NULL && co->co_argcount == nargs) { -- result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); -- goto done; -- } -- else if (nargs == 0 && argdefs != NULL -- && co->co_argcount == Py_SIZE(argdefs)) { -- /* function called with no arguments, but all parameters have -- a default value: use default values as arguments .*/ -- args = &PyTuple_GET_ITEM(argdefs, 0); -- result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); -- goto done; -- } -- } -- if (kwargs != NULL) { -- Py_ssize_t pos, i; -- kwtuple = PyTuple_New(2 * nk); -- if (kwtuple == NULL) { -- result = NULL; -- goto done; -- } -- k = &PyTuple_GET_ITEM(kwtuple, 0); -- pos = i = 0; -- while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { -- Py_INCREF(k[i]); -- Py_INCREF(k[i+1]); -- i += 2; -- } -- nk = i / 2; -- } -- else { -- kwtuple = NULL; -- k = NULL; -- } -- closure = PyFunction_GET_CLOSURE(func); --#if PY_MAJOR_VERSION >= 3 -- kwdefs = PyFunction_GET_KW_DEFAULTS(func); --#endif -- if (argdefs != NULL) { -- d = &PyTuple_GET_ITEM(argdefs, 0); -- nd = Py_SIZE(argdefs); -- } -- else { -- d = NULL; -- nd = 0; -- } --#if PY_MAJOR_VERSION >= 3 -- result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, kwdefs, closure); --#else -- result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, closure); --#endif -- Py_XDECREF(kwtuple); --done: -- Py_LeaveRecursiveCall(); -- return result; --} --#endif --#endif -- --/* PyObjectCallMethO */ --#if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { -- PyObject *self, *result; -- PyCFunction cfunc; -- cfunc = PyCFunction_GET_FUNCTION(func); -- self = PyCFunction_GET_SELF(func); -- if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -- return NULL; -- result = cfunc(self, arg); -- Py_LeaveRecursiveCall(); -- if (unlikely(!result) && unlikely(!PyErr_Occurred())) { -- PyErr_SetString( -- PyExc_SystemError, -- "NULL result without error in PyObject_Call"); -- } -- return result; --} --#endif -- --/* PyObjectCallOneArg */ --#if CYTHON_COMPILING_IN_CPYTHON --static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_New(1); -- if (unlikely(!args)) return NULL; -- Py_INCREF(arg); -- PyTuple_SET_ITEM(args, 0, arg); -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { --#if CYTHON_FAST_PYCALL -- if (PyFunction_Check(func)) { -- return __Pyx_PyFunction_FastCall(func, &arg, 1); -- } --#endif -- if (likely(PyCFunction_Check(func))) { -- if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { -- return __Pyx_PyObject_CallMethO(func, arg); --#if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -- return __Pyx_PyCFunction_FastCall(func, &arg, 1); --#endif -- } -- } -- return __Pyx__PyObject_CallOneArg(func, arg); --} --#else --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_Pack(1, arg); -- if (unlikely(!args)) return NULL; -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --#endif -- --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -6284,6 +4647,28 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable) { - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -6311,43 +4696,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -6449,7 +4842,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -6479,7 +4872,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -6553,7 +4946,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -6576,30 +4969,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -6618,11 +5012,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -6654,37 +5053,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - Py_XDECREF(py_frame); - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- - /* Declarations */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus -@@ -6802,7 +5170,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -6957,7 +5324,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -6995,251 +5361,54 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - #endif - #endif - --/* CIntFromPyVerify */ --#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ -- __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) --#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ -- __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) --#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ -- {\ -- func_type value = func_value;\ -- if (sizeof(target_type) < sizeof(func_type)) {\ -- if (unlikely(value != (func_type) (target_type) value)) {\ -- func_type zero = 0;\ -- if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ -- return (target_type) -1;\ -- if (is_unsigned && unlikely(value < zero))\ -- goto raise_neg_overflow;\ -- else\ -- goto raise_overflow;\ -- }\ -- }\ -- return (target_type) value;\ -- } -- - /* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; - const int is_unsigned = neg_one > const_zero; --#if PY_MAJOR_VERSION < 3 -- if (likely(PyInt_Check(x))) { -+ if (is_unsigned) { - if (sizeof(int) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) -- } else { -- long val = PyInt_AS_LONG(x); -- if (is_unsigned && unlikely(val < 0)) { -- goto raise_neg_overflow; -- } -- return (int) val; -- } -- } else --#endif -- if (likely(PyLong_Check(x))) { -- if (is_unsigned) { --#if CYTHON_USE_PYLONG_INTERNALS -- const digit* digits = ((PyLongObject*)x)->ob_digit; -- switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) -- case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -- return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -- } -- } -- break; -- case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -- return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -- } -- } -- break; -- case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -- return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -- } -- } -- break; -- } --#endif --#if CYTHON_COMPILING_IN_CPYTHON -- if (unlikely(Py_SIZE(x) < 0)) { -- goto raise_neg_overflow; -- } --#else -- { -- int result = PyObject_RichCompareBool(x, Py_False, Py_LT); -- if (unlikely(result < 0)) -- return (int) -1; -- if (unlikely(result == 1)) -- goto raise_neg_overflow; -- } --#endif -- if (sizeof(int) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) --#endif -- } -- } else { --#if CYTHON_USE_PYLONG_INTERNALS -- const digit* digits = ((PyLongObject*)x)->ob_digit; -- switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) -- case -2: -- if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- case -3: -- if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- case -4: -- if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- } --#endif -- if (sizeof(int) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) --#endif -- } -- } -- { --#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) -- PyErr_SetString(PyExc_RuntimeError, -- "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); --#else -- int val; -- PyObject *v = __Pyx_PyNumber_IntOrLong(x); -- #if PY_MAJOR_VERSION < 3 -- if (likely(v) && !PyLong_Check(v)) { -- PyObject *tmp = v; -- v = PyNumber_Long(tmp); -- Py_DECREF(tmp); -- } -- #endif -- if (likely(v)) { -- int one = 1; int is_little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&val; -- int ret = _PyLong_AsByteArray((PyLongObject *)v, -- bytes, sizeof(val), -- is_little, !is_unsigned); -- Py_DECREF(v); -- if (likely(!ret)) -- return val; -- } -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif -- return (int) -1; - } - } else { -- int val; -- PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (int) -1; -- val = __Pyx_PyInt_As_int(tmp); -- Py_DECREF(tmp); -- return val; -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); - } --raise_overflow: -- PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to int"); -- return (int) -1; --raise_neg_overflow: -- PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to int"); -- return (int) -1; - } - - /* CIntToPy */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { -@@ -7268,9 +5437,38 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { - } - } - -+/* CIntFromPyVerify */ -+#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ -+ __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -+#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ -+ __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) -+#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ -+ {\ -+ func_type value = func_value;\ -+ if (sizeof(target_type) < sizeof(func_type)) {\ -+ if (unlikely(value != (func_type) (target_type) value)) {\ -+ func_type zero = 0;\ -+ if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ -+ return (target_type) -1;\ -+ if (is_unsigned && unlikely(value < zero))\ -+ goto raise_neg_overflow;\ -+ else\ -+ goto raise_overflow;\ -+ }\ -+ }\ -+ return (target_type) value;\ -+ } -+ - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -7457,6 +5655,202 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - return (long) -1; - } - -+/* CIntFromPy */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+#if PY_MAJOR_VERSION < 3 -+ if (likely(PyInt_Check(x))) { -+ if (sizeof(int) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) -+ } else { -+ long val = PyInt_AS_LONG(x); -+ if (is_unsigned && unlikely(val < 0)) { -+ goto raise_neg_overflow; -+ } -+ return (int) val; -+ } -+ } else -+#endif -+ if (likely(PyLong_Check(x))) { -+ if (is_unsigned) { -+#if CYTHON_USE_PYLONG_INTERNALS -+ const digit* digits = ((PyLongObject*)x)->ob_digit; -+ switch (Py_SIZE(x)) { -+ case 0: return (int) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) -+ case 2: -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -+ return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ } -+ } -+ break; -+ case 3: -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -+ return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ } -+ } -+ break; -+ case 4: -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -+ return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ } -+ } -+ break; -+ } -+#endif -+#if CYTHON_COMPILING_IN_CPYTHON -+ if (unlikely(Py_SIZE(x) < 0)) { -+ goto raise_neg_overflow; -+ } -+#else -+ { -+ int result = PyObject_RichCompareBool(x, Py_False, Py_LT); -+ if (unlikely(result < 0)) -+ return (int) -1; -+ if (unlikely(result == 1)) -+ goto raise_neg_overflow; -+ } -+#endif -+ if (sizeof(int) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+#endif -+ } -+ } else { -+#if CYTHON_USE_PYLONG_INTERNALS -+ const digit* digits = ((PyLongObject*)x)->ob_digit; -+ switch (Py_SIZE(x)) { -+ case 0: return (int) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) -+ case -2: -+ if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ case 2: -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ case -3: -+ if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ case 3: -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ case -4: -+ if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ case 4: -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ } -+#endif -+ if (sizeof(int) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -+#endif -+ } -+ } -+ { -+#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) -+ PyErr_SetString(PyExc_RuntimeError, -+ "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); -+#else -+ int val; -+ PyObject *v = __Pyx_PyNumber_IntOrLong(x); -+ #if PY_MAJOR_VERSION < 3 -+ if (likely(v) && !PyLong_Check(v)) { -+ PyObject *tmp = v; -+ v = PyNumber_Long(tmp); -+ Py_DECREF(tmp); -+ } -+ #endif -+ if (likely(v)) { -+ int one = 1; int is_little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&val; -+ int ret = _PyLong_AsByteArray((PyLongObject *)v, -+ bytes, sizeof(val), -+ is_little, !is_unsigned); -+ Py_DECREF(v); -+ if (likely(!ret)) -+ return val; -+ } -+#endif -+ return (int) -1; -+ } -+ } else { -+ int val; -+ PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -+ if (!tmp) return (int) -1; -+ val = __Pyx_PyInt_As_int(tmp); -+ Py_DECREF(tmp); -+ return val; -+ } -+raise_overflow: -+ PyErr_SetString(PyExc_OverflowError, -+ "value too large to convert to int"); -+ return (int) -1; -+raise_neg_overflow: -+ PyErr_SetString(PyExc_OverflowError, -+ "can't convert negative value to int"); -+ return (int) -1; -+} -+ - /* FastTypeChecks */ - #if CYTHON_COMPILING_IN_CPYTHON - static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { -@@ -7821,6 +6215,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyCgl.cpp b/cylp/cy/CyCgl.cpp -index c210ec9..0e19d5e 100644 ---- a/cylp/cy/CyCgl.cpp -+++ b/cylp/cy/CyCgl.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -610,7 +693,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include <string.h> - #include <stdio.h> - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "CglAllDifferent.hpp" - #include "CglClique.hpp" - #include "CglKnapsackCover.hpp" -@@ -724,6 +813,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -859,12 +949,12 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyCgl.pyx", -+ "cylp/cy/CyCgl.pyx", - "__init__.pxd", - "type.pxd", - }; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -873,7 +963,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -882,7 +972,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -891,7 +981,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -900,7 +990,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -909,7 +999,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -918,7 +1008,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -927,7 +1017,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -936,7 +1026,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -945,7 +1035,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -954,7 +1044,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -963,7 +1053,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -972,7 +1062,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -981,7 +1071,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -990,7 +1080,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -999,7 +1089,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1008,7 +1098,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1017,7 +1107,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1026,7 +1116,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1035,7 +1125,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1044,7 +1134,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1096,7 +1186,7 @@ struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglPreProcess; - struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglProbing; - struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglSimpleRounding; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1105,7 +1195,7 @@ struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglSimpleRounding; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1114,7 +1204,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1123,7 +1213,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1511,67 +1601,6 @@ static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr - #define __Pyx_PyObject_SetAttrStr(o,n,v) PyObject_SetAttr(o,n,v) - #endif - --/* PyCFunctionFastCall.proto */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); --#else --#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) --#endif -- --/* PyFunctionFastCall.proto */ --#if CYTHON_FAST_PYCALL --#define __Pyx_PyFunction_FastCall(func, args, nargs)\ -- __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); --#else --#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) --#endif --#define __Pyx_BUILD_ASSERT_EXPR(cond)\ -- (sizeof(char [1 - 2*!(cond)]) - 1) --#ifndef Py_MEMBER_SIZE --#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) --#endif -- static size_t __pyx_pyframe_localsplus_offset = 0; -- #include "frameobject.h" -- #define __Pxy_PyFrame_Initialize_Offsets()\ -- ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ -- (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) -- #define __Pyx_PyFrame_GetLocalsplus(frame)\ -- (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) --#endif -- --/* PyObjectCallMethO.proto */ --#if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); --#endif -- --/* PyObjectCallOneArg.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); -- --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -1618,6 +1647,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - #define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr - #endif - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -1729,8 +1761,10 @@ static void __Pyx_CppExn2PyErr() { - } - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -1831,7 +1865,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - #endif - - /* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -@@ -1890,8 +1924,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyCgl' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_5CyCgl_CyCglCutGenerator = 0; -@@ -1917,22 +1960,17 @@ int __pyx_module_is_main_cylp__cy__CyCgl = 0; - - /* Implementation of 'cylp.cy.CyCgl' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_test[] = "__test__"; - static const char __pyx_k_limit[] = "limit"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_reduce[] = "__reduce__"; - static const char __pyx_k_getstate[] = "__getstate__"; - static const char __pyx_k_setstate[] = "__setstate__"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; - static const char __pyx_k_CyCglLandP[] = "CyCglLandP"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_CyCglClique[] = "CyCglClique"; - static const char __pyx_k_CyCglGomory[] = "CyCglGomory"; -@@ -1940,7 +1978,6 @@ static const char __pyx_k_CyCglTwomir[] = "CyCglTwomir"; - static const char __pyx_k_ImportError[] = "ImportError"; - static const char __pyx_k_CyCglOddHole[] = "CyCglOddHole"; - static const char __pyx_k_CyCglProbing[] = "CyCglProbing"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_CyCglRedSplit[] = "CyCglRedSplit"; - static const char __pyx_k_maxInKnapsack[] = "maxInKnapsack"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; -@@ -1956,16 +1993,10 @@ static const char __pyx_k_CyCglSimpleRounding[] = "CyCglSimpleRounding"; - static const char __pyx_k_CyCglResidualCapacity[] = "CyCglResidualCapacity"; - static const char __pyx_k_CyCglMixedIntegerRounding[] = "CyCglMixedIntegerRounding"; - static const char __pyx_k_CyCglMixedIntegerRounding2[] = "CyCglMixedIntegerRounding2"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_self_CppSelf_cannot_be_converted[] = "self.CppSelf cannot be converted to a Python object for pickling"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyCglAllDifferent; - static PyObject *__pyx_n_s_CyCglClique; - static PyObject *__pyx_n_s_CyCglCutGenerator; -@@ -1983,26 +2014,18 @@ static PyObject *__pyx_n_s_CyCglRedSplit; - static PyObject *__pyx_n_s_CyCglResidualCapacity; - static PyObject *__pyx_n_s_CyCglSimpleRounding; - static PyObject *__pyx_n_s_CyCglTwomir; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_getstate; - static PyObject *__pyx_n_s_limit; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_maxInKnapsack; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_no_default___reduce___due_to_non; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -2010,7 +2033,6 @@ static PyObject *__pyx_kp_s_self_CppSelf_cannot_be_converted; - static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_17CyCglCutGenerator___reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglCutGenerator *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_17CyCglCutGenerator_2__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglCutGenerator *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ - static int __pyx_pf_4cylp_2cy_5CyCgl_17CyCglAllDifferent___cinit__(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglAllDifferent *__pyx_v_self); /* proto */ -@@ -2065,8 +2087,6 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_12CyCglProbing_4__setstate_cython__(C - static int __pyx_pf_4cylp_2cy_5CyCgl_19CyCglSimpleRounding___cinit__(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglSimpleRounding *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_19CyCglSimpleRounding_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglSimpleRounding *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_19CyCglSimpleRounding_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglSimpleRounding *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglCutGenerator(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglAllDifferent(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglClique(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ -@@ -2121,11 +2141,6 @@ static PyObject *__pyx_tuple__33; - static PyObject *__pyx_tuple__34; - static PyObject *__pyx_tuple__35; - static PyObject *__pyx_tuple__36; --static PyObject *__pyx_tuple__37; --static PyObject *__pyx_tuple__38; --static PyObject *__pyx_tuple__39; --static PyObject *__pyx_tuple__40; --static PyObject *__pyx_tuple__41; - /* Late includes */ - - /* "(tree fragment)":1 -@@ -2151,6 +2166,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_17CyCglCutGenerator___reduce_cython__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -2205,6 +2223,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_17CyCglCutGenerator_2__setstate_cytho - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -2263,6 +2284,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_17CyCglAllDifferent___cinit__(struct __pyx_ - int __pyx_r; - __Pyx_RefNannyDeclarations - CglAllDifferent *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":9 -@@ -2322,6 +2346,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_17CyCglAllDifferent_2__reduce_cython_ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -2376,6 +2403,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_17CyCglAllDifferent_4__setstate_cytho - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -2434,6 +2464,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_11CyCglClique___cinit__(struct __pyx_obj_4c - int __pyx_r; - __Pyx_RefNannyDeclarations - CglClique *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":13 -@@ -2493,6 +2526,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_11CyCglClique_2__reduce_cython__(CYTH - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -2547,6 +2583,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_11CyCglClique_4__setstate_cython__(CY - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -2589,6 +2628,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_11CyCglClique_4__setstate_cython__(CY - static int __pyx_pw_4cylp_2cy_5CyCgl_18CyCglKnapsackCover_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ - static int __pyx_pw_4cylp_2cy_5CyCgl_18CyCglKnapsackCover_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_maxInKnapsack = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - int __pyx_r; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); -@@ -2645,6 +2687,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_18CyCglKnapsackCover___cinit__(struct __pyx - int __pyx_r; - __Pyx_RefNannyDeclarations - CglKnapsackCover *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":17 -@@ -2752,6 +2797,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_18CyCglKnapsackCover_13maxInKnapsack_ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCgl.pyx":25 -@@ -2812,6 +2860,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_18CyCglKnapsackCover_13maxInKnapsack_2__set - int __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__set__", 0); - - /* "cylp/cy/CyCgl.pyx":28 -@@ -2866,6 +2917,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_18CyCglKnapsackCover_2__reduce_cython - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -2920,6 +2974,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_18CyCglKnapsackCover_4__setstate_cyth - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -2978,6 +3035,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_12CyCglOddHole___cinit__(struct __pyx_obj_4 - int __pyx_r; - __Pyx_RefNannyDeclarations - CglOddHole *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":32 -@@ -3037,6 +3097,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_12CyCglOddHole_2__reduce_cython__(CYT - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3091,6 +3154,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_12CyCglOddHole_4__setstate_cython__(C - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3149,6 +3215,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_14CyCglFlowCover___cinit__(struct __pyx_obj - int __pyx_r; - __Pyx_RefNannyDeclarations - CglFlowCover *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":38 -@@ -3208,6 +3277,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_14CyCglFlowCover_2__reduce_cython__(C - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3262,6 +3334,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_14CyCglFlowCover_4__setstate_cython__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3304,6 +3379,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_14CyCglFlowCover_4__setstate_cython__ - static int __pyx_pw_4cylp_2cy_5CyCgl_11CyCglGomory_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ - static int __pyx_pw_4cylp_2cy_5CyCgl_11CyCglGomory_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_limit = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - int __pyx_r; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); -@@ -3360,6 +3438,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_11CyCglGomory___cinit__(struct __pyx_obj_4c - int __pyx_r; - __Pyx_RefNannyDeclarations - CglGomory *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":44 -@@ -3467,6 +3548,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_11CyCglGomory_5limit___get__(struct _ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCgl.pyx":52 -@@ -3527,6 +3611,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_11CyCglGomory_5limit_2__set__(struct __pyx_ - int __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__set__", 0); - - /* "cylp/cy/CyCgl.pyx":55 -@@ -3581,6 +3668,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_11CyCglGomory_2__reduce_cython__(CYTH - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3635,6 +3725,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_11CyCglGomory_4__setstate_cython__(CY - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3693,6 +3786,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_13CyCglRedSplit___cinit__(struct __pyx_obj_ - int __pyx_r; - __Pyx_RefNannyDeclarations - CglRedSplit *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":59 -@@ -3752,6 +3848,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_13CyCglRedSplit_2__reduce_cython__(CY - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3806,6 +3905,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_13CyCglRedSplit_4__setstate_cython__( - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3864,6 +3966,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_19CyCglLiftAndProject___cinit__(struct __py - int __pyx_r; - __Pyx_RefNannyDeclarations - CglLiftAndProject *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":65 -@@ -3923,6 +4028,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_19CyCglLiftAndProject_2__reduce_cytho - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3977,6 +4085,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_19CyCglLiftAndProject_4__setstate_cyt - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -4035,6 +4146,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_10CyCglLandP___cinit__(struct __pyx_obj_4cy - int __pyx_r; - __Pyx_RefNannyDeclarations - CglLandP *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":69 -@@ -4094,6 +4208,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_10CyCglLandP_2__reduce_cython__(CYTHO - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -4148,6 +4265,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_10CyCglLandP_4__setstate_cython__(CYT - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -4206,6 +4326,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_25CyCglMixedIntegerRounding___cinit__(struc - int __pyx_r; - __Pyx_RefNannyDeclarations - CglMixedIntegerRounding *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":75 -@@ -4265,6 +4388,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_25CyCglMixedIntegerRounding_2__reduce - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -4319,6 +4445,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_25CyCglMixedIntegerRounding_4__setsta - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -4377,6 +4506,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_26CyCglMixedIntegerRounding2___cinit__(stru - int __pyx_r; - __Pyx_RefNannyDeclarations - CglMixedIntegerRounding2 *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":79 -@@ -4436,6 +4568,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_26CyCglMixedIntegerRounding2_2__reduc - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -4490,6 +4625,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_26CyCglMixedIntegerRounding2_4__setst - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -4548,6 +4686,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_11CyCglTwomir___cinit__(struct __pyx_obj_4c - int __pyx_r; - __Pyx_RefNannyDeclarations - CglTwomir *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":83 -@@ -4607,6 +4748,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_11CyCglTwomir_2__reduce_cython__(CYTH - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -4661,6 +4805,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_11CyCglTwomir_4__setstate_cython__(CY - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -4719,6 +4866,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_21CyCglResidualCapacity___cinit__(struct __ - int __pyx_r; - __Pyx_RefNannyDeclarations - CglResidualCapacity *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":88 -@@ -4778,6 +4928,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_21CyCglResidualCapacity_2__reduce_cyt - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -4832,6 +4985,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_21CyCglResidualCapacity_4__setstate_c - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -4890,6 +5046,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_15CyCglPreProcess___cinit__(struct __pyx_ob - int __pyx_r; - __Pyx_RefNannyDeclarations - CglPreProcess *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":100 -@@ -4949,6 +5108,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_15CyCglPreProcess_2__reduce_cython__( - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -5003,6 +5165,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_15CyCglPreProcess_4__setstate_cython_ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -5061,6 +5226,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_12CyCglProbing___cinit__(struct __pyx_obj_4 - int __pyx_r; - __Pyx_RefNannyDeclarations - CglProbing *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":104 -@@ -5120,6 +5288,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_12CyCglProbing_2__reduce_cython__(CYT - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -5174,6 +5345,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_12CyCglProbing_4__setstate_cython__(C - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -5232,6 +5406,9 @@ static int __pyx_pf_4cylp_2cy_5CyCgl_19CyCglSimpleRounding___cinit__(struct __py - int __pyx_r; - __Pyx_RefNannyDeclarations - CglSimpleRounding *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCgl.pyx":108 -@@ -5291,6 +5468,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_19CyCglSimpleRounding_2__reduce_cytho - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -5345,6 +5525,9 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_19CyCglSimpleRounding_4__setstate_cyt - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -5375,863 +5558,7 @@ static PyObject *__pyx_pf_4cylp_2cy_5CyCgl_19CyCglSimpleRounding_4__setstate_cyt - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * -- * ndim = PyArray_NDIM(self) -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__35, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__36, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -- * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -- * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -- * -- * cdef int t -- */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -- * -- */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -- * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__37, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -6243,9 +5570,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * - * cdef inline object PyArray_MultiIterNew1(a): - * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -@@ -6253,13 +5583,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - * cdef inline object PyArray_MultiIterNew2(a, b): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -6278,7 +5608,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -6290,9 +5620,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * - * cdef inline object PyArray_MultiIterNew2(a, b): - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -@@ -6300,13 +5633,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -6325,7 +5658,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -6337,9 +5670,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -@@ -6347,13 +5683,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -6372,7 +5708,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -6384,9 +5720,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -@@ -6394,13 +5733,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -6419,7 +5758,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -6431,9 +5770,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -@@ -6441,13 +5783,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - * cdef inline tuple PyDataType_SHAPE(dtype d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -6466,7 +5808,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -6480,7 +5822,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - int __pyx_t_1; - __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -6490,7 +5832,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): - * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -@@ -6502,7 +5844,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -6511,12 +5853,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 - * return <tuple>d.subarray.shape - * else: - * return () # <<<<<<<<<<<<<< - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -+ * - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); -@@ -6525,7 +5867,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - goto __pyx_L0; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -6540,754 +5882,8 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__38, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__37, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__39, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- goto __pyx_L13; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -- */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -- * -- * -- */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -- __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -- * int _import_umath() except -1 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 -+ * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< - * Py_INCREF(base) # important to do this before stealing the reference below! -@@ -7298,7 +5894,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -7307,7 +5903,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -7316,7 +5912,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -7328,7 +5924,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -7343,7 +5939,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -7352,7 +5948,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -7362,7 +5958,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -7373,7 +5969,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -7382,7 +5978,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -7394,7 +5990,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -7409,12 +6005,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -7428,13 +6024,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -7446,20 +6045,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -7469,9 +6068,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -7479,32 +6078,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__40, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__35, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -7515,12 +6114,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -7538,7 +6137,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -7557,9 +6156,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -7575,16 +6177,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -7598,7 +6200,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -7608,28 +6210,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__41, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__36, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -7644,7 +6246,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -7667,7 +6269,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -7686,9 +6288,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -7704,16 +6309,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -7727,35 +6332,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__41, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__36, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -7770,7 +6378,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -7793,6 +6401,180 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - return __pyx_r; - } - -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglCutGenerator(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { - PyObject *o; - if (likely((t->tp_flags & Py_TPFLAGS_IS_ABSTRACT) == 0)) { -@@ -7825,7 +6607,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglCutGenerator = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglCutGenerator), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -7878,6 +6665,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglCutGenerator = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglAllDifferent(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -7902,7 +6695,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglAllDifferent = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglAllDifferent), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -7955,6 +6753,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglAllDifferent = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglClique(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -7979,7 +6783,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglClique = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglClique), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8032,6 +6841,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglClique = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - static struct __pyx_vtabstruct_4cylp_2cy_5CyCgl_CyCglKnapsackCover __pyx_vtable_4cylp_2cy_5CyCgl_CyCglKnapsackCover; - -@@ -8079,7 +6894,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglKnapsackCover = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglKnapsackCover), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8132,6 +6952,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglKnapsackCover = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglOddHole(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -8156,7 +6982,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglOddHole = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglOddHole), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8209,6 +7040,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglOddHole = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglFlowCover(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -8233,7 +7070,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglFlowCover = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglFlowCover), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8286,6 +7128,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglFlowCover = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - static struct __pyx_vtabstruct_4cylp_2cy_5CyCgl_CyCglGomory __pyx_vtable_4cylp_2cy_5CyCgl_CyCglGomory; - -@@ -8333,7 +7181,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglGomory = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglGomory), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8386,6 +7239,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglGomory = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglRedSplit(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -8410,7 +7269,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglRedSplit = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglRedSplit), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8460,8 +7324,14 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglRedSplit = { - #if PY_VERSION_HEX >= 0x030400a1 - 0, /*tp_finalize*/ - #endif -- #if PY_VERSION_HEX >= 0x030800b1 -- 0, /*tp_vectorcall*/ -+ #if PY_VERSION_HEX >= 0x030800b1 -+ 0, /*tp_vectorcall*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ - #endif - }; - -@@ -8487,7 +7357,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglLiftAndProject = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglLiftAndProject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8540,6 +7415,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglLiftAndProject = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglLandP(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -8564,7 +7445,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglLandP = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglLandP), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8617,6 +7503,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglLandP = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglMixedIntegerRounding(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -8641,7 +7533,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglMixedIntegerRounding = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglMixedIntegerRounding), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8694,6 +7591,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglMixedIntegerRounding = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglMixedIntegerRounding2(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -8718,7 +7621,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglMixedIntegerRounding2 = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglMixedIntegerRounding2), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8771,6 +7679,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglMixedIntegerRounding2 = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglTwomir(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -8795,7 +7709,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglTwomir = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglTwomir), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8848,6 +7767,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglTwomir = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglResidualCapacity(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -8872,7 +7797,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglResidualCapacity = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglResidualCapacity), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -8925,6 +7855,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglResidualCapacity = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglPreProcess(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -8949,7 +7885,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglPreProcess = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglPreProcess), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -9002,6 +7943,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglPreProcess = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglProbing(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -9026,7 +7973,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglProbing = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglProbing), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -9079,6 +8031,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglProbing = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_5CyCgl_CyCglSimpleRounding(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -9103,7 +8061,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglSimpleRounding = { - sizeof(struct __pyx_obj_4cylp_2cy_5CyCgl_CyCglSimpleRounding), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_5CyCgl_CyCglCutGenerator, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -9156,6 +8119,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_5CyCgl_CyCglSimpleRounding = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -9221,26 +8190,18 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyCglResidualCapacity, __pyx_k_CyCglResidualCapacity, sizeof(__pyx_k_CyCglResidualCapacity), 0, 0, 1, 1}, - {&__pyx_n_s_CyCglSimpleRounding, __pyx_k_CyCglSimpleRounding, sizeof(__pyx_k_CyCglSimpleRounding), 0, 0, 1, 1}, - {&__pyx_n_s_CyCglTwomir, __pyx_k_CyCglTwomir, sizeof(__pyx_k_CyCglTwomir), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, - {&__pyx_n_s_limit, __pyx_k_limit, sizeof(__pyx_k_limit), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_maxInKnapsack, __pyx_k_maxInKnapsack, sizeof(__pyx_k_maxInKnapsack), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -9248,15 +8209,11 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -9589,82 +8546,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__34); - __Pyx_GIVEREF(__pyx_tuple__34); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__35 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__35)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__35); -- __Pyx_GIVEREF(__pyx_tuple__35); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__36 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__36)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__36); -- __Pyx_GIVEREF(__pyx_tuple__36); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__37 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__37)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__37); -- __Pyx_GIVEREF(__pyx_tuple__37); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__38 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__38)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__38); -- __Pyx_GIVEREF(__pyx_tuple__38); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__39 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__39)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__39); -- __Pyx_GIVEREF(__pyx_tuple__39); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__40 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__40)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__40); -- __Pyx_GIVEREF(__pyx_tuple__40); -+ __pyx_tuple__35 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__35)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__35); -+ __Pyx_GIVEREF(__pyx_tuple__35); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__41 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__41)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__41); -- __Pyx_GIVEREF(__pyx_tuple__41); -+ __pyx_tuple__36 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__36)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__36); -+ __Pyx_GIVEREF(__pyx_tuple__36); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -9714,6 +8616,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - if (PyType_Ready(&__pyx_type_4cylp_2cy_5CyCgl_CyCglCutGenerator) < 0) __PYX_ERR(1, 4, __pyx_L1_error) -@@ -9918,6 +8823,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -9931,18 +8839,38 @@ static int __Pyx_modinit_type_import_code(void) { - __Pyx_ImportType_CheckSize_Warn); - if (!__pyx_ptype_7cpython_4type_type) __PYX_ERR(3, 9, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; -@@ -9969,17 +8897,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -10061,6 +8991,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyCgl(PyObject *__pyx_pyinit_modul - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -10108,11 +9041,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -10149,15 +9080,15 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ -@@ -10175,12 +9106,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -10257,7 +9188,7 @@ static PyObject *__Pyx_GetBuiltinName(PyObject *name) { - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -10558,7 +9489,7 @@ static int __Pyx_ParseOptionalKeywords( - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 -- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { -+ if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { -@@ -10585,7 +9516,7 @@ static int __Pyx_ParseOptionalKeywords( - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -10601,7 +9532,7 @@ static int __Pyx_ParseOptionalKeywords( - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -10652,263 +9583,6 @@ static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr - } - #endif - --/* PyCFunctionFastCall */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { -- PyCFunctionObject *func = (PyCFunctionObject*)func_obj; -- PyCFunction meth = PyCFunction_GET_FUNCTION(func); -- PyObject *self = PyCFunction_GET_SELF(func); -- int flags = PyCFunction_GET_FLAGS(func); -- assert(PyCFunction_Check(func)); -- assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); -- assert(nargs >= 0); -- assert(nargs == 0 || args != NULL); -- /* _PyCFunction_FastCallDict() must not be called with an exception set, -- because it may clear it (directly or indirectly) and so the -- caller loses its exception */ -- assert(!PyErr_Occurred()); -- if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { -- return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); -- } else { -- return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); -- } --} --#endif -- --/* PyFunctionFastCall */ --#if CYTHON_FAST_PYCALL --static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, -- PyObject *globals) { -- PyFrameObject *f; -- PyThreadState *tstate = __Pyx_PyThreadState_Current; -- PyObject **fastlocals; -- Py_ssize_t i; -- PyObject *result; -- assert(globals != NULL); -- /* XXX Perhaps we should create a specialized -- PyFrame_New() that doesn't take locals, but does -- take builtins without sanity checking them. -- */ -- assert(tstate != NULL); -- f = PyFrame_New(tstate, co, globals, NULL); -- if (f == NULL) { -- return NULL; -- } -- fastlocals = __Pyx_PyFrame_GetLocalsplus(f); -- for (i = 0; i < na; i++) { -- Py_INCREF(*args); -- fastlocals[i] = *args++; -- } -- result = PyEval_EvalFrameEx(f,0); -- ++tstate->recursion_depth; -- Py_DECREF(f); -- --tstate->recursion_depth; -- return result; --} --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { -- PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); -- PyObject *globals = PyFunction_GET_GLOBALS(func); -- PyObject *argdefs = PyFunction_GET_DEFAULTS(func); -- PyObject *closure; --#if PY_MAJOR_VERSION >= 3 -- PyObject *kwdefs; --#endif -- PyObject *kwtuple, **k; -- PyObject **d; -- Py_ssize_t nd; -- Py_ssize_t nk; -- PyObject *result; -- assert(kwargs == NULL || PyDict_Check(kwargs)); -- nk = kwargs ? PyDict_Size(kwargs) : 0; -- if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { -- return NULL; -- } -- if ( --#if PY_MAJOR_VERSION >= 3 -- co->co_kwonlyargcount == 0 && --#endif -- likely(kwargs == NULL || nk == 0) && -- co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { -- if (argdefs == NULL && co->co_argcount == nargs) { -- result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); -- goto done; -- } -- else if (nargs == 0 && argdefs != NULL -- && co->co_argcount == Py_SIZE(argdefs)) { -- /* function called with no arguments, but all parameters have -- a default value: use default values as arguments .*/ -- args = &PyTuple_GET_ITEM(argdefs, 0); -- result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); -- goto done; -- } -- } -- if (kwargs != NULL) { -- Py_ssize_t pos, i; -- kwtuple = PyTuple_New(2 * nk); -- if (kwtuple == NULL) { -- result = NULL; -- goto done; -- } -- k = &PyTuple_GET_ITEM(kwtuple, 0); -- pos = i = 0; -- while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { -- Py_INCREF(k[i]); -- Py_INCREF(k[i+1]); -- i += 2; -- } -- nk = i / 2; -- } -- else { -- kwtuple = NULL; -- k = NULL; -- } -- closure = PyFunction_GET_CLOSURE(func); --#if PY_MAJOR_VERSION >= 3 -- kwdefs = PyFunction_GET_KW_DEFAULTS(func); --#endif -- if (argdefs != NULL) { -- d = &PyTuple_GET_ITEM(argdefs, 0); -- nd = Py_SIZE(argdefs); -- } -- else { -- d = NULL; -- nd = 0; -- } --#if PY_MAJOR_VERSION >= 3 -- result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, kwdefs, closure); --#else -- result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, closure); --#endif -- Py_XDECREF(kwtuple); --done: -- Py_LeaveRecursiveCall(); -- return result; --} --#endif --#endif -- --/* PyObjectCallMethO */ --#if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { -- PyObject *self, *result; -- PyCFunction cfunc; -- cfunc = PyCFunction_GET_FUNCTION(func); -- self = PyCFunction_GET_SELF(func); -- if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -- return NULL; -- result = cfunc(self, arg); -- Py_LeaveRecursiveCall(); -- if (unlikely(!result) && unlikely(!PyErr_Occurred())) { -- PyErr_SetString( -- PyExc_SystemError, -- "NULL result without error in PyObject_Call"); -- } -- return result; --} --#endif -- --/* PyObjectCallOneArg */ --#if CYTHON_COMPILING_IN_CPYTHON --static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_New(1); -- if (unlikely(!args)) return NULL; -- Py_INCREF(arg); -- PyTuple_SET_ITEM(args, 0, arg); -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { --#if CYTHON_FAST_PYCALL -- if (PyFunction_Check(func)) { -- return __Pyx_PyFunction_FastCall(func, &arg, 1); -- } --#endif -- if (likely(PyCFunction_Check(func))) { -- if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { -- return __Pyx_PyObject_CallMethO(func, arg); --#if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -- return __Pyx_PyCFunction_FastCall(func, &arg, 1); --#endif -- } -- } -- return __Pyx__PyObject_CallOneArg(func, arg); --} --#else --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_Pack(1, arg); -- if (unlikely(!args)) return NULL; -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --#endif -- --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -11114,6 +9788,28 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - } - #endif - -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -11141,43 +9837,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -11297,7 +10001,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -11327,7 +10031,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -11401,7 +10105,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -11424,30 +10128,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -11466,11 +10171,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -11502,37 +10212,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - Py_XDECREF(py_frame); - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- - /* CIntFromPyVerify */ - #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -@@ -11672,7 +10351,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -11827,7 +10505,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -11866,24 +10543,31 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - #endif - - /* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -+ if (sizeof(int) < sizeof(long)) { - return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -+ } else if (sizeof(int) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif - } - } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -+ if (sizeof(int) <= sizeof(long)) { - return PyInt_FromLong((long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - #endif - } -@@ -11891,14 +10575,21 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES v - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -+ return _PyLong_FromByteArray(bytes, sizeof(int), - little, !is_unsigned); - } - } - - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -12087,7 +10778,14 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - - /* CIntToPy */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { -@@ -12118,7 +10816,14 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { - - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -12669,6 +11374,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyCglCutGeneratorBase.cpp b/cylp/cy/CyCglCutGeneratorBase.cpp -index acf66c0..5195449 100644 ---- a/cylp/cy/CyCglCutGeneratorBase.cpp -+++ b/cylp/cy/CyCglCutGeneratorBase.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -615,7 +698,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "ClpFactorization.hpp" - #include "IClpPrimalColumnPivotBase.h" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ClpDualRowPivot.hpp" - #include "IClpDualRowPivotBase.h" - #include "CoinModel.hpp" -@@ -643,11 +732,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "OsiSolverInterface.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "IClpSimplex.hpp" - #include "IOsiCuts.hpp" -@@ -749,6 +838,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -884,26 +974,26 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyCglCutGeneratorBase.pyx", -+ "cylp/cy/CyCglCutGeneratorBase.pyx", - "__init__.pxd", - "type.pxd", - "bool.pxd", - "complex.pxd", -- "cylp\\cy\\CyCoinIndexedVector.pxd", -- "cylp\\cy\\CyClpPrimalColumnPivotBase.pxd", -- "cylp\\cy\\CyClpDualRowPivotBase.pxd", -- "cylp\\cy\\CyCoinModel.pxd", -- "cylp\\cy\\CyCoinPackedMatrix.pxd", -- "cylp\\cy\\CyCgl.pxd", -- "cylp\\cy\\CyCbcNode.pxd", -- "cylp\\cy\\CyOsiSolverInterface.pxd", -- "cylp\\cy\\CyCbcModel.pxd", -- "cylp\\cy\\CyClpSimplex.pxd", -- "cylp\\cy\\CyOsiCuts.pxd", -- "cylp\\cy\\CyCglTreeInfo.pxd", -+ "cylp/cy/CyCoinIndexedVector.pxd", -+ "cylp/cy/CyClpPrimalColumnPivotBase.pxd", -+ "cylp/cy/CyClpDualRowPivotBase.pxd", -+ "cylp/cy/CyCoinModel.pxd", -+ "cylp/cy/CyCoinPackedMatrix.pxd", -+ "cylp/cy/CyCgl.pxd", -+ "cylp/cy/CyCbcNode.pxd", -+ "cylp/cy/CyOsiSolverInterface.pxd", -+ "cylp/cy/CyCbcModel.pxd", -+ "cylp/cy/CyClpSimplex.pxd", -+ "cylp/cy/CyOsiCuts.pxd", -+ "cylp/cy/CyCglTreeInfo.pxd", - }; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -912,7 +1002,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -921,7 +1011,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -930,7 +1020,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -939,7 +1029,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -948,7 +1038,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -957,7 +1047,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -966,7 +1056,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -975,7 +1065,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -984,7 +1074,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -993,7 +1083,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -1002,7 +1092,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1011,7 +1101,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1020,7 +1110,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1029,7 +1119,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1038,7 +1128,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1047,7 +1137,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1056,7 +1146,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1065,7 +1155,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1074,7 +1164,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1083,7 +1173,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1148,7 +1238,7 @@ struct __pyx_obj_4cylp_2cy_9CyOsiCuts_CyOsiCuts; - struct __pyx_obj_4cylp_2cy_13CyCglTreeInfo_CyCglTreeInfo; - struct __pyx_obj_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1157,7 +1247,7 @@ struct __pyx_obj_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1166,7 +1256,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1175,7 +1265,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1972,67 +2062,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* PyCFunctionFastCall.proto */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); --#else --#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) --#endif -- --/* PyFunctionFastCall.proto */ --#if CYTHON_FAST_PYCALL --#define __Pyx_PyFunction_FastCall(func, args, nargs)\ -- __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); --#else --#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) --#endif --#define __Pyx_BUILD_ASSERT_EXPR(cond)\ -- (sizeof(char [1 - 2*!(cond)]) - 1) --#ifndef Py_MEMBER_SIZE --#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) --#endif -- static size_t __pyx_pyframe_localsplus_offset = 0; -- #include "frameobject.h" -- #define __Pxy_PyFrame_Initialize_Offsets()\ -- ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ -- (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) -- #define __Pyx_PyFrame_GetLocalsplus(frame)\ -- (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) --#endif -- --/* PyObjectCallMethO.proto */ --#if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); --#endif -- --/* PyObjectCallOneArg.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); -- --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -2082,6 +2111,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -2252,14 +2284,10 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #endif - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- --/* CIntFromPy.proto */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -@@ -2267,6 +2295,9 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -+/* CIntFromPy.proto */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+ - /* FastTypeChecks.proto */ - #if CYTHON_COMPILING_IN_CPYTHON - #define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -@@ -2390,8 +2421,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyClpDualRowPivotBase' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase = 0; -@@ -2454,60 +2494,40 @@ int __pyx_module_is_main_cylp__cy__CyCglCutGeneratorBase = 0; - - /* Implementation of 'cylp.cy.CyCglCutGeneratorBase' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_test[] = "__test__"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_import[] = "__import__"; - static const char __pyx_k_reduce[] = "__reduce__"; - static const char __pyx_k_getstate[] = "__getstate__"; - static const char __pyx_k_setstate[] = "__setstate__"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_CyCglCutGeneratorBase[] = "CyCglCutGeneratorBase"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_cylp_cy_CyCglCutGeneratorBase[] = "cylp.cy.CyCglCutGeneratorBase"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; - static const char __pyx_k_CyCglCutGenerator_pyx_generateCu[] = "CyCglCutGenerator.pyx: generateCuts must be implemented."; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_self_CppSelf_cannot_be_converted[] = "self.CppSelf cannot be converted to a Python object for pickling"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyCglCutGeneratorBase; - static PyObject *__pyx_kp_s_CyCglCutGenerator_pyx_generateCu; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_cylp_cy_CyCglCutGeneratorBase; - static PyObject *__pyx_n_s_getstate; - static PyObject *__pyx_n_s_import; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -2515,24 +2535,16 @@ static PyObject *__pyx_kp_s_self_CppSelf_cannot_be_converted; - static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static int __pyx_pf_4cylp_2cy_21CyCglCutGeneratorBase_21CyCglCutGeneratorBase___init__(struct __pyx_obj_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase *__pyx_v_self); /* proto */ - static void __pyx_pf_4cylp_2cy_21CyCglCutGeneratorBase_21CyCglCutGeneratorBase_2__dealloc__(struct __pyx_obj_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_21CyCglCutGeneratorBase_21CyCglCutGeneratorBase_4__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_21CyCglCutGeneratorBase_21CyCglCutGeneratorBase_6__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; - static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; --static PyObject *__pyx_tuple__10; - /* Late includes */ - - /* "cylp/cy/CyCglCutGeneratorBase.pyx":6 -@@ -2546,6 +2558,9 @@ static PyObject *__pyx_tuple__10; - static void __pyx_f_4cylp_2cy_21CyCglCutGeneratorBase_RunGenerateCuts(void *__pyx_v_ptr, OsiSolverInterface *__pyx_v_si, CppOsiCuts *__pyx_v_cs, CglTreeInfo __pyx_v_info) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("RunGenerateCuts", 0); - - /* "cylp/cy/CyCglCutGeneratorBase.pyx":9 -@@ -2739,6 +2754,9 @@ static PyObject *__pyx_f_4cylp_2cy_21CyCglCutGeneratorBase_21CyCglCutGeneratorBa - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("generateCuts", 0); - - /* "cylp/cy/CyCglCutGeneratorBase.pyx":30 -@@ -2843,6 +2861,9 @@ static PyObject *__pyx_pf_4cylp_2cy_21CyCglCutGeneratorBase_21CyCglCutGeneratorB - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -2898,6 +2919,9 @@ static PyObject *__pyx_pf_4cylp_2cy_21CyCglCutGeneratorBase_21CyCglCutGeneratorB - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -2928,1918 +2952,331 @@ static PyObject *__pyx_pf_4cylp_2cy_21CyCglCutGeneratorBase_21CyCglCutGeneratorB - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t -+ * -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * - */ - --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -+ PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): -+ * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< - * -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): - */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t - * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) - */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") - */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. - */ -- goto __pyx_L9; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * - */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< - * -- * cdef int t -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- * info.obj = self # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * if not PyDataType_HASFIELDS(descr): - */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< - * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -+ * cdef inline tuple PyDataType_SHAPE(dtype d): - */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): - */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -- * -- * cdef inline object PyArray_MultiIterNew1(a): -- * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -- * else: -- * return () -- */ -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -- __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -- * return <tuple>d.subarray.shape -- * else: -- * return () # <<<<<<<<<<<<<< -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -- */ -- /*else*/ { -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(__pyx_empty_tuple); -- __pyx_r = __pyx_empty_tuple; -- goto __pyx_L0; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- -- /* function exit code */ -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ int __pyx_t_1; -+ __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ -- goto __pyx_L13; -- } -+ __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -+ if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -+ * else: -+ * return () - */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -+ __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ - } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 -+ * return <tuple>d.subarray.shape -+ * else: -+ * return () # <<<<<<<<<<<<<< - * - * - */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -+ /*else*/ { -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(__pyx_empty_tuple); -+ __pyx_r = __pyx_empty_tuple; -+ goto __pyx_L0; -+ } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ - - /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; - __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -+ __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -4851,7 +3288,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -4860,7 +3297,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -4869,7 +3306,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -4881,7 +3318,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -4896,7 +3333,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -4905,7 +3342,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -4915,7 +3352,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -4926,7 +3363,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -4935,7 +3372,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -4947,7 +3384,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -4962,12 +3399,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -4981,13 +3418,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -4999,20 +3439,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5022,9 +3462,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5032,32 +3472,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5068,12 +3508,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -5091,7 +3531,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5110,9 +3550,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5128,16 +3571,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5151,7 +3594,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -5161,28 +3604,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5197,7 +3640,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5220,7 +3663,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5239,9 +3682,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5257,16 +3703,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5280,69 +3726,246 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< - * _import_umath() - * except Exception: - */ -- __Pyx_XGIVEREF(__pyx_t_1); -- __Pyx_XGIVEREF(__pyx_t_2); -- __Pyx_XGIVEREF(__pyx_t_3); -- __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -- goto __pyx_L1_error; -- __pyx_L8_try_end:; -- } -+ __Pyx_XGIVEREF(__pyx_t_1); -+ __Pyx_XGIVEREF(__pyx_t_2); -+ __Pyx_XGIVEREF(__pyx_t_3); -+ __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -+ goto __pyx_L1_error; -+ __pyx_L8_try_end:; -+ } -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 -+ * raise ImportError("numpy.core.umath failed to import") -+ * -+ * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -+ * try: -+ * _import_umath() -+ */ -+ -+ /* function exit code */ -+ __pyx_r = 0; -+ goto __pyx_L0; -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_5); -+ __Pyx_XDECREF(__pyx_t_6); -+ __Pyx_XDECREF(__pyx_t_7); -+ __Pyx_XDECREF(__pyx_t_8); -+ __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = -1; -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_5); -- __Pyx_XDECREF(__pyx_t_6); -- __Pyx_XDECREF(__pyx_t_7); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; - __pyx_L0:; -- __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - static struct __pyx_vtabstruct_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase __pyx_vtable_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase; -@@ -5373,9 +3996,9 @@ static void __pyx_tp_dealloc_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGenerator - { - PyObject *etype, *eval, *etb; - PyErr_Fetch(&etype, &eval, &etb); -- ++Py_REFCNT(o); -+ __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); - __pyx_pw_4cylp_2cy_21CyCglCutGeneratorBase_21CyCglCutGeneratorBase_3__dealloc__(o); -- --Py_REFCNT(o); -+ __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); - PyErr_Restore(etype, eval, etb); - } - Py_CLEAR(p->cyModel); -@@ -5412,7 +4035,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGenerat - sizeof(struct __pyx_obj_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -5465,6 +4093,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGenerat - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -5515,25 +4149,17 @@ static struct PyModuleDef __pyx_moduledef = { - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyCglCutGeneratorBase, __pyx_k_CyCglCutGeneratorBase, sizeof(__pyx_k_CyCglCutGeneratorBase), 0, 0, 1, 1}, - {&__pyx_kp_s_CyCglCutGenerator_pyx_generateCu, __pyx_k_CyCglCutGenerator_pyx_generateCu, sizeof(__pyx_k_CyCglCutGenerator_pyx_generateCu), 0, 0, 1, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_cylp_cy_CyCglCutGeneratorBase, __pyx_k_cylp_cy_CyCglCutGeneratorBase, sizeof(__pyx_k_cylp_cy_CyCglCutGeneratorBase), 0, 0, 1, 1}, - {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, - {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -5541,15 +4167,11 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -5589,82 +4211,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__3); - __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__10 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__10); -- __Pyx_GIVEREF(__pyx_tuple__10); -+ __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__5); -+ __Pyx_GIVEREF(__pyx_tuple__5); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -5705,6 +4272,9 @@ static int __Pyx_modinit_variable_export_code(void) { - - static int __Pyx_modinit_function_export_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); - /*--- Function export code ---*/ - if (__Pyx_ExportFunction("RunGenerateCuts", (void (*)(void))__pyx_f_4cylp_2cy_21CyCglCutGeneratorBase_RunGenerateCuts, "void (void *, OsiSolverInterface *, CppOsiCuts *, CglTreeInfo)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -5718,6 +4288,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_vtabptr_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase = &__pyx_vtable_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase; -@@ -5744,6 +4317,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -5779,18 +4355,38 @@ static int __Pyx_modinit_type_import_code(void) { - if (!__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase) __PYX_ERR(7, 67, __pyx_L1_error) - __pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase = (struct __pyx_vtabstruct_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase*)__Pyx_GetVtable(__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase->tp_dict); if (unlikely(!__pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase)) __PYX_ERR(7, 67, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(8, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -5911,17 +4507,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6004,6 +4602,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyCglCutGeneratorBase(PyObject *__ - { - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -6051,11 +4652,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -6092,15 +4691,15 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); -- if (unlikely(__Pyx_modinit_function_export_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_function_export_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ -@@ -6135,12 +4734,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -6350,7 +4949,7 @@ static int __Pyx_CheckKeywordStrings( - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -6525,263 +5124,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* PyCFunctionFastCall */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { -- PyCFunctionObject *func = (PyCFunctionObject*)func_obj; -- PyCFunction meth = PyCFunction_GET_FUNCTION(func); -- PyObject *self = PyCFunction_GET_SELF(func); -- int flags = PyCFunction_GET_FLAGS(func); -- assert(PyCFunction_Check(func)); -- assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); -- assert(nargs >= 0); -- assert(nargs == 0 || args != NULL); -- /* _PyCFunction_FastCallDict() must not be called with an exception set, -- because it may clear it (directly or indirectly) and so the -- caller loses its exception */ -- assert(!PyErr_Occurred()); -- if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { -- return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); -- } else { -- return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); -- } --} --#endif -- --/* PyFunctionFastCall */ --#if CYTHON_FAST_PYCALL --static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, -- PyObject *globals) { -- PyFrameObject *f; -- PyThreadState *tstate = __Pyx_PyThreadState_Current; -- PyObject **fastlocals; -- Py_ssize_t i; -- PyObject *result; -- assert(globals != NULL); -- /* XXX Perhaps we should create a specialized -- PyFrame_New() that doesn't take locals, but does -- take builtins without sanity checking them. -- */ -- assert(tstate != NULL); -- f = PyFrame_New(tstate, co, globals, NULL); -- if (f == NULL) { -- return NULL; -- } -- fastlocals = __Pyx_PyFrame_GetLocalsplus(f); -- for (i = 0; i < na; i++) { -- Py_INCREF(*args); -- fastlocals[i] = *args++; -- } -- result = PyEval_EvalFrameEx(f,0); -- ++tstate->recursion_depth; -- Py_DECREF(f); -- --tstate->recursion_depth; -- return result; --} --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { -- PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); -- PyObject *globals = PyFunction_GET_GLOBALS(func); -- PyObject *argdefs = PyFunction_GET_DEFAULTS(func); -- PyObject *closure; --#if PY_MAJOR_VERSION >= 3 -- PyObject *kwdefs; --#endif -- PyObject *kwtuple, **k; -- PyObject **d; -- Py_ssize_t nd; -- Py_ssize_t nk; -- PyObject *result; -- assert(kwargs == NULL || PyDict_Check(kwargs)); -- nk = kwargs ? PyDict_Size(kwargs) : 0; -- if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { -- return NULL; -- } -- if ( --#if PY_MAJOR_VERSION >= 3 -- co->co_kwonlyargcount == 0 && --#endif -- likely(kwargs == NULL || nk == 0) && -- co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { -- if (argdefs == NULL && co->co_argcount == nargs) { -- result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); -- goto done; -- } -- else if (nargs == 0 && argdefs != NULL -- && co->co_argcount == Py_SIZE(argdefs)) { -- /* function called with no arguments, but all parameters have -- a default value: use default values as arguments .*/ -- args = &PyTuple_GET_ITEM(argdefs, 0); -- result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); -- goto done; -- } -- } -- if (kwargs != NULL) { -- Py_ssize_t pos, i; -- kwtuple = PyTuple_New(2 * nk); -- if (kwtuple == NULL) { -- result = NULL; -- goto done; -- } -- k = &PyTuple_GET_ITEM(kwtuple, 0); -- pos = i = 0; -- while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { -- Py_INCREF(k[i]); -- Py_INCREF(k[i+1]); -- i += 2; -- } -- nk = i / 2; -- } -- else { -- kwtuple = NULL; -- k = NULL; -- } -- closure = PyFunction_GET_CLOSURE(func); --#if PY_MAJOR_VERSION >= 3 -- kwdefs = PyFunction_GET_KW_DEFAULTS(func); --#endif -- if (argdefs != NULL) { -- d = &PyTuple_GET_ITEM(argdefs, 0); -- nd = Py_SIZE(argdefs); -- } -- else { -- d = NULL; -- nd = 0; -- } --#if PY_MAJOR_VERSION >= 3 -- result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, kwdefs, closure); --#else -- result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, closure); --#endif -- Py_XDECREF(kwtuple); --done: -- Py_LeaveRecursiveCall(); -- return result; --} --#endif --#endif -- --/* PyObjectCallMethO */ --#if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { -- PyObject *self, *result; -- PyCFunction cfunc; -- cfunc = PyCFunction_GET_FUNCTION(func); -- self = PyCFunction_GET_SELF(func); -- if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -- return NULL; -- result = cfunc(self, arg); -- Py_LeaveRecursiveCall(); -- if (unlikely(!result) && unlikely(!PyErr_Occurred())) { -- PyErr_SetString( -- PyExc_SystemError, -- "NULL result without error in PyObject_Call"); -- } -- return result; --} --#endif -- --/* PyObjectCallOneArg */ --#if CYTHON_COMPILING_IN_CPYTHON --static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_New(1); -- if (unlikely(!args)) return NULL; -- Py_INCREF(arg); -- PyTuple_SET_ITEM(args, 0, arg); -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { --#if CYTHON_FAST_PYCALL -- if (PyFunction_Check(func)) { -- return __Pyx_PyFunction_FastCall(func, &arg, 1); -- } --#endif -- if (likely(PyCFunction_Check(func))) { -- if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { -- return __Pyx_PyObject_CallMethO(func, arg); --#if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -- return __Pyx_PyCFunction_FastCall(func, &arg, 1); --#endif -- } -- } -- return __Pyx__PyObject_CallOneArg(func, arg); --} --#else --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_Pack(1, arg); -- if (unlikely(!args)) return NULL; -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --#endif -- --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -7005,6 +5347,28 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable) { - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -7032,43 +5396,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -7192,7 +5564,7 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { - { - #if PY_MAJOR_VERSION >= 3 - if (level == -1) { -- if (strchr(__Pyx_MODULE_NAME, '.')) { -+ if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) { - module = PyImport_ImportModuleLevelObject( - name, global_dict, empty_dict, list, 1); - if (!module) { -@@ -7255,7 +5627,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -7285,7 +5657,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -7359,7 +5731,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -7382,30 +5754,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -7424,11 +5797,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -7577,7 +5955,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -7732,7 +6109,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -7771,24 +6147,31 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #endif - - /* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -+ if (sizeof(long) < sizeof(long)) { - return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -+ } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif - } - } else { -- if (sizeof(int) <= sizeof(long)) { -+ if (sizeof(long) <= sizeof(long)) { - return PyInt_FromLong((long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - #endif - } -@@ -7796,7 +6179,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -+ return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); - } - } -@@ -7823,51 +6206,27 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - return (target_type) value;\ - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+/* CIntFromPy */ -+static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(int) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) -+ if (sizeof(long) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (int) val; -+ return (long) val; - } - } else - #endif -@@ -7876,32 +6235,32 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) -+ case 0: return (long) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -- return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -+ return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -- return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -+ return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -- return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -+ return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; -@@ -7915,86 +6274,86 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (int) -1; -+ return (long) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(int) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(long) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) -+ case 0: return (long) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) - case -2: -- if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(int) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -+ if (sizeof(long) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -8003,7 +6362,7 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- int val; -+ long val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -8023,71 +6382,47 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - return val; - } - #endif -- return (int) -1; -+ return (long) -1; - } - } else { -- int val; -+ long val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (int) -1; -- val = __Pyx_PyInt_As_int(tmp); -+ if (!tmp) return (long) -1; -+ val = __Pyx_PyInt_As_long(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to int"); -- return (int) -1; -+ "value too large to convert to long"); -+ return (long) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to int"); -- return (int) -1; -+ "can't convert negative value to long"); -+ return (long) -1; - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(long) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(long) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+/* CIntFromPy */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(long) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(long), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ --static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(long) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) -+ if (sizeof(int) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (long) val; -+ return (int) val; - } - } else - #endif -@@ -8096,32 +6431,32 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) -+ case 0: return (int) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -- return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -+ return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -- return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -+ return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -- return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -+ return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; -@@ -8135,86 +6470,86 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (long) -1; -+ return (int) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(long) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(int) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) -+ case 0: return (int) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) - case -2: -- if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(long) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) -+ if (sizeof(int) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -8223,7 +6558,7 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- long val; -+ int val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -8243,24 +6578,24 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - return val; - } - #endif -- return (long) -1; -+ return (int) -1; - } - } else { -- long val; -+ int val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (long) -1; -- val = __Pyx_PyInt_As_long(tmp); -+ if (!tmp) return (int) -1; -+ val = __Pyx_PyInt_As_int(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to long"); -- return (long) -1; -+ "value too large to convert to int"); -+ return (int) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to long"); -- return (long) -1; -+ "can't convert negative value to int"); -+ return (int) -1; - } - - /* FastTypeChecks */ -@@ -8664,6 +6999,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyCglTreeInfo.cpp b/cylp/cy/CyCglTreeInfo.cpp -index af46065..de3fa97 100644 ---- a/cylp/cy/CyCglTreeInfo.cpp -+++ b/cylp/cy/CyCglTreeInfo.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -704,6 +787,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -817,7 +901,7 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyCglTreeInfo.pyx", -+ "cylp/cy/CyCglTreeInfo.pyx", - }; - - /*--- Type declarations ---*/ -@@ -995,6 +1079,17 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyErrExceptionMatches.proto */ -+#if CYTHON_FAST_THREAD_STATE -+#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) -+static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); -+#else -+#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) -+#endif -+ -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -1092,6 +1187,11 @@ static void __Pyx_CppExn2PyErr() { - } - #endif - -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif -+ - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - -@@ -1194,6 +1294,9 @@ static int __pyx_pf_4cylp_2cy_13CyCglTreeInfo_13CyCglTreeInfo___cinit__(struct _ - int __pyx_r; - __Pyx_RefNannyDeclarations - CglTreeInfo *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCglTreeInfo.pyx":7 -@@ -1298,6 +1401,9 @@ static PyObject *__pyx_pf_4cylp_2cy_13CyCglTreeInfo_13CyCglTreeInfo_2__reduce_cy - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -1352,6 +1458,9 @@ static PyObject *__pyx_pf_4cylp_2cy_13CyCglTreeInfo_13CyCglTreeInfo_4__setstate_ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -1422,7 +1531,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_13CyCglTreeInfo_CyCglTreeInfo = { - sizeof(struct __pyx_obj_4cylp_2cy_13CyCglTreeInfo_CyCglTreeInfo), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_13CyCglTreeInfo_CyCglTreeInfo, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -1475,6 +1589,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_13CyCglTreeInfo_CyCglTreeInfo = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -1616,6 +1736,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_vtabptr_4cylp_2cy_13CyCglTreeInfo_CyCglTreeInfo = &__pyx_vtable_4cylp_2cy_13CyCglTreeInfo_CyCglTreeInfo; -@@ -1663,17 +1786,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -1755,6 +1880,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyCglTreeInfo(PyObject *__pyx_pyin - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -1802,11 +1930,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -1843,14 +1969,14 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 2, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 2, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 2, __pyx_L1_error) - (void)__Pyx_modinit_type_import_code(); - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); -@@ -2010,7 +2136,7 @@ static int __Pyx_CheckKeywordStrings( - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -2277,6 +2403,53 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable) { - return -1; - } - -+/* PyErrExceptionMatches */ -+#if CYTHON_FAST_THREAD_STATE -+static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { -+ Py_ssize_t i, n; -+ n = PyTuple_GET_SIZE(tuple); -+#if PY_MAJOR_VERSION >= 3 -+ for (i=0; i<n; i++) { -+ if (exc_type == PyTuple_GET_ITEM(tuple, i)) return 1; -+ } -+#endif -+ for (i=0; i<n; i++) { -+ if (__Pyx_PyErr_GivenExceptionMatches(exc_type, PyTuple_GET_ITEM(tuple, i))) return 1; -+ } -+ return 0; -+} -+static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err) { -+ PyObject *exc_type = tstate->curexc_type; -+ if (exc_type == err) return 1; -+ if (unlikely(!exc_type)) return 0; -+ if (unlikely(PyTuple_Check(err))) -+ return __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); -+ return __Pyx_PyErr_GivenExceptionMatches(exc_type, err); -+} -+#endif -+ -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -2304,43 +2477,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -2381,7 +2562,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -2411,7 +2592,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -2485,7 +2666,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -2508,30 +2689,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -2550,11 +2732,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -2588,7 +2775,14 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - - /* CIntToPy */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { -@@ -2641,7 +2835,14 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { - - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -2830,7 +3031,14 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -3381,6 +3589,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyClpDualRowPivotBase.cpp b/cylp/cy/CyClpDualRowPivotBase.cpp -index 21f3977..93a41a8 100644 ---- a/cylp/cy/CyClpDualRowPivotBase.cpp -+++ b/cylp/cy/CyClpDualRowPivotBase.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -615,7 +698,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "ClpFactorization.hpp" - #include "IClpPrimalColumnPivotBase.h" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "CoinModel.hpp" - #include "ICoinPackedMatrix.hpp" - #include "CglAllDifferent.hpp" -@@ -641,11 +730,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "OsiSolverInterface.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "ClpDualRowPivot.hpp" - #include "IClpSimplex.hpp" -@@ -746,6 +835,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -881,20 +971,20 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyClpDualRowPivotBase.pyx", -+ "cylp/cy/CyClpDualRowPivotBase.pyx", - "__init__.pxd", - "type.pxd", - "bool.pxd", - "complex.pxd", -- "cylp\\cy\\CyCoinIndexedVector.pxd", -- "cylp\\cy\\CyClpPrimalColumnPivotBase.pxd", -- "cylp\\cy\\CyCoinModel.pxd", -- "cylp\\cy\\CyCoinPackedMatrix.pxd", -- "cylp\\cy\\CyCgl.pxd", -- "cylp\\cy\\CyCbcNode.pxd", -- "cylp\\cy\\CyOsiSolverInterface.pxd", -- "cylp\\cy\\CyCbcModel.pxd", -- "cylp\\cy\\CyClpSimplex.pxd", -+ "cylp/cy/CyCoinIndexedVector.pxd", -+ "cylp/cy/CyClpPrimalColumnPivotBase.pxd", -+ "cylp/cy/CyCoinModel.pxd", -+ "cylp/cy/CyCoinPackedMatrix.pxd", -+ "cylp/cy/CyCgl.pxd", -+ "cylp/cy/CyCbcNode.pxd", -+ "cylp/cy/CyOsiSolverInterface.pxd", -+ "cylp/cy/CyCbcModel.pxd", -+ "cylp/cy/CyClpSimplex.pxd", - }; - /* BufferFormatStructs.proto */ - #define IS_UNSIGNED(type) (((type) -1) > 0) -@@ -933,7 +1023,7 @@ typedef struct { - } __Pyx_BufFmt_Context; - - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -942,7 +1032,7 @@ typedef struct { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -951,7 +1041,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -960,7 +1050,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -969,7 +1059,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -978,7 +1068,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -987,7 +1077,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -996,7 +1086,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -1005,7 +1095,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -1014,7 +1104,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -1023,7 +1113,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -1032,7 +1122,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1041,7 +1131,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1050,7 +1140,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1059,7 +1149,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1068,7 +1158,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1077,7 +1167,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1086,7 +1176,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1095,7 +1185,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1104,7 +1194,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1113,7 +1203,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1175,7 +1265,7 @@ struct __pyx_obj_4cylp_2cy_12CyClpSimplex_CyClpSimplex; - struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus; - struct __pyx_obj_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1184,7 +1274,7 @@ struct __pyx_obj_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1193,7 +1283,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1202,7 +1292,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1927,11 +2017,45 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define CYTHON_FRAME_DEL(frame) Py_CLEAR(frame) - #endif - #define __Pyx_TraceDeclarations\ -- static PyCodeObject *__pyx_frame_code = NULL;\ -- CYTHON_FRAME_MODIFIER PyFrameObject *__pyx_frame = NULL;\ -- int __Pyx_use_tracing = 0; -+ static PyCodeObject *__pyx_frame_code = NULL;\ -+ CYTHON_FRAME_MODIFIER PyFrameObject *__pyx_frame = NULL;\ -+ int __Pyx_use_tracing = 0; - #define __Pyx_TraceFrameInit(codeobj)\ -- if (codeobj) __pyx_frame_code = (PyCodeObject*) codeobj; -+ if (codeobj) __pyx_frame_code = (PyCodeObject*) codeobj; -+#if PY_VERSION_HEX >= 0x030b00a2 -+ #define __Pyx_IsTracing(tstate, check_tracing, check_funcs)\ -+ (unlikely((tstate)->cframe->use_tracing) &&\ -+ (!(check_tracing) || !(tstate)->tracing) &&\ -+ (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc))) -+ #define __Pyx_EnterTracing(tstate) PyThreadState_EnterTracing(tstate) -+ #define __Pyx_LeaveTracing(tstate) PyThreadState_LeaveTracing(tstate) -+#elif PY_VERSION_HEX >= 0x030a00b1 -+ #define __Pyx_IsTracing(tstate, check_tracing, check_funcs)\ -+ (unlikely((tstate)->cframe->use_tracing) &&\ -+ (!(check_tracing) || !(tstate)->tracing) &&\ -+ (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc))) -+ #define __Pyx_EnterTracing(tstate)\ -+ do { tstate->tracing++; tstate->cframe->use_tracing = 0; } while (0) -+ #define __Pyx_LeaveTracing(tstate)\ -+ do {\ -+ tstate->tracing--;\ -+ tstate->cframe->use_tracing = ((CYTHON_TRACE && tstate->c_tracefunc != NULL)\ -+ || tstate->c_profilefunc != NULL);\ -+ } while (0) -+#else -+ #define __Pyx_IsTracing(tstate, check_tracing, check_funcs)\ -+ (unlikely((tstate)->use_tracing) &&\ -+ (!(check_tracing) || !(tstate)->tracing) &&\ -+ (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc))) -+ #define __Pyx_EnterTracing(tstate)\ -+ do { tstate->tracing++; tstate->use_tracing = 0; } while (0) -+ #define __Pyx_LeaveTracing(tstate)\ -+ do {\ -+ tstate->tracing--;\ -+ tstate->use_tracing = ((CYTHON_TRACE && tstate->c_tracefunc != NULL)\ -+ || tstate->c_profilefunc != NULL);\ -+ } while (0) -+#endif - #ifdef WITH_THREAD - #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error)\ - if (nogil) {\ -@@ -1939,8 +2063,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyThreadState *tstate;\ - PyGILState_STATE state = PyGILState_Ensure();\ - tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing) && !tstate->tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -+ if (__Pyx_IsTracing(tstate, 1, 1)) {\ - __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&__pyx_frame_code, &__pyx_frame, tstate, funcname, srcfile, firstlineno);\ - }\ - PyGILState_Release(state);\ -@@ -1948,8 +2071,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - }\ - } else {\ - PyThreadState* tstate = PyThreadState_GET();\ -- if (unlikely(tstate->use_tracing) && !tstate->tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -+ if (__Pyx_IsTracing(tstate, 1, 1)) {\ - __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&__pyx_frame_code, &__pyx_frame, tstate, funcname, srcfile, firstlineno);\ - if (unlikely(__Pyx_use_tracing < 0)) goto_error;\ - }\ -@@ -1957,8 +2079,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #else - #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error)\ - { PyThreadState* tstate = PyThreadState_GET();\ -- if (unlikely(tstate->use_tracing) && !tstate->tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -+ if (__Pyx_IsTracing(tstate, 1, 1)) {\ - __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&__pyx_frame_code, &__pyx_frame, tstate, funcname, srcfile, firstlineno);\ - if (unlikely(__Pyx_use_tracing < 0)) goto_error;\ - }\ -@@ -1967,10 +2088,8 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define __Pyx_TraceException()\ - if (likely(!__Pyx_use_tracing)); else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -- tstate->tracing++;\ -- tstate->use_tracing = 0;\ -+ if (__Pyx_IsTracing(tstate, 0, 1)) {\ -+ __Pyx_EnterTracing(tstate);\ - PyObject *exc_info = __Pyx_GetExceptionTuple(tstate);\ - if (exc_info) {\ - if (CYTHON_TRACE && tstate->c_tracefunc)\ -@@ -1980,22 +2099,19 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - tstate->c_profileobj, __pyx_frame, PyTrace_EXCEPTION, exc_info);\ - Py_DECREF(exc_info);\ - }\ -- tstate->use_tracing = 1;\ -- tstate->tracing--;\ -+ __Pyx_LeaveTracing(tstate);\ - }\ - } - static void __Pyx_call_return_trace_func(PyThreadState *tstate, PyFrameObject *frame, PyObject *result) { - PyObject *type, *value, *traceback; - __Pyx_ErrFetchInState(tstate, &type, &value, &traceback); -- tstate->tracing++; -- tstate->use_tracing = 0; -+ __Pyx_EnterTracing(tstate); - if (CYTHON_TRACE && tstate->c_tracefunc) - tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_RETURN, result); - if (tstate->c_profilefunc) - tstate->c_profilefunc(tstate->c_profileobj, frame, PyTrace_RETURN, result); - CYTHON_FRAME_DEL(frame); -- tstate->use_tracing = 1; -- tstate->tracing--; -+ __Pyx_LeaveTracing(tstate); - __Pyx_ErrRestoreInState(tstate, type, value, traceback); - } - #ifdef WITH_THREAD -@@ -2006,14 +2122,14 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyThreadState *tstate;\ - PyGILState_STATE state = PyGILState_Ensure();\ - tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0)) {\ - __Pyx_call_return_trace_func(tstate, __pyx_frame, (PyObject*)result);\ - }\ - PyGILState_Release(state);\ - }\ - } else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0)) {\ - __Pyx_call_return_trace_func(tstate, __pyx_frame, (PyObject*)result);\ - }\ - }\ -@@ -2022,7 +2138,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define __Pyx_TraceReturn(result, nogil)\ - if (likely(!__Pyx_use_tracing)); else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0)) {\ - __Pyx_call_return_trace_func(tstate, __pyx_frame, (PyObject*)result);\ - }\ - } -@@ -2042,11 +2158,9 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyObject *type, *value, *traceback; - __Pyx_ErrFetchInState(tstate, &type, &value, &traceback); - __Pyx_PyFrame_SetLineNumber(frame, lineno); -- tstate->tracing++; -- tstate->use_tracing = 0; -+ __Pyx_EnterTracing(tstate); - ret = tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_LINE, NULL); -- tstate->use_tracing = 1; -- tstate->tracing--; -+ __Pyx_LeaveTracing(tstate); - if (likely(!ret)) { - __Pyx_ErrRestoreInState(tstate, type, value, traceback); - } else { -@@ -2065,7 +2179,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyThreadState *tstate;\ - PyGILState_STATE state = PyGILState_Ensure();\ - tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing && tstate->c_tracefunc && __pyx_frame->f_trace)) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && __pyx_frame->f_trace) {\ - ret = __Pyx_call_line_trace_func(tstate, __pyx_frame, lineno);\ - }\ - PyGILState_Release(state);\ -@@ -2073,7 +2187,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - }\ - } else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing && tstate->c_tracefunc && __pyx_frame->f_trace)) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && __pyx_frame->f_trace) {\ - int ret = __Pyx_call_line_trace_func(tstate, __pyx_frame, lineno);\ - if (unlikely(ret)) goto_error;\ - }\ -@@ -2083,7 +2197,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define __Pyx_TraceLine(lineno, nogil, goto_error)\ - if (likely(!__Pyx_use_tracing)); else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing && tstate->c_tracefunc && __pyx_frame->f_trace)) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && __pyx_frame->f_trace) {\ - int ret = __Pyx_call_line_trace_func(tstate, __pyx_frame, lineno);\ - if (unlikely(ret)) goto_error;\ - }\ -@@ -2139,64 +2253,6 @@ static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info); - static Py_ssize_t __Pyx_minusones[] = { -1, -1, -1, -1, -1, -1, -1, -1 }; - static Py_ssize_t __Pyx_zeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - --/* PyCFunctionFastCall.proto */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); --#else --#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) --#endif -- --/* PyFunctionFastCall.proto */ --#if CYTHON_FAST_PYCALL --#define __Pyx_PyFunction_FastCall(func, args, nargs)\ -- __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); --#else --#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) --#endif --#define __Pyx_BUILD_ASSERT_EXPR(cond)\ -- (sizeof(char [1 - 2*!(cond)]) - 1) --#ifndef Py_MEMBER_SIZE --#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) --#endif -- static size_t __pyx_pyframe_localsplus_offset = 0; -- #include "frameobject.h" -- #define __Pxy_PyFrame_Initialize_Offsets()\ -- ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ -- (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) -- #define __Pyx_PyFrame_GetLocalsplus(frame)\ -- (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) --#endif -- --/* PyObjectCallMethO.proto */ --#if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); --#endif -- --/* PyObjectCallOneArg.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); -- --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -2246,6 +2302,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -2338,8 +2397,10 @@ typedef struct { - #endif - - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -2439,12 +2500,12 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - #endif - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); - -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+ - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - -@@ -2577,8 +2638,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void); /*proto*/ - - /* Module declarations from 'cylp.cy.CyCoinModel' */ -@@ -2640,60 +2710,40 @@ int __pyx_module_is_main_cylp__cy__CyClpDualRowPivotBase = 0; - - /* Implementation of 'cylp.cy.CyClpDualRowPivotBase' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_test[] = "__test__"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_reduce[] = "__reduce__"; - static const char __pyx_k_getstate[] = "__getstate__"; - static const char __pyx_k_setstate[] = "__setstate__"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_CyClpDualRowPivotBase[] = "CyClpDualRowPivotBase"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; - static const char __pyx_k_CyClpDualRowPivotBase_pyx_pivotR[] = "CyClpDualRowPivotBase.pyx: pivotRow() should be implemented."; - static const char __pyx_k_CyClpDualRowPivotBase_pyx_update[] = "CyClpDualRowPivotBase.pyx: updateWeights should be implemented."; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_self_CppSelf_cannot_be_converted[] = "self.CppSelf cannot be converted to a Python object for pickling"; - static const char __pyx_k_CyClpDualRowPivotBase_pyx_update_2[] = "CyClpDualRowPivotBase.pyx: updatePrimalSolution should be implemented."; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyClpDualRowPivotBase; - static PyObject *__pyx_kp_s_CyClpDualRowPivotBase_pyx_pivotR; - static PyObject *__pyx_kp_s_CyClpDualRowPivotBase_pyx_update; - static PyObject *__pyx_kp_s_CyClpDualRowPivotBase_pyx_update_2; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_getstate; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -2701,14 +2751,11 @@ static PyObject *__pyx_kp_s_self_CppSelf_cannot_be_converted; - static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static int __pyx_pf_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotBase___init__(struct __pyx_obj_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotBase_5nRows___get__(struct __pyx_obj_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotBase_5nCols___get__(struct __pyx_obj_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotBase_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotBase_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; -@@ -2717,11 +2764,6 @@ static PyObject *__pyx_tuple__4; - static PyObject *__pyx_tuple__5; - static PyObject *__pyx_tuple__6; - static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; --static PyObject *__pyx_tuple__10; --static PyObject *__pyx_tuple__11; --static PyObject *__pyx_tuple__12; - /* Late includes */ - - /* "cylp/cy/CyClpDualRowPivotBase.pyx":9 -@@ -2738,6 +2780,9 @@ static int __pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_RunPivotRow(void *__pyx_v_p - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_t_2; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("RunPivotRow", 0); - __Pyx_TraceCall("RunPivotRow", __pyx_f[1], 9, 0, __PYX_ERR(1, 9, __pyx_L1_error)); - -@@ -2786,6 +2831,9 @@ static ClpDualRowPivot *__pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_RunDualPivotCl - ClpDualRowPivot *__pyx_r; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("RunDualPivotClone", 0); - __Pyx_TraceCall("RunDualPivotClone", __pyx_f[1], 12, 0, __PYX_ERR(1, 12, __pyx_L1_error)); - -@@ -2829,6 +2877,9 @@ static double __pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_RunUpdateWeights(void *_ - double __pyx_r; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("RunUpdateWeights", 0); - __Pyx_TraceCall("RunUpdateWeights", __pyx_f[1], 15, 0, __PYX_ERR(1, 15, __pyx_L1_error)); - -@@ -2874,6 +2925,9 @@ static void __pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_RunUpdatePrimalSolution(vo - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("RunUpdatePrimalSolution", 0); - __Pyx_TraceCall("RunUpdatePrimalSolution", __pyx_f[1], 21, 0, __PYX_ERR(1, 21, __pyx_L1_error)); - -@@ -2955,6 +3009,9 @@ static int __pyx_pf_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotBase___ - int __pyx_r; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__init__", 0); - __Pyx_TraceCall("__init__", __pyx_f[1], 30, 0, __PYX_ERR(1, 30, __pyx_L1_error)); - -@@ -3000,6 +3057,9 @@ static PyObject *__pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotBa - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("pivotRow", 0); - __Pyx_TraceCall("pivotRow", __pyx_f[1], 38, 0, __PYX_ERR(1, 38, __pyx_L1_error)); - -@@ -3048,6 +3108,9 @@ static ClpDualRowPivot *__pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRow - ClpDualRowPivot *__pyx_r; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("clone", 0); - __Pyx_TraceCall("clone", __pyx_f[1], 42, 0, __PYX_ERR(1, 42, __pyx_L1_error)); - -@@ -3101,6 +3164,9 @@ static double __pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotBase_ - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("updateWeights", 0); - __Pyx_TraceCall("updateWeights", __pyx_f[1], 52, 0, __PYX_ERR(1, 52, __pyx_L1_error)); - -@@ -3149,6 +3215,9 @@ static void __pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotBase_up - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("updatePrimalSolution", 0); - __Pyx_TraceCall("updatePrimalSolution", __pyx_f[1], 59, 0, __PYX_ERR(1, 59, __pyx_L1_error)); - __pyx_pybuffer_changeInObjective.pybuffer.buf = NULL; -@@ -3202,6 +3271,9 @@ static IClpSimplex *__pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivo - IClpSimplex *__pyx_r; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("model", 0); - __Pyx_TraceCall("model", __pyx_f[1], 66, 0, __PYX_ERR(1, 66, __pyx_L1_error)); - -@@ -3244,6 +3316,9 @@ static IClpSimplex *__pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivo - static void __pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotBase_setModel(struct __pyx_obj_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase *__pyx_v_self, IClpSimplex *__pyx_v_m) { - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("setModel", 0); - __Pyx_TraceCall("setModel", __pyx_f[1], 69, 0, __PYX_ERR(1, 69, __pyx_L1_error)); - -@@ -3285,6 +3360,9 @@ static double *__pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotBase - double *__pyx_r; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("getReducedCosts", 0); - __Pyx_TraceCall("getReducedCosts", __pyx_f[1], 72, 0, __PYX_ERR(1, 72, __pyx_L1_error)); - -@@ -3342,6 +3420,9 @@ static PyObject *__pyx_pf_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotB - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - __Pyx_TraceCall("__get__", __pyx_f[1], 76, 0, __PYX_ERR(1, 76, __pyx_L1_error)); - -@@ -3404,6 +3485,9 @@ static PyObject *__pyx_pf_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotB - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - __Pyx_TraceCall("__get__", __pyx_f[1], 80, 0, __PYX_ERR(1, 80, __pyx_L1_error)); - -@@ -3463,6 +3547,9 @@ static PyObject *__pyx_pf_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotB - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - __Pyx_TraceCall("__reduce_cython__", __pyx_f[0], 1, 0, __PYX_ERR(0, 1, __pyx_L1_error)); - -@@ -3521,6 +3608,9 @@ static PyObject *__pyx_pf_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotB - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - __Pyx_TraceCall("__setstate_cython__", __pyx_f[0], 3, 0, __PYX_ERR(0, 3, __pyx_L1_error)); - -@@ -3553,1952 +3643,355 @@ static PyObject *__pyx_pf_4cylp_2cy_21CyClpDualRowPivotBase_21CyClpDualRowPivotB - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t -+ * -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * - */ - --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -+ PyObject *__pyx_r = NULL; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- __Pyx_TraceCall("__getbuffer__", __pyx_f[2], 258, 0, __PYX_ERR(2, 258, __pyx_L1_error)); -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -+ __Pyx_TraceCall("PyArray_MultiIterNew1", __pyx_f[2], 735, 0, __PYX_ERR(2, 735, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ * cdef inline object PyArray_MultiIterNew1(a): -+ * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< - * -+ * cdef inline object PyArray_MultiIterNew2(a, b): - */ -- __pyx_v_endian_detector = 1; -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t -+ * -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * ndim = PyArray_NDIM(self) - */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) - */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -+ __Pyx_TraceCall("PyArray_MultiIterNew2", __pyx_f[2], 738, 0, __PYX_ERR(2, 738, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew2(a, b): -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< - * -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) - */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -+ * -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") - */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -+ __Pyx_TraceCall("PyArray_MultiIterNew3", __pyx_f[2], 741, 0, __PYX_ERR(2, 741, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< - * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * info.buf = PyArray_DATA(self) - */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. - */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); -+ __Pyx_TraceCall("PyArray_MultiIterNew4", __pyx_f[2], 744, 0, __PYX_ERR(2, 744, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * - */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef int t - */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -+ __Pyx_TraceCall("PyArray_MultiIterNew5", __pyx_f[2], 747, 0, __PYX_ERR(2, 747, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< - * -+ * cdef inline tuple PyDataType_SHAPE(dtype d): - */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- * info.obj = self # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * if not PyDataType_HASFIELDS(descr): - */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_TraceReturn(Py_None, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- __Pyx_TraceCall("__releasebuffer__", __pyx_f[2], 337, 0, __PYX_ERR(2, 337, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_WriteUnraisable("numpy.ndarray.__releasebuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0); -- __pyx_L0:; -- __Pyx_TraceReturn(Py_None, 0); -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew1", __pyx_f[2], 821, 0, __PYX_ERR(2, 821, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -- * -- * cdef inline object PyArray_MultiIterNew1(a): -- * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew2", __pyx_f[2], 824, 0, __PYX_ERR(2, 824, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew3", __pyx_f[2], 827, 0, __PYX_ERR(2, 827, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew4", __pyx_f[2], 830, 0, __PYX_ERR(2, 830, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew5", __pyx_f[2], 833, 0, __PYX_ERR(2, 833, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); -- __Pyx_TraceCall("PyDataType_SHAPE", __pyx_f[2], 836, 0, __PYX_ERR(2, 836, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -- * else: -- * return () -- */ -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -- __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -- * return <tuple>d.subarray.shape -- * else: -- * return () # <<<<<<<<<<<<<< -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -- */ -- /*else*/ { -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(__pyx_empty_tuple); -- __pyx_r = __pyx_empty_tuple; -- goto __pyx_L0; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_AddTraceback("numpy.PyDataType_SHAPE", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- __Pyx_TraceCall("_util_dtypestring", __pyx_f[2], 842, 0, __PYX_ERR(2, 842, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ int __pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); -+ __Pyx_TraceCall("PyDataType_SHAPE", __pyx_f[2], 750, 0, __PYX_ERR(2, 750, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ -- goto __pyx_L13; -- } -+ __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -+ if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -+ * else: -+ * return () - */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -+ __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ - } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 -+ * return <tuple>d.subarray.shape -+ * else: -+ * return () # <<<<<<<<<<<<<< - * - * - */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -+ /*else*/ { -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(__pyx_empty_tuple); -+ __pyx_r = __pyx_empty_tuple; -+ goto __pyx_L0; -+ } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ - - /* function exit code */ - __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -+ __Pyx_AddTraceback("numpy.PyDataType_SHAPE", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; - __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_TraceReturn(Py_None, 0); -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5509,10 +4002,13 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx - static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_arr, PyObject *__pyx_v_base) { - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("set_array_base", 0); -- __Pyx_TraceCall("set_array_base", __pyx_f[2], 1022, 0, __PYX_ERR(2, 1022, __pyx_L1_error)); -+ __Pyx_TraceCall("set_array_base", __pyx_f[2], 929, 0, __PYX_ERR(2, 929, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -5521,7 +4017,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5530,7 +4026,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5547,7 +4043,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5561,10 +4057,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - int __pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("get_array_base", 0); -- __Pyx_TraceCall("get_array_base", __pyx_f[2], 1026, 0, __PYX_ERR(2, 1026, __pyx_L1_error)); -+ __Pyx_TraceCall("get_array_base", __pyx_f[2], 933, 0, __PYX_ERR(2, 933, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5573,7 +4072,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5583,7 +4082,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5594,7 +4093,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5603,7 +4102,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5615,7 +4114,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5634,12 +4133,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -5654,14 +4153,17 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); -- __Pyx_TraceCall("import_array", __pyx_f[2], 1034, 0, __PYX_ERR(2, 1034, __pyx_L1_error)); -+ __Pyx_TraceCall("import_array", __pyx_f[2], 941, 0, __PYX_ERR(2, 941, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -5673,20 +4175,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5696,9 +4198,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5706,32 +4208,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__11, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5742,12 +4244,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -5766,7 +4268,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5786,10 +4288,13 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); -- __Pyx_TraceCall("import_umath", __pyx_f[2], 1040, 0, __PYX_ERR(2, 1040, __pyx_L1_error)); -+ __Pyx_TraceCall("import_umath", __pyx_f[2], 947, 0, __PYX_ERR(2, 947, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5805,16 +4310,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5828,7 +4333,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -5838,28 +4343,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__12, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5874,7 +4379,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5898,7 +4403,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5918,10 +4423,13 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); -- __Pyx_TraceCall("import_ufunc", __pyx_f[2], 1046, 0, __PYX_ERR(2, 1046, __pyx_L1_error)); -+ __Pyx_TraceCall("import_ufunc", __pyx_f[2], 953, 0, __PYX_ERR(2, 953, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5937,16 +4445,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5960,35 +4468,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__12, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6003,7 +4514,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -6026,6 +4537,225 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ __Pyx_TraceCall("is_timedelta64_object", __pyx_f[2], 967, 0, __PYX_ERR(2, 967, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.is_timedelta64_object", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ __Pyx_TraceCall("is_datetime64_object", __pyx_f[2], 982, 0, __PYX_ERR(2, 982, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.is_datetime64_object", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ __Pyx_TraceDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_TraceCall("get_datetime64_value", __pyx_f[2], 997, 1, __PYX_ERR(2, 997, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.get_datetime64_value", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 1); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ __Pyx_TraceDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_TraceCall("get_timedelta64_value", __pyx_f[2], 1007, 1, __PYX_ERR(2, 1007, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.get_timedelta64_value", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 1); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ __Pyx_TraceDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_TraceCall("get_datetime64_unit", __pyx_f[2], 1014, 1, __PYX_ERR(2, 1014, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.get_datetime64_unit", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1); -+ __pyx_r = (NPY_DATETIMEUNIT) 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 1); -+ return __pyx_r; -+} - static struct __pyx_vtabstruct_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase __pyx_vtable_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase; - - static PyObject *__pyx_tp_new_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { -@@ -6099,7 +4829,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPiv - sizeof(struct __pyx_obj_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -6149,8 +4884,14 @@ static PyTypeObject __pyx_type_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPiv - #if PY_VERSION_HEX >= 0x030400a1 - 0, /*tp_finalize*/ - #endif -- #if PY_VERSION_HEX >= 0x030800b1 -- 0, /*tp_vectorcall*/ -+ #if PY_VERSION_HEX >= 0x030800b1 -+ 0, /*tp_vectorcall*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ - #endif - }; - -@@ -6204,23 +4945,15 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_kp_s_CyClpDualRowPivotBase_pyx_pivotR, __pyx_k_CyClpDualRowPivotBase_pyx_pivotR, sizeof(__pyx_k_CyClpDualRowPivotBase_pyx_pivotR), 0, 0, 1, 0}, - {&__pyx_kp_s_CyClpDualRowPivotBase_pyx_update, __pyx_k_CyClpDualRowPivotBase_pyx_update, sizeof(__pyx_k_CyClpDualRowPivotBase_pyx_update), 0, 0, 1, 0}, - {&__pyx_kp_s_CyClpDualRowPivotBase_pyx_update_2, __pyx_k_CyClpDualRowPivotBase_pyx_update_2, sizeof(__pyx_k_CyClpDualRowPivotBase_pyx_update_2), 0, 0, 1, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -6228,15 +4961,11 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -6298,82 +5027,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__5); - __Pyx_GIVEREF(__pyx_tuple__5); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__10 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__10); -- __Pyx_GIVEREF(__pyx_tuple__10); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__11 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__11)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__11); -- __Pyx_GIVEREF(__pyx_tuple__11); -+ __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__6); -+ __Pyx_GIVEREF(__pyx_tuple__6); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__12 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__12)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__12); -- __Pyx_GIVEREF(__pyx_tuple__12); -+ __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__7); -+ __Pyx_GIVEREF(__pyx_tuple__7); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6414,6 +5088,9 @@ static int __Pyx_modinit_variable_export_code(void) { - - static int __Pyx_modinit_function_export_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); - /*--- Function export code ---*/ - if (__Pyx_ExportFunction("RunPivotRow", (void (*)(void))__pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_RunPivotRow, "int (void *)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -6429,6 +5106,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_vtabptr_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase = &__pyx_vtable_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase; -@@ -6460,6 +5140,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -6495,18 +5178,38 @@ static int __Pyx_modinit_type_import_code(void) { - if (!__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase) __PYX_ERR(7, 67, __pyx_L1_error) - __pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase = (struct __pyx_vtabstruct_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase*)__Pyx_GetVtable(__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase->tp_dict); if (unlikely(!__pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase)) __PYX_ERR(7, 67, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyCoinModel"); if (unlikely(!__pyx_t_1)) __PYX_ERR(8, 34, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -6609,17 +5312,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6703,6 +5408,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyClpDualRowPivotBase(PyObject *__ - __Pyx_TraceDeclarations - int __pyx_t_1; - PyObject *__pyx_t_2 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -6750,11 +5458,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -6791,15 +5497,15 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); -- if (unlikely(__Pyx_modinit_function_export_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_function_export_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ -@@ -6827,12 +5533,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - __Pyx_TraceReturn(Py_None, 0); - -@@ -6961,10 +5667,9 @@ static int __Pyx_TraceSetupAndCall(PyCodeObject** code, - (*frame)->f_tstate = tstate; - #endif - } -- __Pyx_PyFrame_SetLineNumber(*frame, firstlineno); -+ __Pyx_PyFrame_SetLineNumber(*frame, firstlineno); - retval = 1; -- tstate->tracing++; -- tstate->use_tracing = 0; -+ __Pyx_EnterTracing(tstate); - __Pyx_ErrFetchInState(tstate, &type, &value, &traceback); - #if CYTHON_TRACE - if (tstate->c_tracefunc) -@@ -6972,12 +5677,10 @@ static int __Pyx_TraceSetupAndCall(PyCodeObject** code, - if (retval && tstate->c_profilefunc) - #endif - retval = tstate->c_profilefunc(tstate->c_profileobj, *frame, PyTrace_CALL, NULL) == 0; -- tstate->use_tracing = (tstate->c_profilefunc || -- (CYTHON_TRACE && tstate->c_tracefunc)); -- tstate->tracing--; -+ __Pyx_LeaveTracing(tstate); - if (retval) { - __Pyx_ErrRestoreInState(tstate, type, value, traceback); -- return tstate->use_tracing && retval; -+ return __Pyx_IsTracing(tstate, 0, 0) && retval; - } else { - Py_XDECREF(type); - Py_XDECREF(value); -@@ -7148,7 +5851,7 @@ static int __Pyx_CheckKeywordStrings( - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -7390,6 +6093,7 @@ static void __Pyx_BufFmt_RaiseUnexpectedChar(char ch) { - } - static const char* __Pyx_BufFmt_DescribeTypeChar(char ch, int is_complex) { - switch (ch) { -+ case '?': return "'bool'"; - case 'c': return "'char'"; - case 'b': return "'signed char'"; - case 'B': return "'unsigned char'"; -@@ -7432,7 +6136,7 @@ static size_t __Pyx_BufFmt_TypeCharToStandardSize(char ch, int is_complex) { - } - static size_t __Pyx_BufFmt_TypeCharToNativeSize(char ch, int is_complex) { - switch (ch) { -- case 'c': case 'b': case 'B': case 's': case 'p': return 1; -+ case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; - case 'h': case 'H': return sizeof(short); - case 'i': case 'I': return sizeof(int); - case 'l': case 'L': return sizeof(long); -@@ -7516,7 +6220,7 @@ static char __Pyx_BufFmt_TypeCharToGroup(char ch, int is_complex) { - case 'b': case 'h': case 'i': - case 'l': case 'q': case 's': case 'p': - return 'I'; -- case 'B': case 'H': case 'I': case 'L': case 'Q': -+ case '?': case 'B': case 'H': case 'I': case 'L': case 'Q': - return 'U'; - case 'f': case 'd': case 'g': - return (is_complex ? 'C' : 'R'); -@@ -7660,9 +6364,7 @@ static PyObject * - __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) - { - const char *ts = *tsp; -- int i = 0, number; -- int ndim = ctx->head->field->type->ndim; --; -+ int i = 0, number, ndim; - ++ts; - if (ctx->new_count != 1) { - PyErr_SetString(PyExc_ValueError, -@@ -7670,6 +6372,7 @@ __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) - return NULL; - } - if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; -+ ndim = ctx->head->field->type->ndim; - while (*ts && *ts != ')') { - switch (*ts) { - case ' ': case '\f': case '\r': case '\n': case '\t': case '\v': continue; -@@ -7795,12 +6498,12 @@ static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const cha - return NULL; - } - CYTHON_FALLTHROUGH; -- case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': -+ case '?': case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': - case 'l': case 'L': case 'q': case 'Q': - case 'f': case 'd': case 'g': - case 'O': case 'p': -- if (ctx->enc_type == *ts && got_Z == ctx->is_complex && -- ctx->enc_packmode == ctx->new_packmode) { -+ if ((ctx->enc_type == *ts) && (got_Z == ctx->is_complex) && -+ (ctx->enc_packmode == ctx->new_packmode) && (!ctx->is_valid_array)) { - ctx->enc_count += ctx->new_count; - ctx->new_count = 1; - got_Z = 0; -@@ -7883,250 +6586,6 @@ fail:; - return -1; - } - --/* PyCFunctionFastCall */ -- #if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { -- PyCFunctionObject *func = (PyCFunctionObject*)func_obj; -- PyCFunction meth = PyCFunction_GET_FUNCTION(func); -- PyObject *self = PyCFunction_GET_SELF(func); -- int flags = PyCFunction_GET_FLAGS(func); -- assert(PyCFunction_Check(func)); -- assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); -- assert(nargs >= 0); -- assert(nargs == 0 || args != NULL); -- /* _PyCFunction_FastCallDict() must not be called with an exception set, -- because it may clear it (directly or indirectly) and so the -- caller loses its exception */ -- assert(!PyErr_Occurred()); -- if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { -- return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); -- } else { -- return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); -- } --} --#endif -- --/* PyFunctionFastCall */ -- #if CYTHON_FAST_PYCALL --static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, -- PyObject *globals) { -- PyFrameObject *f; -- PyThreadState *tstate = __Pyx_PyThreadState_Current; -- PyObject **fastlocals; -- Py_ssize_t i; -- PyObject *result; -- assert(globals != NULL); -- /* XXX Perhaps we should create a specialized -- PyFrame_New() that doesn't take locals, but does -- take builtins without sanity checking them. -- */ -- assert(tstate != NULL); -- f = PyFrame_New(tstate, co, globals, NULL); -- if (f == NULL) { -- return NULL; -- } -- fastlocals = __Pyx_PyFrame_GetLocalsplus(f); -- for (i = 0; i < na; i++) { -- Py_INCREF(*args); -- fastlocals[i] = *args++; -- } -- result = PyEval_EvalFrameEx(f,0); -- ++tstate->recursion_depth; -- Py_DECREF(f); -- --tstate->recursion_depth; -- return result; --} --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { -- PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); -- PyObject *globals = PyFunction_GET_GLOBALS(func); -- PyObject *argdefs = PyFunction_GET_DEFAULTS(func); -- PyObject *closure; --#if PY_MAJOR_VERSION >= 3 -- PyObject *kwdefs; --#endif -- PyObject *kwtuple, **k; -- PyObject **d; -- Py_ssize_t nd; -- Py_ssize_t nk; -- PyObject *result; -- assert(kwargs == NULL || PyDict_Check(kwargs)); -- nk = kwargs ? PyDict_Size(kwargs) : 0; -- if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { -- return NULL; -- } -- if ( --#if PY_MAJOR_VERSION >= 3 -- co->co_kwonlyargcount == 0 && --#endif -- likely(kwargs == NULL || nk == 0) && -- co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { -- if (argdefs == NULL && co->co_argcount == nargs) { -- result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); -- goto done; -- } -- else if (nargs == 0 && argdefs != NULL -- && co->co_argcount == Py_SIZE(argdefs)) { -- /* function called with no arguments, but all parameters have -- a default value: use default values as arguments .*/ -- args = &PyTuple_GET_ITEM(argdefs, 0); -- result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); -- goto done; -- } -- } -- if (kwargs != NULL) { -- Py_ssize_t pos, i; -- kwtuple = PyTuple_New(2 * nk); -- if (kwtuple == NULL) { -- result = NULL; -- goto done; -- } -- k = &PyTuple_GET_ITEM(kwtuple, 0); -- pos = i = 0; -- while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { -- Py_INCREF(k[i]); -- Py_INCREF(k[i+1]); -- i += 2; -- } -- nk = i / 2; -- } -- else { -- kwtuple = NULL; -- k = NULL; -- } -- closure = PyFunction_GET_CLOSURE(func); --#if PY_MAJOR_VERSION >= 3 -- kwdefs = PyFunction_GET_KW_DEFAULTS(func); --#endif -- if (argdefs != NULL) { -- d = &PyTuple_GET_ITEM(argdefs, 0); -- nd = Py_SIZE(argdefs); -- } -- else { -- d = NULL; -- nd = 0; -- } --#if PY_MAJOR_VERSION >= 3 -- result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, kwdefs, closure); --#else -- result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, closure); --#endif -- Py_XDECREF(kwtuple); --done: -- Py_LeaveRecursiveCall(); -- return result; --} --#endif --#endif -- --/* PyObjectCallMethO */ -- #if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { -- PyObject *self, *result; -- PyCFunction cfunc; -- cfunc = PyCFunction_GET_FUNCTION(func); -- self = PyCFunction_GET_SELF(func); -- if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -- return NULL; -- result = cfunc(self, arg); -- Py_LeaveRecursiveCall(); -- if (unlikely(!result) && unlikely(!PyErr_Occurred())) { -- PyErr_SetString( -- PyExc_SystemError, -- "NULL result without error in PyObject_Call"); -- } -- return result; --} --#endif -- --/* PyObjectCallOneArg */ -- #if CYTHON_COMPILING_IN_CPYTHON --static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_New(1); -- if (unlikely(!args)) return NULL; -- Py_INCREF(arg); -- PyTuple_SET_ITEM(args, 0, arg); -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { --#if CYTHON_FAST_PYCALL -- if (PyFunction_Check(func)) { -- return __Pyx_PyFunction_FastCall(func, &arg, 1); -- } --#endif -- if (likely(PyCFunction_Check(func))) { -- if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { -- return __Pyx_PyObject_CallMethO(func, arg); --#if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -- return __Pyx_PyCFunction_FastCall(func, &arg, 1); --#endif -- } -- } -- return __Pyx__PyObject_CallOneArg(func, arg); --} --#else --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_Pack(1, arg); -- if (unlikely(!args)) return NULL; -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --#endif -- --/* DictGetItem */ -- #if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ -- static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ -- static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ -- static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -8350,6 +6809,28 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+ static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -8377,43 +6858,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -8535,7 +7024,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -8565,7 +7054,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -8639,7 +7128,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -8662,30 +7151,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -8704,11 +7194,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -8743,7 +7238,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #if PY_MAJOR_VERSION < 3 - static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { - if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags); -- if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) return __pyx_pw_5numpy_7ndarray_1__getbuffer__(obj, view, flags); - PyErr_Format(PyExc_TypeError, "'%.200s' does not have the buffer interface", Py_TYPE(obj)->tp_name); - return -1; - } -@@ -8755,7 +7249,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return; - } - if ((0)) {} -- else if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) __pyx_pw_5numpy_7ndarray_3__releasebuffer__(obj, view); - view->obj = NULL; - Py_DECREF(obj); - } -@@ -8784,37 +7277,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return (target_type) value;\ - } - --/* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- - /* Declarations */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus -@@ -8932,7 +7394,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -9087,7 +7548,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -9125,40 +7585,16 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - #endif - #endif - --/* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -9345,9 +7781,54 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return (int) -1; - } - -+/* CIntToPy */ -+ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(int) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); -+ } -+} -+ - /* CIntToPy */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { -@@ -9378,7 +7859,14 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -9966,6 +8454,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyClpPrimalColumnPivotBase.cpp b/cylp/cy/CyClpPrimalColumnPivotBase.cpp -index 10c5a89..ffa1838 100644 ---- a/cylp/cy/CyClpPrimalColumnPivotBase.cpp -+++ b/cylp/cy/CyClpPrimalColumnPivotBase.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -612,7 +695,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "pythread.h" - #include "ICoinIndexedVector.hpp" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ClpDualRowPivot.hpp" - #include "ClpFactorization.hpp" - #include "IClpDualRowPivotBase.h" -@@ -641,11 +730,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "OsiSolverInterface.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "IClpPrimalColumnPivotBase.h" - #include "ClpPrimalColumnPivot.hpp" -@@ -746,6 +835,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -881,23 +971,23 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyClpPrimalColumnPivotBase.pyx", -+ "cylp/cy/CyClpPrimalColumnPivotBase.pyx", - "__init__.pxd", - "type.pxd", - "bool.pxd", - "complex.pxd", -- "cylp\\cy\\CyCoinIndexedVector.pxd", -- "cylp\\cy\\CyClpDualRowPivotBase.pxd", -- "cylp\\cy\\CyCoinModel.pxd", -- "cylp\\cy\\CyCoinPackedMatrix.pxd", -- "cylp\\cy\\CyCgl.pxd", -- "cylp\\cy\\CyCbcNode.pxd", -- "cylp\\cy\\CyOsiSolverInterface.pxd", -- "cylp\\cy\\CyCbcModel.pxd", -- "cylp\\cy\\CyClpSimplex.pxd", -+ "cylp/cy/CyCoinIndexedVector.pxd", -+ "cylp/cy/CyClpDualRowPivotBase.pxd", -+ "cylp/cy/CyCoinModel.pxd", -+ "cylp/cy/CyCoinPackedMatrix.pxd", -+ "cylp/cy/CyCgl.pxd", -+ "cylp/cy/CyCbcNode.pxd", -+ "cylp/cy/CyOsiSolverInterface.pxd", -+ "cylp/cy/CyCbcModel.pxd", -+ "cylp/cy/CyClpSimplex.pxd", - }; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -906,7 +996,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -915,7 +1005,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -924,7 +1014,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -933,7 +1023,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -942,7 +1032,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -951,7 +1041,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -960,7 +1050,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -969,7 +1059,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -978,7 +1068,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -987,7 +1077,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -996,7 +1086,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1005,7 +1095,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1014,7 +1104,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1023,7 +1113,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1032,7 +1122,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1041,7 +1131,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1050,7 +1140,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1059,7 +1149,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1068,7 +1158,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1077,7 +1167,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1139,7 +1229,7 @@ struct __pyx_obj_4cylp_2cy_12CyClpSimplex_CyClpSimplex; - struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus; - struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1148,7 +1238,7 @@ struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBa - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1157,7 +1247,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1166,7 +1256,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1891,11 +1981,45 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define CYTHON_FRAME_DEL(frame) Py_CLEAR(frame) - #endif - #define __Pyx_TraceDeclarations\ -- static PyCodeObject *__pyx_frame_code = NULL;\ -- CYTHON_FRAME_MODIFIER PyFrameObject *__pyx_frame = NULL;\ -- int __Pyx_use_tracing = 0; -+ static PyCodeObject *__pyx_frame_code = NULL;\ -+ CYTHON_FRAME_MODIFIER PyFrameObject *__pyx_frame = NULL;\ -+ int __Pyx_use_tracing = 0; - #define __Pyx_TraceFrameInit(codeobj)\ -- if (codeobj) __pyx_frame_code = (PyCodeObject*) codeobj; -+ if (codeobj) __pyx_frame_code = (PyCodeObject*) codeobj; -+#if PY_VERSION_HEX >= 0x030b00a2 -+ #define __Pyx_IsTracing(tstate, check_tracing, check_funcs)\ -+ (unlikely((tstate)->cframe->use_tracing) &&\ -+ (!(check_tracing) || !(tstate)->tracing) &&\ -+ (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc))) -+ #define __Pyx_EnterTracing(tstate) PyThreadState_EnterTracing(tstate) -+ #define __Pyx_LeaveTracing(tstate) PyThreadState_LeaveTracing(tstate) -+#elif PY_VERSION_HEX >= 0x030a00b1 -+ #define __Pyx_IsTracing(tstate, check_tracing, check_funcs)\ -+ (unlikely((tstate)->cframe->use_tracing) &&\ -+ (!(check_tracing) || !(tstate)->tracing) &&\ -+ (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc))) -+ #define __Pyx_EnterTracing(tstate)\ -+ do { tstate->tracing++; tstate->cframe->use_tracing = 0; } while (0) -+ #define __Pyx_LeaveTracing(tstate)\ -+ do {\ -+ tstate->tracing--;\ -+ tstate->cframe->use_tracing = ((CYTHON_TRACE && tstate->c_tracefunc != NULL)\ -+ || tstate->c_profilefunc != NULL);\ -+ } while (0) -+#else -+ #define __Pyx_IsTracing(tstate, check_tracing, check_funcs)\ -+ (unlikely((tstate)->use_tracing) &&\ -+ (!(check_tracing) || !(tstate)->tracing) &&\ -+ (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc))) -+ #define __Pyx_EnterTracing(tstate)\ -+ do { tstate->tracing++; tstate->use_tracing = 0; } while (0) -+ #define __Pyx_LeaveTracing(tstate)\ -+ do {\ -+ tstate->tracing--;\ -+ tstate->use_tracing = ((CYTHON_TRACE && tstate->c_tracefunc != NULL)\ -+ || tstate->c_profilefunc != NULL);\ -+ } while (0) -+#endif - #ifdef WITH_THREAD - #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error)\ - if (nogil) {\ -@@ -1903,8 +2027,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyThreadState *tstate;\ - PyGILState_STATE state = PyGILState_Ensure();\ - tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing) && !tstate->tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -+ if (__Pyx_IsTracing(tstate, 1, 1)) {\ - __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&__pyx_frame_code, &__pyx_frame, tstate, funcname, srcfile, firstlineno);\ - }\ - PyGILState_Release(state);\ -@@ -1912,8 +2035,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - }\ - } else {\ - PyThreadState* tstate = PyThreadState_GET();\ -- if (unlikely(tstate->use_tracing) && !tstate->tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -+ if (__Pyx_IsTracing(tstate, 1, 1)) {\ - __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&__pyx_frame_code, &__pyx_frame, tstate, funcname, srcfile, firstlineno);\ - if (unlikely(__Pyx_use_tracing < 0)) goto_error;\ - }\ -@@ -1921,8 +2043,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #else - #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error)\ - { PyThreadState* tstate = PyThreadState_GET();\ -- if (unlikely(tstate->use_tracing) && !tstate->tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -+ if (__Pyx_IsTracing(tstate, 1, 1)) {\ - __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&__pyx_frame_code, &__pyx_frame, tstate, funcname, srcfile, firstlineno);\ - if (unlikely(__Pyx_use_tracing < 0)) goto_error;\ - }\ -@@ -1931,10 +2052,8 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define __Pyx_TraceException()\ - if (likely(!__Pyx_use_tracing)); else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -- tstate->tracing++;\ -- tstate->use_tracing = 0;\ -+ if (__Pyx_IsTracing(tstate, 0, 1)) {\ -+ __Pyx_EnterTracing(tstate);\ - PyObject *exc_info = __Pyx_GetExceptionTuple(tstate);\ - if (exc_info) {\ - if (CYTHON_TRACE && tstate->c_tracefunc)\ -@@ -1944,22 +2063,19 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - tstate->c_profileobj, __pyx_frame, PyTrace_EXCEPTION, exc_info);\ - Py_DECREF(exc_info);\ - }\ -- tstate->use_tracing = 1;\ -- tstate->tracing--;\ -+ __Pyx_LeaveTracing(tstate);\ - }\ - } - static void __Pyx_call_return_trace_func(PyThreadState *tstate, PyFrameObject *frame, PyObject *result) { - PyObject *type, *value, *traceback; - __Pyx_ErrFetchInState(tstate, &type, &value, &traceback); -- tstate->tracing++; -- tstate->use_tracing = 0; -+ __Pyx_EnterTracing(tstate); - if (CYTHON_TRACE && tstate->c_tracefunc) - tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_RETURN, result); - if (tstate->c_profilefunc) - tstate->c_profilefunc(tstate->c_profileobj, frame, PyTrace_RETURN, result); - CYTHON_FRAME_DEL(frame); -- tstate->use_tracing = 1; -- tstate->tracing--; -+ __Pyx_LeaveTracing(tstate); - __Pyx_ErrRestoreInState(tstate, type, value, traceback); - } - #ifdef WITH_THREAD -@@ -1970,14 +2086,14 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyThreadState *tstate;\ - PyGILState_STATE state = PyGILState_Ensure();\ - tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0)) {\ - __Pyx_call_return_trace_func(tstate, __pyx_frame, (PyObject*)result);\ - }\ - PyGILState_Release(state);\ - }\ - } else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0)) {\ - __Pyx_call_return_trace_func(tstate, __pyx_frame, (PyObject*)result);\ - }\ - }\ -@@ -1986,7 +2102,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define __Pyx_TraceReturn(result, nogil)\ - if (likely(!__Pyx_use_tracing)); else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0)) {\ - __Pyx_call_return_trace_func(tstate, __pyx_frame, (PyObject*)result);\ - }\ - } -@@ -2006,11 +2122,9 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyObject *type, *value, *traceback; - __Pyx_ErrFetchInState(tstate, &type, &value, &traceback); - __Pyx_PyFrame_SetLineNumber(frame, lineno); -- tstate->tracing++; -- tstate->use_tracing = 0; -+ __Pyx_EnterTracing(tstate); - ret = tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_LINE, NULL); -- tstate->use_tracing = 1; -- tstate->tracing--; -+ __Pyx_LeaveTracing(tstate); - if (likely(!ret)) { - __Pyx_ErrRestoreInState(tstate, type, value, traceback); - } else { -@@ -2029,7 +2143,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyThreadState *tstate;\ - PyGILState_STATE state = PyGILState_Ensure();\ - tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing && tstate->c_tracefunc && __pyx_frame->f_trace)) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && __pyx_frame->f_trace) {\ - ret = __Pyx_call_line_trace_func(tstate, __pyx_frame, lineno);\ - }\ - PyGILState_Release(state);\ -@@ -2037,7 +2151,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - }\ - } else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing && tstate->c_tracefunc && __pyx_frame->f_trace)) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && __pyx_frame->f_trace) {\ - int ret = __Pyx_call_line_trace_func(tstate, __pyx_frame, lineno);\ - if (unlikely(ret)) goto_error;\ - }\ -@@ -2047,7 +2161,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define __Pyx_TraceLine(lineno, nogil, goto_error)\ - if (likely(!__Pyx_use_tracing)); else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing && tstate->c_tracefunc && __pyx_frame->f_trace)) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && __pyx_frame->f_trace) {\ - int ret = __Pyx_call_line_trace_func(tstate, __pyx_frame, lineno);\ - if (unlikely(ret)) goto_error;\ - }\ -@@ -2079,67 +2193,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* PyCFunctionFastCall.proto */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); --#else --#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) --#endif -- --/* PyFunctionFastCall.proto */ --#if CYTHON_FAST_PYCALL --#define __Pyx_PyFunction_FastCall(func, args, nargs)\ -- __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); --#else --#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) --#endif --#define __Pyx_BUILD_ASSERT_EXPR(cond)\ -- (sizeof(char [1 - 2*!(cond)]) - 1) --#ifndef Py_MEMBER_SIZE --#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) --#endif -- static size_t __pyx_pyframe_localsplus_offset = 0; -- #include "frameobject.h" -- #define __Pxy_PyFrame_Initialize_Offsets()\ -- ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ -- (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) -- #define __Pyx_PyFrame_GetLocalsplus(frame)\ -- (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) --#endif -- --/* PyObjectCallMethO.proto */ --#if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); --#endif -- --/* PyObjectCallOneArg.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); -- --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -2189,6 +2242,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -2258,8 +2314,10 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); - static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -2359,12 +2417,12 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - #endif - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); - -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+ - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - -@@ -2493,8 +2551,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyClpDualRowPivotBase' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase = 0; -@@ -2556,58 +2623,38 @@ int __pyx_module_is_main_cylp__cy__CyClpPrimalColumnPivotBase = 0; - - /* Implementation of 'cylp.cy.CyClpPrimalColumnPivotBase' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_test[] = "__test__"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_reduce[] = "__reduce__"; - static const char __pyx_k_getstate[] = "__getstate__"; - static const char __pyx_k_setstate[] = "__setstate__"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_CyClpPrimalColumnPivotBase[] = "CyClpPrimalColumnPivotBase"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; - static const char __pyx_k_CyClpPrimalColumnPivotBase_pyx_p[] = "CyClpPrimalColumnPivotBase.pyx: pivotColumn must be implemented."; - static const char __pyx_k_CyClpPrimalColumnPivotBase_pyx_s[] = "CyClpPrimalColumnPivotBase.pyx: saveWeights must be implemented."; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_self_CppSelf_cannot_be_converted[] = "self.CppSelf cannot be converted to a Python object for pickling"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyClpPrimalColumnPivotBase; - static PyObject *__pyx_kp_s_CyClpPrimalColumnPivotBase_pyx_p; - static PyObject *__pyx_kp_s_CyClpPrimalColumnPivotBase_pyx_s; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_getstate; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -2615,15 +2662,12 @@ static PyObject *__pyx_kp_s_self_CppSelf_cannot_be_converted; - static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static int __pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnPivotBase___init__(struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase *__pyx_v_self); /* proto */ - static void __pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnPivotBase_2__dealloc__(struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnPivotBase_5nRows___get__(struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnPivotBase_5nCols___get__(struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnPivotBase_4__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnPivotBase_6__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; -@@ -2631,11 +2675,6 @@ static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; - static PyObject *__pyx_tuple__5; - static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; --static PyObject *__pyx_tuple__10; --static PyObject *__pyx_tuple__11; - /* Late includes */ - - /* "cylp/cy/CyClpPrimalColumnPivotBase.pyx":7 -@@ -2652,6 +2691,9 @@ static int __pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunPivotColumn(void *_ - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_t_2; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("RunPivotColumn", 0); - __Pyx_TraceCall("RunPivotColumn", __pyx_f[1], 7, 0, __PYX_ERR(1, 7, __pyx_L1_error)); - -@@ -2700,6 +2742,9 @@ static ClpPrimalColumnPivot *__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunC - ClpPrimalColumnPivot *__pyx_r; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("RunClone", 0); - __Pyx_TraceCall("RunClone", __pyx_f[1], 14, 0, __PYX_ERR(1, 14, __pyx_L1_error)); - -@@ -2742,6 +2787,9 @@ static ClpPrimalColumnPivot *__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunC - static void __pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunSaveWeights(void *__pyx_v_ptr, IClpSimplex *__pyx_v_model, int __pyx_v_mode) { - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("RunSaveWeights", 0); - __Pyx_TraceCall("RunSaveWeights", __pyx_f[1], 17, 0, __PYX_ERR(1, 17, __pyx_L1_error)); - -@@ -2799,6 +2847,9 @@ static int __pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnPi - int __pyx_r; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__init__", 0); - __Pyx_TraceCall("__init__", __pyx_f[1], 24, 0, __PYX_ERR(1, 24, __pyx_L1_error)); - -@@ -2862,6 +2913,9 @@ static void __pyx_pw_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnP - static void __pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnPivotBase_2__dealloc__(struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase *__pyx_v_self) { - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__dealloc__", 0); - __Pyx_TraceCall("__dealloc__", __pyx_f[1], 32, 0, __PYX_ERR(1, 32, __pyx_L1_error)); - -@@ -2913,6 +2967,9 @@ static PyObject *__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalCol - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("pivotColumn", 0); - __Pyx_TraceCall("pivotColumn", __pyx_f[1], 36, 0, __PYX_ERR(1, 36, __pyx_L1_error)); - -@@ -2961,6 +3018,9 @@ static ClpPrimalColumnPivot *__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_26Cy - ClpPrimalColumnPivot *__pyx_r; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("clone", 0); - __Pyx_TraceCall("clone", __pyx_f[1], 42, 0, __PYX_ERR(1, 42, __pyx_L1_error)); - -@@ -3013,6 +3073,9 @@ static void __pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnPi - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("saveWeights", 0); - __Pyx_TraceCall("saveWeights", __pyx_f[1], 51, 0, __PYX_ERR(1, 51, __pyx_L1_error)); - -@@ -3057,6 +3120,9 @@ static IClpSimplex *__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimal - IClpSimplex *__pyx_r; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("model", 0); - __Pyx_TraceCall("model", __pyx_f[1], 55, 0, __PYX_ERR(1, 55, __pyx_L1_error)); - -@@ -3099,6 +3165,9 @@ static IClpSimplex *__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimal - static void __pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnPivotBase_setModel(struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase *__pyx_v_self, IClpSimplex *__pyx_v_m) { - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("setModel", 0); - __Pyx_TraceCall("setModel", __pyx_f[1], 58, 0, __PYX_ERR(1, 58, __pyx_L1_error)); - -@@ -3140,6 +3209,9 @@ static double *__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColum - double *__pyx_r; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("getReducedCosts", 0); - __Pyx_TraceCall("getReducedCosts", __pyx_f[1], 61, 0, __PYX_ERR(1, 61, __pyx_L1_error)); - -@@ -3197,6 +3269,9 @@ static PyObject *__pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalCo - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - __Pyx_TraceCall("__get__", __pyx_f[1], 65, 0, __PYX_ERR(1, 65, __pyx_L1_error)); - -@@ -3259,6 +3334,9 @@ static PyObject *__pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalCo - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - __Pyx_TraceCall("__get__", __pyx_f[1], 69, 0, __PYX_ERR(1, 69, __pyx_L1_error)); - -@@ -3318,6 +3396,9 @@ static PyObject *__pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalCo - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - __Pyx_TraceCall("__reduce_cython__", __pyx_f[0], 1, 0, __PYX_ERR(0, 1, __pyx_L1_error)); - -@@ -3376,6 +3457,9 @@ static PyObject *__pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalCo - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - __Pyx_TraceCall("__setstate_cython__", __pyx_f[0], 3, 0, __PYX_ERR(0, 3, __pyx_L1_error)); - -@@ -3408,1952 +3492,355 @@ static PyObject *__pyx_pf_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalCo - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t -+ * -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * - */ - --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -+ PyObject *__pyx_r = NULL; - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- __Pyx_TraceCall("__getbuffer__", __pyx_f[2], 258, 0, __PYX_ERR(2, 258, __pyx_L1_error)); -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -+ __Pyx_TraceCall("PyArray_MultiIterNew1", __pyx_f[2], 735, 0, __PYX_ERR(2, 735, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): -+ * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< - * -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): - */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t - * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) - */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -+ __Pyx_TraceCall("PyArray_MultiIterNew2", __pyx_f[2], 738, 0, __PYX_ERR(2, 738, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") - */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -+ __Pyx_TraceCall("PyArray_MultiIterNew3", __pyx_f[2], 741, 0, __PYX_ERR(2, 741, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. - */ -- goto __pyx_L9; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * - */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); -+ __Pyx_TraceCall("PyArray_MultiIterNew4", __pyx_f[2], 744, 0, __PYX_ERR(2, 744, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< - * -- * cdef int t -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- * info.obj = self # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * if not PyDataType_HASFIELDS(descr): - */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -+ __Pyx_TraceCall("PyArray_MultiIterNew5", __pyx_f[2], 747, 0, __PYX_ERR(2, 747, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -+ * -+ * cdef inline tuple PyDataType_SHAPE(dtype d): - */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_TraceReturn(Py_None, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- __Pyx_TraceCall("__releasebuffer__", __pyx_f[2], 337, 0, __PYX_ERR(2, 337, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_WriteUnraisable("numpy.ndarray.__releasebuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0); -- __pyx_L0:; -- __Pyx_TraceReturn(Py_None, 0); -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew1", __pyx_f[2], 821, 0, __PYX_ERR(2, 821, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -- * -- * cdef inline object PyArray_MultiIterNew1(a): -- * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew2", __pyx_f[2], 824, 0, __PYX_ERR(2, 824, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew3", __pyx_f[2], 827, 0, __PYX_ERR(2, 827, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew4", __pyx_f[2], 830, 0, __PYX_ERR(2, 830, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew5", __pyx_f[2], 833, 0, __PYX_ERR(2, 833, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); -- __Pyx_TraceCall("PyDataType_SHAPE", __pyx_f[2], 836, 0, __PYX_ERR(2, 836, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -- * else: -- * return () -- */ -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -- __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -- * return <tuple>d.subarray.shape -- * else: -- * return () # <<<<<<<<<<<<<< -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -- */ -- /*else*/ { -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(__pyx_empty_tuple); -- __pyx_r = __pyx_empty_tuple; -- goto __pyx_L0; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_AddTraceback("numpy.PyDataType_SHAPE", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_TraceReturn(__pyx_r, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- __Pyx_TraceCall("_util_dtypestring", __pyx_f[2], 842, 0, __PYX_ERR(2, 842, __pyx_L1_error)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -+ * -+ */ - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -+ * -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ -- __pyx_v_f = (__pyx_v_f + 1); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ int __pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); -+ __Pyx_TraceCall("PyDataType_SHAPE", __pyx_f[2], 750, 0, __PYX_ERR(2, 750, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ -- goto __pyx_L13; -- } -+ __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -+ if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -+ * else: -+ * return () - */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -+ __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ - } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 -+ * return <tuple>d.subarray.shape -+ * else: -+ * return () # <<<<<<<<<<<<<< - * - * - */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -+ /*else*/ { -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(__pyx_empty_tuple); -+ __pyx_r = __pyx_empty_tuple; -+ goto __pyx_L0; -+ } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ - - /* function exit code */ - __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -+ __Pyx_AddTraceback("numpy.PyDataType_SHAPE", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; - __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_TraceReturn(Py_None, 0); -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_TraceReturn(__pyx_r, 0); - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5364,10 +3851,13 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx - static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_arr, PyObject *__pyx_v_base) { - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("set_array_base", 0); -- __Pyx_TraceCall("set_array_base", __pyx_f[2], 1022, 0, __PYX_ERR(2, 1022, __pyx_L1_error)); -+ __Pyx_TraceCall("set_array_base", __pyx_f[2], 929, 0, __PYX_ERR(2, 929, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -5376,7 +3866,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5385,7 +3875,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5402,7 +3892,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5416,10 +3906,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __Pyx_TraceDeclarations - __Pyx_RefNannyDeclarations - int __pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("get_array_base", 0); -- __Pyx_TraceCall("get_array_base", __pyx_f[2], 1026, 0, __PYX_ERR(2, 1026, __pyx_L1_error)); -+ __Pyx_TraceCall("get_array_base", __pyx_f[2], 933, 0, __PYX_ERR(2, 933, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5428,7 +3921,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5438,7 +3931,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5449,7 +3942,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5458,7 +3951,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5470,7 +3963,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5489,12 +3982,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -5509,14 +4002,17 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); -- __Pyx_TraceCall("import_array", __pyx_f[2], 1034, 0, __PYX_ERR(2, 1034, __pyx_L1_error)); -+ __Pyx_TraceCall("import_array", __pyx_f[2], 941, 0, __PYX_ERR(2, 941, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -5528,20 +4024,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5551,9 +4047,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5561,32 +4057,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5597,12 +4093,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -5621,7 +4117,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5641,10 +4137,13 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); -- __Pyx_TraceCall("import_umath", __pyx_f[2], 1040, 0, __PYX_ERR(2, 1040, __pyx_L1_error)); -+ __Pyx_TraceCall("import_umath", __pyx_f[2], 947, 0, __PYX_ERR(2, 947, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5660,16 +4159,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5683,7 +4182,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -5693,28 +4192,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__11, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5729,7 +4228,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5753,7 +4252,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5773,10 +4272,13 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); -- __Pyx_TraceCall("import_ufunc", __pyx_f[2], 1046, 0, __PYX_ERR(2, 1046, __pyx_L1_error)); -+ __Pyx_TraceCall("import_ufunc", __pyx_f[2], 953, 0, __PYX_ERR(2, 953, __pyx_L1_error)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5792,16 +4294,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5815,35 +4317,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__11, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5858,7 +4363,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5881,6 +4386,225 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ __Pyx_TraceCall("is_timedelta64_object", __pyx_f[2], 967, 0, __PYX_ERR(2, 967, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.is_timedelta64_object", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ __Pyx_TraceCall("is_datetime64_object", __pyx_f[2], 982, 0, __PYX_ERR(2, 982, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.is_datetime64_object", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ __Pyx_TraceDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_TraceCall("get_datetime64_value", __pyx_f[2], 997, 1, __PYX_ERR(2, 997, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.get_datetime64_value", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 1); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ __Pyx_TraceDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_TraceCall("get_timedelta64_value", __pyx_f[2], 1007, 1, __PYX_ERR(2, 1007, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.get_timedelta64_value", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 1); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ __Pyx_TraceDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_TraceCall("get_datetime64_unit", __pyx_f[2], 1014, 1, __PYX_ERR(2, 1014, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.get_datetime64_unit", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1); -+ __pyx_r = (NPY_DATETIMEUNIT) 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 1); -+ return __pyx_r; -+} - static struct __pyx_vtabstruct_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase __pyx_vtable_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase; - - static PyObject *__pyx_tp_new_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { -@@ -5909,9 +4633,9 @@ static void __pyx_tp_dealloc_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalC - { - PyObject *etype, *eval, *etb; - PyErr_Fetch(&etype, &eval, &etb); -- ++Py_REFCNT(o); -+ __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); - __pyx_pw_4cylp_2cy_26CyClpPrimalColumnPivotBase_26CyClpPrimalColumnPivotBase_3__dealloc__(o); -- --Py_REFCNT(o); -+ __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); - PyErr_Restore(etype, eval, etb); - } - Py_CLEAR(p->cyModel); -@@ -5962,7 +4686,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrima - sizeof(struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -6015,6 +4744,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrima - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -6066,23 +4801,15 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyClpPrimalColumnPivotBase, __pyx_k_CyClpPrimalColumnPivotBase, sizeof(__pyx_k_CyClpPrimalColumnPivotBase), 0, 0, 1, 1}, - {&__pyx_kp_s_CyClpPrimalColumnPivotBase_pyx_p, __pyx_k_CyClpPrimalColumnPivotBase_pyx_p, sizeof(__pyx_k_CyClpPrimalColumnPivotBase_pyx_p), 0, 0, 1, 0}, - {&__pyx_kp_s_CyClpPrimalColumnPivotBase_pyx_s, __pyx_k_CyClpPrimalColumnPivotBase_pyx_s, sizeof(__pyx_k_CyClpPrimalColumnPivotBase_pyx_s), 0, 0, 1, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -6090,15 +4817,11 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -6130,101 +4853,46 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "(tree fragment)":2 -- * def __reduce_cython__(self): -- * raise TypeError("self.CppSelf cannot be converted to a Python object for pickling") # <<<<<<<<<<<<<< -- * def __setstate_cython__(self, __pyx_state): -- * raise TypeError("self.CppSelf cannot be converted to a Python object for pickling") -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_self_CppSelf_cannot_be_converted); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 2, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "(tree fragment)":4 -- * raise TypeError("self.CppSelf cannot be converted to a Python object for pickling") -- * def __setstate_cython__(self, __pyx_state): -- * raise TypeError("self.CppSelf cannot be converted to a Python object for pickling") # <<<<<<<<<<<<<< -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_self_CppSelf_cannot_be_converted); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(0, 4, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -+ /* "(tree fragment)":2 -+ * def __reduce_cython__(self): -+ * raise TypeError("self.CppSelf cannot be converted to a Python object for pickling") # <<<<<<<<<<<<<< -+ * def __setstate_cython__(self, __pyx_state): -+ * raise TypeError("self.CppSelf cannot be converted to a Python object for pickling") - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_self_CppSelf_cannot_be_converted); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 2, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -+ /* "(tree fragment)":4 -+ * raise TypeError("self.CppSelf cannot be converted to a Python object for pickling") -+ * def __setstate_cython__(self, __pyx_state): -+ * raise TypeError("self.CppSelf cannot be converted to a Python object for pickling") # <<<<<<<<<<<<<< - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_self_CppSelf_cannot_be_converted); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(0, 4, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__10 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__10); -- __Pyx_GIVEREF(__pyx_tuple__10); -+ __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__5); -+ __Pyx_GIVEREF(__pyx_tuple__5); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__11 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__11)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__11); -- __Pyx_GIVEREF(__pyx_tuple__11); -+ __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__6); -+ __Pyx_GIVEREF(__pyx_tuple__6); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6265,6 +4933,9 @@ static int __Pyx_modinit_variable_export_code(void) { - - static int __Pyx_modinit_function_export_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); - /*--- Function export code ---*/ - if (__Pyx_ExportFunction("RunPivotColumn", (void (*)(void))__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunPivotColumn, "int (void *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -6279,6 +4950,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase = &__pyx_vtable_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase; -@@ -6309,6 +4983,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -6338,18 +5015,38 @@ static int __Pyx_modinit_type_import_code(void) { - if (!__pyx_ptype_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector) __PYX_ERR(6, 22, __pyx_L1_error) - __pyx_vtabptr_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector = (struct __pyx_vtabstruct_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector*)__Pyx_GetVtable(__pyx_ptype_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector->tp_dict); if (unlikely(!__pyx_vtabptr_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector)) __PYX_ERR(6, 22, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(7, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -6458,17 +5155,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6551,6 +5250,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyClpPrimalColumnPivotBase(PyObjec - { - __Pyx_TraceDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -6598,11 +5300,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -6639,15 +5339,15 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); -- if (unlikely(__Pyx_modinit_function_export_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_function_export_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ -@@ -6666,12 +5366,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - __Pyx_TraceReturn(Py_None, 0); - -@@ -6800,10 +5500,9 @@ static int __Pyx_TraceSetupAndCall(PyCodeObject** code, - (*frame)->f_tstate = tstate; - #endif - } -- __Pyx_PyFrame_SetLineNumber(*frame, firstlineno); -+ __Pyx_PyFrame_SetLineNumber(*frame, firstlineno); - retval = 1; -- tstate->tracing++; -- tstate->use_tracing = 0; -+ __Pyx_EnterTracing(tstate); - __Pyx_ErrFetchInState(tstate, &type, &value, &traceback); - #if CYTHON_TRACE - if (tstate->c_tracefunc) -@@ -6811,12 +5510,10 @@ static int __Pyx_TraceSetupAndCall(PyCodeObject** code, - if (retval && tstate->c_profilefunc) - #endif - retval = tstate->c_profilefunc(tstate->c_profileobj, *frame, PyTrace_CALL, NULL) == 0; -- tstate->use_tracing = (tstate->c_profilefunc || -- (CYTHON_TRACE && tstate->c_tracefunc)); -- tstate->tracing--; -+ __Pyx_LeaveTracing(tstate); - if (retval) { - __Pyx_ErrRestoreInState(tstate, type, value, traceback); -- return tstate->use_tracing && retval; -+ return __Pyx_IsTracing(tstate, 0, 0) && retval; - } else { - Py_XDECREF(type); - Py_XDECREF(value); -@@ -6974,7 +5671,7 @@ static int __Pyx_CheckKeywordStrings( - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -7149,263 +5846,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* PyCFunctionFastCall */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { -- PyCFunctionObject *func = (PyCFunctionObject*)func_obj; -- PyCFunction meth = PyCFunction_GET_FUNCTION(func); -- PyObject *self = PyCFunction_GET_SELF(func); -- int flags = PyCFunction_GET_FLAGS(func); -- assert(PyCFunction_Check(func)); -- assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); -- assert(nargs >= 0); -- assert(nargs == 0 || args != NULL); -- /* _PyCFunction_FastCallDict() must not be called with an exception set, -- because it may clear it (directly or indirectly) and so the -- caller loses its exception */ -- assert(!PyErr_Occurred()); -- if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { -- return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); -- } else { -- return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); -- } --} --#endif -- --/* PyFunctionFastCall */ --#if CYTHON_FAST_PYCALL --static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, -- PyObject *globals) { -- PyFrameObject *f; -- PyThreadState *tstate = __Pyx_PyThreadState_Current; -- PyObject **fastlocals; -- Py_ssize_t i; -- PyObject *result; -- assert(globals != NULL); -- /* XXX Perhaps we should create a specialized -- PyFrame_New() that doesn't take locals, but does -- take builtins without sanity checking them. -- */ -- assert(tstate != NULL); -- f = PyFrame_New(tstate, co, globals, NULL); -- if (f == NULL) { -- return NULL; -- } -- fastlocals = __Pyx_PyFrame_GetLocalsplus(f); -- for (i = 0; i < na; i++) { -- Py_INCREF(*args); -- fastlocals[i] = *args++; -- } -- result = PyEval_EvalFrameEx(f,0); -- ++tstate->recursion_depth; -- Py_DECREF(f); -- --tstate->recursion_depth; -- return result; --} --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { -- PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); -- PyObject *globals = PyFunction_GET_GLOBALS(func); -- PyObject *argdefs = PyFunction_GET_DEFAULTS(func); -- PyObject *closure; --#if PY_MAJOR_VERSION >= 3 -- PyObject *kwdefs; --#endif -- PyObject *kwtuple, **k; -- PyObject **d; -- Py_ssize_t nd; -- Py_ssize_t nk; -- PyObject *result; -- assert(kwargs == NULL || PyDict_Check(kwargs)); -- nk = kwargs ? PyDict_Size(kwargs) : 0; -- if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { -- return NULL; -- } -- if ( --#if PY_MAJOR_VERSION >= 3 -- co->co_kwonlyargcount == 0 && --#endif -- likely(kwargs == NULL || nk == 0) && -- co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { -- if (argdefs == NULL && co->co_argcount == nargs) { -- result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); -- goto done; -- } -- else if (nargs == 0 && argdefs != NULL -- && co->co_argcount == Py_SIZE(argdefs)) { -- /* function called with no arguments, but all parameters have -- a default value: use default values as arguments .*/ -- args = &PyTuple_GET_ITEM(argdefs, 0); -- result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); -- goto done; -- } -- } -- if (kwargs != NULL) { -- Py_ssize_t pos, i; -- kwtuple = PyTuple_New(2 * nk); -- if (kwtuple == NULL) { -- result = NULL; -- goto done; -- } -- k = &PyTuple_GET_ITEM(kwtuple, 0); -- pos = i = 0; -- while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { -- Py_INCREF(k[i]); -- Py_INCREF(k[i+1]); -- i += 2; -- } -- nk = i / 2; -- } -- else { -- kwtuple = NULL; -- k = NULL; -- } -- closure = PyFunction_GET_CLOSURE(func); --#if PY_MAJOR_VERSION >= 3 -- kwdefs = PyFunction_GET_KW_DEFAULTS(func); --#endif -- if (argdefs != NULL) { -- d = &PyTuple_GET_ITEM(argdefs, 0); -- nd = Py_SIZE(argdefs); -- } -- else { -- d = NULL; -- nd = 0; -- } --#if PY_MAJOR_VERSION >= 3 -- result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, kwdefs, closure); --#else -- result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, closure); --#endif -- Py_XDECREF(kwtuple); --done: -- Py_LeaveRecursiveCall(); -- return result; --} --#endif --#endif -- --/* PyObjectCallMethO */ --#if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { -- PyObject *self, *result; -- PyCFunction cfunc; -- cfunc = PyCFunction_GET_FUNCTION(func); -- self = PyCFunction_GET_SELF(func); -- if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -- return NULL; -- result = cfunc(self, arg); -- Py_LeaveRecursiveCall(); -- if (unlikely(!result) && unlikely(!PyErr_Occurred())) { -- PyErr_SetString( -- PyExc_SystemError, -- "NULL result without error in PyObject_Call"); -- } -- return result; --} --#endif -- --/* PyObjectCallOneArg */ --#if CYTHON_COMPILING_IN_CPYTHON --static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_New(1); -- if (unlikely(!args)) return NULL; -- Py_INCREF(arg); -- PyTuple_SET_ITEM(args, 0, arg); -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { --#if CYTHON_FAST_PYCALL -- if (PyFunction_Check(func)) { -- return __Pyx_PyFunction_FastCall(func, &arg, 1); -- } --#endif -- if (likely(PyCFunction_Check(func))) { -- if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { -- return __Pyx_PyObject_CallMethO(func, arg); --#if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -- return __Pyx_PyCFunction_FastCall(func, &arg, 1); --#endif -- } -- } -- return __Pyx__PyObject_CallOneArg(func, arg); --} --#else --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_Pack(1, arg); -- if (unlikely(!args)) return NULL; -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --#endif -- --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -7629,6 +6069,28 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable) { - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -7656,43 +6118,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -7814,7 +6284,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -7844,7 +6314,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -7918,7 +6388,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -7941,30 +6411,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -7983,11 +6454,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -8041,37 +6517,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - return (target_type) value;\ - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- - /* Declarations */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus -@@ -8189,7 +6634,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -8344,7 +6788,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -8382,40 +6825,16 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - #endif - #endif - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -8602,9 +7021,54 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - return (int) -1; - } - -+/* CIntToPy */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(int) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); -+ } -+} -+ - /* CIntToPy */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { -@@ -8635,7 +7099,14 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { - - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -9223,6 +7694,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyClpSimplex.cpp b/cylp/cy/CyClpSimplex.cpp -index 8acc740..4a84cb1 100644 ---- a/cylp/cy/CyClpSimplex.cpp -+++ b/cylp/cy/CyClpSimplex.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.21 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_21" --#define CYTHON_HEX_VERSION 0x001D15F0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -450,7 +517,11 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) - #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif - #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) - #endif -@@ -556,10 +627,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) -@@ -627,7 +698,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "ClpFactorization.hpp" - #include "IClpPrimalColumnPivotBase.h" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ClpDualRowPivot.hpp" - #include "IClpDualRowPivotBase.h" - #include "CoinModel.hpp" -@@ -655,11 +732,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "OsiSolverInterface.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "IClpSimplex.hpp" - #include "ICoinMpsIO.hpp" -@@ -759,6 +836,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -951,7 +1029,7 @@ typedef struct { - } __Pyx_BufFmt_Context; - - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":775 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -960,7 +1038,7 @@ typedef struct { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -969,7 +1047,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -978,7 +1056,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -987,7 +1065,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":782 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -996,7 +1074,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -1005,7 +1083,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -1014,7 +1092,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -1023,7 +1101,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":789 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -1032,7 +1110,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -1041,7 +1119,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":799 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -1050,7 +1128,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1059,7 +1137,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1068,7 +1146,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":803 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1077,7 +1155,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1086,7 +1164,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1095,7 +1173,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":807 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1104,7 +1182,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1113,7 +1191,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":810 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1122,7 +1200,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1131,7 +1209,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1198,7 +1276,7 @@ struct __pyx_obj_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO; - struct __pyx_obj_4cylp_2cy_12CyClpSimplex_CyClpSimplex; - struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":814 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1207,7 +1285,7 @@ struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1216,7 +1294,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1225,7 +1303,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":818 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -2082,11 +2160,45 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define CYTHON_FRAME_DEL(frame) Py_CLEAR(frame) - #endif - #define __Pyx_TraceDeclarations\ -- static PyCodeObject *__pyx_frame_code = NULL;\ -- CYTHON_FRAME_MODIFIER PyFrameObject *__pyx_frame = NULL;\ -- int __Pyx_use_tracing = 0; -+ static PyCodeObject *__pyx_frame_code = NULL;\ -+ CYTHON_FRAME_MODIFIER PyFrameObject *__pyx_frame = NULL;\ -+ int __Pyx_use_tracing = 0; - #define __Pyx_TraceFrameInit(codeobj)\ -- if (codeobj) __pyx_frame_code = (PyCodeObject*) codeobj; -+ if (codeobj) __pyx_frame_code = (PyCodeObject*) codeobj; -+#if PY_VERSION_HEX >= 0x030b00a2 -+ #define __Pyx_IsTracing(tstate, check_tracing, check_funcs)\ -+ (unlikely((tstate)->cframe->use_tracing) &&\ -+ (!(check_tracing) || !(tstate)->tracing) &&\ -+ (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc))) -+ #define __Pyx_EnterTracing(tstate) PyThreadState_EnterTracing(tstate) -+ #define __Pyx_LeaveTracing(tstate) PyThreadState_LeaveTracing(tstate) -+#elif PY_VERSION_HEX >= 0x030a00b1 -+ #define __Pyx_IsTracing(tstate, check_tracing, check_funcs)\ -+ (unlikely((tstate)->cframe->use_tracing) &&\ -+ (!(check_tracing) || !(tstate)->tracing) &&\ -+ (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc))) -+ #define __Pyx_EnterTracing(tstate)\ -+ do { tstate->tracing++; tstate->cframe->use_tracing = 0; } while (0) -+ #define __Pyx_LeaveTracing(tstate)\ -+ do {\ -+ tstate->tracing--;\ -+ tstate->cframe->use_tracing = ((CYTHON_TRACE && tstate->c_tracefunc != NULL)\ -+ || tstate->c_profilefunc != NULL);\ -+ } while (0) -+#else -+ #define __Pyx_IsTracing(tstate, check_tracing, check_funcs)\ -+ (unlikely((tstate)->use_tracing) &&\ -+ (!(check_tracing) || !(tstate)->tracing) &&\ -+ (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc))) -+ #define __Pyx_EnterTracing(tstate)\ -+ do { tstate->tracing++; tstate->use_tracing = 0; } while (0) -+ #define __Pyx_LeaveTracing(tstate)\ -+ do {\ -+ tstate->tracing--;\ -+ tstate->use_tracing = ((CYTHON_TRACE && tstate->c_tracefunc != NULL)\ -+ || tstate->c_profilefunc != NULL);\ -+ } while (0) -+#endif - #ifdef WITH_THREAD - #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error)\ - if (nogil) {\ -@@ -2094,8 +2206,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyThreadState *tstate;\ - PyGILState_STATE state = PyGILState_Ensure();\ - tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing) && !tstate->tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -+ if (__Pyx_IsTracing(tstate, 1, 1)) {\ - __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&__pyx_frame_code, &__pyx_frame, tstate, funcname, srcfile, firstlineno);\ - }\ - PyGILState_Release(state);\ -@@ -2103,8 +2214,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - }\ - } else {\ - PyThreadState* tstate = PyThreadState_GET();\ -- if (unlikely(tstate->use_tracing) && !tstate->tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -+ if (__Pyx_IsTracing(tstate, 1, 1)) {\ - __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&__pyx_frame_code, &__pyx_frame, tstate, funcname, srcfile, firstlineno);\ - if (unlikely(__Pyx_use_tracing < 0)) goto_error;\ - }\ -@@ -2112,8 +2222,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #else - #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error)\ - { PyThreadState* tstate = PyThreadState_GET();\ -- if (unlikely(tstate->use_tracing) && !tstate->tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -+ if (__Pyx_IsTracing(tstate, 1, 1)) {\ - __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&__pyx_frame_code, &__pyx_frame, tstate, funcname, srcfile, firstlineno);\ - if (unlikely(__Pyx_use_tracing < 0)) goto_error;\ - }\ -@@ -2122,10 +2231,8 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define __Pyx_TraceException()\ - if (likely(!__Pyx_use_tracing)); else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing &&\ -- (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc))) {\ -- tstate->tracing++;\ -- tstate->use_tracing = 0;\ -+ if (__Pyx_IsTracing(tstate, 0, 1)) {\ -+ __Pyx_EnterTracing(tstate);\ - PyObject *exc_info = __Pyx_GetExceptionTuple(tstate);\ - if (exc_info) {\ - if (CYTHON_TRACE && tstate->c_tracefunc)\ -@@ -2135,22 +2242,19 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - tstate->c_profileobj, __pyx_frame, PyTrace_EXCEPTION, exc_info);\ - Py_DECREF(exc_info);\ - }\ -- tstate->use_tracing = 1;\ -- tstate->tracing--;\ -+ __Pyx_LeaveTracing(tstate);\ - }\ - } - static void __Pyx_call_return_trace_func(PyThreadState *tstate, PyFrameObject *frame, PyObject *result) { - PyObject *type, *value, *traceback; - __Pyx_ErrFetchInState(tstate, &type, &value, &traceback); -- tstate->tracing++; -- tstate->use_tracing = 0; -+ __Pyx_EnterTracing(tstate); - if (CYTHON_TRACE && tstate->c_tracefunc) - tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_RETURN, result); - if (tstate->c_profilefunc) - tstate->c_profilefunc(tstate->c_profileobj, frame, PyTrace_RETURN, result); - CYTHON_FRAME_DEL(frame); -- tstate->use_tracing = 1; -- tstate->tracing--; -+ __Pyx_LeaveTracing(tstate); - __Pyx_ErrRestoreInState(tstate, type, value, traceback); - } - #ifdef WITH_THREAD -@@ -2161,14 +2265,14 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyThreadState *tstate;\ - PyGILState_STATE state = PyGILState_Ensure();\ - tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0)) {\ - __Pyx_call_return_trace_func(tstate, __pyx_frame, (PyObject*)result);\ - }\ - PyGILState_Release(state);\ - }\ - } else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0)) {\ - __Pyx_call_return_trace_func(tstate, __pyx_frame, (PyObject*)result);\ - }\ - }\ -@@ -2177,7 +2281,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define __Pyx_TraceReturn(result, nogil)\ - if (likely(!__Pyx_use_tracing)); else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (tstate->use_tracing) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0)) {\ - __Pyx_call_return_trace_func(tstate, __pyx_frame, (PyObject*)result);\ - }\ - } -@@ -2197,11 +2301,9 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyObject *type, *value, *traceback; - __Pyx_ErrFetchInState(tstate, &type, &value, &traceback); - __Pyx_PyFrame_SetLineNumber(frame, lineno); -- tstate->tracing++; -- tstate->use_tracing = 0; -+ __Pyx_EnterTracing(tstate); - ret = tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_LINE, NULL); -- tstate->use_tracing = 1; -- tstate->tracing--; -+ __Pyx_LeaveTracing(tstate); - if (likely(!ret)) { - __Pyx_ErrRestoreInState(tstate, type, value, traceback); - } else { -@@ -2220,7 +2322,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - PyThreadState *tstate;\ - PyGILState_STATE state = PyGILState_Ensure();\ - tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing && tstate->c_tracefunc && __pyx_frame->f_trace)) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && __pyx_frame->f_trace) {\ - ret = __Pyx_call_line_trace_func(tstate, __pyx_frame, lineno);\ - }\ - PyGILState_Release(state);\ -@@ -2228,7 +2330,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - }\ - } else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing && tstate->c_tracefunc && __pyx_frame->f_trace)) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && __pyx_frame->f_trace) {\ - int ret = __Pyx_call_line_trace_func(tstate, __pyx_frame, lineno);\ - if (unlikely(ret)) goto_error;\ - }\ -@@ -2238,7 +2340,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #define __Pyx_TraceLine(lineno, nogil, goto_error)\ - if (likely(!__Pyx_use_tracing)); else {\ - PyThreadState* tstate = __Pyx_PyThreadState_Current;\ -- if (unlikely(tstate->use_tracing && tstate->c_tracefunc && __pyx_frame->f_trace)) {\ -+ if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && __pyx_frame->f_trace) {\ - int ret = __Pyx_call_line_trace_func(tstate, __pyx_frame, lineno);\ - if (unlikely(ret)) goto_error;\ - }\ -@@ -2262,6 +2364,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -2269,6 +2372,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -2582,9 +2686,6 @@ static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject * - /* HasAttr.proto */ - static CYTHON_INLINE int __Pyx_HasAttr(PyObject *, PyObject *); - --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- - /* PyObject_GenericGetAttrNoDict.proto */ - #if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 - static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); -@@ -2675,18 +2776,14 @@ typedef struct { - #endif - - -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif -+ - /* None.proto */ - static CYTHON_INLINE long __Pyx_pow_long(long, long); - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__IClpSimplex_3a__3a_Status(enum IClpSimplex::Status value); -- - /* RealImag.proto */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus -@@ -2785,18 +2882,24 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__IClpSimplex_3a__3a_Status( - #endif - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); - -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -+ - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+ - /* CIntFromPy.proto */ - static CYTHON_INLINE size_t __Pyx_PyInt_As_size_t(PyObject *); - -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__IClpSimplex_3a__3a_Status(enum IClpSimplex::Status value); -+ - /* CIntFromPy.proto */ - static CYTHON_INLINE enum IClpSimplex::Status __Pyx_PyInt_As_enum__IClpSimplex_3a__3a_Status(PyObject *); - -@@ -2948,8 +3051,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void); /*proto*/ - - /* Module declarations from 'cylp.cy.CyClpDualRowPivotBase' */ -@@ -3031,8 +3143,6 @@ static PyObject *__pyx_builtin_xrange; - static PyObject *__pyx_builtin_range; - static PyObject *__pyx_builtin_print; - static PyObject *__pyx_builtin_open; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_RuntimeError; - static const char __pyx_k_A[] = "A"; - static const char __pyx_k_B[] = "B"; - static const char __pyx_k_D[] = "D"; -@@ -3210,7 +3320,6 @@ static const char __pyx_k_pyx_state[] = "__pyx_state"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; - static const char __pyx_k_rowStarts[] = "rowStarts"; - static const char __pyx_k_variables[] = "variables"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_constIndex[] = "constIndex"; - static const char __pyx_k_coo_matrix[] = "coo_matrix"; - static const char __pyx_k_filterVars[] = "filterVars"; -@@ -3239,7 +3348,6 @@ static const char __pyx_k_setRowUpper[] = "setRowUpper"; - static const char __pyx_k_useRowNames[] = "useRowNames"; - static const char __pyx_k_CyClpSimplex[] = "CyClpSimplex"; - static const char __pyx_k_CyLPSolution[] = "CyLPSolution"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_atLowerBound[] = "atLowerBound"; - static const char __pyx_k_atUpperBound[] = "atUpperBound"; - static const char __pyx_k_columnStarts[] = "columnStarts"; -@@ -3338,7 +3446,6 @@ static const char __pyx_k_unrecognised_extension_s[] = "unrecognised extension % - static const char __pyx_k_No_CyClpSimplex_cyLPModel[] = "No CyClpSimplex cyLPModel."; - static const char __pyx_k_cylp_py_modeling_CyLPModel[] = "cylp.py.modeling.CyLPModel"; - static const char __pyx_k_CyClpSimplex_dual_line_1577[] = "CyClpSimplex.dual (line 1577)"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_setColumnLowerFirstElements[] = "setColumnLowerFirstElements"; - static const char __pyx_k_setColumnUpperFirstElements[] = "setColumnUpperFirstElements"; - static const char __pyx_k_stopped_on_iterations_or_time[] = "stopped on iterations or time"; -@@ -3355,7 +3462,6 @@ static const char __pyx_k_To_remove_a_constraint_you_must[] = "To remove a const - static const char __pyx_k_dualPivotMethodObject_should_be[] = "dualPivotMethodObject should be of a class derived from DualPivotPythonBase"; - static const char __pyx_k_if_arg_is_an_integer_mark_varia[] = "\n if ``arg`` is an integer: mark variable index ``arg`` as integer.\n if ``arg`` is a :class:`CyLPVar` object: mark variable\n ``arg`` as integer. Here is an example of the latter:\n\n >>> import numpy as np\n >>> from cylp.cy import CyClpSimplex\n >>> from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray\n >>> model = CyLPModel()\n >>>\n >>> x = model.addVariable('x', 3)\n >>> y = model.addVariable('y', 2)\n >>>\n >>> A = np.matrix([[1., 2., 0],[1., 0, 1.]])\n >>> B = np.matrix([[1., 0, 0], [0, 0, 1.]])\n >>> D = np.matrix([[1., 2.],[0, 1]])\n >>> a = CyLPArray([5, 2.5])\n >>> b = CyLPArray([4.2, 3])\n >>> x_u= CyLPArray([2., 3.5])\n >>>\n >>> model += A*x <= a\n >>> model += 2 <= B * x + D * y <= b\n >>> model += y >= 0\n >>> model += 1.1 <= x[1:3] <= x_u\n >>>\n >>> c = CyLPArray([1., -2., 3.])\n >>> model.objective = c * x + 2 * y.sum()\n >>>\n >>>\n >>> s = CyClpSimplex(model)\n >>> s.setInteger(x[1:3])\n >>>\n >>> cbcModel = s.getCbcModel()\n >>> cbcModel.solve()\n 0\n >>> print(cbcModel.status)\n 'solution'\n >>>\n >>> sol_x = cbcModel.primalVariableSolution['x']\n >>> (abs(sol_x -\n ... np.array([0.5, 2, 2]) ) <= 10**-6).all()\n True\n >>> sol_y = cbcModel.primalVariableSolution['y']\n >>> (abs(sol_y -\n ... np.array([0, 0.75]) ) <= 10**-6).all()\n True\n\n "; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; - static const char __pyx_k_CyClpPrimalColumnPivotBase_pyx_p[] = "CyClpPrimalColumnPivotBase.pyx: pivot column should be implemented."; - static const char __pyx_k_CyClpSimplex_initialDualSolve_li[] = "CyClpSimplex.initialDualSolve (line 1274)"; - static const char __pyx_k_CyClpSimplex_initialSolve_line_1[] = "CyClpSimplex.initialSolve (line 1233)"; -@@ -3368,11 +3474,9 @@ static const char __pyx_k_CyClpSimplex_setConstraintStatus[] = "CyClpSimplex.set - static const char __pyx_k_CyClpSimplex_setInteger_line_167[] = "CyClpSimplex.setInteger (line 1678)"; - static const char __pyx_k_CyClpSimplex_setVariableStatus_l[] = "CyClpSimplex.setVariableStatus (line 1006)"; - static const char __pyx_k_Expected_a_CyLPModel_as_an_argum[] = "Expected a CyLPModel as an argument to cylpSimplex constructor. Got %s"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; - static const char __pyx_k_Hessian_can_be_set_to_a_matrix_t[] = "Hessian can be set to a matrix that implements *tocoo* method"; - static const char __pyx_k_Incompatible_checksums_s_vs_0xd4[] = "Incompatible checksums (%s vs 0xd41d8cd = ())"; - static const char __pyx_k_No_write_access_for_s_or_an_inte[] = "No write access for %s or an intermediate directory does not exist."; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; - static const char __pyx_k_Presolve_says_problem_infeasible[] = "Presolve says problem infeasible."; - static const char __pyx_k_The_argument_of_getVarStatus_can[] = "The argument of getVarStatus can be a CyLPVar only if the object is built using a CyLPModel."; - static const char __pyx_k_The_argument_of_setInteger_can_b[] = "The argument of setInteger can be a CyLPVar only if the object is built using a CyLPModel."; -@@ -3383,13 +3487,11 @@ static const char __pyx_k_To_set_the_objective_function_of[] = "To set the objec - static const char __pyx_k_Variables_should_have_the_same_d[] = "Variables should have the same dimensions to be complements. Got %s: %g and %s: %g"; - static const char __pyx_k_coefMatrix_must_be_a_scipy_spars[] = "coefMatrix must be a scipy sparse matrix."; - static const char __pyx_k_cylp_py_pivots_DualPivotPythonBa[] = "cylp.py.pivots.DualPivotPythonBase"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_pivotMethodObject_should_be_of_a[] = "pivotMethodObject should be of a class derived from PivotPythonBase"; - static const char __pyx_k_stopped_by_event_handler_virtual[] = "stopped by event handler (virtual int ClpEventHandler::event())"; - static const char __pyx_k_Run_CLP_s_initalPrimalSolve_The_2[] = "\n Run CLP's initalPrimalSolve. The same as :func:`initalSolve` but force\n the use of dual Simplex.\n\n **Usage example**\n\n >>> from cylp.cy.CyClpSimplex import CyClpSimplex, getMpsExample\n >>> s = CyClpSimplex()\n >>> f = getMpsExample()\n >>> s.readMps(f)\n 0\n >>> s.initialDualSolve()\n 'optimal'\n >>> round(s.objectiveValue, 4)\n 2520.5717\n\n "; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_A; - static PyObject *__pyx_n_s_B; - static PyObject *__pyx_n_s_CLP_deleteConstraints; -@@ -3417,8 +3519,6 @@ static PyObject *__pyx_n_s_CyLPVar; - static PyObject *__pyx_n_s_D; - static PyObject *__pyx_n_s_DualPivotPythonBase; - static PyObject *__pyx_kp_s_Expected_a_CyLPModel_as_an_argum; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_Hessian; - static PyObject *__pyx_kp_s_Hessian_can_be_set_to_a_matrix_t; - static PyObject *__pyx_n_s_ImportError; -@@ -3429,7 +3529,6 @@ static PyObject *__pyx_kp_s_No_cylpSimplex_cyLPModel_is_set; - static PyObject *__pyx_kp_s_No_such_constraint_s; - static PyObject *__pyx_kp_s_No_such_variable_s; - static PyObject *__pyx_kp_s_No_write_access_for_s_or_an_inte; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; - static PyObject *__pyx_n_s_PickleError; - static PyObject *__pyx_n_s_PivotPythonBase; - static PyObject *__pyx_kp_s_Presolve_says_problem_infeasible; -@@ -3437,7 +3536,6 @@ static PyObject *__pyx_kp_u_Run_CLP_s_initalPrimalSolve_The; - static PyObject *__pyx_kp_u_Run_CLP_s_initalPrimalSolve_The_2; - static PyObject *__pyx_kp_u_Run_CLP_s_initialSolve_It_does; - static PyObject *__pyx_kp_u_Runs_CLP_dual_simplex_Usage_Exa; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_kp_u_Set_the_coefficient_matrix_cons; - static PyObject *__pyx_kp_u_Set_the_status_of_a_constraint; - static PyObject *__pyx_kp_u_Set_the_status_of_a_variable_ar; -@@ -3450,7 +3548,6 @@ static PyObject *__pyx_kp_s_To_remove_a_constraint_you_must; - static PyObject *__pyx_kp_s_To_remove_a_variable_you_must_se; - static PyObject *__pyx_kp_s_To_set_the_objective_function_of; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_VarStatus; - static PyObject *__pyx_kp_s_Variables_should_have_the_same_d; - static PyObject *__pyx_kp_s__8; -@@ -3604,8 +3701,6 @@ static PyObject *__pyx_n_s_nVars; - static PyObject *__pyx_n_s_name; - static PyObject *__pyx_n_s_name_2; - static PyObject *__pyx_n_s_ncol; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_n_s_new; - static PyObject *__pyx_n_s_newNumberColumns; - static PyObject *__pyx_n_s_newNumberRows; -@@ -3713,7 +3808,6 @@ static PyObject *__pyx_n_s_test; - static PyObject *__pyx_n_s_toarray; - static PyObject *__pyx_n_s_tocoo; - static PyObject *__pyx_n_s_tryPlusMinusOne; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_kp_s_unrecognised_extension_s; - static PyObject *__pyx_n_s_update; - static PyObject *__pyx_n_s_updateStatus; -@@ -3942,8 +4036,6 @@ static PyObject *__pyx_pf_4cylp_2cy_12CyClpSimplex_4getMpsExample(CYTHON_UNUSED - static PyObject *__pyx_pf_4cylp_2cy_12CyClpSimplex_9VarStatus___reduce_cython__(struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_12CyClpSimplex_9VarStatus_2__setstate_cython__(struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus *__pyx_v_self, PyObject *__pyx_v___pyx_state); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_12CyClpSimplex_6__pyx_unpickle_VarStatus(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_12CyClpSimplex_CyClpSimplex(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tp_new_4cylp_2cy_12CyClpSimplex_VarStatus(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_float_0_; -@@ -3998,11 +4090,6 @@ static PyObject *__pyx_tuple__30; - static PyObject *__pyx_tuple__31; - static PyObject *__pyx_tuple__32; - static PyObject *__pyx_tuple__33; --static PyObject *__pyx_tuple__34; --static PyObject *__pyx_tuple__35; --static PyObject *__pyx_tuple__36; --static PyObject *__pyx_tuple__37; --static PyObject *__pyx_tuple__38; - static PyObject *__pyx_codeobj__23; - static PyObject *__pyx_codeobj__27; - static PyObject *__pyx_codeobj__28; -@@ -37604,879 +37691,7 @@ static PyObject *__pyx_f_4cylp_2cy_12CyClpSimplex___pyx_unpickle_VarStatus__set_ - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- __Pyx_TraceCall("__getbuffer__", __pyx_f[2], 258, 0, __PYX_ERR(2, 258, __pyx_L1_error)); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * -- * ndim = PyArray_NDIM(self) -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":271 -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__29, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":275 -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__30, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":279 -- * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -- * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -- * -- * cdef int t -- */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -- * -- */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -- * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__31, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_TraceReturn(Py_None, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- __Pyx_TraceCall("__releasebuffer__", __pyx_f[2], 337, 0, __PYX_ERR(2, 337, __pyx_L1_error)); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_WriteUnraisable("numpy.ndarray.__releasebuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0); -- __pyx_L0:; -- __Pyx_TraceReturn(Py_None, 0); -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":820 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -38493,9 +37708,9 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew1", __pyx_f[2], 820, 0, __PYX_ERR(2, 820, __pyx_L1_error)); -+ __Pyx_TraceCall("PyArray_MultiIterNew1", __pyx_f[2], 735, 0, __PYX_ERR(2, 735, __pyx_L1_error)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * - * cdef inline object PyArray_MultiIterNew1(a): - * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -@@ -38503,13 +37718,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - * cdef inline object PyArray_MultiIterNew2(a, b): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 821, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":820 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -38529,7 +37744,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":823 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -38546,9 +37761,9 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew2", __pyx_f[2], 823, 0, __PYX_ERR(2, 823, __pyx_L1_error)); -+ __Pyx_TraceCall("PyArray_MultiIterNew2", __pyx_f[2], 738, 0, __PYX_ERR(2, 738, __pyx_L1_error)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * - * cdef inline object PyArray_MultiIterNew2(a, b): - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -@@ -38556,13 +37771,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 824, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":823 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -38582,7 +37797,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":826 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -38599,9 +37814,9 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew3", __pyx_f[2], 826, 0, __PYX_ERR(2, 826, __pyx_L1_error)); -+ __Pyx_TraceCall("PyArray_MultiIterNew3", __pyx_f[2], 741, 0, __PYX_ERR(2, 741, __pyx_L1_error)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -@@ -38609,13 +37824,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 827, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":826 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -38635,7 +37850,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":829 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -38652,9 +37867,9 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew4", __pyx_f[2], 829, 0, __PYX_ERR(2, 829, __pyx_L1_error)); -+ __Pyx_TraceCall("PyArray_MultiIterNew4", __pyx_f[2], 744, 0, __PYX_ERR(2, 744, __pyx_L1_error)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -@@ -38662,13 +37877,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 830, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":829 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -38688,7 +37903,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":832 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -38705,9 +37920,9 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -- __Pyx_TraceCall("PyArray_MultiIterNew5", __pyx_f[2], 832, 0, __PYX_ERR(2, 832, __pyx_L1_error)); -+ __Pyx_TraceCall("PyArray_MultiIterNew5", __pyx_f[2], 747, 0, __PYX_ERR(2, 747, __pyx_L1_error)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -@@ -38715,13 +37930,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - * cdef inline tuple PyDataType_SHAPE(dtype d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 833, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":832 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -38741,7 +37956,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":835 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -38758,9 +37973,9 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); -- __Pyx_TraceCall("PyDataType_SHAPE", __pyx_f[2], 835, 0, __PYX_ERR(2, 835, __pyx_L1_error)); -+ __Pyx_TraceCall("PyDataType_SHAPE", __pyx_f[2], 750, 0, __PYX_ERR(2, 750, __pyx_L1_error)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -38770,7 +37985,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); - if (__pyx_t_1) { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): - * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -@@ -38782,7 +37997,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -38791,12 +38006,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - */ - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":839 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 - * return <tuple>d.subarray.shape - * else: - * return () # <<<<<<<<<<<<<< - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -+ * - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); -@@ -38805,7 +38020,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - goto __pyx_L0; - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":835 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -38824,759 +38039,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":841 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_TraceDeclarations -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- __Pyx_TraceCall("_util_dtypestring", __pyx_f[2], 841, 0, __PYX_ERR(2, 841, __pyx_L1_error)); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":846 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":850 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 850, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 850, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 850, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 852, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":854 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 854, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 854, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 854, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__32, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 855, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":854 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":857 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":857 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__31, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 859, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 859, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":857 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":869 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 869, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 869, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 869, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":874 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":876 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 877, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__33, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 879, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 879, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":882 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 882, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 882, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 882, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":900 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 900, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 900, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 900, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":876 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- goto __pyx_L13; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":905 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -- */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 905, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":850 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -- * -- * -- */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":841 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -- __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_TraceReturn(Py_None, 0); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1021 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -39591,9 +38054,9 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("set_array_base", 0); -- __Pyx_TraceCall("set_array_base", __pyx_f[2], 1021, 0, __PYX_ERR(2, 1021, __pyx_L1_error)); -+ __Pyx_TraceCall("set_array_base", __pyx_f[2], 929, 0, __PYX_ERR(2, 929, __pyx_L1_error)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -39602,7 +38065,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -39611,7 +38074,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1021 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -39628,7 +38091,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1025 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -39646,9 +38109,9 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("get_array_base", 0); -- __Pyx_TraceCall("get_array_base", __pyx_f[2], 1025, 0, __PYX_ERR(2, 1025, __pyx_L1_error)); -+ __Pyx_TraceCall("get_array_base", __pyx_f[2], 933, 0, __PYX_ERR(2, 933, __pyx_L1_error)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -39657,7 +38120,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -39667,7 +38130,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -39678,7 +38141,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -39687,7 +38150,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -39699,7 +38162,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1025 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -39718,12 +38181,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1033 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -39742,13 +38205,13 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); -- __Pyx_TraceCall("import_array", __pyx_f[2], 1033, 0, __PYX_ERR(2, 1033, __pyx_L1_error)); -+ __Pyx_TraceCall("import_array", __pyx_f[2], 941, 0, __PYX_ERR(2, 941, __pyx_L1_error)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -39760,20 +38223,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1035, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -39783,9 +38246,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -39793,32 +38256,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1036, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__34, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__29, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -39829,12 +38292,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1033 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -39853,7 +38316,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1039 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -39877,9 +38340,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); -- __Pyx_TraceCall("import_umath", __pyx_f[2], 1039, 0, __PYX_ERR(2, 1039, __pyx_L1_error)); -+ __Pyx_TraceCall("import_umath", __pyx_f[2], 947, 0, __PYX_ERR(2, 947, __pyx_L1_error)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -39895,16 +38358,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1041, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -39918,7 +38381,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -39928,28 +38391,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1042, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__35, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__30, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -39964,7 +38427,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1039 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -39988,7 +38451,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1045 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -40012,9 +38475,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); -- __Pyx_TraceCall("import_ufunc", __pyx_f[2], 1045, 0, __PYX_ERR(2, 1045, __pyx_L1_error)); -+ __Pyx_TraceCall("import_ufunc", __pyx_f[2], 953, 0, __PYX_ERR(2, 953, __pyx_L1_error)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -40030,16 +38493,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1047, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -40053,35 +38516,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1048, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__35, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__30, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -40096,7 +38562,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1045 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -40119,6 +38585,225 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ __Pyx_TraceCall("is_timedelta64_object", __pyx_f[2], 967, 0, __PYX_ERR(2, 967, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.is_timedelta64_object", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_TraceDeclarations -+ __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ __Pyx_TraceCall("is_datetime64_object", __pyx_f[2], 982, 0, __PYX_ERR(2, 982, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.is_datetime64_object", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 0); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ __Pyx_TraceDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_TraceCall("get_datetime64_value", __pyx_f[2], 997, 1, __PYX_ERR(2, 997, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.get_datetime64_value", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 1); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ __Pyx_TraceDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_TraceCall("get_timedelta64_value", __pyx_f[2], 1007, 1, __PYX_ERR(2, 1007, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.get_timedelta64_value", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 1); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ __Pyx_TraceDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_TraceCall("get_datetime64_unit", __pyx_f[2], 1014, 1, __PYX_ERR(2, 1014, __pyx_L1_error)); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_WriteUnraisable("numpy.get_datetime64_unit", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1); -+ __pyx_r = (NPY_DATETIMEUNIT) 0; -+ __pyx_L0:; -+ __Pyx_TraceReturn(Py_None, 1); -+ return __pyx_r; -+} - static struct __pyx_vtabstruct_4cylp_2cy_12CyClpSimplex_CyClpSimplex __pyx_vtable_4cylp_2cy_12CyClpSimplex_CyClpSimplex; - - static PyObject *__pyx_tp_new_4cylp_2cy_12CyClpSimplex_CyClpSimplex(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -40976,6 +39661,9 @@ static PyTypeObject __pyx_type_4cylp_2cy_12CyClpSimplex_CyClpSimplex = { - #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 - 0, /*tp_print*/ - #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyObject *__pyx_tp_new_4cylp_2cy_12CyClpSimplex_VarStatus(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { -@@ -41071,6 +39759,9 @@ static PyTypeObject __pyx_type_4cylp_2cy_12CyClpSimplex_VarStatus = { - #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 - 0, /*tp_print*/ - #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -41147,8 +39838,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_D, __pyx_k_D, sizeof(__pyx_k_D), 0, 0, 1, 1}, - {&__pyx_n_s_DualPivotPythonBase, __pyx_k_DualPivotPythonBase, sizeof(__pyx_k_DualPivotPythonBase), 0, 0, 1, 1}, - {&__pyx_kp_s_Expected_a_CyLPModel_as_an_argum, __pyx_k_Expected_a_CyLPModel_as_an_argum, sizeof(__pyx_k_Expected_a_CyLPModel_as_an_argum), 0, 0, 1, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_Hessian, __pyx_k_Hessian, sizeof(__pyx_k_Hessian), 0, 0, 1, 1}, - {&__pyx_kp_s_Hessian_can_be_set_to_a_matrix_t, __pyx_k_Hessian_can_be_set_to_a_matrix_t, sizeof(__pyx_k_Hessian_can_be_set_to_a_matrix_t), 0, 0, 1, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -@@ -41159,7 +39848,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_kp_s_No_such_constraint_s, __pyx_k_No_such_constraint_s, sizeof(__pyx_k_No_such_constraint_s), 0, 0, 1, 0}, - {&__pyx_kp_s_No_such_variable_s, __pyx_k_No_such_variable_s, sizeof(__pyx_k_No_such_variable_s), 0, 0, 1, 0}, - {&__pyx_kp_s_No_write_access_for_s_or_an_inte, __pyx_k_No_write_access_for_s_or_an_inte, sizeof(__pyx_k_No_write_access_for_s_or_an_inte), 0, 0, 1, 0}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, - {&__pyx_n_s_PickleError, __pyx_k_PickleError, sizeof(__pyx_k_PickleError), 0, 0, 1, 1}, - {&__pyx_n_s_PivotPythonBase, __pyx_k_PivotPythonBase, sizeof(__pyx_k_PivotPythonBase), 0, 0, 1, 1}, - {&__pyx_kp_s_Presolve_says_problem_infeasible, __pyx_k_Presolve_says_problem_infeasible, sizeof(__pyx_k_Presolve_says_problem_infeasible), 0, 0, 1, 0}, -@@ -41167,7 +39855,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_kp_u_Run_CLP_s_initalPrimalSolve_The_2, __pyx_k_Run_CLP_s_initalPrimalSolve_The_2, sizeof(__pyx_k_Run_CLP_s_initalPrimalSolve_The_2), 0, 1, 0, 0}, - {&__pyx_kp_u_Run_CLP_s_initialSolve_It_does, __pyx_k_Run_CLP_s_initialSolve_It_does, sizeof(__pyx_k_Run_CLP_s_initialSolve_It_does), 0, 1, 0, 0}, - {&__pyx_kp_u_Runs_CLP_dual_simplex_Usage_Exa, __pyx_k_Runs_CLP_dual_simplex_Usage_Exa, sizeof(__pyx_k_Runs_CLP_dual_simplex_Usage_Exa), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_kp_u_Set_the_coefficient_matrix_cons, __pyx_k_Set_the_coefficient_matrix_cons, sizeof(__pyx_k_Set_the_coefficient_matrix_cons), 0, 1, 0, 0}, - {&__pyx_kp_u_Set_the_status_of_a_constraint, __pyx_k_Set_the_status_of_a_constraint, sizeof(__pyx_k_Set_the_status_of_a_constraint), 0, 1, 0, 0}, - {&__pyx_kp_u_Set_the_status_of_a_variable_ar, __pyx_k_Set_the_status_of_a_variable_ar, sizeof(__pyx_k_Set_the_status_of_a_variable_ar), 0, 1, 0, 0}, -@@ -41180,7 +39867,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_kp_s_To_remove_a_variable_you_must_se, __pyx_k_To_remove_a_variable_you_must_se, sizeof(__pyx_k_To_remove_a_variable_you_must_se), 0, 0, 1, 0}, - {&__pyx_kp_s_To_set_the_objective_function_of, __pyx_k_To_set_the_objective_function_of, sizeof(__pyx_k_To_set_the_objective_function_of), 0, 0, 1, 0}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_VarStatus, __pyx_k_VarStatus, sizeof(__pyx_k_VarStatus), 0, 0, 1, 1}, - {&__pyx_kp_s_Variables_should_have_the_same_d, __pyx_k_Variables_should_have_the_same_d, sizeof(__pyx_k_Variables_should_have_the_same_d), 0, 0, 1, 0}, - {&__pyx_kp_s__8, __pyx_k__8, sizeof(__pyx_k__8), 0, 0, 1, 0}, -@@ -41334,8 +40020,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, - {&__pyx_n_s_name_2, __pyx_k_name_2, sizeof(__pyx_k_name_2), 0, 0, 1, 1}, - {&__pyx_n_s_ncol, __pyx_k_ncol, sizeof(__pyx_k_ncol), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_n_s_new, __pyx_k_new, sizeof(__pyx_k_new), 0, 0, 1, 1}, - {&__pyx_n_s_newNumberColumns, __pyx_k_newNumberColumns, sizeof(__pyx_k_newNumberColumns), 0, 0, 1, 1}, - {&__pyx_n_s_newNumberRows, __pyx_k_newNumberRows, sizeof(__pyx_k_newNumberRows), 0, 0, 1, 1}, -@@ -41443,7 +40127,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_toarray, __pyx_k_toarray, sizeof(__pyx_k_toarray), 0, 0, 1, 1}, - {&__pyx_n_s_tocoo, __pyx_k_tocoo, sizeof(__pyx_k_tocoo), 0, 0, 1, 1}, - {&__pyx_n_s_tryPlusMinusOne, __pyx_k_tryPlusMinusOne, sizeof(__pyx_k_tryPlusMinusOne), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {&__pyx_kp_s_unrecognised_extension_s, __pyx_k_unrecognised_extension_s, sizeof(__pyx_k_unrecognised_extension_s), 0, 0, 1, 0}, - {&__pyx_n_s_update, __pyx_k_update, sizeof(__pyx_k_update), 0, 0, 1, 1}, - {&__pyx_n_s_updateStatus, __pyx_k_updateStatus, sizeof(__pyx_k_updateStatus), 0, 0, 1, 1}, -@@ -41491,8 +40174,6 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 314, __pyx_L1_error) - __pyx_builtin_print = __Pyx_GetBuiltinName(__pyx_n_s_print); if (!__pyx_builtin_print) __PYX_ERR(0, 1500, __pyx_L1_error) - __pyx_builtin_open = __Pyx_GetBuiltinName(__pyx_n_s_open); if (!__pyx_builtin_open) __PYX_ERR(0, 1807, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 855, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -41730,82 +40411,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_slice__26); - __Pyx_GIVEREF(__pyx_slice__26); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__29 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__29)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__29); -- __Pyx_GIVEREF(__pyx_tuple__29); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__30 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__30)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__30); -- __Pyx_GIVEREF(__pyx_tuple__30); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__31 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__31)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__31); -- __Pyx_GIVEREF(__pyx_tuple__31); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__32 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__32)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__32); -- __Pyx_GIVEREF(__pyx_tuple__32); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__33 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__33)) __PYX_ERR(2, 879, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__33); -- __Pyx_GIVEREF(__pyx_tuple__33); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__34 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__34)) __PYX_ERR(2, 1037, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__34); -- __Pyx_GIVEREF(__pyx_tuple__34); -+ __pyx_tuple__29 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__29)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__29); -+ __Pyx_GIVEREF(__pyx_tuple__29); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__35 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__35)) __PYX_ERR(2, 1043, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__35); -- __Pyx_GIVEREF(__pyx_tuple__35); -+ __pyx_tuple__30 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__30)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__30); -+ __Pyx_GIVEREF(__pyx_tuple__30); - - /* "cylp/cy/CyClpSimplex.pyx":2178 - * -@@ -41814,10 +40440,10 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - * ''' - * Return a model example to be used in doctests. - */ -- __pyx_tuple__36 = PyTuple_Pack(14, __pyx_n_s_np, __pyx_n_s_CyLPModel, __pyx_n_s_CyLPArray, __pyx_n_s_CyClpSimplex, __pyx_n_s_model, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_A, __pyx_n_s_B, __pyx_n_s_D, __pyx_n_s_a, __pyx_n_s_b, __pyx_n_s_x_u, __pyx_n_s_c); if (unlikely(!__pyx_tuple__36)) __PYX_ERR(0, 2178, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__36); -- __Pyx_GIVEREF(__pyx_tuple__36); -- __pyx_codeobj__23 = (PyObject*)__Pyx_PyCode_New(0, 0, 14, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__36, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_cylp_cy_CyClpSimplex_pyx, __pyx_n_s_getModelExample, 2178, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__23)) __PYX_ERR(0, 2178, __pyx_L1_error) -+ __pyx_tuple__31 = PyTuple_Pack(14, __pyx_n_s_np, __pyx_n_s_CyLPModel, __pyx_n_s_CyLPArray, __pyx_n_s_CyClpSimplex, __pyx_n_s_model, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_A, __pyx_n_s_B, __pyx_n_s_D, __pyx_n_s_a, __pyx_n_s_b, __pyx_n_s_x_u, __pyx_n_s_c); if (unlikely(!__pyx_tuple__31)) __PYX_ERR(0, 2178, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__31); -+ __Pyx_GIVEREF(__pyx_tuple__31); -+ __pyx_codeobj__23 = (PyObject*)__Pyx_PyCode_New(0, 0, 14, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__31, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_cylp_cy_CyClpSimplex_pyx, __pyx_n_s_getModelExample, 2178, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__23)) __PYX_ERR(0, 2178, __pyx_L1_error) - - /* "cylp/cy/CyClpSimplex.pyx":2212 - * -@@ -41826,20 +40452,20 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - * ''' - * Return full path to an MPS example file for doctests - */ -- __pyx_tuple__37 = PyTuple_Pack(3, __pyx_n_s_os, __pyx_n_s_inspect, __pyx_n_s_curpath); if (unlikely(!__pyx_tuple__37)) __PYX_ERR(0, 2212, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__37); -- __Pyx_GIVEREF(__pyx_tuple__37); -- __pyx_codeobj__27 = (PyObject*)__Pyx_PyCode_New(0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__37, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_cylp_cy_CyClpSimplex_pyx, __pyx_n_s_getMpsExample, 2212, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__27)) __PYX_ERR(0, 2212, __pyx_L1_error) -+ __pyx_tuple__32 = PyTuple_Pack(3, __pyx_n_s_os, __pyx_n_s_inspect, __pyx_n_s_curpath); if (unlikely(!__pyx_tuple__32)) __PYX_ERR(0, 2212, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__32); -+ __Pyx_GIVEREF(__pyx_tuple__32); -+ __pyx_codeobj__27 = (PyObject*)__Pyx_PyCode_New(0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__32, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_cylp_cy_CyClpSimplex_pyx, __pyx_n_s_getMpsExample, 2212, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__27)) __PYX_ERR(0, 2212, __pyx_L1_error) - - /* "(tree fragment)":1 - * def __pyx_unpickle_VarStatus(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< - * cdef object __pyx_PickleError - * cdef object __pyx_result - */ -- __pyx_tuple__38 = PyTuple_Pack(5, __pyx_n_s_pyx_type, __pyx_n_s_pyx_checksum, __pyx_n_s_pyx_state, __pyx_n_s_pyx_PickleError, __pyx_n_s_pyx_result); if (unlikely(!__pyx_tuple__38)) __PYX_ERR(1, 1, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__38); -- __Pyx_GIVEREF(__pyx_tuple__38); -- __pyx_codeobj__28 = (PyObject*)__Pyx_PyCode_New(3, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__38, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_pyx_unpickle_VarStatus, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__28)) __PYX_ERR(1, 1, __pyx_L1_error) -+ __pyx_tuple__33 = PyTuple_Pack(5, __pyx_n_s_pyx_type, __pyx_n_s_pyx_checksum, __pyx_n_s_pyx_state, __pyx_n_s_pyx_PickleError, __pyx_n_s_pyx_result); if (unlikely(!__pyx_tuple__33)) __PYX_ERR(1, 1, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__33); -+ __Pyx_GIVEREF(__pyx_tuple__33); -+ __pyx_codeobj__28 = (PyObject*)__Pyx_PyCode_New(3, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__33, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_pyx_unpickle_VarStatus, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__28)) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -42017,18 +40643,38 @@ static int __Pyx_modinit_type_import_code(void) { - if (!__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase) __PYX_ERR(7, 67, __pyx_L1_error) - __pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase = (struct __pyx_vtabstruct_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase*)__Pyx_GetVtable(__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase->tp_dict); if (unlikely(!__pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase)) __PYX_ERR(7, 67, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 917, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(8, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -42315,11 +40961,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -43083,12 +41727,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1045 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - __Pyx_TraceReturn(Py_None, 0); - -@@ -43367,10 +42011,9 @@ static int __Pyx_TraceSetupAndCall(PyCodeObject** code, - (*frame)->f_tstate = tstate; - #endif - } -- __Pyx_PyFrame_SetLineNumber(*frame, firstlineno); -+ __Pyx_PyFrame_SetLineNumber(*frame, firstlineno); - retval = 1; -- tstate->tracing++; -- tstate->use_tracing = 0; -+ __Pyx_EnterTracing(tstate); - __Pyx_ErrFetchInState(tstate, &type, &value, &traceback); - #if CYTHON_TRACE - if (tstate->c_tracefunc) -@@ -43378,12 +42021,10 @@ static int __Pyx_TraceSetupAndCall(PyCodeObject** code, - if (retval && tstate->c_profilefunc) - #endif - retval = tstate->c_profilefunc(tstate->c_profileobj, *frame, PyTrace_CALL, NULL) == 0; -- tstate->use_tracing = (tstate->c_profilefunc || -- (CYTHON_TRACE && tstate->c_tracefunc)); -- tstate->tracing--; -+ __Pyx_LeaveTracing(tstate); - if (retval) { - __Pyx_ErrRestoreInState(tstate, type, value, traceback); -- return tstate->use_tracing && retval; -+ return __Pyx_IsTracing(tstate, 0, 0) && retval; - } else { - Py_XDECREF(type); - Py_XDECREF(value); -@@ -43552,7 +42193,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -43745,7 +42386,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -45623,11 +44264,6 @@ static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *o, PyObject *n, PyObject - } - } - --/* RaiseNoneIterError */ -- static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- - /* PyObject_GenericGetAttrNoDict */ - #if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 - static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { -@@ -45935,7 +44571,7 @@ static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -46032,30 +44668,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -46074,11 +44711,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -46113,7 +44755,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #if PY_MAJOR_VERSION < 3 - static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { - if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags); -- if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) return __pyx_pw_5numpy_7ndarray_1__getbuffer__(obj, view, flags); - PyErr_Format(PyExc_TypeError, "'%.200s' does not have the buffer interface", Py_TYPE(obj)->tp_name); - return -1; - } -@@ -46125,7 +44766,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return; - } - if ((0)) {} -- else if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) __pyx_pw_5numpy_7ndarray_3__releasebuffer__(obj, view); - view->obj = NULL; - Py_DECREF(obj); - } -@@ -46181,99 +44821,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return t; - } - --/* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(long) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(long) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(long) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(long), -- little, !is_unsigned); -- } --} -- --/* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- --/* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__IClpSimplex_3a__3a_Status(enum IClpSimplex::Status value) { -- const enum IClpSimplex::Status neg_one = (enum IClpSimplex::Status) ((enum IClpSimplex::Status) 0 - (enum IClpSimplex::Status) 1), const_zero = (enum IClpSimplex::Status) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum IClpSimplex::Status) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum IClpSimplex::Status) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum IClpSimplex::Status) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(enum IClpSimplex::Status) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum IClpSimplex::Status) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum IClpSimplex::Status), -- little, !is_unsigned); -- } --} -- - /* Declarations */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus -@@ -46582,40 +45129,16 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - #endif - #endif - --/* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -46802,9 +45325,54 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return (int) -1; - } - -+/* CIntToPy */ -+ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(long) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(long) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(long) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(long), -+ little, !is_unsigned); -+ } -+} -+ - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -46991,9 +45559,54 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return (long) -1; - } - -+/* CIntToPy */ -+ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(int) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); -+ } -+} -+ - /* CIntFromPy */ - static CYTHON_INLINE size_t __Pyx_PyInt_As_size_t(PyObject *x) { -- const size_t neg_one = (size_t) ((size_t) 0 - (size_t) 1), const_zero = (size_t) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const size_t neg_one = (size_t) -1, const_zero = (size_t) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -47180,9 +45793,54 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return (size_t) -1; - } - -+/* CIntToPy */ -+ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__IClpSimplex_3a__3a_Status(enum IClpSimplex::Status value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const enum IClpSimplex::Status neg_one = (enum IClpSimplex::Status) -1, const_zero = (enum IClpSimplex::Status) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(enum IClpSimplex::Status) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(enum IClpSimplex::Status) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(enum IClpSimplex::Status) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(enum IClpSimplex::Status) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(enum IClpSimplex::Status) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(enum IClpSimplex::Status), -+ little, !is_unsigned); -+ } -+} -+ - /* CIntFromPy */ - static CYTHON_INLINE enum IClpSimplex::Status __Pyx_PyInt_As_enum__IClpSimplex_3a__3a_Status(PyObject *x) { -- const enum IClpSimplex::Status neg_one = (enum IClpSimplex::Status) ((enum IClpSimplex::Status) 0 - (enum IClpSimplex::Status) 1), const_zero = (enum IClpSimplex::Status) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const enum IClpSimplex::Status neg_one = (enum IClpSimplex::Status) -1, const_zero = (enum IClpSimplex::Status) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -47371,7 +46029,14 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - - /* CIntFromPy */ - static CYTHON_INLINE Py_intptr_t __Pyx_PyInt_As_Py_intptr_t(PyObject *x) { -- const Py_intptr_t neg_one = (Py_intptr_t) ((Py_intptr_t) 0 - (Py_intptr_t) 1), const_zero = (Py_intptr_t) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const Py_intptr_t neg_one = (Py_intptr_t) -1, const_zero = (Py_intptr_t) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -47959,6 +46624,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyCoinIndexedVector.cpp b/cylp/cy/CyCoinIndexedVector.cpp -index d2f3446..c247ad2 100644 ---- a/cylp/cy/CyCoinIndexedVector.cpp -+++ b/cylp/cy/CyCoinIndexedVector.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -706,6 +789,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -819,7 +903,7 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyCoinIndexedVector.pyx", -+ "cylp/cy/CyCoinIndexedVector.pyx", - "type.pxd", - }; - -@@ -984,6 +1068,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -991,6 +1076,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -1075,6 +1161,17 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyErrExceptionMatches.proto */ -+#if CYTHON_FAST_THREAD_STATE -+#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) -+static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); -+#else -+#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) -+#endif -+ -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -1115,12 +1212,17 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); - static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); - -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+ - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - -@@ -1395,6 +1497,9 @@ static PyObject *__pyx_f_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_r - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - int __pyx_t_5; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("reserve", 0); - /* Check if called by wrapper */ - if (unlikely(__pyx_skip_dispatch)) ; -@@ -1495,6 +1600,9 @@ static PyObject *__pyx_pf_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("reserve", 0); - __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = __pyx_f_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_reserve(__pyx_v_self, __pyx_v_n, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 38, __pyx_L1_error) -@@ -1540,6 +1648,9 @@ static PyObject *__pyx_pf_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_ - __Pyx_RefNannyDeclarations - int __pyx_t_1; - PyObject *__pyx_t_2 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__getitem__", 0); - - /* "cylp/cy/CyCoinIndexedVector.pyx":42 -@@ -1601,6 +1712,9 @@ static int __pyx_pf_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_8__set - int __pyx_r; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setitem__", 0); - - /* "cylp/cy/CyCoinIndexedVector.pyx":45 -@@ -1754,6 +1868,9 @@ static PyObject *__pyx_f_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_a - PyObject *__pyx_t_4 = NULL; - int __pyx_t_5; - PyObject *__pyx_t_6 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("assign", 0); - /* Check if called by wrapper */ - if (unlikely(__pyx_skip_dispatch)) ; -@@ -1872,6 +1989,9 @@ static char __pyx_doc_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_14as - static PyObject *__pyx_pw_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_15assign(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_ind = 0; - PyObject *__pyx_v_other = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("assign (wrapper)", 0); -@@ -1932,6 +2052,9 @@ static PyObject *__pyx_pf_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("assign", 0); - __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = __pyx_f_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_assign(__pyx_v_self, __pyx_v_ind, __pyx_v_other, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 58, __pyx_L1_error) -@@ -2086,6 +2209,9 @@ static PyObject *__pyx_pf_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCoinIndexedVector.pyx":71 -@@ -2146,6 +2272,9 @@ static int __pyx_pf_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_9nElem - int __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__set__", 0); - - /* "cylp/cy/CyCoinIndexedVector.pyx":74 -@@ -2201,6 +2330,9 @@ static PyObject *__pyx_pf_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCoinIndexedVector.pyx":78 -@@ -2257,6 +2389,9 @@ static PyObject *__pyx_pf_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -2312,6 +2447,9 @@ static PyObject *__pyx_pf_4cylp_2cy_19CyCoinIndexedVector_19CyCoinIndexedVector_ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -2458,7 +2596,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVect - sizeof(struct __pyx_obj_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -2511,6 +2654,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVect - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -2656,6 +2805,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_vtabptr_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector = &__pyx_vtable_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector; -@@ -2683,6 +2835,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 9, __pyx_L1_error) -@@ -2721,17 +2876,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -2813,6 +2970,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyCoinIndexedVector(PyObject *__py - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -2860,11 +3020,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -2901,15 +3059,15 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ -@@ -3235,7 +3393,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -3322,7 +3480,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -3376,7 +3534,7 @@ static int __Pyx_ParseOptionalKeywords( - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 -- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { -+ if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { -@@ -3403,7 +3561,7 @@ static int __Pyx_ParseOptionalKeywords( - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -3419,7 +3577,7 @@ static int __Pyx_ParseOptionalKeywords( - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -3707,6 +3865,53 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable) { - return -1; - } - -+/* PyErrExceptionMatches */ -+#if CYTHON_FAST_THREAD_STATE -+static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { -+ Py_ssize_t i, n; -+ n = PyTuple_GET_SIZE(tuple); -+#if PY_MAJOR_VERSION >= 3 -+ for (i=0; i<n; i++) { -+ if (exc_type == PyTuple_GET_ITEM(tuple, i)) return 1; -+ } -+#endif -+ for (i=0; i<n; i++) { -+ if (__Pyx_PyErr_GivenExceptionMatches(exc_type, PyTuple_GET_ITEM(tuple, i))) return 1; -+ } -+ return 0; -+} -+static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err) { -+ PyObject *exc_type = tstate->curexc_type; -+ if (exc_type == err) return 1; -+ if (unlikely(!exc_type)) return 0; -+ if (unlikely(PyTuple_Check(err))) -+ return __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); -+ return __Pyx_PyErr_GivenExceptionMatches(exc_type, err); -+} -+#endif -+ -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -3734,43 +3939,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -3846,7 +4059,7 @@ static PyTypeObject *__Pyx_ImportType(PyObject *module, const char *module_name, - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -3876,7 +4089,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -3950,7 +4163,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -3973,30 +4186,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -4015,11 +4229,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -4073,40 +4292,16 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - return (target_type) value;\ - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -4293,9 +4488,54 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - return (int) -1; - } - -+/* CIntToPy */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(int) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); -+ } -+} -+ - /* CIntToPy */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { -@@ -4326,7 +4566,14 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { - - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -4877,6 +5124,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyCoinModel.cpp b/cylp/cy/CyCoinModel.cpp -index af39332..7fdaea8 100644 ---- a/cylp/cy/CyCoinModel.cpp -+++ b/cylp/cy/CyCoinModel.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -610,7 +693,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include <string.h> - #include <stdio.h> - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "CoinModel.hpp" - #ifdef _OPENMP - #include <omp.h> -@@ -708,6 +797,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -843,7 +933,7 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyCoinModel.pyx", -+ "cylp/cy/CyCoinModel.pyx", - "__init__.pxd", - "type.pxd", - }; -@@ -884,7 +974,7 @@ typedef struct { - } __Pyx_BufFmt_Context; - - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -893,7 +983,7 @@ typedef struct { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -902,7 +992,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -911,7 +1001,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -920,7 +1010,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -929,7 +1019,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -938,7 +1028,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -947,7 +1037,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -956,7 +1046,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -965,7 +1055,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -974,7 +1064,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -983,7 +1073,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -992,7 +1082,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1001,7 +1091,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1010,7 +1100,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1019,7 +1109,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1028,7 +1118,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1037,7 +1127,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1046,7 +1136,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1055,7 +1145,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1064,7 +1154,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1100,7 +1190,7 @@ static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(do - /*--- Type declarations ---*/ - struct __pyx_obj_4cylp_2cy_11CyCoinModel_CyCoinModel; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1109,7 +1199,7 @@ struct __pyx_obj_4cylp_2cy_11CyCoinModel_CyCoinModel; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1118,7 +1208,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1127,7 +1217,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1327,67 +1417,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* PyCFunctionFastCall.proto */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); --#else --#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) --#endif -- --/* PyFunctionFastCall.proto */ --#if CYTHON_FAST_PYCALL --#define __Pyx_PyFunction_FastCall(func, args, nargs)\ -- __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); --#else --#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) --#endif --#define __Pyx_BUILD_ASSERT_EXPR(cond)\ -- (sizeof(char [1 - 2*!(cond)]) - 1) --#ifndef Py_MEMBER_SIZE --#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) --#endif -- static size_t __pyx_pyframe_localsplus_offset = 0; -- #include "frameobject.h" -- #define __Pxy_PyFrame_Initialize_Offsets()\ -- ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ -- (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) -- #define __Pyx_PyFrame_GetLocalsplus(frame)\ -- (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) --#endif -- --/* PyObjectCallMethO.proto */ --#if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); --#endif -- --/* PyObjectCallOneArg.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); -- --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -1437,6 +1466,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -1568,8 +1600,10 @@ static void __Pyx_CppExn2PyErr() { - } - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -1669,12 +1703,12 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - #endif - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); - -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+ - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - -@@ -1729,8 +1763,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy' */ - -@@ -1744,9 +1787,6 @@ int __pyx_module_is_main_cylp__cy__CyCoinModel = 0; - - /* Implementation of 'cylp.cy.CyCoinModel' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_ind[] = "ind"; - static const char __pyx_k_val[] = "val"; -@@ -1754,7 +1794,6 @@ static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_rows[] = "rows"; - static const char __pyx_k_test[] = "__test__"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_reduce[] = "__reduce__"; - static const char __pyx_k_varInd[] = "varInd"; - static const char __pyx_k_columns[] = "columns"; -@@ -1766,35 +1805,22 @@ static const char __pyx_k_setstate[] = "__setstate__"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_objective[] = "objective"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_CyCoinModel[] = "CyCoinModel"; - static const char __pyx_k_ImportError[] = "ImportError"; - static const char __pyx_k_columnLower[] = "columnLower"; - static const char __pyx_k_columnUpper[] = "columnUpper"; - static const char __pyx_k_numberInRow[] = "numberInRow"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; - static const char __pyx_k_numberInColumn[] = "numberInColumn"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyCoinModel; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_columnLower; - static PyObject *__pyx_n_s_columnUpper; -@@ -1804,8 +1830,6 @@ static PyObject *__pyx_n_s_getstate; - static PyObject *__pyx_n_s_ind; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_no_default___reduce___due_to_non; - static PyObject *__pyx_n_s_numberInColumn; - static PyObject *__pyx_n_s_numberInRow; -@@ -1813,7 +1837,6 @@ static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_objective; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -1823,7 +1846,6 @@ static PyObject *__pyx_n_s_rows; - static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_n_s_val; - static PyObject *__pyx_n_s_varInd; - static int __pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel___cinit__(struct __pyx_obj_4cylp_2cy_11CyCoinModel_CyCoinModel *__pyx_v_self); /* proto */ -@@ -1838,18 +1860,11 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_16getNumVariable - static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_18getNumConstraints(struct __pyx_obj_4cylp_2cy_11CyCoinModel_CyCoinModel *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_20__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_11CyCoinModel_CyCoinModel *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_22__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_11CyCoinModel_CyCoinModel *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_11CyCoinModel_CyCoinModel(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; --static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; - /* Late includes */ - - /* "cylp/cy/CyCoinModel.pyx":42 -@@ -1880,6 +1895,9 @@ static int __pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel___cinit__(struct __pyx - int __pyx_r; - __Pyx_RefNannyDeclarations - CoinModel *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCoinModel.pyx":43 -@@ -1967,6 +1985,9 @@ static PyObject *__pyx_pw_4cylp_2cy_11CyCoinModel_11CyCoinModel_3addVariable(PyO - PyObject *__pyx_v_columnLower = 0; - PyObject *__pyx_v_columnUpper = 0; - PyObject *__pyx_v_objective = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("addVariable (wrapper)", 0); -@@ -2080,6 +2101,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_2addVariable(str - double __pyx_t_2; - double __pyx_t_3; - double __pyx_t_4; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("addVariable", 0); - __pyx_pybuffer_rows.pybuffer.buf = NULL; - __pyx_pybuffer_rows.refcount = 0; -@@ -2218,6 +2242,9 @@ static PyObject *__pyx_pw_4cylp_2cy_11CyCoinModel_11CyCoinModel_5addConstraint(P - PyArrayObject *__pyx_v_elements = 0; - PyObject *__pyx_v_rowLower = 0; - PyObject *__pyx_v_rowUpper = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("addConstraint (wrapper)", 0); -@@ -2320,6 +2347,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_4addConstraint(s - int __pyx_t_1; - double __pyx_t_2; - double __pyx_t_3; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("addConstraint", 0); - __pyx_pybuffer_columns.pybuffer.buf = NULL; - __pyx_pybuffer_columns.refcount = 0; -@@ -2413,6 +2443,9 @@ static char __pyx_doc_4cylp_2cy_11CyCoinModel_11CyCoinModel_6setVariableLower[] - static PyObject *__pyx_pw_4cylp_2cy_11CyCoinModel_11CyCoinModel_7setVariableLower(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_ind = 0; - PyObject *__pyx_v_val = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("setVariableLower (wrapper)", 0); -@@ -2474,6 +2507,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_6setVariableLowe - __Pyx_RefNannyDeclarations - int __pyx_t_1; - double __pyx_t_2; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("setVariableLower", 0); - - /* "cylp/cy/CyCoinModel.pyx":124 -@@ -2521,6 +2557,9 @@ static char __pyx_doc_4cylp_2cy_11CyCoinModel_11CyCoinModel_8setVariableUpper[] - static PyObject *__pyx_pw_4cylp_2cy_11CyCoinModel_11CyCoinModel_9setVariableUpper(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_ind = 0; - PyObject *__pyx_v_val = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("setVariableUpper (wrapper)", 0); -@@ -2582,6 +2621,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_8setVariableUppe - __Pyx_RefNannyDeclarations - int __pyx_t_1; - double __pyx_t_2; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("setVariableUpper", 0); - - /* "cylp/cy/CyCoinModel.pyx":127 -@@ -2629,6 +2671,9 @@ static char __pyx_doc_4cylp_2cy_11CyCoinModel_11CyCoinModel_10setConstraintLower - static PyObject *__pyx_pw_4cylp_2cy_11CyCoinModel_11CyCoinModel_11setConstraintLower(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_ind = 0; - PyObject *__pyx_v_val = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("setConstraintLower (wrapper)", 0); -@@ -2690,6 +2735,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_10setConstraintL - __Pyx_RefNannyDeclarations - int __pyx_t_1; - double __pyx_t_2; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("setConstraintLower", 0); - - /* "cylp/cy/CyCoinModel.pyx":130 -@@ -2737,6 +2785,9 @@ static char __pyx_doc_4cylp_2cy_11CyCoinModel_11CyCoinModel_12setConstraintUpper - static PyObject *__pyx_pw_4cylp_2cy_11CyCoinModel_11CyCoinModel_13setConstraintUpper(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_ind = 0; - PyObject *__pyx_v_val = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("setConstraintUpper (wrapper)", 0); -@@ -2798,6 +2849,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_12setConstraintU - __Pyx_RefNannyDeclarations - int __pyx_t_1; - double __pyx_t_2; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("setConstraintUpper", 0); - - /* "cylp/cy/CyCoinModel.pyx":133 -@@ -2845,6 +2899,9 @@ static char __pyx_doc_4cylp_2cy_11CyCoinModel_11CyCoinModel_14setObjective[] = " - static PyObject *__pyx_pw_4cylp_2cy_11CyCoinModel_11CyCoinModel_15setObjective(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_varInd = 0; - PyObject *__pyx_v_val = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("setObjective (wrapper)", 0); -@@ -2906,6 +2963,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_14setObjective(s - __Pyx_RefNannyDeclarations - int __pyx_t_1; - double __pyx_t_2; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("setObjective", 0); - - /* "cylp/cy/CyCoinModel.pyx":136 -@@ -2965,6 +3025,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_16getNumVariable - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("getNumVariables", 0); - - /* "cylp/cy/CyCoinModel.pyx":139 -@@ -3025,6 +3088,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_18getNumConstrai - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("getNumConstraints", 0); - - /* "cylp/cy/CyCoinModel.pyx":142 -@@ -3081,6 +3147,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_20__reduce_cytho - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3136,6 +3205,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_22__setstate_cyt - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3166,863 +3238,7 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinModel_11CyCoinModel_22__setstate_cyt - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * -- * ndim = PyArray_NDIM(self) -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -- * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -- * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -- * -- * cdef int t -- */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -- * -- */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -- * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4034,9 +3250,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * - * cdef inline object PyArray_MultiIterNew1(a): - * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -@@ -4044,13 +3263,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - * cdef inline object PyArray_MultiIterNew2(a, b): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4069,7 +3288,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4081,9 +3300,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * - * cdef inline object PyArray_MultiIterNew2(a, b): - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -@@ -4091,13 +3313,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4116,7 +3338,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4128,9 +3350,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -@@ -4138,13 +3363,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4163,7 +3388,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4175,9 +3400,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -@@ -4185,13 +3413,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4210,7 +3438,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4222,9 +3450,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -@@ -4232,13 +3463,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - * cdef inline tuple PyDataType_SHAPE(dtype d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4257,7 +3488,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4271,7 +3502,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - int __pyx_t_1; - __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4281,7 +3512,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): - * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -@@ -4293,7 +3524,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4302,12 +3533,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 - * return <tuple>d.subarray.shape - * else: - * return () # <<<<<<<<<<<<<< - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -+ * - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); -@@ -4316,7 +3547,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - goto __pyx_L0; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4331,754 +3562,8 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- goto __pyx_L13; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -- */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -- * -- * -- */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -- __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -- * int _import_umath() except -1 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 -+ * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< - * Py_INCREF(base) # important to do this before stealing the reference below! -@@ -5089,7 +3574,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -5098,7 +3583,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5107,7 +3592,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5119,7 +3604,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5134,7 +3619,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5143,7 +3628,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5153,7 +3638,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5164,7 +3649,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5173,7 +3658,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5185,7 +3670,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5200,12 +3685,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -5219,13 +3704,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -5237,20 +3725,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5260,9 +3748,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5270,32 +3758,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5306,12 +3794,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -5329,7 +3817,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5348,9 +3836,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5366,16 +3857,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5389,7 +3880,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -5399,28 +3890,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5435,7 +3926,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5458,7 +3949,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5477,9 +3968,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5495,16 +3989,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5518,35 +4012,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5561,7 +4058,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5583,6 +4080,180 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} - static struct __pyx_vtabstruct_4cylp_2cy_11CyCoinModel_CyCoinModel __pyx_vtable_4cylp_2cy_11CyCoinModel_CyCoinModel; - - static PyObject *__pyx_tp_new_4cylp_2cy_11CyCoinModel_CyCoinModel(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { -@@ -5633,7 +4304,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_11CyCoinModel_CyCoinModel = { - sizeof(struct __pyx_obj_4cylp_2cy_11CyCoinModel_CyCoinModel), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_11CyCoinModel_CyCoinModel, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -5686,6 +4362,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_11CyCoinModel_CyCoinModel = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -5735,13 +4417,8 @@ static struct PyModuleDef __pyx_moduledef = { - - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyCoinModel, __pyx_k_CyCoinModel, sizeof(__pyx_k_CyCoinModel), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_columnLower, __pyx_k_columnLower, sizeof(__pyx_k_columnLower), 0, 0, 1, 1}, - {&__pyx_n_s_columnUpper, __pyx_k_columnUpper, sizeof(__pyx_k_columnUpper), 0, 0, 1, 1}, -@@ -5751,8 +4428,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_ind, __pyx_k_ind, sizeof(__pyx_k_ind), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, - {&__pyx_n_s_numberInColumn, __pyx_k_numberInColumn, sizeof(__pyx_k_numberInColumn), 0, 0, 1, 1}, - {&__pyx_n_s_numberInRow, __pyx_k_numberInRow, sizeof(__pyx_k_numberInRow), 0, 0, 1, 1}, -@@ -5760,7 +4435,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_objective, __pyx_k_objective, sizeof(__pyx_k_objective), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -5770,17 +4444,13 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {&__pyx_n_s_val, __pyx_k_val, sizeof(__pyx_k_val), 0, 0, 1, 1}, - {&__pyx_n_s_varInd, __pyx_k_varInd, sizeof(__pyx_k_varInd), 0, 0, 1, 1}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -5790,101 +4460,46 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); - -- /* "(tree fragment)":2 -- * def __reduce_cython__(self): -- * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< -- * def __setstate_cython__(self, __pyx_state): -- * raise TypeError("no default __reduce__ due to non-trivial __cinit__") -- */ -- __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 2, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple_); -- __Pyx_GIVEREF(__pyx_tuple_); -- -- /* "(tree fragment)":4 -- * raise TypeError("no default __reduce__ due to non-trivial __cinit__") -- * def __setstate_cython__(self, __pyx_state): -- * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< -- */ -- __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 4, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__2); -- __Pyx_GIVEREF(__pyx_tuple__2); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -+ /* "(tree fragment)":2 -+ * def __reduce_cython__(self): -+ * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< -+ * def __setstate_cython__(self, __pyx_state): -+ * raise TypeError("no default __reduce__ due to non-trivial __cinit__") - */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -+ __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 2, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple_); -+ __Pyx_GIVEREF(__pyx_tuple_); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -+ /* "(tree fragment)":4 -+ * raise TypeError("no default __reduce__ due to non-trivial __cinit__") -+ * def __setstate_cython__(self, __pyx_state): -+ * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< - */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -+ __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 4, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__2); -+ __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -5933,6 +4548,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_vtabptr_4cylp_2cy_11CyCoinModel_CyCoinModel = &__pyx_vtable_4cylp_2cy_11CyCoinModel_CyCoinModel; -@@ -5959,6 +4577,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -5972,18 +4593,38 @@ static int __Pyx_modinit_type_import_code(void) { - __Pyx_ImportType_CheckSize_Warn); - if (!__pyx_ptype_7cpython_4type_type) __PYX_ERR(3, 9, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; -@@ -6010,17 +4651,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6102,6 +4745,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyCoinModel(PyObject *__pyx_pyinit - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -6149,11 +4795,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -6190,15 +4834,15 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ -@@ -6216,12 +4860,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -6396,7 +5040,7 @@ static int __Pyx_ParseOptionalKeywords( - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 -- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { -+ if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { -@@ -6423,7 +5067,7 @@ static int __Pyx_ParseOptionalKeywords( - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -6439,7 +5083,7 @@ static int __Pyx_ParseOptionalKeywords( - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -6564,6 +5208,7 @@ static void __Pyx_BufFmt_RaiseUnexpectedChar(char ch) { - } - static const char* __Pyx_BufFmt_DescribeTypeChar(char ch, int is_complex) { - switch (ch) { -+ case '?': return "'bool'"; - case 'c': return "'char'"; - case 'b': return "'signed char'"; - case 'B': return "'unsigned char'"; -@@ -6606,7 +5251,7 @@ static size_t __Pyx_BufFmt_TypeCharToStandardSize(char ch, int is_complex) { - } - static size_t __Pyx_BufFmt_TypeCharToNativeSize(char ch, int is_complex) { - switch (ch) { -- case 'c': case 'b': case 'B': case 's': case 'p': return 1; -+ case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; - case 'h': case 'H': return sizeof(short); - case 'i': case 'I': return sizeof(int); - case 'l': case 'L': return sizeof(long); -@@ -6690,7 +5335,7 @@ static char __Pyx_BufFmt_TypeCharToGroup(char ch, int is_complex) { - case 'b': case 'h': case 'i': - case 'l': case 'q': case 's': case 'p': - return 'I'; -- case 'B': case 'H': case 'I': case 'L': case 'Q': -+ case '?': case 'B': case 'H': case 'I': case 'L': case 'Q': - return 'U'; - case 'f': case 'd': case 'g': - return (is_complex ? 'C' : 'R'); -@@ -6834,9 +5479,7 @@ static PyObject * - __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) - { - const char *ts = *tsp; -- int i = 0, number; -- int ndim = ctx->head->field->type->ndim; --; -+ int i = 0, number, ndim; - ++ts; - if (ctx->new_count != 1) { - PyErr_SetString(PyExc_ValueError, -@@ -6844,6 +5487,7 @@ __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) - return NULL; - } - if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; -+ ndim = ctx->head->field->type->ndim; - while (*ts && *ts != ')') { - switch (*ts) { - case ' ': case '\f': case '\r': case '\n': case '\t': case '\v': continue; -@@ -6969,12 +5613,12 @@ static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const cha - return NULL; - } - CYTHON_FALLTHROUGH; -- case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': -+ case '?': case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': - case 'l': case 'L': case 'q': case 'Q': - case 'f': case 'd': case 'g': - case 'O': case 'p': -- if (ctx->enc_type == *ts && got_Z == ctx->is_complex && -- ctx->enc_packmode == ctx->new_packmode) { -+ if ((ctx->enc_type == *ts) && (got_Z == ctx->is_complex) && -+ (ctx->enc_packmode == ctx->new_packmode) && (!ctx->is_valid_array)) { - ctx->enc_count += ctx->new_count; - ctx->new_count = 1; - got_Z = 0; -@@ -7085,7 +5729,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -7260,263 +5904,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* PyCFunctionFastCall */ -- #if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { -- PyCFunctionObject *func = (PyCFunctionObject*)func_obj; -- PyCFunction meth = PyCFunction_GET_FUNCTION(func); -- PyObject *self = PyCFunction_GET_SELF(func); -- int flags = PyCFunction_GET_FLAGS(func); -- assert(PyCFunction_Check(func)); -- assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); -- assert(nargs >= 0); -- assert(nargs == 0 || args != NULL); -- /* _PyCFunction_FastCallDict() must not be called with an exception set, -- because it may clear it (directly or indirectly) and so the -- caller loses its exception */ -- assert(!PyErr_Occurred()); -- if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { -- return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); -- } else { -- return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); -- } --} --#endif -- --/* PyFunctionFastCall */ -- #if CYTHON_FAST_PYCALL --static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, -- PyObject *globals) { -- PyFrameObject *f; -- PyThreadState *tstate = __Pyx_PyThreadState_Current; -- PyObject **fastlocals; -- Py_ssize_t i; -- PyObject *result; -- assert(globals != NULL); -- /* XXX Perhaps we should create a specialized -- PyFrame_New() that doesn't take locals, but does -- take builtins without sanity checking them. -- */ -- assert(tstate != NULL); -- f = PyFrame_New(tstate, co, globals, NULL); -- if (f == NULL) { -- return NULL; -- } -- fastlocals = __Pyx_PyFrame_GetLocalsplus(f); -- for (i = 0; i < na; i++) { -- Py_INCREF(*args); -- fastlocals[i] = *args++; -- } -- result = PyEval_EvalFrameEx(f,0); -- ++tstate->recursion_depth; -- Py_DECREF(f); -- --tstate->recursion_depth; -- return result; --} --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { -- PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); -- PyObject *globals = PyFunction_GET_GLOBALS(func); -- PyObject *argdefs = PyFunction_GET_DEFAULTS(func); -- PyObject *closure; --#if PY_MAJOR_VERSION >= 3 -- PyObject *kwdefs; --#endif -- PyObject *kwtuple, **k; -- PyObject **d; -- Py_ssize_t nd; -- Py_ssize_t nk; -- PyObject *result; -- assert(kwargs == NULL || PyDict_Check(kwargs)); -- nk = kwargs ? PyDict_Size(kwargs) : 0; -- if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { -- return NULL; -- } -- if ( --#if PY_MAJOR_VERSION >= 3 -- co->co_kwonlyargcount == 0 && --#endif -- likely(kwargs == NULL || nk == 0) && -- co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { -- if (argdefs == NULL && co->co_argcount == nargs) { -- result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); -- goto done; -- } -- else if (nargs == 0 && argdefs != NULL -- && co->co_argcount == Py_SIZE(argdefs)) { -- /* function called with no arguments, but all parameters have -- a default value: use default values as arguments .*/ -- args = &PyTuple_GET_ITEM(argdefs, 0); -- result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); -- goto done; -- } -- } -- if (kwargs != NULL) { -- Py_ssize_t pos, i; -- kwtuple = PyTuple_New(2 * nk); -- if (kwtuple == NULL) { -- result = NULL; -- goto done; -- } -- k = &PyTuple_GET_ITEM(kwtuple, 0); -- pos = i = 0; -- while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { -- Py_INCREF(k[i]); -- Py_INCREF(k[i+1]); -- i += 2; -- } -- nk = i / 2; -- } -- else { -- kwtuple = NULL; -- k = NULL; -- } -- closure = PyFunction_GET_CLOSURE(func); --#if PY_MAJOR_VERSION >= 3 -- kwdefs = PyFunction_GET_KW_DEFAULTS(func); --#endif -- if (argdefs != NULL) { -- d = &PyTuple_GET_ITEM(argdefs, 0); -- nd = Py_SIZE(argdefs); -- } -- else { -- d = NULL; -- nd = 0; -- } --#if PY_MAJOR_VERSION >= 3 -- result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, kwdefs, closure); --#else -- result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, closure); --#endif -- Py_XDECREF(kwtuple); --done: -- Py_LeaveRecursiveCall(); -- return result; --} --#endif --#endif -- --/* PyObjectCallMethO */ -- #if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { -- PyObject *self, *result; -- PyCFunction cfunc; -- cfunc = PyCFunction_GET_FUNCTION(func); -- self = PyCFunction_GET_SELF(func); -- if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -- return NULL; -- result = cfunc(self, arg); -- Py_LeaveRecursiveCall(); -- if (unlikely(!result) && unlikely(!PyErr_Occurred())) { -- PyErr_SetString( -- PyExc_SystemError, -- "NULL result without error in PyObject_Call"); -- } -- return result; --} --#endif -- --/* PyObjectCallOneArg */ -- #if CYTHON_COMPILING_IN_CPYTHON --static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_New(1); -- if (unlikely(!args)) return NULL; -- Py_INCREF(arg); -- PyTuple_SET_ITEM(args, 0, arg); -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { --#if CYTHON_FAST_PYCALL -- if (PyFunction_Check(func)) { -- return __Pyx_PyFunction_FastCall(func, &arg, 1); -- } --#endif -- if (likely(PyCFunction_Check(func))) { -- if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { -- return __Pyx_PyObject_CallMethO(func, arg); --#if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -- return __Pyx_PyCFunction_FastCall(func, &arg, 1); --#endif -- } -- } -- return __Pyx__PyObject_CallOneArg(func, arg); --} --#else --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_Pack(1, arg); -- if (unlikely(!args)) return NULL; -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --#endif -- --/* DictGetItem */ -- #if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ -- static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ -- static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ -- static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ -- static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -7740,6 +6127,28 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+ static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -7767,43 +6176,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -7905,7 +6322,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -7935,7 +6352,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -8009,7 +6426,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -8032,30 +6449,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -8074,11 +6492,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -8113,7 +6536,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #if PY_MAJOR_VERSION < 3 - static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { - if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags); -- if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) return __pyx_pw_5numpy_7ndarray_1__getbuffer__(obj, view, flags); - PyErr_Format(PyExc_TypeError, "'%.200s' does not have the buffer interface", Py_TYPE(obj)->tp_name); - return -1; - } -@@ -8125,7 +6547,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return; - } - if ((0)) {} -- else if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) __pyx_pw_5numpy_7ndarray_3__releasebuffer__(obj, view); - view->obj = NULL; - Py_DECREF(obj); - } -@@ -8154,37 +6575,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return (target_type) value;\ - } - --/* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- - /* Declarations */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus -@@ -8302,7 +6692,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -8457,7 +6846,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -8495,40 +6883,16 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - #endif - #endif - --/* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -8715,9 +7079,54 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return (int) -1; - } - -+/* CIntToPy */ -+ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(int) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); -+ } -+} -+ - /* CIntToPy */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { -@@ -8748,7 +7157,14 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -9299,6 +7715,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyCoinMpsIO.cpp b/cylp/cy/CyCoinMpsIO.cpp -index 268873e..67226b6 100644 ---- a/cylp/cy/CyCoinMpsIO.cpp -+++ b/cylp/cy/CyCoinMpsIO.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -610,7 +693,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include <string.h> - #include <stdio.h> - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ICoinPackedMatrix.hpp" - #include "ICoinMpsIO.hpp" - #ifdef _OPENMP -@@ -709,6 +798,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -844,13 +934,13 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyCoinMpsIO.pyx", -+ "cylp/cy/CyCoinMpsIO.pyx", - "__init__.pxd", - "type.pxd", -- "cylp\\cy\\CyCoinPackedMatrix.pxd", -+ "cylp/cy/CyCoinPackedMatrix.pxd", - }; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -859,7 +949,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -868,7 +958,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -877,7 +967,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -886,7 +976,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -895,7 +985,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -904,7 +994,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -913,7 +1003,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -922,7 +1012,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -931,7 +1021,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -940,7 +1030,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -949,7 +1039,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -958,7 +1048,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -967,7 +1057,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -976,7 +1066,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -985,7 +1075,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -994,7 +1084,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1003,7 +1093,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1012,7 +1102,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1021,7 +1111,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1030,7 +1120,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1067,7 +1157,7 @@ static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(do - struct __pyx_obj_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix; - struct __pyx_obj_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1076,7 +1166,7 @@ struct __pyx_obj_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1085,7 +1175,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1094,7 +1184,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1232,6 +1322,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -1239,6 +1330,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -1369,29 +1461,6 @@ static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_c - /* PatchInspect.proto */ - static PyObject* __Pyx_patch_inspect(PyObject* module); - --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -1438,6 +1507,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - #define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr - #endif - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -1523,8 +1595,10 @@ static void __Pyx_CppExn2PyErr() { - } - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -1625,7 +1699,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - #endif - - /* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -@@ -1682,8 +1756,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyCoinPackedMatrix' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix = 0; -@@ -1696,9 +1779,6 @@ int __pyx_module_is_main_cylp__cy__CyCoinMpsIO = 0; - - /* Implementation of 'cylp.cy.CyCoinMpsIO' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_T[] = "T"; - static const char __pyx_k_np[] = "np"; -@@ -1709,7 +1789,6 @@ static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_path[] = "path"; - static const char __pyx_k_test[] = "__test__"; - static const char __pyx_k_numpy[] = "numpy"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_scipy[] = "scipy"; - static const char __pyx_k_shape[] = "shape"; - static const char __pyx_k_utf_8[] = "utf-8"; -@@ -1730,12 +1809,10 @@ static const char __pyx_k_QPColumns[] = "QPColumns"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; - static const char __pyx_k_QPElements[] = "QPElements"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_dia_matrix[] = "dia_matrix"; - static const char __pyx_k_nVariables[] = "nVariables"; - static const char __pyx_k_CyCoinMpsIO[] = "CyCoinMpsIO"; - static const char __pyx_k_ImportError[] = "ImportError"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_currentframe[] = "currentframe"; - static const char __pyx_k_nConstraints[] = "nConstraints"; - static const char __pyx_k_scipy_sparse[] = "scipy.sparse"; -@@ -1749,34 +1826,23 @@ static const char __pyx_k_input_hs268_qps[] = "../input/hs268.qps"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_cylp_cy_CyCoinMpsIO[] = "cylp.cy.CyCoinMpsIO"; --static const char __pyx_k_cylp_cy_CyCoinMpsIO_pyx[] = "cylp\\cy\\CyCoinMpsIO.pyx"; -+static const char __pyx_k_cylp_cy_CyCoinMpsIO_pyx[] = "cylp/cy/CyCoinMpsIO.pyx"; - static const char __pyx_k_cylp_py_utils_sparseUtil[] = "cylp.py.utils.sparseUtil"; - static const char __pyx_k_CyCoinMpsIO_readMps_line_21[] = "CyCoinMpsIO.readMps (line 21)"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_Read_an_mps_file_Check_if_the_f[] = "\n Read an mps file. Check if the file is a QP symmetrisize its Hessian\n and store it.\n\n >>> import numpy as np\n >>> from cylp.cy import CyCoinMpsIO\n >>> from cylp.cy.CyCoinMpsIO import getQpsExample\n >>> problem = CyCoinMpsIO()\n >>> problem.readMps(getQpsExample())\n 0\n >>> problem.nVariables\n 5\n >>> problem.nConstraints\n 5\n >>> signs = problem.constraintSigns\n >>> [chr(i) for i in signs] == problem.nConstraints * ['G']\n True\n >>> c = problem.matrixByRow\n >>> (abs(c.elements -\n ... np.array([-1., -1., -1., -1., -1., 10., 10., -3.,\n ... 5., 4., -8., 1., -2., -5., 3., 8., -1., 2.,\n ... 5., -3., -4., -2., 3., -5., 1.])) <\n ... 10 ** -8).all()\n True\n >>> (c.indices ==\n ... np.array([0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1,\n ... 2, 3, 4, 0, 1, 2, 3, 4], dtype=np.int32)).all()\n True\n >>> (c.vectorStarts ==\n ... np.array([0, 5, 10, 15, 20, 25], dtype=np.int32)).all()\n True\n >>> (problem.rightHandSide ==\n ... np.array([-5., 20., -40., 11., -30.])).all()\n True\n >>> H = problem.Hessian.todense()\n >>> (abs(H -\n ... np.matrix([[20394., -24908., -2026., 3896., 658.],\n ... [-24908., 41818., -3466., -9828., -372.],\n ... [-2026., -3466., 3510., 2178., -348.],\n ... [3896., -9828., 2178., 3030., -44.],\n ... [658., -372., -348., -44., 54.]])) <\n ... 10 ** -8).all()\n True\n\n "; - static const char __pyx_k_This_module_interface_COIN_OR_s[] = "\nThis module interface COIN-OR's ``CoinMpsIO``. When you call\n:func:`cylp.cy.CyClpSimplex.readMps` then ``CoinMpsIO``'s ``readMps`` is\ncalled. The main reason why cylp interfaces this class is to be able to read\nan ``mps`` file without creating a Simplex object. This way it is possible to\nread a QP using CoinMpsIO and work on the elements of the problem, e.g. the\nHessian,...\n"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyCoinMpsIO; - static PyObject *__pyx_kp_u_CyCoinMpsIO_readMps_line_21; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; - static PyObject *__pyx_n_s_QPColumnStarts; - static PyObject *__pyx_n_s_QPColumns; - static PyObject *__pyx_n_s_QPElements; - static PyObject *__pyx_kp_u_Read_an_mps_file_Check_if_the_f; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_T; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_checkSymmetry; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_csc_matrixPlus; -@@ -1803,8 +1869,6 @@ static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_nConstraints; - static PyObject *__pyx_n_s_nVariables; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_no_default___reduce___due_to_non; - static PyObject *__pyx_n_s_np; - static PyObject *__pyx_n_s_numpy; -@@ -1812,7 +1876,6 @@ static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_os; - static PyObject *__pyx_n_s_path; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -1823,7 +1886,6 @@ static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_shape; - static PyObject *__pyx_n_s_sparse; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_kp_s_utf_8; - static int __pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO___cinit__(struct __pyx_obj_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_2readMps(struct __pyx_obj_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO *__pyx_v_self, PyObject *__pyx_v_filename); /* proto */ -@@ -1850,8 +1912,6 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_12nConstraints__ - static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_6__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_8__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_getQpsExample(CYTHON_UNUSED PyObject *__pyx_self); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_int_0; - static PyObject *__pyx_tuple_; -@@ -1859,12 +1919,7 @@ static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; - static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; --static PyObject *__pyx_tuple__10; --static PyObject *__pyx_codeobj__11; -+static PyObject *__pyx_codeobj__6; - /* Late includes */ - - /* "cylp/cy/CyCoinMpsIO.pyx":17 -@@ -1895,6 +1950,9 @@ static int __pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO___cinit__(struct __pyx - int __pyx_r; - __Pyx_RefNannyDeclarations - ICoinMpsIO *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyCoinMpsIO.pyx":18 -@@ -1984,6 +2042,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_2readMps(struct - char *__pyx_t_6; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("readMps", 0); - __Pyx_INCREF(__pyx_v_filename); - -@@ -2319,6 +2380,9 @@ static PyObject *__pyx_pw_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_5readQuadraticMp - static PyObject *__pyx_pw_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_5readQuadraticMps(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - CYTHON_UNUSED PyObject *__pyx_v_filename = 0; - PyObject *__pyx_v_checkSymmetry = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("readQuadraticMps (wrapper)", 0); -@@ -2380,6 +2444,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_4readQuadraticMp - __Pyx_RefNannyDeclarations - int __pyx_t_1; - PyObject *__pyx_t_2 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("readQuadraticMps", 0); - - /* "cylp/cy/CyCoinMpsIO.pyx":88 -@@ -3209,6 +3276,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_11matrixByRow___ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCoinMpsIO.pyx":147 -@@ -3300,6 +3370,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_11matrixByCol___ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCoinMpsIO.pyx":154 -@@ -3389,6 +3462,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_15objectiveOffse - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCoinMpsIO.pyx":161 -@@ -3449,6 +3525,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_10nVariables___g - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCoinMpsIO.pyx":165 -@@ -3509,6 +3588,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_12nConstraints__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCoinMpsIO.pyx":169 -@@ -3567,6 +3649,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_6__reduce_cython - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3621,6 +3706,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_11CyCoinMpsIO_8__setstate_cyth - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3688,6 +3776,9 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_getQpsExample(CYTHON_UNUSED Py - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - int __pyx_t_8; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("getQpsExample", 0); - - /* "cylp/cy/CyCoinMpsIO.pyx":176 -@@ -3870,863 +3961,7 @@ static PyObject *__pyx_pf_4cylp_2cy_11CyCoinMpsIO_getQpsExample(CYTHON_UNUSED Py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * -- * ndim = PyArray_NDIM(self) -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -- * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -- * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -- * -- * cdef int t -- */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -- * -- */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -- * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4738,9 +3973,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * - * cdef inline object PyArray_MultiIterNew1(a): - * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -@@ -4748,13 +3986,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - * cdef inline object PyArray_MultiIterNew2(a, b): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4773,7 +4011,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4785,9 +4023,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * - * cdef inline object PyArray_MultiIterNew2(a, b): - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -@@ -4795,13 +4036,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4820,7 +4061,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4832,9 +4073,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -@@ -4842,13 +4086,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4867,7 +4111,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4879,9 +4123,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -@@ -4889,13 +4136,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4914,7 +4161,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4926,9 +4173,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -@@ -4936,13 +4186,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - * cdef inline tuple PyDataType_SHAPE(dtype d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4961,7 +4211,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4975,7 +4225,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - int __pyx_t_1; - __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4985,7 +4235,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): - * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -@@ -4997,7 +4247,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -5006,12 +4256,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 - * return <tuple>d.subarray.shape - * else: - * return () # <<<<<<<<<<<<<< - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -+ * - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); -@@ -5020,7 +4270,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - goto __pyx_L0; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -5035,774 +4285,28 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 -+ * int _import_umath() except -1 - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -+ * Py_INCREF(base) # important to do this before stealing the reference below! -+ * PyArray_SetBaseObject(arr, base) - */ - --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -+static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_arr, PyObject *__pyx_v_base) { - __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -+ __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- goto __pyx_L13; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -- */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -- * -- * -- */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -- __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -- * int _import_umath() except -1 -- * -- * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -- * Py_INCREF(base) # important to do this before stealing the reference below! -- * PyArray_SetBaseObject(arr, base) -- */ -- --static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_arr, PyObject *__pyx_v_base) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("set_array_base", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -- * -- * cdef inline void set_array_base(ndarray arr, object base): -- * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -- * PyArray_SetBaseObject(arr, base) -+ * cdef inline void set_array_base(ndarray arr, object base): -+ * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -+ * PyArray_SetBaseObject(arr, base) - * - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5811,7 +4315,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5823,7 +4327,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5838,7 +4342,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5847,7 +4351,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5857,7 +4361,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5868,7 +4372,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5877,7 +4381,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5889,7 +4393,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5904,12 +4408,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -5923,13 +4427,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -5941,20 +4448,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5964,9 +4471,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5974,32 +4481,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -6010,12 +4517,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -6033,7 +4540,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -6052,9 +4559,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6070,16 +4580,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6093,7 +4603,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -6103,28 +4613,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6139,7 +4649,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -6162,7 +4672,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -6181,9 +4691,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6199,16 +4712,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6222,35 +4735,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6265,7 +4781,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -6288,6 +4804,180 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - return __pyx_r; - } - -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ - static PyObject *__pyx_tp_new_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { - struct __pyx_obj_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO *p; - PyObject *o; -@@ -6454,7 +5144,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO = { - sizeof(struct __pyx_obj_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -6507,6 +5202,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -6557,18 +5258,13 @@ static struct PyModuleDef __pyx_moduledef = { - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyCoinMpsIO, __pyx_k_CyCoinMpsIO, sizeof(__pyx_k_CyCoinMpsIO), 0, 0, 1, 1}, - {&__pyx_kp_u_CyCoinMpsIO_readMps_line_21, __pyx_k_CyCoinMpsIO_readMps_line_21, sizeof(__pyx_k_CyCoinMpsIO_readMps_line_21), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, - {&__pyx_n_s_QPColumnStarts, __pyx_k_QPColumnStarts, sizeof(__pyx_k_QPColumnStarts), 0, 0, 1, 1}, - {&__pyx_n_s_QPColumns, __pyx_k_QPColumns, sizeof(__pyx_k_QPColumns), 0, 0, 1, 1}, - {&__pyx_n_s_QPElements, __pyx_k_QPElements, sizeof(__pyx_k_QPElements), 0, 0, 1, 1}, - {&__pyx_kp_u_Read_an_mps_file_Check_if_the_f, __pyx_k_Read_an_mps_file_Check_if_the_f, sizeof(__pyx_k_Read_an_mps_file_Check_if_the_f), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_T, __pyx_k_T, sizeof(__pyx_k_T), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_checkSymmetry, __pyx_k_checkSymmetry, sizeof(__pyx_k_checkSymmetry), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_csc_matrixPlus, __pyx_k_csc_matrixPlus, sizeof(__pyx_k_csc_matrixPlus), 0, 0, 1, 1}, -@@ -6595,8 +5291,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_nConstraints, __pyx_k_nConstraints, sizeof(__pyx_k_nConstraints), 0, 0, 1, 1}, - {&__pyx_n_s_nVariables, __pyx_k_nVariables, sizeof(__pyx_k_nVariables), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, - {&__pyx_n_s_np, __pyx_k_np, sizeof(__pyx_k_np), 0, 0, 1, 1}, - {&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1}, -@@ -6604,7 +5298,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_os, __pyx_k_os, sizeof(__pyx_k_os), 0, 0, 1, 1}, - {&__pyx_n_s_path, __pyx_k_path, sizeof(__pyx_k_path), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -6615,16 +5308,12 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_shape, __pyx_k_shape, sizeof(__pyx_k_shape), 0, 0, 1, 1}, - {&__pyx_n_s_sparse, __pyx_k_sparse, sizeof(__pyx_k_sparse), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {&__pyx_kp_s_utf_8, __pyx_k_utf_8, sizeof(__pyx_k_utf_8), 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -6653,82 +5342,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - - /* "cylp/cy/CyCoinMpsIO.pyx":172 - * -@@ -6737,10 +5371,10 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - * ''' - * Return full path to a QPS example file for doctests - */ -- __pyx_tuple__10 = PyTuple_Pack(3, __pyx_n_s_os, __pyx_n_s_inspect, __pyx_n_s_curpath); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(1, 172, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__10); -- __Pyx_GIVEREF(__pyx_tuple__10); -- __pyx_codeobj__11 = (PyObject*)__Pyx_PyCode_New(0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__10, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_cylp_cy_CyCoinMpsIO_pyx, __pyx_n_s_getQpsExample, 172, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__11)) __PYX_ERR(1, 172, __pyx_L1_error) -+ __pyx_tuple__5 = PyTuple_Pack(3, __pyx_n_s_os, __pyx_n_s_inspect, __pyx_n_s_curpath); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(1, 172, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__5); -+ __Pyx_GIVEREF(__pyx_tuple__5); -+ __pyx_codeobj__6 = (PyObject*)__Pyx_PyCode_New(0, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__5, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_cylp_cy_CyCoinMpsIO_pyx, __pyx_n_s_getQpsExample, 172, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__6)) __PYX_ERR(1, 172, __pyx_L1_error) - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6790,6 +5424,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - if (PyType_Ready(&__pyx_type_4cylp_2cy_11CyCoinMpsIO_CyCoinMpsIO) < 0) __PYX_ERR(1, 16, __pyx_L1_error) -@@ -6812,6 +5449,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -6825,18 +5465,38 @@ static int __Pyx_modinit_type_import_code(void) { - __Pyx_ImportType_CheckSize_Warn); - if (!__pyx_ptype_7cpython_4type_type) __PYX_ERR(3, 9, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyCoinPackedMatrix"); if (unlikely(!__pyx_t_1)) __PYX_ERR(4, 27, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -6868,17 +5528,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6961,6 +5623,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyCoinMpsIO(PyObject *__pyx_pyinit - { - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -7008,11 +5673,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -7049,15 +5712,15 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ -@@ -7177,12 +5840,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -7468,7 +6131,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -7555,7 +6218,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -7692,7 +6355,7 @@ static int __Pyx_ParseOptionalKeywords( - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 -- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { -+ if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { -@@ -7719,7 +6382,7 @@ static int __Pyx_ParseOptionalKeywords( - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -7735,7 +6398,7 @@ static int __Pyx_ParseOptionalKeywords( - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -7985,7 +6648,7 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { - { - #if PY_MAJOR_VERSION >= 3 - if (level == -1) { -- if (strchr(__Pyx_MODULE_NAME, '.')) { -+ if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) { - module = PyImport_ImportModuleLevelObject( - name, global_dict, empty_dict, list, 1); - if (!module) { -@@ -8085,61 +6748,6 @@ static PyObject* __Pyx_patch_inspect(PyObject* module) { - return module; - } - --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -8345,6 +6953,28 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - } - #endif - -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -8372,43 +7002,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -8498,7 +7136,7 @@ static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -8528,7 +7166,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -8602,7 +7240,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -8625,30 +7263,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -8667,11 +7306,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -8703,37 +7347,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - Py_XDECREF(py_frame); - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- - /* CIntFromPyVerify */ - #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -@@ -8873,7 +7486,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -9028,7 +7640,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -9067,24 +7678,31 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - #endif - - /* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -+ if (sizeof(int) < sizeof(long)) { - return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -+ } else if (sizeof(int) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif - } - } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -+ if (sizeof(int) <= sizeof(long)) { - return PyInt_FromLong((long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - #endif - } -@@ -9092,14 +7710,21 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES v - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -+ return _PyLong_FromByteArray(bytes, sizeof(int), - little, !is_unsigned); - } - } - - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -9288,7 +7913,14 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - - /* CIntToPy */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { -@@ -9319,7 +7951,14 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { - - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -9870,6 +8509,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyCoinPackedMatrix.cpp b/cylp/cy/CyCoinPackedMatrix.cpp -index 536b013..df2b688 100644 ---- a/cylp/cy/CyCoinPackedMatrix.cpp -+++ b/cylp/cy/CyCoinPackedMatrix.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -611,7 +694,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include <stdio.h> - #include "ICoinPackedMatrix.hpp" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #ifdef _OPENMP - #include <omp.h> - #endif /* _OPENMP */ -@@ -708,6 +797,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -843,7 +933,7 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyCoinPackedMatrix.pyx", -+ "cylp/cy/CyCoinPackedMatrix.pyx", - "__init__.pxd", - "type.pxd", - }; -@@ -884,7 +974,7 @@ typedef struct { - } __Pyx_BufFmt_Context; - - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -893,7 +983,7 @@ typedef struct { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -902,7 +992,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -911,7 +1001,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -920,7 +1010,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -929,7 +1019,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -938,7 +1028,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -947,7 +1037,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -956,7 +1046,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -965,7 +1055,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -974,7 +1064,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -983,7 +1073,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -992,7 +1082,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1001,7 +1091,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1010,7 +1100,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1019,7 +1109,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1028,7 +1118,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1037,7 +1127,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1046,7 +1136,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1055,7 +1145,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1064,7 +1154,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1100,7 +1190,7 @@ static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(do - /*--- Type declarations ---*/ - struct __pyx_obj_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1109,7 +1199,7 @@ struct __pyx_obj_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1118,7 +1208,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1127,7 +1217,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1308,67 +1398,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* PyCFunctionFastCall.proto */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); --#else --#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) --#endif -- --/* PyFunctionFastCall.proto */ --#if CYTHON_FAST_PYCALL --#define __Pyx_PyFunction_FastCall(func, args, nargs)\ -- __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); --#else --#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) --#endif --#define __Pyx_BUILD_ASSERT_EXPR(cond)\ -- (sizeof(char [1 - 2*!(cond)]) - 1) --#ifndef Py_MEMBER_SIZE --#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) --#endif -- static size_t __pyx_pyframe_localsplus_offset = 0; -- #include "frameobject.h" -- #define __Pxy_PyFrame_Initialize_Offsets()\ -- ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ -- (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) -- #define __Pyx_PyFrame_GetLocalsplus(frame)\ -- (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) --#endif -- --/* PyObjectCallMethO.proto */ --#if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); --#endif -- --/* PyObjectCallOneArg.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); -- --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -1415,6 +1444,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - #define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr - #endif - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -1507,8 +1539,10 @@ typedef struct { - #endif - - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -1609,7 +1643,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - #endif - - /* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -@@ -1666,8 +1700,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyCoinPackedMatrix' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix = 0; -@@ -1679,16 +1722,12 @@ int __pyx_module_is_main_cylp__cy__CyCoinPackedMatrix = 0; - - /* Implementation of 'cylp.cy.CyCoinPackedMatrix' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_np[] = "np"; - static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_test[] = "__test__"; - static const char __pyx_k_numpy[] = "numpy"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_create[] = "create"; - static const char __pyx_k_import[] = "__import__"; - static const char __pyx_k_reduce[] = "__reduce__"; -@@ -1698,36 +1737,23 @@ static const char __pyx_k_getstate[] = "__getstate__"; - static const char __pyx_k_setstate[] = "__setstate__"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_colIndices[] = "colIndices"; - static const char __pyx_k_colOrdered[] = "colOrdered"; - static const char __pyx_k_newMaxSize[] = "newMaxSize"; - static const char __pyx_k_rowIndices[] = "rowIndices"; - static const char __pyx_k_ImportError[] = "ImportError"; - static const char __pyx_k_removeValue[] = "removeValue"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; - static const char __pyx_k_newMaxMajorDim[] = "newMaxMajorDim"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_CyCoinPackedMatrix[] = "CyCoinPackedMatrix"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyCoinPackedMatrix; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_colIndices; - static PyObject *__pyx_n_s_colOrdered; -@@ -1737,8 +1763,6 @@ static PyObject *__pyx_n_s_getstate; - static PyObject *__pyx_n_s_import; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_n_s_newMaxMajorDim; - static PyObject *__pyx_n_s_newMaxSize; - static PyObject *__pyx_kp_s_no_default___reduce___due_to_non; -@@ -1746,7 +1770,6 @@ static PyObject *__pyx_n_s_np; - static PyObject *__pyx_n_s_numpy; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -1755,7 +1778,6 @@ static PyObject *__pyx_n_s_rowIndices; - static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_n_s_vecInd; - static int __pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix___cinit__(struct __pyx_obj_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix *__pyx_v_self, PyObject *__pyx_v_colOrdered, PyArrayObject *__pyx_v_rowIndices, PyArrayObject *__pyx_v_colIndices, PyArrayObject *__pyx_v_elements); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_7indices___get__(struct __pyx_obj_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix *__pyx_v_self); /* proto */ -@@ -1773,8 +1795,6 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_10 - static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_12removeGaps(struct __pyx_obj_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix *__pyx_v_self, PyObject *__pyx_v_removeValue); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_14__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_16__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_float_neg_1_0; - static PyObject *__pyx_int_0; -@@ -1782,11 +1802,6 @@ static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; --static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; - /* Late includes */ - - /* "cylp/cy/CyCoinPackedMatrix.pyx":26 -@@ -1804,6 +1819,9 @@ static int __pyx_pw_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_1__cinit - PyArrayObject *__pyx_v_rowIndices = 0; - PyArrayObject *__pyx_v_colIndices = 0; - PyArrayObject *__pyx_v_elements = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - int __pyx_r; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); -@@ -1943,6 +1961,9 @@ static int __pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix___cinit_ - int __pyx_t_1; - int __pyx_t_2; - Py_ssize_t __pyx_t_3; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - __pyx_pybuffer_rowIndices.pybuffer.buf = NULL; - __pyx_pybuffer_rowIndices.refcount = 0; -@@ -2254,6 +2275,9 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_9n - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCoinPackedMatrix.pyx":56 -@@ -2314,6 +2338,9 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_8m - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCoinPackedMatrix.pyx":60 -@@ -2374,6 +2401,9 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_8m - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCoinPackedMatrix.pyx":64 -@@ -2434,6 +2464,9 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_12 - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyCoinPackedMatrix.pyx":68 -@@ -2484,6 +2517,9 @@ static PyObject *__pyx_pw_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_3r - PyObject *__pyx_v_newMaxMajorDim = 0; - PyObject *__pyx_v_newMaxSize = 0; - PyObject *__pyx_v_create = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("reserve (wrapper)", 0); -@@ -2560,6 +2596,9 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_2r - int __pyx_t_1; - int __pyx_t_2; - int __pyx_t_3; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("reserve", 0); - - /* "cylp/cy/CyCoinPackedMatrix.pyx":71 -@@ -2608,6 +2647,9 @@ static char __pyx_doc_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_4appen - static PyObject *__pyx_pw_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_5appendRow(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyArrayObject *__pyx_v_vecInd = 0; - PyArrayObject *__pyx_v_elements = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("appendRow (wrapper)", 0); -@@ -2705,6 +2747,9 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_4a - __Pyx_RefNannyDeclarations - int __pyx_t_1; - Py_ssize_t __pyx_t_2; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("appendRow", 0); - __pyx_pybuffer_vecInd.pybuffer.buf = NULL; - __pyx_pybuffer_vecInd.refcount = 0; -@@ -2820,6 +2865,9 @@ static char __pyx_doc_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_6appen - static PyObject *__pyx_pw_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_7appendCol(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyArrayObject *__pyx_v_vecInd = 0; - PyArrayObject *__pyx_v_elements = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("appendCol (wrapper)", 0); -@@ -2917,6 +2965,9 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_6a - __Pyx_RefNannyDeclarations - int __pyx_t_1; - Py_ssize_t __pyx_t_2; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("appendCol", 0); - __pyx_pybuffer_vecInd.pybuffer.buf = NULL; - __pyx_pybuffer_vecInd.refcount = 0; -@@ -3031,6 +3082,9 @@ static PyObject *__pyx_pw_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_9d - static char __pyx_doc_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_8dumpMatrix[] = "CyCoinPackedMatrix.dumpMatrix(self, char *s)"; - static PyObject *__pyx_pw_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_9dumpMatrix(PyObject *__pyx_v_self, PyObject *__pyx_arg_s) { - char *__pyx_v_s; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("dumpMatrix (wrapper)", 0); -@@ -3105,6 +3159,9 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_10 - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("hasGaps", 0); - - /* "cylp/cy/CyCoinPackedMatrix.pyx":102 -@@ -3153,6 +3210,9 @@ static PyObject *__pyx_pw_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_13 - static char __pyx_doc_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_12removeGaps[] = "CyCoinPackedMatrix.removeGaps(self, removeValue=-1.0)"; - static PyObject *__pyx_pw_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_13removeGaps(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_removeValue = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("removeGaps (wrapper)", 0); -@@ -3209,6 +3269,9 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_12 - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - double __pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("removeGaps", 0); - - /* "cylp/cy/CyCoinPackedMatrix.pyx":105 -@@ -3265,6 +3328,9 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_14 - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3320,6 +3386,9 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_16 - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3350,863 +3419,7 @@ static PyObject *__pyx_pf_4cylp_2cy_18CyCoinPackedMatrix_18CyCoinPackedMatrix_16 - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * -- * ndim = PyArray_NDIM(self) -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -- * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -- * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -- * -- * cdef int t -- */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -- * -- */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -- * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4218,9 +3431,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * - * cdef inline object PyArray_MultiIterNew1(a): - * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -@@ -4228,13 +3444,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - * cdef inline object PyArray_MultiIterNew2(a, b): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4253,7 +3469,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4265,9 +3481,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * - * cdef inline object PyArray_MultiIterNew2(a, b): - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -@@ -4275,13 +3494,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4300,7 +3519,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4312,9 +3531,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -@@ -4322,13 +3544,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4347,7 +3569,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4359,9 +3581,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -@@ -4369,13 +3594,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4394,7 +3619,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4406,9 +3631,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -@@ -4416,13 +3644,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - * cdef inline tuple PyDataType_SHAPE(dtype d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4441,7 +3669,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4455,7 +3683,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - int __pyx_t_1; - __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4465,7 +3693,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): - * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -@@ -4477,7 +3705,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4486,12 +3714,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 - * return <tuple>d.subarray.shape - * else: - * return () # <<<<<<<<<<<<<< - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -+ * - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); -@@ -4500,7 +3728,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - goto __pyx_L0; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4515,754 +3743,8 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- goto __pyx_L13; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -- */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -- * -- * -- */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -- __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -- * int _import_umath() except -1 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 -+ * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< - * Py_INCREF(base) # important to do this before stealing the reference below! -@@ -5273,7 +3755,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -5282,7 +3764,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5291,7 +3773,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5303,7 +3785,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5318,7 +3800,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5327,7 +3809,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5337,7 +3819,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5348,7 +3830,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5357,7 +3839,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5369,7 +3851,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5384,12 +3866,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -5403,13 +3885,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -5421,20 +3906,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5444,9 +3929,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5454,32 +3939,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5490,12 +3975,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -5513,7 +3998,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5532,9 +4017,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5550,16 +4038,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5573,7 +4061,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -5583,28 +4071,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5619,7 +4107,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5642,7 +4130,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5661,9 +4149,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5679,16 +4170,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5702,69 +4193,246 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 -+ * -+ * cdef inline int import_ufunc() except -1: -+ * try: # <<<<<<<<<<<<<< -+ * _import_umath() -+ * except Exception: -+ */ -+ __Pyx_XGIVEREF(__pyx_t_1); -+ __Pyx_XGIVEREF(__pyx_t_2); -+ __Pyx_XGIVEREF(__pyx_t_3); -+ __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -+ goto __pyx_L1_error; -+ __pyx_L8_try_end:; -+ } -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 -+ * raise ImportError("numpy.core.umath failed to import") -+ * -+ * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -+ * try: -+ * _import_umath() -+ */ -+ -+ /* function exit code */ -+ __pyx_r = 0; -+ goto __pyx_L0; -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_5); -+ __Pyx_XDECREF(__pyx_t_6); -+ __Pyx_XDECREF(__pyx_t_7); -+ __Pyx_XDECREF(__pyx_t_8); -+ __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = -1; -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: -- * try: # <<<<<<<<<<<<<< -- * _import_umath() -- * except Exception: -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ -- __Pyx_XGIVEREF(__pyx_t_1); -- __Pyx_XGIVEREF(__pyx_t_2); -- __Pyx_XGIVEREF(__pyx_t_3); -- __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -- goto __pyx_L1_error; -- __pyx_L8_try_end:; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_5); -- __Pyx_XDECREF(__pyx_t_6); -- __Pyx_XDECREF(__pyx_t_7); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; - __pyx_L0:; -- __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - -@@ -5849,7 +4517,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix - sizeof(struct __pyx_obj_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -5902,6 +4575,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -5951,13 +4630,8 @@ static struct PyModuleDef __pyx_moduledef = { - - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyCoinPackedMatrix, __pyx_k_CyCoinPackedMatrix, sizeof(__pyx_k_CyCoinPackedMatrix), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_colIndices, __pyx_k_colIndices, sizeof(__pyx_k_colIndices), 0, 0, 1, 1}, - {&__pyx_n_s_colOrdered, __pyx_k_colOrdered, sizeof(__pyx_k_colOrdered), 0, 0, 1, 1}, -@@ -5967,8 +4641,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_n_s_newMaxMajorDim, __pyx_k_newMaxMajorDim, sizeof(__pyx_k_newMaxMajorDim), 0, 0, 1, 1}, - {&__pyx_n_s_newMaxSize, __pyx_k_newMaxSize, sizeof(__pyx_k_newMaxSize), 0, 0, 1, 1}, - {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, -@@ -5976,7 +4648,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -5985,16 +4656,12 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {&__pyx_n_s_vecInd, __pyx_k_vecInd, sizeof(__pyx_k_vecInd), 0, 0, 1, 1}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -6023,82 +4690,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6149,6 +4761,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - if (PyType_Ready(&__pyx_type_4cylp_2cy_18CyCoinPackedMatrix_CyCoinPackedMatrix) < 0) __PYX_ERR(1, 7, __pyx_L1_error) -@@ -6171,6 +4786,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -6184,18 +4802,38 @@ static int __Pyx_modinit_type_import_code(void) { - __Pyx_ImportType_CheckSize_Warn); - if (!__pyx_ptype_7cpython_4type_type) __PYX_ERR(3, 9, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; -@@ -6222,17 +4860,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6314,6 +4954,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyCoinPackedMatrix(PyObject *__pyx - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -6361,11 +5004,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -6402,15 +5043,15 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ -@@ -6440,12 +5081,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -6554,7 +5195,7 @@ static int __Pyx_ParseOptionalKeywords( - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 -- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { -+ if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { -@@ -6581,7 +5222,7 @@ static int __Pyx_ParseOptionalKeywords( - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -6597,7 +5238,7 @@ static int __Pyx_ParseOptionalKeywords( - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -6748,6 +5389,7 @@ static void __Pyx_BufFmt_RaiseUnexpectedChar(char ch) { - } - static const char* __Pyx_BufFmt_DescribeTypeChar(char ch, int is_complex) { - switch (ch) { -+ case '?': return "'bool'"; - case 'c': return "'char'"; - case 'b': return "'signed char'"; - case 'B': return "'unsigned char'"; -@@ -6790,7 +5432,7 @@ static size_t __Pyx_BufFmt_TypeCharToStandardSize(char ch, int is_complex) { - } - static size_t __Pyx_BufFmt_TypeCharToNativeSize(char ch, int is_complex) { - switch (ch) { -- case 'c': case 'b': case 'B': case 's': case 'p': return 1; -+ case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; - case 'h': case 'H': return sizeof(short); - case 'i': case 'I': return sizeof(int); - case 'l': case 'L': return sizeof(long); -@@ -6874,7 +5516,7 @@ static char __Pyx_BufFmt_TypeCharToGroup(char ch, int is_complex) { - case 'b': case 'h': case 'i': - case 'l': case 'q': case 's': case 'p': - return 'I'; -- case 'B': case 'H': case 'I': case 'L': case 'Q': -+ case '?': case 'B': case 'H': case 'I': case 'L': case 'Q': - return 'U'; - case 'f': case 'd': case 'g': - return (is_complex ? 'C' : 'R'); -@@ -7018,9 +5660,7 @@ static PyObject * - __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) - { - const char *ts = *tsp; -- int i = 0, number; -- int ndim = ctx->head->field->type->ndim; --; -+ int i = 0, number, ndim; - ++ts; - if (ctx->new_count != 1) { - PyErr_SetString(PyExc_ValueError, -@@ -7028,6 +5668,7 @@ __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) - return NULL; - } - if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; -+ ndim = ctx->head->field->type->ndim; - while (*ts && *ts != ')') { - switch (*ts) { - case ' ': case '\f': case '\r': case '\n': case '\t': case '\v': continue; -@@ -7153,12 +5794,12 @@ static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const cha - return NULL; - } - CYTHON_FALLTHROUGH; -- case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': -+ case '?': case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': - case 'l': case 'L': case 'q': case 'Q': - case 'f': case 'd': case 'g': - case 'O': case 'p': -- if (ctx->enc_type == *ts && got_Z == ctx->is_complex && -- ctx->enc_packmode == ctx->new_packmode) { -+ if ((ctx->enc_type == *ts) && (got_Z == ctx->is_complex) && -+ (ctx->enc_packmode == ctx->new_packmode) && (!ctx->is_valid_array)) { - ctx->enc_count += ctx->new_count; - ctx->new_count = 1; - got_Z = 0; -@@ -7269,7 +5910,7 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -7444,263 +6085,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* PyCFunctionFastCall */ -- #if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { -- PyCFunctionObject *func = (PyCFunctionObject*)func_obj; -- PyCFunction meth = PyCFunction_GET_FUNCTION(func); -- PyObject *self = PyCFunction_GET_SELF(func); -- int flags = PyCFunction_GET_FLAGS(func); -- assert(PyCFunction_Check(func)); -- assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); -- assert(nargs >= 0); -- assert(nargs == 0 || args != NULL); -- /* _PyCFunction_FastCallDict() must not be called with an exception set, -- because it may clear it (directly or indirectly) and so the -- caller loses its exception */ -- assert(!PyErr_Occurred()); -- if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { -- return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); -- } else { -- return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); -- } --} --#endif -- --/* PyFunctionFastCall */ -- #if CYTHON_FAST_PYCALL --static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, -- PyObject *globals) { -- PyFrameObject *f; -- PyThreadState *tstate = __Pyx_PyThreadState_Current; -- PyObject **fastlocals; -- Py_ssize_t i; -- PyObject *result; -- assert(globals != NULL); -- /* XXX Perhaps we should create a specialized -- PyFrame_New() that doesn't take locals, but does -- take builtins without sanity checking them. -- */ -- assert(tstate != NULL); -- f = PyFrame_New(tstate, co, globals, NULL); -- if (f == NULL) { -- return NULL; -- } -- fastlocals = __Pyx_PyFrame_GetLocalsplus(f); -- for (i = 0; i < na; i++) { -- Py_INCREF(*args); -- fastlocals[i] = *args++; -- } -- result = PyEval_EvalFrameEx(f,0); -- ++tstate->recursion_depth; -- Py_DECREF(f); -- --tstate->recursion_depth; -- return result; --} --#if 1 || PY_VERSION_HEX < 0x030600B1 --static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { -- PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); -- PyObject *globals = PyFunction_GET_GLOBALS(func); -- PyObject *argdefs = PyFunction_GET_DEFAULTS(func); -- PyObject *closure; --#if PY_MAJOR_VERSION >= 3 -- PyObject *kwdefs; --#endif -- PyObject *kwtuple, **k; -- PyObject **d; -- Py_ssize_t nd; -- Py_ssize_t nk; -- PyObject *result; -- assert(kwargs == NULL || PyDict_Check(kwargs)); -- nk = kwargs ? PyDict_Size(kwargs) : 0; -- if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { -- return NULL; -- } -- if ( --#if PY_MAJOR_VERSION >= 3 -- co->co_kwonlyargcount == 0 && --#endif -- likely(kwargs == NULL || nk == 0) && -- co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { -- if (argdefs == NULL && co->co_argcount == nargs) { -- result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); -- goto done; -- } -- else if (nargs == 0 && argdefs != NULL -- && co->co_argcount == Py_SIZE(argdefs)) { -- /* function called with no arguments, but all parameters have -- a default value: use default values as arguments .*/ -- args = &PyTuple_GET_ITEM(argdefs, 0); -- result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); -- goto done; -- } -- } -- if (kwargs != NULL) { -- Py_ssize_t pos, i; -- kwtuple = PyTuple_New(2 * nk); -- if (kwtuple == NULL) { -- result = NULL; -- goto done; -- } -- k = &PyTuple_GET_ITEM(kwtuple, 0); -- pos = i = 0; -- while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { -- Py_INCREF(k[i]); -- Py_INCREF(k[i+1]); -- i += 2; -- } -- nk = i / 2; -- } -- else { -- kwtuple = NULL; -- k = NULL; -- } -- closure = PyFunction_GET_CLOSURE(func); --#if PY_MAJOR_VERSION >= 3 -- kwdefs = PyFunction_GET_KW_DEFAULTS(func); --#endif -- if (argdefs != NULL) { -- d = &PyTuple_GET_ITEM(argdefs, 0); -- nd = Py_SIZE(argdefs); -- } -- else { -- d = NULL; -- nd = 0; -- } --#if PY_MAJOR_VERSION >= 3 -- result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, kwdefs, closure); --#else -- result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, -- args, (int)nargs, -- k, (int)nk, -- d, (int)nd, closure); --#endif -- Py_XDECREF(kwtuple); --done: -- Py_LeaveRecursiveCall(); -- return result; --} --#endif --#endif -- --/* PyObjectCallMethO */ -- #if CYTHON_COMPILING_IN_CPYTHON --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { -- PyObject *self, *result; -- PyCFunction cfunc; -- cfunc = PyCFunction_GET_FUNCTION(func); -- self = PyCFunction_GET_SELF(func); -- if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -- return NULL; -- result = cfunc(self, arg); -- Py_LeaveRecursiveCall(); -- if (unlikely(!result) && unlikely(!PyErr_Occurred())) { -- PyErr_SetString( -- PyExc_SystemError, -- "NULL result without error in PyObject_Call"); -- } -- return result; --} --#endif -- --/* PyObjectCallOneArg */ -- #if CYTHON_COMPILING_IN_CPYTHON --static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_New(1); -- if (unlikely(!args)) return NULL; -- Py_INCREF(arg); -- PyTuple_SET_ITEM(args, 0, arg); -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { --#if CYTHON_FAST_PYCALL -- if (PyFunction_Check(func)) { -- return __Pyx_PyFunction_FastCall(func, &arg, 1); -- } --#endif -- if (likely(PyCFunction_Check(func))) { -- if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { -- return __Pyx_PyObject_CallMethO(func, arg); --#if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -- return __Pyx_PyCFunction_FastCall(func, &arg, 1); --#endif -- } -- } -- return __Pyx__PyObject_CallOneArg(func, arg); --} --#else --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_Pack(1, arg); -- if (unlikely(!args)) return NULL; -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --#endif -- --/* DictGetItem */ -- #if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ -- static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ -- static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ -- static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ -- static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -7906,6 +6290,28 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - } - #endif - -+/* PyObjectGetAttrStrNoError */ -+ static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -7933,43 +6339,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -8073,7 +6487,7 @@ static PyTypeObject *__Pyx_ImportType(PyObject *module, const char *module_name, - { - #if PY_MAJOR_VERSION >= 3 - if (level == -1) { -- if (strchr(__Pyx_MODULE_NAME, '.')) { -+ if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) { - module = PyImport_ImportModuleLevelObject( - name, global_dict, empty_dict, list, 1); - if (!module) { -@@ -8136,7 +6550,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -8166,7 +6580,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -8240,7 +6654,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -8263,30 +6677,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -8305,11 +6720,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -8344,7 +6764,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #if PY_MAJOR_VERSION < 3 - static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { - if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags); -- if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) return __pyx_pw_5numpy_7ndarray_1__getbuffer__(obj, view, flags); - PyErr_Format(PyExc_TypeError, "'%.200s' does not have the buffer interface", Py_TYPE(obj)->tp_name); - return -1; - } -@@ -8356,45 +6775,13 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return; - } - if ((0)) {} -- else if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) __pyx_pw_5numpy_7ndarray_3__releasebuffer__(obj, view); - view->obj = NULL; - Py_DECREF(obj); - } - #endif - - -- /* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- --/* CIntFromPyVerify */ -+ /* CIntFromPyVerify */ - #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) - #define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ -@@ -8533,7 +6920,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -8688,7 +7074,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -8727,24 +7112,31 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - #endif - - /* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -+ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -+ if (sizeof(int) < sizeof(long)) { - return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -+ } else if (sizeof(int) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif - } - } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -+ if (sizeof(int) <= sizeof(long)) { - return PyInt_FromLong((long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - #endif - } -@@ -8752,14 +7144,21 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -+ return _PyLong_FromByteArray(bytes, sizeof(int), - little, !is_unsigned); - } - } - - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -8948,7 +7347,14 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - - /* CIntToPy */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { -@@ -8979,7 +7385,14 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -9530,6 +7943,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyCutGeneratorPythonBase.cpp b/cylp/cy/CyCutGeneratorPythonBase.cpp -index 85efdde..55d29ea 100644 ---- a/cylp/cy/CyCutGeneratorPythonBase.cpp -+++ b/cylp/cy/CyCutGeneratorPythonBase.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -615,7 +698,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "ClpFactorization.hpp" - #include "IClpPrimalColumnPivotBase.h" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ClpDualRowPivot.hpp" - #include "IClpDualRowPivotBase.h" - #include "CoinModel.hpp" -@@ -643,11 +732,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "OsiSolverInterface.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "IClpSimplex.hpp" - #include "IOsiCuts.hpp" -@@ -749,6 +838,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -884,26 +974,26 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyCutGeneratorPythonBase.pyx", -+ "cylp/cy/CyCutGeneratorPythonBase.pyx", - "__init__.pxd", - "type.pxd", - "bool.pxd", - "complex.pxd", -- "cylp\\cy\\CyCoinIndexedVector.pxd", -- "cylp\\cy\\CyClpPrimalColumnPivotBase.pxd", -- "cylp\\cy\\CyClpDualRowPivotBase.pxd", -- "cylp\\cy\\CyCoinModel.pxd", -- "cylp\\cy\\CyCoinPackedMatrix.pxd", -- "cylp\\cy\\CyCgl.pxd", -- "cylp\\cy\\CyCbcNode.pxd", -- "cylp\\cy\\CyOsiSolverInterface.pxd", -- "cylp\\cy\\CyCbcModel.pxd", -- "cylp\\cy\\CyClpSimplex.pxd", -- "cylp\\cy\\CyOsiCuts.pxd", -- "cylp\\cy\\CyCglTreeInfo.pxd", -+ "cylp/cy/CyCoinIndexedVector.pxd", -+ "cylp/cy/CyClpPrimalColumnPivotBase.pxd", -+ "cylp/cy/CyClpDualRowPivotBase.pxd", -+ "cylp/cy/CyCoinModel.pxd", -+ "cylp/cy/CyCoinPackedMatrix.pxd", -+ "cylp/cy/CyCgl.pxd", -+ "cylp/cy/CyCbcNode.pxd", -+ "cylp/cy/CyOsiSolverInterface.pxd", -+ "cylp/cy/CyCbcModel.pxd", -+ "cylp/cy/CyClpSimplex.pxd", -+ "cylp/cy/CyOsiCuts.pxd", -+ "cylp/cy/CyCglTreeInfo.pxd", - }; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -912,7 +1002,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -921,7 +1011,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -930,7 +1020,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -939,7 +1029,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -948,7 +1038,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -957,7 +1047,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -966,7 +1056,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -975,7 +1065,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -984,7 +1074,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -993,7 +1083,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -1002,7 +1092,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1011,7 +1101,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1020,7 +1110,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1029,7 +1119,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1038,7 +1128,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1047,7 +1137,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1056,7 +1146,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1065,7 +1155,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1074,7 +1164,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1083,7 +1173,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1149,7 +1239,7 @@ struct __pyx_obj_4cylp_2cy_13CyCglTreeInfo_CyCglTreeInfo; - struct __pyx_obj_4cylp_2cy_21CyCglCutGeneratorBase_CyCglCutGeneratorBase; - struct __pyx_obj_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1158,7 +1248,7 @@ struct __pyx_obj_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1167,7 +1257,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1176,7 +1266,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1976,6 +2066,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -1983,6 +2074,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -2049,29 +2141,6 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -2144,6 +2213,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -2297,14 +2369,10 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #endif - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- --/* CIntFromPy.proto */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -@@ -2312,6 +2380,9 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -+/* CIntFromPy.proto */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+ - /* FastTypeChecks.proto */ - #if CYTHON_COMPILING_IN_CPYTHON - #define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -@@ -2435,8 +2506,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyClpDualRowPivotBase' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase = 0; -@@ -2502,16 +2582,12 @@ int __pyx_module_is_main_cylp__cy__CyCutGeneratorPythonBase = 0; - - /* Implementation of 'cylp.cy.CyCutGeneratorPythonBase' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_cut[] = "cut"; - static const char __pyx_k_init[] = "__init__"; - static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_test[] = "__test__"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_reduce[] = "__reduce__"; - static const char __pyx_k_isRange[] = "isRange"; - static const char __pyx_k_evaluate[] = "evaluate"; -@@ -2521,10 +2597,8 @@ static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_addRowCut[] = "addRowCut"; - static const char __pyx_k_cyLPModel[] = "cyLPModel"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_addColumnCut[] = "addColumnCut"; - static const char __pyx_k_generateCuts[] = "generateCuts"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; -@@ -2532,23 +2606,12 @@ static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_cutGeneratorObject[] = "cutGeneratorObject"; - static const char __pyx_k_CyCutGeneratorPythonBase[] = "CyCutGeneratorPythonBase"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_self_CppSelf_cannot_be_converted[] = "self.CppSelf cannot be converted to a Python object for pickling"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyCutGeneratorPythonBase; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_addColumnCut; - static PyObject *__pyx_n_s_addRowCut; - static PyObject *__pyx_n_s_cline_in_traceback; -@@ -2562,12 +2625,9 @@ static PyObject *__pyx_n_s_init; - static PyObject *__pyx_n_s_isRange; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -2575,23 +2635,15 @@ static PyObject *__pyx_kp_s_self_CppSelf_cannot_be_converted; - static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static int __pyx_pf_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorPythonBase___init__(struct __pyx_obj_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase *__pyx_v_self, PyObject *__pyx_v_cutGeneratorObject, PyObject *__pyx_v_cyLPModel); /* proto */ - static void __pyx_pf_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorPythonBase_2__dealloc__(struct __pyx_obj_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorPythonBase_4__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorPythonBase_6__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; --static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; - /* Late includes */ - - /* "cylp/cy/CyCutGeneratorPythonBase.pyx":8 -@@ -2607,6 +2659,9 @@ static int __pyx_pw_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorPythonB - static int __pyx_pw_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorPythonBase_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_cutGeneratorObject = 0; - PyObject *__pyx_v_cyLPModel = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - int __pyx_r; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); -@@ -2673,6 +2728,9 @@ static int __pyx_pf_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorPythonB - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__init__", 0); - - /* "cylp/cy/CyCutGeneratorPythonBase.pyx":9 -@@ -2833,6 +2891,9 @@ static PyObject *__pyx_f_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorPy - Py_ssize_t __pyx_t_8; - PyObject *(*__pyx_t_9)(PyObject *); - PyObject *__pyx_t_10 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("generateCuts", 0); - - /* "cylp/cy/CyCutGeneratorPythonBase.pyx":20 -@@ -3322,6 +3383,9 @@ static PyObject *__pyx_pf_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorP - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3377,6 +3441,9 @@ static PyObject *__pyx_pf_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorP - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3407,863 +3474,7 @@ static PyObject *__pyx_pf_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorP - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * -- * ndim = PyArray_NDIM(self) -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -- * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -- * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -- * -- * cdef int t -- */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -- * -- */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -- * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4275,9 +3486,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * - * cdef inline object PyArray_MultiIterNew1(a): - * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -@@ -4285,13 +3499,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - * cdef inline object PyArray_MultiIterNew2(a, b): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4310,7 +3524,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4322,9 +3536,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * - * cdef inline object PyArray_MultiIterNew2(a, b): - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -@@ -4332,13 +3549,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4357,7 +3574,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4369,9 +3586,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -@@ -4379,13 +3599,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4404,7 +3624,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4416,9 +3636,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -@@ -4426,13 +3649,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4451,7 +3674,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4463,9 +3686,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -@@ -4473,13 +3699,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - * cdef inline tuple PyDataType_SHAPE(dtype d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4498,7 +3724,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4512,7 +3738,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - int __pyx_t_1; - __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4522,7 +3748,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): - * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -@@ -4534,7 +3760,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4543,12 +3769,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 - * return <tuple>d.subarray.shape - * else: - * return () # <<<<<<<<<<<<<< - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -+ * - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); -@@ -4557,7 +3783,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - goto __pyx_L0; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4572,753 +3798,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- goto __pyx_L13; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -- */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -- * -- * -- */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -- __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5330,7 +3810,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -5339,7 +3819,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5348,7 +3828,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5360,7 +3840,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5375,7 +3855,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5384,7 +3864,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5394,7 +3874,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5405,7 +3885,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5414,7 +3894,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5426,7 +3906,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5441,12 +3921,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -5460,13 +3940,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -5478,20 +3961,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5501,9 +3984,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5511,32 +3994,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5547,12 +4030,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -5570,7 +4053,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5589,9 +4072,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5607,16 +4093,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5630,7 +4116,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -5640,28 +4126,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5676,7 +4162,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5699,7 +4185,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5718,9 +4204,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5736,16 +4225,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5759,35 +4248,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5802,7 +4294,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5824,6 +4316,180 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} - static struct __pyx_vtabstruct_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase __pyx_vtable_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase; - - static PyObject *__pyx_tp_new_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -5848,9 +4514,9 @@ static void __pyx_tp_dealloc_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGenerator - { - PyObject *etype, *eval, *etb; - PyErr_Fetch(&etype, &eval, &etb); -- ++Py_REFCNT(o); -+ __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); - __pyx_pw_4cylp_2cy_24CyCutGeneratorPythonBase_24CyCutGeneratorPythonBase_3__dealloc__(o); -- --Py_REFCNT(o); -+ __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); - PyErr_Restore(etype, eval, etb); - } - Py_CLEAR(p->cutGeneratorObject); -@@ -5897,7 +4563,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGenerat - sizeof(struct __pyx_obj_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGeneratorPythonBase, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -5950,6 +4621,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_24CyCutGeneratorPythonBase_CyCutGenerat - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -5999,13 +4676,8 @@ static struct PyModuleDef __pyx_moduledef = { - - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyCutGeneratorPythonBase, __pyx_k_CyCutGeneratorPythonBase, sizeof(__pyx_k_CyCutGeneratorPythonBase), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_addColumnCut, __pyx_k_addColumnCut, sizeof(__pyx_k_addColumnCut), 0, 0, 1, 1}, - {&__pyx_n_s_addRowCut, __pyx_k_addRowCut, sizeof(__pyx_k_addRowCut), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, -@@ -6019,12 +4691,9 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_isRange, __pyx_k_isRange, sizeof(__pyx_k_isRange), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -6032,15 +4701,11 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -6069,82 +4734,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6194,6 +4804,9 @@ static int __Pyx_modinit_function_export_code(void) { - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyCglCutGeneratorBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -6229,6 +4842,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -6264,18 +4880,38 @@ static int __Pyx_modinit_type_import_code(void) { - if (!__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase) __PYX_ERR(7, 67, __pyx_L1_error) - __pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase = (struct __pyx_vtabstruct_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase*)__Pyx_GetVtable(__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase->tp_dict); if (unlikely(!__pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase)) __PYX_ERR(7, 67, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(8, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -6390,12 +5026,16 @@ static int __Pyx_modinit_variable_import_code(void) { - static int __Pyx_modinit_function_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); - /*--- Function import code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyCglCutGeneratorBase"); if (!__pyx_t_1) __PYX_ERR(1, 1, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); - if (__Pyx_ImportFunction(__pyx_t_1, "RunGenerateCuts", (void (**)(void))&__pyx_f_4cylp_2cy_21CyCglCutGeneratorBase_RunGenerateCuts, "void (void *, OsiSolverInterface *, CppOsiCuts *, CglTreeInfo)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunCglClone", (void (**)(void))&__pyx_f_4cylp_2cy_21CyCglCutGeneratorBase_RunCglClone, "CglCutGenerator *(void *)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) -- Py_DECREF(__pyx_t_1); __pyx_t_1 = 0; -+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6405,17 +5045,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6497,6 +5139,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyCutGeneratorPythonBase(PyObject - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -6544,11 +5189,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -6585,17 +5228,17 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); -- if (unlikely(__Pyx_modinit_function_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_function_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Execution code ---*/ - #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) - if (__Pyx_patch_abc() < 0) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -6611,12 +5254,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -6725,7 +5368,7 @@ static int __Pyx_ParseOptionalKeywords( - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 -- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { -+ if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { -@@ -6752,7 +5395,7 @@ static int __Pyx_ParseOptionalKeywords( - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -6768,7 +5411,7 @@ static int __Pyx_ParseOptionalKeywords( - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -6977,7 +5620,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -7064,7 +5707,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -7287,61 +5930,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -7680,6 +6268,28 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable) { - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -7707,43 +6317,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -7784,7 +6402,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -7814,7 +6432,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -7888,7 +6506,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -7911,30 +6529,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -7953,11 +6572,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -8106,7 +6730,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -8261,7 +6884,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -8300,24 +6922,31 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #endif - - /* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -+ if (sizeof(long) < sizeof(long)) { - return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -+ } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif - } - } else { -- if (sizeof(int) <= sizeof(long)) { -+ if (sizeof(long) <= sizeof(long)) { - return PyInt_FromLong((long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - #endif - } -@@ -8325,7 +6954,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -+ return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); - } - } -@@ -8352,51 +6981,27 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - return (target_type) value;\ - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+/* CIntFromPy */ -+static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(int) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) -+ if (sizeof(long) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (int) val; -+ return (long) val; - } - } else - #endif -@@ -8405,32 +7010,32 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) -+ case 0: return (long) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -- return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -+ return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -- return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -+ return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -- return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -+ return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; -@@ -8444,86 +7049,86 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (int) -1; -+ return (long) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(int) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(long) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) -+ case 0: return (long) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) - case -2: -- if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(int) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -+ if (sizeof(long) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -8532,7 +7137,7 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- int val; -+ long val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -8552,71 +7157,47 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - return val; - } - #endif -- return (int) -1; -+ return (long) -1; - } - } else { -- int val; -+ long val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (int) -1; -- val = __Pyx_PyInt_As_int(tmp); -+ if (!tmp) return (long) -1; -+ val = __Pyx_PyInt_As_long(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to int"); -- return (int) -1; -+ "value too large to convert to long"); -+ return (long) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to int"); -- return (int) -1; -+ "can't convert negative value to long"); -+ return (long) -1; - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(long) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(long) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+/* CIntFromPy */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(long) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(long), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ --static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(long) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) -+ if (sizeof(int) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (long) val; -+ return (int) val; - } - } else - #endif -@@ -8625,32 +7206,32 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) -+ case 0: return (int) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -- return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -+ return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -- return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -+ return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -- return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -+ return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; -@@ -8664,86 +7245,86 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (long) -1; -+ return (int) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(long) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(int) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) -+ case 0: return (int) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) - case -2: -- if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(long) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) -+ if (sizeof(int) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -8752,7 +7333,7 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- long val; -+ int val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -8772,24 +7353,24 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - return val; - } - #endif -- return (long) -1; -+ return (int) -1; - } - } else { -- long val; -+ int val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (long) -1; -- val = __Pyx_PyInt_As_long(tmp); -+ if (!tmp) return (int) -1; -+ val = __Pyx_PyInt_As_int(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to long"); -- return (long) -1; -+ "value too large to convert to int"); -+ return (int) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to long"); -- return (long) -1; -+ "can't convert negative value to int"); -+ return (int) -1; - } - - /* FastTypeChecks */ -@@ -9210,6 +7791,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyDantzigPivot.cpp b/cylp/cy/CyDantzigPivot.cpp -index 93b3950..9b50d3b 100644 ---- a/cylp/cy/CyDantzigPivot.cpp -+++ b/cylp/cy/CyDantzigPivot.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -612,7 +695,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "pythread.h" - #include "ICoinIndexedVector.hpp" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ClpDualRowPivot.hpp" - #include "ClpFactorization.hpp" - #include "IClpDualRowPivotBase.h" -@@ -641,11 +730,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "OsiSolverInterface.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "IClpPrimalColumnPivotBase.h" - #include "ClpPrimalColumnPivot.hpp" -@@ -746,6 +835,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -881,23 +971,23 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyDantzigPivot.pyx", -+ "cylp/cy/CyDantzigPivot.pyx", - "__init__.pxd", - "type.pxd", - "bool.pxd", - "complex.pxd", -- "cylp\\cy\\CyCoinIndexedVector.pxd", -- "cylp\\cy\\CyClpDualRowPivotBase.pxd", -- "cylp\\cy\\CyCoinModel.pxd", -- "cylp\\cy\\CyCoinPackedMatrix.pxd", -- "cylp\\cy\\CyCgl.pxd", -- "cylp\\cy\\CyCbcNode.pxd", -- "cylp\\cy\\CyOsiSolverInterface.pxd", -- "cylp\\cy\\CyCbcModel.pxd", -- "cylp\\cy\\CyClpSimplex.pxd", -+ "cylp/cy/CyCoinIndexedVector.pxd", -+ "cylp/cy/CyClpDualRowPivotBase.pxd", -+ "cylp/cy/CyCoinModel.pxd", -+ "cylp/cy/CyCoinPackedMatrix.pxd", -+ "cylp/cy/CyCgl.pxd", -+ "cylp/cy/CyCbcNode.pxd", -+ "cylp/cy/CyOsiSolverInterface.pxd", -+ "cylp/cy/CyCbcModel.pxd", -+ "cylp/cy/CyClpSimplex.pxd", - }; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -906,7 +996,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -915,7 +1005,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -924,7 +1014,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -933,7 +1023,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -942,7 +1032,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -951,7 +1041,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -960,7 +1050,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -969,7 +1059,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -978,7 +1068,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -987,7 +1077,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -996,7 +1086,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1005,7 +1095,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1014,7 +1104,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1023,7 +1113,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1032,7 +1122,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1041,7 +1131,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1050,7 +1140,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1059,7 +1149,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1068,7 +1158,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1077,7 +1167,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1140,7 +1230,7 @@ struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus; - struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase; - struct __pyx_obj_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1149,7 +1239,7 @@ struct __pyx_obj_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1158,7 +1248,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1167,7 +1257,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1882,6 +1972,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -1889,6 +1980,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -2048,26 +2140,6 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -2140,6 +2212,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -2172,11 +2247,10 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); - static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -2277,11 +2351,14 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - #endif - - /* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); - -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+ - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -@@ -2406,8 +2483,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyClpDualRowPivotBase' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase = 0; -@@ -2468,9 +2554,6 @@ int __pyx_module_is_main_cylp__cy__CyDantzigPivot = 0; - - /* Implementation of 'cylp.cy.CyDantzigPivot' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_np[] = "np"; - static const char __pyx_k_init[] = "__init__"; -@@ -2480,7 +2563,6 @@ static const char __pyx_k_test[] = "__test__"; - static const char __pyx_k_basic[] = "basic"; - static const char __pyx_k_clear[] = "clear"; - static const char __pyx_k_numpy[] = "numpy"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_shape[] = "shape"; - static const char __pyx_k_where[] = "where"; - static const char __pyx_k_argmax[] = "argmax"; -@@ -2498,14 +2580,12 @@ static const char __pyx_k_nElements[] = "nElements"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; - static const char __pyx_k_varIsFree[] = "varIsFree"; - static const char __pyx_k_varStatus[] = "varStatus"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_nVariables[] = "nVariables"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_superBasic[] = "superBasic"; - static const char __pyx_k_ImportError[] = "ImportError"; - static const char __pyx_k_varNotBasic[] = "varNotBasic"; - static const char __pyx_k_varNotFixed[] = "varNotFixed"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_atLowerBound[] = "atLowerBound"; - static const char __pyx_k_atUpperBound[] = "atUpperBound"; - static const char __pyx_k_reducedCosts[] = "reducedCosts"; -@@ -2520,23 +2600,12 @@ static const char __pyx_k_varIsAtLowerBound[] = "varIsAtLowerBound"; - static const char __pyx_k_varIsAtUpperBound[] = "varIsAtUpperBound"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_updateColumnTranspose[] = "updateColumnTranspose"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_self_CppSelf_cannot_be_converted[] = "self.CppSelf cannot be converted to a Python object for pickling"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyDantzigPivot; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_argWeightedMax; - static PyObject *__pyx_n_s_argmax; - static PyObject *__pyx_n_s_atLowerBound; -@@ -2557,14 +2626,11 @@ static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_nElements; - static PyObject *__pyx_n_s_nVariables; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_n_s_np; - static PyObject *__pyx_n_s_numpy; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -2576,7 +2642,6 @@ static PyObject *__pyx_n_s_shape; - static PyObject *__pyx_n_s_superBasic; - static PyObject *__pyx_n_s_test; - static PyObject *__pyx_n_s_transposeTimes; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_n_s_updateColumnTranspose; - static PyObject *__pyx_n_s_varIsAtLowerBound; - static PyObject *__pyx_n_s_varIsAtUpperBound; -@@ -2589,8 +2654,6 @@ static PyObject *__pyx_n_s_where; - static int __pyx_pf_4cylp_2cy_14CyDantzigPivot_14CyDantzigPivot___init__(struct __pyx_obj_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot *__pyx_v_self, PyObject *__pyx_v_cyModel); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_14CyDantzigPivot_14CyDantzigPivot_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_14CyDantzigPivot_14CyDantzigPivot_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_int_0; - static PyObject *__pyx_int_1; -@@ -2599,11 +2662,6 @@ static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; --static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; - /* Late includes */ - - /* "cylp/cy/CyDantzigPivot.pyx":15 -@@ -2618,6 +2676,9 @@ static PyObject *__pyx_tuple__9; - static int __pyx_pw_4cylp_2cy_14CyDantzigPivot_14CyDantzigPivot_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ - static int __pyx_pw_4cylp_2cy_14CyDantzigPivot_14CyDantzigPivot_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_cyModel = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - int __pyx_r; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); -@@ -2670,6 +2731,9 @@ static int __pyx_pf_4cylp_2cy_14CyDantzigPivot_14CyDantzigPivot___init__(struct - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__init__", 0); - - /* "cylp/cy/CyDantzigPivot.pyx":16 -@@ -2770,6 +2834,9 @@ static PyObject *__pyx_f_4cylp_2cy_14CyDantzigPivot_14CyDantzigPivot_pivotColumn - PyObject *__pyx_t_8 = NULL; - double __pyx_t_9; - PyObject *__pyx_t_10 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("pivotColumn", 0); - - /* "cylp/cy/CyDantzigPivot.pyx":22 -@@ -3764,6 +3831,9 @@ static PyObject *__pyx_pf_4cylp_2cy_14CyDantzigPivot_14CyDantzigPivot_2__reduce_ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3819,6 +3889,9 @@ static PyObject *__pyx_pf_4cylp_2cy_14CyDantzigPivot_14CyDantzigPivot_4__setstat - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3849,1918 +3922,331 @@ static PyObject *__pyx_pf_4cylp_2cy_14CyDantzigPivot_14CyDantzigPivot_4__setstat - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t -+ * -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * - */ - --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -+ PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): -+ * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< - * -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): - */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t - * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) - */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") - */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. - */ -- goto __pyx_L9; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * - */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< - * -- * cdef int t -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- * info.obj = self # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * if not PyDataType_HASFIELDS(descr): - */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< - * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -+ * cdef inline tuple PyDataType_SHAPE(dtype d): - */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): - */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -- * -- * cdef inline object PyArray_MultiIterNew1(a): -- * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -- * else: -- * return () -- */ -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -- __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -- * return <tuple>d.subarray.shape -- * else: -- * return () # <<<<<<<<<<<<<< -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -- */ -- /*else*/ { -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(__pyx_empty_tuple); -- __pyx_r = __pyx_empty_tuple; -- goto __pyx_L0; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- -- /* function exit code */ -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -+ * -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ int __pyx_t_1; -+ __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ -- goto __pyx_L13; -- } -+ __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -+ if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -+ * else: -+ * return () - */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -+ __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ - } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 -+ * return <tuple>d.subarray.shape -+ * else: -+ * return () # <<<<<<<<<<<<<< - * - * - */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -+ /*else*/ { -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(__pyx_empty_tuple); -+ __pyx_r = __pyx_empty_tuple; -+ goto __pyx_L0; -+ } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ - - /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; - __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -+ __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5772,7 +4258,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -5781,7 +4267,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5790,7 +4276,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5802,7 +4288,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5817,7 +4303,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5826,7 +4312,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5836,7 +4322,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5847,7 +4333,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5856,7 +4342,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5868,7 +4354,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5883,12 +4369,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -5902,13 +4388,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -5920,20 +4409,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5943,9 +4432,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5953,32 +4442,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5989,12 +4478,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -6012,7 +4501,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -6031,9 +4520,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6049,16 +4541,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6072,7 +4564,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -6082,28 +4574,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6118,7 +4610,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -6141,7 +4633,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -6160,9 +4652,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6178,16 +4673,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6201,69 +4696,246 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -- * _import_umath() -- * except Exception: -- * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 -+ * _import_umath() -+ * except Exception: -+ * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: -+ */ -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) -+ __Pyx_GOTREF(__pyx_t_8); -+ __Pyx_Raise(__pyx_t_8, 0, 0, 0); -+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -+ __PYX_ERR(2, 957, __pyx_L5_except_error) -+ } -+ goto __pyx_L5_except_error; -+ __pyx_L5_except_error:; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 -+ * -+ * cdef inline int import_ufunc() except -1: -+ * try: # <<<<<<<<<<<<<< -+ * _import_umath() -+ * except Exception: -+ */ -+ __Pyx_XGIVEREF(__pyx_t_1); -+ __Pyx_XGIVEREF(__pyx_t_2); -+ __Pyx_XGIVEREF(__pyx_t_3); -+ __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -+ goto __pyx_L1_error; -+ __pyx_L8_try_end:; -+ } -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 -+ * raise ImportError("numpy.core.umath failed to import") -+ * -+ * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -+ * try: -+ * _import_umath() -+ */ -+ -+ /* function exit code */ -+ __pyx_r = 0; -+ goto __pyx_L0; -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_5); -+ __Pyx_XDECREF(__pyx_t_6); -+ __Pyx_XDECREF(__pyx_t_7); -+ __Pyx_XDECREF(__pyx_t_8); -+ __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = -1; -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_Raise(__pyx_t_8, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -- } -- goto __pyx_L5_except_error; -- __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * - * -- * cdef inline int import_ufunc() except -1: -- * try: # <<<<<<<<<<<<<< -- * _import_umath() -- * except Exception: - */ -- __Pyx_XGIVEREF(__pyx_t_1); -- __Pyx_XGIVEREF(__pyx_t_2); -- __Pyx_XGIVEREF(__pyx_t_3); -- __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -- goto __pyx_L1_error; -- __pyx_L8_try_end:; -- } -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object - */ - - /* function exit code */ -- __pyx_r = 0; -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); - goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_5); -- __Pyx_XDECREF(__pyx_t_6); -- __Pyx_XDECREF(__pyx_t_7); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ - __pyx_L0:; -- __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - static struct __pyx_vtabstruct_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot __pyx_vtable_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot; -@@ -6311,7 +4983,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot = { - sizeof(struct __pyx_obj_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -6364,6 +5041,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -6413,13 +5096,8 @@ static struct PyModuleDef __pyx_moduledef = { - - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyDantzigPivot, __pyx_k_CyDantzigPivot, sizeof(__pyx_k_CyDantzigPivot), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_argWeightedMax, __pyx_k_argWeightedMax, sizeof(__pyx_k_argWeightedMax), 0, 0, 1, 1}, - {&__pyx_n_s_argmax, __pyx_k_argmax, sizeof(__pyx_k_argmax), 0, 0, 1, 1}, - {&__pyx_n_s_atLowerBound, __pyx_k_atLowerBound, sizeof(__pyx_k_atLowerBound), 0, 0, 1, 1}, -@@ -6440,14 +5118,11 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_nElements, __pyx_k_nElements, sizeof(__pyx_k_nElements), 0, 0, 1, 1}, - {&__pyx_n_s_nVariables, __pyx_k_nVariables, sizeof(__pyx_k_nVariables), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_n_s_np, __pyx_k_np, sizeof(__pyx_k_np), 0, 0, 1, 1}, - {&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -6459,7 +5134,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_superBasic, __pyx_k_superBasic, sizeof(__pyx_k_superBasic), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, - {&__pyx_n_s_transposeTimes, __pyx_k_transposeTimes, sizeof(__pyx_k_transposeTimes), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {&__pyx_n_s_updateColumnTranspose, __pyx_k_updateColumnTranspose, sizeof(__pyx_k_updateColumnTranspose), 0, 0, 1, 1}, - {&__pyx_n_s_varIsAtLowerBound, __pyx_k_varIsAtLowerBound, sizeof(__pyx_k_varIsAtLowerBound), 0, 0, 1, 1}, - {&__pyx_n_s_varIsAtUpperBound, __pyx_k_varIsAtUpperBound, sizeof(__pyx_k_varIsAtUpperBound), 0, 0, 1, 1}, -@@ -6473,10 +5147,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -6505,82 +5176,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6633,6 +5249,9 @@ static int __Pyx_modinit_function_export_code(void) { - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpPrimalColumnPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -6669,6 +5288,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -6698,18 +5320,38 @@ static int __Pyx_modinit_type_import_code(void) { - if (!__pyx_ptype_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector) __PYX_ERR(6, 22, __pyx_L1_error) - __pyx_vtabptr_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector = (struct __pyx_vtabstruct_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector*)__Pyx_GetVtable(__pyx_ptype_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector->tp_dict); if (unlikely(!__pyx_vtabptr_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector)) __PYX_ERR(6, 22, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(7, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -6812,13 +5454,17 @@ static int __Pyx_modinit_variable_import_code(void) { - static int __Pyx_modinit_function_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); - /*--- Function import code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpPrimalColumnPivotBase"); if (!__pyx_t_1) __PYX_ERR(1, 1, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); - if (__Pyx_ImportFunction(__pyx_t_1, "RunPivotColumn", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunPivotColumn, "int (void *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunClone", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunClone, "ClpPrimalColumnPivot *(void *, int)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunSaveWeights", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunSaveWeights, "void (void *, IClpSimplex *, int)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) -- Py_DECREF(__pyx_t_1); __pyx_t_1 = 0; -+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6828,17 +5474,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6920,6 +5568,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyDantzigPivot(PyObject *__pyx_pyi - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -6967,11 +5618,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -7008,17 +5657,17 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); -- if (unlikely(__Pyx_modinit_function_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_function_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Execution code ---*/ - #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) - if (__Pyx_patch_abc() < 0) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -7076,12 +5725,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -7190,7 +5839,7 @@ static int __Pyx_ParseOptionalKeywords( - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 -- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { -+ if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { -@@ -7217,7 +5866,7 @@ static int __Pyx_ParseOptionalKeywords( - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -7233,7 +5882,7 @@ static int __Pyx_ParseOptionalKeywords( - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -7455,7 +6104,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -7542,7 +6191,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -7866,7 +6515,7 @@ static PyObject *__Pyx_PyLong_AbsNeg(PyObject *n) { - { - PyObject *copy = _PyLong_Copy((PyLongObject*)n); - if (likely(copy)) { -- Py_SIZE(copy) = -(Py_SIZE(copy)); -+ __Pyx_SET_SIZE(copy, -Py_SIZE(copy)); - } - return copy; - } -@@ -8059,48 +6708,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -8439,6 +7046,28 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable) { - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -8466,43 +7095,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -8545,7 +7182,7 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { - { - #if PY_MAJOR_VERSION >= 3 - if (level == -1) { -- if (strchr(__Pyx_MODULE_NAME, '.')) { -+ if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) { - module = PyImport_ImportModuleLevelObject( - name, global_dict, empty_dict, list, 1); - if (!module) { -@@ -8582,7 +7219,7 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -8612,7 +7249,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -8686,7 +7323,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -8709,30 +7346,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -8751,11 +7389,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -8787,37 +7430,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - Py_XDECREF(py_frame); - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(long) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(long) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(long) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(long), -- little, !is_unsigned); -- } --} -- - /* CIntFromPyVerify */ - #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -@@ -8840,37 +7452,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { - return (target_type) value;\ - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- - /* Declarations */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus -@@ -8988,7 +7569,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -9143,7 +7723,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -9182,24 +7761,31 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - #endif - - /* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -+ if (sizeof(long) < sizeof(long)) { - return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -+ } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif - } - } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -+ if (sizeof(long) <= sizeof(long)) { - return PyInt_FromLong((long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - #endif - } -@@ -9207,14 +7793,21 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES v - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -+ return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); - } - } - - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -9401,9 +7994,54 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - return (int) -1; - } - -+/* CIntToPy */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(int) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); -+ } -+} -+ - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -10008,6 +8646,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyDualPivotPythonBase.cpp b/cylp/cy/CyDualPivotPythonBase.cpp -index df769b2..b5a8e15 100644 ---- a/cylp/cy/CyDualPivotPythonBase.cpp -+++ b/cylp/cy/CyDualPivotPythonBase.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -610,7 +693,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include <string.h> - #include <stdio.h> - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "pythread.h" - #include "ICoinIndexedVector.hpp" - #include "ClpPrimalColumnPivot.hpp" -@@ -641,11 +730,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "OsiSolverInterface.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "ClpDualRowPivot.hpp" - #include "IClpSimplex.hpp" -@@ -746,6 +835,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -881,20 +971,20 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyDualPivotPythonBase.pyx", -+ "cylp/cy/CyDualPivotPythonBase.pyx", - "__init__.pxd", - "type.pxd", - "bool.pxd", - "complex.pxd", -- "cylp\\cy\\CyCoinIndexedVector.pxd", -- "cylp\\cy\\CyClpPrimalColumnPivotBase.pxd", -- "cylp\\cy\\CyCoinModel.pxd", -- "cylp\\cy\\CyCoinPackedMatrix.pxd", -- "cylp\\cy\\CyCgl.pxd", -- "cylp\\cy\\CyCbcNode.pxd", -- "cylp\\cy\\CyOsiSolverInterface.pxd", -- "cylp\\cy\\CyCbcModel.pxd", -- "cylp\\cy\\CyClpSimplex.pxd", -+ "cylp/cy/CyCoinIndexedVector.pxd", -+ "cylp/cy/CyClpPrimalColumnPivotBase.pxd", -+ "cylp/cy/CyCoinModel.pxd", -+ "cylp/cy/CyCoinPackedMatrix.pxd", -+ "cylp/cy/CyCgl.pxd", -+ "cylp/cy/CyCbcNode.pxd", -+ "cylp/cy/CyOsiSolverInterface.pxd", -+ "cylp/cy/CyCbcModel.pxd", -+ "cylp/cy/CyClpSimplex.pxd", - }; - /* BufferFormatStructs.proto */ - #define IS_UNSIGNED(type) (((type) -1) > 0) -@@ -933,7 +1023,7 @@ typedef struct { - } __Pyx_BufFmt_Context; - - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -942,7 +1032,7 @@ typedef struct { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -951,7 +1041,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -960,7 +1050,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -969,7 +1059,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -978,7 +1068,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -987,7 +1077,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -996,7 +1086,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -1005,7 +1095,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -1014,7 +1104,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -1023,7 +1113,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -1032,7 +1122,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1041,7 +1131,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1050,7 +1140,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1059,7 +1149,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1068,7 +1158,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1077,7 +1167,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1086,7 +1176,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1095,7 +1185,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1104,7 +1194,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1113,7 +1203,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1176,7 +1266,7 @@ struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus; - struct __pyx_obj_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase; - struct __pyx_obj_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPythonBase; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1185,7 +1275,7 @@ struct __pyx_obj_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPythonBase; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1194,7 +1284,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1203,7 +1293,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1916,6 +2006,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -1923,6 +2014,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -2019,29 +2111,6 @@ static void __Pyx_RaiseBufferIndexError(int axis); - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -2114,6 +2183,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -2290,14 +2362,10 @@ typedef struct { - #endif - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- --/* CIntFromPy.proto */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -@@ -2305,6 +2373,9 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -+/* CIntFromPy.proto */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+ - /* FastTypeChecks.proto */ - #if CYTHON_COMPILING_IN_CPYTHON - #define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -@@ -2422,8 +2493,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy' */ - -@@ -2491,25 +2571,19 @@ int __pyx_module_is_main_cylp__cy__CyDualPivotPythonBase = 0; - - /* Implementation of 'cylp.cy.CyDualPivotPythonBase' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_init[] = "__init__"; - static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_test[] = "__test__"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_reduce[] = "__reduce__"; - static const char __pyx_k_getstate[] = "__getstate__"; - static const char __pyx_k_pivotRow[] = "pivotRow"; - static const char __pyx_k_setstate[] = "__setstate__"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; - static const char __pyx_k_updateWeights[] = "updateWeights"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; -@@ -2517,36 +2591,22 @@ static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_updatePrimalSolution[] = "updatePrimalSolution"; - static const char __pyx_k_CyDualPivotPythonBase[] = "CyDualPivotPythonBase"; - static const char __pyx_k_dualPivotMethodObject[] = "dualPivotMethodObject"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_self_CppSelf_cannot_be_converted[] = "self.CppSelf cannot be converted to a Python object for pickling"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyDualPivotPythonBase; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_dualPivotMethodObject; - static PyObject *__pyx_n_s_getstate; - static PyObject *__pyx_n_s_init; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_pivotRow; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -2554,24 +2614,16 @@ static PyObject *__pyx_kp_s_self_CppSelf_cannot_be_converted; - static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_n_s_updatePrimalSolution; - static PyObject *__pyx_n_s_updateWeights; - static int __pyx_pf_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonBase___init__(struct __pyx_obj_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPythonBase *__pyx_v_self, PyObject *__pyx_v_dualPivotMethodObject); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonBase_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPythonBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonBase_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPythonBase *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPythonBase(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; --static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; - /* Late includes */ - - /* "cylp/cy/CyDualPivotPythonBase.pyx":7 -@@ -2586,6 +2638,9 @@ static PyObject *__pyx_tuple__9; - static int __pyx_pw_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonBase_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ - static int __pyx_pw_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonBase_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_dualPivotMethodObject = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - int __pyx_r; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); -@@ -2638,6 +2693,9 @@ static int __pyx_pf_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonBase___ - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__init__", 0); - - /* "cylp/cy/CyDualPivotPythonBase.pyx":8 -@@ -2724,6 +2782,9 @@ static PyObject *__pyx_f_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonBa - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("pivotRow", 0); - - /* "cylp/cy/CyDualPivotPythonBase.pyx":13 -@@ -2844,6 +2905,9 @@ static double __pyx_f_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonBase_ - int __pyx_t_4; - PyObject *__pyx_t_5 = NULL; - double __pyx_t_6; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("updateWeights", 0); - - /* "cylp/cy/CyDualPivotPythonBase.pyx":29 -@@ -3050,6 +3114,9 @@ static void __pyx_f_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonBase_up - PyObject *__pyx_t_6 = NULL; - __pyx_t_5numpy_double_t __pyx_t_7; - Py_ssize_t __pyx_t_8; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("updatePrimalSolution", 0); - __pyx_pybuffer_changeInObjective.pybuffer.buf = NULL; - __pyx_pybuffer_changeInObjective.refcount = 0; -@@ -3221,6 +3288,9 @@ static PyObject *__pyx_pf_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonB - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3276,6 +3346,9 @@ static PyObject *__pyx_pf_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonB - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3306,863 +3379,7 @@ static PyObject *__pyx_pf_4cylp_2cy_21CyDualPivotPythonBase_21CyDualPivotPythonB - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * -- * ndim = PyArray_NDIM(self) -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -- * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -- * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -- * -- * cdef int t -- */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -- * -- */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -- * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4174,9 +3391,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * - * cdef inline object PyArray_MultiIterNew1(a): - * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -@@ -4184,13 +3404,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - * cdef inline object PyArray_MultiIterNew2(a, b): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4209,7 +3429,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4221,9 +3441,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * - * cdef inline object PyArray_MultiIterNew2(a, b): - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -@@ -4231,13 +3454,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4256,7 +3479,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4268,9 +3491,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -@@ -4278,13 +3504,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4303,7 +3529,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4315,9 +3541,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -@@ -4325,13 +3554,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4350,7 +3579,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4362,9 +3591,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -@@ -4372,13 +3604,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - * cdef inline tuple PyDataType_SHAPE(dtype d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4397,7 +3629,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4411,7 +3643,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - int __pyx_t_1; - __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4421,7 +3653,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): - * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -@@ -4433,7 +3665,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4442,12 +3674,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 - * return <tuple>d.subarray.shape - * else: - * return () # <<<<<<<<<<<<<< - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -+ * - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); -@@ -4456,7 +3688,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - goto __pyx_L0; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4471,765 +3703,19 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 -+ * int _import_umath() except -1 - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -+ * Py_INCREF(base) # important to do this before stealing the reference below! -+ * PyArray_SetBaseObject(arr, base) - */ - --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- goto __pyx_L13; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -- */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -- * -- * -- */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -- __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -- * int _import_umath() except -1 -- * -- * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -- * Py_INCREF(base) # important to do this before stealing the reference below! -- * PyArray_SetBaseObject(arr, base) -- */ -- --static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_arr, PyObject *__pyx_v_base) { -+static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_arr, PyObject *__pyx_v_base) { - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -5238,7 +3724,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5247,7 +3733,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5259,7 +3745,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5274,7 +3760,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5283,7 +3769,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5293,7 +3779,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5304,7 +3790,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5313,7 +3799,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5325,7 +3811,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5340,12 +3826,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -5359,13 +3845,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -5377,20 +3866,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5400,9 +3889,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5410,32 +3899,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5446,12 +3935,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -5469,7 +3958,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5488,9 +3977,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5506,16 +3998,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5529,7 +4021,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -5539,28 +4031,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5575,7 +4067,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5598,7 +4090,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5617,9 +4109,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5635,16 +4130,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5658,35 +4153,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5701,7 +4199,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5723,6 +4221,180 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} - static struct __pyx_vtabstruct_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPythonBase __pyx_vtable_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPythonBase; - - static PyObject *__pyx_tp_new_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPythonBase(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -5780,7 +4452,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPyth - sizeof(struct __pyx_obj_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPythonBase), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPythonBase, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -5833,6 +4510,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_21CyDualPivotPythonBase_CyDualPivotPyth - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -5882,26 +4565,18 @@ static struct PyModuleDef __pyx_moduledef = { - - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyDualPivotPythonBase, __pyx_k_CyDualPivotPythonBase, sizeof(__pyx_k_CyDualPivotPythonBase), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_dualPivotMethodObject, __pyx_k_dualPivotMethodObject, sizeof(__pyx_k_dualPivotMethodObject), 0, 0, 1, 1}, - {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, - {&__pyx_n_s_init, __pyx_k_init, sizeof(__pyx_k_init), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_pivotRow, __pyx_k_pivotRow, sizeof(__pyx_k_pivotRow), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -5909,17 +4584,13 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {&__pyx_n_s_updatePrimalSolution, __pyx_k_updatePrimalSolution, sizeof(__pyx_k_updatePrimalSolution), 0, 0, 1, 1}, - {&__pyx_n_s_updateWeights, __pyx_k_updateWeights, sizeof(__pyx_k_updateWeights), 0, 0, 1, 1}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -5948,82 +4619,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6073,6 +4689,9 @@ static int __Pyx_modinit_function_export_code(void) { - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -6110,6 +4729,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -6133,18 +4755,38 @@ static int __Pyx_modinit_type_import_code(void) { - __pyx_ptype_7cpython_7complex_complex = __Pyx_ImportType(__pyx_t_1, __Pyx_BUILTIN_MODULE_NAME, "complex", sizeof(PyComplexObject), __Pyx_ImportType_CheckSize_Warn); - if (!__pyx_ptype_7cpython_7complex_complex) __PYX_ERR(5, 15, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyCoinIndexedVector"); if (unlikely(!__pyx_t_1)) __PYX_ERR(6, 22, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -6253,14 +4895,18 @@ static int __Pyx_modinit_variable_import_code(void) { - static int __Pyx_modinit_function_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); - /*--- Function import code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (!__pyx_t_1) __PYX_ERR(1, 1, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); - if (__Pyx_ImportFunction(__pyx_t_1, "RunPivotRow", (void (**)(void))&__pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_RunPivotRow, "int (void *)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunDualPivotClone", (void (**)(void))&__pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_RunDualPivotClone, "ClpDualRowPivot *(void *, int)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunUpdateWeights", (void (**)(void))&__pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_RunUpdateWeights, "double (void *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunUpdatePrimalSolution", (void (**)(void))&__pyx_f_4cylp_2cy_21CyClpDualRowPivotBase_RunUpdatePrimalSolution, "void (void *, ICoinIndexedVector *, double, double *)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) -- Py_DECREF(__pyx_t_1); __pyx_t_1 = 0; -+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6270,17 +4916,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6362,6 +5010,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyDualPivotPythonBase(PyObject *__ - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -6409,11 +5060,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -6450,17 +5099,17 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); -- if (unlikely(__Pyx_modinit_function_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_function_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Execution code ---*/ - #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) - if (__Pyx_patch_abc() < 0) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -6476,12 +5125,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -6590,7 +5239,7 @@ static int __Pyx_ParseOptionalKeywords( - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 -- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { -+ if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { -@@ -6617,7 +5266,7 @@ static int __Pyx_ParseOptionalKeywords( - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -6633,7 +5282,7 @@ static int __Pyx_ParseOptionalKeywords( - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -6842,7 +5491,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -6929,7 +5578,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -7102,6 +5751,7 @@ static void __Pyx_BufFmt_RaiseUnexpectedChar(char ch) { - } - static const char* __Pyx_BufFmt_DescribeTypeChar(char ch, int is_complex) { - switch (ch) { -+ case '?': return "'bool'"; - case 'c': return "'char'"; - case 'b': return "'signed char'"; - case 'B': return "'unsigned char'"; -@@ -7144,7 +5794,7 @@ static size_t __Pyx_BufFmt_TypeCharToStandardSize(char ch, int is_complex) { - } - static size_t __Pyx_BufFmt_TypeCharToNativeSize(char ch, int is_complex) { - switch (ch) { -- case 'c': case 'b': case 'B': case 's': case 'p': return 1; -+ case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; - case 'h': case 'H': return sizeof(short); - case 'i': case 'I': return sizeof(int); - case 'l': case 'L': return sizeof(long); -@@ -7228,7 +5878,7 @@ static char __Pyx_BufFmt_TypeCharToGroup(char ch, int is_complex) { - case 'b': case 'h': case 'i': - case 'l': case 'q': case 's': case 'p': - return 'I'; -- case 'B': case 'H': case 'I': case 'L': case 'Q': -+ case '?': case 'B': case 'H': case 'I': case 'L': case 'Q': - return 'U'; - case 'f': case 'd': case 'g': - return (is_complex ? 'C' : 'R'); -@@ -7372,9 +6022,7 @@ static PyObject * - __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) - { - const char *ts = *tsp; -- int i = 0, number; -- int ndim = ctx->head->field->type->ndim; --; -+ int i = 0, number, ndim; - ++ts; - if (ctx->new_count != 1) { - PyErr_SetString(PyExc_ValueError, -@@ -7382,6 +6030,7 @@ __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) - return NULL; - } - if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; -+ ndim = ctx->head->field->type->ndim; - while (*ts && *ts != ')') { - switch (*ts) { - case ' ': case '\f': case '\r': case '\n': case '\t': case '\v': continue; -@@ -7507,12 +6156,12 @@ static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const cha - return NULL; - } - CYTHON_FALLTHROUGH; -- case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': -+ case '?': case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': - case 'l': case 'L': case 'q': case 'Q': - case 'f': case 'd': case 'g': - case 'O': case 'p': -- if (ctx->enc_type == *ts && got_Z == ctx->is_complex && -- ctx->enc_packmode == ctx->new_packmode) { -+ if ((ctx->enc_type == *ts) && (got_Z == ctx->is_complex) && -+ (ctx->enc_packmode == ctx->new_packmode) && (!ctx->is_valid_array)) { - ctx->enc_count += ctx->new_count; - ctx->new_count = 1; - got_Z = 0; -@@ -7760,61 +6409,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* DictGetItem */ -- #if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ -- static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ -- static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ -- static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ -- static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -8153,6 +6747,28 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+ static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -8180,43 +6796,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -8257,7 +6881,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -8287,7 +6911,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -8361,7 +6985,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -8384,30 +7008,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -8426,11 +7051,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -8465,7 +7095,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #if PY_MAJOR_VERSION < 3 - static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { - if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags); -- if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) return __pyx_pw_5numpy_7ndarray_1__getbuffer__(obj, view, flags); - PyErr_Format(PyExc_TypeError, "'%.200s' does not have the buffer interface", Py_TYPE(obj)->tp_name); - return -1; - } -@@ -8477,7 +7106,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return; - } - if ((0)) {} -- else if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) __pyx_pw_5numpy_7ndarray_3__releasebuffer__(obj, view); - view->obj = NULL; - Py_DECREF(obj); - } -@@ -8601,7 +7229,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -8756,7 +7383,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -8795,24 +7421,31 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - #endif - - /* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -+ if (sizeof(long) < sizeof(long)) { - return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -+ } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif - } - } else { -- if (sizeof(int) <= sizeof(long)) { -+ if (sizeof(long) <= sizeof(long)) { - return PyInt_FromLong((long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - #endif - } -@@ -8820,7 +7453,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -+ return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); - } - } -@@ -8847,51 +7480,27 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return (target_type) value;\ - } - --/* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+/* CIntFromPy */ -+ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ -- static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(int) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) -+ if (sizeof(long) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (int) val; -+ return (long) val; - } - } else - #endif -@@ -8900,32 +7509,32 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) -+ case 0: return (long) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -- return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -+ return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -- return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -+ return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -- return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -+ return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; -@@ -8939,86 +7548,86 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (int) -1; -+ return (long) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(int) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(long) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) -+ case 0: return (long) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) - case -2: -- if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(int) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -+ if (sizeof(long) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -9027,7 +7636,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- int val; -+ long val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -9047,71 +7656,47 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return val; - } - #endif -- return (int) -1; -+ return (long) -1; - } - } else { -- int val; -+ long val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (int) -1; -- val = __Pyx_PyInt_As_int(tmp); -+ if (!tmp) return (long) -1; -+ val = __Pyx_PyInt_As_long(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to int"); -- return (int) -1; -+ "value too large to convert to long"); -+ return (long) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to int"); -- return (int) -1; -+ "can't convert negative value to long"); -+ return (long) -1; - } - --/* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(long) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(long) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+/* CIntFromPy */ -+ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(long) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(long), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ -- static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(long) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) -+ if (sizeof(int) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (long) val; -+ return (int) val; - } - } else - #endif -@@ -9120,32 +7705,32 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) -+ case 0: return (int) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -- return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -+ return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -- return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -+ return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -- return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -+ return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; -@@ -9159,86 +7744,86 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (long) -1; -+ return (int) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(long) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(int) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) -+ case 0: return (int) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) - case -2: -- if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(long) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) -+ if (sizeof(int) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -9247,7 +7832,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- long val; -+ int val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -9267,24 +7852,24 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return val; - } - #endif -- return (long) -1; -+ return (int) -1; - } - } else { -- long val; -+ int val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (long) -1; -- val = __Pyx_PyInt_As_long(tmp); -+ if (!tmp) return (int) -1; -+ val = __Pyx_PyInt_As_int(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to long"); -- return (long) -1; -+ "value too large to convert to int"); -+ return (int) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to long"); -- return (long) -1; -+ "can't convert negative value to int"); -+ return (int) -1; - } - - /* FastTypeChecks */ -@@ -9705,6 +8290,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyOsiCuts.cpp b/cylp/cy/CyOsiCuts.cpp -index bbf629d..5b18903 100644 ---- a/cylp/cy/CyOsiCuts.cpp -+++ b/cylp/cy/CyOsiCuts.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -610,7 +693,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include <string.h> - #include <stdio.h> - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "IOsiCuts.hpp" - #ifdef _OPENMP - #include <omp.h> -@@ -708,6 +797,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -842,7 +932,7 @@ static const char *__pyx_filename; - - - static const char *__pyx_f[] = { -- "cylp\\cy\\CyOsiCuts.pyx", -+ "cylp/cy/CyOsiCuts.pyx", - "stringsource", - "__init__.pxd", - "type.pxd", -@@ -884,7 +974,7 @@ typedef struct { - } __Pyx_BufFmt_Context; - - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -893,7 +983,7 @@ typedef struct { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -902,7 +992,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -911,7 +1001,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -920,7 +1010,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -929,7 +1019,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -938,7 +1028,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -947,7 +1037,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -956,7 +1046,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -965,7 +1055,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -974,7 +1064,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -983,7 +1073,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -992,7 +1082,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1001,7 +1091,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1010,7 +1100,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1019,7 +1109,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1028,7 +1118,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1037,7 +1127,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1046,7 +1136,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1055,7 +1145,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1064,7 +1154,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1100,7 +1190,7 @@ static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(do - /*--- Type declarations ---*/ - struct __pyx_obj_4cylp_2cy_9CyOsiCuts_CyOsiCuts; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1109,7 +1199,7 @@ struct __pyx_obj_4cylp_2cy_9CyOsiCuts_CyOsiCuts; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1118,7 +1208,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1127,7 +1217,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1314,6 +1404,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -1321,6 +1412,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -1462,20 +1554,6 @@ static void __Pyx_RaiseBufferFallbackError(void); - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -1525,6 +1603,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -1636,11 +1717,10 @@ static void __Pyx_CppExn2PyErr() { - } - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -1741,14 +1821,17 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - #endif - - /* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - --/* CIntFromPy.proto */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -+/* CIntFromPy.proto */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+ - /* FastTypeChecks.proto */ - #if CYTHON_COMPILING_IN_CPYTHON - #define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -@@ -1796,8 +1879,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyOsiCuts' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_9CyOsiCuts_CyOsiCuts = 0; -@@ -1810,9 +1902,6 @@ int __pyx_module_is_main_cylp__cy__CyOsiCuts = 0; - /* Implementation of 'cylp.cy.CyOsiCuts' */ - static PyObject *__pyx_builtin_xrange; - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_x[] = "x"; - static const char __pyx_k_np[] = "np"; -@@ -1843,12 +1932,10 @@ static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_cyLpModel[] = "cyLpModel"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; - static const char __pyx_k_variables[] = "variables"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_csr_matrix[] = "csr_matrix"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; - static const char __pyx_k_addVariable[] = "addVariable"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_getVarByName[] = "getVarByName"; - static const char __pyx_k_makeMatrices[] = "makeMatrices"; - static const char __pyx_k_scipy_sparse[] = "scipy.sparse"; -@@ -1856,24 +1943,13 @@ static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_cylp_py_modeling_CyLPModel[] = "cylp.py.modeling.CyLPModel"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyLPModel; - static PyObject *__pyx_n_s_CyOsiCuts; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_addVariable; - static PyObject *__pyx_n_s_arange; - static PyObject *__pyx_n_s_cline_in_traceback; -@@ -1894,8 +1970,6 @@ static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_makeMatrices; - static PyObject *__pyx_n_s_name; - static PyObject *__pyx_n_s_name_2; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_no_default___reduce___due_to_non; - static PyObject *__pyx_n_s_np; - static PyObject *__pyx_n_s_numpy; -@@ -1912,7 +1986,6 @@ static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_shape; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_n_s_variables; - static PyObject *__pyx_n_s_x; - static PyObject *__pyx_n_s_xrange; -@@ -1925,19 +1998,12 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_4addColumnCut(struct _ - static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_6addRowCut(struct __pyx_obj_4cylp_2cy_9CyOsiCuts_CyOsiCuts *__pyx_v_self, PyObject *__pyx_v_cut, PyObject *__pyx_v_cyLpModel); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_8__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_9CyOsiCuts_CyOsiCuts *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_10__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_9CyOsiCuts_CyOsiCuts *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_9CyOsiCuts_CyOsiCuts(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_slice_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; - static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; --static PyObject *__pyx_tuple__10; - /* Late includes */ - - /* "cylp/cy/CyOsiCuts.pyx":10 -@@ -1968,6 +2034,9 @@ static int __pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts___cinit__(struct __pyx_obj_4 - int __pyx_r; - __Pyx_RefNannyDeclarations - CppOsiCuts *__pyx_t_1; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__cinit__", 0); - - /* "cylp/cy/CyOsiCuts.pyx":11 -@@ -2125,6 +2194,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_15numberOfRowCuts___ge - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyOsiCuts.pyx":22 -@@ -2185,6 +2257,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_18numberOfColumnCuts__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyOsiCuts.pyx":26 -@@ -2245,6 +2320,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_12numberOfCuts___get__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyOsiCuts.pyx":30 -@@ -2294,6 +2372,9 @@ static char __pyx_doc_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_4addColumnCut[] = "\n - static PyObject *__pyx_pw_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_5addColumnCut(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_cut = 0; - PyObject *__pyx_v_cyLpModel = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("addColumnCut (wrapper)", 0); -@@ -2386,6 +2467,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_4addColumnCut(struct _ - int __pyx_t_10; - PyObject *__pyx_t_11 = NULL; - PyObject *(*__pyx_t_12)(PyObject *); -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("addColumnCut", 0); - __pyx_pybuffer_vl_inds.pybuffer.buf = NULL; - __pyx_pybuffer_vl_inds.refcount = 0; -@@ -2909,6 +2993,9 @@ static char __pyx_doc_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_6addRowCut[] = "\n - static PyObject *__pyx_pw_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_7addRowCut(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_cut = 0; - PyObject *__pyx_v_cyLpModel = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("addRowCut (wrapper)", 0); -@@ -3004,6 +3091,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_6addRowCut(struct __py - Py_ssize_t __pyx_t_19; - double __pyx_t_20; - double __pyx_t_21; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("addRowCut", 0); - __pyx_pybuffer_row_inds.pybuffer.buf = NULL; - __pyx_pybuffer_row_inds.refcount = 0; -@@ -3561,6 +3651,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_8__reduce_cython__(CYT - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3615,6 +3708,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_10__setstate_cython__( - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3645,863 +3741,7 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyOsiCuts_9CyOsiCuts_10__setstate_cython__( - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * -- * ndim = PyArray_NDIM(self) -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -- * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -- * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -- * -- * cdef int t -- */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -- * -- */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -- * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4513,9 +3753,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * - * cdef inline object PyArray_MultiIterNew1(a): - * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -@@ -4523,13 +3766,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - * cdef inline object PyArray_MultiIterNew2(a, b): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4548,7 +3791,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4560,9 +3803,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * - * cdef inline object PyArray_MultiIterNew2(a, b): - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -@@ -4570,13 +3816,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4595,7 +3841,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4607,9 +3853,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -@@ -4617,13 +3866,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4642,7 +3891,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4654,9 +3903,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -@@ -4664,13 +3916,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4689,7 +3941,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4701,9 +3953,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -@@ -4711,13 +3966,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - * cdef inline tuple PyDataType_SHAPE(dtype d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4736,7 +3991,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4750,7 +4005,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - int __pyx_t_1; - __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4760,7 +4015,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): - * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -@@ -4772,7 +4027,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4781,12 +4036,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 - * return <tuple>d.subarray.shape - * else: - * return () # <<<<<<<<<<<<<< - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -+ * - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); -@@ -4795,7 +4050,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - goto __pyx_L0; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4810,754 +4065,8 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- goto __pyx_L13; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -- */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -- * -- * -- */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -- __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -- * int _import_umath() except -1 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 -+ * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< - * Py_INCREF(base) # important to do this before stealing the reference below! -@@ -5568,7 +4077,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -5577,7 +4086,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5586,7 +4095,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5598,7 +4107,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5613,7 +4122,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5622,7 +4131,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5632,7 +4141,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5643,7 +4152,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5652,7 +4161,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5664,7 +4173,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5679,12 +4188,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -5698,13 +4207,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -5716,20 +4228,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5739,9 +4251,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5749,32 +4261,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5785,12 +4297,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -5808,7 +4320,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5827,9 +4339,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5845,16 +4360,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5868,7 +4383,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -5878,28 +4393,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5914,7 +4429,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5937,7 +4452,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5956,9 +4471,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5974,16 +4492,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5997,35 +4515,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6040,7 +4561,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -6062,6 +4583,180 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} - static struct __pyx_vtabstruct_4cylp_2cy_9CyOsiCuts_CyOsiCuts __pyx_vtable_4cylp_2cy_9CyOsiCuts_CyOsiCuts; - - static PyObject *__pyx_tp_new_4cylp_2cy_9CyOsiCuts_CyOsiCuts(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { -@@ -6125,7 +4820,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_9CyOsiCuts_CyOsiCuts = { - sizeof(struct __pyx_obj_4cylp_2cy_9CyOsiCuts_CyOsiCuts), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_9CyOsiCuts_CyOsiCuts, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -6178,6 +4878,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_9CyOsiCuts_CyOsiCuts = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -6228,13 +4934,8 @@ static struct PyModuleDef __pyx_moduledef = { - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyLPModel, __pyx_k_CyLPModel, sizeof(__pyx_k_CyLPModel), 0, 0, 1, 1}, - {&__pyx_n_s_CyOsiCuts, __pyx_k_CyOsiCuts, sizeof(__pyx_k_CyOsiCuts), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_addVariable, __pyx_k_addVariable, sizeof(__pyx_k_addVariable), 0, 0, 1, 1}, - {&__pyx_n_s_arange, __pyx_k_arange, sizeof(__pyx_k_arange), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, -@@ -6255,8 +4956,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_makeMatrices, __pyx_k_makeMatrices, sizeof(__pyx_k_makeMatrices), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, - {&__pyx_n_s_name_2, __pyx_k_name_2, sizeof(__pyx_k_name_2), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, - {&__pyx_n_s_np, __pyx_k_np, sizeof(__pyx_k_np), 0, 0, 1, 1}, - {&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1}, -@@ -6273,7 +4972,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_shape, __pyx_k_shape, sizeof(__pyx_k_shape), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {&__pyx_n_s_variables, __pyx_k_variables, sizeof(__pyx_k_variables), 0, 0, 1, 1}, - {&__pyx_n_s_x, __pyx_k_x, sizeof(__pyx_k_x), 0, 0, 1, 1}, - {&__pyx_n_s_xrange, __pyx_k_xrange, sizeof(__pyx_k_xrange), 0, 0, 1, 1}, -@@ -6286,10 +4984,7 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_xrange = __Pyx_GetBuiltinName(__pyx_n_s_xrange); if (!__pyx_builtin_xrange) __PYX_ERR(0, 70, __pyx_L1_error) - #endif - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(1, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -6329,82 +5024,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__3); - __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__10 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__10); -- __Pyx_GIVEREF(__pyx_tuple__10); -+ __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__5); -+ __Pyx_GIVEREF(__pyx_tuple__5); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6453,6 +5093,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_vtabptr_4cylp_2cy_9CyOsiCuts_CyOsiCuts = &__pyx_vtable_4cylp_2cy_9CyOsiCuts_CyOsiCuts; -@@ -6478,6 +5121,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -6491,18 +5137,38 @@ static int __Pyx_modinit_type_import_code(void) { - __Pyx_ImportType_CheckSize_Warn); - if (!__pyx_ptype_7cpython_4type_type) __PYX_ERR(3, 9, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; -@@ -6529,17 +5195,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6622,6 +5290,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyOsiCuts(PyObject *__pyx_pyinit_m - { - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -6669,11 +5340,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -6710,15 +5379,15 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(0, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(0, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ -@@ -6799,12 +5468,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -6980,7 +5649,7 @@ static int __Pyx_ParseOptionalKeywords( - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 -- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { -+ if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { -@@ -7007,7 +5676,7 @@ static int __Pyx_ParseOptionalKeywords( - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -7023,7 +5692,7 @@ static int __Pyx_ParseOptionalKeywords( - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -7244,7 +5913,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -7347,7 +6016,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -7534,6 +6203,7 @@ static void __Pyx_BufFmt_RaiseUnexpectedChar(char ch) { - } - static const char* __Pyx_BufFmt_DescribeTypeChar(char ch, int is_complex) { - switch (ch) { -+ case '?': return "'bool'"; - case 'c': return "'char'"; - case 'b': return "'signed char'"; - case 'B': return "'unsigned char'"; -@@ -7576,7 +6246,7 @@ static size_t __Pyx_BufFmt_TypeCharToStandardSize(char ch, int is_complex) { - } - static size_t __Pyx_BufFmt_TypeCharToNativeSize(char ch, int is_complex) { - switch (ch) { -- case 'c': case 'b': case 'B': case 's': case 'p': return 1; -+ case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; - case 'h': case 'H': return sizeof(short); - case 'i': case 'I': return sizeof(int); - case 'l': case 'L': return sizeof(long); -@@ -7660,7 +6330,7 @@ static char __Pyx_BufFmt_TypeCharToGroup(char ch, int is_complex) { - case 'b': case 'h': case 'i': - case 'l': case 'q': case 's': case 'p': - return 'I'; -- case 'B': case 'H': case 'I': case 'L': case 'Q': -+ case '?': case 'B': case 'H': case 'I': case 'L': case 'Q': - return 'U'; - case 'f': case 'd': case 'g': - return (is_complex ? 'C' : 'R'); -@@ -7804,9 +6474,7 @@ static PyObject * - __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) - { - const char *ts = *tsp; -- int i = 0, number; -- int ndim = ctx->head->field->type->ndim; --; -+ int i = 0, number, ndim; - ++ts; - if (ctx->new_count != 1) { - PyErr_SetString(PyExc_ValueError, -@@ -7814,6 +6482,7 @@ __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) - return NULL; - } - if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; -+ ndim = ctx->head->field->type->ndim; - while (*ts && *ts != ')') { - switch (*ts) { - case ' ': case '\f': case '\r': case '\n': case '\t': case '\v': continue; -@@ -7939,12 +6608,12 @@ static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const cha - return NULL; - } - CYTHON_FALLTHROUGH; -- case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': -+ case '?': case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': - case 'l': case 'L': case 'q': case 'Q': - case 'f': case 'd': case 'g': - case 'O': case 'p': -- if (ctx->enc_type == *ts && got_Z == ctx->is_complex && -- ctx->enc_packmode == ctx->new_packmode) { -+ if ((ctx->enc_type == *ts) && (got_Z == ctx->is_complex) && -+ (ctx->enc_packmode == ctx->new_packmode) && (!ctx->is_valid_array)) { - ctx->enc_count += ctx->new_count; - ctx->new_count = 1; - got_Z = 0; -@@ -8332,35 +7001,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* DictGetItem */ -- #if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseNoneIterError */ -- static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -8584,6 +7224,28 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+ static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -8611,43 +7273,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -8751,7 +7421,7 @@ static PyTypeObject *__Pyx_ImportType(PyObject *module, const char *module_name, - { - #if PY_MAJOR_VERSION >= 3 - if (level == -1) { -- if (strchr(__Pyx_MODULE_NAME, '.')) { -+ if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) { - module = PyImport_ImportModuleLevelObject( - name, global_dict, empty_dict, list, 1); - if (!module) { -@@ -8802,7 +7472,7 @@ static PyTypeObject *__Pyx_ImportType(PyObject *module, const char *module_name, - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -8832,7 +7502,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -8906,7 +7576,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -8929,30 +7599,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -8971,11 +7642,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -9010,7 +7686,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #if PY_MAJOR_VERSION < 3 - static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { - if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags); -- if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) return __pyx_pw_5numpy_7ndarray_1__getbuffer__(obj, view, flags); - PyErr_Format(PyExc_TypeError, "'%.200s' does not have the buffer interface", Py_TYPE(obj)->tp_name); - return -1; - } -@@ -9022,76 +7697,13 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return; - } - if ((0)) {} -- else if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) __pyx_pw_5numpy_7ndarray_3__releasebuffer__(obj, view); - view->obj = NULL; - Py_DECREF(obj); - } - #endif - - -- /* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- --/* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(long) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(long) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(long) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(long), -- little, !is_unsigned); -- } --} -- --/* Declarations */ -+ /* Declarations */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus - static CYTHON_INLINE __pyx_t_float_complex __pyx_t_float_complex_from_parts(float x, float y) { -@@ -9208,7 +7820,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -9363,7 +7974,6 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -9401,47 +8011,70 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - #endif - #endif - --/* CIntFromPyVerify */ -- #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ -- __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) --#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ -- __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) --#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ -- {\ -- func_type value = func_value;\ -- if (sizeof(target_type) < sizeof(func_type)) {\ -- if (unlikely(value != (func_type) (target_type) value)) {\ -- func_type zero = 0;\ -- if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ -- return (target_type) -1;\ -- if (is_unsigned && unlikely(value < zero))\ -- goto raise_neg_overflow;\ -- else\ -- goto raise_overflow;\ -- }\ -- }\ -- return (target_type) value;\ -+/* CIntToPy */ -+ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(int) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); - } -+} - - /* CIntToPy */ -- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -+ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -+ if (sizeof(long) < sizeof(long)) { - return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -+ } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif - } - } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -+ if (sizeof(long) <= sizeof(long)) { - return PyInt_FromLong((long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - #endif - } -@@ -9449,25 +8082,54 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -+ return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); - } - } - -+/* CIntFromPyVerify */ -+ #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ -+ __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -+#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ -+ __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) -+#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ -+ {\ -+ func_type value = func_value;\ -+ if (sizeof(target_type) < sizeof(func_type)) {\ -+ if (unlikely(value != (func_type) (target_type) value)) {\ -+ func_type zero = 0;\ -+ if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ -+ return (target_type) -1;\ -+ if (is_unsigned && unlikely(value < zero))\ -+ goto raise_neg_overflow;\ -+ else\ -+ goto raise_overflow;\ -+ }\ -+ }\ -+ return (target_type) value;\ -+ } -+ - /* CIntFromPy */ -- static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(int) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) -+ if (sizeof(long) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (int) val; -+ return (long) val; - } - } else - #endif -@@ -9476,32 +8138,32 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) -+ case 0: return (long) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -- return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -+ return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -- return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -+ return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -- return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -+ return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; -@@ -9515,86 +8177,86 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (int) -1; -+ return (long) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(int) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(long) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) -+ case 0: return (long) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) - case -2: -- if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(int) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -+ if (sizeof(long) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -9603,7 +8265,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- int val; -+ long val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -9623,40 +8285,47 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return val; - } - #endif -- return (int) -1; -+ return (long) -1; - } - } else { -- int val; -+ long val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (int) -1; -- val = __Pyx_PyInt_As_int(tmp); -+ if (!tmp) return (long) -1; -+ val = __Pyx_PyInt_As_long(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to int"); -- return (int) -1; -+ "value too large to convert to long"); -+ return (long) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to int"); -- return (int) -1; -+ "can't convert negative value to long"); -+ return (long) -1; - } - - /* CIntFromPy */ -- static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(long) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) -+ if (sizeof(int) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (long) val; -+ return (int) val; - } - } else - #endif -@@ -9665,32 +8334,32 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) -+ case 0: return (int) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -- return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -+ return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -- return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -+ return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -- return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -+ return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; -@@ -9704,86 +8373,86 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (long) -1; -+ return (int) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(long) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(int) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) -+ case 0: return (int) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) - case -2: -- if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(long) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) -+ if (sizeof(int) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -9792,7 +8461,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- long val; -+ int val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -9812,24 +8481,24 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { - return val; - } - #endif -- return (long) -1; -+ return (int) -1; - } - } else { -- long val; -+ int val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (long) -1; -- val = __Pyx_PyInt_As_long(tmp); -+ if (!tmp) return (int) -1; -+ val = __Pyx_PyInt_As_int(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to long"); -- return (long) -1; -+ "value too large to convert to int"); -+ return (int) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to long"); -- return (long) -1; -+ "can't convert negative value to int"); -+ return (int) -1; - } - - /* FastTypeChecks */ -@@ -10196,6 +8865,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyOsiSolverInterface.cpp b/cylp/cy/CyOsiSolverInterface.cpp -index e0d5a87..8381cf8 100644 ---- a/cylp/cy/CyOsiSolverInterface.cpp -+++ b/cylp/cy/CyOsiSolverInterface.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -615,7 +698,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "ClpFactorization.hpp" - #include "IClpPrimalColumnPivotBase.h" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ClpDualRowPivot.hpp" - #include "IClpDualRowPivotBase.h" - #include "CoinModel.hpp" -@@ -640,11 +729,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "ICbcNode.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "IClpSimplex.hpp" - #include "ClpSimplex.hpp" -@@ -746,6 +835,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -881,23 +971,23 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyOsiSolverInterface.pyx", -+ "cylp/cy/CyOsiSolverInterface.pyx", - "__init__.pxd", - "type.pxd", - "bool.pxd", - "complex.pxd", -- "cylp\\cy\\CyCoinIndexedVector.pxd", -- "cylp\\cy\\CyClpPrimalColumnPivotBase.pxd", -- "cylp\\cy\\CyClpDualRowPivotBase.pxd", -- "cylp\\cy\\CyCoinModel.pxd", -- "cylp\\cy\\CyCoinPackedMatrix.pxd", -- "cylp\\cy\\CyCgl.pxd", -- "cylp\\cy\\CyCbcNode.pxd", -- "cylp\\cy\\CyCbcModel.pxd", -- "cylp\\cy\\CyClpSimplex.pxd", -+ "cylp/cy/CyCoinIndexedVector.pxd", -+ "cylp/cy/CyClpPrimalColumnPivotBase.pxd", -+ "cylp/cy/CyClpDualRowPivotBase.pxd", -+ "cylp/cy/CyCoinModel.pxd", -+ "cylp/cy/CyCoinPackedMatrix.pxd", -+ "cylp/cy/CyCgl.pxd", -+ "cylp/cy/CyCbcNode.pxd", -+ "cylp/cy/CyCbcModel.pxd", -+ "cylp/cy/CyClpSimplex.pxd", - }; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -906,7 +996,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -915,7 +1005,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -924,7 +1014,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -933,7 +1023,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -942,7 +1032,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -951,7 +1041,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -960,7 +1050,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -969,7 +1059,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -978,7 +1068,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -987,7 +1077,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -996,7 +1086,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1005,7 +1095,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1014,7 +1104,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1023,7 +1113,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1032,7 +1122,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1041,7 +1131,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1050,7 +1140,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1059,7 +1149,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1068,7 +1158,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1077,7 +1167,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1139,7 +1229,7 @@ struct __pyx_obj_4cylp_2cy_12CyClpSimplex_CyClpSimplex; - struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus; - struct __pyx_obj_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1148,7 +1238,7 @@ struct __pyx_obj_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1157,7 +1247,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1166,7 +1256,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1840,6 +1930,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -1847,6 +1938,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -1907,39 +1999,6 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* PyCFunctionFastCall.proto */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); --#else --#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) --#endif -- --/* PyObjectCallOneArg.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); -- --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -1989,6 +2048,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -2156,14 +2218,10 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #endif - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- --/* CIntFromPy.proto */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -@@ -2171,6 +2229,9 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -+/* CIntFromPy.proto */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+ - /* FastTypeChecks.proto */ - #if CYTHON_COMPILING_IN_CPYTHON - #define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -@@ -2290,8 +2351,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyClpDualRowPivotBase' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase = 0; -@@ -2343,78 +2413,50 @@ int __pyx_module_is_main_cylp__cy__CyOsiSolverInterface = 0; - - /* Implementation of 'cylp.cy.CyOsiSolverInterface' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_test[] = "__test__"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_reduce[] = "__reduce__"; - static const char __pyx_k_getstate[] = "__getstate__"; - static const char __pyx_k_setstate[] = "__setstate__"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_CyOsiSolverInterface[] = "CyOsiSolverInterface"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyOsiSolverInterface; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_getstate; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_no_default___reduce___due_to_non; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; - static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static int __pyx_pf_4cylp_2cy_20CyOsiSolverInterface_20CyOsiSolverInterface___cinit__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_20CyOsiSolverInterface_20CyOsiSolverInterface_8clpModel___get__(struct __pyx_obj_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_20CyOsiSolverInterface_20CyOsiSolverInterface_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_20CyOsiSolverInterface_20CyOsiSolverInterface_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; --static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; - /* Late includes */ - - /* "cylp/cy/CyOsiSolverInterface.pyx":11 -@@ -2526,6 +2568,9 @@ static PyObject *__pyx_pf_4cylp_2cy_20CyOsiSolverInterface_20CyOsiSolverInterfac - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__get__", 0); - - /* "cylp/cy/CyOsiSolverInterface.pyx":20 -@@ -2621,6 +2666,9 @@ static PyObject *__pyx_pf_4cylp_2cy_20CyOsiSolverInterface_20CyOsiSolverInterfac - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -2675,6 +2723,9 @@ static PyObject *__pyx_pf_4cylp_2cy_20CyOsiSolverInterface_20CyOsiSolverInterfac - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -2705,863 +2756,7 @@ static PyObject *__pyx_pf_4cylp_2cy_20CyOsiSolverInterface_20CyOsiSolverInterfac - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * -- * ndim = PyArray_NDIM(self) -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -- * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -- * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -- * -- * cdef int t -- */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -- * -- */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -- * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -3573,9 +2768,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * - * cdef inline object PyArray_MultiIterNew1(a): - * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -@@ -3583,13 +2781,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - * cdef inline object PyArray_MultiIterNew2(a, b): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -3608,7 +2806,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -3620,9 +2818,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * - * cdef inline object PyArray_MultiIterNew2(a, b): - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -@@ -3630,13 +2831,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -3655,7 +2856,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -3667,9 +2868,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -@@ -3677,13 +2881,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -3702,7 +2906,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -3714,9 +2918,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -@@ -3724,13 +2931,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -3749,7 +2956,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -3761,9 +2968,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -@@ -3771,13 +2981,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - * cdef inline tuple PyDataType_SHAPE(dtype d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -3796,7 +3006,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -3810,7 +3020,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - int __pyx_t_1; - __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -3820,7 +3030,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): - * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -@@ -3832,7 +3042,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -3841,12 +3051,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 - * return <tuple>d.subarray.shape - * else: - * return () # <<<<<<<<<<<<<< - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -+ * - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); -@@ -3855,7 +3065,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - goto __pyx_L0; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -3870,754 +3080,8 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- goto __pyx_L13; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -- */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -- * -- * -- */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -- __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -- * int _import_umath() except -1 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 -+ * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< - * Py_INCREF(base) # important to do this before stealing the reference below! -@@ -4628,7 +3092,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -4637,7 +3101,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -4646,7 +3110,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -4658,7 +3122,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -4673,7 +3137,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -4682,7 +3146,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -4692,7 +3156,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -4703,7 +3167,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -4712,7 +3176,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -4724,7 +3188,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -4739,12 +3203,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -4758,13 +3222,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -4776,20 +3243,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -4799,9 +3266,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -4809,32 +3276,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -4845,12 +3312,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -4868,7 +3335,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -4887,9 +3354,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -4905,16 +3375,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -4928,7 +3398,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -4938,28 +3408,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -4974,7 +3444,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -4997,7 +3467,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5016,9 +3486,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5034,16 +3507,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5057,35 +3530,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5100,7 +3576,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5122,6 +3598,180 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} - static struct __pyx_vtabstruct_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface __pyx_vtable_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface; - - static PyObject *__pyx_tp_new_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { -@@ -5172,7 +3822,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInter - sizeof(struct __pyx_obj_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -5225,6 +3880,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInter - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -5274,39 +3935,27 @@ static struct PyModuleDef __pyx_moduledef = { - - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyOsiSolverInterface, __pyx_k_CyOsiSolverInterface, sizeof(__pyx_k_CyOsiSolverInterface), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -5335,82 +3984,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -5459,6 +4053,9 @@ static int __Pyx_modinit_function_export_code(void) { - - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_vtabptr_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface = &__pyx_vtable_4cylp_2cy_20CyOsiSolverInterface_CyOsiSolverInterface; -@@ -5484,6 +4081,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -5519,18 +4119,38 @@ static int __Pyx_modinit_type_import_code(void) { - if (!__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase) __PYX_ERR(7, 67, __pyx_L1_error) - __pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase = (struct __pyx_vtabstruct_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase*)__Pyx_GetVtable(__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase->tp_dict); if (unlikely(!__pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase)) __PYX_ERR(7, 67, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(8, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -5633,17 +4253,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -5725,6 +4347,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyOsiSolverInterface(PyObject *__p - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -5772,11 +4397,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -5813,15 +4436,15 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 2, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 2, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 2, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 2, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ -@@ -5840,12 +4463,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 2, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -6107,7 +4730,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -6348,124 +4971,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* PyCFunctionFastCall */ --#if CYTHON_FAST_PYCCALL --static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { -- PyCFunctionObject *func = (PyCFunctionObject*)func_obj; -- PyCFunction meth = PyCFunction_GET_FUNCTION(func); -- PyObject *self = PyCFunction_GET_SELF(func); -- int flags = PyCFunction_GET_FLAGS(func); -- assert(PyCFunction_Check(func)); -- assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); -- assert(nargs >= 0); -- assert(nargs == 0 || args != NULL); -- /* _PyCFunction_FastCallDict() must not be called with an exception set, -- because it may clear it (directly or indirectly) and so the -- caller loses its exception */ -- assert(!PyErr_Occurred()); -- if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { -- return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); -- } else { -- return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); -- } --} --#endif -- --/* PyObjectCallOneArg */ --#if CYTHON_COMPILING_IN_CPYTHON --static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_New(1); -- if (unlikely(!args)) return NULL; -- Py_INCREF(arg); -- PyTuple_SET_ITEM(args, 0, arg); -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { --#if CYTHON_FAST_PYCALL -- if (PyFunction_Check(func)) { -- return __Pyx_PyFunction_FastCall(func, &arg, 1); -- } --#endif -- if (likely(PyCFunction_Check(func))) { -- if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { -- return __Pyx_PyObject_CallMethO(func, arg); --#if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -- return __Pyx_PyCFunction_FastCall(func, &arg, 1); --#endif -- } -- } -- return __Pyx__PyObject_CallOneArg(func, arg); --} --#else --static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { -- PyObject *result; -- PyObject *args = PyTuple_Pack(1, arg); -- if (unlikely(!args)) return NULL; -- result = __Pyx_PyObject_Call(func, args, NULL); -- Py_DECREF(args); -- return result; --} --#endif -- --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -6689,6 +5194,28 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable) { - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -6716,43 +5243,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -6874,7 +5409,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -6904,7 +5439,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -6978,7 +5513,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -7001,30 +5536,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -7043,11 +5579,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -7196,7 +5737,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -7351,7 +5891,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -7390,24 +5929,31 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #endif - - /* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -+ if (sizeof(long) < sizeof(long)) { - return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -+ } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif - } - } else { -- if (sizeof(int) <= sizeof(long)) { -+ if (sizeof(long) <= sizeof(long)) { - return PyInt_FromLong((long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - #endif - } -@@ -7415,7 +5961,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -+ return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); - } - } -@@ -7442,51 +5988,27 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - return (target_type) value;\ - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+/* CIntFromPy */ -+static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(int) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) -+ if (sizeof(long) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (int) val; -+ return (long) val; - } - } else - #endif -@@ -7495,32 +6017,32 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) -+ case 0: return (long) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -- return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -+ return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -- return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -+ return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -- return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -+ return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; -@@ -7534,86 +6056,86 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (int) -1; -+ return (long) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(int) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(long) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) -+ case 0: return (long) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) - case -2: -- if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(int) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -+ if (sizeof(long) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -7622,7 +6144,7 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- int val; -+ long val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -7642,71 +6164,47 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - return val; - } - #endif -- return (int) -1; -+ return (long) -1; - } - } else { -- int val; -+ long val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (int) -1; -- val = __Pyx_PyInt_As_int(tmp); -+ if (!tmp) return (long) -1; -+ val = __Pyx_PyInt_As_long(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to int"); -- return (int) -1; -+ "value too large to convert to long"); -+ return (long) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to int"); -- return (int) -1; -+ "can't convert negative value to long"); -+ return (long) -1; - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(long) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(long) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+/* CIntFromPy */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(long) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(long), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ --static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(long) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) -+ if (sizeof(int) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (long) val; -+ return (int) val; - } - } else - #endif -@@ -7715,32 +6213,32 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) -+ case 0: return (int) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -- return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -+ return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -- return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -+ return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -- return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -+ return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; -@@ -7754,86 +6252,86 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (long) -1; -+ return (int) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(long) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(int) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) -+ case 0: return (int) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) - case -2: -- if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(long) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) -+ if (sizeof(int) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -7842,7 +6340,7 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- long val; -+ int val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -7862,24 +6360,24 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - return val; - } - #endif -- return (long) -1; -+ return (int) -1; - } - } else { -- long val; -+ int val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (long) -1; -- val = __Pyx_PyInt_As_long(tmp); -+ if (!tmp) return (int) -1; -+ val = __Pyx_PyInt_As_int(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to long"); -- return (long) -1; -+ "value too large to convert to int"); -+ return (int) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to long"); -- return (long) -1; -+ "can't convert negative value to int"); -+ return (int) -1; - } - - /* FastTypeChecks */ -@@ -8246,6 +6744,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyPEPivot.cpp b/cylp/cy/CyPEPivot.cpp -index e28622e..f4e3db9 100644 ---- a/cylp/cy/CyPEPivot.cpp -+++ b/cylp/cy/CyPEPivot.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -612,7 +695,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "pythread.h" - #include "ICoinIndexedVector.hpp" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ClpDualRowPivot.hpp" - #include "ClpFactorization.hpp" - #include "IClpDualRowPivotBase.h" -@@ -641,11 +730,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "OsiSolverInterface.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "IClpPrimalColumnPivotBase.h" - #include "ClpPrimalColumnPivot.hpp" -@@ -746,6 +835,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -880,24 +970,24 @@ static const char *__pyx_filename; - - - static const char *__pyx_f[] = { -- "cylp\\cy\\CyPEPivot.pyx", -+ "cylp/cy/CyPEPivot.pyx", - "stringsource", - "__init__.pxd", - "type.pxd", - "bool.pxd", - "complex.pxd", -- "cylp\\cy\\CyCoinIndexedVector.pxd", -- "cylp\\cy\\CyClpDualRowPivotBase.pxd", -- "cylp\\cy\\CyCoinModel.pxd", -- "cylp\\cy\\CyCoinPackedMatrix.pxd", -- "cylp\\cy\\CyCgl.pxd", -- "cylp\\cy\\CyCbcNode.pxd", -- "cylp\\cy\\CyOsiSolverInterface.pxd", -- "cylp\\cy\\CyCbcModel.pxd", -- "cylp\\cy\\CyClpSimplex.pxd", -+ "cylp/cy/CyCoinIndexedVector.pxd", -+ "cylp/cy/CyClpDualRowPivotBase.pxd", -+ "cylp/cy/CyCoinModel.pxd", -+ "cylp/cy/CyCoinPackedMatrix.pxd", -+ "cylp/cy/CyCgl.pxd", -+ "cylp/cy/CyCbcNode.pxd", -+ "cylp/cy/CyOsiSolverInterface.pxd", -+ "cylp/cy/CyCbcModel.pxd", -+ "cylp/cy/CyClpSimplex.pxd", - }; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -906,7 +996,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -915,7 +1005,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -924,7 +1014,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -933,7 +1023,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -942,7 +1032,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -951,7 +1041,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -960,7 +1050,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -969,7 +1059,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -978,7 +1068,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -987,7 +1077,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -996,7 +1086,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1005,7 +1095,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1014,7 +1104,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1023,7 +1113,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1032,7 +1122,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1041,7 +1131,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1050,7 +1140,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1059,7 +1149,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1068,7 +1158,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1077,7 +1167,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1140,7 +1230,7 @@ struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus; - struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase; - struct __pyx_obj_4cylp_2cy_9CyPEPivot_CyPEPivot; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1149,7 +1239,7 @@ struct __pyx_obj_4cylp_2cy_9CyPEPivot_CyPEPivot; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1158,7 +1248,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1167,7 +1257,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1882,6 +1972,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -1889,6 +1980,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -2048,26 +2140,6 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -2140,6 +2212,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -2172,11 +2247,10 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); - static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -2277,11 +2351,14 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - #endif - - /* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); - -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+ - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -@@ -2406,8 +2483,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyClpDualRowPivotBase' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase = 0; -@@ -2470,9 +2556,6 @@ int __pyx_module_is_main_cylp__cy__CyPEPivot = 0; - static PyObject *__pyx_builtin_xrange; - static PyObject *__pyx_builtin_print; - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_np[] = "np"; - static const char __pyx_k_init[] = "__init__"; -@@ -2500,13 +2583,11 @@ static const char __pyx_k_iteration[] = "iteration"; - static const char __pyx_k_nElements[] = "nElements"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; - static const char __pyx_k_varIsFree[] = "varIsFree"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_nVariables[] = "nVariables"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; - static const char __pyx_k_varNotBasic[] = "varNotBasic"; - static const char __pyx_k_varNotFixed[] = "varNotFixed"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_isCompatible[] = "isCompatible"; - static const char __pyx_k_reducedCosts[] = "reducedCosts"; - static const char __pyx_k_comp_selected[] = " : comp selected"; -@@ -2520,23 +2601,12 @@ static const char __pyx_k_varIsAtLowerBound[] = "varIsAtLowerBound"; - static const char __pyx_k_varIsAtUpperBound[] = "varIsAtUpperBound"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_updateColumnTranspose[] = "updateColumnTranspose"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_self_CppSelf_cannot_be_converted[] = "self.CppSelf cannot be converted to a Python object for pickling"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyPEPivot; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_clear; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_kp_s_comp_selected; -@@ -2554,8 +2624,6 @@ static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_nElements; - static PyObject *__pyx_n_s_nVariables; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_n_s_np; - static PyObject *__pyx_n_s_numpy; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; -@@ -2572,7 +2640,6 @@ static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; - static PyObject *__pyx_n_s_transposeTimes; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_n_s_updateColumnTranspose; - static PyObject *__pyx_n_s_updateP; - static PyObject *__pyx_n_s_updateW; -@@ -2587,19 +2654,12 @@ static PyObject *__pyx_n_s_xrange; - static int __pyx_pf_4cylp_2cy_9CyPEPivot_9CyPEPivot___init__(struct __pyx_obj_4cylp_2cy_9CyPEPivot_CyPEPivot *__pyx_v_self, PyObject *__pyx_v_cyModel); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_9CyPEPivot_9CyPEPivot_2__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_9CyPEPivot_CyPEPivot *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_9CyPEPivot_9CyPEPivot_4__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_9CyPEPivot_CyPEPivot *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_9CyPEPivot_CyPEPivot(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_int_neg_1; - static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; --static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; - /* Late includes */ - - /* "cylp/cy/CyPEPivot.pyx":12 -@@ -2614,6 +2674,9 @@ static PyObject *__pyx_tuple__9; - static int __pyx_pw_4cylp_2cy_9CyPEPivot_9CyPEPivot_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ - static int __pyx_pw_4cylp_2cy_9CyPEPivot_9CyPEPivot_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_cyModel = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - int __pyx_r; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); -@@ -2666,6 +2729,9 @@ static int __pyx_pf_4cylp_2cy_9CyPEPivot_9CyPEPivot___init__(struct __pyx_obj_4c - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__init__", 0); - - /* "cylp/cy/CyPEPivot.pyx":13 -@@ -2773,6 +2839,9 @@ static PyObject *__pyx_f_4cylp_2cy_9CyPEPivot_9CyPEPivot_pivotColumn(struct __py - Py_ssize_t __pyx_t_12; - Py_ssize_t __pyx_t_13; - int __pyx_t_14; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("pivotColumn", 0); - - /* "cylp/cy/CyPEPivot.pyx":19 -@@ -3867,6 +3936,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyPEPivot_9CyPEPivot_2__reduce_cython__(CYT - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3922,6 +3994,9 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyPEPivot_9CyPEPivot_4__setstate_cython__(C - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3952,1918 +4027,331 @@ static PyObject *__pyx_pf_4cylp_2cy_9CyPEPivot_9CyPEPivot_4__setstate_cython__(C - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t -+ * -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * - */ - --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -+ PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ * cdef inline object PyArray_MultiIterNew1(a): -+ * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< - * -+ * cdef inline object PyArray_MultiIterNew2(a, b): - */ -- __pyx_v_endian_detector = 1; -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t -+ * -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * ndim = PyArray_NDIM(self) - */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) - */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew2(a, b): -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< - * -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) - */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -+ * -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") - */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< - * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * info.buf = PyArray_DATA(self) - */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. - */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * - */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef int t - */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< - * -+ * cdef inline tuple PyDataType_SHAPE(dtype d): - */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- * info.obj = self # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * if not PyDataType_HASFIELDS(descr): - */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -- * -- * cdef inline object PyArray_MultiIterNew1(a): -- * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -- * else: -- * return () -- */ -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -- __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -- * return <tuple>d.subarray.shape -- * else: -- * return () # <<<<<<<<<<<<<< -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -- */ -- /*else*/ { -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(__pyx_empty_tuple); -- __pyx_r = __pyx_empty_tuple; -- goto __pyx_L0; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- -- /* function exit code */ -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ int __pyx_t_1; -+ __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ -- goto __pyx_L13; -- } -+ __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -+ if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -+ * else: -+ * return () - */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -+ __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ - } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 -+ * return <tuple>d.subarray.shape -+ * else: -+ * return () # <<<<<<<<<<<<<< - * - * - */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -+ /*else*/ { -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(__pyx_empty_tuple); -+ __pyx_r = __pyx_empty_tuple; -+ goto __pyx_L0; -+ } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ - - /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; - __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -+ __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5875,7 +4363,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -5884,7 +4372,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5893,7 +4381,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5905,7 +4393,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5920,7 +4408,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5929,7 +4417,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5939,7 +4427,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5950,7 +4438,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5959,7 +4447,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5971,7 +4459,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5986,12 +4474,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -6005,13 +4493,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -6023,20 +4514,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -6046,9 +4537,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -6056,32 +4547,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -6092,12 +4583,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -6115,7 +4606,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -6134,9 +4625,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6152,16 +4646,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6175,7 +4669,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -6185,28 +4679,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6221,7 +4715,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -6244,7 +4738,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -6263,9 +4757,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6281,16 +4778,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -6304,69 +4801,246 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -- * _import_umath() -- * except Exception: -- * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 -+ * _import_umath() -+ * except Exception: -+ * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: -+ */ -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) -+ __Pyx_GOTREF(__pyx_t_8); -+ __Pyx_Raise(__pyx_t_8, 0, 0, 0); -+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -+ __PYX_ERR(2, 957, __pyx_L5_except_error) -+ } -+ goto __pyx_L5_except_error; -+ __pyx_L5_except_error:; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 -+ * -+ * cdef inline int import_ufunc() except -1: -+ * try: # <<<<<<<<<<<<<< -+ * _import_umath() -+ * except Exception: -+ */ -+ __Pyx_XGIVEREF(__pyx_t_1); -+ __Pyx_XGIVEREF(__pyx_t_2); -+ __Pyx_XGIVEREF(__pyx_t_3); -+ __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -+ goto __pyx_L1_error; -+ __pyx_L8_try_end:; -+ } -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 -+ * raise ImportError("numpy.core.umath failed to import") -+ * -+ * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -+ * try: -+ * _import_umath() -+ */ -+ -+ /* function exit code */ -+ __pyx_r = 0; -+ goto __pyx_L0; -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_5); -+ __Pyx_XDECREF(__pyx_t_6); -+ __Pyx_XDECREF(__pyx_t_7); -+ __Pyx_XDECREF(__pyx_t_8); -+ __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = -1; -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_Raise(__pyx_t_8, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -- } -- goto __pyx_L5_except_error; -- __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * - * -- * cdef inline int import_ufunc() except -1: -- * try: # <<<<<<<<<<<<<< -- * _import_umath() -- * except Exception: - */ -- __Pyx_XGIVEREF(__pyx_t_1); -- __Pyx_XGIVEREF(__pyx_t_2); -- __Pyx_XGIVEREF(__pyx_t_3); -- __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -- goto __pyx_L1_error; -- __pyx_L8_try_end:; -- } -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object - */ - - /* function exit code */ -- __pyx_r = 0; -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); - goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_5); -- __Pyx_XDECREF(__pyx_t_6); -- __Pyx_XDECREF(__pyx_t_7); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ - __pyx_L0:; -- __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - static struct __pyx_vtabstruct_4cylp_2cy_9CyPEPivot_CyPEPivot __pyx_vtable_4cylp_2cy_9CyPEPivot_CyPEPivot; -@@ -6414,7 +5088,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_9CyPEPivot_CyPEPivot = { - sizeof(struct __pyx_obj_4cylp_2cy_9CyPEPivot_CyPEPivot), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_9CyPEPivot_CyPEPivot, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -6467,6 +5146,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_9CyPEPivot_CyPEPivot = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -6516,13 +5201,8 @@ static struct PyModuleDef __pyx_moduledef = { - - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyPEPivot, __pyx_k_CyPEPivot, sizeof(__pyx_k_CyPEPivot), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_clear, __pyx_k_clear, sizeof(__pyx_k_clear), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_kp_s_comp_selected, __pyx_k_comp_selected, sizeof(__pyx_k_comp_selected), 0, 0, 1, 0}, -@@ -6540,8 +5220,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_nElements, __pyx_k_nElements, sizeof(__pyx_k_nElements), 0, 0, 1, 1}, - {&__pyx_n_s_nVariables, __pyx_k_nVariables, sizeof(__pyx_k_nVariables), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_n_s_np, __pyx_k_np, sizeof(__pyx_k_np), 0, 0, 1, 1}, - {&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, -@@ -6558,7 +5236,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, - {&__pyx_n_s_transposeTimes, __pyx_k_transposeTimes, sizeof(__pyx_k_transposeTimes), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {&__pyx_n_s_updateColumnTranspose, __pyx_k_updateColumnTranspose, sizeof(__pyx_k_updateColumnTranspose), 0, 0, 1, 1}, - {&__pyx_n_s_updateP, __pyx_k_updateP, sizeof(__pyx_k_updateP), 0, 0, 1, 1}, - {&__pyx_n_s_updateW, __pyx_k_updateW, sizeof(__pyx_k_updateW), 0, 0, 1, 1}, -@@ -6580,10 +5257,7 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - #endif - __pyx_builtin_print = __Pyx_GetBuiltinName(__pyx_n_s_print); if (!__pyx_builtin_print) __PYX_ERR(0, 71, __pyx_L1_error) - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(1, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -6612,82 +5286,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6738,6 +5357,9 @@ static int __Pyx_modinit_function_export_code(void) { - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpPrimalColumnPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) -@@ -6774,6 +5396,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -6803,18 +5428,38 @@ static int __Pyx_modinit_type_import_code(void) { - if (!__pyx_ptype_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector) __PYX_ERR(6, 22, __pyx_L1_error) - __pyx_vtabptr_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector = (struct __pyx_vtabstruct_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector*)__Pyx_GetVtable(__pyx_ptype_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector->tp_dict); if (unlikely(!__pyx_vtabptr_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector)) __PYX_ERR(6, 22, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(7, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -6917,13 +5562,17 @@ static int __Pyx_modinit_variable_import_code(void) { - static int __Pyx_modinit_function_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); - /*--- Function import code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpPrimalColumnPivotBase"); if (!__pyx_t_1) __PYX_ERR(0, 1, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); - if (__Pyx_ImportFunction(__pyx_t_1, "RunPivotColumn", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunPivotColumn, "int (void *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunClone", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunClone, "ClpPrimalColumnPivot *(void *, int)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunSaveWeights", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunSaveWeights, "void (void *, IClpSimplex *, int)") < 0) __PYX_ERR(0, 1, __pyx_L1_error) -- Py_DECREF(__pyx_t_1); __pyx_t_1 = 0; -+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6933,17 +5582,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -7025,6 +5676,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyPEPivot(PyObject *__pyx_pyinit_m - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -7072,11 +5726,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -7113,17 +5765,17 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(0, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(0, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); -- if (unlikely(__Pyx_modinit_function_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_function_import_code() < 0)) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Execution code ---*/ - #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) - if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) -@@ -7151,12 +5803,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -7265,7 +5917,7 @@ static int __Pyx_ParseOptionalKeywords( - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 -- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { -+ if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { -@@ -7292,7 +5944,7 @@ static int __Pyx_ParseOptionalKeywords( - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -7308,7 +5960,7 @@ static int __Pyx_ParseOptionalKeywords( - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -7530,7 +6182,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -7617,7 +6269,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -7941,7 +6593,7 @@ static PyObject *__Pyx_PyLong_AbsNeg(PyObject *n) { - { - PyObject *copy = _PyLong_Copy((PyLongObject*)n); - if (likely(copy)) { -- Py_SIZE(copy) = -(Py_SIZE(copy)); -+ __Pyx_SET_SIZE(copy, -Py_SIZE(copy)); - } - return copy; - } -@@ -8134,48 +6786,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -8514,6 +7124,28 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable) { - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -8541,43 +7173,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -8620,7 +7260,7 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { - { - #if PY_MAJOR_VERSION >= 3 - if (level == -1) { -- if (strchr(__Pyx_MODULE_NAME, '.')) { -+ if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) { - module = PyImport_ImportModuleLevelObject( - name, global_dict, empty_dict, list, 1); - if (!module) { -@@ -8657,7 +7297,7 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -8687,7 +7327,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -8761,7 +7401,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -8784,30 +7424,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -8826,11 +7467,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -8862,37 +7508,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - Py_XDECREF(py_frame); - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(long) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(long) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(long) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(long), -- little, !is_unsigned); -- } --} -- - /* CIntFromPyVerify */ - #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -@@ -8915,37 +7530,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { - return (target_type) value;\ - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- - /* Declarations */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus -@@ -9063,7 +7647,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -9218,7 +7801,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -9257,24 +7839,31 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - #endif - - /* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -+ if (sizeof(long) < sizeof(long)) { - return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -+ } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif - } - } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -+ if (sizeof(long) <= sizeof(long)) { - return PyInt_FromLong((long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - #endif - } -@@ -9282,14 +7871,21 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES v - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -+ return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); - } - } - - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -9476,9 +8072,54 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - return (int) -1; - } - -+/* CIntToPy */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(int) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); -+ } -+} -+ - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -10083,6 +8724,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyPivotPythonBase.cpp b/cylp/cy/CyPivotPythonBase.cpp -index dfb373e..ad6db3d 100644 ---- a/cylp/cy/CyPivotPythonBase.cpp -+++ b/cylp/cy/CyPivotPythonBase.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -612,7 +695,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "pythread.h" - #include "ICoinIndexedVector.hpp" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ClpDualRowPivot.hpp" - #include "ClpFactorization.hpp" - #include "IClpDualRowPivotBase.h" -@@ -641,11 +730,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "OsiSolverInterface.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "IClpPrimalColumnPivotBase.h" - #include "ClpPrimalColumnPivot.hpp" -@@ -746,6 +835,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -881,23 +971,23 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyPivotPythonBase.pyx", -+ "cylp/cy/CyPivotPythonBase.pyx", - "__init__.pxd", - "type.pxd", - "bool.pxd", - "complex.pxd", -- "cylp\\cy\\CyCoinIndexedVector.pxd", -- "cylp\\cy\\CyClpDualRowPivotBase.pxd", -- "cylp\\cy\\CyCoinModel.pxd", -- "cylp\\cy\\CyCoinPackedMatrix.pxd", -- "cylp\\cy\\CyCgl.pxd", -- "cylp\\cy\\CyCbcNode.pxd", -- "cylp\\cy\\CyOsiSolverInterface.pxd", -- "cylp\\cy\\CyCbcModel.pxd", -- "cylp\\cy\\CyClpSimplex.pxd", -+ "cylp/cy/CyCoinIndexedVector.pxd", -+ "cylp/cy/CyClpDualRowPivotBase.pxd", -+ "cylp/cy/CyCoinModel.pxd", -+ "cylp/cy/CyCoinPackedMatrix.pxd", -+ "cylp/cy/CyCgl.pxd", -+ "cylp/cy/CyCbcNode.pxd", -+ "cylp/cy/CyOsiSolverInterface.pxd", -+ "cylp/cy/CyCbcModel.pxd", -+ "cylp/cy/CyClpSimplex.pxd", - }; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -906,7 +996,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -915,7 +1005,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -924,7 +1014,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -933,7 +1023,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -942,7 +1032,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -951,7 +1041,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -960,7 +1050,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -969,7 +1059,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -978,7 +1068,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -987,7 +1077,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -996,7 +1086,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1005,7 +1095,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1014,7 +1104,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1023,7 +1113,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1032,7 +1122,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1041,7 +1131,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1050,7 +1140,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1059,7 +1149,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1068,7 +1158,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1077,7 +1167,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1140,7 +1230,7 @@ struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus; - struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase; - struct __pyx_obj_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1149,7 +1239,7 @@ struct __pyx_obj_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1158,7 +1248,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1167,7 +1257,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1880,6 +1970,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -1887,6 +1978,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -1958,29 +2050,6 @@ static void __Pyx_WriteUnraisable(const char *name, int clineno, - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -2053,6 +2122,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -2108,8 +2180,10 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); - static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -2210,10 +2284,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - #endif - - /* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- --/* CIntFromPy.proto */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -@@ -2221,6 +2292,9 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -+/* CIntFromPy.proto */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+ - /* FastTypeChecks.proto */ - #if CYTHON_COMPILING_IN_CPYTHON - #define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -@@ -2342,8 +2416,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyClpDualRowPivotBase' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase = 0; -@@ -2404,61 +2487,41 @@ int __pyx_module_is_main_cylp__cy__CyPivotPythonBase = 0; - - /* Implementation of 'cylp.cy.CyPivotPythonBase' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_init[] = "__init__"; - static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_test[] = "__test__"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_reduce[] = "__reduce__"; - static const char __pyx_k_getstate[] = "__getstate__"; - static const char __pyx_k_setstate[] = "__setstate__"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; - static const char __pyx_k_pivotColumn[] = "pivotColumn"; - static const char __pyx_k_saveWeights[] = "saveWeights"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_CyPivotPythonBase[] = "CyPivotPythonBase"; - static const char __pyx_k_pivotMethodObject[] = "pivotMethodObject"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_self_CppSelf_cannot_be_converted[] = "self.CppSelf cannot be converted to a Python object for pickling"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyPivotPythonBase; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_getstate; - static PyObject *__pyx_n_s_init; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_pivotColumn; - static PyObject *__pyx_n_s_pivotMethodObject; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -2467,23 +2530,15 @@ static PyObject *__pyx_kp_s_self_CppSelf_cannot_be_converted; - static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static int __pyx_pf_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase___init__(struct __pyx_obj_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase *__pyx_v_self, PyObject *__pyx_v_pivotMethodObject); /* proto */ - static void __pyx_pf_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase_2__dealloc__(struct __pyx_obj_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase_4__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase_6__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; --static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; - /* Late includes */ - - /* "cylp/cy/CyPivotPythonBase.pyx":7 -@@ -2498,6 +2553,9 @@ static PyObject *__pyx_tuple__9; - static int __pyx_pw_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ - static int __pyx_pw_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_pivotMethodObject = 0; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - int __pyx_r; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); -@@ -2550,6 +2608,9 @@ static int __pyx_pf_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase___init__(s - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__init__", 0); - - /* "cylp/cy/CyPivotPythonBase.pyx":8 -@@ -2691,6 +2752,9 @@ static PyObject *__pyx_f_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase_pivot - PyObject *__pyx_t_3 = NULL; - int __pyx_t_4; - PyObject *__pyx_t_5 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("pivotColumn", 0); - - /* "cylp/cy/CyPivotPythonBase.pyx":18 -@@ -2975,6 +3039,9 @@ static void __pyx_f_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase_saveWeight - PyObject *__pyx_t_4 = NULL; - int __pyx_t_5; - PyObject *__pyx_t_6 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("saveWeights", 0); - - /* "cylp/cy/CyPivotPythonBase.pyx":42 -@@ -3105,6 +3172,9 @@ static PyObject *__pyx_pf_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase_4__r - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3160,6 +3230,9 @@ static PyObject *__pyx_pf_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase_6__s - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3190,863 +3263,7 @@ static PyObject *__pyx_pf_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase_6__s - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -- * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * -- * ndim = PyArray_NDIM(self) -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -- * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -- * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -- * -- * cdef int t -- */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -- * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -- * -- */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -- * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4058,9 +3275,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * - * cdef inline object PyArray_MultiIterNew1(a): - * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -@@ -4068,13 +3288,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - * cdef inline object PyArray_MultiIterNew2(a, b): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 - * ctypedef npy_cdouble complex_t - * - * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -@@ -4093,7 +3313,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4105,9 +3325,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * - * cdef inline object PyArray_MultiIterNew2(a, b): - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -@@ -4115,13 +3338,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 - * return PyArray_MultiIterNew(1, <void*>a) - * - * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -@@ -4140,7 +3363,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4152,9 +3375,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -@@ -4162,13 +3388,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 - * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -@@ -4187,7 +3413,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4199,9 +3425,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -@@ -4209,13 +3438,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -4234,7 +3463,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4246,9 +3475,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -@@ -4256,13 +3488,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - * cdef inline tuple PyDataType_SHAPE(dtype d): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -4281,7 +3513,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4295,7 +3527,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - int __pyx_t_1; - __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4305,7 +3537,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): - * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -@@ -4317,7 +3549,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * - * cdef inline tuple PyDataType_SHAPE(dtype d): - * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -@@ -4326,12 +3558,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 - * return <tuple>d.subarray.shape - * else: - * return () # <<<<<<<<<<<<<< - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -+ * - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); -@@ -4340,7 +3572,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - goto __pyx_L0; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 - * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -@@ -4355,765 +3587,19 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__ - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 -+ * int _import_umath() except -1 - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -+ * Py_INCREF(base) # important to do this before stealing the reference below! -+ * PyArray_SetBaseObject(arr, base) - */ - --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -+static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_arr, PyObject *__pyx_v_base) { - __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -+ __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- goto __pyx_L13; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -- */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -- * -- * -- */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; -- __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -- * int _import_umath() except -1 -- * -- * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -- * Py_INCREF(base) # important to do this before stealing the reference below! -- * PyArray_SetBaseObject(arr, base) -- */ -- --static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_arr, PyObject *__pyx_v_base) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("set_array_base", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -5122,7 +3608,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5131,7 +3617,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5143,7 +3629,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5158,7 +3644,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5167,7 +3653,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5177,7 +3663,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5188,7 +3674,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5197,7 +3683,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5209,7 +3695,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5224,12 +3710,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -5243,13 +3729,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -5261,20 +3750,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5284,9 +3773,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5294,32 +3783,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5330,12 +3819,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -5353,7 +3842,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5372,9 +3861,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5390,16 +3882,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5413,7 +3905,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -5423,28 +3915,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5459,7 +3951,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5482,7 +3974,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5501,9 +3993,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5519,16 +4014,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5542,35 +4037,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5585,7 +4083,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5607,6 +4105,180 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} - static struct __pyx_vtabstruct_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase __pyx_vtable_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase; - - static PyObject *__pyx_tp_new_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -5630,9 +4302,9 @@ static void __pyx_tp_dealloc_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase(PyO - { - PyObject *etype, *eval, *etb; - PyErr_Fetch(&etype, &eval, &etb); -- ++Py_REFCNT(o); -+ __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); - __pyx_pw_4cylp_2cy_17CyPivotPythonBase_17CyPivotPythonBase_3__dealloc__(o); -- --Py_REFCNT(o); -+ __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); - PyErr_Restore(etype, eval, etb); - } - Py_CLEAR(p->pivotMethodObject); -@@ -5672,7 +4344,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase = - sizeof(struct __pyx_obj_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -5725,6 +4402,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_17CyPivotPythonBase_CyPivotPythonBase = - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -5774,26 +4457,18 @@ static struct PyModuleDef __pyx_moduledef = { - - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyPivotPythonBase, __pyx_k_CyPivotPythonBase, sizeof(__pyx_k_CyPivotPythonBase), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, - {&__pyx_n_s_init, __pyx_k_init, sizeof(__pyx_k_init), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_pivotColumn, __pyx_k_pivotColumn, sizeof(__pyx_k_pivotColumn), 0, 0, 1, 1}, - {&__pyx_n_s_pivotMethodObject, __pyx_k_pivotMethodObject, sizeof(__pyx_k_pivotMethodObject), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -5802,15 +4477,11 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -5839,82 +4510,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -5964,6 +4580,9 @@ static int __Pyx_modinit_function_export_code(void) { - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpPrimalColumnPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -6000,6 +4619,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -6029,18 +4651,38 @@ static int __Pyx_modinit_type_import_code(void) { - if (!__pyx_ptype_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector) __PYX_ERR(6, 22, __pyx_L1_error) - __pyx_vtabptr_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector = (struct __pyx_vtabstruct_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector*)__Pyx_GetVtable(__pyx_ptype_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector->tp_dict); if (unlikely(!__pyx_vtabptr_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector)) __PYX_ERR(6, 22, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(7, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -6143,13 +4785,17 @@ static int __Pyx_modinit_variable_import_code(void) { - static int __Pyx_modinit_function_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); - /*--- Function import code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpPrimalColumnPivotBase"); if (!__pyx_t_1) __PYX_ERR(1, 1, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); - if (__Pyx_ImportFunction(__pyx_t_1, "RunPivotColumn", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunPivotColumn, "int (void *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunClone", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunClone, "ClpPrimalColumnPivot *(void *, int)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunSaveWeights", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunSaveWeights, "void (void *, IClpSimplex *, int)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) -- Py_DECREF(__pyx_t_1); __pyx_t_1 = 0; -+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6159,17 +4805,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6251,6 +4899,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyPivotPythonBase(PyObject *__pyx_ - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -6298,11 +4949,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -6339,17 +4988,17 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); -- if (unlikely(__Pyx_modinit_function_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_function_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Execution code ---*/ - #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) - if (__Pyx_patch_abc() < 0) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -6365,12 +5014,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -6479,7 +5128,7 @@ static int __Pyx_ParseOptionalKeywords( - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 -- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { -+ if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { -@@ -6506,7 +5155,7 @@ static int __Pyx_ParseOptionalKeywords( - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -6522,7 +5171,7 @@ static int __Pyx_ParseOptionalKeywords( - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 -- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : -+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; -@@ -6731,7 +5380,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -6818,7 +5467,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -7083,61 +5732,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * -@@ -7476,6 +6070,28 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable) { - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -7503,43 +6119,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -7580,7 +6204,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -7610,7 +6234,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -7684,7 +6308,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -7707,30 +6331,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -7749,11 +6374,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -7785,37 +6415,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - Py_XDECREF(py_frame); - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- - /* Declarations */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus -@@ -7933,7 +6532,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -8088,7 +6686,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -8126,251 +6723,54 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - #endif - #endif - --/* CIntFromPyVerify */ --#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ -- __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) --#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ -- __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) --#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ -- {\ -- func_type value = func_value;\ -- if (sizeof(target_type) < sizeof(func_type)) {\ -- if (unlikely(value != (func_type) (target_type) value)) {\ -- func_type zero = 0;\ -- if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ -- return (target_type) -1;\ -- if (is_unsigned && unlikely(value < zero))\ -- goto raise_neg_overflow;\ -- else\ -- goto raise_overflow;\ -- }\ -- }\ -- return (target_type) value;\ -- } -- - /* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; - const int is_unsigned = neg_one > const_zero; --#if PY_MAJOR_VERSION < 3 -- if (likely(PyInt_Check(x))) { -+ if (is_unsigned) { - if (sizeof(int) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) -- } else { -- long val = PyInt_AS_LONG(x); -- if (is_unsigned && unlikely(val < 0)) { -- goto raise_neg_overflow; -- } -- return (int) val; -- } -- } else --#endif -- if (likely(PyLong_Check(x))) { -- if (is_unsigned) { --#if CYTHON_USE_PYLONG_INTERNALS -- const digit* digits = ((PyLongObject*)x)->ob_digit; -- switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) -- case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -- return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -- } -- } -- break; -- case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -- return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -- } -- } -- break; -- case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -- return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -- } -- } -- break; -- } --#endif --#if CYTHON_COMPILING_IN_CPYTHON -- if (unlikely(Py_SIZE(x) < 0)) { -- goto raise_neg_overflow; -- } --#else -- { -- int result = PyObject_RichCompareBool(x, Py_False, Py_LT); -- if (unlikely(result < 0)) -- return (int) -1; -- if (unlikely(result == 1)) -- goto raise_neg_overflow; -- } --#endif -- if (sizeof(int) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) --#endif -- } -- } else { --#if CYTHON_USE_PYLONG_INTERNALS -- const digit* digits = ((PyLongObject*)x)->ob_digit; -- switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) -- case -2: -- if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- case -3: -- if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- case -4: -- if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -- } -- } -- break; -- } --#endif -- if (sizeof(int) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) --#endif -- } -- } -- { --#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) -- PyErr_SetString(PyExc_RuntimeError, -- "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); --#else -- int val; -- PyObject *v = __Pyx_PyNumber_IntOrLong(x); -- #if PY_MAJOR_VERSION < 3 -- if (likely(v) && !PyLong_Check(v)) { -- PyObject *tmp = v; -- v = PyNumber_Long(tmp); -- Py_DECREF(tmp); -- } -- #endif -- if (likely(v)) { -- int one = 1; int is_little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&val; -- int ret = _PyLong_AsByteArray((PyLongObject *)v, -- bytes, sizeof(val), -- is_little, !is_unsigned); -- Py_DECREF(v); -- if (likely(!ret)) -- return val; -- } -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif -- return (int) -1; - } - } else { -- int val; -- PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (int) -1; -- val = __Pyx_PyInt_As_int(tmp); -- Py_DECREF(tmp); -- return val; -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); - } --raise_overflow: -- PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to int"); -- return (int) -1; --raise_neg_overflow: -- PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to int"); -- return (int) -1; - } - - /* CIntToPy */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { -@@ -8399,9 +6799,38 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { - } - } - -+/* CIntFromPyVerify */ -+#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ -+ __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -+#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ -+ __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) -+#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ -+ {\ -+ func_type value = func_value;\ -+ if (sizeof(target_type) < sizeof(func_type)) {\ -+ if (unlikely(value != (func_type) (target_type) value)) {\ -+ func_type zero = 0;\ -+ if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ -+ return (target_type) -1;\ -+ if (is_unsigned && unlikely(value < zero))\ -+ goto raise_neg_overflow;\ -+ else\ -+ goto raise_overflow;\ -+ }\ -+ }\ -+ return (target_type) value;\ -+ } -+ - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -8588,6 +7017,202 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - return (long) -1; - } - -+/* CIntFromPy */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+#if PY_MAJOR_VERSION < 3 -+ if (likely(PyInt_Check(x))) { -+ if (sizeof(int) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) -+ } else { -+ long val = PyInt_AS_LONG(x); -+ if (is_unsigned && unlikely(val < 0)) { -+ goto raise_neg_overflow; -+ } -+ return (int) val; -+ } -+ } else -+#endif -+ if (likely(PyLong_Check(x))) { -+ if (is_unsigned) { -+#if CYTHON_USE_PYLONG_INTERNALS -+ const digit* digits = ((PyLongObject*)x)->ob_digit; -+ switch (Py_SIZE(x)) { -+ case 0: return (int) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) -+ case 2: -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -+ return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ } -+ } -+ break; -+ case 3: -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -+ return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ } -+ } -+ break; -+ case 4: -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -+ return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ } -+ } -+ break; -+ } -+#endif -+#if CYTHON_COMPILING_IN_CPYTHON -+ if (unlikely(Py_SIZE(x) < 0)) { -+ goto raise_neg_overflow; -+ } -+#else -+ { -+ int result = PyObject_RichCompareBool(x, Py_False, Py_LT); -+ if (unlikely(result < 0)) -+ return (int) -1; -+ if (unlikely(result == 1)) -+ goto raise_neg_overflow; -+ } -+#endif -+ if (sizeof(int) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+#endif -+ } -+ } else { -+#if CYTHON_USE_PYLONG_INTERNALS -+ const digit* digits = ((PyLongObject*)x)->ob_digit; -+ switch (Py_SIZE(x)) { -+ case 0: return (int) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) -+ case -2: -+ if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ case 2: -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ case -3: -+ if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ case 3: -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ case -4: -+ if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ case 4: -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ } -+ } -+ break; -+ } -+#endif -+ if (sizeof(int) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -+#endif -+ } -+ } -+ { -+#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) -+ PyErr_SetString(PyExc_RuntimeError, -+ "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); -+#else -+ int val; -+ PyObject *v = __Pyx_PyNumber_IntOrLong(x); -+ #if PY_MAJOR_VERSION < 3 -+ if (likely(v) && !PyLong_Check(v)) { -+ PyObject *tmp = v; -+ v = PyNumber_Long(tmp); -+ Py_DECREF(tmp); -+ } -+ #endif -+ if (likely(v)) { -+ int one = 1; int is_little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&val; -+ int ret = _PyLong_AsByteArray((PyLongObject *)v, -+ bytes, sizeof(val), -+ is_little, !is_unsigned); -+ Py_DECREF(v); -+ if (likely(!ret)) -+ return val; -+ } -+#endif -+ return (int) -1; -+ } -+ } else { -+ int val; -+ PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -+ if (!tmp) return (int) -1; -+ val = __Pyx_PyInt_As_int(tmp); -+ Py_DECREF(tmp); -+ return val; -+ } -+raise_overflow: -+ PyErr_SetString(PyExc_OverflowError, -+ "value too large to convert to int"); -+ return (int) -1; -+raise_neg_overflow: -+ PyErr_SetString(PyExc_OverflowError, -+ "can't convert negative value to int"); -+ return (int) -1; -+} -+ - /* FastTypeChecks */ - #if CYTHON_COMPILING_IN_CPYTHON - static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { -@@ -9006,6 +7631,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyTest.cpp b/cylp/cy/CyTest.cpp -index 27df348..5d2bf28 100644 ---- a/cylp/cy/CyTest.cpp -+++ b/cylp/cy/CyTest.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.21 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_21" --#define CYTHON_HEX_VERSION 0x001D15F0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -450,7 +517,11 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) - #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif - #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) - #endif -@@ -556,10 +627,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) -@@ -627,7 +698,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "ClpFactorization.hpp" - #include "IClpPrimalColumnPivotBase.h" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ClpDualRowPivot.hpp" - #include "IClpDualRowPivotBase.h" - #include "CoinModel.hpp" -@@ -655,11 +732,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "OsiSolverInterface.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "IClpSimplex.hpp" - #ifdef _OPENMP -@@ -758,6 +835,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -911,7 +989,7 @@ static const char *__pyx_f[] = { - "cylp/cy/CyPEPivot.pxd", - }; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":775 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -920,7 +998,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -929,7 +1007,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -938,7 +1016,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -947,7 +1025,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":782 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -956,7 +1034,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -965,7 +1043,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -974,7 +1052,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -983,7 +1061,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":789 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -992,7 +1070,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -1001,7 +1079,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":799 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -1010,7 +1088,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1019,7 +1097,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1028,7 +1106,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":803 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1037,7 +1115,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1046,7 +1124,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1055,7 +1133,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":807 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1064,7 +1142,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1073,7 +1151,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":810 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1082,7 +1160,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1091,7 +1169,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1155,7 +1233,7 @@ struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus; - struct __pyx_obj_4cylp_2cy_14CyDantzigPivot_CyDantzigPivot; - struct __pyx_obj_4cylp_2cy_9CyPEPivot_CyPEPivot; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":814 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1164,7 +1242,7 @@ struct __pyx_obj_4cylp_2cy_9CyPEPivot_CyPEPivot; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1173,7 +1251,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1182,7 +1260,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":818 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1913,6 +1991,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -1920,6 +1999,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -2014,6 +2094,11 @@ static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_ve - static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); - #endif - -+/* GetTopmostException.proto */ -+#if CYTHON_USE_EXC_INFO_STACK -+static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -+#endif -+ - /* PyThreadStateGet.proto */ - #if CYTHON_FAST_THREAD_STATE - #define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; -@@ -2025,6 +2110,33 @@ static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); - #define __Pyx_PyErr_Occurred() PyErr_Occurred() - #endif - -+/* SaveResetException.proto */ -+#if CYTHON_FAST_THREAD_STATE -+#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) -+static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); -+#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) -+static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); -+#else -+#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) -+#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) -+#endif -+ -+/* PyErrExceptionMatches.proto */ -+#if CYTHON_FAST_THREAD_STATE -+#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) -+static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); -+#else -+#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) -+#endif -+ -+/* GetException.proto */ -+#if CYTHON_FAST_THREAD_STATE -+#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) -+static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); -+#else -+static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); -+#endif -+ - /* PyErrFetchRestore.proto */ - #if CYTHON_FAST_THREAD_STATE - #define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) -@@ -2053,61 +2165,6 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- --/* GetTopmostException.proto */ --#if CYTHON_USE_EXC_INFO_STACK --static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); --#endif -- --/* SaveResetException.proto */ --#if CYTHON_FAST_THREAD_STATE --#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) --static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); --#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) --static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); --#else --#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) --#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) --#endif -- --/* PyErrExceptionMatches.proto */ --#if CYTHON_FAST_THREAD_STATE --#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) --static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); --#else --#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) --#endif -- --/* GetException.proto */ --#if CYTHON_FAST_THREAD_STATE --#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) --static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); --#else --static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); --#endif -- - /* TypeImport.proto */ - #ifndef __PYX_HAVE_RT_ImportType_proto - #define __PYX_HAVE_RT_ImportType_proto -@@ -2252,14 +2309,10 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #endif - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- --/* CIntFromPy.proto */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* CIntToPy.proto */ - static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -@@ -2267,6 +2320,9 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -+/* CIntFromPy.proto */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); -+ - /* FastTypeChecks.proto */ - #if CYTHON_COMPILING_IN_CPYTHON - #define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -@@ -2385,8 +2441,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyClpDualRowPivotBase' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase = 0; -@@ -2446,9 +2511,6 @@ int __pyx_module_is_main_cylp__cy__CyTest = 0; - - /* Implementation of 'cylp.cy.CyTest' */ - static PyObject *__pyx_builtin_print; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_d[] = "d"; - static const char __pyx_k_p[] = "p"; -@@ -2459,7 +2521,6 @@ static const char __pyx_k_name[] = "__name__"; - static const char __pyx_k_test[] = "__test__"; - static const char __pyx_k_time[] = "time"; - static const char __pyx_k_print[] = "print"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_start[] = "start"; - static const char __pyx_k_dpivot[] = "dpivot"; - static const char __pyx_k_import[] = "__import__"; -@@ -2469,31 +2530,18 @@ static const char __pyx_k_primal[] = "primal"; - static const char __pyx_k_CySolve[] = "CySolve"; - static const char __pyx_k_fileName[] = "fileName"; - static const char __pyx_k_Exec_time[] = "Exec time: "; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_perf_counter[] = "perf_counter"; - static const char __pyx_k_cylp_cy_CyTest[] = "cylp.cy.CyTest"; - static const char __pyx_k_objectiveValue[] = "objectiveValue"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_cylp_cy_CyTest_pyx[] = "cylp/cy/CyTest.pyx"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CySolve; - static PyObject *__pyx_kp_s_Exec_time; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_cylp_cy_CyTest; - static PyObject *__pyx_kp_s_cylp_cy_CyTest_pyx; -@@ -2504,8 +2552,6 @@ static PyObject *__pyx_n_s_import; - static PyObject *__pyx_n_s_main; - static PyObject *__pyx_n_s_method; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_objectiveValue; -@@ -2515,25 +2561,16 @@ static PyObject *__pyx_n_s_ppivot; - static PyObject *__pyx_n_s_primal; - static PyObject *__pyx_n_s_print; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_s; - static PyObject *__pyx_n_s_start; - static PyObject *__pyx_n_s_sys; - static PyObject *__pyx_n_s_test; - static PyObject *__pyx_n_s_time; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_pf_4cylp_2cy_6CyTest_CySolve(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_fileName, PyObject *__pyx_v_method); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; --static PyObject *__pyx_tuple__4; --static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_codeobj__9; -+static PyObject *__pyx_codeobj__4; - /* Late includes */ - - /* "cylp/cy/CyTest.pyx":9 -@@ -2865,1020 +2902,161 @@ static PyObject *__pyx_pf_4cylp_2cy_6CyTest_CySolve(CYTHON_UNUSED PyObject *__py - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t -+ * -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * - */ - --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -+ PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -+ PyObject *__pyx_t_1 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":265 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): -+ * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< - * -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): - */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 736, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t - * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) - */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":271 -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") - */ -- if (unlikely(__pyx_t_1)) { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(1, 272, __pyx_L1_error) -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew2(a, b): -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 739, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":275 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(1, 276, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") - */ -- } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -- * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":279 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. -- */ -- __pyx_v_info->ndim = __pyx_v_ndim; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< - * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 742, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * cdef int t -- */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":296 -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset - */ -- __pyx_v_f = NULL; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -- * -- */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * info.obj = self # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(descr): -- */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":303 -- * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(1, 306, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(1, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(1, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":820 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * -- * cdef inline object PyArray_MultiIterNew1(a): -- * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 821, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":820 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":823 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 824, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":823 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":826 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 827, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":826 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":829 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - */ - -@@ -3891,7 +3069,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":830 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -@@ -3899,13 +3077,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ - __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 830, __pyx_L1_error) -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 745, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":829 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 - * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -@@ -3924,7 +3102,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__ - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":832 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 - * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -@@ -3941,863 +3119,114 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__ - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":833 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 - * - * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 833, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":832 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":835 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -- if (__pyx_t_1) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -- * else: -- * return () -- */ -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -- __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -- goto __pyx_L0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":839 -- * return <tuple>d.subarray.shape -- * else: -- * return () # <<<<<<<<<<<<<< -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -- */ -- /*else*/ { -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(__pyx_empty_tuple); -- __pyx_r = __pyx_empty_tuple; -- goto __pyx_L0; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":835 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- -- /* function exit code */ -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":841 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- int __pyx_lineno = 0; -- const char *__pyx_filename = NULL; -- int __pyx_clineno = 0; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":846 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":850 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(1, 850, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(1, 850, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 850, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(1, 851, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(1, 851, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(1, 852, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(1, 852, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(1, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":854 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 854, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 854, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 854, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(1, 855, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":854 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":857 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":857 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 859, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(1, 859, __pyx_L1_error) -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":857 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":869 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 869, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 869, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 869, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":874 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":876 -- * offset[0] += child.itemsize -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< - * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -+ * cdef inline tuple PyDataType_SHAPE(dtype d): - */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 748, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":877 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 877, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * - */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 879, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(1, 879, __pyx_L1_error) -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":882 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 882, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 882, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 882, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":900 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -- */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 900, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 900, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(1, 900, __pyx_L1_error) -- } -- __pyx_L15:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ int __pyx_t_1; -+ __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":876 -- * offset[0] += child.itemsize -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ -- goto __pyx_L13; -- } -+ __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -+ if (__pyx_t_1) { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":905 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -+ * else: -+ * return () - */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(1, 905, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -+ __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":850 -- * cdef tuple fields -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ - } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 -+ * return <tuple>d.subarray.shape -+ * else: -+ * return () # <<<<<<<<<<<<<< - * - * - */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -+ /*else*/ { -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(__pyx_empty_tuple); -+ __pyx_r = __pyx_empty_tuple; -+ goto __pyx_L0; -+ } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":841 -- * return () -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ - - /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; - __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -+ __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1021 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -4809,7 +3238,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -4818,7 +3247,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -4827,7 +3256,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1021 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -4839,7 +3268,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1025 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -4854,7 +3283,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -4863,7 +3292,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -4873,7 +3302,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -4884,7 +3313,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -4893,7 +3322,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -4905,7 +3334,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1025 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -4920,12 +3349,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1033 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -4944,11 +3373,11 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -4960,20 +3389,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 1035, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 943, __pyx_L3_error) - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -4983,9 +3412,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -4993,32 +3422,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 1036, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 1037, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(1, 1037, __pyx_L5_except_error) -+ __PYX_ERR(1, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5029,12 +3458,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1033 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -5052,7 +3481,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1039 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5076,7 +3505,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5092,16 +3521,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 1041, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 949, __pyx_L3_error) - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5115,7 +3544,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -5125,28 +3554,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 1042, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 1043, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(1, 1043, __pyx_L5_except_error) -+ __PYX_ERR(1, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5161,7 +3590,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1039 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5184,7 +3613,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1045 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5208,7 +3637,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5224,92 +3653,269 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 1047, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 955, __pyx_L3_error) -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 -+ * -+ * cdef inline int import_ufunc() except -1: -+ * try: # <<<<<<<<<<<<<< -+ * _import_umath() -+ * except Exception: -+ */ -+ } -+ __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; -+ __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; -+ __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; -+ goto __pyx_L8_try_end; -+ __pyx_L3_error:; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 -+ * try: -+ * _import_umath() -+ * except Exception: # <<<<<<<<<<<<<< -+ * raise ImportError("numpy.core.umath failed to import") -+ * -+ */ -+ __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); -+ if (__pyx_t_4) { -+ __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 956, __pyx_L5_except_error) -+ __Pyx_GOTREF(__pyx_t_5); -+ __Pyx_GOTREF(__pyx_t_6); -+ __Pyx_GOTREF(__pyx_t_7); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 -+ * _import_umath() -+ * except Exception: -+ * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: -+ */ -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 957, __pyx_L5_except_error) -+ __Pyx_GOTREF(__pyx_t_8); -+ __Pyx_Raise(__pyx_t_8, 0, 0, 0); -+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -+ __PYX_ERR(1, 957, __pyx_L5_except_error) -+ } -+ goto __pyx_L5_except_error; -+ __pyx_L5_except_error:; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 -+ * -+ * cdef inline int import_ufunc() except -1: -+ * try: # <<<<<<<<<<<<<< -+ * _import_umath() -+ * except Exception: -+ */ -+ __Pyx_XGIVEREF(__pyx_t_1); -+ __Pyx_XGIVEREF(__pyx_t_2); -+ __Pyx_XGIVEREF(__pyx_t_3); -+ __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -+ goto __pyx_L1_error; -+ __pyx_L8_try_end:; -+ } -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 -+ * raise ImportError("numpy.core.umath failed to import") -+ * -+ * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -+ * try: -+ * _import_umath() -+ */ -+ -+ /* function exit code */ -+ __pyx_r = 0; -+ goto __pyx_L0; -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_5); -+ __Pyx_XDECREF(__pyx_t_6); -+ __Pyx_XDECREF(__pyx_t_7); -+ __Pyx_XDECREF(__pyx_t_8); -+ __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = -1; -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * - * -- * cdef inline int import_ufunc() except -1: -- * try: # <<<<<<<<<<<<<< -- * _import_umath() -- * except Exception: - */ -- } -- __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; -- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; -- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; -- goto __pyx_L8_try_end; -- __pyx_L3_error:; -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -- * try: -- * _import_umath() -- * except Exception: # <<<<<<<<<<<<<< -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object - */ -- __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); -- if (__pyx_t_4) { -- __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 1048, __pyx_L5_except_error) -- __Pyx_GOTREF(__pyx_t_5); -- __Pyx_GOTREF(__pyx_t_6); -- __Pyx_GOTREF(__pyx_t_7); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -- * _import_umath() -- * except Exception: -- * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -- */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 1049, __pyx_L5_except_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_Raise(__pyx_t_8, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(1, 1049, __pyx_L5_except_error) -- } -- goto __pyx_L5_except_error; -- __pyx_L5_except_error:; -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: -- * try: # <<<<<<<<<<<<<< -- * _import_umath() -- * except Exception: -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ -- __Pyx_XGIVEREF(__pyx_t_1); -- __Pyx_XGIVEREF(__pyx_t_2); -- __Pyx_XGIVEREF(__pyx_t_3); -- __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); -- goto __pyx_L1_error; -- __pyx_L8_try_end:; -- } - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1045 -- * raise ImportError("numpy.core.umath failed to import") -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_5); -- __Pyx_XDECREF(__pyx_t_6); -- __Pyx_XDECREF(__pyx_t_7); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; - __pyx_L0:; -- __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - -@@ -5361,12 +3967,7 @@ static struct PyModuleDef __pyx_moduledef = { - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CySolve, __pyx_k_CySolve, sizeof(__pyx_k_CySolve), 0, 0, 1, 1}, - {&__pyx_kp_s_Exec_time, __pyx_k_Exec_time, sizeof(__pyx_k_Exec_time), 0, 0, 1, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_cylp_cy_CyTest, __pyx_k_cylp_cy_CyTest, sizeof(__pyx_k_cylp_cy_CyTest), 0, 0, 1, 1}, - {&__pyx_kp_s_cylp_cy_CyTest_pyx, __pyx_k_cylp_cy_CyTest_pyx, sizeof(__pyx_k_cylp_cy_CyTest_pyx), 0, 0, 1, 0}, -@@ -5377,8 +3978,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_method, __pyx_k_method, sizeof(__pyx_k_method), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_objectiveValue, __pyx_k_objectiveValue, sizeof(__pyx_k_objectiveValue), 0, 0, 1, 1}, -@@ -5388,21 +3987,16 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_primal, __pyx_k_primal, sizeof(__pyx_k_primal), 0, 0, 1, 1}, - {&__pyx_n_s_print, __pyx_k_print, sizeof(__pyx_k_print), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_s, __pyx_k_s, sizeof(__pyx_k_s), 0, 0, 1, 1}, - {&__pyx_n_s_start, __pyx_k_start, sizeof(__pyx_k_start), 0, 0, 1, 1}, - {&__pyx_n_s_sys, __pyx_k_sys, sizeof(__pyx_k_sys), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, - {&__pyx_n_s_time, __pyx_k_time, sizeof(__pyx_k_time), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_print = __Pyx_GetBuiltinName(__pyx_n_s_print); if (!__pyx_builtin_print) __PYX_ERR(0, 26, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(1, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(1, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(1, 855, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(1, 1037, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(1, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -5412,82 +4006,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple_)) __PYX_ERR(1, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple_); -- __Pyx_GIVEREF(__pyx_tuple_); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(1, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__2); -- __Pyx_GIVEREF(__pyx_tuple__2); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(1, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(1, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(1, 879, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(1, 1037, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -+ __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple_)) __PYX_ERR(1, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple_); -+ __Pyx_GIVEREF(__pyx_tuple_); - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(1, 1043, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -+ __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(1, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__2); -+ __Pyx_GIVEREF(__pyx_tuple__2); - - /* "cylp/cy/CyTest.pyx":9 - * -@@ -5496,10 +4035,10 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - * cdef CyClpSimplex s = CyClpSimplex() - * s.readMps(fileName, 0, 0) - */ -- __pyx_tuple__8 = PyTuple_Pack(6, __pyx_n_s_fileName, __pyx_n_s_method, __pyx_n_s_s, __pyx_n_s_dpivot, __pyx_n_s_ppivot, __pyx_n_s_start); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(0, 9, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -- __pyx_codeobj__9 = (PyObject*)__Pyx_PyCode_New(2, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__8, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_cylp_cy_CyTest_pyx, __pyx_n_s_CySolve, 9, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__9)) __PYX_ERR(0, 9, __pyx_L1_error) -+ __pyx_tuple__3 = PyTuple_Pack(6, __pyx_n_s_fileName, __pyx_n_s_method, __pyx_n_s_s, __pyx_n_s_dpivot, __pyx_n_s_ppivot, __pyx_n_s_start); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 9, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); -+ __pyx_codeobj__4 = (PyObject*)__Pyx_PyCode_New(2, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__3, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_cylp_cy_CyTest_pyx, __pyx_n_s_CySolve, 9, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__4)) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -5595,18 +4134,38 @@ static int __Pyx_modinit_type_import_code(void) { - if (!__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase) __PYX_ERR(6, 67, __pyx_L1_error) - __pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase = (struct __pyx_vtabstruct_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase*)__Pyx_GetVtable(__pyx_ptype_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase->tp_dict); if (unlikely(!__pyx_vtabptr_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase)) __PYX_ERR(6, 67, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(1, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(1, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(1, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(1, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(1, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(1, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(1, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(1, 917, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(1, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(1, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(1, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(1, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(1, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(1, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(1, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(1, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(1, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(1, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(1, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(1, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(7, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -5872,11 +4431,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -5983,12 +4540,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - -- /* "../../.local/anaconda3/lib/python3.8/site-packages/Cython/Includes/numpy/__init__.pxd":1045 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -6327,7 +4884,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -6579,7 +5136,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -6658,6 +5215,161 @@ static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) - return __Pyx_GetBuiltinName(name); - } - -+/* GetTopmostException */ -+#if CYTHON_USE_EXC_INFO_STACK -+static _PyErr_StackItem * -+__Pyx_PyErr_GetTopmostException(PyThreadState *tstate) -+{ -+ _PyErr_StackItem *exc_info = tstate->exc_info; -+ while ((exc_info->exc_type == NULL || exc_info->exc_type == Py_None) && -+ exc_info->previous_item != NULL) -+ { -+ exc_info = exc_info->previous_item; -+ } -+ return exc_info; -+} -+#endif -+ -+/* SaveResetException */ -+#if CYTHON_FAST_THREAD_STATE -+static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { -+ #if CYTHON_USE_EXC_INFO_STACK -+ _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); -+ *type = exc_info->exc_type; -+ *value = exc_info->exc_value; -+ *tb = exc_info->exc_traceback; -+ #else -+ *type = tstate->exc_type; -+ *value = tstate->exc_value; -+ *tb = tstate->exc_traceback; -+ #endif -+ Py_XINCREF(*type); -+ Py_XINCREF(*value); -+ Py_XINCREF(*tb); -+} -+static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { -+ PyObject *tmp_type, *tmp_value, *tmp_tb; -+ #if CYTHON_USE_EXC_INFO_STACK -+ _PyErr_StackItem *exc_info = tstate->exc_info; -+ tmp_type = exc_info->exc_type; -+ tmp_value = exc_info->exc_value; -+ tmp_tb = exc_info->exc_traceback; -+ exc_info->exc_type = type; -+ exc_info->exc_value = value; -+ exc_info->exc_traceback = tb; -+ #else -+ tmp_type = tstate->exc_type; -+ tmp_value = tstate->exc_value; -+ tmp_tb = tstate->exc_traceback; -+ tstate->exc_type = type; -+ tstate->exc_value = value; -+ tstate->exc_traceback = tb; -+ #endif -+ Py_XDECREF(tmp_type); -+ Py_XDECREF(tmp_value); -+ Py_XDECREF(tmp_tb); -+} -+#endif -+ -+/* PyErrExceptionMatches */ -+#if CYTHON_FAST_THREAD_STATE -+static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { -+ Py_ssize_t i, n; -+ n = PyTuple_GET_SIZE(tuple); -+#if PY_MAJOR_VERSION >= 3 -+ for (i=0; i<n; i++) { -+ if (exc_type == PyTuple_GET_ITEM(tuple, i)) return 1; -+ } -+#endif -+ for (i=0; i<n; i++) { -+ if (__Pyx_PyErr_GivenExceptionMatches(exc_type, PyTuple_GET_ITEM(tuple, i))) return 1; -+ } -+ return 0; -+} -+static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err) { -+ PyObject *exc_type = tstate->curexc_type; -+ if (exc_type == err) return 1; -+ if (unlikely(!exc_type)) return 0; -+ if (unlikely(PyTuple_Check(err))) -+ return __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); -+ return __Pyx_PyErr_GivenExceptionMatches(exc_type, err); -+} -+#endif -+ -+/* GetException */ -+#if CYTHON_FAST_THREAD_STATE -+static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) -+#else -+static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) -+#endif -+{ -+ PyObject *local_type, *local_value, *local_tb; -+#if CYTHON_FAST_THREAD_STATE -+ PyObject *tmp_type, *tmp_value, *tmp_tb; -+ local_type = tstate->curexc_type; -+ local_value = tstate->curexc_value; -+ local_tb = tstate->curexc_traceback; -+ tstate->curexc_type = 0; -+ tstate->curexc_value = 0; -+ tstate->curexc_traceback = 0; -+#else -+ PyErr_Fetch(&local_type, &local_value, &local_tb); -+#endif -+ PyErr_NormalizeException(&local_type, &local_value, &local_tb); -+#if CYTHON_FAST_THREAD_STATE -+ if (unlikely(tstate->curexc_type)) -+#else -+ if (unlikely(PyErr_Occurred())) -+#endif -+ goto bad; -+ #if PY_MAJOR_VERSION >= 3 -+ if (local_tb) { -+ if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) -+ goto bad; -+ } -+ #endif -+ Py_XINCREF(local_tb); -+ Py_XINCREF(local_type); -+ Py_XINCREF(local_value); -+ *type = local_type; -+ *value = local_value; -+ *tb = local_tb; -+#if CYTHON_FAST_THREAD_STATE -+ #if CYTHON_USE_EXC_INFO_STACK -+ { -+ _PyErr_StackItem *exc_info = tstate->exc_info; -+ tmp_type = exc_info->exc_type; -+ tmp_value = exc_info->exc_value; -+ tmp_tb = exc_info->exc_traceback; -+ exc_info->exc_type = local_type; -+ exc_info->exc_value = local_value; -+ exc_info->exc_traceback = local_tb; -+ } -+ #else -+ tmp_type = tstate->exc_type; -+ tmp_value = tstate->exc_value; -+ tmp_tb = tstate->exc_traceback; -+ tstate->exc_type = local_type; -+ tstate->exc_value = local_value; -+ tstate->exc_traceback = local_tb; -+ #endif -+ Py_XDECREF(tmp_type); -+ Py_XDECREF(tmp_value); -+ Py_XDECREF(tmp_tb); -+#else -+ PyErr_SetExcInfo(local_type, local_value, local_tb); -+#endif -+ return 0; -+bad: -+ *type = 0; -+ *value = 0; -+ *tb = 0; -+ Py_XDECREF(local_type); -+ Py_XDECREF(local_value); -+ Py_XDECREF(local_tb); -+ return -1; -+} -+ - /* PyErrFetchRestore */ - #if CYTHON_FAST_THREAD_STATE - static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { -@@ -6841,216 +5553,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - } - #endif - --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -- } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; --} -- --/* GetTopmostException */ --#if CYTHON_USE_EXC_INFO_STACK --static _PyErr_StackItem * --__Pyx_PyErr_GetTopmostException(PyThreadState *tstate) --{ -- _PyErr_StackItem *exc_info = tstate->exc_info; -- while ((exc_info->exc_type == NULL || exc_info->exc_type == Py_None) && -- exc_info->previous_item != NULL) -- { -- exc_info = exc_info->previous_item; -- } -- return exc_info; --} --#endif -- --/* SaveResetException */ --#if CYTHON_FAST_THREAD_STATE --static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { -- #if CYTHON_USE_EXC_INFO_STACK -- _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); -- *type = exc_info->exc_type; -- *value = exc_info->exc_value; -- *tb = exc_info->exc_traceback; -- #else -- *type = tstate->exc_type; -- *value = tstate->exc_value; -- *tb = tstate->exc_traceback; -- #endif -- Py_XINCREF(*type); -- Py_XINCREF(*value); -- Py_XINCREF(*tb); --} --static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { -- PyObject *tmp_type, *tmp_value, *tmp_tb; -- #if CYTHON_USE_EXC_INFO_STACK -- _PyErr_StackItem *exc_info = tstate->exc_info; -- tmp_type = exc_info->exc_type; -- tmp_value = exc_info->exc_value; -- tmp_tb = exc_info->exc_traceback; -- exc_info->exc_type = type; -- exc_info->exc_value = value; -- exc_info->exc_traceback = tb; -- #else -- tmp_type = tstate->exc_type; -- tmp_value = tstate->exc_value; -- tmp_tb = tstate->exc_traceback; -- tstate->exc_type = type; -- tstate->exc_value = value; -- tstate->exc_traceback = tb; -- #endif -- Py_XDECREF(tmp_type); -- Py_XDECREF(tmp_value); -- Py_XDECREF(tmp_tb); --} --#endif -- --/* PyErrExceptionMatches */ --#if CYTHON_FAST_THREAD_STATE --static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { -- Py_ssize_t i, n; -- n = PyTuple_GET_SIZE(tuple); --#if PY_MAJOR_VERSION >= 3 -- for (i=0; i<n; i++) { -- if (exc_type == PyTuple_GET_ITEM(tuple, i)) return 1; -- } --#endif -- for (i=0; i<n; i++) { -- if (__Pyx_PyErr_GivenExceptionMatches(exc_type, PyTuple_GET_ITEM(tuple, i))) return 1; -- } -- return 0; --} --static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err) { -- PyObject *exc_type = tstate->curexc_type; -- if (exc_type == err) return 1; -- if (unlikely(!exc_type)) return 0; -- if (unlikely(PyTuple_Check(err))) -- return __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); -- return __Pyx_PyErr_GivenExceptionMatches(exc_type, err); --} --#endif -- --/* GetException */ --#if CYTHON_FAST_THREAD_STATE --static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) --#else --static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) --#endif --{ -- PyObject *local_type, *local_value, *local_tb; --#if CYTHON_FAST_THREAD_STATE -- PyObject *tmp_type, *tmp_value, *tmp_tb; -- local_type = tstate->curexc_type; -- local_value = tstate->curexc_value; -- local_tb = tstate->curexc_traceback; -- tstate->curexc_type = 0; -- tstate->curexc_value = 0; -- tstate->curexc_traceback = 0; --#else -- PyErr_Fetch(&local_type, &local_value, &local_tb); --#endif -- PyErr_NormalizeException(&local_type, &local_value, &local_tb); --#if CYTHON_FAST_THREAD_STATE -- if (unlikely(tstate->curexc_type)) --#else -- if (unlikely(PyErr_Occurred())) --#endif -- goto bad; -- #if PY_MAJOR_VERSION >= 3 -- if (local_tb) { -- if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) -- goto bad; -- } -- #endif -- Py_XINCREF(local_tb); -- Py_XINCREF(local_type); -- Py_XINCREF(local_value); -- *type = local_type; -- *value = local_value; -- *tb = local_tb; --#if CYTHON_FAST_THREAD_STATE -- #if CYTHON_USE_EXC_INFO_STACK -- { -- _PyErr_StackItem *exc_info = tstate->exc_info; -- tmp_type = exc_info->exc_type; -- tmp_value = exc_info->exc_value; -- tmp_tb = exc_info->exc_traceback; -- exc_info->exc_type = local_type; -- exc_info->exc_value = local_value; -- exc_info->exc_traceback = local_tb; -- } -- #else -- tmp_type = tstate->exc_type; -- tmp_value = tstate->exc_value; -- tmp_tb = tstate->exc_traceback; -- tstate->exc_type = local_type; -- tstate->exc_value = local_value; -- tstate->exc_traceback = local_tb; -- #endif -- Py_XDECREF(tmp_type); -- Py_XDECREF(tmp_value); -- Py_XDECREF(tmp_tb); --#else -- PyErr_SetExcInfo(local_type, local_value, local_tb); --#endif -- return 0; --bad: -- *type = 0; -- *value = 0; -- *tb = 0; -- Py_XDECREF(local_type); -- Py_XDECREF(local_value); -- Py_XDECREF(local_tb); -- return -1; --} -- - /* TypeImport */ - #ifndef __PYX_HAVE_RT_ImportType - #define __PYX_HAVE_RT_ImportType -@@ -7243,7 +5745,7 @@ static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -7340,30 +5842,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -7382,11 +5885,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -7727,24 +6235,31 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - #endif - - /* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -+ if (sizeof(long) < sizeof(long)) { - return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -+ } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - #endif - } - } else { -- if (sizeof(int) <= sizeof(long)) { -+ if (sizeof(long) <= sizeof(long)) { - return PyInt_FromLong((long) value); - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - #endif - } -@@ -7752,7 +6267,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -+ return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); - } - } -@@ -7779,51 +6294,27 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - return (target_type) value;\ - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+/* CIntFromPy */ -+static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ --static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(int) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) -+ if (sizeof(long) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (int) val; -+ return (long) val; - } - } else - #endif -@@ -7832,32 +6323,32 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) -+ case 0: return (long) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -- return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -+ return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -- return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -+ return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -- return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -+ return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; -@@ -7871,86 +6362,86 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (int) -1; -+ return (long) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(int) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(long) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (int) 0; -- case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) -+ case 0: return (long) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) - case -2: -- if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(int) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -- return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(int) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -- return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(int) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(long) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -- return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -+ return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(int) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -+ if (sizeof(long) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -7959,7 +6450,7 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- int val; -+ long val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -7979,71 +6470,47 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - return val; - } - #endif -- return (int) -1; -+ return (long) -1; - } - } else { -- int val; -+ long val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (int) -1; -- val = __Pyx_PyInt_As_int(tmp); -+ if (!tmp) return (long) -1; -+ val = __Pyx_PyInt_As_long(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to int"); -- return (int) -1; -+ "value too large to convert to long"); -+ return (long) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to int"); -- return (int) -1; -+ "can't convert negative value to long"); -+ return (long) -1; - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(long) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(long) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+/* CIntFromPy */ -+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" - #endif -- } -- } else { -- if (sizeof(long) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop - #endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(long), -- little, !is_unsigned); -- } --} -- --/* CIntFromPy */ --static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -- if (sizeof(long) < sizeof(long)) { -- __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) -+ if (sizeof(int) < sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } -- return (long) val; -+ return (int) val; - } - } else - #endif -@@ -8052,32 +6519,32 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) -+ case 0: return (int) 0; -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { -- return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { -+ return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { -- return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { -+ return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { -- return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { -+ return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; -@@ -8091,86 +6558,86 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) -- return (long) -1; -+ return (int) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } - #endif -- if (sizeof(long) <= sizeof(unsigned long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) -+ if (sizeof(int) <= sizeof(unsigned long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - #endif - } - } else { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { -- case 0: return (long) 0; -- case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) -- case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) -+ case 0: return (int) 0; -+ case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) -+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) - case -2: -- if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 2: -- if (8 * sizeof(long) > 1 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -- return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { -+ return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -3: -- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 3: -- if (8 * sizeof(long) > 2 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -- return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { -+ return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -4: -- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 4: -- if (8 * sizeof(long) > 3 * PyLong_SHIFT) { -+ if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { -- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { -- return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); -+ __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) -+ } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { -+ return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - } - #endif -- if (sizeof(long) <= sizeof(long)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) -+ if (sizeof(int) <= sizeof(long)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) - #ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) - #endif - } - } -@@ -8179,7 +6646,7 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); - #else -- long val; -+ int val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { -@@ -8199,24 +6666,24 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - return val; - } - #endif -- return (long) -1; -+ return (int) -1; - } - } else { -- long val; -+ int val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); -- if (!tmp) return (long) -1; -- val = __Pyx_PyInt_As_long(tmp); -+ if (!tmp) return (int) -1; -+ val = __Pyx_PyInt_As_int(tmp); - Py_DECREF(tmp); - return val; - } - raise_overflow: - PyErr_SetString(PyExc_OverflowError, -- "value too large to convert to long"); -- return (long) -1; -+ "value too large to convert to int"); -+ return (int) -1; - raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, -- "can't convert negative value to long"); -- return (long) -1; -+ "can't convert negative value to int"); -+ return (int) -1; - } - - /* FastTypeChecks */ -@@ -8583,6 +7050,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } -diff --git a/cylp/cy/CyWolfePivot.cpp b/cylp/cy/CyWolfePivot.cpp -index 4a04bbf..7f08627 100644 ---- a/cylp/cy/CyWolfePivot.cpp -+++ b/cylp/cy/CyWolfePivot.cpp -@@ -1,14 +1,16 @@ --/* Generated by Cython 0.29.12 */ -+/* Generated by Cython 0.29.25 */ - -+#ifndef PY_SSIZE_T_CLEAN - #define PY_SSIZE_T_CLEAN -+#endif /* PY_SSIZE_T_CLEAN */ - #include "Python.h" - #ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. - #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. - #else --#define CYTHON_ABI "0_29_12" --#define CYTHON_HEX_VERSION 0x001D0CF0 -+#define CYTHON_ABI "0_29_25" -+#define CYTHON_HEX_VERSION 0x001D19F0 - #define CYTHON_FUTURE_DIVISION 0 - #include <stddef.h> - #ifndef offsetof -@@ -155,7 +157,7 @@ - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif -- #if PY_VERSION_HEX < 0x030300F0 -+ #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) -@@ -174,7 +176,7 @@ - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL -- #define CYTHON_FAST_PYCALL 1 -+ #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030B00A1) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) -@@ -193,7 +195,9 @@ - #define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) - #endif - #if CYTHON_USE_PYLONG_INTERNALS -- #include "longintrepr.h" -+ #if PY_MAJOR_VERSION < 3 -+ #include "longintrepr.h" -+ #endif - #undef SHIFT - #undef BASE - #undef MASK -@@ -324,9 +328,68 @@ class __Pyx_FakeReference { - #define __Pyx_DefaultClassType PyClass_Type - #else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" --#if PY_VERSION_HEX >= 0x030800A4 && PY_VERSION_HEX < 0x030800B2 -- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ -- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -+ #define __Pyx_DefaultClassType PyType_Type -+#if PY_VERSION_HEX >= 0x030B00A1 -+ static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, -+ PyObject *code, PyObject *c, PyObject* n, PyObject *v, -+ PyObject *fv, PyObject *cell, PyObject* fn, -+ PyObject *name, int fline, PyObject *lnos) { -+ PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; -+ PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; -+ const char *fn_cstr=NULL; -+ const char *name_cstr=NULL; -+ PyCodeObject* co=NULL; -+ PyObject *type, *value, *traceback; -+ PyErr_Fetch(&type, &value, &traceback); -+ if (!(kwds=PyDict_New())) goto end; -+ if (!(argcount=PyLong_FromLong(a))) goto end; -+ if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; -+ if (!(posonlyargcount=PyLong_FromLong(0))) goto end; -+ if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; -+ if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; -+ if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; -+ if (!(nlocals=PyLong_FromLong(l))) goto end; -+ if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; -+ if (!(stacksize=PyLong_FromLong(s))) goto end; -+ if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; -+ if (!(flags=PyLong_FromLong(f))) goto end; -+ if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; -+ if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; -+ if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; -+ if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; -+ if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; -+ if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; -+ if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here -+ if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; -+ Py_XDECREF((PyObject*)co); -+ co = (PyCodeObject*)call_result; -+ call_result = NULL; -+ if (0) { -+ cleanup_code_too: -+ Py_XDECREF((PyObject*)co); -+ co = NULL; -+ } -+ end: -+ Py_XDECREF(kwds); -+ Py_XDECREF(argcount); -+ Py_XDECREF(posonlyargcount); -+ Py_XDECREF(kwonlyargcount); -+ Py_XDECREF(nlocals); -+ Py_XDECREF(stacksize); -+ Py_XDECREF(replace); -+ Py_XDECREF(call_result); -+ Py_XDECREF(empty); -+ if (type) { -+ PyErr_Restore(type, value, traceback); -+ } -+ return co; -+ } - #else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -@@ -440,8 +503,12 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #endif - #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 -+ #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) -+ #else -+ #define __Pyx_PyUnicode_READY(op) (0) -+ #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) -@@ -449,7 +516,15 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) -+ #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) -+ #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) -+ #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) -+ #endif -+ #else -+ #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) -+ #endif - #else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 -@@ -498,8 +573,10 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -+#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str - #endif -+#endif - #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -@@ -510,6 +587,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) - #endif -+#if PY_VERSION_HEX >= 0x030900A4 -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -+#else -+ #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -+ #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -+#endif - #if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #else -@@ -543,13 +627,13 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - #if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong -- #define __Pyx_PyInt_AsHash_t PyInt_AsLong -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t - #else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t -- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -+ #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t - #endif - #if PY_MAJOR_VERSION >= 3 -- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) -+ #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) - #else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) - #endif -@@ -590,11 +674,10 @@ static CYTHON_INLINE float __PYX_NAN() { - #define __Pyx_truncl truncl - #endif - -- -+#define __PYX_MARK_ERR_POS(f_index, lineno) \ -+ { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } - #define __PYX_ERR(f_index, lineno, Ln_error) \ --{ \ -- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ --} -+ { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - - #ifndef __PYX_EXTERN_C - #ifdef __cplusplus -@@ -612,7 +695,13 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "pythread.h" - #include "ICoinIndexedVector.hpp" - #include "numpy/arrayobject.h" -+#include "numpy/ndarrayobject.h" -+#include "numpy/ndarraytypes.h" -+#include "numpy/arrayscalars.h" - #include "numpy/ufuncobject.h" -+ -+ /* NumPy API declarations from "numpy/__init__.pxd" */ -+ - #include "ClpDualRowPivot.hpp" - #include "ClpFactorization.hpp" - #include "IClpDualRowPivotBase.h" -@@ -641,11 +730,11 @@ static CYTHON_INLINE float __PYX_NAN() { - #include "OsiSolverInterface.hpp" - #include "CbcCompareUser.hpp" - #include "ICbcModel.hpp" -+#include <string> - #include "ios" - #include "new" - #include "stdexcept" - #include "typeinfo" --#include <string> - #include <vector> - #include "IClpPrimalColumnPivotBase.h" - #include "ClpPrimalColumnPivot.hpp" -@@ -746,6 +835,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); - static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); - #if CYTHON_ASSUME_SAFE_MACROS - #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - #else -@@ -881,23 +971,23 @@ static const char *__pyx_filename; - - static const char *__pyx_f[] = { - "stringsource", -- "cylp\\cy\\CyWolfePivot.pyx", -+ "cylp/cy/CyWolfePivot.pyx", - "__init__.pxd", - "type.pxd", - "bool.pxd", - "complex.pxd", -- "cylp\\cy\\CyCoinIndexedVector.pxd", -- "cylp\\cy\\CyClpDualRowPivotBase.pxd", -- "cylp\\cy\\CyCoinModel.pxd", -- "cylp\\cy\\CyCoinPackedMatrix.pxd", -- "cylp\\cy\\CyCgl.pxd", -- "cylp\\cy\\CyCbcNode.pxd", -- "cylp\\cy\\CyOsiSolverInterface.pxd", -- "cylp\\cy\\CyCbcModel.pxd", -- "cylp\\cy\\CyClpSimplex.pxd", -+ "cylp/cy/CyCoinIndexedVector.pxd", -+ "cylp/cy/CyClpDualRowPivotBase.pxd", -+ "cylp/cy/CyCoinModel.pxd", -+ "cylp/cy/CyCoinPackedMatrix.pxd", -+ "cylp/cy/CyCgl.pxd", -+ "cylp/cy/CyCbcNode.pxd", -+ "cylp/cy/CyOsiSolverInterface.pxd", -+ "cylp/cy/CyCbcModel.pxd", -+ "cylp/cy/CyClpSimplex.pxd", - }; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":776 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":690 - * # in Cython to enable them only on the right systems. - * - * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< -@@ -906,7 +996,7 @@ static const char *__pyx_f[] = { - */ - typedef npy_int8 __pyx_t_5numpy_int8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":777 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":691 - * - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< -@@ -915,7 +1005,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t; - */ - typedef npy_int16 __pyx_t_5numpy_int16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":778 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":692 - * ctypedef npy_int8 int8_t - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< -@@ -924,7 +1014,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t; - */ - typedef npy_int32 __pyx_t_5numpy_int32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":779 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":693 - * ctypedef npy_int16 int16_t - * ctypedef npy_int32 int32_t - * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< -@@ -933,7 +1023,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t; - */ - typedef npy_int64 __pyx_t_5numpy_int64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":783 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":697 - * #ctypedef npy_int128 int128_t - * - * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< -@@ -942,7 +1032,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t; - */ - typedef npy_uint8 __pyx_t_5numpy_uint8_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":784 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":698 - * - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< -@@ -951,7 +1041,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t; - */ - typedef npy_uint16 __pyx_t_5numpy_uint16_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":785 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":699 - * ctypedef npy_uint8 uint8_t - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< -@@ -960,7 +1050,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t; - */ - typedef npy_uint32 __pyx_t_5numpy_uint32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":786 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":700 - * ctypedef npy_uint16 uint16_t - * ctypedef npy_uint32 uint32_t - * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< -@@ -969,7 +1059,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t; - */ - typedef npy_uint64 __pyx_t_5numpy_uint64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":790 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":704 - * #ctypedef npy_uint128 uint128_t - * - * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< -@@ -978,7 +1068,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t; - */ - typedef npy_float32 __pyx_t_5numpy_float32_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":791 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":705 - * - * ctypedef npy_float32 float32_t - * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< -@@ -987,7 +1077,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t; - */ - typedef npy_float64 __pyx_t_5numpy_float64_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":800 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":714 - * # The int types are mapped a bit surprising -- - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t # <<<<<<<<<<<<<< -@@ -996,7 +1086,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t; - */ - typedef npy_long __pyx_t_5numpy_int_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":801 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":715 - * # numpy.int corresponds to 'l' and numpy.long to 'q' - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< -@@ -1005,7 +1095,7 @@ typedef npy_long __pyx_t_5numpy_int_t; - */ - typedef npy_longlong __pyx_t_5numpy_long_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":802 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":716 - * ctypedef npy_long int_t - * ctypedef npy_longlong long_t - * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< -@@ -1014,7 +1104,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t; - */ - typedef npy_longlong __pyx_t_5numpy_longlong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":804 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":718 - * ctypedef npy_longlong longlong_t - * - * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< -@@ -1023,7 +1113,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t; - */ - typedef npy_ulong __pyx_t_5numpy_uint_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":805 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":719 - * - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< -@@ -1032,7 +1122,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":806 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":720 - * ctypedef npy_ulong uint_t - * ctypedef npy_ulonglong ulong_t - * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< -@@ -1041,7 +1131,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t; - */ - typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":808 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":722 - * ctypedef npy_ulonglong ulonglong_t - * - * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< -@@ -1050,7 +1140,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; - */ - typedef npy_intp __pyx_t_5numpy_intp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":809 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":723 - * - * ctypedef npy_intp intp_t - * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< -@@ -1059,7 +1149,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t; - */ - typedef npy_uintp __pyx_t_5numpy_uintp_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":811 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":725 - * ctypedef npy_uintp uintp_t - * - * ctypedef npy_double float_t # <<<<<<<<<<<<<< -@@ -1068,7 +1158,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t; - */ - typedef npy_double __pyx_t_5numpy_float_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":812 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":726 - * - * ctypedef npy_double float_t - * ctypedef npy_double double_t # <<<<<<<<<<<<<< -@@ -1077,7 +1167,7 @@ typedef npy_double __pyx_t_5numpy_float_t; - */ - typedef npy_double __pyx_t_5numpy_double_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":813 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":727 - * ctypedef npy_double float_t - * ctypedef npy_double double_t - * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< -@@ -1140,7 +1230,7 @@ struct __pyx_obj_4cylp_2cy_12CyClpSimplex_VarStatus; - struct __pyx_obj_4cylp_2cy_26CyClpPrimalColumnPivotBase_CyClpPrimalColumnPivotBase; - struct __pyx_obj_4cylp_2cy_12CyWolfePivot_CyWolfePivot; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":815 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":729 - * ctypedef npy_longdouble longdouble_t - * - * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< -@@ -1149,7 +1239,7 @@ struct __pyx_obj_4cylp_2cy_12CyWolfePivot_CyWolfePivot; - */ - typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":816 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":730 - * - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< -@@ -1158,7 +1248,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t; - */ - typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":817 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":731 - * ctypedef npy_cfloat cfloat_t - * ctypedef npy_cdouble cdouble_t - * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< -@@ -1167,7 +1257,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t; - */ - typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":819 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":733 - * ctypedef npy_clongdouble clongdouble_t - * - * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< -@@ -1860,6 +1950,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #ifndef Py_MEMBER_SIZE - #define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) - #endif -+#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ -@@ -1867,6 +1958,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -+#endif // CYTHON_FAST_PYCALL - #endif - - /* PyObjectCall.proto */ -@@ -1983,29 +2075,6 @@ static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject - /* RaiseException.proto */ - static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - --/* DictGetItem.proto */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); --#define __Pyx_PyObject_Dict_GetItem(obj, name)\ -- (likely(PyDict_CheckExact(obj)) ?\ -- __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) --#else --#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) --#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) --#endif -- --/* RaiseTooManyValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); -- --/* RaiseNeedMoreValuesToUnpack.proto */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); -- --/* RaiseNoneIterError.proto */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); -- --/* ExtTypeTest.proto */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); -- - /* GetTopmostException.proto */ - #if CYTHON_USE_EXC_INFO_STACK - static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -@@ -2078,6 +2147,9 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam - /* SetVTable.proto */ - static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -+/* PyObjectGetAttrStrNoError.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); -+ - /* SetupReduce.proto */ - static int __Pyx_setup_reduce(PyObject* type_obj); - -@@ -2133,14 +2205,10 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); - static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__IClpSimplex_3a__3a_Status(enum IClpSimplex::Status value); -- --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+/* GCCDiagnostics.proto */ -+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -+#define __Pyx_HAS_GCC_DIAGNOSTIC -+#endif - - /* RealImag.proto */ - #if CYTHON_CCOMPLEX -@@ -2240,12 +2308,18 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - #endif - #endif - --/* CIntToPy.proto */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); -- - /* CIntFromPy.proto */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); - -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); -+ -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__IClpSimplex_3a__3a_Status(enum IClpSimplex::Status value); -+ -+/* CIntToPy.proto */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); -+ - /* CIntFromPy.proto */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -@@ -2370,8 +2444,17 @@ static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; - static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; - static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; - static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; -+static PyTypeObject *__pyx_ptype_5numpy_generic = 0; -+static PyTypeObject *__pyx_ptype_5numpy_number = 0; -+static PyTypeObject *__pyx_ptype_5numpy_integer = 0; -+static PyTypeObject *__pyx_ptype_5numpy_signedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_unsignedinteger = 0; -+static PyTypeObject *__pyx_ptype_5numpy_inexact = 0; -+static PyTypeObject *__pyx_ptype_5numpy_floating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_complexfloating = 0; -+static PyTypeObject *__pyx_ptype_5numpy_flexible = 0; -+static PyTypeObject *__pyx_ptype_5numpy_character = 0; - static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ - - /* Module declarations from 'cylp.cy.CyClpDualRowPivotBase' */ - static PyTypeObject *__pyx_ptype_4cylp_2cy_21CyClpDualRowPivotBase_CyClpDualRowPivotBase = 0; -@@ -2432,9 +2515,6 @@ int __pyx_module_is_main_cylp__cy__CyWolfePivot = 0; - - /* Implementation of 'cylp.cy.CyWolfePivot' */ - static PyObject *__pyx_builtin_TypeError; --static PyObject *__pyx_builtin_ValueError; --static PyObject *__pyx_builtin_range; --static PyObject *__pyx_builtin_RuntimeError; - static PyObject *__pyx_builtin_ImportError; - static const char __pyx_k_main[] = "__main__"; - static const char __pyx_k_name[] = "__name__"; -@@ -2442,7 +2522,6 @@ static const char __pyx_k_test[] = "__test__"; - static const char __pyx_k_clear[] = "clear"; - static const char __pyx_k_nCols[] = "nCols"; - static const char __pyx_k_nRows[] = "nRows"; --static const char __pyx_k_range[] = "range"; - static const char __pyx_k_reduce[] = "__reduce__"; - static const char __pyx_k_indices[] = "indices"; - static const char __pyx_k_elements[] = "elements"; -@@ -2451,12 +2530,10 @@ static const char __pyx_k_setstate[] = "__setstate__"; - static const char __pyx_k_TypeError[] = "TypeError"; - static const char __pyx_k_nElements[] = "nElements"; - static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; --static const char __pyx_k_ValueError[] = "ValueError"; - static const char __pyx_k_nVariables[] = "nVariables"; - static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; - static const char __pyx_k_ImportError[] = "ImportError"; - static const char __pyx_k_CyWolfePivot[] = "CyWolfePivot"; --static const char __pyx_k_RuntimeError[] = "RuntimeError"; - static const char __pyx_k_reducedCosts[] = "reducedCosts"; - static const char __pyx_k_dualTolerance[] = "dualTolerance"; - static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; -@@ -2464,23 +2541,12 @@ static const char __pyx_k_transposeTimes[] = "transposeTimes"; - static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; - static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; - static const char __pyx_k_updateColumnTranspose[] = "updateColumnTranspose"; --static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; - static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; --static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; --static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; --static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; --static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; - static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; - static const char __pyx_k_self_CppSelf_cannot_be_converted[] = "self.CppSelf cannot be converted to a Python object for pickling"; --static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; - static PyObject *__pyx_n_s_CyWolfePivot; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; --static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; - static PyObject *__pyx_n_s_ImportError; --static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; --static PyObject *__pyx_n_s_RuntimeError; - static PyObject *__pyx_n_s_TypeError; --static PyObject *__pyx_n_s_ValueError; - static PyObject *__pyx_n_s_clear; - static PyObject *__pyx_n_s_cline_in_traceback; - static PyObject *__pyx_n_s_dualTolerance; -@@ -2493,12 +2559,9 @@ static PyObject *__pyx_n_s_nElements; - static PyObject *__pyx_n_s_nRows; - static PyObject *__pyx_n_s_nVariables; - static PyObject *__pyx_n_s_name; --static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; --static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; - static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; - static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; - static PyObject *__pyx_n_s_pyx_vtable; --static PyObject *__pyx_n_s_range; - static PyObject *__pyx_n_s_reduce; - static PyObject *__pyx_n_s_reduce_cython; - static PyObject *__pyx_n_s_reduce_ex; -@@ -2508,12 +2571,9 @@ static PyObject *__pyx_n_s_setstate; - static PyObject *__pyx_n_s_setstate_cython; - static PyObject *__pyx_n_s_test; - static PyObject *__pyx_n_s_transposeTimes; --static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; - static PyObject *__pyx_n_s_updateColumnTranspose; - static PyObject *__pyx_pf_4cylp_2cy_12CyWolfePivot_12CyWolfePivot___reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_12CyWolfePivot_CyWolfePivot *__pyx_v_self); /* proto */ - static PyObject *__pyx_pf_4cylp_2cy_12CyWolfePivot_12CyWolfePivot_2__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4cylp_2cy_12CyWolfePivot_CyWolfePivot *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ - static PyObject *__pyx_tp_new_4cylp_2cy_12CyWolfePivot_CyWolfePivot(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ - static PyObject *__pyx_int_1; - static PyObject *__pyx_int_2; -@@ -2524,11 +2584,6 @@ static PyObject *__pyx_tuple_; - static PyObject *__pyx_tuple__2; - static PyObject *__pyx_tuple__3; - static PyObject *__pyx_tuple__4; --static PyObject *__pyx_tuple__5; --static PyObject *__pyx_tuple__6; --static PyObject *__pyx_tuple__7; --static PyObject *__pyx_tuple__8; --static PyObject *__pyx_tuple__9; - /* Late includes */ - - /* "cylp/cy/CyWolfePivot.pyx":8 -@@ -2566,6 +2621,9 @@ static PyObject *__pyx_f_4cylp_2cy_12CyWolfePivot_12CyWolfePivot_pivotColumn(str - double __pyx_t_9; - Py_ssize_t __pyx_t_10; - int __pyx_t_11; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("pivotColumn", 0); - - /* "cylp/cy/CyWolfePivot.pyx":11 -@@ -3500,6 +3558,9 @@ static PyObject *__pyx_pf_4cylp_2cy_12CyWolfePivot_12CyWolfePivot___reduce_cytho - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":2 -@@ -3555,6 +3616,9 @@ static PyObject *__pyx_pf_4cylp_2cy_12CyWolfePivot_12CyWolfePivot_2__setstate_cy - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":4 -@@ -3585,1918 +3649,331 @@ static PyObject *__pyx_pf_4cylp_2cy_12CyWolfePivot_12CyWolfePivot_2__setstate_cy - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t -+ * -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * - */ - --/* Python wrapper */ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ --static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_r; -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); -- __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { -- int __pyx_v_i; -- int __pyx_v_ndim; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- int __pyx_v_t; -- char *__pyx_v_f; -- PyArray_Descr *__pyx_v_descr = 0; -- int __pyx_v_offset; -- int __pyx_r; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -+ PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- int __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- int __pyx_t_4; -- int __pyx_t_5; -- int __pyx_t_6; -- PyArray_Descr *__pyx_t_7; -- PyObject *__pyx_t_8 = NULL; -- char *__pyx_t_9; -- if (__pyx_v_info == NULL) { -- PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); -- return -1; -- } -- __Pyx_RefNannySetupContext("__getbuffer__", 0); -- __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); -- __Pyx_GIVEREF(__pyx_v_info->obj); -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":265 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":736 - * -- * cdef int i, ndim -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":266 -- * cdef int i, ndim -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): -+ * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< - * -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): - */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 736, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":268 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":735 -+ * ctypedef npy_cdouble complex_t - * -- * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) - */ -- __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L4_bool_binop_done; -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":271 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L4_bool_binop_done:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -- * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":739 - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 272, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":270 -- * ndim = PyArray_NDIM(self) -+ * cdef inline object PyArray_MultiIterNew2(a, b): -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 739, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":738 -+ * return PyArray_MultiIterNew(1, <void*>a) -+ * -+ * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") - */ -- __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L7_bool_binop_done; -- } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":275 -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * - */ -- __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L7_bool_binop_done:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -- */ -- if (unlikely(__pyx_t_1)) { -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":742 - * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 276, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":274 -- * raise ValueError(u"ndarray is not C contiguous") -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< - * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): - */ -- } -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 742, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":278 -- * raise ValueError(u"ndarray is not Fortran contiguous") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":741 -+ * return PyArray_MultiIterNew(2, <void*>a, <void*>b) - * -- * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":279 -+ * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * # Allocate new buffer for strides and shape info. - */ -- __pyx_v_info->ndim = __pyx_v_ndim; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":283 -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) # <<<<<<<<<<<<<< -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- */ -- __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":284 -- * # This is allocated as one block, strides first. -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim # <<<<<<<<<<<<<< -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- */ -- __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":285 -- * info.strides = <Py_ssize_t*>PyObject_Malloc(sizeof(Py_ssize_t) * 2 * <size_t>ndim) -- * info.shape = info.strides + ndim -- * for i in range(ndim): # <<<<<<<<<<<<<< -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] -- */ -- __pyx_t_4 = __pyx_v_ndim; -- __pyx_t_5 = __pyx_t_4; -- for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { -- __pyx_v_i = __pyx_t_6; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":286 -- * info.shape = info.strides + ndim -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- */ -- (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":287 -- * for i in range(ndim): -- * info.strides[i] = PyArray_STRIDES(self)[i] -- * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- */ -- (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":280 -- * info.buf = PyArray_DATA(self) -- * info.ndim = ndim -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * # Allocate new buffer for strides and shape info. -- * # This is allocated as one block, strides first. -- */ -- goto __pyx_L9; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":289 -- * info.shape[i] = PyArray_DIMS(self)[i] -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<< -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- */ -- /*else*/ { -- __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":290 -- * else: -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<< -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -+ * -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * - */ -- __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); -- } -- __pyx_L9:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":291 -- * info.strides = <Py_ssize_t*>PyArray_STRIDES(self) -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL # <<<<<<<<<<<<<< -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) -- */ -- __pyx_v_info->suboffsets = NULL; -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":292 -- * info.shape = <Py_ssize_t*>PyArray_DIMS(self) -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< -- * info.readonly = not PyArray_ISWRITEABLE(self) -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":745 - * -- */ -- __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":293 -- * info.suboffsets = NULL -- * info.itemsize = PyArray_ITEMSIZE(self) -- * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< - * -- * cdef int t -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): - */ -- __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 745, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":296 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":744 -+ * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) - * -- * cdef int t -- * cdef char* f = NULL # <<<<<<<<<<<<<< -- * cdef dtype descr = <dtype>PyArray_DESCR(self) -- * cdef int offset -- */ -- __pyx_v_f = NULL; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":297 -- * cdef int t -- * cdef char* f = NULL -- * cdef dtype descr = <dtype>PyArray_DESCR(self) # <<<<<<<<<<<<<< -- * cdef int offset -+ * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * - */ -- __pyx_t_7 = PyArray_DESCR(__pyx_v_self); -- __pyx_t_3 = ((PyObject *)__pyx_t_7); -- __Pyx_INCREF(__pyx_t_3); -- __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); -- __pyx_t_3 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":300 -- * cdef int offset -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) - * -- * info.obj = self # <<<<<<<<<<<<<< -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * if not PyDataType_HASFIELDS(descr): - */ -- __Pyx_INCREF(((PyObject *)__pyx_v_self)); -- __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); -- __pyx_v_info->obj = ((PyObject *)__pyx_v_self); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; -+ __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":748 -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< - * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -+ * cdef inline tuple PyDataType_SHAPE(dtype d): - */ -- __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); -- if (__pyx_t_1) { -+ __Pyx_XDECREF(__pyx_r); -+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 748, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); -+ __pyx_r = __pyx_t_1; -+ __pyx_t_1 = 0; -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":303 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":747 -+ * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -+ * -+ * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num # <<<<<<<<<<<<<< -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): - */ -- __pyx_t_4 = __pyx_v_descr->type_num; -- __pyx_v_t = __pyx_t_4; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); -- if (!__pyx_t_2) { -- goto __pyx_L15_next_or; -- } else { -- } -- __pyx_t_2 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_L15_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":305 -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- */ -- __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); -- if (__pyx_t_2) { -- } else { -- __pyx_t_1 = __pyx_t_2; -- goto __pyx_L14_bool_binop_done; -- } -- __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_1 = __pyx_t_2; -- __pyx_L14_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_1)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 306, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":304 -- * if not PyDataType_HASFIELDS(descr): -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":307 -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- */ -- switch (__pyx_v_t) { -- case NPY_BYTE: -- __pyx_v_f = ((char *)"b"); -- break; -- case NPY_UBYTE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":308 -- * raise ValueError(u"Non-native byte order not supported") -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- */ -- __pyx_v_f = ((char *)"B"); -- break; -- case NPY_SHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":309 -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- */ -- __pyx_v_f = ((char *)"h"); -- break; -- case NPY_USHORT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":310 -- * elif t == NPY_UBYTE: f = "B" -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- */ -- __pyx_v_f = ((char *)"H"); -- break; -- case NPY_INT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":311 -- * elif t == NPY_SHORT: f = "h" -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- */ -- __pyx_v_f = ((char *)"i"); -- break; -- case NPY_UINT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":312 -- * elif t == NPY_USHORT: f = "H" -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- */ -- __pyx_v_f = ((char *)"I"); -- break; -- case NPY_LONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":313 -- * elif t == NPY_INT: f = "i" -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- */ -- __pyx_v_f = ((char *)"l"); -- break; -- case NPY_ULONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":314 -- * elif t == NPY_UINT: f = "I" -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- */ -- __pyx_v_f = ((char *)"L"); -- break; -- case NPY_LONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":315 -- * elif t == NPY_LONG: f = "l" -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- */ -- __pyx_v_f = ((char *)"q"); -- break; -- case NPY_ULONGLONG: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":316 -- * elif t == NPY_ULONG: f = "L" -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- */ -- __pyx_v_f = ((char *)"Q"); -- break; -- case NPY_FLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":317 -- * elif t == NPY_LONGLONG: f = "q" -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- */ -- __pyx_v_f = ((char *)"f"); -- break; -- case NPY_DOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":318 -- * elif t == NPY_ULONGLONG: f = "Q" -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- */ -- __pyx_v_f = ((char *)"d"); -- break; -- case NPY_LONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":319 -- * elif t == NPY_FLOAT: f = "f" -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- */ -- __pyx_v_f = ((char *)"g"); -- break; -- case NPY_CFLOAT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":320 -- * elif t == NPY_DOUBLE: f = "d" -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- */ -- __pyx_v_f = ((char *)"Zf"); -- break; -- case NPY_CDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":321 -- * elif t == NPY_LONGDOUBLE: f = "g" -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" -- */ -- __pyx_v_f = ((char *)"Zd"); -- break; -- case NPY_CLONGDOUBLE: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":322 -- * elif t == NPY_CFLOAT: f = "Zf" -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f = "O" -- * else: -- */ -- __pyx_v_f = ((char *)"Zg"); -- break; -- case NPY_OBJECT: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":323 -- * elif t == NPY_CDOUBLE: f = "Zd" -- * elif t == NPY_CLONGDOUBLE: f = "Zg" -- * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_v_f = ((char *)"O"); -- break; -- default: -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":325 -- * elif t == NPY_OBJECT: f = "O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * info.format = f -- * return -- */ -- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_8); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 325, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 325, __pyx_L1_error) -- break; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":326 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f # <<<<<<<<<<<<<< -- * return -- * else: -- */ -- __pyx_v_info->format = __pyx_v_f; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":327 -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * info.format = f -- * return # <<<<<<<<<<<<<< -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- */ -- __pyx_r = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":302 -- * info.obj = self -- * -- * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< -- * t = descr.type_num -- * if ((descr.byteorder == c'>' and little_endian) or -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":329 -- * return -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- */ -- /*else*/ { -- __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":330 -- * else: -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, -- */ -- (__pyx_v_info->format[0]) = '^'; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":331 -- * info.format = <char*>PyObject_Malloc(_buffer_format_string_len) -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 # <<<<<<<<<<<<<< -- * f = _util_dtypestring(descr, info.format + 1, -- * info.format + _buffer_format_string_len, -- */ -- __pyx_v_offset = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":332 -- * info.format[0] = c'^' # Native data types, manual alignment -- * offset = 0 -- * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< -- * info.format + _buffer_format_string_len, -- * &offset) -- */ -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 332, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":335 -- * info.format + _buffer_format_string_len, -- * &offset) -- * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- */ -- (__pyx_v_f[0]) = '\x00'; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":258 -- * # experimental exception made for __getbuffer__ and __releasebuffer__ -- * # -- the details of this may change. -- * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< -- * # This implementation of getbuffer is geared towards Cython -- * # requirements, and does not yet fulfill the PEP. -- */ -- -- /* function exit code */ -- __pyx_r = 0; -- goto __pyx_L0; -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_8); -- __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = -1; -- if (__pyx_v_info->obj != NULL) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- goto __pyx_L2; -- __pyx_L0:; -- if (__pyx_v_info->obj == Py_None) { -- __Pyx_GOTREF(__pyx_v_info->obj); -- __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; -- } -- __pyx_L2:; -- __Pyx_XDECREF((PyObject *)__pyx_v_descr); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- --/* Python wrapper */ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ --static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); -- __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("__releasebuffer__", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":339 -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) # <<<<<<<<<<<<<< -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) -- */ -- PyObject_Free(__pyx_v_info->format); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":338 -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): -- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":341 -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): -- * PyObject_Free(info.strides) # <<<<<<<<<<<<<< -- * # info.shape was stored after info.strides in the same block -- * -- */ -- PyObject_Free(__pyx_v_info->strides); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":340 -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< -- * PyObject_Free(info.strides) -- * # info.shape was stored after info.strides in the same block -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":337 -- * f[0] = c'\0' # Terminate format string -- * -- * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< -- * if PyArray_HASFIELDS(self): -- * PyObject_Free(info.format) -- */ -- -- /* function exit code */ -- __Pyx_RefNannyFinishContext(); --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":822 -- * -- * cdef inline object PyArray_MultiIterNew1(a): -- * return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 822, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":821 -- * ctypedef npy_cdouble complex_t -- * -- * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":825 -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 825, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":824 -- * return PyArray_MultiIterNew(1, <void*>a) -- * -- * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":828 -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 828, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":827 -- * return PyArray_MultiIterNew(2, <void*>a, <void*>b) -- * -- * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":831 -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<< -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 831, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":830 -- * return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) -- * -- * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":834 -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<< -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- */ -- __Pyx_XDECREF(__pyx_r); -- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 834, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_1); -- __pyx_r = __pyx_t_1; -- __pyx_t_1 = 0; -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":833 -- * return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) -- * -- * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- */ -- -- /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = 0; -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- --static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -- PyObject *__pyx_r = NULL; -- __Pyx_RefNannyDeclarations -- int __pyx_t_1; -- __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -- if (__pyx_t_1) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":838 -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -- * else: -- * return () -- */ -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -- __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -- goto __pyx_L0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":837 -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): -- * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -- * return <tuple>d.subarray.shape -- * else: -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":840 -- * return <tuple>d.subarray.shape -- * else: -- * return () # <<<<<<<<<<<<<< -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: -- */ -- /*else*/ { -- __Pyx_XDECREF(__pyx_r); -- __Pyx_INCREF(__pyx_empty_tuple); -- __pyx_r = __pyx_empty_tuple; -- goto __pyx_L0; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":836 -- * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -- * -- * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -- * if PyDataType_HASSUBARRAY(d): -- * return <tuple>d.subarray.shape -- */ -- -- /* function exit code */ -- __pyx_L0:; -- __Pyx_XGIVEREF(__pyx_r); -- __Pyx_RefNannyFinishContext(); -- return __pyx_r; --} -- --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -- * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -- */ -- --static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { -- PyArray_Descr *__pyx_v_child = 0; -- int __pyx_v_endian_detector; -- int __pyx_v_little_endian; -- PyObject *__pyx_v_fields = 0; -- PyObject *__pyx_v_childname = NULL; -- PyObject *__pyx_v_new_offset = NULL; -- PyObject *__pyx_v_t = NULL; -- char *__pyx_r; -- __Pyx_RefNannyDeclarations -- PyObject *__pyx_t_1 = NULL; -- Py_ssize_t __pyx_t_2; -- PyObject *__pyx_t_3 = NULL; -- PyObject *__pyx_t_4 = NULL; -- int __pyx_t_5; -- int __pyx_t_6; -- int __pyx_t_7; -- long __pyx_t_8; -- char *__pyx_t_9; -- __Pyx_RefNannySetupContext("_util_dtypestring", 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":847 -- * -- * cdef dtype child -- * cdef int endian_detector = 1 # <<<<<<<<<<<<<< -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) -- * cdef tuple fields -- */ -- __pyx_v_endian_detector = 1; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":848 -- * cdef dtype child -- * cdef int endian_detector = 1 -- * cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<< -- * cdef tuple fields -- * -- */ -- __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -- * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -- */ -- if (unlikely(__pyx_v_descr->names == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -- __PYX_ERR(2, 851, __pyx_L1_error) -- } -- __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; -- for (;;) { -- if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(2, 851, __pyx_L1_error) -- #else -- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 851, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- #endif -- __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":852 -- * -- * for childname in descr.names: -- * fields = descr.fields[childname] # <<<<<<<<<<<<<< -- * child, new_offset = fields -- * -- */ -- if (unlikely(__pyx_v_descr->fields == Py_None)) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); -- __PYX_ERR(2, 852, __pyx_L1_error) -- } -- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(2, 852, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); -- __pyx_t_3 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":853 -- * for childname in descr.names: -- * fields = descr.fields[childname] -- * child, new_offset = fields # <<<<<<<<<<<<<< -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- */ -- if (likely(__pyx_v_fields != Py_None)) { -- PyObject* sequence = __pyx_v_fields; -- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); -- if (unlikely(size != 2)) { -- if (size > 2) __Pyx_RaiseTooManyValuesError(2); -- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); -- __PYX_ERR(2, 853, __pyx_L1_error) -- } -- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS -- __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); -- __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); -- __Pyx_INCREF(__pyx_t_3); -- __Pyx_INCREF(__pyx_t_4); -- #else -- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- #endif -- } else { -- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(2, 853, __pyx_L1_error) -- } -- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(2, 853, __pyx_L1_error) -- __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); -- __pyx_t_3 = 0; -- __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(2, 855, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 856, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":855 -- * child, new_offset = fields -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); -- if (!__pyx_t_7) { -- goto __pyx_L8_next_or; -- } else { -- } -- __pyx_t_7 = (__pyx_v_little_endian != 0); -- if (!__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_L8_next_or:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":859 -- * -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< -- * raise ValueError(u"Non-native byte order not supported") -- * # One could encode it in the format string and have Cython -- */ -- __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); -- if (__pyx_t_7) { -- } else { -- __pyx_t_6 = __pyx_t_7; -- goto __pyx_L7_bool_binop_done; -- } -- __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); -- __pyx_t_6 = __pyx_t_7; -- __pyx_L7_bool_binop_done:; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":860 -- * if ((child.byteorder == c'>' and little_endian) or -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * # One could encode it in the format string and have Cython -- * # complain instead, BUT: < and > in format strings also imply -- */ -- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 860, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __Pyx_Raise(__pyx_t_3, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __PYX_ERR(2, 860, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":858 -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") -- * -- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< -- * (child.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":870 -- * -- * # Output padding bytes -- * while offset[0] < new_offset: # <<<<<<<<<<<<<< -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- */ -- while (1) { -- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 870, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (!__pyx_t_6) break; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":871 -- * # Output padding bytes -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< -- * f += 1 -- * offset[0] += 1 -- */ -- (__pyx_v_f[0]) = 0x78; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":872 -- * while offset[0] < new_offset: -- * f[0] = 120 # "x"; pad byte -- * f += 1 # <<<<<<<<<<<<<< -- * offset[0] += 1 -- * -- */ -- __pyx_v_f = (__pyx_v_f + 1); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":873 -- * f[0] = 120 # "x"; pad byte -- * f += 1 -- * offset[0] += 1 # <<<<<<<<<<<<<< -- * -- * offset[0] += child.itemsize -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":875 -- * offset[0] += 1 -- * -- * offset[0] += child.itemsize # <<<<<<<<<<<<<< -- * -- * if not PyDataType_HASFIELDS(child): -- */ -- __pyx_t_8 = 0; -- (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -- * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -- */ -- __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); -- if (__pyx_t_6) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":878 -- * -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num # <<<<<<<<<<<<<< -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") -- */ -- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 878, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); -- __pyx_t_4 = 0; -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); -- if (unlikely(__pyx_t_6)) { -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 880, __pyx_L1_error) -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":879 -- * if not PyDataType_HASFIELDS(child): -- * t = child.type_num -- * if end - f < 5: # <<<<<<<<<<<<<< -- * raise RuntimeError(u"Format string allocated too short.") -- * -- */ -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":883 -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 883, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 98; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":884 -- * # Until ticket #99 is fixed, use integers to avoid warnings -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 884, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":885 -- * if t == NPY_BYTE: f[0] = 98 #"b" -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 885, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x68; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":886 -- * elif t == NPY_UBYTE: f[0] = 66 #"B" -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 886, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 72; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":887 -- * elif t == NPY_SHORT: f[0] = 104 #"h" -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 887, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x69; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":888 -- * elif t == NPY_USHORT: f[0] = 72 #"H" -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 888, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 73; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":889 -- * elif t == NPY_INT: f[0] = 105 #"i" -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 889, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x6C; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":890 -- * elif t == NPY_UINT: f[0] = 73 #"I" -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 890, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 76; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":891 -- * elif t == NPY_LONG: f[0] = 108 #"l" -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 891, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x71; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":892 -- * elif t == NPY_ULONG: f[0] = 76 #"L" -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 892, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 81; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":893 -- * elif t == NPY_LONGLONG: f[0] = 113 #"q" -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 893, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x66; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":894 -- * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 894, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x64; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":895 -- * elif t == NPY_FLOAT: f[0] = 102 #"f" -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 895, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 0x67; -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":896 -- * elif t == NPY_DOUBLE: f[0] = 100 #"d" -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 896, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x66; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":897 -- * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 897, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x64; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":898 -- * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- */ -- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 898, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- if (__pyx_t_6) { -- (__pyx_v_f[0]) = 90; -- (__pyx_v_f[1]) = 0x67; -- __pyx_v_f = (__pyx_v_f + 1); -- goto __pyx_L15; -- } -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":899 -- * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd -- * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg -- * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- */ -- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(2, 899, __pyx_L1_error) -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- if (likely(__pyx_t_6)) { -- (__pyx_v_f[0]) = 79; -- goto __pyx_L15; -- } -+ /* function exit code */ -+ __pyx_L1_error:; -+ __Pyx_XDECREF(__pyx_t_1); -+ __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); -+ __pyx_r = 0; -+ __pyx_L0:; -+ __Pyx_XGIVEREF(__pyx_r); -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":901 -- * elif t == NPY_OBJECT: f[0] = 79 #"O" -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< -- * f += 1 -- * else: -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) -+ * -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ -- /*else*/ { -- __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_3); -- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(2, 901, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_t_4); -- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; -- __Pyx_Raise(__pyx_t_4, 0, 0, 0); -- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; -- __PYX_ERR(2, 901, __pyx_L1_error) -- } -- __pyx_L15:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":902 -- * else: -- * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) -- * f += 1 # <<<<<<<<<<<<<< -- * else: -- * # Cython ignores struct boundary information ("T{...}"), -- */ -- __pyx_v_f = (__pyx_v_f + 1); -+static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { -+ PyObject *__pyx_r = NULL; -+ __Pyx_RefNannyDeclarations -+ int __pyx_t_1; -+ __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":877 -- * offset[0] += child.itemsize -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< -- * t = child.type_num -- * if end - f < 5: -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ -- goto __pyx_L13; -- } -+ __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); -+ if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":906 -- * # Cython ignores struct boundary information ("T{...}"), -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< -- * return f -- * -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":752 -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape # <<<<<<<<<<<<<< -+ * else: -+ * return () - */ -- /*else*/ { -- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(2, 906, __pyx_L1_error) -- __pyx_v_f = __pyx_t_9; -- } -- __pyx_L13:; -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); -+ __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); -+ goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":851 -- * cdef tuple fields -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":751 - * -- * for childname in descr.names: # <<<<<<<<<<<<<< -- * fields = descr.fields[childname] -- * child, new_offset = fields -+ * cdef inline tuple PyDataType_SHAPE(dtype d): -+ * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< -+ * return <tuple>d.subarray.shape -+ * else: - */ - } -- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":907 -- * # so don't output it -- * f = _util_dtypestring(child, f, end, offset) -- * return f # <<<<<<<<<<<<<< -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":754 -+ * return <tuple>d.subarray.shape -+ * else: -+ * return () # <<<<<<<<<<<<<< - * - * - */ -- __pyx_r = __pyx_v_f; -- goto __pyx_L0; -+ /*else*/ { -+ __Pyx_XDECREF(__pyx_r); -+ __Pyx_INCREF(__pyx_empty_tuple); -+ __pyx_r = __pyx_empty_tuple; -+ goto __pyx_L0; -+ } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":842 -- * return () -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":750 -+ * return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) - * -- * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< -- * # Recursive utility function used in __getbuffer__ to get format -- * # string. The new location in the format string is returned. -+ * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< -+ * if PyDataType_HASSUBARRAY(d): -+ * return <tuple>d.subarray.shape - */ - - /* function exit code */ -- __pyx_L1_error:; -- __Pyx_XDECREF(__pyx_t_1); -- __Pyx_XDECREF(__pyx_t_3); -- __Pyx_XDECREF(__pyx_t_4); -- __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); -- __pyx_r = NULL; - __pyx_L0:; -- __Pyx_XDECREF((PyObject *)__pyx_v_child); -- __Pyx_XDECREF(__pyx_v_fields); -- __Pyx_XDECREF(__pyx_v_childname); -- __Pyx_XDECREF(__pyx_v_new_offset); -- __Pyx_XDECREF(__pyx_v_t); -+ __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5508,7 +3985,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("set_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1023 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":930 - * - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< -@@ -5517,7 +3994,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - Py_INCREF(__pyx_v_base); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1024 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":931 - * cdef inline void set_array_base(ndarray arr, object base): - * Py_INCREF(base) # important to do this before stealing the reference below! - * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< -@@ -5526,7 +4003,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - */ - (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1022 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":929 - * int _import_umath() except -1 - * - * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< -@@ -5538,7 +4015,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a - __Pyx_RefNannyFinishContext(); - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5553,7 +4030,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - int __pyx_t_1; - __Pyx_RefNannySetupContext("get_array_base", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1027 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":934 - * - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< -@@ -5562,7 +4039,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - __pyx_v_base = PyArray_BASE(__pyx_v_arr); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5572,7 +4049,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_t_1 = ((__pyx_v_base == NULL) != 0); - if (__pyx_t_1) { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1029 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":936 - * base = PyArray_BASE(arr) - * if base is NULL: - * return None # <<<<<<<<<<<<<< -@@ -5583,7 +4060,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1028 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":935 - * cdef inline object get_array_base(ndarray arr): - * base = PyArray_BASE(arr) - * if base is NULL: # <<<<<<<<<<<<<< -@@ -5592,7 +4069,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - */ - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1030 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":937 - * if base is NULL: - * return None - * return <object>base # <<<<<<<<<<<<<< -@@ -5604,7 +4081,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - __pyx_r = ((PyObject *)__pyx_v_base); - goto __pyx_L0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1026 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":933 - * PyArray_SetBaseObject(arr, base) - * - * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< -@@ -5619,12 +4096,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { -@@ -5638,13 +4115,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_array", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - { -@@ -5656,20 +4136,20 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1036 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":943 - * cdef inline int import_array() except -1: - * try: -- * _import_array() # <<<<<<<<<<<<<< -+ * __pyx_import_array() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") - */ -- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1036, __pyx_L3_error) -+ __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 943, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - } -@@ -5679,9 +4159,9 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1037 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":944 - * try: -- * _import_array() -+ * __pyx_import_array() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.multiarray failed to import") - * -@@ -5689,32 +4169,32 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1037, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 944, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 945, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1038, __pyx_L5_except_error) -+ __PYX_ERR(2, 945, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1035 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":942 - * # Cython code. - * cdef inline int import_array() except -1: - * try: # <<<<<<<<<<<<<< -- * _import_array() -+ * __pyx_import_array() - * except Exception: - */ - __Pyx_XGIVEREF(__pyx_t_1); -@@ -5725,12 +4205,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1034 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":941 - * # Versions of the import_* functions which are more suitable for - * # Cython code. - * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< - * try: -- * _import_array() -+ * __pyx_import_array() - */ - - /* function exit code */ -@@ -5748,7 +4228,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5767,9 +4247,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_umath", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5785,16 +4268,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1042 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":949 - * cdef inline int import_umath() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1042, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 949, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5808,7 +4291,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1043 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":950 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< -@@ -5818,28 +4301,28 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1043, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 950, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 951, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1044, __pyx_L5_except_error) -+ __PYX_ERR(2, 951, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1041 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":948 - * - * cdef inline int import_umath() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5854,7 +4337,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1040 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":947 - * raise ImportError("numpy.core.multiarray failed to import") - * - * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< -@@ -5877,7 +4360,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { - return __pyx_r; - } - --/* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -5896,9 +4379,12 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("import_ufunc", 0); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5914,16 +4400,16 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1048 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":955 - * cdef inline int import_ufunc() except -1: - * try: - * _import_umath() # <<<<<<<<<<<<<< - * except Exception: - * raise ImportError("numpy.core.umath failed to import") - */ -- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 1048, __pyx_L3_error) -+ __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 955, __pyx_L3_error) - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5937,35 +4423,38 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - goto __pyx_L8_try_end; - __pyx_L3_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1049 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":956 - * try: - * _import_umath() - * except Exception: # <<<<<<<<<<<<<< - * raise ImportError("numpy.core.umath failed to import") -+ * - */ - __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); - if (__pyx_t_4) { - __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); -- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 1049, __pyx_L5_except_error) -+ if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 956, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GOTREF(__pyx_t_7); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1050 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":957 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< -+ * -+ * cdef extern from *: - */ -- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 957, __pyx_L5_except_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_Raise(__pyx_t_8, 0, 0, 0); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; -- __PYX_ERR(2, 1050, __pyx_L5_except_error) -+ __PYX_ERR(2, 957, __pyx_L5_except_error) - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1047 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":954 - * - * cdef inline int import_ufunc() except -1: - * try: # <<<<<<<<<<<<<< -@@ -5980,7 +4469,7 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __pyx_L8_try_end:; - } - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":953 - * raise ImportError("numpy.core.umath failed to import") - * - * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -@@ -6002,6 +4491,180 @@ static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { - __Pyx_RefNannyFinishContext(); - return __pyx_r; - } -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_timedelta64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_timedelta64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":979 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyTimedeltaArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":967 -+ * -+ * -+ * cdef inline bint is_timedelta64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.timedelta64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+static CYTHON_INLINE int __pyx_f_5numpy_is_datetime64_object(PyObject *__pyx_v_obj) { -+ int __pyx_r; -+ __Pyx_RefNannyDeclarations -+ __Pyx_RefNannySetupContext("is_datetime64_object", 0); -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":994 -+ * bool -+ * """ -+ * return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type) # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = PyObject_TypeCheck(__pyx_v_obj, (&PyDatetimeArrType_Type)); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":982 -+ * -+ * -+ * cdef inline bint is_datetime64_object(object obj): # <<<<<<<<<<<<<< -+ * """ -+ * Cython equivalent of `isinstance(obj, np.datetime64)` -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ __Pyx_RefNannyFinishContext(); -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+static CYTHON_INLINE npy_datetime __pyx_f_5numpy_get_datetime64_value(PyObject *__pyx_v_obj) { -+ npy_datetime __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1004 -+ * also needed. That can be found using `get_datetime64_unit`. -+ * """ -+ * return (<PyDatetimeScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyDatetimeScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":997 -+ * -+ * -+ * cdef inline npy_datetime get_datetime64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy datetime64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+static CYTHON_INLINE npy_timedelta __pyx_f_5numpy_get_timedelta64_value(PyObject *__pyx_v_obj) { -+ npy_timedelta __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1011 -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ * """ -+ * return (<PyTimedeltaScalarObject*>obj).obval # <<<<<<<<<<<<<< -+ * -+ * -+ */ -+ __pyx_r = ((PyTimedeltaScalarObject *)__pyx_v_obj)->obval; -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1007 -+ * -+ * -+ * cdef inline npy_timedelta get_timedelta64_value(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the int64 value underlying scalar numpy timedelta64 object -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} -+ -+/* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+static CYTHON_INLINE NPY_DATETIMEUNIT __pyx_f_5numpy_get_datetime64_unit(PyObject *__pyx_v_obj) { -+ NPY_DATETIMEUNIT __pyx_r; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1018 -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ * """ -+ * return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base # <<<<<<<<<<<<<< -+ */ -+ __pyx_r = ((NPY_DATETIMEUNIT)((PyDatetimeScalarObject *)__pyx_v_obj)->obmeta.base); -+ goto __pyx_L0; -+ -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 -+ * -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. -+ */ -+ -+ /* function exit code */ -+ __pyx_L0:; -+ return __pyx_r; -+} - static struct __pyx_vtabstruct_4cylp_2cy_12CyWolfePivot_CyWolfePivot __pyx_vtable_4cylp_2cy_12CyWolfePivot_CyWolfePivot; - - static PyObject *__pyx_tp_new_4cylp_2cy_12CyWolfePivot_CyWolfePivot(PyTypeObject *t, PyObject *a, PyObject *k) { -@@ -6047,7 +4710,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_12CyWolfePivot_CyWolfePivot = { - sizeof(struct __pyx_obj_4cylp_2cy_12CyWolfePivot_CyWolfePivot), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4cylp_2cy_12CyWolfePivot_CyWolfePivot, /*tp_dealloc*/ -+ #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030800b4 -+ 0, /*tp_vectorcall_offset*/ -+ #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 -@@ -6100,6 +4768,12 @@ static PyTypeObject __pyx_type_4cylp_2cy_12CyWolfePivot_CyWolfePivot = { - #if PY_VERSION_HEX >= 0x030800b1 - 0, /*tp_vectorcall*/ - #endif -+ #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 -+ 0, /*tp_print*/ -+ #endif -+ #if PY_VERSION_HEX >= 0x030B00A2 -+ 0, /*tp_inline_values_offset*/ -+ #endif - }; - - static PyMethodDef __pyx_methods[] = { -@@ -6149,13 +4823,8 @@ static struct PyModuleDef __pyx_moduledef = { - - static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_CyWolfePivot, __pyx_k_CyWolfePivot, sizeof(__pyx_k_CyWolfePivot), 0, 0, 1, 1}, -- {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, -- {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, - {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, -- {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, -- {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, -- {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_n_s_clear, __pyx_k_clear, sizeof(__pyx_k_clear), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_dualTolerance, __pyx_k_dualTolerance, sizeof(__pyx_k_dualTolerance), 0, 0, 1, 1}, -@@ -6168,12 +4837,9 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_nRows, __pyx_k_nRows, sizeof(__pyx_k_nRows), 0, 0, 1, 1}, - {&__pyx_n_s_nVariables, __pyx_k_nVariables, sizeof(__pyx_k_nVariables), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, -- {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, -- {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, - {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, - {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, -- {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, -@@ -6183,16 +4849,12 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, - {&__pyx_n_s_transposeTimes, __pyx_k_transposeTimes, sizeof(__pyx_k_transposeTimes), 0, 0, 1, 1}, -- {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, - {&__pyx_n_s_updateColumnTranspose, __pyx_k_updateColumnTranspose, sizeof(__pyx_k_updateColumnTranspose), 0, 0, 1, 1}, - {0, 0, 0, 0, 0, 0, 0} - }; - static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 2, __pyx_L1_error) -- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(2, 272, __pyx_L1_error) -- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(2, 285, __pyx_L1_error) -- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(2, 856, __pyx_L1_error) -- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 1038, __pyx_L1_error) -+ __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(2, 945, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -@@ -6221,82 +4883,27 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":272 -- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< -- * -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- */ -- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 272, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__3); -- __Pyx_GIVEREF(__pyx_tuple__3); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":276 -- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) -- * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): -- * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< -- * -- * info.buf = PyArray_DATA(self) -- */ -- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 276, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__4); -- __Pyx_GIVEREF(__pyx_tuple__4); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":306 -- * if ((descr.byteorder == c'>' and little_endian) or -- * (descr.byteorder == c'<' and not little_endian)): -- * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< -- * if t == NPY_BYTE: f = "b" -- * elif t == NPY_UBYTE: f = "B" -- */ -- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(2, 306, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__5); -- __Pyx_GIVEREF(__pyx_tuple__5); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":856 -- * -- * if (end - f) - <int>(new_offset - offset[0]) < 15: -- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< -- * -- * if ((child.byteorder == c'>' and little_endian) or -- */ -- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(2, 856, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__6); -- __Pyx_GIVEREF(__pyx_tuple__6); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":880 -- * t = child.type_num -- * if end - f < 5: -- * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< -- * -- * # Until ticket #99 is fixed, use integers to avoid warnings -- */ -- __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(2, 880, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__7); -- __Pyx_GIVEREF(__pyx_tuple__7); -- -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1038 -- * _import_array() -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":945 -+ * __pyx_import_array() - * except Exception: - * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_umath() except -1: - */ -- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(2, 1038, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__8); -- __Pyx_GIVEREF(__pyx_tuple__8); -+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(2, 945, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__3); -+ __Pyx_GIVEREF(__pyx_tuple__3); - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1044 -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":951 - * _import_umath() - * except Exception: - * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< - * - * cdef inline int import_ufunc() except -1: - */ -- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(2, 1044, __pyx_L1_error) -- __Pyx_GOTREF(__pyx_tuple__9); -- __Pyx_GIVEREF(__pyx_tuple__9); -+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(2, 951, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_tuple__4); -+ __Pyx_GIVEREF(__pyx_tuple__4); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6351,6 +4958,9 @@ static int __Pyx_modinit_function_export_code(void) { - static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpPrimalColumnPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -6387,6 +4997,9 @@ static int __Pyx_modinit_type_init_code(void) { - static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(3, 9, __pyx_L1_error) -@@ -6416,18 +5029,38 @@ static int __Pyx_modinit_type_import_code(void) { - if (!__pyx_ptype_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector) __PYX_ERR(6, 22, __pyx_L1_error) - __pyx_vtabptr_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector = (struct __pyx_vtabstruct_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector*)__Pyx_GetVtable(__pyx_ptype_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector->tp_dict); if (unlikely(!__pyx_vtabptr_4cylp_2cy_19CyCoinIndexedVector_CyCoinIndexedVector)) __PYX_ERR(6, 22, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; -- __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 206, __pyx_L1_error) -+ __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 206, __pyx_L1_error) -- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 229, __pyx_L1_error) -- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 233, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(2, 200, __pyx_L1_error) -+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(2, 223, __pyx_L1_error) -+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(2, 227, __pyx_L1_error) - __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); -- if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 242, __pyx_L1_error) -- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); -- if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 918, __pyx_L1_error) -+ if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(2, 239, __pyx_L1_error) -+ __pyx_ptype_5numpy_generic = __Pyx_ImportType(__pyx_t_1, "numpy", "generic", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_generic) __PYX_ERR(2, 771, __pyx_L1_error) -+ __pyx_ptype_5numpy_number = __Pyx_ImportType(__pyx_t_1, "numpy", "number", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_number) __PYX_ERR(2, 773, __pyx_L1_error) -+ __pyx_ptype_5numpy_integer = __Pyx_ImportType(__pyx_t_1, "numpy", "integer", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_integer) __PYX_ERR(2, 775, __pyx_L1_error) -+ __pyx_ptype_5numpy_signedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "signedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_signedinteger) __PYX_ERR(2, 777, __pyx_L1_error) -+ __pyx_ptype_5numpy_unsignedinteger = __Pyx_ImportType(__pyx_t_1, "numpy", "unsignedinteger", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_unsignedinteger) __PYX_ERR(2, 779, __pyx_L1_error) -+ __pyx_ptype_5numpy_inexact = __Pyx_ImportType(__pyx_t_1, "numpy", "inexact", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_inexact) __PYX_ERR(2, 781, __pyx_L1_error) -+ __pyx_ptype_5numpy_floating = __Pyx_ImportType(__pyx_t_1, "numpy", "floating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_floating) __PYX_ERR(2, 783, __pyx_L1_error) -+ __pyx_ptype_5numpy_complexfloating = __Pyx_ImportType(__pyx_t_1, "numpy", "complexfloating", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_complexfloating) __PYX_ERR(2, 785, __pyx_L1_error) -+ __pyx_ptype_5numpy_flexible = __Pyx_ImportType(__pyx_t_1, "numpy", "flexible", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_flexible) __PYX_ERR(2, 787, __pyx_L1_error) -+ __pyx_ptype_5numpy_character = __Pyx_ImportType(__pyx_t_1, "numpy", "character", sizeof(PyObject), __Pyx_ImportType_CheckSize_Warn); -+ if (!__pyx_ptype_5numpy_character) __PYX_ERR(2, 789, __pyx_L1_error) -+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Ignore); -+ if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(2, 827, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpDualRowPivotBase"); if (unlikely(!__pyx_t_1)) __PYX_ERR(7, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); -@@ -6530,13 +5163,17 @@ static int __Pyx_modinit_variable_import_code(void) { - static int __Pyx_modinit_function_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); - /*--- Function import code ---*/ - __pyx_t_1 = PyImport_ImportModule("cylp.cy.CyClpPrimalColumnPivotBase"); if (!__pyx_t_1) __PYX_ERR(1, 1, __pyx_L1_error) -+ __Pyx_GOTREF(__pyx_t_1); - if (__Pyx_ImportFunction(__pyx_t_1, "RunPivotColumn", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunPivotColumn, "int (void *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *, ICoinIndexedVector *)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunClone", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunClone, "ClpPrimalColumnPivot *(void *, int)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) - if (__Pyx_ImportFunction(__pyx_t_1, "RunSaveWeights", (void (**)(void))&__pyx_f_4cylp_2cy_26CyClpPrimalColumnPivotBase_RunSaveWeights, "void (void *, IClpSimplex *, int)") < 0) __PYX_ERR(1, 1, __pyx_L1_error) -- Py_DECREF(__pyx_t_1); __pyx_t_1 = 0; -+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; -@@ -6546,17 +5183,19 @@ static int __Pyx_modinit_function_import_code(void) { - } - - --#if PY_MAJOR_VERSION < 3 --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC void --#else -+#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#elif PY_MAJOR_VERSION < 3 -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" void -+#else -+#define __Pyx_PyMODINIT_FUNC void - #endif - #else --#ifdef CYTHON_NO_PYINIT_EXPORT --#define __Pyx_PyMODINIT_FUNC PyObject * -+#ifdef __cplusplus -+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else --#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -+#define __Pyx_PyMODINIT_FUNC PyObject * - #endif - #endif - -@@ -6638,6 +5277,9 @@ static CYTHON_SMALL_CODE int __pyx_pymod_exec_CyWolfePivot(PyObject *__pyx_pyini - #endif - { - PyObject *__pyx_t_1 = NULL; -+ int __pyx_lineno = 0; -+ const char *__pyx_filename = NULL; -+ int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { -@@ -6685,11 +5327,9 @@ if (!__Pyx_RefNanny) { - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ -- #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS -- #ifdef WITH_THREAD /* Python build with threading support? */ -+ #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif -- #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; -@@ -6726,17 +5366,17 @@ if (!__Pyx_RefNanny) { - } - #endif - /*--- Builtin init code ---*/ -- if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Constants init code ---*/ -- if (__Pyx_InitCachedConstants() < 0) goto __pyx_L1_error; -+ if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); -- if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; -- if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) -+ if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); -- if (unlikely(__Pyx_modinit_function_import_code() != 0)) goto __pyx_L1_error; -+ if (unlikely(__Pyx_modinit_function_import_code() < 0)) __PYX_ERR(1, 1, __pyx_L1_error) - /*--- Execution code ---*/ - #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) - if (__Pyx_patch_abc() < 0) __PYX_ERR(1, 1, __pyx_L1_error) -@@ -6752,12 +5392,12 @@ if (!__Pyx_RefNanny) { - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - -- /* "../../../../Users/tkral/Anaconda3/lib/site-packages/Cython/Includes/numpy/__init__.pxd":1046 -- * raise ImportError("numpy.core.umath failed to import") -+ /* "../miniforge3/envs/numpy-dev/lib/python3.10/site-packages/numpy/__init__.pxd":1014 - * -- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< -- * try: -- * _import_umath() -+ * -+ * cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil: # <<<<<<<<<<<<<< -+ * """ -+ * returns the unit part of the dtype for a numpy datetime64 object. - */ - - /*--- Wrapped vars code ---*/ -@@ -6953,7 +5593,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, - #if CYTHON_COMPILING_IN_CPYTHON - static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; -- ternaryfunc call = func->ob_type->tp_call; -+ ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) -@@ -7269,7 +5909,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); - #if CYTHON_FAST_PYCCALL -- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { -+ } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); - #endif - } -@@ -7650,71 +6290,16 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject - PyObject* tmp_tb = tstate->curexc_traceback; - if (tb != tmp_tb) { - Py_INCREF(tb); -- tstate->curexc_traceback = tb; -- Py_XDECREF(tmp_tb); -- } --#endif -- } --bad: -- Py_XDECREF(owned_instance); -- return; --} --#endif -- --/* DictGetItem */ --#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY --static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { -- PyObject *value; -- value = PyDict_GetItemWithError(d, key); -- if (unlikely(!value)) { -- if (!PyErr_Occurred()) { -- if (unlikely(PyTuple_Check(key))) { -- PyObject* args = PyTuple_Pack(1, key); -- if (likely(args)) { -- PyErr_SetObject(PyExc_KeyError, args); -- Py_DECREF(args); -- } -- } else { -- PyErr_SetObject(PyExc_KeyError, key); -- } -- } -- return NULL; -- } -- Py_INCREF(value); -- return value; --} --#endif -- --/* RaiseTooManyValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { -- PyErr_Format(PyExc_ValueError, -- "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); --} -- --/* RaiseNeedMoreValuesToUnpack */ --static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { -- PyErr_Format(PyExc_ValueError, -- "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", -- index, (index == 1) ? "" : "s"); --} -- --/* RaiseNoneIterError */ --static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { -- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); --} -- --/* ExtTypeTest */ --static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { -- if (unlikely(!type)) { -- PyErr_SetString(PyExc_SystemError, "Missing type object"); -- return 0; -+ tstate->curexc_traceback = tb; -+ Py_XDECREF(tmp_tb); -+ } -+#endif - } -- if (likely(__Pyx_TypeCheck(obj, type))) -- return 1; -- PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", -- Py_TYPE(obj)->tp_name, type->tp_name); -- return 0; -+bad: -+ Py_XDECREF(owned_instance); -+ return; - } -+#endif - - /* GetTopmostException */ - #if CYTHON_USE_EXC_INFO_STACK -@@ -8054,6 +6639,28 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable) { - return -1; - } - -+/* PyObjectGetAttrStrNoError */ -+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { -+ __Pyx_PyThreadState_declare -+ __Pyx_PyThreadState_assign -+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) -+ __Pyx_PyErr_Clear(); -+} -+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { -+ PyObject *result; -+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 -+ PyTypeObject* tp = Py_TYPE(obj); -+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { -+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); -+ } -+#endif -+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name); -+ if (unlikely(!result)) { -+ __Pyx_PyObject_GetAttrStr_ClearAttributeError(); -+ } -+ return result; -+} -+ - /* SetupReduce */ - static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; -@@ -8081,43 +6688,51 @@ static int __Pyx_setup_reduce(PyObject* type_obj) { - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - #if CYTHON_USE_PYTYPE_LOOKUP -- if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (_PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #else -- if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto GOOD; -+ if (PyObject_HasAttr(type_obj, __pyx_n_s_getstate)) goto __PYX_GOOD; - #endif - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #else -- object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto BAD; -+ object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; - #endif -- reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto BAD; -+ reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { - #if CYTHON_USE_PYTYPE_LOOKUP -- object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #else -- object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto BAD; -+ object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; - #endif -- reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto BAD; -+ reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { -- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_cython); if (unlikely(!reduce_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto BAD; -+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); -+ if (likely(reduce_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (reduce == object_reduce || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { -- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate_cython); if (unlikely(!setstate_cython)) goto BAD; -- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto BAD; -- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto BAD; -+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); -+ if (likely(setstate_cython)) { -+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; -+ } else if (!setstate || PyErr_Occurred()) { -+ goto __PYX_BAD; -+ } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } -- goto GOOD; --BAD: -+ goto __PYX_GOOD; -+__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; --GOOD: -+__PYX_GOOD: - #if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); -@@ -8158,7 +6773,7 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN - - /* CLineInTraceback */ - #ifndef CYTHON_CLINE_IN_TRACEBACK --static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { -+static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; - #if CYTHON_COMPILING_IN_CPYTHON -@@ -8188,7 +6803,7 @@ static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - } - if (!use_cline) { - c_line = 0; -- PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); -+ (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; -@@ -8262,7 +6877,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( -- __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); -+ __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } -@@ -8285,30 +6900,31 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { -- PyCodeObject *py_code = 0; -- PyObject *py_srcfile = 0; -- PyObject *py_funcname = 0; -+ PyCodeObject *py_code = NULL; -+ PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 -+ PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); -- #else -- py_srcfile = PyUnicode_FromString(filename); -- #endif - if (!py_srcfile) goto bad; -+ #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); -+ if (!py_funcname) goto bad; -+ funcname = PyUnicode_AsUTF8(py_funcname); -+ if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); -- #else -- py_funcname = PyUnicode_FromString(funcname); -+ if (!py_funcname) goto bad; - #endif - } -- if (!py_funcname) goto bad; -+ #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, -@@ -8327,11 +6943,16 @@ static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); -- Py_DECREF(py_funcname); -+ #else -+ py_code = PyCode_NewEmpty(filename, funcname, py_line); -+ #endif -+ Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; - bad: -- Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); -+ #if PY_MAJOR_VERSION < 3 -+ Py_XDECREF(py_srcfile); -+ #endif - return NULL; - } - static void __Pyx_AddTraceback(const char *funcname, int c_line, -@@ -8385,99 +7006,6 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line, - return (target_type) value;\ - } - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(long) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(long) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(long) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(long), -- little, !is_unsigned); -- } --} -- --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__IClpSimplex_3a__3a_Status(enum IClpSimplex::Status value) { -- const enum IClpSimplex::Status neg_one = (enum IClpSimplex::Status) ((enum IClpSimplex::Status) 0 - (enum IClpSimplex::Status) 1), const_zero = (enum IClpSimplex::Status) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum IClpSimplex::Status) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum IClpSimplex::Status) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum IClpSimplex::Status) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(enum IClpSimplex::Status) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum IClpSimplex::Status) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum IClpSimplex::Status), -- little, !is_unsigned); -- } --} -- --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(int) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(int) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(int) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(int), -- little, !is_unsigned); -- } --} -- - /* Declarations */ - #if CYTHON_CCOMPLEX - #ifdef __cplusplus -@@ -8595,7 +7123,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_float(a, a); - return __Pyx_c_prod_float(a, a); - case 3: - z = __Pyx_c_prod_float(a, a); -@@ -8750,7 +7277,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - case 1: - return a; - case 2: -- z = __Pyx_c_prod_double(a, a); - return __Pyx_c_prod_double(a, a); - case 3: - z = __Pyx_c_prod_double(a, a); -@@ -8788,40 +7314,16 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { - #endif - #endif - --/* CIntToPy */ --static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { -- const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; -- const int is_unsigned = neg_one > const_zero; -- if (is_unsigned) { -- if (sizeof(enum NPY_TYPES) < sizeof(long)) { -- return PyInt_FromLong((long) value); -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { -- return PyLong_FromUnsignedLong((unsigned long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { -- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); --#endif -- } -- } else { -- if (sizeof(enum NPY_TYPES) <= sizeof(long)) { -- return PyInt_FromLong((long) value); --#ifdef HAVE_LONG_LONG -- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { -- return PyLong_FromLongLong((PY_LONG_LONG) value); --#endif -- } -- } -- { -- int one = 1; int little = (int)*(unsigned char *)&one; -- unsigned char *bytes = (unsigned char *)&value; -- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), -- little, !is_unsigned); -- } --} -- - /* CIntFromPy */ - static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -- const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -9008,9 +7510,130 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - return (int) -1; - } - -+/* CIntToPy */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(long) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(long) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(long) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(long), -+ little, !is_unsigned); -+ } -+} -+ -+/* CIntToPy */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__IClpSimplex_3a__3a_Status(enum IClpSimplex::Status value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const enum IClpSimplex::Status neg_one = (enum IClpSimplex::Status) -1, const_zero = (enum IClpSimplex::Status) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(enum IClpSimplex::Status) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(enum IClpSimplex::Status) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(enum IClpSimplex::Status) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(enum IClpSimplex::Status) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(enum IClpSimplex::Status) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(enum IClpSimplex::Status), -+ little, !is_unsigned); -+ } -+} -+ -+/* CIntToPy */ -+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const int neg_one = (int) -1, const_zero = (int) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif -+ const int is_unsigned = neg_one > const_zero; -+ if (is_unsigned) { -+ if (sizeof(int) < sizeof(long)) { -+ return PyInt_FromLong((long) value); -+ } else if (sizeof(int) <= sizeof(unsigned long)) { -+ return PyLong_FromUnsignedLong((unsigned long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { -+ return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -+#endif -+ } -+ } else { -+ if (sizeof(int) <= sizeof(long)) { -+ return PyInt_FromLong((long) value); -+#ifdef HAVE_LONG_LONG -+ } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { -+ return PyLong_FromLongLong((PY_LONG_LONG) value); -+#endif -+ } -+ } -+ { -+ int one = 1; int little = (int)*(unsigned char *)&one; -+ unsigned char *bytes = (unsigned char *)&value; -+ return _PyLong_FromByteArray(bytes, sizeof(int), -+ little, !is_unsigned); -+ } -+} -+ - /* CIntFromPy */ - static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -- const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wconversion" -+#endif -+ const long neg_one = (long) -1, const_zero = (long) 0; -+#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -+#pragma GCC diagnostic pop -+#endif - const int is_unsigned = neg_one > const_zero; - #if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { -@@ -9615,6 +8238,23 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_DECREF(x); - return ival; - } -+static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { -+ if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { -+ return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -+#if PY_MAJOR_VERSION < 3 -+ } else if (likely(PyInt_CheckExact(o))) { -+ return PyInt_AS_LONG(o); -+#endif -+ } else { -+ Py_ssize_t ival; -+ PyObject *x; -+ x = PyNumber_Index(o); -+ if (!x) return -1; -+ ival = PyInt_AsLong(x); -+ Py_DECREF(x); -+ return ival; -+ } -+} - static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); - } diff --git a/build/pkgs/cylp/spkg-install.in b/build/pkgs/cylp/spkg-install.in index 26ae9ae59f7..e840732a8e5 100644 --- a/build/pkgs/cylp/spkg-install.in +++ b/build/pkgs/cylp/spkg-install.in @@ -1,5 +1,5 @@ cd src -#export CYLP_USE_CYTHON=1 # use pkg-config to discover coin installation unset COIN_INSTALL_DIR -sdh_pip_install . +# --no-build-isolation to ignore the numpy version pin in pyproject.toml +sdh_pip_install --no-build-isolation . diff --git a/build/pkgs/cypari/dependencies b/build/pkgs/cypari/dependencies index 72b5af7ad81..69dfe7e7d8a 100644 --- a/build/pkgs/cypari/dependencies +++ b/build/pkgs/cypari/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cython pari cysignals | $(PYTHON_TOOLCHAIN) + cython pari cysignals | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cypari/patches/cython3-legacy.patch b/build/pkgs/cypari/patches/cython3-legacy.patch new file mode 100644 index 00000000000..41392fe80d7 --- /dev/null +++ b/build/pkgs/cypari/patches/cython3-legacy.patch @@ -0,0 +1,32 @@ +commit 8ef356a4eb936c37f55a5c501f3a955e6740c0c5 +Author: Gonzalo Tornarรญa <tornaria@cmat.edu.uy> +Date: Wed Jul 19 19:45:23 2023 -0300 + + cython3 support using legacy directives + +diff --git a/cypari2/gen.pyx b/cypari2/gen.pyx +index 247b1ad..75050a0 100644 +--- a/cypari2/gen.pyx ++++ b/cypari2/gen.pyx +@@ -329,7 +329,7 @@ cdef class Gen(Gen_base): + >>> pari = Pari() + >>> L = pari("vector(10,i,i^2)") + >>> L.__iter__() +- <generator object at ...> ++ <...generator object at ...> + >>> [x for x in L] + [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] + >>> list(L) +diff --git a/setup.py b/setup.py +index 2188711..455337f 100755 +--- a/setup.py ++++ b/setup.py +@@ -36,6 +36,8 @@ class build_ext(_build_ext): + "binding": True, + "cdivision": True, + "language_level": 2, ++ "legacy_implicit_noexcept": True, ++ "c_api_binop_methods": True, + } + + _build_ext.finalize_options(self) diff --git a/build/pkgs/cysignals/dependencies b/build/pkgs/cysignals/dependencies index d3225d480f1..cd45ae2076c 100644 --- a/build/pkgs/cysignals/dependencies +++ b/build/pkgs/cysignals/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cython pari | $(PYTHON_TOOLCHAIN) + cython pari | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cysignals/patches/cython3-fix-warning.patch b/build/pkgs/cysignals/patches/cython3-fix-warning.patch new file mode 100644 index 00000000000..98cad9625e4 --- /dev/null +++ b/build/pkgs/cysignals/patches/cython3-fix-warning.patch @@ -0,0 +1,13 @@ +diff --git a/src/cysignals/signals.pxd.in b/src/cysignals/signals.pxd.in +index c86e085..a98c8d1 100644 +--- a/src/cysignals/signals.pxd.in ++++ b/src/cysignals/signals.pxd.in +@@ -54,7 +54,7 @@ cdef extern from "macros.h" nogil: + # can be used to make Cython check whether there is a pending exception + # (PyErr_Occurred() is non-NULL). To Cython, it will look like + # cython_check_exception() actually raised the exception. +-cdef inline void cython_check_exception() nogil except *: ++cdef inline void cython_check_exception() except * nogil: + pass + + diff --git a/build/pkgs/cysignals/patches/cython3-legacy.patch b/build/pkgs/cysignals/patches/cython3-legacy.patch new file mode 100644 index 00000000000..274575d5d35 --- /dev/null +++ b/build/pkgs/cysignals/patches/cython3-legacy.patch @@ -0,0 +1,30 @@ +commit 9996a4028ddc7f9a5ffda3df65d5b7d3b7df8aa5 +Author: Gonzalo Tornarรญa <tornaria@cmat.edu.uy> +Date: Wed Jul 19 18:34:57 2023 -0300 + + cython3 support using legacy directives + +diff --git a/setup.py b/setup.py +index 37acdfc..f68270b 100755 +--- a/setup.py ++++ b/setup.py +@@ -157,13 +157,17 @@ class build_ext(_build_ext): + # Run Cython with -Werror on continuous integration services + # with Python 3.6 or later + from Cython.Compiler import Options +- Options.warning_errors = True ++ Options.warning_errors = False + + from Cython.Build.Dependencies import cythonize + return cythonize(extensions, + build_dir=cythonize_dir, + include_path=["src", os.path.join(cythonize_dir, "src")], +- compiler_directives=dict(binding=True, language_level=2)) ++ compiler_directives=dict( ++ binding=True, ++ language_level=2, ++ legacy_implicit_noexcept=True, ++ )) + + + class build_py(_build_py): diff --git a/build/pkgs/cython/checksums.ini b/build/pkgs/cython/checksums.ini index b06052c59aa..5d0bc66c242 100644 --- a/build/pkgs/cython/checksums.ini +++ b/build/pkgs/cython/checksums.ini @@ -1,5 +1,5 @@ tarball=Cython-VERSION.tar.gz -sha1=015b737107304a5777f5c6552ffb12713684c924 -md5=91c36ea86c00adcc5c1c11cf48b733c0 -cksum=1793363471 +sha1=08eb99f7c95b7ca667b1547575e7369d8064b4b3 +md5=00def3f2b96c393098e01eb2f1f169ad +cksum=2321746451 upstream_url=https://pypi.io/packages/source/C/Cython/Cython-VERSION.tar.gz diff --git a/build/pkgs/cython/dependencies b/build/pkgs/cython/dependencies index 0738c2d7777..7cb4e63bf76 100644 --- a/build/pkgs/cython/dependencies +++ b/build/pkgs/cython/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) pythran ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cython/distros/arch.txt b/build/pkgs/cython/distros/arch.txt new file mode 100644 index 00000000000..f6629e02456 --- /dev/null +++ b/build/pkgs/cython/distros/arch.txt @@ -0,0 +1 @@ +cython diff --git a/build/pkgs/cython/distros/debian.txt b/build/pkgs/cython/distros/debian.txt new file mode 100644 index 00000000000..f6629e02456 --- /dev/null +++ b/build/pkgs/cython/distros/debian.txt @@ -0,0 +1 @@ +cython diff --git a/build/pkgs/cython/distros/fedora.txt b/build/pkgs/cython/distros/fedora.txt new file mode 100644 index 00000000000..002d1b93c6f --- /dev/null +++ b/build/pkgs/cython/distros/fedora.txt @@ -0,0 +1 @@ +Cython diff --git a/build/pkgs/cython/distros/gentoo.txt b/build/pkgs/cython/distros/gentoo.txt new file mode 100644 index 00000000000..bb1512a15ba --- /dev/null +++ b/build/pkgs/cython/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/cython diff --git a/build/pkgs/cython/distros/opensuse.txt b/build/pkgs/cython/distros/opensuse.txt new file mode 100644 index 00000000000..09d8844feaf --- /dev/null +++ b/build/pkgs/cython/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-Cython diff --git a/build/pkgs/cython/install-requires.txt b/build/pkgs/cython/install-requires.txt index b8a968fa247..3693d637891 100644 --- a/build/pkgs/cython/install-requires.txt +++ b/build/pkgs/cython/install-requires.txt @@ -1 +1 @@ -cython >=0.29.21, <1.0 +cython >=3.0, <4.0 diff --git a/build/pkgs/cython/package-version.txt b/build/pkgs/cython/package-version.txt index babe4be9be1..b5021469305 100644 --- a/build/pkgs/cython/package-version.txt +++ b/build/pkgs/cython/package-version.txt @@ -1 +1 @@ -0.29.32.p2 +3.0.2 diff --git a/build/pkgs/cython/patches/4918.patch b/build/pkgs/cython/patches/4918.patch deleted file mode 100644 index a9dbb0a4a0c..00000000000 --- a/build/pkgs/cython/patches/4918.patch +++ /dev/null @@ -1,287 +0,0 @@ -From 0dade9353e06b052d0da5e512cdc2ce04061904a Mon Sep 17 00:00:00 2001 -From: Matthias Koeppe <mkoeppe@math.ucdavis.edu> -Date: Sat, 23 Jul 2022 10:53:49 -0700 -Subject: [PATCH 1/3] Add PEP420 namespace support - -Backport of https://github.com/cython/cython/pull/2946 to 0.29.x ---- - Cython/Compiler/Main.py | 44 +++++++++++++++---- - Cython/Utils.py | 26 ++++++++--- - runtests.py | 1 + - .../build/cythonize_pep420_namespace.srctree | 44 +++++++++++++++++++ - 4 files changed, 99 insertions(+), 16 deletions(-) - create mode 100644 tests/build/cythonize_pep420_namespace.srctree - -diff --git a/Cython/Compiler/Main.py b/Cython/Compiler/Main.py -index dc4add541e..2be7a06a1c 100644 ---- a/Cython/Compiler/Main.py -+++ b/Cython/Compiler/Main.py -@@ -801,32 +801,58 @@ def search_include_directories(dirs, qualified_name, suffix, pos, include=False) - else: - dirs = (Utils.find_root_package_dir(file_desc.filename),) + dirs - -+ # search for dotted filename e.g. <dir>/foo.bar.pxd - dotted_filename = qualified_name - if suffix: - dotted_filename += suffix - -+ for dirname in dirs: -+ path = os.path.join(dirname, dotted_filename) -+ if os.path.exists(path): -+ return path -+ -+ # search for filename in package structure e.g. <dir>/foo/bar.pxd or <dir>/foo/bar/__init__.pxd - if not include: -+ - names = qualified_name.split('.') - package_names = tuple(names[:-1]) - module_name = names[-1] - module_filename = module_name + suffix - package_filename = "__init__" + suffix - -- for dirname in dirs: -- path = os.path.join(dirname, dotted_filename) -- if os.path.exists(path): -- return path -- -- if not include: -- package_dir = Utils.check_package_dir(dirname, package_names) -+ # search for standard packages first - PEP420 -+ namespace_dirs = [] -+ for dirname in dirs: -+ package_dir, is_namespace = Utils.check_package_dir(dirname, package_names) - if package_dir is not None: -+ -+ if is_namespace: -+ namespace_dirs.append(package_dir) -+ continue -+ -+ # matches modules of the form: <dir>/foo/bar.pxd - path = os.path.join(package_dir, module_filename) - if os.path.exists(path): - return path -- path = os.path.join(package_dir, module_name, -- package_filename) -+ -+ # matches modules of the form: <dir>/foo/bar/__init__.pxd -+ path = os.path.join(package_dir, module_name, package_filename) - if os.path.exists(path): - return path -+ -+ # search for namespaces second - PEP420 -+ for package_dir in namespace_dirs: -+ -+ # matches modules of the form: <dir>/foo/bar.pxd -+ path = os.path.join(package_dir, module_filename) -+ if os.path.exists(path): -+ return path -+ -+ # matches modules of the form: <dir>/foo/bar/__init__.pxd -+ path = os.path.join(package_dir, module_name, package_filename) -+ if os.path.exists(path): -+ return path -+ - return None - - -diff --git a/Cython/Utils.py b/Cython/Utils.py -index d59d67d78b..305ebf8412 100644 ---- a/Cython/Utils.py -+++ b/Cython/Utils.py -@@ -134,16 +134,21 @@ def find_root_package_dir(file_path): - else: - return dir - -+ - @cached_function --def check_package_dir(dir, package_names): -+def check_package_dir(dir_path, package_names): -+ namespace = True - for dirname in package_names: -- dir = os.path.join(dir, dirname) -- if not is_package_dir(dir): -- return None -- return dir -+ dir_path = os.path.join(dir_path, dirname) -+ has_init = contains_init(dir_path) -+ if not namespace and not has_init: -+ return None, False -+ elif has_init: -+ namespace = False -+ return dir_path, namespace - --@cached_function --def is_package_dir(dir_path): -+ -+def contains_init(dir_path): - for filename in ("__init__.py", - "__init__.pyc", - "__init__.pyx", -@@ -152,6 +157,13 @@ def is_package_dir(dir_path): - if path_exists(path): - return 1 - -+ -+@cached_function -+def is_package_dir(dir_path): -+ if contains_init(dir_path): -+ return 1 -+ -+ - @cached_function - def path_exists(path): - # try on the filesystem first -diff --git a/runtests.py b/runtests.py -index 91a0dd2570..7d04463846 100755 ---- a/runtests.py -+++ b/runtests.py -@@ -415,6 +415,7 @@ def get_openmp_compiler_flags(language): - 'run.special_methods_T561_py2' - ]), - (3,3) : (operator.lt, lambda x: x in ['build.package_compilation', -+ 'build.cythonize_pep420_namespace', - 'run.yield_from_py33', - 'pyximport.pyximport_namespace', - ]), -diff --git a/tests/build/cythonize_pep420_namespace.srctree b/tests/build/cythonize_pep420_namespace.srctree -new file mode 100644 -index 0000000000..6a031e4170 ---- /dev/null -+++ b/tests/build/cythonize_pep420_namespace.srctree -@@ -0,0 +1,44 @@ -+PYTHON setup.py build_ext --inplace -+PYTHON -c "import runner" -+ -+######## setup.py ######## -+ -+from Cython.Build.Dependencies import cythonize -+ -+from distutils.core import setup, Extension -+ -+setup( -+ ext_modules=cythonize([ -+ Extension("nsp.m1.a", ["nsp/m1/a.pyx"]), -+ Extension("nsp.m2.b", ["nsp/m2/b.pyx"]) -+ ]), -+) -+ -+######## nsp/m1/__init__.py ######## -+ -+######## nsp/m1/a.pyx ######## -+ -+cdef class A: -+ pass -+ -+######## nsp/m1/a.pxd ######## -+ -+cdef class A: -+ pass -+ -+######## nsp/m2/__init__.py ######## -+ -+######## nsp/m2/b.pyx ######## -+ -+from nsp.m1.a cimport A -+ -+cdef class B(A): -+ pass -+ -+######## runner.py ######## -+ -+from nsp.m1.a import A -+from nsp.m2.b import B -+ -+a = A() -+b = B() - -From fcd3e7bd1351a0964704f2921ae33b4b57250668 Mon Sep 17 00:00:00 2001 -From: Fedor Alekseev <feodor.alexeev@gmail.com> -Date: Mon, 9 Nov 2020 14:34:01 +0300 -Subject: [PATCH 2/3] Support namespace packages inside regular packages - ---- - Cython/Utils.py | 4 +--- - tests/build/cythonize_pep420_namespace.srctree | 17 ++++++++++++++++- - 2 files changed, 17 insertions(+), 4 deletions(-) - -diff --git a/Cython/Utils.py b/Cython/Utils.py -index 305ebf8412..f21d5cddba 100644 ---- a/Cython/Utils.py -+++ b/Cython/Utils.py -@@ -141,9 +141,7 @@ def check_package_dir(dir_path, package_names): - for dirname in package_names: - dir_path = os.path.join(dir_path, dirname) - has_init = contains_init(dir_path) -- if not namespace and not has_init: -- return None, False -- elif has_init: -+ if has_init: - namespace = False - return dir_path, namespace - -diff --git a/tests/build/cythonize_pep420_namespace.srctree b/tests/build/cythonize_pep420_namespace.srctree -index 6a031e4170..04013a3004 100644 ---- a/tests/build/cythonize_pep420_namespace.srctree -+++ b/tests/build/cythonize_pep420_namespace.srctree -@@ -10,7 +10,8 @@ from distutils.core import setup, Extension - setup( - ext_modules=cythonize([ - Extension("nsp.m1.a", ["nsp/m1/a.pyx"]), -- Extension("nsp.m2.b", ["nsp/m2/b.pyx"]) -+ Extension("nsp.m2.b", ["nsp/m2/b.pyx"]), -+ Extension("nsp.m3.c.d", ["nsp/m3/c/d.pyx"]) - ]), - ) - -@@ -31,14 +32,28 @@ cdef class A: - ######## nsp/m2/b.pyx ######## - - from nsp.m1.a cimport A -+from nsp.m3.c.d cimport D - - cdef class B(A): - pass - -+######## nsp/m3/__init__.py ######## -+ -+######## nsp/m3/c/d.pyx ######## -+ -+cdef class D: -+ pass -+ -+######## nsp/m3/c/d.pxd ######## -+ -+cdef class D: -+ pass -+ - ######## runner.py ######## - - from nsp.m1.a import A - from nsp.m2.b import B -+from nsp.m3.c.d import D - - a = A() - b = B() - -From 9d61b95a6a71a4c88a51ab8f30d5b3a8b93998b8 Mon Sep 17 00:00:00 2001 -From: scoder <stefan_ml@behnel.de> -Date: Sat, 14 Nov 2020 09:42:09 +0100 -Subject: [PATCH 3/3] Anticipate future changes. - ---- - tests/build/cythonize_pep420_namespace.srctree | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tests/build/cythonize_pep420_namespace.srctree b/tests/build/cythonize_pep420_namespace.srctree -index 04013a3004..99649376a3 100644 ---- a/tests/build/cythonize_pep420_namespace.srctree -+++ b/tests/build/cythonize_pep420_namespace.srctree -@@ -11,7 +11,7 @@ setup( - ext_modules=cythonize([ - Extension("nsp.m1.a", ["nsp/m1/a.pyx"]), - Extension("nsp.m2.b", ["nsp/m2/b.pyx"]), -- Extension("nsp.m3.c.d", ["nsp/m3/c/d.pyx"]) -+ Extension("nsp.m3.c.d", ["nsp/m3/c/d.pyx"]), - ]), - ) - diff --git a/build/pkgs/cython/patches/trashcan.patch b/build/pkgs/cython/patches/trashcan.patch deleted file mode 100644 index e1e88ebe465..00000000000 --- a/build/pkgs/cython/patches/trashcan.patch +++ /dev/null @@ -1,187 +0,0 @@ -See https://github.com/cython/cython/pull/2842 - -and https://github.com/cython/cython/pull/4475 - -commit c47c4ef735c4b7f1863b21bbe6f112b06c4aad05 -Author: Jeroen Demeyer <J.Demeyer@UGent.be> -Date: Thu Feb 14 10:02:41 2019 +0100 - - @cython.trashcan directive to enable the Python trashcan for deallocations - -diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py -index d5742de..27fcad6 100644 ---- a/Cython/Compiler/ModuleNode.py -+++ b/Cython/Compiler/ModuleNode.py -@@ -1426,6 +1426,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): - - is_final_type = scope.parent_type.is_final_type - needs_gc = scope.needs_gc() -+ needs_trashcan = scope.needs_trashcan() - - weakref_slot = scope.lookup_here("__weakref__") if not scope.is_closure_class_scope else None - if weakref_slot not in scope.var_entries: -@@ -1464,6 +1465,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): - # running this destructor. - code.putln("PyObject_GC_UnTrack(o);") - -+ if needs_trashcan: -+ code.globalstate.use_utility_code( -+ UtilityCode.load_cached("PyTrashcan", "ExtensionTypes.c")) -+ code.putln("__Pyx_TRASHCAN_BEGIN(o, %s)" % slot_func_cname) -+ - # call the user's __dealloc__ - self.generate_usr_dealloc_call(scope, code) - -@@ -1537,6 +1543,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): - code.putln("(*Py_TYPE(o)->tp_free)(o);") - if freelist_size: - code.putln("}") -+ -+ if needs_trashcan: -+ code.putln("__Pyx_TRASHCAN_END") -+ - code.putln( - "}") - -diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py -index d859c19..19d96f1 100644 ---- a/Cython/Compiler/Options.py -+++ b/Cython/Compiler/Options.py -@@ -313,6 +313,7 @@ directive_types = { - 'freelist': int, - 'c_string_type': one_of('bytes', 'bytearray', 'str', 'unicode'), - 'c_string_encoding': normalise_encoding_name, -+ 'trashcan': bool, - } - - for key, val in _directive_defaults.items(): -@@ -355,6 +356,7 @@ directive_scopes = { # defaults to available everywhere - 'np_pythran': ('module',), - 'fast_gil': ('module',), - 'iterable_coroutine': ('module', 'function'), -+ 'trashcan' : ('cclass',), - } - - -diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py -index 3b572d6..f200c5f 100644 ---- a/Cython/Compiler/PyrexTypes.py -+++ b/Cython/Compiler/PyrexTypes.py -@@ -1136,6 +1136,7 @@ class PyObjectType(PyrexType): - is_extern = False - is_subclassed = False - is_gc_simple = False -+ builtin_trashcan = False # builtin type using trashcan - - def __str__(self): - return "Python object" -@@ -1190,10 +1191,14 @@ class PyObjectType(PyrexType): - - - builtin_types_that_cannot_create_refcycles = set([ -- 'bool', 'int', 'long', 'float', 'complex', -+ 'object', 'bool', 'int', 'long', 'float', 'complex', - 'bytearray', 'bytes', 'unicode', 'str', 'basestring' - ]) - -+builtin_types_with_trashcan = set([ -+ 'dict', 'list', 'set', 'frozenset', 'tuple', 'type', -+]) -+ - - class BuiltinObjectType(PyObjectType): - # objstruct_cname string Name of PyObject struct -@@ -1218,6 +1223,7 @@ class BuiltinObjectType(PyObjectType): - self.typeptr_cname = "(&%s)" % cname - self.objstruct_cname = objstruct_cname - self.is_gc_simple = name in builtin_types_that_cannot_create_refcycles -+ self.builtin_trashcan = name in builtin_types_with_trashcan - if name == 'type': - # Special case the type type, as many C API calls (and other - # libraries) actually expect a PyTypeObject* for type arguments. -diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py -index f7443cb..d44484d 100644 ---- a/Cython/Compiler/Symtab.py -+++ b/Cython/Compiler/Symtab.py -@@ -2085,6 +2085,22 @@ class CClassScope(ClassScope): - return not self.parent_type.is_gc_simple - return False - -+ def needs_trashcan(self): -+ # If the trashcan directive is explicitly set to False, -+ # unconditionally disable the trashcan. -+ directive = self.directives.get('trashcan') -+ if directive is False: -+ return False -+ # If the directive is set to True and the class has Python-valued -+ # C attributes, then it should use the trashcan in tp_dealloc. -+ if directive and self.has_cyclic_pyobject_attrs: -+ return True -+ # Use the trashcan if the base class uses it -+ base_type = self.parent_type.base_type -+ if base_type and base_type.scope is not None: -+ return base_type.scope.needs_trashcan() -+ return self.parent_type.builtin_trashcan -+ - def needs_tp_clear(self): - """ - Do we need to generate an implementation for the tp_clear slot? Can -diff --git a/Cython/Utility/ExtensionTypes.c b/Cython/Utility/ExtensionTypes.c -index 50d0e21..ca2adbe 100644 ---- a/Cython/Utility/ExtensionTypes.c -+++ b/Cython/Utility/ExtensionTypes.c -@@ -74,6 +74,54 @@ static int __Pyx_PyType_Ready(PyTypeObject *t) { - return r; - } - -+/////////////// PyTrashcan.proto /////////////// -+ -+// These macros are taken from https://github.com/python/cpython/pull/11841 -+// Unlike the Py_TRASHCAN_SAFE_BEGIN/Py_TRASHCAN_SAFE_END macros, they -+// allow dealing correctly with subclasses. -+ -+// This requires CPython version >= 2.7.4 -+// (or >= 3.2.4 but we don't support such old Python 3 versions anyway) -+#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03080000 -+// https://github.com/python/cpython/pull/11841 merged so Cython reimplementation -+// is no longer necessary -+#define __Pyx_TRASHCAN_BEGIN Py_TRASHCAN_BEGIN -+#define __Pyx_TRASHCAN_END Py_TRASHCAN_END -+#elif CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02070400 -+#define __Pyx_TRASHCAN_BEGIN_CONDITION(op, cond) \ -+ do { \ -+ PyThreadState *_tstate = NULL; \ -+ // If "cond" is false, then _tstate remains NULL and the deallocator -+ // is run normally without involving the trashcan -+ if (cond) { \ -+ _tstate = PyThreadState_GET(); \ -+ if (_tstate->trash_delete_nesting >= PyTrash_UNWIND_LEVEL) { \ -+ // Store the object (to be deallocated later) and jump past -+ // Py_TRASHCAN_END, skipping the body of the deallocator -+ _PyTrash_thread_deposit_object((PyObject*)(op)); \ -+ break; \ -+ } \ -+ ++_tstate->trash_delete_nesting; \ -+ } -+ // The body of the deallocator is here. -+#define __Pyx_TRASHCAN_END \ -+ if (_tstate) { \ -+ --_tstate->trash_delete_nesting; \ -+ if (_tstate->trash_delete_later && _tstate->trash_delete_nesting <= 0) \ -+ _PyTrash_thread_destroy_chain(); \ -+ } \ -+ } while (0); -+ -+#define __Pyx_TRASHCAN_BEGIN(op, dealloc) __Pyx_TRASHCAN_BEGIN_CONDITION(op, \ -+ Py_TYPE(op)->tp_dealloc == (destructor)(dealloc)) -+ -+#else -+// The trashcan is a no-op on other Python implementations -+// or old CPython versions -+#define __Pyx_TRASHCAN_BEGIN(op, dealloc) -+#define __Pyx_TRASHCAN_END -+#endif -+ - /////////////// CallNextTpDealloc.proto /////////////// - - static void __Pyx_call_next_tp_dealloc(PyObject* obj, destructor current_tp_dealloc); diff --git a/build/pkgs/database_cubic_hecke/dependencies b/build/pkgs/database_cubic_hecke/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/database_cubic_hecke/dependencies +++ b/build/pkgs/database_cubic_hecke/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/database_knotinfo/checksums.ini b/build/pkgs/database_knotinfo/checksums.ini index 9b521522202..fe398cb7354 100644 --- a/build/pkgs/database_knotinfo/checksums.ini +++ b/build/pkgs/database_knotinfo/checksums.ini @@ -1,5 +1,5 @@ tarball=database_knotinfo-VERSION.tar.gz -sha1=16039d4e399efc78e4b1278527019f4bcdfdde13 -md5=3095993756f6b51d14c35adae5a75930 -cksum=2884062991 +sha1=1c6746a2742b5fb5c6a2803249dd6988d6ec1890 +md5=b2cd3295f179fbbde2a970ba7f0c3db4 +cksum=1079889953 upstream_url=https://pypi.io/packages/source/d/database_knotinfo/database_knotinfo-VERSION.tar.gz diff --git a/build/pkgs/database_knotinfo/dependencies b/build/pkgs/database_knotinfo/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/database_knotinfo/dependencies +++ b/build/pkgs/database_knotinfo/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/database_knotinfo/package-version.txt b/build/pkgs/database_knotinfo/package-version.txt index eef52011e7f..603f3a6d51a 100644 --- a/build/pkgs/database_knotinfo/package-version.txt +++ b/build/pkgs/database_knotinfo/package-version.txt @@ -1 +1 @@ -2022.7.1 +2023.6.1 diff --git a/build/pkgs/dateutil/dependencies b/build/pkgs/dateutil/dependencies index 7a972de985e..a90844872ae 100644 --- a/build/pkgs/dateutil/dependencies +++ b/build/pkgs/dateutil/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) six | $(PYTHON_TOOLCHAIN) + six | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/dateutil/distros/arch.txt b/build/pkgs/dateutil/distros/arch.txt new file mode 100644 index 00000000000..0f08daace31 --- /dev/null +++ b/build/pkgs/dateutil/distros/arch.txt @@ -0,0 +1 @@ +python-dateutil diff --git a/build/pkgs/dateutil/distros/debian.txt b/build/pkgs/dateutil/distros/debian.txt new file mode 100644 index 00000000000..2f46170765c --- /dev/null +++ b/build/pkgs/dateutil/distros/debian.txt @@ -0,0 +1 @@ +python3-dateutil diff --git a/build/pkgs/dateutil/distros/fedora.txt b/build/pkgs/dateutil/distros/fedora.txt new file mode 100644 index 00000000000..0f08daace31 --- /dev/null +++ b/build/pkgs/dateutil/distros/fedora.txt @@ -0,0 +1 @@ +python-dateutil diff --git a/build/pkgs/dateutil/distros/freebsd.txt b/build/pkgs/dateutil/distros/freebsd.txt new file mode 100644 index 00000000000..c336f5e0b1d --- /dev/null +++ b/build/pkgs/dateutil/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-dateutil diff --git a/build/pkgs/dateutil/distros/gentoo.txt b/build/pkgs/dateutil/distros/gentoo.txt new file mode 100644 index 00000000000..e129df768dc --- /dev/null +++ b/build/pkgs/dateutil/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/python-dateutil diff --git a/build/pkgs/dateutil/distros/opensuse.txt b/build/pkgs/dateutil/distros/opensuse.txt new file mode 100644 index 00000000000..ba37df671e5 --- /dev/null +++ b/build/pkgs/dateutil/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-python-dateutil diff --git a/build/pkgs/dateutil/install-requires.txt b/build/pkgs/dateutil/install-requires.txt index 0ae93da485e..face537605d 100644 --- a/build/pkgs/dateutil/install-requires.txt +++ b/build/pkgs/dateutil/install-requires.txt @@ -1 +1 @@ -dateutil >=2.8.1 +python-dateutil >=2.8.1 diff --git a/build/pkgs/dateutil/spkg-configure.m4 b/build/pkgs/dateutil/spkg-configure.m4 new file mode 100644 index 00000000000..fdcd1273975 --- /dev/null +++ b/build/pkgs/dateutil/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([dateutil], [SAGE_PYTHON_PACKAGE_CHECK([dateutil])]) diff --git a/build/pkgs/debugpy/dependencies b/build/pkgs/debugpy/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/debugpy/dependencies +++ b/build/pkgs/debugpy/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/debugpy/distros/gentoo.txt b/build/pkgs/debugpy/distros/gentoo.txt new file mode 100644 index 00000000000..8b797ce715f --- /dev/null +++ b/build/pkgs/debugpy/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/debugpy diff --git a/build/pkgs/debugpy/spkg-configure.m4 b/build/pkgs/debugpy/spkg-configure.m4 new file mode 100644 index 00000000000..db605ff03c8 --- /dev/null +++ b/build/pkgs/debugpy/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([debugpy], [SAGE_PYTHON_PACKAGE_CHECK([debugpy])]) diff --git a/build/pkgs/decorator/dependencies b/build/pkgs/decorator/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/decorator/dependencies +++ b/build/pkgs/decorator/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/decorator/distros/arch.txt b/build/pkgs/decorator/distros/arch.txt new file mode 100644 index 00000000000..079560412f1 --- /dev/null +++ b/build/pkgs/decorator/distros/arch.txt @@ -0,0 +1 @@ +python-decorator diff --git a/build/pkgs/decorator/distros/debian.txt b/build/pkgs/decorator/distros/debian.txt new file mode 100644 index 00000000000..46c478e1513 --- /dev/null +++ b/build/pkgs/decorator/distros/debian.txt @@ -0,0 +1 @@ +python3-decorator diff --git a/build/pkgs/decorator/distros/fedora.txt b/build/pkgs/decorator/distros/fedora.txt new file mode 100644 index 00000000000..079560412f1 --- /dev/null +++ b/build/pkgs/decorator/distros/fedora.txt @@ -0,0 +1 @@ +python-decorator diff --git a/build/pkgs/decorator/distros/gentoo.txt b/build/pkgs/decorator/distros/gentoo.txt new file mode 100644 index 00000000000..fea5a67ac9e --- /dev/null +++ b/build/pkgs/decorator/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/decorator diff --git a/build/pkgs/decorator/distros/opensuse.txt b/build/pkgs/decorator/distros/opensuse.txt index 46c478e1513..4b9085da296 100644 --- a/build/pkgs/decorator/distros/opensuse.txt +++ b/build/pkgs/decorator/distros/opensuse.txt @@ -1 +1 @@ -python3-decorator +python3${PYTHON_MINOR}-decorator diff --git a/build/pkgs/decorator/spkg-configure.m4 b/build/pkgs/decorator/spkg-configure.m4 new file mode 100644 index 00000000000..e062778d6db --- /dev/null +++ b/build/pkgs/decorator/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([decorator], [SAGE_PYTHON_PACKAGE_CHECK([decorator])]) diff --git a/build/pkgs/defusedxml/dependencies b/build/pkgs/defusedxml/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/defusedxml/dependencies +++ b/build/pkgs/defusedxml/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/defusedxml/distros/gentoo.txt b/build/pkgs/defusedxml/distros/gentoo.txt new file mode 100644 index 00000000000..2804214449e --- /dev/null +++ b/build/pkgs/defusedxml/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/defusedxml diff --git a/build/pkgs/defusedxml/spkg-configure.m4 b/build/pkgs/defusedxml/spkg-configure.m4 new file mode 100644 index 00000000000..e02f34524ce --- /dev/null +++ b/build/pkgs/defusedxml/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([defusedxml], [SAGE_PYTHON_PACKAGE_CHECK([defusedxml])]) diff --git a/build/pkgs/deprecation/dependencies b/build/pkgs/deprecation/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/deprecation/dependencies +++ b/build/pkgs/deprecation/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/distlib/checksums.ini b/build/pkgs/distlib/checksums.ini index 1d749b2f9a7..be255ceca11 100644 --- a/build/pkgs/distlib/checksums.ini +++ b/build/pkgs/distlib/checksums.ini @@ -1,5 +1,5 @@ tarball=distlib-VERSION.tar.gz -sha1=3a86d49dc17320325004564d0dc86afa808624bc -md5=f60ba4e3f8e76c214d3d00b2227a16f7 -cksum=1543870863 +sha1=5c99f8bd1cc58c387a8d22afa632f81c6fec9993 +md5=44e4357e35bbd77fdf1b81e174e34f20 +cksum=3690000669 upstream_url=https://pypi.io/packages/source/d/distlib/distlib-VERSION.tar.gz diff --git a/build/pkgs/distlib/dependencies b/build/pkgs/distlib/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/distlib/dependencies +++ b/build/pkgs/distlib/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/distlib/package-version.txt b/build/pkgs/distlib/package-version.txt index 449d7e73a96..0f82685331e 100644 --- a/build/pkgs/distlib/package-version.txt +++ b/build/pkgs/distlib/package-version.txt @@ -1 +1 @@ -0.3.6 +0.3.7 diff --git a/build/pkgs/docutils/dependencies b/build/pkgs/docutils/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/docutils/dependencies +++ b/build/pkgs/docutils/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/docutils/distros/gentoo.txt b/build/pkgs/docutils/distros/gentoo.txt new file mode 100644 index 00000000000..fe4a4524cbb --- /dev/null +++ b/build/pkgs/docutils/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/docutils diff --git a/build/pkgs/docutils/distros/opensuse.txt b/build/pkgs/docutils/distros/opensuse.txt index a4bb792a5a4..a7fcdac14ef 100644 --- a/build/pkgs/docutils/distros/opensuse.txt +++ b/build/pkgs/docutils/distros/opensuse.txt @@ -1 +1 @@ -python3-docutils +python3${PYTHON_MINOR}-docutils diff --git a/build/pkgs/docutils/spkg-configure.m4 b/build/pkgs/docutils/spkg-configure.m4 new file mode 100644 index 00000000000..3584e4513c6 --- /dev/null +++ b/build/pkgs/docutils/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([docutils], [SAGE_PYTHON_PACKAGE_CHECK([docutils])]) diff --git a/build/pkgs/dot2tex/dependencies b/build/pkgs/dot2tex/dependencies index c1925d16b73..75d8c64edb5 100644 --- a/build/pkgs/dot2tex/dependencies +++ b/build/pkgs/dot2tex/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) pyparsing + | $(PYTHON_TOOLCHAIN) pyparsing $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/e_antic/checksums.ini b/build/pkgs/e_antic/checksums.ini index 82757976c54..d24ae72e6f4 100644 --- a/build/pkgs/e_antic/checksums.ini +++ b/build/pkgs/e_antic/checksums.ini @@ -1,5 +1,5 @@ tarball=e-antic-VERSION.tar.gz -sha1=0fa6ba4a1f13e881f369f9185fe42c7f4bc10a18 -md5=5d77933d78dd08109b0a2c8403892eb6 -cksum=3304746077 +sha1=4f551cf2ab58201fb2137ae994cb670c6fa8b154 +md5=6c6f38408994f7d79f814bbad8183fcb +cksum=2487959662 upstream_url=https://github.com/flatsurf/e-antic/releases/download/VERSION/e-antic-VERSION.tar.gz diff --git a/build/pkgs/e_antic/package-version.txt b/build/pkgs/e_antic/package-version.txt index 6085e946503..f0bb29e7638 100644 --- a/build/pkgs/e_antic/package-version.txt +++ b/build/pkgs/e_antic/package-version.txt @@ -1 +1 @@ -1.2.1 +1.3.0 diff --git a/build/pkgs/ecl/dependencies_order_only b/build/pkgs/ecl/dependencies_order_only new file mode 100644 index 00000000000..55021245387 --- /dev/null +++ b/build/pkgs/ecl/dependencies_order_only @@ -0,0 +1 @@ +info diff --git a/build/pkgs/ecl/spkg-configure.m4 b/build/pkgs/ecl/spkg-configure.m4 index ae1e0ac5e1a..7dbcfa6377b 100644 --- a/build/pkgs/ecl/spkg-configure.m4 +++ b/build/pkgs/ecl/spkg-configure.m4 @@ -35,10 +35,7 @@ SAGE_SPKG_CONFIGURE([ecl], [ AC_SUBST(SAGE_ECL_CONFIG, [$ECL_CONFIG]) fi - # Maxima cannot yet be provided by the system, so we always use + # Kenzo cannot yet be provided by the system, so we always use # the SAGE_LOCAL path for now. - AC_SUBST(SAGE_MAXIMA_FAS, ['${prefix}'/lib/ecl/maxima.fas]) - - # Likewise for the optional Kenzo SPKG AC_SUBST(SAGE_KENZO_FAS, ['${prefix}'/lib/ecl/kenzo.fas]) ]) diff --git a/build/pkgs/ecl/spkg-install.in b/build/pkgs/ecl/spkg-install.in index ee1667aec16..72083337942 100644 --- a/build/pkgs/ecl/spkg-install.in +++ b/build/pkgs/ecl/spkg-install.in @@ -31,18 +31,6 @@ cp "$SAGE_ROOT"/config/config.* src if [ x"$SAGE_SPKG_INSTALL_DOCS" != xyes ] ; then ECL_CONFIGURE="$ECL_CONFIGURE --enable-manual=no" -else - # ECL 2020 needs modern makeinfo - command -v texi2any >/dev/null 2>&1 - if [ $? -ne 0 ]; then # texi2any not found -> makeinfo too old, if present - ECL_CONFIGURE="$ECL_CONFIGURE --enable-manual=no" - else - if makeinfo -c foo 2>&1 | grep -q invalid; then - # makeinfo found but does not support all options that ecl - # likes to use - ECL_CONFIGURE="$ECL_CONFIGURE --enable-manual=no" - fi - fi fi sdh_configure $SAGE_CONFIGURE_GMP \ diff --git a/build/pkgs/eclib/checksums.ini b/build/pkgs/eclib/checksums.ini index 8154d34c1ba..266e6bfac1c 100644 --- a/build/pkgs/eclib/checksums.ini +++ b/build/pkgs/eclib/checksums.ini @@ -1,5 +1,5 @@ tarball=eclib-VERSION.tar.bz2 -sha1=2e86bc02e43edfb43473ecb1ae8e7b67cfe87e3c -md5=bb6fc7cb57c01c45a033276e1a94028f -cksum=3974905173 -upstream_url=https://github.com/JohnCremona/eclib/releases/download/VERSION/eclib-VERSION.tar.bz2 +sha1=bd49acf96c4e7246c8ca3e5d188ae1b03a3aeff3 +md5=42721f2f1343c49dc774763a57a85ca6 +cksum=3624641360 +upstream_url=https://github.com/JohnCremona/eclib/releases/download/vVERSION/eclib-VERSION.tar.bz2 diff --git a/build/pkgs/eclib/package-version.txt b/build/pkgs/eclib/package-version.txt index 774b03215ac..b5f339e560b 100644 --- a/build/pkgs/eclib/package-version.txt +++ b/build/pkgs/eclib/package-version.txt @@ -1 +1 @@ -20220621 +20230424 diff --git a/build/pkgs/eclib/spkg-configure.m4 b/build/pkgs/eclib/spkg-configure.m4 index 471f40e0aee..c98781201cc 100644 --- a/build/pkgs/eclib/spkg-configure.m4 +++ b/build/pkgs/eclib/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([eclib], [ SAGE_SPKG_DEPCHECK([ntl pari flint], [ dnl Trac #31443, #34029: use existing eclib only if the version reported by pkg-config is correct - m4_pushdef([SAGE_ECLIB_VER],["20220621"]) + m4_pushdef([SAGE_ECLIB_VER],["20230424"]) PKG_CHECK_MODULES([ECLIB], [eclib = SAGE_ECLIB_VER], [ AC_CACHE_CHECK([for mwrank version == SAGE_ECLIB_VER], [ac_cv_path_MWRANK], [ AC_PATH_PROGS_FEATURE_CHECK([MWRANK], [mwrank], [ diff --git a/build/pkgs/ecm/spkg-install.in b/build/pkgs/ecm/spkg-install.in index b60230f368a..ce58949c8ee 100644 --- a/build/pkgs/ecm/spkg-install.in +++ b/build/pkgs/ecm/spkg-install.in @@ -189,6 +189,12 @@ export CFLAGS # Not exported by 'sage-env'. LDFLAGS are exported above if # necessary. We currently don't set (or modify) any other # environment variables, so don't have to export them here. +# Workaround for build failure with Xcode 15, https://github.com/sagemath/sage/issues/36342 +case "$UNAME" in + Darwin*) + export gmp_cv_asm_underscore=yes + ;; +esac ############################################################################### # Now configure ECM: diff --git a/build/pkgs/ecos_python/SPKG.rst b/build/pkgs/ecos_python/SPKG.rst new file mode 100644 index 00000000000..5c7bb0d9a22 --- /dev/null +++ b/build/pkgs/ecos_python/SPKG.rst @@ -0,0 +1,20 @@ +ecos_python: Embedded Cone Solver (Python wrapper) +================================================== + +Description +----------- + +This is the Python package for ECOS: Embedded Cone Solver. + +It vendors ECOS. + +License +------- + +GPLv3 + +Upstream Contact +---------------- + +https://pypi.org/project/ecos/ + diff --git a/build/pkgs/ecos_python/checksums.ini b/build/pkgs/ecos_python/checksums.ini new file mode 100644 index 00000000000..dc6d7b9a6f1 --- /dev/null +++ b/build/pkgs/ecos_python/checksums.ini @@ -0,0 +1,5 @@ +tarball=ecos-VERSION.tar.gz +sha1=7afce63aec44522052e05fa2e1c82e12fe20fd45 +md5=a76939695aa07f8ab2f01a532732f348 +cksum=2810151369 +upstream_url=https://pypi.io/packages/source/e/ecos/ecos-VERSION.tar.gz diff --git a/build/pkgs/ecos_python/dependencies b/build/pkgs/ecos_python/dependencies new file mode 100644 index 00000000000..aaf3b261709 --- /dev/null +++ b/build/pkgs/ecos_python/dependencies @@ -0,0 +1,4 @@ + numpy scipy | $(PYTHON_TOOLCHAIN) $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/ecos_python/distros/conda.txt b/build/pkgs/ecos_python/distros/conda.txt new file mode 100644 index 00000000000..d75c5988ca8 --- /dev/null +++ b/build/pkgs/ecos_python/distros/conda.txt @@ -0,0 +1 @@ +ecos diff --git a/build/pkgs/ecos_python/install-requires.txt b/build/pkgs/ecos_python/install-requires.txt new file mode 100644 index 00000000000..d75c5988ca8 --- /dev/null +++ b/build/pkgs/ecos_python/install-requires.txt @@ -0,0 +1 @@ +ecos diff --git a/build/pkgs/ecos_python/package-version.txt b/build/pkgs/ecos_python/package-version.txt new file mode 100644 index 00000000000..280a1e3368b --- /dev/null +++ b/build/pkgs/ecos_python/package-version.txt @@ -0,0 +1 @@ +2.0.12 diff --git a/build/pkgs/ecos_python/spkg-install.in b/build/pkgs/ecos_python/spkg-install.in new file mode 100644 index 00000000000..a143d1eff96 --- /dev/null +++ b/build/pkgs/ecos_python/spkg-install.in @@ -0,0 +1,3 @@ +cd src +# --no-build-isolation to ignore the numpy version pin in pyproject.toml +sdh_pip_install --no-build-isolation . diff --git a/build/pkgs/ecos_python/type b/build/pkgs/ecos_python/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/ecos_python/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/editables/checksums.ini b/build/pkgs/editables/checksums.ini index 6a0618183b7..52c7fa0b03b 100644 --- a/build/pkgs/editables/checksums.ini +++ b/build/pkgs/editables/checksums.ini @@ -1,5 +1,5 @@ tarball=editables-VERSION.tar.gz -sha1=a99e0ba3d75e4f439b9742e65cbff24e0b8ce80e -md5=e91709fbb0ef586cb7b785042068ab67 -cksum=2338248945 +sha1=90efed858e78bf6276d1a5959ec6692e11a6bce9 +md5=520de8c3a9dc5dfb2b365d104541c9de +cksum=3074203672 upstream_url=https://pypi.io/packages/source/e/editables/editables-VERSION.tar.gz diff --git a/build/pkgs/editables/dependencies b/build/pkgs/editables/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/editables/dependencies +++ b/build/pkgs/editables/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/editables/distros/gentoo.txt b/build/pkgs/editables/distros/gentoo.txt new file mode 100644 index 00000000000..a7759b55c3f --- /dev/null +++ b/build/pkgs/editables/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/editables diff --git a/build/pkgs/editables/package-version.txt b/build/pkgs/editables/package-version.txt index be586341736..2eb3c4fe4ee 100644 --- a/build/pkgs/editables/package-version.txt +++ b/build/pkgs/editables/package-version.txt @@ -1 +1 @@ -0.3 +0.5 diff --git a/build/pkgs/editables/spkg-configure.m4 b/build/pkgs/editables/spkg-configure.m4 new file mode 100644 index 00000000000..66a93c4165b --- /dev/null +++ b/build/pkgs/editables/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([editables], [SAGE_PYTHON_PACKAGE_CHECK([editables])]) diff --git a/build/pkgs/elliptic_curves/dependencies b/build/pkgs/elliptic_curves/dependencies index 6b134137610..3518086ab84 100644 --- a/build/pkgs/elliptic_curves/dependencies +++ b/build/pkgs/elliptic_curves/dependencies @@ -1,4 +1,4 @@ -| $(PYTHON) +| $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/entrypoints/dependencies b/build/pkgs/entrypoints/dependencies index 902a5feed13..4fedbe70cd1 100644 --- a/build/pkgs/entrypoints/dependencies +++ b/build/pkgs/entrypoints/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) flit_core tomli + | $(PYTHON_TOOLCHAIN) flit_core tomli $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/entrypoints/distros/gentoo.txt b/build/pkgs/entrypoints/distros/gentoo.txt new file mode 100644 index 00000000000..684ddd036ee --- /dev/null +++ b/build/pkgs/entrypoints/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/entrypoints diff --git a/build/pkgs/entrypoints/spkg-configure.m4 b/build/pkgs/entrypoints/spkg-configure.m4 new file mode 100644 index 00000000000..caed658b69a --- /dev/null +++ b/build/pkgs/entrypoints/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([entrypoints], [SAGE_PYTHON_PACKAGE_CHECK([entrypoints])]) diff --git a/build/pkgs/executing/dependencies b/build/pkgs/executing/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/executing/dependencies +++ b/build/pkgs/executing/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/executing/distros/gentoo.txt b/build/pkgs/executing/distros/gentoo.txt new file mode 100644 index 00000000000..c2b60c085b9 --- /dev/null +++ b/build/pkgs/executing/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/executing diff --git a/build/pkgs/executing/spkg-configure.m4 b/build/pkgs/executing/spkg-configure.m4 new file mode 100644 index 00000000000..fdf2735ef0a --- /dev/null +++ b/build/pkgs/executing/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([executing], [SAGE_PYTHON_PACKAGE_CHECK([executing])]) diff --git a/build/pkgs/fastjsonschema/checksums.ini b/build/pkgs/fastjsonschema/checksums.ini index 9b6be281643..3df871d077a 100644 --- a/build/pkgs/fastjsonschema/checksums.ini +++ b/build/pkgs/fastjsonschema/checksums.ini @@ -1,5 +1,5 @@ tarball=fastjsonschema-VERSION.tar.gz -sha1=a6c53c1eed4f0fbb9c7eaf0fc21fc2c0be85bcd8 -md5=d7d76db7518e64b53a13a7a2315a1671 -cksum=1205433737 +sha1=eab76262783dd81303e2b1da0914a1d5a7f388aa +md5=4dd3d7946af566fc32e30f0768cddae3 +cksum=2794560071 upstream_url=https://pypi.io/packages/source/f/fastjsonschema/fastjsonschema-VERSION.tar.gz diff --git a/build/pkgs/fastjsonschema/dependencies b/build/pkgs/fastjsonschema/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/fastjsonschema/dependencies +++ b/build/pkgs/fastjsonschema/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/fastjsonschema/package-version.txt b/build/pkgs/fastjsonschema/package-version.txt index 43c85e79255..cf8690732fe 100644 --- a/build/pkgs/fastjsonschema/package-version.txt +++ b/build/pkgs/fastjsonschema/package-version.txt @@ -1 +1 @@ -2.16.2 +2.18.0 diff --git a/build/pkgs/filelock/checksums.ini b/build/pkgs/filelock/checksums.ini index 48a18055930..0d412bb2ca3 100644 --- a/build/pkgs/filelock/checksums.ini +++ b/build/pkgs/filelock/checksums.ini @@ -1,5 +1,5 @@ -tarball=filelock-VERSION.tar.gz -sha1=1de304add05b7e3e8874aa9f86202204f8042e30 -md5=9bd8d33d5d7dc95012981ccbfb2d2a0f -cksum=2335245752 -upstream_url=https://pypi.io/packages/source/f/filelock/filelock-VERSION.tar.gz +tarball=filelock-VERSION-py3-none-any.whl +sha1=74f5368865bf05ddc5b69949e4547ad25c078fc1 +md5=63b0f117cb65ef531ffafb566170661e +cksum=1046951951 +upstream_url=https://pypi.io/packages/py3/f/filelock/filelock-VERSION-py3-none-any.whl diff --git a/build/pkgs/filelock/dependencies b/build/pkgs/filelock/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/filelock/dependencies +++ b/build/pkgs/filelock/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/filelock/package-version.txt b/build/pkgs/filelock/package-version.txt index 19811903a7f..871f80a34be 100644 --- a/build/pkgs/filelock/package-version.txt +++ b/build/pkgs/filelock/package-version.txt @@ -1 +1 @@ -3.8.0 +3.12.3 diff --git a/build/pkgs/flintqs/SPKG.rst b/build/pkgs/flintqs/SPKG.rst deleted file mode 100644 index 28e0bed9329..00000000000 --- a/build/pkgs/flintqs/SPKG.rst +++ /dev/null @@ -1,14 +0,0 @@ -flintqs: Multi-polynomial quadratic sieve for integer factorization -=================================================================== - -Description ------------ - -This is William Hart's GPL'd highly optimized multi-polynomial quadratic -sieve for integer factorization: - - http://www.friedspace.com/QS/ - -See also http://www.maths.warwick.ac.uk/~masfaw/preprint.html - -See also the repository: https://github.com/sagemath/FlintQS diff --git a/build/pkgs/flintqs/checksums.ini b/build/pkgs/flintqs/checksums.ini deleted file mode 100644 index 56f20b4607c..00000000000 --- a/build/pkgs/flintqs/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=flintqs-VERSION.tar.bz2 -sha1=9b89246517dae1e1dbbb051323bf9d19da8f99d2 -md5=3a285f1eef304602247ddd8cbc3412df -cksum=2363348369 diff --git a/build/pkgs/flintqs/dependencies b/build/pkgs/flintqs/dependencies deleted file mode 100644 index 42dc0e9c107..00000000000 --- a/build/pkgs/flintqs/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -$(MP_LIBRARY) - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/flintqs/distros/arch.txt b/build/pkgs/flintqs/distros/arch.txt deleted file mode 100644 index 87de35f2830..00000000000 --- a/build/pkgs/flintqs/distros/arch.txt +++ /dev/null @@ -1 +0,0 @@ -flintqs diff --git a/build/pkgs/flintqs/distros/conda.txt b/build/pkgs/flintqs/distros/conda.txt deleted file mode 100644 index 87de35f2830..00000000000 --- a/build/pkgs/flintqs/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -flintqs diff --git a/build/pkgs/flintqs/distros/debian.txt b/build/pkgs/flintqs/distros/debian.txt deleted file mode 100644 index 87de35f2830..00000000000 --- a/build/pkgs/flintqs/distros/debian.txt +++ /dev/null @@ -1 +0,0 @@ -flintqs diff --git a/build/pkgs/flintqs/distros/freebsd.txt b/build/pkgs/flintqs/distros/freebsd.txt deleted file mode 100644 index fbb4a5350ad..00000000000 --- a/build/pkgs/flintqs/distros/freebsd.txt +++ /dev/null @@ -1 +0,0 @@ -math/flintqs diff --git a/build/pkgs/flintqs/distros/gentoo.txt b/build/pkgs/flintqs/distros/gentoo.txt deleted file mode 100644 index 2b06251e947..00000000000 --- a/build/pkgs/flintqs/distros/gentoo.txt +++ /dev/null @@ -1 +0,0 @@ -sci-mathematics/flintqs diff --git a/build/pkgs/flintqs/distros/nix.txt b/build/pkgs/flintqs/distros/nix.txt deleted file mode 100644 index 87de35f2830..00000000000 --- a/build/pkgs/flintqs/distros/nix.txt +++ /dev/null @@ -1 +0,0 @@ -flintqs diff --git a/build/pkgs/flintqs/distros/repology.txt b/build/pkgs/flintqs/distros/repology.txt deleted file mode 100644 index 87de35f2830..00000000000 --- a/build/pkgs/flintqs/distros/repology.txt +++ /dev/null @@ -1 +0,0 @@ -flintqs diff --git a/build/pkgs/flintqs/distros/void.txt b/build/pkgs/flintqs/distros/void.txt deleted file mode 100644 index dcc1f9f725f..00000000000 --- a/build/pkgs/flintqs/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -FlintQS diff --git a/build/pkgs/flintqs/package-version.txt b/build/pkgs/flintqs/package-version.txt deleted file mode 100644 index f9c24f5d4ec..00000000000 --- a/build/pkgs/flintqs/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -1.0.p0 diff --git a/build/pkgs/flintqs/spkg-configure.m4 b/build/pkgs/flintqs/spkg-configure.m4 deleted file mode 100644 index 8b50a817dee..00000000000 --- a/build/pkgs/flintqs/spkg-configure.m4 +++ /dev/null @@ -1,17 +0,0 @@ -SAGE_SPKG_CONFIGURE([flintqs], [ - # The QuadraticSieve program is the only interface to FlintQS that - # sagelib uses. As a result, we don't need to call SAGE_SPKG_DEPCHECK - # here because there's no possibility for a library conflict. - AC_CHECK_PROG(HAVE_QUADRATICSIEVE, QuadraticSieve, yes, no) - - # If we try to just do the obvious thing and swap the return value - # of AC_CHECK_PROG, then ./configure outputs - # - # checking for QuadraticSieve... no - # - # when QuadraticSieve is found... which is not great. - # - AS_IF([test "x$HAVE_QUADRATICSIEVE" = "xyes"], - [sage_spkg_install_flintqs=no], - [sage_spkg_install_flintqs=yes]) -]) diff --git a/build/pkgs/flintqs/spkg-install.in b/build/pkgs/flintqs/spkg-install.in deleted file mode 100644 index fefc1215b37..00000000000 --- a/build/pkgs/flintqs/spkg-install.in +++ /dev/null @@ -1,7 +0,0 @@ -cd src - -export CXXFLAGS="-fomit-frame-pointer -O3 -Wno-sign-compare -Wno-write-strings -I$SAGE_LOCAL/include $CXXFLAGS" - -sdh_configure -sdh_make -sdh_make_install diff --git a/build/pkgs/flit_core/dependencies b/build/pkgs/flit_core/dependencies index 93c460228b4..644ad35f773 100644 --- a/build/pkgs/flit_core/dependencies +++ b/build/pkgs/flit_core/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | pip + | pip $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/flit_core/distros/gentoo.txt b/build/pkgs/flit_core/distros/gentoo.txt new file mode 100644 index 00000000000..fe6bea92362 --- /dev/null +++ b/build/pkgs/flit_core/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/flit_core diff --git a/build/pkgs/flit_core/install-requires.txt b/build/pkgs/flit_core/install-requires.txt index 14ccfd92035..88b912bf11a 100644 --- a/build/pkgs/flit_core/install-requires.txt +++ b/build/pkgs/flit_core/install-requires.txt @@ -1 +1 @@ -flit-core +flit-core >= 3.7.1 diff --git a/build/pkgs/flit_core/spkg-configure.m4 b/build/pkgs/flit_core/spkg-configure.m4 new file mode 100644 index 00000000000..ee67557024f --- /dev/null +++ b/build/pkgs/flit_core/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([flit_core], [SAGE_PYTHON_PACKAGE_CHECK([flit_core])]) diff --git a/build/pkgs/fonttools/dependencies b/build/pkgs/fonttools/dependencies index 9c736669d9a..909380550a2 100644 --- a/build/pkgs/fonttools/dependencies +++ b/build/pkgs/fonttools/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) cython + | $(PYTHON_TOOLCHAIN) cython $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/fonttools/distros/gentoo.txt b/build/pkgs/fonttools/distros/gentoo.txt new file mode 100644 index 00000000000..172476e3166 --- /dev/null +++ b/build/pkgs/fonttools/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/fonttools diff --git a/build/pkgs/fonttools/spkg-configure.m4 b/build/pkgs/fonttools/spkg-configure.m4 new file mode 100644 index 00000000000..93c1477cc3c --- /dev/null +++ b/build/pkgs/fonttools/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([fonttools], [SAGE_PYTHON_PACKAGE_CHECK([fonttools])]) diff --git a/build/pkgs/fpylll/dependencies b/build/pkgs/fpylll/dependencies index 4b4fb1b44fb..4837249bcfa 100644 --- a/build/pkgs/fpylll/dependencies +++ b/build/pkgs/fpylll/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cython cysignals numpy fplll + cython cysignals numpy fplll | $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/fpylll/patches/cython3-legacy.patch b/build/pkgs/fpylll/patches/cython3-legacy.patch new file mode 100644 index 00000000000..808c14e9c1b --- /dev/null +++ b/build/pkgs/fpylll/patches/cython3-legacy.patch @@ -0,0 +1,37 @@ +commit b6e12c2b0648e84b26dcf0aac507a5b4d9dde301 +Author: Gonzalo Tornarรญa <tornaria@cmat.edu.uy> +Date: Wed Jul 19 20:38:01 2023 -0300 + + cython3 support using legacy directives + +diff --git a/setup.py b/setup.py +index 274836f..8fc5af5 100755 +--- a/setup.py ++++ b/setup.py +@@ -123,7 +123,12 @@ class build_ext(_build_ext, object): + self.extensions, + include_path=["src"], + build_dir=self.cythonize_dir, +- compiler_directives={"binding": True, "embedsignature": True, "language_level": 2}, ++ compiler_directives={ ++ "binding": True, ++ "embedsignature": True, ++ "language_level": 2, ++ "legacy_implicit_noexcept": True, ++ }, + ) + super(build_ext, self).run() + +diff --git a/src/fpylll/fplll/enumeration_callback_helper.h b/src/fpylll/fplll/enumeration_callback_helper.h +index c099430..706162f 100644 +--- a/src/fpylll/fplll/enumeration_callback_helper.h ++++ b/src/fpylll/fplll/enumeration_callback_helper.h +@@ -5,7 +5,7 @@ + #include <Python.h> + #include <fplll/fplll.h> + +-extern "C" { ++extern "C++" { + bool evaluator_callback_call_obj(PyObject *obj, int n, double *new_sol_coord); + } + diff --git a/build/pkgs/furo/dependencies b/build/pkgs/furo/dependencies index fec067b2058..07434099dee 100644 --- a/build/pkgs/furo/dependencies +++ b/build/pkgs/furo/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) beautifulsoup4 sphinx pygments sphinx_basic_ng | $(PYTHON_TOOLCHAIN) + beautifulsoup4 sphinx pygments sphinx_basic_ng | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/furo/distros/arch.txt b/build/pkgs/furo/distros/arch.txt new file mode 100644 index 00000000000..8cd8d580864 --- /dev/null +++ b/build/pkgs/furo/distros/arch.txt @@ -0,0 +1 @@ +python-sphinx-furo diff --git a/build/pkgs/furo/distros/debian.txt b/build/pkgs/furo/distros/debian.txt new file mode 100644 index 00000000000..a95ae18b4f9 --- /dev/null +++ b/build/pkgs/furo/distros/debian.txt @@ -0,0 +1 @@ +furo diff --git a/build/pkgs/furo/distros/fedora.txt b/build/pkgs/furo/distros/fedora.txt new file mode 100644 index 00000000000..d274c983622 --- /dev/null +++ b/build/pkgs/furo/distros/fedora.txt @@ -0,0 +1 @@ +python-furo diff --git a/build/pkgs/furo/distros/freebsd.txt b/build/pkgs/furo/distros/freebsd.txt new file mode 100644 index 00000000000..389d717bad0 --- /dev/null +++ b/build/pkgs/furo/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-furo diff --git a/build/pkgs/furo/distros/gentoo.txt b/build/pkgs/furo/distros/gentoo.txt new file mode 100644 index 00000000000..e823e710d71 --- /dev/null +++ b/build/pkgs/furo/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/furo diff --git a/build/pkgs/furo/spkg-configure.m4 b/build/pkgs/furo/spkg-configure.m4 new file mode 100644 index 00000000000..b1a92a7a70e --- /dev/null +++ b/build/pkgs/furo/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([furo], [ + SAGE_PYTHON_PACKAGE_CHECK([furo]) +]) diff --git a/build/pkgs/gambit/dependencies b/build/pkgs/gambit/dependencies index 1f00cbf5321..e026bfaacf9 100644 --- a/build/pkgs/gambit/dependencies +++ b/build/pkgs/gambit/dependencies @@ -1,4 +1,4 @@ -cython | $(PYTHON_TOOLCHAIN) +cython | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/gap/checksums.ini b/build/pkgs/gap/checksums.ini index 066e943308a..b0ea8ba8818 100644 --- a/build/pkgs/gap/checksums.ini +++ b/build/pkgs/gap/checksums.ini @@ -1,5 +1,5 @@ tarball=gap-VERSION.tar.gz -sha1=4ecdd281b8f430282fb9b12690b06e0a26abde10 -md5=85dc9e459d5b6c66fcad9f468afd3e3e -cksum=1351843158 +sha1=a6e36f3f874a2c46f51561402634497eab705cca +md5=c5cd9f272f2703d7a3649ad7193b2d90 +cksum=2760477284 upstream_url=https://github.com/gap-system/gap/releases/download/vVERSION/gap-VERSION.tar.gz diff --git a/build/pkgs/gap/distros/conda.txt b/build/pkgs/gap/distros/conda.txt index 401c67cba31..e1d9958012d 100644 --- a/build/pkgs/gap/distros/conda.txt +++ b/build/pkgs/gap/distros/conda.txt @@ -1 +1 @@ -gap-defaults +gap-defaults>=4.12.2 diff --git a/build/pkgs/gap/package-version.txt b/build/pkgs/gap/package-version.txt index d782fca8f64..f1cd7de1de5 100644 --- a/build/pkgs/gap/package-version.txt +++ b/build/pkgs/gap/package-version.txt @@ -1 +1 @@ -4.11.1 +4.12.2 diff --git a/build/pkgs/gap/patches/atlasrep-dont_use_network_by_default.patch b/build/pkgs/gap/patches/atlasrep-dont_use_network_by_default.patch new file mode 100644 index 00000000000..1a6be215091 --- /dev/null +++ b/build/pkgs/gap/patches/atlasrep-dont_use_network_by_default.patch @@ -0,0 +1,11 @@ +--- a/pkg/atlasrep/gap/userpref.g 2022-09-06 17:41:17.000000000 -0300 ++++ b/pkg/atlasrep/gap/userpref.g 2022-10-29 07:46:48.580833277 -0300 +@@ -46,7 +46,7 @@ + this information depends on the value of the preference at the time \ + when the AtlasRep package and its data extensions get loaded." + ], +- default:= true, ++ default:= false, + values:= [ true, false ], + multi:= false, + package:= "AtlasRep", diff --git a/build/pkgs/gap/spkg-check.in b/build/pkgs/gap/spkg-check.in index d9791d33293..d2fccda6e04 100644 --- a/build/pkgs/gap/spkg-check.in +++ b/build/pkgs/gap/spkg-check.in @@ -3,6 +3,13 @@ cd src # #28728: Fix test failure in tst/testinstall/strings.tst export LC_CTYPE=en_US.UTF-8 +# #34391: in GAP 4.12 some packages need GAP package io +# to let tests run, otherwise this hangs. Thus we install io here. +cd pkg/io +./configure --with-gaproot=../.. +make +cd ../.. + make testinstall if [[ $? -ne 0 ]]; then exit 1 diff --git a/build/pkgs/gap/spkg-install.in b/build/pkgs/gap/spkg-install.in index 30320027274..47a7a8700ac 100644 --- a/build/pkgs/gap/spkg-install.in +++ b/build/pkgs/gap/spkg-install.in @@ -8,8 +8,7 @@ export CFLAGS=$CFLAGS_NON_NATIVE export CXXFLAGS=$CXXFLAGS_NON_NATIVE GAP_BUILD_ROOT="$(pwd)" -GAP_ROOT="$SAGE_LOCAL/share/gap" -DESTDIR_GAP_ROOT="$SAGE_DESTDIR$GAP_ROOT" +GAP_ROOT="$SAGE_LOCAL/lib/gap" # Enable debug info if requested. # Note that -g3 allows you to use preprocessor macros in gdb which are widely used @@ -17,37 +16,17 @@ if [ "$SAGE_DEBUG" = yes ] ; then export CFLAGS="-O0 -g3 -DDEBUG_MASTERPOINTERS -DDEBUG_GLOBAL_BAGS -DDEBUG_FUNCTIONS_BAGS $CFLAGS" fi -sdh_configure $SAGE_CONFIGURE_GMP -sdh_make -j1 +# LDFLAGS hack below needed by Semigroups package +sdh_configure $SAGE_CONFIGURE_GMP LDFLAGS="-pthread" --prefix=$SAGE_LOCAL +sdh_make -# GAP's "make install" is work in progress; we use bits and pieces of it -# but we install many things manually. -sdh_make install-headers install-libgap - -# Install config.h, which is not currently handled by `make install-headers` -sdh_install gen/config.h "$SAGE_LOCAL/include/gap" - -# Now install the gap executable as "gap-bin"; it will be called normally -# through our wrapper script that sets the appropriate GAP_ROOT -SAGE_BIN="$SAGE_LOCAL/bin" -mkdir -p "$SAGE_DESTDIR$SAGE_BIN" || sdh_die "Failed to create the directory $SAGE_BIN" - -./libtool --mode=install install gap "$SAGE_DESTDIR$SAGE_BIN/gap-bin" || \ - sdh_die "Failed to install gap-bin to $SAGE_BIN" - -./libtool --mode=install install gac "$SAGE_DESTDIR$SAGE_BIN/gac" || \ - sdh_die "Failed to install gac to $SAGE_BIN" - -# Now copy additional files GAP needs to run (and a few optional bits) into -# GAP_ROOT; we don't need everything from the source tree -sdh_install bin doc gen grp lib src tst sysinfo.gap "$GAP_ROOT" - -# GAP's copy of libtool is also used by the toolchain for build GAP packages -# (i.e. by gac) -sdh_install libtool "$GAP_ROOT" +sdh_make_install +# sdh_make install-headers install-libgap +# The 'packagemanager' package expects this https://github.com/gap-packages/PackageManager/issues/105 +mkdir -p "$SAGE_LOCAL/lib/gap/bin" # Install only the minimal packages GAP needs to run -sdh_install pkg/GAPDoc-* pkg/primgrp-* pkg/SmallGrp-* pkg/transgrp "$GAP_ROOT"/pkg +sdh_install pkg/gapdoc pkg/primgrp pkg/smallgrp pkg/transgrp "$GAP_ROOT"/pkg # Install additional packages that are not strictly required, but that are # typically "expected" to be loaded: These are the default packages that are @@ -58,50 +37,25 @@ sdh_install pkg/GAPDoc-* pkg/primgrp-* pkg/SmallGrp-* pkg/transgrp "$GAP_ROOT"/p # Also include atlasrep which is a dependency of tomlib sdh_install \ pkg/atlasrep \ - pkg/autpgrp-* \ - pkg/alnuth-* \ - pkg/crisp-* \ - pkg/ctbllib-* \ - pkg/FactInt-* \ + pkg/autodoc \ + pkg/autpgrp \ + pkg/alnuth \ + pkg/crisp \ + pkg/ctbllib \ + pkg/factint \ pkg/fga \ - pkg/irredsol-* \ - pkg/laguna-* \ - pkg/PackageManager-* \ - pkg/polenta-* \ - pkg/polycyclic-* \ - pkg/resclasses-* \ - pkg/sophus-* \ - pkg/tomlib-* \ + pkg/irredsol \ + pkg/laguna \ + pkg/packagemanager \ + pkg/polenta \ + pkg/polycyclic \ + pkg/radiroot \ + pkg/resclasses \ + pkg/sophus \ + pkg/tomlib \ + pkg/utils \ "$GAP_ROOT"/pkg -# Install the GAP startup script; ensure it is executable -sdh_install -T ../gap "$SAGE_BIN/gap" -chmod +x "$SAGE_DESTDIR$SAGE_BIN/gap" - -# Create symlinks under $GAP_ROOT for these executables, as they are expected -# (especially when building kernel packages) to exist -ln -sf "../../bin/gap-bin" "$DESTDIR_GAP_ROOT/gap" -ln -sf "../../bin/gac" "$DESTDIR_GAP_ROOT/gac" - -# Fix the $GAP_ROOT/bin/<arch>/src symlink to be relative (otherwise it links -# to the actual path of the sources GAP was compiled from) -for srclink in "$DESTDIR_GAP_ROOT"/bin/*/src; do - rm -f "$srclink" - ln -s "../../src" "$srclink" -done - -# Additional fixups for some files after they have been copied into their -# destination directory. gac and sysinfo.gap are generated files that contain -# in them hard-coded references to the GAP build directory, which will soon -# be going away. This breaks the build toolchain for some compiled GAP -# packages. We need to replace these paths with the final GAP_ROOT path. The -# below will work so long as neither of these paths contain '|', and if they do -# then god help you. https://github.com/sagemath/sage/issues/27218 -sed -i -e "s|$GAP_BUILD_ROOT|$GAP_ROOT|g" \ - "$SAGE_DESTDIR$SAGE_BIN/gac" "$DESTDIR_GAP_ROOT/sysinfo.gap" \ - "$DESTDIR_GAP_ROOT/bin/gap.sh" "$DESTDIR_GAP_ROOT/doc/make_doc" || \ - sdh_die "Failed to fix up hard-coded paths in GAP build tools." - # TODO: This seems unnecessary--we are already installing all of doc/ to # GAP_ROOT, which is necessary for some functionality in GAP to work. Do # we need this? Maybe doc/gap could just be a symlink to gap/doc?? diff --git a/build/pkgs/gap/spkg-legacy-uninstall b/build/pkgs/gap/spkg-legacy-uninstall index d17eb939eb7..a8e5c59e1fb 100755 --- a/build/pkgs/gap/spkg-legacy-uninstall +++ b/build/pkgs/gap/spkg-legacy-uninstall @@ -4,6 +4,8 @@ rm -rf "$SAGE_LOCAL/gap/gap-4."* rm -rf "$SAGE_SHARE/gap" rm -f "$SAGE_LOCAL/gap/latest" rm -f "$SAGE_LOCAL/bin/gap" +rm -f "$SAGE_LOCAL/bin/gac" -# Remove old libgap headers +# Remove old libgap headers and library rm -rf "$SAGE_LOCAL/include/gap" +rm -rf "$SAGE_LOCAL/lib/gap" diff --git a/build/pkgs/gap/spkg-prerm.in b/build/pkgs/gap/spkg-prerm.in deleted file mode 100644 index 661d92621fa..00000000000 --- a/build/pkgs/gap/spkg-prerm.in +++ /dev/null @@ -1,6 +0,0 @@ -# These generated files are placed in directory provided by the SPKG, so -# delete the generated files first so that their parent directories can be -# removed during installation -GAP_ROOT="$SAGE_LOCAL/share/gap" -rm -f "$GAP_ROOT/pkg/atlasrep/datagens/"*.* -rm -f "$GAP_ROOT/pkg/atlasrep/dataword/"*.* diff --git a/build/pkgs/gap_jupyter/dependencies b/build/pkgs/gap_jupyter/dependencies index 41133c3ff0a..89f9b88dd92 100644 --- a/build/pkgs/gap_jupyter/dependencies +++ b/build/pkgs/gap_jupyter/dependencies @@ -1 +1 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) ipython gap + | $(PYTHON_TOOLCHAIN) ipython gap $(PYTHON) diff --git a/build/pkgs/gap_packages/patches/cohomolo-gcc10.patch b/build/pkgs/gap_packages/patches/cohomolo-gcc10.patch deleted file mode 100644 index e45fe7d9c6f..00000000000 --- a/build/pkgs/gap_packages/patches/cohomolo-gcc10.patch +++ /dev/null @@ -1,150 +0,0 @@ -diff --git a/pkg/cohomolo-1.6.8/standalone/progs.d/crp1.c b/pkg/cohomolo-1.6.8/standalone/progs.d/crp1.c -index 3bbdc45..7df699f 100644 ---- a/pkg/cohomolo-1.6.8/standalone/progs.d/crp1.c -+++ b/pkg/cohomolo-1.6.8/standalone/progs.d/crp1.c -@@ -8,9 +8,8 @@ extern short sp[],**mat[],*psp[],**imcos[],**cpco[],lorb[], - short *cst,**cpst,***cdpst,**svptr,*cp,*rel; - short *spst,**pspst,**pptr,**cpptr,npt,nb,nph,nph2,npg,npg2, - rno,orno,coh_index,*invg; --FILE *ip,*op; - --void seeknln (void) { while (getc(ip)!='\n'); } -+void seeknln (FILE *ip) { while (getc(ip)!='\n'); } - - /* This program differs from most other permutation programs in that perms are - all stored in the single array sp. Schreier vectors are stored in the short -@@ -23,13 +22,14 @@ void seeknln (void) { while (getc(ip)!='\n'); } - int - crprog1 (void) - { short *pc,*qc,ex,neg; int x; -+ FILE *ip,*op; - short i,j,k,l,m,n,cl,rl,*p,ocl,im,pt,pt1,pn,ipt; - if ((ip=fopen(inf2,"r"))== 0) - { fprintf(stderr,"Cannot open %s.\n",inf2); return(-1);} - fscanf(ip,"%hd%hd%hd%hd",&npt,&nph,&nb,&k); - if (nb>=mb) {fprintf(stderr,"nb too big. Increase MB.\n"); return(-1);} - if (k<=2) {fprintf(stderr,"inf2 has illegal format.\n"); return(-1); } -- seeknln(); seeknln(); -+ seeknln(ip); seeknln(ip); - for (i=1;i<=nb;i++) fscanf(ip,"%hd",lorb+i); - pptr=psp-1; pspst=psp+nph; svptr=cpsp-1; cpst=cpsp+nb; - invg=sp; nph2=2*nph; spst=sp+nph2; -@@ -37,7 +37,7 @@ crprog1 (void) - { pptr[i]=spst+(i-1)*npt-1; p=pptr[i]; - for (j=1;j<=npt;j++) {fscanf(ip,"%hd",&k); p[k]=j; } - invg[2*i-2]=2*i-1; invg[2*i-1]=2*i-2; -- seeknln(); -+ seeknln(ip); - } - spst+=(npt*nph); - for (i=1;i<=nb;i++) -@@ -75,7 +75,7 @@ crprog1 (void) - strcpy(inf1,inf0); strcat(inf1,".rel"); - if ((ip=fopen(inf1,"r"))==0) - { fprintf(stderr,"Cannot open %s.\n",inf1); return(-1);} -- fscanf(ip,"%hd%hd",&k,&rno); seeknln(); -+ fscanf(ip,"%hd%hd",&k,&rno); seeknln(ip); - op=fopen(outft,"w"); - /* Now we have read everything in, and the computation can start */ - orno=0; -diff --git a/pkg/cohomolo-1.6.8/standalone/progs.d/nq+chfns.c b/pkg/cohomolo-1.6.8/standalone/progs.d/nq+chfns.c -index a7396b2..658496f 100644 ---- a/pkg/cohomolo-1.6.8/standalone/progs.d/nq+chfns.c -+++ b/pkg/cohomolo-1.6.8/standalone/progs.d/nq+chfns.c -@@ -20,8 +20,6 @@ short mexp=MEXP,mcl=MCL,no,rel[RSP],wt[MEXP],exp,*rpf,*rpb, - extern short prime,dim,*spv,**spm,mspace[],*vec[],**mat[],cp[],pinv[],opmats, - mm,mv; - extern int msp; --FILE *ip,*op; -- - - int - calcmats (void) -@@ -59,7 +57,7 @@ calcmats (void) - } - for (i=1;i<=exp;i++) trans(mat[i+exp],mat[i]); - if (opmats) -- { op=fopen(outf,"w"); -+ { FILE *op=fopen(outf,"w"); - fprintf(op,"%4d%4d%4d\n",prime,dim,exp); - for (i=1;i<=exp;i++) printmat(mat[i]); - fclose(op); -@@ -71,6 +69,7 @@ int - rdmats (void) - /* reads matrices of generators of P */ - { short i; int quot; -+ FILE *ip; - ip=fopen(inf4,"r"); - if (ip==0) - { fprintf(stderr,"Cannot open %s\n ",inf4); return(-1); } -@@ -90,12 +89,12 @@ rdmats (void) - fclose(ip); - return(0); - } --FILE *ip; - - int - ingp (int inp) - /* Read in output of respcrun -s */ - { short i,j,k,l,m,*orpf,**pcp; -+ FILE *ip; - ip=fopen(inf3,"r"); - if (ip==0) { fprintf(stderr,"Cannot open %s\n",inf3); return(-1); } - fscanf(ip,"%hd%hd%hd%hd%hd%hd",&prime,&exp,&i,&no,&j,&m); -diff --git a/pkg/cohomolo-1.6.8/standalone/progs.d/nqmfns.c b/pkg/cohomolo-1.6.8/standalone/progs.d/nqmfns.c -index 0896551..6841bc8 100644 ---- a/pkg/cohomolo-1.6.8/standalone/progs.d/nqmfns.c -+++ b/pkg/cohomolo-1.6.8/standalone/progs.d/nqmfns.c -@@ -9,7 +9,6 @@ extern short intexp,mexp,mng,wksp, - spugen[],*tlintg[]; - extern int ptrsp,rsp; - short fac; --FILE *ip,*op; - - int - ingp (void) -@@ -18,6 +17,7 @@ ingp (void) - of nqrun, and tails are also read in. - */ - { short i,j,k,l,m,x,y,no,*orpf,*orpb,**pcp; char tails; -+ FILE *ip; - if ((ip=fopen(inf1,"r"))==0) - { fprintf(stderr,"Cannot open %s.\n",inf1); return(-1); } - fscanf(ip,"%hd%hd%hd%hd%hd%hd",&prime,&exp,&nng,&no,&class,&m); -@@ -89,6 +89,7 @@ int - outgp (void) - /* The PCP is output, together with tails */ - { short i,k,l,**pcp,*b,*e,*c; -+ FILE *op; - op=fopen(outf,"w"); - fprintf(op,"%4d%4d%4d%4d%4d%4d\n",prime,exp,nng,exp,class,1); - for (i=1;i<=exp;i++) fprintf(op,"%4d",wt[i]); fprintf(op,"\n"); -@@ -379,7 +380,7 @@ restart: - nng--; mnng--; enexpnt--; - if (nng==0) - { if (gap) -- { op=fopen(outfm,"w"); fprintf(op,"COHOMOLO.Multiplier:=[];\n"); -+ { FILE *op=fopen(outfm,"w"); fprintf(op,"COHOMOLO.Multiplier:=[];\n"); - fclose(op); - printf("All new generators eliminated. Multiplier is trivial.\n"); - } -diff --git a/pkg/cohomolo-1.6.8/standalone/progs.d/nqmp.c b/pkg/cohomolo-1.6.8/standalone/progs.d/nqmp.c -index 01cf914..0144883 100644 ---- a/pkg/cohomolo-1.6.8/standalone/progs.d/nqmp.c -+++ b/pkg/cohomolo-1.6.8/standalone/progs.d/nqmp.c -@@ -9,7 +9,6 @@ extern short intexp,mng,mexp,wksp, - spugen[],*intg[],*imintg[],*tlintg[]; - extern int ptrsp,rsp; - short *wf,*wc; char norm; --FILE *ip,*op; - - /* The data structures for this program and for nqrun are similar. - d1 and d2 contain definitions of generators. (Def. comes from commutator -@@ -35,6 +34,7 @@ nqmprog (void) - { short i,j,k,l,m,d,*gi,*gj,*ti,*tj,cl,def,*ps,*pf,**dp,*nrpb,*p,*orpf,*orpb, - nb,np,k1,*rno,*covrel,**pgen,tdef,sgn; - char nt; -+ FILE *ip,*op; - if (ingp() == -1) {fprintf(stderr,"Input error.\n"); return(-1); } - eexpnt=expnt+exp; enexpnt=nexpnt+nng; - diff --git a/build/pkgs/gap_packages/patches/guava_leon_includes.patch b/build/pkgs/gap_packages/patches/guava_leon_includes.patch deleted file mode 100644 index cdcd19cc3e8..00000000000 --- a/build/pkgs/gap_packages/patches/guava_leon_includes.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- a/pkg/guava-3.15/src/leon/src/generate.c Sat Feb 29 09:02:10 2020 ---- b/pkg/guava-3.15/src/leon/src/generate.c Thu Sep 24 13:58:36 2020 -*************** -*** 115,120 **** ---- 115,122 ---- - #include "groupio.h" - #include "enum.h" - #include "storage.h" -+ #include "chbase.h" -+ #include "inform.h" - - #ifdef ALT_TIME_HEADER - #include "cputime.h" diff --git a/build/pkgs/gap_packages/spkg-install.in b/build/pkgs/gap_packages/spkg-install.in index 168e6b11532..6dff182a48f 100644 --- a/build/pkgs/gap_packages/spkg-install.in +++ b/build/pkgs/gap_packages/spkg-install.in @@ -1,4 +1,4 @@ -GAP_ROOT="$SAGE_LOCAL/share/gap" +GAP_ROOT="$SAGE_LOCAL/lib/gap" PKG_DIR="$GAP_ROOT/pkg" PKG_SRC_DIR="$(pwd)/src/pkg" @@ -11,33 +11,31 @@ cd "$PKG_SRC_DIR" # (GAP 4.8.6 still had it, but this is gone in 4.10) sdh_install \ - aclib-* \ - AutoDoc-* \ - corelg-* \ - crime-* \ + aclib \ + corelg \ + crime \ cryst \ crystcat \ - design-* \ + design \ gbnp \ - genss-* \ - hap-* \ - hapcryst-* \ - hecke-* \ - images-* \ - liealgdb-* \ - liepring-* \ - liering-* \ - loops-* \ - MapClass-* \ - polymaking-* \ - qpa-* \ - quagroup-* \ - radiroot-* \ - repsn-* \ - sla-* \ - sonata-* \ - Toric-* \ - utils-* \ + genss \ + hap \ + hapcryst \ + hecke \ + images \ + liealgdb \ + liepring \ + liering \ + loops \ + mapclass \ + polymaking \ + qpa \ + quagroup \ + repsn \ + singular \ + sla \ + sonata \ + toric \ "$PKG_DIR" install_compiled_pkg() @@ -45,27 +43,23 @@ install_compiled_pkg() local pkg="$1" # Install the bin/ dir (where compiled modules should end up) # under <prefix>/lib/gap; we then symlink to it later - sdh_install bin "$SAGE_LOCAL/lib/gap/pkg/$pkg" + sdh_install * "$SAGE_LOCAL/lib/gap/pkg/$pkg" + # TODO: # Clean up any build artificts before installing the rest of the package # Also remove configure/Makefiles # Note: None, if any of the packages really have a proper install target - make clean # Works for some packages but not all - rm -rf bin/ - rm -rf configure configure.* config.* autogen.sh *.m4 Makefile* m4/ + #make clean # Works for some packages but not all + #rm -rf bin/ + #rm -rf configure configure.* config.* autogen.sh *.m4 Makefile* m4/ - # Create the bin/ symlink - ln -s "$SAGE_LOCAL/lib/gap/pkg/$pkg/bin" bin - - # Install the rest of the package files - sdh_install * "$PKG_DIR/$pkg" } # Build and install compiled packages: # # These packages have an old ./configure that take the GAP_ROOT as a positional # argument -for pkg in cohomolo-* crypting-* grape-* guava-* orb-* datastructures-* +for pkg in cohomolo crypting grape guava orb datastructures do echo "Building GAP package $pkg" CFLAGS="$CFLAGS -Wno-implicit-function-declaration" @@ -91,7 +85,7 @@ pararr=( " " " " "--with-external-planarity" "--with-external-libsemigroups" ) ############################################################################## parind=0 -for pkg in nq-* io-* digraphs-* semigroups-* +for pkg in nq io digraphs semigroups do echo "Building GAP package $pkg" cd "$PKG_SRC_DIR/$pkg" diff --git a/build/pkgs/gast/checksums.ini b/build/pkgs/gast/checksums.ini index 1aa653229f2..57bc0736a13 100644 --- a/build/pkgs/gast/checksums.ini +++ b/build/pkgs/gast/checksums.ini @@ -1,5 +1,5 @@ tarball=gast-VERSION.tar.gz -sha1=a84811eedebc5bca94b4eae978aab5f2c805b106 -md5=fdff900805e03e9dd76d377eb4cbaed7 -cksum=387443419 +sha1=6c113cf8d33cc654d33210335103485ab41d3dbb +md5=907c689e3fdbc7a48cc010e665195baa +cksum=218846575 upstream_url=https://pypi.io/packages/source/g/gast/gast-VERSION.tar.gz diff --git a/build/pkgs/gast/dependencies b/build/pkgs/gast/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/gast/dependencies +++ b/build/pkgs/gast/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/gast/distros/gentoo.txt b/build/pkgs/gast/distros/gentoo.txt new file mode 100644 index 00000000000..3be5e7e785c --- /dev/null +++ b/build/pkgs/gast/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/gast diff --git a/build/pkgs/gast/package-version.txt b/build/pkgs/gast/package-version.txt index be14282b7ff..7d8568351b4 100644 --- a/build/pkgs/gast/package-version.txt +++ b/build/pkgs/gast/package-version.txt @@ -1 +1 @@ -0.5.3 +0.5.4 diff --git a/build/pkgs/gast/spkg-configure.m4 b/build/pkgs/gast/spkg-configure.m4 new file mode 100644 index 00000000000..26ec59feaee --- /dev/null +++ b/build/pkgs/gast/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([gast], [SAGE_PYTHON_PACKAGE_CHECK([gast])]) diff --git a/build/pkgs/gc/SPKG.rst b/build/pkgs/gc/SPKG.rst index ece6b70d3e6..ee778eb5fcd 100644 --- a/build/pkgs/gc/SPKG.rst +++ b/build/pkgs/gc/SPKG.rst @@ -6,25 +6,24 @@ Description The Boehm-Demers-Weiser conservative garbage collector. + License ------- -- Permissive BSD + GPL 2.0+ +- MIT-style (https://github.com/ivmai/bdwgc/blob/master/LICENSE) Upstream Contact ---------------- -Webpage: http://www.hboehm.info/gc/ +- Ivan Maidanski + +Webpage: +- https://github.com/ivmai/bdwgc/ +- https://www.hboehm.info/gc/ -Email List: bdwgc@lists.opendylan.org Special Update/Build Instructions --------------------------------- None. - -Patches -~~~~~~~ - -- cygwin64.patch: let libgc build on Cygwin64. diff --git a/build/pkgs/gc/checksums.ini b/build/pkgs/gc/checksums.ini index 628ecde3d37..828d7e35d93 100644 --- a/build/pkgs/gc/checksums.ini +++ b/build/pkgs/gc/checksums.ini @@ -1,5 +1,5 @@ tarball=gc-VERSION.tar.gz -sha1=4b8b24534f469b64ff4bc2332a9bdf8bef8bf1d4 -md5=67a5093e2f9f381bd550aa891d00b54b -cksum=121524068 +sha1=41c88cbc4bc9bf76e1a95a1500ea5b0360bc4f55 +md5=8901a6ed29ac35842420054772ea3441 +cksum=4201205407 upstream_url=https://github.com/ivmai/bdwgc/releases/download/vVERSION/gc-VERSION.tar.gz diff --git a/build/pkgs/gc/package-version.txt b/build/pkgs/gc/package-version.txt index 50c496d20c6..11cb5b746c0 100644 --- a/build/pkgs/gc/package-version.txt +++ b/build/pkgs/gc/package-version.txt @@ -1 +1 @@ -8.0.4 +8.2.4 diff --git a/build/pkgs/gc/spkg-install.in b/build/pkgs/gc/spkg-install.in index 4acf5cf8b19..f42295bb279 100644 --- a/build/pkgs/gc/spkg-install.in +++ b/build/pkgs/gc/spkg-install.in @@ -4,9 +4,7 @@ GC_CONFIGURE="--enable-large-config" if [ "$UNAME" = "CYGWIN" ]; then # See https://github.com/sagemath/sage/issues/22694 - GC_CONFIGURE="$GC_CONFIGURE --enable-threads=posix --enable-handle-fork --enable-shared --disable-static" - # Force use of mmap on Cygwin https://github.com/sagemath/sage/issues/23973 - export CFLAGS="$CFLAGS -DUSE_MMAP -DUSE_MUNMAP" + GC_CONFIGURE="$GC_CONFIGURE --enable-threads=posix --enable-handle-fork" fi sdh_configure $GC_CONFIGURE diff --git a/build/pkgs/gcc/SPKG.rst b/build/pkgs/gcc/SPKG.rst index 75feee2d6d8..1f90eb0bf67 100644 --- a/build/pkgs/gcc/SPKG.rst +++ b/build/pkgs/gcc/SPKG.rst @@ -6,7 +6,7 @@ Description This package represents the required C and C++ compilers. -- GCC (GNU Compiler Collection) versions 8.x to 12.x are supported. +- GCC (GNU Compiler Collection) versions 8.x (>= 8.4.0) to 13.x are supported. - Clang (LLVM) is also supported. @@ -25,7 +25,7 @@ need to run:: Vendor and versions of the C and C++ compilers should match. Users of older Linux distributions (in particular, ``ubuntu-xenial`` -or older, ``debian-stretch`` or older, ``linuxmint-18`` or older) +or older, ``debian-buster`` or older, ``linuxmint-18`` or older) should upgrade their systems before attempting to install Sage from source. Users of ``ubuntu-bionic``, ``linuxmint-19.x``, and ``opensuse-15.x`` can install a versioned ``gcc`` system package diff --git a/build/pkgs/gcc/spkg-configure.m4 b/build/pkgs/gcc/spkg-configure.m4 index fe4d220a189..e1b44ec1c9d 100644 --- a/build/pkgs/gcc/spkg-configure.m4 +++ b/build/pkgs/gcc/spkg-configure.m4 @@ -161,12 +161,12 @@ SAGE_SPKG_CONFIGURE_BASE([gcc], [ # Add the .0 because Debian/Ubuntu gives version numbers like # 4.6 instead of 4.6.4 (Trac #18885) AS_CASE(["$GXX_VERSION.0"], - [[[0-7]].*], [ - # Install our own GCC if the system-provided one is older than gcc 8 + [[[0-7]].*|8.[[0-3]].*], [ + # Install our own GCC if the system-provided one is older than gcc 8.4 SAGE_SHOULD_INSTALL_GCC([you have $CXX version $GXX_VERSION, which is quite old]) ], - [1[[3-9]].*], [ - # Install our own GCC if the system-provided one is newer than 12.x. + [1[[4-9]].*], [ + # Install our own GCC if the system-provided one is newer than 13.x. # See https://github.com/sagemath/sage/issues/29456 SAGE_SHOULD_INSTALL_GCC([$CXX is g++ version $GXX_VERSION, which is too recent for this version of Sage]) ]) @@ -232,7 +232,7 @@ SAGE_SPKG_CONFIGURE_BASE([gcc], [ fi AC_SUBST(CFLAGS_MARCH) - # Determine wether compiler supports OpenMP. + # Determine whether compiler supports OpenMP. AC_LANG_PUSH([C]) AX_OPENMP([ AC_SUBST(OPENMP_CFLAGS) diff --git a/build/pkgs/gdb/dependencies b/build/pkgs/gdb/dependencies index bdf81f77180..cf6822bb92e 100644 --- a/build/pkgs/gdb/dependencies +++ b/build/pkgs/gdb/dependencies @@ -1,4 +1,4 @@ -mpfr zlib ncurses $(PYTHON) xz +mpfr zlib ncurses xz | $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/gfortran/spkg-configure.m4 b/build/pkgs/gfortran/spkg-configure.m4 index 1a2d6ba767c..d2841f740aa 100644 --- a/build/pkgs/gfortran/spkg-configure.m4 +++ b/build/pkgs/gfortran/spkg-configure.m4 @@ -86,8 +86,8 @@ SAGE_SPKG_CONFIGURE([gfortran], [ # Install our own gfortran if the system-provided one is older than gcc-4.8. SAGE_SHOULD_INSTALL_GFORTRAN([$FC is version $GFORTRAN_VERSION, which is quite old]) ], - [1[[3-9]].*], [ - # Install our own gfortran if the system-provided one is newer than 12.x. + [1[[4-9]].*], [ + # Install our own gfortran if the system-provided one is newer than 13.x. # See https://github.com/sagemath/sage/issues/29456, https://github.com/sagemath/sage/issues/31838 SAGE_MUST_INSTALL_GFORTRAN([$FC is version $GFORTRAN_VERSION, which is too recent for this version of Sage]) ]) diff --git a/build/pkgs/giac/checksums.ini b/build/pkgs/giac/checksums.ini index 2fb1d3fdf31..089c15f34b4 100644 --- a/build/pkgs/giac/checksums.ini +++ b/build/pkgs/giac/checksums.ini @@ -2,4 +2,3 @@ tarball=giac-VERSION.tar.bz2 sha1=78c15badd19b49b7d111ac204b611a4378ce3d15 md5=8fbd43a5c60848b6813b7fc8698a0199 cksum=1923149665 -upstream_url=https://trac.sagemath.org/raw-attachment/ticket/31563/giac-VERSION.tar.bz2 diff --git a/build/pkgs/giac/spkg-configure.m4 b/build/pkgs/giac/spkg-configure.m4 index 5859e35f12e..53e3a8301cd 100644 --- a/build/pkgs/giac/spkg-configure.m4 +++ b/build/pkgs/giac/spkg-configure.m4 @@ -5,7 +5,7 @@ SAGE_SPKG_CONFIGURE([giac], [ m4_pushdef([GIAC_MAX_VERSION], [1.9.999]) AC_CACHE_CHECK([for giac >= ]GIAC_MIN_VERSION[, <= ]GIAC_MAX_VERSION, [ac_cv_path_GIAC], [ AC_PATH_PROGS_FEATURE_CHECK([GIAC], [giac], [ - giac_version=$($ac_path_GIAC --version 2> /dev/null | tail -1) + giac_version=$($ac_path_GIAC --version 2> /dev/null | tail -n 1) AS_IF([test -n "$giac_version"], [ AX_COMPARE_VERSION([$giac_version], [ge], GIAC_MIN_VERSION, [ AX_COMPARE_VERSION([$giac_version], [le], GIAC_MAX_VERSION, [ diff --git a/build/pkgs/gitpython/dependencies b/build/pkgs/gitpython/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/gitpython/dependencies +++ b/build/pkgs/gitpython/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/givaro/patches/218.patch b/build/pkgs/givaro/patches/218.patch new file mode 100644 index 00000000000..15178289ca8 --- /dev/null +++ b/build/pkgs/givaro/patches/218.patch @@ -0,0 +1,23 @@ +From c7744bb133496cd7ac04688f345646d505e1bf52 Mon Sep 17 00:00:00 2001 +From: "Benjamin A. Beasley" <code@musicinmybrain.net> +Date: Thu, 19 Jan 2023 09:12:22 -0500 +Subject: [PATCH] Add missing #include <cstdint> for (u)int64_t + +Fixes failure to compile on GCC 13. +--- + src/library/poly1/givdegree.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/library/poly1/givdegree.h b/src/library/poly1/givdegree.h +index 3753a425..eb85a0dd 100644 +--- a/src/library/poly1/givdegree.h ++++ b/src/library/poly1/givdegree.h +@@ -19,6 +19,8 @@ + #ifndef __GIVARO_poly1degree_H + #define __GIVARO_poly1degree_H + ++#include <cstdint> ++ + #include <iostream> + + namespace Givaro { diff --git a/build/pkgs/gmpy2/dependencies b/build/pkgs/gmpy2/dependencies index 98c6065dc87..b1f92b9241d 100644 --- a/build/pkgs/gmpy2/dependencies +++ b/build/pkgs/gmpy2/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) $(MP_LIBRARY) mpfr mpc | $(PYTHON_TOOLCHAIN) + $(MP_LIBRARY) mpfr mpc | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/gmpy2/distros/arch.txt b/build/pkgs/gmpy2/distros/arch.txt new file mode 100644 index 00000000000..d4464a5ce2c --- /dev/null +++ b/build/pkgs/gmpy2/distros/arch.txt @@ -0,0 +1 @@ +python-gmpy2 diff --git a/build/pkgs/gmpy2/distros/debian.txt b/build/pkgs/gmpy2/distros/debian.txt new file mode 100644 index 00000000000..afdd6281722 --- /dev/null +++ b/build/pkgs/gmpy2/distros/debian.txt @@ -0,0 +1 @@ +python3-gmpy2 diff --git a/build/pkgs/gmpy2/distros/fedora.txt b/build/pkgs/gmpy2/distros/fedora.txt new file mode 100644 index 00000000000..d4464a5ce2c --- /dev/null +++ b/build/pkgs/gmpy2/distros/fedora.txt @@ -0,0 +1 @@ +python-gmpy2 diff --git a/build/pkgs/gmpy2/distros/freebsd.txt b/build/pkgs/gmpy2/distros/freebsd.txt new file mode 100644 index 00000000000..0d9d2c435a6 --- /dev/null +++ b/build/pkgs/gmpy2/distros/freebsd.txt @@ -0,0 +1 @@ +math/py-gmpy2 diff --git a/build/pkgs/gmpy2/distros/gentoo.txt b/build/pkgs/gmpy2/distros/gentoo.txt new file mode 100644 index 00000000000..519f9d8729a --- /dev/null +++ b/build/pkgs/gmpy2/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/gmpy diff --git a/build/pkgs/gmpy2/distros/opensuse.txt b/build/pkgs/gmpy2/distros/opensuse.txt new file mode 100644 index 00000000000..36d52b88ba6 --- /dev/null +++ b/build/pkgs/gmpy2/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-gmpy2 diff --git a/build/pkgs/gmpy2/spkg-configure.m4 b/build/pkgs/gmpy2/spkg-configure.m4 new file mode 100644 index 00000000000..2d0390f7db3 --- /dev/null +++ b/build/pkgs/gmpy2/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([gmpy2], [SAGE_PYTHON_PACKAGE_CHECK([gmpy2])]) diff --git a/build/pkgs/hatch_fancy_pypi_readme/checksums.ini b/build/pkgs/hatch_fancy_pypi_readme/checksums.ini index 6728a45be5c..6d48eb14be8 100644 --- a/build/pkgs/hatch_fancy_pypi_readme/checksums.ini +++ b/build/pkgs/hatch_fancy_pypi_readme/checksums.ini @@ -1,5 +1,5 @@ tarball=hatch_fancy_pypi_readme-VERSION.tar.gz -sha1=2cdf215fdd13de69f5de09c7ef0e2ceff4a03666 -md5=588776ea8e3608714d4cbba16dffa92b -cksum=613442646 +sha1=8c8568bb86bdc65133e9d8b27493a464fa3320da +md5=8755cce1a4a4d5e5d84992089801acbf +cksum=2176903739 upstream_url=https://pypi.io/packages/source/h/hatch_fancy_pypi_readme/hatch_fancy_pypi_readme-VERSION.tar.gz diff --git a/build/pkgs/hatch_fancy_pypi_readme/dependencies b/build/pkgs/hatch_fancy_pypi_readme/dependencies index 8cd44d06682..cfb7c484697 100644 --- a/build/pkgs/hatch_fancy_pypi_readme/dependencies +++ b/build/pkgs/hatch_fancy_pypi_readme/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) hatchling + | $(PYTHON_TOOLCHAIN) hatchling $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/hatch_fancy_pypi_readme/package-version.txt b/build/pkgs/hatch_fancy_pypi_readme/package-version.txt index 9d673278df8..f8aed3e0b7a 100644 --- a/build/pkgs/hatch_fancy_pypi_readme/package-version.txt +++ b/build/pkgs/hatch_fancy_pypi_readme/package-version.txt @@ -1 +1 @@ -22.8.0 +23.1.0 diff --git a/build/pkgs/hatch_nodejs_version/dependencies b/build/pkgs/hatch_nodejs_version/dependencies index e9293f104ca..85e8893f785 100644 --- a/build/pkgs/hatch_nodejs_version/dependencies +++ b/build/pkgs/hatch_nodejs_version/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) hatchling | $(PYTHON_TOOLCHAIN) + hatchling | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/hatch_vcs/checksums.ini b/build/pkgs/hatch_vcs/checksums.ini index 47e0c350f03..9c1290bda3b 100644 --- a/build/pkgs/hatch_vcs/checksums.ini +++ b/build/pkgs/hatch_vcs/checksums.ini @@ -1,5 +1,5 @@ tarball=hatch_vcs-VERSION.tar.gz -sha1=9d38f55610b156b513d3d2a79f81cbf4fdea3cb2 -md5=e56b6d0c05cfb9b59d493c67f94d6e48 -cksum=680867691 +sha1=026b964066b38fd7e823900817fb9ea7af3f8d9b +md5=c2f2cbe6851b7b2969cb4aa24c4b9b2f +cksum=588874896 upstream_url=https://pypi.io/packages/source/h/hatch_vcs/hatch_vcs-VERSION.tar.gz diff --git a/build/pkgs/hatch_vcs/dependencies b/build/pkgs/hatch_vcs/dependencies index 8cd44d06682..cfb7c484697 100644 --- a/build/pkgs/hatch_vcs/dependencies +++ b/build/pkgs/hatch_vcs/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) hatchling + | $(PYTHON_TOOLCHAIN) hatchling $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/hatch_vcs/package-version.txt b/build/pkgs/hatch_vcs/package-version.txt index 0ea3a944b39..0d91a54c7d4 100644 --- a/build/pkgs/hatch_vcs/package-version.txt +++ b/build/pkgs/hatch_vcs/package-version.txt @@ -1 +1 @@ -0.2.0 +0.3.0 diff --git a/build/pkgs/hatchling/checksums.ini b/build/pkgs/hatchling/checksums.ini index 2980620c8d8..d21781abeba 100644 --- a/build/pkgs/hatchling/checksums.ini +++ b/build/pkgs/hatchling/checksums.ini @@ -1,5 +1,5 @@ tarball=hatchling-VERSION.tar.gz -sha1=5d2e7ac6feffa2dfdbf81e7d10661ac1b08b9608 -md5=e06cc65ac646f9b01df5406aa1f97022 -cksum=310056602 +sha1=f3db8639e9bee89e2e2420d1bc7a048a910622c9 +md5=43f7203cacb6c3c178b93149b8a8151d +cksum=235277633 upstream_url=https://pypi.io/packages/source/h/hatchling/hatchling-VERSION.tar.gz diff --git a/build/pkgs/hatchling/dependencies b/build/pkgs/hatchling/dependencies index 84b5ea48ccc..479f1630979 100644 --- a/build/pkgs/hatchling/dependencies +++ b/build/pkgs/hatchling/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) pathspec tomli editables pluggy packaging | $(PYTHON_TOOLCHAIN) + pathspec tomli editables pluggy packaging trove_classifiers | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/hatchling/distros/gentoo.txt b/build/pkgs/hatchling/distros/gentoo.txt new file mode 100644 index 00000000000..24842db3e5a --- /dev/null +++ b/build/pkgs/hatchling/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/hatchling diff --git a/build/pkgs/hatchling/package-version.txt b/build/pkgs/hatchling/package-version.txt index 720c7384c61..84cc529467b 100644 --- a/build/pkgs/hatchling/package-version.txt +++ b/build/pkgs/hatchling/package-version.txt @@ -1 +1 @@ -1.11.1 +1.18.0 diff --git a/build/pkgs/hatchling/spkg-configure.m4 b/build/pkgs/hatchling/spkg-configure.m4 new file mode 100644 index 00000000000..d03747f230b --- /dev/null +++ b/build/pkgs/hatchling/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([hatchling], [SAGE_PYTHON_PACKAGE_CHECK([hatchling])]) diff --git a/build/pkgs/html5lib/SPKG.rst b/build/pkgs/html5lib/SPKG.rst deleted file mode 100644 index c0abaca59f3..00000000000 --- a/build/pkgs/html5lib/SPKG.rst +++ /dev/null @@ -1,19 +0,0 @@ -html5lib: An HTML parser -======================== - -Description ------------ - -HTML parser based on the WHATWG HTML specification. - -License -------- - -MIT License - - -Upstream Contact ----------------- - -Home Page: https://github.com/html5lib/html5lib-python/issues - diff --git a/build/pkgs/html5lib/checksums.ini b/build/pkgs/html5lib/checksums.ini deleted file mode 100644 index 13cb3b0d87f..00000000000 --- a/build/pkgs/html5lib/checksums.ini +++ /dev/null @@ -1,5 +0,0 @@ -tarball=html5lib-VERSION.tar.gz -sha1=6d1348b6356b62305e4a410df9dfd02143d841a1 -md5=6748742e2ec4cb99287a6bc82bcfe2b0 -cksum=3263889571 -upstream_url=https://pypi.io/packages/source/h/html5lib/html5lib-VERSION.tar.gz diff --git a/build/pkgs/html5lib/dependencies b/build/pkgs/html5lib/dependencies deleted file mode 100644 index 89200065387..00000000000 --- a/build/pkgs/html5lib/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -$(PYTHON) webencodings | $(PYTHON_TOOLCHAIN) - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/html5lib/distros/conda.txt b/build/pkgs/html5lib/distros/conda.txt deleted file mode 100644 index 6bcef8ab7d4..00000000000 --- a/build/pkgs/html5lib/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -html5lib diff --git a/build/pkgs/html5lib/distros/macports.txt b/build/pkgs/html5lib/distros/macports.txt deleted file mode 100644 index b11ce6f9dad..00000000000 --- a/build/pkgs/html5lib/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -py-html5lib diff --git a/build/pkgs/html5lib/distros/repology.txt b/build/pkgs/html5lib/distros/repology.txt deleted file mode 100644 index 52080964da2..00000000000 --- a/build/pkgs/html5lib/distros/repology.txt +++ /dev/null @@ -1,2 +0,0 @@ -html5lib -python:html5lib diff --git a/build/pkgs/html5lib/distros/void.txt b/build/pkgs/html5lib/distros/void.txt deleted file mode 100644 index 6d7b8dfb001..00000000000 --- a/build/pkgs/html5lib/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -python3-html5lib diff --git a/build/pkgs/html5lib/install-requires.txt b/build/pkgs/html5lib/install-requires.txt deleted file mode 100644 index f71f129272c..00000000000 --- a/build/pkgs/html5lib/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -html5lib >=1.0.1 diff --git a/build/pkgs/html5lib/package-version.txt b/build/pkgs/html5lib/package-version.txt deleted file mode 100644 index 9459d4ba2a0..00000000000 --- a/build/pkgs/html5lib/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -1.1 diff --git a/build/pkgs/html5lib/spkg-install.in b/build/pkgs/html5lib/spkg-install.in deleted file mode 100644 index deba1bb42bb..00000000000 --- a/build/pkgs/html5lib/spkg-install.in +++ /dev/null @@ -1 +0,0 @@ -cd src && sdh_pip_install . diff --git a/build/pkgs/idna/dependencies b/build/pkgs/idna/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/idna/dependencies +++ b/build/pkgs/idna/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/idna/distros/arch.txt b/build/pkgs/idna/distros/arch.txt new file mode 100644 index 00000000000..a73e70cade0 --- /dev/null +++ b/build/pkgs/idna/distros/arch.txt @@ -0,0 +1 @@ +python-idna diff --git a/build/pkgs/idna/distros/debian.txt b/build/pkgs/idna/distros/debian.txt new file mode 100644 index 00000000000..de48e70887b --- /dev/null +++ b/build/pkgs/idna/distros/debian.txt @@ -0,0 +1 @@ +python3-idna diff --git a/build/pkgs/idna/distros/fedora.txt b/build/pkgs/idna/distros/fedora.txt new file mode 100644 index 00000000000..a73e70cade0 --- /dev/null +++ b/build/pkgs/idna/distros/fedora.txt @@ -0,0 +1 @@ +python-idna diff --git a/build/pkgs/idna/distros/gentoo.txt b/build/pkgs/idna/distros/gentoo.txt new file mode 100644 index 00000000000..68ef51c453e --- /dev/null +++ b/build/pkgs/idna/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/idna diff --git a/build/pkgs/idna/distros/opensuse.txt b/build/pkgs/idna/distros/opensuse.txt new file mode 100644 index 00000000000..ea8400fa563 --- /dev/null +++ b/build/pkgs/idna/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-idna diff --git a/build/pkgs/idna/spkg-configure.m4 b/build/pkgs/idna/spkg-configure.m4 new file mode 100644 index 00000000000..9d363f212e6 --- /dev/null +++ b/build/pkgs/idna/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([idna], [SAGE_PYTHON_PACKAGE_CHECK([idna])]) diff --git a/build/pkgs/igraph/checksums.ini b/build/pkgs/igraph/checksums.ini index f7d3336bda8..279cba457a9 100644 --- a/build/pkgs/igraph/checksums.ini +++ b/build/pkgs/igraph/checksums.ini @@ -1,5 +1,5 @@ tarball=igraph-VERSION.tar.gz -sha1=20587332f0f36d6d7eb3cca248e2dab76e1e58ad -md5=af41eb9c614946c4a92a51834e9cab4a -cksum=4011381306 +sha1=fc3c6627f889b13581b2b468e1b16aceff453cfc +md5=10a3f325425970c75a7ba8359376e208 +cksum=3103730646 upstream_url=https://github.com/igraph/igraph/releases/download/VERSION/igraph-VERSION.tar.gz diff --git a/build/pkgs/igraph/package-version.txt b/build/pkgs/igraph/package-version.txt index 5eef0f10e8c..9b40aa6c214 100644 --- a/build/pkgs/igraph/package-version.txt +++ b/build/pkgs/igraph/package-version.txt @@ -1 +1 @@ -0.10.2 +0.10.4 diff --git a/build/pkgs/imagesize/dependencies b/build/pkgs/imagesize/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/imagesize/dependencies +++ b/build/pkgs/imagesize/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/imagesize/distros/gentoo.txt b/build/pkgs/imagesize/distros/gentoo.txt new file mode 100644 index 00000000000..54350ba2642 --- /dev/null +++ b/build/pkgs/imagesize/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/imagesize diff --git a/build/pkgs/imagesize/spkg-configure.m4 b/build/pkgs/imagesize/spkg-configure.m4 new file mode 100644 index 00000000000..20210eff2f0 --- /dev/null +++ b/build/pkgs/imagesize/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([imagesize], [SAGE_PYTHON_PACKAGE_CHECK([imagesize])]) diff --git a/build/pkgs/iml/checksums.ini b/build/pkgs/iml/checksums.ini index d876ccb5b53..628d5461e70 100644 --- a/build/pkgs/iml/checksums.ini +++ b/build/pkgs/iml/checksums.ini @@ -2,4 +2,3 @@ tarball=iml-VERSION.tar.bz2 sha1=8aba468a62e6fb0584be9b014350b734663c0670 md5=a8083e70c0c4378f69eb772c1eeed6f0 cksum=2793221462 -upstream_url=https://trac.sagemath.org/raw-attachment/ticket/33195/iml-1.0.4p2.tar.bz2 diff --git a/build/pkgs/importlib_metadata/SPKG.rst b/build/pkgs/importlib_metadata/SPKG.rst index d1b490d0082..c9b0bae0392 100644 --- a/build/pkgs/importlib_metadata/SPKG.rst +++ b/build/pkgs/importlib_metadata/SPKG.rst @@ -4,17 +4,19 @@ importlib_metadata: Library to access the metadata for a Python package Description ----------- -importlib_metadata is a library to access the metadata for a Python package. -It is intended to be ported to Python 3.8. +This is a backport package, supplying access to the functionality of +``importlib.metadata`` including improvements added to subsequent Python versions. + License ------- -Apache Software License +Apache Software License Upstream Contact ---------------- -Home page: http://importlib-metadata.readthedocs.io/ +- https://pypi.org/project/importlib-metadata/ +- http://importlib-metadata.readthedocs.io/ diff --git a/build/pkgs/importlib_metadata/checksums.ini b/build/pkgs/importlib_metadata/checksums.ini index 4d326297be6..dfcaf149224 100644 --- a/build/pkgs/importlib_metadata/checksums.ini +++ b/build/pkgs/importlib_metadata/checksums.ini @@ -1,5 +1,5 @@ tarball=importlib_metadata-VERSION.tar.gz -sha1=4a49e8c6d8e2eb02e9ea821444b5ba153d8c34a6 -md5=56d34f2e854bb0f318baa9e47aba3439 -cksum=3438247256 +sha1=b9b1f85f9d7ea8464990aa48078c2bc18c88b17d +md5=a7d0734680f70b03368b69fe3e89dc56 +cksum=579037727 upstream_url=https://pypi.io/packages/source/i/importlib_metadata/importlib_metadata-VERSION.tar.gz diff --git a/build/pkgs/importlib_metadata/dependencies b/build/pkgs/importlib_metadata/dependencies index 77aa2a42f93..3c8d3aeb24e 100644 --- a/build/pkgs/importlib_metadata/dependencies +++ b/build/pkgs/importlib_metadata/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) zipp typing_extensions | $(PYTHON_TOOLCHAIN) tomli + zipp typing_extensions | $(PYTHON_TOOLCHAIN) tomli $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/importlib_metadata/distros/arch.txt b/build/pkgs/importlib_metadata/distros/arch.txt new file mode 100644 index 00000000000..b3c206287ec --- /dev/null +++ b/build/pkgs/importlib_metadata/distros/arch.txt @@ -0,0 +1 @@ +python-importlib-metadata diff --git a/build/pkgs/importlib_metadata/distros/debian.txt b/build/pkgs/importlib_metadata/distros/debian.txt new file mode 100644 index 00000000000..c005bf38793 --- /dev/null +++ b/build/pkgs/importlib_metadata/distros/debian.txt @@ -0,0 +1 @@ +python3-importlib-metadata diff --git a/build/pkgs/importlib_metadata/distros/fedora.txt b/build/pkgs/importlib_metadata/distros/fedora.txt new file mode 100644 index 00000000000..b3c206287ec --- /dev/null +++ b/build/pkgs/importlib_metadata/distros/fedora.txt @@ -0,0 +1 @@ +python-importlib-metadata diff --git a/build/pkgs/importlib_metadata/distros/freebsd.txt b/build/pkgs/importlib_metadata/distros/freebsd.txt new file mode 100644 index 00000000000..23518da7cff --- /dev/null +++ b/build/pkgs/importlib_metadata/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-importlib-metadata diff --git a/build/pkgs/importlib_metadata/distros/gentoo.txt b/build/pkgs/importlib_metadata/distros/gentoo.txt new file mode 100644 index 00000000000..4f927864c2b --- /dev/null +++ b/build/pkgs/importlib_metadata/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/importlib_metadata diff --git a/build/pkgs/importlib_metadata/distros/opensuse.txt b/build/pkgs/importlib_metadata/distros/opensuse.txt new file mode 100644 index 00000000000..7a665131cd4 --- /dev/null +++ b/build/pkgs/importlib_metadata/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-importlib-metadata diff --git a/build/pkgs/importlib_metadata/install-requires.txt b/build/pkgs/importlib_metadata/install-requires.txt index 715fbb76b3a..7a0ebd24888 100644 --- a/build/pkgs/importlib_metadata/install-requires.txt +++ b/build/pkgs/importlib_metadata/install-requires.txt @@ -1 +1,3 @@ -importlib_metadata >=1.7.0 +# According to https://pypi.org/project/importlib-metadata/, +# 4.13 provides the features of Python 3.11 importlib.metadata +importlib_metadata >=4.13 diff --git a/build/pkgs/importlib_metadata/package-version.txt b/build/pkgs/importlib_metadata/package-version.txt index 831446cbd27..09b254e90c6 100644 --- a/build/pkgs/importlib_metadata/package-version.txt +++ b/build/pkgs/importlib_metadata/package-version.txt @@ -1 +1 @@ -5.1.0 +6.0.0 diff --git a/build/pkgs/importlib_metadata/spkg-configure.m4 b/build/pkgs/importlib_metadata/spkg-configure.m4 new file mode 100644 index 00000000000..0554e522252 --- /dev/null +++ b/build/pkgs/importlib_metadata/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([importlib_metadata], [ + SAGE_PYTHON_PACKAGE_CHECK([importlib_metadata]) +]) diff --git a/build/pkgs/importlib_resources/checksums.ini b/build/pkgs/importlib_resources/checksums.ini index 9885db7ffb4..ac6747edaec 100644 --- a/build/pkgs/importlib_resources/checksums.ini +++ b/build/pkgs/importlib_resources/checksums.ini @@ -1,5 +1,5 @@ tarball=importlib_resources-VERSION.tar.gz -sha1=a8c7a6a976fffb9841c548230cb633eda3111c4f -md5=8afc48c5f3a7c4ba63cb38163340d78b -cksum=196052500 +sha1=b793f4fb94148414679e3192e731fef25e3e9bc9 +md5=5457c25b89b19fcaca8af03e541dfa41 +cksum=527125049 upstream_url=https://pypi.io/packages/source/i/importlib_resources/importlib_resources-VERSION.tar.gz diff --git a/build/pkgs/importlib_resources/dependencies b/build/pkgs/importlib_resources/dependencies index 58927ab6f75..655283898b7 100644 --- a/build/pkgs/importlib_resources/dependencies +++ b/build/pkgs/importlib_resources/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) zipp | $(PYTHON_TOOLCHAIN) + zipp | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/importlib_resources/distros/gentoo.txt b/build/pkgs/importlib_resources/distros/gentoo.txt new file mode 100644 index 00000000000..d5e1f2cf6a8 --- /dev/null +++ b/build/pkgs/importlib_resources/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/importlib_resources diff --git a/build/pkgs/importlib_resources/install-requires.txt b/build/pkgs/importlib_resources/install-requires.txt index 2b0146fc669..632e716f5a0 100644 --- a/build/pkgs/importlib_resources/install-requires.txt +++ b/build/pkgs/importlib_resources/install-requires.txt @@ -1 +1,3 @@ -importlib-resources +# According to https://pypi.org/project/importlib-resources/, +# version 5.7 provides the features of Python 3.11 importlib.resources +importlib_resources >= 5.7 diff --git a/build/pkgs/importlib_resources/package-version.txt b/build/pkgs/importlib_resources/package-version.txt index 509b0b618ad..dd0ad7ae60c 100644 --- a/build/pkgs/importlib_resources/package-version.txt +++ b/build/pkgs/importlib_resources/package-version.txt @@ -1 +1 @@ -5.10.0 +5.12.0 diff --git a/build/pkgs/importlib_resources/spkg-configure.m4 b/build/pkgs/importlib_resources/spkg-configure.m4 new file mode 100644 index 00000000000..50df55b4643 --- /dev/null +++ b/build/pkgs/importlib_resources/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([importlib_resources], [ + SAGE_PYTHON_PACKAGE_CHECK([importlib_resources]) +]) diff --git a/build/pkgs/info/distros/fedora.txt b/build/pkgs/info/distros/fedora.txt index 283aa462f74..c0d8f74e0ad 100644 --- a/build/pkgs/info/distros/fedora.txt +++ b/build/pkgs/info/distros/fedora.txt @@ -1 +1 @@ -texinfo +texinfo info diff --git a/build/pkgs/info/spkg-configure.m4 b/build/pkgs/info/spkg-configure.m4 index 0980a4b8ef8..76ea2cc7565 100644 --- a/build/pkgs/info/spkg-configure.m4 +++ b/build/pkgs/info/spkg-configure.m4 @@ -1,4 +1,15 @@ SAGE_SPKG_CONFIGURE([info], [ AC_PATH_PROG(INFO, info) - AS_IF([test -z "${INFO}"], [sage_spkg_install_info=yes]) + AS_IF([test -z "${INFO}"], [sage_spkg_install_info=yes + ], [ + dnl very old makeinfo are not texi2any, newer are symlinks to texi2any + AC_PATH_PROG(TEXI2ANY, texi2any) + AS_IF([test -z "${TEXI2ANY}"], [sage_spkg_install_info=yes + ], [ + AS_IF([makeinfo -c foo 2>&1 | grep -q invalid], [ + dnl makeinfo found, but too old, and does not support all options that ecl likes to use + sage_spkg_install_info=yes]) + rm -f stdin.info + ]) + ]) ]) diff --git a/build/pkgs/info/spkg-install.in b/build/pkgs/info/spkg-install.in index 8086e4b2ec8..3ea8c053669 100644 --- a/build/pkgs/info/spkg-install.in +++ b/build/pkgs/info/spkg-install.in @@ -1,2 +1,2 @@ -cd src/info +cd src sdh_make_install diff --git a/build/pkgs/info/type b/build/pkgs/info/type index 134d9bc32d5..a6a7b9cd726 100644 --- a/build/pkgs/info/type +++ b/build/pkgs/info/type @@ -1 +1 @@ -optional +standard diff --git a/build/pkgs/ipykernel/dependencies b/build/pkgs/ipykernel/dependencies index 792c3e70634..7e153a0cb46 100644 --- a/build/pkgs/ipykernel/dependencies +++ b/build/pkgs/ipykernel/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) ipython_genutils importlib_metadata matplotlib_inline ipython jupyter_client tornado appnope traitlets executing | $(PYTHON_TOOLCHAIN) + ipython_genutils importlib_metadata matplotlib_inline ipython jupyter_client tornado appnope traitlets executing | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/ipykernel/distros/arch.txt b/build/pkgs/ipykernel/distros/arch.txt new file mode 100644 index 00000000000..286458797f7 --- /dev/null +++ b/build/pkgs/ipykernel/distros/arch.txt @@ -0,0 +1 @@ +python-ipykernel diff --git a/build/pkgs/ipykernel/distros/debian.txt b/build/pkgs/ipykernel/distros/debian.txt new file mode 100644 index 00000000000..d919f6f3190 --- /dev/null +++ b/build/pkgs/ipykernel/distros/debian.txt @@ -0,0 +1 @@ +ipykernel diff --git a/build/pkgs/ipykernel/distros/fedora.txt b/build/pkgs/ipykernel/distros/fedora.txt new file mode 100644 index 00000000000..286458797f7 --- /dev/null +++ b/build/pkgs/ipykernel/distros/fedora.txt @@ -0,0 +1 @@ +python-ipykernel diff --git a/build/pkgs/ipykernel/distros/freebsd.txt b/build/pkgs/ipykernel/distros/freebsd.txt new file mode 100644 index 00000000000..92235f132be --- /dev/null +++ b/build/pkgs/ipykernel/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-ipykernel diff --git a/build/pkgs/ipykernel/distros/gentoo.txt b/build/pkgs/ipykernel/distros/gentoo.txt new file mode 100644 index 00000000000..88aab61ef39 --- /dev/null +++ b/build/pkgs/ipykernel/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/ipykernel diff --git a/build/pkgs/ipykernel/distros/opensuse.txt b/build/pkgs/ipykernel/distros/opensuse.txt new file mode 100644 index 00000000000..1485db27e0d --- /dev/null +++ b/build/pkgs/ipykernel/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-ipykernel diff --git a/build/pkgs/ipykernel/spkg-configure.m4 b/build/pkgs/ipykernel/spkg-configure.m4 new file mode 100644 index 00000000000..94ecc2dcc4e --- /dev/null +++ b/build/pkgs/ipykernel/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([ipykernel], [SAGE_PYTHON_PACKAGE_CHECK([ipykernel])]) diff --git a/build/pkgs/ipympl/checksums.ini b/build/pkgs/ipympl/checksums.ini new file mode 100644 index 00000000000..2c724147c64 --- /dev/null +++ b/build/pkgs/ipympl/checksums.ini @@ -0,0 +1,5 @@ +tarball=ipympl-VERSION-py2.py3-none-any.whl +sha1=9848409026669d9edd83074730d7e2456ae8a187 +md5=e08ec29d29955174178b7230d41a7ff7 +cksum=490103438 +upstream_url=https://pypi.io/packages/py2.py3/i/ipympl/ipympl-VERSION-py2.py3-none-any.whl diff --git a/build/pkgs/ipympl/dependencies b/build/pkgs/ipympl/dependencies index 05d47407b15..b9a86422e74 100644 --- a/build/pkgs/ipympl/dependencies +++ b/build/pkgs/ipympl/dependencies @@ -1,6 +1,4 @@ -$(PYTHON) ipywidgets matplotlib ipykernel | $(PYTHON_TOOLCHAIN) jupyter_packaging +ipython numpy ipython_genutils pillow traitlets ipywidgets matplotlib | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. - -jupyterlab is listed as a "build-system requires", but the package installs correctly without it. diff --git a/build/pkgs/ipympl/distros/arch.txt b/build/pkgs/ipympl/distros/arch.txt new file mode 100644 index 00000000000..85cef6a0662 --- /dev/null +++ b/build/pkgs/ipympl/distros/arch.txt @@ -0,0 +1 @@ +python-ipympl diff --git a/build/pkgs/ipympl/distros/freebsd.txt b/build/pkgs/ipympl/distros/freebsd.txt new file mode 100644 index 00000000000..12b982ba727 --- /dev/null +++ b/build/pkgs/ipympl/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-ipympl diff --git a/build/pkgs/ipympl/distros/macports.txt b/build/pkgs/ipympl/distros/macports.txt new file mode 100644 index 00000000000..3102367bb00 --- /dev/null +++ b/build/pkgs/ipympl/distros/macports.txt @@ -0,0 +1 @@ +py-ipympl diff --git a/build/pkgs/ipympl/distros/repology.txt b/build/pkgs/ipympl/distros/repology.txt new file mode 100644 index 00000000000..68e8e609e7f --- /dev/null +++ b/build/pkgs/ipympl/distros/repology.txt @@ -0,0 +1 @@ +python:ipympl diff --git a/build/pkgs/ipympl/package-version.txt b/build/pkgs/ipympl/package-version.txt new file mode 100644 index 00000000000..965065db5b8 --- /dev/null +++ b/build/pkgs/ipympl/package-version.txt @@ -0,0 +1 @@ +0.9.3 diff --git a/build/pkgs/ipympl/requirements.txt b/build/pkgs/ipympl/requirements.txt deleted file mode 100644 index d715db054cd..00000000000 --- a/build/pkgs/ipympl/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -ipympl diff --git a/build/pkgs/ipympl/spkg-configure.m4 b/build/pkgs/ipympl/spkg-configure.m4 new file mode 100644 index 00000000000..d6ccf959ec7 --- /dev/null +++ b/build/pkgs/ipympl/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([ipympl], [ + SAGE_PYTHON_PACKAGE_CHECK([ipympl]) +]) diff --git a/build/pkgs/ipython/dependencies b/build/pkgs/ipython/dependencies index 38dad7b80ee..cc719ef4ea5 100644 --- a/build/pkgs/ipython/dependencies +++ b/build/pkgs/ipython/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) jinja2 tornado pyzmq pickleshare simplegeneric traitlets decorator wcwidth prompt_toolkit pygments pexpect appnope backcall jedi stack_data | $(PYTHON_TOOLCHAIN) +tornado pyzmq pickleshare traitlets decorator wcwidth prompt_toolkit pygments pexpect appnope backcall jedi stack_data | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/ipython/distros/arch.txt b/build/pkgs/ipython/distros/arch.txt new file mode 100644 index 00000000000..49a7ffe2a95 --- /dev/null +++ b/build/pkgs/ipython/distros/arch.txt @@ -0,0 +1 @@ +ipython diff --git a/build/pkgs/ipython/distros/debian.txt b/build/pkgs/ipython/distros/debian.txt new file mode 100644 index 00000000000..c32c6b449cf --- /dev/null +++ b/build/pkgs/ipython/distros/debian.txt @@ -0,0 +1 @@ +python3-ipython diff --git a/build/pkgs/ipython/distros/fedora.txt b/build/pkgs/ipython/distros/fedora.txt new file mode 100644 index 00000000000..49a7ffe2a95 --- /dev/null +++ b/build/pkgs/ipython/distros/fedora.txt @@ -0,0 +1 @@ +ipython diff --git a/build/pkgs/ipython/distros/freebsd.txt b/build/pkgs/ipython/distros/freebsd.txt new file mode 100644 index 00000000000..3252ee7fbc1 --- /dev/null +++ b/build/pkgs/ipython/distros/freebsd.txt @@ -0,0 +1 @@ +devel/ipython diff --git a/build/pkgs/ipython/distros/gentoo.txt b/build/pkgs/ipython/distros/gentoo.txt new file mode 100644 index 00000000000..8b76f186ff8 --- /dev/null +++ b/build/pkgs/ipython/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/ipython diff --git a/build/pkgs/ipython/distros/opensuse.txt b/build/pkgs/ipython/distros/opensuse.txt index c32c6b449cf..32aac30ae1e 100644 --- a/build/pkgs/ipython/distros/opensuse.txt +++ b/build/pkgs/ipython/distros/opensuse.txt @@ -1 +1 @@ -python3-ipython +python3${PYTHON_MINOR}-ipython diff --git a/build/pkgs/ipython/install-requires.txt b/build/pkgs/ipython/install-requires.txt index a52df49c421..03d4a4f3413 100644 --- a/build/pkgs/ipython/install-requires.txt +++ b/build/pkgs/ipython/install-requires.txt @@ -1 +1,2 @@ -ipython >=7.13.0 +ipython >=7.13.0, <8.9.0 +# ipython >= 8.9.0 requires prompt_toolkit too new for Sage diff --git a/build/pkgs/ipython/spkg-configure.m4 b/build/pkgs/ipython/spkg-configure.m4 new file mode 100644 index 00000000000..02ab89f5193 --- /dev/null +++ b/build/pkgs/ipython/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([ipython], [SAGE_PYTHON_PACKAGE_CHECK([ipython])]) diff --git a/build/pkgs/ipython_genutils/dependencies b/build/pkgs/ipython_genutils/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/ipython_genutils/dependencies +++ b/build/pkgs/ipython_genutils/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/ipython_genutils/distros/gentoo.txt b/build/pkgs/ipython_genutils/distros/gentoo.txt new file mode 100644 index 00000000000..01bc49d4e1a --- /dev/null +++ b/build/pkgs/ipython_genutils/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/ipython_genutils diff --git a/build/pkgs/ipython_genutils/spkg-configure.m4 b/build/pkgs/ipython_genutils/spkg-configure.m4 new file mode 100644 index 00000000000..b0ba86ac7a3 --- /dev/null +++ b/build/pkgs/ipython_genutils/spkg-configure.m4 @@ -0,0 +1,4 @@ +SAGE_SPKG_CONFIGURE( + [ipython_genutils], + [SAGE_PYTHON_PACKAGE_CHECK([ipython_genutils])] +) diff --git a/build/pkgs/ipywidgets/dependencies b/build/pkgs/ipywidgets/dependencies index 64f5151c754..bcb4e030b7d 100644 --- a/build/pkgs/ipywidgets/dependencies +++ b/build/pkgs/ipywidgets/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) widgetsnbextension jupyterlab_widgets | $(PYTHON_TOOLCHAIN) ipykernel ipython traitlets + widgetsnbextension jupyterlab_widgets | $(PYTHON_TOOLCHAIN) ipykernel ipython traitlets $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/ipywidgets/distros/conda.txt b/build/pkgs/ipywidgets/distros/conda.txt index f582a4a3283..f943f9d4979 100644 --- a/build/pkgs/ipywidgets/distros/conda.txt +++ b/build/pkgs/ipywidgets/distros/conda.txt @@ -1 +1 @@ -ipywidgets +ipywidgets<8.0.0 diff --git a/build/pkgs/ipywidgets/distros/gentoo.txt b/build/pkgs/ipywidgets/distros/gentoo.txt new file mode 100644 index 00000000000..7c76967c65b --- /dev/null +++ b/build/pkgs/ipywidgets/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/ipywidgets diff --git a/build/pkgs/ipywidgets/spkg-configure.m4 b/build/pkgs/ipywidgets/spkg-configure.m4 new file mode 100644 index 00000000000..51ca9be74db --- /dev/null +++ b/build/pkgs/ipywidgets/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([ipywidgets], [SAGE_PYTHON_PACKAGE_CHECK([ipywidgets])]) diff --git a/build/pkgs/jedi/dependencies b/build/pkgs/jedi/dependencies index 60b5f820a37..0e2212bd149 100644 --- a/build/pkgs/jedi/dependencies +++ b/build/pkgs/jedi/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) parso | $(PYTHON_TOOLCHAIN) + parso | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jedi/distros/gentoo.txt b/build/pkgs/jedi/distros/gentoo.txt new file mode 100644 index 00000000000..6c85a46cfcb --- /dev/null +++ b/build/pkgs/jedi/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/jedi diff --git a/build/pkgs/jedi/spkg-configure.m4 b/build/pkgs/jedi/spkg-configure.m4 new file mode 100644 index 00000000000..a37dbcc92db --- /dev/null +++ b/build/pkgs/jedi/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([jedi], [SAGE_PYTHON_PACKAGE_CHECK([jedi])]) diff --git a/build/pkgs/jinja2/dependencies b/build/pkgs/jinja2/dependencies index 6947978ec42..151ae9767d1 100644 --- a/build/pkgs/jinja2/dependencies +++ b/build/pkgs/jinja2/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) markupsafe docutils | $(PYTHON_TOOLCHAIN) + markupsafe docutils | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jinja2/distros/debian.txt b/build/pkgs/jinja2/distros/debian.txt new file mode 100644 index 00000000000..f2db865ab36 --- /dev/null +++ b/build/pkgs/jinja2/distros/debian.txt @@ -0,0 +1 @@ +python3-jinja2 diff --git a/build/pkgs/jinja2/distros/fedora.txt b/build/pkgs/jinja2/distros/fedora.txt new file mode 100644 index 00000000000..f5f3caf99cc --- /dev/null +++ b/build/pkgs/jinja2/distros/fedora.txt @@ -0,0 +1 @@ +python-jinja2 diff --git a/build/pkgs/jinja2/distros/gentoo.txt b/build/pkgs/jinja2/distros/gentoo.txt new file mode 100644 index 00000000000..15a27aecd44 --- /dev/null +++ b/build/pkgs/jinja2/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/jinja diff --git a/build/pkgs/jinja2/distros/opensuse.txt b/build/pkgs/jinja2/distros/opensuse.txt index 5d90a223f55..8ad585a7ef3 100644 --- a/build/pkgs/jinja2/distros/opensuse.txt +++ b/build/pkgs/jinja2/distros/opensuse.txt @@ -1 +1 @@ -python3-Jinja2 +python3${PYTHON_MINOR}-jinja2 diff --git a/build/pkgs/jinja2/install-requires.txt b/build/pkgs/jinja2/install-requires.txt index 99d8e6ecd6e..829d4c266d3 100644 --- a/build/pkgs/jinja2/install-requires.txt +++ b/build/pkgs/jinja2/install-requires.txt @@ -1 +1,2 @@ -jinja2 >=2.11.2 +jinja2 >=3.0 +# for sphinx diff --git a/build/pkgs/jinja2/spkg-configure.m4 b/build/pkgs/jinja2/spkg-configure.m4 new file mode 100644 index 00000000000..0970d1c8bea --- /dev/null +++ b/build/pkgs/jinja2/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([jinja2], [SAGE_PYTHON_PACKAGE_CHECK([jinja2])]) diff --git a/build/pkgs/jsonschema/dependencies b/build/pkgs/jsonschema/dependencies index 51698156cf0..d0211604157 100644 --- a/build/pkgs/jsonschema/dependencies +++ b/build/pkgs/jsonschema/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) vcversioner attrs importlib_metadata pyrsistent | $(PYTHON_TOOLCHAIN) hatchling hatch_vcs hatch_fancy_pypi_readme + vcversioner attrs importlib_metadata pyrsistent | $(PYTHON_TOOLCHAIN) hatchling hatch_vcs hatch_fancy_pypi_readme $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jsonschema/distros/arch.txt b/build/pkgs/jsonschema/distros/arch.txt new file mode 100644 index 00000000000..8943c30f9ed --- /dev/null +++ b/build/pkgs/jsonschema/distros/arch.txt @@ -0,0 +1 @@ +python-jsonschema diff --git a/build/pkgs/jsonschema/distros/debian.txt b/build/pkgs/jsonschema/distros/debian.txt new file mode 100644 index 00000000000..047e6cc5d1d --- /dev/null +++ b/build/pkgs/jsonschema/distros/debian.txt @@ -0,0 +1 @@ +python3-jsonschema diff --git a/build/pkgs/jsonschema/distros/fedora.txt b/build/pkgs/jsonschema/distros/fedora.txt new file mode 100644 index 00000000000..8943c30f9ed --- /dev/null +++ b/build/pkgs/jsonschema/distros/fedora.txt @@ -0,0 +1 @@ +python-jsonschema diff --git a/build/pkgs/jsonschema/distros/gentoo.txt b/build/pkgs/jsonschema/distros/gentoo.txt new file mode 100644 index 00000000000..d708e4c9990 --- /dev/null +++ b/build/pkgs/jsonschema/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/jsonschema diff --git a/build/pkgs/jsonschema/distros/opensuse.txt b/build/pkgs/jsonschema/distros/opensuse.txt index 047e6cc5d1d..2a587a55946 100644 --- a/build/pkgs/jsonschema/distros/opensuse.txt +++ b/build/pkgs/jsonschema/distros/opensuse.txt @@ -1 +1 @@ -python3-jsonschema +python3${PYTHON_MINOR}-jsonschema diff --git a/build/pkgs/jsonschema/spkg-configure.m4 b/build/pkgs/jsonschema/spkg-configure.m4 new file mode 100644 index 00000000000..b9e5e216a3b --- /dev/null +++ b/build/pkgs/jsonschema/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([jsonschema], [SAGE_PYTHON_PACKAGE_CHECK([jsonschema])]) diff --git a/build/pkgs/jupymake/dependencies b/build/pkgs/jupymake/dependencies index c8ed956ad6a..aa714006aae 100644 --- a/build/pkgs/jupymake/dependencies +++ b/build/pkgs/jupymake/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) polymake | $(PYTHON_TOOLCHAIN) + polymake | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jupyter_client/dependencies b/build/pkgs/jupyter_client/dependencies index 29d5d3b6bf3..dcc8c256fad 100644 --- a/build/pkgs/jupyter_client/dependencies +++ b/build/pkgs/jupyter_client/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) jupyter_core | $(PYTHON_TOOLCHAIN) pyzmq dateutil nest_asyncio tornado traitlets entrypoints hatchling + jupyter_core | $(PYTHON_TOOLCHAIN) pyzmq dateutil nest_asyncio tornado traitlets entrypoints hatchling $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jupyter_client/distros/gentoo.txt b/build/pkgs/jupyter_client/distros/gentoo.txt new file mode 100644 index 00000000000..4f1de883ca1 --- /dev/null +++ b/build/pkgs/jupyter_client/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/jupyter_client diff --git a/build/pkgs/jupyter_client/distros/opensuse.txt b/build/pkgs/jupyter_client/distros/opensuse.txt index 0159b2d7b90..a1e21956a79 100644 --- a/build/pkgs/jupyter_client/distros/opensuse.txt +++ b/build/pkgs/jupyter_client/distros/opensuse.txt @@ -1 +1 @@ -python3-jupyter-client +python3${PYTHON_MINOR}-jupyter-client diff --git a/build/pkgs/jupyter_client/spkg-configure.m4 b/build/pkgs/jupyter_client/spkg-configure.m4 new file mode 100644 index 00000000000..fbd34982c14 --- /dev/null +++ b/build/pkgs/jupyter_client/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([jupyter_client], [ + SAGE_PYTHON_PACKAGE_CHECK([jupyter_client]) +]) diff --git a/build/pkgs/jupyter_core/checksums.ini b/build/pkgs/jupyter_core/checksums.ini index 5a49b040b98..3e45d122068 100644 --- a/build/pkgs/jupyter_core/checksums.ini +++ b/build/pkgs/jupyter_core/checksums.ini @@ -1,5 +1,5 @@ tarball=jupyter_core-VERSION.tar.gz -sha1=6e48f90477c11ad41b9404732a2bdcb485f4e630 -md5=84d207d4c48513a2b87ff2ed508beb98 -cksum=2072829465 +sha1=2a0a14c4c1624826100d59169636bb588465deb9 +md5=7586526dd4ca9d1bc820a4a5429df48b +cksum=1776144013 upstream_url=https://pypi.io/packages/source/j/jupyter_core/jupyter_core-VERSION.tar.gz diff --git a/build/pkgs/jupyter_core/dependencies b/build/pkgs/jupyter_core/dependencies index 6aeda10f20d..a312196cbed 100644 --- a/build/pkgs/jupyter_core/dependencies +++ b/build/pkgs/jupyter_core/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) traitlets + traitlets | $(PYTHON_TOOLCHAIN) hatchling $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jupyter_core/distros/gentoo.txt b/build/pkgs/jupyter_core/distros/gentoo.txt new file mode 100644 index 00000000000..f168c5ad7ad --- /dev/null +++ b/build/pkgs/jupyter_core/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/jupyter_core diff --git a/build/pkgs/jupyter_core/distros/opensuse.txt b/build/pkgs/jupyter_core/distros/opensuse.txt index 2f316f2ee07..2c677674477 100644 --- a/build/pkgs/jupyter_core/distros/opensuse.txt +++ b/build/pkgs/jupyter_core/distros/opensuse.txt @@ -1 +1 @@ -python3-jupyter-core +python3${PYTHON_MINOR}-jupyter-core diff --git a/build/pkgs/jupyter_core/package-version.txt b/build/pkgs/jupyter_core/package-version.txt index 4f89fb96069..815588ef140 100644 --- a/build/pkgs/jupyter_core/package-version.txt +++ b/build/pkgs/jupyter_core/package-version.txt @@ -1 +1 @@ -4.11.2 +4.12.0 diff --git a/build/pkgs/jupyter_core/spkg-configure.m4 b/build/pkgs/jupyter_core/spkg-configure.m4 new file mode 100644 index 00000000000..67df9c38b5b --- /dev/null +++ b/build/pkgs/jupyter_core/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([jupyter_core], [ + SAGE_PYTHON_PACKAGE_CHECK([jupyter_core]) +]) diff --git a/build/pkgs/jupyter_jsmol/SPKG.rst b/build/pkgs/jupyter_jsmol/SPKG.rst index e318a86c7b1..64458e86b2d 100644 --- a/build/pkgs/jupyter_jsmol/SPKG.rst +++ b/build/pkgs/jupyter_jsmol/SPKG.rst @@ -9,7 +9,7 @@ JSmol viewer widget for Jupyter License ------- -BSD +MIT Upstream Contact ---------------- diff --git a/build/pkgs/jupyter_jsmol/checksums.ini b/build/pkgs/jupyter_jsmol/checksums.ini index 0ac16d6e78c..9ac2c41a8e4 100644 --- a/build/pkgs/jupyter_jsmol/checksums.ini +++ b/build/pkgs/jupyter_jsmol/checksums.ini @@ -1,5 +1,5 @@ -tarball=jupyter_jsmol-VERSION.tar.gz -sha1=6ba59de9d1df15b2a09a57f6bdf10f48f13af9ac -md5=90e9490414e7fbecc6013b4b051b06d7 -cksum=917919116 -upstream_url=https://pypi.io/packages/source/j/jupyter-jsmol/jupyter_jsmol-VERSION.tar.gz +tarball=jupyter_jsmol-VERSION-py2.py3-none-any.whl +sha1=b00f1ca76aaa906c7c0a43e36baf608183f3d552 +md5=dd786877513296a36a08518ad64ace47 +cksum=2135042898 +upstream_url=https://pypi.io/packages/py2.py3/j/jupyter_jsmol/jupyter_jsmol-VERSION-py2.py3-none-any.whl diff --git a/build/pkgs/jupyter_jsmol/dependencies b/build/pkgs/jupyter_jsmol/dependencies index a6d87526311..2c7683a6111 100644 --- a/build/pkgs/jupyter_jsmol/dependencies +++ b/build/pkgs/jupyter_jsmol/dependencies @@ -1,4 +1,4 @@ -ipywidgets jupyter_packaging $(PYTHON) | $(PYTHON_TOOLCHAIN) +ipywidgets | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jupyter_jsmol/distros/arch.txt b/build/pkgs/jupyter_jsmol/distros/arch.txt new file mode 100644 index 00000000000..9465bfb8e0c --- /dev/null +++ b/build/pkgs/jupyter_jsmol/distros/arch.txt @@ -0,0 +1 @@ +jupyter-jsmol diff --git a/build/pkgs/jupyter_jsmol/distros/freebsd.txt b/build/pkgs/jupyter_jsmol/distros/freebsd.txt new file mode 100644 index 00000000000..5954a774e80 --- /dev/null +++ b/build/pkgs/jupyter_jsmol/distros/freebsd.txt @@ -0,0 +1 @@ +science/py-jupyter_jsmol diff --git a/build/pkgs/jupyter_jsmol/install-requires.txt b/build/pkgs/jupyter_jsmol/install-requires.txt index 2df501ec9a8..9465bfb8e0c 100644 --- a/build/pkgs/jupyter_jsmol/install-requires.txt +++ b/build/pkgs/jupyter_jsmol/install-requires.txt @@ -1 +1 @@ -jupyter-jsmol >=2022.1.0 +jupyter-jsmol diff --git a/build/pkgs/jupyter_jsmol/spkg-configure.m4 b/build/pkgs/jupyter_jsmol/spkg-configure.m4 new file mode 100644 index 00000000000..202fe5fff31 --- /dev/null +++ b/build/pkgs/jupyter_jsmol/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([jupyter_jsmol], [ + SAGE_PYTHON_PACKAGE_CHECK([jupyter_jsmol]) +]) diff --git a/build/pkgs/jupyter_jsmol/spkg-install.in b/build/pkgs/jupyter_jsmol/spkg-install.in deleted file mode 100644 index 72d65dde8d5..00000000000 --- a/build/pkgs/jupyter_jsmol/spkg-install.in +++ /dev/null @@ -1,3 +0,0 @@ -cd src -# Use --no-build-isolation because we have a different version of jupyter_packaging -eval sdh_pip_install --no-build-isolation --config-settings "--global-option=--skip-npm" . diff --git a/build/pkgs/jupyter_packaging/SPKG.rst b/build/pkgs/jupyter_packaging/SPKG.rst deleted file mode 100644 index 7e6a0bcfd8a..00000000000 --- a/build/pkgs/jupyter_packaging/SPKG.rst +++ /dev/null @@ -1,18 +0,0 @@ -jupyter_packaging: Jupyter Packaging Utilities -============================================== - -Description ------------ - -Jupyter Packaging Utilities - -License -------- - -BSD - -Upstream Contact ----------------- - -https://pypi.org/project/jupyter-packaging/ - diff --git a/build/pkgs/jupyter_packaging/checksums.ini b/build/pkgs/jupyter_packaging/checksums.ini deleted file mode 100644 index 65b3bd148f6..00000000000 --- a/build/pkgs/jupyter_packaging/checksums.ini +++ /dev/null @@ -1,5 +0,0 @@ -tarball=jupyter_packaging-VERSION.tar.gz -sha1=092d249360aa56838a188decc4bcd09647fda4d9 -md5=9c6834023bd699bda5365ab7ed18bde2 -cksum=3308833189 -upstream_url=https://pypi.io/packages/source/j/jupyter_packaging/jupyter_packaging-VERSION.tar.gz diff --git a/build/pkgs/jupyter_packaging/dependencies b/build/pkgs/jupyter_packaging/dependencies deleted file mode 100644 index 838afe13edf..00000000000 --- a/build/pkgs/jupyter_packaging/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -$(PYTHON) packaging deprecation tomlkit | $(PYTHON_TOOLCHAIN) hatchling - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/jupyter_packaging/distros/conda.txt b/build/pkgs/jupyter_packaging/distros/conda.txt deleted file mode 100644 index b5ec61b7d14..00000000000 --- a/build/pkgs/jupyter_packaging/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -jupyter-packaging diff --git a/build/pkgs/jupyter_packaging/install-requires.txt b/build/pkgs/jupyter_packaging/install-requires.txt deleted file mode 100644 index b5ec61b7d14..00000000000 --- a/build/pkgs/jupyter_packaging/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -jupyter-packaging diff --git a/build/pkgs/jupyter_packaging/package-version.txt b/build/pkgs/jupyter_packaging/package-version.txt deleted file mode 100644 index aa22d3ce39b..00000000000 --- a/build/pkgs/jupyter_packaging/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -0.12.3 diff --git a/build/pkgs/jupyter_sphinx/dependencies b/build/pkgs/jupyter_sphinx/dependencies index 785929f6ea8..37476f7a572 100644 --- a/build/pkgs/jupyter_sphinx/dependencies +++ b/build/pkgs/jupyter_sphinx/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) sphinx ipywidgets ipython nbconvert nbformat | $(PYTHON_TOOLCHAIN) + sphinx ipywidgets ipython nbconvert nbformat | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jupyter_sphinx/distros/arch.txt b/build/pkgs/jupyter_sphinx/distros/arch.txt new file mode 100644 index 00000000000..95d44e5858f --- /dev/null +++ b/build/pkgs/jupyter_sphinx/distros/arch.txt @@ -0,0 +1 @@ +python-jupyter-sphinx diff --git a/build/pkgs/jupyter_sphinx/distros/fedora.txt b/build/pkgs/jupyter_sphinx/distros/fedora.txt new file mode 100644 index 00000000000..95d44e5858f --- /dev/null +++ b/build/pkgs/jupyter_sphinx/distros/fedora.txt @@ -0,0 +1 @@ +python-jupyter-sphinx diff --git a/build/pkgs/jupyter_sphinx/distros/freebsd.txt b/build/pkgs/jupyter_sphinx/distros/freebsd.txt new file mode 100644 index 00000000000..7e84cc729e6 --- /dev/null +++ b/build/pkgs/jupyter_sphinx/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-jupyter_sphinx diff --git a/build/pkgs/jupyter_sphinx/distros/macports.txt b/build/pkgs/jupyter_sphinx/distros/macports.txt new file mode 100644 index 00000000000..9ad2b36d1ba --- /dev/null +++ b/build/pkgs/jupyter_sphinx/distros/macports.txt @@ -0,0 +1 @@ +py-jupyter_sphinx diff --git a/build/pkgs/jupyter_sphinx/distros/opensuse.txt b/build/pkgs/jupyter_sphinx/distros/opensuse.txt new file mode 100644 index 00000000000..95d44e5858f --- /dev/null +++ b/build/pkgs/jupyter_sphinx/distros/opensuse.txt @@ -0,0 +1 @@ +python-jupyter-sphinx diff --git a/build/pkgs/jupyter_sphinx/spkg-configure.m4 b/build/pkgs/jupyter_sphinx/spkg-configure.m4 new file mode 100644 index 00000000000..e9650c888f8 --- /dev/null +++ b/build/pkgs/jupyter_sphinx/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([jupyter_sphinx], [ + SAGE_PYTHON_PACKAGE_CHECK([jupyter_sphinx]) +]) diff --git a/build/pkgs/jupyterlab/dependencies b/build/pkgs/jupyterlab/dependencies index 98ad2e94050..059006650e1 100644 --- a/build/pkgs/jupyterlab/dependencies +++ b/build/pkgs/jupyterlab/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) vcversioner jupyter_core jupyter_client jinja2 tornado ipython packaging terminado traitlets nbconvert send2trash nbformat prometheus_client ipython_genutils argon2_cffi pyzmq idna requests jsonschema babel notebook | $(PYTHON_TOOLCHAIN) + vcversioner jupyter_core jupyter_client jinja2 tornado ipython packaging terminado traitlets nbconvert send2trash nbformat prometheus_client ipython_genutils argon2_cffi pyzmq idna requests jsonschema babel notebook | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jupyterlab_pygments/dependencies b/build/pkgs/jupyterlab_pygments/dependencies index a59532cdda1..fd3f15b7aa3 100644 --- a/build/pkgs/jupyterlab_pygments/dependencies +++ b/build/pkgs/jupyterlab_pygments/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) pygments | $(PYTHON_TOOLCHAIN) + pygments | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jupyterlab_pygments/distros/gentoo.txt b/build/pkgs/jupyterlab_pygments/distros/gentoo.txt new file mode 100644 index 00000000000..c57b4f13403 --- /dev/null +++ b/build/pkgs/jupyterlab_pygments/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/jupyterlab_pygments diff --git a/build/pkgs/jupyterlab_pygments/spkg-configure.m4 b/build/pkgs/jupyterlab_pygments/spkg-configure.m4 new file mode 100644 index 00000000000..e46e21f461e --- /dev/null +++ b/build/pkgs/jupyterlab_pygments/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([jupyterlab_pygments], [ + SAGE_PYTHON_PACKAGE_CHECK([jupyterlab_pygments]) +]) diff --git a/build/pkgs/jupyterlab_widgets/dependencies b/build/pkgs/jupyterlab_widgets/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/jupyterlab_widgets/dependencies +++ b/build/pkgs/jupyterlab_widgets/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jupyterlab_widgets/distros/arch.txt b/build/pkgs/jupyterlab_widgets/distros/arch.txt new file mode 100644 index 00000000000..0800dc09838 --- /dev/null +++ b/build/pkgs/jupyterlab_widgets/distros/arch.txt @@ -0,0 +1 @@ +jupyterlab-widgets diff --git a/build/pkgs/jupyterlab_widgets/distros/freebsd.txt b/build/pkgs/jupyterlab_widgets/distros/freebsd.txt new file mode 100644 index 00000000000..6fc98fe86a0 --- /dev/null +++ b/build/pkgs/jupyterlab_widgets/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-jupyterlab-widgets diff --git a/build/pkgs/jupyterlab_widgets/distros/opensuse.txt b/build/pkgs/jupyterlab_widgets/distros/opensuse.txt new file mode 100644 index 00000000000..04706eee600 --- /dev/null +++ b/build/pkgs/jupyterlab_widgets/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-jupyterlab-widgets diff --git a/build/pkgs/jupyterlab_widgets/spkg-configure.m4 b/build/pkgs/jupyterlab_widgets/spkg-configure.m4 new file mode 100644 index 00000000000..dfea30713eb --- /dev/null +++ b/build/pkgs/jupyterlab_widgets/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([jupyterlab_widgets], [ + SAGE_PYTHON_PACKAGE_CHECK([jupyterlab_widgets]) +]) diff --git a/build/pkgs/kissat/checksums.ini b/build/pkgs/kissat/checksums.ini index 66b187bb599..85929110253 100644 --- a/build/pkgs/kissat/checksums.ini +++ b/build/pkgs/kissat/checksums.ini @@ -1,5 +1,5 @@ tarball=kissat-rel-VERSION.tar.gz -sha1=abfd971d5f560ed76281ed3ed7b75e20cb445618 -md5=6ef4b2efcc60c95a32581bfe59720154 -cksum=1532123399 +sha1=49972324939761306ee50cfa3df93cd3cd530256 +md5=1d0fa246c5451e3592910f2c9a5f3476 +cksum=2570717921 upstream_url=https://github.com/arminbiere/kissat/archive/refs/tags/rel-VERSION.tar.gz diff --git a/build/pkgs/kissat/package-version.txt b/build/pkgs/kissat/package-version.txt index 4a36342fcab..fd2a01863fd 100644 --- a/build/pkgs/kissat/package-version.txt +++ b/build/pkgs/kissat/package-version.txt @@ -1 +1 @@ -3.0.0 +3.1.0 diff --git a/build/pkgs/kiwisolver/dependencies b/build/pkgs/kiwisolver/dependencies index 5df13094620..1ba038a9b7a 100644 --- a/build/pkgs/kiwisolver/dependencies +++ b/build/pkgs/kiwisolver/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cppy | $(PYTHON_TOOLCHAIN) + cppy | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/kiwisolver/distros/gentoo.txt b/build/pkgs/kiwisolver/distros/gentoo.txt new file mode 100644 index 00000000000..7b30c9540ec --- /dev/null +++ b/build/pkgs/kiwisolver/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/kiwisolver diff --git a/build/pkgs/kiwisolver/spkg-configure.m4 b/build/pkgs/kiwisolver/spkg-configure.m4 new file mode 100644 index 00000000000..4e7ac97b57d --- /dev/null +++ b/build/pkgs/kiwisolver/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([kiwisolver], [SAGE_PYTHON_PACKAGE_CHECK([kiwisolver])]) diff --git a/build/pkgs/libatomic_ops/SPKG.rst b/build/pkgs/libatomic_ops/SPKG.rst index 5d376f67e91..daa139b9d1b 100644 --- a/build/pkgs/libatomic_ops/SPKG.rst +++ b/build/pkgs/libatomic_ops/SPKG.rst @@ -4,19 +4,21 @@ libatomic_ops: Access hardware-provided atomic memory update operations Description ----------- -A part of the Boehm-Demers-Weiser conservative garbage collector. +This package provides semi-portable access to hardware-provided +atomic memory update operations on a number of architectures. + License ------- -- Permissive BSD + GPL 2.0+ +- MIT + GPL 2.0+ Upstream Contact ---------------- -- Webpage: http://www.hboehm.info/gc/ -- Email List: bdwgc@lists.opendylan.org +https://github.com/ivmai/libatomic_ops/ + Special Update/Build Instructions --------------------------------- diff --git a/build/pkgs/libatomic_ops/checksums.ini b/build/pkgs/libatomic_ops/checksums.ini index 35390b81443..92ac5be4cd5 100644 --- a/build/pkgs/libatomic_ops/checksums.ini +++ b/build/pkgs/libatomic_ops/checksums.ini @@ -1,5 +1,5 @@ tarball=libatomic_ops-VERSION.tar.gz -sha1=ad1c9cd6cc22e042a784e34baa360874083e5f60 -md5=90a78a84d9c28ce11f331c25289bfbd0 -cksum=1553525211 +sha1=69223bbec025a0d57977feb861479f78a5e6c8d7 +md5=a7e51e8041c3e60c298c037b2789c3fa +cksum=596151076 upstream_url=https://github.com/ivmai/libatomic_ops/releases/download/vVERSION/libatomic_ops-VERSION.tar.gz diff --git a/build/pkgs/libatomic_ops/package-version.txt b/build/pkgs/libatomic_ops/package-version.txt index dd812d3580c..09a6d30847d 100644 --- a/build/pkgs/libatomic_ops/package-version.txt +++ b/build/pkgs/libatomic_ops/package-version.txt @@ -1 +1 @@ -7.6.10 +7.8.0 diff --git a/build/pkgs/libbraiding/package-version.txt b/build/pkgs/libbraiding/package-version.txt index 9459d4ba2a0..5625e59da88 100644 --- a/build/pkgs/libbraiding/package-version.txt +++ b/build/pkgs/libbraiding/package-version.txt @@ -1 +1 @@ -1.1 +1.2 diff --git a/build/pkgs/libgd/SPKG.rst b/build/pkgs/libgd/SPKG.rst index cade8ea66c7..e022fa67978 100644 --- a/build/pkgs/libgd/SPKG.rst +++ b/build/pkgs/libgd/SPKG.rst @@ -23,9 +23,4 @@ Upstream Contact - https://libgd.github.io - Pierre Joye (http://blog.thepimp.net) -- http://libgd.bitbucket.org/ - -Special Update/Build Instructions ---------------------------------- - -See spkg-src script. +- https://github.com/libgd/libgd diff --git a/build/pkgs/libgd/checksums.ini b/build/pkgs/libgd/checksums.ini index 0db72cded2e..504b0d2d5be 100644 --- a/build/pkgs/libgd/checksums.ini +++ b/build/pkgs/libgd/checksums.ini @@ -1,5 +1,5 @@ tarball=libgd-VERSION.tar.xz -sha1=dddf5e9d25cb0b20b8642d5cbcfad67f8903532f -md5=0ee844caca06bb02bf4b4dabdfab4fb1 -cksum=902217083 +sha1=7ce6ecb5aed26c08246a37b6351c886ab4b51ca2 +md5=7a58b54d375eda236414201252a0ee3c +cksum=1360697583 upstream_url=https://github.com/libgd/libgd/releases/download/gd-VERSION/libgd-VERSION.tar.xz diff --git a/build/pkgs/libgd/dependencies b/build/pkgs/libgd/dependencies index e2cbc65b7da..f2c5686fb06 100644 --- a/build/pkgs/libgd/dependencies +++ b/build/pkgs/libgd/dependencies @@ -1,4 +1,4 @@ -libpng freetype xz +libpng xz # xz needed to unpack tarball when sage-bootstrap-python is Python < 3.3 ---------- diff --git a/build/pkgs/libgd/package-version.txt b/build/pkgs/libgd/package-version.txt index f90b1afc082..0bee604df76 100644 --- a/build/pkgs/libgd/package-version.txt +++ b/build/pkgs/libgd/package-version.txt @@ -1 +1 @@ -2.3.2 +2.3.3 diff --git a/build/pkgs/libgd/spkg-install.in b/build/pkgs/libgd/spkg-install.in index d291869a923..e314d99d2ab 100644 --- a/build/pkgs/libgd/spkg-install.in +++ b/build/pkgs/libgd/spkg-install.in @@ -2,25 +2,13 @@ cd src export CFLAGS="-g $CFLAGS" -if [ "$UNAME" = "CYGWIN" ]; then - # Compiling with vpx support creates a broken library in some cases - # because the vpx package itself is broken on some older Cygwin versions; - # we don't need this feature so safer to just disable - # https://github.com/sagemath/sage/issues/27970 - LIBGD_CONFIGURE="--without-vpx $LIBGD_CONFIGURE" -fi -if [ -n "$SAGE_FREETYPE_PREFIX" ]; then - LIBGD_CONFIGURE="--with-freetype=$SAGE_FREETYPE_PREFIX $LIBGD_CONFIGURE" -else - LIBGD_CONFIGURE="--with-freetype=yes $LIBGD_CONFIGURE" -fi - -# We explicitly disable X and fontconfig support, since (1) X is not a SAGE dependency, -# and (2) the gd build fails on a lot of OS X PPC machines when X is enabled. -# Also, libgd will try to link against system libavif/libvmaf and fail -# on Fedora 34 +# We explicitly disable X, fontconfig, and support of various formats/libraries. +# We only need png. +# see https://github.com/libgd/libgd/blob/master/configure.ac sdh_configure --without-jpeg --without-xpm --without-x --without-fontconfig \ - --without-avif \ + --without-avif --without-freetype --without-raqm --without-liq \ + --without-tiff --without-webp --without-heif \ + --disable-gd-formats \ --with-zlib="$SAGE_LOCAL" $LIBGD_CONFIGURE sdh_make sdh_make_install diff --git a/build/pkgs/libgd/spkg-src b/build/pkgs/libgd/spkg-src deleted file mode 100755 index 35ee15123f7..00000000000 --- a/build/pkgs/libgd/spkg-src +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -VERSION="2.1.1" - -if [ $# -ne 0 ]; then - UPSTREAM_SOURCE_DIRECTORY=$1 - echo "Using tarballs from $UPSTREAM_SOURCE_DIRECTORY instead of downloading" -fi - -SPKG_ROOT=`pwd` - -set -e -shopt -s extglob - -# Remove old sources and download new -rm -rf gd* - -URL="https://bitbucket.org/libgd/gd-libgd/downloads" -if [ -z "$UPSTREAM_SOURCE_DIRECTORY" ]; then - tar xJf <( curl -L "$URL/libgd-$VERSION.tar.xz" ) -else - tar xJf "$UPSTREAM_SOURCE_DIRECTORY/libgd-$VERSION.tar.xz" -fi - -# Autoreconf it so that it builds correctly on Cygwin64 and ppc64le -cd libgd-$VERSION -rm -f aclocal.m4 Makefile.in configure -autoreconf -fiv -rm -rf autom4te.cache src/config.hin~ -cd $SPKG_ROOT -mv "libgd-$VERSION" src - -# Recompress directory -tar cjf libgd-`sed s/[.]p.*// package-version.txt`.tar.bz2 src diff --git a/build/pkgs/libsemigroups/checksums.ini b/build/pkgs/libsemigroups/checksums.ini index 62c4268515f..4e13a36cb35 100644 --- a/build/pkgs/libsemigroups/checksums.ini +++ b/build/pkgs/libsemigroups/checksums.ini @@ -1,5 +1,5 @@ tarball=libsemigroups-VERSION.tar.gz -sha1=2b16c095cc5ffd3f77a71dfbf48cce188e054c03 -md5=7082cadcf7a195ccb93175cd72b6db95 -cksum=1501022358 +sha1=86375824b47ce4b0e23570122e873f67136d0c0a +md5=ff79ad5fbc8bfeb64d48faaf24106b98 +cksum=2845045455 upstream_url=https://github.com/libsemigroups/libsemigroups/releases/download/vVERSION/libsemigroups-VERSION.tar.gz diff --git a/build/pkgs/libsemigroups/package-version.txt b/build/pkgs/libsemigroups/package-version.txt index 9084fa2f716..f90b1afc082 100644 --- a/build/pkgs/libsemigroups/package-version.txt +++ b/build/pkgs/libsemigroups/package-version.txt @@ -1 +1 @@ -1.1.0 +2.3.2 diff --git a/build/pkgs/libsemigroups/spkg-install.in b/build/pkgs/libsemigroups/spkg-install.in index 2aaf0e99043..128b54d2f99 100644 --- a/build/pkgs/libsemigroups/spkg-install.in +++ b/build/pkgs/libsemigroups/spkg-install.in @@ -1,4 +1,4 @@ cd src -sdh_configure +sdh_configure --disable-eigen sdh_make sdh_make_install diff --git a/build/pkgs/lrcalc_python/dependencies b/build/pkgs/lrcalc_python/dependencies index 27c96045586..d7e0cec0534 100644 --- a/build/pkgs/lrcalc_python/dependencies +++ b/build/pkgs/lrcalc_python/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) lrcalc | $(PYTHON_TOOLCHAIN) cython + lrcalc | $(PYTHON_TOOLCHAIN) cython $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/lrcalc_python/distros/conda.txt b/build/pkgs/lrcalc_python/distros/conda.txt index 3a3af9e524f..4dca5b61e5d 100644 --- a/build/pkgs/lrcalc_python/distros/conda.txt +++ b/build/pkgs/lrcalc_python/distros/conda.txt @@ -1 +1 @@ -python-lrcalc +python-lrcalc~=2.1 diff --git a/build/pkgs/lrcalc_python/spkg-configure.m4 b/build/pkgs/lrcalc_python/spkg-configure.m4 new file mode 100644 index 00000000000..c29476b742b --- /dev/null +++ b/build/pkgs/lrcalc_python/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([lrcalc_python], [SAGE_PYTHON_PACKAGE_CHECK([lrcalc_python])]) diff --git a/build/pkgs/markupsafe/dependencies b/build/pkgs/markupsafe/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/markupsafe/dependencies +++ b/build/pkgs/markupsafe/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/markupsafe/distros/gentoo.txt b/build/pkgs/markupsafe/distros/gentoo.txt new file mode 100644 index 00000000000..9654e3531b6 --- /dev/null +++ b/build/pkgs/markupsafe/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/markupsafe diff --git a/build/pkgs/markupsafe/distros/opensuse.txt b/build/pkgs/markupsafe/distros/opensuse.txt index 483c7ee1e18..8c103c6b5e5 100644 --- a/build/pkgs/markupsafe/distros/opensuse.txt +++ b/build/pkgs/markupsafe/distros/opensuse.txt @@ -1 +1 @@ -python3-MarkupSafe +python3${PYTHON_MINOR}-MarkupSafe diff --git a/build/pkgs/markupsafe/install-requires.txt b/build/pkgs/markupsafe/install-requires.txt index 331f488e6a0..7d44bce10e1 100644 --- a/build/pkgs/markupsafe/install-requires.txt +++ b/build/pkgs/markupsafe/install-requires.txt @@ -1 +1 @@ -markupsafe >=1.1.0 +markupsafe >=2.0 diff --git a/build/pkgs/markupsafe/spkg-configure.m4 b/build/pkgs/markupsafe/spkg-configure.m4 new file mode 100644 index 00000000000..79eb8dba6f1 --- /dev/null +++ b/build/pkgs/markupsafe/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([markupsafe], [SAGE_PYTHON_PACKAGE_CHECK([markupsafe])]) diff --git a/build/pkgs/mathics/dependencies b/build/pkgs/mathics/dependencies index ac723a5ac26..11d5626d8c7 100644 --- a/build/pkgs/mathics/dependencies +++ b/build/pkgs/mathics/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) pint palettable mathics_scanner + | $(PYTHON_TOOLCHAIN) pint palettable mathics_scanner $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/mathics_scanner/dependencies b/build/pkgs/mathics_scanner/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/mathics_scanner/dependencies +++ b/build/pkgs/mathics_scanner/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/mathjax/checksums.ini b/build/pkgs/mathjax/checksums.ini index 76e362f6b28..6a6b233b2ae 100644 --- a/build/pkgs/mathjax/checksums.ini +++ b/build/pkgs/mathjax/checksums.ini @@ -2,4 +2,3 @@ tarball=mathjax-VERSION.tar.gz sha1=3f7abecf8cacd7f5d7f9ae6c3baca7739101c17d md5=ba1a65ab58aaad6c84f39735c619bc34 cksum=1142131398 -upstream_url=https://trac.sagemath.org/raw-attachment/ticket/25833/mathjax-3.2.0.tar.gz diff --git a/build/pkgs/mathjax/distros/gentoo.txt b/build/pkgs/mathjax/distros/gentoo.txt new file mode 100644 index 00000000000..a347f8c2348 --- /dev/null +++ b/build/pkgs/mathjax/distros/gentoo.txt @@ -0,0 +1 @@ +">=dev-libs/mathjax-3" diff --git a/build/pkgs/mathjax/spkg-configure.m4 b/build/pkgs/mathjax/spkg-configure.m4 new file mode 100644 index 00000000000..70fb46a2067 --- /dev/null +++ b/build/pkgs/mathjax/spkg-configure.m4 @@ -0,0 +1,26 @@ +SAGE_SPKG_CONFIGURE([mathjax], [ + # Arch: /usr/share/mathjax + # Gentoo: /usr/share/mathjax + # Void: /usr/share/mathjax + AC_MSG_CHECKING([for MathJax-3.x]) + m4_foreach([mathjax_dir], [/usr/share/mathjax], [ + # tex-chtml.hs is used in src/sage_docbuild/conf.py + # and was not present in MathJax-2.x + AS_IF([test -f "mathjax_dir/tex-chtml.js"], [ + SAGE_MATHJAX_DIR="mathjax_dir" + AC_MSG_RESULT([mathjax_dir]) + ]) + ]) + AS_IF([test -z "${SAGE_MATHJAX_DIR}"], [ + AC_MSG_RESULT([no]) + sage_spkg_install_mathjax=yes + ]) +],[],[],[ + # post-check + AS_IF([test x$sage_spkg_install_mathjax = xyes], [ + # Our spkg-src script adds an extra "mathjax" + SAGE_MATHJAX_DIR='${prefix}'/share/mathjax/mathjax + ]) + + AC_SUBST(SAGE_MATHJAX_DIR, "${SAGE_MATHJAX_DIR}") +]) diff --git a/build/pkgs/matplotlib/dependencies b/build/pkgs/matplotlib/dependencies index cfcf3edda7e..8abcba00ee8 100644 --- a/build/pkgs/matplotlib/dependencies +++ b/build/pkgs/matplotlib/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) numpy freetype pillow dateutil pyparsing tornado six cycler qhull fonttools contourpy | $(PYTHON_TOOLCHAIN) kiwisolver certifi setuptools_scm_git_archive + numpy freetype pillow dateutil pyparsing tornado cycler qhull fonttools contourpy | $(PYTHON_TOOLCHAIN) kiwisolver certifi setuptools_scm $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/matplotlib/distros/arch.txt b/build/pkgs/matplotlib/distros/arch.txt new file mode 100644 index 00000000000..f6d856e585c --- /dev/null +++ b/build/pkgs/matplotlib/distros/arch.txt @@ -0,0 +1 @@ +python-matplotlib diff --git a/build/pkgs/matplotlib/distros/debian.txt b/build/pkgs/matplotlib/distros/debian.txt new file mode 100644 index 00000000000..13743297213 --- /dev/null +++ b/build/pkgs/matplotlib/distros/debian.txt @@ -0,0 +1 @@ +python3-matplotlib diff --git a/build/pkgs/matplotlib/distros/fedora.txt b/build/pkgs/matplotlib/distros/fedora.txt new file mode 100644 index 00000000000..f6d856e585c --- /dev/null +++ b/build/pkgs/matplotlib/distros/fedora.txt @@ -0,0 +1 @@ +python-matplotlib diff --git a/build/pkgs/matplotlib/distros/gentoo.txt b/build/pkgs/matplotlib/distros/gentoo.txt new file mode 100644 index 00000000000..bcfefb5fcc4 --- /dev/null +++ b/build/pkgs/matplotlib/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/matplotlib diff --git a/build/pkgs/matplotlib/distros/opensuse.txt b/build/pkgs/matplotlib/distros/opensuse.txt index 13743297213..40f1130ec6f 100644 --- a/build/pkgs/matplotlib/distros/opensuse.txt +++ b/build/pkgs/matplotlib/distros/opensuse.txt @@ -1 +1 @@ -python3-matplotlib +python3${PYTHON_MINOR}-matplotlib diff --git a/build/pkgs/matplotlib/spkg-configure.m4 b/build/pkgs/matplotlib/spkg-configure.m4 new file mode 100644 index 00000000000..39c2d2901d0 --- /dev/null +++ b/build/pkgs/matplotlib/spkg-configure.m4 @@ -0,0 +1,5 @@ +SAGE_SPKG_CONFIGURE([matplotlib], [ + SAGE_SPKG_DEPCHECK([bzip2 freetype libpng qhull], [ + SAGE_PYTHON_PACKAGE_CHECK([matplotlib]) + ]) +]) diff --git a/build/pkgs/matplotlib_inline/dependencies b/build/pkgs/matplotlib_inline/dependencies index 1da34eeae60..a1a8daa948c 100644 --- a/build/pkgs/matplotlib_inline/dependencies +++ b/build/pkgs/matplotlib_inline/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) traitlets | $(PYTHON_TOOLCHAIN) + traitlets | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/matplotlib_inline/distros/gentoo.txt b/build/pkgs/matplotlib_inline/distros/gentoo.txt new file mode 100644 index 00000000000..6a5859ca074 --- /dev/null +++ b/build/pkgs/matplotlib_inline/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/matplotlib-inline diff --git a/build/pkgs/matplotlib_inline/spkg-configure.m4 b/build/pkgs/matplotlib_inline/spkg-configure.m4 new file mode 100644 index 00000000000..e59658ff159 --- /dev/null +++ b/build/pkgs/matplotlib_inline/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([matplotlib_inline], [ + SAGE_PYTHON_PACKAGE_CHECK([matplotlib_inline]) +]) diff --git a/build/pkgs/maxima/checksums.ini b/build/pkgs/maxima/checksums.ini index a804c7b831f..0f594389fe6 100644 --- a/build/pkgs/maxima/checksums.ini +++ b/build/pkgs/maxima/checksums.ini @@ -1,5 +1,5 @@ tarball=maxima-VERSION.tar.gz -sha1=ed15d5285794413ba94412079eca3d0fa55a47bf -md5=9b9ae1dace55b1386739dabaa9122e60 -cksum=1765409766 +sha1=1010594e6d6082bbd8efaac1b7756ec1721a4ed5 +md5=3c01f1daa6936e11d8713fef7751d3fe +cksum=2420393096 upstream_url=https://sourceforge.net/projects/maxima/files/Maxima-source/VERSION-source/maxima-VERSION.tar.gz/download diff --git a/build/pkgs/maxima/dependencies_order_only b/build/pkgs/maxima/dependencies_order_only new file mode 100644 index 00000000000..55021245387 --- /dev/null +++ b/build/pkgs/maxima/dependencies_order_only @@ -0,0 +1 @@ +info diff --git a/build/pkgs/maxima/distros/arch.txt b/build/pkgs/maxima/distros/arch.txt index 6400290f44d..6ac052fa62b 100644 --- a/build/pkgs/maxima/distros/arch.txt +++ b/build/pkgs/maxima/distros/arch.txt @@ -1 +1 @@ -maxima-ecl +maxima-fas diff --git a/build/pkgs/maxima/distros/cygwin.txt b/build/pkgs/maxima/distros/cygwin.txt new file mode 100644 index 00000000000..f5fe3fdc6cb --- /dev/null +++ b/build/pkgs/maxima/distros/cygwin.txt @@ -0,0 +1 @@ +maxima diff --git a/build/pkgs/maxima/distros/freebsd.txt b/build/pkgs/maxima/distros/freebsd.txt new file mode 100644 index 00000000000..766a71b5074 --- /dev/null +++ b/build/pkgs/maxima/distros/freebsd.txt @@ -0,0 +1 @@ +math/maxima diff --git a/build/pkgs/maxima/distros/gentoo.txt b/build/pkgs/maxima/distros/gentoo.txt new file mode 100644 index 00000000000..85fb33f1610 --- /dev/null +++ b/build/pkgs/maxima/distros/gentoo.txt @@ -0,0 +1,2 @@ +sci-mathematics/maxima[ecls] + diff --git a/build/pkgs/maxima/package-version.txt b/build/pkgs/maxima/package-version.txt index 83476624dc0..5681375f3be 100644 --- a/build/pkgs/maxima/package-version.txt +++ b/build/pkgs/maxima/package-version.txt @@ -1 +1 @@ -5.45.0.p0 +5.46.0 diff --git a/build/pkgs/maxima/patches/matrixexp.patch b/build/pkgs/maxima/patches/matrixexp.patch deleted file mode 100644 index 5c8527c33bf..00000000000 --- a/build/pkgs/maxima/patches/matrixexp.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/share/linearalgebra/matrixexp.lisp b/share/linearalgebra/matrixexp.lisp -index 218bf35..f2fd468 100644 ---- a/share/linearalgebra/matrixexp.lisp -+++ b/share/linearalgebra/matrixexp.lisp -@@ -138,8 +138,8 @@ - (print `(ratvars = ,$ratvars gcd = '$gcd algebraic = ,$algebraic)) - (print `(ratfac = ,$ratfac)) - (merror "Unable to find the spectrum"))) -- -- (setq res ($fullratsimp (ncpower (sub (mult z ($ident n)) mat) -1) z)) -+ -+ (setq res ($fullratsimp ($invert_by_lu (sub (mult z ($ident n)) mat) '$crering) z)) - (setq m (length sp)) - (dotimes (i m) - (setq zi (nth i sp)) diff --git a/build/pkgs/maxima/patches/maxima.system.patch b/build/pkgs/maxima/patches/maxima.system.patch deleted file mode 100644 index 74db62e7f9f..00000000000 --- a/build/pkgs/maxima/patches/maxima.system.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/src/maxima.system b/src/maxima.system -index 76f2452..cf25f51 100644 ---- a/src/maxima.system -+++ b/src/maxima.system -@@ -1,5 +1,8 @@ - ;;; -*- Lisp -*- - -+(require :cmp) -+(setf c::*compile-in-constants* t) -+ - (in-package :cl-user) - - (pushnew :cl *features*) -@@ -75,6 +78,11 @@ - ;; Convert dir/foo.fas to dir/foo.o - (make-pathname :type "o" :defaults p)) - files))) -+ (c::build-fasl "binary-ecl/maxima" :lisp-files obj -+ :ld-flags -+ (let ((x (symbol-value (find-symbol "*AUTOCONF-LD-FLAGS*" -+ (find-package "MAXIMA"))))) -+ (if (and x (not (string= x ""))) (list x)))) - (c::build-program "binary-ecl/maxima" :lisp-files obj - :ld-flags - (let ((x (symbol-value (find-symbol "*AUTOCONF-LD-FLAGS*" diff --git a/build/pkgs/maxima/spkg-configure.m4 b/build/pkgs/maxima/spkg-configure.m4 new file mode 100644 index 00000000000..86de8c1dfc1 --- /dev/null +++ b/build/pkgs/maxima/spkg-configure.m4 @@ -0,0 +1,46 @@ +SAGE_SPKG_CONFIGURE([maxima], [ + m4_pushdef([SAGE_MAXIMA_MINVER],["5.45.0"])dnl this version and higher allowed + SAGE_SPKG_DEPCHECK([ecl], [ + dnl First check for the "maxima" executable in the user's PATH, because + dnl we still use pexpect to communicate with it in a few places. + AC_CACHE_CHECK([for Maxima >= $SAGE_MAXIMA_MINVER], [ac_cv_path_MAXIMA], [ + AC_PATH_PROGS_FEATURE_CHECK([MAXIMA], [maxima], [ + maxima_version=`$ac_path_MAXIMA --version 2>&1 | tail -n 1\ + | $SED -n -e 's/Maxima *\([[0-9]]*\.[[0-9]]*\.[[0-9]]*\)/\1/p'` + AS_IF([test -n "$maxima_version"], [ + AX_COMPARE_VERSION([$maxima_version], [ge], [SAGE_MAXIMA_MINVER], [ + ac_cv_path_MAXIMA="$ac_path_MAXIMA" + ac_path_MAXIMA_found=: + ]) + ]) + ]) + ]) + SAGE_MAXIMA="$ac_cv_path_MAXIMA" + AS_IF([test -z "${SAGE_MAXIMA}"], [ + sage_spkg_install_maxima=yes + ],[ + dnl If we have the executable, check also for the ECL library. + AC_MSG_CHECKING([if ECL can "require" the maxima module]) + AS_IF([ecl --eval "(require 'maxima)" --eval "(quit)" \ + >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD], [ + AC_MSG_RESULT(yes) + ], [ + AC_MSG_RESULT(no) + sage_spkg_install_maxima=yes + ]) + ]) + ]) + m4_popdef([SAGE_MAXIMA_MINVER]) +],[],[],[ + # post-check + AS_IF([test x$sage_spkg_install_maxima = xyes], [ + dnl Leaving this variable empty will tell sagelib to load + dnl the maxima library (within ECL) by name instead of by + dnl absolute path. + SAGE_MAXIMA='${prefix}'/bin/maxima + SAGE_MAXIMA_FAS='${prefix}'/lib/ecl/maxima.fas + ]) + + AC_SUBST(SAGE_MAXIMA, "${SAGE_MAXIMA}") + AC_SUBST(SAGE_MAXIMA_FAS, "${SAGE_MAXIMA_FAS}") +]) diff --git a/build/pkgs/maxima/spkg-install.in b/build/pkgs/maxima/spkg-install.in index 3ae6382f9ba..ef044cbf010 100644 --- a/build/pkgs/maxima/spkg-install.in +++ b/build/pkgs/maxima/spkg-install.in @@ -20,6 +20,10 @@ cd src/ # Use newer version of config.guess and config.sub (see Trac #19734) cp "$SAGE_ROOT"/config/config.* . +# Patch out bad 'multiple targets' rule +# https://github.com/sagemath/sage/pull/35619#issuecomment-1567351409 +sed -i.bak 's/^maxima_singlepage.html //' doc/info/Makefile.in + # Note that maxima configure checks for git and, if it finds it, uses # versions information from the repo. See #15529. We disable this with # git_found=false @@ -28,28 +32,6 @@ echo echo "Now configuring Maxima..." sdh_configure --enable-ecl git_found=false -# Note the following is regression in maxima build system -# see https://sourceforge.net/p/maxima/bugs/3278/ -# and https://sourceforge.net/p/maxima/bugs/2878/ -# For the previous time it was fixed. -#--------------------------------------------------------------- -# Touching html and info file to avoid to regenerate them. -# This must be done after configuration since the timestamp need -# to be later than include-maxima.texi which is generated at -# configuration time -for i in doc/info/*.html ; do - touch "${i}" -done -touch doc/info/maxima.info* -# Maxima 5.44.0 build_html.sh is not compatible with makeinfo 4.8 -# (which is /usr/bin/makeinfo on macOS). #30063 -# Do not build the HTML docs unless the user asks for it, -# in which case it is their problem to install a better -# makeinfo version. -if [[ "$SAGE_SPKG_INSTALL_DOCS" != yes ]] ; then -touch doc/info/maxima_toc.html interfaces/xmaxima/doc/xmaxima.html -fi - #--------------------------------------------------------------- sdh_make diff --git a/build/pkgs/memory_allocator/dependencies b/build/pkgs/memory_allocator/dependencies index 296a2bebad3..1db13c07e43 100644 --- a/build/pkgs/memory_allocator/dependencies +++ b/build/pkgs/memory_allocator/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cython | $(PYTHON_TOOLCHAIN) + cython | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/meson/checksums.ini b/build/pkgs/meson/checksums.ini index 39f0a42c527..ef8b1ec0b21 100644 --- a/build/pkgs/meson/checksums.ini +++ b/build/pkgs/meson/checksums.ini @@ -1,5 +1,5 @@ tarball=meson-VERSION.tar.gz -sha1=3bce963302f547547c82fda35f84838ebc608e8a -md5=b2f2757b5dd84cc754b9df53ce37a175 -cksum=2257545181 +sha1=087da0ecbc065bb40361ba683b55c20cb42a948a +md5=e3cc846536189aacd7d01858a45ca9af +cksum=4011973902 upstream_url=https://pypi.io/packages/source/m/meson/meson-VERSION.tar.gz diff --git a/build/pkgs/meson/dependencies b/build/pkgs/meson/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/meson/dependencies +++ b/build/pkgs/meson/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/meson/package-version.txt b/build/pkgs/meson/package-version.txt index 068337d8307..6085e946503 100644 --- a/build/pkgs/meson/package-version.txt +++ b/build/pkgs/meson/package-version.txt @@ -1 +1 @@ -0.63.3 +1.2.1 diff --git a/build/pkgs/meson/spkg-configure.m4 b/build/pkgs/meson/spkg-configure.m4 index 3fbcf288065..dbc575650fc 100644 --- a/build/pkgs/meson/spkg-configure.m4 +++ b/build/pkgs/meson/spkg-configure.m4 @@ -1,10 +1,11 @@ SAGE_SPKG_CONFIGURE( [meson], [ - AC_CACHE_CHECK([for meson >= 0.63.3], [ac_cv_path_MESON], [ + dnl scipy 1.11.2 needs meson >= 1.1.0 + AC_CACHE_CHECK([for meson >= 1.1.0], [ac_cv_path_MESON], [ AC_PATH_PROGS_FEATURE_CHECK([MESON], [meson], [ meson_version=`$ac_path_MESON --version 2>&1` AS_IF([test -n "$meson_version"], [ - AX_COMPARE_VERSION([$meson_version], [ge], [0.63.3], [ + AX_COMPARE_VERSION([$meson_version], [ge], [1.1.0], [ ac_cv_path_MESON="$ac_path_MESON" ac_path_MESON_found=: ]) diff --git a/build/pkgs/meson_python/checksums.ini b/build/pkgs/meson_python/checksums.ini index fa69cec7dca..da59c9577aa 100644 --- a/build/pkgs/meson_python/checksums.ini +++ b/build/pkgs/meson_python/checksums.ini @@ -1,5 +1,5 @@ tarball=meson_python-VERSION.tar.gz -sha1=09035196e1576073a7e4acac1f010e5e07e55f89 -md5=60856897b63bc91e1f953bf29f410be4 -cksum=3201302061 +sha1=e52e84fcd84ea7dd8c11f464390786686a1be8e6 +md5=0db4483e30df43dbd465254be9c7db8a +cksum=1452585711 upstream_url=https://pypi.io/packages/source/m/meson_python/meson_python-VERSION.tar.gz diff --git a/build/pkgs/meson_python/dependencies b/build/pkgs/meson_python/dependencies index 160adbf36c9..01b5cb597b0 100644 --- a/build/pkgs/meson_python/dependencies +++ b/build/pkgs/meson_python/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) meson pyproject_metadata tomli ninja_build patchelf | $(PYTHON_TOOLCHAIN) + meson pyproject_metadata tomli ninja_build patchelf | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/meson_python/distros/alpine.txt b/build/pkgs/meson_python/distros/alpine.txt new file mode 100644 index 00000000000..248216b1fdc --- /dev/null +++ b/build/pkgs/meson_python/distros/alpine.txt @@ -0,0 +1 @@ +py3-meson-python diff --git a/build/pkgs/meson_python/distros/arch.txt b/build/pkgs/meson_python/distros/arch.txt new file mode 100644 index 00000000000..9705cab644e --- /dev/null +++ b/build/pkgs/meson_python/distros/arch.txt @@ -0,0 +1 @@ +meson-python diff --git a/build/pkgs/meson_python/distros/debian.txt b/build/pkgs/meson_python/distros/debian.txt new file mode 100644 index 00000000000..9705cab644e --- /dev/null +++ b/build/pkgs/meson_python/distros/debian.txt @@ -0,0 +1 @@ +meson-python diff --git a/build/pkgs/meson_python/distros/fedora.txt b/build/pkgs/meson_python/distros/fedora.txt new file mode 100644 index 00000000000..17b4e0c04c5 --- /dev/null +++ b/build/pkgs/meson_python/distros/fedora.txt @@ -0,0 +1 @@ +python-meson-python diff --git a/build/pkgs/meson_python/distros/freebsd.txt b/build/pkgs/meson_python/distros/freebsd.txt new file mode 100644 index 00000000000..5609e7545cf --- /dev/null +++ b/build/pkgs/meson_python/distros/freebsd.txt @@ -0,0 +1 @@ +devel/meson-python diff --git a/build/pkgs/meson_python/distros/gentoo.txt b/build/pkgs/meson_python/distros/gentoo.txt new file mode 100644 index 00000000000..0dec932b5b3 --- /dev/null +++ b/build/pkgs/meson_python/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/meson-python diff --git a/build/pkgs/meson_python/distros/opensuse.txt b/build/pkgs/meson_python/distros/opensuse.txt new file mode 100644 index 00000000000..17b4e0c04c5 --- /dev/null +++ b/build/pkgs/meson_python/distros/opensuse.txt @@ -0,0 +1 @@ +python-meson-python diff --git a/build/pkgs/meson_python/distros/void.txt b/build/pkgs/meson_python/distros/void.txt new file mode 100644 index 00000000000..93dae9570a4 --- /dev/null +++ b/build/pkgs/meson_python/distros/void.txt @@ -0,0 +1 @@ +python3-meson-python diff --git a/build/pkgs/meson_python/package-version.txt b/build/pkgs/meson_python/package-version.txt index d9df1bbc0c7..9beb74d490b 100644 --- a/build/pkgs/meson_python/package-version.txt +++ b/build/pkgs/meson_python/package-version.txt @@ -1 +1 @@ -0.11.0 +0.13.2 diff --git a/build/pkgs/meson_python/spkg-configure.m4 b/build/pkgs/meson_python/spkg-configure.m4 new file mode 100644 index 00000000000..69a5eb89a85 --- /dev/null +++ b/build/pkgs/meson_python/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([meson_python], [ + SAGE_PYTHON_PACKAGE_CHECK([meson_python]) +]) diff --git a/build/pkgs/mistune/dependencies b/build/pkgs/mistune/dependencies index 296a2bebad3..1db13c07e43 100644 --- a/build/pkgs/mistune/dependencies +++ b/build/pkgs/mistune/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cython | $(PYTHON_TOOLCHAIN) + cython | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/mistune/distros/gentoo.txt b/build/pkgs/mistune/distros/gentoo.txt new file mode 100644 index 00000000000..56f0a4ebced --- /dev/null +++ b/build/pkgs/mistune/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/mistune diff --git a/build/pkgs/mistune/spkg-configure.m4 b/build/pkgs/mistune/spkg-configure.m4 new file mode 100644 index 00000000000..972f33d086b --- /dev/null +++ b/build/pkgs/mistune/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([mistune], [SAGE_PYTHON_PACKAGE_CHECK([mistune])]) diff --git a/build/pkgs/mpmath/SPKG.rst b/build/pkgs/mpmath/SPKG.rst index 279d47a0318..6fea444608c 100644 --- a/build/pkgs/mpmath/SPKG.rst +++ b/build/pkgs/mpmath/SPKG.rst @@ -20,6 +20,6 @@ Upstream Contact - Author: Fredrik Johansson - Email: fredrik.johansson@gmail.com -- http://mpmath.org -- Website: https://github.com/fredrik-johansson/mpmath/ +- https://mpmath.org +- Website: https://github.com/mpmath/mpmath diff --git a/build/pkgs/mpmath/checksums.ini b/build/pkgs/mpmath/checksums.ini index 1313275f20e..08d6d38673d 100644 --- a/build/pkgs/mpmath/checksums.ini +++ b/build/pkgs/mpmath/checksums.ini @@ -1,5 +1,5 @@ tarball=mpmath-VERSION.tar.gz -sha1=ce8bd24606eeb02218b26304e6d99228919021f8 -md5=ef8a6449851755319673b06f71731d52 -cksum=3549837503 +sha1=b7c00f35eb35978197c8f5afc11a8b4b994dd382 +md5=d5d17bbefea73eeb959967351d905306 +cksum=1852385672 upstream_url=https://files.pythonhosted.org/packages/source/m/mpmath/mpmath-VERSION.tar.gz diff --git a/build/pkgs/mpmath/dependencies b/build/pkgs/mpmath/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/mpmath/dependencies +++ b/build/pkgs/mpmath/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/mpmath/distros/arch.txt b/build/pkgs/mpmath/distros/arch.txt new file mode 100644 index 00000000000..a7dc8d568f3 --- /dev/null +++ b/build/pkgs/mpmath/distros/arch.txt @@ -0,0 +1 @@ +python-mpmath diff --git a/build/pkgs/mpmath/distros/debian.txt b/build/pkgs/mpmath/distros/debian.txt new file mode 100644 index 00000000000..fbc82a97e07 --- /dev/null +++ b/build/pkgs/mpmath/distros/debian.txt @@ -0,0 +1 @@ +python3-mpmath diff --git a/build/pkgs/mpmath/distros/fedora.txt b/build/pkgs/mpmath/distros/fedora.txt new file mode 100644 index 00000000000..a7dc8d568f3 --- /dev/null +++ b/build/pkgs/mpmath/distros/fedora.txt @@ -0,0 +1 @@ +python-mpmath diff --git a/build/pkgs/mpmath/distros/gentoo.txt b/build/pkgs/mpmath/distros/gentoo.txt new file mode 100644 index 00000000000..946c62d9e1a --- /dev/null +++ b/build/pkgs/mpmath/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/mpmath diff --git a/build/pkgs/mpmath/distros/opensuse.txt b/build/pkgs/mpmath/distros/opensuse.txt new file mode 100644 index 00000000000..8b65d97862d --- /dev/null +++ b/build/pkgs/mpmath/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-mpmath diff --git a/build/pkgs/mpmath/package-version.txt b/build/pkgs/mpmath/package-version.txt index 6085e946503..f0bb29e7638 100644 --- a/build/pkgs/mpmath/package-version.txt +++ b/build/pkgs/mpmath/package-version.txt @@ -1 +1 @@ -1.2.1 +1.3.0 diff --git a/build/pkgs/mpmath/spkg-configure.m4 b/build/pkgs/mpmath/spkg-configure.m4 new file mode 100644 index 00000000000..f43c8388264 --- /dev/null +++ b/build/pkgs/mpmath/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([mpmath], [SAGE_PYTHON_PACKAGE_CHECK([mpmath])]) diff --git a/build/pkgs/msolve/SPKG.rst b/build/pkgs/msolve/SPKG.rst index 00c1c417208..17f4802b4b1 100644 --- a/build/pkgs/msolve/SPKG.rst +++ b/build/pkgs/msolve/SPKG.rst @@ -16,6 +16,3 @@ Upstream Contact ---------------- https://github.com/algebraic-solving/msolve - -Upstream does not make source tarballs. -We make tarballs from the fork https://github.com/mkoeppe/msolve (branch 0.4.4+sage) diff --git a/build/pkgs/msolve/checksums.ini b/build/pkgs/msolve/checksums.ini index 0b7558afd2b..ae12f77abc9 100644 --- a/build/pkgs/msolve/checksums.ini +++ b/build/pkgs/msolve/checksums.ini @@ -1,5 +1,5 @@ tarball=msolve-VERSION.tar.gz -sha1=5b227de8b222bfe8d143e1d7ea77ad71cd209dc8 -md5=2f34bd9ccb089688ae169201281108dc -cksum=941373315 -upstream_url=https://trac.sagemath.org/raw-attachment/ticket/31664/msolve-VERSION.tar.gz +sha1=bfd1d4f2e5dc0eb321592b3add6665a9d3eadf8c +md5=33a16c21ea8dea9e796d40f1dfd52fa9 +cksum=117017965 +upstream_url=https://github.com/algebraic-solving/msolve/releases/download/vVERSION/msolve-VERSION.tar.gz diff --git a/build/pkgs/msolve/package-version.txt b/build/pkgs/msolve/package-version.txt index fb78594e923..8f0916f768f 100644 --- a/build/pkgs/msolve/package-version.txt +++ b/build/pkgs/msolve/package-version.txt @@ -1 +1 @@ -0.4.4+sage-2022-09-11 +0.5.0 diff --git a/build/pkgs/nbclient/dependencies b/build/pkgs/nbclient/dependencies index e21070fd3af..acec3fadace 100644 --- a/build/pkgs/nbclient/dependencies +++ b/build/pkgs/nbclient/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) jupyter_client nbformat | $(PYTHON_TOOLCHAIN) + jupyter_client nbformat | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/nbclient/distros/gentoo.txt b/build/pkgs/nbclient/distros/gentoo.txt new file mode 100644 index 00000000000..06ff18d206a --- /dev/null +++ b/build/pkgs/nbclient/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/nbclient diff --git a/build/pkgs/nbclient/spkg-configure.m4 b/build/pkgs/nbclient/spkg-configure.m4 new file mode 100644 index 00000000000..14178b793d2 --- /dev/null +++ b/build/pkgs/nbclient/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([nbclient], [SAGE_PYTHON_PACKAGE_CHECK([nbclient])]) diff --git a/build/pkgs/nbconvert/dependencies b/build/pkgs/nbconvert/dependencies index b423493e603..4a7730e8e9f 100644 --- a/build/pkgs/nbconvert/dependencies +++ b/build/pkgs/nbconvert/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) mistune jinja2 pygments traitlets jupyter_core nbformat entrypoints bleach pandocfilters defusedxml jupyter_client jupyterlab_pygments nbclient beautifulsoup4 markupsafe | $(PYTHON_TOOLCHAIN) +mistune jinja2 pygments traitlets jupyter_core nbformat entrypoints bleach pandocfilters defusedxml jupyter_client jupyterlab_pygments nbclient beautifulsoup4 markupsafe tinycss2 | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/nbconvert/distros/gentoo.txt b/build/pkgs/nbconvert/distros/gentoo.txt new file mode 100644 index 00000000000..6c45a107368 --- /dev/null +++ b/build/pkgs/nbconvert/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/nbconvert diff --git a/build/pkgs/nbconvert/spkg-configure.m4 b/build/pkgs/nbconvert/spkg-configure.m4 new file mode 100644 index 00000000000..9b5dee3b8b5 --- /dev/null +++ b/build/pkgs/nbconvert/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([nbconvert], [SAGE_PYTHON_PACKAGE_CHECK([nbconvert])]) diff --git a/build/pkgs/nbformat/dependencies b/build/pkgs/nbformat/dependencies index 6c8921f1382..a6f9cc5f425 100644 --- a/build/pkgs/nbformat/dependencies +++ b/build/pkgs/nbformat/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) jsonschema fastjsonschema jupyter_core traitlets | $(PYTHON_TOOLCHAIN) hatchling hatch_nodejs_version + jsonschema fastjsonschema jupyter_core traitlets | $(PYTHON_TOOLCHAIN) hatchling hatch_nodejs_version $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/nbformat/distros/gentoo.txt b/build/pkgs/nbformat/distros/gentoo.txt new file mode 100644 index 00000000000..006b1f2fc6d --- /dev/null +++ b/build/pkgs/nbformat/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/nbformat diff --git a/build/pkgs/nbformat/spkg-configure.m4 b/build/pkgs/nbformat/spkg-configure.m4 new file mode 100644 index 00000000000..5a7f8c4ccec --- /dev/null +++ b/build/pkgs/nbformat/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([nbformat], [SAGE_PYTHON_PACKAGE_CHECK([nbformat])]) diff --git a/build/pkgs/nest_asyncio/dependencies b/build/pkgs/nest_asyncio/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/nest_asyncio/dependencies +++ b/build/pkgs/nest_asyncio/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/nest_asyncio/distros/gentoo.txt b/build/pkgs/nest_asyncio/distros/gentoo.txt new file mode 100644 index 00000000000..ab742d2b0bd --- /dev/null +++ b/build/pkgs/nest_asyncio/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/nest_asyncio diff --git a/build/pkgs/nest_asyncio/spkg-configure.m4 b/build/pkgs/nest_asyncio/spkg-configure.m4 new file mode 100644 index 00000000000..4d815276dfb --- /dev/null +++ b/build/pkgs/nest_asyncio/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([nest_asyncio], [SAGE_PYTHON_PACKAGE_CHECK([nest_asyncio])]) diff --git a/build/pkgs/networkx/checksums.ini b/build/pkgs/networkx/checksums.ini index 00b6f1fa335..dd792a15a2e 100644 --- a/build/pkgs/networkx/checksums.ini +++ b/build/pkgs/networkx/checksums.ini @@ -1,5 +1,5 @@ tarball=networkx-VERSION.tar.gz -sha1=40e981041664856ba473c9079006367ed0d0e71b -md5=22139ab5a47818fa00cbaa91eb126381 -cksum=4201985987 +sha1=d4b1d6117b7c54db61f6cbec8f0ccfb0f7d47293 +md5=1a9baa93b7fd4470c80e29a7a6d93ccf +cksum=1675580484 upstream_url=https://pypi.io/packages/source/n/networkx/networkx-VERSION.tar.gz diff --git a/build/pkgs/networkx/dependencies b/build/pkgs/networkx/dependencies index 8eb6920e25d..f8dc78f0bf4 100644 --- a/build/pkgs/networkx/dependencies +++ b/build/pkgs/networkx/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) decorator | $(PYTHON_TOOLCHAIN) scipy + | $(PYTHON_TOOLCHAIN) scipy $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/networkx/distros/arch.txt b/build/pkgs/networkx/distros/arch.txt new file mode 100644 index 00000000000..293f943529a --- /dev/null +++ b/build/pkgs/networkx/distros/arch.txt @@ -0,0 +1 @@ +python-networkx diff --git a/build/pkgs/networkx/distros/conda.txt b/build/pkgs/networkx/distros/conda.txt index 4d07dfe2f85..67cbec89b21 100644 --- a/build/pkgs/networkx/distros/conda.txt +++ b/build/pkgs/networkx/distros/conda.txt @@ -1 +1 @@ -networkx +networkx<3.0,>=2.4 diff --git a/build/pkgs/networkx/distros/debian.txt b/build/pkgs/networkx/distros/debian.txt new file mode 100644 index 00000000000..67790667af2 --- /dev/null +++ b/build/pkgs/networkx/distros/debian.txt @@ -0,0 +1 @@ +python3-networkx diff --git a/build/pkgs/networkx/distros/fedora.txt b/build/pkgs/networkx/distros/fedora.txt new file mode 100644 index 00000000000..293f943529a --- /dev/null +++ b/build/pkgs/networkx/distros/fedora.txt @@ -0,0 +1 @@ +python-networkx diff --git a/build/pkgs/networkx/distros/gentoo.txt b/build/pkgs/networkx/distros/gentoo.txt new file mode 100644 index 00000000000..dd97742cff8 --- /dev/null +++ b/build/pkgs/networkx/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/networkx diff --git a/build/pkgs/networkx/distros/opensuse.txt b/build/pkgs/networkx/distros/opensuse.txt index 67790667af2..7c421f08d48 100644 --- a/build/pkgs/networkx/distros/opensuse.txt +++ b/build/pkgs/networkx/distros/opensuse.txt @@ -1 +1 @@ -python3-networkx +python3${PYTHON_MINOR}-networkx diff --git a/build/pkgs/networkx/install-requires.txt b/build/pkgs/networkx/install-requires.txt index 9b1205be0a8..ea173da7538 100644 --- a/build/pkgs/networkx/install-requires.txt +++ b/build/pkgs/networkx/install-requires.txt @@ -1,2 +1 @@ -# features removed in 3.0 listed in https://networkx.org/documentation/stable/developer/deprecations.html#version-3-0 -networkx >=2.4, <3.0 +networkx >=2.4, <3.2 diff --git a/build/pkgs/networkx/package-version.txt b/build/pkgs/networkx/package-version.txt index 80803faf1b9..8c50098d8ae 100644 --- a/build/pkgs/networkx/package-version.txt +++ b/build/pkgs/networkx/package-version.txt @@ -1 +1 @@ -2.8.8 +3.1 diff --git a/build/pkgs/networkx/spkg-configure.m4 b/build/pkgs/networkx/spkg-configure.m4 new file mode 100644 index 00000000000..926671e166e --- /dev/null +++ b/build/pkgs/networkx/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([networkx], [SAGE_PYTHON_PACKAGE_CHECK([networkx])]) diff --git a/build/pkgs/nibabel/distros/opensuse.txt b/build/pkgs/nibabel/distros/opensuse.txt index 19df029d93f..1a7f1fd31f7 100644 --- a/build/pkgs/nibabel/distros/opensuse.txt +++ b/build/pkgs/nibabel/distros/opensuse.txt @@ -1 +1 @@ -python3-nibabel +python3${PYTHON_MINOR}-nibabel diff --git a/build/pkgs/ninja_build/checksums.ini b/build/pkgs/ninja_build/checksums.ini index d3914da794a..43ddbfd6334 100644 --- a/build/pkgs/ninja_build/checksums.ini +++ b/build/pkgs/ninja_build/checksums.ini @@ -1,5 +1,5 @@ tarball=ninja_build-VERSION.tar.gz -sha1=f8c9279bdd4efc63b1a6be3b8c5a5031699af9ac -md5=7d1a1a2f5cdc06795b3054df5c17d5ef -cksum=3142198237 +sha1=938723cdfc7a6f7c8f84c83b9a2cecdf1e5e1ad3 +md5=32151c08211d7ca3c1d832064f6939b0 +cksum=4040304461 upstream_url=https://github.com/ninja-build/ninja/archive/refs/tags/vVERSION.tar.gz diff --git a/build/pkgs/ninja_build/dependencies b/build/pkgs/ninja_build/dependencies index 6b134137610..3518086ab84 100644 --- a/build/pkgs/ninja_build/dependencies +++ b/build/pkgs/ninja_build/dependencies @@ -1,4 +1,4 @@ -| $(PYTHON) +| $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/ninja_build/package-version.txt b/build/pkgs/ninja_build/package-version.txt index 1cac385c6cb..720c7384c61 100644 --- a/build/pkgs/ninja_build/package-version.txt +++ b/build/pkgs/ninja_build/package-version.txt @@ -1 +1 @@ -1.11.0 +1.11.1 diff --git a/build/pkgs/nodeenv/dependencies b/build/pkgs/nodeenv/dependencies index 16df46f57ee..04eff0c842c 100644 --- a/build/pkgs/nodeenv/dependencies +++ b/build/pkgs/nodeenv/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) certifi + | $(PYTHON_TOOLCHAIN) certifi $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/normaliz/checksums.ini b/build/pkgs/normaliz/checksums.ini index f7d47180ceb..fd5561cad24 100644 --- a/build/pkgs/normaliz/checksums.ini +++ b/build/pkgs/normaliz/checksums.ini @@ -1,5 +1,5 @@ tarball=normaliz-VERSION.tar.gz -sha1=6382fcb14b0e602f5bf7d5abd53b421d0e3a0a3d -md5=1c6bdd4da166da1718b08a3b9ee40949 -cksum=2272467212 +sha1=d3c4e554c6a5ccf4fd04147e7744a63e3def1766 +md5=1c7a7833ad180ef4e0e4f124ed398973 +cksum=3124231015 upstream_url=https://github.com/Normaliz/Normaliz/releases/download/vVERSION/normaliz-VERSION.tar.gz diff --git a/build/pkgs/normaliz/package-version.txt b/build/pkgs/normaliz/package-version.txt index e0d61b5b062..f870be23bad 100644 --- a/build/pkgs/normaliz/package-version.txt +++ b/build/pkgs/normaliz/package-version.txt @@ -1 +1 @@ -3.9.4 +3.10.1 diff --git a/build/pkgs/normaliz/patches/411.patch b/build/pkgs/normaliz/patches/411.patch new file mode 100644 index 00000000000..d9e52bd78bf --- /dev/null +++ b/build/pkgs/normaliz/patches/411.patch @@ -0,0 +1,21 @@ +commit ecdb62c90a3767b440800dcf2c49589e890a53b1 +Author: Matthias Koeppe <mkoeppe@math.ucdavis.edu> +Date: Tue Aug 8 17:03:32 2023 -0700 + + full_cone.cpp: Remove debug output + +diff --git a/source/libnormaliz/full_cone.cpp b/source/libnormaliz/full_cone.cpp +index 0fd906b3..cb2cce2b 100644 +--- a/source/libnormaliz/full_cone.cpp ++++ b/source/libnormaliz/full_cone.cpp +@@ -3447,8 +3447,8 @@ void Full_Cone<Integer>::build_cone_dynamic() { + // if they aren't in a hyperplane anyway + if(IntHullNorm.size() > 0){ + #pragma omp parallel for +- for(size_t i = 0; i< OriGens.nr_of_rows(); ++i){ +- cout << "i " << i << " -- " << OriGensFloat[i]; ++ for (size_t i = 0; i< OriGens.nr_of_rows(); ++i){ ++ // cout << "i " << i << " -- " << OriGensFloat[i]; + nmz_float norm = v_scalar_product(OriGensFloat[i], IntHullNormFloat); + v_scalar_division(OriGensFloat[i], norm); + } diff --git a/build/pkgs/notebook/dependencies b/build/pkgs/notebook/dependencies index 9f5cb330ae2..9e6cbf4b36d 100644 --- a/build/pkgs/notebook/dependencies +++ b/build/pkgs/notebook/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) ipython jupyter_client ipykernel nbconvert nbformat jinja2 tornado terminado send2trash prometheus_client argon2_cffi + | $(PYTHON_TOOLCHAIN) ipython jupyter_client ipykernel nbconvert nbformat jinja2 tornado terminado send2trash prometheus_client argon2_cffi $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/notebook/distros/gentoo.txt b/build/pkgs/notebook/distros/gentoo.txt new file mode 100644 index 00000000000..6475d72541e --- /dev/null +++ b/build/pkgs/notebook/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/notebook diff --git a/build/pkgs/notebook/spkg-configure.m4 b/build/pkgs/notebook/spkg-configure.m4 new file mode 100644 index 00000000000..a17ba95eac6 --- /dev/null +++ b/build/pkgs/notebook/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([notebook], [SAGE_PYTHON_PACKAGE_CHECK([notebook])]) diff --git a/build/pkgs/notedown/dependencies b/build/pkgs/notedown/dependencies index ea77eefc7f4..3dcb5b1900f 100644 --- a/build/pkgs/notedown/dependencies +++ b/build/pkgs/notedown/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) $(PYTHON_TOOLCHAIN) | pip nbformat nbconvert six pandoc_attributes + $(PYTHON_TOOLCHAIN) | pip nbformat nbconvert six pandoc_attributes $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/numpy/dependencies b/build/pkgs/numpy/dependencies index d3c0f0055e4..63faafe335a 100644 --- a/build/pkgs/numpy/dependencies +++ b/build/pkgs/numpy/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) $(BLAS) gfortran | $(PYTHON_TOOLCHAIN) pkgconfig cython + $(BLAS) gfortran | $(PYTHON_TOOLCHAIN) pkgconfig cython $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/numpy/distros/arch.txt b/build/pkgs/numpy/distros/arch.txt new file mode 100644 index 00000000000..c8722b9f663 --- /dev/null +++ b/build/pkgs/numpy/distros/arch.txt @@ -0,0 +1 @@ +python-numpy diff --git a/build/pkgs/numpy/distros/debian.txt b/build/pkgs/numpy/distros/debian.txt new file mode 100644 index 00000000000..79d5c5a1429 --- /dev/null +++ b/build/pkgs/numpy/distros/debian.txt @@ -0,0 +1 @@ +python3-numpy diff --git a/build/pkgs/numpy/distros/fedora.txt b/build/pkgs/numpy/distros/fedora.txt new file mode 100644 index 00000000000..c8722b9f663 --- /dev/null +++ b/build/pkgs/numpy/distros/fedora.txt @@ -0,0 +1 @@ +python-numpy diff --git a/build/pkgs/numpy/distros/gentoo.txt b/build/pkgs/numpy/distros/gentoo.txt new file mode 100644 index 00000000000..d2179d43851 --- /dev/null +++ b/build/pkgs/numpy/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/numpy diff --git a/build/pkgs/numpy/distros/opensuse.txt b/build/pkgs/numpy/distros/opensuse.txt new file mode 100644 index 00000000000..2e278515236 --- /dev/null +++ b/build/pkgs/numpy/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-numpy diff --git a/build/pkgs/numpy/patches/cython3-legacy.patch b/build/pkgs/numpy/patches/cython3-legacy.patch new file mode 100644 index 00000000000..dfcb9c4a69c --- /dev/null +++ b/build/pkgs/numpy/patches/cython3-legacy.patch @@ -0,0 +1,12 @@ +diff --git a/tools/cythonize.py b/tools/cythonize.py +index 002b2fa..c04422e 100755 +--- a/tools/cythonize.py ++++ b/tools/cythonize.py +@@ -47,6 +47,7 @@ def process_pyx(fromfile, tofile): + flags = ['-3', '--fast-fail'] + if tofile.endswith('.cxx'): + flags.append('--cplus') ++ flags += ['--directive', 'legacy_implicit_noexcept=true'] + + subprocess.check_call( + [sys.executable, '-m', 'cython'] + flags + ["-o", tofile, fromfile]) diff --git a/build/pkgs/numpy/spkg-configure.m4 b/build/pkgs/numpy/spkg-configure.m4 new file mode 100644 index 00000000000..16f9a90fad2 --- /dev/null +++ b/build/pkgs/numpy/spkg-configure.m4 @@ -0,0 +1,5 @@ +SAGE_SPKG_CONFIGURE([numpy], [ + SAGE_SPKG_DEPCHECK([openblas], [ + SAGE_PYTHON_PACKAGE_CHECK([numpy]) + ]) +]) diff --git a/build/pkgs/onetbb/distros/opensuse.txt b/build/pkgs/onetbb/distros/opensuse.txt new file mode 100644 index 00000000000..2e18bff2796 --- /dev/null +++ b/build/pkgs/onetbb/distros/opensuse.txt @@ -0,0 +1 @@ +tbb diff --git a/build/pkgs/openblas/checksums.ini b/build/pkgs/openblas/checksums.ini index e6e83e7d891..c2a1fe997c5 100644 --- a/build/pkgs/openblas/checksums.ini +++ b/build/pkgs/openblas/checksums.ini @@ -1,5 +1,5 @@ tarball=openblas-VERSION.tar.gz -sha1=b052d196ad694b29302e074b3eb8cc66745f6e2f -md5=ffb6120e2309a2280471716301824805 -cksum=241092070 +sha1=6b781727c7b95850ae4a3eb0a391492eb4f3e780 +md5=115634b39007de71eb7e75cf7591dfb2 +cksum=2485407229 upstream_url=https://github.com/xianyi/OpenBLAS/archive/vVERSION.tar.gz diff --git a/build/pkgs/openblas/package-version.txt b/build/pkgs/openblas/package-version.txt index dfdc368868b..a1dad2aa79c 100644 --- a/build/pkgs/openblas/package-version.txt +++ b/build/pkgs/openblas/package-version.txt @@ -1 +1 @@ -0.3.21 +0.3.23 diff --git a/build/pkgs/openblas/spkg-configure.m4 b/build/pkgs/openblas/spkg-configure.m4 index c81533ba71a..06affdacff8 100644 --- a/build/pkgs/openblas/spkg-configure.m4 +++ b/build/pkgs/openblas/spkg-configure.m4 @@ -7,7 +7,12 @@ SAGE_SPKG_CONFIGURE([openblas], [ m4_pushdef([SAGE_OPENBLAS_MIN_VERSION_MINOR], [2]) m4_pushdef([SAGE_OPENBLAS_MIN_VERSION_MICRO], [20]) m4_pushdef([SAGE_OPENBLAS_MIN_VERSION], [SAGE_OPENBLAS_MIN_VERSION_MAJOR.SAGE_OPENBLAS_MIN_VERSION_MINOR.SAGE_OPENBLAS_MIN_VERSION_MICRO]) - PKG_CHECK_MODULES([OPENBLAS], [openblas >= ]SAGE_OPENBLAS_MIN_VERSION, [ + dnl Reject openblas 0.3.22 - https://github.com/sagemath/sage/pull/35371 + m4_pushdef([SAGE_OPENBLAS_LT_VERSION_MAJOR], [0]) + m4_pushdef([SAGE_OPENBLAS_LT_VERSION_MINOR], [3]) + m4_pushdef([SAGE_OPENBLAS_LT_VERSION_MICRO], [99]) + m4_pushdef([SAGE_OPENBLAS_LT_VERSION], [SAGE_OPENBLAS_LT_VERSION_MAJOR.SAGE_OPENBLAS_LT_VERSION_MINOR.SAGE_OPENBLAS_LT_VERSION_MICRO]) + PKG_CHECK_MODULES([OPENBLAS], [openblas >= ]SAGE_OPENBLAS_MIN_VERSION [openblas < ]SAGE_OPENBLAS_LT_VERSION, [ LIBS="$OPENBLAS_LIBS $LIBS" CFLAGS="$OPENBLAS_CFLAGS $CFLAGS" PKG_CHECK_VAR([OPENBLASPCDIR], [openblas], [pcfiledir], [ @@ -35,6 +40,21 @@ SAGE_SPKG_CONFIGURE([openblas], [ AC_MSG_WARN([Unable to locate the directory of openblas.pc. This should not happen!]) sage_spkg_install_openblas=yes ]) + AS_IF([test x$sage_spkg_install_openblas != xyes], [ + AC_MSG_CHECKING([the OpenBLAS version using openblas_get_config]) + AC_LANG_PUSH([C]) + AC_RUN_IFELSE([ + dnl Reject 0.3.22 - see https://github.com/sagemath/sage/pull/35377 + AC_LANG_PROGRAM([[#include <string.h> + char *openblas_get_config(void); ]], + [[if (!strncmp(openblas_get_config(), "OpenBLAS 0.3.22", 15)) return 1;]]) + ], [ + AC_MSG_RESULT([good]) + ], [ + AC_MSG_RESULT([known bad version]) + sage_spkg_install_openblas=yes]) + AC_LANG_POP([C]) + ]) AS_IF([test x$sage_spkg_install_openblas != xyes], [ AC_SUBST([SAGE_SYSTEM_FACADE_PC_FILES]) AC_SUBST([SAGE_OPENBLAS_PC_COMMAND], ["\$(LN) -sf \"$OPENBLASPCDIR/openblas.pc\" \"\$(@)\""]) @@ -61,6 +81,7 @@ SAGE_SPKG_CONFIGURE([openblas], [ AC_LANG_PUSH([C]) AC_RUN_IFELSE([ AC_LANG_PROGRAM([[#include <stdio.h> + #include <string.h> char *openblas_get_config(void); int version[3]; ]], [[version[0] = version[1] = version[2] = 0; @@ -74,7 +95,15 @@ SAGE_SPKG_CONFIGURE([openblas], [ < 10000 * ]]SAGE_OPENBLAS_MIN_VERSION_MAJOR[[ + 100 * ]]SAGE_OPENBLAS_MIN_VERSION_MINOR[[ + ]]SAGE_OPENBLAS_MIN_VERSION_MICRO[[) - return 1;]]) + return 1; + if ( 10000 * version[0] + + 100 * version[1] + + version[2] + >=10000 * ]]SAGE_OPENBLAS_LT_VERSION_MAJOR[[ + + 100 * ]]SAGE_OPENBLAS_LT_VERSION_MINOR[[ + + ]]SAGE_OPENBLAS_LT_VERSION_MICRO[[) + return 1; + if (!strncmp(openblas_get_config(), "OpenBLAS 0.3.22", 15)) return 1;]]) ], [AS_VAR_SET([HAVE_OPENBLAS], [yes])], [AS_VAR_SET([HAVE_OPENBLAS], [no])], [AS_VAR_SET([HAVE_OPENBLAS], [yes])]) AC_LANG_POP([C]) diff --git a/build/pkgs/openssl/checksums.ini b/build/pkgs/openssl/checksums.ini index 216fe96e725..a443f001e4a 100644 --- a/build/pkgs/openssl/checksums.ini +++ b/build/pkgs/openssl/checksums.ini @@ -1,5 +1,5 @@ tarball=openssl-VERSION.tar.gz -sha1=a5305213c681a5a4322dad7347a6e66b7b6ef3c7 -md5=163bb3e58c143793d1dc6a6ec7d185d5 -cksum=439183449 +sha1=580d8a7232327fe1fa6e7db54ac060d4321f40ab +md5=61e017cf4fea1b599048f621f1490fbd +cksum=1708357994 upstream_url=https://www.openssl.org/source/openssl-VERSION.tar.gz diff --git a/build/pkgs/openssl/package-version.txt b/build/pkgs/openssl/package-version.txt index eca690e737b..67786e246ef 100644 --- a/build/pkgs/openssl/package-version.txt +++ b/build/pkgs/openssl/package-version.txt @@ -1 +1 @@ -3.0.5 +3.0.8 diff --git a/build/pkgs/ore_algebra/dependencies b/build/pkgs/ore_algebra/dependencies index 05ba0d8954b..126e8ceee06 100644 --- a/build/pkgs/ore_algebra/dependencies +++ b/build/pkgs/ore_algebra/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) $(SAGERUNTIME) + | $(PYTHON_TOOLCHAIN) $(SAGERUNTIME) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/osqp_python/SPKG.rst b/build/pkgs/osqp_python/SPKG.rst new file mode 100644 index 00000000000..7672b270ec9 --- /dev/null +++ b/build/pkgs/osqp_python/SPKG.rst @@ -0,0 +1,20 @@ +osqp_python: The Operator Splitting QP Solver (Python wrapper) +============================================================== + +Description +----------- + +This is the Python wrapper for OSQP: The Operator Splitting QP Solver. + +It vendors OSQP. + +License +------- + +Apache 2.0 + +Upstream Contact +---------------- + +https://pypi.org/project/osqp/ + diff --git a/build/pkgs/osqp_python/checksums.ini b/build/pkgs/osqp_python/checksums.ini new file mode 100644 index 00000000000..750d1d8450a --- /dev/null +++ b/build/pkgs/osqp_python/checksums.ini @@ -0,0 +1,5 @@ +tarball=osqp-VERSION.tar.gz +sha1=d69d05b87c03aaaf80ac0bb11e1a68746cf8c486 +md5=ae46dc55aa4ff7a2009db756f2b61d98 +cksum=2780901429 +upstream_url=https://pypi.io/packages/source/o/osqp/osqp-VERSION.tar.gz diff --git a/build/pkgs/osqp_python/dependencies b/build/pkgs/osqp_python/dependencies new file mode 100644 index 00000000000..6cc50626d1d --- /dev/null +++ b/build/pkgs/osqp_python/dependencies @@ -0,0 +1,4 @@ + qdldl_python numpy scipy | $(PYTHON_TOOLCHAIN) cmake $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/osqp_python/distros/conda.txt b/build/pkgs/osqp_python/distros/conda.txt new file mode 100644 index 00000000000..c2c8a965707 --- /dev/null +++ b/build/pkgs/osqp_python/distros/conda.txt @@ -0,0 +1 @@ +osqp diff --git a/build/pkgs/osqp_python/install-requires.txt b/build/pkgs/osqp_python/install-requires.txt new file mode 100644 index 00000000000..c2c8a965707 --- /dev/null +++ b/build/pkgs/osqp_python/install-requires.txt @@ -0,0 +1 @@ +osqp diff --git a/build/pkgs/osqp_python/package-version.txt b/build/pkgs/osqp_python/package-version.txt new file mode 100644 index 00000000000..72b079f4d76 --- /dev/null +++ b/build/pkgs/osqp_python/package-version.txt @@ -0,0 +1 @@ +0.6.2.post8 diff --git a/build/pkgs/osqp_python/spkg-install.in b/build/pkgs/osqp_python/spkg-install.in new file mode 100644 index 00000000000..a143d1eff96 --- /dev/null +++ b/build/pkgs/osqp_python/spkg-install.in @@ -0,0 +1,3 @@ +cd src +# --no-build-isolation to ignore the numpy version pin in pyproject.toml +sdh_pip_install --no-build-isolation . diff --git a/build/pkgs/osqp_python/type b/build/pkgs/osqp_python/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/osqp_python/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/p_group_cohomology/dependencies b/build/pkgs/p_group_cohomology/dependencies index a9d113183c5..57ea7e0dd94 100644 --- a/build/pkgs/p_group_cohomology/dependencies +++ b/build/pkgs/p_group_cohomology/dependencies @@ -1 +1 @@ -$(PYTHON) cython cysignals singular meataxe modular_resolution $(SAGE_SRC)/sage/matrix/matrix_gfpn_dense.pxd $(SAGE_SRC)/sage/structure/element.pxd $(SAGE_SRC)/sage/matrix/matrix_gfpn_dense.pxd $(SAGE_SRC)/sage/matrix/matrix0.pxd $(SAGE_SRC)/sage/libs/meataxe.pxd $(SAGE_SRC)/sage/rings/morphism.pxd | $(PYTHON_TOOLCHAIN) matplotlib gap xz $(SAGERUNTIME) ipywidgets + cython cysignals singular meataxe modular_resolution $(SAGE_SRC)/sage/matrix/matrix_gfpn_dense.pxd $(SAGE_SRC)/sage/structure/element.pxd $(SAGE_SRC)/sage/matrix/matrix_gfpn_dense.pxd $(SAGE_SRC)/sage/matrix/matrix0.pxd $(SAGE_SRC)/sage/libs/meataxe.pxd $(SAGE_SRC)/sage/rings/morphism.pxd | $(PYTHON_TOOLCHAIN) matplotlib gap xz $(SAGERUNTIME) ipywidgets $(PYTHON) diff --git a/build/pkgs/packaging/checksums.ini b/build/pkgs/packaging/checksums.ini index c8c315c78c8..83ab122e324 100644 --- a/build/pkgs/packaging/checksums.ini +++ b/build/pkgs/packaging/checksums.ini @@ -1,5 +1,5 @@ tarball=packaging-VERSION.tar.gz -sha1=b8caff3bec760723db6af4092c68075e22bdb769 -md5=e713c1939f294fd729af4a7be40dd141 -cksum=2539089468 +sha1=1245c28c10ae6cb80164f081daece224b6fa89bc +md5=f7d5c39c6f92cc2dfa1293ba8f6c097c +cksum=11867377 upstream_url=https://pypi.io/packages/source/p/packaging/packaging-VERSION.tar.gz diff --git a/build/pkgs/packaging/dependencies b/build/pkgs/packaging/dependencies index 2323f9df04a..17220ffcc37 100644 --- a/build/pkgs/packaging/dependencies +++ b/build/pkgs/packaging/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | setuptools pip wheel pyparsing setuptools_wheel + | setuptools pip wheel pyparsing setuptools_wheel $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/packaging/distros/arch.txt b/build/pkgs/packaging/distros/arch.txt new file mode 100644 index 00000000000..02ad855da9a --- /dev/null +++ b/build/pkgs/packaging/distros/arch.txt @@ -0,0 +1 @@ +python-packaging diff --git a/build/pkgs/packaging/distros/debian.txt b/build/pkgs/packaging/distros/debian.txt new file mode 100644 index 00000000000..8f1c0ffc29f --- /dev/null +++ b/build/pkgs/packaging/distros/debian.txt @@ -0,0 +1 @@ +python3-packaging diff --git a/build/pkgs/packaging/distros/fedora.txt b/build/pkgs/packaging/distros/fedora.txt new file mode 100644 index 00000000000..02ad855da9a --- /dev/null +++ b/build/pkgs/packaging/distros/fedora.txt @@ -0,0 +1 @@ +python-packaging diff --git a/build/pkgs/packaging/distros/gentoo.txt b/build/pkgs/packaging/distros/gentoo.txt new file mode 100644 index 00000000000..e5309ed2b25 --- /dev/null +++ b/build/pkgs/packaging/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/packaging diff --git a/build/pkgs/packaging/distros/opensuse.txt b/build/pkgs/packaging/distros/opensuse.txt new file mode 100644 index 00000000000..bec5186f923 --- /dev/null +++ b/build/pkgs/packaging/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-packaging diff --git a/build/pkgs/packaging/install-requires.txt b/build/pkgs/packaging/install-requires.txt index cb98c369e84..637d00eff2f 100644 --- a/build/pkgs/packaging/install-requires.txt +++ b/build/pkgs/packaging/install-requires.txt @@ -1,2 +1,3 @@ -packaging >=18.0 +packaging >=21.0 # Trac #30975: packaging 20.5 is known to work but we have to silence "DeprecationWarning: Creating a LegacyVersion" +# Sphinx needs >= 21 diff --git a/build/pkgs/packaging/package-version.txt b/build/pkgs/packaging/package-version.txt index 8e5954eb6f3..a12b18e4372 100644 --- a/build/pkgs/packaging/package-version.txt +++ b/build/pkgs/packaging/package-version.txt @@ -1 +1 @@ -21.3 +23.1 diff --git a/build/pkgs/packaging/spkg-configure.m4 b/build/pkgs/packaging/spkg-configure.m4 new file mode 100644 index 00000000000..398f9e13cd3 --- /dev/null +++ b/build/pkgs/packaging/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([packaging], [SAGE_PYTHON_PACKAGE_CHECK([packaging])]) diff --git a/build/pkgs/palettable/dependencies b/build/pkgs/palettable/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/palettable/dependencies +++ b/build/pkgs/palettable/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pandoc_attributes/dependencies b/build/pkgs/pandoc_attributes/dependencies index 64f88253c78..cc9d4970706 100644 --- a/build/pkgs/pandoc_attributes/dependencies +++ b/build/pkgs/pandoc_attributes/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) $(PYTHON_TOOLCHAIN) | pip pandocfilters + $(PYTHON_TOOLCHAIN) | pip pandocfilters $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pandocfilters/dependencies b/build/pkgs/pandocfilters/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/pandocfilters/dependencies +++ b/build/pkgs/pandocfilters/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pandocfilters/distros/arch.txt b/build/pkgs/pandocfilters/distros/arch.txt new file mode 100644 index 00000000000..e7a86d0373c --- /dev/null +++ b/build/pkgs/pandocfilters/distros/arch.txt @@ -0,0 +1 @@ +python-pandocfilters diff --git a/build/pkgs/pandocfilters/distros/debian.txt b/build/pkgs/pandocfilters/distros/debian.txt new file mode 100644 index 00000000000..d0d4c24e15e --- /dev/null +++ b/build/pkgs/pandocfilters/distros/debian.txt @@ -0,0 +1 @@ +python3-pandocfilters diff --git a/build/pkgs/pandocfilters/distros/fedora.txt b/build/pkgs/pandocfilters/distros/fedora.txt new file mode 100644 index 00000000000..e7a86d0373c --- /dev/null +++ b/build/pkgs/pandocfilters/distros/fedora.txt @@ -0,0 +1 @@ +python-pandocfilters diff --git a/build/pkgs/pandocfilters/distros/gentoo.txt b/build/pkgs/pandocfilters/distros/gentoo.txt new file mode 100644 index 00000000000..a726fda2817 --- /dev/null +++ b/build/pkgs/pandocfilters/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pandocfilters diff --git a/build/pkgs/pandocfilters/distros/opensuse.txt b/build/pkgs/pandocfilters/distros/opensuse.txt new file mode 100644 index 00000000000..843b3c1b32b --- /dev/null +++ b/build/pkgs/pandocfilters/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-pandocfilters diff --git a/build/pkgs/pandocfilters/spkg-configure.m4 b/build/pkgs/pandocfilters/spkg-configure.m4 new file mode 100644 index 00000000000..3e9537f818c --- /dev/null +++ b/build/pkgs/pandocfilters/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([pandocfilters], [ + SAGE_PYTHON_PACKAGE_CHECK([pandocfilters]) +]) diff --git a/build/pkgs/pari_jupyter/dependencies b/build/pkgs/pari_jupyter/dependencies index 44eaa153cc2..f7f0020c13b 100644 --- a/build/pkgs/pari_jupyter/dependencies +++ b/build/pkgs/pari_jupyter/dependencies @@ -1 +1 @@ -$(PYTHON) pari | $(PYTHON_TOOLCHAIN) cython notebook jupyter_core + pari | $(PYTHON_TOOLCHAIN) cython notebook jupyter_core $(PYTHON) diff --git a/build/pkgs/parso/dependencies b/build/pkgs/parso/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/parso/dependencies +++ b/build/pkgs/parso/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/parso/distros/gentoo.txt b/build/pkgs/parso/distros/gentoo.txt new file mode 100644 index 00000000000..f9ce4c7f2f2 --- /dev/null +++ b/build/pkgs/parso/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/parso diff --git a/build/pkgs/parso/spkg-configure.m4 b/build/pkgs/parso/spkg-configure.m4 new file mode 100644 index 00000000000..1ca6f1b909d --- /dev/null +++ b/build/pkgs/parso/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([parso], [SAGE_PYTHON_PACKAGE_CHECK([parso])]) diff --git a/build/pkgs/patchelf/distros/conda.txt b/build/pkgs/patchelf/distros/conda.txt new file mode 100644 index 00000000000..fca4680084f --- /dev/null +++ b/build/pkgs/patchelf/distros/conda.txt @@ -0,0 +1 @@ +patchelf diff --git a/build/pkgs/patchelf/distros/debian.txt b/build/pkgs/patchelf/distros/debian.txt new file mode 100644 index 00000000000..fca4680084f --- /dev/null +++ b/build/pkgs/patchelf/distros/debian.txt @@ -0,0 +1 @@ +patchelf diff --git a/build/pkgs/patchelf/distros/fedora.txt b/build/pkgs/patchelf/distros/fedora.txt new file mode 100644 index 00000000000..fca4680084f --- /dev/null +++ b/build/pkgs/patchelf/distros/fedora.txt @@ -0,0 +1 @@ +patchelf diff --git a/build/pkgs/patchelf/distros/freebsd.txt b/build/pkgs/patchelf/distros/freebsd.txt new file mode 100644 index 00000000000..b45345ef8e7 --- /dev/null +++ b/build/pkgs/patchelf/distros/freebsd.txt @@ -0,0 +1 @@ +sysutils/patchelf diff --git a/build/pkgs/patchelf/distros/gentoo.txt b/build/pkgs/patchelf/distros/gentoo.txt new file mode 100644 index 00000000000..5a8e4027272 --- /dev/null +++ b/build/pkgs/patchelf/distros/gentoo.txt @@ -0,0 +1 @@ +dev-util/patchelf diff --git a/build/pkgs/patchelf/distros/homebrew.txt b/build/pkgs/patchelf/distros/homebrew.txt new file mode 100644 index 00000000000..fca4680084f --- /dev/null +++ b/build/pkgs/patchelf/distros/homebrew.txt @@ -0,0 +1 @@ +patchelf diff --git a/build/pkgs/patchelf/distros/macports.txt b/build/pkgs/patchelf/distros/macports.txt new file mode 100644 index 00000000000..fca4680084f --- /dev/null +++ b/build/pkgs/patchelf/distros/macports.txt @@ -0,0 +1 @@ +patchelf diff --git a/build/pkgs/patchelf/distros/nix.txt b/build/pkgs/patchelf/distros/nix.txt new file mode 100644 index 00000000000..fca4680084f --- /dev/null +++ b/build/pkgs/patchelf/distros/nix.txt @@ -0,0 +1 @@ +patchelf diff --git a/build/pkgs/patchelf/distros/opensuse.txt b/build/pkgs/patchelf/distros/opensuse.txt new file mode 100644 index 00000000000..fca4680084f --- /dev/null +++ b/build/pkgs/patchelf/distros/opensuse.txt @@ -0,0 +1 @@ +patchelf diff --git a/build/pkgs/patchelf/distros/repology.txt b/build/pkgs/patchelf/distros/repology.txt new file mode 100644 index 00000000000..fca4680084f --- /dev/null +++ b/build/pkgs/patchelf/distros/repology.txt @@ -0,0 +1 @@ +patchelf diff --git a/build/pkgs/patchelf/distros/void.txt b/build/pkgs/patchelf/distros/void.txt new file mode 100644 index 00000000000..fca4680084f --- /dev/null +++ b/build/pkgs/patchelf/distros/void.txt @@ -0,0 +1 @@ +patchelf diff --git a/build/pkgs/patchelf/spkg-configure.m4 b/build/pkgs/patchelf/spkg-configure.m4 new file mode 100644 index 00000000000..599c23e3f8b --- /dev/null +++ b/build/pkgs/patchelf/spkg-configure.m4 @@ -0,0 +1,4 @@ +SAGE_SPKG_CONFIGURE([patchelf],[ + AC_PATH_PROG(PATCHELF, patchelf) + AS_IF([test -z "${PATCHELF}"], [sage_spkg_install_patchelf=yes]) +]) diff --git a/build/pkgs/pathspec/dependencies b/build/pkgs/pathspec/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/pathspec/dependencies +++ b/build/pkgs/pathspec/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pathspec/distros/gentoo.txt b/build/pkgs/pathspec/distros/gentoo.txt new file mode 100644 index 00000000000..6f8fd9dc4cd --- /dev/null +++ b/build/pkgs/pathspec/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pathspec diff --git a/build/pkgs/pathspec/spkg-configure.m4 b/build/pkgs/pathspec/spkg-configure.m4 new file mode 100644 index 00000000000..086fd9830e9 --- /dev/null +++ b/build/pkgs/pathspec/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pathspec], [SAGE_PYTHON_PACKAGE_CHECK([pathspec])]) diff --git a/build/pkgs/pcre/SPKG.rst b/build/pkgs/pcre/SPKG.rst deleted file mode 100644 index d1839c2c1df..00000000000 --- a/build/pkgs/pcre/SPKG.rst +++ /dev/null @@ -1,23 +0,0 @@ -pcre: Perl-compatible regular expressions library -================================================= - -Description ------------ - -Perl-compatible regular expressions library. - -License -------- - -BSD License; see LICENCE (sic) at the root of the original tarball. - - -Upstream Contact ----------------- - -Mailing list at https://lists.exim.org/mailman/listinfo/pcre-dev - -Special Update/Build Instructions ---------------------------------- - -None applicable (see README at tarball's root). diff --git a/build/pkgs/pcre/checksums.ini b/build/pkgs/pcre/checksums.ini deleted file mode 100644 index 31e13a23cbc..00000000000 --- a/build/pkgs/pcre/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=pcre-8.40.tar.gz -sha1=10384eb3d411794cc15f55b9d837d3f69e35391e -md5=890c808122bd90f398e6bc40ec862102 -cksum=451624496 diff --git a/build/pkgs/pcre/dependencies b/build/pkgs/pcre/dependencies deleted file mode 100644 index 1ccba14e349..00000000000 --- a/build/pkgs/pcre/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -bzip2 - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/pcre/distros/conda.txt b/build/pkgs/pcre/distros/conda.txt deleted file mode 100644 index abd501ce241..00000000000 --- a/build/pkgs/pcre/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -pcre diff --git a/build/pkgs/pcre/distros/cygwin.txt b/build/pkgs/pcre/distros/cygwin.txt deleted file mode 100644 index 11042f02d24..00000000000 --- a/build/pkgs/pcre/distros/cygwin.txt +++ /dev/null @@ -1 +0,0 @@ -libpcre-devel diff --git a/build/pkgs/pcre/distros/debian.txt b/build/pkgs/pcre/distros/debian.txt deleted file mode 100644 index 1c546f65a7b..00000000000 --- a/build/pkgs/pcre/distros/debian.txt +++ /dev/null @@ -1 +0,0 @@ -libpcre3-dev diff --git a/build/pkgs/pcre/distros/fedora.txt b/build/pkgs/pcre/distros/fedora.txt deleted file mode 100644 index cd3cd89bdd9..00000000000 --- a/build/pkgs/pcre/distros/fedora.txt +++ /dev/null @@ -1 +0,0 @@ -pcre pcre-devel diff --git a/build/pkgs/pcre/distros/freebsd.txt b/build/pkgs/pcre/distros/freebsd.txt deleted file mode 100644 index d370f1c5c51..00000000000 --- a/build/pkgs/pcre/distros/freebsd.txt +++ /dev/null @@ -1 +0,0 @@ -devel/pcre diff --git a/build/pkgs/pcre/distros/homebrew.txt b/build/pkgs/pcre/distros/homebrew.txt deleted file mode 100644 index abd501ce241..00000000000 --- a/build/pkgs/pcre/distros/homebrew.txt +++ /dev/null @@ -1 +0,0 @@ -pcre diff --git a/build/pkgs/pcre/distros/macports.txt b/build/pkgs/pcre/distros/macports.txt deleted file mode 100644 index abd501ce241..00000000000 --- a/build/pkgs/pcre/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -pcre diff --git a/build/pkgs/pcre/distros/opensuse.txt b/build/pkgs/pcre/distros/opensuse.txt deleted file mode 100644 index 00edc2cd4ca..00000000000 --- a/build/pkgs/pcre/distros/opensuse.txt +++ /dev/null @@ -1,3 +0,0 @@ -"pkgconfig(libpcre)" -"pkgconfig(libpcreposix)" -"pkgconfig(libpcrecpp)" diff --git a/build/pkgs/pcre/distros/repology.txt b/build/pkgs/pcre/distros/repology.txt deleted file mode 100644 index abd501ce241..00000000000 --- a/build/pkgs/pcre/distros/repology.txt +++ /dev/null @@ -1 +0,0 @@ -pcre diff --git a/build/pkgs/pcre/distros/slackware.txt b/build/pkgs/pcre/distros/slackware.txt deleted file mode 100644 index abd501ce241..00000000000 --- a/build/pkgs/pcre/distros/slackware.txt +++ /dev/null @@ -1 +0,0 @@ -pcre diff --git a/build/pkgs/pcre/distros/void.txt b/build/pkgs/pcre/distros/void.txt deleted file mode 100644 index cac6a31d037..00000000000 --- a/build/pkgs/pcre/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -pcre-devel diff --git a/build/pkgs/pcre/package-version.txt b/build/pkgs/pcre/package-version.txt deleted file mode 100644 index 0a0ec5dd93d..00000000000 --- a/build/pkgs/pcre/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -8.40.p2 diff --git a/build/pkgs/pcre/patches/8.39-cygwin-jit.patch b/build/pkgs/pcre/patches/8.39-cygwin-jit.patch deleted file mode 100644 index ca1ea43c435..00000000000 --- a/build/pkgs/pcre/patches/8.39-cygwin-jit.patch +++ /dev/null @@ -1,172 +0,0 @@ -Patch from Cygwin to fix segfault when using the JIT compiler; see -https://github.com/sagemath/sage/issues/23291 ---- a/sljit/sljitConfigInternal.h 2016-04-06 03:05:43.000000000 -0500 -+++ b/sljit/sljitConfigInternal.h 2016-08-11 14:33:58.201820000 -0500 -@@ -564,7 +564,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free - - #elif (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - --#ifndef _WIN64 -+#if !defined _WIN64 && !defined __CYGWIN__ - #define SLJIT_NUMBER_OF_REGISTERS 12 - #define SLJIT_NUMBER_OF_SAVED_REGISTERS 6 - #define SLJIT_LOCALS_OFFSET_BASE (sizeof(sljit_sw)) -@@ -572,7 +572,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free - #define SLJIT_NUMBER_OF_REGISTERS 12 - #define SLJIT_NUMBER_OF_SAVED_REGISTERS 8 - #define SLJIT_LOCALS_OFFSET_BASE ((4 + 2) * sizeof(sljit_sw)) --#endif /* _WIN64 */ -+#endif /* _WIN64 || __CYGWIN__ */ - - #elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) - -@@ -644,7 +644,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free - (SLJIT_NUMBER_OF_REGISTERS - SLJIT_NUMBER_OF_SAVED_REGISTERS) - - #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 6 --#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && (defined _WIN64) -+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && (defined _WIN64 || defined __CYGWIN__) - #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 1 - #else - #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0 ---- a/sljit/sljitNativeX86_32.c 2016-02-29 11:00:26.000000000 -0600 -+++ b/sljit/sljitNativeX86_32.c 2016-08-11 14:34:29.121178600 -0500 -@@ -164,7 +164,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - #endif - - compiler->local_size = local_size; --#ifdef _WIN32 -+#if defined _WIN32 || defined __CYGWIN__ - if (local_size > 1024) { - #if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL) - FAIL_IF(emit_do_imm(compiler, MOV_r_i32 + reg_map[SLJIT_R0], local_size)); ---- a/sljit/sljitNativeX86_64.c 2016-02-29 11:00:26.000000000 -0600 -+++ b/sljit/sljitNativeX86_64.c 2016-08-11 14:35:57.151763100 -0500 -@@ -131,7 +131,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - - INC_SIZE(size); - --#ifndef _WIN64 -+#if !defined _WIN64 && !defined __CYGWIN__ - if (args > 0) { - *inst++ = REX_W; - *inst++ = MOV_r_rm; -@@ -169,7 +169,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size; - compiler->local_size = local_size; - --#ifdef _WIN64 -+#if defined _WIN64 || defined __CYGWIN__ - if (local_size > 1024) { - /* Allocate stack for the callback, which grows the stack. */ - inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + (3 + sizeof(sljit_s32))); -@@ -223,7 +223,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - inst += sizeof(sljit_s32); - } - --#ifdef _WIN64 -+#if defined _WIN64 || defined __CYGWIN__ - /* Save xmm6 register: movaps [rsp + 0x20], xmm6 */ - if (fscratches >= 6 || fsaveds >= 1) { - inst = (sljit_u8*)ensure_buf(compiler, 1 + 5); -@@ -264,7 +264,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - compiler->flags_saved = 0; - FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); - --#ifdef _WIN64 -+#if defined _WIN64 || defined __CYGWIN__ - /* Restore xmm6 register: movaps xmm6, [rsp + 0x20] */ - if (compiler->fscratches >= 6 || compiler->fsaveds >= 1) { - inst = (sljit_u8*)ensure_buf(compiler, 1 + 5); -@@ -557,7 +557,7 @@ static SLJIT_INLINE sljit_s32 call_with_ - { - sljit_u8 *inst; - --#ifndef _WIN64 -+#if !defined _WIN64 && !defined __CYGWIN__ - SLJIT_COMPILE_ASSERT(reg_map[SLJIT_R1] == 6 && reg_map[SLJIT_R0] < 8 && reg_map[SLJIT_R2] < 8, args_registers); - - inst = (sljit_u8*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6)); ---- a/sljit/sljitNativeX86_common.c 2016-03-04 03:20:25.000000000 -0600 -+++ b/sljit/sljitNativeX86_common.c 2016-08-11 14:39:01.993876900 -0500 -@@ -87,7 +87,7 @@ static const sljit_u8 reg_map[SLJIT_NUMB - /* Note: r12 & 0x7 == 0b100, which decoded as SIB byte present - Note: avoid to use r12 and r13 for memory addessing - therefore r12 is better for SAVED_EREG than SAVED_REG. */ --#ifndef _WIN64 -+#if !defined _WIN64 && !defined __CYGWIN__ - /* 1st passed in rdi, 2nd argument passed in rsi, 3rd in rdx. */ - static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = { - 0, 0, 6, 1, 8, 11, 10, 12, 5, 13, 14, 15, 3, 4, 2, 7, 9 -@@ -628,7 +628,7 @@ static SLJIT_INLINE sljit_s32 emit_resto - return SLJIT_SUCCESS; - } - --#ifdef _WIN32 -+#if defined _WIN32 || defined __CYGWIN__ - #include <malloc.h> - - static void SLJIT_CALL sljit_grow_stack(sljit_sw local_size) -@@ -750,7 +750,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - case SLJIT_DIV_SW: - compiler->flags_saved = 0; - #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) --#ifdef _WIN64 -+#if defined _WIN64 || defined __CYGWIN__ - SLJIT_COMPILE_ASSERT( - reg_map[SLJIT_R0] == 0 - && reg_map[SLJIT_R1] == 2 -@@ -769,7 +769,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - - op = GET_OPCODE(op); - if ((op | 0x2) == SLJIT_DIV_UW) { --#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) -+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) || defined(__CYGWIN__) - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0); - inst = emit_x86_instruction(compiler, 1, SLJIT_R1, 0, SLJIT_R1, 0); - #else -@@ -780,7 +780,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - } - - if ((op | 0x2) == SLJIT_DIV_SW) { --#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) -+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) || defined(__CYGWIN__) - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0); - #endif - -@@ -812,7 +812,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - *inst++ = GROUP_F7; - *inst = MOD_REG | ((op >= SLJIT_DIVMOD_UW) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]); - #else --#ifdef _WIN64 -+#if defined _WIN64 || defined __CYGWIN__ - size = (!compiler->mode32 || op >= SLJIT_DIVMOD_UW) ? 3 : 2; - #else - size = (!compiler->mode32) ? 3 : 2; -@@ -820,7 +820,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - inst = (sljit_u8*)ensure_buf(compiler, 1 + size); - FAIL_IF(!inst); - INC_SIZE(size); --#ifdef _WIN64 -+#if defined _WIN64 || defined __CYGWIN__ - if (!compiler->mode32) - *inst++ = REX_W | ((op >= SLJIT_DIVMOD_UW) ? REX_B : 0); - else if (op >= SLJIT_DIVMOD_UW) -@@ -850,7 +850,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - *inst |= IDIV; - break; - } --#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !defined(_WIN64) -+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !defined(_WIN64) && !defined(__CYGWIN__) - if (op <= SLJIT_DIVMOD_SW) - EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0); - #else -@@ -2616,7 +2616,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit - srcw += sizeof(sljit_sw); - #endif - #endif --#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && defined(_WIN64) -+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && (defined(_WIN64) || defined(__CYGWIN__)) - if (src == SLJIT_R2) { - EMIT_MOV(compiler, TMP_REG1, 0, src, 0); - src = TMP_REG1; diff --git a/build/pkgs/pcre/spkg-configure.m4 b/build/pkgs/pcre/spkg-configure.m4 deleted file mode 100644 index ac5e51f6601..00000000000 --- a/build/pkgs/pcre/spkg-configure.m4 +++ /dev/null @@ -1,18 +0,0 @@ -SAGE_SPKG_CONFIGURE([pcre], [ - AC_REQUIRE([SAGE_SPKG_CONFIGURE_BZIP2]) - AC_MSG_CHECKING([installing bzip2? ]) - if test x$sage_spkg_install_bzip2 = xyes; then - AC_MSG_RESULT([yes; install pcre as well]) - sage_spkg_install_pcre=yes - else - AC_MSG_RESULT([no]) - dnl First try checking for pcre with pkg-config - PKG_CHECK_MODULES([PCRE], [libpcre >= 8.39 libpcreposix libpcrecpp], [], [ - dnl Fallback to manually grubbing around for headers and libs - AC_CHECK_HEADERS([pcre.h pcrecpp.h pcreposix.h], [ - AC_SEARCH_LIBS([regexec], [pcreposix], [], [sage_spkg_install_pcre=yes])], - [sage_spkg_install_pcre=yes]) - ]) - fi -]) - diff --git a/build/pkgs/pcre/spkg-install.in b/build/pkgs/pcre/spkg-install.in deleted file mode 100644 index fb0c49272fe..00000000000 --- a/build/pkgs/pcre/spkg-install.in +++ /dev/null @@ -1,27 +0,0 @@ -cd src - -PCRE_CONFIGURE="--enable-utf --enable-unicode-properties $PCRE_CONFIGURE" - -sdh_configure $PCRE_CONFIGURE --enable-jit -sdh_make - -# The JIT feature of pcre is known to be broken on some systems, in -# particular on Solaris. We run the testsuite of pcre (this takes only -# a few seconds). It the testsuite fails, we rebuild pcre without JIT -# support. See https://github.com/sagemath/sage/issues/24628 -if ! $MAKE check; then - echo >&2 "*** Rebuilding pcre without JIT support ***" - $MAKE clean - - sdh_configure $PCRE_CONFIGURE --disable-jit - sdh_make - - # On some systems, the test suite fails anyway but PCRE still works - # for all practical purposes. So, the second time, we only run the - # testsuite if explicitly asked. - if [ "$SAGE_CHECK" = yes ]; then - $MAKE check || sdh_die "Error checking $PKG_NAME" - fi -fi - -sdh_make_install diff --git a/build/pkgs/pexpect/dependencies b/build/pkgs/pexpect/dependencies index 4a942502496..d3f8eced66f 100644 --- a/build/pkgs/pexpect/dependencies +++ b/build/pkgs/pexpect/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) ptyprocess | $(PYTHON_TOOLCHAIN) + ptyprocess | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pexpect/distros/arch.txt b/build/pkgs/pexpect/distros/arch.txt new file mode 100644 index 00000000000..74d08141569 --- /dev/null +++ b/build/pkgs/pexpect/distros/arch.txt @@ -0,0 +1 @@ +python-pexpect diff --git a/build/pkgs/pexpect/distros/fedora.txt b/build/pkgs/pexpect/distros/fedora.txt new file mode 100644 index 00000000000..74d08141569 --- /dev/null +++ b/build/pkgs/pexpect/distros/fedora.txt @@ -0,0 +1 @@ +python-pexpect diff --git a/build/pkgs/pexpect/distros/freebsd.txt b/build/pkgs/pexpect/distros/freebsd.txt new file mode 100644 index 00000000000..767fd38a2fa --- /dev/null +++ b/build/pkgs/pexpect/distros/freebsd.txt @@ -0,0 +1 @@ +misc/py-pexpect diff --git a/build/pkgs/pexpect/distros/gentoo.txt b/build/pkgs/pexpect/distros/gentoo.txt new file mode 100644 index 00000000000..30c4b60d014 --- /dev/null +++ b/build/pkgs/pexpect/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pexpect diff --git a/build/pkgs/pexpect/distros/opensuse.txt b/build/pkgs/pexpect/distros/opensuse.txt index 8d745ee4a07..f8cc97d1599 100644 --- a/build/pkgs/pexpect/distros/opensuse.txt +++ b/build/pkgs/pexpect/distros/opensuse.txt @@ -1 +1 @@ -python3-pexpect +python3${PYTHON_MINOR}-pexpect diff --git a/build/pkgs/pexpect/spkg-configure.m4 b/build/pkgs/pexpect/spkg-configure.m4 new file mode 100644 index 00000000000..6520856fbb5 --- /dev/null +++ b/build/pkgs/pexpect/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pexpect], [SAGE_PYTHON_PACKAGE_CHECK([pexpect])]) diff --git a/build/pkgs/phitigra/dependencies b/build/pkgs/phitigra/dependencies index 7aeb0c77c74..61dca76d6bc 100644 --- a/build/pkgs/phitigra/dependencies +++ b/build/pkgs/phitigra/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) ipywidgets pillow numpy | $(PYTHON_TOOLCHAIN) + ipywidgets pillow numpy | $(PYTHON_TOOLCHAIN) $(PYTHON) These dependencies include the install-requires of ipycanvas. ---------- diff --git a/build/pkgs/pickleshare/dependencies b/build/pkgs/pickleshare/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/pickleshare/dependencies +++ b/build/pkgs/pickleshare/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pickleshare/distros/arch.txt b/build/pkgs/pickleshare/distros/arch.txt new file mode 100644 index 00000000000..6d991a27d41 --- /dev/null +++ b/build/pkgs/pickleshare/distros/arch.txt @@ -0,0 +1 @@ +python-pickleshare diff --git a/build/pkgs/pickleshare/distros/debian.txt b/build/pkgs/pickleshare/distros/debian.txt new file mode 100644 index 00000000000..a00907d167b --- /dev/null +++ b/build/pkgs/pickleshare/distros/debian.txt @@ -0,0 +1 @@ +python3-pickleshare diff --git a/build/pkgs/pickleshare/distros/fedora.txt b/build/pkgs/pickleshare/distros/fedora.txt new file mode 100644 index 00000000000..6d991a27d41 --- /dev/null +++ b/build/pkgs/pickleshare/distros/fedora.txt @@ -0,0 +1 @@ +python-pickleshare diff --git a/build/pkgs/pickleshare/distros/gentoo.txt b/build/pkgs/pickleshare/distros/gentoo.txt new file mode 100644 index 00000000000..14fad0fa428 --- /dev/null +++ b/build/pkgs/pickleshare/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pickleshare diff --git a/build/pkgs/pickleshare/distros/opensuse.txt b/build/pkgs/pickleshare/distros/opensuse.txt index a00907d167b..260701493fc 100644 --- a/build/pkgs/pickleshare/distros/opensuse.txt +++ b/build/pkgs/pickleshare/distros/opensuse.txt @@ -1 +1 @@ -python3-pickleshare +python3${PYTHON_MINOR}-pickleshare diff --git a/build/pkgs/pickleshare/spkg-configure.m4 b/build/pkgs/pickleshare/spkg-configure.m4 new file mode 100644 index 00000000000..80e9b7ccba9 --- /dev/null +++ b/build/pkgs/pickleshare/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pickleshare], [SAGE_PYTHON_PACKAGE_CHECK([pickleshare])]) diff --git a/build/pkgs/pillow/dependencies b/build/pkgs/pillow/dependencies index 2ece64e58e8..f2500281136 100644 --- a/build/pkgs/pillow/dependencies +++ b/build/pkgs/pillow/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) zlib freetype | $(PYTHON_TOOLCHAIN) pkgconf + zlib freetype | $(PYTHON_TOOLCHAIN) pkgconf $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pillow/distros/arch.txt b/build/pkgs/pillow/distros/arch.txt new file mode 100644 index 00000000000..86dbb1d13b8 --- /dev/null +++ b/build/pkgs/pillow/distros/arch.txt @@ -0,0 +1 @@ +python-pillow diff --git a/build/pkgs/pillow/distros/debian.txt b/build/pkgs/pillow/distros/debian.txt new file mode 100644 index 00000000000..3319fcd7e0f --- /dev/null +++ b/build/pkgs/pillow/distros/debian.txt @@ -0,0 +1 @@ +python3-pillow diff --git a/build/pkgs/pillow/distros/fedora.txt b/build/pkgs/pillow/distros/fedora.txt new file mode 100644 index 00000000000..86dbb1d13b8 --- /dev/null +++ b/build/pkgs/pillow/distros/fedora.txt @@ -0,0 +1 @@ +python-pillow diff --git a/build/pkgs/pillow/distros/gentoo.txt b/build/pkgs/pillow/distros/gentoo.txt new file mode 100644 index 00000000000..12436496ed4 --- /dev/null +++ b/build/pkgs/pillow/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pillow diff --git a/build/pkgs/pillow/distros/opensuse.txt b/build/pkgs/pillow/distros/opensuse.txt index 88283bea6d9..8261b108af6 100644 --- a/build/pkgs/pillow/distros/opensuse.txt +++ b/build/pkgs/pillow/distros/opensuse.txt @@ -1 +1 @@ -python3-Pillow +python3${PYTHON_MINOR}-Pillow diff --git a/build/pkgs/pillow/spkg-configure.m4 b/build/pkgs/pillow/spkg-configure.m4 new file mode 100644 index 00000000000..f2e68e230ac --- /dev/null +++ b/build/pkgs/pillow/spkg-configure.m4 @@ -0,0 +1,5 @@ +SAGE_SPKG_CONFIGURE([pillow], [ + SAGE_SPKG_DEPCHECK([bzip2 freetype libpng zlib], [ + SAGE_PYTHON_PACKAGE_CHECK([pillow]) + ]) +]) diff --git a/build/pkgs/pint/dependencies b/build/pkgs/pint/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/pint/dependencies +++ b/build/pkgs/pint/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pip/dependencies b/build/pkgs/pip/dependencies index 618d627629a..dac3579f7e3 100644 --- a/build/pkgs/pip/dependencies +++ b/build/pkgs/pip/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) setuptools wheel + setuptools wheel | $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pip/distros/debian.txt b/build/pkgs/pip/distros/debian.txt new file mode 100644 index 00000000000..39bd9fc5097 --- /dev/null +++ b/build/pkgs/pip/distros/debian.txt @@ -0,0 +1 @@ +python3-pip diff --git a/build/pkgs/pip/distros/fedora.txt b/build/pkgs/pip/distros/fedora.txt new file mode 100644 index 00000000000..311c1b821ca --- /dev/null +++ b/build/pkgs/pip/distros/fedora.txt @@ -0,0 +1 @@ +python-pip diff --git a/build/pkgs/pip/distros/freebsd.txt b/build/pkgs/pip/distros/freebsd.txt new file mode 100644 index 00000000000..7b125c1bfa4 --- /dev/null +++ b/build/pkgs/pip/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-pip diff --git a/build/pkgs/pip/distros/gentoo.txt b/build/pkgs/pip/distros/gentoo.txt new file mode 100644 index 00000000000..793fb731829 --- /dev/null +++ b/build/pkgs/pip/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pip diff --git a/build/pkgs/pip/distros/opensuse.txt b/build/pkgs/pip/distros/opensuse.txt index 39bd9fc5097..eb4aa7ea9f1 100644 --- a/build/pkgs/pip/distros/opensuse.txt +++ b/build/pkgs/pip/distros/opensuse.txt @@ -1 +1 @@ -python3-pip +python3${PYTHON_MINOR}-pip diff --git a/build/pkgs/pip/install-requires.txt b/build/pkgs/pip/install-requires.txt index 7af2e246633..5e76a10f694 100644 --- a/build/pkgs/pip/install-requires.txt +++ b/build/pkgs/pip/install-requires.txt @@ -1,2 +1,3 @@ -pip >=21.3 +pip >=22.1 # for use of the "in-tree-build" feature, default since 21.3, by the Sage distribution +# for use of --config-settings, 22.1 diff --git a/build/pkgs/pip/spkg-configure.m4 b/build/pkgs/pip/spkg-configure.m4 new file mode 100644 index 00000000000..c7a55621f48 --- /dev/null +++ b/build/pkgs/pip/spkg-configure.m4 @@ -0,0 +1,12 @@ +SAGE_SPKG_CONFIGURE([pip], [ + dnl always run this macro because it changes the default value of + dnl the --with-system-<package> option. + SAGE_PYTHON_PACKAGE_CHECK([pip]) + + dnl if we might not install the spkg, make sure that "pip" is in + dnl the user's PATH, too. + AS_IF([test "x$sage_spkg_install_pip" != "xyes"], [ + AC_CHECK_PROG(HAVE_PIP, pip, yes, no) + AS_IF([test "x$HAVE_PIP" = "xno"], [sage_spkg_install_pip=yes]) + ]) +]) diff --git a/build/pkgs/pkgconfig/checksums.ini b/build/pkgs/pkgconfig/checksums.ini index d3cc48bde60..80d5aac1b27 100644 --- a/build/pkgs/pkgconfig/checksums.ini +++ b/build/pkgs/pkgconfig/checksums.ini @@ -1,5 +1,5 @@ -tarball=pkgconfig-VERSION.tar.gz -sha1=32af6abc220c64b36f745a208b950542b1ab3456 -md5=12523e11b91b050ca49975cc033689a4 -cksum=1707388199 -upstream_url=https://pypi.io/packages/source/p/pkgconfig/pkgconfig-VERSION.tar.gz +tarball=pkgconfig-VERSION-py3-none-any.whl +sha1=bca14b2806a8e8afb0bd04f8e3675550b286dda8 +md5=80f1e06563f3af0f090694db58736455 +cksum=15738577 +upstream_url=https://pypi.io/packages/py3/p/pkgconfig/pkgconfig-VERSION-py3-none-any.whl diff --git a/build/pkgs/pkgconfig/dependencies b/build/pkgs/pkgconfig/dependencies index 6dfe046e55e..07274d4d9a5 100644 --- a/build/pkgs/pkgconfig/dependencies +++ b/build/pkgs/pkgconfig/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) pkgconf poetry_core + | pkgconf $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pkgconfig/distros/arch.txt b/build/pkgs/pkgconfig/distros/arch.txt new file mode 100644 index 00000000000..38a18b3565f --- /dev/null +++ b/build/pkgs/pkgconfig/distros/arch.txt @@ -0,0 +1 @@ +python-pkgconfig diff --git a/build/pkgs/pkgconfig/distros/debian.txt b/build/pkgs/pkgconfig/distros/debian.txt new file mode 100644 index 00000000000..38e5106dd74 --- /dev/null +++ b/build/pkgs/pkgconfig/distros/debian.txt @@ -0,0 +1 @@ +python3-pkgconfig diff --git a/build/pkgs/pkgconfig/distros/fedora.txt b/build/pkgs/pkgconfig/distros/fedora.txt new file mode 100644 index 00000000000..38a18b3565f --- /dev/null +++ b/build/pkgs/pkgconfig/distros/fedora.txt @@ -0,0 +1 @@ +python-pkgconfig diff --git a/build/pkgs/pkgconfig/distros/freebsd.txt b/build/pkgs/pkgconfig/distros/freebsd.txt new file mode 100644 index 00000000000..d26a4e96787 --- /dev/null +++ b/build/pkgs/pkgconfig/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-pkgconfig diff --git a/build/pkgs/pkgconfig/distros/gentoo.txt b/build/pkgs/pkgconfig/distros/gentoo.txt new file mode 100644 index 00000000000..32e86187155 --- /dev/null +++ b/build/pkgs/pkgconfig/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pkgconfig diff --git a/build/pkgs/pkgconfig/install-requires.txt b/build/pkgs/pkgconfig/install-requires.txt index afa452604e3..549fd1bf164 100644 --- a/build/pkgs/pkgconfig/install-requires.txt +++ b/build/pkgs/pkgconfig/install-requires.txt @@ -1 +1 @@ -pkgconfig >=1.5.1 +pkgconfig diff --git a/build/pkgs/pkgconfig/spkg-configure.m4 b/build/pkgs/pkgconfig/spkg-configure.m4 new file mode 100644 index 00000000000..67082934525 --- /dev/null +++ b/build/pkgs/pkgconfig/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pkgconfig], [SAGE_PYTHON_PACKAGE_CHECK([pkgconfig])]) diff --git a/build/pkgs/pkgconfig/spkg-install.in b/build/pkgs/pkgconfig/spkg-install.in deleted file mode 100644 index d14edc90bcd..00000000000 --- a/build/pkgs/pkgconfig/spkg-install.in +++ /dev/null @@ -1,8 +0,0 @@ -cd src - -sdh_pip_install . - -if [ $? -ne 0 ]; then - echo >&2 "Error installing pkgconfig." - exit 1 -fi diff --git a/build/pkgs/platformdirs/checksums.ini b/build/pkgs/platformdirs/checksums.ini index 604aa7f6c99..288483e8fc2 100644 --- a/build/pkgs/platformdirs/checksums.ini +++ b/build/pkgs/platformdirs/checksums.ini @@ -1,5 +1,5 @@ tarball=platformdirs-VERSION.tar.gz -sha1=082974f7d3ea03adfa147f4ab5be76079c2a116f -md5=f449b7f3767577fa2a57465a4523e92e -cksum=2966639810 +sha1=c4e0f8486e67a97affbc1b6b267a1f196c4177fa +md5=1c1c8c05e9bc370b78e0a95103523b75 +cksum=4231977838 upstream_url=https://pypi.io/packages/source/p/platformdirs/platformdirs-VERSION.tar.gz diff --git a/build/pkgs/platformdirs/dependencies b/build/pkgs/platformdirs/dependencies index 5b4aec583a4..952ebfb66cd 100644 --- a/build/pkgs/platformdirs/dependencies +++ b/build/pkgs/platformdirs/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) setuptools_scm | $(PYTHON_TOOLCHAIN) hatchling hatch_vcs + setuptools_scm | $(PYTHON_TOOLCHAIN) hatchling hatch_vcs $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/platformdirs/distros/gentoo.txt b/build/pkgs/platformdirs/distros/gentoo.txt new file mode 100644 index 00000000000..e25e3dd9e9d --- /dev/null +++ b/build/pkgs/platformdirs/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/platformdirs diff --git a/build/pkgs/platformdirs/package-version.txt b/build/pkgs/platformdirs/package-version.txt index fe16b348d97..30291cba223 100644 --- a/build/pkgs/platformdirs/package-version.txt +++ b/build/pkgs/platformdirs/package-version.txt @@ -1 +1 @@ -2.5.4 +3.10.0 diff --git a/build/pkgs/platformdirs/spkg-configure.m4 b/build/pkgs/platformdirs/spkg-configure.m4 new file mode 100644 index 00000000000..a01f0dd4912 --- /dev/null +++ b/build/pkgs/platformdirs/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([platformdirs], [SAGE_PYTHON_PACKAGE_CHECK([platformdirs])]) diff --git a/build/pkgs/pluggy/checksums.ini b/build/pkgs/pluggy/checksums.ini index 087f36ad1a6..02c89db5e83 100644 --- a/build/pkgs/pluggy/checksums.ini +++ b/build/pkgs/pluggy/checksums.ini @@ -1,5 +1,5 @@ -tarball=pluggy-VERSION.tar.gz -sha1=0486bc511fc3415bb84252339b63b9d9e6d0734a -md5=daa6fddfb6cd364f3c82e52098911e4b -cksum=996010694 -upstream_url=https://pypi.io/packages/source/p/pluggy/pluggy-VERSION.tar.gz +tarball=pluggy-VERSION-py3-none-any.whl +sha1=25492905db99a151fc86368f0cca518a5ee5a832 +md5=9d0a58f023a0642eebae7c19f2729b72 +cksum=273236458 +upstream_url=https://pypi.io/packages/py3/p/pluggy/pluggy-VERSION-py3-none-any.whl diff --git a/build/pkgs/pluggy/dependencies b/build/pkgs/pluggy/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/pluggy/dependencies +++ b/build/pkgs/pluggy/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pluggy/distros/arch.txt b/build/pkgs/pluggy/distros/arch.txt new file mode 100644 index 00000000000..c869e54c551 --- /dev/null +++ b/build/pkgs/pluggy/distros/arch.txt @@ -0,0 +1 @@ +python-pluggy diff --git a/build/pkgs/pluggy/distros/debian.txt b/build/pkgs/pluggy/distros/debian.txt new file mode 100644 index 00000000000..43a3acf0462 --- /dev/null +++ b/build/pkgs/pluggy/distros/debian.txt @@ -0,0 +1 @@ +python3-pluggy diff --git a/build/pkgs/pluggy/distros/fedora.txt b/build/pkgs/pluggy/distros/fedora.txt new file mode 100644 index 00000000000..c869e54c551 --- /dev/null +++ b/build/pkgs/pluggy/distros/fedora.txt @@ -0,0 +1 @@ +python-pluggy diff --git a/build/pkgs/pluggy/distros/gentoo.txt b/build/pkgs/pluggy/distros/gentoo.txt new file mode 100644 index 00000000000..7b338764374 --- /dev/null +++ b/build/pkgs/pluggy/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pluggy diff --git a/build/pkgs/pluggy/distros/opensuse.txt b/build/pkgs/pluggy/distros/opensuse.txt new file mode 100644 index 00000000000..42720b43944 --- /dev/null +++ b/build/pkgs/pluggy/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-pluggy diff --git a/build/pkgs/pluggy/package-version.txt b/build/pkgs/pluggy/package-version.txt index 3eefcb9dd5b..f0bb29e7638 100644 --- a/build/pkgs/pluggy/package-version.txt +++ b/build/pkgs/pluggy/package-version.txt @@ -1 +1 @@ -1.0.0 +1.3.0 diff --git a/build/pkgs/pluggy/spkg-configure.m4 b/build/pkgs/pluggy/spkg-configure.m4 new file mode 100644 index 00000000000..11b1fce4f94 --- /dev/null +++ b/build/pkgs/pluggy/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pluggy], [SAGE_PYTHON_PACKAGE_CHECK([pluggy])]) diff --git a/build/pkgs/pluggy/spkg-install.in b/build/pkgs/pluggy/spkg-install.in deleted file mode 100644 index 37ac1a53437..00000000000 --- a/build/pkgs/pluggy/spkg-install.in +++ /dev/null @@ -1,2 +0,0 @@ -cd src -sdh_pip_install . diff --git a/build/pkgs/ply/dependencies b/build/pkgs/ply/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/ply/dependencies +++ b/build/pkgs/ply/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/ply/distros/gentoo.txt b/build/pkgs/ply/distros/gentoo.txt new file mode 100644 index 00000000000..c8b16309b09 --- /dev/null +++ b/build/pkgs/ply/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/ply diff --git a/build/pkgs/ply/spkg-configure.m4 b/build/pkgs/ply/spkg-configure.m4 new file mode 100644 index 00000000000..ffb0030d013 --- /dev/null +++ b/build/pkgs/ply/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([ply], [SAGE_PYTHON_PACKAGE_CHECK([ply])]) diff --git a/build/pkgs/poetry_core/SPKG.rst b/build/pkgs/poetry_core/SPKG.rst deleted file mode 100644 index 6a65756f4ec..00000000000 --- a/build/pkgs/poetry_core/SPKG.rst +++ /dev/null @@ -1,18 +0,0 @@ -poetry_core: Poetry PEP 517 Build Backend -========================================= - -Description ------------ - -Poetry PEP 517 Build Backend - -License -------- - -MIT - -Upstream Contact ----------------- - -https://pypi.org/project/poetry-core/ - diff --git a/build/pkgs/poetry_core/checksums.ini b/build/pkgs/poetry_core/checksums.ini deleted file mode 100644 index bef11e2f92c..00000000000 --- a/build/pkgs/poetry_core/checksums.ini +++ /dev/null @@ -1,5 +0,0 @@ -tarball=poetry-core-VERSION.tar.gz -sha1=67c8e65065f751c87cadf973a0a2d7b2cfad3bfa -md5=8cc4e6bf435733d91bb1b2fd7ec85749 -cksum=2571863917 -upstream_url=https://pypi.io/packages/source/p/poetry_core/poetry-core-VERSION.tar.gz diff --git a/build/pkgs/poetry_core/dependencies b/build/pkgs/poetry_core/dependencies deleted file mode 100644 index 0738c2d7777..00000000000 --- a/build/pkgs/poetry_core/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/poetry_core/distros/conda.txt b/build/pkgs/poetry_core/distros/conda.txt deleted file mode 100644 index 9b1f9e3fa7d..00000000000 --- a/build/pkgs/poetry_core/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -poetry-core diff --git a/build/pkgs/poetry_core/install-requires.txt b/build/pkgs/poetry_core/install-requires.txt deleted file mode 100644 index 9b1f9e3fa7d..00000000000 --- a/build/pkgs/poetry_core/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -poetry-core diff --git a/build/pkgs/poetry_core/package-version.txt b/build/pkgs/poetry_core/package-version.txt deleted file mode 100644 index b0f3d96f877..00000000000 --- a/build/pkgs/poetry_core/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -1.0.8 diff --git a/build/pkgs/poetry_core/patches/5547.diff_bin b/build/pkgs/poetry_core/patches/5547.diff_bin deleted file mode 100644 index f4f5f4c83b8..00000000000 --- a/build/pkgs/poetry_core/patches/5547.diff_bin +++ /dev/null @@ -1,12 +0,0 @@ -diff -urB a/poetry/core/vcs/__init__.py b/poetry/core/vcs/__init__.py ---- a/poetry/core/vcs/__init__.py 2022-02-27 20:15:29.000000000 -0800 -+++ b/poetry/core/vcs/__init__.py 2022-05-05 10:26:37.248645073 -0700 -@@ -20,7 +20,7 @@ - ) - ).strip() - -- vcs = Git(Path(git_dir)) -+ vcs = Git(Path(git_dir)) if git_dir.startswith(str(directory.resolve())) else None - - except (subprocess.CalledProcessError, OSError, RuntimeError): - vcs = None diff --git a/build/pkgs/poetry_core/spkg-install.in b/build/pkgs/poetry_core/spkg-install.in deleted file mode 100644 index 4dc571e2c62..00000000000 --- a/build/pkgs/poetry_core/spkg-install.in +++ /dev/null @@ -1,4 +0,0 @@ -cd src -# Work around https://github.com/python-poetry/poetry/issues/5547 -patch -p1 --posix --binary < "../patches/5547.diff_bin" || sdh_die -sdh_pip_install . diff --git a/build/pkgs/polymake/checksums.ini b/build/pkgs/polymake/checksums.ini index 2727d96238b..eba30ebcced 100644 --- a/build/pkgs/polymake/checksums.ini +++ b/build/pkgs/polymake/checksums.ini @@ -1,5 +1,5 @@ tarball=polymake-VERSION-minimal.tar.bz2 -sha1=a3903ef9438388e56a76cb04918c1fe9b2e2b563 -md5=9a451d56cfe8c6138b91558d6d369dbe -cksum=1195315956 +sha1=e34a9cb83a831b4b058e0803a606f29ff940a4e2 +md5=2118f0cae2f512b994bbc72552966bb9 +cksum=2954910267 upstream_url=https://polymake.org/lib/exe/fetch.php/download/polymake-VERSION-minimal.tar.bz2 diff --git a/build/pkgs/polymake/dependencies b/build/pkgs/polymake/dependencies index b3ed8ed4299..c7df48724c2 100644 --- a/build/pkgs/polymake/dependencies +++ b/build/pkgs/polymake/dependencies @@ -1,4 +1,4 @@ -$(MP_LIBRARY) bliss cddlib normaliz perl_term_readline_gnu ppl perl_cpan_polymake_prereq libxml2 | ninja_build +$(MP_LIBRARY) bliss cddlib normaliz perl_term_readline_gnu ppl perl_cpan_polymake_prereq libxml2 lrslib | ninja_build ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/polymake/package-version.txt b/build/pkgs/polymake/package-version.txt index 4f8c639658e..86a9588adcd 100644 --- a/build/pkgs/polymake/package-version.txt +++ b/build/pkgs/polymake/package-version.txt @@ -1 +1 @@ -4.7 +4.9 diff --git a/build/pkgs/polymake/spkg-install.in b/build/pkgs/polymake/spkg-install.in index 827409cccd2..36e32de869e 100644 --- a/build/pkgs/polymake/spkg-install.in +++ b/build/pkgs/polymake/spkg-install.in @@ -21,6 +21,10 @@ if [ -x $SAGE_LOCAL/bin/lrs1 ]; then more_configure_options="$more_configure_options --with-lrs=$SAGE_LOCAL" fi +# Put these includes on the front, to avoid shadowing by installed headers +# from a previous version. (polymake 4.8 puts these includes to the end.) +export CXXFLAGS="-I$(pwd)/include/core-wrappers -I$(pwd)/include/core $CXXFLAGS" + ./configure --without-java \ --without-javaview \ --without-soplex \ diff --git a/build/pkgs/pplpy/SPKG.rst b/build/pkgs/pplpy/SPKG.rst index 0708613cd43..1d894de3198 100644 --- a/build/pkgs/pplpy/SPKG.rst +++ b/build/pkgs/pplpy/SPKG.rst @@ -20,4 +20,4 @@ GPL version 3 Upstream Contact ---------------- -- https://github.com/videlec/pplpy +- https://github.com/sagemath/pplpy diff --git a/build/pkgs/pplpy/checksums.ini b/build/pkgs/pplpy/checksums.ini index daf28c45b01..22961af9a1f 100644 --- a/build/pkgs/pplpy/checksums.ini +++ b/build/pkgs/pplpy/checksums.ini @@ -1,5 +1,5 @@ tarball=pplpy-VERSION.tar.gz -sha1=b4f7d8ce6e78b3b55f71291ae912cf5bfab604f9 -md5=fabbdba19ce8fb2269024e99e13f028c -cksum=1087084993 +sha1=9f0d531d77dab19f1f0f350022687a8bd749aee2 +md5=980223c38fc95b2f4f8265f20b45a98e +cksum=3147352163 upstream_url=https://pypi.io/packages/source/p/pplpy/pplpy-VERSION.tar.gz diff --git a/build/pkgs/pplpy/dependencies b/build/pkgs/pplpy/dependencies index d3e56291f73..f61061ddefe 100644 --- a/build/pkgs/pplpy/dependencies +++ b/build/pkgs/pplpy/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) $(MP_LIBRARY) gmpy2 cysignals mpfr mpc ppl | $(PYTHON_TOOLCHAIN) + $(MP_LIBRARY) gmpy2 cysignals mpfr mpc ppl | $(PYTHON_TOOLCHAIN) sphinx $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pplpy/distros/arch.txt b/build/pkgs/pplpy/distros/arch.txt new file mode 100644 index 00000000000..579bdb042f6 --- /dev/null +++ b/build/pkgs/pplpy/distros/arch.txt @@ -0,0 +1 @@ +python-pplpy diff --git a/build/pkgs/pplpy/distros/fedora.txt b/build/pkgs/pplpy/distros/fedora.txt new file mode 100644 index 00000000000..579bdb042f6 --- /dev/null +++ b/build/pkgs/pplpy/distros/fedora.txt @@ -0,0 +1 @@ +python-pplpy diff --git a/build/pkgs/pplpy/distros/freebsd.txt b/build/pkgs/pplpy/distros/freebsd.txt new file mode 100644 index 00000000000..2006f870646 --- /dev/null +++ b/build/pkgs/pplpy/distros/freebsd.txt @@ -0,0 +1 @@ +math/py-pplpy diff --git a/build/pkgs/pplpy/distros/void.txt b/build/pkgs/pplpy/distros/void.txt new file mode 100644 index 00000000000..f39eaff76ae --- /dev/null +++ b/build/pkgs/pplpy/distros/void.txt @@ -0,0 +1 @@ +python3-pplpy diff --git a/build/pkgs/pplpy/package-version.txt b/build/pkgs/pplpy/package-version.txt index 7fc2521fd74..1e9b46b2298 100644 --- a/build/pkgs/pplpy/package-version.txt +++ b/build/pkgs/pplpy/package-version.txt @@ -1 +1 @@ -0.8.6 +0.8.7 diff --git a/build/pkgs/pplpy/patches/cython3-legacy.patch b/build/pkgs/pplpy/patches/cython3-legacy.patch new file mode 100644 index 00000000000..a038da16d6b --- /dev/null +++ b/build/pkgs/pplpy/patches/cython3-legacy.patch @@ -0,0 +1,22 @@ +commit e6f3e66154138ce3e31e803e74b8c71787c70acc +Author: Gonzalo Tornarรญa <tornaria@cmat.edu.uy> +Date: Wed Jul 19 20:47:52 2023 -0300 + + cython3 support using legacy directives + +diff --git a/setup.py b/setup.py +index 13d543b..55dcd34 100755 +--- a/setup.py ++++ b/setup.py +@@ -38,7 +38,11 @@ class build_ext(_build_ext): + self.extensions[:] = cythonize( + self.extensions, + include_path=sys.path, +- compiler_directives={'embedsignature': True}) ++ compiler_directives={ ++ 'embedsignature': True, ++ 'legacy_implicit_noexcept': True, ++ 'c_api_binop_methods': True, ++ }) + + _build_ext.run(self) diff --git a/build/pkgs/pplpy/patches/relative-import.patch b/build/pkgs/pplpy/patches/relative-import.patch new file mode 100644 index 00000000000..3c011203367 --- /dev/null +++ b/build/pkgs/pplpy/patches/relative-import.patch @@ -0,0 +1,21 @@ +From aaa28537fa7ea061ebb8d5131b1e23673eaf741d Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe <mkoeppe@math.ucdavis.edu> +Date: Sun, 31 Jul 2022 12:39:34 -0700 +Subject: [PATCH] ppl/bit_arrays.pxd: Use relative cimport + +--- + ppl/bit_arrays.pxd | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ppl/bit_arrays.pxd b/ppl/bit_arrays.pxd +index eb57434..145a978 100644 +--- a/ppl/bit_arrays.pxd ++++ b/ppl/bit_arrays.pxd +@@ -1,4 +1,4 @@ +-from ppl_decl cimport * ++from .ppl_decl cimport * + + cdef class Bit_Row(object): + cdef PPL_Bit_Row *thisptr +-- +GitLab diff --git a/build/pkgs/pplpy_doc/SPKG.rst b/build/pkgs/pplpy_doc/SPKG.rst index e559dd568e9..241edcee713 100644 --- a/build/pkgs/pplpy_doc/SPKG.rst +++ b/build/pkgs/pplpy_doc/SPKG.rst @@ -15,4 +15,4 @@ GPL version 3 Upstream Contact ---------------- -- https://github.com/videlec/pplpy +- https://github.com/sagemath/pplpy diff --git a/build/pkgs/primecount/checksums.ini b/build/pkgs/primecount/checksums.ini index 21b9538bd58..11900687fca 100644 --- a/build/pkgs/primecount/checksums.ini +++ b/build/pkgs/primecount/checksums.ini @@ -1,5 +1,5 @@ tarball=primecount-VERSION.tar.gz -sha1=5477d5c69263d3f7d370a8fa4e9b2705b0db2911 -md5=9f7819fb0b2fc0cebd6f24d9b6115271 -cksum=167695697 +sha1=3854ef6c7f454086f31aa80d68f628c5b685d702 +md5=a566d9b95ccc01f0c7c1329ca4c06b89 +cksum=1260437024 upstream_url=https://github.com/kimwalisch/primecount/archive/refs/tags/vVERSION.tar.gz diff --git a/build/pkgs/primecount/distros/gentoo.txt b/build/pkgs/primecount/distros/gentoo.txt new file mode 100644 index 00000000000..6dac8de293b --- /dev/null +++ b/build/pkgs/primecount/distros/gentoo.txt @@ -0,0 +1 @@ +sci-mathematics/primecount diff --git a/build/pkgs/primecount/package-version.txt b/build/pkgs/primecount/package-version.txt index 37722ebbc75..38abeb202c0 100644 --- a/build/pkgs/primecount/package-version.txt +++ b/build/pkgs/primecount/package-version.txt @@ -1 +1 @@ -7.4 +7.6 diff --git a/build/pkgs/primecountpy/dependencies b/build/pkgs/primecountpy/dependencies index c141a1d7c2f..ce1374b2a0e 100644 --- a/build/pkgs/primecountpy/dependencies +++ b/build/pkgs/primecountpy/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) primecount cysignals | $(PYTHON_TOOLCHAIN) cython + primecount cysignals | $(PYTHON_TOOLCHAIN) cython $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/primesieve/checksums.ini b/build/pkgs/primesieve/checksums.ini index 723897aec8a..2f3dc247407 100644 --- a/build/pkgs/primesieve/checksums.ini +++ b/build/pkgs/primesieve/checksums.ini @@ -1,5 +1,5 @@ tarball=primesieve-VERSION.tar.gz -sha1=abd7627ac05dbc61c5cf7200f1d4570217a9f6d7 -md5=9c6cc6d25dcc8ba85369bd29761512b5 -cksum=2105775559 +sha1=cb0a7c49b37b51980fc610d3041b9591c67a460c +md5=73f51a77b0d43356b404999e777ad910 +cksum=1567518743 upstream_url=https://github.com/kimwalisch/primesieve/archive/refs/tags/vVERSION.tar.gz diff --git a/build/pkgs/primesieve/distros/gentoo.txt b/build/pkgs/primesieve/distros/gentoo.txt new file mode 100644 index 00000000000..9cb22ee12ac --- /dev/null +++ b/build/pkgs/primesieve/distros/gentoo.txt @@ -0,0 +1 @@ +sci-mathematics/primesieve diff --git a/build/pkgs/primesieve/package-version.txt b/build/pkgs/primesieve/package-version.txt index cc40bca69a0..2dbc24b32d3 100644 --- a/build/pkgs/primesieve/package-version.txt +++ b/build/pkgs/primesieve/package-version.txt @@ -1 +1 @@ -8.0 +11.0 diff --git a/build/pkgs/prometheus_client/dependencies b/build/pkgs/prometheus_client/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/prometheus_client/dependencies +++ b/build/pkgs/prometheus_client/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/prometheus_client/distros/gentoo.txt b/build/pkgs/prometheus_client/distros/gentoo.txt new file mode 100644 index 00000000000..aa2889c913e --- /dev/null +++ b/build/pkgs/prometheus_client/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/prometheus_client diff --git a/build/pkgs/prometheus_client/distros/opensuse.txt b/build/pkgs/prometheus_client/distros/opensuse.txt index 4d7723ec37e..c061661b6e6 100644 --- a/build/pkgs/prometheus_client/distros/opensuse.txt +++ b/build/pkgs/prometheus_client/distros/opensuse.txt @@ -1 +1 @@ -python3-prometheus_client +python3${PYTHON_MINOR}-prometheus_client diff --git a/build/pkgs/prometheus_client/spkg-configure.m4 b/build/pkgs/prometheus_client/spkg-configure.m4 new file mode 100644 index 00000000000..b4945889131 --- /dev/null +++ b/build/pkgs/prometheus_client/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([prometheus_client], [ + SAGE_PYTHON_PACKAGE_CHECK([prometheus_client]) +]) diff --git a/build/pkgs/prompt_toolkit/dependencies b/build/pkgs/prompt_toolkit/dependencies index 57465daf937..2bdb6af86bc 100644 --- a/build/pkgs/prompt_toolkit/dependencies +++ b/build/pkgs/prompt_toolkit/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) six wcwidth | $(PYTHON_TOOLCHAIN) + six wcwidth | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/prompt_toolkit/distros/arch.txt b/build/pkgs/prompt_toolkit/distros/arch.txt new file mode 100644 index 00000000000..89b0ac83a9b --- /dev/null +++ b/build/pkgs/prompt_toolkit/distros/arch.txt @@ -0,0 +1 @@ +python-importlib_resources diff --git a/build/pkgs/prompt_toolkit/distros/debian.txt b/build/pkgs/prompt_toolkit/distros/debian.txt new file mode 100644 index 00000000000..2b0146fc669 --- /dev/null +++ b/build/pkgs/prompt_toolkit/distros/debian.txt @@ -0,0 +1 @@ +importlib-resources diff --git a/build/pkgs/prompt_toolkit/distros/fedora.txt b/build/pkgs/prompt_toolkit/distros/fedora.txt new file mode 100644 index 00000000000..967f8570d4f --- /dev/null +++ b/build/pkgs/prompt_toolkit/distros/fedora.txt @@ -0,0 +1 @@ +python-prompt-toolkit diff --git a/build/pkgs/prompt_toolkit/distros/freebsd.txt b/build/pkgs/prompt_toolkit/distros/freebsd.txt new file mode 100644 index 00000000000..a2f0c05129b --- /dev/null +++ b/build/pkgs/prompt_toolkit/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-importlib-resources diff --git a/build/pkgs/prompt_toolkit/distros/gentoo.txt b/build/pkgs/prompt_toolkit/distros/gentoo.txt new file mode 100644 index 00000000000..6902484e74c --- /dev/null +++ b/build/pkgs/prompt_toolkit/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/prompt_toolkit diff --git a/build/pkgs/prompt_toolkit/distros/opensuse.txt b/build/pkgs/prompt_toolkit/distros/opensuse.txt index 424253f1340..3c48b809bc1 100644 --- a/build/pkgs/prompt_toolkit/distros/opensuse.txt +++ b/build/pkgs/prompt_toolkit/distros/opensuse.txt @@ -1 +1 @@ -python3-prompt_toolkit +python3${PYTHON_MINOR}-importlib_resources diff --git a/build/pkgs/prompt_toolkit/spkg-configure.m4 b/build/pkgs/prompt_toolkit/spkg-configure.m4 new file mode 100644 index 00000000000..fd8c1a67015 --- /dev/null +++ b/build/pkgs/prompt_toolkit/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([prompt_toolkit], [ + SAGE_PYTHON_PACKAGE_CHECK([prompt_toolkit]) +]) diff --git a/build/pkgs/ptyprocess/checksums.ini b/build/pkgs/ptyprocess/checksums.ini index 7c8cf7bd652..d55046be142 100644 --- a/build/pkgs/ptyprocess/checksums.ini +++ b/build/pkgs/ptyprocess/checksums.ini @@ -1,5 +1,5 @@ tarball=ptyprocess-VERSION.tar.gz -sha1=3290062d67ef8a2f136bff9c2cd106673ff21316 -md5=94e537122914cc9ec9c1eadcd36e73a1 -cksum=1748633415 +sha1=2d8830d1025c8e33149c7723c2f283122f9488c1 +md5=9da200c397cb1752209a6b718b6cfc68 +cksum=2094263560 upstream_url=https://pypi.io/packages/source/p/ptyprocess/ptyprocess-VERSION.tar.gz diff --git a/build/pkgs/ptyprocess/dependencies b/build/pkgs/ptyprocess/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/ptyprocess/dependencies +++ b/build/pkgs/ptyprocess/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/ptyprocess/distros/arch.txt b/build/pkgs/ptyprocess/distros/arch.txt new file mode 100644 index 00000000000..911a22468fc --- /dev/null +++ b/build/pkgs/ptyprocess/distros/arch.txt @@ -0,0 +1 @@ +python-ptyprocess diff --git a/build/pkgs/ptyprocess/distros/conda.txt b/build/pkgs/ptyprocess/distros/conda.txt index 57ebb2d6bdd..4a518435c60 100644 --- a/build/pkgs/ptyprocess/distros/conda.txt +++ b/build/pkgs/ptyprocess/distros/conda.txt @@ -1 +1,3 @@ -ptyprocess +# The version should be fixed to 0.5.1 (see https://github.com/sagemath/sage/issues/32147), but this is not available on conda-forge +# thus don't install ptyprocess with conda, but let pip handle it +# ptyprocess diff --git a/build/pkgs/ptyprocess/distros/fedora.txt b/build/pkgs/ptyprocess/distros/fedora.txt new file mode 100644 index 00000000000..911a22468fc --- /dev/null +++ b/build/pkgs/ptyprocess/distros/fedora.txt @@ -0,0 +1 @@ +python-ptyprocess diff --git a/build/pkgs/ptyprocess/distros/freebsd.txt b/build/pkgs/ptyprocess/distros/freebsd.txt new file mode 100644 index 00000000000..bc587f2e5fc --- /dev/null +++ b/build/pkgs/ptyprocess/distros/freebsd.txt @@ -0,0 +1 @@ +sysutils/py-ptyprocess diff --git a/build/pkgs/ptyprocess/distros/gentoo.txt b/build/pkgs/ptyprocess/distros/gentoo.txt new file mode 100644 index 00000000000..571a851d976 --- /dev/null +++ b/build/pkgs/ptyprocess/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/ptyprocess diff --git a/build/pkgs/ptyprocess/distros/opensuse.txt b/build/pkgs/ptyprocess/distros/opensuse.txt index ad4f6db1ca7..846495a86e8 100644 --- a/build/pkgs/ptyprocess/distros/opensuse.txt +++ b/build/pkgs/ptyprocess/distros/opensuse.txt @@ -1 +1 @@ -python3-ptyprocess +python3${PYTHON_MINOR}-ptyprocess diff --git a/build/pkgs/ptyprocess/install-requires.txt b/build/pkgs/ptyprocess/install-requires.txt index a89be777b4a..4527bfdd3d1 100644 --- a/build/pkgs/ptyprocess/install-requires.txt +++ b/build/pkgs/ptyprocess/install-requires.txt @@ -1,3 +1 @@ -ptyprocess ==0.5.1 -# https://github.com/sagemath/sage/issues/31280#comment:42 and following -# sagelib is not compatible with ptyprocess 0.5.2, 0.6, and 0.7 +ptyprocess > 0.5 diff --git a/build/pkgs/ptyprocess/package-version.txt b/build/pkgs/ptyprocess/package-version.txt index dfd7f4b3ab3..faef31a4357 100644 --- a/build/pkgs/ptyprocess/package-version.txt +++ b/build/pkgs/ptyprocess/package-version.txt @@ -1 +1 @@ -0.5.1.p0 +0.7.0 diff --git a/build/pkgs/ptyprocess/spkg-configure.m4 b/build/pkgs/ptyprocess/spkg-configure.m4 new file mode 100644 index 00000000000..bfacbaed935 --- /dev/null +++ b/build/pkgs/ptyprocess/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([ptyprocess], [SAGE_PYTHON_PACKAGE_CHECK([ptyprocess])]) diff --git a/build/pkgs/pure_eval/dependencies b/build/pkgs/pure_eval/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/pure_eval/dependencies +++ b/build/pkgs/pure_eval/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pure_eval/distros/gentoo.txt b/build/pkgs/pure_eval/distros/gentoo.txt new file mode 100644 index 00000000000..9905067ea96 --- /dev/null +++ b/build/pkgs/pure_eval/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pure_eval diff --git a/build/pkgs/pure_eval/spkg-configure.m4 b/build/pkgs/pure_eval/spkg-configure.m4 new file mode 100644 index 00000000000..5b6ef2d4a6b --- /dev/null +++ b/build/pkgs/pure_eval/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pure_eval], [SAGE_PYTHON_PACKAGE_CHECK([pure_eval])]) diff --git a/build/pkgs/py/dependencies b/build/pkgs/py/dependencies index 14a312e5dee..995ddecb8f4 100644 --- a/build/pkgs/py/dependencies +++ b/build/pkgs/py/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) setuptools_scm + | $(PYTHON_TOOLCHAIN) setuptools_scm $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/py/distros/arch.txt b/build/pkgs/py/distros/arch.txt new file mode 100644 index 00000000000..b348d395fbd --- /dev/null +++ b/build/pkgs/py/distros/arch.txt @@ -0,0 +1 @@ +python-py diff --git a/build/pkgs/py/distros/debian.txt b/build/pkgs/py/distros/debian.txt new file mode 100644 index 00000000000..81fefe60903 --- /dev/null +++ b/build/pkgs/py/distros/debian.txt @@ -0,0 +1 @@ +python3-py diff --git a/build/pkgs/py/distros/fedora.txt b/build/pkgs/py/distros/fedora.txt new file mode 100644 index 00000000000..b348d395fbd --- /dev/null +++ b/build/pkgs/py/distros/fedora.txt @@ -0,0 +1 @@ +python-py diff --git a/build/pkgs/py/distros/gentoo.txt b/build/pkgs/py/distros/gentoo.txt new file mode 100644 index 00000000000..d4894e50cf7 --- /dev/null +++ b/build/pkgs/py/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/py diff --git a/build/pkgs/py/distros/opensuse.txt b/build/pkgs/py/distros/opensuse.txt new file mode 100644 index 00000000000..c03de61a449 --- /dev/null +++ b/build/pkgs/py/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-py diff --git a/build/pkgs/py/spkg-configure.m4 b/build/pkgs/py/spkg-configure.m4 new file mode 100644 index 00000000000..ded70343090 --- /dev/null +++ b/build/pkgs/py/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([py], [SAGE_PYTHON_PACKAGE_CHECK([py])]) diff --git a/build/pkgs/pybind11/checksums.ini b/build/pkgs/pybind11/checksums.ini index 1cc6d36c174..c8b9c661568 100644 --- a/build/pkgs/pybind11/checksums.ini +++ b/build/pkgs/pybind11/checksums.ini @@ -1,5 +1,5 @@ tarball=pybind11-VERSION.tar.gz -sha1=d0e6e22c2ce36fad4bb60dbac4d6d498ceb464df -md5=0b181dbb44c3cc632e724cef5081cae1 -cksum=4287838207 +sha1=3c75333a9056f0be18eb612803cd46a2bb0c87fc +md5=67c58224e41c442e47fa84e7789c2c39 +cksum=419587142 upstream_url=https://pypi.io/packages/source/p/pybind11/pybind11-VERSION.tar.gz diff --git a/build/pkgs/pybind11/dependencies b/build/pkgs/pybind11/dependencies index da2b0925acd..ca33204bd52 100644 --- a/build/pkgs/pybind11/dependencies +++ b/build/pkgs/pybind11/dependencies @@ -1 +1 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) diff --git a/build/pkgs/pybind11/distros/gentoo.txt b/build/pkgs/pybind11/distros/gentoo.txt new file mode 100644 index 00000000000..0c500b3c84d --- /dev/null +++ b/build/pkgs/pybind11/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pybind11 diff --git a/build/pkgs/pybind11/install-requires.txt b/build/pkgs/pybind11/install-requires.txt index 7f37917011f..6c44c4bd07e 100644 --- a/build/pkgs/pybind11/install-requires.txt +++ b/build/pkgs/pybind11/install-requires.txt @@ -1 +1 @@ -pybind11 >=2.5.0 +pybind11 >=2.6 diff --git a/build/pkgs/pybind11/package-version.txt b/build/pkgs/pybind11/package-version.txt index 8bbb6e406a7..6ceb272eecd 100644 --- a/build/pkgs/pybind11/package-version.txt +++ b/build/pkgs/pybind11/package-version.txt @@ -1 +1 @@ -2.10.1 +2.11.1 diff --git a/build/pkgs/pybind11/spkg-configure.m4 b/build/pkgs/pybind11/spkg-configure.m4 new file mode 100644 index 00000000000..cce1cf5cff8 --- /dev/null +++ b/build/pkgs/pybind11/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pybind11], [SAGE_PYTHON_PACKAGE_CHECK([pybind11])]) diff --git a/build/pkgs/pybtex/distros/opensuse.txt b/build/pkgs/pybtex/distros/opensuse.txt index bdd39a48fde..e482a1bfea0 100644 --- a/build/pkgs/pybtex/distros/opensuse.txt +++ b/build/pkgs/pybtex/distros/opensuse.txt @@ -1 +1 @@ -python3-pybtex +python3${PYTHON_MINOR}-pybtex diff --git a/build/pkgs/pycosat/dependencies b/build/pkgs/pycosat/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/pycosat/dependencies +++ b/build/pkgs/pycosat/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pycosat/distros/alpine.txt b/build/pkgs/pycosat/distros/alpine.txt new file mode 100644 index 00000000000..7eb034d6713 --- /dev/null +++ b/build/pkgs/pycosat/distros/alpine.txt @@ -0,0 +1 @@ +py3-pycosat diff --git a/build/pkgs/pycosat/distros/arch.txt b/build/pkgs/pycosat/distros/arch.txt new file mode 100644 index 00000000000..dab3122ef4c --- /dev/null +++ b/build/pkgs/pycosat/distros/arch.txt @@ -0,0 +1 @@ +python-pycosat diff --git a/build/pkgs/pycosat/distros/fedora.txt b/build/pkgs/pycosat/distros/fedora.txt new file mode 100644 index 00000000000..dab3122ef4c --- /dev/null +++ b/build/pkgs/pycosat/distros/fedora.txt @@ -0,0 +1 @@ +python-pycosat diff --git a/build/pkgs/pycosat/distros/freebsd.txt b/build/pkgs/pycosat/distros/freebsd.txt new file mode 100644 index 00000000000..35e4e7730cc --- /dev/null +++ b/build/pkgs/pycosat/distros/freebsd.txt @@ -0,0 +1 @@ +math/py-pycosat diff --git a/build/pkgs/pycparser/dependencies b/build/pkgs/pycparser/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/pycparser/dependencies +++ b/build/pkgs/pycparser/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pycparser/distros/gentoo.txt b/build/pkgs/pycparser/distros/gentoo.txt new file mode 100644 index 00000000000..5e87307c4b9 --- /dev/null +++ b/build/pkgs/pycparser/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pycparser diff --git a/build/pkgs/pycparser/distros/opensuse.txt b/build/pkgs/pycparser/distros/opensuse.txt index 0ba4f8b19f5..503e7c176d1 100644 --- a/build/pkgs/pycparser/distros/opensuse.txt +++ b/build/pkgs/pycparser/distros/opensuse.txt @@ -1 +1 @@ -python3-pycparser +python3${PYTHON_MINOR}-pycparser diff --git a/build/pkgs/pycparser/spkg-configure.m4 b/build/pkgs/pycparser/spkg-configure.m4 new file mode 100644 index 00000000000..4b9b90079a9 --- /dev/null +++ b/build/pkgs/pycparser/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pycparser], [SAGE_PYTHON_PACKAGE_CHECK([pycparser])]) diff --git a/build/pkgs/pycryptosat/dependencies b/build/pkgs/pycryptosat/dependencies index b897ff72eae..c51735427aa 100644 --- a/build/pkgs/pycryptosat/dependencies +++ b/build/pkgs/pycryptosat/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) m4ri zlib libpng cryptominisat | cmake boost_cropped $(PYTHON_TOOLCHAIN) + m4ri zlib libpng cryptominisat | cmake boost_cropped $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pycygwin/dependencies b/build/pkgs/pycygwin/dependencies index 296a2bebad3..1db13c07e43 100644 --- a/build/pkgs/pycygwin/dependencies +++ b/build/pkgs/pycygwin/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cython | $(PYTHON_TOOLCHAIN) + cython | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pyflakes/SPKG.rst b/build/pkgs/pyflakes/SPKG.rst deleted file mode 100644 index 88c3f07d2a7..00000000000 --- a/build/pkgs/pyflakes/SPKG.rst +++ /dev/null @@ -1,18 +0,0 @@ -pyflakes: Passive checker of Python programs -============================================ - -Description ------------ - -passive checker of Python programs - -License -------- - -MIT - -Upstream Contact ----------------- - -https://pypi.org/project/pyflakes/ - diff --git a/build/pkgs/pyflakes/distros/conda.txt b/build/pkgs/pyflakes/distros/conda.txt deleted file mode 100644 index 38675cb44a2..00000000000 --- a/build/pkgs/pyflakes/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -pyflakes diff --git a/build/pkgs/pyflakes/distros/macports.txt b/build/pkgs/pyflakes/distros/macports.txt deleted file mode 100644 index 399db8ac7bb..00000000000 --- a/build/pkgs/pyflakes/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -py-pyflakes diff --git a/build/pkgs/pyflakes/distros/opensuse.txt b/build/pkgs/pyflakes/distros/opensuse.txt deleted file mode 100644 index a16ae878a72..00000000000 --- a/build/pkgs/pyflakes/distros/opensuse.txt +++ /dev/null @@ -1 +0,0 @@ -python3-pyflakes diff --git a/build/pkgs/pyflakes/distros/repology.txt b/build/pkgs/pyflakes/distros/repology.txt deleted file mode 100644 index 9990e60b2eb..00000000000 --- a/build/pkgs/pyflakes/distros/repology.txt +++ /dev/null @@ -1,2 +0,0 @@ -pyflakes -python:pyflakes diff --git a/build/pkgs/pyflakes/distros/void.txt b/build/pkgs/pyflakes/distros/void.txt deleted file mode 100644 index a16ae878a72..00000000000 --- a/build/pkgs/pyflakes/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -python3-pyflakes diff --git a/build/pkgs/pyflakes/requirements.txt b/build/pkgs/pyflakes/requirements.txt deleted file mode 100644 index 38675cb44a2..00000000000 --- a/build/pkgs/pyflakes/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pyflakes diff --git a/build/pkgs/pygments/dependencies b/build/pkgs/pygments/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/pygments/dependencies +++ b/build/pkgs/pygments/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pygments/distros/arch.txt b/build/pkgs/pygments/distros/arch.txt new file mode 100644 index 00000000000..f3e72a89c38 --- /dev/null +++ b/build/pkgs/pygments/distros/arch.txt @@ -0,0 +1 @@ +python-pygments diff --git a/build/pkgs/pygments/distros/debian.txt b/build/pkgs/pygments/distros/debian.txt new file mode 100644 index 00000000000..3ab37929b2c --- /dev/null +++ b/build/pkgs/pygments/distros/debian.txt @@ -0,0 +1 @@ +python3-pygments diff --git a/build/pkgs/pygments/distros/fedora.txt b/build/pkgs/pygments/distros/fedora.txt new file mode 100644 index 00000000000..f3e72a89c38 --- /dev/null +++ b/build/pkgs/pygments/distros/fedora.txt @@ -0,0 +1 @@ +python-pygments diff --git a/build/pkgs/pygments/distros/gentoo.txt b/build/pkgs/pygments/distros/gentoo.txt new file mode 100644 index 00000000000..a584f321e71 --- /dev/null +++ b/build/pkgs/pygments/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pygments diff --git a/build/pkgs/pygments/distros/opensuse.txt b/build/pkgs/pygments/distros/opensuse.txt index 9ff5740e79c..ef63366ff27 100644 --- a/build/pkgs/pygments/distros/opensuse.txt +++ b/build/pkgs/pygments/distros/opensuse.txt @@ -1 +1 @@ -python3-Pygments +python3${PYTHON_MINOR}-pygments diff --git a/build/pkgs/pygments/install-requires.txt b/build/pkgs/pygments/install-requires.txt index 0d0dc97d523..337e5bbad8b 100644 --- a/build/pkgs/pygments/install-requires.txt +++ b/build/pkgs/pygments/install-requires.txt @@ -1 +1 @@ -pygments >=2.3.1 +pygments >=2.12 diff --git a/build/pkgs/pygments/spkg-configure.m4 b/build/pkgs/pygments/spkg-configure.m4 new file mode 100644 index 00000000000..99f29e3c9b3 --- /dev/null +++ b/build/pkgs/pygments/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pygments], [SAGE_PYTHON_PACKAGE_CHECK([pygments])]) diff --git a/build/pkgs/pygraphviz/dependencies b/build/pkgs/pygraphviz/dependencies index 232dc205925..a723707e09c 100644 --- a/build/pkgs/pygraphviz/dependencies +++ b/build/pkgs/pygraphviz/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) libgraphviz | $(PYTHON_TOOLCHAIN) + libgraphviz | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pynormaliz/checksums.ini b/build/pkgs/pynormaliz/checksums.ini index d9f614efaf9..327461a230f 100644 --- a/build/pkgs/pynormaliz/checksums.ini +++ b/build/pkgs/pynormaliz/checksums.ini @@ -1,5 +1,5 @@ tarball=PyNormaliz-VERSION.tar.gz -sha1=de8771b0339c4567665331df221c880bfe2b69a2 -md5=e8a571bdc3a8fcad16fdfabf9a6874d3 -cksum=2734845416 +sha1=08617ca50ce0e0317a3377381bf37c1a0ab826c1 +md5=9ae78f7638741c26b588443f0d6024ce +cksum=4090940781 upstream_url=https://pypi.io/packages/source/p/pynormaliz/PyNormaliz-VERSION.tar.gz diff --git a/build/pkgs/pynormaliz/dependencies b/build/pkgs/pynormaliz/dependencies index 76200c19d23..1fca858579e 100644 --- a/build/pkgs/pynormaliz/dependencies +++ b/build/pkgs/pynormaliz/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) normaliz | $(PYTHON_TOOLCHAIN) + normaliz | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pynormaliz/install-requires.txt b/build/pkgs/pynormaliz/install-requires.txt index b1e222ae76c..c4e93c56b2e 100644 --- a/build/pkgs/pynormaliz/install-requires.txt +++ b/build/pkgs/pynormaliz/install-requires.txt @@ -1 +1 @@ -pynormaliz ==2.12 +pynormaliz ==2.18 diff --git a/build/pkgs/pynormaliz/package-version.txt b/build/pkgs/pynormaliz/package-version.txt index 5c6fb54899b..fc249e9a747 100644 --- a/build/pkgs/pynormaliz/package-version.txt +++ b/build/pkgs/pynormaliz/package-version.txt @@ -1 +1 @@ -2.17 +2.18 diff --git a/build/pkgs/pyparsing/dependencies b/build/pkgs/pyparsing/dependencies index 2471ffdf59d..22915b3da68 100644 --- a/build/pkgs/pyparsing/dependencies +++ b/build/pkgs/pyparsing/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | pip wheel flit_core tomli + | pip wheel flit_core tomli $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pyparsing/distros/arch.txt b/build/pkgs/pyparsing/distros/arch.txt new file mode 100644 index 00000000000..428820c215f --- /dev/null +++ b/build/pkgs/pyparsing/distros/arch.txt @@ -0,0 +1 @@ +python-pyparsing diff --git a/build/pkgs/pyparsing/distros/freebsd.txt b/build/pkgs/pyparsing/distros/freebsd.txt new file mode 100644 index 00000000000..39fdc921fd0 --- /dev/null +++ b/build/pkgs/pyparsing/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-pyparsing diff --git a/build/pkgs/pyparsing/distros/gentoo.txt b/build/pkgs/pyparsing/distros/gentoo.txt new file mode 100644 index 00000000000..ef0419f9cbc --- /dev/null +++ b/build/pkgs/pyparsing/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pyparsing diff --git a/build/pkgs/pyparsing/distros/opensuse.txt b/build/pkgs/pyparsing/distros/opensuse.txt index 492a7ce0a69..2a91a003cf9 100644 --- a/build/pkgs/pyparsing/distros/opensuse.txt +++ b/build/pkgs/pyparsing/distros/opensuse.txt @@ -1 +1 @@ -python3-pyparsing +python3${PYTHON_MINOR}-pyparsing diff --git a/build/pkgs/pyparsing/spkg-configure.m4 b/build/pkgs/pyparsing/spkg-configure.m4 new file mode 100644 index 00000000000..d2b4c0055e4 --- /dev/null +++ b/build/pkgs/pyparsing/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pyparsing], [SAGE_PYTHON_PACKAGE_CHECK([pyparsing])]) diff --git a/build/pkgs/pyppeteer/dependencies b/build/pkgs/pyppeteer/dependencies index 1c2d4afb8d4..7d9ec36f9c7 100644 --- a/build/pkgs/pyppeteer/dependencies +++ b/build/pkgs/pyppeteer/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) appdirs importlib_metadata urllib3 certifi | $(PYTHON_TOOLCHAIN) + appdirs importlib_metadata urllib3 certifi | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pyproject_api/SPKG.rst b/build/pkgs/pyproject_api/SPKG.rst new file mode 100644 index 00000000000..521b15e35d6 --- /dev/null +++ b/build/pkgs/pyproject_api/SPKG.rst @@ -0,0 +1,16 @@ +pyproject_api: API to interact with the python pyproject.toml based projects +============================================================================ + +Description +----------- + +API to interact with the python pyproject.toml based projects + +License +------- + +Upstream Contact +---------------- + +https://pypi.org/project/pyproject-api/ + diff --git a/build/pkgs/pyproject_api/checksums.ini b/build/pkgs/pyproject_api/checksums.ini new file mode 100644 index 00000000000..9fc8e383a7c --- /dev/null +++ b/build/pkgs/pyproject_api/checksums.ini @@ -0,0 +1,5 @@ +tarball=pyproject_api-VERSION-py3-none-any.whl +sha1=5ea24c784a68fd0ef0228c332dc078ce64387eb8 +md5=8941280ffec3eb79a8cd6e380774980f +cksum=913049079 +upstream_url=https://pypi.io/packages/py3/p/pyproject_api/pyproject_api-VERSION-py3-none-any.whl diff --git a/build/pkgs/pyproject_api/dependencies b/build/pkgs/pyproject_api/dependencies new file mode 100644 index 00000000000..47296a7bace --- /dev/null +++ b/build/pkgs/pyproject_api/dependencies @@ -0,0 +1,4 @@ + | $(PYTHON_TOOLCHAIN) $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/pyproject_api/install-requires.txt b/build/pkgs/pyproject_api/install-requires.txt new file mode 100644 index 00000000000..3f2ab4cb2a0 --- /dev/null +++ b/build/pkgs/pyproject_api/install-requires.txt @@ -0,0 +1 @@ +pyproject-api diff --git a/build/pkgs/pyproject_api/package-version.txt b/build/pkgs/pyproject_api/package-version.txt new file mode 100644 index 00000000000..9c6d6293b1a --- /dev/null +++ b/build/pkgs/pyproject_api/package-version.txt @@ -0,0 +1 @@ +1.6.1 diff --git a/build/pkgs/poetry_core/type b/build/pkgs/pyproject_api/type similarity index 100% rename from build/pkgs/poetry_core/type rename to build/pkgs/pyproject_api/type diff --git a/build/pkgs/pyproject_metadata/checksums.ini b/build/pkgs/pyproject_metadata/checksums.ini index 4fcc0ec49c2..6fb14a63679 100644 --- a/build/pkgs/pyproject_metadata/checksums.ini +++ b/build/pkgs/pyproject_metadata/checksums.ini @@ -1,5 +1,5 @@ tarball=pyproject-metadata-VERSION.tar.gz -sha1=c2b7679b1e56a341aa00c186c0d1a6bbd7bd5c2c -md5=e13b11cb723da96f8397addddca963cc -cksum=2246727402 +sha1=41fba5c33917d77b9364fadb76e590e86789634d +md5=ca5e9527cff96153a976e14530b53746 +cksum=2053869519 upstream_url=https://pypi.io/packages/source/p/pyproject_metadata/pyproject-metadata-VERSION.tar.gz diff --git a/build/pkgs/pyproject_metadata/dependencies b/build/pkgs/pyproject_metadata/dependencies index 6d5368db738..3df264eee42 100644 --- a/build/pkgs/pyproject_metadata/dependencies +++ b/build/pkgs/pyproject_metadata/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) packaging pyparsing | $(PYTHON_TOOLCHAIN) + packaging pyparsing | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pyproject_metadata/distros/gentoo.txt b/build/pkgs/pyproject_metadata/distros/gentoo.txt new file mode 100644 index 00000000000..f4acf389e43 --- /dev/null +++ b/build/pkgs/pyproject_metadata/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pyproject-metadata diff --git a/build/pkgs/pyproject_metadata/package-version.txt b/build/pkgs/pyproject_metadata/package-version.txt index ee6cdce3c29..39e898a4f95 100644 --- a/build/pkgs/pyproject_metadata/package-version.txt +++ b/build/pkgs/pyproject_metadata/package-version.txt @@ -1 +1 @@ -0.6.1 +0.7.1 diff --git a/build/pkgs/pyproject_metadata/spkg-configure.m4 b/build/pkgs/pyproject_metadata/spkg-configure.m4 new file mode 100644 index 00000000000..1e61f2eada6 --- /dev/null +++ b/build/pkgs/pyproject_metadata/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([pyproject_metadata], [ + SAGE_PYTHON_PACKAGE_CHECK([pyproject_metadata]) +]) diff --git a/build/pkgs/pyrsistent/dependencies b/build/pkgs/pyrsistent/dependencies index 4361e46ddaf..9be6b4aab7c 100644 --- a/build/pkgs/pyrsistent/dependencies +++ b/build/pkgs/pyrsistent/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) vcversioner | $(PYTHON_TOOLCHAIN) + vcversioner | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pyrsistent/distros/gentoo.txt b/build/pkgs/pyrsistent/distros/gentoo.txt new file mode 100644 index 00000000000..83439cebfe4 --- /dev/null +++ b/build/pkgs/pyrsistent/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pyrsistent diff --git a/build/pkgs/pyrsistent/spkg-configure.m4 b/build/pkgs/pyrsistent/spkg-configure.m4 new file mode 100644 index 00000000000..f7ca75dbac5 --- /dev/null +++ b/build/pkgs/pyrsistent/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pyrsistent], [SAGE_PYTHON_PACKAGE_CHECK([pyrsistent])]) diff --git a/build/pkgs/pyscipopt/checksums.ini b/build/pkgs/pyscipopt/checksums.ini index 153466efcb5..a7c0dad6706 100644 --- a/build/pkgs/pyscipopt/checksums.ini +++ b/build/pkgs/pyscipopt/checksums.ini @@ -1,5 +1,5 @@ -tarball=PySCIPOpt-VERSION.tar.gz -sha1=0c3644ce6a0624774dceaef10694e090e3863ab5 -md5=2e4ce8087fb9acac8e806655f20c3d70 -cksum=3316817556 -upstream_url=https://pypi.io/packages/source/p/pyscipopt/PySCIPOpt-VERSION.tar.gz +tarball=PySCIPOpt_no_C-VERSION.tar.gz +sha1=cd8a7a5ee2f3d72eb0505b050ab8ffcf3acba409 +md5=b8a846432a7a1e6d5c6dcc547e7a6380 +cksum=710591360 +upstream_url=https://github.com/scipopt/PySCIPOpt/archive/refs/tags/vVERSION.tar.gz diff --git a/build/pkgs/pyscipopt/dependencies b/build/pkgs/pyscipopt/dependencies index dd41f46d3a1..3c4a108db0f 100644 --- a/build/pkgs/pyscipopt/dependencies +++ b/build/pkgs/pyscipopt/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) scip | $(PYTHON_TOOLCHAIN) + scip | $(PYTHON_TOOLCHAIN) cython $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pyscipopt/package-version.txt b/build/pkgs/pyscipopt/package-version.txt index 6aba2b245a8..80895903a15 100644 --- a/build/pkgs/pyscipopt/package-version.txt +++ b/build/pkgs/pyscipopt/package-version.txt @@ -1 +1 @@ -4.2.0 +4.3.0 diff --git a/build/pkgs/pysingular/dependencies b/build/pkgs/pysingular/dependencies index bd58b826630..075bad15831 100644 --- a/build/pkgs/pysingular/dependencies +++ b/build/pkgs/pysingular/dependencies @@ -1 +1 @@ -$(PYTHON) singular | $(PYTHON_TOOLCHAIN) + singular | $(PYTHON_TOOLCHAIN) $(PYTHON) diff --git a/build/pkgs/pytest/dependencies b/build/pkgs/pytest/dependencies index 7e5a90a20bd..af3334a7daf 100644 --- a/build/pkgs/pytest/dependencies +++ b/build/pkgs/pytest/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) pluggy packaging attrs py pyparsing importlib_metadata tomli | $(PYTHON_TOOLCHAIN) + pluggy packaging attrs py pyparsing importlib_metadata tomli | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pytest_mock/dependencies b/build/pkgs/pytest_mock/dependencies index 37ea60eb442..720c11ec214 100644 --- a/build/pkgs/pytest_mock/dependencies +++ b/build/pkgs/pytest_mock/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) pytest packaging attrs pluggy tomli py pyparsing | $(PYTHON_TOOLCHAIN) + pytest packaging attrs pluggy tomli py pyparsing | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pytest_xdist/dependencies b/build/pkgs/pytest_xdist/dependencies index aa8c608f663..19d8b032667 100644 --- a/build/pkgs/pytest_xdist/dependencies +++ b/build/pkgs/pytest_xdist/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) pytest | $(PYTHON_TOOLCHAIN) + pytest | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/python3/SPKG.rst b/build/pkgs/python3/SPKG.rst index 94a163de1f3..73c9f958f26 100644 --- a/build/pkgs/python3/SPKG.rst +++ b/build/pkgs/python3/SPKG.rst @@ -8,7 +8,7 @@ By default, Sage will try to use system's ``python3`` to set up a virtual environment, a.k.a. `venv <https://docs.python.org/3.10/library/venv.html>`_ rather than building a Python 3 installation from scratch. -Sage will accept versions 3.8.x to 3.10.x. +Sage will accept versions 3.9.x to 3.10.x. You can also use ``--with-python=/path/to/python3_binary`` to tell Sage to use ``/path/to/python3_binary`` to set up the venv. Note that setting up the venv requires diff --git a/build/pkgs/python3/distros/opensuse.txt b/build/pkgs/python3/distros/opensuse.txt index 07358a92e89..760ddd76f2c 100644 --- a/build/pkgs/python3/distros/opensuse.txt +++ b/build/pkgs/python3/distros/opensuse.txt @@ -1 +1 @@ -python3-devel +python3${PYTHON_MINOR}-devel diff --git a/build/pkgs/python3/spkg-configure.m4 b/build/pkgs/python3/spkg-configure.m4 index d8ece39683a..d57aa416e3a 100644 --- a/build/pkgs/python3/spkg-configure.m4 +++ b/build/pkgs/python3/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([python3], [ - m4_pushdef([MIN_VERSION], [3.8.0]) - m4_pushdef([MIN_NONDEPRECATED_VERSION], [3.8.0]) + m4_pushdef([MIN_VERSION], [3.9.0]) + m4_pushdef([MIN_NONDEPRECATED_VERSION], [3.9.0]) m4_pushdef([LT_STABLE_VERSION], [3.12.0]) m4_pushdef([LT_VERSION], [3.12.0]) AC_ARG_WITH([python], @@ -20,7 +20,7 @@ SAGE_SPKG_CONFIGURE([python3], [ dnl dnl However, if we add another package (providing a shared library linked into a Python module) dnl that also uses libsqlite3, then we will have to put the DEPCHECK back in. - SAGE_SPKG_DEPCHECK([bzip2 liblzma libffi], [ + SAGE_SPKG_DEPCHECK([bzip2 liblzma libffi zlib], [ dnl Check if we can do venv with a system python3 dnl instead of building our own copy. dnl Trac #31160: We no longer check for readline here. @@ -130,17 +130,17 @@ To build Sage with a different system python, use ./configure --with-python=/pat ]) AC_SUBST([PYTHON_FOR_VENV]) + AS_IF([test -n "$PYTHON_FOR_VENV"], + [PYTHON_VERSION=$("$PYTHON_FOR_VENV" -c "import sysconfig; print(sysconfig.get_python_version())")], + [PYTHON_VERSION=$(echo $(cat build/pkgs/python3/package-version.txt))]) + AC_SUBST([PYTHON_MINOR], [$(echo $PYTHON_VERSION | cut -d. -f2)]) + export PYTHON_MINOR # for sage-get-system-packages + AS_VAR_IF([SAGE_VENV], [auto], [SAGE_VENV=$SAGE_VENV_AUTO]) AS_CASE([$SAGE_VENV], [no], [SAGE_VENV='${SAGE_LOCAL}'],dnl Quoted so that it is resolved at build time by shell/Makefile - [yes], [AS_IF([test -n "$PYTHON_FOR_VENV"], [ - PYTHON_VERSION=$("$PYTHON_FOR_VENV" -c "import sysconfig; print(sysconfig.get_python_version())") - ], [ - PYTHON_VERSION=$(echo $(cat build/pkgs/python3/package-version.txt)) - ]) - SAGE_VENV='${SAGE_LOCAL}'/var/lib/sage/venv-python$PYTHON_VERSION] + [yes], [SAGE_VENV='${SAGE_LOCAL}'/var/lib/sage/venv-python$PYTHON_VERSION] ) - dnl These temporary directories are created by the check above dnl and need to be cleaned up to prevent the "rm -f conftest*" dnl (that a bunch of other checks do) from emitting warnings about diff --git a/build/pkgs/python_build/dependencies b/build/pkgs/python_build/dependencies index 769e08a8c26..b72a6d1c776 100644 --- a/build/pkgs/python_build/dependencies +++ b/build/pkgs/python_build/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) pyparsing tomli packaging | $(PYTHON_TOOLCHAIN) + pyparsing tomli packaging | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/python_igraph/checksums.ini b/build/pkgs/python_igraph/checksums.ini index 5f8bc59a4de..7247680193c 100644 --- a/build/pkgs/python_igraph/checksums.ini +++ b/build/pkgs/python_igraph/checksums.ini @@ -1,5 +1,5 @@ tarball=python-igraph-VERSION.tar.gz -sha1=6a6bca77737ff501e97f808aa18a9045e86b3e3e -md5=6951cc2e803118b74209ae21d54de38a -cksum=650236223 +sha1=807a95ad4080d8eb500e7797325d6f11a5c46892 +md5=2ac3561dda7e7321789041261a29aba4 +cksum=754615899 upstream_url=https://pypi.io/packages/source/i/igraph/igraph-VERSION.tar.gz diff --git a/build/pkgs/python_igraph/dependencies b/build/pkgs/python_igraph/dependencies index 67ed15160f4..dde58706323 100644 --- a/build/pkgs/python_igraph/dependencies +++ b/build/pkgs/python_igraph/dependencies @@ -1,4 +1,4 @@ -igraph texttable $(PYTHON) | $(PYTHON_TOOLCHAIN) +igraph texttable | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/python_igraph/distros/arch.txt b/build/pkgs/python_igraph/distros/arch.txt new file mode 100644 index 00000000000..03f8142066f --- /dev/null +++ b/build/pkgs/python_igraph/distros/arch.txt @@ -0,0 +1 @@ +python-igraph diff --git a/build/pkgs/python_igraph/distros/debian.txt b/build/pkgs/python_igraph/distros/debian.txt new file mode 100644 index 00000000000..218ba998007 --- /dev/null +++ b/build/pkgs/python_igraph/distros/debian.txt @@ -0,0 +1 @@ +python3-igraph diff --git a/build/pkgs/python_igraph/distros/fedora.txt b/build/pkgs/python_igraph/distros/fedora.txt new file mode 100644 index 00000000000..03f8142066f --- /dev/null +++ b/build/pkgs/python_igraph/distros/fedora.txt @@ -0,0 +1 @@ +python-igraph diff --git a/build/pkgs/python_igraph/distros/freebsd.txt b/build/pkgs/python_igraph/distros/freebsd.txt new file mode 100644 index 00000000000..d86a516f3ed --- /dev/null +++ b/build/pkgs/python_igraph/distros/freebsd.txt @@ -0,0 +1 @@ +math/py-igraph diff --git a/build/pkgs/python_igraph/package-version.txt b/build/pkgs/python_igraph/package-version.txt index 5eef0f10e8c..9b40aa6c214 100644 --- a/build/pkgs/python_igraph/package-version.txt +++ b/build/pkgs/python_igraph/package-version.txt @@ -1 +1 @@ -0.10.2 +0.10.4 diff --git a/build/pkgs/pythran/checksums.ini b/build/pkgs/pythran/checksums.ini index 0789ef48f67..2a926b36347 100644 --- a/build/pkgs/pythran/checksums.ini +++ b/build/pkgs/pythran/checksums.ini @@ -1,5 +1,5 @@ tarball=pythran-VERSION.tar.gz -sha1=ed5630b0879be9c59885d83c5a24fcd5dfbca5af -md5=d2961ece35b4b9f44a84ef31df1b21ff -cksum=399652957 +sha1=8f997393d123a6185dbf2be0ead588df004c6c4c +md5=2885a2974b9b523439761bfd8bc54f03 +cksum=1307669216 upstream_url=https://pypi.io/packages/source/p/pythran/pythran-VERSION.tar.gz diff --git a/build/pkgs/pythran/dependencies b/build/pkgs/pythran/dependencies index 8a64589c0bc..89cdb86e634 100644 --- a/build/pkgs/pythran/dependencies +++ b/build/pkgs/pythran/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) beniget gast ply numpy | $(PYTHON_TOOLCHAIN) +beniget gast ply | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pythran/distros/gentoo.txt b/build/pkgs/pythran/distros/gentoo.txt new file mode 100644 index 00000000000..1bb7cdcd4eb --- /dev/null +++ b/build/pkgs/pythran/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pythran diff --git a/build/pkgs/pythran/install-requires.txt b/build/pkgs/pythran/install-requires.txt index 86d056b339f..f365e5f4971 100644 --- a/build/pkgs/pythran/install-requires.txt +++ b/build/pkgs/pythran/install-requires.txt @@ -1 +1 @@ -pythran +pythran >=0.12.1 diff --git a/build/pkgs/pythran/package-version.txt b/build/pkgs/pythran/package-version.txt index ac454c6a1fc..a803cc227fe 100644 --- a/build/pkgs/pythran/package-version.txt +++ b/build/pkgs/pythran/package-version.txt @@ -1 +1 @@ -0.12.0 +0.14.0 diff --git a/build/pkgs/pythran/spkg-configure.m4 b/build/pkgs/pythran/spkg-configure.m4 new file mode 100644 index 00000000000..592e95bcb3d --- /dev/null +++ b/build/pkgs/pythran/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pythran], [SAGE_PYTHON_PACKAGE_CHECK([pythran])]) diff --git a/build/pkgs/pytz/dependencies b/build/pkgs/pytz/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/pytz/dependencies +++ b/build/pkgs/pytz/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pytz/distros/arch.txt b/build/pkgs/pytz/distros/arch.txt new file mode 100644 index 00000000000..2cccc9e61ec --- /dev/null +++ b/build/pkgs/pytz/distros/arch.txt @@ -0,0 +1 @@ +python-pytz diff --git a/build/pkgs/pytz/distros/debian.txt b/build/pkgs/pytz/distros/debian.txt new file mode 100644 index 00000000000..db209080161 --- /dev/null +++ b/build/pkgs/pytz/distros/debian.txt @@ -0,0 +1 @@ +python3-tz diff --git a/build/pkgs/pytz/distros/fedora.txt b/build/pkgs/pytz/distros/fedora.txt new file mode 100644 index 00000000000..2cccc9e61ec --- /dev/null +++ b/build/pkgs/pytz/distros/fedora.txt @@ -0,0 +1 @@ +python-pytz diff --git a/build/pkgs/pytz/distros/gentoo.txt b/build/pkgs/pytz/distros/gentoo.txt new file mode 100644 index 00000000000..902a18bf73e --- /dev/null +++ b/build/pkgs/pytz/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pytz diff --git a/build/pkgs/pytz/distros/opensuse.txt b/build/pkgs/pytz/distros/opensuse.txt index 1b20e1dbb77..232b99a6d04 100644 --- a/build/pkgs/pytz/distros/opensuse.txt +++ b/build/pkgs/pytz/distros/opensuse.txt @@ -1 +1 @@ -python3-pytz +python3${PYTHON_MINOR}-pytz diff --git a/build/pkgs/pytz/spkg-configure.m4 b/build/pkgs/pytz/spkg-configure.m4 new file mode 100644 index 00000000000..366521be957 --- /dev/null +++ b/build/pkgs/pytz/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pytz], [SAGE_PYTHON_PACKAGE_CHECK([pytz])]) diff --git a/build/pkgs/pytz_deprecation_shim/dependencies b/build/pkgs/pytz_deprecation_shim/dependencies index 232fe6c0554..2ea28ad2718 100644 --- a/build/pkgs/pytz_deprecation_shim/dependencies +++ b/build/pkgs/pytz_deprecation_shim/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) tzdata | $(PYTHON_TOOLCHAIN) + tzdata | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pyx/distros/opensuse.txt b/build/pkgs/pyx/distros/opensuse.txt index 03265558e86..f7dd2365b82 100644 --- a/build/pkgs/pyx/distros/opensuse.txt +++ b/build/pkgs/pyx/distros/opensuse.txt @@ -1 +1 @@ -python3-PyX +python3${PYTHON_MINOR}-PyX diff --git a/build/pkgs/pyzmq/dependencies b/build/pkgs/pyzmq/dependencies index c72b3d23340..5031d872d13 100644 --- a/build/pkgs/pyzmq/dependencies +++ b/build/pkgs/pyzmq/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cython zeromq | $(PYTHON_TOOLCHAIN) + cython zeromq | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pyzmq/distros/arch.txt b/build/pkgs/pyzmq/distros/arch.txt new file mode 100644 index 00000000000..23f64d1f1a3 --- /dev/null +++ b/build/pkgs/pyzmq/distros/arch.txt @@ -0,0 +1 @@ +python-pyzmq diff --git a/build/pkgs/pyzmq/distros/fedora.txt b/build/pkgs/pyzmq/distros/fedora.txt new file mode 100644 index 00000000000..23f64d1f1a3 --- /dev/null +++ b/build/pkgs/pyzmq/distros/fedora.txt @@ -0,0 +1 @@ +python-pyzmq diff --git a/build/pkgs/pyzmq/distros/gentoo.txt b/build/pkgs/pyzmq/distros/gentoo.txt new file mode 100644 index 00000000000..77c24295bd0 --- /dev/null +++ b/build/pkgs/pyzmq/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pyzmq diff --git a/build/pkgs/pyzmq/distros/opensuse.txt b/build/pkgs/pyzmq/distros/opensuse.txt index 265a272130e..fe243347c49 100644 --- a/build/pkgs/pyzmq/distros/opensuse.txt +++ b/build/pkgs/pyzmq/distros/opensuse.txt @@ -1 +1 @@ -python3-pyzmq +python3${PYTHON_MINOR}-pyzmq diff --git a/build/pkgs/pyzmq/spkg-configure.m4 b/build/pkgs/pyzmq/spkg-configure.m4 new file mode 100644 index 00000000000..ae2b126efb1 --- /dev/null +++ b/build/pkgs/pyzmq/spkg-configure.m4 @@ -0,0 +1,5 @@ +SAGE_SPKG_CONFIGURE([pyzmq], [ + SAGE_SPKG_DEPCHECK([zeromq], [ + SAGE_PYTHON_PACKAGE_CHECK([pyzmq]) + ]) +]) diff --git a/build/pkgs/qdldl_python/SPKG.rst b/build/pkgs/qdldl_python/SPKG.rst new file mode 100644 index 00000000000..f2ddd73224a --- /dev/null +++ b/build/pkgs/qdldl_python/SPKG.rst @@ -0,0 +1,18 @@ +qdldl_python: QDLDL, a free LDL factorization routine (Python wrapper) +====================================================================== + +Description +----------- + +QDLDL, a free LDL factorization routine. + +License +------- + +Apache 2.0 + +Upstream Contact +---------------- + +https://pypi.org/project/qdldl/ + diff --git a/build/pkgs/qdldl_python/checksums.ini b/build/pkgs/qdldl_python/checksums.ini new file mode 100644 index 00000000000..defd264f787 --- /dev/null +++ b/build/pkgs/qdldl_python/checksums.ini @@ -0,0 +1,5 @@ +tarball=qdldl-VERSION.tar.gz +sha1=af76c57ca1787f5e44e42f6c9f916b84ae599f1f +md5=63d719bd8073c1661a1baa6b510b8aad +cksum=105675620 +upstream_url=https://pypi.io/packages/source/q/qdldl/qdldl-VERSION.tar.gz diff --git a/build/pkgs/qdldl_python/dependencies b/build/pkgs/qdldl_python/dependencies new file mode 100644 index 00000000000..757104fcba0 --- /dev/null +++ b/build/pkgs/qdldl_python/dependencies @@ -0,0 +1,4 @@ + pybind11 numpy scipy | $(PYTHON_TOOLCHAIN) cmake $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/qdldl_python/distros/conda.txt b/build/pkgs/qdldl_python/distros/conda.txt new file mode 100644 index 00000000000..a540df83800 --- /dev/null +++ b/build/pkgs/qdldl_python/distros/conda.txt @@ -0,0 +1 @@ +qdldl-python diff --git a/build/pkgs/qdldl_python/install-requires.txt b/build/pkgs/qdldl_python/install-requires.txt new file mode 100644 index 00000000000..19334259738 --- /dev/null +++ b/build/pkgs/qdldl_python/install-requires.txt @@ -0,0 +1 @@ +qdldl diff --git a/build/pkgs/qdldl_python/package-version.txt b/build/pkgs/qdldl_python/package-version.txt new file mode 100644 index 00000000000..a2b2442e697 --- /dev/null +++ b/build/pkgs/qdldl_python/package-version.txt @@ -0,0 +1 @@ +0.1.5.post3 diff --git a/build/pkgs/filelock/spkg-install.in b/build/pkgs/qdldl_python/spkg-install.in similarity index 100% rename from build/pkgs/filelock/spkg-install.in rename to build/pkgs/qdldl_python/spkg-install.in diff --git a/build/pkgs/qdldl_python/type b/build/pkgs/qdldl_python/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/qdldl_python/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/r/SPKG.rst b/build/pkgs/r/SPKG.rst index 2bfe4e8375e..584294e891a 100644 --- a/build/pkgs/r/SPKG.rst +++ b/build/pkgs/r/SPKG.rst @@ -24,15 +24,3 @@ Upstream Contact - https://www.r-project.org - R mailing list, #R in IRC - -Dependencies ------------- - -- GNU patch -- iconv -- Readline -- BLAS/LAPACK -- xz -- pcre -- curl -- https-capable SSL diff --git a/build/pkgs/r/dependencies b/build/pkgs/r/dependencies deleted file mode 100644 index c34daf966bd..00000000000 --- a/build/pkgs/r/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -$(BLAS) gfortran iconv readline bzip2 liblzma pcre curl | pkgconf - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/requests/dependencies b/build/pkgs/requests/dependencies index b896dbc3cac..668fe014f12 100644 --- a/build/pkgs/requests/dependencies +++ b/build/pkgs/requests/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) idna urllib3 certifi charset_normalizer + | $(PYTHON_TOOLCHAIN) idna urllib3 certifi charset_normalizer $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/requests/distros/arch.txt b/build/pkgs/requests/distros/arch.txt new file mode 100644 index 00000000000..93a7bc19b60 --- /dev/null +++ b/build/pkgs/requests/distros/arch.txt @@ -0,0 +1 @@ +python-requests diff --git a/build/pkgs/requests/distros/debian.txt b/build/pkgs/requests/distros/debian.txt new file mode 100644 index 00000000000..43147b2be74 --- /dev/null +++ b/build/pkgs/requests/distros/debian.txt @@ -0,0 +1 @@ +python3-requests diff --git a/build/pkgs/requests/distros/fedora.txt b/build/pkgs/requests/distros/fedora.txt new file mode 100644 index 00000000000..93a7bc19b60 --- /dev/null +++ b/build/pkgs/requests/distros/fedora.txt @@ -0,0 +1 @@ +python-requests diff --git a/build/pkgs/requests/distros/gentoo.txt b/build/pkgs/requests/distros/gentoo.txt new file mode 100644 index 00000000000..d3dc9415e3d --- /dev/null +++ b/build/pkgs/requests/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/requests diff --git a/build/pkgs/requests/distros/opensuse.txt b/build/pkgs/requests/distros/opensuse.txt index 43147b2be74..c1581ad8a95 100644 --- a/build/pkgs/requests/distros/opensuse.txt +++ b/build/pkgs/requests/distros/opensuse.txt @@ -1 +1 @@ -python3-requests +python3${PYTHON_MINOR}-requests diff --git a/build/pkgs/requests/spkg-configure.m4 b/build/pkgs/requests/spkg-configure.m4 new file mode 100644 index 00000000000..f50a66cdee3 --- /dev/null +++ b/build/pkgs/requests/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([requests], [SAGE_PYTHON_PACKAGE_CHECK([requests])]) diff --git a/build/pkgs/retrolab/dependencies b/build/pkgs/retrolab/dependencies index 531f28310be..58027d3558c 100644 --- a/build/pkgs/retrolab/dependencies +++ b/build/pkgs/retrolab/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) jupyterlab | $(PYTHON_TOOLCHAIN) + jupyterlab | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/rpy2/dependencies b/build/pkgs/rpy2/dependencies index b8937d88769..b88615716d4 100644 --- a/build/pkgs/rpy2/dependencies +++ b/build/pkgs/rpy2/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) r cffi tzlocal pytz jinja2 | $(PYTHON_TOOLCHAIN) pycparser + r cffi tzlocal pytz jinja2 | $(PYTHON_TOOLCHAIN) pycparser $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/rpy2/distros/arch.txt b/build/pkgs/rpy2/distros/arch.txt new file mode 100644 index 00000000000..9748535a285 --- /dev/null +++ b/build/pkgs/rpy2/distros/arch.txt @@ -0,0 +1 @@ +python-rpy2 diff --git a/build/pkgs/rpy2/distros/debian.txt b/build/pkgs/rpy2/distros/debian.txt new file mode 100644 index 00000000000..8f389862688 --- /dev/null +++ b/build/pkgs/rpy2/distros/debian.txt @@ -0,0 +1 @@ +rpy2 diff --git a/build/pkgs/rpy2/distros/freebsd.txt b/build/pkgs/rpy2/distros/freebsd.txt new file mode 100644 index 00000000000..21caa8b9edd --- /dev/null +++ b/build/pkgs/rpy2/distros/freebsd.txt @@ -0,0 +1 @@ +math/py-rpy2 diff --git a/build/pkgs/rpy2/distros/macports.txt b/build/pkgs/rpy2/distros/macports.txt new file mode 100644 index 00000000000..71f03850a9b --- /dev/null +++ b/build/pkgs/rpy2/distros/macports.txt @@ -0,0 +1 @@ +py-rpy2 diff --git a/build/pkgs/rpy2/distros/opensuse.txt b/build/pkgs/rpy2/distros/opensuse.txt new file mode 100644 index 00000000000..5b9c1542845 --- /dev/null +++ b/build/pkgs/rpy2/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-rpy2 diff --git a/build/pkgs/rpy2/spkg-configure.m4 b/build/pkgs/rpy2/spkg-configure.m4 index c9831c6b60a..0cb3784ea9c 100644 --- a/build/pkgs/rpy2/spkg-configure.m4 +++ b/build/pkgs/rpy2/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([rpy2], [ - sage_spkg_install_rpy2=yes - ], [dnl REQUIRED-CHECK + SAGE_PYTHON_PACKAGE_CHECK([rpy2]) +], [dnl REQUIRED-CHECK AC_REQUIRE([SAGE_SPKG_CONFIGURE_R]) dnl rpy2 is only needed when there is a usable system R AS_VAR_IF([sage_spkg_install_r], [yes], [dnl diff --git a/build/pkgs/rst2ipynb/dependencies b/build/pkgs/rst2ipynb/dependencies index 7fcda2181e1..d828daf957d 100644 --- a/build/pkgs/rst2ipynb/dependencies +++ b/build/pkgs/rst2ipynb/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) pandoc | $(PYTHON_TOOLCHAIN) notedown + pandoc | $(PYTHON_TOOLCHAIN) notedown $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sage_conf/dependencies b/build/pkgs/sage_conf/dependencies index 0479fd1d280..f2bd00aaf0d 100644 --- a/build/pkgs/sage_conf/dependencies +++ b/build/pkgs/sage_conf/dependencies @@ -1 +1 @@ -$(PYTHON) $(SAGE_ROOT)/pkgs/sage-conf/_sage_conf/_conf.py $(SAGE_ROOT)/pkgs/sage-conf/setup.cfg $(SAGE_ROOT)/pkgs/sage-conf/bin/sage-env-config | $(PYTHON_TOOLCHAIN) + $(SAGE_ROOT)/pkgs/sage-conf/_sage_conf/_conf.py $(SAGE_ROOT)/pkgs/sage-conf/setup.cfg $(SAGE_ROOT)/pkgs/sage-conf/bin/sage-env-config | $(PYTHON_TOOLCHAIN) $(PYTHON) diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt index 87a8f39f3f0..f38cdee4efc 100644 --- a/build/pkgs/sage_conf/install-requires.txt +++ b/build/pkgs/sage_conf/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 10.0b1 +sage-conf ~= 10.2b5 diff --git a/build/pkgs/sage_conf/spkg-src b/build/pkgs/sage_conf/spkg-src index af6e8b16342..c2fa51df092 100755 --- a/build/pkgs/sage_conf/spkg-src +++ b/build/pkgs/sage_conf/spkg-src @@ -16,4 +16,7 @@ fi set -e cd pkgs/sage-conf_pypi -python3 -u setup.py --no-user-cfg sdist --dist-dir "$SAGE_DISTFILES" +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sage_docbuild/dependencies b/build/pkgs/sage_docbuild/dependencies index 376ad09772a..c21e4b287e3 100644 --- a/build/pkgs/sage_docbuild/dependencies +++ b/build/pkgs/sage_docbuild/dependencies @@ -1 +1 @@ -$(PYTHON) sphinx $(SAGE_ROOT)/pkgs/sage-docbuild/sage_docbuild/*.py $(SAGE_ROOT)/pkgs/sage-docbuild/sage_docbuild/ext/*.py | $(PYTHON_TOOLCHAIN) sagelib + sphinx $(SAGE_ROOT)/pkgs/sage-docbuild/sage_docbuild/*.py $(SAGE_ROOT)/pkgs/sage-docbuild/sage_docbuild/ext/*.py | $(PYTHON_TOOLCHAIN) sagelib $(PYTHON) diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt index dc1652133a1..62965fd0775 100644 --- a/build/pkgs/sage_docbuild/install-requires.txt +++ b/build/pkgs/sage_docbuild/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 10.0b1 +sage-docbuild ~= 10.2b5 diff --git a/build/pkgs/sage_docbuild/spkg-src b/build/pkgs/sage_docbuild/spkg-src index dc1ba829b3a..b21f8f015c8 100755 --- a/build/pkgs/sage_docbuild/spkg-src +++ b/build/pkgs/sage_docbuild/spkg-src @@ -18,4 +18,7 @@ set -e cd build/pkgs/sage_docbuild cd src -python3 -u setup.py --no-user-cfg sdist --dist-dir "$SAGE_DISTFILES" +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sage_flatsurf/dependencies b/build/pkgs/sage_flatsurf/dependencies index 4c62fdd4fef..c706908baa7 100644 --- a/build/pkgs/sage_flatsurf/dependencies +++ b/build/pkgs/sage_flatsurf/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) surface_dynamics $(SAGERUNTIME) + | $(PYTHON_TOOLCHAIN) surface_dynamics $(SAGERUNTIME) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sage_numerical_backends_coin/dependencies b/build/pkgs/sage_numerical_backends_coin/dependencies index 4cbde1164f2..0448728cea5 100644 --- a/build/pkgs/sage_numerical_backends_coin/dependencies +++ b/build/pkgs/sage_numerical_backends_coin/dependencies @@ -1,4 +1,4 @@ -cbc cysignals $(SAGE_SRC)/sage/numerical/backends/generic_backend.pxd $(SAGE_SRC)/sage/cpython/string.pxd $(SAGE_SRC)/sage/cpython/string_impl.h | $(SAGERUNTIME) $(PYTHON_TOOLCHAIN) cython ipywidgets +cbc cysignals $(SAGE_SRC)/sage/numerical/backends/generic_backend.pxd $(SAGE_SRC)/sage/cpython/string.pxd $(SAGE_SRC)/sage/cpython/string_impl.h | $(SAGERUNTIME) $(PYTHON_TOOLCHAIN) cython ipywidgets $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sage_numerical_backends_cplex/dependencies b/build/pkgs/sage_numerical_backends_cplex/dependencies index 0b35afa3540..840bdcabd34 100644 --- a/build/pkgs/sage_numerical_backends_cplex/dependencies +++ b/build/pkgs/sage_numerical_backends_cplex/dependencies @@ -1,4 +1,4 @@ -cysignals $(SAGE_SRC)/sage/numerical/backends/generic_backend.pxd $(SAGE_SRC)/sage/cpython/string.pxd $(SAGE_SRC)/sage/cpython/string_impl.h | $(SAGERUNTIME) $(PYTHON_TOOLCHAIN) cython ipywidgets +cysignals $(SAGE_SRC)/sage/numerical/backends/generic_backend.pxd $(SAGE_SRC)/sage/cpython/string.pxd $(SAGE_SRC)/sage/cpython/string_impl.h | $(SAGERUNTIME) $(PYTHON_TOOLCHAIN) cython ipywidgets $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sage_numerical_backends_gurobi/dependencies b/build/pkgs/sage_numerical_backends_gurobi/dependencies index 0b35afa3540..840bdcabd34 100644 --- a/build/pkgs/sage_numerical_backends_gurobi/dependencies +++ b/build/pkgs/sage_numerical_backends_gurobi/dependencies @@ -1,4 +1,4 @@ -cysignals $(SAGE_SRC)/sage/numerical/backends/generic_backend.pxd $(SAGE_SRC)/sage/cpython/string.pxd $(SAGE_SRC)/sage/cpython/string_impl.h | $(SAGERUNTIME) $(PYTHON_TOOLCHAIN) cython ipywidgets +cysignals $(SAGE_SRC)/sage/numerical/backends/generic_backend.pxd $(SAGE_SRC)/sage/cpython/string.pxd $(SAGE_SRC)/sage/cpython/string_impl.h | $(SAGERUNTIME) $(PYTHON_TOOLCHAIN) cython ipywidgets $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sage_setup/dependencies b/build/pkgs/sage_setup/dependencies index 8c2e218f49a..cae3faf9049 100644 --- a/build/pkgs/sage_setup/dependencies +++ b/build/pkgs/sage_setup/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cython pkgconfig jinja2 $(SAGE_ROOT)/pkgs/sage-setup/sage_setup/*.py $(SAGE_ROOT)/pkgs/sage-setup/sage_setup/autogen/interpreters/specs/*.py $(SAGE_ROOT)/pkgs/sage-setup/sage_setup/command/*.py | $(PYTHON_TOOLCHAIN) + cython pkgconfig jinja2 $(SAGE_ROOT)/pkgs/sage-setup/sage_setup/*.py $(SAGE_ROOT)/pkgs/sage-setup/sage_setup/autogen/interpreters/specs/*.py $(SAGE_ROOT)/pkgs/sage-setup/sage_setup/command/*.py | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index f418d8648ec..42ef7aa07f9 100644 --- a/build/pkgs/sage_setup/install-requires.txt +++ b/build/pkgs/sage_setup/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 10.0b1 +sage-setup ~= 10.2b5 diff --git a/build/pkgs/sage_setup/spkg-src b/build/pkgs/sage_setup/spkg-src index e1bcbdaabdb..1b137206a5c 100755 --- a/build/pkgs/sage_setup/spkg-src +++ b/build/pkgs/sage_setup/spkg-src @@ -18,4 +18,7 @@ set -e cd build/pkgs/sage_setup cd src -python3 -u setup.py --no-user-cfg sdist --dist-dir "$SAGE_DISTFILES" +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sage_sws2rst/dependencies b/build/pkgs/sage_sws2rst/dependencies index 5ca5e27df75..f32c4fc594d 100644 --- a/build/pkgs/sage_sws2rst/dependencies +++ b/build/pkgs/sage_sws2rst/dependencies @@ -1 +1 @@ -$(PYTHON) beautifulsoup4 $(SAGE_ROOT)/pkgs/sage-sws2rst/*.py | $(PYTHON_TOOLCHAIN) + beautifulsoup4 $(SAGE_ROOT)/pkgs/sage-sws2rst/*.py | $(PYTHON_TOOLCHAIN) $(PYTHON) diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt index d62c0ef4662..8c3cca6a40a 100644 --- a/build/pkgs/sage_sws2rst/install-requires.txt +++ b/build/pkgs/sage_sws2rst/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 10.0b1 +sage-sws2rst ~= 10.2b5 diff --git a/build/pkgs/sage_sws2rst/spkg-install b/build/pkgs/sage_sws2rst/spkg-install index 47ef9ee6cbf..9cb71471fd8 100755 --- a/build/pkgs/sage_sws2rst/spkg-install +++ b/build/pkgs/sage_sws2rst/spkg-install @@ -18,6 +18,7 @@ if [ "$SAGE_EDITABLE" = yes ]; then else sdh_pip_install . fi +cd .. # For type=script packages, spkg-check is not run case "$SAGE_CHECK" in yes) diff --git a/build/pkgs/sage_sws2rst/spkg-src b/build/pkgs/sage_sws2rst/spkg-src index 0da7d0cd24c..5a2a6d464dd 100755 --- a/build/pkgs/sage_sws2rst/spkg-src +++ b/build/pkgs/sage_sws2rst/spkg-src @@ -18,4 +18,7 @@ set -e cd build/pkgs/sage_sws2rst cd src -python3 -u setup.py --no-user-cfg sdist --dist-dir "$SAGE_DISTFILES" +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagelib/bootstrap b/build/pkgs/sagelib/bootstrap index 08f9002f8f5..2c9b3f78974 100755 --- a/build/pkgs/sagelib/bootstrap +++ b/build/pkgs/sagelib/bootstrap @@ -1,5 +1,7 @@ #! /bin/sh set -e +export M4PATH="$SAGE_ROOT/m4" +MACRO_PATTERN='SPKG_' for infile in src/*.m4; do if [ -f "$infile" ]; then outfile="src/$(basename $infile .m4)" @@ -7,5 +9,10 @@ for infile in src/*.m4; do echo "$0: installing $(pwd)/$outfile" fi m4 "$infile" > "$outfile" + if sed 's/#.*//' "$outfile" | grep -q -E "$MACRO_PATTERN"; then + echo >&2 "$(pwd)/$infile: error: Unrecognized SPKG_ macro:" + grep -E "$MACRO_PATTERN" "$outfile" >&2 + exit 1 + fi fi done diff --git a/build/pkgs/sagelib/dependencies b/build/pkgs/sagelib/dependencies index abf21122c87..5dc2efe1d31 100644 --- a/build/pkgs/sagelib/dependencies +++ b/build/pkgs/sagelib/dependencies @@ -1,4 +1,4 @@ -FORCE $(SCRIPTS) arb boost_cropped $(BLAS) brial cliquer cypari cysignals cython ecl eclib ecm flint libgd gap giac givaro glpk gmpy2 gsl iml jinja2 jupyter_core lcalc lrcalc_python libbraiding libhomfly libpng linbox m4ri m4rie memory_allocator mpc mpfi mpfr $(MP_LIBRARY) ntl numpy pari pip pkgconfig planarity ppl pplpy primesieve primecount primecountpy pycygwin $(PYTHON) requests rw sage_conf singular symmetrica $(PCFILES) | $(PYTHON_TOOLCHAIN) sage_setup +FORCE $(SCRIPTS) arb boost_cropped $(BLAS) brial cliquer cypari cysignals cython ecl eclib ecm flint libgd gap giac givaro glpk gmpy2 gsl iml importlib_metadata importlib_resources jupyter_core lcalc lrcalc_python libbraiding libhomfly libpng linbox m4ri m4rie memory_allocator mpc mpfi mpfr $(MP_LIBRARY) ntl numpy pari pip pkgconfig planarity ppl pplpy primesieve primecount primecountpy pycygwin $(PYTHON) requests rw sage_conf singular symmetrica typing_extensions $(PCFILES) | $(PYTHON_TOOLCHAIN) sage_setup $(PYTHON) pythran ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt index c231384faae..981188d32ca 100644 --- a/build/pkgs/sagelib/install-requires.txt +++ b/build/pkgs/sagelib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagelib ~= 10.0b1 +sagemath-standard ~= 10.2b5 diff --git a/build/pkgs/sagelib/spkg-install b/build/pkgs/sagelib/spkg-install index ed6bb969f31..730829b3101 100755 --- a/build/pkgs/sagelib/spkg-install +++ b/build/pkgs/sagelib/spkg-install @@ -55,6 +55,8 @@ unset SAGE_PKG_CONFIG_PATH SITEPACKAGESDIR=$(python3 -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])') +export SAGE_OPTIONAL_PACKAGES_WITH_EXTENSIONS="" + if [ "$SAGE_EDITABLE" = yes ]; then # In an incremental build, we may need to uninstall old versions installed by distutils # under the old distribution name "sage" (before #30912, which switched to setuptools @@ -79,6 +81,7 @@ else # Compiling sage/interfaces/sagespawn.pyx because it depends on /private/var/folders/38/wnh4gf1552g_crsjnv2vmmww0000gp/T/pip-build-env-609n5985/overlay/lib/python3.10/site-packages/Cython/Includes/posix/unistd.pxd time sdh_pip_install --no-build-isolation . else + SAGE_OPTIONAL_PACKAGES_WITH_EXTENSIONS+="mcqd,tdlib,coxeter3,sirocco,meataxe,bliss" time python3 -u setup.py --no-user-cfg build install || exit 1 fi fi diff --git a/build/pkgs/sagelib/spkg-src b/build/pkgs/sagelib/spkg-src index db4e2682ba1..aa97a393b0b 100755 --- a/build/pkgs/sagelib/spkg-src +++ b/build/pkgs/sagelib/spkg-src @@ -4,7 +4,7 @@ # This script is not used during build. # # HOW TO MAKE THE TARBALL: -# ./sage --sh build/pkgs/sagelib/spkg-src +# make python_build && ./sage --sh build/pkgs/sagelib/spkg-src if [ -z "$SAGE_ROOT" ] ; then echo >&2 "Error - SAGE_ROOT undefined ... exiting" @@ -18,4 +18,8 @@ set -e cd "$SAGE_ROOT"/build/pkgs/sagelib cd src -python3 -u setup.py --no-user-cfg sdist --dist-dir "$SAGE_DISTFILES" + +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_bliss/SPKG.rst b/build/pkgs/sagemath_bliss/SPKG.rst new file mode 120000 index 00000000000..b4545b4bda6 --- /dev/null +++ b/build/pkgs/sagemath_bliss/SPKG.rst @@ -0,0 +1 @@ +src/README.rst \ No newline at end of file diff --git a/build/pkgs/sagemath_bliss/bootstrap b/build/pkgs/sagemath_bliss/bootstrap new file mode 120000 index 00000000000..40542346a4e --- /dev/null +++ b/build/pkgs/sagemath_bliss/bootstrap @@ -0,0 +1 @@ +../sagelib/bootstrap \ No newline at end of file diff --git a/build/pkgs/sagemath_bliss/dependencies b/build/pkgs/sagemath_bliss/dependencies new file mode 100644 index 00000000000..a7915e316b9 --- /dev/null +++ b/build/pkgs/sagemath_bliss/dependencies @@ -0,0 +1 @@ + bliss cysignals | $(PYTHON_TOOLCHAIN) sage_setup sage_conf sagemath_environment cython pkgconfig $(PYTHON) diff --git a/build/pkgs/sagemath_bliss/distros/conda.txt b/build/pkgs/sagemath_bliss/distros/conda.txt new file mode 100644 index 00000000000..d6139d966ec --- /dev/null +++ b/build/pkgs/sagemath_bliss/distros/conda.txt @@ -0,0 +1 @@ +sagemath-bliss diff --git a/build/pkgs/sagemath_bliss/install-requires.txt b/build/pkgs/sagemath_bliss/install-requires.txt new file mode 100644 index 00000000000..eaf783b463d --- /dev/null +++ b/build/pkgs/sagemath_bliss/install-requires.txt @@ -0,0 +1,2 @@ +# This file is updated on every release by the sage-update-version script +sagemath-bliss ~= 10.2b5 diff --git a/build/pkgs/sagemath_bliss/package-version.txt b/build/pkgs/sagemath_bliss/package-version.txt new file mode 120000 index 00000000000..c4540217bba --- /dev/null +++ b/build/pkgs/sagemath_bliss/package-version.txt @@ -0,0 +1 @@ +src/VERSION.txt \ No newline at end of file diff --git a/build/pkgs/sagemath_bliss/spkg-install b/build/pkgs/sagemath_bliss/spkg-install new file mode 100755 index 00000000000..7ce202f09ae --- /dev/null +++ b/build/pkgs/sagemath_bliss/spkg-install @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# From sage-spkg. +# For type=script packages, the build rule in build/make/Makefile sources +# sage-env but not sage-dist-helpers. +lib="$SAGE_ROOT/build/bin/sage-dist-helpers" +source "$lib" +if [ $? -ne 0 ]; then + echo >&2 "Error: failed to source $lib" + echo >&2 "Is $SAGE_ROOT the correct SAGE_ROOT?" + exit 1 +fi +cd src + +export PIP_NO_INDEX=true +export PIP_FIND_LINKS="file://$SAGE_SPKG_WHEELS" + +if [ "$SAGE_EDITABLE" = yes ]; then + # SAGE_ROOT/src/setup.py installs everything, nothing to do... + if [ "$SAGE_WHEELS" = yes ]; then + # ... except we build the wheel if requested + sdh_setup_bdist_wheel && sdh_store_wheel . + fi +else + if [ "$SAGE_WHEELS" = yes ]; then + # Modularized install via wheels + sdh_pip_install . + # else nothing to do in legacy direct installation. + fi +fi diff --git a/build/pkgs/sagemath_bliss/spkg-src b/build/pkgs/sagemath_bliss/spkg-src new file mode 100755 index 00000000000..483b2f349e3 --- /dev/null +++ b/build/pkgs/sagemath_bliss/spkg-src @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Script to prepare an sdist tarball for sagemath-bliss +# This script is not used during build. +# +# HOW TO MAKE THE TARBALL: +# ./sage --sh build/pkgs/sagemath_bliss/spkg-src + +if [ -z "$SAGE_ROOT" ] ; then + echo >&2 "Error - SAGE_ROOT undefined ... exiting" + echo >&2 "Maybe run 'sage -sh'?" + exit 1 +fi + +# Exit on failure +set -e + +cd build/pkgs/sagemath_bliss + +cd src +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_bliss/src b/build/pkgs/sagemath_bliss/src new file mode 120000 index 00000000000..51c70b82b95 --- /dev/null +++ b/build/pkgs/sagemath_bliss/src @@ -0,0 +1 @@ +../../../pkgs/sagemath-bliss \ No newline at end of file diff --git a/build/pkgs/sagemath_bliss/type b/build/pkgs/sagemath_bliss/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/sagemath_bliss/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/sagemath_categories/dependencies b/build/pkgs/sagemath_categories/dependencies index d8b6bdbd4a7..9fa43a64aae 100644 --- a/build/pkgs/sagemath_categories/dependencies +++ b/build/pkgs/sagemath_categories/dependencies @@ -1 +1 @@ -$(PYTHON) sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig python_build + sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig python_build $(PYTHON) diff --git a/build/pkgs/sagemath_categories/install-requires.txt b/build/pkgs/sagemath_categories/install-requires.txt index 1ddff9fc8f8..6f9c7bce7d6 100644 --- a/build/pkgs/sagemath_categories/install-requires.txt +++ b/build/pkgs/sagemath_categories/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 10.0b1 +sagemath-categories ~= 10.2b5 diff --git a/build/pkgs/sagemath_categories/spkg-src b/build/pkgs/sagemath_categories/spkg-src index 327d51651b9..e7c48e54193 100755 --- a/build/pkgs/sagemath_categories/spkg-src +++ b/build/pkgs/sagemath_categories/spkg-src @@ -18,4 +18,7 @@ set -e cd build/pkgs/sagemath_categories cd src -python3 -u setup.py --no-user-cfg sdist --dist-dir "$SAGE_DISTFILES" +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_coxeter3/SPKG.rst b/build/pkgs/sagemath_coxeter3/SPKG.rst new file mode 120000 index 00000000000..b4545b4bda6 --- /dev/null +++ b/build/pkgs/sagemath_coxeter3/SPKG.rst @@ -0,0 +1 @@ +src/README.rst \ No newline at end of file diff --git a/build/pkgs/sagemath_coxeter3/bootstrap b/build/pkgs/sagemath_coxeter3/bootstrap new file mode 120000 index 00000000000..40542346a4e --- /dev/null +++ b/build/pkgs/sagemath_coxeter3/bootstrap @@ -0,0 +1 @@ +../sagelib/bootstrap \ No newline at end of file diff --git a/build/pkgs/sagemath_coxeter3/dependencies b/build/pkgs/sagemath_coxeter3/dependencies new file mode 100644 index 00000000000..ada45656089 --- /dev/null +++ b/build/pkgs/sagemath_coxeter3/dependencies @@ -0,0 +1 @@ + coxeter3 | $(PYTHON_TOOLCHAIN) sage_setup sagemath_environment cython pkgconfig $(PYTHON) diff --git a/build/pkgs/sagemath_coxeter3/install-requires.txt b/build/pkgs/sagemath_coxeter3/install-requires.txt new file mode 100644 index 00000000000..79e17497045 --- /dev/null +++ b/build/pkgs/sagemath_coxeter3/install-requires.txt @@ -0,0 +1,2 @@ +# This file is updated on every release by the sage-update-version script +sagemath-coxeter3 ~= 10.2b5 diff --git a/build/pkgs/sagemath_coxeter3/package-version.txt b/build/pkgs/sagemath_coxeter3/package-version.txt new file mode 120000 index 00000000000..c4540217bba --- /dev/null +++ b/build/pkgs/sagemath_coxeter3/package-version.txt @@ -0,0 +1 @@ +src/VERSION.txt \ No newline at end of file diff --git a/build/pkgs/sagemath_coxeter3/spkg-install b/build/pkgs/sagemath_coxeter3/spkg-install new file mode 100755 index 00000000000..7ce202f09ae --- /dev/null +++ b/build/pkgs/sagemath_coxeter3/spkg-install @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# From sage-spkg. +# For type=script packages, the build rule in build/make/Makefile sources +# sage-env but not sage-dist-helpers. +lib="$SAGE_ROOT/build/bin/sage-dist-helpers" +source "$lib" +if [ $? -ne 0 ]; then + echo >&2 "Error: failed to source $lib" + echo >&2 "Is $SAGE_ROOT the correct SAGE_ROOT?" + exit 1 +fi +cd src + +export PIP_NO_INDEX=true +export PIP_FIND_LINKS="file://$SAGE_SPKG_WHEELS" + +if [ "$SAGE_EDITABLE" = yes ]; then + # SAGE_ROOT/src/setup.py installs everything, nothing to do... + if [ "$SAGE_WHEELS" = yes ]; then + # ... except we build the wheel if requested + sdh_setup_bdist_wheel && sdh_store_wheel . + fi +else + if [ "$SAGE_WHEELS" = yes ]; then + # Modularized install via wheels + sdh_pip_install . + # else nothing to do in legacy direct installation. + fi +fi diff --git a/build/pkgs/sagemath_coxeter3/spkg-src b/build/pkgs/sagemath_coxeter3/spkg-src new file mode 100755 index 00000000000..df635f450cf --- /dev/null +++ b/build/pkgs/sagemath_coxeter3/spkg-src @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Script to prepare an sdist tarball for sagemath-coxeter3 +# This script is not used during build. +# +# HOW TO MAKE THE TARBALL: +# ./sage --sh build/pkgs/sagemath_coxeter3/spkg-src + +if [ -z "$SAGE_ROOT" ] ; then + echo >&2 "Error - SAGE_ROOT undefined ... exiting" + echo >&2 "Maybe run 'sage -sh'?" + exit 1 +fi + +# Exit on failure +set -e + +cd build/pkgs/sagemath_coxeter3 + +cd src +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_coxeter3/src b/build/pkgs/sagemath_coxeter3/src new file mode 120000 index 00000000000..a9a1c8ae443 --- /dev/null +++ b/build/pkgs/sagemath_coxeter3/src @@ -0,0 +1 @@ +../../../pkgs/sagemath-coxeter3 \ No newline at end of file diff --git a/build/pkgs/sagemath_coxeter3/type b/build/pkgs/sagemath_coxeter3/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/sagemath_coxeter3/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/sagemath_doc_html/bootstrap b/build/pkgs/sagemath_doc_html/bootstrap new file mode 120000 index 00000000000..8dfc4b56a30 --- /dev/null +++ b/build/pkgs/sagemath_doc_html/bootstrap @@ -0,0 +1 @@ +src/bootstrap \ No newline at end of file diff --git a/build/pkgs/sagemath_doc_html/dependencies b/build/pkgs/sagemath_doc_html/dependencies index 5dfe1c2d453..9e4732ce372 100644 --- a/build/pkgs/sagemath_doc_html/dependencies +++ b/build/pkgs/sagemath_doc_html/dependencies @@ -1,4 +1,4 @@ -sagelib sphinx pplpy_doc | $(SAGERUNTIME) maxima networkx scipy sympy matplotlib pillow mathjax mpmath ipykernel jupyter_client conway_polynomials tachyon jmol ipywidgets jupyter_sphinx sage_docbuild elliptic_curves furo fpylll +sagelib sphinx sphinx_copybutton pplpy_doc | $(SAGERUNTIME) maxima networkx scipy sympy matplotlib pillow mathjax mpmath ipykernel jupyter_client conway_polynomials tachyon jmol ipywidgets jupyter_sphinx sage_docbuild elliptic_curves furo fpylll # Building the documentation has many dependencies, because all # documented modules are imported and because we use matplotlib to diff --git a/build/pkgs/sagemath_doc_html/src b/build/pkgs/sagemath_doc_html/src new file mode 120000 index 00000000000..95e24c1b7a5 --- /dev/null +++ b/build/pkgs/sagemath_doc_html/src @@ -0,0 +1 @@ +../../../src/doc \ No newline at end of file diff --git a/build/pkgs/sagemath_environment/dependencies b/build/pkgs/sagemath_environment/dependencies index 605611e7a21..0f36ec317e6 100644 --- a/build/pkgs/sagemath_environment/dependencies +++ b/build/pkgs/sagemath_environment/dependencies @@ -1 +1 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) python_build + | $(PYTHON_TOOLCHAIN) python_build $(PYTHON) diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt index 760c1dcf2e9..5e7993d773b 100644 --- a/build/pkgs/sagemath_environment/install-requires.txt +++ b/build/pkgs/sagemath_environment/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 10.0b1 +sagemath-environment ~= 10.2b5 diff --git a/build/pkgs/sagemath_environment/spkg-src b/build/pkgs/sagemath_environment/spkg-src index 4e2b7503da2..2d5b3aafde7 100755 --- a/build/pkgs/sagemath_environment/spkg-src +++ b/build/pkgs/sagemath_environment/spkg-src @@ -18,4 +18,7 @@ set -e cd build/pkgs/sagemath_environment cd src -python3 -u setup.py --no-user-cfg sdist --dist-dir "$SAGE_DISTFILES" +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_mcqd/SPKG.rst b/build/pkgs/sagemath_mcqd/SPKG.rst new file mode 120000 index 00000000000..b4545b4bda6 --- /dev/null +++ b/build/pkgs/sagemath_mcqd/SPKG.rst @@ -0,0 +1 @@ +src/README.rst \ No newline at end of file diff --git a/build/pkgs/sagemath_mcqd/bootstrap b/build/pkgs/sagemath_mcqd/bootstrap new file mode 120000 index 00000000000..40542346a4e --- /dev/null +++ b/build/pkgs/sagemath_mcqd/bootstrap @@ -0,0 +1 @@ +../sagelib/bootstrap \ No newline at end of file diff --git a/build/pkgs/sagemath_mcqd/dependencies b/build/pkgs/sagemath_mcqd/dependencies new file mode 100644 index 00000000000..9896fdaccfc --- /dev/null +++ b/build/pkgs/sagemath_mcqd/dependencies @@ -0,0 +1 @@ + mcqd memory_allocator cysignals | $(PYTHON_TOOLCHAIN) sage_setup cython pkgconfig $(PYTHON) diff --git a/build/pkgs/sagemath_mcqd/install-requires.txt b/build/pkgs/sagemath_mcqd/install-requires.txt new file mode 100644 index 00000000000..cf817314c08 --- /dev/null +++ b/build/pkgs/sagemath_mcqd/install-requires.txt @@ -0,0 +1,2 @@ +# This file is updated on every release by the sage-update-version script +sagemath-mcqd ~= 10.2b5 diff --git a/build/pkgs/sagemath_mcqd/package-version.txt b/build/pkgs/sagemath_mcqd/package-version.txt new file mode 120000 index 00000000000..c4540217bba --- /dev/null +++ b/build/pkgs/sagemath_mcqd/package-version.txt @@ -0,0 +1 @@ +src/VERSION.txt \ No newline at end of file diff --git a/build/pkgs/sagemath_mcqd/spkg-install b/build/pkgs/sagemath_mcqd/spkg-install new file mode 100755 index 00000000000..7ce202f09ae --- /dev/null +++ b/build/pkgs/sagemath_mcqd/spkg-install @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# From sage-spkg. +# For type=script packages, the build rule in build/make/Makefile sources +# sage-env but not sage-dist-helpers. +lib="$SAGE_ROOT/build/bin/sage-dist-helpers" +source "$lib" +if [ $? -ne 0 ]; then + echo >&2 "Error: failed to source $lib" + echo >&2 "Is $SAGE_ROOT the correct SAGE_ROOT?" + exit 1 +fi +cd src + +export PIP_NO_INDEX=true +export PIP_FIND_LINKS="file://$SAGE_SPKG_WHEELS" + +if [ "$SAGE_EDITABLE" = yes ]; then + # SAGE_ROOT/src/setup.py installs everything, nothing to do... + if [ "$SAGE_WHEELS" = yes ]; then + # ... except we build the wheel if requested + sdh_setup_bdist_wheel && sdh_store_wheel . + fi +else + if [ "$SAGE_WHEELS" = yes ]; then + # Modularized install via wheels + sdh_pip_install . + # else nothing to do in legacy direct installation. + fi +fi diff --git a/build/pkgs/sagemath_mcqd/spkg-src b/build/pkgs/sagemath_mcqd/spkg-src new file mode 100755 index 00000000000..c1602f0953e --- /dev/null +++ b/build/pkgs/sagemath_mcqd/spkg-src @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Script to prepare an sdist tarball for sagemath-mcqd +# This script is not used during build. +# +# HOW TO MAKE THE TARBALL: +# ./sage --sh build/pkgs/sagemath_mcqd/spkg-src + +if [ -z "$SAGE_ROOT" ] ; then + echo >&2 "Error - SAGE_ROOT undefined ... exiting" + echo >&2 "Maybe run 'sage -sh'?" + exit 1 +fi + +# Exit on failure +set -e + +cd build/pkgs/sagemath_mcqd + +cd src +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_mcqd/src b/build/pkgs/sagemath_mcqd/src new file mode 120000 index 00000000000..03d68b8cbe3 --- /dev/null +++ b/build/pkgs/sagemath_mcqd/src @@ -0,0 +1 @@ +../../../pkgs/sagemath-mcqd \ No newline at end of file diff --git a/build/pkgs/sagemath_mcqd/type b/build/pkgs/sagemath_mcqd/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/sagemath_mcqd/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/sagemath_meataxe/SPKG.rst b/build/pkgs/sagemath_meataxe/SPKG.rst new file mode 120000 index 00000000000..b4545b4bda6 --- /dev/null +++ b/build/pkgs/sagemath_meataxe/SPKG.rst @@ -0,0 +1 @@ +src/README.rst \ No newline at end of file diff --git a/build/pkgs/sagemath_meataxe/bootstrap b/build/pkgs/sagemath_meataxe/bootstrap new file mode 120000 index 00000000000..40542346a4e --- /dev/null +++ b/build/pkgs/sagemath_meataxe/bootstrap @@ -0,0 +1 @@ +../sagelib/bootstrap \ No newline at end of file diff --git a/build/pkgs/sagemath_meataxe/dependencies b/build/pkgs/sagemath_meataxe/dependencies new file mode 100644 index 00000000000..c333fcc61db --- /dev/null +++ b/build/pkgs/sagemath_meataxe/dependencies @@ -0,0 +1 @@ + meataxe | $(PYTHON_TOOLCHAIN) sage_setup sagemath_environment cython pkgconfig $(PYTHON) diff --git a/build/pkgs/sagemath_meataxe/install-requires.txt b/build/pkgs/sagemath_meataxe/install-requires.txt new file mode 100644 index 00000000000..97b6bb48c9c --- /dev/null +++ b/build/pkgs/sagemath_meataxe/install-requires.txt @@ -0,0 +1,2 @@ +# This file is updated on every release by the sage-update-version script +sagemath-meataxe ~= 10.2b5 diff --git a/build/pkgs/sagemath_meataxe/package-version.txt b/build/pkgs/sagemath_meataxe/package-version.txt new file mode 120000 index 00000000000..c4540217bba --- /dev/null +++ b/build/pkgs/sagemath_meataxe/package-version.txt @@ -0,0 +1 @@ +src/VERSION.txt \ No newline at end of file diff --git a/build/pkgs/sagemath_meataxe/spkg-install b/build/pkgs/sagemath_meataxe/spkg-install new file mode 100755 index 00000000000..7ce202f09ae --- /dev/null +++ b/build/pkgs/sagemath_meataxe/spkg-install @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# From sage-spkg. +# For type=script packages, the build rule in build/make/Makefile sources +# sage-env but not sage-dist-helpers. +lib="$SAGE_ROOT/build/bin/sage-dist-helpers" +source "$lib" +if [ $? -ne 0 ]; then + echo >&2 "Error: failed to source $lib" + echo >&2 "Is $SAGE_ROOT the correct SAGE_ROOT?" + exit 1 +fi +cd src + +export PIP_NO_INDEX=true +export PIP_FIND_LINKS="file://$SAGE_SPKG_WHEELS" + +if [ "$SAGE_EDITABLE" = yes ]; then + # SAGE_ROOT/src/setup.py installs everything, nothing to do... + if [ "$SAGE_WHEELS" = yes ]; then + # ... except we build the wheel if requested + sdh_setup_bdist_wheel && sdh_store_wheel . + fi +else + if [ "$SAGE_WHEELS" = yes ]; then + # Modularized install via wheels + sdh_pip_install . + # else nothing to do in legacy direct installation. + fi +fi diff --git a/build/pkgs/sagemath_meataxe/spkg-src b/build/pkgs/sagemath_meataxe/spkg-src new file mode 100755 index 00000000000..a0e05c1fc98 --- /dev/null +++ b/build/pkgs/sagemath_meataxe/spkg-src @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Script to prepare an sdist tarball for sagemath-meataxe +# This script is not used during build. +# +# HOW TO MAKE THE TARBALL: +# ./sage --sh build/pkgs/sagemath_meataxe/spkg-src + +if [ -z "$SAGE_ROOT" ] ; then + echo >&2 "Error - SAGE_ROOT undefined ... exiting" + echo >&2 "Maybe run 'sage -sh'?" + exit 1 +fi + +# Exit on failure +set -e + +cd build/pkgs/sagemath_meataxe + +cd src +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_meataxe/src b/build/pkgs/sagemath_meataxe/src new file mode 120000 index 00000000000..1164dd787fd --- /dev/null +++ b/build/pkgs/sagemath_meataxe/src @@ -0,0 +1 @@ +../../../pkgs/sagemath-meataxe \ No newline at end of file diff --git a/build/pkgs/sagemath_meataxe/type b/build/pkgs/sagemath_meataxe/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/sagemath_meataxe/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/sagemath_objects/dependencies b/build/pkgs/sagemath_objects/dependencies index 807b8b17215..ffc14bb6ba6 100644 --- a/build/pkgs/sagemath_objects/dependencies +++ b/build/pkgs/sagemath_objects/dependencies @@ -1,3 +1,3 @@ -FORCE $(PYTHON) cysignals gmpy2 | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig python_build +FORCE cysignals gmpy2 | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig python_build $(PYTHON) # FORCE: Always run the spkg-install script diff --git a/build/pkgs/sagemath_objects/install-requires.txt b/build/pkgs/sagemath_objects/install-requires.txt index 51e5c5a346d..99b0309ee9e 100644 --- a/build/pkgs/sagemath_objects/install-requires.txt +++ b/build/pkgs/sagemath_objects/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 10.0b1 +sagemath-objects ~= 10.2b5 diff --git a/build/pkgs/sagemath_objects/spkg-install b/build/pkgs/sagemath_objects/spkg-install index 6cc85e07e55..472e7f0d4d6 100755 --- a/build/pkgs/sagemath_objects/spkg-install +++ b/build/pkgs/sagemath_objects/spkg-install @@ -21,9 +21,28 @@ export PIP_FIND_LINKS="file://$SAGE_SPKG_WHEELS" DIST_DIR="$(mktemp -d)" python3 -m build --outdir "$DIST_DIR"/dist . || sdh_die "Failure building sdist and wheel" -wheel=$(cd "$DIST_DIR" && sdh_store_wheel . && echo $wheel) +wheel=$(cd "$DIST_DIR" && sdh_store_wheel . >&2 && echo $wheel) ls -l "$wheel" if [ "$SAGE_CHECK" != no ]; then - tox -r -v -e sagepython-sagewheels-nopypi-norequirements --installpkg $wheel + export TOX_PARALLEL_NO_SPINNER=1 + echo Running "tox -r -p auto -v --installpkg $wheel" + tox -r -p auto -v --installpkg $wheel + status=$? + case $status:$SAGE_CHECK:$([ -r known-test-failures.json ]; echo $?) in + 0:*:0) echo "Passed the test suite (modulo baseline known-test-failures*.json)";; + 0:*:*) echo "Passed the test suite";; + *:warn:0) echo "Warning: New failures (not in baseline known-test-failures*.json (ignored)"; status=0;; + *:warn:*) echo "Warning: Failures testing the package (ignored)"; status=0;; + *:yes:0) echo "New failures, not in baseline known-test-failures*.json";; + *:yes:*) echo "Failures testing the package";; + esac + # Show summaries of failures (suppress lines ending with '[failed in baseline]') + for f in $(pwd)/.tox/sagepython-sagewheels-nopypi-norequirements*/log/*-command*.log; do + if [ -r "$f" ]; then + echo "$f" + grep '^sage -t.*#[^]]*$' "$f" + fi + done + exit $status fi diff --git a/build/pkgs/sagemath_objects/spkg-src b/build/pkgs/sagemath_objects/spkg-src index 68719fae1b6..f46ddc2bd3b 100755 --- a/build/pkgs/sagemath_objects/spkg-src +++ b/build/pkgs/sagemath_objects/spkg-src @@ -18,4 +18,8 @@ set -e cd build/pkgs/sagemath_objects cd src -python3 -u setup.py --no-user-cfg sdist --dist-dir "$SAGE_DISTFILES" + +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_repl/dependencies b/build/pkgs/sagemath_repl/dependencies index ebc253dac5b..7d7ba20c5dd 100644 --- a/build/pkgs/sagemath_repl/dependencies +++ b/build/pkgs/sagemath_repl/dependencies @@ -1 +1 @@ -$(PYTHON) sagemath_objects sagemath_environment ipython ipywidgets | $(PYTHON_TOOLCHAIN) python_build + sagemath_objects sagemath_environment ipython ipywidgets | $(PYTHON_TOOLCHAIN) python_build $(PYTHON) diff --git a/build/pkgs/sagemath_repl/install-requires.txt b/build/pkgs/sagemath_repl/install-requires.txt index ca64cd6b39f..9dab260bb52 100644 --- a/build/pkgs/sagemath_repl/install-requires.txt +++ b/build/pkgs/sagemath_repl/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-repl ~= 10.0b1 +sagemath-repl ~= 10.2b5 diff --git a/build/pkgs/sagemath_repl/spkg-src b/build/pkgs/sagemath_repl/spkg-src index b20ea463784..2ef7b673696 100755 --- a/build/pkgs/sagemath_repl/spkg-src +++ b/build/pkgs/sagemath_repl/spkg-src @@ -18,4 +18,7 @@ set -e cd build/pkgs/sagemath_repl cd src -python3 -u setup.py --no-user-cfg sdist --dist-dir "$SAGE_DISTFILES" +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_sirocco/SPKG.rst b/build/pkgs/sagemath_sirocco/SPKG.rst new file mode 120000 index 00000000000..b4545b4bda6 --- /dev/null +++ b/build/pkgs/sagemath_sirocco/SPKG.rst @@ -0,0 +1 @@ +src/README.rst \ No newline at end of file diff --git a/build/pkgs/sagemath_sirocco/bootstrap b/build/pkgs/sagemath_sirocco/bootstrap new file mode 120000 index 00000000000..40542346a4e --- /dev/null +++ b/build/pkgs/sagemath_sirocco/bootstrap @@ -0,0 +1 @@ +../sagelib/bootstrap \ No newline at end of file diff --git a/build/pkgs/sagemath_sirocco/dependencies b/build/pkgs/sagemath_sirocco/dependencies new file mode 100644 index 00000000000..4f47049ec4b --- /dev/null +++ b/build/pkgs/sagemath_sirocco/dependencies @@ -0,0 +1 @@ + sirocco cypari cysignals mpfr | $(PYTHON_TOOLCHAIN) sage_setup sagemath_environment cython pkgconfig $(PYTHON) diff --git a/build/pkgs/sagemath_sirocco/distros/conda.txt b/build/pkgs/sagemath_sirocco/distros/conda.txt new file mode 100644 index 00000000000..fc9cfb79706 --- /dev/null +++ b/build/pkgs/sagemath_sirocco/distros/conda.txt @@ -0,0 +1 @@ +sagemath-sirocco diff --git a/build/pkgs/sagemath_sirocco/install-requires.txt b/build/pkgs/sagemath_sirocco/install-requires.txt new file mode 100644 index 00000000000..7b67a383e35 --- /dev/null +++ b/build/pkgs/sagemath_sirocco/install-requires.txt @@ -0,0 +1,2 @@ +# This file is updated on every release by the sage-update-version script +sagemath-sirocco ~= 10.2b5 diff --git a/build/pkgs/sagemath_sirocco/package-version.txt b/build/pkgs/sagemath_sirocco/package-version.txt new file mode 120000 index 00000000000..c4540217bba --- /dev/null +++ b/build/pkgs/sagemath_sirocco/package-version.txt @@ -0,0 +1 @@ +src/VERSION.txt \ No newline at end of file diff --git a/build/pkgs/sagemath_sirocco/spkg-install b/build/pkgs/sagemath_sirocco/spkg-install new file mode 100755 index 00000000000..7ce202f09ae --- /dev/null +++ b/build/pkgs/sagemath_sirocco/spkg-install @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# From sage-spkg. +# For type=script packages, the build rule in build/make/Makefile sources +# sage-env but not sage-dist-helpers. +lib="$SAGE_ROOT/build/bin/sage-dist-helpers" +source "$lib" +if [ $? -ne 0 ]; then + echo >&2 "Error: failed to source $lib" + echo >&2 "Is $SAGE_ROOT the correct SAGE_ROOT?" + exit 1 +fi +cd src + +export PIP_NO_INDEX=true +export PIP_FIND_LINKS="file://$SAGE_SPKG_WHEELS" + +if [ "$SAGE_EDITABLE" = yes ]; then + # SAGE_ROOT/src/setup.py installs everything, nothing to do... + if [ "$SAGE_WHEELS" = yes ]; then + # ... except we build the wheel if requested + sdh_setup_bdist_wheel && sdh_store_wheel . + fi +else + if [ "$SAGE_WHEELS" = yes ]; then + # Modularized install via wheels + sdh_pip_install . + # else nothing to do in legacy direct installation. + fi +fi diff --git a/build/pkgs/sagemath_sirocco/spkg-src b/build/pkgs/sagemath_sirocco/spkg-src new file mode 100755 index 00000000000..4082abf43b2 --- /dev/null +++ b/build/pkgs/sagemath_sirocco/spkg-src @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Script to prepare an sdist tarball for sagemath-sirocco +# This script is not used during build. +# +# HOW TO MAKE THE TARBALL: +# ./sage --sh build/pkgs/sagemath_sirocco/spkg-src + +if [ -z "$SAGE_ROOT" ] ; then + echo >&2 "Error - SAGE_ROOT undefined ... exiting" + echo >&2 "Maybe run 'sage -sh'?" + exit 1 +fi + +# Exit on failure +set -e + +cd build/pkgs/sagemath_sirocco + +cd src +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_sirocco/src b/build/pkgs/sagemath_sirocco/src new file mode 120000 index 00000000000..03d0d674991 --- /dev/null +++ b/build/pkgs/sagemath_sirocco/src @@ -0,0 +1 @@ +../../../pkgs/sagemath-sirocco \ No newline at end of file diff --git a/build/pkgs/sagemath_sirocco/type b/build/pkgs/sagemath_sirocco/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/sagemath_sirocco/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/sagemath_tdlib/SPKG.rst b/build/pkgs/sagemath_tdlib/SPKG.rst new file mode 120000 index 00000000000..b4545b4bda6 --- /dev/null +++ b/build/pkgs/sagemath_tdlib/SPKG.rst @@ -0,0 +1 @@ +src/README.rst \ No newline at end of file diff --git a/build/pkgs/sagemath_tdlib/bootstrap b/build/pkgs/sagemath_tdlib/bootstrap new file mode 120000 index 00000000000..40542346a4e --- /dev/null +++ b/build/pkgs/sagemath_tdlib/bootstrap @@ -0,0 +1 @@ +../sagelib/bootstrap \ No newline at end of file diff --git a/build/pkgs/sagemath_tdlib/dependencies b/build/pkgs/sagemath_tdlib/dependencies new file mode 100644 index 00000000000..b22ab6c52a7 --- /dev/null +++ b/build/pkgs/sagemath_tdlib/dependencies @@ -0,0 +1 @@ + tdlib cysignals | $(PYTHON_TOOLCHAIN) sage_setup sagemath_environment cython pkgconfig $(PYTHON) diff --git a/build/pkgs/sagemath_tdlib/install-requires.txt b/build/pkgs/sagemath_tdlib/install-requires.txt new file mode 100644 index 00000000000..a5f0a2240a4 --- /dev/null +++ b/build/pkgs/sagemath_tdlib/install-requires.txt @@ -0,0 +1,2 @@ +# This file is updated on every release by the sage-update-version script +sagemath-tdlib ~= 10.2b5 diff --git a/build/pkgs/sagemath_tdlib/package-version.txt b/build/pkgs/sagemath_tdlib/package-version.txt new file mode 120000 index 00000000000..c4540217bba --- /dev/null +++ b/build/pkgs/sagemath_tdlib/package-version.txt @@ -0,0 +1 @@ +src/VERSION.txt \ No newline at end of file diff --git a/build/pkgs/sagemath_tdlib/spkg-install b/build/pkgs/sagemath_tdlib/spkg-install new file mode 100755 index 00000000000..7ce202f09ae --- /dev/null +++ b/build/pkgs/sagemath_tdlib/spkg-install @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# From sage-spkg. +# For type=script packages, the build rule in build/make/Makefile sources +# sage-env but not sage-dist-helpers. +lib="$SAGE_ROOT/build/bin/sage-dist-helpers" +source "$lib" +if [ $? -ne 0 ]; then + echo >&2 "Error: failed to source $lib" + echo >&2 "Is $SAGE_ROOT the correct SAGE_ROOT?" + exit 1 +fi +cd src + +export PIP_NO_INDEX=true +export PIP_FIND_LINKS="file://$SAGE_SPKG_WHEELS" + +if [ "$SAGE_EDITABLE" = yes ]; then + # SAGE_ROOT/src/setup.py installs everything, nothing to do... + if [ "$SAGE_WHEELS" = yes ]; then + # ... except we build the wheel if requested + sdh_setup_bdist_wheel && sdh_store_wheel . + fi +else + if [ "$SAGE_WHEELS" = yes ]; then + # Modularized install via wheels + sdh_pip_install . + # else nothing to do in legacy direct installation. + fi +fi diff --git a/build/pkgs/sagemath_tdlib/spkg-src b/build/pkgs/sagemath_tdlib/spkg-src new file mode 100755 index 00000000000..88e67414c05 --- /dev/null +++ b/build/pkgs/sagemath_tdlib/spkg-src @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Script to prepare an sdist tarball for sagemath-tdlib +# This script is not used during build. +# +# HOW TO MAKE THE TARBALL: +# ./sage --sh build/pkgs/sagemath_tdlib/spkg-src + +if [ -z "$SAGE_ROOT" ] ; then + echo >&2 "Error - SAGE_ROOT undefined ... exiting" + echo >&2 "Maybe run 'sage -sh'?" + exit 1 +fi + +# Exit on failure +set -e + +cd build/pkgs/sagemath_tdlib + +cd src +# Get rid of old *.egg-info/SOURCES.txt +rm -Rf *.egg-info + +python3 -m build --sdist --no-isolation --skip-dependency-check --outdir "$SAGE_DISTFILES" diff --git a/build/pkgs/sagemath_tdlib/src b/build/pkgs/sagemath_tdlib/src new file mode 120000 index 00000000000..0d238df793e --- /dev/null +++ b/build/pkgs/sagemath_tdlib/src @@ -0,0 +1 @@ +../../../pkgs/sagemath-tdlib \ No newline at end of file diff --git a/build/pkgs/sagemath_tdlib/type b/build/pkgs/sagemath_tdlib/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/sagemath_tdlib/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/sagenb_export/dependencies b/build/pkgs/sagenb_export/dependencies index 26033350f88..f9a2f2adbb9 100644 --- a/build/pkgs/sagenb_export/dependencies +++ b/build/pkgs/sagenb_export/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) notebook nbconvert ipython six | $(PYTHON_TOOLCHAIN) + notebook nbconvert ipython six | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sagetex/dependencies b/build/pkgs/sagetex/dependencies index 6090d5dc3ac..af9b5f370fb 100644 --- a/build/pkgs/sagetex/dependencies +++ b/build/pkgs/sagetex/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) maxima scipy matplotlib pillow tachyon pyparsing + maxima scipy matplotlib pillow tachyon pyparsing | $(PYTHON) To build SageTeX, you just need Python and pyparsing, but to test (SAGE_CHECK=yes) SageTeX, you actually need to run Sage, produce plots,... diff --git a/build/pkgs/scipy/checksums.ini b/build/pkgs/scipy/checksums.ini index 24c26b4981b..7015206d1e7 100644 --- a/build/pkgs/scipy/checksums.ini +++ b/build/pkgs/scipy/checksums.ini @@ -1,5 +1,5 @@ tarball=scipy-VERSION.tar.gz -sha1=55fb286ab1a0b66a7439c5cc76e3c80e9de409ec -md5=83b0d9eab2ce79b7fe5888f119adee64 -cksum=1605676871 +sha1=856f8ac8498751b72d678ef64b88e436d04a957d +md5=27baf613b6cf3f9600a05161f132151c +cksum=1656738318 upstream_url=https://pypi.io/packages/source/s/scipy/scipy-VERSION.tar.gz diff --git a/build/pkgs/scipy/dependencies b/build/pkgs/scipy/dependencies index 5d42789eb10..82fa8e0c0d7 100644 --- a/build/pkgs/scipy/dependencies +++ b/build/pkgs/scipy/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) $(BLAS) gfortran numpy pybind11 cython pythran | $(PYTHON_TOOLCHAIN) meson_python + $(BLAS) gfortran numpy pybind11 cython pythran | $(PYTHON_TOOLCHAIN) meson_python $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/scipy/distros/arch.txt b/build/pkgs/scipy/distros/arch.txt new file mode 100644 index 00000000000..7ff2882c1bf --- /dev/null +++ b/build/pkgs/scipy/distros/arch.txt @@ -0,0 +1 @@ +python-scipy diff --git a/build/pkgs/scipy/distros/conda.txt b/build/pkgs/scipy/distros/conda.txt index 9a635b910d9..21b2670008a 100644 --- a/build/pkgs/scipy/distros/conda.txt +++ b/build/pkgs/scipy/distros/conda.txt @@ -1 +1 @@ -scipy +scipy<1.11,>=1.5 diff --git a/build/pkgs/scipy/distros/debian.txt b/build/pkgs/scipy/distros/debian.txt new file mode 100644 index 00000000000..12b366666d6 --- /dev/null +++ b/build/pkgs/scipy/distros/debian.txt @@ -0,0 +1 @@ +python3-scipy diff --git a/build/pkgs/scipy/distros/fedora.txt b/build/pkgs/scipy/distros/fedora.txt new file mode 100644 index 00000000000..7ff2882c1bf --- /dev/null +++ b/build/pkgs/scipy/distros/fedora.txt @@ -0,0 +1 @@ +python-scipy diff --git a/build/pkgs/scipy/distros/gentoo.txt b/build/pkgs/scipy/distros/gentoo.txt new file mode 100644 index 00000000000..11dabd2830f --- /dev/null +++ b/build/pkgs/scipy/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/scipy diff --git a/build/pkgs/scipy/distros/opensuse.txt b/build/pkgs/scipy/distros/opensuse.txt index 12b366666d6..d2bc2a30a85 100644 --- a/build/pkgs/scipy/distros/opensuse.txt +++ b/build/pkgs/scipy/distros/opensuse.txt @@ -1 +1 @@ -python3-scipy +python3${PYTHON_MINOR}-scipy diff --git a/build/pkgs/scipy/install-requires.txt b/build/pkgs/scipy/install-requires.txt index 16d57fdb9b0..dd975a870e3 100644 --- a/build/pkgs/scipy/install-requires.txt +++ b/build/pkgs/scipy/install-requires.txt @@ -4,4 +4,4 @@ # deprecations cannot be introduced in micro releases. # SciPy devs wait "at least 6 months", "in practice two (minor) releases" # from deprecation to removal of a feature. -scipy >=1.5, <1.11 +scipy >=1.5, <1.12 diff --git a/build/pkgs/scipy/package-version.txt b/build/pkgs/scipy/package-version.txt index 77fee73a8cf..ca7176690dd 100644 --- a/build/pkgs/scipy/package-version.txt +++ b/build/pkgs/scipy/package-version.txt @@ -1 +1 @@ -1.9.3 +1.11.2 diff --git a/build/pkgs/scipy/patches/tests_no_internet_dependency.patch b/build/pkgs/scipy/patches/tests_no_internet_dependency.patch new file mode 100644 index 00000000000..5578e80c7b5 --- /dev/null +++ b/build/pkgs/scipy/patches/tests_no_internet_dependency.patch @@ -0,0 +1,12 @@ +Disable tests in scipy/datasets, which require internet access. +See https://github.com/scipy/scipy/pull/17965 + +diff --git a/scipy/datasets/meson.build b/scipy/datasets/meson.build +index 10137725381..132e8d29534 100644 +--- a/scipy/datasets/meson.build ++++ b/scipy/datasets/meson.build +@@ -11,4 +11,3 @@ py3.install_sources( + subdir: 'scipy/datasets' + ) + +-subdir('tests') diff --git a/build/pkgs/scipy/spkg-configure.m4 b/build/pkgs/scipy/spkg-configure.m4 new file mode 100644 index 00000000000..0b7294a02e8 --- /dev/null +++ b/build/pkgs/scipy/spkg-configure.m4 @@ -0,0 +1,5 @@ +SAGE_SPKG_CONFIGURE([scipy], [ + SAGE_SPKG_DEPCHECK([openblas], [ + SAGE_PYTHON_PACKAGE_CHECK([scipy]) + ]) +]) diff --git a/build/pkgs/scs/SPKG.rst b/build/pkgs/scs/SPKG.rst new file mode 100644 index 00000000000..5d8430bfd6a --- /dev/null +++ b/build/pkgs/scs/SPKG.rst @@ -0,0 +1,18 @@ +scs: Splitting conic solver +=========================== + +Description +----------- + +scs: splitting conic solver + +License +------- + +MIT + +Upstream Contact +---------------- + +https://pypi.org/project/scs/ + diff --git a/build/pkgs/scs/checksums.ini b/build/pkgs/scs/checksums.ini new file mode 100644 index 00000000000..1e2e269bf71 --- /dev/null +++ b/build/pkgs/scs/checksums.ini @@ -0,0 +1,5 @@ +tarball=scs-VERSION.tar.gz +sha1=309a035e5031f7a51c4992d5ad6c9236a406adc2 +md5=c984027aea923fa88e2f73c61bc06dd0 +cksum=1688898932 +upstream_url=https://pypi.io/packages/source/s/scs/scs-VERSION.tar.gz diff --git a/build/pkgs/scs/dependencies b/build/pkgs/scs/dependencies new file mode 100644 index 00000000000..a736df74ec5 --- /dev/null +++ b/build/pkgs/scs/dependencies @@ -0,0 +1,4 @@ + numpy | $(PYTHON_TOOLCHAIN) cmake $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/scs/distros/conda.txt b/build/pkgs/scs/distros/conda.txt new file mode 100644 index 00000000000..846d47b8e24 --- /dev/null +++ b/build/pkgs/scs/distros/conda.txt @@ -0,0 +1 @@ +scs diff --git a/build/pkgs/scs/install-requires.txt b/build/pkgs/scs/install-requires.txt new file mode 100644 index 00000000000..846d47b8e24 --- /dev/null +++ b/build/pkgs/scs/install-requires.txt @@ -0,0 +1 @@ +scs diff --git a/build/pkgs/scs/package-version.txt b/build/pkgs/scs/package-version.txt new file mode 100644 index 00000000000..be94e6f53db --- /dev/null +++ b/build/pkgs/scs/package-version.txt @@ -0,0 +1 @@ +3.2.2 diff --git a/build/pkgs/scs/spkg-install.in b/build/pkgs/scs/spkg-install.in new file mode 100644 index 00000000000..a143d1eff96 --- /dev/null +++ b/build/pkgs/scs/spkg-install.in @@ -0,0 +1,3 @@ +cd src +# --no-build-isolation to ignore the numpy version pin in pyproject.toml +sdh_pip_install --no-build-isolation . diff --git a/build/pkgs/scs/type b/build/pkgs/scs/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/scs/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/send2trash/checksums.ini b/build/pkgs/send2trash/checksums.ini index f8655f8a27b..1b16811d046 100644 --- a/build/pkgs/send2trash/checksums.ini +++ b/build/pkgs/send2trash/checksums.ini @@ -1,5 +1,5 @@ tarball=Send2Trash-VERSION.tar.gz -sha1=a264800d0fe5040f4c6a25fd9c781122c95d2754 -md5=6d76f3ab178c15a2ff4d924652ebcb73 -cksum=2364080384 +sha1=211092dcefa5468582f7d083472ad7f1880cc019 +md5=3fc7ff801bc76da65cf4e97d6b89025e +cksum=3017010359 upstream_url=https://pypi.io/packages/source/s/send2trash/Send2Trash-VERSION.tar.gz diff --git a/build/pkgs/send2trash/dependencies b/build/pkgs/send2trash/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/send2trash/dependencies +++ b/build/pkgs/send2trash/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/send2trash/distros/gentoo.txt b/build/pkgs/send2trash/distros/gentoo.txt new file mode 100644 index 00000000000..a89b1798476 --- /dev/null +++ b/build/pkgs/send2trash/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/send2trash diff --git a/build/pkgs/send2trash/distros/opensuse.txt b/build/pkgs/send2trash/distros/opensuse.txt index 404e2bd3580..8d3c81fa23c 100644 --- a/build/pkgs/send2trash/distros/opensuse.txt +++ b/build/pkgs/send2trash/distros/opensuse.txt @@ -1 +1 @@ -python3-Send2Trash +python3${PYTHON_MINOR}-Send2Trash diff --git a/build/pkgs/send2trash/package-version.txt b/build/pkgs/send2trash/package-version.txt index 27f9cd322bb..53adb84c822 100644 --- a/build/pkgs/send2trash/package-version.txt +++ b/build/pkgs/send2trash/package-version.txt @@ -1 +1 @@ -1.8.0 +1.8.2 diff --git a/build/pkgs/send2trash/spkg-configure.m4 b/build/pkgs/send2trash/spkg-configure.m4 new file mode 100644 index 00000000000..3bbb727e430 --- /dev/null +++ b/build/pkgs/send2trash/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([send2trash], [SAGE_PYTHON_PACKAGE_CHECK([send2trash])]) diff --git a/build/pkgs/setuptools/dependencies b/build/pkgs/setuptools/dependencies index 1700e743d59..d45a397db36 100644 --- a/build/pkgs/setuptools/dependencies +++ b/build/pkgs/setuptools/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) + | $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/setuptools/distros/arch.txt b/build/pkgs/setuptools/distros/arch.txt new file mode 100644 index 00000000000..e1ad17860cd --- /dev/null +++ b/build/pkgs/setuptools/distros/arch.txt @@ -0,0 +1 @@ +python-setuptools diff --git a/build/pkgs/setuptools/distros/debian.txt b/build/pkgs/setuptools/distros/debian.txt new file mode 100644 index 00000000000..1c0901c0374 --- /dev/null +++ b/build/pkgs/setuptools/distros/debian.txt @@ -0,0 +1 @@ +python3-setuptools diff --git a/build/pkgs/setuptools/distros/fedora.txt b/build/pkgs/setuptools/distros/fedora.txt new file mode 100644 index 00000000000..e1ad17860cd --- /dev/null +++ b/build/pkgs/setuptools/distros/fedora.txt @@ -0,0 +1 @@ +python-setuptools diff --git a/build/pkgs/setuptools/distros/gentoo.txt b/build/pkgs/setuptools/distros/gentoo.txt new file mode 100644 index 00000000000..3a4fa34a57f --- /dev/null +++ b/build/pkgs/setuptools/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/setuptools diff --git a/build/pkgs/setuptools/distros/opensuse.txt b/build/pkgs/setuptools/distros/opensuse.txt index 1c0901c0374..b2d8de78f80 100644 --- a/build/pkgs/setuptools/distros/opensuse.txt +++ b/build/pkgs/setuptools/distros/opensuse.txt @@ -1 +1 @@ -python3-setuptools +python3${PYTHON_MINOR}-setuptools diff --git a/build/pkgs/setuptools/install-requires.txt b/build/pkgs/setuptools/install-requires.txt index 0810ca37277..e0cf7c9b5dc 100644 --- a/build/pkgs/setuptools/install-requires.txt +++ b/build/pkgs/setuptools/install-requires.txt @@ -1 +1 @@ -setuptools >=49.6.0 +setuptools >=49.6.0, <64 diff --git a/build/pkgs/setuptools/spkg-configure.m4 b/build/pkgs/setuptools/spkg-configure.m4 new file mode 100644 index 00000000000..a2ad8119063 --- /dev/null +++ b/build/pkgs/setuptools/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([setuptools], [SAGE_PYTHON_PACKAGE_CHECK([setuptools])]) diff --git a/build/pkgs/setuptools_scm/dependencies b/build/pkgs/setuptools_scm/dependencies index f3662a5c829..7dd3b6e8f6e 100644 --- a/build/pkgs/setuptools_scm/dependencies +++ b/build/pkgs/setuptools_scm/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) typing_extensions | setuptools pip wheel tomli packaging + typing_extensions | setuptools pip wheel tomli packaging $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/setuptools_scm/distros/arch.txt b/build/pkgs/setuptools_scm/distros/arch.txt new file mode 100644 index 00000000000..2b97444decf --- /dev/null +++ b/build/pkgs/setuptools_scm/distros/arch.txt @@ -0,0 +1 @@ +python-setuptools-scm diff --git a/build/pkgs/setuptools_scm/distros/debian.txt b/build/pkgs/setuptools_scm/distros/debian.txt new file mode 100644 index 00000000000..bcfdd6ebcdd --- /dev/null +++ b/build/pkgs/setuptools_scm/distros/debian.txt @@ -0,0 +1 @@ +setuptools-scm diff --git a/build/pkgs/setuptools_scm/distros/fedora.txt b/build/pkgs/setuptools_scm/distros/fedora.txt new file mode 100644 index 00000000000..720fd2897be --- /dev/null +++ b/build/pkgs/setuptools_scm/distros/fedora.txt @@ -0,0 +1 @@ +python-setuptools_scm diff --git a/build/pkgs/setuptools_scm/distros/freebsd.txt b/build/pkgs/setuptools_scm/distros/freebsd.txt new file mode 100644 index 00000000000..ba714681e0a --- /dev/null +++ b/build/pkgs/setuptools_scm/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-setuptools_scm diff --git a/build/pkgs/setuptools_scm/distros/gentoo.txt b/build/pkgs/setuptools_scm/distros/gentoo.txt new file mode 100644 index 00000000000..46efc2bdeb4 --- /dev/null +++ b/build/pkgs/setuptools_scm/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/setuptools-scm diff --git a/build/pkgs/setuptools_scm/distros/opensuse.txt b/build/pkgs/setuptools_scm/distros/opensuse.txt index 2aa5ca12cba..cacb303c566 100644 --- a/build/pkgs/setuptools_scm/distros/opensuse.txt +++ b/build/pkgs/setuptools_scm/distros/opensuse.txt @@ -1 +1 @@ -python3-setuptools_scm +python3${PYTHON_MINOR}-setuptools_scm diff --git a/build/pkgs/setuptools_scm/install-requires.txt b/build/pkgs/setuptools_scm/install-requires.txt index ee00ef62d52..34188327a0f 100644 --- a/build/pkgs/setuptools_scm/install-requires.txt +++ b/build/pkgs/setuptools_scm/install-requires.txt @@ -1 +1,2 @@ -setuptools_scm >=4.1.2 +# matplotlib-3.6.2 needs >= 7 +setuptools_scm >=7 diff --git a/build/pkgs/setuptools_scm/spkg-configure.m4 b/build/pkgs/setuptools_scm/spkg-configure.m4 new file mode 100644 index 00000000000..437148c2a8f --- /dev/null +++ b/build/pkgs/setuptools_scm/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([setuptools_scm], [ + SAGE_PYTHON_PACKAGE_CHECK([setuptools_scm]) +]) diff --git a/build/pkgs/setuptools_scm_git_archive/SPKG.rst b/build/pkgs/setuptools_scm_git_archive/SPKG.rst deleted file mode 100644 index 540e0c2d923..00000000000 --- a/build/pkgs/setuptools_scm_git_archive/SPKG.rst +++ /dev/null @@ -1,18 +0,0 @@ -setuptools_scm_git_archive: setuptools_scm plugin for git archives -================================================================== - -Description ------------ - -setuptools_scm plugin for git archives - -License -------- - -MIT - -Upstream Contact ----------------- - -https://pypi.org/project/setuptools-scm-git-archive/ - diff --git a/build/pkgs/setuptools_scm_git_archive/checksums.ini b/build/pkgs/setuptools_scm_git_archive/checksums.ini deleted file mode 100644 index ed010b0f53e..00000000000 --- a/build/pkgs/setuptools_scm_git_archive/checksums.ini +++ /dev/null @@ -1,5 +0,0 @@ -tarball=setuptools_scm_git_archive-VERSION.tar.gz -sha1=5e893fcb35f9633ea1431138c1d90a5f2687b36d -md5=df3933d33c49c5d9aca06715b4c65370 -cksum=2554004806 -upstream_url=https://pypi.io/packages/source/s/setuptools_scm_git_archive/setuptools_scm_git_archive-VERSION.tar.gz diff --git a/build/pkgs/setuptools_scm_git_archive/dependencies b/build/pkgs/setuptools_scm_git_archive/dependencies deleted file mode 100644 index 0738c2d7777..00000000000 --- a/build/pkgs/setuptools_scm_git_archive/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/setuptools_scm_git_archive/distros/alpine.txt b/build/pkgs/setuptools_scm_git_archive/distros/alpine.txt new file mode 100644 index 00000000000..c08bc88e16c --- /dev/null +++ b/build/pkgs/setuptools_scm_git_archive/distros/alpine.txt @@ -0,0 +1 @@ +py3-setuptools-scm-git-archive diff --git a/build/pkgs/setuptools_scm_git_archive/distros/arch.txt b/build/pkgs/setuptools_scm_git_archive/distros/arch.txt new file mode 100644 index 00000000000..bc2a39f97a3 --- /dev/null +++ b/build/pkgs/setuptools_scm_git_archive/distros/arch.txt @@ -0,0 +1 @@ +python-setuptools-scm-git-archive diff --git a/build/pkgs/setuptools_scm_git_archive/install-requires.txt b/build/pkgs/setuptools_scm_git_archive/distros/debian.txt similarity index 100% rename from build/pkgs/setuptools_scm_git_archive/install-requires.txt rename to build/pkgs/setuptools_scm_git_archive/distros/debian.txt diff --git a/build/pkgs/setuptools_scm_git_archive/distros/fedora.txt b/build/pkgs/setuptools_scm_git_archive/distros/fedora.txt new file mode 100644 index 00000000000..ada37357769 --- /dev/null +++ b/build/pkgs/setuptools_scm_git_archive/distros/fedora.txt @@ -0,0 +1 @@ +python-setuptools_scm_git_archive diff --git a/build/pkgs/setuptools_scm_git_archive/distros/freebsd.txt b/build/pkgs/setuptools_scm_git_archive/distros/freebsd.txt new file mode 100644 index 00000000000..2ace76a2af0 --- /dev/null +++ b/build/pkgs/setuptools_scm_git_archive/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-setuptools_scm_git_archive diff --git a/build/pkgs/setuptools_scm_git_archive/distros/gentoo.txt b/build/pkgs/setuptools_scm_git_archive/distros/gentoo.txt new file mode 100644 index 00000000000..fb7388e3dd7 --- /dev/null +++ b/build/pkgs/setuptools_scm_git_archive/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/setuptools_scm_git_archive diff --git a/build/pkgs/setuptools_scm_git_archive/package-version.txt b/build/pkgs/setuptools_scm_git_archive/package-version.txt deleted file mode 100644 index c068b2447cc..00000000000 --- a/build/pkgs/setuptools_scm_git_archive/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -1.4 diff --git a/build/pkgs/setuptools_scm_git_archive/spkg-configure.m4 b/build/pkgs/setuptools_scm_git_archive/spkg-configure.m4 new file mode 100644 index 00000000000..0da3db40d22 --- /dev/null +++ b/build/pkgs/setuptools_scm_git_archive/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([setuptools_scm_git_archive], [SAGE_PYTHON_PACKAGE_CHECK([setuptools_scm_git_archive])]) diff --git a/build/pkgs/setuptools_scm_git_archive/spkg-install.in b/build/pkgs/setuptools_scm_git_archive/spkg-install.in deleted file mode 100644 index 37ac1a53437..00000000000 --- a/build/pkgs/setuptools_scm_git_archive/spkg-install.in +++ /dev/null @@ -1,2 +0,0 @@ -cd src -sdh_pip_install . diff --git a/build/pkgs/setuptools_wheel/dependencies b/build/pkgs/setuptools_wheel/dependencies index 618d627629a..dac3579f7e3 100644 --- a/build/pkgs/setuptools_wheel/dependencies +++ b/build/pkgs/setuptools_wheel/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) setuptools wheel + setuptools wheel | $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/setuptools_wheel/install-requires.txt b/build/pkgs/setuptools_wheel/install-requires.txt index d1dc532ceab..d3767a68c8f 100644 --- a/build/pkgs/setuptools_wheel/install-requires.txt +++ b/build/pkgs/setuptools_wheel/install-requires.txt @@ -1 +1 @@ -# We use this file to mark the package as a Python package +setuptools >= 65.6 diff --git a/build/pkgs/setuptools_wheel/spkg-configure.m4 b/build/pkgs/setuptools_wheel/spkg-configure.m4 new file mode 100644 index 00000000000..db71392a8b0 --- /dev/null +++ b/build/pkgs/setuptools_wheel/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([setuptools_wheel], [SAGE_PYTHON_PACKAGE_CHECK([setuptools_wheel])]) diff --git a/build/pkgs/simplegeneric/SPKG.rst b/build/pkgs/simplegeneric/SPKG.rst deleted file mode 100644 index 24fd4c59a1a..00000000000 --- a/build/pkgs/simplegeneric/SPKG.rst +++ /dev/null @@ -1,28 +0,0 @@ -simplegeneric: Simple single-dispatch generic functions for Python -================================================================== - -Description ------------ - -Simple generic functions (similar to Python's own len(), pickle.dump(), -etc.) - -The simplegeneric module lets you define simple single-dispatch generic -functions, akin to Python's built-in generic functions like len() iter() -and so on. However, instead of using specially-named methods, these -generic functions use simple lookup tables, akin to those used by e.g. -pickle.dump() and other generic functions found in the Python standard -library. - -As you can see from the above examples, generic functions are actually -quite common in Python already, but there is no standard way to create -simple ones. This library attempts to fill that gap, as generic -functions are an excellent alternative to the Visitor pattern, as well -as being a great substitute for most common uses of adaptation. - -This library tries to be the simplest possible implementation of generic -functions, and it therefore eschews the use of multiple or predicate -dispatch, as well as avoiding speedup techniques such as C dispatching -or code generation. But it has absolutely no dependencies, other than -Python 2.4, and the implementation is just a single Python module of -less than 100 lines. diff --git a/build/pkgs/simplegeneric/checksums.ini b/build/pkgs/simplegeneric/checksums.ini deleted file mode 100644 index 77e7d78ec0a..00000000000 --- a/build/pkgs/simplegeneric/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=simplegeneric-VERSION.tar.bz2 -sha1=b736091e8cfe97bd9dfbbf56e3ee0579b5e5ffaf -md5=b804806ff347bec45fe8ad0f642537e6 -cksum=3156769418 diff --git a/build/pkgs/simplegeneric/dependencies b/build/pkgs/simplegeneric/dependencies deleted file mode 100644 index 703d0ec7ba3..00000000000 --- a/build/pkgs/simplegeneric/dependencies +++ /dev/null @@ -1,9 +0,0 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) - -# simplegeneric does not strictly require setuptools, but it does try -# to use setuptools if it is available. However, there is a problem -# when setuptools is partially installed in a parallel build, see -# Trac #19648. Adding the dependency avoids this problem. - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/simplegeneric/distros/conda.txt b/build/pkgs/simplegeneric/distros/conda.txt deleted file mode 100644 index ec4d5980052..00000000000 --- a/build/pkgs/simplegeneric/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -simplegeneric diff --git a/build/pkgs/simplegeneric/distros/macports.txt b/build/pkgs/simplegeneric/distros/macports.txt deleted file mode 100644 index e1ab5cbfea5..00000000000 --- a/build/pkgs/simplegeneric/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -py-simplegeneric diff --git a/build/pkgs/simplegeneric/distros/opensuse.txt b/build/pkgs/simplegeneric/distros/opensuse.txt deleted file mode 100644 index d788a7233a7..00000000000 --- a/build/pkgs/simplegeneric/distros/opensuse.txt +++ /dev/null @@ -1 +0,0 @@ -python3-simplegeneric diff --git a/build/pkgs/simplegeneric/distros/repology.txt b/build/pkgs/simplegeneric/distros/repology.txt deleted file mode 100644 index 52baf78b41b..00000000000 --- a/build/pkgs/simplegeneric/distros/repology.txt +++ /dev/null @@ -1,2 +0,0 @@ -simplegeneric -python:simplegeneric diff --git a/build/pkgs/simplegeneric/distros/void.txt b/build/pkgs/simplegeneric/distros/void.txt deleted file mode 100644 index d788a7233a7..00000000000 --- a/build/pkgs/simplegeneric/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -python3-simplegeneric diff --git a/build/pkgs/simplegeneric/install-requires.txt b/build/pkgs/simplegeneric/install-requires.txt deleted file mode 100644 index 0e30d0f896b..00000000000 --- a/build/pkgs/simplegeneric/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -simplegeneric >=0.8.1 diff --git a/build/pkgs/simplegeneric/package-version.txt b/build/pkgs/simplegeneric/package-version.txt deleted file mode 100644 index 25329dc9cba..00000000000 --- a/build/pkgs/simplegeneric/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -0.8.1.p0 diff --git a/build/pkgs/simplegeneric/spkg-install.in b/build/pkgs/simplegeneric/spkg-install.in deleted file mode 100644 index deba1bb42bb..00000000000 --- a/build/pkgs/simplegeneric/spkg-install.in +++ /dev/null @@ -1 +0,0 @@ -cd src && sdh_pip_install . diff --git a/build/pkgs/singular/checksums.ini b/build/pkgs/singular/checksums.ini index 313463d2fea..1101fc55700 100644 --- a/build/pkgs/singular/checksums.ini +++ b/build/pkgs/singular/checksums.ini @@ -1,5 +1,5 @@ tarball=singular-VERSION.tar.gz -sha1=28bb3ee97ef48d04dfa96de182fd93eebe08426c -md5=fc0a4f5720dadba45a52ee94324ce00c -cksum=1573851737 -upstream_url=ftp://jim.mathematik.uni-kl.de/pub/Math/Singular/SOURCES/4-3-1/singular-VERSION.tar.gz +sha1=df1997f412580f2073295aba569bb955ad227317 +md5=50349213e206a18cdaa1bc410dde7ea4 +cksum=376854707 +upstream_url=ftp://jim.mathematik.uni-kl.de/pub/Math/Singular/SOURCES/4-3-2/singular-VERSION.tar.gz diff --git a/build/pkgs/singular/package-version.txt b/build/pkgs/singular/package-version.txt index 66e2bede53a..9f1bf008217 100644 --- a/build/pkgs/singular/package-version.txt +++ b/build/pkgs/singular/package-version.txt @@ -1 +1 @@ -4.3.1p3 +4.3.2p7 diff --git a/build/pkgs/singular/spkg-configure.m4 b/build/pkgs/singular/spkg-configure.m4 index d4d145defe3..d0310c459fb 100644 --- a/build/pkgs/singular/spkg-configure.m4 +++ b/build/pkgs/singular/spkg-configure.m4 @@ -6,78 +6,31 @@ SAGE_SPKG_CONFIGURE([singular], [ AS_IF([test -z "${SINGULAR_BIN}"], [sage_spkg_install_singular=yes], [ dnl Use pkg-config to ensure that Singular is new enough. PKG_CHECK_MODULES([SINGULAR], [Singular >= 4.2.1], [ - AC_MSG_CHECKING([that Singular's help is working]) - AS_IF([test x`printf "system(\"--browser\", \"builtin\"); \n help;" | Singular 2>&1 | grep "error occurred"` = x], [ - AC_MSG_RESULT(yes) - dnl We have Singular. Now determine the shared library path on - dnl platforms on which sage.libs.singular needs to reload the library with RTLD_GLOBAL. - AS_CASE([$host_os], - [cygwin*], [dnl Nothing to do - ], - [dnl Use pkg-config to get singular's libdir while we're at it. As a - dnl moral compromise for using pkg-config, this ultimately allows us - dnl to pass an absolute path to dlopen(), which is the only approach - dnl that POSIX guarantees will work. - PKG_CHECK_VAR([SINGULAR_LIB_DIR], [Singular], [libdir]) - dnl The acl_shlibext variable is set in the top-level configure.ac. - AC_LANG_PUSH(C) - ORIG_LIBS="${LIBS}" - LIBS="${LIBS} -ldl" - AC_MSG_CHECKING([if we can dlopen($LIBSINGULAR_PATH)]) - LIBSINGULAR_PATH="${SINGULAR_LIB_DIR}/libSingular.${acl_shlibext}" - - dnl if we can dlopen() it, substitute the name for sage_conf; - dnl otherwise, fall back to using the SPKG. - AC_RUN_IFELSE( - [AC_LANG_PROGRAM( - [[#include <dlfcn.h>]], - [[void* h = dlopen("${LIBSINGULAR_PATH}", RTLD_LAZY | RTLD_GLOBAL); - if (h == 0) { return 1; } else { return dlclose(h); }]] - )], [ - AC_MSG_RESULT(yes) - ], [ - dnl try Debian-specific name - LIBSINGULAR_PATH="${SINGULAR_LIB_DIR}/libsingular-Singular.${acl_shlibext}" - AC_RUN_IFELSE( - [AC_LANG_PROGRAM( - [[#include <dlfcn.h>]], - [[void* h = dlopen("${LIBSINGULAR_PATH}", RTLD_LAZY | RTLD_GLOBAL); - if (h == 0) { return 1; } else { return dlclose(h); }]] - )], [ - AC_MSG_RESULT(yes) - ], [ - AC_MSG_RESULT(no) - sage_spkg_install_singular=yes - ], [AC_MSG_RESULT(yes)]) - ], [AC_MSG_RESULT(yes)]) - - AC_LANG_POP() - LIBS="${ORIG_LIBS}" - ] - )], [ - AC_MSG_RESULT(no) - sage_spkg_install_singular=yes - ] - )], [ + AC_MSG_CHECKING([whether Singular is built with FLINT]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #include <singular/singularconfig.h> + #if !defined(HAVE_FLINT) + # error "Need Singular compiled with FLINT" + #endif + ], []) + ], [ + AC_MSG_RESULT([yes]) + AC_MSG_CHECKING([that Singular's help is working]) + AS_IF([test x`printf "system(\"--browser\", \"builtin\"); \n help;" | Singular 2>&1 | grep "error occurred"` = x], [ + AC_MSG_RESULT(yes) + ], [ + AC_MSG_RESULT(no) + sage_spkg_install_singular=yes + ]) + ], [ + AC_MSG_RESULT([no]) + sage_spkg_install_singular=yes + ]) + ], [ dnl pkg-config version check failed sage_spkg_install_singular=yes ]) ]) ]) -],[],[],[ - dnl Post-check phase - dnl We make the sage_conf substitutions here, because the "default" - dnl substitution needs to be made even if we skipped the system-Singular - dnl checks themselves. - AS_IF([test "x${sage_spkg_install_singular}" = "xyes"], [ - AS_CASE([$host_os], - [cygwin*], [dnl Nothing to do - ], - [dnl Set shared library path, needed for reloading the library with RTLD_GLOBAL - LIBSINGULAR_PATH="\$SAGE_LOCAL/lib/libSingular.${acl_shlibext}" - ] - ) - ]) - - AC_SUBST(LIBSINGULAR_PATH, "${LIBSINGULAR_PATH}") ]) diff --git a/build/pkgs/singular_jupyter/dependencies b/build/pkgs/singular_jupyter/dependencies index 14dc06f7076..dc15abb82c7 100644 --- a/build/pkgs/singular_jupyter/dependencies +++ b/build/pkgs/singular_jupyter/dependencies @@ -1 +1 @@ -$(PYTHON) jupyter_client | $(PYTHON_TOOLCHAIN) pysingular ipython ipywidgets + jupyter_client | $(PYTHON_TOOLCHAIN) pysingular ipython ipywidgets $(PYTHON) diff --git a/build/pkgs/six/dependencies b/build/pkgs/six/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/six/dependencies +++ b/build/pkgs/six/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/six/distros/arch.txt b/build/pkgs/six/distros/arch.txt new file mode 100644 index 00000000000..787c5308ea4 --- /dev/null +++ b/build/pkgs/six/distros/arch.txt @@ -0,0 +1 @@ +python-six diff --git a/build/pkgs/six/distros/debian.txt b/build/pkgs/six/distros/debian.txt new file mode 100644 index 00000000000..68ff8595d0b --- /dev/null +++ b/build/pkgs/six/distros/debian.txt @@ -0,0 +1 @@ +python3-six diff --git a/build/pkgs/six/distros/fedora.txt b/build/pkgs/six/distros/fedora.txt new file mode 100644 index 00000000000..787c5308ea4 --- /dev/null +++ b/build/pkgs/six/distros/fedora.txt @@ -0,0 +1 @@ +python-six diff --git a/build/pkgs/six/distros/gentoo.txt b/build/pkgs/six/distros/gentoo.txt new file mode 100644 index 00000000000..f73f648ff75 --- /dev/null +++ b/build/pkgs/six/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/six diff --git a/build/pkgs/six/distros/opensuse.txt b/build/pkgs/six/distros/opensuse.txt index 68ff8595d0b..127cfc6a26a 100644 --- a/build/pkgs/six/distros/opensuse.txt +++ b/build/pkgs/six/distros/opensuse.txt @@ -1 +1 @@ -python3-six +python3${PYTHON_MINOR}-six diff --git a/build/pkgs/six/spkg-configure.m4 b/build/pkgs/six/spkg-configure.m4 new file mode 100644 index 00000000000..a382b81a3dd --- /dev/null +++ b/build/pkgs/six/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([six], [SAGE_PYTHON_PACKAGE_CHECK([six])]) diff --git a/build/pkgs/slabbe/dependencies b/build/pkgs/slabbe/dependencies index 05ba0d8954b..126e8ceee06 100644 --- a/build/pkgs/slabbe/dependencies +++ b/build/pkgs/slabbe/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) $(SAGERUNTIME) + | $(PYTHON_TOOLCHAIN) $(SAGERUNTIME) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/snappy/dependencies b/build/pkgs/snappy/dependencies index db96ccc42e0..ceaf757887e 100644 --- a/build/pkgs/snappy/dependencies +++ b/build/pkgs/snappy/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) decorator ipython cypari | $(PYTHON_TOOLCHAIN) sagelib + decorator ipython cypari | $(PYTHON_TOOLCHAIN) sagelib $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/snowballstemmer/dependencies b/build/pkgs/snowballstemmer/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/snowballstemmer/dependencies +++ b/build/pkgs/snowballstemmer/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/snowballstemmer/distros/gentoo.txt b/build/pkgs/snowballstemmer/distros/gentoo.txt new file mode 100644 index 00000000000..63fd8513221 --- /dev/null +++ b/build/pkgs/snowballstemmer/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/snowballstemmer diff --git a/build/pkgs/snowballstemmer/distros/opensuse.txt b/build/pkgs/snowballstemmer/distros/opensuse.txt index 09b2636df60..a21cc876a24 100644 --- a/build/pkgs/snowballstemmer/distros/opensuse.txt +++ b/build/pkgs/snowballstemmer/distros/opensuse.txt @@ -1 +1 @@ -python3-snowballstemmer +python3${PYTHON_MINOR}-snowballstemmer diff --git a/build/pkgs/snowballstemmer/spkg-configure.m4 b/build/pkgs/snowballstemmer/spkg-configure.m4 new file mode 100644 index 00000000000..6aa08825d39 --- /dev/null +++ b/build/pkgs/snowballstemmer/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([snowballstemmer], [ + SAGE_PYTHON_PACKAGE_CHECK([snowballstemmer]) +]) diff --git a/build/pkgs/soupsieve/dependencies b/build/pkgs/soupsieve/dependencies index 8cd44d06682..cfb7c484697 100644 --- a/build/pkgs/soupsieve/dependencies +++ b/build/pkgs/soupsieve/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) hatchling + | $(PYTHON_TOOLCHAIN) hatchling $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinx/dependencies b/build/pkgs/sphinx/dependencies index 75c668d9c23..9b7505c9aec 100644 --- a/build/pkgs/sphinx/dependencies +++ b/build/pkgs/sphinx/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) docutils jinja2 pygments snowballstemmer imagesize babel alabaster requests sphinxcontrib_websupport sphinxcontrib_applehelp sphinxcontrib_devhelp sphinxcontrib_htmlhelp sphinxcontrib_jsmath sphinxcontrib_qthelp sphinxcontrib_serializinghtml packaging importlib_metadata + | $(PYTHON_TOOLCHAIN) docutils jinja2 pygments snowballstemmer imagesize babel alabaster requests sphinxcontrib_websupport sphinxcontrib_applehelp sphinxcontrib_devhelp sphinxcontrib_htmlhelp sphinxcontrib_jsmath sphinxcontrib_qthelp sphinxcontrib_serializinghtml packaging importlib_metadata $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinx/distros/arch.txt b/build/pkgs/sphinx/distros/arch.txt new file mode 100644 index 00000000000..db9f745da4c --- /dev/null +++ b/build/pkgs/sphinx/distros/arch.txt @@ -0,0 +1 @@ +python-sphinx diff --git a/build/pkgs/sphinx/distros/conda.txt b/build/pkgs/sphinx/distros/conda.txt index 6966869c705..596885d6456 100644 --- a/build/pkgs/sphinx/distros/conda.txt +++ b/build/pkgs/sphinx/distros/conda.txt @@ -1 +1 @@ -sphinx +sphinx<8,>=5.2 diff --git a/build/pkgs/sphinx/distros/debian.txt b/build/pkgs/sphinx/distros/debian.txt new file mode 100644 index 00000000000..6966869c705 --- /dev/null +++ b/build/pkgs/sphinx/distros/debian.txt @@ -0,0 +1 @@ +sphinx diff --git a/build/pkgs/sphinx/distros/fedora.txt b/build/pkgs/sphinx/distros/fedora.txt new file mode 100644 index 00000000000..db9f745da4c --- /dev/null +++ b/build/pkgs/sphinx/distros/fedora.txt @@ -0,0 +1 @@ +python-sphinx diff --git a/build/pkgs/sphinx/distros/freebsd.txt b/build/pkgs/sphinx/distros/freebsd.txt new file mode 100644 index 00000000000..f7f30dba25f --- /dev/null +++ b/build/pkgs/sphinx/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-sphinx diff --git a/build/pkgs/sphinx/distros/opensuse.txt b/build/pkgs/sphinx/distros/opensuse.txt index bc54d0bd553..0aa0566b066 100644 --- a/build/pkgs/sphinx/distros/opensuse.txt +++ b/build/pkgs/sphinx/distros/opensuse.txt @@ -1 +1 @@ -python3-Sphinx +python3${PYTHON_MINOR}-Sphinx diff --git a/build/pkgs/sphinx/install-requires.txt b/build/pkgs/sphinx/install-requires.txt index 16e1ac533d9..9003fdec2f8 100644 --- a/build/pkgs/sphinx/install-requires.txt +++ b/build/pkgs/sphinx/install-requires.txt @@ -1 +1 @@ -sphinx >=5.2, <6 +sphinx >=5.2, <8 diff --git a/build/pkgs/sphinx/spkg-configure.m4 b/build/pkgs/sphinx/spkg-configure.m4 new file mode 100644 index 00000000000..6376e00a02d --- /dev/null +++ b/build/pkgs/sphinx/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([sphinx], [ + SAGE_PYTHON_PACKAGE_CHECK([sphinx]) +]) diff --git a/build/pkgs/sphinx_basic_ng/dependencies b/build/pkgs/sphinx_basic_ng/dependencies index 175a793ecbc..ac849c62bf6 100644 --- a/build/pkgs/sphinx_basic_ng/dependencies +++ b/build/pkgs/sphinx_basic_ng/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) sphinx | $(PYTHON_TOOLCHAIN) + sphinx | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinx_basic_ng/distros/arch.txt b/build/pkgs/sphinx_basic_ng/distros/arch.txt new file mode 100644 index 00000000000..de43e3bfd58 --- /dev/null +++ b/build/pkgs/sphinx_basic_ng/distros/arch.txt @@ -0,0 +1 @@ +python-sphinx-basic-ng diff --git a/build/pkgs/sphinx_basic_ng/distros/conda.txt b/build/pkgs/sphinx_basic_ng/distros/conda.txt new file mode 100644 index 00000000000..c11d80ea377 --- /dev/null +++ b/build/pkgs/sphinx_basic_ng/distros/conda.txt @@ -0,0 +1 @@ +sphinx-basic-ng diff --git a/build/pkgs/sphinx_basic_ng/distros/debian.txt b/build/pkgs/sphinx_basic_ng/distros/debian.txt new file mode 100644 index 00000000000..c11d80ea377 --- /dev/null +++ b/build/pkgs/sphinx_basic_ng/distros/debian.txt @@ -0,0 +1 @@ +sphinx-basic-ng diff --git a/build/pkgs/sphinx_basic_ng/distros/fedora.txt b/build/pkgs/sphinx_basic_ng/distros/fedora.txt new file mode 100644 index 00000000000..de43e3bfd58 --- /dev/null +++ b/build/pkgs/sphinx_basic_ng/distros/fedora.txt @@ -0,0 +1 @@ +python-sphinx-basic-ng diff --git a/build/pkgs/sphinx_basic_ng/distros/freebsd.txt b/build/pkgs/sphinx_basic_ng/distros/freebsd.txt new file mode 100644 index 00000000000..1d0b5ec22b4 --- /dev/null +++ b/build/pkgs/sphinx_basic_ng/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-sphinx-basic-ng diff --git a/build/pkgs/sphinx_basic_ng/distros/gentoo.txt b/build/pkgs/sphinx_basic_ng/distros/gentoo.txt new file mode 100644 index 00000000000..8b7a20a21ea --- /dev/null +++ b/build/pkgs/sphinx_basic_ng/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/sphinx-basic-ng diff --git a/build/pkgs/sphinx_basic_ng/spkg-configure.m4 b/build/pkgs/sphinx_basic_ng/spkg-configure.m4 new file mode 100644 index 00000000000..9400cc485e1 --- /dev/null +++ b/build/pkgs/sphinx_basic_ng/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([sphinx_basic_ng], [ + SAGE_PYTHON_PACKAGE_CHECK([sphinx_basic_ng]) +]) diff --git a/build/pkgs/sphinx_copybutton/SPKG.rst b/build/pkgs/sphinx_copybutton/SPKG.rst new file mode 100644 index 00000000000..2a4d04e7bbf --- /dev/null +++ b/build/pkgs/sphinx_copybutton/SPKG.rst @@ -0,0 +1,18 @@ +sphinx_copybutton: Add a copy button to each of your code cells. +================================================================ + +Description +----------- + +Add a copy button to each of your code cells. + +License +------- + +MIT License + +Upstream Contact +---------------- + +https://pypi.org/project/sphinx-copybutton/ + diff --git a/build/pkgs/sphinx_copybutton/checksums.ini b/build/pkgs/sphinx_copybutton/checksums.ini new file mode 100644 index 00000000000..c0ed7e26d2f --- /dev/null +++ b/build/pkgs/sphinx_copybutton/checksums.ini @@ -0,0 +1,5 @@ +tarball=sphinx_copybutton-VERSION-py3-none-any.whl +sha1=329d24e382c80fbb39aba221479f3ca3f566d19c +md5=1181950a5fd59160f7ec588e805d986f +cksum=142562474 +upstream_url=https://pypi.io/packages/py3/s/sphinx_copybutton/sphinx_copybutton-VERSION-py3-none-any.whl diff --git a/build/pkgs/sphinx_copybutton/dependencies b/build/pkgs/sphinx_copybutton/dependencies new file mode 100644 index 00000000000..ac849c62bf6 --- /dev/null +++ b/build/pkgs/sphinx_copybutton/dependencies @@ -0,0 +1,4 @@ + sphinx | $(PYTHON_TOOLCHAIN) $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinx_copybutton/distros/alpine.txt b/build/pkgs/sphinx_copybutton/distros/alpine.txt new file mode 100644 index 00000000000..85cc9c14557 --- /dev/null +++ b/build/pkgs/sphinx_copybutton/distros/alpine.txt @@ -0,0 +1 @@ +py3-sphinx-copybutton diff --git a/build/pkgs/sphinx_copybutton/distros/arch.txt b/build/pkgs/sphinx_copybutton/distros/arch.txt new file mode 100644 index 00000000000..2a99b129e49 --- /dev/null +++ b/build/pkgs/sphinx_copybutton/distros/arch.txt @@ -0,0 +1 @@ +python-sphinx-copybutton diff --git a/build/pkgs/sphinx_copybutton/distros/conda.txt b/build/pkgs/sphinx_copybutton/distros/conda.txt new file mode 100644 index 00000000000..787317a2ec9 --- /dev/null +++ b/build/pkgs/sphinx_copybutton/distros/conda.txt @@ -0,0 +1 @@ +sphinx-copybutton diff --git a/build/pkgs/sphinx_copybutton/distros/fedora.txt b/build/pkgs/sphinx_copybutton/distros/fedora.txt new file mode 100644 index 00000000000..2a99b129e49 --- /dev/null +++ b/build/pkgs/sphinx_copybutton/distros/fedora.txt @@ -0,0 +1 @@ +python-sphinx-copybutton diff --git a/build/pkgs/sphinx_copybutton/distros/freebsd.txt b/build/pkgs/sphinx_copybutton/distros/freebsd.txt new file mode 100644 index 00000000000..96e72696cff --- /dev/null +++ b/build/pkgs/sphinx_copybutton/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-sphinx-copybutton diff --git a/build/pkgs/sphinx_copybutton/distros/gentoo.txt b/build/pkgs/sphinx_copybutton/distros/gentoo.txt new file mode 100644 index 00000000000..e9d93b941e9 --- /dev/null +++ b/build/pkgs/sphinx_copybutton/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/sphinx-copybutton diff --git a/build/pkgs/sphinx_copybutton/distros/void.txt b/build/pkgs/sphinx_copybutton/distros/void.txt new file mode 100644 index 00000000000..576663b4a9d --- /dev/null +++ b/build/pkgs/sphinx_copybutton/distros/void.txt @@ -0,0 +1 @@ +python3-sphinx-copybutton diff --git a/build/pkgs/sphinx_copybutton/install-requires.txt b/build/pkgs/sphinx_copybutton/install-requires.txt new file mode 100644 index 00000000000..787317a2ec9 --- /dev/null +++ b/build/pkgs/sphinx_copybutton/install-requires.txt @@ -0,0 +1 @@ +sphinx-copybutton diff --git a/build/pkgs/sphinx_copybutton/package-version.txt b/build/pkgs/sphinx_copybutton/package-version.txt new file mode 100644 index 00000000000..4b9fcbec101 --- /dev/null +++ b/build/pkgs/sphinx_copybutton/package-version.txt @@ -0,0 +1 @@ +0.5.1 diff --git a/build/pkgs/sphinx_copybutton/spkg-configure.m4 b/build/pkgs/sphinx_copybutton/spkg-configure.m4 new file mode 100644 index 00000000000..8a0d5c983af --- /dev/null +++ b/build/pkgs/sphinx_copybutton/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([sphinx_copybutton], [ + SAGE_PYTHON_PACKAGE_CHECK([sphinx_copybutton]) +]) diff --git a/build/pkgs/setuptools_scm_git_archive/type b/build/pkgs/sphinx_copybutton/type similarity index 100% rename from build/pkgs/setuptools_scm_git_archive/type rename to build/pkgs/sphinx_copybutton/type diff --git a/build/pkgs/sphinxcontrib_applehelp/dependencies b/build/pkgs/sphinxcontrib_applehelp/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/sphinxcontrib_applehelp/dependencies +++ b/build/pkgs/sphinxcontrib_applehelp/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_applehelp/distros/arch.txt b/build/pkgs/sphinxcontrib_applehelp/distros/arch.txt new file mode 100644 index 00000000000..3754baa21f5 --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/distros/arch.txt @@ -0,0 +1 @@ +python-sphinxcontrib-applehelp diff --git a/build/pkgs/sphinxcontrib_applehelp/distros/fedora.txt b/build/pkgs/sphinxcontrib_applehelp/distros/fedora.txt new file mode 100644 index 00000000000..3754baa21f5 --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/distros/fedora.txt @@ -0,0 +1 @@ +python-sphinxcontrib-applehelp diff --git a/build/pkgs/sphinxcontrib_applehelp/distros/freebsd.txt b/build/pkgs/sphinxcontrib_applehelp/distros/freebsd.txt new file mode 100644 index 00000000000..73fbc3bf7ad --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-sphinxcontrib-applehelp diff --git a/build/pkgs/sphinxcontrib_applehelp/distros/gentoo.txt b/build/pkgs/sphinxcontrib_applehelp/distros/gentoo.txt new file mode 100644 index 00000000000..66ac8da7340 --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/sphinxcontrib-applehelp diff --git a/build/pkgs/sphinxcontrib_applehelp/distros/opensuse.txt b/build/pkgs/sphinxcontrib_applehelp/distros/opensuse.txt index adedbd455f8..9d71e79f307 100644 --- a/build/pkgs/sphinxcontrib_applehelp/distros/opensuse.txt +++ b/build/pkgs/sphinxcontrib_applehelp/distros/opensuse.txt @@ -1 +1 @@ -python3-sphinxcontrib-applehelp +python3${PYTHON_MINOR}-sphinxcontrib-applehelp diff --git a/build/pkgs/sphinxcontrib_applehelp/spkg-configure.m4 b/build/pkgs/sphinxcontrib_applehelp/spkg-configure.m4 new file mode 100644 index 00000000000..e834aed8fd8 --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([sphinxcontrib_applehelp], [ + SAGE_PYTHON_PACKAGE_CHECK([sphinxcontrib_applehelp]) +]) diff --git a/build/pkgs/sphinxcontrib_devhelp/dependencies b/build/pkgs/sphinxcontrib_devhelp/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/sphinxcontrib_devhelp/dependencies +++ b/build/pkgs/sphinxcontrib_devhelp/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_devhelp/distros/arch.txt b/build/pkgs/sphinxcontrib_devhelp/distros/arch.txt new file mode 100644 index 00000000000..0b1b3e44a6b --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/distros/arch.txt @@ -0,0 +1 @@ +python-sphinxcontrib-devhelp diff --git a/build/pkgs/sphinxcontrib_devhelp/distros/fedora.txt b/build/pkgs/sphinxcontrib_devhelp/distros/fedora.txt new file mode 100644 index 00000000000..0b1b3e44a6b --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/distros/fedora.txt @@ -0,0 +1 @@ +python-sphinxcontrib-devhelp diff --git a/build/pkgs/sphinxcontrib_devhelp/distros/freebsd.txt b/build/pkgs/sphinxcontrib_devhelp/distros/freebsd.txt new file mode 100644 index 00000000000..86982bcbd27 --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-sphinxcontrib-devhelp diff --git a/build/pkgs/sphinxcontrib_devhelp/distros/gentoo.txt b/build/pkgs/sphinxcontrib_devhelp/distros/gentoo.txt new file mode 100644 index 00000000000..9b5c899a706 --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/sphinxcontrib-devhelp diff --git a/build/pkgs/sphinxcontrib_devhelp/distros/opensuse.txt b/build/pkgs/sphinxcontrib_devhelp/distros/opensuse.txt new file mode 100644 index 00000000000..95012c2425d --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-sphinxcontrib-devhelp diff --git a/build/pkgs/sphinxcontrib_devhelp/spkg-configure.m4 b/build/pkgs/sphinxcontrib_devhelp/spkg-configure.m4 new file mode 100644 index 00000000000..8728136e92e --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([sphinxcontrib_devhelp], [ + SAGE_PYTHON_PACKAGE_CHECK([sphinxcontrib_devhelp]) +]) diff --git a/build/pkgs/sphinxcontrib_htmlhelp/dependencies b/build/pkgs/sphinxcontrib_htmlhelp/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/sphinxcontrib_htmlhelp/dependencies +++ b/build/pkgs/sphinxcontrib_htmlhelp/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_htmlhelp/distros/arch.txt b/build/pkgs/sphinxcontrib_htmlhelp/distros/arch.txt new file mode 100644 index 00000000000..81390fd522f --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/distros/arch.txt @@ -0,0 +1 @@ +python-sphinxcontrib-htmlhelp diff --git a/build/pkgs/sphinxcontrib_htmlhelp/distros/fedora.txt b/build/pkgs/sphinxcontrib_htmlhelp/distros/fedora.txt new file mode 100644 index 00000000000..81390fd522f --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/distros/fedora.txt @@ -0,0 +1 @@ +python-sphinxcontrib-htmlhelp diff --git a/build/pkgs/sphinxcontrib_htmlhelp/distros/freebsd.txt b/build/pkgs/sphinxcontrib_htmlhelp/distros/freebsd.txt new file mode 100644 index 00000000000..9b97c55996b --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-sphinxcontrib-htmlhelp diff --git a/build/pkgs/sphinxcontrib_htmlhelp/distros/gentoo.txt b/build/pkgs/sphinxcontrib_htmlhelp/distros/gentoo.txt new file mode 100644 index 00000000000..e080bacf8ba --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/sphinxcontrib-htmlhelp diff --git a/build/pkgs/sphinxcontrib_htmlhelp/distros/opensuse.txt b/build/pkgs/sphinxcontrib_htmlhelp/distros/opensuse.txt new file mode 100644 index 00000000000..5859fe855bb --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-sphinxcontrib-htmlhelp diff --git a/build/pkgs/sphinxcontrib_htmlhelp/spkg-configure.m4 b/build/pkgs/sphinxcontrib_htmlhelp/spkg-configure.m4 new file mode 100644 index 00000000000..c77b003dc37 --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([sphinxcontrib_htmlhelp], [ + SAGE_PYTHON_PACKAGE_CHECK([sphinxcontrib_htmlhelp]) +]) diff --git a/build/pkgs/sphinxcontrib_jsmath/dependencies b/build/pkgs/sphinxcontrib_jsmath/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/sphinxcontrib_jsmath/dependencies +++ b/build/pkgs/sphinxcontrib_jsmath/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_jsmath/distros/arch.txt b/build/pkgs/sphinxcontrib_jsmath/distros/arch.txt new file mode 100644 index 00000000000..2b4927832ac --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/distros/arch.txt @@ -0,0 +1 @@ +python-sphinxcontrib-jsmath diff --git a/build/pkgs/sphinxcontrib_jsmath/distros/fedora.txt b/build/pkgs/sphinxcontrib_jsmath/distros/fedora.txt new file mode 100644 index 00000000000..2b4927832ac --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/distros/fedora.txt @@ -0,0 +1 @@ +python-sphinxcontrib-jsmath diff --git a/build/pkgs/sphinxcontrib_jsmath/distros/freebsd.txt b/build/pkgs/sphinxcontrib_jsmath/distros/freebsd.txt new file mode 100644 index 00000000000..78aa428cb13 --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-sphinxcontrib-jsmath diff --git a/build/pkgs/sphinxcontrib_jsmath/distros/gentoo.txt b/build/pkgs/sphinxcontrib_jsmath/distros/gentoo.txt new file mode 100644 index 00000000000..041a4710e66 --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/sphinxcontrib-jsmath diff --git a/build/pkgs/sphinxcontrib_jsmath/distros/opensuse.txt b/build/pkgs/sphinxcontrib_jsmath/distros/opensuse.txt new file mode 100644 index 00000000000..dbe478264db --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-sphinxcontrib-jsmath diff --git a/build/pkgs/sphinxcontrib_jsmath/spkg-configure.m4 b/build/pkgs/sphinxcontrib_jsmath/spkg-configure.m4 new file mode 100644 index 00000000000..e46bde2bd9d --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([sphinxcontrib_jsmath], [ + SAGE_PYTHON_PACKAGE_CHECK([sphinxcontrib_jsmath]) +]) diff --git a/build/pkgs/sphinxcontrib_qthelp/dependencies b/build/pkgs/sphinxcontrib_qthelp/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/sphinxcontrib_qthelp/dependencies +++ b/build/pkgs/sphinxcontrib_qthelp/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_qthelp/distros/arch.txt b/build/pkgs/sphinxcontrib_qthelp/distros/arch.txt new file mode 100644 index 00000000000..2c11924a5df --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/distros/arch.txt @@ -0,0 +1 @@ +python-sphinxcontrib-qthelp diff --git a/build/pkgs/sphinxcontrib_qthelp/distros/fedora.txt b/build/pkgs/sphinxcontrib_qthelp/distros/fedora.txt new file mode 100644 index 00000000000..2c11924a5df --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/distros/fedora.txt @@ -0,0 +1 @@ +python-sphinxcontrib-qthelp diff --git a/build/pkgs/sphinxcontrib_qthelp/distros/freebsd.txt b/build/pkgs/sphinxcontrib_qthelp/distros/freebsd.txt new file mode 100644 index 00000000000..77ff8756694 --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-sphinxcontrib-qthelp diff --git a/build/pkgs/sphinxcontrib_qthelp/distros/gentoo.txt b/build/pkgs/sphinxcontrib_qthelp/distros/gentoo.txt new file mode 100644 index 00000000000..7210099b087 --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/sphinxcontrib-qthelp diff --git a/build/pkgs/sphinxcontrib_qthelp/distros/opensuse.txt b/build/pkgs/sphinxcontrib_qthelp/distros/opensuse.txt new file mode 100644 index 00000000000..9462502bae5 --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-sphinxcontrib-qthelp diff --git a/build/pkgs/sphinxcontrib_qthelp/spkg-configure.m4 b/build/pkgs/sphinxcontrib_qthelp/spkg-configure.m4 new file mode 100644 index 00000000000..81ea5e1269f --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([sphinxcontrib_qthelp], [ + SAGE_PYTHON_PACKAGE_CHECK([sphinxcontrib_qthelp]) +]) diff --git a/build/pkgs/sphinxcontrib_serializinghtml/dependencies b/build/pkgs/sphinxcontrib_serializinghtml/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/sphinxcontrib_serializinghtml/dependencies +++ b/build/pkgs/sphinxcontrib_serializinghtml/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_serializinghtml/distros/arch.txt b/build/pkgs/sphinxcontrib_serializinghtml/distros/arch.txt new file mode 100644 index 00000000000..46d22be403f --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/distros/arch.txt @@ -0,0 +1 @@ +python-sphinxcontrib-serializinghtml diff --git a/build/pkgs/sphinxcontrib_serializinghtml/distros/fedora.txt b/build/pkgs/sphinxcontrib_serializinghtml/distros/fedora.txt new file mode 100644 index 00000000000..46d22be403f --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/distros/fedora.txt @@ -0,0 +1 @@ +python-sphinxcontrib-serializinghtml diff --git a/build/pkgs/sphinxcontrib_serializinghtml/distros/freebsd.txt b/build/pkgs/sphinxcontrib_serializinghtml/distros/freebsd.txt new file mode 100644 index 00000000000..de7f59bad6e --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-sphinxcontrib-serializinghtml diff --git a/build/pkgs/sphinxcontrib_serializinghtml/distros/gentoo.txt b/build/pkgs/sphinxcontrib_serializinghtml/distros/gentoo.txt new file mode 100644 index 00000000000..38bca8f1dcb --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/sphinxcontrib-serializinghtml diff --git a/build/pkgs/sphinxcontrib_serializinghtml/distros/opensuse.txt b/build/pkgs/sphinxcontrib_serializinghtml/distros/opensuse.txt index 1a8ea8424a7..7a647e3e36a 100644 --- a/build/pkgs/sphinxcontrib_serializinghtml/distros/opensuse.txt +++ b/build/pkgs/sphinxcontrib_serializinghtml/distros/opensuse.txt @@ -1 +1 @@ -python3-sphinxcontrib-serializinghtml +python3${PYTHON_MINOR}-sphinxcontrib-serializinghtml diff --git a/build/pkgs/sphinxcontrib_serializinghtml/install-requires.txt b/build/pkgs/sphinxcontrib_serializinghtml/install-requires.txt index 98fc0654928..584fc77c6b2 100644 --- a/build/pkgs/sphinxcontrib_serializinghtml/install-requires.txt +++ b/build/pkgs/sphinxcontrib_serializinghtml/install-requires.txt @@ -1 +1 @@ -sphinxcontrib_serializinghtml >=1.1.4 +sphinxcontrib_serializinghtml >=1.1.5 diff --git a/build/pkgs/sphinxcontrib_serializinghtml/spkg-configure.m4 b/build/pkgs/sphinxcontrib_serializinghtml/spkg-configure.m4 new file mode 100644 index 00000000000..be8e62555ac --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([sphinxcontrib_serializinghtml], [ + SAGE_PYTHON_PACKAGE_CHECK([sphinxcontrib_serializinghtml]) +]) diff --git a/build/pkgs/sphinxcontrib_websupport/dependencies b/build/pkgs/sphinxcontrib_websupport/dependencies index dabbd0f750d..52be4a5ba53 100644 --- a/build/pkgs/sphinxcontrib_websupport/dependencies +++ b/build/pkgs/sphinxcontrib_websupport/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) sphinxcontrib_serializinghtml | $(PYTHON_TOOLCHAIN) + sphinxcontrib_serializinghtml | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_websupport/distros/alpine.txt b/build/pkgs/sphinxcontrib_websupport/distros/alpine.txt new file mode 100644 index 00000000000..521405d79ba --- /dev/null +++ b/build/pkgs/sphinxcontrib_websupport/distros/alpine.txt @@ -0,0 +1 @@ +py3-sphinxcontrib-websupport diff --git a/build/pkgs/sphinxcontrib_websupport/distros/arch.txt b/build/pkgs/sphinxcontrib_websupport/distros/arch.txt new file mode 100644 index 00000000000..a9a5a1a1727 --- /dev/null +++ b/build/pkgs/sphinxcontrib_websupport/distros/arch.txt @@ -0,0 +1 @@ +python-sphinxcontrib-websupport diff --git a/build/pkgs/sphinxcontrib_websupport/distros/debian.txt b/build/pkgs/sphinxcontrib_websupport/distros/debian.txt new file mode 100644 index 00000000000..141994ece36 --- /dev/null +++ b/build/pkgs/sphinxcontrib_websupport/distros/debian.txt @@ -0,0 +1 @@ +sphinxcontrib-websupport diff --git a/build/pkgs/sphinxcontrib_websupport/distros/fedora.txt b/build/pkgs/sphinxcontrib_websupport/distros/fedora.txt new file mode 100644 index 00000000000..a9a5a1a1727 --- /dev/null +++ b/build/pkgs/sphinxcontrib_websupport/distros/fedora.txt @@ -0,0 +1 @@ +python-sphinxcontrib-websupport diff --git a/build/pkgs/sphinxcontrib_websupport/distros/freebsd.txt b/build/pkgs/sphinxcontrib_websupport/distros/freebsd.txt new file mode 100644 index 00000000000..b8911943237 --- /dev/null +++ b/build/pkgs/sphinxcontrib_websupport/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-sphinxcontrib-websupport diff --git a/build/pkgs/sphinxcontrib_websupport/distros/gentoo.txt b/build/pkgs/sphinxcontrib_websupport/distros/gentoo.txt new file mode 100644 index 00000000000..8f21bafa771 --- /dev/null +++ b/build/pkgs/sphinxcontrib_websupport/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/sphinxcontrib-websupport diff --git a/build/pkgs/sphinxcontrib_websupport/distros/opensuse.txt b/build/pkgs/sphinxcontrib_websupport/distros/opensuse.txt index 2c8e8e8d34d..d01c76bd534 100644 --- a/build/pkgs/sphinxcontrib_websupport/distros/opensuse.txt +++ b/build/pkgs/sphinxcontrib_websupport/distros/opensuse.txt @@ -1 +1 @@ -python3-sphinxcontrib-websupport +python3${PYTHON_MINOR}-sphinxcontrib-websupport diff --git a/build/pkgs/sphinxcontrib_websupport/spkg-configure.m4 b/build/pkgs/sphinxcontrib_websupport/spkg-configure.m4 new file mode 100644 index 00000000000..2a27c8f5802 --- /dev/null +++ b/build/pkgs/sphinxcontrib_websupport/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([sphinxcontrib_websupport], [ + SAGE_PYTHON_PACKAGE_CHECK([sphinxcontrib_websupport]) +]) diff --git a/build/pkgs/sqlalchemy/distros/opensuse.txt b/build/pkgs/sqlalchemy/distros/opensuse.txt index 023e06b7468..0a1757fd5b3 100644 --- a/build/pkgs/sqlalchemy/distros/opensuse.txt +++ b/build/pkgs/sqlalchemy/distros/opensuse.txt @@ -1 +1 @@ -python3-SQLAlchemy +python3${PYTHON_MINOR}-SQLAlchemy diff --git a/build/pkgs/stack_data/dependencies b/build/pkgs/stack_data/dependencies index cf6aae43990..52b3edda4b5 100644 --- a/build/pkgs/stack_data/dependencies +++ b/build/pkgs/stack_data/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) executing asttokens pure_eval | $(PYTHON_TOOLCHAIN) + executing asttokens pure_eval | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/stack_data/distros/gentoo.txt b/build/pkgs/stack_data/distros/gentoo.txt new file mode 100644 index 00000000000..6f94c8c7fdc --- /dev/null +++ b/build/pkgs/stack_data/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/stack_data diff --git a/build/pkgs/stack_data/spkg-configure.m4 b/build/pkgs/stack_data/spkg-configure.m4 new file mode 100644 index 00000000000..6c1dd4cee59 --- /dev/null +++ b/build/pkgs/stack_data/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([stack_data], [ + SAGE_PYTHON_PACKAGE_CHECK([stack_data]) +]) diff --git a/build/pkgs/surface_dynamics/dependencies b/build/pkgs/surface_dynamics/dependencies index 936121d388d..d8bc8524dbb 100644 --- a/build/pkgs/surface_dynamics/dependencies +++ b/build/pkgs/surface_dynamics/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cysignals pplpy $(SAGE_SRC)/sage/rings/integer.pxd $(SAGE_SRC)/sage/ext/stdsage.pxd | $(PYTHON_TOOLCHAIN) $(SAGERUNTIME) + cysignals pplpy $(SAGE_SRC)/sage/rings/integer.pxd $(SAGE_SRC)/sage/ext/stdsage.pxd | $(PYTHON_TOOLCHAIN) $(SAGERUNTIME) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/symengine/checksums.ini b/build/pkgs/symengine/checksums.ini index 712c4eddb90..1c1813e7eea 100644 --- a/build/pkgs/symengine/checksums.ini +++ b/build/pkgs/symengine/checksums.ini @@ -1,5 +1,5 @@ tarball=symengine-VERSION.tar.gz -sha1=87a0104d8682cb2f192d8b4bf3435a514bdb6f4c -md5=967b913b365eda9fb30ecb3f1ded46f2 -cksum=2359123828 +sha1=11885879ddcd0a9ab69e36a79b93aef836d6c95d +md5=4673c85b423241ce85a9df35a7ed61bb +cksum=1344562381 upstream_url=https://github.com/symengine/symengine/releases/download/vVERSION/symengine-VERSION.tar.gz diff --git a/build/pkgs/symengine/package-version.txt b/build/pkgs/symengine/package-version.txt index 6f4eebdf6f6..571215736a6 100644 --- a/build/pkgs/symengine/package-version.txt +++ b/build/pkgs/symengine/package-version.txt @@ -1 +1 @@ -0.8.1 +0.10.1 diff --git a/build/pkgs/symengine_py/checksums.ini b/build/pkgs/symengine_py/checksums.ini index 3b0db282ffa..0235c5e9cd9 100644 --- a/build/pkgs/symengine_py/checksums.ini +++ b/build/pkgs/symengine_py/checksums.ini @@ -1,5 +1,5 @@ tarball=symengine.py-VERSION.tar.gz -sha1=16da67020baf6ab95cd517f58618fa7af1c8fc5e -md5=1c365dd039f8568b732c39fa4c9a7cf4 -cksum=3244910588 +sha1=fbbf052e66077ec51df319444b71f94114f33d9e +md5=fc5d2d7f571a880aa2e040214aed2ff0 +cksum=2535731241 upstream_url=https://github.com/symengine/symengine.py/archive/vVERSION.tar.gz diff --git a/build/pkgs/symengine_py/dependencies b/build/pkgs/symengine_py/dependencies index 0b94df79ab9..c48bcedf69c 100644 --- a/build/pkgs/symengine_py/dependencies +++ b/build/pkgs/symengine_py/dependencies @@ -1,4 +1,4 @@ -symengine $(PYTHON) | cmake cython $(PYTHON_TOOLCHAIN) +symengine | cmake cython $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/symengine_py/package-version.txt b/build/pkgs/symengine_py/package-version.txt index 25329dc9cba..78bc1abd14f 100644 --- a/build/pkgs/symengine_py/package-version.txt +++ b/build/pkgs/symengine_py/package-version.txt @@ -1 +1 @@ -0.8.1.p0 +0.10.0 diff --git a/build/pkgs/symengine_py/patches/0001-Fix-getting-string-representation-of-sage-objects.patch b/build/pkgs/symengine_py/patches/0001-Fix-getting-string-representation-of-sage-objects.patch deleted file mode 100644 index 78c71610b53..00000000000 --- a/build/pkgs/symengine_py/patches/0001-Fix-getting-string-representation-of-sage-objects.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 68c90c14ae3e779b88a513195cc89db599d10efb Mon Sep 17 00:00:00 2001 -From: Isuru Fernando <isuruf@gmail.com> -Date: Fri, 1 Oct 2021 19:25:07 -0700 -Subject: [PATCH] Fix getting string representation of sage objects - ---- - symengine/lib/pywrapper.cpp | 17 ++++++----------- - symengine/lib/symengine_wrapper.pyx | 9 ++++++--- - symengine/tests/test_sage.py | 10 +++------- - symengine/tests/test_sympy_conv.py | 1 + - 4 files changed, 16 insertions(+), 21 deletions(-) - -diff --git a/symengine/lib/pywrapper.cpp b/symengine/lib/pywrapper.cpp -index ca7b7c1..c321ea3 100644 ---- a/symengine/lib/pywrapper.cpp -+++ b/symengine/lib/pywrapper.cpp -@@ -175,17 +175,12 @@ RCP<const Number> PyNumber::eval(long bits) const { - } - - std::string PyNumber::__str__() const { -- PyObject* temp; -- std::string str; --#if PY_MAJOR_VERSION > 2 -- temp = PyUnicode_AsUTF8String(pyobject_); -- str = std::string(PyBytes_AsString(temp)); --#else -- temp = PyObject_Str(pyobject_); -- str = std::string(PyString_AsString(temp)); --#endif -- Py_XDECREF(temp); -- return str; -+ Py_ssize_t size; -+ PyObject *pystr = PyObject_Str(pyobject_); -+ const char* data = PyUnicode_AsUTF8AndSize(pystr, &size); -+ std::string result = std::string(data, size); -+ Py_XDECREF(pystr); -+ return result; - } - - // PyFunctionClass -diff --git a/symengine/lib/symengine_wrapper.pyx b/symengine/lib/symengine_wrapper.pyx -index d178afe..d18c058 100644 ---- a/symengine/lib/symengine_wrapper.pyx -+++ b/symengine/lib/symengine_wrapper.pyx -@@ -2690,7 +2690,7 @@ class FunctionSymbol(Function): - def _sage_(self): - import sage.all as sage - name = self.get_name() -- return sage.function(name, *self.args_as_sage()) -+ return sage.function(name)(*self.args_as_sage()) - - def func(self, *values): - name = self.get_name() -@@ -2711,7 +2711,7 @@ cdef rcp_const_basic pynumber_to_symengine(PyObject* o1): - - cdef PyObject* symengine_to_sage(rcp_const_basic o1): - import sage.all as sage -- t = sage.SR(c2py(o1)._sage_()) -+ t = c2py(o1)._sage_() - Py_XINCREF(<PyObject*>t) - return <PyObject*>(t) - -@@ -2765,7 +2765,10 @@ cdef class PyNumber(Number): - - def _sage_(self): - import sage.all as sage -- return sage.SR(self.pyobject()) -+ res = self.pyobject() -+ if hasattr(res, '_sage_'): -+ return res._sage_() -+ return res - - def pyobject(self): - return <object>deref(symengine.rcp_static_cast_PyNumber(self.thisptr)).get_py_object() -diff --git a/symengine/tests/test_sage.py b/symengine/tests/test_sage.py -index 3b994ab..e364bd6 100644 ---- a/symengine/tests/test_sage.py -+++ b/symengine/tests/test_sage.py -@@ -66,9 +66,9 @@ def test_sage_conversions(): - assert cos(x1)._sage_() == sage.cos(x) - assert cos(x1) == sympify(sage.cos(x)) - -- assert function_symbol('f', x1, y1)._sage_() == sage.function('f', x, y) -+ assert function_symbol('f', x1, y1)._sage_() == sage.function('f')(x, y) - assert (function_symbol('f', 2 * x1, x1 + y1).diff(x1)._sage_() == -- sage.function('f', 2 * x, x + y).diff(x)) -+ sage.function('f')(2 * x, x + y).diff(x)) - - assert LambertW(x1) == LambertW(x) - assert LambertW(x1)._sage_() == sage.lambert_w(x) -@@ -142,11 +142,7 @@ def test_sage_conversions(): - b = b + 8 - assert isinstance(b, PyNumber) - assert b._sage_() == a -- -- a = a + x -- b = b + x -- assert isinstance(b, Add) -- assert b._sage_() == a -+ assert str(a) == str(b) - - # Sage Function - e = x1 + wrap_sage_function(sage.log_gamma(x)) -diff --git a/symengine/tests/test_sympy_conv.py b/symengine/tests/test_sympy_conv.py -index 3f8b152..ee070a8 100644 ---- a/symengine/tests/test_sympy_conv.py -+++ b/symengine/tests/test_sympy_conv.py -@@ -760,6 +760,7 @@ def test_pynumber(): - assert isinstance(b, PyNumber) - assert b == a # Check equality via SymEngine - assert a == b # Check equality via SymPy -+ assert str(a) == str(b) - - a = 1 - a - b = 1 - b --- -2.7.4 - diff --git a/build/pkgs/sympy/checksums.ini b/build/pkgs/sympy/checksums.ini index f59c0083e07..72ea62bb91f 100644 --- a/build/pkgs/sympy/checksums.ini +++ b/build/pkgs/sympy/checksums.ini @@ -1,5 +1,5 @@ tarball=sympy-VERSION.tar.gz -sha1=9e75c8cafa4324f2803a6488ac713d87adf5cb64 -md5=232141d248ab4164e92c8ac59a996914 -cksum=2645245679 +sha1=604968f191e2d69053b8310066d089f73a1bd109 +md5=3e0033109352d7303ea97b9216e16645 +cksum=2437095035 upstream_url=https://github.com/sympy/sympy/releases/download/sympy-VERSION/sympy-VERSION.tar.gz diff --git a/build/pkgs/sympy/dependencies b/build/pkgs/sympy/dependencies index 24e1585f16e..6480ac46289 100644 --- a/build/pkgs/sympy/dependencies +++ b/build/pkgs/sympy/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) mpmath | $(PYTHON_TOOLCHAIN) + mpmath | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sympy/distros/arch.txt b/build/pkgs/sympy/distros/arch.txt new file mode 100644 index 00000000000..126c88afd85 --- /dev/null +++ b/build/pkgs/sympy/distros/arch.txt @@ -0,0 +1 @@ +python-sympy diff --git a/build/pkgs/sympy/distros/debian.txt b/build/pkgs/sympy/distros/debian.txt new file mode 100644 index 00000000000..db423c87ba7 --- /dev/null +++ b/build/pkgs/sympy/distros/debian.txt @@ -0,0 +1 @@ +python3-sympy diff --git a/build/pkgs/sympy/distros/fedora.txt b/build/pkgs/sympy/distros/fedora.txt new file mode 100644 index 00000000000..126c88afd85 --- /dev/null +++ b/build/pkgs/sympy/distros/fedora.txt @@ -0,0 +1 @@ +python-sympy diff --git a/build/pkgs/sympy/distros/gentoo.txt b/build/pkgs/sympy/distros/gentoo.txt new file mode 100644 index 00000000000..b5a5034c731 --- /dev/null +++ b/build/pkgs/sympy/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/sympy diff --git a/build/pkgs/sympy/distros/opensuse.txt b/build/pkgs/sympy/distros/opensuse.txt new file mode 100644 index 00000000000..bea17da35b4 --- /dev/null +++ b/build/pkgs/sympy/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-sympy diff --git a/build/pkgs/sympy/package-version.txt b/build/pkgs/sympy/package-version.txt index 720c7384c61..809bdcb851d 100644 --- a/build/pkgs/sympy/package-version.txt +++ b/build/pkgs/sympy/package-version.txt @@ -1 +1 @@ -1.11.1 +1.12 diff --git a/build/pkgs/sympy/spkg-configure.m4 b/build/pkgs/sympy/spkg-configure.m4 new file mode 100644 index 00000000000..fa0f1f54311 --- /dev/null +++ b/build/pkgs/sympy/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([sympy], [SAGE_PYTHON_PACKAGE_CHECK([sympy])]) diff --git a/build/pkgs/terminado/dependencies b/build/pkgs/terminado/dependencies index 54ec1c7c229..2138b7ccbe8 100644 --- a/build/pkgs/terminado/dependencies +++ b/build/pkgs/terminado/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) ptyprocess tornado | $(PYTHON_TOOLCHAIN) hatchling + ptyprocess tornado | $(PYTHON_TOOLCHAIN) hatchling $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/terminado/distros/gentoo.txt b/build/pkgs/terminado/distros/gentoo.txt new file mode 100644 index 00000000000..1df16f18abb --- /dev/null +++ b/build/pkgs/terminado/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/terminado diff --git a/build/pkgs/terminado/spkg-configure.m4 b/build/pkgs/terminado/spkg-configure.m4 new file mode 100644 index 00000000000..5defc2ff877 --- /dev/null +++ b/build/pkgs/terminado/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([terminado], [SAGE_PYTHON_PACKAGE_CHECK([terminado])]) diff --git a/build/pkgs/texttable/dependencies b/build/pkgs/texttable/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/texttable/dependencies +++ b/build/pkgs/texttable/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/texttable/distros/arch.txt b/build/pkgs/texttable/distros/arch.txt new file mode 100644 index 00000000000..8d1ccec8c7d --- /dev/null +++ b/build/pkgs/texttable/distros/arch.txt @@ -0,0 +1 @@ +python-texttable diff --git a/build/pkgs/texttable/distros/debian.txt b/build/pkgs/texttable/distros/debian.txt new file mode 100644 index 00000000000..8f8e7e29d7a --- /dev/null +++ b/build/pkgs/texttable/distros/debian.txt @@ -0,0 +1 @@ +python3-texttable diff --git a/build/pkgs/texttable/distros/fedora.txt b/build/pkgs/texttable/distros/fedora.txt new file mode 100644 index 00000000000..8d1ccec8c7d --- /dev/null +++ b/build/pkgs/texttable/distros/fedora.txt @@ -0,0 +1 @@ +python-texttable diff --git a/build/pkgs/texttable/distros/gentoo.txt b/build/pkgs/texttable/distros/gentoo.txt new file mode 100644 index 00000000000..b33a7a75d50 --- /dev/null +++ b/build/pkgs/texttable/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/texttable diff --git a/build/pkgs/texttable/distros/opensuse.txt b/build/pkgs/texttable/distros/opensuse.txt new file mode 100644 index 00000000000..d4959328e94 --- /dev/null +++ b/build/pkgs/texttable/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-texttable diff --git a/build/pkgs/texttable/spkg-configure.m4 b/build/pkgs/texttable/spkg-configure.m4 new file mode 100644 index 00000000000..42a3de105b5 --- /dev/null +++ b/build/pkgs/texttable/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([texttable], [SAGE_PYTHON_PACKAGE_CHECK([texttable])]) diff --git a/build/pkgs/tinycss2/dependencies b/build/pkgs/tinycss2/dependencies index 89200065387..7ebee8487db 100644 --- a/build/pkgs/tinycss2/dependencies +++ b/build/pkgs/tinycss2/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) webencodings | $(PYTHON_TOOLCHAIN) + webencodings | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/tinycss2/distros/alpine.txt b/build/pkgs/tinycss2/distros/alpine.txt new file mode 100644 index 00000000000..5e465b22439 --- /dev/null +++ b/build/pkgs/tinycss2/distros/alpine.txt @@ -0,0 +1 @@ +py3-tinycss2 diff --git a/build/pkgs/tinycss2/distros/arch.txt b/build/pkgs/tinycss2/distros/arch.txt new file mode 100644 index 00000000000..cb5becfe9eb --- /dev/null +++ b/build/pkgs/tinycss2/distros/arch.txt @@ -0,0 +1 @@ +python-tinycss2 diff --git a/build/pkgs/tinycss2/distros/debian.txt b/build/pkgs/tinycss2/distros/debian.txt new file mode 100644 index 00000000000..cb5becfe9eb --- /dev/null +++ b/build/pkgs/tinycss2/distros/debian.txt @@ -0,0 +1 @@ +python-tinycss2 diff --git a/build/pkgs/tinycss2/distros/fedora.txt b/build/pkgs/tinycss2/distros/fedora.txt new file mode 100644 index 00000000000..cb5becfe9eb --- /dev/null +++ b/build/pkgs/tinycss2/distros/fedora.txt @@ -0,0 +1 @@ +python-tinycss2 diff --git a/build/pkgs/tinycss2/distros/freebsd.txt b/build/pkgs/tinycss2/distros/freebsd.txt new file mode 100644 index 00000000000..048731bb153 --- /dev/null +++ b/build/pkgs/tinycss2/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-tinycss2 diff --git a/build/pkgs/tinycss2/distros/gentoo.txt b/build/pkgs/tinycss2/distros/gentoo.txt new file mode 100644 index 00000000000..dcfa0d16aed --- /dev/null +++ b/build/pkgs/tinycss2/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/tinycss2 diff --git a/build/pkgs/tinycss2/distros/macports.txt b/build/pkgs/tinycss2/distros/macports.txt new file mode 100644 index 00000000000..2d8350494f2 --- /dev/null +++ b/build/pkgs/tinycss2/distros/macports.txt @@ -0,0 +1 @@ +py-tinycss2 diff --git a/build/pkgs/tinycss2/distros/opensuse.txt b/build/pkgs/tinycss2/distros/opensuse.txt new file mode 100644 index 00000000000..cb5becfe9eb --- /dev/null +++ b/build/pkgs/tinycss2/distros/opensuse.txt @@ -0,0 +1 @@ +python-tinycss2 diff --git a/build/pkgs/tinycss2/distros/void.txt b/build/pkgs/tinycss2/distros/void.txt new file mode 100644 index 00000000000..a2c2cb2f4ab --- /dev/null +++ b/build/pkgs/tinycss2/distros/void.txt @@ -0,0 +1 @@ +python3-tinycss2 diff --git a/build/pkgs/tinycss2/spkg-configure.m4 b/build/pkgs/tinycss2/spkg-configure.m4 new file mode 100644 index 00000000000..a27e98eaa2a --- /dev/null +++ b/build/pkgs/tinycss2/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([tinycss2], [ + SAGE_PYTHON_PACKAGE_CHECK([tinycss2]) +]) diff --git a/build/pkgs/toml/SPKG.rst b/build/pkgs/toml/SPKG.rst deleted file mode 100644 index e1b53b8f79e..00000000000 --- a/build/pkgs/toml/SPKG.rst +++ /dev/null @@ -1,18 +0,0 @@ -toml: Python Library for Tom's Obvious, Minimal Language -======================================================== - -Description ------------ - -Python Library for Tom's Obvious, Minimal Language - -License -------- - -MIT - -Upstream Contact ----------------- - -https://pypi.org/project/toml/ - diff --git a/build/pkgs/toml/checksums.ini b/build/pkgs/toml/checksums.ini deleted file mode 100644 index 27467959676..00000000000 --- a/build/pkgs/toml/checksums.ini +++ /dev/null @@ -1,5 +0,0 @@ -tarball=toml-VERSION.tar.gz -sha1=00137fc72f31100edd1c03670081b03053b6c836 -md5=59bce5d8d67e858735ec3f399ec90253 -cksum=3015531877 -upstream_url=https://pypi.io/packages/source/t/toml/toml-VERSION.tar.gz diff --git a/build/pkgs/toml/dependencies b/build/pkgs/toml/dependencies deleted file mode 100644 index 0738c2d7777..00000000000 --- a/build/pkgs/toml/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/toml/distros/conda.txt b/build/pkgs/toml/distros/conda.txt deleted file mode 100644 index bd79a658fe7..00000000000 --- a/build/pkgs/toml/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -toml diff --git a/build/pkgs/toml/distros/void.txt b/build/pkgs/toml/distros/void.txt deleted file mode 100644 index 543e89d2a6f..00000000000 --- a/build/pkgs/toml/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -python3-toml diff --git a/build/pkgs/toml/install-requires.txt b/build/pkgs/toml/install-requires.txt deleted file mode 100644 index bd79a658fe7..00000000000 --- a/build/pkgs/toml/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -toml diff --git a/build/pkgs/toml/package-version.txt b/build/pkgs/toml/package-version.txt deleted file mode 100644 index 5eef0f10e8c..00000000000 --- a/build/pkgs/toml/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -0.10.2 diff --git a/build/pkgs/toml/spkg-configure.m4 b/build/pkgs/toml/spkg-configure.m4 deleted file mode 100644 index 0dbc722cde5..00000000000 --- a/build/pkgs/toml/spkg-configure.m4 +++ /dev/null @@ -1,7 +0,0 @@ -SAGE_SPKG_CONFIGURE([toml], [ - sage_spkg_install_toml=yes - ], [dnl REQUIRED-CHECK - AC_REQUIRE([SAGE_SPKG_CONFIGURE_TOX]) - dnl toml is only needed when we cannot use system tox. - AS_VAR_SET([SPKG_REQUIRE], [$sage_spkg_install_tox]) - ]) diff --git a/build/pkgs/toml/spkg-install.in b/build/pkgs/toml/spkg-install.in deleted file mode 100644 index 37ac1a53437..00000000000 --- a/build/pkgs/toml/spkg-install.in +++ /dev/null @@ -1,2 +0,0 @@ -cd src -sdh_pip_install . diff --git a/build/pkgs/toml/type b/build/pkgs/toml/type deleted file mode 100644 index a6a7b9cd726..00000000000 --- a/build/pkgs/toml/type +++ /dev/null @@ -1 +0,0 @@ -standard diff --git a/build/pkgs/tomli/dependencies b/build/pkgs/tomli/dependencies index 7cd1e28759d..992761d1f11 100644 --- a/build/pkgs/tomli/dependencies +++ b/build/pkgs/tomli/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | pip flit_core + | pip flit_core $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/tomli/distros/gentoo.txt b/build/pkgs/tomli/distros/gentoo.txt new file mode 100644 index 00000000000..0458e252a4d --- /dev/null +++ b/build/pkgs/tomli/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/tomli diff --git a/build/pkgs/tomli/spkg-configure.m4 b/build/pkgs/tomli/spkg-configure.m4 new file mode 100644 index 00000000000..95a8b8b84c2 --- /dev/null +++ b/build/pkgs/tomli/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([tomli], [SAGE_PYTHON_PACKAGE_CHECK([tomli])]) diff --git a/build/pkgs/tomlkit/SPKG.rst b/build/pkgs/tomlkit/SPKG.rst deleted file mode 100644 index ebb77909ba7..00000000000 --- a/build/pkgs/tomlkit/SPKG.rst +++ /dev/null @@ -1,18 +0,0 @@ -tomlkit: Style preserving TOML library -====================================== - -Description ------------ - -Style preserving TOML library - -License -------- - -MIT - -Upstream Contact ----------------- - -https://pypi.org/project/tomlkit/ - diff --git a/build/pkgs/tomlkit/checksums.ini b/build/pkgs/tomlkit/checksums.ini deleted file mode 100644 index 545bb2bc02b..00000000000 --- a/build/pkgs/tomlkit/checksums.ini +++ /dev/null @@ -1,5 +0,0 @@ -tarball=tomlkit-VERSION.tar.gz -sha1=b097f71385b3b693a41a23ecd551959faae73e0d -md5=ac33a015aa5f3f8e8e0667081b388bb7 -cksum=785586052 -upstream_url=https://pypi.io/packages/source/t/tomlkit/tomlkit-VERSION.tar.gz diff --git a/build/pkgs/tomlkit/dependencies b/build/pkgs/tomlkit/dependencies deleted file mode 100644 index 3eb5a92ef22..00000000000 --- a/build/pkgs/tomlkit/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) poetry_core - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/tomlkit/distros/conda.txt b/build/pkgs/tomlkit/distros/conda.txt deleted file mode 100644 index 8141b831035..00000000000 --- a/build/pkgs/tomlkit/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -tomlkit diff --git a/build/pkgs/tomlkit/distros/gentoo.txt b/build/pkgs/tomlkit/distros/gentoo.txt new file mode 100644 index 00000000000..afe59d9bfe2 --- /dev/null +++ b/build/pkgs/tomlkit/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/tomlkit diff --git a/build/pkgs/tomlkit/install-requires.txt b/build/pkgs/tomlkit/install-requires.txt deleted file mode 100644 index 8141b831035..00000000000 --- a/build/pkgs/tomlkit/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -tomlkit diff --git a/build/pkgs/tomlkit/package-version.txt b/build/pkgs/tomlkit/package-version.txt deleted file mode 100644 index e5cbde33e62..00000000000 --- a/build/pkgs/tomlkit/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -0.11.6 diff --git a/build/pkgs/tomlkit/spkg-configure.m4 b/build/pkgs/tomlkit/spkg-configure.m4 new file mode 100644 index 00000000000..6da571e5370 --- /dev/null +++ b/build/pkgs/tomlkit/spkg-configure.m4 @@ -0,0 +1,2 @@ +SAGE_SPKG_CONFIGURE([tomlkit], [SAGE_PYTHON_PACKAGE_CHECK([tomlkit])]) + diff --git a/build/pkgs/tomlkit/spkg-install.in b/build/pkgs/tomlkit/spkg-install.in deleted file mode 100644 index 37ac1a53437..00000000000 --- a/build/pkgs/tomlkit/spkg-install.in +++ /dev/null @@ -1,2 +0,0 @@ -cd src -sdh_pip_install . diff --git a/build/pkgs/tomlkit/type b/build/pkgs/tomlkit/type deleted file mode 100644 index a6a7b9cd726..00000000000 --- a/build/pkgs/tomlkit/type +++ /dev/null @@ -1 +0,0 @@ -standard diff --git a/build/pkgs/tornado/dependencies b/build/pkgs/tornado/dependencies index 212c6234efb..0d4701f9d71 100644 --- a/build/pkgs/tornado/dependencies +++ b/build/pkgs/tornado/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) certifi | $(PYTHON_TOOLCHAIN) + certifi | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/tornado/distros/gentoo.txt b/build/pkgs/tornado/distros/gentoo.txt new file mode 100644 index 00000000000..6ae4b9fc443 --- /dev/null +++ b/build/pkgs/tornado/distros/gentoo.txt @@ -0,0 +1 @@ +www-servers/tornado diff --git a/build/pkgs/tornado/distros/opensuse.txt b/build/pkgs/tornado/distros/opensuse.txt index 426685be95b..1f37b341221 100644 --- a/build/pkgs/tornado/distros/opensuse.txt +++ b/build/pkgs/tornado/distros/opensuse.txt @@ -1 +1 @@ -python3-tornado +python3${PYTHON_MINOR}-tornado diff --git a/build/pkgs/tornado/spkg-configure.m4 b/build/pkgs/tornado/spkg-configure.m4 new file mode 100644 index 00000000000..1ee5bc9f544 --- /dev/null +++ b/build/pkgs/tornado/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([tornado], [SAGE_PYTHON_PACKAGE_CHECK([tornado])]) diff --git a/build/pkgs/tox/checksums.ini b/build/pkgs/tox/checksums.ini index 19a159a8e4a..caf44efe123 100644 --- a/build/pkgs/tox/checksums.ini +++ b/build/pkgs/tox/checksums.ini @@ -1,5 +1,5 @@ -tarball=tox-VERSION.tar.gz -sha1=4a17b94eea345a2fb1a76106fb4d01ac9aca3569 -md5=ed4a11d13cd6a206b516c84750109602 -cksum=3144404727 -upstream_url=https://pypi.io/packages/source/t/tox/tox-VERSION.tar.gz +tarball=tox-VERSION-py3-none-any.whl +sha1=d3312285c4988d3307d3b000a8a18cfcb16aea29 +md5=127a9d3fae61a0967f14ab6d59fd118f +cksum=4147794288 +upstream_url=https://pypi.io/packages/py3/t/tox/tox-VERSION-py3-none-any.whl diff --git a/build/pkgs/tox/dependencies b/build/pkgs/tox/dependencies index 5a00a282b7d..ebec555b1e0 100644 --- a/build/pkgs/tox/dependencies +++ b/build/pkgs/tox/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) packaging six filelock pluggy py toml virtualenv importlib_metadata | $(PYTHON_TOOLCHAIN) +cachetools chardet colorama filelock packaging platformdirs pluggy pyproject_api tomli virtualenv | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/tox/install-requires.txt b/build/pkgs/tox/install-requires.txt index ffbf4099ae8..41bd756ea6b 100644 --- a/build/pkgs/tox/install-requires.txt +++ b/build/pkgs/tox/install-requires.txt @@ -1 +1,2 @@ -tox >= 3.21.4 +# see spkg-configure.m4 +tox >= 4.2.7 diff --git a/build/pkgs/tox/package-version.txt b/build/pkgs/tox/package-version.txt index 8c53120442c..d782fca8f64 100644 --- a/build/pkgs/tox/package-version.txt +++ b/build/pkgs/tox/package-version.txt @@ -1 +1 @@ -3.27.0 +4.11.1 diff --git a/build/pkgs/tox/spkg-configure.m4 b/build/pkgs/tox/spkg-configure.m4 index 7d8ade4c14b..ab69f673b5a 100644 --- a/build/pkgs/tox/spkg-configure.m4 +++ b/build/pkgs/tox/spkg-configure.m4 @@ -1,28 +1,18 @@ SAGE_SPKG_CONFIGURE([tox], [ - dnl Use non-ancient tox with full support for PEP 517. - m4_pushdef([TOX3_MIN_VERSION], [3.21.4]) dnl Early 4.0.x versions have bugs regarding complex factor conditions - m4_pushdef([TOX4_MIN_VERSION], [4.0.15]) - AC_CACHE_CHECK([for tox 3 >= ]TOX3_MIN_VERSION[ or tox 4 >= ]TOX4_MIN_VERSION, [ac_cv_path_TOX], [ + dnl [pkgenv] added in 4.2 - https://tox.wiki/en/latest/upgrading.html#packaging-configuration-and-inheritance + dnl 4.2.7 for repaired numerical factors + m4_pushdef([TOX4_MIN_VERSION], [4.2.7]) + AC_CACHE_CHECK([for tox >= ]TOX4_MIN_VERSION, [ac_cv_path_TOX], [ AC_PATH_PROGS_FEATURE_CHECK([TOX], [tox], [ - tox_version=$($ac_path_TOX --version 2> /dev/null | tail -1) - AS_IF([test -n "$tox_version"], [ - AX_COMPARE_VERSION([$tox_version], [lt], [4], [ - AX_COMPARE_VERSION([$tox_version], [ge], TOX3_MIN_VERSION, [ - ac_cv_path_TOX="$ac_path_TOX" - ac_path_TOX_found=: - ]) - ], [ - AX_COMPARE_VERSION([$tox_version], [ge], TOX4_MIN_VERSION, [ - ac_cv_path_TOX="$ac_path_TOX" - ac_path_TOX_found=: - ]) - ]) + tox_version=$($ac_path_TOX --version 2> /dev/null | tail -n 1) + AX_COMPARE_VERSION([$tox_version], [ge], TOX4_MIN_VERSION, [ + ac_cv_path_TOX="$ac_path_TOX" + ac_path_TOX_found=: ]) ]) ]) AS_IF([test -z "$ac_cv_path_TOX"], [sage_spkg_install_tox=yes]) m4_popdef([TOX4_MIN_VERSION]) - m4_popdef([TOX3_MIN_VERSION]) ]) diff --git a/build/pkgs/tox/spkg-install.in b/build/pkgs/tox/spkg-install.in deleted file mode 100644 index 37ac1a53437..00000000000 --- a/build/pkgs/tox/spkg-install.in +++ /dev/null @@ -1,2 +0,0 @@ -cd src -sdh_pip_install . diff --git a/build/pkgs/traitlets/checksums.ini b/build/pkgs/traitlets/checksums.ini index 4d90280ec63..8ca6285b9e3 100644 --- a/build/pkgs/traitlets/checksums.ini +++ b/build/pkgs/traitlets/checksums.ini @@ -1,5 +1,5 @@ tarball=traitlets-VERSION.tar.gz -sha1=cb5c3545ddad62ee6700ea0f279b3d168ac58ed9 -md5=d5f87bbea8acf897ac3e435c7b71acdc -cksum=238091586 +sha1=694fb48d89f2dcdca0d15957a23e24e340ac1567 +md5=91af43de0a2182735677875b4c8a533a +cksum=1530835442 upstream_url=https://pypi.io/packages/source/t/traitlets/traitlets-VERSION.tar.gz diff --git a/build/pkgs/traitlets/dependencies b/build/pkgs/traitlets/dependencies index df88de8f64c..85237293d1c 100644 --- a/build/pkgs/traitlets/dependencies +++ b/build/pkgs/traitlets/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) ipython_genutils decorator six hatchling + | $(PYTHON_TOOLCHAIN) ipython_genutils hatchling $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/traitlets/distros/gentoo.txt b/build/pkgs/traitlets/distros/gentoo.txt new file mode 100644 index 00000000000..46bfaab6fef --- /dev/null +++ b/build/pkgs/traitlets/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/traitlets diff --git a/build/pkgs/traitlets/distros/opensuse.txt b/build/pkgs/traitlets/distros/opensuse.txt index 93cb8375e46..f0cc6730e1f 100644 --- a/build/pkgs/traitlets/distros/opensuse.txt +++ b/build/pkgs/traitlets/distros/opensuse.txt @@ -1 +1 @@ -python3-traitlets +python3${PYTHON_MINOR}-traitlets diff --git a/build/pkgs/traitlets/package-version.txt b/build/pkgs/traitlets/package-version.txt index d50359de185..b3d91f9cfc0 100644 --- a/build/pkgs/traitlets/package-version.txt +++ b/build/pkgs/traitlets/package-version.txt @@ -1 +1 @@ -5.5.0 +5.9.0 diff --git a/build/pkgs/traitlets/spkg-configure.m4 b/build/pkgs/traitlets/spkg-configure.m4 new file mode 100644 index 00000000000..df2382b8f01 --- /dev/null +++ b/build/pkgs/traitlets/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([traitlets], [SAGE_PYTHON_PACKAGE_CHECK([traitlets])]) diff --git a/build/pkgs/trove_classifiers/SPKG.rst b/build/pkgs/trove_classifiers/SPKG.rst new file mode 100644 index 00000000000..4e1e7d08746 --- /dev/null +++ b/build/pkgs/trove_classifiers/SPKG.rst @@ -0,0 +1,16 @@ +trove_classifiers: Canonical source for classifiers on PyPI (pypi.org). +======================================================================= + +Description +----------- + +Canonical source for classifiers on PyPI (pypi.org). + +License +------- + +Upstream Contact +---------------- + +https://pypi.org/project/trove-classifiers/ + diff --git a/build/pkgs/trove_classifiers/checksums.ini b/build/pkgs/trove_classifiers/checksums.ini new file mode 100644 index 00000000000..1f04c749038 --- /dev/null +++ b/build/pkgs/trove_classifiers/checksums.ini @@ -0,0 +1,5 @@ +tarball=trove-classifiers-VERSION.tar.gz +sha1=4763a32114b3bb96dfd447404022586355c5f83f +md5=6ae148c8374d131dd18e28c22275d56a +cksum=1938191178 +upstream_url=https://pypi.io/packages/source/t/trove_classifiers/trove-classifiers-VERSION.tar.gz diff --git a/build/pkgs/trove_classifiers/dependencies b/build/pkgs/trove_classifiers/dependencies new file mode 100644 index 00000000000..2134b2a4179 --- /dev/null +++ b/build/pkgs/trove_classifiers/dependencies @@ -0,0 +1,4 @@ +$(PYTHON) calver | $(PYTHON_TOOLCHAIN) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/trove_classifiers/install-requires.txt b/build/pkgs/trove_classifiers/install-requires.txt new file mode 100644 index 00000000000..b8333e0eb25 --- /dev/null +++ b/build/pkgs/trove_classifiers/install-requires.txt @@ -0,0 +1 @@ +trove-classifiers diff --git a/build/pkgs/trove_classifiers/package-version.txt b/build/pkgs/trove_classifiers/package-version.txt new file mode 100644 index 00000000000..0497ae632a3 --- /dev/null +++ b/build/pkgs/trove_classifiers/package-version.txt @@ -0,0 +1 @@ +2023.8.7 diff --git a/build/pkgs/jupyter_packaging/spkg-install.in b/build/pkgs/trove_classifiers/spkg-install.in similarity index 100% rename from build/pkgs/jupyter_packaging/spkg-install.in rename to build/pkgs/trove_classifiers/spkg-install.in diff --git a/build/pkgs/simplegeneric/type b/build/pkgs/trove_classifiers/type similarity index 100% rename from build/pkgs/simplegeneric/type rename to build/pkgs/trove_classifiers/type diff --git a/build/pkgs/typing_extensions/checksums.ini b/build/pkgs/typing_extensions/checksums.ini index d6cbf2607c0..449824b887b 100644 --- a/build/pkgs/typing_extensions/checksums.ini +++ b/build/pkgs/typing_extensions/checksums.ini @@ -1,5 +1,5 @@ tarball=typing_extensions-VERSION.tar.gz -sha1=9dbf798784009efaef80c8198a75b2a9e519eb95 -md5=5cfcb56ea6fc4972c3600c0030f4d136 -cksum=386983249 +sha1=ef61789c91d5e9de37c5960c1e6f904e029fbba3 +md5=06e7fff4b1d51f8dc6f49b16e71de54e +cksum=3833864103 upstream_url=https://pypi.io/packages/source/t/typing_extensions/typing_extensions-VERSION.tar.gz diff --git a/build/pkgs/typing_extensions/dependencies b/build/pkgs/typing_extensions/dependencies index f8bd1ee040d..e0e94942dba 100644 --- a/build/pkgs/typing_extensions/dependencies +++ b/build/pkgs/typing_extensions/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | flit_core + | flit_core $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/typing_extensions/distros/arch.txt b/build/pkgs/typing_extensions/distros/arch.txt new file mode 100644 index 00000000000..92ad68dabc4 --- /dev/null +++ b/build/pkgs/typing_extensions/distros/arch.txt @@ -0,0 +1 @@ +python-typing_extensions diff --git a/build/pkgs/typing_extensions/distros/debian.txt b/build/pkgs/typing_extensions/distros/debian.txt new file mode 100644 index 00000000000..424ebf1a645 --- /dev/null +++ b/build/pkgs/typing_extensions/distros/debian.txt @@ -0,0 +1 @@ +python3-typing-extensions diff --git a/build/pkgs/typing_extensions/distros/fedora.txt b/build/pkgs/typing_extensions/distros/fedora.txt new file mode 100644 index 00000000000..8c13a4539ac --- /dev/null +++ b/build/pkgs/typing_extensions/distros/fedora.txt @@ -0,0 +1 @@ +python-typing-extensions diff --git a/build/pkgs/typing_extensions/distros/freebsd.txt b/build/pkgs/typing_extensions/distros/freebsd.txt new file mode 100644 index 00000000000..b4424d384df --- /dev/null +++ b/build/pkgs/typing_extensions/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-typing-extensions diff --git a/build/pkgs/typing_extensions/distros/gentoo.txt b/build/pkgs/typing_extensions/distros/gentoo.txt new file mode 100644 index 00000000000..20b3d1de123 --- /dev/null +++ b/build/pkgs/typing_extensions/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/typing-extensions diff --git a/build/pkgs/typing_extensions/distros/opensuse.txt b/build/pkgs/typing_extensions/distros/opensuse.txt new file mode 100644 index 00000000000..62a10cbbc72 --- /dev/null +++ b/build/pkgs/typing_extensions/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-typing_extensions diff --git a/build/pkgs/typing_extensions/install-requires.txt b/build/pkgs/typing_extensions/install-requires.txt index 3492fa57976..22c3dd116b6 100644 --- a/build/pkgs/typing_extensions/install-requires.txt +++ b/build/pkgs/typing_extensions/install-requires.txt @@ -1 +1,3 @@ -typing-extensions +# According to https://github.com/python/typing_extensions/blob/main/CHANGELOG.md, +# version 4.4.0 adds another Python 3.11 typing backport +typing_extensions >= 4.4.0 diff --git a/build/pkgs/typing_extensions/package-version.txt b/build/pkgs/typing_extensions/package-version.txt index fdc6698807a..7c66fca5791 100644 --- a/build/pkgs/typing_extensions/package-version.txt +++ b/build/pkgs/typing_extensions/package-version.txt @@ -1 +1 @@ -4.4.0 +4.7.1 diff --git a/build/pkgs/typing_extensions/spkg-configure.m4 b/build/pkgs/typing_extensions/spkg-configure.m4 new file mode 100644 index 00000000000..cbb75fec955 --- /dev/null +++ b/build/pkgs/typing_extensions/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([typing_extensions],[ + SAGE_PYTHON_PACKAGE_CHECK([typing_extensions]) +]) diff --git a/build/pkgs/tzdata/dependencies b/build/pkgs/tzdata/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/tzdata/dependencies +++ b/build/pkgs/tzdata/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/tzlocal/dependencies b/build/pkgs/tzlocal/dependencies index da4c8ca99cf..4e161b299ab 100644 --- a/build/pkgs/tzlocal/dependencies +++ b/build/pkgs/tzlocal/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) backports_zoneinfo pytz_deprecation_shim | $(PYTHON_TOOLCHAIN) + pytz_deprecation_shim | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/tzlocal/distros/arch.txt b/build/pkgs/tzlocal/distros/arch.txt new file mode 100644 index 00000000000..1de39af60b2 --- /dev/null +++ b/build/pkgs/tzlocal/distros/arch.txt @@ -0,0 +1 @@ +python-tzlocal diff --git a/build/pkgs/tzlocal/distros/debian.txt b/build/pkgs/tzlocal/distros/debian.txt new file mode 100644 index 00000000000..95d2d705c05 --- /dev/null +++ b/build/pkgs/tzlocal/distros/debian.txt @@ -0,0 +1 @@ +python3-tzlocal diff --git a/build/pkgs/tzlocal/distros/fedora.txt b/build/pkgs/tzlocal/distros/fedora.txt new file mode 100644 index 00000000000..1de39af60b2 --- /dev/null +++ b/build/pkgs/tzlocal/distros/fedora.txt @@ -0,0 +1 @@ +python-tzlocal diff --git a/build/pkgs/tzlocal/distros/freebsd.txt b/build/pkgs/tzlocal/distros/freebsd.txt new file mode 100644 index 00000000000..c42ec397d1c --- /dev/null +++ b/build/pkgs/tzlocal/distros/freebsd.txt @@ -0,0 +1 @@ +devel/py-tzlocal diff --git a/build/pkgs/tzlocal/distros/gentoo.txt b/build/pkgs/tzlocal/distros/gentoo.txt new file mode 100644 index 00000000000..2018442dcc4 --- /dev/null +++ b/build/pkgs/tzlocal/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/tzlocal diff --git a/build/pkgs/tzlocal/distros/opensuse.txt b/build/pkgs/tzlocal/distros/opensuse.txt index 95d2d705c05..2e4de5e9e49 100644 --- a/build/pkgs/tzlocal/distros/opensuse.txt +++ b/build/pkgs/tzlocal/distros/opensuse.txt @@ -1 +1 @@ -python3-tzlocal +python3${PYTHON_MINOR}-tzlocal diff --git a/build/pkgs/tzlocal/spkg-configure.m4 b/build/pkgs/tzlocal/spkg-configure.m4 new file mode 100644 index 00000000000..e020b2823f9 --- /dev/null +++ b/build/pkgs/tzlocal/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([tzlocal], [SAGE_PYTHON_PACKAGE_CHECK([tzlocal])]) diff --git a/build/pkgs/urllib3/dependencies b/build/pkgs/urllib3/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/urllib3/dependencies +++ b/build/pkgs/urllib3/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/urllib3/distros/arch.txt b/build/pkgs/urllib3/distros/arch.txt new file mode 100644 index 00000000000..af6e58664fb --- /dev/null +++ b/build/pkgs/urllib3/distros/arch.txt @@ -0,0 +1 @@ +python-urllib3 diff --git a/build/pkgs/urllib3/distros/debian.txt b/build/pkgs/urllib3/distros/debian.txt new file mode 100644 index 00000000000..918569f9677 --- /dev/null +++ b/build/pkgs/urllib3/distros/debian.txt @@ -0,0 +1 @@ +python3-urllib3 diff --git a/build/pkgs/urllib3/distros/fedora.txt b/build/pkgs/urllib3/distros/fedora.txt new file mode 100644 index 00000000000..af6e58664fb --- /dev/null +++ b/build/pkgs/urllib3/distros/fedora.txt @@ -0,0 +1 @@ +python-urllib3 diff --git a/build/pkgs/urllib3/distros/freebsd.txt b/build/pkgs/urllib3/distros/freebsd.txt new file mode 100644 index 00000000000..751c1d25c41 --- /dev/null +++ b/build/pkgs/urllib3/distros/freebsd.txt @@ -0,0 +1 @@ +net/py-urllib3 diff --git a/build/pkgs/urllib3/distros/gentoo.txt b/build/pkgs/urllib3/distros/gentoo.txt new file mode 100644 index 00000000000..172a5357dba --- /dev/null +++ b/build/pkgs/urllib3/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/urllib3 diff --git a/build/pkgs/urllib3/distros/opensuse.txt b/build/pkgs/urllib3/distros/opensuse.txt new file mode 100644 index 00000000000..7466e3c2bdd --- /dev/null +++ b/build/pkgs/urllib3/distros/opensuse.txt @@ -0,0 +1 @@ +python3${PYTHON_MINOR}-urllib3 diff --git a/build/pkgs/urllib3/spkg-configure.m4 b/build/pkgs/urllib3/spkg-configure.m4 new file mode 100644 index 00000000000..d7ef3e1661c --- /dev/null +++ b/build/pkgs/urllib3/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([urllib3], [SAGE_PYTHON_PACKAGE_CHECK([urllib3])]) diff --git a/build/pkgs/vcversioner/dependencies b/build/pkgs/vcversioner/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/vcversioner/dependencies +++ b/build/pkgs/vcversioner/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/vcversioner/distros/opensuse.txt b/build/pkgs/vcversioner/distros/opensuse.txt index 3a9b9818aa4..a9b307f8509 100644 --- a/build/pkgs/vcversioner/distros/opensuse.txt +++ b/build/pkgs/vcversioner/distros/opensuse.txt @@ -1 +1 @@ -python3-vcversioner +python3${PYTHON_MINOR}-vcversioner diff --git a/build/pkgs/virtualenv/checksums.ini b/build/pkgs/virtualenv/checksums.ini index e324ed781ee..b7def1fa7e0 100644 --- a/build/pkgs/virtualenv/checksums.ini +++ b/build/pkgs/virtualenv/checksums.ini @@ -1,5 +1,5 @@ -tarball=virtualenv-VERSION.tar.gz -sha1=8371dccb9866b40c3fdc5c0aa9c8f034cc0b174b -md5=b2d60f3c431f370b5fed5169b94f4798 -cksum=3124829245 -upstream_url=https://pypi.io/packages/source/v/virtualenv/virtualenv-VERSION.tar.gz +tarball=virtualenv-VERSION-py3-none-any.whl +sha1=a17fc6409d29b7e7b1427f37496bfc0fa399f9bf +md5=6374ee91c1ed02956a334aa01d9414ed +cksum=31593789 +upstream_url=https://pypi.io/packages/py3/v/virtualenv/virtualenv-VERSION-py3-none-any.whl diff --git a/build/pkgs/virtualenv/dependencies b/build/pkgs/virtualenv/dependencies index a8b8def7051..b0e964bba0c 100644 --- a/build/pkgs/virtualenv/dependencies +++ b/build/pkgs/virtualenv/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) appdirs distlib filelock six importlib_metadata importlib_resources platformdirs | $(PYTHON_TOOLCHAIN) +distlib filelock platformdirs | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/virtualenv/package-version.txt b/build/pkgs/virtualenv/package-version.txt index d1df974a56b..b744a5a46cb 100644 --- a/build/pkgs/virtualenv/package-version.txt +++ b/build/pkgs/virtualenv/package-version.txt @@ -1 +1 @@ -20.16.6 +20.24.4 diff --git a/build/pkgs/virtualenv/spkg-install.in b/build/pkgs/virtualenv/spkg-install.in deleted file mode 100644 index 37ac1a53437..00000000000 --- a/build/pkgs/virtualenv/spkg-install.in +++ /dev/null @@ -1,2 +0,0 @@ -cd src -sdh_pip_install . diff --git a/build/pkgs/wcwidth/dependencies b/build/pkgs/wcwidth/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/wcwidth/dependencies +++ b/build/pkgs/wcwidth/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/wcwidth/distros/gentoo.txt b/build/pkgs/wcwidth/distros/gentoo.txt new file mode 100644 index 00000000000..edeb80b62a1 --- /dev/null +++ b/build/pkgs/wcwidth/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/wcwidth diff --git a/build/pkgs/wcwidth/distros/opensuse.txt b/build/pkgs/wcwidth/distros/opensuse.txt index 2974220c878..8fea03a6c67 100644 --- a/build/pkgs/wcwidth/distros/opensuse.txt +++ b/build/pkgs/wcwidth/distros/opensuse.txt @@ -1 +1 @@ -python3-wcwidth +python3${PYTHON_MINOR}-wcwidth diff --git a/build/pkgs/wcwidth/spkg-configure.m4 b/build/pkgs/wcwidth/spkg-configure.m4 new file mode 100644 index 00000000000..5bde15af224 --- /dev/null +++ b/build/pkgs/wcwidth/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([wcwidth], [SAGE_PYTHON_PACKAGE_CHECK([wcwidth])]) diff --git a/build/pkgs/webencodings/dependencies b/build/pkgs/webencodings/dependencies index 0738c2d7777..47296a7bace 100644 --- a/build/pkgs/webencodings/dependencies +++ b/build/pkgs/webencodings/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) + | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/webencodings/distros/arch.txt b/build/pkgs/webencodings/distros/arch.txt new file mode 100644 index 00000000000..12ddba901a4 --- /dev/null +++ b/build/pkgs/webencodings/distros/arch.txt @@ -0,0 +1 @@ +python-webencodings diff --git a/build/pkgs/webencodings/distros/debian.txt b/build/pkgs/webencodings/distros/debian.txt new file mode 100644 index 00000000000..ac30c2f3307 --- /dev/null +++ b/build/pkgs/webencodings/distros/debian.txt @@ -0,0 +1 @@ +python3-webencodings diff --git a/build/pkgs/webencodings/distros/fedora.txt b/build/pkgs/webencodings/distros/fedora.txt new file mode 100644 index 00000000000..12ddba901a4 --- /dev/null +++ b/build/pkgs/webencodings/distros/fedora.txt @@ -0,0 +1 @@ +python-webencodings diff --git a/build/pkgs/webencodings/distros/gentoo.txt b/build/pkgs/webencodings/distros/gentoo.txt new file mode 100644 index 00000000000..7539b0fdcde --- /dev/null +++ b/build/pkgs/webencodings/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/webencodings diff --git a/build/pkgs/webencodings/distros/opensuse.txt b/build/pkgs/webencodings/distros/opensuse.txt index ac30c2f3307..b8d9c4d299c 100644 --- a/build/pkgs/webencodings/distros/opensuse.txt +++ b/build/pkgs/webencodings/distros/opensuse.txt @@ -1 +1 @@ -python3-webencodings +python3${PYTHON_MINOR}-webencodings diff --git a/build/pkgs/webencodings/spkg-configure.m4 b/build/pkgs/webencodings/spkg-configure.m4 new file mode 100644 index 00000000000..1b9a5c431f3 --- /dev/null +++ b/build/pkgs/webencodings/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([webencodings], [ + SAGE_PYTHON_PACKAGE_CHECK([webencodings]) +]) diff --git a/build/pkgs/wheel/dependencies b/build/pkgs/wheel/dependencies index 98d3e59447b..a8e327be793 100644 --- a/build/pkgs/wheel/dependencies +++ b/build/pkgs/wheel/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) setuptools + setuptools | $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/wheel/distros/arch.txt b/build/pkgs/wheel/distros/arch.txt new file mode 100644 index 00000000000..ae4cbb9f52f --- /dev/null +++ b/build/pkgs/wheel/distros/arch.txt @@ -0,0 +1 @@ +python-wheel diff --git a/build/pkgs/wheel/distros/debian.txt b/build/pkgs/wheel/distros/debian.txt new file mode 100644 index 00000000000..3c066725a1d --- /dev/null +++ b/build/pkgs/wheel/distros/debian.txt @@ -0,0 +1 @@ +python3-wheel diff --git a/build/pkgs/wheel/distros/fedora.txt b/build/pkgs/wheel/distros/fedora.txt new file mode 100644 index 00000000000..ae4cbb9f52f --- /dev/null +++ b/build/pkgs/wheel/distros/fedora.txt @@ -0,0 +1 @@ +python-wheel diff --git a/build/pkgs/wheel/distros/gentoo.txt b/build/pkgs/wheel/distros/gentoo.txt new file mode 100644 index 00000000000..ec571d59d93 --- /dev/null +++ b/build/pkgs/wheel/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/wheel diff --git a/build/pkgs/wheel/distros/opensuse.txt b/build/pkgs/wheel/distros/opensuse.txt index 3c066725a1d..3df335c1375 100644 --- a/build/pkgs/wheel/distros/opensuse.txt +++ b/build/pkgs/wheel/distros/opensuse.txt @@ -1 +1 @@ -python3-wheel +python3${PYTHON_MINOR}-wheel diff --git a/build/pkgs/wheel/spkg-configure.m4 b/build/pkgs/wheel/spkg-configure.m4 new file mode 100644 index 00000000000..7897ea96cc6 --- /dev/null +++ b/build/pkgs/wheel/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([wheel], [SAGE_PYTHON_PACKAGE_CHECK([wheel])]) diff --git a/build/pkgs/widgetsnbextension/SPKG.rst b/build/pkgs/widgetsnbextension/SPKG.rst index 8ebc9468f32..8788fa7c034 100644 --- a/build/pkgs/widgetsnbextension/SPKG.rst +++ b/build/pkgs/widgetsnbextension/SPKG.rst @@ -1,7 +1,18 @@ -widgetsnbextension: Jupyter notebook extension for interactive HTML widgets -=========================================================================== +widgetsnbextension: Jupyter interactive widgets for Jupyter Notebook +==================================================================== Description ----------- -Interactive HTML widgets for Jupyter notebooks. +Jupyter interactive widgets for Jupyter Notebook + +License +------- + +BSD 3-Clause License + +Upstream Contact +---------------- + +https://pypi.org/project/widgetsnbextension/ + diff --git a/build/pkgs/widgetsnbextension/checksums.ini b/build/pkgs/widgetsnbextension/checksums.ini index 2b335f09484..30e08312a8f 100644 --- a/build/pkgs/widgetsnbextension/checksums.ini +++ b/build/pkgs/widgetsnbextension/checksums.ini @@ -1,5 +1,5 @@ -tarball=widgetsnbextension-VERSION.tar.gz -sha1=21f8dc7732adad09921bf590fa0eb0d4c3dd7f48 -md5=2d44896382b3a587823e08df6d2f3165 -cksum=209268639 -upstream_url=https://pypi.io/packages/source/w/widgetsnbextension/widgetsnbextension-VERSION.tar.gz +tarball=widgetsnbextension-VERSION-py3-none-any.whl +sha1=1ffb84b17fca00a6e4bbad41f395ed6f37e1c6b9 +md5=38786a4166938b1b4165a76c244c3fc9 +cksum=2255132975 +upstream_url=https://pypi.io/packages/py3/w/widgetsnbextension/widgetsnbextension-VERSION-py3-none-any.whl diff --git a/build/pkgs/widgetsnbextension/dependencies b/build/pkgs/widgetsnbextension/dependencies index f7ff1dca568..b5af54575fc 100644 --- a/build/pkgs/widgetsnbextension/dependencies +++ b/build/pkgs/widgetsnbextension/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) jupyter_packaging | $(PYTHON_TOOLCHAIN) jupyter_core +jupyter_core | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/widgetsnbextension/install-requires.txt b/build/pkgs/widgetsnbextension/install-requires.txt index 1b446d635a2..c6d44d55e1f 100644 --- a/build/pkgs/widgetsnbextension/install-requires.txt +++ b/build/pkgs/widgetsnbextension/install-requires.txt @@ -1 +1 @@ -widgetsnbextension >=3.5.1 +widgetsnbextension diff --git a/build/pkgs/widgetsnbextension/package-version.txt b/build/pkgs/widgetsnbextension/package-version.txt index c4e41f94594..a2cec7aff41 100644 --- a/build/pkgs/widgetsnbextension/package-version.txt +++ b/build/pkgs/widgetsnbextension/package-version.txt @@ -1 +1 @@ -4.0.3 +4.0.8 diff --git a/build/pkgs/widgetsnbextension/spkg-configure.m4 b/build/pkgs/widgetsnbextension/spkg-configure.m4 new file mode 100644 index 00000000000..bf82dafe209 --- /dev/null +++ b/build/pkgs/widgetsnbextension/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([widgetsnbextension], [ + SAGE_PYTHON_PACKAGE_CHECK([widgetsnbextension]) +]) diff --git a/build/pkgs/widgetsnbextension/spkg-install.in b/build/pkgs/widgetsnbextension/spkg-install.in deleted file mode 100644 index deba1bb42bb..00000000000 --- a/build/pkgs/widgetsnbextension/spkg-install.in +++ /dev/null @@ -1 +0,0 @@ -cd src && sdh_pip_install . diff --git a/build/pkgs/zeromq/distros/arch.txt b/build/pkgs/zeromq/distros/arch.txt new file mode 100644 index 00000000000..bd4caa9e83d --- /dev/null +++ b/build/pkgs/zeromq/distros/arch.txt @@ -0,0 +1 @@ +zeromq diff --git a/build/pkgs/zeromq/distros/gentoo.txt b/build/pkgs/zeromq/distros/gentoo.txt new file mode 100644 index 00000000000..2e8ad6358d5 --- /dev/null +++ b/build/pkgs/zeromq/distros/gentoo.txt @@ -0,0 +1 @@ +net-libs/zeromq diff --git a/build/pkgs/zeromq/patches/438d5d88392baffa6c2c5e0737d9de19d6686f0d.patch b/build/pkgs/zeromq/patches/438d5d88392baffa6c2c5e0737d9de19d6686f0d.patch new file mode 100644 index 00000000000..75bfbd8744b --- /dev/null +++ b/build/pkgs/zeromq/patches/438d5d88392baffa6c2c5e0737d9de19d6686f0d.patch @@ -0,0 +1,58 @@ +From 438d5d88392baffa6c2c5e0737d9de19d6686f0d Mon Sep 17 00:00:00 2001 +From: Sergei Trofimovich <slyich@gmail.com> +Date: Tue, 20 Dec 2022 21:45:16 +0000 +Subject: [PATCH] src/secure_allocator.hpp: define missing 'rebind' type + +`gcc-13` added an assert to standard headers to make sure custom +allocators have intended implementation of rebind type instead +of inherited rebind. gcc change: + https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=64c986b49558a7 + +Without the fix build fails on this week's `gcc-13` as: + + [ 92%] Building CXX object tests/CMakeFiles/test_security_curve.dir/test_security_curve.cpp.o + In file included from /<<NIX>>/gcc-13.0.0/include/c++/13.0.0/ext/alloc_traits.h:34, + from /<<NIX>>/gcc-13.0.0/include/c++/13.0.0/bits/stl_uninitialized.h:64, + from /<<NIX>>/gcc-13.0.0/include/c++/13.0.0/memory:69, + from tests/../src/secure_allocator.hpp:42, + from tests/../src/curve_client_tools.hpp:49, + from tests/test_security_curve.cpp:53: + /<<NIX>>/gcc-13.0.0/include/c++/13.0.0/bits/alloc_traits.h: In instantiation of 'struct std::__allocator_traits_base::__rebind<zmq::secure_allocator_t<unsigned char>, unsigned char, void>': + /<<NIX>>/gcc-13.0.0/include/c++/13.0.0/bits/alloc_traits.h:94:11: required by substitution of 'template<class _Alloc, class _Up> using std::__alloc_rebind = typename std::__allocator_traits_base::__rebind<_Alloc, _Up>::type [with _Alloc = zmq::secure_allocator_t<unsigned char>; _Up = unsigned char]' + /<<NIX>>/gcc-13.0.0/include/c++/13.0.0/bits/alloc_traits.h:228:8: required by substitution of 'template<class _Alloc> template<class _Tp> using std::allocator_traits< <template-parameter-1-1> >::rebind_alloc = std::__alloc_rebind<_Alloc, _Tp> [with _Tp = unsigned char; _Alloc = zmq::secure_allocator_t<unsigned char>]' + /<<NIX>>/gcc-13.0.0/include/c++/13.0.0/ext/alloc_traits.h:126:65: required from 'struct __gnu_cxx::__alloc_traits<zmq::secure_allocator_t<unsigned char>, unsigned char>::rebind<unsigned char>' + /<<NIX>>/gcc-13.0.0/include/c++/13.0.0/bits/stl_vector.h:88:21: required from 'struct std::_Vector_base<unsigned char, zmq::secure_allocator_t<unsigned char> >' + /<<NIX>>/gcc-13.0.0/include/c++/13.0.0/bits/stl_vector.h:423:11: required from 'class std::vector<unsigned char, zmq::secure_allocator_t<unsigned char> >' + tests/../src/curve_client_tools.hpp:64:76: required from here + /<<NIX>>/gcc-13.0.0/include/c++/13.0.0/bits/alloc_traits.h:70:31: error: static assertion failed: allocator_traits<A>::rebind_alloc<A::value_type> must be A + 70 | _Tp>::value, + | ^~~~~ + +The change adds trivial `rebind` definition with expected return type +and satisfies conversion requirements. +--- + src/secure_allocator.hpp | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/secure_allocator.hpp b/src/secure_allocator.hpp +index e0871dcc99..5e97368911 100644 +--- a/src/secure_allocator.hpp ++++ b/src/secure_allocator.hpp +@@ -99,6 +99,17 @@ bool operator!= (const secure_allocator_t<T> &, const secure_allocator_t<U> &) + #else + template <typename T> struct secure_allocator_t : std::allocator<T> + { ++ secure_allocator_t () ZMQ_DEFAULT; ++ ++ template <class U> ++ secure_allocator_t (const secure_allocator_t<U> &) ZMQ_NOEXCEPT ++ { ++ } ++ ++ template <class U> struct rebind ++ { ++ typedef secure_allocator_t<U> other; ++ }; + }; + #endif + } diff --git a/build/pkgs/zipp/dependencies b/build/pkgs/zipp/dependencies index 4361e46ddaf..9be6b4aab7c 100644 --- a/build/pkgs/zipp/dependencies +++ b/build/pkgs/zipp/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) vcversioner | $(PYTHON_TOOLCHAIN) + vcversioner | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/zipp/distros/gentoo.txt b/build/pkgs/zipp/distros/gentoo.txt new file mode 100644 index 00000000000..7f59450c2b7 --- /dev/null +++ b/build/pkgs/zipp/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/zipp diff --git a/build/pkgs/zipp/spkg-configure.m4 b/build/pkgs/zipp/spkg-configure.m4 new file mode 100644 index 00000000000..0fe3a9cd224 --- /dev/null +++ b/build/pkgs/zipp/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([zipp], [SAGE_PYTHON_PACKAGE_CHECK([zipp])]) diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index c9523e8cdc7..22fb252410b 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -305,7 +305,7 @@ def create(self, package_name, version=None, tarball=None, pkg_type=None, upstre raise ValueError('Only platform-independent wheels can be used for wheel packages, got {0}'.format(tarball)) if not version: version = pypi_version.version - upstream_url = 'https://pypi.io/packages/py3/{0:1.1}/{0}/{1}'.format(package_name, tarball) + upstream_url = 'https://pypi.io/packages/{2}/{0:1.1}/{0}/{1}'.format(package_name, tarball, pypi_version.python_version) if not description: description = pypi_version.summary if not license: diff --git a/build/sage_bootstrap/creator.py b/build/sage_bootstrap/creator.py index f7a6ab203dc..c52090e5fa3 100644 --- a/build/sage_bootstrap/creator.py +++ b/build/sage_bootstrap/creator.py @@ -94,7 +94,7 @@ def set_python_data_and_scripts(self, pypi_package_name=None, source='normal'): if pypi_package_name is None: pypi_package_name = self.package_name with open(os.path.join(self.path, 'dependencies'), 'w+') as f: - f.write('$(PYTHON) | $(PYTHON_TOOLCHAIN)\n\n') + f.write(' | $(PYTHON_TOOLCHAIN) $(PYTHON)\n\n') f.write('----------\nAll lines of this file are ignored except the first.\n') if source == 'normal': with open(os.path.join(self.path, 'spkg-install.in'), 'w+') as f: diff --git a/build/sage_bootstrap/pypi.py b/build/sage_bootstrap/pypi.py index a11f3a95b46..e3ca4e560c7 100644 --- a/build/sage_bootstrap/pypi.py +++ b/build/sage_bootstrap/pypi.py @@ -69,7 +69,8 @@ def url(self): Return the source url """ for download in self.json['urls']: - if download['python_version'] == self.python_version: + if self.python_version in download['python_version']: + self.python_version = download['python_version'] return download['url'] raise PyPiError('No %s url for %s found', self.python_version, self.name) @@ -79,7 +80,8 @@ def tarball(self): Return the source tarball name """ for download in self.json['urls']: - if download['python_version'] == self.python_version: + if self.python_version in download['python_version']: + self.python_version = download['python_version'] return download['filename'] raise PyPiError('No %s url for %s found', self.python_version, self.name) diff --git a/configure.ac b/configure.ac index 0edf830c05d..62d80bc79ca 100644 --- a/configure.ac +++ b/configure.ac @@ -445,6 +445,40 @@ AC_ARG_ENABLE([download-from-upstream-url], [disallow downloading packages from their upstream URL if they cannot be found on the Sage mirrors])], [], [AS_VAR_SET([enable_download_from_upstream_url], [yes])]) +AC_ARG_ENABLE( + [system-site-packages], [AS_HELP_STRING( + [--enable-system-site-packages], + [allow the use of python packages from the system (experimental; default: no)] + )], [ + AS_IF([test "x$enable_system_site_packages" = "xyes"], [ + dnl When installing python SPKGs in the presence of system-site + dnl packages, we need to --ignore-installed so that a patched SPKG + dnl can be installed in the presence of an unpatched system package + dnl that appears (to pip) to be identical. The --no-deps flag is + dnl then needed because --ignore-installed will make any installed + dnl dependencies invisible to pip, who does not appreciate that. + SAGE_PIP_INSTALL_FLAGS="${SAGE_PIP_INSTALL_FLAGS} --no-deps --ignore-installed" + + SAGE_VENV_FLAGS="${SAGE_VENV_FLAGS} --system-site-packages" + + dnl We want to raise an error if the user asked for "system site + dnl packages" but the system python will not be used. Technically + dnl that causes no problems (SAGE_PYTHON_PACKAGE_CHECK always fails, + dnl so SPKGs are used for all python packages), but it may be confusing + dnl to end users who expect the flag to actually give them access to + dnl their system python packages and who may not be paying close + dnl attention to their ./configure output. + with_system_python3="force" + + dnl This is substituted in to build/bin/sage-build-env-config.in for use + dnl by build/bin/sage-get-system-packages + ENABLE_SYSTEM_SITE_PACKAGES=yes + ]) +]) +AC_SUBST([ENABLE_SYSTEM_SITE_PACKAGES]) +AC_SUBST([SAGE_PIP_INSTALL_FLAGS]) +AC_SUBST([SAGE_VENV_FLAGS]) + SAGE_SPKG_OPTIONS="" AS_IF([test "x$enable_experimental_packages" = "xyes"], [ AS_VAR_APPEND([SAGE_SPKG_OPTIONS], [" -y"]) @@ -473,13 +507,7 @@ AC_ARG_ENABLE([cvxopt], AC_ARG_ENABLE([notebook], AS_HELP_STRING([--disable-notebook], [disable build of the Jupyter notebook and related packages]), [ - for pkg in notebook nbconvert beautifulsoup4 sagenb_export nbformat nbclient terminado send2trash prometheus_client mistune pandocfilters bleach defusedxml jsonschema jupyter_jsmol argon2_cffi; do - AS_VAR_SET([SAGE_ENABLE_$pkg], [$enableval]) - done - ]) - -AS_IF([test "$SAGE_ENABLE_notebook" = no -a "$SAGE_ENABLE_sagelib" = no], [ - for pkg in jupyter_client ipykernel ipython zeromq pyzmq; do + for pkg in notebook nbconvert beautifulsoup4 sagenb_export nbformat nbclient terminado send2trash prometheus_client mistune pandocfilters bleach defusedxml jsonschema jupyter_jsmol argon2_cffi argon2_cffi_bindings webencodings tinycss2 ipympl soupsieve fastjsonschema; do AS_VAR_SET([SAGE_ENABLE_$pkg], [$enableval]) done ]) @@ -487,7 +515,7 @@ AS_IF([test "$SAGE_ENABLE_notebook" = no -a "$SAGE_ENABLE_sagelib" = no], [ AC_ARG_ENABLE([r], AS_HELP_STRING([--disable-r], [disable build of the R package and related packages]), [ - for pkg in r rpy2 r_jupyter pcre; do + for pkg in r rpy2 r_jupyter tzlocal pytz_deprecation_shim; do AS_VAR_SET([SAGE_ENABLE_$pkg], [$enableval]) done ]) @@ -496,7 +524,7 @@ AC_ARG_ENABLE([doc], AS_HELP_STRING([--disable-doc], [disable build of the Sage documentation and packages depending on it]), [ dnl Disable packages needed for docbuilding - for pkg in sage_docbuild alabaster babel snowballstemmer imagesize sphinx sphinxcontrib_devhelp sphinxcontrib_jsmath sphinxcontrib_serializinghtml sphinxcontrib_applehelp sphinxcontrib_htmlhelp sphinxcontrib_qthelp sphinxcontrib_websupport jupyter_sphinx furo; do + for pkg in sage_docbuild alabaster babel snowballstemmer imagesize sphinx sphinxcontrib_devhelp sphinxcontrib_jsmath sphinxcontrib_serializinghtml sphinxcontrib_applehelp sphinxcontrib_htmlhelp sphinxcontrib_qthelp sphinxcontrib_websupport jupyter_sphinx furo sphinx_copybutton mathjax sphinx_basic_ng; do AS_VAR_SET([SAGE_ENABLE_$pkg], [$enableval]) done AS_VAR_IF([enableval], [no], [dnl Disable the docbuild by disabling the install tree for documentation @@ -512,6 +540,28 @@ AC_ARG_ENABLE([sagelib], done ]) + +dnl Handle combinations of --disable-foo flags that may enable us to +dnl prune even more dependencies. +AS_IF([test "$SAGE_ENABLE_notebook" = no -a "$SAGE_ENABLE_sagelib" = no], [ + for pkg in jupyter_client ipykernel ipython zeromq pyzmq; do + AS_VAR_SET([SAGE_ENABLE_$pkg], [$enableval]) + done + ]) +AS_IF([test "$SAGE_ENABLE_r" = no -a "$SAGE_ENABLE_sage_docbuild" = no], [ + dnl pytz is needed only by rpy2 and babel, and babel is already + dnl disabled by --disable-doc. + for pkg in pytz; do + AS_VAR_SET([SAGE_ENABLE_$pkg], [$enableval]) + done +]) +AS_IF([test "$SAGE_ENABLE_r" = no -a "$SAGE_ENABLE_notebook" = no], [ + dnl These two are dependencies of both rpy2 and some notebook stuff + for pkg in cffi pycparser; do + AS_VAR_SET([SAGE_ENABLE_$pkg], [$enableval]) + done +]) + dnl Packages that require a special override to use the SPKG dnl when the system package is not usable. AS_VAR_SET([sage_use_system_gcc], [force]) diff --git a/docker/Dockerfile b/docker/Dockerfile index 9d56b10b9c5..6b0ecab4795 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -70,11 +70,12 @@ ARG ARTIFACT_BASE=source-clean +ARG MAKE_BUILD=make-build ################################################################################ # Image containing the run-time dependencies for Sage # ################################################################################ -FROM ubuntu:jammy as run-time-dependencies +FROM ubuntu:latest as run-time-dependencies LABEL maintainer="Erik M. Bray <erik.bray@lri.fr>, Julian Rรผth <julian.rueth@fsfe.org>" # Set sane defaults for common environment variables. ENV LC_ALL C.UTF-8 @@ -122,7 +123,7 @@ ARG SAGE_ROOT=/home/sage/sage RUN mkdir -p "$SAGE_ROOT" WORKDIR $SAGE_ROOT RUN git init -RUN git remote add trac https://gitlab.com/sagemath/dev/tracmirror.git +RUN git remote add upstream https://github.com/sagemath/sage.git ################################################################################ # Image with the build context added, i.e., the directory from which `docker # @@ -155,10 +156,10 @@ WORKDIR $SAGE_ROOT # We create a list of all files present in the artifact-base (with a timestamp # of now) so we can find out later which files were added/changed/removed. RUN find . \( -type f -or -type l \) > $HOME/artifact-base.manifest -RUN git fetch "$HOME/sage-context" HEAD \ +RUN git fetch --update-shallow "$HOME/sage-context" HEAD \ && if [ -e docker/.commit ]; then \ git reset `cat docker/.commit` \ - || ( echo "Could not find commit `cat docker/.commit` in your local Git history. Please merge in the latest built develop branch to fix this: git fetch trac && git merge `cat docker/.commit`." && exit 1 ) \ + || ( echo "Could not find commit `cat docker/.commit` in your local Git history. Please merge in the latest built develop branch to fix this: git fetch upstream && git merge `cat docker/.commit`." && exit 1 ) \ else \ echo "You are building from $ARTIFACT_BASE which has no docker/.commit file. That's a bug unless you are building from source-clean or something similar." \ && git reset FETCH_HEAD \ @@ -203,7 +204,7 @@ RUN make build ################################################################################ # Image with a full build of sage and its documentation. # ################################################################################ -FROM make-build as make-all +FROM $MAKE_BUILD as make-all # The docbuild needs quite some RAM (as of May 2018). It sometimes calls # os.fork() to spawn an external program which then exceeds easily the # overcommit limit of the system (no RAM is actually used, but this limit is diff --git a/m4/ax_gcc_option.m4 b/m4/ax_gcc_option.m4 index 93a4beddd32..215ff6d0956 100644 --- a/m4/ax_gcc_option.m4 +++ b/m4/ax_gcc_option.m4 @@ -8,7 +8,7 @@ # # DESCRIPTION # -# AX_GCC_OPTION checks wheter gcc accepts the passed OPTION. If it accepts +# AX_GCC_OPTION checks whether gcc accepts the passed OPTION. If it accepts # the OPTION then ACTION-IF-SUCCESSFUL will be executed, otherwise # ACTION-IF-UNSUCCESSFUL. # diff --git a/m4/ax_gxx_option.m4 b/m4/ax_gxx_option.m4 index b55cf1285f7..f7e412e7ac3 100644 --- a/m4/ax_gxx_option.m4 +++ b/m4/ax_gxx_option.m4 @@ -9,7 +9,7 @@ # # DESCRIPTION # -# AX_GCC_OPTION checks wheter gcc accepts the passed OPTION. If it accepts +# AX_GCC_OPTION checks whether gcc accepts the passed OPTION. If it accepts # the OPTION then ACTION-IF-SUCCESSFUL will be executed, otherwise # ACTION-IF-UNSUCCESSFUL. # diff --git a/m4/sage_python_package_check.m4 b/m4/sage_python_package_check.m4 new file mode 100644 index 00000000000..e0713512ea0 --- /dev/null +++ b/m4/sage_python_package_check.m4 @@ -0,0 +1,118 @@ +# +# SYNOPSIS +# +# SAGE_PYTHON_PACKAGE_CHECK(package) +# +# DESCRIPTION +# +# Determine if the system copy of a python package can be used by sage. +# +# This macro uses setuptools.version's pkg_resources to check that the +# "install-requires.txt" file for the named package is satisfied, and +# it can typically fail in four ways: +# +# 1. If --enable-system-site-packages was not passed to ./configure, +# +# 2. If we are not using the system python (no $PYTHON_FOR_VENV), +# +# 3. If we are unable to create a venv with the system python, +# +# 4. If setuptools is not available to the system python, +# +# 5. If the contents of install-requires.txt are not met (wrong +# version, no version, etc.) by the system python. +# +# In any of those cases, we set sage_spkg_install_$package to "yes" +# so that the corresponding SPKG is installed. Otherwise, we do +# nothing, since the default value of sage_spkg_install_$package +# is "no" (to use the system copy). +# +# The SAGE_SPKG_CONFIGURE_PYTHON3() macro is AC_REQUIRE'd to ensure +# that $PYTHON_FOR_VENV is available, if it is going to be available. +# The check is run inside a new venv, and with the PYTHONUSERBASE +# variable poisoned in the same manner as sage-env poisons it, to +# ensure that the ./configure- and run-time views of the system +# are as similar as possible. +# +# To avoid suggesting these system packages to users who have not +# set --enable-system-site-packages, this macro also changes the +# default for --with-system-foo from "yes" to "no" in that case. +# + +AC_DEFUN([SAGE_PYTHON_PACKAGE_CHECK], [ + AC_MSG_CHECKING([if --enable-system-site-packages was used]) + AS_IF([test "${enable_system_site_packages}" = "yes"], [ + AC_MSG_RESULT(yes) + AC_REQUIRE([SAGE_SPKG_CONFIGURE_PYTHON3]) + + dnl We run this check inside a python venv, because that's ultimately + dnl how the system $PYTHON_FOR_VENV will be used. + AC_MSG_CHECKING([if we can create a python venv in config.venv]) + + dnl Use --clear because ./configure typically clobbers its output files. + AS_IF(["${PYTHON_FOR_VENV}" build/bin/sage-venv dnl + --system-site-packages dnl + --clear dnl + config.venv dnl + 2>&AS_MESSAGE_LOG_FD], [ + AC_MSG_RESULT(yes) + dnl strip all comments from install-requires.txt; this should leave + dnl only a single line containing the version specification for this + dnl package. + SAGE_PKG_VERSPEC=$(sed '/^#/d' "./build/pkgs/$1/install-requires.txt") + AC_MSG_CHECKING([for python package $1 ("${SAGE_PKG_VERSPEC}")]) + + dnl To prevent user-site (pip install --user) packages from being + dnl detected as "system" packages, we poison PYTHONUSERBASE. The + dnl sage-env script also does this at runtime; we mimic that + dnl implementation to ensure that the behaviors at ./configure and + dnl runtime are identical. Beware that (as in sage-env) the poisoning + dnl is skipped if PYTHONUSERBASE is non-empty. In particular, if the + dnl user points PYTHONUSERBASE to any path (even the default), then + dnl his local pip packages will be detected. + PYTHONUSERBASE_SAVED="${PYTHONUSERBASE}" + AS_IF([test -z "${PYTHONUSERBASE}"], [ + PYTHONUSERBASE="${HOME}/.sage/local" + ]) + + AS_IF( + [PYTHONUSERBASE="${PYTHONUSERBASE}" config.venv/bin/python3 -c dnl + "import pkg_resources; dnl + pkg_resources.require('${SAGE_PKG_VERSPEC}'.splitlines())" dnl + 2>&AS_MESSAGE_LOG_FD], + [AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no); sage_spkg_install_$1=yes] + ) + + PYTHONUSERBASE="${PYTHONUSERBASE_SAVED}" + ], [ + dnl failed to create a venv for some reason + AC_MSG_RESULT(no) + sage_spkg_install_$1=yes + ]) + + dnl Clean up config.venv, but only if we could have created it. + dnl (The --clear flag to pyvenv will not clobber a plain file.) + AS_IF([test -d config.venv], [rm -rf config.venv]) + ], [ + dnl System site packages are disabled. + AC_MSG_RESULT(no; skipping check) + sage_spkg_install_$1=yes + + dnl We have to retroactively hack the --with-system-foo={no,yes,force} + dnl mechanism here because it wasn't designed with the ability to + dnl disable arbitrary chunks of system packages in mind. The easy cases + dnl are "no" and "force" which require no action; "no" means we won't + dnl suggest the package anyway, and "force" will raise an error when + dnl the system-package check fails. + dnl + dnl The default of "yes" is more troubling because it is the default. To + dnl avoid prompting users to install packages that won't be used, we want + dnl to ignore "yes" when reporting the "hint: install these packages..." + dnl at the end of ./configure. To accomplish that, we change "yes" to + dnl "no" here, essentially changing the default for packages using this + dnl macro when --enable-system-site-packages is disabled. Packages with + dnl "no" are not suggested to the user. + AS_IF([test "${sage_use_system_$1}" = "yes"],[sage_use_system_$1=no]) + ]) +]) diff --git a/m4/sage_spkg_configure.m4 b/m4/sage_spkg_configure.m4 index a0eeaa53a74..1f07d7cd294 100644 --- a/m4/sage_spkg_configure.m4 +++ b/m4/sage_spkg_configure.m4 @@ -58,6 +58,31 @@ dnl indicate why m4_pushdef([SPKG_USE_SYSTEM], [sage_use_system_]SPKG_NAME) # BEGIN SAGE_SPKG_CONFIGURE_]m4_toupper($1)[ +dnl Hide the output from Python (system site package) checks +dnl when --enable-system-site-packages was not given. This +dnl doesn't affect the test results but it minimizes the noise +dnl in the ./configure output. The config.log however retains +dnl everything. +dnl +dnl Open descriptor 9 as a copy of AS_MESSAGE_FD, so that it +dnl can later be used to restore AS_MESSAGE_FD. Afterwards, +dnl send AS_MESSAGE_FD to /dev/null. We'll restore it if this +dnl isn't a python package or if --enable-system-site-packages +dnl was given (or at the end of this macro, if nothing else). +exec 9<&AS_MESSAGE_FD +exec AS_MESSAGE_FD>/dev/null + +AS_IF([test "${enable_system_site_packages}" = "yes"], [ + dnl Python package checks are enabled, so restore AS_MESSAGE_FD + exec AS_MESSAGE_FD<&9 +]) + +SPKG_CONFIGURE="${SAGE_ROOT}/build/pkgs/$1/spkg-configure.m4" +AS_IF([! grep -q [SAGE_PYTHON_PACKAGE_CHECK] "${SPKG_CONFIGURE}"],[ + dnl Not a python package, so restore AS_MESSAGE_FD + exec AS_MESSAGE_FD<&9 +]) + echo "-----------------------------------------------------------------------------" >& AS_MESSAGE_FD echo "Checking whether SageMath should install SPKG $1..." >& AS_MESSAGE_FD AS_BOX([Checking whether SageMath should install SPKG $1...]) >& AS_MESSAGE_LOG_FD @@ -140,6 +165,13 @@ AS_VAR_IF(SPKG_INSTALL, [no], [ dnl Run POST $5 +dnl Restore the message file descriptor that we clobbered earlier +dnl for the sake of hiding site package check noise. It's possible +dnl that we've already done this above, but it doesn't hurt to do +dnl it again, and we want everything "back to normal" at the end +dnl of this macro. +exec AS_MESSAGE_FD<&9 + # END SAGE_SPKG_CONFIGURE_]m4_toupper($1)[ m4_popdef([SPKG_USE_SYSTEM]) m4_popdef([SPKG_REQUIRE]) diff --git a/m4/setup_cfg_metadata.m4 b/m4/setup_cfg_metadata.m4 new file mode 100644 index 00000000000..896ca37eb7f --- /dev/null +++ b/m4/setup_cfg_metadata.m4 @@ -0,0 +1,20 @@ +dnl Standard metadata of SageMath distribution packages +dnl +license = GNU General Public License (GPL) v2 or later +author = The Sage Developers +author_email = sage-support@googlegroups.com +url = https://www.sagemath.org + +classifiers = + Development Status :: 6 - Mature + Intended Audience :: Education + Intended Audience :: Science/Research + License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) + Operating System :: POSIX + Operating System :: MacOS :: MacOS X + Programming Language :: Python :: 3 :: Only + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 + Programming Language :: Python :: Implementation :: CPython + Topic :: Scientific/Engineering :: Mathematics diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index 4ab501a9912..7786f0e63e4 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.0.beta1 +10.2.beta5 diff --git a/pkgs/sage-conf/_sage_conf/_conf.py.in b/pkgs/sage-conf/_sage_conf/_conf.py.in index 6cd28f558a8..87b27ca05cb 100644 --- a/pkgs/sage-conf/_sage_conf/_conf.py.in +++ b/pkgs/sage-conf/_sage_conf/_conf.py.in @@ -9,9 +9,11 @@ VERSION = "@PACKAGE_VERSION@" SAGE_LOCAL = "@prefix@" SAGE_ROOT = "@SAGE_ROOT@" -MAXIMA = "@prefix@/bin/maxima" +# The path to the standalone maxima executable. +MAXIMA = "@SAGE_MAXIMA@".replace('${prefix}', SAGE_LOCAL) -# Delete this line if your ECL can load maxima without further prodding. +# Set this to the empty string if your ECL can load maxima without +# further prodding. MAXIMA_FAS = "@SAGE_MAXIMA_FAS@".replace('${prefix}', SAGE_LOCAL) # Delete this line if your ECL can load Kenzo without further prodding. @@ -48,16 +50,13 @@ SAGE_ARCHFLAGS = "@SAGE_ARCHFLAGS@" SAGE_PKG_CONFIG_PATH = "@SAGE_PKG_CONFIG_PATH@".replace('$SAGE_LOCAL', SAGE_LOCAL) # Used in sage.repl.ipython_kernel.install -MATHJAX_DIR = SAGE_LOCAL + "/share/mathjax" +MATHJAX_DIR = "@SAGE_MATHJAX_DIR@".replace('${prefix}', SAGE_LOCAL) THREEJS_DIR = SAGE_LOCAL + "/share/threejs-sage" # OpenMP flags, if available. OPENMP_CFLAGS = "@OPENMP_CFLAGS@" OPENMP_CXXFLAGS = "@OPENMP_CXXFLAGS@" -# The full absolute path to the main Singular library. -LIBSINGULAR_PATH = "@LIBSINGULAR_PATH@".replace('$SAGE_LOCAL', SAGE_LOCAL) - # Installation location of wheels. This is determined at configuration time # and does not depend on the installation location of sage-conf. SAGE_SPKG_WHEELS = "@SAGE_VENV@".replace('${SAGE_LOCAL}', SAGE_LOCAL) + "/var/lib/sage/wheels" diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index 4ab501a9912..7786f0e63e4 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.0.beta1 +10.2.beta5 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index 4ab501a9912..7786f0e63e4 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.0.beta1 +10.2.beta5 diff --git a/pkgs/sage-docbuild/setup.cfg b/pkgs/sage-docbuild/setup.cfg index 337548c6ff3..596f9b4506e 100644 --- a/pkgs/sage-docbuild/setup.cfg +++ b/pkgs/sage-docbuild/setup.cfg @@ -17,7 +17,6 @@ classifiers = Operating System :: POSIX Operating System :: MacOS :: MacOS X Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index 4ab501a9912..7786f0e63e4 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.0.beta1 +10.2.beta5 diff --git a/pkgs/sage-setup/setup.cfg b/pkgs/sage-setup/setup.cfg index 5d7f440e7c6..2355ef6b301 100644 --- a/pkgs/sage-setup/setup.cfg +++ b/pkgs/sage-setup/setup.cfg @@ -32,7 +32,7 @@ packages = sage_setup.autogen.interpreters.specs sage_setup.command -python_requires = >=3.8, <3.12 +python_requires = >=3.9, <3.12 install_requires = pkgconfig diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index 4ab501a9912..7786f0e63e4 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -10.0.beta1 +10.2.beta5 diff --git a/pkgs/sagemath-bliss/MANIFEST.in b/pkgs/sagemath-bliss/MANIFEST.in new file mode 100644 index 00000000000..6d981b9d30e --- /dev/null +++ b/pkgs/sagemath-bliss/MANIFEST.in @@ -0,0 +1,18 @@ +include VERSION.txt + +graft sage/graphs/bliss_cpp + +global-exclude *.c +global-exclude *.cpp + +global-exclude all__sagemath_*.* +global-include all__sagemath_bliss.py + +global-exclude __pycache__ +global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-bliss/README.rst b/pkgs/sagemath-bliss/README.rst new file mode 100644 index 00000000000..9e1cb2e826f --- /dev/null +++ b/pkgs/sagemath-bliss/README.rst @@ -0,0 +1,32 @@ +============================================================================== + Sage: Open Source Mathematics Software: Graph (iso/auto)morphisms with bliss +============================================================================== + +About SageMath +-------------- + + "Creating a Viable Open Source Alternative to + Magma, Maple, Mathematica, and MATLAB" + + Copyright (C) 2005-2023 The Sage Development Team + + https://www.sagemath.org + +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). + +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). + + +About this pip-installable source distribution +---------------------------------------------- + +This pip-installable source distribution ``sagemath-bliss`` is a small +optional distribution for use with ``sagemath-standard``. + +It provides a Cython interface to the ``bliss`` library for the purpose +of computing graph (iso/auto)morphisms. diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt new file mode 100644 index 00000000000..7786f0e63e4 --- /dev/null +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -0,0 +1 @@ +10.2.beta5 diff --git a/pkgs/sagemath-bliss/pyproject.toml.m4 b/pkgs/sagemath-bliss/pyproject.toml.m4 new file mode 100644 index 00000000000..1cbcdf7e162 --- /dev/null +++ b/pkgs/sagemath-bliss/pyproject.toml.m4 @@ -0,0 +1,12 @@ +include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- +[build-system] +# Minimum requirements for the build system to execute. +requires = [ + SPKG_INSTALL_REQUIRES_setuptools_wheel + SPKG_INSTALL_REQUIRES_sage_conf + SPKG_INSTALL_REQUIRES_sage_setup + SPKG_INSTALL_REQUIRES_sagemath_environment + SPKG_INSTALL_REQUIRES_cython + SPKG_INSTALL_REQUIRES_cysignals +] +build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-bliss/requirements.txt.m4 b/pkgs/sagemath-bliss/requirements.txt.m4 new file mode 100644 index 00000000000..8b6ca03b0b9 --- /dev/null +++ b/pkgs/sagemath-bliss/requirements.txt.m4 @@ -0,0 +1,2 @@ +Cython==esyscmd(`printf $(sed "s/[.]p.*//;" ../cython/package-version.txt)') +sagemath-standard==esyscmd(`printf $(sed "s/[.]p.*//;" ../sagelib/package-version.txt)') diff --git a/pkgs/sagemath-bliss/sage b/pkgs/sagemath-bliss/sage new file mode 120000 index 00000000000..e0da5daa6f2 --- /dev/null +++ b/pkgs/sagemath-bliss/sage @@ -0,0 +1 @@ +../../src/sage \ No newline at end of file diff --git a/pkgs/sagemath-bliss/setup.cfg.m4 b/pkgs/sagemath-bliss/setup.cfg.m4 new file mode 100644 index 00000000000..d1faa96a563 --- /dev/null +++ b/pkgs/sagemath-bliss/setup.cfg.m4 @@ -0,0 +1,17 @@ +include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- +[metadata] +name = sagemath-bliss +version = file: VERSION.txt +description = Sage: Open Source Mathematics Software: Graph (iso/auto)morphisms with bliss +long_description = file: README.rst +long_description_content_type = text/x-rst +include(`setup_cfg_metadata.m4')dnl' + +[options] +python_requires = >=3.8, <3.12 +install_requires = + SPKG_INSTALL_REQUIRES_cysignals + +[options.extras_require] +test = + SPKG_INSTALL_REQUIRES_sagemath_repl diff --git a/pkgs/sagemath-bliss/setup.py b/pkgs/sagemath-bliss/setup.py new file mode 100644 index 00000000000..a78c51347d6 --- /dev/null +++ b/pkgs/sagemath-bliss/setup.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +from distutils import log +from setuptools import setup + +# Work around a Cython problem in Python 3.8.x on macOS +# https://github.com/cython/cython/issues/3262 +import os +if os.uname().sysname == 'Darwin': + import multiprocessing + multiprocessing.set_start_method('fork', force=True) + +# If build isolation is not in use and setuptools_scm is installed, +# then its file_finders entry point is invoked, which we don't need. +# Workaround from โ€‹https://github.com/pypa/setuptools_scm/issues/190#issuecomment-351181286 +try: + import setuptools_scm.integration + setuptools_scm.integration.find_files = lambda _: [] +except ImportError: + pass + +# PEP 517 builds do not have . in sys.path +import sys +sys.path.insert(0, os.path.dirname(__file__)) + +if len(sys.argv) > 1 and (sys.argv[1] == "sdist" or sys.argv[1] == "egg_info"): + sdist = True +else: + sdist = False + +if sdist: + cmdclass = {} +else: + from sage_setup.excepthook import excepthook + sys.excepthook = excepthook + + from sage_setup.setenv import setenv + setenv() + + import sage.env + sage.env.default_required_modules = sage.env.default_optional_modules = () + + from sage_setup.command.sage_build_cython import sage_build_cython + from sage_setup.command.sage_build_ext import sage_build_ext + sage_build_cython.built_distributions = ['sagemath-bliss'] + + cmdclass = dict(build_cython=sage_build_cython, + build_ext=sage_build_ext) + +from sage_setup.find import find_python_sources +python_packages, python_modules, cython_modules = find_python_sources( + '.', ['sage'], distributions=['sagemath-bliss']) + +log.warn('python_packages = {0}'.format(python_packages)) +log.warn('python_modules = {0}'.format(python_modules)) +log.warn('cython_modules = {0}'.format(cython_modules)) + +setup( + cmdclass = cmdclass, + packages = python_packages, + py_modules = python_modules, + ext_modules = cython_modules, +) diff --git a/pkgs/sagemath-categories/MANIFEST.in.m4 b/pkgs/sagemath-categories/MANIFEST.in.m4 index 361132e0cfa..b2e35673ec0 100644 --- a/pkgs/sagemath-categories/MANIFEST.in.m4 +++ b/pkgs/sagemath-categories/MANIFEST.in.m4 @@ -3,7 +3,6 @@ prune sage include VERSION.txt -global-include all__sagemath_categories.py graft sage/categories # Exclude what is already shipped in sagemath-objects exclude sage/categories/action.* @@ -42,6 +41,9 @@ graft sage/typeset # dep of sage.categories.tensor global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_categories.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-categories/README.rst b/pkgs/sagemath-categories/README.rst index d1f90fea966..55cddc3c95c 100644 --- a/pkgs/sagemath-categories/README.rst +++ b/pkgs/sagemath-categories/README.rst @@ -8,7 +8,7 @@ About SageMath "Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, and MATLAB" - Copyright (C) 2005-2022 The Sage Development Team + Copyright (C) 2005-2023 The Sage Development Team https://www.sagemath.org diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index 4ab501a9912..7786f0e63e4 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.0.beta1 +10.2.beta5 diff --git a/pkgs/sagemath-categories/known-test-failures.json b/pkgs/sagemath-categories/known-test-failures.json new file mode 100644 index 00000000000..ddae185a7d9 --- /dev/null +++ b/pkgs/sagemath-categories/known-test-failures.json @@ -0,0 +1,1421 @@ +{ + "sage.arith.numerical_approx": { + "ntests": 1 + }, + "sage.arith.power": { + "failed": true, + "ntests": 16 + }, + "sage.categories.action": { + "failed": true, + "ntests": 78 + }, + "sage.categories.additive_groups": { + "ntests": 9 + }, + "sage.categories.additive_magmas": { + "failed": true, + "ntests": 134 + }, + "sage.categories.additive_monoids": { + "failed": true, + "ntests": 16 + }, + "sage.categories.additive_semigroups": { + "failed": true, + "ntests": 28 + }, + "sage.categories.affine_weyl_groups": { + "ntests": 14 + }, + "sage.categories.algebra_ideals": { + "failed": true, + "ntests": 8 + }, + "sage.categories.algebra_modules": { + "failed": true, + "ntests": 9 + }, + "sage.categories.algebras": { + "failed": true, + "ntests": 20 + }, + "sage.categories.algebras_with_basis": { + "failed": true, + "ntests": 46 + }, + "sage.categories.aperiodic_semigroups": { + "ntests": 1 + }, + "sage.categories.associative_algebras": { + "failed": true, + "ntests": 5 + }, + "sage.categories.bialgebras": { + "ntests": 3 + }, + "sage.categories.bialgebras_with_basis": { + "failed": true, + "ntests": 31 + }, + "sage.categories.bimodules": { + "failed": true, + "ntests": 15 + }, + "sage.categories.cartesian_product": { + "failed": true, + "ntests": 42 + }, + "sage.categories.category": { + "failed": true, + "ntests": 433 + }, + "sage.categories.category_cy_helper": { + "failed": true, + "ntests": 27 + }, + "sage.categories.category_singleton": { + "failed": true, + "ntests": 59 + }, + "sage.categories.category_types": { + "failed": true, + "ntests": 74 + }, + "sage.categories.category_with_axiom": { + "failed": true, + "ntests": 328 + }, + "sage.categories.chain_complexes": { + "failed": true, + "ntests": 20 + }, + "sage.categories.coalgebras": { + "ntests": 6 + }, + "sage.categories.coalgebras_with_basis": { + "failed": true, + "ntests": 23 + }, + "sage.categories.coercion_methods": { + "failed": true, + "ntests": 6 + }, + "sage.categories.commutative_additive_groups": { + "failed": true, + "ntests": 17 + }, + "sage.categories.commutative_additive_monoids": { + "ntests": 5 + }, + "sage.categories.commutative_additive_semigroups": { + "failed": true, + "ntests": 6 + }, + "sage.categories.commutative_algebra_ideals": { + "failed": true, + "ntests": 9 + }, + "sage.categories.commutative_algebras": { + "failed": true, + "ntests": 11 + }, + "sage.categories.commutative_ring_ideals": { + "failed": true, + "ntests": 7 + }, + "sage.categories.commutative_rings": { + "failed": true, + "ntests": 39 + }, + "sage.categories.complete_discrete_valuation": { + "failed": true, + "ntests": 30 + }, + "sage.categories.complex_reflection_groups": { + "failed": true, + "ntests": 16 + }, + "sage.categories.complex_reflection_or_generalized_coxeter_groups": { + "ntests": 67 + }, + "sage.categories.covariant_functorial_construction": { + "failed": true, + "ntests": 65 + }, + "sage.categories.coxeter_group_algebras": { + "ntests": 2 + }, + "sage.categories.coxeter_groups": { + "failed": true, + "ntests": 362 + }, + "sage.categories.cw_complexes": { + "failed": true, + "ntests": 36 + }, + "sage.categories.discrete_valuation": { + "failed": true, + "ntests": 23 + }, + "sage.categories.distributive_magmas_and_additive_magmas": { + "failed": true, + "ntests": 13 + }, + "sage.categories.division_rings": { + "ntests": 11 + }, + "sage.categories.domains": { + "failed": true, + "ntests": 7 + }, + "sage.categories.drinfeld_modules": { + "ntests": 2 + }, + "sage.categories.dual": { + "failed": true, + "ntests": 1 + }, + "sage.categories.enumerated_sets": { + "failed": true, + "ntests": 132 + }, + "sage.categories.euclidean_domains": { + "failed": true, + "ntests": 22 + }, + "sage.categories.examples.algebras_with_basis": { + "ntests": 8 + }, + "sage.categories.examples.commutative_additive_monoids": { + "failed": true, + "ntests": 14 + }, + "sage.categories.examples.commutative_additive_semigroups": { + "failed": true, + "ntests": 28 + }, + "sage.categories.examples.cw_complexes": { + "failed": true, + "ntests": 33 + }, + "sage.categories.examples.facade_sets": { + "failed": true, + "ntests": 21 + }, + "sage.categories.examples.filtered_algebras_with_basis": { + "failed": true, + "ntests": 25 + }, + "sage.categories.examples.filtered_modules_with_basis": { + "ntests": 12 + }, + "sage.categories.examples.finite_dimensional_lie_algebras_with_basis": { + "ntests": 1 + }, + "sage.categories.examples.finite_enumerated_sets": { + "failed": true, + "ntests": 29 + }, + "sage.categories.examples.finite_monoids": { + "failed": true, + "ntests": 15 + }, + "sage.categories.examples.finite_semigroups": { + "failed": true, + "ntests": 27 + }, + "sage.categories.examples.finite_weyl_groups": { + "failed": true, + "ntests": 25 + }, + "sage.categories.examples.graded_modules_with_basis": { + "ntests": 14 + }, + "sage.categories.examples.graphs": { + "failed": true, + "ntests": 24 + }, + "sage.categories.examples.infinite_enumerated_sets": { + "failed": true, + "ntests": 35 + }, + "sage.categories.examples.lie_algebras": { + "ntests": 25 + }, + "sage.categories.examples.magmas": { + "failed": true, + "ntests": 20 + }, + "sage.categories.examples.manifolds": { + "failed": true, + "ntests": 15 + }, + "sage.categories.examples.monoids": { + "failed": true, + "ntests": 16 + }, + "sage.categories.examples.posets": { + "failed": true, + "ntests": 29 + }, + "sage.categories.examples.semigroups": { + "failed": true, + "ntests": 83 + }, + "sage.categories.examples.semigroups_cython": { + "failed": true, + "ntests": 47 + }, + "sage.categories.examples.sets_with_grading": { + "failed": true, + "ntests": 14 + }, + "sage.categories.facade_sets": { + "failed": true, + "ntests": 27 + }, + "sage.categories.fields": { + "failed": true, + "ntests": 109 + }, + "sage.categories.filtered_algebras": { + "failed": true, + "ntests": 5 + }, + "sage.categories.filtered_algebras_with_basis": { + "failed": true, + "ntests": 39 + }, + "sage.categories.filtered_hopf_algebras_with_basis": { + "failed": true, + "ntests": 12 + }, + "sage.categories.filtered_modules": { + "failed": true, + "ntests": 18 + }, + "sage.categories.filtered_modules_with_basis": { + "failed": true, + "ntests": 65 + }, + "sage.categories.finite_complex_reflection_groups": { + "failed": true, + "ntests": 178 + }, + "sage.categories.finite_coxeter_groups": { + "ntests": 6 + }, + "sage.categories.finite_dimensional_algebras_with_basis": { + "failed": true, + "ntests": 87 + }, + "sage.categories.finite_dimensional_bialgebras_with_basis": { + "failed": true, + "ntests": 4 + }, + "sage.categories.finite_dimensional_coalgebras_with_basis": { + "failed": true, + "ntests": 4 + }, + "sage.categories.finite_dimensional_graded_lie_algebras_with_basis": { + "failed": true, + "ntests": 22 + }, + "sage.categories.finite_dimensional_hopf_algebras_with_basis": { + "failed": true, + "ntests": 3 + }, + "sage.categories.finite_dimensional_lie_algebras_with_basis": { + "failed": true, + "ntests": 34 + }, + "sage.categories.finite_dimensional_modules_with_basis": { + "failed": true, + "ntests": 55 + }, + "sage.categories.finite_dimensional_nilpotent_lie_algebras_with_basis": { + "failed": true, + "ntests": 19 + }, + "sage.categories.finite_dimensional_semisimple_algebras_with_basis": { + "failed": true, + "ntests": 12 + }, + "sage.categories.finite_enumerated_sets": { + "failed": true, + "ntests": 123 + }, + "sage.categories.finite_fields": { + "failed": true, + "ntests": 14 + }, + "sage.categories.finite_lattice_posets": { + "ntests": 31 + }, + "sage.categories.finite_monoids": { + "failed": true, + "ntests": 28 + }, + "sage.categories.finite_permutation_groups": { + "ntests": 2 + }, + "sage.categories.finite_semigroups": { + "failed": true, + "ntests": 14 + }, + "sage.categories.finite_sets": { + "failed": true, + "ntests": 14 + }, + "sage.categories.finite_weyl_groups": { + "failed": true, + "ntests": 6 + }, + "sage.categories.finitely_generated_lambda_bracket_algebras": { + "ntests": 11 + }, + "sage.categories.finitely_generated_lie_conformal_algebras": { + "ntests": 10 + }, + "sage.categories.finitely_generated_magmas": { + "failed": true, + "ntests": 6 + }, + "sage.categories.finitely_generated_semigroups": { + "failed": true, + "ntests": 27 + }, + "sage.categories.function_fields": { + "failed": true, + "ntests": 11 + }, + "sage.categories.functor": { + "failed": true, + "ntests": 128 + }, + "sage.categories.g_sets": { + "ntests": 7 + }, + "sage.categories.gcd_domains": { + "ntests": 5 + }, + "sage.categories.generalized_coxeter_groups": { + "ntests": 12 + }, + "sage.categories.graded_algebras": { + "failed": true, + "ntests": 8 + }, + "sage.categories.graded_algebras_with_basis": { + "failed": true, + "ntests": 8 + }, + "sage.categories.graded_bialgebras": { + "failed": true, + "ntests": 3 + }, + "sage.categories.graded_bialgebras_with_basis": { + "failed": true, + "ntests": 3 + }, + "sage.categories.graded_coalgebras": { + "failed": true, + "ntests": 6 + }, + "sage.categories.graded_coalgebras_with_basis": { + "failed": true, + "ntests": 6 + }, + "sage.categories.graded_hopf_algebras": { + "failed": true, + "ntests": 3 + }, + "sage.categories.graded_hopf_algebras_with_basis": { + "failed": true, + "ntests": 12 + }, + "sage.categories.graded_lie_algebras": { + "failed": true, + "ntests": 12 + }, + "sage.categories.graded_lie_algebras_with_basis": { + "failed": true, + "ntests": 5 + }, + "sage.categories.graded_lie_conformal_algebras": { + "failed": true, + "ntests": 5 + }, + "sage.categories.graded_modules": { + "failed": true, + "ntests": 16 + }, + "sage.categories.graded_modules_with_basis": { + "failed": true, + "ntests": 25 + }, + "sage.categories.graphs": { + "failed": true, + "ntests": 25 + }, + "sage.categories.group_algebras": { + "failed": true, + "ntests": 27 + }, + "sage.categories.groups": { + "ntests": 45 + }, + "sage.categories.h_trivial_semigroups": { + "ntests": 4 + }, + "sage.categories.hecke_modules": { + "failed": true, + "ntests": 16 + }, + "sage.categories.homset": { + "failed": true, + "ntests": 197 + }, + "sage.categories.homsets": { + "failed": true, + "ntests": 56 + }, + "sage.categories.hopf_algebras": { + "failed": true, + "ntests": 15 + }, + "sage.categories.hopf_algebras_with_basis": { + "failed": true, + "ntests": 30 + }, + "sage.categories.infinite_enumerated_sets": { + "failed": true, + "ntests": 13 + }, + "sage.categories.inner_product_spaces": { + "failed": true, + "ntests": 9 + }, + "sage.categories.integral_domains": { + "failed": true, + "ntests": 22 + }, + "sage.categories.isomorphic_objects": { + "ntests": 2 + }, + "sage.categories.j_trivial_semigroups": { + "ntests": 1 + }, + "sage.categories.kac_moody_algebras": { + "failed": true, + "ntests": 9 + }, + "sage.categories.l_trivial_semigroups": { + "ntests": 5 + }, + "sage.categories.lambda_bracket_algebras": { + "failed": true, + "ntests": 16 + }, + "sage.categories.lambda_bracket_algebras_with_basis": { + "ntests": 5 + }, + "sage.categories.lattice_posets": { + "ntests": 10 + }, + "sage.categories.left_modules": { + "failed": true, + "ntests": 4 + }, + "sage.categories.lie_algebras": { + "failed": true, + "ntests": 125 + }, + "sage.categories.lie_algebras_with_basis": { + "ntests": 19 + }, + "sage.categories.lie_conformal_algebras": { + "failed": true, + "ntests": 25 + }, + "sage.categories.lie_conformal_algebras_with_basis": { + "ntests": 17 + }, + "sage.categories.lie_groups": { + "failed": true, + "ntests": 9 + }, + "sage.categories.loop_crystals": { + "ntests": 1 + }, + "sage.categories.magmas": { + "failed": true, + "ntests": 147 + }, + "sage.categories.magmas_and_additive_magmas": { + "ntests": 21 + }, + "sage.categories.magmatic_algebras": { + "failed": true, + "ntests": 27 + }, + "sage.categories.manifolds": { + "failed": true, + "ntests": 52 + }, + "sage.categories.map": { + "failed": true, + "ntests": 353 + }, + "sage.categories.matrix_algebras": { + "failed": true, + "ntests": 3 + }, + "sage.categories.metric_spaces": { + "failed": true, + "ntests": 46 + }, + "sage.categories.modular_abelian_varieties": { + "failed": true, + "ntests": 8 + }, + "sage.categories.modules": { + "failed": true, + "ntests": 120 + }, + "sage.categories.modules_with_basis": { + "failed": true, + "ntests": 221 + }, + "sage.categories.monoid_algebras": { + "failed": true, + "ntests": 4 + }, + "sage.categories.monoids": { + "failed": true, + "ntests": 81 + }, + "sage.categories.morphism": { + "failed": true, + "ntests": 99 + }, + "sage.categories.number_fields": { + "failed": true, + "ntests": 41 + }, + "sage.categories.objects": { + "failed": true, + "ntests": 12 + }, + "sage.categories.partially_ordered_monoids": { + "ntests": 4 + }, + "sage.categories.permutation_groups": { + "ntests": 6 + }, + "sage.categories.pointed_sets": { + "ntests": 3 + }, + "sage.categories.polyhedra": { + "failed": true, + "ntests": 4 + }, + "sage.categories.poor_man_map": { + "failed": true, + "ntests": 59 + }, + "sage.categories.posets": { + "ntests": 2 + }, + "sage.categories.primer": { + "failed": true, + "ntests": 162 + }, + "sage.categories.principal_ideal_domains": { + "failed": true, + "ntests": 11 + }, + "sage.categories.pushout": { + "failed": true, + "ntests": 624 + }, + "sage.categories.quantum_group_representations": { + "failed": true, + "ntests": 13 + }, + "sage.categories.quotient_fields": { + "failed": true, + "ntests": 81 + }, + "sage.categories.quotients": { + "ntests": 2 + }, + "sage.categories.r_trivial_semigroups": { + "ntests": 3 + }, + "sage.categories.realizations": { + "failed": true, + "ntests": 21 + }, + "sage.categories.right_modules": { + "failed": true, + "ntests": 4 + }, + "sage.categories.ring_ideals": { + "failed": true, + "ntests": 9 + }, + "sage.categories.rings": { + "failed": true, + "ntests": 141 + }, + "sage.categories.rngs": { + "ntests": 6 + }, + "sage.categories.schemes": { + "failed": true, + "ntests": 23 + }, + "sage.categories.semigroups": { + "failed": true, + "ntests": 112 + }, + "sage.categories.semirings": { + "ntests": 6 + }, + "sage.categories.semisimple_algebras": { + "failed": true, + "ntests": 15 + }, + "sage.categories.sets_cat": { + "failed": true, + "ntests": 412 + }, + "sage.categories.sets_with_grading": { + "failed": true, + "ntests": 23 + }, + "sage.categories.sets_with_partial_maps": { + "ntests": 4 + }, + "sage.categories.shephard_groups": { + "ntests": 5 + }, + "sage.categories.signed_tensor": { + "failed": true, + "ntests": 10 + }, + "sage.categories.simplicial_complexes": { + "ntests": 17 + }, + "sage.categories.simplicial_sets": { + "failed": true, + "ntests": 57 + }, + "sage.categories.subobjects": { + "ntests": 2 + }, + "sage.categories.super_algebras": { + "failed": true, + "ntests": 8 + }, + "sage.categories.super_algebras_with_basis": { + "failed": true, + "ntests": 10 + }, + "sage.categories.super_hopf_algebras_with_basis": { + "failed": true, + "ntests": 10 + }, + "sage.categories.super_lie_conformal_algebras": { + "failed": true, + "ntests": 20 + }, + "sage.categories.super_modules": { + "failed": true, + "ntests": 18 + }, + "sage.categories.super_modules_with_basis": { + "failed": true, + "ntests": 10 + }, + "sage.categories.supercommutative_algebras": { + "failed": true, + "ntests": 8 + }, + "sage.categories.tensor": { + "failed": true, + "ntests": 9 + }, + "sage.categories.topological_spaces": { + "ntests": 27 + }, + "sage.categories.triangular_kac_moody_algebras": { + "failed": true, + "ntests": 15 + }, + "sage.categories.tutorial": { + "failed": true, + "ntests": 4 + }, + "sage.categories.unique_factorization_domains": { + "failed": true, + "ntests": 39 + }, + "sage.categories.unital_algebras": { + "failed": true, + "ntests": 39 + }, + "sage.categories.vector_spaces": { + "failed": true, + "ntests": 44 + }, + "sage.categories.with_realizations": { + "failed": true, + "ntests": 24 + }, + "sage.cpython.atexit": { + "ntests": 19 + }, + "sage.cpython.cython_metaclass": { + "ntests": 4 + }, + "sage.cpython.debug": { + "failed": true, + "ntests": 14 + }, + "sage.cpython.dict_del_by_value": { + "failed": true, + "ntests": 21 + }, + "sage.cpython.getattr": { + "failed": true, + "ntests": 65 + }, + "sage.cpython.string": { + "ntests": 1 + }, + "sage.cpython.string.pxd": { + "ntests": 8 + }, + "sage.cpython.type": { + "ntests": 7 + }, + "sage.cpython.wrapperdescr": { + "failed": true, + "ntests": 0 + }, + "sage.doctest.control": { + "failed": true, + "ntests": 0 + }, + "sage.doctest.external": { + "ntests": 42 + }, + "sage.doctest.fixtures": { + "failed": true, + "ntests": 59 + }, + "sage.doctest.forker": { + "failed": true, + "ntests": 433 + }, + "sage.doctest.parsing": { + "failed": true, + "ntests": 321 + }, + "sage.doctest.reporting": { + "failed": true, + "ntests": 124 + }, + "sage.doctest.sources": { + "failed": true, + "ntests": 378 + }, + "sage.doctest.test": { + "failed": true, + "ntests": 23 + }, + "sage.doctest.util": { + "failed": true, + "ntests": 141 + }, + "sage.env": { + "failed": true, + "ntests": 41 + }, + "sage.features": { + "ntests": 145 + }, + "sage.features.all": { + "ntests": 14 + }, + "sage.features.bliss": { + "ntests": 8 + }, + "sage.features.cddlib": { + "ntests": 4 + }, + "sage.features.csdp": { + "ntests": 6 + }, + "sage.features.cython": { + "ntests": 3 + }, + "sage.features.databases": { + "failed": true, + "ntests": 26 + }, + "sage.features.dvipng": { + "ntests": 4 + }, + "sage.features.ffmpeg": { + "ntests": 4 + }, + "sage.features.four_ti_2": { + "ntests": 6 + }, + "sage.features.gap": { + "ntests": 6 + }, + "sage.features.gfan": { + "ntests": 2 + }, + "sage.features.graph_generators": { + "ntests": 18 + }, + "sage.features.graphviz": { + "ntests": 16 + }, + "sage.features.igraph": { + "ntests": 4 + }, + "sage.features.imagemagick": { + "ntests": 10 + }, + "sage.features.interfaces": { + "failed": true, + "ntests": 33 + }, + "sage.features.internet": { + "ntests": 5 + }, + "sage.features.join_feature": { + "ntests": 25 + }, + "sage.features.kenzo": { + "ntests": 6 + }, + "sage.features.latex": { + "ntests": 30 + }, + "sage.features.latte": { + "ntests": 8 + }, + "sage.features.lrs": { + "ntests": 16 + }, + "sage.features.mcqd": { + "ntests": 4 + }, + "sage.features.meataxe": { + "ntests": 4 + }, + "sage.features.mip_backends": { + "ntests": 7 + }, + "sage.features.msolve": { + "ntests": 6 + }, + "sage.features.nauty": { + "ntests": 8 + }, + "sage.features.normaliz": { + "ntests": 4 + }, + "sage.features.palp": { + "ntests": 4 + }, + "sage.features.pandoc": { + "ntests": 4 + }, + "sage.features.pdf2svg": { + "ntests": 4 + }, + "sage.features.phitigra": { + "ntests": 4 + }, + "sage.features.pkg_systems": { + "ntests": 25 + }, + "sage.features.polymake": { + "ntests": 4 + }, + "sage.features.poppler": { + "ntests": 4 + }, + "sage.features.rubiks": { + "ntests": 28 + }, + "sage.features.sagemath": { + "failed": true, + "ntests": 147 + }, + "sage.features.singular": { + "ntests": 4 + }, + "sage.features.sphinx": { + "ntests": 4 + }, + "sage.features.tdlib": { + "ntests": 2 + }, + "sage.misc.abstract_method": { + "failed": true, + "ntests": 33 + }, + "sage.misc.banner": { + "failed": true, + "ntests": 12 + }, + "sage.misc.bindable_class": { + "ntests": 47 + }, + "sage.misc.c3_controlled": { + "failed": true, + "ntests": 150 + }, + "sage.misc.cachefunc": { + "failed": true, + "ntests": 692 + }, + "sage.misc.call": { + "ntests": 28 + }, + "sage.misc.classcall_metaclass": { + "ntests": 78 + }, + "sage.misc.constant_function": { + "ntests": 21 + }, + "sage.misc.decorators": { + "failed": true, + "ntests": 126 + }, + "sage.misc.fast_methods": { + "failed": true, + "ntests": 80 + }, + "sage.misc.flatten": { + "failed": true, + "ntests": 15 + }, + "sage.misc.function_mangling": { + "ntests": 32 + }, + "sage.misc.inherit_comparison": { + "ntests": 2 + }, + "sage.misc.instancedoc": { + "ntests": 67 + }, + "sage.misc.lazy_attribute": { + "failed": true, + "ntests": 100 + }, + "sage.misc.lazy_format": { + "failed": true, + "ntests": 23 + }, + "sage.misc.lazy_import": { + "failed": true, + "ntests": 279 + }, + "sage.misc.lazy_import_cache": { + "failed": true, + "ntests": 8 + }, + "sage.misc.lazy_string": { + "failed": true, + "ntests": 131 + }, + "sage.misc.misc": { + "failed": true, + "ntests": 176 + }, + "sage.misc.misc_c": { + "failed": true, + "ntests": 121 + }, + "sage.misc.namespace_package": { + "ntests": 7 + }, + "sage.misc.nested_class": { + "ntests": 67 + }, + "sage.misc.package": { + "ntests": 36 + }, + "sage.misc.package_dir": { + "failed": true, + "ntests": 29 + }, + "sage.misc.persist": { + "failed": true, + "ntests": 137 + }, + "sage.misc.prandom": { + "failed": true, + "ntests": 74 + }, + "sage.misc.repr": { + "failed": true, + "ntests": 31 + }, + "sage.misc.sage_eval": { + "failed": true, + "ntests": 31 + }, + "sage.misc.sage_input": { + "failed": true, + "ntests": 732 + }, + "sage.misc.sage_unittest": { + "failed": true, + "ntests": 88 + }, + "sage.misc.sagedoc": { + "failed": true, + "ntests": 103 + }, + "sage.misc.sageinspect": { + "failed": true, + "ntests": 329 + }, + "sage.misc.superseded": { + "failed": true, + "ntests": 59 + }, + "sage.misc.temporary_file": { + "failed": true, + "ntests": 80 + }, + "sage.misc.timing": { + "failed": true, + "ntests": 35 + }, + "sage.misc.unknown": { + "ntests": 22 + }, + "sage.misc.verbose": { + "ntests": 22 + }, + "sage.misc.viewer": { + "failed": true, + "ntests": 49 + }, + "sage.misc.weak_dict": { + "failed": true, + "ntests": 251 + }, + "sage.repl.attach": { + "failed": true, + "ntests": 128 + }, + "sage.repl.configuration": { + "ntests": 22 + }, + "sage.repl.display.fancy_repr": { + "failed": true, + "ntests": 27 + }, + "sage.repl.display.formatter": { + "failed": true, + "ntests": 58 + }, + "sage.repl.display.jsmol_iframe": { + "ntests": 25 + }, + "sage.repl.display.pretty_print": { + "failed": true, + "ntests": 21 + }, + "sage.repl.display.util": { + "ntests": 7 + }, + "sage.repl.image": { + "failed": true, + "ntests": 42 + }, + "sage.repl.inputhook": { + "ntests": 7 + }, + "sage.repl.interface_magic": { + "failed": true, + "ntests": 20 + }, + "sage.repl.interpreter": { + "failed": true, + "ntests": 118 + }, + "sage.repl.ipython_extension": { + "failed": true, + "ntests": 80 + }, + "sage.repl.ipython_kernel.install": { + "failed": true, + "ntests": 40 + }, + "sage.repl.ipython_kernel.interact": { + "failed": true, + "ntests": 42 + }, + "sage.repl.ipython_kernel.kernel": { + "ntests": 12 + }, + "sage.repl.ipython_kernel.widgets": { + "failed": true, + "ntests": 98 + }, + "sage.repl.ipython_kernel.widgets_sagenb": { + "failed": true, + "ntests": 77 + }, + "sage.repl.ipython_tests": { + "failed": true, + "ntests": 26 + }, + "sage.repl.load": { + "failed": true, + "ntests": 42 + }, + "sage.repl.preparse": { + "failed": true, + "ntests": 349 + }, + "sage.repl.rich_output.backend_base": { + "failed": true, + "ntests": 96 + }, + "sage.repl.rich_output.backend_doctest": { + "ntests": 58 + }, + "sage.repl.rich_output.backend_emacs": { + "ntests": 15 + }, + "sage.repl.rich_output.backend_ipython": { + "failed": true, + "ntests": 78 + }, + "sage.repl.rich_output.buffer": { + "failed": true, + "ntests": 49 + }, + "sage.repl.rich_output.display_manager": { + "failed": true, + "ntests": 88 + }, + "sage.repl.rich_output.output_basic": { + "ntests": 47 + }, + "sage.repl.rich_output.output_browser": { + "ntests": 12 + }, + "sage.repl.rich_output.output_graphics": { + "ntests": 38 + }, + "sage.repl.rich_output.output_graphics3d": { + "ntests": 46 + }, + "sage.repl.rich_output.output_video": { + "ntests": 25 + }, + "sage.repl.rich_output.preferences": { + "ntests": 68 + }, + "sage.repl.rich_output.pretty_print": { + "failed": true, + "ntests": 41 + }, + "sage.repl.rich_output.test_backend": { + "failed": true, + "ntests": 37 + }, + "sage.rings.ideal": { + "failed": true, + "ntests": 336 + }, + "sage.rings.integer_fake.pxd": { + "ntests": 1 + }, + "sage.rings.ring": { + "failed": true, + "ntests": 337 + }, + "sage.sets.pythonclass": { + "failed": true, + "ntests": 55 + }, + "sage.structure.category_object": { + "failed": true, + "ntests": 140 + }, + "sage.structure.coerce": { + "failed": true, + "ntests": 314 + }, + "sage.structure.coerce_actions": { + "failed": true, + "ntests": 128 + }, + "sage.structure.coerce_dict": { + "failed": true, + "ntests": 289 + }, + "sage.structure.coerce_maps": { + "failed": true, + "ntests": 90 + }, + "sage.structure.debug_options": { + "ntests": 5 + }, + "sage.structure.dynamic_class": { + "failed": true, + "ntests": 83 + }, + "sage.structure.element": { + "failed": true, + "ntests": 562 + }, + "sage.structure.element.pxd": { + "failed": true, + "ntests": 23 + }, + "sage.structure.element_wrapper": { + "failed": true, + "ntests": 160 + }, + "sage.structure.factorization": { + "failed": true, + "ntests": 203 + }, + "sage.structure.factorization_integer": { + "failed": true, + "ntests": 6 + }, + "sage.structure.factory": { + "failed": true, + "ntests": 99 + }, + "sage.structure.formal_sum": { + "failed": true, + "ntests": 67 + }, + "sage.structure.global_options": { + "ntests": 145 + }, + "sage.structure.graphics_file": { + "ntests": 8 + }, + "sage.structure.indexed_generators": { + "failed": true, + "ntests": 90 + }, + "sage.structure.list_clone": { + "failed": true, + "ntests": 380 + }, + "sage.structure.list_clone_demo": { + "ntests": 43 + }, + "sage.structure.list_clone_timings": { + "ntests": 18 + }, + "sage.structure.list_clone_timings_cy": { + "ntests": 12 + }, + "sage.structure.mutability": { + "failed": true, + "ntests": 68 + }, + "sage.structure.nonexact": { + "failed": true, + "ntests": 11 + }, + "sage.structure.parent": { + "failed": true, + "ntests": 300 + }, + "sage.structure.parent_gens": { + "failed": true, + "ntests": 24 + }, + "sage.structure.parent_old": { + "failed": true, + "ntests": 5 + }, + "sage.structure.proof.all": { + "ntests": 31 + }, + "sage.structure.proof.proof": { + "ntests": 50 + }, + "sage.structure.richcmp": { + "failed": true, + "ntests": 56 + }, + "sage.structure.richcmp.pxd": { + "ntests": 24 + }, + "sage.structure.sage_object": { + "failed": true, + "ntests": 84 + }, + "sage.structure.sequence": { + "failed": true, + "ntests": 183 + }, + "sage.structure.set_factories": { + "failed": true, + "ntests": 225 + }, + "sage.structure.set_factories_example": { + "failed": true, + "ntests": 81 + }, + "sage.structure.support_view": { + "ntests": 38 + }, + "sage.structure.test_factory": { + "failed": true, + "ntests": 6 + }, + "sage.structure.unique_representation": { + "failed": true, + "ntests": 226 + }, + "sage.typeset.ascii_art": { + "failed": true, + "ntests": 24 + }, + "sage.typeset.character_art": { + "failed": true, + "ntests": 108 + }, + "sage.typeset.character_art_factory": { + "failed": true, + "ntests": 53 + }, + "sage.typeset.symbols": { + "failed": true, + "ntests": 28 + }, + "sage.typeset.unicode_art": { + "failed": true, + "ntests": 18 + }, + "sage.typeset.unicode_characters": { + "ntests": 27 + } +} \ No newline at end of file diff --git a/pkgs/sagemath-categories/pyproject.toml.m4 b/pkgs/sagemath-categories/pyproject.toml.m4 index 0afd7849de5..cf4c97f1fd1 100644 --- a/pkgs/sagemath-categories/pyproject.toml.m4 +++ b/pkgs/sagemath-categories/pyproject.toml.m4 @@ -1,14 +1,14 @@ +include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- [build-system] # Minimum requirements for the build system to execute. requires = [ - esyscmd(`sage-get-system-packages install-requires-toml \ - setuptools \ - wheel \ - sage_setup \ - sagemath_environment \ - sagemath_objects \ - cython \ - gmpy2 \ - cysignals \ - ')] + SPKG_INSTALL_REQUIRES_setuptools_wheel + SPKG_INSTALL_REQUIRES_wheel + SPKG_INSTALL_REQUIRES_sage_setup + SPKG_INSTALL_REQUIRES_sagemath_environment + SPKG_INSTALL_REQUIRES_sagemath_objects + SPKG_INSTALL_REQUIRES_cython + SPKG_INSTALL_REQUIRES_gmpy2 + SPKG_INSTALL_REQUIRES_cysignals +] build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-categories/setup.cfg.m4 b/pkgs/sagemath-categories/setup.cfg.m4 index 62aca5af44f..f5eb7c72968 100644 --- a/pkgs/sagemath-categories/setup.cfg.m4 +++ b/pkgs/sagemath-categories/setup.cfg.m4 @@ -1,36 +1,16 @@ -# -*- conf-unix -*- +include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- [metadata] name = sagemath-categories version = file: VERSION.txt description = Sage: Open Source Mathematics Software: Sage categories and basic rings long_description = file: README.rst long_description_content_type = text/x-rst -license = GNU General Public License (GPL) v2 or later -author = The Sage Developers -author_email = sage-support@googlegroups.com -url = https://www.sagemath.org - -classifiers = - Development Status :: 6 - Mature - Intended Audience :: Education - Intended Audience :: Science/Research - License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) - Operating System :: POSIX - Operating System :: MacOS :: MacOS X - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: Implementation :: CPython - Topic :: Scientific/Engineering :: Mathematics +include(`setup_cfg_metadata.m4')dnl' [options] -python_requires = >=3.8, <3.12 +python_requires = >=3.9, <3.12 install_requires = - esyscmd(`sage-get-system-packages install-requires \ - sagemath_objects \ - | sed "2,\$s/^/ /;"')dnl + SPKG_INSTALL_REQUIRES_sagemath_objects [options.extras_require] -test = sagemath-repl +test = SPKG_INSTALL_REQUIRES_sagemath_repl diff --git a/pkgs/sagemath-categories/tox.ini b/pkgs/sagemath-categories/tox.ini index a240b091e30..5469be55b3c 100644 --- a/pkgs/sagemath-categories/tox.ini +++ b/pkgs/sagemath-categories/tox.ini @@ -1,23 +1,23 @@ # To build and test in the tox environment: # -# ./sage -sh -c '(cd pkgs/sagemath-categories && tox -v -v -v -e sagepython)' +# make SAGE_WHEELS=yes sagemath_categories-build-deps sagemath_repl && ./sage -sh -c '(cd pkgs/sagemath-categories && SAGE_NUM_THREADS=8 tox -v -v -v -e sagepython-sagewheels-nopypi-norequirements)' # -# To test interactively: +# After this, to test interactively: # -# pkgs/sagemath-categories/.tox/sagepython/bin/python +# pkgs/sagemath-categories/.tox/sagepython-sagewheels-nopypi-norequirements/bin/sage # [tox] envlist = - sagepython-norequirements + sagepython-sagewheels-nopypi-norequirements -[testenv] -deps = - !norequirements: -rrequirements.txt - # tox 3.x does not handle extras when using --installpkg. https://github.com/tox-dev/tox/issues/1576 - sagemath-repl - -extras = test +requires = + # Auto-provision a modern tox. + # [pkgenv] added in 4.2 - https://tox.wiki/en/latest/upgrading.html#packaging-configuration-and-inheritance + tox>=4.2 +[pkgenv] +# Environment in which to build the sdist. +# https://tox.wiki/en/latest/upgrading.html#packaging-environments passenv = # Variables set by .homebrew-build-env CPATH @@ -32,36 +32,73 @@ passenv = sagewheels: SAGE_SPKG_WHEELS setenv = - # Sage scripts such as sage-runtests like to use $HOME/.sage - HOME={envdir} # We supply pip options by environment variables so that they # apply both to the installation of the dependencies and of the package sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} nopypi: PIP_NO_INDEX=true +[testenv] +deps = + !norequirements: -rrequirements.txt + +extras = test + +passenv = {[pkgenv]passenv} + +setenv = {[pkgenv]setenv} + # Sage scripts such as sage-runtests like to use $HOME/.sage + HOME={envdir} + allowlist_externals = bash commands = - # Beware of the treacherous non-src layout. "./sage/" shadows the install sage package. + # Beware of the treacherous non-src layout. "./sage/" shadows the installed sage package. {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); import sage.cpython.builtin_types, sage.cpython.cython_metaclass, sage.cpython.debug, sage.structure.all, sage.categories.all' # Test that importing sage.categories.all initializes categories {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); from sage.categories.all import *; SimplicialComplexes(); FunctionFields()' - bash -c 'cd {temp_dir} && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --initial --environment=sage.all__sagemath_categories --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' + bash -c 'cd $(python -c "import sys; \"\" in sys.path and sys.path.remove(\"\"); from sage.env import SAGE_LIB; print(SAGE_LIB)") \ + && sage-runtests -p --initial --environment=sage.all__sagemath_categories --probe all --baseline-stats-path={toxinidir}/known-test-failures.json --optional=sage --installed' + +[testenv:.tox] +# Allow access to PyPI for auto-provisioning a suitable tox version +passenv = +setenv = PIP_NO_INDEX=false + +[testenv:.pkg-sagepython] +# Environment in which to build the sdist. +# inherits from [pkgenv] - https://tox.wiki/en/latest/upgrading.html#packaging-environments +basepython = {env:SAGE_VENV}/bin/python3 + +[testenv:.pkg-sagepython-sagewheels-nopypi] +passenv = {[pkgenv]passenv} + SAGE_VENV + SAGE_SPKG_WHEELS + +setenv = {[pkgenv]setenv} + PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + PIP_NO_INDEX=true + +basepython = {env:SAGE_VENV}/bin/python3 [testenv:sagepython] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython [testenv:sagepython-sagewheels-nopypi] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-sagewheels-nopypi [testenv:sagepython-sagewheels-nopypi-norequirements] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-sagewheels-nopypi [testenv:sagepython-sagewheels] -basepython = {env:SAGE_VENV}/bin/python3 +basepython = {env:SAGE_VENV}/bin/python +package_env = .pkg-sagepython [testenv:sagepython-norequirements] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython diff --git a/pkgs/sagemath-coxeter3/MANIFEST.in b/pkgs/sagemath-coxeter3/MANIFEST.in new file mode 100644 index 00000000000..a69f2e71363 --- /dev/null +++ b/pkgs/sagemath-coxeter3/MANIFEST.in @@ -0,0 +1,20 @@ +prune sage + +include VERSION.txt + +graft sage/libs/coxeter3 + +global-exclude *.c +global-exclude *.cpp + +global-exclude all__sagemath_*.* +global-include all__sagemath_coxeter3.py + +global-exclude __pycache__ +global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-coxeter3/README.rst b/pkgs/sagemath-coxeter3/README.rst new file mode 100644 index 00000000000..8b605bda499 --- /dev/null +++ b/pkgs/sagemath-coxeter3/README.rst @@ -0,0 +1,31 @@ +==================================================================================================================== + Sage: Open Source Mathematics Software: Coxeter groups, Bruhat ordering, Kazhdan-Lusztig polynomials with coxeter3 +==================================================================================================================== + +About SageMath +-------------- + + "Creating a Viable Open Source Alternative to + Magma, Maple, Mathematica, and MATLAB" + + Copyright (C) 2005-2023 The Sage Development Team + + https://www.sagemath.org + +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). + +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). + + +About this pip-installable source distribution +---------------------------------------------- + +This pip-installable source distribution ``sagemath-coxeter3`` is a small +optional distribution for use with ``sagemath-standard``. + +It provides a Cython interface to the ``coxeter3`` library. diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt new file mode 100644 index 00000000000..7786f0e63e4 --- /dev/null +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -0,0 +1 @@ +10.2.beta5 diff --git a/pkgs/sagemath-coxeter3/pyproject.toml.m4 b/pkgs/sagemath-coxeter3/pyproject.toml.m4 new file mode 100644 index 00000000000..a7d65382b21 --- /dev/null +++ b/pkgs/sagemath-coxeter3/pyproject.toml.m4 @@ -0,0 +1,11 @@ +include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- +[build-system] +# Minimum requirements for the build system to execute. +requires = [ + SPKG_INSTALL_REQUIRES_setuptools_wheel + SPKG_INSTALL_REQUIRES_sage_setup + SPKG_INSTALL_REQUIRES_sagemath_environment + SPKG_INSTALL_REQUIRES_cython + SPKG_INSTALL_REQUIRES_cysignals +] +build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-coxeter3/requirements.txt.m4 b/pkgs/sagemath-coxeter3/requirements.txt.m4 new file mode 100644 index 00000000000..8b6ca03b0b9 --- /dev/null +++ b/pkgs/sagemath-coxeter3/requirements.txt.m4 @@ -0,0 +1,2 @@ +Cython==esyscmd(`printf $(sed "s/[.]p.*//;" ../cython/package-version.txt)') +sagemath-standard==esyscmd(`printf $(sed "s/[.]p.*//;" ../sagelib/package-version.txt)') diff --git a/pkgs/sagemath-coxeter3/sage b/pkgs/sagemath-coxeter3/sage new file mode 120000 index 00000000000..e0da5daa6f2 --- /dev/null +++ b/pkgs/sagemath-coxeter3/sage @@ -0,0 +1 @@ +../../src/sage \ No newline at end of file diff --git a/pkgs/sagemath-coxeter3/setup.cfg.m4 b/pkgs/sagemath-coxeter3/setup.cfg.m4 new file mode 100644 index 00000000000..ab3288d89ab --- /dev/null +++ b/pkgs/sagemath-coxeter3/setup.cfg.m4 @@ -0,0 +1,20 @@ +include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- +[metadata] +name = sagemath-coxeter3 +version = file: VERSION.txt +description = Sage: Open Source Mathematics Software: Coxeter groups, Bruhat ordering, Kazhdan-Lusztig polynomials with coxeter3 +long_description = file: README.rst +long_description_content_type = text/x-rst +include(`setup_cfg_metadata.m4')dnl' + +[options] +python_requires = >=3.8, <3.12 +install_requires = + +packages = + sage.libs.coxeter3 + +[options.package_data] +sage.libs.coxeter3 = + coxeter.pxd + decl.pxd diff --git a/pkgs/sagemath-coxeter3/setup.py b/pkgs/sagemath-coxeter3/setup.py new file mode 100644 index 00000000000..50d81893558 --- /dev/null +++ b/pkgs/sagemath-coxeter3/setup.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +from distutils import log +from setuptools import setup + +# Work around a Cython problem in Python 3.8.x on macOS +# https://github.com/cython/cython/issues/3262 +import os +if os.uname().sysname == 'Darwin': + import multiprocessing + multiprocessing.set_start_method('fork', force=True) + +# If build isolation is not in use and setuptools_scm is installed, +# then its file_finders entry point is invoked, which we don't need. +# Workaround from โ€‹https://github.com/pypa/setuptools_scm/issues/190#issuecomment-351181286 +try: + import setuptools_scm.integration + setuptools_scm.integration.find_files = lambda _: [] +except ImportError: + pass + +# PEP 517 builds do not have . in sys.path +import sys +sys.path.insert(0, os.path.dirname(__file__)) + +if len(sys.argv) > 1 and (sys.argv[1] == "sdist" or sys.argv[1] == "egg_info"): + sdist = True +else: + sdist = False + +if sdist: + cmdclass = {} +else: + from sage_setup.excepthook import excepthook + sys.excepthook = excepthook + + from sage_setup.setenv import setenv + setenv() + + import sage.env + sage.env.default_required_modules = sage.env.default_optional_modules = () + + from sage_setup.command.sage_build_cython import sage_build_cython + from sage_setup.command.sage_build_ext import sage_build_ext + sage_build_cython.built_distributions = ['sagemath-coxeter3'] + + cmdclass = dict(build_cython=sage_build_cython, + build_ext=sage_build_ext) + +from sage_setup.find import find_python_sources +python_packages, python_modules, cython_modules = find_python_sources( + '.', ['sage'], distributions=['sagemath-coxeter3']) + +log.warn('python_packages = {0}'.format(python_packages)) +log.warn('python_modules = {0}'.format(python_modules)) +log.warn('cython_modules = {0}'.format(cython_modules)) + +setup( + cmdclass = cmdclass, + packages = python_packages, + py_modules = python_modules, + ext_modules = cython_modules, +) diff --git a/pkgs/sagemath-environment/MANIFEST.in b/pkgs/sagemath-environment/MANIFEST.in index 36f8fae1845..ca4266e2bf4 100644 --- a/pkgs/sagemath-environment/MANIFEST.in +++ b/pkgs/sagemath-environment/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_environment.py - include sage/env.py include sage/version.py include sage/misc/package.py @@ -12,4 +10,14 @@ graft sage/features include VERSION.txt +global-exclude all__*.py +global-include all__sagemath_environment.py + +global-exclude __pycache__ global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-environment/README.rst b/pkgs/sagemath-environment/README.rst index ba5905777c0..eaeb4078fed 100644 --- a/pkgs/sagemath-environment/README.rst +++ b/pkgs/sagemath-environment/README.rst @@ -8,7 +8,7 @@ About SageMath "Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, and MATLAB" - Copyright (C) 2005-2022 The Sage Development Team + Copyright (C) 2005-2023 The Sage Development Team https://www.sagemath.org diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index 4ab501a9912..7786f0e63e4 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.0.beta1 +10.2.beta5 diff --git a/pkgs/sagemath-environment/pyproject.toml.m4 b/pkgs/sagemath-environment/pyproject.toml.m4 index 686515673fc..fb2db955ed5 100644 --- a/pkgs/sagemath-environment/pyproject.toml.m4 +++ b/pkgs/sagemath-environment/pyproject.toml.m4 @@ -1,8 +1,8 @@ +include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- [build-system] # Minimum requirements for the build system to execute. requires = [ - esyscmd(`sage-get-system-packages install-requires-toml \ - setuptools \ - wheel \ - ')] + SPKG_INSTALL_REQUIRES_setuptools_wheel + SPKG_INSTALL_REQUIRES_wheel +] build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-environment/setup.cfg.m4 b/pkgs/sagemath-environment/setup.cfg.m4 index 919a5b576cd..9e5bb31eeb7 100644 --- a/pkgs/sagemath-environment/setup.cfg.m4 +++ b/pkgs/sagemath-environment/setup.cfg.m4 @@ -1,35 +1,15 @@ -# -*- conf-unix -*- +include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- [metadata] name = sagemath-environment version = file: VERSION.txt description = Sage: Open Source Mathematics Software: System and software environment long_description = file: README.rst long_description_content_type = text/x-rst -license = GNU General Public License (GPL) v2 or later -author = The Sage Developers -author_email = sage-support@googlegroups.com -url = https://www.sagemath.org - -classifiers = - Development Status :: 6 - Mature - Intended Audience :: Education - Intended Audience :: Science/Research - License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) - Operating System :: POSIX - Operating System :: MacOS :: MacOS X - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: Implementation :: CPython - Topic :: Scientific/Engineering :: Mathematics +include(`setup_cfg_metadata.m4')dnl' [options] -python_requires = >=3.8, <3.12 +python_requires = >=3.9, <3.12 install_requires = - esyscmd(`sage-get-system-packages install-requires \ - | sed "2,\$s/^/ /;"')dnl py_modules = sage.all__sagemath_environment @@ -37,6 +17,7 @@ py_modules = sage.version sage.misc.all__sagemath_environment sage.misc.package + sage.misc.package_dir sage.misc.temporary_file sage.misc.viewer @@ -61,16 +42,25 @@ scripts = [options.extras_require] # sage.env can optionally use sage_conf -conf = esyscmd(`sage-get-system-packages install-requires sage_conf') +conf = SPKG_INSTALL_REQUIRES_sage_conf + # For "sage --docbuild" -docbuild = esyscmd(`sage-get-system-packages install-requires sage_docbuild') +docbuild = SPKG_INSTALL_REQUIRES_sage_docbuild + # For "sage", "sage -t", ... -sage = esyscmd(`sage-get-system-packages install-requires sagelib') +sage = SPKG_INSTALL_REQUIRES_sagelib + # For "sage --cython" -cython = esyscmd(`sage-get-system-packages install-requires cython') +cython = SPKG_INSTALL_REQUIRES_cython + # For "sage --pytest" -pytest = esyscmd(`sage-get-system-packages install-requires pytest') +pytest = SPKG_INSTALL_REQUIRES_pytest + # For "sage --rst2ipynb" -rst2ipynb = esyscmd(`sage-get-system-packages install-requires rst2ipynb') +rst2ipynb = SPKG_INSTALL_REQUIRES_rst2ipynb + +# For "sage --tox" +tox = SPKG_INSTALL_REQUIRES_tox + # For "sage --sws2rst" -sws2rst = esyscmd(`sage-get-system-packages install-requires sage_sws2rst') +sws2rst = SPKG_INSTALL_REQUIRES_sage_sws2rst diff --git a/pkgs/sagemath-environment/tox.ini b/pkgs/sagemath-environment/tox.ini index 46077bd8e27..ff2eef44f66 100644 --- a/pkgs/sagemath-environment/tox.ini +++ b/pkgs/sagemath-environment/tox.ini @@ -1,22 +1,28 @@ # To build and test in the tox environment: # -# ./sage -sh -c '(cd pkgs/sagemath-environment && tox -v -v -e sagepython)' +# ./sage -sh -c '(cd pkgs/sagemath-environment && tox -v -v -e sagepython-norequirements)' # # To test interactively: # -# pkgs/sagemath-environment/.tox/sagepython/bin/python +# pkgs/sagemath-environment/.tox/sagepython-norequirements/bin/python # [tox] envlist = - sagepython-norequirements + sagepython-sagewheels-nopypi-norequirements -isolated_build = True - -[testenv] -deps = - !norequirements: -rrequirements.txt +requires = + # Auto-provision a modern tox. + # [pkgenv] added in 4.2 - https://tox.wiki/en/latest/upgrading.html#packaging-configuration-and-inheritance + tox>=4.2 +[pkgenv] +# Environment in which to build the sdist. +# https://tox.wiki/en/latest/upgrading.html#packaging-environments passenv = + # Variables set by .homebrew-build-env + CPATH + LIBRARY_PATH + PKG_CONFIG_PATH # Parallel build SAGE_NUM_THREADS SAGE_NUM_THREADS_PARALLEL @@ -26,13 +32,23 @@ passenv = sagewheels: SAGE_SPKG_WHEELS setenv = - # Sage scripts such as sage-runtests like to use $HOME/.sage - HOME={envdir} # We supply pip options by environment variables so that they # apply both to the installation of the dependencies and of the package sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} nopypi: PIP_NO_INDEX=true +[testenv] +deps = + !norequirements: -rrequirements.txt + +extras = test + +passenv = {[pkgenv]passenv} + +setenv = {[pkgenv]setenv} + # Sage scripts such as sage-runtests like to use $HOME/.sage + HOME={envdir} + allowlist_externals = bash @@ -40,17 +56,44 @@ commands = # Beware of the treacherous non-src layout. "./sage/" shadows the installed sage package. {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); from sage.features.all import all_features; print(sorted(all_features(), key=lambda x: x.name)); import sage.misc.package' -[testenv:sagepython] +[testenv:.tox] +# Allow access to PyPI for auto-provisioning a suitable tox version +passenv = +setenv = PIP_NO_INDEX=false + +[testenv:.pkg-sagepython] +# Environment in which to build the sdist. +# inherits from [pkgenv] - https://tox.wiki/en/latest/upgrading.html#packaging-environments basepython = {env:SAGE_VENV}/bin/python3 -[testenv:sagepython-sagewheels-nopypi] +[testenv:.pkg-sagepython-sagewheels-nopypi] +passenv = {[pkgenv]passenv} + SAGE_VENV + SAGE_SPKG_WHEELS + +setenv = {[pkgenv]setenv} + PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + PIP_NO_INDEX=true + basepython = {env:SAGE_VENV}/bin/python3 -[testenv:sagepython-sagewheels-nopypi-norequirements] +[testenv:sagepython] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython -[testenv:sagepython-sagewheels] +[testenv:sagepython-sagewheels-nopypi] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-sagewheels-nopypi + +[testenv:sagepython-sagewheels] +basepython = {env:SAGE_VENV}/bin/python +package_env = .pkg-sagepython [testenv:sagepython-norequirements] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython + + +[testenv:sagepython-sagewheels-nopypi-norequirements] +basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-sagewheels-nopypi diff --git a/pkgs/sagemath-mcqd/MANIFEST.in b/pkgs/sagemath-mcqd/MANIFEST.in new file mode 100644 index 00000000000..801e1b3e48d --- /dev/null +++ b/pkgs/sagemath-mcqd/MANIFEST.in @@ -0,0 +1,20 @@ +prune sage + +include VERSION.txt + +include sage/graphs/mcqd.p* + +global-exclude *.c +global-exclude *.cpp + +global-exclude all__sagemath_*.* +global-include all__sagemath_mcqd.py + +global-exclude __pycache__ +global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-mcqd/README.rst b/pkgs/sagemath-mcqd/README.rst new file mode 100644 index 00000000000..00ef5f8ea3e --- /dev/null +++ b/pkgs/sagemath-mcqd/README.rst @@ -0,0 +1,33 @@ +=========================================================================== + Sage: Open Source Mathematics Software: Finding maximum cliques with mcqd +=========================================================================== + +About SageMath +-------------- + + "Creating a Viable Open Source Alternative to + Magma, Maple, Mathematica, and MATLAB" + + Copyright (C) 2005-2023 The Sage Development Team + + https://www.sagemath.org + +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). + +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). + + +About this pip-installable source distribution +---------------------------------------------- + +This pip-installable source distribution ``sagemath-mcqd`` is a small +optional distribution for use with ``sagemath-standard``. + +It provides a Cython interface to the ``mcqd`` library, +providing a fast exact algorithm for finding a maximum clique in +an undirected graph. diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt new file mode 100644 index 00000000000..7786f0e63e4 --- /dev/null +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -0,0 +1 @@ +10.2.beta5 diff --git a/pkgs/sagemath-mcqd/pyproject.toml.m4 b/pkgs/sagemath-mcqd/pyproject.toml.m4 new file mode 100644 index 00000000000..7e651119193 --- /dev/null +++ b/pkgs/sagemath-mcqd/pyproject.toml.m4 @@ -0,0 +1,12 @@ +include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- +[build-system] +# Minimum requirements for the build system to execute. +requires = [ + SPKG_INSTALL_REQUIRES_setuptools_wheel + SPKG_INSTALL_REQUIRES_sage_setup + SPKG_INSTALL_REQUIRES_sagemath_environment + SPKG_INSTALL_REQUIRES_cython + SPKG_INSTALL_REQUIRES_memory_allocator + SPKG_INSTALL_REQUIRES_cysignals +] +build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-mcqd/requirements.txt.m4 b/pkgs/sagemath-mcqd/requirements.txt.m4 new file mode 100644 index 00000000000..8b6ca03b0b9 --- /dev/null +++ b/pkgs/sagemath-mcqd/requirements.txt.m4 @@ -0,0 +1,2 @@ +Cython==esyscmd(`printf $(sed "s/[.]p.*//;" ../cython/package-version.txt)') +sagemath-standard==esyscmd(`printf $(sed "s/[.]p.*//;" ../sagelib/package-version.txt)') diff --git a/pkgs/sagemath-mcqd/sage b/pkgs/sagemath-mcqd/sage new file mode 120000 index 00000000000..e0da5daa6f2 --- /dev/null +++ b/pkgs/sagemath-mcqd/sage @@ -0,0 +1 @@ +../../src/sage \ No newline at end of file diff --git a/pkgs/sagemath-mcqd/setup.cfg.m4 b/pkgs/sagemath-mcqd/setup.cfg.m4 new file mode 100644 index 00000000000..fff8f2805ef --- /dev/null +++ b/pkgs/sagemath-mcqd/setup.cfg.m4 @@ -0,0 +1,21 @@ +include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- +[metadata] +name = sagemath-mcqd +version = file: VERSION.txt +description = Sage: Open Source Mathematics Software: Finding maximum cliques with mcqd +long_description = file: README.rst +long_description_content_type = text/x-rst +include(`setup_cfg_metadata.m4')dnl' + +[options] +python_requires = >=3.8, <3.12 +install_requires = + SPKG_INSTALL_REQUIRES_memory_allocator + SPKG_INSTALL_REQUIRES_cysignals + +packages = + sage.graphs + +[options.package_data] +sage.graphs = + mcqd.pxd diff --git a/pkgs/sagemath-mcqd/setup.py b/pkgs/sagemath-mcqd/setup.py new file mode 100644 index 00000000000..c7d90663bfc --- /dev/null +++ b/pkgs/sagemath-mcqd/setup.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +from distutils import log +from setuptools import setup + +# Work around a Cython problem in Python 3.8.x on macOS +# https://github.com/cython/cython/issues/3262 +import os +if os.uname().sysname == 'Darwin': + import multiprocessing + multiprocessing.set_start_method('fork', force=True) + +# If build isolation is not in use and setuptools_scm is installed, +# then its file_finders entry point is invoked, which we don't need. +# Workaround from โ€‹https://github.com/pypa/setuptools_scm/issues/190#issuecomment-351181286 +try: + import setuptools_scm.integration + setuptools_scm.integration.find_files = lambda _: [] +except ImportError: + pass + +# PEP 517 builds do not have . in sys.path +import sys +sys.path.insert(0, os.path.dirname(__file__)) + +if len(sys.argv) > 1 and (sys.argv[1] == "sdist" or sys.argv[1] == "egg_info"): + sdist = True +else: + sdist = False + +if sdist: + cmdclass = {} +else: + from sage_setup.excepthook import excepthook + sys.excepthook = excepthook + + from sage_setup.setenv import setenv + setenv() + + import sage.env + sage.env.default_required_modules = sage.env.default_optional_modules = () + + from sage_setup.command.sage_build_cython import sage_build_cython + from sage_setup.command.sage_build_ext import sage_build_ext + sage_build_cython.built_distributions = ['sagemath-mcqd'] + + cmdclass = dict(build_cython=sage_build_cython, + build_ext=sage_build_ext) + +from sage_setup.find import find_python_sources +python_packages, python_modules, cython_modules = find_python_sources( + '.', ['sage'], distributions=['sagemath-mcqd']) + +log.warn('python_packages = {0}'.format(python_packages)) +log.warn('python_modules = {0}'.format(python_modules)) +log.warn('cython_modules = {0}'.format(cython_modules)) + +setup( + cmdclass = cmdclass, + packages = python_packages, + py_modules = python_modules, + ext_modules = cython_modules, +) diff --git a/pkgs/sagemath-meataxe/MANIFEST.in b/pkgs/sagemath-meataxe/MANIFEST.in new file mode 100644 index 00000000000..c69ce68fc40 --- /dev/null +++ b/pkgs/sagemath-meataxe/MANIFEST.in @@ -0,0 +1,21 @@ +prune sage + +include VERSION.txt + +include sage/libs/meataxe.p* +include sage/matrix/matrix_gfpn_dense.p* + +global-exclude *.c +global-exclude *.cpp + +global-exclude all__sagemath_*.* +global-include all__sagemath_meataxe.py + +global-exclude __pycache__ +global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-meataxe/README.rst b/pkgs/sagemath-meataxe/README.rst new file mode 100644 index 00000000000..659edb3cf9f --- /dev/null +++ b/pkgs/sagemath-meataxe/README.rst @@ -0,0 +1,36 @@ +======================================================================================== + Sage: Open Source Mathematics Software: Matrices over small finite fields with meataxe +======================================================================================== + +About SageMath +-------------- + + "Creating a Viable Open Source Alternative to + Magma, Maple, Mathematica, and MATLAB" + + Copyright (C) 2005-2023 The Sage Development Team + + https://www.sagemath.org + +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). + +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). + + +About this pip-installable source distribution +---------------------------------------------- + +This pip-installable source distribution ``sagemath-meataxe`` is a small +optional distribution for use with ``sagemath-standard``. + +This distribution provides the SageMath modules ``sage.libs.meataxe`` +and ``sage.matrix.matrix_gfpn_dense``. + +It provides a specialized implementation of matrices over the finite field F_q, where +q <= 255, using the `SharedMeatAxe <http://users.minet.uni-jena.de/~king/SharedMeatAxe/>` +library. diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt new file mode 100644 index 00000000000..7786f0e63e4 --- /dev/null +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -0,0 +1 @@ +10.2.beta5 diff --git a/pkgs/sagemath-meataxe/pyproject.toml.m4 b/pkgs/sagemath-meataxe/pyproject.toml.m4 new file mode 100644 index 00000000000..a7d65382b21 --- /dev/null +++ b/pkgs/sagemath-meataxe/pyproject.toml.m4 @@ -0,0 +1,11 @@ +include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- +[build-system] +# Minimum requirements for the build system to execute. +requires = [ + SPKG_INSTALL_REQUIRES_setuptools_wheel + SPKG_INSTALL_REQUIRES_sage_setup + SPKG_INSTALL_REQUIRES_sagemath_environment + SPKG_INSTALL_REQUIRES_cython + SPKG_INSTALL_REQUIRES_cysignals +] +build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-meataxe/requirements.txt.m4 b/pkgs/sagemath-meataxe/requirements.txt.m4 new file mode 100644 index 00000000000..8b6ca03b0b9 --- /dev/null +++ b/pkgs/sagemath-meataxe/requirements.txt.m4 @@ -0,0 +1,2 @@ +Cython==esyscmd(`printf $(sed "s/[.]p.*//;" ../cython/package-version.txt)') +sagemath-standard==esyscmd(`printf $(sed "s/[.]p.*//;" ../sagelib/package-version.txt)') diff --git a/pkgs/sagemath-meataxe/sage b/pkgs/sagemath-meataxe/sage new file mode 120000 index 00000000000..e0da5daa6f2 --- /dev/null +++ b/pkgs/sagemath-meataxe/sage @@ -0,0 +1 @@ +../../src/sage \ No newline at end of file diff --git a/pkgs/sagemath-meataxe/setup.cfg.m4 b/pkgs/sagemath-meataxe/setup.cfg.m4 new file mode 100644 index 00000000000..a558825e120 --- /dev/null +++ b/pkgs/sagemath-meataxe/setup.cfg.m4 @@ -0,0 +1,22 @@ +include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- +[metadata] +name = sagemath-meataxe +version = file: VERSION.txt +description = Sage: Open Source Mathematics Software: Matrices over small finite fields with meataxe +long_description = file: README.rst +long_description_content_type = text/x-rst +include(`setup_cfg_metadata.m4')dnl' + +[options] +python_requires = >=3.8, <3.12 + +packages = + sage.libs + sage.matrix + +[options.package_data] +sage.libs = + meataxe.pxd + +sage.matrix = + matrix_gfpn_dense.pxd diff --git a/pkgs/sagemath-meataxe/setup.py b/pkgs/sagemath-meataxe/setup.py new file mode 100644 index 00000000000..638c921a0d3 --- /dev/null +++ b/pkgs/sagemath-meataxe/setup.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +from distutils import log +from setuptools import setup + +# Work around a Cython problem in Python 3.8.x on macOS +# https://github.com/cython/cython/issues/3262 +import os +if os.uname().sysname == 'Darwin': + import multiprocessing + multiprocessing.set_start_method('fork', force=True) + +# If build isolation is not in use and setuptools_scm is installed, +# then its file_finders entry point is invoked, which we don't need. +# Workaround from โ€‹https://github.com/pypa/setuptools_scm/issues/190#issuecomment-351181286 +try: + import setuptools_scm.integration + setuptools_scm.integration.find_files = lambda _: [] +except ImportError: + pass + +# PEP 517 builds do not have . in sys.path +import sys +sys.path.insert(0, os.path.dirname(__file__)) + +if len(sys.argv) > 1 and (sys.argv[1] == "sdist" or sys.argv[1] == "egg_info"): + sdist = True +else: + sdist = False + +if sdist: + cmdclass = {} +else: + from sage_setup.excepthook import excepthook + sys.excepthook = excepthook + + from sage_setup.setenv import setenv + setenv() + + import sage.env + sage.env.default_required_modules = sage.env.default_optional_modules = () + + from sage_setup.command.sage_build_cython import sage_build_cython + from sage_setup.command.sage_build_ext import sage_build_ext + sage_build_cython.built_distributions = ['sagemath-meataxe'] + + cmdclass = dict(build_cython=sage_build_cython, + build_ext=sage_build_ext) + +from sage_setup.find import find_python_sources +python_packages, python_modules, cython_modules = find_python_sources( + '.', ['sage'], distributions=['sagemath-meataxe']) + +log.warn('python_packages = {0}'.format(python_packages)) +log.warn('python_modules = {0}'.format(python_modules)) +log.warn('cython_modules = {0}'.format(cython_modules)) + +setup( + cmdclass = cmdclass, + packages = python_packages, + py_modules = python_modules, + ext_modules = cython_modules, +) diff --git a/pkgs/sagemath-objects/MANIFEST.in b/pkgs/sagemath-objects/MANIFEST.in index eced95ea865..98b6910849a 100644 --- a/pkgs/sagemath-objects/MANIFEST.in +++ b/pkgs/sagemath-objects/MANIFEST.in @@ -3,8 +3,6 @@ graft sage/cpython include VERSION.txt -global-include all__sagemath_objects.py - graft sage/structure include sage/categories/action.* include sage/categories/algebra_functor.* @@ -82,8 +80,11 @@ graft sage/libs/gmp ## FIXME: Needed for doctesting -include sage/misc/misc.* # walltime, cputime used in sage.doctest +include sage/misc/misc.* # some_tuples used in sage.misc.sage_unittest +include sage/misc/timing.p* # walltime, cputime used in sage.doctest +global-exclude all__*.py +global-include all__sagemath_objects.py global-exclude *.c global-exclude *.cpp diff --git a/pkgs/sagemath-objects/README.rst b/pkgs/sagemath-objects/README.rst index 9dc9cfd888f..4426d8683a3 100644 --- a/pkgs/sagemath-objects/README.rst +++ b/pkgs/sagemath-objects/README.rst @@ -8,7 +8,7 @@ About SageMath "Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, and MATLAB" - Copyright (C) 2005-2022 The Sage Development Team + Copyright (C) 2005-2023 The Sage Development Team https://www.sagemath.org diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index 4ab501a9912..7786f0e63e4 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.0.beta1 +10.2.beta5 diff --git a/pkgs/sagemath-objects/pyproject.toml.m4 b/pkgs/sagemath-objects/pyproject.toml.m4 index c13665be51d..d8fda57a8f8 100644 --- a/pkgs/sagemath-objects/pyproject.toml.m4 +++ b/pkgs/sagemath-objects/pyproject.toml.m4 @@ -1,13 +1,13 @@ +include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- [build-system] # Minimum requirements for the build system to execute. requires = [ - esyscmd(`sage-get-system-packages install-requires-toml \ - setuptools \ - wheel \ - sage_setup \ - sagemath_environment \ - cython \ - gmpy2 \ - cysignals \ - ')] + SPKG_INSTALL_REQUIRES_setuptools_wheel + SPKG_INSTALL_REQUIRES_wheel + SPKG_INSTALL_REQUIRES_sage_setup + SPKG_INSTALL_REQUIRES_sagemath_environment + SPKG_INSTALL_REQUIRES_cython + SPKG_INSTALL_REQUIRES_gmpy2 + SPKG_INSTALL_REQUIRES_cysignals +] build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-objects/setup.cfg.m4 b/pkgs/sagemath-objects/setup.cfg.m4 index 88246c422f2..894c07b5bbf 100644 --- a/pkgs/sagemath-objects/setup.cfg.m4 +++ b/pkgs/sagemath-objects/setup.cfg.m4 @@ -5,33 +5,14 @@ version = file: VERSION.txt description = Sage: Open Source Mathematics Software: Sage objects, elements, parents, categories, coercion, metaclasses long_description = file: README.rst long_description_content_type = text/x-rst -license = GNU General Public License (GPL) v2 or later -author = The Sage Developers -author_email = sage-support@googlegroups.com -url = https://www.sagemath.org - -classifiers = - Development Status :: 6 - Mature - Intended Audience :: Education - Intended Audience :: Science/Research - License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) - Operating System :: POSIX - Operating System :: MacOS :: MacOS X - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: Implementation :: CPython - Topic :: Scientific/Engineering :: Mathematics +include(`setup_cfg_metadata.m4')dnl' [options] -python_requires = >=3.8, <3.12 +include(`sage_spkg_versions.m4')dnl' +python_requires = >=3.9, <3.12 install_requires = - esyscmd(`sage-get-system-packages install-requires \ - gmpy2 \ - cysignals \ - | sed "2,\$s/^/ /;"')dnl + SPKG_INSTALL_REQUIRES_gmpy2 + SPKG_INSTALL_REQUIRES_cysignals [options.extras_require] # Currently we do not use the sage doctester to test sagemath-objects, diff --git a/pkgs/sagemath-objects/tox.ini b/pkgs/sagemath-objects/tox.ini index e34531467e5..0ca92ea9570 100644 --- a/pkgs/sagemath-objects/tox.ini +++ b/pkgs/sagemath-objects/tox.ini @@ -1,21 +1,23 @@ # To build and test in the tox environment: # -# ./sage -sh -c '(cd pkgs/sagemath-objects && tox -v -v -e sagepython)' +# ./sage -sh -c '(cd pkgs/sagemath-objects && SAGE_NUM_THREADS=8 tox -v -v -e sagepython-norequirements)' # -# To test interactively: +# After this, to test interactively: # -# pkgs/sagemath-objects/.tox/sagepython/bin/python +# pkgs/sagemath-objects/.tox/sagepython-norequirements/bin/python # [tox] envlist = - sagepython-norequirements + sagepython-sagewheels-nopypi-norequirements -[testenv] -deps = - !norequirements: -rrequirements.txt - -extras = test +requires = + # Auto-provision a modern tox. + # [pkgenv] added in 4.2 - https://tox.wiki/en/latest/upgrading.html#packaging-configuration-and-inheritance + tox>=4.2 +[pkgenv] +# Environment in which to build the sdist. +# https://tox.wiki/en/latest/upgrading.html#packaging-environments passenv = # Variables set by .homebrew-build-env CPATH @@ -30,13 +32,23 @@ passenv = sagewheels: SAGE_SPKG_WHEELS setenv = - # Sage scripts such as sage-runtests like to use $HOME/.sage - HOME={envdir} # We supply pip options by environment variables so that they # apply both to the installation of the dependencies and of the package sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} nopypi: PIP_NO_INDEX=true +[testenv] +deps = + !norequirements: -rrequirements.txt + +extras = test + +passenv = {[pkgenv]passenv} + +setenv = {[pkgenv]setenv} + # Sage scripts such as sage-runtests like to use $HOME/.sage + HOME={envdir} + allowlist_externals = bash @@ -48,17 +60,44 @@ commands = #bash -c 'cd {temp_dir} && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_objects --initial --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' -[testenv:sagepython] +[testenv:.tox] +# Allow access to PyPI for auto-provisioning a suitable tox version +passenv = +setenv = PIP_NO_INDEX=false + +[testenv:.pkg-sagepython] +# Environment in which to build the sdist. +# inherits from [pkgenv] - https://tox.wiki/en/latest/upgrading.html#packaging-environments basepython = {env:SAGE_VENV}/bin/python3 -[testenv:sagepython-sagewheels-nopypi] +[testenv:.pkg-sagepython-sagewheels-nopypi] +passenv = {[pkgenv]passenv} + SAGE_VENV + SAGE_SPKG_WHEELS + +setenv = {[pkgenv]setenv} + PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + PIP_NO_INDEX=true + basepython = {env:SAGE_VENV}/bin/python3 -[testenv:sagepython-sagewheels-nopypi-norequirements] +[testenv:sagepython] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython -[testenv:sagepython-sagewheels] +[testenv:sagepython-sagewheels-nopypi] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-sagewheels-nopypi + +[testenv:sagepython-sagewheels] +basepython = {env:SAGE_VENV}/bin/python +package_env = .pkg-sagepython [testenv:sagepython-norequirements] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython + + +[testenv:sagepython-sagewheels-nopypi-norequirements] +basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-sagewheels-nopypi diff --git a/pkgs/sagemath-repl/MANIFEST.in b/pkgs/sagemath-repl/MANIFEST.in index c54f63b15ee..ba331ec2931 100644 --- a/pkgs/sagemath-repl/MANIFEST.in +++ b/pkgs/sagemath-repl/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_repl.py - graft sage/doctest graft sage/repl include sage/misc/banner.py @@ -11,6 +9,9 @@ include sage/misc/sage_eval.py include VERSION.txt +global-exclude all__*.py +global-include all__sagemath_repl.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-repl/README.rst b/pkgs/sagemath-repl/README.rst index 3dde4aae5e5..90b73be3cf5 100644 --- a/pkgs/sagemath-repl/README.rst +++ b/pkgs/sagemath-repl/README.rst @@ -8,7 +8,7 @@ About SageMath "Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, and MATLAB" - Copyright (C) 2005-2022 The Sage Development Team + Copyright (C) 2005-2023 The Sage Development Team https://www.sagemath.org diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index 4ab501a9912..7786f0e63e4 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.0.beta1 +10.2.beta5 diff --git a/pkgs/sagemath-repl/known-test-failures.json b/pkgs/sagemath-repl/known-test-failures.json new file mode 100644 index 00000000000..6703c0a50cf --- /dev/null +++ b/pkgs/sagemath-repl/known-test-failures.json @@ -0,0 +1,165 @@ +{ + "sage.doctest.control": { + "failed": true, + "ntests": 0 + }, + "sage.doctest.external": { + "ntests": 41 + }, + "sage.doctest.fixtures": { + "failed": true, + "ntests": 59 + }, + "sage.doctest.forker": { + "failed": true, + "ntests": 432 + }, + "sage.doctest.parsing": { + "failed": true, + "ntests": 316 + }, + "sage.doctest.reporting": { + "failed": true, + "ntests": 124 + }, + "sage.doctest.sources": { + "failed": true, + "ntests": 376 + }, + "sage.doctest.test": { + "ntests": 23 + }, + "sage.doctest.util": { + "failed": true, + "ntests": 141 + }, + "sage.misc.sage_eval": { + "failed": true, + "ntests": 28 + }, + "sage.misc.sage_input": { + "failed": true, + "ntests": 721 + }, + "sage.repl.attach": { + "ntests": 128 + }, + "sage.repl.configuration": { + "ntests": 22 + }, + "sage.repl.display.fancy_repr": { + "failed": true, + "ntests": 24 + }, + "sage.repl.display.formatter": { + "failed": true, + "ntests": 47 + }, + "sage.repl.display.jsmol_iframe": { + "ntests": 24 + }, + "sage.repl.display.pretty_print": { + "failed": true, + "ntests": 21 + }, + "sage.repl.display.util": { + "ntests": 6 + }, + "sage.repl.image": { + "failed": true, + "ntests": 42 + }, + "sage.repl.inputhook": { + "ntests": 7 + }, + "sage.repl.interface_magic": { + "failed": true, + "ntests": 11 + }, + "sage.repl.interpreter": { + "failed": true, + "ntests": 109 + }, + "sage.repl.ipython_extension": { + "failed": true, + "ntests": 72 + }, + "sage.repl.ipython_kernel.install": { + "failed": true, + "ntests": 40 + }, + "sage.repl.ipython_kernel.interact": { + "failed": true, + "ntests": 35 + }, + "sage.repl.ipython_kernel.kernel": { + "ntests": 12 + }, + "sage.repl.ipython_kernel.widgets": { + "failed": true, + "ntests": 91 + }, + "sage.repl.ipython_kernel.widgets_sagenb": { + "failed": true, + "ntests": 77 + }, + "sage.repl.ipython_tests": { + "failed": true, + "ntests": 20 + }, + "sage.repl.load": { + "failed": true, + "ntests": 41 + }, + "sage.repl.preparse": { + "failed": true, + "ntests": 343 + }, + "sage.repl.rich_output.backend_base": { + "failed": true, + "ntests": 96 + }, + "sage.repl.rich_output.backend_doctest": { + "ntests": 50 + }, + "sage.repl.rich_output.backend_emacs": { + "ntests": 15 + }, + "sage.repl.rich_output.backend_ipython": { + "failed": true, + "ntests": 75 + }, + "sage.repl.rich_output.buffer": { + "ntests": 49 + }, + "sage.repl.rich_output.display_manager": { + "failed": true, + "ntests": 85 + }, + "sage.repl.rich_output.output_basic": { + "ntests": 46 + }, + "sage.repl.rich_output.output_browser": { + "ntests": 12 + }, + "sage.repl.rich_output.output_graphics": { + "ntests": 38 + }, + "sage.repl.rich_output.output_graphics3d": { + "ntests": 46 + }, + "sage.repl.rich_output.output_video": { + "ntests": 25 + }, + "sage.repl.rich_output.preferences": { + "ntests": 68 + }, + "sage.repl.rich_output.pretty_print": { + "failed": true, + "ntests": 22 + }, + "sage.repl.rich_output.test_backend": { + "failed": true, + "ntests": 37 + } +} \ No newline at end of file diff --git a/pkgs/sagemath-repl/pyproject.toml.m4 b/pkgs/sagemath-repl/pyproject.toml.m4 index 686515673fc..fb2db955ed5 100644 --- a/pkgs/sagemath-repl/pyproject.toml.m4 +++ b/pkgs/sagemath-repl/pyproject.toml.m4 @@ -1,8 +1,8 @@ +include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- [build-system] # Minimum requirements for the build system to execute. requires = [ - esyscmd(`sage-get-system-packages install-requires-toml \ - setuptools \ - wheel \ - ')] + SPKG_INSTALL_REQUIRES_setuptools_wheel + SPKG_INSTALL_REQUIRES_wheel +] build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-repl/setup.cfg.m4 b/pkgs/sagemath-repl/setup.cfg.m4 index 2367fda7b9a..f71d7bf6c2a 100644 --- a/pkgs/sagemath-repl/setup.cfg.m4 +++ b/pkgs/sagemath-repl/setup.cfg.m4 @@ -1,39 +1,19 @@ -# -*- conf-unix -*- +include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- [metadata] name = sagemath-repl version = file: VERSION.txt description = Sage: Open Source Mathematics Software: System and software environment long_description = file: README.rst long_description_content_type = text/x-rst -license = GNU General Public License (GPL) v2 or later -author = The Sage Developers -author_email = sage-support@googlegroups.com -url = https://www.sagemath.org - -classifiers = - Development Status :: 6 - Mature - Intended Audience :: Education - Intended Audience :: Science/Research - License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) - Operating System :: POSIX - Operating System :: MacOS :: MacOS X - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: Implementation :: CPython - Topic :: Scientific/Engineering :: Mathematics +include(`setup_cfg_metadata.m4')dnl' [options] -python_requires = >=3.8, <3.12 +python_requires = >=3.9, <3.12 install_requires = - esyscmd(`sage-get-system-packages install-requires \ - sagemath_objects \ - sagemath_environment \ - ipython \ - ipywidgets \ - | sed "2,\$s/^/ /;"')dnl + SPKG_INSTALL_REQUIRES_sagemath_objects + SPKG_INSTALL_REQUIRES_sagemath_environment + SPKG_INSTALL_REQUIRES_ipython + SPKG_INSTALL_REQUIRES_ipywidgets py_modules = sage.all__sagemath_repl diff --git a/pkgs/sagemath-repl/tox.ini b/pkgs/sagemath-repl/tox.ini index 084016ce768..6944df002f5 100644 --- a/pkgs/sagemath-repl/tox.ini +++ b/pkgs/sagemath-repl/tox.ini @@ -1,21 +1,23 @@ # To build and test in the tox environment: # -# ./sage -sh -c '(cd pkgs/sagemath-repl && tox -v -v -e sagepython)' +# make SAGE_WHEELS=yes sagemath_repl-build-deps && ./sage -sh -c '(cd pkgs/sagemath-repl && SAGE_NUM_THREADS=8 tox -v -v -e sagepython-sagewheels-nopypi-norequirements)' # -# To test interactively: +# After this, to test interactively: # -# pkgs/sagemath-repl/.tox/sagepython/bin/python +# pkgs/sagemath-repl/.tox/sagepython-sagewheels-nopypi-norequirements/bin/python # [tox] envlist = - sagepython-norequirements + sagepython-sagewheels-nopypi-norequirements -isolated_build = True - -[testenv] -deps = - !norequirements: -rrequirements.txt +requires = + # Auto-provision a modern tox. + # [pkgenv] added in 4.2 - https://tox.wiki/en/latest/upgrading.html#packaging-configuration-and-inheritance + tox>=4.2 +[pkgenv] +# Environment in which to build the sdist. +# https://tox.wiki/en/latest/upgrading.html#packaging-environments passenv = # Variables set by .homebrew-build-env CPATH @@ -30,13 +32,23 @@ passenv = sagewheels: SAGE_SPKG_WHEELS setenv = - # Sage scripts such as sage-runtests like to use $HOME/.sage - HOME={envdir} # We supply pip options by environment variables so that they # apply both to the installation of the dependencies and of the package sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} nopypi: PIP_NO_INDEX=true +[testenv] +deps = + !norequirements: -rrequirements.txt + +extras = test + +passenv = {[pkgenv]passenv} + +setenv = {[pkgenv]setenv} + # Sage scripts such as sage-runtests like to use $HOME/.sage + HOME={envdir} + allowlist_externals = bash @@ -44,19 +56,45 @@ commands = # Beware of the treacherous non-src layout. "./sage/" shadows the installed sage package. {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); import sage.repl.all; import sage.doctest.all' - bash -c 'cd bin && SAGE_SRC=$({envpython} -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_repl --initial --optional=sage $SAGE_SRC/sage/repl $SAGE_SRC/sage/doctest $SAGE_SRC/sage/misc/sage_input.py $SAGE_SRC/sage/misc/sage_eval.py || echo "(lots of doctest failures are expected)"' + bash -c 'cd $({envpython} -c "import sys; \"\" in sys.path and sys.path.remove(\"\"); from sage.env import SAGE_LIB; print(SAGE_LIB)") && sage-runtests -p --environment=sage.all__sagemath_repl --baseline-stats-path={toxinidir}/known-test-failures.json --initial --optional=sage sage/repl sage/doctest sage/misc/sage_input.py sage/misc/sage_eval.py' + +[testenv:.tox] +# Allow access to PyPI for auto-provisioning a suitable tox version +passenv = +setenv = PIP_NO_INDEX=false + +[testenv:.pkg-sagepython] +# Environment in which to build the sdist. +# inherits from [pkgenv] - https://tox.wiki/en/latest/upgrading.html#packaging-environments +basepython = {env:SAGE_VENV}/bin/python3 + +[testenv:.pkg-sagepython-sagewheels-nopypi] +passenv = {[pkgenv]passenv} + SAGE_VENV + SAGE_SPKG_WHEELS + +setenv = {[pkgenv]setenv} + PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + PIP_NO_INDEX=true + +basepython = {env:SAGE_VENV}/bin/python3 [testenv:sagepython] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython [testenv:sagepython-sagewheels-nopypi] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-sagewheels-nopypi [testenv:sagepython-sagewheels-nopypi-norequirements] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-sagewheels-nopypi [testenv:sagepython-sagewheels] -basepython = {env:SAGE_VENV}/bin/python3 +basepython = {env:SAGE_VENV}/bin/python +package_env = .pkg-sagepython [testenv:sagepython-norequirements] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython diff --git a/pkgs/sagemath-sirocco/MANIFEST.in b/pkgs/sagemath-sirocco/MANIFEST.in new file mode 100644 index 00000000000..815a868524d --- /dev/null +++ b/pkgs/sagemath-sirocco/MANIFEST.in @@ -0,0 +1,16 @@ +include VERSION.txt + +global-exclude *.c +global-exclude *.cpp + +global-exclude all__sagemath_*.* +global-include all__sagemath_sirocco.py + +global-exclude __pycache__ +global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-sirocco/README.rst b/pkgs/sagemath-sirocco/README.rst new file mode 100644 index 00000000000..0207d63b9a5 --- /dev/null +++ b/pkgs/sagemath-sirocco/README.rst @@ -0,0 +1,32 @@ +================================================================================== + Sage: Open Source Mathematics Software: Certified root continuation with sirocco +================================================================================== + +About SageMath +-------------- + + "Creating a Viable Open Source Alternative to + Magma, Maple, Mathematica, and MATLAB" + + Copyright (C) 2005-2023 The Sage Development Team + + https://www.sagemath.org + +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). + +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). + + +About this pip-installable source distribution +---------------------------------------------- + +This pip-installable source distribution ``sagemath-sirocco`` is a small +optional distribution for use with ``sagemath-standard``. + +It provides a Cython interface to the ``sirocco`` library for the purpose +of compute topologically certified root continuation of bivariate polynomials. diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt new file mode 100644 index 00000000000..7786f0e63e4 --- /dev/null +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -0,0 +1 @@ +10.2.beta5 diff --git a/pkgs/sagemath-sirocco/pyproject.toml.m4 b/pkgs/sagemath-sirocco/pyproject.toml.m4 new file mode 100644 index 00000000000..99894dd5e5e --- /dev/null +++ b/pkgs/sagemath-sirocco/pyproject.toml.m4 @@ -0,0 +1,12 @@ +include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- +[build-system] +# Minimum requirements for the build system to execute. +requires = [ + SPKG_INSTALL_REQUIRES_setuptools_wheel + SPKG_INSTALL_REQUIRES_sage_setup + SPKG_INSTALL_REQUIRES_sagemath_environment + SPKG_INSTALL_REQUIRES_cython + SPKG_INSTALL_REQUIRES_cypari + SPKG_INSTALL_REQUIRES_cysignals +] +build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-sirocco/requirements.txt.m4 b/pkgs/sagemath-sirocco/requirements.txt.m4 new file mode 100644 index 00000000000..8b6ca03b0b9 --- /dev/null +++ b/pkgs/sagemath-sirocco/requirements.txt.m4 @@ -0,0 +1,2 @@ +Cython==esyscmd(`printf $(sed "s/[.]p.*//;" ../cython/package-version.txt)') +sagemath-standard==esyscmd(`printf $(sed "s/[.]p.*//;" ../sagelib/package-version.txt)') diff --git a/pkgs/sagemath-sirocco/sage b/pkgs/sagemath-sirocco/sage new file mode 120000 index 00000000000..e0da5daa6f2 --- /dev/null +++ b/pkgs/sagemath-sirocco/sage @@ -0,0 +1 @@ +../../src/sage \ No newline at end of file diff --git a/pkgs/sagemath-sirocco/setup.cfg.m4 b/pkgs/sagemath-sirocco/setup.cfg.m4 new file mode 100644 index 00000000000..4f1e0f03d95 --- /dev/null +++ b/pkgs/sagemath-sirocco/setup.cfg.m4 @@ -0,0 +1,14 @@ +include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- +[metadata] +name = sagemath-sirocco +version = file: VERSION.txt +description = Sage: Open Source Mathematics Software: Certified root continuation with sirocco +long_description = file: README.rst +long_description_content_type = text/x-rst +include(`setup_cfg_metadata.m4')dnl' + +[options] +python_requires = >=3.8, <3.12 +install_requires = + SPKG_INSTALL_REQUIRES_cypari + SPKG_INSTALL_REQUIRES_cysignals diff --git a/pkgs/sagemath-sirocco/setup.py b/pkgs/sagemath-sirocco/setup.py new file mode 100644 index 00000000000..bffe9189bb5 --- /dev/null +++ b/pkgs/sagemath-sirocco/setup.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +from distutils import log +from setuptools import setup + +# Work around a Cython problem in Python 3.8.x on macOS +# https://github.com/cython/cython/issues/3262 +import os +if os.uname().sysname == 'Darwin': + import multiprocessing + multiprocessing.set_start_method('fork', force=True) + +# If build isolation is not in use and setuptools_scm is installed, +# then its file_finders entry point is invoked, which we don't need. +# Workaround from โ€‹https://github.com/pypa/setuptools_scm/issues/190#issuecomment-351181286 +try: + import setuptools_scm.integration + setuptools_scm.integration.find_files = lambda _: [] +except ImportError: + pass + +# PEP 517 builds do not have . in sys.path +import sys +sys.path.insert(0, os.path.dirname(__file__)) + +if len(sys.argv) > 1 and (sys.argv[1] == "sdist" or sys.argv[1] == "egg_info"): + sdist = True +else: + sdist = False + +if sdist: + cmdclass = {} +else: + from sage_setup.excepthook import excepthook + sys.excepthook = excepthook + + from sage_setup.setenv import setenv + setenv() + + import sage.env + sage.env.default_required_modules = sage.env.default_optional_modules = () + + from sage_setup.command.sage_build_cython import sage_build_cython + from sage_setup.command.sage_build_ext import sage_build_ext + sage_build_cython.built_distributions = ['sagemath-sirocco'] + + cmdclass = dict(build_cython=sage_build_cython, + build_ext=sage_build_ext) + +from sage_setup.find import find_python_sources +python_packages, python_modules, cython_modules = find_python_sources( + '.', ['sage'], distributions=['sagemath-sirocco']) + +log.warn('python_packages = {0}'.format(python_packages)) +log.warn('python_modules = {0}'.format(python_modules)) +log.warn('cython_modules = {0}'.format(cython_modules)) + +setup( + cmdclass = cmdclass, + packages = python_packages, + py_modules = python_modules, + ext_modules = cython_modules, +) diff --git a/pkgs/sagemath-standard/setup.py b/pkgs/sagemath-standard/setup.py index 975f89b5905..7f6318a0fa0 100755 --- a/pkgs/sagemath-standard/setup.py +++ b/pkgs/sagemath-standard/setup.py @@ -76,15 +76,14 @@ # TODO: This should be quiet by default print("Discovering Python/Cython source code....") t = time.time() -distributions = [''] from sage.misc.package import is_package_installed_and_updated -optional_packages_with_extensions = ['mcqd', 'bliss', 'tdlib', - 'coxeter3', 'sirocco', 'meataxe'] +distributions = [''] +optional_packages_with_extensions = os.environ.get('SAGE_OPTIONAL_PACKAGES_WITH_EXTENSIONS', '').split(',') distributions += ['sagemath-{}'.format(pkg) for pkg in optional_packages_with_extensions if is_package_installed_and_updated(pkg)] log.warn('distributions = {0}'.format(distributions)) -from sage_setup.find import find_python_sources, find_extra_files +from sage_setup.find import find_python_sources python_packages, python_modules, cython_modules = find_python_sources( SAGE_SRC, ['sage'], distributions=distributions) diff --git a/pkgs/sagemath-standard/tox.ini b/pkgs/sagemath-standard/tox.ini index 305eddd7586..c14f97f8bbf 100644 --- a/pkgs/sagemath-standard/tox.ini +++ b/pkgs/sagemath-standard/tox.ini @@ -1,7 +1,3 @@ -# First install tox: -# -# ./sage -i tox -# # All tests require an installation of the non-Python components of the Sage distribution # in SAGE_LOCAL. # @@ -20,23 +16,20 @@ # [tox] envlist = - # - # SUPPORTED ENVIRONMENTS: - # - # Build dependencies according to requirements.txt (all versions fixed). - # Use ONLY the wheels built and stored by the Sage distribution (no PyPI): - # - # ./sage -sh -c '(cd pkgs/sagemath-standard && tox -v -v -v -e sagepython-sagewheels-nopypi)' - # - sagepython-sagewheels-nopypi, - # # Build and test without using the concrete dependencies specified by requirements.txt, # using the dependencies declared in pyproject.toml and setup.cfg (install-requires) only: # Still use ONLY the wheels built and stored by the Sage distribution (no PyPI). # # ./sage -sh -c '(cd pkgs/sagemath-standard && tox -v -v -v -e sagepython-sagewheels-nopypi-norequirements)' # - sagepython-sagewheels-nopypi-norequirements, + sagepython-sagewheels-nopypi-norequirements + # + # OTHER SUPPORTED ENVIRONMENTS: + # + # Build dependencies according to requirements.txt (all versions fixed). + # Use ONLY the wheels built and stored by the Sage distribution (no PyPI): + # + # ./sage -sh -c '(cd pkgs/sagemath-standard && tox -v -v -v -e sagepython-sagewheels-nopypi)' # # EXPERIMENTAL ENVIRONMENTS: # @@ -47,12 +40,10 @@ envlist = # # ./sage -sh -c '(cd pkgs/sagemath-standard && tox -v -v -v -e sagepython-sagewheels)' # - sagepython-sagewheels, - # # Likewise, but using pipenv using Pipfile-dist (= SAGE_ROOT/Pipfile). # This also fixes the concrete dependencies (at least for some packages). # - sagepython-sagewheels-pipenv-dist, + # ./sage -sh -c '(cd pkgs/sagemath-standard && tox -v -v -v -e sagepython-sagewheels-pipenv-dist)' # # Build using the dependencies declared in pyproject.toml and setup.cfg (install-requires) only. # Use the wheels built and stored by the Sage distribution, @@ -61,20 +52,21 @@ envlist = # Because the version ranges will allow for packages to come in from PyPI (in source or wheel form), # this is likely to fail because we do not have control over the configuration of these packages. # - sagepython-sagewheels-norequirements, + # ./sage -sh -c '(cd pkgs/sagemath-standard && tox -v -v -v -e sagepython-sagewheels-norequirements)' # # Likewise, but using pipenv # - sagepython-sagewheels-pipenv + # ./sage -sh -c '(cd pkgs/sagemath-standard && tox -v -v -v -e sagepython-sagewheels-pipenv)' + # -[testenv] -deps = - pipenv: pipenv - !pipenv-!norequirements: -rrequirements.txt - ## Needed for fpylll - norequirements: Cython - norequirements: cysignals +requires = + # Auto-provision a modern tox. + # [pkgenv] added in 4.2 - https://tox.wiki/en/latest/upgrading.html#packaging-configuration-and-inheritance + tox>=4.2 +[pkgenv] +# Environment in which to build the sdist. +# https://tox.wiki/en/latest/upgrading.html#packaging-environments passenv = # Variables set by .homebrew-build-env CPATH @@ -82,14 +74,13 @@ passenv = PKG_CONFIG_PATH # Parallel build SAGE_NUM_THREADS + SAGE_NUM_THREADS_PARALLEL # SAGE_VENV only for referring to the basepython or finding the wheels sagepython, sagewheels: SAGE_VENV # Location of the wheels sagewheels: SAGE_SPKG_WHEELS setenv = - # Sage scripts such as sage-runtests like to use $HOME/.sage - HOME={envdir} # We supply pip options by environment variables so that they # apply both to the installation of the dependencies and of the package sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} @@ -103,50 +94,87 @@ setenv = # so we cannot isolate it in the tox environment. pipenv: PIPENV_SKIP_LOCK=true +[testenv] +deps = + pipenv: pipenv + !pipenv-!norequirements: -rrequirements.txt + ## Needed for fpylll + norequirements: Cython + norequirements: cysignals + sitepackages = sitepackages: True !sitepackages: False +extras = test + +passenv = {[pkgenv]passenv} + +setenv = {[pkgenv]setenv} + # Sage scripts such as sage-runtests like to use $HOME/.sage + HOME={envdir} + allowlist_externals = bash -skip_install = - pipenv: True - !pipenv: False - -commands_pre = - # Use Pipenv to install according to Pipfile into the virtual environment created by tox. - # https://pipenv-searchable.readthedocs.io/advanced.html#tox-automation-project - pipenv-!dist: pipenv install -v -v -v - # Same, but use $SAGE_ROOT/Pipfile - pipenv-dist: bash -c '(cd ../../../.. && pipenv install -v -v -v)' +# Beware of the treacherous non-src layout. "./sage/" shadows the installed sage package. +# So we change to another directory when running commands. +change_dir = {env_tmp_dir} commands = - # Beware of the treacherous non-src layout. "./sage/" shadows the installed sage package. - python -c 'import sys; "" in sys.path and sys.path.remove(""); import sage.all; print(sage.all.__file__)' + python -c 'import sage.all; print(sage.all.__file__)' # We check that the "sage" script invokes the correct Python. sage -c 'import sys; print("sys.path =", sys.path); import sage.all; print(sage.all.__file__)' sage -t -p --all -[testenv:sagepython] +[testenv:.tox] +# Allow access to PyPI for auto-provisioning a suitable tox version +passenv = +setenv = PIP_NO_INDEX=false + +[testenv:.pkg-sagepython] +# Environment in which to build the sdist. +# inherits from [pkgenv] - https://tox.wiki/en/latest/upgrading.html#packaging-environments basepython = {env:SAGE_VENV}/bin/python3 -[testenv:sagepython-sagewheels-nopypi] +[testenv:.pkg-sagepython-sagewheels-nopypi] +passenv = {[pkgenv]passenv} + SAGE_VENV + SAGE_SPKG_WHEELS + +setenv = {[pkgenv]setenv} + PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + PIP_NO_INDEX=true + basepython = {env:SAGE_VENV}/bin/python3 -[testenv:sagepython-sagewheels-nopypi-norequirements] +[testenv:sagepython] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython + +[testenv:sagepython-sagewheels-nopypi] +basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-sagewheels-nopypi [testenv:sagepython-sagewheels] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython [testenv:sagepython-sagewheels-pipenv-dist] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython [testenv:sagepython-sagewheels-norequirements] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython [testenv:sagepython-sagewheels-pipenv] basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython + + +[testenv:sagepython-sagewheels-nopypi-norequirements] +basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-sagewheels-nopypi diff --git a/pkgs/sagemath-tdlib/MANIFEST.in b/pkgs/sagemath-tdlib/MANIFEST.in new file mode 100644 index 00000000000..614186d89ab --- /dev/null +++ b/pkgs/sagemath-tdlib/MANIFEST.in @@ -0,0 +1,18 @@ +include VERSION.txt + +global-exclude *.c +global-exclude *.cpp + +include sage/graphs/graph_decompositions/sage_tdlib.cpp + +global-exclude all__sagemath_*.* +global-include all__sagemath_tdlib.py + +global-exclude __pycache__ +global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-tdlib/README.rst b/pkgs/sagemath-tdlib/README.rst new file mode 100644 index 00000000000..0c91ddcf1c6 --- /dev/null +++ b/pkgs/sagemath-tdlib/README.rst @@ -0,0 +1,32 @@ +======================================================================== + Sage: Open Source Mathematics Software: Tree decompositions with tdlib +======================================================================== + +About SageMath +-------------- + + "Creating a Viable Open Source Alternative to + Magma, Maple, Mathematica, and MATLAB" + + Copyright (C) 2005-2023 The Sage Development Team + + https://www.sagemath.org + +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). + +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). + + +About this pip-installable source distribution +---------------------------------------------- + +This pip-installable source distribution ``sagemath-tdlib`` is a small +optional distribution for use with ``sagemath-standard``. + +It provides a Cython interface to the ``tdlib`` library, providing +algorithms concerning tree decompositions. diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt new file mode 100644 index 00000000000..7786f0e63e4 --- /dev/null +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -0,0 +1 @@ +10.2.beta5 diff --git a/pkgs/sagemath-tdlib/pyproject.toml.m4 b/pkgs/sagemath-tdlib/pyproject.toml.m4 new file mode 100644 index 00000000000..a7d65382b21 --- /dev/null +++ b/pkgs/sagemath-tdlib/pyproject.toml.m4 @@ -0,0 +1,11 @@ +include(`sage_spkg_versions_toml.m4')dnl' -*- conf-toml -*- +[build-system] +# Minimum requirements for the build system to execute. +requires = [ + SPKG_INSTALL_REQUIRES_setuptools_wheel + SPKG_INSTALL_REQUIRES_sage_setup + SPKG_INSTALL_REQUIRES_sagemath_environment + SPKG_INSTALL_REQUIRES_cython + SPKG_INSTALL_REQUIRES_cysignals +] +build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-tdlib/requirements.txt.m4 b/pkgs/sagemath-tdlib/requirements.txt.m4 new file mode 100644 index 00000000000..8b6ca03b0b9 --- /dev/null +++ b/pkgs/sagemath-tdlib/requirements.txt.m4 @@ -0,0 +1,2 @@ +Cython==esyscmd(`printf $(sed "s/[.]p.*//;" ../cython/package-version.txt)') +sagemath-standard==esyscmd(`printf $(sed "s/[.]p.*//;" ../sagelib/package-version.txt)') diff --git a/pkgs/sagemath-tdlib/sage b/pkgs/sagemath-tdlib/sage new file mode 120000 index 00000000000..e0da5daa6f2 --- /dev/null +++ b/pkgs/sagemath-tdlib/sage @@ -0,0 +1 @@ +../../src/sage \ No newline at end of file diff --git a/pkgs/sagemath-tdlib/setup.cfg.m4 b/pkgs/sagemath-tdlib/setup.cfg.m4 new file mode 100644 index 00000000000..62833bbe6f6 --- /dev/null +++ b/pkgs/sagemath-tdlib/setup.cfg.m4 @@ -0,0 +1,12 @@ +include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- +[metadata] +name = sagemath-tdlib +version = file: VERSION.txt +description = Sage: Open Source Mathematics Software: Tree decompositions with tdlib +long_description = file: README.rst +long_description_content_type = text/x-rst +include(`setup_cfg_metadata.m4')dnl' + +[options] +python_requires = >=3.8, <3.12 +install_requires = SPKG_INSTALL_REQUIRES_cysignals diff --git a/pkgs/sagemath-tdlib/setup.py b/pkgs/sagemath-tdlib/setup.py new file mode 100644 index 00000000000..12547533309 --- /dev/null +++ b/pkgs/sagemath-tdlib/setup.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +from distutils import log +from setuptools import setup + +# Work around a Cython problem in Python 3.8.x on macOS +# https://github.com/cython/cython/issues/3262 +import os +if os.uname().sysname == 'Darwin': + import multiprocessing + multiprocessing.set_start_method('fork', force=True) + +# If build isolation is not in use and setuptools_scm is installed, +# then its file_finders entry point is invoked, which we don't need. +# Workaround from โ€‹https://github.com/pypa/setuptools_scm/issues/190#issuecomment-351181286 +try: + import setuptools_scm.integration + setuptools_scm.integration.find_files = lambda _: [] +except ImportError: + pass + +# PEP 517 builds do not have . in sys.path +import sys +sys.path.insert(0, os.path.dirname(__file__)) + +if len(sys.argv) > 1 and (sys.argv[1] == "sdist" or sys.argv[1] == "egg_info"): + sdist = True +else: + sdist = False + +if sdist: + cmdclass = {} +else: + from sage_setup.excepthook import excepthook + sys.excepthook = excepthook + + from sage_setup.setenv import setenv + setenv() + + import sage.env + sage.env.default_required_modules = sage.env.default_optional_modules = () + + from sage_setup.command.sage_build_cython import sage_build_cython + from sage_setup.command.sage_build_ext import sage_build_ext + sage_build_cython.built_distributions = ['sagemath-tdlib'] + + cmdclass = dict(build_cython=sage_build_cython, + build_ext=sage_build_ext) + +from sage_setup.find import find_python_sources +python_packages, python_modules, cython_modules = find_python_sources( + '.', ['sage'], distributions=['sagemath-tdlib']) + +log.warn('python_packages = {0}'.format(python_packages)) +log.warn('python_modules = {0}'.format(python_modules)) +log.warn('cython_modules = {0}'.format(cython_modules)) + +setup( + cmdclass = cmdclass, + packages = python_packages, + py_modules = python_modules, + ext_modules = cython_modules, +) diff --git a/src/.relint.yml b/src/.relint.yml index 86684ad1040..97bf2ac1dbc 100644 --- a/src/.relint.yml +++ b/src/.relint.yml @@ -6,8 +6,8 @@ - name: 'python3: Python3 incompatible code' hint: | # ifilter, imap, izip # __metaclass__ - Hint: # update raise statements # except Exception, var - Hint: # six is no longer allowed + # update raise statements # except Exception, var + # six is no longer allowed pattern: '(import.*[, ]ifilter|import.*[, ]imap|import.*[, ]izip|^\s*raise\s*[A-Za-z]*Error\s*,|__metaclass__|except\s*[A-Za-z]\s*,|import six|from six import)' filePattern: .*[.](py|pyx|rst) @@ -20,9 +20,9 @@ - name: 'blocks: wrong syntax for blocks (INPUT, OUTPUT, EXAMPLES, NOTE, etc.)' hint: | # the correct syntax is .. SEEALSO:: - Hint: # TESTS and EXAMPLES should be plural, NOTE singular - Hint: # no :: after INPUT, OUTPUT, REFERENCE blocks - Hint: # no " :" at the end of lines + # TESTS and EXAMPLES should be plural, NOTE singular + # no :: after INPUT, OUTPUT, REFERENCE blocks + # no " :" at the end of lines pattern: '(\.\.SEE|SEE ALSO|SEEALSO:($|[^:])|^\s*TEST:|^\s*EXAMPLE:|^\s*NOTES:|^\s*[A-Z]*PUT::|^\s*REFERENCES?::$)' - name: 'trac_links: bad trac link' @@ -46,9 +46,29 @@ - name: 'namespace_pkg_all_import: import from .all of a namespace package' hint: | Sage library code should not import from sage.PAC.KAGE.all when sage.PAC.KAGE is an implicit - Hint: namespace package. Type import_statements("SOME_IDENTIFIER") to find a more specific import, - Hint: or use 'sage --fiximports' to fix automatically in the source file. + namespace package. Type import_statements("SOME_IDENTIFIER") to find a more specific import, + or use 'sage --fiximports' to fix automatically in the source file. # Keep in sync with SAGE_ROOT/src/sage/misc/replace_dot_all.py - pattern: 'from\s+sage(|[.](arith|categories|combinat|ext|graphs(|[.]decompositions)|interfaces|libs|matrix|misc|numerical(|[.]backends)|rings|sets))[.]all\s+import' - filePattern: '.*[.](py|pyx|pxi)$' - error: false # Make this a warning instead of an error for now + pattern: 'from\s+sage(|[.](arith|categories|combinat|crypto|databases|data_structures|dynamics|ext|game_theory|games|geometry|graphs|groups|interfaces|manifolds|matrix|matroids|misc|modules|monoids|numerical|probability|quadratic_forms|quivers|rings|sat|schemes|sets|stats|symbolic|tensor)[a-z0-9_.]*|[.]libs)[.]all\s+import' + # imports from .all are allowed in all.py; also allow in some modules that need sage.all + filePattern: '(.*/|)(?!(all|benchmark|dev_tools|parsing|sage_eval|explain_pickle|.*_test))[^/.]*[.](py|pyx|pxi)$' + +- name: 'namespace_pkg_all_import_2: Module-level import of .all of a namespace package' + hint: | + Sage library code should not import sage.PAC.KAGE.all when sage.PAC.KAGE is an implicit + namespace package. Type import_statements("SOME_IDENTIFIER") to find a more specific import, + and rewrite the import statement as "from sage.PAC.KAGE.MODULE import ..." + or "lazy_import('sage.PAC.KAGE.MODULE', '...')". + # Keep in sync with above; but for now we ignore sage.{arith,categories} + pattern: '^import\s+sage(|[.](combinat|crypto|databases|data_structures|dynamics|ext|game_theory|games|geometry|graphs|groups|interfaces|manifolds|matrix|matroids|misc|modules|monoids|numerical|probability|quadratic_forms|quivers|rings|sat|schemes|sets|stats|symbolic|tensor)[a-z0-9_.]*|[.]libs)[.]all' + # imports from .all are allowed in all.py; also allow in some modules that need sage.all + filePattern: '(.*/|)(?!(all|benchmark|dev_tools|parsing|sage_eval|explain_pickle|.*_test))[^/.]*[.](py|pyx|pxi)$' + +# Magic doctest comments + +- name: 'multiline_doctest_comment: magic comment on a continuation line' + hint: | + magic doctest comments should appear on the "sage:" line, not "....:" lines + # see optional_regex in src/sage/doctest/parsing.py + # "indirect doctest" is from src/bin/sage-coverage + pattern: '^[ ]*[.][.][.][.]:.*#.*(arb216|arb218|py2|py3|long time|not implemented|not tested|known bug|optional|indirect doctest)' diff --git a/src/MANIFEST.in b/src/MANIFEST.in index 1e7df6e529b..bbed8838199 100644 --- a/src/MANIFEST.in +++ b/src/MANIFEST.in @@ -21,7 +21,6 @@ global-exclude *.cpp include sage/cpython/debugimpl.c include sage/graphs/base/boost_interface.cpp include sage/graphs/cliquer/cl.c -include sage/graphs/graph_decompositions/sage_tdlib.cpp include sage/libs/eclib/wrap.cpp include sage/libs/linkages/padics/relaxed/flint_helper.c include sage/misc/inherit_comparison_impl.c @@ -44,6 +43,23 @@ include sage/geometry/triangulation/triangulations.cc include sage/geometry/triangulation/data.cc include sage/geometry/triangulation/functions.cc +# Exclude extension modules shipped by optional packages +exclude sage/graphs/bliss.p* +prune sage/graphs/bliss_cpp +prune sage/libs/coxeter3 +exclude sage/graphs/mcqd.p* +exclude sage/libs/meataxe.p* +exclude sage/matrix/matrix_gfpn_dense.p* +exclude sage/graphs/graph_decomposition/tdlib.p* + +# Exclude all__*.py files belonging to distributions related to optional packages +global-exclude all__sagemath_bliss.py +global-exclude all__sagemath_coxeter3.py +global-exclude all__sagemath_mcqd.py +global-exclude all__sagemath_meataxe.py +global-exclude all__sagemath_sirocco.py +global-exclude all__sagemath_tdlib.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/src/VERSION.txt b/src/VERSION.txt index 4ab501a9912..7786f0e63e4 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.0.beta1 +10.2.beta5 diff --git a/src/bin/sage b/src/bin/sage index 97f6b2d540b..64d7986482b 100755 --- a/src/bin/sage +++ b/src/bin/sage @@ -672,7 +672,7 @@ if [ "$1" = '-maxima' -o "$1" = '--maxima' ]; then shift maxima_cmd=$(sage-config MAXIMA 2>/dev/null) if [ -z "${maxima_cmd}" ]; then - maxima_cmd="maxima -l ecl" + maxima_cmd="maxima" fi exec $maxima_cmd "$@" fi diff --git a/src/bin/sage-cleaner b/src/bin/sage-cleaner index e2e578eec60..dc7d8f0482e 100755 --- a/src/bin/sage-cleaner +++ b/src/bin/sage-cleaner @@ -99,6 +99,15 @@ def cleanup(): return len(pid_list) +def cleanup_cruft(): + """ remove directories leftover from improper shutdown """ + tmp_dirs = os.listdir(SAGE_TMP_ROOT) + for dir_entry in tmp_dirs: + baddir = os.path.join(SAGE_TMP_ROOT, dir_entry) + if os.path.isdir(baddir): + logger.warning('Removing old directory %s from SAGE_TMP_ROOT', baddir) + rm_rf(baddir) + def kill_spawned_jobs(jobfile, parent_pid): logger.info("Killing %s's spawned jobs", parent_pid) killed_them_all = True @@ -193,6 +202,7 @@ if __name__ == '__main__': setup_daemon() fix_old_mistakes() logger.info("Starting sage-cleaner with PID %s", os.getpid()) + cleanup_cruft() if len(sys.argv) > 1: wait = int(sys.argv[1]) diff --git a/src/bin/sage-env b/src/bin/sage-env index 28f86bc52ef..2a63be5b7c0 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -305,11 +305,11 @@ if [ -n "$SAGE_LOCAL" ]; then fi if [ -z "$SAGE_REPO_ANONYMOUS" ]; then - SAGE_REPO_ANONYMOUS="https://github.com/sagemath/sagetrac-mirror.git" + SAGE_REPO_ANONYMOUS="https://github.com/sagemath/sage.git" export SAGE_REPO_ANONYMOUS fi if [ -z "$SAGE_REPO_AUTHENTICATED" ]; then - SAGE_REPO_AUTHENTICATED="ssh://git@trac.sagemath.org:2222/sage.git" + SAGE_REPO_AUTHENTICATED="https://github.com/sagemath/sage.git" export SAGE_REPO_AUTHENTICATED fi @@ -440,9 +440,6 @@ if [ -d "$DOT_SAGE" ] ; then fi fi -if [ -n "$SAGE_LOCAL" ]; then - export MAXIMA_PREFIX="$SAGE_LOCAL" -fi export MAXIMA_USERDIR="$DOT_SAGE/maxima" if [ -n "$SAGE_LOCAL" ]; then @@ -638,3 +635,11 @@ if [ -n "$SAGE_LOCAL" ]; then fi fi + + +# Newer versions of debugpy come with a bundled pydevd that complains +# about >=python-3.11's core modules being frozen (and therefore not +# breakpoint-able). This workaround simply hides the warning to keep +# our doctests predictable (which was the status quo with earlier +# versions of debugpy). +export PYDEVD_DISABLE_FILE_VALIDATION=1 diff --git a/src/bin/sage-fixdoctests b/src/bin/sage-fixdoctests index 3cba3464a3e..49de702cd51 100755 --- a/src/bin/sage-fixdoctests +++ b/src/bin/sage-fixdoctests @@ -14,71 +14,287 @@ AUTHORS:: situations when either the expected output or computed output are empty. Added doctest to sage.tests.cmdline """ + +# **************************************************************************** +# Copyright (C) 2006 William Stein +# 2009 Nicolas M. Thiery +# 2013 Andrew Mathas +# 2014 Volker Braun +# 2020 Jonathan Kliem +# 2021 Frรฉdรฉric Chapoton +# 2023 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +import itertools +import json import os +import re +import shlex import subprocess -from argparse import ArgumentParser, FileType +import sys + +from argparse import ArgumentParser +from pathlib import Path + +from sage.doctest.control import DocTestDefaults, DocTestController +from sage.doctest.parsing import parse_file_optional_tags, parse_optional_tags, unparse_optional_tags, update_optional_tags +from sage.env import SAGE_ROOT +from sage.features import PythonModule +from sage.features.all import all_features, module_feature, name_feature +from sage.misc.cachefunc import cached_function from sage.misc.temporary_file import tmp_filename parser = ArgumentParser(description="Given an input file with doctests, this creates a modified file that passes the doctests (modulo any raised exceptions). By default, the input file is modified. You can also name an output file.") -parser.add_argument('-l', '--long', - dest='long', action="store_true", default=False) -parser.add_argument("input", help="input filename", - type=FileType('r')) -parser.add_argument('output', nargs='?', help="output filename", - type=FileType('w')) +parser.add_argument('-l', '--long', dest='long', action="store_true", default=False, + help="include tests tagged '# long time'") +parser.add_argument("--distribution", type=str, default=[], action='append', + help="distribution package to test, e.g., 'sagemath-graphs', 'sagemath-combinat[modules]'; sets defaults for --venv and --environment. This option can be repeated to test several distributions") +parser.add_argument("--fixed-point", default=False, action="store_true", + help="whether to repeat until stable") +parser.add_argument("--venv", type=str, default='', + help="directory name of a venv where 'sage -t' is to be run") +parser.add_argument("--environment", type=str, default='', + help="name of a module that provides the global environment for tests, e.g., 'sage.all__sagemath_modules'; implies --keep-both and --full-tracebacks") +parser.add_argument("--no-test", default=False, action="store_true", + help="do not run the doctester, only rewrite '# optional/needs' tags; implies --only-tags") +parser.add_argument("--full-tracebacks", default=False, action="store_true", + help="include full tracebacks rather than '...'") +parser.add_argument("--only-tags", default=False, action="store_true", + help="only add '# optional/needs' tags where needed, ignore other failures") +parser.add_argument("--probe", metavar="FEATURES", type=str, default='', + help="check whether '# optional/needs' tags are still needed, remove those not needed") +parser.add_argument("--keep-both", default=False, action="store_true", + help="do not replace test results; duplicate the test instead, showing both results, and mark both copies '# optional'") +parser.add_argument("--overwrite", default=False, action="store_true", + help="never interpret a second filename as OUTPUT; overwrite the source files") +parser.add_argument("--no-overwrite", default=False, action="store_true", + help="never interpret a second filename as OUTPUT; output goes to files named INPUT.fixed") +parser.add_argument("--update-known-test-failures", default=False, action="store_true", + help="update the file pkgs/DISTRIBUTION/known-test-failures.json") +parser.add_argument("--verbose", default=False, action="store_true", + help="show details of all changes; implies --no-diff") +parser.add_argument("--no-diff", default=False, action="store_true", + help="don't show the 'git diff' of the modified files") +parser.add_argument("filename", nargs='*', help="input filenames; or (deprecated) INPUT_FILENAME OUTPUT_FILENAME if exactly two filenames are given and neither --overwrite nor --no-overwrite is present", + type=str) + +runtest_default_environment = "sage.repl.ipython_kernel.all_jupyter" + +def plain_distribution_and_extras(distribution): + # shortcuts / variants + distribution = distribution.replace('_', '-') + if not (distribution.startswith('sagemath-') + or distribution.startswith('sage-')): + distribution = f'sagemath-{distribution}' + # extras + m = re.fullmatch(r'([^[]*)(\[([^]]*)\])?', distribution) + return m.group(1), m.group(3) + +def default_venv_environment_from_distribution(distribution): + if distribution: + plain_distribution, extras = plain_distribution_and_extras(distribution) + tox_env_name = 'sagepython-sagewheels-nopypi-norequirements' + if extras: + tox_env_name += '-' + extras.replace(',', '-') + default_venv = os.path.join(SAGE_ROOT, 'pkgs', plain_distribution, '.tox', tox_env_name) + default_environment = 'sage.all__' + plain_distribution.replace('-', '_') + else: + default_venv = '' + default_environment = runtest_default_environment + return default_venv, default_environment + + +@cached_function +def venv_explainer(distribution, venv=None, environment=None): + venv_explainers = [] + default_venv, default_environment = default_venv_environment_from_distribution(distribution) + if venv: + if m := re.search(f'pkgs/(sage[^/]*)/[.]tox/((sagepython|sagewheels|nopypi|norequirements)-*)*([^/]*)$', + venv): + distribution, extras = m.group(1), m.group(4) + if extras: + distribution += '[' + extras.replace('-', ',') + ']' + default_venv_given_distribution, default_environment_given_distribution = default_venv_environment_from_distribution(distribution) + + if (Path(venv).resolve() == Path(default_venv_given_distribution).resolve() + or not environment or environment == default_environment_given_distribution): + venv_explainers.append(f'--distribution {shlex.quote(distribution)}') + default_venv, default_environment = default_venv_given_distribution, default_environment_given_distribution + + if venv and Path(venv).resolve() != Path(default_venv).resolve(): + venv_explainers.append(f'--venv {shlex.quote(venv)}') + if environment and environment != default_environment: + venv_explainers.append(f'--environment {environment}') + + if venv_explainers: + return ' (with ' + ' '.join(venv_explainers) + ')' + return '' -args = parser.parse_args() -# set input and output files -test_file = args.input -src_in = test_file.read() -test_file.close() - -# put the output of the test into sage's temporary directory -doc_file = tmp_filename() -os.system('sage -t %s %s > %s' % ('--long' if args.long else '', - test_file.name, doc_file)) -with open(doc_file, 'r') as doc: - doc_out = doc.read() sep = "**********************************************************************\n" -doctests = doc_out.split(sep) -src_in_lines = src_in.splitlines() -for block in doctests: - if 'Failed example:' not in block: - continue # sanity checking, but shouldn't happen +def process_block(block, src_in_lines, file_optional_tags, venv_explainer=''): + if args.verbose: + print(sep + block.rstrip()) # Extract the line, what was expected, and was got. - line = block.find('line ') # block should contain: 'line ##, in ...', where ## is an integer - comma = block.find(', in ') # we try to extract the line number which gives the test failure - if line == -1 or comma == -1: - continue # but if something goes wrong we give up - line_num = eval(block[line + 5:comma]) - - # Take care of multiline examples. - if 'Expected' in block: - i1 = block.index('Failed example') - i2 = block.index('Expected') - example_len = block[i1:i2].count('\n') - 1 - line_num += example_len - 1 - - if 'Expected nothing' in block: - exp = block.find('Expected nothing') - block = '\n' + block[exp + 17:] # so that split('\nGot:\n') does not fail below - elif 'Expected:' in block: - exp = block.find('Expected:\n') - block = block[exp + 10:] - elif 'Exception raised' in block: - exp = block.find('Exception raised') - block = '\nGot:\n' + block[exp + 17:] + if not (m := re.match('File "([^"]*)", line ([0-9]+), in ', block)): + return + + def print_line(num): + if args.verbose and (src := src_in_lines[num]): + if src: + for line in src.split('\n'): + line = line.strip() + if line.startswith("sage: ") or line.startswith("....: "): + line = line[6:] + print(f" {line}") # indent to match the displayed "Example" in the sage-runtest message + + def update_line(num, new, message=None): + src_in_lines[num] = new + if args.verbose and message: + print(f"sage-fixdoctests: {message}") + print_line(num) + + def append_to_line(num, new, message=None): + update_line(num, src_in_lines[num] + new, message=message) + + def prepend_to_line(num, new, message=None): + update_line(num, new + src_in_lines[num], message=message) + + def update_line_optional_tags(num, *args, message=None, **kwds): + update_line(num, + update_optional_tags(src_in_lines[num], *args, **kwds), + message=message) + + filename = m.group(1) + first_line_num = line_num = int(m.group(2)) # 1-based line number of the first line of the example + + if m := re.search(r"using.*block-scoped tag.*'(sage: .*)'.*to avoid repeating the tag", block): + indent = (len(src_in_lines[first_line_num - 1]) - len(src_in_lines[first_line_num - 1].lstrip())) + append_to_line(line_num - 2, '\n' + ' ' * indent + m.group(1), + message="Adding this block-scoped tag") + print_line(first_line_num - 1) + + if m := re.search(r"updating.*block-scoped tag.*'sage: (.*)'.*to avoid repeating the tag", block): + update_line_optional_tags(first_line_num - 1, tags=parse_optional_tags('# ' + m.group(1)), + message="Adding this tag to the existing block-scoped tag") + + if m := re.search(r"referenced here was set only in doctest marked '# (optional|needs)[-: ]*([^;']*)", block): + optional = m.group(2).split() + if src_in_lines[first_line_num - 1].strip() in ['"""', "'''"]: + # This happens due to a virtual doctest in src/sage/repl/user_globals.py + return + optional = set(optional) - set(file_optional_tags) + update_line_optional_tags(first_line_num - 1, add_tags=optional, + message=f"Adding the tag(s) {optional}") + + if m := re.search(r"tag '# (optional|needs)[-: ]([^;']*)' may no longer be needed", block): + optional = m.group(2).split() + update_line_optional_tags(first_line_num - 1, remove_tags=optional, + message=f"Removing the tag(s) {optional}") + + if m2 := re.search('(Expected:|Expected nothing|Exception raised:)\n', block): + m1 = re.search('Failed example:\n', block) + line_num += block[m1.end() : m2.start()].count('\n') - 1 + # Now line_num is the 1-based line number of the last line of the example + + if m2.group(1) == 'Expected nothing': + expected = '' + block = '\n' + block[m2.end():] # so that split('\nGot:\n') does not fail below + elif m2.group(1) == 'Exception raised:': + # In this case, the doctester does not show the expected output, + # so we do not know how many lines it spans; so we check for the next prompt or + # docstring end. + expected = [] + indentation = ' ' * (len(src_in_lines[line_num - 1]) - len(src_in_lines[line_num - 1].lstrip())) + i = line_num + while ((not src_in_lines[i].rstrip() or src_in_lines[i].startswith(indentation)) + and not re.match(' *(sage:|""")', src_in_lines[i])): + expected.append(src_in_lines[i]) + i += 1 + block = '\n'.join(expected) + '\nGot:\n' + block[m2.end():] + else: + block = block[m2.end():] else: - continue + return + # Error testing. + if m := re.search(r"(?:ModuleNotFoundError: No module named|ImportError: cannot import name '(.*?)' from) '(.*?)'|AttributeError: module '(.*)?' has no attribute '(.*?)'", block): + if m.group(1): + # "ImportError: cannot import name 'function_field_polymod' from 'sage.rings.function_field' (unknown location)" + module = m.group(2) + '.' + m.group(1) + elif m.group(2): + # "ModuleNotFoundError: No module named ..." + module = m.group(2) + else: + # AttributeError: module 'sage.rings' has no attribute 'qqbar' + module = m.group(3) + '.' + m.group(4) + asked_why = re.search('#.*(why|explain)', src_in_lines[first_line_num - 1]) + optional = module_feature(module) + if optional and optional.name not in file_optional_tags: + update_line_optional_tags(first_line_num - 1, add_tags=[optional.name], + message=f"Module '{module}' may be provided by feature '{optional.name}'; adding this tag") + if not asked_why: + # When no explanation has been demanded, + # we just mark the doctest with the feature + return + # Otherwise, continue and show the backtrace as 'GOT' + if 'Traceback (most recent call last):' in block: + expected, got = block.split('\nGot:\n') - got = got.splitlines() - got = [' Traceback (most recent call last):', ' ...', got[-1]] + if args.full_tracebacks: + if re.fullmatch(' *\n', got): + got = got[re.end(0):] + # don't show doctester internals (anything before first "<doctest...>" frame + if m := re.search('( *Traceback.*\n *)(?s:.*?)(^ *File "<doctest)( [^>]*)>', got, re.MULTILINE): + got = m.group(1) + '...\n' + m.group(2) + '...' + got[m.end(3):] + while m := re.search(' *File "<doctest( [^>]*)>', got): + got = got[:m.start(1)] + '...' + got[m.end(1):] + # simplify filenames shown in backtrace + while m := re.search('"([-a-zA-Z0-9._/]*/site-packages)/sage/', got): + got = got[:m.start(1)] + '...' + got[m.end(1):] + + last_frame = got.rfind('File "') + if (last_frame >= 0 + and (index_NameError := got.rfind("NameError:")) >= 0 + and got[last_frame:].startswith('File "<doctest')): + if args.verbose: + print("sage-fixdoctests: This is a NameError from the top level of the doctest") # so we keep it brief + if m := re.match("NameError: name '(.*)'", got[index_NameError:]): + name = m.group(1) + if name in ['I', 'i']: + add_tags = ['sage.symbolic'] # This is how we mark it currently (2023-08) + elif len(name) >= 2 and (feature := name_feature(name)) and feature.name != 'sage.all': + # Don't mark use of 'x' '# needs sage.symbolic'; that's almost always wrong + # Likewise for variables like 'R', 'r' + add_tags = [feature.name] # FIXME: This feature may actually already be present in line, block, or file. Move this lookup code into the doctester and issue more specific instructions + elif args.only_tags: + if args.verbose: + print("sage-fixdoctests: No feature providing this global is known; no action because of --only-tags") + return + else: + add_tags = [f"NameError ('{name}', {venv_explainer.lstrip().lstrip('(')}"] + else: + if args.only_tags: + if args.verbose: + print("sage-fixdoctests: No feature providing this global is known; no action because of --only-tags") + return + add_tags = [f"NameError{venv_explainer}"] + update_line_optional_tags(first_line_num - 1, add_tags=add_tags, + message=f"Adding tag {add_tags}") + return + got = got.splitlines() + else: + got = got.splitlines() + got = ['Traceback (most recent call last):', '...', got[-1].lstrip()] elif block[-21:] == 'Got:\n <BLANKLINE>\n': expected = block[:-22] got = [''] @@ -86,21 +302,41 @@ for block in doctests: expected, got = block.split('\nGot:\n') got = got.splitlines() # got can't be the empty string + if args.only_tags: + if args.verbose: + print("sage-fixdoctests: No action because of --only-tags") + return + + expected = expected.splitlines() + + if args.keep_both: + test_lines = ([update_optional_tags(src_in_lines[first_line_num - 1], + add_tags=[f'GOT{venv_explainer}'])] + + src_in_lines[first_line_num : line_num]) + update_line_optional_tags(first_line_num - 1, add_tags=['EXPECTED'], + message="Marking the doctest with idempotent tag EXPECTED, creating another copy with idempotent tag GOT") + indent = (len(src_in_lines[line_num - 1]) - len(src_in_lines[line_num - 1].lstrip())) + line_num += len(expected) # skip to the last line of the expected output + append_to_line(line_num - 1, '\n'.join([''] + test_lines)) # 2nd copy of the test + # now line_num is the last line of the 2nd copy of the test + expected = [] + # If we expected nothing, and got something, then we need to insert the line before line_num # and match indentation with line number line_num-1 - if expected == '': - indent = (len(src_in_lines[line_num - 1]) - len(src_in_lines[line_num - 1].lstrip())) - src_in_lines[line_num - 1] += '\n' + '\n'.join('%s%s' % (' ' * indent, line.lstrip()) for line in got) - continue + if not expected: + indent = (len(src_in_lines[first_line_num - 1]) - len(src_in_lines[first_line_num - 1].lstrip())) + append_to_line(line_num - 1, + '\n' + '\n'.join('%s%s' % (' ' * indent, line.lstrip()) for line in got), + message="Adding the new output") + return - # Guess how much extra indenting got needs to match with the indentation + # Guess how much extra indenting ``got`` needs to match with the indentation # of src_in_lines - we match the indentation with the line in ``got`` which # has the smallest indentation after lstrip(). Note that the amount of indentation # required could be negative if the ``got`` block is indented. In this case # ``indent`` is set to zero. - indent = max(0, (len(src_in_lines[line_num]) - len(src_in_lines[line_num].lstrip()) - min(len(got[j]) - len(got[j].lstrip()) for j in range(len(got))))) - - expected = expected.splitlines() + indent = max(0, (len(src_in_lines[line_num]) - len(src_in_lines[line_num].lstrip()) + - min(len(got[j]) - len(got[j].lstrip()) for j in range(len(got))))) # Double check that what was expected was indeed in the source file and if # it is not then then print a warning for the user which contains the @@ -111,42 +347,313 @@ for block in doctests: txt = "Did not manage to replace\n%s\n%s\n%s\nwith\n%s\n%s\n%s" warnings.warn(txt % ('>' * 40, '\n'.join(expected), '>' * 40, '<' * 40, '\n'.join(got), '<' * 40)) - continue + return - # If we got something when we expected nothing then we delete the line from the + # If we got nothing when we expected something then we delete the line from the # output, otherwise, add all of what we `got` onto the end of src_in_lines[line_num] if got == ['']: - src_in_lines[line_num] = None + update_line(line_num, None, + message="Expected something, got nothing; deleting the old output") else: - src_in_lines[line_num] = '\n'.join((' ' * indent + got[i]) - for i in range(len(got))) + update_line(line_num, '\n'.join((' ' * indent + got[i]) for i in range(len(got))), + message="Replacing the old expected output with the new output") # Mark any remaining `expected` lines as ``None`` so as to preserve the line numbering for i in range(1, len(expected)): - src_in_lines[line_num + i] = None - -# Overwrite the source (or output file specified on the command line) -if args.output: - test_output = args.output -else: - test_output = open(test_file.name, 'w') - -for line in src_in_lines: - if line is None: - continue - test_output.write(line) - test_output.write('\n') - -test_output.close() - -# Show summary of changes -if args.output: - print('The fixed doctests have been saved as {0}.'.format(test_output.name)) -else: - from sage.env import SAGE_ROOT - relative = os.path.relpath(test_output.name, SAGE_ROOT) - print(relative) - if relative.startswith('..'): - print('Fixed source file is not part of Sage.') + update_line(line_num + i, None) + + +# set input and output files +def output_filename(filename): + if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite: + if args.filename[0] == filename: + return args.filename[1] + else: + return None + return filename + ".fixed" + if args.no_overwrite: + return filename + ".fixed" + return filename + + +tested_doctesters = set() +venv_files = {} # distribution -> files that are not yet known to be fixed points in venv; we add and remove items +venv_ignored_files = {} # distribution -> files that should be ignored; we only add items +unprocessed_files = set() + + +class BadDistribution(Exception): + pass + + +def doctest_blocks(args, input_filenames, distribution=None, venv=None, environment=None): + executable = f'{os.path.relpath(venv)}/bin/sage' if venv else 'sage' + environment_args = f'--environment {environment} ' if environment and environment != runtest_default_environment else '' + long_args = f'--long ' if args.long else '' + probe_args = f'--probe {shlex.quote(args.probe)} ' if args.probe else '' + lib_args = f'--if-installed ' if venv else '' + doc_file = tmp_filename() + if venv or environment_args: + # Test the doctester, putting the output of the test into sage's temporary directory + input = os.path.join(os.path.relpath(SAGE_ROOT), 'src', 'sage', 'version.py') + cmdline = f'{shlex.quote(executable)} -t {environment_args}{long_args}{probe_args}'.rstrip() + if cmdline not in tested_doctesters: + if args.verbose: + print(f'sage-fixdoctests: Checking whether the doctester "{cmdline}" works') + cmdline += f' {shlex.quote(input)}' + if status := os.waitstatus_to_exitcode(os.system(f'{cmdline} > {shlex.quote(doc_file)}')): + raise BadDistribution(f"Doctester exited with error status {status}") + tested_doctesters.add(cmdline) + # Run the doctester, putting the output of the test into sage's temporary directory + input_args = " ".join(shlex.quote(f) for f in input_filenames) + cmdline = f'{shlex.quote(executable)} -t -p {environment_args}{long_args}{probe_args}{lib_args}{input_args}' + print(f'Running "{cmdline}"') + os.system(f'{cmdline} > {shlex.quote(doc_file)}') + + with open(doc_file, 'r') as doc: + doc_out = doc.read() + + # Remove skipped files, echo control messages + for m in re.finditer(r"^Skipping '(.*?)'.*$", doc_out, re.MULTILINE): + print('sage-runtests: ' + m.group(0)) + if distribution is not None: + venv_files[distribution].discard(m.group(1)) + venv_ignored_files[distribution].add(m.group(1)) + + return doc_out.split(sep) + + +def block_filename(block): + if not (m := re.match('File "([^"]*)", line ([0-9]+), in ', block)): + return None + return m.group(1) + + +def expanded_filename_args(): + DD = DocTestDefaults(optional='all', warn_long=10000) + DC = DocTestController(DD, input_filenames) + DC.add_files() + DC.expand_files_into_sources() + for source in DC.sources: + yield source.path + + +def process_grouped_blocks(grouped_iterator, distribution=None, venv=None, environment=None): + + seen = set() + + explainer = venv_explainer(distribution, venv, environment) + + for input, blocks in grouped_iterator: + + if not input: # Blocks of noise + continue + if input in seen: + continue + seen.add(input) + + with open(input, 'r') as test_file: + src_in = test_file.read() + src_in_lines = src_in.splitlines() + shallow_copy_of_src_in_lines = list(src_in_lines) + file_optional_tags = set(parse_file_optional_tags(enumerate(src_in_lines))) + + for block in blocks: + try: + process_block(block, src_in_lines, file_optional_tags, venv_explainer=explainer) + except Exception: + print('sage-fixdoctests: Failure to process block') + print(block) + + # Now source line numbers do not matter any more, and lines can be real lines again + src_in_lines = list(itertools.chain.from_iterable( + [] if line is None else [''] if not line else line.splitlines() + for line in src_in_lines)) + + # Remove duplicate optional tags and rewrite all '# optional' that should be '# needs' + persistent_optional_tags = {} + for i, line in enumerate(src_in_lines): + if m := re.match(' *sage: *(.*)#', line): + tags, line_sans_tags, is_persistent = parse_optional_tags(line, return_string_sans_tags=True) + if is_persistent: + persistent_optional_tags = {tag: explanation + for tag, explanation in tags.items() + if explanation or tag not in file_optional_tags} + line = update_optional_tags(line, tags=persistent_optional_tags, force_rewrite='standard') + if re.fullmatch(' *sage: *', line): + # persistent (block-scoped or file-scoped) tag was removed, so remove the whole line + line = None + else: + tags = {tag: explanation + for tag, explanation in tags.items() + if explanation or (tag not in file_optional_tags + and tag not in persistent_optional_tags)} + line = update_optional_tags(line, tags=tags, force_rewrite='standard') + src_in_lines[i] = line + elif line.strip() in ['', '"""', "'''"]: # Blank line or end of docstring + persistent_optional_tags = {} + + if src_in_lines != shallow_copy_of_src_in_lines: + if (output := output_filename(input)) is None: + print(f"sage-fixdoctests: Not saving modifications made in '{input}'") + else: + with open(output, 'w') as test_output: + for line in src_in_lines: + if line is None: + continue + test_output.write(line) + test_output.write('\n') + # Show summary of changes + if input != output: + print("sage-fixdoctests: The fixed doctests have been saved as '{0}'.".format(output)) + else: + relative = os.path.relpath(output, SAGE_ROOT) + print(f"sage-fixdoctests: The input file '{output}' has been overwritten.") + if not args.no_diff and not relative.startswith('..'): + subprocess.call(['git', '--no-pager', 'diff', relative], cwd=SAGE_ROOT) + for other_distribution, file_set in venv_files.items(): + if input not in venv_ignored_files[other_distribution]: + file_set.add(input) + else: + print(f"sage-fixdoctests: No fixes made in '{input}'") + if distribution is not None: + venv_files[distribution].discard(input) + + unprocessed_files.discard(input) + + +def fix_with_distribution(file_set, distribution=None, verbose=False): + if verbose: + print("#" * 78) + print(f"sage-fixdoctests: Fixing with --distribution={shlex.quote(distribution)}") + default_venv, default_environment = default_venv_environment_from_distribution(distribution) + venv = args.venv or default_venv + environment = args.environment or default_environment + file_set_to_process = sorted(file_set) + file_set.clear() + try: + doctests = doctest_blocks(args, file_set_to_process, + distribution=distribution, venv=venv, environment=environment) + process_grouped_blocks(itertools.groupby(doctests, block_filename), # modifies file_set + distribution=distribution, venv=venv, environment=environment) + except BadDistribution as e: + if args.ignore_bad_distributions: + print(f"sage-fixdoctests: {e}, ignoring") + else: + sys.exit(f"sage-fixdoctests: {e}") + + +if __name__ == "__main__": + + args = parser.parse_args() + + if args.verbose: + args.no_diff = True + + args.ignore_bad_distributions = False # This could also be a switch + + args.update_failures_distribution = args.distribution + + if args.distribution == ['all']: + args.distribution = ['sagemath-categories', + ''] # monolithic distribution + args.update_failures_distribution = args.distribution + ['sagemath-repl', # not included above because it knows too little and complains too much + ] + + args.ignore_bad_distributions = True + + if not args.filename: + if not args.update_known_test_failures: + sys.exit("sage-fixdoctests: At least one filename is required when --update-known-test-failures is not used") + if not args.distribution: + sys.exit("sage-fixdoctests: At least one --distribution argument is required for --update-known-test-failures") + + if args.distribution or args.venv or args.environment: + args.keep_both = args.full_tracebacks = True + + if len(args.distribution) > 1: + if args.venv or args.environment: + sys.exit("sage-fixdoctests: at most one --distribution argument can be combined with --venv and --environment") + elif not args.distribution: + args.distribution = [''] + + if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite: + print("sage-fixdoctests: When passing two filenames, the second one is taken as an output filename; " + "this is deprecated. To pass two input filenames, use the option --overwrite.") + input_filenames = [args.filename[0]] else: - subprocess.call(['git', 'diff', relative], cwd=SAGE_ROOT) + input_filenames = args.filename + + try: + unprocessed_files = set(expanded_filename_args()) + for distribution in args.distribution: + venv_files[distribution] = set(unprocessed_files) # make copies + venv_ignored_files[distribution] = set() + if args.no_test: + pass + elif len(args.distribution) == 1 and not args.fixed_point: + fix_with_distribution(set(unprocessed_files), args.distribution[0]) + else: + for distribution, file_set in venv_files.items(): + fix_with_distribution(file_set, distribution, verbose=True) + if args.fixed_point: + if args.probe: + print(f"sage-fixdoctests: Turning off --probe for the following iterations") + # This forces convergence to a fixed point + args.probe = '' + while True: + # Run a distribution with largest number of files remaining to be checked + # because of the startup overhead of sage-runtests + distribution, file_set = max(venv_files.items(), key=lambda df: len(df[1])) + if not file_set: + break + while file_set: + fix_with_distribution(file_set, distribution, verbose=True) + # Immediately re-run with the same distribution to continue chains of + # "NameError" / "variable was set only in doctest" fixes + + # Each file must be processed by process_grouped_blocks at least once to clean up tags, + # even if sage-runtest does not have any complaints. + if unprocessed_files: + print(f"sage-fixdoctests: Processing unprocessed files") + process_grouped_blocks([(filename, []) + for filename in unprocessed_files]) + + if args.fixed_point: + print(f"sage-fixdoctests: Fixed point reached") + + if args.update_known_test_failures: + if args.update_failures_distribution == ['']: + print("sage-fixdoctests: Ignoring switch --update-known-test-failures because no --distribution was given") + else: + for distribution in sorted(args.update_failures_distribution): + if distribution == '': + continue + plain_distribution, extras = plain_distribution_and_extras(distribution) + default_venv, _ = default_venv_environment_from_distribution(distribution) + venv = args.venv or default_venv + try: + stats_filename = os.path.join(default_venv, '.sage/timings2.json') + with open(stats_filename, 'r') as stats_file: + stats = json.load(stats_file) + except FileNotFoundError: + print(f"sage-fixdoctests: {os.path.relpath(stats_filename, SAGE_ROOT)} " + "does not exist (ignoring)") + else: + for d in stats.values(): + del d['walltime'] + stats = {k: d for k, d in stats.items() + if d.get('failed') or d.get('ntests', True)} + if extras: + extras_suffix = '--' + '--'.join(extras.split(',')) + else: + extras_suffix = '' + failures_file = os.path.join(SAGE_ROOT, 'pkgs', plain_distribution, + f'known-test-failures{extras_suffix}.json') + with open(failures_file, 'w') as f: + json.dump(stats, f, sort_keys=True, indent=4) + print(f"sage-fixdoctests: Updated {os.path.relpath(failures_file, SAGE_ROOT)}") + + except Exception: + print(f"sage-fixdoctests: Internal error") + raise diff --git a/src/bin/sage-grep b/src/bin/sage-grep index 8441fa83519..c7975ae97af 100755 --- a/src/bin/sage-grep +++ b/src/bin/sage-grep @@ -2,4 +2,4 @@ cd "$SAGE_SRC" -find sage -print | GREP_OPTIONS= egrep '.py([xdi])?$' | xargs grep "$@" +find sage -name "*.py" -o -name "*.pyx" -o -name "*.pxi" -o -name "*.pxd" | xargs grep "$@" diff --git a/src/bin/sage-grepdoc b/src/bin/sage-grepdoc index ec0383178ed..ee6dff707e2 100755 --- a/src/bin/sage-grepdoc +++ b/src/bin/sage-grepdoc @@ -2,4 +2,4 @@ cd "$SAGE_DOC" -find html -print | GREP_OPTIONS= egrep '.html$' | xargs grep "$@" +find html -name '*.html' | xargs grep "$@" diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index ed1e56953ff..01b7ca44868 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -52,6 +52,13 @@ if __name__ == "__main__": 'if set to "all", then all tests will be run; ' 'use "!FEATURE" to disable tests marked "# optional - FEATURE". ' 'Note that "!" needs to be quoted or escaped in the shell.') + parser.add_argument("--hide", metavar="FEATURES", default="", + help='run tests pretending that the software listed in FEATURES (separated by commas) is not installed; ' + 'if "all" is listed, will also hide features corresponding to all optional or experimental packages; ' + 'if "optional" is listed, will also hide features corresponding to optional packages.') + parser.add_argument("--probe", metavar="FEATURES", default="", + help='run tests that would not be run because one of the given FEATURES (separated by commas) is not installed; ' + 'report the tests that pass nevertheless') parser.add_argument("--randorder", type=int, metavar="SEED", help="randomize order of tests") parser.add_argument("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed (integer) for fuzzing doctests", default=os.environ.get("SAGE_DOCTEST_RANDOM_SEED")) @@ -62,6 +69,7 @@ if __name__ == "__main__": parser.add_argument("-i", "--initial", action="store_true", default=False, help="only show the first failure in each file") parser.add_argument("--exitfirst", action="store_true", default=False, help="end the test run immediately after the first failure or unexpected exception") parser.add_argument("--force_lib", "--force-lib", action="store_true", default=False, help="do not import anything from the tested file(s)") + parser.add_argument("--if-installed", action="store_true", default=False, help="skip Python/Cython files that are not installed as modules") parser.add_argument("--abspath", action="store_true", default=False, help="print absolute paths rather than relative paths") parser.add_argument("--verbose", action="store_true", default=False, help="print debugging output during the test") parser.add_argument("-d", "--debug", action="store_true", default=False, help="drop into a python debugger when an unexpected error is raised") @@ -167,14 +175,20 @@ if __name__ == "__main__": pytest_options = [] if args.verbose: pytest_options.append("-v") - # #31924: Do not run pytest on individual Python files unless - # they match the pytest file pattern. However, pass names - # of directories. We use 'not os.path.isfile(f)' for this so that - # we do not silently hide typos. - filenames = [f for f in args.filenames - if f.endswith("_test.py") or not os.path.isfile(f)] - if filenames or not args.filenames: - exit_code_pytest = pytest.main(pytest_options + filenames) + + # #35999: no filename in arguments defaults to "src" + if not args.filenames: + filenames = [SAGE_SRC] + else: + # #31924: Do not run pytest on individual Python files unless + # they match the pytest file pattern. However, pass names + # of directories. We use 'not os.path.isfile(f)' for this so that + # we do not silently hide typos. + filenames = [f for f in args.filenames + if f.endswith("_test.py") or not os.path.isfile(f)] + if filenames: + print(f"Running pytest on {filenames} with options {pytest_options}") + exit_code_pytest = pytest.main(filenames + pytest_options) if exit_code_pytest == 5: # Exit code 5 means there were no test files, pass in this case exit_code_pytest = 0 diff --git a/src/bin/sage-update-version b/src/bin/sage-update-version index 40df8926f74..29d8c794375 100755 --- a/src/bin/sage-update-version +++ b/src/bin/sage-update-version @@ -48,7 +48,11 @@ done if [ -f "$spkg"/install-requires.txt -a -d "$spkg"/src ]; then ( echo "# This file is updated on every release by the sage-update-version script" # Normalize the package name to PyPI convention (dashes, not underscores) - pkg=${spkg//_/-} + if [ "$spkg" = sagelib ]; then + pkg=sagemath-standard + else + pkg=${spkg//_/-} + fi # Normalize the version (updated above as VERSION.txt) according to PEP440. version=$(cat "$spkg"/package-version.txt) version=${version//.beta/b} @@ -86,17 +90,17 @@ echo "$SAGE_VERSION_BANNER" > "$SAGE_ROOT/VERSION.txt" # Regenerate auto-generated files tarball "$SAGE_ROOT/bootstrap" -s -# Create json file for Zenodo +# Create CITATION file for Zenodo-GitHub integration export SAGE_VERSION export SAGE_RELEASE_DATE -envsubst <"$SAGE_ROOT/.zenodo.json.in" >"$SAGE_ROOT/.zenodo.json" +envsubst <"$SAGE_ROOT/CITATION.cff.in" >"$SAGE_ROOT/CITATION.cff" # Commit auto-generated changes git commit -m "Updated SageMath version to $SAGE_VERSION" -- \ "$SAGE_ROOT/VERSION.txt" \ - "$SAGE_ROOT/.zenodo.json" \ "$SAGE_SRC/sage/version.py" \ "$SAGE_SRC/VERSION.txt" \ + "$SAGE_ROOT/CITATION.cff" \ "$SAGE_SRC/bin/sage-version.sh" \ "$SAGE_ROOT/build/pkgs/configure/checksums.ini" \ "$SAGE_ROOT/build/pkgs/configure/package-version.txt" \ diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index d8c6b161134..3bc82696a62 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='10.0.beta1' -SAGE_RELEASE_DATE='2023-02-19' -SAGE_VERSION_BANNER='SageMath version 10.0.beta1, Release Date: 2023-02-19' +SAGE_VERSION='10.2.beta5' +SAGE_RELEASE_DATE='2023-09-27' +SAGE_VERSION_BANNER='SageMath version 10.2.beta5, Release Date: 2023-09-27' diff --git a/src/conftest.py b/src/conftest.py index 9448087cc7a..c7423f89521 100644 --- a/src/conftest.py +++ b/src/conftest.py @@ -24,10 +24,6 @@ ) from _pytest.pathlib import import_path, ImportMode -# Import sage.all is necessary to: -# - avoid cyclic import errors, see Issue #33580 -# - inject it into globals namespace for doctests -import sage.all from sage.doctest.parsing import SageDocTestParser, SageOutputChecker @@ -117,8 +113,19 @@ def _find( ) +class IgnoreCollector(pytest.Collector): + """ + Ignore a file. + """ + def __init__(self, parent: pytest.Collector) -> None: + super().__init__('ignore', parent) + + def collect(self) -> Iterable[pytest.Item | pytest.Collector]: + return [] + + def pytest_collect_file( - file_path: Path, parent: pytest.File + file_path: Path, parent: pytest.Collector ) -> pytest.Collector | None: """ This hook is called when collecting test files, and can be used to @@ -132,13 +139,13 @@ def pytest_collect_file( # We don't allow pytests to be defined in Cython files. # Normally, Cython files are filtered out already by pytest and we only # hit this here if someone explicitly runs `pytest some_file.pyx`. - return pytest.skip("Skipping Cython file") + return IgnoreCollector.from_parent(parent) elif file_path.suffix == ".py": if parent.config.option.doctestmodules: return SageDoctestModule.from_parent(parent, path=file_path) -@pytest.fixture(autouse=True) +@pytest.fixture(autouse=True, scope="session") def add_imports(doctest_namespace: dict[str, Any]): """ Add global imports for doctests. @@ -146,6 +153,7 @@ def add_imports(doctest_namespace: dict[str, Any]): See `pytest documentation <https://docs.pytest.org/en/stable/doctest.html#doctest-namespace-fixture>`. """ # Inject sage.all into each doctest + import sage.all dict_all = sage.all.__dict__ # Remove '__package__' item from the globals since it is not diff --git a/src/conftest_test.py b/src/conftest_test.py index dcf166fd969..fe790c48bb9 100644 --- a/src/conftest_test.py +++ b/src/conftest_test.py @@ -1,12 +1,18 @@ +from pathlib import Path import subprocess +from sage.env import SAGE_SRC + +input_file = Path(SAGE_SRC) / "conftest_inputtest.py" + + class TestOldDoctestSageScript: """Run `sage --t`.""" def test_invoke_on_inputtest_file(self): result = subprocess.run( - ["sage", "-t", "./src/conftest_inputtest.py"], + ["sage", "-t", input_file], capture_output=True, text=True, ) @@ -27,7 +33,7 @@ class TestPytestSageScript: def test_invoke_on_inputtest_file(self): result = subprocess.run( - ["sage", "--pytest", "./src/conftest_inputtest.py"], + ["sage", "--pytest", input_file], capture_output=True, text=True, ) diff --git a/src/doc/bootstrap b/src/doc/bootstrap index 6dd50fd5cec..be2168af064 100755 --- a/src/doc/bootstrap +++ b/src/doc/bootstrap @@ -89,8 +89,8 @@ fi OUTPUT_INDEX="$OUTPUT_DIR"/index.rst cat > "$OUTPUT_INDEX" <<EOF -External Packages -================= +Packages and Features +===================== Standard Packages ----------------- @@ -100,7 +100,7 @@ Sage depends. It installs them automatically if it does not find equivalent system packages. EOF -for PKG_BASE in $(sage-package list --has-file SPKG.rst :standard: | sort); do +for PKG_BASE in $(sage-package list --has-file SPKG.rst :standard: | grep -v '^sagemath_' | sort); do echo "* :ref:\`spkg_$PKG_BASE\`" done >> "$OUTPUT_INDEX" cat >> "$OUTPUT_INDEX" <<EOF @@ -112,7 +112,55 @@ For additional functionality, you can install some of the following optional packages. EOF -for PKG_BASE in $(sage-package list --has-file SPKG.rst :optional: | sort); do +for PKG_BASE in $(sage-package list --has-file SPKG.rst :optional: | grep -v '^sagemath_' | sort); do + echo "* :ref:\`spkg_$PKG_BASE\`" +done >> "$OUTPUT_INDEX" +cat >> "$OUTPUT_INDEX" <<EOF + +Features +-------- + +.. toctree:: + :maxdepth: 1 + + sage/features + sage/features/join_feature + sage/features/all + sage/features/sagemath + sage/features/pkg_systems + sage/features/bliss + sage/features/csdp + sage/features/databases + sage/features/dvipng + sage/features/ffmpeg + sage/features/four_ti_2 + sage/features/gap + sage/features/graph_generators + sage/features/graphviz + sage/features/imagemagick + sage/features/interfaces + sage/features/internet + sage/features/kenzo + sage/features/latex + sage/features/latte + sage/features/lrs + sage/features/mcqd + sage/features/meataxe + sage/features/mip_backends + sage/features/normaliz + sage/features/pandoc + sage/features/pdf2svg + sage/features/polymake + sage/features/rubiks + sage/features/tdlib +EOF +cat >> "$OUTPUT_INDEX" <<EOF + +Distribution Packages of the Sage Library +----------------------------------------- + +EOF +for PKG_BASE in $(sage-package list --has-file SPKG.rst | grep '^sagemath_' | sort); do echo "* :ref:\`spkg_$PKG_BASE\`" done >> "$OUTPUT_INDEX" cat >> "$OUTPUT_INDEX" <<EOF @@ -125,9 +173,10 @@ Some packages that provide additional functionality are marked as integration of these packages into the Sage distribution. EOF -for PKG_BASE in $(sage-package list --has-file SPKG.rst :experimental: | sort); do +for PKG_BASE in $(sage-package list --has-file SPKG.rst :experimental: | grep -v '^sagemath_' | sort); do echo "* :ref:\`spkg_$PKG_BASE\`" done >> "$OUTPUT_INDEX" + cat >> "$OUTPUT_INDEX" <<EOF All External Packages @@ -142,11 +191,14 @@ EOF OUTPUT_INDEX="$OUTPUT_DIR"/index_alph.rst cat >> "$OUTPUT_INDEX" <<EOF + Details of external packages ============================ Packages are in alphabetical order. +.. default-role:: code + .. toctree:: :maxdepth: 1 @@ -160,3 +212,8 @@ for PKG_BASE in $(sage-package list --has-file SPKG.rst | sort); do (echo ".. _spkg_$PKG_BASE:" && echo && OUTPUT_RST=1 sage-spkg-info $PKG_BASE) | sed -e "s|https://github.com/sagemath/sage/issues/\([0-9]*\)|:issue:\`\1\`|g" -e "s|https://arxiv.org/abs/cs/\([0-9]*\)|:arxiv:\`cs/\1\`|g" > "$OUTPUT_DIR"/$PKG_BASE.rst echo >> "$OUTPUT_INDEX" " $PKG_BASE" done +cat >> "$OUTPUT_INDEX" <<EOF + +.. default-role:: + +EOF diff --git a/src/doc/common/python3.inv b/src/doc/common/python3.inv index cd7b37ac1e8..50c7f1fa814 100644 Binary files a/src/doc/common/python3.inv and b/src/doc/common/python3.inv differ diff --git a/src/doc/common/update-python-inv.sh b/src/doc/common/update-python-inv.sh index f073d28a1ce..e6dcc843ced 100755 --- a/src/doc/common/update-python-inv.sh +++ b/src/doc/common/update-python-inv.sh @@ -5,15 +5,16 @@ # http://sphinx-doc.org/ext/intersphinx.html # # To be able to compile Sage without accessing the net, we use a local copy of -# this database. Here is how to update it: +# this database. Here is how to update it by downloading the file +# for the latest stable Python version: if command -v wget > /dev/null 2>&1 ; then rm -f python.inv python2.inv python3.inv - wget https://docs.python.org/release/`sage --python3 --version 2>&1 | cut -d " " -f 2`/objects.inv -O - > python3.inv + wget https://docs.python.org/3/objects.inv -O - > python3.inv elif command -v curl > /dev/null 2>&1 ; then # On OS X, curl is installed by default, but not wget. rm -f python.inv python2.inv python3.inv - curl https://docs.python.org/release/`sage --python3 --version 2>&1 | cut -d " " -f 2`/objects.inv > python3.inv + curl https://docs.python.org/3/objects.inv > python3.inv else echo "Error: neither wget nor curl is installed." return 1 diff --git a/src/doc/de/tutorial/interactive_shell.rst b/src/doc/de/tutorial/interactive_shell.rst index b356ea21f45..d29e7924871 100644 --- a/src/doc/de/tutorial/interactive_shell.rst +++ b/src/doc/de/tutorial/interactive_shell.rst @@ -373,7 +373,7 @@ Fehlerbehandlung Wenn irgendetwas schief geht, werden Sie normalerweise eine Python-Fehlermeldung sehen. Python macht sogar einen Vorschlag, was den Fehler ausgelรถst hat. Oft sehen Sie den Namen der Fehlermeldung, -z.B. ``NameError`` oder ``ValueError`` (vgl. Python Library Reference +z.B. :class:`NameError` oder :class:`ValueError` (vgl. Python Library Reference [PyLR]_ fรผr eine komplette Liste der Fehlermeldungen). Zum Beispiel: .. skip diff --git a/src/doc/de/tutorial/interfaces.rst b/src/doc/de/tutorial/interfaces.rst index edb4f383363..d83225b5315 100644 --- a/src/doc/de/tutorial/interfaces.rst +++ b/src/doc/de/tutorial/interfaces.rst @@ -272,8 +272,8 @@ deren :math:`i,j` Eintrag gerade :math:`i/j` ist, fรผr :math:`i,j=1,\ldots,4`. matrix([1,1/2,1/3,1/4],[0,0,0,0],[0,0,0,0],[0,0,0,0]) sage: A.eigenvalues() [[0,4],[3,1]] - sage: A.eigenvectors() - [[[0,4],[3,1]],[[[1,0,0,-4],[0,1,0,-2],[0,0,1,-4/3]],[[1,2,3,4]]]] + sage: A.eigenvectors().sage() + [[[0, 4], [3, 1]], [[[1, 0, 0, -4], [0, 1, 0, -2], [0, 0, 1, -4/3]], [[1, 2, 3, 4]]]] Hier ein anderes Beispiel: @@ -332,12 +332,9 @@ Und der letzte ist die berรผhmte Kleinsche Flasche: :: - sage: maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0) - 10.0") - 5*cos(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0)-10.0 - sage: maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") - -5*sin(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0) - sage: maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") - 5*(cos(x/2)*sin(2*y)-sin(x/2)*cos(y)) + sage: _ = maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0) - 10.0") + sage: _ = maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") + sage: _ = maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") sage: maxima.plot3d ("[expr_1, expr_2, expr_3]", "[x, -%pi, %pi]", # not tested ....: "[y, -%pi, %pi]", "['grid, 40, 40]", ....: '[plot_format, openmath]') diff --git a/src/doc/de/tutorial/introduction.rst b/src/doc/de/tutorial/introduction.rst index bb80efc7cec..f64ed7ee796 100644 --- a/src/doc/de/tutorial/introduction.rst +++ b/src/doc/de/tutorial/introduction.rst @@ -107,7 +107,7 @@ Wie man Sage benutzen kann Sie kรถnnen Sage auf verschiedene Weise benutzen. -- **graphisches Notebook-Interface:** rufen Sie `sage -n jupyter` auf; lesen Sie +- **graphisches Notebook-Interface:** rufen Sie ``sage -n jupyter`` auf; lesen Sie `Jupyter documentation on-line <https://jupyter-notebook.readthedocs.io/en/latest/notebook.html>`_, - **interaktive Kommandozeile:** lesen Sie :ref:`chapter-interactive_shell`, diff --git a/src/doc/de/tutorial/latex.rst b/src/doc/de/tutorial/latex.rst index c664bb970cd..77c0834ab77 100644 --- a/src/doc/de/tutorial/latex.rst +++ b/src/doc/de/tutorial/latex.rst @@ -319,17 +319,18 @@ lรคsst. Diese Liste wird verwaltet durch die Befehle ``latex.add_to_mathjax_avoid_list`` und ``latex.mathjax_avoid_list``. :: - sage: latex.mathjax_avoid_list([]) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: # not tested + sage: latex.mathjax_avoid_list([]) + sage: latex.mathjax_avoid_list() [] - sage: latex.mathjax_avoid_list(['foo', 'bar']) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.mathjax_avoid_list(['foo', 'bar']) + sage: latex.mathjax_avoid_list() ['foo', 'bar'] - sage: latex.add_to_mathjax_avoid_list('tikzpicture') # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.add_to_mathjax_avoid_list('tikzpicture') + sage: latex.mathjax_avoid_list() ['foo', 'bar', 'tikzpicture'] - sage: latex.mathjax_avoid_list([]) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.mathjax_avoid_list([]) + sage: latex.mathjax_avoid_list() [] Nehmen wir an ein LaTeX-Ausdruck wurde im Notebook durch ``view()`` diff --git a/src/doc/de/tutorial/tour_algebra.rst b/src/doc/de/tutorial/tour_algebra.rst index baba2553a25..59eed8f1888 100644 --- a/src/doc/de/tutorial/tour_algebra.rst +++ b/src/doc/de/tutorial/tour_algebra.rst @@ -209,9 +209,12 @@ Lรถsung: Berechnen Sie die Laplace-Transformierte der ersten Gleichung :: - sage: de1 = maxima("2*diff(x(t),t, 2) + 6*x(t) - 2*y(t)") - sage: lde1 = de1.laplace("t","s"); lde1 - 2*((-%at('diff(x(t),t,1),t = 0))+s^2*'laplace(x(t),t,s)-x(0)*s) -2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) + sage: t,s = SR.var('t,s') + sage: x = function('x') + sage: y = function('y') + sage: f = 2*x(t).diff(t,2) + 6*x(t) - 2*y(t) + sage: f.laplace(t,s) + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) Das ist schwierig zu lesen, es besagt jedoch, dass @@ -226,8 +229,8 @@ Laplace-Transformierte der zweiten Gleichung: :: sage: de2 = maxima("diff(y(t),t, 2) + 2*y(t) - 2*x(t)") - sage: lde2 = de2.laplace("t","s"); lde2 - (-%at('diff(y(t),t,1),t = 0))+s^2*'laplace(y(t),t,s) +2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s) -y(0)*s + sage: lde2 = de2.laplace("t","s"); lde2.sage() + s^2*laplace(y(t), t, s) - s*y(0) - 2*laplace(x(t), t, s) + 2*laplace(y(t), t, s) - D[0](y)(0) Dies besagt diff --git a/src/doc/en/a_tour_of_sage/index.rst b/src/doc/en/a_tour_of_sage/index.rst index 7bff367ebad..15e9d2aae46 100644 --- a/src/doc/en/a_tour_of_sage/index.rst +++ b/src/doc/en/a_tour_of_sage/index.rst @@ -1,8 +1,8 @@ .. _a-tour-of-sage: -========================== -Welcome to a Tour of Sage! -========================== +========================= +Welcome to a Tour of Sage +========================= This is a tour of Sage that closely follows the tour of Mathematica that is at the beginning of the Mathematica Book. diff --git a/src/doc/en/constructions/index.rst b/src/doc/en/constructions/index.rst index c3f0cdb7de6..39ab5a796fe 100644 --- a/src/doc/en/constructions/index.rst +++ b/src/doc/en/constructions/index.rst @@ -4,8 +4,9 @@ .. _constructions: -Welcome to the Sage Constructions! -================================== +============================= +Welcome to Sage Constructions +============================= This document collects the answers to some questions along the line "How do I construct ... in Sage?" Though much of this material can diff --git a/src/doc/en/constructions/linear_algebra.rst b/src/doc/en/constructions/linear_algebra.rst index 8894de9a5fd..4e76c65ad0a 100644 --- a/src/doc/en/constructions/linear_algebra.rst +++ b/src/doc/en/constructions/linear_algebra.rst @@ -277,8 +277,8 @@ Another approach is to use the interface with Maxima: sage: A = maxima("matrix ([1, -4], [1, -1])") sage: eig = A.eigenvectors() - sage: eig - [[[-sqrt(3)*%i,sqrt(3)*%i],[1,1]], [[[1,(sqrt(3)*%i+1)/4]],[[1,-(sqrt(3)*%i-1)/4]]]] + sage: eig.sage() + [[[-I*sqrt(3), I*sqrt(3)], [1, 1]], [[[1, 1/4*I*sqrt(3) + 1/4]], [[1, -1/4*I*sqrt(3) + 1/4]]]] This tells us that :math:`\vec{v}_1 = [1,(\sqrt{3}i + 1)/4]` is an eigenvector of :math:`\lambda_1 = - \sqrt{3}i` (which occurs diff --git a/src/doc/en/constructions/plotting.rst b/src/doc/en/constructions/plotting.rst index 75a0e0e3bbc..58eb17a98c6 100644 --- a/src/doc/en/constructions/plotting.rst +++ b/src/doc/en/constructions/plotting.rst @@ -301,10 +301,10 @@ Here is an example of a plot of a parametric surface in 3-space: :: sage: maxima.plot3d_parametric(["v*sin(u)","v*cos(u)","v"], ["u","v"], - ....: [-3.2,3.2],[0,3]) # optional -- pops up a window. + ....: [-3.2,3.2],[0,3]) sage: opts = '[gnuplot_term, ps], [gnuplot_out_file, "sin-cos-plot.eps"]' sage: maxima.plot3d_parametric(["v*sin(u)","v*cos(u)","v"], ["u","v"], - ....: [-3.2,3.2],[0,3],opts) # optional -- pops up a window. + ....: [-3.2,3.2],[0,3],opts) To illustrate how to pass gnuplot options in , here is an example of a plot of a set of points involving the Riemann zeta function diff --git a/src/doc/en/developer/advanced_git.rst b/src/doc/en/developer/advanced_git.rst deleted file mode 100644 index eb128986452..00000000000 --- a/src/doc/en/developer/advanced_git.rst +++ /dev/null @@ -1,401 +0,0 @@ -.. highlight:: shell-session - -.. _chapter-advanced-git: - -============ -Advanced Git -============ - -.. WARNING:: - - **Sage development is scheduled to move to GitHub in February 2023.** The exact - date will be announced in `<https://groups.google.com/g/sage-devel>`_. After - the transition, some parts of this guide (especially those related with `the - Sage Trac server <https://trac.sagemath.org>`_) will become obsolete and be - updated according to the new workflow on GitHub. See our `transition guide from Trac to - GitHub - <https://github.com/sagemath/trac-to-github/blob/master/docs/Migration-Trac-to-Github.md>`_ - for the preliminary version of the workflow. - -This chapter covers some advanced uses of git that go beyond what is -required to work with branches. These features can be used in Sage -development, but are not really necessary to contribute to Sage. If -you are just getting started with Sage development, you should read -:ref:`chapter-walkthrough` and :ref:`chapter-manual-git` instead. - - -Detached Heads and Reviewing Tickets -==================================== - -Each commit is a snapshot of the Sage source tree at a certain -point. So far, we always used commits organized in branches. But -secretly the branch is just a shortcut for a particular commit, the -head commit of the branch. But you can just go to a particular commit -without a branch, this is called "detached head". If you have the -commit already in your local history, you can directly check it -out without requiring internet access:: - - [user@localhost sage]$ git checkout a63227d0636e29a8212c32eb9ca84e9588bbf80b - Note: checking out 'a63227d0636e29a8212c32eb9ca84e9588bbf80b'. - - You are in 'detached HEAD' state. You can look around, make experimental - changes and commit them, and you can discard any commits you make in this - state without impacting any branches by performing another checkout. - - If you want to create a new branch to retain commits you create, you may - do so (now or later) by using -b with the checkout command again. Example: - - git checkout -b new_branch_name - - HEAD is now at a63227d... Szekeres Snark Graph constructor - -If it is not stored in your local git repository, you need to download -it from the trac server first:: - - [user@localhost sage]$ git fetch trac a63227d0636e29a8212c32eb9ca84e9588bbf80b - From ssh://trac/sage - * branch a63227d0636e29a8212c32eb9ca84e9588bbf80b -> FETCH_HEAD - [user@localhost sage]$ git checkout FETCH_HEAD - HEAD is now at a63227d... Szekeres Snark Graph constructor - -Either way, you end up with your current HEAD and working directory -that is not associated to any local branch:: - - [user@localhost sage]$ git status - # HEAD detached at a63227d - nothing to commit, working directory clean - -This is perfectly fine. You can switch to an existing branch (with the -usual ``git checkout my_branch``) and back to your detached head. - -Detached heads can be used to your advantage when reviewing -tickets. Just check out the commit (look at the "Commit:" field on the -trac ticket) that you are reviewing as a detached head. Then you can -look at the changes and run tests in the detached head. When you are -finished with the review, you just abandon the detached head. That way -you never create a new local branch, so you don't have to type ``git -branch -D my_branch`` at the end to delete the local branch that you -created only to review the ticket. - - -.. _section-git-update-latest: - -Update Branch to Latest SageMath Version (and Minimizing Recompilation Time) -============================================================================ - -- You have a compiled and working new SageMath version ``n``, and -- you want to work on a branch ``some_code`` which is based on some old SageMath version ``o`` -- by updating this branch from version ``o`` to ``n`` -- with only recompiling changed files (and not all touched files from ``o`` to ``n``), -- then continue reading this section. - - -Introduction ------------- - -When developing, quite frequently one ends up with a branch which is -not based on the latest (beta) version of SageMath. - -.. NOTE:: - - Continue working on a feature based on an old branch is perfectly - fine and usually there is no need to merge in this latest SageMath - version. - -However sometimes there is a need for a merge, for example - -- if there are conflicts with the latest version or -- one needs a recent feature or -- simply because the old SageMath version is not available on your machine - any longer. - -Then merging in the latest SageMath version has to be done. - - -Merge in the Latest SageMath Version ------------------------------------- - -(This is the easy way without minimizing the recompilation time.) - -Suppose we are on our current working branch ``some_code`` -(branch is checked out). Then -:: - - git merge develop - -does the merging, i.e. we merge the latest development version into -our working branch. - -However, after this merge, we need to (partially) recompile -SageMath. Sometimes this can take ages (as many files are touched and -their timestamps are renewed) and there is a way to avoid it. - - -Minimize the Recompilation Time -------------------------------- - -Suppose we are on some new SageMath (e.g. on branch ``develop``) which -was already compiled and runs successfully, and we have an "old" -branch ``some_code``, that we want to bring onto this SageMath version -(without triggering unnecessary recompilations). - -We first create a new working tree in a directory ``new_worktree`` and switch -to this directory:: - - git worktree add new_worktree - cd new_worktree - -Here we have a new copy of our source files. Thus no timestamps -etc. of the original repository will be changed. Now we do the merge:: - - git checkout some_code - git merge develop - -And go back to our original repository:: - - git checkout develop - cd .. - -We can now safely checkout ``some_code``:: - - git checkout some_code - -We still need to call -:: - - make - -but only changed files will be recompiled. - -To remove the new working tree simply use -:: - - rm -r new_worktree - - -Why not Merging the Other Way Round? ------------------------------------- - -Being on some new SageMath (e.g. on branch ``develop``) which runs -successfully, it would be possible to merge in our branch -``some_code`` into develop. This would produce the same source files -and avoid unnecessary recompilations. However, it makes reading git's -history very unpleasant: For example, it is hard to keep track of changes etc., -as one cannot simply pursue the first parent of each git commit -(``git log --first-parent``). - - -.. _section-git-recovery: - -Reset and Recovery -================== - -Git makes it very hard to truly mess up. Here is a short way to get -back onto your feet, no matter what. First, if you just want to go -back to a working Sage installation you can always abandon your -working branch by switching to your local copy of the ``master`` -branch:: - - [user@localhost sage]$ git checkout master - -As long as you did not make any changes to the ``master`` branch -directly, this will give you back a working Sage. - -If you want to keep your branch but go back to a previous commit you -can use the *reset* command. For this, look up the commit in the log -which is some 40-digit hexadecimal number (the SHA1 hash). Then use -``git reset --hard`` to revert your files back to the previous state:: - - [user@localhost sage]$ git log - ... - commit eafaedad5b0ae2013f8ae1091d2f1df58b72bae3 - Author: First Last <user@email.com> - Date: Sat Jul 20 21:57:33 2013 -0400 - - Commit message - ... - [user@localhost sage]$ git reset --hard eafae - -.. WARNING:: - - Any *uncommitted* changes will be lost! - -You only need to type the first couple of hex digits, git will -complain if this does not uniquely specify a commit. Also, there is -the useful abbreviation ``HEAD~`` for the previous commit and -``HEAD~n``, with some integer ``n``, for the n-th previous commit. - -Finally, perhaps the ultimate human error recovery tool is the -reflog. This is a chronological history of git operations that you can -undo if needed. For example, let us assume we messed up the *git -reset* command and went back too far (say, 5 commits back). And, on -top of that, deleted a file and committed that:: - - [user@localhost sage]$ git reset --hard HEAD~5 - [user@localhost sage]$ git rm sage - [user@localhost sage]$ git commit -m "I shot myself into my foot" - -Now we cannot just checkout the repository from before the reset, -because it is no longer in the history. However, here is the reflog:: - - [user@localhost sage]$ git reflog - 2eca2a2 HEAD@{0}: commit: I shot myself into my foot - b4d86b9 HEAD@{1}: reset: moving to HEAD~5 - af353bb HEAD@{2}: checkout: moving from some_branch to master - 1142feb HEAD@{3}: checkout: moving from other_branch to some_branch - ... - -The ``HEAD@{n}`` revisions are shortcuts for the history of git -operations. Since we want to rewind to before the erroneous *git -reset* command, we just have to reset back into the future:: - - [user@localhost sage]$ git reset --hard HEAD@{2} - - - -.. _section-git-rewriting-history: - -Rewriting History -================= - -Git allows you to rewrite history, but be careful: the SHA1 hash of a -commit includes the parent's hash. This means that the hash really -depends on the entire content of the working directory; every source -file is in exactly the same state as when the hash was computed. This -also means that you can't change history without modifying the -hash. If others branched off your code and then you rewrite history, -then the others are thoroughly screwed. So, ideally, you would only -rewrite history on branches that you have not yet pushed to trac. - -As an advanced example, consider three commits A, B, C that were made -on top of each other. For simplicity, we'll assume they just added a -file named ``file_A.py``, ``file_B.py``, and ``file_C.py`` :: - - [user@localhost]$ git log --oneline - 9621dae added file C - 7873447 added file B - bf817a5 added file A - 5b5588e base commit - -Now, let's assume that the commit B was really independent and ought -to be on a separate ticket. So we want to move it to a new branch, -which we'll call ``second_branch``. First, branch off at the base -commit before we added A:: - - [user@localhost]$ git checkout 5b5588e - Note: checking out '5b5588e'. - - You are in 'detached HEAD' state. You can look around, make experimental - changes and commit them, and you can discard any commits you make in this - state without impacting any branches by performing another checkout. - - If you want to create a new branch to retain commits you create, you may - do so (now or later) by using -b with the checkout command again. Example: - - git checkout -b new_branch_name - - HEAD is now at 5b5588e... base commit - [user@localhost]$ git checkout -b second_branch - Switched to a new branch 'second_branch' - [user@localhost]$ git branch - first_branch - * second_branch - [user@localhost]$ git log --oneline - 5b5588e base commit - -Now, we make a copy of commit B in the current branch:: - - [user@localhost]$ git cherry-pick 7873447 - [second_branch 758522b] added file B - 1 file changed, 1 insertion(+) - create mode 100644 file_B.py - [user@localhost]$ git log --oneline - 758522b added file B - 5b5588e base commit - -Note that this changes the SHA1 of the commit B, since its parent -changed! Also, cherry-picking *copies* commits, it does not remove -them from the source branch. So we now have to modify the first branch -to exclude commit B, otherwise there will be two commits adding -``file_B.py`` and our two branches would conflict later when they are -being merged into Sage. Hence, we first reset the first branch back to -before B was added:: - - [user@localhost]$ git checkout first_branch - Switched to branch 'first_branch' - [user@localhost]$ git reset --hard bf817a5 - HEAD is now at bf817a5 added file A - -Now we still want commit C, so we cherry-pick it again. Note that this -works even though commit C is, at this point, not included in any -branch:: - - [user@localhost]$ git cherry-pick 9621dae - [first_branch 5844535] added file C - 1 file changed, 1 insertion(+) - create mode 100644 file_C.py - [user@localhost]$ git log --oneline - 5844535 added file C - bf817a5 added file A - 5b5588e base commit - -And, again, we note that the SHA1 of commit C changed because its -parent changed. Voila, now you have two branches where the first -contains commits A, C and the second contains commit B. - - -.. _section-git-interactive-rebase: - -Interactively Rebasing -====================== - -An alternative approach to :ref:`section-git-rewriting-history` is to -use the interactive rebase feature. This will open an editor where you -can modify the most recent commits. Again, this will naturally modify -the hash of all changed commits and all of their children. - -Now we start by making an identical branch to the first branch:: - - [user@localhost]$ git log --oneline - 9621dae added file C - 7873447 added file B - bf817a5 added file A - 5b5588e base commit - [user@localhost]$ git checkout -b second_branch - Switched to a new branch 'second_branch' - [user@localhost]$ git rebase -i HEAD~3 - -This will open an editor with the last 3 (corresponding to ``HEAD~3``) -commits and instuctions for how to modify them: - -.. CODE-BLOCK:: text - - pick bf817a5 added file A - pick 7873447 added file B - pick 9621dae added file C - - # Rebase 5b5588e..9621dae onto 5b5588e - # - # Commands: - # p, pick = use commit - # r, reword = use commit, but edit the commit message - # e, edit = use commit, but stop for amending - # s, squash = use commit, but meld into previous commit - # f, fixup = like "squash", but discard this commit's log message - # x, exec = run command (the rest of the line) using shell - # - # These lines can be re-ordered; they are executed from top to bottom. - # - # If you remove a line here THAT COMMIT WILL BE LOST. - # - # However, if you remove everything, the rebase will be aborted. - # - # Note that empty commits are commented out - -To only use commit B, we delete the first and third line. Then save -and quit your editor, and your branch now consists only of the B commit. - -You still have to delete the B commit from the first branch, so you -would go back (``git checkout first_branch``) and then run the same -``git rebase -i`` command and delete the B commit. - diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index 0371341a3ab..4821dabfd68 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -31,7 +31,7 @@ style conventions discussed in this chapter. .. _section-coding-python: -Python Code Style +Python code style ================= Follow the standard Python formatting rules when writing code for @@ -90,7 +90,7 @@ In particular, .. _chapter-directory-structure: -Files and Directory Structure +Files and directory structure ============================= Roughly, the Sage directory tree is layout like this. Note that we use @@ -193,7 +193,7 @@ search, but restricted to function definitions, while docstrings for more information and more options. -Headings of Sage Library Code Files +Headings of Sage library code files =================================== The top of each Sage code file should follow this format:: @@ -240,7 +240,7 @@ compatible, that is, less restrictive license (e.g. the BSD license). .. _section-docstrings: -Documentation Strings +Documentation strings ===================== .. _section-docstring-function: @@ -473,7 +473,7 @@ information. You can use the existing functions of Sage as templates. Note the trailing underscores which makes the citations into hyperlinks. See below for more about the master bibliography file. For more about citations, see the `Sphinx/reST markup for citations - <https://www.sphinx-doc.org/rest.html#citations>`_. For links to trac tickets + <https://www.sphinx-doc.org/rest.html#citations>`_. For links to GitHub issues and PRs or wikipedia, see :ref:`chapter-sage_manuals_links`. - A **TESTS** block (highly recommended). @@ -771,7 +771,7 @@ there is not one already. That is, you can do the following: .. _section-latex-typeset: -LaTeX Typesetting +LaTeX typesetting ----------------- In Sage's documentation LaTeX code is allowed and is marked with **backticks**: @@ -875,7 +875,7 @@ for details about how to add more macros. .. _section-doctest-writing: -Writing Testable Examples +Writing testable examples ------------------------- The examples from Sage's documentation have a double purpose: @@ -935,8 +935,17 @@ written. Sage does not know about the function ``AA()`` by default, so it needs to be imported before it is tested. Hence the first line in the example. + All blocks within the same docstring are linked: Variables set + in a doctest keep their values for the remaining doctests within the + same docstring. It is good practice to use different variable names for different + values, as it makes the data flow in the examples easier to understand + for human readers. (It also makes the data flow analysis in the + Sage doctester more precise.) In particular, when unrelated examples + appear in the same docstring, do not use the same variable name + for both examples. + - **Preparsing:** As in Sage's console, `4/3` returns `4/3` and not - `1.3333333333333333` as in Python 3.8. Testing occurs with full Sage + `1.3333333333333333` as in Python. Testing occurs with full Sage preparsing of input within the standard Sage shell environment, as described in :ref:`section-preparsing`. @@ -958,6 +967,78 @@ written. 5 7 +- **Wrap long doctest lines:** Note that all doctests in EXAMPLES blocks + get formatted as part of our HTML and PDF reference manuals. Our HTML manuals + are formatted using the responsive design provided by the + :ref:`Furo theme <spkg_furo>`. Even when the browser window is expanded to + make use of the full width of a wide desktop screen, the style will not + allow code boxes to grow arbitrarily wide. + + It is best to wrap long lines when possible so that readers do not have to + scroll horizontally (back and forth) to follow an example. + + - Try to wrap long lines somewhere around columns 80 to 88 + and try to never exceed column 95 in the source file. + (Columns numbers are from the left margin in the source file; + these rules work no matter how deep the docstring may be nested + because also the formatted output will be nested.) + + - If you have to break an expression at a place that is not already + nested in parentheses, wrap it in parentheses:: + + sage: (len(list(Permutations(['a', 'b', 'c', 'd', 'e', 'f', 'g']))) + ....: == len(list(Permutations(7)))) + True + + - If the output in your only example is very wide and cannot be reasonably + reformatted to fit (for example, large symbolic matrices or numbers with many digits), + consider showing a smaller example first. + + - No need to wrap long ``import`` statements. Typically, the ``import`` statements + are not the interesting parts of the doctests. Users only need to be able to + copy-paste them into a Sage session or source file:: + + sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict, MPolynomialRing_polydict_domain # this is fine + + - Wrap and indent long output to maximize readability in the source code + and in the HTML output. But do not wrap strings:: + + sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi + sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) + sage: S = P.subscheme([]) + sage: T = P.subscheme([x - y]) + sage: U = AlgebraicScheme_quasi(S, T); U + Quasi-projective subscheme X - Y of Projective Space of dimension 2 + over Integer Ring, + where X is defined by: (no polynomials) + and Y is defined by: x - y + sage: U._repr_() # this is fine + 'Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, where X is defined by:\n (no polynomials)\nand Y is defined by:\n x - y' + + Also, if there is no whitespace in the doctest output where you could wrap the line, + do not add such whitespace. Just don't wrap the line:: + + sage: B47 = RibbonGraph(4,7, bipartite=True); B47 + Ribbon graph of genus 9 and 1 boundary components + sage: B47.sigma() # this is fine + (1,2,3,4,5,6,7)(8,9,10,11,12,13,14)(15,16,17,18,19,20,21)(22,23,24,25,26,27,28)(29,30,31,32)(33,34,35,36)(37,38,39,40)(41,42,43,44)(45,46,47,48)(49,50,51,52)(53,54,55,56) + + - Doctest tags for modularization purposes such as ``# needs sage.modules`` + (see :ref:`section-further_conventions`) should be aligned at column 88. + Clean lines from consistent alignment help reduce visual clutter. + Moreover, at the maximum window width, only the word ``# needs`` will be + visible in the HTML output without horizontal scrolling, striking a + thoughtfully chosen balance between presenting + the information and reducing visual clutter. (How much can be seen may be + browser-dependent, of course.) In visually dense doctests, you can try to sculpt out visual space to separate + the test commands from the annotation. + + - Doctest tags such as ``# optional - pynormaliz`` that make the doctest + conditional on the presence of optional packages, on the other hand, + should be aligned so that they are visible without having to scroll horizontally. + The :ref:`doctest fixer <section-fixdoctests-optional-needs>` uses + tab stops at columns 48, 56, 64, ... for these tags. + - **Python3 print:** Python3 syntax for print must be used in Sage code and doctests. If you use an old-style print in doctests, it will raise a SyntaxError:: @@ -983,7 +1064,7 @@ written. .. _section-further_conventions: -Special Markup to Influence Doctests +Special markup to influence doctests ------------------------------------ Overly complicated output in the example code can be shortened @@ -1092,9 +1173,9 @@ framework. Here is a comprehensive list: sage: print("The sum of 1 and 1 equals 5") # abs tol 1 The sum of 2 and 2 equals 4 - sage: e^(i*pi/4).n() # rel tol 1e-1 + sage: e^(i*pi/4).n() # rel tol 1e-1 0.7 + 0.7*I - sage: ((x+1.001)^4).expand() # rel tol 2 + sage: ((x+1.001)^4).expand() # rel tol 2 x^4 + 4*x^3 + 6*x^2 + 4*x + 1 sage: M = matrix.identity(3) + random_matrix(RR,3,3)/10^3 sage: M^2 # abs tol 1e-2 @@ -1131,8 +1212,9 @@ framework. Here is a comprehensive list: Neither of this applies to files or directories which are explicitly given as command line arguments: those are always tested. -- **optional:** A line flagged with ``optional - keyword`` is not tested unless - the ``--optional=keyword`` flag is passed to ``sage -t`` (see +- **optional/needs:** A line tagged with ``optional - FEATURE`` + or ``needs FEATURE`` is not tested unless the ``--optional=KEYWORD`` flag + is passed to ``sage -t`` (see :ref:`section-optional-doctest-flag`). The main applications are: - **optional packages:** When a line requires an optional package to be @@ -1140,26 +1222,6 @@ framework. Here is a comprehensive list: sage: SloaneEncyclopedia[60843] # optional - sloane_database - .. NOTE:: - - If one of the first 10 lines of a file starts with any of - ``r""" sage.doctest: optional - keyword`` - (or ``""" sage.doctest: optional - keyword`` - or ``# sage.doctest: optional - keyword`` - or ``% sage.doctest: optional - keyword`` - or ``.. sage.doctest: optional - keyword``, - or any of these with different spacing), - then that file will be skipped unless - the ``--optional=keyword`` flag is passed to ``sage -t``. - - This does not apply to files which are explicitly given - as command line arguments: those are always tested. - - If you add such a line to a file, you are strongly encouraged - to add a note to the module-level documentation, saying that - the doctests in this file will be skipped unless the - appropriate conditions are met. - - **internet:** For lines that require an internet connection:: sage: oeis(60843) # optional - internet @@ -1167,33 +1229,67 @@ framework. Here is a comprehensive list: n-state Turing machine can make on an initially blank tape before eventually halting. - - **bug:** For lines that describe bugs. Alternatively, use ``# known bug`` - instead: it is an alias for ``optional bug``. + - **known bugs:** For lines that describe known bugs, you can use ``# optional - bug``, + although ``# known bug`` is preferred. .. CODE-BLOCK:: rest - The following should yield 4. See :trac:`2`. :: + The following should yield 4. See :issue:`2`. :: sage: 2+2 # optional - bug 5 sage: 2+2 # known bug 5 + - **modularization:** To enable + :ref:`separate testing of the distribution packages <section-doctesting-venv>` + of the modularized Sage library, doctests that depend on features provided + by other distribution packages can be tagged ``# needs FEATURE``. + For example: + + .. CODE-BLOCK:: rest + + Consider the following calculation:: + + sage: a = AA(2).sqrt() # needs sage.rings.number_field + sage: b = sqrt(3) # needs sage.symbolic + sage: a + AA(b) # needs sage.rings.number_field sage.symbolic + 3.146264369941973? + .. NOTE:: - - Any words after ``# optional`` are interpreted as a list of + - Any words after ``# optional`` and ``# needs`` are interpreted as a list of package (spkg) names or other feature tags, separated by spaces. - Any punctuation other than underscores (``_``) and periods (``.``), that is, commas, hyphens, semicolons, ..., after the first word ends the list of packages. Hyphens or colons between the word ``optional`` and the first package name are allowed. Therefore, - you should not write ``optional: needs package CHomP`` but simply - ``optional: CHomP``. + you should not write ``# optional - depends on package CHomP`` but simply + ``# optional - CHomP``. - - Optional tags are case-insensitive, so you could also write ``optional: + - Optional tags are case-insensitive, so you could also write ``# optional - chOMP``. + If ``# optional`` or ``# needs`` is placed right after the ``sage:`` prompt, + it is a block-scoped tag, which applies to all doctest lines until + a blank line is encountered. + + These tags can also be applied to an entire file. If one of the first 10 lines + of a file starts with any of ``r""" sage.doctest: optional - FEATURE``, + ``# sage.doctest: needs FEATURE``, or ``.. sage.doctest: optional - FEATURE`` + (in ``.rst`` files), etc., then this applies to all doctests in this file. + + When a file is skipped that was explicitly given as a command line argument, + a warning is displayed. + + .. NOTE:: + + If you add such a line to a file, you are strongly encouraged + to add a note to the module-level documentation, saying that + the doctests in this file will be skipped unless the + appropriate conditions are met. + - **indirect doctest:** in the docstring of a function ``A(...)``, a line calling ``A`` and in which the name ``A`` does not appear should have this flag. This prevents ``sage --coverage <file>`` from reporting the docstring as @@ -1219,6 +1315,22 @@ framework. Here is a comprehensive list: 8193 # 32-bit 2147491840 # 64-bit +Per coding style (:ref:`section-coding-python`), the magic comment +should be separated by at least 2 spaces. + +For multiline doctests, the comment should appear on the first +`physical line <https://docs.python.org/3/reference/lexical_analysis.html#physical-lines>`_ +of the doctest (the line with the prompt ``sage:``), not on the +continuation lines (the lines with the prompt ``....:``):: + + sage: print(ZZ.random_element()) # random + 42 + sage: for _ in range(3): # random + ....: print(QQ.random_element()) + 1 + 1/77 + -1/2 + Using ``search_src`` from the Sage prompt (or ``grep``), one can easily find the aforementioned keywords. In the case of ``todo: not implemented``, one can use the results of such a search to direct @@ -1226,7 +1338,7 @@ further development on Sage. .. _chapter-testing: -Running Automated Doctests +Running automated doctests ========================== This section describes Sage's automated testing of test files of the @@ -1241,7 +1353,7 @@ doctesting modules in the Sage library. .. _section-testpython: -Testing .py, .pyx and .sage Files +Testing .py, .pyx and .sage files --------------------------------- Run ``sage -t <filename.py>`` to test all code examples in @@ -1266,7 +1378,7 @@ write for the documentation and have them work. For more information, see :ref:`chapter-doctesting`. -Testing reST Documentation +Testing reST documentation -------------------------- Run ``sage -t <filename.rst>`` to test the examples in verbatim @@ -1309,7 +1421,7 @@ Sage. .. _section-coding-general-whitespace: -General Coding Style Regarding Whitespace +General coding style regarding whitespace ========================================= Use spaces instead of tabs for indentation. The only exception is for @@ -1327,7 +1439,7 @@ If you use another editor, we recommend to configure it so you do not add tabs to files. See :ref:`section-ide`. -Global Options +Global options ============== Global options for classes can be defined in Sage using diff --git a/src/doc/en/developer/coding_in_cython.rst b/src/doc/en/developer/coding_in_cython.rst index f5aa767c3cc..829b8234e7b 100644 --- a/src/doc/en/developer/coding_in_cython.rst +++ b/src/doc/en/developer/coding_in_cython.rst @@ -32,7 +32,7 @@ up-to-date information or check out the to get started immediately. -Writing Cython Code in Sage +Writing cython code in Sage =========================== There are several ways to create and build Cython code in Sage. @@ -69,7 +69,7 @@ There are several ways to create and build Cython code in Sage. Then run ``sage -b`` to rebuild Sage. -Attaching or Loading .spyx Files +Attaching or loading .spyx files ================================ The easiest way to try out Cython without having to learn anything @@ -142,7 +142,7 @@ version with a type declaration, by changing ``def is2pow(n):`` to .. _section-interrupt: -Interrupt and Signal Handling +Interrupt and signal handling ============================= When writing Cython code for Sage, special care must be taken to ensure @@ -152,7 +152,7 @@ Sage uses the `cysignals package <https://github.com/sagemath/cysignals>`_ for this, see the `cysignals documentation <http://cysignals.readthedocs.org/>`_ for more information. -Unpickling Cython Code +Unpickling Cython code ====================== Pickling for Python classes and extension classes, such as Cython, is different. diff --git a/src/doc/en/developer/coding_in_other.rst b/src/doc/en/developer/coding_in_other.rst index e7891af92d7..544add15b88 100644 --- a/src/doc/en/developer/coding_in_other.rst +++ b/src/doc/en/developer/coding_in_other.rst @@ -20,7 +20,7 @@ In this chapter, we discuss interfaces between Sage and :ref:`PARI .. _section-pari-library: -The PARI C Library Interface +The PARI C library interface ============================ Here is a step-by-step guide to adding new PARI functions to Sage. We @@ -570,7 +570,7 @@ One more example (in addition to the one in the docstring): ((0, 1, 0), (1, 0, 0), (0, 0, 1)) -Singular: Another Approach +Singular: another approach ========================== There is also a more Python-like interface to Singular. Using this, @@ -626,7 +626,7 @@ implemented in the Sage/Singular interface, whereas the code in the previous section used only the barest minimum of that interface. -Creating a New Pseudo-TTY Interface +Creating a new pseudo-TTY interface =================================== You can create Sage pseudo-tty interfaces that allow Sage to work with @@ -708,7 +708,7 @@ dumps the user into an Octave interactive shell: Use octave to compute a solution x to A*x = b, as a list. INPUT: - + - A -- mxn matrix A with entries in QQ or RR - b -- m-vector b entries in QQ or RR (resp) diff --git a/src/doc/en/developer/coding_in_python.rst b/src/doc/en/developer/coding_in_python.rst index 55633c8a029..d96106ecc98 100644 --- a/src/doc/en/developer/coding_in_python.rst +++ b/src/doc/en/developer/coding_in_python.rst @@ -8,7 +8,7 @@ This chapter discusses some issues with, and advice for, coding in Sage. -Python Language Standard +Python language standard ======================== Sage library code needs to be compatible with all versions of Python @@ -16,27 +16,36 @@ that Sage supports. The information regarding the supported versions can be found in the files ``build/pkgs/python3/spkg-configure.m4`` and ``src/setup.cfg.m4``. -As of Sage 9.7, Python 3.8 is the oldest supported version. Hence, -all language and library features that are available in Python 3.8 can -be used; but features introduced in Python 3.9 cannot be used. If a +Python 3.9 is the oldest supported version. Hence, +all language and library features that are available in Python 3.9 can +be used; but features introduced in Python 3.10 cannot be used. If a feature is deprecated in a newer supported version, it must be ensured that deprecation warnings issued by Python do not lead to failures in doctests. -Some key language and library features have been backported to Python 3.8 +Some key language and library features have been backported to older Python versions using one of two mechanisms: -- ``from __future__ import annotations`` (see - https://docs.python.org/3.7/library/__future__.html) modernizes type - annotations according to PEP 563 (Postponed evaluation of - annotations, see https://www.python.org/dev/peps/pep-0563). All - Sage library code that uses type annotations should include this - ``__future__`` import and follow PEP 563. +- ``from __future__ import annotations`` (see Python reference for + `__future__ <https://docs.python.org/3/library/__future__.html>`_) + modernizes type annotations according to `PEP 563 + <https://www.python.org/dev/peps/pep-0563>`_ (Postponed evaluation + of annotations). All Sage library code that uses type annotations + should include this ``__future__`` import and follow PEP 563. -- The Sage distribution includes the backport packages ``importlib_metadata`` - and ``importlib_resources``. +- Backport packages -Meta-ticket :trac:`29756` keeps track of newer Python features and serves + - `importlib_metadata <../reference/spkg/importlib_metadata>`_ + (to be used in place of ``importlib.metadata``), + - `importlib_resources <../reference/spkg/importlib_resources>`_ + (to be used in place of ``importlib.resources``), + - `typing_extensions <../reference/spkg/typing_extensions>`_ + (to be used in place of ``typing``). + + The Sage library declares these packages as dependencies and ensures that + versions that provide features of Python 3.11 are available. + +Meta :issue:`29756` keeps track of newer Python features and serves as a starting point for discussions on how to make use of them in the Sage library. @@ -55,7 +64,7 @@ scratch. Try to figure out how your code should fit in with other Sage code, and design it accordingly. -Special Sage Functions +Special sage functions ====================== Functions with leading and trailing double underscores ``__XXX__`` are @@ -148,7 +157,7 @@ representing the object ``a``. Calling ``view(a)`` will display the typeset version of this. -Print Representation +Print representation -------------------- The standard Python printing method is ``__repr__(self)``. In Sage, @@ -184,7 +193,7 @@ Here is an example of the ``_latex_`` and ``_repr_`` functions for the return "\\pi" -Matrix or Vector from Object +Matrix or vector from object ---------------------------- Provide a ``_matrix_`` method for an object that can be coerced to a @@ -223,7 +232,7 @@ will work for this object. The following is from the file .. _section-preparsing: -Sage Preparsing +Sage preparsing =============== To make Python even more usable interactively, there are a number of @@ -298,7 +307,7 @@ In particular, the file ``preparse.py`` contains the Sage preparser code. -The Sage Coercion Model +The Sage coercion model ======================= The primary goal of coercion is to be able to transparently do @@ -337,7 +346,7 @@ immutable later. See the file ``SAGE_ROOT/src/sage/structure/mutability.py``. -The __hash__ Special Method +The __hash__ special method ============================ Here is the definition of ``__hash__`` from the Python reference @@ -465,7 +474,7 @@ Note that the syntax in ``except`` is to list all the exceptions that are caught as a tuple, followed by an error message. -Integer Return Values +Integer return values ===================== Many functions and methods in Sage return integer values. @@ -576,8 +585,6 @@ by return initialize_big_data() - - Deprecation =========== @@ -590,7 +597,7 @@ in the future. We call this a *deprecation*. Deprecated code can only be removed one year after the first stable release in which it appeared. -Each deprecation warning contains the number of the trac ticket that defines +Each deprecation warning contains the number of the GitHub PR that defines it. We use 666 in the examples below. For each entry, consult the function's documentation for more information on its behaviour and optional arguments. @@ -663,7 +670,7 @@ documentation for more information on its behaviour and optional arguments. deprecation(666, "Do not use your computer to compute 1+1. Use your brain.") -Experimental/Unstable Code +Experimental/unstable code -------------------------- You can mark your newly created code (classes/functions/methods) as @@ -711,7 +718,7 @@ reviewing process. experimental_warning(66666, 'This code is not foolproof.') -Using Optional Packages +Using optional packages ======================= If a function requires an optional package, that function should fail diff --git a/src/doc/en/developer/conf.py b/src/doc/en/developer/conf.py index bde00a0970d..9dcfc261ed1 100644 --- a/src/doc/en/developer/conf.py +++ b/src/doc/en/developer/conf.py @@ -21,7 +21,7 @@ html_static_path = [] + html_common_static_path # General information about the project. -project = "Developer's Guide" +project = "Developer Guide" # The name for this set of Sphinx documents. html_title = project @@ -33,6 +33,6 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [ - ('index', 'developer.tex', 'Developer\'s Guide', + ('index', 'developer.tex', 'Developer Guide', 'The Sage Development Team', 'manual'), ] diff --git a/src/doc/en/developer/doctesting.rst b/src/doc/en/developer/doctesting.rst index 9619460c30f..589c9260134 100644 --- a/src/doc/en/developer/doctesting.rst +++ b/src/doc/en/developer/doctesting.rst @@ -5,7 +5,7 @@ .. _chapter-doctesting: ======================= -Running Sage's doctests +Running Sage's Doctests ======================= Doctesting a function ensures that the function performs as claimed by @@ -13,11 +13,11 @@ its documentation. Testing can be performed using one thread or multiple threads. After compiling a source version of Sage, doctesting can be run on the whole Sage library, on all modules under a given directory, or on a specified module only. For the purposes of this -chapter, suppose we have compiled Sage 6.0 from source and the top -level Sage directory is:: +chapter, suppose we have compiled Sage from source and the top +level directory is:: - [jdemeyer@sage sage-6.0]$ pwd - /scratch/jdemeyer/build/sage-6.0 + [jdemeyer@localhost sage]$ pwd + /home/jdemeyer/sage See the section :ref:`chapter-testing` for information on Sage's automated testing process. The general syntax for doctesting is as @@ -35,7 +35,7 @@ either a Python script (with the file extension ".py") or it can be a Cython script, in which case it has the file extension ".pyx". -Testing a Module +Testing a module ================ Say we want to run all tests in the sudoku module @@ -43,7 +43,7 @@ Say we want to run all tests in the sudoku module top level Sage directory of our local Sage installation. Now we can start doctesting as demonstrated in the following terminal session:: - [jdemeyer@sage sage-6.0]$ ./sage -t src/sage/games/sudoku.py + [jdemeyer@localhost sage]$ ./sage -t src/sage/games/sudoku.py Running doctests with ID 2012-07-03-03-36-49-d82849c6. Doctesting 1 file. sage -t src/sage/games/sudoku.py @@ -63,7 +63,7 @@ one module so it is not surprising that the total testing time is approximately the same as the time required to test only that one module. Notice that the syntax is:: - [jdemeyer@sage sage-6.0]$ ./sage -t src/sage/games/sudoku.py + [jdemeyer@localhost sage]$ ./sage -t src/sage/games/sudoku.py Running doctests with ID 2012-07-03-03-39-02-da6accbb. Doctesting 1 file. sage -t src/sage/games/sudoku.py @@ -77,7 +77,7 @@ module. Notice that the syntax is:: but not:: - [jdemeyer@sage sage-6.0]$ ./sage -t sage/games/sudoku.py + [jdemeyer@localhost sage]$ ./sage -t sage/games/sudoku.py Running doctests with ID 2012-07-03-03-40-53-6cc4f29f. No files matching sage/games/sudoku.py No files to doctest @@ -85,11 +85,11 @@ but not:: We can also first ``cd`` to the directory containing the module ``sudoku.py`` and doctest that module as follows:: - [jdemeyer@sage sage-6.0]$ cd src/sage/games/ - [jdemeyer@sage games]$ ls + [jdemeyer@localhost sage]$ cd src/sage/games/ + [jdemeyer@localhost games]$ ls __init__.py hexad.py sudoku.py sudoku_backtrack.pyx all.py quantumino.py sudoku_backtrack.c - [jdemeyer@sage games]$ ../../../../sage -t sudoku.py + [jdemeyer@localhost games]$ ../../../../sage -t sudoku.py Running doctests with ID 2012-07-03-03-41-39-95ebd2ff. Doctesting 1 file. sage -t sudoku.py @@ -108,7 +108,7 @@ installation is a recipe for confusion. You can also run the Sage doctester as follows:: - [jdemeyer@sage sage-6.0]$ ./sage -tox -e doctest -- src/sage/games/sudoku.py + [jdemeyer@localhost sage]$ ./sage -tox -e doctest -- src/sage/games/sudoku.py See :ref:`chapter-tools` for more information about tox. @@ -126,7 +126,7 @@ our system has multiple Sage installations. For example, the following syntax is acceptable because we explicitly specify the Sage installation in the current ``SAGE_ROOT``:: - [jdemeyer@sage sage-6.0]$ ./sage -t src/sage/games/sudoku.py + [jdemeyer@localhost sage]$ ./sage -t src/sage/games/sudoku.py Running doctests with ID 2012-07-03-03-43-24-a3449f54. Doctesting 1 file. sage -t src/sage/games/sudoku.py @@ -137,7 +137,7 @@ installation in the current ``SAGE_ROOT``:: Total time for all tests: 4.9 seconds cpu time: 3.6 seconds cumulative wall time: 3.6 seconds - [jdemeyer@sage sage-6.0]$ ./sage -t "src/sage/games/sudoku.py" + [jdemeyer@localhost sage]$ ./sage -t "src/sage/games/sudoku.py" Running doctests with ID 2012-07-03-03-43-54-ac8ca007. Doctesting 1 file. sage -t src/sage/games/sudoku.py @@ -156,10 +156,10 @@ Sage installation (if it exists): :: - [jdemeyer@sage sage-6.0]$ sage -t src/sage/games/sudoku.py + [jdemeyer@localhost sage]$ sage -t src/sage/games/sudoku.py sage -t "src/sage/games/sudoku.py" ********************************************************************** - File "/home/jdemeyer/sage/sage-6.0/src/sage/games/sudoku.py", line 515: + File "/home/jdemeyer/sage/src/sage/games/sudoku.py", line 515: sage: next(h.solve(algorithm='backtrack')) Exception raised: Traceback (most recent call last): @@ -198,7 +198,7 @@ installation is a different (older) version than the one we are using for Sage development. Make sure you always test the files with the correct version of Sage. -Parallel Testing Many Modules +Parallel testing many modules ============================= So far we have used a single thread to doctest a module in the Sage @@ -215,7 +215,7 @@ and then using four threads. For this example, suppose we want to test all the modules under ``sage/crypto/``. We can use a syntax similar to that shown above to achieve this:: - [jdemeyer@sage sage-6.0]$ ./sage -t src/sage/crypto + [jdemeyer@localhost sage]$ ./sage -t src/sage/crypto Running doctests with ID 2012-07-03-03-45-40-7f837dcf. Doctesting 24 files. sage -t src/sage/crypto/__init__.py @@ -276,7 +276,7 @@ that shown above to achieve this:: Now we do the same thing, but this time we also use the optional argument ``--long``:: - [jdemeyer@sage sage-6.0]$ ./sage -t --long src/sage/crypto/ + [jdemeyer@localhost sage]$ ./sage -t --long src/sage/crypto/ Running doctests with ID 2012-07-03-03-48-11-c16721e6. Doctesting 24 files. sage -t --long src/sage/crypto/__init__.py @@ -372,7 +372,7 @@ as taking a long time: Now we doctest the same directory in parallel using 4 threads:: - [jdemeyer@sage sage-6.0]$ ./sage -tp 4 src/sage/crypto/ + [jdemeyer@localhost sage]$ ./sage -tp 4 src/sage/crypto/ Running doctests with ID 2012-07-07-00-11-55-9b17765e. Sorting sources by runtime so that slower doctests are run first.... Doctesting 24 files using 4 threads. @@ -430,7 +430,7 @@ Now we doctest the same directory in parallel using 4 threads:: Total time for all tests: 12.9 seconds cpu time: 30.5 seconds cumulative wall time: 31.7 seconds - [jdemeyer@sage sage-6.0]$ ./sage -tp 4 --long src/sage/crypto/ + [jdemeyer@localhost sage]$ ./sage -tp 4 --long src/sage/crypto/ Running doctests with ID 2012-07-07-00-13-04-d71f3cd4. Sorting sources by runtime so that slower doctests are run first.... Doctesting 24 files using 4 threads. @@ -495,7 +495,7 @@ decreases. .. _section-parallel-test-whole-library: -Parallel Testing the Whole Sage Library +Parallel testing the whole Sage library ======================================= The main Sage library resides in the directory @@ -504,7 +504,7 @@ to doctest the main library using multiple threads. When doing release management or patching the main Sage library, a release manager would parallel test the library using 10 threads with the following command:: - [jdemeyer@sage sage-6.0]$ ./sage -tp 10 --long src/ + [jdemeyer@localhost sage]$ ./sage -tp 10 --long src/ Another way is run ``make ptestlong``, which builds Sage (if necessary), builds the Sage documentation (if necessary), and then runs parallel @@ -516,7 +516,7 @@ the number of CPU cores (as determined by the Python function In any case, this will test the Sage library with multiple threads:: - [jdemeyer@sage sage-6.0]$ make ptestlong + [jdemeyer@localhost sage]$ make ptestlong Any of the following commands would also doctest the Sage library or one of its clones: @@ -569,14 +569,15 @@ you can execute Some of the extra testing options are discussed here; run ``sage -t -h`` for a complete list. -Beyond the Sage Library + +Beyond the Sage library ======================= Doctesting also works fine for files not in the Sage library. For example, suppose we have a Python script called ``my_python_script.py``:: - [mvngu@sage build]$ cat my_python_script.py + [mvngu@localhost sage]$ cat my_python_script.py from sage.all_cmdline import * # import sage library def square(n): @@ -592,7 +593,7 @@ example, suppose we have a Python script called Then we can doctest it just as with Sage library files:: - [mvngu@sage sage-6.0]$ ./sage -t my_python_script.py + [mvngu@localhost sage]$ ./sage -t my_python_script.py Running doctests with ID 2012-07-07-00-17-56-d056f7c0. Doctesting 1 file. sage -t my_python_script.py @@ -607,7 +608,7 @@ Then we can doctest it just as with Sage library files:: Doctesting can also be performed on Sage scripts. Say we have a Sage script called ``my_sage_script.sage`` with the following content:: - [mvngu@sage sage-6.0]$ cat my_sage_script.sage + [mvngu@localhost sage]$ cat my_sage_script.sage def cube(n): r""" Return the cube of n. @@ -621,7 +622,7 @@ script called ``my_sage_script.sage`` with the following content:: Then we can doctest it just as for Python files:: - [mvngu@sage build]$ sage-6.0/sage -t my_sage_script.sage + [mvngu@localhost sage]$ ./sage -t my_sage_script.sage Running doctests with ID 2012-07-07-00-20-06-82ee728c. Doctesting 1 file. sage -t my_sage_script.sage @@ -636,8 +637,8 @@ Then we can doctest it just as for Python files:: Alternatively, we can preparse it to convert it to a Python script, and then doctest that:: - [mvngu@sage build]$ sage-6.0/sage --preparse my_sage_script.sage - [mvngu@sage build]$ cat my_sage_script.sage.py + [mvngu@localhost sage]$ ./sage --preparse my_sage_script.sage + [mvngu@localhost sage]$ cat my_sage_script.sage.py # This file was *autogenerated* from the file my_sage_script.sage. from sage.all_cmdline import * # import sage library _sage_const_3 = Integer(3) @@ -651,7 +652,7 @@ and then doctest that:: 8 """ return n**_sage_const_3 - [mvngu@sage build]$ sage-6.0/sage -t my_sage_script.sage.py + [mvngu@localhost sage]$ ./sage -t my_sage_script.sage.py Running doctests with ID 2012-07-07-00-26-46-2bb00911. Doctesting 1 file. sage -t my_sage_script.sage.py @@ -663,7 +664,8 @@ and then doctest that:: cpu time: 0.0 seconds cumulative wall time: 0.0 seconds -Doctesting from Within Sage + +Doctesting from within Sage =========================== You can run doctests from within Sage, which can be useful since you @@ -686,12 +688,13 @@ function in the global namespace, passing it either a string or a module: cpu time: 3.6 seconds cumulative wall time: 4.3 seconds + .. _section-options: -Optional Arguments +Optional arguments ================== -Run Long Doctests +Run long doctests ----------------- Ideally, doctests should not take any noticeable amount of time. If @@ -713,7 +716,7 @@ Use the ``--long`` flag to run doctests that have been marked with the comment ``# long time``. These tests are normally skipped in order to reduce the time spent running tests:: - [roed@sage sage-6.0]$ sage -t src/sage/rings/tests.py + [roed@localhost sage]$ ./sage -t src/sage/rings/tests.py Running doctests with ID 2012-06-21-16-00-13-40835825. Doctesting 1 file. sage -t tests.py @@ -727,7 +730,7 @@ reduce the time spent running tests:: In order to run the long tests as well, do the following:: - [roed@sage sage-6.0]$ sage -t --long src/sage/rings/tests.py + [roed@localhost sage]$ ./sage -t --long src/sage/rings/tests.py Running doctests with ID 2012-06-21-16-02-05-d13a9a24. Doctesting 1 file. sage -t tests.py @@ -744,7 +747,7 @@ To find tests that take longer than the allowed time use the print a warning if they take longer than 1.0 second. Note that this is a warning, not an error:: - [roed@sage sage-6.0]$ sage -t --warn-long src/sage/rings/factorint.pyx + [roed@localhost sage]$ ./sage -t --warn-long src/sage/rings/factorint.pyx Running doctests with ID 2012-07-14-03-27-03-2c952ac1. Doctesting 1 file. sage -t --warn-long src/sage/rings/factorint.pyx @@ -778,7 +781,7 @@ a warning, not an error:: You can also pass in an explicit amount of time:: - [roed@sage sage-6.0]$ sage -t --long --warn-long 2.0 src/sage/rings/tests.py + [roed@localhost sage]$ ./sage -t --long --warn-long 2.0 src/sage/rings/tests.py Running doctests with ID 2012-07-14-03-30-13-c9164c9d. Doctesting 1 file. sage -t --long --warn-long 2.0 tests.py @@ -805,7 +808,7 @@ Finally, you can disable any warnings about long tests with Doctests start from a random seed:: - [kliem@sage sage-9.2]$ sage -t src/sage/doctest/tests/random_seed.rst + [kliem@localhost sage]$ ./sage -t src/sage/doctest/tests/random_seed.rst Running doctests with ID 2020-06-23-23-22-59-49f37a55. ... Doctesting 1 file. @@ -831,7 +834,9 @@ Doctests start from a random seed:: This seed can be set explicitly to reproduce possible failures:: - [kliem@sage sage-9.2]$ sage -t --warn-long 89.5 --random-seed=112986622569797306072457879734474628454 src/sage/doctest/tests/random_seed.rst + [kliem@localhost sage]$ ./sage -t --warn-long 89.5 \ + --random-seed=112986622569797306072457879734474628454 \ + src/sage/doctest/tests/random_seed.rst Running doctests with ID 2020-06-23-23-24-28-14a52269. ... Doctesting 1 file. @@ -858,20 +863,20 @@ This seed can be set explicitly to reproduce possible failures:: It can also be set explicitly using the environment variable ``SAGE_DOCTEST_RANDOM_SEED``. + .. _section-optional-doctest-flag: -Run Optional Doctests +Run optional doctests --------------------- You can run tests that require optional packages by using the ``--optional`` flag. Obviously, you need to have installed the -necessary optional packages in order for these tests to succeed. See -http://www.sagemath.org/packages/optional/ in order to download -optional packages. +necessary optional packages in order for these tests to succeed. By default, Sage only runs doctests that are not marked with the ``optional`` tag. This is equivalent to running :: - [roed@sage sage-6.0]$ sage -t --optional=sagemath_doc_html,sage src/sage/rings/real_mpfr.pyx + [roed@localhost sage]$ ./sage -t --optional=sagemath_doc_html,sage \ + src/sage/rings/real_mpfr.pyx Running doctests with ID 2012-06-21-16-18-30-a368a200. Doctesting 1 file. sage -t src/sage/rings/real_mpfr.pyx @@ -885,7 +890,8 @@ By default, Sage only runs doctests that are not marked with the ``optional`` ta If you want to also run tests that require magma, you can do the following:: - [roed@sage sage-6.0]$ sage -t --optional=sagemath_doc_html,sage,magma src/sage/rings/real_mpfr.pyx + [roed@localhost sage]$ ./sage -t --optional=sagemath_doc_html,sage,magma \ + src/sage/rings/real_mpfr.pyx Running doctests with ID 2012-06-21-16-18-30-a00a7319 Doctesting 1 file. sage -t src/sage/rings/real_mpfr.pyx @@ -899,7 +905,7 @@ If you want to also run tests that require magma, you can do the following:: In order to just run the tests that are marked as requiring magma, omit ``sage`` and ``sagemath_doc_html``:: - [roed@sage sage-6.0]$ sage -t --optional=magma src/sage/rings/real_mpfr.pyx + [roed@localhost sage]$ ./sage -t --optional=magma src/sage/rings/real_mpfr.pyx Running doctests with ID 2012-06-21-16-18-33-a2bc1fdf Doctesting 1 file. sage -t src/sage/rings/real_mpfr.pyx @@ -915,7 +921,7 @@ If you want Sage to detect external software or other capabilities (such as magma, latex, internet) automatically and run all of the relevant tests, then add ``external``:: - $ sage -t --optional=external src/sage/rings/real_mpfr.pyx + [roed@localhost sage]$ ./sage -t --optional=external src/sage/rings/real_mpfr.pyx Running doctests with ID 2016-03-16-14-10-21-af2ebb67. Using --optional=external External software to be detected: cplex,gurobi,internet,latex,macaulay2,magma,maple,mathematica,matlab,octave,scilab @@ -932,7 +938,7 @@ relevant tests, then add ``external``:: To run all tests, regardless of whether they are marked optional, pass ``all`` as the ``optional`` tag:: - [roed@sage sage-6.0]$ sage -t --optional=all src/sage/rings/real_mpfr.pyx + [roed@localhost sage]$ ./sage -t --optional=all src/sage/rings/real_mpfr.pyx Running doctests with ID 2012-06-21-16-31-18-8c097f55 Doctesting 1 file. sage -t src/sage/rings/real_mpfr.pyx @@ -944,7 +950,8 @@ To run all tests, regardless of whether they are marked optional, pass ``all`` a cpu time: 4.7 seconds cumulative wall time: 11.2 seconds -Running Doctests in Parallel + +Running doctests in parallel ---------------------------- If you're testing many files, you can get big speedups by using more @@ -952,7 +959,7 @@ than one thread. To run doctests in parallel use the ``--nthreads`` flag (``-p`` is a shortened version). Pass in the number of threads you would like to use (by default Sage just uses 1):: - [roed@sage sage-6.0]$ sage -tp 2 src/sage/doctest/ + [roed@localhost sage]$ ./sage -tp 2 src/sage/doctest/ Running doctests with ID 2012-06-22-19-09-25-a3afdb8c. Sorting sources by runtime so that slower doctests are run first.... Doctesting 8 files using 2 threads. @@ -979,7 +986,8 @@ you would like to use (by default Sage just uses 1):: cpu time: 4.2 seconds cumulative wall time: 21.5 seconds -Doctesting All of Sage + +Doctesting all of Sage ---------------------- To doctest the whole Sage library use the ``--all`` flag (``-a`` for @@ -987,17 +995,17 @@ short). In addition to testing the code in Sage's Python and Cython files, this command will run the tests defined in Sage's documentation as well as testing the Sage notebook:: - [roed@sage sage-6.0]$ sage -t -a + [roed@localhost sage]$ ./sage -t -a Running doctests with ID 2012-06-22-19-10-27-e26fce6d. Doctesting entire Sage library. Sorting sources by runtime so that slower doctests are run first.... Doctesting 2020 files. - sage -t /Users/roed/sage/sage-5.3/src/sage/plot/plot.py + sage -t /Users/roed/sage/src/sage/plot/plot.py [304 tests, 69.0 s] ... -Debugging Tools +Debugging tools --------------- Sometimes doctests fail (that's why we run them after all). There are @@ -1008,7 +1016,8 @@ short) then you will drop into an interactive Python debugger whenever a Python exception occurs. As an example, I modified :mod:`sage.schemes.elliptic_curves.constructor` to produce an error:: - [roed@sage sage-6.0]$ sage -t --debug src/sage/schemes/elliptic_curves/constructor.py + [roed@localhost sage]$ ./sage -t --debug \ + src/sage/schemes/elliptic_curves/constructor.py Running doctests with ID 2012-06-23-12-09-04-b6352629. Doctesting 1 file. ********************************************************************** @@ -1017,22 +1026,22 @@ a Python exception occurs. As an example, I modified EllipticCurve([0,0]) Exception raised: Traceback (most recent call last): - File "/Users/roed/sage/sage-5.3/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 573, in _run + File ".../site-packages/sage/doctest/forker.py", line 573, in _run self.execute(example, compiled, test.globs) - File "/Users/roed/sage/sage-5.3/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 835, in execute + File ".../site-packages/sage/doctest/forker.py", line 835, in execute exec compiled in globs File "<doctest sage.schemes.elliptic_curves.constructor[0]>", line 1, in <module> EllipticCurve([Integer(0),Integer(0)]) - File "/Users/roed/sage/sage-5.3/local/lib/python2.7/site-packages/sage/schemes/elliptic_curves/constructor.py", line 346, in EllipticCurve + File ".../site-packages/sage/schemes/elliptic_curves/constructor.py", line 346, in EllipticCurve return ell_rational_field.EllipticCurve_rational_field(x, y) - File "/Users/roed/sage/sage-5.3/local/lib/python2.7/site-packages/sage/schemes/elliptic_curves/ell_rational_field.py", line 216, in __init__ + File ".../site-packages/sage/schemes/elliptic_curves/ell_rational_field.py", line 216, in __init__ EllipticCurve_number_field.__init__(self, Q, ainvs) - File "/Users/roed/sage/sage-5.3/local/lib/python2.7/site-packages/sage/schemes/elliptic_curves/ell_number_field.py", line 159, in __init__ + File ".../site-packages/sage/schemes/elliptic_curves/ell_number_field.py", line 159, in __init__ EllipticCurve_field.__init__(self, [field(x) for x in ainvs]) - File "/Users/roed/sage/sage-5.3/local/lib/python2.7/site-packages/sage/schemes/elliptic_curves/ell_generic.py", line 156, in __init__ + File ".../site-packages/sage/schemes/elliptic_curves/ell_generic.py", line 156, in __init__ "Invariants %s define a singular curve."%ainvs ArithmeticError: Invariants [0, 0, 0, 0, 0] define a singular curve. - > /Users/roed/sage/sage-5.3/local/lib/python2.7/site-packages/sage/schemes/elliptic_curves/ell_generic.py(156)__init__() + > .../site-packages/sage/schemes/elliptic_curves/ell_generic.py(156)__init__() -> "Invariants %s define a singular curve."%ainvs (Pdb) l 151 if len(ainvs) == 2: @@ -1069,8 +1078,9 @@ you know what test caused the problem (if you want this output to appear in real time use the ``--verbose`` flag). To have doctests run under the control of gdb, use the ``--gdb`` flag:: - [roed@sage sage-6.0]$ sage -t --gdb src/sage/schemes/elliptic_curves/constructor.py - exec gdb --eval-commands="run" --args /home/roed/sage-9.7/local/var/lib/sage/venv-python3.9/bin/python3 sage-runtests --serial --timeout=0 --stats_path=/home/roed/.sage/timings2.json --optional=pip,sage,sage_spkg src/sage/schemes/elliptic_curves/constructor.py + [roed@localhost sage]$ ./sage -t --gdb \ + src/sage/schemes/elliptic_curves/constructor.py + exec gdb --eval-commands="run" --args /home/roed/sage/local/var/lib/sage/venv-python3.9/bin/python3 sage-runtests --serial --timeout=0 --stats-path=/home/roed/.sage/timings2.json --optional=pip,sage,sage_spkg src/sage/schemes/elliptic_curves/constructor.py GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> @@ -1104,14 +1114,14 @@ Once you're done fixing whatever problems where revealed by the doctests, you can rerun just those files that failed their most recent test by using the ``--failed`` flag (``-f`` for short):: - [roed@sage sage-6.0]$ sage -t -fa + [roed@localhost sage]$ ./sage -t -fa Running doctests with ID 2012-07-07-00-45-35-d8b5a408. Doctesting entire Sage library. Only doctesting files that failed last test. No files to doctest -Miscellaneous Options +Miscellaneous options --------------------- There are various other options that change the behavior of Sage's @@ -1132,7 +1142,8 @@ Show skipped optional tests To print a summary at the end of each file with the number of optional tests skipped, use the ``--show-skipped`` flag:: - [roed@sage sage-6.0]$ sage -t --show-skipped src/sage/rings/finite_rings/integer_mod.pyx + [roed@localhost sage]$ ./sage -t --show-skipped \ + src/sage/rings/finite_rings/integer_mod.pyx Running doctests with ID 2013-03-14-15-32-05-8136f5e3. Doctesting 1 file. sage -t sage/rings/finite_rings/integer_mod.pyx @@ -1157,7 +1168,7 @@ you to run tests repeatedly in an attempt to search for Heisenbugs. The flag ``--global-iterations`` takes an integer and runs the whole set of tests that many times serially:: - [roed@sage sage-6.0]$ sage -t --global-iterations 2 src/sage/sandpiles + [roed@localhost sage]$ ./sage -t --global-iterations 2 src/sage/sandpiles Running doctests with ID 2012-07-07-00-59-28-e7048ad9. Doctesting 3 files (2 global iterations). sage -t src/sage/sandpiles/__init__.py @@ -1188,7 +1199,7 @@ set of tests that many times serially:: You can also iterate in a different order: the ``--file-iterations`` flag runs the tests in each file ``N`` times before proceeding:: - [roed@sage sage-6.0]$ sage -t --file-iterations 2 src/sage/sandpiles + [roed@localhost sage]$ ./sage -t --file-iterations 2 src/sage/sandpiles Running doctests with ID 2012-07-07-01-01-43-8f954206. Doctesting 3 files (2 file iterations). sage -t src/sage/sandpiles/__init__.py @@ -1216,7 +1227,7 @@ On a slow machine the default timeout of 5 minutes may not be enough for the slowest files. Use the ``--timeout`` flag (``-T`` for short) to set it to something else:: - [roed@sage sage-6.0]$ sage -tp 2 --all --timeout 1 + [roed@localhost sage]$ ./sage -tp 2 --all --timeout 1 Running doctests with ID 2012-07-07-01-09-37-deb1ab83. Doctesting entire Sage library. Sorting sources by runtime so that slower doctests are run first.... @@ -1231,10 +1242,10 @@ Using absolute paths By default filenames are printed using relative paths. To use absolute paths instead pass in the ``--abspath`` flag:: - [roed@sage sage-6.0]$ sage -t --abspath src/sage/doctest/control.py + [roed@localhost sage]$ ./sage -t --abspath src/sage/doctest/control.py Running doctests with ID 2012-07-07-01-13-03-a023e212. Doctesting 1 file. - sage -t /home/roed/sage-6.0/src/sage/doctest/control.py + sage -t /home/roed/sage/src/sage/doctest/control.py [133 tests, 4.7 s] ------------------------------------------------------------------------ All tests passed! @@ -1252,7 +1263,7 @@ convenient to test only the files that have changed. To do so use the ``--new`` flag, which tests files that have been modified or added since the last commit:: - [roed@sage sage-6.0]$ sage -t --new + [roed@localhost sage]$ ./sage -t --new Running doctests with ID 2012-07-07-01-15-52-645620ee. Doctesting files changed since last git commit. Doctesting 1 file. @@ -1273,7 +1284,7 @@ By default, tests are run in the order in which they appear in the file. To run tests in a random order (which can reveal subtle bugs), use the ``--randorder`` flag and pass in a random seed:: - [roed@sage sage-6.0]$ sage -t --new --randorder 127 + [roed@localhost sage]$ ./sage -t --new --randorder 127 Running doctests with ID 2012-07-07-01-19-06-97c8484e. Doctesting files changed since last git commit. Doctesting 1 file. @@ -1297,13 +1308,15 @@ code loads the globals from that file into the namespace before running tests. To disable this behaviour (and require imports to be explicitly specified), use the ``--force-lib`` option. +.. _section-doctest-auxiliary-files: + Auxiliary files ^^^^^^^^^^^^^^^ To specify a logfile (rather than use the default which is created for ``sage -t --all``), use the ``--logfile`` flag:: - [roed@sage sage-6.0]$ sage -t --logfile test1.log src/sage/doctest/control.py + [roed@localhost sage]$ ./sage -t --logfile test1.log src/sage/doctest/control.py Running doctests with ID 2012-07-07-01-25-49-e7c0e52d. Doctesting 1 file. sage -t src/sage/doctest/control.py @@ -1314,7 +1327,7 @@ To specify a logfile (rather than use the default which is created for Total time for all tests: 6.7 seconds cpu time: 0.1 seconds cumulative wall time: 4.3 seconds - [roed@sage sage-6.0]$ cat test1.log + [roed@localhost sage]$ cat test1.log Running doctests with ID 2012-07-07-01-25-49-e7c0e52d. Doctesting 1 file. sage -t src/sage/doctest/control.py @@ -1327,14 +1340,363 @@ To specify a logfile (rather than use the default which is created for cumulative wall time: 4.3 seconds -To give a json file storing the timings for each file, use the -``--stats_path`` flag. These statistics are used in sorting files so -that slower tests are run first (and thus multiple processes are -utilized most efficiently):: +To give a json file storing the timings and pass/fail status for each file, use the +``--stats-path`` flag; the default location of this file is ``~/.sage/timings2.json``. +The doctester reads it if it exists, for the purpose of sorting the files +so that slower tests are run first (and thus multiple processes are utilized most +efficiently):: - [roed@sage sage-6.0]$ sage -tp 2 --stats-path ~/.sage/timings2.json --all + [roed@localhost sage]$ ./sage -tp 2 --stats-path ~/.sage/timings2.json --all Running doctests with ID 2012-07-07-01-28-34-2df4251d. Doctesting entire Sage library. Sorting sources by runtime so that slower doctests are run first.... Doctesting 2067 files using 2 threads. ... + +At the end of the doctest run, Sage updates the json file if it exists or creates +a new one. + +The recorded pass/fail status of the files can be used for running only those files +that failed their most recent test by using the ``--failed`` flag (``-f`` for short). + +Using the option ``--baseline-stats-path known-test-failures.json``, +it is possible to distinguish files with known doctest failures +from new failures. The file ``known-test-failures.json`` should be +prepared in the same format as ``timings2.json``. + +Source files marked as failed there will be marked as "[failed in baseline]" +failures in the doctest report; and if there are only baseline failures, no +new failures, then ``sage -t`` will exit with status code 0 (success). + + +.. _section-doctesting-venv: + +Options for testing in virtual environments +------------------------------------------- + +The distribution packages of the modularized Sage library can be tested in virtual environments. +Sage has infrastructure to create such virtual environments using ``tox``, which is explained +in detail in :ref:`section-modularized-doctesting`. Our examples in this section +refer to this setting, but it applies the same to any user-created virtual environments. + +The virtual environments, set up in directories such as +``pkgs/sagemath-standard/.tox/sagepython-sagewheels-nopypi-norequirements`` +contain installations of built (non-editable) wheels. + +To test all modules of Sage that are installed in a virtual environment, +use the option ``--installed`` (instead of ``--all``):: + + [mkoeppe@localhost sage]$ pkgs/sagemath-standard/.tox/sagepython-.../sage -t \ + -p4 --installed + +This tests against the doctests as they appear in the installed copies of the files +(in ``site-packages/sage/...``). +Note that these installed copies should never be edited, as they can +be overwritten without warning. + +When testing a modularized distribution package other than sagemath-standard, +the top-level module :mod:`sage.all` is not available. Use the option ``--environment`` +to select an appropriate top-level module:: + + [mkoeppe@localhost sage]$ pkgs/sagemath-categories/.tox/sagepython-.../sage -t \ + -p4 --environment sage.all__sagemath_categories \ + --installed + +To test the installed modules against the doctests as they appear in the source +tree (``src/sage/...``):: + + [mkoeppe@localhost sage]$ pkgs/sagemath-categories/.tox/sagepython-.../sage -t \ + -p4 --environment sage.all__sagemath_categories \ + src/sage/structure + +Note that testing all doctests as they appear in the source tree does not make sense +because many of the source files may not be installed in the virtual environment. +Use the option ``--if-installed`` to skip the source files of all Python/Cython modules +that are not installed in the virtual environment:: + + [mkoeppe@localhost sage]$ pkgs/sagemath-categories/.tox/sagepython-.../sage -t \ + -p4 --environment sage.all__sagemath_categories \ + --if-installed src/sage/schemes + +This option can also be combined with ``--all``:: + + [mkoeppe@localhost sage]$ pkgs/sagemath-categories/.tox/sagepython-.../sage -t \ + -p4 --environment sage.all__sagemath_categories \ + --if-installed --all + + +.. _section-fixdoctests: + +The doctest fixer +================= + +Sage provides a development tool that assists with updating doctests. + + +Updating doctest outputs +------------------------ + +By default, ``./sage --fixdoctests`` runs the doctester and replaces the expected outputs +of all examples by the actual outputs from the current version of Sage:: + + [mkoeppe@localhost sage]$ ./sage --fixdoctests \ + --overwrite src/sage/arith/weird.py + +For example, when applied to this Python file:: + + | r""" + | ... + | + | EXAMPLES:: + | + | sage: 2 + 2 + | 5 + | sage: factor("91") + | "7" * "13" + | ... + +the doctest fixer edits the file as follows:: + + | r""" + | ... + | + | EXAMPLES:: + | + | sage: 2 + 2 + | 4 + | sage: factor("91") + | Traceback (most recent call last): + | ... + | TypeError: unable to factor '91' + | ... + +As this command edits the source file, it may be a good practice to first use ``git commit`` +to save any changes made in the file. + +After running the doctest fixer, it is a good idea to use ``git diff`` to check +all edits that the automated tool made. + +An alternative to this workflow is to use the option ``--keep-both``. When expected and +actual output of an example differ, it duplicates the example, marking the two copies +``# optional - EXPECTED`` and ``# optional - GOT``. (Thus, when re-running the doctester, +neither of the two copies is run; this makes ``./sage --fixdoctests`` idempotent.) + +When exceptions are expected by an example, it is standard practice to abbreviate +the tracebacks using ``...``. The doctest fixer uses this abbreviation automatically +when formatting the actual output, as shown in the above example. +To disable it so that the details of the exception +can be inspected, use the option ``--full-tracebacks``. This is particularly useful +in combination with ``--keep-both``:: + + [mkoeppe@localhost sage]$ ./sage --fixdoctests --keep-both --full-tracebacks \ + --overwrite src/sage/arith/weird.py + +This will give the following result on the above example:: + + | r""" + | ... + | + | EXAMPLES:: + | + | sage: 2 + 2 # optional - EXPECTED + | 5 + | sage: 2 + 2 # optional - GOT + | 4 + | sage: factor("91") # optional - EXPECTED + | "7" * "13" + | sage: factor("91") # optional - GOT + | Traceback (most recent call last): + | ... + | File "<doctest...>", line 1, in <module> + | factor("91") + | File ".../src/sage/arith/misc.py", line 2680, in factor + | raise TypeError("unable to factor {!r}".format(n)) + | TypeError: unable to factor '91' + | ... + | """ + +To make sure that all doctests are updated, you may have to use the option ``--long``:: + + [mkoeppe@localhost sage]$ ./sage --fixdoctests --long \ + --overwrite src/sage/arith/weird.py + +If you are not comfortable with allowing this tool to edit your source files, you can use +the option ``--no-overwrite``, which will create a new file with the extension ``.fixed`` +instead of overwriting the source file:: + + [mkoeppe@localhost sage]$ ./sage --fixdoctests \ + --no-overwrite src/sage/arith/weird.py + + +.. _section-fixdoctests-optional-needs: + +Managing ``# optional`` and ``# needs`` tags +-------------------------------------------- + +When a file uses a ``# sage.doctest: optional/needs FEATURE`` directive, the +doctest fixer automatically removes the redundant ``# optional/needs FEATURE`` +tags from all ``sage:`` lines. Likewise, when a block-scoped tag +``sage: # optional/needs FEATURE`` is used, then the doctest fixer removes +redundant tags from all doctests in this scope. For example:: + + | # sage.doctest: optional - sirocco, needs sage.rings.number_field + | r""" + | ... + | + | EXAMPLES:: + | + | sage: # needs sage.modules sage.rings.number_field + | sage: Q5 = QuadraticField(5) + | sage: V = Q5^42 # needs sage.modules + | sage: T = transmogrify(V) # optional - bliss sirocco + +is automatically transformed to:: + + | # sage.doctest: optional - sirocco, needs sage.rings.number_field + | r""" + | ... + | + | EXAMPLES:: + | + | sage: # needs sage.modules + | sage: Q5 = QuadraticField(5) + | sage: V = Q5^42 + | sage: T = transmogrify(V) # optional - bliss + +The doctest fixer also aligns the ``# optional/needs FEATURE`` tags on +individual doctests at a fixed set of tab stops. + +The doctester may issue style warnings when ``# optional/needs`` tags are +repeated on a whole block of doctests, suggesting to use a block-scoped tag +instead. The doctest fixer makes these changes automatically. + +There are situations in which the doctester and doctest fixer show too +much restraint and a manual intervention would improve the formatting +of the doctests. In the example below, the doctester does not issue a +style warning because the first doctest line does not carry the ``# needs`` +tag:: + + | EXAMPLES:: + | + | sage: set_verbose(-1) + | sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) # needs sage.rings.number_field + | sage: C = Curve([x^3*y + 2*x^2*y^2 + x*y^3 # needs sage.rings.number_field + | ....: + x^3*z + 7*x^2*y*z + | ....: + 14*x*y^2*z + 9*y^3*z], P) + | sage: Q = P([0,0,1]) # needs sage.rings.number_field + | sage: C.tangents(Q) # needs sage.rings.number_field + | [x + 4.147899035704788?*y, + | x + (1.426050482147607? + 0.3689894074818041?*I)*y, + | x + (1.426050482147607? - 0.3689894074818041?*I)*y] + +To change this example, there are two approaches: + +#. Just add the line ``sage: # needs sage.rings.number_field`` at + the beginning and run the doctest fixer, which will remove the tags on the individual + doctests that have now become redundant. + +#. Insert a blank line after the first doctest line, splitting the block into two. + Now the ``# needs`` tag is repeated on the whole second block, so running the doctest + fixer will add a block-scoped tag and remove the individual tags:: + + | EXAMPLES:: + | + | sage: set_verbose(-1) + | + | sage: # needs sage.rings.number_field + | sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) + | sage: C = Curve([x^3*y + 2*x^2*y^2 + x*y^3 + | ....: + x^3*z + 7*x^2*y*z + | ....: + 14*x*y^2*z + 9*y^3*z], P) + | sage: Q = P([0,0,1]) + | sage: C.tangents(Q) + | [x + 4.147899035704788?*y, + | x + (1.426050482147607? + 0.3689894074818041?*I)*y, + | x + (1.426050482147607? - 0.3689894074818041?*I)*y] + +In places where the doctester issues a doctest dataflow warning +(``Variable ... referenced here was set only in doctest marked '# optional - FEATURE'``), +the doctest fixer automatically adds the missing ``# optional/needs`` tags. + +Sometimes code changes can make existing ``# optional/needs FEATURE`` tags unnecessary. +In an installation or virtual environment where ``FEATURE`` is not available, +you can invoke the doctest fixer with the option ``--probe FEATURE``. +Then it will run examples marked ``# optional/needs - FEATURE`` silently, and if the example +turns out to work anyway, the tag is automatically removed. + +.. note:: + + Probing works best when the doctests within a docstring do not reuse the same variable + for different values. + +To have the doctest fixer take care of the ``# optional/needs`` tags, +but not change the expected results of examples, use the option ``--only-tags``. +This mode is suitable for mostly unattended runs on many files. + +With the option ``--verbose``, the doctest fixer shows the doctester's messages +one by one and reports the changes made. + +.. warning:: + + While the doctest fixer guarantees to preserve any comments that + appear before ``# optional/needs`` and all parenthesized comments + of the form ``# optional - FEATURE (EXPLANATION)``, any free-form comments + that may be mixed with the doctest tags will be lost. + +If you don't want to update any doctests, you can use the +option ``--no-test``. In this mode, the doctest fixer does not run +the doctester and only normalizes the style of the ``# optional`` tags. + + +Use in virtual environments +--------------------------- + +The doctest fixer can also run tests using the Sage doctester installed in +a virtual environment:: + + [mkoeppe@localhost sage]$ ./sage --fixdoctests --overwrite \ + --distribution sagemath-categories \ + src/sage/geometry/schemes/generic/*.py + +This command, using ``--distribution``, is equivalent to a command +that uses the more specific options ``--venv`` and ``--environment``:: + + [mkoeppe@localhost sage]$ ./sage --fixdoctests --overwrite \ + --venv pkgs/sagemath-categories/.tox/sagepython-... \ + --environment sage.all__sagemath_categories + src/sage/geometry/schemes/generic/*.py + +Either way, the options ``--keep-both``, ``--full-tracebacks``, and +``--if-installed`` are implied. + +In this mode of operation, when the doctester encounters a global name +that is unknown in its virtual environment (:class:`NameError`), +the doctest fixer will look up the name in its own environment (typically +a full installation of the Sage library) and add a ``# needs ...`` tag +to the doctest. + +Likewise, when the doctester runs into a :class:`ModuleNotFoundError`, +the doctest fixer will automatically add a ``# needs ...`` tag. + +The switch ``--distribution`` can be repeated; the given distributions +will be tested in sequence. Using ``--distribution all`` is equivalent +to a preset list of ``--distribution`` switches. With the switch +``--fixed-point``, the doctest fixer runs the given distributions until +no more changes are made. + + +Updating baseline files +----------------------- + +The modularized distribution packages ``pkgs/sagemath-categories`` and +``pkgs/sagemath-repl`` contain files ``known-test-failures*.json`` for use +with the option ``--baseline-stats-path``, see section +:ref:`section-doctest-auxiliary-files`. + +After running the doctesters of the distributions, for example, via +``sage --fixdoctests``, you can use the test results stored in +``timings2.json`` files to update the ``known-test-failures*.json`` files. +This update can be done using the command:: + + [mkoeppe@localhost sage]$ ./sage --fixdoctests --no-test \ + --update-known-test-failures --distribution all diff --git a/src/doc/en/developer/git_advanced.rst b/src/doc/en/developer/git_advanced.rst new file mode 100644 index 00000000000..650f3492695 --- /dev/null +++ b/src/doc/en/developer/git_advanced.rst @@ -0,0 +1,394 @@ +.. highlight:: shell-session + +.. _chapter-advanced-git: + +============ +Advanced Git +============ + +This chapter covers some advanced uses of git that go beyond what is +required to work with branches. These features can be used in Sage +development, but are not really necessary to contribute to Sage. If +you are just getting started with Sage development, you should read +:ref:`chapter-walkthrough` and :ref:`chapter-git-basic` instead. + + +Detached heads and reviewing PRs +================================ + +Each commit is a snapshot of the Sage source tree at a certain +point. So far, we always used commits organized in branches. But +secretly the branch is just a shortcut for a particular commit, the +head commit of the branch. But you can just go to a particular commit +without a branch, this is called "detached head". If you have the +commit already in your local history, you can directly check it +out without requiring internet access:: + + [alice@localhost sage]$ git checkout f9a0d54099d758ccec731a38929902b2b9d0b988 + Note: switching to 'f9a0d54099d758ccec731a38929902b2b9d0b988'. + + You are in 'detached HEAD' state. You can look around, make experimental + changes and commit them, and you can discard any commits you make in this + state without impacting any branches by switching back to a branch. + + If you want to create a new branch to retain commits you create, you may + do so (now or later) by using -c with the switch command. Example: + + git switch -c <new-branch-name> + + Or undo this operation with: + + git switch - + + Turn off this advice by setting config variable advice.detachedHead to false + + HEAD is now at f9a0d54099 Fix a slow doctest in matrix_integer_dense_hnf.py + +If it is not stored in your local Git repository, you need to download +it from the ``upstream`` repo first:: + + [alice@localhost sage]$ git fetch upstream f9a0d54099d758ccec731a38929902b2b9d0b988 + From https://github.com/sagemath/sage + * branch f9a0d54099d758ccec731a38929902b2b9d0b988 -> FETCH_HEAD + [alice@localhost sage]$ git checkout FETCH_HEAD + HEAD is now at f9a0d54099 Fix a slow doctest in matrix_integer_dense_hnf.py + +Either way, you end up with your current HEAD and working directory +that is not associated to any local branch:: + + [alice@localhost sage]$ git status + HEAD detached at f9a0d54099 + nothing to commit, working tree clean + +This is perfectly fine. You can switch to an existing branch (with the +usual ``git checkout my_branch``) and back to your detached head. + +Detached heads can be used to your advantage when reviewing PRs. Just check +out the commit (look at the "Commits" tab of the PR) that you are reviewing as +a detached head. Then you can look at the changes and run tests in the detached +head. When you are finished with the review, you just abandon the detached +head. That way you never create a new local branch, so you don't have to type +``git branch -D my_branch`` at the end to delete the local branch that you +created only to review the ticket. + + +.. _section-git-update-latest: + +Update branch to latest Sage version +==================================== + +- You have a compiled and working new SageMath version ``n``, and +- you want to work on a branch ``some_code`` which is based on some old SageMath version ``o`` +- by updating this branch from version ``o`` to ``n`` +- with only recompiling changed files (and not all touched files from ``o`` to ``n``), +- then continue reading this section. + + +Introduction +------------ + +When developing, quite frequently one ends up with a branch which is +not based on the latest (beta) version of SageMath. + +.. NOTE:: + + Continue working on a feature based on an old branch is perfectly + fine and usually there is no need to merge in this latest SageMath + version. + +However sometimes there is a need for a merge, for example + +- if there are conflicts with the latest version or +- one needs a recent feature or +- simply because the old SageMath version is not available on your machine + any longer. + +Then merging in the latest SageMath version has to be done. + + +Merge in the latest Sage version +-------------------------------- + +(This is the easy way without minimizing the recompilation time.) + +Suppose we are on our current working branch ``some_code`` +(branch is checked out). Then +:: + + git merge develop + +does the merging, i.e. we merge the latest development version into +our working branch. + +However, after this merge, we need to (partially) recompile +SageMath. Sometimes this can take ages (as many files are touched and +their timestamps are renewed) and there is a way to avoid it. + + +Minimize the recompilation time +------------------------------- + +Suppose we are on some new SageMath (e.g. on branch ``develop``) which +was already compiled and runs successfully, and we have an "old" +branch ``some_code``, that we want to bring onto this SageMath version +(without triggering unnecessary recompilations). + +We first create a new working tree in a directory ``new_worktree`` and switch +to this directory:: + + [alice@localhost sage]$ git worktree add new_worktree + [alice@localhost sage]$ cd new_worktree + +Here we have a new copy of our source files. Thus no timestamps +etc. of the original repository will be changed. Now we do the merge:: + + [alice@localhost sage/new_worktree]$ git checkout some_code + [alice@localhost sage/new_worktree]$ git merge develop + +And go back to our original repository:: + + [alice@localhost sage/new_worktree]$ git checkout develop + [alice@localhost sage/new_worktree]$ cd .. + +We can now safely checkout ``some_code``:: + + [alice@localhost sage]$ git checkout some_code + +We still need to call +:: + + [alice@localhost sage]$ make + +but only changed files will be recompiled. + +To remove the new working tree simply use +:: + + [alice@localhost sage]$ rm -r new_worktree + + +Why not merging the other way round? +------------------------------------ + +Being on some new SageMath (e.g. on branch ``develop``) which runs +successfully, it would be possible to merge in our branch +``some_code`` into develop. This would produce the same source files +and avoid unnecessary recompilations. However, it makes reading Git's +history very unpleasant: For example, it is hard to keep track of changes etc., +as one cannot simply pursue the first parent of each Git commit +(``git log --first-parent``). + + +.. _section-git-recovery: + +Reset and recovery +================== + +Git makes it very hard to truly mess up. Here is a short way to get +back onto your feet, no matter what. First, if you just want to go +back to a working Sage installation you can always abandon your +working branch by switching to your local copy of the ``develop`` +branch:: + + [alice@localhost sage]$ git checkout develop + +As long as you did not make any changes to the ``develop`` branch +directly, this will give you back a working Sage. + +If you want to keep your branch but go back to a previous commit you +can use the *reset* command. For this, look up the commit in the log +which is some 40-digit hexadecimal number (the SHA1 hash). Then use +``git reset --hard`` to revert your files back to the previous state:: + + [alice@localhost sage]$ git log + ... + commit eafaedad5b0ae2013f8ae1091d2f1df58b72bae3 + Author: First Last <alice@email.com> + Date: Sat Jul 20 21:57:33 2013 -0400 + + Commit message + ... + [alice@localhost sage]$ git reset --hard eafae + +.. WARNING:: + + Any *uncommitted* changes will be lost! + +You only need to type the first couple of hex digits, Git will +complain if this does not uniquely specify a commit. Also, there is +the useful abbreviation ``HEAD~`` for the previous commit and +``HEAD~n``, with some integer ``n``, for the n-th previous commit. + +Finally, perhaps the ultimate human error recovery tool is the +reflog. This is a chronological history of Git operations that you can +undo if needed. For example, let us assume we messed up the *git +reset* command and went back too far (say, 5 commits back). And, on +top of that, deleted a file and committed that:: + + [alice@localhost sage]$ git reset --hard HEAD~5 + [alice@localhost sage]$ git rm sage + [alice@localhost sage]$ git commit -m "I shot myself into my foot" + +Now we cannot just checkout the repository from before the reset, +because it is no longer in the history. However, here is the reflog:: + + [alice@localhost sage]$ git reflog + 2eca2a2 HEAD@{0}: commit: I shot myself into my foot + b4d86b9 HEAD@{1}: reset: moving to HEAD~5 + af353bb HEAD@{2}: checkout: moving from some_branch to master + 1142feb HEAD@{3}: checkout: moving from other_branch to some_branch + ... + +The ``HEAD@{n}`` revisions are shortcuts for the history of Git +operations. Since we want to rewind to before the erroneous *git +reset* command, we just have to reset back into the future:: + + [alice@localhost sage]$ git reset --hard HEAD@{2} + + +.. _section-git-rewriting-history: + +Rewriting history +================= + +Git allows you to rewrite history, but be careful: the SHA1 hash of a +commit includes the parent's hash. This means that the hash really +depends on the entire content of the working directory; every source +file is in exactly the same state as when the hash was computed. This +also means that you can't change history without modifying the +hash. If others branched off your code and then you rewrite history, +then the others are thoroughly screwed. So, ideally, you would only +rewrite history on branches that you have not yet pushed to a public repo. + +As an advanced example, consider three commits A, B, C that were made +on top of each other. For simplicity, we'll assume they just added a +file named ``file_A.py``, ``file_B.py``, and ``file_C.py`` :: + + [alice@localhost sage]$ git log --oneline + 9621dae added file C + 7873447 added file B + bf817a5 added file A + 5b5588e base commit + +Now, let's assume that the commit B was really independent and ought +to be on a separate ticket. So we want to move it to a new branch, +which we'll call ``second_branch``. First, branch off at the base +commit before we added A:: + + [alice@localhost sage]$ git checkout 5b5588e + Note: checking out '5b5588e'. + + You are in 'detached HEAD' state. You can look around, make experimental + changes and commit them, and you can discard any commits you make in this + state without impacting any branches by performing another checkout. + + If you want to create a new branch to retain commits you create, you may + do so (now or later) by using -b with the checkout command again. Example: + + git checkout -b new_branch_name + + HEAD is now at 5b5588e... base commit + [alice@localhost sage]$ git checkout -b second_branch + Switched to a new branch 'second_branch' + [alice@localhost sage]$ git branch + first_branch + * second_branch + [alice@localhost sage]$ git log --oneline + 5b5588e base commit + +Now, we make a copy of commit B in the current branch:: + + [alice@localhost sage]$ git cherry-pick 7873447 + [second_branch 758522b] added file B + 1 file changed, 1 insertion(+) + create mode 100644 file_B.py + [alice@localhost sage]$ git log --oneline + 758522b added file B + 5b5588e base commit + +Note that this changes the SHA1 of the commit B, since its parent +changed! Also, cherry-picking *copies* commits, it does not remove +them from the source branch. So we now have to modify the first branch +to exclude commit B, otherwise there will be two commits adding +``file_B.py`` and our two branches would conflict later when they are +being merged into Sage. Hence, we first reset the first branch back to +before B was added:: + + [alice@localhost sage]$ git checkout first_branch + Switched to branch 'first_branch' + [alice@localhost sage]$ git reset --hard bf817a5 + HEAD is now at bf817a5 added file A + +Now we still want commit C, so we cherry-pick it again. Note that this +works even though commit C is, at this point, not included in any +branch:: + + [alice@localhost sage]$ git cherry-pick 9621dae + [first_branch 5844535] added file C + 1 file changed, 1 insertion(+) + create mode 100644 file_C.py + [alice@localhost sage]$ git log --oneline + 5844535 added file C + bf817a5 added file A + 5b5588e base commit + +And, again, we note that the SHA1 of commit C changed because its +parent changed. Voila, now you have two branches where the first +contains commits A, C and the second contains commit B. + + +.. _section-git-interactive-rebase: + +Interactively rebasing +====================== + +An alternative approach to :ref:`section-git-rewriting-history` is to +use the interactive rebase feature. This will open an editor where you +can modify the most recent commits. Again, this will naturally modify +the hash of all changed commits and all of their children. + +Now we start by making an identical branch to the first branch:: + + [alice@localhost sage]$ git log --oneline + 9621dae added file C + 7873447 added file B + bf817a5 added file A + 5b5588e base commit + [alice@localhost sage]$ git checkout -b second_branch + Switched to a new branch 'second_branch' + [alice@localhost sage]$ git rebase -i HEAD~3 + +This will open an editor with the last 3 (corresponding to ``HEAD~3``) +commits and instuctions for how to modify them: + +.. CODE-BLOCK:: text + + pick bf817a5 added file A + pick 7873447 added file B + pick 9621dae added file C + + # Rebase 5b5588e..9621dae onto 5b5588e + # + # Commands: + # p, pick = use commit + # r, reword = use commit, but edit the commit message + # e, edit = use commit, but stop for amending + # s, squash = use commit, but meld into previous commit + # f, fixup = like "squash", but discard this commit's log message + # x, exec = run command (the rest of the line) using shell + # + # These lines can be re-ordered; they are executed from top to bottom. + # + # If you remove a line here THAT COMMIT WILL BE LOST. + # + # However, if you remove everything, the rebase will be aborted. + # + # Note that empty commits are commented out + +To only use commit B, we delete the first and third line. Then save +and quit your editor, and your branch now consists only of the B commit. + +You still have to delete the B commit from the first branch, so you +would go back (``git checkout first_branch``) and then run the same +``git rebase -i`` command and delete the B commit. + diff --git a/src/doc/en/developer/git_background.rst b/src/doc/en/developer/git_background.rst index dbea3ed11eb..dcdde034134 100644 --- a/src/doc/en/developer/git_background.rst +++ b/src/doc/en/developer/git_background.rst @@ -2,59 +2,54 @@ .. _chapter-git-background: -=================== -Tips and References -=================== +======================= +Git Tips and References +======================= -This chapter contains additional material about the git revision +This chapter contains additional material about the Git revision control system. See :ref:`chapter-git-setup` for the minimal steps needed for Sage development. - - - - .. _section-git-configuration: -Configuration Tips +Configuration tips ================== -Your personal git configurations are saved in the ``~/.gitconfig`` +Your personal Git configurations are saved in the ``~/.gitconfig`` file in your home directory. Here is an example: .. CODE-BLOCK:: text [user] - name = Your Name - email = you@yourdomain.example.com + name = Alice Adventure + email = alice@wonderland.com [core] editor = emacs -You can edit this file directly or you can use git to make changes for +You can edit this file directly or you can use Git to make changes for you:: - [user@localhost ~] git config --global user.name "Your Name" - [user@localhost ~] git config --global user.email you@yourdomain.example.com - [user@localhost ~] git config --global core.editor vim - + [alice@localhost ~]$ git config --global user.name "Alice Adventure" + [alice@localhost ~]$ git config --global user.email alice@wonderland.com + [alice@localhost ~]$ git config --global core.editor vim Aliases ------- -Aliases are personal shortcuts for git commands. For example, you +Aliases are personal shortcuts for Git commands. For example, you might want to be able to shorten ``git checkout`` to ``git co``. Or you may want to alias ``git diff --color-words`` (which gives a nicely formatted output of the diff) to ``git wdiff``. You can do this with:: - [user@localhost ~] git config --global alias.ci "commit -a" - [user@localhost ~] git config --global alias.co checkout - [user@localhost ~] git config --global alias.st "status -a" - [user@localhost ~] git config --global alias.stat "status -a" - [user@localhost ~] git config --global alias.br branch - [user@localhost ~] git config --global alias.wdiff "diff --color-words" + [alice@localhost ~]$ git config --global alias.ci "commit -a" + [alice@localhost ~]$ git config --global alias.co checkout + [alice@localhost ~]$ git config --global alias.st "status -a" + [alice@localhost ~]$ git config --global alias.stat "status -a" + [alice@localhost ~]$ git config --global alias.br branch + [alice@localhost ~]$ git config --global alias.wdiff "diff --color-words" The above commands will create an ``alias`` section in your ``.gitconfig`` file with contents like this: @@ -75,9 +70,10 @@ Editor To set the editor to use for editing commit messages, you can use:: - [user@localhost ~] git config --global core.editor vim + [alice@localhost ~]$ git config --global core.editor vim + +or set the ``EDITOR`` environment variable. -or set the `EDITOR` environment variable. Merging ------- @@ -91,24 +87,24 @@ To enforce summaries when doing merges (``~/.gitconfig`` file again): Or from the command line:: - [user@localhost ~] git config --global merge.log true + [alice@localhost ~]$ git config --global merge.log true .. _section-fancy-log: -Fancy Log Output +Fancy log output ---------------- -Here is an alias to get a fancy log output; it should go in the +Here is an alias to get a fancy log output. It should go in the ``alias`` section of your ``.gitconfig`` file: .. CODE-BLOCK:: text lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)[%an]%Creset' --abbrev-commit --date=relative -Using this ``lg`` alias gives you the changelog with a colored ascii graph:: +Using this ``lg`` alias gives you the changelog with a colored ASCII graph:: - [user@localhost ~] git lg + [alice@localhost ~]$ git lg * 6d8e1ee - (HEAD, origin/my-fancy-feature, my-fancy-feature) NF - a fancy file (45 minutes ago) [Matthew Brett] * d304a73 - (origin/placeholder, placeholder) Merge pull request #48 from hhuuggoo/master (2 weeks ago) [Jonathan Terhorst] |\ @@ -129,30 +125,24 @@ Using this ``lg`` alias gives you the changelog with a colored ascii graph:: .. _section-git-tutorials: - -Tutorials and Summaries +Tutorials and summaries ======================= There are many, many tutorials and command summaries available online. Beginner -------- -* `Try Git <https://try.github.io/levels/1/challenges/1>`_ is an entry-level - tutorial you can do in your browser. If you are unfamiliar with revision - control, you will want to pay close attention to the "Advice" section toward - the bottom. + +* `gittutorial <https://git-scm.com/docs/gittutorial>`_ is an introductory tutorial + from Git project. * `Git magic <http://www-cs-students.stanford.edu/~blynn/gitmagic/index.html>`_ is an extended introduction with intermediate detail. -* The `git parable +* The `Git parable <http://tom.preston-werner.com/2009/05/19/the-git-parable.html>`_ is - an easy read explaining the concepts behind git. - -* `Git foundation - <http://matthew-brett.github.com/pydagogue/foundation.html>`_ - expands on the `git parable`_. + an easy read explaining the concepts behind Git. * Although it also contains more advanced material about branches and detached head and the like, the visual summaries of merging and branches @@ -162,75 +152,55 @@ Beginner Advanced -------- -* `Github help <http://help.github.com>`_ has an excellent series of + +* `GitHub help <http://help.github.com>`_ has an excellent series of how-to guides. -* The `pro git book <http://git-scm.com/book>`_ is a good in-depth book on git. +* The `pro Git book <http://git-scm.com/book>`_ is a good in-depth book on Git. -* `Github Training <http://training.github.com>`_ has an excellent series +* `Github Training Kit <http://training.github.com>`_ has an excellent series of tutorials as well as videos and screencasts. -* The `git tutorial <http://schacon.github.com/git/gittutorial.html>`_. - * `Git ready <http://www.gitready.com/>`_ is a nice series of tutorials. -* `Fernando Perez' git page - <http://www.fperez.org/py4science/git.html>`_ contains many links - and tips. - -* A good but technical page on `git concepts +* A good but technical page on `Git concepts <http://www.eecs.harvard.edu/~cduan/technical/git/>`_ -* `Git svn crash course <http://git-scm.com/course/svn.html>`_: git - for those of us used to `subversion - <http://subversion.tigris.org/>`_ - -Summaries/Cheat Sheets ----------------------- -* A `git cheat sheet <http://github.com/guides/git-cheat-sheet>`_ is a - page giving summaries of common commands. -* The `git user manual - <http://schacon.github.com/git/user-manual.html>`_. - - - -Git Best Practices +Git best practices ================== -There are many ways of working with git; here are some posts on the +There are many ways of working with Git. Here are some posts on the rules of thumb that other projects have come up with: -* Linus Torvalds on `git management - <https://web.archive.org/web/20120511084711/http://kerneltrap.org/Linux/Git_Management>`_ +* Linus Torvalds on `Git management + <https://web.archive.org/web/20120511084711/http://kerneltrap.org/Linux/Git_Management>`_. -* Linus Torvalds on `linux git workflow +* Linus Torvalds on `Git workflow <http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html>`_. Summary: - use the git tools to make the history of your edits as clean as + use the Git tools to make the history of your edits as clean as possible; merge from upstream edits as little as possible in branches where you are doing active development. -Manual Pages Online +Manual pages online =================== You can get these on your own machine with (e.g) ``git help push`` or (same thing) ``git push --help``, but, for convenience, here are the online manual pages for some common commands: -* `git add <http://schacon.github.com/git/git-add.html>`_ -* `git branch <http://schacon.github.com/git/git-branch.html>`_ -* `git checkout <http://schacon.github.com/git/git-checkout.html>`_ -* `git clone <http://schacon.github.com/git/git-clone.html>`_ -* `git commit <http://schacon.github.com/git/git-commit.html>`_ -* `git config <http://schacon.github.com/git/git-config.html>`_ -* `git diff <http://schacon.github.com/git/git-diff.html>`_ -* `git log <http://schacon.github.com/git/git-log.html>`_ -* `git pull <http://schacon.github.com/git/git-pull.html>`_ -* `git push <http://schacon.github.com/git/git-push.html>`_ -* `git remote <http://schacon.github.com/git/git-remote.html>`_ -* `git status <http://schacon.github.com/git/git-status.html>`_ - - +* `git add <https://git-scm.com/docs/git-add>`_ +* `git branch <https://git-scm.com/docs/git-branch.html>`_ +* `git checkout <https://git-scm.com/docs/git-checkout.html>`_ +* `git clone <https://git-scm.com/docs/git-clone.html>`_ +* `git commit <https://git-scm.com/docs/git-commit.html>`_ +* `git config <https://git-scm.com/docs/git-config.html>`_ +* `git diff <https://git-scm.com/docs/git-diff.html>`_ +* `git log <https://git-scm.com/docs/git-log.html>`_ +* `git pull <https://git-scm.com/docs/git-pull.html>`_ +* `git push <https://git-scm.com/docs/git-push.html>`_ +* `git remote <https://git-scm.com/docs/git-remote.html>`_ +* `git status <https://git-scm.com/docs/git-status.html>`_ diff --git a/src/doc/en/developer/git_basic.rst b/src/doc/en/developer/git_basic.rst new file mode 100644 index 00000000000..524181438ee --- /dev/null +++ b/src/doc/en/developer/git_basic.rst @@ -0,0 +1,436 @@ +.. highlight:: shell-session + +.. _chapter-git-basic: + +========== +Git Basics +========== + +Git is a tool to exchange commits (file changes) and branches (organized of +commits) with other developers. + +As a distributed revision control system, Git does not have the notion of a +central server. However, for Sage development, Git communicates with other +developers via `the Sage repository <https://github.com/sagemath/sage>`_ on +GitHub. Hence we assume that throughout this guide. + +.. _section-git-ssh: + +Git authentication through SSH +============================== + +In order to push changes securely to a remote repository, Git uses public-key +cryptography. This section will show you how to set up the necessary +cryptographic keys for the case that you want to use SSH(Secure Shell) protocol +to authenticate your Git to GitHub, instead of HTTPS protocol. + + +.. _section-github-ssh-key: + +Generating your SSH keys +------------------------ + +Check whether you already have suitable SSH keys by inspecting ``.ssh`` +directory in your home directory. If you don't have suitable SSH keys yet, you +can create a key pair with the ``ssh-keygen`` tool. + +Follow either `the detailed instructions +<https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key>`_ +or the following brief instructions:: + + [alice@localhost ~]$ ssh-keygen + Generating public/private rsa key pair. + Enter file in which to save the key (/home/user/.ssh/id_rsa): + Enter passphrase (empty for no passphrase): + Enter same passphrase again: + Your identification has been saved in /home/user/.ssh/id_rsa. + Your public key has been saved in /home/user/.ssh/id_rsa.pub. + The key fingerprint is: + ce:32:b3:de:38:56:80:c9:11:f0:b3:88:f2:1c:89:0a alice@localhost + The key's randomart image is: + +--[ RSA 2048]----+ + | .... | + | .. | + | .o+ | + | o o+o. | + |E + . .S | + |+o . o. | + |. o +.o | + | oB | + | o+.. | + +-----------------+ + +This will generate a new random private RSA key +in the ``.ssh`` folder in your home directory. By default, they are + +``~/.ssh/id_rsa`` + Your private key. Keep safe. **Never** hand it out to anybody. + +``~/.ssh/id_rsa.pub`` + The corresponding public key. This and only this file can be safely + disclosed to third parties. + +The ``ssh-keygen`` tool will let you generate a key with a different +file name, or protect it with a passphrase. Depending on how much you +trust your own computer or system administrator, you can leave the +passphrase empty to be able to login without any human intervention. + + +Adding your public key for authentication to GitHub +--------------------------------------------------- + +Follow the procedure `Adding a new SSH key to your GitHub account +<https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account>`_. +Then check that it works by:: + + [alice@localhost sage]$ git remote add origin git@github.com:alice/sage.git + [alice@localhost sage]$ git remote -v + origin git@github.com:alice/sage.git (fetch) + origin git@github.com:alice/sage.git (push) + + +.. _section-git-push: + +Pushing your changes to a remote +================================ + +Push your branch to the remote ``origin`` with either :: + + [alice@localhost sage]$ git push --set-upstream origin HEAD:my_branch + +or :: + + [alice@localhost sage]$ git push origin HEAD:my_branch + +if your branch already has an upstream branch. Here "upstream" means the the +remote ``origin``, which is *upstream* to your local Git repo. + +Here, ``HEAD`` means that you are pushing the most recent commit (and, by +extension, all of its parent commits) of the current local branch to the remote +branch. + + +.. _section-git-checkout: + +Checking out a PR +================= + +If you want to work with the changes of a PR branch, you must +make a local copy of the branch. In particular, Git has no concept of directly +working with the remote branch, the remotes are only bookmarks for +things that you can get from/to the remote server. Hence, the first +thing you should do is to get everything from the branch +into your local repository. This is achieved by:: + + [alice@localhost sage]$ git fetch upstream pull/12345/head + remote: Enumerating objects: 12, done. + remote: Counting objects: 100% (12/12), done. + remote: Compressing objects: 100% (3/3), done. + remote: Total 12 (delta 9), reused 11 (delta 9), pack-reused 0 + Unpacking objects: 100% (12/12), 2.22 KiB | 206.00 KiB/s, done. + From https://github.com/sagemath/sage + * branch refs/pull/12345/head -> FETCH_HEAD + +The ``pull/12345/head`` branch refers to the branch of the PR #12345 of the +remote ``upstream``. The branch is now temporarily (until you fetch something +else) stored in your local Git database under the alias ``FETCH_HEAD``. In the +second step, we make it available as a new local branch and switch to it. Your +local branch can have a different name, for example:: + + [alice@localhost sage]$ git checkout -b my_branch FETCH_HEAD + Switched to a new branch 'my_branch' + +creates a new branch in your local Git repository named ``my_branch`` +and modifies your local Sage filesystem tree to the state of the files +in the branch. You can now edit files and commit changes to your +local branch. + + +.. _section-git-pull: + +Getting changes from a remote +============================= + +A common task during development is to synchronize your local copy of the +branch with the branch on the GitHub Sage repo. In particular, assume you +downloaded the branch of a PR made by someone else, say Bob, and made some +suggestions for improvements on the PR. Now Bob incorporated your suggestions +into his branch, and you want to get the added changes to complete your review. +Assuming that you originally got your local branch as in +:ref:`section-git-checkout`, you can just issue:: + + [bob@localhost sage]$ git pull upstream pull/12345/head + From https://github.com/sagemath/sage + * branch refs/pull/35608/head -> FETCH_HEAD + Merge made by the 'ort' strategy. + src/doc/common/python3.inv | Bin 98082 -> 131309 bytes + src/doc/common/update-python-inv.sh | 7 ++++--- + 2 files changed, 4 insertions(+), 3 deletions(-) + +This command downloads the changes from the branch of the PR and merges +them into your local branch. + + +.. _section-git-pull-develop: + +Updating develop +================ + +The ``develop`` branch can be updated just like any other branch. However, your +local copy of the develop branch should stay **identical** to the GitHub Sage repo develop +branch. + +If you accidentally added commits to your local copy of ``develop``, you must +delete them before updating the branch. + +One way to ensure that you are notified of potential problems is to use ``git +pull --ff-only``, which will raise an error if a non-trivial merge would be +required:: + + [alice@localhost sage]$ git checkout develop + [alice@localhost sage]$ git pull --ff-only upstream develop + +If this pull fails, then something is wrong with the local copy of the +master branch. To switch to the correct Sage master branch, use:: + + [alice@localhost sage]$ git checkout develop + [alice@localhost sage]$ git reset --hard upstream/develop + + +.. _section-git-merge: + +Merging and rebasing +==================== + +Sometimes, a new version of Sage is released while you work on a Git branch. + +Let us assume you started ``my_branch`` at commit ``B``. After a while, your +branch has advanced to commit ``Z``, but you updated ``develop`` (see +:ref:`section-git-pull-develop`) and now your Git history looks like this (see +:ref:`section_walkthrough_logs`): + +.. CODE-BLOCK:: text + + X---Y---Z my_branch + / + A---B---C---D develop + +How should you deal with such changes? In principle, there are two ways: + +* **Rebase:** The first solution is to **replay** commits ``X,Y,Z`` atop of the + new ``develop``. This is called **rebase**, and it rewrites your current + branch: + + .. CODE-BLOCK:: text + + git checkout my_branch + git rebase -i develop + + In terms of the commit graph, this results in: + + .. CODE-BLOCK:: text + + X'--Y'--Z' my_branch + / + A---B---C---D develop + + Note that this operation rewrites the history of ``my_branch`` (see + :ref:`section-git-rewriting-history`). This can lead to problems if somebody + began to write code atop of your commits ``X,Y,Z``. It is safe otherwise. + + **Alternatively**, you can rebase ``my_branch`` while updating ``develop`` at the + same time (see :ref:`section-git-pull`): + + .. CODE-BLOCK:: text + + git checkout my_branch + git pull -r develop + +* **Merging** your branch with ``develop`` will create a new commit above the two + of them: + + .. CODE-BLOCK:: text + + git checkout my_branch + git merge develop + + The result is the following commit graph: + + .. CODE-BLOCK:: text + + X---Y---Z---W my_branch + / / + A---B---C-------D develop + + - **Pros:** you did not rewrite history (see + :ref:`section-git-rewriting-history`).The additional commit is then easily + pushed to the git repository and distributed to your collaborators. + + - **Cons:** it introduced an extra merge commit that would + not be there had you used rebase. + + **Alternatively**, you can merge ``my_branch`` while updating ``develop`` at the + same time (see :ref:`section-git-pull`): + + .. CODE-BLOCK:: text + + git checkout my_branch + git pull develop + +**In case of doubt** use merge rather than rebase. There is less risk involved, +and rebase in this case is only useful for branches with a very long history. + + +.. _section-git-mergetool: + +Merge tools +=========== + +Simple conflicts can be easily solved with Git only (see :ref:`section-git-conflict`) + +For more complicated ones, a range of specialized programs are +available. Because the conflict marker includes the hash of the most recent +common parent, you can use a three-way diff:: + + [alice@laptop]$ git mergetool + + This message is displayed because 'merge.tool' is not configured. + See 'git mergetool --tool-help' or 'git help config' for more details. + 'git mergetool' will now attempt to use one of the following tools: + meld opendiff kdiff3 [...] merge araxis bc3 codecompare emerge vimdiff + Merging: + fibonacci.py + + Normal merge conflict for 'fibonacci.py': + {local}: modified file + {remote}: modified file + Hit return to start merge resolution tool (meld): + +If you don't have a favourite merge tool we suggest you try `meld +<http://meldmerge.org/>`_ (cross-platform). The result looks like the following +screenshot. + +.. IMAGE:: static/meld-screenshot.png + +The middle file is the most recent common parent; on the right is +Bob's version and on the left is Alice's conflicting version. Clicking +on the arrow moves the marked change to the file in the adjacent +pane. + + +.. _section-git-conflict: + +Conflict resolution +------------------- + +Merge conflicts happen if there are overlapping edits, and they are an +unavoidable consequence of distributed development. Fortunately, +resolving them is common and easy with Git. As a hypothetical example, +consider the following code snippet: + +.. CODE-BLOCK:: python + + def fibonacci(i): + """ + Return the `i`-th Fibonacci number + """ + return fibonacci(i-1) * fibonacci(i-2) + +This is clearly wrong. Two developers, namely Alice and Bob, decide to +fix it. Bob corrected the seed values: + +.. CODE-BLOCK:: python + + def fibonacci(i): + """ + Return the `i`-th Fibonacci number + """ + if i > 1: + return fibonacci(i-1) * fibonacci(i-2) + return [0, 1][i] + +and turned those changes into a new commit:: + + [bob@laptop sage]$ git add fibonacci.py + [bob@laptop sage]$ git commit -m 'return correct seed values' + +He made his changes a PR to the GitHub Sage repo and got it merged to the +``develop`` branch. His ``fibonacci`` function is not yet perfect but is +certainly better than the original. + +Meanwhile, Alice changed the multiplication to an addition since that is the +correct recursion formula: + +.. CODE-BLOCK:: python + + def fibonacci(i): + """ + Return the `i`-th Fibonacci number + """ + return fibonacci(i-1) + fibonacci(i-2) + +and merged her branch with the latest ``develop`` branch fetched from the GitHub Sage repo:: + + [alice@home sage]$ git add fibonacci.py + [alice@home sage]$ git commit -m 'corrected recursion formula, must be + instead of *' + [alice@home sage]$ git fetch upstream develop:develop + [alice@home sage]$ git merge develop + ... + CONFLICT (content): Merge conflict in fibonacci.py + Automatic merge failed; fix conflicts and then commit the result. + +The file now looks like this: + +.. skip # doctester confuses >>> with input marker + +.. CODE-BLOCK:: python + + def fibonacci(i): + """ + Return the `i`-th Fibonacci number + """ + <<<<<<< HEAD + return fibonacci(i-1) + fibonacci(i-2) + ======= + if i > 1: + return fibonacci(i-1) * fibonacci(i-2) + return [0, 1][i] + >>>>>>> 41675dfaedbfb89dcff0a47e520be4aa2b6c5d1b + +The conflict is shown between the conflict markers ``<<<<<<<`` and +``>>>>>>>``. The first half (up to the ``=======`` marker) is Alice's +current version, the second half is Bob's version. The 40-digit hex +number after the second conflict marker is the SHA1 hash of the most +recent common parent of both. + +It is now Alice's job to resolve the conflict by reconciling their +changes, for example by editing the file. Her result is: + +.. CODE-BLOCK:: python + + def fibonacci(i): + """ + Return the `i`-th Fibonacci number + """ + if i > 1: + return fibonacci(i-1) + fibonacci(i-2) + return [0, 1][i] + +And then upload both her original change *and* her merge commit to the GitHub Sage repo:: + + [alice@laptop sage]$ git add fibonacci.py + [alice@laptop sage]$ git commit -m "merged Bob's changes with mine" + +The resulting commit graph now has a loop:: + + [alice@laptop sage]$ git log --graph --oneline + * 6316447 merged Bob's changes with mine + |\ + | * 41675df corrected recursion formula, must be + instead of * + * | 14ae1d3 return correct seed values + |/ + * 14afe53 initial commit + [alice@laptop sage]$ git push origin + +This time, there is no merge conflict since Alice's branch already merged the ``develop`` branch. + diff --git a/src/doc/en/developer/git_setup.rst b/src/doc/en/developer/git_setup.rst index e2d59c8dfda..49218288afa 100644 --- a/src/doc/en/developer/git_setup.rst +++ b/src/doc/en/developer/git_setup.rst @@ -4,79 +4,67 @@ Setting Up Git ============== -To work on the Sage source code, you need - -* a working ``git`` installation, see :ref:`section-git-install`. - -* configure ``git`` to use your name and email address for commits, see - :ref:`section-git-setup-name`. - -The :ref:`chapter-git-background` chapter contains further information -about ``git`` that might be useful to some but are not required. - .. _section-git-install: Installing Git -------------- -First, try ``git`` on the command line. Most distributions will have -it installed by default if other development tools are installed. If -that fails, use the following to install git: +Depending on your platform, use the following to install Git: Debian / Ubuntu - ``sudo apt-get install git-core`` + Run ``sudo apt-get install git-core`` Fedora - ``sudo yum install git-core`` + Run ``sudo yum install git-core`` Windows (Cygwin) - Install the Cygwin package ``git``. Do not attempt to use native - Windows installations of ``git``. + Install the Cygwin package Git. Do not attempt to use native + Windows installations of Git. Windows (WSL) We strongly recommend to install the package using the Linux distribution's package manager. Native Windows installations of - ``git`` may also work, but there are possible pitfalls. + Git may also work, but there are possible pitfalls. macOS Install the Xcode Command Line Tools. Some further resources for installation help are: -* `Section 1.5 of the git book +* `Section 1.5 of the Git book <https://git-scm.com/book/en/v2/Getting-Started-Installing-Git>`_ -* The `git homepage <http://git-scm.com>`_ for the most recent - information. +* The `Git homepage <http://git-scm.com>`_ for the most recent + information -* `Github install help pages <http://help.github.com>`_ +* `Git install help page on GitHub <https://github.com/git-guides/install-git>`_ .. _section-git-setup-name: -Your Name and Email -------------------- +Configuring Git +--------------- -The commit message of any change contains your name and email address -to acknowledge your contribution and to have a point of contact if -there are questions in the future; filling it in is required if you -want to share your changes. The simplest way to do this is from the -command line: +Assuming your name ``alice`` and email address ``alice@wonderland.com``, .. CODE-BLOCK:: shell-session - [user@localhost ~] git config --global user.name "Your Name" - [user@localhost ~] git config --global user.email you@yourdomain.example.com + [alice@localhost ~]$ git config --global user.name "Alice Adventure" + [alice@localhost ~]$ git config --global user.email alice@wonderland.com -This will write the settings into your :ref:`git configuration file -<section-git-configuration>` with your name and email: +This will write the settings into your Git configuration file +``~/.gitconfig`` with your name and email: .. CODE-BLOCK:: text [user] - name = Your Name - email = you@yourdomain.example.com + name = Alice Adventure + email = alice@wonderland.com + +Of course, replace ``Alice Adventure`` and ``alice@wonderland.com`` with your +actual name and email address. + +This is the basic Git configuration for now. For further tips on configuring +Git, see :ref:`section-git-configuration`. -Of course you'll need to replace ``Your Name`` and ``you@yourdomain.example.com`` -with your actual name and email address. diff --git a/src/doc/en/developer/git_trac.rst b/src/doc/en/developer/git_trac.rst deleted file mode 100644 index 462291488b9..00000000000 --- a/src/doc/en/developer/git_trac.rst +++ /dev/null @@ -1,596 +0,0 @@ -.. highlight:: shell-session - -.. _chapter-git_trac: - -==================================== -Optional: Using the Git-Trac Command -==================================== - -.. WARNING:: - - **Sage development is scheduled to move to GitHub in February 2023.** The exact - date will be announced in `<https://groups.google.com/g/sage-devel>`_. After - the transition, some parts of this guide (especially those related with `the - Sage Trac server <https://trac.sagemath.org>`_) will become obsolete and be - updated according to the new workflow on GitHub. See our `transition guide from Trac to - GitHub - <https://github.com/sagemath/trac-to-github/blob/master/docs/Migration-Trac-to-Github.md>`_ - for the preliminary version of the workflow. - -Git is a separate project from trac, and the two do not know how to -talk to each other. To simplify the development, we have a special -``git trac`` subcommand for the git suite. Note that this really is -only to simplify interaction with our trac issue management, you can -perform every development task with just git and a web browser. - -.. _section-git_trac-install: - -Installing the Git-Trac Command -=============================== - -:: - - [user@localhost]$ git clone https://github.com/sagemath/git-trac-command.git - Cloning into 'git-trac-command'... - [...] - Checking connectivity... done. - [user@localhost]$ source git-trac-command/enable.sh - Prepending the git-trac command to your search PATH - -This creates a directory ``git-trac-command``. - -Sourcing the ``enable.sh`` script in there is just a quick and dirty -way to enable it temporarily. For a more permanent installation on -your system later, make sure to put the ``git-trac`` command in your -``PATH``. Assuming that ``~/bin`` is already in your ``PATH``, you can -do this by symlinking:: - - [user@localhost]$ echo $PATH - /home/user/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin - [user@localhost]$ cd git-trac-command - [user@localhost git-trac-command]$ ln -s `pwd`/git-trac ~/bin/ - -See the `git-trac README <https://github.com/sagemath/git-trac-command>`_ for -more details. At this point you leave ``git-trac-command`` subdirectory, and only go -there whenever you need to update the ``git-trac`` command. - - - -.. _section-git_trac-setup: - -Git and Trac Configuration -========================== - -.. NOTE:: - - * `trac <https://trac.sagemath.org>`_ uses username/password for - authentication. - - * Our `git repository server <https://git.sagemath.org>`_ uses SSH - public key authentication for write access. - -You need to set up both authentication mechanisms to be able to upload -your changes with "git trac". For read-only access neither -authentication mechanism is needed. To set up ``git trac``, first go -to the Sage directory and tell ``git trac`` about your trac account:: - - [user@localhost sage]$ git trac config --user USERNAME --pass 'PASSWORD' - Trac xmlrpc URL: - https://trac.sagemath.org/xmlrpc (anonymous) - https://trac.sagemath.org/login/xmlrpc (authenticated) - realm sage.math.washington.edu - Username: USERNAME - Password: PASSWORD - Retrieving SSH keys... - 1024 ab:1b:7c:c9:9b:48:fe:dd:59:56:1e:9d:a4:a6:51:9d My SSH Key - -where you have to replace USERNAME with your trac user name and -PASSWORD with your trac password. If you don't have a trac account, -use ``git trac config`` without any arguments. The single quotes in -``'PASSWORD'`` escape special characters that you might have in your -password. The password is stored in plain-text in ``.git/config``, so -make sure that it is not readable by other users on your system. For -example, by running ``chmod 0600 .git/config`` if your home directory -is not already private. - -Instead of a username and password you may also configure authentication via -a generated token by passing ``--token=<token>`` instead of ``--pass``:: - - [user@localhost sage]$ git trac config --user=<username> --token=<token> - -This is required if you authenticate to Trac with your GitHub account, as -you do not have a Trac password. Logged in users can find their token -under :trac:`the token tab in preferences on the trac site <prefs/token>`. - -.. NOTE:: - - The username to be entered here is NOT the GitHub username, but rather the trac username which is gh-<GitHub-username> - as given on the top right corner of the trac server. - -If both a token and a username/password are configured, the token-based -authentication takes precedence. - -If you do not want to store your trac username/password/token on disk you -can temporarily override it with the environment variables -``TRAC_USERNAME``, ``TRAC_PASSWORD``, and ``TRAC_TOKEN`` respectively. -These take precedence over any other configuration. - -If there is no SSH key listed then you haven't uploaded your SSH -public key to the trac server. You should do that now following the -instructions to :ref:`section-trac-ssh-key`, if you want to upload -any changes. You may have to add your private key to your authentication agent:: - - [user@localhost sage]$ ssh-add - -.. NOTE:: - - The ``git trac config`` command will automatically add a ``trac`` - remote git repository to your list of remotes if necessary. - -If you followed the above instructions then you will have two remote -repositories set up:: - - [user@localhost sage]$ git remote -v - origin https://github.com/sagemath/sage.git (fetch) - origin https://github.com/sagemath/sage.git (push) - trac git@trac.sagemath.org:sage.git (fetch) - trac git@trac.sagemath.org:sage.git (push) - -The ``git@...`` part of the push url means that write access is -secured with SSH keys, which you must have set up as in -:ref:`section-trac-ssh-key`. Read-only access happens through the -fetch url and does not require SSH. - - -Trac Tickets and Git Branches -============================= - -Now let's start adding code to Sage! - -.. _section-git_trac-create: - -Create a Ticket ---------------- - -Suppose you have written an algorithm for calculating the last twin prime, and -want to add it to Sage. You would first open a ticket for that:: - - [user@localhost sage]$ git trac create 'Last Twin Prime' - Remote branch: u/user/last_twin_prime - Newly-created ticket number: 12345 - Ticket URL: https://trac.sagemath.org/12345 - Local branch: t/12345/last_twin_prime - -This will create a new trac ticket titled "Last Twin Prime" with a -*remote branch* ``u/user/last_twin_prime`` attached to it. The remote -branch name is automatically derived from the ticket title; If you -don't like this then you can use the ``-b`` switch to specify it -explicitly. See ``git trac create -h`` for details. This new branch is -automatically checked out for you with the *local branch* name -``t/12345/last_twin_prime``. - -.. NOTE:: - - Only some trac fields are filled in automatically. See - :ref:`section-trac-fields` for what trac fields are available and - how we use them. - - - -.. _section-git_trac-checkout: - -Check out an Existing Ticket ----------------------------- - -Alternatively, you can use the `web interface to the Sage trac -development server <https://trac.sagemath.org>`_ to open a new ticket. -Just log in and click on "Create Ticket". - -Or maybe somebody else already opened a ticket. Then, to get a suitable -local branch to make your edits, you would just run:: - - [user@localhost sage]$ git trac checkout 12345 - Loading ticket #12345... - Checking out Trac #13744 remote branch u/user/last_twin_prime -> local branch t/12345/last_twin_prime... - -The ``git trac checkout`` command downloads an existing branch (as -specified in the "Branch:" field on the trac ticket) or creates a new -one if there is none yet. Just like the create command, you can -specify the remote branch name explicitly using the ``-b`` switch if -you want. - -.. _section-git_trac-branch-names: - -Note on Branch Names --------------------- - -The "Branch:" field of a trac ticket (see :ref:`section-trac-fields`) indicates -the git branch containing its code. Our git server implements the following -access restrictions for **remote branch names**: - -* You can read/write/create a branch named - ``u/your_username/whatever_you_like``. Everybody else can read. - -* Everybody can read/write/create a branch named ``public/whatever_you_like``. - -Depending on your style of collaboration, you can use one or the -other. The ``git trac`` subcommands defaults to the former. - -As a convention, the ``git trac`` subcommand uses **local branch -names** of the form ``t/12345/description``, where the number is the -trac ticket number. The script uses this number to figure out the -ticket from the local branch name. You can rename the local branches -if you want, but if they don't contain the ticket number then you will -have to specify the ticket number manually when you are uploading your -changes. - -.. _section-git_trac-editing: - -Making Changes --------------- - -Once you have checked out a ticket, edit the appropriate files and -commit your changes to the branch as described in -:ref:`section-walkthrough-add-edit` and -:ref:`section-walkthrough-commit`. - -.. _section-git_trac-push: - -Uploading Changes to Trac -========================= - -.. _section-git_trac-push-auto: - -Automatic Push --------------- - -At some point, you may wish to share your changes with the rest of us: -maybe it is ready for review, or maybe you are collaborating with -someone and want to share your changes "up until now". This is simply -done by:: - - [user@localhost sage]$ git trac push - Pushing to Trac #12345... - Guessed remote branch: u/user/last_twin_prime - - To git@trac.sagemath.org:sage.git - * [new branch] HEAD -> u/user/last_twin_prime - - Changing the trac "Branch:" field... - -This uploads your changes to a remote branch on the `Sage git server -<https://git.sagemath.org/sage.git>`_. The ``git trac`` command uses -the following logic to find out the remote branch name: - -* By default, the remote branch name will be whatever is already on - the trac ticket. - -* If there is no remote branch yet, the branch will be called - ``u/user/description`` (``u/user/last_twin_prime`` in the example). - -* You can use the ``--branch`` option to specify the remote branch - name explicitly, but it needs to follow the naming convention from - :ref:`section-git_trac-branch-names` for you to have write - permission. - - -.. _section-git_trac-push-with-ticket-number: - -Specifying the Ticket Number ----------------------------- - -You can upload any local branch to an existing ticket, whether or not -you created the local branch with ``git trac``. This works exactly -like in the case where you started with a ticket, except that you have -to specify the ticket number (since there is no way to tell which -ticket you have in mind). That is:: - - [user@localhost sage]$ git trac push TICKETNUM - -where you have to replace ``TICKETNUM`` with the number of the trac -ticket. - - -.. _section-git_trac-push-finish: - -Finishing It Up ---------------- - -It is common to go through a few iterations of commits before you -upload, and you will probably also have pushed your changes a few -times before your changes are ready for review. - -Once you are happy with the changes you uploaded, they must be -reviewed by somebody else before they can be included in the next -version of Sage. To mark your ticket as ready for review, you should -set it to ``needs_review`` on the trac server. Also, add yourself as -the (or one of the) author(s) for that ticket by inserting the -following as the first line: - -.. CODE-BLOCK:: text - - Authors: Your Real Name - - -.. _section-git_trac-pull: - -Downloading Changes from Trac -============================= - -If somebody else worked on a ticket, or if you just switched -computers, you'll want to get the latest version of the branch from a -ticket into your local branch. This is done with:: - - [user@localhost sage]$ git trac pull - -Technically, this does a *merge* (just like the standard ``git pull``) -command. See :ref:`section-git-merge` for more background information. - - -.. _section-git_trac-merge: - -Merging -======= - -As soon as you are working on a bigger project that spans multiple -tickets you will want to base your work on branches that have not been -merged into Sage yet. This is natural in collaborative development, -and in fact you are very much encouraged to split your work into -logically different parts. Ideally, each part that is useful on its -own and can be reviewed independently should be a different ticket -instead of a huge patch bomb. - -For this purpose, you can incorporate branches from other tickets (or -just other local branches) into your current branch. This is called -merging, and all it does is include commits from other branches into -your current branch. In particular, this is done when a new Sage -release is made: the finished tickets are merged with the Sage master -and the result is the next Sage version. Git is smart enough to not -merge commits twice. In particular, it is possible to merge two -branches, one of which had already merged the other branch. The syntax -for merging is easy:: - - [user@localhost sage]$ git merge other_branch - -This creates a new "merge" commit, joining your current branch and -``other_branch``. - -.. WARNING:: - - You should avoid merging branches both ways. Once A merged B and B - merged A, there is no way to distinguish commits that were - originally made in A or B. Effectively, merging both ways combines - the branches and makes individual review impossible. - - In practice, you should only merge when one of the following holds: - - * Either two tickets conflict, then you have to merge one into the - other in order to resolve the merge conflict. - - * Or you definitely need a feature that has been developed as part - of another branch. - -A special case of merging is merging in the ``develop`` branch. This -brings your local branch up to date with the newest Sage version. The -above warning against unnecessary merges still applies, though. Try to -do all of your development with the Sage version that you originally -started with. The only reason for merging in the ``develop`` branch is if -you need a new feature or if your branch conflicts. See -:ref:`section-git-update-latest` for details. - - -.. _section-git_trac-collaborate: - -Collaboration and conflict resolution -===================================== - -Exchanging Branches -------------------- - -It is very easy to collaborate by just going through the above steps -any number of times. For example, Alice starts a ticket and adds some -initial code:: - - [alice@laptop sage]$ git trac create "A and B Ticket" - ... EDIT EDIT ... - [alice@laptop sage]$ git add . - [alice@laptop sage]$ git commit - [alice@laptop sage]$ git trac push - -The trac ticket now has "Branch:" set to -``u/alice/a_and_b_ticket``. Bob downloads the branch and works some -more on it:: - - [bob@home sage]$ git trac checkout TICKET_NUMBER - ... EDIT EDIT ... - [bob@home sage]$ git add . - [bob@home sage]$ git commit - [bob@home sage]$ git trac push - -The trac ticket now has "Branch:" set to ``u/bob/a_and_b_ticket``, -since Bob cannot write to ``u/alice/...``. Now the two authors just -pull/push in their collaboration:: - - [alice@laptop sage]$ git trac pull - ... EDIT EDIT ... - [alice@laptop sage]$ git add . - [alice@laptop sage]$ git commit - [alice@laptop sage]$ git trac push - - [bob@home sage]$ git trac pull - ... EDIT EDIT ... - [bob@home sage]$ git add . - [bob@home sage]$ git commit - [bob@home sage]$ git trac push - -Alice and Bob need not alternate, they can also add further commits on -top of their own remote branch. As long as their changes do not -conflict (edit the same lines simultaneously), this is fine. - - -.. _section-git_trac-conflict: - -Conflict Resolution -------------------- - -Merge conflicts happen if there are overlapping edits, and they are an -unavoidable consequence of distributed development. Fortunately, -resolving them is common and easy with git. As a hypothetical example, -consider the following code snippet: - -.. CODE-BLOCK:: python - - def fibonacci(i): - """ - Return the `i`-th Fibonacci number - """ - return fibonacci(i-1) * fibonacci(i-2) - -This is clearly wrong; Two developers, namely Alice and Bob, decide to -fix it. First, in a cabin in the woods far away from any internet -connection, Alice corrects the seed values: - -.. CODE-BLOCK:: python - - def fibonacci(i): - """ - Return the `i`-th Fibonacci number - """ - if i > 1: - return fibonacci(i-1) * fibonacci(i-2) - return [0, 1][i] - -and turns those changes into a new commit:: - - [alice@laptop sage]$ git add fibonacci.py - [alice@laptop sage]$ git commit -m 'return correct seed values' - -However, not having an internet connection, she cannot immediately -send her changes to the trac server. Meanwhile, Bob changes the -multiplication to an addition since that is the correct recursion -formula: - -.. CODE-BLOCK:: python - - def fibonacci(i): - """ - Return the `i`-th Fibonacci number - """ - return fibonacci(i-1) + fibonacci(i-2) - -and immediately uploads his change:: - - [bob@home sage]$ git add fibonacci.py - [bob@home sage]$ git commit -m 'corrected recursion formula, must be + instead of *' - [bob@home sage]$ git trac push - -Eventually, Alice returns to civilization. In her mailbox, she finds a -trac notification email that Bob has uploaded further changes to their -joint project. Hence, she starts out by getting his changes into her -own local branch:: - - [alice@laptop sage]$ git trac pull - ... - CONFLICT (content): Merge conflict in fibonacci.py - Automatic merge failed; fix conflicts and then commit the result. - -The file now looks like this: - -.. skip # doctester confuses >>> with input marker - -.. CODE-BLOCK:: python - - def fibonacci(i): - """ - Return the `i`-th Fibonacci number - """ - <<<<<<< HEAD - if i > 1: - return fibonacci(i-1) * fibonacci(i-2) - return [0, 1][i] - ======= - return fibonacci(i-1) + fibonacci(i-2) - >>>>>>> 41675dfaedbfb89dcff0a47e520be4aa2b6c5d1b - -The conflict is shown between the conflict markers ``<<<<<<<`` and -``>>>>>>>``. The first half (up to the ``=======`` marker) is Alice's -current version, the second half is Bob's version. The 40-digit hex -number after the second conflict marker is the SHA1 hash of the most -recent common parent of both. - -It is now Alice's job to resolve the conflict by reconciling their -changes, for example by editing the file. Her result is: - -.. CODE-BLOCK:: python - - def fibonacci(i): - """ - Return the `i`-th Fibonacci number - """ - if i > 1: - return fibonacci(i-1) + fibonacci(i-2) - return [0, 1][i] - -And then upload both her original change *and* her merge commit to trac:: - - [alice@laptop sage]$ git add fibonacci.py - [alice@laptop sage]$ git commit -m "merged Bob's changes with mine" - -The resulting commit graph now has a loop:: - - [alice@laptop sage]$ git log --graph --oneline - * 6316447 merged Bob's changes with mine - |\ - | * 41675df corrected recursion formula, must be + instead of * - * | 14ae1d3 return correct seed values - |/ - * 14afe53 initial commit - -If Bob decides to do further work on the ticket then he will have to -pull Alice's changes. However, this time there is no conflict on his -end: git downloads both Alice's conflicting commit and her resolution. - - -.. _section-git_trac-review: - -Reviewing -========= - -For an explanation of what should be checked by the reviewer, see -:ref:`chapter-review`. - -If you go to the `web interface to the Sage trac development server -<https://trac.sagemath.org>`_ then you can click on the "Branch:" field and see -the code that is added by combining all commits of the ticket. This is what -needs to be reviewed. - -The ``git trac`` command gives you two commands that might be handy -(replace ``12345`` with the actual ticket number) if you do not want -to use the web interface: - -* ``git trac print 12345`` displays the trac ticket directly in your - terminal. - -* ``git trac review 12345`` downloads the branch from the ticket and - shows you what is being added, analogous to clicking on the - "Branch:" field. - -To review tickets with minimal recompiling, start by building the "develop" -branch, that is, the latest beta. Just checking out an older ticket would most -likely reset the Sage tree to an older version, so you would have to compile -older versions of packages to make it work. Instead, you can create an anonymous -("detached HEAD") merge of the ticket and the develop branch using :: - - $ git trac try 12345 - -This will only touch files that are really modified by the ticket. In particular, -if only Python files are changed by the ticket (which is true for most tickets) -then you just have to run ``sage -b`` to rebuild the Sage library. If files other -than Python have been changed, you must run ``make``. When you are finished -reviewing, just check out a named branch, for example :: - - $ git checkout develop - -If you want to edit the ticket branch (that is, add additional commits) you cannot -use ``git trac try``. You must :ref:`section-git_trac-checkout` to get the actual ticket -branch as a starting point. diff --git a/src/doc/en/developer/github.rst b/src/doc/en/developer/github.rst new file mode 100644 index 00000000000..79db6ccc3d1 --- /dev/null +++ b/src/doc/en/developer/github.rst @@ -0,0 +1,455 @@ +.. highlight:: shell-session + + +.. _chapter-github: + +============================= +The Sage Repository on GitHub +============================= + +The center of Sage development is `the SageMath organization on GitHub +<https://github.com/sagemath>`_, which consists of many repositories related +with Sage. The most important one among them is of course `the Sage repository +<https://github.com/sagemath/sage>`_, which we call "the Sage repo" for short. + + +.. _section-github-account: + +Obtaining a GitHub account +========================== + +To share your work on Sage, you need a GitHub account. If you do not have one +yet, choose a username and `create an account <https://github.com/join>`_. In +the following, we assume your username "alice". So you always read your own +username if you see "alice". + + +.. _section-github-cli: + +Using the GitHub CLI +==================== + +GitHub provides a command-line interface, the GitHub CLI, that can be used +instead of the web interface. The central component of the GitHub CLI is the +``gh`` command that you can use in your terminal. + +Installation +------------ + +The page :ref:`spkg_github_cli` documents how to install the ``gh`` command for +your platform. Or see `GitHub CLI <https://cli.github.com>`_ from GitHub. + +Configuration +------------- + +You have to authenticate to your GitHub account to allow ``gh`` command to +interact with GitHub. Typically the authorization proceeds as follows:: + + [alice@localhost sage]$ gh auth login + ? What is your preferred protocol for Git operations? HTTPS + ? Authenticate Git with your GitHub credentials? Yes + ? How would you like to authenticate GitHub CLI? Login with a web browser + + ! First copy your one-time code: 3DA8-5ADA + Press Enter to open github.com in your browser... + โœ“ Authentication complete. + - gh config set -h github.com git_protocol https + โœ“ Configured git protocol + โœ“ Logged in as sage + +where a web browser is used to enter credentials. You can also use an +authentication token instead, in which case you must first generate `a Personal +Access Token here <https://github.com/settings/tokens>`_. + +Next set the default repo for the ``gh`` command:: + + [alice@localhost sage]$ gh repo set-default sagemath/sage + +and check:: + + [alice@localhost sage]$ gh repo view + sagemath/sage + ... + +which will show the default repo along with its readme, which is quite long. + +``gh`` extensions +----------------- + +``gh`` is extendable; e.g. a useful extension to ``gh`` allows testing of +Sage's GitHub Actions locally, using Docker. It is called ``act`` and can be +installed by running:: + + [alice@localhost sage]$ gh extension install https://github.com/nektos/gh-act + +Append ``--force`` flag to the command above to force an upgrade of the extension. +More details on configuring and using ``gh act`` are in :ref:`chapter-portability_testing`. + + +Linking Git to your GitHub account +================================== + +In order for your Git to work with GitHub, your GitHub account needs to be +linked with your Git. No action is needed if you have already contributed to +any other project on GitHub and set up Git credentials or SSH keys for this. + +The above dialogue from ``gh auth login`` linked your Git to GitHub by HTTPS +protocol using your GitHub credentials. Alternatively you may like to use +popular `Git Credential Manager +<https://github.com/git-ecosystem/git-credential-manager>`_ which stores your +credentials natively to your platform. For more information, see `Caching your +GitHub credentials in Git +<https://docs.github.com/en/get-started/getting-started-with-git/caching-your-github-credentials-in-git>`_. + +If you prefer SSH to HTTPS for authenticating Git to GitHub, then you follow +:ref:`section-git-ssh` to generate an SSH keypair and add the SSH public key to +your GitHub account. A simple way to upload the public key is to choose SSH +protocol for Git operations in the dialogue from ``gh auth login`` command +above. For more details, see `Connecting to GitHub with SSH +<https://docs.github.com/en/authentication/connecting-to-github-with-ssh>`_. + +We assume HTTPS protocol in the rest of this guide. + + +Forking the Sage repository +=========================== + +The first step is to create `your personal fork +<https://docs.github.com/en/get-started/quickstart/fork-a-repo#forking-a-repository>`_ +of the Sage repo on GitHub. After logging in to your GitHub account, visit the +Sage repo https://github.com/sagemath/sage, and simply click "Fork" on the Sage +repo. Then your fork of the Sage repo is created at +https://github.com/alice/sage. + +Next if you don't have a local Git repo of Sage, then start afresh `cloning +your fork +<https://docs.github.com/en/get-started/quickstart/fork-a-repo#cloning-your-forked-repository>`_:: + + [alice@localhost ~]$ git clone https://github.com/alice/sage.git + Cloning into 'sage'... + remote: Enumerating objects: 914565, done. + remote: Counting objects: 100% (2738/2738), done. + remote: Compressing objects: 100% (855/855), done. + remote: Total 914565 (delta 1950), reused 2493 (delta 1875), pack-reused 911827 + Receiving objects: 100% (914565/914565), 331.09 MiB | 11.22 MiB/s, done. + Resolving deltas: 100% (725438/725438), done. + Updating files: 100% (9936/9936), done. + [alice@localhost ~]$ cd sage + [alice@localhost sage]$ git remote -v + origin https://github.com/alice/sage.git (fetch) + origin https://github.com/alice/sage.git (push) + +If you already have a local Git repo and only want to link your fork as ``origin`` remote, then do:: + + [alice@localhost sage]$ git remote add origin https://github.com/alice/sage.git + [alice@localhost sage]$ git remote -v + origin https://github.com/alice/sage.git (fetch) + origin https://github.com/alice/sage.git (push) + [alice@localhost sage]$ git fetch origin + remote: Enumerating objects: 1136, done. + remote: Counting objects: 100% (1084/1084), done. + remote: Compressing objects: 100% (308/308), done. + remote: Total 1136 (delta 825), reused 982 (delta 776), pack-reused 52 + Receiving objects: 100% (1136/1136), 2.62 MiB | 5.30 MiB/s, done. + Resolving deltas: 100% (838/838), completed with 145 local objects. + From https://github.com/alice/sage + * [new branch] develop -> origin/develop + +You also add the Sage repo ``sagemath/sage`` as your remote ``upstream``:: + + [alice@localhost sage]$ git remote add upstream https://github.com/sagemath/sage.git + [alice@localhost sage]$ git remote -v + origin https://github.com/alice/sage.git (fetch) + origin https://github.com/alice/sage.git (push) + upstream https://github.com/sagemath/sage.git (fetch) + upstream https://github.com/sagemath/sage.git (push) + + +.. NOTE:: + + If you linked your Git to GitHub by SSH protocol, then do the following + instead to set up remotes:: + + [alice@localhost sage]$ git remote add origin git@github.com:alice/sage.git + [alice@localhost sage]$ git remote add upstream git@github.com:sagemath/sage.git + [alice@localhost sage]$ git remote -v + origin git@github.com:alice/sage.git (fetch) + origin git@github.com:alice/sage.git (push) + upstream git@github.com:sagemath/sage.git (fetch) + upstream git@github.com:sagemath/sage.git (push) + +To prevent accidental pushes to ``upstream`` (instead of ``origin``), you may want to disable it by running:: + + [alice@localhost sage]$ git remote set-url --push upstream DISABLE + +Of course, you can give arbitrary names to your Git remotes, but ``origin`` and +``upstream`` are the established defaults, which will make it easier to use tools +such as the GitHub CLI. + + +.. _section-github-bug-report: + +Reporting bugs +============== + +If you think you have found a bug in Sage, here is the procedure: + +- Search through our Google groups `sage-devel <https://groups.google.com/group/sage-devel>`_, `sage-support <https://groups.google.com/group/sage-support>`_ for postings related to your possible bug (it + may have been fixed/reported already). You also search `the GitHub issues + <https://github.com/sagemath/sage/issues>`_ to see if anyone else has already + opened an issue about your bug. + +- If you do not find anything but you are not sure that you have found a bug, + ask about it on `sage-devel <https://groups.google.com/group/sage-devel>`_. + +- If you are sure that you have found a bug, then create on GitHub a new issue about the bug. + + A bug report should contain: + + - An explicit and **reproducible example** illustrating your bug (and/or the + steps required to reproduce the buggy behavior). It also helps to describe what + behaviour is expected. + + - The **version of Sage** you run, as well as the version of the optional + packages that may be involved in the bug. + + - If relevant, describe your **operating system** as accurately as you can and the + architecture of your CPU (32 bit, 64 bit, ...). + +Follow :ref:`section-github-create-issue` for further guide. Thank you in +advance for reporting bugs to improve Sage! + + +.. _section-github-new-enhancement: + +Planning an enhancement +======================= + +In addition to bug reports, you should also open an issue if you have some new +code or an idea that makes Sage better. If you have a feature request, start a +discussion on `sage-devel <https://groups.google.com/group/sage-devel>`_ first, +and then if there seems to be a general agreement that you have a good idea, +open an issue describing the idea. + +Before opening a new issue, consider the following points: + +- Make sure that nobody else has opened an issue (or a PR) about the same + or closely related issue. Search through the existing issues and PRs with + some key words. + +- It is much better to open several specific issues than one that + is very broad. Indeed, a single issue which deals with lots of + different issues can be quite problematic, and should be avoided. + +- Be precise: If foo does not work on macOS but is fine on Linux, + mention that in the title. Use the keyword option so that + searches will pick up the issue. + +- The problem described in the issue must be solvable. For + example, it would be silly to open an issue whose purpose was + "Make Sage the best mathematical software in the world". There is + no metric to measure this properly and it is highly subjective. + +- If appropriate, provide URLs to background information or sage-devel + conversation relevant to the issue you are reporting. + + +.. _section-github-create-issue: + +Opening an issue +================ + +Whether it's reporting a bug or planning an enhancement, `issue +<https://docs.github.com/en/issues/tracking-your-work-with-issues/about-issues>`_ +should be opened on our Sage repo `sagemath/sage +<https://github.com/sagemath/sage/issues>`_ on GitHub. + +- Think of an apt title. People scan through the titles of issues to decide + which ones to look into further. So write a title that concisely describes + what the issue is about. + +- Describe the issue in detail in the issue body. What is the issue? How can we + solve the issue? Add links to relevant issues/PRs, and other resources. + + You may use GitHub mention ``@USERNAME`` to get attention from the people + who would be interested in the issue or has expertise in this issue. + +- Add appropriate labels to the created issue: + + - **Type** labels with prefix ``t:`` such as ``t: bug``, ``t: enhancement``, + ``t: feature``, ``t: performance``, ``t: refactoring``, + ``t: tests`` + + - **Component** labels with prefix ``c:`` such as ``c: basic arithmetic``, + ``c: linear algebra``, ``c: geometry``, etc. + + - **Priority** labels with prefix ``p:`` such as ``p: trivial / 5``, + ``p: minor / 4``, ``p: major / 3``, ``p: critical / 2``, and ``p: blocker / 1`` + + If the issue is not expected to be solved in the near future, you may add + ``wishlist item`` label. + + +.. _section-github-create-pr: + +Creating a Pull Request +======================= + +If you worked on an issue, and prepared a fix for a bug or wrote code for +enhancing Sage, then you create a PR on the Sage repo `sagemath/sage +<https://github.com/sagemath/sage/issues>`_. + +In addition to what were said about opening an issue, the following applies: + +- The title should concisely describe what the PR does. If the PR solves an + issue, describe briefly what the PR solves (do not simply put the issue + number in the title). + +- Explain what the PR solves in detail in the body. If the PR solves an issue, + you may mention the issue here. + +- Add type, component, and priority labels. If this PR solves an existing + issue, please duplicate the labels of the issue to this PR. + +- **Dependencies**: Use the phrase ``- Depends on``, followed by the issue or PR + reference. Repeat this in separate lines if there is more than one + dependency. This format is understood by various dependency managers. + +If you are working on a PR and the PR is not yet quite ready for review, then +`open the PR as draft +<https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests>`_. + + +.. _section-github-pr-status: + +The status of a PR +================== + +If a PR is in the state of draft, the review process does not start. Otherwise, +review process will start for the PR as soon as a reviewer gets interested with +the PR, and the status of the PR will be indicated by **status** labels with +prefix ``s:``. + +- ``s: needs review``: The code is ready to be peer-reviewed. If the code is not + yours, then you can review it. See :ref:`chapter-review`. + +- ``s: needs work``: Something needs to be changed in the code. The reason should + appear in the comments. + +- ``s: needs info``: The author of the PR or someone else should answer to a + question or provide information to proceed the review process. + +- ``s: positive review``: The PR has been reviewed positively, and the release manager + will merge it to the ``develop`` branch of the Sage repo in due time. + +If the PR does not get positive review and it is decided to close the PR, then +the PR will get one of **resolution** labels: ``r: duplicate``, ``r: invalid``, +``r: wontfix``, ``r: worksforme``. + + +.. _section-github-stopgaps: + +The stopgap +=========== + +When Sage returns wrong results, an issue and a PR should be created: + +- A stopgap issue with all available details. +- A stopgap PR (e.g. :issue:`12699`) + +The stopgap PR does not fix the problem but adds a warning that will be +printed whenever anyone uses the relevant code, until the problem is +finally fixed. + +To produce the warning message, use code like the following: + +.. CODE-BLOCK:: python + + from sage.misc.stopgap import stopgap + stopgap("This code contains bugs and may be mathematically unreliable.", + ISSUE_NUM) + +Replace ``ISSUE_NUM`` by the reference number for the stopgap issue. On the stopgap issue, enter the reference number for the stopgap PR. Stopgap issues and PRs should be marked as critical. + +.. NOTE:: + + If mathematically valid code causes Sage to raise an error or + crash, for example, there is no need for a stopgap. Rather, + stopgaps are to warn users that they may be using buggy code; if + Sage crashes, this is not an issue. + + +Commenting issues and PRs +========================= + +Anyone can comment on an issue or a PR. If a PR is linked to an issue, +you may not be sure where the comment should go. Then + +- Comments on the reported issue should go on the issue. + +- Comments on the submitted code should go on the PR. + + +Checks on PRs +============= + +If you manage to fix a bug or enhance Sage, you are our hero. See +:ref:`chapter-walkthrough` for making changes to the Sage source code and +:ref:`section-github-create-pr` to create a PR for the changes. + +For each push to a PR, automated tests for the branch of the PR run on GitHub +Actions. + +* A `linting workflow + <https://github.com/sagemath/sage/blob/develop/.github/workflows/lint.yml>`_ + checks that the code of the current branch adheres to the style guidelines + using :ref:`section-tools-pycodestyle` (in the ``pycodestyle-minimal`` + configuration) and :ref:`section-tools-relint`. + + In order to see details when it fails, you can click on the check + and then select the most recent workflow run. + +* The `build and test workflow + <https://github.com/sagemath/sage/blob/develop/.github/workflows/build.yml>`_ + on GitHub Actions builds Sage for the current branch (incrementally + on top of an installation of the ``develop`` branch) and runs the + test. Details are again available by clicking on the check. + + The automatic workflow runs on a container based on + ``ubuntu-focal-standard``. To request a run of the workflow on a different + platform, you can issue a `workflow dispatch + <https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow#running-a-workflow>`_. + You can select any of the platforms for which a `prebuilt container image + <https://github.com/orgs/sagemath/packages?tab=packages&q=with-targets-optional>`_ + exists. + +* The `build documentation workflow + <https://github.com/sagemath/sage/blob/develop/.github/workflows/doc-build.yml>`_ + on GitHub Actions builds the HTML documentation for the current branch. + + A link to the built doc is added in a comment, and so you can easily inspect changes + to the documentation without the need to locally rebuild the docs yourself. + + If the doc build fails, you can go to Actions tab and examine `documentation + build workflow + <https://github.com/sagemath/sage/actions/workflows/doc-build.yml>`_ and + choose the particular branch to see what went wrong. + + +Final notes +=========== + +* Every bug fixed should result in a doctest. + +* There are many enhancements possible for Sage and too few developers to + implement all the good ideas. + +* If you are a developer, be nice and try to solve a stale/old issue + every once in a while. + +* Some people regularly do triage. In this context, this means that we + look at new bugs and classify them according to our perceived + priority. It is very likely that different people will see + priorities of bugs very differently from us, so please let us know + if you see a problem with specific PRs. + diff --git a/src/doc/en/developer/index.rst b/src/doc/en/developer/index.rst index d851df7b0e7..7dc5cefd440 100644 --- a/src/doc/en/developer/index.rst +++ b/src/doc/en/developer/index.rst @@ -1,19 +1,16 @@ .. _developers-guide: -====================================== -Welcome to the Sage Developer's Guide! -====================================== +=============================== +Welcome to Sage Developer Guide +=============================== -.. WARNING:: +.. NOTE:: - **Sage development is scheduled to move to GitHub in February 2023.** The exact - date will be announced in `<https://groups.google.com/g/sage-devel>`_. After - the transition, some parts of this guide (especially those related with `the - Sage Trac server <https://trac.sagemath.org>`_) will become obsolete and be - updated according to the new workflow on GitHub. See our `transition guide from Trac to - GitHub - <https://github.com/sagemath/trac-to-github/blob/master/docs/Migration-Trac-to-Github.md>`_ - for the preliminary version of the workflow. + Sage development moved to `GitHub <https://github.com/sagemath>`_ in + February 2023, from `the Sage Trac server <https://trac.sagemath.org>`_, + which had been the center of Sage development for a long time. After the + transition, this guide was updated accordingly. However, the legacy is + still with us in many aspects of the current Sage development. Everybody who uses Sage is encouraged to contribute something back to Sage at some point. You could: @@ -21,162 +18,171 @@ some point. You could: * Add examples to the documentation * Find bugs or typos * Fix a bug -* Implement a new function +* Implement a new function or create a new class * Contribute a useful tutorial for a mathematical topic * Translate an existing document to a new language -* Create a new class, create a fast new C library, etc. +* Upgrade a package, create a fast new C library, etc. -This document tells you what you need to know to do all the above, from -reporting bugs to modifying and extending Sage and its documentation. We also -discuss how to share your new and modified code with other Sage users around the -globe. +This document tells you what you need to know to do all the above. We also +discuss how to share your new and modified code with other Sage users around +the globe. -Here are brief overviews of each part; for more details, see the extended table -of contents below. No matter where you start, good luck and welcome to Sage -development! +To begin with, you need of course your own copy of Sage source code to change +it. Use our `Installation guide +<http://doc.sagemath.org/html/en/installation/source.html>`_ to get the source +code and build Sage from source. If you have never worked on software before, +pay close attention to the prerequisites to build on your platform. -- **Trac server:** all changes go through `the Sage Trac server - <https://trac.sagemath.org>`_ at some point. It contains bug reports, upgrade - requests, changes in progress, and those already part of Sage - today. :ref:`Click here <chapter-sage-trac>` for more information. +Now here is a brief overview of this guide. - Importantly, you will need to :ref:`create a trac account - <section-trac-account>` in order to contribute. +- :ref:`section-first-steps`: To share changes with the Sage community, you + need to learn about revision control. We use the software Git for this + purpose. Here we walk you through from setting up Git on your platform + and to preparing a local branch to share with all Sage users. -- **Source code:** You need your own copy of Sage's source code to change it. - `Go there <http://doc.sagemath.org/html/en/installation/source.html>`_ to get it - and for instructions to build it. + .. NOTE:: - If you have never worked on software before, pay close attention to the - `prerequisites to compile - <http://doc.sagemath.org/html/en/installation/source.html#prerequisites>`_ on your - system. + As an easy way to get started, you can run and edit Sage's code and contribute + your changes using `Gitpod <https://www.gitpod.io>`_, a free online development + environment based on VS Code. It will launch a pre-made workspace with all + dependencies and tools installed so that you can start contributing straight + away. Start by `going to Gitpod + <https://gitpod.io/#https://github.com/sagemath/sage>`_, and read :ref:`our + Gitpod guidelines <section-gitpod>` to learn more. - As an easy way to get started, you can run and edit Sage's code and contribute - your changes using `Gitpod <https://www.gitpod.io>`_, - a free online development environment based on VS Code. - It will launch a pre-made workspace with all dependencies and tools installed - so that you can start contributing straight away. - Start by `going to Gitpod <https://gitpod.io/#https://github.com/sagemath/sage>`_, - and read :ref:`our Gitpod guidelines <section-gitpod>` to learn more. +- :ref:`section-development-on-github`: All changes go through `the Sage + repository on GitHub <https://github.com/sagemath/sage>`_ at some point. It contains + bug reports, enhancement proposals, changes in progress, and indeed all the + history of Sage today. You have to be familiar with it to be involved in Sage + development. -- **Conventions:** read our :ref:`conventions and guidelines - <section-writing-code-for-sage>` for code and documentation. +- :ref:`section-git-tricks-and-tips`: Here we give an in-depth guide for + working with Git for Sage development. Read this when you need help on Git in + a tricky situation such as merge conflict. - For everything related to manuals, tutorials, and languages, :ref:`click here - <chapter-sage_manuals>`. +- :ref:`section-writing-code-for-sage`: This is a guide on conventions in + writing code and documentation. A beginning developer should read this to be + a good developer. As conventions evolve over time, also experienced Sage + contributors may want to review this chapter once in a while. -- **Git (revision control):** To share changes with the Sage community, you will - need to learn about revision control; we use the software Git for this - purpose. +- :ref:`section-testing-sage`: We value testing Sage highest. Every change of + Sage source code has a risk to break Sage, and must be tested before being + merged. This part explains our various tools to help test Sage. - - :ref:`How to install it? <section-git-install>` - - :ref:`How to configure it for use with Trac? <section-git-setup-name>` - - :ref:`Here is <chapter-walkthrough>` an overview of our development flow. +- :ref:`section-updating-documentation`: All features of Sage are documented in + our manuals. This part explains the technical aspect of updating Sage + documentation. -Git and Trac for Sage development -================================= +- :ref:`section-more-on-coding`: When you need to know the technical details of + Sage for deep coding, read this. -First Steps with Git --------------------- +- :ref:`section-packaging`: Sage is composed of many third-party packages and + its own distribution packages. This part is for advanced developers. -Sage uses git for version control. +For more details, see the table of contents below. No matter where you start, +good luck and welcome to Sage development! + + +Table of Contents +================= + +.. _section-first-steps: + +First Steps +----------- .. toctree:: - :maxdepth: 3 + :maxdepth: 2 + walkthrough git_setup - walk_through -.. _section-git-tricks-and-tips: -Using Git with Trac -------------------- +.. _section-development-on-github: -To contribute back your changes to Sage source code to the project, -you will need a ticket on the -`Sage trac server <http://trac.sagemath.org>`_. +Working on GitHub +----------------- .. toctree:: :maxdepth: 2 - trac - manual_git - git_background - advanced_git + github workflows - git_trac + review + + +.. _section-git-tricks-and-tips: + +Working with Git +---------------- + +.. toctree:: + :maxdepth: 2 + + git_basic + git_advanced + git_background .. _section-writing-code-for-sage: Writing Code for Sage -===================== +--------------------- .. toctree:: - :maxdepth: 3 + :maxdepth: 2 workspace coding_basics - reviewer_checklist -Running Sage's tests --------------------- -.. toctree:: - :maxdepth: 3 +.. _section-testing-sage: - doctesting - -Testing on multiple platforms ------------------------------ +Testing Sage +------------ .. toctree:: - :maxdepth: 3 + :maxdepth: 2 + doctesting portability_testing + tools -Additional development and testing tools ----------------------------------------- - -.. toctree:: - :maxdepth: 3 - tools +.. _section-updating-documentation: -Contributing to Manuals and Tutorials -------------------------------------- +Updating Sage Documentation +--------------------------- .. toctree:: - :maxdepth: 3 + :maxdepth: 2 sage_manuals -Sage Coding Details -------------------- + +.. _section-more-on-coding: + +More on Coding for Sage +----------------------- .. toctree:: - :maxdepth: 3 + :maxdepth: 2 coding_in_python coding_in_cython coding_in_other -Packaging the Sage Library --------------------------- - -.. toctree:: - :maxdepth: 3 - packaging_sage_library +.. _section-packaging: -Packaging Third-Party Code --------------------------- +Packaging +--------- .. toctree:: - :maxdepth: 3 + :maxdepth: 2 packaging + packaging_sage_library Indices and tables diff --git a/src/doc/en/developer/manual_git.rst b/src/doc/en/developer/manual_git.rst deleted file mode 100644 index 83f595abab7..00000000000 --- a/src/doc/en/developer/manual_git.rst +++ /dev/null @@ -1,499 +0,0 @@ -.. highlight:: shell-session - -.. _chapter-manual-git: - -=================================== -Using Git with the Sage Trac Server -=================================== - -.. WARNING:: - - **Sage development is scheduled to move to GitHub in February 2023.** The exact - date will be announced in `<https://groups.google.com/g/sage-devel>`_. After - the transition, some parts of this guide (especially those related with `the - Sage Trac server <https://trac.sagemath.org>`_) will become obsolete and be - updated according to the new workflow on GitHub. See our `transition guide from Trac to - GitHub - <https://github.com/sagemath/trac-to-github/blob/master/docs/Migration-Trac-to-Github.md>`_ - for the preliminary version of the workflow. - -Now we continue our introduction to git from :ref:`chapter-walkthrough`. -We discuss how to push your local changes to a remote repository -so that your changes can be reviewed for inclusion in Sage. - -In the following, we assume that you are in the source directory of Sage (``SAGE_ROOT``), -obtained either from a source tarball or by cloning a Sage git repository -such as https://github.com/sagemath/sage.git, as described in the -`README <https://github.com/sagemath/sage/#readme>`_. -In either case, this source directory is actually the main worktree of -a local git repository. - -Using the following command, we can see which remote repository or repositories -are associated with this local repository:: - - [user@localhost sage]$ git remote -v - origin https://github.com/sagemath/sage.git (fetch) - origin https://github.com/sagemath/sage.git (push) - -.. _section-git-ssh: - -Git authentication through SSH -============================== - -In order to push changes securely to a remote repository, git uses -public-key cryptography. This section will show you how to set up the -necessary cryptographic keys for Secure Shell (SSH). - - -Checking whether you have already have suitable SSH keys --------------------------------------------------------- - -Follow the instructions in -https://docs.gitlab.com/ee/user/ssh.html#see-if-you-have-an-existing-ssh-key-pair. - - -Generating your SSH Keys ------------------------- - -If you don't have suitable SSH keys yet, you can create a key pair -with the ``ssh-keygen`` tool. - -Follow either the detailed instructions at -https://docs.gitlab.com/ee/user/ssh.html#generate-an-ssh-key-pair -or the following brief instructions:: - - [user@localhost ~]$ ssh-keygen - Generating public/private rsa key pair. - Enter file in which to save the key (/home/user/.ssh/id_rsa): - Enter passphrase (empty for no passphrase): - Enter same passphrase again: - Your identification has been saved in /home/user/.ssh/id_rsa. - Your public key has been saved in /home/user/.ssh/id_rsa.pub. - The key fingerprint is: - ce:32:b3:de:38:56:80:c9:11:f0:b3:88:f2:1c:89:0a user@localhost - The key's randomart image is: - +--[ RSA 2048]----+ - | .... | - | .. | - | .o+ | - | o o+o. | - |E + . .S | - |+o . o. | - |. o +.o | - | oB | - | o+.. | - +-----------------+ - -This will generate a new random private RSA key -in the ``.ssh`` folder in your home directory. By default, they are - -``~/.ssh/id_rsa`` - Your private key. Keep safe. **Never** hand it out to anybody. - -``~/.ssh/id_rsa.pub`` - The corresponding public key. This and only this file can be safely - disclosed to third parties. - -The ``ssh-keygen`` tool will let you generate a key with a different -file name, or protect it with a passphrase. Depending on how much you -trust your own computer or system administrator, you can leave the -passphrase empty to be able to login without any human intervention. - - -.. _section-trac-ssh-key: - -Linking your Public Key to your Trac Account --------------------------------------------- - -In order to push your code directly to a branch on the git repository -trac.sagemath.org, the Sage trac server needs to know your public -key. You can upload it in the preferences, that is - -1. Go to https://trac.sagemath.org - -2. Log in with your trac username/password - -3. Click on "Preferences" - -4. Go to the "SSH Keys" tab - -5. Paste the content of your public key file - (e.g. ``~/.ssh/id_rsa.pub``) - -6. Click on "Save changes" - -Note that this does **not** allow you to ssh into any account on trac, -it is only used to authenticate you to the gitolite installation on -trac. You can test that you are being authenticated correctly by -issuing some basic gitolite commands, for example:: - - [user@localhost ~]$ ssh git@trac.sagemath.org info - hello user, this is git@trac running gitolite3 (unknown) on git 1.7.9.5 - - R W sage - [user@localhost ~]$ ssh git@trac.sagemath.org help - hello user, this is gitolite3 (unknown) on git 1.7.9.5 - - list of remote commands available: - - desc - help - info - perms - writable - -Adding your Public Key for authentication on another server ------------------------------------------------------------ - -If you have an account on a lab or department computer that allows you -to log in remotely via SSH, you can now also use your SSH keys to -log in. Just copy the **public** key file (ending in ``.pub``) to -``~/.ssh/authorized_keys`` on the remote computer and make sure that -the file is only read/writeable by yourself. Voila, the next time you -ssh into that machine you don't have to provide your password. - - -.. _section-git-trac: - -The git repository trac.sagemath.org -==================================== - -The Sage trac server is another git repository for the Sage source tree, it is -served via the ssh protocol. To add it as a remote repository to your local git -repository, use these commands:: - - [user@localhost sage]$ git remote add trac https://github.com/sagemath/sagetrac-mirror.git -t master - [user@localhost sage]$ git remote set-url --push trac git@trac.sagemath.org:sage.git - -.. WARNING:: - - **Sage development is scheduled to move to GitHub in February 2023.** After the - move, the Sage trac server git@trac.sagemath.org:sage.git will no longer be - available, but all branches will be available (in read-only mode) on - https://github.com/sagemath/sagetrac-mirror.git. - -Instead of ``trac`` you can use any other name you want, of course. -To verify that it is set up correctly:: - - [user@localhost sage]$ git remote -v - origin https://github.com/sagemath/sage.git (fetch) - origin https://github.com/sagemath/sage.git (push) - trac https://github.com/sagemath/sagetrac-mirror.git (fetch) - trac git@trac.sagemath.org:sage.git (push) - -It is perfectly fine to have multiple remote repositories for git, -think of them as bookmarks. You can then use ``git pull`` to get -changes and ``git push`` to upload your local changes using:: - - [user@localhost sage]$ git <push|pull> trac [ARGS] - -.. NOTE:: - - In the command above we set up the remote to only track the - ``master`` branch on the trac server (the ``-t master`` - option). This avoids clutter by not automatically downloading all - branches ever created. But it also means that you will not fetch - everything that is on trac by default, and you need to explicitly - tell git which branch you want to get from trac. See the - :ref:`section-git-checkout` section for examples. - -Note that write operations (``push``) use the ssh protocol (specified by the ``git@`` -part). For this to work, you need to have a trac account and to set up your ssh public -key as described in `Trac authentication through ssh -<http://doc.sagemath.org/html/en/developer/trac.html#trac-authentication-through-ssh>`_. -Authentication is necessary if you want to upload anything to ensure -that it really is from you. - -The above instructions set up the remote to perform read-only operations (``fetch``) -using HTTPS from a mirror of the trac repository instead. The mirror is faster and -more reliable than our git server. However, this configuration is not recommended if -you use VS Code as an IDE. - -If you want to use ssh only for both ``fetch`` and ``push``, use the -following commands instead:: - - [user@localhost sage]$ git remote add trac git@trac.sagemath.org:sage.git -t master - [user@localhost sage]$ git remote -v - origin https://github.com/sagemath/sage.git (fetch) - origin https://github.com/sagemath/sage.git (push) - trac git@trac.sagemath.org:sage.git (fetch) - trac git@trac.sagemath.org:sage.git (push) - -* The Patch buildbot will automatically test your ticket. See :trac:`wiki/patchbot` - for more information about its features and limitations. Make sure that you - look at the log, especially if the patch buildbot did not give you - the green blob. - - -.. _section-git-checkout: - -Checking Out Tickets --------------------- - -Trac tickets that are finished or in the process of being worked on -can have a git branch attached to them. This is the "Branch:" field in -the ticket description. The branch name is generally of the form -``u/user/description``, where ``user`` is the name of the user who -made the branch and ``description`` is some free-form short -description (and can include further slashes). - -If you want to work with the changes in that remote branch, you must -make a local copy. In particular, git has no concept of directly -working with the remote branch, the remotes are only bookmarks for -things that you can get from/to the remote server. Hence, the first -thing you should do is to get everything from the trac server's branch -into your local repository. This is achieved by:: - - [user@localhost sage]$ git fetch trac u/user/description - remote: Counting objects: 62, done. - remote: Compressing objects: 100% (48/48), done. - remote: Total 48 (delta 42), reused 0 (delta 0) - Unpacking objects: 100% (48/48), done. - From trac.sagemath.org:sage - * [new branch] u/user/description -> FETCH_HEAD - -The ``u/user/description`` branch is now temporarily (until you fetch -something else) stored in your local git database under the alias -``FETCH_HEAD``. In the second step, we make it available as a new -local branch and switch to it. Your local branch can have a different -name, for example:: - - [user@localhost sage]$ git checkout -b my_branch FETCH_HEAD - Switched to a new branch 'my_branch' - -creates a new branch in your local git repository named ``my_branch`` -and modifies your local Sage filesystem tree to the state of the files -in that ticket. You can now edit files and commit changes to your -local branch. - - -.. _section-git-push: - -Pushing Your Changes to a Ticket --------------------------------- - -To add your local branch to a trac ticket, you should first decide on -a name on the Sage trac repository. - -For read/write permissions on git branches, see -:ref:`section-git_trac-branch-names` - -In order to avoid name clashes, you can use -``u/your_username/a_description_of_your_branch`` (the description can contain -slashes, but no spaces). Then: - -- **Fill** the ``Branch`` field of the trac ticket with that name. - -- **Push** your branch to trac with either:: - - [user@localhost sage]$ git push --set-upstream trac HEAD:u/user/description - - if you started the branch yourself and do not follow any other branch, - or use:: - - [user@localhost sage]$ git push trac HEAD:u/user/description - - if your branch already has an upstream branch. - -Here, ``HEAD`` means that you are pushing the most recent commit (and, by -extension, all of its parent commits) of the current local branch to the remote -branch. - -The ``Branch`` field on the trac ticket can appear in red/green. See -:ref:`section-trac-fields` to learn what it means. - - -.. _section-git-pull: - -Getting Changes ---------------- - -A common task during development is to synchronize your local copy of -the branch with the branch on trac. In particular, assume you -downloaded somebody else's branch and made some suggestions for -improvements on the trac ticket. Now the original author incorporated -your suggestions into his branch, and you want to get the added -changesets to complete your review. Assuming that you originally got -your local branch as in :ref:`section-git-checkout`, you can just -issue:: - - [user@localhost sage]$ git pull trac u/user/description - From trac.sagemath.org:sage - * branch u/user/description -> FETCH_HEAD - Updating 8237337..07152d8 - Fast-forward - src/sage/tests/cmdline.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletions(-) - -where now ``user`` is the other developer's trac username and -``description`` is some description that he chose. This command will -download the changes from the originally-used remote branch and merge -them into your local branch. If you haven't published your local -commits yet then you can also rebase them via:: - - [user@localhost sage]$ git pull -r trac u/user/description - From trac.sagemath.org:sage - * branch u/user/description -> FETCH_HEAD - First, rewinding head to replay your work on top of it... - Applying: my local commit - -See :ref:`section-git-merge` section for an in-depth explanation of -merge vs. rebase. - -So far, we assumed that there are no conflicts. It is unavoidable in -distributed development that, sometimes, the same location in a source -source file is changed by more than one person. Reconciling these -conflicting edits is explained in the :ref:`section-git_trac-conflict` -section. - - -.. _section-git-pull-master: - -Updating Master ---------------- - -The ``master`` branch can be updated just like any other branch. However, your -local copy of the master branch should stay **identical** to the trac master -branch. - -If you accidentally added commits to your local copy of ``master``, you must -delete them before updating the branch. - -One way to ensure that you are notified of potential problems is to use ``git -pull --ff-only``, which will raise an error if a non-trivial merge would be -required:: - - [user@localhost sage]$ git checkout master - [user@localhost sage]$ git pull --ff-only trac master - -If this pull fails, then something is wrong with the local copy of the -master branch. To switch to the correct Sage master branch, use:: - - [user@localhost sage]$ git checkout master - [user@localhost sage]$ git reset --hard trac/master - - -.. _section-git-merge: - -Merging and Rebasing -==================== - -Sometimes, a new version of Sage is released while you work on a git branch. - -Let us assume you started ``my_branch`` at commit ``B``. After a while, your -branch has advanced to commit ``Z``, but you updated ``master`` (see -:ref:`section-git-pull-master`) and now your git history looks like this (see -:ref:`section_walkthrough_logs`): - -.. CODE-BLOCK:: text - - X---Y---Z my_branch - / - A---B---C---D master - -How should you deal with such changes? In principle, there are two ways: - - -* **Rebase:** The first solution is to **replay** commits ``X,Y,Z`` atop of the - new ``master``. This is called **rebase**, and it rewrites your current - branch: - - .. CODE-BLOCK:: text - - git checkout my_branch - git rebase -i master - - In terms of the commit graph, this results in: - - .. CODE-BLOCK:: text - - X'--Y'--Z' my_branch - / - A---B---C---D master - - Note that this operation rewrites the history of ``my_branch`` (see - :ref:`section-git-rewriting-history`). This can lead to problems if somebody - began to write code atop of your commits ``X,Y,Z``. It is safe otherwise. - - **Alternatively**, you can rebase ``my_branch`` while updating master at the - same time (see :ref:`section-git-pull`): - - .. CODE-BLOCK:: text - - git checkout my_branch - git pull -r master - -* **Merging** your branch with ``master`` will create a new commit above the two - of them: - - .. CODE-BLOCK:: text - - git checkout my_branch - git merge master - - The result is the following commit graph: - - .. CODE-BLOCK:: text - - X---Y---Z---W my_branch - / / - A---B---C-------D master - - - **Pros:** you did not rewrite history (see - :ref:`section-git-rewriting-history`).The additional commit is then easily - pushed to the git repository and distributed to your collaborators. - - - **Cons:** it introduced an extra merge commit that would - not be there had you used rebase. - - **Alternatively**, you can merge ``my_branch`` while updating master at the - same time (see :ref:`section-git-pull`): - - .. CODE-BLOCK:: text - - git checkout my_branch - git pull master - -**In case of doubt** use merge rather than rebase. There is less risk involved, -and rebase in this case is only useful for branches with a very long history. - -Finally, **do nothing unless necessary:** it is perfectly fine for your branch -to be behind ``master``. You can always merge/rebase if/when your branch's name -appears in red on its trac page (see :ref:`section-trac-fields`), or when you -will really need a feature that is only available in the current master. - -.. _section-git-mergetool: - -Merge Tools -=========== - -Simple conflicts can be easily solved with git only (see :ref:`section-git_trac-conflict`) - -For more complicated ones, a range of specialized programs are -available. Because the conflict marker includes the hash of the most recent -common parent, you can use a three-way diff:: - - [alice@laptop]$ git mergetool - - This message is displayed because 'merge.tool' is not configured. - See 'git mergetool --tool-help' or 'git help config' for more details. - 'git mergetool' will now attempt to use one of the following tools: - meld opendiff kdiff3 [...] merge araxis bc3 codecompare emerge vimdiff - Merging: - fibonacci.py - - Normal merge conflict for 'fibonacci.py': - {local}: modified file - {remote}: modified file - Hit return to start merge resolution tool (meld): - -If you don't have a favourite merge tool we suggest you try `meld -<http://meldmerge.org/>`_ (cross-platform). The result looks like the following -screenshot. - -.. IMAGE:: static/meld-screenshot.png - -The middle file is the most recent common parent; on the right is -Bob's version and on the left is Alice's conflicting version. Clicking -on the arrow moves the marked change to the file in the adjacent -pane. diff --git a/src/doc/en/developer/packaging.rst b/src/doc/en/developer/packaging.rst index 8f084b38ff6..9f8bd2528ef 100644 --- a/src/doc/en/developer/packaging.rst +++ b/src/doc/en/developer/packaging.rst @@ -2,9 +2,9 @@ .. _chapter-packaging: -========================== -Packaging Third-Party Code -========================== +=================================== +Packaging Third-Party Code for Sage +=================================== One of the mottoes of the Sage project is to not reinvent the wheel: If an algorithm is already implemented in a well-tested library then @@ -14,7 +14,7 @@ The installation of packages is done through a bash script located in ``SAGE_ROOT/build/bin/sage-spkg``. This script is typically invoked by giving the command:: - [user@localhost]$ sage -i <options> <package name>... + [alice@localhost sage]$ sage -i <options> <package name>... options can be: @@ -140,7 +140,7 @@ and if it does not, then it is a ``dummy`` package. .. _section-directory-structure: -Directory Structure +Directory structure =================== Third-party packages in Sage consist of two parts: @@ -546,7 +546,7 @@ possible. .. _section-spkg-check: -Self-Tests +Self-tests ---------- The ``spkg-check.in`` file is an optional, but highly recommended, @@ -622,13 +622,13 @@ For example: # gentoo uses 3.2.1 sphinx >=3, <3.3 -The comments may include links to Trac tickets, as in the following example: +The comments may include links to GitHub Issues/PRs, as in the following example: .. CODE-BLOCK:: bash $ cat build/pkgs/packaging/install-requires.txt packaging >=18.0 - # Trac #30975: packaging 20.5 is known to work but we have to silence "DeprecationWarning: Creating a LegacyVersion" + # Issue #30975: packaging 20.5 is known to work but we have to silence "DeprecationWarning: Creating a LegacyVersion" The currently encoded version constraints are merely a starting point. Developers and downstream packagers are invited to refine the version @@ -641,7 +641,7 @@ a complex topic; see :trac:`33520`. .. _section-spkg-SPKG-txt: -The SPKG.rst File +The SPKG.rst file ----------------- The ``SPKG.rst`` file should follow this pattern: @@ -757,7 +757,7 @@ should be declared in a separate file ``dependencies_optional``. In order to check that the dependencies of your package are likely correct, the following command should work without errors:: - [user@localhost]$ make distclean && make base && make PACKAGE_NAME + [alice@localhost sage]$ make distclean && make base && make PACKAGE_NAME Finally, note that standard packages should only depend on standard packages and optional packages should only depend on standard or @@ -808,7 +808,7 @@ word ``SAGE_DOCS``. .. _section-spkg-patching: -Patching Sources +Patching sources ---------------- Actual changes to the source code must be via patches, which should be placed @@ -957,7 +957,7 @@ We recommend the following workflow for maintaining a set of patches. commands. - When a new upstream version becomes available, merge (or import) it - into ``upstream``, then create a new branch and rebase in on top of + into ``upstream``, then create a new branch and rebase it on top of the updated upstream: .. CODE-BLOCK:: bash @@ -971,7 +971,7 @@ We recommend the following workflow for maintaining a set of patches. .. _section-spkg-src: -Modified Tarballs +Modified tarballs ----------------- The ``spkg-src`` file is optional and only to document how the upstream @@ -986,7 +986,7 @@ to apply the same modifications to future versions. .. _section-spkg-versioning: -Package Versioning +Package versioning ------------------ The ``package-version.txt`` file contains just the version. So if @@ -1019,7 +1019,7 @@ account. .. _section-spkg-checksums: -Checksums and Tarball Names +Checksums and tarball names --------------------------- The ``checksums.ini`` file contains the filename pattern of the @@ -1034,7 +1034,7 @@ upstream is ``$SAGE_ROOT/upstream/FoO-1.3.tar.gz``, create a new file Sage internally replaces the ``VERSION`` substring with the content of ``package-version.txt``. To recompute the checksums, run:: - [user@localhost]$ sage --package fix-checksum foo + [alice@localhost sage]$ sage --package fix-checksum foo which will modify the ``checksums.ini`` file with the correct checksums. @@ -1048,11 +1048,11 @@ In addition to these fields in ``checksums.ini``, the optional field The Release Manager uses the information in ``upstream_url`` to download the upstream package archive and to make it available on the -Sage mirrors when a new release is prepared. On Trac tickets -upgrading a package, the ticket description should no longer contain +Sage mirrors when a new release is prepared. On GitHub PRs +upgrading a package, the PR description should no longer contain the upstream URL to avoid duplication of information. -Note that, like the ``tarball`` field, the ``upstream_url`` is a +Note that, like the ``tarball`` field, the ``tpstream_url`` is a template; the substring ``VERSION`` is substituted with the actual version. @@ -1066,20 +1066,20 @@ For Python packages available from PyPI, you should use an A package that has the ``upstream_url`` information can be updated by simply typing:: - [user@localhost]$ sage --package update numpy 3.14.59 + [alice@localhost sage]$ sage --package update numpy 3.14.59 which will automatically download the archive and update the information in ``build/pkgs/``. For Python packages available from PyPI, there is another shortcut:: - [user@localhost]$ sage --package update-latest matplotlib + [alice@localhost sage]$ sage --package update-latest matplotlib Updating matplotlib: 3.3.0 -> 3.3.1 Downloading tarball to ...matplotlib-3.3.1.tar.bz2 [...............................................................] The ``upstream_url`` information serves yet another purpose. -Developers who wish to test a package update from a Trac branch before +Developers who wish to test a package update from a PR branch before the archive is available on a Sage mirror can do so by configuring their Sage tree using ``./configure --enable-download-from-upstream-url``. Then Sage will fall back to @@ -1095,7 +1095,7 @@ Utility script to create packages Assuming that you have downloaded ``$SAGE_ROOT/upstream/FoO-1.3.tar.gz``, you can use:: - [user@localhost]$ sage --package create foo --version 1.3 --tarball FoO-VERSION.tar.gz --type experimental + [alice@localhost sage]$ sage --package create foo --version 1.3 --tarball FoO-VERSION.tar.gz --type experimental to create ``$SAGE_ROOT/build/pkgs/foo/package-version.txt``, ``checksums.ini``, and ``type`` in one step. @@ -1106,7 +1106,7 @@ set the ``upstream_url`` field in ``checksums.ini`` described above. For Python packages available from PyPI, you can use:: - [user@localhost]$ sage --package create scikit_spatial --pypi --type optional + [alice@localhost sage]$ sage --package create scikit_spatial --pypi --type optional This automatically downloads the most recent version from PyPI and also obtains most of the necessary information by querying PyPI. @@ -1117,11 +1117,11 @@ in the file ``install-requires.txt``. To create a pip package rather than a normal package, you can use:: - [user@localhost]$ sage --package create scikit_spatial --pypi --source pip --type optional + [alice@localhost sage]$ sage --package create scikit_spatial --pypi --source pip --type optional To create a wheel package rather than a normal package, you can use:: - [user@localhost]$ sage --package create scikit_spatial --pypi --source wheel --type optional + [alice@localhost sage]$ sage --package create scikit_spatial --pypi --source wheel --type optional .. _section-manual-build: @@ -1137,29 +1137,29 @@ in the ``SAGE_ROOT/upstream/`` directory and run Now you can install the package using:: - [user@localhost]$ sage -i package_name + [alice@localhost sage]$ sage -i package_name or:: - [user@localhost]$ sage -f package_name + [alice@localhost sage]$ sage -f package_name to force a reinstallation. If your package contains a ``spkg-check`` script (see :ref:`section-spkg-check`) it can be run with:: - [user@localhost]$ sage -i -c package_name + [alice@localhost sage]$ sage -i -c package_name or:: - [user@localhost]$ sage -f -c package_name + [alice@localhost sage]$ sage -f -c package_name -If all went fine, open a ticket, put a link to the original tarball in -the ticket and upload a branch with the code under +If all went fine, open a PR, put a link to the original tarball in +the PR and upload a branch with the code under ``SAGE_ROOT/build/pkgs``. .. _section-inclusion-procedure: -Inclusion Procedure for New and Updated Packages +Inclusion procedure for new and updated packages ================================================ Packages that are not part of Sage will first become optional or @@ -1168,22 +1168,22 @@ systems). After they have been in optional for some time without problems they can be proposed to be included as standard packages in Sage. -To propose a package for optional/experimental inclusion please open a -trac ticket with the respective ``Component:`` field set to either -``packages:experimental`` or ``packages:optional``. The associated code -requirements are described in the following sections. +To propose a package for optional/experimental inclusion please open a GitHub +PR added with labels ``c: packages: experimental`` or ``c: packages: +optional``. The associated code requirements are described in the following +sections. -After the ticket was reviewed and included, optional packages stay in +After the PR was reviewed and included, optional packages stay in that status for at least a year, after which they can be proposed to be -included as standard packages in Sage. For this a trac ticket is opened -with the ``Component:`` field set to ``packages:standard``. Then make +included as standard packages in Sage. For this a GitHub PR is opened +with the label ``c: packages: standard``. Then make a proposal in the Google Group ``sage-devel``. Upgrading packages to new upstream versions or with additional patches -includes opening a ticket in the respective category too, as described +includes opening a PR in the respective category too, as described above. -License Information +License information ------------------- If you are patching a standard Sage spkg, then you should make sure that @@ -1204,7 +1204,7 @@ be a good solution to make a custom tarball consisting of only the free parts; see :ref:`section-spkg-src` and the ``giac`` package as an example. -Prerequisites for New Standard Packages +Prerequisites for new standard packages --------------------------------------- For a package to become part of Sage's standard distribution, it @@ -1245,6 +1245,6 @@ must meet the following requirements: this is not possible. - **Refereeing**. The code must be refereed, as discussed in - :ref:`chapter-sage-trac`. + :ref:`chapter-github`. diff --git a/src/doc/en/developer/packaging_sage_library.rst b/src/doc/en/developer/packaging_sage_library.rst index 7e7a5cde56f..abda71bbed8 100644 --- a/src/doc/en/developer/packaging_sage_library.rst +++ b/src/doc/en/developer/packaging_sage_library.rst @@ -1,9 +1,9 @@ .. _chapter-modularization: -============================ - Packaging the Sage Library -============================ +=========================================== +Packaging the Sage Library for Distribution +=========================================== Modules, packages, distribution packages @@ -167,7 +167,7 @@ The source directory of a distribution package, such as the current development release is ``9.7.beta8``, then such a version could be marked ``9.7.beta8.post1``. - Also sometimes when working on tickets it may be necessary to + Also sometimes when working on PRs it may be necessary to increment the version because a new feature is needed in another distribution package. Such versions should be marked by using the version number of the anticipated next development release and @@ -178,7 +178,7 @@ The source directory of a distribution package, such as use ``9.7.beta9.dev1``. If the current development release is the stable release ``9.8``, use ``9.9.beta0.dev1``. - After the ticket is merged in the next development version, it will + After the PR is merged in the next development version, it will be synchronized again with the other package versions. - ``setup.py`` -- a `setuptools <https://pypi.org/project/setuptools/>`_-based @@ -536,21 +536,28 @@ Not shown in the diagram are build dependencies and optional dependencies for te the Sage doctester (:mod:`sage.doctest`), and some related modules from :mod:`sage.misc`. +.. _section-modularized-doctesting: + Testing distribution packages ============================= Of course, we need tools for testing modularized distributions of portions of the Sage library. -- Modularized distributions must be testable separately! +- Distribution packages of the modularized Sage library must be testable separately! - But we want to keep integration testing with other portions of Sage too! -Preparing doctests ------------------- +Preparing doctests for modularized testing +------------------------------------------ + +Section :ref:`section-doctest-writing` explains how to write doctests +for Sage. Here we show how to prepare existing or new doctests so that +they are suitable for modularized testing. -Whenever an optional package is needed for a particular test, we use the -doctest annotation ``# optional``. This mechanism can also be used for making a +Per section :ref:`section-further_conventions`, +whenever an optional package is needed for a particular test, we use the +doctest tag ``# optional``. This mechanism can also be used for making a doctest conditional on the presence of a portion of the Sage library. The available tags take the form of package or module names such as @@ -564,34 +571,44 @@ hints to the user. For example, the package :mod:`sage.tensor` is purely algebraic and has no dependency on symbolics. However, there are a small number of doctests that depend on :class:`sage.symbolic.ring.SymbolicRing` for integration -testing. Hence, these doctests are marked ``# optional - -sage.symbolic``. +testing. Hence, these doctests are marked as depending on the feature +:class:`sage.symbolic <~sage.features.sagemath.sage__symbolic>`. + +By convention, because :class:`sage.symbolic <~sage.features.sagemath.sage__symbolic>` +is present in a standard installation of Sage, we use the keyword ``# needs`` +instead of ``# optional``. These two keywords have identical semantics; +the tool :ref:`sage --fixdoctests <section-fixdoctests-optional-needs>` +rewrites the doctest tags according to the convention. + +When defining new features for the purpose of conditionalizing doctests, it may be a good +idea to hide implementation details from feature names. For example, all doctests that +use large finite fields have to depend on PARI. However, we have defined a feature +:mod:`sage.rings.finite_rings` (which implies the presence of :mod:`sage.libs.pari`). +Marking the doctests ``# needs sage.rings.finite_rings`` expresses the +dependency in a clearer way than using ``# needs sage.libs.pari``, and it +will be a smaller maintenance burden when implementation details change. + Testing the distribution in virtual environments with tox --------------------------------------------------------- -So how to test that this works? - -Sure, we could go into the installation directory -``SAGE_VENV/lib/python3.9/site-packages/`` and do ``rm -rf -sage/symbolic`` and test that things still work. But that's not a good -way of testing. +Chapter :ref:`chapter-doctesting` explains in detail how to run the +Sage doctester with various options. -Instead, we use a virtual environment in which we only install the +To test a distribution package of the modularized Sage library, +we use a virtual environment in which we only install the distribution to be tested (and its Python dependencies). Let's try it out first with the entire Sage library, represented by the distribution **sagemath-standard**. Note that after Sage has been -built normally, a set of wheels for all installed Python packages is -available in ``SAGE_VENV/var/lib/sage/wheels/``:: +built normally, a set of wheels for most installed Python distribution +packages is available in ``SAGE_VENV/var/lib/sage/wheels/``:: $ ls venv/var/lib/sage/wheels Babel-2.9.1-py2.py3-none-any.whl Cython-0.29.24-cp39-cp39-macosx_11_0_x86_64.whl Jinja2-2.11.2-py2.py3-none-any.whl ... - sage_conf-9.5b6-py3-none-any.whl - ... scipy-1.7.2-cp39-cp39-macosx_11_0_x86_64.whl setuptools-58.2.0-py3-none-any.whl ... @@ -599,6 +616,22 @@ available in ``SAGE_VENV/var/lib/sage/wheels/``:: widgetsnbextension-3.5.1-py2.py3-none-any.whl zipp-3.5.0-py3-none-any.whl +However, in a build of Sage with the default configuration +``configure --enable-editable``, there will be no wheels for the +distributions ``sage_*`` and ``sagemath-*``. + +To create these wheels, use the command ``make wheels``:: + + $ make wheels + ... + $ ls venv/var/lib/sage/wheels/sage* + ... + sage_conf-10.0b2-py3-none-any.whl + ... + +(You can also use ``./configure --enable-wheels`` to ensure that +these wheels are always available and up to date.) + Note in particular the wheel for **sage-conf**, which provides configuration variable settings and the connection to the non-Python packages installed in ``SAGE_LOCAL``. @@ -618,7 +651,7 @@ command:: This command does not make any changes to the normal installation of Sage. The virtual environment is created in a subdirectory of -``SAGE_ROOT/pkgs/sagemath-standard-no-symbolics/.tox/``. After the command +``SAGE_ROOT/pkgs/sagemath-standard/.tox/``. After the command finishes, we can start the separate installation of the Sage library in its virtual environment:: @@ -632,14 +665,14 @@ The whole ``.tox`` directory can be safely deleted at any time. We can do the same with other distributions, for example the large distribution **sagemath-standard-no-symbolics** -(from :trac:`32601`), which is intended to provide +(from :trac:`35095`), which is intended to provide everything that is currently in the standard Sage library, i.e., without depending on optional packages, but without the packages -:mod:`sage.symbolic`, :mod:`sage.functions`, :mod:`sage.calculus`, etc. +:mod:`sage.symbolic`, :mod:`sage.calculus`, etc. Again we can run the test with ``tox`` in a separate virtual environment:: - $ ./bootstrap && ./sage -sh -c '(cd pkgs/sagemath-standard-no-symbolics && SAGE_NUM_THREADS=16 tox -v -v -v -e sagepython-sagewheels-nopypi)' + $ ./bootstrap && make wheels && ./sage -sh -c '(cd pkgs/sagemath-standard-no-symbolics && SAGE_NUM_THREADS=16 tox -v -v -v -e sagepython-sagewheels-nopypi-norequirements)' Some small distributions, for example the ones providing the two lowest levels, `sagemath-objects <https://pypi.org/project/sagemath-objects/>`_ @@ -659,4 +692,4 @@ Building these small distributions serves as a valuable regression testsuite. However, a current issue with both of these distributions is that they are not separately testable: The doctests for these modules depend on a lot of other functionality from higher-level parts -of the Sage library. +of the Sage library. This is being addressed in :issue:`35095`. diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index f1a3e5c49fa..b95bb7b5ab7 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -5,7 +5,7 @@ .. _chapter-portability_testing: ============================= -Testing on multiple platforms +Testing on Multiple Platforms ============================= Sage is intended to build and run on a variety of platforms, @@ -18,12 +18,13 @@ machines, it is crucial to test changes to Sage, in particular when external packages are added or upgraded, on a wide spectrum of platforms. -Sage patchbots +GitHub actions ============== -The `Sage patchbots <https://wiki.sagemath.org/patchbot>`_ will -automatically test your Trac ticket by attempting an incremental build -of Sage and running doctests. +The `GitHub Actions +<https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions>`_ +will automatically test your GitHub PR by attempting an incremental build of +Sage and running doctests. Sage buildbots ============== @@ -308,7 +309,7 @@ several developers can work on fixing the bug using containers running on their respective machines. -Generating Dockerfiles +Generating dockerfiles ---------------------- Sage also provides a script for generating a ``Dockerfile``, which is @@ -651,7 +652,7 @@ packages instead of all of Sage, for example:: [mkoeppe@sage sage]$ tox -e docker-centos-8-standard -- ratpoints If the build succeeds, this will create a new image named -``sage-docker-centos-8-standard-with-targets:9.1.beta9-431-gca4b5b2f33-dirty``, +``sage-centos-8-standard-with-targets:9.1.beta9-431-gca4b5b2f33-dirty``, where - the image name is derived from the tox environment name and the @@ -676,22 +677,22 @@ the one just after running the ``configure`` script (``configured``):: Step 109/109 : RUN yum install -y zlib-devel || echo "(ignoring error)" ... Successfully built 4bb14c3d5646 - Successfully tagged sage-docker-centos-8-standard-with-system-packages:9.1.beta9-435-g861ba33bbc-dirty + Successfully tagged sage-centos-8-standard-with-system-packages:9.1.beta9-435-g861ba33bbc-dirty Sending build context to Docker daemon ... ... - Successfully tagged sage-docker-centos-8-standard-configured:9.1.beta9-435-g861ba33bbc-dirty + Successfully tagged sage-centos-8-standard-configured:9.1.beta9-435-g861ba33bbc-dirty ... Sending build context to Docker daemon ... ... - Successfully tagged sage-docker-centos-8-standard-with-targets:9.1.beta9-435-g861ba33bbc-dirty + Successfully tagged sage-centos-8-standard-with-targets:9.1.beta9-435-g861ba33bbc-dirty Let's verify that the images are available:: (base) egret:~/s/sage/sage-rebasing/worktree-algebraic-2018-spring (mkoeppe *$%>)$ docker images | head REPOSITORY TAG IMAGE ID - sage-docker-centos-8-standard-with-targets 9.1.beta9-435-g861ba33bbc-dirty 7ecfa86fceab - sage-docker-centos-8-standard-configured 9.1.beta9-435-g861ba33bbc-dirty 4314929e2b4c - sage-docker-centos-8-standard-with-system-packages 9.1.beta9-435-g861ba33bbc-dirty 4bb14c3d5646 + sage-centos-8-standard-with-targets 9.1.beta9-435-g861ba33bbc-dirty 7ecfa86fceab + sage-centos-8-standard-configured 9.1.beta9-435-g861ba33bbc-dirty 4314929e2b4c + sage-centos-8-standard-with-system-packages 9.1.beta9-435-g861ba33bbc-dirty 4bb14c3d5646 ... @@ -949,49 +950,70 @@ Automatic testing on multiple platforms on GitHub Actions ========================================================= The Sage source tree includes a default configuration for GitHub -Actions that runs our portability tests with tox on a multitude of -platforms on every pull request and on every push of a tag (but not of -a branch) to a repository for which GitHub Actions are enabled. +Actions that runs our portability tests on a multitude of platforms on +every push of a tag (but not of a branch) to a repository for which +GitHub Actions are enabled. -In particular, it automatically runs on our main repository on every -release tag. +In particular, it automatically runs on our main repository sagemath/sage +on every release tag. -This is defined in the files `$SAGE_ROOT/.github/workflows/tox*.yml -<https://github.com/sagemath/sage/tree/develop/.github/workflows/tox.yml>`_. +This is defined in the files -An additional GitHub Actions workflow for testing on Cygwin, not based -on tox, is defined in the files -`$SAGE_ROOT/.github/workflows/ci-cygwin*.yml -<https://github.com/sagemath/sage/tree/develop/.github/workflows/ci-cygwin-standard.yml>`_. +- `$SAGE_ROOT/.github/workflows/ci-linux.yml + <https://github.com/sagemath/sage/tree/develop/.github/workflows/ci-linux.yml>`_ + (which calls `$SAGE_ROOT/.github/workflows/docker.yml + <https://github.com/sagemath/sage/tree/develop/.github/workflows/docker.yml>`_), + +- `$SAGE_ROOT/.github/workflows/ci-macos.yml + <https://github.com/sagemath/sage/tree/develop/.github/workflows/ci-macos.yml>`_, and + +- `$SAGE_ROOT/.github/workflows/ci-cygwin-standard.yml + <https://github.com/sagemath/sage/tree/develop/.github/workflows/ci-cygwin-standard.yml>`_ + (which calls `$SAGE_ROOT/.github/workflows/cygwin.yml + <https://github.com/sagemath/sage/tree/develop/.github/workflows/cygwin.yml>`_). GitHub Actions runs these build jobs on 2-core machines with 7 GB of RAM memory and 14 GB of SSD disk space, cf. `here <https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners#supported-runners-and-hardware-resources>`_, -and has a time limit of 6h per job. This is just barely enough for a -typical ``minimal`` build followed by ``make ptest`` to succeed; and -plenty of time for a typical ``standard`` build to succeed. +and has a time limit of 6h per job. This could be just barely enough for a +typical ``minimal`` build followed by ``make ptest`` to succeed; for +added robustness, we split it into two jobs. Our workflow stores +Docker images corresponding to various build phases within these two +jobs on `GitHub Packages <https://github.com/features/packages>`_ (ghcr.io). + +Build logs can be inspected during the run and become available as +"artifacts" when all jobs of the workflow have finished. Each job +generates one tarball. "Annotations" highlight certain top-level +errors or warnings issued during the build. + +In addition to these automatic runs in our main repository, all Sage +developers can run the same tests on GitHub Actions in their personal +forks of the Sage repository. To prepare this, `enable GitHub Actions <https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#managing-github-actions-permissions-for-your-repository>`_ +in your fork of the Sage repository. + +As usual we assume that ``origin`` is the name of the remote +corresponding to your GitHub fork of the Sage repository:: + + $ git remote -v | grep origin + origin https://github.com/mkoeppe/sage.git (fetch) + origin https://github.com/mkoeppe/sage.git (push) -Build logs become available as "artifacts" when all jobs of the -workflow have finished. Each job generates one tarball. -"Annotations" highlight certain top-level errors or warnings issued -during the build. +Then the following procedure triggers a run of tests with the default set +of system configurations. -The following procedure triggers a run of tests with the default set of -system configurations. +- Push your branch to ``origin`` (your fork). -- Push your changes to trac. -- Go to the `Actions page on the GitHub mirror <https://github.com/sagemath/sagetrac-mirror/actions>`_ and select the workflow you would like to run. -- Click on "Run workflow" above the list of workflow runs and select the branch where the workflow will run. +- Go to the Actions tab of your fork and select the workflow you would like to run, + for example "CI Linux". -For more information, see the `GitHub documentation <https://docs.github.com/en/free-pro-team@latest/actions/managing-workflow-runs/manually-running-a-workflow>`_. +- Click on "Run workflow" above the list of workflow runs and select + your branch as the branch on which the workflow will run. -Alternatively, you can create and push a custom tag in order to trigger a run of tests as follows. -Let's assume that ``my-github`` is the name of -the remote corresponding to your GitHub fork of the Sage repository:: +For more information, see the `GitHub documentation +<https://docs.github.com/en/free-pro-team@latest/actions/managing-workflow-runs/manually-running-a-workflow>`_. - $ git remote -v | grep /my-github - my-github https://github.com/mkoeppe/sage.git (fetch) - my-github https://github.com/mkoeppe/sage.git (push) +Alternatively, you can trigger a run of tests by creating and pushing +a custom tag as follows. - Create a ("lightweight", not "annotated") tag with an arbitrary name, say ``ci`` (for "Continuous Integration"):: @@ -1000,28 +1022,13 @@ the remote corresponding to your GitHub fork of the Sage repository:: - Then push the tag to your GitHub repository:: - git push -f my-github ci + git push -f origin ci (In both commands, the "force" option (``-f``) allows overwriting a previous tag of that name.) -For testing branches against a custom set of system configurations -during development, the following procedure seems to work well. It -avoids changing the CI configuration on your development branch: - -- Create a branch from a recent beta release that contains the default - GitHub Actions configuration; name it ``TESTER``, say. - -- Edit ``$SAGE_ROOT/.github/workflows/tox.yml`` to include the system - config you wish to test. - -- Commit and push the branch to your GitHub fork of sage. - -- Push your development branch to your GitHub repository and create a - pull request against the ``TESTER`` branch. This will trigger the - GitHub Actions workflow. - -You will find a workflow status page in the "Actions" tab of your +Either way, when the workflow has been triggered, you can inspect it +by using the workflow status page in the "Actions" tab of your repository. Here is how to read it. Each of the items in the left pane represents @@ -1029,7 +1036,7 @@ a full build of Sage on a particular system configuration. A test item in the left pane is marked with a green checkmark in the left pane if ``make build doc-html`` finished without error. (It also runs package testsuites and the Sage doctests but failures in these are not -in reflected in the left pane; see below.) +reflected in the left pane; see below.) The right pane ("Artifacts") offers archives of the logs for download. @@ -1055,7 +1062,7 @@ Scrolling down in the right pane shows "Annotations": docker (fedora-31, standard) artifacts/logs-commit-8ca1c2df8f1fb4c6d54b44b34b4d8320ebecb164-tox-docker-fedora-31-standard/config.log#L1 - configure: notice: the following SPKGs did not find equivalent system packages: arb cbc cddlib cmake eclib ecm fflas_ffpack flint flintqs fplll givaro gp + configure: notice: the following SPKGs did not find equivalent system packages: arb cbc cddlib cmake eclib ecm fflas_ffpack flint fplll givaro gp Clicking on the annotations does not take you to a very useful place. To view details, click on one of the items in the pane. This @@ -1082,8 +1089,8 @@ where you replace the token by your token, of course, and Now you can pull the image and run it:: - $ docker pull ghcr.io/YOUR-GITHUB-USERNAME/sage/sage-docker-fedora-31-standard-configured:f4bd671 - $ docker run -it ghcr.io/YOUR-GITHUB-USERNAME/sage/sage-docker-fedora-31-standard-configured:f4bd671 bash + $ docker pull ghcr.io/YOUR-GITHUB-USERNAME/sage/sage-fedora-31-standard-configured:f4bd671 + $ docker run -it ghcr.io/YOUR-GITHUB-USERNAME/sage/sage-fedora-31-standard-configured:f4bd671 bash Using our pre-built Docker images published on ghcr.io @@ -1101,19 +1108,19 @@ the build logs for a given platform. The image version corresponding to the latest development release receives the additional Docker tag ``dev``, see for example the Docker image for the platform `ubuntu-focal-standard -<https://github.com/sagemath/sage/pkgs/container/sage%2Fsage-docker-ubuntu-focal-standard-with-targets-optional>`_. Thus, +<https://github.com/sagemath/sage/pkgs/container/sage%2Fsage-ubuntu-focal-standard-with-targets-optional>`_. Thus, for example, the following command will work:: - $ docker run -it ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional:dev bash - Unable to find image 'ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional:dev' locally - dev: Pulling from sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional + $ docker run -it ghcr.io/sagemath/sage/sage-ubuntu-focal-standard-with-targets-optional:dev bash + Unable to find image 'ghcr.io/sagemath/sage/sage-ubuntu-focal-standard-with-targets-optional:dev' locally + dev: Pulling from sagemath/sage/sage-ubuntu-focal-standard-with-targets-optional d5fd17ec1767: Already exists 67586203f0c7: Pull complete b63c529f4777: Pull complete ... 159775d1a3d2: Pull complete Digest: sha256:e6ba5e12f59c6c4668692ef4cfe4ae5f242556482664fb347bf260f32bf8e698 - Status: Downloaded newer image for ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional:dev + Status: Downloaded newer image for ghcr.io/sagemath/sage/sage-ubuntu-focal-standard-with-targets-optional:dev root@8055a7ba0607:/sage# ./sage โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ SageMath version 9.6, Release Date: 2022-05-15 โ”‚ @@ -1127,7 +1134,7 @@ contain a copy of the source tree and the full logs of the build and test. Also `smaller images corresponding to earlier build stages -<https://github.com/orgs/sagemath/packages?tab=packages&q=sage-docker-debian-bullseye-standard>`_ +<https://github.com/orgs/sagemath/packages?tab=packages&q=sage-debian-bullseye-standard>`_ are available: * ``-with-system-packages`` provides a system installation with @@ -1145,6 +1152,58 @@ are available: ptest`` has not been run yet. +Testing GitHub Actions locally +============================== + +`act <https://github.com/nektos/act>`_ is a tool, written in Go, and using Docker, +to run GitHub Actions locally; in particular, it speeds up developing Actions. +We recommend using ``gh extension`` facility to install ``act``. :: + + [alice@localhost sage]$ gh extension install https://github.com/nektos/gh-act + +Extra steps needed for configuration of Docker to run Actions locally can be found on +`act's GitHub <https://github.com/nektos/act>`_ + +Here we give a very short sampling of ``act``'s capabilities. If you installed standalone +``act``, it should be invoked as ``act``, not as ``gh act``. +After the set up, one can e.g. list all the available linting actions:: + + [alice@localhost sage]$ gh act -l | grep lint + 0 lint-pycodestyle Code style check with pycodestyle Lint lint.yml push,pull_request + 0 lint-relint Code style check with relint Lint lint.yml push,pull_request + 0 lint-rst Validate docstring markup as RST Lint lint.yml push,pull_request + [alice@localhost sage]$ + +run a particular action ``lint-rst`` :: + + [alice@localhost sage]$ gh act -j lint-rst + ... + +and so on. + +By default, ``act`` pulls all the data needed from the next, but it can also cache it, +speeding up repeated runs quite a lot. The following repeats running of ``lint-rst`` using cached data:: + + [alice@localhost sage]$ gh act -p false -r -j lint-rst + [Lint/Validate docstring markup as RST] Start image=catthehacker/ubuntu:act-latest + ... + | rst: commands[0] /home/alice/work/software/sage/src> flake8 --select=RST + | rst: OK (472.60=setup[0.09]+cmd[472.51] seconds) + | congratulations :) (474.10 seconds) + ... + [Lint/Validate docstring markup as RST] Success - Main Lint using tox -e rst + [Lint/Validate docstring markup as RST] Run Post Set up Python + [Lint/Validate docstring markup as RST] docker exec cmd=[node /var/run/act/actions/actions-setup-python@v4/dist/cache-save/index.js] user= workdir= + [Lint/Validate docstring markup as RST] Success - Post Set up Python + [Lint/Validate docstring markup as RST] Job succeeded + +Here ``-p false`` means using already pulled Docker images, and ``-r`` means do not remove Docker images +after a successful run which used them. This, and many more details, can be found by running ``gh act -h``, as well +as reading ``act``'s documentation. + +.. This sectuion is a stub. + More Sage-specfic details for using ``act`` should be added. PRs welcome! + Using our pre-built Docker images for development in VS Code ============================================================ @@ -1174,7 +1233,7 @@ application, then in the command palette of VS Code, enter "Remote-Containers: Open Folder in Container", and hit :kbd:`Enter`, and choose the directory ``$SAGE_ROOT`` of your local Sage repository. -VS Code then prompts you to choose a dev container configuration. +VS Code then prompts you to choose a dev container configuration. For example, choose "Ubuntu jammy" `.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json <https://github.com/sagemath/sage/tree/develop/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json>`_, which uses the Docker image based on ``ubuntu-jammy-standard``, the most recent diff --git a/src/doc/en/developer/review.rst b/src/doc/en/developer/review.rst new file mode 100644 index 00000000000..44a9214b9fe --- /dev/null +++ b/src/doc/en/developer/review.rst @@ -0,0 +1,224 @@ +.. nodoctest + +.. _chapter-review: + +============== +Reviewing Code +============== + +All code that goes into Sage is peer-reviewed. Two reasons for this are: + +- Because a developer cannot think of everything at once +- Because a fresh pair of eyes may spot a mathematical error, + a corner-case in the code, insufficient documentation, a missing + consistency check, etc. + +Anybody (e.g. you) can do this job for somebody else's PR. This document +lists things that the reviewer must check before deciding that a PR is +ready for inclusion into Sage. + +You can now begin the review by reading the diff code. + +**Check the GitHub checks:** We require all checks have passed. + +**Read the diff:** Click "Files changed" tab of the PR. Read through the +changes of all modified files. We use `pull request reviews +<https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/about-pull-request-reviews>`_. +You can add comments directly to changed lines. + +**Build the code:** (This is optional if the **build and test** check has passed.) +While you read the code, you can :ref:`rebuild Sage with the new code +<section-walkthrough-make>`. If you do not know how to **download the code**, +:ref:`see here <section-workflows-pr-checkout>`. + +The following should generally be checked while reading and testing the code: + +- **The purpose**: Does the code address the PR's stated aim? Can it + introduce any new problems? Does testing the new or fixed functionality + with a variety of input, not just the examples in the documentation, + give expected and robust output (and no unexpected errors or crashes)? + +- **User documentation**: Is the use of the new code clear to a user? Are all + mathematical notions involved standard, or is there explanation (or a link + to one) provided? Can he/she find the new code easily if he/she needs it? + +- **Code documentation**: Is the code sufficiently commented so that a developer + does not have to wonder what exactly it does? + +- **Conventions**: Does the code respect :ref:`Sage's conventions + <chapter-code-basics>`? :ref:`Python's conventions <chapter-python>`? + :ref:`Cython's conventions <chapter-cython>`? + +- **Doctest coverage**: Do all functions contain doctests? Use ``sage -coverage + <files>`` to check it. Are all aspects of the new/modified methods and classes + tested (see :ref:`section-doctest-writing`)? + +- **Bugfixes**: If the PR contains a bugfix, does it add a doctest + illustrating that the bug has been fixed? This new doctest should contain the + issue or PR number, for example ``See :issue:`12345```. + +- **Speedup**: Can the PR make any existing code slower? if the PR + claims to speed up some computation, does the PR contain code examples to + illustrate the claim? The PR should explain how the speedup is achieved. + +- **Build the manuals**: Does the reference manual build without + errors (check both html and pdf)? See :ref:`chapter-sage_manuals` to + learn how to build the manuals. + +- **Look at the manuals**: Does the reference manual look okay? The + changes may have typos that allow the documentation to build without + apparent errors but that may cause badly formatted output or broken + hyperlinks. + +- **Run the tests**: Do all doctests pass without errors? Unrelated components + of Sage may be affected by the change. Check all tests in the whole library, + including "long" doctests (this can be done with ``make ptestlong``) and any + optional doctests related to the functionality. See :ref:`chapter-doctesting` + for more information. + +You are now ready to change the PR's status (see +:ref:`section-github-pr-status`): + +- **positive review**: If the answers to the questions above and other + reasonable questions are *"yes"*, you can set the PR to + ``positive review`` status. + +- **needs work**: If something is not as it should, write a list of all points + that need to be addressed in a comment and change the PR's status to + ``needs work`` status. + +- **needs info**: If something is not clear to you and prevents you from going + further with the review, ask your question and set the PR's status to + ``needs info`` status. + +- If you **do not know what to do**, for instance if you don't feel experienced + enough to take a final decision, explain what you already did in a comment and + ask if someone else could take a look. + +For more advice on reviewing, see `How to Referee Sage Trac Tickets +<http://sagemath.blogspot.com/2010/10/how-to-referee-sage-trac-tickets.html>`_ +(caveat: mercurial was replaced with Git and Trac with GitHub). + +.. NOTE:: + + "The perfect is the enemy of the good" + + The point of the review is to ensure that the Sage code guidelines + are followed and that the implementation is mathematically + correct. Please refrain from additional feature requests or + open-ended discussion about alternative implementations. If you + want the code written differently, your suggestion should be a + clear and actionable request. + + +Reviewing and closing PRs +========================= + +PRs can be closed when they have positive review or for other reasons. + +If a PR is closed for a reason other than positive review, use one of the +**resolution** labels ``r: duplicate``, ``r: invalid``, ``r: wontfix``, and +``r: worksforme``. Add a comment explaining why the issue has been closed if +that's not already clear from the discussion. + +If you think an issue has been prematurely be closed, feel free to reopen it. + + +Reasons to invalidate PRs +========================= + +**One Issue Per One Issue**: An issue must cover only one issue +and should not be a laundry list of unrelated issues. If an issue +covers more than one issue, we cannot close it and while some of +the patches have been applied to a given release, the issue would +remain in limbo. + +**No Patch Bombs**: Code that goes into Sage is peer-reviewed. If +you show up with an 80,000 lines of code bundle that completely +rips out a subsystem and replaces it with something else, you can +imagine that the review process will be a little tedious. These +huge patch bombs are problematic for several reasons and we prefer +small, gradual changes that are easy to review and apply. This is +not always possible (e.g. coercion rewrite), but it is still highly +recommended that you avoid this style of development unless there +is no way around it. + +**Sage Specific**: Sage's philosophy is that we ship everything +(or close to it) in one source tarball to make debugging possible. +You can imagine the combinatorial explosion we would have to deal +with if you replaced only ten components of Sage with external +packages. Once you start replacing some of the more essential +components of Sage that are commonly packaged (e.g. Pari, GAP, +lisp, gmp), it is no longer a problem that belongs in our tracker. +If your distribution's Pari package is buggy for example, file a +bug report with them. We are usually willing and able to solve +the problem, but there are no guarantees that we will help you +out. Looking at the open number of PRs that are Sage specific, +you hopefully will understand why. + +**No Support Discussions**: GitHub is not meant to +be a system to track down problems when using Sage. An issue should +be clearly a bug and not "I tried to do X and I couldn't get it to +work. How do I do this?" That is usually not a bug in Sage and it +is likely that ``sage-support`` can answer that question for you. If +it turns out that you did hit a bug, somebody will open a concise +and to-the-point PR. + +**Solution Must Be Achievable**: Issues must be achievable. Many +times, issues that fall into this category usually ran afoul to +some of the other rules listed above. An example would be to +"Make Sage the best CAS in the world". There is no metric to +measure this properly and it is highly subjective. + + +The release process +=================== + +It is good for developers and reviewers to be aware of the procedure that the +Sage Release Manager uses to make releases. Here it is as of 2023: + +**Beta Release Stage**: For preparing a new beta release or the first release +candidate, all positively reviewed PRs with the forthcoming release +milestone are considered. PRs that have dependencies not merged yet are ignored. +The Release Manager merges PRs in batches of 10 to 20 PRs, taking the +PR priority into account. If a merge conflict of a PR to the Release +Manager's branch occurs, the PR is set back to "needs work" status by the +Release Manager, and the list of the PRs already merged to the Release +Manager's branch is posted. The author of the PR needs to identify +conflicting PRs in the list, make merge commits and declare them as +dependencies, before setting back to "positive review" status. Each batch of +merged PRs then undergoes integration testing. If problems are detected, a +PR will be set back to "needs work" status and unmerged. When a batch of +PRs is ready, the Release Manager closes these PRs and proceeds to the +next batch. After a few batches, a new beta release is tagged, pushed to the +``develop`` branch on the Sage repository on GitHub, and announced on +``sage-release``. + +**Release Candidate Stage**: After the first release candidate has been made, +the project is in the release candidate stage, and a modified procedure is +used. Now **only PRs with a priority set to "blocker" are considered**. PRs +with all other priorities, including "critical", are ignored. Hence if a ticket +is important enough to merit inclusion in this stage, it should be set to +"blocker" by adding ``p: blocker / 1`` label. + +**Blocker PRs**: The goal of the release process is to make a stable +release of high quality. Be aware that there is a risk/benefit trade-off in +merging a PR. The benefit of merging a PR is the improvement that the +PR brings, such as fixing a bug. However, any code change has a risk of +introducing unforeseen new problems and thus delaying the release: If a new +issue triggers another release candidate, it delays the release by 1-2 weeks. +Hence developers should use "blocker" priority sparingly and should indicate +the rationale on the PR. Though there is no one fixed rule or authority +that determines what is appropriate for "blocker" status, + +- PRs introducing new features are usually not blockers -- unless perhaps + they round out a set of features that were the focus of development of this + release cycle. + +- PRs that make big changes to the code, for example refactoring PRs, + are usually not blockers. + +**Final Release**: If there is no blocker PR for the last release candidate, +the Release Manager turns it to the final release. It is tagged with the +release milestone, and announced on ``sage-release``. + diff --git a/src/doc/en/developer/reviewer_checklist.rst b/src/doc/en/developer/reviewer_checklist.rst deleted file mode 100644 index 3ddc6b94f96..00000000000 --- a/src/doc/en/developer/reviewer_checklist.rst +++ /dev/null @@ -1,138 +0,0 @@ -.. nodoctest - -.. _chapter-review: - -========================= -The reviewer's check list -========================= - -.. WARNING:: - - **Sage development is scheduled to move to GitHub in February 2023.** The exact - date will be announced in `<https://groups.google.com/g/sage-devel>`_. After - the transition, some parts of this guide (especially those related with `the - Sage Trac server <https://trac.sagemath.org>`_) will become obsolete and be - updated according to the new workflow on GitHub. See our `transition guide from Trac to - GitHub - <https://github.com/sagemath/trac-to-github/blob/master/docs/Migration-Trac-to-Github.md>`_ - for the preliminary version of the workflow. - -All code that goes into Sage is peer-reviewed. Two reasons for this are: - -- Because a developer cannot think of everything at once; -- Because a fresh pair of eyes may spot a mathematical error, - a corner-case in the code, insufficient documentation, a missing - consistency check, etc. - -Anybody (e.g. you) can do this job for somebody else's ticket. This document -lists things that the reviewer must check before deciding that a ticket is -ready for inclusion into Sage. - -- Do you know what the **trac server** is? If not, :ref:`click here - <chapter-sage-trac>`. - -- Do you have a **trac account**? If not, :ref:`click here - <section-trac-account>`. - -You can now begin the review by reading the diff code. - -**Read the diff:** the diff (i.e. the ticket's content) can be obtained by -clicking on the (green) branch's name that appears on the trac ticket. If that -name appears in red (see :ref:`section-trac-fields`) you can say so in a comment -and set the ticket to ``needs_work`` (see :ref:`section-trac-ticket-status`). - -**Build the code:** while you read the code, you can :ref:`rebuild Sage with the -new code <section-walkthrough-make>`. If you do not know how to **download the -code**, :ref:`click here <section-git_trac-review>` (with git trac) or -:ref:`here <section-git-checkout>` (git only). - - -The following should generally be checked while reading and testing the code: - -- **The purpose**: Does the code address the ticket's stated aim? Can it - introduce any new problems? Does testing the new or fixed functionality - with a variety of input, not just the examples in the documentation, - give expected and robust output (and no unexpected errors or crashes)? - -- **User documentation**: Is the use of the new code clear to a user? Are all - mathematical notions involved standard, or is there explanation (or a link - to one) provided? Can he/she find the new code easily if he/she needs it? - -- **Code documentation**: Is the code sufficiently commented so that a developer - does not have to wonder what exactly it does? - -- **Conventions**: Does the code respect :ref:`Sage's conventions - <chapter-code-basics>`? :ref:`Python's convention <chapter-python>`? - :ref:`Cython's convention <chapter-cython>`? - -- **Doctest coverage**: Do all functions contain doctests? Use ``sage -coverage - <files>`` to check it. Are all aspects of the new/modified methods and classes - tested (see :ref:`section-doctest-writing`)? - -- **Bugfixes**: If the ticket contains a bugfix, does it add a doctest - illustrating that the bug has been fixed? This new doctest should contain the - ticket number, for example ``See :trac:`12345```. - -- **Speedup**: Can the ticket make any existing code slower? if the ticket - claims to speed up some computation, does the ticket contain code examples to - illustrate the claim? The ticket should explain how the speedup is achieved. - -- **Build the manuals**: Does the reference manual build without - errors (check both html and pdf)? See :ref:`chapter-sage_manuals` to - learn how to build the manuals. - -- **Look at the manuals**: Does the reference manual look okay? The - changes may have typos that allow the documentation to build without - apparent errors but that may cause badly formatted output or broken - hyperlinks. - -- **Run the tests**: Do all doctests pass without errors? Unrelated components - of Sage may be affected by the change. Check all tests in the whole library, - including "long" doctests (this can be done with ``make ptestlong``) and any - optional doctests related to the functionality. See :ref:`chapter-doctesting` - for more information. - -You are now ready to change the ticket's status (see -:ref:`section-trac-ticket-status`): - -- **positive review**: If the answers to the questions above and other - reasonable questions are *"yes"*, you can set the ticket to - ``positive_review``. Add your full name to the "reviewer" field (see - :ref:`section-trac-fields`). - -- **needs_work**: If something is not as it should, write a list of all points - that need to be addressed in a comment and change the ticket's status to - ``needs_work``. - -- **needs_info**: If something is not clear to you and prevents you from going - further with the review, ask your question and set the ticket's status to - ``needs_info``. - -- If you **do not know what to do**, for instance if you don't feel experienced - enough to take a final decision, explain what you already did in a comment and - ask if someone else could take a look. - -**Reviewer's commit**: if you can fix the issues yourself, you may make a commit -in your own name and mark the commit as a reviewer's patch. To learn how -:ref:`click here <section-git_trac-push>` (git trac) or :ref:`here -<section-git-push>` (git only). This contribution must also be reviewed, for -example by the author of the original patch. - -For more advice on reviewing, see [WSblog]_. - -.. NOTE:: - - "The perfect is the enemy of the good" - - The point of the review is to ensure that the Sage code guidelines - are followed and that the implementation is mathematically - correct. Please refrain from additional feature requests or - open-ended discussion about alternative implementations. If you - want the patch written differently, your suggestion should be a - clear and actionable request. - -REFERENCES: - -.. [WSblog] William Stein, How to Referee Sage Trac Tickets, - http://sagemath.blogspot.com/2010/10/how-to-referee-sage-trac-tickets.html - (Caveat: mercurial was replaced with git) diff --git a/src/doc/en/developer/sage_manuals.rst b/src/doc/en/developer/sage_manuals.rst index f4892b02742..30e8114175d 100644 --- a/src/doc/en/developer/sage_manuals.rst +++ b/src/doc/en/developer/sage_manuals.rst @@ -107,9 +107,9 @@ by Sage, you can link toward it without specifying its full path: :widths: 4 4 4 :header-rows: 0 - * - Trac server - - ``:trac:`17596``` - - :trac:`17596` + * - GitHub issue + - ``issue:`17596``` + - :issue:`17596` * - Wikipedia - ``:wikipedia:`Sage_(mathematics_software)``` @@ -149,7 +149,7 @@ another option is to use `anonymous hyperlinks .. _section-add-file: -Adding a New File +Adding a new file ================= If you added a new file to Sage (e.g. ``sage/matroids/my_algorithm.py``) and you @@ -168,7 +168,7 @@ procedure is different: .. _section-building-manuals: -Building the Manuals +Building the manuals ==================== *(Do you want to edit the documentation?* :ref:`Click here @@ -206,7 +206,7 @@ links:: .. _section-manuals-names: -Document Names +Document names -------------- The ``<document-name>`` has the form: @@ -228,7 +228,7 @@ To specify the French version of the tutorial, you would simply run:: sage --docbuild fr/tutorial html -Syntax Highlighting Cython Code +Syntax highlighting Cython code =============================== If you want to write :ref:`Cython <chapter-cython>` code in a ReST file, precede diff --git a/src/doc/en/developer/static/workflow.png b/src/doc/en/developer/static/workflow.png new file mode 100644 index 00000000000..a04a1d94565 Binary files /dev/null and b/src/doc/en/developer/static/workflow.png differ diff --git a/src/doc/en/developer/ticket_badges.png b/src/doc/en/developer/ticket_badges.png deleted file mode 100644 index 1da26d4e867..00000000000 Binary files a/src/doc/en/developer/ticket_badges.png and /dev/null differ diff --git a/src/doc/en/developer/tools.rst b/src/doc/en/developer/tools.rst index e2ac3ef82dd..a79d682c0c9 100644 --- a/src/doc/en/developer/tools.rst +++ b/src/doc/en/developer/tools.rst @@ -5,7 +5,7 @@ .. _chapter-tools: ======================================== -Additional development and testing tools +Additional Development and Testing Tools ======================================== .. _section-tools-tox: @@ -13,7 +13,7 @@ Additional development and testing tools Tox === -`Tox <https://tox.readthedocs.io/en/latest/>`_ is a popular package that is +`tox <https://tox.readthedocs.io/en/latest/>`_ is a popular package that is used by a large number of Python projects as the standard entry point for testing and linting. @@ -59,7 +59,10 @@ available:: pycodestyle-minimal -- check against Sage's minimal style conventions relint -- check whether some forbidden patterns appear (includes all patchbot pattern-exclusion plugins) + rst -- validate Python docstrings markup as reStructuredText codespell -- check for misspelled words in source code + cython-lint -- Check Cython files for code style + pyright -- run the static typing checker pyright pycodestyle -- check against the Python style conventions of PEP8 -p auto -- run test environments in parallel --help -- show tox help @@ -156,18 +159,18 @@ more thorough check:: ___________ summary ____________ ERROR: pycodestyle: commands failed -When preparing a branch for a Sage ticket that adds new code, +When preparing a branch for a PR that adds new code, developers should verify that ``./sage -tox -e pycodestyle`` does not issue warnings for the added code. This will avoid later cleanup -tickets as the Sage codebase is moving toward full PEP 8 compliance. +PRs as the Sage codebase is moving toward full PEP 8 compliance. On the other hand, it is usually not advisable to mix coding-style -fixes with productive changes on the same ticket because this would +fixes with productive changes on the same PR because this would makes it harder for reviewers to evaluate the changes. By passing the options ``--count -qq`` we can reduce the output to only show the number of style violation warnings. This can be helpful -for planning work on coding-style clean-up tickets that focus on one +for planning work on coding-style clean-up PRs that focus on one or a few related issues:: $ ./sage -tox -e pycodestyle -- --count -qq src/sage @@ -199,8 +202,8 @@ or a few related issues:: - VS Code: The minimal version of pycodestyle is activated by default in ``SAGE_ROOT/.vscode/settings.json`` (the corresponding setting is ``"python.linting.pycodestyleEnabled": true``). Note that the - ``settings.json`` file is not ignored by git so be aware to keep it in sync - with the trac repo. For further details, see the + ``settings.json`` file is not ignored by Git so be aware to keep it in sync + with the Sage repo on GitHub. For further details, see the `official VS Code documentation <https://code.visualstudio.com/docs/python/linting>`__. *Configuration:* ``[pycodestyle]`` block in ``SAGE_ROOT/src/tox.ini`` @@ -208,6 +211,14 @@ or a few related issues:: *Documentation:* https://pycodestyle.pycqa.org/en/latest/index.html +.. _section-tools-cython-lint: + +Cython-lint +=========== + +`Cython-lint <https://pypi.org/project/cython-lint/>`_ checks Cython source files +for coding style. + .. _section-tools-relint: Relint diff --git a/src/doc/en/developer/trac.rst b/src/doc/en/developer/trac.rst deleted file mode 100644 index a584a61284f..00000000000 --- a/src/doc/en/developer/trac.rst +++ /dev/null @@ -1,494 +0,0 @@ -.. highlight:: shell-session - -.. _chapter-sage-trac: - -==================== -The Sage Trac Server -==================== - -.. WARNING:: - - **Sage development is scheduled to move to GitHub in February 2023.** The exact - date will be announced in `<https://groups.google.com/g/sage-devel>`_. After - the transition, some parts of this guide (especially those related with `the - Sage Trac server <https://trac.sagemath.org>`_) will become obsolete and be - updated according to the new workflow on GitHub. See our `transition guide from Trac to - GitHub - <https://github.com/sagemath/trac-to-github/blob/master/docs/Migration-Trac-to-Github.md>`_ - for the preliminary version of the workflow. - -Sometimes you will only want to work on local changes to Sage, for -your own private needs. However, typically it is beneficial to -share code and ideas with others; the manner in which the -`Sage project <https://www.sagemath.org>`_ does this (as well as fixing -bugs and upgrading components) is in a very collaborative and -public setting on `the Sage Trac server <https://trac.sagemath.org>`_ -(the Sage bug and enhancement tracker). - -The purpose of the Sage trac server is to - -1. Provide a place for discussion on issues and store a permanent - record. - -2. Provide a repository of source code and all proposed changes. - -3. Link these two together. - -There is also a :trac:`wiki <wiki>` for more general -organizational web pages, like Sage development workshops. - -Thus if you find a bug in Sage, if you have new code to submit, want -to review new code already written but not yet included in Sage, or if -you have corrections for the documentation, you should post on the -trac server. Items on the server are called *tickets*, and anyone may -search or browse the tickets. For a list of recent changes, just visit -the :trac:`Sage trac timeline <timeline>`. - -.. WARNING:: - - **Sage development is scheduled to move to GitHub in February 2023.** - All functions of our Trac server will be taken over by our main repository, - https://github.com/sagemath/sage. - - -.. _section-trac-account: - -Obtaining an Account -==================== - -If you do not have an account on GitHub yet, choose a user name and -`create an account <https://github.com/join>`_. - -Using your GitHub account, you can log in to: - -- `the Sage trac server <https://trac.sagemath.org>`_, so that you can - open tickets and participate in discussions on existing tickets. - - On the Sage trac server, click the link "GitHub Login" in the top - right corner and follow the prompts. - - Within the Sage trac server, your GitHub user name will be prefixed - with the letters ``gh-`` (which stand for "GitHub"). - -- GitLab, where the mirror repository `sagemath/sage - <https://gitlab.com/sagemath/sage>`_ accepts Merge Requests. - - In GitLab, click the button "Sign in / Register" in the top right - corner, and then use the button "Sign in with GitHub" and follow the - prompts. - -Users with legacy sage-trac accounts (account names not starting with -"gh-") should use the Login link. Do not to use GitHub login, as it -will be treated as a separate user from their original account (unless -you actively prefer to switch). - - -.. _trac-bug-report: - -Reporting Bugs -============== - -If you think you have found a bug in Sage, here is the procedure: - -- Search through our Google groups for postings related to your possible bug (it - may have been fixed/reported already): - - * ``sage-devel``: `<https://groups.google.com/group/sage-devel>`_ - * ``sage-support``: `<https://groups.google.com/group/sage-support>`_ - - Similarly, you can search :ref:`chapter-sage-trac` to see if anyone else has - opened a ticket about your bug. - -- If you do not find anything, and you are not sure that you have found a bug, - ask about it on `sage-devel <https://groups.google.com/group/sage-devel>`_. A - bug report should contain: - - - An explicit and **reproducible example** illustrating your bug (and/or the - steps required to reproduce the buggy behavior). - - - The **version** of Sage you run, as well as the version of the optional - packages that may be involved in the bug. - - - Describe your **operating system** as accurately as you can and your - architecture (32-bit, 64-bit, ...). - -- You might be asked to open a new ticket. In this case, follow the - :ref:`section-trac-new-ticket`. - -Thank you in advance for reporting bugs to improve Sage in the future! - -.. _section-trac-new-ticket: - -Guidelines for Opening Tickets -============================== - -In addition to bug reports (see :ref:`trac-bug-report`), you should also open a -ticket if you have some new code that makes Sage a better tool. If you have a -feature request, start a discussion on ``sage-devel`` first, and then if there -seems to be general agreement that you have a good idea, open a ticket -describing the idea. - -- Do you already have a **trac account**? If not, :ref:`click here - <section-trac-account>`. - -**Before** opening a new ticket, consider the following points: - -- Make sure that nobody else has opened a ticket about the same or closely - related issue. - -- It is much better to open several specific tickets than one that - is very broad. Indeed, a single ticket which deals with lots of - different issues can be quite problematic, and should be avoided. - -- Be precise: If foo does not work on OS X but is fine on Linux, - mention that in the title. Use the keyword option so that - searches will pick up the issue. - -- The problem described in the ticket must be solvable. For - example, it would be silly to open a ticket whose purpose was - "Make Sage the best mathematical software in the world". There is - no metric to measure this properly and it is highly subjective. - -- For bug reports: the ticket's description should contain the information - described at :ref:`trac-bug-report`. - -- If appropriate, provide URLs to background information or sage-devel - conversation relevant to the problem you are reporting. - -**When creating** the ticket, you may find useful to read -:ref:`section-trac-fields`. - -Unless you know what you are doing, leave the milestone field to its default -value. - -.. _section-trac-fields: - -The Ticket Fields -================= - -When you open a new ticket or change an existing ticket, you will find a variety -of fields that can be changed. Here is a comprehensive overview (for the -'status' field, see :ref:`section-trac-ticket-status`): - -* **Reported by:** The trac account name of whoever created the - ticket. Cannot be changed. - -* **Owned by:** Trac account name of owner, by default the person in charge of - the Component (see below). Generally not used in the Sage trac. - -* **Type:** One of ``enhancement`` (e.g. a new feature), ``defect`` (e.g. a bug - fix), or ``task`` (rarely used). - -* **Priority:** The priority of the ticket. Keep in mind that the - "blocker" label should be used very sparingly. - -* **Milestone:** Milestones are usually goals to be met while working - toward a release. In Sageโ€™s trac, we use milestones instead of - releases. Each ticket must have a milestone assigned. If you are - unsure, assign it to the current milestone. - -* **Component:** A list of components of Sage, pick one that most - closely matches the ticket. - -* **Keywords:** List of keywords. Fill in any keywords that you think - will make your ticket easier to find. Tickets that have been worked - on at Sage days ``NN`` (some number) ofter have ``sdNN`` as keyword. - -* **Cc:** List of trac user names to Cc (send emails for changes on - the ticket). Note that users that enter a comment are automatically - substcribed to email updates and don't need to be listed under Cc. - -* **Merged in:** The Sage release where the ticket was merged in. Only - changed by the release manager. - -* **Authors:** Real name of the ticket author(s). Set this field only if you - intend to provide code. - -* **Reviewers:** Real name of the ticket reviewer(s). - -* **Report Upstream:** If the ticket is a bug in an upstream component - of Sage, this field is used to summarize the communication with the - upstream developers. - -* **Work issues:** Issues that need to be resolved before the ticket - can leave the "needs work" status. - -* **Branch:** The Git branch containing the ticket's code (see - :ref:`section-walkthrough-branch`). It is displayed in green color, - unless there is a conflict between the branch and the latest beta - release (red color). In this case, the branch should be merged or - rebased. - -* **Dependencies:** Does the ticket depend on another ticket? - Sometimes, a ticket requires that another ticket be applied - first. If this is the case, put the dependencies as a - comma-separated list (``#1234, #5678``) into the "Dependencies:" - field. - -* **Stopgaps:** See :ref:`section-trac-stopgaps`. - -.. _section-trac-ticket-status: - -The Status of a Ticket -====================== - -The status of a ticket appears right next to its number, at the top-left corner -of its page. It indicates who has to work on it. - -- **new** -- the ticket has only been created (or the author forgot to change - the status to something else). - - If you intend to work on the code yourself, put your name in the Authors - field, or leave a comment to say so. It could avoid having two persons doing - the same job. - -- **needs_review** -- the code is ready to be peer-reviewed. If the code is not - yours, then you can review it. See :ref:`chapter-review`. - -- **needs_work** -- something needs to be changed in the code. The reason should - appear in the comments. - -- **needs_info** -- somebody has to answer a question before anything else can - happen. It should be clear from the comments. - -- **positive_review** -- the ticket has been reviewed, and the release manager - will close it. - -The status of a ticket can be changed using a form at the bottom of the ticket's -page. Leave a comment explaining your reasons whenever you change it. - -.. _section-trac-stopgaps: - -Stopgaps -======== - -When Sage returns wrong results, two tickets should be opened: - -- A main ticket with all available details. -- A "stopgap" ticket (e.g. :trac:`12699`) - -This second ticket does not fix the problem but adds a warning that will be -printed whenever anyone uses the relevant code. This, until the problem is -finally fixed. - -To produce the warning message, use code like the following: - -.. CODE-BLOCK:: python - - from sage.misc.stopgap import stopgap - stopgap("This code contains bugs and may be mathematically unreliable.", - TICKET_NUM) - -Replace ``TICKET_NUM`` by the ticket number for the main ticket. On the main -trac ticket, enter the ticket number for the stopgap ticket in the "Stopgaps" -field (see :ref:`section-trac-fields`). Stopgap tickets should be marked as -blockers. - -.. NOTE:: - - If mathematically valid code causes Sage to raise an error or - crash, for example, there is no need for a stopgap. Rather, - stopgaps are to warn users that they may be using buggy code; if - Sage crashes, this is not an issue. - - -Working on Tickets -================== - -If you manage to fix a bug or enhance Sage you are our hero. See -:ref:`chapter-walkthrough` for making changes to the Sage source -code, uploading them to the Sage trac server, and finally putting your -new branch on the trac ticket. - -.. image:: ticket_badges.png - -After pushing a branch to a ticket, the ticket will show badges -linking to results of automated tests that run on the patchbot and -other tests that run on GitHub Actions. - -* A `linting workflow - <https://github.com/sagemath/sage/blob/develop/.github/workflows/lint.yml>`_ - runs on all pushes to a branch on Trac. It checks that the code of - the current branch adheres to the style guidelines using - :ref:`section-tools-pycodestyle` (in the ``pycodestyle-minimal`` - configuration) and :ref:`section-tools-relint`. - - In order to see details when it fails, you can click on the badge - and then select the most recent workflow run. - -* The `incremental build and test workflow - <https://github.com/sagemath/sage/blob/develop/.github/workflows/build.yml>`_ - on GitHub Actions builds Sage for the current branch (incrementally - on top of an installation of the ``develop`` branch) and runs the - test. Note that in contrast to the patchbot, the ticket branch is - not merged into the current beta version. - - Details are again available by clicking on the badge. - - The automatic workflow runs on a container based on - ``ubuntu-focal-standard``. To request a run of the workflow on a - different platform, you can issue a `workflow_dispatch - <https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow#running-a-workflow>`_. - You can select any of the platforms for which a `prebuilt container - image - <https://github.com/orgs/sagemath/packages?tab=packages&q=with-targets-optional>`_ - exists. - -* The `build documentation workflow - <https://github.com/sagemath/sage/blob/develop/.github/workflows/doc-build.yml>`_ - on GitHub Actions builds the HTML documentation for the current - branch. - - If you click on the badge, you get the HTML output of the successful - run. The idea is to use this to easily inspect changes to the - documentation without the need to locally rebuild the docs - yourself. If the doc build fails, you can go to `the Actions tab of - sagemath/sagetrac-mirror repo - <https://github.com/sagemath/sagetrac-mirror/actions/workflows/doc-build.yml>`_ - and choose the particular branch to see what went wrong. - -* The patch buildbot will automatically test your ticket. See :trac:`wiki/patchbot` - for more information about its features and limitations. Make sure that you - look at the log, especially if the patch buildbot did not give you - the green blob. - -.. WARNING:: - - **Sage development is scheduled to move to GitHub in February 2023.** - After the move, the patch buildbot will no longer be available; the three - workflows above are considered a full replacement. If you miss any features - of the patch buildbot, please report this in :trac:`33457`. - -The following are some other relevant issues: - -* Every bug fixed should result in a doctest. - -* This is not an issue with defects, but there are many enhancements - possible for Sage and too few developers to implement all the good - ideas. The trac server is useful for keeping ideas in a central - place because in the Google groups they tend to get lost once they - drop off the first page. - -* If you are a developer, be nice and try to solve a stale/old ticket - every once in a while. - -* Some people regularly do triage. In this context, this means that we - look at new bugs and classify them according to our perceived - priority. It is very likely that different people will see - priorities of bugs very differently from us, so please let us know - if you see a problem with specific tickets. - -Reviewing and Closing Tickets -============================= - -Tickets can be closed when they have positive review or for other reasons. To -learn how to review, please see :ref:`chapter-review`. - -Only the Sage release manager will close tickets. Most likely, this is -not you nor will your trac account have the necessary permissions. If -you feel strongly that a ticket should be closed or deleted, then -change the status of the ticket to *needs review* and change the -milestone to *sage-duplicate/invalid/wontfix*. You should also -comment on the ticket, explaining why it should be closed. If another -developer agrees, he sets the ticket to *positive review*. - -A related issue is re-opening tickets. You should refrain from -re-opening a ticket that is already closed. Instead, open a new ticket -and provide a link in the description to the old ticket. - -Reasons to Invalidate Tickets -============================= - -**One Issue Per Ticket**: A ticket must cover only one issue -and should not be a laundry list of unrelated issues. If a ticket -covers more than one issue, we cannot close it and while some of -the patches have been applied to a given release, the ticket would -remain in limbo. - -**No Patch Bombs**: Code that goes into Sage is peer-reviewed. If -you show up with an 80,000 lines of code bundle that completely -rips out a subsystem and replaces it with something else, you can -imagine that the review process will be a little tedious. These -huge patch bombs are problematic for several reasons and we prefer -small, gradual changes that are easy to review and apply. This is -not always possible (e.g. coercion rewrite), but it is still highly -recommended that you avoid this style of development unless there -is no way around it. - -**Sage Specific**: Sage's philosophy is that we ship everything -(or close to it) in one source tarball to make debugging possible. -You can imagine the combinatorial explosion we would have to deal -with if you replaced only ten components of Sage with external -packages. Once you start replacing some of the more essential -components of Sage that are commonly packaged (e.g. Pari, GAP, -lisp, gmp), it is no longer a problem that belongs in our tracker. -If your distribution's Pari package is buggy for example, file a -bug report with them. We are usually willing and able to solve -the problem, but there are no guarantees that we will help you -out. Looking at the open number of tickets that are Sage specific, -you hopefully will understand why. - -**No Support Discussions**: The trac installation is not meant to -be a system to track down problems when using Sage. Tickets should -be clearly a bug and not "I tried to do X and I couldn't get it to -work. How do I do this?" That is usually not a bug in Sage and it -is likely that ``sage-support`` can answer that question for you. If -it turns out that you did hit a bug, somebody will open a concise -and to-the-point ticket. - -**Solution Must Be Achievable**: Tickets must be achievable. Many -times, tickets that fall into this category usually ran afoul to -some of the other rules listed above. An example would be to -"Make Sage the best CAS in the world". There is no metric to -measure this properly and it is highly subjective. - -The Release Process -=================== - -The Sage Release Manager uses the following procedure to make releases, as of -2022. - -**Beta Release Stage**: For preparing a new beta release or the first release -candidate, all positively reviewed tickets with the forthcoming release -milestone are considered. Tickets that have unmerged dependencies are ignored. -The Release Manager merges tickets in batches of 10 to 20 tickets, taking the -ticket priority into account. If a merge conflict of a ticket to the Release -Manager's branch occurs, the ticket is set back to "needs work" status by the -Release Manager, and the list of the tickets already merged to the Release -Manager's branch is posted. The author of the ticket needs to identify -conflicting tickets in the list, make merge commits and declare them as -dependencies, before setting back to "positive review" status. Each batch of -merged tickets then undergoes integration testing. If problems are detected, a -ticket will be set back to "needs work" status and unmerged. When a batch of -tickets is ready, the Release Manager closes these tickets and proceeds to the -next batch. After a few batches, a new beta release is tagged, pushed to the -``develop`` branch on the main git repository, and announced on -``sage-release``. - -**Release Candidate Stage**: After the first release candidate has been made, -the project is in the release candidate stage, and a modified procedure is -used. Now **only tickets with a priority set to "blocker" are considered**. -Tickets with all other priorities, including "critical", are ignored. Hence if -a ticket is important enough to merit inclusion in this stage, it should be set -to "blocker". - -**Blocker Tickets**: The goal of the release process is to make a stable -release of high quality. Be aware that there is a risk/benefit trade-off in -merging a ticket. The benefit of merging a ticket is the improvement that the -ticket brings, such as fixing a bug. However, any code change has a risk of -introducing unforeseen new problems and thus delaying the release: If a new -issue triggers another release candidate, it delays the release by 1-2 weeks. -Hence developers should use "blocker" priority sparingly and should indicate -the rationale on the ticket. Though there is no one fixed rule or authority -that determines what is appropriate for "blocker" status, - -- Tickets introducing new features are usually not blockers -- unless perhaps - they round out a set of features that were the focus of development of this - release cycle. - -- Tickets that make big changes to the code, for example refactoring tickets, - are usually not blockers. - -**Final Release**: If there is no blocker ticket for the last release -candidate, the Release Manager turns it to the final release. It is tagged with -the release milestone, and announced on ``sage-release``. diff --git a/src/doc/en/developer/walk_through.rst b/src/doc/en/developer/walk_through.rst deleted file mode 100644 index 74f0fd514f0..00000000000 --- a/src/doc/en/developer/walk_through.rst +++ /dev/null @@ -1,361 +0,0 @@ -.. highlight:: shell-session - -.. _chapter-walkthrough: - -======================== -Sage Development Process -======================== - -.. WARNING:: - - **Sage development is scheduled to move to GitHub in February 2023.** The exact - date will be announced in `<https://groups.google.com/g/sage-devel>`_. After - the transition, some parts of this guide (especially those related with `the - Sage Trac server <https://trac.sagemath.org>`_) will become obsolete and be - updated according to the new workflow on GitHub. See our `transition guide from Trac to - GitHub - <https://github.com/sagemath/trac-to-github/blob/master/docs/Migration-Trac-to-Github.md>`_ - for the preliminary version of the workflow. - -This section is a concise overview of the Sage development process. In -it, we will see how to make changes to the Sage source code and record -them in the ``git`` revision control system. - -We also have a handy `one-page "cheat sheet" -<http://github.com/sagemath/git-trac-command/raw/master/doc/git-cheat-sheet.pdf>`_ -of commonly used git commands that you can print out and leave on your -desk. We have some :ref:`recommended references and tutorials -<section-git-tutorials>` as well. - -In the following sections on :ref:`chapter-sage-trac` and -:ref:`section-git-tricks-and-tips` we will look at communicating these -changes back to the Sage project. All changes to Sage source code -have to go through the `Sage Trac development server -<https://trac.sagemath.org>`_. - -As an alternative to using the Trac server directly, you can fork and -create a Merge Request (MR) at `GitLab <https://gitlab.com/sagemath/sage>`_ -which will automatically fetch your code and open a ticket on our trac -server. - -Pull Requests (PR) on GitHub are currently not supported by the -SageMath project. - - -.. _section-walkthrough-setup-git: - -Configuring Git -=============== - -One way or another, ``git`` is what Sage uses for tracking changes. -So first, open a shell (for instance, Terminal on Mac) and check that -``git`` works:: - - [user@localhost]$ git - usage: git [--version] [--help] [-C <path>] [-c name=value] - ... - The most commonly used git commands are: - add Add file contents to the index - ... - tag Create, list, delete or verify a tag object signed with GPG - - 'git help -a' and 'git help -g' lists available subcommands and some - concept guides. See 'git help <command>' or 'git help <concept>' - to read about a specific subcommand or concept. - - -Don't worry about the giant list of subcommands. You really only need -a handful for effective development, and we will walk you through them -in this guide. If you got a "command not found" error, then you don't -have git installed. Now is the time to install it; see -:ref:`chapter-git-setup` for instructions. - -Because we also track who does changes in Sage with git, you must tell -git how you want to be known. This only needs to be done once:: - - [user@localhost]$ git config --global user.name "Your Name" - [user@localhost]$ git config --global user.email you@yourdomain.example.com - -If you have multiple accounts / computers use the same name on each of -them. This name/email combination ends up in commits, so do it now -before you forget! - - -.. _section-walkthrough-sage-source: - -Obtaining and Compiling the Sage Source Code -============================================ - -Obviously one needs the Sage source code to develop. You can use your -local installation of Sage, or (to start from scratch) download it -from GitHub which is a public read-only mirror (=faster) of our -internal git repository:: - - [user@localhost ~]$ git clone https://github.com/sagemath/sage.git - Cloning into 'sage'... - [...] - Checking connectivity... done. - -This creates a directory named ``sage`` containing the sources for the -current stable and development releases of Sage. You next need to switch -to the develop branch (latest development release):: - - [user@localhost ~]$ cd sage - [user@localhost sage]$ git checkout develop - -Next, compile Sage, following the instruction in the file -`README.md <https://github.com/sagemath/sage/#readme>`_ in ``SAGE_ROOT``. -Additional details can be found in the -`section on installation from source <../installation/source.html>`_ -in the Sage installation guide. -If you wish to use conda-forge, see the `section on conda -<../installation/conda.html>`_. - -.. NOTE:: - - macOS allows changing directories without using exact capitalization. - Beware of this convenience when compiling for macOS. Ignoring exact - capitalization when changing into :envvar:`SAGE_ROOT` can lead to build - errors for dependencies requiring exact capitalization in path names. - -For the experts, note that the repository at -`git.sagemath.org <http://git.sagemath.org>`_ is where development -actually takes place. - -.. WARNING:: - - **Sage development is scheduled to move to GitHub in February 2023.** - After the move, https://github.com/sagemath/sage.git will be the - primary repository. - -.. _section-walkthrough-branch: - -Branching Out -============= - -In order to start modifying Sage, we want to make a *branch* of Sage. -A branch is a copy (except that it doesn't take up twice the space) of -the Sage source code where you can store your modifications to the -Sage source code and which you can upload to trac tickets. - -To begin with, type the command ``git branch``. You will see the following:: - - [user@localhost sage]$ git branch - * develop - master - -The asterisk shows you which branch you are on. Without an argument, -the ``git branch`` command displays a list of all local branches -with the current one marked by an asterisk. - -It is easy to create a new branch; first make sure you are on the branch from -which you want to branch out. That is, if you are not currently on the -``develop`` branch, type the command ``git checkout develop``:: - - [user@localhost sage]$ git checkout develop - Switched to branch 'develop' - Your branch is up-to-date with 'origin/develop'. - -Then use the ``git branch`` command to create a new branch, as follows:: - - [user@localhost sage]$ git branch last_twin_prime - -Also note that ``git branch`` creates a new branch, but does not switch -to it. For this, you have to use ``git checkout``:: - - [user@localhost sage]$ git checkout last_twin_prime - Switched to branch 'last_twin_prime' - -Now if you use the command ``git branch``, you will see the following:: - - [user@localhost sage]$ git branch - develop - * last_twin_prime - master - -Note that unless you explicitly upload ("push") a branch to a remote -git repository, the branch is a local branch that is only on your computer -and not visible to anyone else. - -To avoid typing the new branch name twice you can use the shortcut -``git checkout -b my_new_branch`` to create and switch to the new -branch in one command. - -.. _section_walkthrough_logs: - -The History -=========== - -It is always a good idea to check that you are making your edits on -the version that you think you are on. The first one shows you the -topmost commit in detail, including its changes to the sources:: - - [user@localhost sage]$ git show - -To dig deeper, you can inspect the log:: - - [user@localhost sage]$ git log - -By default, this lists all commits in reverse chronological order. - -- If you find your branch to be in the wrong place, see the - :ref:`section-git-recovery` section. - -- Many programs are available to help you visualize the history tree - better. ``tig`` is a very nice text-mode such tool. - -.. _section-walkthrough-add-edit: - -Editing the Source Code -======================= - -Once you have your own branch, feel free to make any changes as you -like. :ref:`Subsequent chapters <section-writing-code-for-sage>` of -this developer guide explain how your code should look like to fit -into Sage, and how we ensure high code quality throughout. - -*Status* is probably the most important git command. It tells -you which files changed, and how to continue with recording the -changes:: - - [user@localhost sage]$ git status - On branch last_twin_prime - Changes not staged for commit: - (use "git add <file>..." to update what will be committed) - (use "git checkout -- <file>..." to discard changes in working directory) - - modified: some_file.py - modified: src/sage/primes/all.py - - Untracked files: - (use "git add <file>..." to include in what will be committed) - - src/sage/primes/last_pair.py - - no changes added to commit (use "git add" and/or "git commit -a") - -To dig deeper into what was changed in the files you can use:: - - [user@localhost sage]$ git diff some_file.py - -to show you the differences. - - - -.. _section-walkthrough-make: - -Rebuilding Sage -=============== - -Once you have made any changes you of course want to build Sage and -try out your edits. As long as you only modified the Sage library -(that is, Python and Cython files under ``src/sage/...``) you just -have to run:: - - [user@localhost sage]$ ./sage -br - -to rebuild the Sage library and then start Sage. This should be quite -fast. If you made changes to -:ref:`third-party packages <chapter-packaging>`, then you have to run :: - - [user@localhost sage]$ make build - -as if you were `installing Sage from scratch -<http://doc.sagemath.org/html/en/installation/source.html>`_. -However, this time only packages which were changed (or which depend -on a changed package) will be recompiled, -so it should be much faster than compiling Sage -the first time. - -.. NOTE:: - - If you have `pulled a branch from trac - <http://doc.sagemath.org/html/en/developer/manual_git.html#checking-out-tickets>`_, - it may depend on changes to third-party packages, so ``./sage -br`` - may fail. If this happens (and you believe the code in this branch - should compile), try running ``make build``. - -Rarely there are conflicts with other packages, -or with the already-installed older version of the package that you -changed, in that case you do have to recompile everything using:: - - [user@localhost sage]$ make distclean && make build - -Also, don't forget to run the tests (see :ref:`chapter-doctesting`) -and build the documentation (see :ref:`chapter-sage_manuals`). - -.. NOTE:: - - If you switch between branches based on different releases, the timestamps - of modified files will change. This triggers recythonization and recompilation - of modified files on subsequent builds, whether or not you have made any - additional changes to files. To minimize the impact of switching between branches, - install ccache using the command :: - - [user@localhost sage]$ ./sage -i ccache - - Recythonization will still occur when rebuilding, but the recompilation stage - first checks whether previously compiled files are cached for reuse before - compiling them again. This saves considerable time rebuilding. - - -.. _section-walkthrough-commit: - -Commits (Snapshots) -=================== - -Whenever you have reached your goal, a milestone towards it, or -just feel like you got some work done you should *commit* your -changes. A commit is just a snapshot of the state of all files in -the *repository* (the program you are working on). - -Unlike with some other revision control programs, in git you first -need to *stage* the changed files, which tells git which files you -want to be part of the next commit:: - - [user@localhost sage]$ git status - # On branch my_branch - # Untracked files: - # (use "git add <file>..." to include in what will be committed) - # - # src/sage/primes/last_pair.py - nothing added to commit but untracked files present (use "git add" to track) - - [user@localhost sage]$ git add src/sage/primes/last_pair.py - [user@localhost sage]$ git status - # On branch my_branch - # Changes to be committed: - # (use "git reset HEAD <file>..." to unstage) - # - # new file: src/sage/primes/last_pair.py - # - -Once you are satisfied with the list of staged files, you create a new -snapshot with the ``git commit`` command:: - - [user@localhost sage]$ git commit - ... editor opens ... - [my_branch 31331f7] Added the very important foobar text file - 1 file changed, 1 insertion(+) - create mode 100644 foobar.txt - -This will open an editor for you to write your commit message. The -commit message should generally have a one-line description, followed -by an empty line, followed by further explanatory text: - -.. CODE-BLOCK:: text - - Added the last twin prime - - This is an example commit message. You see there is a one-line - summary followed by more detailed description, if necessary. - -You can then continue working towards your next milestone, make -another commit, repeat until finished. As long as you do not -``git checkout`` another branch, all commits that you make will be part of -the branch that you created. - - - - - diff --git a/src/doc/en/developer/walkthrough.rst b/src/doc/en/developer/walkthrough.rst new file mode 100644 index 00000000000..6e1b686989a --- /dev/null +++ b/src/doc/en/developer/walkthrough.rst @@ -0,0 +1,327 @@ +.. highlight:: shell-session + +.. _chapter-walkthrough: + +======================== +Development Walk-through +======================== + +This section is a concise overview of the Sage development process. We will see +how to make changes to the Sage source code and record them in the Git revision +control system. + +In the sections of the following chapter :ref:`section-development-on-github`, +we will look at communicating these changes back to the Sage project. All +changes to Sage source code have to go through `the Sage repository +<https://github.com/sagemath/sage>`_ on GitHub. + +For examples, we assume your name Alice. Always replace it with your own name. + +.. _section-walkthrough-setup-git: + +Checking Git +============ + +First, open a shell (for instance, Terminal on Mac) and check that Git works:: + + [alice@localhost ~]$ git + usage: git [--version] [--help] [-C <path>] [-c name=value] + ... + The most commonly used git commands are: + add Add file contents to the index + ... + tag Create, list, delete or verify a tag object signed with GPG + + 'git help -a' and 'git help -g' lists available subcommands and some + concept guides. See 'git help <command>' or 'git help <concept>' + to read about a specific subcommand or concept. + +Don't worry about the giant list of subcommands. You really only need a handful +of them for effective development, and we will walk you through them in this +guide. If you got a "command not found" error, then you don't have Git +installed; now is the time to install it. See +:ref:`section-git-install` for instructions. + +Because we also track who does what changes with Git, you must tell +Git how you want to be known. Check if Git knows you:: + + [alice@localhost ~]$ git config --global user.name + Alice Adventure + [alice@localhost ~]$ git config --global user.email + alice@wonderland.com + +If you have multiple computers, then use the same name on each of them. This +name/email combination ends up in commits. So if it's not set yet, do it now +before you forget! This only needs to be done once. See +:ref:`section-git-setup-name` for instructions. + +.. _section-walkthrough-sage-source: + +Obtaining the Sage source code +============================== + +Obviously one needs the Sage source code to develop. You can use your +local installation of Sage, or (to start from scratch) download it +from our Sage repository on GitHub:: + + [alice@localhost ~]$ git clone --origin upstream https://github.com/sagemath/sage.git + Cloning into 'sage'... + [...] + Checking connectivity... done. + +This creates a directory named ``sage`` containing the sources for the +current stable and development releases of Sage. You next need to switch +to the develop branch (latest development release):: + + [alice@localhost ~]$ cd sage + [alice@localhost sage]$ git checkout develop + +Next, build Sage, following the instruction in the file `README.md +<https://github.com/sagemath/sage/#readme>`_ in ``SAGE_ROOT``. If all +prerequisites to build are in place, the commands ``./configure && make -j4`` +will do it. Additional details can be found in the section on `installation +from source <../installation/source.html>`_ in the Sage installation guide. If +you wish to use conda-forge, see the section on `conda +<../installation/conda.html>`_. + +.. NOTE:: + + macOS allows changing directories without using exact capitalization. + Beware of this convenience when compiling for macOS. Ignoring exact + capitalization when changing into :envvar:`SAGE_ROOT` can lead to build + errors for dependencies requiring exact capitalization in path names. + + +.. _section-walkthrough-branch: + +Branching out +============= + +In order to start modifying Sage, we want to make a new *branch* in the local +Sage repo. A branch is a copy (except that it doesn't take up twice the space) +of the Sage source code where you can store your modifications to the Sage +source code (and which you can push to your fork of the Sage repository on GitHub). + +To begin with, type the command ``git branch``. You will see the following:: + + [alice@localhost sage]$ git branch + * develop + master + +The asterisk shows you which branch you are on. Without an argument, +the ``git branch`` command displays a list of all local branches +with the current one marked by an asterisk. + +It is easy to create a new branch. First make sure you are on the branch from +which you want to branch out. That is, if you are not currently on the +``develop`` branch, type the command ``git checkout develop``:: + + [alice@localhost sage]$ git checkout develop + Switched to branch 'develop' + Your branch is up-to-date with 'origin/develop'. + +Then use the ``git branch`` command to create a new branch, as follows:: + + [alice@localhost sage]$ git branch last_twin_prime + +Also note that ``git branch`` creates a new branch, but does not switch +to it. For this, you have to use ``git checkout``:: + + [alice@localhost sage]$ git checkout last_twin_prime + Switched to branch 'last_twin_prime' + +Now if you use the command ``git branch``, you will see the following:: + + [alice@localhost sage]$ git branch + develop + * last_twin_prime + master + +Note that unless you explicitly push a branch to a remote Git repository, the +branch is a local branch that is only on your computer and not visible to +anyone else. + +To avoid typing the new branch name twice you can use the shortcut +``git checkout -b last_twin_prime develop`` to create and switch to the new +branch based on ``develop`` in one command. + + +.. _section_walkthrough_logs: + +The history +=========== + +It is always a good idea to check that you are making your edits on the branch +that you think you are on. The following command shows you the topmost commit +in detail, including its changes to files:: + + [alice@localhost sage]$ git show + +To dig deeper, you can inspect the log:: + + [alice@localhost sage]$ git log + +By default, this lists all commits in reverse chronological order. + +- If you find your branch to be in the wrong place, see the + :ref:`section-git-recovery` section. + +- Many tools are available to help you visualize the history tree better. + For instance, ``tig`` is a very nice text-mode tool. + +.. _section-walkthrough-add-edit: + +Editing the source code +======================= + +Once you have your own branch, feel free to make any changes to source files as +you like. The chapter :ref:`section-writing-code-for-sage` explains how your +code should look like to fit into Sage, and how we ensure high code quality +throughout. + +The Git command ``git status`` is probably the most important of all Git +commands. It tells you which files changed, and how to continue with recording +the changes:: + + [alice@localhost sage]$ git status + On branch last_twin_prime + Changes not staged for commit: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: some_file.py + modified: src/sage/primes/all.py + + Untracked files: + (use "git add <file>..." to include in what will be committed) + + src/sage/primes/last_pair.py + + no changes added to commit (use "git add" and/or "git commit -a") + +To dig deeper into what was changed in the files you can use:: + + [alice@localhost sage]$ git diff some_file.py + +to show you the differences. + + +.. _section-walkthrough-make: + +Rebuilding Sage +=============== + +Once you have made any changes, you of course want to build Sage and try out +your edits. As long as you only modified the Sage library (that is, Python and +Cython files under ``src/sage/...``) you just have to run:: + + [alice@localhost sage]$ ./sage -br + +to rebuild the Sage library and then start Sage. + +.. NOTE:: + + All changes to Python files take effect immediately after restarting Sage + (unless you have used ``./configure --disable-editable`` when you built + Sage). Hence you can just start Sage instead of ``./sage -br`` if only Python + files were modified. + +If you made changes to :ref:`third-party packages <chapter-packaging>` +installed as part of Sage, then you have to run :: + + [alice@localhost sage]$ make build + +as if you were `installing Sage from scratch +<http://doc.sagemath.org/html/en/installation/source.html>`_. However, this +time only, the packages which were changed (or which depend on a changed package) +will be rebuilt, so it should be much faster than building Sage the first +time. + +.. NOTE:: + + If you have `pulled a branch from the GitHub Sage repository + <https://doc.sagemath.org/html/en/developer/workflows.html#checking-out-an-existing-pr>`_, + it may depend on changes to third-party packages, so ``./sage -br`` may + fail. If this happens (and you believe the code in this branch should + compile), try running ``make build``. + +Rarely there are conflicts with other packages, +or with the already-installed older version of the package that you +changed, in that case you do have to recompile everything using:: + + [alice@localhost sage]$ make distclean && make build + +Also, don't forget to run the tests (see :ref:`chapter-doctesting`) +and build the documentation (see :ref:`chapter-sage_manuals`). + +.. NOTE:: + + If you switch between branches based on different releases, the timestamps + of modified files will change. This triggers recythonization and recompilation + of modified files on subsequent builds, whether or not you have made any + additional changes to files. To minimize the impact of switching between branches, + install ccache using the command :: + + [alice@localhost sage]$ ./sage -i ccache + + Recythonization will still occur when rebuilding, but the recompilation stage + first checks whether previously compiled files are cached for reuse before + compiling them again. This saves considerable time rebuilding. + + +.. _section-walkthrough-commit: + +Making commits +============== + +Whenever you have reached your goal, a milestone towards it, or +just feel like you got some work done you should *commit* your +changes. A commit is just a snapshot of the state of all files in +the repository. + +Unlike with some other revision control programs, in Git you first +need to *stage* the changed files, which tells Git which files you +want to be part of the next commit:: + + [alice@localhost sage]$ git status + # On branch my_branch + # Untracked files: + # (use "git add <file>..." to include in what will be committed) + # + # src/sage/primes/last_pair.py + nothing added to commit but untracked files present (use "git add" to track) + + [alice@localhost sage]$ git add src/sage/primes/last_pair.py + [alice@localhost sage]$ git status + # On branch my_branch + # Changes to be committed: + # (use "git reset HEAD <file>..." to unstage) + # + # new file: src/sage/primes/last_pair.py + # + +Once you are satisfied with the list of staged files, you create a new +snapshot with the ``git commit`` command:: + + [alice@localhost sage]$ git commit + ... editor opens ... + [my_branch 31331f7] Added the very important foobar text file + 1 file changed, 1 insertion(+) + create mode 100644 foobar.txt + +This will open an editor for you to write your commit message. The +commit message should generally have a one-line description, followed +by an empty line, followed by further explanatory text: + +.. CODE-BLOCK:: text + + Added the last twin prime + + This is an example commit message. You see there is a one-line + summary followed by more detailed description, if necessary. + +You can then continue working towards your next milestone, make +another commit, repeat until finished. As long as you do not +``git checkout`` another branch, all commits that you make will be part of +the branch that you created. + diff --git a/src/doc/en/developer/workflows.rst b/src/doc/en/developer/workflows.rst index b4d00265ee2..fbe05963947 100644 --- a/src/doc/en/developer/workflows.rst +++ b/src/doc/en/developer/workflows.rst @@ -2,201 +2,169 @@ .. _chapter-workflows: -======================= -Distributed Development -======================= +===================== +Using Git with GitHub +===================== -.. WARNING:: +We continue our introduction to Sage development from :ref:`chapter-walkthrough`. +We discuss how to push your local changes to your fork of the GitHub Sage repository +so that your changes can be reviewed for inclusion in Sage. - **Sage development is scheduled to move to GitHub in February 2023.** The exact - date will be announced in `<https://groups.google.com/g/sage-devel>`_. After - the transition, some parts of this guide (especially those related with `the - Sage Trac server <https://trac.sagemath.org>`_) will become obsolete and be - updated according to the new workflow on GitHub. See our `transition guide from Trac to - GitHub - <https://github.com/sagemath/trac-to-github/blob/master/docs/Migration-Trac-to-Github.md>`_ - for the preliminary version of the workflow. +Before proceeding, check that you have ``origin`` and ``upstream`` remotes right:: -Git is a tool to exchange commits (organized into branches) with other -developers. As a distributed revision control system, it does not have -the notion of a central server. The Sage trac server is just one of -many possible remote repositories from your point of view. This lets -you use and experiment with different ways to interact with other -developers. In this chapter, we describe some common ways to develop -for Sage. + [alice@localhost sage]$ git remote -v + origin https://github.com/alice/sage.git (fetch) + origin https://github.com/alice/sage.git (push) + upstream https://github.com/sagemath/sage.git (fetch) + upstream https://github.com/sagemath/sage.git (push) -For simplicity, let us assume two developers (Alice and Bob) are -collaborating on a ticket. The first step of opening the ticket is -always the same, and could be performed by either Alice or Bob or a -third person. +Development workflow at a glance +================================ - - - -Simple Workflow -=============== - -.. IMAGE:: static/flowchart.* +.. IMAGE:: static/workflow.* :align: center - 1. Alice creates a :ref:`new local branch <section-walkthrough-branch>` and - :ref:`commits <section-walkthrough-commit>` changes to the Sage sources. - -2. Alice :ref:`uploads her branch <section-git_trac-push>` to the trac - server. This fills in the "Branch:" field with her remote branch - name ``u/alice/description``. - -3. Bob :ref:`downloads Alice's branch <section-git_trac-checkout>`, looks - through the source, and leaves a comment on the ticket about a - mistake in Alice's code. + :ref:`commits <section-walkthrough-commit>` changes to the Sage source files. -4. Alice fixes the bug on top of her current branch, and uploads the - updated branch. +2. Alice pushes the local branch to the remote ``origin``, her fork of the Sage + repo on GitHub, and with it :ref:`creates a PR <section-workflows-push>` to + the Sage repo. When ready, Alice sets the PR to ``needs review`` status. -5. Bob :ref:`retrieves Alice's updates <section-git_trac-pull>` and reviews - the changes. +3. Bob, a developer acting as reviewer, :ref:`examines the PR + <section-workflows-pr-checkout>`, looks through the changes, leaves comments + on the PR, and requests fixes (``needs work``). -6. Once Bob is satisfied, he sets the ticket to positive review. The - "Author:" field is set to Alice's full name, and the "Reviewer:" - field is set to Bob's full name. +4. Alice makes more commits on top of her local branch, and pushes the new + commits to the remote ``origin``. These new commits are reflected in the PR. -Alternatively, Bob might want to make some changes himself. Then, -instead, we would have +5. Bob looks through the changes in the new commits and reviews the changes. -3. Bob :ref:`downloads Alice's branch <section-git_trac-checkout>`, makes - changes, and :ref:`commits <section-walkthrough-commit>` them to his local - branch. +6. After a few of iterations of commenting and fixing, finally the reviewer Bob + is satisfied, and then he approves the PR and sets it to ``positive review`` + status. -4. Bob :ref:`uploads his branch <section-git_trac-push>` to the trac - server. This fills in the "Branch:" field with his remote branch name - ``u/bob/description``. -5. Alice :ref:`downloads Bob's branch <section-git_trac-checkout>` and - reviews his changes. +.. _section-workflows-pr-create: -6. Once Alice is satisfied, she sets the ticket to positive review. If - both contributions are of comparable size, then the "Author:" and - "Reviewer:" fields are set to both Alice's and Bob's full name. - - - - -Public Repository +Creating a new PR ================= -In addition to the user branches (``u/<user>/<description>`` on the -Sage trac server with ``<user>`` replaced by your trac user name) that -only you can write to, you can also create a public branch that -everybody with a trac account can write to. These start with -``public/`` plus some description. To avoid branch name collisions it -is a good idea to include your trac user name in the branch name, so -it is recommended that you use ``public/<user>/<description>`` as the -branch name. Now all ticket authors push to the same remote branch. +Suppose you have written an algorithm for calculating the last twin prime, +committed the code to a local branch based upon ``develop`` branch. Now you +want to add it to Sage. You would first open a PR for that:: -1. Alice creates a :ref:`new local branch <section-walkthrough-branch>` and - :ref:`commits <section-walkthrough-commit>` some changes to the Sage library. + [alice@localhost sage]$ gh pr create + ? Where should we push the 'last-twin-prime' branch? user/sage + + Creating pull request for user:last-twin-prime into develop in sagemath/sage -2. Alice :ref:`uploads her branch <section-git_trac-push>` as a public - branch to the trac server. This fills in the "Branch:" field with - her remote branch name ``public/alice/description``. + ? Title Last twin prime + ? Choose a template PULL_REQUEST_TEMPLATE.md + ? Body <Received> + ? What's next? Submit as draft + https://github.com/sagemath/sage/pull/12345 -3. Bob :ref:`downloads Alice's branch <section-git_trac-checkout>` and - makes changes to his local copy. +This will create a new PR titled "Last twin prime" in the Sage repo for the +branch pushed to your fork ``alice/sage`` from the local branch on your +desktop. The title is automatically derived from the last commit title. If you +don't like this, then you can use the ``-t`` switch to specify it explicitly. +See the manual page of the command `gh pr create +<https://cli.github.com/manual/gh_pr_create>`_ for details. -4. Bob :ref:`commits <section-walkthrough-commit>` changes to his local branch - of the Sage sources. +If you did not provide enough details about the PR at the prompts, you may want +to edit the PR further via the web interface. -5. Bob uploads his changes to the joint remote repository:: - [bob@localhost sage]$ git push trac local_branch:public/alice/description +.. _section-workflows-pr-checkout: -6. Alice :ref:`retrieves Bob's updates <section-git_trac-pull>`, makes - more changes, commits, and pushes them to trac. +Checking out an existing PR +=========================== -7. Charly reviews the final version, and then sets the ticket to - positive review. The "Author:" field is set to Alice's and Bob's - full name, and the "Reviewer:" field is set to Charly's full name. +If you want to base your work on an existing PR or want to review the code of a PR, +then you would run:: + [alice@localhost sage]$ gh pr checkout 12345 + remote: Enumerating objects: 7, done. + remote: Counting objects: 100% (7/7), done. + remote: Compressing objects: 100% (7/7), done. + remote: Total 7 (delta 0), reused 0 (delta 0), pack-reused 0 + Unpacking objects: 100% (7/7), 25.50 KiB | 2.83 MiB/s, done. + From https://github.com/sagemath/sage + * [new ref] refs/pull/12345/head -> last-twin-prime + Switched to branch 'last-twin-prime' +The command ``gh pr checkout`` downloads the branch of the PR. Just +like the ``create`` command, you can specify the local branch name explicitly using +the ``-b`` switch if you want. -GitHub -====== +.. _section-workflows-push: -Yet another possible workflow is to use GitHub (or any other -third-party git repository) to collaboratively edit your new branch, -and only push the result to trac once you and your ticket co-authors -are satisfied. +Uploading more changes to GitHub +================================ +Once you have created a PR, edit the appropriate files and commit your changes +to your local branch as described in :ref:`section-walkthrough-add-edit` and +:ref:`section-walkthrough-commit`. -Fork ----- +If you are ready to share the changes up to now, upload your new commits to +your fork by:: -The first step is to create your own fork of the Sage repository; -simply click "Fork" on the `Sage GitHub repository -<https://github.com/sagemath/sage>`_. Then add it as one of the -remotes to your local Sage repository. In the following, we will use -the label "github" for this remote repository, though you are of -course free to use a different one:: + [alice@localhost sage]$ git push origin + Enumerating objects: 13, done. + Counting objects: 100% (13/13), done. + Delta compression using up to 12 threads + Compressing objects: 100% (7/7), done. + Writing objects: 100% (7/7), 1.98 KiB | 1.98 MiB/s, done. + Total 7 (delta 6), reused 0 (delta 0), pack-reused 0 + remote: Resolving deltas: 100% (6/6), completed with 6 local objects. + To https://github.com/alice/sage.git + + 352d842907...56ffdab967 last-twin-prime -> last-twin-prime - $ git remote add github git@github.com:github_user_name/sage.git - $ git remote -v - github git@github.com:github_user_name/sage.git (fetch) - github git@github.com:github_user_name/sage.git (push) - trac git@trac.sagemath.org:sage.git (fetch) - trac git@trac.sagemath.org:sage.git (push) - $ git fetch github - remote: Counting objects: 107, done. - remote: Compressing objects: 100% (63/63), done. - remote: Total 74 (delta 41), reused 40 (delta 10) - Unpacking objects: 100% (74/74), done. - From github.com:github_user_name/sage - * [new branch] master -> github/master +Note that you do not push the branch to the remote ``upstream`` the Sage repo. +Instead the new commits pushed to the remote ``origin`` are shown in the PR at +the Sage repo. -Develop -------- +.. _section-workflows-finish: -You now use the github repository to develop your ticket branch; First -create a new branch:: +Finishing it up +=============== - $ git checkout -b my_branch --track github/master - Branch my_branch set up to track remote branch master from github. - Switched to a new branch 'my_branch' - $ git push github my_branch - Total 0 (delta 0), reused 0 (delta 0) - To git@github.com:github_user_name/sage.git - * [new branch] my_branch -> my_branch +It is common to go through a few iterations of commits before you +push the branch, and you will probably also have pushed your branch a few +times before your branch is ready for review. -Because of the ``--track`` option, the ``git pull`` command will -default to downloading your coauthor's changes from your github -branch. Alternatively, you can create a new branch on your fork's -GitHub webpage. +Once you are happy with the changes you pushed, they must be +reviewed by someone else before they can be included in the next +release of Sage. To mark your PR as ready for review, you should +set it to ``needs review`` status. -At this point you can use the GitHub workflow that you prefer. In -particular, your choices are -* Give your coauthors write permissions to your github fork. Every - author edits/commits to their own local copy and they jointly push - to your github branch. +.. _section-workflows-merge: -* Have every coauthor create their own fork and send you (the lead - author) pull requests to your GitHub fork. +Merging the upstream develop branch +=================================== -* Use the GitHub web page editing & committing feature, that way you - can make changes without ever using your local machine. +It commonly happens that ``develop`` branch at the remote ``upstream`` was +updated and you need to merge the upstream changes to your local branch. Then +you do:: + [alice@localhost sage]$ git fetch upstream develop:develop -Push to Trac ------------- +This fast-forwards your local ``develop`` branch to the upstream +``develop`` branch. -When you are satisfied with your branch, you push it to the Sage trac -server:: +Now you go back to your working branch and merge the updated ``develop`` branch:: - $ git push trac HEAD:u/user/description + [alice@localhost sage]$ git merge develop + .... -and then fill in the "Branch" field in the trac ticket description as -explained in :ref:`section-git-push`. +If there was no upstream change conflicting with the changes you made locally, +this merge operation will finish cleanly. Otherwise, you are in *merge +conflict*. This rarely happens since Git is smart in merging changes. However, +once merge conflict occurs, you have to manually resolve the conflicts. The +conflict resolving procedure is explained in :ref:`section-git-conflict`. diff --git a/src/doc/en/developer/workspace.rst b/src/doc/en/developer/workspace.rst index d820721e11b..4587c43c797 100644 --- a/src/doc/en/developer/workspace.rst +++ b/src/doc/en/developer/workspace.rst @@ -8,10 +8,10 @@ Setting up your workspace .. _section-ide: -Configuring text editors and IDEs for use with Sage -=================================================== +Text editors and IDEs for use with Sage +======================================= -In Meta-ticket :trac:`30500` we are collecting instructions how to configure +In meta :issue:`30500` we are collecting instructions how to configure various text editors and IDEs for use with Sage. @@ -22,27 +22,27 @@ Gitpod `Gitpod <https://www.gitpod.io>`_ is a free service that will let you build and run Sage from an online development environment based on VS Code. -Without needing to install anything on your computer, Gitpod creates a virtual +Without needing to install anything on your computer, Gitpod creates a virtual fully-functional workspace with all the dependencies and tools pre-installed. -To get started, `go to Gitpod <https://gitpod.io/#https://github.com/sagemath/sage>`_ -and log in using your GitHub or GitLab account. -Wait while Gitpod creates a workspace. -The first time, it may take some time to build Sage. +To get started, `go to Gitpod +<https://gitpod.io/#https://github.com/sagemath/sage>`_ and log in using your +GitHub or GitLab account. Wait while Gitpod creates a workspace. The first +time, it may take some time to build Sage. You can now run and edit Sage's code. Contributing your changes follows the normal -:ref:`Git workflow <chapter-manual-git>`. -For this to work, you first have to authorize Gitpod with Trac: +:ref:`Git workflow <chapter-git-basic>`. +For this to work, you first have to authorize Gitpod with GitHub: - 1. In the running Gitpod workspace, generate a new SSH key pair by ``ssh-keygen -f tempkey``. - 2. Save the private key as a secure environment variable in Gitpod using - ``gp env PRIVATE_SSH_KEY="$(<tempkey)"``, - or by using the `Gitpod UI <https://www.gitpod.io/docs/environment-variables#using-the-account-settings>`_. - 3. Register the public key with Trac following the instructions in :ref:`section-trac-ssh-key`. - 4. Close this Gitpod workspace. +1. In the running Gitpod workspace, generate a new SSH key pair by ``ssh-keygen -f tempkey``. +2. Save the private key as a secure environment variable in Gitpod using ``gp + env PRIVATE_SSH_KEY="$(<tempkey)"``, or by using the `Gitpod UI + <https://www.gitpod.io/docs/environment-variables#using-the-account-settings>`_. +3. Register the public key with GitHub following the instructions in :ref:`section-github-ssh-key`. +4. Close this Gitpod workspace. After following this procedure, every new Gitpod workspace will have a -working ``trac`` remote to which you can push your changes. +working ``origin`` remote to which you can push your changes. -You can also `use your VS Code Desktop <https://www.gitpod.io/docs/develop/vscode-desktop-support>`_ to keep +You can also `use your VS Code Desktop <https://www.gitpod.io/docs/develop/vscode-desktop-support>`_ to keep your local IDE configuration while still benefiting from Gitpodโ€™s high-spec servers and automated prebuilds. diff --git a/src/doc/en/faq/faq-contribute.rst b/src/doc/en/faq/faq-contribute.rst index 386e552b038..644715a0435 100644 --- a/src/doc/en/faq/faq-contribute.rst +++ b/src/doc/en/faq/faq-contribute.rst @@ -4,6 +4,7 @@ FAQ: Contributing to Sage ========================= + How can I start contributing to Sage? """"""""""""""""""""""""""""""""""""" @@ -11,10 +12,11 @@ The first step is to use Sage and encourage your friends to use Sage. If you find bugs or confusing documentation along the way, please report your problems! -Two popular ways to contribute to Sage are to write code and to -create documentation or tutorials. Some steps in each direction +Two popular ways to contribute to Sage are to write code and to +create documentation or tutorials. Some steps in each direction are described below. + I want to contribute code to Sage. How do I get started? """""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -22,19 +24,19 @@ Take a look at the `official development guide <https://doc.sagemath.org/html/en/developer>`_ for Sage. At a minimum, the first chapter in that guide is required reading for any Sage developer. Also pay special attention to the -`trac guidelines <https://doc.sagemath.org/html/en/developer/trac.html>`_. +`GitHub guidelines <https://doc.sagemath.org/html/en/developer/github.html>`_. You can also join the `sage-devel <https://groups.google.com/group/sage-devel>`_ mailing list or hang around on the `SageMath Zulip chat channel <https://sagemath.zulipchat.com/>`_. While you are getting to know the community, grab a copy of the Sage source and familiarize yourself with the -`git <https://git-scm.com>`_ version control system. +`git <https://git-scm.com>`_ version control system. The best way to become familiar with the Sage development process is -to choose a ticket from the -`trac server <https://trac.sagemath.org>`_ -and review the proposed changes contained in that ticket. If you want +to choose an issue from +`the Sage repository on GitHub <https://github.com/sagemath/sage/issues>`_ +and review the proposed changes contained in that issue. If you want to implement something, it is a good practice to discuss your ideas on the ``sage-devel`` mailing list first, so that other developers have a chance to comment on your ideas/proposals. They are pretty open to new @@ -53,7 +55,7 @@ optimization. In the following paper * D. Knuth. Structured Programming with go to Statements. *ACM Journal Computing Surveys*, 6(4), 1974. - + Don Knuth observes that: "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." @@ -72,20 +74,21 @@ by Steven F. Lott is suitable for anyone who is already comfortable with programming. If you want, you can -try to learn Python by using Sage. However, +try to learn Python by using Sage. However, it is helpful to know what is pure Python and when Sage is doing its "magic". There are many things that work in Python but not in Sage, -and vice versa. Furthermore, even when the syntax is identical, many -programming concepts are explained more thoroughly in Python-centered -resources than in Sage-centered resources; in the latter, +and vice versa. Furthermore, even when the syntax is identical, many +programming concepts are explained more thoroughly in Python-centered +resources than in Sage-centered resources; in the latter, mathematics is usually the priority. + I am not a programmer. Is there another way I can help out? """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" Yes. As with any free open source software project, there are numerous ways in which you could help out within the Sage community, and -programming is only one of many ways to contribute. +programming is only one of many ways to contribute. Many people like writing technical tutorials. One of the joys of doing so is that you also learn something new in the process. At the same @@ -155,6 +158,7 @@ resources can be found by a web search. by A. M. Kuchling * `reStructuredText <https://docutils.sourceforge.io/rst.html>`_ + Are there any coding conventions I need to follow? """""""""""""""""""""""""""""""""""""""""""""""""" @@ -164,13 +168,13 @@ Also consult the Sage Developer's Guide, especially the chapter `Conventions for Coding in Sage <https://doc.sagemath.org/html/en/developer/#sage-coding-details>`_. -I submitted a bug fix to the trac server several weeks ago. Why are you ignoring my branch? -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +I submitted a bug fix to the GitHub Sage repo several weeks ago. Why are you ignoring my branch? +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" We are not trying to ignore your branch. Most people who work on Sage do so -in their free time. With hundreds of open tickets of varying degrees of -impacts on the whole Sage community, people who work on tickets need -to prioritize their time and work on those tickets that interest +in their free time. With hundreds of open PRs of varying degrees of +impacts on the whole Sage community, people who work on PRs need +to prioritize their time and work on those PRs that interest them. Sometimes you may be the only person who understands your branch. In that case, you are encouraged to take extra care to make it as easy as possible for anyone to review. Here are some @@ -185,7 +189,7 @@ tips on making your branch easy to review: * Have you clearly described how your branch solves the problem under consideration? * Have you clearly described how to test the changes in your branch? -* Have you listed any tickets that your branch depends on? +* Have you listed any issues/PRs that your branch depends on? * Is your branch based on a recent (preferably, the latest) Sage beta version? * Does your branch `follow relevant conventions <https://doc.sagemath.org/html/en/developer/#writing-code-for-sage>`_ @@ -193,7 +197,7 @@ tips on making your branch easy to review: If your branch stands no chance of being merged in the Sage source tree, we will not ignore your branch but simply close the relevant -ticket with an explanation why we cannot include your changes. +PR with an explanation why we cannot include your changes. When and how might I remind the Sage community of a branch I care about? diff --git a/src/doc/en/faq/faq-general.rst b/src/doc/en/faq/faq-general.rst index 32fe20e6ffd..354df395e99 100644 --- a/src/doc/en/faq/faq-general.rst +++ b/src/doc/en/faq/faq-general.rst @@ -258,7 +258,7 @@ testing <../developer/portability_testing.html>`_ in the Developer's Guide for details. -With so many bugs in Sage and hundreds of open tickets, why don't you produce a stabilization release? +With so many bugs in Sage and hundreds of open issues, why don't you produce a stabilization release? """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Any software package contains bug. With something as complex as Sage, neither @@ -269,7 +269,7 @@ A Sage release cycle lasts for a few months, with several betas appearing at 1-2 week intervals, followed by several release candidates (as of 2022). Under this schedule and with the limited capacity of the Sage developer community, the project cannot make stabilization releases. However, important -bug fix tickets are merged with high priority and will be available in the +bug fix PRs are merged with high priority and will be available in the development release. Thanks to rigorous integration testing by our dedicated Release Manager, development releases (betas and release candidates) are generally safe and reliable to use. diff --git a/src/doc/en/faq/faq-usage.rst b/src/doc/en/faq/faq-usage.rst index 40e4be5ddec..a495ad7f4cc 100644 --- a/src/doc/en/faq/faq-usage.rst +++ b/src/doc/en/faq/faq-usage.rst @@ -115,7 +115,7 @@ issue these commands: import _tkinter import Tkinter -If they do not raise an ``ImportError`` then it worked. +If they do not raise an :class:`ImportError` then it worked. How do I import Sage into a Python script? @@ -322,7 +322,7 @@ ints. For example:: sage: RealNumber = float; Integer = int sage: from scipy import stats sage: stats.ttest_ind([1,2,3,4,5], [2,3,4,5,.6]) - Ttest_indResult(statistic=0.0767529..., pvalue=0.940704...) + Ttest...Result(statistic=0.0767529..., pvalue=0.940704...) sage: stats.uniform(0,15).ppf([0.5,0.7]) array([ 7.5, 10.5]) @@ -663,7 +663,7 @@ With objects a and b and a function f, I accidentally typed f(a) = b instead of It is because of how functions are defined in Sage with the ``f(x) = expr`` notation using the preparser. Also notice that if you make this mistake inside of an ``if`` statement, you will get a -``SyntaxError`` before anything else goes wrong. So in this case, +:class:`SyntaxError` before anything else goes wrong. So in this case, there is no problem. diff --git a/src/doc/en/faq/index.rst b/src/doc/en/faq/index.rst index 0c11bee9f11..1cc635f804e 100644 --- a/src/doc/en/faq/index.rst +++ b/src/doc/en/faq/index.rst @@ -5,8 +5,9 @@ .. _faq: -Welcome to the Sage FAQ! -======================== +=================== +Welcome to Sage FAQ +=================== This work is licensed under a `Creative Commons Attribution-Share Alike 3.0 License`__. With grateful thanks, we acknowledge it as being diff --git a/src/doc/en/installation/conda.rst b/src/doc/en/installation/conda.rst index df396777262..5228611de3b 100644 --- a/src/doc/en/installation/conda.rst +++ b/src/doc/en/installation/conda.rst @@ -143,6 +143,7 @@ Here we assume that you are using a git checkout. $ ./configure --with-python=$CONDA_PREFIX/bin/python \ --prefix=$CONDA_PREFIX \ $(for pkg in $(./sage -package list :standard: \ + --exclude rpy2 \ --has-file spkg-configure.m4 \ --has-file distros/conda.txt); do \ echo --with-system-$pkg=force; \ @@ -173,3 +174,12 @@ suffices to restart Sage. After editing any Cython files, rebuild the Sage library using:: $ pip install --no-build-isolation -v -v --editable src + +In order to update the conda environment later, you can run:: + + $ mamba env update --file src/environment-dev.yml --name sage-dev + +To build the documentation, use:: + + $ pip install --no-build-isolation -v -v --editable ./pkgs/sage-docbuild + $ sage --docbuild all html diff --git a/src/doc/en/installation/index.rst b/src/doc/en/installation/index.rst index b8ad5522062..9baf654f457 100644 --- a/src/doc/en/installation/index.rst +++ b/src/doc/en/installation/index.rst @@ -1,8 +1,8 @@ .. _installation-guide: -======================================= -Welcome to the Sage Installation Guide! -======================================= +================================== +Welcome to Sage Installation Guide +================================== If you are reading this manual at https://doc.sagemath.org/, note that it was built at the time the most recent stable release of SageMath @@ -25,7 +25,7 @@ macOS Obtain the SageMath sources via ``git`` as described in `The Sage Developer's Guide - <https://doc.sagemath.org/html/en/developer/walk_through.html#chapter-walkthrough>`_. + <https://doc.sagemath.org/html/en/developer/walkthrough.html#chapter-walkthrough>`_. - Then build SageMath from source as described in section :ref:`sec-installation-from-sources`. @@ -62,6 +62,8 @@ Windows `official WSL setup guide <https://docs.microsoft.com/en-us/windows/wsl/install-win10>`_. Be sure to do the steps to install WSL2 and set it as default. + Make sure to allocate enough RAM to WSL: 5GB is known to be enough, + 2GB might not allow you to build some packages. Then go to the Microsoft Store and install Ubuntu (or another Linux distribution). Start Ubuntu from the start menu. @@ -73,6 +75,8 @@ Windows `official WSL setup guide <https://docs.microsoft.com/en-us/windows/wsl/install-win10>`_. Be sure to do the steps to install WSL2 and set it as default. + Make sure to allocate enough RAM to WSL: 5GB is known to be enough, + 2GB might not allow you to build some packages. Then go to the Microsoft Store and install Ubuntu (or another Linux distribution). Start Ubuntu from the start menu. @@ -89,7 +93,7 @@ Linux Obtain the SageMath sources via ``git`` as described in `The Sage Developer's Guide - <https://doc.sagemath.org/html/en/developer/walk_through.html#chapter-walkthrough>`_. + <https://doc.sagemath.org/html/en/developer/walkthrough.html#chapter-walkthrough>`_. - Then build SageMath from source as described in section :ref:`sec-installation-from-sources`. diff --git a/src/doc/en/installation/launching.rst b/src/doc/en/installation/launching.rst index 543a47463f7..33019109960 100644 --- a/src/doc/en/installation/launching.rst +++ b/src/doc/en/installation/launching.rst @@ -29,6 +29,18 @@ To start a Jupyter Notebook instead of a Sage console, run the command instead of just ``sage``. To quit the Jupyter Notebook press ``<Ctrl> + <c>`` twice in the console where you launched the command. +You can pass extra parameters to this command. For example, + +.. CODE-BLOCK:: bash + + sage -n jupyter --port 8899 + +will run the Jupyter server on a port different from the default (8888). +In particular on WSL, this is very useful because Jupyter may not be able to +detect whether the default port is already taken by another instance of +Jupyter running in Windows. + + Environment variables --------------------- @@ -83,7 +95,8 @@ the internet, e.g. https://www.ssh.com/ssh/tunneling/example. WSL Post-installation steps --------------------------- -If you've installed Sage Math from source on WSL, there are a couple of extra steps you can do to make your life easier: +If you've installed SageMath from source on WSL, there are a couple of extra steps you can do to make your life easier: + Create a notebook launch script """"""""""""""""""""""""""""""" diff --git a/src/doc/en/installation/linux.rst b/src/doc/en/installation/linux.rst index 853659ba5e0..ec3b5e07ecf 100644 --- a/src/doc/en/installation/linux.rst +++ b/src/doc/en/installation/linux.rst @@ -21,5 +21,5 @@ distribution, consider upgrading your distribution. Gentoo users might want to give a try to `sage-on-gentoo <https://github.com/cschwan/sage-on-gentoo>`_. -The :trac:`Trac wiki page Distribution <wiki/Distribution>` collects information +The `GitHub wiki page Distribution <https://github.com/sagemath/sage/wiki/Distribution>` collects information regarding packaging and distribution of SageMath. diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index bd4b406baf1..b156165778b 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -257,9 +257,11 @@ Some additional optional packages are taken care of by: .. literalinclude:: homebrew-optional.txt +WSL prerequisites +^^^^^^^^^^^^^^^^^ Ubuntu on Windows Subsystem for Linux (WSL) prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sage can be installed onto Linux running on Windows Subsystem for Linux (WSL). These instructions describe a fresh install of Ubuntu 20.10, but other distributions or installation methods should work too, though have not been tested. @@ -283,11 +285,17 @@ Sage can be installed onto Linux running on Windows Subsystem for Linux (WSL). T From this point on, follow the instructions in the :ref:`sec-installation-from-sources-linux-recommended-installation` section. It is strongly recommended to put the Sage source files in the Linux file system, for example, in the ``/home/username/sage`` directory, and not in the Windows file system (e.g. ``/mnt/c/...``). +WSL permission denied error when building `packaging` package. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + You may encounter permission errors of the kind ``"[Errno 13] Permission denied: 'build/bdist.linux-x86_64/wheel/<package>.dist-info'"`` during ``make``. This usually comes from a permission conflict between the Windows and Linux file system. To fix it create a temporary build folder in the Linux file system using ``mkdir -p ~/tmp/sage`` and use it for building by ``eval SAGE_BUILD_DIR="~/tmp/sage" make``. Also see the `related Github issue <https://github.com/pypa/packaging-problems/issues/258>`_ for other workarounds. +WSL post-installation notes +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + When the installation is complete, you may be interested in :ref:`sec-launching-wsl-post-installation`. .. _section_cygwinprereqs: @@ -538,7 +546,7 @@ If sage: import _tkinter sage: import Tkinter -does not raise an ``ImportError``, then it worked. +does not raise an :class:`ImportError`, then it worked. .. _build-from-source-step-by-step: diff --git a/src/doc/en/reference/algebras/fusion_rings.rst b/src/doc/en/reference/algebras/fusion_rings.rst index 06d2473c558..c13523478b2 100644 --- a/src/doc/en/reference/algebras/fusion_rings.rst +++ b/src/doc/en/reference/algebras/fusion_rings.rst @@ -6,6 +6,7 @@ Fusion Rings sage/algebras/fusion_rings/fusion_ring sage/algebras/fusion_rings/f_matrix + sage/algebras/fusion_rings/fusion_double F-Matrix Backend ---------------- diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 1aae4090861..90c9a66ab87 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -48,6 +48,7 @@ Named associative algebras sage/algebras/clifford_algebra sage/algebras/cluster_algebra sage/combinat/descent_algebra + sage/algebras/down_up_algebra fusion_rings sage/algebras/hall_algebra sage/combinat/posets/incidence_algebras @@ -109,6 +110,7 @@ Non-associative algebras .. toctree:: :maxdepth: 1 + sage/algebras/octonion_algebra lie_algebras lie_conformal_algebras sage/algebras/jordan_algebra diff --git a/src/doc/en/reference/coercion/index.rst b/src/doc/en/reference/coercion/index.rst index d6d117cd263..27459609dc9 100644 --- a/src/doc/en/reference/coercion/index.rst +++ b/src/doc/en/reference/coercion/index.rst @@ -345,7 +345,7 @@ Methods to implement this case ``r * s`` gets handled as ``r._act_on_(s, True)`` or ``s._acted_upon_(r, False)`` and ``s * r`` as ``r._act_on_(s, False)`` or ``s._acted_upon_(r, True)``. There is no constraint on the type or parents - of objects passed to these methods; raise a ``TypeError`` or ``ValueError`` + of objects passed to these methods; raise a :class:`TypeError` or :class:`ValueError` if the wrong kind of object is passed in to indicate the action is not appropriate here. diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 3bfa10ed3f7..92ae74b30db 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -22,6 +22,7 @@ Comprehensive Module List sage/combinat/alternating_sign_matrix sage/combinat/backtrack sage/combinat/baxter_permutations + sage/combinat/bijectionist sage/combinat/binary_recurrence_sequences sage/combinat/binary_tree sage/combinat/blob_algebra @@ -142,7 +143,6 @@ Comprehensive Module List sage/combinat/integer_vector_weighted sage/combinat/integer_vectors_mod_permgroup sage/combinat/interval_posets - sage/combinat/k_regular_sequence sage/combinat/k_tableau sage/combinat/kazhdan_lusztig sage/combinat/key_polynomial @@ -205,6 +205,7 @@ Comprehensive Module List sage/combinat/quickref sage/combinat/ranker sage/combinat/recognizable_series + sage/combinat/regular_sequence sage/combinat/restricted_growth sage/combinat/ribbon sage/combinat/ribbon_shaped_tableau @@ -290,6 +291,7 @@ Comprehensive Module List sage/combinat/rsk sage/combinat/schubert_polynomial sage/combinat/set_partition + sage/combinat/set_partition_iterator sage/combinat/set_partition_ordered sage/combinat/sf/all sage/combinat/sf/character @@ -345,6 +347,7 @@ Comprehensive Module List sage/combinat/species/structure sage/combinat/species/subset_species sage/combinat/species/sum_species + sage/combinat/specht_module sage/combinat/subset sage/combinat/subsets_hereditary sage/combinat/subsets_pairwise @@ -366,7 +369,7 @@ Comprehensive Module List sage/combinat/tutorial sage/combinat/vector_partition sage/combinat/words/abstract_word - sage/combinat/words + sage/combinat/words/all sage/combinat/words/alphabet sage/combinat/words/finite_word sage/combinat/words/infinite_word diff --git a/src/doc/en/reference/curves/index.rst b/src/doc/en/reference/curves/index.rst index b95ab97f839..2bc0d098cba 100644 --- a/src/doc/en/reference/curves/index.rst +++ b/src/doc/en/reference/curves/index.rst @@ -10,6 +10,7 @@ Curves sage/schemes/curves/projective_curve sage/schemes/curves/point sage/schemes/curves/closed_point + sage/schemes/curves/zariski_vankampen sage/schemes/jacobians/abstract_jacobian diff --git a/src/doc/en/reference/finance/conf.py b/src/doc/en/reference/drinfeld_modules/conf.py similarity index 100% rename from src/doc/en/reference/finance/conf.py rename to src/doc/en/reference/drinfeld_modules/conf.py diff --git a/src/doc/en/reference/drinfeld_modules/index.rst b/src/doc/en/reference/drinfeld_modules/index.rst new file mode 100644 index 00000000000..d7485c9762e --- /dev/null +++ b/src/doc/en/reference/drinfeld_modules/index.rst @@ -0,0 +1,42 @@ +Drinfeld modules +==================================== + +SageMath include facilities to manipulate Drinfeld modules and their morphisms. The +main entry point is the class +:class:`sage.rings.function_field.drinfeld_modules.drinfeld_module.DrinfeldModule`. + +Drinfeld modules +---------------- + +.. toctree:: + :maxdepth: 2 + + sage/rings/function_field/drinfeld_modules/drinfeld_module + sage/rings/function_field/drinfeld_modules/finite_drinfeld_module + +Morphisms and isogenies +----------------------- + +.. toctree:: + :maxdepth: 2 + + sage/rings/function_field/drinfeld_modules/morphism + sage/rings/function_field/drinfeld_modules/homset + +The module action induced by a Drinfeld module +---------------------------------------------- + +.. toctree:: + :maxdepth: 2 + + sage/rings/function_field/drinfeld_modules/action + +The category of Drinfeld modules +-------------------------------- + +.. toctree:: + :maxdepth: 2 + + sage/categories/drinfeld_modules + +.. include:: ../footer.txt diff --git a/src/doc/en/reference/dynamics/index.rst b/src/doc/en/reference/dynamics/index.rst index 83cb7782f3a..e91f343c899 100644 --- a/src/doc/en/reference/dynamics/index.rst +++ b/src/doc/en/reference/dynamics/index.rst @@ -29,6 +29,7 @@ Arithmetic Dynamical Systems sage/dynamics/arithmetic_dynamics/product_projective_ds sage/dynamics/arithmetic_dynamics/wehlerK3 sage/dynamics/arithmetic_dynamics/berkovich_ds + sage/dynamics/arithmetic_dynamics/dynamical_semigroup .. SEEALSO:: diff --git a/src/doc/en/reference/finance/index.rst b/src/doc/en/reference/finance/index.rst deleted file mode 100644 index 2c0f62cbf3c..00000000000 --- a/src/doc/en/reference/finance/index.rst +++ /dev/null @@ -1,14 +0,0 @@ -Quantitative Finance -====================== - -.. toctree:: - :maxdepth: 1 - - sage/finance/stock - sage/finance/option - sage/finance/fractal - sage/finance/markov_multifractal - sage/finance/markov_multifractal_cython - - -.. include:: ../footer.txt diff --git a/src/doc/en/reference/function_fields/index.rst b/src/doc/en/reference/function_fields/index.rst index 50c04560a33..9f9a7e8c42d 100644 --- a/src/doc/en/reference/function_fields/index.rst +++ b/src/doc/en/reference/function_fields/index.rst @@ -11,13 +11,27 @@ algebraic closure of `\QQ`. :maxdepth: 1 sage/rings/function_field/function_field + sage/rings/function_field/function_field_rational + sage/rings/function_field/function_field_polymod sage/rings/function_field/element + sage/rings/function_field/element_rational + sage/rings/function_field/element_polymod sage/rings/function_field/order + sage/rings/function_field/order_rational + sage/rings/function_field/order_basis + sage/rings/function_field/order_polymod sage/rings/function_field/ideal + sage/rings/function_field/ideal_rational + sage/rings/function_field/ideal_polymod sage/rings/function_field/place + sage/rings/function_field/place_rational + sage/rings/function_field/place_polymod sage/rings/function_field/divisor sage/rings/function_field/differential sage/rings/function_field/valuation_ring + sage/rings/function_field/derivations + sage/rings/function_field/derivations_rational + sage/rings/function_field/derivations_polymod sage/rings/function_field/maps sage/rings/function_field/extensions sage/rings/function_field/constructor diff --git a/src/doc/en/reference/groups/index.rst b/src/doc/en/reference/groups/index.rst index e3df953c29a..97a7c126698 100644 --- a/src/doc/en/reference/groups/index.rst +++ b/src/doc/en/reference/groups/index.rst @@ -18,6 +18,7 @@ Groups sage/groups/braid sage/groups/cubic_braid sage/groups/indexed_free_group + sage/groups/artin sage/groups/raag sage/groups/cactus_group sage/groups/group_exp @@ -72,17 +73,24 @@ Matrix and Affine Groups sage/groups/matrix_gps/catalog sage/groups/matrix_gps/matrix_group + sage/groups/matrix_gps/matrix_group_gap sage/groups/matrix_gps/group_element + sage/groups/matrix_gps/group_element_gap sage/groups/matrix_gps/finitely_generated + sage/groups/matrix_gps/finitely_generated_gap sage/groups/matrix_gps/morphism sage/groups/matrix_gps/homset sage/groups/matrix_gps/binary_dihedral sage/groups/matrix_gps/coxeter_group sage/groups/matrix_gps/linear + sage/groups/matrix_gps/linear_gap sage/groups/matrix_gps/orthogonal + sage/groups/matrix_gps/orthogonal_gap sage/groups/matrix_gps/isometries sage/groups/matrix_gps/symplectic + sage/groups/matrix_gps/symplectic_gap sage/groups/matrix_gps/unitary + sage/groups/matrix_gps/unitary_gap sage/groups/matrix_gps/heisenberg sage/groups/affine_gps/affine_group sage/groups/affine_gps/euclidean_group @@ -115,5 +123,6 @@ Internals :maxdepth: 1 sage/groups/matrix_gps/named_group + sage/groups/matrix_gps/named_group_gap .. include:: ../footer.txt diff --git a/src/doc/en/reference/index.rst b/src/doc/en/reference/index.rst index c91bbc02de9..646f7c76680 100644 --- a/src/doc/en/reference/index.rst +++ b/src/doc/en/reference/index.rst @@ -1,8 +1,8 @@ .. _reference-manual: -************************************* -Welcome to the Sage Reference Manual! -************************************* +******************************** +Welcome to Sage Reference Manual +******************************** Here you find documentation for all of `Sage <http://www.sagemath.org/>`_'s features, illustrated with lots of examples. A thematic index follows. @@ -66,7 +66,6 @@ Probability and Statistics * :doc:`Probability <probability/index>` * :doc:`Statistics <stats/index>` -* :doc:`Quantitative Finance <finance/index>` Mathematical Structures ----------------------- @@ -115,6 +114,7 @@ Number Fields, Function Fields, and Valuations * :doc:`Number Fields <number_fields/index>` * :doc:`Function Fields <function_fields/index>` * :doc:`Discrete Valuations <valuations/index>` +* :doc:`Drinfeld Modules <drinfeld_modules/index>` Number Theory ------------- diff --git a/src/doc/en/reference/interfaces/index.rst b/src/doc/en/reference/interfaces/index.rst index 67d69886285..7d030df056d 100644 --- a/src/doc/en/reference/interfaces/index.rst +++ b/src/doc/en/reference/interfaces/index.rst @@ -99,7 +99,6 @@ and testing to make sure nothing funny is going on). sage/interfaces/povray sage/interfaces/psage sage/interfaces/qepcad - sage/interfaces/qsieve sage/interfaces/r sage/interfaces/rubik sage/interfaces/sage0 diff --git a/src/doc/en/reference/libs/index.rst b/src/doc/en/reference/libs/index.rst index fd0295e60c6..0fde7b179e0 100644 --- a/src/doc/en/reference/libs/index.rst +++ b/src/doc/en/reference/libs/index.rst @@ -45,6 +45,7 @@ FLINT sage/libs/flint/flint sage/libs/flint/fmpz_poly sage/libs/flint/arith + sage/libs/flint/qsieve Giac ---- diff --git a/src/doc/en/reference/matrices/index.rst b/src/doc/en/reference/matrices/index.rst index 25aed6c2cb3..89453635472 100644 --- a/src/doc/en/reference/matrices/index.rst +++ b/src/doc/en/reference/matrices/index.rst @@ -79,6 +79,7 @@ objects like operation tables (e.g. the multiplication table of a group). sage/matrix/matrix_modn_dense_float sage/matrix/matrix_modn_sparse sage/matrix/matrix_symbolic_dense + sage/matrix/matrix_symbolic_sparse sage/matrix/matrix_complex_double_dense sage/matrix/matrix_complex_ball_dense sage/matrix/matrix_polynomial_dense @@ -93,6 +94,8 @@ objects like operation tables (e.g. the multiplication table of a group). sage/matrix/matrix_misc sage/matrix/matrix_window sage/matrix/misc + sage/matrix/misc_mpfr + sage/matrix/misc_flint sage/matrix/symplectic_basis sage/matrix/compute_J_ideal diff --git a/src/doc/en/reference/misc/index.rst b/src/doc/en/reference/misc/index.rst index 8a26fcb9a00..0b660cd9732 100644 --- a/src/doc/en/reference/misc/index.rst +++ b/src/doc/en/reference/misc/index.rst @@ -68,17 +68,6 @@ Database Access sage/databases/sql_db -Media -~~~~~ - -.. toctree:: - :maxdepth: 1 - - sage/structure/graphics_file - sage/media/wav -.. underscore-methods only -.. sage/media/channels - Warnings ~~~~~~~~ @@ -141,44 +130,6 @@ Fast Expression Evaluation .. sage/ext/interpreters/wrapper_rdf .. sage/ext/interpreters/wrapper_rr -Features -~~~~~~~~ - -.. toctree:: - :maxdepth: 1 - - sage/features - sage/features/join_feature - sage/features/all - sage/features/sagemath - sage/features/pkg_systems - sage/features/bliss - sage/features/csdp - sage/features/databases - sage/features/dvipng - sage/features/ffmpeg - sage/features/four_ti_2 - sage/features/gap - sage/features/graph_generators - sage/features/graphviz - sage/features/imagemagick - sage/features/interfaces - sage/features/internet - sage/features/kenzo - sage/features/latex - sage/features/latte - sage/features/lrs - sage/features/mcqd - sage/features/meataxe - sage/features/mip_backends - sage/features/normaliz - sage/features/pandoc - sage/features/pdf2svg - sage/features/polymake - sage/features/rubiks - sage/features/tdlib - - Code Evaluation --------------- @@ -311,7 +262,7 @@ Miscellaneous Inspection and Development Tools .. toctree:: :maxdepth: 1 - sage/docs/instancedoc + sage/misc/instancedoc sage/misc/sageinspect sage/misc/edit_module sage/misc/classgraph diff --git a/src/doc/en/reference/modules/index.rst b/src/doc/en/reference/modules/index.rst index c6109643c35..93a337db04c 100644 --- a/src/doc/en/reference/modules/index.rst +++ b/src/doc/en/reference/modules/index.rst @@ -29,7 +29,7 @@ Modules with basis .. toctree:: :maxdepth: 1 - sage/modules/with_basis/__init__ + sage/modules/with_basis/all sage/modules/with_basis/cell_module sage/modules/with_basis/indexed_element sage/modules/with_basis/invariant @@ -99,13 +99,19 @@ Vectors :maxdepth: 1 sage/modules/vector_integer_dense + sage/modules/vector_integer_sparse sage/modules/vector_mod2_dense sage/modules/vector_modn_dense + sage/modules/vector_modn_sparse sage/modules/vector_rational_dense + sage/modules/vector_rational_sparse sage/modules/vector_symbolic_dense + sage/modules/vector_symbolic_sparse sage/modules/vector_callable_symbolic_dense sage/modules/vector_double_dense sage/modules/vector_real_double_dense + sage/modules/vector_numpy_dense + sage/modules/vector_numpy_integer_dense sage/modules/vector_complex_double_dense sage/modules/complex_double_vector sage/modules/real_double_vector diff --git a/src/doc/en/reference/polynomial_rings/index.rst b/src/doc/en/reference/polynomial_rings/index.rst index 8a8ef70563c..b03fa4279ca 100644 --- a/src/doc/en/reference/polynomial_rings/index.rst +++ b/src/doc/en/reference/polynomial_rings/index.rst @@ -45,6 +45,7 @@ Laurent Polynomials .. toctree:: :maxdepth: 1 + sage/rings/polynomial/laurent_polynomial_ring_base sage/rings/polynomial/laurent_polynomial_ring sage/rings/polynomial/laurent_polynomial sage/rings/polynomial/omega diff --git a/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst b/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst index 414c04bb611..97cff1bb835 100644 --- a/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst +++ b/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst @@ -43,3 +43,5 @@ whereas others have multiple bases. sage/rings/polynomial/polynomial_compiled sage/rings/polynomial/polynomial_fateman + + sage/rings/polynomial/integer_valued_polynomials diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 7bef2a9a4e5..fd795532c00 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -43,6 +43,10 @@ REFERENCES: University of New South Wales, 1995 +.. [Ab2022] Willie Aboumrad, + *Quantum compution with anyons: an F-matrix and braid calculator* + (2022). https://arxiv.org/abs/2212.00831 + .. [AB2007] \M. Aschenbrenner, C. Hillar, *Finite generation of symmetric ideals*. Trans. Amer. Math. Soc. 359 (2007), no. 11, 5171--5192. @@ -347,6 +351,10 @@ REFERENCES: *Characteristic polynomials of subspace arrangements and finite fields*. Advances in Mathematics, 122(2):193-233, 1996. +.. [Ath2000] \C. A. Athanasiadis, + *Deformations of Coxeter hyperplane arrangements and their characteristic polynomials*. + Adv. Stud. Pure Math., 27, 2000. + .. [Av2000] \D. Avis, *A revised implementation of the reverse search vertex enumeration algorithm.* Polytopes-combinatorics and computation. Birkhauser Basel, 2000. @@ -624,7 +632,7 @@ REFERENCES: and variants*. :arxiv:`1810.00789` -.. [BDKR2013] \D. Best, D.Z. Dokovic, H. Kharaghani and H. Ramp. +.. [BDKR2013] \D. Best, D.ลฝ. ฤokoviฤ‡, H. Kharaghani and H. Ramp. *Turyn-Type Sequences: Classification, Enumeration, and Construction*, Journal of Combinatorial Designs 21(1) (2013): 24-35. :doi:`10.1002/jcd.21318` @@ -803,6 +811,14 @@ REFERENCES: Stein. strassen_window_multiply_c. strassen.pyx, Sage 3.0, 2008. http://www.sagemath.org +.. [BHS2023] Jose Bastidas, Christophe Hohlweg, and Franco Saliola. + *The primitive Eulerian polynomial*. + Preprint, (2023) :arxiv:`2306.15556`. + +.. [BrHu2019] Petter Brรคndรฉn, June Huh. *Lorentzian polynomials*. + Ann. Math. (2) 192, No. 3, 821-891 (2020). + :arxiv:`1902.03719`, :doi:`10.4007/annals.2020.192.3.4`. + .. [BHNR2004] \S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the Palindromic Complexity of Infinite Words, in J. Berstel, J. Karhumaki, D. Perrin, Eds, @@ -1092,6 +1108,9 @@ REFERENCES: complexes and combinatorics of simplicial manifolds," *Uspekhi Mat. Nauk* 55 (2000), 171--172. +.. [BP2014] \V. M. Bukhshtaber and T. E. Panov. "Toric Topology", + 2014. :arxiv:`1210.2368` + .. [BP2015] \P. Butera and M. Pernici "Sums of permanental minors using Grassmann algebra", International Journal of Graph Theory and its Applications, 1 (2015), @@ -1119,6 +1138,10 @@ REFERENCES: Achtzelle (Oktatope)", Verhand. Konik. Akad. Wetenschap, Erste Sectie, 10 (1910) +.. [BR1998] Georgia Benkart and Tom Roby. *Down-up algebras*. + J. Algebra, **209** no. 1 (1999), pp. 305-335. + :doi:`10.1006/jabr.1998.7511`. + .. [Br2000] Kenneth S. Brown, *Semigroups, rings, and Markov chains*, :arxiv:`math/0006145v1`. @@ -1180,6 +1203,9 @@ REFERENCES: moduli spaces to Feynman integrals*, in Contemporary Mathematics vol 539, pages 27-52, 2011. +.. [Bro2013] Francis Brown, *Single-valued motivic periods and multiple zeta + values*, Forum Math. Sigma 2 (2014), :doi:`10.1017/fms.2014.18`. + .. [Bro2016] \A.E. Brouwer, Personal communication, 2016. @@ -1216,6 +1242,11 @@ REFERENCES: Proc. London Math. Soc. (3) **77** (1998), 551โ€“581. :mathscinet:`MR1643413` +.. [BS1969] \D. Blatt, G. Szekeres. + *A Skew Hadamard Matrix of Order 52*, + Canadian Journal of Mathematics 21 (1969): 1319-1322. + :doi:`10.4153/CJM-1969-144-2` + .. [BS1996] Eric Bach, Jeffrey Shallit. *Algorithmic Number Theory, Vol. 1: Efficient Algorithms*. MIT Press, 1996. ISBN 978-0262024051. @@ -1357,6 +1388,10 @@ REFERENCES: 20(1.6):1-18, 2015. :doi:`10.1145/2780652` or [`<https://hal.inria.fr/hal-01182890>`_]. +.. [CS1999a] \D. Cohen and A. Suciu. *Characteristic varieties of arrangements*. + Math. Proc. Cambridge Philos. Soc.127 (1999), no.1, 33โ€“-53. + :doi:`10.1017/S0305004199003576`. + .. [CCLSV2005] \M. Chudnovsky, G. Cornuejols, X. Liu, P. Seymour, K. Vuskovic. *Recognizing berge graphs*. Combinatorica vol 25 (2005), n 2, pages 143--186. @@ -1474,6 +1509,9 @@ REFERENCES: .. [Conr] Keith Conrad, "Artin-Hasse-Type Series and Roots of Unity", http://www.math.uconn.edu/~kconrad/blurbs/gradnumthy/AHrootofunity.pdf +.. [Coron2023] Basile Coron *Supersolvability of built lattices and Koszulness + of generalized Chow rings*. Preprint, :arxiv:`2302.13072` (2023). + .. [CGMRV16] \A. Conte, R. Grossi, A. Marino, R. Rizzi, L. Versari, "Directing Road Networks by Listing Strong Orientations.", Combinatorial Algorithms, Proceedings of 27th International Workshop, @@ -1539,6 +1577,10 @@ REFERENCES: and Monographs*. American Mathematical Society, Providence, RI, 1999. +.. [Cox1989] David A. Cox. + Primes of the form `x^2+ny^2`. + Wiley, 1989. + .. [CK2008] Derek G. Corneil and Richard M. Krueger, *A Unified View of Graph Searching*, SIAM Jounal on Discrete Mathematics, 22(4), 1259โ€“-1276, 2008. @@ -1596,6 +1638,10 @@ REFERENCES: \J. Algebr. Comb. **39** (2014) pp. 17-51. :doi:`10.1007/s10801-013-0437-x`, :arxiv:`1108.1776`. +.. [CM2000] Paula A.A.B. Carvalho and Ian M. Musson. *Down-up algebras and + their representation theory*. J. Algebra. **228** no. 1, (2000), + pp. 286-310. :doi:`10.1006/jabr.1999.8263` + .. [CM2012] \M. Cabanes, I. Marin, *On ternary quotients of cubic Hecke algebras*, Comm. Math. Phys. (2012), Volume 314, Issue 1, pp 57-92. :doi:`10.1007/s00220-012-1519-7`, :arxiv:`1010.1465`. @@ -1635,6 +1681,11 @@ REFERENCES: .. [CrNa2020] \J.E. Cremona and F. Najman, `\QQ`-curves over odd degree number fields, :arxiv:`2004.10054`. +.. [CreSuth2023] \J.E. Cremona and A.V. Sutherland. + *Computing the endomorphism ring of an elliptic curve + over a number field*. + :arxiv:`2301.11169`. + .. [CoCo1] J.H. Conway, H.S.M. Coxeter *Triangulated polygons and frieze patterns*, The Mathematical Gazette (1973) 57 p.87-94 @@ -1794,6 +1845,11 @@ REFERENCES: *Tracking p-adic precision*, LMS J. Comput. Math. **17** (2014), 274-294. +.. [Connell1999] Ian Connell. + *Elliptic Curve Handbook*. + Online lecture notes, available at + https://git.hackade.org/ben/tinycrypt/raw/branch/master/docs/Elliptic%20Curve%20Handbook.pdf + .. [CS1986] \J. Conway and N. Sloane. *Lexicographic codes: error-correcting codes from game theory*, IEEE Trans. Infor. Theory **32** (1986) 337-348. @@ -1859,9 +1915,9 @@ REFERENCES: .. [CW2005] \J. E. Cremona and M. Watkins. Computing isogenies of elliptic curves. preprint, 2005. -.. [CHW2015] Shawn X.; Hong, Seung-Moon; Wang, Zhenghan Universal quantum computation +.. [CHW2015] Cui, Shawn X.; Hong, Seung-Moon; Wang, Zhenghan Universal quantum computation with weakly integral anyons. Quantum Inf. Process. 14 (2015), - no. 8, 2687-2727. + no. 8, 2687-2727. .. [CW2015] Cui, S. X. and Wang, Z. (2015). Universal quantum computation with metaplectic anyons. Journal of Mathematical Physics, 56(3), 032202. @@ -1980,6 +2036,11 @@ REFERENCES: .. [DeVi1984] \M.-P. Delest, and G. Viennot, *Algebraic Languages and Polyominoes Enumeration.* Theoret. Comput. Sci. 34, 169-206, 1984. +.. [DJP2014] Luca De Feo, David Jao and Jรฉrรดme Plรปt: Towards quantum-resistant + cryptosystems from supersingular elliptic curve isogenies. Journal + of Mathematical Cryptology, vol. 8, no. 3, 2014, pp. 209-247. + https://eprint.iacr.org/2011/506.pdf + .. [DFMS1996] Philipppe Di Francesco, Pierre Mathieu, and David Sรฉnรฉchal. *Conformal Field Theory*. Graduate Texts in Contemporary Physics, Springer, 1996. @@ -2001,6 +2062,11 @@ REFERENCES: Lexicographically: an efficient new strategy compared with others, 2020, https://hal.archives-ouvertes.fr/hal-02462764v1 +.. [DGK2014] \D. ฤokoviฤ‡, O. Golubitsky and I.Kotsireas. + *Some New Orders of Hadamard and Skew-Hadamard Matrices*, + Journal of Combinatorial Designs 22(6) (2014): 270-277. + :doi:`10.1002/jcd.21358` + .. [DGMPPS2019] \N. Datta, A. Ghoshal, D. Mukhopadhyay, S. Patranabis, S. Picek, R. Sashukhan. "TRIFLE" https://csrc.nist.gov/CSRC/media/Projects/Lightweight-Cryptography/documents/round-1/spec-doc/trifle-spec.pdf @@ -2041,18 +2107,59 @@ REFERENCES: and some constructions of de Luca and Rauzy*, Theoret. Comput. Sci. 255 (2001) 539--553. -.. [Djo1992] \D. ฤokoviฤ‡. +.. [Djo1992a] \D. ฤokoviฤ‡. *Construction of some new Hadamard matrices*, Bulletin of the Australian Mathematical Society 45(2) (1992): 327-332. :doi:`10.1017/S0004972700030185` -.. [Djo1994] \D. ฤokoviฤ‡. +.. [Djo1992b] \D. ฤokoviฤ‡. + *Skew Hadamard matrices of order 4 x 37 and 4 x 43*, + Journal of Combinatorial Theory, Series A 61(2) (1992): 319-321. + :doi:`10.1016/0097-3165(92)90029-T` + +.. [Djo1992c] \D. ฤokoviฤ‡. + *Ten New Orders for Hadamard Matrices of Skew Type*, + Publikacije Elektrotehniฤkog fakulteta. Serija Matematika 2 (1992): 47-59. + +.. [Djo1994a] \D. ฤokoviฤ‡. *Five New Orders for Hadamard Matrices of Skew Type*, Australasian Journal of Combinatorics 10 (1994): 259-264. +.. [Djo1994b] \D. ฤokoviฤ‡. + *Two Hadamard matrices of order 956 of Goethals-Seidel type*, + Combinatorica 14(3) (1994): 375-377. + :doi:`10.1007/BF01212983` + +.. [Djo2008a] \D. ฤokoviฤ‡. + *Skew-Hadamard matrices of orders 188 and 388 exist*, + International Mathematical Forum 3 no.22 (2008): 1063-1068. + :arxiv:`0704.0640` + +.. [Djo2008b] \D. ฤokoviฤ‡. + *Skew-Hadamard matrices of orders 436, 580 and 988 exist*, + Journal of Combinatorial Designs 16 (2008): 493-498. + :arxiv:`0706.1973` + +.. [Djo2008c] \D. ฤokoviฤ‡. + *Hadamard matrices of order 764 exist*, + Combinatorica 28(4) (2008): 487-489. + :doi:`10.1007/s00493-008-2384-z` + +.. [Djo2023a] \D. ฤokoviฤ‡. + *Skew-Hadamard matrices of order 276*. + :arxiv:`10.48550/ARXIV.2301.02751` + +.. [Djo2023b] \D. ฤokoviฤ‡, Email Communication. 26 January 2023. + .. [DK2013] John R. Doyle and David Krumm, *Computing algebraic numbers of bounded height*, :arxiv:`1111.4963v4` (2013). +.. [DK2016] \D. รokovic, I. Kotsireas. + *A class of cyclic (v; k1, k2, k3; ฮป) difference families + with v = 3 (mod 4) a prime*, + Special Matrices 4(1) (2016): 317-325. + :doi:`10.1515/spma-2016-0029` + .. [DLHK2007] \J. A. De Loera, D. C. Haws, M. Kรถppe, Ehrhart polynomials of matroid polytopes and polymatroids. Discrete & Computational Geometry, Volume @@ -2200,7 +2307,7 @@ REFERENCES: .. [Dy1993] \M. J. Dyer. *Hecke algebras and shellings of Bruhat intervals*. Compositio Mathematica, 1993, 89(1): 91-115. -.. [Dy1994] \M. J. Dyer. *Bruhat intervals, polyhedral cones and +.. [Dy1994] \M. J. Dyer. *Bruhat intervals, polyhedral cones and Kazhdan-Lusztig-Stanley polynomials*. Math.Z., 215(2):223-236, 1994. .. _ref-E: @@ -2397,6 +2504,11 @@ REFERENCES: code, by I.A.Faradjev (with contributions by A.E.Brouwer, D.V.Pasechnik). https://github.com/dimpase/coco +.. [FKS2004] \R. J. Fletcher, C. Koukouvinos and J. Seberry. + *New skew-Hadamard matrices of order 4ยท59 and new D-optimal designs of order 2ยท59*, + Discrete Mathematics 286(3) (2004): 251-253. + :doi:`10.1016/j.disc.2004.05.009` + .. [FL2001] David Forge and Michel Las Vergnas. *Orlik-Solomon type algebras*. European J. Combin. **22** (5), (2001). pp. 699-704. @@ -2564,6 +2676,12 @@ REFERENCES: TR-737-05, (2005). ftp://ftp.cs.princeton.edu/reports/2005/737.pdf +.. [Gek1988] \E.-U. Gekeler, On the coefficients of Drinfel'd modular + forms. Invent. Math. 93 (1988), no. 3, 667-700 + +.. [Gek1991] \E.-U. Gekeler. On finite Drinfeld modules. Journal of + algebra, 1(141):187โ€“203, 1991. + .. [GG2012] Jim Geelen and Bert Gerards, Characterizing graphic matroids by a system of linear equations, submitted, 2012. Preprint: @@ -2620,6 +2738,14 @@ REFERENCES: .. [GJ2007] \A. Glen, J. Justin, Episturmian words: a survey, Preprint, 2007, :arxiv:`0801.1655`. +.. [Goff1999] Christopher Goff. *Isomorphic fusion algebras of twisted quantum + doubles of finite groups*. PhD Thesis, + University of California, Santa Cruz. 1999. + +.. [GoMa2010] Christopher Goff and Geoffrey Mason, + *Generalized twisted quantum doubles and the McKay correspondence*, + J. Algebra 324 (2010), no. 11, 3007โ€“3016. + .. [GJ2016] Muddappa Seetharama Gowda and Juyoung Jeong. Spectral cones in Euclidean Jordan algebras. Linear Algebra and its Applications, 509:286-305, 2016. @@ -2669,6 +2795,10 @@ REFERENCES: .. [GL1996] \G. Golub and C. van Loan. *Matrix Computations*. 3rd edition, Johns Hopkins Univ. Press, 1996. +.. [GL2019] \J. Grbiฤ‡ and A. Linton. + "Lowest-degree triple Massey products in moment-angle complexes", + 2019. :arxiv:`1908.02222v2` + .. [GrLe1996] \J. Graham and G.I. Lehrer *Cellular algebras*. Invent. Math. 123 (1996), 1โ€“34. :mathscinet:`MR1376244` @@ -2727,6 +2857,9 @@ REFERENCES: .. [Gos1972] Bill Gosper, "Continued Fraction Arithmetic" https://perl.plover.com/classes/cftalk/INFO/gosper.txt +.. [Gos1998] \D. Goss. Basic structures of function field arithmetic. Springer, + 1998. + .. [Gor1980] Daniel Gorenstein, Finite Groups (New York: Chelsea Publishing, 1980) @@ -2927,6 +3060,9 @@ REFERENCES: .. [Har1994] Frank Harary. *Graph Theory*. Reading, MA: Addison-Wesley, 1994. +.. [Har2009] Harvey, David. *Efficient computation of p-adic heights*. + LMS J. Comput. Math. **11** (2008), 40โ€“59. + .. [Harako2020] Shuichi Harako. *The second homology group of the commutative case of Kontsevich's symplectic derivation Lie algebra*. Preprint, 2020, :arxiv:`2006.06064`. @@ -2988,8 +3124,9 @@ REFERENCES: with tunable clustering*, Phys. Rev. E (2002). vol 65, no 2, 026107. :doi:`10.1103/PhysRevE.65.026107`. -.. [HKL2021] Clemens Heuberger, Daniel Krenn, Gabriel F. Lipnik, "Asymptotic - Analysis of `q`-Recursive Sequences", :arxiv:`2105.04334`, 2021. +.. [HKL2022] Clemens Heuberger, Daniel Krenn, Gabriel F. Lipnik, "Asymptotic + Analysis of `q`-Recursive Sequences". Algorithmica **84** (2022), + 2480โ€“2532. :doi:`10.1007/s00453-022-00950-y`. .. [HKOTY1999] \G. Hatayama, A. Kuniba, M. Okado, T. Tagaki, and Y. Yamada, *Remarks on fermionic formula*. Contemp. Math., **248** (1999). @@ -3207,6 +3344,11 @@ REFERENCES: Designs, Codes and Cryptography 8 (1996) 145-157. :doi:`10.1023/A:1018037025910`. +.. [HMMS2019] June Huh, Jacob P. Matherne, Karola Mรฉszรกros, Avery St. Dizier. + *Logarithmic concavity of Schur and related polynomials*. + Trans. Am. Math. Soc. 375, No. 6, 4411-4427 (2022). + :arxiv:`1906.09633`, :doi:`10.1090/tran/8606`. + .. [Hutz2007] \B. Hutz. Arithmetic Dynamics on Varieties of dimension greater than one. PhD Thesis, Brown University 2007 @@ -3415,7 +3557,7 @@ REFERENCES: :doi:`10.1016/j.bbr.2011.03.031`, :arxiv:`0909.2442`. .. [JS2021] \D. Jahn, C. Stump. - *Bruhat intervals, subword complexes and brick polyhedra for + *Bruhat intervals, subword complexes and brick polyhedra for finite Coxeter groups*, 2021, :arxiv:`2103.03715`. .. [JV2000] \J. Justin, L. Vuillon, *Return words in Sturmian and @@ -3631,6 +3773,11 @@ REFERENCES: .. [KMOY2007] \M. Kashiwara, K. C. Misra, M. Okado, D. Yamada. *Perfect crystals for* `U_q(D_4^{(3)})`, J. Algebra. **317** (2007). +.. [Klaise2012] Janis Klaise. + *Orders in imaginary quadratic fields of small class number* + University of Warwick Undergraduate Masters thesis, unpublished (2012). + https://warwick.ac.uk/fac/cross_fac/complexity/people/students/dtc/students2013/klaise/janis_klaise_ug_report.pdf + .. [KMR2012] \A. Kleshchev, A. Mathas, and A. Ram, *Universal Specht modules for cyclotomic Hecke algebras*, Proc. London Math. Soc. (2012) 105 (6): 1245-1289. @@ -3830,6 +3977,7 @@ REFERENCES: set as the intersection of super greedy linear extensions. Order 4, 293-311 (1987). :doi:`10.1007/BF00337892` + .. [Kuh1987] \W. Kรผhnel, "Minimal triangulations of Kummer varieties", Abh. Math. Sem. Univ. Hamburg 57 (1987), 7-20. @@ -4092,6 +4240,11 @@ REFERENCES: of a genus 2 Jacobian*, Mathematics of Computation 88 (2019), 889-929. :doi:`10.1090/mcom/3358`. +.. [Lon2013] \S. London, + *Constructing New Turyn Type Sequences, T-Sequences and Hadamard Matrices*. + PhD Thesis, University of Illinois at Chicago, 2013. + https://hdl.handle.net/10027/9916 + .. [LOS2012] \C. Lecouvey, M. Okado, M. Shimozono. "Affine crystals, one-dimensional sums and parabolic Lusztig `q`-analogues". Mathematische Zeitschrift. **271** (2012). Issue 3-4. @@ -4330,6 +4483,10 @@ REFERENCES: .. [Mat2002] Jiล™รญ Matousek, "Lectures on Discrete Geometry", Springer, 2002 +.. [Mas1995] Mason, Geoffrey. *The quantum double of a finite group and its role + in conformal field theory*. Groups '93 Galway/St. Andrews, Vol. 2, + 405-417, London Math. Soc. Lecture Note Ser., 212, Cambridge, 1995. + .. [Ma2009] Sarah Mason, An Explicit Construction of Type A Demazure Atoms, Journal of Algebraic Combinatorics, Vol. 29, (2009), No. 3, p.295-313. :arxiv:`0707.4267` @@ -4446,6 +4603,9 @@ REFERENCES: .. [Mil1974] \J. W. Milnor and J. D. Stasheff, *Characteristic Classes*, University Press, Princeton and Tokyo, 1974. +.. [Mil2006] \J. W. Milnor, *On Lattes maps*, + Dynamics on the Riemann sphere, Eur. Math. Soc., 9โ€“43 + .. [Mil1978] \S. Milne, *A q-analog of restricted growth functions, Dobinskyโ€™s equality and Charlier polynomials*. Trans. Amer. Math. Soc., 245 (1978), @@ -4467,6 +4627,11 @@ REFERENCES: .. [Mit2008] \A. Mitra. *On the construction of M-sequences via primitive polynomials with a fast identification method*, International Journal of Electronics and Communication Engineering 2(9) (2008): 1991-1996. +.. [Miy1991] \M. Miyamoto. + *A construction of Hadamard matrices*, + Journal of Combinatorial Theory, Series A 57(1) (1991): 86-108. + :doi:`10.1016/0097-3165(91)90008-5` + .. [MKO1998] Hans Munthe--Kaas and Brynjulf Owren. *Computations in a free Lie algebra*. (1998). `Downloadable from Munthe-Kaas's website @@ -4592,21 +4757,30 @@ REFERENCES: Int. Math. Res. Not. (2015). :doi:`10.1093/imrn/rnv194`, :arxiv:`1408.0320`. +.. [MS2019] \Y. Musleh and \'E. Schost. Computing the characteristic polynomial + of a finite rank two Drinfeld module. In Proceedings of the 2019 + ACM on International Symposium on Symbolic and Algebraic + Computation, pages 307โ€“314. ACM, 2019. + .. [MSSY2001] Mateescu, A., Salomaa, A., Salomaa, K. and Yu, S., *A sharpening of the Parikh mapping*. Theoret. Informatics Appl. 35 (2001) 551-564. +.. [MST2006] Barry Mazur, William Stein, John Tate. + *Computation of p-adic heights and log convergence*. + Doc. Math. 2006, Extra Vol., 577-614. + .. [MSZ2013] Michael Maschler, Solan Eilon, and Zamir Shmuel. *Game Theory*. Cambridge: Cambridge University Press, (2013). ISBN 9781107005488. -.. [MT1991] Mazur, B., & Tate, J. (1991). The `p`-adic sigma - function. Duke Mathematical Journal, 62(3), 663-688. +.. [MT1991] Mazur, B., & Tate, J. (1991). *The `p`-adic sigma + function*. Duke Mathematical Journal, **62** (3), 663-688. -.. [MTT1986] \B. Mazur, J. Tate, and J. Teitelbaum, On `p`-adic - analogues of the conjectures of Birch and - Swinnerton-Dyer, Inventiones Mathematicae 84, (1986), - 1-48. +.. [MTT1986] \B. Mazur, J. Tate, and J. Teitelbaum, + *On `p`-adic analogues of the conjectures of Birch and + Swinnerton-Dyer*, + Inventiones Mathematicae **84**, (1986), 1-48. .. [Mu1997] Murty, M. Ram. *Congruences between modular forms*. In "Analytic Number Theory" (ed. Y. Motohashi), London Math. Soc. Lecture Notes @@ -4798,6 +4972,11 @@ REFERENCES: Electronic Journal of Linear Algebra, 34:444-458, 2018, :doi:`10.13001/1081-3810.3782`. +.. [ORS2013] Peter Ozsvath, Jacob Rasmussen, Zoltan Szabo, + *Odd Khovanov homology*, + Algebraic & Geometric Topology 13 (2013) 1465โ€“1488, + :doi:`10.2140/agt.2013.13.1465`. + .. [ORV] Grigori Olshanski, Amitai Regev, Anatoly Vershik, *Frobenius-Schur functions*, :arxiv:`math/0110077v1`. @@ -4929,6 +5108,11 @@ REFERENCES: .. [Pos2005] \A. Postnikov, Affine approach to quantum Schubert calculus, Duke Math. J. 128 (2005) 473-509 +.. [Pot1998] Potemine, I.Y., + Minimal Terminal Q-Factorial Models of Drinfeld Coarse Moduli Schemes. + Mathematical Physics, Analysis and Geometry 1, 171-191 (1998). + :doi:`10.1023/A:1009724323513` + .. [PPW2013] \D. Perkinson, J. Perlman, and J. Wilmes. *Primer for the algebraic geometry of sandpiles*. Tropical and Non-Archimedean @@ -5172,6 +5356,8 @@ REFERENCES: .. [Ros2002] Rosenfeld, Vladimir Raphael, 2002: Enumerating De Bruijn Sequences. *Communications in Math. and in Computer Chem.* +.. [Rosen2002] \M. Rosen. Number theory in function fields. Springer, 2022. + .. [Rot2001] Gunter Rote, *Division-Free Algorithms for the Determinant and the Pfaffian: Algebraic and Combinatorial Approaches*, H. Alt (Ed.): Computational Discrete @@ -5310,6 +5496,9 @@ REFERENCES: .. [Sch1996] \E. Schaefer. A simplified data encryption algorithm. Cryptologia, 20(1):77--84, 1996. +.. [Scha1996] Richard D. Schaefer. *An Introduction to Nonassociative Algebras*. + Dover, New York, 1996. + .. [Sch1999] Gilles Schaeffer, *Random Sampling of Large Planar Maps and Convex Polyhedra*, Annual ACM Symposium on Theory of Computing (Atlanta, GA, 1999). :doi:`10.1145/301250.301448`. @@ -5345,6 +5534,10 @@ REFERENCES: *Wide-open encryption design offers flexible implementations*; in Cryptologia, (1985), pp. 75-91. +.. [Seb1978] \J. Seberry. + *On Skew Hadamard Matrices*, + Ars Combinatoria 6 (1978): 255-276. + .. [Seb2017] \J. Seberry, *Orthogonal designs: Hadamard matrices, quadratic forms and algebras*. Springer 2017. :doi:`10.1007/978-3-319-59032-5` @@ -5479,6 +5672,10 @@ REFERENCES: Journal of Cryptology. 12. 193-196. 1999. :doi:`10.1007/s001459900052`. +.. [Smi2023] \D. Smith, J. S. Myers, C. S. Kaplan and C. Goodman-Strauss, + *An aperiodic monotile*, + :arxiv:`2303.10798` + .. [SP2010] Fernando Solano and Michal Pioro, *Lightpath Reconfiguration in WDM networks*, IEEE/OSA Journal of Optical Communication and Networking 2(12):1010-1021, 2010. :doi:`10.1364/JOCN.2.001010`. @@ -5493,6 +5690,21 @@ REFERENCES: :doi:`10.1007/978-1-4684-9322-1`, ISBN 978-1-4684-9322-1. +.. [Spe1975] \E. Spence. + *Hadamard matrices from relative difference sets*, + Journal of Combinatorial Theory, Series A 19(3) (1975): 287-300. + :doi:`10.1016/0097-3165(75)90054-0` + +.. [Spe1975b] \E. Spence. + *Skew-Hadamard Matrices of the Goethals-Seidel Type*, + Canadian Journal of Mathematics 27(3) (1975): 555-560. + :doi:`10.4153/cjm-1975-066-9` + +.. [Spe1977] \E. Spence. + *Skew-Hadamard matrices of order 2(q + 1)*, + Discrete Mathematics 18(1) (1977): 79-85. + :doi:`10.1016/0012-365X(77)90009-7` + .. [Spe2013] \D. Speyer, *An infinitely generated upper cluster algebra*, :arxiv:`1305.6867`. @@ -5633,11 +5845,6 @@ REFERENCES: matrices, and characteristic polynomials without division* :doi:`10.1023/A:1021878507303` -.. [Spe1975] \E. Spence. - *Hadamard matrices from relative difference sets*, - Journal of Combinatorial Theory, Series A 19(3) (1975): 287-300. - :doi:`10.1016/0097-3165(75)90054-0` - .. [ST1981] \J. J. Seidel and D. E. Taylor, *Two-graphs, a second survey*. Algebraic methods in graph theory, Vol. I, II (Szeged, 1978), @@ -5764,11 +5971,22 @@ REFERENCES: isogenies of prime degree. Journal de Thรฉorie des Nombres de Bordeaux, 2012. +.. [Suth2007] Andrew V. Sutherland, *Order Computations in Generic Groups*. + PhD Thesis, Massachusetts Institute of Technology, + June 2007. + https://math.mit.edu/~drew/sutherland-phd.pdf + .. [Suth2008] Andrew V. Sutherland, *Structure computation and discrete logarithms in finite abelian p-groups*. Mathematics of Computation **80** (2011), pp. 477-500. :arxiv:`0809.3413v3`. +.. [RouSuthZur2022] Jeremy Rouse, Andrew V. Sutherland, David Zureick-Brown. + *`\ell`-adic images of Galois for elliptic curves over `\Q`* (and an appendix with John Voight). + Forum of Mathematics, Sigma , Volume 10 , 2022. + :doi: `10.1017/fms.2022.38`. + :arxiv:`2106.11141`. + .. [SV1970] \H. Schneider and M. Vidyasagar. Cross-positive matrices. SIAM Journal on Numerical Analysis, 7:508-519, 1970. @@ -5842,6 +6060,15 @@ REFERENCES: Hall-Littlewood vertex operators and generalized Kostka polynomials. Adv. Math. 158 (2001), no. 1, 66-85. +.. [Sze1971] \G. Szekeres. + *Cyclotomy and complementary difference sets*, + Acta Arithmetica 18 (1971): 349-353. + :doi:`10.4064/aa-18-1-349-353` + +.. [Sze1988] \G. Szekeres. + *A note on skew type orthogonal ยฑ1 matrices*, + Combinatorics, Colloquia Mathematica Societatis, Janos Bolyai, 52 (1988): 489-498. + .. _ref-T: **T** @@ -5929,6 +6156,10 @@ REFERENCES: .. [TOPCOM] \J. Rambau, TOPCOM <http://www.rambau.wm.uni-bayreuth.de/TOPCOM/>. +.. [TT2023] Tan Nhat Tran and Shuhei Tsujie. + *A type B analog of Ish arrangement*. + Preprint, :arxiv:`2304.12022`. (2023) + .. [TTWL2009] Trebst, Troyer, Wang and Ludwig, A short introduction to Fibonacci anyon models, :arxiv:`0902.3275`. @@ -6034,6 +6265,9 @@ REFERENCES: .. [Voi2012] \J. Voight. Identifying the matrix ring: algorithms for quaternion algebras and quadratic forms, to appear. +.. [VS06] \G.D. Villa Salvador. Topics in the Theory of Algebraic Function + Fields. Birkh\"auser, 2006. + .. [VW1994] Leonard Van Wyk. *Graph groups are biautomatic*. J. Pure Appl. Alg. **94** (1994). no. 3, 341-352. @@ -6053,6 +6287,11 @@ REFERENCES: .. [Wal1970] David W. Walkup, "The lower bound conjecture for 3- and 4-manifolds", Acta Math. 125 (1970), 75-107. +.. [Wal1970b] \J. Wallis. + *(v, k, ฮป) Configurations and Hadamard matrices*, + Journal of the Australian Mathematical Society 11(3) (1970): 297-309. + :doi:`10.1017/S1446788700006674` + .. [Wal2001] Timothy Walsh, *Gray codes for involutions*, J. Combin. Math. Combin. Comput. **36** (2001), 95-118. http://www.info2.uqam.ca/~walsh_t/papers/Involutions%20paper.pdf @@ -6079,6 +6318,11 @@ REFERENCES: .. [Watkins] Mark Watkins, *Hypergeometric motives over Q and their L-functions*, http://magma.maths.usyd.edu.au/~watkins/papers/known.pdf +.. [Watkins2004] Mark Watkins. + *Class numbers of imaginary quadratic fields*. + Math. Comp. 73 (2004), 907-938. + https://www.ams.org/journals/mcom/2004-73-246/S0025-5718-03-01517-5/ + .. [Wat2003] Joel Watson. *Strategy: an introduction to game theory*. WW Norton, 2002. @@ -6122,6 +6366,11 @@ REFERENCES: pages 150--168, 1932, `available on JSTOR <http://www.jstor.org/stable/2371086>`_ +.. [Whi1971] \A. Whiteman. + *An infinite family of skew Hadamard matrices*, + Pacific Journal of Mathematics 38(3) (1971): 817-822. + :doi:`10.2140/pjm.1971.38.817` + .. [White2015] Noah White. *The monodromy of real Bethe vectors for the Gaudin model*. J. Combin. Algebra, **2** no. 3 (2018). pp. 259-300. @@ -6307,7 +6556,7 @@ REFERENCES: Combinatorics, 19(1), P53, 2012. :doi:`10.37236/2087` .. [Zie1959] \N. Zierler. *Linear Recurring Sequences*. - Journal of the Society for Industrial and Applied Mathematics 7(1) + Journal of the Society for Industrial and Applied Mathematics 7(1) (1959): 31-48. :doi:`10.1137/0107003` .. [Zie1998] \G. M. Ziegler. *Shelling polyhedral 3-balls and diff --git a/src/doc/en/reference/rings/index.rst b/src/doc/en/reference/rings/index.rst index d43d1be4003..52847e952b4 100644 --- a/src/doc/en/reference/rings/index.rst +++ b/src/doc/en/reference/rings/index.rst @@ -8,6 +8,7 @@ Base Classes for Rings, Algebras and Fields :maxdepth: 1 sage/rings/ring + sage/rings/abc Ideals ------ diff --git a/src/doc/en/reference/rings_standard/index.rst b/src/doc/en/reference/rings_standard/index.rst index 4bb5338609f..97bf2b8ea35 100644 --- a/src/doc/en/reference/rings_standard/index.rst +++ b/src/doc/en/reference/rings_standard/index.rst @@ -12,6 +12,8 @@ Integers sage/rings/bernmm sage/rings/bernoulli_mod_p sage/rings/factorint + sage/rings/factorint_flint + sage/rings/factorint_pari sage/rings/fast_arith sage/rings/sum_of_squares sage/arith/functions diff --git a/src/doc/en/reference/topology/index.rst b/src/doc/en/reference/topology/index.rst index 1442b327ed2..955e6827722 100644 --- a/src/doc/en/reference/topology/index.rst +++ b/src/doc/en/reference/topology/index.rst @@ -23,5 +23,6 @@ other types of cell complexes. sage/topology/simplicial_set_morphism sage/topology/cell_complex sage/topology/filtered_simplicial_complex + sage/topology/moment_angle_complex .. include:: ../footer.txt diff --git a/src/doc/en/reference/valuations/index.rst b/src/doc/en/reference/valuations/index.rst index 90a8c3c97f7..bd09af43248 100644 --- a/src/doc/en/reference/valuations/index.rst +++ b/src/doc/en/reference/valuations/index.rst @@ -201,7 +201,7 @@ More Details sage/rings/valuation/mapped_valuation sage/rings/valuation/scaled_valuation - sage/rings/function_field/function_field_valuation + sage/rings/function_field/valuation sage/rings/padics/padic_valuation .. include:: ../footer.txt diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index 4efe68a2617..bb23331c151 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -105,8 +105,7 @@ it makes sense to build on top of the base class This base class provides a lot more methods than a general parent:: sage: [p for p in dir(Field) if p not in dir(Parent)] - ['__fraction_field', - '__ideal_monoid', + ['_CommutativeRing__fraction_field', '__iter__', '__len__', '__rxor__', @@ -119,6 +118,7 @@ This base class provides a lot more methods than a general parent:: '_default_category', '_gens', '_ideal_class_', + '_ideal_monoid', '_latex_names', '_list', '_one_element', diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/integer_factorization.rst b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/integer_factorization.rst index 24c6c15c21b..810db483bf0 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/integer_factorization.rst +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/integer_factorization.rst @@ -6,30 +6,24 @@ Quadratic Sieve --------------- Bill Hart's quadratic sieve is included with Sage. The quadratic sieve -is the best algorithm for factoring numbers of the form :math:`pq` up -to around 100 digits. It involves searching for relations, solving a -linear algebra problem modulo :math:`2`, then factoring :math:`n` -using a relation :math:`x^2 \equiv y^2 \mod n`. +is one of the best algorithms for factoring numbers of the form +:math:`pq` up to around 100 digits. It involves searching for +relations, solving a linear algebra problem modulo :math:`2`, then +factoring :math:`n` using a relation :math:`x^2 \equiv y^2 \mod n`. +Using the qsieve algorithm can be faster than the default, which +uses PARI. :: - sage: qsieve(next_prime(2^90)*next_prime(2^91), time=True) # not tested - ([1237940039285380274899124357, 2475880078570760549798248507], - '14.94user 0.53system 0:15.72elapsed 98%CPU (0avgtext+0avgdata 0maxresident)k') - -Using qsieve is twice as fast as Sage's general factor command in -this example. Note that Sage's general factor command does nothing -but call Pari's factor C library function. - -:: - - sage: time factor(next_prime(2^90)*next_prime(2^91)) # not tested - CPU times: user 28.71 s, sys: 0.28 s, total: 28.98 s - Wall time: 29.38 s + sage: n = next_prime(2^90)*next_prime(2^91) + sage: n.factor(algorithm="qsieve") + doctest:... RuntimeWarning: the factorization returned + by qsieve may be incomplete (the factors may not be prime) + or even wrong; see qsieve? for details + 1237940039285380274899124357 * 2475880078570760549798248507 + sage: n.factor() # uses PARI at the time of writing 1237940039285380274899124357 * 2475880078570760549798248507 -Obviously, Sage's factor command should not just call Pari, but -nobody has gotten around to rewriting it yet. GMP-ECM ------- @@ -43,19 +37,14 @@ over :math:`\ZZ/n\ZZ`, and doing arithmetic on that curve--if something goes wrong when doing arithmetic, we factor :math:`n`. -In the following example, GMP-ECM is over 10 times faster than -Sage's generic factor function. Again, this emphasizes that Sage's -generic factor command would benefit from a rewrite that uses -GMP-ECM and qsieve. +In the following example, GMP-ECM is much faster than Sage's generic +factor function. Again, this emphasizes that the best factoring +algorithm may depend on your specific problem. :: - sage: time ecm.factor(next_prime(2^40) * next_prime(2^300)) # not tested - CPU times: user 0.85 s, sys: 0.01 s, total: 0.86 s - Wall time: 1.73 s - [1099511627791, - 2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397533] - sage: time factor(next_prime(2^40) * next_prime(2^300)) # not tested - CPU times: user 23.82 s, sys: 0.04 s, total: 23.86 s - Wall time: 24.35 s + sage: n = next_prime(2^40) * next_prime(2^300) + sage: n.factor(algorithm="ecm") + 1099511627791 * 2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397533 + sage: n.factor() # uses PARI at the time of writing 1099511627791 * 2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397533 diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst index fb7697587c5..9e5b3b8fbf0 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst @@ -188,7 +188,7 @@ field). :: sage: w = [-1,-2,..,-200] - sage: v = [D for D in w if is_fundamental_discriminant(D)] + sage: v = [D for D in w if D.is_fundamental_discriminant()] sage: v [-3, -4, -7, -8, -11, -15, -19, -20, ..., -195, -199] @@ -222,7 +222,7 @@ class number :math:`1`! :: sage: w = [1..1000] - sage: v = [D for D in w if is_fundamental_discriminant(D)] + sage: v = [D for D in w if D.is_fundamental_discriminant()] sage: len(v) 302 sage: len([D for D in v if QuadraticField(D,'a').class_number() == 1]) diff --git a/src/doc/en/thematic_tutorials/index.rst b/src/doc/en/thematic_tutorials/index.rst index b6993af83b8..04a23cb22d9 100644 --- a/src/doc/en/thematic_tutorials/index.rst +++ b/src/doc/en/thematic_tutorials/index.rst @@ -4,8 +4,8 @@ .. _thematic-tutorials: -Welcome to the Sage Thematic Tutorials! -======================================= +Sage Thematic Tutorials +======================= Here you will find Sage demonstrations, quick reference cards, primers, and thematic tutorials, diff --git a/src/doc/en/thematic_tutorials/lie/weyl_groups.rst b/src/doc/en/thematic_tutorials/lie/weyl_groups.rst index c917338e444..f936073a53a 100644 --- a/src/doc/en/thematic_tutorials/lie/weyl_groups.rst +++ b/src/doc/en/thematic_tutorials/lie/weyl_groups.rst @@ -125,10 +125,9 @@ and whose values are the roots, you may use the inverse family:: The behaviour of this function was changed in :trac:`20027`. The Weyl group is implemented as a GAP matrix group. You therefore can -display its character table. The character table is returned as a -string, which you can print:: +display its character table as follows:: - sage: print(WeylGroup("D4").character_table()) + sage: WeylGroup("D4").character_table() CT1 <BLANKLINE> 2 6 4 5 1 3 5 5 4 3 3 1 4 6 @@ -139,12 +138,12 @@ string, which you can print:: X.1 1 1 1 1 1 1 1 1 1 1 1 1 1 X.2 1 -1 1 1 -1 1 1 -1 -1 -1 1 1 1 X.3 2 . 2 -1 . 2 2 . . . -1 2 2 - X.4 3 -1 -1 . 1 -1 3 -1 1 -1 . -1 3 - X.5 3 -1 -1 . 1 3 -1 -1 -1 1 . -1 3 - X.6 3 1 -1 . -1 -1 3 1 -1 1 . -1 3 - X.7 3 1 -1 . -1 3 -1 1 1 -1 . -1 3 - X.8 3 -1 3 . -1 -1 -1 -1 1 1 . -1 3 - X.9 3 1 3 . 1 -1 -1 1 -1 -1 . -1 3 + X.4 3 -1 -1 . 1 3 -1 -1 -1 1 . -1 3 + X.5 3 1 -1 . -1 3 -1 1 1 -1 . -1 3 + X.6 3 -1 3 . -1 -1 -1 -1 1 1 . -1 3 + X.7 3 -1 -1 . 1 -1 3 -1 1 -1 . -1 3 + X.8 3 1 3 . 1 -1 -1 1 -1 -1 . -1 3 + X.9 3 1 -1 . -1 -1 3 1 -1 1 . -1 3 X.10 4 -2 . -1 . . . 2 . . 1 . -4 X.11 4 2 . -1 . . . -2 . . 1 . -4 X.12 6 . -2 . . -2 -2 . . . . 2 6 diff --git a/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst b/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst index 51aec989810..553a946c4d8 100644 --- a/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst +++ b/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst @@ -298,7 +298,7 @@ http://docs.python.org/library/ for a complete list. :: sage: el bla sage: el.__dict__ - {'__custom_name': 'bla', 'value': 42} + {'_SageObject__custom_name': 'bla', 'value': 42} Lots of Sage objects are not Python objects but compiled Cython objects. Python sees them as builtin objects and you do not have diff --git a/src/doc/en/thematic_tutorials/tutorial-programming-python.rst b/src/doc/en/thematic_tutorials/tutorial-programming-python.rst index 5cafdf1ea1b..47055a41bb5 100644 --- a/src/doc/en/thematic_tutorials/tutorial-programming-python.rst +++ b/src/doc/en/thematic_tutorials/tutorial-programming-python.rst @@ -176,9 +176,9 @@ indentation. Most of the time a new block is introduced by .. CODE-BLOCK:: python - raise <ErrorType> [, error message] + raise <ErrorType>[("error message")] - Usual errors include ``ValueError`` and ``TypeError``. + Usual errors include :class:`ValueError` and :class:`TypeError`. Functions ========= diff --git a/src/doc/en/tutorial/index.rst b/src/doc/en/tutorial/index.rst index 7113e311a57..9098e68c78e 100644 --- a/src/doc/en/tutorial/index.rst +++ b/src/doc/en/tutorial/index.rst @@ -4,8 +4,9 @@ .. _tutorial: -Welcome to the Sage Tutorial! -============================= +======================== +Welcome to Sage Tutorial +======================== Sage is free, open-source math software that supports research and teaching in algebra, geometry, number theory, cryptography, diff --git a/src/doc/en/tutorial/interactive_shell.rst b/src/doc/en/tutorial/interactive_shell.rst index 4c06c6a6255..5ab9e6a79a6 100644 --- a/src/doc/en/tutorial/interactive_shell.rst +++ b/src/doc/en/tutorial/interactive_shell.rst @@ -383,33 +383,6 @@ IPython documentation <http://ipython.scipy.org/moin/Documentation>`_. Meanwhile, here are some fun tricks -- these are called "Magic commands" in IPython: -- You can use ``%bg`` to run a command in the background, and then use - ``jobs`` to access the results, as follows. (The comments ``not - tested`` are here because the ``%bg`` syntax doesn't work well with - Sage's automatic testing facility. If you type this in yourself, it - should work as written. This is of course most useful with commands - which take a while to complete.) - - :: - - sage: def quick(m): return 2*m - sage: %bg quick(20) # not tested - Starting job # 0 in a separate thread. - sage: jobs.status() # not tested - Completed jobs: - 0 : quick(20) - sage: jobs[0].result # the actual answer, not tested - 40 - - Note that jobs run in the background don't use the Sage preparser -- - see :ref:`section-mathannoy` for more information. One - (perhaps awkward) way to get around this would be to run :: - - sage: %bg eval(preparse('quick(20)')) # not tested - - It is safer and easier, though, to just use ``%bg`` on commands - which don't require the preparser. - - You can use ``%edit`` (or ``%ed`` or ``ed``) to open an editor, if you want to type in some complex code. Before you start Sage, make sure that the :envvar:`EDITOR` environment variable is set to your @@ -453,7 +426,7 @@ Errors and Exceptions When something goes wrong, you will usually see a Python "exception". Python even tries to suggest what raised the exception. Often you see the name of the exception, e.g., -``NameError`` or ``ValueError`` (see the Python Library Reference [PyLR]_ +:class:`NameError` or :class:`ValueError` (see the Python Library Reference [PyLR]_ for a complete list of exceptions). For example, .. skip diff --git a/src/doc/en/tutorial/interfaces.rst b/src/doc/en/tutorial/interfaces.rst index b0e55345669..19c28f636d4 100644 --- a/src/doc/en/tutorial/interfaces.rst +++ b/src/doc/en/tutorial/interfaces.rst @@ -267,8 +267,8 @@ whose :math:`i,j` entry is :math:`i/j`, for matrix([1,1/2,1/3,1/4],[0,0,0,0],[0,0,0,0],[0,0,0,0]) sage: A.eigenvalues() [[0,4],[3,1]] - sage: A.eigenvectors() - [[[0,4],[3,1]],[[[1,0,0,-4],[0,1,0,-2],[0,0,1,-4/3]],[[1,2,3,4]]]] + sage: A.eigenvectors().sage() + [[[0, 4], [3, 1]], [[[1, 0, 0, -4], [0, 1, 0, -2], [0, 0, 1, -4/3]], [[1, 2, 3, 4]]]] Here's another example: @@ -320,8 +320,8 @@ The next plot is the famous Klein bottle (do not type the ``....:``):: sage: maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0) - 10.0") 5*cos(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0)-10.0 - sage: maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") - -5*sin(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0) + sage: maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)").sage() + -5*(cos(1/2*x)*cos(y) + sin(1/2*x)*sin(2*y) + 3.0)*sin(x) sage: maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") 5*(cos(x/2)*sin(2*y)-sin(x/2)*cos(y)) sage: maxima.plot3d ("[expr_1, expr_2, expr_3]", "[x, -%pi, %pi]", # not tested diff --git a/src/doc/en/tutorial/tour_algebra.rst b/src/doc/en/tutorial/tour_algebra.rst index 2e872cc9059..c388b7adb5c 100644 --- a/src/doc/en/tutorial/tour_algebra.rst +++ b/src/doc/en/tutorial/tour_algebra.rst @@ -16,7 +16,7 @@ functions are defined to be ``var(...)``. As an example: sage: diff(sin(u), u) cos(u) -If you get a ``NameError``, check to see if you misspelled something, +If you get a :class:`NameError`, check to see if you misspelled something, or forgot to define a variable with ``var(...)``. @@ -216,9 +216,12 @@ the notation :math:`x=x_{1}`, :math:`y=x_{2}`): :: - sage: de1 = maxima("2*diff(x(t),t, 2) + 6*x(t) - 2*y(t)") - sage: lde1 = de1.laplace("t","s"); lde1 - 2*((-%at('diff(x(t),t,1),t = 0))+s^2*'laplace(x(t),t,s)-x(0)*s) -2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) + sage: t,s = SR.var('t,s') + sage: x = function('x') + sage: y = function('y') + sage: f = 2*x(t).diff(t,2) + 6*x(t) - 2*y(t) + sage: f.laplace(t,s) + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) This is hard to read, but it says that @@ -232,8 +235,8 @@ Laplace transform of the second equation: :: sage: de2 = maxima("diff(y(t),t, 2) + 2*y(t) - 2*x(t)") - sage: lde2 = de2.laplace("t","s"); lde2 - (-%at('diff(y(t),t,1),t = 0))+s^2*'laplace(y(t),t,s) +2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s) -y(0)*s + sage: lde2 = de2.laplace("t","s"); lde2.sage() + s^2*laplace(y(t), t, s) - s*y(0) - 2*laplace(x(t), t, s) + 2*laplace(y(t), t, s) - D[0](y)(0) This says diff --git a/src/doc/en/tutorial/tour_functions.rst b/src/doc/en/tutorial/tour_functions.rst index f00991813c2..096e088bd2e 100644 --- a/src/doc/en/tutorial/tour_functions.rst +++ b/src/doc/en/tutorial/tour_functions.rst @@ -24,7 +24,7 @@ These functions can be plotted, but not differentiated or integrated. Graphics object consisting of 1 graphics primitive In the last line, note the syntax. Using ``plot(f(z), 0, 2)`` instead -will give a ``NameError``, because ``z`` is a dummy variable in the +will give a :class:`NameError`, because ``z`` is a dummy variable in the definition of ``f`` and is not defined outside of that definition. In order to be able to use ``f(z)`` in the plot command, ``z`` (or whatever is desired) needs to be defined as a variable. We diff --git a/src/doc/en/website/conf.py b/src/doc/en/website/conf.py index 099a10865c4..38f31e5d46f 100644 --- a/src/doc/en/website/conf.py +++ b/src/doc/en/website/conf.py @@ -21,7 +21,7 @@ html_static_path = [] + html_common_static_path # General information about the project. -project = "Documentation" +project = "Documentation" # The name for this set of Sphinx documents. html_title = project @@ -33,8 +33,8 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [ - ('index', 'sage_documentation.tex', 'Documentation', - 'The Sage Development Team', 'manual'), + ('index', 'sage_documentation.tex', 'Documentation', + 'The Sage Development Team', 'manual'), ] # Note that this effectively replaces the index.html generated from index.rst. diff --git a/src/doc/en/website/root_index.html b/src/doc/en/website/root_index.html index 0fe6ab69968..21a6086ed72 100644 --- a/src/doc/en/website/root_index.html +++ b/src/doc/en/website/root_index.html @@ -47,7 +47,7 @@ <h1>Sage Documentation</h1> <div class='entry lang-en'><a href='html/en/faq/index.html'>FAQ</a></div> <div class='entry lang-en'><a href='html/en/reference/index.html'>Reference Manual</a></div> <div class='entry lang-en'><a href='html/en/installation/index.html'>Installation Guide</a></div> -<div class='entry lang-en'><a href='html/en/developer/index.html'>Developer's Guide</a></div> +<div class='entry lang-en'><a href='html/en/developer/index.html'>Developer Guide</a></div> </div></div> <div class="row fr"><div class="cell"></div> <div class="cell lang">French</div> @@ -113,14 +113,14 @@ <h1>Sage Documentation</h1> <div class="cell lang"><a href='html/en/index.html'>English</a></div> <div class="cell doc"> <div class='entry lang-en'><a href='pdf/en/a_tour_of_sage/a_tour_of_sage.pdf'>A Tour of Sage</a></div> -<div class='entry lang-en'><a href='pdf/en/tutorial/SageTutorial.pdf'>Tutorial</a></div> +<div class='entry lang-en'><a href='pdf/en/tutorial/sage_tutorial.pdf'>Tutorial</a></div> <div class='entry lang-en'><a href='pdf/en/thematic_tutorials/thematic_tutorials.pdf'>Thematic Tutorials</a></div> <div class='entry lang-en'><a href='pdf/en/prep/prep_tutorials.pdf'>PREP Tutorials</a></div> <div class='entry lang-en'><a href='pdf/en/constructions/constructions.pdf'>Constructions</a></div> <div class='entry lang-en'><a href='pdf/en/faq/faq.pdf'>FAQ</a></div> <div class='entry lang-en'><a href='pdf/en/reference/index.html'>Reference Manual</a></div> <div class='entry lang-en'><a href='pdf/en/installation/installation.pdf'>Installation Guide</a></div> -<div class='entry lang-en'><a href='pdf/en/developer/developer.pdf'>Developer's Guide</a></div> +<div class='entry lang-en'><a href='pdf/en/developer/developer.pdf'>Developer Guide</a></div> </div></div> <div class="row fr"><div class="cell"></div> <div class="cell lang">French</div> diff --git a/src/doc/en/website/templates/index.html b/src/doc/en/website/templates/index.html index cdadfb78ffd..c63d109b4dc 100644 --- a/src/doc/en/website/templates/index.html +++ b/src/doc/en/website/templates/index.html @@ -19,7 +19,7 @@ align: center; border-spacing: 20px; } - table.contentstable span { {# trac #33600 comment:22 #} + table.contentstable span { {# issue #33600 comment:22 #} border-spacing: initial; } </style> @@ -207,7 +207,7 @@ <h2> <td width="50%"> <p class="biglink"> <a class="biglink" href="developer/index.html"> - Developer's Guide + Developer Guide </a> <a title="Download PDF" class="pdf" href="../../pdf/en/developer/developer.pdf"> <img class="icon" src="_static/pdf.png"></img> diff --git a/src/doc/en/website/templates/index_furo.html b/src/doc/en/website/templates/index_furo.html index 4ffc4003683..ae70b6ea4df 100644 --- a/src/doc/en/website/templates/index_furo.html +++ b/src/doc/en/website/templates/index_furo.html @@ -19,7 +19,7 @@ align: center; border-spacing: 20px; } - table.contentstable span { {# trac #33600 comment:22 #} + table.contentstable span { {# issue #33600 comment:22 #} border-spacing: initial; } </style> @@ -204,7 +204,7 @@ <h2> <td width="50%"> <p class="biglink"> <a class="biglink" href="developer/index.html"> - Developer's Guide + Developer Guide </a> <a title="Download PDF" class="pdf" href="../../pdf/en/developer/developer.pdf"> <img class="icon" src="_static/pdf.png"></img> diff --git a/src/doc/es/tutorial/introduction.rst b/src/doc/es/tutorial/introduction.rst index fdd811d7f96..92e01281ef6 100644 --- a/src/doc/es/tutorial/introduction.rst +++ b/src/doc/es/tutorial/introduction.rst @@ -101,7 +101,7 @@ Formas de usar Sage Puedes usar Sage de varias maneras. -- **Interfaz grรกfico del Notebook:** iniciar `sage -n jupyter`; leer +- **Interfaz grรกfico del Notebook:** iniciar ``sage -n jupyter``; leer `Jupyter documentation on-line <https://jupyter-notebook.readthedocs.io/en/latest/notebook.html>`_, - **Lรญnea de comandos interactiva:**, diff --git a/src/doc/es/tutorial/tour_algebra.rst b/src/doc/es/tutorial/tour_algebra.rst index dc1a7a96719..42c818fe8d7 100644 --- a/src/doc/es/tutorial/tour_algebra.rst +++ b/src/doc/es/tutorial/tour_algebra.rst @@ -197,8 +197,8 @@ la notaciรณn :math:`x=x_{1}`, :math:`y=x_{2}`): :: sage: de1 = maxima("2*diff(x(t),t, 2) + 6*x(t) - 2*y(t)") - sage: lde1 = de1.laplace("t","s"); lde1 - 2*((-%at('diff(x(t),t,1),t = 0))+s^2*'laplace(x(t),t,s)-x(0)*s) -2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) + sage: lde1 = de1.laplace("t","s"); lde1.sage() + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) El resultado puede ser difรญcil de leer, pero significa que @@ -211,9 +211,12 @@ Toma la transformada de Laplace de la segunda ecuaciรณn: :: - sage: de2 = maxima("diff(y(t),t, 2) + 2*y(t) - 2*x(t)") - sage: lde2 = de2.laplace("t","s"); lde2 - (-%at('diff(y(t),t,1),t = 0))+s^2*'laplace(y(t),t,s) +2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s) -y(0)*s + sage: t,s = SR.var('t,s') + sage: x = function('x') + sage: y = function('y') + sage: f = 2*x(t).diff(t,2) + 6*x(t) - 2*y(t) + sage: f.laplace(t,s) + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) Esto dice diff --git a/src/doc/fr/tutorial/afterword.rst b/src/doc/fr/tutorial/afterword.rst index 857d2de5ec1..05e26ae4a50 100644 --- a/src/doc/fr/tutorial/afterword.rst +++ b/src/doc/fr/tutorial/afterword.rst @@ -112,12 +112,12 @@ Aussi, Sage se comporte diffรฉremment de Python ร  plusieurs รฉgards. sage: a 10 -- **Division entiรจre :** L'expression Python ``2/3`` ne se comporte pas - de la maniรจre ร  laquelle s'attendraient des mathรฉmaticiens. En Python 2, si - ``m`` et ``n`` sont de type int, alors ``m/n`` est aussi de type int, c'est - le quotient entier de ``m`` par ``n``. Par consรฉquent, ``2/3=0``. Ce - comportement est diffรฉrent en Python 3, oรน ``2/3`` renvoie un flottant - ``0.6666...`` et c'est ``2//3`` qui renvoie ``0``. +- **Division entiรจre :** L'expression Python ``2/3`` ne se comporte + pas de la maniรจre ร  laquelle s'attendraient des mathรฉmaticiens. En + Python 3, si ``m`` et ``n`` sont de type ``int``, alors ``m/n`` est + de type ``float``, c'est le quotient rรฉel de ``m`` par ``n``. Par + exemple, ``2/3`` renvoie ``0.6666...``. Pour obtenir le quotient + entier, il faut utiliser ``2//3`` qui renvoie ``0``. Dans l'interprรฉteur Sage, nous rรฉglons cela en encapsulant automatiquement les entiers litรฉraux par ``Integer( )`` et en faisant diff --git a/src/doc/fr/tutorial/interactive_shell.rst b/src/doc/fr/tutorial/interactive_shell.rst index 81235ccaab9..1d1703cebea 100644 --- a/src/doc/fr/tutorial/interactive_shell.rst +++ b/src/doc/fr/tutorial/interactive_shell.rst @@ -387,34 +387,6 @@ celui-ci. Vous voudrez peut-รชtre consulter la `documentation complรจte de IPyth astuces utiles -- qui reposent sur ce que IPython appelle des ยซ commandes magiques ยป : -- La commande magique ``%bg`` lance une commande en arriรจre-plan. Le rรฉsultat - sera ensuite accessible ร  travers l'objet ``jobs``, comme dans l'exemple - ci-dessous. (Les commentaires ยซ not tested ยป sont lร  parce que ``%bg`` ne - fonctionne pas correctement dans l'infrastructure de test automatisรฉ de Sage, - mais si vous reproduisez l'exemple, il devrait fonctionner comme indiquรฉ. - Naturellement, ``%bg`` est surtout utile pour les commandes dont l'exรฉcution - prend beaucoup de temps.) - - :: - - sage: def quick(m): return 2*m - sage: %bg quick(20) # not tested - Starting job # 0 in a separate thread. - sage: jobs.status() # not tested - Completed jobs: - 0 : quick(20) - sage: jobs[0].result # the actual answer, not tested - 40 - - Attention, les tรขches lancรฉes en arriรจre-plan ignorent le prรฉprocesseur Sage - (voir section :ref:`section-mathannoy`). Une maniรจre (certes pas trรจs - commode) de contourner le problรจme est la suivante :: - - sage: %bg eval(preparse('quick(20)')) # not tested - - Mais il est plus simple et plus sรปr de rรฉserver ``%bg`` aux commandes en pur - Python, qui ne font pas appel au prรฉprocesseur. - - Lorsque l'on souhaite saisir un morceau de code complexe, on peut utiliser ``%edit`` (ou ``%ed``, ou ``ed``) pour ouvrir un รฉditeur de texte. Assurez-vous que la variable d'environnement :envvar:`EDITOR` est rรฉglรฉe ร  @@ -460,8 +432,9 @@ Erreurs et exceptions Quand quelque chose ne marche pas, cela se manifeste habituellement par une ยซ exception ยป Python. Python essaie de plus de donner une idรฉe de ce qui a pu dรฉclencher l'exception. Bien souvent, il affiche le nom de -l'exception (par exemple ``NameError`` ou ``ValueError``, voir le manuel -de rรฉfรฉrence de la bibliothรจque de Python [PyLR]_ pour une liste complรจte). Par exemple : +l'exception (par exemple :class:`NameError` ou :class:`ValueError`, voir +le manuel de rรฉfรฉrence de la bibliothรจque de Python [PyLR]_ pour une liste +complรจte). Par exemple : .. skip diff --git a/src/doc/fr/tutorial/interfaces.rst b/src/doc/fr/tutorial/interfaces.rst index 1cd662f3083..2cb14e772eb 100644 --- a/src/doc/fr/tutorial/interfaces.rst +++ b/src/doc/fr/tutorial/interfaces.rst @@ -273,8 +273,8 @@ pour :math:`i,j=1,\ldots,4`. matrix([1,1/2,1/3,1/4],[0,0,0,0],[0,0,0,0],[0,0,0,0]) sage: A.eigenvalues() [[0,4],[3,1]] - sage: A.eigenvectors() - [[[0,4],[3,1]],[[[1,0,0,-4],[0,1,0,-2],[0,0,1,-4/3]],[[1,2,3,4]]]] + sage: A.eigenvectors().sage() + [[[0, 4], [3, 1]], [[[1, 0, 0, -4], [0, 1, 0, -2], [0, 0, 1, -4/3]], [[1, 2, 3, 4]]]] Un deuxiรจme exemple : @@ -334,12 +334,9 @@ Et la fameuse bouteille de Klein (n'entrez pas les ``....:``): :: - sage: maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0) - 10.0") - 5*cos(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0)-10.0 - sage: maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") - -5*sin(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0) - sage: maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") - 5*(cos(x/2)*sin(2*y)-sin(x/2)*cos(y)) + sage: _ = maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0) - 10.0") + sage: _ = maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") + sage: _ = maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") sage: maxima.plot3d ("[expr_1, expr_2, expr_3]", "[x, -%pi, %pi]", # not tested ....: "[y, -%pi, %pi]", "['grid, 40, 40]", ....: '[plot_format, openmath]') diff --git a/src/doc/fr/tutorial/introduction.rst b/src/doc/fr/tutorial/introduction.rst index 6edb2362061..cfc10a965a3 100644 --- a/src/doc/fr/tutorial/introduction.rst +++ b/src/doc/fr/tutorial/introduction.rst @@ -105,7 +105,7 @@ Les diffรฉrentes maniรจres d'utiliser Sage Il y a plusieurs faรงons d'utiliser Sage. -- **Interface graphique (ยซ notebook ยป) :** dรฉmarrer `sage -n jupyter`; lire +- **Interface graphique (ยซ notebook ยป) :** dรฉmarrer ``sage -n jupyter``; lire `Jupyter documentation on-line <https://jupyter-notebook.readthedocs.io/en/latest/notebook.html>`_ ; - **Ligne de commande :** voir :ref:`chapter-interactive_shell` ; diff --git a/src/doc/fr/tutorial/latex.rst b/src/doc/fr/tutorial/latex.rst index ae326102be1..bed8a4fad93 100644 --- a/src/doc/fr/tutorial/latex.rst +++ b/src/doc/fr/tutorial/latex.rst @@ -306,17 +306,18 @@ d'appeler latex (ou plus gรฉnรฉralement le moteur choisi via ``latex.engine()``) au lieu MathJax. Les mรฉthodes ``latex.add_to_mathjax_avoid_list`` et ``latex.mathjax_avoid_list`` permettent de gรฉrer le contenu de cette liste. :: - sage: latex.mathjax_avoid_list([]) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: # not tested + sage: latex.mathjax_avoid_list([]) + sage: latex.mathjax_avoid_list() [] - sage: latex.mathjax_avoid_list(['foo', 'bar']) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.mathjax_avoid_list(['foo', 'bar']) + sage: latex.mathjax_avoid_list() ['foo', 'bar'] - sage: latex.add_to_mathjax_avoid_list('tikzpicture') # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.add_to_mathjax_avoid_list('tikzpicture') + sage: latex.mathjax_avoid_list() ['foo', 'bar', 'tikzpicture'] - sage: latex.mathjax_avoid_list([]) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.mathjax_avoid_list([]) + sage: latex.mathjax_avoid_list() [] Supposons maintenant que, dans le bloc-notes, un appel ร  ``view()`` ou diff --git a/src/doc/fr/tutorial/tour_algebra.rst b/src/doc/fr/tutorial/tour_algebra.rst index 658894b2e8b..267bd1dd4f9 100644 --- a/src/doc/fr/tutorial/tour_algebra.rst +++ b/src/doc/fr/tutorial/tour_algebra.rst @@ -182,8 +182,8 @@ Solution : Considรฉrons la transformรฉe de Laplace de la premiรจre รฉquation :: sage: de1 = maxima("2*diff(x(t),t, 2) + 6*x(t) - 2*y(t)") - sage: lde1 = de1.laplace("t","s"); lde1 - 2*((-%at('diff(x(t),t,1),t = 0))+s^2*'laplace(x(t),t,s)-x(0)*s) -2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) + sage: lde1 = de1.laplace("t","s"); lde1.sage() + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) La rรฉponse n'est pas trรจs lisible, mais elle signifie que @@ -196,9 +196,12 @@ la seconde รฉquation : :: - sage: de2 = maxima("diff(y(t),t, 2) + 2*y(t) - 2*x(t)") - sage: lde2 = de2.laplace("t","s"); lde2 - (-%at('diff(y(t),t,1),t = 0))+s^2*'laplace(y(t),t,s) +2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s) -y(0)*s + sage: t,s = SR.var('t,s') + sage: x = function('x') + sage: y = function('y') + sage: f = 2*x(t).diff(t,2) + 6*x(t) - 2*y(t) + sage: f.laplace(t,s) + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) Ceci signifie diff --git a/src/doc/it/faq/faq-usage.rst b/src/doc/it/faq/faq-usage.rst index 0b6c75644ce..13a2e0b7e5a 100644 --- a/src/doc/it/faq/faq-usage.rst +++ b/src/doc/it/faq/faq-usage.rst @@ -98,7 +98,7 @@ lancia i seguenti comandi dall'interfaccia a riga di comando di Sage:: import _tkinter import Tkinter -Se non ti viene segnalato alcun errore di ``ImportError`` +Se non ti viene segnalato alcun errore di :class:`ImportError` allora il problema รจ risolto. @@ -304,7 +304,7 @@ anzichรฉ Integer di Sage. Ad esempio:: sage: RealNumber = float; Integer = int sage: from scipy import stats sage: stats.ttest_ind([1,2,3,4,5], [2,3,4,5,.6]) - Ttest_indResult(statistic=0.0767529..., pvalue=0.940704...) + Ttest...Result(statistic=0.0767529..., pvalue=0.940704...) sage: stats.uniform(0,15).ppf([0.5,0.7]) array([ 7.5, 10.5]) @@ -662,7 +662,7 @@ Con degli oggetti "a" e "b" ed una funzione "f" ho digitato accidentalmente "f(a Questo รจ dovuto a come sono definite le funzioni in Sage con la notazione ``f(x)=expr`` usando il preparser. Nota anche che se fai -quest'errore in un costrutto ``if``, avrai un errore ``SyntaxError`` +quest'errore in un costrutto ``if``, avrai un errore :class:`SyntaxError` prima di qualunque altro comportamento errato, quindi, in questo caso, non hai il problema. diff --git a/src/doc/it/tutorial/tour_algebra.rst b/src/doc/it/tutorial/tour_algebra.rst index 5a5311e9b1c..cde427d3090 100644 --- a/src/doc/it/tutorial/tour_algebra.rst +++ b/src/doc/it/tutorial/tour_algebra.rst @@ -183,8 +183,8 @@ la notazione :math:`x=x_{1}`, :math:`y=x_{2}`: :: sage: de1 = maxima("2*diff(x(t),t, 2) + 6*x(t) - 2*y(t)") - sage: lde1 = de1.laplace("t","s"); lde1 - 2*((-%at('diff(x(t),t,1),t = 0))+s^2*'laplace(x(t),t,s)-x(0)*s) -2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) + sage: lde1 = de1.laplace("t","s"); lde1.sage() + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) Questo รจ di difficile lettura, ma dice che @@ -197,9 +197,12 @@ trasformata di Laplace della seconda equazione: :: - sage: de2 = maxima("diff(y(t),t, 2) + 2*y(t) - 2*x(t)") - sage: lde2 = de2.laplace("t","s"); lde2 - (-%at('diff(y(t),t,1),t = 0))+s^2*'laplace(y(t),t,s) +2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s) -y(0)*s + sage: t,s = SR.var('t,s') + sage: x = function('x') + sage: y = function('y') + sage: f = 2*x(t).diff(t,2) + 6*x(t) - 2*y(t) + sage: f.laplace(t,s) + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) che significa diff --git a/src/doc/ja/tutorial/interactive_shell.rst b/src/doc/ja/tutorial/interactive_shell.rst index 38a5c2c4d3f..3d741045b22 100644 --- a/src/doc/ja/tutorial/interactive_shell.rst +++ b/src/doc/ja/tutorial/interactive_shell.rst @@ -353,33 +353,6 @@ IPythonใƒˆใƒชใƒƒใ‚ฏ <http://ipython.scipy.org/moin/Documentation>`_ ใ‚’่ชญใ‚“ใฟใฆใปใ—ใ„๏ผŽ ใใฎใ‹ใ‚ใ‚Š๏ผŒใ“ใ“ใงใฏIPythonใฎใ€Œใƒžใ‚ธใƒƒใ‚ฏใ‚ณใƒžใƒณใƒ‰ใ€ใจๅ‘ผใฐใ‚Œใ‚‹๏ผŒใŠไพฟๅˆฉใชใƒˆใƒชใƒƒใ‚ฏใ‚’ใ„ใใคใ‹็ดนไป‹ใ•ใ›ใฆใ„ใŸใ ใ“ใ†: -- ``%bg`` ใ‚’ไฝฟใˆใฐใ‚ณใƒžใƒณใƒ‰ใ‚’ใƒใƒƒใ‚ฏใ‚ฐใƒฉใ‚ฆใƒณใƒ‰ใงๅฎŸ่กŒใ—๏ผŒ ็ตๆžœใซใฏ ``jobs`` ใงใ‚ขใ‚ฏใ‚ปใ‚นใ™ใ‚‹ใ“ใจใŒใงใใ‚‹๏ผŽ(ใ“ใฎๆฉŸ่ƒฝใฏ ``not tested`` ใจใ‚ณใƒกใƒณใƒˆใ•ใ‚Œใฆใ„ใ‚‹๏ผŽใจใ„ใ†ใฎใฏ ``%bg`` ๆ›ธๆณ•ใŒSageใฎ่‡ชๅ‹•ใƒ†ใ‚นใƒˆๆฉŸ่ƒฝใจใฏไฝ™ใ‚Š็›ธๆ€งใŒ่‰ฏใใชใ„ใ‹ใ‚‰ใ ๏ผŽใƒฆใƒผใ‚ถๅ„่‡ชใŒๅ…ฅๅŠ›ใ—ใฆใ‚„ใ‚Œใฐ๏ผŒใใฎ้€šใ‚Šๅ‹•ไฝœใ™ใ‚‹ใฏใšใงใ‚ใ‚‹๏ผŽใ‚‚ใกใ‚ใ‚“๏ผŒใ“ใฎๆฉŸ่ƒฝใŒๆœ€ใ‚‚ๅฝน็ซ‹ใคใฎใฏๅฎŸ่กŒใซๆ™‚้–“ใฎใ‹ใ‹ใ‚‹ใ‚ณใƒžใƒณใƒ‰ใจ็ต„ใฟๅˆใ‚ใ›ใ‚‹ๅ ดๅˆใงใ‚ใ‚‹๏ผŽ) - - ไฝฟ็”จไพ‹ใ‚’ไปฅไธ‹ใซ็คบใ™๏ผŽ - - :: - - sage: def quick(m): return 2*m - sage: %bg quick(20) # not tested - Starting job # 0 in a separate thread. - sage: jobs.status() # not tested - Completed jobs: - 0 : quick(20) - sage: jobs[0].result # the actual answer, not tested - 40 - - ใƒใƒƒใ‚ฏใ‚ฐใƒฉใ‚ฆใƒณใƒ‰ใซ้€ใ‚‰ใ‚Œใ‚‹ใ‚ธใƒงใƒ–ใฏSageใฎๅ‰ๅ‡ฆ็†ใƒ‘ใƒผใ‚ตใ‚’็ตŒ็”ฑใ—ใชใ„ใ“ใจใซๆณจๆ„ -- ่ฉณ็ดฐใฏ :ref:`section-mathannoy` ็ฏ€ใ‚’ๅ‚็…งใ•ใ‚ŒใŸใ„๏ผŽ - ใƒ‘ใƒผใ‚ตใ‚’้€šใ™ใŸใ‚ใฎ(ไธๅ™จ็”จใงใ‚ใ‚‹ใ‘ใ‚Œใฉใ‚‚)๏ผ‘ใคใฎๆ–นๆณ•ใฏ - - :: - - sage: %bg eval(preparse('quick(20)')) # not tested - - ใจใ™ใ‚‹ใ“ใจใ ใ‚ใ†๏ผŽ - - ใŸใ ใ—๏ผŒใ‚ˆใ‚Šๅฎ‰ๅ…จใง็ฐกๅ˜ใชใฎใฏๅ‰ๅ‡ฆ็†ใƒ‘ใƒผใ‚ตใ‚’ๅฟ…่ฆใจใ—ใชใ„ใ‚ณใƒžใƒณใƒ‰ใง ``%bg`` ใ‚’ไฝฟใ†ใ“ใจใ ใ‚ใ†๏ผŽ - - - ``%edit`` (``%ed`` ใ‚„ ``ed`` ใงใ‚‚ใ„ใ„)ใ‚’ไฝฟใฃใฆใ‚จใƒ‡ใ‚ฃใ‚ฟใ‚’่ตทๅ‹•ใ™ใ‚Œใฐ๏ผŒ่ค‡้›‘ใชใ‚ณใƒผใƒ‰ใฎๅ…ฅๅŠ›ใŒๆฅฝใซใชใ‚‹๏ผŽ Sageใฎไฝฟ็”จๅ‰ใซ๏ผŒ็’ฐๅขƒๅค‰ๆ•ฐ :envvar:`EDITOR` ใซๅฅฝใฟใฎใ‚จใƒ‡ใ‚ฃใ‚ฟๅใ‚’่จญๅฎšใ—ใฆใŠใ“ใ†(``export EDITOR=/usr/bin/emacs`` ใพใŸใฏ ``export EDITOR=/usr/bin/vim`` ใจใ™ใ‚‹ใ‹๏ผŒ ``.profile`` ใƒ•ใ‚กใ‚คใƒซใชใฉใงๅŒๆง˜ใฎ่จญๅฎšใ‚’ใ™ใ‚‹)๏ผŽ ใ™ใ‚‹ใจSageใƒ—ใƒญใƒณใƒ—ใƒˆใง ``%edit`` ใ‚’ๅฎŸ่กŒใ™ใ‚Œใฐ่จญๅฎšใ—ใŸใ‚จใƒ‡ใ‚ฃใ‚ฟใŒ่ตทๅ‹•ใ™ใ‚‹๏ผŽใใฎใ‚จใƒ‡ใ‚ฃใ‚ฟใง้–ขๆ•ฐ @@ -418,7 +391,7 @@ IPythonใฎใ‚ฏใ‚คใƒƒใ‚ฏ ใƒฌใƒ•ใ‚กใƒฌใƒณใ‚นใ‚ฌใ‚คใƒ‰ใ‚’่ฆ‹ใŸใ‘ใ‚Œใฐ๏ผŒ ``%quick ===================== ๅ‡ฆ็†ไธญใซไฝ•ใ‹ใพใšใ„ใ“ใจใŒ่ตทใใ‚‹ใจ๏ผŒPythonใฏใตใคใ†ใ€Žไพ‹ๅค–ใ€(exception)ใ‚’็™บ็”Ÿใ—๏ผŒใใฎไพ‹ๅค–ใ‚’ๅผ•ใ่ตทใ“ใ—ใŸๅŽŸๅ› ใ‚’ๆ•™ใˆใฆใใ‚Œใ‚‹ใ“ใจใ‚‚ใ‚ใ‚‹๏ผŽ -ใ‚ˆใใŠ็›ฎใซใ‹ใ‹ใ‚‹ใ“ใจใซใชใ‚‹ใฎใฏ๏ผŒ ``NameError`` ใ‚„ ``ValueError`` ใจใ„ใฃใŸๅ็งฐใฎไพ‹ๅค–ใ (Pythonใƒฉใ‚คใƒ–ใƒฉใƒชใƒผใƒชใƒ•ใ‚กใƒฌใƒณใ‚น [PyLR]_ ใซไพ‹ๅค–ๅใฎๅŒ…ๆ‹ฌ็š„ใชใƒชใ‚นใƒˆใŒใ‚ใ‚‹)๏ผŽ +ใ‚ˆใใŠ็›ฎใซใ‹ใ‹ใ‚‹ใ“ใจใซใชใ‚‹ใฎใฏ๏ผŒ :class:`NameError` ใ‚„ :class:`ValueError` ใจใ„ใฃใŸๅ็งฐใฎไพ‹ๅค–ใ (Pythonใƒฉใ‚คใƒ–ใƒฉใƒชใƒผใƒชใƒ•ใ‚กใƒฌใƒณใ‚น [PyLR]_ ใซไพ‹ๅค–ๅใฎๅŒ…ๆ‹ฌ็š„ใชใƒชใ‚นใƒˆใŒใ‚ใ‚‹)๏ผŽ ๅฎŸไพ‹ใ‚’่ฆ‹ใฆใฟใ‚ˆใ†: :: diff --git a/src/doc/ja/tutorial/interfaces.rst b/src/doc/ja/tutorial/interfaces.rst index 9c16b2eba08..892fc6f852f 100644 --- a/src/doc/ja/tutorial/interfaces.rst +++ b/src/doc/ja/tutorial/interfaces.rst @@ -239,8 +239,8 @@ Sage/Maximaใ‚คใƒณใ‚ฟใƒผใƒ•ใ‚งใ‚คใ‚นใฎไฝฟใ„ๆ–นใ‚’ไพ‹็คบใ™ใ‚‹ใŸใ‚๏ผŒใ“ใ“ใง matrix([1,1/2,1/3,1/4],[0,0,0,0],[0,0,0,0],[0,0,0,0]) sage: A.eigenvalues() [[0,4],[3,1]] - sage: A.eigenvectors() - [[[0,4],[3,1]],[[[1,0,0,-4],[0,1,0,-2],[0,0,1,-4/3]],[[1,2,3,4]]]] + sage: A.eigenvectors().sage() + [[[0, 4], [3, 1]], [[[1, 0, 0, -4], [0, 1, 0, -2], [0, 0, 1, -4/3]], [[1, 2, 3, 4]]]] ไฝฟ็”จไพ‹ใ‚’ใ‚‚ใ†ไธ€ใค็คบใ™: @@ -299,11 +299,8 @@ Sage/Maximaใ‚คใƒณใ‚ฟใƒผใƒ•ใ‚งใ‚คใ‚นใฎไฝฟใ„ๆ–นใ‚’ไพ‹็คบใ™ใ‚‹ใŸใ‚๏ผŒใ“ใ“ใง :: - sage: maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0) - 10.0") - 5*cos(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0)-10.0 - sage: maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") - -5*sin(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0) - sage: maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") - 5*(cos(x/2)*sin(2*y)-sin(x/2)*cos(y)) + sage: _ = maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0) - 10.0") + sage: _ = maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") + sage: _ = maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") sage: maxima.plot3d ("[expr_1, expr_2, expr_3]", "[x, -%pi, %pi]", # not tested ....: "[y, -%pi, %pi]", "['grid, 40, 40]", '[plot_format, openmath]') diff --git a/src/doc/ja/tutorial/introduction.rst b/src/doc/ja/tutorial/introduction.rst index 79d90c9d5c1..c71737d7177 100644 --- a/src/doc/ja/tutorial/introduction.rst +++ b/src/doc/ja/tutorial/introduction.rst @@ -83,7 +83,7 @@ Sageใฎไฝฟใ„ใ‹ใŸ Sageใ‚’ไฝฟใ†ใซใฏไปฅไธ‹ใฎใ‚ˆใ†ใชใ‚„ใ‚Šๆ–นใŒใ‚ใ‚‹๏ผŽ -- **ใƒŽใƒผใƒˆใƒ–ใƒƒใ‚ฏ ใ‚ฐใƒฉใƒ•ใ‚ฃใ‚ซใƒซ ใ‚คใƒณใ‚ฟใƒผใƒ•ใ‚งใ‚คใ‚น:** `sage -n jupyter` ใ‚’่ตทๅ‹•ใ—ใพใ™ใ€‚ +- **ใƒŽใƒผใƒˆใƒ–ใƒƒใ‚ฏ ใ‚ฐใƒฉใƒ•ใ‚ฃใ‚ซใƒซ ใ‚คใƒณใ‚ฟใƒผใƒ•ใ‚งใ‚คใ‚น:** ``sage -n jupyter`` ใ‚’ๅฎŸ่กŒใ™ใ‚‹. `Jupyter documentation on-line <https://jupyter-notebook.readthedocs.io/en/latest/notebook.html>`_ ใ‚’่ชญใ‚€. - **ๅฏพ่ฉฑ็š„ใ‚ณใƒžใƒณใƒ‰ใƒฉใ‚คใƒณ:** :ref:`chapter-interactive_shell` ็ฏ€ใ‚’ๅ‚็…ง๏ผŽ diff --git a/src/doc/ja/tutorial/latex.rst b/src/doc/ja/tutorial/latex.rst index e02d8507eb6..9f4dc85090b 100644 --- a/src/doc/ja/tutorial/latex.rst +++ b/src/doc/ja/tutorial/latex.rst @@ -280,17 +280,18 @@ LaTeXๅ‡ฆ็†ใฎใ‚ซใ‚นใ‚ฟใƒžใ‚คใ‚บ :: - sage: latex.mathjax_avoid_list([]) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: # not tested + sage: latex.mathjax_avoid_list([]) + sage: latex.mathjax_avoid_list() [] - sage: latex.mathjax_avoid_list(['foo', 'bar']) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.mathjax_avoid_list(['foo', 'bar']) + sage: latex.mathjax_avoid_list() ['foo', 'bar'] - sage: latex.add_to_mathjax_avoid_list('tikzpicture') # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.add_to_mathjax_avoid_list('tikzpicture') + sage: latex.mathjax_avoid_list() ['foo', 'bar', 'tikzpicture'] - sage: latex.mathjax_avoid_list([]) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.mathjax_avoid_list([]) + sage: latex.mathjax_avoid_list() [] diff --git a/src/doc/ja/tutorial/tour_algebra.rst b/src/doc/ja/tutorial/tour_algebra.rst index 784fd0d5c40..746cbb4475c 100644 --- a/src/doc/ja/tutorial/tour_algebra.rst +++ b/src/doc/ja/tutorial/tour_algebra.rst @@ -213,8 +213,8 @@ Sageใ‚’ไฝฟใฃใฆๅธธๅพฎๅˆ†ๆ–น็จ‹ๅผใ‚’็ ”็ฉถใ™ใ‚‹ใ“ใจใ‚‚ใงใใ‚‹๏ผŽ :math:`x' :: sage: de1 = maxima("2*diff(x(t),t, 2) + 6*x(t) - 2*y(t)") - sage: lde1 = de1.laplace("t","s"); lde1 - 2*((-%at('diff(x(t),t,1),t = 0))+s^2*'laplace(x(t),t,s)-x(0)*s) -2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) + sage: lde1 = de1.laplace("t","s"); lde1.sage() + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) ใ“ใฎๅ‡บๅŠ›ใฏ่ชญใฟใซใใ„ใ‘ใ‚Œใฉใ‚‚๏ผŒๆ„ๅ‘ณใ—ใฆใ„ใ‚‹ใฎใฏ @@ -226,9 +226,12 @@ Sageใ‚’ไฝฟใฃใฆๅธธๅพฎๅˆ†ๆ–น็จ‹ๅผใ‚’็ ”็ฉถใ™ใ‚‹ใ“ใจใ‚‚ใงใใ‚‹๏ผŽ :math:`x' :: - sage: de2 = maxima("diff(y(t),t, 2) + 2*y(t) - 2*x(t)") - sage: lde2 = de2.laplace("t","s"); lde2 - (-%at('diff(y(t),t,1),t = 0))+s^2*'laplace(y(t),t,s) +2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s) -y(0)*s + sage: t,s = SR.var('t,s') + sage: x = function('x') + sage: y = function('y') + sage: f = 2*x(t).diff(t,2) + 6*x(t) - 2*y(t) + sage: f.laplace(t,s) + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) ๆ„ๅ‘ณใ™ใ‚‹ใจใ“ใ‚ใฏ diff --git a/src/doc/pt/tutorial/interactive_shell.rst b/src/doc/pt/tutorial/interactive_shell.rst index 67d27269a1e..77fd02870e0 100644 --- a/src/doc/pt/tutorial/interactive_shell.rst +++ b/src/doc/pt/tutorial/interactive_shell.rst @@ -372,34 +372,6 @@ pode usar quaisquer comandos e recursos do IPython. Vocรช pode ler a `Documentaรงรฃo completa do IPython <http://ipython.scipy.org/moin/Documentation>`_ (em inglรชs). -- Vocรช pode usar ``%bg`` para executar um comando no background, e - entรฃo usar ``jobs`` para acessar os resultados, da seguinte forma. - (Os comentรกrios ``not tested`` estรฃo aqui porque a sintaxe ``%bg`` - nรฃo funciona bem com o sistema de testes automรกticos do Sage. Se - vocรช digitar esses comandos, eles devem funcionar. Isso รฉ obviamente - mais รบtil com comandos que demoram para serem completados.) - - :: - - sage: def quick(m): return 2*m - sage: %bg quick(20) # not tested - Starting job # 0 in a separate thread. - sage: jobs.status() # not tested - Completed jobs: - 0 : quick(20) - sage: jobs[0].result # the actual answer, not tested - 40 - - Note que os comandos executados no background nรฃo usam o - pre-processador (preparser) do Sage -- veja :ref:`section-mathannoy` - para mais informaรงรตes. Uma forma (estranha talvez) de contornar esse - problema seria executar :: - - sage: %bg eval(preparse('quick(20)')) # not tested - - ร‰ mais seguro e simples, todavia, usar ``%bg`` apenas em comandos - que nรฃo requerem o pre-processador (preparser). - - Vocรช pode usar ``%edit`` (ou ``%ed`` ou ``ed``) para abrir um editor, se vocรช desejar digitar algum cรณdigo mais complexo. Antes de iniciar o Sage, certifique-se de que a variรกvel de ambiente @@ -439,7 +411,7 @@ Erros e Exceรงรตes Quando algo errado ocorre, vocรช usualmente verรก uma "exceรงรฃo" do Python. O Python atรฉ mesmo tenta sugerir o que ocasionou a exceรงรฃo, -por exemplo, ``NameError`` ou ``ValueError`` (veja o Referรชncia da +por exemplo, :class:`NameError` ou :class:`ValueError` (veja o Referรชncia da Biblioteca Python [PyLR]_ para uma lista completa de exceรงรตes). Por exemplo, diff --git a/src/doc/pt/tutorial/interfaces.rst b/src/doc/pt/tutorial/interfaces.rst index 3c080cc3cfc..5badb31ab35 100644 --- a/src/doc/pt/tutorial/interfaces.rst +++ b/src/doc/pt/tutorial/interfaces.rst @@ -233,8 +233,8 @@ cรกlculos). Nรฃo digite ``...``: sage: x, y = QQ['x, y'].gens() sage: f = 9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + 9*x^6*y^4 \ - ....: + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - 9*x^12*y^3 \ - ....: - 18*x^13*y^2 + 9*x^16 + ....: + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - 9*x^12*y^3 \ + ....: - 18*x^13*y^2 + 9*x^16 sage: factor(f) (9) * (-x^5 + y^2)^2 * (x^6 - 2*x^3*y^2 - x^2*y^3 + y^4) @@ -269,8 +269,8 @@ entrada :math:`i,j` รฉ :math:`i/j`, para :math:`i,j=1,\ldots,4`. matrix([1,1/2,1/3,1/4],[0,0,0,0],[0,0,0,0],[0,0,0,0]) sage: A.eigenvalues() [[0,4],[3,1]] - sage: A.eigenvectors() - [[[0,4],[3,1]],[[[1,0,0,-4],[0,1,0,-2],[0,0,1,-4/3]],[[1,2,3,4]]]] + sage: A.eigenvectors().sage() + [[[0, 4], [3, 1]], [[[1, 0, 0, -4], [0, 1, 0, -2], [0, 0, 1, -4/3]], [[1, 2, 3, 4]]]] Aqui vai outro exemplo: @@ -305,38 +305,35 @@ Um grรกfico em duas dimensรตes de diversas funรงรตes (nรฃo digite ``...``): :: - sage: maxima.plot2d('[cos(7*x),cos(23*x)^4,sin(13*x)^3]','[x,0,1]', # not tested - ....: '[plot_format,openmath]') # not tested + sage: maxima.plot2d('[cos(7*x),cos(23*x)^4,sin(13*x)^3]', '[x,0,1]', # not tested + ....: '[plot_format,openmath]') Um grรกfico em 3D que vocรช pode mover com o seu mouse: :: sage: maxima.plot3d("2^(-u^2 + v^2)", "[u, -3, 3]", "[v, -2, 2]", # not tested - ....: '[plot_format, openmath]') # not tested + ....: '[plot_format, openmath]') - sage: maxima.plot3d("atan(-x^2 + y^3/4)", "[x, -4, 4]", "[y, -4, 4]", # not tested - ....: "[grid, 50, 50]",'[plot_format, openmath]') # not tested + sage: maxima.plot3d("atan(-x^2 + y^3/4)", "[x, -4, 4]", "[y, -4, 4]", # not tested + ....: "[grid, 50, 50]",'[plot_format, openmath]') O prรณximo grรกfico รฉ a famosa faixa de Mรถbious: :: - sage: maxima.plot3d("[cos(x)*(3 + y*cos(x/2)), sin(x)*(3 + y*cos(x/2))," \ # not tested - ....: "y*sin(x/2)]", "[x, -4, 4]", "[y, -4, 4]", # not tested - ....: '[plot_format, openmath]') # not tested + sage: maxima.plot3d("[cos(x)*(3 + y*cos(x/2)), sin(x)*(3 + y*cos(x/2))," # not tested + ....: "y*sin(x/2)]", "[x, -4, 4]", "[y, -4, 4]", + ....: '[plot_format, openmath]') E agora a famosa garrafa de Klein: :: - sage: maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)"\ - ....: "- 10.0") - 5*cos(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0)-10.0 - sage: maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") - -5*sin(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0) - sage: maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") - 5*(cos(x/2)*sin(2*y)-sin(x/2)*cos(y)) + sage: _ = maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)" + ....: "- 10.0") + sage: _ = maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") + sage: _ = maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") sage: maxima.plot3d("[expr_1, expr_2, expr_3]", "[x, -%pi, %pi]", # not tested - ....: "[y, -%pi, %pi]", "['grid, 40, 40]", # not tested - ....: '[plot_format, openmath]') # not tested + ....: "[y, -%pi, %pi]", "['grid, 40, 40]", + ....: '[plot_format, openmath]') diff --git a/src/doc/pt/tutorial/introduction.rst b/src/doc/pt/tutorial/introduction.rst index b0b2fac6e1b..8ddf257d3c7 100644 --- a/src/doc/pt/tutorial/introduction.rst +++ b/src/doc/pt/tutorial/introduction.rst @@ -100,7 +100,7 @@ Formas de usar o Sage Vocรช pode usar o Sage de diversas formas. -- **Interface grรกfica Notebook:** inicie `sage -n jupyter`; leia +- **Interface grรกfica Notebook:** inicie ``sage -n jupyter``; leia `Jupyter documentation on-line <https://jupyter-notebook.readthedocs.io/en/latest/notebook.html>`_, - **Linha de comando interativa:** veja diff --git a/src/doc/pt/tutorial/latex.rst b/src/doc/pt/tutorial/latex.rst index 3ed1a642ba8..56cb8e778c7 100644 --- a/src/doc/pt/tutorial/latex.rst +++ b/src/doc/pt/tutorial/latex.rst @@ -328,17 +328,18 @@ que for definido pelo comando ``latex.engine()``). Essa lista รฉ gerenciada pelos comandos ``latex.add_to_mathjax_avoid_list`` e ``latex.mathjax_avoid_list``. :: - sage: latex.mathjax_avoid_list([]) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: # not tested + sage: latex.mathjax_avoid_list([]) + sage: latex.mathjax_avoid_list() [] - sage: latex.mathjax_avoid_list(['foo', 'bar']) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.mathjax_avoid_list(['foo', 'bar']) + sage: latex.mathjax_avoid_list() ['foo', 'bar'] - sage: latex.add_to_mathjax_avoid_list('tikzpicture') # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.add_to_mathjax_avoid_list('tikzpicture') + sage: latex.mathjax_avoid_list() ['foo', 'bar', 'tikzpicture'] - sage: latex.mathjax_avoid_list([]) # not tested - sage: latex.mathjax_avoid_list() # not tested + sage: latex.mathjax_avoid_list([]) + sage: latex.mathjax_avoid_list() [] Suponha que uma expressรฃo em LaTeX รฉ produzida no Notebook com o diff --git a/src/doc/pt/tutorial/tour_algebra.rst b/src/doc/pt/tutorial/tour_algebra.rst index baeb37b1c71..170e0d8a367 100644 --- a/src/doc/pt/tutorial/tour_algebra.rst +++ b/src/doc/pt/tutorial/tour_algebra.rst @@ -205,8 +205,8 @@ equaรงรฃo (usando a notaรงรฃo :math:`x=x_{1}`, :math:`y=x_{2}`): :: sage: de1 = maxima("2*diff(x(t),t, 2) + 6*x(t) - 2*y(t)") - sage: lde1 = de1.laplace("t","s"); lde1 - 2*((-%at('diff(x(t),t,1),t = 0))+s^2*'laplace(x(t),t,s)-x(0)*s) -2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) + sage: lde1 = de1.laplace("t","s"); lde1.sage() + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) O resultado รฉ um pouco difรญcil de ler, mas diz que @@ -219,9 +219,12 @@ calcule a transformada de Laplace da segunda equaรงรฃo: :: - sage: de2 = maxima("diff(y(t),t, 2) + 2*y(t) - 2*x(t)") - sage: lde2 = de2.laplace("t","s"); lde2 - (-%at('diff(y(t),t,1),t = 0))+s^2*'laplace(y(t),t,s) +2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s) -y(0)*s + sage: t,s = SR.var('t,s') + sage: x = function('x') + sage: y = function('y') + sage: f = 2*x(t).diff(t,2) + 6*x(t) - 2*y(t) + sage: f.laplace(t,s) + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) O resultado significa que diff --git a/src/doc/ru/tutorial/interactive_shell.rst b/src/doc/ru/tutorial/interactive_shell.rst index e2d8a68cde6..13ea34f89db 100644 --- a/src/doc/ru/tutorial/interactive_shell.rst +++ b/src/doc/ru/tutorial/interactive_shell.rst @@ -357,8 +357,9 @@ Wall time. ะžะดะฝะฐะบะพ, ะตัะปะธ ััƒั‰ะตัั‚ะฒัƒะตั‚ ััƒั‰ะตัั‚ะฒะตะฝะฝะฐั ะšะพะณะดะฐ ั‡ั‚ะพ-ั‚ะพ ะธะดะตั‚ ะฝะต ั‚ะฐะบ, ะพะฑั‹ั‡ะฝะพ ะผะพะถะฝะพ ัƒะฒะธะดะตั‚ัŒ ะธัะบะปัŽั‡ะตะฝะธะต Python (Python "exception"). Python ะดะฐะถะต ะฟะพะฟั‹ั‚ะฐะตั‚ัั ะฟั€ะตะดะฟะพะปะพะถะธั‚ัŒ, ั‡ั‚ะพ ะฒั‹ะทะฒะฐะปะพ ะพัˆะธะฑะบัƒ. ะงะฐัั‚ะพ -ะฒั‹ ะผะพะถะตั‚ะต ะฒะธะดะตั‚ัŒ ะธะผั ะธัะบะปัŽั‡ะตะฝะธั, ะฝะฐะฟั€ะธะผะตั€, ``NameError`` ะธะปะธ ``ValueError`` -(ัะผ. Python Library Reference [PyLR]_ ะดะปั ะฟะพะปะฝะพะณะพ ัะฟะธัะบะฐ ะธัะบะปัŽั‡ะตะฝะธะน). ะะฐะฟั€ะธะผะตั€, +ะฒั‹ ะผะพะถะตั‚ะต ะฒะธะดะตั‚ัŒ ะธะผั ะธัะบะปัŽั‡ะตะฝะธั, ะฝะฐะฟั€ะธะผะตั€, :class:`NameError` ะธะปะธ +:class:`ValueError` (ัะผ. Python Library Reference [PyLR]_ ะดะปั ะฟะพะปะฝะพะณะพ ัะฟะธัะบะฐ +ะธัะบะปัŽั‡ะตะฝะธะน). ะะฐะฟั€ะธะผะตั€, .. skip diff --git a/src/doc/ru/tutorial/interfaces.rst b/src/doc/ru/tutorial/interfaces.rst index ea84527f478..061818ca4a5 100644 --- a/src/doc/ru/tutorial/interfaces.rst +++ b/src/doc/ru/tutorial/interfaces.rst @@ -264,8 +264,8 @@ gnuplot, ะธะผะตะตั‚ ะผะตั‚ะพะดั‹ ั€ะตัˆะตะฝะธั ะธ ะผะฐะฝะธะฟัƒะปัั†ะธะธ ะผะฐั‚ matrix([1,1/2,1/3,1/4],[0,0,0,0],[0,0,0,0],[0,0,0,0]) sage: A.eigenvalues() [[0,4],[3,1]] - sage: A.eigenvectors() - [[[0,4],[3,1]],[[[1,0,0,-4],[0,1,0,-2],[0,0,1,-4/3]],[[1,2,3,4]]]] + sage: A.eigenvectors().sage() + [[[0, 4], [3, 1]], [[[1, 0, 0, -4], [0, 1, 0, -2], [0, 0, 1, -4/3]], [[1, 2, 3, 4]]]] ะ’ะพั‚ ะดั€ัƒะณะพะน ะฟั€ะธะผะตั€: @@ -323,12 +323,9 @@ gnuplot, ะธะผะตะตั‚ ะผะตั‚ะพะดั‹ ั€ะตัˆะตะฝะธั ะธ ะผะฐะฝะธะฟัƒะปัั†ะธะธ ะผะฐั‚ :: - sage: maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0) - 10.0") - 5*cos(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0)-10.0 - sage: maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") - -5*sin(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0) - sage: maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") - 5*(cos(x/2)*sin(2*y)-sin(x/2)*cos(y)) + sage: _ = maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0) - 10.0") + sage: _ = maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") + sage: _ = maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") sage: maxima.plot3d ("[expr_1, expr_2, expr_3]", "[x, -%pi, %pi]", # not tested ....: "[y, -%pi, %pi]", "['grid, 40, 40]", ....: '[plot_format, openmath]') diff --git a/src/doc/ru/tutorial/introduction.rst b/src/doc/ru/tutorial/introduction.rst index 445d17fb505..fe8681d8a79 100644 --- a/src/doc/ru/tutorial/introduction.rst +++ b/src/doc/ru/tutorial/introduction.rst @@ -97,7 +97,7 @@ Sage ะฒ ั€ะฐะทะดะตะปะต ะดะพะบัƒะผะตะฝั‚ะฐั†ะธะธ: [SA]_ ะ—ะดะตััŒ ะผั‹ ะฟั€ะธะฒ ะ ะฐะฑะพั‚ะฐ ะฒ Sage ะผะพะถะตั‚ ะฑั‹ั‚ัŒ ะพััƒั‰ะตัั‚ะฒะปะตะฝะฐ ะฝะตัะบะพะปัŒะบะธะผะธ ะฟัƒั‚ัะผะธ: -- **Notebook (ะณั€ะฐั„ะธั‡ะตัะบะธะน ะธะฝั‚ะตั€ั„ะตะนั):** ะทะฐะฟัƒัั‚ะธั‚ะต `sage -n jupyter`; ั‡ะธั‚ะฐะนั‚ะต +- **Notebook (ะณั€ะฐั„ะธั‡ะตัะบะธะน ะธะฝั‚ะตั€ั„ะตะนั):** ะทะฐะฟัƒัั‚ะธั‚ะต ``sage -n jupyter``; ั‡ะธั‚ะฐะนั‚ะต `Jupyter documentation on-line <https://jupyter-notebook.readthedocs.io/en/latest/notebook.html>`_, - **ะ˜ะฝั‚ะตั€ะฐะบั‚ะธะฒะฝะฐั ะบะพะผะฐะฝะดะฝะฐั ัั‚ั€ะพะบะฐ:** ัะผ. :ref:`chapter-interactive_shell`; diff --git a/src/doc/ru/tutorial/tour_algebra.rst b/src/doc/ru/tutorial/tour_algebra.rst index 9f08c41d118..bc0d4926f83 100644 --- a/src/doc/ru/tutorial/tour_algebra.rst +++ b/src/doc/ru/tutorial/tour_algebra.rst @@ -199,8 +199,8 @@ Sage ะผะพะถะตั‚ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒัั ะดะปั ั€ะตัˆะตะฝะธั ะดะธั„ั„ะตั€ :: sage: de1 = maxima("2*diff(x(t),t, 2) + 6*x(t) - 2*y(t)") - sage: lde1 = de1.laplace("t","s"); lde1 - 2*((-%at('diff(x(t),t,1),t = 0))+s^2*'laplace(x(t),t,s)-x(0)*s) -2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) + sage: lde1 = de1.laplace("t","s"); lde1.sage() + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) ะ”ะฐะฝะฝั‹ะน ั€ะตะทัƒะปัŒั‚ะฐั‚ ั‚ัะถะตะปะพ ั‡ะธั‚ะฐะตะผ, ะพะดะฝะฐะบะพ ะดะพะปะถะตะฝ ะฑั‹ั‚ัŒ ะฟะพะฝัั‚ ะบะฐะบ @@ -210,9 +210,12 @@ Sage ะผะพะถะตั‚ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒัั ะดะปั ั€ะตัˆะตะฝะธั ะดะธั„ั„ะตั€ :: - sage: de2 = maxima("diff(y(t),t, 2) + 2*y(t) - 2*x(t)") - sage: lde2 = de2.laplace("t","s"); lde2 - (-%at('diff(y(t),t,1),t = 0))+s^2*'laplace(y(t),t,s) +2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s) -y(0)*s + sage: t,s = SR.var('t,s') + sage: x = function('x') + sage: y = function('y') + sage: f = 2*x(t).diff(t,2) + 6*x(t) - 2*y(t) + sage: f.laplace(t,s) + 2*s^2*laplace(x(t), t, s) - 2*s*x(0) + 6*laplace(x(t), t, s) - 2*laplace(y(t), t, s) - 2*D[0](x)(0) ะ ะตะทัƒะปัŒั‚ะฐั‚: diff --git a/src/pyproject.toml.m4 b/src/pyproject.toml.m4 index 56f1b2b03ab..f707b6f890e 100644 --- a/src/pyproject.toml.m4 +++ b/src/pyproject.toml.m4 @@ -6,7 +6,7 @@ requires = [ # https://github.com/pypa/pip/issues/6144 esyscmd(`sage-get-system-packages install-requires-toml \ sage_conf \ - setuptools \ + setuptools_wheel \ wheel \ sage_setup \ cypari \ diff --git a/src/requirements.txt.m4 b/src/requirements.txt.m4 index a6cba21cc7e..346ea3c6301 100644 --- a/src/requirements.txt.m4 +++ b/src/requirements.txt.m4 @@ -20,6 +20,8 @@ dnl ... but building bdist_wheel of cypari2 fails with recent pip... https://git cysignals==esyscmd(`printf $(sed "s/[.]p.*//;" ../cysignals/package-version.txt)') Cython==esyscmd(`printf $(sed "s/[.]p.*//;" ../cython/package-version.txt)') gmpy2==esyscmd(`printf $(sed "s/[.]p.*//;" ../gmpy2/package-version.txt)') +importlib_metadata==esyscmd(`printf $(sed "s/[.]p.*//;" ../importlib_metadata/package-version.txt)') +importlib_resources==esyscmd(`printf $(sed "s/[.]p.*//;" ../importlib_resources/package-version.txt)') jinja2==esyscmd(`printf $(sed "s/[.]p.*//;" ../jinja2/package-version.txt)') dnl ... for sage_setup.autogen.interpreters jupyter_core==esyscmd(`printf $(sed "s/[.]p.*//;" ../jupyter_core/package-version.txt)') @@ -32,6 +34,7 @@ pplpy==esyscmd(`printf $(sed "s/[.]p.*//;" ../pplpy/package-version.txt)') primecountpy==esyscmd(`printf $(sed "s/[.]p.*//;" ../primecountpy/package-version.txt)') pycygwin==esyscmd(`printf $(sed "s/[.]p.*//;" ../pycygwin/package-version.txt)'); sys_platform == 'cygwin' requests==esyscmd(`printf $(sed "s/[.]p.*//;" ../requests/package-version.txt)') +typing_extensions==esyscmd(`printf $(sed "s/[.]p.*//;" ../typing_extensions/package-version.txt)') dnl From Makefile.in: SAGERUNTIME ipython==esyscmd(`printf $(sed "s/[.]p.*//;" ../ipython/package-version.txt)') diff --git a/src/sage/algebras/affine_nil_temperley_lieb.py b/src/sage/algebras/affine_nil_temperley_lieb.py index 8aff4321abb..720c5f481cd 100644 --- a/src/sage/algebras/affine_nil_temperley_lieb.py +++ b/src/sage/algebras/affine_nil_temperley_lieb.py @@ -7,7 +7,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.categories.all import AlgebrasWithBasis +from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.weyl_group import WeylGroup from sage.rings.ring import Ring @@ -119,7 +119,7 @@ def _repr_(self): sage: A = AffineNilTemperleyLiebTypeA(3); A The affine nilTemperley Lieb algebra A3 over the ring Integer Ring """ - return "The affine nilTemperley Lieb algebra A%s over the ring %s"%(self._n, self._base_ring) + return "The affine nilTemperley Lieb algebra A%s over the ring %s" % (self._n, self._base_ring) def weyl_group(self): """ @@ -234,7 +234,7 @@ def has_no_braid_relation(self, w, i): return False s = w.parent().simple_reflections() wi = w*s[i] - adjacent = [(i-1)%w.parent().n, (i+1)%w.parent().n] + adjacent = [(i-1) % w.parent().n, (i+1) % w.parent().n] for j in adjacent: if j in w.descents(): if j in wi.descents(): @@ -258,6 +258,6 @@ def _repr_term(self, t, short_display=True): if len(redword) == 0: return "1" elif short_display: - return "*".join("%s%d"%(self._prefix, i) for i in redword) + return "*".join("%s%d" % (self._prefix, i) for i in redword) else: - return "*".join("%s[%d]"%(self._prefix, i) for i in redword) + return "*".join("%s[%d]" % (self._prefix, i) for i in redword) diff --git a/src/sage/algebras/algebra.py b/src/sage/algebras/algebra.py index 5c64a2c4ad0..5aac6f22b9a 100644 --- a/src/sage/algebras/algebra.py +++ b/src/sage/algebras/algebra.py @@ -29,8 +29,13 @@ def is_Algebra(x): sage: from sage.algebras.algebra import is_Algebra sage: R.<x,y> = FreeAlgebra(QQ,2) sage: is_Algebra(R) + doctest:warning... + DeprecationWarning: the function is_Algebra is deprecated; use '... in Algebras(base_ring)' instead + See https://github.com/sagemath/sage/issues/35253 for details. True """ + from sage.misc.superseded import deprecation + deprecation(35253, "the function is_Algebra is deprecated; use '... in Algebras(base_ring)' instead") try: return isinstance(x, Algebra) or x in Algebras(x.base_ring()) except Exception: diff --git a/src/sage/algebras/all.py b/src/sage/algebras/all.py index ac06fa76ab8..14be60e8f56 100644 --- a/src/sage/algebras/all.py +++ b/src/sage/algebras/all.py @@ -48,6 +48,8 @@ lazy_import('sage.algebras.jordan_algebra', 'JordanAlgebra') +lazy_import('sage.algebras.octonion_algebra', 'OctonionAlgebra') + lazy_import('sage.algebras.shuffle_algebra', 'ShuffleAlgebra') from .clifford_algebra import CliffordAlgebra, ExteriorAlgebra diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index 1ccf517e2c0..efda74ed00e 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -23,6 +23,7 @@ - :class:`algebras.Descent <sage.combinat.descent_algebra.DescentAlgebra>` - :class:`algebras.DifferentialWeyl <sage.algebras.weyl_algebra.DifferentialWeylAlgebra>` +- :class:`algebras.DownUp <sage.algebras.down_up_algebra.DownUpAlgebra>` - :class:`algebras.Exterior <sage.algebras.clifford_algebra.ExteriorAlgebra>` - :class:`algebras.FiniteDimensional <sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra.FiniteDimensionalAlgebra>` @@ -47,6 +48,7 @@ - :class:`algebras.MalvenutoReutenauer <sage.combinat.fqsym.FreeQuasisymmetricFunctions>` - :class:`algebras.NilCoxeter <sage.algebras.nil_coxeter_algebra.NilCoxeterAlgebra>` +- :class:`algebras.Octonion <sage.algebras.octonion_algebra.OctonionAlgebra>` - :class:`algebras.OrlikTerao <sage.algebras.orlik_terao.OrlikTeraoAlgebra>` - :class:`algebras.OrlikSolomon @@ -62,6 +64,8 @@ - :class:`algebras.PlanarPartition <sage.combinat.diagram_algebras.PlanarAlgebra>` - :class:`algebras.qCommutingPolynomials <sage.algebras.q_commuting_polynomials.qCommutingPolynomials>` +- :class:`algebras.qCommutingLaurentPolynomials + <sage.algebras.q_commuting_polynomials.qCommutingLaurentPolynomials>` - :class:`algebras.QuantumGroup <sage.algebras.quantum_groups.quantum_group_gap.QuantumGroup>` - :func:`algebras.Quaternion @@ -127,10 +131,13 @@ 'QuantumMatrixCoordinateAlgebra', 'QuantumMatrixCoordinate') lazy_import('sage.algebras.quantum_matrix_coordinate_algebra', 'QuantumGL') lazy_import('sage.algebras.q_commuting_polynomials', 'qCommutingPolynomials') +lazy_import('sage.algebras.q_commuting_polynomials', 'qCommutingLaurentPolynomials') lazy_import('sage.algebras.tensor_algebra', 'TensorAlgebra', 'Tensor') lazy_import('sage.algebras.quantum_groups.quantum_group_gap', 'QuantumGroup') lazy_import('sage.algebras.quantum_groups.ace_quantum_onsager', 'ACEQuantumOnsagerAlgebra', 'AlternatingCentralExtensionQuantumOnsager') +lazy_import('sage.algebras.down_up_algebra', 'DownUpAlgebra', 'DownUp') lazy_import('sage.algebras.yangian', 'Yangian') +lazy_import('sage.algebras.octonion_algebra', 'OctonionAlgebra', 'Octonion') del lazy_import # We remove the object from here so it doesn't appear under tab completion diff --git a/src/sage/algebras/cellular_basis.py b/src/sage/algebras/cellular_basis.py index 42ce84307d5..873bd899b3e 100644 --- a/src/sage/algebras/cellular_basis.py +++ b/src/sage/algebras/cellular_basis.py @@ -233,7 +233,7 @@ def _latex_term(self, x): sm = latex(m) if sm.find('\\text{\\textt') != -1: sm = str(m) - return "C^{%s}_{%s}"%(sla, sm) + return "C^{%s}_{%s}" % (sla, sm) def cellular_basis_of(self): """ diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 04d9b3f0cae..220a2eb27a5 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -571,8 +571,8 @@ def _coerce_map_from_(self, V): Q = self._quadratic_form try: return (V.variable_names() == self.variable_names() and - V._quadratic_form.base_change_to(self.base_ring()) == Q) - except Exception: + V._quadratic_form.change_ring(self.base_ring()) == Q) + except (TypeError, AttributeError): return False if self.free_module().has_coerce_map_from(V): diff --git a/src/sage/algebras/clifford_algebra_element.pxd b/src/sage/algebras/clifford_algebra_element.pxd index 64ac7253351..14d5a7a625c 100644 --- a/src/sage/algebras/clifford_algebra_element.pxd +++ b/src/sage/algebras/clifford_algebra_element.pxd @@ -1,7 +1,6 @@ """ Clifford algebra elements """ - from sage.modules.with_basis.indexed_element cimport IndexedFreeModuleElement from sage.data_structures.bitset cimport FrozenBitset @@ -14,4 +13,3 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): cdef class CohomologyRAAGElement(CliffordAlgebraElement): pass - diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index 6a12d5657a3..046ee44c8e9 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -6,8 +6,7 @@ AUTHORS: - Travis Scrimshaw (2013-09-06): Initial version - Trevor Karn (2022-07-10): Rewrite multiplication using bitsets """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2022 Trevor K. Karn <karnx018 at umn.edu> # (C) 2022 Travis Scrimshaw <tcscrims at gmail.com> # @@ -16,8 +15,7 @@ AUTHORS: # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** - +# **************************************************************************** from sage.structure.parent cimport Parent from sage.data_structures.bitset cimport Bitset from sage.algebras.weyl_algebra import repr_from_monomials @@ -125,7 +123,7 @@ cdef class CliffordAlgebraElement(IndexedFreeModuleElement): for ml, cl in self: # Distribute the current term ``cl`` * ``ml`` over ``other``. - cur = copy(other._monomial_coefficients) # The current distribution of the term + cur = copy(other._monomial_coefficients) # The current distribution of the term for i in reversed(ml): # Distribute the current factor ``e[i]`` (the ``i``-th # element of the standard basis). @@ -142,10 +140,10 @@ cdef class CliffordAlgebraElement(IndexedFreeModuleElement): break # Add the additional term from the commutation # get a non-frozen bitset to manipulate - t = Bitset(mr) # a mutable copy + t = Bitset(mr) # a mutable copy t.discard(j) t = FrozenBitset(t) - next_level[t] = next_level.get(t, zero) + cr * Q[i,j] + next_level[t] = next_level.get(t, zero) + cr * Q[i, j] # Note: ``Q[i,j] == Q(e[i]+e[j]) - Q(e[i]) - Q(e[j])`` for # ``i != j``, where ``e[k]`` is the ``k``-th standard # basis vector. @@ -154,16 +152,16 @@ cdef class CliffordAlgebraElement(IndexedFreeModuleElement): del next_level[t] # Check to see if we have a squared term or not - mr = Bitset(mr) # temporarily mutable + mr = Bitset(mr) # temporarily mutable if i in mr: mr.discard(i) - cr *= Q[i,i] + cr *= Q[i, i] # Note: ``Q[i,i] == Q(e[i])`` where ``e[i]`` is the # ``i``-th standard basis vector. else: # mr is implicitly sorted mr.add(i) - mr = FrozenBitset(mr) # refreeze it + mr = FrozenBitset(mr) # refreeze it next_level[mr] = next_level.get(mr, zero) + cr if next_level[mr] == zero: del next_level[mr] @@ -213,11 +211,6 @@ cdef class CliffordAlgebraElement(IndexedFreeModuleElement): sage: r * 2 # indirect doctest 2*x*y*z + 2*x*y + 2*x*z + 2*y*z + 2*x + 2*y + 2*z + 2 """ - cdef dict d - cdef list to_remove - cdef Py_ssize_t num_cross, tot_cross, i, j - cdef FrozenBitset ml - if supp.isempty(): # Multiplication by a base ring element if coeff == self._parent._base.one(): return self @@ -315,7 +308,8 @@ cdef class CliffordAlgebraElement(IndexedFreeModuleElement): sage: all(x.reflection().reflection() == x for x in Cl.basis()) True """ - return self.__class__(self._parent, {m: (-1)**len(m) * c for m,c in self}) + return self.__class__(self._parent, + {m: (-1)**len(m) * c for m, c in self}) degree_negation = reflection @@ -361,7 +355,7 @@ cdef class CliffordAlgebraElement(IndexedFreeModuleElement): if not self._monomial_coefficients: return P.zero() g = P.gens() - return P.sum(c * P.prod(g[i] for i in reversed(m)) for m,c in self) + return P.sum(c * P.prod(g[i] for i in reversed(m)) for m, c in self) def conjugate(self): r""" @@ -475,7 +469,7 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): ml = FrozenBitset() if ml in self._monomial_coefficients: const_coeff = self._monomial_coefficients[ml] - d = dict(rhs._monomial_coefficients) # Make a shallow copy + d = dict(rhs._monomial_coefficients) # Make a shallow copy to_remove = [] if const_coeff != P._base.one(): for k in d: @@ -488,10 +482,12 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): d = {} n = P.ngens() - for ml, cl in self._monomial_coefficients.items(): # ml for "monomial on the left" + for ml, cl in self._monomial_coefficients.items(): + # ml for "monomial on the left" if ml.isempty(): # We already handled the trivial element continue - for mr,cr in rhs._monomial_coefficients.items(): # mr for "monomial on the right" + for mr, cr in rhs._monomial_coefficients.items(): + # mr for "monomial on the right" if mr.isempty(): t = ml else: @@ -502,7 +498,7 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): it = iter(mr) j = next(it) - num_cross = 0 # keep track of the number of signs + num_cross = 0 # keep track of the number of signs tot_cross = 0 for i in ml: while i > j: @@ -576,7 +572,8 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): n = self._parent.ngens() d = {} - for ml, cl in self._monomial_coefficients.items(): # ml for "monomial on the left" + for ml, cl in self._monomial_coefficients.items(): + # ml for "monomial on the left" if not ml.isdisjoint(supp): # if they intersect nontrivially, move along. continue @@ -584,7 +581,7 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): it = iter(supp) j = next(it) - num_cross = 0 # keep track of the number of signs + num_cross = 0 # keep track of the number of signs tot_cross = 0 for i in ml: while i > j: @@ -668,7 +665,8 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): const_coeff = self._monomial_coefficients.pop(mr) d[supp] = const_coeff - for mr, cr in self._monomial_coefficients.items(): # mr for "monomial on the right" + for mr, cr in self._monomial_coefficients.items(): + # mr for "monomial on the right" if not supp.isdisjoint(mr): # if they intersect nontrivially, move along. continue @@ -676,7 +674,7 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): it = iter(mr) j = next(it) # We assume mr is non-empty here - num_cross = 0 # keep track of the number of signs + num_cross = 0 # keep track of the number of signs tot_cross = 0 for i in supp: while i > j: @@ -839,7 +837,7 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): """ P = self._parent return P.sum([c * cx * P.interior_product_on_basis(m, mx) - for m,c in self for mx,cx in x]) + for m, c in self for mx, cx in x]) antiderivation = interior_product @@ -968,7 +966,8 @@ cdef class CohomologyRAAGElement(CliffordAlgebraElement): tp = tuple(sorted(mr + ml)) if any(tp[i] == tp[i+1] for i in range(len(tp)-1)): # e_i ^ e_i = 0 continue - if tp not in I: # not an independent set, so this term is also 0 + if tp not in I: + # not an independent set, so this term is also 0 continue t = list(mr) diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index 62340be2072..b72d2a12976 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -354,7 +354,7 @@ from copy import copy -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.categories.homset import Hom from sage.categories.morphism import SetMorphism from sage.categories.rings import Rings @@ -613,7 +613,7 @@ def theta_basis_decomposition(self): y_exp = min(f_poly.dict()) coeff = f_poly.dict()[y_exp] g_theta = tuple(g_vect + B*vector(y_exp)) - out[g_theta] = out.get(g_theta, zero_A) + A({zero_t + tuple(y_exp):coeff}) + out[g_theta] = out.get(g_theta, zero_A) + A({zero_t + tuple(y_exp):coeff}) f_poly -= U({y_exp:coeff}) * A.theta_basis_F_polynomial(g_theta) return out diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index f0bf211bfc5..953364d6813 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -141,7 +141,7 @@ def sorting_keys(element): class Differential(UniqueRepresentation, Morphism, - metaclass=InheritComparisonClasscallMetaclass): + metaclass=InheritComparisonClasscallMetaclass): r""" Differential of a commutative graded algebra. @@ -204,7 +204,7 @@ def image_monomial(exponent): ell = len(cexp) while i < ell: if not cexp[i]: - i +=1 + i += 1 continue a = A.gen(i) try: @@ -214,7 +214,7 @@ def image_monomial(exponent): cexp[i] -= 1 b = A.prod(A.gen(j) ** cexp[j] for j in range(len(cexp))) db = image_monomial(cexp) - im = da * b + (-1)**A._degrees[i] * a * db + im = da * b + (-1)**A._degrees[i] * a * db return A(im) return A.zero() @@ -232,7 +232,7 @@ def image_monomial(exponent): != total_degree(i.degree()) + 1)): raise ValueError("the given dictionary does not determine a degree 1 map") - im_gens = tuple([im_gens.get(x, A.zero()) for x in A.gens()]) + im_gens = tuple(im_gens.get(x, A.zero()) for x in A.gens()) return super().__classcall__(cls, A, im_gens) def __init__(self, A, im_gens): @@ -333,8 +333,7 @@ def _repr_defn(self): z --> z*t t --> -z*t """ - return '\n'.join("{} --> {}".format(i, self(i)) - for i in self.domain().gens()) + return '\n'.join(f"{i} --> {self(i)}" for i in self.domain().gens()) def _repr_(self): r""" @@ -392,8 +391,8 @@ def differential_matrix(self, n): cod = A.basis(n + 1) cokeys = [next(iter(a.lift().dict().keys())) for a in cod] m = matrix(A.base_ring(), len(dom), len(cod)) - for i in range(len(dom)): - im = self(dom[i]) + for i, domi in enumerate(dom): + im = self(domi) dic = im.lift().dict() for j in dic.keys(): k = cokeys.index(j) @@ -555,13 +554,13 @@ def cohomology(self, n): [0 0 1 0 0 0 0 0 0 0] """ H = self.cohomology_raw(n) - H_basis_raw = [H.lift(H.basis()[i]) for i in range(H.dimension())] + H_basis_raw = (H.lift(H.basis()[i]) for i in range(H.dimension())) A = self.domain() B = A.basis(n) - H_basis = [sum(c * b for (c, b) in zip(coeffs, B)) for coeffs in - H_basis_raw] + H_basis = (sum(c * b for (c, b) in zip(coeffs, B)) + for coeffs in H_basis_raw) # Put brackets around classes. - H_basis_brackets = [CohomologyClass(b) for b in H_basis] + H_basis_brackets = [CohomologyClass(b, A) for b in H_basis] return CombinatorialFreeModule(A.base_ring(), H_basis_brackets, sorting_key=sorting_keys, @@ -591,7 +590,7 @@ def _is_nonzero(self): sage: bool(C.differential()) False """ - return any(x for x in self._dic_.values()) + return any(self._dic_.values()) class Differential_multigraded(Differential): @@ -671,8 +670,8 @@ def differential_matrix_multigraded(self, n, total=False): cod = A.basis(n + self._degree_of_differential) cokeys = [next(iter(a.lift().dict().keys())) for a in cod] m = matrix(self.base_ring(), len(dom), len(cod)) - for i in range(len(dom)): - im = self(dom[i]) + for i, domi in enumerate(dom): + im = self(domi) dic = im.lift().dict() for j in dic.keys(): k = cokeys.index(j) @@ -849,13 +848,13 @@ def cohomology(self, n, total=False): Free module generated by {[b]} over Rational Field """ H = self.cohomology_raw(n, total) - H_basis_raw = [H.lift(H.basis()[i]) for i in range(H.dimension())] + H_basis_raw = (H.lift(H.basis()[i]) for i in range(H.dimension())) A = self.domain() B = A.basis(n, total) - H_basis = [sum(c * b for (c, b) in zip(coeffs, B)) - for coeffs in H_basis_raw] + H_basis = (sum(c * b for (c, b) in zip(coeffs, B)) + for coeffs in H_basis_raw) # Put brackets around classes. - H_basis_brackets = [CohomologyClass(b) for b in H_basis] + H_basis_brackets = [CohomologyClass(b, A) for b in H_basis] return CombinatorialFreeModule(A.base_ring(), H_basis_brackets, sorting_key=sorting_keys, @@ -964,9 +963,8 @@ def __classcall__(cls, base, names=None, degrees=None, R=None, I=None, category= if names is None: if degrees is None: raise ValueError("you must specify names or degrees") - else: - n = len(degrees) - names = tuple('x{}'.format(i) for i in range(n)) + n = len(degrees) + names = tuple(f'x{i}' for i in range(n)) elif isinstance(names, str): names = tuple(names.split(',')) n = len(names) @@ -975,7 +973,7 @@ def __classcall__(cls, base, names=None, degrees=None, R=None, I=None, category= names = tuple(names) if degrees is None: - degrees = tuple([1 for i in range(n)]) + degrees = tuple([1] * n) else: # Deal with multigrading: convert lists and tuples to elements # of an additive abelian group. @@ -1074,7 +1072,7 @@ def _repr_(self): squares = [R.zero()] relns = [g for g in I.gens() if g not in squares] if relns: - s = s + " with relations {}".format(relns) + s += " with relations {}".format(relns) return s + " over {}".format(self.base_ring()) _base_repr = _repr_ @@ -1179,7 +1177,7 @@ def basis(self, n): free_basis = self._basis_for_free_alg(n) fb_reversed_entries = [list(reversed(e)) for e in free_basis] fb_reversed_entries.sort() - free_basis = [tuple(reversed(e)) for e in fb_reversed_entries] + free_basis = (tuple(reversed(e)) for e in fb_reversed_entries) basis = [] for v in free_basis: el = prod([self.gen(i)**v[i] for i in range(len(v))]) @@ -1912,8 +1910,7 @@ def degree(self, total=False): l = [sum(exp[i] * degrees[i] for i in range(n)) for exp in exps] if len(set(l)) == 1: return l[0] - else: - raise ValueError('this element is not homogeneous') + raise ValueError('this element is not homogeneous') ########################################################### @@ -2109,7 +2106,7 @@ def _repr_(self): t --> 0 """ d = self._differential._repr_defn().replace('\n', '\n ') - return self._base_repr() + " with differential:{}".format('\n ' + d) + return self._base_repr() + f" with differential:\n {d}" def quotient(self, I, check=True): """ @@ -2359,7 +2356,7 @@ def cohomology_generators(self, max_degree): sage: A3.<a,x,y> = GradedCommutativeAlgebra(GF(3), degrees=(1,2,2)) sage: B3 = A3.cdg_algebra(differential={y: a*x}) - sage: B3.cohomology_generators(20) + sage: B3.cohomology_generators(16) {1: [a], 2: [x], 3: [a*y], 5: [a*y^2], 6: [y^3]} This method works with both singly graded and multi-graded algebras:: @@ -2427,7 +2424,7 @@ def vector_to_element(v, deg): for g in Q.basis()] return res - def minimal_model(self, i=3, max_iterations=3): + def minimal_model(self, i=3, max_iterations=3, partial_result=False): r""" Try to compute a map from a ``i``-minimal gcda that is a ``i``-quasi-isomorphism to self. @@ -2440,7 +2437,12 @@ def minimal_model(self, i=3, max_iterations=3): - ``max_iterations`` -- integer (default: `3`); the number of iterations of the method at each degree. If the algorithm does not - finish in this many iterations at each degree, an error is raised. + finish in this many iterations at each degree, an error is raised, + or the partial result computed up to that point is returned, deppending + on the ``partial_result`` flag. + + - ``partial_result`` -- boolean (default: ``False``); wether to return + the partial result if the ``max_iterations`` limit is reached. OUTPUT: @@ -2579,6 +2581,34 @@ def minimal_model(self, i=3, max_iterations=3): t --> 0 Defn: (x3_0, x3_1) --> (z, t) + :: + + sage: A.<a,b,c> = GradedCommutativeAlgebra(QQ) + sage: I = A.ideal([a*b-a*c+b*c]) + sage: B = A.quotient(I) + sage: S = B.cdg_algebra({}) + sage: S.minimal_model() + Traceback (most recent call last): + ... + ValueError: could not cover all relations in max iterations in degree 2 + sage: S.minimal_model(partial_result=True) + Commutative Differential Graded Algebra morphism: + From: Commutative Differential Graded Algebra with generators + ('x1_0', 'x1_1', 'x1_2', 'y1_0', 'y1_1', 'y1_2') in degrees (1, 1, 1, 1, 1, 1) + over Rational Field with differential: + x1_0 --> 0 + x1_1 --> 0 + x1_2 --> 0 + y1_0 --> x1_0*x1_1 - x1_0*x1_2 + x1_1*x1_2 + y1_1 --> x1_0*y1_0 - x1_2*y1_0 + y1_2 --> x1_1*y1_0 - x1_2*y1_0 + To: Commutative Differential Graded Algebra with generators ('a', 'b', 'c') + in degrees (1, 1, 1) with relations [a*b - a*c + b*c] over Rational Field with differential: + a --> 0 + b --> 0 + c --> 0 + Defn: (x1_0, x1_1, x1_2, y1_0, y1_1, y1_2) --> (a, b, c, 0, 0, 0) + REFERENCES: - [Fel2001]_ @@ -2611,8 +2641,7 @@ def extend(phi, ndegrees, ndifs, nimags, nnames): for g in A.gens()[B.ngens():]: diff[g] = h(cndifs.pop(0)) NB = A.cdg_algebra(diff) - Nphi = NB.hom([phi(g) for g in B.gens()] + nimags, check=False) - return Nphi + return NB.hom([phi(g) for g in B.gens()] + nimags, check=False) def extendx(phi, degree): B = phi.domain() @@ -2631,8 +2660,7 @@ def extendx(phi, degree): QI = CS.quotient(phico.image()) self._numerical_invariants[degree] = [QI.dimension()] if QI.dimension() > 0: - nnames = ['x{}_{}'.format(degree, j) - for j in range(QI.dimension())] + nnames = [f'x{degree}_{j}' for j in range(QI.dimension())] nbasis = [] bbasis = self.basis(degree) for v in QI.basis(): @@ -2649,8 +2677,8 @@ def extendy(phi, degree): nnamesy = 0 for iteration in range(max_iterations): B = phi.domain() - imagesbcohom = [phi(g.representative()) for g in - B.cohomology(degree).basis().keys()] + imagesbcohom = [phi(g.representative()) + for g in B.cohomology(degree).basis().keys()] CS = self.cohomology_raw(degree) VS = CS.V() CB = B.cohomology_raw(degree) @@ -2666,7 +2694,7 @@ def extendy(phi, degree): if K.dimension() == 0: return phi if iteration == max_iterations - 1: - raise ValueError("could not cover all relations in max iterations in degree {}".format(degree)) + return (phi,) ndifs = [CB.lift(g) for g in K.basis()] basisdegree = B.basis(degree) ndifs = [sum(basisdegree[j] * g[j] for j in @@ -2704,7 +2732,12 @@ def extendy(phi, degree): B = A.cdg_algebra(A.differential({})) # Solve case that fails with one generator return B,gens phi = B.hom(gens) - phi = extendy(phi, degnzero + 1) + phiext = extendy(phi, degnzero + 1) + if isinstance(phiext, tuple): + if not partial_result: + raise ValueError("could not cover all relations in max iterations in degree {}".format(degnzero + 1)) + return phiext[0] + phi = phiext self._minimalmodels[degnzero] = phi else: degnzero = max(self._minimalmodels) @@ -2712,9 +2745,14 @@ def extendy(phi, degree): for degree in range(degnzero + 1, max_degree + 1): phi = extendx(phi, degree) - phi = extendy(phi, degree + 1) + phiext = extendy(phi, degree + 1) + if isinstance(phiext, tuple): + if partial_result: + return phiext[0] + else: + raise ValueError("could not cover all relations in max iterations in degree {}".format(degree + 1)) + phi = phiext self._minimalmodels[degree] = phi - return phi def cohomology_algebra(self, max_degree=3): @@ -2753,7 +2791,7 @@ def cohomology_algebra(self, max_degree=3): """ cohomgens = self.cohomology_generators(max_degree) if not cohomgens: - raise ValueError("Cohomology ring has no generators") + raise ValueError("cohomology ring has no generators") chgens = [] degrees = [] for d in cohomgens: @@ -2761,7 +2799,7 @@ def cohomology_algebra(self, max_degree=3): degrees.append(d) chgens.append(g) A = GradedCommutativeAlgebra(self.base_ring(), - ['x{}'.format(i) for i in range(len(chgens))], + [f'x{i}' for i in range(len(chgens))], degrees) rels = [] for d in range(1, max_degree + 1): @@ -2980,18 +3018,15 @@ def is_cohomologous_to(self, other): True sage: (x*y*z).is_cohomologous_to(0) # make sure 0 works True - """ if other.is_zero(): return self.is_coboundary() if (not isinstance(other, DifferentialGCAlgebra.Element) or self.parent() is not other.parent()): - raise ValueError('the element {} does not lie in this DGA' - .format(other)) + raise ValueError(f'the element {other} does not lie in this DGA') if (self - other).is_homogeneous(): return (self - other).is_coboundary() - else: - return (self.is_coboundary() and other.is_coboundary()) + return self.is_coboundary() and other.is_coboundary() def cohomology_class(self): r""" @@ -3032,9 +3067,9 @@ def cohomology_class(self): True """ if not self.is_homogeneous(): - raise ValueError("The element is not homogeneous") + raise ValueError("the element is not homogeneous") if not self.differential().is_zero(): - raise ValueError("The element is not closed") + raise ValueError("the element is not closed") d = self.degree() C = self.parent().cohomology(d) CR = self.parent().cohomology_raw(d) @@ -3067,7 +3102,7 @@ def _cohomology_class_dict(self): """ from sage.misc.flatten import flatten if not self.differential().is_zero(): - raise ValueError("The element is not closed") + raise ValueError("the element is not closed") if not self.is_homogeneous(): res = {} for d in self.homogeneous_parts().values(): @@ -3500,8 +3535,7 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, pass if multi: return GCAlgebra_multigraded(ring, names=names, degrees=degrees) - else: - return GCAlgebra(ring, names=names, degrees=degrees) + return GCAlgebra(ring, names=names, degrees=degrees) ################################################ @@ -3873,8 +3907,7 @@ def __call__(self, im_gens, check=True): from sage.categories.map import Map if isinstance(im_gens, Map): return self._coerce_impl(im_gens) - else: - return GCAlgebraMorphism(self, im_gens, check=check) + return GCAlgebraMorphism(self, im_gens, check=check) ################################################ @@ -3893,10 +3926,54 @@ class CohomologyClass(SageObject, CachedRepresentation): sage: CohomologyClass(3) [3] sage: A.<x,y,z,t> = GradedCommutativeAlgebra(QQ, degrees = (2,2,3,3)) - sage: CohomologyClass(x^2+2*y*z) + sage: CohomologyClass(x^2+2*y*z, A) [2*y*z + x^2] + + TESTS: + + In order for the cache to not confuse objects with the same representation, + we can pass the parent of the representative as a parameter:: + + sage: A.<e1,e2,e3,e4,e5,e6> = GradedCommutativeAlgebra(QQ) + sage: B1 = A.cdg_algebra({e5:e1*e2,e6:e3*e4}) + sage: B2 = A.cdg_algebra({e5:e1*e2,e6:e1*e2+e3*e4}) + sage: B1.minimal_model() + Commutative Differential Graded Algebra morphism: + From: Commutative Differential Graded Algebra with generators ('x1_0', 'x1_1', 'x1_2', 'x1_3', 'y1_0', 'y1_1') in degrees (1, 1, 1, 1, 1, 1) over Rational Field with differential: + x1_0 --> 0 + x1_1 --> 0 + x1_2 --> 0 + x1_3 --> 0 + y1_0 --> x1_0*x1_1 + y1_1 --> x1_2*x1_3 + To: Commutative Differential Graded Algebra with generators ('e1', 'e2', 'e3', 'e4', 'e5', 'e6') in degrees (1, 1, 1, 1, 1, 1) over Rational Field with differential: + e1 --> 0 + e2 --> 0 + e3 --> 0 + e4 --> 0 + e5 --> e1*e2 + e6 --> e3*e4 + Defn: (x1_0, x1_1, x1_2, x1_3, y1_0, y1_1) --> (e1, e2, e3, e4, e5, e6) + sage: B2.minimal_model() + Commutative Differential Graded Algebra morphism: + From: Commutative Differential Graded Algebra with generators ('x1_0', 'x1_1', 'x1_2', 'x1_3', 'y1_0', 'y1_1') in degrees (1, 1, 1, 1, 1, 1) over Rational Field with differential: + x1_0 --> 0 + x1_1 --> 0 + x1_2 --> 0 + x1_3 --> 0 + y1_0 --> x1_0*x1_1 + y1_1 --> x1_2*x1_3 + To: Commutative Differential Graded Algebra with generators ('e1', 'e2', 'e3', 'e4', 'e5', 'e6') in degrees (1, 1, 1, 1, 1, 1) over Rational Field with differential: + e1 --> 0 + e2 --> 0 + e3 --> 0 + e4 --> 0 + e5 --> e1*e2 + e6 --> e1*e2 + e3*e4 + Defn: (x1_0, x1_1, x1_2, x1_3, y1_0, y1_1) --> (e1, e2, e3, e4, e5, -e5 + e6) + """ - def __init__(self, x): + def __init__(self, x, cdga=None): """ EXAMPLES:: @@ -3905,6 +3982,7 @@ def __init__(self, x): [x - 2] """ self._x = x + self._cdga = cdga def __hash__(self): r""" @@ -3978,12 +4056,11 @@ def exterior_algebra_basis(n, degrees): [] """ if n == 0: - return [[0 for j in degrees]] + return [[0 for _ in degrees]] if len(degrees) == 1: if degrees[0] == n: return [[1]] - else: - return [] + return [] if not degrees: return [] if min(degrees) > n: @@ -3991,7 +4068,7 @@ def exterior_algebra_basis(n, degrees): if sum(degrees) < n: return [] if sum(degrees) == n: - return [[1 for j in degrees]] + return [[1 for _ in degrees]] i = len(degrees) // 2 res = [] for j in range(n + 1): diff --git a/src/sage/algebras/down_up_algebra.py b/src/sage/algebras/down_up_algebra.py new file mode 100644 index 00000000000..3ee1bcea25f --- /dev/null +++ b/src/sage/algebras/down_up_algebra.py @@ -0,0 +1,858 @@ +r""" +Down-Up Algebras + +AUTHORS: + +- Travis Scrimshaw (2023-4): initial version +""" + +# **************************************************************************** +# Copyright (C) 2023 Travis Scrimshaw <tcscrims at gmail.com> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.categories.algebras import Algebras +from sage.categories.modules import Modules +from sage.categories.rings import Rings +from sage.combinat.free_module import CombinatorialFreeModule +from sage.sets.non_negative_integers import NonNegativeIntegers +from sage.categories.sets_cat import cartesian_product +from sage.sets.family import Family +from sage.misc.lazy_list import lazy_list +from sage.misc.misc_c import prod +from sage.modules.free_module import FreeModule + +class DownUpAlgebra(CombinatorialFreeModule): + r""" + The down-up algebra. + + Let `R` be a commutative ring, and let `\alpha, \beta, \gamma \in R`. + The *down-up algebra* is the associative unital algebra + `DU(\alpha, \beta, \gamma)` generated by `d, u` with relations + + .. MATH:: + + \begin{aligned} + d^2u & = \alpha dud + \beta ud^2 + \gamma d, + \\ du^2 & = \alpha udu + \beta u^2d + \gamma u. + \end{aligned} + + The down-up algebra has a PBW-type basis given by + + .. MATH:: + + \{ u^i (du)^j d^k \mid i,j,k \in \ZZ_{\geq 0} \}. + + This algebra originates in the study of posets. For a poset `P`, + we define operators acting on `R[P]` by + + .. MATH:: + + d(y) = \sum_x x \qquad\qquad u(y) = \sum_z z, + + where `y` covers `x` and `z` covers `y`. For `r`-differential posets + we have `du - ud = r 1`, and thus it affords a representation of a + :class:`Weyl algebra <sage.algebras.weyl_algebra.DifferentialWeylAlgebra>`. + This Weyl algebra is obtained as the quotient of `DU(0, 1, 2r)` by the + ideal generated by `du - ud - r`. For a `(q, r)`-differential poset, + we have the `d` and `u` operators satisfying + + .. MATH:: + + \begin{aligned} + d^2u & = q(q+1) dud - q^3 ud^2 + r d, + \\ du^2 & = q(q+1) udu - q^3 u^2d + r u, + \end{aligned} + + or `\alpha = q(q+1)`, `\beta = -q^3`, and `\gamma = r`. Specializing + `q = -1` recovers the `r`-differential poset relation. + + Two other noteworthy quotients are: + + - the `q`-Weyl algebra from `DU(0, q^2, q+1)` by the ideal generated by + `du - qud - 1`, and + - the quantum plane `R_q[d, u]`, where `du = qud`, from `DU(2q, -q^2, 0)` + by the ideal generated by `du - qud`. + + EXAMPLES: + + We begin by constructing the down-up algebra and perform some + basic computations:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: d, u = DU.gens() + sage: d * u + (d*u) + sage: u * d + u*d + sage: d^2 * u + b*u*d^2 + a*(d*u)*d + g*d + sage: d * u^2 + b*u^2*d + a*u*(d*u) + g*u + + We verify some examples of Proposition 3.5 in [BR1998]_, which states + that the 0-th degree part is commutative:: + + sage: DU0 = [u^i * (d*u)^j * d^i for i,j in + ....: cartesian_product([range(3), range(3)])] + sage: all(x.degree() == 0 for x in DU0) + True + sage: all(x * y == y * x for x, y in cartesian_product([DU0, DU0])) + True + + We verify that `DU(2, -1, \gamma)` can be described as the universal + enveloping algebra of the 3-dimensional Lie algebra spanned by `x,y,z` + satisfying `z = [x, y]`, `[x, z] = \gamma x`, and `[z, y] = \gamma y`:: + + sage: R.<g> = QQ[] + sage: L = LieAlgebra(R, {('x','y'): {'z': 1}, ('x','z'): {'x': g}, ('z','y'): {'y': g}}, + ....: names='x,y,z') + sage: x, y, z = L.basis() + sage: (L[x, y], L[x, z], L[z, y]) + (z, g*x, g*y) + sage: x, y, z = L.pbw_basis().gens() + sage: x^2*y - 2*x*y*x + y*x^2 == g*x + True + sage: x*y^2 - 2*y*x*y + y^2*x == g*y + True + sage: DU = algebras.DownUp(2, -1, g) + sage: d, u = DU.gens() + sage: d^2*u - 2*d*u*d + u*d^2 == g*d + True + sage: d*u^2 - 2*u*d*u + u^2*d == g*u + True + + Young's lattice is known to be a differential poset. Thus we can + construct a representation of `DU(0, 1, 2)` on this poset (which + gives a proof that Fomin's :class:`growth diagrams <GrowthDiagram>` + are equivalent to edge local rules or shadow lines construction + for :func:`RSK`):: + + sage: DU = algebras.DownUp(0, 1, 2) + sage: d, u = DU.gens() + sage: d^2*u == 0*d*u*d + 1*u*d*d + 2*d + True + sage: d*u^2 == 0*u*d*u + 1*u*u*d + 2*u + True + + sage: YL = CombinatorialFreeModule(DU.base_ring(), Partitions()) + sage: def d_action(la): + ....: return YL.sum_of_monomials(la.remove_cell(*c) for c in la.removable_cells()) + sage: def u_action(la): + ....: return YL.sum_of_monomials(la.add_cell(*c) for c in la.addable_cells()) + sage: D = YL.module_morphism(on_basis=d_action, codomain=YL) + sage: U = YL.module_morphism(on_basis=u_action, codomain=YL) + sage: for la in PartitionsInBox(5, 5): + ....: b = YL.basis()[la] + ....: assert (D*D*U)(b) == 0*(D*U*D)(b) + 1*(U*D*D)(b) + 2*D(b) + ....: assert (D*U*U)(b) == 0*(U*D*U)(la) + 1*(U*U*D)(b) + 2*U(b) + ....: assert (D*U)(b) == (U*D)(b) + b # the Weyl algebra relation + + .. TODO:: + + Implement the homogenized version. + + REFERENCES: + + - [BR1998]_ + - [CM2000]_ + """ + @staticmethod + def __classcall_private__(cls, alpha, beta, gamma, base_ring=None): + r""" + Standardize input to ensure a unique representation. + + TESTS:: + + sage: R.<a,b,g> = QQ[] + sage: DU1 = algebras.DownUp(a, 1, g) + sage: DU2 = algebras.DownUp(a, R.one(), g) + sage: DU3 = algebras.DownUp(a, 1, g, R) + sage: DU1 is DU2 and DU2 is DU3 + True + """ + if base_ring is None: + from sage.structure.element import get_coercion_model + base_ring = get_coercion_model().common_parent(alpha, beta, gamma) + if base_ring not in Rings().Commutative(): + raise TypeError("base ring must be a commutative ring") + alpha = base_ring(alpha) + beta = base_ring(beta) + gamma = base_ring(gamma) + return super().__classcall__(cls, alpha, beta, gamma, base_ring=base_ring) + + def __init__(self, alpha, beta, gamma, base_ring): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: d, u = DU.gens() + sage: elts = [d, u, d^2, u^2, d*u, u*d] + sage: TestSuite(DU).run(elements=elts) + sage: elts += [d*(d*u)*u] + sage: TestSuite(DU).run(elements=elts) # long time + """ + self._alpha = alpha + self._beta = beta + self._gamma = gamma + cat = Algebras(base_ring).WithBasis().Graded() + if self._beta: + from sage.categories.domains import Domains + cat &= Domains() + indices = cartesian_product([NonNegativeIntegers()] * 3) + CombinatorialFreeModule.__init__(self, base_ring, indices, category=cat, sorting_reverse=True) + self._assign_names(['d', 'u']) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: DU = algebras.DownUp(1, 2, 3) + sage: DU + Down-Up algebra with parameters (1, 2, 3) over Integer Ring + """ + return "Down-Up algebra with parameters ({}, {}, {}) over {}".format( + self._alpha, self._beta, self._gamma, self.base_ring()) + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: latex(DU) + \mathcal{DU}(a,b,g) + """ + return "\\mathcal{DU}(%s,%s,%s)" % (self._alpha, self._beta, self._gamma) + + def _repr_term(self, m): + r""" + Return a string representation of the basis element indexed by ``m``. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: I = DU.indices() + sage: DU._repr_term(I([1,0,5])) + 'u*d^5' + sage: DU._repr_term(I([6,3,1])) + 'u^6*(d*u)^3*d' + sage: DU._repr_term(I([0,1,2])) + '(d*u)*d^2' + sage: DU._repr_term(I([0,0,0])) + '1' + """ + if not any(m): + return '1' + ret = '' + for i, s in enumerate(['u', '(d*u)', 'd']): + if not m[i]: + continue + if ret: + ret += '*' + if m[i] == 1: + ret += s + else: + ret += f"{s}^{m[i]}" + return ret + + def _latex_term(self, m): + r""" + Return a latex representation for the basis element indexed by ``m``. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: I = DU.indices() + sage: DU._latex_term(I([1,0,5])) + 'ud^{5}' + sage: DU._latex_term(I([6,3,1])) + 'u^{6}(du)^{3}d' + sage: DU._latex_term(I([0,1,2])) + '(du)d^{2}' + sage: DU._latex_term(I([0,0,0])) + '1' + """ + if all(val == 0 for val in m): + return '1' + ret = '' + for i, s in enumerate(['u', '(du)', 'd']): + if not m[i]: + continue + if m[i] == 1: + ret += s + else: + ret += f"{s}^{{{m[i]}}}" + return ret + + @cached_method + def algebra_generators(self): + r""" + Return the algebra generators of ``self``. + + EXAMPLES:: + + sage: DU = algebras.DownUp(2, 3, 4) + sage: dict(DU.algebra_generators()) + {'d': d, 'u': u} + """ + u = self.monomial(self._indices([1,0,0])) + d = self.monomial(self._indices([0,0,1])) + return Family({'d': d, 'u': u}) + + @cached_method + def gens(self): + r""" + Return the generators of ``self``. + + EXAMPLES:: + + sage: DU = algebras.DownUp(2, 3, 4) + sage: DU.gens() + (d, u) + """ + G = self.algebra_generators() + return (G['d'], G['u']) + + @cached_method + def one_basis(self): + r""" + Return the index of the basis element of `1`. + + EXAMPLES:: + + sage: DU = algebras.DownUp(2, 3, 4) + sage: DU.one_basis() + (0, 0, 0) + """ + return self._indices([0, 0, 0]) + + def product_on_basis(self, m1, m2): + r""" + Return the product of the basis elements indexed by ``m1`` and ``m2``. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: I = DU.indices() + sage: DU.product_on_basis(I([2,0,0]), I([4,0,0])) + u^6 + sage: DU.product_on_basis(I([2,0,0]), I([0,4,0])) + u^2*(d*u)^4 + sage: DU.product_on_basis(I([2,0,0]), I([0,0,4])) + u^2*d^4 + sage: DU.product_on_basis(I([0,2,0]), I([0,4,0])) + (d*u)^6 + sage: DU.product_on_basis(I([0,2,0]), I([0,0,4])) + (d*u)^2*d^4 + sage: DU.product_on_basis(I([0,0,2]), I([0,0,4])) + d^6 + sage: DU.product_on_basis(I([5,3,1]), I([1,0,4])) + u^5*(d*u)^4*d^4 + + sage: DU.product_on_basis(I([0,1,0]), I([1,0,0])) + b*u^2*d + a*u*(d*u) + g*u + sage: DU.product_on_basis(I([0,0,2]), I([1,0,0])) + b*u*d^2 + a*(d*u)*d + g*d + sage: DU.product_on_basis(I([0,0,1]), I([2,0,0])) + b*u^2*d + a*u*(d*u) + g*u + sage: DU.product_on_basis(I([0,0,1]), I([0,1,0])) + b*u*d^2 + a*(d*u)*d + g*d + + sage: DU.product_on_basis(I([0,1,0]), I([3,0,0])) + (a^2*b+b^2)*u^4*d + (a^3+2*a*b)*u^3*(d*u) + (a^2*g+a*g+b*g+g)*u^3 + sage: DU.product_on_basis(I([1,1,3]), I([0,1,1])) + (a^2*b^2+b^3)*u^3*d^6 + (a^3*b+a*b^2)*u^2*(d*u)*d^5 + (a^2*b*g+b^2*g)*u^2*d^5 + + (a^3+2*a*b)*u*(d*u)^2*d^4 + (a^2*g+a*g+b*g+g)*u*(d*u)*d^4 + """ + # Check trivial cases + if not any(m1): + return self.monomial(m2) + if not any(m2): + return self.monomial(m1) + + u1, du1, d1 = m1 + u2, du2, d2 = m2 + I = self._indices + + if not d1: + if not u2: + return self.monomial(I([u1, du1+du2, d2])) + # else u2 > 0 + if not du1: + return self.monomial(I([u1+u2, du2, d2])) + # Perform du * u reduction + lhs = self.monomial(I([u1, du1-1, 0])) + mid = self._from_dict({I([1,1,0]): self._alpha, + I([2,0,1]): self._beta, + I([1,0,0]): self._gamma}) + rhs = self.monomial(I([u2-1, du2, d2])) + else: # d1 > 0 + if not u2: + if not du2: + return self.monomial(I([u1, du1, d1+d2])) + # Perform a d * du reduction + lhs = self.monomial(I([u1, du1, d1-1])) + mid = self._from_dict({I([0,1,1]): self._alpha, + I([1,0,2]): self._beta, + I([0,0,1]): self._gamma}) + rhs = self.monomial(I([0, du2-1, d2])) + elif u2 > 1: + # Perform d * u^2 reduction + lhs = self.monomial(I([u1, du1, d1-1])) + mid = self._from_dict({I([1,1,0]): self._alpha, + I([2,0,1]): self._beta, + I([1,0,0]): self._gamma}) + rhs = self.monomial(I([u2-2, du2, d2])) + elif u2 == 1: + if d1 == 1: + return self.monomial(I([u1, du1+du2+1, d2])) + # Perform a d^2 * u reduction + lhs = self.monomial(I([u1, du1, d1-2])) + mid = self._from_dict({I([0,1,1]): self._alpha, + I([1,0,2]): self._beta, + I([0,0,1]): self._gamma}) + rhs = self.monomial(I([0, du2, d2])) + + if lhs == self.one(): + if rhs == self.one(): + return mid + return mid * rhs + if rhs == self.one(): + return lhs * mid + return lhs * mid * rhs + + def degree_on_basis(self, m): + r""" + Return the degree of the basis element indexed by ``m``. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: I = DU.indices() + sage: DU.degree_on_basis(I([0, 3, 2])) + -2 + sage: DU.degree_on_basis(I([2, 3, 0])) + 2 + sage: DU.degree_on_basis(I([2, 0, 3])) + -1 + sage: DU.degree_on_basis(I([3, 10, 3])) + 0 + """ + return m[0] - m[2] + + def verma_module(self, la): + r""" + Return the :class:`Verma module + <sage.algebras.down_up_algebra.VermaModule>` + `V(\lambda)` of ``self``. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: DU.verma_module(5) + Verma module of weight 5 of Down-Up algebra with parameters (a, b, g) + over Multivariate Polynomial Ring in a, b, g over Rational Field + """ + return VermaModule(self, la) + + +class VermaModule(CombinatorialFreeModule): + r""" + The Verma module `V(\lambda)` of a down-up algebra. + + The Verma module `V(\lambda)` for the down-up algebra generated + by `d, u` is the span of `\{v_n \mid n \in \ZZ_{\geq 0} \}` + satisfying the relations + + .. MATH:: + + d \cdot v_n = \lambda_{n-1} v_{n-1}, \qquad\qquad + u \cdot v_n = v_{n+1}, + + where `\lambda_n = \alpha \lambda_{n-1} + \beta \lambda_{n-2} + \gamma` + and we set `\lambda_0 = \lambda` and `\lambda_{-1} = 0`. + + By Proposition 2.4 in [BR1998]_, `V(\lambda)` is simple if and + only if `\lambda_n \neq 0` for all `n \geq 0`. Moreover, a maximal + submodule is spanned by `\{ v_n \mid n > m \}`, where `m` is the + minimal index such that `\lambda_m = 0`. Moreover, this is unique + unless `\gamma = \lambda = 0`. + + EXAMPLES:: + + sage: R.<a,b> = QQ[] + sage: DU = algebras.DownUp(0, b, 1) + sage: d, u = DU.gens() + sage: V = DU.verma_module(a) + sage: list(V.weights()[:6]) + [a, 1, a*b + 1, b + 1, a*b^2 + b + 1, b^2 + b + 1] + sage: v = V.basis() + sage: d^2 * v[2] + a*v[0] + sage: d * (d * v[2]) + a*v[0] + + The weight is computed by looking at the scalars associated to the + action of `du` and `ud`:: + + sage: d*u * v[3] + (b+1)*v[3] + sage: u*d * v[3] + (a*b+1)*v[3] + sage: v[3].weight() + (b + 1, a*b + 1) + + An `U(\mathfrak{sl}_2)` example:: + + sage: DU = algebras.DownUp(2, -1, -2) + sage: d, u = DU.gens() + sage: V = DU.verma_module(5) + sage: list(V.weights()[:10]) + [5, 8, 9, 8, 5, 0, -7, -16, -27, -40] + sage: v6 = V.basis()[6] + sage: d * v6 + 0 + sage: [V.basis()[i].weight() for i in range(6)] + [(5, 0), (8, 5), (9, 8), (8, 9), (5, 8), (0, 5)] + + Note that these are the same `\mathfrak{sl}_2` weights from the usual + construction of the irreducible representation `V(5)` (but they are + different as `\mathfrak{gl}_2` weights):: + + sage: B = crystals.Tableaux(['A',1], shape=[5]) + sage: [b.weight() for b in B] + [(5, 0), (4, 1), (3, 2), (2, 3), (1, 4), (0, 5)] + + An example with periodic weights (see Theorem 2.13 of [BR1998]_):: + + sage: k.<z6> = CyclotomicField(6) + sage: al = z6 + 1 + sage: (al - 1)^6 == 1 + True + sage: DU = algebras.DownUp(al, 1-al, 0) + sage: V = DU.verma_module(5) + sage: list(V.weights()[:8]) + [5, 5*z6 + 5, 10*z6, 10*z6 - 5, 5*z6 - 5, 0, 5, 5*z6 + 5] + """ + @staticmethod + def __classcall_private__(cls, DU, la): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: from sage.algebras.down_up_algebra import VermaModule + sage: VermaModule(DU, 5) is VermaModule(DU, R(5)) + True + sage: VermaModule(DU, 1/a) + Traceback (most recent call last): + ... + TypeError: fraction must have unit denominator + """ + R = DU.base_ring() + la = R(la) + return super().__classcall__(cls, DU, la) + + def __init__(self, DU, la): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: V = DU.verma_module(5) + sage: TestSuite(V).run() + sage: V = DU.verma_module(0) + sage: TestSuite(V).run() + + sage: DU = algebras.DownUp(a, 0, g) + sage: V = DU.verma_module(5) + sage: TestSuite(V).run() + sage: V = DU.verma_module(0) + sage: TestSuite(V).run() + + sage: DU = algebras.DownUp(a, 1-a, 0) + sage: V = DU.verma_module(5) + sage: TestSuite(V).run() + sage: V = DU.verma_module(0) + sage: TestSuite(V).run() + """ + self._DU = DU + R = DU.base_ring() + + def _la_iter(): + m2 = la + yield la + m2 = R.zero() + m1 = la + while True: + cur = DU._alpha * m1 + DU._beta * m2 + DU._gamma + yield cur + m2 = m1 + m1 = cur + + self._weights = lazy_list(_la_iter()) + cat = Modules(R).WithBasis() + CombinatorialFreeModule.__init__(self, R, NonNegativeIntegers(), + prefix='v', category=cat) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: DU = algebras.DownUp(1, 2, 3) + sage: DU.verma_module(5) + Verma module of weight 5 of Down-Up algebra with parameters (1, 2, 3) over Integer Ring + """ + return f"Verma module of weight {self._weights[0]} of {self._DU}" + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: DU = algebras.DownUp(1, 2, 3) + sage: latex(DU.verma_module(5)) + V\left(5\right) + """ + return f"V\\left({self._weights[0]}\\right)" + + def highest_weight_vector(self): + r""" + Return the highest weight vector of ``self`` that generates + ``self`` as a down-up module. + + EXAMPLES:: + + sage: DU = algebras.DownUp(1, 2, 3) + sage: V = DU.verma_module(5) + sage: V.highest_weight_vector() + v[0] + """ + return self.basis()[0] + + def weights(self): + r""" + Return the sequence of weights `(\lambda_n)_{n=0}^{\infty}`. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: V = DU.verma_module(5) + sage: V.weights() + lazy list [5, 5*a + g, 5*a^2 + a*g + 5*b + g, ...] + + sage: V = DU.verma_module(0) + sage: DU = algebras.DownUp(a, 1-a, 0) + sage: V = DU.verma_module(0) + sage: V.weights() + lazy list [0, 0, 0, ...] + + We reproduce the Fibonacci numbers example from [BR1998]_:: + + sage: R.<la> = QQ[] + sage: DU = algebras.DownUp(1, 1, 0, R) + sage: V = DU.verma_module(la) + sage: list(V.weights()[:11]) + [la, la, 2*la, 3*la, 5*la, 8*la, 13*la, 21*la, 34*la, 55*la, 89*la] + """ + return self._weights + + def _action_on_basis(self, m, n): + r""" + Return the action of a basis element of the down-up algebra indexed + by ``m`` on the basis element of ``self`` indexed by ``n``. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(0, b, 1) + sage: I = DU.indices() + sage: V = DU.verma_module(1) + sage: V.weights() + lazy list [1, 1, b + 1, ...] + sage: V._action_on_basis(I([0,0,1]), 0) + 0 + sage: V._action_on_basis(I([0,1,0]), 0) + v[0] + sage: V._action_on_basis(I([1,0,0]), 0) + v[1] + + sage: V._action_on_basis(I([0,0,1]), 3) + (b+1)*v[2] + sage: V._action_on_basis(I([0,1,0]), 3) + (b+1)*v[3] + sage: V._action_on_basis(I([1,0,0]), 3) + v[4] + + sage: V._action_on_basis(I([0,0,3]), 3) + (b+1)*v[0] + sage: V._action_on_basis(I([1,2,1]), 3) + (b^3+3*b^2+3*b+1)*v[3] + + sage: V = DU.verma_module(0) + sage: V._action_on_basis(I([0,0,1]), 1) + 0 + """ + if m[2] > n: + return self.zero() + np = n - m[2] + coeff = prod(self._weights[np:n]) * self._weights[np] ** m[1] + return self.term(n - m[2] + m[0], coeff) + + class Element(CombinatorialFreeModule.Element): + r""" + An element of a Verma module of a down-up algebra. + """ + def _acted_upon_(self, scalar, self_on_left): + r""" + Return the action of ``scalar`` (an element of the base ring or + the defining down-up algebra) on ``self``. + + EXAMPLES:: + + sage: R.<a,b> = QQ[] + sage: DU = algebras.DownUp(0, b, 1) + sage: d, u = DU.gens() + sage: V = DU.verma_module(a) + sage: it = iter(DU.basis()) + sage: scalars = [next(it) for _ in range(10)]; scalars + [1, u, (d*u), d, u^2, u*(d*u), u*d, (d*u)^2, (d*u)*d, d^2] + sage: vecs = [V.basis()[0], V.basis()[1], V.basis()[6]] + sage: all((x * y) * v == x * (y * v) + ....: for x in scalars for y in scalars for v in vecs) + True + sage: 5 * V.basis()[3] + 5*v[3] + sage: V.basis()[0] * d + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for *: + 'Verma module of weight a of Down-Up algebra ...' + and 'Down-Up algebra ...' + """ + ret = super()._acted_upon_(scalar, self_on_left) + if ret is not None: + return ret + P = self.parent() + try: + scalar = P._DU(scalar) + except (TypeError, ValueError): + return None + if self_on_left: + return None + return P.linear_combination((P._action_on_basis(m, n), mc*nc) + for m, mc in scalar._monomial_coefficients.items() + for n, nc in self._monomial_coefficients.items()) + + def is_weight_vector(self): + r""" + Return if ``self`` is a weight vector. + + EXAMPLES:: + + sage: DU = algebras.DownUp(2, -1, -2) + sage: V = DU.verma_module(5) + sage: V.zero().is_weight_vector() + False + sage: B = V.basis() + sage: [B[i].weight() for i in range(6)] + [(5, 0), (8, 5), (9, 8), (8, 9), (5, 8), (0, 5)] + sage: B[5].is_weight_vector() + True + sage: v = B[0] + B[1] + sage: v.is_weight_vector() + False + + sage: DU = algebras.DownUp(2, -1, 0) + sage: V = DU.verma_module(0) + sage: B = V.basis() + sage: v = sum(i*B[i] for i in range(1,5)) + sage: v.is_weight_vector() + True + """ + if not self: + return False + + P = self.parent() + R = P.base_ring() + weights = P._weights + + def get_wt(n): + if not n: + return (R(P._weights[0]), R.zero()) + return (R(P._weights[n]), R(P._weights[n-1])) + + it = iter(self._monomial_coefficients) + wt = get_wt(next(it)) + return all(get_wt(n) == wt for n in it) + + def weight(self): + r""" + Return the weight of ``self``. + + For `v_n`, this is the vector with the pair + `(\lambda_n, \lambda_{n-1})`. + + EXAMPLES:: + + sage: R.<a,b,g> = QQ[] + sage: DU = algebras.DownUp(a, b, g) + sage: V = DU.verma_module(5) + sage: B = V.basis() + sage: B[0].weight() + (5, 0) + sage: B[1].weight() + (5*a + g, 5) + sage: B[2].weight() + (5*a^2 + a*g + 5*b + g, 5*a + g) + + sage: V.zero().weight() + Traceback (most recent call last): + ... + ValueError: the zero element does not have well-defined weight + sage: (B[0] + B[1]).weight() + Traceback (most recent call last): + ... + ValueError: not a weight vector + """ + if not self: + raise ValueError("the zero element does not have well-defined weight") + if not self.is_weight_vector(): + raise ValueError("not a weight vector") + P = self.parent() + R = P.base_ring() + V = FreeModule(R, 2) + weights = P._weights + it = iter(self._monomial_coefficients) + n = next(it) + if not n: + return V([P._weights[0], R.zero()]) + return V([P._weights[n], P._weights[n-1]]) diff --git a/src/sage/algebras/exterior_algebra_groebner.pxd b/src/sage/algebras/exterior_algebra_groebner.pxd index d00fb2e8560..28cea102be7 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pxd +++ b/src/sage/algebras/exterior_algebra_groebner.pxd @@ -1,7 +1,6 @@ """ Exterior algebras Grรถbner bases """ - from sage.data_structures.bitset cimport FrozenBitset from sage.rings.integer cimport Integer from sage.algebras.clifford_algebra_element cimport CliffordAlgebraElement @@ -53,4 +52,3 @@ cdef class GroebnerStrategyDegRevLex(GroebnerStrategy): cdef class GroebnerStrategyDegLex(GroebnerStrategy): pass - diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index cdd445e7253..ba46a5f38b4 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -21,8 +21,8 @@ AUTHORS: # **************************************************************************** from cysignals.signals cimport sig_check -from sage.libs.gmp.mpz cimport mpz_sizeinbase, mpz_setbit, mpz_tstbit, mpz_cmp_si, mpz_sgn -from sage.data_structures.bitset_base cimport (bitset_t, bitset_init, bitset_first, +from sage.libs.gmp.mpz cimport mpz_sizeinbase, mpz_setbit, mpz_tstbit, mpz_sgn +from sage.data_structures.bitset_base cimport (bitset_init, bitset_first, bitset_next, bitset_set_to, bitset_len) from sage.structure.parent cimport Parent from sage.structure.richcmp cimport richcmp, rich_to_bool @@ -175,8 +175,8 @@ cdef class GroebnerStrategy: Convert ``f`` into a ``GBElement``. """ cdef dict mc = <dict> f._monomial_coefficients - #if not mc: - # return GBElement(f, FrozenBitset(), -1) + # if not mc: + # return GBElement(f, FrozenBitset(), -1) cdef Integer r = <Integer> max(self.bitset_to_int(k) for k in mc) return GBElement(f, self.int_to_bitset(r), r) @@ -232,7 +232,7 @@ cdef class GroebnerStrategy: if self.build_S_poly(f0, f1): L.add(self.partial_S_poly_right(f0, f1)) L.add(self.partial_S_poly_right(f1, f0)) - else: # We compute a left Grรถbner basis for two-sided ideals + else: # We compute a left Grรถbner basis for two-sided ideals for f0, f1 in P: if self.build_S_poly(f0, f1): L.add(self.partial_S_poly_left(f0, f1)) @@ -272,14 +272,14 @@ cdef class GroebnerStrategy: cdef set L = self.preprocessing(P, G) cdef Py_ssize_t i from sage.matrix.constructor import matrix - cdef Integer r = Integer(2) ** self.rank - Integer(1) # r for "rank" or "reverso" + cdef Integer r = Integer(2) ** self.rank - Integer(1) # r for "rank" or "reverso" M = matrix({(i, r - self.bitset_to_int(<FrozenBitset> m)): c - for i,f in enumerate(L) - for m,c in (<GBElement> f).elt._monomial_coefficients.items()}, + for i, f in enumerate(L) + for m, c in (<GBElement> f).elt._monomial_coefficients.items()}, sparse=True) M.echelonize() # Do this in place lead_supports = set((<GBElement> f).lsi for f in L) - return [GBElement(self.E.element_class(self.E, {self.int_to_bitset(r - Integer(j)): c for j,c in M[i].iteritems()}), + return [GBElement(self.E.element_class(self.E, {self.int_to_bitset(r - Integer(j)): c for j, c in M[i].iteritems()}), self.int_to_bitset(Integer(r - p)), Integer(r - p)) for i, p in enumerate(M.pivots()) @@ -309,8 +309,7 @@ cdef class GroebnerStrategy: """ cdef FrozenBitset p0, p1 cdef long deg - cdef Py_ssize_t i, j, k - cdef set additions + cdef Py_ssize_t i, j cdef GBElement f0, f1 cdef list G = [], Gp cdef dict constructed = {} @@ -321,7 +320,7 @@ cdef class GroebnerStrategy: continue f0 = self.build_elt(f) if f0.lsi in constructed: - if f0 in constructed[f0.lsi]: # Already there + if f0 in constructed[f0.lsi]: # Already there continue constructed[f0.lsi].add(f0) else: @@ -338,7 +337,7 @@ cdef class GroebnerStrategy: continue f1 = self.build_elt(f) if f1.lsi in constructed: - if f1 in constructed[f1.lsi]: # Already there + if f1 in constructed[f1.lsi]: # Already there continue constructed[f1.lsi].add(f1) else: @@ -367,7 +366,7 @@ cdef class GroebnerStrategy: # Add the elements Gp to G when a new element is found for f0 in Gp: if f0.lsi in constructed: - if f0 in constructed[f0.lsi]: # Already there + if f0 in constructed[f0.lsi]: # Already there continue constructed[f0.lsi].add(f0) else: @@ -402,20 +401,16 @@ cdef class GroebnerStrategy: cdef GBElement f0, f1 # Now that we have a Grรถbner basis, we make this into a reduced Grรถbner basis - cdef tuple supp - cdef bint did_reduction - cdef FrozenBitset lm, s - cdef Integer r cdef Py_ssize_t num_zeros = 0 cdef Py_ssize_t n = len(G) cdef set pairs = set((i, j) for i in range(n) for j in range(n) if i != j) while pairs: sig_check() - i,j = pairs.pop() + i, j = pairs.pop() f0 = <GBElement> G[i] f1 = <GBElement> G[j] - assert f0.elt._monomial_coefficients is not f1.elt._monomial_coefficients, (i,j) + assert f0.elt._monomial_coefficients is not f1.elt._monomial_coefficients, (i, j) # We perform the classical reduction algorithm here on each pair # TODO: Make this faster by using the previous technique? if self.reduce_single(f0.elt, f1.elt): @@ -500,7 +495,6 @@ cdef class GroebnerStrategy: """ cdef FrozenBitset lm = self.leading_support(g), s, t cdef bint did_reduction = True, was_reduced=False - cdef tuple supp cdef CliffordAlgebraElement gp one = self.E._base.one() @@ -521,7 +515,6 @@ cdef class GroebnerStrategy: iaxpy(-coeff, gp._monomial_coefficients, f._monomial_coefficients) return was_reduced - cdef Integer bitset_to_int(self, FrozenBitset X): raise NotImplementedError @@ -658,8 +651,6 @@ cdef class GroebnerStrategyDegRevLex(GroebnerStrategy): """ Convert a nonnegative integer ``n`` to a :class:`FrozenBitset`. """ - cdef size_t i - if mpz_sgn(n.value) == 0: return FrozenBitset() @@ -701,8 +692,6 @@ cdef class GroebnerStrategyDegLex(GroebnerStrategy): """ Convert a nonnegative integer ``n`` to a :class:`FrozenBitset`. """ - cdef size_t i - if mpz_sgn(n.value) == 0: return FrozenBitset() diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 9c8090c8929..af2b5e7dd3c 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -740,7 +740,7 @@ def maximal_ideal(self): - :class:`~sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_ideal.FiniteDimensionalAlgebraIdeal`; the unique maximal ideal of ``self``. If ``self`` is not a local - algebra, a ``ValueError`` is raised. + algebra, a :class:`ValueError` is raised. EXAMPLES:: diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd index e5f098c67d7..c13b8dbab07 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd @@ -1,4 +1,4 @@ -from sage.structure.element cimport AlgebraElement, Element, Vector, parent +from sage.structure.element cimport AlgebraElement, Element, Vector from sage.matrix.matrix cimport Matrix cdef class FiniteDimensionalAlgebraElement(AlgebraElement): diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx index b0ae904d3d2..1fc0977ce10 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx @@ -14,10 +14,8 @@ Elements of Finite Algebras # **************************************************************************** import re -from sage.misc.lazy_attribute import lazy_attribute from sage.matrix.matrix_space import MatrixSpace from sage.structure.element import is_Matrix -from sage.modules.free_module_element import vector from sage.rings.integer import Integer from cpython.object cimport PyObject_RichCompare as richcmp @@ -36,7 +34,7 @@ cpdef FiniteDimensionalAlgebraElement unpickle_FiniteDimensionalAlgebraElement(A """ cdef FiniteDimensionalAlgebraElement x = A.element_class.__new__(A.element_class) AlgebraElement.__init__(x, A) - x._vector = vec + x._vector = vec x.__matrix = mat return x @@ -90,13 +88,13 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): k = A.base_ring() n = A.degree() if elt is None: - self._vector = MatrixSpace(k,1,n)() + self._vector = MatrixSpace(k, 1, n)() self.__matrix = MatrixSpace(k, n)() else: if isinstance(elt, int): elt = Integer(elt) elif isinstance(elt, list): - elt = MatrixSpace(k,1,n)(elt) + elt = MatrixSpace(k, 1, n)(elt) if A == elt.parent(): mat = (<FiniteDimensionalAlgebraElement> elt).__matrix if mat is None: @@ -115,7 +113,7 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): else: raise TypeError("algebra is not unitary") elif isinstance(elt, Vector): - self._vector = MatrixSpace(k,1,n)(list(elt)) + self._vector = MatrixSpace(k, 1, n)(list(elt)) elif is_Matrix(elt): if elt.ncols() != n: raise ValueError("matrix does not define an element of the algebra") @@ -171,7 +169,7 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): self._parent, D = state v = D.pop('_vector') if isinstance(v, Vector): - self._vector = MatrixSpace(self._parent.base_ring(), 1,len(v))(list(v)) + self._vector = MatrixSpace(self._parent.base_ring(), 1, len(v))(list(v)) else: self._vector = v self.__matrix = D.pop('_matrix', None) @@ -197,7 +195,7 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): if self.__matrix is None: A = self.parent() table = <tuple> A.table() - ret = sum(self._vector[0,i] * table[i] for i in xrange(A.degree())) + ret = sum(self._vector[0, i] * table[i] for i in range(A.degree())) self.__matrix = MatrixSpace(A.base_ring(), A.degree())(ret) return self.__matrix @@ -211,9 +209,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): sage: B(5).vector() (5, 0, 5) """ - #By :trac:`23707`, ``self._vector`` now is a single row matrix, - #not a vector, which results in a speed-up. For backwards compatibility, - #this method still returns a vector. + # By :trac:`23707`, ``self._vector`` now is a single row matrix, + # not a vector, which results in a speed-up. + # For backwards compatibility, this method still returns a vector. return self._vector[0] def matrix(self): @@ -248,7 +246,7 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): {0: 1, 1: 1} """ cdef Py_ssize_t i - return {i:self._vector[0,i] for i in range(self._vector.ncols())} + return {i: self._vector[0, i] for i in range(self._vector.ncols())} def left_matrix(self): """ @@ -261,12 +259,11 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): [1 0 0] [0 1 0] [0 2 0] - """ A = self.parent() if A.is_commutative(): return self._matrix - return sum([self._vector[0,i] * A.left_table()[i] for + return sum([self._vector[0, i] * A.left_table()[i] for i in range(A.degree())]) def _repr_(self): @@ -299,8 +296,8 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): var = "*{}".format(A._names[n]) s += "{}{}".format(x, var) s = s.replace(" + -", " - ") - s = re.sub(r' 1(\.0+)?\*',' ', s) - s = re.sub(r' -1(\.0+)?\*',' -', s) + s = re.sub(r' 1(\.0+)?\*', ' ', s) + s = re.sub(r' -1(\.0+)?\*', ' -', s) if s == " ": return "0" return s[1:] @@ -330,9 +327,8 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: A([2,1/4,3])[2] 3 - """ - return self._vector[0,m] + return self._vector[0, m] def __len__(self): """ @@ -341,11 +337,10 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: len(A([2,1/4,3])) 3 - """ return self._vector.ncols() - ## (Rich) comparison + # (Rich) comparison cpdef _richcmp_(self, right, int op): """ EXAMPLES:: @@ -375,7 +370,6 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): True sage: A(1) <= 0 False - """ return richcmp(self._vector, <FiniteDimensionalAlgebraElement>right._vector, op) @@ -435,7 +429,8 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): if not self._parent.base_ring().has_coerce_map_from(other.parent()): raise TypeError("unsupported operand parent(s) for *: '{}' and '{}'" .format(self.parent(), other.parent())) - return self._parent.element_class(self._parent, other * self._vector) # Note the different order + # Note the different order below + return self._parent.element_class(self._parent, other * self._vector) def __pow__(self, n, m): """ diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py index e3f456c263e..22f12ce6bb5 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py @@ -29,7 +29,7 @@ class FiniteDimensionalAlgebraMorphism(RingHomomorphism_im_gens): - ``f`` -- matrix of the underlying `k`-linear map - ``unitary`` -- boolean (default: ``True``); if ``True`` and ``check`` - is also ``True``, raise a ``ValueError`` unless ``A`` and ``B`` are + is also ``True``, raise a :class:`ValueError` unless ``A`` and ``B`` are unitary and ``f`` respects unit elements - ``check`` -- boolean (default: ``True``); check whether the given diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index 7286f62ce27..460b623b877 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -149,7 +149,7 @@ from sage.structure.factory import UniqueFactory from sage.misc.cachefunc import cached_method -from sage.all import PolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.ring import Algebra from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.combinat.free_module import CombinatorialFreeModule @@ -282,7 +282,7 @@ def create_key(self, base_ring, arg1=None, arg2=None, PolRing = PolynomialRing(base_ring, *args, **kwds) if degrees is None: return (PolRing,) - from sage.all import TermOrder + from sage.rings.polynomial.term_order import TermOrder T = TermOrder(PolRing.term_order(), PolRing.ngens() + 1) varnames = list(PolRing.variable_names()) newname = 'x' @@ -331,6 +331,7 @@ def create_object(self, version, key): return FreeAlgebra_letterplace(key[1], degrees=key[0]) return FreeAlgebra_generic(key[0], len(key[1]), key[1]) + FreeAlgebra = FreeAlgebraFactory('FreeAlgebra') @@ -420,6 +421,7 @@ class FreeAlgebra_generic(CombinatorialFreeModule, Algebra): is a coercion. """ Element = FreeAlgebraElement + def __init__(self, R, n, names): """ The free algebra on `n` generators over a base ring. @@ -596,7 +598,7 @@ def exp_to_monomial(T): out = [] for i in range(len(T)): if T[i]: - out.append((i%ngens,T[i])) + out.append((i % ngens,T[i])) return M(out) return self.element_class(self, {exp_to_monomial(T):c for T,c in x.letterplace_polynomial().dict().items()}) # ok, not a free algebra element (or should not be viewed as one). diff --git a/src/sage/algebras/free_algebra_quotient.py b/src/sage/algebras/free_algebra_quotient.py index 583eb5f9ae8..81c7f5ad91e 100644 --- a/src/sage/algebras/free_algebra_quotient.py +++ b/src/sage/algebras/free_algebra_quotient.py @@ -211,7 +211,7 @@ def gen(self, i): sage: H.gen(2) k - An IndexError is raised if an invalid generator is requested:: + An :class:`IndexError` is raised if an invalid generator is requested:: sage: H.gen(3) Traceback (most recent call last): @@ -295,6 +295,8 @@ def module(self): """ The free module of the algebra. + EXAMPLES:: + sage: H = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0]; H Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field sage: H.module() @@ -357,7 +359,7 @@ def hamilton_quatalg(R): """ n = 3 from sage.algebras.free_algebra import FreeAlgebra - from sage.matrix.all import MatrixSpace + from sage.matrix.matrix_space import MatrixSpace A = FreeAlgebra(R, n, 'i') F = A.monoid() i, j, k = F.gens() diff --git a/src/sage/algebras/fusion_rings/all.py b/src/sage/algebras/fusion_rings/all.py index 9c375f15440..bf9c016510f 100644 --- a/src/sage/algebras/fusion_rings/all.py +++ b/src/sage/algebras/fusion_rings/all.py @@ -14,5 +14,4 @@ from sage.misc.lazy_import import lazy_import lazy_import('sage.algebras.fusion_rings.fusion_ring', ['FusionRing']) - -del lazy_import +lazy_import('sage.algebras.fusion_rings.fusion_double', ['FusionDouble']) diff --git a/src/sage/algebras/fusion_rings/f_matrix.py b/src/sage/algebras/fusion_rings/f_matrix.py index 82b5d764fa6..fe39ebf72b4 100644 --- a/src/sage/algebras/fusion_rings/f_matrix.py +++ b/src/sage/algebras/fusion_rings/f_matrix.py @@ -10,12 +10,10 @@ # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # **************************************************************************** - - from copy import deepcopy from ctypes import cast, py_object from itertools import product, zip_longest -from multiprocessing import Pool, cpu_count, set_start_method, shared_memory +from multiprocessing import Pool, cpu_count, set_start_method, shared_memory import numpy as np from os import getpid, remove import pickle @@ -132,7 +130,7 @@ class FMatrix(SageObject): See [TTWL2009]_ for an introduction to this topic, [EGNO2015]_ Section 4.9 for a precise mathematical - definition, and [Bond2007]_ Section 2.5 for a discussion + definition, and [Bond2007]_ Section 2.5 and [Ab2022]_ for discussions of how to compute the F-matrix. In addition to [Bond2007]_, worked out F-matrices may be found in [RoStWa2009]_ and [CHW2015]_. @@ -282,7 +280,7 @@ def __init__(self, fusion_ring, fusion_label="f", var_prefix='fx', inject_variab n_vars = self.findcases() self._poly_ring = PolynomialRing(self._FR.field(), n_vars, var_prefix) if inject_variables: - print("creating variables %s%s..%s%s"%(var_prefix, 1, var_prefix, n_vars)) + print("creating variables %s%s..%s%s" % (var_prefix, 1, var_prefix, n_vars)) self._poly_ring.inject_variables(get_main_globals()) self._idx_to_sextuple, self._fvars = self.findcases(output=True) @@ -311,7 +309,7 @@ def _repr_(self): sage: FusionRing("B2", 1).get_fmatrix() F-Matrix factory for The Fusion Ring of Type B2 and level 1 with Integer Ring coefficients """ - return "F-Matrix factory for %s"%self._FR + return "F-Matrix factory for %s" % self._FR def clear_equations(self): r""" @@ -1231,11 +1229,6 @@ def start_worker_pool(self, processes=None): :meth:`shutdown_worker_pool` to close the pool and properly dispose of shared memory resources. - .. NOTE:: - - Python 3.8+ is required, since the ``multiprocessing.shared_memory`` - module must be imported. - INPUT: - ``processes`` -- an integer indicating the number of workers @@ -1607,7 +1600,7 @@ def _triangular_elim(self, eqns=None, verbose=True): n = self.pool._processes chunks = [[] for i in range(n)] for i, eq_tup in enumerate(eqns): - chunks[i%n].append(eq_tup) + chunks[i % n].append(eq_tup) eqns = chunks else: eqns = [eqns] @@ -1687,7 +1680,7 @@ def equations_graph(self, eqns=None): s = [v for v in eq.variables()] for x in s: for y in s: - if y!=x: + if y != x: G.add_edge(x, y) return G @@ -1728,11 +1721,11 @@ def _partition_eqns(self, eqns=None, verbose=True): if eqns is None: eqns = self.ideal_basis graph = self.equations_graph(eqns) - partition = {tuple(c): [] for c in graph.connected_components()} + partition = {tuple(c): [] for c in graph.connected_components(sort=True)} for eq_tup in eqns: - partition[tuple(graph.connected_component_containing_vertex(variables(eq_tup)[0]))].append(eq_tup) + partition[tuple(graph.connected_component_containing_vertex(variables(eq_tup)[0], sort=True))].append(eq_tup) if verbose: - print("Partitioned {} equations into {} components of size:".format(len(eqns), len(graph.connected_components()))) + print("Partitioned {} equations into {} components of size:".format(len(eqns), graph.connected_components_number())) print(graph.connected_components_sizes()) return partition @@ -2201,7 +2194,7 @@ def _fix_gauge(self, algorithm=""): adding equation... fx18 - 1 adding equation... fx21 - 1 """ - while not all(v for v in self._solved): + while not all(self._solved): # Get a variable that has not been fixed # In ascending index order, for consistent results for i, var in enumerate(self._poly_ring.gens()): @@ -2219,7 +2212,7 @@ def _substitute_degree_one(self, eqns=None): r""" Substitute known value from linear univariate polynomial and solve, following [Bond2007]_ p.37, for two-term linear equation - for one of the variables. + for one of the variables. See also [Ab2022]_. EXAMPLES:: diff --git a/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pxd b/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pxd index 11dc0253b35..e0908ab5884 100644 --- a/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pxd +++ b/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pxd @@ -2,4 +2,3 @@ cdef _fmat(fvars, Nk_ij, one, a, b, c, d, x, y) cpdef _backward_subs(factory, bint flatten=*) cpdef executor(tuple params) cpdef _solve_for_linear_terms(factory, list eqns=*) - diff --git a/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx b/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx index a482c0c4fc1..a9b7eb50fab 100644 --- a/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx +++ b/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx @@ -29,7 +29,7 @@ from sage.rings.ideal import Ideal from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing ########################## -### Fast class methods ### +# Fast class methods # ########################## cpdef _solve_for_linear_terms(factory, list eqns=None): @@ -87,7 +87,8 @@ cpdef _solve_for_linear_terms(factory, list eqns=None): # assert factory.test_fvars[s] == fvars[s], "OG value {}, Shared: {}".format(fvars[s], factory.test_fvars[s]) if len(eq_tup) == 2: idx = has_appropriate_linear_term(eq_tup) - if idx < 0: continue + if idx < 0: + continue # The chosen term is guaranteed to be univariate in the largest variable exp = eq_tup[idx][0] max_var = exp._data[0] @@ -161,7 +162,7 @@ cpdef _backward_subs(factory, bint flatten=True): sextuple = idx_to_sextuple[i] rhs = fvars[sextuple] d = {var_idx: fvars[idx_to_sextuple[var_idx]] - for var_idx in variables(rhs) if solved[var_idx]} + for var_idx in variables(rhs) if solved[var_idx]} if d: kp = compute_known_powers(get_variables_degrees([rhs], nvars), d, one) res = tuple(subs_squares(subs(rhs, kp, one), _ks).items()) @@ -210,7 +211,7 @@ cdef _fmat(fvars, _Nk_ij, id_anyon, a, b, c, d, x, y): # _Nk_ij = cached_function(_Nk_ij, name='_Nk_ij') ############### -### Mappers ### +# Mappers # ############### cdef req_cy(tuple basis, r_matrix, dict fvars, Nk_ij, id_anyon, tuple sextuple): @@ -227,6 +228,7 @@ cdef req_cy(tuple basis, r_matrix, dict fvars, Nk_ij, id_anyon, tuple sextuple): rhs += _fmat(fvars, Nk_ij, id_anyon, c, a, b, d, e, f) * r_matrix(f, c, d, base_coercion=False) * _fmat(fvars, Nk_ij, id_anyon, a, b, c, d, f, g) return lhs-rhs + @cython.wraparound(False) @cython.nonecheck(False) @cython.cdivision(True) @@ -287,13 +289,15 @@ cdef MPolynomial_libsingular feq_cy(tuple basis, fvars, Nk_ij, id_anyon, zero, t """ a, b, c, d, e, f, g, k, l = nonuple lhs = _fmat(fvars, Nk_ij, id_anyon, f, c, d, e, g, l) * _fmat(fvars, Nk_ij, id_anyon, a, b, l, e, f, k) - if lhs == 0 and prune: # it is believed that if lhs=0, the equation carries no new information + if lhs == 0 and prune: + # it is believed that if lhs=0, the equation carries no new information return zero rhs = zero for h in basis: rhs += _fmat(fvars, Nk_ij, id_anyon, a, b, c, g, f, h)*_fmat(fvars, Nk_ij, id_anyon, a, h, d, e, g, k)*_fmat(fvars, Nk_ij, id_anyon, b, c, d, k, h, l) return lhs - rhs + @cython.wraparound(False) @cython.nonecheck(False) @cython.cdivision(True) @@ -304,7 +308,7 @@ cdef get_reduced_pentagons(factory, tuple mp_params): # Set up multiprocessing parameters cdef list worker_results = list() cdef int child_id, n_proc - child_id, n_proc, output = mp_params + child_id, n_proc, _ = mp_params cdef unsigned long i cdef tuple nonuple, red cdef MPolynomial_libsingular pe @@ -395,7 +399,7 @@ cdef list compute_gb(factory, tuple args): cdef MPolynomialRing_libsingular R = PolynomialRing(factory._FR.field(), len(sorted_vars), 'a', order=term_order) # Zip tuples into R and compute Groebner basis - cdef idx_map = { old : new for new, old in enumerate(sorted_vars) } + cdef idx_map = {old : new for new, old in enumerate(sorted_vars)} nvars = len(sorted_vars) F = factory.field() cdef list polys = list() @@ -405,7 +409,7 @@ cdef list compute_gb(factory, tuple args): gb = Ideal(sorted(polys)).groebner_basis(algorithm="libsingular:slimgb") # Change back to fmats poly ring and append to temp_eqns - cdef dict inv_idx_map = { v : k for k, v in idx_map.items() } + cdef dict inv_idx_map = {v: k for k, v in idx_map.items()} cdef tuple t nvars = factory._poly_ring.ngens() for p in gb: @@ -418,7 +422,7 @@ cdef list compute_gb(factory, tuple args): return collect_eqns(res) ################ -### Reducers ### +# Reducers # ################ cdef inline list collect_eqns(list eqns): @@ -434,7 +438,7 @@ cdef inline list collect_eqns(list eqns): return list(reduced) ############################## -### Parallel code executor ### +# Parallel code executor # ############################## # Hard-coded module __dict__-style attribute with visible cdef methods @@ -490,7 +494,7 @@ cpdef executor(tuple params): return mappers[fn_name](fmats_obj, args) #################### -### Verification ### +# Verification # #################### cdef feq_verif(factory, worker_results, fvars, Nk_ij, id_anyon, tuple nonuple, float tol=5e-8): @@ -508,6 +512,7 @@ cdef feq_verif(factory, worker_results, fvars, Nk_ij, id_anyon, tuple nonuple, f if diff > tol or diff < -tol: worker_results.append(diff) + @cython.wraparound(False) @cython.nonecheck(False) @cython.cdivision(True) @@ -517,7 +522,6 @@ cdef pent_verify(factory, tuple mp_params): and reduce them. """ child_id, n_proc, verbose = mp_params - cdef float t0 cdef tuple nonuple cdef unsigned long long i cdef list worker_results = list() @@ -531,4 +535,3 @@ cdef pent_verify(factory, tuple mp_params): feq_verif(factory, worker_results, fvars, Nk_ij, id_anyon, nonuple) if i % 50000000 == 0 and i and verbose: print("{:5d}m equations checked... {} potential misses so far...".format(i // 1000000, len(worker_results))) - diff --git a/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pxd b/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pxd index b3eec73b15b..a992f0339a4 100644 --- a/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pxd +++ b/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pxd @@ -1,3 +1,2 @@ cpdef _unflatten_entries(factory, list entries) cpdef executor(tuple params) - diff --git a/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pyx b/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pyx index 9fcb4408c21..8fc054f50cd 100644 --- a/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pyx +++ b/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pyx @@ -15,7 +15,7 @@ from sage.algebras.fusion_rings.fast_parallel_fmats_methods cimport _fmat from sage.rings.qqbar import QQbar ############### -### Mappers ### +# Mappers # ############### cdef mid_sig_ij(fusion_ring, row, col, a, b): @@ -96,6 +96,7 @@ cdef cached_odd_one_out_ij(fusion_ring, xi, xj, a, b): odd_one_out_ij_cache[xi, xj, a, b] = entry return entry + @cython.nonecheck(False) @cython.cdivision(True) cdef sig_2k(fusion_ring, tuple args): @@ -175,6 +176,7 @@ cdef sig_2k(fusion_ring, tuple args): worker_results.append(((basis_dict[nnz_pos], i), entry)) return worker_results + @cython.nonecheck(False) @cython.cdivision(True) cdef odd_one_out(fusion_ring, tuple args): @@ -252,7 +254,7 @@ cdef odd_one_out(fusion_ring, tuple args): return worker_results ############################## -### Parallel code executor ### +# Parallel code executor # ############################## # Hard-coded module __dict__-style attribute with visible cdef methods @@ -300,7 +302,7 @@ cpdef executor(tuple params): return mappers[fn_name](fusion_ring_obj, args) ###################################### -### Pickling circumvention helpers ### +# Pickling circumvention helpers # ###################################### cpdef _unflatten_entries(fusion_ring, list entries): @@ -323,7 +325,6 @@ cpdef _unflatten_entries(fusion_ring, list entries): True """ F = fusion_ring.fvars_field() - fm = fusion_ring.get_fmatrix() if F != QQbar: for i, (coord, entry) in enumerate(entries): entries[i] = (coord, F(entry)) diff --git a/src/sage/algebras/fusion_rings/fusion_double.py b/src/sage/algebras/fusion_rings/fusion_double.py new file mode 100644 index 00000000000..520ea96ef13 --- /dev/null +++ b/src/sage/algebras/fusion_rings/fusion_double.py @@ -0,0 +1,894 @@ +""" +The Fusion Ring of the Drinfeld Double of a Finite Group +""" + +# **************************************************************************** +# Copyright (C) 2023 Wenqi Li +# Daniel Bump <bump at match.stanford.edu> +# Travis Scrimshaw <tcscrims at gmail.com> +# Guillermo Aboumrad <gh_willieab> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.categories.algebras_with_basis import AlgebrasWithBasis +from sage.combinat.free_module import CombinatorialFreeModule +from sage.rings.integer_ring import ZZ +from sage.misc.misc import inject_variable +from sage.misc.cachefunc import cached_method +from sage.sets.set import Set +from sage.rings.number_field.number_field import CyclotomicField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.ideal import Ideal +from sage.matrix.constructor import matrix + +class FusionDouble(CombinatorialFreeModule): + r""" + The fusion ring corresponding to the Drinfeld double of a finite group. + + This is the fusion ring of the modular tensor category of modules + over the Drinfeld double of a finite group. Usage is similar + to :class:`FusionRing`; we refer the reader to that class for more + information. + + INPUT: + + - ``G`` -- a finite group + - ``prefix`` -- (default: ``'s'``) a prefix for the names of simple objects + - ``inject_varables`` -- (optional) set to ``True`` to create variables + for the simple objects + + REFERENCES: + + - [BaKi2001]_ Chapter 3 + - [Mas1995]_ + - [CHW2015]_ + - [Goff1999]_ + + EXAMPLES:: + + sage: G = DihedralGroup(5) + sage: H = FusionDouble(G, inject_variables=True) + sage: H.basis() + Finite family {0: s0, 1: s1, 2: s2, 3: s3, 4: s4, 5: s5, 6: s6, 7: s7, 8: s8, + 9: s9, 10: s10, 11: s11, 12: s12, 13: s13, 14: s14, 15: s15} + sage: for x in H.basis(): + ....: print ("%s : %s"%(x,x^2)) + ....: + s0 : s0 + s1 : s0 + s2 : s0 + s1 + s3 + s3 : s0 + s1 + s2 + s4 : s0 + s2 + s3 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15 + s5 : s0 + s2 + s3 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15 + s6 : s0 + s1 + s11 + s7 : s0 + s1 + s13 + s8 : s0 + s1 + s15 + s9 : s0 + s1 + s12 + s10 : s0 + s1 + s14 + s11 : s0 + s1 + s6 + s12 : s0 + s1 + s9 + s13 : s0 + s1 + s7 + s14 : s0 + s1 + s10 + s15 : s0 + s1 + s8 + sage: s4*s5 + s1 + s2 + s3 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15 + sage: s4.ribbon() + 1 + sage: s5.ribbon() + -1 + sage: s8.ribbon() + zeta5^3 + + If the fusion double is multiplicity-free, meaning that the fusion + coefficients `N_k^{ij}` are bounded by `1`, then the F-matrix may be + computed, by solving the pentagon and hexagon relations as described + in [Bond2007]_ and [Ab2022]_, just as for :class:`FusionRing`. + There is a caveat here, since even if the fusion rules are multiplicity-free, + if there are too many F-matrix values to compute, even if many of them are + zero, in the current implementation singular cannot create enough variables. + At least, this code can compute the F-matrix for the Fusion Double of the + symmetric group `S_3`, duplicating the result of [CHW2015]_. + + :: + + sage: G1 = SymmetricGroup(3) + sage: H1 = FusionDouble(G1, prefix="u", inject_variables=True) + sage: F = H1.get_fmatrix() + + The above commands create the F-matrix. You can compute all of the + F-matrices with the command:: + + sage: H1.find_orthogonal_solution() # not tested (10-15 minutes) + + Individual F-matrices may be computed thus:: + + sage: F.fmatrix(u3, u3, u3, u4) # not tested + + See :class:`FMatrix` for more information. + + Unfortunately beyond `S_3` the number of simple objects is seemingly + impractical. Although the :class:`FusionDouble` class and its methods + work well for groups of moderate size, the :class:`FMatrix` may not be + computable. For the dihedral group of order 8, there are already 22 + simple objects, and the F-matrix seems out of reach. The actual limitation + is that singular will not create a polynomial ring in more than + `2^{15}-1 = 32767` symbols, and there are more than this many F-matrix + values to be computed for the dihedral group of order 8, so in the + current implementation, this FusionRing is out of reach. + + It is an open problem to classify the finite groups whose fusion doubles + are multiplicity-free. Abelian groups, dihedral groups, dicyclic groups, + and all groups of order 16 are multiplicity-free. On the other hand, for + groups of order 32, some are multiplicity-free and others are not. + These can all be constructed using :class:`SmallPermutationGroup`. + + EXAMPLES:: + + sage: G = SmallPermutationGroup(16,9) + sage: F = FusionDouble(G, prefix="b",inject_variables=True) + sage: b13^2 # long time (4s) + b0 + b2 + b4 + b15 + b16 + b17 + b18 + b24 + b26 + b27 + + """ + @staticmethod + def __classcall_private__(cls, G, prefix="s", inject_variables=False): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: H1 = FusionDouble(DihedralGroup(6), inject_variables=True) + sage: H2 = FusionDouble(DihedralGroup(6), prefix='s') + sage: H1 is H2 + True + """ + F = super().__classcall__(cls, G=G, prefix=prefix) + if inject_variables: + F.inject_variables() + return F + + def __init__(self, G, prefix="s"): + """ + EXAMPLES:: + + sage: H = FusionDouble(DihedralGroup(6)) + sage: TestSuite(H).run() + sage: H = FusionDouble(DihedralGroup(7)) + sage: TestSuite(H).run() # long time + + sage: F = FusionDouble(CyclicPermutationGroup(2)) + sage: [F._repr_term(t) for t in F._names] + ['s0', 's1', 's2', 's3'] + sage: F = FusionDouble(CyclicPermutationGroup(2)) + sage: [F._latex_term(t) for t in F._names] + ['s_{0}', 's_{1}', 's_{2}', 's_{3}'] + + sage: FusionDouble(SymmetricGroup(4)).get_order() + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] + """ + self._G = G + self._names = {} + self._elt = {} + self._chi = {} + count = ZZ.zero() + for g in G.conjugacy_classes_representatives(): + for chi in G.centralizer(g).irreducible_characters(): + self._names[count] = "%s%s" % (prefix, count) + self._elt[count] = g + self._chi[count] = chi + count += ZZ.one() + self._cyclotomic_order = G.exponent() + self._basecoer = None + self._fusion_labels = None + self._field = None + cat = AlgebrasWithBasis(ZZ) + CombinatorialFreeModule.__init__(self, ZZ, [k for k in self._names], + prefix=prefix, bracket=False, category=cat) + + def _repr_(self): + """ + EXAMPLES:: + + sage: FusionDouble(SymmetricGroup(3)) + The Fusion Ring of the Drinfeld Double of Symmetric group of + order 3! as a permutation group + """ + return "The Fusion Ring of the Drinfeld Double of %s" % self._G + + def inject_variables(self): + """ + Create variables for the simple objects in the global name space. + + EXAMPLES:: + + sage: F = FusionDouble(DiCyclicGroup(3), prefix="d") + sage: F.inject_variables() + sage: d0 + d1 + d5 + d0 + d1 + d5 + """ + for i, name in self._names.items(): + inject_variable(name, self.monomial(i)) + + @cached_method + def _char_cache(self, i, g): + """ + Return ``self._chi[i](g)``, cached here for speed. + + TESTS:: + + sage: D = FusionDouble(SymmetricGroup(4)) + + sage: all(D._char_cache(b.support_of_term(), b.g()) == b.char()(b.g()) + ....: for b in D.basis()) + True + """ + return self._chi[i](g) + + @cached_method + def s_ij(self, i, j, unitary=False, base_coercion=True): + r""" + Return the element of the S-matrix of this fusion ring + corresponding to the given elements. + + Without the unitary option set true, this is the unnormalized S-matrix + entry, denoted `\tilde{s}_{ij}`, in [BaKi2001]_ Chapter 3. The + normalized S-matrix entries are denoted `s_{ij}`. + + INPUT: + + - ``i``, ``j``, -- a pair of basis elements + - ``unitary`` -- (default: ``False``) set to ``True`` to obtain + the unitary S-matrix + + EXAMPLES:: + + sage: D = FusionDouble(SymmetricGroup(3), prefix="t", inject_variables=True) + sage: [D.s_ij(t2, x) for x in D.basis()] + [2, 2, 4, 0, 0, -2, -2, -2] + sage: [D.s_ij(t2, x, unitary=True) for x in D.basis()] + [1/3, 1/3, 2/3, 0, 0, -1/3, -1/3, -1/3] + """ + sum_val = ZZ.zero() + G = self._G + [i] = list(i._monomial_coefficients) + [j] = list(j._monomial_coefficients) + a = self._elt[i] + b = self._elt[j] + for g in G: + gi = g.inverse() + conj = g * b * gi + if a * conj == conj * a: + sum_val += self._char_cache(i, conj) * self._char_cache(j, gi * a * g) + if unitary: + coef = 1 / (G.centralizer(a).order() * G.centralizer(b).order()) + else: + coef = G.order() / (G.centralizer(a).order() * G.centralizer(b).order()) + ret = coef * sum_val + if (not base_coercion) or (self._basecoer is None): + return ret + return self._basecoer(ret) + + def s_ijconj(self, i, j, unitary=False, base_coercion=True): + r""" + Return the conjugate of the element of the S-matrix given by + ``self.s_ij(elt_i, elt_j, base_coercion=base_coercion)``. + + .. SEEALSO:: + + :meth:`s_ij` + + EXAMPLES:: + + sage: P=FusionDouble(CyclicPermutationGroup(3),prefix="p",inject_variables=True) + sage: P.s_ij(p1,p3) + zeta3 + sage: P.s_ijconj(p1,p3) + -zeta3 - 1 + """ + return self.s_ij(i, j, unitary=unitary, base_coercion=base_coercion).conjugate() + + def s_matrix(self, unitary=False, base_coercion=True): + r""" + Return the S-matrix of this fusion ring. + + OPTIONAL: + + - ``unitary`` -- (default: ``False``) set to ``True`` to obtain + the unitary S-matrix + + Without the ``unitary`` parameter, this is the matrix denoted + `\widetilde{s}` in [BaKi2001]_. + + EXAMPLES:: + + sage: FusionDouble(SymmetricGroup(3)).s_matrix() + [ 1 1 2 3 3 2 2 2] + [ 1 1 2 -3 -3 2 2 2] + [ 2 2 4 0 0 -2 -2 -2] + [ 3 -3 0 3 -3 0 0 0] + [ 3 -3 0 -3 3 0 0 0] + [ 2 2 -2 0 0 4 -2 -2] + [ 2 2 -2 0 0 -2 -2 4] + [ 2 2 -2 0 0 -2 4 -2] + sage: FusionDouble(SymmetricGroup(3)).s_matrix(unitary=True) + [ 1/6 1/6 1/3 1/2 1/2 1/3 1/3 1/3] + [ 1/6 1/6 1/3 -1/2 -1/2 1/3 1/3 1/3] + [ 1/3 1/3 2/3 0 0 -1/3 -1/3 -1/3] + [ 1/2 -1/2 0 1/2 -1/2 0 0 0] + [ 1/2 -1/2 0 -1/2 1/2 0 0 0] + [ 1/3 1/3 -1/3 0 0 2/3 -1/3 -1/3] + [ 1/3 1/3 -1/3 0 0 -1/3 -1/3 2/3] + [ 1/3 1/3 -1/3 0 0 -1/3 2/3 -1/3] + + """ + b = self.basis() + S = matrix([[self.s_ij(b[x], b[y], unitary=unitary, base_coercion=base_coercion) + for x in self.get_order()] for y in self.get_order()]) + return S + + @cached_method + def N_ijk(self, i, j, k): + r""" + The symmetric invariant of three simple objects. + + This is the dimension of + + .. MATH:: + + Hom(i \otimes j \otimes k, s_0), + + where `s_0` is the unit element (assuming ``prefix='s'``). + Method of computation is through the Verlinde formula, + deducing the values from the known values of the S-matrix. + + EXAMPLES:: + + sage: A = FusionDouble(AlternatingGroup(4),prefix="a",inject_variables=True) + sage: [A.N_ijk(a10,a11,x) for x in A.basis()] + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0] + + TESTS:: + + sage: F = FusionDouble(SymmetricGroup(4)) + sage: from itertools import product + sage: B = list(F.basis()) + sage: all(F.N_ijk(i,j,k).parent() is ZZ + ....: for i, j, k in product(B[::6], repeat=3)) + True + """ + sz = self.one() + return ZZ(sum(self.s_ij(i, r, unitary=True) * self.s_ij(j, r, unitary=True) + * self.s_ij(k, r, unitary=True) / self.s_ij(sz, r, unitary=True) + for r in self.basis())) + + @cached_method + def Nk_ij(self, i, j, k, use_characters=False): + r""" + Return the fusion coefficient `N^k_{ij}`. + + INPUT: + + - ``i``, ``j``, ``k`` -- basis elements + - ``use_characters`` -- (default: ``False``) see the algorithm + description below + + ALGORITHM: + + If ``use_characters=False``, then this is computed using + the Verlinde formula: + + .. MATH:: + + N^k_{ij} = \sum_l \frac{s(i, \ell)\, s(j, \ell)\, + \overline{s(k, \ell)}}{s(I, \ell)}. + + Otherwise we use a character theoretic method to compute the fusion + coefficient `N_{ij}^k` as follows. Each simple object, for example + `i` corresponds to a conjugacy class `\mathcal{C}_i` of the underlying + group `G`, and an irreducible character `\chi_i` of the centralizer + `C(g_i)` of a fixed representative `g_i` of `\mathcal{C}_i`. In addition + to the fixed representative `g_k` of the class `\mathcal{C}_i` + and `\mathcal{C}_j`, the formula will make use of variable elements + `h_i` and `h_j` that are subject to the condition `h_i h_j = g_k`. + See [GoMa2010]_ equation (7). + + .. MATH:: + + \frac{|\mathcal{C}_k|}{|G|} + \sum_{\substack{h_i\in\mathcal{C}_i \\ h_j\in\mathcal{C}_j \\ h_ih_j=g_k}} + \lvert C(h_i)\cap C(h_j) \rvert \, + \langle \chi_i^{(h_i)} \chi_j^{(h_j)}, \chi_k \rangle_{C(h_i)\cap C(h_j)}, + + where `\chi_i^{(h_i)}` is the character `\chi_i` of `C(g_i)` + conjugated to a character of `C(h_i)`, when `h_i` is a conjugate + of the fixed representative `g_i`. More exactly, there exists `r_i` + such that `r_i g_i r_i^{-1} = h_i`, and then `\chi_i^{(h_i)}(x) = + \chi_i(r_i^{-1}xr_i)`, and this definition does not depend on the + choice of `r_i`. + + .. NOTE:: + + This should be functionally equivalent, and testing shows + that it is, but it is slower. + + EXAMPLES:: + + sage: A = FusionDouble(AlternatingGroup(4),prefix="aa",inject_variables=True) + sage: [A.Nk_ij(aa8,aa10,x) for x in A.basis()] + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1] + + sage: B = FusionDouble(CyclicPermutationGroup(2)) + sage: all(B.Nk_ij(x,y,z,use_characters=True) == B.Nk_ij(x,y,z) + ....: for x in B.basis() for y in B.basis() for z in B.basis()) + True + """ + if not use_characters: + return self.N_ijk(i, j, self.dual(k)) + + G = self._G + I = G.conjugacy_class(i.g()) + J = G.conjugacy_class(j.g()) + IJ = set(I_elem * J_elem for I_elem in I for J_elem in J) + if k.g() not in IJ: + return ZZ.zero() + + K = G.conjugacy_class(k.g()) + CI = G.centralizer(i.g()) + CJ = G.centralizer(j.g()) + CK = G.centralizer(k.g()) + + c = K.cardinality() / G.order() + summands = [(I_elem, J_elem) for I_elem in I for J_elem in J if I_elem * J_elem == k.g()] + res = ZZ.zero() + ichar = i.char() + jchar = j.char() + kchar = k.char() + for p in summands: + I_elem, J_elem = p + for g in G: + ginv = g.inverse() + if ginv * i.g() * g == I_elem: + i_twist = g + if ginv * j.g() * g == J_elem: + j_twist = g + A = Set(i_twist.inverse() * zi * i_twist for zi in CI) + B = Set(j_twist.inverse() * zj * j_twist for zj in CJ) + inner_summands = A.intersection(B).intersection(Set(CK)) + i_twist_inv = i_twist.inverse() + j_twist_inv = j_twist.inverse() + res += sum(ichar(i_twist * x * i_twist_inv) * jchar(j_twist * x * j_twist_inv) * kchar(x).conjugate() + for x in inner_summands) + return c * res + + @cached_method + def field(self): + """ + Returns a cyclotomic field large enough to contain the values + of R-matrices and twists that can arise for this fusion ring. + + EXAMPLES:: + + sage: FusionDouble(SymmetricGroup(3)).field() + Cyclotomic Field of order 24 and degree 8 + """ + return CyclotomicField(4 * self._cyclotomic_order) + + def fvars_field(self): + r""" + Return a field containing the ``CyclotomicField`` computed by + :meth:`field` as well as all the F-symbols of the associated + ``FMatrix`` factory object. + + This method is only available if ``self`` is multiplicity-free. + + EXAMPLES:: + + sage: FusionDouble(SymmetricGroup(3)).fvars_field() + Cyclotomic Field of order 24 and degree 8 + """ + if self.is_multiplicity_free(verbose=False): + return self.get_fmatrix().field() + raise NotImplementedError("method is only available for multiplicity free fusion rings") + + def root_of_unity(self, r, base_coercion=True): + r""" + Return `e^{i\pi r}` as an element of ``self.field()`` if possible. + + INPUT: + + - ``r`` -- a rational number + + EXAMPLES:: + + sage: H = FusionDouble(DihedralGroup(6)) + sage: H.field() + Cyclotomic Field of order 24 and degree 8 + sage: for n in [1..7]: + ....: try: + ....: print (n,H.root_of_unity(2/n)) + ....: except ValueError as err: + ....: print (n,err) + ....: + 1 1 + 2 -1 + 3 zeta24^4 - 1 + 4 zeta24^6 + 5 not a root of unity in the field + 6 zeta24^4 + 7 not a root of unity in the field + """ + n = 2 * r * self._cyclotomic_order + if n not in ZZ: + raise ValueError("not a root of unity in the field") + ret = self.field().gen() ** n + if (not base_coercion) or (self._basecoer is None): + return ret + return self._basecoer(ret) + + @cached_method + def r_matrix(self, i, j, k, base_coercion=True): + r""" + Return the R-matrix entry corresponding to the subobject ``k`` + in the tensor product of ``i`` with ``j``. This method is only + correct if the fusion coefficient ``N_{ij}^k\leq 1``. See the + :class:`FusionRing` method for more information, including + the reason for this caveat, and the algorithm. + + EXAMPLES:: + + sage: C = FusionDouble(SymmetricGroup(3),prefix="c",inject_variables=True) + sage: c4*c5 + c3 + c4 + sage: [C.r_matrix(c4,c5,k) for k in [c3,c4]] + [-zeta24^6, 1] + sage: c6^2 + c0 + c1 + c6 + sage: [C.r_matrix(c6,c6,k) for k in [c0,c1,c6]] + [zeta3, -zeta3, -zeta3 - 1] + """ + if self.Nk_ij(i, j, k) == 0: + return self.field().zero() if (not base_coercion) or (self._basecoer is None) else self.fvars_field().zero() + + if i != j: + ret = self.root_of_unity((k.twist() - i.twist() - j.twist()) / 2) + else: + i0 = self.one() + B = self.basis() + ret = sum(y.ribbon()**2 / (i.ribbon() * x.ribbon()**2) + * self.s_ij(i0, y) * self.s_ij(i, z) * self.s_ijconj(x, z) + * self.s_ijconj(k, x) * self.s_ijconj(y, z) / self.s_ij(i0, z) + for x in B for y in B for z in B) / (self.total_q_order()**4) + + if (not base_coercion) or (self._basecoer is None): + return ret + return self._basecoer(ret) + + def global_q_dimension(self, base_coercion=True): + r""" + Return the global quantum dimension, which is the sum of the squares of the + quantum dimensions of the simple objects. + For the Drinfeld double, it is the square of the order of the underlying quantum group. + + EXAMPLES:: + + sage: G = SymmetricGroup(4) + sage: H = FusionDouble(G) + sage: H.global_q_dimension() + 576 + sage: sum(x.q_dimension()^2 for x in H.basis()) + 576 + """ + ret = self._G.order() ** 2 + if (not base_coercion) or (self._basecoer is None): + return ret + return self._basecoer(ret) + + def total_q_order(self, base_coercion=True): + r""" + Return the positive square root of :meth:`self.global_q_dimension() + <global_q_dimension>` as an element of :meth:`self.field() <field>`. + + For the Drinfeld double of a finite group `G`, this equals the + cardinality of `G`. This is also equal to `\sum d_i^2 \theta_i^{\pm 1}`, + where `i` runs through the simple objects, `d_i` is the quantum + dimension, and `\theta_i` is the twist. This sum with `\theta_i` is + denoted `p_-` in [BaKi2001]_ Chapter 3. + + EXAMPLES:: + + sage: FusionDouble(DihedralGroup(7)).total_q_order() + 14 + """ + ret = self._G.order() + if (not base_coercion) or (self._basecoer is None): + return ret + return self._basecoer(ret) + + D_minus = D_plus = total_q_order + + def is_multiplicity_free(self, verbose=False): + """ + Return ``True`` if all fusion coefficients are at most 1. + + EXAMPLES:: + + sage: FusionDouble(SymmetricGroup(3)).is_multiplicity_free() + True + sage: FusionDouble(SymmetricGroup(4)).is_multiplicity_free() + False + + sage: FusionDouble(SymmetricGroup(3)).is_multiplicity_free(True) + Checking multiplicity freeness + True + sage: FusionDouble(SymmetricGroup(4)).is_multiplicity_free(True) + Checking multiplicity freeness + N(s2,s13,s13) = 2 + False + """ + if verbose: + print("Checking multiplicity freeness") + from itertools import product + for (i, j, k) in product(self.basis(), repeat=3): + if self.N_ijk(i, j, k) > 1: + print("N(%s,%s,%s) = %s" % (i, j, k, self.N_ijk(i, j, k))) + return False + return True + + return all(self.N_ijk(i,j,k) <= 1 for i in self.basis() + for j in self.basis() for k in self.basis()) + + @cached_method + def one_basis(self): + r""" + The unit element of the ring, which is the first basis element. + + EXAMPLES:: + + sage: FusionDouble(CyclicPermutationGroup(2), prefix="h").one() + h0 + """ + return ZZ.zero() + + @cached_method + def dual(self, i): + r""" + Return the dual object ``i^\ast`` to ``i``. + + The dual is also available as an element method of ``i``. + + EXAMPLES:: + + sage: K = FusionDouble(CyclicPermutationGroup(3),prefix="k") + sage: [(x,K.dual(x)) for x in K.basis()] + [(k0, k0), + (k1, k2), + (k2, k1), + (k3, k6), + (k4, k8), + (k5, k7), + (k6, k3), + (k7, k5), + (k8, k4)] + sage: all(K.dual(x)==x.dual() for x in K.basis()) + True + """ + sz = self.one() + for j in self.basis(): + if self.N_ijk(i, j, sz) > 0: + return j + + def product_on_basis(self, a, b): + """ + Return the product of two basis elements corresponding to keys `a` and `b`. + + INPUT: + + - ``a`, ``b`` -- keys for the dictionary ``self._names`` representing simple objects + + EXAMPLES:: + + sage: Q=FusionDouble(SymmetricGroup(3),prefix="q",inject_variables=True) + sage: q3*q4 + q1 + q2 + q5 + q6 + q7 + sage: Q._names + {0: 'q0', 1: 'q1', 2: 'q2', 3: 'q3', 4: 'q4', 5: 'q5', 6: 'q6', 7: 'q7'} + sage: Q.product_on_basis(3,4) + q1 + q2 + q5 + q6 + q7 + """ + d = {k.support_of_term(): val for k in self.basis() + if (val := self.N_ijk(self.monomial(a),self.monomial(b),self.dual(k)))} + return self._from_dict(d, remove_zeros=False) + + def group(self): + """ + Return the underlying group. + + EXAMPLES:: + + sage: FusionDouble(DiCyclicGroup(4)).group() + Dicyclic group of order 16 as a permutation group + """ + return self._G + + def get_fmatrix(self, *args, **kwargs): + r""" + Construct an :class:`FMatrix` factory to solve the pentagon and + hexagon relations and organize the resulting F-symbols. + + EXAMPLES:: + + sage: f = FusionDouble(SymmetricGroup(3)).get_fmatrix(); f + F-Matrix factory for The Fusion Ring of the Drinfeld Double of + Symmetric group of order 3! as a permutation group + """ + if not hasattr(self, 'fmats') or kwargs.get('new', False): + kwargs.pop('new', None) + from sage.algebras.fusion_rings.f_matrix import FMatrix + self.fmats = FMatrix(self, *args, **kwargs) + return self.fmats + + class Element(CombinatorialFreeModule.Element): + def is_simple_object(self): + r""" + Determine whether ``self`` is a simple object (basis element) of the fusion ring. + + EXAMPLES:: + + sage: H = FusionDouble(CyclicPermutationGroup(2), prefix="g", inject_variables=True) + sage: [x.is_simple_object() for x in [g0, g1, g0+g1]] + [True, True, False] + """ + return len(self._monomial_coefficients) == 1 + + def g(self): + r""" + The data determining a simple object consists of a conjugacy + class representative `g` and an irreducible character `\chi` of + the centralizer of `g`. + + Returns the conjugacy class representative of the underlying + group corresponding to a simple object. See also :meth:`char`. + + EXAMPLES:: + + sage: G = QuaternionGroup() + sage: H = FusionDouble(G, prefix="e", inject_variables=True) + sage: e10.g() + (1,3)(2,4)(5,7)(6,8) + sage: e10.char() + Character of Subgroup generated by [(1,2,3,4)(5,6,7,8), (1,5,3,7)(2,8,4,6)] + of (Quaternion group of order 8 as a permutation group) + """ + return self.parent()._elt[self.support_of_term()] + + def char(self): + r""" + Return the character `\chi` corresponding to ``self``. + + The data determining a simple object consists of a conjugacy + class representative `g` and an irreducible character `\chi` of + the centralizer of `g`. + + .. SEEALSO:: :meth:`g` + + EXAMPLES:: + + sage: G = DihedralGroup(5) + sage: H = FusionDouble(G, prefix="f", inject_variables=True) + sage: f10.g() + (1,2,3,4,5) + sage: f10.char() + Character of Subgroup generated by [(1,2,3,4,5)] of + (Dihedral group of order 10 as a permutation group) + """ + return self.parent()._chi[self.support_of_term()] + + def ribbon(self, base_coercion=True): + """ + The twist or ribbon of the simple object. + + EXAMPLES:: + + sage: H = FusionDouble(CyclicPermutationGroup(3)) + sage: [i.ribbon() for i in H.basis()] + [1, 1, 1, 1, zeta3, -zeta3 - 1, 1, -zeta3 - 1, zeta3] + """ + i = self.support_of_term() + P = self.parent() + ret = P._char_cache(i, self.g()) / P._char_cache(i, P._G.one()) + if (not base_coercion) or (P._basecoer is None): + return ret + return self.parent()._basecoer(ret) + + def twist(self, reduced=True): + r""" + Return a rational number `h` such that `\theta = e^{i \pi h}` + is the twist of ``self``. + + The quantity `e^{i \pi h}` is also available using :meth:`ribbon`. + + This method is only available for simple objects. + + EXAMPLES:: + + sage: Q=FusionDouble(CyclicPermutationGroup(3)) + sage: [x.twist() for x in Q.basis()] + [0, 0, 0, 0, 2/3, 4/3, 0, 4/3, 2/3] + sage: [x.ribbon() for x in Q.basis()] + [1, 1, 1, 1, zeta3, -zeta3 - 1, 1, -zeta3 - 1, zeta3] + + TESTS:: + + sage: H = FusionDouble(AlternatingGroup(4)) + sage: sum(H.basis()).twist() + Traceback (most recent call last): + ... + ValueError: quantum twist is only available for simple objects + """ + if not self.is_simple_object(): + raise ValueError("quantum twist is only available for simple objects") + P = self.parent() + zeta = P.field().gen() + rib = self.ribbon() + norm = 2 * P._cyclotomic_order + for k in range(4*P._cyclotomic_order): + if zeta ** k == rib: + return k / norm + + def dual(self): + """ + Return the dual of ``self``. + + This method is only available for simple objects. + + EXAMPLES:: + + sage: G = CyclicPermutationGroup(4) + sage: H = FusionDouble(G, prefix="j") + sage: [x for x in H.basis() if x == x.dual()] + [j0, j1, j8, j9] + + TESTS:: + + sage: H = FusionDouble(AlternatingGroup(4)) + sage: sum(H.basis()).dual() + Traceback (most recent call last): + ... + ValueError: dual is only available for simple objects + """ + if not self.is_simple_object(): + raise ValueError("dual is only available for simple objects") + return self.parent().dual(self) + + @cached_method + def q_dimension(self, base_coercion=True): + """ + Return the q-dimension of ``self``. + + This method is only available for simple objects. + + EXAMPLES:: + + sage: G = AlternatingGroup(4) + sage: H = FusionDouble(G) + sage: [x.q_dimension() for x in H.basis()] + [1, 1, 1, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4] + sage: sum(x.q_dimension()^2 for x in H.basis()) == G.order()^2 + True + + TESTS:: + + sage: H = FusionDouble(AlternatingGroup(4)) + sage: sum(H.basis()).q_dimension() + Traceback (most recent call last): + ... + ValueError: quantum dimension is only available for simple objects + """ + if not self.is_simple_object(): + raise ValueError("quantum dimension is only available for simple objects") + return self.parent().s_ij(self,self.parent().one()) diff --git a/src/sage/algebras/fusion_rings/fusion_ring.py b/src/sage/algebras/fusion_rings/fusion_ring.py index 915ca62e73b..02da0032802 100644 --- a/src/sage/algebras/fusion_rings/fusion_ring.py +++ b/src/sage/algebras/fusion_rings/fusion_ring.py @@ -8,7 +8,10 @@ # Nicolas Thiery <nthiery at users.sf.net> # 2022 Guillermo Aboumrad <gh_willieab> # -# Distributed under the terms of the GNU General Public License (GPL) +# 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. # https://www.gnu.org/licenses/ # **************************************************************************** @@ -50,7 +53,7 @@ class FusionRing(WeylCharacterRing): The cyclotomic order is an integer `N` such that all computations will return elements of the cyclotomic field of `N`-th roots of unity. Normally you will never need to change this but consider changing it - if :meth:`root_of_unity` raises a ``ValueError``. + if :meth:`root_of_unity` raises a :class:`ValueError`. This algebra has a basis (sometimes called *primary fields* but here called *simple objects*) indexed by the weights of level `\leq k`. @@ -207,8 +210,8 @@ class FusionRing(WeylCharacterRing): As an exercise, the reader may verify the examples in Section 5.3 of [RoStWa2009]_. Here we check the example of the Ising modular tensor category, which is related - to the BPZ minimal model `M(4, 3)` or to an `E_8` coset - model. See [DFMS1996]_ Sections 7.4.2 and 18.4.1. + to the Belavin, Polyakov, Zamolodchikov minimal model `M(4, 3)` + or to an `E_8` coset model. See [DFMS1996]_ Sections 7.4.2 and 18.4.1. [RoStWa2009]_ Example 5.3.4 tells us how to construct it as the conjugate of the `E_8` level 2 :class:`FusionRing`:: @@ -401,7 +404,7 @@ def test_braid_representation(self, max_strands=6, anyon=None): sage: A21 = FusionRing("A2", 1) sage: A21.test_braid_representation(max_strands=4) True - sage: F41 = FusionRing("F4", 1) # long time + sage: F41 = FusionRing("F4", 1) # long time sage: F41.test_braid_representation() # long time True """ @@ -815,6 +818,11 @@ def s_ij(self, elt_i, elt_j, base_coercion=True): Return the element of the S-matrix of this fusion ring corresponding to the given elements. + This is the unnormalized S-matrix, denoted `\tilde{s}_{ij}` + in [BaKi2001]_ . To obtain the normalized S-matrix, divide by + :meth:`global_q_dimension()` or use :meth:`S_matrix()` with + the option ``unitary=True``. + This is computed using the formula .. MATH:: @@ -1172,7 +1180,7 @@ def _get_trees(fr, top_row, root): comp_basis = list() for top in product((a*a).monomials(), repeat=n_strands//2): # If the n_strands is odd, we must extend the top row by a fusing anyon - top_row = list(top)+[a]*(n_strands%2) + top_row = list(top)+[a]*(n_strands % 2) comp_basis.extend(tuple([*top, *levels]) for levels in _get_trees(self, top_row, b)) return comp_basis @@ -1181,8 +1189,6 @@ def get_fmatrix(self, *args, **kwargs): Construct an :class:`FMatrix` factory to solve the pentagon relations and organize the resulting F-symbols. - We only need this attribute to compute braid group representations. - EXAMPLES:: sage: A15 = FusionRing("A1", 5) @@ -1283,7 +1289,7 @@ def get_braid_generators(self, we don't run the solver again. - ``use_mp`` -- (default: ``True``) a boolean indicating whether to use multiprocessing to speed up the computation; this is - highly recommended. Python 3.8+ is required. + highly recommended. - ``verbose`` -- (default: ``True``) boolean indicating whether to be verbose with the computation diff --git a/src/sage/algebras/fusion_rings/poly_tup_engine.pxd b/src/sage/algebras/fusion_rings/poly_tup_engine.pxd index 22c6449385a..a4ddf9b92ae 100644 --- a/src/sage/algebras/fusion_rings/poly_tup_engine.pxd +++ b/src/sage/algebras/fusion_rings/poly_tup_engine.pxd @@ -21,4 +21,3 @@ cdef tuple reduce_poly_dict(dict eq_dict, ETuple nonz, KSHandler known_sq, Numbe cdef tuple _flatten_coeffs(tuple eq_tup) cpdef tuple _unflatten_coeffs(field, tuple eq_tup) cdef int has_appropriate_linear_term(tuple eq_tup) - diff --git a/src/sage/algebras/fusion_rings/poly_tup_engine.pyx b/src/sage/algebras/fusion_rings/poly_tup_engine.pyx index ac465e14a77..67176402134 100644 --- a/src/sage/algebras/fusion_rings/poly_tup_engine.pyx +++ b/src/sage/algebras/fusion_rings/poly_tup_engine.pyx @@ -9,7 +9,7 @@ Arithmetic Engine for Polynomials as Tuples # **************************************************************************** ########### -### API ### +# API # ########### cpdef inline tuple poly_to_tup(MPolynomial_libsingular poly): @@ -115,7 +115,7 @@ cpdef tuple _unflatten_coeffs(field, tuple eq_tup): return tuple(unflat) ################################# -### Useful private predicates ### +# Useful private predicates # ################################# cdef inline int has_appropriate_linear_term(tuple eq_tup): @@ -146,7 +146,7 @@ cdef inline int has_appropriate_linear_term(tuple eq_tup): return -1 ###################### -### "Change rings" ### +# "Change rings" # ###################### cpdef inline tup_to_univ_poly(tuple eq_tup, univ_poly_ring): @@ -215,7 +215,7 @@ cpdef inline tuple resize(tuple eq_tup, dict idx_map, int nvars): return tuple(resized) ########################### -### Convenience methods ### +# Convenience methods # ########################### cdef inline ETuple degrees(tuple poly_tup): @@ -225,7 +225,7 @@ cdef inline ETuple degrees(tuple poly_tup): # Deal with the empty tuple, representing the zero polynomial if not poly_tup: return ETuple() - cdef ETuple max_degs, exp + cdef ETuple max_degs cdef int i max_degs = <ETuple> (<tuple> poly_tup[0])[0] for i in range(1, len(poly_tup)): @@ -251,7 +251,7 @@ cpdef list get_variables_degrees(list eqns, int nvars): cdef int i max_deg = degrees(eqns[0]) for i in range(1, len(eqns)): - max_deg = max_deg.emax(degrees( <tuple>(eqns[i]) )) + max_deg = max_deg.emax(degrees(<tuple>(eqns[i]))) cdef list dense = [0] * len(max_deg) for i in range(max_deg._nonzero): dense[max_deg._data[2*i]] = max_deg._data[2*i+1] @@ -339,7 +339,7 @@ cdef inline bint tup_fixes_sq(tuple eq_tup): return True ###################### -### Simplification ### +# Simplification # ###################### cdef dict subs_squares(dict eq_dict, KSHandler known_sq): @@ -358,7 +358,7 @@ cdef dict subs_squares(dict eq_dict, KSHandler known_sq): A dictionary of ``(ETuple, coeff)`` pairs. """ cdef dict subbed, new_e - cdef ETuple exp, lm + cdef ETuple exp cdef int idx, power subbed = dict() for exp, coeff in eq_dict.items(): @@ -434,7 +434,7 @@ cdef tuple reduce_poly_dict(dict eq_dict, ETuple nonz, KSHandler known_sq, Numbe return to_monic(gcf_rmvd, one) #################### -### Substitution ### +# Substitution # #################### cpdef dict compute_known_powers(max_degs, dict val_dict, one): @@ -521,7 +521,7 @@ cdef tuple tup_mul(tuple p1, tuple p2): return tuple(prod.items()) ############### -### Sorting ### +# Sorting # ############### cdef tuple monom_sortkey(ETuple exp): @@ -564,7 +564,7 @@ cpdef tuple poly_tup_sortkey(tuple eq_tup): (2, 0, 2, 2, 0, 1, -2, 1, 2, -2, 2, 1, 0, 1, 1, -1, 1) """ cdef ETuple exp - cdef int i, l, nnz + cdef int i cdef list key = [] for exp, c in eq_tup: # Compare by term degree @@ -576,4 +576,3 @@ cpdef tuple poly_tup_sortkey(tuple eq_tup): key.append(-exp._data[2*i]) key.append(exp._data[2*i+1]) return tuple(key) - diff --git a/src/sage/algebras/fusion_rings/shm_managers.pxd b/src/sage/algebras/fusion_rings/shm_managers.pxd index 342b533acae..8f4967d6d0a 100644 --- a/src/sage/algebras/fusion_rings/shm_managers.pxd +++ b/src/sage/algebras/fusion_rings/shm_managers.pxd @@ -21,4 +21,3 @@ cdef class FvarsHandler: cdef object fvars_t, pid_list cdef Py_ssize_t child_id cdef public object shm - diff --git a/src/sage/algebras/fusion_rings/shm_managers.pyx b/src/sage/algebras/fusion_rings/shm_managers.pyx index 91aba7ba59f..bbb364e91dd 100644 --- a/src/sage/algebras/fusion_rings/shm_managers.pyx +++ b/src/sage/algebras/fusion_rings/shm_managers.pyx @@ -22,7 +22,7 @@ from multiprocessing import shared_memory from sage.algebras.fusion_rings.poly_tup_engine cimport poly_to_tup, tup_fixes_sq, _flatten_coeffs from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational -from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular +from sage.rings.polynomial.multi_polynomial cimport MPolynomial_libsingular from sage.rings.polynomial.polydict cimport ETuple import numpy as np @@ -55,8 +55,7 @@ cdef class KSHandler: - ``n_slots`` -- the total number of F-symbols - ``field`` -- F-matrix's base cyclotomic field - ``use_mp`` -- a boolean indicating whether to construct a shared - memory block to back ``self``. Requires Python 3.8+, since we - must import the ``multiprocessing.shared_memory`` module. + memory block to back ``self``. - ``init_data`` -- a dictionary or :class:`KSHandler` object containing known squares for initialization, e.g., from a solver checkpoint - ``name`` -- the name of a shared memory object (used by child processes @@ -96,7 +95,7 @@ cdef class KSHandler: sage: ks.shm.unlink() sage: f.shutdown_worker_pool() """ - def __init__(self, n_slots, field, use_mp=False, init_data={}, name=None): + def __init__(self, n_slots, field, use_mp=False, init_data=None, name=None): r""" Initialize ``self``. @@ -115,6 +114,8 @@ cdef class KSHandler: sage: f.shutdown_worker_pool() """ cdef int n, d + if init_data is None: + init_data = {} self.field = field n = n_slots d = self.field.degree() @@ -342,6 +343,7 @@ cdef class KSHandler: if self.ks_dat['known'][i]: yield i, self.get(i) + def make_KSHandler(n_slots, field, init_data): r""" Provide pickling / unpickling support for :class:`KSHandler`. @@ -358,6 +360,7 @@ def make_KSHandler(n_slots, field, init_data): """ return KSHandler(n_slots, field, init_data=init_data) + cdef class FvarsHandler: r""" A shared memory backed dict-like structure to manage the @@ -387,9 +390,6 @@ cdef class FvarsHandler: ``name`` attribute. Children processes use the ``name`` attribute, accessed via ``self.shm.name`` to attach to the shared memory block. - Multiprocessing requires Python 3.8+, since we must import the - ``multiprocessing.shared_memory`` module. - INPUT: - ``n_slots`` -- number of generators of the underlying polynomial ring @@ -418,7 +418,7 @@ cdef class FvarsHandler: .. NOTE:: - If you ever encounter an ``OverflowError`` when running the + If you ever encounter an :class:`OverflowError` when running the :meth:`FMatrix.find_orthogonal_solution` solver, consider increasing the parameter ``n_bytes``. @@ -451,7 +451,8 @@ cdef class FvarsHandler: sage: fvars.shm.unlink() sage: f.shutdown_worker_pool() """ - def __init__(self, n_slots, field, idx_to_sextuple, init_data={}, use_mp=0, + def __init__(self, n_slots, field, idx_to_sextuple, init_data=None, + use_mp=0, pids_name=None, name=None, max_terms=20, n_bytes=32): r""" Initialize ``self``. @@ -477,6 +478,8 @@ cdef class FvarsHandler: self.bytes = n_bytes cdef int slots = self.bytes // 8 cdef int n_proc = use_mp + 1 + if init_data is None: + init_data = {} self.fvars_t = np.dtype([ ('modified', np.int8, (n_proc, )), ('ticks', 'u1', (max_terms, )), @@ -575,7 +578,7 @@ cdef class FvarsHandler: return self.obj_cache[idx] cdef ETuple e, exp cdef int count, nnz - cdef Integer d, num + cdef Integer num cdef list poly_tup, rats cdef NumberFieldElement_absolute cyc_coeff cdef Py_ssize_t cum, i, j, k @@ -753,6 +756,7 @@ cdef class FvarsHandler: for sextuple in self.sext_to_idx: yield sextuple, self[sextuple] + def make_FvarsHandler(n, field, idx_map, init_data): r""" Provide pickling / unpickling support for :class:`FvarsHandler`. @@ -773,4 +777,3 @@ def make_FvarsHandler(n, field, idx_map, init_data): sage: f.shutdown_worker_pool() """ return FvarsHandler(n, field, idx_map, init_data=init_data) - diff --git a/src/sage/algebras/group_algebra.py b/src/sage/algebras/group_algebra.py index 6821a64f68f..e16b0c08a21 100644 --- a/src/sage/algebras/group_algebra.py +++ b/src/sage/algebras/group_algebra.py @@ -35,8 +35,8 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import IntegerRing -from sage.categories.all import Rings +from sage.rings.integer_ring import IntegerRing +from sage.categories.rings import Rings from sage.categories.magmas import Magmas from sage.categories.additive_magmas import AdditiveMagmas from sage.categories.sets_cat import Sets @@ -223,5 +223,6 @@ def _coerce_map_from_(self, S): return SetMorphism(S.Hom(self, category=self.category() | S.category()), lambda x: self.sum_of_terms( (hom_G(g), hom_K(c)) for g,c in x )) + from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.algebras.group_algebras', 'GroupAlgebra', GroupAlgebra_class) diff --git a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py index c1596761c99..cf1c7a04c39 100644 --- a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py +++ b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py @@ -366,7 +366,7 @@ def _latex_(self): sage: latex(H) \mathcal{H}_{5,2}(q) """ - return "\\mathcal{H}_{%s,%s}(%s)"%(self._r, self._n, self._q) + return "\\mathcal{H}_{%s,%s}(%s)" % (self._r, self._n, self._q) def hecke_parameter(self): r""" @@ -479,7 +479,7 @@ def _repr_(self): Ariki-Koike algebra of rank 5 and order 2 with q=q and u=(u0, u1, u2, u3, u4) ... in the LT-basis """ - return "%s in the %s-basis"%(self.realization_of(), self._realization_name()) + return "%s in the %s-basis" % (self.realization_of(), self._realization_name()) def hecke_parameter(self): r""" @@ -540,7 +540,7 @@ def dimension(self): sage: LT.dimension() 29160 """ - from sage.arith.all import factorial + from sage.arith.misc import factorial return self._r**self._n * factorial(self._n) def some_elements(self): @@ -602,8 +602,8 @@ def _repr_term(self, m): sage: LT._repr_term( ((1, 0, 2), Permutation([3,2,1])) ) 'L1*L3^2*T[2,1,2]' """ - gen_str = lambda e: '' if e == 1 else '^%s'%e - lhs = '*'.join('L%s'%(j+1) + gen_str(i) + gen_str = lambda e: '' if e == 1 else '^%s' % e + lhs = '*'.join('L%s' % (j+1) + gen_str(i) for j,i in enumerate(m[0]) if i > 0) redword = m[1].reduced_word() if not redword: @@ -625,15 +625,15 @@ def _latex_term(self, m): sage: LT._latex_term( ((1, 0, 2), Permutation([3,2,1])) ) 'L_{1} L_{3}^{2} T_{2} T_{1} T_{2}' """ - gen_str = lambda e: '' if e == 1 else '^{%s}'%e - lhs = ' '.join('L_{%s}'%(j+1) + gen_str(i) + gen_str = lambda e: '' if e == 1 else '^{%s}' % e + lhs = ' '.join('L_{%s}' % (j+1) + gen_str(i) for j,i in enumerate(m[0]) if i > 0) redword = m[1].reduced_word() if not redword: if not lhs: return '1' return lhs - return lhs + ' ' + ' '.join("T_{%d}"%i for i in redword) + return lhs + ' ' + ' '.join("T_{%d}" % i for i in redword) def _from_T_basis(self, t): r""" @@ -698,10 +698,10 @@ def algebra_generators(self): for i in range(self._n): r = list(self._zero_tuple) # Make a copy r[i] = 1 - d['L%s'%(i+1)] = self.monomial( (tuple(r), self._one_perm) ) + d['L%s' % (i+1)] = self.monomial( (tuple(r), self._one_perm) ) G = self._Pn.group_generators() for i in range(1, self._n): - d['T%s'%i] = self.monomial( (self._zero_tuple, G[i]) ) + d['T%s' % i] = self.monomial( (self._zero_tuple, G[i]) ) return Family(sorted(d), lambda i: d[i]) def T(self, i=None): @@ -725,10 +725,10 @@ def T(self, i=None): """ G = self.algebra_generators() if i is None: - return [G['L1']] + [G['T%s'%j] for j in range(1, self._n)] + return [G['L1']] + [G['T%s' % j] for j in range(1, self._n)] if i == 0: return G['L1'] - return G['T%s'%i] + return G['T%s' % i] def L(self, i=None): r""" @@ -759,10 +759,10 @@ def L(self, i=None): if i is None: if self._r == 1: return [self._Li_power(j, 1) for j in range(1, self._n+1)] - return [G['L%s'%j] for j in range(1, self._n+1)] + return [G['L%s' % j] for j in range(1, self._n+1)] if self._r == 1: return self._Li_power(i, 1) - return G['L%s'%i] + return G['L%s' % i] @cached_method def product_on_basis(self, m1, m2): @@ -1179,7 +1179,7 @@ def __init__(self, algebra): sage: TestSuite(T).run() # long time """ _Basis.__init__(self, algebra, prefix='T') - self._assign_names(['T%s'%i for i in range(self._n)]) + self._assign_names(['T%s' % i for i in range(self._n)]) def _repr_term(self, t): r""" @@ -1200,7 +1200,7 @@ def _repr_term(self, t): if len(redword) == 0: return "1" return (self._print_options['prefix'] - + '[%s]'%','.join('%d'%i for i in redword)) + + '[%s]' % ','.join('%d' % i for i in redword)) def _latex_term(self, t): r""" @@ -1220,7 +1220,7 @@ def _latex_term(self, t): redword += t[1].reduced_word() if len(redword) == 0: return "1" - return ''.join("%s_{%d}"%(self._print_options['prefix'], i) + return ''.join("%s_{%d}" % (self._print_options['prefix'], i) for i in redword) def _from_LT_basis(self, m): diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py index 6388fa79e60..7c2fe4a2210 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -59,9 +59,9 @@ def normalize_names_markov(names, markov_trace_version): if markov_trace_version: names = normalize_names(4, names) else: - if type(names) == tuple: + if isinstance(names, tuple): names = list(names) - if type(names) == list and len(names) > 3: + if isinstance(names, list) and len(names) > 3: names = normalize_names(3, names[0:3]) else: names = normalize_names(3, names) @@ -641,10 +641,10 @@ def create_specialization(self, im_cubic_equation_roots, im_writhe_parameter=Non # corresponding specialized extension ring. # ---------------------------------------------------------------------- - if type(im_cubic_equation_roots) == tuple: + if isinstance(im_cubic_equation_roots, tuple): im_cubic_equation_roots = list(im_cubic_equation_roots) - if type(im_cubic_equation_roots) != list: + if not isinstance(im_cubic_equation_roots, list): raise TypeError('cubic_equation_roots must be a list of three elements') if len(im_cubic_equation_roots) != 3: @@ -1226,10 +1226,10 @@ def create_specialization(self, im_cubic_equation_parameters, im_writhe_paramete # ---------------------------------------------------------------------- # setting the base_ring according to the cubic_equation_parameters # ---------------------------------------------------------------------- - if type(im_cubic_equation_parameters) == tuple: + if isinstance(im_cubic_equation_parameters, tuple): im_cubic_equation_parameters = list(im_cubic_equation_parameters) - if type(im_cubic_equation_parameters) != list: + if not isinstance(im_cubic_equation_parameters, list): raise TypeError('cubic_equation_parameters must be a list of three elements') if len(im_cubic_equation_parameters) != 3: diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 900039c7909..0b6696af043 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -30,10 +30,12 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.realizations import Realizations, Category_realization_of_parent -from sage.categories.all import AlgebrasWithBasis, FiniteDimensionalAlgebrasWithBasis, CoxeterGroups +from sage.categories.algebras_with_basis import AlgebrasWithBasis +from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis +from sage.categories.coxeter_groups import CoxeterGroups from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.arith.all import is_square +from sage.arith.misc import is_square from sage.combinat.root_system.coxeter_group import CoxeterGroup from sage.sets.family import Family from sage.combinat.free_module import CombinatorialFreeModule @@ -2491,6 +2493,8 @@ def __init__(self, IHAlgebra, prefix=None): r""" Initialize the `A`-basis of the Iwahori-Hecke algebra ``IHAlgebra``. + EXAMPLES:: + sage: R.<v> = LaurentPolynomialRing(QQ) sage: H = IwahoriHeckeAlgebra('A3', v**2) sage: A = H.A() diff --git a/src/sage/algebras/jordan_algebra.py b/src/sage/algebras/jordan_algebra.py index f5824069797..81c40105f8a 100644 --- a/src/sage/algebras/jordan_algebra.py +++ b/src/sage/algebras/jordan_algebra.py @@ -4,26 +4,30 @@ AUTHORS: - Travis Scrimshaw (2014-04-02): initial version +- Travis Scrimshaw (2023-05-09): added the 27 dimensional exceptional + Jordan algebra """ #***************************************************************************** -# Copyright (C) 2014 Travis Scrimshaw <tscrim at ucdavis.edu> +# Copyright (C) 2014, 2023 Travis Scrimshaw <tscrim at ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element import AlgebraElement +from sage.structure.richcmp import richcmp from sage.categories.magmatic_algebras import MagmaticAlgebras from sage.misc.cachefunc import cached_method from sage.structure.element import is_Matrix from sage.modules.free_module import FreeModule +from sage.matrix.constructor import matrix from sage.sets.family import Family -class JordanAlgebra(Parent, UniqueRepresentation): +class JordanAlgebra(UniqueRepresentation, Parent): r""" A Jordan algebra. @@ -63,7 +67,7 @@ class JordanAlgebra(Parent, UniqueRepresentation): (\alpha + x) \circ (\beta + y) = \underbrace{\alpha \beta + (x,y)}_{\in R} - + \underbrace{\beta x + \alpha y}_{\in M} + + \underbrace{\beta x + \alpha y}_{\in M}, where `\alpha, \beta \in R` and `x,y \in M`. @@ -71,7 +75,7 @@ class JordanAlgebra(Parent, UniqueRepresentation): Can be either an associative algebra `A` or a symmetric bilinear form given as a matrix (possibly followed by, or preceded by, a base - ring argument) + ring argument). EXAMPLES: @@ -144,13 +148,9 @@ class JordanAlgebra(Parent, UniqueRepresentation): REFERENCES: - :wikipedia:`Jordan_algebra` - - [Ja1971]_ - - [Ch2012]_ - - [McC1978]_ - - [Al1947]_ """ @staticmethod @@ -194,6 +194,9 @@ def __classcall_private__(self, arg0, arg1=None, names=None): if arg1 is None: if not is_Matrix(arg0): + from sage.algebras.octonion_algebra import OctonionAlgebra + if isinstance(arg0, OctonionAlgebra): + return ExceptionalJordanAlgebra(arg0) if arg0.base_ring().characteristic() == 2: raise ValueError("the base ring cannot have characteristic 2") return SpecialJordanAlgebra(arg0, names) @@ -209,6 +212,29 @@ def __classcall_private__(self, arg0, arg1=None, names=None): arg1.set_immutable() return JordanAlgebraSymmetricBilinear(arg0, arg1, names=names) + def _test_jordan_relations(self, **options): + r""" + Test the Jordan algebra relations. + + The Jordan algebra relations are + + - `xy = yx`, and + - `(xy)(xx) = x(y(xx))` (the Jordan identity). + + EXAMPLES:: + + sage: O = OctonionAlgebra(GF(7), 1, 3, 4) + sage: J = JordanAlgebra(O) + sage: J._test_jordan_relations() + """ + tester = self._tester(**options) + S = tester.some_elements() + from sage.misc.misc import some_tuples + for x, y in some_tuples(S, 2, tester._max_runs): + tester.assertEqual(x * y, y * x) + tester.assertEqual((x * y) * (x * x), x * (y * (x * x))) + + class SpecialJordanAlgebra(JordanAlgebra): r""" A (special) Jordan algebra `A^+` from an associative algebra `A`. @@ -572,6 +598,7 @@ def monomial_coefficients(self, copy=True): """ return self._x.monomial_coefficients(copy) + class JordanAlgebraSymmetricBilinear(JordanAlgebra): r""" A Jordan algebra given by a symmetric bilinear form `m`. @@ -694,6 +721,12 @@ def _coerce_map_from_base_ring(self): TESTS:: sage: J = JordanAlgebra(Matrix([[0, 1], [1, 1]])) + sage: J._coerce_map_from_base_ring() + Conversion map: + From: Integer Ring + To: Jordan algebra over Integer Ring given by the symmetric bilinear form: + [0 1] + [1 1] sage: J.coerce_map_from(ZZ) Coercion map: From: Integer Ring @@ -737,8 +770,8 @@ def gens(self): sage: m = matrix([[0,1],[1,1]]) sage: J = JordanAlgebra(m) - sage: J.basis() - Family (1 + (0, 0), 0 + (1, 0), 0 + (0, 1)) + sage: J.gens() + (1 + (0, 0), 0 + (1, 0), 0 + (0, 1)) """ return tuple(self.algebra_generators()) @@ -1052,3 +1085,688 @@ def bar(self): True """ return self.__class__(self.parent(), self._s, -self._v) + + +class ExceptionalJordanAlgebra(JordanAlgebra): + r""" + The exceptional `27` dimensional Jordan algebra as self-adjoint + `3 \times 3` matrix over an octonion algebra. + + Let `\mathbf{O}` be the :class:`OctonionAlgebra` over a commutative + ring `R` of characteristic not equal to `2`. The *exceptional Jordan + algebra* `\mathfrak{h}_3(\mathbf{O})` is a `27` dimensional free + `R`-module spanned by the matrices + + .. MATH:: + + \begin{bmatrix} + \alpha & x & y \\ + x^* & \beta & z \\ + y^* & z^* & \gamma + \end{bmatrix} + + for `\alpha, \beta, \gamma \in R` and `x, y, z \in \mathbf{O}`, + with multiplication given by the usual symmetrizer operation + `X \circ Y = \frac{1}{2}(XY + YX)`. + + These are also known as *Albert algebras* due to the work of + Abraham Adrian Albert on these algebras over `\RR`. + + EXAMPLES: + + We construct an exceptional Jordan algebra over `\QQ` and perform + some basic computations:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: gens = J.gens() + sage: gens[1] + [0 0 0] + [0 1 0] + [0 0 0] + sage: gens[3] + [0 1 0] + [1 0 0] + [0 0 0] + sage: gens[1] * gens[3] + [ 0 1/2 0] + [1/2 0 0] + [ 0 0 0] + + The Lie algebra of derivations of the exceptional Jordan algebra + is isomorphic to the simple Lie algebra of type `F_4`. We verify + that we the derivation module has the correct dimension:: + + sage: len(J.derivations_basis()) # long time + 52 + sage: LieAlgebra(QQ, cartan_type='F4').dimension() + 52 + + REFERENCES: + + - :wikipedia:`Albert_algebra` + - :wikipedia:`Jordan_algebra#Examples` + - :wikipedia:`Hurwitz's_theorem_(composition_algebras)#Applications_to_Jordan_algebras` + - `<https://math.ucr.edu/home/baez/octonions/octonions.pdf>`_ + """ + def __init__(self, O): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: TestSuite(J).run() # long time + + sage: O = OctonionAlgebra(QQ, 1, -2, 9) + sage: J = JordanAlgebra(O) + sage: TestSuite(J).run() # long time + + sage: R.<x, y> = GF(11)[] + sage: O = OctonionAlgebra(R, 1, x + y, 9) + sage: J = JordanAlgebra(O) + sage: TestSuite(J).run() # long time + + sage: O = OctonionAlgebra(ZZ) + sage: J = JordanAlgebra(O) + Traceback (most recent call last): + ... + ValueError: 2 must be invertible + """ + self._O = O + R = O.base_ring() + + if not R(2).is_unit(): + raise ValueError("2 must be invertible") + self._half = R(2).inverse_of_unit() + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + Onames = list(O.variable_names()) + Onames.extend(Onames[3] + Onames[i] for i in range(3)) + self._repr_poly_ring = PolynomialRing(R, Onames) + + cat = MagmaticAlgebras(R).Unital().FiniteDimensional().WithBasis() + Parent.__init__(self, base=R, category=cat) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: JordanAlgebra(O) + Exceptional Jordan algebra constructed from Octonion algebra + over Rational Field + """ + return "Exceptional Jordan algebra constructed from {}".format(self._O) + + def _element_constructor_(self, x): + r""" + Construct an element of ``self`` from ``s``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: J(2) + [2 0 0] + [0 2 0] + [0 0 2] + sage: J([2, 3, 0, -1, O.basis()[3], 2]) + [ 2 -1 k] + [-1 3 2] + [-k 2 0] + """ + R = self.base_ring() + try: + x = R(x) + zero = self._O.zero() + return self.element_class(self, [x, x, x, zero, zero, zero]) + except (ValueError, TypeError): + pass + x = list(x) + if len(x) != 6: + raise ValueError("invalid data to construct an element") + R = self.base_ring() + for i in range(3): + x[i] = R(x[i]) + x[3+i] = self._O(x[3+i]) + return self.element_class(self, x) + + def _test_multiplication_self_adjoint(self, **options): + r""" + Test that `(XY + YX) / 2` is self-adjoint. + + EXAMPLES:: + + sage: O = OctonionAlgebra(GF(7), 1, 3, 4) + sage: J = JordanAlgebra(O) + sage: J._test_multiplication_self_adjoint() + """ + tester = self._tester(**options) + S = tester.some_elements() + data_pairs = [(0, 0), (1, 1), (2, 2), (0, 1), (0, 2), (1, 2)] + zerO = self._O.zero() + from sage.misc.misc import some_tuples + for x, y in some_tuples(S, 2, tester._max_runs): + SD = x._data + OD = y._data + X = [[SD[0], SD[3], SD[4]], + [SD[3].conjugate(), SD[1], SD[5]], + [SD[4].conjugate(), SD[5].conjugate(), SD[2]]] + Y = [[OD[0], OD[3], OD[4]], + [OD[3].conjugate(), OD[1], OD[5]], + [OD[4].conjugate(), OD[5].conjugate(), OD[2]]] + for r, c in data_pairs: + if r != c: + val = sum(X[r][i] * Y[i][c] + Y[r][i] * X[i][c] for i in range(3)) * self._half + val_opp = sum(X[c][i] * Y[i][r] + Y[c][i] * X[i][r] for i in range(3)) * self._half + tester.assertEqual(val, val_opp.conjugate()) + else: + val = sum(X[r][i] * Y[i][c] + Y[r][i] * X[i][c] for i in range(3)) * self._half + tester.assertEqual(val.imag_part(), zerO) + + @cached_method + def basis(self): + r""" + Return a basis of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: B = J.basis() + sage: B[::6] + ([1 0 0] + [0 0 0] + [0 0 0], + [ 0 k 0] + [-k 0 0] + [ 0 0 0], + [ 0 0 i] + [ 0 0 0] + [-i 0 0], + [ 0 0 lk] + [ 0 0 0] + [-lk 0 0], + [ 0 0 0] + [ 0 0 li] + [ 0 -li 0]) + sage: len(B) + 27 + """ + import itertools + R = self.base_ring() + OB = self._O.basis() + base = [R.zero()] * 3 + [self._O.zero()] * 3 + ret = [] + for i in range(3): + temp = list(base) + temp[i] = R.one() + ret.append(self.element_class(self, temp)) + for i in range(3): + for b in OB: + temp = list(base) + temp[3+i] = b + ret.append(self.element_class(self, temp)) + return Family(ret) + + algebra_generators = basis + + def gens(self): + """ + Return the generators of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: G = J.gens() + sage: G[0] + [1 0 0] + [0 0 0] + [0 0 0] + sage: G[5] + [ 0 j 0] + [-j 0 0] + [ 0 0 0] + sage: G[22] + [ 0 0 0] + [ 0 0 k] + [ 0 -k 0] + """ + return tuple(self.algebra_generators()) + + @cached_method + def zero(self): + r""" + Return the additive identity. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: J.zero() + [0 0 0] + [0 0 0] + [0 0 0] + """ + Rz = self.base_ring().zero() + Oz = self._O.zero() + return self.element_class(self, (Rz, Rz, Rz, Oz, Oz, Oz)) + + @cached_method + def one(self): + r""" + Return multiplicative identity. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: J.one() + [1 0 0] + [0 1 0] + [0 0 1] + sage: all(J.one() * b == b for b in J.basis()) + True + """ + one = self.base_ring().one() + zero = self._O.zero() + return self.element_class(self, (one, one, one, zero, zero, zero)) + + def some_elements(self): + r""" + Return some elements of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: J.some_elements() + [[6/5 0 0] + [ 0 6/5 0] + [ 0 0 6/5], + [1 0 0] + [0 1 0] + [0 0 1], + [0 0 0] + [0 0 0] + [0 0 0], + [0 0 0] + [0 1 0] + [0 0 0], + [ 0 j 0] + [-j 0 0] + [ 0 0 0], + [ 0 0 lj] + [ 0 0 0] + [-lj 0 0], + [ 0 0 0] + [ 0 1 1/2*lj] + [ 0 -1/2*lj 0], + [ 1 0 j + 2*li] + [ 0 1 0] + [-j - 2*li 0 1], + [ 1 j + lk l] + [-j - lk 0 i + lj] + [ -l -i - lj 0], + [ 1 3/2*l 2*k] + [-3/2*l 0 5/2*j] + [ -2*k -5/2*j 0]] + + sage: O = OctonionAlgebra(GF(3)) + sage: J = JordanAlgebra(O) + sage: J.some_elements() + [[-1 0 0] + [ 0 -1 0] + [ 0 0 -1], + [1 0 0] + [0 1 0] + [0 0 1], + [0 0 0] + [0 0 0] + [0 0 0], + [0 0 0] + [0 1 0] + [0 0 0], + [ 0 j 0] + [-j 0 0] + [ 0 0 0], + [ 0 0 lj] + [ 0 0 0] + [-lj 0 0], + [ 0 0 0] + [ 0 1 -lj] + [ 0 lj 0], + [ 1 0 j - li] + [ 0 1 0] + [-j + li 0 1], + [ 1 j + lk l] + [-j - lk 0 i + lj] + [ -l -i - lj 0], + [ 1 0 -k] + [ 0 0 j] + [ k -j 0]] + """ + B = self.basis() + S = [self.an_element(), self.one(), self.zero(), + B[1], B[5], B[17], B[1] + self._half*B[25], + self.one() + B[13] + 2*B[16]] + S.append(sum(B[::5])) + S.append(sum(self._half * ind * b for ind, b in enumerate(B[::7], start=2))) + return S + + class Element(AlgebraElement): + r""" + An element of an exceptional Jordan algebra. + """ + def __init__(self, parent, data): + """ + Initialize ``self``. + + TESTS:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: elt = sum(J.basis()) + sage: TestSuite(elt).run() + """ + self._data = tuple(data) + AlgebraElement.__init__(self, parent) + + def _to_print_matrix(self): + r""" + Return ``self`` as a matrix for printing. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: elt = J([2, 3, 0, -1 + O.basis()[2], O.basis()[3], -O.basis()[5] + 5*O.basis()[7]]) + sage: elt._to_print_matrix() + [ 2 j - 1 k] + [ -j - 1 3 -li + 5*lk] + [ -k li - 5*lk 0] + """ + PR = self.parent()._repr_poly_ring + gens = [PR.one()] + list(PR.gens()) + data = [PR(self._data[i]) for i in range(3)] + data.extend(PR.sum(c * g for c, g in zip(self._data[3+i].vector(), gens)) + for i in range(3)) + # add the conjugates + for i in range(1, 8): + gens[i] = -gens[i] + data.extend(PR.sum(c * g for c, g in zip(self._data[3+i].vector(), gens)) + for i in range(3)) + return matrix(PR, [[data[0], data[3], data[4]], [data[6], data[1], data[5]], [data[7], data[8], data[2]]]) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: J.an_element() + [6/5 0 0] + [ 0 6/5 0] + [ 0 0 6/5] + """ + return repr(self._to_print_matrix()) + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: latex(J.an_element()) + \left(\begin{array}{rrr} + \frac{6}{5} & 0 & 0 \\ + 0 & \frac{6}{5} & 0 \\ + 0 & 0 & \frac{6}{5} + \end{array}\right) + """ + from sage.misc.latex import latex + return latex(self._to_print_matrix()) + + def _ascii_art_(self): + r""" + Return an ascii art representation of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: ascii_art(J.an_element()) + [6/5 0 0] + [ 0 6/5 0] + [ 0 0 6/5] + """ + from sage.typeset.ascii_art import ascii_art + return ascii_art(self._to_print_matrix()) + + def _unicode_art_(self): + r""" + Return a unicode art representation of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: unicode_art(J.an_element()) + โŽ›6/5 0 0โŽž + โŽœ 0 6/5 0โŽŸ + โŽ 0 0 6/5โŽ  + """ + from sage.typeset.unicode_art import unicode_art + return unicode_art(self._to_print_matrix()) + + def __bool__(self) -> bool: + """ + Return if ``self`` is non-zero. + + TESTS:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: all(bool(b) for b in J.basis()) + True + sage: bool(J.zero()) + False + """ + return any(d for d in self._data) + + def _richcmp_(self, other, op): + r""" + Rich comparison of ``self`` with ``other`` by ``op``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: x = sum(J.basis()[::6]) + sage: y = sum(J.basis()[::5]) + sage: x == x + True + sage: x == y + False + sage: x < y + True + sage: x != J.zero() + True + """ + return richcmp(self._data, other._data, op) + + def _add_(self, other): + """ + Add ``self`` and ``other``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: x = sum(J.basis()[::6]) + sage: y = sum(J.basis()[::5]) + sage: x + x + [ 2 2*k 2*i + 2*lk] + [ -2*k 0 2*li] + [-2*i - 2*lk -2*li 0] + sage: x + y + [ 2 j + k + lk i + l + lk] + [ -j - k - lk 0 i + li + lj] + [ -i - l - lk -i - li - lj 0] + """ + return self.__class__(self.parent(), [a + b for a, b in zip(self._data, other._data)]) + + def _neg_(self): + """ + Negate ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: x = sum(J.basis()[::6]) + sage: -x + [ -1 -k -i - lk] + [ k 0 -li] + [ i + lk li 0] + """ + return self.__class__(self.parent(), [-c for c in self._data]) + + def _sub_(self, other): + r""" + Subtract ``other`` from ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: x = sum(J.basis()[::6]) + sage: y = sum(J.basis()[::5]) + sage: x - x + [0 0 0] + [0 0 0] + [0 0 0] + sage: x - y + [ 0 -j + k - lk i - l + lk] + [ j - k + lk 0 -i + li - lj] + [ -i + l - lk i - li + lj 0] + """ + return self.__class__(self.parent(), [a - b for a, b in zip(self._data, other._data)]) + + def _mul_(self, other): + """ + Multiply ``self`` and ``other``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: x = sum(J.basis()[::7]) + sage: y = sum(J.basis()[::11]) + sage: x * y + [ 1 -1/2*j + 1/2*l + 1/2 1/2*k + 1/2*lk + 1/2] + [ 1/2*j - 1/2*l + 1/2 0 -1/2*l] + [-1/2*k - 1/2*lk + 1/2 1/2*l 0] + """ + P = self.parent() + SD = self._data + OD = other._data + X = [[SD[0], SD[3], SD[4]], + [SD[3].conjugate(), SD[1], SD[5]], + [SD[4].conjugate(), SD[5].conjugate(), SD[2]]] + Y = [[OD[0], OD[3], OD[4]], + [OD[3].conjugate(), OD[1], OD[5]], + [OD[4].conjugate(), OD[5].conjugate(), OD[2]]] + # we do a simplified multiplication for the diagonal entries since + # we have, e.g., \alpha * \alpha' + (x (x')^* + x' x^* + y (y')^* + y' y^*) / 2 + ret = [X[0][0] * Y[0][0] + (X[0][1] * Y[1][0]).real_part() + (X[0][2] * Y[2][0]).real_part(), + X[1][1] * Y[1][1] + (X[1][0] * Y[0][1]).real_part() + (X[1][2] * Y[2][1]).real_part(), + X[2][2] * Y[2][2] + (X[2][0] * Y[0][2]).real_part() + (X[2][1] * Y[1][2]).real_part()] + ret += [sum(X[r][i] * Y[i][c] + Y[r][i] * X[i][c] for i in range(3)) * P._half + for r, c in [(0, 1), (0, 2), (1, 2)]] + return self.__class__(P, ret) + + def _lmul_(self, other): + r""" + Multiply ``self`` by the scalar ``other`` on the left. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: elt = sum(2 * b for b in J.basis()[::6]); elt + [ 2 2*k 2*i + 2*lk] + [ -2*k 0 2*li] + [-2*i - 2*lk -2*li 0] + sage: elt * 2 + [ 4 4*k 4*i + 4*lk] + [ -4*k 0 4*li] + [-4*i - 4*lk -4*li 0] + """ + return self.__class__(self.parent(), [c * other for c in self._data]) + + def _rmul_(self, other): + r""" + Multiply ``self`` with the scalar ``other`` by the right + action. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: elt = sum(b * 2 for b in J.basis()[::6]); elt + [ 2 2*k 2*i + 2*lk] + [ -2*k 0 2*li] + [-2*i - 2*lk -2*li 0] + sage: (1/2) * elt + [ 1 k i + lk] + [ -k 0 li] + [-i - lk -li 0] + """ + return self.__class__(self.parent(), [other * c for c in self._data]) + + def monomial_coefficients(self, copy=True): + r""" + Return a dictionary whose keys are indices of basis elements in + the support of ``self`` and whose values are the corresponding + coefficients. + + INPUT: + + - ``copy`` -- ignored + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: elt = sum(~QQ(ind) * b for ind, b in enumerate(J.basis()[::6], start=1)); elt + [ 1 1/2*k 1/3*i + 1/4*lk] + [ -1/2*k 0 1/5*li] + [-1/3*i - 1/4*lk -1/5*li 0] + sage: elt.monomial_coefficients() + {0: 1, 6: 1/2, 12: 1/3, 18: 1/4, 24: 1/5} + + TESTS:: + + sage: O = OctonionAlgebra(QQ) + sage: J = JordanAlgebra(O) + sage: all(b.monomial_coefficients() == {i: 1} for i,b in enumerate(J.basis())) + True + """ + ret = {} + for i in range(3): + if self._data[i]: + ret[i] = self._data[i] + mc = self._data[3+i].monomial_coefficients() + for k, coeff in mc.items(): + ret[3+i*8+k] = coeff + return ret diff --git a/src/sage/algebras/__init__.py b/src/sage/algebras/letterplace/all.py similarity index 100% rename from src/sage/algebras/__init__.py rename to src/sage/algebras/letterplace/all.py diff --git a/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx b/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx index 80ac48b202c..9029a8b07a5 100644 --- a/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx +++ b/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx @@ -17,9 +17,8 @@ AUTHOR: # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.groups.perm_gps.all import CyclicPermutationGroup +from sage.groups.perm_gps.permgroup_named import CyclicPermutationGroup from sage.libs.singular.function import lib, singular_function -from sage.misc.repr import repr_lincomb from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal from cpython.object cimport PyObject_RichCompare @@ -165,7 +164,6 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): """ cdef list L = [] cdef FreeAlgebra_letterplace P = self._parent - cdef int ngens = P.__ngens if P._base._repr_option('element_is_atomic'): for E, c in zip(self._poly.exponents(), self._poly.coefficients()): monstr = P.exponents_to_string(E) @@ -240,7 +238,6 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): """ cdef list L = [] cdef FreeAlgebra_letterplace P = self._parent - cdef int ngens = P.__ngens from sage.misc.latex import latex if P._base._repr_option('element_is_atomic'): for E, c in zip(self._poly.exponents(), self._poly.coefficients()): diff --git a/src/sage/algebras/letterplace/free_algebra_letterplace.pxd b/src/sage/algebras/letterplace/free_algebra_letterplace.pxd index d1d162c3b40..47a7275aba0 100644 --- a/src/sage/algebras/letterplace/free_algebra_letterplace.pxd +++ b/src/sage/algebras/letterplace/free_algebra_letterplace.pxd @@ -20,16 +20,15 @@ cdef class FreeAlgebra_letterplace_libsingular(): cdef ring* _lp_ring cdef MPolynomialRing_libsingular _commutative_ring cdef MPolynomialRing_libsingular _lp_ring_internal - cdef object __ngens + cdef object _ngens cdef class FreeAlgebra_letterplace(Algebra): cdef MPolynomialRing_libsingular _commutative_ring cdef MPolynomialRing_libsingular _current_ring cdef int _degbound - cdef int __ngens + cdef int _ngens cdef int _nb_slackvars cdef object __monoid - cdef public object __custom_name cdef str exponents_to_string(self, E) cdef str exponents_to_latex(self, E) cdef tuple _degrees diff --git a/src/sage/algebras/letterplace/free_algebra_letterplace.pyx b/src/sage/algebras/letterplace/free_algebra_letterplace.pyx index 0e1e47efc11..53f0dfdea6d 100644 --- a/src/sage/algebras/letterplace/free_algebra_letterplace.pyx +++ b/src/sage/algebras/letterplace/free_algebra_letterplace.pyx @@ -115,8 +115,6 @@ TESTS:: algebras with different term orderings, yet. """ - -from sage.misc.misc_c import prod from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.libs.singular.function import lib, singular_function from sage.libs.singular.function cimport RingWrap @@ -178,7 +176,6 @@ cdef MPolynomialRing_libsingular make_letterplace_ring(base_ring, blocks): (Lexicographic term order of length 3, Lexicographic term order of length 3) """ - n = base_ring.ngens() T0 = base_ring.term_order() T = T0 cdef i @@ -258,7 +255,7 @@ cdef class FreeAlgebra_letterplace(Algebra): """ if not isinstance(R, MPolynomialRing_libsingular): raise TypeError("a letterplace algebra must be provided by a polynomial ring of type %s" % MPolynomialRing_libsingular) - self.__ngens = R.ngens() + self._ngens = R.ngens() if degrees is None: varnames = R.variable_names() self._nb_slackvars = 0 @@ -272,12 +269,12 @@ cdef class FreeAlgebra_letterplace(Algebra): self._current_ring = make_letterplace_ring(R, 1) self._degbound = 1 if degrees is None: - self._degrees = tuple([int(1)] * self.__ngens) + self._degrees = tuple([int(1)] * self._ngens) else: if (not isinstance(degrees, (tuple, list))) \ - or len(degrees) != self.__ngens - self._nb_slackvars \ + or len(degrees) != self._ngens - self._nb_slackvars \ or any(i <= 0 for i in degrees): - raise TypeError("the generator degrees must be given by a list or tuple of %d positive integers" % (self.__ngens - 1)) + raise TypeError("the generator degrees must be given by a list or tuple of %d positive integers" % (self._ngens - 1)) self._degrees = tuple([int(i) for i in degrees]) self.set_degbound(max(self._degrees)) self._populate_coercion_lists_(coerce_list=[base_ring]) @@ -308,7 +305,7 @@ cdef class FreeAlgebra_letterplace(Algebra): sage: F.ngens() 3 """ - return self.__ngens - self._nb_slackvars + return self._ngens - self._nb_slackvars def gen(self, i): """ @@ -330,17 +327,17 @@ cdef class FreeAlgebra_letterplace(Algebra): sage: F.gen(2) c """ - if i >= self.__ngens - self._nb_slackvars: - raise ValueError("this free algebra only has %d generators" % (self.__ngens - self._nb_slackvars)) + if i >= self._ngens - self._nb_slackvars: + raise ValueError("this free algebra only has %d generators" % (self._ngens - self._nb_slackvars)) if self._gens is not None: return self._gens[i] deg = self._degrees[i] # self.set_degbound(deg) p = self._current_ring.gen(i) cdef int n - cdef int j = self.__ngens - 1 + cdef int j = self._ngens - 1 for n in range(1, deg): - j += self.__ngens + j += self._ngens p *= self._current_ring.gen(j) return FreeAlgebraElement_letterplace(self, p) @@ -416,7 +413,7 @@ cdef class FreeAlgebra_letterplace(Algebra): sage: FreeAlgebra(QQ, implementation='letterplace', names=['x']).is_commutative() True """ - return self.__ngens - self._nb_slackvars <= 1 + return self._ngens - self._nb_slackvars <= 1 def is_field(self, proof=True): """ @@ -433,7 +430,7 @@ cdef class FreeAlgebra_letterplace(Algebra): sage: F.is_field() False """ - return (not (self.__ngens - self._nb_slackvars)) and self._base.is_field(proof=proof) + return (not (self._ngens - self._nb_slackvars)) and self._base.is_field(proof=proof) def _repr_(self): """ @@ -449,7 +446,7 @@ cdef class FreeAlgebra_letterplace(Algebra): sage: F Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field """ - return "Free Associative Unital Algebra on %d generators %s over %s" % (self.__ngens - self._nb_slackvars, self.gens(), self._base) + return "Free Associative Unital Algebra on %d generators %s over %s" % (self._ngens - self._nb_slackvars, self.gens(), self._base) def _latex_(self): r""" @@ -589,14 +586,14 @@ cdef class FreeAlgebra_letterplace(Algebra): generated free abelian monoid. In principle, this is correct, but it is not implemented, yet.> """ - cdef int ngens = self.__ngens + cdef int ngens = self._ngens cdef int nblocks = len(E) // ngens cdef int i, j, base, exp, var_ind cdef list out = [] cdef list tmp for i from 0<=i<nblocks: base = i*ngens - tmp = [(j,E[base+j]) for j in xrange(ngens) if E[base+j]] + tmp = [(j, E[base+j]) for j in range(ngens) if E[base+j]] if not tmp: continue var_ind, exp = tmp[0] @@ -621,7 +618,7 @@ cdef class FreeAlgebra_letterplace(Algebra): sage: latex(-(a*b*(z+1)-c)^2) # indirect doctest \left(2 z + 1\right) a b a b + \left(z + 1\right) a b c + \left(z + 1\right) c a b - c c """ - cdef int ngens = self.__ngens + cdef int ngens = self._ngens cdef int nblocks = len(E) // ngens cdef int i, j, base, exp, var_ind cdef list out = [] @@ -629,7 +626,7 @@ cdef class FreeAlgebra_letterplace(Algebra): cdef list names = self.latex_variable_names() for i from 0<=i<nblocks: base = i*ngens - tmp = [(j,E[base+j]) for j in xrange(ngens) if E[base+j]] + tmp = [(j, E[base+j]) for j in range(ngens) if E[base+j]] if not tmp: continue var_ind, exp = tmp[0] @@ -681,10 +678,9 @@ cdef class FreeAlgebra_letterplace(Algebra): cdef list out = [] C = self.current_ring() cdef FreeAlgebraElement_letterplace x - ngens = self.__ngens - degbound = self._degbound + ngens = self._ngens cdef list G = [C(x._poly) for x in g] - from sage.groups.perm_gps.all import CyclicPermutationGroup + from sage.groups.perm_gps.permgroup_named import CyclicPermutationGroup CG = CyclicPermutationGroup(C.ngens()) for y in G: out.extend([y] + [y * CG[ngens * (n + 1)] @@ -815,7 +811,7 @@ cdef class FreeAlgebra_letterplace(Algebra): l = len(e) break cdef dict out = {} - self.set_degbound(l // self.__ngens) + self.set_degbound(l // self._ngens) cdef Py_ssize_t n = self._current_ring.ngens() for e, c in D.iteritems(): out[tuple(e) + (0,) * (n - l)] = c @@ -863,7 +859,7 @@ cdef class FreeAlgebra_letterplace(Algebra): (2)*y*y*y + z*z + t*y """ - if isinstance(x, basestring): + if isinstance(x, str): from sage.misc.sage_eval import sage_eval return sage_eval(x, locals=self.gens_dict()) try: @@ -900,7 +896,7 @@ cdef class FreeAlgebra_letterplace_libsingular(): self._commutative_ring = commutative_ring def __init__(self, commutative_ring, degbound): - self.__ngens = commutative_ring.ngens() * degbound + self._ngens = commutative_ring.ngens() * degbound def __dealloc__(self): r""" diff --git a/src/sage/algebras/lie_algebras/affine_lie_algebra.py b/src/sage/algebras/lie_algebras/affine_lie_algebra.py index 90ecf56a5f0..f94866cd1c6 100644 --- a/src/sage/algebras/lie_algebras/affine_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/affine_lie_algebra.py @@ -17,8 +17,9 @@ #***************************************************************************** from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute from sage.structure.element import parent -from sage.categories.lie_algebras import LieAlgebras +from sage.categories.kac_moody_algebras import KacMoodyAlgebras from sage.algebras.lie_algebras.lie_algebra import LieAlgebra, FinitelyGeneratedLieAlgebra from sage.algebras.lie_algebras.lie_algebra_element import UntwistedAffineLieAlgebraElement @@ -27,57 +28,14 @@ from sage.rings.integer_ring import ZZ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Set_generic class AffineLieAlgebra(FinitelyGeneratedLieAlgebra): r""" An (untwisted) affine Lie algebra. - Let `R` be a ring. Given a finite-dimensional simple Lie algebra - `\mathfrak{g}` over `R`, the affine Lie algebra - `\widehat{\mathfrak{g}}^{\prime}` associated to `\mathfrak{g}` is - defined as - - .. MATH:: - - \widehat{\mathfrak{g}}' = \bigl( \mathfrak{g} \otimes - R[t, t^{-1}] \bigr) \oplus R c, - - where `c` is the canonical central element and `R[t, t^{-1}]` is the - Laurent polynomial ring over `R`. The Lie bracket is defined as - - .. MATH:: - - [x \otimes t^m + \lambda c, y \otimes t^n + \mu c] = - [x, y] \otimes t^{m+n} + m \delta_{m,-n} ( x | y ) c, - - where `( x | y )` is the Killing form on `\mathfrak{g}`. - - There is a canonical derivation `d` on `\widehat{\mathfrak{g}}'` - that is defined by - - .. MATH:: - - d(x \otimes t^m + \lambda c) = a \otimes m t^m, - - or equivalently by `d = t \frac{d}{dt}`. - - The affine Kac-Moody algebra `\widehat{\mathfrak{g}}` is formed by - adjoining the derivation `d` such that - - .. MATH:: - - \widehat{\mathfrak{g}} = \bigl( \mathfrak{g} \otimes R[t,t^{-1}] - \bigr) \oplus R c \oplus R d. - - Specifically, the bracket on `\widehat{\mathfrak{g}}` is defined as - - .. MATH:: - - [t^m \otimes x \oplus \lambda c \oplus \mu d, t^n \otimes y \oplus - \lambda_1 c \oplus \mu_1 d] = \bigl( t^{m+n} [x,y] + \mu n t^n \otimes - y - \mu_1 m t^m \otimes x\bigr) \oplus m \delta_{m,-n} (x|y) c . - Note that the derived subalgebra of the Kac-Moody algebra is the affine Lie algebra. @@ -96,44 +54,10 @@ class AffineLieAlgebra(FinitelyGeneratedLieAlgebra): to ``False`` to obtain the affine Lie algebra instead of the affine Kac-Moody algebra. - EXAMPLES: + .. SEEALSO:: - We begin by constructing an affine Kac-Moody algebra of type `G_2^{(1)}` - from the classical Lie algebra of type `G_2`:: - - sage: g = LieAlgebra(QQ, cartan_type=['G',2]) - sage: A = g.affine() - sage: A - Affine Kac-Moody algebra of ['G', 2] in the Chevalley basis - - Next, we construct the generators and perform some computations:: - - sage: A.inject_variables() - Defining e1, e2, f1, f2, h1, h2, e0, f0, c, d - sage: e1.bracket(f1) - (h1)#t^0 - sage: e0.bracket(f0) - (-h1 - 2*h2)#t^0 + 8*c - sage: e0.bracket(f1) - 0 - sage: A[d, f0] - (-E[3*alpha[1] + 2*alpha[2]])#t^-1 - sage: A([[e0, e2], [[[e1, e2], [e0, [e1, e2]]], e1]]) - (-6*E[-3*alpha[1] - alpha[2]])#t^2 - sage: f0.bracket(f1) - 0 - sage: f0.bracket(f2) - (E[3*alpha[1] + alpha[2]])#t^-1 - sage: A[h1+3*h2, A[[[f0, f2], f1], [f1,f2]] + f1] - f1 - (2*E[alpha[1]])#t^-1 - - We can construct its derived subalgebra, the affine Lie algebra - of type `G_2^{(1)}`. In this case, there is no canonical derivation, - so the generator `d` is `0`:: - - sage: D = A.derived_subalgebra() - sage: D.d() - 0 + - :class:`UntwistedAffineLieAlgebra` + - :class:`TwistedAffineLieAlgebra` REFERENCES: @@ -151,13 +75,18 @@ def __classcall_private__(cls, arg0, cartan_type=None, kac_moody=True): EXAMPLES:: - sage: L1 = lie_algebras.Affine(QQ, ['A',4,1]) + sage: L1 = lie_algebras.Affine(QQ, ['A', 4, 1]) sage: cl = lie_algebras.sl(QQ, 5) sage: L2 = lie_algebras.Affine(cl) sage: L1 is L2 True sage: cl.affine() is L1 True + + sage: L1 = LieAlgebra(QQ, cartan_type=['A', 5, 2]) + sage: L2 = lie_algebras.Affine(QQ, ['A', 5, 2]) + sage: L1 is L2 + True """ if isinstance(arg0, LieAlgebra): ct = arg0.cartan_type() @@ -170,25 +99,24 @@ def __classcall_private__(cls, arg0, cartan_type=None, kac_moody=True): cartan_type = CartanType(cartan_type) if not cartan_type.is_affine(): raise ValueError("the Cartan type must be affine") - g = LieAlgebra(arg0, cartan_type=cartan_type.classical()) + if cartan_type.is_untwisted_affine(): + g = LieAlgebra(arg0, cartan_type=cartan_type.classical()) - if not cartan_type.is_untwisted_affine(): - raise NotImplementedError("only currently implemented for untwisted affine types") - return super().__classcall__(cls, g, kac_moody) + if cartan_type.is_untwisted_affine(): + return UntwistedAffineLieAlgebra(g, kac_moody=kac_moody) + return TwistedAffineLieAlgebra(arg0, cartan_type, kac_moody=kac_moody) - def __init__(self, g, kac_moody): + def __init__(self, g, cartan_type, names, kac_moody): """ Initialize ``self``. EXAMPLES:: - sage: asl = lie_algebras.Affine(QQ, ['A',4,1]) + sage: asl = lie_algebras.Affine(QQ, ['D', 4, 1]) sage: TestSuite(asl).run() """ self._g = g - self._cartan_type = g.cartan_type().affine() - R = g.base_ring() - names = list(g.variable_names()) + ['e0', 'f0', 'c'] + self._cartan_type = cartan_type if kac_moody: names += ['d'] @@ -196,30 +124,12 @@ def __init__(self, g, kac_moody): names = tuple(names) self._ordered_indices = names - cat = LieAlgebras(R).WithBasis() + R = g.base_ring() + cat = KacMoodyAlgebras(R).WithBasis() + if not self._cartan_type.is_untwisted_affine(): + cat = cat.Subobjects() FinitelyGeneratedLieAlgebra.__init__(self, R, names, names, category=cat) - def _repr_(self): - r""" - Return a string representation of ``self``. - - EXAMPLES:: - - sage: g = LieAlgebra(QQ, cartan_type=['D',4,1]) - sage: g - Affine Kac-Moody algebra of ['D', 4] in the Chevalley basis - sage: g.derived_subalgebra() - Affine Lie algebra of ['D', 4] in the Chevalley basis - """ - base = "Affine " - rep = repr(self._g) - if self._kac_moody: - old_len = len(rep) - rep = rep.replace("Lie", "Kac-Moody") - if len(rep) == old_len: # We did not replace anything - base += "Kac-Moody " - return base + rep - @cached_method def basis(self): r""" @@ -227,7 +137,7 @@ def basis(self): EXAMPLES:: - sage: g = LieAlgebra(QQ, cartan_type=['D',4,1]) + sage: g = LieAlgebra(QQ, cartan_type=['D', 4, 1]) sage: B = g.basis() sage: al = RootSystem(['D',4]).root_lattice().simple_roots() sage: B[al[1]+al[2]+al[4],4] @@ -240,8 +150,21 @@ def basis(self): c sage: B['d'] d + + sage: g = LieAlgebra(QQ, cartan_type=['D', 4, 2], kac_moody=False) + sage: B = g.basis() + sage: it = iter(B) + sage: [next(it) for _ in range(3)] + [c, (E[alpha[1]])#t^0, (E[alpha[2]])#t^0] + sage: B['c'] + c + sage: B['d'] + 0 """ - K = cartesian_product([self._g.basis().keys(), ZZ]) + if self._cartan_type.is_untwisted_affine(): + K = cartesian_product([self._g.basis().keys(), ZZ]) + else: + K = TwistedAffineIndices(self._cartan_type) from sage.sets.finite_enumerated_set import FiniteEnumeratedSet c = FiniteEnumeratedSet(['c']) if self._kac_moody: @@ -294,24 +217,6 @@ def _coerce_map_from_(self, R): return True return super()._coerce_map_from_(R) - def derived_subalgebra(self): - """ - Return the derived subalgebra of ``self``. - - EXAMPLES:: - - sage: g = LieAlgebra(QQ, cartan_type=['B',3,1]) - sage: g - Affine Kac-Moody algebra of ['B', 3] in the Chevalley basis - sage: D = g.derived_subalgebra(); D - Affine Lie algebra of ['B', 3] in the Chevalley basis - sage: D.derived_subalgebra() == D - True - """ - if self._kac_moody: - return AffineLieAlgebra(self._g, kac_moody=False) - return self - def derived_series(self): """ Return the derived series of ``self``. @@ -446,26 +351,117 @@ def lie_algebra_generators(self): (E[alpha[1]])#t^-1, c, d] + + sage: L = LieAlgebra(QQ, cartan_type=['A',5,2]) + sage: list(L.lie_algebra_generators()) + [(E[alpha[1]])#t^0, + (E[alpha[2]])#t^0, + (E[alpha[3]])#t^0, + (E[-alpha[1]])#t^0, + (E[-alpha[2]])#t^0, + (E[-alpha[3]])#t^0, + (h1)#t^0, + (h2)#t^0, + (h3)#t^0, + (E[-alpha[1] - 2*alpha[2] - alpha[3]])#t^1, + (E[alpha[1] + 2*alpha[2] + alpha[3]])#t^-1, + c, + d] """ zero = self.base_ring().zero() d = {} if self._kac_moody: d['d'] = self.d() d['c'] = self.c() + try: finite_gens = dict(self._g.lie_algebra_generators(True)) except TypeError: finite_gens = dict(self._g.lie_algebra_generators()) - for k,g in finite_gens.items(): + for k, g in finite_gens.items(): d[k] = self.element_class(self, {0: g}, zero, zero) - # e_0 = f_{\theta} t - d['e0'] = self.element_class(self, {1: self._g.highest_root_basis_elt(False)}, - zero, zero) - # f_0 = e_{\theta} t^-1 - d['f0'] = self.element_class(self, {-1: self._g.highest_root_basis_elt(True)}, - zero, zero) + + if self._cartan_type.is_untwisted_affine(): + # e_0 = f_{\theta} t + d['e0'] = self.element_class(self, {1: self._g.highest_root_basis_elt(False)}, + zero, zero) + # f_0 = e_{\theta} t^-1 + d['f0'] = self.element_class(self, {-1: self._g.highest_root_basis_elt(True)}, + zero, zero) + elif self._cartan_type.type() != 'BC': + a = self._cartan_type.a() + Q = self._g._Q + theta = Q._from_dict({i: a[i] for i in Q.index_set()}, remove_zeros=False) + # e_0 = f_{\theta} t + d['e0'] = self.element_class(self, {1: self._g.basis()[-theta]}, + zero, zero) + # f_0 = e_{\theta} t^-1 + d['f0'] = self.element_class(self, {-1: self._g.basis()[theta]}, + zero, zero) + else: + n = self._g.cartan_type().rank() + a = self._cartan_type.a() + Q = self._g._Q + theta = Q._from_dict({i: ZZ(2) for i in Q.index_set()}, remove_zeros=False) + # e_0 = f_{\theta} t + d[f'e{n}'] = self.element_class(self, {1: self._g1.basis()[-theta]}, + zero, zero) + # f_0 = e_{\theta} t^-1 + d[f'f{n}'] = self.element_class(self, {-1: self._g1.basis()[theta]}, + zero, zero) + return Family(self.variable_names(), d.__getitem__) + def e(self, i=None): + """ + Return the generators `e` of ``self``. + + INPUT: + + - ``i`` -- (optional) if specified, return just the + generator `e_i` + + EXAMPLES:: + + sage: g = LieAlgebra(QQ, cartan_type=['B', 3, 1]) + sage: list(g.e()) + [(E[-alpha[1] - 2*alpha[2] - 2*alpha[3]])#t^1, + (E[alpha[1]])#t^0, (E[alpha[2]])#t^0, (E[alpha[3]])#t^0] + sage: g.e(2) + (E[alpha[2]])#t^0 + """ + gens = self.lie_algebra_generators() + if i is None: + I = self._cartan_type.index_set() + d = {j: gens[f'e{j}'] for j in I} + return Family(I, d.__getitem__) + return gens[f'e{i}'] + + def f(self, i=None): + """ + Return the generators `f` of ``self``. + + INPUT: + + - ``i`` -- (optional) if specified, return just the + generator `f_i` + + EXAMPLES:: + + sage: g = LieAlgebra(QQ, cartan_type=['A', 5, 2]) + sage: list(g.f()) + [(E[alpha[1] + 2*alpha[2] + alpha[3]])#t^-1, + (E[-alpha[1]])#t^0, (E[-alpha[2]])#t^0, (E[-alpha[3]])#t^0] + sage: g.f(2) + (E[-alpha[2]])#t^0 + """ + gens = self.lie_algebra_generators() + if i is None: + I = self._cartan_type.index_set() + d = {j: gens[f'f{j}'] for j in I} + return Family(I, d.__getitem__) + return gens[f'f{i}'] + def monomial(self, m): r""" Construct the monomial indexed by ``m``. @@ -493,4 +489,726 @@ def monomial(self, m): zero = self.base_ring().zero() return self.element_class(self, {m[1]: G[m[0]]}, zero, zero) + +class UntwistedAffineLieAlgebra(AffineLieAlgebra): + r""" + An untwisted affine Lie algebra. + + Let `R` be a ring. Given a finite-dimensional simple Lie algebra + `\mathfrak{g}` over `R`, the affine Lie algebra + `\widehat{\mathfrak{g}}^{\prime}` associated to `\mathfrak{g}` is + defined as + + .. MATH:: + + \widehat{\mathfrak{g}}' = \bigl( \mathfrak{g} \otimes + R[t, t^{-1}] \bigr) \oplus R c, + + where `c` is the canonical central element and `R[t, t^{-1}]` is the + Laurent polynomial ring over `R`. The Lie bracket is defined as + + .. MATH:: + + [x \otimes t^m + \lambda c, y \otimes t^n + \mu c] = + [x, y] \otimes t^{m+n} + m \delta_{m,-n} ( x | y ) c, + + where `( x | y )` is the Killing form on `\mathfrak{g}`. + + There is a canonical derivation `d` on `\widehat{\mathfrak{g}}'` + that is defined by + + .. MATH:: + + d(x \otimes t^m + \lambda c) = a \otimes m t^m, + + or equivalently by `d = t \frac{d}{dt}`. + + The affine Kac-Moody algebra `\widehat{\mathfrak{g}}` is formed by + adjoining the derivation `d` such that + + .. MATH:: + + \widehat{\mathfrak{g}} = \bigl( \mathfrak{g} \otimes R[t,t^{-1}] + \bigr) \oplus R c \oplus R d. + + Specifically, the bracket on `\widehat{\mathfrak{g}}` is defined as + + .. MATH:: + + [t^m \otimes x \oplus \lambda c \oplus \mu d, t^n \otimes y \oplus + \lambda_1 c \oplus \mu_1 d] = \bigl( t^{m+n} [x,y] + \mu n t^n \otimes + y - \mu_1 m t^m \otimes x\bigr) \oplus m \delta_{m,-n} (x|y) c . + + EXAMPLES: + + We begin by constructing an affine Kac-Moody algebra of type `G_2^{(1)}` + from the classical Lie algebra of type `G_2`:: + + sage: g = LieAlgebra(QQ, cartan_type=['G',2]) + sage: A = g.affine() + sage: A + Affine Kac-Moody algebra of ['G', 2] in the Chevalley basis + + Next, we construct the generators and perform some computations:: + + sage: A.inject_variables() + Defining e1, e2, f1, f2, h1, h2, e0, f0, c, d + sage: e1.bracket(f1) + (h1)#t^0 + sage: e0.bracket(f0) + (-h1 - 2*h2)#t^0 + 8*c + sage: e0.bracket(f1) + 0 + sage: A[d, f0] + (-E[3*alpha[1] + 2*alpha[2]])#t^-1 + sage: A([[e0, e2], [[[e1, e2], [e0, [e1, e2]]], e1]]) + (-6*E[-3*alpha[1] - alpha[2]])#t^2 + sage: f0.bracket(f1) + 0 + sage: f0.bracket(f2) + (E[3*alpha[1] + alpha[2]])#t^-1 + sage: A[h1+3*h2, A[[[f0, f2], f1], [f1,f2]] + f1] - f1 + (2*E[alpha[1]])#t^-1 + + We can construct its derived subalgebra, the affine Lie algebra + of type `G_2^{(1)}`. In this case, there is no canonical derivation, + so the generator `d` is `0`:: + + sage: D = A.derived_subalgebra() + sage: D.d() + 0 + """ + def __init__(self, g, kac_moody): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: asl = lie_algebras.Affine(QQ, ['A',4,1]) + sage: TestSuite(asl).run() + """ + cartan_type = g.cartan_type().affine() + names = list(g.variable_names()) + ['e0', 'f0', 'c'] + super().__init__(g, cartan_type, names, kac_moody) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: g = LieAlgebra(QQ, cartan_type=['D',4,1]) + sage: g + Affine Kac-Moody algebra of ['D', 4] in the Chevalley basis + sage: g.derived_subalgebra() + Affine Lie algebra of ['D', 4] in the Chevalley basis + """ + base = "Affine " + rep = repr(self._g) + if self._kac_moody: + old_len = len(rep) + rep = rep.replace("Lie", "Kac-Moody") + if len(rep) == old_len: # We did not replace anything + base += "Kac-Moody " + return base + rep + + def derived_subalgebra(self): + """ + Return the derived subalgebra of ``self``. + + EXAMPLES:: + + sage: g = LieAlgebra(QQ, cartan_type=['B',3,1]) + sage: g + Affine Kac-Moody algebra of ['B', 3] in the Chevalley basis + sage: D = g.derived_subalgebra(); D + Affine Lie algebra of ['B', 3] in the Chevalley basis + sage: D.derived_subalgebra() == D + True + """ + if self._kac_moody: + return UntwistedAffineLieAlgebra(self._g, kac_moody=False) + return self + Element = UntwistedAffineLieAlgebraElement + + +class TwistedAffineLieAlgebra(AffineLieAlgebra): + r""" + A twisted affine Lie algebra. + + A twisted affine Lie algebra is an affine Lie algebra for + type `X_N^{(r)}` with `r > 1`. We realize this inside an + untwisted affine Kac--Moody Lie algebra following Chapter 8 + of [Ka1990]_. + + Let `\overline{\mathfrak{g}}` be the classical Lie algebra by + taking the index set `I \setminus \{\epsilon\}`, where + `\epsilon = 0` unless `\epsilon = n` for `X_N^{(r)} = A_{2n}^{(2)}`, + for the twisted affine Lie algebra `\widetilde{\mathfrak{g}}`. + Let `\mathfrak{g}` be the basic Lie algebra of type `X_N`. + We realize `\overline{\mathfrak{g}}` as the fixed-point subalgebra + `\mathfrak{g}^{(0)}` of `\mathfrak{g}` under the order `r` diagram + automorphism `\mu`. This naturally acts on the `\zeta_r` (a primitive + `r`-th root of unity) eigenspace `\mathfrak{g}^{(1)}` of `\mu`, + which is the highest weight representation corresponding to + the small adjoint (where the weight spaces are the short roots + of `\overline{\mathfrak{g}}`). The *twisted affine (Kac-Moody) + Lie algebra* `\widehat{\mathfrak{g}}` is constructed as the + subalgebra of `X_N^{(1)}` given by + + .. MATH:: + + \sum_{i \in \ZZ} \mathfrak{g}^{(i \mod 2)} \otimes t^i + \oplus R c \oplus R d, + + where `R` is the base ring. + + We encode our basis by using the classical Lie algebra except + for type `A_{2n}^{(2)}`. For type `A_{2n}^{(2)}`, the fixed-point + algebra `\mathfrak{g}^{(0)}` is of type `B_n` using the index set + `\{0, \ldots, n-1\}`. For `\mathfrak{g}^{(1)}`, we identify the + weights in this representation with the roots of type `B_n` and + the double all of its short roots. + """ + def __init__(self, R, cartan_type, kac_moody): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: g = lie_algebras.Affine(QQ, ['A', 5, 2]) + sage: TestSuite(g).run() + + sage: g = lie_algebras.Affine(QQ, ['D', 4, 2]) + sage: TestSuite(g).run() + + sage: g = lie_algebras.Affine(QQ, ['D', 5, 2]) + sage: TestSuite(g).run() + + sage: g = lie_algebras.Affine(QQ, ['A', 6, 2]) + sage: TestSuite(g).run() + + sage: g = lie_algebras.Affine(QQ, ['A', 2, 2]) + sage: TestSuite(g).run() + + sage: g = lie_algebras.Affine(QQ, ['E', 6, 2]) + sage: TestSuite(g).run() # long time + + sage: g = lie_algebras.Affine(QQ, ['D', 4, 3]) + sage: TestSuite(g).run() # long time + """ + # basic setup for AffineLieAlgebra + if cartan_type.type() == 'BC': + classical = cartan_type.classical().dual() + n = classical.rank() + classical = classical.relabel({n-i: i for i in range(n)}) + else: + classical = cartan_type.classical() + g = LieAlgebra(R, cartan_type=classical) + n = classical.rank() + names = ['e%s' % i for i in range(1, n+1)] + names.extend('f%s' % i for i in range(1, n+1)) + if cartan_type.type() == 'BC': + names.extend('h%s' % i for i in range(n)) + else: + names.extend('h%s' % i for i in range(1, n+1)) + names += ['e0', 'f0', 'c'] + super().__init__(g, cartan_type, names, kac_moody) + + # setup the ambient simply-laced algebra + basic_ct = cartan_type.basic_untwisted() + if cartan_type.dual().type() == 'B': + ep = [(i, i+1) for i in range(1, n)] + ep.extend((i+1, i) for i in range(n, 2*n-1)) + elif cartan_type.dual().type() == 'F': + ep = [(1, 3), (3, 4), (5, 4), (6, 5), (4, 2)] + elif cartan_type.dual().type() == 'G': + ep = [(1, 2), (3, 2), (4, 2)] + else: + ep = basic_ct.dynkin_diagram().to_undirected().edges(labels=False, sort=False) + + if self._cartan_type.dual().type() == 'G': + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + RP = PolynomialRing(R, 'x') + Rext = RP.quotient(RP.gen(0)**3 - 1) + self._basic = LieAlgebra(Rext, cartan_type=basic_ct, epsilon=ep) + else: + self._basic = LieAlgebra(R, cartan_type=basic_ct, epsilon=ep) + self._ambient = self._basic.affine(kac_moody=self._kac_moody) + + # setup the embeddings + basic_ct = self._basic.cartan_type() + if self._cartan_type.dual().type() == 'G': + gens = basic_ct.dynkin_diagram().automorphism_group().gens() + auto = gens[0] * gens[1] + else: + auto = basic_ct.dynkin_diagram().automorphism_group().gen(0) + basic_Q = basic_ct.root_system().root_lattice() + basic_p_roots = basic_Q.positive_roots() + visited = set() + orbits = [] + for al in basic_p_roots: + if al in visited: + continue + visited.add(al) + O = [al] + cur = basic_Q._from_dict({auto(i): c for i, c in al}, remove_zeros=False) + while cur != al: + O.append(cur) + visited.add(cur) + cur = basic_Q._from_dict({auto(i): c for i, c in cur}, remove_zeros=False) + orbits.append(O) + + finite_ct = self._g.cartan_type() + Q = finite_ct.root_system().root_lattice() + I = finite_ct.index_set() + a = finite_ct.symmetrizer() + ord = auto.order() + + if self._cartan_type.dual().type() == 'F': + # For E_6^(2), we need to take into account the lack of index sets matching + reindex = {2: 4, 4: 3, 3: 2, 1: 1} + + def build_root(O): + return Q._from_dict({reindex[i]: c * (ord // a[reindex[i]]) / len(O) for i, c in sum(O) if i in reindex}, + remove_zeros=False) + elif self._cartan_type.type() == 'BC': + reindex = {n-i: i for i in range(finite_ct.rank())} + + def build_root(O): + return Q._from_dict({reindex[i]: c * (ord // len(O)) for i, c in sum(O) if i in reindex}, + remove_zeros=False) + else: + + def build_root(O): + return Q._from_dict({i: c * (ord // a[i]) / len(O) for i, c in sum(O) if i in I}, + remove_zeros=False) + + self._root_mapping = {build_root(O): O for O in orbits} + for r in list(self._root_mapping.keys()): + self._root_mapping[-r] = [-s for s in self._root_mapping[r]] + if self._cartan_type.type() == 'BC': + assert set(r for r in self._root_mapping if len(self._root_mapping[r]) > 1) == set(Q.roots()) + if self._cartan_type.rank() == 2: + # Special case since sl_2 has only 1 root length + assert set(r / 2 for r in self._root_mapping if len(self._root_mapping[r]) == 1) == set(Q.roots()) + else: + assert set(r / 2 for r in self._root_mapping if len(self._root_mapping[r]) == 1) == set(Q.short_roots()) + from sage.combinat.free_module import CombinatorialFreeModule + X = sorted(self._root_mapping, key=str) + self._g1 = CombinatorialFreeModule(R, X, prefix='E') + else: + assert set(self._root_mapping) == set(Q.roots()) + al = Q.simple_roots() + ac = Q.simple_coroots() + for i in I: + self._root_mapping[ac[i]] = [r.associated_coroot() for r in self._root_mapping[al[i]]] + self._inverse_root_map = {O[0]: r for r, O in self._root_mapping.items()} + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: g = LieAlgebra(QQ, cartan_type=['D', 4, 2]) + sage: g + Twisted affine Kac-Moody algebra of type ['C', 3, 1]^* over Rational Field + sage: g.derived_subalgebra() + Twisted affine Lie algebra of type ['C', 3, 1]^* over Rational Field + """ + rep = "Twisted affine " + rep += "Kac-Moody " if self._kac_moody else "Lie " + rep += f"algebra of type {self._cartan_type} over {self.base_ring()}" + return rep + + def _test_classical_subalgebra(self, **options): + r""" + Test the Chevalley basis properties for the classical subalgebra + of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['A', 5, 2]) + sage: L._test_classical_subalgebra() + sage: L = LieAlgebra(QQ, cartan_type=['D', 4, 2]) + sage: L._test_classical_subalgebra() + """ + tester = self._tester(**options) + B = self.basis() + roots = set(self._g._Q.roots()) + ac = list(self._g._Q.simple_coroots()) + from sage.misc.misc import some_tuples + for r, s in some_tuples(roots, 2, tester._max_runs): + ret = B[r,0].bracket(B[s,0]) + if r + s in roots: + tester.assertEqual(list(ret.support()), [(r+s, 0)], f"obtained [{r}, {s}] == {ret}") + elif r == -s: + supp = set((ac, 0) for ac in r.associated_coroot().monomials()) + tester.assertEqual(set(ret.support()), supp, f"obtained [{r}, {s}] == {ret}") + else: + tester.assertEqual(ret, self.zero(), f"nonzero for [{r}, {s}]") + + def derived_subalgebra(self): + r""" + Return the derived subalgebra of ``self``. + + EXAMPLES:: + + sage: g = LieAlgebra(QQ, cartan_type=['A', 5, 2]) + sage: g + Twisted affine Kac-Moody algebra of type ['B', 3, 1]^* over Rational Field + sage: D = g.derived_subalgebra(); D + Twisted affine Lie algebra of type ['B', 3, 1]^* over Rational Field + sage: D.derived_subalgebra() == D + True + """ + if self._kac_moody: + return TwistedAffineLieAlgebra(self.base_ring(), self._cartan_type, kac_moody=False) + return self + + def ambient(self): + r""" + Return the ambient untwisted affine Lie algebra of ``self``. + + EXAMPLES:: + + sage: g = LieAlgebra(QQ, cartan_type=['A', 5, 2]) + sage: g.ambient() + Affine Kac-Moody algebra of ['A', 5] in the Chevalley basis + """ + return self._ambient + + def retract(self, x): + r""" + Retract the element ``x`` from the ambient untwisted affine Lie + algebra into ``self``. + + EXAMPLES:: + + sage: g = LieAlgebra(QQ, cartan_type=['A', 5, 2]) + sage: it = iter(g.basis()) + sage: elts = [next(it) for _ in range(20)] + sage: elts + [c, + d, + (E[alpha[1]])#t^0, + (E[alpha[2]])#t^0, + (E[alpha[3]])#t^0, + (E[alpha[1] + alpha[2]])#t^0, + (E[alpha[2] + alpha[3]])#t^0, + (E[2*alpha[2] + alpha[3]])#t^0, + (E[alpha[1] + alpha[2] + alpha[3]])#t^0, + (E[2*alpha[1] + 2*alpha[2] + alpha[3]])#t^0, + (E[alpha[1] + 2*alpha[2] + alpha[3]])#t^0, + (E[-alpha[1]])#t^0, + (E[-alpha[2]])#t^0, + (E[-alpha[3]])#t^0, + (E[-alpha[1] - alpha[2]])#t^0, + (E[-alpha[2] - alpha[3]])#t^0, + (E[-2*alpha[2] - alpha[3]])#t^0, + (E[-alpha[1] - alpha[2] - alpha[3]])#t^0, + (E[-2*alpha[1] - 2*alpha[2] - alpha[3]])#t^0, + (E[-alpha[1] - 2*alpha[2] - alpha[3]])#t^0] + sage: all(g.retract(g.to_ambient(x)) == x for x in elts) + True + """ + t_dict = x.t_dict() + c_coeff = x.c_coefficient() + d_coeff = x.d_coefficient() + if self._cartan_type.dual().type() == 'G': + R = self.base_ring() + for i in t_dict: + t_dict[i] = self._g._from_dict({self._inverse_root_map[r]: R(c.lift()) + for r, c in t_dict[i] if r in self._inverse_root_map}, + remove_zeros=False) + elif self._cartan_type.type() == 'BC': + for i in t_dict: + if i % 2: + t_dict[i] = self._g1._from_dict({self._inverse_root_map[r]: c for r, c in t_dict[i] + if r in self._inverse_root_map}, + remove_zeros=False) + else: + t_dict[i] = self._g._from_dict({self._inverse_root_map[r]: c for r, c in t_dict[i] + if r in self._inverse_root_map}, + remove_zeros=False) + else: + for i in t_dict: + t_dict[i] = self._g._from_dict({self._inverse_root_map[r]: c for r, c in t_dict[i] + if r in self._inverse_root_map}, + remove_zeros=False) + return self.element_class(self, t_dict, c_coeff, d_coeff) + + @lazy_attribute + def to_ambient(self): + r""" + Lift the element ``x`` from the ambient untwisted affine Lie + algebra into ``self``. + + EXAMPLES:: + + sage: g = LieAlgebra(QQ, cartan_type=['A', 5, 2]) + sage: g.to_ambient + Generic morphism: + From: Twisted affine Kac-Moody algebra of type ['B', 3, 1]^* over Rational Field + To: Affine Kac-Moody algebra of ['A', 5] in the Chevalley basis + """ + one = self.base_ring().one() + + if self._cartan_type.type() == 'BC': + mone = -one + + def basis_map(r): + O = self._root_mapping[r] + return self._basic._from_dict({O[0]: one, O[1]: mone**(1+O[1].height())}, + remove_zeros=False) + else: + + def basis_map(r): + return self._basic._from_dict({s: one for s in self._root_mapping[r]}, remove_zeros=False) + + if self._cartan_type.dual().type() == 'G': + zeta3 = self._basic.base_ring().gen() + + def basis_alt(r): + return self._basic._from_dict({s: zeta3**ind for ind, s in enumerate(self._root_mapping[r])}, + remove_zeros=False) + elif self._cartan_type.type() == 'BC': + + def basis_alt(r): + O = self._root_mapping[r] + if len(O) == 1: + return self._basic.monomial(O[0]) + return self._basic._from_dict({O[0]: one, O[1]: mone**O[1].height()}, + remove_zeros=False) + else: + mone = -one + + def basis_alt(r): + return self._basic._from_dict({s: mone**ind for ind, s in enumerate(self._root_mapping[r])}, + remove_zeros=False) + + def lift_map(elt): + t_dict = elt.t_dict() + c_coeff = elt.c_coefficient() + d_coeff = elt.d_coefficient() + for i in t_dict: + if i % 2: + t_dict[i] = self._basic.linear_combination((basis_alt(r), c) + for r, c in t_dict[i]) + else: + t_dict[i] = self._basic.linear_combination((basis_map(r), c) + for r, c in t_dict[i]) + return self._ambient.element_class(self._ambient, t_dict, c_coeff, d_coeff) + + return self.module_morphism(function=lift_map, codomain=self._ambient) + + class Element(UntwistedAffineLieAlgebraElement): + def _bracket_(self, y): + r""" + Return the Lie bracket ``[self, y]``. + + EXAMPLES:: + + sage: g = LieAlgebra(QQ, cartan_type=['D', 5, 2]) + sage: e0, e1, e2, e3, e4 = g.e() + sage: f0, f1, f2, f3, f4 = g.f() + sage: B = g.basis() + sage: Q = g.classical().cartan_type().root_system().root_lattice() + sage: h1, h2, h3, h4 = [B[ac, 0] for ac in Q.simple_coroots()] + sage: e1._bracket_(e2) + (-E[alpha[1] + alpha[2]])#t^0 + sage: e1._bracket_(e3) + 0 + sage: e0._bracket_(e1) + (-E[-alpha[2] - alpha[3] - alpha[4]])#t^1 + sage: e0._bracket_(e2) + 0 + sage: f1._bracket_(f2) + (E[-alpha[1] - alpha[2]])#t^0 + sage: f1._bracket_(f3) + 0 + sage: f0._bracket_(f1) + (E[alpha[2] + alpha[3] + alpha[4]])#t^-1 + sage: f0._bracket_(f2) + 0 + sage: g[f0, e0] + (2*h1 + 2*h2 + 2*h3 + h4)#t^0 + -32*c + sage: g([f1, [e1, e2]]) + (E[alpha[2]])#t^0 + sage: g[h1, e0] + (-E[-alpha[1] - alpha[2] - alpha[3] - alpha[4]])#t^1 + sage: g[h2, f0] + 0 + """ + P = parent(self) + ax = P.to_ambient(self) + ay = P.to_ambient(y) + return P.retract(ax.bracket(ay)) + + +class TwistedAffineIndices(UniqueRepresentation, Set_generic): + r""" + The indices for the basis of a twisted affine Lie algebra. + + INPUT: + + - ``cartan_type`` -- the Cartan type of twisted affine type Lie algebra + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.affine_lie_algebra import TwistedAffineIndices + sage: I = TwistedAffineIndices(['A', 3, 2]) + sage: it = iter(I) + sage: [next(it) for _ in range(20)] + [(alpha[1], 0), (alpha[2], 0), (alpha[1] + alpha[2], 0), + (2*alpha[1] + alpha[2], 0), (-alpha[1], 0), (-alpha[2], 0), + (-alpha[1] - alpha[2], 0), (-2*alpha[1] - alpha[2], 0), + (alphacheck[1], 0), (alphacheck[2], 0), (alpha[1], 1), + (alpha[1] + alpha[2], 1), (-alpha[1], 1), (-alpha[1] - alpha[2], 1), + (alphacheck[1], 1), (alpha[1], -1), (alpha[1] + alpha[2], -1), + (-alpha[1], -1), (-alpha[1] - alpha[2], -1), (alphacheck[1], -1)] + + sage: I = TwistedAffineIndices(['A', 4, 2]) + sage: it = iter(I) + sage: [next(it) for _ in range(20)] + [(alpha[0], 0), (alpha[1], 0), (alpha[0] + alpha[1], 0), + (2*alpha[0] + alpha[1], 0), (-alpha[0], 0), (-alpha[1], 0), + (-alpha[0] - alpha[1], 0), (-2*alpha[0] - alpha[1], 0), + (alphacheck[0], 0), (alphacheck[1], 0), (alpha[0], 1), (alpha[1], 1), + (alpha[0] + alpha[1], 1), (2*alpha[0] + alpha[1], 1), (-alpha[0], 1), + (-alpha[1], 1), (-alpha[0] - alpha[1], 1), (-2*alpha[0] - alpha[1], 1), + (2*alpha[0], 1), (2*alpha[0] + 2*alpha[1], 1)] + + sage: I = TwistedAffineIndices(['A', 2, 2]) + sage: it = iter(I) + sage: [next(it) for _ in range(10)] + [(alpha[0], 0), (-alpha[0], 0), (alphacheck[0], 0), (alpha[0], 1), + (-alpha[0], 1), (2*alpha[0], 1), (-2*alpha[0], 1), + (alphacheck[0], 1), (alpha[0], -1), (-alpha[0], -1)] + """ + @staticmethod + def __classcall_private__(cls, cartan_type): + """ + Normalize input to ensure a unique representation. + + sage: from sage.algebras.lie_algebras.affine_lie_algebra import TwistedAffineIndices + sage: I1 = TwistedAffineIndices(CartanType(['C', 4, 1]).dual()) + sage: I2 = TwistedAffineIndices(['D', 5, 2]) + sage: I1 is I2 + True + sage: I = TwistedAffineIndices(['C', 4, 1]) + Traceback (most recent call last): + ... + ValueError: the Cartan type must be a twisted affine type + """ + cartan_type = CartanType(cartan_type) + if not cartan_type.is_affine() or cartan_type.is_untwisted_affine(): + raise ValueError("the Cartan type must be a twisted affine type") + return super().__classcall__(cls, cartan_type) + + def __init__(self, cartan_type): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.affine_lie_algebra import TwistedAffineIndices + sage: I = TwistedAffineIndices(['D', 4, 2]) + sage: TestSuite(I).run() + """ + self._cartan_type = cartan_type + if cartan_type.type() == 'BC': + finite_ct = cartan_type.classical().dual() + n = finite_ct.rank() + Q = finite_ct.relabel({n-i: i for i in range(n)}).root_system().root_lattice() + self._roots = tuple(Q.roots()) + self._ac = tuple(Q.simple_coroots()) + CP = cartesian_product([range(3)] * n) + if cartan_type.rank() == 2: + self._short_roots = self._roots + tuple(2*r for r in Q.roots()) + else: + self._short_roots = self._roots + tuple(2*r for r in Q.short_roots()) + self._short_roots += self._ac + facade = cartesian_product([self._short_roots, ZZ]) + else: + Q = cartan_type.classical().root_system().root_lattice() + self._roots = tuple(Q.roots()) + self._ac = tuple(Q.simple_coroots()) + self._short_roots = tuple(Q.short_roots()) + ac = Q.simple_coroots() + self._short_roots += tuple([ac[i] for i in Q.index_set() if Q.simple_root(i).is_short_root()]) + facade = cartesian_product([self._roots + self._ac, ZZ]) + from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets + super().__init__(facade=facade, category=InfiniteEnumeratedSets()) + + def __contains__(self, x): + """ + Return if ``x`` is contained in ``self``. + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.affine_lie_algebra import TwistedAffineIndices + sage: I = TwistedAffineIndices(['D', 4, 2]) + sage: Q = RootSystem(['B', 3]).root_lattice() + sage: all((r, 4) in I for r in Q.roots()) + True + sage: all((r, 3) in I for r in Q.short_roots()) + True + sage: all((r, 3) not in I for r in Q.long_roots()) + True + sage: list(I.an_element()) in I # lists are not included + False + sage: (5, Q) in I + False + sage: (5, 5) in I + False + sage: (Q.simple_root(1), Q.simple_root(1)) in I + False + sage: (Q.simple_coroot(2), 1) in I + False + sage: (Q.simple_coroot(3), 1) in I + True + """ + if x not in self._facade_for[0]: + return False + x = self._facade_for[0](x) + # self._short_roots also contains the corresponding coroots + return (x[1] % 2 == 0) or x[0] in self._short_roots + + def __iter__(self): + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.affine_lie_algebra import TwistedAffineIndices + sage: I = TwistedAffineIndices(['D', 3, 2]) + sage: it = iter(I) + sage: [next(it) for _ in range(22)] + [(alpha[1], 0), (alpha[2], 0), (alpha[1] + 2*alpha[2], 0), (alpha[1] + alpha[2], 0), + (-alpha[1], 0), (-alpha[2], 0), (-alpha[1] - 2*alpha[2], 0), (-alpha[1] - alpha[2], 0), + (alphacheck[1], 0), (alphacheck[2], 0), (alpha[2], 1), (alpha[1] + alpha[2], 1), + (-alpha[2], 1), (-alpha[1] - alpha[2], 1), (alphacheck[2], 1), (alpha[2], -1), + (alpha[1] + alpha[2], -1), (-alpha[2], -1), (-alpha[1] - alpha[2], -1), + (alphacheck[2], -1), (alpha[1], 2), (alpha[2], 2)] + """ + if self._cartan_type.type() == 'BC': + finite_ct = self._cartan_type.classical().dual() + n = finite_ct.rank() + finite_ct = finite_ct.relabel({n-i: i for i in range(n)}) + else: + finite_ct = self._cartan_type.classical() + Q = finite_ct.root_system().root_lattice() + P = self._facade_for[0] + for i in ZZ: + if i % 2: + # self._short_roots also contains the corresponding coroots + for r in self._short_roots: + yield P((r, i)) + else: + for r in self._roots: + yield P((r, i)) + for r in self._ac: + yield P((r, i)) diff --git a/src/sage/algebras/lie_algebras/bch.py b/src/sage/algebras/lie_algebras/bch.py index 1cb3f0442cb..657b8c194a1 100644 --- a/src/sage/algebras/lie_algebras/bch.py +++ b/src/sage/algebras/lie_algebras/bch.py @@ -20,7 +20,7 @@ from sage.arith.misc import bernoulli from sage.categories.lie_algebras import LieAlgebras from sage.combinat.integer_vector import IntegerListsLex -from sage.arith.all import factorial +from sage.arith.misc import factorial from sage.rings.rational_field import QQ from sage.structure.element import canonical_coercion diff --git a/src/sage/algebras/lie_algebras/classical_lie_algebra.py b/src/sage/algebras/lie_algebras/classical_lie_algebra.py index 39f7be6c856..a2bb531abe0 100644 --- a/src/sage/algebras/lie_algebras/classical_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/classical_lie_algebra.py @@ -147,9 +147,10 @@ def __init__(self, R, ct, e, f, h, sparse=True): 2 """ n = len(e) - names = ['e%s'%i for i in range(1, n+1)] - names += ['f%s'%i for i in range(1, n+1)] - names += ['h%s'%i for i in range(1, n+1)] + I = ct.index_set() + names = ['e%s' % i for i in I] + names += ['f%s' % i for i in I] + names += ['h%s' % i for i in I] category = LieAlgebras(R).FiniteDimensional().WithBasis() from sage.sets.finite_enumerated_set import FiniteEnumeratedSet index_set = FiniteEnumeratedSet(names) @@ -162,10 +163,9 @@ def __init__(self, R, ct, e, f, h, sparse=True): self._sparse = sparse gens = tuple(self.gens()) - i_set = ct.index_set() - self._e = Family(dict( (i, gens[c]) for c,i in enumerate(i_set) )) - self._f = Family(dict( (i, gens[n+c]) for c,i in enumerate(i_set) )) - self._h = Family(dict( (i, gens[2*n+c]) for c,i in enumerate(i_set) )) + self._e = Family({i: gens[c] for c, i in enumerate(I)}) + self._f = Family({i: gens[n+c] for c, i in enumerate(I)}) + self._h = Family({i: gens[2*n+c] for c, i in enumerate(I)}) def e(self, i): r""" @@ -345,7 +345,7 @@ def set_row(mat, row, val): def build_assoc(row): ret = {} for i, v in row.dict().items(): - ret[i//m, i%m] = v + ret[i//m, i % m] = v return self._assoc(ret) while added: @@ -392,7 +392,7 @@ def build_assoc(row): for i in range(cur_mat.rank())] return Family(basis) - def affine(self, kac_moody=False): + def affine(self, kac_moody=True): """ Return the affine (Kac-Moody) Lie algebra of ``self``. @@ -403,9 +403,11 @@ def affine(self, kac_moody=False): Special orthogonal Lie algebra of rank 5 over Rational Field sage: so5.affine() Affine Special orthogonal Kac-Moody algebra of rank 5 over Rational Field + sage: so5.affine(False) + Affine Special orthogonal Lie algebra of rank 5 over Rational Field """ from sage.algebras.lie_algebras.affine_lie_algebra import AffineLieAlgebra - return AffineLieAlgebra(self, kac_moody) + return AffineLieAlgebra(self, kac_moody=kac_moody) class gl(MatrixLieAlgebraFromAssociative): @@ -629,9 +631,34 @@ class so(ClassicalMatrixLieAlgebra): r""" The matrix Lie algebra `\mathfrak{so}_n`. - The Lie algebra `\mathfrak{so}_n`, which consists of all real - anti-symmetric `n \times n` matrices. This is the Lie algebra of - type `B_{(n-1)/2}` or `D_{n/2}` if `n` is odd or even respectively. + The Lie algebra `\mathfrak{so}_n`, which is isomorphic to the + Lie algebra of all anti-symmetric `n \times n` matrices. + The implementation here uses a different bilinear form and follows + the description in Chapter 8 of [HK2002]_. More precisely, this + is the set of matrices: + + .. MATH:: + + \begin{pmatrix} + A & B \\ + C & D + \end{pmatrix} + + such that `A^t = -D`, `B^t = -B`, `C^t = -C` for `n` even and + + .. MATH:: + + \begin{pmatrix} + A & B & a \\ + C & D & b \\ + c & d & 0 + \end{pmatrix} + + such that `A^t = -D`, `B^t = -B`, `C^t = -C`, `a^t = -d`, + and `b^t = -c` for `n` odd. + + This is the Lie algebra of type `B_{(n-1)/2}` or `D_{n/2}` if `n` + is odd or even respectively. """ def __init__(self, R, n): """ @@ -647,25 +674,26 @@ def __init__(self, R, n): MS = MatrixSpace(R, n) one = R.one() self._n = n - if n % 2 == 0: # Even - m = n / 2 - 1 # -1 for indexing + if n % 2 == 0: # Even + m = n // 2 - 1 # -1 for indexing n -= 1 - e = [MS({(m-1,n):one, (m,n-1):-one})] - f = [MS({(n,m-1):one, (n-1,m):-one})] - h = [MS({(m-1,m-1):one, (m,m):one, (n-1,n-1):-one, (n,n):-one})] + e = [MS({(m-1, n): one, (m, n-1): -one})] + f = [MS({(n, m-1): one, (n-1, m): -one})] + h = [MS({(m-1, m-1): one, (m, m): one, (n-1, n-1): -one, (n, n): -one})] m += 1 ct = CartanType(['D', m]) - else: # Odd - m = (n-1) / 2 - 1 # -1 for indexing + else: # Odd + m = (n-1) // 2 - 1 # -1 for indexing n -= 1 - e = [MS({(m,n):2, (n,n-1):-2})] - f = [MS({(n,m):one, (n-1,n):-one})] - h = [MS({(m,m):2, (n-1,n-1):-2})] + e = [MS({(m, n): 2, (n, n-1): -2})] + f = [MS({(n, m): one, (n-1, n): -one})] + h = [MS({(m, m): 2, (n-1, n-1): -2})] m += 1 ct = CartanType(['B', m]) - e = [MS({(i,i+1):one, (m+i+1,m+i):-one}) for i in range(m-1)] + e - f = [MS({(i+1,i):one, (m+i,m+i+1):-one}) for i in range(m-1)] + f - h = [MS({(i,i):one, (i+1,i+1):-one, (m+i,m+i):-one, (m+i+1,m+i+1):one}) for i in range(m-1)] + h + e = [MS({(i, i+1): one, (m+i+1, m+i): -one}) for i in range(m-1)] + e + f = [MS({(i+1, i): one, (m+i, m+i+1): -one}) for i in range(m-1)] + f + h = [MS({(i, i): one, (i+1, i+1): -one, (m+i, m+i): -one, (m+i+1, m+i+1): one}) + for i in range(m-1)] + h ClassicalMatrixLieAlgebra.__init__(self, R, ct, e, f, h) def _repr_(self): @@ -735,10 +763,10 @@ def simple_root(self, i, h): i = self.index_set().index(i) if i == len(self.index_set()) - 1: if self._n % 2 == 0: - return h[i-1,i-1] + h[i,i] + return h[i-1, i-1] + h[i, i] # otherwise we are odd - return h[i,i] - return h[i,i] - h[i+1,i+1] + return h[i, i] + return h[i, i] - h[i+1, i+1] class sp(ClassicalMatrixLieAlgebra): r""" @@ -938,8 +966,8 @@ def __init__(self, R): TESTS:: - sage: g = LieAlgebra(QQ, cartan_type=['E', 8], representation='matrix') - sage: g + sage: g = LieAlgebra(QQ, cartan_type=['E', 8], representation='matrix') # long time + sage: g # long time Simple matrix Lie algebra of type ['E', 8] over Rational Field We skip the not implemented methods test as it takes too much time:: @@ -959,7 +987,7 @@ def basis(self): EXAMPLES:: - sage: g = LieAlgebra(QQ, cartan_type=['E', 8], representation='matrix') + sage: g = LieAlgebra(QQ, cartan_type=['E', 8], representation='matrix') # long time sage: len(g.basis()) # long time 248 """ @@ -1096,7 +1124,7 @@ def __init__(self, R, cartan_type): dim = self._classical.dimension() from sage.sets.finite_enumerated_set import FiniteEnumeratedSet index_set = FiniteEnumeratedSet(range(dim)) - names = tuple(['CR%s'%s for s in range(dim)]) + names = tuple(['CR%s' % s for s in range(dim)]) category = LieAlgebras(R).FiniteDimensional().WithBasis() FinitelyGeneratedLieAlgebra.__init__(self, R, names=names, index_set=index_set, @@ -1535,22 +1563,27 @@ class LieAlgebraChevalleyBasis(LieAlgebraWithStructureCoefficients): .. MATH:: \begin{aligned} - [h_i, h_j] & = 0 - \\ [h_i, e_{\beta}] & = A_{\alpha_i, \beta} e_{\beta} - \\ [e_{\beta}, e_{-\beta}] & = \sum_i A_{\beta, \alpha_i} h_i + [h_i, h_j] & = 0, + \\ [h_i, e_{\beta}] & = A_{\alpha_i, \beta} e_{\beta}, + \\ [e_{\beta}, e_{-\beta}] & = \sum_i A_{\beta, \alpha_i} h_i, \\ [e_{\beta}, e_{\gamma}] & = \begin{cases} - N_{\beta,\gamma} e_{\beta + \gamma} & \beta + \gamma \in \Phi \\ - 0 & \text{otherwise.} \end{cases} + N_{\beta,\gamma} e_{\beta + \gamma} & \beta + \gamma \in \Phi, \\ + 0 & \text{otherwise,} \end{cases} \end{aligned} - where `A_{\alpha, \beta} = \frac{2 (\alpha, \beta)}{(\alpha, \alpha)}` and - `N_{\alpha, \beta}` is the maximum such that + where `A_{\alpha, \beta} = \frac{2 (\alpha, \beta)}{(\alpha, \alpha)}` + and `N_{\alpha, \beta}` is the maximum such that `\alpha - N_{\alpha, \beta} \beta \in \Phi`. For computing the signs of the coefficients, see Section 3 of [CMT2003]_. + + .. SEEALSO:: + + For simply-laced types, an alternative construction using an asymmetry + function is given by :class:`LieAlgebraChevalleyBasis_simply_laced`. """ @staticmethod - def __classcall_private__(cls, R, cartan_type): + def __classcall_private__(cls, R, cartan_type, epsilon=None): """ Normalize ``self`` to ensure a unique representation. @@ -1561,11 +1594,50 @@ def __classcall_private__(cls, R, cartan_type): sage: L3 = LieAlgebra(QQ, cartan_type=CartanMatrix(['A', 2])) sage: L1 is L2 and L2 is L3 True + + + sage: L = LieAlgebra(QQ, cartan_type=['A', 2], epsilon=[(1,2)]) + sage: type(L) + <class '...LieAlgebraChevalleyBasis_simply_laced_with_category'> + sage: L = LieAlgebra(QQ, cartan_type=['A', 1], epsilon=[]) + sage: type(L) + <class '...LieAlgebraChevalleyBasis_simply_laced_with_category'> + + sage: L = LieAlgebra(QQ, cartan_type=['A', 2], epsilon=[(2,3)]) + Traceback (most recent call last): + ... + ValueError: not a valid Dynkin orientation + sage: L = LieAlgebra(QQ, cartan_type=['A', 2], epsilon=[(1,2), (2,1)]) + Traceback (most recent call last): + ... + ValueError: not a valid Dynkin orientation + sage: L = LieAlgebra(QQ, cartan_type=['A', 2], epsilon=[(1,2), (1,1)]) + Traceback (most recent call last): + ... + ValueError: not a valid Dynkin orientation + sage: L = LieAlgebra(QQ, cartan_type=['A', 1], epsilon=[(1,1)]) + Traceback (most recent call last): + ... + ValueError: not a valid Dynkin orientation """ if isinstance(cartan_type, (CartanMatrix, DynkinDiagram_class)): cartan_type = cartan_type.cartan_type() else: cartan_type = CartanType(cartan_type) + if epsilon is not None: + if not cartan_type.is_simply_laced(): + raise ValueError("the Cartan type must be simply-laced with an asymmetry function") + epsilon = frozenset([tuple(p) for p in epsilon]) + if cartan_type.rank() == 1: + if epsilon: + raise ValueError("not a valid Dynkin orientation") + else: + from sage.graphs.graph import Graph + G = Graph(epsilon, multiedges=True, loops=True, format="list_of_edges") + if (G.has_multiple_edges() or G.has_loops() + or cartan_type.dynkin_diagram().to_undirected() != G.to_simple()): + raise ValueError("not a valid Dynkin orientation") + return LieAlgebraChevalleyBasis_simply_laced(R, cartan_type, epsilon) return super().__classcall__(cls, R, cartan_type) def __init__(self, R, cartan_type): @@ -1579,14 +1651,52 @@ def __init__(self, R, cartan_type): """ self._cartan_type = cartan_type self._Q = cartan_type.root_system().root_lattice() - alpha = self._Q.simple_roots() p_roots = list(self._Q.positive_roots_by_height()) n_roots = [-x for x in p_roots] self._p_roots_index = OrderedDict((al, i) for i, al in enumerate(p_roots)) + + alphacheck = self._Q.simple_coroots() + # We pass p_roots and n_roots so we don't have to reconstruct them + s_coeffs = self._construct_struct_coeffs(R, p_roots) + + # Make sure a < b for all (a, b) in the coefficients and flip if necessary + for k in list(s_coeffs): + a, b = k + if self._basis_key(a) > self._basis_key(b): + s_coeffs[(b, a)] = [(index, -v) for index, v in s_coeffs[k].items()] + del s_coeffs[k] + else: + s_coeffs[k] = s_coeffs[k].items() + + I = self._cartan_type.index_set() + names = ['e{}'.format(i) for i in I] + names += ['f{}'.format(i) for i in I] + names += ['h{}'.format(i) for i in I] + category = TriangularKacMoodyAlgebras(R).FiniteDimensional() + index_set = p_roots + list(alphacheck) + n_roots + self._cartan_indices = range(len(p_roots), len(p_roots) + len(alphacheck)) + names = tuple(names) + from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + index_set = FiniteEnumeratedSet(index_set) + LieAlgebraWithStructureCoefficients.__init__(self, R, s_coeffs, names, index_set, + category, prefix='E', bracket='[', + sorting_key=self._basis_key) + + def _construct_struct_coeffs(self, R, p_roots): + """ + Construct the structure coefficients of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['A',1], epsilon=[]) + sage: sorted(L._construct_struct_coeffs(QQ, list(L._Q.positive_roots())).items(), key=str) + [((alpha[1], -alpha[1]), {alphacheck[1]: 1}), + ((alpha[1], alphacheck[1]), {alpha[1]: -2}), + ((alphacheck[1], -alpha[1]), {-alpha[1]: -2})] + """ alphacheck = self._Q.simple_coroots() roots = frozenset(self._Q.roots()) - num_sroots = len(alpha) one = R.one() # Determine the signs for the structure coefficients from the root system @@ -1652,8 +1762,8 @@ def e_coeff(r, s): # [e_r, e_s] and [e_r, f_s] with r != +/-s # We assume s is positive, as otherwise we negate # both r and s and the resulting coefficient - for j, s in enumerate(p_roots[i+1:]): - j += i+1 # Offset + for j, s in enumerate(p_roots[i+1:], start=i+1): + #j += i + 1 # Offset # Since h(s) >= h(r), we have s - r > 0 when s - r is a root # [f_r, e_s] if s - r in p_roots: @@ -1674,26 +1784,7 @@ def e_coeff(r, s): s_coeffs[(r, s)] = {a: c} s_coeffs[(-r, -s)] = {-a: -c} - # Lastly, make sure a < b for all (a, b) in the coefficients and flip if necessary - for k in list(s_coeffs): - a, b = k[0], k[1] - if self._basis_key(a) > self._basis_key(b): - s_coeffs[(b, a)] = [(index, -v) for index, v in s_coeffs[k].items()] - del s_coeffs[k] - else: - s_coeffs[k] = s_coeffs[k].items() - - names = ['e{}'.format(i) for i in range(1, num_sroots+1)] - names += ['f{}'.format(i) for i in range(1, num_sroots+1)] - names += ['h{}'.format(i) for i in range(1, num_sroots+1)] - category = TriangularKacMoodyAlgebras(R).FiniteDimensional() - index_set = p_roots + list(alphacheck) + n_roots - names = tuple(names) - from sage.sets.finite_enumerated_set import FiniteEnumeratedSet - index_set = FiniteEnumeratedSet(index_set) - LieAlgebraWithStructureCoefficients.__init__(self, R, s_coeffs, names, index_set, - category, prefix='E', bracket='[', - sorting_key=self._basis_key) + return s_coeffs def _repr_(self): """ @@ -1897,8 +1988,8 @@ def _weight_action(self, m, wt): alc = wt.parent().simple_coroots() return R(wt.scalar( alc[aci[m]] )) - def affine(self, kac_moody=False): - """ + def affine(self, kac_moody=True): + r""" Return the affine Lie algebra of ``self``. EXAMPLES:: @@ -1908,14 +1999,20 @@ def affine(self, kac_moody=False): Lie algebra of ['C', 3] in the Chevalley basis sage: sp6.affine() Affine Kac-Moody algebra of ['C', 3] in the Chevalley basis + + sage: L = LieAlgebra(QQ, cartan_type=['A',3], epsilon=[(1,2),(3,2)]) + sage: L.affine(False) + Affine Lie algebra of ['A', 3] in the Chevalley basis + sage: L.affine(True) + Affine Kac-Moody algebra of ['A', 3] in the Chevalley basis """ from sage.algebras.lie_algebras.affine_lie_algebra import AffineLieAlgebra - return AffineLieAlgebra(self, kac_moody) + return AffineLieAlgebra(self, kac_moody=kac_moody) # Useful in creating the UEA @cached_method def indices_to_positive_roots_map(self): - """ + r""" Return the map from indices to positive roots. EXAMPLES:: @@ -2006,7 +2103,7 @@ def _part_generators(self, positive=False): @cached_method def gens(self): - """ + r""" Return the generators of ``self`` in the order of `e_i`, `f_i`, and `h_i`. @@ -2052,3 +2149,303 @@ def highest_root_basis_elt(self, pos=True): if pos: return B[theta] return B[-theta] + + @cached_method + def killing_form_matrix(self): + r""" + Return the matrix of the Killing form of ``self``. + + The rows and the columns of this matrix are indexed by the + elements of the basis of ``self`` (in the order provided by + :meth:`basis`). + + EXAMPLES:: + + sage: g = LieAlgebra(QQ, cartan_type=['A', 2]) + sage: g.killing_form_matrix() + [ 0 0 0 0 0 6 0 0] + [ 0 0 0 0 0 0 6 0] + [ 0 0 0 0 0 0 0 6] + [ 0 0 0 12 -6 0 0 0] + [ 0 0 0 -6 12 0 0 0] + [ 6 0 0 0 0 0 0 0] + [ 0 6 0 0 0 0 0 0] + [ 0 0 6 0 0 0 0 0] + """ + B = self.basis() + Q = self._Q + from sage.matrix.constructor import matrix + ret = matrix.zero(self.base_ring(), self._M.rank()) + keys = list(B.keys()) + for i, a in enumerate(keys): + for j, b in enumerate(keys[i:], start=i): + if ((a in Q) != (b in Q)) or (a in Q and a + b): + continue + # either a and b are both coroots or a + b == 0 + temp = self.killing_matrix(B[a], B[b]).trace() + ret[i, j] = temp + ret[j, i] = temp + ret.set_immutable() + return ret + + def killing_form(self, x, y): + r""" + Return the Killing form on ``x`` and ``y``, where ``x`` + and ``y`` are two elements of ``self``. + + The Killing form is defined as + + .. MATH:: + + \langle x \mid y \rangle + = \operatorname{tr}\left( \operatorname{ad}_x + \circ \operatorname{ad}_y \right). + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) + sage: L.killing_form(L.an_element(), L.an_element()) + 36 + sage: B = L.basis() + sage: matrix([[L.killing_form(a, b) for a in B] for b in B]) + [ 0 0 0 0 0 6 0 0] + [ 0 0 0 0 0 0 6 0] + [ 0 0 0 0 0 0 0 6] + [ 0 0 0 12 -6 0 0 0] + [ 0 0 0 -6 12 0 0 0] + [ 6 0 0 0 0 0 0 0] + [ 0 6 0 0 0 0 0 0] + [ 0 0 6 0 0 0 0 0] + """ + return x.value * self.killing_form_matrix() * y.value + + +class LieAlgebraChevalleyBasis_simply_laced(LieAlgebraChevalleyBasis): + r""" + A finite dimensional simply-laced Lie algebra in the Chevalley basis + with structure coefficients given by an orientation of the Dynkin + diagram. + + We follow Chapter 7.7 of [Ka1990]_, where the structure coefficients + are given by an :meth:`asymmetry function <asymmetry_function>` defined by + `\varepsilon(\alpha_i, \alpha_j) = -1` if there is an arrow `i \to j` in + the Dynkin quiver (an orientation of the Dynkin diagram). However we twist + `E_{\alpha}` by `\mathrm{sign}(\alpha)` so that `F_i = E_{-\alpha_i}` + rather than its negative. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['A', 2], epsilon=[(2, 1)]) + sage: L.e(1).bracket(L.e(2)) + E[alpha[1] + alpha[2]] + + sage: L = LieAlgebra(QQ, cartan_type=['A', 2], epsilon=[(1, 2)]) + sage: L.e(1).bracket(L.e(2)) + -E[alpha[1] + alpha[2]] + """ + def __init__(self, R, cartan_type, epsilon): + """ + Initialize ``self``. + + TESTS:: + + sage: L = LieAlgebra(QQ, cartan_type=['A', 2], epsilon=[(2,1)]) + sage: TestSuite(L).run(elements=list(L.basis())) + sage: L = LieAlgebra(QQ, cartan_type=['D', 4], epsilon=[(2,1), (3,2), (4,2)]) + sage: TestSuite(L).run(elements=list(L.basis())) # long time + """ + self._epsilon = epsilon + super().__init__(R, cartan_type) + + def _construct_struct_coeffs(self, R, p_roots): + r""" + Construct the structure coefficients of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['A',1], epsilon=[]) + sage: sorted(L._construct_struct_coeffs(QQ, list(L._Q.positive_roots())).items(), key=str) + [((alpha[1], -alpha[1]), {alphacheck[1]: 1}), + ((alpha[1], alphacheck[1]), {alpha[1]: -2}), + ((alphacheck[1], -alpha[1]), {-alpha[1]: -2})] + """ + p_roots_set = set(p_roots) + alphacheck = self._Q.simple_coroots() + + s_coeffs = {} + for i, r in enumerate(p_roots): + # [e_r, h_i] and [h_i, f_r] + for ac in alphacheck: + c = r.scalar(ac) + if c == 0: + continue + s_coeffs[(r, ac)] = {r: -c} + s_coeffs[(ac, -r)] = {-r: -c} + + # [e_r, f_r] + s_coeffs[(r, -r)] = {alphacheck[j]: c + for j, c in r.associated_coroot()} + + # [e_r, e_s] and [e_r, f_s] with r != +/-s + # We assume s is positive, as otherwise we negate + # both r and s and the resulting coefficient + for j, s in enumerate(p_roots[i+1:], start=i+1): + if r + s in p_roots_set: + coeff = R.prod((-1)**(ca*cb) if (ii, jj) in self._epsilon or ii == jj else 1 + for ii, ca in r._monomial_coefficients.items() + for jj, cb in s._monomial_coefficients.items()) + s_coeffs[r, s] = {r+s: coeff} + ht = sum(r.coefficients()) + sum(s.coefficients()) + s_coeffs[-r, -s] = {-r-s: -coeff} + if r - s in p_roots_set or s - r in p_roots_set: + coeff = R.prod((-1)**(ca*cb) if (ii, jj) in self._epsilon or ii == jj else 1 + for ii, ca in r._monomial_coefficients.items() + for jj, cb in s._monomial_coefficients.items()) + if r - s in p_roots_set: + s_coeffs[r, -s] = {r-s: -coeff} + s_coeffs[-r, s] = {s-r: coeff} + else: + s_coeffs[r, -s] = {r-s: coeff} + s_coeffs[-r, s] = {s-r: -coeff} + + return s_coeffs + + def asymmetry_function(self): + r""" + Return the asymmetry function of ``self``. + + An *asymmetry function* is a function `\varepsilon : Q \times Q + \to \{1, -1\}` that satisfies the following properties: + + 1. `\varepsilon(\alpha, \alpha) = (-1)^{(\alpha|\alpha)/2}` + 2. bimultiplicativity `\varepsilon(alpha + \alpha', \beta) = + \varepsilon(\alpha, \beta) \varepsilon(\alpha', \beta)` and + `\varepsilon(alpha, \beta + \beta') = + \varepsilon(\alpha, \beta) \varepsilon(\alpha', \beta)`, + + where `(\alpha | \beta)` is the symmetric bilinear form on `Q` given + by the Cartan matrix. Some consequences of these properties are that + `\varepsilon(\alpha, 0) = \varepsilon(0, \beta) = 1` and + `varepsilon(\alpha, \beta) \varepsilon(\beta, \alpha) = + (-1)^{(\alpha|\beta)}`. + + OUTPUT: + + The asymmetry function as a ``dict`` consisting of pairs of all of + the roots of `Q` and `0`. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['A',2], epsilon=[(2,1)]) + sage: ep = L.asymmetry_function() + sage: al = L.cartan_type().root_system().root_lattice().simple_roots() + sage: ep[al[1], al[2]] + 1 + sage: ep[al[2],al[1]] + -1 + + sage: L = LieAlgebra(QQ, cartan_type=['A',2], epsilon=[(1,2)]) + sage: ep = L.asymmetry_function() + sage: al = L.cartan_type().root_system().root_lattice().simple_roots() + sage: ep[al[1], al[2]] + -1 + sage: ep[al[2],al[1]] + 1 + """ + roots = set(self._Q.roots()) + al = self._Q.simple_roots() + + ep = {(r, r): (-1)**(r.scalar(r.associated_coroot()) // 2) for r in roots} + next_level = set() + for i in self._Q.index_set(): + # ep[i,0] = ep[i,-j] * ep[i,j] = ep[i,0]^2 + # => ep[i,0] = 1 = ep[i,-j] * ep[i,j] + # => ep[-i,0] = 1 = ep[-i,-j] * ep[-i,j] + ep[al[i], self._Q.zero()] = 1 + ep[-al[i], self._Q.zero()] = 1 + for j in self._Q.index_set(): + if i == j or (i, j) in self._epsilon: + ep[al[i], al[j]] = -1 + else: + ep[al[i], al[j]] = 1 + next_level.add((al[i], al[j])) + ep[al[i], -al[j]] = ep[al[i], al[j]] + next_level.add((al[i], -al[j])) + ep[-al[i], al[j]] = ep[al[i], al[j]] + next_level.add((-al[i], al[j])) + ep[-al[i], -al[j]] = ep[al[i], al[j]] + next_level.add((-al[i], -al[j])) + + while next_level: + cur = next_level + next_level = set() + for r, s in cur: + for a in al: + prev = r + temp = r + a + while temp in roots or temp == 0: + if (temp, s) in ep: + break + next_level.add((temp, s)) + ep[temp, s] = ep[prev, s] * ep[a, s] + prev = temp + temp += a + + prev = r + temp = r - a + while temp in roots or temp == 0: + if (temp, s) in ep: + break + next_level.add((temp, s)) + ep[temp, s] = ep[prev, s] * ep[-a, s] + prev = temp + temp -= a + + prev = s + temp = s + a + while temp in roots or temp == 0: + if (r, temp) in ep: + break + next_level.add((r, temp)) + ep[r, temp] = ep[r, prev] * ep[r, a] + prev = temp + temp += a + + prev = s + temp = s - a + while temp in roots or temp == 0: + if (r, temp) in ep: + break + next_level.add((r, temp)) + ep[r, temp] = ep[r, prev] * ep[r, -a] + prev = temp + temp -= a + + return ep + + def _test_structure_coeffs(self, **options): + r""" + Check the structure coefficients using the :meth:`asymmetry_function`. + + EXAMPLES:: + + sage: L = LieAlgebra(ZZ, cartan_type=['A',4], epsilon=[(1,2), (3,2), (3,4)]) + sage: L._test_structure_coeffs() + """ + tester = self._tester(**options) + + ep = self.asymmetry_function() + + roots = set(self._Q.roots()) + p_roots = set(self._Q.positive_roots()) + B = self.basis() + for r in roots: + for s in roots: + if r + s not in roots: + continue + x = B[r].bracket(B[s]) + tester.assertEqual(list(x.support()), [r+s], f"[{r}, {s}] = {x} is not a root vector") + sign = 1 if (r in p_roots) == (s in p_roots) else -1 + if (r + s) not in p_roots: + sign = -sign + tester.assertEqual(x[r+s], sign * ep[r, s], f"[{r}, {s}] = {x[r+s]} != {sign*ep[r,s]}") diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 2017ad3c6d2..2c6c23297f9 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -309,6 +309,7 @@ def regular_vector_fields(R): from sage.algebras.lie_algebras.virasoro import LieAlgebraRegularVectorFields return LieAlgebraRegularVectorFields(R) + witt = regular_vector_fields def pwitt(R, p): @@ -522,8 +523,14 @@ def so(R, n, representation='bracket'): The Lie algebra `\mathfrak{so}_n` is the type `B_k` Lie algebra if `n = 2k - 1` or the type `D_k` Lie algebra if `n = 2k`, and in - either case is finite dimensional. As a matrix Lie algebra, it - is given by the set of all real anti-symmetric `n \times n` matrices. + either case is finite dimensional. + + A classical description of this as a matrix Lie algebra is + the set of all anti-symmetric `n \times n` matrices. However, + the implementation here uses a different bilinear form for the Lie + group and follows the description in Chapter 8 of [HK2002]_. + See :class:`sage.algebras.lie_algebras.classical_lie_algebra.so` + for a precise description. INPUT: diff --git a/src/sage/algebras/lie_algebras/free_lie_algebra.py b/src/sage/algebras/lie_algebras/free_lie_algebra.py index af001d0fa57..60d49a174b6 100644 --- a/src/sage/algebras/lie_algebras/free_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/free_lie_algebra.py @@ -265,7 +265,7 @@ def graded_dimension(self, k): """ if k == 0: return 0 - from sage.arith.all import moebius + from sage.arith.misc import moebius s = len(self.lie_algebra_generators()) k = ZZ(k) # Make sure we have something that is in ZZ return sum(moebius(d) * s**(k // d) for d in k.divisors()) // k @@ -713,7 +713,7 @@ def _rewrite_bracket(self, l, r): sage: Lyn([x, [y, [z, x]]]) # indirect doctest [x, [[x, z], y]] """ - assert l < r, "Order mismatch %s > %s"%(l, r) + assert l < r, "Order mismatch %s > %s" % (l, r) if self._is_basis_element(l, r): # Compute the grade of the new element diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 4662a3e313f..d2f336f642c 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -58,7 +58,7 @@ def p(self, i): sage: L.p(2) p2 """ - return self.element_class(self, {'p%i'%i: self.base_ring().one()}) + return self.element_class(self, {'p%i' % i: self.base_ring().one()}) def q(self, i): """ @@ -70,7 +70,7 @@ def q(self, i): sage: L.q(2) q2 """ - return self.element_class(self, {'q%i'%i: self.base_ring().one()}) + return self.element_class(self, {'q%i' % i: self.base_ring().one()}) def z(self): """ @@ -122,6 +122,23 @@ def _repr_term(self, m): """ return m + def _ascii_art_term(self, m): + r""" + Return a string representation of the term indexed by ``m``. + + EXAMPLES:: + + sage: H = lie_algebras.Heisenberg(QQ, 3) + sage: H._ascii_art_term('p1') + p1 + sage: H._ascii_art_term('z') + z + sage: ascii_art(sum(i * b for i, b in enumerate(H.basis()))) + p2 + 2*p3 + 3*q1 + 4*q2 + 5*q3 + 6*z + """ + from sage.typeset.ascii_art import ascii_art + return ascii_art(m) + def _latex_term(self, m): r""" Return a string representation of the term indexed by ``m``. @@ -138,7 +155,7 @@ def _latex_term(self, m): """ if len(m) == 1: return m - return "%s_{%s}"%(m[0], m[1:]) # else it is of length at least 2 + return "%s_{%s}" % (m[0], m[1:]) # else it is of length at least 2 def _unicode_art_term(self, m): r""" @@ -261,12 +278,12 @@ def lie_algebra_generators(self): """ if self._n == 0: return Family(['z'], lambda i: self.z()) - k = ['p%s'%i for i in range(1, self._n+1)] - k += ['q%s'%i for i in range(1, self._n+1)] + k = ['p%s' % i for i in range(1, self._n+1)] + k += ['q%s' % i for i in range(1, self._n+1)] d = {} for i in range(1, self._n+1): - d['p%s'%i] = self.p(i) - d['q%s'%i] = self.q(i) + d['p%s' % i] = self.p(i) + d['q%s' % i] = self.q(i) return Family(k, lambda i: d[i]) @cached_method @@ -282,8 +299,8 @@ def basis(self): """ d = {} for i in range(1, self._n+1): - d['p%s'%i] = self.p(i) - d['q%s'%i] = self.q(i) + d['p%s' % i] = self.p(i) + d['q%s' % i] = self.q(i) d['z'] = self.z() return Family(self._indices, lambda i: d[i]) @@ -385,8 +402,8 @@ def __init__(self, R, n): sage: TestSuite(L).run() """ HeisenbergAlgebra_fd.__init__(self, n) - names = tuple(['p%s'%i for i in range(1,n+1)] - + ['q%s'%i for i in range(1,n+1)] + names = tuple(['p%s' % i for i in range(1,n+1)] + + ['q%s' % i for i in range(1,n+1)] + ['z']) LieAlgebraWithGenerators.__init__(self, R, names=names, index_set=names, category=LieAlgebras(R).Nilpotent().FiniteDimensional().WithBasis()) @@ -687,8 +704,8 @@ def __init__(self, R, n): p = tuple(MS({(0,i): one}) for i in range(1, n+1)) q = tuple(MS({(i,n+1): one}) for i in range(1, n+1)) z = (MS({(0,n+1): one}),) - names = tuple('p%s'%i for i in range(1,n+1)) - names = names + tuple('q%s'%i for i in range(1,n+1)) + ('z',) + names = tuple('p%s' % i for i in range(1,n+1)) + names = names + tuple('q%s' % i for i in range(1,n+1)) + ('z',) cat = LieAlgebras(R).Nilpotent().FiniteDimensional().WithBasis() LieAlgebraFromAssociative.__init__(self, MS, p + q + z, names=names, index_set=names, category=cat) @@ -716,7 +733,7 @@ def p(self, i): [0 0 0] [0 0 0] """ - return self._gens['p%s'%i] + return self._gens['p%s' % i] def q(self, i): r""" @@ -730,7 +747,7 @@ def q(self, i): [0 0 1] [0 0 0] """ - return self._gens['q%s'%i] + return self._gens['q%s' % i] def z(self): """ diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 87b1a8cee37..5e1d44813ac 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -217,7 +217,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): **4.** We can construct a Lie algebra from a Cartan type by using the ``cartan_type`` option:: - sage: L = LieAlgebra(ZZ, cartan_type=['C',3]) + sage: L = LieAlgebra(ZZ, cartan_type=['C', 3]) sage: L.inject_variables() Defining e1, e2, e3, f1, f2, f3, h1, h2, h3 sage: e1.bracket(e2) @@ -229,13 +229,27 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): sage: L([e2, [e2, e3]]) 2*E[2*alpha[2] + alpha[3]] - sage: L = LieAlgebra(ZZ, cartan_type=['E',6]) + sage: L = LieAlgebra(ZZ, cartan_type=['E', 6]) sage: L Lie algebra of ['E', 6] in the Chevalley basis + When the Cartan type is finite type and simply-laced, we can also + specify an asymmetry function from [Ka1990]_ using a Dynkin diagram + orientation with the ``epsilon`` option:: + + sage: L = LieAlgebra(QQ, cartan_type=['A', 2], epsilon=[(1, 2)]) + sage: e1, e2 = L.e() + sage: L[e1, e2] + -E[alpha[1] + alpha[2]] + + sage: L = LieAlgebra(QQ, cartan_type=['A', 2], epsilon=[(2, 1)]) + sage: e1, e2 = L.e() + sage: L[e1, e2] + E[alpha[1] + alpha[2]] + We also have matrix versions of the classical Lie algebras:: - sage: L = LieAlgebra(ZZ, cartan_type=['A',2], representation='matrix') + sage: L = LieAlgebra(ZZ, cartan_type=['A', 2], representation='matrix') sage: L.gens() ( [0 1 0] [0 0 0] [0 0 0] [0 0 0] [ 1 0 0] [ 0 0 0] @@ -246,7 +260,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): There is also the compact real form of matrix Lie algebras implemented (the base ring must currently be a field):: - sage: L = LieAlgebra(QQ, cartan_type=['A',2], representation="compact real") + sage: L = LieAlgebra(QQ, cartan_type=['A', 2], representation="compact real") sage: list(L.basis()) [ [ 0 1 0] [ 0 0 1] [ 0 0 0] [ i 0 0] [0 i 0] [0 0 i] @@ -376,7 +390,7 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, # Parse input as a Cartan type # ----- - ct = kwds.get("cartan_type", None) + ct = kwds.pop("cartan_type", None) if ct is not None: from sage.combinat.root_system.cartan_type import CartanType ct = CartanType(ct) @@ -386,16 +400,16 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, kac_moody=kwds.get("kac_moody", True)) if not ct.is_finite(): raise NotImplementedError("non-finite types are not implemented yet, see trac #14901 for details") - rep = kwds.get("representation", "bracket") + rep = kwds.pop("representation", "bracket") if rep == 'bracket': from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis - return LieAlgebraChevalleyBasis(R, ct) + return LieAlgebraChevalleyBasis(R, ct, **kwds) if rep == 'matrix': from sage.algebras.lie_algebras.classical_lie_algebra import ClassicalMatrixLieAlgebra - return ClassicalMatrixLieAlgebra(R, ct) + return ClassicalMatrixLieAlgebra(R, ct, **kwds) if rep == 'compact real': from sage.algebras.lie_algebras.classical_lie_algebra import MatrixCompactRealForm - return MatrixCompactRealForm(R, ct) + return MatrixCompactRealForm(R, ct, **kwds) raise ValueError("invalid representation") # Parse the remaining arguments diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pxd b/src/sage/algebras/lie_algebras/lie_algebra_element.pxd index 8d82e65fefb..fdae38396b9 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pxd +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pxd @@ -22,7 +22,7 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): cpdef _bracket_(self, right) cpdef to_vector(self, bint sparse=*) cpdef dict monomial_coefficients(self, bint copy=*) - #cpdef lift(self) + # cpdef lift(self) cdef class UntwistedAffineLieAlgebraElement(Element): cdef dict _t_dict diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx index d0a1f70510a..ec8dafeec66 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx @@ -17,11 +17,9 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from copy import copy -from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE +from cpython.object cimport Py_EQ, Py_NE, Py_GT, Py_GE from sage.misc.repr import repr_lincomb -from sage.combinat.free_module import CombinatorialFreeModule from sage.structure.element cimport have_same_parent, parent from sage.structure.coerce cimport coercion_model from sage.cpython.wrapperdescr cimport wrapperdescr_fastcall @@ -116,13 +114,15 @@ cdef class LieAlgebraElement(IndexedFreeModuleElement): -[a, [a, b]] + [a, b] - [[a, b], b] """ s = codomain.zero() - if not self: # If we are 0 + if not self: # If we are 0 return s names = self.parent().variable_names() if base_map is None: - base_map = lambda x: x + def base_map(x): + return x + return codomain.sum(base_map(c) * t._im_gens_(codomain, im_gens, names) - for t, c in self._monomial_coefficients.iteritems()) + for t, c in self._monomial_coefficients.items()) cpdef lift(self): """ @@ -167,10 +167,10 @@ cdef class LieAlgebraElement(IndexedFreeModuleElement): # does not match the generators index set of the UEA. if hasattr(self._parent, '_UEA_names_map'): names_map = self._parent._UEA_names_map - for t, c in self._monomial_coefficients.iteritems(): + for t, c in self._monomial_coefficients.items(): s += c * gen_dict[names_map[t]] else: - for t, c in self._monomial_coefficients.iteritems(): + for t, c in self._monomial_coefficients.items(): s += c * gen_dict[t] return s @@ -408,7 +408,7 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): if scalar_parent != self._parent.base_ring(): # Temporary needed by coercion (see Polynomial/FractionField tests). if self._parent.base_ring().has_coerce_map_from(scalar_parent): - scalar = self._parent.base_ring()( scalar ) + scalar = self._parent.base_ring()(scalar) else: return None if self_on_left: @@ -460,7 +460,7 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): ((1,3,2), 1), ((1,3), 1)] """ cdef dict d = self.value.monomial_coefficients(copy=False) - yield from d.iteritems() + yield from d.items() # TODO: Also used for vectors, find a better name @@ -479,7 +479,7 @@ cdef class LieAlgebraMatrixWrapper(LieAlgebraElementWrapper): sage: z.value.is_immutable() True """ - value.set_immutable() # Make the matrix immutable for hashing + value.set_immutable() # Make the matrix immutable for hashing LieAlgebraElementWrapper.__init__(self, parent, value) @@ -599,7 +599,8 @@ cdef class LieSubalgebraElementWrapper(LieAlgebraElementWrapper): if self._monomial_coefficients is None: sm = self.parent().module() v = sm.coordinate_vector(self.to_vector()) - self._monomial_coefficients = {k: v[k] for k in range(len(v)) if v[k]} + self._monomial_coefficients = {k: v[k] for k in range(len(v)) + if v[k]} if copy: return dict(self._monomial_coefficients) return self._monomial_coefficients @@ -681,7 +682,7 @@ cdef class LieSubalgebraElementWrapper(LieAlgebraElementWrapper): if scalar_parent != self._parent.base_ring(): # Temporary needed by coercion (see Polynomial/FractionField tests). if self._parent.base_ring().has_coerce_map_from(scalar_parent): - scalar = self._parent.base_ring()( scalar ) + scalar = self._parent.base_ring()(scalar) else: return None cdef LieSubalgebraElementWrapper ret @@ -827,7 +828,7 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): zero = self._parent.base_ring().zero() I = self._parent._indices cdef int i - for i,v in enumerate(self.value): + for i, v in enumerate(self.value): if v != zero: yield (I[i], v) @@ -862,7 +863,7 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): """ UEA = self._parent.universal_enveloping_algebra() gens = UEA.gens() - return UEA.sum(c * gens[i] for i, c in self.value.iteritems()) + return UEA.sum(c * gens[i] for i, c in self.value.items()) cpdef dict monomial_coefficients(self, bint copy=True): """ @@ -879,7 +880,7 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): {'x': 2, 'z': -3/2} """ I = self._parent._indices - return {I[i]: v for i,v in self.value.iteritems()} + return {I[i]: v for i, v in self.value.items()} def __getitem__(self, i): """ @@ -942,6 +943,15 @@ cdef class UntwistedAffineLieAlgebraElement(Element): with ``style`` - ``tensor_symb`` -- the tensor symbol; must be compatible with ``style`` + + EXAMPLES:: + + sage: L = lie_algebras.Affine(QQ, ['B', 3, 1]) + sage: elt = L.an_element() + sage: elt._repr_generic(str, str, lambda t: "T^{}".format(t), '.', '(x)') + '(E[alpha[3]] + E[alpha[2]] + E[alpha[1]] + h1 + h2 + h3 + E[-alpha[3]] + + E[-alpha[2]] + E[-alpha[1]])(x)T^0 + (E[-alpha[1] - 2*alpha[2] + - 2*alpha[3]])(x)T^1 + (E[alpha[1] + 2*alpha[2] + 2*alpha[3]])(x)T^-1 + c + d' """ ret = style('') mult = style(mult) @@ -1058,7 +1068,8 @@ cdef class UntwistedAffineLieAlgebraElement(Element): ( alpha[1] - alphacheck[1] + 2ยท-alpha[1] )โŠ—tโฐ + ( -alpha[1] )โŠ—tยน + 3โ‹…c + -2โ‹…d """ from sage.typeset.unicode_art import unicode_art, unicode_superscript - return self._repr_generic(unicode_art, unicode_art, lambda t: "t" + unicode_superscript(t), + return self._repr_generic(unicode_art, unicode_art, + lambda t: "t" + unicode_superscript(t), unicode_art('โ‹…'), unicode_art('โŠ—')) cpdef dict t_dict(self): @@ -1261,8 +1272,8 @@ cdef class UntwistedAffineLieAlgebraElement(Element): """ cdef dict d = {} for t, g in self._t_dict.items(): - for k, c in g.monomial_coefficients(copy=False).iteritems(): - d[k,t] = c + for k, c in g.monomial_coefficients(copy=False).items(): + d[k, t] = c if self._c_coeff: d['c'] = self._c_coeff if self._d_coeff: @@ -1322,7 +1333,6 @@ cdef class UntwistedAffineLieAlgebraElement(Element): if not self or not y: return self._parent.zero() - gd = self._parent._g.basis() cdef dict d = {} cdef UntwistedAffineLieAlgebraElement rt = <UntwistedAffineLieAlgebraElement>(y) c = self._parent.base_ring().zero() @@ -1430,7 +1440,7 @@ class FreeLieAlgebraElement(LieAlgebraElement): if not self: return s gen_dict = UEA.gens_dict() - for t, c in self._monomial_coefficients.iteritems(): + for t, c in self._monomial_coefficients.items(): s += c * t.lift(gen_dict) return s @@ -1439,6 +1449,7 @@ class FreeLieAlgebraElement(LieAlgebraElement): Return ``self`` as a list of pairs ``(m, c)`` where ``m`` is a basis key (i.e., a key of one of the basis elements) and ``c`` is its coefficient. + This list is sorted from highest to lowest degree. EXAMPLES:: @@ -1448,8 +1459,10 @@ class FreeLieAlgebraElement(LieAlgebraElement): sage: elt.list() [([x, y], -1), (x, 1)] """ - k = lambda x: (-x[0]._grade, x[0]) if isinstance(x[0], GradedLieBracket) else (-1, x[0]) - return sorted((<dict>self._monomial_coefficients).iteritems(), key=k) + def k(x): + y = x[0] + return (-y._grade, y) if isinstance(y, GradedLieBracket) else (-1, y) + return sorted((<dict>self._monomial_coefficients).items(), key=k) def _bracket_(self, y): """ @@ -1472,16 +1485,16 @@ class FreeLieAlgebraElement(LieAlgebraElement): cdef dict d = {} zero = self.base_ring().zero() - for ml, cl in self._monomial_coefficients.iteritems(): # The left monomials - for mr, cr in y._monomial_coefficients.iteritems(): # The right monomials + for ml, cl in self._monomial_coefficients.items(): # The left monomials + for mr, cr in y._monomial_coefficients.items(): # The right monomials if ml == mr: continue - if ml < mr: # Make sure ml < mr + if ml < mr: # Make sure ml < mr a, b = ml, mr else: a, b = mr, ml cr = -cr - for b_elt, coeff in self.parent()._rewrite_bracket(a, b).iteritems(): + for b_elt, coeff in self.parent()._rewrite_bracket(a, b).items(): d[b_elt] = d.get(b_elt, zero) + cl * cr * coeff if d[b_elt] == zero: del d[b_elt] @@ -1490,8 +1503,9 @@ class FreeLieAlgebraElement(LieAlgebraElement): return self.parent().zero() return type(self)(self.parent(), d) + ##################################################################### -## Helper classes for free Lie algebras +# Helper classes for free Lie algebras cdef class LieObject(SageObject): """ diff --git a/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py b/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py index dbfc3d3d5ec..38334bfe1f8 100644 --- a/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py +++ b/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py @@ -496,6 +496,46 @@ def degree_on_basis(self, m): """ return m.length() + def casimir_element(self, order=2): + r""" + Return the Casimir element of ``self``. + + .. SEEALSO:: + + :meth:`~sage.categories.finite_dimensional_lie_algebras_with_basis.FiniteDimensionalLieAlgebrasWithBasis.ParentMethods.casimir_element` + + INPUT: + + - ``order`` -- (default: ``2``) the order of the Casimir element + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['G', 2]) + sage: U = L.pbw_basis() + sage: C = U.casimir_element(); C + 1/4*PBW[alpha[2]]*PBW[-alpha[2]] + 1/12*PBW[alpha[1]]*PBW[-alpha[1]] + + 1/12*PBW[alpha[1] + alpha[2]]*PBW[-alpha[1] - alpha[2]] + 1/12*PBW[2*alpha[1] + alpha[2]]*PBW[-2*alpha[1] - alpha[2]] + + 1/4*PBW[3*alpha[1] + alpha[2]]*PBW[-3*alpha[1] - alpha[2]] + + 1/4*PBW[3*alpha[1] + 2*alpha[2]]*PBW[-3*alpha[1] - 2*alpha[2]] + + 1/12*PBW[alphacheck[1]]^2 + 1/4*PBW[alphacheck[1]]*PBW[alphacheck[2]] + + 1/4*PBW[alphacheck[2]]^2 - 5/12*PBW[alphacheck[1]] - 3/4*PBW[alphacheck[2]] + sage: all(g * C == C * g for g in U.algebra_generators()) + True + + TESTS:: + + sage: H = lie_algebras.Heisenberg(QQ, oo) + sage: U = H.pbw_basis() + sage: U.casimir_element() + Traceback (most recent call last): + ... + ValueError: the Lie algebra must be finite dimensional + """ + from sage.rings.infinity import Infinity + if self._g.dimension() == Infinity: + raise ValueError("the Lie algebra must be finite dimensional") + return self._g.casimir_element(order=order, UEA=self) + class Element(CombinatorialFreeModule.Element): def _act_on_(self, x, self_on_left): """ diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 8eb6033c4c4..16c2cf51029 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -358,6 +358,31 @@ def from_vector(self, v, order=None, coerce=True): v = self._M(v) return self.element_class(self, v) + def _from_dict(self, d, coerce=False, remove_zeros=False): + r""" + Construct an element of ``self`` from an ``{index: coefficient}`` + dictionary. + + INPUT: + + - ``d`` -- a dictionary ``{index: coeff}`` where each ``index`` is the + index of a basis element and each ``coeff`` belongs to the + coefficient ring ``self.base_ring()`` + - ``coerce`` -- ignored + - ``remove_zeros`` -- ignored + + EXAMPLES:: + + sage: L.<x,y,z> = LieAlgebra(QQ, {('x','y'): {'z':1}}) + sage: L._from_dict({'x': -3, 'z': 2, 'y': 0}) + -3*x + 2*z + """ + zero = self._M.base_ring().zero() + ret = [zero] * self._M.rank() + for k, c in d.items(): + ret[self._index_to_pos[k]] = c + return self.element_class(self, self._M(ret)) + def some_elements(self): """ Return some elements of ``self``. diff --git a/src/sage/algebras/lie_algebras/verma_module.py b/src/sage/algebras/lie_algebras/verma_module.py index 5a9d5956557..2db27f5f60d 100644 --- a/src/sage/algebras/lie_algebras/verma_module.py +++ b/src/sage/algebras/lie_algebras/verma_module.py @@ -590,7 +590,7 @@ def _Hom_(self, Y, category=None, **options): The sole purpose of this method is to construct the homset as a :class:`~sage.algebras.lie_algebras.verma_module.VermaModuleHomset`. If ``category`` is specified and is not a subcategory of - ``self.category()``, a ``TypeError`` is raised instead. + ``self.category()``, a :class:`TypeError` is raised instead. This method is not meant to be called directly. Please use :func:`sage.categories.homset.Hom` instead. diff --git a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py index 2cd0e9fe2c4..9fdf888fe39 100644 --- a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py @@ -107,24 +107,24 @@ def __init__(self, R, ct, names=None, prefix=None, bracket=None): if S.rank(k2) <= S.rank(k1): myb = B[k1].bracket(B[k2]).monomial_coefficients() myf = R(2).inverse_of_unit()*R(hv).inverse_of_unit()\ - *g.killing_form(B[k1],B[k2]) + * g.killing_form(B[k1], B[k2]) if myb or myf: - gdict[(k1,k2)] = {} + gdict[(k1, k2)] = {} if myb: - gdict[(k1,k2)][0] = {(nk,0):v for nk,v in \ - myb.items()} + gdict[(k1, k2)][0] = {(nk, 0): v + for nk, v in myb.items()} if myf: - gdict[(k1,k2)][1] = {('K',0):myf} + gdict[(k1, k2)][1] = {('K', 0): myf} - weights = (1,)*B.cardinality() + weights = (1,) * B.cardinality() self._ct = ct if prefix is None and names is None: prefix = 'B' GradedLieConformalAlgebra.__init__(self, - R, gdict, index_set=S, - central_elements=('K',), weights=weights, - names=names, prefix=prefix,bracket=bracket) + R, gdict, index_set=S, + central_elements=('K',), weights=weights, + names=names, prefix=prefix, bracket=bracket) def cartan_type(self): """ diff --git a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py index e5cddaed759..178493b13e8 100644 --- a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py @@ -87,29 +87,31 @@ def __init__(self, R, ngens=2, names=None, index_set=None): """ from sage.rings.integer_ring import ZZ try: - assert (ngens in ZZ and ngens > 0 and ngens % 2 == 0) + assert (ngens in ZZ and ngens > 0 and not ngens % 2) except AssertionError: raise ValueError("ngens should be an even positive integer, " + "got {}".format(ngens)) latex_names = None + half = ngens // 2 if (names is None) and (index_set is None): from sage.misc.defaults import variable_names as varnames from sage.misc.defaults import latex_variable_names as laxnames - names = varnames(ngens/2,'beta') + varnames(ngens/2,'gamma') - latex_names = tuple(laxnames(ngens/2,r'\beta') +\ - laxnames(ngens/2,r'\gamma')) + ('K',) + names = varnames(half, 'beta') + varnames(half, 'gamma') + latex_names = tuple(laxnames(half, r'\beta') + + laxnames(half, r'\gamma')) + ('K',) - names,index_set = standardize_names_index_set(names=names, + names, index_set = standardize_names_index_set(names=names, index_set=index_set, ngens=ngens) - A = identity_matrix(R, ngens // 2) + A = identity_matrix(R, half) from sage.matrix.special import block_matrix - gram_matrix = block_matrix([[R.zero(),A],[-A,R.zero()]]) - ghostsdict = { (i,j): {0: {('K',0): gram_matrix[index_set.rank(i), - index_set.rank(j)]}} for i in index_set for j in index_set} - weights = (1,)*(ngens//2) + (0,)*(ngens//2) + gram_matrix = block_matrix([[R.zero(), A], [-A, R.zero()]]) + ghostsdict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), + index_set.rank(j)]}} + for i in index_set for j in index_set} + weights = (1,) * half + (0,) * half super().__init__(R, - ghostsdict,names=names, + ghostsdict, names=names, latex_names=latex_names, index_set=index_set, weights=weights, diff --git a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py index 4a74d9f9357..e6bca4de671 100644 --- a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py @@ -80,33 +80,35 @@ def __init__(self,R,ngens=2,names=None,index_set=None): sage: TestSuite(V).run() """ try: - assert (ngens > 0 and ngens % 2 == 0) + assert (ngens > 0 and not ngens % 2) except AssertionError: raise ValueError("ngens should be an even positive integer, " + "got {}".format(ngens)) latex_names = None + half = ngens // 2 if (names is None) and (index_set is None): from sage.misc.defaults import variable_names as varnames from sage.misc.defaults import latex_variable_names as laxnames - names = varnames(ngens/2,'b') + varnames(ngens/2,'c') - latex_names = tuple(laxnames(ngens/2,'b') +\ - laxnames(ngens/2,'c')) + ('K',) + names = varnames(half, 'b') + varnames(half, 'c') + latex_names = tuple(laxnames(half, 'b') + + laxnames(half, 'c')) + ('K',) from sage.structure.indexed_generators import \ - standardize_names_index_set - names,index_set = standardize_names_index_set(names=names, - index_set=index_set, - ngens=ngens) + standardize_names_index_set + names, index_set = standardize_names_index_set(names=names, + index_set=index_set, + ngens=ngens) from sage.matrix.special import identity_matrix - A = identity_matrix(R, ngens // 2) + A = identity_matrix(R, half) from sage.matrix.special import block_matrix - gram_matrix = block_matrix([[R.zero(),A],[A,R.zero()]]) - ghostsdict = { (i,j): {0: {('K',0): gram_matrix[index_set.rank(i), - index_set.rank(j)]}} for i in index_set for j in index_set} - weights = (1,)*(ngens//2) + (0,)*(ngens//2) - parity = (1,)*ngens + gram_matrix = block_matrix([[R.zero(), A], [A, R.zero()]]) + ghostsdict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), + index_set.rank(j)]}} + for i in index_set for j in index_set} + weights = (1,) * half + (0,) * half + parity = (1,) * ngens super().__init__(R, - ghostsdict,names=names, + ghostsdict, names=names, latex_names=latex_names, index_set=index_set, weights=weights, diff --git a/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py b/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py index 96f6c99defe..9077ef8f6a2 100644 --- a/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +++ b/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py @@ -73,7 +73,8 @@ def _repr_(self): return "Lie conformal algebra generated by {0} over {1}".format( self.gen(0), self.base_ring()) return "Lie conformal algebra with generators {0} over {1}".format( - self.gens(), self.base_ring()) + self.gens(), self.base_ring()) + def _an_element_(self): """ An element of this Lie conformal algebra. diff --git a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py index 31b542cd373..8cc6533b781 100644 --- a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py @@ -111,7 +111,7 @@ def __init__(self, R, ngens=None, gram_matrix=None, names=None, latex_names = None if (names is None) and (index_set is None): - if ngens==1: + if ngens == 1: names = 'psi' else: names = 'psi_' diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py index 5c14016eab2..1007488e165 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py @@ -328,10 +328,10 @@ def __classcall_private__(cls, R=None, arg0=None, index_set=None, 'string_quotes', 'sorting_key', 'graded', 'super'] for key in kwds: if key not in known_keywords: - raise ValueError("got an unexpected keyword argument '%s'"%key) + raise ValueError("got an unexpected keyword argument '%s'" % key) if isinstance(arg0,dict) and arg0: - graded=kwds.pop("graded", False) + graded = kwds.pop("graded", False) if weights is not None or graded: from .graded_lie_conformal_algebra import \ GradedLieConformalAlgebra diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py index c40e654e157..723ae5c385a 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py @@ -14,7 +14,7 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.all import factorial +from sage.arith.misc import factorial from sage.misc.misc_c import prod from sage.misc.repr import repr_lincomb from sage.misc.latex import latex @@ -60,14 +60,14 @@ def T(self, n=1): raise ValueError("n must be a nonnegative Integer") if n == 0 or self.is_zero(): return self - #it's faster to sum than to use recursion + # it's faster to sum than to use recursion if self.is_monomial(): p = self.parent() - a,m = self.index() - coef = self._monomial_coefficients[(a,m)] - if (a,m+n) in p._indices: - return coef*prod(j for j in range(m+1,m+n+1))\ - *p.monomial((a,m+n)) + a, m = self.index() + coef = self._monomial_coefficients[(a, m)] + if (a, m + n) in p._indices: + return coef * prod(range(m + 1, m + n + 1))\ + * p.monomial((a, m + n)) else: return p.zero() return sum(mon.T(n) for mon in self.terms()) @@ -121,23 +121,25 @@ def _bracket_(self, right): if self.is_zero() or right.is_zero(): return {} s_coeff = p._s_coeff - a,k = self.index() - coefa = self.monomial_coefficients()[(a,k)] - b,m = right.index() - coefb = right.monomial_coefficients()[(b,m)] + a, k = self.index() + coefa = self.monomial_coefficients()[(a, k)] + b, m = right.index() + coefb = right.monomial_coefficients()[(b, m)] try: - mbr = dict(s_coeff[(a,b)]) + mbr = dict(s_coeff[(a, b)]) except KeyError: return {} pole = max(mbr.keys()) - ret = {l: coefa*coefb*(-1)**k/factorial(k)*sum(factorial(l)\ - /factorial(m+k+j-l)/factorial(l-k-j)/factorial(j)*\ - mbr[j].T(m+k+j-l) for j in mbr if j >= l-m-k and\ - j <= l-k) for l in range(m+k+pole+1)} + ret = {l: coefa * coefb * (-1)**k / factorial(k) * + sum(factorial(l) / factorial(m + k + j - l) + / factorial(l - k - j) / factorial(j) + * mbr[j].T(m + k + j - l) + for j in mbr if l - m - k <= j <= l - k) + for l in range(m + k + pole + 1)} return {k: v for k, v in ret.items() if v} - diclist = [i._bracket_(j) for i in self.terms() for - j in right.terms()] + diclist = [i._bracket_(j) for i in self.terms() + for j in right.terms()] ret = {} pz = p.zero() for d in diclist: diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py index b2cf3582793..7581daf0ddb 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py @@ -17,7 +17,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.sets.family import Family from .lie_conformal_algebra_element import LCAStructureCoefficientsElement from sage.categories.lie_conformal_algebras import LieConformalAlgebras @@ -152,50 +152,50 @@ def _standardize_s_coeff(s_coeff, index_set, ce, parity=None): #e.g. v = { 0: { (L,2):3, (G,3):1}, 1:{(L,1),2} } v = s_coeff[mypair] key = tuple(mypair) - vals={} + vals = {} for l in v.keys(): lth_product = {k:y for k,y in v[l].items() if y} if lth_product: - vals[l]=lth_product + vals[l] = lth_product - myvals = tuple([(k,tuple(v.items())) for k,v in vals.items() if v]) + myvals = tuple((k, tuple(v.items())) for k, v in vals.items() if v) - if key in sc.keys() and sorted(sc[key]) != sorted(myvals): - raise ValueError("two distinct values given for one "\ - "and the same bracket, skew-symmetry"\ + if key in sc and sorted(sc[key]) != sorted(myvals): + raise ValueError("two distinct values given for one " + "and the same bracket, skew-symmetry" "is not satisfied?") if myvals: sc[key] = myvals - #We now add the skew-symmetric part to optimize - #brackets computations later - key=(mypair[1],mypair[0]) + # We now add the skew-symmetric part to optimize + # brackets computations later + key = (mypair[1], mypair[0]) if index_to_parity[mypair[0]]*index_to_parity[mypair[1]]: parsgn = -1 else: parsgn = 1 maxpole = max(v.keys()) - vals={} + vals = {} for k in range(maxpole+1): kth_product = {} for j in range(maxpole+1-k): if k+j in v.keys(): for i in v[k+j]: if (i[0] not in ce) or ( - i[0] in ce and i[1] + j == 0): - kth_product[(i[0],i[1]+j)] = \ - kth_product.get((i[0], i[1]+j), 0) - kth_product[(i[0],i[1]+j)] += parsgn*\ - v[k+j][i]*(-1)**(k+j+1)*binomial(i[1]+j,j) - kth_product = {k:v for k,v in kth_product.items() if v} + i[0] in ce and i[1] + j == 0): + kth_product[(i[0], i[1] + j)] = \ + kth_product.get((i[0], i[1] + j), 0) + kth_product[(i[0], i[1] + j)] += parsgn *\ + v[k+j][i]*(-1)**(k+j+1)*binomial(i[1]+j,j) + kth_product = {k: v for k, v in kth_product.items() if v} if kth_product: - vals[k]=kth_product + vals[k] = kth_product - myvals = tuple([(k,tuple(v.items())) for k,v in vals.items() if v]) + myvals = tuple((k, tuple(v.items())) for k, v in vals.items() if v) - if key in sc.keys() and sorted(sc[key]) != sorted(myvals): - raise ValueError("two distinct values given for one "\ - "and the same bracket. "\ + if key in sc and sorted(sc[key]) != sorted(myvals): + raise ValueError("two distinct values given for one " + "and the same bracket. " "Skew-symmetry is not satisfied?") if myvals: sc[key] = myvals @@ -214,7 +214,7 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, """ names, index_set = standardize_names_index_set(names,index_set) if central_elements is None: - central_elements= tuple() + central_elements = tuple() if names is not None and names != tuple(index_set): names2 = names + tuple(central_elements) @@ -233,31 +233,31 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, # index_set pass - issuper=kwds.pop('super', False) + issuper = kwds.pop('super', False) if parity is None: - parity = (0,)*index_set.cardinality() + parity = (0,) * index_set.cardinality() else: issuper = True try: assert len(parity) == index_set.cardinality() except AssertionError: - raise ValueError("parity should have the same length as the "\ - "number of generators, got {}".format(parity)) + raise ValueError("parity should have the same length as the " + f"number of generators, got {parity}") s_coeff = LieConformalAlgebraWithStructureCoefficients\ - ._standardize_s_coeff(s_coeff, index_set, central_elements, - parity) + ._standardize_s_coeff(s_coeff, index_set, central_elements, + parity) if names is not None and central_elements is not None: names += tuple(central_elements) - self._index_to_pos = {k: i for i,k in enumerate(index_set)} - #Add central parameters to index_to_pos so that we can - #represent names + self._index_to_pos = {k: i for i, k in enumerate(index_set)} + # Add central parameters to index_to_pos so that we can + # represent names if central_elements is not None: - for i,ce in enumerate(central_elements): - self._index_to_pos[ce] = len(index_set)+i + for i, ce in enumerate(central_elements): + self._index_to_pos[ce] = len(index_set) + i default_category = LieConformalAlgebras(R).WithBasis().FinitelyGenerated() if issuper: @@ -266,14 +266,14 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, category = default_category.or_subcategory(category) if element_class is None: - element_class=LCAStructureCoefficientsElement + element_class = LCAStructureCoefficientsElement FinitelyFreelyGeneratedLCA.__init__( self, R, index_set=index_set, central_elements=central_elements, category=category, element_class=element_class, prefix=prefix, names=names, latex_names=latex_names, **kwds) - s_coeff=dict(s_coeff) + s_coeff = dict(s_coeff) self._s_coeff = Family({k: tuple((j, sum(c*self.monomial(i) for i,c in v )) for j,v in s_coeff[k]) for k in s_coeff}) self._parity = dict(zip(self.gens(),parity+(0,)*len(central_elements))) diff --git a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py index 23af0d3f7dd..045bfb6e57a 100644 --- a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py @@ -43,7 +43,8 @@ class N2LieConformalAlgebra(GradedLieConformalAlgebra): EXAMPLES:: - sage: F.<x> = NumberField(x^2 -2) + sage: x = polygen(ZZ, 'x') + sage: F.<x> = NumberField(x^2 - 2) sage: R = lie_conformal_algebras.N2(F); R The N=2 super Lie conformal algebra over Number Field in x with defining polynomial x^2 - 2 sage: R.inject_variables() diff --git a/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py index d581558aafa..8f5756f993f 100644 --- a/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py @@ -57,15 +57,17 @@ def __init__(self, R): sage: V = lie_conformal_algebras.NeveuSchwarz(QQ) sage: TestSuite(V).run() """ - nsdict = {('L','L'):{0:{('L',1):1}, 1:{('L',0): 2}, - 3:{('C', 0):R(2).inverse_of_unit()}}, - ('L','G'):{0:{('G',1):1}, 1:{('G',0):R(3)*R(2).\ - inverse_of_unit()}}, ('G','G'): {0:{('L',0):2}, - 2:{('C',0):R(2)*R(3).inverse_of_unit()}}} + nsdict = {('L', 'L'): {0: {('L', 1): 1}, + 1: {('L', 0): 2}, + 3: {('C', 0): R(2).inverse_of_unit()}}, + ('L', 'G'): {0: {('G', 1): 1}, + 1: {('G', 0): R(3) * R(2).inverse_of_unit()}}, + ('G', 'G'): {0: {('L', 0): 2}, + 2: {('C', 0): R(2) * R(3).inverse_of_unit()}}} from sage.rings.rational_field import QQ - weights = (2,QQ(3/2)) - parity = (0,1) - GradedLieConformalAlgebra.__init__(self, R, nsdict, names=('L','G'), + weights = (2, QQ((3, 2))) + parity = (0, 1) + GradedLieConformalAlgebra.__init__(self, R, nsdict, names=('L', 'G'), central_elements=('C',), weights=weights, parity=parity) def _repr_(self): diff --git a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py index ee47970a31f..e4a91723558 100644 --- a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py @@ -23,21 +23,22 @@ - Reimundo Heluani (2019-08-09): Initial implementation. """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2019 Reimundo Heluani <heluani@potuz.net> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from .lie_conformal_algebra_with_structure_coefs import \ - LieConformalAlgebraWithStructureCoefficients + LieConformalAlgebraWithStructureCoefficients from sage.matrix.special import identity_matrix from sage.structure.indexed_generators import standardize_names_index_set + class WeylLieConformalAlgebra(LieConformalAlgebraWithStructureCoefficients): r""" The Weyl Lie conformal algebra. @@ -119,7 +120,7 @@ class WeylLieConformalAlgebra(LieConformalAlgebraWithStructureCoefficients): [0 1 0] [0 0 1] """ - def __init__(self,R,ngens=None, gram_matrix=None, names=None, + def __init__(self, R, ngens=None, gram_matrix=None, names=None, index_set=None): """ Initialize self. @@ -131,31 +132,29 @@ def __init__(self,R,ngens=None, gram_matrix=None, names=None, """ from sage.matrix.matrix_space import MatrixSpace if ngens: - try: - from sage.rings.integer_ring import ZZ - assert ngens in ZZ and ngens % 2 == 0 - except AssertionError: - raise ValueError("ngens needs to be an even positive "+ - "Integer, got {}".format(ngens)) - if (gram_matrix is not None): + from sage.rings.integer_ring import ZZ + if not (ngens in ZZ and not ngens % 2): + raise ValueError("ngens needs to be an even positive Integer, " + f"got {ngens}") + if gram_matrix is not None: if ngens is None: ngens = gram_matrix.dimensions()[0] try: - assert (gram_matrix in MatrixSpace(R,ngens,ngens)) + assert (gram_matrix in MatrixSpace(R, ngens, ngens)) except AssertionError: - raise ValueError("The gram_matrix should be a skew-symmetric "+ - "{0} x {0} matrix, got {1}".format(ngens,gram_matrix)) - if (not gram_matrix.is_skew_symmetric()) or \ - (gram_matrix.is_singular()): - raise ValueError("The gram_matrix should be a non degenerate " + - "skew-symmetric {0} x {0} matrix, got {1}"\ - .format(ngens,gram_matrix)) - elif (gram_matrix is None): + raise ValueError("The gram_matrix should be a skew-symmetric " + "{0} x {0} matrix, got {1}".format(ngens, gram_matrix)) + if (not gram_matrix.is_skew_symmetric() or + gram_matrix.is_singular()): + raise ValueError("The gram_matrix should be a non degenerate " + "skew-symmetric {0} x {0} matrix, got {1}" + .format(ngens, gram_matrix)) + elif gram_matrix is None: if ngens is None: ngens = 2 A = identity_matrix(R, ngens // 2) from sage.matrix.special import block_matrix - gram_matrix = block_matrix([[R.zero(),A],[-A,R.zero()]]) + gram_matrix = block_matrix([[R.zero(), A], [-A, R.zero()]]) latex_names = None if (names is None) and (index_set is None): @@ -165,8 +164,9 @@ def __init__(self,R,ngens=None, gram_matrix=None, names=None, names, index_set = standardize_names_index_set(names=names, index_set=index_set, ngens=ngens) - weyldict = { (i,j): {0: {('K',0): gram_matrix[index_set.rank(i), - index_set.rank(j)]}} for i in index_set for j in index_set} + weyldict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), + index_set.rank(j)]}} + for i in index_set for j in index_set} super().__init__(R, weyldict, names=names, latex_names=latex_names, @@ -184,7 +184,7 @@ def _repr_(self): The Weyl Lie conformal algebra with generators (alpha0, alpha1, K) over Integer Ring """ return "The Weyl Lie conformal algebra with generators {} over {}"\ - .format(self.gens(),self.base_ring()) + .format(self.gens(), self.base_ring()) def gram_matrix(self): r""" diff --git a/src/sage/algebras/nil_coxeter_algebra.py b/src/sage/algebras/nil_coxeter_algebra.py index 5d255b9786d..862fdc3b97e 100644 --- a/src/sage/algebras/nil_coxeter_algebra.py +++ b/src/sage/algebras/nil_coxeter_algebra.py @@ -110,16 +110,18 @@ def homogeneous_generator_noncommutative_variables(self, r): 0 sage: U.homogeneous_generator_noncommutative_variables(0) 1 - """ - assert (len(self._cartan_type) == 2 and self._cartan_type[0] in ['A','B']) or (len(self._cartan_type) == 3 and self._cartan_type[2] == 1), "Analogue of symmetric functions in noncommutative variables is not defined in type %s"%(self._cartan_type) + ct = self._cartan_type + msg = f"Analogue of symmetric functions in noncommutative variables is not defined in type {ct}" + assert (len(ct) == 2 and ct[0] in ['A', 'B']) or (len(ct) == 3 and ct[2] == 1), msg if r >= self._n: return self.zero() return self.sum_of_monomials(w for w in self._W.pieri_factors() if w.length() == r) - def homogeneous_noncommutative_variables(self,la): + def homogeneous_noncommutative_variables(self, la): r""" Give the homogeneous function indexed by `la`, viewed inside the Nil-Coxeter algebra. + This is only defined in finite type `A`, `B` and affine types `A^{(1)}`, `B^{(1)}`, `C^{(1)}`, `D^{(1)}`. INPUT: @@ -182,9 +184,9 @@ def k_schur_noncommutative_variables(self, la): """ - assert self._cartan_type[0] == 'A' and len(self._cartan_type) == 3 and self._cartan_type[2] == 1, "%s is not affine type A."%(self._W) - assert la in Partitions(), "%s is not a partition."%(la) - assert (len(la) == 0 or la[0] < self._W.n), "%s is not a %s-bounded partition."%(la, self._W.n-1) + assert self._cartan_type[0] == 'A' and len(self._cartan_type) == 3 and self._cartan_type[2] == 1, "%s is not affine type A." % (self._W) + assert la in Partitions(), "%s is not a partition." % (la) + assert (len(la) == 0 or la[0] < self._W.n), "%s is not a %s-bounded partition." % (la, self._W.n-1) Sym = SymmetricFunctions(self._base_ring) h = Sym.homogeneous() ks = Sym.kschur(self._n-1,1) diff --git a/src/sage/algebras/octonion_algebra.pxd b/src/sage/algebras/octonion_algebra.pxd new file mode 100644 index 00000000000..78500729bdc --- /dev/null +++ b/src/sage/algebras/octonion_algebra.pxd @@ -0,0 +1,19 @@ +""" +Octonions +""" + +from sage.structure.element cimport AlgebraElement +from sage.modules.free_module_element cimport FreeModuleElement + +cdef class Octonion_generic(AlgebraElement): + cdef FreeModuleElement vec + + cpdef Octonion_generic conjugate(self) + cpdef quadratic_form(self) + cpdef norm(self) + cpdef abs(self) + cpdef real_part(self) + cpdef Octonion_generic imag_part(self) + +cdef class Octonion(Octonion_generic): + pass diff --git a/src/sage/algebras/octonion_algebra.pyx b/src/sage/algebras/octonion_algebra.pyx new file mode 100644 index 00000000000..18101c48f66 --- /dev/null +++ b/src/sage/algebras/octonion_algebra.pyx @@ -0,0 +1,986 @@ +""" +Octonion Algebras + +AUTHORS: + +- Travis Scrimshaw (2023-05-06): Initial version +""" +# **************************************************************************** +# Copyright (C) 2023 Travis Scrimshaw <tcscrims at gmail.com> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.misc.functional import sqrt +from sage.structure.element cimport Element, parent +from sage.structure.parent cimport Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.richcmp cimport richcmp +from sage.structure.category_object import normalize_names +from sage.modules.free_module import FreeModule +from sage.categories.magmatic_algebras import MagmaticAlgebras +from sage.categories.rings import Rings +from sage.categories.metric_spaces import MetricSpaces + + +cdef class Octonion_generic(AlgebraElement): + r""" + An octonion with generic parameters. + """ + def __init__(self, parent, v): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: TestSuite(elt).run() + sage: elt = sum(O.basis()) + sage: TestSuite(elt).run() + sage: TestSuite(O.zero()).run() + + sage: O = OctonionAlgebra(Zmod(8), 1, 3, 7) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: TestSuite(elt).run() + sage: elt = sum(O.basis()) + sage: TestSuite(elt).run() + sage: TestSuite(O.zero()).run() + """ + v.set_immutable() + self.vec = v + super().__init__(parent) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: elt + 2 + 3*i + 4*j + 5*k + 6*l + 7*li + 8*lj + 9*lk + """ + from sage.algebras.weyl_algebra import repr_from_monomials + data = [p for p in enumerate(self.vec) if p[1]] + return repr_from_monomials(data, self._parent._repr_term) + + def _latex_(self): + r""" + Return a `\LaTeX` representation of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: latex(elt) + 2 + 3 i + 4 j + 5 k + 6 l + 7 li + 8 lj + 9 lk + """ + from sage.algebras.weyl_algebra import repr_from_monomials + data = [p for p in enumerate(self.vec) if p[1]] + return repr_from_monomials(data, self._parent._repr_term, True) + + def __bool__(self): + r""" + Return if ``self`` is non-zero or not. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: bool(elt) + True + sage: bool(O.zero()) + False + """ + return bool(self.vec) + + def __reduce__(self): + r""" + For pickling. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: x = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: x.__reduce__() + (<class 'sage.algebras.octonion_algebra.Octonion_generic'>, + (Octonion algebra over Rational Field with parameters (1, 3, 7), + (2, 3, 4, 5, 6, 7, 8, 9))) + """ + return (self.__class__, (self._parent, self.vec)) + + cpdef _richcmp_(self, other, int op): + r""" + Compare ``self`` to ``other`` with type ``op``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: x = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: y = sum(O.basis()) + sage: x != y + True + sage: x == y + False + sage: x < y + False + """ + return richcmp(self.vec, (<Octonion_generic> other).vec, op) + + def __hash__(self): + r""" + Return a hash of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: hash(elt) == hash(elt.vector()) + True + """ + return hash(self.vec) + + cpdef _add_(self, other): + r""" + Return ``self`` plus ``other``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: x = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: y = sum(O.basis()) + sage: x + y + 3 + 4*i + 5*j + 6*k + 7*l + 8*li + 9*lj + 10*lk + """ + return self.__class__(self._parent, self.vec + (<Octonion_generic> other).vec) + + cpdef _sub_(self, other): + r""" + Return ``self`` minus ``other``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: x = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: y = sum(O.basis()) + sage: x - y + 1 + 2*i + 3*j + 4*k + 5*l + 6*li + 7*lj + 8*lk + """ + return self.__class__(self._parent, self.vec - (<Octonion_generic> other).vec) + + def __neg__(self): + r""" + Return the negative of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: x = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: -x + -2 - 3*i - 4*j - 5*k - 6*l - 7*li - 8*lj - 9*lk + sage: y = sum(O.basis()) + sage: -y + -1 - i - j - k - l - li - lj - lk + """ + return self.__class__(self._parent, -self.vec) + + cpdef _lmul_(self, Element other): + r""" + Return ``self * other`` for a scalar ``other``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: i, j, k, l = O.gens() + sage: elt = 2 * i + 3 * j + k * 4 + l * 5 + sage: elt * 5 + 10*i + 15*j + 20*k + 25*l + """ + return self.__class__(self._parent, self.vec * other) + + cpdef _rmul_(self, Element other): + r""" + Return ``self * other`` for a scalar ``other``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: i, j, k, l = O.gens() + sage: elt = 2 * i + 3 * j + k * 4 + l * 5 + sage: 5 * elt + 10*i + 15*j + 20*k + 25*l + """ + return self.__class__(self._parent, other * self.vec) + + cpdef _mul_(self, other): + r""" + Return ``self`` multiplied by ``other``. + + INPUT: + + - ``other`` -- element of the octonion algebra as ``self`` + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: table([[r * c for c in O.basis()] for r in O.basis()]) + 1 i j k l li lj lk + i -1 -k j -li l lk -lj + j k -1 -i -lj -lk l li + k -j i -1 -lk lj -li l + l li lj lk -1 -i -j -k + li -l lk -lj i -1 k -j + lj -lk -l li j -k -1 i + lk lj -li -l k j -i -1 + + sage: SO = OctonionAlgebra(QQ, c=1) + sage: table([[r * c for c in SO.basis()] for r in SO.basis()]) + 1 i j k l li lj lk + i -1 -k j -li l lk -lj + j k -1 -i -lj -lk l li + k -j i -1 -lk lj -li l + l li lj lk 1 i j k + li -l lk -lj -i 1 -k j + lj -lk -l li -j k 1 -i + lk lj -li -l -k -j i 1 + """ + cdef Parent P = self._parent + cdef list ret = [P._base.zero()] * 8 + cdef tuple table = <tuple> P._mult_table + cdef tuple row + cdef int i, j, k + cdef FreeModuleElement rv = (<Octonion_generic> other).vec + for i in range(8): + row = <tuple> table[i] + cl = self.vec.get_unsafe(i) + for j in range(8): + k = <int> row[j][0] + coeff = row[j][1] + cr = rv.get_unsafe(j) + ret[k] += cl * cr * coeff + return self.__class__(P, P._module(ret)) + + cpdef _div_(self, other): + """ + Return ``self`` divided by ``other``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(ZZ) + sage: x = O([0, 0, 2, 0, 2, 0, 0, 0]) + sage: y = O([1, 0, 0, 0, 1, 0, 0, 0]) + sage: y.quadratic_form() + 2 + sage: x * y.conjugate() + 2 + 2*j + 2*l + 2*lj + sage: x / y + 1 + j + l + lj + """ + cdef Octonion_generic temp = <Octonion_generic> self * (<Octonion_generic> other).conjugate() + qf = (<Octonion_generic> other).quadratic_form() + return self.__class__(self._parent, temp.vec / qf) + + def is_unit(self): + r""" + Return if ``self`` is a unit or not. + + EXAMPLES:: + + sage: O = OctonionAlgebra(ZZ) + sage: x = O([1, 0, 1, 0, 0, 0, 0, 0]) + sage: x.quadratic_form() + 2 + sage: x.is_unit() + False + sage: O([1, 0, -1, 0, 0, 0, 0, 0]).is_unit() + False + sage: x = O([1, 0, 0, 0, 1, 0, 0, 0]) + sage: x.quadratic_form() + 2 + sage: x.is_unit() + False + sage: x = O([0, 0, 0, 0, 1, 0, 0, 0]) + sage: x.quadratic_form() + 1 + sage: x.is_unit() + True + + sage: O = OctonionAlgebra(ZZ, -1, 1, 2) + sage: x = O([1, 0, 1, 0, 0, 0, 0, 0]) + sage: x.quadratic_form() + 0 + sage: x.is_unit() + False + sage: O([1, 0, -1, 0, 0, 0, 0, 0]).is_unit() + False + sage: x = O([1, 0, 0, 0, 1, 0, 0, 0]) + sage: x.quadratic_form() + -1 + sage: x.is_unit() + True + sage: x = O([0, 0, 0, 0, 1, 0, 0, 0]) + sage: x.quadratic_form() + -2 + sage: x.is_unit() + False + """ + return self.quadratic_form().is_unit() + + def __invert__(self): + r""" + Return the (multiplicative) inverse of ``self``. + + EXAMPLES:: + + sage: O137 = OctonionAlgebra(QQ, 1, 3, 7) + sage: elt = sum(O137.basis()) + sage: elt.quadratic_form() + 0 + sage: ~elt + Traceback (most recent call last): + ... + ZeroDivisionError: rational division by zero + sage: ~O137.zero() + Traceback (most recent call last): + ... + ZeroDivisionError + """ + if not self.vec: + raise ZeroDivisionError + return self.quadratic_form().inverse_of_unit() * self.conjugate() + + cpdef Octonion_generic conjugate(self): + r""" + Return the conjugate of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: elt = sum(O.basis()); elt + 1 + i + j + k + l + li + lj + lk + sage: elt.conjugate() + 1 - i - j - k - l - li - lj - lk + """ + cdef FreeModuleElement v = <FreeModuleElement> -self.vec + v.set_unsafe(0, -v.get_unsafe(0)) + return self.__class__(self._parent, v) + + cpdef quadratic_form(self): + r""" + Return the quadratic form of ``self``. + + The octonion algebra has a distinguished quadratic form given + by `N(x) = x x^*`, where `x^*` is the :meth:`conjugate` of `x`. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: elt = sum(O.basis()) + sage: elt.quadratic_form() + 0 + sage: elt * elt.conjugate() + 0 + """ + cdef int i + cdef tuple table = self._parent._mult_table + ret = self.vec.get_unsafe(0) ** 2 + for i in range(1, 8): + ret += -(<tuple> table[i])[i][1] * self.vec.get_unsafe(i) ** 2 + return ret + + cpdef norm(self): + r""" + Return the norm of ``self``. + + The norm of an octonion `x` is `\lVert x \rVert = \sqrt{x x^*}`, + where `x^*` is the :meth:`conjugate` of `x`. + + .. SEEALSO:: + + This is the square root of :meth:`quadratic_form()`. + + .. WARNING:: + + If any of the parameters `a, b, c \not> 0`, then this is not + an actual norm. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: elt.norm() + 2*sqrt(-61) + sage: elt = sum(O.basis()) + sage: elt.norm() + 0 + """ + return sqrt(self.quadratic_form()) + + cpdef abs(self): + r""" + Return the absolute value of ``self``. + + This is equal to the :meth:`norm`. + + .. WARNING:: + + If any of the parameters `a, b, c \not> 0`, then this does + not define a metric. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: elt.abs() + 2*sqrt(-61) + sage: elt = sum(O.basis()) + sage: elt.abs() + 0 + """ + return self.norm() + + cpdef real_part(self): + r""" + Return the real part of ``self``. + + OUTPUT: + + The real part of ``self`` as an element in the base ring. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)); elt + 2 + 3*i + 4*j + 5*k + 6*l + 7*li + 8*lj + 9*lk + sage: r = elt.real_part(); r + 2 + sage: r.parent() is QQ + True + """ + return self.vec.get_unsafe(0) + + cpdef Octonion_generic imag_part(self): + r""" + Return the imginary part of ``self``. + + OUTPUT: + + The imaginary part of ``self`` as an element in the octonion algebra. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)); elt + 2 + 3*i + 4*j + 5*k + 6*l + 7*li + 8*lj + 9*lk + sage: elt.imag_part() + 3*i + 4*j + 5*k + 6*l + 7*li + 8*lj + 9*lk + + TESTS:: + + sage: O = OctonionAlgebra(QQ) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: elt.imag_part() + 3*i + 4*j + 5*k + 6*l + 7*li + 8*lj + 9*lk + sage: elt + 2 + 3*i + 4*j + 5*k + 6*l + 7*li + 8*lj + 9*lk + """ + cdef FreeModuleElement v = <FreeModuleElement> self.vec.__copy__() + v.set_unsafe(0, self._parent._base.zero()) + return self.__class__(self._parent, v) + + def _vector_(self, new_base_ring=None): + r""" + Return ``self`` as a vector in `R^8`, where `R` is the base + ring of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: elt.vector() + (2, 3, 4, 5, 6, 7, 8, 9) + """ + if new_base_ring is None: + return self.vec + return self.vec.change_ring(new_base_ring) + + vector = _vector_ + + def monomial_coefficients(self, copy=False): + """ + Return ``self`` as a ``dict`` with keys being indices + for the basis and the values being the corresponding + nonzero coefficients. + + INPUT: + + - ``copy`` -- ignored + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: x = O([2/7, 0, 0, 0, 2/3, 0, -5, 0]) + sage: x.monomial_coefficients() + {0: 2/7, 4: 2/3, 6: -5} + """ + return self.vec.dict() + + dict = monomial_coefficients + + +cdef class Octonion(Octonion_generic): + r""" + An octonion. + + This is an element of the octonion algebra with parameters + `a = b = c = -1`, which is a classical octonion number. + """ + cpdef quadratic_form(self): + r""" + Return the quadratic form of ``self``. + + The octonion algebra has a distinguished quadratic form given + by `N(x) = x x^*`, where `x^*` is the :meth:`conjugate` of `x`. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: elt = sum(O.basis()); elt + 1 + i + j + k + l + li + lj + lk + sage: elt.quadratic_form() + 8 + sage: elt * elt.conjugate() + 8 + """ + return self.vec * self.vec + + cpdef norm(self): + r""" + Return the norm of ``self``. + + The norm of an octonion `x` is `\lVert x \rVert = \sqrt{x x^*}`, + where `x^*` is the :meth:`conjugate` of `x`. + + .. SEEALSO:: + + This is the square root of :meth:`quadratic_form()`. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) + sage: elt.norm() + 2*sqrt(71) + sage: elt = sum(O.basis()) + sage: elt.norm() + 2*sqrt(2) + """ + return self.vec.norm() + + +class OctonionAlgebra(UniqueRepresentation, Parent): + r""" + The octonion algebra. + + Let `R` be a commutative ring of characteristic not equal to `2`. The + *octonion algebra* with parameters `a, b, c` is a non-associative + non-commutative unital 8-dimensional `R`-algebra that is a deformation + of the usual octonions, which are when `a = b = c = -1`. The octonions + were originally constructed by Graves and independently discovered by + Cayley (due to being published first, these are sometimes called + the Cayley numbers) and can also be built from the Cayley-Dickson + construction with the :class:`quaternions <QuaternionAlgebra>`. + + We use the multiplication table from [Scha1996]_. The octonion + algebra `\mathbf{O}_{a,b,c}(R)` is a composition (Hurwitz) algebra, + which means it is also an alternative algebra as it satisfies + `x^2 y = (x x) y = x (x y)` and `y x^2 = y (x x) = (y x) x` + for all `x, y \in \mathbf{O}_{a,b,c}`. + + EXAMPLES: + + We first create the classical octonions and perform some basic + computations:: + + sage: O = OctonionAlgebra(QQ) + sage: O + Octonion algebra over Rational Field + sage: i, j, k, l = O.gens() + sage: i * j * k + 1 + sage: k * j * i + -1 + sage: (i * k) * l + -lj + sage: i * (k * l) + lj + sage: elt = sum(O.basis()) + sage: elt^2 + -6 + 2*i + 2*j + 2*k + 2*l + 2*li + 2*lj + 2*lk + sage: prod(O.basis()) + 1 + sage: (i + l)^2 + -2 + sage: (1 + l) * (1 + l).conjugate() + 2 + sage: S = O.some_elements() + sage: B = O.basis() + sage: S.extend(x * (i + j/2 - 5*k/3) for x in O.some_elements()) + sage: all((x * x) * y == (x * (x * y)) for x in S for y in S) + True + sage: all(y * (x * x) == (y * x) * x for x in S for y in S) + True + sage: all((x + x.conjugate()) / 2 == x.real_part() for x in S) + True + sage: all((x - x.conjugate()) / 2 == x.imag_part() for x in S) + True + sage: all(sum((b*x)*b for b in B) == -6 * x.conjugate() for x in S) + True + + We construct the (rescaled) `E_8` lattice as the integral octonions, + which we verify by constructing `240` shortest length elements in + the lattice (see also :wikipedia:`E8_lattice#Integral_octonions`):: + + sage: m = (i + j + k + l) / 2 + sage: basis = [i, j, i*j, i^2, m, i * m, j * m, (i * j) * m] + sage: basis + [i, + j, + -k, + -1, + 1/2*i + 1/2*j + 1/2*k + 1/2*l, + -1/2 + 1/2*j - 1/2*k - 1/2*li, + -1/2 - 1/2*i + 1/2*k - 1/2*lj, + 1/2 - 1/2*i + 1/2*j + 1/2*lk] + sage: matrix([vector(b) for b in basis]).rank() + 8 + sage: [b.norm() for b in basis] + [1, 1, 1, 1, 1, 1, 1, 1] + sage: roots = set(basis) + sage: roots.update(-b for b in basis) + sage: new_roots = set(roots) # make a copy + sage: while new_roots: + ....: prev_roots = new_roots + ....: new_roots = set() + ....: for a in prev_roots: + ....: for b in roots: + ....: c = a + b + ....: if c.quadratic_form() != 1 or c in roots: + ....: continue + ....: new_roots.update([c, -c]) + ....: roots.update(new_roots) + sage: len(roots) + 240 + + A classical construction of the Lie algebra of type `G_2` is + the Lie algebra of all derivations of `\mathbf{O}` (as the + automorphism group is the Lie group of type `G_2`). We verify + that the derivations have the correct dimension:: + + sage: len(O.derivations_basis()) + 14 + + We can construct the split octonions by taking the parameter `c = 1`:: + + sage: SO = OctonionAlgebra(QQ, c=1) + sage: SO + Octonion algebra over Rational Field with parameters (-1, -1, 1) + sage: i, j, k, l = SO.gens() + sage: i^2 == j^2 == k^2 == -1 + True + sage: l^2 + 1 + sage: (i + l)^2 + 0 + sage: (1 + l) * (1 + l).conjugate() + 0 + + REFERENCES: + + - [Scha1996]_ + - :wikipedia:`octonion` + - :wikipedia:`Split-octonion` + - :wikipedia:`Hurwitz's_theorem_(composition_algebras)` + """ + @staticmethod + def __classcall_private__(cls, R, a=-1, b=-1, c=-1, names=('i', 'j', 'k', 'l')): + r""" + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: O1 = OctonionAlgebra(QQ, 1) + sage: O2 = OctonionAlgebra(QQ, QQ.one(), -1, QQ['x'](-1)) + sage: O3 = algebras.Octonion(QQ, QQ.one(), c=int(-1), names='ijkl') + sage: O1 is O2 + True + sage: O1 is O3 + True + + sage: OctonionAlgebra(ExteriorAlgebra(QQ, 3)) + Traceback (most recent call last): + ... + ValueError: the base ring must be a commutative ring + sage: OctonionAlgebra(GF(2)['x','y','z']) + Traceback (most recent call last): + ... + ValueError: the characteristic must not be 2 + """ + if R not in Rings().Commutative(): + raise ValueError("the base ring must be a commutative ring") + if R.one() + R.one() == R.zero(): + raise ValueError("the characteristic must not be 2") + a = R(a) + b = R(b) + c = R(c) + names = normalize_names(4, names) + return super().__classcall__(cls, R, a, b, c, names) + + def __init__(self, R, a, b, c, names): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: TestSuite(O).run() + + sage: O = OctonionAlgebra(QQ, 1, 3, 7) + sage: TestSuite(O).run() + + sage: O = OctonionAlgebra(GF(3), 1, 2, 2) + sage: TestSuite(O).run() + + sage: O = OctonionAlgebra(Zmod(6), -1, 2, 3) + sage: TestSuite(O).run() + + sage: R.<a, b, c> = QQ[] + sage: O = OctonionAlgebra(R, a, b, c) + sage: TestSuite(O).run() + """ + self._params = (a, b, c) + self._module = FreeModule(R, 8) + cat = MagmaticAlgebras(R.category()).Unital().WithBasis().FiniteDimensional() + if a == b == c == -1: + self.Element = Octonion + if R in MetricSpaces(): + cat &= MetricSpaces() + Parent.__init__(self, base=R, category=cat, names=names) + + # setup the multiplication table + d = a * b + e = a * c + f = b * c + g = a * b * c + self._mult_table = ( + ((0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1)), + ((1, 1), (0, a), (3, -1), (2, -a), (5, -1), (4, -a), (7, 1), (6, a)), + ((2, 1), (3, 1), (0, b), (1, b), (6, -1), (7, -1), (4, -b), (5, -b)), + ((3, 1), (2, a), (1, -b), (0, -d), (7, -1), (6, -a), (5, b), (4, d)), + ((4, 1), (5, 1), (6, 1), (7, 1), (0, c), (1, c), (2, c), (3, c)), + ((5, 1), (4, a), (7, 1), (6, a), (1, -c), (0, -e), (3, -c), (2, -e)), + ((6, 1), (7, -1), (4, b), (5, -b), (2, -c), (3, c), (0, -f), (1, f)), + ((7, 1), (6, -a), (5, b), (4, -d), (3, -c), (2, e), (1, -f), (0, g)), + ) + + def _test_alternative(self, **options): + r""" + Test that ``self`` is an alternative algebra. + + An algebra `A` is *alternative* if for all `x, y \in A`, we have + `(x * x) * y = x * (x * y)` and `(y * x) * x = y * (x * x)`. + + EXAMPLES:: + + sage: R.<a,b,c> = QQ[] + sage: O = OctonionAlgebra(R, a, b, c) + sage: O._test_alternative() + """ + tester = self._tester(**options) + S = tester.some_elements() + from sage.misc.misc import some_tuples + for x, y in some_tuples(S, 2, tester._max_runs): + tester.assertEqual((x * x) * y, x * (x * y)) + tester.assertEqual(y * (x * x), (y * x) * x) + + def _test_hurwitz(self, **options): + r""" + Test that ``self`` is an Hurwitz algebra. + + An algebra `A` is *Hurwitz* if there exists a nondegenerate quadratic + form `N` such that `N(x y) = N(x) N(y)` for all `x, y \in A`. + + EXAMPLES:: + + sage: R.<a,b,c> = QQ[] + sage: O = OctonionAlgebra(R, a, b, c) + sage: O._test_hurwitz() + """ + tester = self._tester(**options) + S = tester.some_elements() + from sage.misc.misc import some_tuples + for x, y in some_tuples(S, 2, tester._max_runs): + tester.assertEqual((x * y).quadratic_form(), x.quadratic_form() * y.quadratic_form()) + + def _repr_term(self, m): + r""" + Return a string representation of the term indexed by ``m``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(QQ) + sage: [O._repr_term(i) for i in range(8)] + ['1', 'i', 'j', 'k', 'l', 'li', 'lj', 'lk'] + """ + data = ['1', 'i', 'j', 'k', 'l', 'li', 'lj', 'lk'] + return data[m] + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: OctonionAlgebra(QQ) + Octonion algebra over Rational Field + sage: OctonionAlgebra(QQ, 1, 3, 7) + Octonion algebra over Rational Field with parameters (1, 3, 7) + """ + ret = f"Octonion algebra over {self.base_ring()}" + a, b, c = self._params + if a != -1 or b != -1 or c != -1: + ret += f" with parameters ({a}, {b}, {c})" + return ret + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: latex(OctonionAlgebra(QQ)) + \Bold{O}\left(\Bold{Q}\right) + sage: latex(OctonionAlgebra(QQ, 1, 3, 7)) + \Bold{O}_{1, 3, 7}\left(\Bold{Q}\right) + """ + from sage.misc.latex import latex + ret = r"\Bold{O}" + a, b, c = self._params + if a != -1 or b != -1 or c != -1: + ret += r"_{{{}, {}, {}}}".format(latex(a), latex(b), latex(c)) + return ret + r"\left({}\right)".format(latex(self.base_ring())) + + def _element_constructor_(self, x): + r""" + Construct an element of ``self``. + + EXAMPLES:: + + sage: O137 = OctonionAlgebra(QQ, 1, 3, 7) + sage: x = O137([1, 5, 2, 3, 6, -2, 3, -3]); x + 1 + 5*i + 2*j + 3*k + 6*l - 2*li + 3*lj - 3*lk + sage: O = OctonionAlgebra(ZZ) + sage: y = O([1, 5, 2, 3, 6, -2, 3, -3]) + sage: O(x) + 1 + 5*i + 2*j + 3*k + 6*l - 2*li + 3*lj - 3*lk + sage: O137(y) + 1 + 5*i + 2*j + 3*k + 6*l - 2*li + 3*lj - 3*lk + + sage: xp = O137([1, 5, 2, 3, 6, -2/3, 3, -3]); xp + 1 + 5*i + 2*j + 3*k + 6*l - 2/3*li + 3*lj - 3*lk + sage: O(xp) + Traceback (most recent call last): + ... + TypeError: no conversion of this rational to integer + sage: O([1, 5, 2, 3, 6, -2, 3, -3/4]) + Traceback (most recent call last): + ... + TypeError: no conversion of this rational to integer + """ + if isinstance(x, Octonion_generic): + v = self._module((<Octonion_generic> x).vec) + elif self.base_ring().has_coerce_map_from(parent(x)): + R = self.base_ring() + v = self._module([R(x)] + [R.zero()]*7) + else: + v = self._module(x) + return self.element_class(self, v) + + def some_elements(self): + r""" + Return some elements of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(ZZ) + sage: O.some_elements() + [2, 1, i, j, k, l, li, lj, lk, + 2 + 3*i + 4*j + 5*k + 6*l + 7*li + 8*lj + 9*lk, + -2*j + 3*k - li - lj, + 8 - 7*i + 2*j + 13*k - 18*l + 45*li - 40*lj + 5*lk] + sage: O = OctonionAlgebra(Zmod(6)) + sage: O.some_elements() + [2, 1, i, j, k, l, li, lj, lk, + 2 + 3*i + 4*j + 5*k + li + 2*lj + 3*lk, + 4*j + 3*k + 5*li + 5*lj, + 2 + 5*i + 2*j + k + 3*li + 2*lj + 5*lk] + """ + elts = [self.an_element()] + elts.extend(self.basis()) + elt = sum(i * b for i, b in enumerate(self.basis(), start=2)) + elts.append(elt) + elt2 = self([0, 0, -2, 3, 0, -1, -1, 0]) + elts.append(elt2) + elts.append(elt * elt2) + return elts + + @cached_method + def one_basis(self): + r""" + Return the index for the basis element of `1`. + + EXAMPLES:: + + sage: O = OctonionAlgebra(ZZ) + sage: O.one_basis() + 0 + """ + return 0 + + @cached_method + def gens(self): + r""" + Return the generators of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(ZZ) + sage: O.gens() + (i, j, k, l) + """ + e = self._module.basis() + return tuple([self.element_class(self, v) for v in e[1:5]]) + + @cached_method + def basis(self): + r""" + Return the basis of ``self``. + + EXAMPLES:: + + sage: O = OctonionAlgebra(ZZ) + sage: O.basis() + Family (1, i, j, k, l, li, lj, lk) + """ + e = self._module.basis() + from sage.sets.family import Family + return Family([self.element_class(self, v) for v in e]) + + Element = Octonion_generic diff --git a/src/sage/algebras/orlik_solomon.py b/src/sage/algebras/orlik_solomon.py index 4f256fe7777..920056787c6 100644 --- a/src/sage/algebras/orlik_solomon.py +++ b/src/sage/algebras/orlik_solomon.py @@ -446,6 +446,88 @@ def degree_on_basis(self, m): """ return len(m) + def as_gca(self): + r""" + Return the graded commutative algebra corresponding to ``self``. + + EXAMPLES:: + + sage: H = hyperplane_arrangements.braid(3) + sage: O = H.orlik_solomon_algebra(QQ) + sage: O.as_gca() + Graded Commutative Algebra with generators ('e0', 'e1', 'e2') in degrees (1, 1, 1) + with relations [e0*e1 - e0*e2 + e1*e2] over Rational Field + + :: + + sage: N = matroids.named_matroids.Fano() + sage: O = N.orlik_solomon_algebra(QQ) + sage: O.as_gca() + Graded Commutative Algebra with generators ('e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6') + in degrees (1, 1, 1, 1, 1, 1, 1) with relations + [e1*e2 - e1*e3 + e2*e3, e0*e1*e3 - e0*e1*e4 + e0*e3*e4 - e1*e3*e4, + e0*e2 - e0*e4 + e2*e4, e3*e4 - e3*e5 + e4*e5, + e1*e2*e4 - e1*e2*e5 + e1*e4*e5 - e2*e4*e5, + e0*e2*e3 - e0*e2*e5 + e0*e3*e5 - e2*e3*e5, e0*e1 - e0*e5 + e1*e5, + e2*e5 - e2*e6 + e5*e6, e1*e3*e5 - e1*e3*e6 + e1*e5*e6 - e3*e5*e6, + e0*e4*e5 - e0*e4*e6 + e0*e5*e6 - e4*e5*e6, e1*e4 - e1*e6 + e4*e6, + e2*e3*e4 - e2*e3*e6 + e2*e4*e6 - e3*e4*e6, e0*e3 - e0*e6 + e3*e6, + e0*e1*e2 - e0*e1*e6 + e0*e2*e6 - e1*e2*e6] over Rational Field + + TESTS:: + + sage: H = hyperplane_arrangements.Catalan(3,QQ).cone() + sage: O = H.orlik_solomon_algebra(QQ) + sage: A = O.as_gca() + sage: H.poincare_polynomial() + 20*x^3 + 29*x^2 + 10*x + 1 + sage: [len(A.basis(i)) for i in range(5)] + [1, 10, 29, 20, 0] + + """ + from sage.algebras.commutative_dga import GradedCommutativeAlgebra + gens = self.algebra_generators() + gkeys = gens.keys() + names = ['e{}'.format(i) for i in range(len(gens))] + A = GradedCommutativeAlgebra(self.base_ring(), names) + rels = [] + for bc in self._broken_circuits.items(): + bclist = [bc[1]] + list(bc[0]) + indices = [gkeys.index(el) for el in bclist] + indices.sort() + rel = A.zero() + sign = -(-1)**len(indices) + for i in indices: + mon = A.one() + for j in indices: + if j != i: + mon *= A.gen(j) + rel += sign * mon + sign = -sign + rels.append(rel) + I = A.ideal(rels) + return A.quotient(I) + + def as_cdga(self): + r""" + Return the commutative differential graded algebra corresponding to ``self`` + with the trivial differential. + + EXAMPLES:: + + sage: H = hyperplane_arrangements.braid(3) + sage: O = H.orlik_solomon_algebra(QQ) + sage: O.as_cdga() + Commutative Differential Graded Algebra with generators ('e0', 'e1', 'e2') + in degrees (1, 1, 1) with relations [e0*e1 - e0*e2 + e1*e2] over Rational Field + with differential: + e0 --> 0 + e1 --> 0 + e2 --> 0 + """ + return self.as_gca().cdg_algebra({}) + + class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): r""" The invariant algebra of the Orlik-Solomon algebra from the diff --git a/src/sage/algebras/q_commuting_polynomials.py b/src/sage/algebras/q_commuting_polynomials.py index d1aae987d61..a50b2335787 100644 --- a/src/sage/algebras/q_commuting_polynomials.py +++ b/src/sage/algebras/q_commuting_polynomials.py @@ -4,10 +4,11 @@ AUTHORS: - Travis Scrimshaw (2022-08-23): Initial version +- Travis Scrimshaw (2023-02-10): Added Laurent polynomials """ # **************************************************************************** -# Copyright (C) 2022 Travis Scrimshaw <tcscrims at gmail.com> +# Copyright (C) 2022-2023 Travis Scrimshaw <tcscrims at gmail.com> # # 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 @@ -17,21 +18,26 @@ # **************************************************************************** from sage.misc.cachefunc import cached_method +from sage.misc.latex import latex from sage.sets.family import Family from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.categories.algebras import Algebras +from sage.categories.commutative_rings import CommutativeRings from sage.combinat.free_module import CombinatorialFreeModule from sage.monoids.free_abelian_monoid import FreeAbelianMonoid +from sage.groups.free_group import FreeGroup +from sage.modules.free_module import FreeModule from sage.matrix.constructor import matrix from sage.structure.element import Matrix -class qCommutingPolynomials(CombinatorialFreeModule): + +class qCommutingPolynomials_generic(CombinatorialFreeModule): r""" - The algebra of `q`-commuting polynomials. + Base class for algebra of `q`-commuting (Laurent, etc.) polynomials. Let `R` be a commutative ring, and fix an element `q \in R`. Let - B = (B_{xy})_{x,y \in I}` be a skew-symmetric bilinear form with + `B = (B_{xy})_{x,y \in I}` be a skew-symmetric bilinear form with index set `I`. Let `R[I]_{q,B}` denote the polynomial ring in the variables `I` such that we have the `q`-*commuting* relation for `x, y \in I`: @@ -41,51 +47,9 @@ class qCommutingPolynomials(CombinatorialFreeModule): This is a graded `R`-algebra with a natural basis given by monomials written in increasing order with respect to some total order on `I`. - - When `B_{xy} = 1` and `B_{yx} = -1` for all `x < y`, then we have - a `q`-analog of the classical binomial coefficient theorem: - - .. MATH:: - - (x + y)^n = \sum_{k=0}^n \binom{n}{k}_q x^k y^{n-k}. - - EXAMPLES:: - - sage: q = ZZ['q'].fraction_field().gen() - sage: R.<x,y> = algebras.qCommutingPolynomials(q) - - We verify a case of the `q`-binomial theorem:: - - sage: f = (x + y)^10 - sage: all(f[b] == q_binomial(10, b.list()[0]) for b in f.support()) - True - - We now do a computation with a non-standard `B` matrix:: - - sage: B = matrix([[0,1,2],[-1,0,3],[-2,-3,0]]) - sage: B - [ 0 1 2] - [-1 0 3] - [-2 -3 0] - sage: q = ZZ['q'].gen() - sage: R.<x,y,z> = algebras.qCommutingPolynomials(q, B) - sage: y * x - q*x*y - sage: z * x - q^2*x*z - sage: z * y - q^3*y*z - - sage: f = (x + z)^10 - sage: all(f[b] == q_binomial(10, b.list()[0], q^2) for b in f.support()) - True - - sage: f = (y + z)^10 - sage: all(f[b] == q_binomial(10, b.list()[1], q^3) for b in f.support()) - True """ @staticmethod - def __classcall_private__(cls, q, n=None, B=None, base_ring=None, names=None): + def __classcall__(cls, q, n=None, B=None, base_ring=None, names=None): r""" Normalize input to ensure a unique representation. @@ -118,8 +82,8 @@ def __classcall_private__(cls, q, n=None, B=None, base_ring=None, names=None): B = matrix.zero(ZZ, n) for i in range(n): for j in range(i+1, n): - B[i,j] = 1 - B[j,i] = -1 + B[i, j] = 1 + B[j, i] = -1 B.set_immutable() else: if not B.is_skew_symmetric(): @@ -128,7 +92,7 @@ def __classcall_private__(cls, q, n=None, B=None, base_ring=None, names=None): B.set_immutable() return super().__classcall__(cls, q=q, B=B, names=names) - def __init__(self, q, B, names): + def __init__(self, q, B, indices, names): r""" Initialize ``self``. @@ -141,45 +105,13 @@ def __init__(self, q, B, names): self._q = q self._B = B base_ring = q.parent() - indices = FreeAbelianMonoid(len(names), names) + if base_ring not in CommutativeRings(): + raise ValueError("the base ring must be a commutative ring") category = Algebras(base_ring).WithBasis().Graded() CombinatorialFreeModule.__init__(self, base_ring, indices, bracket=False, prefix='', - sorting_key=qCommutingPolynomials._term_key, - names=indices.variable_names(), category=category) - - def _repr_(self): - r""" - Return a string representation of ``self``. - - EXAMPLES:: - - sage: q = ZZ['q'].fraction_field().gen() - sage: R.<x,y,z> = algebras.qCommutingPolynomials(q) - sage: R - q-commuting polynomial ring in x, y, z over Fraction Field of - Univariate Polynomial Ring in q over Integer Ring with matrix: - [ 0 1 1] - [-1 0 1] - [-1 -1 0] - """ - names = ", ".join(self.variable_names()) - return "{}-commuting polynomial ring in {} over {} with matrix:\n{}".format(self._q, names, self.base_ring(), self._B) - - def _latex_(self): - r""" - Return a latex representation of ``self``. - - EXAMPLES:: - - sage: q = ZZ['q'].fraction_field().gen() - sage: R.<x,y,z> = algebras.qCommutingPolynomials(q) - sage: latex(R) - \mathrm{Frac}(\Bold{Z}[q])[x, y, z]_{q} - """ - from sage.misc.latex import latex - names = ", ".join(self.variable_names()) - return "{}[{}]_{{{}}}".format(latex(self.base_ring()), names, self._q) + sorting_key=qCommutingPolynomials_generic._term_key, + names=names, category=category) @staticmethod def _term_key(x): @@ -239,23 +171,9 @@ def algebra_generators(self): sage: R.algebra_generators() Finite family {'x': x, 'y': y, 'z': z} """ - d = {v: self.gen(i) for i,v in enumerate(self.variable_names())} + d = {v: self.gen(i) for i, v in enumerate(self.variable_names())} return Family(self.variable_names(), d.__getitem__, name="generator") - @cached_method - def one_basis(self): - r""" - Return the basis index of the element `1`. - - EXAMPLES:: - - sage: q = ZZ['q'].fraction_field().gen() - sage: R.<x,y,z> = algebras.qCommutingPolynomials(q) - sage: R.one_basis() - 1 - """ - return self._indices.one() - def degree_on_basis(self, m): r""" Return the degree of the monomial index by ``m``. @@ -285,7 +203,137 @@ def dimension(self): """ return infinity + def q(self): + """ + Return the parameter `q`. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y,z> = algebras.qCommutingPolynomials(q) + sage: R.q() == q + True + """ + return self._q + + +class qCommutingPolynomials(qCommutingPolynomials_generic): + r""" + The algebra of `q`-commuting polynomials. + + Let `R` be a commutative ring, and fix an element `q \in R`. Let + `B = (B_{xy})_{x,y \in I}` be a skew-symmetric bilinear form with + index set `I`. Let `R[I]_{q,B}` denote the polynomial ring in the variables + `I` such that we have the `q`-*commuting* relation for `x, y \in I`: + + .. MATH:: + + y x = q^{B_{xy}} \cdot x y. + + This is a graded `R`-algebra with a natural basis given by monomials + written in increasing order with respect to some total order on `I`. + + When `B_{xy} = 1` and `B_{yx} = -1` for all `x < y`, then we have + a `q`-analog of the classical binomial coefficient theorem: + + .. MATH:: + + (x + y)^n = \sum_{k=0}^n \binom{n}{k}_q x^k y^{n-k}. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y> = algebras.qCommutingPolynomials(q) + + We verify a case of the `q`-binomial theorem:: + + sage: f = (x + y)^10 + sage: all(f[b] == q_binomial(10, b.list()[0]) for b in f.support()) + True + + We now do a computation with a non-standard `B` matrix:: + + sage: B = matrix([[0,1,2],[-1,0,3],[-2,-3,0]]) + sage: B + [ 0 1 2] + [-1 0 3] + [-2 -3 0] + sage: q = ZZ['q'].gen() + sage: R.<x,y,z> = algebras.qCommutingPolynomials(q, B) + sage: y * x + q*x*y + sage: z * x + q^2*x*z + sage: z * y + q^3*y*z + + sage: f = (x + z)^10 + sage: all(f[b] == q_binomial(10, b.list()[0], q^2) for b in f.support()) + True + + sage: f = (y + z)^10 + sage: all(f[b] == q_binomial(10, b.list()[1], q^3) for b in f.support()) + True + """ + def __init__(self, q, B, names): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y,z> = algebras.qCommutingPolynomials(q) + sage: TestSuite(R).run() + """ + indices = FreeAbelianMonoid(len(names), names) + qCommutingPolynomials_generic.__init__(self, q, B, indices, indices.variable_names()) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y,z> = algebras.qCommutingPolynomials(q) + sage: R + q-commuting polynomial ring in x, y, z over Fraction Field of + Univariate Polynomial Ring in q over Integer Ring with matrix: + [ 0 1 1] + [-1 0 1] + [-1 -1 0] + """ + names = ", ".join(self.variable_names()) + return "{}-commuting polynomial ring in {} over {} with matrix:\n{}".format(self._q, names, self.base_ring(), self._B) + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y,z> = algebras.qCommutingPolynomials(q) + sage: latex(R) + \mathrm{Frac}(\Bold{Z}[q])[x, y, z]_{q} + """ + names = ", ".join(self.variable_names()) + return "{}[{}]_{{{}}}".format(latex(self.base_ring()), names, self._q) + @cached_method + def one_basis(self): + r""" + Return the basis index of the element `1`. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y,z> = algebras.qCommutingPolynomials(q) + sage: R.one_basis() + 1 + """ + return self._indices.one() + def product_on_basis(self, x, y): r""" Return the product of two monomials given by ``x`` and ``y``. @@ -346,5 +394,278 @@ def product_on_basis(self, x, y): Ly = y.list() # This could be made more efficient - qpow = sum(exp * sum(self._B[j, i] * val for j, val in enumerate(Ly[:i])) for i, exp in enumerate(Lx)) + B = self._B + qpow = sum(exp * sum(B[j, i] * val for j, val in enumerate(Ly[:i])) for i, exp in enumerate(Lx) if exp) return self.term(x * y, self._q ** qpow) + + +class qCommutingLaurentPolynomials(qCommutingPolynomials_generic): + r""" + The algebra of `q`-commuting Laurent polynomials. + + Let `R` be a commutative ring, and fix an element `q \in R`. Let + `B = (B_{xy})_{x,y \in I}` be a skew-symmetric bilinear form with + index set `I`. Let `R[I]_{q,B}` denote the Laurent polynomial ring in + the variables `I` such that we have the `q`-*commuting* relation + for `x, y \in I`: + + .. MATH:: + + y x = q^{B_{xy}} \cdot x y. + + This is a graded `R`-algebra with a natural basis given by monomials + written in increasing order with respect to some total order on `I`. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y> = algebras.qCommutingLaurentPolynomials(q) + + We verify a case of the `q`-binomial theorem using inverse variables:: + + sage: f = (x^-1 + y^-1)^10 + sage: all(f[b] == q_binomial(10, -b.list()[0]) for b in f.support()) + True + + We now do a computation with a non-standard `B` matrix:: + + sage: B = matrix([[0,1,2],[-1,0,3],[-2,-3,0]]) + sage: B + [ 0 1 2] + [-1 0 3] + [-2 -3 0] + sage: q = ZZ['q'].gen() + sage: R.<x,y,z> = algebras.qCommutingLaurentPolynomials(q, B) + sage: y^-1 * x + 1/q*x*y^-1 + sage: z^-1 * x + 1/q^2*x*z^-1 + sage: z^-1 * y^-1 + q^3*y^-1*z^-1 + + sage: f = (x + z^-1)^10 + sage: all(f[b] == q_binomial(10, b.list()[0], q^-2) for b in f.support()) + True + + sage: f = (y^-1 + z^-1)^10 + sage: all(f[b] == q_binomial(10, -b.list()[1], q^3) for b in f.support()) + True + """ + def __init__(self, q, B, names): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y,z> = algebras.qCommutingLaurentPolynomials(q) + sage: TestSuite(R).run() + """ + indices = FreeModule(ZZ, len(names)) + self._display_group = FreeGroup(names=names, abelian=True, bracket=False) + qCommutingPolynomials_generic.__init__(self, q, B, indices, names) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y,z> = algebras.qCommutingLaurentPolynomials(q) + sage: R + q-commuting Laurent polynomial ring in x, y, z over Fraction Field of + Univariate Polynomial Ring in q over Integer Ring with matrix: + [ 0 1 1] + [-1 0 1] + [-1 -1 0] + """ + names = ", ".join(self.variable_names()) + return "{}-commuting Laurent polynomial ring in {} over {} with matrix:\n{}".format(self._q, names, self.base_ring(), self._B) + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y,z> = algebras.qCommutingLaurentPolynomials(q) + sage: latex(R) + \mathrm{Frac}(\Bold{Z}[q])[x^{\pm}, y^{\pm}, z^{\pm}]_{q} + """ + from sage.misc.latex import latex + names = ", ".join(r"{}^{{\pm}}".format(v) for v in self.variable_names()) + return "{}[{}]_{{{}}}".format(latex(self.base_ring()), names, self._q) + + def _repr_term(self, m): + r""" + Return a latex representation of the basis element indexed by ``m``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<w,x,y,z> = algebras.qCommutingLaurentPolynomials(q) + sage: R._repr_term(R._indices([1,-2,0,3])) + 'w*x^-2*z^3' + sage: R._repr_term(R.zero()) + '1' + sage: q^3 * R.one() + q^3 + """ + if not m: + return '1' + G = self._display_group + return repr(G.prod(g ** val for g, val in zip(G.gens(), m) if val != 0)) + + def _latex_term(self, m): + r""" + Return a latex representation of the basis element indexed by ``m``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<w,x,y,z> = algebras.qCommutingLaurentPolynomials(q) + sage: R._latex_term(R._indices([1,-2,0,3])) + w x^{-2} z^{3} + sage: R._latex_term(R.zero()) + '1' + sage: latex(q^3 * R.one()) + q^{3} + """ + if not m: + return '1' + G = self._display_group + return latex(G.prod(g ** val for g, val in zip(G.gens(), m) if val != 0)) + + @cached_method + def one_basis(self): + r""" + Return the basis index of the element `1`. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y,z> = algebras.qCommutingPolynomials(q) + sage: R.one_basis() + 1 + """ + return self._indices.zero() + + def product_on_basis(self, x, y): + r""" + Return the product of two monomials given by ``x`` and ``y``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y> = algebras.qCommutingLaurentPolynomials(q) + sage: R.product_on_basis(x.leading_support(), y.leading_support()) + x*y + sage: R.product_on_basis(y.leading_support(), x.leading_support()) + q*x*y + + sage: x * y + x*y + sage: y * x + q*x*y + sage: y^2 * x + q^2*x*y^2 + sage: y * x^2 + q^2*x^2*y + sage: y^-2 * x + 1/q^2*x*y^-2 + sage: y * x^-2 + 1/q^2*x^-2*y + sage: x * y * x + q*x^2*y + sage: x * y * ~x + 1/q*y + sage: y^2 * x^2 + q^4*x^2*y^2 + sage: y^-2 * x^2 + 1/q^4*x^2*y^-2 + sage: y^-2 * x^-2 + q^4*x^-2*y^-2 + sage: (x + y)^4 + x^4 + (q^3+q^2+q+1)*x^3*y + (q^4+q^3+2*q^2+q+1)*x^2*y^2 + (q^3+q^2+q+1)*x*y^3 + y^4 + + With a non-standard `B` matrix:: + + sage: B = matrix([[0,1,2],[-1,0,3],[-2,-3,0]]) + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y,z> = algebras.qCommutingLaurentPolynomials(q, B=B) + sage: x * y + x*y + sage: y * x^2 + q^2*x^2*y + sage: z^2 * x + q^4*x*z^2 + sage: z^2 * x^3 + q^12*x^3*z^2 + sage: z^2 * y + q^6*y*z^2 + sage: z^2 * y^3 + q^18*y^3*z^2 + sage: x * y^-1 + x*y^-1 + sage: y * x^-2 + 1/q^2*x^-2*y + sage: z^-2 * x + 1/q^4*x*z^-2 + sage: z^-2 * x^-3 + q^12*x^-3*z^-2 + sage: z^2 * y^-1 + 1/q^6*y^-1*z^2 + sage: z^2 * y^-3 + 1/q^18*y^-3*z^2 + """ + # Special case for multiplying by 1 + if x == self.one_basis(): + return self.monomial(y) + if y == self.one_basis(): + return self.monomial(x) + + # This could be made more efficient + B = self._B + qpow = sum(exp * sum(B[j, i] * y[j] for j in range(i)) for i, exp in enumerate(x) if exp) + ret = x + y + ret.set_immutable() + return self.term(ret, self._q ** qpow) + + class Element(qCommutingPolynomials_generic.Element): + def __invert__(self): + r""" + Return the (multiplicative) inverse of ``self``. + + EXAMPLES:: + + sage: B = matrix([[0,1,2],[-1,0,3],[-2,-3,0]]) + sage: q = ZZ['q'].fraction_field().gen() + sage: R.<x,y,z> = algebras.qCommutingLaurentPolynomials(q, B=B) + sage: ~x + x^-1 + sage: ~(x * y^-2) + 1/q^2*x^-1*y^2 + sage: for a, b in cartesian_product([R.gens(), R.gens()]): + ....: elt = a * b + ....: assert ~elt * elt == R.one(), elt + ....: assert elt * ~elt == R.one(), elt + sage: elt = x^2 * y^-3 * z + sage: ~elt + 1/q^11*x^-2*y^3*z^-1 + sage: elt * ~elt == ~elt * elt == R.one() + True + """ + if len(self._monomial_coefficients) == 1: + P = self.parent() + B = P._B + q = P._q + m, c = next(iter(self._monomial_coefficients.items())) + ret = -m + n = len(m) + qpow = sum(exp * sum(B[j, i] * m[j] for j in range(i+1, n)) + for i, exp in enumerate(m) if exp) + ret.set_immutable() + return P.term(ret, ~c * q**-qpow) + return super().__invert__() diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index 1e57682f255..2b85615cf20 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -27,7 +27,7 @@ from sage.rings.fraction_field import FractionField from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from itertools import product -from sage.misc.misc import powerset +from sage.combinat.subset import powerset class QuantumCliffordAlgebra(CombinatorialFreeModule): r""" @@ -288,14 +288,14 @@ def algebra_generators(self): for i in range(self._n): r = list(zero) # Make a copy r[i] = 1 - d['psi%s'%i] = self.monomial( (self._psi(r), one) ) + d['psi%s' % i] = self.monomial((self._psi(r), one)) r[i] = -1 - d['psid%s'%i] = self.monomial( (self._psi(r), one) ) + d['psid%s' % i] = self.monomial((self._psi(r), one)) zero = self._psi(zero) for i in range(self._n): temp = list(zero) # Make a copy temp[i] = 1 - d['w%s'%i] = self.monomial( (zero, tuple(temp)) ) + d['w%s' % i] = self.monomial((zero, tuple(temp))) return Family(sorted(d), lambda i: d[i]) @cached_method @@ -397,10 +397,10 @@ def _repr_term(self, m): 5 """ p, v = m - rp = '*'.join('psi%s'%i if p[i] > 0 else 'psid%s'%i + rp = '*'.join('psi%s' % i if p[i] > 0 else 'psid%s' % i for i in range(self._n) if p[i] != 0) - gen_str = lambda e: '' if e == 1 else '^%s'%e - rv = '*'.join('w%s'%i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) + gen_str = lambda e: '' if e == 1 else '^%s' % e + rv = '*'.join('w%s' % i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) if rp: if rv: return rp + '*' + rv @@ -429,10 +429,10 @@ def _latex_term(self, m): 5 """ p, v = m - rp = ''.join('\\psi_{%s}'%i if p[i] > 0 else '\\psi^{\\dagger}_{%s}'%i + rp = ''.join('\\psi_{%s}' % i if p[i] > 0 else '\\psi^{\\dagger}_{%s}' % i for i in range(self._n) if p[i] != 0) - gen_str = lambda e: '' if e == 1 else '^{%s}'%e - rv = ''.join('\\omega_{%s}'%i + gen_str(v[i]) + gen_str = lambda e: '' if e == 1 else '^{%s}' % e + rv = ''.join('\\omega_{%s}' % i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) if not rp and not rv: return '1' @@ -700,15 +700,15 @@ def _repr_term(self, m): def ppr(i): val = p[i] if val == -1: - return 'psid%s'%i + return 'psid%s' % i elif val == 1: - return 'psi%s'%i + return 'psi%s' % i elif val == 2: - return 'psi%s*psid%s'%(i,i) + return 'psi%s*psid%s' % (i,i) rp = '*'.join(ppr(i) for i in range(self._n) if p[i] != 0) - gen_str = lambda e: '' if e == 1 else '^%s'%e - rv = '*'.join('w%s'%i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) + gen_str = lambda e: '' if e == 1 else '^%s' % e + rv = '*'.join('w%s' % i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) if rp: if rv: return rp + '*' + rv @@ -741,15 +741,15 @@ def _latex_term(self, m): def ppr(i): val = p[i] if val == -1: - return '\\psi^{\\dagger}_{%s}'%i + return '\\psi^{\\dagger}_{%s}' % i elif val == 1: - return '\\psi_{%s}'%i + return '\\psi_{%s}' % i elif val == 2: return '\\psi_{%s}\\psi^{\\dagger}_{%s}' % (i, i) rp = ''.join(ppr(i) for i in range(self._n) if p[i] != 0) - gen_str = lambda e: '' if e == 1 else '^{%s}'%e - rv = ''.join('\\omega_{%s}'%i + gen_str(v[i]) + gen_str = lambda e: '' if e == 1 else '^{%s}' % e + rv = ''.join('\\omega_{%s}' % i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) if not rp and not rv: return '1' @@ -875,7 +875,7 @@ def key(X): return (self._psi(p), tuple(e)) q = self._q - ret = {key(X): (-1)**len(X) * sign * q**(q_power+k*(len(pairings)%2)) + ret = {key(X): (-1)**len(X) * sign * q**(q_power+k*(len(pairings) % 2)) for X in powerset(pairings)} return self._from_dict(ret) diff --git a/src/sage/algebras/quantum_groups/quantum_group_gap.py b/src/sage/algebras/quantum_groups/quantum_group_gap.py index b901c3b8225..8925c047916 100644 --- a/src/sage/algebras/quantum_groups/quantum_group_gap.py +++ b/src/sage/algebras/quantum_groups/quantum_group_gap.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - gap_package_quagroup """ Quantum Groups Using GAP's QuaGroup Package @@ -57,8 +58,8 @@ def __init__(self, parent, libgap_elt): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: TestSuite(Q.an_element()).run() # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: TestSuite(Q.an_element()).run() """ self._libgap = libgap(libgap_elt) Element.__init__(self, parent) @@ -69,13 +70,13 @@ def _repr_(self): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: Q.an_element() # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: Q.an_element() 1 + (q)*F[a1] + E[a1] + (q^2-1-q^-2 + q^-4)*[ K1 ; 2 ] + K1 + (-q^-1 + q^-3)*K1[ K1 ; 1 ] - sage: Q = QuantumGroup(['D',4]) # optional - gap_packages - sage: Q.F_simple() # optional - gap_packages + sage: Q = QuantumGroup(['D',4]) + sage: Q.F_simple() Finite family {1: F[a1], 2: F[a2], 3: F[a3], 4: F[a4]} """ # We add some space between the terms @@ -99,13 +100,13 @@ def _latex_(self): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: latex(Q.an_element()) # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: latex(Q.an_element()) 1+{(q)} F_{\alpha_{1}}+E_{\alpha_{1}}+{(q^{2}-1-q^{-2}+q^{-4})} [ K_{1} ; 2 ]+K_{1}+{(-q^{-1}+q^{-3})} K_{1}[ K_{1} ; 1 ] - sage: Q = QuantumGroup(['D',4]) # optional - gap_packages - sage: latex(list(Q.F_simple())) # optional - gap_packages + sage: Q = QuantumGroup(['D',4]) + sage: latex(list(Q.F_simple())) \left[F_{\alpha_{1}}, F_{\alpha_{2}}, F_{\alpha_{3}}, F_{\alpha_{4}}\right] """ @@ -135,9 +136,9 @@ def __reduce__(self): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: x = Q.an_element() # optional - gap_packages - sage: loads(dumps(x)) == x # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: x = Q.an_element() + sage: loads(dumps(x)) == x True """ data = self._libgap.ExtRepOfObj() @@ -154,9 +155,9 @@ def __hash__(self): EXAMPLES:: - sage: Q = QuantumGroup(['B',3]) # optional - gap_packages - sage: x = Q.an_element() # optional - gap_packages - sage: hash(x) == hash(x.gap()) # optional - gap_packages + sage: Q = QuantumGroup(['B',3]) + sage: x = Q.an_element() + sage: hash(x) == hash(x.gap()) True """ return hash(self._libgap) @@ -167,17 +168,17 @@ def _richcmp_(self, other, op): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: x = Q.an_element() # optional - gap_packages - sage: F1, F12, F2 = Q.F() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: x == F1 # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: x = Q.an_element() + sage: F1, F12, F2 = Q.F() + sage: q = Q.q() + sage: x == F1 False - sage: x != F1 # optional - gap_packages + sage: x != F1 True - sage: F2 * F1 # optional - gap_packages + sage: F2 * F1 (q)*F[a1]*F[a2] + F[a1+a2] - sage: F2 * F1 == q * F1 * F2 + F12 # optional - gap_packages + sage: F2 * F1 == q * F1 * F2 + F12 True """ return richcmp(self._libgap, other._libgap, op) @@ -188,9 +189,9 @@ def gap(self): EXAMPLES:: - sage: Q = QuantumGroup(['B',3]) # optional - gap_packages - sage: x = Q.an_element() # optional - gap_packages - sage: x.gap() # optional - gap_packages + sage: Q = QuantumGroup(['B',3]) + sage: x = Q.an_element() + sage: x.gap() 1+(q)*F1+E1+(q^4-1-q^-4+q^-8)*[ K1 ; 2 ]+K1+(-q^-2+q^-6)*K1[ K1 ; 1 ] """ return self._libgap @@ -203,9 +204,9 @@ def _add_(self, other): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: F1 * F2 + F2 * F1 # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: F1, F2 = Q.F_simple() + sage: F1 * F2 + F2 * F1 (q^3 + 1)*F[a1]*F[a2] + F[a1+a2] """ return self.__class__(self.parent(), self._libgap + other._libgap) @@ -216,9 +217,9 @@ def _sub_(self, other): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: F1 * F2 - F2 * F1 # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: F1, F2 = Q.F_simple() + sage: F1 * F2 - F2 * F1 (-q^3 + 1)*F[a1]*F[a2] + (-1)*F[a1+a2] """ return self.__class__(self.parent(), self._libgap - other._libgap) @@ -229,17 +230,17 @@ def _acted_upon_(self, scalar, self_on_left=True): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: x = Q.one().f_tilde([1,2,1,1,2,2]); x # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: q = Q.q() + sage: x = Q.one().f_tilde([1,2,1,1,2,2]); x F[a1+a2]^(3) - sage: 3 * x # optional - gap_packages + sage: 3 * x (3)*F[a1+a2]^(3) - sage: x * (5/3) # optional - gap_packages + sage: x * (5/3) (5/3)*F[a1+a2]^(3) - sage: q^-10 * x # optional - gap_packages + sage: q^-10 * x (q^-10)*F[a1+a2]^(3) - sage: (1 + q^2 - q^-1) * x # optional - gap_packages + sage: (1 + q^2 - q^-1) * x (q^2 + 1-q^-1)*F[a1+a2]^(3) """ try: @@ -261,9 +262,9 @@ def e_tilde(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: x = Q.one().f_tilde([1,2,1,1,2,2]) # optional - gap_packages - sage: x.e_tilde([2,2,1,2]) # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: x = Q.one().f_tilde([1,2,1,1,2,2]) + sage: x.e_tilde([2,2,1,2]) F[a1]^(2) """ # Do not override this method, instead implement _et @@ -288,12 +289,12 @@ def f_tilde(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: Q.one().f_tilde(1) # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: Q.one().f_tilde(1) F[a1] - sage: Q.one().f_tilde(2) # optional - gap_packages + sage: Q.one().f_tilde(2) F[a2] - sage: Q.one().f_tilde([1,2,1,1,2]) # optional - gap_packages + sage: Q.one().f_tilde([1,2,1,1,2]) F[a1]*F[a1+a2]^(2) """ # Do not override this method, instead implement _ft @@ -321,19 +322,19 @@ class QuantumGroup(UniqueRepresentation, Parent): We verify the Serre relations for type `A_2`:: - sage: Q = algebras.QuantumGroup(['A',2]) # optional - gap_packages - sage: F1,F12,F2 = Q.F() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: F1^2*F2 - q_binomial(2,1,q) * F1*F2*F1 + F2*F1^2 # optional - gap_packages + sage: Q = algebras.QuantumGroup(['A',2]) + sage: F1,F12,F2 = Q.F() + sage: q = Q.q() + sage: F1^2*F2 - q_binomial(2,1,q) * F1*F2*F1 + F2*F1^2 0 We verify the Serre relations for type `B_2`:: - sage: Q = algebras.QuantumGroup(['B',2]) # optional - gap_packages - sage: F1, F12, F122, F2 = Q.F() # optional - gap_packages - sage: F1^2*F2 - q_binomial(2,1,q^2) * F1*F2*F1 + F2*F1^2 # optional - gap_packages + sage: Q = algebras.QuantumGroup(['B',2]) + sage: F1, F12, F122, F2 = Q.F() + sage: F1^2*F2 - q_binomial(2,1,q^2) * F1*F2*F1 + F2*F1^2 0 - sage: (F2^3*F1 - q_binomial(3,1,q) * F2^2*F1*F2 # optional - gap_packages + sage: (F2^3*F1 - q_binomial(3,1,q) * F2^2*F1*F2 ....: + q_binomial(3,2,q) * F2*F1*F2^2 - F1*F2^3) 0 @@ -348,8 +349,8 @@ def __classcall_private__(cls, cartan_type, q=None): TESTS:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q is QuantumGroup('A2', None) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q is QuantumGroup('A2', None) True """ cartan_type = CartanType(cartan_type) @@ -361,14 +362,14 @@ def __init__(self, cartan_type, q): TESTS:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: TestSuite(Q).run() # long time # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: TestSuite(Q).run() # long time - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: TestSuite(Q).run() # long time # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: TestSuite(Q).run() # long time """ self._cartan_type = cartan_type - GapPackage("QuaGroup", spkg="gap_packages").require() + GapPackage("QuaGroup", spkg="gap_package_quagroup").require() libgap.LoadPackage('QuaGroup') R = libgap.eval('RootSystem("%s",%s)' % (cartan_type.type(), cartan_type.rank())) Q = self._cartan_type.root_system().root_lattice() @@ -397,7 +398,7 @@ def _repr_(self): EXAMPLES:: - sage: QuantumGroup(['A',2]) # optional - gap_packages + sage: QuantumGroup(['A',2]) Quantum Group of type ['A', 2] with q=q """ return "Quantum Group of type {} with q={}".format(self._cartan_type, self._q) @@ -408,10 +409,10 @@ def _latex_(self): EXAMPLES:: - sage: latex(QuantumGroup(['A',3])) # optional - gap_packages + sage: latex(QuantumGroup(['A',3])) U_{q}(A_{3}) - sage: zeta3 = CyclotomicField(3).gen() # optional - gap_packages - sage: latex(QuantumGroup(['G',2], q=zeta3)) # optional - gap_packages + sage: zeta3 = CyclotomicField(3).gen() + sage: latex(QuantumGroup(['G',2], q=zeta3)) U_{\zeta_{3}}(G_2) """ from sage.misc.latex import latex @@ -423,8 +424,8 @@ def gap(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.gap() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.gap() QuantumUEA( <root system of type A2>, Qpar = q ) """ return self._libgap @@ -437,8 +438,8 @@ def cartan_type(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.cartan_type() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.cartan_type() ['A', 2] """ return self._cartan_type @@ -449,16 +450,16 @@ def _element_constructor_(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q(0) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q(0) 0 - sage: Q(4) # optional - gap_packages + sage: Q(4) (4)*1 - sage: Q(4).parent() is Q # optional - gap_packages + sage: Q(4).parent() is Q True - sage: Q(Q.q()).parent() is Q # optional - gap_packages + sage: Q(Q.q()).parent() is Q True - sage: Q(Q.an_element()) == Q.an_element() # optional - gap_packages + sage: Q(Q.an_element()) == Q.an_element() True """ if not elt: @@ -477,8 +478,8 @@ def one(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.one() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.one() 1 """ return self.element_class(self, self._libgap.One()) @@ -490,8 +491,8 @@ def zero(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.zero() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.zero() 0 """ return self.element_class(self, self._libgap.ZeroImmutable()) @@ -503,8 +504,8 @@ def gens(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.gens() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.gens() (F[a1], F[a1+a2], F[a2], K1, (-q + q^-1)*[ K1 ; 1 ] + K1, K2, (-q + q^-1)*[ K2 ; 1 ] + K2, @@ -520,8 +521,8 @@ def E(self): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: list(Q.E()) # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: list(Q.E()) [E[a1], E[a1+a2], E[a1+2*a2], E[a2]] """ N = len(self._pos_roots) + len(self._cartan_type.index_set()) * 2 @@ -534,8 +535,8 @@ def E_simple(self): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: Q.E_simple() # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: Q.E_simple() Finite family {1: E[a1], 2: E[a2]} """ I = self._cartan_type.index_set() @@ -550,8 +551,8 @@ def F(self): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: list(Q.F()) # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: list(Q.F()) [F[a1], F[3*a1+a2], F[2*a1+a2], F[3*a1+2*a2], F[a1+a2], F[a2]] """ d = {al: self.gens()[i] for i, al in enumerate(self._pos_roots)} @@ -563,8 +564,8 @@ def F_simple(self): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: Q.F_simple() # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: Q.F_simple() Finite family {1: F[a1], 2: F[a2]} """ I = self._cartan_type.index_set() @@ -578,10 +579,10 @@ def K(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',3]) # optional - gap_packages - sage: Q.K() # optional - gap_packages + sage: Q = QuantumGroup(['A',3]) + sage: Q.K() Finite family {1: K1, 2: K2, 3: K3} - sage: Q.K_inverse() # optional - gap_packages + sage: Q.K_inverse() Finite family {1: (-q + q^-1)*[ K1 ; 1 ] + K1, 2: (-q + q^-1)*[ K2 ; 1 ] + K2, 3: (-q + q^-1)*[ K3 ; 1 ] + K3} @@ -597,8 +598,8 @@ def K_inverse(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',3]) # optional - gap_packages - sage: Q.K_inverse() # optional - gap_packages + sage: Q = QuantumGroup(['A',3]) + sage: Q.K_inverse() Finite family {1: (-q + q^-1)*[ K1 ; 1 ] + K1, 2: (-q + q^-1)*[ K2 ; 1 ] + K2, 3: (-q + q^-1)*[ K3 ; 1 ] + K3} @@ -615,8 +616,8 @@ def algebra_generators(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: list(Q.algebra_generators()) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: list(Q.algebra_generators()) [F[a1], F[a2], K1, K2, (-q + q^-1)*[ K1 ; 1 ] + K1, (-q + q^-1)*[ K2 ; 1 ] + K2, @@ -641,8 +642,8 @@ def _an_element_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.an_element() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.an_element() 1 + (q)*F[a1] + E[a1] + (q^2-1-q^-2 + q^-4)*[ K1 ; 2 ] + K1 + (-q^-1 + q^-3)*K1[ K1 ; 1 ] """ @@ -656,8 +657,8 @@ def some_elements(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: Q.some_elements() # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: Q.some_elements() [1 + (q)*F[a1] + E[a1] + (q^2-1-q^-2 + q^-4)*[ K1 ; 2 ] + K1 + (-q^-1 + q^-3)*K1[ K1 ; 1 ], K1, F[a1], E[a1]] @@ -671,12 +672,12 @@ def q(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',3]) # optional - gap_packages - sage: Q.q() # optional - gap_packages + sage: Q = QuantumGroup(['A',3]) + sage: Q.q() q - sage: zeta3 = CyclotomicField(3).gen() # optional - gap_packages - sage: Q = QuantumGroup(['B',2], q=zeta3) # optional - gap_packages - sage: Q.q() # optional - gap_packages + sage: zeta3 = CyclotomicField(3).gen() + sage: Q = QuantumGroup(['B',2], q=zeta3) + sage: Q.q() zeta3 """ return self._q @@ -690,12 +691,12 @@ def _Hom_(self, Y, category): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: H = Hom(Q, B); H # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: H = Hom(Q, B); H Set of Morphisms from Quantum Group of type ['A', 2] with q=q to Lower Half of Quantum Group of type ['A', 2] with q=q in Category of rings - sage: type(H) # optional - gap_packages + sage: type(H) <class '...QuantumGroupHomset_with_category_with_equality_by_id'> """ if category is not None and not category.is_subcategory(Rings()): @@ -710,8 +711,8 @@ def highest_weight_module(self, weight): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.highest_weight_module([1,3]) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.highest_weight_module([1,3]) Highest weight module of weight Lambda[1] + 3*Lambda[2] of Quantum Group of type ['A', 2] with q=q """ @@ -723,8 +724,8 @@ def lower_half(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.lower_half() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.lower_half() Lower Half of Quantum Group of type ['A', 2] with q=q """ return LowerHalfQuantumGroup(self) @@ -749,8 +750,8 @@ def coproduct(self, elt, n=1): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: [Q.coproduct(e) for e in Q.E()] # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: [Q.coproduct(e) for e in Q.E()] [1*(E[a1]<x>1) + 1*(K1<x>E[a1]), 1*(E[a1+a2]<x>1) + 1*(K1*K2<x>E[a1+a2]) + q^2-q^-2*(K2*E[a1]<x>E[a2]), q^4-q^2-1 + q^-2*(E[a1]<x>E[a2]^(2)) + 1*(E[a1+2*a2]<x>1) @@ -758,7 +759,7 @@ def coproduct(self, elt, n=1): + q-q^-1*(K2*E[a1+a2]<x>E[a2]) + q^5-2*q^3 + 2*q^-1-q^-3*(K2[ K2 ; 1 ]*E[a1]<x>E[a2]^(2)), 1*(E[a2]<x>1) + 1*(K2<x>E[a2])] - sage: [Q.coproduct(f, 2) for f in Q.F_simple()] # optional - gap_packages + sage: [Q.coproduct(f, 2) for f in Q.F_simple()] [1*(1<x>1<x>F[a1]) + -q^2 + q^-2*(1<x>F[a1]<x>[ K1 ; 1 ]) + 1*(1<x>F[a1]<x>K1) + q^4-2 + q^-4*(F[a1]<x>[ K1 ; 1 ]<x>[ K1 ; 1 ]) + -q^2 + q^-2*(F[a1]<x>[ K1 ; 1 ]<x>K1) + -q^2 @@ -787,8 +788,8 @@ def antipode(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: [Q.antipode(f) for f in Q.F()] # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: [Q.antipode(f) for f in Q.F()] [(-1)*F[a1]*K1, (-q^6 + q^2)*F[a1]*F[a2]*K1*K2 + (-q^4)*F[a1+a2]*K1*K2, (-q^8 + q^6 + q^4-q^2)*F[a1]*F[a2]^(2)*K1 @@ -815,13 +816,13 @@ def counit(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: x = Q.an_element()^2 # optional - gap_packages - sage: Q.counit(x) # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: x = Q.an_element()^2 + sage: Q.counit(x) 4 - sage: Q.counit(Q.one()) # optional - gap_packages + sage: Q.counit(Q.one()) 1 - sage: Q.counit(Q.zero()) # optional - gap_packages + sage: Q.counit(Q.zero()) 0 """ # We need to extract the constant coefficient because the @@ -847,14 +848,14 @@ def _mul_(self, other): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: F1 * F2 * F1 * F2 # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: F1, F2 = Q.F_simple() + sage: F1 * F2 * F1 * F2 F[a1]*F[a1+a2]*F[a2] + (q^7 + q^5 + q + q^-1)*F[a1]^(2)*F[a2]^(2) - sage: E1, E2 = Q.E_simple() # optional - gap_packages - sage: F1 * E1 # optional - gap_packages + sage: E1, E2 = Q.E_simple() + sage: F1 * E1 F[a1]*E[a1] - sage: E1 * F1 # optional - gap_packages + sage: E1 * F1 F[a1]*E[a1] + [ K1 ; 1 ] """ return self.__class__(self.parent(), self._libgap * other._libgap) @@ -873,8 +874,8 @@ def bar(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: [gen.bar() for gen in Q.gens()] # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: [gen.bar() for gen in Q.gens()] [F[a1], (q-q^-1)*F[a1]*F[a2] + F[a1+a2], F[a2], @@ -901,8 +902,8 @@ def omega(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: [gen.omega() for gen in Q.gens()] # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: [gen.omega() for gen in Q.gens()] [E[a1], (-q)*E[a1+a2], E[a2], @@ -931,8 +932,8 @@ def tau(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: [gen.tau() for gen in Q.gens()] # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: [gen.tau() for gen in Q.gens()] [F[a1], (-q^2 + 1)*F[a1]*F[a2] + (-q)*F[a1+a2], F[a2], @@ -973,13 +974,13 @@ def braid_group_action(self, braid): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: F1 = Q.F_simple()[1] # optional - gap_packages - sage: F1.braid_group_action([1]) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: F1 = Q.F_simple()[1] + sage: F1.braid_group_action([1]) (q-q^-1)*[ K1 ; 1 ]*E[a1] + (-1)*K1*E[a1] - sage: F1.braid_group_action([1,2]) # optional - gap_packages + sage: F1.braid_group_action([1,2]) F[a2] - sage: F1.braid_group_action([2,1]) # optional - gap_packages + sage: F1.braid_group_action([2,1]) (-q^3 + 3*q-3*q^-1 + q^-3)*[ K1 ; 1 ]*[ K2 ; 1 ]*E[a1]*E[a2] + (q^3-2*q + q^-1)*[ K1 ; 1 ]*[ K2 ; 1 ]*E[a1+a2] + (q^2-2 + q^-2)*[ K1 ; 1 ]*K2*E[a1]*E[a2] @@ -987,9 +988,9 @@ def braid_group_action(self, braid): + (q^2-2 + q^-2)*K1*[ K2 ; 1 ]*E[a1]*E[a2] + (-q^2 + 1)*K1*[ K2 ; 1 ]*E[a1+a2] + (-q + q^-1)*K1*K2*E[a1]*E[a2] + (q)*K1*K2*E[a1+a2] - sage: F1.braid_group_action([1,2,1]) == F1.braid_group_action([2,1,2]) # optional - gap_packages + sage: F1.braid_group_action([1,2,1]) == F1.braid_group_action([2,1,2]) True - sage: F1.braid_group_action([]) == F1 # optional - gap_packages + sage: F1.braid_group_action([]) == F1 True """ if not braid: @@ -1013,17 +1014,17 @@ def _et(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: [(g.e_tilde(1), g.e_tilde(2)) for g in Q.F()] # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: [(g.e_tilde(1), g.e_tilde(2)) for g in Q.F()] [(1, 0), (0, F[a1]^(3)), (0, F[a1]^(2)), (0, F[3*a1+a2]), (0, F[a1]), (0, 1)] TESTS:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.one()._et(1) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.one()._et(1) 0 - sage: Q.zero().e_tilde(1) # optional - gap_packages + sage: Q.zero().e_tilde(1) 0 """ if not self: # self == 0 @@ -1040,21 +1041,21 @@ def _ft(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: [(g._ft(1), g._ft(2)) for g in Q.F()] # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: [(g._ft(1), g._ft(2)) for g in Q.F()] [(F[a1]^(2), F[a1+a2]), (F[a1]*F[3*a1+a2], F[3*a1+2*a2]), (F[a1]*F[2*a1+a2], F[a1+a2]^(2)), (F[a1]*F[3*a1+2*a2], F[a1+a2]^(3)), (F[a1]*F[a1+a2], F[a1+a2]*F[a2]), (F[a1]*F[a2], F[a2]^(2))] - sage: Q.one().f_tilde([1,2,1,1,2,2]) # optional - gap_packages + sage: Q.one().f_tilde([1,2,1,1,2,2]) F[2*a1+a2]*F[a1+a2]*F[a2] TESTS:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.zero().f_tilde(1) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.zero().f_tilde(1) 0 """ if not self: # self == 0 @@ -1078,10 +1079,10 @@ def __init__(self, parent, im_gens, check=True): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: TestSuite(phi).run(skip="_test_category") # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: TestSuite(phi).run(skip="_test_category") """ self._repr_type_str = "Quantum group homomorphism" Morphism.__init__(self, parent) @@ -1097,10 +1098,10 @@ def __reduce__(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: loads(dumps(phi)) == phi # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: loads(dumps(phi)) == phi True """ return (self.parent(), (self._im_gens,)) @@ -1111,18 +1112,18 @@ def _call_(self, val): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: phi(F) # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: phi(F) E[a1] - sage: phi(E*F) # optional - gap_packages + sage: phi(E*F) F[a1]*E[a1] - sage: phi(F*E) # optional - gap_packages + sage: phi(F*E) F[a1]*E[a1] + [ K1 ; 1 ] - sage: phi(E*K) # optional - gap_packages + sage: phi(E*K) (-q + q^-1)*F[a1]*[ K1 ; 1 ] + F[a1]*K1 - sage: phi(F*E) == phi(F) * phi(E) # optional - gap_packages + sage: phi(F*E) == phi(F) * phi(E) True """ try: @@ -1136,31 +1137,31 @@ def __richcmp__(self, other, op): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: psi = Q.hom([F, K, Ki, E]) # optional - gap_packages - sage: phi == Q.hom([E, Ki, K, F]) # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: psi = Q.hom([F, K, Ki, E]) + sage: phi == Q.hom([E, Ki, K, F]) True - sage: phi == psi # optional - gap_packages + sage: phi == psi False - sage: psi != Q.hom([F, K, Ki, E]) # optional - gap_packages + sage: psi != Q.hom([F, K, Ki, E]) False - sage: phi != psi # optional - gap_packages + sage: phi != psi True - sage: QB = QuantumGroup(['B',3]) # optional - gap_packages - sage: QC = QuantumGroup(['C',3]) # optional - gap_packages - sage: x = ZZ.one() # optional - gap_packages - sage: phi = QB.hom([x]*len(QB.algebra_generators())) # optional - gap_packages - sage: psi = QC.hom([x]*len(QC.algebra_generators())) # optional - gap_packages - sage: phi.im_gens() == psi.im_gens() # optional - gap_packages + sage: QB = QuantumGroup(['B',3]) + sage: QC = QuantumGroup(['C',3]) + sage: x = ZZ.one() + sage: phi = QB.hom([x]*len(QB.algebra_generators())) + sage: psi = QC.hom([x]*len(QC.algebra_generators())) + sage: phi.im_gens() == psi.im_gens() True - sage: phi == psi # optional - gap_packages + sage: phi == psi False """ if op == op_EQ: - return (type(self) == type(other) + return (type(self) is type(other) and self.domain() is other.domain() and self._im_gens == other._im_gens) if op == op_NE: @@ -1173,10 +1174,10 @@ def im_gens(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: phi.im_gens() # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: phi.im_gens() (E[a1], (-q + q^-1)*[ K1 ; 1 ] + K1, K1, F[a1]) """ return self._im_gens @@ -1187,10 +1188,10 @@ def _repr_defn(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = Q.hom([E, Ki, K, F]) # optional - gap_packages - sage: print(phi._repr_defn()) # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: F, K, Ki, E = Q.gens() + sage: phi = Q.hom([E, Ki, K, F]) + sage: print(phi._repr_defn()) F[a1] |--> E[a1] K1 |--> (-q + q^-1)*[ K1 ; 1 ] + K1 (-q + q^-1)*[ K1 ; 1 ] + K1 |--> K1 @@ -1210,21 +1211,21 @@ def __call__(self, im_gens, check=True): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: H = Hom(Q, Q) # optional - gap_packages - sage: F, K, Ki, E = Q.gens() # optional - gap_packages - sage: phi = H([E, Ki, K, F]); phi # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: H = Hom(Q, Q) + sage: F, K, Ki, E = Q.gens() + sage: phi = H([E, Ki, K, F]); phi Quantum group homomorphism endomorphism of Quantum Group of type ['A', 1] with q=q Defn: F[a1] |--> E[a1] K1 |--> (-q + q^-1)*[ K1 ; 1 ] + K1 (-q + q^-1)*[ K1 ; 1 ] + K1 |--> K1 E[a1] |--> F[a1] - sage: H(phi) == phi # optional - gap_packages + sage: H(phi) == phi True - sage: H2 = Hom(Q, Q, Modules(Fields())) # optional - gap_packages - sage: H == H2 # optional - gap_packages + sage: H2 = Hom(Q, Q, Modules(Fields())) + sage: H == H2 False - sage: H2(phi) # optional - gap_packages + sage: H2(phi) Quantum group homomorphism endomorphism of Quantum Group of type ['A', 1] with q=q Defn: F[a1] |--> E[a1] K1 |--> (-q + q^-1)*[ K1 ; 1 ] + K1 @@ -1247,8 +1248,8 @@ def projection_lower_half(Q): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import projection_lower_half - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: phi = projection_lower_half(Q); phi # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: phi = projection_lower_half(Q); phi Quantum group homomorphism endomorphism of Quantum Group of type ['G', 2] with q=q Defn: F[a1] |--> F[a1] F[a2] |--> F[a2] @@ -1258,11 +1259,11 @@ def projection_lower_half(Q): (-q^3 + q^-3)*[ K2 ; 1 ] + K2 |--> 0 E[a1] |--> 0 E[a2] |--> 0 - sage: all(phi(f) == f for f in Q.F()) # optional - gap_packages + sage: all(phi(f) == f for f in Q.F()) True - sage: all(phi(e) == Q.zero() for e in Q.E()) # optional - gap_packages + sage: all(phi(e) == Q.zero() for e in Q.E()) True - sage: all(phi(K) == Q.zero() for K in Q.K()) # optional - gap_packages + sage: all(phi(K) == Q.zero() for K in Q.K()) True """ I = Q._cartan_type.index_set() @@ -1282,13 +1283,13 @@ def __reduce__(self): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: V = Q.highest_weight_module([2,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: x = (2 - q) * v + F1*v + q*F2*F1*v # optional - gap_packages - sage: loads(dumps(x)) == x # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: V = Q.highest_weight_module([2,1]) + sage: v = V.highest_weight_vector() + sage: x = (2 - q) * v + F1*v + q*F2*F1*v + sage: loads(dumps(x)) == x True """ return (self.parent(), (self.monomial_coefficients(),)) @@ -1299,24 +1300,24 @@ def _acted_upon_(self, scalar, self_on_left=False): EXAMPLES:: - sage: Q = QuantumGroup(['B',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: V = Q.highest_weight_module([2,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: F1 * v # optional - gap_packages + sage: Q = QuantumGroup(['B',2]) + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: V = Q.highest_weight_module([2,1]) + sage: v = V.highest_weight_vector() + sage: F1 * v F[a1]*v0 - sage: F2 * v # optional - gap_packages + sage: F2 * v F[a2]*v0 - sage: F1^2 * v # optional - gap_packages + sage: F1^2 * v (q^2 + q^-2)*F[a1]^(2)*v0 - sage: F2^2 * v # optional - gap_packages + sage: F2^2 * v 0*v0 - sage: (F1 * F2) * v # optional - gap_packages + sage: (F1 * F2) * v F[a1]*F[a2]*v0 - sage: F1 * (F2 * v) # optional - gap_packages + sage: F1 * (F2 * v) F[a1]*F[a2]*v0 - sage: (2 - q) * v + F1*v + q*F2*F1*v # optional - gap_packages + sage: (2 - q) * v + F1*v + q*F2*F1*v (-q + 2)*1*v0 + F[a1]*v0 + (q^3)*F[a1]*F[a2]*v0 + (q)*F[a1+a2]*v0 """ try: @@ -1336,12 +1337,12 @@ def _et(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: v._et(1) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: v = V.highest_weight_vector() + sage: v._et(1) 0*v0 - sage: V.zero().e_tilde(1) # optional - gap_packages + sage: V.zero().e_tilde(1) 0*v0 """ if not self: # self == 0 @@ -1356,22 +1357,22 @@ def _ft(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['C',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: v._ft(1) # optional - gap_packages + sage: Q = QuantumGroup(['C',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: v = V.highest_weight_vector() + sage: v._ft(1) F[a1]*v0 - sage: v._ft(2) # optional - gap_packages + sage: v._ft(2) F[a2]*v0 - sage: v.f_tilde([1,1]) # optional - gap_packages + sage: v.f_tilde([1,1]) 0*v0 - sage: v.f_tilde([2,2]) # optional - gap_packages + sage: v.f_tilde([2,2]) 0*v0 - sage: v.f_tilde([2,1,1]) # optional - gap_packages + sage: v.f_tilde([2,1,1]) (-q^-3)*F[a1]*F[a1+a2]*v0 + (-q^-4)*F[2*a1+a2]*v0 - sage: v.f_tilde([1,2,2]) # optional - gap_packages + sage: v.f_tilde([1,2,2]) F[a1+a2]*F[a2]*v0 - sage: V.zero().f_tilde(1) # optional - gap_packages + sage: V.zero().f_tilde(1) 0*v0 """ if not self: # self == 0 @@ -1387,14 +1388,14 @@ def monomial_coefficients(self, copy=True): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: x = v + F1*v + q*F2*F1*v; x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: v = V.highest_weight_vector() + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: x = v + F1*v + q*F2*F1*v; x 1*v0 + F[a1]*v0 + (q^2)*F[a1]*F[a2]*v0 + (q)*F[a1+a2]*v0 - sage: sorted(x.monomial_coefficients().items(), key=str) # optional - gap_packages + sage: sorted(x.monomial_coefficients().items(), key=str) [(0, 1), (1, 1), (3, q^2), (4, q)] """ R = self.parent()._Q.base_ring() @@ -1408,25 +1409,25 @@ def _vector_(self, R=None, order=None, sparse=False): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: v = V.highest_weight_vector() # optional - gap_packages - sage: vector(v) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: v = V.highest_weight_vector() + sage: vector(v) (1, 0, 0, 0, 0, 0, 0, 0) - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: x = v + F1*v + q*F2*F1*v; x # optional - gap_packages + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: x = v + F1*v + q*F2*F1*v; x 1*v0 + F[a1]*v0 + (q^2)*F[a1]*F[a2]*v0 + (q)*F[a1+a2]*v0 - sage: vector(x) # optional - gap_packages + sage: vector(x) (1, 1, 0, q^2, q, 0, 0, 0) - sage: v._vector_(sparse=True) # optional - gap_packages + sage: v._vector_(sparse=True) (1, 0, 0, 0, 0, 0, 0, 0) - sage: x._vector_(sparse=True) # optional - gap_packages + sage: x._vector_(sparse=True) (1, 1, 0, q^2, q, 0, 0, 0) - sage: M = V.submodule([V.an_element()]) # optional - gap_packages - sage: M # optional - gap_packages + sage: M = V.submodule([V.an_element()]) + sage: M Free module generated by {0} over Fraction Field of Univariate Polynomial Ring in q over Rational Field """ V = self.parent()._dense_free_module(R) @@ -1456,10 +1457,10 @@ def __init__(self, V, s): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import CrystalGraphVertex - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: v = CrystalGraphVertex(V, '<F2*v0>') # optional - gap_packages - sage: TestSuite(v).run() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: v = CrystalGraphVertex(V, '<F2*v0>') + sage: TestSuite(v).run() """ self.V = V self.s = s @@ -1471,10 +1472,10 @@ def __hash__(self): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import CrystalGraphVertex - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: v = CrystalGraphVertex(V, '<F2*v0>') # optional - gap_packages - sage: hash(v) == hash('<F2*v0>') # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: v = CrystalGraphVertex(V, '<F2*v0>') + sage: hash(v) == hash('<F2*v0>') True """ return hash(self.s) @@ -1486,14 +1487,14 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import CrystalGraphVertex - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: v = CrystalGraphVertex(V, '<F2*v0>') # optional - gap_packages - sage: vp = CrystalGraphVertex(V, '<F2*v0>') # optional - gap_packages - sage: v == vp # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: v = CrystalGraphVertex(V, '<F2*v0>') + sage: vp = CrystalGraphVertex(V, '<F2*v0>') + sage: v == vp True - sage: vpp = CrystalGraphVertex(V, '<1*v0>') # optional - gap_packages - sage: v == vpp # optional - gap_packages + sage: vpp = CrystalGraphVertex(V, '<1*v0>') + sage: v == vpp False """ return isinstance(other, CrystalGraphVertex) and self.s == other.s @@ -1505,9 +1506,9 @@ def _repr_(self): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import CrystalGraphVertex - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: CrystalGraphVertex(V, '<F2*v0>') # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: CrystalGraphVertex(V, '<F2*v0>') <F2*v0> """ return self.s @@ -1519,10 +1520,10 @@ def _latex_(self): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import CrystalGraphVertex - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: v = CrystalGraphVertex(V, '<F2*v0>') # optional - gap_packages - sage: latex(v) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: v = CrystalGraphVertex(V, '<F2*v0>') + sage: latex(v) \langle F_{\alpha_{1} + \alpha_{2}} v_0 \rangle """ # Essentially same as QuaGroupModuleElement._latex_ @@ -1556,9 +1557,9 @@ def __init__(self, Q, category): EXAMPLES:: - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: TestSuite(V).run() # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: TestSuite(V).run() """ self._Q = Q self._libgap_q = Q._libgap_q @@ -1573,12 +1574,12 @@ def _latex_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[0] # optional - gap_packages - sage: latex(S) # optional - gap_packages # random (depends on dot2tex) - \begin{tikzpicture} + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[0] + sage: latex(S) + \begin{tikzpicture}... ... \end{tikzpicture} """ @@ -1591,9 +1592,9 @@ def gap(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: V.gap() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: V.gap() <8-dimensional left-module over QuantumUEA( <root system of type A2>, Qpar = q )> """ @@ -1607,12 +1608,12 @@ def _element_constructor_(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: V(0) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: q = Q.q() + sage: V(0) 0*v0 - sage: V({1: q^2 - q^-2, 3: 2}) # optional - gap_packages + sage: V({1: q^2 - q^-2, 3: 2}) (q^2-q^-2)*F[a1]*v0 + (2)*F[a1]*F[a2]*v0 """ if not elt: @@ -1628,9 +1629,9 @@ def basis(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: V.basis() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: V.basis() Family (1*v0, F[a1]*v0, F[a2]*v0, F[a1]*F[a2]*v0, F[a1+a2]*v0, F[a1]*F[a1+a2]*v0, F[a1+a2]*F[a2]*v0, F[a1+a2]^(2)*v0) """ @@ -1643,9 +1644,9 @@ def crystal_basis(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: V.crystal_basis() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: V.crystal_basis() Family (1*v0, F[a1]*v0, F[a2]*v0, F[a1]*F[a2]*v0, (q)*F[a1]*F[a2]*v0 + F[a1+a2]*v0, F[a1+a2]*F[a2]*v0, (-q^-2)*F[a1]*F[a1+a2]*v0, (-q^-1)*F[a1+a2]^(2)*v0) @@ -1659,9 +1660,9 @@ def R_matrix(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',1]) # optional - gap_packages - sage: V = Q.highest_weight_module([1]) # optional - gap_packages - sage: V.R_matrix() # optional - gap_packages + sage: Q = QuantumGroup(['A',1]) + sage: V = Q.highest_weight_module([1]) + sage: V.R_matrix() [ 1 0 0 0] [ 0 q -q^2 + 1 0] [ 0 0 q 0] @@ -1680,13 +1681,13 @@ def crystal_graph(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: G = V.crystal_graph(); G # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: G = V.crystal_graph(); G Digraph on 8 vertices - sage: B = crystals.Tableaux(['A',2], shape=[2,1]) # optional - gap_packages - sage: G.is_isomorphic(B.digraph(), edge_labels=True) # optional - gap_packages + sage: B = crystals.Tableaux(['A',2], shape=[2,1]) + sage: G.is_isomorphic(B.digraph(), edge_labels=True) True """ G = self._libgap.CrystalGraph() @@ -1708,9 +1709,9 @@ def zero(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: V.zero() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: V.zero() 0*v0 """ return self.element_class(self, self._libgap.ZeroImmutable()) @@ -1727,10 +1728,10 @@ def __classcall_private__(cls, Q, weight): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: La = Q.cartan_type().root_system().weight_lattice().fundamental_weights() # optional - gap_packages - sage: V = Q.highest_weight_module([1,3]) # optional - gap_packages - sage: V is Q.highest_weight_module(La[1]+3*La[2]) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: La = Q.cartan_type().root_system().weight_lattice().fundamental_weights() + sage: V = Q.highest_weight_module([1,3]) + sage: V is Q.highest_weight_module(La[1]+3*La[2]) True """ P = Q._cartan_type.root_system().weight_lattice() @@ -1747,9 +1748,9 @@ def __init__(self, Q, weight): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: TestSuite(V).run() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: TestSuite(V).run() """ self._libgap = Q._libgap.HighestWeightModule(list(weight.to_vector())) self._weight = weight @@ -1762,8 +1763,8 @@ def _repr_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.highest_weight_module([1,1]) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.highest_weight_module([1,1]) Highest weight module of weight Lambda[1] + Lambda[2] of Quantum Group of type ['A', 2] with q=q """ @@ -1775,9 +1776,9 @@ def _latex_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,2]) # optional - gap_packages - sage: latex(V) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,2]) + sage: latex(V) V(\Lambda_{1} + 2 \Lambda_{2}) """ from sage.misc.latex import latex @@ -1790,9 +1791,9 @@ def highest_weight_vector(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: V.highest_weight_vector() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: V.highest_weight_vector() 1*v0 """ return self.element_class(self, self._libgap.HighestWeightsAndVectors()[1][0][0]) @@ -1805,10 +1806,10 @@ def tensor(self, *V, **options): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: Vp = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: Vp.tensor(V) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: Vp = Q.highest_weight_module([1,0]) + sage: Vp.tensor(V) Highest weight module of weight Lambda[1] of Quantum Group of type ['A', 2] with q=q # Highest weight module of weight Lambda[1] + Lambda[2] of Quantum Group of type ['A', 2] with q=q """ @@ -1824,10 +1825,10 @@ def __init__(self, *modules, **options): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,1]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: TestSuite(T).run() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,1]) + sage: T = tensor([V,V]) + sage: TestSuite(T).run() """ Q = modules[0]._Q self._modules = tuple(modules) @@ -1841,10 +1842,10 @@ def _repr_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T Highest weight module of weight Lambda[1] of Quantum Group of type ['A', 2] with q=q # Highest weight module of weight Lambda[1] of Quantum Group of type ['A', 2] with q=q """ @@ -1856,10 +1857,10 @@ def _latex_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: latex(T) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: latex(T) V(\Lambda_{1}) \otimes V(\Lambda_{1}) """ from sage.misc.latex import latex @@ -1876,10 +1877,10 @@ def _highest_weights_and_vectors(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([0,1]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T._highest_weights_and_vectors # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([0,1]) + sage: T = tensor([V,V]) + sage: T._highest_weights_and_vectors [ [ [ 0, 2 ], [ 1, 0 ] ], [ [ 1*(1*v0<x>1*v0) ], [ -q^-1*(1*v0<x>F3*v0)+1*(F3*v0<x>1*v0) ] ] ] """ @@ -1891,10 +1892,10 @@ def highest_weight_vectors(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T.highest_weight_vectors() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T.highest_weight_vectors() [1*(1*v0<x>1*v0), -q^-1*(1*v0<x>F[a1]*v0) + 1*(F[a1]*v0<x>1*v0)] """ return [self.element_class(self, v) @@ -1909,10 +1910,10 @@ def _an_element_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T.an_element() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T.an_element() 1*(1*v0<x>1*v0) """ return self.highest_weight_vectors()[0] @@ -1924,10 +1925,10 @@ def highest_weight_decomposition(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T.highest_weight_decomposition() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T.highest_weight_decomposition() [Highest weight submodule with weight 2*Lambda[1] generated by 1*(1*v0<x>1*v0), Highest weight submodule with weight Lambda[2] generated by -q^-1*(1*v0<x>F[a1]*v0) + 1*(F[a1]*v0<x>1*v0)] """ @@ -1941,10 +1942,10 @@ def tensor_factors(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T.tensor_factors() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T.tensor_factors() (Highest weight module of weight Lambda[1] of Quantum Group of type ['A', 2] with q=q, Highest weight module of weight Lambda[1] of Quantum Group of type ['A', 2] with q=q) """ @@ -1960,11 +1961,11 @@ def __init__(self, ambient, gen, weight): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[0] # optional - gap_packages - sage: TestSuite(S).run() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[0] + sage: TestSuite(S).run() """ self._ambient = ambient # We do not use the generic ambient category since submodules of tensor @@ -1989,10 +1990,10 @@ def _repr_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: T.highest_weight_decomposition() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: T.highest_weight_decomposition() [Highest weight submodule with weight 2*Lambda[1] generated by 1*(1*v0<x>1*v0), Highest weight submodule with weight Lambda[2] @@ -2007,11 +2008,11 @@ def _ambient_basis_map(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[0] # optional - gap_packages - sage: S._ambient_basis_map # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[0] + sage: S._ambient_basis_map {0: 1*(1*v0<x>1*v0), 1: 1*(1*v0<x>F[a1]*v0) + q^-1*(F[a1]*v0<x>1*v0), 2: 1*(F[a1]*v0<x>F[a1]*v0), @@ -2038,11 +2039,11 @@ def ambient(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[0] # optional - gap_packages - sage: S.ambient() is T # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[0] + sage: S.ambient() is T True """ return self._ambient @@ -2054,16 +2055,16 @@ def lift(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[0] # optional - gap_packages - sage: S.lift # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[0] + sage: S.lift Generic morphism: From: Highest weight submodule with weight 2*Lambda[1] generated by 1*(1*v0<x>1*v0) To: Highest weight module ... # Highest weight module ... - sage: x = sum(S.basis()) # optional - gap_packages - sage: x.lift() # optional - gap_packages + sage: x = sum(S.basis()) + sage: x.lift() 1*(1*v0<x>1*v0) + 1*(1*v0<x>F[a1]*v0) + 1*(1*v0<x>F[a1+a2]*v0) + q^-1*(F[a1]*v0<x>1*v0) + 1*(F[a1]*v0<x>F[a1]*v0) + 1*(F[a1]*v0<x>F[a1+a2]*v0) + q^-1*(F[a1+a2]*v0<x>1*v0) @@ -2078,10 +2079,10 @@ def retract(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: all(S.retract(S.lift(x)) == x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: all(S.retract(S.lift(x)) == x ....: for S in T.highest_weight_decomposition() ....: for x in S.basis()) True @@ -2095,13 +2096,13 @@ def highest_weight_vector(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[1] # optional - gap_packages - sage: u = S.highest_weight_vector(); u # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[1] + sage: u = S.highest_weight_vector(); u (1)*e.1 - sage: u.lift() # optional - gap_packages + sage: u.lift() -q^-1*(1*v0<x>F[a1]*v0) + 1*(F[a1]*v0<x>1*v0) """ I = self._cartan_type.index_set() @@ -2124,16 +2125,16 @@ def crystal_graph(self, use_ambient=True): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: V = Q.highest_weight_module([1,0]) # optional - gap_packages - sage: T = tensor([V,V]) # optional - gap_packages - sage: S = T.highest_weight_decomposition()[1] # optional - gap_packages - sage: G = S.crystal_graph() # optional - gap_packages - sage: sorted(G.vertices(sort=False), key=str) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: V = Q.highest_weight_module([1,0]) + sage: T = tensor([V,V]) + sage: S = T.highest_weight_decomposition()[1] + sage: G = S.crystal_graph() + sage: sorted(G.vertices(sort=False), key=str) [<-q^-1*(1*v0<x>F[a1+a2]*v0) + 1*(F[a1+a2]*v0<x>1*v0)>, <-q^-1*(1*v0<x>F[a1]*v0) + 1*(F[a1]*v0<x>1*v0)>, <-q^-1*(F[a1]*v0<x>F[a1+a2]*v0) + 1*(F[a1+a2]*v0<x>F[a1]*v0)>] - sage: sorted(S.crystal_graph(False).vertices(sort=False), key=str) # optional - gap_packages + sage: sorted(S.crystal_graph(False).vertices(sort=False), key=str) [<(1)*e.1>, <(1)*e.2>, <(1)*e.3>] """ G = self._libgap.CrystalGraph() @@ -2171,8 +2172,8 @@ def __classcall_private__(cls, Q): EXAMPLES:: sage: from sage.algebras.quantum_groups.quantum_group_gap import LowerHalfQuantumGroup - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.lower_half() is LowerHalfQuantumGroup(Q) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.lower_half() is LowerHalfQuantumGroup(Q) True """ from sage.combinat.root_system.cartan_type import CartanType_abstract @@ -2186,9 +2187,9 @@ def __init__(self, Q): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: TestSuite(B).run() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: TestSuite(B).run() """ self._Q = Q self._libgap = Q._libgap @@ -2206,8 +2207,8 @@ def _repr_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: Q.lower_half() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: Q.lower_half() Lower Half of Quantum Group of type ['A', 2] with q=q """ return "Lower Half of {}".format(self._Q) @@ -2218,8 +2219,8 @@ def _latex_(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: latex(Q.lower_half()) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: latex(Q.lower_half()) U^-_{q}(A_{2}) """ from sage.misc.latex import latex @@ -2231,14 +2232,14 @@ def _element_constructor_(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: B(0) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: q = Q.q() + sage: B(0) 0 - sage: B(1 + q^2) # optional - gap_packages + sage: B(1 + q^2) (q^2 + 1)*1 - sage: B({(1,2,0): q, (0,0,2): q^2 - 2}) # optional - gap_packages + sage: B({(1,2,0): q, (0,0,2): q^2 - 2}) (q)*F[a1]*F[a1+a2]^(2) + (q^2-2)*F[a2]^(2) """ if not elt: @@ -2257,9 +2258,9 @@ def ambient(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B.ambient() is Q # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B.ambient() is Q True """ return self._Q @@ -2271,9 +2272,9 @@ def highest_weight_vector(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B.highest_weight_vector() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B.highest_weight_vector() 1 """ return self.element_class(self, self._Q.one()._libgap) @@ -2288,9 +2289,9 @@ def zero(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B.zero() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B.zero() 0 """ return self.element_class(self, self._Q._libgap.ZeroImmutable()) @@ -2302,9 +2303,9 @@ def algebra_generators(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B.algebra_generators() # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B.algebra_generators() Finite family {1: F[a1], 2: F[a2]} """ F = self._Q.F_simple() @@ -2320,11 +2321,11 @@ def _construct_monomial(self, k): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B._construct_monomial((1,2,1)) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B._construct_monomial((1,2,1)) F[a1]*F[a1+a2]^(2)*F[a2] - sage: B._construct_monomial((3,0,1)) # optional - gap_packages + sage: B._construct_monomial((3,0,1)) F[a1]^(3)*F[a2] """ F = libgap.eval('ElementsFamily')(libgap.eval('FamilyObj')(self._libgap)) @@ -2348,16 +2349,16 @@ def basis(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: basis = B.basis(); basis # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: basis = B.basis(); basis Lazy family (monomial(i))_{i in The Cartesian product of (Non negative integers, Non negative integers, Non negative integers)} - sage: basis[1,2,1] # optional - gap_packages + sage: basis[1,2,1] F[a1]*F[a1+a2]^(2)*F[a2] - sage: basis[1,2,4] # optional - gap_packages + sage: basis[1,2,4] F[a1]*F[a1+a2]^(2)*F[a2]^(4) - sage: basis[1,0,4] # optional - gap_packages + sage: basis[1,0,4] F[a1]*F[a2]^(4) """ I = cartesian_product([NonNegativeIntegers()]*len(self._pos_roots)) @@ -2369,9 +2370,9 @@ def _construct_canonical_basis_elts(self, k): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: B._construct_canonical_basis_elts((1,2)) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: B._construct_canonical_basis_elts((1,2)) [F[a1]*F[a2]^(2), (q^2)*F[a1]*F[a2]^(2) + F[a1+a2]*F[a2]] """ B = self._libgap.CanonicalBasis() @@ -2384,14 +2385,14 @@ def canonical_basis_elements(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: C = B.canonical_basis_elements(); C # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: C = B.canonical_basis_elements(); C Lazy family (Canonical basis(i))_{i in The Cartesian product of (Non negative integers, Non negative integers)} - sage: C[2,1] # optional - gap_packages + sage: C[2,1] [F[a1]^(2)*F[a2], F[a1]*F[a1+a2] + (q^2)*F[a1]^(2)*F[a2]] - sage: C[1,2] # optional - gap_packages + sage: C[1,2] [F[a1]*F[a2]^(2), (q^2)*F[a1]*F[a2]^(2) + F[a1+a2]*F[a2]] """ I = cartesian_product([NonNegativeIntegers()]*len(self._cartan_type.index_set())) @@ -2403,11 +2404,11 @@ def lift(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B.lift(B.an_element()); x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: x = B.lift(B.an_element()); x 1 - sage: x.parent() is Q # optional - gap_packages + sage: x.parent() is Q True """ return self._Q.element_class(self._Q, elt._libgap) @@ -2418,12 +2419,12 @@ def retract(self, elt): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = Q.an_element(); x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: x = Q.an_element(); x 1 + (q)*F[a1] + E[a1] + (q^2-1-q^-2 + q^-4)*[ K1 ; 2 ] + K1 + (-q^-1 + q^-3)*K1[ K1 ; 1 ] - sage: B.retract(x) # optional - gap_packages + sage: B.retract(x) 1 + (q)*F[a1] """ return self.element_class(self, self._proj(elt)._libgap) @@ -2438,20 +2439,20 @@ def _acted_upon_(self, scalar, self_on_left=False): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: v = B.highest_weight_vector(); v # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: F1, F2 = Q.F_simple() + sage: v = B.highest_weight_vector(); v 1 - sage: 2 * v # optional - gap_packages + sage: 2 * v (2)*1 - sage: v * (3/2) # optional - gap_packages + sage: v * (3/2) (3/2)*1 - sage: F1 * v # optional - gap_packages + sage: F1 * v F[a1] - sage: F2 * (F1 * v) # optional - gap_packages + sage: F2 * (F1 * v) (q)*F[a1]*F[a2] + F[a1+a2] - sage: (F1 * v) * F2 # optional - gap_packages + sage: (F1 * v) * F2 F[a1]*F[a2] """ try: @@ -2473,16 +2474,16 @@ def _mul_(self, other): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: v = B.highest_weight_vector() # optional - gap_packages - sage: f1, f2 = F1 * v, F2 * v # optional - gap_packages - sage: f1 * f2 # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: F1, F2 = Q.F_simple() + sage: v = B.highest_weight_vector() + sage: f1, f2 = F1 * v, F2 * v + sage: f1 * f2 F[a1]*F[a2] - sage: f1^2 * f2 # optional - gap_packages + sage: f1^2 * f2 (q + q^-1)*F[a1]^(2)*F[a2] - sage: f2 * f1^2 * f2 # optional - gap_packages + sage: f2 * f1^2 * f2 (q + q^-1)*F[a1]*F[a1+a2]*F[a2] + (q^4 + 2*q^2 + 1)*F[a1]^(2)*F[a2]^(2) """ @@ -2496,11 +2497,11 @@ def monomial_coefficients(self, copy=True): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B.retract(Q.an_element()); x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: B = Q.lower_half() + sage: x = B.retract(Q.an_element()); x 1 + (q)*F[a1] - sage: sorted(x.monomial_coefficients().items(), key=str) # optional - gap_packages + sage: sorted(x.monomial_coefficients().items(), key=str) [((0, 0, 0), 1), ((1, 0, 0), q)] """ ext_rep = self._libgap.ExtRepOfObj() @@ -2521,27 +2522,27 @@ def bar(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B(Q.an_element()); x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: F1, F2 = Q.F_simple() + sage: B = Q.lower_half() + sage: x = B(Q.an_element()); x 1 + (q)*F[a1] - sage: x.bar() # optional - gap_packages + sage: x.bar() 1 + (q^-1)*F[a1] - sage: (F1*x).bar() == F1 * x.bar() # optional - gap_packages + sage: (F1*x).bar() == F1 * x.bar() True - sage: (F2*x).bar() == F2 * x.bar() # optional - gap_packages + sage: (F2*x).bar() == F2 * x.bar() True - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B(q^-2*F1*F2^2*F1) # optional - gap_packages - sage: x # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: B = Q.lower_half() + sage: x = B(q^-2*F1*F2^2*F1) + sage: x (q + q^-5)*F[a1]*F[a1+a2]*F[a2] + (q^8 + q^6 + q^2 + 1)*F[a1]^(2)*F[a2]^(2) - sage: x.bar() # optional - gap_packages + sage: x.bar() (q^5 + q^-1)*F[a1]*F[a1+a2]*F[a2] + (q^12 + q^10 + q^6 + q^4)*F[a1]^(2)*F[a2]^(2) """ @@ -2555,27 +2556,27 @@ def tau(self): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B(Q.an_element()); x # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: F1, F2 = Q.F_simple() + sage: B = Q.lower_half() + sage: x = B(Q.an_element()); x 1 + (q)*F[a1] - sage: x.tau() # optional - gap_packages + sage: x.tau() 1 + (q)*F[a1] - sage: (F1*x).tau() == x.tau() * F1.tau() # optional - gap_packages + sage: (F1*x).tau() == x.tau() * F1.tau() True - sage: (F2*x).tau() == x.tau() * F2.tau() # optional - gap_packages + sage: (F2*x).tau() == x.tau() * F2.tau() True - sage: Q = QuantumGroup(['G',2]) # optional - gap_packages - sage: F1, F2 = Q.F_simple() # optional - gap_packages - sage: q = Q.q() # optional - gap_packages - sage: B = Q.lower_half() # optional - gap_packages - sage: x = B(q^-2*F1*F2^2*F1) # optional - gap_packages - sage: x # optional - gap_packages + sage: Q = QuantumGroup(['G',2]) + sage: F1, F2 = Q.F_simple() + sage: q = Q.q() + sage: B = Q.lower_half() + sage: x = B(q^-2*F1*F2^2*F1) + sage: x (q + q^-5)*F[a1]*F[a1+a2]*F[a2] + (q^8 + q^6 + q^2 + 1)*F[a1]^(2)*F[a2]^(2) - sage: x.tau() # optional - gap_packages + sage: x.tau() (q + q^-5)*F[a1]*F[a1+a2]*F[a2] + (q^8 + q^6 + q^2 + 1)*F[a1]^(2)*F[a2]^(2) """ @@ -2594,13 +2595,13 @@ def braid_group_action(self, braid): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: L = Q.lower_half() # optional - gap_packages - sage: v = L.highest_weight_vector().f_tilde([1,2,2,1]); v # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: L = Q.lower_half() + sage: v = L.highest_weight_vector().f_tilde([1,2,2,1]); v F[a1]*F[a1+a2]*F[a2] - sage: v.braid_group_action([1]) # optional - gap_packages + sage: v.braid_group_action([1]) (-q^3-q)*F[a2]^(2) - sage: v.braid_group_action([]) == v # optional - gap_packages + sage: v.braid_group_action([]) == v True """ if not braid: @@ -2625,18 +2626,18 @@ def _et(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: L = Q.lower_half() # optional - gap_packages - sage: v = L.highest_weight_vector() # optional - gap_packages - sage: v._et(1) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: L = Q.lower_half() + sage: v = L.highest_weight_vector() + sage: v._et(1) 0 - sage: w = v.f_tilde([1,2,1]); w # optional - gap_packages + sage: w = v.f_tilde([1,2,1]); w F[a1]*F[a1+a2] - sage: w._et(1) # optional - gap_packages + sage: w._et(1) F[a1+a2] - sage: w._et(2) # optional - gap_packages + sage: w._et(2) F[a1]^(2) - sage: L.zero().e_tilde(1) # optional - gap_packages + sage: L.zero().e_tilde(1) 0 """ if not self: # self == 0 @@ -2653,12 +2654,12 @@ def _ft(self, i): EXAMPLES:: - sage: Q = QuantumGroup(['A',2]) # optional - gap_packages - sage: L = Q.lower_half() # optional - gap_packages - sage: v = L.highest_weight_vector() # optional - gap_packages - sage: v._ft(1) # optional - gap_packages + sage: Q = QuantumGroup(['A',2]) + sage: L = Q.lower_half() + sage: v = L.highest_weight_vector() + sage: v._ft(1) F[a1] - sage: L.zero().f_tilde(1) # optional - gap_packages + sage: L.zero().f_tilde(1) 0 """ if not self: # self == 0 @@ -2676,9 +2677,9 @@ def _unpickle_generic_element(parent, data): EXAMPLES:: - sage: Q = QuantumGroup(['D',4]) # optional - gap_packages - sage: x = Q.an_element() # optional - gap_packages - sage: loads(dumps(x)) == x # indirect doctest # optional - gap_packages + sage: Q = QuantumGroup(['D',4]) + sage: x = Q.an_element() + sage: loads(dumps(x)) == x # indirect doctest True """ F = libgap.eval('ElementsFamily')(libgap.eval('FamilyObj')(parent._libgap)) diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index 4b7af26d31c..1b6001209a0 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -35,9 +35,14 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.all import (hilbert_conductor_inverse, hilbert_conductor, - factor, gcd, kronecker_symbol, valuation) -from sage.rings.all import RR, Integer +from sage.arith.misc import (hilbert_conductor_inverse, + hilbert_conductor, + factor, + gcd, + kronecker as kronecker_symbol, + valuation) +from sage.rings.real_mpfr import RR +from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.rational import Rational from sage.rings.finite_rings.finite_field_constructor import GF @@ -46,7 +51,7 @@ from sage.rings.ideal import Ideal_fractional from sage.rings.rational_field import is_RationalField, QQ from sage.rings.infinity import infinity -from sage.rings.number_field.number_field import is_NumberField +from sage.rings.number_field.number_field_base import NumberField from sage.rings.power_series_ring import PowerSeriesRing from sage.structure.category_object import normalize_names from sage.structure.parent import Parent @@ -657,7 +662,7 @@ def __init__(self, base_ring, a, b, names='i,j,k'): self._b = b if is_RationalField(base_ring) and a.denominator() == 1 == b.denominator(): self.Element = QuaternionAlgebraElement_rational_field - elif (is_NumberField(base_ring) and base_ring.degree() > 2 and base_ring.is_absolute() and + elif (isinstance(base_ring, NumberField) and base_ring.degree() > 2 and base_ring.is_absolute() and a.denominator() == 1 == b.denominator() and base_ring.defining_polynomial().is_monic()): # This QuaternionAlgebraElement_number_field class is not # designed to work with elements of a quadratic field. To @@ -1026,8 +1031,9 @@ def discriminant(self): sage: QuaternionAlgebra(19).discriminant() 19 - sage: F.<a> = NumberField(x^2-x-1) - sage: B.<i,j,k> = QuaternionAlgebra(F, 2*a,F(-1)) + sage: x = polygen(ZZ, 'x') + sage: F.<a> = NumberField(x^2 - x - 1) + sage: B.<i,j,k> = QuaternionAlgebra(F, 2*a, F(-1)) sage: B.discriminant() Fractional ideal (2) @@ -1337,8 +1343,8 @@ def __init__(self, A, basis, check=True): sage: type(R) <class 'sage.algebras.quatalg.quaternion_algebra.QuaternionOrder_with_category'> - Over QQ and number fields it is checked whether the given - basis actually gives an order (as a module over the maximal order): + Over QQ and number fields it is checked whether the given + basis actually gives an order (as a module over the maximal order):: sage: A.<i,j,k> = QuaternionAlgebra(-1,-1) sage: A.quaternion_order([1,i,j,i-j]) @@ -1394,8 +1400,8 @@ def __init__(self, A, basis, check=True): raise ValueError("lattice must contain 1") # check if multiplicatively closed - M1 = basis_for_quaternion_lattice(basis) - M2 = basis_for_quaternion_lattice(list(basis) + [x * y for x in basis for y in basis]) + M1 = basis_for_quaternion_lattice(basis, reverse=False) + M2 = basis_for_quaternion_lattice(list(basis) + [x * y for x in basis for y in basis], reverse=False) if M1 != M2: raise ValueError("given lattice must be a ring") @@ -1787,6 +1793,42 @@ def unit_ideal(self): else: raise NotImplementedError("ideal only implemented for quaternion algebras over QQ") + def basis_matrix(self): + r""" + Return the basis matrix of this quaternion order, for the + specific basis returned by :meth:`basis()`. + + OUTPUT: matrix over `\QQ` + + EXAMPLES:: + + sage: O = QuaternionAlgebra(-11,-1).maximal_order() + sage: O.basis() + (1/2 + 1/2*i, 1/2*j - 1/2*k, i, -k) + sage: O.basis_matrix() + [ 1/2 1/2 0 0] + [ 0 0 1/2 -1/2] + [ 0 1 0 0] + [ 0 0 0 -1] + + Note that the returned matrix is *not* necessarily the same as + the basis matrix of the :meth:`unit_ideal()`:: + + sage: Q.<i,j,k> = QuaternionAlgebra(-1,-11) + sage: O = Q.quaternion_order([j,i,-1,k]) + sage: O.basis_matrix() + [ 0 0 1 0] + [ 0 1 0 0] + [-1 0 0 0] + [ 0 0 0 1] + sage: O.unit_ideal().basis_matrix() + [1 0 0 0] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + """ + return matrix(QQ, map(list, self.__basis)) + def __mul__(self, other): """ Every order equals its own unit ideal. Overload ideal multiplication @@ -2543,7 +2585,7 @@ def __mul__(self, right): # if self.__right_order == right.__left_order: # left_order = self.__left_order # right_order = right.__right_order - basis = tuple(basis_for_quaternion_lattice(gens)) + basis = tuple(basis_for_quaternion_lattice(gens, reverse=False)) A = self.quaternion_algebra() return A.ideal(basis, check=False) @@ -2686,7 +2728,7 @@ def multiply_by_conjugate(self, J): """ Jbar = [b.conjugate() for b in J.basis()] gens = [a * b for a in self.basis() for b in Jbar] - basis = tuple(basis_for_quaternion_lattice(gens)) + basis = tuple(basis_for_quaternion_lattice(gens, reverse=False)) R = self.quaternion_algebra() return R.ideal(basis, check=False) @@ -2786,8 +2828,8 @@ def cyclic_right_subideals(self, p, alpha=None): .. NOTE:: Currently, `p` must satisfy a bunch of conditions, or a - ``NotImplementedError`` is raised. In particular, `p` must be - odd and unramified in the quaternion algebra, must be + :class:`NotImplementedError` is raised. In particular, `p` must + be odd and unramified in the quaternion algebra, must be coprime to the index of the right order in the maximal order, and also coprime to the normal of self. (The Brandt modules code has a more general algorithm in some cases.) @@ -2894,7 +2936,7 @@ def cyclic_right_subideals(self, p, alpha=None): ####################################################################### -def basis_for_quaternion_lattice(gens, reverse=False): +def basis_for_quaternion_lattice(gens, reverse=None): r""" Return a basis for the `\ZZ`-lattice in a quaternion algebra spanned by the given gens. @@ -2913,12 +2955,18 @@ def basis_for_quaternion_lattice(gens, reverse=False): sage: from sage.algebras.quatalg.quaternion_algebra import basis_for_quaternion_lattice sage: A.<i,j,k> = QuaternionAlgebra(-1,-7) sage: basis_for_quaternion_lattice([i+j, i-j, 2*k, A(1/3)]) + doctest:warning ... DeprecationWarning: ... [1/3, i + j, 2*j, 2*k] sage: basis_for_quaternion_lattice([A(1),i,j,k]) [1, i, j, k] """ + if reverse is None: + from sage.misc.superseded import deprecation + deprecation(34880, 'The default value for the "reverse" argument to basis_for_quaternion_lattice() will' + ' change from False to True. Pass the argument explicitly to silence this warning.') + reverse = False if not gens: return [] Z, d = quaternion_algebra_cython.integral_matrix_and_denom_from_rational_quaternions(gens, reverse) diff --git a/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx b/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx index 0d110aad7e3..983e2515c04 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx @@ -25,7 +25,7 @@ AUTHORS: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** from sage.rings.integer_ring import ZZ @@ -38,12 +38,12 @@ from sage.matrix.matrix_rational_dense cimport Matrix_rational_dense from .quaternion_algebra_element cimport QuaternionAlgebraElement_rational_field from sage.libs.gmp.mpz cimport mpz_t, mpz_lcm, mpz_init, mpz_set, mpz_clear, mpz_init_set, mpz_mul, mpz_fdiv_q, mpz_cmp_si -from sage.libs.gmp.mpq cimport mpq_set_num, mpq_set_den, mpq_canonicalize from sage.libs.flint.fmpz cimport fmpz_set_mpz from sage.libs.flint.fmpq cimport fmpq_canonicalise from sage.libs.flint.fmpq_mat cimport fmpq_mat_entry_num, fmpq_mat_entry_den, fmpq_mat_entry + def integral_matrix_and_denom_from_rational_quaternions(v, reverse=False): r""" Given a list of rational quaternions, return matrix `A` over `\ZZ` @@ -96,7 +96,6 @@ def integral_matrix_and_denom_from_rational_quaternions(v, reverse=False): # Now fill in each row x of A, multiplying it by q = d/denom(x) cdef mpz_t q - cdef mpz_t* row cdef mpz_t tmp mpz_init(q) mpz_init(tmp) @@ -105,26 +104,27 @@ def integral_matrix_and_denom_from_rational_quaternions(v, reverse=False): mpz_fdiv_q(q, d.value, x.d) if reverse: mpz_mul(tmp, q, x.x) - A.set_unsafe_mpz(n-i-1,3,tmp) + A.set_unsafe_mpz(n-i-1, 3, tmp) mpz_mul(tmp, q, x.y) - A.set_unsafe_mpz(n-i-1,2,tmp) + A.set_unsafe_mpz(n-i-1, 2, tmp) mpz_mul(tmp, q, x.z) - A.set_unsafe_mpz(n-i-1,1,tmp) + A.set_unsafe_mpz(n-i-1, 1, tmp) mpz_mul(tmp, q, x.w) - A.set_unsafe_mpz(n-i-1,0,tmp) + A.set_unsafe_mpz(n-i-1, 0, tmp) else: mpz_mul(tmp, q, x.x) - A.set_unsafe_mpz(i,0,tmp) + A.set_unsafe_mpz(i, 0, tmp) mpz_mul(tmp, q, x.y) - A.set_unsafe_mpz(i,1,tmp) + A.set_unsafe_mpz(i, 1, tmp) mpz_mul(tmp, q, x.z) - A.set_unsafe_mpz(i,2,tmp) + A.set_unsafe_mpz(i, 2, tmp) mpz_mul(tmp, q, x.w) - A.set_unsafe_mpz(i,3,tmp) + A.set_unsafe_mpz(i, 3, tmp) mpz_clear(q) mpz_clear(tmp) return A, d + def rational_matrix_from_rational_quaternions(v, reverse=False): r""" Return matrix over the rationals whose rows have entries the @@ -166,7 +166,7 @@ def rational_matrix_from_rational_quaternions(v, reverse=False): fmpz_set_mpz(fmpq_mat_entry_num(A._matrix, n-i-1, 1), x.z) fmpz_set_mpz(fmpq_mat_entry_num(A._matrix, n-i-1, 0), x.w) - if mpz_cmp_si(x.d,1): + if mpz_cmp_si(x.d, 1): for j in range(4): fmpz_set_mpz(fmpq_mat_entry_den(A._matrix, n-i-1, j), x.d) fmpq_canonicalise(fmpq_mat_entry(A._matrix, n-i-1, j)) @@ -178,13 +178,14 @@ def rational_matrix_from_rational_quaternions(v, reverse=False): fmpz_set_mpz(fmpq_mat_entry_num(A._matrix, i, 2), x.z) fmpz_set_mpz(fmpq_mat_entry_num(A._matrix, i, 3), x.w) - if mpz_cmp_si(x.d,1): + if mpz_cmp_si(x.d, 1): for j in range(4): fmpz_set_mpz(fmpq_mat_entry_den(A._matrix, i, j), x.d) fmpq_canonicalise(fmpq_mat_entry(A._matrix, i, j)) return A + def rational_quaternions_from_integral_matrix_and_denom(A, Matrix_integer_dense H, Integer d, reverse=False): r""" Given an integral matrix and denominator, returns a list of @@ -222,14 +223,14 @@ def rational_quaternions_from_integral_matrix_and_denom(A, Matrix_integer_dense cdef Integer a, b a = Integer(A.invariants()[0]) b = Integer(A.invariants()[1]) - cdef Py_ssize_t i, j + cdef Py_ssize_t i cdef mpz_t tmp mpz_init(tmp) if reverse: - rng = xrange(H.nrows()-1, -1, -1) + rng = range(H.nrows()-1, -1, -1) else: - rng = xrange(H.nrows()) + rng = range(H.nrows()) for i in rng: x = <QuaternionAlgebraElement_rational_field> QuaternionAlgebraElement_rational_field.__new__(QuaternionAlgebraElement_rational_field) @@ -237,26 +238,26 @@ def rational_quaternions_from_integral_matrix_and_denom(A, Matrix_integer_dense mpz_set(x.a, a.value) mpz_set(x.b, b.value) if reverse: - H.get_unsafe_mpz(i,3,tmp) + H.get_unsafe_mpz(i, 3, tmp) mpz_init_set(x.x, tmp) - H.get_unsafe_mpz(i,2,tmp) + H.get_unsafe_mpz(i, 2, tmp) mpz_init_set(x.y, tmp) - H.get_unsafe_mpz(i,1,tmp) + H.get_unsafe_mpz(i, 1, tmp) mpz_init_set(x.z, tmp) - H.get_unsafe_mpz(i,0,tmp) + H.get_unsafe_mpz(i, 0, tmp) mpz_init_set(x.w, tmp) else: - H.get_unsafe_mpz(i,0,tmp) + H.get_unsafe_mpz(i, 0, tmp) mpz_init_set(x.x, tmp) - H.get_unsafe_mpz(i,1,tmp) + H.get_unsafe_mpz(i, 1, tmp) mpz_init_set(x.y, tmp) - H.get_unsafe_mpz(i,2,tmp) + H.get_unsafe_mpz(i, 2, tmp) mpz_init_set(x.z, tmp) - H.get_unsafe_mpz(i,3,tmp) + H.get_unsafe_mpz(i, 3, tmp) mpz_init_set(x.w, tmp) mpz_init_set(x.d, d.value) - # WARNING -- we do *not* canonicalize the entries in the quaternion. This is - # I think _not_ needed for quaternion_element.pyx + # WARNING -- we do *not* canonicalize the entries in the quaternion. + # This is I think _not_ needed for quaternion_element.pyx v.append(x) mpz_clear(tmp) return v diff --git a/src/sage/algebras/quatalg/quaternion_algebra_element.pxd b/src/sage/algebras/quatalg/quaternion_algebra_element.pxd index 8ffc4722d9c..243cae8e222 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_element.pxd +++ b/src/sage/algebras/quatalg/quaternion_algebra_element.pxd @@ -8,15 +8,15 @@ from sage.categories.morphism cimport Morphism cdef class QuaternionAlgebraElement_abstract(AlgebraElement): cpdef bint is_constant(self) - cdef _do_print(self, x,y,z,w) + cdef _do_print(self, x, y, z, w) cpdef conjugate(self) cpdef reduced_norm(self) cpdef reduced_trace(self) cdef class QuaternionAlgebraElement_generic(QuaternionAlgebraElement_abstract): cdef object x, y, z, w - # we will assume that our element has the representation - # x + yi + zj + wk, where i^2 = a, j^2 = b + # we will assume that our element has the representation + # x + yi + zj + wk, where i^2 = a, j^2 = b cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstract): cdef fmpz_poly_t x, y, z, w, a, b, modulus diff --git a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx index 4d4f0ead756..723c284989e 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx @@ -32,12 +32,10 @@ Check that :trac:`20829` is fixed:: # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.element cimport AlgebraElement, RingElement, ModuleElement, Element +from sage.structure.element cimport AlgebraElement, Element from sage.structure.richcmp cimport rich_to_bool, rich_to_bool_sgn, richcmp_item -from sage.algebras.quatalg.quaternion_algebra_element cimport QuaternionAlgebraElement_abstract from sage.rings.rational cimport Rational from sage.rings.integer cimport Integer -from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint from sage.rings.number_field.number_field_element cimport NumberFieldElement from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.matrix.constructor import matrix @@ -349,21 +347,21 @@ cdef class QuaternionAlgebraElement_abstract(AlgebraElement): """ cdef bint atomic = self._parent._base._repr_option('element_is_atomic') v = [] - i,j,k = self._parent.variable_names() + i, j, k = self._parent.variable_names() if x: v.append(str(x)) - c = print_coeff(y,i,atomic) + c = print_coeff(y, i, atomic) if c: v.append(c) - c = print_coeff(z,j,atomic) + c = print_coeff(z, j, atomic) if c: v.append(c) - c = print_coeff(w,k,atomic) + c = print_coeff(w, k, atomic) if c: v.append(c) if not v: return '0' - return ' + '.join(v).replace('+ -','- ') + return ' + '.join(v).replace('+ -', '- ') def _repr_(self): """ @@ -467,7 +465,8 @@ cdef class QuaternionAlgebraElement_abstract(AlgebraElement): sage: theta.reduced_norm() w^2*a*b - y^2*a - z^2*b + x^2 """ - a,b,x,y,z,w = self._parent._a,self._parent._b,self[0],self[1],self[2],self[3] + a, b = self._parent._a, self._parent._b + x, y, z, w = self[0], self[1], self[2], self[3] return w*w*a*b - y*y*a - z*z*b + x*x def __invert__(self): @@ -515,6 +514,7 @@ cdef class QuaternionAlgebraElement_abstract(AlgebraElement): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2-x-1); Q.<i,j,k> = QuaternionAlgebra(K,-1,-1); z=2*i+3*j+4/3*k+5/8 sage: a*z 5/8*a + 2*a*i + 3*a*j + 4/3*a*k @@ -529,6 +529,7 @@ cdef class QuaternionAlgebraElement_abstract(AlgebraElement): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2-x-1); Q.<i,j,k> = QuaternionAlgebra(K,-1,-1); z=2*i+3*j+4/3*k+5/8 sage: z*a 5/8*a + 2*a*i + 3*a*j + 4/3*a*k @@ -819,10 +820,10 @@ cdef class QuaternionAlgebraElement_generic(QuaternionAlgebraElement_abstract): x1, y1, z1, w1 = self.x, self.y, self.z, self.w x2, y2, z2, w2 = right.x, right.y, right.z, right.w - #x = x1*x2 + y1*y2*a + z1*z2*b - w1*w2*a*b - #y = x1*y2 + y1*x2 - z1*w2*b + w1*z2*b - #z = x1*z2 + y1*w2 + z1*x2 - w1*y2*a - #w = x1*w2 + y1*z2 - z1*y2 + w1*x2 + # x = x1*x2 + y1*y2*a + z1*z2*b - w1*w2*a*b + # y = x1*y2 + y1*x2 - z1*w2*b + w1*z2*b + # z = x1*z2 + y1*w2 + z1*x2 - w1*y2*a + # w = x1*w2 + y1*z2 - z1*y2 + w1*x2 t1 = x1 * x2 t2 = y1 * y2 @@ -834,7 +835,7 @@ cdef class QuaternionAlgebraElement_generic(QuaternionAlgebraElement_abstract): t8 = y1 * w2 x = t1 + a * t2 + b * (t3 - a*t4) - y = (x1 + y1)*(x2 + y2) - t1 - t2 + b*( (z1 + w1)*(z2 - w2) - t3 + t4) + y = (x1 + y1)*(x2 + y2) - t1 - t2 + b*((z1 + w1)*(z2 - w2) - t3 + t4) z = t5 - a*t6 + t7 + a*t8 w = (x2 - y2)*(z1 + w1) - t5 + t6 + (x1 + y1)*(z2 + w2) - t7 - t8 @@ -896,7 +897,7 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst mpz_init(self.b) mpz_init(self.d) - def __dealloc__(self): + def __dealloc__(self): mpz_clear(self.x) mpz_clear(self.y) mpz_clear(self.z) @@ -1040,7 +1041,7 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst cdef Rational x, y, z, w cdef mpz_t lcm cdef mpq_t lcm_rat - if not isinstance(v, (list,tuple)): + if not isinstance(v, (list, tuple)): try: x = Rational(v) mpz_set(self.x, mpq_numref(x.value)) @@ -1060,7 +1061,7 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst z = Rational(v[2]) w = Rational(v[3]) else: - x,y,z,w = v + x, y, z, w = v mpz_init(lcm) mpz_lcm(lcm, mpq_denref(x.value), mpq_denref(y.value)) mpz_lcm(lcm, lcm, mpq_denref(z.value)) @@ -1172,7 +1173,7 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst mpz_mul(U2, right.w, self.d) # U2 = w2 * d1 mpz_add(result.w, U1, U2) # w3 = w1 * d2 + w2 * d1 - mpz_mul(result.d, self.d, right.d) # d3 = d1 * d2 + mpz_mul(result.d, self.d, right.d) # d3 = d1 * d2 result.canonicalize() @@ -1286,7 +1287,7 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst mpz_add(s1, self.x, self.y) # s1 = x1 + y1 mpz_add(s2, self.z, self.w) # s2 = z1 + w1 - #------------------ + # ------------------ mpz_mul(U1, self.a, t4) mpz_sub(U1, t3, U1) @@ -1295,7 +1296,7 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst mpz_add(result.x, T1, U2) mpz_add(result.x, result.x, U1) - #------------------ + # ------------------ mpz_sub(U1, right.z, right.w) mpz_mul(U1, U1, s2) @@ -1308,7 +1309,7 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst mpz_mul(U2, s1, U2) mpz_add(result.y, U1, U2) - #------------------ + # ------------------ mpz_mul(U1, self.a, t8) mpz_add(U1, U1, t7) @@ -1316,7 +1317,7 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst mpz_sub(U1, U1, U2) mpz_add(result.z, U1, t5) - #------------------ + # ------------------ mpz_add(U1, right.z, right.w) mpz_mul(U1, U1, s1) @@ -1328,8 +1329,6 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst mpz_mul(U2, U2, s2) mpz_add(result.w, U1, U2) - - mpz_mul(result.d, self.d, right.d) result.canonicalize() @@ -1425,8 +1424,6 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst sage: a.reduced_trace() 2/3 """ - #return 2*self[0] - mpz_mul_si(U1, self.x, 2) cdef Rational result = Rational.__new__(Rational) mpq_set_num(result.value, U1) @@ -1455,7 +1452,6 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst # Implementation-wise, we compute the GCD's one at a time, # and quit if it ever becomes one - mpz_gcd(U1, self.d, self.x) if mpz_cmp_ui(U1, 1) != 0: mpz_gcd(U1, U1, self.y) @@ -1552,8 +1548,6 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst return (x, y, z, w) - - def coefficient_tuple(self): """ Return 4-tuple of rational numbers which are the coefficients of this quaternion. @@ -1705,15 +1699,15 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra x, y, z, w = v cdef NumberFieldElement a = <NumberFieldElement>(parent._base(parent._a)) cdef NumberFieldElement b = <NumberFieldElement>(parent._base(parent._b)) - fmpz_poly_set_ZZX(self.x, (<NumberFieldElement>x).__numerator) - fmpz_poly_set_ZZX(self.y, (<NumberFieldElement>y).__numerator) - fmpz_poly_set_ZZX(self.z, (<NumberFieldElement>z).__numerator) - fmpz_poly_set_ZZX(self.w, (<NumberFieldElement>w).__numerator) + fmpz_poly_set_ZZX(self.x, (<NumberFieldElement>x)._numerator) + fmpz_poly_set_ZZX(self.y, (<NumberFieldElement>y)._numerator) + fmpz_poly_set_ZZX(self.z, (<NumberFieldElement>z)._numerator) + fmpz_poly_set_ZZX(self.w, (<NumberFieldElement>w)._numerator) - ZZ_to_mpz(T1, &(<NumberFieldElement>x).__denominator) - ZZ_to_mpz(T2, &(<NumberFieldElement>y).__denominator) - ZZ_to_mpz(t3, &(<NumberFieldElement>z).__denominator) - ZZ_to_mpz(t4, &(<NumberFieldElement>w).__denominator) + ZZ_to_mpz(T1, &(<NumberFieldElement>x)._denominator) + ZZ_to_mpz(T2, &(<NumberFieldElement>y)._denominator) + ZZ_to_mpz(t3, &(<NumberFieldElement>z)._denominator) + ZZ_to_mpz(t4, &(<NumberFieldElement>w)._denominator) mpz_lcm(self.d, T1, T2) mpz_lcm(self.d, self.d, t3) @@ -1729,10 +1723,10 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra fmpz_poly_scalar_mul_mpz(self.z, self.z, t3) fmpz_poly_scalar_mul_mpz(self.w, self.w, t4) - fmpz_poly_set_ZZX(self.a, a.__numerator) # we will assume that the denominator of a and b are 1 - fmpz_poly_set_ZZX(self.b, b.__numerator) + fmpz_poly_set_ZZX(self.a, a._numerator) # we will assume that the denominator of a and b are 1 + fmpz_poly_set_ZZX(self.b, b._numerator) - fmpz_poly_set_ZZX(self.modulus, (<NumberFieldElement>x).__fld_numerator.x) # and same for the modulus + fmpz_poly_set_ZZX(self.modulus, (<NumberFieldElement>x)._fld_numerator.x) # and same for the modulus def __getitem__(self, int i): """ @@ -1761,17 +1755,17 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra cdef NumberFieldElement item = el._new() if i == 0: - fmpz_poly_get_ZZX(item.__numerator, self.x) + fmpz_poly_get_ZZX(item._numerator, self.x) elif i == 1: - fmpz_poly_get_ZZX(item.__numerator, self.y) + fmpz_poly_get_ZZX(item._numerator, self.y) elif i == 2: - fmpz_poly_get_ZZX(item.__numerator, self.z) + fmpz_poly_get_ZZX(item._numerator, self.z) elif i == 3: - fmpz_poly_get_ZZX(item.__numerator, self.w) + fmpz_poly_get_ZZX(item._numerator, self.w) else: raise IndexError("quaternion element index out of range") - mpz_to_ZZ(&item.__denominator, self.d) + mpz_to_ZZ(&item._denominator, self.d) return item @@ -1806,6 +1800,7 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra Check that the fix in :trac:`17099` is correct:: + sage: x = polygen(QQ, 'x') sage: K = NumberField(x**3 + x - 1, 'a') sage: D.<i,j,k> = QuaternionAlgebra(K, -1, -3) sage: j/3 + (2*j)/3 == j @@ -1884,7 +1879,6 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra cdef QuaternionAlgebraElement_number_field right = _right cdef QuaternionAlgebraElement_number_field result = <QuaternionAlgebraElement_number_field> QuaternionAlgebraElement_number_field.__new__(QuaternionAlgebraElement_number_field) - fmpz_poly_set(result.a, self.a) fmpz_poly_set(result.b, self.b) fmpz_poly_set(result.modulus, self.modulus) @@ -1982,7 +1976,7 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra fmpz_poly_add(fs1, self.x, self.y) # s1 = x1 + y1 fmpz_poly_add(fs2, self.z, self.w) # s2 = z1 + w - #------------------ + # ------------------ fmpz_poly_mul(fU1, self.a, ft4) fmpz_poly_sub(fU1, ft3, fU1) @@ -1991,7 +1985,7 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra fmpz_poly_add(result.x, fT1, fU2) fmpz_poly_add(result.x, result.x, fU1) - #------------------ + # ------------------ fmpz_poly_sub(fU1, right.z, right.w) fmpz_poly_mul(fU1, fU1, fs2) @@ -2004,7 +1998,7 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra fmpz_poly_mul(fU2, fs1, fU2) fmpz_poly_add(result.y, fU1, fU2) - #------------------ + # ------------------ fmpz_poly_mul(fU1, self.a, ft8) fmpz_poly_add(fU1, fU1, ft7) @@ -2012,7 +2006,7 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra fmpz_poly_sub(fU1, fU1, fU2) fmpz_poly_add(result.z, fU1, ft5) - #------------------ + # ------------------ fmpz_poly_add(fU1, right.z, right.w) fmpz_poly_mul(fU1, fU1, fs1) diff --git a/src/sage/algebras/rational_cherednik_algebra.py b/src/sage/algebras/rational_cherednik_algebra.py index 597954c7249..3b85c1e13a3 100644 --- a/src/sage/algebras/rational_cherednik_algebra.py +++ b/src/sage/algebras/rational_cherednik_algebra.py @@ -237,7 +237,7 @@ def algebra_generators(self): sage: list(R.algebra_generators()) [a1, a2, s1, s2, ac1, ac2] """ - keys = ['a'+str(i) for i in self._cartan_type.index_set()] + keys = ['a'+str(i) for i in self._cartan_type.index_set()] keys += ['s'+str(i) for i in self._cartan_type.index_set()] keys += ['ac'+str(i) for i in self._cartan_type.index_set()] diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index b716db0ce94..ff960e56dd9 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -41,7 +41,7 @@ from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra from sage.combinat.tableau import SemistandardTableaux -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.matrix.constructor import Matrix from sage.misc.cachefunc import cached_method from sage.misc.flatten import flatten diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index 26c8a40f485..5d383f8dfab 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -972,7 +972,7 @@ def expansion_on_basis(self, w): sage: S.expansion_on_basis(Word('abab')) 2*B[aabb] + B[abab] """ - from sage.arith.all import factorial + from sage.arith.misc import factorial if not w: return self._alg.one() if len(w) == 1: diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index e19a2bb6d9a..3b0dfce4586 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -217,7 +217,7 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): deg = monic_polynomial.degree() from sage.structure.category_object import normalize_names - self._root_names = normalize_names(deg-1, names) + self._root_names = normalize_names(deg-1, names) root_names = list(self._root_names) verbose("Create splitting algebra to base ring %s and polynomial %s (%s %s)" % (base_ring, monic_polynomial, iterate, warning)) @@ -238,8 +238,8 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): if deg < 1: raise ValueError("the degree of the polynomial must positive") - self._splitting_roots = [] - self._coefficients_list = [] + self._splitting_roots = [] + self._coefficients_list = [] self._invertible_elements = {} if isinstance(base_ring, SplittingAlgebra): @@ -289,12 +289,12 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): SplittingAlgebra.__init__(self, q, root_names_reduces, warning=False) - splitting_roots = base_ring_step._splitting_roots + self._splitting_roots + splitting_roots = base_ring_step._splitting_roots + self._splitting_roots coefficients_list = base_ring_step._coefficients_list + self._coefficients_list verbose("Adding roots: %s" % (splitting_roots)) - self._splitting_roots = splitting_roots + self._splitting_roots = splitting_roots self._coefficients_list = coefficients_list else: PolynomialQuotientRing_domain.__init__(self, P, p, root_name) @@ -318,41 +318,39 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): self._splitting_roots = [self(root) for root in self._splitting_roots] verbose("splitting_roots: %s embedded" % (self._splitting_roots)) - - # ------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------- # try to calculate inverses of the roots. This is possible if the original polynomial # has an invertible constant term. For example let cf = [-w, v,-u, 1] that is # p = h^3 -u*h^2 + v*h -w, than u = x + y + z, v = x*y + x*z + y*z, w = x*y*z. If # w is invertible then 1/x = (v -(u-x)*x)/w, 1/y = (v -(u-y)*y)/w, 1/z = (v -(u-z)*z)/w - # ------------------------------------------------------------------------------------------- + # ----------------------------------------------------------------- # first find the polynomial with invertible constant coefficient - # ------------------------------------------------------------------------------------------- + # ----------------------------------------------------------------- cf0_inv = None for cf in self._coefficients_list: cf0 = cf[0] try: cf0_inv = ~(cf[0]) cf0_inv = self(cf0_inv) - verbose("invertible coefficient: %s found" %(cf0_inv)) + verbose("invertible coefficient: %s found" % (cf0_inv)) break except NotImplementedError: - verbose("constant coefficient: %s not invertibe" %(cf0)) - + verbose("constant coefficient: %s not invertibe" % (cf0)) - # ---------------------------------------------------------------------------------- - # assuming that cf splits into linear factors over self and the _splitting_roots - # are its roots we can calculate inverses - # ---------------------------------------------------------------------------------- + # ------------------------------------------------------------------ + # assuming that cf splits into linear factors over self + # and the _splitting_roots are its roots we can calculate inverses + # ------------------------------------------------------------------ if cf0_inv is not None: deg_cf = len(cf)-1 - pf = P(cf) + pf = P(cf) for root in self._splitting_roots: check = self(pf) if not check.is_zero(): continue root_inv = self.one() for pos in range(deg_cf-1 ): - root_inv = (-1 )**(pos+1 ) * cf[deg_cf-pos-1 ] - root_inv * root + root_inv = (-1 )**(pos+1 ) * cf[deg_cf-pos-1 ] - root_inv * root verbose("inverse %s of root %s" % (root_inv, root)) root_inv = (-1 )**(deg_cf) * cf0_inv * root_inv self._invertible_elements.update({root:root_inv}) @@ -362,12 +360,11 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): self._invertible_elements.update({v: k}) return - - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- + ######################################################################## + # ---------------------------------------------------------------------- # overloaded inherited methods - # --------------------------------------------------------------------------------------------------------------------- - ####################################################################################################################### + # ---------------------------------------------------------------------- + ######################################################################## def __reduce__(self): r""" Used in pickling. @@ -397,7 +394,6 @@ def __reduce__(self): defining_polynomial = par_pol(definig_coefficients) return self.__class__, (defining_polynomial, self._root_names, self._iterate, False) - def _repr_(self): r""" Return a string representation of ``self``. @@ -514,20 +510,17 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): lift = self.lifting_map() return hom_from_cover*lift - - - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- + ################################################################### + # ----------------------------------------------------------------- # local methods - # --------------------------------------------------------------------------------------------------------------------- - ####################################################################################################################### + # ----------------------------------------------------------------- + ################################################################### - - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- + ################################################################### + # ----------------------------------------------------------------- # global methods - # --------------------------------------------------------------------------------------------------------------------- - ####################################################################################################################### + # ----------------------------------------------------------------- + ################################################################### def is_completely_split(self): r""" @@ -727,7 +720,6 @@ def create_roots(monic_polynomial, warning=True): roots = [(r, 1) for r in ext_ring.splitting_roots()] return roots - deg_pol = monic_polynomial.degree() if not root_names: from sage.structure.category_object import normalize_names @@ -740,12 +732,12 @@ def create_roots(monic_polynomial, warning=True): pass if not root_list: - # ------------------------------------------------------------------------------ + # -------------------------------------------------------------- # no roots found: find roots in an appropriate extension ring - # ------------------------------------------------------------------------------ + # -------------------------------------------------------------- verbose("no roots in base_ring") - if len(name_list) > deg_pol -1: - name_list = [name_list[i] for i in range(deg_pol-1)] + if len(name_list) > deg_pol - 1: + name_list = [name_list[i] for i in range(deg_pol - 1)] roots = create_roots(monic_polynomial, warning=warning) else: diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index 49b281d9a49..978a3557a9d 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -455,7 +455,9 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.misc.lazy_attribute import lazy_attribute from sage.misc.cachefunc import cached_method -from sage.categories.all import ModulesWithBasis, tensor, Hom +from sage.categories.modules_with_basis import ModulesWithBasis +from sage.categories.tensor import tensor +from sage.categories.homset import Hom ###################################################### # the main class @@ -584,7 +586,7 @@ def __init__(self, p=2, basis='milnor', **kwds): sage: A1 == SteenrodAlgebra(2, profile=[2,1], basis='pst') False """ - from sage.arith.all import is_prime + from sage.arith.misc import is_prime from sage.categories.super_hopf_algebras_with_basis import SuperHopfAlgebrasWithBasis from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets diff --git a/src/sage/algebras/steenrod/steenrod_algebra_bases.py b/src/sage/algebras/steenrod/steenrod_algebra_bases.py index f028e6d5df5..c289b284fe1 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_bases.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_bases.py @@ -834,12 +834,12 @@ def degree_dictionary(n, basis): """ dict = {} if basis.find('wood') >= 0: - k=0 - m=0 + k = 0 + m = 0 deg = 2**m * (2**(k+1) - 1) while deg <= n: dict[deg] = (m,k) - if m>0: + if m > 0: m = m - 1 k = k + 1 else: @@ -847,8 +847,8 @@ def degree_dictionary(n, basis): k = 0 deg = 2**m * (2**(k+1) - 1) elif basis.find('wall') >= 0 or basis.find('arnon') >= 0: - k=0 - m=0 + k = 0 + m = 0 deg = 2**k * (2**(m-k+1) - 1) while deg <= n: dict[deg] = (m,k) @@ -859,8 +859,8 @@ def degree_dictionary(n, basis): k = k - 1 deg = 2**k * (2**(m-k+1) - 1) elif basis.find('pst') >= 0 or basis.find('comm') >= 0: - s=0 - t=1 + s = 0 + t = 1 deg = 2**s * (2**t - 1) while deg <= n: if basis.find('pst') >= 0: @@ -1128,7 +1128,7 @@ def steenrod_basis_error_check(dim, p, **kwds): for i in range(dim): if i % 5 == 0: - verbose("up to dimension %s"%i) + verbose("up to dimension %s" % i) milnor_dim = len(steenrod_algebra_basis.f(i,'milnor',p=p,generic=generic)) for B in bases: if milnor_dim != len(steenrod_algebra_basis.f(i,B,p,generic=generic)): @@ -1147,7 +1147,7 @@ def steenrod_basis_error_check(dim, p, **kwds): for i in range(dim): if i % 5 == 0: - verbose("up to dimension %s"%i) + verbose("up to dimension %s" % i) for pro in profiles: milnor_dim = len(steenrod_algebra_basis.f(i,'milnor',p=p,profile=pro,generic=generic)) for B in bases: diff --git a/src/sage/algebras/steenrod/steenrod_algebra_misc.py b/src/sage/algebras/steenrod/steenrod_algebra_misc.py index d8fedad70b8..91ab657a84f 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_misc.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_misc.py @@ -177,7 +177,7 @@ def get_basis_name(basis, p, generic=None): if basis.find('long') >= 0: result = result + '_long' else: - gencase = " for the generic Steenrod algebra" if p==2 and generic else "" + gencase = " for the generic Steenrod algebra" if p == 2 and generic else "" raise ValueError("%s is not a recognized basis%s at the prime %s" % (basis, gencase, p)) return result diff --git a/src/sage/algebras/steenrod/steenrod_algebra_mult.py b/src/sage/algebras/steenrod/steenrod_algebra_mult.py index ec92c86fcc5..1fb52aba028 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_mult.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_mult.py @@ -611,8 +611,9 @@ def multinomial_odd(list,p): sage: multinomial_odd([1,2,4], 107) 105 """ - from sage.rings.all import GF, Integer - from sage.arith.all import binomial + from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + from sage.rings.integer import Integer + from sage.arith.misc import binomial n = sum(list) answer = 1 F = GF(p) diff --git a/src/sage/algebras/yokonuma_hecke_algebra.py b/src/sage/algebras/yokonuma_hecke_algebra.py index 700395a2d84..df474b8d4f7 100644 --- a/src/sage/algebras/yokonuma_hecke_algebra.py +++ b/src/sage/algebras/yokonuma_hecke_algebra.py @@ -183,7 +183,7 @@ def _latex_(self): sage: latex(Y) \mathcal{Y}_{5,2}(q) """ - return "\\mathcal{Y}_{%s,%s}(%s)"%(self._d, self._n, self._q) + return "\\mathcal{Y}_{%s,%s}(%s)" % (self._d, self._n, self._q) def _repr_term(self, m): """ @@ -195,8 +195,8 @@ def _repr_term(self, m): sage: Y._repr_term( ((1, 0, 2), Permutation([3,2,1])) ) 't1*t3^2*g[2,1,2]' """ - gen_str = lambda e: '' if e == 1 else '^%s'%e - lhs = '*'.join('t%s'%(j+1) + gen_str(i) for j,i in enumerate(m[0]) if i > 0) + gen_str = lambda e: '' if e == 1 else '^%s' % e + lhs = '*'.join('t%s' % (j+1) + gen_str(i) for j,i in enumerate(m[0]) if i > 0) redword = m[1].reduced_word() if not redword: if not lhs: @@ -217,14 +217,14 @@ def _latex_term(self, m): sage: Y._latex_term( ((1, 0, 2), Permutation([3,2,1])) ) 't_{1} t_{3}^2 g_{2} g_{1} g_{2}' """ - gen_str = lambda e: '' if e == 1 else '^%s'%e - lhs = ' '.join('t_{%s}'%(j+1) + gen_str(i) for j,i in enumerate(m[0]) if i > 0) + gen_str = lambda e: '' if e == 1 else '^%s' % e + lhs = ' '.join('t_{%s}' % (j+1) + gen_str(i) for j,i in enumerate(m[0]) if i > 0) redword = m[1].reduced_word() if not redword: if not lhs: return '1' return lhs - return lhs + ' ' + ' '.join("g_{%d}"%i for i in redword) + return lhs + ' ' + ' '.join("g_{%d}" % i for i in redword) @cached_method def algebra_generators(self): @@ -243,10 +243,10 @@ def algebra_generators(self): for i in range(self._n): r = list(zero) # Make a copy r[i] = 1 - d['t%s'%(i+1)] = self.monomial( (tuple(r), one) ) + d['t%s' % (i+1)] = self.monomial( (tuple(r), one) ) G = self._Pn.group_generators() for i in range(1, self._n): - d['g%s'%i] = self.monomial( (tuple(zero), G[i]) ) + d['g%s' % i] = self.monomial( (tuple(zero), G[i]) ) return Family(sorted(d), lambda i: d[i]) @cached_method @@ -323,8 +323,8 @@ def g(self, i=None): """ G = self.algebra_generators() if i is None: - return [G['g%s'%i] for i in range(1, self._n)] - return G['g%s'%i] + return [G['g%s' % i] for i in range(1, self._n)] + return G['g%s' % i] def t(self, i=None): """ @@ -345,8 +345,8 @@ def t(self, i=None): """ G = self.algebra_generators() if i is None: - return [G['t%s'%i] for i in range(1, self._n+1)] - return G['t%s'%i] + return [G['t%s' % i] for i in range(1, self._n+1)] + return G['t%s' % i] def product_on_basis(self, m1, m2): """ @@ -488,7 +488,7 @@ def __invert__(self): if not self: raise ZeroDivisionError if len(self) != 1: - raise NotImplementedError("inverse only implemented for basis elements (monomials in the generators)"%self) + raise NotImplementedError("inverse only implemented for basis elements (monomials in the generators)" % self) H = self.parent() t,w = self.support_of_term() c = ~self.coefficients()[0] diff --git a/src/sage/all.py b/src/sage/all.py index 93588df1b93..b54610c819d 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -54,87 +54,12 @@ # **************************************************************************** import os -import sys import operator import math -############ setup warning filters before importing Sage stuff #### -import warnings - -__with_pydebug = hasattr(sys, 'gettotalrefcount') # This is a Python debug build (--with-pydebug) -if __with_pydebug: - # a debug build does not install the default warning filters. Sadly, this breaks doctests so we - # have to re-add them: - warnings.filterwarnings('ignore', category=PendingDeprecationWarning) - warnings.filterwarnings('ignore', category=ImportWarning) - warnings.filterwarnings('ignore', category=ResourceWarning) -else: - deprecationWarning = ('ignore', None, DeprecationWarning, None, 0) - if deprecationWarning in warnings.filters: - warnings.filters.remove(deprecationWarning) - -# Ignore all deprecations from IPython etc. -warnings.filterwarnings('ignore', category=DeprecationWarning, - module='(IPython|ipykernel|jupyter_client|jupyter_core|nbformat|notebook|ipywidgets|storemagic|jedi)') - -# scipy 1.18 introduced reprecation warnings on a number of things they are moving to -# numpy, e.g. DeprecationWarning: scipy.array is deprecated -# and will be removed in SciPy 2.0.0, use numpy.array instead -# This affects networkx 2.2 up and including 2.4 (cf. :trac:29766) -warnings.filterwarnings('ignore', category=DeprecationWarning, - module='(scipy|networkx)') - -# However, be sure to keep OUR deprecation warnings -warnings.filterwarnings('default', category=DeprecationWarning, - message=r'[\s\S]*See https?://trac\.sagemath\.org/[0-9]* for details.') - -# Ignore Python 3.9 deprecation warnings -warnings.filterwarnings('ignore', category=DeprecationWarning, - module='ast') - -# Ignore packaging 20.5 deprecation warnings -warnings.filterwarnings('ignore', category=DeprecationWarning, - module='(.*[.]_vendor[.])?packaging') - -# Ignore numpy warnings triggered by pythran -warnings.filterwarnings('ignore', category=DeprecationWarning, - module='pythran') - -warnings.filterwarnings('ignore', category=DeprecationWarning, - message='The distutils(.sysconfig module| package) is deprecated', - module='Cython|distutils|numpy|sage.env|sage.features') - -# triggered by cython 0.29.32 -warnings.filterwarnings('ignore', category=DeprecationWarning, - message="'cgi' is deprecated and slated for removal in Python 3.13", - module='Cython') - -# triggered by pyparsing 2.4.7 -warnings.filterwarnings('ignore', category=DeprecationWarning, - message="module 'sre_constants' is deprecated", - module='pyparsing') - -# importlib.resources.path and ...read_binary are deprecated in python 3.11, -# but the replacement importlib.resources.files needs python 3.9 -warnings.filterwarnings('ignore', category=DeprecationWarning, - message=r'(path|read_binary) is deprecated\. Use files\(\) instead\.', - module='sage.repl.rich_output.output_(graphics|graphics3d|video)') - -# triggered by sphinx -warnings.filterwarnings('ignore', category=DeprecationWarning, - message="'imghdr' is deprecated and slated for removal in Python 3.13", - module='sphinx.util.images') - -# triggered by docutils 0.19 on Python 3.11 -warnings.filterwarnings('ignore', category=DeprecationWarning, - message=r"Use setlocale\(\), getencoding\(\) and getlocale\(\) instead", - module='docutils.io') - ################ end setup warnings ############################### - -from .all__sagemath_environment import * - +from .all__sagemath_repl import * # includes .all__sagemath_objects, .all__sagemath_environment ################################################################### @@ -149,13 +74,11 @@ from sage.misc.all import * # takes a while from sage.typeset.all import * -from sage.repl.all import * from sage.misc.sh import sh from sage.libs.all import * from sage.data_structures.all import * -from sage.doctest.all import * from sage.structure.all import * from sage.rings.all import * @@ -209,8 +132,6 @@ from sage.games.all import * -lazy_import('sage.media.wav', 'Wave', as_='wave', deprecation=12673) - from sage.logic.all import * from sage.numerical.all import * @@ -218,8 +139,6 @@ from sage.stats.all import * import sage.stats.all as stats -lazy_import("sage.finance", "all", as_="finance", deprecation=32427) - from sage.parallel.all import * from sage.ext.fast_callable import fast_callable @@ -271,10 +190,6 @@ copying = license copyright = license -_cpu_time_ = cputime() -_wall_time_ = walltime() - - def quit_sage(verbose=True): """ Does nothing. Code that needs cleanup should register its own diff --git a/src/sage/algebras/finite_dimensional_algebras/__init__.py b/src/sage/all__sagemath_bliss.py similarity index 100% rename from src/sage/algebras/finite_dimensional_algebras/__init__.py rename to src/sage/all__sagemath_bliss.py diff --git a/src/sage/algebras/fusion_rings/__init__.py b/src/sage/all__sagemath_coxeter3.py similarity index 100% rename from src/sage/algebras/fusion_rings/__init__.py rename to src/sage/all__sagemath_coxeter3.py diff --git a/src/sage/algebras/hecke_algebras/__init__.py b/src/sage/all__sagemath_mcqd.py similarity index 100% rename from src/sage/algebras/hecke_algebras/__init__.py rename to src/sage/all__sagemath_mcqd.py diff --git a/src/sage/algebras/letterplace/__init__.py b/src/sage/all__sagemath_meataxe.py similarity index 100% rename from src/sage/algebras/letterplace/__init__.py rename to src/sage/all__sagemath_meataxe.py diff --git a/src/sage/all__sagemath_repl.py b/src/sage/all__sagemath_repl.py index c9508c15bbe..8d0b43679ca 100644 --- a/src/sage/all__sagemath_repl.py +++ b/src/sage/all__sagemath_repl.py @@ -1,7 +1,88 @@ +############ setup warning filters before importing Sage stuff #### +import sys +import warnings + +__with_pydebug = hasattr(sys, 'gettotalrefcount') # This is a Python debug build (--with-pydebug) +if __with_pydebug: + # a debug build does not install the default warning filters. Sadly, this breaks doctests so we + # have to re-add them: + warnings.filterwarnings('ignore', category=PendingDeprecationWarning) + warnings.filterwarnings('ignore', category=ImportWarning) + warnings.filterwarnings('ignore', category=ResourceWarning) +else: + deprecationWarning = ('ignore', None, DeprecationWarning, None, 0) + if deprecationWarning in warnings.filters: + warnings.filters.remove(deprecationWarning) + +# Ignore all deprecations from IPython etc. +warnings.filterwarnings('ignore', category=DeprecationWarning, + module='(IPython|ipykernel|jupyter_client|jupyter_core|nbformat|notebook|ipywidgets|storemagic|jedi)') + +# scipy 1.18 introduced reprecation warnings on a number of things they are moving to +# numpy, e.g. DeprecationWarning: scipy.array is deprecated +# and will be removed in SciPy 2.0.0, use numpy.array instead +# This affects networkx 2.2 up and including 2.4 (cf. :trac:29766) +warnings.filterwarnings('ignore', category=DeprecationWarning, + module='(scipy|networkx)') + +# However, be sure to keep OUR deprecation warnings +warnings.filterwarnings('default', category=DeprecationWarning, + message=r'[\s\S]*See https?://trac\.sagemath\.org/[0-9]* for details.') + +# Ignore Python 3.9 deprecation warnings +warnings.filterwarnings('ignore', category=DeprecationWarning, + module='ast') + +# Ignore packaging 20.5 deprecation warnings +warnings.filterwarnings('ignore', category=DeprecationWarning, + module='(.*[.]_vendor[.])?packaging') + +# Ignore a few warnings triggered by pythran 0.12.1 +warnings.filterwarnings('ignore', category=DeprecationWarning, + message='\n\n `numpy.distutils` is deprecated since NumPy 1.23.0', + module='pythran.dist') +warnings.filterwarnings('ignore', category=DeprecationWarning, + message='pkg_resources is deprecated as an API|' + 'Deprecated call to `pkg_resources.declare_namespace(.*)`', + module='pkg_resources|setuptools.sandbox') +warnings.filterwarnings('ignore', category=DeprecationWarning, + message='msvccompiler is deprecated and slated to be removed', + module='distutils.msvccompiler') + +warnings.filterwarnings('ignore', category=DeprecationWarning, + message='The distutils(.sysconfig module| package) is deprecated', + module='Cython|distutils|numpy|sage.env|sage.features') + +# triggered by cython 0.29.32 +warnings.filterwarnings('ignore', category=DeprecationWarning, + message="'cgi' is deprecated and slated for removal in Python 3.13", + module='Cython') + +# triggered by pyparsing 2.4.7 +warnings.filterwarnings('ignore', category=DeprecationWarning, + message="module 'sre_constants' is deprecated", + module='pyparsing') + +# importlib.resources.path and ...read_binary are deprecated in python 3.11, +# but the replacement importlib.resources.files needs python 3.9 +warnings.filterwarnings('ignore', category=DeprecationWarning, + message=r'(path|read_binary) is deprecated\. Use files\(\) instead\.', + module='sage.repl.rich_output.output_(graphics|graphics3d|video)') + +# triggered by sphinx +warnings.filterwarnings('ignore', category=DeprecationWarning, + message="'imghdr' is deprecated and slated for removal in Python 3.13", + module='sphinx.util.images') + +# triggered by docutils 0.19 on Python 3.11 +warnings.filterwarnings('ignore', category=DeprecationWarning, + message=r"Use setlocale\(\), getencoding\(\) and getlocale\(\) instead", + module='docutils.io') + + from .all__sagemath_objects import * from .all__sagemath_environment import * -# FIXME: all.py should import from here and remove these imports. from sage.doctest.all import * from sage.repl.all import * from sage.misc.all__sagemath_repl import * diff --git a/src/sage/algebras/lie_algebras/__init__.py b/src/sage/all__sagemath_sirocco.py similarity index 100% rename from src/sage/algebras/lie_algebras/__init__.py rename to src/sage/all__sagemath_sirocco.py diff --git a/src/sage/algebras/lie_conformal_algebras/__init__.py b/src/sage/all__sagemath_tdlib.py similarity index 100% rename from src/sage/algebras/lie_conformal_algebras/__init__.py rename to src/sage/all__sagemath_tdlib.py diff --git a/src/sage/arith/constants.pxd b/src/sage/arith/constants.pxd index 6e5e713707f..371960ec3bc 100644 --- a/src/sage/arith/constants.pxd +++ b/src/sage/arith/constants.pxd @@ -13,14 +13,14 @@ # cdef extern from *: - double M_PI "0x3.243f6a8885a3p+0" # ฯ€ - double M_EULER "0x9.3c467e37db0c8p-4" # ฮณ - double M_LN2 "0xb.17217f7d1cf78p-4" # log(2) - double M_LN10 "0x2.4d763776aaa2cp+0" # log(10) - double M_LNPI "0x1.250d048e7a1bdp+0" # log(ฯ€) - double M_1_LN2 "0x1.71547652b82fep+0" # 1/log(2) - double M_1_LN10 "0x6.f2dec549b9438p-4" # 1/log(10) - double M_1_LNPI "0xd.fa22fdd8cfd98p-4" # 1/log(ฯ€) - double M_LN2_LN10 "0x4.d104d427de7fcp-4" # log(2)/log(10) + double M_PI "0x3.243f6a8885a3p+0" # ฯ€ + double M_EULER "0x9.3c467e37db0c8p-4" # ฮณ + double M_LN2 "0xb.17217f7d1cf78p-4" # log(2) + double M_LN10 "0x2.4d763776aaa2cp+0" # log(10) + double M_LNPI "0x1.250d048e7a1bdp+0" # log(ฯ€) + double M_1_LN2 "0x1.71547652b82fep+0" # 1/log(2) + double M_1_LN10 "0x6.f2dec549b9438p-4" # 1/log(10) + double M_1_LNPI "0xd.fa22fdd8cfd98p-4" # 1/log(ฯ€) + double M_LN2_LN10 "0x4.d104d427de7fcp-4" # log(2)/log(10) double LOG_TEN_TWO_PLUS_EPSILON "0x3.5269e12f346e4p+0" # log(10,2) rounded up diff --git a/src/sage/arith/functions.pxd b/src/sage/arith/functions.pxd index b883b489be1..9ddfc38b38b 100644 --- a/src/sage/arith/functions.pxd +++ b/src/sage/arith/functions.pxd @@ -1,4 +1,3 @@ cpdef LCM_list(v) cdef LCM_generic(itr, ret) - diff --git a/src/sage/arith/functions.pyx b/src/sage/arith/functions.pyx index 2fe15bbb974..db49367b7f4 100644 --- a/src/sage/arith/functions.pyx +++ b/src/sage/arith/functions.pyx @@ -72,25 +72,25 @@ def lcm(a, b=None): Make sure we try `\QQ` and not merely `\ZZ` (:trac:`13014`):: - sage: bool(lcm(2/5, 3/7) == lcm(SR(2/5), SR(3/7))) + sage: bool(lcm(2/5, 3/7) == lcm(SR(2/5), SR(3/7))) # needs sage.symbolic True Make sure that the lcm of Expressions stays symbolic:: sage: parent(lcm(2, 4)) Integer Ring - sage: parent(lcm(SR(2), 4)) + sage: parent(lcm(SR(2), 4)) # needs sage.symbolic Symbolic Ring - sage: parent(lcm(2, SR(4))) + sage: parent(lcm(2, SR(4))) # needs sage.symbolic Symbolic Ring - sage: parent(lcm(SR(2), SR(4))) + sage: parent(lcm(SR(2), SR(4))) # needs sage.symbolic Symbolic Ring Verify that objects without lcm methods but which can't be coerced to `\ZZ` or `\QQ` raise an error:: - sage: F.<x,y> = FreeMonoid(2) - sage: lcm(x,y) + sage: F.<x,y> = FreeMonoid(2) # needs sage.groups + sage: lcm(x,y) # needs sage.groups Traceback (most recent call last): ... TypeError: unable to find lcm of x and y diff --git a/src/sage/arith/long.pxd b/src/sage/arith/long.pxd index 4addc8cfc89..0031a0ae337 100644 --- a/src/sage/arith/long.pxd +++ b/src/sage/arith/long.pxd @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.misc.cython r""" Fast conversion of Python objects to C long """ @@ -16,8 +17,6 @@ Fast conversion of Python objects to C long from libc.limits cimport LONG_MIN, LONG_MAX from cpython.object cimport Py_SIZE -from cpython.int cimport PyInt_AS_LONG -from cpython.long cimport PyLong_AsLong from cpython.number cimport PyNumber_Index, PyIndex_Check from cpython.longintrepr cimport py_long, PyLong_SHIFT, digit @@ -29,8 +28,9 @@ cdef inline long pyobject_to_long(x) except? LONG_MIN: r""" Given a Python object ``x`` cast it quickly to a C long. - A ``TypeError`` is raised if the input cannot be converted to an integer or - an ``OverflowError`` is raised if it does not fit into a C long. + A :class:`TypeError` is raised if the input cannot be converted to + an integer or + an :class:`OverflowError` is raised if it does not fit into a C long. TESTS: @@ -82,7 +82,7 @@ cdef enum: cdef inline bint integer_check_long(x, long* value, int* err) except -1: """ Return whether ``x`` is some integer type. This is true for the - Python types ``int`` and ``long``, for Sage Integers and for types + Python type ``int``, for Sage Integers and for types implementing ``__index__``. If possible, compute the value of this integer as C long and store @@ -103,7 +103,7 @@ cdef inline bint integer_check_long(x, long* value, int* err) except -1: - ``ERR_TYPE``: ``x`` is not an integer type of any kind. - - ``ERR_INDEX``: ``x`` implements ``__index__`` but a ``TypeError`` + - ``ERR_INDEX``: ``x`` implements ``__index__`` but a :class:`TypeError` was raised calling ``__index__()``. - Other exceptions in ``__index__`` are simply propagated. This is @@ -113,7 +113,7 @@ cdef inline bint integer_check_long(x, long* value, int* err) except -1: We create a pure Python wrapper of this function:: - sage: cython(''' # optional - sage.misc.cython + sage: cython(''' ....: from sage.arith.long cimport * ....: from sage.rings.integer cimport smallInteger ....: def check_long(x): @@ -246,7 +246,7 @@ cdef inline bint integer_check_long_py(x, long* value, int* err): We create a pure Python wrapper of this function:: - sage: cython(''' # optional - sage.misc.cython + sage: cython(''' ....: from sage.arith.long cimport * ....: def check_long_py(x): ....: cdef long value @@ -270,6 +270,17 @@ cdef inline bint integer_check_long_py(x, long* value, int* err): sage: L += [-x for x in L] + [0, long_min()] sage: for v in L: ....: assert check_long_py(int(v)) == v + sage: check_long_py(int(2^60)) + 1152921504606846976 # 64-bit + 'Overflow (...)' # 32-bit + sage: check_long_py(int(2^61)) + 2305843009213693952 # 64-bit + 'Overflow (...)' # 32-bit + sage: check_long_py(int(2^62)) + 4611686018427387904 # 64-bit + 'Overflow (...)' # 32-bit + sage: check_long_py(int(2^63)) + 'Overflow (...)' sage: check_long_py(int(2^100)) 'Overflow (...)' sage: check_long_py(int(long_max() + 1)) @@ -309,7 +320,12 @@ cdef inline bint integer_check_long_py(x, long* value, int* err): cdef long lead cdef long lead_2_overflow = (<long>1) << (BITS_IN_LONG - PyLong_SHIFT) - cdef long lead_3_overflow = (<long>1) << (BITS_IN_LONG - 2 * PyLong_SHIFT) + cdef long lead_3_overflow + if BITS_IN_LONG < 2 * PyLong_SHIFT: + # in this case 3 digit is always overflow + lead_3_overflow = 0 + else: + lead_3_overflow = (<long>1) << (BITS_IN_LONG - 2 * PyLong_SHIFT) if size == 0: value[0] = 0 err[0] = 0 @@ -371,7 +387,7 @@ cdef inline bint is_small_python_int(obj): EXAMPLES:: - sage: cython(''' # optional - sage.misc.cython + sage: cython(''' ....: from sage.arith.long cimport is_small_python_int ....: def is_small_wrapper(x): ....: return is_small_python_int(x) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 8be5f952d68..d18e83309e5 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -20,16 +20,15 @@ import math from collections.abc import Iterable -from sage.misc.misc import powerset from sage.misc.misc_c import prod from sage.structure.element import parent from sage.structure.coerce import py_scalar_to_element -from sage.rings.rational_field import QQ -from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer, GCD_list +from sage.rings.integer_ring import ZZ from sage.rings.rational import Rational +from sage.rings.rational_field import QQ from sage.rings.abc import RealField, ComplexField from sage.rings.fast_arith import arith_int, arith_llong, prime_range @@ -59,7 +58,7 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, is not found, then ``None`` will be returned. If ``proof=True`` then the result is returned only if it can be proved correct (i.e. the only possible minimal polynomial satisfying the height bound, or no - such polynomial exists). Otherwise a ``ValueError`` is raised + such polynomial exists). Otherwise a :class:`ValueError` is raised indicating that higher precision is required. ALGORITHM: Uses LLL for real/complex inputs, PARI C-library @@ -82,32 +81,33 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, EXAMPLES:: - sage: algdep(1.888888888888888, 1) + sage: algdep(1.888888888888888, 1) # needs sage.libs.pari 9*x - 17 - sage: algdep(0.12121212121212,1) + sage: algdep(0.12121212121212, 1) # needs sage.libs.pari 33*x - 4 - sage: algdep(sqrt(2),2) + sage: algdep(sqrt(2), 2) # needs sage.libs.pari sage.symbolic x^2 - 2 This example involves a complex number:: - sage: z = (1/2)*(1 + RDF(sqrt(3)) *CC.0); z + sage: z = (1/2) * (1 + RDF(sqrt(3)) * CC.0); z # needs sage.symbolic 0.500000000000000 + 0.866025403784439*I - sage: algdep(z, 6) + sage: algdep(z, 6) # needs sage.symbolic x^2 - x + 1 This example involves a `p`-adic number:: - sage: K = Qp(3, print_mode = 'series') - sage: a = K(7/19); a + sage: K = Qp(3, print_mode='series') # needs sage.rings.padics + sage: a = K(7/19); a # needs sage.rings.padics 1 + 2*3 + 3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^8 + 2*3^9 + 3^11 + 3^12 + 2*3^15 + 2*3^16 + 3^17 + 2*3^19 + O(3^20) - sage: algdep(a, 1) + sage: algdep(a, 1) # needs sage.rings.padics 19*x - 7 These examples show the importance of proper precision control. We compute a 200-bit approximation to `sqrt(2)` which is wrong in the 33'rd bit:: + sage: # needs sage.libs.pari sage.rings.real_mpfr sage: z = sqrt(RealField(200)(2)) + (1/2)^33 sage: p = algdep(z, 4); p 227004321085*x^4 - 216947902586*x^3 - 99411220986*x^2 + 82234881648*x - 211871195088 @@ -126,18 +126,18 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, `pi` is not the root of an integer polynomial of degree at most 5 and coefficients bounded above by 10:: - sage: algdep(pi.n(), 5, height_bound=10, proof=True) is None + sage: algdep(pi.n(), 5, height_bound=10, proof=True) is None # needs sage.libs.pari sage.symbolic True For stronger results, we need more precision:: + sage: # needs sage.libs.pari sage.symbolic sage: algdep(pi.n(), 5, height_bound=100, proof=True) is None Traceback (most recent call last): ... ValueError: insufficient precision for non-existence proof sage: algdep(pi.n(200), 5, height_bound=100, proof=True) is None True - sage: algdep(pi.n(), 10, height_bound=10, proof=True) is None Traceback (most recent call last): ... @@ -147,6 +147,7 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, We can also use ``proof=True`` to get positive results:: + sage: # needs sage.libs.pari sage.symbolic sage: a = sqrt(2) + sqrt(3) + sqrt(5) sage: algdep(a.n(), 8, height_bound=1000, proof=True) Traceback (most recent call last): @@ -159,32 +160,32 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, TESTS:: - sage: algdep(complex("1+2j"), 4) + sage: algdep(complex("1+2j"), 4) # needs sage.libs.pari sage.rings.complex_double x^2 - 2*x + 5 We get an irreducible polynomial even if PARI returns a reducible one:: - sage: z = CDF(1, RR(3).sqrt())/2 - sage: pari(z).algdep(5) + sage: z = CDF(1, RR(3).sqrt())/2 # needs sage.rings.complex_double + sage: pari(z).algdep(5) # needs sage.libs.pari sage.rings.complex_double sage.symbolic x^5 + x^2 - sage: algdep(z, 5) + sage: algdep(z, 5) # needs sage.libs.pari sage.rings.complex_double sage.symbolic x^2 - x + 1 Check that cases where a constant polynomial might look better get handled correctly:: - sage: z=CC(-1)**(1/3) - sage: algdep(z,1) + sage: z = CC(-1)**(1/3) # needs sage.rings.real_mpfr + sage: algdep(z, 1) # needs sage.libs.pari sage.symbolic x Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8, float64 - sage: algdep(float64(1.888888888888888), int8(1)) + sage: from numpy import int8, float64 # needs numpy + sage: algdep(float64(1.888888888888888), int8(1)) # needs numpy sage.libs.pari 9*x - 17 sage: from gmpy2 import mpz, mpfr - sage: algdep(mpfr(1.888888888888888), mpz(1)) + sage: algdep(mpfr(1.888888888888888), mpz(1)) # needs sage.libs.pari 9*x - 17 """ if proof and not height_bound: @@ -303,47 +304,54 @@ def bernoulli(n, algorithm='default', num_threads=1): EXAMPLES:: - sage: bernoulli(12) + sage: bernoulli(12) # needs sage.libs.flint -691/2730 - sage: bernoulli(50) + sage: bernoulli(50) # needs sage.libs.flint 495057205241079648212477525/66 We demonstrate each of the alternative algorithms:: - sage: bernoulli(12, algorithm='arb') + sage: bernoulli(12, algorithm='arb') # needs sage.libs.flint -691/2730 - sage: bernoulli(12, algorithm='flint') + sage: bernoulli(12, algorithm='flint') # needs sage.libs.flint -691/2730 - sage: bernoulli(12, algorithm='gap') + sage: bernoulli(12, algorithm='gap') # needs sage.libs.gap -691/2730 - sage: bernoulli(12, algorithm='gp') + sage: bernoulli(12, algorithm='gp') # needs sage.libs.pari -691/2730 sage: bernoulli(12, algorithm='magma') # optional - magma -691/2730 - sage: bernoulli(12, algorithm='pari') + sage: bernoulli(12, algorithm='pari') # needs sage.libs.pari -691/2730 - sage: bernoulli(12, algorithm='bernmm') + sage: bernoulli(12, algorithm='bernmm') # needs sage.libs.ntl -691/2730 - sage: bernoulli(12, algorithm='bernmm', num_threads=4) + sage: bernoulli(12, algorithm='bernmm', num_threads=4) # needs sage.libs.ntl -691/2730 TESTS:: - sage: algs = ['arb', 'gap', 'gp', 'pari', 'bernmm', 'flint'] + sage: algs = [] # The imports below are so that "sage -fixdoctests --probe" does not remove + sage: import sage.libs.arb; algs += ['arb'] # needs sage.libs.flint + sage: import sage.libs.gap; algs += ['gap'] # needs sage.libs.gap + sage: import sage.libs.pari; algs += ['gp', 'pari'] # needs sage.libs.pari + sage: import sage.libs.ntl; algs += ['bernmm'] # needs sage.libs.ntl + sage: import sage.libs.flint; algs += ['flint'] # needs sage.libs.flint sage: test_list = [ZZ.random_element(2, 2255) for _ in range(500)] sage: vals = [[bernoulli(i, algorithm=j) for j in algs] for i in test_list] # long time (up to 21s on sage.math, 2011) - sage: all(len(set(x))==1 for x in vals) # long time (depends on previous line) + sage: all(len(set(x)) == 1 for x in vals) # long time (depends on previous line) True - sage: algs = ['gp', 'pari', 'bernmm'] + sage: algs = [] + sage: import sage.libs.pari; algs += ['gp', 'pari'] # needs sage.libs.pari + sage: import sage.libs.ntl; algs += ['bernmm'] # needs sage.libs.ntl sage: test_list = [ZZ.random_element(2256, 5000) for _ in range(500)] sage: vals = [[bernoulli(i, algorithm=j) for j in algs] for i in test_list] # long time (up to 30s on sage.math, 2011) sage: all(len(set(x))==1 for x in vals) # long time (depends on previous line) True - sage: from numpy import int8 - sage: bernoulli(int8(12)) + sage: from numpy import int8 # needs numpy + sage: bernoulli(int8(12)) # needs numpy sage.libs.flint -691/2730 sage: from gmpy2 import mpz - sage: bernoulli(mpz(12)) + sage: bernoulli(mpz(12)) # needs sage.libs.flint -691/2730 AUTHOR: @@ -369,22 +377,18 @@ def bernoulli(n, algorithm='default', num_threads=1): warn("flint is known to not be accurate for large Bernoulli numbers") from sage.libs.flint.arith import bernoulli_number as flint_bernoulli return flint_bernoulli(n) - elif algorithm == 'pari': + elif algorithm == 'pari' or algorithm == 'gp': from sage.libs.pari.all import pari x = pari(n).bernfrac() # Use the PARI C library return Rational(x) elif algorithm == 'gap': - import sage.interfaces.gap - x = sage.interfaces.gap.gap('Bernoulli(%s)' % n) + from sage.libs.gap.libgap import libgap + x = libgap.Bernoulli(n).sage() return Rational(x) elif algorithm == 'magma': import sage.interfaces.magma x = sage.interfaces.magma.magma('Bernoulli(%s)' % n) return Rational(x) - elif algorithm == 'gp': - import sage.interfaces.gp - x = sage.interfaces.gp.gp('bernfrac(%s)' % n) - return Rational(x) elif algorithm == 'bernmm': import sage.rings.bernmm return sage.rings.bernmm.bernmm_bern_rat(n, num_threads) @@ -433,19 +437,17 @@ def factorial(n, algorithm='gmp'): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: factorial(int8(4)) + sage: from numpy import int8 # needs numpy + sage: factorial(int8(4)) # needs numpy 24 sage: from gmpy2 import mpz sage: factorial(mpz(4)) 24 - PERFORMANCE: This discussion is valid as of April 2006. All timings below are on a Pentium Core Duo 2Ghz MacBook Pro running Linux with a 2.6.16.1 kernel. - - It takes less than a minute to compute the factorial of `10^7` using the GMP algorithm, and the factorial of `10^6` takes less than 4 seconds. @@ -474,7 +476,7 @@ def factorial(n, algorithm='gmp'): raise ValueError('unknown algorithm') -def is_prime(n): +def is_prime(n) -> bool: r""" Determine whether `n` is a prime element of its parent ring. @@ -519,7 +521,7 @@ def is_prime(n): sage: a = 2**2048 + 981 sage: is_prime(a) # not tested - takes ~ 1min sage: proof.arithmetic(False) - sage: is_prime(a) # instantaneous! + sage: is_prime(a) # instantaneous! # needs sage.libs.pari True sage: proof.arithmetic(True) @@ -543,8 +545,9 @@ def is_prime(n): However, number fields redefine ``.is_prime()`` in an incompatible fashion (cf. :trac:`32340`) and we should not warn:: - sage: K.<i> = NumberField(x^2+1) - sage: is_prime(1+i) + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) # needs sage.rings.number_field + sage: is_prime(1 + i) # needs sage.rings.number_field True """ try: @@ -555,8 +558,8 @@ def is_prime(n): R = n.parent() if R.is_field(): # number fields redefine .is_prime(), see #32340 - from sage.rings.number_field.number_field import NumberField_generic - if not isinstance(R, NumberField_generic): + from sage.rings.number_field.number_field_base import NumberField + if R is QQ or not isinstance(R, NumberField): import warnings s = f'Testing primality in {R}, which is a field, ' \ 'hence the result will always be False. ' @@ -585,6 +588,7 @@ def is_pseudoprime(n): EXAMPLES:: + sage: # needs sage.libs.pari sage: is_pseudoprime(389) True sage: is_pseudoprime(2000) @@ -620,6 +624,7 @@ def is_prime_power(n, get_data=False): EXAMPLES:: + sage: # needs sage.libs.pari sage: is_prime_power(389) True sage: is_prime_power(2000) @@ -633,6 +638,7 @@ def is_prime_power(n, get_data=False): The same results can be obtained with:: + sage: # needs sage.libs.pari sage: 389.is_prime_power() True sage: 2000.is_prime_power() @@ -646,6 +652,7 @@ def is_prime_power(n, get_data=False): TESTS:: + sage: # needs sage.libs.pari sage: is_prime_power(-1) False sage: is_prime_power(1) @@ -663,8 +670,8 @@ def is_prime_power(n, get_data=False): sage: from gmpy2 import mpz sage: is_prime_power(mpz(389)) True - sage: from numpy import int16 - sage: is_prime_power(int16(389)) + sage: from numpy import int16 # needs numpy + sage: is_prime_power(int16(389)) # needs numpy True """ return ZZ(n).is_prime_power(get_data=get_data) @@ -687,6 +694,7 @@ def is_pseudoprime_power(n, get_data=False): EXAMPLES:: + sage: # needs sage.libs.pari sage: is_pseudoprime_power(389) True sage: is_pseudoprime_power(2000) @@ -704,6 +712,7 @@ def is_pseudoprime_power(n, get_data=False): Use of the get_data keyword:: + sage: # needs sage.libs.pari sage: is_pseudoprime_power(3^1024, get_data=True) (3, 1024) sage: is_pseudoprime_power(2^256, get_data=True) @@ -715,8 +724,8 @@ def is_pseudoprime_power(n, get_data=False): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int16 - sage: is_pseudoprime_power(int16(1024)) + sage: from numpy import int16 # needs numpy + sage: is_pseudoprime_power(int16(1024)) # needs numpy sage.libs.pari True sage: from gmpy2 import mpz sage: is_pseudoprime_power(mpz(1024)) @@ -783,8 +792,8 @@ def valuation(m, *args, **kwds): Traceback (most recent call last): ... ValueError: You can only compute the valuation with respect to a integer larger than 1. - sage: from numpy import int16 - sage: valuation(int16(512), int16(2)) + sage: from numpy import int16 # needs numpy + sage: valuation(int16(512), int16(2)) # needs numpy 9 sage: from gmpy2 import mpz sage: valuation(mpz(512), mpz(2)) @@ -821,15 +830,16 @@ def prime_powers(start, stop=None): EXAMPLES:: - sage: prime_powers(20) + sage: prime_powers(20) # needs sage.libs.pari [2, 3, 4, 5, 7, 8, 9, 11, 13, 16, 17, 19] - sage: len(prime_powers(1000)) + sage: len(prime_powers(1000)) # needs sage.libs.pari 193 - sage: len(prime_range(1000)) + sage: len(prime_range(1000)) # needs sage.libs.pari 168 - sage: a = [z for z in range(95,1234) if is_prime_power(z)] - sage: b = prime_powers(95,1234) + sage: # needs sage.libs.pari + sage: a = [z for z in range(95, 1234) if is_prime_power(z)] + sage: b = prime_powers(95, 1234) sage: len(b) 194 sage: len(a) @@ -841,29 +851,29 @@ def prime_powers(start, stop=None): sage: a == b True - sage: prime_powers(100) == [i for i in range(100) if is_prime_power(i)] + sage: prime_powers(100) == [i for i in range(100) if is_prime_power(i)] # needs sage.libs.pari True - sage: prime_powers(10,7) + sage: prime_powers(10, 7) [] sage: prime_powers(-5) [] - sage: prime_powers(-1,3) + sage: prime_powers(-1, 3) # needs sage.libs.pari [2] TESTS: Check that output are always Sage integers (:trac:`922`):: - sage: v = prime_powers(10) - sage: type(v[0]) + sage: v = prime_powers(10) # needs sage.libs.pari + sage: type(v[0]) # needs sage.libs.pari <class 'sage.rings.integer.Integer'> - sage: prime_powers(0,1) + sage: prime_powers(0, 1) [] sage: prime_powers(2) [] - sage: prime_powers(3) + sage: prime_powers(3) # needs sage.libs.pari [2] sage: prime_powers("foo") @@ -878,18 +888,18 @@ def prime_powers(start, stop=None): Check that long input are accepted (:trac:`17852`):: - sage: prime_powers(6l) + sage: prime_powers(6l) # needs sage.libs.pari [2, 3, 4, 5] - sage: prime_powers(6l,10l) + sage: prime_powers(6l, 10l) # needs sage.libs.pari [7, 8, 9] Check numpy and gmpy2 support:: - sage: from numpy import int8 - sage: prime_powers(int8(20)) + sage: from numpy import int8 # needs numpy + sage: prime_powers(int8(20)) # needs numpy sage.libs.pari [2, 3, 4, 5, 7, 8, 9, 11, 13, 16, 17, 19] sage: from gmpy2 import mpz - sage: prime_powers(mpz(20)) + sage: prime_powers(mpz(20)) # needs sage.libs.pari [2, 3, 4, 5, 7, 8, 9, 11, 13, 16, 17, 19] """ start = ZZ(start) @@ -931,9 +941,9 @@ def primes_first_n(n, leave_pari=False): EXAMPLES:: - sage: primes_first_n(10) + sage: primes_first_n(10) # needs sage.libs.pari [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - sage: len(primes_first_n(1000)) + sage: len(primes_first_n(1000)) # needs sage.libs.pari 1000 sage: primes_first_n(0) [] @@ -973,13 +983,13 @@ def eratosthenes(n): [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] sage: len(eratosthenes(100)) 25 - sage: eratosthenes(213) == prime_range(213) + sage: eratosthenes(213) == prime_range(213) # needs sage.libs.pari True TESTS:: - sage: from numpy import int8 - sage: eratosthenes(int8(3)) + sage: from numpy import int8 # needs numpy + sage: eratosthenes(int8(3)) # needs numpy [2, 3] sage: from gmpy2 import mpz sage: eratosthenes(mpz(3)) @@ -1010,42 +1020,43 @@ def eratosthenes(n): return [ZZ(2)] + [ZZ(x) for x in s if x and x <= n] -def primes(start, stop=None, proof=None): +def primes(start=2, stop=None, proof=None): r""" - Return an iterator over all primes between start and stop-1, - inclusive. This is much slower than ``prime_range``, but + Return an iterator over all primes between ``start`` and ``stop-1``, + inclusive. This is much slower than :func:`prime_range`, but potentially uses less memory. As with :func:`next_prime`, the optional - argument proof controls whether the numbers returned are + argument ``proof`` controls whether the numbers returned are guaranteed to be prime or not. - This command is like the Python 3 ``range`` command, except it only iterates - over primes. In some cases it is better to use primes than - ``prime_range``, because primes does not build a list of all primes in - the range in memory all at once. However, it is potentially much - slower since it simply calls the :func:`next_prime` function - repeatedly, and :func:`next_prime` is slow. + This command is like the Python 3 :func:`range` command, except it only + iterates over primes. In some cases it is better to use :func:`primes` than + :func:`prime_range`, because :func:`primes` does not build a list of all + primes in the range in memory all at once. However, it is potentially much + slower since it simply calls the :func:`next_prime` function repeatedly, and + :func:`next_prime` is slow. INPUT: - - ``start`` - an integer - lower bound for the primes + - ``start`` -- an integer (optional, default: 2) lower bound for the primes - - ``stop`` - an integer (or infinity) optional argument - - giving upper (open) bound for the primes + - ``stop`` -- an integer (or infinity) upper (open) bound for the + primes - - ``proof`` - bool or None (default: None) If True, the function - yields only proven primes. If False, the function uses a - pseudo-primality test, which is much faster for really big - numbers but does not provide a proof of primality. If None, - uses the global default (see :mod:`sage.structure.proof.proof`) + - ``proof`` -- bool or ``None`` (default: ``None``) If ``True``, the + function yields only proven primes. If ``False``, the function uses a + pseudo-primality test, which is much faster for really big numbers but + does not provide a proof of primality. If ``None``, uses the global + default (see :mod:`sage.structure.proof.proof`) OUTPUT: - - an iterator over primes from start to stop-1, inclusive + - an iterator over primes from ``start`` to ``stop-1``, inclusive EXAMPLES:: - sage: for p in primes(5,10): + sage: # needs sage.libs.pari + sage: for p in primes(5, 10): ....: print(p) 5 7 @@ -1061,6 +1072,7 @@ def primes(start, stop=None, proof=None): TESTS:: + sage: # needs sage.libs.pari sage: for a in range(-10, 50): ....: for b in range(-10, 50): ....: assert list(primes(a,b)) == list(filter(is_prime, range(a,b))) @@ -1075,8 +1087,8 @@ def primes(start, stop=None, proof=None): 19 sage: next(p for p in primes(10,oo)) # checks alternate infinity notation 11 - sage: from numpy import int8 - sage: list(primes(int8(13))) + sage: from numpy import int8 # needs numpy + sage: list(primes(int8(13))) # needs numpy [2, 3, 5, 7, 11] sage: from gmpy2 import mpz sage: list(primes(mpz(13))) @@ -1119,6 +1131,7 @@ def next_prime_power(n): EXAMPLES:: + sage: # needs sage.libs.pari sage: next_prime_power(1) 2 sage: next_prime_power(2) @@ -1148,8 +1161,8 @@ def next_prime_power(n): TESTS:: - sage: from numpy import int8 - sage: next_prime_power(int8(10)) + sage: from numpy import int8 # needs numpy + sage: next_prime_power(int8(10)) # needs numpy sage.libs.pari 11 sage: from gmpy2 import mpz sage: next_prime_power(mpz(10)) @@ -1170,6 +1183,7 @@ def next_probable_prime(n): EXAMPLES:: + sage: # needs sage.libs.pari sage: next_probable_prime(-100) 2 sage: next_probable_prime(19) @@ -1181,11 +1195,11 @@ def next_probable_prime(n): TESTS:: - sage: from numpy import int8 - sage: next_probable_prime(int8(19)) + sage: from numpy import int8 # needs numpy + sage: next_probable_prime(int8(19)) # needs numpy sage.libs.pari 23 sage: from gmpy2 import mpz - sage: next_probable_prime(mpz(19)) + sage: next_probable_prime(mpz(19)) # needs sage.libs.pari 23 """ return ZZ(n).next_probable_prime() @@ -1209,6 +1223,7 @@ def next_prime(n, proof=None): EXAMPLES:: + sage: # needs sage.libs.pari sage: next_prime(-100) 2 sage: next_prime(1) @@ -1224,18 +1239,18 @@ def next_prime(n, proof=None): :: - sage: next_prime(5) + sage: next_prime(5) # needs sage.libs.pari 7 - sage: next_prime(2004) + sage: next_prime(2004) # needs sage.libs.pari 2011 TESTS:: - sage: from numpy import int8 - sage: next_prime(int8(3)) + sage: from numpy import int8 # needs numpy + sage: next_prime(int8(3)) # needs numpy sage.libs.pari 5 sage: from gmpy2 import mpz - sage: next_probable_prime(mpz(3)) + sage: next_probable_prime(mpz(3)) # needs sage.libs.pari 5 """ return ZZ(n).next_prime(proof) @@ -1248,6 +1263,7 @@ def previous_prime(n): EXAMPLES:: + sage: # needs sage.libs.pari sage: previous_prime(10) 7 sage: previous_prime(7) @@ -1275,8 +1291,8 @@ def previous_prime(n): TESTS:: - sage: from numpy import int8 - sage: previous_prime(int8(7)) + sage: from numpy import int8 # needs numpy + sage: previous_prime(int8(7)) # needs numpy sage.libs.pari 5 sage: from gmpy2 import mpz sage: previous_prime(mpz(7)) @@ -1314,6 +1330,7 @@ def previous_prime_power(n): EXAMPLES:: + sage: # needs sage.libs.pari sage: previous_prime_power(3) 2 sage: previous_prime_power(10) @@ -1325,6 +1342,7 @@ def previous_prime_power(n): The same results can be obtained with:: + sage: # needs sage.libs.pari sage: 3.previous_prime_power() 2 sage: 10.previous_prime_power() @@ -1347,19 +1365,19 @@ def previous_prime_power(n): :: - sage: n = previous_prime_power(2^16 - 1) - sage: while is_prime(n): + sage: n = previous_prime_power(2^16 - 1) # needs sage.libs.pari + sage: while is_prime(n): # needs sage.libs.pari ....: n = previous_prime_power(n) - sage: factor(n) + sage: factor(n) # needs sage.libs.pari 251^2 TESTS:: - sage: from numpy import int8 - sage: previous_prime_power(int8(10)) + sage: from numpy import int8 # needs numpy + sage: previous_prime_power(int8(10)) # needs numpy sage.libs.pari 9 sage: from gmpy2 import mpz - sage: previous_prime_power(mpz(10)) + sage: previous_prime_power(mpz(10)) # needs sage.libs.pari 9 """ return ZZ(n).previous_prime_power() @@ -1376,17 +1394,18 @@ def random_prime(n, proof=None, lbound=2): INPUT: - - ``n`` - an integer >= 2. + - ``n`` - an integer `\geq 2`. - - ``proof`` - bool or None (default: None) If False, the function uses a + - ``proof`` - bool or ``None`` (default: ``None``) If ``False``, the function uses a pseudo-primality test, which is much faster for really big numbers but - does not provide a proof of primality. If None, uses the global default + does not provide a proof of primality. If ``None``, uses the global default (see :mod:`sage.structure.proof.proof`) - - ``lbound`` - an integer >= 2, lower bound for the chosen primes + - ``lbound`` - an integer `\geq 2`, lower bound for the chosen primes EXAMPLES:: + sage: # needs sage.libs.pari sage: p = random_prime(100000) sage: p.is_prime() True @@ -1406,19 +1425,20 @@ def random_prime(n, proof=None, lbound=2): If all we care about is finding a pseudo prime, then we can pass in ``proof=False`` :: - sage: p = random_prime(200, proof=False, lbound=100) - sage: p.is_pseudoprime() + sage: p = random_prime(200, proof=False, lbound=100) # needs sage.libs.pari + sage: p.is_pseudoprime() # needs sage.libs.pari True sage: 100 <= p <= 200 True TESTS:: + sage: # needs sage.libs.pari sage: type(random_prime(2)) <class 'sage.rings.integer.Integer'> sage: type(random_prime(100)) <class 'sage.rings.integer.Integer'> - sage: random_prime(1, lbound=-2) #caused Sage hang #10112 + sage: random_prime(1, lbound=-2) # caused Sage hang #10112 Traceback (most recent call last): ... ValueError: n must be greater than or equal to 2 @@ -1514,22 +1534,23 @@ def divisors(n): This function works whenever one has unique factorization:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(7) sage: divisors(K.ideal(7)) [Fractional ideal (1), Fractional ideal (a), Fractional ideal (7)] sage: divisors(K.ideal(3)) [Fractional ideal (1), Fractional ideal (3), - Fractional ideal (a - 2), Fractional ideal (a + 2)] + Fractional ideal (a - 2), Fractional ideal (a + 2)] sage: divisors(K.ideal(35)) [Fractional ideal (1), Fractional ideal (5), Fractional ideal (a), - Fractional ideal (7), Fractional ideal (5*a), Fractional ideal (35)] + Fractional ideal (7), Fractional ideal (5*a), Fractional ideal (35)] TESTS:: sage: divisors(int(300)) [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 25, 30, 50, 60, 75, 100, 150, 300] - sage: import numpy - sage: divisors(numpy.int8(100)) + sage: import numpy # needs numpy + sage: divisors(numpy.int8(100)) # needs numpy [1, 2, 4, 5, 10, 20, 25, 50, 100] sage: import gmpy2 sage: divisors(gmpy2.mpz(100)) @@ -1591,13 +1612,13 @@ class Sigma: :: - sage: P = plot(sigma, 1, 100) + sage: P = plot(sigma, 1, 100) # needs sage.plot This method also works with k-th powers. :: - sage: P = plot(sigma, 1, 100, k=2) + sage: P = plot(sigma, 1, 100, k=2) # needs sage.plot AUTHORS: @@ -1609,21 +1630,24 @@ class Sigma: sage: sigma(100,4) 106811523 - sage: sigma(factorial(100),3).mod(144169) + + sage: # needs sage.libs.pari + sage: sigma(factorial(100), 3).mod(144169) 3672 - sage: sigma(factorial(150),12).mod(691) + sage: sigma(factorial(150), 12).mod(691) 176 - sage: RR(sigma(factorial(133),20)) + sage: RR(sigma(factorial(133),20)) # needs sage.rings.real_mpfr 2.80414775675747e4523 sage: sigma(factorial(100),0) 39001250856960000 sage: sigma(factorial(41),1) 229199532273029988767733858700732906511758707916800 - sage: from numpy import int8 - sage: sigma(int8(100),int8(4)) + sage: from numpy import int8 # needs numpy + sage: sigma(int8(100), int8(4)) # needs numpy 106811523 + sage: from gmpy2 import mpz - sage: sigma(mpz(100),mpz(4)) + sage: sigma(mpz(100), mpz(4)) 106811523 """ def __repr__(self): @@ -1691,8 +1715,8 @@ def plot(self, xmin=1, xmax=50, k=1, pointsize=30, rgbcolor=(0,0,1), join=True, EXAMPLES:: sage: from sage.arith.misc import Sigma - sage: p = Sigma().plot() - sage: p.ymax() + sage: p = Sigma().plot() # needs sage.libs.pari sage.plot + sage: p.ymax() # needs sage.libs.pari sage.plot 124.0 """ v = [(n, sigma(n, k)) for n in range(xmin, xmax + 1)] @@ -1771,44 +1795,44 @@ def gcd(a, b=None, **kwargs): The following shows that indeed coercion takes place before computing the gcd. This behaviour was introduced in :trac:`10771`:: - sage: R.<x>=QQ[] - sage: S.<x>=ZZ[] + sage: R.<x> = QQ[] + sage: S.<x> = ZZ[] sage: p = S.random_element(degree=(0,10)) sage: q = R.random_element(degree=(0,10)) - sage: parent(gcd(1/p,q)) + sage: parent(gcd(1/p, q)) Fraction Field of Univariate Polynomial Ring in x over Rational Field - sage: parent(gcd([1/p,q])) + sage: parent(gcd([1/p, q])) Fraction Field of Univariate Polynomial Ring in x over Rational Field Make sure we try QQ and not merely ZZ (:trac:`13014`):: - sage: bool(gcd(2/5, 3/7) == gcd(SR(2/5), SR(3/7))) + sage: bool(gcd(2/5, 3/7) == gcd(SR(2/5), SR(3/7))) # needs sage.symbolic True Make sure that the gcd of Expressions stays symbolic:: sage: parent(gcd(2, 4)) Integer Ring - sage: parent(gcd(SR(2), 4)) + sage: parent(gcd(SR(2), 4)) # needs sage.symbolic Symbolic Ring - sage: parent(gcd(2, SR(4))) + sage: parent(gcd(2, SR(4))) # needs sage.symbolic Symbolic Ring - sage: parent(gcd(SR(2), SR(4))) + sage: parent(gcd(SR(2), SR(4))) # needs sage.symbolic Symbolic Ring Verify that objects without gcd methods but which cannot be coerced to ZZ or QQ raise an error:: - sage: F.<a,b> = FreeMonoid(2) - sage: gcd(a,b) + sage: F.<a,b> = FreeMonoid(2) # needs sage.groups + sage: gcd(a, b) # needs sage.groups Traceback (most recent call last): ... TypeError: unable to call gcd with a Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: GCD(int8(97),int8(100)) + sage: from numpy import int8 # needs numpy + sage: GCD(int8(97), int8(100)) # needs numpy 1 sage: from gmpy2 import mpq, mpz sage: GCD(mpq(2/3), mpq(4/5)) @@ -1907,8 +1931,8 @@ def xlcm(m, n): TESTS:: - sage: from numpy import int16 - sage: xlcm(int16(120), int16(36)) + sage: from numpy import int16 # needs numpy + sage: xlcm(int16(120), int16(36)) # needs numpy (360, 40, 9) sage: from gmpy2 import mpz sage: xlcm(mpz(120), mpz(36)) @@ -1973,15 +1997,16 @@ def xgcd(a, b): sage: xgcd(x^3 - 1, x^2 - 1) (x - 1, 1, -x) - sage: K.<g> = NumberField(x^2-3) - sage: g.xgcd(g+2) + sage: K.<g> = NumberField(x^2 - 3) # needs sage.rings.number_field + sage: g.xgcd(g + 2) # needs sage.rings.number_field (1, 1/3*g, 0) + sage: # needs sage.rings.number_field sage: R.<a,b> = K[] sage: S.<y> = R.fraction_field()[] - sage: xgcd(y^2, a*y+b) + sage: xgcd(y^2, a*y + b) (1, a^2/b^2, ((-a)/b^2)*y + 1/b) - sage: xgcd((b+g)*y^2, (a+g)*y+b) + sage: xgcd((b+g)*y^2, (a+g)*y + b) (1, (a^2 + (2*g)*a + 3)/(b^3 + g*b^2), ((-a + (-g))/b^2)*y + 1/b) Here is an example of a xgcd for two polynomials over the integers, where the linear @@ -1992,15 +2017,15 @@ def xgcd(a, b): x sage: xgcd(2*x*(x-1), x^2) (2*x, -1, 2) - sage: (2*(x-1)).resultant(x) + sage: (2*(x-1)).resultant(x) # needs sage.libs.pari 2 Tests with numpy and gmpy2 types:: - sage: from numpy import int8 - sage: xgcd(4,int8(8)) + sage: from numpy import int8 # needs numpy + sage: xgcd(4, int8(8)) # needs numpy (4, 1, 0) - sage: xgcd(int8(4),int8(8)) + sage: xgcd(int8(4), int8(8)) # needs numpy (4, 1, 0) sage: from gmpy2 import mpz sage: xgcd(mpz(4), mpz(8)) @@ -2012,10 +2037,11 @@ def xgcd(a, b): We check that :trac:`3330` has been fixed:: - sage: R.<a,b> = NumberField(x^2-3,'g').extension(x^2-7,'h')[] + sage: # needs sage.rings.number_field + sage: R.<a,b> = NumberField(x^2 - 3, 'g').extension(x^2 - 7, 'h')[] sage: h = R.base_ring().gen() sage: S.<y> = R.fraction_field()[] - sage: xgcd(y^2, a*h*y+b) + sage: xgcd(y^2, a*h*y + b) (1, 7*a^2/b^2, (((-h)*a)/b^2)*y + 1/b) """ try: @@ -2130,20 +2156,20 @@ def inverse_mod(a, m): :: - sage: inverse_mod(7,1) + sage: inverse_mod(7, 1) 0 - sage: inverse_mod(5,14) + sage: inverse_mod(5, 14) 3 - sage: inverse_mod(3,-5) + sage: inverse_mod(3, -5) 2 Tests with numpy and mpz numbers:: - sage: from numpy import int8 - sage: inverse_mod(int8(5),int8(14)) + sage: from numpy import int8 # needs numpy + sage: inverse_mod(int8(5), int8(14)) # needs numpy 3 sage: from gmpy2 import mpz - sage: inverse_mod(mpz(5),mpz(14)) + sage: inverse_mod(mpz(5), mpz(14)) 3 """ try: @@ -2220,13 +2246,13 @@ def power_mod(a, n, m): EXAMPLES:: - sage: power_mod(2,388,389) + sage: power_mod(2, 388, 389) 1 - sage: power_mod(2,390,391) + sage: power_mod(2, 390, 391) 285 - sage: power_mod(2,-1,7) + sage: power_mod(2, -1, 7) 4 - sage: power_mod(11,1,7) + sage: power_mod(11, 1, 7) 4 This function works for fairly general rings:: @@ -2234,7 +2260,7 @@ def power_mod(a, n, m): sage: R.<x> = ZZ[] sage: power_mod(3*x, 10, 7) 4*x^10 - sage: power_mod(-3*x^2+4, 7, 2*x^3-5) + sage: power_mod(-3*x^2 + 4, 7, 2*x^3 - 5) x^14 + x^8 + x^6 + x^3 + 962509*x^2 - 791910*x - 698281 TESTS:: @@ -2248,11 +2274,11 @@ def power_mod(a, n, m): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int32 - sage: power_mod(int32(2),int32(390),int32(391)) + sage: from numpy import int32 # needs numpy + sage: power_mod(int32(2), int32(390), int32(391)) # needs numpy 285 sage: from gmpy2 import mpz - sage: power_mod(mpz(2),mpz(390),mpz(391)) + sage: power_mod(mpz(2), mpz(390), mpz(391)) mpz(285) """ if not m: @@ -2371,8 +2397,8 @@ def rational_reconstruction(a, m, algorithm='fast'): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int32 - sage: rational_reconstruction(int32(3), int32(292393)) + sage: from numpy import int32 # needs numpy + sage: rational_reconstruction(int32(3), int32(292393)) # needs numpy 3 sage: from gmpy2 import mpz sage: rational_reconstruction(mpz(3), mpz(292393)) @@ -2406,16 +2432,16 @@ def mqrr_rational_reconstruction(u, m, T): EXAMPLES:: - sage: mqrr_rational_reconstruction(21,3100,13) + sage: mqrr_rational_reconstruction(21, 3100, 13) (21, 1) Tests with numpy and gmpy2 numbers:: - sage: from numpy import int16 - sage: mqrr_rational_reconstruction(int16(21),int16(3100),int16(13)) + sage: from numpy import int16 # needs numpy + sage: mqrr_rational_reconstruction(int16(21), int16(3100), int16(13)) # needs numpy (21, 1) sage: from gmpy2 import mpz - sage: mqrr_rational_reconstruction(mpz(21),mpz(3100),mpz(13)) + sage: mqrr_rational_reconstruction(mpz(21), mpz(3100), mpz(13)) (21, 1) """ u = py_scalar_to_element(u) @@ -2479,8 +2505,8 @@ def trial_division(n, bound=None): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: trial_division(int8(91)) + sage: from numpy import int8 # needs numpy + sage: trial_division(int8(91)) # needs numpy 7 sage: from gmpy2 import mpz sage: trial_division(mpz(91)) @@ -2498,67 +2524,67 @@ def factor(n, proof=None, int_=False, algorithm='pari', verbose=0, **kwds): type of ``n``. If ``n`` is an integer, returns the factorization as an object - of type ``Factorization``. + of type :class:`Factorization`. - If n is not an integer, ``n.factor(proof=proof, **kwds)`` gets called. + If ``n`` is not an integer, ``n.factor(proof=proof, **kwds)`` gets called. See ``n.factor??`` for more documentation in this case. .. warning:: - This means that applying ``factor`` to an integer result of + This means that applying :func:`factor` to an integer result of a symbolic computation will not factor the integer, because it is considered as an element of a larger symbolic ring. EXAMPLES:: - sage: f(n)=n^2 - sage: is_prime(f(3)) + sage: f(n) = n^2 # needs sage.symbolic + sage: is_prime(f(3)) # needs sage.symbolic False - sage: factor(f(3)) + sage: factor(f(3)) # needs sage.symbolic 9 INPUT: - - ``n`` - an nonzero integer + - ``n`` -- a nonzero integer - - ``proof`` - bool or None (default: None) + - ``proof`` -- bool or ``None`` (default: ``None``) - - ``int_`` - bool (default: False) whether to return + - ``int_`` -- bool (default: ``False``) whether to return answers as Python ints - - ``algorithm`` - string + - ``algorithm`` -- string - - ``'pari'`` - (default) use the PARI c library + - ``'pari'`` -- (default) use the PARI c library - - ``'kash'`` - use KASH computer algebra system (requires that + - ``'kash'`` -- use KASH computer algebra system (requires that kash be installed) - - ``'magma'`` - use Magma (requires magma be installed) + - ``'magma'`` -- use Magma (requires magma be installed) - - ``verbose`` - integer (default: 0); PARI's debug + - ``verbose`` -- integer (default: 0); PARI's debug variable is set to this; e.g., set to 4 or 8 to see lots of output during factorization. OUTPUT: - - factorization of n + - factorization of `n` The qsieve and ecm commands give access to highly optimized implementations of algorithms for doing certain integer factorization problems. These implementations are not used by the - generic factor command, which currently just calls PARI (note that + generic :func:`factor` command, which currently just calls PARI (note that PARI also implements sieve and ecm algorithms, but they are not as optimized). Thus you might consider using them instead for certain numbers. The factorization returned is an element of the class - :class:`~sage.structure.factorization.Factorization`; see Factorization?? - for more details, and examples below for usage. A Factorization contains - both the unit factor (+1 or -1) and a sorted list of (prime, exponent) + :class:`~sage.structure.factorization.Factorization`; use ``Factorization??`` + to see more details, and examples below for usage. A :class:`~sage.structure.factorization.Factorization` contains + both the unit factor (`+1` or `-1`) and a sorted list of ``(prime, exponent)`` pairs. The factorization displays in pretty-print format but it is easy to - obtain access to the (prime,exponent) pairs and the unit, to + obtain access to the ``(prime, exponent)`` pairs and the unit, to recover the number from its factorization, and even to multiply two factorizations. See examples below. @@ -2575,12 +2601,17 @@ def factor(n, proof=None, int_=False, algorithm='pari', verbose=0, **kwds): -1 sage: f.value() -20 - sage: factor( -next_prime(10^2) * next_prime(10^7) ) + sage: factor(-next_prime(10^2) * next_prime(10^7)) # needs sage.libs.pari -1 * 101 * 10000019 :: - sage: factor(-500, algorithm='kash') # optional - kash + sage: factor(293292629867846432923017396246429, algorithm='flint') # needs sage.libs.flint + 3 * 4852301647696687 * 20148007492971089 + + :: + + sage: factor(-500, algorithm='kash') -1 * 2^2 * 5^3 :: @@ -2598,32 +2629,33 @@ def factor(n, proof=None, int_=False, algorithm='pari', verbose=0, **kwds): 1 sage: factor(-1) -1 - sage: factor(2^(2^7)+1) + sage: factor(2^(2^7) + 1) # needs sage.libs.pari 59649589127497217 * 5704689200685129054721 - Sage calls PARI's factor, which has proof False by default. - Sage has a global proof flag, set to True by default (see - :mod:`sage.structure.proof.proof`, or proof.[tab]). To override - the default, call this function with proof=False. + Sage calls PARI's :pari:`factor`, which has ``proof=False`` by default. + Sage has a global proof flag, set to ``True`` by default (see + :mod:`sage.structure.proof.proof`, or use ``proof.[tab]``). To override + the default, call this function with ``proof=False``. :: - sage: factor(3^89-1, proof=False) + sage: factor(3^89 - 1, proof=False) # needs sage.libs.pari 2 * 179 * 1611479891519807 * 5042939439565996049162197 :: - sage: factor(2^197 + 1) # long time (2s) + sage: factor(2^197 + 1) # long time (2s) # needs sage.libs.pari 3 * 197002597249 * 1348959352853811313 * 251951573867253012259144010843 Any object which has a factor method can be factored like this:: - sage: K.<i> = QuadraticField(-1) - sage: factor(122 - 454*i) + sage: K.<i> = QuadraticField(-1) # needs sage.rings.number_field + sage: factor(122 - 454*i) # needs sage.rings.number_field (-i) * (-i - 2)^3 * (i + 1)^3 * (-2*i + 3) * (i + 4) To access the data in a factorization:: + sage: # needs sage.libs.pari sage: f = factor(420); f 2^2 * 3 * 5 * 7 sage: [x for x in f] @@ -2639,8 +2671,8 @@ def factor(n, proof=None, int_=False, algorithm='pari', verbose=0, **kwds): sage: factor(math.pi) 3.141592653589793 - sage: import numpy - sage: factor(numpy.int8(30)) + sage: import numpy # needs numpy + sage: factor(numpy.int8(30)) # needs numpy sage.libs.pari 2 * 3 * 5 sage: import gmpy2 sage: factor(gmpy2.mpz(30)) @@ -2695,14 +2727,14 @@ def radical(n, *args, **kwds): Traceback (most recent call last): ... ArithmeticError: radical of 0 is not defined - sage: K.<i> = QuadraticField(-1) - sage: radical(K(2)) + sage: K.<i> = QuadraticField(-1) # needs sage.rings.number_field + sage: radical(K(2)) # needs sage.rings.number_field i + 1 Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: radical(int8(50)) + sage: from numpy import int8 # needs numpy + sage: radical(int8(50)) # needs numpy 10 sage: from gmpy2 import mpz sage: radical(mpz(50)) @@ -2755,13 +2787,13 @@ def prime_divisors(n): For polynomials we get all irreducible factors:: sage: R.<x> = PolynomialRing(QQ) - sage: prime_divisors(x^12 - 1) + sage: prime_divisors(x^12 - 1) # needs sage.libs.pari [x - 1, x + 1, x^2 - x + 1, x^2 + 1, x^2 + x + 1, x^4 - x^2 + 1] Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: prime_divisors(int8(-100)) + sage: from numpy import int8 # needs numpy + sage: prime_divisors(int8(-100)) # needs numpy [2, 5] sage: from gmpy2 import mpz sage: prime_divisors(mpz(-100)) @@ -2793,8 +2825,8 @@ def odd_part(n): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: odd_part(int8(5)) + sage: from numpy import int8 # needs numpy + sage: odd_part(int8(5)) # needs numpy 5 sage: from gmpy2 import mpz sage: odd_part(mpz(5)) @@ -2837,8 +2869,8 @@ def prime_to_m_part(n, m): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int16 - sage: prime_to_m_part(int16(240), int16(2)) + sage: from numpy import int16 # needs numpy + sage: prime_to_m_part(int16(240), int16(2)) # needs numpy 15 sage: from gmpy2 import mpz sage: prime_to_m_part(mpz(240), mpz(2)) @@ -2878,9 +2910,9 @@ def is_square(n, root=False): True sage: is_square(-2.2) False - sage: is_square(CDF(-2.2)) + sage: is_square(CDF(-2.2)) # needs sage.rings.complex_double True - sage: is_square((x-1)^2) + sage: is_square((x-1)^2) # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: is_square() not implemented for @@ -2893,8 +2925,8 @@ def is_square(n, root=False): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: is_square(int8(4)) + sage: from numpy import int8 # needs numpy + sage: is_square(int8(4)) # needs numpy True sage: from gmpy2 import mpz sage: is_square(mpz(4)) @@ -2903,7 +2935,7 @@ def is_square(n, root=False): Tests with Polynomial:: sage: R.<v> = LaurentPolynomialRing(QQ, 'v') - sage: H = IwahoriHeckeAlgebra('A3', v**2) + sage: H = IwahoriHeckeAlgebra('A3', v**2) # needs sage.combinat sage.modules sage: R.<a,b,c,d> = QQ[] sage: p = a*b + c*d*a*d*a + 5 sage: is_square(p**2) @@ -2932,21 +2964,22 @@ def is_squarefree(n): EXAMPLES:: - sage: is_squarefree(100) + sage: is_squarefree(100) # needs sage.libs.pari False - sage: is_squarefree(101) + sage: is_squarefree(101) # needs sage.libs.pari True sage: R = ZZ['x'] sage: x = R.gen() - sage: is_squarefree((x^2+x+1) * (x-2)) + sage: is_squarefree((x^2+x+1) * (x-2)) # needs sage.libs.pari True - sage: is_squarefree((x-1)**2 * (x-3)) + sage: is_squarefree((x-1)**2 * (x-3)) # needs sage.libs.pari False + sage: # needs sage.rings.number_field sage.symbolic sage: O = ZZ[sqrt(-1)] sage: I = O.gen(1) - sage: is_squarefree(I+1) + sage: is_squarefree(I + 1) True sage: is_squarefree(O(2)) False @@ -2955,19 +2988,20 @@ def is_squarefree(n): This method fails on domains which are not Unique Factorization Domains:: - sage: O = ZZ[sqrt(-5)] - sage: a = O.gen(1) - sage: is_squarefree(a - 3) + sage: O = ZZ[sqrt(-5)] # needs sage.rings.number_field sage.symbolic + sage: a = O.gen(1) # needs sage.rings.number_field sage.symbolic + sage: is_squarefree(a - 3) # needs sage.rings.number_field sage.symbolic Traceback (most recent call last): ... ArithmeticError: non-principal ideal in factorization Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: is_squarefree(int8(100)) + sage: # needs sage.libs.pari + sage: from numpy import int8 # needs numpy + sage: is_squarefree(int8(100)) # needs numpy False - sage: is_squarefree(int8(101)) + sage: is_squarefree(int8(101)) # needs numpy True sage: from gmpy2 import mpz sage: is_squarefree(mpz(100)) @@ -3009,11 +3043,11 @@ class Euler_Phi: 1 sage: euler_phi(2) 1 - sage: euler_phi(3) + sage: euler_phi(3) # needs sage.libs.pari 2 - sage: euler_phi(12) + sage: euler_phi(12) # needs sage.libs.pari 4 - sage: euler_phi(37) + sage: euler_phi(37) # needs sage.libs.pari 36 Notice that euler_phi is defined to be 0 on negative numbers and @@ -3032,7 +3066,7 @@ class Euler_Phi: :: - sage: euler_phi(21) + sage: euler_phi(21) # needs sage.libs.pari 12 sage: [i for i in range(21) if gcd(21,i) == 1] [1, 2, 4, 5, 8, 10, 11, 13, 16, 17, 19, 20] @@ -3042,22 +3076,22 @@ class Euler_Phi: :: - sage: len([i for i in range(21) if gcd(21,i) == 1]) == euler_phi(21) + sage: len([i for i in range(21) if gcd(21,i) == 1]) == euler_phi(21) # needs sage.libs.pari True The phi function also has a special plotting method. :: - sage: P = plot(euler_phi, -3, 71) + sage: P = plot(euler_phi, -3, 71) # needs sage.libs.pari sage.plot Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: euler_phi(int8(37)) + sage: from numpy import int8 # needs numpy + sage: euler_phi(int8(37)) # needs numpy sage.libs.pari 36 sage: from gmpy2 import mpz - sage: euler_phi(mpz(37)) + sage: euler_phi(mpz(37)) # needs sage.libs.pari 36 AUTHORS: @@ -3085,9 +3119,9 @@ def __call__(self, n): EXAMPLES:: sage: from sage.arith.misc import Euler_Phi - sage: Euler_Phi()(10) + sage: Euler_Phi()(10) # needs sage.libs.pari 4 - sage: Euler_Phi()(720) + sage: Euler_Phi()(720) # needs sage.libs.pari 192 """ if n <= 0: @@ -3121,8 +3155,8 @@ def plot(self, xmin=1, xmax=50, pointsize=30, rgbcolor=(0, 0, 1), EXAMPLES:: sage: from sage.arith.misc import Euler_Phi - sage: p = Euler_Phi().plot() - sage: p.ymax() + sage: p = Euler_Phi().plot() # needs sage.libs.pari sage.plot + sage: p.ymax() # needs sage.libs.pari sage.plot 46.0 """ v = [(n, euler_phi(n)) for n in range(xmin, xmax + 1)] @@ -3178,7 +3212,7 @@ def carmichael_lambda(n): The Carmichael function of the first ten primes:: - sage: list(map(carmichael_lambda, primes_first_n(10))) + sage: list(map(carmichael_lambda, primes_first_n(10))) # needs sage.libs.pari [1, 2, 4, 6, 10, 12, 16, 18, 22, 28] Cases where the Carmichael function is equivalent to the Euler phi @@ -3186,19 +3220,19 @@ def carmichael_lambda(n): sage: carmichael_lambda(2) == euler_phi(2) True - sage: carmichael_lambda(4) == euler_phi(4) + sage: carmichael_lambda(4) == euler_phi(4) # needs sage.libs.pari True - sage: p = random_prime(1000, lbound=3, proof=True) + sage: p = random_prime(1000, lbound=3, proof=True) # needs sage.libs.pari sage: k = randint(1, 1000) - sage: carmichael_lambda(p^k) == euler_phi(p^k) + sage: carmichael_lambda(p^k) == euler_phi(p^k) # needs sage.libs.pari True A case where `\lambda(n) \neq \varphi(n)`:: sage: k = randint(3, 1000) - sage: carmichael_lambda(2^k) == 2^(k - 2) + sage: carmichael_lambda(2^k) == 2^(k - 2) # needs sage.libs.pari True - sage: carmichael_lambda(2^k) == 2^(k - 2) == euler_phi(2^k) + sage: carmichael_lambda(2^k) == 2^(k - 2) == euler_phi(2^k) # needs sage.libs.pari False Verifying the current implementation of the Carmichael function using @@ -3338,17 +3372,20 @@ def crt(a, b, m=None, n=None): Note that this also works for polynomial rings:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 7) sage: R.<y> = K[] sage: f = y^2 + 3 sage: g = y^3 - 5 - sage: CRT(1,3,f,g) + sage: CRT(1, 3, f, g) -3/26*y^4 + 5/26*y^3 + 15/26*y + 53/26 - sage: CRT(1,a,f,g) + sage: CRT(1, a, f, g) (-3/52*a + 3/52)*y^4 + (5/52*a - 5/52)*y^3 + (15/52*a - 15/52)*y + 27/52*a + 25/52 You can also do this for any number of moduli:: + sage: # needs sage.rings.number_field sage: K.<a> = NumberField(x^3 - 7) sage: R.<x> = K[] sage: CRT([], []) @@ -3359,7 +3396,11 @@ def crt(a, b, m=None, n=None): sage: g = x^3 - 5 sage: h = x^5 + x^2 - 9 sage: k = CRT([1, a, 3], [f, g, h]); k - (127/26988*a - 5807/386828)*x^9 + (45/8996*a - 33677/1160484)*x^8 + (2/173*a - 6/173)*x^7 + (133/6747*a - 5373/96707)*x^6 + (-6/2249*a + 18584/290121)*x^5 + (-277/8996*a + 38847/386828)*x^4 + (-135/4498*a + 42673/193414)*x^3 + (-1005/8996*a + 470245/1160484)*x^2 + (-1215/8996*a + 141165/386828)*x + 621/8996*a + 836445/386828 + (127/26988*a - 5807/386828)*x^9 + (45/8996*a - 33677/1160484)*x^8 + + (2/173*a - 6/173)*x^7 + (133/6747*a - 5373/96707)*x^6 + + (-6/2249*a + 18584/290121)*x^5 + (-277/8996*a + 38847/386828)*x^4 + + (-135/4498*a + 42673/193414)*x^3 + (-1005/8996*a + 470245/1160484)*x^2 + + (-1215/8996*a + 141165/386828)*x + 621/8996*a + 836445/386828 sage: k.mod(f) 1 sage: k.mod(g) @@ -3369,19 +3410,19 @@ def crt(a, b, m=None, n=None): If the moduli are not coprime, a solution may not exist:: - sage: crt(4,8,8,12) + sage: crt(4, 8, 8, 12) 20 - sage: crt(4,6,8,12) + sage: crt(4, 6, 8, 12) Traceback (most recent call last): ... ValueError: no solution to crt problem since gcd(8,12) does not divide 4-6 sage: x = polygen(QQ) - sage: crt(2,3,x-1,x+1) + sage: crt(2, 3, x - 1, x + 1) -1/2*x + 5/2 - sage: crt(2,x,x^2-1,x^2+1) + sage: crt(2, x, x^2 - 1, x^2 + 1) -1/2*x^3 + x^2 + 1/2*x + 1 - sage: crt(2,x,x^2-1,x^3-1) + sage: crt(2, x, x^2 - 1, x^3 - 1) Traceback (most recent call last): ... ValueError: no solution to crt problem since gcd(x^2 - 1,x^3 - 1) does not divide 2-x @@ -3391,13 +3432,13 @@ def crt(a, b, m=None, n=None): crt also work with numpy and gmpy2 numbers:: - sage: import numpy - sage: crt(numpy.int8(2), numpy.int8(3), numpy.int8(7), numpy.int8(11)) + sage: import numpy # needs numpy + sage: crt(numpy.int8(2), numpy.int8(3), numpy.int8(7), numpy.int8(11)) # needs numpy 58 sage: from gmpy2 import mpz sage: crt(mpz(2), mpz(3), mpz(7), mpz(11)) 58 - sage: crt(mpz(2), 3, mpz(7), numpy.int8(11)) + sage: crt(mpz(2), 3, mpz(7), numpy.int8(11)) # needs numpy 58 """ if isinstance(a, list): @@ -3484,8 +3525,8 @@ def CRT_list(values, moduli): sage: CRT([32r,2r,2r],[60r,90r,150r]) 452 - sage: from numpy import int8 - sage: CRT_list([int8(2),int8(3),int8(2)], [int8(3),int8(5),int8(7)]) + sage: from numpy import int8 # needs numpy + sage: CRT_list([int8(2), int8(3), int8(2)], [int8(3), int8(5), int8(7)]) # needs numpy 23 sage: from gmpy2 import mpz sage: CRT_list([mpz(2),mpz(3),mpz(2)], [mpz(3),mpz(5),mpz(7)]) @@ -3589,7 +3630,7 @@ def CRT_vectors(X, moduli): sage: CRT_vectors([[3,5,7],[3,5,11]], [2,3]) [3, 5, 5] - sage: CRT_vectors([vector(ZZ, [2,3,1]), Sequence([1,7,8],ZZ)], [8,9]) + sage: CRT_vectors([vector(ZZ, [2,3,1]), Sequence([1,7,8], ZZ)], [8,9]) # needs sage.modules [10, 43, 17] """ # First find the CRT basis: @@ -3631,27 +3672,27 @@ def binomial(x, m, **kwds): EXAMPLES:: sage: from sage.arith.misc import binomial - sage: binomial(5,2) + sage: binomial(5, 2) 10 - sage: binomial(2,0) + sage: binomial(2, 0) 1 - sage: binomial(1/2, 0) + sage: binomial(1/2, 0) # needs sage.libs.pari 1 - sage: binomial(3,-1) + sage: binomial(3, -1) 0 - sage: binomial(20,10) + sage: binomial(20, 10) 184756 sage: binomial(-2, 5) -6 sage: binomial(-5, -2) 0 - sage: binomial(RealField()('2.5'), 2) + sage: binomial(RealField()('2.5'), 2) # needs sage.rings.real_mpfr 1.87500000000000 - sage: n=var('n'); binomial(n,2) + sage: n = var('n'); binomial(n, 2) # needs sage.symbolic 1/2*(n - 1)*n - sage: n=var('n'); binomial(n,n) + sage: n = var('n'); binomial(n, n) # needs sage.symbolic 1 - sage: n=var('n'); binomial(n,n-1) + sage: n = var('n'); binomial(n, n - 1) # needs sage.symbolic n sage: binomial(2^100, 2^100) 1 @@ -3659,7 +3700,7 @@ def binomial(x, m, **kwds): sage: x = polygen(ZZ) sage: binomial(x, 3) 1/6*x^3 - 1/2*x^2 + 1/3*x - sage: binomial(x, x-3) + sage: binomial(x, x - 3) 1/6*x^3 - 1/2*x^2 + 1/3*x If `x \in \ZZ`, there is an optional 'algorithm' parameter, which @@ -3667,8 +3708,8 @@ def binomial(x, m, **kwds): 'pari' (faster for large values):: sage: a = binomial(100, 45, algorithm='gmp') - sage: b = binomial(100, 45, algorithm='pari') - sage: a == b + sage: b = binomial(100, 45, algorithm='pari') # needs sage.libs.pari + sage: a == b # needs sage.libs.pari True TESTS: @@ -3680,21 +3721,21 @@ def binomial(x, m, **kwds): We test conversion of arguments to Integers -- see :trac:`6870`:: - sage: binomial(1/2,1/1) + sage: binomial(1/2, 1/1) # needs sage.libs.pari 1/2 - sage: binomial(10^20+1/1,10^20) + sage: binomial(10^20 + 1/1, 10^20) 100000000000000000001 - sage: binomial(SR(10**7),10**7) + sage: binomial(SR(10**7), 10**7) # needs sage.symbolic 1 - sage: binomial(3/2,SR(1/1)) + sage: binomial(3/2, SR(1/1)) # needs sage.symbolic 3/2 Some floating point cases -- see :trac:`7562`, :trac:`9633`, and :trac:`12448`:: - sage: binomial(1.,3) + sage: binomial(1., 3) 0.000000000000000 - sage: binomial(-2.,3) + sage: binomial(-2., 3) -4.00000000000000 sage: binomial(0.5r, 5) 0.02734375 @@ -3739,8 +3780,8 @@ def binomial(x, m, **kwds): sage: binomial(y,3).parent() Multivariate Polynomial Ring in x, y over Ring of integers modulo 7 - sage: n = var('n') - sage: binomial(n,2) + sage: n = var('n') # needs sage.symbolic + sage: binomial(n,2) # needs sage.symbolic 1/2*(n - 1)*n Invalid inputs:: @@ -3751,8 +3792,8 @@ def binomial(x, m, **kwds): ... TypeError: either m or x-m must be an integer - sage: k, i = var('k,i') - sage: binomial(k,i) + sage: k, i = var('k,i') # needs sage.symbolic + sage: binomial(k,i) # needs sage.symbolic Traceback (most recent call last): ... TypeError: either m or x-m must be an integer @@ -3790,14 +3831,14 @@ def binomial(x, m, **kwds): :mod:`sage.functions.other`:: sage: from sage.functions.other import binomial - sage: binomial(k, i) + sage: binomial(k, i) # needs sage.symbolic binomial(k, i) binomial support numpy and gmpy2 parameters:: sage: from sage.arith.misc import binomial - sage: import numpy - sage: binomial(numpy.int32(20), numpy.int32(10)) + sage: import numpy # needs numpy + sage: binomial(numpy.int32(20), numpy.int32(10)) # needs numpy 184756 sage: import gmpy2 sage: binomial(gmpy2.mpz(20), gmpy2.mpz(10)) @@ -3880,15 +3921,15 @@ def multinomial(*ks): 618970023101454657175683075 sage: multinomial(Composition([1, 3])) 4 - sage: multinomial(Partition([4, 2])) + sage: multinomial(Partition([4, 2])) # needs sage.combinat 15 TESTS: Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: multinomial(int8(3), int8(2)) + sage: from numpy import int8 # needs numpy + sage: multinomial(int8(3), int8(2)) # needs numpy 10 sage: from gmpy2 import mpz sage: multinomial(mpz(3), mpz(2)) @@ -3944,8 +3985,8 @@ def binomial_coefficients(n): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: sorted(binomial_coefficients(int8(3)).items()) + sage: from numpy import int8 # needs numpy + sage: sorted(binomial_coefficients(int8(3)).items()) # needs numpy [((0, 3), 1), ((1, 2), 3), ((2, 1), 3), ((3, 0), 1)] sage: from gmpy2 import mpz sage: sorted(binomial_coefficients(mpz(3)).items()) @@ -4021,8 +4062,8 @@ def multinomial_coefficients(m, n): {(): 1} sage: multinomial_coefficients(0, 3) {} - sage: from numpy import int8 - sage: sorted(multinomial_coefficients(int8(2), int8(5)).items()) + sage: from numpy import int8 # needs numpy + sage: sorted(multinomial_coefficients(int8(2), int8(5)).items()) # needs numpy [((0, 5), 1), ((1, 4), 5), ((2, 3), 10), ((3, 2), 10), ((4, 1), 5), ((5, 0), 1)] sage: from gmpy2 import mpz sage: sorted(multinomial_coefficients(mpz(2), mpz(5)).items()) @@ -4110,8 +4151,8 @@ def kronecker_symbol(x,y): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: kronecker_symbol(int8(13),int8(21)) + sage: from numpy import int8 # needs numpy + sage: kronecker_symbol(int8(13),int8(21)) # needs numpy -1 sage: from gmpy2 import mpz sage: kronecker_symbol(mpz(13),mpz(21)) @@ -4162,8 +4203,8 @@ def legendre_symbol(x, p): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: legendre_symbol(int8(2),int8(3)) + sage: from numpy import int8 # needs numpy + sage: legendre_symbol(int8(2), int8(3)) # needs numpy -1 sage: from gmpy2 import mpz sage: legendre_symbol(mpz(2),mpz(3)) @@ -4218,8 +4259,8 @@ def jacobi_symbol(a, b): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int16 - sage: jacobi_symbol(int16(10),int16(777)) + sage: from numpy import int16 # needs numpy + sage: jacobi_symbol(int16(10), int16(777)) # needs numpy -1 sage: from gmpy2 import mpz sage: jacobi_symbol(mpz(10),mpz(777)) @@ -4235,7 +4276,7 @@ def primitive_root(n, check=True): """ Return a positive integer that generates the multiplicative group of integers modulo `n`, if one exists; otherwise, raise a - ``ValueError``. + :class:`ValueError`. A primitive root exists if `n=4` or `n=p^k` or `n=2p^k`, where `p` is an odd prime and `k` is a nonnegative number. @@ -4254,6 +4295,7 @@ def primitive_root(n, check=True): EXAMPLES:: + sage: # needs sage.libs.pari sage: primitive_root(23) 5 sage: primitive_root(-46) @@ -4278,15 +4320,16 @@ def primitive_root(n, check=True): :: sage: n = 10^50 + 151 # a prime - sage: primitive_root(n) + sage: primitive_root(n) # needs sage.libs.pari 11 - sage: primitive_root(n, check=False) + sage: primitive_root(n, check=False) # needs sage.libs.pari 11 TESTS: Various special cases:: + sage: # needs sage.libs.pari sage: primitive_root(-1) 0 sage: primitive_root(0) @@ -4305,6 +4348,7 @@ def primitive_root(n, check=True): We test that various numbers without primitive roots give an error - see :trac:`10836`:: + sage: # needs sage.libs.pari sage: primitive_root(15) Traceback (most recent call last): ... @@ -4324,11 +4368,11 @@ def primitive_root(n, check=True): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: primitive_root(int8(-46)) + sage: from numpy import int8 # needs numpy + sage: primitive_root(int8(-46)) # needs numpy sage.libs.pari 5 sage: from gmpy2 import mpz - sage: primitive_root(mpz(-46)) + sage: primitive_root(mpz(-46)) # needs sage.libs.pari 5 """ from sage.libs.pari.all import pari @@ -4364,11 +4408,11 @@ def nth_prime(n): EXAMPLES:: - sage: nth_prime(3) + sage: nth_prime(3) # needs sage.libs.pari 5 - sage: nth_prime(10) + sage: nth_prime(10) # needs sage.libs.pari 29 - sage: nth_prime(10^7) + sage: nth_prime(10^7) # needs sage.libs.pari 179424673 :: @@ -4380,13 +4424,13 @@ def nth_prime(n): TESTS:: - sage: all(prime_pi(nth_prime(j)) == j for j in range(1, 1000, 10)) + sage: all(prime_pi(nth_prime(j)) == j for j in range(1, 1000, 10)) # needs sage.libs.pari sage.symbolic True - sage: from numpy import int8 - sage: nth_prime(int8(10)) + sage: from numpy import int8 # needs numpy + sage: nth_prime(int8(10)) # needs numpy sage.libs.pari 29 sage: from gmpy2 import mpz - sage: nth_prime(mpz(10)) + sage: nth_prime(mpz(10)) # needs sage.libs.pari 29 """ if n <= 0: @@ -4417,8 +4461,8 @@ def quadratic_residues(n): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: quadratic_residues(int8(11)) + sage: from numpy import int8 # needs numpy + sage: quadratic_residues(int8(11)) # needs numpy [0, 1, 3, 4, 5, 9] sage: from gmpy2 import mpz sage: quadratic_residues(mpz(11)) @@ -4452,6 +4496,7 @@ class Moebius: EXAMPLES:: + sage: # needs sage.libs.pari sage: moebius(-5) -1 sage: moebius(9) @@ -4475,16 +4520,16 @@ class Moebius: :: sage: x = GF(7)['x'].0 - sage: moebius(x+2) + sage: moebius(x + 2) # needs sage.libs.pari -1 Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: moebius(int8(-5)) + sage: from numpy import int8 # needs numpy + sage: moebius(int8(-5)) # needs numpy sage.libs.pari -1 sage: from gmpy2 import mpz - sage: moebius(mpz(-5)) + sage: moebius(mpz(-5)) # needs sage.libs.pari -1 """ def __call__(self, n): @@ -4492,7 +4537,7 @@ def __call__(self, n): EXAMPLES:: sage: from sage.arith.misc import Moebius - sage: Moebius().__call__(7) + sage: Moebius().__call__(7) # needs sage.libs.pari -1 """ n = py_scalar_to_element(n) @@ -4550,8 +4595,8 @@ def plot(self, xmin=0, xmax=50, pointsize=30, rgbcolor=(0,0,1), join=True, EXAMPLES:: sage: from sage.arith.misc import Moebius - sage: p = Moebius().plot() - sage: p.ymax() + sage: p = Moebius().plot() # needs sage.libs.pari sage.plot + sage: p.ymax() # needs sage.libs.pari sage.plot 1.0 """ values = self.range(xmin, xmax + 1) @@ -4573,12 +4618,13 @@ def range(self, start, stop=None, step=None): EXAMPLES:: - sage: v = moebius.range(-10,10); v + sage: # needs sage.libs.pari + sage: v = moebius.range(-10, 10); v [1, 0, 0, -1, 1, -1, 0, -1, -1, 1, 0, 1, -1, -1, 0, -1, 1, -1, 0, 0] - sage: v == [moebius(n) for n in range(-10,10)] + sage: v == [moebius(n) for n in range(-10, 10)] True sage: v = moebius.range(-1000, 2000, 4) - sage: v == [moebius(n) for n in range(-1000,2000, 4)] + sage: v == [moebius(n) for n in range(-1000, 2000, 4)] True """ if stop is None: @@ -4642,14 +4688,15 @@ def continuant(v, n=None): sage: q = continuant([1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10]) sage: p/q 517656/190435 - sage: continued_fraction([2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10]).convergent(14) + sage: F = continued_fraction([2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10]) + sage: F.convergent(14) 517656/190435 - sage: x = PolynomialRing(RationalField(),'x',5).gens() + sage: x = PolynomialRing(RationalField(), 'x', 5).gens() sage: continuant(x) x0*x1*x2*x3*x4 + x0*x1*x2 + x0*x1*x4 + x0*x3*x4 + x2*x3*x4 + x0 + x2 + x4 sage: continuant(x, 3) x0*x1*x2 + x0 + x2 - sage: continuant(x,2) + sage: continuant(x, 2) x0*x1 + 1 We verify the identity @@ -4661,7 +4708,7 @@ def continuant(v, n=None): for `n = 6` using polynomial arithmetic:: sage: z = QQ['z'].0 - sage: continuant((z,z,z,z,z,z,z,z,z,z,z,z,z,z,z),6) + sage: continuant((z,z,z,z,z,z,z,z,z,z,z,z,z,z,z), 6) z^6 + 5*z^4 + 6*z^2 + 1 sage: continuant(9) @@ -4671,11 +4718,11 @@ def continuant(v, n=None): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: continuant([int8(1),int8(2),int8(3)]) + sage: from numpy import int8 # needs numpy + sage: continuant([int8(1), int8(2), int8(3)]) # needs numpy 10 sage: from gmpy2 import mpz - sage: continuant([mpz(1),mpz(2),mpz(3)]) + sage: continuant([mpz(1), mpz(2), mpz(3)]) mpz(10) AUTHORS: @@ -4709,18 +4756,18 @@ def number_of_divisors(n): EXAMPLES:: - sage: number_of_divisors(100) + sage: number_of_divisors(100) # needs sage.libs.pari 9 - sage: number_of_divisors(-720) + sage: number_of_divisors(-720) # needs sage.libs.pari 30 Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: number_of_divisors(int8(100)) + sage: from numpy import int8 # needs numpy + sage: number_of_divisors(int8(100)) # needs numpy sage.libs.pari 9 sage: from gmpy2 import mpz - sage: number_of_divisors(mpz(100)) + sage: number_of_divisors(mpz(100)) # needs sage.libs.pari 9 """ m = ZZ(n) @@ -4758,33 +4805,34 @@ def hilbert_symbol(a, b, p, algorithm="pari"): EXAMPLES:: - sage: hilbert_symbol (-1, -1, -1, algorithm='all') + sage: # needs sage.libs.pari + sage: hilbert_symbol(-1, -1, -1, algorithm='all') -1 - sage: hilbert_symbol (2,3, 5, algorithm='all') + sage: hilbert_symbol(2, 3, 5, algorithm='all') 1 - sage: hilbert_symbol (4, 3, 5, algorithm='all') + sage: hilbert_symbol(4, 3, 5, algorithm='all') 1 - sage: hilbert_symbol (0, 3, 5, algorithm='all') + sage: hilbert_symbol(0, 3, 5, algorithm='all') 0 - sage: hilbert_symbol (-1, -1, 2, algorithm='all') + sage: hilbert_symbol(-1, -1, 2, algorithm='all') -1 - sage: hilbert_symbol (1, -1, 2, algorithm='all') + sage: hilbert_symbol(1, -1, 2, algorithm='all') 1 - sage: hilbert_symbol (3, -1, 2, algorithm='all') + sage: hilbert_symbol(3, -1, 2, algorithm='all') -1 - sage: hilbert_symbol(QQ(-1)/QQ(4), -1, 2) == -1 + sage: hilbert_symbol(QQ(-1)/QQ(4), -1, 2) == -1 # needs sage.libs.pari True - sage: hilbert_symbol(QQ(-1)/QQ(4), -1, 3) == 1 + sage: hilbert_symbol(QQ(-1)/QQ(4), -1, 3) == 1 # needs sage.libs.pari True Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: hilbert_symbol(int8(2),int8(3),int8(5),algorithm='all') + sage: from numpy import int8 # needs numpy + sage: hilbert_symbol(int8(2), int8(3), int8(5), algorithm='all') # needs numpy sage.libs.pari 1 sage: from gmpy2 import mpz - sage: hilbert_symbol(mpz(2),mpz(3),mpz(5),algorithm='all') + sage: hilbert_symbol(mpz(2), mpz(3), mpz(5), algorithm='all') # needs sage.libs.pari 1 AUTHORS: @@ -4863,6 +4911,7 @@ def hilbert_conductor(a, b): EXAMPLES:: + sage: # needs sage.libs.pari sage: hilbert_conductor(-1, -1) 2 sage: hilbert_conductor(-1, -11) @@ -4874,11 +4923,11 @@ def hilbert_conductor(a, b): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: hilbert_conductor(int8(-3), int8(-17)) + sage: from numpy import int8 # needs numpy + sage: hilbert_conductor(int8(-3), int8(-17)) # needs numpy sage.libs.pari 17 sage: from gmpy2 import mpz - sage: hilbert_conductor(mpz(-3), mpz(-17)) + sage: hilbert_conductor(mpz(-3), mpz(-17)) # needs sage.libs.pari 17 AUTHOR: @@ -4906,6 +4955,7 @@ def hilbert_conductor_inverse(d): EXAMPLES:: + sage: # needs sage.libs.pari sage: hilbert_conductor_inverse(2) (-1, -1) sage: hilbert_conductor_inverse(3) @@ -4929,18 +4979,18 @@ def hilbert_conductor_inverse(d): TESTS:: - sage: for i in range(100): + sage: for i in range(100): # needs sage.libs.pari ....: d = ZZ.random_element(2**32).squarefree_part() ....: if hilbert_conductor(*hilbert_conductor_inverse(d)) != d: ....: print("hilbert_conductor_inverse failed for d = {}".format(d)) Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: hilbert_conductor_inverse(int8(30)) + sage: from numpy import int8 # needs numpy + sage: hilbert_conductor_inverse(int8(30)) # needs numpy sage.libs.pari (-3, -10) sage: from gmpy2 import mpz - sage: hilbert_conductor_inverse(mpz(30)) + sage: hilbert_conductor_inverse(mpz(30)) # needs sage.libs.pari (-3, -10) """ Z = ZZ @@ -5016,26 +5066,28 @@ def falling_factorial(x, a): sage: falling_factorial(10, 3) 720 - sage: falling_factorial(10, RR('3.0')) - 720.000000000000 - sage: falling_factorial(10, RR('3.3')) - 1310.11633396601 sage: falling_factorial(10, 10) 3628800 sage: factorial(10) 3628800 - sage: a = falling_factorial(1+I, I); a + + sage: # needs sage.symbolic + sage: falling_factorial(10, RR('3.0')) + 720.000000000000 + sage: falling_factorial(10, RR('3.3')) + 1310.11633396601 + sage: a = falling_factorial(1 + I, I); a gamma(I + 2) sage: CC(a) 0.652965496420167 + 0.343065839816545*I - sage: falling_factorial(1+I, 4) + sage: falling_factorial(1 + I, 4) 4*I + 2 sage: falling_factorial(I, 4) -10 - sage: M = MatrixSpace(ZZ, 4, 4) - sage: A = M([1,0,1,0,1,0,1,0,1,0,10,10,1,0,1,1]) - sage: falling_factorial(A, 2) # A(A - I) + sage: M = MatrixSpace(ZZ, 4, 4) # needs sage.modules + sage: A = M([1,0,1,0, 1,0,1,0, 1,0,10,10, 1,0,1,1]) # needs sage.modules + sage: falling_factorial(A, 2) # A(A - I) # needs sage.modules [ 1 0 10 10] [ 1 0 10 10] [ 20 0 101 100] @@ -5049,13 +5101,13 @@ def falling_factorial(x, a): Check that :trac:`14858` is fixed:: - sage: falling_factorial(-4, SR(2)) + sage: falling_factorial(-4, SR(2)) # needs sage.symbolic 20 Check that :trac:`16770` is fixed:: - sage: d = var('d') - sage: parent(falling_factorial(d, 0)) + sage: d = var('d') # needs sage.symbolic + sage: parent(falling_factorial(d, 0)) # needs sage.symbolic Symbolic Ring Check that :trac:`20075` is fixed:: @@ -5065,8 +5117,8 @@ def falling_factorial(x, a): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: falling_factorial(int8(10), int8(3)) + sage: from numpy import int8 # needs numpy + sage: falling_factorial(int8(10), int8(3)) # needs numpy 720 sage: from gmpy2 import mpz sage: falling_factorial(mpz(10), mpz(3)) @@ -5119,17 +5171,15 @@ def rising_factorial(x, a): sage: rising_factorial(10,3) 1320 - sage: rising_factorial(10,RR('3.0')) + sage: # needs sage.symbolic + sage: rising_factorial(10, RR('3.0')) 1320.00000000000 - - sage: rising_factorial(10,RR('3.3')) + sage: rising_factorial(10, RR('3.3')) 2826.38895824964 - sage: a = rising_factorial(1+I, I); a gamma(2*I + 1)/gamma(I + 1) sage: CC(a) 0.266816390637832 + 0.122783354006372*I - sage: a = rising_factorial(I, 4); a -10 @@ -5141,15 +5191,15 @@ def rising_factorial(x, a): Check that :trac:`14858` is fixed:: - sage: bool(rising_factorial(-4, 2) == + sage: bool(rising_factorial(-4, 2) == # needs sage.symbolic ....: rising_factorial(-4, SR(2)) == ....: rising_factorial(SR(-4), SR(2))) True Check that :trac:`16770` is fixed:: - sage: d = var('d') - sage: parent(rising_factorial(d, 0)) + sage: d = var('d') # needs sage.symbolic + sage: parent(rising_factorial(d, 0)) # needs sage.symbolic Symbolic Ring Check that :trac:`20075` is fixed:: @@ -5159,8 +5209,8 @@ def rising_factorial(x, a): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: rising_factorial(int8(10), int8(3)) + sage: from numpy import int8 # needs numpy + sage: rising_factorial(int8(10), int8(3)) # needs numpy 1320 sage: from gmpy2 import mpz sage: rising_factorial(mpz(10), mpz(3)) @@ -5189,15 +5239,15 @@ def integer_ceil(x): sage: integer_ceil(5.4) 6 - sage: integer_ceil(x) + sage: integer_ceil(x) # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: computation of ceil of x not implemented Tests with numpy and gmpy2 numbers:: - sage: from numpy import float32 - sage: integer_ceil(float32(5.4)) + sage: from numpy import float32 # needs numpy + sage: integer_ceil(float32(5.4)) # needs numpy 6 sage: from gmpy2 import mpfr sage: integer_ceil(mpfr(5.4)) @@ -5235,15 +5285,15 @@ def integer_floor(x): sage: integer_floor(RDF(-5/2)) -3 - sage: integer_floor(x) + sage: integer_floor(x) # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: computation of floor of x not implemented Tests with numpy and gmpy2 numbers:: - sage: from numpy import float32 - sage: integer_floor(float32(5.4)) + sage: from numpy import float32 # needs numpy + sage: integer_floor(float32(5.4)) # needs numpy 5 sage: from gmpy2 import mpfr sage: integer_floor(mpfr(5.4)) @@ -5280,7 +5330,7 @@ def integer_trunc(i): def two_squares(n): """ Write the integer `n` as a sum of two integer squares if possible; - otherwise raise a ``ValueError``. + otherwise raise a :class:`ValueError`. INPUT: @@ -5299,11 +5349,11 @@ def two_squares(n): ValueError: 21 is not a sum of 2 squares sage: two_squares(21^2) (0, 21) - sage: a,b = two_squares(100000000000000000129); a,b + sage: a, b = two_squares(100000000000000000129); a, b # needs sage.libs.pari (4418521500, 8970878873) - sage: a^2 + b^2 + sage: a^2 + b^2 # needs sage.libs.pari 100000000000000000129 - sage: two_squares(2^222+1) + sage: two_squares(2^222 + 1) # needs sage.libs.pari (253801659504708621991421712450521, 2583712713213354898490304645018692) sage: two_squares(0) (0, 0) @@ -5314,17 +5364,17 @@ def two_squares(n): TESTS:: - sage: for _ in range(100): + sage: for _ in range(100): # needs sage.libs.pari ....: a = ZZ.random_element(2**16, 2**20) ....: b = ZZ.random_element(2**16, 2**20) ....: n = a**2 + b**2 - ....: aa,bb = two_squares(n) + ....: aa, bb = two_squares(n) ....: assert aa**2 + bb**2 == n Tests with numpy and gmpy2 numbers:: - sage: from numpy import int16 - sage: two_squares(int16(389)) + sage: from numpy import int16 # needs numpy + sage: two_squares(int16(389)) # needs numpy (10, 17) sage: from gmpy2 import mpz sage: two_squares(mpz(389)) @@ -5402,7 +5452,7 @@ def two_squares(n): def three_squares(n): """ Write the integer `n` as a sum of three integer squares if possible; - otherwise raise a ``ValueError``. + otherwise raise a :class:`ValueError`. INPUT: @@ -5421,9 +5471,10 @@ def three_squares(n): (3, 24, 49) sage: three_squares(7^100) (0, 0, 1798465042647412146620280340569649349251249) - sage: three_squares(11^111-1) - (616274160655975340150706442680, 901582938385735143295060746161, 6270382387635744140394001363065311967964099981788593947233) - sage: three_squares(7 * 2^41) + sage: three_squares(11^111 - 1) # needs sage.libs.pari + (616274160655975340150706442680, 901582938385735143295060746161, + 6270382387635744140394001363065311967964099981788593947233) + sage: three_squares(7 * 2^41) # needs sage.libs.pari (1048576, 2097152, 3145728) sage: three_squares(7 * 2^42) Traceback (most recent call last): @@ -5438,18 +5489,18 @@ def three_squares(n): TESTS:: - sage: for _ in range(100): + sage: for _ in range(100): # needs sage.libs.pari ....: a = ZZ.random_element(2**16, 2**20) ....: b = ZZ.random_element(2**16, 2**20) ....: c = ZZ.random_element(2**16, 2**20) ....: n = a**2 + b**2 + c**2 - ....: aa,bb,cc = three_squares(n) + ....: aa, bb, cc = three_squares(n) ....: assert aa**2 + bb**2 + cc**2 == n Tests with numpy and gmpy2 numbers:: - sage: from numpy import int16 - sage: three_squares(int16(389)) + sage: from numpy import int16 # needs numpy + sage: three_squares(int16(389)) # needs numpy (1, 8, 18) sage: from gmpy2 import mpz sage: three_squares(mpz(389)) @@ -5565,23 +5616,24 @@ def four_squares(n): (0, 0, 3, 11) sage: four_squares(1101011011004) (90, 102, 1220, 1049290) - sage: four_squares(10^100-1) - (155024616290, 2612183768627, 14142135623730950488016887, 99999999999999999999999999999999999999999999999999) - sage: for i in range(2^129, 2^129+10000): # long time + sage: four_squares(10^100 - 1) # needs sage.libs.pari + (155024616290, 2612183768627, 14142135623730950488016887, + 99999999999999999999999999999999999999999999999999) + sage: for i in range(2^129, 2^129 + 10000): # long time # needs sage.libs.pari ....: S = four_squares(i) ....: assert sum(x^2 for x in S) == i TESTS:: sage: for _ in range(100): - ....: n = ZZ.random_element(2**32,2**34) - ....: aa,bb,cc,dd = four_squares(n) + ....: n = ZZ.random_element(2**32, 2**34) + ....: aa, bb, cc, dd = four_squares(n) ....: assert aa**2 + bb**2 + cc**2 + dd**2 == n Tests with numpy and gmpy2 numbers:: - sage: from numpy import int16 - sage: four_squares(int16(389)) + sage: from numpy import int16 # needs numpy + sage: four_squares(int16(389)) # needs numpy (0, 1, 8, 18) sage: from gmpy2 import mpz sage: four_squares(mpz(389)) @@ -5621,7 +5673,7 @@ def four_squares(n): def sum_of_k_squares(k, n): """ Write the integer `n` as a sum of `k` integer squares if possible; - otherwise raise a ``ValueError``. + otherwise raise a :class:`ValueError`. INPUT: @@ -5642,8 +5694,12 @@ def sum_of_k_squares(k, n): (1, 2, 5, 98) sage: sum_of_k_squares(5, 9634) (0, 1, 2, 5, 98) - sage: sum_of_k_squares(6, 11^1111-1) - (19215400822645944253860920437586326284, 37204645194585992174252915693267578306, 3473654819477394665857484221256136567800161086815834297092488779216863122, 5860191799617673633547572610351797996721850737768032876360978911074629287841061578270832330322236796556721252602860754789786937515870682024273948, 20457423294558182494001919812379023992538802203730791019728543439765347851316366537094696896669915675685581905102118246887673397020172285247862426612188418787649371716686651256443143210952163970564228423098202682066311189439731080552623884051737264415984619097656479060977602722566383385989, 311628095411678159849237738619458396497534696043580912225334269371611836910345930320700816649653412141574887113710604828156159177769285115652741014638785285820578943010943846225597311231847997461959204894255074229895666356909071243390280307709880906261008237873840245959883405303580405277298513108957483306488193844321589356441983980532251051786704380984788999660195252373574924026139168936921591652831237741973242604363696352878914129671292072201700073286987126265965322808664802662993006926302359371379531571194266134916767573373504566621665949840469229781956838744551367172353) + sage: sum_of_k_squares(6, 11^1111 - 1) # needs sage.libs.pari + (19215400822645944253860920437586326284, 37204645194585992174252915693267578306, + 3473654819477394665857484221256136567800161086815834297092488779216863122, + 5860191799617673633547572610351797996721850737768032876360978911074629287841061578270832330322236796556721252602860754789786937515870682024273948, + 20457423294558182494001919812379023992538802203730791019728543439765347851316366537094696896669915675685581905102118246887673397020172285247862426612188418787649371716686651256443143210952163970564228423098202682066311189439731080552623884051737264415984619097656479060977602722566383385989, + 311628095411678159849237738619458396497534696043580912225334269371611836910345930320700816649653412141574887113710604828156159177769285115652741014638785285820578943010943846225597311231847997461959204894255074229895666356909071243390280307709880906261008237873840245959883405303580405277298513108957483306488193844321589356441983980532251051786704380984788999660195252373574924026139168936921591652831237741973242604363696352878914129671292072201700073286987126265965322808664802662993006926302359371379531571194266134916767573373504566621665949840469229781956838744551367172353) sage: sum_of_k_squares(7, 0) (0, 0, 0, 0, 0, 0, 0) sage: sum_of_k_squares(30,999999) @@ -5675,8 +5731,8 @@ def sum_of_k_squares(k, n): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int16 - sage: sum_of_k_squares(int16(2), int16(9634)) + sage: from numpy import int16 # needs numpy + sage: sum_of_k_squares(int16(2), int16(9634)) # needs numpy (15, 97) sage: from gmpy2 import mpz sage: sum_of_k_squares(mpz(2), mpz(9634)) @@ -5747,8 +5803,8 @@ def subfactorial(n): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: subfactorial(int8(8)) + sage: from numpy import int8 # needs numpy + sage: subfactorial(int8(8)) # needs numpy 14833 sage: from gmpy2 import mpz sage: subfactorial(mpz(8)) @@ -5788,10 +5844,10 @@ def is_power_of_two(n): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: is_power_of_two(int8(16)) + sage: from numpy import int8 # needs numpy + sage: is_power_of_two(int8(16)) # needs numpy True - sage: is_power_of_two(int8(24)) + sage: is_power_of_two(int8(24)) # needs numpy False sage: from gmpy2 import mpz sage: is_power_of_two(mpz(16)) @@ -5808,7 +5864,7 @@ def differences(lis, n=1): EXAMPLES:: - sage: differences(prime_range(50)) + sage: differences(prime_range(50)) # needs sage.libs.pari [1, 2, 2, 4, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4] sage: differences([i^2 for i in range(1,11)]) [3, 5, 7, 9, 11, 13, 15, 17, 19] @@ -5816,16 +5872,16 @@ def differences(lis, n=1): [10, 22, 40, 64, 94, 130, 172, 220, 274, 334, 400, 472, 550, 634, 724, 820, 922, 1030, 1144] sage: differences([i^3 - i^2 for i in range(1,21)], 2) [10, 16, 22, 28, 34, 40, 46, 52, 58, 64, 70, 76, 82, 88, 94, 100, 106, 112] - sage: differences([p - i^2 for i, p in enumerate(prime_range(50))], 3) + sage: differences([p - i^2 for i, p in enumerate(prime_range(50))], 3) # needs sage.libs.pari [-1, 2, -4, 4, -4, 4, 0, -6, 8, -6, 0, 4] Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: differences([int8(1),int8(4),int8(6),int8(19)]) + sage: from numpy import int8 # needs numpy + sage: differences([int8(1), int8(4), int8(6), int8(19)]) # needs numpy [3, 2, 13] sage: from gmpy2 import mpz - sage: differences([mpz(1),mpz(4),mpz(6),mpz(19)]) + sage: differences([mpz(1), mpz(4), mpz(6), mpz(19)]) [mpz(3), mpz(2), mpz(13)] AUTHORS: @@ -5855,15 +5911,15 @@ def _key_complex_for_display(a): sage: import sage.arith.misc sage: key_c = sage.arith.misc._key_complex_for_display - sage: key_c(CC(5)) + sage: key_c(CC(5)) # needs sage.rings.real_mpfr (0, 5.00000000000000) - sage: key_c(CC(5, 5)) + sage: key_c(CC(5, 5)) # needs sage.rings.real_mpfr (1, 5.00000000, 5.00000000000000) - sage: CIF200 = ComplexIntervalField(200) - sage: key_c(CIF200(5)) + sage: CIF200 = ComplexIntervalField(200) # needs sage.rings.complex_interval_field + sage: key_c(CIF200(5)) # needs sage.rings.complex_interval_field (0, 5) - sage: key_c(CIF200(5, 5)) + sage: key_c(CIF200(5, 5)) # needs sage.rings.complex_interval_field (1, 5.00000000, 5) """ ar = a.real() @@ -5902,6 +5958,7 @@ def sort_complex_numbers_for_display(nums): EXAMPLES:: + sage: # needs sage.rings.complex_double sage: import sage.arith.misc sage: sort_c = sort_complex_numbers_for_display sage: nums = [CDF(i) for i in range(3)] @@ -5921,7 +5978,6 @@ def sort_complex_numbers_for_display(nums): sage: assert first_non_real >= 3 sage: for i in range(first_non_real - 1): ....: assert nums[i].real() <= nums[i + 1].real() - sage: def truncate(n): ....: if n.real() < 1e-10: ....: return 0 @@ -5967,8 +6023,8 @@ def fundamental_discriminant(D): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: fundamental_discriminant(int8(102)) + sage: from numpy import int8 # needs numpy + sage: fundamental_discriminant(int8(102)) # needs numpy 408 sage: from gmpy2 import mpz sage: fundamental_discriminant(mpz(102)) @@ -6025,13 +6081,15 @@ def squarefree_divisors(x): Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: list(squarefree_divisors(int8(12))) + sage: from numpy import int8 # needs numpy + sage: list(squarefree_divisors(int8(12))) # needs numpy [1, 2, 3, 6] sage: from gmpy2 import mpz sage: list(squarefree_divisors(mpz(12))) [1, 2, 3, 6] """ + from sage.combinat.subset import powerset + for a in powerset(prime_divisors(x)): yield prod(a, ZZ.one()) @@ -6076,7 +6134,7 @@ def dedekind_sum(p, q, algorithm='default'): Several small values:: - sage: for q in range(10): print([dedekind_sum(p,q) for p in range(q+1)]) + sage: for q in range(10): print([dedekind_sum(p,q) for p in range(q+1)]) # needs sage.libs.flint [0] [0, 0] [0, 0, 0] @@ -6090,44 +6148,44 @@ def dedekind_sum(p, q, algorithm='default'): Check relations for restricted arguments:: - sage: q = 23; dedekind_sum(1, q); (q-1)*(q-2)/(12*q) + sage: q = 23; dedekind_sum(1, q); (q-1)*(q-2)/(12*q) # needs sage.libs.flint 77/46 77/46 sage: p, q = 100, 723 # must be coprime - sage: dedekind_sum(p, q) + dedekind_sum(q, p) + sage: dedekind_sum(p, q) + dedekind_sum(q, p) # needs sage.libs.flint 31583/86760 sage: -1/4 + (p/q + q/p + 1/(p*q))/12 31583/86760 We check that evaluation works with large input:: - sage: dedekind_sum(3^54 - 1, 2^93 + 1) + sage: dedekind_sum(3^54 - 1, 2^93 + 1) # needs sage.libs.flint 459340694971839990630374299870/29710560942849126597578981379 - sage: dedekind_sum(3^54 - 1, 2^93 + 1, algorithm='pari') + sage: dedekind_sum(3^54 - 1, 2^93 + 1, algorithm='pari') # needs sage.libs.pari 459340694971839990630374299870/29710560942849126597578981379 We check consistency of the results:: - sage: dedekind_sum(5, 7, algorithm='default') + sage: dedekind_sum(5, 7, algorithm='default') # needs sage.libs.flint -1/14 - sage: dedekind_sum(5, 7, algorithm='flint') + sage: dedekind_sum(5, 7, algorithm='flint') # needs sage.libs.flint -1/14 - sage: dedekind_sum(5, 7, algorithm='pari') + sage: dedekind_sum(5, 7, algorithm='pari') # needs sage.libs.pari -1/14 - sage: dedekind_sum(6, 8, algorithm='default') + sage: dedekind_sum(6, 8, algorithm='default') # needs sage.libs.flint -1/8 - sage: dedekind_sum(6, 8, algorithm='flint') + sage: dedekind_sum(6, 8, algorithm='flint') # needs sage.libs.flint -1/8 - sage: dedekind_sum(6, 8, algorithm='pari') + sage: dedekind_sum(6, 8, algorithm='pari') # needs sage.libs.pari -1/8 Tests with numpy and gmpy2 numbers:: - sage: from numpy import int8 - sage: dedekind_sum(int8(5), int8(7), algorithm='default') + sage: from numpy import int8 # needs numpy + sage: dedekind_sum(int8(5), int8(7), algorithm='default') # needs numpy sage.libs.flint -1/14 sage: from gmpy2 import mpz - sage: dedekind_sum(mpz(5), mpz(7), algorithm='default') + sage: dedekind_sum(mpz(5), mpz(7), algorithm='default') # needs sage.libs.flint -1/14 REFERENCES: @@ -6185,10 +6243,11 @@ def gauss_sum(char_value, finite_field): EXAMPLES:: + sage: # needs sage.libs.pari sage.rings.number_field sage: from sage.arith.misc import gauss_sum sage: F = GF(5); q = 5 - sage: zq = UniversalCyclotomicField().zeta(q-1) - sage: L = [gauss_sum(zq**i,F) for i in range(5)]; L + sage: zq = UniversalCyclotomicField().zeta(q - 1) + sage: L = [gauss_sum(zq**i, F) for i in range(5)]; L [-1, E(20)^4 + E(20)^13 - E(20)^16 - E(20)^17, E(5) - E(5)^2 - E(5)^3 + E(5)^4, @@ -6197,34 +6256,37 @@ def gauss_sum(char_value, finite_field): sage: [g*g.conjugate() for g in L] [1, 5, 5, 5, 1] + sage: # needs sage.libs.pari sage.rings.number_field sage: F = GF(11**2); q = 11**2 - sage: zq = UniversalCyclotomicField().zeta(q-1) - sage: g = gauss_sum(zq**4,F) + sage: zq = UniversalCyclotomicField().zeta(q - 1) + sage: g = gauss_sum(zq**4, F) sage: g*g.conjugate() 121 TESTS:: + sage: # needs sage.libs.pari sage.rings.number_field sage: F = GF(11); q = 11 - sage: zq = UniversalCyclotomicField().zeta(q-1) - sage: gauss_sum(zq**2,F).n(60) + sage: zq = UniversalCyclotomicField().zeta(q - 1) + sage: gauss_sum(zq**2, F).n(60) 2.6361055643248352 + 2.0126965627574471*I - sage: zq = QQbar.zeta(q-1) - sage: gauss_sum(zq**2,F) + sage: zq = QQbar.zeta(q - 1) # needs sage.libs.pari sage.rings.number_field + sage: gauss_sum(zq**2, F) # needs sage.libs.pari sage.rings.number_field 2.636105564324836? + 2.012696562757447?*I - sage: zq = ComplexField(60).zeta(q-1) - sage: gauss_sum(zq**2,F) + sage: zq = ComplexField(60).zeta(q - 1) # needs sage.libs.pari sage.rings.number_field + sage: gauss_sum(zq**2, F) # needs sage.libs.pari sage.rings.number_field 2.6361055643248352 + 2.0126965627574471*I + sage: # needs sage.libs.pari sage.rings.number_field sage: F = GF(7); q = 7 - sage: zq = QQbar.zeta(q-1) + sage: zq = QQbar.zeta(q - 1) sage: D = DirichletGroup(7, QQbar) - sage: all(D[i].gauss_sum()==gauss_sum(zq**i,F) for i in range(6)) + sage: all(D[i].gauss_sum() == gauss_sum(zq**i, F) for i in range(6)) True - sage: gauss_sum(1,QQ) + sage: gauss_sum(1, QQ) # needs sage.libs.pari sage.rings.number_field Traceback (most recent call last): ... ValueError: second input must be a finite field diff --git a/src/sage/arith/multi_modular.pxd b/src/sage/arith/multi_modular.pxd index ca7a95581e7..ca43eb3e23f 100644 --- a/src/sage/arith/multi_modular.pxd +++ b/src/sage/arith/multi_modular.pxd @@ -2,12 +2,12 @@ from sage.ext.mod_int cimport * from sage.libs.gmp.types cimport mpz_t cdef class MultiModularBasis_base(): - cdef int n + cdef int n cdef mod_int* moduli - cdef mpz_t* partial_products - cdef mod_int* C # precomputed values for CRT - cdef mpz_t product - cdef mpz_t half_product + cdef mpz_t* partial_products + cdef mod_int* C # precomputed values for CRT + cdef mpz_t product + cdef mpz_t half_product cdef unsigned long _l_bound cdef unsigned long _u_bound cdef unsigned long _num_primes diff --git a/src/sage/arith/multi_modular.pyx b/src/sage/arith/multi_modular.pyx index 2958315c346..a656742bd50 100644 --- a/src/sage/arith/multi_modular.pyx +++ b/src/sage/arith/multi_modular.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - primecountpy """ Utility classes for multi-modular algorithms """ @@ -16,7 +17,7 @@ from cysignals.memory cimport check_allocarray, check_reallocarray, sig_free from sage.libs.gmp.mpz cimport * from sage.rings.integer cimport Integer, smallInteger -from sage.arith.all import random_prime +from sage.arith.misc import random_prime from types import GeneratorType from sage.ext.stdsage cimport PY_NEW from cpython.object cimport PyObject_RichCompare @@ -185,7 +186,7 @@ cdef class MultiModularBasis_base(): cdef mod_int _new_random_prime(self, set known_primes) except 1: """ Choose a new random prime for inclusion in the list of moduli, - or raise a ``RuntimeError`` if there are no more primes. + or raise a :class:`RuntimeError` if there are no more primes. INPUT: @@ -193,7 +194,6 @@ cdef class MultiModularBasis_base(): the allowed interval; we will not return a prime in known_primes. """ - cdef Py_ssize_t i cdef mod_int p while True: if len(known_primes) >= self._num_primes: @@ -371,11 +371,10 @@ cdef class MultiModularBasis_base(): return self.n # find new prime moduli - cdef int i new_moduli = [] new_partial_products = [] - cdef Integer M # keeps current height - cdef mod_int p # keeps current prime moduli + cdef Integer M # keeps current height + cdef mod_int p # keeps current prime moduli if self.n == 0: M = smallInteger(1) @@ -392,7 +391,7 @@ cdef class MultiModularBasis_base(): new_partial_products.append(M) mpz_clear(height) return self.extend_with_primes(new_moduli, new_partial_products, - check=False) + check=False) def _extend_moduli_to_count(self, int count): r""" @@ -471,7 +470,7 @@ cdef class MultiModularBasis_base(): Compute and store `\prod_j=1^{i-1} m_j^{-1} (mod m_i)` for i >= start. """ if start == 0: - start = 1 # first one is trivial, never used + start = 1 # first one is trivial, never used self.C[0] = 1 for i in range(start, self.n): self.C[i] = ai.c_inverse_mod_longlong(mpz_fdiv_ui(self.partial_products[i-1], self.moduli[i]), self.moduli[i]) @@ -484,7 +483,7 @@ cdef class MultiModularBasis_base(): self._extend_moduli_to_height_c(height) cdef int count - count = self.n * mpz_sizeinbase(height, 2) / mpz_sizeinbase(self.partial_products[self.n-1], 2) # an estimate + count = self.n * mpz_sizeinbase(height, 2) / mpz_sizeinbase(self.partial_products[self.n-1], 2) # an estimate count = max(min(count, self.n), 1) while count > 1 and mpz_cmp(height, self.partial_products[count-1]) < 0: count -= 1 @@ -569,7 +568,7 @@ cdef class MultiModularBasis_base(): s = 1 mpz_init_set_si(z, b[0]) if b[0] == 0: - while s < len and b[s] == 0: # fast forward to first non-zero + while s < len and b[s] == 0: # fast forward to first non-zero s += 1 else: s = 0 @@ -620,10 +619,10 @@ cdef class MultiModularBasis_base(): if offset == 0: mpz_set_si(z[j], b[0][j]) if b[0][j] == 0: - while i < len and b[i][j] == 0: # fast forward to first non-zero + while i < len and b[i][j] == 0: # fast forward to first non-zero i += 1 while i < len: - mpz_set_si(u, ((b[i][j] + m[i] - mpz_fdiv_ui(z[j], m[i])) * self.C[i]) % m[i]) # u = ((b_i - z) * C_i) % m_i + mpz_set_si(u, ((b[i][j] + m[i] - mpz_fdiv_ui(z[j], m[i])) * self.C[i]) % m[i]) # u = ((b_i - z) * C_i) % m_i mpz_mul(u, u, self.partial_products[i-1]) mpz_add(z[j], z[j], u) i += 1 @@ -632,7 +631,6 @@ cdef class MultiModularBasis_base(): if mpz_cmp(z[j], self.half_product) > 0: mpz_sub(z[j], z[j], self.product) - cdef Integer zz zz = PY_NEW(Integer) mpz_set(zz.value, self.half_product) @@ -833,7 +831,7 @@ cdef class MultiModularBasis_base(): """ if isinstance(ix, slice): return self.__class__(self.list()[ix], l_bound = self._l_bound, - u_bound = self._u_bound) + u_bound = self._u_bound) cdef Py_ssize_t i = ix if i != ix: @@ -852,7 +850,7 @@ cdef class MultiModularBasis_base(): sage: MultiModularBasis_base([10007]) MultiModularBasis with moduli [10007] """ - return "MultiModularBasis with moduli "+str(self.list()) + return "MultiModularBasis with moduli " + str(self.list()) cdef class MultiModularBasis(MultiModularBasis_base): diff --git a/src/sage/arith/numerical_approx.pxd b/src/sage/arith/numerical_approx.pxd index b12750f3dc3..85f92eca336 100644 --- a/src/sage/arith/numerical_approx.pxd +++ b/src/sage/arith/numerical_approx.pxd @@ -1,3 +1,5 @@ +# sage.doctest: needs sage.rings.real_mpfr + cpdef inline long digits_to_bits(d) except -1: """ EXAMPLES:: diff --git a/src/sage/arith/numerical_approx.pyx b/src/sage/arith/numerical_approx.pyx index b53d7679099..6698a0ec317 100644 --- a/src/sage/arith/numerical_approx.pyx +++ b/src/sage/arith/numerical_approx.pyx @@ -1,21 +1,24 @@ +# sage.doctest: needs sage.rings.real_mpfr r""" Generic numerical approximation function """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Jeroen Demeyer <jdemeyer@cage.ugent.be> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.parent cimport Parent from sage.structure.element cimport parent cdef Parent CDF -from sage.rings.all import RealField, ComplexField, CDF +from sage.rings.real_mpfr import RealField +from sage.rings.complex_mpfr import ComplexField +from sage.rings.complex_double import CDF def numerical_approx_generic(x, prec): @@ -26,7 +29,7 @@ def numerical_approx_generic(x, prec): EXAMPLES:: sage: from sage.arith.numerical_approx import numerical_approx_generic - sage: numerical_approx_generic(pi, 20) + sage: numerical_approx_generic(pi, 20) # needs sage.symbolic 3.1416 sage: numerical_approx_generic(int(42), 20) 42.000 diff --git a/src/sage/arith/power.pyx b/src/sage/arith/power.pyx index 2900d9f2a45..acd5f885e85 100644 --- a/src/sage/arith/power.pyx +++ b/src/sage/arith/power.pyx @@ -5,15 +5,15 @@ This implements powering of arbitrary objects using a square-and-multiply algorithm. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Jeroen Demeyer <J.Demeyer@UGent.be> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_check diff --git a/src/sage/arith/rational_reconstruction.pyx b/src/sage/arith/rational_reconstruction.pyx index 6d2a4886bb3..4a669f977cb 100644 --- a/src/sage/arith/rational_reconstruction.pyx +++ b/src/sage/arith/rational_reconstruction.pyx @@ -11,7 +11,7 @@ AUTHORS: - Jeroen Demeyer (2014-10-20): move this function from ``gmp.pxi``, simplify and fix some bugs, see :trac:`17180` """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 ??? # Copyright (C) 2014 Jeroen Demeyer <jdemeyer@cage.ugent.be> # @@ -19,8 +19,8 @@ AUTHORS: # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off @@ -34,8 +34,8 @@ cdef int mpq_rational_reconstruction(mpq_t answer, mpz_t a, mpz_t m) except -1: such that the numerator and denominator of the result is bounded by sqrt(m/2). - If `m` is zero, raise ``ZeroDivisionError``. If the rational - reconstruction does not exist, raise ``ValueError``. + If `m` is zero, raise :class`ZeroDivisionError`. If the rational + reconstruction does not exist, raise :class:`ValueError`. We assume that ``mpq_init`` has been called on ``answer``. diff --git a/src/sage/arith/srange.pyx b/src/sage/arith/srange.pyx index c21a43c0ee1..132cf93d085 100644 --- a/src/sage/arith/srange.pyx +++ b/src/sage/arith/srange.pyx @@ -84,7 +84,7 @@ def xsrange(start, end=None, step=1, universe=None, *, coerce=True, bint include EXAMPLES:: sage: xsrange(10) - <generator object at 0x...> + <...generator object at 0x...> sage: for i in xsrange(1,5): ....: print(i) 1 @@ -244,8 +244,8 @@ def srange(*args, **kwds): [1.00000000000000] sage: srange(1.0, 1.0) [] - sage: V = VectorSpace(QQ, 2) - sage: srange(V([0,0]), V([5,5]), step=V([2,2])) + sage: V = VectorSpace(QQ, 2) # needs sage.modules + sage: srange(V([0,0]), V([5,5]), step=V([2,2])) # needs sage.modules [(0, 0), (2, 2), (4, 4)] Including the endpoint:: diff --git a/src/sage/calculus/all.py b/src/sage/calculus/all.py index bc93e3f62a7..c83a97f6eb4 100644 --- a/src/sage/calculus/all.py +++ b/src/sage/calculus/all.py @@ -1,7 +1,7 @@ from .calculus import maxima as maxima_calculus from .calculus import (laplace, inverse_laplace, - limit, lim) + limit, lim) from .integration import numerical_integral, monte_carlo_integral integral_numerical = numerical_integral @@ -9,17 +9,17 @@ from .interpolation import spline, Spline from .functional import (diff, derivative, - expand, - taylor, simplify) + expand, + taylor, simplify) -from .functions import (wronskian,jacobian) +from .functions import (wronskian, jacobian) from .ode import ode_solver, ode_system from .desolvers import (desolve, desolve_laplace, desolve_system, - eulers_method, eulers_method_2x2, - eulers_method_2x2_plot, desolve_rk4, desolve_system_rk4, - desolve_odeint, desolve_mintides, desolve_tides_mpfr) + eulers_method, eulers_method_2x2, + eulers_method_2x2_plot, desolve_rk4, desolve_system_rk4, + desolve_odeint, desolve_mintides, desolve_tides_mpfr) from .var import (var, function, clear_vars) @@ -27,8 +27,8 @@ # We lazy_import the following modules since they import numpy which slows down sage startup from sage.misc.lazy_import import lazy_import -lazy_import("sage.calculus.riemann",["Riemann_Map"]) -lazy_import("sage.calculus.interpolators",["polygon_spline","complex_cubic_spline"]) +lazy_import("sage.calculus.riemann", ["Riemann_Map"]) +lazy_import("sage.calculus.interpolators", ["polygon_spline", "complex_cubic_spline"]) from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix @@ -77,21 +77,21 @@ def symbolic_expression(x): If ``x`` is a list or tuple, create a vector of symbolic expressions:: - sage: v=symbolic_expression([x,1]); v + sage: v = symbolic_expression([x,1]); v (x, 1) sage: v.base_ring() Symbolic Ring - sage: v=symbolic_expression((x,1)); v + sage: v = symbolic_expression((x,1)); v (x, 1) sage: v.base_ring() Symbolic Ring - sage: v=symbolic_expression((3,1)); v + sage: v = symbolic_expression((3,1)); v (3, 1) sage: v.base_ring() Symbolic Ring sage: E = EllipticCurve('15a'); E Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field - sage: v=symbolic_expression([E,E]); v + sage: v = symbolic_expression([E,E]); v (x*y + y^2 + y == x^3 + x^2 - 10*x - 10, x*y + y^2 + y == x^3 + x^2 - 10*x - 10) sage: v.base_ring() Symbolic Ring @@ -229,4 +229,5 @@ def symbolic_expression(x): return SR(result).function(*vars) return SR(x) + from . import desolvers diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 00da3f9d4af..37807450ac0 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -80,23 +80,23 @@ :: - sage: f(x,y)=x^2*y+y^2+y - sage: f.diff() # gradient + sage: f(x,y) = x^2*y + y^2 + y + sage: f.diff() # gradient (x, y) |--> (2*x*y, x^2 + 2*y + 1) - sage: solve(list(f.diff()),[x,y]) + sage: solve(list(f.diff()), [x,y]) [[x == -I, y == 0], [x == I, y == 0], [x == 0, y == (-1/2)]] sage: H=f.diff(2); H # Hessian matrix [(x, y) |--> 2*y (x, y) |--> 2*x] [(x, y) |--> 2*x (x, y) |--> 2] - sage: H(x=0,y=-1/2) + sage: H(x=0, y=-1/2) [-1 0] [ 0 2] - sage: H(x=0,y=-1/2).eigenvalues() + sage: H(x=0, y=-1/2).eigenvalues() [-1, 2] Here we calculate the Jacobian for the polar coordinate transformation:: - sage: T(r,theta)=[r*cos(theta),r*sin(theta)] + sage: T(r,theta) = [r*cos(theta),r*sin(theta)] sage: T (r, theta) |--> (r*cos(theta), r*sin(theta)) sage: T.diff() # Jacobian matrix @@ -117,7 +117,7 @@ ValueError: No differentiation variable specified. Simplifying symbolic sums is also possible, using the -sum command, which also uses Maxima in the background:: +:func:`sum` command, which also uses Maxima in the background:: sage: k, m = var('k, m') sage: sum(1/k^4, k, 1, oo) @@ -136,10 +136,11 @@ [ 1/2*(e^(2*sqrt(x)) + 1)*e^(x - sqrt(x)) 1/2*(x*e^(2*sqrt(x)) - x)*sqrt(x)*e^(x - sqrt(x))] [ 1/2*(e^(2*sqrt(x)) - 1)*e^(x - sqrt(x))/x^(3/2) 1/2*(e^(2*sqrt(x)) + 1)*e^(x - sqrt(x))] -And complex exponentiation works now:: +Complex exponentiation works, but may require a patched version of +maxima (:trac:`32898`) for now:: sage: M = i*matrix([[pi]]) - sage: e^M + sage: e^M # not tested, requires patched maxima [-1] sage: M = i*matrix([[pi,0],[0,2*pi]]) sage: e^M @@ -181,19 +182,19 @@ sage: f(x=pi) 0 -We can also make a ``CallableSymbolicExpression``, -which is a ``SymbolicExpression`` that is a function of +We can also make a :class:`CallableSymbolicExpression`, +which is a :class:`SymbolicExpression` that is a function of specified variables in a fixed order. Each -``SymbolicExpression`` has a +:class:`SymbolicExpression` has a ``function(...)`` method that is used to create a -``CallableSymbolicExpression``, as illustrated below:: +:class:`CallableSymbolicExpression`, as illustrated below:: sage: u = log((2-x)/(y+5)) sage: f = u.function(x, y); f (x, y) |--> log(-(x - 2)/(y + 5)) There is an easier way of creating a -``CallableSymbolicExpression``, which relies on the +:class:`CallableSymbolicExpression`, which relies on the Sage preparser. :: @@ -266,7 +267,8 @@ sage: CC(f) 1.12762596520638 + 1.17520119364380*I sage: ComplexField(200)(f) - 1.1276259652063807852262251614026720125478471180986674836290 + 1.1752011936438014568823818505956008151557179813340958702296*I + 1.1276259652063807852262251614026720125478471180986674836290 + + 1.1752011936438014568823818505956008151557179813340958702296*I sage: ComplexField(100)(f) 1.1276259652063807852262251614 + 1.1752011936438014568823818506*I @@ -285,8 +287,9 @@ We can, of course, substitute:: - sage: f(n9=9,n7=n6) - 1/n1 + 1/n2^2 + 1/n3^3 + 1/n4^4 + 1/n5^5 + 1/n6^6 + 1/n6^7 + 1/n8^8 + 387420490/387420489 + sage: f(n9=9, n7=n6) + 1/n1 + 1/n2^2 + 1/n3^3 + 1/n4^4 + 1/n5^5 + 1/n6^6 + 1/n6^7 + 1/n8^8 + + 387420490/387420489 TESTS: @@ -316,7 +319,7 @@ sage: maxima.eval('expand((x+y)^3)') '27' -If the copy of maxima used by the symbolic calculus package were +If the copy of Maxima used by the symbolic calculus package were the same as the default one, then the following would return 27, which would be very confusing indeed! @@ -424,9 +427,9 @@ from sage.misc.latex import latex from sage.misc.parser import Parser, LookupNameMaker - -from sage.symbolic.ring import var, SR, is_SymbolicVariable -from sage.symbolic.expression import Expression, symbol_table +from sage.structure.element import Expression +from sage.symbolic.ring import var, SR +from sage.symbolic.symbols import symbol_table from sage.symbolic.function import Function from sage.symbolic.function_factory import function_factory from sage.symbolic.integration.integral import (indefinite_integral, @@ -445,27 +448,27 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): INPUT: - - ``expression`` - a symbolic expression + - ``expression`` -- a symbolic expression - - ``v`` - a variable or variable name + - ``v`` -- a variable or variable name - - ``a`` - lower endpoint of the sum + - ``a`` -- lower endpoint of the sum - - ``b`` - upper endpoint of the sum + - ``b`` -- upper endpoint of the sum - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'maple'`` - (optional) use Maple + - ``'maple'`` -- (optional) use Maple - - ``'mathematica'`` - (optional) use Mathematica + - ``'mathematica'`` -- (optional) use Mathematica - - ``'giac'`` - (optional) use Giac + - ``'giac'`` -- (optional) use Giac - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``hold`` - (default: ``False``) if ``True`` don't evaluate + - ``hold`` -- (default: ``False``) if ``True``, don't evaluate EXAMPLES:: @@ -492,13 +495,13 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): And some truncations thereof:: sage: assume(n>1) - sage: symbolic_sum(binomial(n,k),k,1,n) + sage: symbolic_sum(binomial(n,k), k, 1, n) 2^n - 1 - sage: symbolic_sum(binomial(n,k),k,2,n) + sage: symbolic_sum(binomial(n,k), k, 2, n) 2^n - n - 1 - sage: symbolic_sum(binomial(n,k),k,0,n-1) + sage: symbolic_sum(binomial(n,k), k, 0, n-1) 2^n - 1 - sage: symbolic_sum(binomial(n,k),k,1,n-1) + sage: symbolic_sum(binomial(n,k), k, 1, n-1) 2^n - 2 The binomial theorem:: @@ -555,22 +558,22 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): ... ValueError: Sum is divergent. sage: forget() - sage: assumptions() # check the assumptions were really forgotten + sage: assumptions() # check the assumptions were really forgotten [] A summation performed by Mathematica:: - sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'mathematica') # optional - mathematica + sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='mathematica') # optional - mathematica pi*coth(pi) An example of this summation with Giac:: - sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'giac') + sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='giac') (pi*e^(2*pi) - pi*e^(-2*pi))/(e^(2*pi) + e^(-2*pi) - 2) The same summation is solved by SymPy:: - sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'sympy') + sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='sympy') pi/tanh(pi) SymPy and Maxima 5.39.0 can do the following (see @@ -583,7 +586,7 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): Use Maple as a backend for summation:: - sage: symbolic_sum(binomial(n,k)*x^k, k, 0, n, algorithm = 'maple') # optional - maple + sage: symbolic_sum(binomial(n,k)*x^k, k, 0, n, algorithm='maple') # optional - maple (x + 1)^n If you don't want to evaluate immediately give the ``hold`` keyword:: @@ -613,7 +616,7 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): the summation the result might not be convertible into a Sage expression. """ - if not is_SymbolicVariable(v): + if not (isinstance(v, Expression) and v.is_symbol()): if isinstance(v, str): v = var(v) else: @@ -685,17 +688,17 @@ def nintegral(ex, x, a, b, INPUT: - - ``x`` - variable to integrate with respect to + - ``x`` -- variable to integrate with respect to - - ``a`` - lower endpoint of integration + - ``a`` -- lower endpoint of integration - - ``b`` - upper endpoint of integration + - ``b`` -- upper endpoint of integration - - ``desired_relative_error`` - (default: '1e-8') the + - ``desired_relative_error`` -- (default: ``1e-8``) the desired relative error - - ``maximum_num_subintervals`` - (default: 200) - maxima number of subintervals + - ``maximum_num_subintervals`` -- (default: 200) + maximal number of subintervals OUTPUT: @@ -708,26 +711,26 @@ def nintegral(ex, x, a, b, - an error code: - - ``0`` - no problems were encountered + - ``0`` -- no problems were encountered - - ``1`` - too many subintervals were done + - ``1`` -- too many subintervals were done - - ``2`` - excessive roundoff error + - ``2`` -- excessive roundoff error - - ``3`` - extremely bad integrand behavior + - ``3`` -- extremely bad integrand behavior - - ``4`` - failed to converge + - ``4`` -- failed to converge - - ``5`` - integral is probably divergent or slowly + - ``5`` -- integral is probably divergent or slowly convergent - - ``6`` - the input is invalid; this includes the case of - desired_relative_error being too small to be achieved + - ``6`` -- the input is invalid; this includes the case of + ``desired_relative_error`` being too small to be achieved - ALIAS: nintegrate is the same as nintegral + ALIAS: :func:`nintegrate` is the same as :func:`nintegral` REMARK: There is also a function - ``numerical_integral`` that implements numerical + :func:`numerical_integral` that implements numerical integration using the GSL C library. It is potentially much faster and applies to arbitrary user defined functions. @@ -740,7 +743,7 @@ def nintegral(ex, x, a, b, :: sage: f = x - sage: f.nintegral(x,0,1,1e-14) + sage: f.nintegral(x, 0, 1, 1e-14) (0.0, 0.0, 0, 6) EXAMPLES:: @@ -749,7 +752,7 @@ def nintegral(ex, x, a, b, sage: f.nintegral(x, 0, 1) (0.5284822353142306, 4.163...e-11, 231, 0) - We can also use the ``numerical_integral`` function, + We can also use the :func:`numerical_integral` function, which calls the GSL C library. :: @@ -782,9 +785,9 @@ def nintegral(ex, x, a, b, Now numerically integrating, we see why the answer is wrong:: sage: f.nintegrate(x,0,1) - (-480.0000000000001, 5.32907051820075...e-12, 21, 0) + (-480.000000000000..., 5.32907051820075...e-12, 21, 0) - It is just because every floating point evaluation of return -480.0 + It is just because every floating point evaluation of `f` returns `-480.0` in floating point. Important note: using PARI/GP one can compute numerical integrals @@ -830,25 +833,25 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): INPUT: - - ``expression`` - a symbolic expression + - ``expression`` -- a symbolic expression - - ``v`` - a variable or variable name + - ``v`` -- a variable or variable name - - ``a`` - lower endpoint of the product + - ``a`` -- lower endpoint of the product - - ``b`` - upper endpoint of the prduct + - ``b`` -- upper endpoint of the prduct - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'giac'`` - use Giac + - ``'giac'`` -- use Giac - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``'mathematica'`` - (optional) use Mathematica + - ``'mathematica'`` -- (optional) use Mathematica - - ``hold`` - (default: ``False``) if ``True`` don't evaluate + - ``hold`` - (default: ``False``) if ``True``, don't evaluate EXAMPLES:: @@ -879,7 +882,7 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): (-1)^n*factorial(n)^2 """ - if not is_SymbolicVariable(v): + if not (isinstance(v, Expression) and v.is_symbol()): if isinstance(v, str): v = var(v) else: @@ -934,50 +937,50 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): r""" - Return the minimal polynomial of self, if possible. + Return the minimal polynomial of ``self``, if possible. INPUT: - - ``var`` - polynomial variable name (default 'x') + - ``var`` -- polynomial variable name (default 'x') - - ``algorithm`` - 'algebraic' or 'numerical' (default + - ``algorithm`` -- ``'algebraic'`` or ``'numerical'`` (default both, but with numerical first) - - ``bits`` - the number of bits to use in numerical + - ``bits`` -- the number of bits to use in numerical approx - - ``degree`` - the expected algebraic degree + - ``degree`` -- the expected algebraic degree - - ``epsilon`` - return without error as long as + - ``epsilon`` -- return without error as long as f(self) epsilon, in the case that the result cannot be proven. - All of the above parameters are optional, with epsilon=0, bits and - degree tested up to 1000 and 24 by default respectively. The + All of the above parameters are optional, with epsilon=0, ``bits`` and + ``degree`` tested up to 1000 and 24 by default respectively. The numerical algorithm will be faster if bits and/or degree are given explicitly. The algebraic algorithm ignores the last three parameters. - OUTPUT: The minimal polynomial of self. If the numerical algorithm - is used then it is proved symbolically when epsilon=0 (default). + OUTPUT: The minimal polynomial of ``self``. If the numerical algorithm + is used, then it is proved symbolically when ``epsilon=0`` (default). If the minimal polynomial could not be found, two distinct kinds of errors are raised. If no reasonable candidate was found with the - given bit/degree parameters, a ``ValueError`` will be + given ``bits``/``degree`` parameters, a :class:`ValueError` will be raised. If a reasonable candidate was found but (perhaps due to limits in the underlying symbolic package) was unable to be proved - correct, a ``NotImplementedError`` will be raised. + correct, a :class:`NotImplementedError` will be raised. ALGORITHM: Two distinct algorithms are used, depending on the algorithm parameter. By default, the numerical algorithm is attempted first, then the algebraic one. - Algebraic: Attempt to evaluate this expression in QQbar, using + Algebraic: Attempt to evaluate this expression in ``QQbar``, using cyclotomic fields to resolve exponential and trig functions at - rational multiples of pi, field extensions to handle roots and + rational multiples of `\pi`, field extensions to handle roots and rational exponents, and computing compositums to represent the full expression as an element of a number field where the minimal - polynomial can be computed exactly. The bits, degree, and epsilon + polynomial can be computed exactly. The ``bits``, ``degree``, and ``epsilon`` parameters are ignored. Numerical: Computes a numerical approximation of @@ -988,8 +991,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): vanishing. If this fails, and ``epsilon`` is non-zero, return `f` if and only if `f(\mathtt{self}) < \mathtt{epsilon}`. - Otherwise raise a ``ValueError`` (if no suitable - candidate was found) or a ``NotImplementedError`` (if a + Otherwise raise a :class:`ValueError` (if no suitable + candidate was found) or a :class:`NotImplementedError` (if a likely candidate was found but could not be proved correct). EXAMPLES: First some simple examples:: @@ -1013,7 +1016,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: sin(pi/7).minpoly() x^6 - 7/4*x^4 + 7/8*x^2 - 7/64 sage: minpoly(exp(I*pi/17)) - x^16 - x^15 + x^14 - x^13 + x^12 - x^11 + x^10 - x^9 + x^8 - x^7 + x^6 - x^5 + x^4 - x^3 + x^2 - x + 1 + x^16 - x^15 + x^14 - x^13 + x^12 - x^11 + x^10 - x^9 + x^8 + - x^7 + x^6 - x^5 + x^4 - x^3 + x^2 - x + 1 Here we verify it gives the same result as the abstract number field. @@ -1026,14 +1030,15 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: (a+b+a*b).absolute_minpoly() x^4 - 22*x^2 - 48*x - 23 - The minpoly function is used implicitly when creating + The :func:`minpoly` function is used implicitly when creating number fields:: sage: x = var('x') sage: eqn = x^3 + sqrt(2)*x + 5 == 0 sage: a = solve(eqn, x)[0].rhs() sage: QQ[a] - Number Field in a with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25 with a = 0.7185272465828846? - 1.721353471724806?*I + Number Field in a with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25 + with a = 0.7185272465828846? - 1.721353471724806?*I Here we solve a cubic and then recover it from its complicated radical expansion. @@ -1042,7 +1047,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: f = x^3 - x + 1 sage: a = f.solve(x)[0].rhs(); a - -1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1) - 1/6*(-I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3) + -1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1) + - 1/6*(-I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3) sage: a.minpoly() x^3 - x + 1 @@ -1055,7 +1061,9 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: f = a.minpoly(); f x^8 - 40*x^6 + 352*x^4 - 960*x^2 + 576 sage: f(a) - (sqrt(5) + sqrt(3) + sqrt(2))^8 - 40*(sqrt(5) + sqrt(3) + sqrt(2))^6 + 352*(sqrt(5) + sqrt(3) + sqrt(2))^4 - 960*(sqrt(5) + sqrt(3) + sqrt(2))^2 + 576 + (sqrt(5) + sqrt(3) + sqrt(2))^8 - 40*(sqrt(5) + sqrt(3) + sqrt(2))^6 + + 352*(sqrt(5) + sqrt(3) + sqrt(2))^4 - 960*(sqrt(5) + sqrt(3) + sqrt(2))^2 + + 576 sage: f(a).expand() 0 @@ -1082,9 +1090,11 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): :: sage: cos(pi/33).minpoly(algorithm='algebraic') - x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 + x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 + - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 sage: cos(pi/33).minpoly(algorithm='numerical') - x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 + x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 + - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 Sometimes it fails, as it must given that some numbers aren't algebraic:: @@ -1161,12 +1171,12 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): INPUT: - - ``dir`` - (default: None); dir may have the value - 'plus' (or '+' or 'right' or 'above') for a limit from above, - 'minus' (or '-' or 'left' or 'below') for a limit from below, or may be omitted + - ``dir`` -- (default: ``None``); may have the value + ``'plus'`` (or ``'+'`` or ``'right'`` or ``'above'``) for a limit from above, + ``'minus'`` (or ``'-'`` or ``'left'`` or ``'below'``) for a limit from below, or may be omitted (implying a two-sided limit is to be computed). - - ``taylor`` - (default: False); if True, use Taylor + - ``taylor`` -- (default: ``False``); if ``True``, use Taylor series, which allows more limits to be computed (but may also crash in some obscure cases due to bugs in Maxima). @@ -1174,8 +1184,8 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): .. note:: - The output may also use 'und' (undefined), 'ind' - (indefinite but bounded), and 'infinity' (complex + The output may also use ``und`` (undefined), ``ind`` + (indefinite but bounded), and ``infinity`` (complex infinity). EXAMPLES:: @@ -1186,8 +1196,18 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): e sage: f.limit(x=5) 7776/3125 - sage: f.limit(x=1.2) + + Domain to real, a regression in 5.46.0, see https://sf.net/p/maxima/bugs/4138 :: + + sage: maxima_calculus.eval("domain:real") + ... + sage: f.limit(x=1.2).n() 2.06961575467... + sage: maxima_calculus.eval("domain:complex"); + ... + + Otherwise, it works :: + sage: f.limit(x=I, taylor=True) (-I + 1)^I sage: f(x=1.2) @@ -1215,7 +1235,7 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): With this example, Maxima is looking for a LOT of information:: sage: assume(a>0) - sage: limit(x^a,x=0) + sage: limit(x^a,x=0) # random - maxima 5.46.0 does not need extra assumption Traceback (most recent call last): ... ValueError: Computation failed since Maxima requested additional @@ -1224,7 +1244,7 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): more details) Is a an integer? sage: assume(a,'integer') - sage: limit(x^a, x=0) + sage: limit(x^a, x=0) # random - maxima 5.46.0 does not need extra assumption Traceback (most recent call last): ... ValueError: Computation failed since Maxima requested additional @@ -1325,7 +1345,7 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): sage: limit(floor(x), x=0, dir='+') 0 sage: limit(floor(x), x=0) - und + ...nd Maxima gives the right answer here, too, showing that :trac:`4142` is fixed:: @@ -1477,7 +1497,7 @@ def mma_free_limit(expression, v, a, dir=None): - ``expression`` -- symbolic expression - ``v`` -- variable - ``a`` -- value where the variable goes to - - ``dir`` -- ``'+'``, ``'-'`` or ``None`` (optional, default:``None``) + - ``dir`` -- ``'+'``, ``'-'`` or ``None`` (optional, default: ``None``) EXAMPLES:: @@ -1536,19 +1556,19 @@ def laplace(ex, t, s, algorithm='maxima'): INPUT: - - ``ex`` - a symbolic expression + - ``ex`` -- a symbolic expression - - ``t`` - independent variable + - ``t`` -- independent variable - - ``s`` - transform parameter + - ``s`` -- transform parameter - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``'giac'`` - use Giac + - ``'giac'`` -- use Giac .. NOTE:: @@ -1611,7 +1631,7 @@ def laplace(ex, t, s, algorithm='maxima'): Next we form the augmented matrix of the above system:: - sage: A = matrix([[s, 16, 270],[1, s, 90+1/s]]) + sage: A = matrix([[s, 16, 270], [1, s, 90+1/s]]) sage: E = A.echelon_form() sage: xt = E[0,2].inverse_laplace(s,t) sage: yt = E[1,2].inverse_laplace(s,t) @@ -1619,11 +1639,11 @@ def laplace(ex, t, s, algorithm='maxima'): -91/2*e^(4*t) + 629/2*e^(-4*t) + 1 sage: yt 91/8*e^(4*t) + 629/8*e^(-4*t) - sage: p1 = plot(xt,0,1/2,rgbcolor=(1,0,0)) - sage: p2 = plot(yt,0,1/2,rgbcolor=(0,1,0)) + sage: p1 = plot(xt, 0, 1/2, rgbcolor=(1,0,0)) # needs sage.plot + sage: p2 = plot(yt, 0, 1/2, rgbcolor=(0,1,0)) # needs sage.plot sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: - ....: (p1+p2).save(f.name) + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot + ....: (p1 + p2).save(f.name) Another example:: @@ -1690,8 +1710,11 @@ def laplace(ex, t, s, algorithm='maxima'): Testing SymPy:: - sage: laplace(t^n, t, s, algorithm='sympy') - (gamma(n + 1)/(s*s^n), 0, re(n) > -1) + sage: F, a, cond = laplace(t^n, t, s, algorithm='sympy') + sage: a, cond + (0, re(n) > -1) + sage: F.simplify() + s^(-n - 1)*gamma(n + 1) Testing Maxima:: @@ -1700,17 +1723,19 @@ def laplace(ex, t, s, algorithm='maxima'): Check that :trac:`24212` is fixed:: - sage: laplace(cos(t^2), t, s, algorithm='sympy') - (-1/2*sqrt(pi)*(sqrt(2)*cos(1/4*s^2)*fresnel_sin(1/2*sqrt(2)*s/sqrt(pi)) - - sqrt(2)*fresnel_cos(1/2*sqrt(2)*s/sqrt(pi))*sin(1/4*s^2) - cos(1/4*pi + 1/4*s^2)), - 0, True) + sage: F, a, cond = laplace(cos(t^2), t, s, algorithm='sympy') + sage: a, cond + (0, True) + sage: F._sympy_().simplify() + sqrt(pi)*(sqrt(2)*sin(s**2/4)*fresnelc(sqrt(2)*s/(2*sqrt(pi))) - + sqrt(2)*cos(s**2/4)*fresnels(sqrt(2)*s/(2*sqrt(pi))) + cos(s**2/4 + pi/4))/2 Testing result from SymPy that Sage doesn't know how to handle:: sage: laplace(cos(-1/t), t, s, algorithm='sympy') Traceback (most recent call last): ... - AttributeError: Unable to convert SymPy result (=meijerg(((), ()), ((-1/2, 0, 1/2), (0,)), s**2/16)/4) into Sage + AttributeError: Unable to convert SymPy result (=meijerg(((), ()), ((-1/2, 0, 1/2), (0,)), ...)/4) into Sage """ if not isinstance(ex, (Expression, Function)): ex = SR(ex) @@ -1766,26 +1791,26 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): .. MATH:: - F(s) = \frac{1}{2\pi i} \int_{\gamma-i\infty}^{\gamma + i\infty} e^{st} F(s) dt, + f(t) = \frac{1}{2\pi i} \int_{\gamma-i\infty}^{\gamma + i\infty} e^{st} F(s) ds, where `\gamma` is chosen so that the contour path of integration is in the region of convergence of `F(s)`. INPUT: - - ``ex`` - a symbolic expression + - ``ex`` -- a symbolic expression - - ``s`` - transform parameter + - ``s`` -- transform parameter - - ``t`` - independent variable + - ``t`` -- independent variable - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``'giac'`` - use Giac + - ``'giac'`` -- use Giac .. SEEALSO:: @@ -1817,8 +1842,8 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): Transform an expression involving a time-shift, via SymPy:: - sage: inverse_laplace(1/s^2*exp(-s), s, t, algorithm='sympy') - -(log(e^(-t)) + 1)*heaviside(t - 1) + sage: inverse_laplace(1/s^2*exp(-s), s, t, algorithm='sympy').simplify() + (t - 1)*heaviside(t - 1) The same instance with Giac:: @@ -1827,9 +1852,11 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): Transform a rational expression:: - sage: inverse_laplace((2*s^2*exp(-2*s) - exp(-s))/(s^3+1), s, t, algorithm='giac') - -1/3*(sqrt(3)*e^(1/2*t - 1/2)*sin(1/2*sqrt(3)*(t - 1)) - cos(1/2*sqrt(3)*(t - 1))*e^(1/2*t - 1/2) + - e^(-t + 1))*heaviside(t - 1) + 2/3*(2*cos(1/2*sqrt(3)*(t - 2))*e^(1/2*t - 1) + e^(-t + 2))*heaviside(t - 2) + sage: inverse_laplace((2*s^2*exp(-2*s) - exp(-s))/(s^3+1), s, t, + ....: algorithm='giac') + -1/3*(sqrt(3)*e^(1/2*t - 1/2)*sin(1/2*sqrt(3)*(t - 1)) + - cos(1/2*sqrt(3)*(t - 1))*e^(1/2*t - 1/2) + e^(-t + 1))*heaviside(t - 1) + + 2/3*(2*cos(1/2*sqrt(3)*(t - 2))*e^(1/2*t - 1) + e^(-t + 2))*heaviside(t - 2) sage: inverse_laplace(1/(s - 1), s, x) e^x @@ -1939,7 +1966,7 @@ def at(ex, *args, **kwds): We do not import ``at`` at the top level, but we can use it as a synonym for substitution if we import it:: - sage: g = x^3-3 + sage: g = x^3 - 3 sage: from sage.calculus.calculus import at sage: at(g, x=1) -2 @@ -1954,15 +1981,16 @@ def at(ex, *args, **kwds): u(h + x) sage: diff(u(x+h), x) D[0](u)(h + x) - sage: taylor(u(x+h),h,0,4) - 1/24*h^4*diff(u(x), x, x, x, x) + 1/6*h^3*diff(u(x), x, x, x) + 1/2*h^2*diff(u(x), x, x) + h*diff(u(x), x) + u(x) + sage: taylor(u(x+h), h, 0, 4) + 1/24*h^4*diff(u(x), x, x, x, x) + 1/6*h^3*diff(u(x), x, x, x) + + 1/2*h^2*diff(u(x), x, x) + h*diff(u(x), x) + u(x) We compute a Laplace transform:: sage: var('s,t') (s, t) - sage: f=function('f')(t) - sage: f.diff(t,2) + sage: f = function('f')(t) + sage: f.diff(t, 2) diff(f(t), t, t) sage: f.diff(t,2).laplace(t,s) s^2*laplace(f(t), t, s) - s*f(0) - D[0](f)(0) @@ -2062,7 +2090,7 @@ def dummy_laplace(*args): sage: from sage.calculus.calculus import dummy_laplace sage: s,t = var('s,t') sage: f = function('f') - sage: dummy_laplace(f(t),t,s) + sage: dummy_laplace(f(t), t, s) laplace(f(t), t, s) """ return _laplace(args[0], var(repr(args[1])), var(repr(args[2]))) @@ -2070,7 +2098,7 @@ def dummy_laplace(*args): def dummy_inverse_laplace(*args): """ - This function is called to create formal wrappers of inverse laplace + This function is called to create formal wrappers of inverse Laplace transforms that Maxima can't compute: EXAMPLES:: @@ -2078,7 +2106,7 @@ def dummy_inverse_laplace(*args): sage: from sage.calculus.calculus import dummy_inverse_laplace sage: s,t = var('s,t') sage: F = function('F') - sage: dummy_inverse_laplace(F(s),s,t) + sage: dummy_inverse_laplace(F(s), s, t) ilt(F(s), s, t) """ return _inverse_laplace(args[0], var(repr(args[1])), var(repr(args[2]))) @@ -2092,13 +2120,14 @@ def dummy_pochhammer(*args): sage: from sage.calculus.calculus import dummy_pochhammer sage: s,t = var('s,t') - sage: dummy_pochhammer(s,t) + sage: dummy_pochhammer(s, t) gamma(s + t)/gamma(s) """ x, y = args from sage.functions.gamma import gamma return gamma(x + y) / gamma(x) + ####################################################### # # Helper functions for printing latex expression @@ -2207,12 +2236,12 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): INPUT: - - ``x`` - a string + - ``x`` -- a string - - ``equals_sub`` - (default: False) if True, replace + - ``equals_sub`` -- (default: ``False``) if ``True``, replace '=' by '==' in self - - ``maxima`` - (default: the calculus package's + - ``maxima`` -- (default: the calculus package's copy of Maxima) the Maxima interpreter to use. EXAMPLES:: @@ -2251,10 +2280,10 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): True sage: sefms("x # 3") == SR(x != 3) True - sage: solve([x != 5], x) - [[x - 5 != 0]] + sage: solve([x != 5], x) in [[[x - 5 != 0]], [[x < 5], [5 < x]]] + True sage: solve([2*x==3, x != 5], x) - [[x == (3/2), (-7/2) != 0]] + [[x == (3/2)... Make sure that we don't accidentally pick up variables in the maxima namespace (:trac:`8734`):: @@ -2398,7 +2427,7 @@ def mapped_opts(v): INPUT: - - ``v`` - an object + - ``v`` -- an object OUTPUT: a string. @@ -2442,7 +2471,6 @@ def maxima_options(**kwds): syms_default = dict(syms_cur) - def _find_var(name, interface=None): """ Function to pass to Parser for constructing @@ -2532,13 +2560,13 @@ def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, pars INPUT: - - ``s`` - a string + - ``s`` -- a string - - ``syms`` - (default: {}) dictionary of - strings to be regarded as symbols or functions ; + - ``syms`` -- (default: ``{}``) dictionary of + strings to be regarded as symbols or functions; keys are pairs (string, number of arguments) - - ``accept_sequence`` - (default: False) controls whether + - ``accept_sequence`` -- (default: ``False``) controls whether to allow a (possibly nested) set of lists and tuples as input @@ -2546,23 +2574,25 @@ def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, pars EXAMPLES:: + sage: from sage.calculus.calculus import symbolic_expression_from_string sage: y = var('y') - sage: sage.calculus.calculus.symbolic_expression_from_string('[sin(0)*x^2,3*spam+e^pi]',syms={('spam',0):y},accept_sequence=True) + sage: symbolic_expression_from_string('[sin(0)*x^2,3*spam+e^pi]', + ....: syms={('spam',0): y}, accept_sequence=True) [0, 3*y + e^pi] TESTS: Check that the precision is preserved (:trac:`28814`):: - sage: sage.calculus.calculus.symbolic_expression_from_string(str(RealField(100)(1/3))) + sage: symbolic_expression_from_string(str(RealField(100)(1/3))) 0.3333333333333333333333333333 - sage: sage.calculus.calculus.symbolic_expression_from_string(str(RealField(100)(10^-500/3))) + sage: symbolic_expression_from_string(str(RealField(100)(10^-500/3))) 3.333333333333333333333333333e-501 The Giac interface uses a different parser (:trac:`30133`):: sage: from sage.calculus.calculus import SR_parser_giac - sage: sage.calculus.calculus.symbolic_expression_from_string(repr(giac(SR.var('e'))), parser=SR_parser_giac) + sage: symbolic_expression_from_string(repr(giac(SR.var('e'))), parser=SR_parser_giac) e """ if syms is None: diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index 1e5d87de635..afe63ccb954 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -60,7 +60,6 @@ - Robert Marik (10-2009) - Some bugfixes and enhancements - Miguel Marco (06-2014) - Tides desolvers - """ ########################################################################## @@ -76,17 +75,16 @@ import os from sage.interfaces.maxima import Maxima -from sage.misc.lazy_import import lazy_import -lazy_import("sage.plot.all", "line") -from sage.symbolic.expression import is_SymbolicEquation -from sage.symbolic.ring import SR, is_SymbolicVariable -from sage.calculus.functional import diff from sage.misc.functional import N from sage.rings.real_mpfr import RealField +from sage.structure.element import Expression + +from .functional import diff maxima = Maxima() + def fricas_desolve(de, dvar, ics, ivar): r""" Solve an ODE using FriCAS. @@ -119,9 +117,10 @@ def fricas_desolve(de, dvar, ics, ivar): if isinstance(y, dict): basis = y["basis"] particular = y["particular"] - return particular + sum(SR.var("_C"+str(i))*v for i, v in enumerate(basis)) - else: - return y + return particular + sum(SR.var("_C" + str(i)) * v + for i, v in enumerate(basis)) + return y + def fricas_desolve_system(des, dvars, ics, ivar): r""" @@ -164,8 +163,8 @@ def fricas_desolve_system(des, dvars, ics, ivar): y = fricas(des).solve(ops, ivar).sage() basis = y["basis"] particular = y["particular"] - pars = [SR.var("_C"+str(i)) for i in range(len(basis))] - solv = particular + sum(p*v for p, v in zip(pars, basis)) + pars = [SR.var("_C" + str(i)) for i in range(len(basis))] + solv = particular + sum(p * v for p, v in zip(pars, basis)) if ics is None: sols = solv @@ -177,6 +176,7 @@ def fricas_desolve_system(des, dvars, ics, ivar): return [dvar == sol for dvar, sol in zip(dvars, sols)] + def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False, algorithm="maxima"): r""" @@ -296,7 +296,7 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False, Clairaut equation: general and singular solutions:: sage: desolve(diff(y,x)^2+x*diff(y,x)-y==0,y,contrib_ode=True,show_method=True) - [[y(x) == _C^2 + _C*x, y(x) == -1/4*x^2], 'clairault'] + [[y(x) == _C^2 + _C*x, y(x) == -1/4*x^2], 'clairau...'] For equations involving more variables we specify an independent variable:: @@ -550,9 +550,9 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False, - Robert Bradshaw (10-2008) - Robert Marik (10-2009) """ - if is_SymbolicEquation(de): + if isinstance(de, Expression) and de.is_relational(): de = de.lhs() - de.rhs() - if is_SymbolicVariable(dvar): + if isinstance(dvar, Expression) and dvar.is_symbol(): raise ValueError("You have to declare dependent variable as a function evaluated at the independent variable, eg. y=function('y')(x)") # for backwards compatibility if isinstance(dvar, list): @@ -571,24 +571,24 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False, de00 = de._maxima_() P = de00.parent() - dvar_str=P(dvar.operator()).str() - ivar_str=P(ivar).str() + dvar_str = P(dvar.operator()).str() + ivar_str = P(ivar).str() de00 = de00.str() def sanitize_var(exprs): - return exprs.replace("'"+dvar_str+"("+ivar_str+")",dvar_str) + return exprs.replace("'" + dvar_str + "(" + ivar_str + ")", dvar_str) de0 = sanitize_var(de00) - ode_solver="ode2" - cmd="(TEMP:%s(%s,%s,%s), if TEMP=false then TEMP else substitute(%s=%s(%s),TEMP))"%(ode_solver,de0,dvar_str,ivar_str,dvar_str,dvar_str,ivar_str) + ode_solver = "ode2" + cmd = "(TEMP:%s(%s,%s,%s), if TEMP=false then TEMP else substitute(%s=%s(%s),TEMP))" % (ode_solver, de0, dvar_str, ivar_str, dvar_str, dvar_str, ivar_str) # we produce string like this # ode2('diff(y,x,2)+2*'diff(y,x,1)+y-cos(x),y(x),x) soln = P(cmd) if str(soln).strip() == 'false': if contrib_ode: - ode_solver="contrib_ode" + ode_solver = "contrib_ode" P("load('contrib_ode)") - cmd="(TEMP:%s(%s,%s,%s), if TEMP=false then TEMP else substitute(%s=%s(%s),TEMP))"%(ode_solver,de0,dvar_str,ivar_str,dvar_str,dvar_str,ivar_str) + cmd = "(TEMP:%s(%s,%s,%s), if TEMP=false then TEMP else substitute(%s=%s(%s),TEMP))" % (ode_solver, de0, dvar_str, ivar_str, dvar_str, dvar_str, ivar_str) # we produce string like this # (TEMP:contrib_ode(x*('diff(y,x,1))^2-(x*y+1)*'diff(y,x,1)+y,y,x), if TEMP=false then TEMP else substitute(y=y(x),TEMP)) soln = P(cmd) @@ -598,23 +598,23 @@ def sanitize_var(exprs): raise NotImplementedError("Maxima was unable to solve this ODE. Consider to set option contrib_ode to True.") if show_method: - maxima_method=P("method") + maxima_method = P("method") - if (ics is not None): - if not is_SymbolicEquation(soln.sage()): + if ics is not None: + if not (isinstance(soln.sage(), Expression) and soln.sage().is_relational()): if not show_method: - maxima_method=P("method") - raise NotImplementedError("Unable to use initial condition for this equation (%s)."%(str(maxima_method).strip())) + maxima_method = P("method") + raise NotImplementedError("Unable to use initial condition for this equation (%s)." % (str(maxima_method).strip())) if len(ics) == 2: - tempic=(ivar==ics[0])._maxima_().str() - tempic=tempic+","+(dvar==ics[1])._maxima_().str() - cmd="(TEMP:ic1(%s(%s,%s,%s),%s),substitute(%s=%s(%s),TEMP))"%(ode_solver,de00,dvar_str,ivar_str,tempic,dvar_str,dvar_str,ivar_str) - cmd=sanitize_var(cmd) + tempic = (ivar == ics[0])._maxima_().str() + tempic = tempic + "," + (dvar == ics[1])._maxima_().str() + cmd = "(TEMP:ic1(%s(%s,%s,%s),%s),substitute(%s=%s(%s),TEMP))" % (ode_solver, de00, dvar_str, ivar_str, tempic, dvar_str, dvar_str, ivar_str) + cmd = sanitize_var(cmd) # we produce string like this # (TEMP:ic2(ode2('diff(y,x,2)+2*'diff(y,x,1)+y-cos(x),y,x),x=0,y=3,'diff(y,x)=1),substitute(y=y(x),TEMP)) - soln=P(cmd) + soln = P(cmd) if len(ics) == 3: - #fixed ic2 command from Maxima - we have to ensure that %k1, %k2 do not depend on variables, should be removed when fixed in Maxima + # fixed ic2 command from Maxima - we have to ensure that %k1, %k2 do not depend on variables, should be removed when fixed in Maxima P("ic2_sage(soln,xa,ya,dya):=block([programmode:true,backsubst:true,singsolve:true,temp,%k2,%k1,TEMP_k], \ noteqn(xa), noteqn(ya), noteqn(dya), boundtest('%k1,%k1), boundtest('%k2,%k2), \ temp: lhs(soln) - rhs(soln), \ @@ -622,85 +622,41 @@ def sanitize_var(exprs): if not freeof(lhs(ya),TEMP_k) or not freeof(lhs(xa),TEMP_k) then return (false), \ temp: maplist(lambda([zz], subst(zz,soln)), TEMP_k), \ if length(temp)=1 then return(first(temp)) else return(temp))") - tempic=P(ivar==ics[0]).str() - tempic=tempic+","+P(dvar==ics[1]).str() - tempic=tempic+",'diff("+dvar_str+","+ivar_str+")="+P(ics[2]).str() - cmd="(TEMP:ic2_sage(%s(%s,%s,%s),%s),substitute(%s=%s(%s),TEMP))"%(ode_solver,de00,dvar_str,ivar_str,tempic,dvar_str,dvar_str,ivar_str) - cmd=sanitize_var(cmd) + tempic = P(ivar == ics[0]).str() + tempic += "," + P(dvar == ics[1]).str() + tempic += ",'diff(" + dvar_str + "," + ivar_str + ")=" + P(ics[2]).str() + cmd = "(TEMP:ic2_sage(%s(%s,%s,%s),%s),substitute(%s=%s(%s),TEMP))" % (ode_solver, de00, dvar_str, ivar_str, tempic, dvar_str, dvar_str, ivar_str) + cmd = sanitize_var(cmd) # we produce string like this # (TEMP:ic2(ode2('diff(y,x,2)+2*'diff(y,x,1)+y-cos(x),y,x),x=0,y=3,'diff(y,x)=1),substitute(y=y(x),TEMP)) - soln=P(cmd) + soln = P(cmd) if str(soln).strip() == 'false': raise NotImplementedError("Maxima was unable to solve this IVP. Remove the initial condition to get the general solution.") if len(ics) == 4: - #fixed bc2 command from Maxima - we have to ensure that %k1, %k2 do not depend on variables, should be removed when fixed in Maxima + # fixed bc2 command from Maxima - we have to ensure that %k1, %k2 do not depend on variables, should be removed when fixed in Maxima P("bc2_sage(soln,xa,ya,xb,yb):=block([programmode:true,backsubst:true,singsolve:true,temp,%k1,%k2,TEMP_k], \ noteqn(xa), noteqn(ya), noteqn(xb), noteqn(yb), boundtest('%k1,%k1), boundtest('%k2,%k2), \ TEMP_k:solve([subst([xa,ya],soln), subst([xb,yb],soln)], [%k1,%k2]), \ if not freeof(lhs(ya),TEMP_k) or not freeof(lhs(xa),TEMP_k) then return (false), \ temp: maplist(lambda([zz], subst(zz,soln)),TEMP_k), \ if length(temp)=1 then return(first(temp)) else return(temp))") - cmd="bc2_sage(%s(%s,%s,%s),%s,%s=%s,%s,%s=%s)"%(ode_solver,de00,dvar_str,ivar_str,P(ivar==ics[0]).str(),dvar_str,P(ics[1]).str(),P(ivar==ics[2]).str(),dvar_str,P(ics[3]).str()) - cmd="(TEMP:%s,substitute(%s=%s(%s),TEMP))"%(cmd,dvar_str,dvar_str,ivar_str) - cmd=sanitize_var(cmd) + cmd = "bc2_sage(%s(%s,%s,%s),%s,%s=%s,%s,%s=%s)" % (ode_solver, de00, dvar_str, ivar_str, P(ivar == ics[0]).str(), dvar_str, P(ics[1]).str(), P(ivar == ics[2]).str(), dvar_str, P(ics[3]).str()) + cmd = "(TEMP:%s,substitute(%s=%s(%s),TEMP))" % (cmd, dvar_str, dvar_str, ivar_str) + cmd = sanitize_var(cmd) # we produce string like this # (TEMP:bc2(ode2('diff(y,x,2)+2*'diff(y,x,1)+y-cos(x),y,x),x=0,y=3,x=%pi/2,y=2),substitute(y=y(x),TEMP)) - soln=P(cmd) + soln = P(cmd) if str(soln).strip() == 'false': raise NotImplementedError("Maxima was unable to solve this BVP. Remove the initial condition to get the general solution.") - soln=soln.sage() - if is_SymbolicEquation(soln) and soln.lhs() == dvar: + soln = soln.sage() + if isinstance(soln, Expression) and soln.is_relational() and soln.lhs() == dvar: # Remark: Here we do not check that the right hand side does not depend on dvar. # This probably will not happen for solutions obtained via ode2, anyway. soln = soln.rhs() if show_method: - return [soln,maxima_method.str()] - else: - return soln - - -#def desolve_laplace2(de,vars,ics=None): -## """ -## Solves an ODE using laplace transforms via maxima. Initial conditions -## are optional. - -## INPUT: -## de -- a lambda expression representing the ODE -## (eg, de = "diff(f(x),x,2)=diff(f(x),x)+sin(x)") -## vars -- a list of strings representing the variables -## (eg, vars = ["x","f"], if x is the independent -## variable and f is the dependent variable) -## ics -- a list of numbers representing initial conditions, -## with symbols allowed which are represented by strings -## (eg, f(0)=1, f'(0)=2 is ics = [0,1,2]) - -## EXAMPLES:: - -## sage: from sage.calculus.desolvers import desolve_laplace -## sage: x = var('x') -## sage: f = function('f')(x) -## sage: de = lambda y: diff(y,x,x) - 2*diff(y,x) + y -## sage: desolve_laplace(de(f(x)),[f,x]) -## #x*%e^x*(?%at('diff('f(x),x,1),x=0))-'f(0)*x*%e^x+'f(0)*%e^x -## sage: desolve_laplace(de(f(x)),[f,x],[0,1,2]) # IC option does not work -## #x*%e^x*(?%at('diff('f(x),x,1),x=0))-'f(0)*x*%e^x+'f(0)*%e^x - -## AUTHOR: David Joyner (1st version 1-2006, 8-2007) -## """ -# ######## this method seems reasonable but doesn't work for some reason -# name0 = vars[0]._repr_()[0:(len(vars[0]._repr_())-2-len(str(vars[1])))] -# name1 = str(vars[1]) -# #maxima("de:"+de+";") -# if ics is not None: -# ic0 = maxima("ic:"+str(vars[1])+"="+str(ics[0])) -# d = len(ics) -# for i in range(d-1): -# maxima(vars[0](vars[1])).diff(vars[1],i).atvalue(ic0,ics[i+1]) -# de0 = de._maxima_() -# #cmd = "desolve("+de+","+vars[1]+"("+vars[0]+"));" -# #return maxima.eval(cmd) -# return de0.desolve(vars[0]).rhs() + return [soln, maxima_method.str()] + return soln def desolve_laplace(de, dvar, ics=None, ivar=None): @@ -784,21 +740,21 @@ def desolve_laplace(de, dvar, ics=None, ivar=None): - Robert Marik (10-2009) """ - #This is the original code from David Joyner (inputs and outputs strings) - #maxima("de:"+de._repr_()+"=0;") - #if ics is not None: - # d = len(ics) - # for i in range(0,d-1): - # ic = "atvalue(diff("+vars[1]+"("+vars[0]+"),"+str(vars[0])+","+str(i)+"),"+str(vars[0])+"="+str(ics[0])+","+str(ics[1+i])+")" - # maxima(ic) + # This is the original code from David Joyner (inputs and outputs strings) + # maxima("de:"+de._repr_()+"=0;") + # if ics is not None: + # d = len(ics) + # for i in range(0,d-1): + # ic = "atvalue(diff("+vars[1]+"("+vars[0]+"),"+str(vars[0])+","+str(i)+"),"+str(vars[0])+"="+str(ics[0])+","+str(ics[1+i])+")" + # maxima(ic) # - #cmd = "desolve("+de._repr_()+","+vars[1]+"("+vars[0]+"));" - #return maxima(cmd).rhs()._maxima_init_() + # cmd = "desolve("+de._repr_()+","+vars[1]+"("+vars[0]+"));" + # return maxima(cmd).rhs()._maxima_init_() - ## verbatim copy from desolve - begin - if is_SymbolicEquation(de): + # verbatim copy from desolve - begin + if isinstance(de, Expression) and de.is_relational(): de = de.lhs() - de.rhs() - if is_SymbolicVariable(dvar): + if isinstance(dvar, Expression) and dvar.is_symbol(): raise ValueError("You have to declare dependent variable as a function evaluated at the independent variable, eg. y=function('y')(x)") # for backwards compatibility if isinstance(dvar, list): @@ -809,25 +765,27 @@ def desolve_laplace(de, dvar, ics=None, ivar=None): if len(ivars) != 1: raise ValueError("Unable to determine independent variable, please specify.") ivar = ivars[0] - ## verbatim copy from desolve - end + # verbatim copy from desolve - end dvar_str = str(dvar) - def sanitize_var(exprs): # 'y(x) -> y(x) - return exprs.replace("'"+dvar_str,dvar_str) - de0=de._maxima_() + def sanitize_var(exprs): + # 'y(x) -> y(x) + return exprs.replace("'" + dvar_str, dvar_str) + + de0 = de._maxima_() P = de0.parent() i = dvar_str.find('(') - dvar_str = dvar_str[:i+1] + '_SAGE_VAR_' + dvar_str[i+1:] - cmd = sanitize_var("desolve("+de0.str()+","+dvar_str+")") - soln=P(cmd).rhs() + dvar_str = dvar_str[:i + 1] + '_SAGE_VAR_' + dvar_str[i + 1:] + cmd = sanitize_var("desolve(" + de0.str() + "," + dvar_str + ")") + soln = P(cmd).rhs() if str(soln).strip() == 'false': raise NotImplementedError("Maxima was unable to solve this ODE.") - soln=soln.sage() + soln = soln.sage() if ics is not None: d = len(ics) - for i in range(0,d-1): - soln=eval('soln.substitute(diff(dvar,ivar,i)('+str(ivar)+'=ics[0])==ics[i+1])') + for i in range(d - 1): + soln = eval('soln.substitute(diff(dvar,ivar,i)(' + str(ivar) + '=ics[0])==ics[i+1])') return soln @@ -916,8 +874,8 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"): :: - sage: P1 = plot([solx,soly], (0,1)) - sage: P2 = parametric_plot((solx,soly), (0,1)) + sage: P1 = plot([solx,soly], (0,1)) # needs sage.plot + sage: P2 = parametric_plot((solx,soly), (0,1)) # needs sage.plot Now type ``show(P1)``, ``show(P2)`` to view these plots. @@ -934,7 +892,8 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"): sage: desolve_system([de1, de2], [x1, x2], ics=[1,1], ivar=t) Traceback (most recent call last): ... - ValueError: Initial conditions aren't complete: number of vars is different from number of dependent variables. Got ics = [1, 1], vars = [x1(t), x2(t)] + ValueError: Initial conditions aren't complete: number of vars is different + from number of dependent variables. Got ics = [1, 1], vars = [x1(t), x2(t)] Check that :trac:`9825` is fixed:: @@ -959,7 +918,7 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"): return desolve_laplace(des[0], vars[0], ics=ics, ivar=ivar) ivars = set([]) for i, de in enumerate(des): - if not is_SymbolicEquation(de): + if not (isinstance(de, Expression) and de.is_relational()): des[i] = de == 0 ivars = ivars.union(set(de.variables())) if ivar is None: @@ -977,7 +936,7 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"): if ics is not None: ivar_ic = ics[0] for dvar, ic in zip(dvars, ics[1:]): - dvar.atvalue(ivar==ivar_ic, ic) + dvar.atvalue(ivar == ivar_ic, ic) soln = dvars[0].parent().desolve(des, dvars) if str(soln).strip() == 'false': raise NotImplementedError("Maxima was unable to solve this system.") @@ -987,11 +946,11 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"): if ics is not None: ivar_ic = ics[0] for dvar, ic in zip(dvars, ics[:1]): - dvar.atvalue(ivar==ivar_ic, dvar) + dvar.atvalue(ivar == ivar_ic, dvar) return soln -def eulers_method(f,x0,y0,h,x1,algorithm="table"): +def eulers_method(f, x0, y0, h, x1, algorithm="table"): r""" This implements Euler's method for finding numerically the solution of the 1st order ODE `y' = f(x,y)`, `y(a)=c`. The ``x`` @@ -1055,31 +1014,31 @@ def eulers_method(f,x0,y0,h,x1,algorithm="table"): :: sage: pts = eulers_method(5*x+y-5,0,1,1/2,1,algorithm="none") - sage: P1 = list_plot(pts) - sage: P2 = line(pts) - sage: (P1+P2).show() + sage: P1 = list_plot(pts) # needs sage.plot + sage: P2 = line(pts) # needs sage.plot + sage: (P1 + P2).show() # needs sage.plot AUTHORS: - David Joyner """ - if algorithm=="table": - print("%10s %20s %25s"%("x","y","h*f(x,y)")) - n=int((1.0)*(x1-x0)/h) + if algorithm == "table": + print("%10s %20s %25s" % ("x", "y", "h*f(x,y)")) + n = int((1.0) * (x1 - x0) / h) x00 = x0 y00 = y0 - soln = [[x00,y00]] - for i in range(n+1): - if algorithm=="table": - print("%10r %20r %20r"%(x00,y00,h*f(x00,y00))) - y00 = y00+h*f(x00,y00) - x00=x00+h - soln.append([x00,y00]) - if algorithm!="table": + soln = [[x00, y00]] + for i in range(n + 1): + if algorithm == "table": + print("%10r %20r %20r" % (x00, y00, h * f(x00, y00))) + y00 = y00 + h * f(x00, y00) + x00 = x00 + h + soln.append([x00, y00]) + if algorithm != "table": return soln -def eulers_method_2x2(f,g, t0, x0, y0, h, t1,algorithm="table"): +def eulers_method_2x2(f, g, t0, x0, y0, h, t1, algorithm="table"): r""" This implements Euler's method for finding numerically the solution of the 1st order system of two ODEs @@ -1163,25 +1122,26 @@ def eulers_method_2x2(f,g, t0, x0, y0, h, t1,algorithm="table"): - David Joyner """ - if algorithm=="table": - print("%10s %20s %25s %20s %20s"%("t", "x","h*f(t,x,y)","y", "h*g(t,x,y)")) - n = int((1.0)*(t1-t0)/h) + if algorithm == "table": + print("%10s %20s %25s %20s %20s" % ("t", "x", "h*f(t,x,y)", "y", "h*g(t,x,y)")) + n = int((1.0) * (t1 - t0) / h) t00 = t0 x00 = x0 y00 = y0 soln = [[t00, x00, y00]] - for i in range(n+1): - if algorithm=="table": - print("%10r %20r %25r %20r %20r"%(t00,x00,h*f(t00,x00,y00),y00,h*g(t00,x00,y00))) - x01 = x00 + h*f(t00,x00,y00) - y00 = y00 + h*g(t00,x00,y00) + for i in range(n + 1): + if algorithm == "table": + print("%10r %20r %25r %20r %20r" % (t00, x00, h * f(t00, x00, y00), y00, h * g(t00, x00, y00))) + x01 = x00 + h * f(t00, x00, y00) + y00 = y00 + h * g(t00, x00, y00) x00 = x01 t00 = t00 + h - soln.append([t00,x00,y00]) - if algorithm!="table": + soln.append([t00, x00, y00]) + if algorithm != "table": return soln -def eulers_method_2x2_plot(f,g, t0, x0, y0, h, t1): + +def eulers_method_2x2_plot(f, g, t0, x0, y0, h, t1): r""" Plot solution of ODE. @@ -1204,9 +1164,11 @@ def eulers_method_2x2_plot(f,g, t0, x0, y0, h, t1): sage: from sage.calculus.desolvers import eulers_method_2x2_plot sage: f = lambda z : z[2]; g = lambda z : -sin(z[1]) - sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) + sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) # needs sage.plot """ - n = int((1.0)*(t1-t0)/h) + from sage.plot.line import line + + n = int((1.0) * (t1 - t0) / h) t00 = t0 x00 = x0 y00 = y0 @@ -1222,7 +1184,7 @@ def eulers_method_2x2_plot(f,g, t0, x0, y0, h, t1): return [Q1, Q2] -def desolve_rk4_determine_bounds(ics,end_points=None): +def desolve_rk4_determine_bounds(ics, end_points=None): """ Used to determine bounds for numerical integration. @@ -1324,7 +1286,7 @@ def desolve_rk4(de, dvar, ics=None, ivar=None, end_points=None, step=0.1, output sage: x,y = var('x,y') sage: desolve_rk4(x*y*(2-y),y,ics=[0,1],end_points=1,step=0.5) - [[0, 1], [0.5, 1.12419127424558], [1.0, 1.461590162288825]] + [[0, 1], [0.5, 1.12419127424558], [1.0, 1.46159016228882...]] Variant 1 for input - we can pass ODE in the form used by desolve function In this example we integrate backwards, since @@ -1332,7 +1294,7 @@ def desolve_rk4(de, dvar, ics=None, ivar=None, end_points=None, step=0.1, output sage: y = function('y')(x) sage: desolve_rk4(diff(y,x)+y*(y-1) == x-2,y,ics=[1,1],step=0.5, end_points=0) - [[0.0, 8.904257108962112], [0.5, 1.909327945361535], [1, 1]] + [[0.0, 8.904257108962112], [0.5, 1.90932794536153...], [1, 1]] Here we show how to plot simple pictures. For more advanced applications use list_plot instead. To see the resulting picture @@ -1364,26 +1326,26 @@ def desolve_rk4(de, dvar, ics=None, ivar=None, end_points=None, step=0.1, output raise ValueError("Unable to determine independent variable, please specify.") ivar = ivars[0] - step=abs(step) + step = abs(step) def desolve_rk4_inner(de, dvar): - de0=de._maxima_() + de0 = de._maxima_() maxima("load('dynamics)") - lower_bound,upper_bound=desolve_rk4_determine_bounds(ics,end_points) - sol_1, sol_2 = [],[] - if lower_bound<ics[0]: - cmd="rk(%s,%s,%s,[%s,%s,%s,%s])\ - "%(de0.str(),'_SAGE_VAR_'+str(dvar),str(ics[1]),'_SAGE_VAR_'+str(ivar),str(ics[0]),lower_bound,-step) - sol_1=maxima(cmd).sage() + lower_bound, upper_bound = desolve_rk4_determine_bounds(ics, end_points) + sol_1, sol_2 = [], [] + if lower_bound < ics[0]: + cmd = "rk(%s,%s,%s,[%s,%s,%s,%s])\ + " % (de0.str(), '_SAGE_VAR_' + str(dvar), str(ics[1]), '_SAGE_VAR_' + str(ivar), str(ics[0]), lower_bound, -step) + sol_1 = maxima(cmd).sage() sol_1.pop(0) sol_1.reverse() - if upper_bound>ics[0]: - cmd="rk(%s,%s,%s,[%s,%s,%s,%s])\ - "%(de0.str(),'_SAGE_VAR_'+str(dvar),str(ics[1]),'_SAGE_VAR_'+str(ivar),str(ics[0]),upper_bound,step) - sol_2=maxima(cmd).sage() + if upper_bound > ics[0]: + cmd = "rk(%s,%s,%s,[%s,%s,%s,%s])\ + " % (de0.str(), '_SAGE_VAR_' + str(dvar), str(ics[1]), '_SAGE_VAR_' + str(ivar), str(ics[0]), upper_bound, step) + sol_2 = maxima(cmd).sage() sol_2.pop(0) - sol=sol_1 - sol.extend([[ics[0],ics[1]]]) + sol = sol_1 + sol.extend([[ics[0], ics[1]]]) sol.extend(sol_2) if output == 'list': @@ -1407,23 +1369,24 @@ def desolve_rk4_inner(de, dvar): YMAX = t if t < YMIN: YMIN = t - return plot_slope_field(de, (ivar,XMIN,XMAX), (dvar,YMIN,YMAX))+R + return plot_slope_field(de, (ivar, XMIN, XMAX), (dvar, YMIN, YMAX)) + R - if not is_SymbolicVariable(dvar): + if not (isinstance(dvar, Expression) and dvar.is_symbol()): from sage.symbolic.ring import SR from sage.calculus.all import diff from sage.symbolic.relation import solve - if is_SymbolicEquation(de): + if isinstance(de, Expression) and de.is_relational(): de = de.lhs() - de.rhs() # consider to add warning if the solution is not unique - de=solve(de,diff(dvar,ivar),solution_dict=True) + de = solve(de, diff(dvar, ivar), solution_dict=True) if len(de) != 1: raise NotImplementedError("Sorry, cannot find explicit formula for right-hand side of the ODE.") with SR.temp_var() as dummy_dvar: - return desolve_rk4_inner(de[0][diff(dvar,ivar)].subs({dvar:dummy_dvar}), dummy_dvar) + return desolve_rk4_inner(de[0][diff(dvar, ivar)].subs({dvar: dummy_dvar}), dummy_dvar) else: return desolve_rk4_inner(de, dvar) + def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1): r""" Solve numerically a system of first-order ordinary differential @@ -1468,13 +1431,14 @@ def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1 Lotka Volterra system:: sage: from sage.calculus.desolvers import desolve_system_rk4 - sage: x,y,t=var('x y t') - sage: P=desolve_system_rk4([x*(1-y),-y*(1-x)],[x,y],ics=[0,0.5,2],ivar=t,end_points=20) - sage: Q=[ [i,j] for i,j,k in P] - sage: LP=list_plot(Q) + sage: x,y,t = var('x y t') + sage: P = desolve_system_rk4([x*(1-y),-y*(1-x)], [x,y], ics=[0,0.5,2], + ....: ivar=t, end_points=20) + sage: Q = [[i,j] for i,j,k in P] + sage: LP = list_plot(Q) # needs sage.plot - sage: Q=[ [j,k] for i,j,k in P] - sage: LP=list_plot(Q) + sage: Q = [[j,k] for i,j,k in P] + sage: LP = list_plot(Q) # needs sage.plot ALGORITHM: @@ -1504,34 +1468,35 @@ def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1 desstr = "[" + ",".join(dess) + "]" varss = [varsi._maxima_().str() for varsi in vars] varstr = "[" + ",".join(varss) + "]" - x0=ics[0] - icss = [ics[i]._maxima_().str() for i in range(1,len(ics))] + x0 = ics[0] + icss = [ics[i]._maxima_().str() for i in range(1, len(ics))] icstr = "[" + ",".join(icss) + "]" - step=abs(step) + step = abs(step) maxima("load('dynamics)") - lower_bound,upper_bound=desolve_rk4_determine_bounds(ics,end_points) - sol_1, sol_2 = [],[] - if lower_bound<ics[0]: - cmd="rk(%s,%s,%s,[%s,%s,%s,%s])\ - "%(desstr,varstr,icstr,'_SAGE_VAR_'+str(ivar),str(x0),lower_bound,-step) - sol_1=maxima(cmd).sage() + lower_bound, upper_bound = desolve_rk4_determine_bounds(ics, end_points) + sol_1, sol_2 = [], [] + if lower_bound < ics[0]: + cmd = "rk(%s,%s,%s,[%s,%s,%s,%s])\ + " % (desstr, varstr, icstr, '_SAGE_VAR_' + str(ivar), str(x0), lower_bound, -step) + sol_1 = maxima(cmd).sage() sol_1.pop(0) sol_1.reverse() - if upper_bound>ics[0]: - cmd="rk(%s,%s,%s,[%s,%s,%s,%s])\ - "%(desstr,varstr,icstr,'_SAGE_VAR_'+str(ivar),str(x0),upper_bound,step) - sol_2=maxima(cmd).sage() + if upper_bound > ics[0]: + cmd = "rk(%s,%s,%s,[%s,%s,%s,%s])\ + " % (desstr, varstr, icstr, '_SAGE_VAR_' + str(ivar), str(x0), upper_bound, step) + sol_2 = maxima(cmd).sage() sol_2.pop(0) - sol=sol_1 + sol = sol_1 sol.append(ics) sol.extend(sol_2) return sol -def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() -, rtol=None, atol=None, tcrit=None, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0 -, mxstep=0, mxhnil=0, mxordn=12, mxords=5, printmessg=0): + +def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=(), + rtol=None, atol=None, tcrit=None, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0, + mxstep=0, mxhnil=0, mxordn=12, mxords=5, printmessg=0): r""" Solve numerically a system of first-order ordinary differential equations using ``odeint`` from scipy.integrate module. @@ -1607,49 +1572,52 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() Lotka Volterra Equations:: sage: from sage.calculus.desolvers import desolve_odeint - sage: x,y=var('x,y') - sage: f=[x*(1-y),-y*(1-x)] - sage: sol=desolve_odeint(f,[0.5,2],srange(0,10,0.1),[x,y]) - sage: p=line(zip(sol[:,0],sol[:,1])) - sage: p.show() + sage: x,y = var('x,y') + sage: f = [x*(1-y), -y*(1-x)] + sage: sol = desolve_odeint(f, [0.5,2], srange(0,10,0.1), [x,y]) # needs scipy + sage: p = line(zip(sol[:,0],sol[:,1])) # needs scipy sage.plot + sage: p.show() # needs scipy sage.plot Lorenz Equations:: - sage: x,y,z=var('x,y,z') + sage: x,y,z = var('x,y,z') sage: # Next we define the parameters - sage: sigma=10 - sage: rho=28 - sage: beta=8/3 + sage: sigma = 10 + sage: rho = 28 + sage: beta = 8/3 sage: # The Lorenz equations - sage: lorenz=[sigma*(y-x),x*(rho-z)-y,x*y-beta*z] + sage: lorenz = [sigma*(y-x),x*(rho-z)-y,x*y-beta*z] sage: # Time and initial conditions - sage: times=srange(0,50.05,0.05) - sage: ics=[0,1,1] - sage: sol=desolve_odeint(lorenz,ics,times,[x,y,z],rtol=1e-13,atol=1e-14) + sage: times = srange(0,50.05,0.05) + sage: ics = [0,1,1] + sage: sol = desolve_odeint(lorenz, ics, times, [x,y,z], # needs scipy + ....: rtol=1e-13, atol=1e-14) One-dimensional stiff system:: - sage: y= var('y') - sage: epsilon=0.01 - sage: f=y^2*(1-y) - sage: ic=epsilon - sage: t=srange(0,2/epsilon,1) - sage: sol=desolve_odeint(f,ic,t,y,rtol=1e-9,atol=1e-10,compute_jac=True) - sage: p=points(zip(t,sol)) - sage: p.show() + sage: y = var('y') + sage: epsilon = 0.01 + sage: f = y^2*(1-y) + sage: ic = epsilon + sage: t = srange(0,2/epsilon,1) + sage: sol = desolve_odeint(f, ic, t, y, # needs scipy + ....: rtol=1e-9, atol=1e-10, compute_jac=True) + sage: p = points(zip(t,sol[:,0])) # needs scipy sage.plot + sage: p.show() # needs scipy sage.plot Another stiff system with some optional parameters with no default value:: - sage: y1,y2,y3=var('y1,y2,y3') - sage: f1=77.27*(y2+y1*(1-8.375*1e-6*y1-y2)) - sage: f2=1/77.27*(y3-(1+y1)*y2) - sage: f3=0.16*(y1-y3) - sage: f=[f1,f2,f3] - sage: ci=[0.2,0.4,0.7] - sage: t=srange(0,10,0.01) - sage: v=[y1,y2,y3] - sage: sol=desolve_odeint(f,ci,t,v,rtol=1e-3,atol=1e-4,h0=0.1,hmax=1,hmin=1e-4,mxstep=1000,mxords=17) + sage: y1,y2,y3 = var('y1,y2,y3') + sage: f1 = 77.27*(y2+y1*(1-8.375*1e-6*y1-y2)) + sage: f2 = 1/77.27*(y3-(1+y1)*y2) + sage: f3 = 0.16*(y1-y3) + sage: f = [f1,f2,f3] + sage: ci = [0.2,0.4,0.7] + sage: t = srange(0,10,0.01) + sage: v = [y1,y2,y3] + sage: sol = desolve_odeint(f, ci, t, v, rtol=1e-3, atol=1e-4, # needs scipy + ....: h0=0.1, hmax=1, hmin=1e-4, mxstep=1000, mxords=17) AUTHOR: @@ -1674,7 +1642,7 @@ def desolve_odeint_inner(ivar): J = fast_float(J, dvar, ivar) def Dfun(y, t): - return [J(y, t)] + return [J(y.item(), t)] # n-dimensional systems: else: @@ -1701,12 +1669,11 @@ def Dfun(y, t): v.append(t) return [[element(*v) for element in row] for row in J] - sol=odeint(func, ics, times, args=args, Dfun=Dfun, rtol=rtol, atol=atol, - tcrit=tcrit, h0=h0, hmax=hmax, hmin=hmin, ixpr=ixpr, mxstep=mxstep, - mxhnil=mxhnil, mxordn=mxordn, mxords=mxords, printmessg=printmessg) - return sol + return odeint(func, ics, times, args=args, Dfun=Dfun, rtol=rtol, atol=atol, + tcrit=tcrit, h0=h0, hmax=hmax, hmin=hmin, ixpr=ixpr, mxstep=mxstep, + mxhnil=mxhnil, mxordn=mxordn, mxords=mxords, printmessg=printmessg) - if is_SymbolicVariable(dvars): + if isinstance(dvars, Expression) and dvars.is_symbol(): dvars = [dvars] if not isinstance(des, (list, tuple)): @@ -1716,16 +1683,18 @@ def Dfun(y, t): all_vars = set().union(*[de.variables() for de in des]) ivars = all_vars - set(dvars) - if len(ivars)==1: + if len(ivars) == 1: return desolve_odeint_inner(next(iter(ivars))) elif not ivars: + from sage.symbolic.ring import SR with SR.temp_var() as ivar: return desolve_odeint_inner(ivar) else: raise ValueError("Unable to determine independent variable, please specify.") return desolve_odeint_inner(ivar) -def desolve_mintides(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-16): + +def desolve_mintides(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-16): r""" Solve numerically a system of first order differential equations using the taylor series integrator implemented in mintides. @@ -1796,27 +1765,27 @@ def desolve_mintides(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-16) from sage.misc.temporary_file import tmp_dir tempdir = tmp_dir() intfile = os.path.join(tempdir, 'integrator.c') - drfile = os.path.join(tempdir ,'driver.c') + drfile = os.path.join(tempdir, 'driver.c') fileoutput = os.path.join(tempdir, 'output') runmefile = os.path.join(tempdir, 'runme') - genfiles_mintides(intfile, drfile, f, [N(_) for _ in ics], N(initial), N(final), N(delta), N(tolrel), - N(tolabs), fileoutput) + genfiles_mintides(intfile, drfile, f, [N(_) for _ in ics], + N(initial), N(final), N(delta), N(tolrel), + N(tolabs), fileoutput) subprocess.check_call('gcc -o ' + runmefile + ' ' + os.path.join(tempdir, '*.c ') + - os.path.join('$SAGE_LOCAL','lib','libTIDES.a') + ' $LDFLAGS ' - + os.path.join('-L$SAGE_LOCAL','lib ') +' -lm -O2 ' + - os.path.join('-I$SAGE_LOCAL','include '), - shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - subprocess.check_call(os.path.join(tempdir, 'runme'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - outfile = open(fileoutput) - res = outfile.readlines() - outfile.close() + os.path.join('$SAGE_LOCAL', 'lib', 'libTIDES.a') + ' $LDFLAGS ' + + os.path.join('-L$SAGE_LOCAL', 'lib ') + ' -lm -O2 ' + + os.path.join('-I$SAGE_LOCAL', 'include '), + shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + subprocess.check_call(os.path.join(tempdir, 'runme'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + with open(fileoutput) as outfile: + res = outfile.readlines() for i in range(len(res)): res[i] = [RealField()(_) for _ in res[i].split(' ') if len(_) > 2] shutil.rmtree(tempdir) return res -def desolve_tides_mpfr(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-16, digits=50): +def desolve_tides_mpfr(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-16, digits=50): r""" Solve numerically a system of first order differential equations using the taylor series integrator in arbitrary precision implemented in tides. @@ -1900,17 +1869,17 @@ def desolve_tides_mpfr(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-1 fileoutput = os.path.join(tempdir, 'output') runmefile = os.path.join(tempdir, 'runme') genfiles_mpfr(intfile, drfile, f, ics, initial, final, delta, [], [], - digits, tolrel, tolabs, fileoutput) + digits, tolrel, tolabs, fileoutput) subprocess.check_call('gcc -o ' + runmefile + ' ' + os.path.join(tempdir, '*.c ') + - os.path.join('$SAGE_LOCAL','lib','libTIDES.a') + ' $LDFLAGS ' - + os.path.join('-L$SAGE_LOCAL','lib ') + '-lmpfr -lgmp -lm -O2 -w ' + - os.path.join('-I$SAGE_LOCAL','include ') , - shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - subprocess.check_call(os.path.join(tempdir, 'runme'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - outfile = open(fileoutput) - res = outfile.readlines() - outfile.close() + os.path.join('$SAGE_LOCAL', 'lib', 'libTIDES.a') + ' $LDFLAGS ' + + os.path.join('-L$SAGE_LOCAL', 'lib ') + '-lmpfr -lgmp -lm -O2 -w ' + + os.path.join('-I$SAGE_LOCAL', 'include '), + shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + subprocess.check_call(os.path.join(tempdir, 'runme'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + with open(fileoutput) as outfile: + res = outfile.readlines() for i in range(len(res)): - res[i] = [RealField(ceil(digits*log(10,2)))(_) for _ in res[i].split(' ') if len(_) > 2] + res[i] = [RealField(ceil(digits * log(10, 2)))(piece) + for piece in res[i].split(' ') if len(piece) > 2] shutil.rmtree(tempdir) return res diff --git a/src/sage/calculus/functional.py b/src/sage/calculus/functional.py index 0654118d257..03ea8bbd294 100644 --- a/src/sage/calculus/functional.py +++ b/src/sage/calculus/functional.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Functional notation support for common calculus methods @@ -25,29 +26,46 @@ sage: expand((x - a)^3) -a^3 + 3*a^2*x - 3*a*x^2 + x^3 """ +from sage.structure.element import Expression -from .calculus import SR -from sage.symbolic.expression import Expression -def simplify(f): +def simplify(f, algorithm="maxima", **kwds): r""" Simplify the expression `f`. - EXAMPLES: We simplify the expression `i + x - x`. + See the documentation of the + :meth:`~sage.symbolic.expression.Expression.simplify` method of symbolic + expressions for details on options. - :: + EXAMPLES: + + We simplify the expression `i + x - x`:: sage: f = I + x - x; simplify(f) I In fact, printing `f` yields the same thing - i.e., the simplified form. + + Some simplifications are algorithm-specific:: + + sage: x, t = var("x, t") + sage: ex = 1/2*I*x + 1/2*I*sqrt(x^2 - 1) + 1/2/(I*x + I*sqrt(x^2 - 1)) + sage: simplify(ex) + 1/2*I*x + 1/2*I*sqrt(x^2 - 1) + 1/(2*I*x + 2*I*sqrt(x^2 - 1)) + sage: simplify(ex, algorithm="giac") + I*sqrt(x^2 - 1) """ + try: + return f.simplify(algorithm=algorithm, **kwds) + except (TypeError, AttributeError): + pass try: return f.simplify() except AttributeError: return f + def derivative(f, *args, **kwds): r""" The derivative of `f`. @@ -147,11 +165,14 @@ def derivative(f, *args, **kwds): except AttributeError: pass if not isinstance(f, Expression): + from sage.symbolic.ring import SR f = SR(f) return f.derivative(*args, **kwds) + diff = derivative + def integral(f, *args, **kwds): r""" The integral of `f`. @@ -224,9 +245,7 @@ def integral(f, *args, **kwds): Sage is now (:trac:`27958`) able to compute the following integral:: - sage: result = integral(exp(-x^2)*log(x), x) - ... - sage: result + sage: integral(exp(-x^2)*log(x), x) # long time 1/2*sqrt(pi)*erf(x)*log(x) - x*hypergeometric((1/2, 1/2), (3/2, 3/2), -x^2) and its value:: @@ -296,11 +315,14 @@ def integral(f, *args, **kwds): pass if not isinstance(f, Expression): + from sage.symbolic.ring import SR f = SR(f) return f.integral(*args, **kwds) + integrate = integral + def limit(f, dir=None, taylor=False, **argv): r""" Return the limit as the variable `v` approaches `a` @@ -349,11 +371,14 @@ def limit(f, dir=None, taylor=False, **argv): -limit((erf(x) - 1)*e^(x^2), x, +Infinity) """ if not isinstance(f, Expression): + from sage.symbolic.ring import SR f = SR(f) return f.limit(dir=dir, taylor=taylor, **argv) + lim = limit + def taylor(f, *args): """ Expands self in a truncated Taylor or Laurent series in the @@ -392,9 +417,11 @@ def taylor(f, *args): (x - 1)*(y + 1)^3 - 3*(x - 1)*(y + 1)^2 + (y + 1)^3 + 3*(x - 1)*(y + 1) - 3*(y + 1)^2 - x + 3*y + 3 """ if not isinstance(f, Expression): + from sage.symbolic.ring import SR f = SR(f) return f.taylor(*args) + def expand(x, *args, **kwds): """ EXAMPLES:: diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index 6a06f755101..11a23aac323 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -1,10 +1,12 @@ +# sage.doctest: needs sage.symbolic r""" Calculus functions """ -from sage.matrix.constructor import matrix -from sage.structure.element import is_Matrix -from sage.structure.element import is_Vector -from sage.symbolic.ring import is_SymbolicVariable +from sage.misc.lazy_import import lazy_import +from sage.structure.element import is_Matrix, is_Vector, Expression + +lazy_import('sage.matrix.constructor', 'matrix') + from .functional import diff @@ -82,7 +84,7 @@ def wronskian(*args): # a 1x1 Wronskian is just its argument return args[0] else: - if is_SymbolicVariable(args[-1]): + if isinstance(args[-1], Expression) and args[-1].is_symbol(): # if last argument is a variable, peel it off and # differentiate the other args v = args[-1] @@ -135,9 +137,9 @@ def jacobian(functions, variables): [ x^3*cos(y) 3*x^2*sin(y)] [ cos(x)*cos(y) -sin(x)*sin(y)] [ 0 e^x] - """ - if is_Matrix(functions) and (functions.nrows()==1 or functions.ncols()==1): + if is_Matrix(functions) and (functions.nrows() == 1 + or functions.ncols() == 1): functions = functions.list() elif not (isinstance(functions, (tuple, list)) or is_Vector(functions)): functions = [functions] diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index f2125bbc2d7..19b2dc2e4c8 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Numerical Integration @@ -457,6 +458,11 @@ def monte_carlo_integral(func, xl, xu, size_t calls, algorithm='plain', * 'vegas' -- The VEGAS algorithm of Lepage is based on importance sampling. + OUTPUT: + + A tuple whose first component is the approximated integral and whose second + component is an error estimate. + EXAMPLES:: sage: x, y = SR.var('x,y') diff --git a/src/sage/calculus/interpolation.pyx b/src/sage/calculus/interpolation.pyx index e703f78d7c0..83bc83d1797 100644 --- a/src/sage/calculus/interpolation.pyx +++ b/src/sage/calculus/interpolation.pyx @@ -55,9 +55,9 @@ cdef class Spline: This example is in the GSL documentation:: - sage: v = [(i + sin(i)/2, i+cos(i^2)) for i in range(10)] + sage: v = [(i + RDF(i).sin()/2, i + RDF(i^2).cos()) for i in range(10)] sage: s = spline(v) - sage: show(point(v) + plot(s,0,9, hue=.8)) + sage: show(point(v) + plot(s,0,9, hue=.8)) # needs sage.plot We compute the area underneath the spline:: @@ -77,13 +77,13 @@ cdef class Spline: We compute the first and second-order derivatives at a few points:: sage: s.derivative(5) - -0.16230085261803... + -0.1623008526180... sage: s.derivative(6) - 0.20997986285714... + 0.2099798628571... sage: s.derivative(5, order=2) - -3.08747074561380... + -3.0874707456138... sage: s.derivative(6, order=2) - 2.61876848274853... + 2.6187684827485... Only the first two derivatives are supported:: @@ -92,7 +92,7 @@ cdef class Spline: ... ValueError: Order of derivative must be 1 or 2. """ - def __init__(self, v=[]): + def __init__(self, v=None): """ EXAMPLES:: @@ -101,7 +101,7 @@ cdef class Spline: sage: type(S) <class 'sage.calculus.interpolation.Spline'> """ - self.v = list(v) + self.v = [] if v is None else list(v) self.started = 0 def __dealloc__(self): @@ -118,7 +118,7 @@ cdef class Spline: Replace `0`-th point, which changes the spline:: - sage: S[0]=(0,1); S + sage: S[0] = (0,1); S [(0, 1), (2, 3), (4, 5)] sage: S(1.5) 2.5 @@ -135,8 +135,8 @@ cdef class Spline: if i < len(self.v): self.v[i] = xy else: - for j from len(self.v) <= j <= i: - self.v.append((0,0)) + for j in range(len(self.v), i + 1): + self.v.append((0, 0)) self.v[i] = xy self.stop_interp() @@ -262,7 +262,7 @@ cdef class Spline: raise MemoryError cdef int i - for i from 0 <= i < n: + for i in range(n): self.x[i] = v[i][0] self.y[i] = v[i][1] diff --git a/src/sage/calculus/interpolators.pyx b/src/sage/calculus/interpolators.pyx index 662a1fd0ce3..fb057f0fc2e 100644 --- a/src/sage/calculus/interpolators.pyx +++ b/src/sage/calculus/interpolators.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs numpy """ Complex Interpolation @@ -29,6 +30,7 @@ cimport numpy as np from math import pi cdef double TWOPI = 2*pi + def polygon_spline(pts): """ Creates a polygon from a set of complex or `(x,y)` points. The polygon @@ -48,9 +50,10 @@ def polygon_spline(pts): sage: ps = polygon_spline(pts) sage: fx = lambda x: ps.value(x).real sage: fy = lambda x: ps.value(x).imag - sage: show(parametric_plot((fx, fy), (0, 2*pi))) - sage: m = Riemann_Map([lambda x: ps.value(real(x))], [lambda x: ps.derivative(real(x))],0) - sage: show(m.plot_colored() + m.plot_spiderweb()) + sage: show(parametric_plot((fx, fy), (0, 2*pi))) # needs sage.plot + sage: m = Riemann_Map([lambda x: ps.value(real(x))], + ....: [lambda x: ps.derivative(real(x))], 0) + sage: show(m.plot_colored() + m.plot_spiderweb()) # needs sage.plot Polygon approximation of an circle:: @@ -61,6 +64,7 @@ def polygon_spline(pts): """ return PSpline(pts) + cdef class PSpline: """ A ``CCSpline`` object contains a polygon interpolation of a figure @@ -117,7 +121,7 @@ cdef class PSpline: sage: ps = polygon_spline(pts) sage: ps.value(.5) (-0.363380227632...-1j) - sage: ps.value(0) - ps.value(2*pi) + sage: ps.value(0) - ps.value(2*RDF.pi()) 0j sage: ps.value(10) (0.26760455264...+1j) @@ -150,6 +154,7 @@ cdef class PSpline: sage: ps = polygon_spline(pts) sage: ps.derivative(1 / 3) (1.27323954473...+0j) + sage: from math import pi sage: ps.derivative(0) - ps.derivative(2*pi) 0j sage: ps.derivative(10) @@ -160,6 +165,7 @@ cdef class PSpline: pt2 = self.pts[(int(t1) + 1) % self.N] return (pt2 - pt1) * self.N / TWOPI + def complex_cubic_spline(pts): """ Creates a cubic spline interpolated figure from a set of complex or @@ -168,7 +174,7 @@ def complex_cubic_spline(pts): INPUT: - - ``pts`` A list or array of complex numbers, or tuples of the form + - ``pts`` -- A list or array of complex numbers, or tuples of the form `(x,y)`. EXAMPLES: @@ -179,19 +185,23 @@ def complex_cubic_spline(pts): sage: cs = complex_cubic_spline(pts) sage: fx = lambda x: cs.value(x).real sage: fy = lambda x: cs.value(x).imag - sage: show(parametric_plot((fx, fy), (0, 2*pi))) - sage: m = Riemann_Map([lambda x: cs.value(real(x))], [lambda x: cs.derivative(real(x))], 0) - sage: show(m.plot_colored() + m.plot_spiderweb()) + sage: from math import pi + sage: show(parametric_plot((fx, fy), (0, 2*pi))) # needs sage.plot + sage: m = Riemann_Map([lambda x: cs.value(real(x))], + ....: [lambda x: cs.derivative(real(x))], 0) + sage: show(m.plot_colored() + m.plot_spiderweb()) # needs sage.plot Polygon approximation of a circle:: - sage: pts = [e^(I*t / 25) for t in range(25)] + sage: from cmath import exp + sage: pts = [exp(1j * t / 25) for t in range(25)] sage: cs = complex_cubic_spline(pts) sage: cs.derivative(2) (-0.0497765406583...+0.151095006434...j) """ return CCSpline(pts) + cdef class CCSpline: """ A ``CCSpline`` object contains a cubic interpolation of a figure @@ -209,7 +219,7 @@ cdef class CCSpline: (0.9549296...-0.9549296...j) """ cdef int N - cdef np.ndarray avec,bvec,cvec,dvec + cdef np.ndarray avec, bvec, cvec, dvec #standard cubic interpolation method def __init__(self, pts): @@ -222,24 +232,24 @@ cdef class CCSpline: if isinstance(pts[0], tuple): pts = np.array( [complex(pt[0], pt[1]) for pt in pts], dtype=np.complex128) - cdef int N, i, k + cdef int N, i N = len(pts) yvec = np.zeros(N, dtype=np.complex128) - for i in xrange(N): + for i in range(N): yvec[i] = 3 * (pts[(i - 1) % N] - 2*pts[i] + pts[(i + 1) % N]) bmat = np.zeros([N, N], dtype=np.complex128) - for i in xrange(N): + for i in range(N): bmat[i, i] = 4 bmat[(i - 1) % N, i] = 1 bmat[(i + 1) % N, i] = 1 bvec = (np.linalg.solve(bmat, yvec)) cvec = np.zeros(N, dtype=np.complex128) - for i in xrange(N): + for i in range(N): cvec[i] = (pts[(i + 1) % N] - pts[i] - 1.0/3.0 * bvec[(i + 1) % N] - 2./3. * bvec[i]) dvec = np.array(pts, dtype=np.complex128) avec = np.zeros(N, dtype=np.complex128) - for i in xrange(N): + for i in range(N): avec[i] = 1.0/3.0 * (bvec[(i + 1) % N] - bvec[i]) self.avec = avec self.bvec = bvec @@ -269,6 +279,7 @@ cdef class CCSpline: sage: cs = complex_cubic_spline(pts) sage: cs.value(4 / 7) (-0.303961332787...-1.34716728183...j) + sage: from math import pi sage: cs.value(0) - cs.value(2*pi) 0j sage: cs.value(-2.73452) @@ -300,6 +311,7 @@ cdef class CCSpline: sage: cs = complex_cubic_spline(pts) sage: cs.derivative(3 / 5) (1.40578892327...-0.225417136326...j) + sage: from math import pi sage: cs.derivative(0) - cs.derivative(2 * pi) 0j sage: cs.derivative(-6) diff --git a/src/sage/calculus/ode.pxd b/src/sage/calculus/ode.pxd index a897f33b16e..e517fe0c401 100644 --- a/src/sage/calculus/ode.pxd +++ b/src/sage/calculus/ode.pxd @@ -1,6 +1,4 @@ cdef class ode_system: cdef int c_j(self,double , double *, double *,double *) - cdef int c_f(self,double t, double* , double* ) - diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx index 22d8d7d491e..f1004b9b438 100644 --- a/src/sage/calculus/ode.pyx +++ b/src/sage/calculus/ode.pyx @@ -64,20 +64,20 @@ cdef int c_jac(double t,double *y,double *dfdy,double *dfdt,void *params): cdef int param_n cdef PyFunctionWrapper wrapper wrapper = <PyFunctionWrapper > params - y_n=wrapper.y_n - y_list=[] - for i from 0<=i<y_n: + y_n = wrapper.y_n + y_list = [] + for i in range(y_n): y_list.append(y[i]) try: if len(wrapper.the_parameters)==0: jac_list=wrapper.the_jacobian(t,y_list) else: jac_list=wrapper.the_jacobian(t,y_list,wrapper.the_parameters) - for i from 0<=i<y_n: - for j from 0<=j<y_n: + for i in range(y_n): + for j in range(y_n): dfdy[i*y_n+j]=jac_list[i][j] - for i from 0 <=i<y_n: + for i in range(y_n): dfdt[i]=jac_list[y_n][i] return GSL_SUCCESS @@ -91,17 +91,17 @@ cdef int c_f(double t,double* y, double* dydt,void *params): cdef PyFunctionWrapper wrapper wrapper = <PyFunctionWrapper> params - y_n= wrapper.y_n - y_list=[] - for i from 0<=i<y_n: + y_n = wrapper.y_n + y_list = [] + for i in range(y_n): y_list.append(y[i]) try: if len(wrapper.the_parameters)!=0: dydt_list=wrapper.the_function(t,y_list,wrapper.the_parameters) else: dydt_list=wrapper.the_function(t,y_list) - for i from 0<=i<y_n: - dydt[i]=dydt_list[i] + for i in range(y_n): + dydt[i] = dydt_list[i] return GSL_SUCCESS except Exception: return -1 @@ -109,30 +109,31 @@ cdef int c_f(double t,double* y, double* dydt,void *params): class ode_solver(): r""" - :meth:`ode_solver` is a class that wraps the GSL libraries ode - solver routines To use it instantiate a class,:: + :meth:`ode_solver` is a class that wraps the GSL library's ode solver routines. - sage: T=ode_solver() + To use it, instantiate the class:: - To solve a system of the form ``dy_i/dt=f_i(t,y)``, you must + sage: T = ode_solver() + + To solve a system of the form `dy_i/dt=f_i(t,y)`, you must supply a vector or tuple/list valued function ``f`` representing - ``f_i``. The functions ``f`` and the jacobian should have the + `f_i`. The functions `f` and the jacobian should have the form ``foo(t,y)`` or ``foo(t,y,params)``. ``params`` which is optional allows for your function to depend on one or a tuple of parameters. Note if you use it, ``params`` must be a tuple even if it only has one component. For example if you wanted to solve - `y''+y=0`. You need to write it as a first order system:: + `y''+y=0`, you would need to write it as a first order system:: y_0' = y_1 y_1' = -y_0 In code:: - sage: f = lambda t,y:[y[1],-y[0]] - sage: T.function=f + sage: f = lambda t, y: [y[1], -y[0]] + sage: T.function = f - For some algorithms the jacobian must be supplied as well, the - form of this should be a function return a list of lists of the + For some algorithms, the jacobian must be supplied as well, the + form of this should be a function returning a list of lists of the form ``[ [df_1/dy_1,...,df_1/dy_n], ..., [df_n/dy_1,...,df_n,dy_n], [df_1/dt,...,df_n/dt] ]``. @@ -143,45 +144,45 @@ class ode_solver(): There are a variety of algorithms available for different types of systems. Possible algorithms are - - ``rkf45`` - runga-kutta-felhberg (4,5) + - ``'rkf45'`` -- Runge-Kutta-Fehlberg (4,5) - - ``rk2`` - embedded runga-kutta (2,3) + - ``'rk2'`` -- embedded Runge-Kutta (2,3) - - ``rk4`` - 4th order classical runga-kutta + - ``'rk4'`` -- 4th order classical Runge-Kutta - - ``rk8pd`` - runga-kutta prince-dormand (8,9) + - ``'rk8pd'`` -- Runge-Kutta Prince-Dormand (8,9) - - ``rk2imp`` - implicit 2nd order runga-kutta at gaussian points + - ``'rk2imp'`` -- implicit 2nd order Runge-Kutta at gaussian points - - ``rk4imp`` - implicit 4th order runga-kutta at gaussian points + - ``'rk4imp'`` -- implicit 4th order Runge-Kutta at gaussian points - - ``bsimp`` - implicit burlisch-stoer (requires jacobian) + - ``'bsimp'`` -- implicit Burlisch-Stoer (requires jacobian) - - ``gear1`` - M=1 implicit gear + - ``'gear1'`` -- M=1 implicit gear - - ``gear2`` - M=2 implicit gear + - ``'gear2'`` -- M=2 implicit gear - The default algorithm is ``rkf45``. If you instead wanted to use - ``bsimp`` you would do:: + The default algorithm is ``'rkf45'``. If you instead wanted to use + ``'bsimp'`` you would do:: - sage: T.algorithm="bsimp" + sage: T.algorithm = "bsimp" - The user should supply initial conditions in y_0. For example if - your initial conditions are y_0=1,y_1=1, do:: + The user should supply initial conditions in ``y_0``. For example if + your initial conditions are `y_0=1, y_1=1`, do:: - sage: T.y_0=[1,1] + sage: T.y_0 = [1,1] The actual solver is invoked by the method :meth:`ode_solve`. It has arguments ``t_span``, ``y_0``, ``num_points``, ``params``. ``y_0`` must be supplied either as an argument or above by assignment. Params which are optional and only necessary if your - system uses params can be supplied to ``ode_solve`` or by + system uses ``params`` can be supplied to ``ode_solve`` or by assignment. ``t_span`` is the time interval on which to solve the ode. There are two ways to specify ``t_span``: - * If ``num_points`` is not specified then the sequence ``t_span`` + * If ``num_points`` is not specified, then the sequence ``t_span`` is used as the time points for the solution. Note that the first element ``t_span[0]`` is the initial time, where the initial condition ``y_0`` is the specified solution, and @@ -192,10 +193,10 @@ class ode_solver(): and the solution will be computed at ``num_points`` equally spaced points between ``t_span[0]`` and ``t_span[1]``. The initial condition is also included in the output so that - ``num_points``\ +1 total points are returned. E.g. if ``t_span + ``num_points + 1`` total points are returned. E.g. if ``t_span = [0.0, 1.0]`` and ``num_points = 10``, then solution is returned at the 11 time points ``[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, - 0.6, 0.7, 0.8, 0.9, 1.0]``\ . + 0.6, 0.7, 0.8, 0.9, 1.0]``. (Note that if ``num_points`` is specified and ``t_span`` is not length 2 then ``t_span`` are used as the time points and @@ -203,13 +204,19 @@ class ode_solver(): Error is estimated via the expression ``D_i = error_abs*s_i+error_rel*(a|y_i|+a_dydt*h*|y_i'|)``. The user can - specify ``error_abs`` (1e-10 by default), ``error_rel`` (1e-10 by - default) ``a`` (1 by default), ``a_(dydt)`` (0 by default) and - ``s_i`` (as scaling_abs which should be a tuple and is 1 in all - components by default). If you specify one of ``a`` or ``a_dydt`` + specify + + - ``error_abs`` (1e-10 by default), + - ``error_rel`` (1e-10 by default), + - ``a`` (1 by default), + - ``a_dydt`` (0 by default) and + - ``s_i`` (as ``scaling_abs`` which should be a tuple and is 1 in all + components by default). + + If you specify one of ``a`` or ``a_dydt`` you must specify the other. You may specify ``a`` and ``a_dydt`` without ``scaling_abs`` (which will be taken =1 be default). - ``h`` is the initial step size which is (1e-2) by default. + ``h`` is the initial step size, which is 1e-2 by default. ``ode_solve`` solves the solution as a list of tuples of the form, ``[ (t_0,[y_1,...,y_n]),(t_1,[y_1,...,y_n]),...,(t_n,[y_1,...,y_n])]``. @@ -223,27 +230,29 @@ class ode_solver(): Consider solving the Van der Pol oscillator `x''(t) + ux'(t)(x(t)^2-1)+x(t)=0` between `t=0` and `t= 100`. As a first order system it is `x'=y`, `y'=-x+uy(1-x^2)`. Let us take `u=10` - and use initial conditions `(x,y)=(1,0)` and use the runga-kutta - prince-dormand algorithm. :: - - sage: def f_1(t,y,params): - ....: return[y[1],-y[0]-params[0]*y[1]*(y[0]**2-1.0)] - - sage: def j_1(t,y,params): - ....: return [ [0.0, 1.0],[-2.0*params[0]*y[0]*y[1]-1.0,-params[0]*(y[0]*y[0]-1.0)], [0.0, 0.0] ] - - sage: T=ode_solver() - sage: T.algorithm="rk8pd" - sage: T.function=f_1 - sage: T.jacobian=j_1 - sage: T.ode_solve(y_0=[1,0],t_span=[0,100],params=[10.0],num_points=1000) + and use initial conditions `(x,y)=(1,0)` and use the Runge-Kutta + Prince-Dormand algorithm. :: + + sage: def f_1(t, y, params): + ....: return [y[1], -y[0] - params[0]*y[1]*(y[0]**2-1.0)] + + sage: def j_1(t, y, params): + ....: return [[0.0, 1.0], + ....: [-2.0*params[0]*y[0]*y[1] - 1.0, -params[0]*(y[0]*y[0]-1.0)], + ....: [0.0, 0.0]] + + sage: T = ode_solver() + sage: T.algorithm = "rk8pd" + sage: T.function = f_1 + sage: T.jacobian = j_1 + sage: T.ode_solve(y_0=[1,0], t_span=[0,100], params=[10.0], num_points=1000) sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot ....: T.plot_solution(filename=f.name) The solver line is equivalent to:: - sage: T.ode_solve(y_0=[1,0],t_span=[x/10.0 for x in range(1000)],params = [10.0]) + sage: T.ode_solve(y_0=[1,0], t_span=[x/10.0 for x in range(1000)], params=[10.0]) Let's try a system:: @@ -254,40 +263,42 @@ class ode_solver(): We will not use the jacobian this time and will change the error tolerances. :: - sage: g_1= lambda t,y: [y[1]*y[2],-y[0]*y[2],-0.51*y[0]*y[1]] - sage: T.function=g_1 - sage: T.y_0=[0,1,1] - sage: T.scale_abs=[1e-4,1e-4,1e-5] - sage: T.error_rel=1e-4 - sage: T.ode_solve(t_span=[0,12],num_points=100) + sage: g_1 = lambda t,y: [y[1]*y[2], -y[0]*y[2], -0.51*y[0]*y[1]] + sage: T.function = g_1 + sage: T.y_0 = [0,1,1] + sage: T.scale_abs = [1e-4, 1e-4, 1e-5] + sage: T.error_rel = 1e-4 + sage: T.ode_solve(t_span=[0,12], num_points=100) - By default T.plot_solution() plots the y_0, to plot general y_i use:: + By default ``T.plot_solution()`` plots the `y_0`; to plot general `y_i`, use:: - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot ....: T.plot_solution(i=0, filename=f.name) ....: T.plot_solution(i=1, filename=f.name) ....: T.plot_solution(i=2, filename=f.name) The method interpolate_solution will return a spline interpolation - through the points found by the solver. By default y_0 is - interpolated. You can interpolate y_i through the keyword - argument i. :: + through the points found by the solver. By default, `y_0` is + interpolated. You can interpolate `y_i` through the keyword + argument ``i``. :: sage: f = T.interpolate_solution() - sage: plot(f,0,12).show() + sage: plot(f,0,12).show() # needs sage.plot sage: f = T.interpolate_solution(i=1) - sage: plot(f,0,12).show() + sage: plot(f,0,12).show() # needs sage.plot sage: f = T.interpolate_solution(i=2) - sage: plot(f,0,12).show() + sage: plot(f,0,12).show() # needs sage.plot sage: f = T.interpolate_solution() + sage: from math import pi sage: f(pi) 0.5379... The solver attributes may also be set up using arguments to ode_solver. The previous example can be rewritten as:: - sage: T = ode_solver(g_1,y_0=[0,1,1],scale_abs=[1e-4,1e-4,1e-5],error_rel=1e-4, algorithm="rk8pd") - sage: T.ode_solve(t_span=[0,12],num_points=100) + sage: T = ode_solver(g_1, y_0=[0,1,1], scale_abs=[1e-4,1e-4,1e-5], + ....: error_rel=1e-4, algorithm="rk8pd") + sage: T.ode_solve(t_span=[0,12], num_points=100) sage: f = T.interpolate_solution() sage: f(pi) 0.5379... @@ -295,7 +306,7 @@ class ode_solver(): Unfortunately because Python functions are used, this solver is slow on systems that require many function evaluations. It is possible to pass a compiled function by deriving from the - class ``ode_sysem`` and overloading ``c_f`` and ``c_j`` with C + class :class:`ode_system` and overloading ``c_f`` and ``c_j`` with C functions that specify the system. The following will work in the notebook: @@ -324,15 +335,16 @@ class ode_solver(): following (WARNING: the following is *not* automatically doctested):: - sage: T = ode_solver() # not tested - sage: T.algorithm = "bsimp" # not tested - sage: vander = van_der_pol() # not tested - sage: T.function=vander # not tested - sage: T.ode_solve(y_0 = [1,0], t_span=[0,2000], # not tested - ....: num_points=1000) # not tested - sage: from tempfile import NamedTemporaryFile # not tested - sage: with NamedTemporaryFile(suffix=".png") as f: # not tested - ....: T.plot_solution(i=0, filename=f.name) # not tested + sage: # not tested + sage: T = ode_solver() + sage: T.algorithm = "bsimp" + sage: vander = van_der_pol() + sage: T.function = vander + sage: T.ode_solve(y_0=[1, 0], t_span=[0, 2000], + ....: num_points=1000) + sage: from tempfile import NamedTemporaryFile + sage: with NamedTemporaryFile(suffix=".png") as f: + ....: T.plot_solution(i=0, filename=f.name) """ def __init__(self,function=None,jacobian=None,h = 1e-2,error_abs=1e-10,error_rel=1e-10, a=False,a_dydt=False,scale_abs=False,algorithm="rkf45",y_0=None,t_span=None,params = []): @@ -381,11 +393,11 @@ class ode_solver(): sage: T.function = lambda t,y: [cos(y[0]) * sin(t)] sage: T.jacobian = lambda t,y: [[-sin(y[0]) * sin(t)]] sage: T.ode_solve(y_0=[1],t_span=[0,20],num_points=1000) - sage: T.plot_solution() + sage: T.plot_solution() # needs sage.plot And with some options:: - sage: T.plot_solution(color='red', axes_labels=["t", "x(t)"]) + sage: T.plot_solution(color='red', axes_labels=["t", "x(t)"]) # needs sage.plot """ if interpolate: from sage.plot.line import line2d @@ -401,9 +413,8 @@ class ode_solver(): G.save(filename=filename) def ode_solve(self,t_span=False,y_0=False,num_points=False,params=[]): - import inspect cdef double h # step size - h=self.h + h = self.h cdef int i cdef int j cdef int type @@ -436,22 +447,21 @@ class ode_solver(): wrapper.the_parameters = self.params wrapper.y_n = dim - cdef double t cdef double t_end cdef double *y cdef double * scale_abs_array scale_abs_array=NULL - y= <double*> sig_malloc(sizeof(double)*(dim)) - if y==NULL: + y = <double*> sig_malloc(sizeof(double)*(dim)) + if y == NULL: raise MemoryError("error allocating memory") - result=[] - v=[0]*dim + result = [] + v = [0]*dim cdef gsl_odeiv_step_type * T - for i from 0 <=i< dim: #copy initial conditions into C array - y[i]=self.y_0[i] + for i in range(dim): # copy initial conditions into C array + y[i] = self.y_0[i] if self.algorithm == "rkf45": T=gsl_odeiv_step_rkf45 @@ -478,14 +488,12 @@ class ode_solver(): else: raise TypeError("algorithm not valid") - cdef gsl_odeiv_step * s s = gsl_odeiv_step_alloc (T, dim) if s==NULL: sig_free(y) raise MemoryError("error setting up solver") - cdef gsl_odeiv_control * c if not self.a and not self.a_dydt: @@ -494,9 +502,9 @@ class ode_solver(): if not self.scale_abs: c = gsl_odeiv_control_standard_new(self.error_abs,self.error_rel,self.a,self.a_dydt) elif hasattr(self.scale_abs,'__len__'): - if len(self.scale_abs)==dim: + if len(self.scale_abs) == dim: scale_abs_array =<double *> sig_malloc(dim*sizeof(double)) - for i from 0 <=i<dim: + for i in range(dim): scale_abs_array[i]=self.scale_abs[i] c = gsl_odeiv_control_scaled_new(self.error_abs,self.error_rel,self.a,self.a_dydt,scale_abs_array,dim) @@ -507,7 +515,6 @@ class ode_solver(): sig_free(scale_abs_array) raise MemoryError("error setting up solver") - cdef gsl_odeiv_evolve * e e = gsl_odeiv_evolve_alloc(dim) @@ -518,7 +525,6 @@ class ode_solver(): sig_free(scale_abs_array) raise MemoryError("error setting up solver") - cdef gsl_odeiv_system sys if type: # The user has passed a class with a compiled function, use that for the system sys.function = c_f_compiled @@ -531,7 +537,6 @@ class ode_solver(): sys.params = <void *> wrapper sys.dimension = dim - cdef int status import copy cdef int n @@ -546,11 +551,11 @@ class ode_solver(): sig_free(y) sig_free(scale_abs_array) raise TypeError("numpoints must be integer") - result.append( (self.t_span[0],self.y_0)) + result.append((self.t_span[0], self.y_0)) delta = (self.t_span[1]-self.t_span[0])/(1.0*num_points) - t =self.t_span[0] - t_end=self.t_span[0]+delta - for i from 0<i<=n: + t = self.t_span[0] + t_end = self.t_span[0]+delta + for i in range(1, n + 1): while (t < t_end): try: sig_on() @@ -566,7 +571,7 @@ class ode_solver(): sig_free(scale_abs_array) raise ValueError("error solving") - for j from 0<=j<dim: + for j in range(dim): v[j]=<double> y[j] result.append( (t,copy.copy(v)) ) t = t_end @@ -574,9 +579,9 @@ class ode_solver(): else: n = len(self.t_span) - result.append((self.t_span[0],self.y_0)) - t=self.t_span[0] - for i from 0<i<n: + result.append((self.t_span[0], self.y_0)) + t = self.t_span[0] + for i in range(1, n): t_end=self.t_span[i] while (t < t_end): try: @@ -593,12 +598,11 @@ class ode_solver(): sig_free(scale_abs_array) raise ValueError("error solving") - for j from 0<=j<dim: - v[j]=<double> y[j] - result.append( (t,copy.copy(v)) ) - - t=self.t_span[i] + for j in range(dim): + v[j] = <double> y[j] + result.append((t, copy.copy(v))) + t = self.t_span[i] gsl_odeiv_evolve_free (e) gsl_odeiv_control_free (c) diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx index 4dc18b964f2..a4f9545bffb 100644 --- a/src/sage/calculus/riemann.pyx +++ b/src/sage/calculus/riemann.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs numpy sage.symbolic """ Riemann Mapping @@ -46,7 +47,6 @@ cimport numpy as np from math import pi from math import sin from math import cos -from math import sqrt from math import log # used for complex plot lightness from math import atan @@ -54,8 +54,6 @@ from math import atan from cmath import exp from cmath import phase -from random import uniform # used for accuracy tests - FLOAT = np.float64 ctypedef np.float64_t FLOAT_T @@ -236,7 +234,7 @@ cdef class Riemann_Map: self.tk = np.array(np.arange(N) * TWOPI / N + 0.001 / N, dtype=FLOAT) self.tk2 = np.zeros(N + 1, dtype=FLOAT) - for i in xrange(N): + for i in range(N): self.tk2[i] = self.tk[i] self.tk2[N] = TWOPI self.B = len(fs) # number of boundaries of the figure @@ -249,14 +247,14 @@ cdef class Riemann_Map: dtype=COMPLEX) # Find the points on the boundaries and their derivatives. if self.exterior: - for k in xrange(self.B): - for i in xrange(N): + for k in range(self.B): + for i in range(N): fk = fs[k](self.tk[N-i-1]) cps[k, i] = complex(1/fk) dps[k, i] = complex(1/fk**2*fprimes[k](self.tk[N-i-1])) else: - for k in xrange(self.B): - for i in xrange(N): + for k in range(self.B): + for i in range(N): cps[k, i] = complex(fs[k](self.tk[i])) dps[k, i] = complex(fprimes[k](self.tk[i])) if self.exterior: @@ -296,7 +294,9 @@ cdef class Riemann_Map: cdef _generate_theta_array(self): """ Generates the essential data for the Riemann map, primarily the - Szego kernel and boundary correspondence. See [KT1986]_ for the algorithm. + Szegล‘ kernel and boundary correspondence. + + See [KT1986]_ for the algorithm. TESTS:: @@ -304,16 +304,16 @@ cdef class Riemann_Map: sage: fprime(t) = I*e^(I*t) + 0.5*I*e^(-I*t) sage: m = Riemann_Map([f], [fprime], 0, N = 10) """ - cdef np.ndarray[COMPLEX_T,ndim =1] cp = self.cps.flatten() - cdef np.ndarray[COMPLEX_T,ndim =1] dp = self.dps.flatten() + cdef np.ndarray[COMPLEX_T, ndim=1] cp = self.cps.flatten() + cdef np.ndarray[COMPLEX_T, ndim=1] dp = self.dps.flatten() cdef int N = self.N cdef int NB = N * self.B cdef int B = self.B cdef int i, k cdef FLOAT_T saa, t0 cdef np.ndarray[FLOAT_T, ndim=1] adp, sadp - cdef np.ndarray[COMPLEX_T,ndim =1] h, hconj, g, normalized_dp, C, phi - cdef np.ndarray[COMPLEX_T,ndim =2] K + cdef np.ndarray[COMPLEX_T, ndim=1] h, hconj, g, normalized_dp, C, phi + cdef np.ndarray[COMPLEX_T, ndim=2] K cdef np.ndarray[FLOAT_T, ndim=2] theta_array # Setting things up to use the Nystrom method adp = abs(dp) @@ -330,7 +330,7 @@ cdef class Riemann_Map: (normalized_dp[t]/(cp-cp[t])).conjugate()) for t in np.arange(NB)], dtype=np.complex128) np.seterr(divide=errdivide,invalid=errinvalid) # resets the error handling - for i in xrange(NB): + for i in range(NB): K[i, i] = 1 # Nystrom Method for solving 2nd kind integrals phi = np.linalg.solve(K, g) / NB * TWOPI @@ -342,22 +342,22 @@ cdef class Riemann_Map: # regions. if B != 1: theta_array = np.zeros([1, NB]) - for i in xrange(NB): + for i in range(NB): theta_array[0, i] = phase(-I * np.power(phi[i], 2) * dp[i]) self.theta_array = np.concatenate( [theta_array.reshape([B, N]), np.zeros([B, 1])], axis=1) - for k in xrange(B): + for k in range(B): self.theta_array[k, N] = self.theta_array[k, 0] + TWOPI # Finding the theta correspondence using abs. Well behaved, but # doesn't work on multiply connected domains. else: phi2 = phi.reshape([self.B, N]) theta_array = np.zeros([B, N + 1], dtype=np.float64) - for k in xrange(B): + for k in range(B): phik = phi2[k] saa = (np.dot(abs(phi), abs(phi))) * TWOPI / NB theta_array[k, 0] = 0 - for i in xrange(1, N): + for i in range(1, N): theta_array[k, i] = ( theta_array[k, i - 1] + ((TWOPI / NB * TWOPI * @@ -371,7 +371,7 @@ cdef class Riemann_Map: t0 = theta_array[k, tmax] + phase(phimax) else: t0 = theta_array[k, tmax] - phase(phimax) - for i in xrange(N): + for i in range(N): theta_array[k, i] = theta_array[k, i] - t0 theta_array[k, N] = TWOPI + theta_array[k, 0] self.theta_array = theta_array @@ -435,7 +435,7 @@ cdef class Riemann_Map: cdef int k, B if boundary < 0: temptk = self.tk - for i in xrange(self.B - 1): + for i in range(self.B - 1): temptk = np.concatenate([temptk, self.tk]) if absolute_value: return np.column_stack( @@ -507,7 +507,7 @@ cdef class Riemann_Map: """ if boundary < 0: temptk = self.tk2 - for i in xrange(self.B - 1): + for i in range(self.B - 1): temptk = np.concatenate([temptk, self.tk2]) return np.column_stack( [temptk, self.theta_array.flatten()]).tolist() @@ -535,8 +535,8 @@ cdef class Riemann_Map: [self.B, N + 1], dtype=np.complex128) cdef int k, i # Lots of setup for Simpson's method of integration. - for k in xrange(self.B): - for i in xrange(N // 3): + for k in range(self.B): + for i in range(N // 3): p_vector[k, 3*i] = (2*coeff * dps[k, 3*i] * exp(I * theta_array[k, 3*i])) p_vector[k, 3*i + 1] = (3*coeff * dps[k, 3*i + 1] * @@ -639,8 +639,8 @@ cdef class Riemann_Map: self.p_vector_inverse = np.zeros([B, N], dtype=np.complex128) # Setup for trapezoid integration because integration points are # not equally spaced. - for k in xrange(B): - for i in xrange(N): + for k in range(B): + for i in range(N): di = theta_array[k, (i + 1) % N] - theta_array[k, (i - 1) % N] if di > PI: di = di - TWOPI @@ -648,12 +648,12 @@ cdef class Riemann_Map: di = di + TWOPI self.p_vector_inverse[k, i] = di / 2 self.sinalpha = np.zeros([B, N], dtype=np.float64) - for k in xrange(B): - for i in xrange(N): + for k in range(B): + for i in range(N): self.sinalpha[k, i] = sin(-theta_array[k, i]) self.cosalpha = np.zeros([B, N], dtype=np.float64) - for k in xrange(B): - for i in xrange(N): + for k in range(B): + for i in range(N): self.cosalpha[k, i] = cos(-theta_array[k, i]) cpdef inverse_riemann_map(self, COMPLEX_T pt): @@ -751,7 +751,7 @@ cdef class Riemann_Map: from sage.plot.all import list_plot plots = list(range(self.B)) - for k in xrange(self.B): + for k in range(self.B): # This conditional should be eliminated when the thickness/pointsize # issue is resolved later. Same for the others in plot_spiderweb(). if plotjoined: @@ -817,13 +817,13 @@ cdef class Riemann_Map: cdef np.ndarray[COMPLEX_T, ndim=2] z_values = np.empty( [y_points, x_points], dtype=np.complex128) if self.exterior: - for i in xrange(x_points): - for j in xrange(y_points): + for i in range(x_points): + for j in range(y_points): pt = 1/(xmin + 0.5*xstep + i*xstep + I*(ymin + 0.5*ystep + j*ystep)) z_values[j, i] = 1/(-np.dot(p_vector,1/(pre_q_vector - pt))) else: - for i in xrange(x_points): - for j in xrange(y_points): + for i in range(x_points): + for j in range(y_points): pt = xmin + 0.5*xstep + i*xstep + I*(ymin + 0.5*ystep + j*ystep) z_values[j, i] = -np.dot(p_vector,1/(pre_q_vector - pt)) return z_values, xmin, xmax, ymin, ymax @@ -952,9 +952,9 @@ cdef class Riemann_Map: s = spline(np.column_stack([self.theta_array[0], self.tk2]).tolist()) tmax = self.theta_array[0, self.N] tmin = self.theta_array[0, 0] - for k in xrange(circles): + for k in range(circles): temp = list(range(pts*2)) - for i in xrange(2*pts): + for i in range(2*pts): temp[i] = self.inverse_riemann_map( (k + 1) / (circles + 1.0) * exp(I*i * TWOPI / (2*pts))) if plotjoined: @@ -964,14 +964,14 @@ cdef class Riemann_Map: circle_list[k] = list_plot(comp_pt(temp, 1), rgbcolor=rgbcolor, pointsize=thickness) line_list = list(range(spokes)) - for k in xrange(spokes): + for k in range(spokes): temp = list(range(pts)) angle = (k*1.0) / spokes * TWOPI if angle >= tmax: angle -= TWOPI elif angle <= tmin: angle += TWOPI - for i in xrange(pts - 1): + for i in range(pts - 1): temp[i] = self.inverse_riemann_map( (i * 1.0) / (pts * 1.0) * exp(I * angle) * linescale) temp[pts - 1] = complex( @@ -1191,9 +1191,10 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values, sage: from sage.calculus.riemann import complex_to_spiderweb sage: import numpy - sage: zval = numpy.array([[0, 1, 1000],[.2+.3j,1,-.3j],[0,0,0]],dtype = numpy.complex128) + sage: zval = numpy.array([[0,1,1000], [.2+.3j,1,-.3j], [0,0,0]], + ....: dtype=numpy.complex128) sage: deriv = numpy.array([[.1]],dtype = numpy.float64) - sage: complex_to_spiderweb(zval, deriv,deriv, 4,4,[0,0,0],1,False,0.001) + sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, False, 0.001) array([[[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]], @@ -1206,7 +1207,7 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values, [1., 1., 1.], [1., 1., 1.]]]) - sage: complex_to_spiderweb(zval, deriv,deriv, 4,4,[0,0,0],1,True,0.001) + sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, True, 0.001) array([[[1. , 1. , 1. ], [1. , 0.05558355, 0.05558355], [0.17301243, 0. , 0. ]], @@ -1241,8 +1242,8 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values, spoke_angles = srange(-PI,PI+TWOPI/spokes,TWOPI/spokes) else: spoke_angles = [] - for i in xrange(imax-2): # the d arrays are 1 smaller on each side - for j in xrange(jmax-2): + for i in range(imax-2): # the d arrays are 1 smaller on each side + for j in range(jmax-2): z = z_values[i+1,j+1] mag = abs(z) arg = phase(z) @@ -1281,12 +1282,12 @@ cpdef complex_to_rgb(np.ndarray[COMPLEX_T, ndim = 2] z_values): sage: from sage.calculus.riemann import complex_to_rgb sage: import numpy - sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype = numpy.complex128)) + sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype=numpy.complex128)) array([[[1. , 1. , 1. ], [1. , 0.05558355, 0.05558355], [0.17301243, 0. , 0. ]]]) - sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype = numpy.complex128)) + sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype=numpy.complex128)) array([[[1. , 1. , 1. ], [0.52779177, 1. , 0.05558355], [0.08650622, 0.17301243, 0. ]]]) @@ -1312,9 +1313,9 @@ cpdef complex_to_rgb(np.ndarray[COMPLEX_T, ndim = 2] z_values): dtype=FLOAT, shape=(imax, jmax, 3)) sig_on() - for i in xrange(imax): + for i in range(imax): row = z_values[i] - for j in xrange(jmax): + for j in range(jmax): z = row[j] mag = abs(z) arg = phase(z) @@ -1411,7 +1412,7 @@ cpdef analytic_boundary(FLOAT_T t, int n, FLOAT_T epsilon): """ cdef FLOAT_T i cdef FLOAT_T result = t - for i from 1 <= i < n+1: + for i in range(1, n + 1): result += (2*(-1)**i/i)*(epsilon**i/(1+epsilon**(2*i)))*sin(2*i*t) return result diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py index 927e6ee4fb6..b99d5d7857e 100644 --- a/src/sage/calculus/test_sympy.py +++ b/src/sage/calculus/test_sympy.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic r""" A Sample Session using SymPy @@ -102,46 +102,47 @@ And here are some actual tests of sympy:: - sage: from sympy import Symbol, cos, sympify, pprint - sage: from sympy.abc import x + sage: from sympy import Symbol, cos, sympify, pprint # needs sympy + sage: from sympy.abc import x # needs sympy :: - sage: e = (1/cos(x)^3)._sympy_(); e + sage: e = (1/cos(x)^3)._sympy_(); e # needs sympy cos(x)**(-3) - sage: f = e.series(x, 0, int(10)); f + sage: f = e.series(x, 0, int(10)); f # needs sympy 1 + 3*x**2/2 + 11*x**4/8 + 241*x**6/240 + 8651*x**8/13440 + O(x**10) And the pretty-printer. Since unicode characters are not working on some architectures, we disable it:: - sage: from sympy.printing import pprint_use_unicode - sage: prev_use = pprint_use_unicode(False) - sage: pprint(e) + sage: from sympy.printing import pprint_use_unicode # needs sympy + sage: prev_use = pprint_use_unicode(False) # needs sympy + sage: pprint(e) # needs sympy 1 ------- 3 cos (x) - sage: pprint(f) + sage: pprint(f) # needs sympy 2 4 6 8 3*x 11*x 241*x 8651*x / 10\ 1 + ---- + ----- + ------ + ------- + O\x / 2 8 240 13440 - sage: pprint_use_unicode(prev_use) + sage: pprint_use_unicode(prev_use) # needs sympy False And the functionality to convert from sympy format to Sage format:: - sage: e._sage_() + sage: e._sage_() # needs sympy cos(x)^(-3) - sage: e._sage_().taylor(x._sage_(), 0, 8) + sage: e._sage_().taylor(x._sage_(), 0, 8) # needs sympy 8651/13440*x^8 + 241/240*x^6 + 11/8*x^4 + 3/2*x^2 + 1 - sage: f._sage_() + sage: f._sage_() # needs sympy 8651/13440*x^8 + 241/240*x^6 + 11/8*x^4 + 3/2*x^2 + Order(x^10) + 1 Mixing SymPy with Sage:: + sage: # needs sympy sage: import sympy sage: var("x")._sympy_() + var("y")._sympy_() x + y @@ -155,7 +156,7 @@ <class 'sage.symbolic.expression.Expression'> sage: t1, t2 (omega + x, omega + x) - sage: e=sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x")) + sage: e = sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x")) sage: type(e) <class 'sympy.core.add.Add'> sage: e @@ -172,23 +173,24 @@ :: - sage: a = sympy.Matrix([1, 2, 3]) - sage: a[1] + sage: a = sympy.Matrix([1, 2, 3]) # needs sympy + sage: a[1] # needs sympy 2 :: - sage: sympify(1.5) + sage: sympify(1.5) # needs sympy 1.50000000000000 - sage: sympify(2) + sage: sympify(2) # needs sympy 2 - sage: sympify(-2) + sage: sympify(-2) # needs sympy -2 TESTS: This was fixed in Sympy, see :trac:`14437`:: + sage: # needs sympy sage: from sympy import Function, Symbol, rsolve sage: u = Function('u') sage: n = Symbol('n', integer=True) diff --git a/src/sage/calculus/tests.py b/src/sage/calculus/tests.py index 1af43a97745..904ee7d17cf 100644 --- a/src/sage/calculus/tests.py +++ b/src/sage/calculus/tests.py @@ -121,9 +121,7 @@ sage: integrate(sin(x^2),x) 1/16*sqrt(pi)*((I + 1)*sqrt(2)*erf((1/2*I + 1/2)*sqrt(2)*x) + (I - 1)*sqrt(2)*erf((1/2*I - 1/2)*sqrt(2)*x) - (I - 1)*sqrt(2)*erf(sqrt(-I)*x) + (I + 1)*sqrt(2)*erf((-1)^(1/4)*x)) - sage: result = integrate((1-x^2)^n,x) - ... - sage: result + sage: integrate((1-x^2)^n,x) # long time x*hypergeometric((1/2, -n), (3/2,), x^2*exp_polar(2*I*pi)) sage: integrate(x^x,x) integrate(x^x, x) @@ -143,7 +141,7 @@ Other examples that now (:trac:`27958`) work:: - sage: integrate(log(x)*exp(-x^2), x) + sage: integrate(log(x)*exp(-x^2), x) # long time 1/2*sqrt(pi)*erf(x)*log(x) - x*hypergeometric((1/2, 1/2), (3/2, 3/2), -x^2) sage: integrate(log(1+sqrt(1+4*x)/2)/x, x, 0, 1) @@ -201,12 +199,12 @@ 1/3*sqrt(3)*arctan(1/3*sqrt(3)*(2*x + 1)) - 1/6*log(x^2 + x + 1) + 1/3*log(x - 1) sage: integrate(exp(-x^2), x) 1/2*sqrt(pi)*erf(x) - sage: integrate(exp(-x^2)*log(x), x) + sage: integrate(exp(-x^2)*log(x), x) # long time 1/2*sqrt(pi)*erf(x)*log(x) - x*hypergeometric((1/2, 1/2), (3/2, 3/2), -x^2) sage: f = exp(-x^2)*log(x) sage: f.nintegral(x, 0, 999) (-0.87005772672831..., 7.5584...e-10, 567, 0) - sage: integral(1/sqrt(2*t^4 - 3*t^2 - 2), t, 2, 3) # todo: maple can do this + sage: integral(1/sqrt(2*t^4 - 3*t^2 - 2), t, 2, 3) # long time # todo: maple can do this integrate(1/(sqrt(2*t^2 + 1)*sqrt(t^2 - 2)), t, 2, 3) sage: integral(integral(x*y^2, x, 0, y), y, -2, 2) 32/5 diff --git a/src/sage/calculus/transforms/all.py b/src/sage/calculus/transforms/all.py index 06ed525b868..379b3b69c37 100644 --- a/src/sage/calculus/transforms/all.py +++ b/src/sage/calculus/transforms/all.py @@ -1,3 +1,5 @@ -from .fft import FastFourierTransform, FFT -from .dwt import WaveletTransform, DWT +from sage.misc.lazy_import import lazy_import + +lazy_import("sage.calculus.transforms.fft", ["FastFourierTransform", "FFT"]) +lazy_import("sage.calculus.transforms.dwt", ["WaveletTransform", "DWT"]) from .dft import IndexedSequence diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index 9fd396f1915..b413bc0ea81 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -16,7 +16,7 @@ - plotting, printing -- :meth:`IndexedSequence.plot`, :meth:`IndexedSequence.plot_histogram`, :meth:`_repr_`, :meth:`__str__` -- dft -- computes the discrete Fourier transform for the following cases: +- :meth:`dft` -- computes the discrete Fourier transform for the following cases: * a sequence (over `\QQ` or :class:`CyclotomicField`) indexed by ``range(N)`` or `\ZZ / N \ZZ` @@ -26,21 +26,21 @@ * a sequence (as above) indexed by a complete set of representatives of the conjugacy classes of a finite matrix group -- idft -- computes the discrete Fourier transform for the following cases: +- :meth:`idft` -- computes the discrete Fourier transform for the following cases: * a sequence (over `\QQ` or CyclotomicField) indexed by ``range(N)`` or `\ZZ / N \ZZ` -- dct, dst (for discrete Fourier/Cosine/Sine transform) +- :meth:`dct`, :meth:`dst` (for discrete Fourier/Cosine/Sine transform) - convolution (in :meth:`IndexedSequence.convolution` and :meth:`IndexedSequence.convolution_periodic`) -- fft, ifft -- (fast Fourier transforms) wrapping GSL's +- :meth:`fft`, :meth:`ifft` -- (fast Fourier transforms) wrapping GSL's ``gsl_fft_complex_forward()``, ``gsl_fft_complex_inverse()``, using William Stein's :func:`FastFourierTransform` -- dwt, idwt -- (fast wavelet transforms) wrapping GSL's ``gsl_dwt_forward()``, +- :meth:`dwt`, :meth:`idwt` -- (fast wavelet transforms) wrapping GSL's ``gsl_dwt_forward()``, ``gsl_dwt_backward()`` using Joshua Kantor's :func:`WaveletTransform` class. Allows for wavelets of type: @@ -71,22 +71,21 @@ # # https://www.gnu.org/licenses/ ########################################################################## -from sage.rings.number_field.number_field import CyclotomicField +from sage.functions.trig import sin, cos from sage.misc.lazy_import import lazy_import -lazy_import("sage.plot.all", ["polygon", "line", "text"]) -from sage.groups.abelian_gps.abelian_group import AbelianGroup -from sage.groups.perm_gps.permgroup_element import is_PermutationGroupElement -from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.real_mpfr import RR -from sage.functions.all import sin, cos -from sage.calculus.transforms.fft import FastFourierTransform -from sage.calculus.transforms.dwt import WaveletTransform - from sage.structure.sage_object import SageObject from sage.structure.sequence import Sequence +lazy_import("sage.calculus.transforms.dwt", "WaveletTransform") +lazy_import("sage.calculus.transforms.fft", "FastFourierTransform") +lazy_import("sage.groups.abelian_gps.abelian_group", "AbelianGroup") +lazy_import("sage.groups.perm_gps.permgroup_element", "PermutationGroupElement") +lazy_import("sage.plot.all", ["polygon", "line", "text"]) +lazy_import("sage.rings.number_field.number_field", "CyclotomicField") + class IndexedSequence(SageObject): """ @@ -219,8 +218,7 @@ def _repr_(self): indexed by [0, 1, 2] sage: I = GF(3) sage: A = [i^2 for i in I] - sage: s = IndexedSequence(A,I) - sage: s + sage: s = IndexedSequence(A,I); s Indexed sequence: [0, 1, 1] indexed by Finite Field of size 3 """ @@ -241,9 +239,10 @@ def plot_histogram(self, clr=(0, 0, 1), eps=0.4): sage: J = list(range(3)) sage: A = [ZZ(i^2)+1 for i in J] sage: s = IndexedSequence(A,J) - sage: P = s.plot_histogram() - sage: show(P) # Not tested + sage: P = s.plot_histogram() # needs sage.plot + sage: show(P) # not tested # needs sage.plot """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR I = self.index_object() N = len(I) @@ -269,9 +268,10 @@ def plot(self): sage: I = list(range(3)) sage: A = [ZZ(i^2)+1 for i in I] sage: s = IndexedSequence(A,I) - sage: P = s.plot() - sage: show(P) # Not tested + sage: P = s.plot() # needs sage.plot + sage: show(P) # not tested # needs sage.plot """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR I = self.index_object() S = self.list() @@ -287,30 +287,44 @@ def dft(self, chi=lambda x: x): sage: J = list(range(6)) sage: A = [ZZ(1) for i in J] sage: s = IndexedSequence(A,J) - sage: s.dft(lambda x:x^2) + sage: s.dft(lambda x: x^2) # needs sage.rings.number_field Indexed sequence: [6, 0, 0, 6, 0, 0] indexed by [0, 1, 2, 3, 4, 5] - sage: s.dft() + sage: s.dft() # needs sage.rings.number_field Indexed sequence: [6, 0, 0, 0, 0, 0] indexed by [0, 1, 2, 3, 4, 5] + + sage: # needs sage.groups sage: G = SymmetricGroup(3) sage: J = G.conjugacy_classes_representatives() - sage: s = IndexedSequence([1,2,3],J) # 1,2,3 are the values of a class fcn on G + sage: s = IndexedSequence([1,2,3], J) # 1,2,3 are the values of a class fcn on G sage: s.dft() # the "scalar-valued Fourier transform" of this class fcn Indexed sequence: [8, 2, 2] indexed by [(), (1,2), (1,2,3)] - sage: J = AbelianGroup(2,[2,3],names='ab') - sage: s = IndexedSequence([1,2,3,4,5,6],J) + sage: J = AbelianGroup(2, [2,3], names='ab') + sage: s = IndexedSequence([1,2,3,4,5,6], J) sage: s.dft() # the precision of output is somewhat random and architecture dependent. - Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] - indexed by Multiplicative Abelian group isomorphic to C2 x C3 + Indexed sequence: [21.0000000000000, + -2.99999999999997 - 1.73205080756885*I, + -2.99999999999999 + 1.73205080756888*I, + -9.00000000000000 + 0.0000000000000485744257349999*I, + -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, + -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] + indexed by Multiplicative Abelian group isomorphic to C2 x C3 sage: J = CyclicPermutationGroup(6) - sage: s = IndexedSequence([1,2,3,4,5,6],J) + sage: s = IndexedSequence([1,2,3,4,5,6], J) sage: s.dft() # the precision of output is somewhat random and architecture dependent. - Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] - indexed by Cyclic group of order 6 as a permutation group + Indexed sequence: [21.0000000000000, + -2.99999999999997 - 1.73205080756885*I, + -2.99999999999999 + 1.73205080756888*I, + -9.00000000000000 + 0.0000000000000485744257349999*I, + -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, + -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] + indexed by Cyclic group of order 6 as a permutation group + + sage: # needs sage.rings.number_field sage: p = 7; J = list(range(p)); A = [kronecker_symbol(j,p) for j in J] - sage: s = IndexedSequence(A,J) + sage: s = IndexedSequence(A, J) sage: Fs = s.dft() sage: c = Fs.list()[1]; [x/c for x in Fs.list()]; s.list() [0, 1, 1, -1, 1, -1, -1] @@ -337,7 +351,7 @@ def dft(self, chi=lambda x: x): zeta = CyclotomicField(N).gen() FT = [sum([S[i] * chi(zeta**(i * j)) for i in J]) for j in J] elif (J[0] not in ZZ) and G.is_abelian() and F == ZZ or (F.is_field() and F.base_ring() == QQ): - if is_PermutationGroupElement(J[0]): + if isinstance(J[0], PermutationGroupElement): # J is a CyclicPermGp n = G.order() a = list(n.factor()) @@ -365,13 +379,13 @@ def idft(self): sage: J = list(range(5)) sage: A = [ZZ(1) for i in J] sage: s = IndexedSequence(A,J) - sage: fs = s.dft(); fs + sage: fs = s.dft(); fs # needs sage.rings.number_field Indexed sequence: [5, 0, 0, 0, 0] indexed by [0, 1, 2, 3, 4] - sage: it = fs.idft(); it + sage: it = fs.idft(); it # needs sage.rings.number_field Indexed sequence: [1, 1, 1, 1, 1] indexed by [0, 1, 2, 3, 4] - sage: it == s + sage: it == s # needs sage.rings.number_field True """ F = self.base_ring() # elements must be coercible into QQ(zeta_N) @@ -391,18 +405,23 @@ def dct(self): EXAMPLES:: sage: J = list(range(5)) - sage: A = [exp(-2*pi*i*I/5) for i in J] - sage: s = IndexedSequence(A,J) - sage: s.dct() + sage: A = [exp(-2*pi*i*I/5) for i in J] # needs sage.symbolic + sage: s = IndexedSequence(A, J) # needs sage.symbolic + sage: s.dct() # needs sage.symbolic Indexed sequence: [0, 1/16*(sqrt(5) + I*sqrt(-2*sqrt(5) + 10) + ... indexed by [0, 1, 2, 3, 4] """ - from sage.symbolic.constants import pi F = self.base_ring() # elements must be coercible into RR + try: + pi = F.pi() + except AttributeError: + from sage.symbolic.constants import pi + pi = F(pi) + J = self.index_object() # must be = range(N) N = len(J) S = self.list() - PI = 2 * F(pi) / N + PI = 2 * pi / N FT = [sum([S[i] * cos(PI * i * j) for i in J]) for j in J] return IndexedSequence(FT, J) @@ -413,16 +432,21 @@ def dst(self): EXAMPLES:: sage: J = list(range(5)) - sage: I = CC.0; pi = CC(pi) + sage: I = CC.0; pi = CC.pi() sage: A = [exp(-2*pi*i*I/5) for i in J] - sage: s = IndexedSequence(A,J) + sage: s = IndexedSequence(A, J) sage: s.dst() # discrete sine Indexed sequence: [0.000000000000000, 1.11022302462516e-16 - 2.50000000000000*I, ...] indexed by [0, 1, 2, 3, 4] """ - from sage.symbolic.constants import pi F = self.base_ring() # elements must be coercible into RR + try: + pi = F.pi() + except AttributeError: + from sage.symbolic.constants import pi + pi = F(pi) + J = self.index_object() # must be = range(N) N = len(J) S = self.list() @@ -712,6 +736,7 @@ def dwt(self, other="haar", wavelet_k=2): Indexed sequence: [2.82842712474999, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000] indexed by [0, 1, 2, 3, 4, 5, 6, 7] """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR J = self.index_object() # must be = range(N) N = len(J) # must be 1 minus a power of 2 @@ -789,6 +814,7 @@ def idwt(self, other="haar", wavelet_k=2): sage: t.idwt("bspline", 103) == s True """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR J = self.index_object() # must be = range(N) N = len(J) # must be 1 minus a power of 2 diff --git a/src/sage/calculus/transforms/dwt.pyx b/src/sage/calculus/transforms/dwt.pyx index 61e0f83d331..1330f6ac063 100644 --- a/src/sage/calculus/transforms/dwt.pyx +++ b/src/sage/calculus/transforms/dwt.pyx @@ -21,6 +21,7 @@ AUTHOR: # https://www.gnu.org/licenses/ # **************************************************************************** + def WaveletTransform(n, wavelet_type, wavelet_k): r""" This function initializes an GSLDoubleArray of length n which @@ -63,27 +64,28 @@ def WaveletTransform(n, wavelet_type, wavelet_k): sage: for i in range(1, 11): ....: a[i] = 1 ....: a[128-i] = 1 - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # needs sage.plot sage: a.forward_transform() - sage: a.plot().show() + sage: a.plot().show() # needs sage.plot sage: a = WaveletTransform(128,'haar',2) sage: for i in range(1, 11): a[i] = 1; a[128-i] = 1 sage: a.forward_transform() - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # needs sage.plot sage: a = WaveletTransform(128,'bspline_centered',103) sage: for i in range(1, 11): a[i] = 1; a[100+i] = 1 sage: a.forward_transform() - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # needs sage.plot This example gives a simple example of wavelet compression:: + sage: # needs sage.symbolic sage: a = DWT(2048,'daubechies',6) sage: for i in range(2048): a[i]=float(sin((i*5/2048)**2)) - sage: a.plot().show() # long time (7s on sage.math, 2011) + sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot sage: a.forward_transform() sage: for i in range(1800): a[2048-i-1] = 0 sage: a.backward_transform() - sage: a.plot().show() # long time (7s on sage.math, 2011) + sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot """ cdef size_t _n, _k _n = int(n) @@ -94,8 +96,10 @@ def WaveletTransform(n, wavelet_type, wavelet_k): raise NotImplementedError("discrete wavelet transform only implemented when n is a 2-power") return DiscreteWaveletTransform(_n,1,wavelet_type,_k) + DWT = WaveletTransform + cdef class DiscreteWaveletTransform(GSLDoubleArray): """ Discrete wavelet transform class. @@ -143,7 +147,7 @@ cdef class DiscreteWaveletTransform(GSLDoubleArray): x_min = 0 if xmax is None: x_max = self.n - for i from x_min <= i < x_max: + for i in range(x_min, x_max): x = self.data[i] if i > 0: v.append(point([(i, x)], hue=(1, 1, 1), **args)) @@ -151,6 +155,6 @@ cdef class DiscreteWaveletTransform(GSLDoubleArray): def is2pow(unsigned int n): - while n != 0 and n%2 == 0: + while n and not n % 2: n = n >> 1 return n == 1 diff --git a/src/sage/calculus/transforms/fft.pyx b/src/sage/calculus/transforms/fft.pyx index 1ea2cb6b2b2..363fa65a836 100644 --- a/src/sage/calculus/transforms/fft.pyx +++ b/src/sage/calculus/transforms/fft.pyx @@ -10,19 +10,18 @@ AUTHORS: - L.F. Tabera Alonso (2013-3): Documentation """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein <wstein@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.memory cimport sig_malloc, sig_free -import sage.libs.pari.all from sage.rings.integer import Integer from sage.rings.complex_mpfr import ComplexNumber @@ -70,15 +69,17 @@ def FastFourierTransform(size, base_ring=None): ....: a[128-i] = 1 sage: a[:6:2] [(0.0, 0.0), (1.0, 0.0), (1.0, 0.0)] - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # needs sage.plot sage: a.forward_transform() - sage: a.plot().show() + sage: a.plot().show() # needs sage.plot """ return FastFourierTransform_complex(int(size)) + FFT = FastFourierTransform + cdef class FastFourierTransform_base: pass @@ -102,16 +103,15 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: a = FastFourierTransform(1) # indirect doctest sage: a [(0.0, 0.0)] - """ self.n = n self.stride = stride self.data = <double*>sig_malloc(sizeof(double)*(2*n)) cdef int i - for i from 0 <= i < 2*n: + for i in range(2 * n): self.data[i] = 0 - def __dealloc__(self): + def __dealloc__(self): """ Frees allocated memory. @@ -119,7 +119,6 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: a = FastFourierTransform(128) sage: del a - """ sig_free(self.data) @@ -152,6 +151,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): EXAMPLES:: + sage: # needs sage.rings.mpfr sage.symbolic sage: I = CC(I) sage: a = FastFourierTransform(4) sage: a[0] = 1 @@ -243,24 +243,25 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): EXAMPLES:: sage: a = FastFourierTransform(4) - sage: a._plot_polar(0,2) + sage: a._plot_polar(0,2) # needs sage.plot Graphics object consisting of 2 graphics primitives """ from sage.plot.point import point + from sage.symbolic.constants import pi, I cdef int i v = [] - pi = sage.symbolic.constants.pi.n() - I = sage.symbolic.constants.I.n() + pi = pi.n() + I = I.n() s = 1/(3*pi) # so arg gets scaled between -1/3 and 1/3. - for i from xmin <= i < xmax: + for i in range(xmin, xmax): z = self.data[2*i] + I*self.data[2*i+1] mag = z.abs() arg = z.arg()*s - v.append(point((i,mag), hue=arg, **args)) + v.append(point((i, mag), hue=arg, **args)) return sum(v) def _plot_rect(self, xmin, xmax, **args): @@ -282,20 +283,19 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): EXAMPLES:: sage: a = FastFourierTransform(4) - sage: a._plot_rect(0,3) + sage: a._plot_rect(0,3) # needs sage.plot Graphics object consisting of 3 graphics primitives - """ + from sage.plot.point import point + cdef int i - cdef double pr_x, x, h + cdef double x, h v = [] - point = sage.plot.all.point - - for i from xmin <= i < xmax: + for i in range(xmin, xmax): x = self.data[2*i] h = self.data[2*i+1] - v.append(point((i,x), hue=h, **args)) + v.append(point((i, x), hue=h, **args)) return sum(v) def plot(self, style='rect', xmin=None, xmax=None, **args): @@ -303,10 +303,12 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): Plot a slice of the array. - ``style`` -- Style of the plot, options are ``"rect"`` or ``"polar"`` - - ``rect`` -- height represents real part, color represents - imaginary part. - - ``polar`` -- height represents absolute value, color - represents argument. + + - ``rect`` -- height represents real part, color represents + imaginary part. + - ``polar`` -- height represents absolute value, color + represents argument. + - ``xmin`` -- The lower bound of the slice to plot. 0 by default. - ``xmax`` -- The upper bound of the slice to plot. ``len(self)`` by default. - ``**args`` -- passed on to the line plotting function. @@ -319,11 +321,11 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: a = FastFourierTransform(16) sage: for i in range(16): a[i] = (random(),random()) - sage: A = plot(a) - sage: B = plot(a, style='polar') - sage: type(A) + sage: A = plot(a) # needs sage.plot + sage: B = plot(a, style='polar') # needs sage.plot + sage: type(A) # needs sage.plot <class 'sage.plot.graphics.Graphics'> - sage: type(B) + sage: type(B) # needs sage.plot <class 'sage.plot.graphics.Graphics'> sage: a = FastFourierTransform(125) sage: b = FastFourierTransform(125) @@ -331,7 +333,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: (a.plot()+b.plot()) + sage: a.plot() + b.plot() # needs sage.plot Graphics object consisting of 250 graphics primitives """ @@ -409,7 +411,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: (a.plot()+b.plot()) + sage: a.plot() + b.plot() # needs sage.plot Graphics object consisting of 250 graphics primitives sage: abs(sum([CDF(a[i])-CDF(b[i]) for i in range(125)])) < 2**-16 True @@ -422,7 +424,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: (a.plot()+b.plot()) + sage: a.plot() + b.plot() # needs sage.plot Graphics object consisting of 256 graphics primitives """ @@ -460,7 +462,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.backward_transform() - sage: (a.plot() + b.plot()).show(ymin=0) # long time (2s on sage.math, 2011) + sage: (a.plot() + b.plot()).show(ymin=0) # long time (2s on sage.math, 2011), needs sage.plot sage: abs(sum([CDF(a[i])/125-CDF(b[i]) for i in range(125)])) < 2**-16 True @@ -472,7 +474,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.backward_transform() - sage: (a.plot() + b.plot()).show(ymin=0) + sage: (a.plot() + b.plot()).show(ymin=0) # needs sage.plot """ cdef gsl_fft_complex_wavetable * wt cdef gsl_fft_complex_workspace * mem diff --git a/src/sage/calculus/var.pyx b/src/sage/calculus/var.pyx index ed7a4305188..84f7a16a91f 100644 --- a/src/sage/calculus/var.pyx +++ b/src/sage/calculus/var.pyx @@ -36,7 +36,7 @@ def var(*args, **kwds): If a single symbolic variable was created, the variable itself. Otherwise, a tuple of symbolic variables. The variable names are checked to be valid Python identifiers and a - ``ValueError`` is raised otherwise. + :class:`ValueError` is raised otherwise. EXAMPLES: @@ -384,10 +384,12 @@ def clear_vars(): sage: k 15 """ + from sage.structure.element import Expression + G = globals() - from sage.symbolic.ring import is_SymbolicVariable for i in list(range(65, 65 + 26)) + list(range(97, 97 + 26)): - if chr(i) in G and is_SymbolicVariable(G[chr(i)]): + chr_i = chr(i) + if chr_i in G and isinstance(G[chr_i], Expression) and G[chr_i].is_symbol(): # We check to see if there is a corresponding pyobject # associated with the expression. This will work for # constants which we want to keep, but will fail for diff --git a/src/sage/calculus/wester.py b/src/sage/calculus/wester.py index 0a2a374cd5f..e33409a49ac 100644 --- a/src/sage/calculus/wester.py +++ b/src/sage/calculus/wester.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic r""" Further examples from Wester's paper @@ -168,6 +169,7 @@ :: sage: # (YES) Factorize x^4-3*x^2+1 in the field of rational numbers extended by roots of x^2-x-1. + sage: x = polygen(ZZ, 'x') sage: k.< a> = NumberField(x^2 - x -1) sage: R.< y> = k[] sage: f = y^4 - 3*y^2 + 1 @@ -226,16 +228,16 @@ sage: # Maxima doesn't solve inequalities sage: # (but some Maxima packages do): sage: eqn = abs(x-1) > 2 - sage: eqn - abs(x - 1) > 2 + sage: eqn.solve(x) + [[x < -1], [3 < x]] :: sage: # (NO) Solve the inequality (x-1)*...*(x-5)<0. sage: eqn = prod(x-i for i in range(1,5 +1)) < 0 sage: # but don't know how to solve - sage: eqn - (x - 1)*(x - 2)*(x - 3)*(x - 4)*(x - 5) < 0 + sage: eqn.solve(x) + [[x < 1], [x > 2, x < 3], [x > 4, x < 5]] :: diff --git a/src/sage/categories/action.pyx b/src/sage/categories/action.pyx index b15cebde220..b3244f766d4 100644 --- a/src/sage/categories/action.pyx +++ b/src/sage/categories/action.pyx @@ -21,7 +21,8 @@ A group action `G \times S \rightarrow S` is a functor from `G` to Sets. sage: import gc sage: _ = gc.collect() sage: A - <repr(<sage.categories.action.Action at 0x...>) failed: RuntimeError: This action acted on a set that became garbage collected> + <repr(<sage.categories.action.Action at 0x...>) failed: + RuntimeError: This action acted on a set that became garbage collected> To avoid garbage collection of the underlying set, it is sufficient to create a strong reference to it before the action is created. @@ -43,15 +44,15 @@ AUTHOR: - Robert Bradshaw: initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Robert Bradshaw <robertwb@math.washington.edu> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cpython.tuple cimport PyTuple_GET_ITEM @@ -62,9 +63,7 @@ from sage.structure.element cimport parent from sage.structure.parent cimport Parent from . import homset -import sage.structure.element from weakref import ref -from sage.misc.constant_function import ConstantFunction cdef inline category(x): @@ -243,8 +242,8 @@ cdef class Action(Functor): def _repr_(self): side = "Left" if self._is_left else "Right" - return "%s %s by %r on %r"%(side, self._repr_name_(), self.G, - self.underlying_set()) + return "%s %s by %r on %r" % (side, self._repr_name_(), self.G, + self.underlying_set()) def _repr_name_(self): return "action" @@ -267,15 +266,17 @@ cdef class Action(Functor): sage: R = (ZZ['x'])['y'] sage: A = R.get_action(P,operator.mul,True) sage: A # indirect doctest - Right scalar multiplication by Univariate Polynomial Ring in x over - Rational Field on Univariate Polynomial Ring in y over Univariate - Polynomial Ring in x over Integer Ring + Right scalar multiplication + by Univariate Polynomial Ring in x over Rational Field + on Univariate Polynomial Ring in y over + Univariate Polynomial Ring in x over Integer Ring In this example, the underlying set is the ring ``R``. This is the same as the left domain, which is different from the codomain of the action:: sage: A.codomain() - Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + Univariate Polynomial Ring in y + over Univariate Polynomial Ring in x over Rational Field sage: A.codomain() == R False sage: A.left_domain() is R @@ -296,7 +297,8 @@ cdef class Action(Functor): sage: import gc sage: _ = gc.collect() sage: A - <repr(<sage.categories.action.Action at 0x...>) failed: RuntimeError: This action acted on a set that became garbage collected> + <repr(<sage.categories.action.Action at 0x...>) failed: + RuntimeError: This action acted on a set that became garbage collected> """ S = self.US() if S is None: @@ -331,23 +333,29 @@ cdef class InverseAction(Action): EXAMPLES:: - sage: V = QQ^3 - sage: v = V((1, 2, 3)) + sage: V = QQ^3 # needs sage.modules + sage: v = V((1, 2, 3)) # needs sage.modules sage: cm = get_coercion_model() + sage: # needs sage.modules sage: a = cm.get_action(V, QQ, operator.mul) sage: a - Right scalar multiplication by Rational Field on Vector space of dimension 3 over Rational Field + Right scalar multiplication by Rational Field + on Vector space of dimension 3 over Rational Field sage: ~a - Right inverse action by Rational Field on Vector space of dimension 3 over Rational Field + Right inverse action by Rational Field + on Vector space of dimension 3 over Rational Field sage: (~a)(v, 1/3) (3, 6, 9) + sage: # needs sage.modules sage: b = cm.get_action(QQ, V, operator.mul) sage: b - Left scalar multiplication by Rational Field on Vector space of dimension 3 over Rational Field + Left scalar multiplication by Rational Field + on Vector space of dimension 3 over Rational Field sage: ~b - Left inverse action by Rational Field on Vector space of dimension 3 over Rational Field + Left inverse action by Rational Field + on Vector space of dimension 3 over Rational Field sage: (~b)(1/3, v) (3, 6, 9) @@ -392,6 +400,7 @@ cdef class InverseAction(Action): Check that this action can be pickled (:trac:`29031`):: + sage: # needs sage.modules sage: V = QQ^3 sage: v = V((1, 2, 3)) sage: cm = get_coercion_model() @@ -426,6 +435,7 @@ cdef class PrecomposedAction(Action): We demonstrate that an example discussed on :trac:`14711` did not become a problem:: + sage: # needs sage.modular sage: E = ModularSymbols(11).2 sage: s = E.modular_symbol_rep() sage: del E,s @@ -436,8 +446,9 @@ cdef class PrecomposedAction(Action): sage: c,x = v[0] sage: y = x.modular_symbol_rep() sage: coercion_model.get_action(QQ, parent(y), op=operator.mul) - Left scalar multiplication by Rational Field on Abelian Group of all Formal Finite Sums over Rational Field - with precomposition on right by Coercion map: + Left scalar multiplication by Rational Field + on Abelian Group of all Formal Finite Sums over Rational Field + with precomposition on right by Coercion map: From: Abelian Group of all Formal Finite Sums over Integer Ring To: Abelian Group of all Formal Finite Sums over Rational Field """ @@ -476,6 +487,7 @@ cdef class PrecomposedAction(Action): Check that this action can be pickled (:trac:`29031`):: + sage: # needs sage.modular sage: E = ModularSymbols(11).2 sage: v = E.manin_symbol_rep() sage: c,x = v[0] @@ -544,8 +556,8 @@ cdef class ActionEndomorphism(Morphism): sage: A = ZZ['x'].get_action(QQ, self_on_left=False, op=operator.mul) sage: A - Left scalar multiplication by Rational Field on Univariate Polynomial - Ring in x over Integer Ring + Left scalar multiplication by Rational Field + on Univariate Polynomial Ring in x over Integer Ring sage: A(1/2) Action of 1/2 on Univariate Polynomial Ring in x over Integer Ring under Left scalar multiplication by Rational Field on Univariate @@ -604,8 +616,9 @@ cdef class ActionEndomorphism(Morphism): return self._action._act_(self._g, x) def _repr_(self): - return "Action of %s on %s under %s."%(self._g, - self._action.underlying_set(), self._action) + return "Action of %s on %s under %s." % (self._g, + self._action.underlying_set(), + self._action) def __mul__(left, right): cdef ActionEndomorphism left_c, right_c diff --git a/src/sage/categories/additive_magmas.py b/src/sage/categories/additive_magmas.py index 8d2c46d0771..b39441fe84d 100644 --- a/src/sage/categories/additive_magmas.py +++ b/src/sage/categories/additive_magmas.py @@ -33,7 +33,10 @@ class AdditiveMagmas(Category_singleton): sage: AdditiveMagmas().super_categories() [Category of sets] sage: AdditiveMagmas().all_super_categories() - [Category of additive magmas, Category of sets, Category of sets with partial maps, Category of objects] + [Category of additive magmas, + Category of sets, + Category of sets with partial maps, + Category of objects] The following axioms are defined by this category:: @@ -45,11 +48,11 @@ class AdditiveMagmas(Category_singleton): Category of additive commutative additive magmas sage: AdditiveMagmas().AdditiveUnital().AdditiveInverse() Category of additive inverse additive unital additive magmas - sage: AdditiveMagmas().AdditiveAssociative().AdditiveCommutative() + sage: C = AdditiveMagmas().AdditiveAssociative().AdditiveCommutative(); C Category of commutative additive semigroups - sage: AdditiveMagmas().AdditiveAssociative().AdditiveCommutative().AdditiveUnital() + sage: C.AdditiveUnital() Category of commutative additive monoids - sage: AdditiveMagmas().AdditiveAssociative().AdditiveCommutative().AdditiveUnital().AdditiveInverse() + sage: C.AdditiveUnital().AdditiveInverse() Category of commutative additive groups TESTS:: @@ -112,9 +115,10 @@ def AdditiveCommutative(self): sage: AdditiveMagmas().AdditiveCommutative() Category of additive commutative additive magmas - sage: AdditiveMagmas().AdditiveAssociative().AdditiveUnital().AdditiveCommutative() + sage: C = AdditiveMagmas().AdditiveAssociative().AdditiveUnital() + sage: C.AdditiveCommutative() Category of commutative additive monoids - sage: _ is CommutativeAdditiveMonoids() + sage: C.AdditiveCommutative() is CommutativeAdditiveMonoids() True TESTS:: @@ -279,7 +283,7 @@ def addition_table(self, names='letters', elements=None): elements as lowercase ASCII letters. :: sage: R = IntegerModRing(5) - sage: R.addition_table() + sage: R.addition_table() # needs sage.modules + a b c d e +---------- a| a b c d e @@ -294,8 +298,7 @@ def addition_table(self, names='letters', elements=None): ``digits`` will include leading zeros as padding. :: sage: R = IntegerModRing(11) - sage: P = R.addition_table(names='elements') - sage: P + sage: P = R.addition_table(names='elements'); P # needs sage.modules + 0 1 2 3 4 5 6 7 8 9 10 +--------------------------------- 0| 0 1 2 3 4 5 6 7 8 9 10 @@ -310,8 +313,7 @@ def addition_table(self, names='letters', elements=None): 9| 9 10 0 1 2 3 4 5 6 7 8 10| 10 0 1 2 3 4 5 6 7 8 9 - sage: T = R.addition_table(names='digits') - sage: T + sage: T = R.addition_table(names='digits'); T # needs sage.modules + 00 01 02 03 04 05 06 07 08 09 10 +--------------------------------- 00| 00 01 02 03 04 05 06 07 08 09 10 @@ -331,7 +333,7 @@ def addition_table(self, names='letters', elements=None): sage: S = IntegerModRing(7) sage: elts = [0, 3, 6, 2, 5, 1, 4] - sage: S.addition_table(elements=elts) + sage: S.addition_table(elements=elts) # needs sage.modules + a b c d e f g +-------------- a| a b c d e f g @@ -351,8 +353,8 @@ def addition_table(self, names='letters', elements=None): representation. :: sage: T = IntegerModRing(12) - sage: elts=[0, 3, 6, 9] - sage: T.addition_table(names='elements', elements=elts) + sage: elts = [0, 3, 6, 9] + sage: T.addition_table(names='elements', elements=elts) # needs sage.modules + 0 3 6 9 +-------- 0| 0 3 6 9 @@ -365,6 +367,7 @@ def addition_table(self, names='letters', elements=None): :class:`~sage.matrix.operation_table.OperationTable` for more comprehensive documentation. :: + sage: # needs sage.modules sage: R = IntegerModRing(3) sage: T = R.addition_table() sage: T.column_keys() @@ -471,16 +474,17 @@ def _add_(self, right): r""" EXAMPLES:: - sage: G5=GF(5); G8=GF(4,'x'); GG = G5.cartesian_product(G8) - sage: e = GG((G5(1),G8.primitive_element())); e + sage: # needs sage.rings.finite_rings + sage: G5 = GF(5); G8 = GF(4, 'x'); GG = G5.cartesian_product(G8) + sage: e = GG((G5(1), G8.primitive_element())); e (1, x) - sage: e+e + sage: e + e (2, 0) - sage: e = groups.misc.AdditiveCyclic(8) - sage: x = e.cartesian_product(e)((e(1),e(2))) + sage: e = groups.misc.AdditiveCyclic(8) # needs sage.groups + sage: x = e.cartesian_product(e)((e(1), e(2))) sage: x (1, 2) - sage: 4*x + sage: 4 * x (4, 0) """ return self.parent()._cartesian_product_of_elements( @@ -497,7 +501,8 @@ def extra_super_categories(self): [Category of magmatic algebras with basis over Rational Field] sage: AdditiveMagmas().Algebras(QQ).super_categories() - [Category of magmatic algebras with basis over Rational Field, Category of set algebras over Rational Field] + [Category of magmatic algebras with basis over Rational Field, + Category of set algebras over Rational Field] """ from sage.categories.magmatic_algebras import MagmaticAlgebras return [MagmaticAlgebras(self.base_ring()).WithBasis()] @@ -516,9 +521,10 @@ def algebra_generators(self): EXAMPLES:: sage: S = CommutativeAdditiveSemigroups().example(); S - An example of a commutative semigroup: the free commutative semigroup generated by ('a', 'b', 'c', 'd') - sage: A = S.algebra(QQ) - sage: A.algebra_generators() + An example of a commutative semigroup: + the free commutative semigroup generated by ('a', 'b', 'c', 'd') + sage: A = S.algebra(QQ) # needs sage.modules + sage: A.algebra_generators() # needs sage.modules Family (B[a], B[b], B[c], B[d]) .. TODO:: @@ -541,10 +547,11 @@ def product_on_basis(self, g1, g2): EXAMPLES:: sage: S = CommutativeAdditiveSemigroups().example(); S - An example of a commutative semigroup: the free commutative semigroup generated by ('a', 'b', 'c', 'd') - sage: A = S.algebra(QQ) - sage: a,b,c,d = A.algebra_generators() - sage: a * d * b + An example of a commutative semigroup: + the free commutative semigroup generated by ('a', 'b', 'c', 'd') + sage: A = S.algebra(QQ) # needs sage.modules + sage: a, b, c, d = A.algebra_generators() # needs sage.modules + sage: a * d * b # needs sage.modules B[a + b + d] .. TODO:: @@ -580,10 +587,11 @@ def extra_super_categories(self): EXAMPLES:: - sage: AdditiveMagmas().AdditiveCommutative().Algebras(QQ).extra_super_categories() + sage: C = AdditiveMagmas().AdditiveCommutative().Algebras(QQ) + sage: C.extra_super_categories() [Category of commutative magmas] - sage: AdditiveMagmas().AdditiveCommutative().Algebras(QQ).super_categories() + sage: C.super_categories() [Category of additive magma algebras over Rational Field, Category of commutative magmas] """ @@ -718,7 +726,8 @@ def is_empty(self): EXAMPLES:: - sage: A = AdditiveAbelianGroup([3,3]) + sage: # needs sage.modules + sage: A = AdditiveAbelianGroup([3, 3]) sage: A in AdditiveMagmas() True sage: A.is_empty() @@ -733,7 +742,7 @@ def is_empty(self): We check that the method ``is_empty`` is inherited from this category in both examples above:: - sage: A.is_empty.__module__ + sage: A.is_empty.__module__ # needs sage.modules 'sage.categories.additive_magmas' sage: B.is_empty.__module__ 'sage.categories.additive_magmas' @@ -801,9 +810,9 @@ def _sub_(left, right): EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ, ['a','b']) - sage: a,b = F.basis() - sage: a - b + sage: F = CombinatorialFreeModule(QQ, ['a', 'b']) # needs sage.modules + sage: a, b = F.basis() # needs sage.modules + sage: a - b # needs sage.modules B['a'] - B['b'] TESTS: @@ -827,17 +836,18 @@ def __neg__(self): EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ, ['a','b']) - sage: a,b = F.basis() - sage: - b + sage: F = CombinatorialFreeModule(QQ, ['a', 'b']) # needs sage.modules + sage: a, b = F.basis() # needs sage.modules + sage: -b # needs sage.modules -B['b'] TESTS:: - sage: F = CombinatorialFreeModule(ZZ, ['a','b']) - sage: a,b = F.gens() - sage: FF = cartesian_product((F,F)) - sage: x = cartesian_product([a,2*a-3*b]) ; x + sage: # needs sage.modules + sage: F = CombinatorialFreeModule(ZZ, ['a', 'b']) + sage: a, b = F.gens() + sage: FF = cartesian_product((F, F)) + sage: x = cartesian_product([a, 2*a-3*b]); x B[(0, 'a')] + 2*B[(1, 'a')] - 3*B[(1, 'b')] sage: x.parent() is FF True @@ -911,14 +921,15 @@ def _neg_(self): EXAMPLES:: - sage: x = cartesian_product((GF(7)(2),17)) ; x + sage: x = cartesian_product((GF(7)(2), 17)); x (2, 17) sage: -x (5, -17) TESTS:: - sage: x.parent() in AdditiveMagmas().AdditiveUnital().AdditiveInverse().CartesianProducts() + sage: C = AdditiveMagmas().AdditiveUnital().AdditiveInverse().CartesianProducts() + sage: x.parent() in C True """ return self.parent()._cartesian_product_of_elements( @@ -947,7 +958,7 @@ def zero(self): EXAMPLES:: - sage: GF(8,'x').cartesian_product(GF(5)).zero() + sage: GF(8, 'x').cartesian_product(GF(5)).zero() # needs sage.rings.finite_rings (0, 0) """ return self._cartesian_product_of_elements( @@ -964,7 +975,8 @@ def extra_super_categories(self): [Category of unital magmas] sage: C.super_categories() - [Category of unital algebras with basis over Rational Field, Category of additive magma algebras over Rational Field] + [Category of unital algebras with basis over Rational Field, + Category of additive magma algebras over Rational Field] """ from sage.categories.magmas import Magmas return [Magmas().Unital()] @@ -981,8 +993,10 @@ def one_basis(self): EXAMPLES:: + sage: # needs sage.modules sage: S = CommutativeAdditiveMonoids().example(); S - An example of a commutative monoid: the free commutative monoid generated by ('a', 'b', 'c', 'd') + An example of a commutative monoid: + the free commutative monoid generated by ('a', 'b', 'c', 'd') sage: A = S.algebra(ZZ) sage: A.one_basis() 0 @@ -1007,17 +1021,17 @@ def zero(self): EXAMPLES:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: A.zero.__module__ + sage: A.zero.__module__ # needs sage.modules 'sage.categories.additive_magmas' - sage: A.zero() + sage: A.zero() # needs sage.modules 0 TESTS:: - sage: A.zero() is A.a_realization().zero() + sage: A.zero() is A.a_realization().zero() # needs sage.modules True - sage: A._test_zero() + sage: A._test_zero() # needs sage.modules """ return self.a_realization().zero() diff --git a/src/sage/categories/additive_semigroups.py b/src/sage/categories/additive_semigroups.py index 0527867154b..038221fe5be 100644 --- a/src/sage/categories/additive_semigroups.py +++ b/src/sage/categories/additive_semigroups.py @@ -150,9 +150,10 @@ def algebra_generators(self): EXAMPLES:: sage: S = CommutativeAdditiveSemigroups().example(); S - An example of a commutative semigroup: the free commutative semigroup generated by ('a', 'b', 'c', 'd') - sage: A = S.algebra(QQ) - sage: A.algebra_generators() + An example of a commutative semigroup: + the free commutative semigroup generated by ('a', 'b', 'c', 'd') + sage: A = S.algebra(QQ) # needs sage.modules + sage: A.algebra_generators() # needs sage.modules Family (B[a], B[b], B[c], B[d]) """ return self.basis().keys().additive_semigroup_generators().map(self.monomial) @@ -169,10 +170,11 @@ def product_on_basis(self, g1, g2): EXAMPLES:: sage: S = CommutativeAdditiveSemigroups().example(); S - An example of a commutative semigroup: the free commutative semigroup generated by ('a', 'b', 'c', 'd') - sage: A = S.algebra(QQ) - sage: a,b,c,d = A.algebra_generators() - sage: b * d * c + An example of a commutative semigroup: + the free commutative semigroup generated by ('a', 'b', 'c', 'd') + sage: A = S.algebra(QQ) # needs sage.modules + sage: a, b, c, d = A.algebra_generators() # needs sage.modules + sage: b * d * c # needs sage.modules B[b + c + d] """ return self.monomial(g1 + g2) diff --git a/src/sage/categories/affine_weyl_groups.py b/src/sage/categories/affine_weyl_groups.py index 285fe9e45ab..4eeea88b6c3 100644 --- a/src/sage/categories/affine_weyl_groups.py +++ b/src/sage/categories/affine_weyl_groups.py @@ -14,7 +14,6 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets - class AffineWeylGroups(Category_singleton): """ The category of affine Weyl groups @@ -35,9 +34,9 @@ class AffineWeylGroups(Category_singleton): sage: C.example() NotImplemented - sage: W = WeylGroup(["A",4,1]); W + sage: W = WeylGroup(["A", 4, 1]); W # needs sage.combinat sage.groups Weyl Group of type ['A', 4, 1] (as a matrix group acting on the root space) - sage: W.category() + sage: W.category() # needs sage.combinat sage.groups Category of irreducible affine weyl groups TESTS:: @@ -82,8 +81,8 @@ def special_node(self): EXAMPLES:: - sage: W = WeylGroup(['A',3,1]) - sage: W.special_node() + sage: W = WeylGroup(['A', 3, 1]) # needs sage.combinat sage.groups + sage: W.special_node() # needs sage.combinat sage.groups 0 """ return self.cartan_type().special_node() @@ -96,8 +95,9 @@ def affine_grassmannian_elements_of_given_length(self, k): EXAMPLES:: - sage: W = WeylGroup(['A',3,1]) - sage: [x.reduced_word() for x in W.affine_grassmannian_elements_of_given_length(3)] + sage: W = WeylGroup(['A', 3, 1]) # needs sage.combinat sage.groups + sage: [x.reduced_word() # needs sage.combinat sage.groups + ....: for x in W.affine_grassmannian_elements_of_given_length(3)] [[2, 1, 0], [3, 1, 0], [2, 3, 0]] .. SEEALSO:: @@ -137,7 +137,8 @@ def is_affine_grassmannian(self): EXAMPLES:: - sage: W = WeylGroup(['A',3,1]) + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['A', 3, 1]) sage: w = W.from_reduced_word([2,1,0]) sage: w.is_affine_grassmannian() True @@ -169,7 +170,8 @@ def affine_grassmannian_to_core(self): EXAMPLES:: - sage: W = WeylGroup(['A',2,1]) + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['A', 2, 1]) sage: w = W.from_reduced_word([0,2,1,0]) sage: la = w.affine_grassmannian_to_core(); la [4, 2] @@ -178,8 +180,8 @@ def affine_grassmannian_to_core(self): sage: la.to_grassmannian() == w True - sage: w = W.from_reduced_word([0,2,1]) - sage: w.affine_grassmannian_to_core() + sage: w = W.from_reduced_word([0,2,1]) # needs sage.combinat sage.groups + sage: w.affine_grassmannian_to_core() # needs sage.combinat sage.groups Traceback (most recent call last): ... ValueError: this only works on type 'A' affine Grassmannian elements @@ -214,8 +216,9 @@ def affine_grassmannian_to_partition(self): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: k = 2 - sage: W = WeylGroup(['A',k,1]) + sage: W = WeylGroup(['A', k, 1]) sage: w = W.from_reduced_word([0,2,1,0]) sage: la = w.affine_grassmannian_to_partition(); la [2, 2] diff --git a/src/sage/categories/algebra_functor.py b/src/sage/categories/algebra_functor.py index d9b4872b129..dd56f26895f 100644 --- a/src/sage/categories/algebra_functor.py +++ b/src/sage/categories/algebra_functor.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.groups r""" Group algebras and beyond: the Algebra functorial construction @@ -631,7 +631,7 @@ def _apply_functor_to_morphism(self, f): 2*() + 2*(2,3) + (1,2,3) + 4*(1,3,2) """ from sage.categories.rings import Rings - domain = self(f.domain()) + domain = self(f.domain()) codomain = self(f.codomain()) # we would want to use something like: # domain.module_morphism(on_coefficients=h, codomain=codomain, category=Rings()) diff --git a/src/sage/categories/algebra_ideals.py b/src/sage/categories/algebra_ideals.py index 1d6fe32c9c3..1d6e3775e7b 100644 --- a/src/sage/categories/algebra_ideals.py +++ b/src/sage/categories/algebra_ideals.py @@ -10,8 +10,10 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from .category_types import Category_ideal from .algebra_modules import AlgebraModules +from .algebras import Algebras +from .rings import Rings +from .category_types import Category_ideal class AlgebraIdeals(Category_ideal): @@ -48,9 +50,14 @@ def __init__(self, A): sage: TestSuite(AlgebraIdeals(QQ['a'])).run() """ - from sage.algebras.algebra import is_Algebra - if not is_Algebra(A): # A not in Algebras() ? - raise TypeError("A (=%s) must be an algebra"%A) + try: + base_ring = A.base_ring() + except AttributeError: + raise TypeError(f"A (={A}) must be an algebra") + else: + if base_ring not in Rings() or A not in Algebras(base_ring.category()): + raise TypeError(f"A (={A}) must be an algebra") + Category_ideal.__init__(self, A) def algebra(self): @@ -72,9 +79,10 @@ def super_categories(self): EXAMPLES:: sage: AlgebraIdeals(QQ['x']).super_categories() - [Category of algebra modules over Univariate Polynomial Ring in x over Rational Field] - sage: C = AlgebraIdeals(FreeAlgebra(QQ,2,'a,b')) - sage: C.super_categories() + [Category of algebra modules + over Univariate Polynomial Ring in x over Rational Field] + sage: C = AlgebraIdeals(FreeAlgebra(QQ, 2, 'a,b')) # needs sage.combinat sage.modules + sage: C.super_categories() # needs sage.combinat sage.modules [] """ @@ -82,6 +90,6 @@ def super_categories(self): try: if R.is_commutative(): return [AlgebraModules(R)] - except (AttributeError,NotImplementedError): + except (AttributeError, NotImplementedError): pass return [] diff --git a/src/sage/categories/algebra_modules.py b/src/sage/categories/algebra_modules.py index 2472989723d..7be7de2c471 100644 --- a/src/sage/categories/algebra_modules.py +++ b/src/sage/categories/algebra_modules.py @@ -11,6 +11,8 @@ #****************************************************************************** from .category_types import Category_module +from .commutative_algebras import CommutativeAlgebras +from .commutative_rings import CommutativeRings from .modules import Modules class AlgebraModules(Category_module): @@ -37,7 +39,7 @@ def __init__(self, A): sage: AlgebraModules(QQ['a']) Category of algebra modules over Univariate Polynomial Ring in a over Rational Field sage: AlgebraModules(QQ['a,b']) # todo: not implemented (QQ['a,b'] should be in Algebras(QQ)) - sage: AlgebraModules(FreeAlgebra(QQ,2,'a,b')) + sage: AlgebraModules(FreeAlgebra(QQ, 2, 'a,b')) # needs sage.combinat sage.modules Traceback (most recent call last): ... TypeError: A (=Free Algebra on 2 generators (a, b) over Rational Field) must be a commutative algebra @@ -50,9 +52,14 @@ def __init__(self, A): sage: TestSuite(AlgebraModules(QQ['a'])).run() """ - from sage.categories.commutative_algebras import CommutativeAlgebras - if not hasattr(A, "base_ring") or A not in CommutativeAlgebras(A.base_ring()): - raise TypeError("A (=%s) must be a commutative algebra" % A) + try: + base_ring = A.base_ring() + except AttributeError: + raise TypeError(f"A (={A}) must be a commutative algebra") + else: + if base_ring not in CommutativeRings() or A not in CommutativeAlgebras(base_ring.category()): + raise TypeError(f"A (={A}) must be a commutative algebra") + Category_module.__init__(self, A) @classmethod diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 253d64a2819..d93a51d28bd 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -68,9 +68,9 @@ def __contains__(self, x): sage: QQ['x'] in Algebras(QQ) True - sage: QQ^3 in Algebras(QQ) + sage: QQ^3 in Algebras(QQ) # needs sage.modules False - sage: QQ['x'] in Algebras(CDF) + sage: QQ['x'] in Algebras(CDF) # needs sage.rings.complex_double False """ if super().__contains__(x): @@ -154,12 +154,12 @@ def _div_(self, y): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: C = AlgebrasWithBasis(QQ).example() sage: x = C(2); x 2*B[word: ] sage: y = C.algebra_generators().first(); y B[word: a] - sage: y._div_(x) 1/2*B[word: a] sage: x._div_(y) @@ -182,6 +182,7 @@ def algebra_generators(self): EXAMPLES:: + sage: # needs sage.graphs sage.modules sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver @@ -215,9 +216,8 @@ def extra_super_categories(self): sage: C.extra_super_categories() [Category of algebras over Rational Field] sage: sorted(C.super_categories(), key=str) - [Category of Cartesian products of distributive magmas and additive magmas, - Category of Cartesian products of monoids, - Category of Cartesian products of vector spaces over Rational Field, + [Category of Cartesian products of monoids, + Category of Cartesian products of unital algebras over Rational Field, Category of algebras over Rational Field] """ return [self.base_category()] diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index dbd7a9a43a1..28177a1ff45 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -33,35 +33,37 @@ class AlgebrasWithBasis(CategoryWithAxiom_over_base_ring): We construct a typical parent in this category, and do some computations with it:: - sage: A = C.example(); A - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field + sage: A = C.example(); A # needs sage.combinat sage.modules + An example of an algebra with basis: + the free algebra on the generators ('a', 'b', 'c') over Rational Field - sage: A.category() + sage: A.category() # needs sage.combinat sage.modules Category of algebras with basis over Rational Field - sage: A.one_basis() + sage: A.one_basis() # needs sage.combinat sage.modules word: - sage: A.one() + sage: A.one() # needs sage.combinat sage.modules B[word: ] - sage: A.base_ring() + sage: A.base_ring() # needs sage.combinat sage.modules Rational Field - sage: A.basis().keys() + sage: A.basis().keys() # needs sage.combinat sage.modules Finite words over {'a', 'b', 'c'} - sage: (a,b,c) = A.algebra_generators() - sage: a^3, b^2 + sage: (a,b,c) = A.algebra_generators() # needs sage.combinat sage.modules + sage: a^3, b^2 # needs sage.combinat sage.modules (B[word: aaa], B[word: bb]) - sage: a*c*b + sage: a * c * b # needs sage.combinat sage.modules B[word: acb] - sage: A.product + sage: A.product # needs sage.combinat sage.modules <bound method MagmaticAlgebras.WithBasis.ParentMethods._product_from_product_on_basis_multiply of - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field> - sage: A.product(a*b,b) + An example of an algebra with basis: + the free algebra on the generators ('a', 'b', 'c') over Rational Field> + sage: A.product(a * b, b) # needs sage.combinat sage.modules B[word: abb] - sage: TestSuite(A).run(verbose=True) + sage: TestSuite(A).run(verbose=True) # needs sage.combinat sage.modules running ._test_additive_associativity() . . . pass running ._test_an_element() . . . pass running ._test_associativity() . . . pass @@ -91,9 +93,9 @@ class AlgebrasWithBasis(CategoryWithAxiom_over_base_ring): running ._test_prod() . . . pass running ._test_some_elements() . . . pass running ._test_zero() . . . pass - sage: A.__class__ + sage: A.__class__ # needs sage.combinat sage.modules <class 'sage.categories.examples.algebras_with_basis.FreeAlgebra_with_category'> - sage: A.element_class + sage: A.element_class # needs sage.combinat sage.modules <class 'sage.categories.examples.algebras_with_basis.FreeAlgebra_with_category.element_class'> Please see the source code of `A` (with ``A??``) for how to @@ -110,13 +112,15 @@ def example(self, alphabet=('a','b','c')): EXAMPLES:: - sage: AlgebrasWithBasis(QQ).example() - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field + sage: AlgebrasWithBasis(QQ).example() # needs sage.combinat sage.modules + An example of an algebra with basis: + the free algebra on the generators ('a', 'b', 'c') over Rational Field An other set of generators can be specified as optional argument:: - sage: AlgebrasWithBasis(QQ).example((1,2,3)) - An example of an algebra with basis: the free algebra on the generators (1, 2, 3) over Rational Field + sage: AlgebrasWithBasis(QQ).example((1,2,3)) # needs sage.combinat sage.modules + An example of an algebra with basis: + the free algebra on the generators (1, 2, 3) over Rational Field """ from sage.categories.examples.algebras_with_basis import Example return Example(self.base_ring(), alphabet) @@ -143,12 +147,12 @@ def hochschild_complex(self, M): EXAMPLES:: sage: R.<x> = QQ[] - sage: A = algebras.DifferentialWeyl(R) - sage: H = A.hochschild_complex(A) + sage: A = algebras.DifferentialWeyl(R) # needs sage.modules + sage: H = A.hochschild_complex(A) # needs sage.modules - sage: SGA = SymmetricGroupAlgebra(QQ, 3) - sage: T = SGA.trivial_representation() - sage: H = SGA.hochschild_complex(T) + sage: SGA = SymmetricGroupAlgebra(QQ, 3) # needs sage.combinat sage.modules + sage: T = SGA.trivial_representation() # needs sage.combinat sage.modules + sage: H = SGA.hochschild_complex(T) # needs sage.combinat sage.modules """ from sage.homology.hochschild_complex import HochschildComplex return HochschildComplex(self, M) @@ -176,6 +180,7 @@ def __invert__(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: C = AlgebrasWithBasis(QQ).example() sage: x = C(2); x 2*B[word: ] @@ -226,7 +231,8 @@ class ParentMethods: @cached_method def one_from_cartesian_product_of_one_basis(self): """ - Returns the one of this Cartesian product of algebras, as per ``Monoids.ParentMethods.one`` + Return the one of this Cartesian product of algebras, as per + ``Monoids.ParentMethods.one`` It is constructed as the Cartesian product of the ones of the summands, using their :meth:`~AlgebrasWithBasis.ParentMethods.one_basis` methods. @@ -237,18 +243,20 @@ def one_from_cartesian_product_of_one_basis(self): EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).example(); A - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field - sage: A.one_basis() + sage: A = AlgebrasWithBasis(QQ).example(); A # needs sage.combinat sage.modules + An example of an algebra with basis: the free algebra + on the generators ('a', 'b', 'c') over Rational Field + sage: A.one_basis() # needs sage.combinat sage.modules word: - sage: B = cartesian_product((A, A, A)) - sage: B.one_from_cartesian_product_of_one_basis() + sage: B = cartesian_product((A, A, A)) # needs sage.combinat sage.modules + sage: B.one_from_cartesian_product_of_one_basis() # needs sage.combinat sage.modules B[(0, word: )] + B[(1, word: )] + B[(2, word: )] - sage: B.one() + sage: B.one() # needs sage.combinat sage.modules B[(0, word: )] + B[(1, word: )] + B[(2, word: )] - sage: cartesian_product([SymmetricGroupAlgebra(QQ, 3), SymmetricGroupAlgebra(QQ, 4)]).one() + sage: cartesian_product([SymmetricGroupAlgebra(QQ, 3), # needs sage.combinat sage.modules + ....: SymmetricGroupAlgebra(QQ, 4)]).one() B[(0, [1, 2, 3])] + B[(1, [1, 2, 3, 4])] """ return self.sum_of_monomials( zip( self._sets_keys(), (set.one_basis() for set in self._sets)) ) @@ -258,23 +266,24 @@ def one(self): """ TESTS:: - sage: A = AlgebrasWithBasis(QQ).example(); A - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field - sage: B = cartesian_product((A, A, A)) - sage: B.one() + sage: A = AlgebrasWithBasis(QQ).example(); A # needs sage.combinat sage.modules + An example of an algebra with basis: the free algebra + on the generators ('a', 'b', 'c') over Rational Field + sage: B = cartesian_product((A, A, A)) # needs sage.combinat sage.modules + sage: B.one() # needs sage.combinat sage.modules B[(0, word: )] + B[(1, word: )] + B[(2, word: )] """ - if all(hasattr(module, "one_basis") for module in self._sets): + if all(hasattr(module, "one_basis") and module.one_basis is not NotImplemented for module in self._sets): return self.one_from_cartesian_product_of_one_basis - else: - return NotImplemented + return self._one_generic + + _one_generic = UnitalAlgebras.CartesianProducts.ParentMethods.one # def product_on_basis(self, t1, t2): # would be easy to implement, but without a special # version of module morphism, this would not take # advantage of the block structure - class TensorProducts(TensorProductsCategory): """ The category of algebras with basis constructed by tensor product of algebras with basis @@ -311,8 +320,10 @@ def one_basis(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = AlgebrasWithBasis(QQ).example(); A - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field + An example of an algebra with basis: the free algebra + on the generators ('a', 'b', 'c') over Rational Field sage: A.one_basis() word: sage: B = tensor((A, A, A)) @@ -336,23 +347,25 @@ def product_on_basis(self, t1, t2): EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).example(); A - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field - sage: (a,b,c) = A.algebra_generators() + sage: A = AlgebrasWithBasis(QQ).example(); A # needs sage.combinat sage.modules + An example of an algebra with basis: the free algebra + on the generators ('a', 'b', 'c') over Rational Field + sage: (a,b,c) = A.algebra_generators() # needs sage.combinat sage.modules - sage: x = tensor( (a, b, c) ); x + sage: x = tensor((a, b, c)); x # needs sage.combinat sage.modules B[word: a] # B[word: b] # B[word: c] - sage: y = tensor( (c, b, a) ); y + sage: y = tensor((c, b, a)); y # needs sage.combinat sage.modules B[word: c] # B[word: b] # B[word: a] - sage: x*y + sage: x * y # needs sage.combinat sage.modules B[word: ac] # B[word: bb] # B[word: ca] - sage: x = tensor( ((a+2*b), c) ) ; x + sage: x = tensor(((a + 2*b), c)); x # needs sage.combinat sage.modules B[word: a] # B[word: c] + 2*B[word: b] # B[word: c] - sage: y = tensor( (c, a) ) + 1; y + sage: y = tensor((c, a)) + 1; y # needs sage.combinat sage.modules B[word: ] # B[word: ] + B[word: c] # B[word: a] - sage: x*y - B[word: a] # B[word: c] + B[word: ac] # B[word: ca] + 2*B[word: b] # B[word: c] + 2*B[word: bc] # B[word: ca] + sage: x * y # needs sage.combinat sage.modules + B[word: a] # B[word: c] + B[word: ac] # B[word: ca] + + 2*B[word: b] # B[word: c] + 2*B[word: bc] # B[word: ca] TODO: optimize this implementation! diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index e70914295af..b927766568b 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Bialgebras """ @@ -10,7 +11,8 @@ # ***************************************************************************** from sage.categories.category_types import Category_over_base_ring -from sage.categories.all import Algebras, Coalgebras +from sage.categories.algebras import Algebras +from sage.categories.coalgebras import Coalgebras from sage.categories.super_modules import SuperModulesCategory from sage.misc.lazy_import import LazyImport @@ -67,6 +69,7 @@ def is_primitive(self): EXAMPLES:: + sage: # needs sage.modules sage: s = SymmetricFunctions(QQ).schur() sage: s([5]).is_primitive() False @@ -83,10 +86,10 @@ def is_grouplike(self): EXAMPLES:: - sage: s = SymmetricFunctions(QQ).schur() - sage: s([5]).is_grouplike() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.modules + sage: s([5]).is_grouplike() # needs sage.modules False - sage: s([]).is_grouplike() + sage: s([]).is_grouplike() # needs sage.modules True """ return self.coproduct() == self.tensor(self) diff --git a/src/sage/categories/bialgebras_with_basis.py b/src/sage/categories/bialgebras_with_basis.py index 831bab3f068..36dd5fccf2a 100644 --- a/src/sage/categories/bialgebras_with_basis.py +++ b/src/sage/categories/bialgebras_with_basis.py @@ -92,6 +92,7 @@ def convolution_product(self, *maps): with the projection ``Proj2`` on the Hopf algebra of non-commutative symmetric functions:: + sage: # needs sage.combinat sage.modules sage: R = NonCommutativeSymmetricFunctions(QQ).ribbon() sage: T = R.convolution_product([Id, Id]) sage: [T(R(comp)) for comp in Compositions(3)] @@ -107,17 +108,18 @@ def convolution_product(self, *maps): symmetric functions in non-commuting variables. This is the composition of the counit with the unit:: - sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() - sage: T = m.convolution_product() - sage: [T(m(lam)) for lam in SetPartitions(0).list() + SetPartitions(2).list()] + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() # needs sage.combinat sage.modules + sage: T = m.convolution_product() # needs sage.combinat sage.modules + sage: [T(m(lam)) # needs sage.combinat sage.modules + ....: for lam in SetPartitions(0).list() + SetPartitions(2).list()] [m{}, 0, 0] Compute the convolution product of the projection ``Proj2`` with the identity on the Hopf algebra of symmetric functions in non-commuting variables:: - sage: T = m.convolution_product(Proj2, Id) - sage: [T(m(lam)) for lam in SetPartitions(3)] + sage: T = m.convolution_product(Proj2, Id) # needs sage.combinat sage.modules + sage: [T(m(lam)) for lam in SetPartitions(3)] # needs sage.combinat sage.modules [0, m{{1, 2}, {3}} + m{{1, 2, 3}}, m{{1, 2}, {3}} + m{{1, 2, 3}}, @@ -127,9 +129,13 @@ def convolution_product(self, *maps): Compute the convolution product of the antipode with itself and the identity map on group algebra of the symmetric group:: + sage: # needs sage.combinat sage.groups sage: G = SymmetricGroup(3) sage: QG = GroupAlgebra(G, QQ) - sage: x = QG.sum_of_terms([(p,p.number_of_peaks() + p.number_of_inversions()) for p in Permutations(3)]); x + sage: x = QG.sum_of_terms( + ....: [(p, p.number_of_peaks() + p.number_of_inversions()) + ....: for p in Permutations(3)] + ....: ); x 2*[1, 3, 2] + [2, 1, 3] + 3*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] sage: T = QG.convolution_product(Antipode, Antipode, Id) sage: T(x) @@ -168,6 +174,7 @@ def adams_operator(self, n): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: h = SymmetricFunctions(QQ).h() sage: h[5].adams_operator(2) 2*h[3, 2] + 2*h[4, 1] + 2*h[5] @@ -184,15 +191,16 @@ def adams_operator(self, n): :: - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S[4].adams_operator(5) - 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] + sage: S = NonCommutativeSymmetricFunctions(QQ).S() # needs sage.combinat sage.modules + sage: S[4].adams_operator(5) # needs sage.combinat sage.modules + 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] :: - sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() - sage: m[[1,3],[2]].adams_operator(-2) + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() # needs sage.combinat sage.modules + sage: m[[1,3],[2]].adams_operator(-2) # needs sage.combinat sage.modules 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} """ if n < 0: @@ -254,18 +262,18 @@ def convolution_product(self, *maps): sage: Id = lambda x: x sage: Antipode = lambda x: x.antipode() - sage: s = SymmetricFunctions(QQ).schur() - sage: s[3].convolution_product(Id, Id) + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: s[3].convolution_product(Id, Id) # needs sage.combinat sage.modules 2*s[2, 1] + 4*s[3] - sage: s[3,2].convolution_product(Id) == s[3,2] + sage: s[3,2].convolution_product(Id) == s[3,2] # needs sage.combinat sage.modules True The method accepts multiple arguments, or a single argument consisting of a list of maps:: - sage: s[3,2].convolution_product(Id, Id) + sage: s[3,2].convolution_product(Id, Id) # needs sage.combinat sage.modules 2*s[2, 1, 1, 1] + 6*s[2, 2, 1] + 6*s[3, 1, 1] + 12*s[3, 2] + 6*s[4, 1] + 2*s[5] - sage: s[3,2].convolution_product([Id, Id]) + sage: s[3,2].convolution_product([Id, Id]) # needs sage.combinat sage.modules 2*s[2, 1, 1, 1] + 6*s[2, 2, 1] + 6*s[3, 1, 1] + 12*s[3, 2] + 6*s[4, 1] + 2*s[5] We test the defining property of the antipode morphism; namely, @@ -273,28 +281,32 @@ def convolution_product(self, *maps): convolution algebra whose identity element is the composition of the counit and unit:: - sage: s[3,2].convolution_product() == s[3,2].convolution_product(Antipode, Id) == s[3,2].convolution_product(Id, Antipode) + sage: (s[3,2].convolution_product() # needs sage.combinat sage.modules + ....: == s[3,2].convolution_product(Antipode, Id) + ....: == s[3,2].convolution_product(Id, Antipode)) True :: - sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() - sage: Psi[2,1].convolution_product(Id, Id, Id) + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() # needs sage.combinat sage.modules + sage: Psi[2,1].convolution_product(Id, Id, Id) # needs sage.combinat sage.modules 3*Psi[1, 2] + 6*Psi[2, 1] - sage: (Psi[5,1] - Psi[1,5]).convolution_product(Id, Id, Id) + sage: (Psi[5,1] - Psi[1,5]).convolution_product(Id, Id, Id) # needs sage.combinat sage.modules -3*Psi[1, 5] + 3*Psi[5, 1] :: + sage: # needs sage.combinat sage.modules sage: G = SymmetricGroup(3) - sage: QG = GroupAlgebra(G,QQ) - sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x + sage: QG = GroupAlgebra(G, QQ) + sage: x = QG.sum_of_terms([(p, p.length()) + ....: for p in Permutations(3)]); x [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] sage: x.convolution_product(Id, Id) 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] sage: x.convolution_product(Id, Id, Id) 4*[1, 2, 3] + [1, 3, 2] + [2, 1, 3] + 3*[3, 2, 1] - sage: x.convolution_product([Id]*6) + sage: x.convolution_product([Id] * 6) 9*[1, 2, 3] TESTS:: @@ -304,6 +316,7 @@ def convolution_product(self, *maps): :: + sage: # needs sage.combinat sage.modules sage: h = SymmetricFunctions(QQ).h() sage: h[5].convolution_product([Id, Id]) 2*h[3, 2] + 2*h[4, 1] + 2*h[5] @@ -311,18 +324,20 @@ def convolution_product(self, *maps): h[] sage: h[3,2].convolution_product([Id, Antipode]) 0 - sage: h.one().convolution_product([Id, Antipode]) == h.one().convolution_product() + sage: (h.one().convolution_product([Id, Antipode]) + ....: == h.one().convolution_product()) True :: - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S[4].convolution_product([Id]*5) + sage: S = NonCommutativeSymmetricFunctions(QQ).S() # needs sage.combinat sage.modules + sage: S[4].convolution_product([Id] * 5) # needs sage.combinat sage.modules 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] :: + sage: # needs sage.combinat sage.modules sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() sage: m[[1,3],[2]].convolution_product([Antipode, Antipode]) 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} @@ -333,8 +348,9 @@ def convolution_product(self, *maps): :: + sage: # needs sage.combinat sage.modules sage: QS = SymmetricGroupAlgebra(QQ, 5) - sage: x = QS.sum_of_terms(zip(Permutations(5)[3:6],[1,2,3])); x + sage: x = QS.sum_of_terms(zip(Permutations(5)[3:6], [1,2,3])); x [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] sage: x.convolution_product([Antipode, Id]) 6*[1, 2, 3, 4, 5] @@ -343,9 +359,11 @@ def convolution_product(self, *maps): :: + sage: # needs sage.combinat sage.modules sage: G = SymmetricGroup(3) - sage: QG = GroupAlgebra(G,QQ) - sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x + sage: QG = GroupAlgebra(G, QQ) + sage: x = QG.sum_of_terms([(p, p.length()) + ....: for p in Permutations(3)]); x [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] sage: x.convolution_product(Antipode, Id) 9*[1, 2, 3] @@ -354,7 +372,8 @@ def convolution_product(self, *maps): :: - sage: s[3,2].counit().parent() == s[3,2].convolution_product().parent() + sage: (s[3,2].counit().parent() # needs sage.combinat sage.modules + ....: == s[3,2].convolution_product().parent()) False """ # Be flexible on how the maps are entered: accept a list/tuple of diff --git a/src/sage/categories/bimodules.py b/src/sage/categories/bimodules.py index d85af83880d..eccadf20a02 100644 --- a/src/sage/categories/bimodules.py +++ b/src/sage/categories/bimodules.py @@ -103,7 +103,7 @@ def an_instance(cls): EXAMPLES:: - sage: Bimodules.an_instance() + sage: Bimodules.an_instance() # needs sage.rings.real_mpfr Category of bimodules over Rational Field on the left and Real Field with 53 bits of precision on the right """ from sage.rings.rational_field import QQ @@ -118,7 +118,7 @@ def _repr_object_names(self): Category of bimodules over Rational Field on the left and Integer Ring on the right """ return "bimodules over %s on the left and %s on the right" \ - %(self._left_base_ring, self._right_base_ring) + % (self._left_base_ring, self._right_base_ring) def left_base_ring(self): """ diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index e6fbf670750..d7b380b2598 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -16,7 +16,7 @@ from sage.categories.covariant_functorial_construction import CovariantFunctorialConstruction, CovariantConstructionCategory from sage.categories.pushout import MultivariateConstructionFunctor -native_python_containers = set([tuple, list, set, frozenset, range]) +native_python_containers = set([tuple, list, set, frozenset, range]) class CartesianProductFunctor(CovariantFunctorialConstruction, MultivariateConstructionFunctor): """ @@ -155,7 +155,7 @@ def __call__(self, args, **kwds): sage: _.category() Category of Cartesian products of finite enumerated sets - Check that the empty product is handled correctly: + Check that the empty product is handled correctly:: sage: C = cartesian_product([]) sage: C @@ -242,7 +242,7 @@ def _repr_object_names(self): """ # This method is only required for the capital `C` - return "Cartesian products of %s"%(self.base_category()._repr_object_names()) + return "Cartesian products of %s" % (self.base_category()._repr_object_names()) def CartesianProducts(self): """ @@ -271,6 +271,7 @@ def base_ring(self): """ return self.base_category().base_ring() + # Moved to avoid circular imports lazy_import('sage.categories.sets_cat', 'cartesian_product') """ diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index f70455cf1a0..57ef7f4184b 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -22,7 +22,7 @@ sage: Sets() Category of sets - sage: GSets(AbelianGroup([2,4,9])) + sage: GSets(AbelianGroup([2, 4, 9])) # needs sage.groups Category of G-sets for Multiplicative Abelian group isomorphic to C2 x C4 x C9 sage: Semigroups() Category of semigroups @@ -33,37 +33,38 @@ Let's request the category of some objects:: - sage: V = VectorSpace(RationalField(), 3) - sage: V.category() + sage: V = VectorSpace(RationalField(), 3) # needs sage.modules + sage: V.category() # needs sage.modules Category of finite dimensional vector spaces with basis over (number fields and quotient fields and metric spaces) - sage: G = SymmetricGroup(9) - sage: G.category() - Join of Category of finite enumerated permutation groups and - Category of finite weyl groups and - Category of well generated finite irreducible complex reflection groups + sage: G = SymmetricGroup(9) # needs sage.groups + sage: G.category() # needs sage.groups + Join of + Category of finite enumerated permutation groups and + Category of finite weyl groups and + Category of well generated finite irreducible complex reflection groups - sage: P = PerfectMatchings(3) - sage: P.category() + sage: P = PerfectMatchings(3) # needs sage.combinat + sage: P.category() # needs sage.combinat Category of finite enumerated sets Let's check some memberships:: - sage: V in VectorSpaces(QQ) + sage: V in VectorSpaces(QQ) # needs sage.modules True - sage: V in VectorSpaces(FiniteField(11)) + sage: V in VectorSpaces(FiniteField(11)) # needs sage.modules False - sage: G in Monoids() + sage: G in Monoids() # needs sage.groups True - sage: P in Rings() + sage: P in Rings() # needs sage.combinat False For parametrized categories one can use the following shorthand:: - sage: V in VectorSpaces + sage: V in VectorSpaces # needs sage.modules True - sage: G in VectorSpaces + sage: G in VectorSpaces # needs sage.groups False A parent ``P`` is in a category ``C`` if ``P.category()`` is a subcategory of @@ -83,11 +84,11 @@ True By default, the category of an element `x` of a parent `P` is the category - of all objects of `P` (this is dubious an may be deprecated):: + of all objects of `P` (this is dubious and may be deprecated):: - sage: V = VectorSpace(RationalField(), 3) - sage: v = V.gen(1) - sage: v.category() + sage: V = VectorSpace(RationalField(), 3) # needs sage.modules + sage: v = V.gen(1) # needs sage.modules + sage: v.category() # needs sage.modules Category of elements of Vector space of dimension 3 over Rational Field """ @@ -153,7 +154,7 @@ class Category(UniqueRepresentation, SageObject): This is achieved as follows:: - sage: from sage.categories.all import Category + sage: from sage.categories.category import Category sage: class EuclideanDomains(Category): ....: # operations on the category itself ....: def super_categories(self): @@ -201,7 +202,7 @@ class inheritance from ``C.parent_class``. :: - sage: from sage.categories.all import Category + sage: from sage.categories.category import Category sage: from sage.misc.lazy_attribute import lazy_attribute sage: class As (Category): ....: def super_categories(self): @@ -308,7 +309,8 @@ class inheritance from ``C.parent_class``. sage: Ds().parent_class.__bases__ (<class '__main__.Cs.parent_class'>, <class '__main__.Bs.parent_class'>) sage: Ds().parent_class.mro() - [<class '__main__.Ds.parent_class'>, <class '__main__.Cs.parent_class'>, <class '__main__.Bs.parent_class'>, <class '__main__.As.parent_class'>, <... 'object'>] + [<class '__main__.Ds.parent_class'>, <class '__main__.Cs.parent_class'>, + <class '__main__.Bs.parent_class'>, <class '__main__.As.parent_class'>, <... 'object'>] Note that two categories in the same class need not have the same ``super_categories``. For example, ``Algebras(QQ)`` has @@ -564,10 +566,12 @@ def an_instance(cls): sage: Algebras.an_instance() Category of algebras over Rational Field - sage: Bimodules.an_instance() - Category of bimodules over Rational Field on the left and Real Field with 53 bits of precision on the right + sage: Bimodules.an_instance() # needs sage.rings.real_mpfr + Category of bimodules over Rational Field on the left + and Real Field with 53 bits of precision on the right sage: AlgebraIdeals.an_instance() - Category of algebra ideals in Univariate Polynomial Ring in x over Rational Field + Category of algebra ideals + in Univariate Polynomial Ring in x over Rational Field """ return cls() @@ -625,7 +629,7 @@ def _latex_(self): sage: latex(CommutativeAdditiveSemigroups()) \mathbf{CommutativeAdditiveSemigroups} """ - return "\\mathbf{%s}"%self._short_name() + return "\\mathbf{%s}" % self._short_name() # The convention for which hash function to use should be decided at the level of UniqueRepresentation # The implementation below is bad (hash independent of the base ring) @@ -724,15 +728,15 @@ def __classcontains__(cls, x): This method makes it easy to test if an object is, say, a vector space, without having to specify the base ring:: - sage: F = FreeModule(QQ,3) - sage: F in VectorSpaces + sage: F = FreeModule(QQ, 3) # needs sage.modules + sage: F in VectorSpaces # needs sage.modules True - sage: F = FreeModule(ZZ,3) - sage: F in VectorSpaces + sage: F = FreeModule(ZZ, 3) # needs sage.modules + sage: F in VectorSpaces # needs sage.modules False - sage: F in Algebras + sage: F in Algebras # needs sage.modules False TESTS: @@ -798,14 +802,14 @@ def category_graph(self): EXAMPLES:: sage: C = Algebras(QQ) - sage: G = C.category_graph() - sage: G.is_directed_acyclic() + sage: G = C.category_graph() # needs sage.graphs + sage: G.is_directed_acyclic() # needs sage.graphs True The girth of a directed acyclic graph is infinite, however, the girth of the underlying undirected graph is 4 in this case:: - sage: Graph(G).girth() + sage: Graph(G).girth() # needs sage.graphs 4 """ return category_graph([self]) @@ -929,7 +933,7 @@ def _set_of_super_categories(self): TESTS:: sage: C = HopfAlgebrasWithBasis(GF(7)) - sage: C._set_of_super_categories == frozenset(C._all_super_categories_proper) + sage: C._set_of_super_categories == set(C._all_super_categories_proper) True """ return frozenset(self._all_super_categories_proper) @@ -1448,9 +1452,9 @@ def _test_category(self, **options): from sage.categories.sets_cat import Sets tester = self._tester(**options) tester.assertTrue(isinstance(self.super_categories(), list), - "%s.super_categories() should return a list"%self) + "%s.super_categories() should return a list" % self) tester.assertTrue(self.is_subcategory(Objects()), - "%s is not a subcategory of Objects()"%self) + "%s is not a subcategory of Objects()" % self) tester.assertTrue(isinstance(self.parent_class, type)) tester.assertTrue(all(not isinstance(cat, JoinCategory) for cat in self._super_categories)) if not isinstance(self, JoinCategory): @@ -1470,7 +1474,6 @@ def _test_category(self, **options): _cmp_key = _cmp_key - ########################################################################## # Construction of the associated abstract classes for parents, elements, ... ########################################################################## @@ -1577,7 +1580,7 @@ def _make_named_class(self, name, method_provider, cache=False, picklable=True): cls = self.__class__ if isinstance(cls, DynamicMetaclass): cls = cls.__base__ - class_name = "%s.%s"%(cls.__name__, name) + class_name = "%s.%s" % (cls.__name__, name) method_provider_cls = getattr(self, method_provider, None) if method_provider_cls is None: # If the category provides no XXXMethods class, @@ -1586,10 +1589,10 @@ def _make_named_class(self, name, method_provider, cache=False, picklable=True): else: # Otherwise, check XXXMethods assert inspect.isclass(method_provider_cls),\ - "%s.%s should be a class"%(cls.__name__, method_provider) + "%s.%s should be a class" % (cls.__name__, method_provider) mro = inspect.getmro(method_provider_cls) if len(mro) > 2 or (len(mro) == 2 and mro[1] is not object): - warn("%s.%s should not have a super class"%(cls.__name__, method_provider)) + warn("%s.%s should not have a super class" % (cls.__name__, method_provider)) # and point the documentation to it doccls = method_provider_cls if picklable: @@ -1790,8 +1793,8 @@ def is_subcategory(self, c): :: sage: M3 = VectorSpaces(FiniteField(3)) - sage: M9 = VectorSpaces(FiniteField(9, 'a')) - sage: M3.is_subcategory(M9) + sage: M9 = VectorSpaces(FiniteField(9, 'a')) # needs sage.rings.finite_rings + sage: M3.is_subcategory(M9) # needs sage.rings.finite_rings False Join categories are properly handled:: @@ -1853,7 +1856,8 @@ def or_subcategory(self, category=None, join=False): sage: Monoids().or_subcategory(EnumeratedSets()) Traceback (most recent call last): ... - ValueError: Subcategory of `Category of monoids` required; got `Category of enumerated sets` + ValueError: Subcategory of `Category of monoids` required; + got `Category of enumerated sets` Otherwise, the two categories are joined together:: @@ -2078,7 +2082,8 @@ def _with_axiom(self, axiom): <class 'sage.categories.category.JoinCategory_with_category'> sage: Magmas().Finite().Commutative().super_categories() [Category of commutative magmas, Category of finite sets] - sage: Algebras(QQ).WithBasis().Commutative() is Algebras(QQ).Commutative().WithBasis() + sage: C = Algebras(QQ).WithBasis().Commutative() + sage: C is Algebras(QQ).Commutative().WithBasis() True When ``axiom`` is not defined for ``self``, ``self`` is returned:: @@ -2253,7 +2258,9 @@ def _sort(categories): Category of commutative magmas, Category of finite sets, Category of facade sets) - sage: Category._sort(Category._flatten_categories([Sets().Finite(), Algebras(QQ).WithBasis(), Semigroups().Finite(), Sets().Facade(),Algebras(QQ).Commutative(), Algebras(QQ).Graded().WithBasis()], sage.categories.category.JoinCategory)) + sage: Category._sort(Category._flatten_categories([Sets().Finite(), Algebras(QQ).WithBasis(), Semigroups().Finite(), + ....: Sets().Facade(), Algebras(QQ).Commutative(), Algebras(QQ).Graded().WithBasis()], + ....: sage.categories.category.JoinCategory)) (Category of algebras with basis over Rational Field, Category of algebras with basis over Rational Field, Category of graded algebras over Rational Field, @@ -2598,7 +2605,7 @@ def category_sample(): EXAMPLES:: sage: from sage.categories.category import category_sample - sage: sorted(category_sample(), key=str) + sage: sorted(category_sample(), key=str) # needs sage.groups [Category of G-sets for Symmetric group of order 8! as a permutation group, Category of Hecke modules over Rational Field, Category of Lie algebras over Rational Field, @@ -2637,14 +2644,14 @@ def category_graph(categories=None): EXAMPLES:: - sage: G = sage.categories.category.category_graph(categories = [Groups()]) - sage: G.vertices(sort=True) + sage: G = sage.categories.category.category_graph(categories=[Groups()]) # needs sage.graphs + sage: G.vertices(sort=True) # needs sage.graphs ['groups', 'inverse unital magmas', 'magmas', 'monoids', 'objects', 'semigroups', 'sets', 'sets with partial maps', 'unital magmas'] - sage: G.plot() + sage: G.plot() # needs sage.graphs sage.plot Graphics object consisting of 20 graphics primitives - sage: sage.categories.category.category_graph().plot() + sage: sage.categories.category.category_graph().plot() # needs sage.graphs sage.plot Graphics object consisting of ... graphics primitives """ from sage import graphs @@ -2745,9 +2752,9 @@ def _make_named_class(self, name, method_provider, cache=False, **options): The categories of bimodules over the fields ``CC`` or ``RR`` provide the same methods to their parents and elements:: - sage: Bimodules(ZZ,RR).parent_class is Bimodules(ZZ,RDF).parent_class #indirect doctest + sage: Bimodules(ZZ,RR).parent_class is Bimodules(ZZ,RDF).parent_class # indirect doctest True - sage: Bimodules(CC,ZZ).element_class is Bimodules(RR,ZZ).element_class + sage: Bimodules(CC,ZZ).element_class is Bimodules(RR,ZZ).element_class # needs sage.rings.real_mpfr True On the other hand, modules over a field have more methods than @@ -2761,7 +2768,7 @@ def _make_named_class(self, name, method_provider, cache=False, **options): For a more subtle example, one could possibly share the classes for ``GF(3)`` and ``GF(2^3, 'x')``, but this is not currently the case:: - sage: Modules(GF(3)).parent_class is Modules(GF(2^3,'x')).parent_class + sage: Modules(GF(3)).parent_class is Modules(GF(2^3,'x')).parent_class # needs sage.rings.finite_rings False This is because those two fields do not have the exact same category:: @@ -2770,7 +2777,7 @@ def _make_named_class(self, name, method_provider, cache=False, **options): Join of Category of finite enumerated fields and Category of subquotients of monoids and Category of quotients of semigroups - sage: GF(2^3,'x').category() + sage: GF(2^3,'x').category() # needs sage.rings.finite_rings Category of finite enumerated fields Similarly for ``QQ`` and ``RR``:: @@ -2780,15 +2787,17 @@ def _make_named_class(self, name, method_provider, cache=False, **options): and Category of quotient fields and Category of metric spaces sage: RR.category() - Join of Category of fields and Category of infinite sets and Category of complete metric spaces + Join of Category of fields and Category of infinite sets + and Category of complete metric spaces sage: Modules(QQ).parent_class is Modules(RR).parent_class False Some other cases where one could potentially share those classes:: - sage: Modules(GF(3),dispatch=False).parent_class is Modules(ZZ).parent_class + sage: MF = Modules(GF(3), dispatch=False) + sage: MF.parent_class is Modules(ZZ).parent_class False - sage: Modules(GF(3),dispatch=False).element_class is Modules(ZZ).element_class + sage: MF.element_class is Modules(ZZ).element_class False TESTS:: @@ -2817,7 +2826,6 @@ def _make_named_class(self, name, method_provider, cache=False, **options): self._make_named_class_cache[key] = result return result - @abstract_method def _make_named_class_key(self, name): r""" @@ -2920,6 +2928,7 @@ class JoinCategory(CategoryWithParameters): the underlying implementation is the same for all finite fields, we have:: + sage: # needs sage.groups sage.rings.finite_rings sage: G = SymmetricGroup(10) sage: A3 = G.algebra(GF(3)) sage: A5 = G.algebra(GF(5)) diff --git a/src/sage/categories/category_cy_helper.pxd b/src/sage/categories/category_cy_helper.pxd index d0c833d9fe8..f50ce4e8226 100644 --- a/src/sage/categories/category_cy_helper.pxd +++ b/src/sage/categories/category_cy_helper.pxd @@ -1,6 +1,6 @@ cpdef tuple _sort_uniq(categories) cdef class AxiomContainer(dict): - pass + pass cpdef tuple canonicalize_axioms(AxiomContainer all_axioms, axioms) from sage.misc.classcall_metaclass cimport ClasscallMetaclass cpdef tuple _flatten_categories(categories, ClasscallMetaclass JoinCategory) diff --git a/src/sage/categories/category_cy_helper.pyx b/src/sage/categories/category_cy_helper.pyx index 135b015fc1c..1d0c5a2ad41 100644 --- a/src/sage/categories/category_cy_helper.pyx +++ b/src/sage/categories/category_cy_helper.pyx @@ -19,7 +19,7 @@ AUTHOR: #***************************************************************************** ####################################### -## Sorting +# Sorting cpdef inline tuple category_sort_key(object category): """ @@ -106,7 +106,7 @@ cpdef tuple _flatten_categories(categories, ClasscallMetaclass JoinCategory): return tuple(out) ############################################# -## Join +# Join cdef bint is_supercategory_of_done(new_cat, dict done): # This is a helper function. It replaces the closure @@ -164,7 +164,7 @@ cpdef tuple join_as_tuple(tuple categories, tuple axioms, tuple ignore_axioms): axs = axs | {axiom} done[category] = axs for axiom in axiomsS.difference(axs): - todo.add( (category, axiom) ) + todo.add((category, axiom)) # Invariants: # - the current list of categories is stored in the keys of ``done`` @@ -198,7 +198,7 @@ cpdef tuple join_as_tuple(tuple categories, tuple axioms, tuple ignore_axioms): # Mark old categories with new axioms as todo for category in done: for axiom in new_axioms: - todo.add( (category, axiom) ) + todo.add((category, axiom)) for new_cat in new_cats: axs = new_cat.axioms() for (cat, axiom) in ignore_axioms: @@ -206,13 +206,13 @@ cpdef tuple join_as_tuple(tuple categories, tuple axioms, tuple ignore_axioms): axs = axs | {axiom} done[new_cat] = axs for axiom in axiomsS.difference(axs): - todo.add( (new_cat, axiom) ) + todo.add((new_cat, axiom)) return _sort_uniq(done) ############################################# -## Axiom related functions +# Axiom related functions cdef class AxiomContainer(dict): """ diff --git a/src/sage/categories/category_singleton.pyx b/src/sage/categories/category_singleton.pyx index 1a5095e6017..543ce0375f7 100644 --- a/src/sage/categories/category_singleton.pyx +++ b/src/sage/categories/category_singleton.pyx @@ -9,13 +9,11 @@ Singleton categories # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.misc.cachefunc import cached_method, cached_function from sage.misc.constant_function import ConstantFunction -from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute +from sage.misc.lazy_attribute import lazy_class_attribute from sage.categories.category import Category from sage.structure.category_object cimport CategoryObject from sage.structure.dynamic_class import DynamicMetaclass -from sage.structure.unique_representation import UniqueRepresentation from cpython.type cimport PyType_IsSubtype @@ -83,6 +81,7 @@ cdef class Category_contains_method_by_parent_class: except AttributeError: return False + class Category_singleton(Category): """ A base class for implementing singleton category @@ -136,13 +135,14 @@ class Category_singleton(Category): One sees that containment tests for the singleton class is a lot faster than for a usual class:: - sage: timeit("R in MyRings()", number=10000) # not tested + sage: # not tested + sage: timeit("R in MyRings()", number=10000) 10000 loops, best of 3: 7.12 ยตs per loop - sage: timeit("R1 in MyRings()", number=10000) # not tested + sage: timeit("R1 in MyRings()", number=10000) 10000 loops, best of 3: 6.98 ยตs per loop - sage: timeit("R in MyRingsSingleton()", number=10000) # not tested + sage: timeit("R in MyRingsSingleton()", number=10000) 10000 loops, best of 3: 3.08 ยตs per loop - sage: timeit("R2 in MyRingsSingleton()", number=10000) # not tested + sage: timeit("R2 in MyRingsSingleton()", number=10000) 10000 loops, best of 3: 2.99 ยตs per loop So this is an improvement, but not yet competitive with a pure diff --git a/src/sage/categories/category_types.py b/src/sage/categories/category_types.py index 4469a57a996..cb18dcd42c0 100644 --- a/src/sage/categories/category_types.py +++ b/src/sage/categories/category_types.py @@ -72,12 +72,13 @@ def _call_(self, x): """ EXAMPLES:: - sage: V = VectorSpace(QQ,3) + sage: # needs sage.modules + sage: V = VectorSpace(QQ, 3) sage: x = V.0 sage: C = x.category() sage: C Category of elements of Vector space of dimension 3 over Rational Field - sage: w = C([1,2,3]); w # indirect doctest + sage: w = C([1, 2, 3]); w # indirect doctest (1, 2, 3) sage: w.category() Category of elements of Vector space of dimension 3 over Rational Field @@ -123,18 +124,18 @@ def _repr_object_names(self): sage: Elements(ZZ)._repr_object_names() 'elements of Integer Ring' """ - return "elements of %s"%self.object() + return "elements of %s" % self.object() def _latex_(self): r""" EXAMPLES:: - sage: V = VectorSpace(QQ,3) - sage: x = V.0 - sage: latex(x.category()) # indirect doctest + sage: V = VectorSpace(QQ, 3) # needs sage.modules + sage: x = V.0 # needs sage.modules + sage: latex(x.category()) # indirect doctest # needs sage.modules \mathbf{Elt}_{\Bold{Q}^{3}} """ - return "\\mathbf{Elt}_{%s}"%latex(self.__object) + return "\\mathbf{Elt}_{%s}" % latex(self.__object) ############################################################# @@ -289,7 +290,7 @@ def _repr_object_names(self): name = base._repr_object_names() else: name = base - return Category._repr_object_names(self) + " over %s"%name + return Category._repr_object_names(self) + " over %s" % name def _latex_(self): r""" @@ -298,7 +299,7 @@ def _latex_(self): sage: latex(ModulesWithBasis(ZZ)) \mathbf{ModulesWithBasis}_{\Bold{Z}} """ - return "\\mathbf{%s}_{%s}"%(self._label, latex(self.__base)) + return "\\mathbf{%s}_{%s}" % (self._label, latex(self.__base)) # def construction(self): # return (self.__class__, self.__base) @@ -399,6 +400,8 @@ def _subcategory_hook_(self, C): sage: VectorSpaces(QQ)._subcategory_hook_(VectorSpaces(QQ) & Rings()) Unknown + + sage: # needs sage.combinat sage.modules sage: Sym = SymmetricFunctions(QQ) sage: from sage.combinat.sf.sfa import SymmetricFunctionsBases sage: Modules(QQ)._subcategory_hook_(SymmetricFunctionsBases(Sym)) @@ -411,7 +414,7 @@ def _subcategory_hook_(self, C): sage: VectorSpaces(Fields())._subcategory_hook_(Algebras(Fields())) True - sage: VectorSpaces(Fields())._subcategory_hook_(Algebras(Fields().Finite())) # todo: not implemented + sage: VectorSpaces(Fields())._subcategory_hook_(Algebras(Fields().Finite())) # todo: not implemented True sage: VectorSpaces(Fields().Finite())._subcategory_hook_(Algebras(Fields())) False @@ -419,7 +422,7 @@ def _subcategory_hook_(self, C): Case 2: the base of ``self`` is a category; then the base of ``C`` shall be a parent in this category:: - sage: VectorSpaces(Fields())._subcategory_hook_(Algebras(QQ)) # todo: not implemented + sage: VectorSpaces(Fields())._subcategory_hook_(Algebras(QQ)) # todo: not implemented True sage: VectorSpaces(Fields().Finite())._subcategory_hook_(Algebras(QQ)) False @@ -428,23 +431,26 @@ def _subcategory_hook_(self, C): sage: VectorSpaces(QQ)._subcategory_hook_(Algebras(QQ)) True - sage: VectorSpaces(CC)._subcategory_hook_(Algebras(QQ)) # base ring in different categories + sage: VectorSpaces(CC)._subcategory_hook_(Algebras(QQ)) # base ring in different categories # needs sage.rings.real_mpfr False - sage: VectorSpaces(GF(2))._subcategory_hook_(Algebras(GF(3))) # base ring in the same category + sage: VectorSpaces(GF(2))._subcategory_hook_(Algebras(GF(3))) # base ring in the same category False Note; we need both previous tests since the distinction is made respectively using the parent class or the base ring:: - sage: issubclass(Algebras(QQ).parent_class, VectorSpaces(CC).parent_class) + sage: issubclass(Algebras(QQ).parent_class, # needs sage.modules + ....: VectorSpaces(CC).parent_class) False - sage: issubclass(Algebras(GF(2)).parent_class, VectorSpaces(GF(3)).parent_class) + sage: issubclass(Algebras(GF(2)).parent_class, + ....: VectorSpaces(GF(3)).parent_class) True Check that :trac:`16618` is fixed: this `_subcategory_hook_` method is only valid for :class:`Category_over_base_ring`, not :class:`Category_over_base`:: + sage: # needs sage.groups sage: from sage.categories.category_types import Category_over_base sage: D = Modules(Rings()) sage: class Cs(Category_over_base): @@ -549,7 +555,7 @@ def _repr_(self): sage: Ideals(IntegerRing()) Category of ring ideals in Integer Ring """ - return Category._repr_(self) + " in %s"%self.__ambient + return Category._repr_(self) + " in %s" % self.__ambient # def construction(self): # return (self.__class__, self.__ambient) diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 9850f4d4c85..5227792e725 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -182,7 +182,8 @@ class ``Semigroups.Infinite`` inheriting from :class:`CategoryWithAxiom`. :trac:`15648`), one should pass the option ``as_name`` to :class:`~sage.misc.lazy_import.LazyImport`:: - Finite = LazyImport('sage.categories.finite_groups', 'FiniteGroups', as_name='Finite') + Finite = LazyImport('sage.categories.finite_groups', 'FiniteGroups', + as_name='Finite') in order to prevent ``Groups.Finite`` to keep on reimporting ``FiniteGroups``. @@ -1730,7 +1731,8 @@ def base_category_class_and_axiom(cls): (<class 'sage.categories.sets_cat.Sets'>, 'Finite') sage: base_category_class_and_axiom(FiniteDimensionalHopfAlgebrasWithBasis) - (<class 'sage.categories.hopf_algebras_with_basis.HopfAlgebrasWithBasis'>, 'FiniteDimensional') + (<class 'sage.categories.hopf_algebras_with_basis.HopfAlgebrasWithBasis'>, + 'FiniteDimensional') sage: base_category_class_and_axiom(HopfAlgebrasWithBasis) (<class 'sage.categories.hopf_algebras.HopfAlgebras'>, 'WithBasis') @@ -1742,7 +1744,9 @@ def base_category_class_and_axiom(cls): sage: base_category_class_and_axiom(FacadeSemigroups) Traceback (most recent call last): ... - AssertionError: Missing (lazy import) link for <class 'sage.categories.semigroups.Semigroups'> to <class '__main__.FacadeSemigroups'> for axiom Facade? + AssertionError: Missing (lazy import) link + for <class 'sage.categories.semigroups.Semigroups'> + to <class '__main__.FacadeSemigroups'> for axiom Facade? sage: Semigroups.Facade = FacadeSemigroups sage: base_category_class_and_axiom(FacadeSemigroups) @@ -1760,7 +1764,8 @@ def base_category_class_and_axiom(cls): sage: base_category_class_and_axiom(Sets.Infinite) Traceback (most recent call last): ... - TypeError: Could not retrieve the base category class and axiom for <class 'sage.categories.sets_cat.Sets.Infinite'>. + TypeError: Could not retrieve the base category class and axiom + for <class 'sage.categories.sets_cat.Sets.Infinite'>. ... """ if "." in cls.__name__: @@ -1812,7 +1817,8 @@ def axiom_of_nested_class(cls, nested_cls): sage: from sage.categories.category_with_axiom import TestObjects, axiom_of_nested_class sage: axiom_of_nested_class(TestObjects, TestObjects.FiniteDimensional) 'FiniteDimensional' - sage: axiom_of_nested_class(TestObjects.FiniteDimensional, TestObjects.FiniteDimensional.Finite) + sage: axiom_of_nested_class(TestObjects.FiniteDimensional, + ....: TestObjects.FiniteDimensional.Finite) 'Finite' sage: axiom_of_nested_class(Sets, FiniteSets) 'Finite' @@ -2518,6 +2524,7 @@ def __init__(self, base_category): class CategoryWithAxiom_singleton(Category_singleton, CategoryWithAxiom):#, Category_singleton, FastHashable_class): pass + """ The following workaround is needed until any :class:`CategoryWithAxiom` of a :class:`Category_over_base_ring` becomes automatically a @@ -2543,7 +2550,8 @@ class CategoryWithAxiom_singleton(Category_singleton, CategoryWithAxiom):#, Cate sage: isinstance(C, Category_over_base_ring) # todo: not implemented True sage: C.FiniteDimensional() - Category of finite dimensional connected test objects over base ring over Ring of integers modulo 2 + Category of finite dimensional connected test objects + over base ring over Ring of integers modulo 2 sage: C.Connected() Category of connected test objects over base ring over Ring of integers modulo 2 """ @@ -2609,11 +2617,11 @@ def super_categories(self): class SubcategoryMethods: FiniteDimensional = axiom("FiniteDimensional") - Commutative = axiom("Commutative") - Unital = axiom("Unital") - Connected = axiom("Connected") - Flying = axiom("Flying") - Blue = axiom("Blue") + Commutative = axiom("Commutative") + Unital = axiom("Unital") + Connected = axiom("Connected") + Flying = axiom("Flying") + Blue = axiom("Blue") class FiniteDimensional(CategoryWithAxiom): pass @@ -2757,6 +2765,7 @@ def super_categories(self): class FiniteDimensional(CategoryWithAxiom): class Finite(CategoryWithAxiom): pass + class Unital(CategoryWithAxiom): class Commutative(CategoryWithAxiom): pass @@ -2764,14 +2773,17 @@ class Commutative(CategoryWithAxiom): class Commutative(CategoryWithAxiom): class Facade(CategoryWithAxiom): pass + class FiniteDimensional(CategoryWithAxiom): pass + class Finite(CategoryWithAxiom): pass class Unital(CategoryWithAxiom): pass + class TestObjectsOverBaseRing(Category_over_base_ring): r""" A toy singleton category, for testing purposes. @@ -2790,13 +2802,15 @@ def super_categories(self): Category of unital test objects over base ring over Rational Field sage: TestObjectsOverBaseRing.FiniteDimensional.Unital.an_instance() Category of finite dimensional unital test objects over base ring over Rational Field - sage: TestSuite(TestObjectsOverBaseRing(QQ).FiniteDimensional().Unital().Commutative()).run() + sage: C = TestObjectsOverBaseRing(QQ).FiniteDimensional().Unital().Commutative() + sage: TestSuite(C).run() """ return [TestObjects()] class FiniteDimensional(CategoryWithAxiom_over_base_ring): class Finite(CategoryWithAxiom_over_base_ring): pass + class Unital(CategoryWithAxiom_over_base_ring): class Commutative(CategoryWithAxiom_over_base_ring): pass @@ -2804,8 +2818,10 @@ class Commutative(CategoryWithAxiom_over_base_ring): class Commutative(CategoryWithAxiom_over_base_ring): class Facade(CategoryWithAxiom_over_base_ring): pass + class FiniteDimensional(CategoryWithAxiom_over_base_ring): pass + class Finite(CategoryWithAxiom_over_base_ring): pass diff --git a/src/sage/categories/chain_complexes.py b/src/sage/categories/chain_complexes.py index 531fc48e4cd..db9c5d03f56 100644 --- a/src/sage/categories/chain_complexes.py +++ b/src/sage/categories/chain_complexes.py @@ -46,7 +46,9 @@ def super_categories(self): [Category of modules over Ring of integers modulo 9] """ - from sage.categories.all import Fields, Modules, VectorSpaces + from sage.categories.fields import Fields + from sage.categories.modules import Modules + from sage.categories.vector_spaces import VectorSpaces base_ring = self.base_ring() if base_ring in Fields(): return [VectorSpaces(base_ring)] @@ -65,6 +67,7 @@ def homology(self, n=None): EXAMPLES:: + sage: # needs sage.modules sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) sage: C.homology(0) Z x Z @@ -75,6 +78,7 @@ def homology(self, n=None): :: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3)) sage: C = A.cdg_algebra({z: x*y}) sage: C.homology(0) @@ -97,17 +101,18 @@ def differential(self, *args, **kwargs): EXAMPLES:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) - sage: C.differential(0) + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) # needs sage.modules + sage: C.differential(0) # needs sage.modules [3 0 0] [0 0 0] :: - sage: A.<x,y,z> = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3)) - sage: C = A.cdg_algebra({z: x*y}) - sage: C.differential() - Differential of Commutative Differential Graded Algebra with generators ('x', 'y', 'z') in degrees (2, 2, 3) over Rational Field + sage: A.<x,y,z> = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3)) # needs sage.combinat sage.modules + sage: C = A.cdg_algebra({z: x*y}) # needs sage.combinat sage.modules + sage: C.differential() # needs sage.combinat sage.modules + Differential of Commutative Differential Graded Algebra with + generators ('x', 'y', 'z') in degrees (2, 2, 3) over Rational Field Defn: x --> 0 y --> 0 z --> x*y @@ -121,10 +126,11 @@ def lift_from_homology(self, x): EXAMPLES:: - sage: E3 = EuclideanSpace(3) # optional - sage.symbolic - sage: C = E3.de_rham_complex() # optional - sage.symbolic - sage: one = C.homology().one() # optional - sage.symbolic - sage: C.lift_from_homology(one) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: E3 = EuclideanSpace(3) + sage: C = E3.de_rham_complex() + sage: one = C.homology().one() + sage: C.lift_from_homology(one) Mixed differential form one on the Euclidean space E^3 """ @@ -141,10 +147,11 @@ def reduce_to_homology(self, x, n=None): EXAMPLES:: - sage: E3 = EuclideanSpace(3) # optional - sage.symbolic - sage: C = E3.de_rham_complex() # optional - sage.symbolic - sage: one = C.one() # optional - sage.symbolic - sage: C.reduce_to_homology(one) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: E3 = EuclideanSpace(3) + sage: C = E3.de_rham_complex() + sage: one = C.one() + sage: C.reduce_to_homology(one) [one] """ try: @@ -166,33 +173,36 @@ class HomologyFunctor(Functor): EXAMPLES:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) # needs sage.modules sage: H = HomologyFunctor(ChainComplexes(ZZ), 1) - sage: H(C) + sage: H(C) # needs sage.modules Z x C3 :: - sage: A.<x,y,z> = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3)) - sage: C = A.cdg_algebra({z: x*y}) + sage: A.<x,y,z> = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3)) # needs sage.combinat sage.modules + sage: C = A.cdg_algebra({z: x*y}) # needs sage.combinat sage.modules sage: H = HomologyFunctor(ChainComplexes(QQ), 2) - sage: H(C) + sage: H(C) # needs sage.combinat sage.modules Free module generated by {[x], [y]} over Rational Field Applying to a chain map:: + sage: # needs sage.graphs sage.modules sage: S = simplicial_complexes.Sphere(1); S Minimal triangulation of the 1-sphere - sage: C = S.chain_complex() - sage: C.differential() - {0: [], 1: [-1 -1 0] - [ 1 0 -1] - [ 0 1 1], 2: []} - sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)} - sage: G = Hom(C,C) + sage: SCC = S.chain_complex() + sage: SCC.differential() + {0: [], + 1: [-1 -1 0] + [ 1 0 -1] + [ 0 1 1], + 2: []} + sage: f = {0: zero_matrix(ZZ,3,3), 1: zero_matrix(ZZ,3,3)} + sage: G = Hom(SCC, SCC) sage: x = G(f) sage: H = HomologyFunctor(ChainComplexes(ZZ), 1) - sage: H(C) + sage: H(SCC) Z sage: H(x) Generic morphism: @@ -223,9 +233,9 @@ def _apply_functor(self, x): TESTS:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) # needs sage.modules sage: H = HomologyFunctor(ChainComplexes(ZZ), 1) - sage: H._apply_functor(C) + sage: H._apply_functor(C) # needs sage.modules Z x C3 """ @@ -237,15 +247,16 @@ def _apply_functor_to_morphism(self, f): TESTS:: - sage: E3 = EuclideanSpace(3) # optional - sage.symbolic - sage: C = E3.de_rham_complex() # optional - sage.symbolic - sage: id = Hom(C, C).identity() # optional - sage.symbolic - sage: H = HomologyFunctor(ChainComplexes(SR)) # optional - sage.symbolic - sage: id_star = H(id); id_star # optional - sage.symbolic + sage: # needs sage.symbolic + sage: E3 = EuclideanSpace(3) + sage: C = E3.de_rham_complex() + sage: id = Hom(C, C).identity() + sage: H = HomologyFunctor(ChainComplexes(SR)) + sage: id_star = H(id); id_star Generic endomorphism of De Rham cohomology ring on the Euclidean space E^3 - sage: one = H(C).one() # optional - sage.symbolic - sage: id_star(one) # optional - sage.symbolic + sage: one = H(C).one() + sage: id_star(one) [one] """ from .morphism import SetMorphism diff --git a/src/sage/categories/classical_crystals.py b/src/sage/categories/classical_crystals.py index 490337d0bda..fb5d2c7cde8 100644 --- a/src/sage/categories/classical_crystals.py +++ b/src/sage/categories/classical_crystals.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs sage.combinat r""" Classical Crystals """ @@ -107,7 +108,6 @@ def additional_structure(self): """ return None - class ParentMethods: def demazure_character(self, w, f=None): @@ -181,7 +181,7 @@ def demazure_character(self, w, f=None): u = self.algebra(ZZ).sum_of_monomials(self.module_generators) u = self.demazure_operator(u, word) if f is None: - from sage.symbolic.all import SR as P + from sage.symbolic.ring import SR as P x = [P.var('x%s' % (i+1)) for i in range(n)] # TODO: use P.linear_combination when PolynomialRing will be a ModulesWithBasis return sum((coeff*prod((x[i]**(c.weight()[i]) for i in range(n)), P.one()) for c, coeff in u), P.zero()) diff --git a/src/sage/categories/coalgebras.py b/src/sage/categories/coalgebras.py index 22a385d5f0d..abe36aef0bb 100644 --- a/src/sage/categories/coalgebras.py +++ b/src/sage/categories/coalgebras.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Coalgebras """ @@ -10,7 +11,7 @@ # ***************************************************************************** from .category_types import Category_over_base_ring -from sage.categories.all import Modules +from sage.categories.modules import Modules from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.tensor import TensorProductsCategory from sage.categories.dual import DualObjectsCategory @@ -66,6 +67,7 @@ def counit(self, x): EXAMPLES:: + sage: # needs sage.modules sage: A = HopfAlgebrasWithBasis(QQ).example(); A An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field @@ -79,7 +81,6 @@ def counit(self, x): and Hopf algebras using the counit. """ - @abstract_method def coproduct(self, x): """ @@ -91,6 +92,7 @@ def coproduct(self, x): EXAMPLES:: + sage: # needs sage.modules sage: A = HopfAlgebrasWithBasis(QQ).example(); A An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field @@ -109,6 +111,7 @@ def coproduct(self): EXAMPLES:: + sage: # needs sage.modules sage: A = HopfAlgebrasWithBasis(QQ).example(); A An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field @@ -126,6 +129,7 @@ def counit(self): EXAMPLES:: + sage: # needs sage.modules sage: A = HopfAlgebrasWithBasis(QQ).example(); A An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field @@ -292,6 +296,7 @@ def coproduct(self, x): EXAMPLES:: + sage: # needs sage.modules sage: N = NonCommutativeSymmetricFunctions(QQ) sage: S = N.complete() sage: N.coproduct.__module__ @@ -307,6 +312,7 @@ def counit(self, x): EXAMPLES:: + sage: # needs sage.modules sage: Sym = SymmetricFunctions(QQ) sage: s = Sym.schur() sage: f = s[2,1] @@ -317,6 +323,7 @@ def counit(self, x): :: + sage: # needs sage.modules sage: N = NonCommutativeSymmetricFunctions(QQ) sage: N.counit.__module__ 'sage.categories.coalgebras' @@ -340,6 +347,7 @@ def coproduct_by_coercion(self, x): EXAMPLES:: + sage: # needs sage.modules sage: Sym = SymmetricFunctions(QQ) sage: m = Sym.monomial() sage: f = m[2,1] @@ -354,6 +362,7 @@ def coproduct_by_coercion(self, x): :: + sage: # needs sage.modules sage: N = NonCommutativeSymmetricFunctions(QQ) sage: R = N.ribbon() sage: R.coproduct_by_coercion.__module__ @@ -375,16 +384,16 @@ def counit_by_coercion(self, x): EXAMPLES:: - sage: sp = SymmetricFunctions(QQ).sp() - sage: sp.an_element() + sage: sp = SymmetricFunctions(QQ).sp() # needs sage.modules + sage: sp.an_element() # needs sage.modules 2*sp[] + 2*sp[1] + 3*sp[2] - sage: sp.counit(sp.an_element()) + sage: sp.counit(sp.an_element()) # needs sage.modules 2 - sage: o = SymmetricFunctions(QQ).o() - sage: o.an_element() + sage: o = SymmetricFunctions(QQ).o() # needs sage.modules + sage: o.an_element() # needs sage.modules 2*o[] + 2*o[1] + 3*o[2] - sage: o.counit(o.an_element()) + sage: o.counit(o.an_element()) # needs sage.modules -1 """ R = self.realization_of().a_realization() diff --git a/src/sage/categories/coalgebras_with_basis.py b/src/sage/categories/coalgebras_with_basis.py index b672c37dd27..1a3ecfe8302 100644 --- a/src/sage/categories/coalgebras_with_basis.py +++ b/src/sage/categories/coalgebras_with_basis.py @@ -13,7 +13,9 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import LazyImport from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from sage.categories.all import ModulesWithBasis, tensor, Hom +from sage.categories.modules_with_basis import ModulesWithBasis +from sage.categories.tensor import tensor +from sage.categories.homset import Hom from sage.categories.super_modules import SuperModulesCategory from sage.categories.filtered_modules import FilteredModulesCategory @@ -59,10 +61,12 @@ def coproduct_on_basis(self, i): EXAMPLES:: - sage: A = HopfAlgebrasWithBasis(QQ).example(); A - An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field - sage: (a, b) = A._group.gens() - sage: A.coproduct_on_basis(a) + sage: A = HopfAlgebrasWithBasis(QQ).example(); A # needs sage.groups sage.modules + An example of Hopf algebra with basis: + the group algebra of the Dihedral group of order 6 + as a permutation group over Rational Field + sage: (a, b) = A._group.gens() # needs sage.groups sage.modules + sage: A.coproduct_on_basis(a) # needs sage.groups sage.modules B[(1,2,3)] # B[(1,2,3)] """ @@ -77,9 +81,12 @@ def coproduct(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: A = HopfAlgebrasWithBasis(QQ).example(); A - An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field - sage: [a,b] = A.algebra_generators() + An example of Hopf algebra with basis: + the group algebra of the Dihedral group of order 6 + as a permutation group over Rational Field + sage: a, b = A.algebra_generators() sage: a, A.coproduct(a) (B[(1,2,3)], B[(1,2,3)] # B[(1,2,3)]) sage: b, A.coproduct(b) @@ -109,10 +116,12 @@ def counit_on_basis(self, i): EXAMPLES:: - sage: A = HopfAlgebrasWithBasis(QQ).example(); A - An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field - sage: (a, b) = A._group.gens() - sage: A.counit_on_basis(a) + sage: A = HopfAlgebrasWithBasis(QQ).example(); A # needs sage.groups sage.modules + An example of Hopf algebra with basis: + the group algebra of the Dihedral group of order 6 + as a permutation group over Rational Field + sage: (a, b) = A._group.gens() # needs sage.groups sage.modules + sage: A.counit_on_basis(a) # needs sage.groups sage.modules 1 """ @@ -125,9 +134,12 @@ def counit(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: A = HopfAlgebrasWithBasis(QQ).example(); A - An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field - sage: [a,b] = A.algebra_generators() + An example of Hopf algebra with basis: + the group algebra of the Dihedral group of order 6 + as a permutation group over Rational Field + sage: a, b = A.algebra_generators() sage: a, A.counit(a) (B[(1,2,3)], 1) sage: b, A.counit(b) @@ -150,29 +162,29 @@ def coproduct_iterated(self, n=1): EXAMPLES:: - sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() - sage: Psi[2,2].coproduct_iterated(0) + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() # needs sage.combinat sage.modules + sage: Psi[2,2].coproduct_iterated(0) # needs sage.combinat sage.modules Psi[2, 2] - sage: Psi[2,2].coproduct_iterated(2) + sage: Psi[2,2].coproduct_iterated(2) # needs sage.combinat sage.modules Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[2, 2] # Psi[] + 2*Psi[2] # Psi[] # Psi[2] + 2*Psi[2] # Psi[2] # Psi[] + Psi[2, 2] # Psi[] # Psi[] TESTS:: - sage: p = SymmetricFunctions(QQ).p() - sage: p[5,2,2].coproduct_iterated() + sage: p = SymmetricFunctions(QQ).p() # needs sage.combinat sage.modules + sage: p[5,2,2].coproduct_iterated() # needs sage.combinat sage.modules p[] # p[5, 2, 2] + 2*p[2] # p[5, 2] + p[2, 2] # p[5] + p[5] # p[2, 2] + 2*p[5, 2] # p[2] + p[5, 2, 2] # p[] - sage: p([]).coproduct_iterated(3) + sage: p([]).coproduct_iterated(3) # needs sage.combinat sage.modules p[] # p[] # p[] # p[] :: - sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() - sage: Psi[2,2].coproduct_iterated(0) + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() # needs sage.combinat sage.modules + sage: Psi[2,2].coproduct_iterated(0) # needs sage.combinat sage.modules Psi[2, 2] - sage: Psi[2,2].coproduct_iterated(3) + sage: Psi[2,2].coproduct_iterated(3) # needs sage.combinat sage.modules Psi[] # Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[] # Psi[2, 2] # Psi[] + 2*Psi[] # Psi[2] # Psi[] # Psi[2] + 2*Psi[] # Psi[2] # Psi[2] # Psi[] + Psi[] # Psi[2, 2] # Psi[] # Psi[] @@ -181,14 +193,14 @@ def coproduct_iterated(self, n=1): :: - sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() - sage: m[[1,3],[2]].coproduct_iterated(2) + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() # needs sage.combinat sage.modules + sage: m[[1,3],[2]].coproduct_iterated(2) # needs sage.combinat sage.modules m{} # m{} # m{{1, 3}, {2}} + m{} # m{{1}} # m{{1, 2}} + m{} # m{{1, 2}} # m{{1}} + m{} # m{{1, 3}, {2}} # m{} + m{{1}} # m{} # m{{1, 2}} + m{{1}} # m{{1, 2}} # m{} + m{{1, 2}} # m{} # m{{1}} + m{{1, 2}} # m{{1}} # m{} + m{{1, 3}, {2}} # m{} # m{} - sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0) + sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0) # needs sage.combinat sage.modules (m{} # m{} # m{} # m{}, m{{1, 3}, {2}}) """ if n < 0: diff --git a/src/sage/categories/commutative_additive_groups.py b/src/sage/categories/commutative_additive_groups.py index c1383022833..ce1dfc5186a 100644 --- a/src/sage/categories/commutative_additive_groups.py +++ b/src/sage/categories/commutative_additive_groups.py @@ -79,8 +79,10 @@ def additive_order(self): sage: G((0,1)).additive_order() +Infinity + sage: # needs sage.rings.finite_rings sage: K = GF(9) - sage: H = cartesian_product([cartesian_product([Zmod(2),Zmod(9)]), K]) + sage: H = cartesian_product([ + ....: cartesian_product([Zmod(2), Zmod(9)]), K]) sage: z = H(((1,2), K.gen())) sage: z.additive_order() 18 diff --git a/src/sage/categories/commutative_algebra_ideals.py b/src/sage/categories/commutative_algebra_ideals.py index dd47011584a..070503ae6c8 100644 --- a/src/sage/categories/commutative_algebra_ideals.py +++ b/src/sage/categories/commutative_algebra_ideals.py @@ -10,8 +10,11 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from .category_types import Category_ideal, Category_in_ambient from .algebra_ideals import AlgebraIdeals +from .category_types import Category_ideal, Category_in_ambient +from .commutative_algebras import CommutativeAlgebras +from .commutative_rings import CommutativeRings + class CommutativeAlgebraIdeals(Category_ideal): """ @@ -21,14 +24,16 @@ class CommutativeAlgebraIdeals(Category_ideal): sage: C = CommutativeAlgebraIdeals(QQ['x']) sage: C - Category of commutative algebra ideals in Univariate Polynomial Ring in x over Rational Field + Category of commutative algebra ideals in + Univariate Polynomial Ring in x over Rational Field """ def __init__(self, A): """ EXAMPLES:: sage: CommutativeAlgebraIdeals(ZZ['x']) - Category of commutative algebra ideals in Univariate Polynomial Ring in x over Integer Ring + Category of commutative algebra ideals in + Univariate Polynomial Ring in x over Integer Ring sage: CommutativeAlgebraIdeals(ZZ) Traceback (most recent call last): @@ -40,7 +45,7 @@ def __init__(self, A): ... TypeError: A (=Ring of integers modulo 4) must be a commutative algebra - sage: CommutativeAlgebraIdeals(Partitions(4)) + sage: CommutativeAlgebraIdeals(Partitions(4)) # needs sage.combinat Traceback (most recent call last): ... TypeError: A (=Partitions of the integer 4) must be a commutative algebra @@ -51,10 +56,14 @@ def __init__(self, A): """ # TODO: replace by ``A in CommutativeAlgebras(*)`` once a # suitable mantra has been implemented for this. - from sage.algebras.algebra import is_Algebra - from sage.rings.ring import CommutativeRing - if not (is_Algebra(A) and isinstance(A, CommutativeRing)): - raise TypeError("A (=%s) must be a commutative algebra"%A) + try: + base_ring = A.base_ring() + except AttributeError: + raise TypeError(f"A (={A}) must be a commutative algebra") + else: + if base_ring not in CommutativeRings() or A not in CommutativeAlgebras(base_ring.category()): + raise TypeError(f"A (={A}) must be a commutative algebra") + Category_in_ambient.__init__(self, A) def algebra(self): diff --git a/src/sage/categories/commutative_algebras.py b/src/sage/categories/commutative_algebras.py index cff24e1298a..986a45db3e3 100644 --- a/src/sage/categories/commutative_algebras.py +++ b/src/sage/categories/commutative_algebras.py @@ -53,7 +53,7 @@ def __contains__(self, A): True sage: QQ['a,b'] in CommutativeAlgebras(QQ) True - sage: FreeAlgebra(QQ,2,'a,b') in CommutativeAlgebras(QQ) + sage: FreeAlgebra(QQ, 2, 'a,b') in CommutativeAlgebras(QQ) # needs sage.combinat sage.modules False TODO: get rid of this method once all commutative algebras in @@ -80,6 +80,7 @@ def extra_super_categories(self): TESTS:: + sage: # needs sage.combinat sage.modules sage: X = algebras.Shuffle(QQ, 'ab') sage: Y = algebras.Shuffle(QQ, 'bc') sage: X in Algebras(QQ).Commutative() diff --git a/src/sage/categories/commutative_ring_ideals.py b/src/sage/categories/commutative_ring_ideals.py index 115b79afb80..5aef6d7d31d 100644 --- a/src/sage/categories/commutative_ring_ideals.py +++ b/src/sage/categories/commutative_ring_ideals.py @@ -35,14 +35,14 @@ def __init__(self, R): TESTS:: - sage: CommutativeRingIdeals(Partitions(4)) + sage: CommutativeRingIdeals(Partitions(4)) # needs sage.combinat Traceback (most recent call last): ... TypeError: R (=Partitions of the integer 4) must be a commutative ring sage: TestSuite(CommutativeRingIdeals(ZZ)).run() """ if R not in CommutativeRings(): - raise TypeError("R (=%s) must be a commutative ring"%R) + raise TypeError("R (=%s) must be a commutative ring" % R) Category_ideal.__init__(self, R) def super_categories(self): diff --git a/src/sage/categories/commutative_rings.py b/src/sage/categories/commutative_rings.py index 71e08a5070d..9c28072ae0b 100644 --- a/src/sage/categories/commutative_rings.py +++ b/src/sage/categories/commutative_rings.py @@ -35,14 +35,14 @@ class CommutativeRings(CategoryWithAxiom): sage: QQ['x,y,z'] in CommutativeRings() True - sage: GroupAlgebra(DihedralGroup(3), QQ) in CommutativeRings() + sage: GroupAlgebra(DihedralGroup(3), QQ) in CommutativeRings() # needs sage.groups sage.modules False - sage: MatrixSpace(QQ,2,2) in CommutativeRings() + sage: MatrixSpace(QQ, 2, 2) in CommutativeRings() # needs sage.modules False GroupAlgebra should be fixed:: - sage: GroupAlgebra(CyclicPermutationGroup(3), QQ) in CommutativeRings() # todo: not implemented + sage: GroupAlgebra(CyclicPermutationGroup(3), QQ) in CommutativeRings() # not implemented, needs sage.groups sage.modules True """ @@ -110,33 +110,35 @@ def over(self, base=None, gen=None, gens=None, name=None, names=None): We construct an extension of finite fields:: + sage: # needs sage.rings.finite_rings sage: F = GF(5^2) sage: k = GF(5^4) sage: z4 = k.gen() - - sage: K = k.over(F) - sage: K - Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base + sage: K = k.over(F); K # needs sage.modules + Field in z4 with defining polynomial + x^2 + (4*z2 + 3)*x + z2 over its base If not explicitly given, the default generator of the top ring (here k) is used and the same name is kept:: - sage: K.gen() + sage: K.gen() # needs sage.modules sage.rings.finite_rings z4 - sage: K(z4) + sage: K(z4) # needs sage.modules sage.rings.finite_rings z4 However, it is possible to specify another generator and/or another name. For example:: - sage: Ka = k.over(F, name='a') - sage: Ka - Field in a with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base + sage: # needs sage.modules sage.rings.finite_rings + sage: Ka = k.over(F, name='a'); Ka + Field in a with defining polynomial + x^2 + (4*z2 + 3)*x + z2 over its base sage: Ka.gen() a sage: Ka(z4) a + sage: # needs sage.modules sage.rings.finite_rings sage: Kb = k.over(F, gen=-z4+1, name='b') sage: Kb Field in b with defining polynomial x^2 + z2*x + 4 over its base @@ -147,37 +149,40 @@ def over(self, base=None, gen=None, gens=None, name=None, names=None): Note that the shortcut ``K.<a>`` is also available:: - sage: KKa.<a> = k.over(F) - sage: KKa is Ka + sage: KKa.<a> = k.over(F) # needs sage.modules sage.rings.finite_rings + sage: KKa is Ka # needs sage.modules sage.rings.finite_rings True Building an extension on top of another extension is allowed:: - sage: L = GF(5^12).over(K) - sage: L - Field in z12 with defining polynomial x^3 + (1 + (4*z2 + 2)*z4)*x^2 + (2 + 2*z4)*x - z4 over its base - sage: L.base_ring() - Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base + sage: L = GF(5^12).over(K); L # needs sage.modules sage.rings.finite_rings + Field in z12 with defining polynomial + x^3 + (1 + (4*z2 + 2)*z4)*x^2 + (2 + 2*z4)*x - z4 over its base + sage: L.base_ring() # needs sage.modules sage.rings.finite_rings + Field in z4 with defining polynomial + x^2 + (4*z2 + 3)*x + z2 over its base The successive bases of an extension are accessible via the method :meth:`sage.rings.ring_extension.RingExtension_generic.bases`:: - sage: L.bases() - [Field in z12 with defining polynomial x^3 + (1 + (4*z2 + 2)*z4)*x^2 + (2 + 2*z4)*x - z4 over its base, - Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base, + sage: L.bases() # needs sage.modules sage.rings.finite_rings + [Field in z12 with defining polynomial + x^3 + (1 + (4*z2 + 2)*z4)*x^2 + (2 + 2*z4)*x - z4 over its base, + Field in z4 with defining polynomial + x^2 + (4*z2 + 3)*x + z2 over its base, Finite Field in z2 of size 5^2] When ``base`` is omitted, the canonical base of the ring is used:: sage: S.<x> = QQ[] - sage: E = S.over() - sage: E + sage: E = S.over(); E # needs sage.modules Univariate Polynomial Ring in x over Rational Field over its base - sage: E.base_ring() + sage: E.base_ring() # needs sage.modules Rational Field Here is an example where ``base`` is a defining morphism:: + sage: # needs sage.modules sage.rings.number_field sage: k.<a> = QQ.extension(x^2 - 2) sage: l.<b> = QQ.extension(x^4 - 2) sage: f = k.hom([b^2]) @@ -189,9 +194,9 @@ def over(self, base=None, gen=None, gens=None, name=None, names=None): Similarly, one can create a tower of extensions:: + sage: # needs sage.modules sage.rings.number_field sage: K = k.over() - sage: L = l.over(Hom(K,l)(f)) - sage: L + sage: L = l.over(Hom(K, l)(f)); L Field in b with defining polynomial x^2 - a over its base sage: L.base_ring() Field in a with defining polynomial x^2 - 2 over its base @@ -221,7 +226,8 @@ class Finite(CategoryWithAxiom): EXAMPLES:: - sage: cartesian_product([Zmod(34), GF(5)]) in Rings().Commutative().Finite() + sage: cartesian_product([Zmod(34), + ....: GF(5)]) in Rings().Commutative().Finite() True """ class ParentMethods: @@ -278,9 +284,10 @@ def cyclotomic_cosets(self, q, cosets=None): cyclic, the set of squares is a particular case of cyclotomic coset:: - sage: K = GF(25,'z') + sage: # needs sage.rings.finite_rings + sage: K = GF(25, 'z') sage: a = K.multiplicative_generator() - sage: K.cyclotomic_cosets(a**2,cosets=[1]) + sage: K.cyclotomic_cosets(a**2, cosets=[1]) [[1, 2, 3, 4, z + 1, z + 3, 2*z + 1, 2*z + 2, 3*z + 3, 3*z + 4, 4*z + 2, 4*z + 4]] @@ -291,21 +298,22 @@ def cyclotomic_cosets(self, q, cosets=None): We compute some examples of minimal polynomials:: - sage: K = GF(27,'z') + sage: # needs sage.rings.finite_rings + sage: K = GF(27, 'z') sage: a = K.multiplicative_generator() sage: R.<X> = PolynomialRing(K, 'X') sage: a.minimal_polynomial('X') X^3 + 2*X + 1 - sage: cyc3 = Zmod(26).cyclotomic_cosets(3,cosets=[1]); cyc3 + + sage: cyc3 = Zmod(26).cyclotomic_cosets(3, cosets=[1]); cyc3 [[1, 3, 9]] - sage: prod(X - a**i for i in cyc3[0]) + sage: prod(X - a**i for i in cyc3[0]) # needs sage.rings.finite_rings X^3 + 2*X + 1 - - sage: (a**7).minimal_polynomial('X') + sage: (a**7).minimal_polynomial('X') # needs sage.rings.finite_rings X^3 + X^2 + 2*X + 1 - sage: cyc7 = Zmod(26).cyclotomic_cosets(3,cosets=[7]); cyc7 + sage: cyc7 = Zmod(26).cyclotomic_cosets(3, cosets=[7]); cyc7 [[7, 11, 21]] - sage: prod(X - a**i for i in cyc7[0]) + sage: prod(X - a**i for i in cyc7[0]) # needs sage.rings.finite_rings X^3 + X^2 + 2*X + 1 Cyclotomic cosets of fields are useful in combinatorial design @@ -315,17 +323,17 @@ def cyclotomic_cosets(self, q, cosets=None): illustrated on the following examples:: sage: K = GF(5) - sage: a = K.multiplicative_generator() - sage: H = K.cyclotomic_cosets(a**2, cosets=[1,2]); H + sage: a = K.multiplicative_generator() # needs sage.libs.pari + sage: H = K.cyclotomic_cosets(a**2, cosets=[1, 2]); H # needs sage.rings.finite_rings [[1, 4], [2, 3]] - sage: sorted(x-y for D in H for x in D for y in D if x != y) + sage: sorted(x - y for D in H for x in D for y in D if x != y) # needs sage.rings.finite_rings [1, 2, 3, 4] sage: K = GF(37) - sage: a = K.multiplicative_generator() - sage: H = K.cyclotomic_cosets(a**4, cosets=[1]); H + sage: a = K.multiplicative_generator() # needs sage.libs.pari + sage: H = K.cyclotomic_cosets(a**4, cosets=[1]); H # needs sage.rings.finite_rings [[1, 7, 9, 10, 12, 16, 26, 33, 34]] - sage: sorted(x-y for D in H for x in D for y in D if x != y) + sage: sorted(x - y for D in H for x in D for y in D if x != y) # needs sage.rings.finite_rings [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, ..., 33, 34, 34, 35, 35, 36, 36] The method ``cyclotomic_cosets`` works on any finite commutative @@ -341,7 +349,7 @@ def cyclotomic_cosets(self, q, cosets=None): try: ~q except ZeroDivisionError: - raise ValueError("%s is not invertible in %s"%(q,self)) + raise ValueError("%s is not invertible in %s" % (q,self)) if cosets is None: rest = set(self) @@ -373,7 +381,8 @@ def extra_super_categories(self): sage: CommutativeRings().Commutative().CartesianProducts().extra_super_categories() [Category of commutative rings] - sage: cartesian_product([ZZ, Zmod(34), QQ, GF(5)]) in CommutativeRings() + sage: cartesian_product([ZZ, Zmod(34), + ....: QQ, GF(5)]) in CommutativeRings() True """ return [CommutativeRings()] diff --git a/src/sage/categories/complete_discrete_valuation.py b/src/sage/categories/complete_discrete_valuation.py index e7bc01ddd28..442360465a1 100644 --- a/src/sage/categories/complete_discrete_valuation.py +++ b/src/sage/categories/complete_discrete_valuation.py @@ -22,13 +22,13 @@ class CompleteDiscreteValuationRings(Category_singleton): EXAMPLES:: - sage: Zp(7) in CompleteDiscreteValuationRings() + sage: Zp(7) in CompleteDiscreteValuationRings() # needs sage.rings.padics True sage: QQ in CompleteDiscreteValuationRings() False sage: QQ[['u']] in CompleteDiscreteValuationRings() True - sage: Qp(7) in CompleteDiscreteValuationRings() + sage: Qp(7) in CompleteDiscreteValuationRings() # needs sage.rings.padics False sage: TestSuite(CompleteDiscreteValuationRings()).run() """ @@ -49,10 +49,10 @@ def valuation(self): EXAMPLES:: - sage: R = Zp(7) - sage: x = R(7); x + sage: R = Zp(7) # needs sage.rings.padics + sage: x = R(7); x # needs sage.rings.padics 7 + O(7^21) - sage: x.valuation() + sage: x.valuation() # needs sage.rings.padics 1 """ @@ -63,30 +63,30 @@ def denominator(self): EXAMPLES:: + sage: # needs sage.rings.padics sage: K = Qp(7) sage: x = K(1/21) sage: x.denominator() 7 + O(7^21) - sage: x = K(7) sage: x.denominator() 1 + O(7^20) Note that the denominator lives in the ring of integers:: - sage: x.denominator().parent() + sage: x.denominator().parent() # needs sage.rings.padics 7-adic Ring with capped relative precision 20 When the denominator is indistinguishable from 0 and the precision on the input is `O(p^n)`, the return value is `1` if `n` is nonnegative and `p^(-n)` otherwise:: - sage: x = K(0,5); x + sage: # needs sage.rings.padics + sage: x = K(0, 5); x O(7^5) sage: x.denominator() 1 + O(7^20) - - sage: x = K(0,-5); x + sage: x = K(0, -5); x O(7^-5) sage: x.denominator() 7^5 + O(7^25) @@ -101,26 +101,26 @@ def numerator(self): EXAMPLES:: + sage: # needs sage.rings.padics sage: K = Qp(7, 5) sage: x = K(1/21) sage: x.numerator() 5 + 4*7 + 4*7^2 + 4*7^3 + 4*7^4 + O(7^5) - sage: x == x.numerator() / x.denominator() True Note that the numerator lives in the ring of integers:: - sage: x.numerator().parent() + sage: x.numerator().parent() # needs sage.rings.padics 7-adic Ring with capped relative precision 5 TESTS:: - sage: x = K(0,-5); x + sage: x = K(0, -5); x # needs sage.rings.padics O(7^-5) - sage: x.numerator() + sage: x.numerator() # needs sage.rings.padics O(7^0) - sage: x.denominator() + sage: x.denominator() # needs sage.rings.padics 7^5 + O(7^10) """ return self @@ -146,21 +146,23 @@ def lift_to_precision(self, absprec=None): EXAMPLES:: + sage: # needs sage.rings.padics sage: R = ZpCA(17) - sage: R(-1,2).lift_to_precision(10) + sage: R(-1, 2).lift_to_precision(10) 16 + 16*17 + O(17^10) - sage: R(1,15).lift_to_precision(10) + sage: R(1, 15).lift_to_precision(10) 1 + O(17^15) - sage: R(1,15).lift_to_precision(30) + sage: R(1, 15).lift_to_precision(30) Traceback (most recent call last): ... PrecisionError: precision higher than allowed by the precision cap - sage: R(-1,2).lift_to_precision().precision_absolute() == R.precision_cap() + sage: (R(-1, 2).lift_to_precision().precision_absolute() + ....: == R.precision_cap()) True - sage: R = Zp(5); c = R(17,3); c.lift_to_precision(8) + sage: R = Zp(5); c = R(17, 3); c.lift_to_precision(8) # needs sage.rings.padics 2 + 3*5 + O(5^8) - sage: c.lift_to_precision().precision_relative() == R.precision_cap() + sage: c.lift_to_precision().precision_relative() == R.precision_cap() # needs sage.rings.padics True """ @@ -171,13 +173,13 @@ class CompleteDiscreteValuationFields(Category_singleton): EXAMPLES:: - sage: Zp(7) in CompleteDiscreteValuationFields() + sage: Zp(7) in CompleteDiscreteValuationFields() # needs sage.rings.padics False sage: QQ in CompleteDiscreteValuationFields() False - sage: LaurentSeriesRing(QQ,'u') in CompleteDiscreteValuationFields() + sage: LaurentSeriesRing(QQ, 'u') in CompleteDiscreteValuationFields() True - sage: Qp(7) in CompleteDiscreteValuationFields() + sage: Qp(7) in CompleteDiscreteValuationFields() # needs sage.rings.padics True sage: TestSuite(CompleteDiscreteValuationFields()).run() """ @@ -199,10 +201,10 @@ def valuation(self): EXAMPLES:: - sage: K = Qp(7) - sage: x = K(7); x + sage: K = Qp(7) # needs sage.rings.padics + sage: x = K(7); x # needs sage.rings.padics 7 + O(7^21) - sage: x.valuation() + sage: x.valuation() # needs sage.rings.padics 1 """ @@ -213,30 +215,30 @@ def denominator(self): EXAMPLES:: + sage: # needs sage.rings.padics sage: K = Qp(7) sage: x = K(1/21) sage: x.denominator() 7 + O(7^21) - sage: x = K(7) sage: x.denominator() 1 + O(7^20) Note that the denominator lives in the ring of integers:: - sage: x.denominator().parent() + sage: x.denominator().parent() # needs sage.rings.padics 7-adic Ring with capped relative precision 20 When the denominator is indistinguishable from 0 and the precision on the input is `O(p^n)`, the return value is `1` if `n` is nonnegative and `p^(-n)` otherwise:: - sage: x = K(0,5); x + sage: # needs sage.rings.padics + sage: x = K(0, 5); x O(7^5) sage: x.denominator() 1 + O(7^20) - - sage: x = K(0,-5); x + sage: x = K(0, -5); x O(7^-5) sage: x.denominator() 7^5 + O(7^25) @@ -256,26 +258,26 @@ def numerator(self): EXAMPLES:: + sage: # needs sage.rings.padics sage: K = Qp(7, 5) sage: x = K(1/21) sage: x.numerator() 5 + 4*7 + 4*7^2 + 4*7^3 + 4*7^4 + O(7^5) - sage: x == x.numerator() / x.denominator() True Note that the numerator lives in the ring of integers:: - sage: x.numerator().parent() + sage: x.numerator().parent() # needs sage.rings.padics 7-adic Ring with capped relative precision 5 TESTS:: - sage: x = K(0,-5); x + sage: x = K(0, -5); x # needs sage.rings.padics O(7^-5) - sage: x.numerator() + sage: x.numerator() # needs sage.rings.padics O(7^0) - sage: x.denominator() + sage: x.denominator() # needs sage.rings.padics 7^5 + O(7^10) """ R = self.parent().integer_ring() diff --git a/src/sage/categories/complex_reflection_groups.py b/src/sage/categories/complex_reflection_groups.py index 5b23c448a96..fbc04ff329c 100644 --- a/src/sage/categories/complex_reflection_groups.py +++ b/src/sage/categories/complex_reflection_groups.py @@ -64,17 +64,17 @@ class ComplexReflectionGroups(Category_singleton): An example of a reflection group:: - sage: W = ComplexReflectionGroups().example(); W + sage: W = ComplexReflectionGroups().example(); W # needs sage.combinat 5-colored permutations of size 3 ``W`` is in the category of complex reflection groups:: - sage: W in ComplexReflectionGroups() + sage: W in ComplexReflectionGroups() # needs sage.combinat True TESTS:: - sage: TestSuite(W).run() + sage: TestSuite(W).run() # needs sage.combinat sage: TestSuite(ComplexReflectionGroups()).run() """ @@ -115,7 +115,7 @@ def example(self): EXAMPLES:: sage: from sage.categories.complex_reflection_groups import ComplexReflectionGroups - sage: ComplexReflectionGroups().example() + sage: ComplexReflectionGroups().example() # needs sage.combinat 5-colored permutations of size 3 """ from sage.combinat.colored_permutations import ColoredPermutations diff --git a/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py b/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py index 6ddd62e0099..89667bfc237 100644 --- a/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py +++ b/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.groups r""" Common category for Generalized Coxeter Groups or Complex Reflection Groups """ @@ -197,7 +197,7 @@ def simple_reflection(self, i): sage: W = ReflectionGroup((1,1,4), index_set=[1,3,'asdf']) # optional - gap3 sage: for i in W.index_set(): # optional - gap3 - ....: print('%s %s'%(i, W.simple_reflection(i))) # optional - gap3 + ....: print('%s %s'%(i, W.simple_reflection(i))) 1 (1,7)(2,4)(5,6)(8,10)(11,12) 3 (1,4)(2,8)(3,5)(7,10)(9,11) asdf (2,5)(3,9)(4,6)(8,11)(10,12) @@ -419,14 +419,15 @@ def reflection_index_set(self): EXAMPLES:: - sage: W = ReflectionGroup((1,1,4)) # optional - gap3 - sage: W.reflection_index_set() # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup((1,1,4)) + sage: W.reflection_index_set() (1, 2, 3, 4, 5, 6) - sage: W = ReflectionGroup((1,1,4), reflection_index_set=[1,3,'asdf',7,9,11]) # optional - gap3 - sage: W.reflection_index_set() # optional - gap3 + sage: W = ReflectionGroup((1,1,4), reflection_index_set=[1,3,'asdf',7,9,11]) + sage: W.reflection_index_set() (1, 3, 'asdf', 7, 9, 11) - sage: W = ReflectionGroup((1,1,4), reflection_index_set=('a','b','c','d','e','f')) # optional - gap3 - sage: W.reflection_index_set() # optional - gap3 + sage: W = ReflectionGroup((1,1,4), reflection_index_set=('a','b','c','d','e','f')) + sage: W.reflection_index_set() ('a', 'b', 'c', 'd', 'e', 'f') """ @@ -447,7 +448,7 @@ def reflection(self, i): sage: W = ReflectionGroup((1,1,4)) # optional - gap3 sage: for i in W.reflection_index_set(): # optional - gap3 - ....: print('%s %s'%(i, W.reflection(i))) # optional - gap3 + ....: print('%s %s'%(i, W.reflection(i))) 1 (1,7)(2,4)(5,6)(8,10)(11,12) 2 (1,4)(2,8)(3,5)(7,10)(9,11) 3 (2,5)(3,9)(4,6)(8,11)(10,12) @@ -472,7 +473,7 @@ def reflections(self): sage: W = ReflectionGroup((1,1,3)) # optional - gap3 sage: reflections = W.reflections() # optional - gap3 sage: for index in sorted(reflections.keys()): # optional - gap3 - ....: print('%s %s'%(index, reflections[index])) # optional - gap3 + ....: print('%s %s'%(index, reflections[index])) 1 (1,4)(2,3)(5,6) 2 (1,3)(2,5)(4,6) 3 (1,5)(2,4)(3,6) @@ -480,7 +481,7 @@ def reflections(self): sage: W = ReflectionGroup((1,1,3),reflection_index_set=['a','b','c']) # optional - gap3 sage: reflections = W.reflections() # optional - gap3 sage: for index in sorted(reflections.keys()): # optional - gap3 - ....: print('%s %s'%(index, reflections[index])) # optional - gap3 + ....: print('%s %s'%(index, reflections[index])) a (1,4)(2,3)(5,6) b (1,3)(2,5)(4,6) c (1,5)(2,4)(3,6) @@ -488,14 +489,14 @@ def reflections(self): sage: W = ReflectionGroup((3,1,1)) # optional - gap3 sage: reflections = W.reflections() # optional - gap3 sage: for index in sorted(reflections.keys()): # optional - gap3 - ....: print('%s %s'%(index, reflections[index])) # optional - gap3 + ....: print('%s %s'%(index, reflections[index])) 1 (1,2,3) 2 (1,3,2) sage: W = ReflectionGroup((1,1,3), (3,1,2)) # optional - gap3 sage: reflections = W.reflections() # optional - gap3 sage: for index in sorted(reflections.keys()): # optional - gap3 - ....: print('%s %s'%(index, reflections[index])) # optional - gap3 + ....: print('%s %s'%(index, reflections[index])) 1 (1,6)(2,5)(7,8) 2 (1,5)(2,7)(6,8) 3 (3,9,15)(4,10,16)(12,17,23)(14,18,24)(20,25,29)(21,22,26)(27,28,30) @@ -533,14 +534,15 @@ def hyperplane_index_set(self): EXAMPLES:: - sage: W = ReflectionGroup((1,1,4)) # optional - gap3 - sage: W.hyperplane_index_set() # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup((1,1,4)) + sage: W.hyperplane_index_set() (1, 2, 3, 4, 5, 6) - sage: W = ReflectionGroup((1,1,4), hyperplane_index_set=[1,3,'asdf',7,9,11]) # optional - gap3 - sage: W.hyperplane_index_set() # optional - gap3 + sage: W = ReflectionGroup((1,1,4), hyperplane_index_set=[1,3,'asdf',7,9,11]) + sage: W.hyperplane_index_set() (1, 3, 'asdf', 7, 9, 11) - sage: W = ReflectionGroup((1,1,4), hyperplane_index_set=('a','b','c','d','e','f')) # optional - gap3 - sage: W.hyperplane_index_set() # optional - gap3 + sage: W = ReflectionGroup((1,1,4), hyperplane_index_set=('a','b','c','d','e','f')) + sage: W.hyperplane_index_set() ('a', 'b', 'c', 'd', 'e', 'f') """ @@ -562,7 +564,7 @@ def distinguished_reflection(self, i): sage: W = ReflectionGroup((1,1,4), hyperplane_index_set=('a','b','c','d','e','f')) # optional - gap3 sage: for i in W.hyperplane_index_set(): # optional - gap3 - ....: print('%s %s'%(i, W.distinguished_reflection(i))) # optional - gap3 + ....: print('%s %s'%(i, W.distinguished_reflection(i))) a (1,7)(2,4)(5,6)(8,10)(11,12) b (1,4)(2,8)(3,5)(7,10)(9,11) c (2,5)(3,9)(4,6)(8,11)(10,12) @@ -596,7 +598,7 @@ def distinguished_reflections(self): sage: W = ReflectionGroup((1,1,3)) # optional - gap3 sage: distinguished_reflections = W.distinguished_reflections() # optional - gap3 sage: for index in sorted(distinguished_reflections.keys()): # optional - gap3 - ....: print('%s %s'%(index, distinguished_reflections[index])) # optional - gap3 + ....: print('%s %s'%(index, distinguished_reflections[index])) 1 (1,4)(2,3)(5,6) 2 (1,3)(2,5)(4,6) 3 (1,5)(2,4)(3,6) @@ -604,7 +606,7 @@ def distinguished_reflections(self): sage: W = ReflectionGroup((1,1,3),hyperplane_index_set=['a','b','c']) # optional - gap3 sage: distinguished_reflections = W.distinguished_reflections() # optional - gap3 sage: for index in sorted(distinguished_reflections.keys()): # optional - gap3 - ....: print('%s %s'%(index, distinguished_reflections[index])) # optional - gap3 + ....: print('%s %s'%(index, distinguished_reflections[index])) a (1,4)(2,3)(5,6) b (1,3)(2,5)(4,6) c (1,5)(2,4)(3,6) @@ -612,13 +614,13 @@ def distinguished_reflections(self): sage: W = ReflectionGroup((3,1,1)) # optional - gap3 sage: distinguished_reflections = W.distinguished_reflections() # optional - gap3 sage: for index in sorted(distinguished_reflections.keys()): # optional - gap3 - ....: print('%s %s'%(index, distinguished_reflections[index])) # optional - gap3 + ....: print('%s %s'%(index, distinguished_reflections[index])) 1 (1,2,3) sage: W = ReflectionGroup((1,1,3), (3,1,2)) # optional - gap3 sage: distinguished_reflections = W.distinguished_reflections() # optional - gap3 sage: for index in sorted(distinguished_reflections.keys()): # optional - gap3 - ....: print('%s %s'%(index, distinguished_reflections[index])) # optional - gap3 + ....: print('%s %s'%(index, distinguished_reflections[index])) 1 (1,6)(2,5)(7,8) 2 (1,5)(2,7)(6,8) 3 (3,9,15)(4,10,16)(12,17,23)(14,18,24)(20,25,29)(21,22,26)(27,28,30) @@ -766,7 +768,7 @@ def irreducible_component_index_sets(self): for i,j in itertools.combinations(I,2) if s[i]*s[j] != s[j]*s[i] ]], format="vertices_and_edges") - return G.connected_components() + return G.connected_components(sort=False) @abstract_method(optional=True) def irreducible_components(self): @@ -842,7 +844,6 @@ def is_reducible(self): """ return not self.is_irreducible() - class ElementMethods: def apply_simple_reflection_left(self, i): r""" @@ -1046,12 +1047,13 @@ def apply_reflections(self, word, side='right', word_type='all'): EXAMPLES:: - sage: W = ReflectionGroup((1,1,3)) # optional - gap3 - sage: W.one().apply_reflections([1]) # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup((1,1,3)) + sage: W.one().apply_reflections([1]) (1,4)(2,3)(5,6) - sage: W.one().apply_reflections([2]) # optional - gap3 + sage: W.one().apply_reflections([2]) (1,3)(2,5)(4,6) - sage: W.one().apply_reflections([2,1]) # optional - gap3 + sage: W.one().apply_reflections([2,1]) (1,2,6)(3,4,5) @@ -1080,14 +1082,15 @@ def apply_reflections(self, word, side='right', word_type='all'): s1 - sage: W = ReflectionGroup((1,1,3)) # optional - gap3 - sage: W.one().apply_reflections([1], word_type='distinguished') # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup((1,1,3)) + sage: W.one().apply_reflections([1], word_type='distinguished') (1,4)(2,3)(5,6) - sage: W.one().apply_reflections([2], word_type='distinguished') # optional - gap3 + sage: W.one().apply_reflections([2], word_type='distinguished') (1,3)(2,5)(4,6) - sage: W.one().apply_reflections([3], word_type='distinguished') # optional - gap3 + sage: W.one().apply_reflections([3], word_type='distinguished') (1,5)(2,4)(3,6) - sage: W.one().apply_reflections([2,1], word_type='distinguished') # optional - gap3 + sage: W.one().apply_reflections([2,1], word_type='distinguished') (1,2,6)(3,4,5) sage: W = ReflectionGroup((1,1,3), hyperplane_index_set=['A','B','C']); W # optional - gap3 diff --git a/src/sage/categories/covariant_functorial_construction.py b/src/sage/categories/covariant_functorial_construction.py index 40d661945e8..45c94bb7bc1 100644 --- a/src/sage/categories/covariant_functorial_construction.py +++ b/src/sage/categories/covariant_functorial_construction.py @@ -134,9 +134,10 @@ def category_from_parents(self, parents): EXAMPLES:: - sage: E = CombinatorialFreeModule(QQ, ["a", "b", "c"]) - sage: tensor.category_from_parents((E, E, E)) - Category of tensor products of finite dimensional vector spaces with basis over Rational Field + sage: E = CombinatorialFreeModule(QQ, ["a", "b", "c"]) # needs sage.modules + sage: tensor.category_from_parents((E, E, E)) # needs sage.modules + Category of tensor products of + finite dimensional vector spaces with basis over Rational Field """ from sage.structure.parent import Parent assert all(isinstance(parent, Parent) for parent in parents) @@ -198,7 +199,7 @@ def _repr_(self): sage: tensor # indirect doctest The tensor functorial construction """ - return "The %s functorial construction"%self._functor_name + return "The %s functorial construction" % self._functor_name def __call__(self, args, **kwargs): """ @@ -213,8 +214,8 @@ def __call__(self, args, **kwargs): EXAMPLES:: - sage: E = CombinatorialFreeModule(QQ, ["a", "b", "c"]); E.rename("E") - sage: tensor((E, E, E)) + sage: E = CombinatorialFreeModule(QQ, ["a", "b", "c"]); E.rename("E") # needs sage.modules + sage: tensor((E, E, E)) # needs sage.modules E # E # E """ args = tuple(args) # a bit brute force; let's see if this becomes a bottleneck later @@ -286,7 +287,7 @@ def _base_category_class(cls): """ module_name = cls.__module__.replace(cls._functor_category.lower() + "_","") import sys - name = cls.__name__.replace(cls._functor_category, "") + name = cls.__name__.replace(cls._functor_category, "") __import__(module_name) module = sys.modules[module_name] return (module.__dict__[name],) @@ -399,10 +400,12 @@ def category_of(cls, category, *args): EXAMPLES:: - sage: sage.categories.tensor.TensorProductsCategory.category_of(ModulesWithBasis(QQ)) + sage: C = sage.categories.tensor.TensorProductsCategory + sage: C.category_of(ModulesWithBasis(QQ)) Category of tensor products of vector spaces with basis over Rational Field - sage: sage.categories.algebra_functor.AlgebrasCategory.category_of(FiniteMonoids(), QQ) + sage: C = sage.categories.algebra_functor.AlgebrasCategory + sage: C.category_of(FiniteMonoids(), QQ) Join of Category of finite dimensional algebras with basis over Rational Field and Category of monoid algebras over Rational Field and Category of finite set algebras over Rational Field @@ -491,7 +494,7 @@ def _repr_object_names(self): sage: Semigroups().Subquotients() # indirect doctest Category of subquotients of semigroups """ - return "%s of %s"%(Category._repr_object_names(self), self.base_category()._repr_object_names()) + return "%s of %s" % (Category._repr_object_names(self), self.base_category()._repr_object_names()) def _latex_(self): r""" @@ -505,7 +508,7 @@ def _latex_(self): \mathbf{Algebras}(\mathbf{Semigroups}) """ from sage.misc.latex import latex - return "\\mathbf{%s}(%s)"%(self._short_name(), latex(self.base_category())) + return "\\mathbf{%s}(%s)" % (self._short_name(), latex(self.base_category())) class CovariantConstructionCategory(FunctorialConstructionCategory): """ @@ -540,7 +543,8 @@ def default_super_categories(cls, category, *args): Bialgebras are both algebras and coalgebras:: sage: Bialgebras(QQ).super_categories() - [Category of algebras over Rational Field, Category of coalgebras over Rational Field] + [Category of algebras over Rational Field, + Category of coalgebras over Rational Field] Hence tensor products of bialgebras are tensor products of algebras and tensor products of coalgebras:: @@ -551,8 +555,10 @@ def default_super_categories(cls, category, *args): Here is how :meth:`default_super_categories` was called internally:: - sage: sage.categories.tensor.TensorProductsCategory.default_super_categories(Bialgebras(QQ)) - Join of Category of tensor products of algebras over Rational Field and Category of tensor products of coalgebras over Rational Field + sage: C = sage.categories.tensor.TensorProductsCategory + sage: C.default_super_categories(Bialgebras(QQ)) + Join of Category of tensor products of algebras over Rational Field + and Category of tensor products of coalgebras over Rational Field We now show a similar example, with the ``Algebra`` functor which takes a parameter `\QQ`:: @@ -570,7 +576,8 @@ def default_super_categories(cls, category, *args): Here is how :meth:`default_super_categories` was called internally:: - sage: sage.categories.algebra_functor.AlgebrasCategory.default_super_categories(FiniteMonoids(), QQ) + sage: C = sage.categories.algebra_functor.AlgebrasCategory + sage: C.default_super_categories(FiniteMonoids(), QQ) Join of Category of finite dimensional algebras with basis over Rational Field and Category of monoid algebras over Rational Field and Category of finite set algebras over Rational Field @@ -609,7 +616,8 @@ def is_construction_defined_by_base(self): sage: Bialgebras(QQ).Graded().is_construction_defined_by_base() Traceback (most recent call last): ... - AttributeError: 'JoinCategory_with_category' object has no attribute 'is_construction_defined_by_base' + AttributeError: 'JoinCategory_with_category' object has + no attribute 'is_construction_defined_by_base' """ base = self.base_category() f = self._functor_category diff --git a/src/sage/categories/coxeter_group_algebras.py b/src/sage/categories/coxeter_group_algebras.py index c8a3d935f05..5cececc3fef 100644 --- a/src/sage/categories/coxeter_group_algebras.py +++ b/src/sage/categories/coxeter_group_algebras.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.groups r""" Coxeter Group Algebras """ @@ -167,10 +168,10 @@ def demazure_lusztig_eigenvectors(self, q1, q2): sage: q1, q2 = K.gens() sage: KW = W.algebra(K) sage: E = KW.demazure_lusztig_eigenvectors(q1,q2) - sage: E.keys() + sage: E.keys() # needs sage.rings.number_field Weyl Group of type ['B', 2] (as a matrix group acting on the ambient space) sage: w = W.an_element() - sage: E[w] + sage: E[w] # needs sage.rings.number_field (q2/(-q1+q2))*2121 + ((-q2)/(-q1+q2))*121 - 212 + 12 """ W = self.basis().keys() diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 98fe35a0ab3..b5e5da9ea1a 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -57,17 +57,17 @@ class CoxeterGroups(Category_singleton): The 5-th dihedral group of order 10 sage: FiniteWeylGroups().example() The symmetric group on {0, ..., 3} - sage: WeylGroup(["B", 3]) + sage: WeylGroup(["B", 3]) # needs sage.combinat sage.groups Weyl Group of type ['B', 3] (as a matrix group acting on the ambient space) - sage: S4 = SymmetricGroup(4); S4 + sage: S4 = SymmetricGroup(4); S4 # needs sage.groups Symmetric group of order 4! as a permutation group - sage: S4 in CoxeterGroups().Finite() + sage: S4 in CoxeterGroups().Finite() # needs sage.groups True Those will eventually be also in this category:: - sage: DihedralGroup(5) + sage: DihedralGroup(5) # needs sage.groups Dihedral group of order 10 as a permutation group .. TODO:: add a demo of usual computations on Coxeter groups. @@ -136,8 +136,8 @@ def coxeter_matrix(self): EXAMPLES:: - sage: G = WeylGroup(['A',3]) - sage: G.coxeter_matrix() + sage: G = WeylGroup(['A', 3]) # needs sage.combinat sage.groups + sage: G.coxeter_matrix() # needs sage.combinat sage.groups [1 3 2] [3 1 3] [2 3 1] @@ -150,13 +150,14 @@ def index_set(self): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: W = CoxeterGroup([[1,3],[3,1]]) sage: W.index_set() (1, 2) sage: W = CoxeterGroup([[1,3],[3,1]], index_set=['x', 'y']) sage: W.index_set() ('x', 'y') - sage: W = CoxeterGroup(['H',3]) + sage: W = CoxeterGroup(['H', 3]) sage: W.index_set() (1, 2, 3) """ @@ -168,7 +169,8 @@ def coxeter_diagram(self): EXAMPLES:: - sage: W = CoxeterGroup(['H',3], implementation="reflection") + sage: # needs sage.combinat sage.graphs sage.groups + sage: W = CoxeterGroup(['H', 3], implementation="reflection") sage: G = W.coxeter_diagram(); G Graph on 3 vertices sage: G.edges(sort=True) @@ -190,8 +192,8 @@ def coxeter_type(self): EXAMPLES:: - sage: W = CoxeterGroup(['H',3]) - sage: W.coxeter_type() + sage: W = CoxeterGroup(['H', 3]) # needs sage.combinat sage.groups + sage: W.coxeter_type() # needs sage.combinat sage.groups Coxeter type of ['H', 3] """ return self.coxeter_matrix().coxeter_type() @@ -203,12 +205,12 @@ def braid_relations(self): EXAMPLES:: - sage: W = WeylGroup(["A",2]) - sage: W.braid_relations() + sage: W = WeylGroup(["A", 2]) # needs sage.combinat sage.groups + sage: W.braid_relations() # needs sage.combinat sage.groups [[[1, 2, 1], [2, 1, 2]]] - sage: W = WeylGroup(["B",3]) - sage: W.braid_relations() + sage: W = WeylGroup(["B", 3]) # needs sage.combinat sage.groups + sage: W.braid_relations() # needs sage.combinat sage.groups [[[1, 2, 1], [2, 1, 2]], [[1, 3], [3, 1]], [[2, 3, 2, 3], [3, 2, 3, 2]]] """ rels = [] @@ -228,16 +230,16 @@ def braid_group_as_finitely_presented_group(self): EXAMPLES:: - sage: W = CoxeterGroup(['A',2]) - sage: W.braid_group_as_finitely_presented_group() + sage: W = CoxeterGroup(['A', 2]) # needs sage.combinat sage.groups + sage: W.braid_group_as_finitely_presented_group() # needs sage.combinat sage.groups Finitely presented group < S1, S2 | S1*S2*S1*S2^-1*S1^-1*S2^-1 > - sage: W = WeylGroup(['B',2]) - sage: W.braid_group_as_finitely_presented_group() + sage: W = WeylGroup(['B', 2]) # needs sage.combinat sage.groups + sage: W.braid_group_as_finitely_presented_group() # needs sage.combinat sage.groups Finitely presented group < S1, S2 | (S1*S2)^2*(S1^-1*S2^-1)^2 > sage: W = ReflectionGroup(['B',3], index_set=["AA","BB","5"]) # optional - gap3 - sage: W.braid_group_as_finitely_presented_group() # optional - gap3 + sage: W.braid_group_as_finitely_presented_group() # optional - gap3 Finitely presented group < SAA, SBB, S5 | (SAA*SBB)^2*(SAA^-1*SBB^-1)^2, SAA*S5*SAA^-1*S5^-1, SBB*S5*SBB*S5^-1*SBB^-1*S5^-1 > @@ -251,6 +253,53 @@ def braid_group_as_finitely_presented_group(self): rels = self.braid_relations() return F / [prod(S[I.index(i)] for i in l) * prod(S[I.index(i)]**-1 for i in reversed(r)) for l, r in rels] + def braid_orbit_iter(self, word): + r""" + Iterate over the braid orbit of a word ``word`` of indices. + + The input word does not need to be a reduced expression of + an element. + + INPUT: + + - ``word`` -- a list (or iterable) of indices in + ``self.index_set()`` + + OUTPUT: + + all lists that can be obtained from + ``word`` by replacements of braid relations + + EXAMPLES:: + + sage: W = CoxeterGroups().example() + sage: sorted(W.braid_orbit_iter([0, 1, 2, 1])) # needs sage.combinat sage.graphs + [[0, 1, 2, 1], [0, 2, 1, 2], [2, 0, 1, 2]] + """ + word = list(word) + from sage.combinat.root_system.braid_orbit import BraidOrbit + + braid_rels = self.braid_relations() + I = self.index_set() + + from sage.rings.integer_ring import ZZ + be_careful = any(i not in ZZ for i in I) + + if be_careful: + Iinv = {i: j for j, i in enumerate(I)} + word = [Iinv[i] for i in word] + braid_rels = [[[Iinv[i] for i in l], + [Iinv[i] for i in r]] for l, r in braid_rels] + + orb = BraidOrbit(word, braid_rels) + + if be_careful: + for word in orb: + yield [I[i] for i in word] + else: + for I in orb: + yield list(I) + def braid_orbit(self, word): r""" Return the braid orbit of a word ``word`` of indices. @@ -279,15 +328,16 @@ def braid_orbit(self, word): sage: word = w.reduced_word(); word [0, 1, 2, 1] - sage: sorted(W.braid_orbit(word)) + sage: sorted(W.braid_orbit(word)) # needs sage.combinat sage.graphs [[0, 1, 2, 1], [0, 2, 1, 2], [2, 0, 1, 2]] - sage: sorted(W.braid_orbit([2,1,1,2,1])) + sage: sorted(W.braid_orbit([2,1,1,2,1])) # needs sage.combinat sage.graphs [[1, 2, 1, 1, 2], [2, 1, 1, 2, 1], [2, 1, 2, 1, 2], [2, 2, 1, 2, 2]] - sage: W = ReflectionGroup(['A',3], index_set=["AA","BB","5"]) # optional - gap3 - sage: w = W.long_element() # optional - gap3 - sage: W.braid_orbit(w.reduced_word()) # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(['A',3], index_set=["AA","BB","5"]) + sage: w = W.long_element() + sage: W.braid_orbit(w.reduced_word()) [['BB', '5', 'AA', 'BB', '5', 'AA'], ['5', 'BB', '5', 'AA', 'BB', '5'], ['BB', 'AA', 'BB', '5', 'BB', 'AA'], @@ -314,26 +364,7 @@ def braid_orbit(self, word): :meth:`.reduced_words` """ - word = list(word) - from sage.combinat.root_system.braid_orbit import BraidOrbit - - braid_rels = self.braid_relations() - I = self.index_set() - - from sage.rings.integer_ring import ZZ - be_careful = any(i not in ZZ for i in I) - - if be_careful: - Iinv = {i: j for j, i in enumerate(I)} - word = [Iinv[i] for i in word] - braid_rels = [[[Iinv[i] for i in l], - [Iinv[i] for i in r]] for l, r in braid_rels] - - orb = BraidOrbit(word, braid_rels) - - if be_careful: - return [[I[i] for i in word] for word in orb] - return [list(I) for I in orb] + return list(self.braid_orbit_iter(word)) def __iter__(self): r""" @@ -354,7 +385,8 @@ def __iter__(self): (2, 1, 2), (2, 1, 2, 1)] - sage: W = WeylGroup(["A",2,1]) + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(["A", 2, 1]) sage: g = iter(W) sage: next(g) [1 0 0] @@ -377,7 +409,8 @@ def _element_constructor_(self, x, **args): EXAMPLES:: - sage: W1 = WeylGroup("G2",prefix="s") + sage: # needs sage.combinat sage.groups + sage: W1 = WeylGroup("G2", prefix="s") sage: W2 = CoxeterGroup("G2") sage: W3 = CoxeterGroup("G2", implementation="permutation") sage: W1(W2.an_element()) @@ -387,9 +420,9 @@ def _element_constructor_(self, x, **args): [ a -1] sage: W1(W3.an_element()) s1*s2 - sage: s1,s2 = W1.simple_reflections() + sage: s1, s2 = W1.simple_reflections() sage: W = CoxeterGroup("A1") - sage: W(s1*s2) + sage: W(s1 * s2) Traceback (most recent call last): ... ValueError: inconsistent number of rows: should be 1 but got 3 @@ -419,7 +452,7 @@ def weak_order_ideal(self, predicate, side="right", category=None): EXAMPLES:: sage: D6 = FiniteCoxeterGroups().example(5) - sage: I = D6.weak_order_ideal(predicate = lambda w: w.length() <= 3) + sage: I = D6.weak_order_ideal(predicate=lambda w: w.length() <= 3) sage: I.cardinality() 7 sage: list(I) @@ -427,9 +460,9 @@ def weak_order_ideal(self, predicate, side="right", category=None): We now consider an infinite Coxeter group:: - sage: W = WeylGroup(["A",1,1]) - sage: I = W.weak_order_ideal(predicate = lambda w: w.length() <= 2) - sage: list(iter(I)) + sage: W = WeylGroup(["A",1,1]) # needs sage.groups sage.rings.number_field + sage: I = W.weak_order_ideal(predicate=lambda w: w.length() <= 2) # needs sage.groups sage.rings.number_field + sage: list(iter(I)) # needs sage.groups sage.rings.number_field [ [1 0] [-1 2] [ 1 0] [ 3 -2] [-1 2] [0 1], [ 0 1], [ 2 -1], [ 2 -1], [-2 3] @@ -438,17 +471,17 @@ def weak_order_ideal(self, predicate, side="right", category=None): Even when the result is finite, some features of :class:`FiniteEnumeratedSets` are not available:: - sage: I.cardinality() # todo: not implemented + sage: I.cardinality() # todo: not implemented 5 - sage: list(I) # todo: not implemented + sage: list(I) # todo: not implemented unless this finiteness is explicitly specified:: - sage: I = W.weak_order_ideal(predicate = lambda w: w.length() <= 2, - ....: category = FiniteEnumeratedSets()) - sage: I.cardinality() + sage: I = W.weak_order_ideal(predicate=lambda w: w.length() <= 2, # needs sage.groups sage.rings.number_field + ....: category=FiniteEnumeratedSets()) + sage: I.cardinality() # needs sage.groups sage.rings.number_field 5 - sage: list(I) + sage: list(I) # needs sage.groups sage.rings.number_field [ [1 0] [-1 2] [ 1 0] [ 3 -2] [-1 2] [0 1], [ 0 1], [ 2 -1], [ 2 -1], [-2 3] @@ -471,8 +504,8 @@ def weak_order_ideal(self, predicate, side="right", category=None): We iterate over each level (i.e., breadth-first-search in the search forest), see :trac:`19926`:: - sage: W = CoxeterGroup(['A',2]) - sage: [x.length() for x in W] + sage: W = CoxeterGroup(['A',2]) # needs sage.groups sage.rings.number_field + sage: [x.length() for x in W] # needs sage.groups sage.rings.number_field [0, 1, 1, 2, 2, 3] """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest @@ -485,9 +518,10 @@ def succ(u): from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups default_category = FiniteEnumeratedSets() if self in FiniteCoxeterGroups() else EnumeratedSets() + cat = default_category.or_subcategory(category) return RecursivelyEnumeratedSet_forest((self.one(),), succ, - algorithm='breadth', - category=default_category.or_subcategory(category)) + algorithm='breadth', + category=cat) @cached_method def coxeter_element(self): @@ -511,6 +545,7 @@ def coxeter_element(self): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: CoxeterGroup(['A', 4]).coxeter_element().reduced_word() [1, 2, 3, 4] sage: CoxeterGroup(['B', 4]).coxeter_element().reduced_word() @@ -545,9 +580,9 @@ def coxeter_element(self): TESTS:: - sage: WeylGroup(['A', 4]).coxeter_element().reduced_word() + sage: WeylGroup(['A', 4]).coxeter_element().reduced_word() # needs sage.combinat sage.groups [1, 2, 3, 4] - sage: SymmetricGroup(3).coxeter_element() + sage: SymmetricGroup(3).coxeter_element() # needs sage.groups (1,3,2) """ return self.prod(self.simple_reflections()) @@ -575,24 +610,24 @@ class is not unique and we only obtain one such class. TESTS:: - sage: W = SymmetricGroup(3) - sage: sorted(W.standard_coxeter_elements()) + sage: W = SymmetricGroup(3) # needs sage.groups + sage: sorted(W.standard_coxeter_elements()) # needs sage.combinat sage.groups [(1,2,3), (1,3,2)] sage: W = Permutations(3) - sage: sorted(W.standard_coxeter_elements()) + sage: sorted(W.standard_coxeter_elements()) # needs sage.graphs [[2, 3, 1], [3, 1, 2]] - sage: W = CoxeterGroup(['D',3]) - sage: sorted(W.standard_coxeter_elements()) + sage: W = CoxeterGroup(['D', 3]) # needs sage.combinat sage.groups + sage: sorted(W.standard_coxeter_elements()) # needs sage.combinat sage.groups [ [-1 1 1] [ 0 -1 1] [ 0 1 -1] [ 1 -1 -1] [-1 0 1] [ 1 -1 0] [ 0 0 -1] [ 1 -1 0] [-1 1 0], [ 0 -1 0], [ 1 0 -1], [ 1 0 -1] ] - sage: W = ColoredPermutations(3,2) - sage: len(W.standard_coxeter_elements()) + sage: W = ColoredPermutations(3,2) # needs sage.combinat + sage: len(W.standard_coxeter_elements()) # needs sage.combinat sage.graphs 2 """ if not self.is_irreducible() or not self.is_well_generated(): @@ -642,8 +677,9 @@ def fully_commutative_elements(self): EXAMPLES:: - sage: CoxeterGroup(['A', 3]).fully_commutative_elements() - Fully commutative elements of Finite Coxeter group over Integer Ring with Coxeter matrix: + sage: CoxeterGroup(['A', 3]).fully_commutative_elements() # needs sage.combinat sage.groups + Fully commutative elements of + Finite Coxeter group over Integer Ring with Coxeter matrix: [1 3 2] [3 1 3] [2 3 1] @@ -689,7 +725,7 @@ def simple_projection(self, i, side='right', length_increasing=True): sage: sigma (1, 2, 3, 0) sage: u0 = W.simple_projection(0) - sage: d0 = W.simple_projection(0,length_increasing=False) + sage: d0 = W.simple_projection(0, length_increasing=False) sage: sigma.length() 3 sage: pi=sigma*s[0] @@ -738,6 +774,7 @@ def kazhdan_lusztig_cells(self, side='left'): representation of elements in the output cells but not the method used for the cell computation:: + sage: # needs sage.combinat sage.groups sage: W = CoxeterGroup('A2') sage: KL_cells = W.kazhdan_lusztig_cells(side='right') sage: set([tuple(sorted(C, key=lambda w: w.reduced_word())) @@ -761,8 +798,8 @@ def kazhdan_lusztig_cells(self, side='left'): sage: len(KL_cells) 4 - sage: W = CoxeterGroup('A2', implementation='permutation') - sage: len(W.kazhdan_lusztig_cells(side='right')) + sage: W = CoxeterGroup('A2', implementation='permutation') # needs sage.combinat sage.groups + sage: len(W.kazhdan_lusztig_cells(side='right')) # needs sage.combinat sage.groups 4 We compute the left cells in the Coxeter group of type `A_3` @@ -770,9 +807,10 @@ def kazhdan_lusztig_cells(self, side='left'): runs in the background even if the group is not created with the ``'coxeter3'`` implementation:: - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: KL_cells = W.kazhdan_lusztig_cells() # optional - coxeter3 - sage: set([tuple(sorted(C)) for C in KL_cells]) # optional - coxeter3 + sage: # optional - coxeter3, needs sage.combinat sage.groups sage.libs.gap sage.modules sage.rings.number_field + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: KL_cells = W.kazhdan_lusztig_cells() + sage: set([tuple(sorted(C)) for C in KL_cells]) {([],), ([1], [2, 1], [3, 2, 1]), ([1, 2], [2], [3, 2]), @@ -783,20 +821,21 @@ def kazhdan_lusztig_cells(self, side='left'): ([1, 2, 3], [2, 3], [3]), ([1, 3], [2, 1, 3]), ([1, 3, 2], [2, 1, 3, 2])} - sage: len(KL_cells) # optional - coxeter3 + sage: len(KL_cells) 10 - - sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 - sage: len(W.kazhdan_lusztig_cells()) # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='permutation') + sage: len(W.kazhdan_lusztig_cells()) 10 Computing the two sided cells in `B_3`:: - sage: W = CoxeterGroup('B3', implementation='coxeter3') # optional - coxeter3 - sage: b3_cells = W.kazhdan_lusztig_cells('two-sided') # optional - coxeter3 - sage: len(b3_cells) # optional - coxeter3 + sage: # optional - coxeter3, needs sage.combinat sage.groups sage.libs.gap sage.modules sage.rings.number_field + sage: W = CoxeterGroup('B3', implementation='coxeter3') + sage: b3_cells = W.kazhdan_lusztig_cells('two-sided') + sage: len(b3_cells) 6 - sage: set([tuple(sorted(C)) for C in W.kazhdan_lusztig_cells()]) # optional - coxeter3 + sage: set([tuple(sorted(C)) + ....: for C in W.kazhdan_lusztig_cells()]) {([],), ([1], [1, 2, 3, 2, 1], [2, 1], [2, 3, 2, 1], [3, 2, 1]), ([1, 2], [1, 2, 3, 2], [2], [2, 3, 2], [3, 2]), @@ -825,8 +864,8 @@ def kazhdan_lusztig_cells(self, side='left'): TESTS:: - sage: W = CoxeterGroup(['A', 2, 1]) - sage: W.kazhdan_lusztig_cells() + sage: W = CoxeterGroup(['A', 2, 1]) # needs sage.combinat sage.groups + sage: W.kazhdan_lusztig_cells() # needs sage.combinat sage.groups Traceback (most recent call last): ... ValueError: the Coxeter group must be finite to compute Kazhdan--Lusztig cells @@ -887,7 +926,9 @@ def simple_projections(self, side='right', length_increasing=True): sage: sigma = W.an_element(); sigma (1, 2, 3, 0) sage: pi = W.simple_projections(); pi - Finite family {0: <function ...<lambda> at ...>, 1: <function ...<lambda> at ...>, 2: <function ...<lambda> ...>} + Finite family {0: <function ...<lambda> at ...>, + 1: <function ...<lambda> at ...>, + 2: <function ...<lambda> ...>} sage: pi[1](sigma) (1, 3, 2, 0) sage: W.simple_projection(1)(sigma) @@ -907,9 +948,11 @@ def sign_representation(self, base_ring=None, side="twosided"): EXAMPLES:: - sage: W = WeylGroup(["A", 1, 1]) - sage: W.sign_representation() - Sign representation of Weyl Group of type ['A', 1, 1] (as a matrix group acting on the root space) over Integer Ring + sage: W = WeylGroup(["A", 1, 1]) # needs sage.combinat sage.groups + sage: W.sign_representation() # needs sage.combinat sage.groups + Sign representation of + Weyl Group of type ['A', 1, 1] (as a matrix group acting on the root space) + over Integer Ring """ if base_ring is None: @@ -933,18 +976,18 @@ def demazure_product(self, Q): EXAMPLES:: - sage: W = WeylGroup(['A',2]) + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['A', 2]) sage: w = W.demazure_product([2,2,1]) sage: w.reduced_word() [2, 1] - sage: w = W.demazure_product([2,1,2,1,2]) sage: w.reduced_word() [1, 2, 1] - sage: W = WeylGroup(['B',2]) - sage: w = W.demazure_product([2,1,2,1,2]) - sage: w.reduced_word() + sage: W = WeylGroup(['B', 2]) # needs sage.combinat sage.groups + sage: w = W.demazure_product([2,1,2,1,2]) # needs sage.combinat sage.groups + sage: w.reduced_word() # needs sage.combinat sage.groups [2, 1, 2, 1] """ return self.one().apply_demazure_product(Q) @@ -955,16 +998,16 @@ def bruhat_interval(self, x, y): EXAMPLES:: - sage: W = WeylGroup("A3", prefix="s") - sage: [s1,s2,s3] = W.simple_reflections() - sage: W.bruhat_interval(s2,s1*s3*s2*s1*s3) + sage: W = WeylGroup("A3", prefix="s") # needs sage.combinat sage.groups + sage: s1, s2, s3 = W.simple_reflections() # needs sage.combinat sage.groups + sage: W.bruhat_interval(s2, s1*s3*s2*s1*s3) # needs sage.combinat sage.groups [s1*s2*s3*s2*s1, s2*s3*s2*s1, s3*s1*s2*s1, s1*s2*s3*s1, s1*s2*s3*s2, s3*s2*s1, s2*s3*s1, s2*s3*s2, s1*s2*s1, s3*s1*s2, s1*s2*s3, s2*s1, s3*s2, s2*s3, s1*s2, s2] - sage: W = WeylGroup(['A',2,1], prefix="s") - sage: [s0,s1,s2] = W.simple_reflections() - sage: W.bruhat_interval(1,s0*s1*s2) + sage: W = WeylGroup(['A', 2, 1], prefix="s") # needs sage.combinat sage.groups + sage: s0, s1, s2 = W.simple_reflections() # needs sage.combinat sage.groups + sage: W.bruhat_interval(1, s0*s1*s2) # needs sage.combinat sage.groups [s0*s1*s2, s1*s2, s0*s2, s0*s1, s2, s1, s0, 1] """ if x == 1: @@ -994,19 +1037,19 @@ def bruhat_interval_poset(self, x, y, facade=False): EXAMPLES:: - sage: W = WeylGroup("A3", prefix="s") - sage: s1,s2,s3 = W.simple_reflections() - sage: W.bruhat_interval_poset(s2, s1*s3*s2*s1*s3) + sage: W = WeylGroup("A3", prefix="s") # needs sage.combinat sage.groups + sage: s1, s2, s3 = W.simple_reflections() # needs sage.combinat sage.groups + sage: W.bruhat_interval_poset(s2, s1*s3*s2*s1*s3) # needs sage.combinat sage.groups Finite poset containing 16 elements - sage: W = WeylGroup(['A',2,1], prefix="s") - sage: s0,s1,s2 = W.simple_reflections() - sage: W.bruhat_interval_poset(1, s0*s1*s2) + sage: W = WeylGroup(['A', 2, 1], prefix="s") # needs sage.combinat sage.groups + sage: s0, s1, s2 = W.simple_reflections() # needs sage.combinat sage.groups + sage: W.bruhat_interval_poset(1, s0*s1*s2) # needs sage.combinat sage.groups Finite poset containing 8 elements TESTS:: - sage: W.bruhat_interval_poset(s0*s1*s2, s0*s1*s2) + sage: W.bruhat_interval_poset(s0*s1*s2, s0*s1*s2) # needs sage.combinat sage.groups Finite poset containing 1 elements """ if x == 1: @@ -1061,27 +1104,27 @@ def bruhat_graph(self, x=None, y=None, edge_labels=False): EXAMPLES:: - sage: W = CoxeterGroup(['H',3]) - sage: G = W.bruhat_graph(); G + sage: W = CoxeterGroup(['H', 3]) # needs sage.combinat sage.graphs sage.groups + sage: G = W.bruhat_graph(); G # needs sage.combinat sage.graphs sage.groups Digraph on 120 vertices - sage: W = CoxeterGroup(['A',2,1]) + sage: # needs sage.combinat sage.graphs sage.groups + sage: W = CoxeterGroup(['A', 2, 1]) sage: s1, s2, s3 = W.simple_reflections() sage: W.bruhat_graph(s1, s1*s3*s2*s3) Digraph on 6 vertices - sage: W.bruhat_graph(s1, s3*s2*s3) Digraph on 0 vertices - sage: W = WeylGroup("A3", prefix="s") - sage: s1, s2, s3 = W.simple_reflections() - sage: G = W.bruhat_graph(s1*s3, s1*s2*s3*s2*s1); G + sage: W = WeylGroup("A3", prefix="s") # needs sage.combinat sage.graphs sage.groups + sage: s1, s2, s3 = W.simple_reflections() # needs sage.combinat sage.graphs sage.groups + sage: G = W.bruhat_graph(s1*s3, s1*s2*s3*s2*s1); G # needs sage.combinat sage.graphs sage.groups Digraph on 10 vertices Check that the graph has the correct number of edges (see :trac:`17744`):: - sage: len(G.edges(sort=False)) + sage: len(G.edges(sort=False)) # needs sage.combinat sage.graphs sage.groups 16 """ if x is None or x == 1: @@ -1129,8 +1172,8 @@ def canonical_representation(self): EXAMPLES:: - sage: W = WeylGroup("A3") - sage: W.canonical_representation() + sage: W = WeylGroup("A3") # needs sage.combinat sage.groups + sage: W.canonical_representation() # needs sage.combinat sage.groups Finite Coxeter group over Integer Ring with Coxeter matrix: [1 3 2] [3 1 3] @@ -1146,16 +1189,16 @@ def elements_of_length(self, n): EXAMPLES:: - sage: A = AffinePermutationGroup(['A',2,1]) - sage: [len(list(A.elements_of_length(i))) for i in [0..5]] + sage: A = AffinePermutationGroup(['A', 2, 1]) # needs sage.combinat + sage: [len(list(A.elements_of_length(i))) for i in [0..5]] # needs sage.combinat [1, 3, 6, 9, 12, 15] - sage: W = CoxeterGroup(['H',3]) - sage: [len(list(W.elements_of_length(i))) for i in range(4)] + sage: W = CoxeterGroup(['H', 3]) # needs sage.combinat sage.groups + sage: [len(list(W.elements_of_length(i))) for i in range(4)] # needs sage.combinat sage.groups [1, 3, 5, 7] - sage: W = CoxeterGroup(['A',2]) - sage: [len(list(W.elements_of_length(i))) for i in range(6)] + sage: W = CoxeterGroup(['A', 2]) # needs sage.combinat sage.groups + sage: [len(list(W.elements_of_length(i))) for i in range(6)] # needs sage.combinat sage.groups [1, 2, 2, 1, 0, 0] """ I = self.weak_order_ideal(ConstantFunction(True), side='right') @@ -1173,6 +1216,7 @@ def random_element_of_length(self, n): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: A = AffinePermutationGroup(['A', 7, 1]) sage: p = A.random_element_of_length(10) sage: p in A @@ -1180,6 +1224,7 @@ def random_element_of_length(self, n): sage: p.length() == 10 True + sage: # needs sage.combinat sage.groups sage: W = CoxeterGroup(['A', 4]) sage: p = W.random_element_of_length(5) sage: p in W @@ -1195,10 +1240,6 @@ def random_element_of_length(self, n): x = x.apply_simple_reflection_right(antiD[rnd]) return x - # TODO: Groups() should have inverse() call __invert__ - # With strong doc stating that this is just a convenience for the user - # and links to ~ / __invert__ - # parabolic_subgroup def _test_simple_projections(self, **options): @@ -1236,13 +1277,14 @@ def _test_has_descent(self, **options): sage: W = CoxeterGroups().example() sage: W._test_has_descent() + sage: # needs sage.combinat sage.groups sage: W = Permutations(4) sage: W._test_has_descent() sage: sage.combinat.permutation.Permutations.options.mult = "r2l" sage: W._test_has_descent() sage: sage.combinat.permutation.Permutations.options._reset() - sage: W = SignedPermutations(3) + sage: W = SignedPermutations(3) # needs sage.combinat sage: W._test_has_descent() """ tester = self._tester(**options) @@ -1300,28 +1342,32 @@ def _test_coxeter_relations(self, **options): TESTS:: - sage: A = AffinePermutationGroup(['A',7,1]) - sage: A._test_coxeter_relations() + sage: A = AffinePermutationGroup(['A', 7, 1]) # needs sage.combinat + sage: A._test_coxeter_relations() # needs sage.combinat - sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]]) - sage: W = WeylGroup(cm) - sage: W._test_coxeter_relations() + sage: cm = CartanMatrix([[2,-5,0], [-2,2,-1], [0,-1,2]]) # needs sage.graphs + sage: W = WeylGroup(cm) # needs sage.combinat sage.graphs sage.groups + sage: W._test_coxeter_relations() # needs sage.combinat sage.graphs sage.groups + sage: # needs sage.combinat sage.groups sage: W = Permutations(4) sage: W._test_coxeter_relations() sage: sage.combinat.permutation.Permutations.options.mult = "r2l" sage: W._test_coxeter_relations() sage: sage.combinat.permutation.Permutations.options._reset() - sage: W = SignedPermutations(3) - sage: W._test_coxeter_relations() + sage: W = SignedPermutations(3) # needs sage.combinat + sage: W._test_coxeter_relations() # needs sage.combinat """ tester = self._tester(**options) s = self.simple_reflections() one = self.one() for si in s: tester.assertEqual(si**2, one) - cox_mat = self.coxeter_matrix() + try: + cox_mat = self.coxeter_matrix() + except ImportError: + return I = cox_mat.index_set() for ii, i in enumerate(I): for j in I[ii + 1:]: @@ -1347,7 +1393,7 @@ def has_descent(self, i, side='right', positive=False): sage: w = s[0] * s[1] * s[2] sage: w.has_descent(2) True - sage: [ w.has_descent(i) for i in [0,1,2] ] + sage: [ w.has_descent(i) for i in [0,1,2] ] [False, False, True] sage: [ w.has_descent(i, side='left') for i in [0,1,2] ] [True, False, False] @@ -1484,7 +1530,7 @@ def descents(self, side='right', index_set=None, positive=False): return [i for i in index_set if self.has_descent(i, side=side, positive=positive)] - def is_grassmannian(self, side="right"): + def is_grassmannian(self, side="right") -> bool: """ Return whether ``self`` is Grassmannian. @@ -1520,6 +1566,50 @@ def is_grassmannian(self, side="right"): """ return len(self.descents(side=side)) <= 1 + def is_fully_commutative(self) -> bool: + r""" + Check if ``self`` is a fully-commutative element. + + We use the characterization that an element `w` in a Coxeter + system `(W,S)` is fully-commutative if and only if for every pair + of generators `s,t \in S` for which `m(s,t)>2`, no reduced + word of `w` contains the 'braid' word `sts...` of length + `m(s,t)` as a contiguous subword. See [Ste1996]_. + + EXAMPLES:: + + sage: # needs sage.combinat sage.groups + sage: W = CoxeterGroup(['A', 3]) + sage: len([1 for w in W if w.is_fully_commutative()]) + 14 + sage: W = CoxeterGroup(['B', 3]) + sage: len([1 for w in W if w.is_fully_commutative()]) + 24 + + TESTS:: + + sage: W = CoxeterGroup(matrix(2,2,[1,7,7,1]), index_set='ab') # needs sage.combinat sage.groups + sage: len([1 for w in W if w.is_fully_commutative()]) # needs sage.combinat sage.groups + 13 + """ + word = self.reduced_word() + from sage.combinat.root_system.braid_orbit import is_fully_commutative as is_fully_comm + + group = self.parent() + braid_rels = group.braid_relations() + I = group.index_set() + + from sage.rings.integer_ring import ZZ + be_careful = any(i not in ZZ for i in I) + + if be_careful: + Iinv = {i: j for j, i in enumerate(I)} + word = [Iinv[i] for i in word] + braid_rels = [[[Iinv[i] for i in l], + [Iinv[i] for i in r]] for l, r in braid_rels] + + return is_fully_comm(word, braid_rels) + def reduced_word_reverse_iterator(self): """ Return a reverse iterator on a reduced word for ``self``. @@ -1580,6 +1670,31 @@ def reduced_word(self): result = list(self.reduced_word_reverse_iterator()) return list(reversed(result)) + def reduced_words_iter(self): + r""" + Iterate over all reduced words for ``self``. + + See :meth:`reduced_word` for the definition of a reduced + word. + + The algorithm uses the Matsumoto property that any two + reduced expressions are related by braid relations, see + Theorem 3.3.1(ii) in [BB2005]_. + + .. SEEALSO:: + + :meth:`braid_orbit_iter` + + EXAMPLES:: + + sage: W = CoxeterGroups().example() + sage: s = W.simple_reflections() + sage: w = s[0] * s[2] + sage: sorted(w.reduced_words_iter()) # needs sage.combinat sage.graphs + [[0, 2], [2, 0]] + """ + return self.parent().braid_orbit_iter(self.reduced_word()) + def reduced_words(self): r""" Return all reduced words for ``self``. @@ -1600,17 +1715,19 @@ def reduced_words(self): sage: W = CoxeterGroups().example() sage: s = W.simple_reflections() sage: w = s[0] * s[2] - sage: sorted(w.reduced_words()) + sage: sorted(w.reduced_words()) # needs sage.graphs sage.modules [[0, 2], [2, 0]] - sage: W = WeylGroup(['E',6]) - sage: w = W.from_reduced_word([2,3,4,2]) - sage: sorted(w.reduced_words()) + sage: W = WeylGroup(['E', 6]) # needs sage.combinat sage.groups + sage: w = W.from_reduced_word([2,3,4,2]) # needs sage.combinat sage.groups + sage: sorted(w.reduced_words()) # needs sage.combinat sage.groups [[2, 3, 4, 2], [3, 2, 4, 2], [3, 4, 2, 4]] - sage: W = ReflectionGroup(['A',3], index_set=["AA","BB","5"]) # optional - gap3 - sage: w = W.long_element() # optional - gap3 - sage: w.reduced_words() # optional - gap3 + sage: # optional - gap3, needs sage.combinat sage.groups + sage: W = ReflectionGroup(['A',3], + ....: index_set=["AA","BB","5"]) + sage: w = W.long_element() + sage: w.reduced_words() [['BB', '5', 'AA', 'BB', '5', 'AA'], ['5', 'BB', '5', 'AA', 'BB', '5'], ['BB', 'AA', 'BB', '5', 'BB', 'AA'], @@ -1638,7 +1755,7 @@ def reduced_words(self): :meth:`.reduced_word`, :meth:`.reduced_word_reverse_iterator`, :meth:`length`, :meth:`reduced_word_graph` """ - return self.parent().braid_orbit(self.reduced_word()) + return list(self.reduced_words_iter()) def support(self): r""" @@ -1693,7 +1810,8 @@ def reduced_word_graph(self): EXAMPLES:: - sage: W = WeylGroup(['A',3], prefix='s') + sage: # needs sage.combinat sage.graphs sage.groups + sage: W = WeylGroup(['A', 3], prefix='s') sage: w0 = W.long_element() sage: G = w0.reduced_word_graph() sage: G.num_verts() @@ -1710,10 +1828,11 @@ def reduced_word_graph(self): TESTS:: sage: p = Permutation([3,2,4,1]) - sage: pp = WeylGroup(['A',3]).from_reduced_word(p.reduced_word()) - sage: pp.reduced_word_graph() + sage: pp = WeylGroup(['A',3]).from_reduced_word(p.reduced_word()) # needs sage.combinat sage.groups + sage: pp.reduced_word_graph() # needs sage.combinat sage.graphs sage.groups Graph on 3 vertices + sage: # needs sage.combinat sage.graphs sage.groups sage: w1 = W.one() sage: G = w1.reduced_word_graph() sage: G.num_verts() @@ -1814,14 +1933,14 @@ def reflection_length(self): EXAMPLES:: - sage: W = WeylGroup(['A',3]) - sage: s = W.simple_reflections() - sage: (s[1]*s[2]*s[3]).reflection_length() + sage: W = WeylGroup(['A', 3]) # needs sage.combinat sage.groups + sage: s = W.simple_reflections() # needs sage.combinat sage.groups + sage: (s[1]*s[2]*s[3]).reflection_length() # needs sage.combinat sage.groups 3 - sage: W = SymmetricGroup(4) - sage: s = W.simple_reflections() - sage: (s[3]*s[2]*s[3]).reflection_length() + sage: W = SymmetricGroup(4) # needs sage.groups + sage: s = W.simple_reflections() # needs sage.groups + sage: (s[3]*s[2]*s[3]).reflection_length() # needs sage.combinat sage.groups 1 """ @@ -1844,14 +1963,14 @@ def absolute_length(self): EXAMPLES:: - sage: W = WeylGroup(["A", 3]) - sage: s = W.simple_reflections() - sage: (s[1]*s[2]*s[3]).absolute_length() + sage: W = WeylGroup(["A", 3]) # needs sage.combinat sage.groups + sage: s = W.simple_reflections() # needs sage.combinat sage.groups + sage: (s[1]*s[2]*s[3]).absolute_length() # needs sage.combinat sage.groups 3 - sage: W = SymmetricGroup(4) - sage: s = W.simple_reflections() - sage: (s[3]*s[2]*s[1]).absolute_length() + sage: W = SymmetricGroup(4) # needs sage.groups + sage: s = W.simple_reflections() # needs sage.groups + sage: (s[3]*s[2]*s[1]).absolute_length() # needs sage.combinat sage.groups 3 """ M = self.canonical_matrix() @@ -1876,6 +1995,7 @@ def absolute_le(self, other): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: W = WeylGroup(["A", 3]) sage: s = W.simple_reflections() sage: w0 = s[1] @@ -1891,24 +2011,31 @@ def absolute_le(self, other): Check that this is independent of the implementation of the group, see :trac:`34799`:: - sage: W1 = WeylGroup(['A',2]) + sage: # needs sage.combinat sage.groups + sage: W1 = WeylGroup(['A', 2]) sage: W2 = Permutations(3) sage: P = lambda pi: W2(list(pi.to_permutation())) - sage: d1 = set((P(w1), P(w2)) for w1 in W1 for w2 in W1 if w1.absolute_le(w2)) - sage: d2 = set((w1, w2) for w1 in W2 for w2 in W2 if w1.absolute_le(w2)) + sage: d1 = set((P(w1), P(w2)) for w1 in W1 for w2 in W1 + ....: if w1.absolute_le(w2)) + sage: d2 = set((w1, w2) for w1 in W2 for w2 in W2 + ....: if w1.absolute_le(w2)) sage: d1 == d2 True sage: sage.combinat.permutation.Permutations.options.mult = "r2l" - sage: d3 = set((w1, w2) for w1 in W2 for w2 in W2 if w1.absolute_le(w2)) + sage: d3 = set((w1, w2) + ....: for w1 in W2 for w2 in W2 if w1.absolute_le(w2)) sage: d1 == d3 True sage: sage.combinat.permutation.Permutations.options._reset() - sage: W1 = WeylGroup(['B',2]) + sage: # needs sage.combinat sage.groups + sage: W1 = WeylGroup(['B', 2]) sage: W2 = SignedPermutations(2) sage: P = lambda pi: W2(list(pi.to_permutation())) - sage: d1 = set((P(w1), P(w2)) for w1 in W1 for w2 in W1 if w1.absolute_le(w2)) - sage: d2 = set((w1, w2) for w1 in W2 for w2 in W2 if w1.absolute_le(w2)) + sage: d1 = set((P(w1), P(w2)) + ....: for w1 in W1 for w2 in W1 if w1.absolute_le(w2)) + sage: d2 = set((w1, w2) + ....: for w1 in W2 for w2 in W2 if w1.absolute_le(w2)) sage: d1 == d2 True """ @@ -1928,6 +2055,7 @@ def absolute_covers(self): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: W = WeylGroup(["A", 3]) sage: s = W.simple_reflections() sage: w0 = s[1] @@ -1956,9 +2084,9 @@ def canonical_matrix(self): EXAMPLES:: - sage: W = WeylGroup(["A", 3]) - sage: s = W.simple_reflections() - sage: (s[1]*s[2]*s[3]).canonical_matrix() + sage: W = WeylGroup(["A", 3]) # needs sage.combinat sage.groups + sage: s = W.simple_reflections() # needs sage.combinat sage.groups + sage: (s[1]*s[2]*s[3]).canonical_matrix() # needs sage.combinat sage.groups [ 0 0 -1] [ 1 0 -1] [ 0 1 -1] @@ -1988,11 +2116,11 @@ def coset_representative(self, index_set, side='right'): [2, 3] sage: w.coset_representative([1,2]).reduced_word() [2, 3] - sage: w.coset_representative([1,3] ).reduced_word() + sage: w.coset_representative([1,3] ).reduced_word() [2] - sage: w.coset_representative([2,3] ).reduced_word() + sage: w.coset_representative([2,3] ).reduced_word() [2, 1] - sage: w.coset_representative([1,2,3] ).reduced_word() + sage: w.coset_representative([1,2,3] ).reduced_word() [] sage: w.coset_representative([], side='left').reduced_word() [2, 3, 1] @@ -2039,7 +2167,9 @@ def apply_simple_projection(self, i, side='right', length_increasing=True): (1, 2, 3, 0) sage: w.apply_simple_projection(2, length_increasing=False) (1, 2, 0, 3) - sage: W = WeylGroup(['C',4],prefix="s") + + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['C', 4], prefix="s") sage: v = W.from_reduced_word([1,2,3,4,3,1]) sage: v s1*s2*s3*s4*s3*s1 @@ -2047,7 +2177,7 @@ def apply_simple_projection(self, i, side='right', length_increasing=True): s1*s2*s3*s4*s3*s1*s2 sage: v.apply_simple_projection(2, side='left') s1*s2*s3*s4*s3*s1 - sage: v.apply_simple_projection(1, length_increasing = False) + sage: v.apply_simple_projection(1, length_increasing=False) s1*s2*s3*s4*s3 """ @@ -2075,7 +2205,8 @@ def binary_factorizations(self, predicate=ConstantFunction(True)): We construct the set of all factorizations of the maximal element of the group:: - sage: W = WeylGroup(['A',3]) + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['A', 3]) sage: s = W.simple_reflections() sage: w0 = W.from_reduced_word([1,2,3,1,2,1]) sage: w0.binary_factorizations().cardinality() @@ -2083,28 +2214,35 @@ def binary_factorizations(self, predicate=ConstantFunction(True)): The same number of factorizations, by bounded length:: - sage: [w0.binary_factorizations(lambda u: u.length() <= l).cardinality() for l in [-1,0,1,2,3,4,5,6]] + sage: [w0.binary_factorizations( # needs sage.combinat sage.groups + ....: lambda u: u.length() <= l + ....: ).cardinality() + ....: for l in [-1,0,1,2,3,4,5,6]] [0, 1, 4, 9, 15, 20, 23, 24] The number of factorizations of the elements just below the maximal element:: - sage: [(s[i]*w0).binary_factorizations().cardinality() for i in [1,2,3]] + sage: [(s[i]*w0).binary_factorizations().cardinality() # needs sage.combinat sage.groups + ....: for i in [1,2,3]] [12, 12, 12] - sage: w0.binary_factorizations(lambda u: False).cardinality() + sage: w0.binary_factorizations(lambda u: False).cardinality() # needs sage.combinat sage.groups 0 TESTS:: - sage: w0.binary_factorizations().category() + sage: w0.binary_factorizations().category() # needs sage.combinat sage.groups Category of finite enumerated sets Check that this is independent of the implementation of the group, see :trac:`34799`:: - sage: W1 = WeylGroup(['A',3]) + sage: # needs sage.combinat sage.groups + sage: W1 = WeylGroup(['A', 3]) sage: W2 = Permutations(4) sage: P = lambda pi: W2(list(pi.to_permutation())) - sage: d1 = {P(pi): set((P(w[0]), P(w[1])) for w in pi.binary_factorizations()) for pi in W1} + sage: d1 = {P(pi): set((P(w[0]), P(w[1])) + ....: for w in pi.binary_factorizations()) + ....: for pi in W1} sage: d2 = {pi: set(pi.binary_factorizations()) for pi in W2} sage: d1 == d2 True @@ -2119,7 +2257,6 @@ def binary_factorizations(self, predicate=ConstantFunction(True)): if not predicate(W.one()): from sage.sets.finite_enumerated_set import FiniteEnumeratedSet return FiniteEnumeratedSet([]) - s = W.simple_reflections() def succ(u_v): u, v = u_v @@ -2142,35 +2279,40 @@ def bruhat_lower_covers(self): EXAMPLES:: - sage: W = WeylGroup(["A",3]) - sage: w = W.from_reduced_word([3,2,3]) - sage: print([v.reduced_word() for v in w.bruhat_lower_covers()]) + sage: W = WeylGroup(["A", 3]) # needs sage.combinat sage.groups + sage: w = W.from_reduced_word([3,2,3]) # needs sage.combinat sage.groups + sage: print([v.reduced_word() for v in w.bruhat_lower_covers()]) # needs sage.combinat sage.groups [[3, 2], [2, 3]] - sage: W = WeylGroup(["A",3]) - sage: print([v.reduced_word() for v in W.simple_reflection(1).bruhat_lower_covers()]) + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(["A", 3]) + sage: print([v.reduced_word() + ....: for v in W.simple_reflection(1).bruhat_lower_covers()]) [[]] - sage: print([v.reduced_word() for v in W.one().bruhat_lower_covers()]) + sage: print([v.reduced_word() + ....: for v in W.one().bruhat_lower_covers()]) [] - sage: W = WeylGroup(["B",4,1]) + sage: W = WeylGroup(["B", 4, 1]) sage: w = W.from_reduced_word([0,2]) sage: print([v.reduced_word() for v in w.bruhat_lower_covers()]) [[2], [0]] - sage: W = WeylGroup("A3",prefix="s",implementation="permutation") - sage: [s1,s2,s3]=W.simple_reflections() + sage: W = WeylGroup("A3", prefix="s", implementation="permutation") + sage: s1, s2, s3 = W.simple_reflections() sage: (s1*s2*s3*s1).bruhat_lower_covers() [s2*s1*s3, s1*s2*s1, s1*s2*s3] We now show how to construct the Bruhat poset:: - sage: W = WeylGroup(["A",3]) - sage: covers = tuple([u, v] for v in W for u in v.bruhat_lower_covers() ) - sage: P = Poset((W, covers), cover_relations = True) - sage: P.show() + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(["A", 3]) + sage: covers = tuple([u, v] + ....: for v in W for u in v.bruhat_lower_covers()) + sage: P = Poset((W, covers), cover_relations=True) # needs sage.graphs + sage: P.show() # needs sage.graphs sage.plot Alternatively, one can just use:: - sage: P = W.bruhat_poset() + sage: P = W.bruhat_poset() # needs sage.combinat sage.graphs sage.groups The algorithm is taken from Stembridge's 'coxeter/weyl' package for Maple. """ @@ -2193,17 +2335,18 @@ def bruhat_upper_covers(self): EXAMPLES:: - sage: W = WeylGroup(['A',3,1], prefix="s") - sage: w = W.from_reduced_word([1,2,1]) - sage: w.bruhat_upper_covers() + sage: W = WeylGroup(['A', 3, 1], prefix="s") # needs sage.combinat sage.groups + sage: w = W.from_reduced_word([1,2,1]) # needs sage.combinat sage.groups + sage: w.bruhat_upper_covers() # needs sage.combinat sage.groups [s1*s2*s1*s0, s1*s2*s0*s1, s0*s1*s2*s1, s3*s1*s2*s1, s2*s3*s1*s2, s1*s2*s3*s1] - sage: W = WeylGroup(['A',3]) - sage: w = W.long_element() - sage: w.bruhat_upper_covers() + sage: W = WeylGroup(['A', 3]) # needs sage.combinat sage.groups + sage: w = W.long_element() # needs sage.combinat sage.groups + sage: w.bruhat_upper_covers() # needs sage.combinat sage.groups [] - sage: W = WeylGroup(['A',3]) + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['A', 3]) sage: w = W.from_reduced_word([1,2,1]) sage: S = [v for v in W if w in v.bruhat_lower_covers()] sage: C = w.bruhat_upper_covers() @@ -2231,17 +2374,17 @@ def bruhat_lower_covers_reflections(self): EXAMPLES:: - sage: W = WeylGroup(['A',3], prefix="s") - sage: w = W.from_reduced_word([3,1,2,1]) - sage: w.bruhat_lower_covers_reflections() + sage: W = WeylGroup(['A', 3], prefix="s") # needs sage.combinat sage.groups + sage: w = W.from_reduced_word([3,1,2,1]) # needs sage.combinat sage.groups + sage: w.bruhat_lower_covers_reflections() # needs sage.combinat sage.groups [(s1*s2*s1, s1*s2*s3*s2*s1), (s3*s2*s1, s2), (s3*s1*s2, s1)] TESTS: Check bug discovered in :trac:`32669` is fixed:: - sage: W = CoxeterGroup(['A',3], implementation='permutation') - sage: W.w0.bruhat_lower_covers_reflections() + sage: W = CoxeterGroup(['A', 3], implementation='permutation') # needs sage.combinat sage.groups + sage: W.w0.bruhat_lower_covers_reflections() # needs sage.combinat sage.groups [((1,3,7,9)(2,11,6,10)(4,8,5,12), (2,5)(3,9)(4,6)(8,11)(10,12)), ((1,11)(3,10)(4,9)(5,7)(6,12), (1,4)(2,8)(3,5)(7,10)(9,11)), ((1,9,7,3)(2,10,6,11)(4,12,5,8), (1,7)(2,4)(5,6)(8,10)(11,12))] @@ -2252,7 +2395,7 @@ def bruhat_lower_covers_reflections(self): wi = self.apply_simple_reflection(i, side='right') return [(u.apply_simple_reflection(i, side='right'), r.apply_conjugation_by_simple_reflection(i)) - for u,r in wi.bruhat_lower_covers_reflections() + for u, r in wi.bruhat_lower_covers_reflections() if not u.has_descent(i, side='right')] + [ (wi, self.parent().simple_reflection(i))] @@ -2264,7 +2407,8 @@ def lower_cover_reflections(self, side='right'): EXAMPLES:: - sage: W = WeylGroup(['A',3],prefix="s") + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['A', 3],prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.lower_cover_reflections() [s1*s2*s3*s2*s1, s2, s1] @@ -2287,10 +2431,11 @@ def bruhat_upper_covers_reflections(self): EXAMPLES:: - sage: W = WeylGroup(['A',4], prefix="s") - sage: w = W.from_reduced_word([3,1,2,1]) - sage: w.bruhat_upper_covers_reflections() - [(s1*s2*s3*s2*s1, s3), (s2*s3*s1*s2*s1, s2*s3*s2), (s3*s4*s1*s2*s1, s4), (s4*s3*s1*s2*s1, s1*s2*s3*s4*s3*s2*s1)] + sage: W = WeylGroup(['A', 4], prefix="s") # needs sage.combinat sage.groups + sage: w = W.from_reduced_word([3,1,2,1]) # needs sage.combinat sage.groups + sage: w.bruhat_upper_covers_reflections() # needs sage.combinat sage.groups + [(s1*s2*s3*s2*s1, s3), (s2*s3*s1*s2*s1, s2*s3*s2), + (s3*s4*s1*s2*s1, s4), (s4*s3*s1*s2*s1, s1*s2*s3*s4*s3*s2*s1)] """ Covers = set() for i in self.parent().index_set(): @@ -2310,7 +2455,8 @@ def cover_reflections(self, side='right'): EXAMPLES:: - sage: W = WeylGroup(['A',4], prefix="s") + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['A', 4], prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.cover_reflections() [s3, s2*s3*s2, s4, s1*s2*s3*s4*s3*s2*s1] @@ -2335,7 +2481,8 @@ def bruhat_le(self, other): EXAMPLES:: - sage: W = WeylGroup(["A",3]) + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(["A", 3]) sage: u = W.from_reduced_word([1,2,1]) sage: v = W.from_reduced_word([1,2,3,2,1]) sage: u.bruhat_le(u) @@ -2368,19 +2515,22 @@ def bruhat_le(self, other): We now run consistency tests with permutations and :meth:`bruhat_lower_covers`:: - sage: W = WeylGroup(["A",3]) + sage: W = WeylGroup(["A", 3]) # needs sage.combinat sage.groups sage: P4 = Permutations(4) sage: def P4toW(w): return W.from_reduced_word(w.reduced_word()) - sage: for u in P4: + sage: for u in P4: # needs sage.combinat sage.groups ....: for v in P4: ....: assert u.bruhat_lequal(v) == P4toW(u).bruhat_le(P4toW(v)) - sage: W = WeylGroup(["B",3]) - sage: P = W.bruhat_poset() # This is built from bruhat_lower_covers - sage: Q = Poset((W, attrcall("bruhat_le"))) # long time (10s) - sage: all( u.bruhat_le(v) == P.is_lequal(u,v) for u in W for v in W ) # long time (7s) + sage: # needs sage.combinat sage.graphs sage.groups + sage: W = WeylGroup(["B", 3]) + sage: P = W.bruhat_poset() # This is built from bruhat_lower_covers + sage: Q = Poset((W, attrcall("bruhat_le"))) # long time (10s) + sage: all(u.bruhat_le(v) == P.is_lequal(u,v) # long time (7s) + ....: for u in W for v in W) True - sage: all( P.is_lequal(u,v) == Q.is_lequal(u,v) for u in W for v in W) # long time (9s) + sage: all(P.is_lequal(u,v) == Q.is_lequal(u,v) # long time (9s) + ....: for u in W for v in W) True """ if not have_same_parent(self, other): @@ -2409,7 +2559,8 @@ def weak_le(self, other, side='right'): EXAMPLES:: - sage: W = WeylGroup(["A",3]) + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(["A", 3]) sage: u = W.from_reduced_word([1,2]) sage: v = W.from_reduced_word([1,2,3,2]) sage: u.weak_le(u) @@ -2423,7 +2574,7 @@ def weak_le(self, other, side='right'): Comparison for left weak order is achieved with the option ``side``:: - sage: u.weak_le(v, side='left') + sage: u.weak_le(v, side='left') # needs sage.combinat sage.groups False The implementation uses the equivalent condition that any @@ -2439,10 +2590,10 @@ def weak_le(self, other, side='right'): We now run consistency tests with permutations:: - sage: W = WeylGroup(["A",3]) + sage: W = WeylGroup(["A", 3]) # needs sage.combinat sage.groups sage: P4 = Permutations(4) sage: def P4toW(w): return W.from_reduced_word(w.reduced_word()) - sage: for u in P4: # long time (5s on sage.math, 2011) + sage: for u in P4: # long time (5s on sage.math, 2011), needs sage.combinat sage.groups ....: for v in P4: ....: assert u.permutohedron_lequal(v) == P4toW(u).weak_le(P4toW(v)) ....: assert u.permutohedron_lequal(v, side='left') == P4toW(u).weak_le(P4toW(v), side='left') @@ -2475,18 +2626,19 @@ def weak_covers(self, side='right', index_set=None, positive=False): EXAMPLES:: - sage: W = WeylGroup(['A',3]) - sage: w = W.from_reduced_word([3,2,1]) - sage: [x.reduced_word() for x in w.weak_covers()] + sage: W = WeylGroup(['A', 3]) # needs sage.combinat sage.groups + sage: w = W.from_reduced_word([3,2,1]) # needs sage.combinat sage.groups + sage: [x.reduced_word() for x in w.weak_covers()] # needs sage.combinat sage.groups [[3, 2]] To obtain instead elements that cover self, set ``positive=True``:: - sage: [x.reduced_word() for x in w.weak_covers(positive=True)] + sage: [x.reduced_word() for x in w.weak_covers(positive=True)] # needs sage.combinat sage.groups [[3, 1, 2, 1], [2, 3, 2, 1]] To obtain covers for left weak order, set the option side to 'left':: + sage: # needs sage.combinat sage.groups sage: [x.reduced_word() for x in w.weak_covers(side='left')] [[2, 1]] sage: w = W.from_reduced_word([3,2,3,1]) @@ -2497,7 +2649,7 @@ def weak_covers(self, side='right', index_set=None, positive=False): Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``:: - sage: [x.reduced_word() for x in w.weak_covers(index_set = [1,2])] + sage: [x.reduced_word() for x in w.weak_covers(index_set=[1,2])] # needs sage.combinat sage.groups [[2, 3, 2]] """ return [self.apply_simple_reflection(i, side=side) @@ -2580,16 +2732,20 @@ def is_coxeter_sortable(self, c, sorting_word=None): [2, 0, 1, 2, 0] sage: w.is_coxeter_sortable(c) True - sage: W = CoxeterGroup(['A',3]) - sage: c = W.from_reduced_word([1,2,3]) - sage: len([w for w in W if w.is_coxeter_sortable(c)]) # number of c-sortable elements in A_3 (Catalan number) + + sage: W = CoxeterGroup(['A', 3]) # needs sage.combinat sage.groups + sage: c = W.from_reduced_word([1,2,3]) # needs sage.combinat sage.groups + + Number of `c`-sortable elements in `A_3` (Catalan number):: + + sage: len([w for w in W if w.is_coxeter_sortable(c)]) 14 TESTS:: - sage: W = SymmetricGroup(3) + sage: W = SymmetricGroup(3) # needs sage.groups sage: c = Permutation((1,2,3)) - sage: sorted(w for w in W if w.is_coxeter_sortable(c)) + sage: sorted(w for w in W if w.is_coxeter_sortable(c)) # needs sage.combinat sage.groups [(), (2,3), (1,2), (1,3,2), (1,3)] """ if hasattr(c, "reduced_word"): @@ -2640,13 +2796,14 @@ def apply_demazure_product(self, element, side='right', EXAMPLES:: - sage: W = WeylGroup(['C',4],prefix="s") + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['C', 4], prefix="s") sage: v = W.from_reduced_word([1,2,3,4,3,1]) sage: v.apply_demazure_product([1,3,4,3,3]) s4*s1*s2*s3*s4*s3*s1 - sage: v.apply_demazure_product([1,3,4,3],side='left') + sage: v.apply_demazure_product([1,3,4,3], side='left') s3*s4*s1*s2*s3*s4*s2*s3*s1 - sage: v.apply_demazure_product((1,3,4,3),side='left') + sage: v.apply_demazure_product((1,3,4,3), side='left') s3*s4*s1*s2*s3*s4*s2*s3*s1 sage: v.apply_demazure_product(v) s2*s3*s4*s1*s2*s3*s4*s2*s3*s2*s1 @@ -2683,7 +2840,8 @@ def min_demazure_product_greater(self, element): EXAMPLES:: - sage: W = WeylGroup(['A',4],prefix="s") + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['A', 4], prefix="s") sage: v = W.from_reduced_word([2,3,4,1,2]) sage: u = W.from_reduced_word([2,3,2,1]) sage: v.min_demazure_product_greater(u) @@ -2730,17 +2888,19 @@ def deodhar_factor_element(self, w, index_set): EXAMPLES:: - sage: W = WeylGroup(['A',5],prefix="s") + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['A', 5], prefix="s") sage: v = W.from_reduced_word([5]) sage: w = W.from_reduced_word([4,5,2,3,1,2]) - sage: v.deodhar_factor_element(w,[1,3,4]) + sage: v.deodhar_factor_element(w, [1,3,4]) s3*s1 - sage: W = WeylGroup(['C',2]) + sage: W = WeylGroup(['C', 2]) sage: w = W.from_reduced_word([2,1]) sage: w.deodhar_factor_element(W.from_reduced_word([2]),[1]) Traceback (most recent call last): ... - ValueError: [2, 1] is not of minimum length in its coset for the parabolic subgroup with index set [1] + ValueError: [2, 1] is not of minimum length in its coset + for the parabolic subgroup with index set [1] REFERENCES: @@ -2785,7 +2945,8 @@ def deodhar_lift_up(self, w, index_set): EXAMPLES:: - sage: W = WeylGroup(['A',3],prefix="s") + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['A', 3], prefix="s") sage: v = W.from_reduced_word([1,2,3]) sage: w = W.from_reduced_word([1,3,2]) sage: v.deodhar_lift_up(w, [3]) @@ -2819,7 +2980,8 @@ def deodhar_lift_down(self, w, index_set): EXAMPLES:: - sage: W = WeylGroup(['A',3],prefix="s") + sage: # needs sage.combinat sage.groups + sage: W = WeylGroup(['A', 3], prefix="s") sage: v = W.from_reduced_word([1,2,3,2]) sage: w = W.from_reduced_word([3,2]) sage: v.deodhar_lift_down(w, [3]) @@ -2842,9 +3004,9 @@ def inversions_as_reflections(self): EXAMPLES:: - sage: W = WeylGroup(['A',3], prefix="s") - sage: w = W.from_reduced_word([3,1,2,1]) - sage: w.inversions_as_reflections() + sage: W = WeylGroup(['A', 3], prefix="s") # needs sage.combinat sage.groups + sage: w = W.from_reduced_word([3,1,2,1]) # needs sage.combinat sage.groups + sage: w.inversions_as_reflections() # needs sage.combinat sage.groups [s1, s1*s2*s1, s2, s1*s2*s3*s2*s1] """ i = self.first_descent() @@ -2859,9 +3021,9 @@ def left_inversions_as_reflections(self): EXAMPLES:: - sage: W = WeylGroup(['A',3], prefix="s") - sage: w = W.from_reduced_word([3,1,2,1]) - sage: w.left_inversions_as_reflections() + sage: W = WeylGroup(['A', 3], prefix="s") # needs sage.combinat sage.groups + sage: w = W.from_reduced_word([3,1,2,1]) # needs sage.combinat sage.groups + sage: w.left_inversions_as_reflections() # needs sage.combinat sage.groups [s1, s3, s1*s2*s3*s2*s1, s2*s3*s2] """ return self.inverse().inversions_as_reflections() @@ -2872,31 +3034,31 @@ def lower_covers(self, side='right', index_set=None): INPUT: - - side -- 'left' or 'right' (default: 'right') - - index_set -- a list of indices or ``None`` + - ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``) + - ``index_set`` -- a list of indices or ``None`` OUTPUT: a list EXAMPLES:: - sage: W = WeylGroup(['A',3]) - sage: w = W.from_reduced_word([3,2,1]) - sage: [x.reduced_word() for x in w.lower_covers()] + sage: W = WeylGroup(['A', 3]) # needs sage.combinat sage.groups + sage: w = W.from_reduced_word([3,2,1]) # needs sage.combinat sage.groups + sage: [x.reduced_word() for x in w.lower_covers()] # needs sage.combinat sage.groups [[3, 2]] To obtain covers for left weak order, set the option side to 'left':: - sage: [x.reduced_word() for x in w.lower_covers(side='left')] + sage: [x.reduced_word() for x in w.lower_covers(side='left')] # needs sage.combinat sage.groups [[2, 1]] - sage: w = W.from_reduced_word([3,2,3,1]) - sage: [x.reduced_word() for x in w.lower_covers()] + sage: w = W.from_reduced_word([3,2,3,1]) # needs sage.combinat sage.groups + sage: [x.reduced_word() for x in w.lower_covers()] # needs sage.combinat sage.groups [[2, 3, 2], [3, 2, 1]] Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``:: - sage: [x.reduced_word() for x in w.lower_covers(index_set = [1,2])] + sage: [x.reduced_word() for x in w.lower_covers(index_set=[1,2])] # needs sage.combinat sage.groups [[2, 3, 2]] - sage: [x.reduced_word() for x in w.lower_covers(side='left')] + sage: [x.reduced_word() for x in w.lower_covers(side='left')] # needs sage.combinat sage.groups [[3, 2, 1], [2, 3, 1]] """ return self.weak_covers(side=side, index_set=index_set, @@ -2908,28 +3070,29 @@ def upper_covers(self, side='right', index_set=None): INPUT: - - side -- 'left' or 'right' (default: 'right') - - index_set -- a list of indices or None + - ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``) + - ``index_set`` -- a list of indices or ``None`` OUTPUT: a list EXAMPLES:: - sage: W = WeylGroup(['A',3]) - sage: w = W.from_reduced_word([2,3]) - sage: [x.reduced_word() for x in w.upper_covers()] + sage: W = WeylGroup(['A', 3]) # needs sage.combinat sage.groups + sage: w = W.from_reduced_word([2,3]) # needs sage.combinat sage.groups + sage: [x.reduced_word() for x in w.upper_covers()] # needs sage.combinat sage.groups [[2, 3, 1], [2, 3, 2]] To obtain covers for left weak order, set the option ``side`` to 'left':: - sage: [x.reduced_word() for x in w.upper_covers(side='left')] + sage: [x.reduced_word() for x in w.upper_covers(side='left')] # needs sage.combinat sage.groups [[1, 2, 3], [2, 3, 2]] Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``:: - sage: [x.reduced_word() for x in w.upper_covers(index_set = [1])] + sage: [x.reduced_word() for x in w.upper_covers(index_set=[1])] # needs sage.combinat sage.groups [[2, 3, 1]] - sage: [x.reduced_word() for x in w.upper_covers(side='left', index_set = [1])] + sage: [x.reduced_word() # needs sage.combinat sage.groups + ....: for x in w.upper_covers(side='left', index_set=[1])] [[1, 2, 3]] """ return self.weak_covers(side=side, index_set=index_set, @@ -2972,41 +3135,44 @@ def kazhdan_lusztig_cell(self, side='left'): choice of implementation affects the representation of elements in the output cell but not the method used for the cell computation:: - sage: W = CoxeterGroup('A3', implementation='permutation') - sage: s1,s2,s3 = W.simple_reflections() - sage: s1.kazhdan_lusztig_cell() + sage: W = CoxeterGroup('A3', implementation='permutation') # needs sage.combinat sage.groups + sage: s1, s2, s3 = W.simple_reflections() # needs sage.combinat sage.groups + sage: s1.kazhdan_lusztig_cell() # needs sage.combinat sage.groups {(1,2,3,12)(4,5,10,11)(6,7,8,9), (1,2,10)(3,6,5)(4,7,8)(9,12,11), (1,7)(2,4)(5,6)(8,10)(11,12)} The cell computation uses the optional package ``coxeter3`` in the background if available to speed up the computation, - even in the different implementations implementations:: + even in the different implementations:: - sage: W = WeylGroup('A3', prefix='s') # optional - coxeter3 - sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 - sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 + sage: # optional - coxeter3, needs sage.combinat sage.groups sage.modules + sage: W = WeylGroup('A3', prefix='s') + sage: s1,s2,s3 = W.simple_reflections() + sage: s1.kazhdan_lusztig_cell() {s3*s2*s1, s2*s1, s1} - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 - sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: s1,s2,s3 = W.simple_reflections() + sage: s1.kazhdan_lusztig_cell() {[1], [2, 1], [3, 2, 1]} Next, we compute a right cell and a two-sided cell in `A_3`:: - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 - sage: w = s1 * s3 # optional - coxeter3 - sage: w.kazhdan_lusztig_cell(side='right') # optional - coxeter3 + sage: # optional - coxeter3, needs sage.combinat sage.groups sage.modules + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: s1,s2,s3 = W.simple_reflections() + sage: w = s1 * s3 + sage: w.kazhdan_lusztig_cell(side='right') {[1, 3], [1, 3, 2]} - sage: w.kazhdan_lusztig_cell(side='two-sided') # optional - coxeter3 + sage: w.kazhdan_lusztig_cell(side='two-sided') {[1, 3], [1, 3, 2], [2, 1, 3], [2, 1, 3, 2]} Some slightly longer computations in `B_4`:: - sage: W = CoxeterGroup('B4', implementation='coxeter3') # optional - coxeter3 - sage: s1,s2,s3,s4 = W.simple_reflections() # optional - coxeter3 - sage: s1.kazhdan_lusztig_cell(side='right') # long time (4 seconds) # optional - coxeter3 + sage: # optional - coxeter3, needs sage.combinat sage.groups sage.modules + sage: W = CoxeterGroup('B4', implementation='coxeter3') + sage: s1,s2,s3,s4 = W.simple_reflections() + sage: s1.kazhdan_lusztig_cell(side='right') # long time (4 seconds) {[1], [1, 2], [1, 2, 3], @@ -3014,7 +3180,7 @@ def kazhdan_lusztig_cell(self, side='left'): [1, 2, 3, 4, 3], [1, 2, 3, 4, 3, 2], [1, 2, 3, 4, 3, 2, 1]} - sage: (s4*s2*s3*s4).kazhdan_lusztig_cell(side='two-sided') # long time (8 seconds) # optional - coxeter3 + sage: (s4*s2*s3*s4).kazhdan_lusztig_cell(side='two-sided') # long time (8 seconds) {[2, 3, 1], [2, 3, 1, 2], [2, 3, 4, 1], diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index 980bebc9f84..74a8319da29 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs sage.combinat r""" Crystals @@ -388,7 +389,6 @@ def __iter__(self, index_set=None, max_depth=float('inf')): R = RecursivelyEnumeratedSet(self.module_generators, succ, structure=None) return R.breadth_first_search_iterator(max_depth) - def subcrystal(self, index_set=None, generators=None, max_depth=float("inf"), direction="both", contained=None, virtualization=None, scaling_factors=None, @@ -908,7 +908,7 @@ def digraph(self, subset=None, index_set=None): child = x.f(i) if child is None or child not in subset: continue - d[x][child]=i + d[x][child] = i G = DiGraph(d) from sage.graphs.dot2tex_utils import have_dot2tex if have_dot2tex(): @@ -919,7 +919,7 @@ def digraph(self, subset=None, index_set=None): def latex_file(self, filename): r""" - Export a file, suitable for pdflatex, to 'filename'. + Export a file, suitable for pdflatex, to ``filename``. This requires a proper installation of ``dot2tex`` in sage-python. For more @@ -954,7 +954,7 @@ def latex_file(self, filename): def _latex_(self, **options): r""" Returns the crystal graph as a latex string. This can be exported - to a file with self.latex_file('filename'). + to a file with ``self.latex_file('filename')``. EXAMPLES:: @@ -977,15 +977,9 @@ def _latex_(self, **options): def metapost(self, filename, thicklines=False, labels=True, scaling_factor=1.0, tallness=1.0): r""" - Use C.metapost("filename.mp",[options]), where options can be: - - thicklines = True (for thicker edges) labels = False (to suppress - labeling of the vertices) scaling_factor=value, where value is a - floating point number, 1.0 by default. Increasing or decreasing the - scaling factor changes the size of the image. tallness=1.0. - Increasing makes the image taller without increasing the width. + Export a file, suitable for MetaPost, to ``filename``. - Root operators e(1) or f(1) move along red lines, e(2) or f(2) + Root operators `e(1)` or `f(1)` move along red lines, `e(2)` or `f(2)` along green. The highest weight is in the lower left. Vertices with the same weight are kept close together. The concise labels on the nodes are strings introduced by Berenstein and Zelevinsky and @@ -994,20 +988,34 @@ def metapost(self, filename, thicklines=False, labels=True, scaling_factor=1.0, For Cartan types B2 or C2, the pattern has the form - a2 a3 a4 a1 + `a_2 a_3 a_4 a_1` - where c\*a2 = a3 = 2\*a4 =0 and a1=0, with c=2 for B2, c=1 for C2. - Applying e(2) a1 times, e(1) a2 times, e(2) a3 times, e(1) a4 times + where `c*a_2 = a_3 = 2*a_4 = 0` and `a_1=0`, with `c=2` for B2, `c=1` for C2. + Applying `e(2)` `a_1` times, `e(1)` `a_2` times, `e(2)` `a_3` times, `e(1)` `a_4` times returns to the highest weight. (Observe that Littelmann writes the - roots in opposite of the usual order, so our e(1) is his e(2) for + roots in opposite of the usual order, so our `e(1)` is his `e(2)` for these Cartan types.) For type A2, the pattern has the form - a3 a2 a1 + `a_3 a_2 a_1` - where applying e(1) a1 times, e(2) a2 times then e(3) a1 times + where applying `e(1)` `a_3` times, `e(2)` `a_2` times then `e(1)` `a_1` times returns to the highest weight. These data determine the vertex and may be translated into a Gelfand-Tsetlin pattern or tableau. + INPUT: + + - ``filename`` -- name of the output file, e.g., ``'filename.mp'`` + + - ``thicklines`` -- (default: ``True``) for thicker edges + + - ``labels`` -- (default: False) to suppress labeling of the vertices + + - ``scaling_factor`` -- (default: ``1.0``) Increasing or decreasing the + scaling factor changes the size of the image + + - ``tallness`` -- (default: ``1.0``) Increasing makes the image taller + without increasing the width + EXAMPLES:: sage: C = crystals.Letters(['A', 2]) @@ -1057,12 +1065,12 @@ def metapost(self, filename, thicklines=False, labels=True, scaling_factor=1.0, c2 = int(35*tallness*scaling_factor) c3 = int(12*scaling_factor) c4 = int(-12*scaling_factor) - outstring = "verbatimtex\n\\magnification=600\netex\n\nbeginfig(-1);\nsx:=35; sy:=30;\n\nz1000=(%d,0);\nz1001=(%d,%d);\nz1002=(%d,%d);\nz2001=(-3,3);\nz2002=(3,3);\nz2003=(0,-3);\nz2004=(7,0);\nz2005=(0,7);\nz2006=(-7,0);\nz2007=(0,7);\n\n"%(c0,c1,c2,c3,c4) + outstring = "verbatimtex\n\\magnification=600\netex\n\nbeginfig(-1);\nsx:=35; sy:=30;\n\nz1000=(%d,0);\nz1001=(%d,%d);\nz1002=(%d,%d);\nz2001=(-3,3);\nz2002=(3,3);\nz2003=(0,-3);\nz2004=(7,0);\nz2005=(0,7);\nz2006=(-7,0);\nz2007=(0,7);\n\n" % (c0,c1,c2,c3,c4) else: if labels: - outstring = "verbatimtex\n\\magnification=600\netex\n\nbeginfig(-1);\n\nsx := %d;\nsy=%d;\n\nz1000=(2*sx,0);\nz1001=(-sx,sy);\nz1002=(-16,-10);\n\nz2001=(0,-3);\nz2002=(-5,3);\nz2003=(0,3);\nz2004=(5,3);\nz2005=(10,1);\nz2006=(0,10);\nz2007=(-10,1);\nz2008=(0,-8);\n\n"%(int(scaling_factor*40),int(tallness*scaling_factor*40)) + outstring = "verbatimtex\n\\magnification=600\netex\n\nbeginfig(-1);\n\nsx := %d;\nsy=%d;\n\nz1000=(2*sx,0);\nz1001=(-sx,sy);\nz1002=(-16,-10);\n\nz2001=(0,-3);\nz2002=(-5,3);\nz2003=(0,3);\nz2004=(5,3);\nz2005=(10,1);\nz2006=(0,10);\nz2007=(-10,1);\nz2008=(0,-8);\n\n" % (int(scaling_factor*40),int(tallness*scaling_factor*40)) else: - outstring = "beginfig(-1);\n\nsx := %d;\nsy := %d;\n\nz1000=(2*sx,0);\nz1001=(-sx,sy);\nz1002=(-5,-5);\n\nz1003=(10,10);\n\n"%(int(scaling_factor*35),int(tallness*scaling_factor*35)) + outstring = "beginfig(-1);\n\nsx := %d;\nsy := %d;\n\nz1000=(2*sx,0);\nz1001=(-sx,sy);\nz1002=(-5,-5);\n\nz1003=(10,10);\n\n" % (int(scaling_factor*35),int(tallness*scaling_factor*35)) for i in range(size): if self.cartan_type()[0] == 'A': [a1,a2,a3] = string_data[i] @@ -1079,12 +1087,12 @@ def metapost(self, filename, thicklines=False, labels=True, scaling_factor=1.0, if b1+b3 == a1+a3 and b2+b4 == a2+a4: shift += 1 if self.cartan_type()[0] == 'A': - outstring = outstring +"z%d=%d*z1000+%d*z1001+%d*z1002;\n"%(i,a1+a3,a2,shift) + outstring = outstring + "z%d=%d*z1000+%d*z1001+%d*z1002;\n" % (i,a1+a3,a2,shift) else: - outstring = outstring +"z%d=%d*z1000+%d*z1001+%d*z1002;\n"%(i,a1+a3,a2+a4,shift) + outstring = outstring + "z%d=%d*z1000+%d*z1001+%d*z1002;\n" % (i,a1+a3,a2+a4,shift) outstring = outstring + "\n" if thicklines: - outstring = outstring +"pickup pencircle scaled 2\n\n" + outstring = outstring + "pickup pencircle scaled 2\n\n" for i in range(size): for j in range(1,3): dest = self.list()[i].f(j) @@ -1096,19 +1104,19 @@ def metapost(self, filename, thicklines=False, labels=True, scaling_factor=1.0, col = "green; " if self.cartan_type()[0] == 'A': [a1,a2,a3] = string_data[i] # included to facilitate hand editing of the .mp file - outstring = outstring+"draw z%d--z%d withcolor %s %% %d %d %d\n"%(i,dest,col,a1,a2,a3) + outstring = outstring+"draw z%d--z%d withcolor %s %% %d %d %d\n" % (i,dest,col,a1,a2,a3) else: [a1,a2,a3,a4] = string_data[i] - outstring = outstring+"draw z%d--z%d withcolor %s %% %d %d %d %d\n"%(i,dest,col,a1,a2,a3,a4) + outstring = outstring+"draw z%d--z%d withcolor %s %% %d %d %d %d\n" % (i,dest,col,a1,a2,a3,a4) outstring += "\npickup pencircle scaled 3;\n\n" for i in range(self.cardinality()): if labels: if self.cartan_type()[0] == 'A': - outstring = outstring+"pickup pencircle scaled 15;\nfill z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\npickup pencircle scaled .5;\ndraw z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle;\n"%(i,i,i,i,string_data[i][2],i,string_data[i][1],i,string_data[i][0],i,i,i,i,i) + outstring = outstring+"pickup pencircle scaled 15;\nfill z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\npickup pencircle scaled .5;\ndraw z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle;\n" % (i,i,i,i,string_data[i][2],i,string_data[i][1],i,string_data[i][0],i,i,i,i,i) else: - outstring = outstring+"%%%d %d %d %d\npickup pencircle scaled 1;\nfill z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\nlabel(btex %d etex, z%d+z2004);\npickup pencircle scaled .5;\ndraw z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle;\n\n"%(string_data[i][0],string_data[i][1],string_data[i][2],string_data[i][3],i,i,i,i,string_data[i][0],i,string_data[i][1],i,string_data[i][2],i,string_data[i][3],i,i,i,i,i) + outstring = outstring+"%%%d %d %d %d\npickup pencircle scaled 1;\nfill z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\nlabel(btex %d etex, z%d+z2004);\npickup pencircle scaled .5;\ndraw z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle;\n\n" % (string_data[i][0],string_data[i][1],string_data[i][2],string_data[i][3],i,i,i,i,string_data[i][0],i,string_data[i][1],i,string_data[i][2],i,string_data[i][3],i,i,i,i,i) else: - outstring += "drawdot z%d;\n"%i + outstring += "drawdot z%d;\n" % i outstring += "\nendfig;\n\nend;\n\n" f = open(filename, 'w') @@ -1153,8 +1161,8 @@ def dot_tex(self): else: option = "" (source, target) = (x, child) - result += " " + vertex_key(source) + " -> "+vertex_key(target)+ " [ "+option+"label = \" \", texlbl = \""+quoted_latex(i)+"\" ];\n" - result+="}" + result += " " + vertex_key(source) + " -> "+vertex_key(target) + " [ "+option+"label = \" \", texlbl = \""+quoted_latex(i)+"\" ];\n" + result += "}" return result def plot(self, **options): @@ -1450,7 +1458,7 @@ def Phi(self): def f_string(self, list): r""" - Applies `f_{i_r} \cdots f_{i_1}` to self for ``list`` as + Applies `f_{i_r} \cdots f_{i_1}` to ``self`` for ``list`` as `[i_1, ..., i_r]` EXAMPLES:: @@ -1470,7 +1478,7 @@ def f_string(self, list): def e_string(self, list): r""" - Applies `e_{i_r} \cdots e_{i_1}` to self for ``list`` as + Applies `e_{i_r} \cdots e_{i_1}` to ``self`` for ``list`` as `[i_1, ..., i_r]` EXAMPLES:: @@ -1562,11 +1570,11 @@ def is_lowest_weight(self, index_set=None): def to_highest_weight(self, index_set=None): r""" Return the highest weight element `u` and a list `[i_1,...,i_k]` - such that `self = f_{i_1} ... f_{i_k} u`, where `i_1,...,i_k` are + such that ``self`` `= f_{i_1} ... f_{i_k} u`, where `i_1,...,i_k` are elements in ``index_set``. - By default the index set is assumed to be - the full index set of self. + By default the ``index_set`` is assumed to be + the full index set of ``self``. EXAMPLES:: @@ -1603,11 +1611,11 @@ def to_highest_weight(self, index_set=None): def to_lowest_weight(self, index_set=None): r""" Return the lowest weight element `u` and a list `[i_1,...,i_k]` - such that `self = e_{i_1} ... e_{i_k} u`, where `i_1,...,i_k` are + such that ``self`` `= e_{i_1} ... e_{i_k} u`, where `i_1,...,i_k` are elements in ``index_set``. - By default the index set is assumed to be the full index - set of self. + By default the ``index_set`` is assumed to be the full index + set of ``self``. EXAMPLES:: diff --git a/src/sage/categories/discrete_valuation.py b/src/sage/categories/discrete_valuation.py index 5b68f8b6c12..4bb61a5aa67 100644 --- a/src/sage/categories/discrete_valuation.py +++ b/src/sage/categories/discrete_valuation.py @@ -41,7 +41,7 @@ def uniformizer(self): EXAMPLES:: - sage: Zp(5).uniformizer() + sage: Zp(5).uniformizer() # needs sage.rings.padics 5 + O(5^21) sage: K.<u> = QQ[[]] @@ -56,7 +56,7 @@ def residue_field(self): EXAMPLES:: - sage: Zp(5).residue_field() + sage: Zp(5).residue_field() # needs sage.rings.padics Finite Field of size 5 sage: K.<u> = QQ[[]] @@ -70,9 +70,10 @@ def _matrix_charpoly(self, M, var): EXAMPLES:: + sage: # needs sage.modules sage: R.<t> = PowerSeriesRing(GF(5)) - sage: M = matrix(4, 4, [ (t^(i+j)).add_bigoh(10) - ....: for i in range(4) for j in range(4) ]) + sage: M = matrix(4, 4, [(t^(i+j)).add_bigoh(10) + ....: for i in range(4) for j in range(4)]) sage: M [ 1 + O(t^10) t + O(t^10) t^2 + O(t^10) t^3 + O(t^10)] [ t + O(t^10) t^2 + O(t^10) t^3 + O(t^10) t^4 + O(t^10)] @@ -85,6 +86,7 @@ def _matrix_charpoly(self, M, var): that performs divisions. Hence, truncations may show up even if the input matrix is exact:: + sage: # needs sage.modules sage: M = matrix(3, 3, [ 1, t, t^2, 1+t, t^2, t^3, t^2, t^3, t^4 ]) sage: M [ 1 t t^2] @@ -95,6 +97,7 @@ def _matrix_charpoly(self, M, var): Another example over the p-adics:: + sage: # needs sage.modules sage.rings.padics sage: R = Zp(5, print_mode="digits", prec=5) sage: M = matrix(R, 3, 3, range(9)) sage: M @@ -114,6 +117,7 @@ def valuation(self): EXAMPLES:: + sage: # needs sage.rings.padics sage: x = Zp(5)(50) sage: x.valuation() 2 @@ -166,14 +170,16 @@ def quo_rem(self, other): def is_unit(self): """ - Return True if self is invertible. + Return ``True`` if ``self`` is invertible. EXAMPLES:: + sage: # needs sage.rings.padics sage: x = Zp(5)(50) sage: x.is_unit() False + sage: # needs sage.rings.padics sage: x = Zp(7)(50) sage: x.is_unit() True @@ -213,7 +219,7 @@ class DiscreteValuationFields(Category_singleton): EXAMPLES:: - sage: Qp(7) in DiscreteValuationFields() + sage: Qp(7) in DiscreteValuationFields() # needs sage.rings.padics True sage: TestSuite(DiscreteValuationFields()).run() """ @@ -235,7 +241,7 @@ def uniformizer(self): EXAMPLES:: - sage: Qp(5).uniformizer() + sage: Qp(5).uniformizer() # needs sage.rings.padics 5 + O(5^21) """ @@ -247,7 +253,7 @@ def residue_field(self): EXAMPLES:: - sage: Qp(5).residue_field() + sage: Qp(5).residue_field() # needs sage.rings.padics Finite Field of size 5 sage: K.<u> = LaurentSeriesRing(QQ) @@ -261,10 +267,11 @@ def _matrix_hessenbergize(self, H): EXAMPLES:: + sage: # needs sage.modules sage: R.<t> = PowerSeriesRing(GF(5)) sage: K = R.fraction_field() - sage: H = matrix(K, 4, 4, [ (t^(i+j)).add_bigoh(10) - ....: for i in range(4) for j in range(4) ]) + sage: H = matrix(K, 4, 4, [(t^(i+j)).add_bigoh(10) + ....: for i in range(4) for j in range(4)]) sage: H [ 1 + O(t^10) t + O(t^10) t^2 + O(t^10) t^3 + O(t^10)] [ t + O(t^10) t^2 + O(t^10) t^3 + O(t^10) t^4 + O(t^10)] @@ -279,14 +286,13 @@ def _matrix_hessenbergize(self, H): Another example over the p-adics:: + sage: # needs sage.modules sage.rings.padics sage: K = Qp(5, print_mode="digits", prec=5) - sage: H = matrix(K, 3, 3, range(9)) - sage: H + sage: H = matrix(K, 3, 3, range(9)); H [ 0 ...00001 ...00002] [ ...00003 ...00004 ...000010] [ ...00011 ...00012 ...00013] - sage: H.hessenbergize() - sage: H + sage: H.hessenbergize(); H [ 0 ...00010 ...00002] [ ...00003 ...00024 ...000010] [ ...00000 ...44440 ...44443] @@ -302,6 +308,7 @@ def valuation(self): EXAMPLES:: + sage: # needs sage.rings.padics sage: x = Qp(5)(50) sage: x.valuation() 2 diff --git a/src/sage/categories/distributive_magmas_and_additive_magmas.py b/src/sage/categories/distributive_magmas_and_additive_magmas.py index 233f0ce12ac..6d1c7511c11 100644 --- a/src/sage/categories/distributive_magmas_and_additive_magmas.py +++ b/src/sage/categories/distributive_magmas_and_additive_magmas.py @@ -43,7 +43,7 @@ class AdditiveCommutative(CategoryWithAxiom): class AdditiveUnital(CategoryWithAxiom): class Associative(CategoryWithAxiom): AdditiveInverse = LazyImport('sage.categories.rngs', 'Rngs', at_startup=True) - Unital = LazyImport('sage.categories.semirings', 'Semirings', at_startup=True) + Unital = LazyImport('sage.categories.semirings', 'Semirings', at_startup=True) class ParentMethods: @@ -68,7 +68,7 @@ def _test_distributivity(self, **options): However, the elements tested can be customized with the ``elements`` keyword argument:: - sage: CC._test_distributivity(elements=[CC(0),CC(1),CC(3),CC(I)]) + sage: CC._test_distributivity(elements=[CC(0),CC(1),CC(3),CC(I)]) # needs sage.symbolic See the documentation for :class:`TestSuite` for more information. """ diff --git a/src/sage/categories/domains.py b/src/sage/categories/domains.py index 2cdbb4cd2ce..18e2907b8ef 100644 --- a/src/sage/categories/domains.py +++ b/src/sage/categories/domains.py @@ -57,23 +57,24 @@ def _test_zero_divisors(self, **options): In rings whose elements can not be represented exactly, there may be zero divisors in practice, even though these rings do not have them in theory. For such inexact rings, these tests - are not performed: - - sage: R = ZpFM(5); R - 5-adic Ring of fixed modulus 5^20 - sage: R.is_exact() - False - sage: a = R(5^19) - sage: a.is_zero() - False - sage: (a*a).is_zero() - True - sage: R._test_zero_divisors() + are not performed:: + + sage: # needs sage.rings.padics + sage: R = ZpFM(5); R + 5-adic Ring of fixed modulus 5^20 + sage: R.is_exact() + False + sage: a = R(5^19) + sage: a.is_zero() + False + sage: (a * a).is_zero() + True + sage: R._test_zero_divisors() EXAMPLES:: sage: ZZ._test_zero_divisors() - sage: ZpFM(5)._test_zero_divisors() + sage: ZpFM(5)._test_zero_divisors() # needs sage.rings.padics """ if not self.is_exact(): diff --git a/src/sage/categories/drinfeld_modules.py b/src/sage/categories/drinfeld_modules.py new file mode 100644 index 00000000000..380318c37ff --- /dev/null +++ b/src/sage/categories/drinfeld_modules.py @@ -0,0 +1,790 @@ +# sage.doctest: needs sage.rings.finite_rings +r""" +Drinfeld modules over a base + +This module provides the class +:class:`sage.category.drinfeld_modules.DrinfeldModules`. + +AUTHORS: + +- Antoine Leudiรจre (2022-04) +- Xavier Caruso (2022-06) +""" + +# ***************************************************************************** +# Copyright (C) 2022 Xavier Caruso <xavier.caruso@normalesup.org> +# Antoine Leudiรจre <antoine.leudiere@inria.fr> +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +# ****************************************************************************** + +from sage.categories.objects import Objects +from sage.categories.category_types import Category_over_base_ring +from sage.categories.homsets import Homsets +from sage.misc.functional import log +from sage.misc.latex import latex +from sage.misc.lazy_import import lazy_import +from sage.rings.integer import Integer + +lazy_import('sage.rings.polynomial.ore_polynomial_ring', 'OrePolynomialRing') +lazy_import('sage.rings.polynomial.polynomial_ring', 'PolynomialRing_general') +lazy_import('sage.rings.ring_extension', 'RingExtension_generic') + + +class DrinfeldModules(Category_over_base_ring): + r""" + This class implements the category of Drinfeld + `\mathbb{F}_q[T]`-modules on a given base field. + + Let `\mathbb{F}_q[T]` be a polynomial ring with coefficients in a + finite field `\mathbb{F}_q` and let `K` be a field. Fix a ring + morphism `\gamma: \mathbb{F}_q[T] \to K`; we say that `K` is an + `\mathbb{F}_q[T]`*-field*. Let `K\{\tau\}` be the ring of Ore + polynomials with coefficients in `K`, whose multiplication is given + by the rule `\tau \lambda = \lambda^q \tau` for any `\lambda \in K`. + + The extension `K`/`\mathbb{F}_q[T]` (represented as an instance of + the class :class:`sage.rings.ring_extension.RingExtension`) is the + *base field* of the category; its defining morphism `\gamma` is + called the *base morphism*. + + The monic polynomial that generates the kernel of `\gamma` is called + the `\mathbb{F}_q[T]`-*characteristic*, or *function-field + characteristic*, of the base field. We say that `\mathbb{F}_q[T]` is + the *function ring* of the category; `K\{\tau\}` is the *Ore + polynomial ring*. The constant coefficient of the category is the + image of `T` under the base morphism. + + .. RUBRIC:: Construction + + Generally, Drinfeld modules objects are created before their + category, and the category is retrieved as an attribute of the + Drinfeld module:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + sage: C + Category of Drinfeld modules over Finite Field in z of size 11^4 over its base + + The output tells the user that the category is only defined by its + base. + + .. RUBRIC:: Properties of the category + + The base field is retrieved using the method :meth:`base`. + + sage: C.base() + Finite Field in z of size 11^4 over its base + + Equivalently, one can use :meth:`base_morphism` to retrieve the base + morphism:: + + sage: C.base_morphism() + Ring morphism: + From: Univariate Polynomial Ring in T over Finite Field of size 11 + To: Finite Field in z of size 11^4 over its base + Defn: T |--> z^3 + 7*z^2 + 6*z + 10 + + The so-called constant coefficient --- which is the same for all + Drinfeld modules in the category --- is simply the image of `T` by + the base morphism:: + + sage: C.constant_coefficient() + z^3 + 7*z^2 + 6*z + 10 + sage: C.base_morphism()(T) == C.constant_coefficient() + True + + Similarly, the function ring-characteristic of the category is + either `0` or the unique monic polynomial in `\mathbb{F}_q[T]` that + generates the kernel of the base:: + + sage: C.characteristic() + T^2 + 7*T + 2 + sage: C.base_morphism()(C.characteristic()) + 0 + + The base field, base morphism, function ring and Ore polynomial ring + are the same for the category and its objects:: + + sage: C.base() is phi.base() + True + sage: C.base_morphism() is phi.base_morphism() + True + + sage: C.function_ring() + Univariate Polynomial Ring in T over Finite Field of size 11 + sage: C.function_ring() is phi.function_ring() + True + + sage: C.ore_polring() + Ore Polynomial Ring in t over Finite Field in z of size 11^4 over its base twisted by Frob + sage: C.ore_polring() is phi.ore_polring() + True + + + .. RUBRIC:: Creating Drinfeld module objects from the category + + Calling :meth:`object` with an Ore polynomial creates a Drinfeld module + object in the category whose generator is the input:: + + sage: psi = C.object([p_root, 1]) + sage: psi + Drinfeld module defined by T |--> t + z^3 + 7*z^2 + 6*z + 10 + sage: psi.category() is C + True + + Of course, the constant coefficient of the input must be the same as + the category:: + + sage: C.object([z, 1]) + Traceback (most recent call last): + ... + ValueError: constant coefficient must equal that of the category + + It is also possible to create a random object in the category. The + input is the desired rank:: + + sage: rho = C.random_object(2) + sage: rho # random + Drinfeld module defined by T |--> (7*z^3 + 7*z^2 + 10*z + 2)*t^2 + (9*z^3 + 5*z^2 + 2*z + 7)*t + z^3 + 7*z^2 + 6*z + 10 + sage: rho.rank() == 2 + True + sage: rho.category() is C + True + + TESTS:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: from sage.categories.drinfeld_modules import DrinfeldModules + sage: base = Hom(A, K)(0) + sage: C = DrinfeldModules(base) + Traceback (most recent call last): + ... + TypeError: base field must be a ring extension + + :: + + sage: C.base().defining_morphism() == C.base_morphism() + True + + :: + + sage: base = Hom(A, A)(1) + sage: C = DrinfeldModules(base) + Traceback (most recent call last): + ... + TypeError: base field must be a ring extension + + :: + + sage: base = 'I hate Rostropovitch' + sage: C = DrinfeldModules(base) # known bug (blankline) + <BLANKLINE> + Traceback (most recent call last): + ... + TypeError: input must be a ring morphism + + :: + + sage: ZZT.<T> = ZZ[] + sage: base = Hom(ZZT, K)(1) + sage: C = DrinfeldModules(base) # known bug (blankline) + <BLANKLINE> + Traceback (most recent call last): + ... + TypeError: function ring base must be a finite field + """ + + def __init__(self, base_field, name='t'): + r""" + Initialize `self`. + + INPUT: + + - ``base_field`` -- the base field, which is a ring extension + over a base + + - ``name`` (default: ``'t'``) -- the name of the Ore polynomial + variable + + TESTS:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + sage: ore_polring.<t> = OrePolynomialRing(phi.base(), phi.base().frobenius_endomorphism()) + sage: C._ore_polring is ore_polring + True + sage: i = phi.base().coerce_map_from(K) + sage: base_morphism = Hom(A, K)(p_root) + sage: C.base() == K.over(base_morphism) + True + sage: C._base_morphism == i * base_morphism + True + sage: C._function_ring is A + True + sage: C._constant_coefficient == base_morphism(T) + True + sage: C._characteristic(C._constant_coefficient) + 0 + """ + # Check input is a ring extension + if not isinstance(base_field, RingExtension_generic): + raise TypeError('base field must be a ring extension') + base_morphism = base_field.defining_morphism() + self._base_morphism = base_morphism + # Check input is a field + if not base_field.is_field(): + raise TypeError('input must be a field') + self._base_field = base_field + self._function_ring = base_morphism.domain() + # Check domain of base morphism is Fq[T] + function_ring = self._function_ring + if not isinstance(function_ring, PolynomialRing_general): + raise NotImplementedError('function ring must be a polynomial ' + 'ring') + function_ring_base = function_ring.base_ring() + if not function_ring_base.is_field() \ + or not function_ring_base.is_finite(): + raise TypeError('function ring base must be a finite field') + # Shortcuts + Fq = function_ring_base + A = function_ring + T = A.gen() + K = base_field # A ring extension + # Build K{t} + d = log(Fq.cardinality(), Fq.characteristic()) + tau = K.frobenius_endomorphism(d) + self._ore_polring = OrePolynomialRing(K, tau, names=name, + polcast=False) + # Create constant coefficient + self._constant_coefficient = base_morphism(T) + # Create characteristic + self._characteristic = None + if K.is_finite(): + self._characteristic = A(K.over(Fq)(base_morphism(T)).minpoly()) + else: + try: + if base_morphism.is_injective(): + self._characteristic = Integer(0) + except NotImplementedError: + pass + # Create base over constants field + i = A.coerce_map_from(Fq) + Fq_to_K = self._base_morphism * i + self._base_over_constants_field = base_field.over(Fq_to_K) + super().__init__(base=base_field) + + def _latex_(self): + r""" + Return a latex representation of the category. + + OUTPUT: a string + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + sage: latex(C) + \text{Category{ }of{ }Drinfeld{ }modules{ }over{ }\Bold{F}_{11^{4}} + """ + return f'\\text{{Category{{ }}of{{ }}Drinfeld{{ }}modules{{ }}' \ + f'over{{ }}{latex(self._base_field)}' + + def _repr_(self): + r""" + Return a string representation of the category. + + OUTPUT: a string + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + sage: C + Category of Drinfeld modules over Finite Field in z of size 11^4 over its base + """ + return f'Category of Drinfeld modules over {self._base_field}' + + def Homsets(self): + r""" + Return the category of homsets. + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + + sage: from sage.categories.homsets import Homsets + sage: C.Homsets() is Homsets() + True + """ + return Homsets() + + def Endsets(self): + r""" + Return the category of endsets. + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + + sage: from sage.categories.homsets import Homsets + sage: C.Endsets() is Homsets().Endsets() + True + """ + return Homsets().Endsets() + + def base_morphism(self): + r""" + Return the base morphism of the category. + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + sage: C.base_morphism() + Ring morphism: + From: Univariate Polynomial Ring in T over Finite Field of size 11 + To: Finite Field in z of size 11^4 over its base + Defn: T |--> z^3 + 7*z^2 + 6*z + 10 + + sage: C.constant_coefficient() == C.base_morphism()(T) + True + """ + return self._base_morphism + + def base_over_constants_field(self): + r""" + Return the base field, seen as an extension over the constants + field `\mathbb{F}_q`. + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + sage: C.base_over_constants_field() + Field in z with defining polynomial x^4 + 8*x^2 + 10*x + 2 over its base + """ + return self._base_over_constants_field + + def characteristic(self): + r""" + Return the function ring-characteristic. + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + sage: C.characteristic() + T^2 + 7*T + 2 + + :: + + sage: psi = DrinfeldModule(A, [Frac(A).gen(), 1]) + sage: C = psi.category() + sage: C.characteristic() + 0 + """ + if self._characteristic is None: + raise NotImplementedError('function ring characteristic not ' + 'implemented in this case') + return self._characteristic + + def constant_coefficient(self): + r""" + Return the constant coefficient of the category. + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + sage: C.constant_coefficient() + z^3 + 7*z^2 + 6*z + 10 + sage: C.constant_coefficient() == C.base()(T) + True + """ + return self._constant_coefficient + + def function_ring(self): + r""" + Return the function ring of the category. + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + sage: C.function_ring() + Univariate Polynomial Ring in T over Finite Field of size 11 + sage: C.function_ring() is A + True + """ + return self._function_ring + + def object(self, gen): + r""" + Return a Drinfeld module object in the category whose generator + is the input. + + INPUT: + + - ``gen`` -- the generator of the Drinfeld module, given as an Ore + polynomial or a list of coefficients + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: psi = DrinfeldModule(A, [p_root, 1]) + sage: C = psi.category() + + sage: phi = C.object([p_root, 0, 1]) + sage: phi + Drinfeld module defined by T |--> t^2 + z^3 + 7*z^2 + 6*z + 10 + sage: t = phi.ore_polring().gen() + sage: C.object(t^2 + z^3 + 7*z^2 + 6*z + 10) is phi + True + """ + from sage.rings.function_field.drinfeld_modules.drinfeld_module import DrinfeldModule + # If gen is not in the Ore polring, an exception is raised + gen = self._ore_polring(gen) + T = self._function_ring.gen() + if gen[0] != self._base_morphism(T): + raise ValueError('constant coefficient must equal that of the ' + 'category') + return DrinfeldModule(self._function_ring, gen) + + def ore_polring(self): + r""" + Return the Ore polynomial ring of the category + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + sage: C.ore_polring() + Ore Polynomial Ring in t over Finite Field in z of size 11^4 over its base twisted by Frob + """ + return self._ore_polring + + def random_object(self, rank): + r""" + Return a random Drinfeld module in the category with given rank. + + INPUT: + + - ``rank`` -- an integer, the rank of the Drinfeld module + + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + + sage: psi = C.random_object(3) # random + Drinfeld module defined by T |--> (6*z^3 + 4*z^2 + 10*z + 9)*t^3 + (4*z^3 + 8*z^2 + 8*z)*t^2 + (10*z^3 + 3*z^2 + 6*z)*t + z^3 + 7*z^2 + 6*z + 10 + sage: psi.rank() == 3 + True + """ + if not isinstance(rank, Integer): + raise TypeError('rank must be a positive integer') + if rank <= 0: + raise ValueError('rank must be a positive integer') + + K = self._base_field + coeffs = [self._constant_coefficient] + for _ in range(rank-1): + coeffs.append(K.random_element()) + dom_coeff = 0 + while dom_coeff == 0: + dom_coeff = K.random_element() + coeffs.append(dom_coeff) + + return self.object(coeffs) + + def super_categories(self): + """ + EXAMPLES:: + + sage: Fq = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(4) + sage: p_root = z^3 + 7*z^2 + 6*z + 10 + sage: phi = DrinfeldModule(A, [p_root, 0, 0, 1]) + sage: C = phi.category() + sage: C.super_categories() + [Category of objects] + """ + return [Objects()] + + class ParentMethods: + + def base(self): + r""" + Return the base field of this Drinfeld module, viewed as + an algebra over the function ring. + + This is an instance of the class + :class:`sage.rings.ring_extension.RingExtension`. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.base() + Finite Field in z12 of size 5^12 over its base + + The base can be infinite:: + + sage: sigma = DrinfeldModule(A, [Frac(A).gen(), 1]) + sage: sigma.base() + Fraction Field of Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 over its base + """ + return self.category().base() + + def base_morphism(self): + r""" + Return the base morphism of this Drinfeld module. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.base_morphism() + Ring morphism: + From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 + To: Finite Field in z12 of size 5^12 over its base + Defn: T |--> 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + + The base field can be infinite:: + + sage: sigma = DrinfeldModule(A, [Frac(A).gen(), 1]) + sage: sigma.base_morphism() + Ring morphism: + From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 + To: Fraction Field of Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 over its base + Defn: T |--> T + """ + return self.category().base_morphism() + + def base_over_constants_field(self): + r""" + Return the base field, seen as an extension over the constants + field `\mathbb{F}_q`. + + This is an instance of the class + :class:`sage.rings.ring_extension.RingExtension`. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.base_over_constants_field() + Field in z12 with defining polynomial x^6 + (4*z2 + 3)*x^5 + x^4 + (3*z2 + 1)*x^3 + x^2 + (4*z2 + 1)*x + z2 over its base + """ + return self.category().base_over_constants_field() + + def characteristic(self): + r""" + Return the function ring-characteristic. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.characteristic() + T^2 + (4*z2 + 2)*T + 2 + sage: phi.base_morphism()(phi.characteristic()) + 0 + + :: + + sage: B.<Y> = Fq[] + sage: L = Frac(B) + sage: psi = DrinfeldModule(A, [L(1), 0, 0, L(1)]) + sage: psi.characteristic() + Traceback (most recent call last): + ... + NotImplementedError: function ring characteristic not implemented in this case + """ + return self.category().characteristic() + + def function_ring(self): + r""" + Return the function ring of this Drinfeld module. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.function_ring() + Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 + sage: phi.function_ring() is A + True + """ + return self.category().function_ring() + + def constant_coefficient(self): + r""" + Return the constant coefficient of the generator + of this Drinfeld module. + + OUTPUT: an element in the base field + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.constant_coefficient() == p_root + True + + Let `\mathbb{F}_q[T]` be the function ring, and let `\gamma` be + the base of the Drinfeld module. The constant coefficient is + `\gamma(T)`:: + + sage: C = phi.category() + sage: base = C.base() + sage: base(T) == phi.constant_coefficient() + True + + Naturally, two Drinfeld modules in the same category have the + same constant coefficient:: + + sage: t = phi.ore_polring().gen() + sage: psi = C.object(phi.constant_coefficient() + t^3) + sage: psi + Drinfeld module defined by T |--> t^3 + 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + + Reciprocally, it is impossible to create two Drinfeld modules in + this category if they do not share the same constant + coefficient:: + + sage: rho = C.object(phi.constant_coefficient() + 1 + t^3) + Traceback (most recent call last): + ... + ValueError: constant coefficient must equal that of the category + """ + return self.category().constant_coefficient() + + def ore_polring(self): + r""" + Return the Ore polynomial ring of this Drinfeld module. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: S = phi.ore_polring() + sage: S + Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 over its base twisted by Frob^2 + + The Ore polynomial ring can also be retrieved from the category + of the Drinfeld module:: + + sage: S is phi.category().ore_polring() + True + + The generator of the Drinfeld module is in the Ore polynomial + ring:: + + sage: phi(T) in S + True + """ + return self.category().ore_polring() + + def ore_variable(self): + r""" + Return the variable of the Ore polynomial ring of this Drinfeld module. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + + sage: phi.ore_polring() + Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 over its base twisted by Frob^2 + sage: phi.ore_variable() + t + + """ + return self.category().ore_polring().gen() diff --git a/src/sage/categories/dual.py b/src/sage/categories/dual.py index b08eb497d39..2b21f81cbda 100644 --- a/src/sage/categories/dual.py +++ b/src/sage/categories/dual.py @@ -36,4 +36,4 @@ def _repr_object_names(self): Category of duals of vector spaces over Rational Field """ # Just to remove the `objects` - return "duals of %s"%(self.base_category()._repr_object_names()) + return "duals of %s" % (self.base_category()._repr_object_names()) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 695f4982bd8..a8bea53f907 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -85,7 +85,8 @@ class EnumeratedSets(CategoryWithAxiom): sage: EnumeratedSets().super_categories() [Category of sets] sage: EnumeratedSets().all_super_categories() - [Category of enumerated sets, Category of sets, Category of sets with partial maps, Category of objects] + [Category of enumerated sets, Category of sets, + Category of sets with partial maps, Category of objects] TESTS:: @@ -230,7 +231,7 @@ def __iter__(self): """ # Check if .first() and .next(x) are overridden in the subclass if ( self.first != self._first_from_iterator and - self.next != self._next_from_iterator ): + self.next != self._next_from_iterator ): return self._iterator_from_next() #Check to see if .unrank() is overridden in the subclass elif self.unrank != self._unrank_from_iterator: @@ -277,6 +278,7 @@ def iterator_range(self, start=None, stop=None, step=None): EXAMPLES:: + sage: # needs sage.combinat sage: P = Partitions() sage: list(P.iterator_range(stop=5)) [[], [1], [2], [1, 1], [3]] @@ -356,6 +358,7 @@ def unrank_range(self, start=None, stop=None, step=None): EXAMPLES:: + sage: # needs sage.combinat sage: P = Partitions() sage: P.unrank_range(stop=5) [[], [1], [2], [1, 1], [3]] @@ -409,6 +412,7 @@ def __getitem__(self, i): EXAMPLES:: + sage: # needs sage.combinat sage: P = Partitions() sage: P[:5] [[], [1], [2], [1, 1], [3]] @@ -469,7 +473,7 @@ def __len__(self): sage: len(GF(5)) 5 - sage: len(MatrixSpace(GF(2), 3, 3)) + sage: len(MatrixSpace(GF(2), 3, 3)) # needs sage.modules 512 """ from sage.rings.infinity import Infinity @@ -494,7 +498,7 @@ def tuple(self): EXAMPLES:: - sage: (GF(3)^2).tuple() + sage: (GF(3)^2).tuple() # needs sage.modules ((0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)) sage: R = Integers(11) sage: l = R.tuple(); l @@ -575,7 +579,7 @@ def list(self): EXAMPLES:: - sage: (GF(3)^2).list() + sage: (GF(3)^2).list() # needs sage.modules [(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)] sage: R = Integers(11) sage: R.list() @@ -592,7 +596,7 @@ def list(self): [1, 2, 3] """ return list(self.tuple()) - _list_default = list # needed by the check system. + _list_default = list # needed by the check system. def _list_from_iterator(self): r""" @@ -603,7 +607,7 @@ def _list_from_iterator(self): Trying to list an infinite vector space raises an error instead of running forever (see :trac:`10470`):: - sage: (QQ^2).list() # indirect test + sage: (QQ^2).list() # indirect test # needs sage.modules Traceback (most recent call last): ... AttributeError: 'FreeModule_ambient_field_with_category' object has no attribute 'list' @@ -738,7 +742,7 @@ def _unrank_from_iterator(self, r): for counter, u in enumerate(self): if counter == r: return u - raise ValueError("the rank must be in the range from %s to %s"%(0,counter)) + raise ValueError("the rank must be in the range from %s to %s" % (0,counter)) unrank = _unrank_from_iterator def _rank_from_iterator(self, x): @@ -809,17 +813,12 @@ def _iterator_from_next(self): [0, 1, 2, 3, 4] """ f = self.first() - yield f - while True: + while not (f is None or f is False): + yield f try: f = self.next(f) - except (TypeError, ValueError ): - break - - if f is None or f is False: - break - else: - yield f + except (TypeError, ValueError): + f = None def _iterator_from_unrank(self): """ @@ -1108,7 +1107,7 @@ def rank(self): """ return self.parent().rank(self) - Finite = LazyImport('sage.categories.finite_enumerated_sets', 'FiniteEnumeratedSets', at_startup=True) + Finite = LazyImport('sage.categories.finite_enumerated_sets', 'FiniteEnumeratedSets', at_startup=True) Infinite = LazyImport('sage.categories.infinite_enumerated_sets', 'InfiniteEnumeratedSets', at_startup=True) class CartesianProducts(CartesianProductsCategory): diff --git a/src/sage/categories/examples/algebras_with_basis.py b/src/sage/categories/examples/algebras_with_basis.py index 7ad85cb82ed..e19d74ff3c9 100644 --- a/src/sage/categories/examples/algebras_with_basis.py +++ b/src/sage/categories/examples/algebras_with_basis.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Examples of algebras with basis """ @@ -10,7 +11,7 @@ from sage.misc.cachefunc import cached_method from sage.sets.family import Family -from sage.categories.all import AlgebrasWithBasis +from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.words.words import Words @@ -25,9 +26,9 @@ def __init__(self, R, alphabet=("a", "b", "c")): """ EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).example(); A + sage: A = AlgebrasWithBasis(QQ).example(); A # needs sage.modules An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field - sage: TestSuite(A).run() + sage: TestSuite(A).run() # needs sage.modules """ self._alphabet = alphabet @@ -39,10 +40,10 @@ def _repr_(self): """ EXAMPLES:: - sage: AlgebrasWithBasis(QQ).example() # indirect doctest + sage: AlgebrasWithBasis(QQ).example() # indirect doctest # needs sage.modules An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field """ - return "An example of an algebra with basis: the free algebra on the generators %s over %s"%(self._alphabet, self.base_ring()) + return "An example of an algebra with basis: the free algebra on the generators %s over %s" % (self._alphabet, self.base_ring()) @cached_method def one_basis(self): @@ -52,10 +53,10 @@ def one_basis(self): EXAMPLES::r - sage: A = AlgebrasWithBasis(QQ).example() - sage: A.one_basis() + sage: A = AlgebrasWithBasis(QQ).example() # needs sage.modules + sage: A.one_basis() # needs sage.modules word: - sage: A.one() + sage: A.one() # needs sage.modules B[word: ] """ return self.basis().keys()([]) @@ -67,6 +68,7 @@ def product_on_basis(self, w1, w2): EXAMPLES:: + sage: # needs sage.modules sage: A = AlgebrasWithBasis(QQ).example() sage: Words = A.basis().keys() sage: A.product_on_basis(Words("acb"), Words("cba")) @@ -84,9 +86,9 @@ def algebra_generators(self): EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).example(); A + sage: A = AlgebrasWithBasis(QQ).example(); A # needs sage.modules An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field - sage: A.algebra_generators() + sage: A.algebra_generators() # needs sage.modules Family (B[word: a], B[word: b], B[word: c]) """ Words = self.basis().keys() @@ -95,4 +97,5 @@ def algebra_generators(self): # for the specifying the order of the elements in the family #return Family(self._alphabet, lambda a: self.term(self.basis().keys()(a))) + Example = FreeAlgebra diff --git a/src/sage/algebras/quantum_groups/__init__.py b/src/sage/categories/examples/all.py similarity index 100% rename from src/sage/algebras/quantum_groups/__init__.py rename to src/sage/categories/examples/all.py diff --git a/src/sage/categories/examples/commutative_additive_monoids.py b/src/sage/categories/examples/commutative_additive_monoids.py index 945826c22a5..20728722d9f 100644 --- a/src/sage/categories/examples/commutative_additive_monoids.py +++ b/src/sage/categories/examples/commutative_additive_monoids.py @@ -10,7 +10,7 @@ from sage.misc.cachefunc import cached_method from sage.structure.parent import Parent -from sage.categories.all import CommutativeAdditiveMonoids +from sage.categories.commutative_additive_monoids import CommutativeAdditiveMonoids from .commutative_additive_semigroups import FreeCommutativeAdditiveSemigroup class FreeCommutativeAdditiveMonoid(FreeCommutativeAdditiveSemigroup): @@ -95,7 +95,7 @@ def _repr_(self): "An example of a commutative monoid: the free commutative monoid generated by ('a', 'b', 'c')" """ - return "An example of a commutative monoid: the free commutative monoid generated by %s"%(self.alphabet,) + return "An example of a commutative monoid: the free commutative monoid generated by %s" % (self.alphabet,) @cached_method def zero(self): @@ -124,7 +124,7 @@ def __bool__(self) -> bool: sage: [bool(m) for m in M.additive_semigroup_generators()] [True, True, True, True] """ - return any(x for x in self.value.values()) + return any(self.value.values()) Example = FreeCommutativeAdditiveMonoid diff --git a/src/sage/categories/examples/commutative_additive_semigroups.py b/src/sage/categories/examples/commutative_additive_semigroups.py index ea2fde99bb4..ce501d5caef 100644 --- a/src/sage/categories/examples/commutative_additive_semigroups.py +++ b/src/sage/categories/examples/commutative_additive_semigroups.py @@ -12,7 +12,7 @@ from sage.structure.parent import Parent from sage.structure.element_wrapper import ElementWrapper from sage.structure.unique_representation import UniqueRepresentation -from sage.categories.all import CommutativeAdditiveSemigroups +from sage.categories.commutative_additive_semigroups import CommutativeAdditiveSemigroups from sage.sets.family import Family class FreeCommutativeAdditiveSemigroup(UniqueRepresentation, Parent): @@ -94,7 +94,7 @@ def _repr_(self): "An example of a commutative semigroup: the free commutative semigroup generated by ('a', 'b', 'c')" """ - return "An example of a commutative semigroup: the free commutative semigroup generated by %s"%(self.alphabet,) + return "An example of a commutative semigroup: the free commutative semigroup generated by %s" % (self.alphabet,) def summation(self, x, y): r""" @@ -181,7 +181,7 @@ def _repr_(self): 0 """ d = self.value - result = ' + '.join( ("%s*%s"%(d[a],a) if d[a] != 1 else a) for a in sorted(d.keys()) if d[a] != 0) + result = ' + '.join( ("%s*%s" % (d[a],a) if d[a] != 1 else a) for a in sorted(d.keys()) if d[a] != 0) return '0' if result == '' else result def __hash__(self): @@ -194,4 +194,5 @@ def __hash__(self): """ return hash(tuple(self.value.items())) + Example = FreeCommutativeAdditiveSemigroup diff --git a/src/sage/categories/examples/crystals.py b/src/sage/categories/examples/crystals.py index 02121cd3c02..520b97c34d5 100644 --- a/src/sage/categories/examples/crystals.py +++ b/src/sage/categories/examples/crystals.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.graphs r""" Example of a crystal """ @@ -116,7 +117,7 @@ def _repr_(self): sage: Crystals().example() Highest weight crystal of type A_3 of highest weight omega_1 """ - return "Highest weight crystal of type A_%s of highest weight omega_1"%(self.n) + return "Highest weight crystal of type A_%s of highest weight omega_1" % (self.n) # temporary workaround while an_element is overridden by Parent _an_element_ = EnumeratedSets.ParentMethods._an_element_ diff --git a/src/sage/categories/examples/cw_complexes.py b/src/sage/categories/examples/cw_complexes.py index 8422fc0a418..0fefb254c20 100644 --- a/src/sage/categories/examples/cw_complexes.py +++ b/src/sage/categories/examples/cw_complexes.py @@ -158,4 +158,5 @@ def dimension(self): """ return self._dim + Example = Surface diff --git a/src/sage/categories/examples/filtered_algebras_with_basis.py b/src/sage/categories/examples/filtered_algebras_with_basis.py index 5a83c54d1fd..57d106e4555 100644 --- a/src/sage/categories/examples/filtered_algebras_with_basis.py +++ b/src/sage/categories/examples/filtered_algebras_with_basis.py @@ -198,4 +198,5 @@ def product_on_basis(self, s, t): cur = cur * self.monomial(self._indices.gen(a)) return cur + Example = PBWBasisCrossProduct diff --git a/src/sage/categories/examples/filtered_modules_with_basis.py b/src/sage/categories/examples/filtered_modules_with_basis.py index 0b5e9b475eb..a76726099bc 100644 --- a/src/sage/categories/examples/filtered_modules_with_basis.py +++ b/src/sage/categories/examples/filtered_modules_with_basis.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.combinat r""" Examples of filtered modules with basis """ @@ -34,7 +34,7 @@ class FilteredPartitionModule(CombinatorialFreeModule): :: - sage: A = ModulesWithBasis(QQ).Filtered().example() + sage: A = ModulesWithBasis(QQ).Filtered().example() # needs sage.modules - If the algebra is called ``A``, then its basis function is stored as ``A.basis``. Thus the function can be used to @@ -44,7 +44,7 @@ class FilteredPartitionModule(CombinatorialFreeModule): :: - sage: [m for m in A.basis(4)] + sage: [m for m in A.basis(4)] # needs sage.modules [P[4], P[3, 1], P[2, 2], P[2, 1, 1], P[1, 1, 1, 1]] - For dealing with basis elements: :meth:`degree_on_basis`, and @@ -58,9 +58,9 @@ class FilteredPartitionModule(CombinatorialFreeModule): :: - sage: A.degree_on_basis(Partition([4,3])) + sage: A.degree_on_basis(Partition([4,3])) # needs sage.modules 7 - sage: A._repr_term(Partition([4,3])) + sage: A._repr_term(Partition([4,3])) # needs sage.modules 'P[4, 3]' - There is a class for elements, which inherits from @@ -74,20 +74,20 @@ class FilteredPartitionModule(CombinatorialFreeModule): :: - sage: p = A.monomial(Partition([3,2,1])); p + sage: p = A.monomial(Partition([3,2,1])); p # needs sage.modules P[3, 2, 1] - sage: p.is_homogeneous() + sage: p.is_homogeneous() # needs sage.modules True - sage: p.degree() + sage: p.degree() # needs sage.modules 6 """ def __init__(self, base_ring): """ EXAMPLES:: - sage: A = ModulesWithBasis(QQ).Filtered().example(); A + sage: A = ModulesWithBasis(QQ).Filtered().example(); A # needs sage.modules An example of a filtered module with basis: the free module on partitions over Rational Field - sage: TestSuite(A).run() + sage: TestSuite(A).run() # needs sage.modules """ CombinatorialFreeModule.__init__(self, base_ring, Partitions(), category=FilteredModulesWithBasis(base_ring)) @@ -111,6 +111,7 @@ def degree_on_basis(self, t): EXAMPLES:: + sage: # needs sage.modules sage: A = ModulesWithBasis(QQ).Filtered().example() sage: A.degree_on_basis(Partition((2,1))) 3 @@ -127,7 +128,7 @@ def _repr_(self): EXAMPLES:: - sage: ModulesWithBasis(QQ).Filtered().example() # indirect doctest + sage: ModulesWithBasis(QQ).Filtered().example() # indirect doctest # needs sage.modules An example of a filtered module with basis: the free module on partitions over Rational Field """ return "An example of a filtered module with basis: the free module on partitions over %s" % self.base_ring() @@ -142,10 +143,11 @@ def _repr_term(self, t): EXAMPLES:: - sage: A = ModulesWithBasis(QQ).Filtered().example() - sage: A._repr_term(Partition((4,2,1))) + sage: A = ModulesWithBasis(QQ).Filtered().example() # needs sage.modules + sage: A._repr_term(Partition((4,2,1))) # needs sage.modules 'P[4, 2, 1]' """ return 'P' + t._repr_() + Example = FilteredPartitionModule diff --git a/src/sage/categories/examples/finite_coxeter_groups.py b/src/sage/categories/examples/finite_coxeter_groups.py index 71ca54c8a5b..84e4c1f95b4 100644 --- a/src/sage/categories/examples/finite_coxeter_groups.py +++ b/src/sage/categories/examples/finite_coxeter_groups.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.groups r""" Examples of finite Coxeter groups """ @@ -11,7 +12,7 @@ from sage.misc.cachefunc import cached_method from sage.structure.parent import Parent from sage.structure.element_wrapper import ElementWrapper -from sage.categories.all import FiniteCoxeterGroups +from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups from sage.structure.unique_representation import UniqueRepresentation from sage.misc.functional import is_odd, is_even from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix diff --git a/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py index a3721f106b7..df8957dbaf7 100644 --- a/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules r""" Example of a finite dimensional algebra with basis """ @@ -9,7 +10,7 @@ #***************************************************************************** from sage.misc.cachefunc import cached_method -from sage.categories.all import FiniteDimensionalAlgebrasWithBasis +from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis from sage.combinat.free_module import CombinatorialFreeModule @@ -55,7 +56,7 @@ def _repr_(self): """ return "An example of a finite dimensional algebra with basis: " \ "the path algebra of the Kronecker quiver " \ - "(containing the arrows a:x->y and b:x->y) over %s "%(self.base_ring()) + "(containing the arrows a:x->y and b:x->y) over %s " % (self.base_ring()) def one(self): r""" @@ -142,4 +143,5 @@ def _repr_term(self, p): """ return str(p) + Example = KroneckerQuiverPathAlgebra diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 306e0091e12..9f221f1432e 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules r""" Examples of a finite dimensional Lie algebra with basis """ @@ -10,7 +11,7 @@ from sage.misc.cachefunc import cached_method from sage.sets.family import Family -from sage.categories.all import LieAlgebras +from sage.categories.lie_algebras import LieAlgebras from sage.modules.free_module import FreeModule from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -362,7 +363,7 @@ def lift(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() sage: elt = 2*a + 2*b + 3*c - sage: elt.lift() + sage: elt.lift() # needs sage.combinat 2*b0 + 2*b1 + 3*b2 """ UEA = self.parent().universal_enveloping_algebra() @@ -403,4 +404,5 @@ def monomial_coefficients(self, copy=True): """ return self.value.monomial_coefficients(copy) + Example = AbelianLieAlgebra diff --git a/src/sage/categories/examples/finite_monoids.py b/src/sage/categories/examples/finite_monoids.py index f61c28a4032..0a4c1374893 100644 --- a/src/sage/categories/examples/finite_monoids.py +++ b/src/sage/categories/examples/finite_monoids.py @@ -13,7 +13,7 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper -from sage.categories.all import Monoids +from sage.categories.monoids import Monoids from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ @@ -86,7 +86,7 @@ def _repr_(self): sage: M._repr_() 'An example of a finite multiplicative monoid: the integers modulo 12' """ - return "An example of a finite multiplicative monoid: the integers modulo %s"%self.n + return "An example of a finite multiplicative monoid: the integers modulo %s" % self.n def semigroup_generators(self): r""" @@ -146,4 +146,5 @@ def an_element(self): class Element (ElementWrapper): wrapped_class = Integer + Example = IntegerModMonoid diff --git a/src/sage/categories/examples/finite_semigroups.py b/src/sage/categories/examples/finite_semigroups.py index e21a9713815..13712de76fe 100644 --- a/src/sage/categories/examples/finite_semigroups.py +++ b/src/sage/categories/examples/finite_semigroups.py @@ -25,7 +25,8 @@ class LeftRegularBand(UniqueRepresentation, Parent): EXAMPLES:: sage: S = FiniteSemigroups().example(); S - An example of a finite semigroup: the left regular band generated by ('a', 'b', 'c', 'd') + An example of a finite semigroup: + the left regular band generated by ('a', 'b', 'c', 'd') This is the semigroup generated by:: @@ -69,9 +70,9 @@ class LeftRegularBand(UniqueRepresentation, Parent): Now, let us look at the structure of the semigroup:: sage: S = FiniteSemigroups().example(alphabet = ('a','b','c')) - sage: S.cayley_graph(side="left", simple=True).plot() + sage: S.cayley_graph(side="left", simple=True).plot() # needs sage.graphs sage.plot Graphics object consisting of 60 graphics primitives - sage: S.j_transversal_of_idempotents() # random (arbitrary choice) + sage: S.j_transversal_of_idempotents() # random (arbitrary choice) # needs sage.graphs ['acb', 'ac', 'ab', 'bc', 'a', 'c', 'b'] We conclude by running systematic tests on this semigroup:: @@ -128,7 +129,7 @@ def _repr_(self): sage: S._repr_() "An example of a finite semigroup: the left regular band generated by ('a', 'b', 'c', 'd')" """ - return "An example of a finite semigroup: the left regular band generated by %s"%(self.alphabet,) + return "An example of a finite semigroup: the left regular band generated by %s" % (self.alphabet,) def product(self, x, y): r""" @@ -186,4 +187,5 @@ class Element (ElementWrapper): wrapped_class = str __lt__ = ElementWrapper._lt_by_value + Example = LeftRegularBand diff --git a/src/sage/categories/examples/finite_weyl_groups.py b/src/sage/categories/examples/finite_weyl_groups.py index a17a48c142e..a8b27cd7ffe 100644 --- a/src/sage/categories/examples/finite_weyl_groups.py +++ b/src/sage/categories/examples/finite_weyl_groups.py @@ -11,7 +11,7 @@ from sage.misc.cachefunc import cached_method from sage.structure.parent import Parent from sage.structure.element_wrapper import ElementWrapper -from sage.categories.all import FiniteWeylGroups +from sage.categories.finite_weyl_groups import FiniteWeylGroups from sage.structure.unique_representation import UniqueRepresentation class SymmetricGroup(UniqueRepresentation, Parent): @@ -59,7 +59,7 @@ class SymmetricGroup(UniqueRepresentation, Parent): 24 sage: S.long_element() (3, 2, 1, 0) - sage: S.cayley_graph(side = "left").plot() + sage: S.cayley_graph(side="left").plot() # needs sage.graphs sage.plot Graphics object consisting of 120 graphics primitives Alternatively, one could have implemented @@ -91,7 +91,7 @@ def _repr_(self): The symmetric group on {0, ..., 3} """ - return "The symmetric group on {0, ..., %s}"%(self.n-1) + return "The symmetric group on {0, ..., %s}" % (self.n-1) @cached_method def one(self): @@ -135,7 +135,7 @@ def cartan_type(self): EXAMPLES:: - sage: FiniteWeylGroups().example().cartan_type() + sage: FiniteWeylGroups().example().cartan_type() # needs sage.modules ['A', 3] relabelled by {1: 0, 2: 1, 3: 2} """ from sage.combinat.root_system.cartan_type import CartanType diff --git a/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py b/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py index 4e044441d2c..2290419adb3 100644 --- a/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +++ b/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules r""" Examples of graded connected Hopf algebras with basis """ @@ -44,7 +45,6 @@ def __init__(self, base_ring): CombinatorialFreeModule.__init__(self, base_ring, NonNegativeIntegers(), category=GradedHopfAlgebrasWithBasis(base_ring).Connected()) - @cached_method def one_basis(self): """ @@ -162,4 +162,5 @@ def coproduct_on_basis(self, i): for j in range(i+1) ) + Example = GradedConnectedCombinatorialHopfAlgebraWithPrimitiveGenerator diff --git a/src/sage/categories/examples/graded_modules_with_basis.py b/src/sage/categories/examples/graded_modules_with_basis.py index 0be39623fa3..8ddfb7eed04 100644 --- a/src/sage/categories/examples/graded_modules_with_basis.py +++ b/src/sage/categories/examples/graded_modules_with_basis.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.combinat r""" Examples of graded modules with basis """ @@ -35,7 +35,7 @@ class GradedPartitionModule(CombinatorialFreeModule): :: - sage: A = GradedModulesWithBasis(QQ).example() + sage: A = GradedModulesWithBasis(QQ).example() # needs sage.modules - A basis function - this module is graded by the non-negative integers, so there is a function defined in this module, @@ -45,9 +45,9 @@ class GradedPartitionModule(CombinatorialFreeModule): :: - sage: A.basis(2) + sage: A.basis(2) # needs sage.modules Lazy family (Term map from Partitions to An example of a graded module with basis: the free module on partitions over Rational Field(i))_{i in Partitions of the integer 2} - sage: A.basis(6)[Partition([3,2,1])] + sage: A.basis(6)[Partition([3,2,1])] # needs sage.modules P[3, 2, 1] - If the algebra is called ``A``, then its basis function is @@ -58,7 +58,7 @@ class GradedPartitionModule(CombinatorialFreeModule): :: - sage: [m for m in A.basis(4)] + sage: [m for m in A.basis(4)] # needs sage.modules [P[4], P[3, 1], P[2, 2], P[2, 1, 1], P[1, 1, 1, 1]] - For dealing with basis elements: :meth:`degree_on_basis`, and @@ -72,9 +72,9 @@ class GradedPartitionModule(CombinatorialFreeModule): :: - sage: A.degree_on_basis(Partition([4,3])) + sage: A.degree_on_basis(Partition([4,3])) # needs sage.modules 7 - sage: A._repr_term(Partition([4,3])) + sage: A._repr_term(Partition([4,3])) # needs sage.modules 'P[4, 3]' - There is a class for elements, which inherits from @@ -88,20 +88,20 @@ class GradedPartitionModule(CombinatorialFreeModule): :: - sage: p = A.monomial(Partition([3,2,1])); p + sage: p = A.monomial(Partition([3,2,1])); p # needs sage.modules P[3, 2, 1] - sage: p.is_homogeneous() + sage: p.is_homogeneous() # needs sage.modules True - sage: p.degree() + sage: p.degree() # needs sage.modules 6 """ def __init__(self, base_ring): """ EXAMPLES:: - sage: A = GradedModulesWithBasis(QQ).example(); A + sage: A = GradedModulesWithBasis(QQ).example(); A # needs sage.modules An example of a graded module with basis: the free module on partitions over Rational Field - sage: TestSuite(A).run() + sage: TestSuite(A).run() # needs sage.modules """ CombinatorialFreeModule.__init__(self, base_ring, Partitions(), category=GradedModulesWithBasis(base_ring)) @@ -125,6 +125,7 @@ def degree_on_basis(self, t): EXAMPLES:: + sage: # needs sage.modules sage: A = GradedModulesWithBasis(QQ).example() sage: A.degree_on_basis(Partition((2,1))) 3 @@ -141,7 +142,7 @@ def _repr_(self): EXAMPLES:: - sage: GradedModulesWithBasis(QQ).example() # indirect doctest + sage: GradedModulesWithBasis(QQ).example() # indirect doctest # needs sage.modules An example of a graded module with basis: the free module on partitions over Rational Field """ return "An example of a graded module with basis: the free module on partitions over %s" % self.base_ring() @@ -156,10 +157,11 @@ def _repr_term(self, t): EXAMPLES:: - sage: A = GradedModulesWithBasis(QQ).example() - sage: A._repr_term(Partition((4,2,1))) + sage: A = GradedModulesWithBasis(QQ).example() # needs sage.modules + sage: A._repr_term(Partition((4,2,1))) # needs sage.modules 'P[4, 2, 1]' """ return 'P' + t._repr_() + Example = GradedPartitionModule diff --git a/src/sage/categories/examples/graphs.py b/src/sage/categories/examples/graphs.py index 21c2d2a150a..063eeff1427 100644 --- a/src/sage/categories/examples/graphs.py +++ b/src/sage/categories/examples/graphs.py @@ -117,4 +117,5 @@ def dimension(self): return 2 return 1 + Example = Cycle diff --git a/src/sage/categories/examples/hopf_algebras_with_basis.py b/src/sage/categories/examples/hopf_algebras_with_basis.py index 16bd866c9c6..10c89b0f9ad 100644 --- a/src/sage/categories/examples/hopf_algebras_with_basis.py +++ b/src/sage/categories/examples/hopf_algebras_with_basis.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups sage.modules r""" Examples of Hopf algebras with basis """ @@ -10,9 +11,9 @@ from sage.misc.cachefunc import cached_method from sage.sets.family import Family -from sage.categories.all import HopfAlgebrasWithBasis +from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.combinat.free_module import CombinatorialFreeModule -from sage.categories.all import tensor +from sage.categories.tensor import tensor class MyGroupAlgebra(CombinatorialFreeModule): r""" @@ -42,7 +43,7 @@ def _repr_(self): sage: HopfAlgebrasWithBasis(QQ).example() # indirect doctest An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field """ - return "An example of Hopf algebra with basis: the group algebra of the %s over %s"%(self._group, self.base_ring()) + return "An example of Hopf algebra with basis: the group algebra of the %s over %s" % (self._group, self.base_ring()) @cached_method def one_basis(self): diff --git a/src/sage/categories/examples/infinite_enumerated_sets.py b/src/sage/categories/examples/infinite_enumerated_sets.py index c4bb3d8e55d..df4151f21c2 100644 --- a/src/sage/categories/examples/infinite_enumerated_sets.py +++ b/src/sage/categories/examples/infinite_enumerated_sets.py @@ -185,4 +185,5 @@ def _element_constructor_(self, i): Element = Integer + Example = NonNegativeIntegers diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index 3eafe0787f3..135c122efa2 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules r""" Examples of a Lie algebra """ @@ -10,7 +11,7 @@ #from sage.misc.cachefunc import cached_method from sage.sets.family import Family -from sage.categories.all import LieAlgebras +from sage.categories.lie_algebras import LieAlgebras from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper @@ -68,6 +69,7 @@ def __classcall_private__(cls, gens): EXAMPLES:: + sage: # needs sage.combinat sage: S3 = SymmetricGroupAlgebra(QQ, 3) sage: L1 = LieAlgebras(QQ).example() sage: gens = list(S3.algebra_generators()) @@ -81,8 +83,8 @@ def __init__(self, gens): """ EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: TestSuite(L).run() + sage: L = LieAlgebras(QQ).example() # needs sage.combinat + sage: TestSuite(L).run() # needs sage.combinat """ if not gens: raise ValueError("need at least one generator") @@ -95,7 +97,7 @@ def _repr_(self): """ EXAMPLES:: - sage: LieAlgebras(QQ).example() + sage: LieAlgebras(QQ).example() # needs sage.combinat sage.groups An example of a Lie algebra: the Lie algebra from the associative algebra Symmetric group algebra of order 3 over Rational Field generated by ([2, 1, 3], [2, 3, 1]) @@ -110,6 +112,7 @@ def _element_constructor_(self, value): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: S3 = SymmetricGroupAlgebra(ZZ, 3) sage: gens = S3.algebra_generators() sage: L = LieAlgebras(QQ).example() @@ -124,8 +127,8 @@ def zero(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: L.zero() + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.groups + sage: L.zero() # needs sage.combinat sage.groups 0 """ return self.element_class(self, self._A.zero()) @@ -136,8 +139,8 @@ def lie_algebra_generators(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: L.lie_algebra_generators() + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.groups + sage: L.lie_algebra_generators() # needs sage.combinat sage.groups Family ([2, 1, 3], [2, 3, 1]) """ return Family([self.element_class(self, g) for g in self._gens]) @@ -157,8 +160,9 @@ def __eq__(self, rhs): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() + sage: x, y = L.lie_algebra_generators() sage: x == x True sage: x.bracket(y) == -y.bracket(x) @@ -180,8 +184,9 @@ def __ne__(self, rhs): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() + sage: x, y = L.lie_algebra_generators() sage: x != y True sage: x != 0 @@ -199,10 +204,10 @@ def __bool__(self) -> bool: EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: bool(sum(L.lie_algebra_generators())) + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.groups + sage: bool(sum(L.lie_algebra_generators())) # needs sage.combinat sage.groups True - sage: bool(L.zero()) + sage: bool(L.zero()) # needs sage.combinat sage.groups False """ return bool(self.value) @@ -213,9 +218,9 @@ def _add_(self, rhs): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() - sage: x + y + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.groups + sage: x, y = L.lie_algebra_generators() # needs sage.combinat sage.groups + sage: x + y # needs sage.combinat sage.groups [2, 1, 3] + [2, 3, 1] """ return self.__class__(self.parent(), self.value + rhs.value) @@ -226,9 +231,9 @@ def _sub_(self, rhs): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() - sage: x - y + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.groups + sage: x, y = L.lie_algebra_generators() # needs sage.combinat sage.groups + sage: x - y # needs sage.combinat sage.groups [2, 1, 3] - [2, 3, 1] """ return self.__class__(self.parent(), self.value - rhs.value) @@ -239,9 +244,9 @@ def _acted_upon_(self, scalar, self_on_left=False): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() - sage: 3 * x + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.groups + sage: x, y = L.lie_algebra_generators() # needs sage.combinat sage.groups + sage: 3 * x # needs sage.combinat sage.groups 3*[2, 1, 3] """ # This was copied, but IDK if it still applies: @@ -265,9 +270,9 @@ def __truediv__(self, x, self_on_left=False): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() - sage: y / 4 + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.groups + sage: x, y = L.lie_algebra_generators() # needs sage.combinat sage.groups + sage: y / 4 # needs sage.combinat sage.groups 1/4*[2, 3, 1] """ if self_on_left: @@ -280,9 +285,9 @@ def __neg__(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() - sage: -x + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.groups + sage: x, y = L.lie_algebra_generators() # needs sage.combinat sage.groups + sage: -x # needs sage.combinat sage.groups -[2, 1, 3] """ return self.__class__(self.parent(), -self.value) @@ -313,6 +318,7 @@ def _bracket_(self, rhs): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: L = LieAlgebras(QQ).example() sage: x,y = L.lie_algebra_generators() sage: elt = 2*x - y @@ -326,4 +332,5 @@ def _bracket_(self, rhs): """ return self.__class__(self.parent(), self.value * rhs.value - rhs.value * self.value) + Example = LieAlgebraFromAssociative diff --git a/src/sage/categories/examples/lie_algebras_with_basis.py b/src/sage/categories/examples/lie_algebras_with_basis.py index 484e0eee918..ca711e1cdb4 100644 --- a/src/sage/categories/examples/lie_algebras_with_basis.py +++ b/src/sage/categories/examples/lie_algebras_with_basis.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.modules r""" Examples of a Lie algebra with basis """ @@ -99,6 +100,7 @@ def lift(self): I = UEA._indices return UEA.sum_of_terms((I.gen(t), c) for t, c in self) + Example = AbelianLieAlgebra ############## diff --git a/src/sage/categories/examples/magmas.py b/src/sage/categories/examples/magmas.py index 5139041cef0..a4858bc2606 100644 --- a/src/sage/categories/examples/magmas.py +++ b/src/sage/categories/examples/magmas.py @@ -15,7 +15,7 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper -from sage.categories.all import Magmas +from sage.categories.magmas import Magmas from sage.sets.family import Family diff --git a/src/sage/categories/examples/manifolds.py b/src/sage/categories/examples/manifolds.py index e1d7c851202..6a748884eec 100644 --- a/src/sage/categories/examples/manifolds.py +++ b/src/sage/categories/examples/manifolds.py @@ -89,4 +89,5 @@ def an_element(self): Element = ElementWrapper + Example = Plane diff --git a/src/sage/categories/examples/monoids.py b/src/sage/categories/examples/monoids.py index c2919a8cc28..1d2b87279d2 100644 --- a/src/sage/categories/examples/monoids.py +++ b/src/sage/categories/examples/monoids.py @@ -11,7 +11,7 @@ from sage.misc.cachefunc import cached_method from sage.structure.parent import Parent from sage.structure.element_wrapper import ElementWrapper -from sage.categories.all import Monoids +from sage.categories.monoids import Monoids from .semigroups import FreeSemigroup from sage.sets.family import Family @@ -104,7 +104,7 @@ def _repr_(self): "An example of a monoid: the free monoid generated by ('a', 'b', 'c')" """ - return "An example of a monoid: the free monoid generated by %s"%(self.alphabet,) + return "An example of a monoid: the free monoid generated by %s" % (self.alphabet,) @cached_method def one(self): @@ -141,4 +141,5 @@ def monoid_generators(self): class Element (ElementWrapper): wrapped_class = str + Example = FreeMonoid diff --git a/src/sage/categories/examples/posets.py b/src/sage/categories/examples/posets.py index 5041df19835..20f461860c9 100644 --- a/src/sage/categories/examples/posets.py +++ b/src/sage/categories/examples/posets.py @@ -10,7 +10,7 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.categories.all import Posets +from sage.categories.posets import Posets from sage.structure.element_wrapper import ElementWrapper from sage.sets.set import Set, Set_object_enumerated from sage.sets.positive_integers import PositiveIntegers diff --git a/src/sage/categories/examples/semigroups.py b/src/sage/categories/examples/semigroups.py index 4c4d9a1f4df..797fd1b4b03 100644 --- a/src/sage/categories/examples/semigroups.py +++ b/src/sage/categories/examples/semigroups.py @@ -12,7 +12,7 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper -from sage.categories.all import Semigroups +from sage.categories.semigroups import Semigroups from sage.sets.family import Family class LeftZeroSemigroup(UniqueRepresentation, Parent): @@ -209,7 +209,7 @@ def _repr_(self): "An example of a semigroup: the free semigroup generated by ('a', 'b', 'c')" """ - return "An example of a semigroup: the free semigroup generated by %s"%(self.alphabet,) + return "An example of a semigroup: the free semigroup generated by %s" % (self.alphabet,) def product(self, x, y): r""" diff --git a/src/sage/categories/examples/semigroups_cython.pyx b/src/sage/categories/examples/semigroups_cython.pyx index ee7a03ddc82..b456c2868f8 100644 --- a/src/sage/categories/examples/semigroups_cython.pyx +++ b/src/sage/categories/examples/semigroups_cython.pyx @@ -4,7 +4,8 @@ Examples of semigroups in cython from sage.structure.parent cimport Parent from sage.structure.element cimport Element -from sage.categories.all import Category, Semigroups +from sage.categories.category import Category +from sage.categories.semigroups import Semigroups from sage.categories.examples.semigroups import LeftZeroSemigroup as LeftZeroSemigroupPython from cpython.object cimport PyObject_RichCompare diff --git a/src/sage/categories/examples/sets_cat.py b/src/sage/categories/examples/sets_cat.py index 93cc264580d..e0853d63f94 100644 --- a/src/sage/categories/examples/sets_cat.py +++ b/src/sage/categories/examples/sets_cat.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari """ Examples of sets """ @@ -13,7 +14,7 @@ from sage.categories.sets_cat import Sets from sage.rings.integer import Integer, IntegerWrapper from sage.rings.integer_ring import IntegerRing -from sage.arith.all import is_prime +from sage.arith.misc import is_prime from sage.structure.unique_representation import UniqueRepresentation @@ -143,15 +144,12 @@ def _element_constructor_(self, e): AssertionError: 14 is not a prime number """ p = self.element_class(e) - assert is_prime(p), "%s is not a prime number"%(p) + assert is_prime(p), "%s is not a prime number" % (p) return p element_class = Integer - - - from sage.misc.abstract_method import abstract_method class PrimeNumbers_Abstract(UniqueRepresentation, Parent): """ @@ -160,7 +158,7 @@ class PrimeNumbers_Abstract(UniqueRepresentation, Parent): datastructure will then be constructed by inheriting from :class:`PrimeNumbers_Abstract`. - This is used by: + This is used by:: sage: P = Sets().example("facade") sage: P = Sets().example("inherits") @@ -215,7 +213,7 @@ def _element_constructor_(self, i): if i in self: return self._from_integer_(i) else: - raise ValueError("%s is not a prime number"%(i)) + raise ValueError("%s is not a prime number" % (i)) @abstract_method def _from_integer_(self, i): @@ -541,6 +539,7 @@ def _from_integer_(self, e): return self.element_class(self, Integer(e)) from sage.structure.element_wrapper import ElementWrapper + class Element (ElementWrapper, PrimeNumbers_Abstract.Element): def _integer_(self, IntRing): """ @@ -556,9 +555,6 @@ def _integer_(self, IntRing): return IntRing(self.value) - - - #*************************************************************************# class PrimeNumbers_Facade(PrimeNumbers_Abstract): r""" diff --git a/src/sage/categories/examples/with_realizations.py b/src/sage/categories/examples/with_realizations.py index 06e060f8925..5a8c1149187 100644 --- a/src/sage/categories/examples/with_realizations.py +++ b/src/sage/categories/examples/with_realizations.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.modules r""" Examples of parents endowed with multiple realizations """ @@ -10,7 +11,9 @@ from sage.misc.cachefunc import cached_method from sage.misc.bindable_class import BindableClass -from sage.categories.all import Rings, Algebras, AlgebrasWithBasis +from sage.categories.rings import Rings +from sage.categories.algebras import Algebras +from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.categories.realizations import Category_realization_of_parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent @@ -275,7 +278,7 @@ def _repr_(self): sage: Sets().WithRealizations().example() # indirect doctest The subset algebra of {1, 2, 3} over Rational Field """ - return "The subset algebra of %s over %s"%(self.base_set(), self.base_ring()) + return "The subset algebra of %s over %s" % (self.base_set(), self.base_ring()) class Bases(Category_realization_of_parent): r""" @@ -301,7 +304,6 @@ def super_categories(self): return [A.Realizations(), category.Realizations().WithBasis()] - class ParentMethods: def from_set(self, *args): diff --git a/src/sage/categories/facade_sets.py b/src/sage/categories/facade_sets.py index 0ddebfe30d2..746622743fb 100644 --- a/src/sage/categories/facade_sets.py +++ b/src/sage/categories/facade_sets.py @@ -100,7 +100,7 @@ def _element_constructor_(self, element): return parent(element) except Exception: pass - raise ValueError("Can't coerce `%s` in any parent `%s` is a facade for"%(element, self)) + raise ValueError("Can't coerce `%s` in any parent `%s` is a facade for" % (element, self)) def facade_for(self): """ diff --git a/src/sage/categories/fields.py b/src/sage/categories/fields.py index 4bbbd08ae95..fb5e1f06a1b 100644 --- a/src/sage/categories/fields.py +++ b/src/sage/categories/fields.py @@ -41,7 +41,7 @@ class Fields(CategoryWithAxiom): sage: K(PolynomialRing(GF(3), 'x')) Fraction Field of Univariate Polynomial Ring in x over Finite Field of size 3 - sage: K(RealField()) + sage: K(RealField()) # needs sage.rings.real_mpfr Real Field with 53 bits of precision TESTS:: @@ -64,7 +64,7 @@ def __contains__(self, x): """ EXAMPLES:: - sage: GF(4, "a") in Fields() + sage: GF(4, "a") in Fields() # needs sage.rings.finite_rings True sage: QQ in Fields() True @@ -81,15 +81,15 @@ def __contains__(self, x): Caveat: this should eventually be fixed:: - sage: gap.Rationals in Fields() + sage: gap.Rationals in Fields() # needs sage.libs.gap False typically by implementing the method :meth:`category` appropriately for Gap objects:: - sage: GR = gap.Rationals - sage: GR.category = lambda : Fields() - sage: GR in Fields() + sage: GR = gap.Rationals # needs sage.libs.gap + sage: GR.category = lambda: Fields() # needs sage.libs.gap + sage: GR in Fields() # needs sage.libs.gap True The following tests against a memory leak fixed in :trac:`13370`. In order @@ -101,7 +101,7 @@ def __contains__(self, x): sage: _ = gc.collect() sage: permstore = [X for X in gc.get_objects() if isinstance(X, sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic)] sage: n = len(permstore) - sage: for i in prime_range(100): + sage: for i in prime_range(100): # needs sage.libs.pari ....: R = ZZ.quotient(i) ....: t = R in Fields() @@ -139,8 +139,9 @@ def _contains_helper(cls): TESTS:: + sage: # needs sage.libs.pari sage: P.<x> = QQ[] - sage: Q = P.quotient(x^2+2) + sage: Q = P.quotient(x^2 + 2) sage: Q.category() Category of commutative no zero divisors quotients of algebras over (number fields and quotient fields and metric spaces) @@ -167,18 +168,18 @@ def _call_(self, x): sage: Fields().super_categories() [Category of euclidean domains, Category of division rings] - sage: K(IntegerRing()) # indirect doctest + sage: K(IntegerRing()) # indirect doctest Rational Field - sage: K(PolynomialRing(GF(3), 'x')) # indirect doctest + sage: K(PolynomialRing(GF(3), 'x')) # indirect doctest Fraction Field of Univariate Polynomial Ring in x over Finite Field of size 3 - sage: K(RealField()) + sage: K(RealField()) # needs sage.rings.real_mpfr Real Field with 53 bits of precision """ try: return x.fraction_field() except AttributeError: - raise TypeError("unable to associate a field to %s"%x) + raise TypeError("unable to associate a field to %s" % x) Finite = LazyImport('sage.categories.finite_fields', 'FiniteFields', at_startup=True) @@ -207,7 +208,7 @@ def is_integrally_closed(self): sage: QQ.is_integrally_closed() True - sage: QQbar.is_integrally_closed() + sage: QQbar.is_integrally_closed() # needs sage.rings.number_field True sage: Z5 = GF(5); Z5 Finite Field of size 5 @@ -231,13 +232,16 @@ def _gcd_univariate_polynomial(self, a, b): EXAMPLES:: - sage: R.<x> = QQbar[] - sage: QQbar._gcd_univariate_polynomial(2*x, 2*x^2) + sage: R.<x> = QQbar[] # needs sage.rings.number_field + sage: QQbar._gcd_univariate_polynomial(2*x, 2*x^2) # needs sage.rings.number_field x TESTS:: - sage: for A in (RR, CC, QQbar): + sage: fields = [] + sage: fields += [RR, CC] # needs sage.rings.real_mpfr + sage: fields.append(QQbar) # needs sage.rings.number_field + sage: for A in fields: ....: g = A._gcd_univariate_polynomial ....: R.<x> = A[] ....: z = R.zero() @@ -246,10 +250,11 @@ def _gcd_univariate_polynomial(self, a, b): ....: g(2*x, z) == x and ....: g(z, z) == z) + sage: # needs sage.rings.real_mpfr sage: R.<x> = RR[] - sage: (x^3).gcd(x^5+1) + sage: (x^3).gcd(x^5 + 1) 1.00000000000000 - sage: (x^3).gcd(x^5+x^2) + sage: (x^3).gcd(x^5 + x^2) x^2 sage: f = (x+3)^2 * (x-1) sage: g = (x+3)^5 @@ -259,6 +264,7 @@ def _gcd_univariate_polynomial(self, a, b): The following example illustrates the fact that for inexact base rings, the returned gcd is often 1 due to rounding:: + sage: # needs sage.rings.real_mpfr sage: f = (x+RR.pi())^2 * (x-1) sage: g = (x+RR.pi())^5 sage: f.gcd(g) @@ -266,8 +272,9 @@ def _gcd_univariate_polynomial(self, a, b): Check :trac:`23012`:: + sage: # needs sage.libs.pari sage: R.<x> = QQ[] - sage: Q = R.quotient(x^2-1) # Not a field + sage: Q = R.quotient(x^2 - 1) # Not a field sage: P.<x> = Q[] sage: def always_True(*args, **kwds): return True sage: Q.is_field = always_True @@ -330,7 +337,10 @@ def _xgcd_univariate_polynomial(self, a, b): TESTS:: - sage: for A in (RR, CC, QQbar): + sage: fields = [] + sage: fields += [RR, CC] # needs sage.rings.real_mpfr + sage: fields.append(QQbar) # needs sage.rings.number_field + sage: for A in fields: ....: g = A._xgcd_univariate_polynomial ....: R.<x> = A[] ....: z, h = R(0), R(1/2) @@ -350,6 +360,7 @@ def _xgcd_univariate_polynomial(self, a, b): We check that the behavior of xgcd with zero elements is compatible with gcd (:trac:`17671`):: + sage: # needs sage.rings.number_field sage: R.<x> = QQbar[] sage: zero = R.zero() sage: zero.xgcd(2*x) @@ -467,8 +478,8 @@ def _squarefree_decomposition_univariate_polynomial(self, f): sage: x = polygen(GF(3)) sage: x.squarefree_decomposition() x - sage: f = QQbar['x'](1) - sage: f.squarefree_decomposition() + sage: f = QQbar['x'](1) # needs sage.rings.number_field + sage: f.squarefree_decomposition() # needs sage.rings.number_field 1 """ from sage.structure.factorization import Factorization @@ -525,10 +536,11 @@ def vector_space(self, *args, **kwds): EXAMPLES:: - sage: K.<a> = Qq(125) # optional - sage.rings.padics - sage: V, fr, to = K.vector_space() # optional - sage.rings.padics - sage: v = V([1, 2, 3]) # optional - sage.rings.padics - sage: fr(v, 7) # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K.<a> = Qq(125) + sage: V, fr, to = K.vector_space() + sage: v = V([1, 2, 3]) + sage: fr(v, 7) (3*a^2 + 2*a + 1) + O(5^7) """ return self.free_module(*args, **kwds) @@ -606,7 +618,8 @@ def gcd(self,other): 1 sage: K(0).gcd(K(0)) 0 - sage: all(x.gcd(y) == (0 if x == 0 and y == 0 else 1) for x in K for y in K) + sage: all(x.gcd(y) == (0 if x == 0 and y == 0 else 1) + ....: for x in K for y in K) True For field of characteristic zero, the gcd of integers is considered @@ -791,7 +804,8 @@ def inverse_of_unit(self): EXAMPLES:: - sage: NumberField(x^7+2,'a')(2).inverse_of_unit() + sage: x = polygen(ZZ, 'x') + sage: NumberField(x^7 + 2, 'a')(2).inverse_of_unit() # needs sage.rings.number_field 1/2 Trying to invert the zero element typically raises a diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 90c7078e6cc..1abddc81a18 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -321,6 +321,7 @@ def induced_graded_map(self, other, f): `f` will lead into a graded algebra already, namely into the algebra of symmetric functions:: + sage: # needs sage.combinat sage.modules sage: h = SymmetricFunctions(QQ).h() sage: def map_on_basis(m): # redefining map_on_basis ....: d = m.dict() @@ -351,6 +352,7 @@ def induced_graded_map(self, other, f): is already graded, so its associated graded algebra is implemented as itself:: + sage: # needs sage.combinat sage.modules sage: grh = h.graded_algebra(); grh is h True sage: grf = A.induced_graded_map(h, f); grf @@ -384,6 +386,7 @@ def induced_graded_map(self, other, f): have one as the domain instead. Our new ``f`` will go from ``h`` to ``A``:: + sage: # needs sage.combinat sage.modules sage: def map_on_basis(lam): # redefining map_on_basis ....: return x ** (sum(lam)) + y ** (len(lam)) sage: f = h.module_morphism(on_basis=map_on_basis, @@ -426,6 +429,7 @@ def induced_graded_map(self, other, f): The construct `\operatorname{gr} f` also makes sense when `f` is a filtration-preserving map between graded algebras. :: + sage: # needs sage.combinat sage.modules sage: def map_on_basis(lam): # redefining map_on_basis ....: return h[lam] + h[len(lam)] sage: f = h.module_morphism(on_basis=map_on_basis, @@ -459,6 +463,7 @@ def induced_graded_map(self, other, f): For another example, let us compute `\operatorname{gr} f` for a map `f` between two Clifford algebras:: + sage: # needs sage.modules sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: B = CliffordAlgebra(Q, names=['u','v']); B The Clifford algebra of the Quadratic form in 2 diff --git a/src/sage/categories/filtered_hopf_algebras_with_basis.py b/src/sage/categories/filtered_hopf_algebras_with_basis.py index d93f89422da..0310744d9e1 100644 --- a/src/sage/categories/filtered_hopf_algebras_with_basis.py +++ b/src/sage/categories/filtered_hopf_algebras_with_basis.py @@ -65,7 +65,6 @@ def super_categories(self): R = self.base_category().base_ring() return [HopfAlgebras(R).Filtered()] - class Connected(CategoryWithAxiom_over_base_ring): class ParentMethods: @cached_method @@ -89,14 +88,15 @@ def antipode_on_basis(self, index): TESTS:: + sage: # needs sage.modules sage: H = GradedHopfAlgebrasWithBasis(QQ).Connected().example() - sage: H.monomial(0).antipode() # indirect doctest + sage: H.monomial(0).antipode() # indirect doctest P0 - sage: H.monomial(1).antipode() # indirect doctest + sage: H.monomial(1).antipode() # indirect doctest -P1 - sage: H.monomial(2).antipode() # indirect doctest + sage: H.monomial(2).antipode() # indirect doctest P2 - sage: H.monomial(3).antipode() # indirect doctest + sage: H.monomial(3).antipode() # indirect doctest -P3 """ if self.monomial(index) == self.one(): @@ -117,15 +117,15 @@ def antipode(self, elem): TESTS:: - sage: H = GradedHopfAlgebrasWithBasis(QQ).Connected().example() - sage: H.antipode(H.monomial(14)) + sage: H = GradedHopfAlgebrasWithBasis(QQ).Connected().example() # needs sage.modules + sage: H.antipode(H.monomial(14)) # needs sage.modules P14 - sage: H.monomial(0).antipode() + sage: H.monomial(0).antipode() # needs sage.modules P0 - sage: H.monomial(2).antipode() + sage: H.monomial(2).antipode() # needs sage.modules P2 - sage: (2*H.monomial(1) + 3*H.monomial(4)).antipode() + sage: (2*H.monomial(1) + 3*H.monomial(4)).antipode() # needs sage.modules -2*P1 + 3*P4 """ return self.linear_combination( diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index 336c1c326c8..15d0f490713 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -200,9 +200,12 @@ def homogeneous_component_basis(self, d): sage: A = GradedModulesWithBasis(ZZ).example() sage: A.homogeneous_component_basis(4) - Lazy family (Term map from Partitions to An example of a graded module with basis: - the free module on partitions over Integer Ring(i))_{i in Partitions of the integer 4} + Lazy family (Term map + from Partitions + to An example of a graded module with basis: the free module + on partitions over Integer Ring(i))_{i in Partitions of the integer 4} + sage: # needs sage.modules sage: cat = GradedModulesWithBasis(ZZ) sage: C = CombinatorialFreeModule(ZZ, ['a', 'b'], category=cat) sage: C.degree_on_basis = lambda x: 1 if x == 'a' else 2 @@ -316,6 +319,7 @@ def to_graded_conversion(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = Modules(QQ).WithBasis().Filtered().example() sage: p = -2 * A.an_element(); p -4*P[] - 4*P[1] - 6*P[2] @@ -344,6 +348,7 @@ def from_graded_conversion(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = Modules(QQ).WithBasis().Filtered().example() sage: p = -2 * A.an_element(); p -4*P[] - 4*P[1] - 6*P[2] @@ -376,6 +381,7 @@ def projection(self, i): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = Modules(ZZ).WithBasis().Filtered().example() sage: p = -2 * A.an_element(); p -4*P[] - 4*P[1] - 6*P[2] @@ -437,21 +443,26 @@ def induced_graded_map(self, other, f): We start with the free `\QQ`-module with basis the set of all partitions:: - sage: A = Modules(QQ).WithBasis().Filtered().example(); A + sage: A = Modules(QQ).WithBasis().Filtered().example(); A # needs sage.combinat sage.modules An example of a filtered module with basis: the free module on partitions over Rational Field - sage: M = A.indices(); M + sage: M = A.indices(); M # needs sage.combinat sage.modules Partitions - sage: p1, p2, p21, p321 = [A.basis()[Partition(i)] for i in [[1], [2], [2,1], [3,2,1]]] + sage: p1, p2, p21, p321 = [A.basis()[Partition(i)] # needs sage.combinat sage.modules + ....: for i in [[1], [2], [2,1], [3,2,1]]] Let us define a map from ``A`` to itself which acts on the basis by sending every partition `\lambda` to the sum of the conjugates of all partitions `\mu` for which `\lambda / \mu` is a horizontal strip:: + sage: # needs sage.combinat sage.modules sage: def map_on_basis(lam): - ....: return A.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) - ....: for mu in lam.remove_horizontal_border_strip(k)]) + ....: def mus(k): + ....: return lam.remove_horizontal_border_strip(k) + ....: return A.sum_of_monomials([Partition(mu).conjugate() + ....: for k in range(sum(lam) + 1) + ....: for mu in mus(k)]) sage: f = A.module_morphism(on_basis=map_on_basis, ....: codomain=A) sage: f(p1) @@ -468,16 +479,18 @@ def induced_graded_map(self, other, f): We now compute `\operatorname{gr} f` :: + sage: # needs sage.combinat sage.modules sage: grA = A.graded_algebra(); grA Graded Module of An example of a filtered module with basis: the free module on partitions over Rational Field - sage: pp1, pp2, pp21, pp321 = [A.to_graded_conversion()(i) for i in [p1, p2, p21, p321]] + sage: pp1, pp2, pp21, pp321 = [A.to_graded_conversion()(i) + ....: for i in [p1, p2, p21, p321]] sage: pp2 + 4 * pp21 Bbar[[2]] + 4*Bbar[[2, 1]] sage: grf = A.induced_graded_map(A, f); grf - Generic endomorphism of Graded Module of An example of a - filtered module with basis: - the free module on partitions over Rational Field + Generic endomorphism of Graded Module of + An example of a filtered module with basis: + the free module on partitions over Rational Field sage: grf(pp1) Bbar[[1]] sage: grf(pp2 + 4 * pp21) @@ -490,10 +503,14 @@ def induced_graded_map(self, other, f): `f` will lead into a graded algebra already, namely into the algebra of symmetric functions:: + sage: # needs sage.combinat sage.modules sage: h = SymmetricFunctions(QQ).h() sage: def map_on_basis(lam): # redefining map_on_basis - ....: return h.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) - ....: for mu in lam.remove_horizontal_border_strip(k)]) + ....: def mus(k): + ....: return lam.remove_horizontal_border_strip(k) + ....: return h.sum_of_monomials([Partition(mu).conjugate() + ....: for k in range(sum(lam) + 1) + ....: for mu in mus(k)]) sage: f = A.module_morphism(on_basis=map_on_basis, ....: codomain=h) # redefining f sage: f(p1) @@ -509,6 +526,7 @@ def induced_graded_map(self, other, f): is already graded, so its associated graded algebra is implemented as itself:: + sage: # needs sage.combinat sage.modules sage: grh = h.graded_algebra(); grh is h True sage: grf = A.induced_graded_map(h, f); grf @@ -537,9 +555,13 @@ def induced_graded_map(self, other, f): have one as the domain instead. Our new ``f`` will go from ``h`` to ``A``:: + sage: # needs sage.combinat sage.modules sage: def map_on_basis(lam): # redefining map_on_basis - ....: return A.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) - ....: for mu in lam.remove_horizontal_border_strip(k)]) + ....: def mus(k): + ....: return lam.remove_horizontal_border_strip(k) + ....: return A.sum_of_monomials([Partition(mu).conjugate() + ....: for k in range(sum(lam) + 1) + ....: for mu in mus(k)]) sage: f = h.module_morphism(on_basis=map_on_basis, ....: codomain=A) # redefining f sage: f(h[1]) @@ -580,9 +602,13 @@ def induced_graded_map(self, other, f): The construct `\operatorname{gr} f` also makes sense when `f` is a filtration-preserving map between graded modules. :: + sage: # needs sage.combinat sage.modules sage: def map_on_basis(lam): # redefining map_on_basis - ....: return h.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) - ....: for mu in lam.remove_horizontal_border_strip(k)]) + ....: def mus(k): + ....: return lam.remove_horizontal_border_strip(k) + ....: return h.sum_of_monomials([Partition(mu).conjugate() + ....: for k in range(sum(lam) + 1) + ....: for mu in mus(k)]) sage: f = h.module_morphism(on_basis=map_on_basis, ....: codomain=h) # redefining f sage: f(h[1]) @@ -596,8 +622,8 @@ def induced_graded_map(self, other, f): sage: f(h.one()) h[] sage: grf = h.induced_graded_map(h, f); grf - Generic endomorphism of Symmetric Functions over Rational - Field in the homogeneous basis + Generic endomorphism of + Symmetric Functions over Rational Field in the homogeneous basis sage: grf(h[1]) h[1] sage: grf(h[2]) @@ -643,6 +669,7 @@ def is_homogeneous(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = ModulesWithBasis(ZZ).Filtered().example() sage: x = A(Partition((3,2,1))) sage: y = A(Partition((4,4,1))) @@ -656,6 +683,7 @@ def is_homogeneous(self): Here is an example with a graded algebra:: + sage: # needs sage.combinat sage.modules sage: S = NonCommutativeSymmetricFunctions(QQ).S() sage: (x, y) = (S[2], S[3]) sage: (3*x).is_homogeneous() @@ -701,10 +729,10 @@ def degree_on_basis(self, m): EXAMPLES:: - sage: A = GradedModulesWithBasis(QQ).example() - sage: A.degree_on_basis(Partition((2,1))) + sage: A = GradedModulesWithBasis(QQ).example() # needs sage.combinat sage.modules + sage: A.degree_on_basis(Partition((2,1))) # needs sage.combinat sage.modules 3 - sage: A.degree_on_basis(Partition((4,2,1,1,1,1))) + sage: A.degree_on_basis(Partition((4,2,1,1,1,1))) # needs sage.combinat sage.modules 10 """ @@ -722,6 +750,7 @@ def homogeneous_degree(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = ModulesWithBasis(ZZ).Filtered().example() sage: x = A(Partition((3,2,1))) sage: y = A(Partition((4,4,1))) @@ -737,6 +766,7 @@ def homogeneous_degree(self): An example in a graded algebra:: + sage: # needs sage.combinat sage.modules sage: S = NonCommutativeSymmetricFunctions(QQ).S() sage: (x, y) = (S[2], S[3]) sage: x.homogeneous_degree() @@ -765,8 +795,8 @@ def homogeneous_degree(self): TESTS:: - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S.zero().degree() + sage: S = NonCommutativeSymmetricFunctions(QQ).S() # needs sage.combinat sage.modules + sage: S.zero().degree() # needs sage.combinat sage.modules Traceback (most recent call last): ... ValueError: the zero element does not have a well-defined degree @@ -793,6 +823,7 @@ def maximal_degree(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = ModulesWithBasis(ZZ).Filtered().example() sage: x = A(Partition((3,2,1))) sage: y = A(Partition((4,4,1))) @@ -808,6 +839,7 @@ def maximal_degree(self): Now, we test this on a graded algebra:: + sage: # needs sage.combinat sage.modules sage: S = NonCommutativeSymmetricFunctions(QQ).S() sage: (x, y) = (S[2], S[3]) sage: x.maximal_degree() @@ -819,6 +851,7 @@ def maximal_degree(self): Let us now test a filtered algebra:: + sage: # needs sage.combinat sage.modules sage: A = AlgebrasWithBasis(QQ).Filtered().example() sage: x,y,z = A.algebra_generators() sage: (x*y).maximal_degree() @@ -836,8 +869,8 @@ def maximal_degree(self): TESTS:: - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S.zero().degree() + sage: S = NonCommutativeSymmetricFunctions(QQ).S() # needs sage.combinat sage.modules + sage: S.zero().degree() # needs sage.combinat sage.modules Traceback (most recent call last): ... ValueError: the zero element does not have a well-defined degree @@ -861,6 +894,7 @@ def homogeneous_component(self, n): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = ModulesWithBasis(ZZ).Filtered().example() sage: x = A.an_element(); x 2*P[] + 2*P[1] + 3*P[2] @@ -875,6 +909,7 @@ def homogeneous_component(self, n): sage: x.homogeneous_component(3) 0 + sage: # needs sage.combinat sage.modules sage: A = ModulesWithBasis(ZZ).Graded().example() sage: x = A.an_element(); x 2*P[] + 2*P[1] + 3*P[2] @@ -911,6 +946,7 @@ def homogeneous_component(self, n): Check that this really returns ``A.zero()`` and not a plain ``0``:: + sage: # needs sage.combinat sage.modules sage: A = ModulesWithBasis(ZZ).Filtered().example() sage: x = A.an_element() sage: x.homogeneous_component(3).parent() is A @@ -931,6 +967,7 @@ def truncate(self, n): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = ModulesWithBasis(ZZ).Filtered().example() sage: x = A.an_element(); x 2*P[] + 2*P[1] + 3*P[2] @@ -943,6 +980,7 @@ def truncate(self, n): sage: x.truncate(3) 2*P[] + 2*P[1] + 3*P[2] + sage: # needs sage.combinat sage.modules sage: A = ModulesWithBasis(ZZ).Graded().example() sage: x = A.an_element(); x 2*P[] + 2*P[1] + 3*P[2] @@ -980,6 +1018,7 @@ def truncate(self, n): Check that this really return ``A.zero()`` and not a plain ``0``:: + sage: # needs sage.combinat sage.modules sage: A = ModulesWithBasis(ZZ).Filtered().example() sage: x = A.an_element() sage: x.truncate(0).parent() is A @@ -998,6 +1037,7 @@ def degree_on_basis(self, m): EXAMPLES:: + sage: # needs sage.modules sage: E.<x,y,z> = ExteriorAlgebra(QQ) sage: S = E.submodule([x + y, x*y - y*z, y]) sage: B = S.basis() @@ -1019,6 +1059,7 @@ def degree(self): EXAMPLES:: + sage: # needs sage.modules sage: E.<x,y,z> = ExteriorAlgebra(QQ) sage: S = E.submodule([x + y, x*y - y*z, y]) sage: B = S.basis() @@ -1034,14 +1075,14 @@ def degree(self): The degree of inhomogeneous elements is not defined (following the behavior of the exterior algebra):: - sage: (B[0] + B[2]).degree() + sage: (B[0] + B[2]).degree() # needs sage.modules Traceback (most recent call last): ... ValueError: element is not homogeneous We can still get the maximal degree:: - sage: (B[0] + B[2]).maximal_degree() + sage: (B[0] + B[2]).maximal_degree() # needs sage.modules 2 """ return self.lift().degree() @@ -1059,6 +1100,7 @@ def maximal_degree(self): EXAMPLES:: + sage: # needs sage.modules sage: E.<x,y,z> = ExteriorAlgebra(QQ) sage: F = E.submodule([x + 1, x*y - 1]) sage: B = F.basis() diff --git a/src/sage/categories/finite_complex_reflection_groups.py b/src/sage/categories/finite_complex_reflection_groups.py index 9c91c2af549..3ee374b739c 100644 --- a/src/sage/categories/finite_complex_reflection_groups.py +++ b/src/sage/categories/finite_complex_reflection_groups.py @@ -16,7 +16,6 @@ from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.coxeter_groups import CoxeterGroups -from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet class FiniteComplexReflectionGroups(CategoryWithAxiom): @@ -57,7 +56,7 @@ class FiniteComplexReflectionGroups(CategoryWithAxiom): sage: W = ComplexReflectionGroups().Finite().example(); W # optional - gap3 Reducible real reflection group of rank 4 and type A2 x B2 - sage: W.reflections() # optional - gap3 + sage: W.reflections() # optional - gap3 Finite family {1: (1,8)(2,5)(9,12), 2: (1,5)(2,9)(8,12), 3: (3,10)(4,7)(11,14), 4: (3,6)(4,11)(10,13), 5: (1,9)(2,8)(5,12), 6: (4,14)(6,13)(7,11), @@ -65,7 +64,7 @@ class FiniteComplexReflectionGroups(CategoryWithAxiom): ``W`` is in the category of complex reflection groups:: - sage: W in ComplexReflectionGroups().Finite() # optional - gap3 + sage: W in ComplexReflectionGroups().Finite() # optional - gap3 True """ def example(self): @@ -79,7 +78,7 @@ def example(self): Reducible real reflection group of rank 4 and type A2 x B2 """ from sage.combinat.root_system.reflection_group_real import ReflectionGroup - return ReflectionGroup((1,1,3), (2,1,2)) + return ReflectionGroup((1, 1, 3), (2, 1, 2)) class SubcategoryMethods: @@ -105,14 +104,14 @@ def WellGenerated(self): Here is an example of a finite well-generated complex reflection group:: - sage: W = C.example(); W # optional - gap3 + sage: W = C.example(); W # optional - gap3 Reducible complex reflection group of rank 4 and type A2 x G(3,1,2) All finite Coxeter groups are well generated:: sage: CoxeterGroups().Finite().is_subcategory(C) True - sage: SymmetricGroup(3) in C + sage: SymmetricGroup(3) in C # needs sage.groups True .. NOTE:: @@ -125,8 +124,9 @@ def WellGenerated(self): TESTS:: - sage: TestSuite(W).run() # optional - gap3 - sage: TestSuite(ComplexReflectionGroups().Finite().WellGenerated()).run() # optional - gap3 + sage: TestSuite(W).run() # optional - gap3 + sage: C = ComplexReflectionGroups().Finite().WellGenerated() + sage: TestSuite(C).run() sage: CoxeterGroups().Finite().WellGenerated.__module__ 'sage.categories.finite_complex_reflection_groups' @@ -149,12 +149,12 @@ def degrees(self): EXAMPLES:: - sage: W = ColoredPermutations(1,4) - sage: W.degrees() + sage: W = ColoredPermutations(1,4) # needs sage.combinat + sage: W.degrees() # needs sage.combinat (2, 3, 4) - sage: W = ColoredPermutations(3,3) - sage: W.degrees() + sage: W = ColoredPermutations(3,3) # needs sage.combinat + sage: W.degrees() # needs sage.combinat (3, 6, 9) sage: W = ReflectionGroup(31) # optional - gap3 @@ -171,12 +171,12 @@ def codegrees(self): EXAMPLES:: - sage: W = ColoredPermutations(1,4) - sage: W.codegrees() + sage: W = ColoredPermutations(1,4) # needs sage.combinat + sage: W.codegrees() # needs sage.combinat (2, 1, 0) - sage: W = ColoredPermutations(3,3) - sage: W.codegrees() + sage: W = ColoredPermutations(3,3) # needs sage.combinat + sage: W.codegrees() # needs sage.combinat (6, 3, 0) sage: W = ReflectionGroup(31) # optional - gap3 @@ -199,27 +199,27 @@ def _test_degrees(self, **options): Reducible real reflection group of rank 4 and type A2 x B2 sage: W._test_degrees() # optional - gap3 - sage: W = SymmetricGroup(5) - sage: W._test_degrees() + sage: W = SymmetricGroup(5) # needs sage.groups + sage: W._test_degrees() # needs sage.groups We now break the implementation of W.degrees and check that this is caught:: - sage: W.degrees = lambda: (1/1,5) - sage: W._test_degrees() + sage: W.degrees = lambda: (1/1,5) # needs sage.groups + sage: W._test_degrees() # needs sage.groups Traceback (most recent call last): ... AssertionError: the degrees should be integers - sage: W.degrees = lambda: (1,2,3) - sage: W._test_degrees() + sage: W.degrees = lambda: (1,2,3) # needs sage.groups + sage: W._test_degrees() # needs sage.groups Traceback (most recent call last): ... AssertionError: the degrees should be larger than 2 We restore W to its normal state:: - sage: del W.degrees - sage: W._test_degrees() + sage: del W.degrees # needs sage.groups + sage: W._test_degrees() # needs sage.groups See the documentation for :class:`TestSuite` for more information. """ @@ -254,27 +254,27 @@ def _test_codegrees(self, **options): Reducible real reflection group of rank 4 and type A2 x B2 sage: W._test_codegrees() # optional - gap3 - sage: W = SymmetricGroup(5) - sage: W._test_codegrees() + sage: W = SymmetricGroup(5) # needs sage.groups + sage: W._test_codegrees() # needs sage.groups We now break the implementation of W.degrees and check that this is caught:: - sage: W.codegrees = lambda: (1/1,5) - sage: W._test_codegrees() + sage: W.codegrees = lambda: (1/1,5) # needs sage.groups + sage: W._test_codegrees() # needs sage.groups Traceback (most recent call last): ... AssertionError: the codegrees should be integers - sage: W.codegrees = lambda: (2,1,-1) - sage: W._test_codegrees() + sage: W.codegrees = lambda: (2,1,-1) # needs sage.groups + sage: W._test_codegrees() # needs sage.groups Traceback (most recent call last): ... AssertionError: the codegrees should be nonnegative We restore W to its normal state:: - sage: del W.codegrees - sage: W._test_codegrees() + sage: del W.codegrees # needs sage.groups + sage: W._test_codegrees() # needs sage.groups See the documentation for :class:`TestSuite` for more information. """ @@ -311,6 +311,7 @@ def number_of_reflection_hyperplanes(self): EXAMPLES:: + sage: # needs sage.combinat sage: W = ColoredPermutations(1,3) sage: W.number_of_reflection_hyperplanes() 3 @@ -342,9 +343,11 @@ def number_of_reflections(self): EXAMPLES:: - sage: [SymmetricGroup(i).number_of_reflections() for i in range(int(8))] + sage: [SymmetricGroup(i).number_of_reflections() # needs sage.groups + ....: for i in range(int(8))] [0, 0, 1, 3, 6, 10, 15, 21] + sage: # needs sage.combinat sage.groups sage: W = ColoredPermutations(1,3) sage: W.number_of_reflections() 3 @@ -354,8 +357,8 @@ def number_of_reflections(self): sage: W = ColoredPermutations(4,3) sage: W.number_of_reflections() 21 - sage: W = ReflectionGroup((4,2,3)) # optional - gap3 - sage: W.number_of_reflections() # optional - gap3 + sage: W = ReflectionGroup((4,2,3)) # optional - gap3 + sage: W.number_of_reflections() # optional - gap3 15 """ from sage.rings.integer_ring import ZZ @@ -376,6 +379,7 @@ def rank(self): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: W = ColoredPermutations(1,3) sage: W.rank() 2 @@ -385,8 +389,10 @@ def rank(self): sage: W = ColoredPermutations(4,3) sage: W.rank() 3 - sage: W = ReflectionGroup((4,2,3)) # optional - gap3 - sage: W.rank() # optional - gap3 + + sage: # optional - gap3, needs sage.combinat sage.groups + sage: W = ReflectionGroup((4,2,3)) + sage: W.rank() 3 """ return len(self.degrees()) @@ -400,6 +406,7 @@ def cardinality(self): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage: W = ColoredPermutations(1,3) sage: W.cardinality() 6 @@ -409,14 +416,16 @@ def cardinality(self): sage: W = ColoredPermutations(4,3) sage: W.cardinality() 384 - sage: W = ReflectionGroup((4,2,3)) # optional - gap3 - sage: W.cardinality() # optional - gap3 + + sage: # optional - gap3, needs sage.combinat sage.groups + sage: W = ReflectionGroup((4,2,3)) + sage: W.cardinality() 192 """ from sage.rings.integer_ring import ZZ return ZZ.prod(self.degrees()) - def is_well_generated(self): + def is_well_generated(self) -> bool: r""" Return whether ``self`` is well-generated. @@ -438,20 +447,20 @@ def is_well_generated(self): EXAMPLES:: - sage: W = ColoredPermutations(1,3) - sage: W.is_well_generated() + sage: W = ColoredPermutations(1,3) # needs sage.combinat + sage: W.is_well_generated() # needs sage.combinat True - sage: W = ColoredPermutations(4,3) - sage: W.is_well_generated() + sage: W = ColoredPermutations(4,3) # needs sage.combinat + sage: W.is_well_generated() # needs sage.combinat True - sage: W = ReflectionGroup((4,2,3)) # optional - gap3 - sage: W.is_well_generated() # optional - gap3 + sage: # optional - gap3, needs sage.combinat sage.groups + sage: W = ReflectionGroup((4,2,3)) + sage: W.is_well_generated() False - - sage: W = ReflectionGroup((4,4,3)) # optional - gap3 - sage: W.is_well_generated() # optional - gap3 + sage: W = ReflectionGroup((4,4,3)) + sage: W.is_well_generated() True """ return self.number_of_simple_reflections() == self.rank() @@ -473,12 +482,12 @@ def is_real(self): EXAMPLES:: - sage: W = ColoredPermutations(1,3) - sage: W.is_real() + sage: W = ColoredPermutations(1,3) # needs sage.combinat + sage: W.is_real() # needs sage.combinat True - sage: W = ColoredPermutations(4,3) - sage: W.is_real() + sage: W = ColoredPermutations(4,3) # needs sage.combinat + sage: W.is_real() # needs sage.combinat sage.groups False .. TODO:: @@ -502,30 +511,131 @@ def base_change_matrix(self): EXAMPLES:: - sage: W = ReflectionGroup((1,1,3)) # optional - gap3 - sage: W.base_change_matrix() # optional - gap3 + sage: W = ReflectionGroup((1,1,3)) # optional - gap3 + sage: W.base_change_matrix() # optional - gap3 [1 0] [0 1] - sage: W = ReflectionGroup(23) # optional - gap3 - sage: W.base_change_matrix() # optional - gap3 + sage: W = ReflectionGroup(23) # optional - gap3 + sage: W.base_change_matrix() # optional - gap3 [1 0 0] [0 1 0] [0 0 1] - sage: W = ReflectionGroup((3,1,2)) # optional - gap3 - sage: W.base_change_matrix() # optional - gap3 + sage: W = ReflectionGroup((3,1,2)) # optional - gap3 + sage: W.base_change_matrix() # optional - gap3 [1 0] [1 1] - sage: W = ReflectionGroup((4,2,2)) # optional - gap3 - sage: W.base_change_matrix() # optional - gap3 + sage: W = ReflectionGroup((4,2,2)) # optional - gap3 + sage: W.base_change_matrix() # optional - gap3 [ 1 0] [E(4) 1] """ - from sage.matrix.all import Matrix + from sage.matrix.constructor import Matrix return Matrix(list(self.independent_roots())).inverse() + def milnor_fiber_poset(self): + r""" + Return the Milnor fiber poset of ``self``. + + The *Milnor fiber poset* of a finite complex reflection group `W` + is defined as the poset of (right) standard cosets `gW_J`, + where `J` is a subset of the index set `I` of `W`, ordered + by reverse inclusion. This is conjecturally a meet semilattice + if and only if `W` is well-generated. + + EXAMPLES:: + + sage: W = ColoredPermutations(3, 2) + sage: P = W.milnor_fiber_poset() + sage: P + Finite meet-semilattice containing 34 elements + sage: R.<x> = ZZ[] + sage: sum(x**P.rank(elt) for elt in P) + 18*x^2 + 15*x + 1 + + sage: W = ReflectionGroup(4) # optional - gap3 + sage: P = W.milnor_fiber_poset() # optional - gap3 + sage: P # optional - gap3 + Finite meet-semilattice containing 41 elements + sage: sum(x**P.rank(elt) for elt in P) # optional - gap3 + 24*x^2 + 16*x + 1 + + sage: W = ReflectionGroup([4,2,2]) # optional - gap3 + sage: W.is_well_generated() # optional - gap3 + False + sage: P = W.milnor_fiber_poset() # optional - gap3 + sage: P # optional - gap3 + Finite poset containing 47 elements + sage: sum(x**P.rank(elt) for elt in P) # optional - gap3 + 16*x^3 + 24*x^2 + 6*x + 1 + sage: P.is_meet_semilattice() # optional - gap3 + False + """ + I = self.index_set() + data = {} + next_reprs = {(): [g for g in self]} + next_cosets = {(): [frozenset([g]) for g in next_reprs[()]]} + next_level = set((i, ()) for i in range(len(next_cosets[()]))) + while next_level: + cur = next_level + cosets = next_cosets + reprs = next_reprs + next_level = set() + next_cosets = {} + next_reprs = {} + for Y in cur: + index, J = Y + for i in I: + if i in J: + continue + Jp = tuple(sorted(J + (i,))) + # See if the coset is already there + found_coset = False + if Jp in next_cosets: + rep = reprs[J][index] + for ii, C in enumerate(next_cosets[Jp]): + if rep in C: + found_coset = True + Yp = (reprs[J][index], J) + Xp = (next_reprs[Jp][ii], Jp) + if Xp in data: + data[Xp].append(Yp) + else: + data[Xp] = [Yp] + else: + next_cosets[Jp] = [] + next_reprs[Jp] = [] + if found_coset: + continue + + # Otherwise build the coset + next_level.add((len(next_cosets[Jp]), Jp)) + H = set(cosets[J][index]) + to_test = [(g, i) for g in H] + while to_test: + g, j = to_test.pop() + gp = g.apply_simple_reflection(j, side='right') + if gp in H: + continue + H.add(gp) + to_test.extend((gp, j) for j in Jp) + rep = min(H, key=lambda g: g.length()) + next_cosets[Jp].append(frozenset(H)) + next_reprs[Jp].append(rep) + Yp = (reprs[J][index], J) + Xp = (rep, Jp) + if Xp in data: + data[Xp].append(Yp) + else: + data[Xp] = [Yp] + if self.is_well_generated(): + from sage.combinat.posets.lattices import MeetSemilattice + return MeetSemilattice(data) + from sage.combinat.posets.posets import Poset + return Poset(data) + class ElementMethods: @abstract_method(optional=True) @@ -543,8 +653,8 @@ def to_matrix(self): [0 1], [ 0 -1], [ 1 1], [ 1 0], [-1 -1], [-1 0] ] - sage: W = ColoredPermutations(1,3) - sage: [t.to_matrix() for t in W] + sage: W = ColoredPermutations(1,3) # needs sage.combinat + sage: [t.to_matrix() for t in W] # needs sage.combinat sage.groups [ [1 0 0] [1 0 0] [0 1 0] [0 0 1] [0 1 0] [0 0 1] [0 1 0] [0 0 1] [1 0 0] [1 0 0] [0 0 1] [0 1 0] @@ -554,8 +664,8 @@ def to_matrix(self): A different representation is given by the colored permutations:: - sage: W = ColoredPermutations(3, 1) - sage: [t.to_matrix() for t in W] + sage: W = ColoredPermutations(3, 1) # needs sage.combinat + sage: [t.to_matrix() for t in W] # needs sage.combinat sage.groups [[1], [zeta3], [-zeta3 - 1]] """ @@ -581,9 +691,9 @@ def character_value(self): EXAMPLES:: - sage: W = ColoredPermutations(1,3); W + sage: W = ColoredPermutations(1,3); W # needs sage.combinat 1-colored permutations of size 3 - sage: [t.character_value() for t in W] + sage: [t.character_value() for t in W] # needs sage.combinat sage.groups [3, 1, 1, 0, 0, 1] Note that this could be a different (faithful) @@ -595,14 +705,14 @@ def character_value(self): sage: [t.character_value() for t in W] # optional - gap3 [2, 0, 0, -1, -1, 0] - sage: W = ColoredPermutations(2,2); W + sage: W = ColoredPermutations(2,2); W # needs sage.combinat 2-colored permutations of size 2 - sage: [t.character_value() for t in W] + sage: [t.character_value() for t in W] # needs sage.combinat sage.groups [2, 0, 0, -2, 0, 0, 0, 0] - sage: W = ColoredPermutations(3,1); W + sage: W = ColoredPermutations(3,1); W # needs sage.combinat 3-colored permutations of size 1 - sage: [t.character_value() for t in W] + sage: [t.character_value() for t in W] # needs sage.combinat sage.groups [1, zeta3, -zeta3 - 1] """ return self.to_matrix().trace() @@ -623,20 +733,20 @@ def reflection_length(self, in_unitary_group=False): EXAMPLES:: - sage: W = ReflectionGroup((1,1,3)) # optional - gap3 - sage: sorted([t.reflection_length() for t in W]) # optional - gap3 + sage: W = ReflectionGroup((1,1,3)) # optional - gap3 + sage: sorted([t.reflection_length() for t in W]) # optional - gap3 [0, 1, 1, 1, 2, 2] - sage: W = ReflectionGroup((2,1,2)) # optional - gap3 - sage: sorted([t.reflection_length() for t in W]) # optional - gap3 + sage: W = ReflectionGroup((2,1,2)) # optional - gap3 + sage: sorted([t.reflection_length() for t in W]) # optional - gap3 [0, 1, 1, 1, 1, 2, 2, 2] - sage: W = ReflectionGroup((2,2,2)) # optional - gap3 - sage: sorted([t.reflection_length() for t in W]) # optional - gap3 + sage: W = ReflectionGroup((2,2,2)) # optional - gap3 + sage: sorted([t.reflection_length() for t in W]) # optional - gap3 [0, 1, 1, 2] - sage: W = ReflectionGroup((3,1,2)) # optional - gap3 - sage: sorted([t.reflection_length() for t in W]) # optional - gap3 + sage: W = ReflectionGroup((3,1,2)) # optional - gap3 + sage: sorted([t.reflection_length() for t in W]) # optional - gap3 [0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] """ W = self.parent() @@ -656,11 +766,12 @@ def example(self): EXAMPLES:: sage: from sage.categories.complex_reflection_groups import ComplexReflectionGroups - sage: ComplexReflectionGroups().Finite().Irreducible().example() # optional - gap3 + sage: C = ComplexReflectionGroups().Finite().Irreducible() + sage: C.example() # optional - gap3 Irreducible complex reflection group of rank 3 and type G(4,2,3) """ from sage.combinat.root_system.reflection_group_real import ReflectionGroup - return ReflectionGroup((4,2,3)) + return ReflectionGroup((4, 2, 3)) class ParentMethods: def coxeter_number(self): @@ -734,23 +845,26 @@ def absolute_order_ideal(self, gens=None, EXAMPLES:: - sage: W = ReflectionGroup((1,1,3)) # optional - gap3 + sage: W = ReflectionGroup((1,1,3)) # optional - gap3 - sage: sorted( w.reduced_word() for w in W.absolute_order_ideal() ) # optional - gap3 + sage: sorted(w.reduced_word() # optional - gap3 + ....: for w in W.absolute_order_ideal()) [[], [1], [1, 2], [1, 2, 1], [2]] - sage: sorted( w.reduced_word() for w in W.absolute_order_ideal(W.from_reduced_word([2,1])) ) # optional - gap3 + sage: sorted(w.reduced_word() # optional - gap3 + ....: for w in W.absolute_order_ideal(W.from_reduced_word([2,1]))) [[], [1], [1, 2, 1], [2], [2, 1]] - sage: sorted( w.reduced_word() for w in W.absolute_order_ideal(W.from_reduced_word([2])) ) # optional - gap3 + sage: sorted(w.reduced_word() # optional - gap3 + ....: for w in W.absolute_order_ideal(W.from_reduced_word([2]))) [[], [2]] - sage: W = CoxeterGroup(['A', 3]) - sage: len(list(W.absolute_order_ideal())) + sage: W = CoxeterGroup(['A', 3]) # needs sage.combinat sage.groups + sage: len(list(W.absolute_order_ideal())) # needs sage.combinat sage.groups 14 - sage: W = CoxeterGroup(['A', 2]) - sage: for (w, l) in W.absolute_order_ideal(return_lengths=True): + sage: W = CoxeterGroup(['A', 2]) # needs sage.combinat sage.groups + sage: for (w, l) in W.absolute_order_ideal(return_lengths=True): # needs sage.combinat sage.groups ....: print(w.reduced_word(), l) [1, 2] 2 [1, 2, 1] 1 @@ -758,6 +872,8 @@ def absolute_order_ideal(self, gens=None, [1] 1 [] 0 """ + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + if gens is None: seeds = [(self.coxeter_element(), self.rank())] else: @@ -780,27 +896,8 @@ def succ(seed): structure='graded', enumeration='breadth') if return_lengths: - return (x for x in step) - else: - return (x[0] for x in step) - - def elements_below_coxeter_element(self, c=None): - r""" - Deprecated method. - - Superseded by :meth:`absolute_order_ideal` - - TESTS:: - - sage: W = CoxeterGroup(['A', 3]) - sage: len(list(W.elements_below_coxeter_element())) - doctest:...: DeprecationWarning: The method elements_below_coxeter_element is deprecated. Please use absolute_order_ideal instead. - See https://github.com/sagemath/sage/issues/27924 for details. - 14 - """ - from sage.misc.superseded import deprecation - deprecation(27924, "The method elements_below_coxeter_element is deprecated. Please use absolute_order_ideal instead.") - return self.absolute_order_ideal(gens=c) + return step + return (x[0] for x in step) # TODO: have a cached and an uncached version @cached_method @@ -834,26 +931,32 @@ def noncrossing_partition_lattice(self, c=None, L=None, EXAMPLES:: - sage: W = SymmetricGroup(4) - sage: W.noncrossing_partition_lattice() + sage: W = SymmetricGroup(4) # needs sage.combinat sage.groups + sage: W.noncrossing_partition_lattice() # needs sage.combinat sage.groups Finite lattice containing 14 elements - sage: W = WeylGroup(['G', 2]) - sage: W.noncrossing_partition_lattice() + sage: W = WeylGroup(['G', 2]) # needs sage.combinat sage.groups + sage: W.noncrossing_partition_lattice() # needs sage.combinat sage.groups Finite lattice containing 8 elements - sage: W = ReflectionGroup((1,1,3)) # optional - gap3 + sage: W = ReflectionGroup((1,1,3)) # optional - gap3 - sage: sorted( w.reduced_word() for w in W.noncrossing_partition_lattice() ) # optional - gap3 + sage: sorted(w.reduced_word() # optional - gap3 + ....: for w in W.noncrossing_partition_lattice()) [[], [1], [1, 2], [1, 2, 1], [2]] - sage: sorted( w.reduced_word() for w in W.noncrossing_partition_lattice(W.from_reduced_word([2,1])) ) # optional - gap3 + sage: c21 = W.from_reduced_word([2,1]) # optional - gap3 + sage: sorted(w.reduced_word() # optional - gap3 + ....: for w in W.noncrossing_partition_lattice(c21)) [[], [1], [1, 2, 1], [2], [2, 1]] - sage: sorted( w.reduced_word() for w in W.noncrossing_partition_lattice(W.from_reduced_word([2])) ) # optional - gap3 + sage: c2 = W.from_reduced_word([2]) # optional - gap3 + sage: sorted(w.reduced_word() # optional - gap3 + ....: for w in W.noncrossing_partition_lattice(c2)) [[], [2]] """ - from sage.combinat.posets.all import Poset, LatticePoset + from sage.combinat.posets.posets import Poset + from sage.combinat.posets.lattices import LatticePoset R = self.reflections() if L is None: @@ -863,11 +966,11 @@ def noncrossing_partition_lattice(self, c=None, L=None, else: L = [(pi, pi.reflection_length()) for pi in L] rels = [] - ref_lens = {pi:l for (pi, l) in L} + ref_lens = {pi: l for (pi, l) in L} for (pi, l) in L: for t in R: tau = pi * t - if tau in ref_lens and l+1 == ref_lens[tau]: + if tau in ref_lens and l + 1 == ref_lens[tau]: rels.append((pi, tau)) P = Poset(([], rels), cover_relations=True, facade=True) @@ -897,8 +1000,9 @@ def generalized_noncrossing_partitions(self, m, c=None, positive=False): sage: W = ReflectionGroup((1,1,3)) # optional - gap3 + sage: chains = W.generalized_noncrossing_partitions(2) # optional - gap3 sage: sorted([w.reduced_word() for w in chain] # optional - gap3 - ....: for chain in W.generalized_noncrossing_partitions(2)) # optional - gap3 + ....: for chain in chains) [[[], [], [1, 2]], [[], [1], [2]], [[], [1, 2], []], @@ -912,8 +1016,10 @@ def generalized_noncrossing_partitions(self, m, c=None, positive=False): [[2], [], [1, 2, 1]], [[2], [1, 2, 1], []]] + sage: chains = W.generalized_noncrossing_partitions(2, # optional - gap3 + ....: positive=True) sage: sorted([w.reduced_word() for w in chain] # optional - gap3 - ....: for chain in W.generalized_noncrossing_partitions(2, positive=True)) # optional - gap3 + ....: for chain in chains) [[[], [1, 2], []], [[], [1, 2, 1], [1]], [[1], [2], []], @@ -985,8 +1091,9 @@ def absolute_poset(self, in_unitary_group=False): TESTS:: - sage: W1 = CoxeterGroup(['A',2]) - sage: W2 = WeylGroup(['A',2]) + sage: # needs sage.combinat sage.groups + sage: W1 = CoxeterGroup(['A', 2]) + sage: W2 = WeylGroup(['A', 2]) sage: W3 = SymmetricGroup(3) sage: W1.absolute_poset() Finite poset containing 6 elements @@ -1006,11 +1113,12 @@ def example(self): EXAMPLES:: sage: from sage.categories.complex_reflection_groups import ComplexReflectionGroups - sage: ComplexReflectionGroups().Finite().WellGenerated().example() # optional - gap3 + sage: C = ComplexReflectionGroups().Finite().WellGenerated() + sage: C.example() # optional - gap3 Reducible complex reflection group of rank 4 and type A2 x G(3,1,2) """ from sage.combinat.root_system.reflection_group_real import ReflectionGroup - return ReflectionGroup((1,1,3), (3,1,2)) + return ReflectionGroup((1, 1, 3), (3, 1, 2)) class ParentMethods: def _test_well_generated(self, **options): @@ -1060,15 +1168,71 @@ def coxeter_elements(self): EXAMPLES:: sage: W = ReflectionGroup((1,1,3)) # optional - gap3 - sage: sorted(c.reduced_word() for c in W.coxeter_elements()) # optional - gap3 + sage: sorted(c.reduced_word() # optional - gap3 + ....: for c in W.coxeter_elements()) [[1, 2], [2, 1]] sage: W = ReflectionGroup((1,1,4)) # optional - gap3 - sage: sorted(c.reduced_word() for c in W.coxeter_elements()) # optional - gap3 - [[1, 2, 1, 3, 2], [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 1, 3, 2, 1], [3, 2, 1]] + sage: sorted(c.reduced_word() # optional - gap3 + ....: for c in W.coxeter_elements()) + [[1, 2, 1, 3, 2], [1, 2, 3], [1, 3, 2], + [2, 1, 3], [2, 1, 3, 2, 1], [3, 2, 1]] """ return self.coxeter_element().conjugacy_class() + def milnor_fiber_complex(self): + r""" + Return the Milnor fiber complex of ``self``. + + The *Milnor fiber complex* of a finite well-generated + complex reflection group `W` is the simplicial complex whose + face poset is given by :meth:`milnor_fiber_poset`. When `W` + is an irreducible Shephard group, it is also an equivariant + strong deformation retract of the Milnor fiber `f_1^{-1}(1)`, + where `f_1: V \to \CC` is the polynomial invariant of smallest + degree acting on the reflection representation `V`. + + When `W` is a Coxeter group, this is isomorphic to the + :wikipedia:`Coxeter complex <Coxeter_complex>` of `W`. + + EXAMPLES:: + + sage: W = ColoredPermutations(3, 2) + sage: C = W.milnor_fiber_complex() + sage: C.homology() + {0: 0, 1: Z x Z x Z x Z} + + sage: W = ReflectionGroup(5) # optional - gap3 + sage: C = W.milnor_fiber_complex() # optional - gap3 + sage: C.homology() # optional - gap3 + {0: 0, 1: Z^25} + """ + I = self.index_set() + cosets = {} + for i in I: + Ip = tuple([j for j in I if j != i]) + cosets[Ip] = [] + for g in self: + if any(g in C for C in cosets[Ip]): + continue + H = set([g]) + to_test = [(g, j) for j in Ip] + while to_test: + h, j = to_test.pop() + hp = h.apply_simple_reflection(j, side='right') + if hp in H: + continue + H.add(hp) + to_test.extend((hp, j) for j in Ip) + cosets[Ip].append(frozenset(H)) + verts = {} + for Ip in cosets: + for C in cosets[Ip]: + verts[C, Ip] = len(verts) + facets = [[verts[k] for k in verts if g in k[0]] for g in self] + from sage.topology.simplicial_complex import SimplicialComplex + return SimplicialComplex(facets) + class Irreducible(CategoryWithAxiom): r""" The category of finite irreducible well-generated @@ -1082,7 +1246,8 @@ def example(self): EXAMPLES:: sage: from sage.categories.complex_reflection_groups import ComplexReflectionGroups - sage: ComplexReflectionGroups().Finite().WellGenerated().Irreducible().example() + sage: C = ComplexReflectionGroups().Finite().WellGenerated().Irreducible() + sage: C.example() # needs sage.combinat 4-colored permutations of size 3 """ from sage.combinat.colored_permutations import ColoredPermutations @@ -1107,12 +1272,12 @@ def coxeter_number(self): EXAMPLES:: - sage: W = ColoredPermutations(1,3) - sage: W.coxeter_number() + sage: W = ColoredPermutations(1,3) # needs sage.combinat + sage: W.coxeter_number() # needs sage.combinat 3 - sage: W = ColoredPermutations(4,3) - sage: W.coxeter_number() + sage: W = ColoredPermutations(4,3) # needs sage.combinat + sage: W.coxeter_number() # needs sage.combinat 12 sage: W = ReflectionGroup((4,4,3)) # optional - gap3 @@ -1132,16 +1297,16 @@ def number_of_reflections_of_full_support(self): sage: W.number_of_reflections_of_full_support() 1 - sage: W = ColoredPermutations(1,4) + sage: W = ColoredPermutations(1,4) # needs sage.combinat sage: W.number_of_reflections_of_full_support() 1 - sage: W = CoxeterGroup("B3") - sage: W.number_of_reflections_of_full_support() + sage: W = CoxeterGroup("B3") # needs sage.combinat sage.groups + sage: W.number_of_reflections_of_full_support() # needs sage.combinat sage.groups 3 - sage: W = ColoredPermutations(3,3) - sage: W.number_of_reflections_of_full_support() + sage: W = ColoredPermutations(3,3) # needs sage.combinat + sage: W.number_of_reflections_of_full_support() # needs sage.combinat 3 """ n = self.rank() @@ -1173,25 +1338,25 @@ def rational_catalan_number(self, p, polynomial=False): EXAMPLES:: - sage: W = ColoredPermutations(1,3) - sage: [W.rational_catalan_number(p) for p in [5,7,8]] + sage: W = ColoredPermutations(1,3) # needs sage.combinat + sage: [W.rational_catalan_number(p) for p in [5,7,8]] # needs sage.combinat [7, 12, 15] - sage: W = ColoredPermutations(2,2) - sage: [W.rational_catalan_number(p) for p in [7,9,11]] + sage: W = ColoredPermutations(2,2) # needs sage.combinat + sage: [W.rational_catalan_number(p) for p in [7,9,11]] # needs sage.combinat [10, 15, 21] TESTS:: - sage: W = ColoredPermutations(1,4) - sage: W.rational_catalan_number(3, polynomial=True) + sage: W = ColoredPermutations(1,4) # needs sage.combinat + sage: W.rational_catalan_number(3, polynomial=True) # needs sage.combinat q^6 + q^4 + q^3 + q^2 + 1 """ - from sage.arith.all import gcd + from sage.arith.misc import GCD as gcd from sage.combinat.q_analogues import q_int h = self.coxeter_number() - if not gcd(h,p) == 1: + if not gcd(h, p) == 1: raise ValueError("parameter p = %s is not coprime to the Coxeter number %s" % (p, h)) if polynomial: @@ -1241,37 +1406,38 @@ def fuss_catalan_number(self, m, positive=False, EXAMPLES:: - sage: W = ColoredPermutations(1,3) - sage: [W.fuss_catalan_number(i) for i in [1,2,3]] + sage: W = ColoredPermutations(1,3) # needs sage.combinat + sage: [W.fuss_catalan_number(i) for i in [1,2,3]] # needs sage.combinat [5, 12, 22] - sage: W = ColoredPermutations(1,4) - sage: [W.fuss_catalan_number(i) for i in [1,2,3]] + sage: W = ColoredPermutations(1,4) # needs sage.combinat + sage: [W.fuss_catalan_number(i) for i in [1,2,3]] # needs sage.combinat [14, 55, 140] - sage: W = ColoredPermutations(1,5) - sage: [W.fuss_catalan_number(i) for i in [1,2,3]] + sage: W = ColoredPermutations(1,5) # needs sage.combinat + sage: [W.fuss_catalan_number(i) for i in [1,2,3]] # needs sage.combinat [42, 273, 969] - sage: W = ColoredPermutations(2,2) - sage: [W.fuss_catalan_number(i) for i in [1,2,3]] + sage: W = ColoredPermutations(2,2) # needs sage.combinat + sage: [W.fuss_catalan_number(i) for i in [1,2,3]] # needs sage.combinat [6, 15, 28] - sage: W = ColoredPermutations(2,3) - sage: [W.fuss_catalan_number(i) for i in [1,2,3]] + sage: W = ColoredPermutations(2,3) # needs sage.combinat + sage: [W.fuss_catalan_number(i) for i in [1,2,3]] # needs sage.combinat [20, 84, 220] - sage: W = ColoredPermutations(2,4) - sage: [W.fuss_catalan_number(i) for i in [1,2,3]] + sage: W = ColoredPermutations(2,4) # needs sage.combinat + sage: [W.fuss_catalan_number(i) for i in [1,2,3]] # needs sage.combinat [70, 495, 1820] TESTS:: + sage: # needs sage.combinat sage.groups sage: W = ColoredPermutations(2,4) - sage: W.fuss_catalan_number(2,positive=True) + sage: W.fuss_catalan_number(2, positive=True) 330 sage: W = ColoredPermutations(2,2) - sage: W.fuss_catalan_number(2,polynomial=True) + sage: W.fuss_catalan_number(2, polynomial=True) q^16 + q^14 + 2*q^12 + 2*q^10 + 3*q^8 + 2*q^6 + 2*q^4 + q^2 + 1 """ @@ -1315,17 +1481,21 @@ def catalan_number(self, positive=False, polynomial=False): EXAMPLES:: - sage: [ColoredPermutations(1,n).catalan_number() for n in [3,4,5]] + sage: [ColoredPermutations(1,n).catalan_number() # needs sage.combinat + ....: for n in [3,4,5]] [5, 14, 42] - sage: [ColoredPermutations(2,n).catalan_number() for n in [3,4,5]] + sage: [ColoredPermutations(2,n).catalan_number() # needs sage.combinat + ....: for n in [3,4,5]] [20, 70, 252] - sage: [ReflectionGroup((2,2,n)).catalan_number() for n in [3,4,5]] # optional - gap3 + sage: [ReflectionGroup((2,2,n)).catalan_number() # optional - gap3 + ....: for n in [3,4,5]] [14, 50, 182] TESTS:: + sage: # needs sage.combinat sage.groups sage: W = ColoredPermutations(3,6) sage: W.catalan_number(positive=True) 462 diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 270341c2262..3459135c9c0 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.groups r""" Finite Coxeter Groups """ @@ -9,6 +10,8 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** +import sage.rings.abc + from sage.misc.cachefunc import cached_method, cached_in_parent_method from sage.misc.lazy_attribute import lazy_attribute from sage.categories.category_with_axiom import CategoryWithAxiom @@ -354,7 +357,7 @@ def degrees_of_irreducible_component(I): c = self.prod(s[i] for i in I) roots = c.matrix().change_ring(QQbar).charpoly().roots() args = ((z.rational_argument(), m) for z, m in roots) - args = [(z if z >=0 else 1 + z, m) for z, m in args] + args = [(z if z >= 0 else 1 + z, m) for z, m in args] h = max(z.denominator() for z, m in args) return tuple(sorted(ZZ(z * h + 1) for z, m in args if z @@ -745,15 +748,161 @@ def permutahedron(self, point=None, base_ring=None): from sage.rings.integer_ring import ZZ point = [ZZ.one()] * n v = sum(point[i-1] * weights[i] for i in weights.keys()) - from sage.geometry.polyhedron.constructor import Polyhedron - from sage.rings.qqbar import AA, QQbar - from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField vertices = [v*w for w in self] - if base_ring is None and v.base_ring() in [UniversalCyclotomicField(), QQbar]: - vertices = [v.change_ring(AA) for v in vertices] - base_ring = AA + if base_ring is None: + if isinstance(v.base_ring(), (sage.rings.abc.UniversalCyclotomicField, + sage.rings.abc.AlgebraicField_common)): + from sage.rings.qqbar import AA + vertices = [v.change_ring(AA) for v in vertices] + base_ring = AA + from sage.geometry.polyhedron.constructor import Polyhedron return Polyhedron(vertices=vertices, base_ring=base_ring) + def coxeter_poset(self): + r""" + Return the Coxeter poset of ``self``. + + Let `W` be a Coxeter group. The *Coxeter poset* is defined as + the set of (right) standard cosets `gW_J`, where `J` is a + subset of the index set `I` of `W`, ordered by reverse inclusion. + + This is equal to the face poset of the :meth:`Coxeter complex + <coxeter_complex()>`. + + EXAMPLES:: + + sage: W = CoxeterGroup(['A', 3]) + sage: P = W.coxeter_poset() + sage: P + Finite meet-semilattice containing 75 elements + sage: P.rank() + 3 + + sage: W = WeylGroup(['B', 3]) + sage: P = W.coxeter_poset() + sage: P + Finite meet-semilattice containing 147 elements + sage: P.rank() + 3 + + sage: W = CoxeterGroup(['I', 7]) + sage: P = W.coxeter_poset() + sage: P + Finite meet-semilattice containing 29 elements + sage: P.rank() + 2 + + sage: W = CoxeterGroup(['H', 3]) + sage: P = W.coxeter_poset() + sage: P + Finite meet-semilattice containing 363 elements + sage: P.rank() + 3 + + sage: W = CoxeterGroup(['H', 3], implementation="permutation") # optional - gap3 + sage: P = W.coxeter_poset() # optional - gap3 + sage: P # optional - gap3 + Finite meet-semilattice containing 363 elements + sage: P.rank() # optional - gap3 + 3 + """ + I = self.index_set() + data = {} + next_level = set((g, ()) for g in self) + while next_level: + cur = next_level + next_level = set() + for Y in cur: + g, J = Y + for i in I: + if i in J: + continue + Jp = tuple(sorted(J + (i,))) + gp = g.coset_representative(Jp, side='right') + X = (gp, Jp) + if X in data: + data[X].append(Y) + else: + data[X] = [Y] + next_level.add(X) + from sage.combinat.posets.lattices import MeetSemilattice + return MeetSemilattice(data) + + def coxeter_complex(self): + r""" + Return the Coxeter complex of ``self``. + + Let `W` be a Coxeter group, and let `X` be the corresponding Tits + cone, which is constructed as the `W` orbit of the fundamental + chamber in the reflection representation. The *Coxeter complex* + of `W` is the simplicial complex `(X \setminus \{0\}) / \RR_{>0}`. + The face poset of this simplicial complex is given by the + :meth:`coxeter_poset()`. When `W` is a finite group, then the + Coxeter complex is homeomorphic to an `(n-1)`-dimensional sphere, + where `n` is the rank of `W`. + + EXAMPLES:: + + sage: W = CoxeterGroup(['A', 3]) + sage: C = W.coxeter_complex() + sage: C + Simplicial complex with 14 vertices and 24 facets + sage: C.homology() + {0: 0, 1: 0, 2: Z} + + sage: W = WeylGroup(['B', 3]) + sage: C = W.coxeter_complex() + sage: C + Simplicial complex with 26 vertices and 48 facets + sage: C.homology() + {0: 0, 1: 0, 2: Z} + + sage: W = CoxeterGroup(['I', 7]) + sage: C = W.coxeter_complex() + sage: C + Simplicial complex with 14 vertices and 14 facets + sage: C.homology() + {0: 0, 1: Z} + + sage: W = CoxeterGroup(['H', 3]) + sage: C = W.coxeter_complex() + sage: C + Simplicial complex with 62 vertices and 120 facets + sage: C.homology() + {0: 0, 1: 0, 2: Z} + + sage: W = CoxeterGroup(['H', 3], implementation="permutation") # optional - gap3 + sage: C = W.coxeter_complex() # optional - gap3 + sage: C # optional - gap3 + Simplicial complex with 62 vertices and 120 facets + sage: C.homology() # optional - gap3 + {0: 0, 1: 0, 2: Z} + """ + I = self.index_set() + facets = {} + Ip = {i: tuple([j for j in I if j != i]) for i in I} + for g in self: + V = [] + for i in I: + gp = g + D = gp.descents(side='right') + if D and D[0] == i: + D.pop(0) + while D: + gp = gp.apply_simple_reflection(D[0]) + D = gp.descents(side='right') + if D and D[0] == i: + D.pop(0) + V.append((gp, Ip[i])) + facets[g] = V + verts = set() + for F in facets.values(): + verts.update(F) + labels = {x: i for i,x in enumerate(verts)} + result = [[labels[v] for v in F] for F in facets.values()] + from sage.topology.simplicial_complex import SimplicialComplex + return SimplicialComplex(result) + class ElementMethods: @cached_in_parent_method @@ -843,11 +992,11 @@ def coxeter_knuth_neighbor(self, w): v[i] = w[i-1] v[i-1] = w[i] d += [tuple(v)] - elif w[i-1]<w[i-2] and w[i-2]<w[i]: + elif w[i-1] < w[i-2] and w[i-2] < w[i]: v[i] = w[i-1] v[i-1] = w[i] d += [tuple(v)] - elif w[i-2]<w[i] and w[i]<w[i-1]: + elif w[i-2] < w[i] and w[i] < w[i-1]: v[i-2] = w[i-1] v[i-1] = w[i-2] d += [tuple(v)] diff --git a/src/sage/categories/finite_crystals.py b/src/sage/categories/finite_crystals.py index 072df1f9c53..4d5fdda550d 100644 --- a/src/sage/categories/finite_crystals.py +++ b/src/sage/categories/finite_crystals.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.graphs r""" Finite Crystals """ diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 6d2a713ece1..b8ed6332ead 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -44,13 +44,14 @@ class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): sage: C.super_categories() [Category of algebras with basis over Rational Field, Category of finite dimensional magmatic algebras with basis over Rational Field] - sage: C.example() + sage: C.example() # needs sage.modules An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field TESTS:: + sage: # needs sage.graphs sage.modules sage: TestSuite(C).run() sage: C is Algebras(QQ).FiniteDimensional().WithBasis() True @@ -80,6 +81,7 @@ def radical_basis(self): EXAMPLES:: + sage: # needs sage.graphs sage.modules sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver @@ -90,29 +92,29 @@ def radical_basis(self): We construct the group algebra of the Klein Four-Group over the rationals:: - sage: A = KleinFourGroup().algebra(QQ) + sage: A = KleinFourGroup().algebra(QQ) # needs sage.groups sage.modules This algebra belongs to the category of finite dimensional algebras over the rationals:: - sage: A in Algebras(QQ).FiniteDimensional().WithBasis() + sage: A in Algebras(QQ).FiniteDimensional().WithBasis() # needs sage.groups sage.modules True Since the field has characteristic `0`, Maschke's Theorem tells us that the group algebra is semisimple. So its radical is the zero ideal:: - sage: A in Algebras(QQ).Semisimple() + sage: A in Algebras(QQ).Semisimple() # needs sage.groups sage.modules True - sage: A.radical_basis() + sage: A.radical_basis() # needs sage.groups sage.modules () Let's work instead over a field of characteristic `2`:: - sage: A = KleinFourGroup().algebra(GF(2)) - sage: A in Algebras(GF(2)).Semisimple() + sage: A = KleinFourGroup().algebra(GF(2)) # needs sage.groups sage.modules + sage: A in Algebras(GF(2)).Semisimple() # needs sage.groups sage.modules False - sage: A.radical_basis() + sage: A.radical_basis() # needs sage.groups sage.modules (() + (1,2)(3,4), (3,4) + (1,2)(3,4), (1,2) + (1,2)(3,4)) We now implement the algebra `A = K[x] / (x^p-1)`, where `K` @@ -120,6 +122,7 @@ def radical_basis(self): radical; alas, we currently need to wrap `A` to make it a proper :class:`ModulesWithBasis`:: + sage: # needs sage.modules sage: class AnAlgebra(CombinatorialFreeModule): ....: def __init__(self, F): ....: R.<x> = PolynomialRing(F) @@ -134,22 +137,22 @@ def radical_basis(self): ....: return self.from_vector(vector(w1*w2)) sage: AnAlgebra(GF(3)).radical_basis() (B[1] + 2*B[xbar^2], B[xbar] + 2*B[xbar^2]) - sage: AnAlgebra(GF(16,'a')).radical_basis() + sage: AnAlgebra(GF(16,'a')).radical_basis() # needs sage.rings.finite_rings (B[1] + B[xbar],) - sage: AnAlgebra(GF(49,'a')).radical_basis() + sage: AnAlgebra(GF(49,'a')).radical_basis() # needs sage.rings.finite_rings (B[1] + 6*B[xbar^6], B[xbar] + 6*B[xbar^6], B[xbar^2] + 6*B[xbar^6], B[xbar^3] + 6*B[xbar^6], B[xbar^4] + 6*B[xbar^6], B[xbar^5] + 6*B[xbar^6]) TESTS:: - sage: A = KleinFourGroup().algebra(GF(2)) - sage: A.radical_basis() + sage: A = KleinFourGroup().algebra(GF(2)) # needs sage.groups sage.modules + sage: A.radical_basis() # needs sage.groups sage.modules (() + (1,2)(3,4), (3,4) + (1,2)(3,4), (1,2) + (1,2)(3,4)) - sage: A = KleinFourGroup().algebra(QQ, category=Monoids()) - sage: A.radical_basis.__module__ + sage: A = KleinFourGroup().algebra(QQ, category=Monoids()) # needs sage.groups sage.modules + sage: A.radical_basis.__module__ # needs sage.groups sage.modules 'sage.categories.finite_dimensional_algebras_with_basis' - sage: A.radical_basis() + sage: A.radical_basis() # needs sage.groups sage.modules () """ F = self.base_ring() @@ -216,6 +219,7 @@ def radical(self): EXAMPLES:: + sage: # needs sage.graphs sage.modules sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver @@ -228,12 +232,14 @@ def radical(self): The radical is an ideal of `A`, and thus a finite dimensional non unital associative algebra:: + sage: # needs sage.graphs sage.modules sage: from sage.categories.associative_algebras import AssociativeAlgebras sage: radical in AssociativeAlgebras(QQ).WithBasis().FiniteDimensional() True sage: radical in Algebras(QQ) False + sage: # needs sage.graphs sage.modules sage: radical.dimension() 2 sage: radical.basis() @@ -251,6 +257,7 @@ def radical(self): TESTS:: + sage: # needs sage.graphs sage.modules sage: TestSuite(radical).run() """ category = AssociativeAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Subobjects() @@ -271,6 +278,7 @@ def semisimple_quotient(self): EXAMPLES:: + sage: # needs sage.graphs sage.modules sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver @@ -292,10 +300,10 @@ def semisimple_quotient(self): descent algebra of the symmetric group is of dimension the number of partitions of `n`:: - sage: [ DescentAlgebra(QQ,n).B().semisimple_quotient().dimension() + sage: [ DescentAlgebra(QQ,n).B().semisimple_quotient().dimension() # needs sage.combinat sage.modules ....: for n in range(6) ] [1, 1, 2, 3, 5, 7] - sage: [Partitions(n).cardinality() for n in range(10)] + sage: [Partitions(n).cardinality() for n in range(10)] # needs sage.combinat [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] .. TODO:: @@ -305,7 +313,7 @@ def semisimple_quotient(self): TESTS:: - sage: TestSuite(S).run() + sage: TestSuite(S).run() # needs sage.graphs sage.modules """ ring = self.base_ring() category = Algebras(ring).WithBasis().FiniteDimensional().Quotients().Semisimple() @@ -313,7 +321,6 @@ def semisimple_quotient(self): result.rename("Semisimple quotient of {}".format(self)) return result - @cached_method def center_basis(self): r""" @@ -327,6 +334,7 @@ def center_basis(self): EXAMPLES:: + sage: # needs sage.graphs sage.modules sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver @@ -345,6 +353,7 @@ def center(self): EXAMPLES:: + sage: # needs sage.graphs sage.modules sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver @@ -366,7 +375,8 @@ def center(self): The center of a semisimple algebra is semisimple:: - sage: DihedralGroup(6).algebra(QQ).center() in Algebras(QQ).Semisimple() + sage: A = DihedralGroup(6).algebra(QQ) # needs sage.groups sage.modules + sage: A.center() in Algebras(QQ).Semisimple() # needs sage.groups sage.modules True .. TODO:: @@ -376,7 +386,7 @@ def center(self): TESTS:: - sage: TestSuite(center).run() + sage: TestSuite(center).run() # needs sage.graphs sage.modules """ category = Algebras(self.base_ring()).FiniteDimensional().Subobjects().Commutative().WithBasis() if self in Algebras.Semisimple: @@ -397,6 +407,7 @@ def principal_ideal(self, a, side='left'): right principal ideals, our first example deals with a non commutative algebra:: + sage: # needs sage.graphs sage.modules sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver @@ -406,34 +417,34 @@ def principal_ideal(self, a, side='left'): In this algebra, multiplication on the right by `x` annihilates all basis elements but `x`:: - sage: x*x, y*x, a*x, b*x + sage: x*x, y*x, a*x, b*x # needs sage.graphs sage.modules (x, 0, 0, 0) so the left ideal generated by `x` is one-dimensional:: - sage: Ax = A.principal_ideal(x, side='left'); Ax + sage: Ax = A.principal_ideal(x, side='left'); Ax # needs sage.graphs sage.modules Free module generated by {0} over Rational Field - sage: [B.lift() for B in Ax.basis()] + sage: [B.lift() for B in Ax.basis()] # needs sage.graphs sage.modules [x] Multiplication on the left by `x` annihilates only `x` and fixes the other basis elements:: - sage: x*x, x*y, x*a, x*b + sage: x*x, x*y, x*a, x*b # needs sage.graphs sage.modules (x, 0, a, b) so the right ideal generated by `x` is 3-dimensional:: - sage: xA = A.principal_ideal(x, side='right'); xA + sage: xA = A.principal_ideal(x, side='right'); xA # needs sage.graphs sage.modules Free module generated by {0, 1, 2} over Rational Field - sage: [B.lift() for B in xA.basis()] + sage: [B.lift() for B in xA.basis()] # needs sage.graphs sage.modules [x, a, b] .. SEEALSO:: - :meth:`peirce_summand` """ - return self.submodule([(a * b if side=='right' else b * a) + return self.submodule([(a * b if side == 'right' else b * a) for b in self.basis()]) @cached_method @@ -470,15 +481,17 @@ def orthogonal_idempotents_central_mod_radical(self): EXAMPLES:: + sage: # needs sage.graphs sage.modules sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: A.orthogonal_idempotents_central_mod_radical() + sage: A.orthogonal_idempotents_central_mod_radical() # needs sage.rings.number_field (x, y) :: + sage: # needs sage.modules sage.rings.number_field sage: Z12 = Monoids().Finite().example(); Z12 An example of a finite multiplicative monoid: the integers modulo 12 sage: A = Z12.algebra(QQ) @@ -497,17 +510,19 @@ def orthogonal_idempotents_central_mod_radical(self): True sage: all(e*e == e for e in idempotents) True - sage: all(e*f == 0 and f*e == 0 for e in idempotents for f in idempotents if e != f) + sage: all(e*f == 0 and f*e == 0 + ....: for e in idempotents for f in idempotents if e != f) True This is best tested with:: - sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) + sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) # needs sage.graphs sage.modules sage.rings.number_field True We construct orthogonal idempotents for the algebra of the `0`-Hecke monoid:: + sage: # needs sage.combinat sage.graphs sage.groups sage.modules sage: from sage.monoids.hecke_monoid import HeckeMonoid sage: A = HeckeMonoid(SymmetricGroup(4)).algebra(QQ) sage: idempotents = A.orthogonal_idempotents_central_mod_radical() @@ -554,6 +569,7 @@ def idempotent_lift(self, x): EXAMPLES:: + sage: # needs sage.graphs sage.modules sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example() sage: S = A.semisimple_quotient() sage: A.idempotent_lift(S.basis()['x']) @@ -569,7 +585,7 @@ def idempotent_lift(self, x): x = x.lift() p = self.semisimple_quotient().retract(x) if p * p != p: - raise ValueError("%s does not retract to an idempotent."%p) + raise ValueError("%s does not retract to an idempotent." % p) x_prev = None one = self.one() while x != x_prev: @@ -646,8 +662,8 @@ def cartan_invariants_matrix(self): in characteristic zero, the Cartan invariants matrix is the identity:: - sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: A3.cartan_invariants_matrix() + sage: A3 = SymmetricGroup(3).algebra(QQ) # needs sage.groups sage.modules + sage: A3.cartan_invariants_matrix() # needs sage.groups sage.modules [1 0 0] [0 1 0] [0 0 1] @@ -656,7 +672,7 @@ def cartan_invariants_matrix(self): matrix counts the number of paths between two vertices:: sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example() - sage: A.cartan_invariants_matrix() + sage: A.cartan_invariants_matrix() # needs sage.modules sage.rings.number_field [1 2] [0 1] @@ -664,8 +680,8 @@ def cartan_invariants_matrix(self): sage: Z12 = Monoids().Finite().example(); Z12 An example of a finite multiplicative monoid: the integers modulo 12 - sage: A = Z12.algebra(QQ) - sage: A.cartan_invariants_matrix() + sage: A = Z12.algebra(QQ) # needs sage.modules + sage: A.cartan_invariants_matrix() # needs sage.modules sage.rings.number_field [1 0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0] [0 0 2 0 0 0 0 0 0] @@ -678,9 +694,10 @@ def cartan_invariants_matrix(self): With the algebra of the `0`-Hecke monoid:: + sage: # needs sage.combinat sage.groups sage.modules sage: from sage.monoids.hecke_monoid import HeckeMonoid sage: A = HeckeMonoid(SymmetricGroup(4)).algebra(QQ) - sage: A.cartan_invariants_matrix() + sage: A.cartan_invariants_matrix() # needs sage.rings.number_field [1 0 0 0 0 0 0 0] [0 2 1 0 1 1 0 0] [0 1 1 0 1 0 0 0] @@ -736,6 +753,7 @@ def isotypic_projective_modules(self, side='left'): EXAMPLES:: + sage: # needs sage.graphs sage.modules sage.rings.number_field sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver @@ -751,7 +769,7 @@ def isotypic_projective_modules(self, side='left'): We check that the sum of the dimensions of the isotypic projective modules is the dimension of ``self``:: - sage: sum([Qi.dimension() for Qi in Q]) == A.dimension() + sage: sum([Qi.dimension() for Qi in Q]) == A.dimension() # needs sage.graphs sage.modules sage.rings.number_field True .. SEEALSO:: @@ -783,19 +801,19 @@ def peirce_summand(self, ei, ej): EXAMPLES:: sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example() - sage: idemp = A.orthogonal_idempotents_central_mod_radical() - sage: A.peirce_summand(idemp[0], idemp[1]) + sage: idemp = A.orthogonal_idempotents_central_mod_radical() # needs sage.rings.number_field + sage: A.peirce_summand(idemp[0], idemp[1]) # needs sage.rings.number_field Free module generated by {0, 1} over Rational Field - sage: A.peirce_summand(idemp[1], idemp[0]) + sage: A.peirce_summand(idemp[1], idemp[0]) # needs sage.rings.number_field Free module generated by {} over Rational Field We recover the `2\times2` block of `\QQ[S_4]` corresponding to the unique simple module of dimension `2` of the symmetric group `S_4`:: - sage: A4 = SymmetricGroup(4).algebra(QQ) - sage: e = A4.central_orthogonal_idempotents()[2] - sage: A4.peirce_summand(e, e) + sage: A4 = SymmetricGroup(4).algebra(QQ) # needs sage.groups + sage: e = A4.central_orthogonal_idempotents()[2] # needs sage.groups sage.rings.number_field + sage: A4.peirce_summand(e, e) # needs sage.groups sage.rings.number_field Free module generated by {0, 1, 2, 3} over Rational Field TESTS: @@ -803,11 +821,12 @@ def peirce_summand(self, ei, ej): We check each idempotent belong to its own Peirce summand (see :trac:`24687`):: + sage: # needs sage.groups sage: from sage.monoids.hecke_monoid import HeckeMonoid sage: M = HeckeMonoid(SymmetricGroup(4)) sage: A = M.algebra(QQ) - sage: Idms = A.orthogonal_idempotents_central_mod_radical() - sage: all(A.peirce_summand(e, e).retract(e) + sage: Idms = A.orthogonal_idempotents_central_mod_radical() # needs sage.rings.number_field + sage: all(A.peirce_summand(e, e).retract(e) # needs sage.rings.number_field ....: in A.peirce_summand(e, e) for e in Idms) True """ @@ -819,7 +838,6 @@ def peirce_summand(self, ei, ej): return self.submodule([self.from_vector(v) for v in ideal.basis()], already_echelonized=True) - def peirce_decomposition(self, idempotents=None, check=True): r""" Return a Peirce decomposition of ``self``. @@ -861,6 +879,7 @@ def peirce_decomposition(self, idempotents=None, check=True): EXAMPLES:: + sage: # needs sage.graphs sage.groups sage.modules sage.rings.number_field sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver @@ -881,9 +900,10 @@ def peirce_decomposition(self, idempotents=None, check=True): We recover that the group algebra of the symmetric group `S_4` is a block matrix algebra:: + sage: # needs sage.groups sage.modules sage.rings.number_field sage: A = SymmetricGroup(4).algebra(QQ) - sage: decomposition = A.peirce_decomposition() # long time - sage: [[decomposition[i][j].dimension() # long time (4s) + sage: decomposition = A.peirce_decomposition() # long time + sage: [[decomposition[i][j].dimension() # long time (4s) ....: for j in range(len(decomposition))] ....: for i in range(len(decomposition))] [[9, 0, 0, 0, 0], @@ -896,7 +916,7 @@ def peirce_decomposition(self, idempotents=None, check=True): dimension of the corresponding simple module of `S_4`. The latter are given by:: - sage: [p.standard_tableaux().cardinality() for p in Partitions(4)] + sage: [p.standard_tableaux().cardinality() for p in Partitions(4)] # needs sage.combinat [1, 3, 2, 3, 1] """ if idempotents is None: @@ -918,37 +938,37 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): EXAMPLES:: + sage: # needs sage.graphs sage.modules sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: x,y,a,b = A.algebra_generators(); x,y,a,b (x, y, a, b) - sage: A.is_identity_decomposition_into_orthogonal_idempotents([A.one()]) True - sage: A.is_identity_decomposition_into_orthogonal_idempotents([x,y]) + sage: A.is_identity_decomposition_into_orthogonal_idempotents([x, y]) True - sage: A.is_identity_decomposition_into_orthogonal_idempotents([x+a, y-a]) + sage: A.is_identity_decomposition_into_orthogonal_idempotents([x + a, y - a]) True Here the idempotents do not sum up to `1`:: - sage: A.is_identity_decomposition_into_orthogonal_idempotents([x]) + sage: A.is_identity_decomposition_into_orthogonal_idempotents([x]) # needs sage.graphs sage.modules False Here `1+x` and `-x` are neither idempotent nor orthogonal:: - sage: A.is_identity_decomposition_into_orthogonal_idempotents([1+x,-x]) + sage: A.is_identity_decomposition_into_orthogonal_idempotents([1 + x, -x]) # needs sage.graphs sage.modules False With the algebra of the `0`-Hecke monoid:: + sage: # needs sage.combinat sage.groups sage.modules sage: from sage.monoids.hecke_monoid import HeckeMonoid sage: A = HeckeMonoid(SymmetricGroup(4)).algebra(QQ) - sage: idempotents = A.orthogonal_idempotents_central_mod_radical() - sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) + sage: idempotents = A.orthogonal_idempotents_central_mod_radical() # needs sage.rings.number_field + sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) # needs sage.rings.number_field True Here are some more counterexamples: @@ -956,6 +976,7 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): 1. Some orthogonal elements summing to `1` but not being idempotent:: + sage: # needs sage.libs.pari sage.modules sage: class PQAlgebra(CombinatorialFreeModule): ....: def __init__(self, F, p): ....: # Construct the quotient algebra F[x] / p, @@ -974,12 +995,13 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): ....: return self.from_vector(vector(w1*w2)) sage: R.<x> = PolynomialRing(QQ) sage: A = PQAlgebra(QQ, x**3 - x**2 + x + 1); y = A.x() - sage: a, b = y, 1-y + sage: a, b = y, 1 - y sage: A.is_identity_decomposition_into_orthogonal_idempotents((a, b)) False For comparison:: + sage: # needs sage.libs.pari sage.modules sage: A = PQAlgebra(QQ, x**2 - x); y = A.x() sage: a, b = y, 1-y sage: A.is_identity_decomposition_into_orthogonal_idempotents((a, b)) @@ -994,6 +1016,7 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): 2. Some idempotents summing to 1 but not orthogonal:: + sage: # needs sage.libs.pari sage.modules sage: R.<x> = PolynomialRing(GF(2)) sage: A = PQAlgebra(GF(2), x) sage: a = A.one() @@ -1004,6 +1027,7 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): 3. Some orthogonal idempotents not summing to the identity:: + sage: # needs sage.libs.pari sage.modules sage: A.is_identity_decomposition_into_orthogonal_idempotents((a,a)) False sage: A.is_identity_decomposition_into_orthogonal_idempotents(()) @@ -1021,6 +1045,7 @@ def is_commutative(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: S4 = SymmetricGroupAlgebra(QQ, 4) sage: S4.is_commutative() False @@ -1049,6 +1074,7 @@ def to_matrix(self, base_ring=None, action=operator.mul, side='left'): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: QS3 = SymmetricGroupAlgebra(QQ, 3) sage: a = QS3([2,1,3]) sage: a.to_matrix(side='left') @@ -1102,6 +1128,7 @@ def __invert__(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: QS3 = SymmetricGroupAlgebra(QQ, 3) sage: P = Permutation sage: a = 3 * QS3(P([1,2,3])) + QS3(P([1,3,2])) + QS3(P([2,1,3])) @@ -1113,6 +1140,7 @@ def __invert__(self): sage: ~b == a True + sage: # needs sage.groups sage.modules sage: a = 3 * QS3.one() sage: b = ~a sage: b * a == QS3.one() @@ -1123,18 +1151,19 @@ def __invert__(self): True sage: R.<t> = QQ[] - sage: RS3 = SymmetricGroupAlgebra(R, 3) - sage: a = RS3(P([1,2,3])) - RS3(P([1,3,2])) + RS3(P([2,1,3])); ~a + sage: RS3 = SymmetricGroupAlgebra(R, 3) # needs sage.groups sage.modules + sage: a = RS3(P([1,2,3])) - RS3(P([1,3,2])) + RS3(P([2,1,3])); ~a # needs sage.groups sage.modules -1/2*[1, 3, 2] + 1/2*[2, 1, 3] + 1/2*[2, 3, 1] + 1/2*[3, 1, 2] Some examples on elements that do not have an inverse:: - sage: c = 2 * QS3(P([1,2,3])) + QS3(P([1,3,2])) + QS3(P([2,1,3])) - sage: ~c + sage: c = 2 * QS3(P([1,2,3])) + QS3(P([1,3,2])) + QS3(P([2,1,3])) # needs sage.groups sage.modules + sage: ~c # needs sage.groups sage.modules Traceback (most recent call last): ... ValueError: cannot invert self (= 2*[1, 2, 3] + [1, 3, 2] + [2, 1, 3]) + sage: # needs sage.groups sage.modules sage: ZS3 = SymmetricGroupAlgebra(ZZ, 3) sage: aZ = 3 * ZS3(P([1,2,3])) + ZS3(P([1,3,2])) + ZS3(P([2,1,3])) sage: ~aZ @@ -1151,9 +1180,9 @@ def __invert__(self): An algebra that does not define ``one_basis()``:: - sage: I = DescentAlgebra(QQ, 3).I() - sage: a = 3 * I.one() - sage: ~a == 1/3 * I.one() + sage: I = DescentAlgebra(QQ, 3).I() # needs sage.combinat sage.modules + sage: a = 3 * I.one() # needs sage.combinat sage.modules + sage: ~a == 1/3 * I.one() # needs sage.combinat sage.modules True """ alg = self.parent() @@ -1241,8 +1270,8 @@ def _test_cellular(self, **options): EXAMPLES:: - sage: S = SymmetricGroupAlgebra(QQ, 3) - sage: S._test_cellular() + sage: S = SymmetricGroupAlgebra(QQ, 3) # needs sage.combinat sage.modules + sage: S._test_cellular() # needs sage.combinat sage.modules """ tester = self._tester(**options) cell_basis = self.cellular_basis() @@ -1275,8 +1304,8 @@ def cell_poset(self): EXAMPLES:: - sage: S = SymmetricGroupAlgebra(QQ, 4) - sage: S.cell_poset() + sage: S = SymmetricGroupAlgebra(QQ, 4) # needs sage.groups sage.modules + sage: S.cell_poset() # needs sage.groups sage.modules Finite poset containing 5 elements """ @@ -1290,8 +1319,8 @@ def cell_module_indices(self, mu): EXAMPLES:: - sage: S = SymmetricGroupAlgebra(QQ, 3) - sage: S.cell_module_indices([2,1]) + sage: S = SymmetricGroupAlgebra(QQ, 3) # needs sage.groups sage.modules + sage: S.cell_module_indices([2,1]) # needs sage.groups sage.modules Standard tableaux of shape [2, 1] """ @@ -1303,8 +1332,8 @@ def _to_cellular_element(self, i): EXAMPLES:: - sage: S = SymmetricGroupAlgebra(QQ, 3) - sage: S._to_cellular_element # no implementation currently uses this + sage: S = SymmetricGroupAlgebra(QQ, 3) # needs sage.groups sage.modules + sage: S._to_cellular_element # no implementation currently uses this # needs sage.groups sage.modules NotImplemented """ @@ -1316,13 +1345,13 @@ def _from_cellular_index(self, x): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage.modules sage: S = SymmetricGroupAlgebra(QQ, 3) sage: mu = Partition([2,1]) sage: s = StandardTableau([[1,2],[3]]) sage: t = StandardTableau([[1,3],[2]]) sage: S._from_cellular_index((mu, s, t)) - 1/4*[1, 3, 2] - 1/4*[2, 3, 1] + 1/4*[3, 1, 2] - - 1/4*[3, 2, 1] + 1/4*[1, 3, 2] - 1/4*[2, 3, 1] + 1/4*[3, 1, 2] - 1/4*[3, 2, 1] """ def cellular_involution(self, x): @@ -1331,8 +1360,8 @@ def cellular_involution(self, x): EXAMPLES:: - sage: S = SymmetricGroupAlgebra(QQ, 3) - sage: for b in S.basis(): b, S.cellular_involution(b) + sage: S = SymmetricGroupAlgebra(QQ, 3) # needs sage.groups sage.modules + sage: for b in S.basis(): b, S.cellular_involution(b) # needs sage.groups sage.modules ([1, 2, 3], [1, 2, 3]) ([1, 3, 2], 49/48*[1, 3, 2] + 7/48*[2, 3, 1] - 7/48*[3, 1, 2] - 1/48*[3, 2, 1]) @@ -1358,8 +1387,8 @@ def cells(self): EXAMPLES:: - sage: S = SymmetricGroupAlgebra(QQ, 3) - sage: dict(S.cells()) + sage: S = SymmetricGroupAlgebra(QQ, 3) # needs sage.groups sage.modules + sage: dict(S.cells()) # needs sage.groups sage.modules {[1, 1, 1]: Standard tableaux of shape [1, 1, 1], [2, 1]: Standard tableaux of shape [2, 1], [3]: Standard tableaux of shape [3]} @@ -1373,8 +1402,8 @@ def cellular_basis(self): EXAMPLES:: - sage: S = SymmetricGroupAlgebra(QQ, 3) - sage: S.cellular_basis() + sage: S = SymmetricGroupAlgebra(QQ, 3) # needs sage.groups sage.modules + sage: S.cellular_basis() # needs sage.groups sage.modules Cellular basis of Symmetric group algebra of order 3 over Rational Field """ @@ -1387,8 +1416,8 @@ def cell_module(self, mu, **kwds): EXAMPLES:: - sage: S = SymmetricGroupAlgebra(QQ, 3) - sage: S.cell_module(Partition([2,1])) + sage: S = SymmetricGroupAlgebra(QQ, 3) # needs sage.groups sage.modules + sage: S.cell_module(Partition([2,1])) # needs sage.combinat sage.groups sage.modules Cell module indexed by [2, 1] of Cellular basis of Symmetric group algebra of order 3 over Rational Field """ @@ -1406,8 +1435,8 @@ def simple_module_parameterization(self): EXAMPLES:: - sage: S = SymmetricGroupAlgebra(QQ, 4) - sage: S.simple_module_parameterization() + sage: S = SymmetricGroupAlgebra(QQ, 4) # needs sage.groups sage.modules + sage: S.simple_module_parameterization() # needs sage.groups sage.modules ([4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]) """ return tuple([mu for mu in self.cell_poset() @@ -1420,6 +1449,7 @@ def cellular_involution(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: S = SymmetricGroupAlgebra(QQ, 4) sage: elt = S([3,1,2,4]) sage: ci = elt.cellular_involution(); ci @@ -1457,10 +1487,11 @@ def cell_poset(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: S2 = SymmetricGroupAlgebra(QQ, 2) sage: S3 = SymmetricGroupAlgebra(QQ, 3) sage: T = S2.tensor(S3) - sage: T.cell_poset() + sage: T.cell_poset() # needs sage.combinat sage.graphs Finite poset containing 6 elements """ ret = self._sets[0].cell_poset() @@ -1477,6 +1508,7 @@ def cell_module_indices(self, mu): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: S2 = SymmetricGroupAlgebra(QQ, 2) sage: S3 = SymmetricGroupAlgebra(QQ, 3) sage: T = S2.tensor(S3) @@ -1496,6 +1528,7 @@ def cellular_involution(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: S2 = SymmetricGroupAlgebra(QQ, 2) sage: S3 = SymmetricGroupAlgebra(QQ, 3) sage: T = S2.tensor(S3) @@ -1549,6 +1582,7 @@ def _to_cellular_element(self, i): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: S2 = SymmetricGroupAlgebra(QQ, 2) sage: S3 = SymmetricGroupAlgebra(QQ, 3) sage: T = S2.tensor(S3) @@ -1585,6 +1619,7 @@ def _from_cellular_index(self, x): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: S2 = SymmetricGroupAlgebra(QQ, 2) sage: S3 = SymmetricGroupAlgebra(QQ, 3) sage: T = S2.tensor(S3) diff --git a/src/sage/categories/finite_dimensional_bialgebras_with_basis.py b/src/sage/categories/finite_dimensional_bialgebras_with_basis.py index 086892237e6..02f1005e0de 100644 --- a/src/sage/categories/finite_dimensional_bialgebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_bialgebras_with_basis.py @@ -27,5 +27,5 @@ def FiniteDimensionalBialgebrasWithBasis(base_ring): sage: TestSuite(C).run() """ - from sage.categories.all import BialgebrasWithBasis + from sage.categories.bialgebras_with_basis import BialgebrasWithBasis return BialgebrasWithBasis(base_ring).FiniteDimensional() diff --git a/src/sage/categories/finite_dimensional_coalgebras_with_basis.py b/src/sage/categories/finite_dimensional_coalgebras_with_basis.py index 9d1eecf556d..60b135080da 100644 --- a/src/sage/categories/finite_dimensional_coalgebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_coalgebras_with_basis.py @@ -27,5 +27,5 @@ def FiniteDimensionalCoalgebrasWithBasis(base_ring): sage: TestSuite(C).run() """ - from sage.categories.all import CoalgebrasWithBasis + from sage.categories.coalgebras_with_basis import CoalgebrasWithBasis return CoalgebrasWithBasis(base_ring).FiniteDimensional() diff --git a/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py index 4bbdf0807b1..c5554a2f094 100644 --- a/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py @@ -53,6 +53,7 @@ def _test_grading(self, **options): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: C = LieAlgebras(QQ).WithBasis().Graded() sage: C = C.FiniteDimensional().Stratified().Nilpotent() sage: L = LieAlgebra(QQ, {('x','y'): {'z': 1}}, @@ -96,9 +97,9 @@ def homogeneous_component_as_submodule(self, d): sage: C = LieAlgebras(QQ).WithBasis().Graded() sage: C = C.FiniteDimensional().Stratified().Nilpotent() - sage: L = LieAlgebra(QQ, {('x','y'): {'z': 1}}, + sage: L = LieAlgebra(QQ, {('x','y'): {'z': 1}}, # needs sage.combinat sage.modules ....: nilpotent=True, category=C) - sage: L.homogeneous_component_as_submodule(2) + sage: L.homogeneous_component_as_submodule(2) # needs sage.combinat sage.modules Sparse vector space of degree 3 and dimension 1 over Rational Field Basis matrix: [0 0 1] @@ -147,12 +148,12 @@ def _test_generated_by_degree_one(self, **options): sage: C = LieAlgebras(QQ).WithBasis().Graded() sage: C = C.FiniteDimensional().Stratified().Nilpotent() sage: sc = {('x','y'): {'z': 1}} - sage: L.<x,y,z> = LieAlgebra(QQ, sc, nilpotent=True, category=C) - sage: L._test_generated_by_degree_one() + sage: L.<x,y,z> = LieAlgebra(QQ, sc, nilpotent=True, category=C) # needs sage.combinat sage.modules + sage: L._test_generated_by_degree_one() # needs sage.combinat sage.modules sage: sc = {('x','y'): {'z': 1}, ('a','b'): {'c':1}, ('z','c'): {'m':1}} - sage: L.<a,b,c,m,x,y,z> = LieAlgebra(QQ, sc, nilpotent=True, category=C) - sage: L._test_generated_by_degree_one() + sage: L.<a,b,c,m,x,y,z> = LieAlgebra(QQ, sc, nilpotent=True, category=C) # needs sage.combinat sage.modules + sage: L._test_generated_by_degree_one() # needs sage.combinat sage.modules Traceback (most recent call last): ... AssertionError: [a, b, x, y] does not generate Nilpotent Lie algebra @@ -196,6 +197,7 @@ def degree_on_basis(self, m): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: C = LieAlgebras(QQ).WithBasis().Graded() sage: C = C.FiniteDimensional().Stratified().Nilpotent() sage: sc = {('X','Y'): {'Z': 1}} diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py index bfe0de224b2..013b30dc281 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -24,9 +24,7 @@ from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.lie_algebras import LieAlgebras from sage.categories.subobjects import SubobjectsCategory -from sage.algebras.free_algebra import FreeAlgebra from sage.sets.family import Family -from sage.matrix.constructor import matrix class FiniteDimensionalLieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): @@ -48,13 +46,13 @@ def example(self, n=3): EXAMPLES:: sage: C = LieAlgebras(QQ).FiniteDimensional().WithBasis() - sage: C.example() + sage: C.example() # needs sage.modules An example of a finite dimensional Lie algebra with basis: the 3-dimensional abelian Lie algebra over Rational Field Other dimensions can be specified as an optional argument:: - sage: C.example(5) + sage: C.example(5) # needs sage.modules An example of a finite dimensional Lie algebra with basis: the 5-dimensional abelian Lie algebra over Rational Field """ @@ -72,6 +70,7 @@ def _construct_UEA(self): EXAMPLES:: + sage: # needs sage.combinat sage.libs.singular sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: UEA = L._construct_UEA(); UEA Noncommutative Multivariate Polynomial Ring in b0, b1, b2 @@ -81,7 +80,10 @@ def _construct_UEA(self): :: - sage: L.<x,y,z> = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: # needs sage.combinat sage.libs.singular sage.modules + sage: L.<x,y,z> = LieAlgebra(QQ, {('x','y'): {'z':1}, + ....: ('y','z'): {'x':1}, + ....: ('z','x'):{'y':1}}) sage: UEA = L._construct_UEA(); UEA Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {...} @@ -91,12 +93,14 @@ def _construct_UEA(self): Singular's ``nc_algebra`` does not work over `\ZZ/6\ZZ`, so we fallback to the PBW basis in this case:: - sage: L = lie_algebras.pwitt(Zmod(6), 6) - sage: L._construct_UEA() + sage: L = lie_algebras.pwitt(Zmod(6), 6) # needs sage.combinat sage.modules + sage: L._construct_UEA() # needs sage.combinat sage.libs.singular sage.modules Universal enveloping algebra of The 6-Witt Lie algebra over Ring of integers modulo 6 in the Poincare-Birkhoff-Witt basis """ + from sage.algebras.free_algebra import FreeAlgebra + # Create the UEA relations # We need to get names for the basis elements, not just the generators I = self._basis_ordering @@ -147,8 +151,8 @@ def _basis_ordering(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L._basis_ordering + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: L._basis_ordering # needs sage.modules (0, 1, 2) """ return tuple(self.basis().keys()) @@ -161,6 +165,7 @@ def _basis_key_inverse(self): EXAMPLES:: + sage: # needs sage.combinat sage.groups sage.modules sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) sage: L = LieAlgebra(associative=S) @@ -175,24 +180,26 @@ def _basis_key(self, x): TESTS:: - sage: L = lie_algebras.three_dimensional_by_rank(QQ, 3, names=['E','F','H']) - sage: PBW = L.pbw_basis() - sage: PBW._basis_key('E') < PBW._basis_key('H') + sage: L = lie_algebras.three_dimensional_by_rank(QQ, 3, # needs sage.groups sage.modules + ....: names=['E','F','H']) + sage: PBW = L.pbw_basis() # needs sage.groups sage.modules + sage: PBW._basis_key('E') < PBW._basis_key('H') # needs sage.groups sage.modules True :: - sage: L = lie_algebras.sl(QQ, 2) + sage: L = lie_algebras.sl(QQ, 2) # needs sage.groups sage.modules sage: def neg_key(x): ....: return -L.basis().keys().index(x) - sage: PBW = L.pbw_basis(basis_key=neg_key) - sage: prod(PBW.gens()) # indirect doctest + sage: PBW = L.pbw_basis(basis_key=neg_key) # needs sage.groups sage.modules + sage: prod(PBW.gens()) # indirect doctest # needs sage.groups sage.modules PBW[-alpha[1]]*PBW[alphacheck[1]]*PBW[alpha[1]] - 4*PBW[-alpha[1]]*PBW[alpha[1]] + PBW[alphacheck[1]]^2 - 2*PBW[alphacheck[1]] Check that :trac:`23266` is fixed:: + sage: # needs sage.groups sage.modules sage: sl2 = lie_algebras.sl(QQ, 2, 'matrix') sage: sl2.indices() {'e1', 'f1', 'h1'} @@ -214,8 +221,8 @@ def _dense_free_module(self, R=None): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L._dense_free_module() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: L._dense_free_module() # needs sage.modules Vector space of dimension 3 over Rational Field """ if R is None: @@ -237,10 +244,10 @@ def from_vector(self, v, order=None): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u # needs sage.modules (1, 0, 0) - sage: parent(u) is L + sage: parent(u) is L # needs sage.modules True """ if order is None: @@ -260,17 +267,17 @@ def killing_matrix(self, x, y): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: a,b,c = L.lie_algebra_generators() - sage: L.killing_matrix(a, b) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: a, b, c = L.lie_algebra_generators() # needs sage.modules + sage: L.killing_matrix(a, b) # needs sage.modules [0 0 0] [0 0 0] [0 0 0] :: - sage: L.<x,y> = LieAlgebra(QQ, {('x','y'):{'x':1}}) - sage: L.killing_matrix(y, x) + sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) # needs sage.combinat sage.modules + sage: L.killing_matrix(y, x) # needs sage.combinat sage.modules [ 0 -1] [ 0 0] """ @@ -291,9 +298,9 @@ def killing_form(self, x, y): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: a,b,c = L.lie_algebra_generators() - sage: L.killing_form(a, b) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: a, b, c = L.lie_algebra_generators() # needs sage.modules + sage: L.killing_form(a, b) # needs sage.modules 0 """ return self.killing_matrix(x, y).trace() @@ -309,18 +316,20 @@ def killing_form_matrix(self): EXAMPLES:: + sage: # needs sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.killing_form_matrix() [0 0 0] [0 0 0] [0 0 0] - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example(0) sage: m = L.killing_form_matrix(); m [] sage: parent(m) Full MatrixSpace of 0 by 0 dense matrices over Rational Field """ + from sage.matrix.constructor import matrix + B = self.basis() m = matrix(self.base_ring(), [[self.killing_form(x, y) for x in B] for y in B]) @@ -345,14 +354,15 @@ def structure_coefficients(self, include_zeros=False): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.structure_coefficients() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: L.structure_coefficients() # needs sage.modules Finite family {} - sage: L.structure_coefficients(True) + sage: L.structure_coefficients(True) # needs sage.modules Finite family {(0, 1): (0, 0, 0), (0, 2): (0, 0, 0), (1, 2): (0, 0, 0)} :: + sage: # needs sage.combinat sage.groups sage.modules sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) sage: L = LieAlgebra(associative=S) @@ -399,16 +409,18 @@ def centralizer_basis(self, S): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: a,b,c = L.lie_algebra_generators() + sage: a, b, c = L.lie_algebra_generators() sage: L.centralizer_basis([a + b, 2*a + c]) [(1, 0, 0), (0, 1, 0), (0, 0, 1)] + sage: # needs sage.combinat sage.modules sage: H = lie_algebras.Heisenberg(QQ, 2) sage: H.centralizer_basis(H) [z] - + sage: # needs sage.combinat sage.groupssage.modules sage: D = DescentAlgebra(QQ, 4).D() sage: L = LieAlgebra(associative=D) sage: L.centralizer_basis(L) @@ -420,6 +432,8 @@ def centralizer_basis(self, S): D{1} + D{1, 2} + D{2, 3} + D{3}, D{1, 2, 3} + D{1, 3} + D{2}) """ + from sage.matrix.constructor import matrix + #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra #if isinstance(S, LieSubalgebra) or S is self: if S is self: @@ -461,8 +475,9 @@ def centralizer(self, S): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: a,b,c = L.lie_algebra_generators() + sage: a, b, c = L.lie_algebra_generators() sage: S = L.centralizer([a + b, 2*a + c]); S An example of a finite dimensional Lie algebra with basis: the 3-dimensional abelian Lie algebra over Rational Field @@ -479,6 +494,7 @@ def center(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: Z = L.center(); Z An example of a finite dimensional Lie algebra with basis: the @@ -510,6 +526,7 @@ def derivations_basis(self): We construct the derivations of the Heisenberg Lie algebra:: + sage: # needs sage.combinat sage.modules sage: H = lie_algebras.Heisenberg(QQ, 1) sage: H.derivations_basis() ( @@ -520,6 +537,7 @@ def derivations_basis(self): We construct the derivations of `\mathfrak{sl}_2`:: + sage: # needs sage.combinat sage.modules sage: sl2 = lie_algebras.sl(QQ, 2) sage: sl2.derivations_basis() ( @@ -530,6 +548,7 @@ def derivations_basis(self): We verify these are derivations:: + sage: # needs sage.combinat sage.modules sage: D = [sl2.module_morphism(matrix=M, codomain=sl2) ....: for M in sl2.derivations_basis()] sage: all(d(a.bracket(b)) == d(a).bracket(b) + a.bracket(d(b)) @@ -541,6 +560,7 @@ def derivations_basis(self): :wikipedia:`Derivation_(differential_algebra)` """ from sage.matrix.constructor import matrix + R = self.base_ring() B = self.basis() keys = list(B.keys()) @@ -573,6 +593,7 @@ def inner_derivations_basis(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: H = lie_algebras.Heisenberg(QQ, 1) sage: H.inner_derivations_basis() ( @@ -581,6 +602,8 @@ def inner_derivations_basis(self): [1 0 0], [0 1 0] ) """ + from sage.matrix.constructor import matrix + R = self.base_ring() IDer = matrix(R, [b.adjoint_matrix().list() for b in self.basis()]) N = self.dimension() @@ -599,6 +622,7 @@ def subalgebra(self, *gens, **kwds): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: H = lie_algebras.Heisenberg(QQ, 2) sage: p1,p2,q1,q2,z = H.basis() sage: S = H.subalgebra([p1, q1]) @@ -611,6 +635,7 @@ def subalgebra(self, *gens, **kwds): Passing an extra category to a subalgebra:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebra(QQ, 3, step=2) sage: x,y,z = L.homogeneous_component_basis(1) sage: C = LieAlgebras(QQ).FiniteDimensional().WithBasis() @@ -638,9 +663,10 @@ def ideal(self, *gens, **kwds): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: H = lie_algebras.Heisenberg(QQ, 2) sage: p1,p2,q1,q2,z = H.basis() - sage: I = H.ideal([p1-p2, q1-q2]) + sage: I = H.ideal([p1 - p2, q1 - q2]) sage: I.basis().list() [-p1 + p2, -q1 + q2, z] sage: I.reduce(p1 + p2 + q1 + q2 + z) @@ -648,6 +674,7 @@ def ideal(self, *gens, **kwds): Passing an extra category to an ideal:: + sage: # needs sage.combinat sage.modules sage: L.<x,y,z> = LieAlgebra(QQ, abelian=True) sage: C = LieAlgebras(QQ).FiniteDimensional().WithBasis() sage: C = C.Subobjects().Graded().Stratified() @@ -669,18 +696,19 @@ def is_ideal(self, A): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() sage: I = L.ideal([2*a - c, b + c]) sage: I.is_ideal(L) True - sage: L.<x,y> = LieAlgebra(QQ, {('x','y'):{'x':1}}) - sage: L.is_ideal(L) + sage: L.<x,y> = LieAlgebra(QQ, {('x','y'):{'x':1}}) # needs sage.combinat sage.modules + sage: L.is_ideal(L) # needs sage.combinat sage.modules True - sage: F = LieAlgebra(QQ, 'F', representation='polynomial') - sage: L.is_ideal(F) + sage: F = LieAlgebra(QQ, 'F', representation='polynomial') # needs sage.combinat sage.modules + sage: L.is_ideal(F) # needs sage.combinat sage.modules Traceback (most recent call last): ... NotImplementedError: A must be a finite dimensional Lie algebra @@ -691,6 +719,9 @@ def is_ideal(self, A): if A not in LieAlgebras(self.base_ring()).FiniteDimensional().WithBasis(): raise NotImplementedError("A must be a finite dimensional" " Lie algebra with basis") + + from sage.matrix.constructor import matrix + B = self.basis() AB = A.basis() try: @@ -718,24 +749,27 @@ def quotient(self, I, names=None, category=None): The Engel Lie algebra as a quotient of the free nilpotent Lie algebra of step 3 with 2 generators:: - sage: L.<X,Y,Z,W,U> = LieAlgebra(QQ, 2, step=3) - sage: E = L.quotient(U); E - Lie algebra quotient L/I of dimension 4 over Rational Field where - L: Free Nilpotent Lie algebra on 5 generators (X, Y, Z, W, U) over Rational Field - I: Ideal (U) - sage: E.basis().list() - [X, Y, Z, W] - sage: E(X).bracket(E(Y)) - Z - sage: Y.bracket(Z) - -U - sage: E(Y).bracket(E(Z)) - 0 - sage: E(U) - 0 + sage: # needs sage.combinat sage.modules + sage: L.<X,Y,Z,W,U> = LieAlgebra(QQ, 2, step=3) + sage: E = L.quotient(U); E + Lie algebra quotient L/I of dimension 4 over Rational Field where + L: Free Nilpotent Lie algebra on 5 generators (X, Y, Z, W, U) + over Rational Field + I: Ideal (U) + sage: E.basis().list() + [X, Y, Z, W] + sage: E(X).bracket(E(Y)) + Z + sage: Y.bracket(Z) + -U + sage: E(Y).bracket(E(Z)) + 0 + sage: E(U) + 0 Quotients when the base ring is not a field are not implemented:: + sage: # needs sage.combinat sage.modules sage: L = lie_algebras.Heisenberg(ZZ, 1) sage: L.quotient(L.an_element()) Traceback (most recent call last): @@ -759,23 +793,23 @@ def product_space(self, L, submodule=False): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a,b,c = L.lie_algebra_generators() - sage: X = L.subalgebra([a, b+c]) + sage: X = L.subalgebra([a, b + c]) sage: L.product_space(X) An example of a finite dimensional Lie algebra with basis: the 0-dimensional abelian Lie algebra over Rational Field - with basis matrix: - [] - sage: Y = L.subalgebra([a, 2*b-c]) + with basis matrix: [] + sage: Y = L.subalgebra([a, 2*b - c]) sage: X.product_space(Y) An example of a finite dimensional Lie algebra with basis: - the 0-dimensional abelian Lie algebra over Rational - Field with basis matrix: - [] + the 0-dimensional abelian Lie algebra over Rational Field + with basis matrix: [] :: + sage: # needs sage.combinat sage.modules sage: H = lie_algebras.Heisenberg(ZZ, 4) sage: Hp = H.product_space(H, submodule=True).basis() sage: [H.from_vector(v) for v in Hp] @@ -783,21 +817,28 @@ def product_space(self, L, submodule=False): :: + sage: # needs sage.combinat sage.modules sage: L.<x,y> = LieAlgebra(QQ, {('x','y'):{'x':1}}) - sage: Lp = L.product_space(L) # todo: not implemented - #17416 - sage: Lp # todo: not implemented - #17416 - Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: - (x,) - sage: Lp.product_space(L) # todo: not implemented - #17416 - Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: - (x,) - sage: L.product_space(Lp) # todo: not implemented - #17416 - Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: - (x,) - sage: Lp.product_space(Lp) # todo: not implemented - #17416 - Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: - () + sage: Lp = L.product_space(L) # not implemented + sage: Lp # not implemented + Subalgebra generated of + Lie algebra on 2 generators (x, y) over Rational Field + with basis: (x,) + sage: Lp.product_space(L) # not implemented + Subalgebra generated of + Lie algebra on 2 generators (x, y) over Rational Field + with basis: (x,) + sage: L.product_space(Lp) # not implemented + Subalgebra generated of + Lie algebra on 2 generators (x, y) over Rational Field + with basis: (x,) + sage: Lp.product_space(Lp) # not implemented + Subalgebra generated of + Lie algebra on 2 generators (x, y) over Rational Field + with basis: () """ + from sage.matrix.constructor import matrix + # Make sure we lift everything to the ambient space if self in LieAlgebras(self.base_ring()).Subobjects(): A = self.ambient() @@ -831,6 +872,7 @@ def derived_subalgebra(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.derived_subalgebra() An example of a finite dimensional Lie algebra with basis: @@ -840,7 +882,8 @@ def derived_subalgebra(self): If ``self`` is semisimple, then the derived subalgebra is ``self``:: - sage: sl3 = LieAlgebra(QQ, cartan_type=['A',2]) + sage: # needs sage.combinat sage.modules + sage: sl3 = LieAlgebra(QQ, cartan_type=['A', 2]) sage: sl3.derived_subalgebra() Lie algebra of ['A', 2] in the Chevalley basis sage: sl3 is sl3.derived_subalgebra() @@ -882,24 +925,27 @@ def derived_series(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.derived_series() (An example of a finite dimensional Lie algebra with basis: the 3-dimensional abelian Lie algebra over Rational Field, An example of a finite dimensional Lie algebra with basis: the 0-dimensional abelian Lie algebra over Rational Field - with basis matrix: - []) + with basis matrix: []) :: - sage: L.<x,y> = LieAlgebra(QQ, {('x','y'):{'x':1}}) - sage: L.derived_series() # todo: not implemented - #17416 + sage: # needs sage.combinat sage.modules + sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) + sage: L.derived_series() # not implemented (Lie algebra on 2 generators (x, y) over Rational Field, - Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: - (x,), - Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: - ()) + Subalgebra generated of + Lie algebra on 2 generators (x, y) over Rational Field + with basis: (x,), + Subalgebra generated of + Lie algebra on 2 generators (x, y) over Rational Field + with basis: ()) """ L = [self] while L[-1].dimension() > 0: @@ -940,31 +986,33 @@ def lower_central_series(self, submodule=False): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.derived_series() (An example of a finite dimensional Lie algebra with basis: - the 3-dimensional abelian Lie algebra over Rational Field, + the 3-dimensional abelian Lie algebra over Rational Field, An example of a finite dimensional Lie algebra with basis: - the 0-dimensional abelian Lie algebra over Rational Field - with basis matrix: - []) + the 0-dimensional abelian Lie algebra over Rational Field + with basis matrix: []) The lower central series as submodules:: - sage: L.<x,y> = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: # needs sage.combinat sage.modules + sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) sage: L.lower_central_series(submodule=True) (Sparse vector space of dimension 2 over Rational Field, - Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 0]) + Vector space of degree 2 and dimension 1 over Rational Field + Basis matrix: [1 0]) :: - sage: L.<x,y> = LieAlgebra(QQ, {('x','y'):{'x':1}}) - sage: L.lower_central_series() # todo: not implemented - #17416 + sage: # needs sage.combinat sage.modules + sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) + sage: L.lower_central_series() # not implemented (Lie algebra on 2 generators (x, y) over Rational Field, - Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: - (x,)) + Subalgebra generated of + Lie algebra on 2 generators (x, y) over Rational Field + with basis: (x,)) """ if submodule: L = [self.module()] @@ -983,12 +1031,14 @@ def is_abelian(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.is_abelian() True :: + sage: # needs sage.combinat sage.modules sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) sage: L.is_abelian() False @@ -1006,14 +1056,16 @@ def is_solvable(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.is_solvable() True :: - sage: L.<x,y> = LieAlgebra(QQ, {('x','y'):{'x':1}}) - sage: L.is_solvable() # todo: not implemented - #17416 + sage: # needs sage.combinat sage.modules + sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) + sage: L.is_solvable() # not implemented False """ return not self.derived_series()[-1].dimension() @@ -1027,6 +1079,7 @@ def is_nilpotent(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.is_nilpotent() True @@ -1043,6 +1096,7 @@ def is_semisimple(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.is_semisimple() False @@ -1089,6 +1143,7 @@ def chevalley_eilenberg_complex(self, M=None, dual=False, sparse=True, ncpus=Non EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = lie_algebras.sl(ZZ, 2) sage: C = L.chevalley_eilenberg_complex(); C Chain complex with at most 4 nonzero terms over Integer Ring @@ -1098,14 +1153,16 @@ def chevalley_eilenberg_complex(self, M=None, dual=False, sparse=True, ncpus=Non [0 0 0] [ 0 0 2] [0] 0 <-- C_0 <-------- C_1 <----------- C_2 <---- C_3 <-- 0 + sage: # long time, needs sage.combinat sage.modules sage: L = LieAlgebra(QQ, cartan_type=['C',2]) - sage: C = L.chevalley_eilenberg_complex() # long time - sage: [C.free_module_rank(i) for i in range(11)] # long time + sage: C = L.chevalley_eilenberg_complex() + sage: [C.free_module_rank(i) for i in range(11)] [1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1] - sage: g = lie_algebras.sl(QQ,2) - sage: E,F,H = g.basis() - sage: n = g.subalgebra([F,H]) + sage: # needs sage.combinat sage.modules + sage: g = lie_algebras.sl(QQ, 2) + sage: E, F, H = g.basis() + sage: n = g.subalgebra([F, H]) sage: ascii_art(n.chevalley_eilenberg_complex()) [0] [0 0] [2] @@ -1190,7 +1247,7 @@ def compute_diff(k): zero = [zero] * len(indices) for X in combinations(Ind, k): if not sparse: - ret = list(zero) + ret = list(zero) for i in range(k): Y = list(X) Y.pop(i) @@ -1257,6 +1314,7 @@ def homology(self, deg=None, M=None, sparse=True, ncpus=None): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = lie_algebras.cross_product(QQ) sage: L.homology() {0: Vector space of dimension 1 over Rational Field, @@ -1264,6 +1322,7 @@ def homology(self, deg=None, M=None, sparse=True, ncpus=None): 2: Vector space of dimension 0 over Rational Field, 3: Vector space of dimension 1 over Rational Field} + sage: # needs sage.combinat sage.modules sage: L = lie_algebras.pwitt(GF(5), 5) sage: L.homology() {0: Vector space of dimension 1 over Finite Field of size 5, @@ -1273,6 +1332,7 @@ def homology(self, deg=None, M=None, sparse=True, ncpus=None): 4: Vector space of dimension 0 over Finite Field of size 5, 5: Vector space of dimension 1 over Finite Field of size 5} + sage: # needs sage.combinat sage.modules sage: d = {('x', 'y'): {'y': 2}} sage: L.<x,y> = LieAlgebra(ZZ, d) sage: L.homology() @@ -1322,6 +1382,7 @@ def cohomology(self, deg=None, M=None, sparse=True, ncpus=None): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = lie_algebras.so(QQ, 4) sage: L.cohomology() {0: Vector space of dimension 1 over Rational Field, @@ -1332,6 +1393,7 @@ def cohomology(self, deg=None, M=None, sparse=True, ncpus=None): 5: Vector space of dimension 0 over Rational Field, 6: Vector space of dimension 1 over Rational Field} + sage: # needs sage.combinat sage.modules sage: L = lie_algebras.Heisenberg(QQ, 2) sage: L.cohomology() {0: Vector space of dimension 1 over Rational Field, @@ -1341,6 +1403,7 @@ def cohomology(self, deg=None, M=None, sparse=True, ncpus=None): 4: Vector space of dimension 4 over Rational Field, 5: Vector space of dimension 1 over Rational Field} + sage: # needs sage.combinat sage.modules sage: d = {('x', 'y'): {'y': 2}} sage: L.<x,y> = LieAlgebra(ZZ, d) sage: L.cohomology() @@ -1364,15 +1427,18 @@ def as_finite_dimensional_algebra(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = lie_algebras.cross_product(QQ) - sage: x,y,z = L.basis() + sage: x, y, z = L.basis() sage: F = L.as_finite_dimensional_algebra() - sage: X,Y,Z = F.basis() + sage: X, Y, Z = F.basis() sage: x.bracket(y) Z sage: X * Y Z """ + from sage.matrix.constructor import matrix + K = self._basis_ordering mats = [] R = self.base_ring() @@ -1422,7 +1488,9 @@ def morphism(self, on_generators, codomain=None, base_map=None, check=True): A quotient type Lie algebra morphism :: - sage: L.<X,Y,Z,W> = LieAlgebra(QQ, {('X','Y'): {'Z':1}, ('X','Z'): {'W':1}}) + sage: # needs sage.combinat sage.modules + sage: L.<X,Y,Z,W> = LieAlgebra(QQ, {('X','Y'): {'Z': 1}, + ....: ('X','Z'): {'W': 1}}) sage: K.<A,B> = LieAlgebra(QQ, abelian=True) sage: L.morphism({X: A, Y: B}) Lie algebra morphism: @@ -1436,6 +1504,7 @@ def morphism(self, on_generators, codomain=None, base_map=None, check=True): The reverse map `A \mapsto X`, `B \mapsto Y` does not define a Lie algebra morphism, since `[A,B] = 0`, but `[X,Y] \neq 0`:: + sage: # needs sage.combinat sage.modules sage: K.morphism({A:X, B: Y}) Traceback (most recent call last): ... @@ -1446,10 +1515,12 @@ def morphism(self, on_generators, codomain=None, base_map=None, check=True): on the coefficients, even though it's not a Lie algebra morphism (since it isn't linear):: + sage: # needs sage.combinat sage.modules sage.rings.number_fields sage: R.<x> = ZZ[] sage: K.<i> = NumberField(x^2 + 1) sage: cc = K.hom([-i]) - sage: L.<X,Y,Z,W> = LieAlgebra(K, {('X','Y'): {'Z':1}, ('X','Z'): {'W':1}}) + sage: L.<X,Y,Z,W> = LieAlgebra(K, {('X','Y'): {'Z': 1}, + ....: ('X','Z'): {'W': 1}}) sage: M.<A,B> = LieAlgebra(K, abelian=True) sage: phi = L.morphism({X: A, Y: B}, base_map=cc) sage: phi(X) @@ -1483,11 +1554,13 @@ def universal_polynomials(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) sage: L.universal_polynomials() Finite family {('x', 'x', 'y'): X01*X10 - X00*X11 + X00, ('y', 'x', 'y'): X10} + sage: # needs sage.combinat sage.modules sage: L = LieAlgebra(QQ, cartan_type=['A',1]) sage: list(L.universal_polynomials()) [-2*X01*X10 + 2*X00*X11 - 2*X00, @@ -1500,13 +1573,14 @@ def universal_polynomials(self): -2*X12*X20 + 2*X10*X22 + X21, -2*X12*X21 + 2*X11*X22 - 2*X22] - sage: L = LieAlgebra(QQ, cartan_type=['B',2]) - sage: al = RootSystem(['B',2]).root_lattice().simple_roots() + sage: # long time, needs sage.combinat sage.modules + sage: L = LieAlgebra(QQ, cartan_type=['B', 2]) + sage: al = RootSystem(['B', 2]).root_lattice().simple_roots() sage: k = list(L.basis().keys())[0] - sage: UP = L.universal_polynomials() # long time - sage: len(UP) # long time + sage: UP = L.universal_polynomials() + sage: len(UP) 450 - sage: UP[al[2],al[1],-al[1]] # long time + sage: UP[al[2], al[1], -al[1]] X0_7*X4_1 - X0_1*X4_7 - 2*X0_7*X5_1 + 2*X0_1*X5_7 + X2_7*X7_1 - X2_1*X7_7 - X3_7*X8_1 + X3_1*X8_7 + X0_4 """ @@ -1560,10 +1634,11 @@ def universal_commutative_algebra(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) sage: A = L.universal_commutative_algebra() - sage: a,b,c,d = A.gens() - sage: (a,b,c,d) + sage: a, b, c, d = A.gens() + sage: a, b, c, d (X00bar, X01bar, 0, X11bar) sage: a*d - a 0 @@ -1572,6 +1647,173 @@ def universal_commutative_algebra(self): R = P[0].parent() return R.quotient(P) + def casimir_element(self, order=2, UEA=None, force_generic=False): + r""" + Return the Casimir element in the universal enveloping algebra + of ``self``. + + A *Casimir element* of order `k` is a distinguished basis element + for the center of `U(\mathfrak{g})` of homogeneous degree `k` + (that is, it is an element of `U_k \setminus U_{k-1}`, where + `\{U_i\}_{i=0}^{\infty}` is the natural filtration of + `U(\mathfrak{g})`). When `\mathfrak{g}` is a simple Lie algebra, + then this spans `Z(U(\mathfrak{g}))_k`. + + INPUT: + + - ``order`` -- (default: ``2``) the order of the Casimir element + - ``UEA`` -- (optional) the universal enveloping algebra to + return the result in + - ``force_generic`` -- (default: ``False``) if ``True`` for the + quadratic order, then this uses the default algorithm; otherwise + this is ignored + + ALGORITHM: + + For the quadratic order (i.e., ``order=2``), then this uses + `K^{ij}`, the inverse of the Killing form matrix, to compute + `C_{(2)} = \sum_{i,j} K^{ij} X_i \cdots X_j`, where `\{X_1, \ldots, + X_n\}` is a basis for `\mathfrak{g}`. Otherwise this solves the + system of equations + + .. MATH:: + + f_{aj}^b \kappa^{jc\cdots d} + f_{aj}^c \kappa^{cj\cdots d} + \cdots + f_{aj}^d \kappa^{bc \cdots j} + + for the symmetric tensor `\kappa^{i_1 \cdots i_k}`, where `k` is + the ``order``. This system comes from `[X_i, C_{(k)}] = 0` with + + .. MATH:: + + C_{(k)} = \sum_{i_1, \ldots, i_k}^n + \kappa^{i_1 \cdots i_k} X_{i_1} \cdots X_{i_k}. + + EXAMPLES:: + + sage: # needs sage.combinat sage.modules + sage: L = LieAlgebra(QQ, cartan_type=['A', 1]) + sage: C = L.casimir_element(); C + 1/8*b1^2 + 1/2*b0*b2 - 1/4*b1 + sage: U = L.universal_enveloping_algebra() + sage: all(g * C == C * g for g in U.gens()) + True + sage: U = L.pbw_basis() + sage: C = L.casimir_element(UEA=U); C + 1/2*PBW[alpha[1]]*PBW[-alpha[1]] + 1/8*PBW[alphacheck[1]]^2 + - 1/4*PBW[alphacheck[1]] + sage: all(g * C == C * g for g in U.algebra_generators()) + True + + sage: # needs sage.combinat sage.modules + sage: L = LieAlgebra(QQ, cartan_type=['B', 2]) + sage: U = L.pbw_basis() + sage: C = L.casimir_element(UEA=U) + sage: all(g * C == C * g for g in U.algebra_generators()) + True + + sage: # needs sage.combinat sage.modules + sage: L = LieAlgebra(QQ, cartan_type=['C', 3]) + sage: U = L.pbw_basis() + sage: C = L.casimir_element(UEA=U) + sage: all(g * C == C * g for g in U.algebra_generators()) + True + + sage: # needs sage.combinat sage.modules + sage: L = LieAlgebra(QQ, cartan_type=['A', 1]) + sage: C4 = L.casimir_element(order=4, UEA=L.pbw_basis()); C4 + 4*PBW[alpha[1]]^2*PBW[-alpha[1]]^2 + + 2*PBW[alpha[1]]*PBW[alphacheck[1]]^2*PBW[-alpha[1]] + + 1/4*PBW[alphacheck[1]]^4 - PBW[alphacheck[1]]^3 + - 4*PBW[alpha[1]]*PBW[-alpha[1]] + 2*PBW[alphacheck[1]] + sage: all(g * C4 == C4 * g for g in L.pbw_basis().algebra_generators()) + True + + sage: # needs sage.combinat sage.modules + sage: L = lie_algebras.Heisenberg(QQ, 2) + sage: L.casimir_element() + 0 + + TESTS:: + + sage: # needs sage.combinat sage.modules + sage: L = LieAlgebra(QQ, cartan_type=['A', 1]) + sage: L.casimir_element(1) + Traceback (most recent call last): + ... + ValueError: invalid order + sage: 4 * L.casimir_element() == L.casimir_element(force_generic=True) + True + + .. TODO:: + + Use the symmetry of the tensor to reduce the number of + equations and/or variables to solve. + """ + if order < 2: + raise ValueError("invalid order") + + if UEA is None: + UEA = self.universal_enveloping_algebra() + + B = self.basis() + + if order == 2 and not force_generic: + # Special case for the quadratic using the Killing form + try: + K = self.killing_form_matrix().inverse() + return UEA.sum(K[i, j] * UEA(x) * UEA(y) for i, x in enumerate(B) + for j, y in enumerate(B) if K[i, j]) + except (ValueError, TypeError, ZeroDivisionError): + # fall back to finding solutions to the system of equations + pass + + keys = self.get_order() + dim = len(keys) + s_coeffs = dict(self.structure_coefficients()) + for k in list(s_coeffs.keys()): + s_coeffs[k[1], k[0]] = -s_coeffs[k] + + # setup the equations + from sage.matrix.constructor import matrix + from itertools import product + eqns = matrix.zero(self.base_ring(), dim**(order+1), dim**order, sparse=True) + for ii, p in enumerate(product(range(dim), repeat=order+1)): + i = p[0] + a = keys[i] + for j, b in enumerate(keys): + if (a, b) not in s_coeffs: + continue + sc_val = s_coeffs[a, b] + for k in range(order): + c = keys[p[k+1]] + if not sc_val[c]: + continue + pp = list(p[1:]) + pp[k] = j + jj = sum(dim**m * pp[m] for m in range(order)) + eqns[ii, jj] += sc_val[c] + + ker = eqns.right_kernel() + if ker.dimension() == 0: + return self.zero() + + tens = ker.basis()[0] + del eqns # no need to hold onto the matrix + + def to_prod(index): + coeff = tens[index] + p = [0] * order + base = dim ** (order-1) + for i in range(order): + p[i] = index // base + index %= base + base //= dim + p.reverse() + return coeff * UEA.prod(UEA(B[keys[i]]) for i in p) + + return UEA.sum(to_prod(index) for index in tens.support()) + class ElementMethods: def adjoint_matrix(self, sparse=False): # In #11111 (more or less) by using matrix of a morphism """ @@ -1579,6 +1821,7 @@ def adjoint_matrix(self, sparse=False): # In #11111 (more or less) by using matr EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.an_element().adjoint_matrix() [0 0 0] @@ -1589,7 +1832,8 @@ def adjoint_matrix(self, sparse=False): # In #11111 (more or less) by using matr :: - sage: L.<x,y> = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: # needs sage.combinat sage.modules + sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) sage: x.adjoint_matrix() [0 1] [0 0] @@ -1599,6 +1843,7 @@ def adjoint_matrix(self, sparse=False): # In #11111 (more or less) by using matr We verify that this forms a representation:: + sage: # needs sage.combinat sage.modules sage: sl3 = lie_algebras.sl(QQ, 3) sage: e1, e2 = sl3.e(1), sl3.e(2) sage: e12 = e1.bracket(e2) @@ -1606,6 +1851,8 @@ def adjoint_matrix(self, sparse=False): # In #11111 (more or less) by using matr sage: E1 * E2 - E2 * E1 == e12.adjoint_matrix() True """ + from sage.matrix.constructor import matrix + P = self.parent() basis = P.basis() return matrix(self.base_ring(), @@ -1624,13 +1871,14 @@ def to_vector(self, order=None, sparse=False): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.an_element().to_vector() (0, 0, 0) - sage: L.an_element().to_vector(sparse=True) (0, 0, 0) + sage: # needs sage.combinat sage.groupssage.modules sage: D = DescentAlgebra(QQ, 4).D() sage: L = LieAlgebra(associative=D) sage: L.an_element().to_vector() @@ -1641,6 +1889,7 @@ def to_vector(self, order=None, sparse=False): Check that the error raised agrees with the one from ``monomial_coefficients()`` (see :trac:`25007`):: + sage: # needs sage.combinat sage.modules sage: L = lie_algebras.sp(QQ, 4, representation='matrix') sage: x = L.an_element() sage: x.monomial_coefficients() @@ -1681,9 +1930,11 @@ def ambient(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: # needs sage.combinat sage.modules + sage: C = LieAlgebras(QQ).FiniteDimensional().WithBasis() + sage: L = C.example() sage: a, b, c = L.lie_algebra_generators() - sage: S = L.subalgebra([2*a+b, b + c]) + sage: S = L.subalgebra([2*a + b, b + c]) sage: S.ambient() == L True """ @@ -1695,9 +1946,11 @@ def basis_matrix(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: # needs sage.combinat sage.modules + sage: C = LieAlgebras(QQ).FiniteDimensional().WithBasis() + sage: L = C.example() sage: a, b, c = L.lie_algebra_generators() - sage: S = L.subalgebra([2*a+b, b + c]) + sage: S = L.subalgebra([2*a + b, b + c]) sage: S.basis_matrix() [ 1 0 -1/2] [ 0 1 1] diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 0ebca2f2dde..1462073c5f2 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -46,8 +46,8 @@ def gens(self): EXAMPLES:: - sage: F = CombinatorialFreeModule(ZZ, ['a', 'b', 'c']) - sage: F.gens() + sage: F = CombinatorialFreeModule(ZZ, ['a', 'b', 'c']) # needs sage.modules + sage: F.gens() # needs sage.modules (B['a'], B['b'], B['c']) """ return tuple(self.basis()) @@ -91,11 +91,12 @@ def annihilator(self, S, action=operator.mul, side='right', category=None): EXAMPLES:: + sage: # needs sage.modules sage: F = FiniteDimensionalAlgebrasWithBasis(QQ).example(); F An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: x,y,a,b = F.basis() + sage: x, y, a, b = F.basis() sage: A = F.annihilator([a + 3*b + 2*y]); A Free module generated by {0} over Rational Field sage: [b.lift() for b in A.basis()] @@ -104,6 +105,7 @@ def annihilator(self, S, action=operator.mul, side='right', category=None): The category can be used to specify other properties of this subspace, like that this is a subalgebra:: + sage: # needs sage.modules sage: center = F.annihilator(F.basis(), F.bracket, ....: category=Algebras(QQ).Subobjects()) sage: (e,) = center.basis() @@ -114,12 +116,13 @@ def annihilator(self, S, action=operator.mul, side='right', category=None): Taking annihilator is order reversing for inclusion:: + sage: # needs sage.modules sage: A = F.annihilator([]); A .rename("A") sage: Ax = F.annihilator([x]); Ax .rename("Ax") sage: Ay = F.annihilator([y]); Ay .rename("Ay") sage: Axy = F.annihilator([x,y]); Axy.rename("Axy") - sage: P = Poset(([A, Ax, Ay, Axy], attrcall("is_submodule"))) - sage: sorted(P.cover_relations(), key=str) + sage: P = Poset(([A, Ax, Ay, Axy], attrcall("is_submodule"))) # needs sage.combinat sage.graphs + sage: sorted(P.cover_relations(), key=str) # needs sage.combinat sage.graphs [[Ax, A], [Axy, Ax], [Axy, Ay], [Ay, A]] """ return self.submodule(self.annihilator_basis(S, action, side), @@ -147,6 +150,7 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): By default, the action is the standard `*` operation. So our first example is about an algebra:: + sage: # needs sage.graphs sage.modules sage: F = FiniteDimensionalAlgebrasWithBasis(QQ).example(); F An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver @@ -156,39 +160,40 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): In this algebra, multiplication on the right by `x` annihilates all basis elements but `x`:: - sage: x*x, y*x, a*x, b*x + sage: x*x, y*x, a*x, b*x # needs sage.graphs sage.modules (x, 0, 0, 0) So the annihilator is the subspace spanned by `y`, `a`, and `b`:: - sage: F.annihilator_basis([x]) + sage: F.annihilator_basis([x]) # needs sage.graphs sage.modules (y, a, b) The same holds for `a` and `b`:: - sage: x*a, y*a, a*a, b*a + sage: x*a, y*a, a*a, b*a # needs sage.graphs sage.modules (a, 0, 0, 0) - sage: F.annihilator_basis([a]) + sage: F.annihilator_basis([a]) # needs sage.graphs sage.modules (y, a, b) On the other hand, `y` annihilates only `x`:: - sage: F.annihilator_basis([y]) + sage: F.annihilator_basis([y]) # needs sage.graphs sage.modules (x,) Here is a non trivial annihilator:: - sage: F.annihilator_basis([a + 3*b + 2*y]) + sage: F.annihilator_basis([a + 3*b + 2*y]) # needs sage.graphs sage.modules (-1/2*a - 3/2*b + x,) Let's check it:: - sage: (-1/2*a - 3/2*b + x) * (a + 3*b + 2*y) + sage: (-1/2*a - 3/2*b + x) * (a + 3*b + 2*y) # needs sage.graphs sage.modules 0 Doing the same calculations on the left exchanges the roles of `x` and `y`:: + sage: # needs sage.graphs sage.modules sage: F.annihilator_basis([y], side="left") (x, a, b) sage: F.annihilator_basis([a], side="left") @@ -197,27 +202,29 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): (x, a, b) sage: F.annihilator_basis([x], side="left") (y,) - sage: F.annihilator_basis([a+3*b+2*x], side="left") + sage: F.annihilator_basis([a + 3*b + 2*x], side="left") (-1/2*a - 3/2*b + y,) By specifying an inner product, this method can be used to compute the orthogonal of a subspace:: + sage: # needs sage.graphs sage.modules sage: x,y,a,b = F.basis() - sage: def scalar(u,v): return vector([sum(u[i]*v[i] for i in F.basis().keys())]) - sage: F.annihilator_basis([x+y, a+b], scalar) + sage: def scalar(u,v): + ....: return vector([sum(u[i]*v[i] for i in F.basis().keys())]) + sage: F.annihilator_basis([x + y, a + b], scalar) (x - y, a - b) By specifying the standard Lie bracket as action, one can compute the commutator of a subspace of `F`:: - sage: F.annihilator_basis([a+b], action=F.bracket) + sage: F.annihilator_basis([a + b], action=F.bracket) # needs sage.graphs sage.modules (x + y, a, b) In particular one can compute a basis of the center of the algebra. In our example, it is reduced to the identity:: - sage: F.annihilator_basis(F.algebra_generators(), action=F.bracket) + sage: F.annihilator_basis(F.algebra_generators(), action=F.bracket) # needs sage.graphs sage.modules (x + y,) But see also @@ -251,13 +258,13 @@ def _dense_free_module(self, base_ring=None): EXAMPLES:: - sage: C = CombinatorialFreeModule(QQ['x'], ['a','b','c']); C + sage: C = CombinatorialFreeModule(QQ['x'], ['a','b','c']); C # needs sage.modules Free module generated by {'a', 'b', 'c'} over Univariate Polynomial Ring in x over Rational Field - sage: C._dense_free_module() + sage: C._dense_free_module() # needs sage.modules Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field - sage: C._dense_free_module(QQ['x,y']) + sage: C._dense_free_module(QQ['x,y']) # needs sage.modules Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring in x, y over Rational Field """ @@ -272,10 +279,11 @@ def from_vector(self, vector, order=None, coerce=True): EXAMPLES:: - sage: p_mult = matrix([[0,0,0],[0,0,-1],[0,0,0]]) - sage: q_mult = matrix([[0,0,1],[0,0,0],[0,0,0]]) - sage: A = algebras.FiniteDimensional(QQ, [p_mult, q_mult, matrix(QQ,3,3)], - ....: 'p,q,z') + sage: # needs sage.modules + sage: p_mult = matrix([[0,0,0], [0,0,-1], [0,0,0]]) + sage: q_mult = matrix([[0,0,1], [0,0,0], [0,0,0]]) + sage: A = algebras.FiniteDimensional( + ....: QQ, [p_mult, q_mult, matrix(QQ, 3, 3)], 'p,q,z') sage: A.from_vector(vector([1,0,2])) p + 2*z """ @@ -312,9 +320,10 @@ def echelon_form(self, elements, row_reduced=False, order=None): EXAMPLES:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() - sage: V = X.echelon_form([x[0]-x[1], x[0]-x[2],x[1]-x[2]]); V + sage: V = X.echelon_form([x[0]-x[1], x[0]-x[2], x[1]-x[2]]); V [x[0] - x[2], x[1] - x[2]] sage: matrix(list(map(vector, V))) [ 1 0 -1] @@ -322,6 +331,7 @@ def echelon_form(self, elements, row_reduced=False, order=None): :: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(ZZ, [1,2,3,4]) sage: B = F.basis() sage: elements = [B[1]-17*B[2]+6*B[3], B[1]-17*B[2]+B[4]] @@ -330,24 +340,24 @@ def echelon_form(self, elements, row_reduced=False, order=None): :: - sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) - sage: a,b,c = F.basis() - sage: F.echelon_form([8*a+b+10*c, -3*a+b-c, a-b-c]) + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) # needs sage.modules + sage: a,b,c = F.basis() # needs sage.modules + sage: F.echelon_form([8*a+b+10*c, -3*a+b-c, a-b-c]) # needs sage.modules [B['a'] + B['c'], B['b'] + 2*B['c']] :: sage: R.<x,y> = QQ[] - sage: C = CombinatorialFreeModule(R, range(3), prefix='x') - sage: x = C.basis() - sage: C.echelon_form([x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]) + sage: C = CombinatorialFreeModule(R, range(3), prefix='x') # needs sage.modules + sage: x = C.basis() # needs sage.modules + sage: C.echelon_form([x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]) # needs sage.modules sage.rings.function_field [x[0] - x[2], x[1] - x[2]] :: - sage: M = MatrixSpace(QQ, 3, 3) - sage: A = M([[0, 0, 2], [0, 0, 0], [0, 0, 0]]) - sage: M.echelon_form([A, A]) + sage: M = MatrixSpace(QQ, 3, 3) # needs sage.modules + sage: A = M([[0, 0, 2], [0, 0, 0], [0, 0, 0]]) # needs sage.modules + sage: M.echelon_form([A, A]) # needs sage.modules [ [0 0 1] [0 0 0] @@ -358,8 +368,8 @@ def echelon_form(self, elements, row_reduced=False, order=None): We convert the input elements to ``self``:: - sage: E.<x,y,z> = ExteriorAlgebra(QQ) - sage: E.echelon_form([1, x + 2]) + sage: E.<x,y,z> = ExteriorAlgebra(QQ) # needs sage.modules + sage: E.echelon_form([1, x + 2]) # needs sage.modules [1, x] """ # Make sure elements consists of elements of ``self`` @@ -410,6 +420,7 @@ def invariant_module(self, S, action=operator.mul, action_on_basis=None, We build the invariant module of the permutation representation of the symmetric group:: + sage: # needs sage.groups sage.modules sage: G = SymmetricGroup(3); G.rename('S3') sage: M = FreeModule(ZZ, [1,2,3], prefix='M'); M.rename('M') sage: action = lambda g, x: M.term(g(x)) @@ -419,7 +430,6 @@ def invariant_module(self, S, action=operator.mul, action_on_basis=None, Finite family {0: B[0]} sage: [I.lift(b) for b in I.basis()] [M[1] + M[2] + M[3]] - sage: G.rename(); M.rename() # reset the names We can construct the invariant module of any module that has @@ -427,18 +437,23 @@ def invariant_module(self, S, action=operator.mul, action_on_basis=None, group `G = D_4` and the subgroup `H < G` of all rotations. We construct the `H`-invariant module of the group algebra `\QQ[G]`:: + sage: # needs sage.groups sage: G = groups.permutation.Dihedral(4) sage: H = G.subgroup(G.gen(0)) sage: H - Subgroup generated by [(1,2,3,4)] of (Dihedral group of order 8 as a permutation group) + Subgroup generated by [(1,2,3,4)] + of (Dihedral group of order 8 as a permutation group) sage: H.cardinality() 4 + + sage: # needs sage.groups sage.modules sage: A = G.algebra(QQ) sage: I = A.invariant_module(H) sage: [I.lift(b) for b in I.basis()] [() + (1,2,3,4) + (1,3)(2,4) + (1,4,3,2), (2,4) + (1,2)(3,4) + (1,3) + (1,4)(2,3)] - sage: all(h * I.lift(b) == I.lift(b) for b in I.basis() for h in H) + sage: all(h * I.lift(b) == I.lift(b) + ....: for b in I.basis() for h in H) True """ if action_on_basis is not None: @@ -480,10 +495,12 @@ def twisted_invariant_module(self, G, chi, EXAMPLES:: + sage: # needs sage.groups sage.modules sage: M = CombinatorialFreeModule(QQ, [1,2,3]) sage: G = SymmetricGroup(3) - sage: def action(g,x): return(M.term(g(x))) # permute coordinates - sage: T = M.twisted_invariant_module(G, [2,0,-1], action_on_basis=action) + sage: def action(g,x): return(M.term(g(x))) # permute coordinates + sage: T = M.twisted_invariant_module(G, [2,0,-1], + ....: action_on_basis=action) sage: import __main__; __main__.action = action sage: TestSuite(T).run() """ @@ -514,6 +531,7 @@ def dense_coefficient_list(self, order=None): EXAMPLES:: + sage: # needs sage.modules sage: v = vector([0, -1, -3]) sage: v.dense_coefficient_list() [0, -1, -3] @@ -535,6 +553,7 @@ def _vector_(self, order=None): EXAMPLES:: + sage: # needs sage.modules sage: v = vector([0, -1, -3]) sage: v._vector_() (0, -1, -3) @@ -577,10 +596,12 @@ def matrix(self, base_ring=None, side="left"): EXAMPLES:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(ZZ, [1,2]); x = X.basis() sage: Y = CombinatorialFreeModule(ZZ, [3,4]); y = Y.basis() - sage: phi = X.module_morphism(on_basis = {1: y[3] + 3*y[4], 2: 2*y[3] + 5*y[4]}.__getitem__, - ....: codomain = Y) + sage: phi = X.module_morphism(on_basis={1: y[3] + 3*y[4], + ....: 2: 2*y[3] + 5*y[4]}.__getitem__, + ....: codomain=Y) sage: phi.matrix() [1 2] [3 5] @@ -588,19 +609,19 @@ def matrix(self, base_ring=None, side="left"): [1 3] [2 5] - sage: phi.matrix().parent() + sage: phi.matrix().parent() # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Integer Ring - sage: phi.matrix(QQ).parent() + sage: phi.matrix(QQ).parent() # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Rational Field The resulting matrix is immutable:: - sage: phi.matrix().is_mutable() + sage: phi.matrix().is_mutable() # needs sage.modules False The zero morphism has a zero matrix:: - sage: Hom(X,Y).zero().matrix() + sage: Hom(X, Y).zero().matrix() # needs sage.modules [0 0] [0 0] @@ -609,10 +630,11 @@ def matrix(self, base_ring=None, side="left"): Add support for morphisms where the codomain has a different base ring than the domain:: - sage: Y = CombinatorialFreeModule(QQ, [3,4]); y = Y.basis() - sage: phi = X.module_morphism(on_basis = {1: y[3] + 3*y[4], 2: 2*y[3] + 5/2*y[4]}.__getitem__, - ....: codomain = Y) - sage: phi.matrix().parent() # todo: not implemented + sage: Y = CombinatorialFreeModule(QQ, [3,4]); y = Y.basis() # needs sage.modules + sage: phi = X.module_morphism(on_basis={1: y[3] + 3*y[4], # needs sage.modules + ....: 2: 2*y[3] + 5/2*y[4]}.__getitem__, + ....: codomain=Y) + sage: phi.matrix().parent() # not implemented # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Rational Field This currently does not work because, in this case, @@ -620,20 +642,21 @@ def matrix(self, base_ring=None, side="left"): additive groups (i.e. the intersection of the categories of modules over `\ZZ` and over `\QQ`):: - sage: phi.parent().homset_category() + sage: phi.parent().homset_category() # needs sage.modules Category of commutative additive semigroups - sage: phi.parent().homset_category() # todo: not implemented + sage: phi.parent().homset_category() # not implemented, needs sage.modules Category of finite dimensional modules with basis over Integer Ring TESTS: Check that :trac:`23216` is fixed:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, []) sage: Y = CombinatorialFreeModule(QQ, [1,2,3]) - sage: Hom(X,Y).zero().matrix() + sage: Hom(X, Y).zero().matrix() [] - sage: Hom(X,Y).zero().matrix().parent() + sage: Hom(X, Y).zero().matrix().parent() Full MatrixSpace of 3 by 0 dense matrices over Rational Field """ if base_ring is None: @@ -662,11 +685,12 @@ def __invert__(self): EXAMPLES:: + sage: # needs sage.modules sage: category = FiniteDimensionalModulesWithBasis(ZZ) - sage: X = CombinatorialFreeModule(ZZ, [1,2], category = category); X.rename("X"); x = X.basis() - sage: Y = CombinatorialFreeModule(ZZ, [3,4], category = category); Y.rename("Y"); y = Y.basis() - sage: phi = X.module_morphism(on_basis = {1: y[3] + 3*y[4], 2: 2*y[3] + 5*y[4]}.__getitem__, - ....: codomain = Y, category = category) + sage: X = CombinatorialFreeModule(ZZ, [1,2], category=category); X.rename("X"); x = X.basis() + sage: Y = CombinatorialFreeModule(ZZ, [3,4], category=category); Y.rename("Y"); y = Y.basis() + sage: phi = X.module_morphism(on_basis={1: y[3] + 3*y[4], 2: 2*y[3] + 5*y[4]}.__getitem__, + ....: codomain=Y, category=category) sage: psi = ~phi sage: psi Generic morphism: @@ -688,16 +712,16 @@ def __invert__(self): We check that this function complains if the morphism is not invertible:: - sage: phi = X.module_morphism(on_basis = {1: y[3] + y[4], 2: y[3] + y[4]}.__getitem__, - ....: codomain = Y, category = category) - sage: ~phi + sage: phi = X.module_morphism(on_basis={1: y[3] + y[4], 2: y[3] + y[4]}.__getitem__, # needs sage.modules + ....: codomain=Y, category=category) + sage: ~phi # needs sage.modules Traceback (most recent call last): ... RuntimeError: morphism is not invertible - sage: phi = X.module_morphism(on_basis = {1: y[3] + y[4], 2: y[3] + 5*y[4]}.__getitem__, - ....: codomain = Y, category = category) - sage: ~phi + sage: phi = X.module_morphism(on_basis={1: y[3] + y[4], 2: y[3] + 5*y[4]}.__getitem__, # needs sage.modules + ....: codomain=Y, category=category) + sage: ~phi # needs sage.modules Traceback (most recent call last): ... RuntimeError: morphism is not invertible @@ -717,9 +741,9 @@ def kernel_basis(self): EXAMPLES:: - sage: SGA = SymmetricGroupAlgebra(QQ, 3) - sage: f = SGA.module_morphism(lambda x: SGA(x**2), codomain=SGA) - sage: f.kernel_basis() + sage: SGA = SymmetricGroupAlgebra(QQ, 3) # needs sage.groups sage.modules + sage: f = SGA.module_morphism(lambda x: SGA(x**2), codomain=SGA) # needs sage.groups sage.modules + sage: f.kernel_basis() # needs sage.groups sage.modules ([1, 2, 3] - [3, 2, 1], [1, 3, 2] - [3, 2, 1], [2, 1, 3] - [3, 2, 1]) """ return tuple(map( self.domain().from_vector, @@ -731,6 +755,7 @@ def kernel(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: SGA = SymmetricGroupAlgebra(QQ, 3) sage: f = SGA.module_morphism(lambda x: SGA(x**2), codomain=SGA) sage: K = f.kernel() @@ -749,9 +774,9 @@ def image_basis(self): EXAMPLES:: - sage: SGA = SymmetricGroupAlgebra(QQ, 3) - sage: f = SGA.module_morphism(lambda x: SGA(x**2), codomain=SGA) - sage: f.image_basis() + sage: SGA = SymmetricGroupAlgebra(QQ, 3) # needs sage.groups sage.modules + sage: f = SGA.module_morphism(lambda x: SGA(x**2), codomain=SGA) # needs sage.groups sage.modules + sage: f.image_basis() # needs sage.groups sage.modules ([1, 2, 3], [2, 3, 1], [3, 1, 2]) """ C = self.codomain() @@ -763,9 +788,9 @@ def image(self): EXAMPLES:: - sage: SGA = SymmetricGroupAlgebra(QQ, 3) - sage: f = SGA.module_morphism(lambda x: SGA(x**2), codomain=SGA) - sage: f.image() + sage: SGA = SymmetricGroupAlgebra(QQ, 3) # needs sage.groups sage.modules + sage: f = SGA.module_morphism(lambda x: SGA(x**2), codomain=SGA) # needs sage.groups sage.modules + sage: f.image() # needs sage.groups sage.modules Free module generated by {0, 1, 2} over Rational Field """ C = self.codomain() @@ -781,10 +806,12 @@ def extra_super_categories(self): EXAMPLES:: - sage: ModulesWithBasis(ZZ).FiniteDimensional().TensorProducts().extra_super_categories() + sage: C = ModulesWithBasis(ZZ).FiniteDimensional().TensorProducts() + sage: C.extra_super_categories() [Category of finite dimensional modules with basis over Integer Ring] - sage: ModulesWithBasis(ZZ).FiniteDimensional().TensorProducts().FiniteDimensional() - Category of tensor products of finite dimensional modules with basis over Integer Ring + sage: C.FiniteDimensional() + Category of tensor products of + finite dimensional modules with basis over Integer Ring """ return [self.base_category()] diff --git a/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py index fe0ad9f3d21..78d801a5ef4 100644 --- a/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py @@ -60,14 +60,16 @@ def _test_nilpotency(self, **options): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebra(QQ, {('X','Y'): {'Z': 1}}, nilpotent=True) sage: L._test_nilpotency() sage: L = LieAlgebra(QQ, {('X','Y'): {'Z': 1}}, - ....: nilpotent=True, step = 3) + ....: nilpotent=True, step=3) sage: L._test_nilpotency() Traceback (most recent call last): ... - AssertionError: claimed nilpotency step 3 does not match the actual nilpotency step 2 + AssertionError: claimed nilpotency step 3 + does not match the actual nilpotency step 2 sage: L = LieAlgebra(QQ, {('X','Y'): {'X': 1}}, nilpotent=True) sage: L._test_nilpotency() Traceback (most recent call last): @@ -100,28 +102,30 @@ def lie_group(self, name='G', **kwds): We define the Heisenberg group:: - sage: L = lie_algebras.Heisenberg(QQ, 1) - sage: G = L.lie_group('G'); G # optional - sage.symbolic + sage: L = lie_algebras.Heisenberg(QQ, 1) # needs sage.combinat sage.modules + sage: G = L.lie_group('G'); G # needs sage.combinat sage.modules sage.symbolic Lie group G of Heisenberg algebra of rank 1 over Rational Field We test multiplying elements of the group:: - sage: p,q,z = L.basis() # optional - sage.symbolic - sage: g = G.exp(p); g # optional - sage.symbolic + sage: # needs sage.combinat sage.modules sage.symbolic + sage: p, q, z = L.basis() + sage: g = G.exp(p); g exp(p1) - sage: h = G.exp(q); h # optional - sage.symbolic + sage: h = G.exp(q); h exp(q1) - sage: g*h # optional - sage.symbolic + sage: g * h exp(p1 + q1 + 1/2*z) We extend an element of the Lie algebra to a left-invariant vector field:: - sage: X = G.left_invariant_extension(2*p + 3*q, name='X'); X # optional - sage.symbolic - Vector field X on the Lie group G of Heisenberg algebra of rank 1 over Rational Field - sage: X.at(G.one()).display() # optional - sage.symbolic + sage: X = G.left_invariant_extension(2*p + 3*q, name='X'); X # needs sage.combinat sage.modules sage.symbolic + Vector field X on the Lie group G of + Heisenberg algebra of rank 1 over Rational Field + sage: X.at(G.one()).display() # needs sage.combinat sage.modules sage.symbolic X = 2 โˆ‚/โˆ‚x_0 + 3 โˆ‚/โˆ‚x_1 - sage: X.display() # optional - sage.symbolic + sage: X.display() # needs sage.combinat sage.modules sage.symbolic X = 2 โˆ‚/โˆ‚x_0 + 3 โˆ‚/โˆ‚x_1 + (3/2*x_0 - x_1) โˆ‚/โˆ‚x_2 .. SEEALSO:: @@ -137,6 +141,7 @@ def step(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebra(QQ, {('X','Y'): {'Z': 1}}, nilpotent=True) sage: L.step() 2 @@ -154,8 +159,8 @@ def is_nilpotent(self): EXAMPLES:: - sage: L = LieAlgebra(QQ, {('x','y'): {'z': 1}}, nilpotent=True) - sage: L.is_nilpotent() + sage: L = LieAlgebra(QQ, {('x','y'): {'z': 1}}, nilpotent=True) # needs sage.combinat sage.modules + sage: L.is_nilpotent() # needs sage.combinat sage.modules True """ return True diff --git a/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py index 36ad56fdaae..531ee7145a4 100644 --- a/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py @@ -49,13 +49,13 @@ def radical_basis(self, **keywords): EXAMPLES:: - sage: A = SymmetricGroup(4).algebra(QQ) - sage: A.radical_basis() + sage: A = SymmetricGroup(4).algebra(QQ) # needs sage.groups sage.modules + sage: A.radical_basis() # needs sage.groups sage.modules () TESTS:: - sage: A.radical_basis.__module__ + sage: A.radical_basis.__module__ # needs sage.groups sage.modules 'sage.categories.finite_dimensional_semisimple_algebras_with_basis' """ return () @@ -81,6 +81,7 @@ def central_orthogonal_idempotents(self): acts on `V_i` as multiplication by the `i`-th power of a cube root of unity:: + sage: # needs sage.groups sage.rings.number_field sage: R = CyclotomicField(3) sage: A3 = AlternatingGroup(3).algebra(R) sage: idempotents = A3.central_orthogonal_idempotents() @@ -94,6 +95,7 @@ def central_orthogonal_idempotents(self): For the semisimple quotient of a quiver algebra, we recover the vertices of the quiver:: + sage: # needs sage.graphs sage.modules sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing @@ -105,7 +107,6 @@ def central_orthogonal_idempotents(self): return tuple([x.lift() for x in self.center().central_orthogonal_idempotents()]) - class Commutative(CategoryWithAxiom_over_base_ring): class ParentMethods: @@ -158,8 +159,8 @@ def _orthogonal_decomposition(self, generators=None): center of the algebra of the symmetric group `S_4`:: - sage: Z4 = SymmetricGroup(4).algebra(QQ).center() - sage: Z4._orthogonal_decomposition() + sage: Z4 = SymmetricGroup(4).algebra(QQ).center() # needs sage.groups sage.modules + sage: Z4._orthogonal_decomposition() # needs sage.groups sage.modules (B[0] + B[1] + B[2] + B[3] + B[4], B[0] + 1/3*B[1] - 1/3*B[2] - 1/3*B[4], B[0] + B[2] - 1/2*B[3], @@ -202,7 +203,7 @@ def _orthogonal_decomposition(self, generators=None): for subalgebra in subalgebras for idempotent in subalgebra._orthogonal_decomposition()]) # TODO: Should this be an assertion check? - raise Exception("Unable to fully decompose %s!"%self) + raise Exception("Unable to fully decompose %s!" % self) @cached_method def central_orthogonal_idempotents(self): @@ -220,6 +221,7 @@ def central_orthogonal_idempotents(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: A4 = SymmetricGroup(4).algebra(QQ) sage: Z4 = A4.center() sage: idempotents = Z4.central_orthogonal_idempotents() @@ -234,7 +236,7 @@ def central_orthogonal_idempotents(self): recognize among them the sum and alternating sum of all permutations:: - sage: [e.lift() for e in idempotents] + sage: [e.lift() for e in idempotents] # needs sage.groups sage.modules [1/24*() + 1/24*(3,4) + 1/24*(2,3) + 1/24*(2,3,4) + 1/24*(2,4,3) + 1/24*(2,4) + 1/24*(1,2) + 1/24*(1,2)(3,4) + 1/24*(1,2,3) + 1/24*(1,2,3,4) + 1/24*(1,2,4,3) + 1/24*(1,2,4) + 1/24*(1,3,2) @@ -252,7 +254,7 @@ def central_orthogonal_idempotents(self): We check that they indeed form a decomposition of the identity of `Z_4` into orthogonal idempotents:: - sage: Z4.is_identity_decomposition_into_orthogonal_idempotents(idempotents) + sage: Z4.is_identity_decomposition_into_orthogonal_idempotents(idempotents) # needs sage.groups sage.modules True """ return tuple([(e.leading_coefficient()/(e*e).leading_coefficient())*e diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index 4a872cf2fbf..8a3c0e42ca5 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -61,7 +61,7 @@ def _call_(self, X): sage: FiniteEnumeratedSets()(GF(3)) Finite Field of size 3 - sage: Partitions(3) + sage: Partitions(3) # needs sage.combinat Partitions of the integer 3 For now, lists, tuples, sets, Sets are coerced into finite @@ -88,7 +88,7 @@ def __len__(self): sage: len(GF(5)) 5 - sage: len(MatrixSpace(GF(2), 3, 3)) + sage: len(MatrixSpace(GF(2), 3, 3)) # needs sage.modules 512 """ return int(self.cardinality()) @@ -524,7 +524,7 @@ def _last_from_unrank(self): sage: C._last_from_unrank() 3 """ - return self.unrank(self.cardinality() -1) + return self.unrank(self.cardinality() - 1) def _test_enumerated_set_iter_cardinality(self, **options): """ @@ -590,17 +590,17 @@ class ParentMethods: inherit various methods from `Sets.CartesianProducts` and not from :class:`EnumeratedSets.Finite`:: - sage: C = cartesian_product([Partitions(10), Permutations(20)]) - sage: C in EnumeratedSets().Finite() + sage: C = cartesian_product([Partitions(10), Permutations(20)]) # needs sage.combinat + sage: C in EnumeratedSets().Finite() # needs sage.combinat True - sage: C.random_element.__module__ + sage: C.random_element.__module__ # needs sage.combinat 'sage.categories.sets_cat' - sage: C.cardinality.__module__ + sage: C.cardinality.__module__ # needs sage.combinat 'sage.categories.sets_cat' - sage: C.__iter__.__module__ + sage: C.__iter__.__module__ # needs sage.combinat 'sage.categories.sets_cat' """ random_element = raw_getattr(Sets.CartesianProducts.ParentMethods, "random_element") @@ -613,8 +613,9 @@ def last(self): EXAMPLES:: - sage: C = cartesian_product([Zmod(42), Partitions(10), IntegerRange(5)]) - sage: C.last() + sage: C = cartesian_product([Zmod(42), Partitions(10), # needs sage.combinat + ....: IntegerRange(5)]) + sage: C.last() # needs sage.combinat (41, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 4) """ return self._cartesian_product_of_elements( @@ -654,6 +655,7 @@ def rank(self, x): 152 153 + sage: # needs sage.combinat sage: F1 = FiniteEnumeratedSet('abcdefgh') sage: F2 = IntegerRange(250) sage: F3 = Partitions(20) diff --git a/src/sage/categories/finite_fields.py b/src/sage/categories/finite_fields.py index 25a93c8b960..d9333c80707 100644 --- a/src/sage/categories/finite_fields.py +++ b/src/sage/categories/finite_fields.py @@ -67,7 +67,7 @@ def __contains__(self, x): """ EXAMPLES:: - sage: GF(4, "a") in FiniteFields() + sage: GF(4, "a") in FiniteFields() # needs sage.rings.finite_rings True sage: QQ in FiniteFields() False @@ -82,14 +82,14 @@ def _call_(self, x): """ EXAMPLES:: - sage: FiniteFields()(GF(4, "a")) + sage: FiniteFields()(GF(4, "a")) # needs sage.rings.finite_rings Finite Field in a of size 2^2 sage: FiniteFields()(RationalField()) # indirect doctest Traceback (most recent call last): ... TypeError: unable to canonically associate a finite field to Rational Field """ - raise TypeError("unable to canonically associate a finite field to %s"%x) + raise TypeError("unable to canonically associate a finite field to %s" % x) # TODO: local dvr ring? class ParentMethods: diff --git a/src/sage/categories/finite_groups.py b/src/sage/categories/finite_groups.py index 42415233567..7461f6fabfd 100644 --- a/src/sage/categories/finite_groups.py +++ b/src/sage/categories/finite_groups.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups r""" Finite groups """ @@ -165,7 +166,7 @@ def conjugacy_classes(self): ... NotImplementedError: Listing the conjugacy classes for group <sage.groups.group.FiniteGroup object at ...> is not implemented """ - raise NotImplementedError("Listing the conjugacy classes for group %s is not implemented"%self) + raise NotImplementedError("Listing the conjugacy classes for group %s is not implemented" % self) def conjugacy_classes_representatives(self): r""" diff --git a/src/sage/categories/finite_lattice_posets.py b/src/sage/categories/finite_lattice_posets.py index 4b7f0fb9b28..96f2385404c 100644 --- a/src/sage/categories/finite_lattice_posets.py +++ b/src/sage/categories/finite_lattice_posets.py @@ -49,8 +49,8 @@ def join_irreducibles(self): EXAMPLES:: - sage: L = LatticePoset({0:[1,2],1:[3],2:[3,4],3:[5],4:[5]}) - sage: L.join_irreducibles() + sage: L = LatticePoset({0:[1,2],1:[3],2:[3,4],3:[5],4:[5]}) # needs sage.graphs sage.modules + sage: L.join_irreducibles() # needs sage.graphs sage.modules [1, 2, 4] .. SEEALSO:: @@ -71,8 +71,8 @@ def join_irreducibles_poset(self): EXAMPLES:: - sage: L = LatticePoset({0:[1,2,3],1:[4],2:[4],3:[4]}) - sage: L.join_irreducibles_poset() + sage: L = LatticePoset({0:[1,2,3],1:[4],2:[4],3:[4]}) # needs sage.graphs sage.modules + sage: L.join_irreducibles_poset() # needs sage.graphs sage.modules Finite poset containing 3 elements .. SEEALSO:: @@ -92,8 +92,8 @@ def meet_irreducibles(self): EXAMPLES:: - sage: L = LatticePoset({0:[1,2],1:[3],2:[3,4],3:[5],4:[5]}) - sage: L.meet_irreducibles() + sage: L = LatticePoset({0:[1,2],1:[3],2:[3,4],3:[5],4:[5]}) # needs sage.graphs sage.modules + sage: L.meet_irreducibles() # needs sage.graphs sage.modules [1, 3, 4] .. SEEALSO:: @@ -114,8 +114,8 @@ def meet_irreducibles_poset(self): EXAMPLES:: - sage: L = LatticePoset({0:[1,2,3],1:[4],2:[4],3:[4]}) - sage: L.join_irreducibles_poset() + sage: L = LatticePoset({0:[1,2,3],1:[4],2:[4],3:[4]}) # needs sage.graphs sage.modules + sage: L.join_irreducibles_poset() # needs sage.graphs sage.modules Finite poset containing 3 elements .. SEEALSO:: @@ -143,6 +143,7 @@ def irreducibles_poset(self): EXAMPLES:: + sage: # needs sage.combinat sage.graphs sage.modules sage: L = LatticePoset({1: [2, 3, 4], 2: [5, 6], 3: [5], ....: 4: [6], 5: [9, 7], 6: [9, 8], 7: [10], ....: 8: [10], 9: [10], 10: [11]}) @@ -154,9 +155,9 @@ def irreducibles_poset(self): TESTS:: - sage: LatticePoset().irreducibles_poset() + sage: LatticePoset().irreducibles_poset() # needs sage.graphs Finite poset containing 0 elements - sage: posets.ChainPoset(1).irreducibles_poset() + sage: posets.ChainPoset(1).irreducibles_poset() # needs sage.graphs Finite poset containing 1 elements """ if self.cardinality() == 1: @@ -191,35 +192,36 @@ def is_lattice_morphism(self, f, codomain): lattice of divisors of `60`, and check that the map `b \mapsto 5 \prod_{x\in b} x` is a morphism of lattices:: - sage: D = LatticePoset((divisors(60), attrcall("divides"))) - sage: B = LatticePoset((Subsets([2,2,3]), attrcall("issubset"))) + sage: D = LatticePoset((divisors(60), attrcall("divides"))) # needs sage.graphs sage.modules + sage: B = LatticePoset((Subsets([2,2,3]), attrcall("issubset"))) # needs sage.graphs sage.modules sage: def f(b): return D(5*prod(b)) - sage: B.is_lattice_morphism(f, D) + sage: B.is_lattice_morphism(f, D) # needs sage.graphs sage.modules True We construct the boolean lattice `B_2`:: - sage: B = posets.BooleanLattice(2) - sage: B.cover_relations() + sage: B = posets.BooleanLattice(2) # needs sage.graphs + sage: B.cover_relations() # needs sage.graphs [[0, 1], [0, 2], [1, 3], [2, 3]] And the same lattice with new top and bottom elements numbered respectively `-1` and `3`:: - sage: L = LatticePoset(DiGraph({-1:[0], 0:[1,2], 1:[3], 2:[3],3:[4]})) - sage: L.cover_relations() + sage: G = DiGraph({-1:[0], 0:[1,2], 1:[3], 2:[3], 3:[4]}) # needs sage.graphs + sage: L = LatticePoset(G) # needs sage.graphs sage.modules + sage: L.cover_relations() # needs sage.graphs sage.modules [[-1, 0], [0, 1], [0, 2], [1, 3], [2, 3], [3, 4]] - sage: f = { B(0): L(0), B(1): L(1), B(2): L(2), B(3): L(3) }.__getitem__ - sage: B.is_lattice_morphism(f, L) + sage: f = {B(0): L(0), B(1): L(1), B(2): L(2), B(3): L(3)}.__getitem__ # needs sage.graphs sage.modules + sage: B.is_lattice_morphism(f, L) # needs sage.graphs sage.modules True - sage: f = { B(0): L(-1),B(1): L(1), B(2): L(2), B(3): L(3) }.__getitem__ - sage: B.is_lattice_morphism(f, L) + sage: f = {B(0): L(-1),B(1): L(1), B(2): L(2), B(3): L(3)}.__getitem__ # needs sage.graphs sage.modules + sage: B.is_lattice_morphism(f, L) # needs sage.graphs sage.modules False - sage: f = { B(0): L(0), B(1): L(1), B(2): L(2), B(3): L(4) }.__getitem__ - sage: B.is_lattice_morphism(f, L) + sage: f = {B(0): L(0), B(1): L(1), B(2): L(2), B(3): L(4)}.__getitem__ # needs sage.graphs sage.modules + sage: B.is_lattice_morphism(f, L) # needs sage.graphs sage.modules False .. SEEALSO:: diff --git a/src/sage/categories/finite_monoids.py b/src/sage/categories/finite_monoids.py index a300339ae22..b446dc925cb 100644 --- a/src/sage/categories/finite_monoids.py +++ b/src/sage/categories/finite_monoids.py @@ -72,9 +72,9 @@ def nerve(self): The nerve (classifying space) of the cyclic group of order 2 is infinite-dimensional real projective space. :: - sage: Sigma2 = groups.permutation.Cyclic(2) - sage: BSigma2 = Sigma2.nerve() - sage: BSigma2.cohomology(4, base_ring=GF(2)) + sage: Sigma2 = groups.permutation.Cyclic(2) # needs sage.groups + sage: BSigma2 = Sigma2.nerve() # needs sage.groups + sage: BSigma2.cohomology(4, base_ring=GF(2)) # needs sage.groups sage.modules Vector space of dimension 1 over Finite Field of size 2 The `k`-simplices of the nerve are named after the chains @@ -83,14 +83,15 @@ def nerve(self): element) and ``(1,2)`` in Sage. So the 1-cells and 2-cells in `B\Sigma_2` are:: - sage: BSigma2.n_cells(1) + sage: BSigma2.n_cells(1) # needs sage.groups [(1,2)] - sage: BSigma2.n_cells(2) + sage: BSigma2.n_cells(2) # needs sage.groups [(1,2) * (1,2)] Another construction of the group, with different names for its elements:: + sage: # needs sage.groups sage: C2 = groups.misc.MultiplicativeAbelian([2]) sage: BC2 = C2.nerve() sage: BC2.n_cells(0) @@ -103,21 +104,21 @@ def nerve(self): With mod `p` coefficients, `B \Sigma_p` should have its first nonvanishing homology group in dimension `p`:: - sage: Sigma3 = groups.permutation.Symmetric(3) - sage: BSigma3 = Sigma3.nerve() - sage: BSigma3.homology(range(4), base_ring=GF(3)) + sage: Sigma3 = groups.permutation.Symmetric(3) # needs sage.groups + sage: BSigma3 = Sigma3.nerve() # needs sage.groups + sage: BSigma3.homology(range(4), base_ring=GF(3)) # needs sage.groups {0: Vector space of dimension 0 over Finite Field of size 3, - 1: Vector space of dimension 0 over Finite Field of size 3, - 2: Vector space of dimension 0 over Finite Field of size 3, - 3: Vector space of dimension 1 over Finite Field of size 3} + 1: Vector space of dimension 0 over Finite Field of size 3, + 2: Vector space of dimension 0 over Finite Field of size 3, + 3: Vector space of dimension 1 over Finite Field of size 3} Note that we can construct the `n`-skeleton for `B\Sigma_2` for relatively large values of `n`, while for `B\Sigma_3`, the complexes get large pretty quickly:: + sage: # needs sage.groups sage: Sigma2.nerve().n_skeleton(14) Simplicial set with 15 non-degenerate simplices - sage: BSigma3 = Sigma3.nerve() sage: BSigma3.n_skeleton(3) Simplicial set with 156 non-degenerate simplices @@ -129,6 +130,7 @@ def nerve(self): on `p` letters, and its first homology group appears earlier:: + sage: # needs sage.groups sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: list(C3) [1, f, f^2] @@ -143,21 +145,17 @@ def nerve(self): 8 sage: len(BSigma3.n_cells(3)) 125 - - sage: BC3.homology(range(5), base_ring=GF(3)) + sage: BC3.homology(range(4), base_ring=GF(3)) {0: Vector space of dimension 0 over Finite Field of size 3, 1: Vector space of dimension 1 over Finite Field of size 3, 2: Vector space of dimension 1 over Finite Field of size 3, - 3: Vector space of dimension 1 over Finite Field of size 3, - 4: Vector space of dimension 1 over Finite Field of size 3} - + 3: Vector space of dimension 1 over Finite Field of size 3} sage: BC5 = groups.permutation.Cyclic(5).nerve() - sage: BC5.homology(range(5), base_ring=GF(5)) + sage: BC5.homology(range(4), base_ring=GF(5)) {0: Vector space of dimension 0 over Finite Field of size 5, - 1: Vector space of dimension 1 over Finite Field of size 5, - 2: Vector space of dimension 1 over Finite Field of size 5, - 3: Vector space of dimension 1 over Finite Field of size 5, - 4: Vector space of dimension 1 over Finite Field of size 5} + 1: Vector space of dimension 1 over Finite Field of size 5, + 2: Vector space of dimension 1 over Finite Field of size 5, + 3: Vector space of dimension 1 over Finite Field of size 5} """ from sage.topology.simplicial_set_examples import Nerve return Nerve(self) @@ -181,8 +179,10 @@ def rhodes_radical_congruence(self, base_ring=None): EXAMPLES:: sage: M = Monoids().Finite().example() - sage: M.rhodes_radical_congruence() + sage: M.rhodes_radical_congruence() # needs sage.modules [(0, 6), (2, 8), (4, 10)] + + sage: # needs sage.combinat sage.groups sage.modules sage: from sage.monoids.hecke_monoid import HeckeMonoid sage: H3 = HeckeMonoid(SymmetricGroup(3)) sage: H3.repr_element_method(style="reduced") @@ -192,9 +192,9 @@ def rhodes_radical_congruence(self, base_ring=None): By Maschke's theorem, every group algebra over `\QQ` is semisimple hence the Rhodes radical of a group must be trivial:: - sage: SymmetricGroup(3).rhodes_radical_congruence() + sage: SymmetricGroup(3).rhodes_radical_congruence() # needs sage.groups sage.modules [] - sage: DihedralGroup(10).rhodes_radical_congruence() + sage: DihedralGroup(10).rhodes_radical_congruence() # needs sage.groups sage.modules [] REFERENCES: @@ -209,7 +209,7 @@ def rhodes_radical_congruence(self, base_ring=None): res = [] for m in self: for n in self: - if (m == n) or ((n, m) in res): + if m == n or (n, m) in res: continue try: kSrad.retract(kS(m) - kS(n)) @@ -222,7 +222,7 @@ def rhodes_radical_congruence(self, base_ring=None): class ElementMethods: def pseudo_order(self): r""" - Returns the pair `[k, j]` with `k` minimal and `0\leq j <k` such + Return the pair `[k, j]` with `k` minimal and `0\leq j <k` such that ``self^k == self^j``. Note that `j` is uniquely determined. @@ -256,8 +256,10 @@ def pseudo_order(self): sage: x.pseudo_order() [2, 0] - TODO: more appropriate name? see, for example, Jean-Eric Pin's - lecture notes on semigroups. + .. TODO:: + + more appropriate name? see, for example, Jean-Eric Pin's + lecture notes on semigroups. """ self_powers = {self.parent().one(): 0} k = 1 diff --git a/src/sage/categories/finite_permutation_groups.py b/src/sage/categories/finite_permutation_groups.py index 59c00471e3f..f14c66a96c9 100644 --- a/src/sage/categories/finite_permutation_groups.py +++ b/src/sage/categories/finite_permutation_groups.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.groups r""" Finite Permutation Groups """ @@ -270,8 +270,8 @@ def profile_series(self, variable='z'): Univariate Polynomial Ring in z over Rational Field sage: D8.profile_series(variable='y') y^8 + y^7 + 4*y^6 + 5*y^5 + 8*y^4 + 5*y^3 + 4*y^2 + y + 1 - sage: u = var('u') # optional - sage.symbolic - sage: D8.profile_series(u).parent() # optional - sage.symbolic + sage: u = var('u') # needs sage.symbolic + sage: D8.profile_series(u).parent() # needs sage.symbolic Symbolic Ring """ from sage.rings.integer_ring import ZZ diff --git a/src/sage/categories/finite_posets.py b/src/sage/categories/finite_posets.py index b5422adfd4e..c50eb6c100d 100644 --- a/src/sage/categories/finite_posets.py +++ b/src/sage/categories/finite_posets.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.graphs r""" Finite posets @@ -1438,10 +1439,10 @@ def rowmotion_orbits_plots(self): """ from sage.plot.plot import graphics_array - plot_of_orb_plots=[] + plot_of_orb_plots = [] max_orbit_size = 0 for orb in self.rowmotion_orbits(): - orb_plots=[] + orb_plots = [] if len(orb) > max_orbit_size: max_orbit_size = len(orb) for oi in orb: @@ -1524,10 +1525,10 @@ def toggling_orbits_plots(self, vs): """ from sage.plot.plot import graphics_array - plot_of_orb_plots=[] + plot_of_orb_plots = [] max_orbit_size = 0 for orb in self.toggling_orbits(vs): - orb_plots=[] + orb_plots = [] if len(orb) > max_orbit_size: max_orbit_size = len(orb) for oi in orb: diff --git a/src/sage/categories/finite_semigroups.py b/src/sage/categories/finite_semigroups.py index a7f9b9a20a1..ad384fc2b79 100644 --- a/src/sage/categories/finite_semigroups.py +++ b/src/sage/categories/finite_semigroups.py @@ -51,7 +51,8 @@ class FiniteSemigroups(CategoryWithAxiom): sage: sorted(C.axioms()) ['Associative', 'Finite'] sage: C.example() - An example of a finite semigroup: the left regular band generated by ('a', 'b', 'c', 'd') + An example of a finite semigroup: + the left regular band generated by ('a', 'b', 'c', 'd') TESTS:: @@ -86,8 +87,9 @@ def j_classes(self): EXAMPLES:: sage: S = FiniteSemigroups().example(alphabet=('a','b', 'c')) - sage: sorted(map(sorted, S.j_classes())) - [['a'], ['ab', 'ba'], ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'], ['ac', 'ca'], ['b'], ['bc', 'cb'], ['c']] + sage: sorted(map(sorted, S.j_classes())) # needs sage.graphs + [['a'], ['ab', 'ba'], ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'], + ['ac', 'ca'], ['b'], ['bc', 'cb'], ['c']] """ return self.cayley_graph(side="twosided", simple=True).strongly_connected_components() @@ -103,8 +105,9 @@ def j_classes_of_idempotents(self): EXAMPLES:: sage: S = FiniteSemigroups().example(alphabet=('a','b', 'c')) - sage: sorted(map(sorted, S.j_classes_of_idempotents())) - [['a'], ['ab', 'ba'], ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'], ['ac', 'ca'], ['b'], ['bc', 'cb'], ['c']] + sage: sorted(map(sorted, S.j_classes_of_idempotents())) # needs sage.graphs + [['a'], ['ab', 'ba'], ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'], + ['ac', 'ca'], ['b'], ['bc', 'cb'], ['c']] """ return [l for l in ([x for x in cl if attrcall('is_idempotent')(x)] for cl in self.j_classes()) if len(l) > 0] @@ -120,7 +123,7 @@ def j_transversal_of_idempotents(self): The chosen elements depend on the order of each `J`-class, and that order is random when using Python 3. :: - sage: sorted(S.j_transversal_of_idempotents()) # random + sage: sorted(S.j_transversal_of_idempotents()) # random # needs sage.graphs ['a', 'ab', 'abc', 'ac', 'b', 'c', 'cb'] """ def first_idempotent(l): diff --git a/src/sage/categories/finitely_generated_lambda_bracket_algebras.py b/src/sage/categories/finitely_generated_lambda_bracket_algebras.py index 8877491e33e..c997118a3bc 100644 --- a/src/sage/categories/finitely_generated_lambda_bracket_algebras.py +++ b/src/sage/categories/finitely_generated_lambda_bracket_algebras.py @@ -27,10 +27,11 @@ class FinitelyGeneratedLambdaBracketAlgebras(CategoryWithAxiom_over_base_ring): EXAMPLES:: sage: from sage.categories.lambda_bracket_algebras import LambdaBracketAlgebras - sage: LambdaBracketAlgebras(QQbar).FinitelyGenerated() + sage: LambdaBracketAlgebras(QQbar).FinitelyGenerated() # needs sage.rings.number_field Category of finitely generated lambda bracket algebras over Algebraic Field """ _base_category_class_and_axiom = (LambdaBracketAlgebras, "FinitelyGeneratedAsLambdaBracketAlgebra") + class ParentMethods: def ngens(self): r""" @@ -38,12 +39,12 @@ def ngens(self): EXAMPLES:: - sage: Vir = lie_conformal_algebras.Virasoro(QQ) - sage: Vir.ngens() + sage: Vir = lie_conformal_algebras.Virasoro(QQ) # needs sage.combinat sage.modules + sage: Vir.ngens() # needs sage.combinat sage.modules 2 - sage: V = lie_conformal_algebras.Affine(QQ, 'A2') - sage: V.ngens() + sage: V = lie_conformal_algebras.Affine(QQ, 'A2') # needs sage.combinat sage.modules + sage: V.ngens() # needs sage.combinat sage.modules 9 """ return len(self.gens()) @@ -54,6 +55,7 @@ def gen(self,i): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: V = lie_conformal_algebras.Affine(QQ, 'A1') sage: V.gens() (B[alpha[1]], B[alphacheck[1]], B[-alpha[1]], B['K']) @@ -73,10 +75,11 @@ def some_elements(self): EXAMPLES:: - sage: V = lie_conformal_algebras.Affine(QQ, 'A1', names=('e', 'h', 'f')) - sage: V.some_elements() + sage: V = lie_conformal_algebras.Affine(QQ, 'A1', # needs sage.combinat sage.modules + ....: names=('e', 'h', 'f')) + sage: V.some_elements() # needs sage.combinat sage.modules [e, h, f, K, ...] - sage: all(v.parent() is V for v in V.some_elements()) + sage: all(v.parent() is V for v in V.some_elements()) # needs sage.combinat sage.modules True """ S = list(self.gens()) @@ -91,8 +94,9 @@ class Graded(GradedModulesCategory): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).FinitelyGenerated().Graded() - Category of H-graded finitely generated lie conformal algebras over Algebraic Field + sage: LieConformalAlgebras(QQbar).FinitelyGenerated().Graded() # needs sage.rings.number_field + Category of H-graded finitely generated lie conformal algebras + over Algebraic Field """ def _repr_object_names(self): """ @@ -100,7 +104,7 @@ def _repr_object_names(self): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated().Graded() + sage: LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated().Graded() # needs sage.rings.number_field Category of H-graded finitely generated Lie conformal algebras with basis over Algebraic Field """ return "H-graded {}".format(self.base_category()._repr_object_names()) diff --git a/src/sage/categories/finitely_generated_lie_conformal_algebras.py b/src/sage/categories/finitely_generated_lie_conformal_algebras.py index 464d1eb7d03..53d5ed4ccf6 100644 --- a/src/sage/categories/finitely_generated_lie_conformal_algebras.py +++ b/src/sage/categories/finitely_generated_lie_conformal_algebras.py @@ -27,7 +27,7 @@ class FinitelyGeneratedLieConformalAlgebras(CategoryWithAxiom_over_base_ring): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).FinitelyGenerated() + sage: LieConformalAlgebras(QQbar).FinitelyGenerated() # needs sage.rings.number_field Category of finitely generated lie conformal algebras over Algebraic Field """ _base_category_class_and_axiom = (LieConformalAlgebras, "FinitelyGeneratedAsLambdaBracketAlgebra") @@ -43,10 +43,11 @@ def some_elements(self): EXAMPLES:: - sage: V = lie_conformal_algebras.Affine(QQ, 'A1', names=('e', 'h', 'f')) - sage: V.some_elements() + sage: V = lie_conformal_algebras.Affine(QQ, 'A1', # needs sage.combinat sage.modules + ....: names=('e', 'h', 'f')) + sage: V.some_elements() # needs sage.combinat sage.modules [e, h, f, K, ...] - sage: all(v.parent() is V for v in V.some_elements()) + sage: all(v.parent() is V for v in V.some_elements()) # needs sage.combinat sage.modules True """ S = list(self.gens()) @@ -61,8 +62,9 @@ class Super(SuperModulesCategory): EXAMPLES:: - sage: LieConformalAlgebras(AA).FinitelyGenerated().Super() - Category of super finitely generated lie conformal algebras over Algebraic Real Field + sage: LieConformalAlgebras(AA).FinitelyGenerated().Super() # needs sage.rings.number_field + Category of super finitely generated lie conformal algebras + over Algebraic Real Field """ class Graded(GradedModulesCategory): """ @@ -70,8 +72,9 @@ class Graded(GradedModulesCategory): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).FinitelyGenerated().Super().Graded() - Category of H-graded super finitely generated lie conformal algebras over Algebraic Field + sage: LieConformalAlgebras(QQbar).FinitelyGenerated().Super().Graded() # needs sage.rings.number_field + Category of H-graded super finitely generated lie conformal algebras + over Algebraic Field """ def _repr_object_names(self): """ @@ -79,9 +82,10 @@ def _repr_object_names(self): EXAMPLES:: - sage: C = LieConformalAlgebras(QQbar).FinitelyGenerated() - sage: C.Super().Graded() - Category of H-graded super finitely generated lie conformal algebras over Algebraic Field + sage: C = LieConformalAlgebras(QQbar).FinitelyGenerated() # needs sage.rings.number_field + sage: C.Super().Graded() # needs sage.rings.number_field + Category of H-graded super finitely generated + lie conformal algebras over Algebraic Field """ return "H-graded {}".format(self.base_category()._repr_object_names()) @@ -91,8 +95,9 @@ class Graded(GradedModulesCategory): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).FinitelyGenerated().Graded() - Category of H-graded finitely generated lie conformal algebras over Algebraic Field + sage: LieConformalAlgebras(QQbar).FinitelyGenerated().Graded() # needs sage.rings.number_field + Category of H-graded finitely generated lie conformal algebras + over Algebraic Field """ def _repr_object_names(self): """ @@ -100,7 +105,8 @@ def _repr_object_names(self): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated().Graded() - Category of H-graded finitely generated Lie conformal algebras with basis over Algebraic Field + sage: LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated().Graded() # needs sage.rings.number_field + Category of H-graded finitely generated Lie conformal algebras with basis + over Algebraic Field """ return "H-graded {}".format(self.base_category()._repr_object_names()) diff --git a/src/sage/categories/function_fields.py b/src/sage/categories/function_fields.py index 6c30067e53f..6c949b6197a 100644 --- a/src/sage/categories/function_fields.py +++ b/src/sage/categories/function_fields.py @@ -52,20 +52,20 @@ def _call_(self, x): EXAMPLES:: sage: C = FunctionFields() - sage: K.<x>=FunctionField(QQ) + sage: K.<x> = FunctionField(QQ) sage: C(K) Rational function field in x over Rational Field sage: Ky.<y> = K[] - sage: L = K.extension(y^2-x) - sage: C(L) + sage: L = K.extension(y^2 - x) # needs sage.rings.function_field + sage: C(L) # needs sage.rings.function_field Function field in y defined by y^2 - x - sage: C(L.equation_order()) + sage: C(L.equation_order()) # needs sage.rings.function_field Function field in y defined by y^2 - x """ try: return x.function_field() except AttributeError: - raise TypeError("unable to canonically associate a function field to %s"%x) + raise TypeError("unable to canonically associate a function field to %s" % x) class ParentMethods: pass diff --git a/src/sage/categories/functor.pyx b/src/sage/categories/functor.pyx index ccf01cc9177..c25e99f2164 100644 --- a/src/sage/categories/functor.pyx +++ b/src/sage/categories/functor.pyx @@ -55,11 +55,12 @@ def _Functor_unpickle(Cl, D, domain, codomain): """ F = Functor.__new__(Cl) - Functor.__init__(F,domain,codomain) - for s,v in D: - setattr(F,s,v) + Functor.__init__(F, domain, codomain) + for s, v in D: + setattr(F, s, v) return F + cdef class Functor(SageObject): """ A class for functors between two categories @@ -111,7 +112,7 @@ cdef class Functor(SageObject): this behaviour. Here we illustrate the default:: sage: from sage.categories.functor import Functor - sage: F = Functor(Rings(),Fields()) + sage: F = Functor(Rings(), Fields()) sage: F Functor from Category of rings to Category of fields sage: F(ZZ) @@ -127,7 +128,7 @@ cdef class Functor(SageObject): sage: R1.<x> = ZZ[] sage: R2.<a,b> = QQ[] - sage: f = R1.hom([a+b],R2) + sage: f = R1.hom([a + b], R2) sage: f Ring morphism: From: Univariate Polynomial Ring in x over Integer Ring @@ -149,8 +150,10 @@ cdef class Functor(SageObject): Poly[t] sage: F(f) Ring morphism: - From: Univariate Polynomial Ring in t over Univariate Polynomial Ring in x over Integer Ring - To: Univariate Polynomial Ring in t over Multivariate Polynomial Ring in a, b over Rational Field + From: Univariate Polynomial Ring in t + over Univariate Polynomial Ring in x over Integer Ring + To: Univariate Polynomial Ring in t + over Multivariate Polynomial Ring in a, b over Rational Field Defn: Induced from base ring by Ring morphism: From: Univariate Polynomial Ring in x over Integer Ring @@ -158,7 +161,8 @@ cdef class Functor(SageObject): Defn: x |--> a + b sage: p = R1['t']('(-x^2 + x)*t^2 + (x^2 - x)*t - 4*x^2 - x + 1') sage: F(f)(p) - (-a^2 - 2*a*b - b^2 + a + b)*t^2 + (a^2 + 2*a*b + b^2 - a - b)*t - 4*a^2 - 8*a*b - 4*b^2 - a - b + 1 + (-a^2 - 2*a*b - b^2 + a + b)*t^2 + (a^2 + 2*a*b + b^2 - a - b)*t + - 4*a^2 - 8*a*b - 4*b^2 - a - b + 1 """ def __init__(self, domain, codomain): @@ -166,7 +170,7 @@ cdef class Functor(SageObject): TESTS:: sage: from sage.categories.functor import Functor - sage: F = Functor(Rings(),Fields()) + sage: F = Functor(Rings(), Fields()) sage: F Functor from Category of rings to Category of fields sage: F(ZZ) @@ -227,7 +231,7 @@ cdef class Functor(SageObject): TESTS:: sage: from sage.categories.functor import Functor - sage: F = Functor(FiniteFields(),Fields()) + sage: F = Functor(FiniteFields(), Fields()) sage: F._apply_functor(ZZ) Rational Field @@ -246,28 +250,30 @@ cdef class Functor(SageObject): TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.categories.functor import Functor - sage: F = Functor(Rings(),Fields()) + sage: F = Functor(Rings(), Fields()) sage: k.<a> = GF(25) - sage: f = k.hom([-a-4]) + sage: f = k.hom([-a - 4]) sage: R.<t> = k[] - sage: fR = R.hom(f,R) + sage: fR = R.hom(f, R) sage: fF = F(fR) # indirect doctest sage: fF - Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Finite Field in a of size 5^2 + Ring endomorphism of Fraction Field of + Univariate Polynomial Ring in t over Finite Field in a of size 5^2 Defn: Induced from base ring by - Ring endomorphism of Univariate Polynomial Ring in t over Finite Field in a of size 5^2 + Ring endomorphism of Univariate Polynomial Ring in t + over Finite Field in a of size 5^2 Defn: Induced from base ring by Ring endomorphism of Finite Field in a of size 5^2 Defn: a |--> 4*a + 1 sage: fF((a^2+a)*t^2/(a*t - a^2)) ((4*a + 2)*t^2)/(t + a + 4) - """ try: return self(f.domain()).hom(f, self(f.codomain())) except Exception: - raise TypeError('unable to transform %s into a morphism in %s' % (f,self.codomain())) + raise TypeError(f'unable to transform {f} into a morphism in {self.codomain()}') def _coerce_into_domain(self, x): """ @@ -292,9 +298,8 @@ cdef class Functor(SageObject): Traceback (most recent call last): ... TypeError: x (=Integer Ring) is not in Category of fields - """ - if not (x in self.__domain): + if x not in self.__domain: raise TypeError("x (=%s) is not in %s" % (x, self.__domain)) return x @@ -314,9 +319,8 @@ cdef class Functor(SageObject): The identity functor on Category of rings sage: I.rename('Id'); I Id - """ - return "Functor from %s to %s"%(self.__domain, self.__codomain) + return "Functor from %s to %s" % (self.__domain, self.__codomain) def __call__(self, x): """ @@ -340,8 +344,8 @@ cdef class Functor(SageObject): Two subclasses:: - sage: F1 = ForgetfulFunctor(FiniteFields(),Fields()) - sage: F1(GF(5)) #indirect doctest + sage: F1 = ForgetfulFunctor(FiniteFields(), Fields()) + sage: F1(GF(5)) # indirect doctest Finite Field of size 5 sage: F1(ZZ) Traceback (most recent call last): @@ -353,7 +357,8 @@ cdef class Functor(SageObject): sage: F2(ZZ['x','y']) Traceback (most recent call last): ... - TypeError: x (=Multivariate Polynomial Ring in x, y over Integer Ring) is not in Category of fields + TypeError: x (=Multivariate Polynomial Ring in x, y over Integer Ring) + is not in Category of fields The last example shows that it is tested whether the result of applying the functor lies in the functor's codomain. Note that @@ -361,20 +366,22 @@ cdef class Functor(SageObject): which was fixed in :trac:`8807`:: sage: class IllFunctor(Functor): - ....: def __init__(self, m,n): + ....: def __init__(self, m, n): ....: self._m = m ....: self._n = n - ....: Functor.__init__(self,Rings(),Rings()) + ....: Functor.__init__(self, Rings(), Rings()) ....: def _apply_functor(self, R): - ....: return MatrixSpace(R,self._m,self._n) - sage: F = IllFunctor(2,2) - sage: F(QQ) + ....: return MatrixSpace(R, self._m, self._n) + sage: F = IllFunctor(2, 2) + sage: F(QQ) # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: F = IllFunctor(2,3) - sage: F(QQ) + sage: F = IllFunctor(2, 3) + sage: F(QQ) # needs sage.modules Traceback (most recent call last): ... - TypeError: Functor from Category of rings to Category of rings is ill-defined, since it sends x (=Rational Field) to something that is not in Category of rings. + TypeError: Functor from Category of rings to Category of rings + is ill-defined, since it sends x (=Rational Field) to something + that is not in Category of rings. """ from sage.categories.morphism import is_Morphism @@ -391,7 +398,7 @@ cdef class Functor(SageObject): EXAMPLES:: - sage: F = ForgetfulFunctor(FiniteFields(),Fields()) + sage: F = ForgetfulFunctor(FiniteFields(), Fields()) sage: F.domain() Category of finite enumerated fields @@ -404,7 +411,7 @@ cdef class Functor(SageObject): EXAMPLES:: - sage: F = ForgetfulFunctor(FiniteFields(),Fields()) + sage: F = ForgetfulFunctor(FiniteFields(), Fields()) sage: F.codomain() Category of fields @@ -457,9 +464,11 @@ class ForgetfulFunctor_generic(Functor): EXAMPLES:: - sage: F = ForgetfulFunctor(FiniteFields(),Fields()) #indirect doctest + sage: F = ForgetfulFunctor(FiniteFields(), Fields()) # indirect doctest sage: F - The forgetful functor from Category of finite enumerated fields to Category of fields + The forgetful functor + from Category of finite enumerated fields + to Category of fields sage: F(GF(3)) Finite Field of size 3 @@ -478,9 +487,10 @@ class ForgetfulFunctor_generic(Functor): """ TESTS:: - sage: F = ForgetfulFunctor(FiniteFields(),Fields()) - sage: F #indirect doctest - The forgetful functor from Category of finite enumerated fields to Category of fields + sage: F = ForgetfulFunctor(FiniteFields(), Fields()) + sage: F # indirect doctest + The forgetful functor from Category of finite enumerated fields + to Category of fields """ return "The forgetful functor from %s to %s" % (self.domain(), @@ -498,7 +508,7 @@ class ForgetfulFunctor_generic(Functor): TESTS:: - sage: F1 = ForgetfulFunctor(FiniteFields(),Fields()) + sage: F1 = ForgetfulFunctor(FiniteFields(), Fields()) This is to test against a bug occurring in a previous version (see :trac:`8800`):: @@ -525,13 +535,13 @@ class ForgetfulFunctor_generic(Functor): EXAMPLES:: - sage: F1 = ForgetfulFunctor(FiniteFields(),Fields()) + sage: F1 = ForgetfulFunctor(FiniteFields(), Fields()) sage: F1 != F1 False sage: F1 != QQ True """ - return not self == other + return not self == other class IdentityFunctor_generic(ForgetfulFunctor_generic): @@ -586,7 +596,6 @@ class IdentityFunctor_generic(ForgetfulFunctor_generic): sage: F = IdentityFunctor(Groups()) sage: loads(F.dumps()) == F True - """ return IdentityFunctor, (self.domain(), ) @@ -598,9 +607,8 @@ class IdentityFunctor_generic(ForgetfulFunctor_generic): sage: F = IdentityFunctor(fields) sage: F #indirect doctest The identity functor on Category of fields - """ - return "The identity functor on %s"%(self.domain()) + return "The identity functor on %s" % (self.domain()) def _apply_functor(self, x): """ @@ -622,6 +630,7 @@ class IdentityFunctor_generic(ForgetfulFunctor_generic): """ return x + def IdentityFunctor(C): """ Construct the identity functor of the given category. @@ -640,10 +649,10 @@ def IdentityFunctor(C): sage: F = IdentityFunctor(rings) sage: F(ZZ['x','y']) is ZZ['x','y'] True - """ return IdentityFunctor_generic(C) + def ForgetfulFunctor(domain, codomain): """ Construct the forgetful function from one category to another. @@ -667,14 +676,17 @@ def ForgetfulFunctor(domain, codomain): sage: abgrps = CommutativeAdditiveGroups() sage: F = ForgetfulFunctor(rings, abgrps) sage: F - The forgetful functor from Category of rings to Category of commutative additive groups + The forgetful functor + from Category of rings + to Category of commutative additive groups It would be a mistake to call it in opposite order:: sage: F = ForgetfulFunctor(abgrps, rings) Traceback (most recent call last): ... - ValueError: Forgetful functor not supported for domain Category of commutative additive groups + ValueError: Forgetful functor not supported for domain + Category of commutative additive groups If both categories are equal, the forgetful functor is the same as the identity functor:: diff --git a/src/sage/categories/g_sets.py b/src/sage/categories/g_sets.py index b9447203e42..7fd09bafea4 100644 --- a/src/sage/categories/g_sets.py +++ b/src/sage/categories/g_sets.py @@ -23,8 +23,8 @@ class GSets(Category): EXAMPLES:: - sage: S = SymmetricGroup(3) - sage: GSets(S) + sage: S = SymmetricGroup(3) # needs sage.groups + sage: GSets(S) # needs sage.groups Category of G-sets for Symmetric group of order 3! as a permutation group TODO: should this derive from Category_over_base? @@ -33,8 +33,8 @@ def __init__(self, G): """ TESTS:: - sage: S8 = SymmetricGroup(8) - sage: TestSuite(GSets(S8)).run() + sage: S8 = SymmetricGroup(8) # needs sage.groups + sage: TestSuite(GSets(S8)).run() # needs sage.groups """ Category.__init__(self) self.__G = G @@ -43,10 +43,10 @@ def _repr_object_names(self): """ EXAMPLES:: - sage: GSets(SymmetricGroup(8)) # indirect doctests + sage: GSets(SymmetricGroup(8)) # indirect doctests # needs sage.groups Category of G-sets for Symmetric group of order 8! as a permutation group """ - return "G-sets for %s"%self.__G + return "G-sets for %s" % self.__G #def construction(self): # return (self.__class__, self.__G) @@ -55,7 +55,7 @@ def super_categories(self): """ EXAMPLES:: - sage: GSets(SymmetricGroup(8)).super_categories() + sage: GSets(SymmetricGroup(8)).super_categories() # needs sage.groups [Category of sets] """ return [Sets()] @@ -67,7 +67,7 @@ def an_instance(cls): EXAMPLES:: - sage: GSets.an_instance() # indirect doctest + sage: GSets.an_instance() # indirect doctest # needs sage.groups Category of G-sets for Symmetric group of order 8! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup diff --git a/src/sage/categories/generalized_coxeter_groups.py b/src/sage/categories/generalized_coxeter_groups.py index 8a92209299e..a59da41b3f1 100644 --- a/src/sage/categories/generalized_coxeter_groups.py +++ b/src/sage/categories/generalized_coxeter_groups.py @@ -68,7 +68,6 @@ def additional_structure(self): """ return None - class Finite(CategoryWithAxiom): """ The category of finite generalized Coxeter groups. diff --git a/src/sage/categories/graded_algebras.py b/src/sage/categories/graded_algebras.py index 54ce5775c9e..190355b59c5 100644 --- a/src/sage/categories/graded_algebras.py +++ b/src/sage/categories/graded_algebras.py @@ -39,8 +39,8 @@ def graded_algebra(self): EXAMPLES:: - sage: m = SymmetricFunctions(QQ).m() - sage: m.graded_algebra() is m + sage: m = SymmetricFunctions(QQ).m() # needs sage.combinat sage.modules + sage: m.graded_algebra() is m # needs sage.combinat sage.modules True """ return self diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index f992228ba81..95fcebbb7a7 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -46,8 +46,8 @@ def graded_algebra(self): EXAMPLES:: - sage: m = SymmetricFunctions(QQ).m() - sage: m.graded_algebra() is m + sage: m = SymmetricFunctions(QQ).m() # needs sage.combinat sage.modules + sage: m.graded_algebra() is m # needs sage.combinat sage.modules True TESTS: @@ -57,6 +57,7 @@ def graded_algebra(self): and :meth:`projection` (which form the interface of the associated graded algebra) work correctly here:: + sage: # needs sage.combinat sage.modules sage: to_gr = m.to_graded_conversion() sage: from_gr = m.from_graded_conversion() sage: m[2] == to_gr(m[2]) == from_gr(m[2]) @@ -111,6 +112,7 @@ def free_graded_module(self, generator_degrees, names=None): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: Q = QuadraticForm(QQ, 3, [1,2,3,4,5,6]) sage: Cl = CliffordAlgebra(Q) sage: M = Cl.free_graded_module((0, 2, 3)) @@ -134,6 +136,7 @@ def formal_series_ring(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: NCSF = NonCommutativeSymmetricFunctions(QQ) sage: S = NCSF.Complete() sage: L = S.formal_series_ring() @@ -144,6 +147,8 @@ def formal_series_ring(self): from sage.rings.lazy_series_ring import LazyCompletionGradedAlgebra return LazyCompletionGradedAlgebra(self) + completion = formal_series_ring + class ElementMethods: pass @@ -183,6 +188,7 @@ def one_basis(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A.<x,y> = ExteriorAlgebra(QQ) sage: A.one_basis() 0 @@ -209,6 +215,7 @@ def product_on_basis(self, t0, t1): Test the sign in the super tensor product:: + sage: # needs sage.combinat sage.modules sage: A = SteenrodAlgebra(3) sage: x = A.Q(0) sage: y = x.coproduct() diff --git a/src/sage/categories/graded_bialgebras.py b/src/sage/categories/graded_bialgebras.py index 6c751db558b..eff325b320e 100644 --- a/src/sage/categories/graded_bialgebras.py +++ b/src/sage/categories/graded_bialgebras.py @@ -26,5 +26,5 @@ def GradedBialgebras(base_ring): sage: TestSuite(C).run() """ - from sage.categories.all import Bialgebras + from sage.categories.bialgebras import Bialgebras return Bialgebras(base_ring).Graded() diff --git a/src/sage/categories/graded_bialgebras_with_basis.py b/src/sage/categories/graded_bialgebras_with_basis.py index 326e32b735d..d1727c0f40c 100644 --- a/src/sage/categories/graded_bialgebras_with_basis.py +++ b/src/sage/categories/graded_bialgebras_with_basis.py @@ -26,5 +26,5 @@ def GradedBialgebrasWithBasis(base_ring): sage: TestSuite(C).run() """ - from sage.categories.all import BialgebrasWithBasis + from sage.categories.bialgebras_with_basis import BialgebrasWithBasis return BialgebrasWithBasis(base_ring).Graded() diff --git a/src/sage/categories/graded_hopf_algebras.py b/src/sage/categories/graded_hopf_algebras.py index ad350212725..c4d5a24e3fe 100644 --- a/src/sage/categories/graded_hopf_algebras.py +++ b/src/sage/categories/graded_hopf_algebras.py @@ -35,5 +35,5 @@ def GradedHopfAlgebras(base_ring): :class:`super Hopf algebras <sage.categories.hopf_algebras.HopfAlgebras.Super>`. """ - from sage.categories.all import HopfAlgebras + from sage.categories.hopf_algebras import HopfAlgebras return HopfAlgebras(base_ring).Graded() diff --git a/src/sage/categories/graded_hopf_algebras_with_basis.py b/src/sage/categories/graded_hopf_algebras_with_basis.py index d806597ae0c..41beadad8a4 100644 --- a/src/sage/categories/graded_hopf_algebras_with_basis.py +++ b/src/sage/categories/graded_hopf_algebras_with_basis.py @@ -44,7 +44,7 @@ def example(self): TESTS:: - sage: GradedHopfAlgebrasWithBasis(QQ).example() + sage: GradedHopfAlgebrasWithBasis(QQ).example() # needs sage.modules An example of a graded connected Hopf algebra with basis over Rational Field """ from sage.categories.examples.graded_connected_hopf_algebras_with_basis import \ @@ -85,7 +85,7 @@ def example(self): TESTS:: - sage: GradedHopfAlgebrasWithBasis(QQ).Connected().example() + sage: GradedHopfAlgebrasWithBasis(QQ).Connected().example() # needs sage.modules An example of a graded connected Hopf algebra with basis over Rational Field """ from sage.categories.examples.graded_connected_hopf_algebras_with_basis import \ @@ -114,10 +114,10 @@ def counit_on_basis(self, i): EXAMPLES:: - sage: H = GradedHopfAlgebrasWithBasis(QQ).Connected().example() - sage: H.monomial(4).counit() # indirect doctest + sage: H = GradedHopfAlgebrasWithBasis(QQ).Connected().example() # needs sage.modules + sage: H.monomial(4).counit() # indirect doctest # needs sage.modules 0 - sage: H.monomial(0).counit() # indirect doctest + sage: H.monomial(0).counit() # indirect doctest # needs sage.modules 1 """ if i == self.one_basis(): @@ -144,14 +144,15 @@ def antipode_on_basis(self, index): TESTS:: + sage: # needs sage.modules sage: H = GradedHopfAlgebrasWithBasis(QQ).Connected().example() - sage: H.monomial(0).antipode() # indirect doctest + sage: H.monomial(0).antipode() # indirect doctest P0 - sage: H.monomial(1).antipode() # indirect doctest + sage: H.monomial(1).antipode() # indirect doctest -P1 - sage: H.monomial(2).antipode() # indirect doctest + sage: H.monomial(2).antipode() # indirect doctest P2 - sage: H.monomial(3).antipode() # indirect doctest + sage: H.monomial(3).antipode() # indirect doctest -P3 """ if self.monomial(index) == self.one(): diff --git a/src/sage/categories/graded_lie_conformal_algebras.py b/src/sage/categories/graded_lie_conformal_algebras.py index 66950ecce53..a17c067ae4e 100644 --- a/src/sage/categories/graded_lie_conformal_algebras.py +++ b/src/sage/categories/graded_lie_conformal_algebras.py @@ -31,6 +31,7 @@ def Super(self, base_ring=None): EXAMPLES:: + sage: # needs sage.rings.number_field sage: C = LieConformalAlgebras(QQbar) sage: C.Graded().Super() is C.Super().Graded() True @@ -46,10 +47,10 @@ def _repr_object_names(self): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).Graded() + sage: LieConformalAlgebras(QQbar).Graded() # needs sage.rings.number_field Category of H-graded Lie conformal algebras over Algebraic Field - sage: LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated().Graded() + sage: LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated().Graded() # needs sage.rings.number_field Category of H-graded finitely generated Lie conformal algebras with basis over Algebraic Field """ return "H-graded {}".format(self.base_category()._repr_object_names()) @@ -60,7 +61,7 @@ class GradedLieConformalAlgebras(GradedLieConformalAlgebrasCategory): EXAMPLES:: - sage: C = LieConformalAlgebras(QQbar).Graded(); C + sage: C = LieConformalAlgebras(QQbar).Graded(); C # needs sage.rings.number_field Category of H-graded Lie conformal algebras over Algebraic Field sage: CS = LieConformalAlgebras(QQ).Graded().Super(); CS diff --git a/src/sage/categories/graded_modules_with_basis.py b/src/sage/categories/graded_modules_with_basis.py index a53b1de91dd..c813b05e2ec 100644 --- a/src/sage/categories/graded_modules_with_basis.py +++ b/src/sage/categories/graded_modules_with_basis.py @@ -46,17 +46,18 @@ def degree_negation(self, element): EXAMPLES:: - sage: E.<a,b> = ExteriorAlgebra(QQ) - sage: E.degree_negation((1 + a) * (1 + b)) + sage: E.<a,b> = ExteriorAlgebra(QQ) # needs sage.modules + sage: E.degree_negation((1 + a) * (1 + b)) # needs sage.modules a*b - a - b + 1 - sage: E.degree_negation(E.zero()) + sage: E.degree_negation(E.zero()) # needs sage.modules 0 - sage: P = GradedModulesWithBasis(ZZ).example(); P - An example of a graded module with basis: the free module on partitions over Integer Ring + sage: P = GradedModulesWithBasis(ZZ).example(); P # needs sage.combinat sage.modules + An example of a graded module with basis: + the free module on partitions over Integer Ring sage: pbp = lambda x: P.basis()[Partition(list(x))] - sage: p = pbp([3,1]) - 2 * pbp([2]) + 4 * pbp([1]) - sage: P.degree_negation(p) + sage: p = pbp([3,1]) - 2 * pbp([2]) + 4 * pbp([1]) # needs sage.combinat sage.modules + sage: P.degree_negation(p) # needs sage.combinat sage.modules -4*P[1] - 2*P[2] + P[3, 1] """ base_one = self.base_ring().one() @@ -67,7 +68,6 @@ def degree_negation(self, element): for key, value in element.monomial_coefficients(copy=False).items()]) - def submodule(self, gens, check=True, already_echelonized=False, unitriangular=False, support_order=None, category=None, *args, **opts): @@ -115,12 +115,14 @@ def submodule(self, gens, check=True, already_echelonized=False, A graded submodule of a graded module generated by homogeneous elements is naturally graded:: + sage: # needs sage.combinat sage.modules sage: E.<x,y,z> = ExteriorAlgebra(QQ) sage: S = E.submodule([x + y, x*y - y*z]) sage: S.category() - Join of Category of graded vector spaces with basis over Rational Field - and Category of subobjects of filtered modules with basis over Rational Field - and Category of finite dimensional vector spaces with basis over Rational Field + Join of + Category of graded vector spaces with basis over Rational Field and + Category of subobjects of filtered modules with basis over Rational Field and + Category of finite dimensional vector spaces with basis over Rational Field sage: S.basis()[0].degree() 1 sage: S.basis()[1].degree() @@ -128,43 +130,50 @@ def submodule(self, gens, check=True, already_echelonized=False, We check on the echelonized basis:: - sage: Sp = E.submodule([1, x + y + 5, x*y - y*z + x + y - 2]) - sage: Sp.category() - Join of Category of graded vector spaces with basis over Rational Field - and Category of subobjects of filtered modules with basis over Rational Field - and Category of finite dimensional vector spaces with basis over Rational Field + sage: Sp = E.submodule([1, x + y + 5, x*y - y*z + x + y - 2]) # needs sage.combinat sage.modules + sage: Sp.category() # needs sage.combinat sage.modules + Join of + Category of graded vector spaces with basis over Rational Field and + Category of subobjects of filtered modules with basis over Rational Field and + Category of finite dimensional vector spaces with basis over Rational Field If it is generated by inhomogeneous elements, then it is filtered by default:: - sage: F = E.submodule([x + y*z, x*z + y*x]) - sage: F.category() - Join of Category of subobjects of filtered modules with basis over Rational Field - and Category of filtered vector spaces with basis over Rational Field - and Category of finite dimensional vector spaces with basis over Rational Field + sage: F = E.submodule([x + y*z, x*z + y*x]) # needs sage.combinat sage.modules + sage: F.category() # needs sage.combinat sage.modules + Join of + Category of subobjects of filtered modules with basis over Rational Field and + Category of filtered vector spaces with basis over Rational Field and + Category of finite dimensional vector spaces with basis over Rational Field If ``category`` is specified, then it does not give any extra structure to the submodule (we can think of this as applying the forgetful functor):: - sage: SM = E.submodule([x + y, x*y - y*z], category=ModulesWithBasis(QQ)) + sage: # needs sage.combinat sage.modules + sage: SM = E.submodule([x + y, x*y - y*z], + ....: category=ModulesWithBasis(QQ)) sage: SM.category() - Join of Category of finite dimensional vector spaces with basis over Rational Field - and Category of subobjects of sets - sage: FM = E.submodule([x + 1, x*y - x*y*z], category=ModulesWithBasis(QQ)) + Join of + Category of finite dimensional vector spaces with basis over Rational Field and + Category of subobjects of sets + sage: FM = E.submodule([x + 1, x*y - x*y*z], + ....: category=ModulesWithBasis(QQ)) sage: FM.category() - Join of Category of finite dimensional vector spaces with basis over Rational Field - and Category of subobjects of sets + Join of + Category of finite dimensional vector spaces with basis over Rational Field and + Category of subobjects of sets If we have specified that this is a graded submodule of a graded module, then the echelonized elements must be homogeneous:: sage: Cat = ModulesWithBasis(QQ).Graded().Subobjects() - sage: E.submodule([x + y, x*y - 1], category=Cat) + sage: E.submodule([x + y, x*y - 1], category=Cat) # needs sage.combinat sage.modules Traceback (most recent call last): ... ValueError: all of the generators must be homogeneous - sage: E.submodule([x + y, x*y - x - y], category=Cat) + sage: E.submodule([x + y, x*y - x - y], category=Cat) # needs sage.combinat sage.modules Free module generated by {0, 1} over Rational Field """ # Make sure gens consists of elements of ``self`` @@ -216,13 +225,15 @@ def quotient_module(self, submodule, check=True, already_echelonized=False, cate EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: E.<x,y,z> = ExteriorAlgebra(QQ) sage: S = E.submodule([x + y, x*y - y*z, y]) sage: Q = E.quotient_module(S) sage: Q.category() - Join of Category of quotients of graded modules with basis over Rational Field - and Category of graded vector spaces with basis over Rational Field - and Category of finite dimensional vector spaces with basis over Rational Field + Join of + Category of quotients of graded modules with basis over Rational Field and + Category of graded vector spaces with basis over Rational Field and + Category of finite dimensional vector spaces with basis over Rational Field .. SEEALSO:: @@ -259,17 +270,18 @@ def degree_negation(self): EXAMPLES:: - sage: E.<a,b> = ExteriorAlgebra(QQ) - sage: ((1 + a) * (1 + b)).degree_negation() + sage: E.<a,b> = ExteriorAlgebra(QQ) # needs sage.modules + sage: ((1 + a) * (1 + b)).degree_negation() # needs sage.modules a*b - a - b + 1 - sage: E.zero().degree_negation() + sage: E.zero().degree_negation() # needs sage.modules 0 - sage: P = GradedModulesWithBasis(ZZ).example(); P - An example of a graded module with basis: the free module on partitions over Integer Ring + sage: P = GradedModulesWithBasis(ZZ).example(); P # needs sage.combinat sage.modules + An example of a graded module with basis: + the free module on partitions over Integer Ring sage: pbp = lambda x: P.basis()[Partition(list(x))] - sage: p = pbp([3,1]) - 2 * pbp([2]) + 4 * pbp([1]) - sage: p.degree_negation() + sage: p = pbp([3,1]) - 2 * pbp([2]) + 4 * pbp([1]) # needs sage.combinat sage.modules + sage: p.degree_negation() # needs sage.combinat sage.modules -4*P[1] - 2*P[2] + P[3, 1] """ return self.parent().degree_negation(self) @@ -283,6 +295,7 @@ def degree_on_basis(self, m): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: E.<x,y,z> = ExteriorAlgebra(QQ) sage: S = E.submodule([x + y, x*y - y*z, y]) sage: Q = E.quotient_module(S) @@ -301,6 +314,7 @@ def degree(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: E.<x,y,z> = ExteriorAlgebra(QQ) sage: S = E.submodule([x + y, x*y - y*z, y]) sage: Q = E.quotient_module(S) diff --git a/src/sage/categories/group_algebras.py b/src/sage/categories/group_algebras.py index 0df6bf44165..1f68c28c3b4 100644 --- a/src/sage/categories/group_algebras.py +++ b/src/sage/categories/group_algebras.py @@ -50,15 +50,16 @@ class GroupAlgebras(AlgebrasCategory): Here is how to create the group algebra of a group `G`:: - sage: G = DihedralGroup(5) - sage: QG = G.algebra(QQ); QG - Algebra of Dihedral group of order 10 as a permutation group over Rational Field + sage: G = DihedralGroup(5) # needs sage.groups + sage: QG = G.algebra(QQ); QG # needs sage.groups sage.modules + Algebra of + Dihedral group of order 10 as a permutation group over Rational Field and an example of computation:: - sage: g = G.an_element(); g + sage: g = G.an_element(); g # needs sage.groups sage.modules (1,4)(2,3) - sage: (QG.term(g) + 1)**3 + sage: (QG.term(g) + 1)**3 # needs sage.groups sage.modules 4*() + 4*(1,4)(2,3) .. TODO:: @@ -68,14 +69,15 @@ class GroupAlgebras(AlgebrasCategory): TESTS:: + sage: # needs sage.groups sage.modules sage: A = GroupAlgebras(QQ).example(GL(3, GF(11))) sage: A.one_basis() [1 0 0] [0 1 0] [0 0 1] - sage: A = SymmetricGroupAlgebra(QQ,4) + sage: A = SymmetricGroupAlgebra(QQ, 4) # needs sage.combinat sage: x = Permutation([4,3,2,1]) - sage: A.product_on_basis(x,x) + sage: A.product_on_basis(x, x) # needs sage.combinat [1, 2, 3, 4] sage: C = GroupAlgebras(ZZ) @@ -104,13 +106,15 @@ def example(self, G=None): EXAMPLES:: - sage: GroupAlgebras(QQ['x']).example() - Algebra of Dihedral group of order 8 as a permutation group over Univariate Polynomial Ring in x over Rational Field + sage: GroupAlgebras(QQ['x']).example() # needs sage.groups sage.modules + Algebra of Dihedral group of order 8 as a permutation group + over Univariate Polynomial Ring in x over Rational Field An other group can be specified as optional argument:: - sage: GroupAlgebras(QQ).example(AlternatingGroup(4)) - Algebra of Alternating group of order 4!/2 as a permutation group over Rational Field + sage: GroupAlgebras(QQ).example(AlternatingGroup(4)) # needs sage.groups sage.modules + Algebra of + Alternating group of order 4!/2 as a permutation group over Rational Field """ from sage.groups.perm_gps.permgroup_named import DihedralGroup if G is None: @@ -124,6 +128,7 @@ def __init_extra__(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: A = GroupAlgebra(SymmetricGroup(4), QQ) sage: B = GroupAlgebra(SymmetricGroup(3), ZZ) sage: A.has_coerce_map_from(B) @@ -152,8 +157,8 @@ def _latex_(self): EXAMPLES:: - sage: A = GroupAlgebra(KleinFourGroup(), ZZ) - sage: latex(A) # indirect doctest + sage: A = GroupAlgebra(KleinFourGroup(), ZZ) # needs sage.groups sage.modules + sage: latex(A) # indirect doctest # needs sage.groups sage.modules \Bold{Z}[\langle (3,4), (1,2) \rangle] """ from sage.misc.latex import latex @@ -165,9 +170,9 @@ def group(self): EXAMPLES:: - sage: GroupAlgebras(QQ).example(GL(3, GF(11))).group() + sage: GroupAlgebras(QQ).example(GL(3, GF(11))).group() # needs sage.groups sage.modules General Linear Group of degree 3 over Finite Field of size 11 - sage: SymmetricGroup(10).algebra(QQ).group() + sage: SymmetricGroup(10).algebra(QQ).group() # needs sage.groups sage.modules Symmetric group of order 10! as a permutation group """ return self.basis().keys() @@ -195,7 +200,7 @@ def center_basis(self): EXAMPLES:: - sage: SymmetricGroup(3).algebra(QQ).center_basis() + sage: SymmetricGroup(3).algebra(QQ).center_basis() # needs sage.groups sage.modules ((), (2,3) + (1,2) + (1,3), (1,2,3) + (1,3,2)) .. SEEALSO:: @@ -217,8 +222,10 @@ def coproduct_on_basis(self, g): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: A = CyclicPermutationGroup(6).algebra(ZZ); A - Algebra of Cyclic group of order 6 as a permutation group over Integer Ring + Algebra of + Cyclic group of order 6 as a permutation group over Integer Ring sage: g = CyclicPermutationGroup(6).an_element(); g (1,2,3,4,5,6) sage: A.coproduct_on_basis(g) @@ -242,9 +249,11 @@ def antipode_on_basis(self,g): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: A = CyclicPermutationGroup(6).algebra(ZZ); A - Algebra of Cyclic group of order 6 as a permutation group over Integer Ring - sage: g = CyclicPermutationGroup(6).an_element();g + Algebra of + Cyclic group of order 6 as a permutation group over Integer Ring + sage: g = CyclicPermutationGroup(6).an_element(); g (1,2,3,4,5,6) sage: A.antipode_on_basis(g) (1,6,5,4,3,2) @@ -265,11 +274,12 @@ def counit_on_basis(self,g): EXAMPLES:: - sage: A = CyclicPermutationGroup(6).algebra(ZZ);A - Algebra of Cyclic group of order 6 as a permutation group over Integer Ring - sage: g = CyclicPermutationGroup(6).an_element();g + sage: A = CyclicPermutationGroup(6).algebra(ZZ); A # needs sage.groups sage.modules + Algebra of + Cyclic group of order 6 as a permutation group over Integer Ring + sage: g = CyclicPermutationGroup(6).an_element(); g # needs sage.groups sage.modules (1,2,3,4,5,6) - sage: A.counit_on_basis(g) + sage: A.counit_on_basis(g) # needs sage.groups sage.modules 1 """ return self.base_ring().one() @@ -284,11 +294,12 @@ def counit(self,x): EXAMPLES:: - sage: A = CyclicPermutationGroup(6).algebra(ZZ); A - Algebra of Cyclic group of order 6 as a permutation group over Integer Ring - sage: a = A.an_element(); a + sage: A = CyclicPermutationGroup(6).algebra(ZZ); A # needs sage.groups sage.modules + Algebra of + Cyclic group of order 6 as a permutation group over Integer Ring + sage: a = A.an_element(); a # needs sage.groups sage.modules () + 3*(1,2,3,4,5,6) + 3*(1,3,5)(2,4,6) - sage: a.counit() + sage: a.counit() # needs sage.groups sage.modules 7 """ return self.base_ring().sum(x.coefficients()) @@ -305,17 +316,20 @@ def is_integral_domain(self, proof=True): EXAMPLES:: - sage: GroupAlgebra(SymmetricGroup(2)).is_integral_domain() + sage: # needs sage.groups sage.modules + sage: S2 = SymmetricGroup(2) + sage: GroupAlgebra(S2).is_integral_domain() False - sage: GroupAlgebra(SymmetricGroup(1)).is_integral_domain() + sage: S1 = SymmetricGroup(1) + sage: GroupAlgebra(S1).is_integral_domain() True - sage: GroupAlgebra(SymmetricGroup(1), IntegerModRing(4)).is_integral_domain() + sage: GroupAlgebra(S1, IntegerModRing(4)).is_integral_domain() False sage: GroupAlgebra(AbelianGroup(1)).is_integral_domain() True sage: GroupAlgebra(AbelianGroup(2, [0,2])).is_integral_domain() False - sage: GroupAlgebra(GL(2, ZZ)).is_integral_domain() # not implemented + sage: GroupAlgebra(GL(2, ZZ)).is_integral_domain() # not implemented False """ from sage.sets.set import Set @@ -385,22 +399,26 @@ def central_form(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: QS3 = SymmetricGroup(3).algebra(QQ) sage: A = QS3([2,3,1]) + QS3([3,1,2]) sage: A.central_form() B[(1,2,3)] sage: QS4 = SymmetricGroup(4).algebra(QQ) - sage: B = sum(len(s.cycle_type())*QS4(s) for s in Permutations(4)) + sage: B = sum(len(s.cycle_type()) * QS4(s) for s in Permutations(4)) sage: B.central_form() 4*B[()] + 3*B[(1,2)] + 2*B[(1,2)(3,4)] + 2*B[(1,2,3)] + B[(1,2,3,4)] The following test fails due to a bug involving combinatorial free modules and the coercion system (see :trac:`28544`):: - sage: QG = GroupAlgebras(QQ).example(PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])) - sage: s = sum(i for i in QG.basis()) - sage: s.central_form() # not tested - B[()] + B[(4,5)] + B[(3,4,5)] + B[(2,3)(4,5)] + B[(2,3,4,5)] + B[(1,2)(3,4,5)] + B[(1,2,3,4,5)] + sage: # needs sage.groups sage.modules + sage: G = PermutationGroup([[(1,2,3),(4,5)], [(3,4)]]) + sage: QG = GroupAlgebras(QQ).example(G) + sage: s = sum(QG.basis()) + sage: s.central_form() # not tested + B[()] + B[(4,5)] + B[(3,4,5)] + B[(2,3)(4,5)] + + B[(2,3,4,5)] + B[(1,2)(3,4,5)] + B[(1,2,3,4,5)] .. SEEALSO:: diff --git a/src/sage/categories/groupoid.py b/src/sage/categories/groupoid.py index 4c6e3ae6042..850e63a2c09 100644 --- a/src/sage/categories/groupoid.py +++ b/src/sage/categories/groupoid.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups r""" Groupoid """ @@ -51,7 +52,7 @@ def _repr_(self): sage: Groupoid(S8) Groupoid with underlying set Symmetric group of order 8! as a permutation group """ - return "Groupoid with underlying set %s"%self.__G + return "Groupoid with underlying set %s" % self.__G #def construction(self): # return (self.__class__, self.__G) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 97d57799f8c..445ba111c09 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -42,7 +42,7 @@ def example(self): """ EXAMPLES:: - sage: Groups().example() + sage: Groups().example() # needs sage.modules General Linear Group of degree 4 over Rational Field """ from sage.rings.rational_field import QQ @@ -69,6 +69,7 @@ def free(index_set=None, names=None, **kwds): EXAMPLES:: + sage: # needs sage.groups sage: Groups.free(index_set=ZZ) Free group indexed by Integer Ring sage: Groups().free(ZZ) @@ -99,8 +100,8 @@ def group_generators(self): EXAMPLES:: - sage: A = AlternatingGroup(4) - sage: A.group_generators() + sage: A = AlternatingGroup(4) # needs sage.groups + sage: A.group_generators() # needs sage.groups Family ((2,3,4), (1,2,3)) """ from sage.sets.family import Family @@ -120,6 +121,7 @@ def monoid_generators(self): EXAMPLES:: + sage: # needs sage.groups sage: A = AlternatingGroup(4) sage: A.monoid_generators() Family ((2,3,4), (1,2,3)) @@ -142,8 +144,8 @@ def _test_inverse(self, **options): EXAMPLES:: - sage: G = SymmetricGroup(3) - sage: G._test_inverse() + sage: G = SymmetricGroup(3) # needs sage.groups + sage: G._test_inverse() # needs sage.groups """ tester = self._tester(**options) for x in tester.some_elements(): @@ -156,11 +158,13 @@ def semidirect_product(self, N, mapping, check=True): EXAMPLES:: - sage: G = Groups().example() - sage: G.semidirect_product(G,Morphism(G,G)) + sage: G = Groups().example() # needs sage.modules + sage: G.semidirect_product(G, Morphism(G, G)) # needs sage.modules Traceback (most recent call last): ... - NotImplementedError: semidirect product of General Linear Group of degree 4 over Rational Field and General Linear Group of degree 4 over Rational Field not yet implemented + NotImplementedError: semidirect product of General Linear Group of degree 4 + over Rational Field and General Linear Group of degree 4 over Rational Field + not yet implemented """ raise NotImplementedError("semidirect product of %s and %s not yet implemented" % (self, N)) @@ -176,13 +180,14 @@ def holomorph(self): EXAMPLES:: - sage: G = Groups().example() - sage: G.holomorph() + sage: G = Groups().example() # needs sage.modules + sage: G.holomorph() # needs sage.modules Traceback (most recent call last): ... - NotImplementedError: holomorph of General Linear Group of degree 4 over Rational Field not yet implemented + NotImplementedError: holomorph of General Linear Group of degree 4 + over Rational Field not yet implemented """ - raise NotImplementedError("holomorph of %s not yet implemented"%self) + raise NotImplementedError("holomorph of %s not yet implemented" % self) def cayley_table(self, names='letters', elements=None): r""" @@ -243,6 +248,7 @@ def cayley_table(self, names='letters', elements=None): Permutation groups, matrix groups and abelian groups can all compute their multiplication tables. :: + sage: # needs sage.groups sage: G = DiCyclicGroup(3) sage: T = G.cayley_table() sage: T.column_keys() @@ -265,8 +271,8 @@ def cayley_table(self, names='letters', elements=None): :: - sage: M = SL(2, 2) - sage: M.cayley_table() + sage: M = SL(2, 2) # needs sage.modules + sage: M.cayley_table() # needs sage.modules * a b c d e f +------------ a| a b c d e f @@ -279,8 +285,8 @@ def cayley_table(self, names='letters', elements=None): :: - sage: A = AbelianGroup([2, 3]) - sage: A.cayley_table() + sage: A = AbelianGroup([2, 3]) # needs sage.groups + sage: A.cayley_table() # needs sage.groups * a b c d e f +------------ a| a b c d e f @@ -298,8 +304,8 @@ def cayley_table(self, names='letters', elements=None): you can choose to just use the string representations of the elements themselves. :: - sage: C = CyclicPermutationGroup(11) - sage: C.cayley_table(names='digits') + sage: C = CyclicPermutationGroup(11) # needs sage.groups + sage: C.cayley_table(names='digits') # needs sage.groups * 00 01 02 03 04 05 06 07 08 09 10 +--------------------------------- 00| 00 01 02 03 04 05 06 07 08 09 10 @@ -316,9 +322,9 @@ def cayley_table(self, names='letters', elements=None): :: - sage: G = QuaternionGroup() + sage: G = QuaternionGroup() # needs sage.groups sage: names = ['1', 'I', '-1', '-I', 'J', '-K', '-J', 'K'] - sage: G.cayley_table(names=names) + sage: G.cayley_table(names=names) # needs sage.groups * 1 I -1 -I J -K -J K +------------------------ 1| 1 I -1 -I J -K -J K @@ -332,8 +338,8 @@ def cayley_table(self, names='letters', elements=None): :: - sage: A = AbelianGroup([2,2]) - sage: A.cayley_table(names='elements') + sage: A = AbelianGroup([2, 2]) # needs sage.groups + sage: A.cayley_table(names='elements') # needs sage.groups * 1 f1 f0 f0*f1 +------------------------ 1| 1 f1 f0 f0*f1 @@ -345,6 +351,7 @@ def cayley_table(self, names='letters', elements=None): routine behaves similarly, but changes an existing table "in-place." :: + sage: # needs sage.groups sage: G = AlternatingGroup(3) sage: T = G.cayley_table() sage: T.change_names('digits') @@ -360,8 +367,8 @@ def cayley_table(self, names='letters', elements=None): Elements will be coerced into the group as part of setting up the table. :: - sage: G = SL(2,ZZ) - sage: G + sage: # needs sage.modules + sage: G = SL(2,ZZ); G Special Linear Group of degree 2 over Integer Ring sage: identity = matrix(ZZ, [[1,0], [0,1]]) sage: G.cayley_table(elements=[identity, -identity]) @@ -381,11 +388,11 @@ class provides even greater flexibility, including changing confirms that they form a closed subset in the group. :: + sage: # needs sage.groups sage.modules sage: from sage.matrix.operation_table import OperationTable sage: G = DiCyclicGroup(3) sage: commutator = lambda x, y: x*y*x^-1*y^-1 - sage: T = OperationTable(G, commutator) - sage: T + sage: T = OperationTable(G, commutator); T . a b c d e f g h i j k l +------------------------ a| a a a a a a a a a a a a @@ -400,7 +407,6 @@ class provides even greater flexibility, including changing j| a b c a b c a c b a c b k| a b c a b c b a c b a c l| a b c a b c c b a c b a - sage: trans = T.translation() sage: comm = [trans['a'], trans['b'], trans['c']] sage: comm @@ -437,9 +443,9 @@ def conjugacy_class(self, g): EXAMPLES:: - sage: A = AbelianGroup([2,2]) - sage: c = A.conjugacy_class(A.an_element()) - sage: type(c) + sage: A = AbelianGroup([2, 2]) # needs sage.groups + sage: c = A.conjugacy_class(A.an_element()) # needs sage.groups + sage: type(c) # needs sage.groups <class 'sage.groups.conjugacy_classes.ConjugacyClass_with_category'> """ from sage.groups.conjugacy_classes import ConjugacyClass @@ -452,29 +458,32 @@ def conjugacy_class(self): EXAMPLES:: - sage: D = DihedralGroup(5) - sage: g = D((1,3,5,2,4)) - sage: g.conjugacy_class() - Conjugacy class of (1,3,5,2,4) in Dihedral group of order 10 as a permutation group + sage: D = DihedralGroup(5) # needs sage.groups + sage: g = D((1,3,5,2,4)) # needs sage.groups + sage: g.conjugacy_class() # needs sage.groups + Conjugacy class of (1,3,5,2,4) + in Dihedral group of order 10 as a permutation group - sage: H = MatrixGroup([matrix(GF(5),2,[1,2, -1, 1]), matrix(GF(5),2, [1,1, 0,1])]) - sage: h = H(matrix(GF(5),2,[1,2, -1, 1])) - sage: h.conjugacy_class() + sage: H = MatrixGroup([matrix(GF(5), 2, [1,2, -1,1]), # needs sage.modules + ....: matrix(GF(5), 2, [1,1, 0,1])]) + sage: h = H(matrix(GF(5), 2, [1,2, -1,1])) # needs sage.modules + sage: h.conjugacy_class() # needs sage.groups sage.modules Conjugacy class of [1 2] - [4 1] in Matrix group over Finite Field of size 5 with 2 generators ( + [4 1] + in Matrix group over Finite Field of size 5 with 2 generators ( [1 2] [1 1] [4 1], [0 1] ) - sage: G = SL(2, GF(2)) - sage: g = G.gens()[0] - sage: g.conjugacy_class() + sage: G = SL(2, GF(2)) # needs sage.modules + sage: g = G.gens()[0] # needs sage.modules + sage: g.conjugacy_class() # needs sage.modules Conjugacy class of [1 1] [0 1] in Special Linear Group of degree 2 over Finite Field of size 2 - sage: G = SL(2, QQ) - sage: g = G([[1,1],[0,1]]) - sage: g.conjugacy_class() + sage: G = SL(2, QQ) # needs sage.modules + sage: g = G([[1,1], [0,1]]) # needs sage.modules + sage: g.conjugacy_class() # needs sage.groups sage.modules Conjugacy class of [1 1] [0 1] in Special Linear Group of degree 2 over Rational Field """ @@ -505,6 +514,7 @@ def free(index_set=None, names=None, **kwds): EXAMPLES:: + sage: # needs sage.groups sage: Groups.Commutative.free(index_set=ZZ) Free abelian group indexed by Integer Ring sage: Groups().Commutative().free(ZZ) @@ -568,6 +578,7 @@ def group_generators(self): EXAMPLES:: + sage: # needs sage.groups sage: C5 = CyclicPermutationGroup(5) sage: C4 = CyclicPermutationGroup(4) sage: S4 = SymmetricGroup(3) @@ -580,12 +591,13 @@ def group_generators(self): We check the other portion of :trac:`16718` is fixed:: - sage: len(C.j_classes()) + sage: len(C.j_classes()) # needs sage.groups 1 An example with an infinitely generated group (a better output is needed):: + sage: # needs sage.groups sage: G = Groups.free([1,2]) sage: H = Groups.free(ZZ) sage: C = cartesian_product([G, H]) @@ -622,13 +634,13 @@ def order(self): EXAMPLES:: - sage: C = cartesian_product([SymmetricGroup(10), SL(2,GF(3))]) - sage: C.order() + sage: C = cartesian_product([SymmetricGroup(10), SL(2, GF(3))]) # needs sage.groups sage.rings.finite_rings + sage: C.order() # needs sage.groups sage.rings.finite_rings 87091200 TESTS:: - sage: C.order.__module__ + sage: C.order.__module__ # needs sage.groups sage.rings.finite_rings 'sage.categories.groups' .. TODO:: diff --git a/src/sage/categories/hecke_modules.py b/src/sage/categories/hecke_modules.py index 88331973496..118e155654e 100644 --- a/src/sage/categories/hecke_modules.py +++ b/src/sage/categories/hecke_modules.py @@ -64,7 +64,7 @@ def __init__(self, R): sage: TestSuite(HeckeModules(ZZ)).run() - sage: HeckeModules(Partitions(3)).run() + sage: HeckeModules(Partitions(3)).run() # needs sage.combinat Traceback (most recent call last): ... TypeError: R (=Partitions of the integer 3) must be a commutative ring @@ -84,7 +84,6 @@ def super_categories(self): R = self.base_ring() return [ModulesWithBasis(R)] - def _repr_object_names(self): """ Return the names of the objects of this category. @@ -104,7 +103,7 @@ class ParentMethods: def _Hom_(self, Y, category): r""" - Returns the homset from ``self`` to ``Y`` in the category ``category`` + Return the homset from ``self`` to ``Y`` in the category ``category`` INPUT: @@ -122,9 +121,13 @@ def _Hom_(self, Y, category): EXAMPLES:: + sage: # needs sage.modular sage: M = ModularForms(Gamma0(7), 4) - sage: H = M._Hom_(M, category = HeckeModules(QQ)); H - Set of Morphisms from Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field to Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field in Category of Hecke modules over Rational Field + sage: H = M._Hom_(M, category=HeckeModules(QQ)); H + Set of Morphisms + from Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field + to Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field + in Category of Hecke modules over Rational Field sage: H.__class__ <class 'sage.modular.hecke.homspace.HeckeModuleHomspace_with_category'> sage: TestSuite(H).run(skip=["_test_elements", "_test_an_element", "_test_elements_eq", @@ -140,14 +143,15 @@ def _Hom_(self, Y, category): TESTS:: - sage: H = M._Hom_(M, category = HeckeModules(GF(5))); H + sage: H = M._Hom_(M, category=HeckeModules(GF(5))); H # needs sage.modular sage.rings.finite_rings Traceback (most recent call last): ... - TypeError: Category of Hecke modules over Finite Field of size 5 is not a subcategory of Category of Hecke modules over Rational Field + TypeError: Category of Hecke modules over Finite Field of size 5 + is not a subcategory of Category of Hecke modules over Rational Field """ # TODO: double check that it's the correct HeckeModules category below: if category is not None and not category.is_subcategory(HeckeModules(self.base_ring())): - raise TypeError("%s is not a subcategory of %s"%(category, HeckeModules(self.base_ring()))) + raise TypeError("%s is not a subcategory of %s" % (category, HeckeModules(self.base_ring()))) from sage.modular.hecke.homspace import HeckeModuleHomspace return HeckeModuleHomspace(self, Y, category=category) diff --git a/src/sage/categories/highest_weight_crystals.py b/src/sage/categories/highest_weight_crystals.py index b8afdee2117..35cec0173a6 100644 --- a/src/sage/categories/highest_weight_crystals.py +++ b/src/sage/categories/highest_weight_crystals.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.graphs r""" Highest Weight Crystals """ @@ -128,7 +129,8 @@ def highest_weight_vectors(self): :: sage: C = crystals.Letters(['A',2]) - sage: T = crystals.TensorProduct(C,C,C,generators=[[C(2),C(1),C(1)],[C(1),C(2),C(1)]]) + sage: T = crystals.TensorProduct(C, C, C, generators=[[C(2),C(1),C(1)], + ....: [C(1),C(2),C(1)]]) sage: T.highest_weight_vectors() ([2, 1, 1], [1, 2, 1]) """ @@ -174,7 +176,8 @@ def lowest_weight_vectors(self): :: sage: C = crystals.Letters(['A',2]) - sage: T = crystals.TensorProduct(C,C,C,generators=[[C(2),C(1),C(1)],[C(1),C(2),C(1)]]) + sage: T = crystals.TensorProduct(C, C, C,generators=[[C(2),C(1),C(1)], + ....: [C(1),C(2),C(1)]]) sage: T.lowest_weight_vectors() ([3, 2, 3], [3, 3, 2]) """ diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 88b162c5845..22ba9d047fc 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -21,6 +21,7 @@ Nonetheless, garbage collection occurs when the original references are overwritten:: + sage: # needs sage.libs.pari sage: for p in prime_range(200): ....: K = GF(p) ....: H = Hom(ZZ, K) @@ -104,25 +105,35 @@ def Hom(X, Y, category=None, check=True): EXAMPLES:: - sage: V = VectorSpace(QQ,3) - sage: Hom(V, V) + sage: V = VectorSpace(QQ, 3) # needs sage.modules + sage: Hom(V, V) # needs sage.modules Set of Morphisms (Linear Transformations) from Vector space of dimension 3 over Rational Field to Vector space of dimension 3 over Rational Field - sage: G = AlternatingGroup(3) - sage: Hom(G, G) - Set of Morphisms from Alternating group of order 3!/2 as a permutation group to Alternating group of order 3!/2 as a permutation group in Category of finite enumerated permutation groups + sage: G = AlternatingGroup(3) # needs sage.groups + sage: Hom(G, G) # needs sage.groups + Set of Morphisms + from Alternating group of order 3!/2 as a permutation group + to Alternating group of order 3!/2 as a permutation group + in Category of finite enumerated permutation groups sage: Hom(ZZ, QQ, Sets()) Set of Morphisms from Integer Ring to Rational Field in Category of sets - sage: Hom(FreeModule(ZZ,1), FreeModule(QQ,1)) - Set of Morphisms from Ambient free module of rank 1 over the principal ideal domain Integer Ring to Vector space of dimension 1 over Rational Field in Category of commutative additive groups - sage: Hom(FreeModule(QQ,1), FreeModule(ZZ,1)) - Set of Morphisms from Vector space of dimension 1 over Rational Field to Ambient free module of rank 1 over the principal ideal domain Integer Ring in Category of commutative additive groups + sage: Hom(FreeModule(ZZ, 1), FreeModule(QQ, 1)) # needs sage.modules + Set of Morphisms + from Ambient free module of rank 1 over the principal ideal domain Integer Ring + to Vector space of dimension 1 over Rational Field + in Category of commutative additive groups + sage: Hom(FreeModule(QQ, 1), FreeModule(ZZ, 1)) # needs sage.modules + Set of Morphisms + from Vector space of dimension 1 over Rational Field + to Ambient free module of rank 1 over the principal ideal domain Integer Ring + in Category of commutative additive groups Here, we test against a memory leak that has been fixed at :trac:`11521` by using a weak cache:: + sage: # needs sage.libs.pari sage: for p in prime_range(10^3): ....: K = GF(p) ....: a = K(0) @@ -139,13 +150,13 @@ def Hom(X, Y, category=None, check=True): sage: X = ZZ; X Integer Ring - sage: Y = SymmetricGroup(3); Y + sage: Y = SymmetricGroup(3); Y # needs sage.groups Symmetric group of order 3! as a permutation group By default, the smallest category containing both ``X`` and ``Y``, is used:: - sage: Hom(X, Y) + sage: Hom(X, Y) # needs sage.groups Set of Morphisms from Integer Ring to Symmetric group of order 3! as a permutation group in Category of enumerated monoids @@ -153,10 +164,13 @@ def Hom(X, Y, category=None, check=True): Otherwise, if ``category`` is specified, then ``category`` is used, after checking that ``X`` and ``Y`` are indeed in ``category``:: - sage: Hom(X, Y, Magmas()) - Set of Morphisms from Integer Ring to Symmetric group of order 3! as a permutation group in Category of magmas + sage: Hom(X, Y, Magmas()) # needs sage.groups + Set of Morphisms + from Integer Ring + to Symmetric group of order 3! as a permutation group + in Category of magmas - sage: Hom(X, Y, Groups()) + sage: Hom(X, Y, Groups()) # needs sage.groups Traceback (most recent call last): ... ValueError: Integer Ring is not in Category of groups @@ -184,8 +198,8 @@ def Hom(X, Y, category=None, check=True): Homset are unique parents:: sage: k = GF(5) - sage: H1 = Hom(k,k) - sage: H2 = Hom(k,k) + sage: H1 = Hom(k, k) + sage: H2 = Hom(k, k) sage: H1 is H2 True @@ -231,8 +245,9 @@ def Hom(X, Y, category=None, check=True): Variation on the theme:: - sage: U1 = FreeModule(ZZ,2) - sage: U2 = FreeModule(ZZ,2,inner_product_matrix=matrix([[1,0],[0,-1]])) + sage: # needs sage.modules + sage: U1 = FreeModule(ZZ, 2) + sage: U2 = FreeModule(ZZ, 2, inner_product_matrix=matrix([[1,0], [0,-1]])) sage: U1 == U2, U1 is U2 (False, False) sage: V = ZZ^3 @@ -249,12 +264,18 @@ def Hom(X, Y, category=None, check=True): sage: PA = Parent(category=Algebras(QQ)) sage: PJ = Parent(category=Rings() & Modules(QQ)) - sage: Hom(PA,PJ) - Set of Homomorphisms from <sage.structure.parent.Parent object at ...> to <sage.structure.parent.Parent object at ...> - sage: Hom(PA,PJ).category() - Category of homsets of unital magmas and right modules over Rational Field and left modules over Rational Field - sage: Hom(PA,PJ, Rngs()) - Set of Morphisms from <sage.structure.parent.Parent object at ...> to <sage.structure.parent.Parent object at ...> in Category of rngs + sage: Hom(PA, PJ) + Set of Homomorphisms + from <sage.structure.parent.Parent object at ...> + to <sage.structure.parent.Parent object at ...> + sage: Hom(PA, PJ).category() + Category of homsets of + unital magmas and right modules over Rational Field + and left modules over Rational Field + sage: Hom(PA, PJ, Rngs()) + Set of Morphisms + from <sage.structure.parent.Parent object at ...> + to <sage.structure.parent.Parent object at ...> in Category of rngs .. TODO:: @@ -280,16 +301,14 @@ def Hom(X, Y, category=None, check=True): Checks that the domain and codomain are in the specified category. Case of a non parent:: + sage: # needs sage.graphs sage: S = SimplicialComplex([[1,2], [1,4]]); S.rename("S") sage: Hom(S, S, SimplicialComplexes()) Set of Morphisms from S to S in Category of finite simplicial complexes - sage: Hom(Set(), S, Sets()) Set of Morphisms from {} to S in Category of sets - sage: Hom(S, Set(), Sets()) Set of Morphisms from S to {} in Category of sets - sage: H = Hom(S, S, ChainComplexes(QQ)) Traceback (most recent call last): ... @@ -299,6 +318,7 @@ def Hom(X, Y, category=None, check=True): and not ``X.category().is_subcategory(category)`` as it used to be before :trac:`16275` (see :trac:`15801` for a real use case):: + sage: # needs sage.graphs sage: class PermissiveCategory(Category): ....: def super_categories(self): return [Objects()] ....: def __contains__(self, X): return True @@ -321,6 +341,7 @@ def Hom(X, Y, category=None, check=True): Case of a non parent:: + sage: # needs sage.graphs sage: cls = type(SimplicialComplex([[1,2], [1,4]])) sage: S = unpickle_newobj(cls, ()) sage: H = Hom(S, S, Sets(), check=False) @@ -331,9 +352,9 @@ def Hom(X, Y, category=None, check=True): uninitialized parent:: sage: P.<x,y> = QQ['x,y'] - sage: Q = P.quotient([x^2-1,y^2-1]) - sage: q = Q.an_element() - sage: explain_pickle(dumps(Q)) + sage: Q = P.quotient([x^2 - 1, y^2 - 1]) + sage: q = Q.an_element() # needs sage.libs.singular + sage: explain_pickle(dumps(Q)) # needs sage.libs.singular pg_... ... = pg_dynamic_class('QuotientRing_generic_with_category', (pg_QuotientRing_generic, pg_getattr(..., 'parent_class')), None, None, pg_QuotientRing_generic) si... = unpickle_newobj(..., ()) @@ -486,17 +507,21 @@ def End(X, category=None): EXAMPLES:: - sage: V = VectorSpace(QQ, 3) - sage: End(V) - Set of Morphisms (Linear Transformations) from - Vector space of dimension 3 over Rational Field to - Vector space of dimension 3 over Rational Field + sage: V = VectorSpace(QQ, 3) # needs sage.modules + sage: End(V) # needs sage.modules + Set of Morphisms (Linear Transformations) + from Vector space of dimension 3 over Rational Field + to Vector space of dimension 3 over Rational Field :: + sage: # needs sage.groups sage: G = AlternatingGroup(3) sage: S = End(G); S - Set of Morphisms from Alternating group of order 3!/2 as a permutation group to Alternating group of order 3!/2 as a permutation group in Category of finite enumerated permutation groups + Set of Morphisms + from Alternating group of order 3!/2 as a permutation group + to Alternating group of order 3!/2 as a permutation group + in Category of finite enumerated permutation groups sage: from sage.categories.homset import is_Endset sage: is_Endset(S) True @@ -512,10 +537,11 @@ def End(X, category=None): groups currently implement nothing more than unital magmas about their homsets, we have:: - sage: G = GL(3,3) + sage: # needs sage.groups + sage: G = GL(3, 3) sage: G.category() Category of finite groups - sage: H = Hom(G,G) + sage: H = Hom(G, G) sage: H.homset_category() Category of finite groups sage: H.category() @@ -557,8 +583,8 @@ class Homset(Set_generic): EXAMPLES:: - sage: H = Hom(QQ^2, QQ^3) - sage: loads(H.dumps()) is H + sage: H = Hom(QQ^2, QQ^3) # needs sage.modules + sage: loads(H.dumps()) is H # needs sage.modules True Homsets of unique parents are unique as well:: @@ -571,10 +597,11 @@ class Homset(Set_generic): Conversely, homsets of non-unique parents are non-unique:: - sage: H = End(ProductProjectiveSpaces(QQ, [1, 1])) - sage: loads(dumps(ProductProjectiveSpaces(QQ, [1, 1]))) is ProductProjectiveSpaces(QQ, [1, 1]) + sage: P11 = ProductProjectiveSpaces(QQ, [1, 1]) + sage: H = End(P11) + sage: loads(dumps(P11)) is ProductProjectiveSpaces(QQ, [1, 1]) False - sage: loads(dumps(ProductProjectiveSpaces(QQ, [1, 1]))) == ProductProjectiveSpaces(QQ, [1, 1]) + sage: loads(dumps(P11)) == ProductProjectiveSpaces(QQ, [1, 1]) True sage: loads(dumps(H)) is H False @@ -591,7 +618,7 @@ def __init__(self, X, Y, category=None, base=None, check=True): sage: class MyHomset(Homset): ....: def _an_element_(self): ....: return sage.categories.morphism.SetMorphism(self, f) - sage: import __main__; __main__.MyHomset = MyHomset # fakes MyHomset being defined in a Python module + sage: import __main__; __main__.MyHomset = MyHomset # fakes MyHomset being defined in a Python module sage: H = MyHomset(X, Y, category=Monoids(), base = ZZ) sage: H Set of Morphisms from X to Y in Category of monoids @@ -621,12 +648,12 @@ def __init__(self, X, Y, category=None, base=None, check=True): sage: Hom(R, R, category=Sets()).base_ring() sage: Hom(R, R, category=Modules(QQ)).base_ring() Rational Field - sage: Hom(QQ^3, QQ^3, category=Modules(QQ)).base_ring() + sage: Hom(QQ^3, QQ^3, category=Modules(QQ)).base_ring() # needs sage.modules Rational Field For whatever it's worth, the ``base`` arguments takes precedence:: - sage: MyHomset(ZZ^3, ZZ^3, base = QQ).base_ring() + sage: MyHomset(ZZ^3, ZZ^3, base=QQ).base_ring() # needs sage.modules Rational Field """ self._domain = X @@ -636,7 +663,7 @@ def __init__(self, X, Y, category=None, base=None, check=True): self.__category = category if check: if not isinstance(category, Category): - raise TypeError("category (=%s) must be a category"%category) + raise TypeError("category (=%s) must be a category" % category) #if not X in category: # raise TypeError, "X (=%s) must be in category (=%s)"%(X, category) #if not Y in category: @@ -679,8 +706,8 @@ def __reduce__(self): EXAMPLES:: - sage: H = Hom(QQ^2, QQ^3) - sage: H.__reduce__() + sage: H = Hom(QQ^2, QQ^3) # needs sage.modules + sage: H.__reduce__() # needs sage.modules (<function Hom at ...>, (Vector space of dimension 2 over Rational Field, Vector space of dimension 3 over Rational Field, @@ -690,15 +717,16 @@ def __reduce__(self): TESTS:: - sage: loads(H.dumps()) is H + sage: loads(H.dumps()) is H # needs sage.modules True Homsets of non-unique parents are non-unique as well:: - sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) + sage: # needs sage.groups + sage: G = PermutationGroup([[(1, 2, 3), (4, 5)], [(3, 4)]]) sage: G is loads(dumps(G)) False - sage: H = Hom(G,G) + sage: H = Hom(G, G) sage: H is loads(dumps(H)) False sage: H == loads(dumps(H)) @@ -710,7 +738,7 @@ def _repr_(self): """ TESTS:: - sage: Hom(ZZ^2, QQ, category=Sets())._repr_() + sage: Hom(ZZ^2, QQ, category=Sets())._repr_() # needs sage.modules 'Set of Morphisms from Ambient free module of rank 2 over the principal ideal domain Integer Ring to Rational Field in Category of sets' """ return "Set of Morphisms from {} to {} in {}".format(self._domain, @@ -727,10 +755,10 @@ def __hash__(self): sage: hash(Hom(QQ, ZZ)) == hash((QQ, ZZ, QQ)) True - sage: E = EllipticCurve('37a') # optional - sage.symbolic - sage: H = E(0).parent(); H # optional - sage.symbolic + sage: E = EllipticCurve('37a') # needs sage.schemes + sage: H = E(0).parent(); H # needs sage.schemes Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field - sage: hash(H) == hash((H.domain(), H.codomain(), H.base())) + sage: hash(H) == hash((H.domain(), H.codomain(), H.base())) # needs sage.schemes True """ return hash((self._domain, self._codomain, self.base())) @@ -751,8 +779,8 @@ def homset_category(self): EXAMPLES:: - sage: H = Hom(AlternatingGroup(4), AlternatingGroup(7)) - sage: H.homset_category() + sage: H = Hom(AlternatingGroup(4), AlternatingGroup(7)) # needs sage.groups + sage: H.homset_category() # needs sage.groups Category of finite enumerated permutation groups """ return self.__category @@ -763,9 +791,9 @@ def _element_constructor_(self, x, check=None, **options): EXAMPLES:: - sage: H = Hom(SymmetricGroup(4), SymmetricGroup(7)) - sage: phi = Hom(SymmetricGroup(5), SymmetricGroup(6)).natural_map() - sage: phi + sage: H = Hom(SymmetricGroup(4), SymmetricGroup(7)) # needs sage.groups + sage: phi = Hom(SymmetricGroup(5), SymmetricGroup(6)).natural_map() # needs sage.groups + sage: phi # needs sage.groups Coercion morphism: From: Symmetric group of order 5! as a permutation group To: Symmetric group of order 6! as a permutation group @@ -777,7 +805,7 @@ def _element_constructor_(self, x, check=None, **options): collection, if there is a strong reference to its domain (which is the case here):: - sage: H(phi) + sage: H(phi) # needs sage.groups Composite map: From: Symmetric group of order 4! as a permutation group To: Symmetric group of order 7! as a permutation group @@ -798,7 +826,7 @@ def _element_constructor_(self, x, check=None, **options): Also note that making a copy of the resulting map will automatically make strengthened copies of the composed maps:: - sage: copy(H(phi)) + sage: copy(H(phi)) # needs sage.groups Composite map: From: Symmetric group of order 4! as a permutation group To: Symmetric group of order 7! as a permutation group @@ -825,7 +853,7 @@ def _element_constructor_(self, x, check=None, **options): (2, 3, 4) sage: H = Hom(Set([1,2,3]), Set([1,2,3])) - sage: f = H( lambda x: 4-x ) + sage: f = H(lambda x: 4 - x) sage: f.parent() Set of Morphisms from {1, 2, 3} to {1, 2, 3} in Category of finite enumerated sets sage: f(1), f(2), f(3) # todo: not implemented @@ -884,6 +912,7 @@ def _element_constructor_(self, x, check=None, **options): TESTS:: + sage: # needs sage.groups sage: G.<x,y,z> = FreeGroup() sage: H = Hom(G, G) sage: H(H.identity()) @@ -928,12 +957,12 @@ def _element_constructor_(self, x, check=None, **options): if x.domain() != self.domain(): mor = x.domain()._internal_coerce_map_from(self.domain()) if mor is None: - raise TypeError("Incompatible domains: x (=%s) cannot be an element of %s"%(x,self)) + raise TypeError("Incompatible domains: x (=%s) cannot be an element of %s" % (x,self)) x = x * mor if x.codomain() != self.codomain(): mor = self.codomain()._internal_coerce_map_from(x.codomain()) if mor is None: - raise TypeError("Incompatible codomains: x (=%s) cannot be an element of %s"%(x,self)) + raise TypeError("Incompatible codomains: x (=%s) cannot be an element of %s" % (x,self)) x = mor * x return x @@ -981,6 +1010,7 @@ class of ``C`` will be inherited by *all* subcategories of Let's take a homset of finite commutative groups as example; at this point this is the simplest one to create (gosh):: + sage: # needs sage.groups sage: cat = Groups().Finite().Commutative() sage: C3 = PermutationGroup([(1,2,3)]) sage: C3._refine_category_(cat) @@ -1000,6 +1030,7 @@ class of ``C`` will be inherited by *all* subcategories of of semigroups, of magmas, ...; it thus inherits code from all those categories:: + sage: # needs sage.groups sage: issubclass(cls, Semigroups().Finite().morphism_class) True sage: issubclass(cls, Semigroups().morphism_class) @@ -1014,12 +1045,12 @@ class of ``C`` will be inherited by *all* subcategories of Recall that FiniteMonoids() is a full subcategory of ``Monoids()``, but not of ``FiniteSemigroups()``. Thus:: - sage: issubclass(cls, Monoids().Finite().Homsets().element_class) + sage: issubclass(cls, Monoids().Finite().Homsets().element_class) # needs sage.groups True - sage: issubclass(cls, Semigroups().Finite().Homsets().element_class) + sage: issubclass(cls, Semigroups().Finite().Homsets().element_class) # needs sage.groups False """ - class_name = "%s._abstract_element_class"%self.__class__.__name__ + class_name = "%s._abstract_element_class" % self.__class__.__name__ return dynamic_class(class_name, (self.category().element_class, self.homset_category().morphism_class)) @lazy_attribute @@ -1117,11 +1148,13 @@ def natural_map(self): Coercion morphism: From: Univariate Polynomial Ring in t over Integer Ring To: Univariate Polynomial Ring in t over Rational Field - sage: H = Hom(QQ['t'],GF(3)['t']) + sage: H = Hom(QQ['t'], GF(3)['t']) sage: H.natural_map() Traceback (most recent call last): ... - TypeError: natural coercion morphism from Univariate Polynomial Ring in t over Rational Field to Univariate Polynomial Ring in t over Finite Field of size 3 not defined + TypeError: natural coercion morphism + from Univariate Polynomial Ring in t over Rational Field + to Univariate Polynomial Ring in t over Finite Field of size 3 not defined """ return morphism.FormalCoercionMorphism(self) # good default in many cases @@ -1162,9 +1195,10 @@ def one(self): EXAMPLES:: - sage: K = GaussianIntegers() - sage: End(K).one() - Identity endomorphism of Gaussian Integers in Number Field in I with defining polynomial x^2 + 1 with I = 1*I + sage: K = GaussianIntegers() # needs sage.rings.number_field + sage: End(K).one() # needs sage.rings.number_field + Identity endomorphism of Gaussian Integers in Number Field in I + with defining polynomial x^2 + 1 with I = 1*I """ return self.identity() @@ -1205,6 +1239,7 @@ def reversed(self): EXAMPLES:: + sage: # needs sage.modules sage: H = Hom(ZZ^2, ZZ^3); H Set of Morphisms from Ambient free module of rank 2 over the principal ideal domain Integer Ring to Ambient free module diff --git a/src/sage/categories/homsets.py b/src/sage/categories/homsets.py index 7604ec9df72..794d79d304e 100644 --- a/src/sage/categories/homsets.py +++ b/src/sage/categories/homsets.py @@ -199,7 +199,7 @@ def _repr_object_names(self): except ValueError: assert isinstance(base_category, JoinCategory) object_names = ' and '.join(cat._repr_object_names() for cat in base_category.super_categories()) - return "homsets of %s"%(object_names) + return "homsets of %s" % (object_names) def super_categories(self): r""" diff --git a/src/sage/categories/hopf_algebras.py b/src/sage/categories/hopf_algebras.py index 84858c7c5bf..41e349690fe 100644 --- a/src/sage/categories/hopf_algebras.py +++ b/src/sage/categories/hopf_algebras.py @@ -67,8 +67,10 @@ def antipode(self): EXAMPLES:: + sage: # needs sage.groups sage: A = HopfAlgebrasWithBasis(QQ).example(); A - An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field + An example of Hopf algebra with basis: the group algebra of the + Dihedral group of order 6 as a permutation group over Rational Field sage: [a,b] = A.algebra_generators() sage: a, a.antipode() (B[(1,2,3)], B[(1,3,2)]) @@ -77,7 +79,7 @@ def antipode(self): TESTS:: - sage: all(x.antipode() * x == A.one() for x in A.basis()) + sage: all(x.antipode() * x == A.one() for x in A.basis()) # needs sage.groups True """ return self.parent().antipode(self) @@ -135,9 +137,9 @@ def antipode(self): EXAMPLES:: - sage: A = SteenrodAlgebra(3) - sage: a = A.an_element() - sage: a, a.antipode() + sage: A = SteenrodAlgebra(3) # needs sage.combinat sage.modules + sage: a = A.an_element() # needs sage.combinat sage.modules + sage: a, a.antipode() # needs sage.combinat sage.modules (2 Q_1 Q_3 P(2,1), Q_1 Q_3 P(2,1)) """ return self.parent().antipode(self) @@ -204,6 +206,7 @@ def antipode_by_coercion(self, x): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: N = NonCommutativeSymmetricFunctions(QQ) sage: R = N.ribbon() sage: R.antipode_by_coercion.__module__ diff --git a/src/sage/categories/hopf_algebras_with_basis.py b/src/sage/categories/hopf_algebras_with_basis.py index 79a0b69ce14..615fc4eae06 100644 --- a/src/sage/categories/hopf_algebras_with_basis.py +++ b/src/sage/categories/hopf_algebras_with_basis.py @@ -33,22 +33,24 @@ class HopfAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): We now show how to use a simple Hopf algebra, namely the group algebra of the dihedral group (see also AlgebrasWithBasis):: - sage: A = C.example(); A - An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field - sage: A.__custom_name = "A" - sage: A.category() + sage: A = C.example(); A # needs sage.groups + An example of Hopf algebra with basis: the group algebra of the + Dihedral group of order 6 as a permutation group over Rational Field + sage: A.rename("A") # needs sage.groups + sage: A.category() # needs sage.groups Category of finite dimensional hopf algebras with basis over Rational Field - sage: A.one_basis() + sage: A.one_basis() # needs sage.groups () - sage: A.one() + sage: A.one() # needs sage.groups B[()] - sage: A.base_ring() + sage: A.base_ring() # needs sage.groups Rational Field - sage: A.basis().keys() + sage: A.basis().keys() # needs sage.groups Dihedral group of order 6 as a permutation group + sage: # needs sage.groups sage: [a,b] = A.algebra_generators() sage: a, b (B[(1,2,3)], B[(1,3)]) @@ -57,19 +59,19 @@ class HopfAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): sage: a*b B[(1,2)] - sage: A.product # todo: not quite ... + sage: A.product # todo: not quite ... # needs sage.groups <bound method MagmaticAlgebras.WithBasis.ParentMethods._product_from_product_on_basis_multiply of A> - sage: A.product(b,b) + sage: A.product(b, b) # needs sage.groups B[()] - sage: A.zero().coproduct() + sage: A.zero().coproduct() # needs sage.groups 0 - sage: A.zero().coproduct().parent() + sage: A.zero().coproduct().parent() # needs sage.groups A # A - sage: a.coproduct() + sage: a.coproduct() # needs sage.groups B[(1,2,3)] # B[(1,2,3)] - sage: TestSuite(A).run(verbose=True) + sage: TestSuite(A).run(verbose=True) # needs sage.groups running ._test_additive_associativity() . . . pass running ._test_an_element() . . . pass running ._test_antipode() . . . pass @@ -100,18 +102,18 @@ class HopfAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): running ._test_prod() . . . pass running ._test_some_elements() . . . pass running ._test_zero() . . . pass - sage: A.__class__ + sage: A.__class__ # needs sage.groups <class 'sage.categories.examples.hopf_algebras_with_basis.MyGroupAlgebra_with_category'> - sage: A.element_class + sage: A.element_class # needs sage.groups <class 'sage.categories.examples.hopf_algebras_with_basis.MyGroupAlgebra_with_category.element_class'> Let us look at the code for implementing A:: - sage: A?? # todo: not implemented + sage: A?? # not implemented # needs sage.groups TESTS:: - sage: TestSuite(A).run() + sage: TestSuite(A).run() # needs sage.groups sage: TestSuite(C).run() """ @@ -119,13 +121,16 @@ def example(self, G=None): """ Returns an example of algebra with basis:: - sage: HopfAlgebrasWithBasis(QQ['x']).example() - An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Univariate Polynomial Ring in x over Rational Field + sage: HopfAlgebrasWithBasis(QQ['x']).example() # needs sage.groups + An example of Hopf algebra with basis: the group algebra of the + Dihedral group of order 6 as a permutation group + over Univariate Polynomial Ring in x over Rational Field An other group can be specified as optional argument:: - sage: HopfAlgebrasWithBasis(QQ).example(SymmetricGroup(4)) - An example of Hopf algebra with basis: the group algebra of the Symmetric group of order 4! as a permutation group over Rational Field + sage: HopfAlgebrasWithBasis(QQ).example(SymmetricGroup(4)) # needs sage.groups + An example of Hopf algebra with basis: the group algebra of the + Symmetric group of order 4! as a permutation group over Rational Field """ from sage.categories.examples.hopf_algebras_with_basis import MyGroupAlgebra from sage.groups.perm_gps.permgroup_named import DihedralGroup @@ -175,6 +180,7 @@ def antipode_on_basis(self, x): EXAMPLES:: + sage: # needs sage.groups sage: A = HopfAlgebrasWithBasis(QQ).example() sage: W = A.basis().keys(); W Dihedral group of order 6 as a permutation group @@ -196,8 +202,10 @@ def antipode(self): EXAMPLES:: + sage: # needs sage.groups sage: A = HopfAlgebrasWithBasis(ZZ).example(); A - An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Integer Ring + An example of Hopf algebra with basis: the group algebra of the + Dihedral group of order 6 as a permutation group over Integer Ring sage: A = HopfAlgebrasWithBasis(QQ).example() sage: [a,b] = A.algebra_generators() sage: a, A.antipode(a) @@ -207,7 +215,7 @@ def antipode(self): TESTS:: - sage: all(A.antipode(x) * x == A.one() for x in A.basis()) + sage: all(A.antipode(x) * x == A.one() for x in A.basis()) # needs sage.groups True """ if self.antipode_on_basis is not NotImplemented: @@ -239,13 +247,13 @@ def _test_antipode(self, **options): TESTS:: - sage: R = NonCommutativeSymmetricFunctions(QQ).ribbon() - sage: R._test_antipode() + sage: R = NonCommutativeSymmetricFunctions(QQ).ribbon() # needs sage.combinat sage.modules + sage: R._test_antipode() # needs sage.combinat sage.modules :: - sage: s = SymmetricFunctions(QQ).schur() - sage: s._test_antipode() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: s._test_antipode() # needs sage.combinat sage.modules """ tester = self._tester(**options) diff --git a/src/sage/categories/infinite_enumerated_sets.py b/src/sage/categories/infinite_enumerated_sets.py index 581faab5ff4..3c7a861a4b6 100644 --- a/src/sage/categories/infinite_enumerated_sets.py +++ b/src/sage/categories/infinite_enumerated_sets.py @@ -88,7 +88,7 @@ def list(self): NotImplementedError: cannot list an infinite set """ raise NotImplementedError("cannot list an infinite set") - _list_default = list # needed by the check system. + _list_default = list # needed by the check system. def _test_enumerated_set_iter_cardinality(self, **options): """ diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index 2d5d7730693..b6e6f59a196 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -45,7 +45,7 @@ def __contains__(self, x): """ EXAMPLES:: - sage: GF(4, "a") in IntegralDomains() + sage: GF(4, "a") in IntegralDomains() # needs sage.rings.finite_rings True sage: QQ in IntegralDomains() True @@ -108,10 +108,10 @@ def is_integral_domain(self, proof=True): sage: Parent(QQ, category=IntegralDomains()).is_integral_domain() True - sage: L.<z> = LazyLaurentSeriesRing(QQ) - sage: L.is_integral_domain() + sage: L.<z> = LazyLaurentSeriesRing(QQ) # needs sage.combinat + sage: L.is_integral_domain() # needs sage.combinat True - sage: L.is_integral_domain(proof=True) + sage: L.is_integral_domain(proof=True) # needs sage.combinat True """ return True @@ -129,7 +129,7 @@ def _test_fraction_field(self, **options): tester = self._tester(**options) try: fraction_field = self.fraction_field() - except AttributeError: + except (AttributeError, ImportError): # some integral domains do not implement fraction_field() yet if self in Fields(): raise diff --git a/src/sage/categories/kac_moody_algebras.py b/src/sage/categories/kac_moody_algebras.py index cd7af55333d..52f738243b8 100644 --- a/src/sage/categories/kac_moody_algebras.py +++ b/src/sage/categories/kac_moody_algebras.py @@ -43,12 +43,12 @@ def example(self, n=2): EXAMPLES:: sage: from sage.categories.kac_moody_algebras import KacMoodyAlgebras - sage: KacMoodyAlgebras(QQ).example() + sage: KacMoodyAlgebras(QQ).example() # needs sage.combinat sage.modules Lie algebra of ['A', 2] in the Chevalley basis We can specify the rank of the example:: - sage: KacMoodyAlgebras(QQ).example(4) + sage: KacMoodyAlgebras(QQ).example(4) # needs sage.combinat sage.modules Lie algebra of ['A', 4] in the Chevalley basis """ from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis @@ -61,8 +61,8 @@ def cartan_type(self): EXAMPLES:: - sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) - sage: L.cartan_type() + sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) # needs sage.combinat sage.modules + sage: L.cartan_type() # needs sage.combinat sage.modules ['A', 2] """ return self._cartan_type @@ -73,8 +73,8 @@ def weyl_group(self): EXAMPLES:: - sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) - sage: L.weyl_group() + sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) # needs sage.combinat sage.modules + sage: L.weyl_group() # needs sage.combinat sage.modules Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space) """ from sage.combinat.root_system.weyl_group import WeylGroup diff --git a/src/sage/categories/lambda_bracket_algebras.py b/src/sage/categories/lambda_bracket_algebras.py index 531cfb826b1..40cb5ed70c4 100644 --- a/src/sage/categories/lambda_bracket_algebras.py +++ b/src/sage/categories/lambda_bracket_algebras.py @@ -45,9 +45,10 @@ def __classcall_private__(cls, R, check=True): EXAMPLES:: - sage: LieConformalAlgebras(QuaternionAlgebra(2)) + sage: LieConformalAlgebras(QuaternionAlgebra(2)) # needs sage.combinat sage.modules Traceback (most recent call last): - ValueError: base must be a commutative ring got Quaternion Algebra (-1, -1) with base ring Rational Field + ValueError: base must be a commutative ring + got Quaternion Algebra (-1, -1) with base ring Rational Field sage: LieConformalAlgebras(ZZ) Category of Lie conformal algebras over Integer Ring """ @@ -117,14 +118,15 @@ def ideal(self, *gens, **kwds): EXAMPLES:: - sage: Vir = lie_conformal_algebras.Virasoro(QQ) - sage: Vir.ideal() + sage: Vir = lie_conformal_algebras.Virasoro(QQ) # needs sage.combinat sage.modules + sage: Vir.ideal() # needs sage.combinat sage.modules Traceback (most recent call last): ... NotImplementedError: ideals of Lie Conformal algebras are not implemented yet """ raise NotImplementedError("ideals of Lie Conformal algebras are " "not implemented yet") + class ElementMethods: @coerce_binop @@ -136,18 +138,19 @@ def bracket(self, rhs): The brackets of the Virasoro Lie conformal algebra:: - sage: Vir = lie_conformal_algebras.Virasoro(QQ); L = Vir.0 - sage: L.bracket(L) + sage: Vir = lie_conformal_algebras.Virasoro(QQ); L = Vir.0 # needs sage.combinat sage.modules + sage: L.bracket(L) # needs sage.combinat sage.modules {0: TL, 1: 2*L, 3: 1/2*C} - sage: L.bracket(L.T()) + sage: L.bracket(L.T()) # needs sage.combinat sage.modules {0: 2*T^(2)L, 1: 3*TL, 2: 4*L, 4: 2*C} Now with a current algebra:: + sage: # needs sage.combinat sage.modules sage: V = lie_conformal_algebras.Affine(QQ, 'A1') sage: V.gens() (B[alpha[1]], B[alphacheck[1]], B[-alpha[1]], B['K']) - sage: E = V.0; H = V.1; F = V.2; + sage: E = V.0; H = V.1; F = V.2 sage: H.bracket(H) {1: 2*B['K']} sage: E.bracket(F) @@ -169,18 +172,19 @@ def _bracket_(self, rhs): The brackets of the Virasoro Lie conformal Algebra:: - sage: Vir = lie_conformal_algebras.Virasoro(QQ); L = Vir.0 - sage: L._bracket_(L) + sage: Vir = lie_conformal_algebras.Virasoro(QQ); L = Vir.0 # needs sage.combinat sage.modules + sage: L._bracket_(L) # needs sage.combinat sage.modules {0: TL, 1: 2*L, 3: 1/2*C} - sage: L._bracket_(L.T()) + sage: L._bracket_(L.T()) # needs sage.combinat sage.modules {0: 2*T^(2)L, 1: 3*TL, 2: 4*L, 4: 2*C} Now with a current algebra:: + sage: # needs sage.combinat sage.modules sage: V = lie_conformal_algebras.Affine(QQ, 'A1') sage: V.gens() (B[alpha[1]], B[alphacheck[1]], B[-alpha[1]], B['K']) - sage: E = V.0; H = V.1; F = V.2; + sage: E = V.0; H = V.1; F = V.2 sage: H._bracket_(H) {1: 2*B['K']} sage: E._bracket_(F) @@ -194,13 +198,14 @@ def nproduct(self, rhs, n): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: Vir = lie_conformal_algebras.Virasoro(QQ); L = Vir.0 sage: L.nproduct(L, 3) 1/2*C sage: L.nproduct(L.T(), 0) 2*T^(2)L sage: V = lie_conformal_algebras.Affine(QQ, 'A1') - sage: E = V.0; H = V.1; F = V.2; + sage: E = V.0; H = V.1; F = V.2 sage: E.nproduct(H, 0) == - 2*E True sage: E.nproduct(F, 1) @@ -219,16 +224,17 @@ def _nproduct_(self, rhs, n): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: Vir = lie_conformal_algebras.Virasoro(QQ); L = Vir.0 - sage: L._nproduct_(L,3) + sage: L._nproduct_(L, 3) 1/2*C - sage: L._nproduct_(L.T(),0) + sage: L._nproduct_(L.T(), 0) 2*T^(2)L sage: V = lie_conformal_algebras.Affine(QQ, 'A1') - sage: E = V.0; H = V.1; F = V.2; - sage: E._nproduct_(H,0) == - 2*E + sage: E = V.0; H = V.1; F = V.2 + sage: E._nproduct_(H, 0) == - 2*E True - sage: E._nproduct_(F,1) + sage: E._nproduct_(F, 1) B['K'] """ if n >= 0: @@ -253,6 +259,7 @@ def T(self, n=1): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: Vir = lie_conformal_algebras.Virasoro(QQ) sage: Vir.inject_variables() Defining L, C diff --git a/src/sage/categories/lambda_bracket_algebras_with_basis.py b/src/sage/categories/lambda_bracket_algebras_with_basis.py index 9b48ba34615..62fe41f3336 100644 --- a/src/sage/categories/lambda_bracket_algebras_with_basis.py +++ b/src/sage/categories/lambda_bracket_algebras_with_basis.py @@ -25,7 +25,7 @@ class LambdaBracketAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).WithBasis() + sage: LieConformalAlgebras(QQbar).WithBasis() # needs sage.rings.number_field Category of Lie conformal algebras with basis over Algebraic Field """ class ElementMethods: @@ -36,6 +36,7 @@ def index(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: V = lie_conformal_algebras.NeveuSchwarz(QQ) sage: V.inject_variables() Defining L, G, C @@ -63,10 +64,15 @@ class FinitelyGeneratedAsLambdaBracketAlgebra(CategoryWithAxiom_over_base_ring): EXAMPLES:: + sage: # needs sage.rings.number_field sage: C = LieConformalAlgebras(QQbar) - sage: C.WithBasis().FinitelyGenerated() - Category of finitely generated Lie conformal algebras with basis over Algebraic Field - sage: C.WithBasis().FinitelyGenerated() is C.FinitelyGenerated().WithBasis() + sage: C1 = C.WithBasis().FinitelyGenerated(); C1 + Category of finitely generated Lie conformal algebras with basis + over Algebraic Field + sage: C2 = C.FinitelyGenerated().WithBasis(); C2 + Category of finitely generated Lie conformal algebras with basis + over Algebraic Field + sage: C1 is C2 True """ class Graded(GradedModulesCategory): @@ -76,8 +82,10 @@ class Graded(GradedModulesCategory): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated().Graded() - Category of H-graded finitely generated Lie conformal algebras with basis over Algebraic Field + sage: C = LieConformalAlgebras(QQbar) # needs sage.rings.number_field + sage: C.WithBasis().FinitelyGenerated().Graded() # needs sage.rings.number_field + Category of H-graded finitely generated Lie conformal algebras + with basis over Algebraic Field """ class ParentMethods: @@ -88,8 +96,8 @@ def degree_on_basis(self, m): EXAMPLES:: - sage: V = lie_conformal_algebras.Virasoro(QQ) - sage: V.degree_on_basis(('L',2)) + sage: V = lie_conformal_algebras.Virasoro(QQ) # needs sage.combinat sage.modules + sage: V.degree_on_basis(('L', 2)) # needs sage.combinat sage.modules 4 """ if m[0] in self._central_elements: diff --git a/src/sage/categories/lattice_posets.py b/src/sage/categories/lattice_posets.py index d29635f078e..f14fa364415 100644 --- a/src/sage/categories/lattice_posets.py +++ b/src/sage/categories/lattice_posets.py @@ -66,8 +66,8 @@ def meet(self, x, y): EXAMPLES:: - sage: D = LatticePoset((divisors(30), attrcall("divides"))) - sage: D.meet( D(6), D(15) ) + sage: D = LatticePoset((divisors(30), attrcall("divides"))) # needs sage.graphs sage.modules + sage: D.meet( D(6), D(15) ) # needs sage.graphs sage.modules 3 """ @@ -82,7 +82,7 @@ def join(self, x, y): EXAMPLES:: - sage: D = LatticePoset((divisors(60), attrcall("divides"))) - sage: D.join( D(6), D(10) ) + sage: D = LatticePoset((divisors(60), attrcall("divides"))) # needs sage.graphs sage.modules + sage: D.join( D(6), D(10) ) # needs sage.graphs sage.modules 30 """ diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 269ca3dabbe..7244eab161b 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -45,24 +45,24 @@ class LieAlgebras(Category_over_base_ring): We construct a typical parent in this category, and do some computations with it:: - sage: A = C.example(); A + sage: A = C.example(); A # needs sage.groups sage.modules An example of a Lie algebra: the Lie algebra from the associative algebra Symmetric group algebra of order 3 over Rational Field generated by ([2, 1, 3], [2, 3, 1]) - sage: A.category() + sage: A.category() # needs sage.groups sage.modules Category of Lie algebras over Rational Field - sage: A.base_ring() + sage: A.base_ring() # needs sage.groups sage.modules Rational Field - sage: a,b = A.lie_algebra_generators() - sage: a.bracket(b) + sage: a, b = A.lie_algebra_generators() # needs sage.groups sage.modules + sage: a.bracket(b) # needs sage.groups sage.modules -[1, 3, 2] + [3, 2, 1] - sage: b.bracket(2*a + b) + sage: b.bracket(2*a + b) # needs sage.groups sage.modules 2*[1, 3, 2] - 2*[3, 2, 1] - sage: A.bracket(a, b) + sage: A.bracket(a, b) # needs sage.groups sage.modules -[1, 3, 2] + [3, 2, 1] Please see the source code of `A` (with ``A??``) for how to @@ -72,7 +72,7 @@ class LieAlgebras(Category_over_base_ring): sage: C = LieAlgebras(QQ) sage: TestSuite(C).run() - sage: TestSuite(C.example()).run() + sage: TestSuite(C.example()).run() # needs sage.combinat sage.modules .. TODO:: @@ -151,15 +151,15 @@ def example(self, gens=None): EXAMPLES:: - sage: LieAlgebras(QQ).example() + sage: LieAlgebras(QQ).example() # needs sage.groups sage.modules An example of a Lie algebra: the Lie algebra from the associative algebra Symmetric group algebra of order 3 over Rational Field generated by ([2, 1, 3], [2, 3, 1]) Another set of generators can be specified as an optional argument:: - sage: F.<x,y,z> = FreeAlgebra(QQ) - sage: LieAlgebras(QQ).example(F.gens()) + sage: F.<x,y,z> = FreeAlgebra(QQ) # needs sage.combinat sage.modules + sage: LieAlgebras(QQ).example(F.gens()) # needs sage.combinat sage.modules An example of a Lie algebra: the Lie algebra from the associative algebra Free Algebra on 3 generators (x, y, z) over Rational Field generated by (x, y, z) @@ -189,11 +189,14 @@ def extra_super_categories(self): [Category of finite sets] sage: LieAlgebras(ZZ).FiniteDimensional().extra_super_categories() [] - sage: LieAlgebras(GF(5)).FiniteDimensional().is_subcategory(Sets().Finite()) + sage: C = LieAlgebras(GF(5)).FiniteDimensional() + sage: C.is_subcategory(Sets().Finite()) True - sage: LieAlgebras(ZZ).FiniteDimensional().is_subcategory(Sets().Finite()) + sage: C = LieAlgebras(ZZ).FiniteDimensional() + sage: C.is_subcategory(Sets().Finite()) False - sage: LieAlgebras(GF(5)).WithBasis().FiniteDimensional().is_subcategory(Sets().Finite()) + sage: C = LieAlgebras(GF(5)).WithBasis().FiniteDimensional() + sage: C.is_subcategory(Sets().Finite()) True """ if self.base_ring() in Sets().Finite(): @@ -217,8 +220,8 @@ def step(self): EXAMPLES:: - sage: h = lie_algebras.Heisenberg(ZZ, oo) - sage: h.step() + sage: h = lie_algebras.Heisenberg(ZZ, oo) # needs sage.combinat sage.modules + sage: h.step() # needs sage.combinat sage.modules 2 """ @@ -228,8 +231,8 @@ def is_nilpotent(self): EXAMPLES:: - sage: h = lie_algebras.Heisenberg(ZZ, oo) - sage: h.is_nilpotent() + sage: h = lie_algebras.Heisenberg(ZZ, oo) # needs sage.combinat sage.modules + sage: h.is_nilpotent() # needs sage.combinat sage.modules True """ return True @@ -254,8 +257,9 @@ def bracket(self, lhs, rhs): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() + sage: x, y = L.lie_algebra_generators() sage: L.bracket(x, x + y) -[1, 3, 2] + [3, 2, 1] sage: L.bracket(x, 0) @@ -265,19 +269,19 @@ def bracket(self, lhs, rhs): Constructing the product space:: - sage: L = lie_algebras.Heisenberg(QQ, 1) - sage: Z = L.bracket(L, L); Z + sage: L = lie_algebras.Heisenberg(QQ, 1) # needs sage.combinat sage.modules + sage: Z = L.bracket(L, L); Z # needs sage.combinat sage.modules Ideal (z) of Heisenberg algebra of rank 1 over Rational Field - sage: L.bracket(L, Z) + sage: L.bracket(L, Z) # needs sage.combinat sage.modules Ideal () of Heisenberg algebra of rank 1 over Rational Field Constructing ideals:: - sage: p,q,z = L.basis(); (p,q,z) + sage: p, q, z = L.basis(); p, q, z # needs sage.combinat sage.modules (p1, q1, z) - sage: L.bracket(3*p, L) + sage: L.bracket(3*p, L) # needs sage.combinat sage.modules Ideal (3*p1) of Heisenberg algebra of rank 1 over Rational Field - sage: L.bracket(L, q+p) + sage: L.bracket(L, q + p) # needs sage.combinat sage.modules Ideal (p1 + q1) of Heisenberg algebra of rank 1 over Rational Field """ if lhs in LieAlgebras: @@ -297,15 +301,15 @@ def universal_enveloping_algebra(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.universal_enveloping_algebra() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: L.universal_enveloping_algebra() # needs sage.combinat sage.modules Noncommutative Multivariate Polynomial Ring in b0, b1, b2 over Rational Field, nc-relations: {} :: - sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) - sage: L.universal_enveloping_algebra() + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) # needs sage.combinat sage.modules + sage: L.universal_enveloping_algebra() # needs sage.combinat sage.modules Multivariate Polynomial Ring in x0, x1, x2 over Rational Field .. SEEALSO:: @@ -330,15 +334,15 @@ def _construct_UEA(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L._construct_UEA() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: L._construct_UEA() # needs sage.combinat sage.modules Noncommutative Multivariate Polynomial Ring in b0, b1, b2 over Rational Field, nc-relations: {} :: - sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) - sage: L.universal_enveloping_algebra() # indirect doctest + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) # needs sage.combinat sage.modules + sage: L.universal_enveloping_algebra() # indirect doctest # needs sage.combinat sage.modules Multivariate Polynomial Ring in x0, x1, x2 over Rational Field """ @@ -394,8 +398,8 @@ def module(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.module() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: L.module() # needs sage.modules Vector space of dimension 3 over Rational Field """ @@ -410,10 +414,10 @@ def from_vector(self, v, order=None, coerce=False): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u # needs sage.modules (1, 0, 0) - sage: parent(u) is L + sage: parent(u) is L # needs sage.modules True """ @@ -430,6 +434,7 @@ def lift(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() sage: lifted = L.lift(2*a + b - c); lifted @@ -447,9 +452,9 @@ def subalgebra(self, gens, names=None, index_set=None, category=None): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: a, b, c = L.lie_algebra_generators() - sage: L.subalgebra([2*a - c, b + c]) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: a, b, c = L.lie_algebra_generators() # needs sage.modules + sage: L.subalgebra([2*a - c, b + c]) # needs sage.modules An example of a finite dimensional Lie algebra with basis: the 2-dimensional abelian Lie algebra over Rational Field with basis matrix: @@ -458,9 +463,9 @@ def subalgebra(self, gens, names=None, index_set=None, category=None): :: - sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() - sage: L.subalgebra([x + y]) + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.modules + sage: x,y = L.lie_algebra_generators() # needs sage.combinat sage.modules + sage: L.subalgebra([x + y]) # needs sage.combinat sage.modules Traceback (most recent call last): ... NotImplementedError: subalgebras not yet implemented: see #17416 @@ -475,9 +480,9 @@ def ideal(self, *gens, **kwds): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: a, b, c = L.lie_algebra_generators() - sage: L.ideal([2*a - c, b + c]) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: a, b, c = L.lie_algebra_generators() # needs sage.modules + sage: L.ideal([2*a - c, b + c]) # needs sage.modules An example of a finite dimensional Lie algebra with basis: the 2-dimensional abelian Lie algebra over Rational Field with basis matrix: @@ -486,9 +491,9 @@ def ideal(self, *gens, **kwds): :: - sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() - sage: L.ideal([x + y]) + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.modules + sage: x, y = L.lie_algebra_generators() # needs sage.combinat sage.modules + sage: L.ideal([x + y]) # needs sage.combinat sage.modules Traceback (most recent call last): ... NotImplementedError: ideals not yet implemented: see #16824 @@ -508,8 +513,8 @@ def is_ideal(self, A): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: L.is_ideal(L) + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.modules + sage: L.is_ideal(L) # needs sage.combinat sage.modules True """ if A == self: @@ -525,9 +530,9 @@ def killing_form(self, x, y): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: a, b, c = L.lie_algebra_generators() - sage: L.killing_form(a, b+c) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: a, b, c = L.lie_algebra_generators() # needs sage.modules + sage: L.killing_form(a, b + c) # needs sage.modules 0 """ @@ -540,6 +545,7 @@ def is_abelian(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).example() sage: L.is_abelian() False @@ -550,11 +556,12 @@ def is_abelian(self): :: - sage: L.<x> = LieAlgebra(QQ,1) # todo: not implemented - #16823 - sage: L.is_abelian() # todo: not implemented - #16823 + sage: # not implemented, needs sage.combinat sage.modules + sage: L.<x> = LieAlgebra(QQ, 1) + sage: L.is_abelian() True - sage: L.<x,y> = LieAlgebra(QQ,2) # todo: not implemented - #16823 - sage: L.is_abelian() # todo: not implemented - #16823 + sage: L.<x,y> = LieAlgebra(QQ, 2) + sage: L.is_abelian() False """ G = self.lie_algebra_generators() @@ -570,14 +577,14 @@ def is_commutative(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: L.is_commutative() + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.modules + sage: L.is_commutative() # needs sage.combinat sage.modules False :: - sage: L.<x> = LieAlgebra(QQ, 1) # todo: not implemented - #16823 - sage: L.is_commutative() # todo: not implemented - #16823 + sage: L.<x> = LieAlgebra(QQ, 1) # not implemented # needs sage.combinat sage.modules + sage: L.is_commutative() # not implemented # needs sage.combinat sage.modules True """ return self.is_abelian() @@ -589,8 +596,8 @@ def is_solvable(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.is_solvable() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: L.is_solvable() # needs sage.modules True """ @@ -601,8 +608,8 @@ def is_nilpotent(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.is_nilpotent() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: L.is_nilpotent() # needs sage.modules True """ @@ -627,37 +634,40 @@ def bch(self, X, Y, prec=None): The BCH formula for the generators of a free nilpotent Lie algebra of step 4:: - sage: L = LieAlgebra(QQ, 2, step=4) - sage: L.inject_variables() + sage: L = LieAlgebra(QQ, 2, step=4) # needs sage.combinat sage.modules + sage: L.inject_variables() # needs sage.combinat sage.modules Defining X_1, X_2, X_12, X_112, X_122, X_1112, X_1122, X_1222 - sage: L.bch(X_1, X_2) + sage: L.bch(X_1, X_2) # needs sage.combinat sage.modules X_1 + X_2 + 1/2*X_12 + 1/12*X_112 + 1/12*X_122 + 1/24*X_1122 An example of the BCH formula in a quotient:: - sage: Q = L.quotient(X_112 + X_122) - sage: x, y = Q.basis().list()[:2] - sage: Q.bch(x, y) + sage: Q = L.quotient(X_112 + X_122) # needs sage.combinat sage.modules + sage: x, y = Q.basis().list()[:2] # needs sage.combinat sage.modules + sage: Q.bch(x, y) # needs sage.combinat sage.modules X_1 + X_2 + 1/2*X_12 - 1/24*X_1112 The BCH formula for a non-nilpotent Lie algebra requires the precision to be explicitly stated:: - sage: L.<X,Y> = LieAlgebra(QQ) - sage: L.bch(X, Y) + sage: L.<X,Y> = LieAlgebra(QQ) # needs sage.combinat sage.modules + sage: L.bch(X, Y) # needs sage.combinat sage.modules Traceback (most recent call last): ... - ValueError: the Lie algebra is not known to be nilpotent, so you must specify the precision - sage: L.bch(X, Y, 4) - X + 1/12*[X, [X, Y]] + 1/24*[X, [[X, Y], Y]] + 1/2*[X, Y] + 1/12*[[X, Y], Y] + Y + ValueError: the Lie algebra is not known to be nilpotent, + so you must specify the precision + sage: L.bch(X, Y, 4) # needs sage.combinat sage.modules + X + 1/12*[X, [X, Y]] + 1/24*[X, [[X, Y], Y]] + + 1/2*[X, Y] + 1/12*[[X, Y], Y] + Y The BCH formula requires a coercion from the rationals:: - sage: L.<X,Y,Z> = LieAlgebra(ZZ, 2, step=2) - sage: L.bch(X, Y) + sage: L.<X,Y,Z> = LieAlgebra(ZZ, 2, step=2) # needs sage.combinat sage.modules + sage: L.bch(X, Y) # needs sage.combinat sage.modules Traceback (most recent call last): ... - TypeError: the BCH formula is not well defined since Integer Ring has no coercion from Rational Field + TypeError: the BCH formula is not well defined + since Integer Ring has no coercion from Rational Field """ if self not in LieAlgebras.Nilpotent and prec is None: raise ValueError("the Lie algebra is not known to be nilpotent," @@ -682,8 +692,8 @@ def lie_group(self, name='G', **kwds): EXAMPLES:: - sage: L = lie_algebras.Heisenberg(QQ, 1) - sage: G = L.lie_group('G'); G # optional - sage.symbolic + sage: L = lie_algebras.Heisenberg(QQ, 1) # needs sage.combinat sage.modules + sage: G = L.lie_group('G'); G # needs sage.combinat sage.modules sage.symbolic Lie group G of Heisenberg algebra of rank 1 over Rational Field """ @@ -701,15 +711,15 @@ def _test_jacobi_identity(self, **options): By default, this method runs the tests only on the elements returned by ``self.some_elements()``:: - sage: L = LieAlgebras(QQ).example() - sage: L._test_jacobi_identity() + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.modules + sage: L._test_jacobi_identity() # needs sage.combinat sage.modules However, the elements tested can be customized with the ``elements`` keyword argument:: - sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() - sage: L._test_jacobi_identity(elements=[x+y, x, 2*y, x.bracket(y)]) + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.modules + sage: x,y = L.lie_algebra_generators() # needs sage.combinat sage.modules + sage: L._test_jacobi_identity(elements=[x + y, x, 2*y, x.bracket(y)]) # needs sage.combinat sage.modules See the documentation for :class:`TestSuite` for more information. """ @@ -740,15 +750,15 @@ def _test_antisymmetry(self, **options): By default, this method runs the tests only on the elements returned by ``self.some_elements()``:: - sage: L = LieAlgebras(QQ).example() - sage: L._test_antisymmetry() + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.modules + sage: L._test_antisymmetry() # needs sage.combinat sage.modules However, the elements tested can be customized with the ``elements`` keyword argument:: - sage: L = LieAlgebras(QQ).example() - sage: x,y = L.lie_algebra_generators() - sage: L._test_antisymmetry(elements=[x+y, x, 2*y, x.bracket(y)]) + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.modules + sage: x,y = L.lie_algebra_generators() # needs sage.combinat sage.modules + sage: L._test_antisymmetry(elements=[x + y, x, 2*y, x.bracket(y)]) # needs sage.combinat sage.modules See the documentation for :class:`TestSuite` for more information. """ @@ -769,27 +779,28 @@ def _test_distributivity(self, **options): TESTS:: - sage: L = LieAlgebras(QQ).example() - sage: L._test_distributivity() + sage: L = LieAlgebras(QQ).example() # needs sage.combinat sage.modules + sage: L._test_distributivity() # needs sage.combinat sage.modules EXAMPLES: By default, this method runs the tests only on the elements returned by ``self.some_elements()``:: - sage: L = LieAlgebra(QQ, 3, 'x,y,z', representation="polynomial") - sage: L.some_elements() + sage: L = LieAlgebra(QQ, 3, 'x,y,z', representation="polynomial") # needs sage.combinat sage.modules + sage: L.some_elements() # needs sage.combinat sage.modules [x + y + z] - sage: L._test_distributivity() + sage: L._test_distributivity() # needs sage.combinat sage.modules However, the elements tested can be customized with the ``elements`` keyword argument:: - sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) # todo: not implemented - #16821 - sage: h1 = L.gen(0) # todo: not implemented - #16821 - sage: h2 = L.gen(1) # todo: not implemented - #16821 - sage: e2 = L.gen(3) # todo: not implemented - #16821 - sage: L._test_distributivity(elements=[h1, h2, e2]) # todo: not implemented - #16821 + sage: # not implemented, needs sage.combinat sage.modules + sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) + sage: h1 = L.gen(0) + sage: h2 = L.gen(1) + sage: e2 = L.gen(3) + sage: L._test_distributivity(elements=[h1, h2, e2]) See the documentation for :class:`TestSuite` for more information. """ @@ -812,6 +823,7 @@ def bracket(self, rhs): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).example() sage: x,y = L.lie_algebra_generators() sage: x.bracket(y) @@ -831,6 +843,7 @@ def _bracket_(self, y): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).example() sage: x,y = L.lie_algebra_generators() sage: x._bracket_(y) @@ -853,10 +866,10 @@ def to_vector(self, order=None): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: u = L((1, 0, 0)).to_vector(); u + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: u = L((1, 0, 0)).to_vector(); u # needs sage.modules (1, 0, 0) - sage: parent(u) + sage: parent(u) # needs sage.modules Vector space of dimension 3 over Rational Field """ @@ -868,6 +881,7 @@ def lift(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() sage: elt = 3*a + b - c @@ -876,8 +890,8 @@ def lift(self): :: - sage: L.<x,y> = LieAlgebra(QQ, abelian=True) - sage: x.lift() + sage: L.<x,y> = LieAlgebra(QQ, abelian=True) # needs sage.combinat sage.modules + sage: x.lift() # needs sage.combinat sage.modules x """ @@ -887,9 +901,9 @@ def killing_form(self, x): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: a, b, c = L.lie_algebra_generators() - sage: a.killing_form(b) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: a, b, c = L.lie_algebra_generators() # needs sage.modules + sage: a.killing_form(b) # needs sage.modules 0 """ return self.parent().killing_form(self, x) @@ -906,24 +920,28 @@ def exp(self, lie_group=None): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L.<X,Y,Z> = LieAlgebra(QQ, 2, step=2) - sage: g = (X + Y + Z).exp(); g # optional - sage.symbolic + sage: g = (X + Y + Z).exp(); g # needs sage.symbolic exp(X + Y + Z) - sage: h = X.exp(); h # optional - sage.symbolic + sage: h = X.exp(); h # needs sage.symbolic exp(X) - sage: g.parent() # optional - sage.symbolic - Lie group G of Free Nilpotent Lie algebra on 3 generators (X, Y, Z) over Rational Field - sage: g.parent() is h.parent() # optional - sage.symbolic + sage: g.parent() # needs sage.symbolic + Lie group G of Free Nilpotent Lie algebra on 3 generators (X, Y, Z) + over Rational Field + sage: g.parent() is h.parent() # needs sage.symbolic True The Lie group can be specified explicitly:: - sage: H = L.lie_group('H') # optional - sage.symbolic - sage: k = Z.exp(lie_group=H); k # optional - sage.symbolic + sage: # needs sage.combinat sage.modules sage.symbolic + sage: H = L.lie_group('H') + sage: k = Z.exp(lie_group=H); k exp(Z) - sage: k.parent() # optional - sage.symbolic - Lie group H of Free Nilpotent Lie algebra on 3 generators (X, Y, Z) over Rational Field - sage: g.parent() == k.parent() # optional - sage.symbolic + sage: k.parent() + Lie group H of Free Nilpotent Lie algebra on 3 generators (X, Y, Z) + over Rational Field + sage: g.parent() == k.parent() False """ if lie_group is None: @@ -941,13 +959,13 @@ def __init__(self, domain, codomain): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: f = L.lift + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: f = L.lift # needs sage.combinat sage.modules We skip the category test since this is currently not an element of a homspace:: - sage: TestSuite(f).run(skip="_test_category") + sage: TestSuite(f).run(skip="_test_category") # needs sage.combinat sage.modules """ Morphism.__init__(self, Hom(domain, codomain)) @@ -957,9 +975,9 @@ def _call_(self, x): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: a, b, c = L.lie_algebra_generators() - sage: L.lift(3*a + b - c) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: a, b, c = L.lie_algebra_generators() # needs sage.modules + sage: L.lift(3*a + b - c) # needs sage.combinat sage.modules 3*b0 + b1 - b2 """ return x.lift() diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index 71916e3d6ad..6eaebfde844 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -34,13 +34,13 @@ def example(self, gens=None): EXAMPLES:: - sage: LieAlgebras(QQ).WithBasis().example() + sage: LieAlgebras(QQ).WithBasis().example() # needs sage.combinat sage.modules An example of a Lie algebra: the abelian Lie algebra on the generators indexed by Partitions over Rational Field Another set of generators can be specified as an optional argument:: - sage: LieAlgebras(QQ).WithBasis().example(Compositions()) + sage: LieAlgebras(QQ).WithBasis().example(Compositions()) # needs sage.combinat sage.modules An example of a Lie algebra: the abelian Lie algebra on the generators indexed by Compositions of non-negative integers over Rational Field @@ -64,8 +64,8 @@ def _basis_key(self, x): TESTS:: - sage: L = LieAlgebras(QQ).WithBasis().example() - sage: L._basis_key(Partition([3,1])) + sage: L = LieAlgebras(QQ).WithBasis().example() # needs sage.combinat sage.modules + sage: L._basis_key(Partition([3,1])) # needs sage.combinat sage.modules [3, 1] """ return x @@ -79,8 +79,8 @@ def bracket_on_basis(self, x, y): EXAMPLES:: - sage: L = LieAlgebras(QQ).WithBasis().example() - sage: L.bracket_on_basis(Partition([3,1]), Partition([2,2,1,1])) + sage: L = LieAlgebras(QQ).WithBasis().example() # needs sage.combinat sage.modules + sage: L.bracket_on_basis(Partition([3,1]), Partition([2,2,1,1])) # needs sage.combinat sage.modules 0 """ @@ -95,8 +95,8 @@ def module(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).WithBasis().example() - sage: L.module() + sage: L = LieAlgebras(QQ).WithBasis().example() # needs sage.combinat sage.modules + sage: L.module() # needs sage.combinat sage.modules Free module generated by Partitions over Rational Field """ from sage.combinat.free_module import CombinatorialFreeModule @@ -119,10 +119,10 @@ def from_vector(self, v, order=None, coerce=False): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u # needs sage.modules (1, 0, 0) - sage: parent(u) is L + sage: parent(u) is L # needs sage.modules True """ B = self.basis() @@ -135,14 +135,14 @@ def dimension(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.dimension() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: L.dimension() # needs sage.modules 3 :: - sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) - sage: L.dimension() + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) # needs sage.combinat sage.modules + sage: L.dimension() # needs sage.combinat sage.modules 2 """ return self.basis().cardinality() @@ -154,8 +154,8 @@ def pbw_basis(self, basis_key=None, **kwds): EXAMPLES:: - sage: L = lie_algebras.sl(QQ, 2) - sage: PBW = L.pbw_basis() + sage: L = lie_algebras.sl(QQ, 2) # needs sage.combinat sage.modules + sage: PBW = L.pbw_basis() # needs sage.combinat sage.modules """ from sage.algebras.lie_algebras.poincare_birkhoff_witt \ import PoincareBirkhoffWittBasis @@ -173,6 +173,7 @@ def _bracket_(self, y): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebras(QQ).WithBasis().example() sage: G = L.lie_algebra_generators() sage: x = G[Partition([4,3,3,1])] @@ -206,8 +207,8 @@ def to_vector(self, order=None): EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.an_element().to_vector() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() # needs sage.modules + sage: L.an_element().to_vector() # needs sage.modules (0, 0, 0) .. TODO:: @@ -224,6 +225,7 @@ def lift(self): EXAMPLES:: + sage: # needs sage.groups sage: S = SymmetricGroup(3).algebra(QQ) sage: L = LieAlgebra(associative=S) sage: x = L.gen(3) diff --git a/src/sage/categories/lie_conformal_algebras.py b/src/sage/categories/lie_conformal_algebras.py index 54e3956c283..ee48889dd0b 100644 --- a/src/sage/categories/lie_conformal_algebras.py +++ b/src/sage/categories/lie_conformal_algebras.py @@ -152,15 +152,16 @@ class LieConformalAlgebras(Category_over_base_ring): Some subcategories:: - sage: LieConformalAlgebras(QQbar).FinitelyGenerated().WithBasis() - Category of finitely generated Lie conformal algebras with basis over Algebraic Field + sage: LieConformalAlgebras(QQbar).FinitelyGenerated().WithBasis() # needs sage.rings.number_field + Category of finitely generated Lie conformal algebras with basis + over Algebraic Field In addition we support functorial constructions ``Graded`` and ``Super``. These functors commute:: - sage: LieConformalAlgebras(AA).Graded().Super() + sage: CGS = LieConformalAlgebras(AA).Graded().Super(); CGS # needs sage.rings.number_field Category of H-graded super Lie conformal algebras over Algebraic Real Field - sage: LieConformalAlgebras(AA).Graded().Super() is LieConformalAlgebras(AA).Super().Graded() + sage: CGS is LieConformalAlgebras(AA).Super().Graded() # needs sage.rings.number_field True That is, we only consider gradings on super Lie conformal algebras @@ -168,9 +169,10 @@ class LieConformalAlgebras(Category_over_base_ring): The base ring needs to be a commutative ring:: - sage: LieConformalAlgebras(QuaternionAlgebra(2)) + sage: LieConformalAlgebras(QuaternionAlgebra(2)) # needs sage.combinat sage.modules Traceback (most recent call last): - ValueError: base must be a commutative ring got Quaternion Algebra (-1, -1) with base ring Rational Field + ValueError: base must be a commutative ring + got Quaternion Algebra (-1, -1) with base ring Rational Field """ @cached_method def super_categories(self): @@ -219,7 +221,7 @@ def example(self): EXAMPLES:: - sage: LieConformalAlgebras(QQ).example() + sage: LieConformalAlgebras(QQ).example() # needs sage.combinat sage.modules The Virasoro Lie conformal algebra over Rational Field """ from sage.algebras.lie_conformal_algebras.virasoro_lie_conformal_algebra\ @@ -252,27 +254,28 @@ def _test_jacobi(self, **options): By default, this method tests only the elements returned by ``self.some_elements()``:: - sage: V = lie_conformal_algebras.Affine(QQ, 'B2') - sage: V._test_jacobi() # long time (6 seconds) + sage: V = lie_conformal_algebras.Affine(QQ, 'B2') # needs sage.combinat sage.modules + sage: V._test_jacobi() # long time (6 seconds) # needs sage.combinat sage.modules It works for super Lie conformal algebras too:: - sage: V = lie_conformal_algebras.NeveuSchwarz(QQ) - sage: V._test_jacobi() + sage: V = lie_conformal_algebras.NeveuSchwarz(QQ) # needs sage.combinat sage.modules + sage: V._test_jacobi() # needs sage.combinat sage.modules We can use specific elements by passing the ``elements`` keyword argument:: - sage: V = lie_conformal_algebras.Affine(QQ, 'A1', names=('e', 'h', 'f')) - sage: V.inject_variables() + sage: V = lie_conformal_algebras.Affine(QQ, 'A1', # needs sage.combinat sage.modules + ....: names=('e', 'h', 'f')) + sage: V.inject_variables() # needs sage.combinat sage.modules Defining e, h, f, K - sage: V._test_jacobi(elements=(e, 2*f+h, 3*h)) + sage: V._test_jacobi(elements=(e, 2*f+h, 3*h)) # needs sage.combinat sage.modules TESTS:: sage: wrongdict = {('a', 'a'): {0: {('b', 0): 1}}, ('b', 'a'): {0: {('a', 0): 1}}} - sage: V = LieConformalAlgebra(QQ, wrongdict, names=('a', 'b'), parity=(1, 0)) - sage: V._test_jacobi() + sage: V = LieConformalAlgebra(QQ, wrongdict, names=('a', 'b'), parity=(1, 0)) # needs sage.combinat sage.modules + sage: V._test_jacobi() # needs sage.combinat sage.modules Traceback (most recent call last): ... AssertionError: {(0, 0): -3*a} != {} @@ -323,10 +326,10 @@ def is_even_odd(self): EXAMPLES:: - sage: R = lie_conformal_algebras.NeveuSchwarz(QQ); - sage: R.inject_variables() + sage: R = lie_conformal_algebras.NeveuSchwarz(QQ) # needs sage.combinat sage.modules + sage: R.inject_variables() # needs sage.combinat sage.modules Defining L, G, C - sage: G.is_even_odd() + sage: G.is_even_odd() # needs sage.combinat sage.modules 1 """ return 0 diff --git a/src/sage/categories/lie_conformal_algebras_with_basis.py b/src/sage/categories/lie_conformal_algebras_with_basis.py index 50f67d2a970..bedf8934fc4 100644 --- a/src/sage/categories/lie_conformal_algebras_with_basis.py +++ b/src/sage/categories/lie_conformal_algebras_with_basis.py @@ -27,7 +27,7 @@ class LieConformalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).WithBasis() + sage: LieConformalAlgebras(QQbar).WithBasis() # needs sage.rings.number_field Category of Lie conformal algebras with basis over Algebraic Field """ class Super(SuperModulesCategory): @@ -36,8 +36,9 @@ class Super(SuperModulesCategory): EXAMPLES:: - sage: LieConformalAlgebras(AA).WithBasis().Super() - Category of super Lie conformal algebras with basis over Algebraic Real Field + sage: LieConformalAlgebras(AA).WithBasis().Super() # needs sage.rings.number_field + Category of super Lie conformal algebras with basis + over Algebraic Real Field """ class ParentMethods: @@ -52,9 +53,9 @@ def _even_odd_on_basis(self, m): EXAMPLES:: - sage: V = lie_conformal_algebras.NeveuSchwarz(QQ) - sage: B = V._indices - sage: V._even_odd_on_basis(B(('G',1))) + sage: V = lie_conformal_algebras.NeveuSchwarz(QQ) # needs sage.combinat sage.modules + sage: B = V._indices # needs sage.combinat sage.modules + sage: V._even_odd_on_basis(B(('G', 1))) # needs sage.combinat sage.modules 1 """ return self._parity[self.monomial((m[0],0))] @@ -65,8 +66,9 @@ class Graded(GradedLieConformalAlgebrasCategory): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).WithBasis().Super().Graded() - Category of H-graded super Lie conformal algebras with basis over Algebraic Field + sage: LieConformalAlgebras(QQbar).WithBasis().Super().Graded() # needs sage.rings.number_field + Category of H-graded super Lie conformal algebras with basis + over Algebraic Field """ class Graded(GradedLieConformalAlgebrasCategory): @@ -75,7 +77,7 @@ class Graded(GradedLieConformalAlgebrasCategory): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).WithBasis().Graded() + sage: LieConformalAlgebras(QQbar).WithBasis().Graded() # needs sage.rings.number_field Category of H-graded Lie conformal algebras with basis over Algebraic Field """ @@ -86,10 +88,11 @@ class FinitelyGeneratedAsLambdaBracketAlgebra(CategoryWithAxiom_over_base_ring): EXAMPLES:: - sage: C = LieConformalAlgebras(QQbar) - sage: C.WithBasis().FinitelyGenerated() - Category of finitely generated Lie conformal algebras with basis over Algebraic Field - sage: C.WithBasis().FinitelyGenerated() is C.FinitelyGenerated().WithBasis() + sage: C = LieConformalAlgebras(QQbar) # needs sage.rings.number_field + sage: CWF = C.WithBasis().FinitelyGenerated(); CWF # needs sage.rings.number_field + Category of finitely generated Lie conformal algebras with basis + over Algebraic Field + sage: CWF is C.FinitelyGenerated().WithBasis() # needs sage.rings.number_field True """ class Super(SuperModulesCategory): @@ -99,8 +102,9 @@ class Super(SuperModulesCategory): EXAMPLES:: - sage: LieConformalAlgebras(AA).WithBasis().FinitelyGenerated().Super() - Category of super finitely generated Lie conformal algebras with basis over Algebraic Real Field + sage: LieConformalAlgebras(AA).WithBasis().FinitelyGenerated().Super() # needs sage.rings.number_field + Category of super finitely generated Lie conformal algebras with basis + over Algebraic Real Field """ class Graded(GradedModulesCategory): """ @@ -109,10 +113,11 @@ class Graded(GradedModulesCategory): EXAMPLES:: - sage: C = LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated() - sage: C.Graded().Super() - Category of H-graded super finitely generated Lie conformal algebras with basis over Algebraic Field - sage: C.Graded().Super() is C.Super().Graded() + sage: C = LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated() # needs sage.rings.number_field + sage: C.Graded().Super() # needs sage.rings.number_field + Category of H-graded super finitely generated Lie conformal algebras + with basis over Algebraic Field + sage: C.Graded().Super() is C.Super().Graded() # needs sage.rings.number_field True """ def _repr_object_names(self): @@ -121,8 +126,8 @@ def _repr_object_names(self): EXAMPLES:: - sage: C = LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated() - sage: C.Super().Graded() + sage: C = LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated() # needs sage.rings.number_field + sage: C.Super().Graded() # needs sage.rings.number_field Category of H-graded super finitely generated Lie conformal algebras with basis over Algebraic Field """ return "H-graded {}".format(self.base_category()._repr_object_names()) @@ -134,6 +139,7 @@ class Graded(GradedLieConformalAlgebrasCategory): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated().Graded() - Category of H-graded finitely generated Lie conformal algebras with basis over Algebraic Field + sage: LieConformalAlgebras(QQbar).WithBasis().FinitelyGenerated().Graded() # needs sage.rings.number_field + Category of H-graded finitely generated Lie conformal algebras with basis + over Algebraic Field """ diff --git a/src/sage/categories/loop_crystals.py b/src/sage/categories/loop_crystals.py index e065b7ef4f6..ad49bd42892 100644 --- a/src/sage/categories/loop_crystals.py +++ b/src/sage/categories/loop_crystals.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs sage.combinat r""" Loop Crystals """ @@ -19,8 +20,7 @@ from sage.categories.regular_crystals import RegularCrystals from sage.categories.tensor import TensorProductsCategory from sage.categories.map import Map -from sage.graphs.dot2tex_utils import have_dot2tex -from sage.functions.other import ceil + class LoopCrystals(Category_singleton): r""" @@ -117,6 +117,8 @@ def digraph(self, subset=None, index_set=None): {...'edge_options': <function ... at ...>...} sage: view(G, tightpage=True) # optional - dot2tex graphviz, not tested (opens external window) """ + from sage.graphs.dot2tex_utils import have_dot2tex + G = Crystals().parent_class.digraph(self, subset, index_set) if have_dot2tex(): def eopt(u_v_label): @@ -389,11 +391,17 @@ def R_matrix(self, K): sage: K2 = crystals.KirillovReshetikhin(['A',2,1],2,1) sage: T1 = crystals.TensorProduct(K1,K2) sage: T2 = crystals.TensorProduct(K2,K1) - sage: T1.digraph().is_isomorphic(T2.digraph(), edge_labels=True, certificate=True) #todo: not implemented (see #10904 and #10549) - (True, {[[[1]], [[2], [3]]]: [[[1], [3]], [[2]]], [[[3]], [[2], [3]]]: [[[2], [3]], [[3]]], - [[[3]], [[1], [3]]]: [[[1], [3]], [[3]]], [[[1]], [[1], [3]]]: [[[1], [3]], [[1]]], [[[1]], - [[1], [2]]]: [[[1], [2]], [[1]]], [[[2]], [[1], [2]]]: [[[1], [2]], [[2]]], [[[3]], - [[1], [2]]]: [[[2], [3]], [[1]]], [[[2]], [[1], [3]]]: [[[1], [2]], [[3]]], [[[2]], [[2], [3]]]: [[[2], [3]], [[2]]]}) + sage: T1.digraph().is_isomorphic(T2.digraph(), edge_labels=True, # todo: not implemented (see #10904 and #10549) + ....: certificate=True) + (True, {[[[1]], [[2], [3]]]: [[[1], [3]], [[2]]], + [[[3]], [[2], [3]]]: [[[2], [3]], [[3]]], + [[[3]], [[1], [3]]]: [[[1], [3]], [[3]]], + [[[1]], [[1], [3]]]: [[[1], [3]], [[1]]], [[[1]], + [[1], [2]]]: [[[1], [2]], [[1]]], + [[[2]], [[1], [2]]]: [[[1], [2]], [[2]]], [[[3]], + [[1], [2]]]: [[[2], [3]], [[1]]], + [[[2]], [[1], [3]]]: [[[1], [2]], [[3]]], + [[[2]], [[2], [3]]]: [[[2], [3]], [[2]]]}) """ from sage.combinat.crystals.tensor_product import TensorProductOfCrystals T1 = TensorProductOfCrystals(self, K) @@ -513,7 +521,7 @@ def is_perfect(self, ell=None): sage: K.is_perfect() True - sage: K = crystals.KirillovReshetikhin(['E',6,1], 1,3) + sage: K = crystals.KirillovReshetikhin(['E',6,1], 1, 3) sage: K.is_perfect() True @@ -522,7 +530,7 @@ def is_perfect(self, ell=None): Check that this works correctly for `B^{n,s}` of type `A_{2n}^{(2)\dagger}` (:trac:`24364`):: - sage: K = crystals.KirillovReshetikhin(CartanType(['A',6,2]).dual(), 3,1) + sage: K = crystals.KirillovReshetikhin(CartanType(['A',6,2]).dual(), 3, 1) sage: K.is_perfect() True sage: K.is_perfect(1) @@ -834,7 +842,8 @@ def one_dimensional_configuration_sum(self, q=None, group_components=True): sage: R = RootSystem(['A',2,1]) sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]) - sage: LS.one_dimensional_configuration_sum() == T.one_dimensional_configuration_sum() # long time + sage: (LS.one_dimensional_configuration_sum() # long time + ....: == T.one_dimensional_configuration_sum()) True TESTS:: @@ -859,7 +868,7 @@ def one_dimensional_configuration_sum(self, q=None, group_components=True): B = P0.algebra(q.parent()) if group_components: G = self.digraph(index_set=self.cartan_type().classical().index_set()) - C = G.connected_components() + C = G.connected_components(sort=False) return B.sum(q**(c[0].energy_function())*B.sum(B(P0(b.weight())) for b in c) for c in C) return B.sum(q**(b.energy_function())*B(P0(b.weight())) for b in self) @@ -959,6 +968,8 @@ def energy_function(self, algorithm=None): ....: for b in hw) True """ + from sage.arith.misc import integer_ceil as ceil + C = self.parent().crystals[0] ell = ceil(C.s()/C.cartan_type().c()[C.r()]) is_perfect = all(ell == K.s()/K.cartan_type().c()[K.r()] @@ -1090,6 +1101,8 @@ def e_string_to_ground_state(self): ....: for elt in hw) True """ + from sage.arith.misc import integer_ceil as ceil + ell = max(ceil(K.s()/K.cartan_type().c()[K.r()]) for K in self.parent().crystals) if self.cartan_type().dual().type() == 'BC': diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index ff1a7f955c5..603e68ad186 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -296,11 +296,13 @@ def Distributive(self): sage: Magmas().Distributive() Traceback (most recent call last): ... - ValueError: The distributive axiom only makes sense on a magma which is simultaneously an additive magma + ValueError: The distributive axiom only makes sense on a magma + which is simultaneously an additive magma sage: Semigroups().Distributive() Traceback (most recent call last): ... - ValueError: The distributive axiom only makes sense on a magma which is simultaneously an additive magma + ValueError: The distributive axiom only makes sense on a magma + which is simultaneously an additive magma TESTS:: @@ -331,7 +333,8 @@ def JTrivial(self): sage: Magmas().JTrivial() Category of j trivial magmas - sage: (Semigroups().RTrivial() & Semigroups().LTrivial()) is Semigroups().JTrivial() + sage: C = Semigroups().RTrivial() & Semigroups().LTrivial() + sage: C is Semigroups().JTrivial() True """ return self._with_axiom('JTrivial') @@ -349,19 +352,22 @@ def extra_super_categories(self): """ EXAMPLES:: - sage: Magmas().Commutative().Algebras(QQ).extra_super_categories() + sage: MCA = Magmas().Commutative().Algebras(QQ) + sage: MCA.extra_super_categories() [Category of commutative magmas] This implements the fact that the algebra of a commutative magma is commutative:: - sage: Magmas().Commutative().Algebras(QQ).super_categories() - [Category of magma algebras over Rational Field, Category of commutative magmas] + sage: MCA.super_categories() + [Category of magma algebras over Rational Field, + Category of commutative magmas] In particular, commutative monoid algebras are commutative algebras:: - sage: Monoids().Commutative().Algebras(QQ).is_subcategory(Algebras(QQ).Commutative()) + sage: MoCA = Monoids().Commutative().Algebras(QQ) + sage: MoCA.is_subcategory(Algebras(QQ).Commutative()) True """ from sage.categories.magmatic_algebras import MagmaticAlgebras @@ -377,11 +383,11 @@ def is_field(self, proof=True): EXAMPLES:: - sage: SymmetricGroup(1).algebra(QQ).is_field() + sage: SymmetricGroup(1).algebra(QQ).is_field() # needs sage.groups True - sage: SymmetricGroup(1).algebra(ZZ).is_field() + sage: SymmetricGroup(1).algebra(ZZ).is_field() # needs sage.groups False - sage: SymmetricGroup(2).algebra(QQ).is_field() + sage: SymmetricGroup(2).algebra(QQ).is_field() # needs sage.groups False """ if not self.base_ring().is_field(proof): @@ -397,7 +403,7 @@ def is_commutative(self): EXAMPLES:: - sage: Parent(QQ,category=CommutativeRings()).is_commutative() + sage: Parent(QQ, category=CommutativeRings()).is_commutative() True """ return True @@ -408,20 +414,22 @@ def extra_super_categories(self): """ EXAMPLES:: - sage: Magmas().Commutative().Algebras(QQ).extra_super_categories() + sage: MCA = Magmas().Commutative().Algebras(QQ) + sage: MCA.extra_super_categories() [Category of commutative magmas] This implements the fact that the algebra of a commutative magma is commutative:: - sage: Magmas().Commutative().Algebras(QQ).super_categories() + sage: MCA.super_categories() [Category of magma algebras over Rational Field, Category of commutative magmas] In particular, commutative monoid algebras are commutative algebras:: - sage: Monoids().Commutative().Algebras(QQ).is_subcategory(Algebras(QQ).Commutative()) + sage: MoCA = Monoids().Commutative().Algebras(QQ) + sage: MoCA.is_subcategory(Algebras(QQ).Commutative()) True """ return [Magmas().Commutative()] @@ -480,7 +488,8 @@ def one(self): EXAMPLES:: sage: M = Monoids().example(); M - An example of a monoid: the free monoid generated by ('a', 'b', 'c', 'd') + An example of a monoid: + the free monoid generated by ('a', 'b', 'c', 'd') sage: M.one() '' """ @@ -531,8 +540,8 @@ def is_empty(self): EXAMPLES:: - sage: S = SymmetricGroup(2) - sage: S.is_empty() + sage: S = SymmetricGroup(2) # needs sage.groups + sage: S.is_empty() # needs sage.groups False sage: M = Monoids().example() @@ -541,7 +550,7 @@ def is_empty(self): TESTS:: - sage: S.is_empty.__module__ + sage: S.is_empty.__module__ # needs sage.groups 'sage.categories.magmas' sage: M.is_empty.__module__ 'sage.categories.magmas' @@ -629,7 +638,7 @@ def one(self): EXAMPLES:: - sage: cartesian_product([QQ, ZZ, RR]).one() + sage: cartesian_product([QQ, ZZ, RR]).one() # needs sage.rings.real_mpfr (1, 1, 1.00000000000000) """ return self._cartesian_product_of_elements( @@ -657,9 +666,9 @@ def __invert__(self): EXAMPLES:: sage: C = cartesian_product([QQ, ZZ, RR, GF(5)]) - sage: c = C([2,-1,2,2]); c + sage: c = C([2,-1,2,2]); c # needs sage.rings.real_mpfr (2, -1, 2.00000000000000, 2) - sage: ~c + sage: ~c # needs sage.rings.real_mpfr (1/2, -1, 0.500000000000000, 3) This fails as soon as one of the entries is not @@ -670,7 +679,7 @@ def __invert__(self): ... ZeroDivisionError: rational division by zero - sage: ~C([2,2,2,2]) + sage: ~C([2,2,2,2]) # needs sage.rings.real_mpfr (1/2, 1/2, 0.500000000000000, 3) """ # variant without coercion: @@ -684,20 +693,22 @@ def extra_super_categories(self): """ EXAMPLES:: - sage: Magmas().Commutative().Algebras(QQ).extra_super_categories() + sage: MCA = Magmas().Commutative().Algebras(QQ) + sage: MCA.extra_super_categories() [Category of commutative magmas] This implements the fact that the algebra of a commutative magma is commutative:: - sage: Magmas().Commutative().Algebras(QQ).super_categories() + sage: MCA.super_categories() [Category of magma algebras over Rational Field, Category of commutative magmas] In particular, commutative monoid algebras are commutative algebras:: - sage: Monoids().Commutative().Algebras(QQ).is_subcategory(Algebras(QQ).Commutative()) + sage: MoCA = Monoids().Commutative().Algebras(QQ) + sage: MoCA.is_subcategory(Algebras(QQ).Commutative()) True """ return [Magmas().Unital()] @@ -711,6 +722,9 @@ def one(self): r""" Return the unit element of ``self``. + EXAMPLES:: + + sage: # needs sage.combinat sage.groups sage: from sage.combinat.root_system.extended_affine_weyl_group import ExtendedAffineWeylGroup sage: PvW0 = ExtendedAffineWeylGroup(['A',2,1]).PvW0() sage: PvW0 in Magmas().Unital().Realizations() @@ -756,7 +770,8 @@ def product(self, x, y): Currently, ``S.product`` is just a bound method:: sage: bin - <bound method FreeSemigroup.product of An example of a semigroup: the free semigroup generated by ('a', 'b', 'c', 'd')> + <bound method FreeSemigroup.product of An example of a semigroup: + the free semigroup generated by ('a', 'b', 'c', 'd')> When Sage will support multivariate morphisms, it will be possible, and in fact recommended, to enrich ``S.product`` @@ -870,8 +885,8 @@ def multiplication_table(self, names='letters', elements=None): The default is to represent elements as lowercase ASCII letters. :: - sage: G = CyclicPermutationGroup(5) - sage: G.multiplication_table() + sage: G = CyclicPermutationGroup(5) # needs sage.groups + sage: G.multiplication_table() # needs sage.groups * a b c d e +---------- a| a b c d e @@ -888,10 +903,10 @@ def multiplication_table(self, names='letters', elements=None): sage: from sage.categories.examples.finite_semigroups import LeftRegularBand sage: L = LeftRegularBand(('a', 'b')) - sage: T = L.multiplication_table(names='digits') - sage: T.column_keys() + sage: T = L.multiplication_table(names='digits') # needs sage.modules + sage: T.column_keys() # needs sage.modules ('a', 'ab', 'b', 'ba') - sage: T + sage: T # needs sage.modules * 0 1 2 3 +-------- 0| 0 1 1 1 @@ -904,7 +919,7 @@ def multiplication_table(self, names='letters', elements=None): sage: L = LeftRegularBand(('a', 'b', 'c')) sage: elts = sorted(L.list()) - sage: L.multiplication_table(elements=elts) + sage: L.multiplication_table(elements=elts) # needs sage.modules * a b c d e f g h i j k l m n o +------------------------------ a| a b c d e b b c c c d d e e e @@ -933,7 +948,7 @@ def multiplication_table(self, names='letters', elements=None): sage: L = LeftRegularBand(('a','b','c')) sage: elts=['a', 'c', 'ac', 'ca'] - sage: L.multiplication_table(names='elements', elements=elts) + sage: L.multiplication_table(names='elements', elements=elts) # needs sage.modules * 'a' 'c' 'ac' 'ca' +-------------------- 'a'| 'a' 'ac' 'ac' 'ac' @@ -946,6 +961,7 @@ def multiplication_table(self, names='letters', elements=None): :class:`~sage.matrix.operation_table.OperationTable` for more comprehensive documentation. :: + sage: # needs sage.groups sage.modules sage: G = AlternatingGroup(3) sage: T = G.multiplication_table() sage: T.column_keys() @@ -997,7 +1013,8 @@ def is_idempotent(self): EXAMPLES:: sage: S = Semigroups().example("free"); S - An example of a semigroup: the free semigroup generated by ('a', 'b', 'c', 'd') + An example of a semigroup: + the free semigroup generated by ('a', 'b', 'c', 'd') sage: a = S('a') sage: a^2 'aa' @@ -1069,6 +1086,7 @@ def product(self, left, right): sage: x * x (1/4, 1, 1) + sage: # needs sage.groups sage.modules sage: A = SymmetricGroupAlgebra(QQ, 3) sage: x = cartesian_product([A([1,3,2]), A([2,3,1])]) sage: y = cartesian_product([A([1,3,2]), A([2,3,1])]) @@ -1123,9 +1141,9 @@ def product(self, x, y): Here is a more elaborate example involving a sub algebra:: - sage: Z = SymmetricGroup(5).algebra(QQ).center() - sage: B = Z.basis() - sage: B[3] * B[2] + sage: Z = SymmetricGroup(5).algebra(QQ).center() # needs sage.groups + sage: B = Z.basis() # needs sage.groups + sage: B[3] * B[2] # needs sage.groups 4*B[2] + 6*B[3] + 5*B[6] """ assert x in self @@ -1147,10 +1165,14 @@ def product_by_coercion(self, left, right): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: Out = Sets().WithRealizations().example().Out(); Out - The subset algebra of {1, 2, 3} over Rational Field in the Out basis + The subset algebra of {1, 2, 3} over Rational Field + in the Out basis sage: Out.product - <bound method Magmas.Realizations.ParentMethods.product_by_coercion of The subset algebra of {1, 2, 3} over Rational Field in the Out basis> + <bound method Magmas.Realizations.ParentMethods.product_by_coercion + of The subset algebra of {1, 2, 3} over Rational Field + in the Out basis> sage: Out.product.__module__ 'sage.categories.magmas' sage: x = Out.an_element() diff --git a/src/sage/categories/magmatic_algebras.py b/src/sage/categories/magmatic_algebras.py index ef82ba4319b..9d37608569d 100644 --- a/src/sage/categories/magmatic_algebras.py +++ b/src/sage/categories/magmatic_algebras.py @@ -40,7 +40,8 @@ class MagmaticAlgebras(Category_over_base_ring): sage: C = MagmaticAlgebras(ZZ); C Category of magmatic algebras over Integer Ring sage: C.super_categories() - [Category of additive commutative additive associative additive unital distributive magmas and additive magmas, + [Category of additive commutative additive associative additive + unital distributive magmas and additive magmas, Category of modules over Integer Ring] TESTS:: @@ -54,11 +55,14 @@ def super_categories(self): EXAMPLES:: sage: from sage.categories.magmatic_algebras import MagmaticAlgebras - sage: MagmaticAlgebras(ZZ).super_categories() - [Category of additive commutative additive associative additive unital distributive magmas and additive magmas, Category of modules over Integer Ring] + sage: MA = MagmaticAlgebras(ZZ) + sage: MA.super_categories() + [Category of additive commutative additive associative additive + unital distributive magmas and additive magmas, + Category of modules over Integer Ring] sage: from sage.categories.additive_semigroups import AdditiveSemigroups - sage: MagmaticAlgebras(ZZ).is_subcategory((AdditiveSemigroups() & Magmas()).Distributive()) + sage: MA.is_subcategory((AdditiveSemigroups() & Magmas()).Distributive()) True """ @@ -106,9 +110,10 @@ def algebra_generators(self): EXAMPLES:: - sage: F = AlgebrasWithBasis(QQ).example(); F - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field - sage: F.algebra_generators() + sage: F = AlgebrasWithBasis(QQ).example(); F # needs sage.combinat sage.modules + An example of an algebra with basis: + the free algebra on the generators ('a', 'b', 'c') over Rational Field + sage: F.algebra_generators() # needs sage.combinat sage.modules Family (B[word: a], B[word: b], B[word: c]) """ @@ -131,16 +136,18 @@ def algebra_generators(self): EXAMPLES:: - sage: D4 = DescentAlgebra(QQ, 4).B() - sage: D4.algebra_generators() + sage: D4 = DescentAlgebra(QQ, 4).B() # needs sage.combinat sage.modules + sage: D4.algebra_generators() # needs sage.combinat sage.modules Lazy family (...)_{i in Compositions of 4} sage: R.<x> = ZZ[] - sage: P = PartitionAlgebra(1, x, R) - sage: P.algebra_generators() - Lazy family (Term map from Partition diagrams of order 1 to - Partition Algebra of rank 1 with parameter x over Univariate Polynomial Ring in x - over Integer Ring(i))_{i in Partition diagrams of order 1} + sage: P = PartitionAlgebra(1, x, R) # needs sage.combinat sage.modules + sage: P.algebra_generators() # needs sage.combinat sage.modules + Lazy family (Term map + from Partition diagrams of order 1 + to Partition Algebra of rank 1 with parameter x + over Univariate Polynomial Ring in x + over Integer Ring(i))_{i in Partition diagrams of order 1} """ return self.basis() @@ -162,9 +169,9 @@ def product_on_basis(self, i, j): EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).example() - sage: Word = A.basis().keys() - sage: A.product_on_basis(Word("abc"),Word("cba")) + sage: A = AlgebrasWithBasis(QQ).example() # needs sage.combinat sage.modules + sage: Word = A.basis().keys() # needs sage.combinat sage.modules + sage: A.product_on_basis(Word("abc"), Word("cba")) # needs sage.combinat sage.modules B[word: abccba] """ @@ -183,9 +190,9 @@ def product(self): EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).example() - sage: a, b, c = A.algebra_generators() - sage: A.product(a + 2*b, 3*c) + sage: A = AlgebrasWithBasis(QQ).example() # needs sage.combinat sage.modules + sage: a, b, c = A.algebra_generators() # needs sage.combinat sage.modules + sage: A.product(a + 2*b, 3*c) # needs sage.combinat sage.modules 3*B[word: ac] + 6*B[word: bc] """ if self.product_on_basis is not NotImplemented: @@ -205,10 +212,11 @@ def _product_from_product_on_basis_multiply( self, left, right ): EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).example(); A - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field - sage: (a,b,c) = A.algebra_generators() - sage: A._product_from_product_on_basis_multiply(a*b + 2*c, a - b) + sage: A = AlgebrasWithBasis(QQ).example(); A # needs sage.combinat sage.modules + An example of an algebra with basis: + the free algebra on the generators ('a', 'b', 'c') over Rational Field + sage: a, b, c = A.algebra_generators() # needs sage.combinat sage.modules + sage: A._product_from_product_on_basis_multiply(a*b + 2*c, a - b) # needs sage.combinat sage.modules B[word: aba] - B[word: abb] + 2*B[word: ca] - 2*B[word: cb] """ @@ -239,15 +247,16 @@ def derivations_basis(self): We construct the Heisenberg Lie algebra as a multiplicative algebra:: - sage: p_mult = matrix([[0,0,0],[0,0,-1],[0,0,0]]) - sage: q_mult = matrix([[0,0,1],[0,0,0],[0,0,0]]) + sage: # needs sage.combinat sage.modules + sage: p_mult = matrix([[0,0,0], [0,0,-1], [0,0,0]]) + sage: q_mult = matrix([[0,0,1], [0,0,0], [0,0,0]]) sage: A = algebras.FiniteDimensional(QQ, - ....: [p_mult,q_mult,matrix(QQ,3,3)], 'p,q,z') + ....: [p_mult, q_mult, matrix(QQ, 3, 3)], 'p,q,z') sage: A.inject_variables() Defining p, q, z - sage: p*q + sage: p * q z - sage: q*p + sage: q * p -z sage: A.derivations_basis() ( @@ -259,13 +268,15 @@ def derivations_basis(self): We construct another example using the exterior algebra and verify we obtain a derivation:: + sage: # needs sage.combinat sage.modules sage: A = algebras.Exterior(QQ, 1) sage: A.derivations_basis() ( [0 0] [0 1] ) - sage: D = A.module_morphism(matrix=A.derivations_basis()[0], codomain=A) + sage: D = A.module_morphism(matrix=A.derivations_basis()[0], + ....: codomain=A) sage: one, e = A.basis() sage: all(D(a*b) == D(a) * b + a * D(b) ....: for a in A.basis() for b in A.basis()) diff --git a/src/sage/categories/manifolds.py b/src/sage/categories/manifolds.py index 39ba682764e..f8dc1da4de0 100644 --- a/src/sage/categories/manifolds.py +++ b/src/sage/categories/manifolds.py @@ -25,6 +25,7 @@ class Manifolds(Category_over_base_ring): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: from sage.categories.manifolds import Manifolds sage: C = Manifolds(RR); C Category of manifolds over Real Field with 53 bits of precision @@ -33,7 +34,7 @@ class Manifolds(Category_over_base_ring): TESTS:: - sage: TestSuite(C).run(skip="_test_category_over_bases") + sage: TestSuite(C).run(skip="_test_category_over_bases") # needs sage.rings.real_mpfr """ def __init__(self, base, name=None): r""" @@ -100,7 +101,7 @@ def Connected(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Connected() + sage: Manifolds(RR).Connected() # needs sage.rings.real_mpfr Category of connected manifolds over Real Field with 53 bits of precision @@ -120,7 +121,7 @@ def FiniteDimensional(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: C = Manifolds(RR).Connected().FiniteDimensional(); C + sage: C = Manifolds(RR).Connected().FiniteDimensional(); C # needs sage.rings.real_mpfr Category of finite dimensional connected manifolds over Real Field with 53 bits of precision @@ -141,7 +142,7 @@ def Differentiable(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Differentiable() + sage: Manifolds(RR).Differentiable() # needs sage.rings.real_mpfr Category of differentiable manifolds over Real Field with 53 bits of precision @@ -161,7 +162,7 @@ def Smooth(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Smooth() + sage: Manifolds(RR).Smooth() # needs sage.rings.real_mpfr Category of smooth manifolds over Real Field with 53 bits of precision @@ -181,7 +182,7 @@ def Analytic(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Analytic() + sage: Manifolds(RR).Analytic() # needs sage.rings.real_mpfr Category of analytic manifolds over Real Field with 53 bits of precision @@ -202,7 +203,7 @@ def AlmostComplex(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).AlmostComplex() + sage: Manifolds(RR).AlmostComplex() # needs sage.rings.real_mpfr Category of almost complex manifolds over Real Field with 53 bits of precision @@ -222,14 +223,14 @@ def Complex(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(CC).Complex() + sage: Manifolds(CC).Complex() # needs sage.rings.real_mpfr Category of complex manifolds over Complex Field with 53 bits of precision TESTS:: - sage: TestSuite(Manifolds(CC).Complex()).run() - sage: Manifolds(CC).Complex.__module__ + sage: TestSuite(Manifolds(CC).Complex()).run() # needs sage.rings.real_mpfr + sage: Manifolds(CC).Complex.__module__ # needs sage.rings.real_mpfr 'sage.categories.manifolds' """ return ComplexManifolds(self.base())._with_axioms(self.axioms()) @@ -256,7 +257,7 @@ def extra_super_categories(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Smooth().super_categories() # indirect doctest + sage: Manifolds(RR).Smooth().super_categories() # indirect doctest # needs sage.rings.real_mpfr [Category of differentiable manifolds over Real Field with 53 bits of precision] """ @@ -277,7 +278,7 @@ def extra_super_categories(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Analytic().super_categories() # indirect doctest + sage: Manifolds(RR).Analytic().super_categories() # indirect doctest # needs sage.rings.real_mpfr [Category of smooth manifolds over Real Field with 53 bits of precision] """ @@ -301,7 +302,7 @@ def extra_super_categories(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).AlmostComplex().super_categories() # indirect doctest + sage: Manifolds(RR).AlmostComplex().super_categories() # indirect doctest # needs sage.rings.real_mpfr [Category of smooth manifolds over Real Field with 53 bits of precision] """ diff --git a/src/sage/categories/map.pxd b/src/sage/categories/map.pxd index 120ef5ef0da..0467b872353 100644 --- a/src/sage/categories/map.pxd +++ b/src/sage/categories/map.pxd @@ -4,8 +4,9 @@ from sage.structure.element cimport Element cdef class Map(Element): cdef object __weakref__ - cdef public int _coerce_cost # a rough measure of the cost of using this morphism in the coercion system. - # 10 by default, 100 if a DefaultCoercionMorphism, 10000 if inexact. + cdef public int _coerce_cost + # a rough measure of the cost of using this morphism in the coercion system. + # 10 by default, 100 if a DefaultCoercionMorphism, 10000 if inexact. cdef _update_slots(self, dict) cdef dict _extra_slots(self) diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index a569cc83849..45c30ae6c31 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -115,7 +115,7 @@ cdef class Map(Element): Using domain and codomain:: - sage: Map(QQ['x'], SymmetricGroup(6)) + sage: Map(QQ['x'], SymmetricGroup(6)) # needs sage.groups Generic map: From: Univariate Polynomial Ring in x over Rational Field To: Symmetric group of order 6! as a permutation group @@ -131,13 +131,13 @@ cdef class Map(Element): C = parent.codomain() self._category_for = parent.homset_category() self._codomain = C - self.domain = ConstantFunction(D) - self.codomain = ConstantFunction(C) + self.domain = ConstantFunction(D) + self.codomain = ConstantFunction(C) self._is_coercion = False if D.is_exact() and C.is_exact(): - self._coerce_cost = 10 # default value. + self._coerce_cost = 10 # default value. else: - self._coerce_cost = 10000 # inexact morphisms are bad. + self._coerce_cost = 10000 # inexact morphisms are bad. def __copy__(self): """ @@ -196,34 +196,45 @@ cdef class Map(Element): EXAMPLES:: - sage: Q = QuadraticField(-5) - sage: phi = CDF._internal_convert_map_from(Q) - sage: print(phi.parent()) - Set of field embeddings from Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I to Complex Double Field + sage: Q = QuadraticField(-5) # needs sage.rings.number_field + sage: phi = CDF._internal_convert_map_from(Q) # needs sage.rings.number_field + sage: print(phi.parent()) # needs sage.rings.number_field + Set of field embeddings + from Number Field in a with defining polynomial x^2 + 5 + with a = 2.236067977499790?*I + to Complex Double Field We now demonstrate that the reference to the coercion map `\phi` does not prevent `Q` from being garbage collected:: sage: import gc - sage: del Q + sage: del Q # needs sage.rings.number_field sage: _ = gc.collect() - sage: phi.parent() + sage: phi.parent() # needs sage.rings.number_field Traceback (most recent call last): ... - ValueError: This map is in an invalid state, the domain has been garbage collected + ValueError: This map is in an invalid state, + the domain has been garbage collected You can still obtain copies of the maps used by the coercion system with strong references:: + sage: # needs sage.rings.number_field sage: Q = QuadraticField(-5) sage: phi = CDF.convert_map_from(Q) sage: print(phi.parent()) - Set of field embeddings from Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I to Complex Double Field + Set of field embeddings + from Number Field in a with defining polynomial x^2 + 5 + with a = 2.236067977499790?*I + to Complex Double Field sage: import gc sage: del Q sage: _ = gc.collect() sage: phi.parent() - Set of field embeddings from Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I to Complex Double Field + Set of field embeddings + from Number Field in a with defining polynomial x^2 + 5 + with a = 2.236067977499790?*I + to Complex Double Field """ if self._parent is None: D = self.domain() @@ -250,28 +261,33 @@ cdef class Map(Element): EXAMPLES:: - sage: Q = QuadraticField(-5) - sage: phi = CDF._internal_convert_map_from(Q) + sage: Q = QuadraticField(-5) # needs sage.rings.number_field + sage: phi = CDF._internal_convert_map_from(Q) # needs sage.rings.number_field By :trac:`14711`, maps used in the coercion and conversion system use *weak* references to domain and codomain, in contrast to other maps:: - sage: phi.domain + sage: phi.domain # needs sage.rings.number_field <weakref at ...; to 'NumberField_quadratic_with_category' at ...> - sage: phi._make_strong_references() - sage: print(phi.domain) - The constant function (...) -> Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I + sage: phi._make_strong_references() # needs sage.rings.number_field + sage: print(phi.domain) # needs sage.rings.number_field + The constant function (...) -> Number Field in a + with defining polynomial x^2 + 5 with a = 2.236067977499790?*I Now, as there is a strong reference, `Q` cannot be garbage collected:: + sage: # needs sage.rings.number_field sage: import gc sage: _ = gc.collect() sage: C = Q.__class__.__base__ - sage: numberQuadFields = len([x for x in gc.get_objects() if isinstance(x, C)]) + sage: x = None + sage: numberQuadFields = len([x for x in gc.get_objects() + ....: if isinstance(x, C)]) sage: del Q, x sage: _ = gc.collect() - sage: numberQuadFields == len([x for x in gc.get_objects() if isinstance(x, C)]) + sage: numberQuadFields == len([x for x in gc.get_objects() + ....: if isinstance(x, C)]) True However, if we now make the references weak again, the number field can @@ -279,9 +295,11 @@ cdef class Map(Element): invalid. This is why :meth:`_make_weak_references` should only be used if one really knows what one is doing:: + sage: # needs sage.rings.number_field sage: phi._make_weak_references() sage: _ = gc.collect() - sage: numberQuadFields == len([x for x in gc.get_objects() if isinstance(x, C)]) + 1 + sage: numberQuadFields == len([x for x in gc.get_objects() + ....: if isinstance(x, C)]) + 1 True sage: phi Defunct map @@ -311,28 +329,33 @@ cdef class Map(Element): EXAMPLES:: - sage: Q = QuadraticField(-5) - sage: phi = CDF._internal_convert_map_from(Q) + sage: Q = QuadraticField(-5) # needs sage.rings.number_field + sage: phi = CDF._internal_convert_map_from(Q) # needs sage.rings.number_field By :trac:`14711`, maps used in the coercion and conversion system use *weak* references to domain and codomain, in contrast to other maps:: - sage: phi.domain + sage: phi.domain # needs sage.rings.number_field <weakref at ...; to 'NumberField_quadratic_with_category' at ...> - sage: phi._make_strong_references() - sage: print(phi.domain) - The constant function (...) -> Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I + sage: phi._make_strong_references() # needs sage.rings.number_field + sage: print(phi.domain) # needs sage.rings.number_field + The constant function (...) -> Number Field in a + with defining polynomial x^2 + 5 with a = 2.236067977499790?*I Now, as there is a strong reference, `Q` cannot be garbage collected:: + sage: # needs sage.rings.number_field sage: import gc sage: _ = gc.collect() sage: C = Q.__class__.__base__ - sage: numberQuadFields = len([x for x in gc.get_objects() if isinstance(x, C)]) + sage: x = None + sage: numberQuadFields = len([x for x in gc.get_objects() + ....: if isinstance(x, C)]) sage: del Q, x sage: _ = gc.collect() - sage: numberQuadFields == len([x for x in gc.get_objects() if isinstance(x, C)]) + sage: numberQuadFields == len([x for x in gc.get_objects() + ....: if isinstance(x, C)]) True However, if we now make the references weak again, the number field can @@ -340,9 +363,11 @@ cdef class Map(Element): invalid. This is why :meth:`_make_weak_references` should only be used if one really knows what one is doing:: + sage: # needs sage.rings.number_field sage: phi._make_weak_references() sage: _ = gc.collect() - sage: numberQuadFields == len([x for x in gc.get_objects() if isinstance(x, C)]) + 1 + sage: numberQuadFields == len([x for x in gc.get_objects() + ....: if isinstance(x, C)]) + 1 True sage: phi Defunct map @@ -380,6 +405,7 @@ cdef class Map(Element): Since it is a ``cdef``d method, it is tested using a dummy python method. :: + sage: # needs sage.rings.real_mpfr sage: from sage.categories.map import Map sage: f = Map(Hom(QQ, ZZ, Rings())) sage: f._update_slots_test({"_domain": RR, "_codomain": QQ}) # indirect doctest @@ -410,6 +436,7 @@ cdef class Map(Element): TESTS:: + sage: # needs sage.rings.real_mpfr sage: from sage.categories.map import Map sage: f = Map(Hom(QQ, ZZ, Rings())) sage: f._update_slots_test({"_domain": RR, "_codomain": QQ}) @@ -544,6 +571,7 @@ cdef class Map(Element): TESTS:: + sage: # needs sage.rings.number_field sage: Q = QuadraticField(-5) sage: phi = CDF._internal_coerce_map_from(Q); phi (map internal to coercion system -- copy before use) @@ -559,13 +587,13 @@ cdef class Map(Element): D = self.domain() if D is None: return "Defunct map" - s = "%s map:"%self._repr_type() - s += "\n From: %s"%D - s += "\n To: %s"%self._codomain + s = "%s map:" % self._repr_type() + s += "\n From: %s" % D + s += "\n To: %s" % self._codomain if isinstance(self.domain, ConstantFunction): d = self._repr_defn() if d != '': - s += "\n Defn: %s"%('\n '.join(d.split('\n'))) + s += "\n Defn: %s" % ('\n '.join(d.split('\n'))) else: d = "(map internal to coercion system -- copy before use)" s = d + "\n" + s @@ -575,12 +603,12 @@ cdef class Map(Element): D = self.domain() if D is None: return "Defunct map" - s = "%s map:"%self._repr_type() - s += "\n From: %s"%D - s += "\n To: %s"%self._codomain + s = "%s map:" % self._repr_type() + s += "\n From: %s" % D + s += "\n To: %s" % self._codomain d = self._repr_defn() if d != '': - s += "\n Defn: %s"%('\n '.join(d.split('\n'))) + s += "\n Defn: %s" % ('\n '.join(d.split('\n'))) return s def domains(self): @@ -704,7 +732,8 @@ cdef class Map(Element): sage: f(1/2) Traceback (most recent call last): ... - TypeError: 1/2 fails to convert into the map's domain Integer Ring, but a `pushforward` method is not properly implemented + TypeError: 1/2 fails to convert into the map's domain Integer Ring, + but a `pushforward` method is not properly implemented We test that the default call method really works as described above (that was fixed in :trac:`10496`):: @@ -746,11 +775,11 @@ cdef class Map(Element): ``pushforward`` fails, ``_call_`` is tried after conversion:: sage: g = FOO(QQ, ZZ) - sage: g(SR(3)) # optional - sage.symbolic + sage: g(SR(3)) # needs sage.symbolic pushforward Symbolic Ring _call_ Rational Field 3 - sage: g(SR(3), exponent=2) # optional - sage.symbolic + sage: g(SR(3), exponent=2) # needs sage.symbolic pushforward Symbolic Ring _call_with_args Rational Field 9 @@ -761,7 +790,8 @@ cdef class Map(Element): sage: h(2/3) Traceback (most recent call last): ... - TypeError: 2/3 fails to convert into the map's domain Integer Ring, but a `pushforward` method is not properly implemented + TypeError: 2/3 fails to convert into the map's domain Integer Ring, + but a `pushforward` method is not properly implemented """ P = parent(x) cdef Parent D = self.domain() @@ -816,8 +846,8 @@ cdef class Map(Element): """ if not args and not kwds: return self(x) - else: - raise NotImplementedError("_call_with_args not overridden to accept arguments for %s" % type(self)) + raise NotImplementedError("_call_with_args not overridden " + f"to accept arguments for {type(self)}") def __mul__(self, right): r""" @@ -1062,7 +1092,7 @@ cdef class Map(Element): - ``self`` -- a Map in some ``Hom(X, Y, category_right)`` - ``left`` -- a Map in some ``Hom(Y, Z, category_left)`` - Returns the composition of ``self`` followed by ``right`` as a + Returns the composition of ``self`` followed by ``left`` as a morphism in ``Hom(X, Z, category)`` where ``category`` is the meet of ``category_left`` and ``category_right``. @@ -1103,10 +1133,11 @@ cdef class Map(Element): OUTPUT: An element of Hom(X, Z) obtained by composing self with `\phi`. If - no canonical `\phi` exists, a TypeError is raised. + no canonical `\phi` exists, a :class:`TypeError` is raised. EXAMPLES:: + sage: # needs sage.rings.complex_double sage: mor = CDF.coerce_map_from(RDF) sage: mor.extend_domain(QQ) Composite map: @@ -1122,7 +1153,8 @@ cdef class Map(Element): sage: mor.extend_domain(ZZ['x']) Traceback (most recent call last): ... - TypeError: No coercion from Univariate Polynomial Ring in x over Integer Ring to Real Double Field + TypeError: No coercion from Univariate Polynomial Ring in x over Integer Ring + to Real Double Field """ D = self.domain() if D is None: @@ -1146,7 +1178,7 @@ cdef class Map(Element): OUTPUT: An element of Hom(X, Z) obtained by composing self with `\phi`. If - no canonical `\phi` exists, a TypeError is raised. + no canonical `\phi` exists, a :class:`TypeError` is raised. EXAMPLES:: @@ -1217,6 +1249,7 @@ cdef class Map(Element): ... TypeError: self must be an endomorphism + sage: # needs sage.rings.number_field sage: K.<a> = NumberField(x^4 - 5*x + 5) sage: C5.<z> = CyclotomicField(5) sage: tau = K.hom([z - z^2]); tau @@ -1331,7 +1364,7 @@ cdef class Section(Map): To: Multivariate Polynomial Ring in x, y over Rational Field """ from sage.categories.homset import Hom - from sage.categories.all import SetsWithPartialMaps + from sage.categories.sets_with_partial_maps import SetsWithPartialMaps Map.__init__(self, Hom(map.codomain(), map.domain(), SetsWithPartialMaps())) self._inverse = map # TODO: Use this attribute somewhere! @@ -1777,7 +1810,7 @@ cdef class FormalCompositeMap(Map): From: Univariate Polynomial Ring in x over Rational Field To: Univariate Polynomial Ring in a over Rational Field """ - s = " %s"%(self.__list[0]) + s = " %s" % (self.__list[0]) for f in self.__list[1:]: s += "\nthen\n %s" % f return s @@ -1851,6 +1884,7 @@ cdef class FormalCompositeMap(Map): EXAMPLES:: + sage: # needs sage.modules sage: V1 = QQ^2 sage: V2 = QQ^3 sage: phi1 = (QQ^1).hom(Matrix([[1, 1]]), V1) @@ -1859,16 +1893,18 @@ cdef class FormalCompositeMap(Map): If both constituents are injective, the composition is injective:: sage: from sage.categories.map import FormalCompositeMap - sage: c1 = FormalCompositeMap(Hom(QQ^1, V2, phi1.category_for()), phi1, phi2) - sage: c1.is_injective() + sage: c1 = FormalCompositeMap(Hom(QQ^1, V2, phi1.category_for()), # needs sage.modules + ....: phi1, phi2) + sage: c1.is_injective() # needs sage.modules True If it cannot be determined whether the composition is injective, an error is raised:: - sage: psi1 = V2.hom(Matrix([[1, 2], [3, 4], [5, 6]]), V1) - sage: c2 = FormalCompositeMap(Hom(V1, V1, phi2.category_for()), phi2, psi1) - sage: c2.is_injective() + sage: psi1 = V2.hom(Matrix([[1, 2], [3, 4], [5, 6]]), V1) # needs sage.modules + sage: c2 = FormalCompositeMap(Hom(V1, V1, phi2.category_for()), # needs sage.modules + ....: phi2, psi1) + sage: c2.is_injective() # needs sage.modules Traceback (most recent call last): ... NotImplementedError: not enough information to deduce injectivity @@ -1876,17 +1912,18 @@ cdef class FormalCompositeMap(Map): If the first map is surjective and the second map is not injective, then the composition is not injective:: - sage: psi2 = V1.hom([[1], [1]], QQ^1) - sage: c3 = FormalCompositeMap(Hom(V2, QQ^1, phi2.category_for()), psi2, psi1) - sage: c3.is_injective() + sage: psi2 = V1.hom([[1], [1]], QQ^1) # needs sage.modules + sage: c3 = FormalCompositeMap(Hom(V2, QQ^1, phi2.category_for()), # needs sage.modules + ....: psi2, psi1) + sage: c3.is_injective() # needs sage.modules False TESTS: Check that :trac:`23205` has been resolved:: - sage: f = QQ.hom(QQbar)*ZZ.hom(QQ) - sage: f.is_injective() + sage: f = QQ.hom(QQbar) * ZZ.hom(QQ) # needs sage.rings.number_field + sage: f.is_injective() # needs sage.rings.number_field True """ @@ -1923,33 +1960,39 @@ cdef class FormalCompositeMap(Map): EXAMPLES:: sage: from sage.categories.map import FormalCompositeMap - sage: V3 = QQ^3 - sage: V2 = QQ^2 - sage: V1 = QQ^1 + sage: V3 = QQ^3 # needs sage.modules + sage: V2 = QQ^2 # needs sage.modules + sage: V1 = QQ^1 # needs sage.modules If both maps are surjective, the composition is surjective:: + sage: # needs sage.modules sage: phi32 = V3.hom(Matrix([[1, 2], [3, 4], [5, 6]]), V2) sage: phi21 = V2.hom(Matrix([[1], [1]]), V1) - sage: c_phi = FormalCompositeMap(Hom(V3, V1, phi32.category_for()), phi32, phi21) + sage: c_phi = FormalCompositeMap(Hom(V3, V1, phi32.category_for()), + ....: phi32, phi21) sage: c_phi.is_surjective() True If the second map is not surjective, the composition is not surjective:: - sage: FormalCompositeMap(Hom(V3, V1, phi32.category_for()), phi32, V2.hom(Matrix([[0], [0]]), V1)).is_surjective() + sage: FormalCompositeMap(Hom(V3, V1, phi32.category_for()), # needs sage.modules + ....: phi32, + ....: V2.hom(Matrix([[0], [0]]), V1)).is_surjective() False If the second map is an isomorphism and the first map is not surjective, then the composition is not surjective:: - sage: FormalCompositeMap(Hom(V2, V1, phi32.category_for()), V2.hom(Matrix([[0], [0]]), V1), V1.hom(Matrix([[1]]), V1)).is_surjective() + sage: FormalCompositeMap(Hom(V2, V1, phi32.category_for()), # needs sage.modules + ....: V2.hom(Matrix([[0], [0]]), V1), + ....: V1.hom(Matrix([[1]]), V1)).is_surjective() False Otherwise, surjectivity of the composition cannot be determined:: - sage: FormalCompositeMap(Hom(V2, V1, phi32.category_for()), + sage: FormalCompositeMap(Hom(V2, V1, phi32.category_for()), # needs sage.modules ....: V2.hom(Matrix([[1, 1], [1, 1]]), V2), ....: V2.hom(Matrix([[1], [1]]), V1)).is_surjective() Traceback (most recent call last): @@ -1991,8 +2034,8 @@ cdef class FormalCompositeMap(Map): EXAMPLES:: sage: f = QQ.coerce_map_from(ZZ) - sage: g = MatrixSpace(QQ, 2, 2).coerce_map_from(QQ) - sage: list((g*f).domains()) + sage: g = MatrixSpace(QQ, 2, 2).coerce_map_from(QQ) # needs sage.modules + sage: list((g * f).domains()) # needs sage.modules [Integer Ring, Rational Field] """ for f in self.__list: diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py index 6608ca7d4e5..205e8746363 100644 --- a/src/sage/categories/metric_spaces.py +++ b/src/sage/categories/metric_spaces.py @@ -127,10 +127,11 @@ def _test_metric_function(self, **options): EXAMPLES:: - sage: UHP = HyperbolicPlane().UHP() # optional - sage.symbolic - sage: UHP._test_metric_function() # optional - sage.symbolic - sage: elts = [UHP.random_element() for i in range(5)] # optional - sage.symbolic - sage: UHP._test_metric_function(some_elements=elts) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: UHP = HyperbolicPlane().UHP() + sage: UHP._test_metric_function() + sage: elts = [UHP.random_element() for i in range(5)] + sage: UHP._test_metric_function(some_elements=elts) """ tester = self._tester(**options) S = tester.some_elements() @@ -149,11 +150,12 @@ def metric_function(self): EXAMPLES:: - sage: UHP = HyperbolicPlane().UHP() # optional - sage.symbolic - sage: m = UHP.metric_function() # optional - sage.symbolic - sage: p1 = UHP.get_point(5 + 7*I) # optional - sage.symbolic - sage: p2 = UHP.get_point(1.0 + I) # optional - sage.symbolic - sage: m(p1, p2) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: UHP = HyperbolicPlane().UHP() + sage: m = UHP.metric_function() + sage: p1 = UHP.get_point(5 + 7*I) + sage: p2 = UHP.get_point(1.0 + I) + sage: m(p1, p2) 2.23230104635820 """ return lambda a,b: a.dist(b) @@ -166,27 +168,28 @@ def dist(self, a, b): EXAMPLES:: - sage: UHP = HyperbolicPlane().UHP() # optional - sage.symbolic - sage: p1 = UHP.get_point(5 + 7*I) # optional - sage.symbolic - sage: p2 = UHP.get_point(1.0 + I) # optional - sage.symbolic - sage: UHP.dist(p1, p2) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: UHP = HyperbolicPlane().UHP() + sage: p1 = UHP.get_point(5 + 7*I) + sage: p2 = UHP.get_point(1.0 + I) + sage: UHP.dist(p1, p2) 2.23230104635820 - sage: PD = HyperbolicPlane().PD() # optional - sage.symbolic - sage: PD.dist(PD.get_point(0), PD.get_point(I/2)) # optional - sage.symbolic + sage: PD = HyperbolicPlane().PD() # needs sage.symbolic + sage: PD.dist(PD.get_point(0), PD.get_point(I/2)) # needs sage.symbolic arccosh(5/3) TESTS:: - sage: RR.dist(-1, pi) # optional - sage.symbolic + sage: RR.dist(-1, pi) # needs sage.rings.real_mpfr sage.symbolic 4.14159265358979 sage: RDF.dist(1, -1/2) 1.5 - sage: CC.dist(3, 2) + sage: CC.dist(3, 2) # needs sage.rings.real_mpfr 1.00000000000000 - sage: CC.dist(-1, I) + sage: CC.dist(-1, I) # needs sage.rings.real_mpfr sage.symbolic 1.41421356237310 - sage: CDF.dist(-1, I) + sage: CDF.dist(-1, I) # needs sage.rings.real_mpfr sage.symbolic 1.4142135623730951 """ return (self(a) - self(b)).abs() @@ -198,7 +201,7 @@ def abs(self): EXAMPLES:: - sage: CC(I).abs() + sage: CC(I).abs() # needs sage.rings.real_mpfr sage.symbolic 1.00000000000000 """ P = self.parent() @@ -210,10 +213,11 @@ def dist(self, b): EXAMPLES:: - sage: UHP = HyperbolicPlane().UHP() # optional - sage.symbolic - sage: p1 = UHP.get_point(5 + 7*I) # optional - sage.symbolic - sage: p2 = UHP.get_point(1 + I) # optional - sage.symbolic - sage: p1.dist(p2) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: UHP = HyperbolicPlane().UHP() + sage: p1 = UHP.get_point(5 + 7*I) + sage: p2 = UHP.get_point(1 + I) + sage: p1.dist(p2) arccosh(33/7) """ return self.parent().dist(self, b) @@ -266,11 +270,12 @@ def dist(self, a, b): EXAMPLES:: - sage: H = HyperbolicPlane() # optional - sage.symbolic - sage: PD = H.PD() # optional - sage.symbolic - sage: p1 = PD.get_point(0) # optional - sage.symbolic - sage: p2 = PD.get_point(I/2) # optional - sage.symbolic - sage: H.dist(p1, p2) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: H = HyperbolicPlane() + sage: PD = H.PD() + sage: p1 = PD.get_point(0) + sage: p2 = PD.get_point(I/2) + sage: H.dist(p1, p2) arccosh(5/3) """ R = self.a_realization() diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index cb878f1c6f2..e65bab4faf8 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -72,10 +72,12 @@ class Modules(Category_module): Category of modules over Ring of integers modulo 9 sage: Modules(Integers(9)).super_categories() - [Category of bimodules over Ring of integers modulo 9 on the left and Ring of integers modulo 9 on the right] + [Category of bimodules over Ring of integers modulo 9 on the left + and Ring of integers modulo 9 on the right] sage: Modules(ZZ).super_categories() - [Category of bimodules over Integer Ring on the left and Integer Ring on the right] + [Category of bimodules over Integer Ring on the left + and Integer Ring on the right] sage: Modules == RingModules True @@ -162,7 +164,8 @@ def super_categories(self): EXAMPLES:: sage: Modules(ZZ).super_categories() - [Category of bimodules over Integer Ring on the left and Integer Ring on the right] + [Category of bimodules over Integer Ring on the left + and Integer Ring on the right] Nota bene:: @@ -204,29 +207,32 @@ def base_ring(self): EXAMPLES:: sage: C = Modules(QQ) & Semigroups(); C - Join of Category of semigroups and Category of vector spaces over Rational Field + Join of Category of semigroups + and Category of vector spaces over Rational Field sage: C.base_ring() Rational Field sage: C.base_ring.__module__ 'sage.categories.modules' - sage: C = Modules(Rings()) & Semigroups(); C + sage: C2 = Modules(Rings()) & Semigroups(); C2 Join of Category of semigroups and Category of modules over rings - sage: C.base_ring() + sage: C2.base_ring() Category of rings - sage: C.base_ring.__module__ + sage: C2.base_ring.__module__ 'sage.categories.modules' - sage: C = DescentAlgebra(QQ,3).B().category() - sage: C.base_ring.__module__ + sage: # needs sage.combinat sage.modules + sage: C3 = DescentAlgebra(QQ,3).B().category() + sage: C3.base_ring.__module__ 'sage.categories.modules' - sage: C.base_ring() + sage: C3.base_ring() Rational Field - sage: C = QuasiSymmetricFunctions(QQ).F().category() - sage: C.base_ring.__module__ + sage: # needs sage.combinat sage.modules + sage: C4 = QuasiSymmetricFunctions(QQ).F().category() + sage: C4.base_ring.__module__ 'sage.categories.modules' - sage: C.base_ring() + sage: C4.base_ring() Rational Field """ for C in self.super_categories(): @@ -361,10 +367,11 @@ def FinitelyPresented(self): sage: Modules(ZZ).FinitelyPresented() Category of finitely presented modules over Integer Ring - sage: A = SteenrodAlgebra(2) - sage: from sage.modules.fp_graded.module import FPModule - sage: FPModule(A, [0, 1], [[Sq(2), Sq(1)]]).category() - Category of finitely presented graded modules over mod 2 Steenrod algebra, milnor basis + sage: A = SteenrodAlgebra(2) # needs sage.combinat sage.modules + sage: from sage.modules.fp_graded.module import FPModule # needs sage.combinat sage.modules + sage: FPModule(A, [0, 1], [[Sq(2), Sq(1)]]).category() # needs sage.combinat sage.modules + Category of finitely presented graded modules + over mod 2 Steenrod algebra, milnor basis TESTS:: @@ -547,7 +554,8 @@ def extra_super_categories(self): sage: Modules(ZZ).FiniteDimensional().TensorProducts().extra_super_categories() [Category of finite dimensional modules over Integer Ring] sage: Modules(QQ).FiniteDimensional().TensorProducts().FiniteDimensional() - Category of tensor products of finite dimensional vector spaces over Rational Field + Category of tensor products of finite dimensional vector spaces + over Rational Field """ return [self.base_category()] @@ -612,9 +620,9 @@ def linear_combination(self, iter_of_elements_coeff, factor_on_left=True): EXAMPLES:: - sage: m = matrix([[0,1],[1,1]]) - sage: J.<a,b,c> = JordanAlgebra(m) - sage: J.linear_combination(((a+b, 1), (-2*b + c, -1))) + sage: m = matrix([[0,1], [1,1]]) # needs sage.modules + sage: J.<a,b,c> = JordanAlgebra(m) # needs sage.combinat sage.modules + sage: J.linear_combination(((a+b, 1), (-2*b + c, -1))) # needs sage.combinat sage.modules 1 + (3, -1) """ if factor_on_left: @@ -631,8 +639,8 @@ def tensor_square(self): EXAMPLES:: - sage: A = HopfAlgebrasWithBasis(QQ).example() - sage: A.tensor_square() + sage: A = HopfAlgebrasWithBasis(QQ).example() # needs sage.groups sage.modules + sage: A.tensor_square() # needs sage.groups sage.modules An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field # An example @@ -661,11 +669,14 @@ def module_morphism(self, *, function, category=None, codomain, **keywords): EXAMPLES:: + sage: # needs sage.modules sage: V = FiniteRankFreeModule(QQ, 2) sage: e = V.basis('e'); e - Basis (e_0,e_1) on the 2-dimensional vector space over the Rational Field + Basis (e_0,e_1) on the + 2-dimensional vector space over the Rational Field sage: neg = V.module_morphism(function=operator.neg, codomain=V); neg - Generic endomorphism of 2-dimensional vector space over the Rational Field + Generic endomorphism of + 2-dimensional vector space over the Rational Field sage: neg(e[0]) Element -e_0 of the 2-dimensional vector space over the Rational Field @@ -698,11 +709,12 @@ def quotient(self, submodule, check=True, **kwds): EXAMPLES:: - sage: C = CombinatorialFreeModule(QQ, ['a','b','c']) - sage: TA = TensorAlgebra(C) - sage: TA.quotient + sage: C = CombinatorialFreeModule(QQ, ['a','b','c']) # needs sage.modules + sage: TA = TensorAlgebra(C) # needs sage.combinat sage.modules + sage: TA.quotient # needs sage.combinat sage.modules <bound method Rings.ParentMethods.quotient of - Tensor Algebra of Free module generated by {'a', 'b', 'c'} over Rational Field> + Tensor Algebra of Free module generated by {'a', 'b', 'c'} + over Rational Field> """ return self.quotient_module(submodule, check=check, **kwds) @@ -748,6 +760,7 @@ def base_ring(self): EXAMPLES:: + sage: # needs sage.modules sage: E = CombinatorialFreeModule(ZZ, [1,2,3]) sage: F = CombinatorialFreeModule(ZZ, [2,3,4]) sage: H = Hom(E, F) @@ -757,12 +770,12 @@ def base_ring(self): This ``base_ring`` method is actually overridden by :meth:`sage.structure.category_object.CategoryObject.base_ring`:: - sage: H.base_ring.__module__ + sage: H.base_ring.__module__ # needs sage.modules Here we call it directly:: - sage: method = H.category().parent_class.base_ring - sage: method.__get__(H)() + sage: method = H.category().parent_class.base_ring # needs sage.modules + sage: method.__get__(H)() # needs sage.modules Integer Ring """ return self.domain().base_ring() @@ -772,6 +785,7 @@ def zero(self): """ EXAMPLES:: + sage: # needs sage.modules sage: E = CombinatorialFreeModule(ZZ, [1,2,3]) sage: F = CombinatorialFreeModule(ZZ, [2,3,4]) sage: H = Hom(E, F) @@ -789,7 +803,7 @@ def zero(self): We check that ``H.zero()`` is picklable:: - sage: loads(dumps(f.parent().zero())) + sage: loads(dumps(f.parent().zero())) # needs sage.modules Generic morphism: From: Free module generated by {1, 2, 3} over Integer Ring To: Free module generated by {2, 3, 4} over Integer Ring @@ -813,7 +827,7 @@ def extra_super_categories(self): sage: Modules(ZZ).Endsets().extra_super_categories() [Category of magmatic algebras over Integer Ring] - sage: End(ZZ^3) in Algebras(ZZ) + sage: End(ZZ^3) in Algebras(ZZ) # needs sage.modules True """ from .magmatic_algebras import MagmaticAlgebras @@ -852,6 +866,7 @@ def __init_extra__(self): EXAMPLES:: + sage: # needs sage.modules sage: E = CombinatorialFreeModule(ZZ, [1,2,3]) sage: F = CombinatorialFreeModule(ZZ, [2,3,4]) sage: C = cartesian_product([E, F]); C @@ -862,28 +877,36 @@ def __init_extra__(self): Check that :trac:`29225` is fixed:: - sage: M = cartesian_product((ZZ^2, ZZ^3)); M - The Cartesian product of (Ambient free module of rank 2 over the principal ideal domain Integer Ring, Ambient free module of rank 3 over the principal ideal domain Integer Ring) - sage: M.category() - Category of Cartesian products of modules with basis over (euclidean domains and infinite enumerated sets and metric spaces) - sage: M.base_ring() + sage: M = cartesian_product((ZZ^2, ZZ^3)); M # needs sage.modules + The Cartesian product of + (Ambient free module of rank 2 over the principal ideal domain Integer Ring, + Ambient free module of rank 3 over the principal ideal domain Integer Ring) + sage: M.category() # needs sage.modules + Category of Cartesian products of modules with basis + over (euclidean domains and infinite enumerated sets and metric spaces) + sage: M.base_ring() # needs sage.modules Integer Ring - sage: A = cartesian_product((QQ^2, QQ['x'])); A - The Cartesian product of (Vector space of dimension 2 over Rational Field, Univariate Polynomial Ring in x over Rational Field) - sage: A.category() - Category of Cartesian products of vector spaces over (number fields and quotient fields and metric spaces) - sage: A.base_ring() + sage: A = cartesian_product((QQ^2, QQ['x'])); A # needs sage.modules + The Cartesian product of + (Vector space of dimension 2 over Rational Field, + Univariate Polynomial Ring in x over Rational Field) + sage: A.category() # needs sage.modules + Category of Cartesian products of vector spaces + over (number fields and quotient fields and metric spaces) + sage: A.base_ring() # needs sage.modules Rational Field This currently only works if all factors have the same base ring:: - sage: B = cartesian_product((ZZ['x'], QQ^3)); B - The Cartesian product of (Univariate Polynomial Ring in x over Integer Ring, Vector space of dimension 3 over Rational Field) - sage: B.category() + sage: B = cartesian_product((ZZ['x'], QQ^3)); B # needs sage.modules + The Cartesian product of + (Univariate Polynomial Ring in x over Integer Ring, + Vector space of dimension 3 over Rational Field) + sage: B.category() # needs sage.modules Category of Cartesian products of commutative additive groups - sage: B.base_ring() + sage: B.base_ring() # needs sage.modules """ factors = self._sets if factors: @@ -899,10 +922,12 @@ def _lmul_(self, x): EXAMPLES:: - sage: A = FreeModule(ZZ, 2) - sage: B = cartesian_product([A, A]); B - The Cartesian product of (Ambient free module of rank 2 over the principal ideal domain Integer Ring, Ambient free module of rank 2 over the principal ideal domain Integer Ring) - sage: 5*B(([1, 2], [3, 4])) + sage: A = FreeModule(ZZ, 2) # needs sage.modules + sage: B = cartesian_product([A, A]); B # needs sage.modules + The Cartesian product of + (Ambient free module of rank 2 over the principal ideal domain Integer Ring, + Ambient free module of rank 2 over the principal ideal domain Integer Ring) + sage: 5*B(([1, 2], [3, 4])) # needs sage.modules ((5, 10), (15, 20)) """ return self.parent()._cartesian_product_of_elements( @@ -934,9 +959,9 @@ def construction(self): EXAMPLES:: - sage: A = algebras.Free(QQ,2) - sage: T = A.tensor(A) - sage: T.construction() + sage: A = algebras.Free(QQ, 2) # needs sage.combinat sage.modules + sage: T = A.tensor(A) # needs sage.combinat sage.modules + sage: T.construction() # needs sage.combinat sage.modules (The tensor functorial construction, (Free Algebra on 2 generators (None0, None1) over Rational Field, Free Algebra on 2 generators (None0, None1) over Rational Field)) @@ -957,6 +982,7 @@ def tensor_factors(self): EXAMPLES:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(ZZ, [1,2]) sage: F.rename("F") sage: G = CombinatorialFreeModule(ZZ, [3,4]) @@ -968,9 +994,9 @@ def tensor_factors(self): TESTS:: - sage: M = CombinatorialFreeModule(ZZ, ((1, 1), (1, 2), (2, 1), (2, 2)), - ....: category=ModulesWithBasis(ZZ).FiniteDimensional().TensorProducts()) - sage: M.construction() + sage: Cat = ModulesWithBasis(ZZ).FiniteDimensional().TensorProducts() + sage: M = CombinatorialFreeModule(ZZ, ((1, 1), (1, 2), (2, 1), (2, 2)), category=Cat) # needs sage.modules + sage: M.construction() # needs sage.modules doctest:warning... DeprecationWarning: implementations of Modules().TensorProducts() now must define the method tensor_factors See https://github.com/sagemath/sage/issues/34393 for details. diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 99b57ff8c8e..e97bf851388 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -66,22 +66,23 @@ class ModulesWithBasis(CategoryWithAxiom_over_base_ring): Let `X` and `Y` be two modules with basis. We can build `Hom(X,Y)`:: - sage: X = CombinatorialFreeModule(QQ, [1,2]); X.__custom_name = "X" - sage: Y = CombinatorialFreeModule(QQ, [3,4]); Y.__custom_name = "Y" - sage: H = Hom(X, Y); H - Set of Morphisms from X to Y in Category of finite dimensional vector spaces with basis over Rational Field + sage: X = CombinatorialFreeModule(QQ, [1,2]); X.rename("X") # needs sage.modules + sage: Y = CombinatorialFreeModule(QQ, [3,4]); Y.rename("Y") # needs sage.modules + sage: H = Hom(X, Y); H # needs sage.modules + Set of Morphisms from X to Y + in Category of finite dimensional vector spaces with basis over Rational Field The simplest morphism is the zero map:: - sage: H.zero() # todo: move this test into module once we have an example + sage: H.zero() # todo: move this test into module once we have an example # needs sage.modules Generic morphism: From: X To: Y which we can apply to elements of `X`:: - sage: x = X.monomial(1) + 3 * X.monomial(2) - sage: H.zero()(x) + sage: x = X.monomial(1) + 3 * X.monomial(2) # needs sage.modules + sage: H.zero()(x) # needs sage.modules 0 EXAMPLES: @@ -89,17 +90,17 @@ class ModulesWithBasis(CategoryWithAxiom_over_base_ring): We now construct a more interesting morphism by extending a function by linearity:: - sage: phi = H(on_basis = lambda i: Y.monomial(i+2)); phi + sage: phi = H(on_basis=lambda i: Y.monomial(i + 2)); phi # needs sage.modules Generic morphism: From: X To: Y - sage: phi(x) + sage: phi(x) # needs sage.modules B[3] + 3*B[4] We can retrieve the function acting on indices of the basis:: - sage: f = phi.on_basis() - sage: f(1), f(2) + sage: f = phi.on_basis() # needs sage.modules + sage: f(1), f(2) # needs sage.modules (B[3], B[4]) `Hom(X,Y)` has a natural module structure (except for the zero, @@ -108,14 +109,14 @@ class ModulesWithBasis(CategoryWithAxiom_over_base_ring): basis; but see :class:`FiniteDimensionalModulesWithBasis` and :class:`GradedModulesWithBasis`:: - sage: H in ModulesWithBasis(QQ), H in Modules(QQ) + sage: H in ModulesWithBasis(QQ), H in Modules(QQ) # needs sage.modules (False, True) Some more playing around with categories and higher order homsets:: - sage: H.category() + sage: H.category() # needs sage.modules Category of homsets of modules with basis over Rational Field - sage: Hom(H, H).category() + sage: Hom(H, H).category() # needs sage.modules Category of endsets of homsets of modules with basis over Rational Field .. TODO:: ``End(X)`` is an algebra. @@ -128,10 +129,10 @@ class ModulesWithBasis(CategoryWithAxiom_over_base_ring): TESTS:: - sage: f = H.zero().on_basis() - sage: f(1) + sage: f = H.zero().on_basis() # needs sage.modules + sage: f(1) # needs sage.modules 0 - sage: f(2) + sage: f(2) # needs sage.modules 0 sage: TestSuite(ModulesWithBasis(ZZ)).run() @@ -151,20 +152,20 @@ def _call_(self, x): ``x`` is returned unchanged if it is already in this category:: - sage: CZ(CombinatorialFreeModule(ZZ, ('a','b','c'))) + sage: CZ(CombinatorialFreeModule(ZZ, ('a', 'b', 'c'))) # needs sage.modules Free module generated by {'a', 'b', 'c'} over Integer Ring - sage: CZ(ZZ^3) + sage: CZ(ZZ^3) # needs sage.modules Ambient free module of rank 3 over the principal ideal domain Integer Ring If needed (and possible) the base ring is changed appropriately:: - sage: CQ(ZZ^3) # indirect doctest + sage: CQ(ZZ^3) # indirect doctest # needs sage.modules Vector space of dimension 3 over Rational Field If ``x`` itself is not a module with basis, but there is a canonical one associated to it, the latter is returned:: - sage: CQ(AbelianVariety(Gamma0(37))) # indirect doctest + sage: CQ(AbelianVariety(Gamma0(37))) # indirect doctest # needs sage.modular sage.modules Vector space of dimension 4 over Rational Field """ try: @@ -172,7 +173,7 @@ def _call_(self, x): if M.base_ring() != self.base_ring(): M = M.change_ring(self.base_ring()) except (TypeError, AttributeError) as msg: - raise TypeError("%s\nunable to coerce x (=%s) into %s"%(msg,x,self)) + raise TypeError("%s\nunable to coerce x (=%s) into %s" % (msg,x,self)) return M def is_abelian(self): @@ -209,14 +210,14 @@ def basis(self): EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) - sage: F.basis() + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) # needs sage.modules + sage: F.basis() # needs sage.modules Finite family {'a': B['a'], 'b': B['b'], 'c': B['c']} :: - sage: QS3 = SymmetricGroupAlgebra(QQ,3) - sage: list(QS3.basis()) + sage: QS3 = SymmetricGroupAlgebra(QQ, 3) # needs sage.combinat sage.groups sage.modules + sage: list(QS3.basis()) # needs sage.combinat sage.groups sage.modules [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] """ from sage.sets.family import Family @@ -297,13 +298,15 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, :: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, [1,2,3]); X.rename("X") sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4]); Y.rename("Y") - sage: phi = X.module_morphism(lambda i: Y.monomial(i) + 2*Y.monomial(i+1), codomain = Y) + sage: def f(i): + ....: return Y.monomial(i) + 2*Y.monomial(i+1) + sage: phi = X.module_morphism(f, codomain=Y) sage: x = X.basis(); y = Y.basis() sage: phi(x[1] + x[3]) B[1] + 2*B[2] + B[3] + 2*B[4] - sage: phi Generic morphism: From: X @@ -315,101 +318,109 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, ``CommutativeAdditiveMonoids()`` that contains both the domain and the codomain:: - sage: phi.category_for() - Category of finite dimensional vector spaces with basis over Rational Field + sage: phi.category_for() # needs sage.modules + Category of finite dimensional vector spaces with basis + over Rational Field With the ``zero`` argument, one can define affine morphisms:: - sage: phi = X.module_morphism(lambda i: Y.monomial(i) + 2*Y.monomial(i+1), - ....: codomain = Y, zero = 10*y[1]) - sage: phi(x[1] + x[3]) + sage: def f(i): + ....: return Y.monomial(i) + 2*Y.monomial(i+1) + sage: phi = X.module_morphism(f, codomain=Y, zero=10*y[1]) # needs sage.modules + sage: phi(x[1] + x[3]) # needs sage.modules 11*B[1] + 2*B[2] + B[3] + 2*B[4] In this special case, the default category is ``Sets()``:: - sage: phi.category_for() + sage: phi.category_for() # needs sage.modules Category of sets One can construct morphisms with the base ring as codomain:: - sage: X = CombinatorialFreeModule(ZZ,[1,-1]) - sage: phi = X.module_morphism( on_basis=lambda i: i, codomain=ZZ ) - sage: phi( 2 * X.monomial(1) + 3 * X.monomial(-1) ) + sage: # needs sage.modules + sage: X = CombinatorialFreeModule(ZZ, [1, -1]) + sage: phi = X.module_morphism(on_basis=lambda i: i, codomain=ZZ) + sage: phi(2 * X.monomial(1) + 3 * X.monomial(-1)) -1 sage: phi.category_for() Category of commutative additive semigroups - sage: phi.category_for() # todo: not implemented (ZZ is currently not in Modules(ZZ)) + sage: phi.category_for() # not implemented Category of modules over Integer Ring Or more generally any ring admitting a coercion map from the base ring:: - sage: phi = X.module_morphism(on_basis=lambda i: i, codomain=RR ) - sage: phi( 2 * X.monomial(1) + 3 * X.monomial(-1) ) + sage: # needs sage.modules + sage: phi = X.module_morphism(on_basis=lambda i: i, codomain=RR) + sage: phi(2 * X.monomial(1) + 3 * X.monomial(-1)) -1.00000000000000 sage: phi.category_for() Category of commutative additive semigroups - sage: phi.category_for() # todo: not implemented (RR is currently not in Modules(ZZ)) + sage: phi.category_for() # not implemented Category of modules over Integer Ring - sage: phi = X.module_morphism(on_basis=lambda i: i, codomain=Zmod(4) ) - sage: phi( 2 * X.monomial(1) + 3 * X.monomial(-1) ) + sage: phi = X.module_morphism(on_basis=lambda i: i, codomain=Zmod(4)) # needs sage.modules + sage: phi(2 * X.monomial(1) + 3 * X.monomial(-1)) # needs sage.modules 3 - sage: phi = Y.module_morphism(on_basis=lambda i: i, codomain=Zmod(4) ) + sage: phi = Y.module_morphism(on_basis=lambda i: i, codomain=Zmod(4)) # needs sage.modules Traceback (most recent call last): ... - ValueError: codomain(=Ring of integers modulo 4) should be a module over the base ring of the domain(=Y) + ValueError: codomain(=Ring of integers modulo 4) should be a module + over the base ring of the domain(=Y) On can also define module morphisms between free modules over different base rings; here we implement the natural map from `X = \RR^2` to `Y = \CC`:: - sage: X = CombinatorialFreeModule(RR,['x','y']) - sage: Y = CombinatorialFreeModule(CC,['z']) + sage: # needs sage.modules + sage: X = CombinatorialFreeModule(RR, ['x', 'y']) + sage: Y = CombinatorialFreeModule(CC, ['z']) sage: x = X.monomial('x') sage: y = X.monomial('y') sage: z = Y.monomial('z') - sage: def on_basis( a ): + sage: def on_basis(a): ....: if a == 'x': ....: return CC(1) * z ....: elif a == 'y': ....: return CC(I) * z - sage: phi = X.module_morphism( on_basis=on_basis, codomain=Y ) + sage: phi = X.module_morphism(on_basis=on_basis, codomain=Y) sage: v = 3 * x + 2 * y; v 3.00000000000000*B['x'] + 2.00000000000000*B['y'] - sage: phi(v) + sage: phi(v) # needs sage.symbolic (3.00000000000000+2.00000000000000*I)*B['z'] sage: phi.category_for() Category of commutative additive semigroups - sage: phi.category_for() # todo: not implemented (CC is currently not in Modules(RR)!) + sage: phi.category_for() # not implemented Category of vector spaces over Real Field with 53 bits of precision - sage: Y = CombinatorialFreeModule(CC['q'],['z']) + sage: # needs sage.modules + sage: Y = CombinatorialFreeModule(CC['q'], ['z']) sage: z = Y.monomial('z') - sage: phi = X.module_morphism( on_basis=on_basis, codomain=Y ) - sage: phi(v) + sage: phi = X.module_morphism(on_basis=on_basis, codomain=Y) + sage: phi(v) # needs sage.symbolic (3.00000000000000+2.00000000000000*I)*B['z'] Of course, there should be a coercion between the respective base rings of the domain and the codomain for this to be meaningful:: - sage: Y = CombinatorialFreeModule(QQ,['z']) - sage: phi = X.module_morphism( on_basis=on_basis, codomain=Y ) + sage: Y = CombinatorialFreeModule(QQ, ['z']) # needs sage.modules + sage: phi = X.module_morphism(on_basis=on_basis, codomain=Y) # needs sage.modules Traceback (most recent call last): ... ValueError: codomain(=Free module generated by {'z'} over Rational Field) - should be a module over the base ring of the - domain(=Free module generated by {'x', 'y'} over Real Field with 53 bits of precision) + should be a module over the base ring of the domain(=Free module + generated by {'x', 'y'} over Real Field with 53 bits of precision) - sage: Y = CombinatorialFreeModule(RR['q'],['z']) - sage: phi = Y.module_morphism( on_basis=on_basis, codomain=X ) + sage: Y = CombinatorialFreeModule(RR['q'], ['z']) # needs sage.modules + sage: phi = Y.module_morphism(on_basis=on_basis, codomain=X) # needs sage.modules Traceback (most recent call last): ... - ValueError: codomain(=Free module generated by {'x', 'y'} over Real Field with 53 bits of precision) - should be a module over the base ring of the - domain(=Free module generated by {'z'} over Univariate Polynomial Ring in q over Real Field with 53 bits of precision) + ValueError: codomain(=Free module generated by {'x', 'y'} + over Real Field with 53 bits of precision) should be a module over + the base ring of the domain(=Free module generated by {'z'} over + Univariate Polynomial Ring in q over Real Field with 53 bits of precision) With the ``diagonal=d`` argument, this constructs the @@ -422,7 +433,8 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, This assumes that the respective bases `x` and `y` of `X` and `Y` have the same index set `I`:: - sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") + sage: # needs sage.modules + sage: X = CombinatorialFreeModule(ZZ, [1, 2, 3]); X.rename("X") sage: from sage.arith.misc import factorial sage: phi = X.module_morphism(diagonal=factorial, codomain=X) sage: x = X.basis() @@ -435,9 +447,12 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, morphism whose matrix in the distinguished basis of `X` and `Y` is `m`:: - sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X"); x = X.basis() - sage: Y = CombinatorialFreeModule(ZZ, [3,4]); Y.rename("Y"); y = Y.basis() - sage: m = matrix([[0,1,2],[3,5,0]]) + sage: # needs sage.modules + sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") + sage: x = X.basis() + sage: Y = CombinatorialFreeModule(ZZ, [3,4]); Y.rename("Y") + sage: y = Y.basis() + sage: m = matrix([[0,1,2], [3,5,0]]) sage: phi = X.module_morphism(matrix=m, codomain=Y) sage: phi(x[1]) 3*B[4] @@ -453,11 +468,12 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, invertible elements on its diagonal. This is used to compute preimages and to invert the morphism:: + sage: # needs sage.modules sage: I = list(range(1, 200)) sage: X = CombinatorialFreeModule(QQ, I); X.rename("X"); x = X.basis() sage: Y = CombinatorialFreeModule(QQ, I); Y.rename("Y"); y = Y.basis() sage: f = Y.sum_of_monomials * divisors - sage: phi = X.module_morphism(f, triangular="upper", codomain = Y) + sage: phi = X.module_morphism(f, triangular="upper", codomain=Y) sage: phi(x[2]) B[1] + B[2] sage: phi(x[6]) @@ -476,10 +492,12 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, Since :trac:`8678`, one can also define a triangular morphism from a function:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, [0,1,2,3,4]); x = X.basis() sage: from sage.modules.with_basis.morphism import TriangularModuleMorphismFromFunction sage: def f(x): return x + X.term(0, sum(x.coefficients())) - sage: phi = X.module_morphism(function=f, codomain=X, triangular="upper") + sage: phi = X.module_morphism(function=f, codomain=X, + ....: triangular="upper") sage: phi(x[2] + 3*x[4]) 4*B[0] + B[2] + 3*B[4] sage: phi.preimage(_) @@ -505,8 +523,8 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, TESTS:: - sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") - sage: phi = X.module_morphism(codomain=X) + sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") # needs sage.modules + sage: phi = X.module_morphism(codomain=X) # needs sage.modules Traceback (most recent call last): ... ValueError: module_morphism() takes exactly one option @@ -514,8 +532,9 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, :: - sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") - sage: phi = X.module_morphism(diagonal=factorial, matrix=matrix(), codomain=X) + sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") # needs sage.modules + sage: phi = X.module_morphism(diagonal=factorial, matrix=matrix(), # needs sage.modules + ....: codomain=X) Traceback (most recent call last): ... ValueError: module_morphism() takes exactly one option @@ -523,16 +542,16 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, :: - sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") - sage: phi = X.module_morphism(matrix=factorial, codomain=X) + sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") # needs sage.modules + sage: phi = X.module_morphism(matrix=factorial, codomain=X) # needs sage.modules Traceback (most recent call last): ... ValueError: matrix (=...factorial...) should be a matrix :: - sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") - sage: phi = X.module_morphism(diagonal=3, codomain=X) + sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") # needs sage.modules + sage: phi = X.module_morphism(diagonal=3, codomain=X) # needs sage.modules Traceback (most recent call last): ... ValueError: diagonal (=3) should be a function @@ -571,20 +590,19 @@ def _repr_(self): """ EXAMPLES:: + sage: # needs sage.modules sage: class FooBar(CombinatorialFreeModule): pass - sage: C = FooBar(QQ, (1,2,3)); C # indirect doctest + sage: C = FooBar(QQ, (1,2,3)); C # indirect doctest Free module generated by {1, 2, 3} over Rational Field - sage: C._name = "foobar"; C foobar over Rational Field - sage: C.rename("barfoo"); C barfoo sage: class FooBar(Parent): - ....: def basis(self): return Family({1:"foo", 2:"bar"}) + ....: def basis(self): return Family({1: "foo", 2: "bar"}) ....: def base_ring(self): return QQ - sage: FooBar(category = ModulesWithBasis(QQ)) + sage: FooBar(category=ModulesWithBasis(QQ)) Free module generated by [1, 2] over Rational Field """ if hasattr(self, "_name"): @@ -608,9 +626,11 @@ def _compute_support_order(self, elements, support_order=None): A finite dimensional module:: + sage: # needs sage.modules sage: V = CombinatorialFreeModule(QQ, range(10), prefix='x') sage: B = V.basis() - sage: elts = [B[0] - 2*B[3], B[5] + 2*B[0], B[2], B[3], B[1] + B[2] + B[8]] + sage: elts = [B[0] - 2*B[3], B[5] + 2*B[0], + ....: B[2], B[3], B[1] + B[2] + B[8]] sage: V._compute_support_order(elts) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) sage: V._compute_support_order(elts, [1,2,0,4,3,5,9,8,7,6]) @@ -620,9 +640,11 @@ def _compute_support_order(self, elements, support_order=None): An infinite dimensional module:: + sage: # needs sage.modules sage: V = CombinatorialFreeModule(QQ, ZZ, prefix='z') sage: B = V.basis() - sage: elts = [B[0] - 2*B[3], B[5] + 2*B[0], B[2], B[3], B[1] + B[2] + B[8]] + sage: elts = [B[0] - 2*B[3], B[5] + 2*B[0], + ....: B[2], B[3], B[1] + B[2] + B[8]] sage: V._compute_support_order(elts) (0, 1, 2, 3, 5, 8) sage: V._compute_support_order(elts, [1,2,0,4,3,5,9,8,7,6]) @@ -672,17 +694,17 @@ def echelon_form(self, elements, row_reduced=False, order=None): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: C = CombinatorialFreeModule(R, ZZ, prefix='z') - sage: z = C.basis() - sage: C.echelon_form([z[0] - z[1], 2*z[1] - 2*z[2], z[0] - z[2]]) + sage: C = CombinatorialFreeModule(R, ZZ, prefix='z') # needs sage.modules + sage: z = C.basis() # needs sage.modules + sage: C.echelon_form([z[0] - z[1], 2*z[1] - 2*z[2], z[0] - z[2]]) # needs sage.libs.singular sage.modules [z[0] - z[2], z[1] - z[2]] TESTS: We convert the input elements to ``self``:: - sage: s = SymmetricFunctions(QQ).s() - sage: s.echelon_form([1, s[1] + 5]) + sage: s = SymmetricFunctions(QQ).s() # needs sage.combinat sage.modules + sage: s.echelon_form([1, s[1] + 5]) # needs sage.combinat sage.modules [s[], s[1]] """ # Make sure elements consists of elements of ``self`` @@ -751,6 +773,7 @@ def submodule(self, gens, check=True, already_echelonized=False, `x_0, x_1, x_2`. The submodule is spanned by `y_0 = x_0 - x_1` and `y_1 - x_1 - x_2`, and its basis elements are indexed by `0` and `1`:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() sage: gens = [x[0] - x[1], x[1] - x[2]]; gens @@ -763,7 +786,7 @@ def submodule(self, gens, check=True, already_echelonized=False, y[1] sage: y[1].lift() x[1] - x[2] - sage: Y.retract(x[0]-x[2]) + sage: Y.retract(x[0] - x[2]) y[0] + y[1] sage: Y.retract(x[0]) Traceback (most recent call last): @@ -773,9 +796,10 @@ def submodule(self, gens, check=True, already_echelonized=False, By using a family to specify a basis of the submodule, we obtain a submodule whose index set coincides with the index set of the family:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() - sage: gens = Family({1 : x[0] - x[1], 3: x[1] - x[2]}); gens + sage: gens = Family({1: x[0] - x[1], 3: x[1] - x[2]}); gens Finite family {1: x[0] - x[1], 3: x[1] - x[2]} sage: Y = X.submodule(gens, already_echelonized=True) sage: Y.print_options(prefix='y'); Y @@ -787,7 +811,7 @@ def submodule(self, gens, check=True, already_echelonized=False, x[0] - x[1] sage: y[3].lift() x[1] - x[2] - sage: Y.retract(x[0]-x[2]) + sage: Y.retract(x[0] - x[2]) y[1] + y[3] sage: Y.retract(x[0]) Traceback (most recent call last): @@ -797,6 +821,7 @@ def submodule(self, gens, check=True, already_echelonized=False, It is not necessary that the generators of the submodule form a basis (an explicit basis will be computed):: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() sage: gens = [x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]; gens @@ -811,14 +836,16 @@ def submodule(self, gens, check=True, already_echelonized=False, We now implement by hand the center of the algebra of the symmetric group `S_3`:: + sage: # needs sage.combinat sage.groups sage.modules sage: S3 = SymmetricGroup(3) sage: S3A = S3.algebra(QQ) - sage: basis = S3A.annihilator_basis(S3A.algebra_generators(), S3A.bracket) + sage: basis = S3A.annihilator_basis(S3A.algebra_generators(), + ....: S3A.bracket) sage: basis ((), (1,2,3) + (1,3,2), (2,3) + (1,2) + (1,3)) sage: center = S3A.submodule(basis, - ....: category=AlgebrasWithBasis(QQ).Subobjects(), - ....: already_echelonized=True) + ....: category=AlgebrasWithBasis(QQ).Subobjects(), + ....: already_echelonized=True) sage: center Free module generated by {0, 1, 2} over Rational Field sage: center in Algebras @@ -829,17 +856,18 @@ def submodule(self, gens, check=True, already_echelonized=False, (1,2,3) + (1,3,2) sage: c[0]^2 c[0] - sage: e = 1/6*(c[0]+c[1]+c[2]) + sage: e = 1/6 * (c[0]+c[1]+c[2]) sage: e.is_idempotent() True Of course, this center is best constructed using:: - sage: center = S3A.center() + sage: center = S3A.center() # needs sage.combinat sage.groups sage.modules We can also automatically construct a basis such that the lift morphism is (lower) unitriangular:: + sage: # needs sage.modules sage: R.<a,b> = QQ[] sage: C = CombinatorialFreeModule(R, range(3), prefix='x') sage: x = C.basis() @@ -853,6 +881,7 @@ def submodule(self, gens, check=True, already_echelonized=False, We now construct a (finite-dimensional) submodule of an infinite dimensional free module:: + sage: # needs sage.modules sage: C = CombinatorialFreeModule(QQ, ZZ, prefix='z') sage: z = C.basis() sage: gens = [z[0] - z[1], 2*z[1] - 2*z[2], z[0] - z[2]] @@ -862,8 +891,8 @@ def submodule(self, gens, check=True, already_echelonized=False, TESTS:: - sage: TestSuite(Y).run() - sage: TestSuite(center).run() + sage: TestSuite(Y).run() # needs sage.modules + sage: TestSuite(center).run() # needs sage.combinat sage.groups sage.modules """ # Make sure gens consists of elements of ``self`` from sage.sets.family import Family, AbstractFamily @@ -906,9 +935,11 @@ def quotient_module(self, submodule, check=True, already_echelonized=False, cate EXAMPLES:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() - sage: Y = X.quotient_module([x[0]-x[1], x[1]-x[2]], already_echelonized=True) + sage: Y = X.quotient_module([x[0] - x[1], x[1] - x[2]], + ....: already_echelonized=True) sage: Y.print_options(prefix='y'); Y Free module generated by {2} over Rational Field sage: y = Y.basis() @@ -916,9 +947,10 @@ def quotient_module(self, submodule, check=True, already_echelonized=False, cate y[2] sage: y[2].lift() x[2] - sage: Y.retract(x[0]+2*x[1]) + sage: Y.retract(x[0] + 2*x[1]) 3*y[2] + sage: # needs sage.modules sage: R.<a,b> = QQ[] sage: C = CombinatorialFreeModule(R, range(3), prefix='x') sage: x = C.basis() @@ -945,10 +977,10 @@ def tensor(*parents, **kwargs): EXAMPLES:: sage: C = AlgebrasWithBasis(QQ) - sage: A = C.example(); A.rename("A") - sage: A.tensor(A,A) + sage: A = C.example(); A.rename("A") # needs sage.combinat sage.modules + sage: A.tensor(A, A) # needs sage.combinat sage.modules A # A # A - sage: A.rename(None) + sage: A.rename(None) # needs sage.combinat sage.modules """ constructor = kwargs.pop('constructor', tensor) cat = constructor.category_from_parents(parents) @@ -960,15 +992,17 @@ def cardinality(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: S = SymmetricGroupAlgebra(QQ, 4) sage: S.cardinality() +Infinity - sage: S = SymmetricGroupAlgebra(GF(2), 4) # not tested -- MRO bug trac #15475 - sage: S.cardinality() # not tested -- MRO bug trac #15475 + sage: S = SymmetricGroupAlgebra(GF(2), 4) # not tested + sage: S.cardinality() # not tested 16777216 - sage: S.cardinality().factor() # not tested -- MRO bug trac #15475 + sage: S.cardinality().factor() # not tested 2^24 + sage: # needs sage.modules sage: E.<x,y> = ExteriorAlgebra(QQ) sage: E.cardinality() +Infinity @@ -976,8 +1010,8 @@ def cardinality(self): sage: E.cardinality() 81 - sage: s = SymmetricFunctions(GF(2)).s() - sage: s.cardinality() + sage: s = SymmetricFunctions(GF(2)).s() # needs sage.combinat sage.modules + sage: s.cardinality() # needs sage.combinat sage.modules +Infinity """ from sage.rings.infinity import Infinity @@ -994,11 +1028,11 @@ def is_finite(self): EXAMPLES:: - sage: GroupAlgebra(SymmetricGroup(2), IntegerModRing(10)).is_finite() + sage: GroupAlgebra(SymmetricGroup(2), IntegerModRing(10)).is_finite() # needs sage.combinat sage.groups sage.modules True - sage: GroupAlgebra(SymmetricGroup(2)).is_finite() + sage: GroupAlgebra(SymmetricGroup(2)).is_finite() # needs sage.combinat sage.groups sage.modules False - sage: GroupAlgebra(AbelianGroup(1), IntegerModRing(10)).is_finite() + sage: GroupAlgebra(AbelianGroup(1), IntegerModRing(10)).is_finite() # needs sage.groups sage.modules False """ return (self.base_ring().is_finite() and self.group().is_finite()) @@ -1013,14 +1047,15 @@ def monomial(self, i): EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) - sage: F.monomial('a') + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) # needs sage.modules + sage: F.monomial('a') # needs sage.modules B['a'] ``F.monomial`` is in fact (almost) a map:: - sage: F.monomial - Term map from {'a', 'b', 'c'} to Free module generated by {'a', 'b', 'c'} over Rational Field + sage: F.monomial # needs sage.modules + Term map from {'a', 'b', 'c'} + to Free module generated by {'a', 'b', 'c'} over Rational Field """ return self.basis()[i] @@ -1029,8 +1064,8 @@ def _sum_of_monomials(self, indices): TESTS:: sage: R.<x,y> = QQ[] - sage: W = DifferentialWeylAlgebra(R) - sage: W._sum_of_monomials([((1,0), (1,0)), ((0,0), (0,1))]) + sage: W = DifferentialWeylAlgebra(R) # needs sage.modules + sage: W._sum_of_monomials([((1,0), (1,0)), ((0,0), (0,1))]) # needs sage.modules dy + x*dx """ # This is the generic implementation. When implementing a @@ -1051,16 +1086,16 @@ def sum_of_monomials(self): EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) - sage: F.sum_of_monomials(['a', 'b']) + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) # needs sage.modules + sage: F.sum_of_monomials(['a', 'b']) # needs sage.modules B['a'] + B['b'] - sage: F.sum_of_monomials(['a', 'b', 'a']) + sage: F.sum_of_monomials(['a', 'b', 'a']) # needs sage.modules 2*B['a'] + B['b'] ``F.sum_of_monomials`` is in fact (almost) a map:: - sage: F.sum_of_monomials + sage: F.sum_of_monomials # needs sage.modules A map to Free module generated by {'a', 'b', 'c'} over Rational Field """ # domain = iterables of basis indices of self. @@ -1070,10 +1105,10 @@ def monomial_or_zero_if_none(self, i): """ EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) - sage: F.monomial_or_zero_if_none('a') + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) # needs sage.modules + sage: F.monomial_or_zero_if_none('a') # needs sage.modules B['a'] - sage: F.monomial_or_zero_if_none(None) + sage: F.monomial_or_zero_if_none(None) # needs sage.modules 0 """ if i is None: @@ -1095,9 +1130,9 @@ def term(self, index, coeff=None): EXAMPLES:: - sage: m = matrix([[0,1],[1,1]]) - sage: J.<a,b,c> = JordanAlgebra(m) - sage: J.term(1, -2) + sage: m = matrix([[0,1], [1,1]]) # needs sage.modules + sage: J.<a,b,c> = JordanAlgebra(m) # needs sage.combinat sage.modules + sage: J.term(1, -2) # needs sage.combinat sage.modules 0 + (-2, 0) Design: should this do coercion on the coefficient ring? @@ -1121,9 +1156,9 @@ def sum_of_terms(self, terms): EXAMPLES:: - sage: m = matrix([[0,1],[1,1]]) - sage: J.<a,b,c> = JordanAlgebra(m) - sage: J.sum_of_terms([(0, 2), (2, -3)]) + sage: m = matrix([[0,1], [1,1]]) # needs sage.modules + sage: J.<a,b,c> = JordanAlgebra(m) # needs sage.combinat sage.modules + sage: J.sum_of_terms([(0, 2), (2, -3)]) # needs sage.combinat sage.modules 2 + (0, -3) """ return self.sum(self.term(index, coeff) for (index, coeff) in terms) @@ -1150,13 +1185,14 @@ def _apply_module_morphism(self, x, on_basis, codomain=False): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: s = SymmetricFunctions(QQ).schur() sage: a = s([3]) + s([2,1]) + s([1,1,1]) sage: b = 2*a - sage: f = lambda part: Integer( len(part) ) - sage: s._apply_module_morphism(a, f) #1+2+3 + sage: f = lambda part: Integer(len(part)) + sage: s._apply_module_morphism(a, f) #1+2+3 6 - sage: s._apply_module_morphism(b, f) #2*(1+2+3) + sage: s._apply_module_morphism(b, f) #2*(1+2+3) 12 sage: s._apply_module_morphism(s(0), f) 0 @@ -1206,9 +1242,9 @@ def _apply_module_endomorphism(self, x, on_basis): EXAMPLES:: - sage: s = SymmetricFunctions(QQ).schur() - sage: f = lambda part: 2*s(part.conjugate()) - sage: s._apply_module_endomorphism( s([2,1]) + s([1,1,1]), f) + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = lambda part: 2 * s(part.conjugate()) + sage: s._apply_module_endomorphism(s([2,1]) + s([1,1,1]), f) # needs sage.combinat sage.modules 2*s[2, 1] + 2*s[3] """ mc = x.monomial_coefficients(copy=False) @@ -1221,8 +1257,8 @@ def dimension(self): EXAMPLES:: - sage: A.<x,y> = algebras.DifferentialWeyl(QQ) - sage: A.dimension() + sage: A.<x,y> = algebras.DifferentialWeyl(QQ) # needs sage.modules + sage: A.dimension() # needs sage.modules +Infinity """ try: @@ -1242,6 +1278,7 @@ def _from_dict(self, d, coerce=True, remove_zeros=True): EXAMPLES:: + sage: # needs sage.modules sage: A.<x,y> = algebras.DifferentialWeyl(QQ) sage: K = A.basis().keys() sage: d = {K[0]: 3, K[12]: -4/3} @@ -1249,10 +1286,10 @@ def _from_dict(self, d, coerce=True, remove_zeros=True): -4/3*dx^2 + 3 sage: R.<x,y> = QQ[] - sage: d = {K[0]: y, K[12]: -4/3} - sage: A._from_dict(d, coerce=False) + sage: d = {K[0]: y, K[12]: -4/3} # needs sage.modules + sage: A._from_dict(d, coerce=False) # needs sage.modules -4/3*dx^2 + y - sage: A._from_dict(d, coerce=True) + sage: A._from_dict(d, coerce=True) # needs sage.modules Traceback (most recent call last): ... TypeError: not a constant polynomial @@ -1291,21 +1328,21 @@ def random_element(self, n=2): EXAMPLES:: - sage: x = DihedralGroup(6).algebra(QQ).random_element() - sage: x.parent() is DihedralGroup(6).algebra(QQ) + sage: x = DihedralGroup(6).algebra(QQ).random_element() # needs sage.groups sage.modules + sage: x.parent() is DihedralGroup(6).algebra(QQ) # needs sage.groups sage.modules True Note, this result can depend on the PRNG state in libgap in a way that depends on which packages are loaded, so we must re-seed GAP to ensure a consistent result for this example:: - sage: libgap.set_seed(0) + sage: libgap.set_seed(0) # needs sage.libs.gap 0 - sage: m = SU(2, 13).algebra(QQ).random_element(1) - sage: m.parent() is SU(2, 13).algebra(QQ) + sage: m = SU(2, 13).algebra(QQ).random_element(1) # needs sage.groups sage.libs.pari sage.modules + sage: m.parent() is SU(2, 13).algebra(QQ) # needs sage.groups sage.libs.pari sage.modules True - sage: p = CombinatorialFreeModule(ZZ, Partitions(4)).random_element() - sage: p.parent() is CombinatorialFreeModule(ZZ, Partitions(4)) + sage: p = CombinatorialFreeModule(ZZ, Partitions(4)).random_element() # needs sage.combinat sage.modules + sage: p.parent() is CombinatorialFreeModule(ZZ, Partitions(4)) # needs sage.combinat sage.modules True TESTS: @@ -1315,17 +1352,16 @@ def random_element(self, n=2): coerce the base ring's zero into the algebra, and that we can find a random element in a trivial module:: - sage: class Foo(CombinatorialFreeModule): + sage: class Foo(CombinatorialFreeModule): # needs sage.modules ....: def _element_constructor_(self,x): ....: if x in self: ....: return x ....: else: ....: raise ValueError - sage: from sage.categories.magmatic_algebras \ - ....: import MagmaticAlgebras + sage: from sage.categories.magmatic_algebras import MagmaticAlgebras sage: C = MagmaticAlgebras(QQ).WithBasis().Unital() - sage: F = Foo(QQ, tuple(), category=C) - sage: F.random_element() == F.zero() + sage: F = Foo(QQ, tuple(), category=C) # needs sage.modules + sage: F.random_element() == F.zero() # needs sage.modules True """ @@ -1365,6 +1401,7 @@ def monomial_coefficients(self, copy=True): EXAMPLES:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: B = F.basis() sage: f = B['a'] + 3*B['c'] @@ -1378,6 +1415,7 @@ def monomial_coefficients(self, copy=True): We check that we make a copy of the coefficient dictionary:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(ZZ, ['a','b','c']) sage: B = F.basis() sage: f = B['a'] + 3*B['c'] @@ -1393,10 +1431,10 @@ def __getitem__(self, m): EXAMPLES:: - sage: W.<x,y,z> = DifferentialWeylAlgebra(QQ) - sage: x[((0,0,0),(0,0,0))] + sage: W.<x,y,z> = DifferentialWeylAlgebra(QQ) # needs sage.modules + sage: x[((0,0,0), (0,0,0))] # needs sage.modules 0 - sage: x[((1,0,0),(0,0,0))] + sage: x[((1,0,0), (0,0,0))] # needs sage.modules 1 """ res = self.monomial_coefficients(copy=False).get(m) @@ -1422,6 +1460,7 @@ def coefficient(self, m): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: s = CombinatorialFreeModule(QQ, Partitions()) sage: z = s([4]) - 2*s([2,1]) + s([1,1,1]) + s([1]) sage: z.coefficient([4]) @@ -1442,6 +1481,7 @@ def coefficient(self, m): Test that ``coefficient`` also works for those parents that do not have an ``element_class``:: + sage: # needs sage.modules sage.rings.padics sage: H = pAdicWeightSpace(3) sage: F = CombinatorialFreeModule(QQ, H) sage: hasattr(H, "element_class") @@ -1454,7 +1494,7 @@ def coefficient(self, m): # that can be turned on or off C = self.parent().basis().keys() # TODO: This should raise a ValueError - TS - assert m in C, "%s should be an element of %s"%(m, C) + assert m in C, "%s should be an element of %s" % (m, C) if hasattr(C, "element_class") and not isinstance(m, C.element_class): m = C(m) return self[m] @@ -1465,6 +1505,7 @@ def is_zero(self): EXAMPLES:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: B = F.basis() sage: f = B['a'] - 3*B['c'] @@ -1475,6 +1516,7 @@ def is_zero(self): :: + sage: # needs sage.combinat sage.modules sage: s = SymmetricFunctions(QQ).schur() sage: s([2,1]).is_zero() False @@ -1493,6 +1535,7 @@ def __len__(self): EXAMPLES:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: B = F.basis() sage: f = B['a'] - 3*B['c'] @@ -1501,9 +1544,9 @@ def __len__(self): :: - sage: s = SymmetricFunctions(QQ).schur() - sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) - sage: len(z) + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) # needs sage.combinat sage.modules + sage: len(z) # needs sage.combinat sage.modules 4 """ return len(self.support()) @@ -1515,6 +1558,7 @@ def length(self): EXAMPLES:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: B = F.basis() sage: f = B['a'] - 3*B['c'] @@ -1523,9 +1567,9 @@ def length(self): :: - sage: s = SymmetricFunctions(QQ).schur() - sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) - sage: z.length() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) # needs sage.combinat sage.modules + sage: z.length() # needs sage.combinat sage.modules 4 """ return len(self) @@ -1540,6 +1584,7 @@ def support(self): EXAMPLES:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: B = F.basis() sage: f = B['a'] - 3*B['c'] @@ -1548,9 +1593,9 @@ def support(self): :: - sage: s = SymmetricFunctions(QQ).schur() - sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) - sage: sorted(z.support()) + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) # needs sage.combinat sage.modules + sage: sorted(z.support()) # needs sage.combinat sage.modules [[1], [1, 1, 1], [2, 1], [4]] """ try: @@ -1578,13 +1623,14 @@ def monomials(self): EXAMPLES:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: B = F.basis() sage: f = B['a'] + 2*B['c'] sage: f.monomials() [B['a'], B['c']] - sage: (F.zero()).monomials() + sage: (F.zero()).monomials() # needs sage.modules [] """ P = self.parent() @@ -1599,6 +1645,7 @@ def terms(self): EXAMPLES:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: B = F.basis() sage: f = B['a'] + 2*B['c'] @@ -1627,6 +1674,7 @@ def coefficients(self, sort=True): EXAMPLES:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: B = F.basis() sage: f = B['a'] - 3*B['c'] @@ -1638,9 +1686,9 @@ def coefficients(self, sort=True): :: - sage: s = SymmetricFunctions(QQ).schur() - sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) - sage: z.coefficients() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) # needs sage.combinat sage.modules + sage: z.coefficients() # needs sage.combinat sage.modules [1, 1, 1, 1] """ zero = self.parent().base_ring().zero() @@ -1659,15 +1707,15 @@ def support_of_term(self): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, [1,2,3,4]); X.rename("X") - sage: X.monomial(2).support_of_term() + sage: X = CombinatorialFreeModule(QQ, [1,2,3,4]); X.rename("X") # needs sage.modules + sage: X.monomial(2).support_of_term() # needs sage.modules 2 - sage: X.term(3, 2).support_of_term() + sage: X.term(3, 2).support_of_term() # needs sage.modules 3 An exception is raised if ``self`` has more than one term:: - sage: (X.monomial(2) + X.monomial(3)).support_of_term() + sage: (X.monomial(2) + X.monomial(3)).support_of_term() # needs sage.modules Traceback (most recent call last): ... ValueError: B[2] + B[3] is not a single term @@ -1689,6 +1737,7 @@ def leading_support(self, *args, **kwds): EXAMPLES:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]) sage: X.rename("X"); x = X.basis() sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3) @@ -1698,9 +1747,9 @@ def leading_support(self, *args, **kwds): sage: x.leading_support(key=key) 1 - sage: s = SymmetricFunctions(QQ).schur() - sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] - sage: f.leading_support() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules + sage: f.leading_support() # needs sage.combinat sage.modules [3] """ return max(self.support(), *args, **kwds) @@ -1724,7 +1773,8 @@ def leading_item(self, *args, **kwds): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() + sage: # needs sage.modules + sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X") sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3) sage: x.leading_item() (3, 4) @@ -1732,9 +1782,9 @@ def leading_item(self, *args, **kwds): sage: x.leading_item(key=key) (1, 3) - sage: s = SymmetricFunctions(QQ).schur() - sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] - sage: f.leading_item() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules + sage: f.leading_item() # needs sage.combinat sage.modules ([3], -5) """ k = self.leading_support(*args, **kwds) @@ -1753,7 +1803,8 @@ def leading_monomial(self, *args, **kwds): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() + sage: # needs sage.modules + sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X") sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) sage: x.leading_monomial() B[3] @@ -1761,9 +1812,9 @@ def leading_monomial(self, *args, **kwds): sage: x.leading_monomial(key=key) B[1] - sage: s = SymmetricFunctions(QQ).schur() - sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] - sage: f.leading_monomial() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules + sage: f.leading_monomial() # needs sage.combinat sage.modules s[3] """ return self.parent().monomial(self.leading_support(*args, **kwds)) @@ -1781,6 +1832,7 @@ def leading_coefficient(self, *args, **kwds): EXAMPLES:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X") sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) sage: x.leading_coefficient() @@ -1789,9 +1841,9 @@ def leading_coefficient(self, *args, **kwds): sage: x.leading_coefficient(key=key) 3 - sage: s = SymmetricFunctions(QQ).schur() - sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] - sage: f.leading_coefficient() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules + sage: f.leading_coefficient() # needs sage.combinat sage.modules -5 """ return self.leading_item(*args, **kwds)[1] @@ -1809,7 +1861,8 @@ def leading_term(self, *args, **kwds): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() + sage: # needs sage.modules + sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X") sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) sage: x.leading_term() B[3] @@ -1817,9 +1870,9 @@ def leading_term(self, *args, **kwds): sage: x.leading_term(key=key) 3*B[1] - sage: s = SymmetricFunctions(QQ).schur() - sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] - sage: f.leading_term() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules + sage: f.leading_term() # needs sage.combinat sage.modules -5*s[3] """ return self.parent().term(*self.leading_item(*args, **kwds)) @@ -1835,18 +1888,18 @@ def trailing_support(self, *args, **kwds): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() - sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3) - sage: x.trailing_support() + sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X") # needs sage.modules + sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3) # needs sage.modules + sage: x.trailing_support() # needs sage.modules 1 sage: def key(x): return -x - sage: x.trailing_support(key=key) + sage: x.trailing_support(key=key) # needs sage.modules 3 - sage: s = SymmetricFunctions(QQ).schur() - sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] - sage: f.trailing_support() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules + sage: f.trailing_support() # needs sage.combinat sage.modules [1] """ return min(self.support(), *args, **kwds) @@ -1865,7 +1918,8 @@ def trailing_item(self, *args, **kwds): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() + sage: # needs sage.modules + sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X") sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) sage: x.trailing_item() (1, 3) @@ -1873,9 +1927,9 @@ def trailing_item(self, *args, **kwds): sage: x.trailing_item(key=key) (3, 1) - sage: s = SymmetricFunctions(QQ).schur() - sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] - sage: f.trailing_item() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules + sage: f.trailing_item() # needs sage.combinat sage.modules ([1], 2) """ k = self.trailing_support(*args, **kwds) @@ -1894,7 +1948,8 @@ def trailing_monomial(self, *args, **kwds): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() + sage: # needs sage.modules + sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X") sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) sage: x.trailing_monomial() B[1] @@ -1902,9 +1957,9 @@ def trailing_monomial(self, *args, **kwds): sage: x.trailing_monomial(key=key) B[3] - sage: s = SymmetricFunctions(QQ).schur() - sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] - sage: f.trailing_monomial() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules + sage: f.trailing_monomial() # needs sage.combinat sage.modules s[1] """ return self.parent().monomial(self.trailing_support(*args, **kwds)) @@ -1922,7 +1977,8 @@ def trailing_coefficient(self, *args, **kwds): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() + sage: # needs sage.modules + sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X") sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) sage: x.trailing_coefficient() 3 @@ -1930,9 +1986,9 @@ def trailing_coefficient(self, *args, **kwds): sage: x.trailing_coefficient(key=key) 1 - sage: s = SymmetricFunctions(QQ).schur() - sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] - sage: f.trailing_coefficient() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules + sage: f.trailing_coefficient() # needs sage.combinat sage.modules 2 """ return self.trailing_item(*args, **kwds)[1] @@ -1950,7 +2006,8 @@ def trailing_term(self, *args, **kwds): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() + sage: # needs sage.modules + sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X") sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) sage: x.trailing_term() 3*B[1] @@ -1958,9 +2015,9 @@ def trailing_term(self, *args, **kwds): sage: x.trailing_term(key=key) B[3] - sage: s = SymmetricFunctions(QQ).schur() - sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] - sage: f.trailing_term() + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules + sage: f.trailing_term() # needs sage.combinat sage.modules 2*s[1] """ return self.parent().term(*self.trailing_item(*args, **kwds)) @@ -1979,24 +2036,25 @@ def map_coefficients(self, f): EXAMPLES:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: B = F.basis() sage: f = B['a'] - 3*B['c'] - sage: f.map_coefficients(lambda x: x+5) + sage: f.map_coefficients(lambda x: x + 5) 6*B['a'] + 2*B['c'] Killed coefficients are handled properly:: - sage: f.map_coefficients(lambda x: 0) + sage: f.map_coefficients(lambda x: 0) # needs sage.modules 0 - sage: list(f.map_coefficients(lambda x: 0)) + sage: list(f.map_coefficients(lambda x: 0)) # needs sage.modules [] :: - sage: s = SymmetricFunctions(QQ).schur() - sage: a = s([2,1])+2*s([3,2]) - sage: a.map_coefficients(lambda x: x*2) + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: a = s([2,1]) + 2*s([3,2]) # needs sage.combinat sage.modules + sage: a.map_coefficients(lambda x: x * 2) # needs sage.combinat sage.modules 2*s[2, 1] + 4*s[3, 2] """ return self.parent().sum_of_terms( (m, f(c)) for m,c in self ) @@ -2015,30 +2073,30 @@ def map_support(self, f): EXAMPLES:: - sage: B = CombinatorialFreeModule(ZZ, [-1, 0, 1]) - sage: x = B.an_element(); x + sage: B = CombinatorialFreeModule(ZZ, [-1, 0, 1]) # needs sage.modules + sage: x = B.an_element(); x # needs sage.modules 2*B[-1] + 2*B[0] + 3*B[1] - sage: x.map_support(lambda i: -i) + sage: x.map_support(lambda i: -i) # needs sage.modules 3*B[-1] + 2*B[0] + 2*B[1] ``f`` needs not be injective:: - sage: x.map_support(lambda i: 1) + sage: x.map_support(lambda i: 1) # needs sage.modules 7*B[1] - sage: s = SymmetricFunctions(QQ).schur() - sage: a = s([2,1])+2*s([3,2]) - sage: a.map_support(lambda x: x.conjugate()) + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: a = s([2,1]) + 2*s([3,2]) # needs sage.combinat sage.modules + sage: a.map_support(lambda x: x.conjugate()) # needs sage.combinat sage.modules s[2, 1] + 2*s[2, 2, 1] TESTS:: - sage: B.zero() # This actually failed at some point!!! See #8890 + sage: B.zero() # This actually failed at some point!!! See #8890 # needs sage.modules 0 - sage: y = B.zero().map_support(lambda i: i/0); y + sage: y = B.zero().map_support(lambda i: i/0); y # needs sage.modules 0 - sage: y.parent() is B + sage: y.parent() is B # needs sage.modules True """ return self.parent().sum_of_terms( (f(m), c) for m,c in self ) @@ -2057,22 +2115,22 @@ def map_support_skip_none(self, f): EXAMPLES:: - sage: B = CombinatorialFreeModule(ZZ, [-1, 0, 1]) - sage: x = B.an_element(); x + sage: B = CombinatorialFreeModule(ZZ, [-1, 0, 1]) # needs sage.modules + sage: x = B.an_element(); x # needs sage.modules 2*B[-1] + 2*B[0] + 3*B[1] - sage: x.map_support_skip_none(lambda i: -i if i else None) + sage: x.map_support_skip_none(lambda i: -i if i else None) # needs sage.modules 3*B[-1] + 2*B[1] ``f`` needs not be injective:: - sage: x.map_support_skip_none(lambda i: 1 if i else None) + sage: x.map_support_skip_none(lambda i: 1 if i else None) # needs sage.modules 5*B[1] TESTS:: - sage: y = x.map_support_skip_none(lambda i: None); y + sage: y = x.map_support_skip_none(lambda i: None); y # needs sage.modules 0 - sage: y.parent() is B + sage: y.parent() is B # needs sage.modules True """ return self.parent().sum_of_terms( (fm,c) for (fm,c) in ((f(m), c) for m,c in self) if fm is not None) @@ -2092,21 +2150,21 @@ def map_item(self, f): EXAMPLES:: - sage: B = CombinatorialFreeModule(ZZ, [-1, 0, 1]) - sage: x = B.an_element(); x + sage: B = CombinatorialFreeModule(ZZ, [-1, 0, 1]) # needs sage.modules + sage: x = B.an_element(); x # needs sage.modules 2*B[-1] + 2*B[0] + 3*B[1] - sage: x.map_item(lambda i, c: (-i, 2*c)) + sage: x.map_item(lambda i, c: (-i, 2*c)) # needs sage.modules 6*B[-1] + 4*B[0] + 4*B[1] ``f`` needs not be injective:: - sage: x.map_item(lambda i, c: (1, 2*c)) + sage: x.map_item(lambda i, c: (1, 2*c)) # needs sage.modules 14*B[1] - sage: s = SymmetricFunctions(QQ).schur() - sage: f = lambda m,c: (m.conjugate(), 2*c) - sage: a = s([2,1]) + s([1,1,1]) - sage: a.map_item(f) + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat sage.modules + sage: f = lambda m, c: (m.conjugate(), 2 * c) + sage: a = s([2,1]) + s([1,1,1]) # needs sage.combinat sage.modules + sage: a.map_item(f) # needs sage.combinat sage.modules 2*s[2, 1] + 2*s[3] """ return self.parent().sum_of_terms( f(m,c) for m,c in self ) @@ -2119,9 +2177,9 @@ def tensor(*elements): EXAMPLES:: sage: C = AlgebrasWithBasis(QQ) - sage: A = C.example() - sage: (a,b,c) = A.algebra_generators() - sage: a.tensor(b, c) + sage: A = C.example() # needs sage.combinat sage.modules + sage: a, b, c = A.algebra_generators() # needs sage.combinat sage.modules + sage: a.tensor(b, c) # needs sage.combinat sage.modules B[word: a] # B[word: b] # B[word: c] FIXME: is this a policy that we want to enforce on all parents? @@ -2151,26 +2209,30 @@ def __call_on_basis__(self, **options): EXAMPLES:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, [1,2,3]); X.rename("X") sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4]); Y.rename("Y") sage: H = Hom(X, Y) sage: x = X.basis() - - sage: phi = H(on_basis = lambda i: Y.monomial(i) + 2*Y.monomial(i+1)) # indirect doctest + sage: def on_basis(i): + ....: return Y.monomial(i) + 2*Y.monomial(i + 1) + sage: phi = H(on_basis=on_basis) # indirect doctest sage: phi Generic morphism: - From: X - To: Y + From: X + To: Y sage: phi(x[1] + x[3]) B[1] + 2*B[2] + B[3] + 2*B[4] Diagonal functions can be constructed using the ``diagonal`` option:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, [1,2,3,4]); X.rename("X") - sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4], key="Y"); Y.rename("Y") + sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4], + ....: key="Y"); Y.rename("Y") sage: H = Hom(X, Y) sage: x = X.basis() - sage: phi = H(diagonal = lambda x: x^2) + sage: phi = H(diagonal=lambda x: x^2) sage: phi(x[1] + x[2] + x[3]) B[1] + 4*B[2] + 9*B[3] @@ -2178,16 +2240,16 @@ def __call_on_basis__(self, **options): As for usual homsets, the argument can be a Python function:: - sage: phi = H(lambda x: Y.zero()) - sage: phi + sage: phi = H(lambda x: Y.zero()); phi # needs sage.modules Generic morphism: From: X To: Y - sage: phi(x[1] + x[3]) + sage: phi(x[1] + x[3]) # needs sage.modules 0 We check that the homset category is properly set up:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, [1,2,3]); X.rename("X") sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4]); Y.rename("Y") sage: H = Hom(X, Y) @@ -2210,17 +2272,16 @@ def on_basis(self): EXAMPLES:: + sage: # needs sage.modules sage: X = CombinatorialFreeModule(QQ, [1,2,3]); X.rename("X") sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4]); Y.rename("Y") sage: H = Hom(X, Y) sage: x = X.basis() - sage: f = H(lambda x: Y.zero()).on_basis() sage: f(2) 0 - sage: f = lambda i: Y.monomial(i) + 2*Y.monomial(i+1) - sage: g = H(on_basis = f).on_basis() + sage: g = H(on_basis=f).on_basis() sage: g(2) B[2] + 2*B[3] sage: g == f @@ -2238,9 +2299,9 @@ def _on_basis(self, i): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, [1,2,3]); X.rename("X") - sage: phi = End(X)(lambda x: 2*x) - sage: phi._on_basis(3) + sage: X = CombinatorialFreeModule(QQ, [1,2,3]); X.rename("X") # needs sage.modules + sage: phi = End(X)(lambda x: 2*x) # needs sage.modules + sage: phi._on_basis(3) # needs sage.modules 2*B[3] """ return self(self.domain().monomial(i)) @@ -2270,15 +2331,21 @@ def _an_element_(self): """ EXAMPLES:: + sage: # needs sage.combinat sage.groups sage.modules sage: A = AlgebrasWithBasis(QQ).example(); A - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field + An example of an algebra with basis: + the free algebra on the generators ('a', 'b', 'c') + over Rational Field sage: B = HopfAlgebrasWithBasis(QQ).example(); B - An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field + An example of Hopf algebra with basis: + the group algebra of the Dihedral group of order 6 + as a permutation group over Rational Field sage: A.an_element() B[word: ] + 2*B[word: a] + 3*B[word: b] + B[word: bab] sage: B.an_element() B[()] + B[(1,2)] + 3*B[(1,2,3)] + 2*B[(1,3,2)] - sage: cartesian_product((A, B, A)).an_element() # indirect doctest + sage: ABA = cartesian_product((A, B, A)) + sage: ABA.an_element() # indirect doctest 2*B[(0, word: )] + 2*B[(0, word: a)] + 3*B[(0, word: b)] """ from .cartesian_product import cartesian_product @@ -2341,8 +2408,11 @@ def apply_multilinear_morphism(self, f, codomain=None): We start with simple (admittedly not so interesting) examples, with two modules `A` and `B`:: - sage: A = CombinatorialFreeModule(ZZ, [1,2], prefix="A"); A.rename("A") - sage: B = CombinatorialFreeModule(ZZ, [3,4], prefix="B"); B.rename("B") + sage: # needs sage.modules + sage: A = CombinatorialFreeModule(ZZ, [1,2], prefix="A") + sage: A.rename("A") + sage: B = CombinatorialFreeModule(ZZ, [3,4], prefix="B") + sage: B.rename("B") and `f` the bilinear morphism `(a,b) \mapsto b \otimes a` from `A \times B` to `B \otimes A`:: @@ -2353,23 +2423,24 @@ def apply_multilinear_morphism(self, f, codomain=None): Now, calling applying `f` on `a \otimes b` returns the same as `f(a,b)`:: + sage: # needs sage.modules sage: a = A.monomial(1) + 2 * A.monomial(2); a A[1] + 2*A[2] sage: b = B.monomial(3) - 2 * B.monomial(4); b B[3] - 2*B[4] - sage: f(a,b) + sage: f(a, b) B[3] # A[1] + 2*B[3] # A[2] - 2*B[4] # A[1] - 4*B[4] # A[2] - sage: tensor([a,b]).apply_multilinear_morphism(f) + sage: tensor([a, b]).apply_multilinear_morphism(f) B[3] # A[1] + 2*B[3] # A[2] - 2*B[4] # A[1] - 4*B[4] # A[2] `f` may be a bilinear morphism to any module over the base ring of `A` and `B`. Here the codomain is `\ZZ`:: - sage: def f(a,b): + sage: def f(a, b): ....: return sum(a.coefficients(), 0) * sum(b.coefficients(), 0) - sage: f(a,b) + sage: f(a, b) # needs sage.modules -3 - sage: tensor([a,b]).apply_multilinear_morphism(f) + sage: tensor([a, b]).apply_multilinear_morphism(f) # needs sage.modules -3 Mind the `0` in the sums above; otherwise `f` would @@ -2377,12 +2448,12 @@ def apply_multilinear_morphism(self, f, codomain=None): sage: def f(a,b): ....: return sum(a.coefficients()) * sum(b.coefficients()) - sage: type(f(A.zero(), B.zero())) + sage: type(f(A.zero(), B.zero())) # needs sage.modules <... 'int'> Which would be wrong and break this method:: - sage: tensor([a,b]).apply_multilinear_morphism(f) + sage: tensor([a, b]).apply_multilinear_morphism(f) # needs sage.modules Traceback (most recent call last): ... AttributeError: 'int' object has no attribute 'parent' @@ -2390,12 +2461,15 @@ def apply_multilinear_morphism(self, f, codomain=None): Here we consider an example where the codomain is a module with basis with a different base ring:: - sage: C = CombinatorialFreeModule(QQ, [(1,3),(2,4)], prefix="C"); C.rename("C") - sage: def f(a,b): - ....: return C.sum_of_terms( [((1,3), QQ(a[1]*b[3])), ((2,4), QQ(a[2]*b[4]))] ) + sage: # needs sage.modules + sage: C = CombinatorialFreeModule(QQ, [(1,3),(2,4)], prefix="C") + sage: C.rename("C") + sage: def f(a, b): + ....: return C.sum_of_terms([((1,3), QQ(a[1]*b[3])), + ....: ((2,4), QQ(a[2]*b[4]))]) sage: f(a,b) C[(1, 3)] - 4*C[(2, 4)] - sage: tensor([a,b]).apply_multilinear_morphism(f) + sage: tensor([a, b]).apply_multilinear_morphism(f) C[(1, 3)] - 4*C[(2, 4)] We conclude with a real life application, where we @@ -2403,10 +2477,11 @@ def apply_multilinear_morphism(self, f, codomain=None): Symmetric functions on the Schur basis satisfies its defining formula:: + sage: # needs lrcalc_python sage.combinat sage.modules sage: Sym = SymmetricFunctions(QQ) sage: s = Sym.schur() - sage: def f(a,b): return a*b.antipode() - sage: x = 4*s.an_element(); x + sage: def f(a, b): return a * b.antipode() + sage: x = 4 * s.an_element(); x 8*s[] + 8*s[1] + 12*s[2] sage: x.coproduct().apply_multilinear_morphism(f) 8*s[] @@ -2445,6 +2520,7 @@ def extra_super_categories(self): sage: ModulesWithBasis(ZZ).DualObjects().extra_super_categories() [Category of modules over Integer Ring] sage: ModulesWithBasis(QQ).DualObjects().super_categories() - [Category of duals of vector spaces over Rational Field, Category of duals of modules with basis over Rational Field] + [Category of duals of vector spaces over Rational Field, + Category of duals of modules with basis over Rational Field] """ return [Modules(self.base_category().base_ring())] diff --git a/src/sage/categories/monoid_algebras.py b/src/sage/categories/monoid_algebras.py index f51a8d01ce1..a387d7f74f4 100644 --- a/src/sage/categories/monoid_algebras.py +++ b/src/sage/categories/monoid_algebras.py @@ -33,5 +33,5 @@ def MonoidAlgebras(base_ring): sage: TestSuite(MonoidAlgebras(ZZ)).run() """ - from sage.categories.all import Monoids + from sage.categories.monoids import Monoids return Monoids().Algebras(base_ring) diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index dc548a72e66..38dd7248c9d 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -69,7 +69,7 @@ class Monoids(CategoryWithAxiom): Check for :trac:`31212`:: sage: R = IntegerModRing(15) - sage: R.submonoid([R.one()]).list() + sage: R.submonoid([R.one()]).list() # needs sage.combinat [1] """ _base_category_class_and_axiom = (Semigroups, "Unital") @@ -98,11 +98,11 @@ def free(index_set=None, names=None, **kwds): EXAMPLES:: - sage: Monoids.free(index_set=ZZ) + sage: Monoids.free(index_set=ZZ) # needs sage.combinat Free monoid indexed by Integer Ring - sage: Monoids().free(ZZ) + sage: Monoids().free(ZZ) # needs sage.combinat Free monoid indexed by Integer Ring - sage: F.<x,y,z> = Monoids().free(); F + sage: F.<x,y,z> = Monoids().free(); F # needs sage.combinat Free monoid indexed by {'x', 'y', 'z'} """ if names is not None: @@ -130,8 +130,8 @@ def semigroup_generators(self): EXAMPLES:: - sage: M = Monoids().free([1,2,3]) - sage: M.semigroup_generators() + sage: M = Monoids().free([1,2,3]) # needs sage.combinat + sage: M.semigroup_generators() # needs sage.combinat Family (1, F[1], F[2], F[3]) """ G = self.monoid_generators() @@ -212,22 +212,22 @@ def submonoid(self, generators, category=None): EXAMPLES:: sage: R = IntegerModRing(15) - sage: M = R.submonoid([R(3),R(5)]); M + sage: M = R.submonoid([R(3), R(5)]); M # needs sage.combinat A submonoid of (Ring of integers modulo 15) with 2 generators - sage: M.list() + sage: M.list() # needs sage.combinat [1, 3, 5, 9, 0, 10, 12, 6] Not the presence of the unit, unlike in:: - sage: S = R.subsemigroup([R(3),R(5)]); S + sage: S = R.subsemigroup([R(3), R(5)]); S # needs sage.combinat A subsemigroup of (Ring of integers modulo 15) with 2 generators - sage: S.list() + sage: S.list() # needs sage.combinat [3, 5, 9, 0, 10, 12, 6] This method is really a shorthand for subsemigroup:: - sage: M2 = R.subsemigroup([R(3),R(5)], one=R.one()) - sage: M2 is M + sage: M2 = R.subsemigroup([R(3), R(5)], one=R.one()) # needs sage.combinat + sage: M2 is M # needs sage.combinat True """ return self.subsemigroup(generators, one=self.one()) @@ -245,6 +245,7 @@ def _div_(left, right): EXAMPLES:: + sage: # needs sage.groups sage: G = FreeGroup(2) sage: x0, x1 = G.group_generators() sage: c1 = cartesian_product([x0, x1]) @@ -267,7 +268,7 @@ def _div_(left, right): TESTS:: - sage: c1._div_.__module__ + sage: c1._div_.__module__ # needs sage.groups 'sage.categories.monoids' """ return left * ~right @@ -336,8 +337,8 @@ def powers(self, n): EXAMPLES:: - sage: A = Matrix([[1, 1], [-1, 0]]) - sage: A.powers(6) + sage: A = Matrix([[1, 1], [-1, 0]]) # needs sage.modules + sage: A.powers(6) # needs sage.modules [ [1 0] [ 1 1] [ 0 1] [-1 0] [-1 -1] [ 0 -1] [0 1], [-1 0], [-1 -1], [ 0 -1], [ 1 0], [ 1 1] @@ -363,8 +364,8 @@ def __invert__(self): EXAMPLES:: - sage: A = Matrix([[1, 0], [1, 1]]) - sage: ~A + sage: A = Matrix([[1, 0], [1, 1]]) # needs sage.modules + sage: ~A # needs sage.modules [ 1 0] [-1 1] """ @@ -377,9 +378,11 @@ def inverse(self): This is an alias for inversion, which can also be invoked by ``~x`` for an element ``x``. + Nota Bene: Element classes should implement ``__invert__`` only. + EXAMPLES:: - sage: AA(sqrt(~2)).inverse() + sage: AA(sqrt(~2)).inverse() # needs sage.rings.number_field sage.symbolic 1.414213562373095? """ # Nota Bene: Element classes should implement ``__invert__`` only. @@ -412,11 +415,11 @@ def free(index_set=None, names=None, **kwds): EXAMPLES:: - sage: Monoids.Commutative.free(index_set=ZZ) + sage: Monoids.Commutative.free(index_set=ZZ) # needs sage.combinat Free abelian monoid indexed by Integer Ring - sage: Monoids().Commutative().free(ZZ) + sage: Monoids().Commutative().free(ZZ) # needs sage.combinat Free abelian monoid indexed by Integer Ring - sage: F.<x,y,z> = Monoids().Commutative().free(); F + sage: F.<x,y,z> = Monoids().Commutative().free(); F # needs sage.combinat Free abelian monoid indexed by {'x', 'y', 'z'} """ if names is not None: @@ -447,18 +450,18 @@ def one(self): EXAMPLES:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: A.one.__module__ + sage: A.one.__module__ # needs sage.modules 'sage.categories.monoids' - sage: A.one() + sage: A.one() # needs sage.modules F[{}] TESTS:: - sage: A.one() is A.a_realization().one() + sage: A.one() is A.a_realization().one() # needs sage.modules True - sage: A._test_one() + sage: A._test_one() # needs sage.modules """ return self.a_realization().one() @@ -510,6 +513,7 @@ def one_basis(self): EXAMPLES:: + sage: # needs sage.modules sage: A = Monoids().example().algebra(ZZ) sage: A.one_basis() '' @@ -542,7 +546,7 @@ def algebra_generators(self): the free monoid generated by ('a', 'b', 'c', 'd') sage: M.monoid_generators() Finite family {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'} - sage: M.algebra(ZZ).algebra_generators() + sage: M.algebra(ZZ).algebra_generators() # needs sage.modules Finite family {'a': B['a'], 'b': B['b'], 'c': B['c'], 'd': B['d']} sage: Z12 = Monoids().Finite().example(); Z12 @@ -555,17 +559,18 @@ def algebra_generators(self): has no attribute 'monoid_generators' sage: Z12.semigroup_generators() Family (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) - sage: Z12.algebra(QQ).algebra_generators() + sage: Z12.algebra(QQ).algebra_generators() # needs sage.modules Family (B[0], B[1], B[2], B[3], B[4], B[5], B[6], B[7], B[8], B[9], B[10], B[11]) - sage: GroupAlgebras(QQ).example(AlternatingGroup(10)).algebra_generators() + sage: A10 = AlternatingGroup(10) # needs sage.groups + sage: GroupAlgebras(QQ).example(A10).algebra_generators() # needs sage.groups sage.modules Family ((8,9,10), (1,2,3,4,5,6,7,8,9)) - sage: A = DihedralGroup(3).algebra(QQ); A + sage: A = DihedralGroup(3).algebra(QQ); A # needs sage.groups sage.modules Algebra of Dihedral group of order 6 as a permutation group over Rational Field - sage: A.algebra_generators() + sage: A.algebra_generators() # needs sage.groups sage.modules Family ((1,2,3), (1,3)) """ monoid = self.basis().keys() @@ -583,14 +588,16 @@ def is_central(self): EXAMPLES:: - sage: SG4 = SymmetricGroupAlgebra(ZZ,4) - sage: SG4(1).is_central() + sage: SG4 = SymmetricGroupAlgebra(ZZ,4) # needs sage.groups sage.modules + sage: SG4(1).is_central() # needs sage.groups sage.modules True - sage: SG4(Permutation([1,3,2,4])).is_central() + sage: SG4(Permutation([1,3,2,4])).is_central() # needs sage.groups sage.modules False - sage: A = GroupAlgebras(QQ).example(); A - Algebra of Dihedral group of order 8 as a permutation group over Rational Field - sage: sum(i for i in A.basis()).is_central() + + sage: A = GroupAlgebras(QQ).example(); A # needs sage.groups sage.modules + Algebra of Dihedral group of order 8 + as a permutation group over Rational Field + sage: sum(A.basis()).is_central() # needs sage.groups sage.modules True """ return all(i * self == self * i @@ -628,8 +635,9 @@ def monoid_generators(self): EXAMPLES:: - sage: M = Monoids.free([1,2,3]) - sage: N = Monoids.free(['a','b']) + sage: # needs sage.groups + sage: M = Monoids.free([1, 2, 3]) + sage: N = Monoids.free(['a', 'b']) sage: C = cartesian_product([M, N]) sage: C.monoid_generators() Family ((F[1], 1), (F[2], 1), (F[3], 1), @@ -638,9 +646,9 @@ def monoid_generators(self): An example with an infinitely generated group (a better output is needed):: - sage: N = Monoids.free(ZZ) - sage: C = cartesian_product([M, N]) - sage: C.monoid_generators() + sage: N = Monoids.free(ZZ) # needs sage.combinat + sage: C = cartesian_product([M, N]) # needs sage.combinat sage.groups + sage: C.monoid_generators() # needs sage.combinat sage.groups Lazy family (gen(i))_{i in The Cartesian product of (...)} """ F = self.cartesian_factors() @@ -677,9 +685,10 @@ def multiplicative_order(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: G1 = SymmetricGroup(3) - sage: G2 = SL(2,3) - sage: G = cartesian_product([G1,G2]) + sage: G2 = SL(2, 3) + sage: G = cartesian_product([G1, G2]) sage: G((G1.gen(0), G2.gen(1))).multiplicative_order() 12 """ @@ -697,9 +706,10 @@ def __invert__(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: a1 = Permutation((4,2,1,3)) - sage: a2 = SL(2,3)([2,1,1,1]) - sage: h = cartesian_product([a1,a2]) + sage: a2 = SL(2, 3)([2,1,1,1]) + sage: h = cartesian_product([a1, a2]) sage: ~h ([2, 4, 1, 3], [1 2] [2 2]) diff --git a/src/sage/categories/morphism.pyx b/src/sage/categories/morphism.pyx index 59a73a43c62..571f90a7330 100644 --- a/src/sage/categories/morphism.pyx +++ b/src/sage/categories/morphism.pyx @@ -27,17 +27,15 @@ AUTHORS: """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** - -import operator +# https://www.gnu.org/licenses/ +# **************************************************************************** from cpython.object cimport * @@ -51,6 +49,7 @@ from sage.structure.parent cimport Parent def is_Morphism(x): return isinstance(x, Morphism) + cdef class Morphism(Map): def _repr_(self): @@ -70,13 +69,14 @@ cdef class Morphism(Map): EXAMPLES:: sage: R.<t> = ZZ[] - sage: f = R.hom([t+1]) + sage: f = R.hom([t + 1]) sage: f # indirect doctest Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring Defn: t |--> t + 1 TESTS:: + sage: # needs sage.rings.number_field sage: K = CyclotomicField(12) sage: L = CyclotomicField(132) sage: phi = L._internal_coerce_map_from(K); phi @@ -84,7 +84,6 @@ cdef class Morphism(Map): Generic morphism: From: Cyclotomic Field of order 12 and degree 4 To: Cyclotomic Field of order 132 and degree 40 - sage: del K sage: import gc sage: _ = gc.collect() @@ -183,6 +182,7 @@ cdef class Morphism(Map): and left modules over (euclidean domains and infinite enumerated sets and metric spaces) + sage: # needs sage.rings.number_field sage: K = CyclotomicField(12) sage: L = CyclotomicField(132) sage: phi = L._internal_coerce_map_from(K) @@ -203,6 +203,7 @@ cdef class Morphism(Map): sage: f.is_endomorphism() True + sage: # needs sage.rings.number_field sage: K = CyclotomicField(12) sage: L = CyclotomicField(132) sage: phi = L._internal_coerce_map_from(K) @@ -225,7 +226,7 @@ cdef class Morphism(Map): sage: f = R.hom([t]) sage: f.is_identity() True - sage: g = R.hom([t+1]) + sage: g = R.hom([t + 1]) sage: g.is_identity() False @@ -261,7 +262,9 @@ cdef class Morphism(Map): sage: x^2 + y Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for +: 'Univariate Polynomial Ring in x over Integer Ring' and 'Univariate Polynomial Ring in y over Integer Ring' + TypeError: unsupported operand parent(s) for +: + 'Univariate Polynomial Ring in x over Integer Ring' and + 'Univariate Polynomial Ring in y over Integer Ring' Let us declare a coercion from `\ZZ[x]` to `\ZZ[z]`:: @@ -285,7 +288,9 @@ cdef class Morphism(Map): sage: phi.register_as_coercion() Traceback (most recent call last): ... - AssertionError: coercion from Univariate Polynomial Ring in x over Integer Ring to Univariate Polynomial Ring in z over Integer Ring already registered or discovered + AssertionError: coercion from Univariate Polynomial Ring in x over Integer Ring + to Univariate Polynomial Ring in z over Integer Ring + already registered or discovered """ self._codomain.register_coercion(self) @@ -301,6 +306,7 @@ cdef class Morphism(Map): Let us declare a conversion from the symmetric group to `\ZZ` through the sign map:: + sage: # needs sage.groups sage: S = SymmetricGroup(4) sage: phi = Hom(S, ZZ)(lambda x: ZZ(x.sign())) sage: x = S.an_element(); x @@ -347,27 +353,29 @@ cdef class Morphism(Map): TESTS:: + sage: # needs sage.combinat sage: from sage.categories.morphism import SetMorphism sage: E = End(Partitions(5)) sage: f = E.identity() - sage: g = SetMorphism(E, lambda x:x) + sage: g = SetMorphism(E, lambda x: x) sage: f == g Traceback (most recent call last): ... - NotImplementedError: unable to compare morphisms of type <... 'sage.categories.morphism.IdentityMorphism'> and <... 'sage.categories.morphism.SetMorphism'> with domain Partitions of the integer 5 + NotImplementedError: unable to compare morphisms of type <... 'sage.categories.morphism.IdentityMorphism'> + and <... 'sage.categories.morphism.SetMorphism'> with domain Partitions of the integer 5 We check that :trac:`28617` is fixed:: - sage: FF = GF(2^20) - sage: f = FF.frobenius_endomorphism() - sage: f == FF.frobenius_endomorphism() + sage: FF = GF(2^20) # needs sage.rings.finite_rings + sage: f = FF.frobenius_endomorphism() # needs sage.rings.finite_rings + sage: f == FF.frobenius_endomorphism() # needs sage.rings.finite_rings True and that :trac:`29632` is fixed:: - sage: R.<x,y> = QuadraticField(-1)[] - sage: f = R.hom(R.gens(), R) - sage: f.is_identity() + sage: R.<x,y> = QuadraticField(-1)[] # needs sage.rings.number_field + sage: f = R.hom(R.gens(), R) # needs sage.rings.number_field + sage: f.is_identity() # needs sage.rings.number_field True """ if self is other: @@ -474,20 +482,18 @@ cdef class IdentityMorphism(Morphism): if not args and not kwds: return x cdef Parent C = self._codomain - if C._element_init_pass_parent: - from sage.misc.superseded import deprecation_cython as deprecation - deprecation(26879, "_element_init_pass_parent=True is deprecated. This probably means that _element_constructor_ should be a method and not some other kind of callable") - return C._element_constructor(C, x, *args, **kwds) - else: - return C._element_constructor(x, *args, **kwds) + return C._element_constructor(x, *args, **kwds) def __mul__(left, right): if not isinstance(right, Map): - raise TypeError("right (=%s) must be a map to multiply it by %s"%(right, left)) + raise TypeError(f"right (={right}) must be a map " + f"to multiply it by {left}") if not isinstance(left, Map): - raise TypeError("left (=%s) must be a map to multiply it by %s"%(left, right)) + raise TypeError(f"left (={left}) must be a map " + f"to multiply it by {right}") if right.codomain() != left.domain(): - raise TypeError("self (=%s) domain must equal right (=%s) codomain"%(left, right)) + raise TypeError(f"self (={left}) domain must equal " + f"right (={right}) codomain") if isinstance(left, IdentityMorphism): return right else: @@ -505,12 +511,13 @@ cdef class IdentityMorphism(Morphism): EXAMPLES:: - sage: E = End(Partitions(5)) - sage: E.identity().is_identity() + sage: E = End(Partitions(5)) # needs sage.combinat + sage: E.identity().is_identity() # needs sage.combinat True Check that :trac:`15478` is fixed:: + sage: # needs sage.rings.finite_rings sage: K.<z> = GF(4) sage: phi = End(K)([z^2]) sage: R.<t> = K[] @@ -681,7 +688,7 @@ cdef class SetMorphism(Morphism): sage: f = sage.categories.morphism.SetMorphism(Hom(ZZ,ZZ, Sets()), operator.__abs__) sage: g = sage.categories.morphism.SetMorphism(Hom(ZZ,ZZ, Sets()), operator.__abs__) - sage: h = sage.categories.morphism.SetMorphism(Hom(ZZ,ZZ, Rings()), operator.__abs__) # todo: replace by the more correct Monoids + sage: h = sage.categories.morphism.SetMorphism(Hom(ZZ,ZZ, Rings()), operator.__abs__) # todo: replace by the more correct Monoids sage: i = sage.categories.morphism.SetMorphism(Hom(ZZ,ZZ, Sets()), operator.__neg__) sage: f._eq_c_impl(g) True @@ -707,7 +714,7 @@ cdef class SetMorphism(Morphism): sage: f = sage.categories.morphism.SetMorphism(Hom(ZZ,ZZ, Sets()), operator.__abs__) sage: g = sage.categories.morphism.SetMorphism(Hom(ZZ,ZZ, Sets()), operator.__abs__) - sage: h = sage.categories.morphism.SetMorphism(Hom(ZZ,ZZ, Rings()), operator.__abs__) # todo: replace by the more correct Monoids + sage: h = sage.categories.morphism.SetMorphism(Hom(ZZ,ZZ, Rings()), operator.__abs__) # todo: replace by the more correct Monoids sage: i = sage.categories.morphism.SetMorphism(Hom(ZZ,ZZ, Sets()), operator.__neg__) sage: f == f, f != f, f < f, f > f, f <= f, f >= f (True, False, False, False, True, True) diff --git a/src/sage/categories/number_fields.py b/src/sage/categories/number_fields.py index c29e4c57255..3c070bd65b2 100644 --- a/src/sage/categories/number_fields.py +++ b/src/sage/categories/number_fields.py @@ -42,16 +42,16 @@ class NumberFields(Category_singleton): course also in this category:: sage: x = PolynomialRing(RationalField(), 'x').gen() - sage: K = NumberField(x - 1, 'a'); K + sage: K = NumberField(x - 1, 'a'); K # needs sage.rings.number_field Number Field in a with defining polynomial x - 1 - sage: K in C + sage: K in C # needs sage.rings.number_field True Number fields all lie in this category, regardless of the name of the variable:: - sage: K = NumberField(x^2 + 1, 'a') - sage: K in C + sage: K = NumberField(x^2 + 1, 'a') # needs sage.rings.number_field + sage: K in C # needs sage.rings.number_field True TESTS:: @@ -75,11 +75,11 @@ def __contains__(self, x): EXAMPLES:: sage: x = polygen(QQ, 'x') - sage: NumberField(x^2 + 1, 'a') in NumberFields() + sage: NumberField(x^2 + 1, 'a') in NumberFields() # needs sage.rings.number_field True - sage: QuadraticField(-97, 'theta') in NumberFields() + sage: QuadraticField(-97, 'theta') in NumberFields() # needs sage.rings.number_field True - sage: CyclotomicField(97) in NumberFields() + sage: CyclotomicField(97) in NumberFields() # needs sage.rings.number_field True Note that the rational numbers QQ are a number field:: @@ -89,8 +89,8 @@ def __contains__(self, x): sage: ZZ in NumberFields() False """ - import sage.rings.number_field.number_field_base - return sage.rings.number_field.number_field_base.is_NumberField(x) + from sage.rings.number_field.number_field_base import NumberField + return isinstance(x, NumberField) def _call_(self, x): r""" @@ -105,10 +105,10 @@ def _call_(self, x): sage: C(QQ) Rational Field - sage: C(NumberField(x^2 + 1, 'a')) + sage: C(NumberField(x^2 + 1, 'a')) # needs sage.rings.number_field Number Field in a with defining polynomial x^2 + 1 - sage: C(UnitGroup(NumberField(x^2 + 1, 'a'))) # indirect doctest + sage: C(UnitGroup(NumberField(x^2 + 1, 'a'))) # indirect doctest # needs sage.rings.number_field Number Field in a with defining polynomial x^2 + 1 sage: C(ZZ) @@ -151,34 +151,35 @@ def zeta_function(self, prec=53, EXAMPLES:: - sage: K.<a> = NumberField(ZZ['x'].0^2+ZZ['x'].0-1) - sage: Z = K.zeta_function(); Z # optional - sage.symbolic - PARI zeta function associated to Number Field in a with defining polynomial x^2 + x - 1 - sage: Z(-1) # optional - sage.symbolic + sage: K.<a> = NumberField(ZZ['x'].0^2 + ZZ['x'].0 - 1) # needs sage.rings.number_field + sage: Z = K.zeta_function(); Z # needs sage.rings.number_field sage.symbolic + PARI zeta function associated to Number Field in a + with defining polynomial x^2 + x - 1 + sage: Z(-1) # needs sage.rings.number_field sage.symbolic 0.0333333333333333 - sage: x = polygen(QQ, 'x') # optional - sage.symbolic - sage: L.<a, b, c> = NumberField([x^2 - 5, x^2 + 3, x^2 + 1]) # optional - sage.symbolic - sage: Z = L.zeta_function() # optional - sage.symbolic - sage: Z(5) # optional - sage.symbolic + sage: x = polygen(QQ, 'x') + sage: L.<a, b, c> = NumberField([x^2 - 5, x^2 + 3, x^2 + 1]) # needs sage.rings.number_field + sage: Z = L.zeta_function() # needs sage.rings.number_field sage.symbolic + sage: Z(5) # needs sage.rings.number_field sage.symbolic 1.00199015670185 Using the algorithm "pari":: - sage: K.<a> = NumberField(ZZ['x'].0^2+ZZ['x'].0-1) # optional - sage.symbolic - sage: Z = K.zeta_function(algorithm="pari") # optional - sage.symbolic - sage: Z(-1) # optional - sage.symbolic + sage: K.<a> = NumberField(ZZ['x'].0^2 + ZZ['x'].0 - 1) # needs sage.rings.number_field + sage: Z = K.zeta_function(algorithm="pari") # needs sage.rings.number_field sage.symbolic + sage: Z(-1) # needs sage.rings.number_field sage.symbolic 0.0333333333333333 - sage: x = polygen(QQ, 'x') # optional - sage.symbolic - sage: L.<a, b, c> = NumberField([x^2 - 5, x^2 + 3, x^2 + 1]) # optional - sage.symbolic - sage: Z = L.zeta_function(algorithm="pari") # optional - sage.symbolic - sage: Z(5) # optional - sage.symbolic + sage: x = polygen(QQ, 'x') + sage: L.<a, b, c> = NumberField([x^2 - 5, x^2 + 3, x^2 + 1]) # needs sage.rings.number_field + sage: Z = L.zeta_function(algorithm="pari") # needs sage.rings.number_field sage.symbolic + sage: Z(5) # needs sage.rings.number_field sage.symbolic 1.00199015670185 TESTS:: - sage: QQ.zeta_function() # optional - sage.symbolic + sage: QQ.zeta_function() # needs sage.symbolic PARI zeta function associated to Rational Field """ if algorithm == 'gp': @@ -222,8 +223,9 @@ def _test_absolute_disc(self, **options): EXAMPLES:: - sage: S = NumberField(x**3-x-1, 'a') - sage: S._test_absolute_disc() + sage: x = polygen(ZZ, 'x') + sage: S = NumberField(x**3 - x - 1, 'a') # needs sage.rings.number_field + sage: S._test_absolute_disc() # needs sage.rings.number_field """ from sage.rings.integer import Integer tester = self._tester(**options) diff --git a/src/sage/categories/polyhedra.py b/src/sage/categories/polyhedra.py index 20e43bff108..256eb99498d 100644 --- a/src/sage/categories/polyhedra.py +++ b/src/sage/categories/polyhedra.py @@ -26,6 +26,7 @@ class PolyhedralSets(Category_over_base_ring): sage: TestSuite(PolyhedralSets(RDF)).run() + sage: # needs sage.geometry.polyhedron sage: P = Polyhedron() sage: P.parent().category().element_class <class 'sage.categories.category.JoinCategory.element_class'> @@ -53,7 +54,7 @@ def __init__(self, R): """ TESTS:: - sage: PolyhedralSets(AA) + sage: PolyhedralSets(AA) # needs sage.rings.number_field Category of polyhedral sets over Algebraic Real Field """ Category_over_base_ring.__init__(self, R) diff --git a/src/sage/categories/poor_man_map.py b/src/sage/categories/poor_man_map.py index d0fca4b658d..b8d0bdb4de9 100644 --- a/src/sage/categories/poor_man_map.py +++ b/src/sage/categories/poor_man_map.py @@ -39,7 +39,7 @@ class PoorManMap(sage.structure.sage_object.SageObject): EXAMPLES:: sage: from sage.categories.poor_man_map import PoorManMap - sage: f = PoorManMap(factorial, domain = (1, 2, 3), codomain = (1, 2, 6)) + sage: f = PoorManMap(factorial, domain=(1, 2, 3), codomain=(1, 2, 6)) sage: f A map from (1, 2, 3) to (1, 2, 6) sage: f(3) @@ -48,12 +48,12 @@ class PoorManMap(sage.structure.sage_object.SageObject): The composition of several functions can be created by passing in a tuple of functions:: - sage: i = PoorManMap((factorial, sqrt), domain= (1, 4, 9), codomain = (1, 2, 6)) + sage: i = PoorManMap((factorial, sqrt), domain=(1, 4, 9), codomain=(1, 2, 6)) However, the same effect can also be achieved by just composing maps:: - sage: g = PoorManMap(factorial, domain = (1, 2, 3), codomain = (1, 2, 6)) - sage: h = PoorManMap(sqrt, domain = (1, 4, 9), codomain = (1, 2, 3)) + sage: g = PoorManMap(factorial, domain=(1, 2, 3), codomain=(1, 2, 6)) + sage: h = PoorManMap(sqrt, domain=(1, 4, 9), codomain=(1, 2, 3)) sage: i == g*h True @@ -63,8 +63,8 @@ def __init__(self, function, domain=None, codomain=None, name=None): TESTS:: sage: from sage.categories.poor_man_map import PoorManMap - sage: f = PoorManMap(factorial, domain = (1, 2, 3), codomain = (1, 2, 6)) - sage: g = PoorManMap(sqrt, domain = (1, 4, 9), codomain = (1, 2, 6)) + sage: f = PoorManMap(factorial, domain=(1, 2, 3), codomain=(1, 2, 6)) + sage: g = PoorManMap(sqrt, domain=(1, 4, 9), codomain=(1, 2, 6)) sage: TestSuite(f).run() sage: TestSuite(f*g).run() @@ -85,17 +85,17 @@ def _repr_(self): sage: from sage.categories.poor_man_map import PoorManMap sage: PoorManMap(lambda x: x+2) # indirect doctest A map - sage: PoorManMap(lambda x: x+2, domain = (1,2,3)) + sage: PoorManMap(lambda x: x+2, domain=(1,2,3)) A map from (1, 2, 3) - sage: PoorManMap(lambda x: x+2, domain = (1,2,3)) + sage: PoorManMap(lambda x: x+2, domain=(1,2,3)) A map from (1, 2, 3) - sage: PoorManMap(lambda x: x+2, codomain = (3,4,5)) + sage: PoorManMap(lambda x: x+2, codomain=(3,4,5)) A map to (3, 4, 5) """ return ((self._name if self._name is not None else "A map") + - (" from %s"%(self._domain,) if self._domain is not None else "" ) + - (" to %s"%(self._codomain,) if self._codomain is not None else "" )) + (" from %s" % (self._domain,) if self._domain is not None else "" ) + + (" to %s" % (self._codomain,) if self._codomain is not None else "" )) def domain(self): """ @@ -104,7 +104,7 @@ def domain(self): EXAMPLES:: sage: from sage.categories.poor_man_map import PoorManMap - sage: PoorManMap(lambda x: x+1, domain = (1,2,3), codomain = (2,3,4)).domain() + sage: PoorManMap(lambda x: x+1, domain=(1,2,3), codomain=(2,3,4)).domain() (1, 2, 3) """ return self._domain @@ -116,7 +116,7 @@ def codomain(self): EXAMPLES:: sage: from sage.categories.poor_man_map import PoorManMap - sage: PoorManMap(lambda x: x+1, domain = (1,2,3), codomain = (2,3,4)).codomain() + sage: PoorManMap(lambda x: x+1, domain=(1,2,3), codomain=(2,3,4)).codomain() (2, 3, 4) """ return self._codomain @@ -128,12 +128,12 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.categories.poor_man_map import PoorManMap - sage: f = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) - sage: g = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) - sage: h1 = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6,8)) - sage: h2 = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6,8)) - sage: h3 = PoorManMap(factorial, domain = (1,2,3,4), codomain = (1,2,6)) - sage: h4 = PoorManMap(lambda x: x, domain = (1,2,3), codomain = (1,2,6)) + sage: f = PoorManMap(factorial, domain=(1,2,3), codomain=(1,2,6)) + sage: g = PoorManMap(factorial, domain=(1,2,3), codomain=(1,2,6)) + sage: h1 = PoorManMap(factorial, domain=(1,2,3), codomain=(1,2,6,8)) + sage: h2 = PoorManMap(factorial, domain=(1,2,3), codomain=(1,2,6,8)) + sage: h3 = PoorManMap(factorial, domain=(1,2,3,4), codomain=(1,2,6)) + sage: h4 = PoorManMap(lambda x: x, domain=(1,2,3), codomain=(1,2,6)) sage: f == g, f == h1, f == h2, f == h3, f == h4, f == 1, 1 == f (True, False, False, False, False, False, False) @@ -153,12 +153,12 @@ def __ne__(self, other): EXAMPLES:: sage: from sage.categories.poor_man_map import PoorManMap - sage: f = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) - sage: g = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) - sage: h1 = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6,8)) - sage: h2 = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6,8)) - sage: h3 = PoorManMap(factorial, domain = (1,2,3,4), codomain = (1,2,6)) - sage: h4 = PoorManMap(lambda x: x, domain = (1,2,3), codomain = (1,2,6)) + sage: f = PoorManMap(factorial, domain=(1,2,3), codomain=(1,2,6)) + sage: g = PoorManMap(factorial, domain=(1,2,3), codomain=(1,2,6)) + sage: h1 = PoorManMap(factorial, domain=(1,2,3), codomain=(1,2,6,8)) + sage: h2 = PoorManMap(factorial, domain=(1,2,3), codomain=(1,2,6,8)) + sage: h3 = PoorManMap(factorial, domain=(1,2,3,4), codomain=(1,2,6)) + sage: h4 = PoorManMap(lambda x: x, domain=(1,2,3), codomain=(1,2,6)) sage: f != g, f != h1, f != h2, f != h3, f != h4, f != 1, 1 != f (False, True, True, True, True, True, True) @@ -172,8 +172,8 @@ def __hash__(self): TESTS:: sage: from sage.categories.poor_man_map import PoorManMap - sage: f = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) - sage: g = PoorManMap(factorial, domain = (1,2,3), codomain = (1,2,6)) + sage: f = PoorManMap(factorial, domain=(1,2,3), codomain=(1,2,6)) + sage: g = PoorManMap(factorial, domain=(1,2,3), codomain=(1,2,6)) sage: hash(f) == hash(g) True @@ -194,8 +194,8 @@ def __mul__(self, other): EXAMPLES:: sage: from sage.categories.poor_man_map import PoorManMap - sage: f = PoorManMap(lambda x: x+1, domain = (1,2,3), codomain = (2,3,4)) - sage: g = PoorManMap(lambda x: -x, domain = (2,3,4), codomain = (-2,-3,-4)) + sage: f = PoorManMap(lambda x: x+1, domain=(1,2,3), codomain=(2,3,4)) + sage: g = PoorManMap(lambda x: -x, domain=(2,3,4), codomain=(-2,-3,-4)) sage: g*f A map from (1, 2, 3) to (-2, -3, -4) @@ -208,13 +208,14 @@ def __mul__(self, other): But it is detected here:: - sage: g = PoorManMap(factorial, domain = ZZ, codomain = ZZ) - sage: h = PoorManMap(sqrt, domain = RR, codomain = CC) - sage: g*h + sage: g = PoorManMap(factorial, domain=ZZ, codomain=ZZ) + sage: h = PoorManMap(sqrt, domain=RR, codomain=CC) # needs sage.rings.real_mpfr + sage: g*h # needs sage.rings.real_mpfr Traceback (most recent call last): ... - ValueError: the codomain Complex Field with 53 bits of precision does not coerce into the domain Integer Ring - sage: h*g + ValueError: the codomain Complex Field with 53 bits of precision + does not coerce into the domain Integer Ring + sage: h*g # needs sage.rings.real_mpfr A map from Integer Ring to Complex Field with 53 bits of precision """ self_domain = self.domain() @@ -248,11 +249,11 @@ def __call__(self, *args): EXAMPLES:: sage: from sage.categories.poor_man_map import PoorManMap - sage: f = PoorManMap(lambda x: x+1, domain = (1,2,3), codomain = (2,3,4)) + sage: f = PoorManMap(lambda x: x+1, domain=(1,2,3), codomain=(2,3,4)) sage: f(2) 3 - sage: g = PoorManMap(lambda x: -x, domain = (2,3,4), codomain = (-2,-3,-4)) + sage: g = PoorManMap(lambda x: -x, domain=(2,3,4), codomain=(-2,-3,-4)) sage: (g*f)(2) -3 @@ -267,7 +268,7 @@ def _sympy_(self): sage: from sage.categories.poor_man_map import PoorManMap sage: h = PoorManMap(sin, domain=RR, codomain=RR) - sage: h._sympy_() + sage: h._sympy_() # needs sympy sage.symbolic sin """ from sympy import Lambda, sympify diff --git a/src/sage/categories/posets.py b/src/sage/categories/posets.py index b1a2ba1942d..5cad3c70f73 100644 --- a/src/sage/categories/posets.py +++ b/src/sage/categories/posets.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs, sage.combinat r""" Posets """ @@ -70,13 +71,14 @@ class Posets(Category): :trac:`10130` will be resolved, this will be automatically provided by this category:: - sage: x < y # todo: not implemented + sage: # not implemented + sage: x < y True - sage: x < x # todo: not implemented + sage: x < x False - sage: x <= x # todo: not implemented + sage: x <= x True - sage: y >= x # todo: not implemented + sage: y >= x True .. SEEALSO:: :func:`Poset`, :class:`FinitePosets`, :class:`LatticePosets` @@ -112,7 +114,8 @@ def example(self, choice=None): An example of a poset: sets ordered by inclusion sage: Posets().example("facade") - An example of a facade poset: the positive integers ordered by divisibility + An example of a facade poset: + the positive integers ordered by divisibility """ from sage.categories.examples.posets import FiniteSetsOrderedByInclusion, PositiveIntegersOrderedByDivisibilityFacade if choice == "facade": @@ -398,7 +401,7 @@ def order_ideal_toggle(self, I, v): sage: P = Poset({1: [2,3], 2: [4], 3: []}) sage: I = Set({1, 2}) - sage: I in P.order_ideals_lattice() + sage: I in P.order_ideals_lattice() # needs sage.modules True sage: P.order_ideal_toggle(I, 1) {1, 2} @@ -409,7 +412,7 @@ def order_ideal_toggle(self, I, v): sage: P.order_ideal_toggle(I, 4) {1, 2, 4} sage: P4 = Posets(4) - sage: all(all(all(P.order_ideal_toggle(P.order_ideal_toggle(I, i), i) == I + sage: all(all(all(P.order_ideal_toggle(P.order_ideal_toggle(I, i), i) == I # needs sage.modules ....: for i in range(4)) ....: for I in P.order_ideals_lattice(facade=True)) ....: for P in P4) @@ -457,7 +460,8 @@ def is_order_ideal(self, o): EXAMPLES:: - sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True) + sage: P = Poset((divisors(12), attrcall("divides")), + ....: facade=True, linear_extension=True) sage: sorted(P.list()) [1, 2, 3, 4, 6, 12] sage: P.is_order_ideal([1, 3]) @@ -483,7 +487,8 @@ def is_order_filter(self, o): EXAMPLES:: - sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True) + sage: P = Poset((divisors(12), attrcall("divides")), + ....: facade=True, linear_extension=True) sage: sorted(P.list()) [1, 2, 3, 4, 6, 12] sage: P.is_order_filter([4, 12]) @@ -527,7 +532,8 @@ def is_chain_of_poset(self, o, ordered=False): EXAMPLES:: - sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True) + sage: P = Poset((divisors(12), attrcall("divides")), + ....: facade=True, linear_extension=True) sage: sorted(P.list()) [1, 2, 3, 4, 6, 12] sage: P.is_chain_of_poset([1, 3]) @@ -575,11 +581,16 @@ def is_chain_of_poset(self, o, ordered=False): sage: from sage.categories.examples.posets import FiniteSetsOrderedByInclusion sage: R = FiniteSetsOrderedByInclusion() - sage: R.is_chain_of_poset([R(set([3, 1, 2])), R(set([1, 4])), R(set([4, 5]))]) + sage: R.is_chain_of_poset([R(set([3, 1, 2])), + ....: R(set([1, 4])), + ....: R(set([4, 5]))]) False - sage: R.is_chain_of_poset([R(set([3, 1, 2])), R(set([1, 2])), R(set([1]))], ordered=True) + sage: R.is_chain_of_poset([R(set([3, 1, 2])), + ....: R(set([1, 2])), + ....: R(set([1]))], ordered=True) False - sage: R.is_chain_of_poset([R(set([3, 1, 2])), R(set([1, 2])), R(set([1]))]) + sage: R.is_chain_of_poset([R(set([3, 1, 2])), + ....: R(set([1, 2])), R(set([1]))]) True sage: from sage.categories.examples.posets import PositiveIntegersOrderedByDivisibilityFacade @@ -632,7 +643,8 @@ def is_antichain_of_poset(self, o): EXAMPLES:: - sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True) + sage: P = Poset((divisors(12), attrcall("divides")), + ....: facade=True, linear_extension=True) sage: sorted(P.list()) [1, 2, 3, 4, 6, 12] sage: P.is_antichain_of_poset([1, 3]) @@ -653,9 +665,11 @@ def is_antichain_of_poset(self, o): False sage: P.is_antichain_of_poset([6, 4]) True - sage: P.is_antichain_of_poset(i for i in divisors(12) if (2 < i and i < 6)) + sage: P.is_antichain_of_poset(i for i in divisors(12) + ....: if (2 < i and i < 6)) True - sage: P.is_antichain_of_poset(i for i in divisors(12) if (2 <= i and i < 6)) + sage: P.is_antichain_of_poset(i for i in divisors(12) + ....: if (2 <= i and i < 6)) False sage: Q = Poset({2: [3, 1], 3: [4], 1: [4]}) @@ -680,9 +694,11 @@ def is_antichain_of_poset(self, o): sage: from sage.categories.examples.posets import FiniteSetsOrderedByInclusion sage: R = FiniteSetsOrderedByInclusion() - sage: R.is_antichain_of_poset([R(set([3, 1, 2])), R(set([1, 4])), R(set([4, 5]))]) + sage: R.is_antichain_of_poset([R(set([3, 1, 2])), + ....: R(set([1, 4])), R(set([4, 5]))]) True - sage: R.is_antichain_of_poset([R(set([3, 1, 2, 4])), R(set([1, 4])), R(set([4, 5]))]) + sage: R.is_antichain_of_poset([R(set([3, 1, 2, 4])), + ....: R(set([1, 4])), R(set([4, 5]))]) False """ return all(not self.lt(x,y) for x in o for y in o) diff --git a/src/sage/categories/primer.py b/src/sage/categories/primer.py index 96dff8e2631..14f8d5fbbe5 100644 --- a/src/sage/categories/primer.py +++ b/src/sage/categories/primer.py @@ -78,12 +78,12 @@ sage: Permutations(5).cardinality() 120 - sage: GL(2,2).cardinality() + sage: GL(2,2).cardinality() # needs sage.modules 6 - sage: A = random_matrix(ZZ,6,3,x=7) - sage: L = LatticePolytope(A.rows()) - sage: L.npoints() # oops! # random + sage: A = random_matrix(ZZ, 6, 3, x=7) # needs sage.modules + sage: L = LatticePolytope(A.rows()) # needs sage.geometry.polyhedron sage.modules + sage: L.npoints() # oops! # random # needs sage.geometry.polyhedron sage.modules 37 - How to ensure robustness? @@ -98,7 +98,9 @@ :: - sage: m = random_matrix(QQ, 4, algorithm='echelonizable', rank=3, upper_bound=60) + sage: # needs sage.modules + sage: m = random_matrix(QQ, 4, algorithm='echelonizable', + ....: rank=3, upper_bound=60) sage: m^8 == m*m*m*m*m*m*m*m == ((m^2)^2)^2 True @@ -125,12 +127,12 @@ and sure enough, binary powering is defined there:: - sage: m._pow_int.__module__ + sage: m._pow_int.__module__ # needs sage.modules 'sage.categories.monoids' That's our bookshelf! And it's used in many places:: - sage: GL(2,ZZ) in Monoids() + sage: GL(2, ZZ) in Monoids() # needs sage.modules True sage: NN in Monoids() True @@ -168,20 +170,20 @@ Each set in Sage knows which bookshelf of generic algorithms it can use, that is to which category it belongs:: - sage: G = GL(2,ZZ) - sage: G.category() + sage: G = GL(2, ZZ) # needs sage.modules + sage: G.category() # needs sage.modules Category of infinite groups In fact a group is a semigroup, and Sage knows about this:: sage: Groups().is_subcategory(Semigroups()) True - sage: G in Semigroups() + sage: G in Semigroups() # needs sage.modules True Altogether, our group gets algorithms from a bunch of bookshelves:: - sage: G.categories() + sage: G.categories() # needs sage.modules [Category of infinite groups, Category of groups, Category of monoids, ..., Category of magmas, @@ -189,19 +191,19 @@ Those can be viewed graphically:: - sage: g = Groups().category_graph() - sage: g.set_latex_options(format="dot2tex") - sage: view(g) # not tested + sage: g = Groups().category_graph() # needs sage.graphs + sage: g.set_latex_options(format="dot2tex") # needs sage.graphs sage.modules + sage: view(g) # not tested # needs sage.graphs sage.modules sage.plot In case ``dot2tex`` is not available, you can use instead:: - sage: g.show(vertex_shape=None, figsize=20) + sage: g.show(vertex_shape=None, figsize=20) # needs sage.graphs sage.modules sage.plot Here is an overview of all categories in Sage:: - sage: g = sage.categories.category.category_graph() - sage: g.set_latex_options(format="dot2tex") - sage: view(g) # not tested + sage: g = sage.categories.category.category_graph() # needs sage.graphs sage.modules + sage: g.set_latex_options(format="dot2tex") # needs sage.graphs sage.modules + sage: view(g) # not tested # needs sage.graphs sage.modules sage.plot Wrap-up: generic algorithms in Sage are organized in a hierarchy of bookshelves modelled upon the usual hierarchy of categories provided @@ -370,9 +372,9 @@ Category of sets with partial maps, Category of objects] - sage: g = EuclideanDomains().category_graph() - sage: g.set_latex_options(format="dot2tex") - sage: view(g) # not tested + sage: g = EuclideanDomains().category_graph() # needs sage.graphs + sage: g.set_latex_options(format="dot2tex") # needs sage.graphs sage.plot + sage: view(g) # not tested # needs sage.graphs sage.plot A bit of help from computer science =================================== @@ -406,21 +408,24 @@ class implements: sage: i.factor() 2^2 * 3 - sage: x = var('x') # optional - sage.symbolic - sage: p = 6*x^2 + 12*x + 6 # optional - sage.symbolic - sage: type(p) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: x = var('x') + sage: p = 6*x^2 + 12*x + 6 + sage: type(p) <class 'sage.symbolic.expression.Expression'> - sage: p.factor() # optional - sage.symbolic + sage: p.factor() 6*(x + 1)^2 + sage: # needs sage.symbolic sage: R.<x> = PolynomialRing(QQ, sparse=True) - sage: pQ = R ( p ) + sage: pQ = R(p) sage: type(pQ) <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category.element_class'> sage: pQ.factor() (6) * (x + 1)^2 - sage: pZ = ZZ['x'] ( p ) + sage: # needs sage.symbolic + sage: pZ = ZZ['x'](p) sage: type(pZ) <class 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'> sage: pZ.factor() @@ -443,9 +448,9 @@ class implements: sage: i._pow_.__module__ # not tested (Issue #24275) 'sage.categories.semigroups' - sage: pQ._mul_.__module__ + sage: pQ._mul_.__module__ # needs sage.symbolic 'sage.rings.polynomial.polynomial_element_generic' - sage: pQ._pow_.__module__ # not tested (Issue #24275) + sage: pQ._pow_.__module__ # not tested (Issue #24275) # needs sage.symbolic 'sage.categories.semigroups' We see that integers and polynomials have each their own @@ -486,9 +491,9 @@ class implements: The full hierarchy is best viewed graphically:: - sage: g = class_graph(m.__class__) - sage: g.set_latex_options(format="dot2tex") - sage: view(g) # not tested + sage: g = class_graph(m.__class__) # needs sage.combinat sage.graphs + sage: g.set_latex_options(format="dot2tex") # needs sage.combinat sage.graphs + sage: view(g) # not tested # needs sage.combinat sage.graphs sage.plot Parallel hierarchy of classes for parents ----------------------------------------- @@ -522,14 +527,14 @@ class implements: modelled by instances of some (hierarchy of) classes. For example, our group `G` is an instance of the following class:: - sage: G = GL(2,ZZ) - sage: type(G) - <class 'sage.groups.matrix_gps.linear.LinearMatrixGroup_gap_with_category'> + sage: G = GL(2, ZZ) # needs sage.modules + sage: type(G) # needs sage.libs.gap sage.modules + <class 'sage.groups.matrix_gps.linear_gap.LinearMatrixGroup_gap_with_category'> Here is a piece of the hierarchy of classes above it:: - sage: for cls in G.__class__.mro(): print(cls) - <class 'sage.groups.matrix_gps.linear.LinearMatrixGroup_gap_with_category'> + sage: for cls in G.__class__.mro(): print(cls) # needs sage.libs.gap sage.modules + <class 'sage.groups.matrix_gps.linear_gap.LinearMatrixGroup_gap_with_category'> ... <class 'sage.categories.groups.Groups.parent_class'> <class 'sage.categories.monoids.Monoids.parent_class'> @@ -540,10 +545,11 @@ class implements: categories and parallel to that we had seen for the elements. This is best viewed graphically:: + sage: # needs sage.graphs sage.modules sage: g = class_graph(m.__class__) sage: g.relabel(lambda x: x.replace("_",r"\_")) sage: g.set_latex_options(format="dot2tex") - sage: view(g) # not tested + sage: view(g) # not tested # needs sage.plot .. NOTE:: @@ -577,7 +583,7 @@ class implements: - Group, Monoid, Semigroup, Magma, ... - GroupElement, MonoidElement, SemigroupElement, MagmaElement, ... -- GroupMorphism, SemigroupElement, SemigroupMorphism, MagmaMorphism, ... +- GroupMorphism, MonoidMorphism, SemigroupMorphism, MagmaMorphism, ... (and in fact many more as we will see). @@ -724,7 +730,7 @@ class SubcategoryMethods: Note that categories themselves are naturally modelled by instances because they can have operations of their own. An important one is:: - sage: Groups().example() + sage: Groups().example() # needs sage.modules General Linear Group of degree 4 over Rational Field which gives an example of object of the category. Besides illustrating @@ -1017,16 +1023,17 @@ class SubcategoryMethods: example, permutation groups are by default in the category of finite permutation groups (no surprise):: - sage: P = PermutationGroup([[(1,2,3)]]); P + sage: P = PermutationGroup([[(1,2,3)]]); P # needs sage.combinat sage.groups Permutation Group with generators [(1,2,3)] - sage: P.category() + sage: P.category() # needs sage.combinat Category of finite enumerated permutation groups In this case, the group is commutative, so we can specify this:: - sage: P = PermutationGroup([[(1,2,3)]], category=PermutationGroups().Finite().Commutative()); P + sage: P = PermutationGroup([[(1,2,3)]], # needs sage.combinat sage.groups + ....: category=PermutationGroups().Finite().Commutative()); P Permutation Group with generators [(1,2,3)] - sage: P.category() + sage: P.category() # needs sage.combinat Category of finite enumerated commutative permutation groups This feature can even be used, typically in experimental code, to add @@ -1041,7 +1048,8 @@ class SubcategoryMethods: ....: class ElementMethods: ....: def bar(self): print("bar") - sage: P = PermutationGroup([[(1,2,3)]], category=Foos()) + sage: # needs sage.combinat + sage: P = PermutationGroup([[(1,2,3)]], category=Foos()) # needs sage.groups sage: P.foo() foo sage: p = P.an_element() @@ -1052,7 +1060,7 @@ class SubcategoryMethods: forgetful functors; for example the above group could be constructed as a plain set with:: - sage: P = PermutationGroup([[(1,2,3)]], category=Sets()) # todo: not implemented + sage: P = PermutationGroup([[(1,2,3)]], category=Sets()) # not implemented, needs sage.combinat At this stage though, this is still to be explored for robustness and practicality. For now, most parents that accept a category argument @@ -1100,9 +1108,9 @@ class SubcategoryMethods: Let for example `A` and `B` be two parents, and let us construct the Cartesian product `A \times B \times B`:: - sage: A = AlgebrasWithBasis(QQ).example(); A.rename("A") - sage: B = HopfAlgebrasWithBasis(QQ).example(); B.rename("B") - sage: C = cartesian_product([A, B, B]); C + sage: A = AlgebrasWithBasis(QQ).example(); A.rename("A") # needs sage.combinat sage.modules + sage: B = HopfAlgebrasWithBasis(QQ).example(); B.rename("B") # needs sage.combinat sage.modules + sage: C = cartesian_product([A, B, B]); C # needs sage.combinat sage.modules A (+) B (+) B In which category should this new parent be? Since `A` and `B` are @@ -1111,14 +1119,14 @@ class SubcategoryMethods: are monoids, `A \times B \times B` is naturally endowed with a monoid structure for pointwise multiplication:: - sage: C in Monoids() + sage: C in Monoids() # needs sage.combinat sage.modules True the unit being the Cartesian product of the units of the operands:: - sage: C.one() + sage: C.one() # needs sage.combinat sage.modules B[(0, word: )] + B[(1, ())] + B[(2, ())] - sage: cartesian_product([A.one(), B.one(), B.one()]) + sage: cartesian_product([A.one(), B.one(), B.one()]) # needs sage.combinat sage.modules B[(0, word: )] + B[(1, ())] + B[(2, ())] The pointwise product can be implemented generically for all magmas @@ -1126,7 +1134,7 @@ class SubcategoryMethods: constructed as Cartesian products. It's thus implemented in the :class:`Magmas` category:: - sage: C.product.__module__ + sage: C.product.__module__ # needs sage.combinat sage.modules 'sage.categories.magmas' More specifically, keeping on using nested classes to structure the @@ -1158,7 +1166,7 @@ class naming and introspection. Sage currently works around the Let us now look at the categories of ``C``:: - sage: C.categories() + sage: C.categories() # needs sage.combinat sage.modules [Category of finite dimensional Cartesian products of algebras with basis over Rational Field, ... Category of Cartesian products of algebras over Rational Field, ... Category of Cartesian products of semigroups, Category of semigroups, ... @@ -1369,13 +1377,14 @@ class naming and introspection. Sage currently works around the sage: C = (Magmas() & AdditiveMagmas()).Distributive(); C Category of distributive magmas and additive magmas - sage: C.Associative().AdditiveAssociative().AdditiveCommutative().AdditiveUnital().AdditiveInverse() + sage: CAA = C.Associative().AdditiveAssociative() + sage: CAA.AdditiveCommutative().AdditiveUnital().AdditiveInverse() Category of rngs - sage: C.Associative().AdditiveAssociative().AdditiveCommutative().AdditiveUnital().Unital() + sage: CAA.AdditiveCommutative().AdditiveUnital().Unital() Category of semirings - sage: C.Associative().AdditiveAssociative().AdditiveCommutative().AdditiveUnital().AdditiveInverse().Unital() + sage: CAA.AdditiveCommutative().AdditiveUnital().AdditiveInverse().Unital() Category of rings sage: Rings().Division() @@ -1389,9 +1398,9 @@ class naming and introspection. Sage currently works around the or for more advanced categories:: - sage: g = HopfAlgebras(QQ).WithBasis().Graded().Connected().category_graph() - sage: g.set_latex_options(format="dot2tex") - sage: view(g) # not tested + sage: g = HopfAlgebras(QQ).WithBasis().Graded().Connected().category_graph() # needs sage.graphs + sage: g.set_latex_options(format="dot2tex") # needs sage.graphs + sage: view(g) # not tested # needs sage.graphs sage.plot Difference between axioms and regressive covariant functorial constructions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1413,7 +1422,7 @@ class naming and introspection. Sage currently works around the A finite dimensional algebra is also a finite dimensional module:: - sage: Algebras(QQ).FiniteDimensional().is_subcategory( Modules(QQ).FiniteDimensional() ) + sage: Algebras(QQ).FiniteDimensional().is_subcategory(Modules(QQ).FiniteDimensional()) True Similarly a graded algebra is also a graded module:: diff --git a/src/sage/categories/principal_ideal_domains.py b/src/sage/categories/principal_ideal_domains.py index 2821fdf0ef6..7d9ee8c1e32 100644 --- a/src/sage/categories/principal_ideal_domains.py +++ b/src/sage/categories/principal_ideal_domains.py @@ -70,13 +70,14 @@ def _test_gcd_vs_xgcd(self, **options): sage: ZZ._test_gcd_vs_xgcd() sage: QQ._test_gcd_vs_xgcd() sage: QQ['x']._test_gcd_vs_xgcd() - sage: QQbar['x']._test_gcd_vs_xgcd() + sage: QQbar['x']._test_gcd_vs_xgcd() # needs sage.rings.number_field sage: RR._test_gcd_vs_xgcd() sage: RR['x']._test_gcd_vs_xgcd() A slightly more involved example of polynomial ring with a non UFD base ring:: + sage: # needs sage.rings.number_field sage: K = QuadraticField(5) sage: O = K.maximal_order() sage: O in UniqueFactorizationDomains() @@ -109,14 +110,14 @@ def _test_gcd_vs_xgcd(self, **options): tester.assertTrue(has_gcd, "The ring {} provides a xgcd but no gcd".format(self)) for (x,y),gcd,xgcd in zip(pairs,gcds,xgcds): - tester.assertTrue(gcd.parent()==self, + tester.assertTrue(gcd.parent() == self, "The parent of the gcd is {} for element of {}".format( gcd.parent(), self)) - tester.assertTrue(xgcd[0].parent()==self and - xgcd[1].parent()==self and xgcd[2].parent()==self, + tester.assertTrue(xgcd[0].parent() == self and + xgcd[1].parent() == self and xgcd[2].parent() == self, "The parent of output in xgcd is different from " "the parent of input for elements in {}".format(self)) - tester.assertTrue(gcd==xgcd[0], + tester.assertTrue(gcd == xgcd[0], "The methods gcd and xgcd disagree on {}:\n" " gcd({},{}) = {}\n" " xgcd({},{}) = {}\n".format(self,x,y,gcd,x,y,xgcd)) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 6c5b08e003a..3b7b8238d52 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -108,13 +108,16 @@ class ConstructionFunctor(Functor): sage: F = P.construction()[0]; F MPoly[x,y] sage: A.<a,b> = GF(5)[] - sage: f = A.hom([a+b,a-b],A) + sage: f = A.hom([a + b, a - b], A) sage: F(A) - Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5 + Multivariate Polynomial Ring in x, y + over Multivariate Polynomial Ring in a, b over Finite Field of size 5 sage: F(f) - Ring endomorphism of Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5 + Ring endomorphism of Multivariate Polynomial Ring in x, y + over Multivariate Polynomial Ring in a, b over Finite Field of size 5 Defn: Induced from base ring by - Ring endomorphism of Multivariate Polynomial Ring in a, b over Finite Field of size 5 + Ring endomorphism of Multivariate Polynomial Ring in a, b + over Finite Field of size 5 Defn: a |--> a + b b |--> a - b sage: F(f)(F(A)(x)*a) @@ -199,7 +202,7 @@ def __eq__(self, other): sage: I == I # indirect doctest True """ - return type(self) == type(other) + return type(self) is type(other) def __ne__(self, other): """ @@ -430,22 +433,27 @@ class CompositeConstructionFunctor(ConstructionFunctor): EXAMPLES:: sage: from sage.categories.pushout import CompositeConstructionFunctor - sage: F = CompositeConstructionFunctor(QQ.construction()[0],ZZ['x'].construction()[0],QQ.construction()[0],ZZ['y'].construction()[0]) + sage: F = CompositeConstructionFunctor(QQ.construction()[0], ZZ['x'].construction()[0], + ....: QQ.construction()[0], ZZ['y'].construction()[0]) sage: F Poly[y](FractionField(Poly[x](FractionField(...)))) sage: F == loads(dumps(F)) True sage: F == CompositeConstructionFunctor(*F.all) True - sage: F(GF(2)['t']) - Univariate Polynomial Ring in y over Fraction Field of Univariate Polynomial Ring in x over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + sage: F(GF(2)['t']) # needs sage.libs.ntl + Univariate Polynomial Ring in y + over Fraction Field of Univariate Polynomial Ring in x + over Fraction Field of Univariate Polynomial Ring in t + over Finite Field of size 2 (using GF2X) """ def __init__(self, *args): """ TESTS:: sage: from sage.categories.pushout import CompositeConstructionFunctor - sage: F = CompositeConstructionFunctor(QQ.construction()[0],ZZ['x'].construction()[0],QQ.construction()[0],ZZ['y'].construction()[0]) + sage: F = CompositeConstructionFunctor(QQ.construction()[0], ZZ['x'].construction()[0], + ....: QQ.construction()[0], ZZ['y'].construction()[0]) sage: F Poly[y](FractionField(Poly[x](FractionField(...)))) sage: F == CompositeConstructionFunctor(*F.all) @@ -517,7 +525,7 @@ def __eq__(self, other): if isinstance(other, CompositeConstructionFunctor): return self.all == other.all else: - return type(self) == type(other) + return type(self) is type(other) def __ne__(self, other): """ @@ -587,7 +595,10 @@ def expand(self): EXAMPLES:: sage: from sage.categories.pushout import CompositeConstructionFunctor - sage: F = CompositeConstructionFunctor(QQ.construction()[0],ZZ['x'].construction()[0],QQ.construction()[0],ZZ['y'].construction()[0]) + sage: F = CompositeConstructionFunctor(QQ.construction()[0], + ....: ZZ['x'].construction()[0], + ....: QQ.construction()[0], + ....: ZZ['y'].construction()[0]) sage: F Poly[y](FractionField(Poly[x](FractionField(...)))) sage: prod(F.expand()) == F @@ -666,7 +677,7 @@ def __eq__(self, other): sage: I == QQ.construction()[0] False """ - c = (type(self) == type(other)) + c = (type(self) is type(other)) if not c: if isinstance(other, IdentityFunctor_generic): return True @@ -806,15 +817,15 @@ class PolynomialFunctor(ConstructionFunctor): sage: P == loads(dumps(P)) True sage: R.<x,y> = GF(5)[] - sage: f = R.hom([x+2*y,3*x-y],R) - sage: P(f)((x+y)*P(R).0) + sage: f = R.hom([x + 2*y, 3*x - y], R) + sage: P(f)((x+y) * P(R).0) (-x + y)*t By :trac:`9944`, the construction functor distinguishes sparse and dense polynomial rings. Before, the following example failed:: sage: R.<x> = PolynomialRing(GF(5), sparse=True) - sage: F,B = R.construction() + sage: F, B = R.construction() sage: F(B) is R True sage: S.<x> = PolynomialRing(ZZ) @@ -994,10 +1005,12 @@ class MultiPolynomialFunctor(ConstructionFunctor): MPoly[x,y] sage: A.<a,b> = GF(5)[] sage: F(A) - Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5 - sage: f = A.hom([a+b,a-b],A) + Multivariate Polynomial Ring in x, y + over Multivariate Polynomial Ring in a, b over Finite Field of size 5 + sage: f = A.hom([a+b, a-b], A) sage: F(f) - Ring endomorphism of Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5 + Ring endomorphism of Multivariate Polynomial Ring in x, y + over Multivariate Polynomial Ring in a, b over Finite Field of size 5 Defn: Induced from base ring by Ring endomorphism of Multivariate Polynomial Ring in a, b over Finite Field of size 5 Defn: a |--> a + b @@ -1018,7 +1031,7 @@ def __init__(self, vars, term_order): MPoly[x,y] sage: F(ZZ) Multivariate Polynomial Ring in x, y over Integer Ring - sage: F(CC) + sage: F(CC) # needs sage.rings.real_mpfr Multivariate Polynomial Ring in x, y over Complex Field with 53 bits of precision """ Functor.__init__(self, Rings(), Rings()) @@ -1038,7 +1051,7 @@ def _apply_functor(self, R): <class 'sage.categories.pushout.MultiPolynomialFunctor'> sage: F(ZZ) # indirect doctest Multivariate Polynomial Ring in x, y, z over Integer Ring - sage: F(RR) # indirect doctest + sage: F(RR) # indirect doctest # needs sage.rings.real_mpfr Multivariate Polynomial Ring in x, y, z over Real Field with 53 bits of precision """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -1153,9 +1166,11 @@ def expand(self): sage: x + s Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for +: 'Multivariate Polynomial Ring in x, y, z over Integer Ring' and 'Multivariate Polynomial Ring in y, s over Rational Field' - sage: R = PolynomialRing(ZZ, 'x', 500) - sage: S = PolynomialRing(GF(5), 'x', 200) + TypeError: unsupported operand parent(s) for +: + 'Multivariate Polynomial Ring in x, y, z over Integer Ring' and + 'Multivariate Polynomial Ring in y, s over Rational Field' + sage: R = PolynomialRing(ZZ, 'x', 50) + sage: S = PolynomialRing(GF(5), 'x', 20) sage: R.gen(0) + S.gen(0) 2*x0 """ @@ -1203,7 +1218,7 @@ class InfinitePolynomialFunctor(ConstructionFunctor): sage: B.<x,y,a_3,a_1> = PolynomialRing(QQ, order='lex') sage: B.construction() (MPoly[x,y,a_3,a_1], Rational Field) - sage: A.construction()[0]*B.construction()[0] + sage: A.construction()[0] * B.construction()[0] InfPoly{[a,b], "lex", "dense"}(MPoly[x,y](...)) Apparently the variables `a_1,a_3` of the polynomial ring are merged with the variables @@ -1211,7 +1226,8 @@ class InfinitePolynomialFunctor(ConstructionFunctor): However, if the polynomial ring was given a different ordering, merging would not be allowed, resulting in a name conflict:: - sage: A.construction()[0]*PolynomialRing(QQ,names=['x','y','a_3','a_1']).construction()[0] + sage: R = PolynomialRing(QQ, names=['x','y','a_3','a_1']) + sage: A.construction()[0] * R.construction()[0] Traceback (most recent call last): ... CoercionException: Incompatible term orders lex, degrevlex @@ -1219,25 +1235,30 @@ class InfinitePolynomialFunctor(ConstructionFunctor): In an infinite polynomial ring with generator `a_\ast`, the variable `a_3` will always be greater than the variable `a_1`. Hence, the orders are incompatible in the next example as well:: - sage: A.construction()[0]*PolynomialRing(QQ,names=['x','y','a_1','a_3'], order='lex').construction()[0] + sage: R = PolynomialRing(QQ, names=['x','y','a_1','a_3'], order='lex') + sage: A.construction()[0] * R.construction()[0] Traceback (most recent call last): ... - CoercionException: Overlapping variables (('a', 'b'),['a_1', 'a_3']) are incompatible + CoercionException: Overlapping variables (('a', 'b'),['a_1', 'a_3']) + are incompatible Another requirement is that after merging the order of the remaining variables must be unique. This is not the case in the following example, since it is not clear whether the variables `x,y` should be greater or smaller than the variables `b_\ast`:: - sage: A.construction()[0]*PolynomialRing(QQ,names=['a_3','a_1','x','y'], order='lex').construction()[0] + sage: R = PolynomialRing(QQ, names=['a_3','a_1','x','y'], order='lex') + sage: A.construction()[0] * R.construction()[0] Traceback (most recent call last): ... - CoercionException: Overlapping variables (('a', 'b'),['a_3', 'a_1']) are incompatible + CoercionException: Overlapping variables (('a', 'b'),['a_3', 'a_1']) + are incompatible Since the construction functors are actually used to construct infinite polynomial rings, the following result is no surprise:: sage: C.<a,b> = InfinitePolynomialRing(B); C - Infinite polynomial ring in a, b over Multivariate Polynomial Ring in x, y over Rational Field + Infinite polynomial ring in a, b + over Multivariate Polynomial Ring in x, y over Rational Field There is also an overlap in the next example:: @@ -1472,8 +1493,8 @@ def merge(self, other): EXAMPLES:: - sage: X.<x,y> = InfinitePolynomialRing(QQ,implementation='sparse') - sage: Y.<x,y> = InfinitePolynomialRing(QQ,order='degrevlex') + sage: X.<x,y> = InfinitePolynomialRing(QQ, implementation='sparse') + sage: Y.<x,y> = InfinitePolynomialRing(QQ, order='degrevlex') sage: X.construction() [InfPoly{[x,y], "lex", "sparse"}, Rational Field] sage: Y.construction() @@ -1525,11 +1546,13 @@ def expand(self): EXAMPLES:: - sage: F = InfinitePolynomialRing(QQ, ['x','y'],order='degrevlex').construction()[0]; F + sage: A = InfinitePolynomialRing(QQ, ['x','y'], order='degrevlex') + sage: F = A.construction()[0]; F InfPoly{[x,y], "degrevlex", "dense"} sage: F.expand() [InfPoly{[y], "degrevlex", "dense"}, InfPoly{[x], "degrevlex", "dense"}] - sage: F = InfinitePolynomialRing(QQ, ['x','y','z'],order='degrevlex').construction()[0]; F + sage: A = InfinitePolynomialRing(QQ, ['x','y','z'], order='degrevlex') + sage: F = A.construction()[0]; F InfPoly{[x,y,z], "degrevlex", "dense"} sage: F.expand() [InfPoly{[z], "degrevlex", "dense"}, @@ -1551,22 +1574,27 @@ class MatrixFunctor(ConstructionFunctor): EXAMPLES:: - sage: MS = MatrixSpace(ZZ,2, 3) + sage: # needs sage.modules + sage: MS = MatrixSpace(ZZ, 2, 3) sage: F = MS.construction()[0]; F MatrixFunctor - sage: MS = MatrixSpace(ZZ,2) + sage: MS = MatrixSpace(ZZ, 2) sage: F = MS.construction()[0]; F MatrixFunctor sage: P.<x,y> = QQ[] sage: R = F(P); R - Full MatrixSpace of 2 by 2 dense matrices over Multivariate Polynomial Ring in x, y over Rational Field - sage: f = P.hom([x+y,x-y],P); F(f) - Ring endomorphism of Full MatrixSpace of 2 by 2 dense matrices over Multivariate Polynomial Ring in x, y over Rational Field + Full MatrixSpace of 2 by 2 dense matrices + over Multivariate Polynomial Ring in x, y over Rational Field + sage: f = P.hom([x+y, x-y], P); F(f) + Ring endomorphism + of Full MatrixSpace of 2 by 2 dense matrices + over Multivariate Polynomial Ring in x, y over Rational Field Defn: Induced from base ring by - Ring endomorphism of Multivariate Polynomial Ring in x, y over Rational Field + Ring endomorphism + of Multivariate Polynomial Ring in x, y over Rational Field Defn: x |--> x + y y |--> x - y - sage: M = R([x,y,x*y,x+y]) + sage: M = R([x, y, x*y, x + y]) sage: F(f)(M) [ x + y x - y] [x^2 - y^2 2*x] @@ -1578,13 +1606,14 @@ def __init__(self, nrows, ncols, is_sparse=False): """ TESTS:: + sage: # needs sage.modules sage: from sage.categories.pushout import MatrixFunctor - sage: F = MatrixFunctor(2,3) - sage: F == MatrixSpace(ZZ,2,3).construction()[0] + sage: F = MatrixFunctor(2, 3) + sage: F == MatrixSpace(ZZ, 2, 3).construction()[0] True sage: F.codomain() Category of commutative additive groups - sage: R = MatrixSpace(ZZ,2,2).construction()[0] + sage: R = MatrixSpace(ZZ, 2, 2).construction()[0] sage: R.codomain() Category of rings sage: F(ZZ) @@ -1613,10 +1642,10 @@ def _apply_functor(self, R): The following is a test against a bug discussed at :trac:`8800`:: - sage: F = MatrixSpace(ZZ,2,3).construction()[0] - sage: F(RR) # indirect doctest + sage: F = MatrixSpace(ZZ, 2, 3).construction()[0] # needs sage.modules + sage: F(RR) # indirect doctest # needs sage.modules Full MatrixSpace of 2 by 3 dense matrices over Real Field with 53 bits of precision - sage: F(RR) in F.codomain() + sage: F(RR) in F.codomain() # needs sage.modules True """ @@ -1627,10 +1656,10 @@ def __eq__(self, other): """ TESTS:: - sage: F = MatrixSpace(ZZ,2,3).construction()[0] - sage: F == loads(dumps(F)) + sage: F = MatrixSpace(ZZ, 2, 3).construction()[0] # needs sage.modules + sage: F == loads(dumps(F)) # needs sage.modules True - sage: F == MatrixSpace(ZZ,2,2).construction()[0] + sage: F == MatrixSpace(ZZ, 2, 2).construction()[0] # needs sage.modules False """ if isinstance(other, MatrixFunctor): @@ -1643,10 +1672,10 @@ def __ne__(self, other): EXAMPLES:: - sage: F = MatrixSpace(ZZ,2,3).construction()[0] - sage: F != loads(dumps(F)) + sage: F = MatrixSpace(ZZ, 2, 3).construction()[0] # needs sage.modules + sage: F != loads(dumps(F)) # needs sage.modules False - sage: F != MatrixSpace(ZZ,2,2).construction()[0] + sage: F != MatrixSpace(ZZ, 2, 2).construction()[0] # needs sage.modules True """ return not (self == other) @@ -1661,9 +1690,10 @@ def merge(self, other): EXAMPLES:: - sage: F1 = MatrixSpace(ZZ,2,2).construction()[0] - sage: F2 = MatrixSpace(ZZ,2,3).construction()[0] - sage: F3 = MatrixSpace(ZZ,2,2,sparse=True).construction()[0] + sage: # needs sage.modules + sage: F1 = MatrixSpace(ZZ, 2, 2).construction()[0] + sage: F2 = MatrixSpace(ZZ, 2, 3).construction()[0] + sage: F3 = MatrixSpace(ZZ, 2, 2, sparse=True).construction()[0] sage: F1.merge(F2) sage: F1.merge(F3) MatrixFunctor @@ -1698,16 +1728,18 @@ class LaurentPolynomialFunctor(ConstructionFunctor): Univariate Laurent Polynomial Ring in t over Rational Field sage: K.<x> = LaurentPolynomialRing(ZZ) sage: F(K) - Univariate Laurent Polynomial Ring in t over Univariate Laurent Polynomial Ring in x over Integer Ring + Univariate Laurent Polynomial Ring in t + over Univariate Laurent Polynomial Ring in x over Integer Ring sage: P.<x,y> = ZZ[] - sage: f = P.hom([x+2*y,3*x-y],P) + sage: f = P.hom([x + 2*y, 3*x - y],P) sage: F(f) - Ring endomorphism of Univariate Laurent Polynomial Ring in t over Multivariate Polynomial Ring in x, y over Integer Ring + Ring endomorphism of Univariate Laurent Polynomial Ring in t + over Multivariate Polynomial Ring in x, y over Integer Ring Defn: Induced from base ring by Ring endomorphism of Multivariate Polynomial Ring in x, y over Integer Ring Defn: x |--> x + 2*y y |--> 3*x - y - sage: F(f)(x*F(P).gen()^-2+y*F(P).gen()^3) + sage: F(f)(x*F(P).gen()^-2 + y*F(P).gen()^3) (x + 2*y)*t^-2 + (3*x - y)*t^3 """ @@ -1729,10 +1761,11 @@ def __init__(self, var, multi_variate=False): sage: F2 = LaurentPolynomialFunctor('s', multi_variate=True) sage: F3 = LaurentPolynomialFunctor(['s','t']) sage: F1(F2(QQ)) - Univariate Laurent Polynomial Ring in t over Univariate Laurent Polynomial Ring in s over Rational Field - sage: F2(F1(QQ)) + Univariate Laurent Polynomial Ring in t over + Univariate Laurent Polynomial Ring in s over Rational Field + sage: F2(F1(QQ)) # needs sage.modules Multivariate Laurent Polynomial Ring in t, s over Rational Field - sage: F3(QQ) + sage: F3(QQ) # needs sage.modules Multivariate Laurent Polynomial Ring in s, t over Rational Field """ @@ -1753,16 +1786,18 @@ def _apply_functor(self, R): sage: F2 = LaurentPolynomialFunctor('s', multi_variate=True) sage: F3 = LaurentPolynomialFunctor(['s','t']) sage: F1(F2(QQ)) # indirect doctest - Univariate Laurent Polynomial Ring in t over Univariate Laurent Polynomial Ring in s over Rational Field - sage: F2(F1(QQ)) + Univariate Laurent Polynomial Ring in t over + Univariate Laurent Polynomial Ring in s over Rational Field + sage: F2(F1(QQ)) # needs sage.modules Multivariate Laurent Polynomial Ring in t, s over Rational Field - sage: F3(QQ) + sage: F3(QQ) # needs sage.modules Multivariate Laurent Polynomial Ring in s, t over Rational Field """ - from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing, is_LaurentPolynomialRing - if self.multi_variate and is_LaurentPolynomialRing(R): - return LaurentPolynomialRing(R.base_ring(), (list(R.variable_names()) + [self.var])) + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic + if self.multi_variate and isinstance(R, LaurentPolynomialRing_generic): + return LaurentPolynomialRing(R.base_ring(), list(R.variable_names()) + [self.var]) else: return LaurentPolynomialRing(R, self.var) @@ -1823,10 +1858,11 @@ def merge(self, other): sage: F2 = LaurentPolynomialFunctor('t', multi_variate=True) sage: F1.merge(F2) LaurentPolynomialFunctor - sage: F1.merge(F2)(LaurentPolynomialRing(GF(2),'a')) + sage: F1.merge(F2)(LaurentPolynomialRing(GF(2), 'a')) # needs sage.modules Multivariate Laurent Polynomial Ring in a, t over Finite Field of size 2 - sage: F1.merge(F1)(LaurentPolynomialRing(GF(2),'a')) - Univariate Laurent Polynomial Ring in t over Univariate Laurent Polynomial Ring in a over Finite Field of size 2 + sage: F1.merge(F1)(LaurentPolynomialRing(GF(2), 'a')) # needs sage.modules + Univariate Laurent Polynomial Ring in t over + Univariate Laurent Polynomial Ring in a over Finite Field of size 2 """ if self == other or isinstance(other, PolynomialFunctor) and self.var == other.var: @@ -1841,11 +1877,14 @@ class VectorFunctor(ConstructionFunctor): EXAMPLES:: + sage: # needs sage.modules sage: F = (ZZ^3).construction()[0] sage: F VectorFunctor - sage: F(GF(2)['t']) - Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + sage: F(GF(2)['t']) # needs sage.libs.ntl + Ambient free module of rank 3 + over the principal ideal domain Univariate Polynomial Ring in t + over Finite Field of size 2 (using GF2X) """ rank = 10 # ranking of functor, not rank of module. # This coincides with the rank of the matrix construction functor, but this is OK since they cannot both be applied in any order @@ -1864,8 +1903,9 @@ def __init__(self, n=None, is_sparse=False, inner_product_matrix=None, *, TESTS:: + sage: # needs sage.modules sage: from sage.categories.pushout import VectorFunctor - sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9))) + sage: F1 = VectorFunctor(3, inner_product_matrix=Matrix(3, 3, range(9))) sage: F1.domain() Category of commutative rings sage: F1.codomain() @@ -1874,7 +1914,7 @@ def __init__(self, n=None, is_sparse=False, inner_product_matrix=None, *, sage: M1.is_sparse() False sage: v = M1([3, 2, 1]) - sage: v*Matrix(3,3,range(9))*v.column() + sage: v * Matrix(3, 3, range(9)) * v.column() (96) sage: v.inner_product(v) 96 @@ -1906,13 +1946,14 @@ def _apply_functor(self, R): TESTS:: + sage: # needs sage.modules sage: from sage.categories.pushout import VectorFunctor, pushout - sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9))) + sage: F1 = VectorFunctor(3, inner_product_matrix=Matrix(3, 3, range(9))) sage: M1 = F1(ZZ) # indirect doctest sage: M1.is_sparse() False sage: v = M1([3, 2, 1]) - sage: v*Matrix(3,3,range(9))*v.column() + sage: v * Matrix(3, 3, range(9)) * v.column() (96) sage: v.inner_product(v) 96 @@ -1924,6 +1965,7 @@ def _apply_functor(self, R): sage: v.inner_product(v) 14 + sage: # needs sage.modules sage: M = FreeModule(ZZ, 4, with_basis=None, name='M') sage: latex(M) M @@ -1956,10 +1998,10 @@ def _apply_functor_to_morphism(self, f): TESTS:: - sage: F = (ZZ^3).construction()[0] + sage: F = (ZZ^3).construction()[0] # needs sage.modules sage: P.<x,y> = ZZ[] - sage: f = P.hom([x+2*y,3*x-y],P) - sage: F(f) # indirect doctest + sage: f = P.hom([x + 2*y, 3*x - y], P) + sage: F(f) # indirect doctest # needs sage.modules Traceback (most recent call last): ... NotImplementedError: Cannot create induced morphisms of free modules yet @@ -1973,8 +2015,9 @@ def __eq__(self, other): TESTS:: + sage: # needs sage.modules sage: from sage.categories.pushout import VectorFunctor - sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9))) + sage: F1 = VectorFunctor(3, inner_product_matrix=Matrix(3, 3, range(9))) sage: F2 = (ZZ^3).construction()[0] sage: F1 == F2 False @@ -1998,8 +2041,9 @@ def __ne__(self, other): EXAMPLES:: + sage: # needs sage.modules sage: from sage.categories.pushout import VectorFunctor - sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9))) + sage: F1 = VectorFunctor(3, inner_product_matrix=Matrix(3, 3, range(9))) sage: F2 = (ZZ^3).construction()[0] sage: F1 != F2 True @@ -2021,19 +2065,19 @@ def merge(self, other): Two modules without explicitly given inner product allow coercion:: - sage: M1 = QQ^3 + sage: M1 = QQ^3 # needs sage.modules sage: P.<t> = ZZ[] - sage: M2 = FreeModule(P,3) - sage: M1([1,1/2,1/3]) + M2([t,t^2+t,3]) # indirect doctest + sage: M2 = FreeModule(P, 3) # needs sage.modules + sage: M1([1,1/2,1/3]) + M2([t,t^2+t,3]) # indirect doctest # needs sage.modules (t + 1, t^2 + t + 1/2, 10/3) If only one summand has an explicit inner product, the result will be provided with it:: - sage: M3 = FreeModule(P,3, inner_product_matrix = Matrix(3,3,range(9))) - sage: M1([1,1/2,1/3]) + M3([t,t^2+t,3]) + sage: M3 = FreeModule(P, 3, inner_product_matrix=Matrix(3, 3, range(9))) # needs sage.modules + sage: M1([1,1/2,1/3]) + M3([t,t^2+t,3]) # needs sage.modules (t + 1, t^2 + t + 1/2, 10/3) - sage: (M1([1,1/2,1/3]) + M3([t,t^2+t,3])).parent().inner_product_matrix() + sage: (M1([1,1/2,1/3]) + M3([t,t^2+t,3])).parent().inner_product_matrix() # needs sage.modules [0 1 2] [3 4 5] [6 7 8] @@ -2044,7 +2088,8 @@ def merge(self, other): inner product was *explicitly* requested for ``M4``. It is therefore not possible to coerce with a different inner product:: - sage: M4 = FreeModule(QQ,3, inner_product_matrix = Matrix(3,3,1)) + sage: # needs sage.modules + sage: M4 = FreeModule(QQ, 3, inner_product_matrix=Matrix(3, 3, 1)) sage: M4 == M1 True sage: M4.inner_product_matrix() == M1.inner_product_matrix() @@ -2052,11 +2097,14 @@ def merge(self, other): sage: M4([1,1/2,1/3]) + M3([t,t^2+t,3]) # indirect doctest Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for +: 'Ambient quadratic space of dimension 3 over Rational Field + TypeError: unsupported operand parent(s) for +: + 'Ambient quadratic space of dimension 3 over Rational Field Inner product matrix: [1 0 0] [0 1 0] - [0 0 1]' and 'Ambient free quadratic module of rank 3 over the integral domain Univariate Polynomial Ring in t over Integer Ring + [0 0 1]' and + 'Ambient free quadratic module of rank 3 over the integral domain + Univariate Polynomial Ring in t over Integer Ring Inner product matrix: [0 1 2] [3 4 5] @@ -2064,15 +2112,19 @@ def merge(self, other): Names are removed when they conflict:: + sage: # needs sage.modules sage: from sage.categories.pushout import VectorFunctor, pushout sage: M_ZZx = FreeModule(ZZ['x'], 4, with_basis=None, name='M_ZZx') sage: N_ZZx = FreeModule(ZZ['x'], 4, with_basis=None, name='N_ZZx') sage: pushout(M_ZZx, QQ) - Rank-4 free module M_ZZx_base_ext over the Univariate Polynomial Ring in x over Rational Field + Rank-4 free module M_ZZx_base_ext + over the Univariate Polynomial Ring in x over Rational Field sage: pushout(M_ZZx, N_ZZx) - Rank-4 free module over the Univariate Polynomial Ring in x over Integer Ring + Rank-4 free module + over the Univariate Polynomial Ring in x over Integer Ring sage: pushout(pushout(M_ZZx, N_ZZx), QQ) - Rank-4 free module over the Univariate Polynomial Ring in x over Rational Field + Rank-4 free module + over the Univariate Polynomial Ring in x over Rational Field """ if not isinstance(other, VectorFunctor): return None @@ -2142,8 +2194,9 @@ class SubspaceFunctor(ConstructionFunctor): EXAMPLES:: + sage: # needs sage.modules sage: M = ZZ^3 - sage: S = M.submodule([(1,2,3),(4,5,6)]); S + sage: S = M.submodule([(1,2,3), (4,5,6)]); S Free module of degree 3 and rank 2 over Integer Ring Echelon basis matrix: [1 2 3] @@ -2171,9 +2224,9 @@ def __init__(self, basis): TESTS:: sage: from sage.categories.pushout import SubspaceFunctor - sage: M = ZZ^3 - sage: F = SubspaceFunctor([M([1,2,3]),M([4,5,6])]) - sage: F(GF(5)^3) + sage: M = ZZ^3 # needs sage.modules + sage: F = SubspaceFunctor([M([1,2,3]), M([4,5,6])]) # needs sage.modules + sage: F(GF(5)^3) # needs sage.modules Vector space of degree 3 and dimension 2 over Finite Field of size 5 User basis matrix: [1 2 3] @@ -2193,8 +2246,9 @@ def _apply_functor(self, ambient): TESTS:: + sage: # needs sage.modules sage: M = ZZ^3 - sage: S = M.submodule([(1,2,3),(4,5,6)]); S + sage: S = M.submodule([(1,2,3), (4,5,6)]); S Free module of degree 3 and rank 2 over Integer Ring Echelon basis matrix: [1 2 3] @@ -2214,9 +2268,10 @@ def _apply_functor_to_morphism(self, f): TESTS:: - sage: F = (ZZ^3).span([(1,2,3),(4,5,6)]).construction()[0] + sage: # needs sage.modules + sage: F = (ZZ^3).span([(1,2,3), (4,5,6)]).construction()[0] sage: P.<x,y> = ZZ[] - sage: f = P.hom([x+2*y,3*x-y],P) + sage: f = P.hom([x + 2*y, 3*x - y],P) sage: F(f) # indirect doctest Traceback (most recent call last): ... @@ -2228,6 +2283,7 @@ def __eq__(self, other): """ TESTS:: + sage: # needs sage.modules sage: F1 = (GF(5)^3).span([(1,2,3),(4,5,6)]).construction()[0] sage: F2 = (ZZ^3).span([(1,2,3),(4,5,6)]).construction()[0] sage: F3 = (QQ^3).span([(1,2,3),(4,5,6)]).construction()[0] @@ -2238,6 +2294,7 @@ def __eq__(self, other): The ``span`` method automatically transforms the given basis into echelon form. The bases look like that:: + sage: # needs sage.modules sage: F1.basis [ (1, 0, 4), @@ -2263,18 +2320,18 @@ def __eq__(self, other): The basis of ``F2`` is modulo 5 different from the other bases. So, we have:: - sage: F1 != F2 != F3 + sage: F1 != F2 != F3 # needs sage.modules True The bases of ``F1``, ``F3`` and ``F4`` are the same modulo 5; however, there is no coercion from ``QQ^3`` to ``GF(5)^3``. Therefore, we have:: - sage: F1 == F3 + sage: F1 == F3 # needs sage.modules False But there are coercions from ``ZZ^3`` to ``QQ^3`` and ``GF(5)^3``, thus:: - sage: F1 == F4 == F3 + sage: F1 == F4 == F3 # needs sage.modules True """ @@ -2300,8 +2357,8 @@ def __ne__(self, other): EXAMPLES:: - sage: F1 = (GF(5)^3).span([(1,2,3),(4,5,6)]).construction()[0] - sage: F1 != loads(dumps(F1)) + sage: F1 = (GF(5)^3).span([(1,2,3),(4,5,6)]).construction()[0] # needs sage.modules + sage: F1 != loads(dumps(F1)) # needs sage.modules False """ return not (self == other) @@ -2314,6 +2371,7 @@ def merge(self, other): EXAMPLES:: + sage: # needs sage.modules sage: M = GF(5)^3 sage: S1 = M.submodule([(1,2,3),(4,5,6)]) sage: S2 = M.submodule([(2,2,3)]) @@ -2321,10 +2379,11 @@ def merge(self, other): sage: F2 = S2.construction()[0] sage: F1.merge(F2) SubspaceFunctor - sage: F1.merge(F2)(GF(5)^3) == S1+S2 + sage: F1.merge(F2)(GF(5)^3) == S1 + S2 True sage: F1.merge(F2)(GF(5)['t']^3) - Free module of degree 3 and rank 3 over Univariate Polynomial Ring in t over Finite Field of size 5 + Free module of degree 3 and rank 3 + over Univariate Polynomial Ring in t over Finite Field of size 5 User basis matrix: [1 0 0] [0 1 0] @@ -2332,13 +2391,15 @@ def merge(self, other): TESTS:: + sage: # needs sage.modules sage: P.<t> = ZZ[] - sage: S1 = (ZZ^3).submodule([(1,2,3),(4,5,6)]) - sage: S2 = (Frac(P)^3).submodule([(t,t^2,t^3+1),(4*t,0,1)]) + sage: S1 = (ZZ^3).submodule([(1,2,3), (4,5,6)]) + sage: S2 = (Frac(P)^3).submodule([(t,t^2,t^3+1), (4*t,0,1)]) sage: v = S1([0,3,6]) + S2([2,0,1/(2*t)]); v # indirect doctest (2, 3, (-12*t - 1)/(-2*t)) sage: v.parent() - Vector space of degree 3 and dimension 3 over Fraction Field of Univariate Polynomial Ring in t over Integer Ring + Vector space of degree 3 and dimension 3 + over Fraction Field of Univariate Polynomial Ring in t over Integer Ring User basis matrix: [1 0 0] [0 1 0] @@ -2390,7 +2451,8 @@ class FractionField(ConstructionFunctor): sage: P.<x,y> = QQ[] sage: f = P.hom([x+2*y,3*x-y],P) sage: F(f) - Ring endomorphism of Fraction Field of Multivariate Polynomial Ring in x, y over Rational Field + Ring endomorphism of + Fraction Field of Multivariate Polynomial Ring in x, y over Rational Field Defn: x |--> x + 2*y y |--> 3*x - y sage: F(f)(1/x) @@ -2424,7 +2486,8 @@ def _apply_functor(self, R): sage: F = QQ.construction()[0] sage: F(GF(5)['t']) # indirect doctest - Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 + Fraction Field of Univariate Polynomial Ring in t + over Finite Field of size 5 """ return R.fraction_field() @@ -2435,6 +2498,7 @@ class CompletionFunctor(ConstructionFunctor): EXAMPLES:: + sage: # needs sage.rings.padics sage: R = Zp(5) sage: R 5-adic Ring with capped relative precision 20 @@ -2445,11 +2509,13 @@ class CompletionFunctor(ConstructionFunctor): True sage: F1(QQ) 5-adic Field with capped relative precision 20 + sage: F2 = RR.construction()[0] sage: F2 Completion[+Infinity, prec=53] sage: F2(QQ) is RR True + sage: P.<x> = ZZ[] sage: Px = P.completion(x) # currently the only implemented completion of P sage: Px @@ -2460,8 +2526,9 @@ class CompletionFunctor(ConstructionFunctor): TESTS:: - sage: R1.<a> = Zp(5,prec=20)[] - sage: R2 = Qp(5,prec=40) + sage: # needs sage.rings.padics + sage: R1.<a> = Zp(5, prec=20)[] + sage: R2 = Qp(5, prec=40) sage: R2(1) + a (1 + O(5^20))*a + 1 + O(5^40) sage: 1/2 + a @@ -2495,10 +2562,10 @@ def __init__(self, p, prec, extras=None): TESTS:: sage: from sage.categories.pushout import CompletionFunctor - sage: F1 = CompletionFunctor(5,100) - sage: F1(QQ) + sage: F1 = CompletionFunctor(5, 100) + sage: F1(QQ) # needs sage.rings.padics 5-adic Field with capped relative precision 100 - sage: F1(ZZ) + sage: F1(ZZ) # needs sage.rings.padics 5-adic Ring with capped relative precision 100 sage: F1.type is None True @@ -2507,9 +2574,9 @@ def __init__(self, p, prec, extras=None): sage: F2 = RR.construction()[0] sage: F2 Completion[+Infinity, prec=53] - sage: F2.type + sage: F2.type # needs sage.rings.real_mpfr 'MPFR' - sage: F2.extras + sage: F2.extras # needs sage.rings.real_mpfr {'rnd': 0, 'sci_not': False} """ Functor.__init__(self, Rings(), Rings()) @@ -2534,7 +2601,7 @@ def _repr_(self): """ TESTS:: - sage: Zp(7).construction() # indirect doctest + sage: Zp(7).construction() # indirect doctest # needs sage.rings.padics (Completion[7, prec=20], Integer Ring) sage: RR.construction() # indirect doctest @@ -2548,6 +2615,7 @@ def _apply_functor(self, R): TESTS:: + sage: # needs sage.rings.padics sage: R = Zp(5) sage: F1 = R.construction()[0] sage: F1(ZZ) is R # indirect doctest @@ -2591,8 +2659,9 @@ def __eq__(self, other): TESTS:: - sage: R1 = Zp(5,prec=30) - sage: R2 = Zp(5,prec=40) + sage: # needs sage.rings.padics + sage: R1 = Zp(5, prec=30) + sage: R2 = Zp(5, prec=40) sage: F1 = R1.construction()[0] sage: F2 = R2.construction()[0] sage: F1 == loads(dumps(F1)) # indirect doctest @@ -2616,8 +2685,9 @@ def __ne__(self, other): EXAMPLES:: - sage: R1 = Zp(5,prec=30) - sage: R2 = Zp(5,prec=40) + sage: # needs sage.rings.padics + sage: R1 = Zp(5, prec=30) + sage: R2 = Zp(5, prec=40) sage: F1 = R1.construction()[0] sage: F2 = R2.construction()[0] sage: F1 != loads(dumps(F1)) # indirect doctest @@ -2646,9 +2716,10 @@ def merge(self, other): EXAMPLES:: - sage: R1.<a> = Zp(5,prec=20)[] - sage: R2 = Qp(5,prec=40) - sage: R2(1)+a # indirect doctest + sage: # needs sage.rings.padics + sage: R1.<a> = Zp(5, prec=20)[] + sage: R2 = Qp(5, prec=40) + sage: R2(1) + a # indirect doctest (1 + O(5^20))*a + 1 + O(5^40) sage: R3 = RealField(30) sage: R4 = RealField(50) @@ -2661,25 +2732,27 @@ def merge(self, other): We check that :trac:`12353` has been resolved:: - sage: RIF(1) > RR(1) + sage: RIF(1) > RR(1) # needs sage.rings.real_interval_field Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for >: 'Real Interval Field with 53 bits of precision' and 'Real Field with 53 bits of precision' + TypeError: unsupported operand parent(s) for >: + 'Real Interval Field with 53 bits of precision' and 'Real Field with 53 bits of precision' We check that various pushouts work:: + sage: # needs sage.rings.real_interval_field sage.rings.real_mpfr sage: R0 = RealIntervalField(30) sage: R1 = RealIntervalField(30, sci_not=True) sage: R2 = RealIntervalField(53) - sage: R3 = RealIntervalField(53, sci_not = True) + sage: R3 = RealIntervalField(53, sci_not=True) sage: R4 = RealIntervalField(90) - sage: R5 = RealIntervalField(90, sci_not = True) + sage: R5 = RealIntervalField(90, sci_not=True) sage: R6 = RealField(30) sage: R7 = RealField(30, sci_not=True) - sage: R8 = RealField(53, rnd = 'RNDD') - sage: R9 = RealField(53, sci_not = True, rnd = 'RNDZ') - sage: R10 = RealField(53, sci_not = True) - sage: R11 = RealField(90, sci_not = True, rnd = 'RNDZ') + sage: R8 = RealField(53, rnd='RNDD') + sage: R9 = RealField(53, sci_not=True, rnd='RNDZ') + sage: R10 = RealField(53, sci_not=True) + sage: R11 = RealField(90, sci_not=True, rnd='RNDZ') sage: Rlist = [R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11] sage: from sage.categories.pushout import pushout sage: pushouts = [R0,R0,R0,R1,R0,R1,R0,R1,R0,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R0,R1,R2,R2,R2,R3,R0,R1,R2,R3,R3,R3,R1,R1,R3,R3,R3,R3,R1,R1,R3,R3,R3,R3,R0,R1,R2,R3,R4,R4,R0,R1,R2,R3,R3,R5,R1,R1,R3,R3,R5,R5,R1,R1,R3,R3,R3,R5,R0,R1,R0,R1,R0,R1,R6,R6,R6,R7,R7,R7,R1,R1,R1,R1,R1,R1,R7,R7,R7,R7,R7,R7,R0,R1,R2,R3,R2,R3,R6,R7,R8,R9,R10,R9,R1,R1,R3,R3,R3,R3,R7,R7,R9,R9,R10,R9,R1,R1,R3,R3,R3,R3,R7,R7,R10,R10,R10,R10,R1,R1,R3,R3,R5,R5,R7,R7,R9,R9,R10,R11] @@ -2688,6 +2761,7 @@ def merge(self, other): :: + sage: # needs sage.rings.padics sage: P0 = ZpFM(5, 10) sage: P1 = ZpFM(5, 20) sage: P2 = ZpCR(5, 10) @@ -2698,8 +2772,10 @@ def merge(self, other): sage: P7 = Qp(5, 20) sage: Plist = [P2,P3,P4,P5,P6,P7] sage: from sage.categories.pushout import pushout - sage: pushouts = [P2,P3,P4,P5,P6,P7,P3,P3,P5,P5,P7,P7,P4,P5,P4,P5,P6,P7,P5,P5,P5,P5,P7,P7,P6,P7,P6,P7,P6,P7,P7,P7,P7,P7,P7,P7] - sage: all(P is Q for P, Q in zip(pushouts, [pushout(a, b) for a in Plist for b in Plist])) + sage: pushouts = [P2,P3,P4,P5,P6,P7,P3,P3,P5,P5,P7,P7,P4,P5,P4,P5,P6,P7, + ....: P5,P5,P5,P5,P7,P7,P6,P7,P6,P7,P6,P7,P7,P7,P7,P7,P7,P7] + sage: all(P is Q + ....: for P, Q in zip(pushouts, [pushout(a, b) for a in Plist for b in Plist])) True """ if self == other: # both are Completion functors with the same p @@ -2741,9 +2817,9 @@ def commutes(self, other): EXAMPLES:: - sage: F1 = Zp(5).construction()[0] + sage: F1 = Zp(5).construction()[0] # needs sage.rings.padics sage: F2 = QQ.construction()[0] - sage: F1.commutes(F2) + sage: F1.commutes(F2) # needs sage.rings.padics True TESTS: @@ -2770,10 +2846,12 @@ def commutes(self, other): Ambiguous base extension error raised):: sage: from sage.categories.pushout import pushout - sage: pushout(Qp(7),RLF) + sage: pushout(Qp(7), RLF) # needs sage.rings.padics Traceback (most recent call last): ... - CoercionException: Don't know how to apply Completion[+Infinity, prec=+Infinity] to 7-adic Ring with capped relative precision 20 + CoercionException: Don't know how to + apply Completion[+Infinity, prec=+Infinity] + to 7-adic Ring with capped relative precision 20 """ return isinstance(other, FractionField) @@ -2791,17 +2869,19 @@ class QuotientFunctor(ConstructionFunctor): EXAMPLES:: sage: P.<x,y> = ZZ[] - sage: Q = P.quo([x^2+y^2]*P) + sage: Q = P.quo([x^2 + y^2] * P) sage: F = Q.construction()[0] sage: F(QQ['x','y']) - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) - sage: F(QQ['x','y']) == QQ['x','y'].quo([x^2+y^2]*QQ['x','y']) + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2 + y^2) + sage: F(QQ['x','y']) == QQ['x','y'].quo([x^2 + y^2] * QQ['x','y']) True sage: F(QQ['x','y','z']) Traceback (most recent call last): ... - CoercionException: Cannot apply this quotient functor to Multivariate Polynomial Ring in x, y, z over Rational Field - sage: F(QQ['y','z']) + CoercionException: Cannot apply this quotient functor to + Multivariate Polynomial Ring in x, y, z over Rational Field + sage: F(QQ['y','z']) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: Could not find a mapping of the passed element to this ring. @@ -2830,20 +2910,24 @@ def __init__(self, I, names=None, as_field=False, domain=None, sage: from sage.categories.pushout import QuotientFunctor sage: P.<t> = ZZ[] - sage: F = QuotientFunctor([5+t^2]*P) - sage: F(P) - Univariate Quotient Polynomial Ring in tbar over Integer Ring with modulus t^2 + 5 - sage: F(QQ['t']) - Univariate Quotient Polynomial Ring in tbar over Rational Field with modulus t^2 + 5 - sage: F = QuotientFunctor([5+t^2]*P,names='s') - sage: F(P) - Univariate Quotient Polynomial Ring in s over Integer Ring with modulus t^2 + 5 - sage: F(QQ['t']) - Univariate Quotient Polynomial Ring in s over Rational Field with modulus t^2 + 5 - sage: F = QuotientFunctor([5]*ZZ,as_field=True) + sage: F = QuotientFunctor([5 + t^2] * P) + sage: F(P) # needs sage.libs.pari + Univariate Quotient Polynomial Ring in tbar + over Integer Ring with modulus t^2 + 5 + sage: F(QQ['t']) # needs sage.libs.pari + Univariate Quotient Polynomial Ring in tbar + over Rational Field with modulus t^2 + 5 + sage: F = QuotientFunctor([5 + t^2] * P, names='s') + sage: F(P) # needs sage.libs.pari + Univariate Quotient Polynomial Ring in s + over Integer Ring with modulus t^2 + 5 + sage: F(QQ['t']) # needs sage.libs.pari + Univariate Quotient Polynomial Ring in s + over Rational Field with modulus t^2 + 5 + sage: F = QuotientFunctor([5] * ZZ, as_field=True) sage: F(ZZ) Finite Field of size 5 - sage: F = QuotientFunctor([5]*ZZ) + sage: F = QuotientFunctor([5] * ZZ) sage: F(ZZ) Ring of integers modulo 5 @@ -2871,11 +2955,12 @@ def _apply_functor(self, R): TESTS:: sage: P.<x,y> = ZZ[] - sage: Q = P.quo([2+x^2,3*x+y^2]) + sage: Q = P.quo([2 + x^2, 3*x + y^2]) sage: F = Q.construction()[0]; F QuotientFunctor sage: F(QQ['x','y']) # indirect doctest - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + 2, y^2 + 3*x) + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2 + 2, y^2 + 3*x) Note that the ``quo()`` method of a field used to return the integer zero. That strange behaviour was removed in github @@ -2917,6 +3002,7 @@ def __eq__(self, other): TESTS:: + sage: # needs sage.libs.pari sage: P.<x> = QQ[] sage: F = P.quo([(x^2+1)^2*(x^2-3),(x^2+1)^2*(x^5+3)]).construction()[0] sage: F == loads(dumps(F)) @@ -2930,7 +3016,7 @@ def __eq__(self, other): """ if not isinstance(other, QuotientFunctor): return False - return (type(self) == type(other) and + return (type(self) is type(other) and self.domain() == other.domain() and self.codomain() == other.codomain() and self.names == other.names and @@ -2942,6 +3028,7 @@ def __ne__(self, other): EXAMPLES:: + sage: # needs sage.libs.pari sage: P.<x> = QQ[] sage: F = P.quo([(x^2+1)^2*(x^2-3),(x^2+1)^2*(x^5+3)]).construction()[0] sage: F != loads(dumps(F)) @@ -2968,16 +3055,18 @@ def merge(self, other): EXAMPLES:: + sage: # needs sage.libs.pari sage: P.<x> = QQ[] sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)]) sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)]) sage: from sage.categories.pushout import pushout sage: pushout(Q1,Q2) # indirect doctest - Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^4 + 2*x^2 + 1 + Univariate Quotient Polynomial Ring in xbar over Rational Field + with modulus x^4 + 2*x^2 + 1 The following was fixed in :trac:`8800`:: - sage: pushout(GF(5), Integers(5)) + sage: pushout(GF(5), Integers(5)) # needs sage.libs.pari Finite Field of size 5 """ @@ -3009,13 +3098,13 @@ def merge(self, other): for k,v in self.kwds.items(): kwds[k] = v for k,v in other.kwds.items(): - if k=='category': + if k == 'category': if kwds[k] is not None: kwds[k] = v.join([v,kwds[k]]) else: kwds[k] = v continue - if k in kwds and kwds[k] is not None and v!=kwds[k]: + if k in kwds and kwds[k] is not None and v != kwds[k]: # Don't know what default to choose. Hence: No merge! return None kwds[k] = v @@ -3037,41 +3126,50 @@ class AlgebraicExtensionFunctor(ConstructionFunctor): EXAMPLES:: sage: x = polygen(QQ, 'x') - sage: K.<a> = NumberField(x^3 + x^2 + 1) - sage: F = K.construction()[0] - sage: F(ZZ['t']) - Univariate Quotient Polynomial Ring in a over Univariate Polynomial Ring in t over Integer Ring with modulus a^3 + a^2 + 1 + sage: K.<a> = NumberField(x^3 + x^2 + 1) # needs sage.rings.number_field + sage: F = K.construction()[0] # needs sage.rings.number_field + sage: F(ZZ['t']) # needs sage.rings.number_field + Univariate Quotient Polynomial Ring in a + over Univariate Polynomial Ring in t over Integer Ring + with modulus a^3 + a^2 + 1 Note that, even if a field is algebraically closed, the algebraic extension will be constructed as the quotient of a univariate polynomial ring:: - sage: F(CC) - Univariate Quotient Polynomial Ring in a over Complex Field with 53 bits of precision with modulus a^3 + a^2 + 1.00000000000000 - sage: F(RR) - Univariate Quotient Polynomial Ring in a over Real Field with 53 bits of precision with modulus a^3 + a^2 + 1.00000000000000 + sage: F(CC) # needs sage.rings.number_field + Univariate Quotient Polynomial Ring in a + over Complex Field with 53 bits of precision + with modulus a^3 + a^2 + 1.00000000000000 + sage: F(RR) # needs sage.rings.number_field + Univariate Quotient Polynomial Ring in a + over Real Field with 53 bits of precision + with modulus a^3 + a^2 + 1.00000000000000 Note that the construction functor of a number field applied to the integers returns an order (not necessarily maximal) of that field, similar to the behaviour of ``ZZ.extension(...)``:: - sage: F(ZZ) + sage: F(ZZ) # needs sage.rings.number_field Order in Number Field in a with defining polynomial x^3 + x^2 + 1 This also holds for non-absolute number fields:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ, 'x') sage: K.<a,b> = NumberField([x^3 + x^2 + 1, x^2 + x + 1]) sage: F = K.construction()[0] sage: O = F(ZZ); O - Relative Order in Number Field in a with defining polynomial x^3 + x^2 + 1 over its base field + Relative Order in Number Field in a + with defining polynomial x^3 + x^2 + 1 over its base field sage: O.ambient() is K True Special cases are made for cyclotomic fields and residue fields:: + sage: # needs sage.rings.number_field sage: C = CyclotomicField(8) - sage: F,R = C.construction() + sage: F, R = C.construction() sage: F AlgebraicExtensionFunctor sage: R @@ -3083,6 +3181,7 @@ class AlgebraicExtensionFunctor(ConstructionFunctor): :: + sage: # needs sage.rings.number_field sage: K.<z> = CyclotomicField(7) sage: P = K.factor(17)[0][0] sage: k = K.residue_field(P) @@ -3159,21 +3258,23 @@ def __init__(self, polys, names, embeddings=None, structures=None, sage: P.<x> = ZZ[] sage: F1 = AlgebraicExtensionFunctor([x^3 - x^2 + 1], ['a'], [None]) sage: F2 = AlgebraicExtensionFunctor([x^3 - x^2 + 1], ['a'], [0]) - sage: F1==F2 + sage: F1 == F2 False - sage: F1(QQ) + sage: F1(QQ) # needs sage.rings.number_field Number Field in a with defining polynomial x^3 - x^2 + 1 - sage: F1(QQ).coerce_embedding() - sage: phi = F2(QQ).coerce_embedding().__copy__(); phi + sage: F1(QQ).coerce_embedding() # needs sage.rings.number_field + sage: phi = F2(QQ).coerce_embedding().__copy__(); phi # needs sage.rings.number_field Generic morphism: - From: Number Field in a with defining polynomial x^3 - x^2 + 1 with a = -0.7548776662466928? + From: Number Field in a with defining polynomial x^3 - x^2 + 1 + with a = -0.7548776662466928? To: Real Lazy Field Defn: a -> -0.7548776662466928? - sage: F1(QQ)==F2(QQ) + sage: F1(QQ) == F2(QQ) # needs sage.rings.number_field False - sage: F1(GF(5)) - Univariate Quotient Polynomial Ring in a over Finite Field of size 5 with modulus a^3 + 4*a^2 + 1 - sage: F2(GF(5)) + sage: F1(GF(5)) # needs sage.libs.pari + Univariate Quotient Polynomial Ring in a over Finite Field of size 5 + with modulus a^3 + 4*a^2 + 1 + sage: F2(GF(5)) # needs sage.libs.pari Traceback (most recent call last): ... NotImplementedError: ring extension with prescribed embedding is not implemented @@ -3182,14 +3283,15 @@ def __init__(self, polys, names, embeddings=None, structures=None, integers, an order (not necessarily maximal) of that field is returned, similar to the behaviour of ``ZZ.extension``:: - sage: F1(ZZ) + sage: F1(ZZ) # needs sage.rings.number_field Order in Number Field in a with defining polynomial x^3 - x^2 + 1 The cyclotomic fields form a special case of number fields with prescribed embeddings:: + sage: # needs sage.rings.number_field sage: C = CyclotomicField(8) - sage: F,R = C.construction() + sage: F, R = C.construction() sage: F AlgebraicExtensionFunctor sage: R @@ -3202,6 +3304,7 @@ def __init__(self, polys, names, embeddings=None, structures=None, The data stored in this construction includes structural morphisms of number fields (see :trac:`20826`):: + sage: # needs sage.rings.number_field sage: R.<x> = ZZ[] sage: K.<a> = NumberField(x^2 - 3) sage: L0.<b> = K.change_names() @@ -3256,21 +3359,26 @@ def _apply_functor(self, R): TESTS:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 + x^2 + 1) sage: F = K.construction()[0] sage: F(ZZ) # indirect doctest Order in Number Field in a with defining polynomial x^3 + x^2 + 1 sage: F(ZZ['t']) # indirect doctest - Univariate Quotient Polynomial Ring in a over Univariate Polynomial Ring in t over Integer Ring with modulus a^3 + a^2 + 1 + Univariate Quotient Polynomial Ring in a over + Univariate Polynomial Ring in t over Integer Ring with modulus a^3 + a^2 + 1 sage: F(RR) # indirect doctest - Univariate Quotient Polynomial Ring in a over Real Field with 53 bits of precision with modulus a^3 + a^2 + 1.00000000000000 + Univariate Quotient Polynomial Ring in a over + Real Field with 53 bits of precision with modulus a^3 + a^2 + 1.00000000000000 Check that :trac:`13538` is fixed:: - sage: K = Qp(3,3) + sage: # needs sage.rings.padics + sage: from sage.categories.pushout import AlgebraicExtensionFunctor + sage: K = Qp(3, 3) sage: R.<a> = K[] - sage: AEF = sage.categories.pushout.AlgebraicExtensionFunctor([a^2-3], ['a'], [None]) + sage: AEF = AlgebraicExtensionFunctor([a^2 - 3], ['a'], [None]) sage: AEF(K) 3-adic Eisenstein Extension Field in a defined by a^2 - 3 @@ -3301,20 +3409,21 @@ def __eq__(self, other): TESTS:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 + x^2 + 1) sage: F = K.construction()[0] sage: F == loads(dumps(F)) True - sage: K2.<a> = NumberField(x^3 + x^2 + 1, latex_names='a') - sage: F2 = K2.construction()[0] - sage: F2 == F + sage: K2.<a> = NumberField(x^3 + x^2 + 1, latex_names='a') # needs sage.rings.number_field + sage: F2 = K2.construction()[0] # needs sage.rings.number_field + sage: F2 == F # needs sage.rings.number_field True - sage: K3.<a> = NumberField(x^3 + x^2 + 1, latex_names='alpha') - sage: F3 = K3.construction()[0] - sage: F3 == F + sage: K3.<a> = NumberField(x^3 + x^2 + 1, latex_names='alpha') # needs sage.rings.number_field + sage: F3 = K3.construction()[0] # needs sage.rings.number_field + sage: F3 == F # needs sage.rings.number_field False """ if not isinstance(other, AlgebraicExtensionFunctor): @@ -3333,9 +3442,9 @@ def __ne__(self, other): EXAMPLES:: sage: x = polygen(QQ, 'x') - sage: K.<a> = NumberField(x^3 + x^2 + 1) - sage: F = K.construction()[0] - sage: F != loads(dumps(F)) + sage: K.<a> = NumberField(x^3 + x^2 + 1) # needs sage.rings.number_field + sage: F = K.construction()[0] # needs sage.rings.number_field + sage: F != loads(dumps(F)) # needs sage.rings.number_field False """ return not (self == other) @@ -3379,15 +3488,16 @@ def merge(self, other): The following demonstrate coercions for finite fields using Conway or pseudo-Conway polynomials:: - sage: k = GF(3^2, prefix='z'); a = k.gen() - sage: l = GF(3^3, prefix='z'); b = l.gen() - sage: a + b # indirect doctest + sage: k = GF(3^2, prefix='z'); a = k.gen() # needs sage.rings.finite_rings + sage: l = GF(3^3, prefix='z'); b = l.gen() # needs sage.rings.finite_rings + sage: a + b # indirect doctest # needs sage.rings.finite_rings z6^5 + 2*z6^4 + 2*z6^3 + z6^2 + 2*z6 + 1 Note that embeddings are compatible in lattices of such finite fields:: + sage: # needs sage.rings.finite_rings sage: m = GF(3^5, prefix='z'); c = m.gen() - sage: (a+b)+c == a+(b+c) # indirect doctest + sage: (a + b) + c == a + (b + c) # indirect doctest True sage: from sage.categories.pushout import pushout sage: n = pushout(k, l) @@ -3398,17 +3508,21 @@ def merge(self, other): Coercion is also available for number fields:: + sage: # needs sage.rings.number_field sage: P.<x> = QQ[] - sage: L.<b> = NumberField(x^8-x^4+1, embedding=CDF.0) - sage: M1.<c1> = NumberField(x^2+x+1, embedding=b^4-1) - sage: M2.<c2> = NumberField(x^2+1, embedding=-b^6) + sage: L.<b> = NumberField(x^8 - x^4 + 1, embedding=CDF.0) + sage: M1.<c1> = NumberField(x^2 + x + 1, embedding=b^4 - 1) + sage: M2.<c2> = NumberField(x^2 + 1, embedding=-b^6) sage: M1.coerce_map_from(M2) sage: M2.coerce_map_from(M1) - sage: c1+c2; parent(c1+c2) #indirect doctest + sage: c1 + c2; parent(c1 + c2) #indirect doctest -b^6 + b^4 - 1 - Number Field in b with defining polynomial x^8 - x^4 + 1 with b = -0.2588190451025208? + 0.9659258262890683?*I - sage: pushout(M1['x'],M2['x']) - Univariate Polynomial Ring in x over Number Field in b with defining polynomial x^8 - x^4 + 1 with b = -0.2588190451025208? + 0.9659258262890683?*I + Number Field in b with defining polynomial x^8 - x^4 + 1 + with b = -0.2588190451025208? + 0.9659258262890683?*I + sage: pushout(M1['x'], M2['x']) # needs sage.rings.finite_rings + Univariate Polynomial Ring in x + over Number Field in b with defining polynomial x^8 - x^4 + 1 + with b = -0.2588190451025208? + 0.9659258262890683?*I In the previous example, the number field ``L`` becomes the pushout of ``M1`` and ``M2`` since both are provided with an embedding into @@ -3416,16 +3530,19 @@ def merge(self, other): are embedded into a field that is not a numberfield, no merging occurs:: + sage: # needs sage.rings.complex_double sage.rings.number_field sage: cbrt2 = CDF(2)^(1/3) sage: zeta3 = CDF.zeta(3) - sage: K.<a> = NumberField(x^3-2, embedding=cbrt2 * zeta3) - sage: L.<b> = NumberField(x^6-2, embedding=1.1) + sage: K.<a> = NumberField(x^3 - 2, embedding=cbrt2 * zeta3) + sage: L.<b> = NumberField(x^6 - 2, embedding=1.1) sage: L.coerce_map_from(K) sage: K.coerce_map_from(L) - sage: pushout(K,L) + sage: pushout(K, L) # needs sage.rings.finite_rings Traceback (most recent call last): ... - CoercionException: ('Ambiguous Base Extension', Number Field in a with defining polynomial x^3 - 2 with a = -0.6299605249474365? + 1.091123635971722?*I, Number Field in b with defining polynomial x^6 - 2 with b = 1.122462048309373?) + CoercionException: ('Ambiguous Base Extension', Number Field in a with + defining polynomial x^3 - 2 with a = -0.6299605249474365? + 1.091123635971722?*I, + Number Field in b with defining polynomial x^6 - 2 with b = 1.122462048309373?) """ if isinstance(other, AlgebraicClosureFunctor): @@ -3462,8 +3579,8 @@ def merge(self, other): # nothing else helps, hence, we move to the pushout of the codomains of the embeddings try: P = pushout(self.embeddings[0].parent(), other.embeddings[0].parent()) - from sage.rings.number_field.number_field import is_NumberField - if is_NumberField(P): + from sage.rings.number_field.number_field_base import NumberField + if isinstance(P, NumberField): return P.construction()[0] except CoercionException: return None @@ -3494,11 +3611,12 @@ def __mul__(self, other): TESTS:: + sage: # needs sage.rings.number_field sage: P.<x> = QQ[] - sage: K.<a> = NumberField(x^3-5,embedding=0) - sage: L.<b> = K.extension(x^2+a) - sage: F,R = L.construction() - sage: prod(F.expand())(R) == L #indirect doctest + sage: K.<a> = NumberField(x^3 - 5, embedding=0) + sage: L.<b> = K.extension(x^2 + a) + sage: F, R = L.construction() + sage: prod(F.expand())(R) == L #indirect doctest True """ @@ -3526,13 +3644,14 @@ def expand(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: P.<x> = QQ[] - sage: K.<a> = NumberField(x^3-5,embedding=0) - sage: L.<b> = K.extension(x^2+a) - sage: F,R = L.construction() + sage: K.<a> = NumberField(x^3 - 5, embedding=0) + sage: L.<b> = K.extension(x^2 + a) + sage: F, R = L.construction() sage: prod(F.expand())(R) == L True - sage: K = NumberField([x^2-2, x^2-3],'a') + sage: K = NumberField([x^2 - 2, x^2 - 3],'a') sage: F, R = K.construction() sage: F AlgebraicExtensionFunctor @@ -3557,10 +3676,11 @@ class AlgebraicClosureFunctor(ConstructionFunctor): EXAMPLES:: + sage: # needs sage.rings.complex_double sage.rings.number_field sage: F = CDF.construction()[0] sage: F(QQ) Algebraic Field - sage: F(RR) + sage: F(RR) # needs sage.rings.real_mpfr Complex Field with 53 bits of precision sage: F(F(QQ)) is F(QQ) True @@ -3574,9 +3694,9 @@ def __init__(self): sage: from sage.categories.pushout import AlgebraicClosureFunctor sage: F = AlgebraicClosureFunctor() - sage: F(QQ) + sage: F(QQ) # needs sage.rings.number_field Algebraic Field - sage: F(RR) + sage: F(RR) # needs sage.rings.real_mpfr Complex Field with 53 bits of precision sage: F == loads(dumps(F)) True @@ -3590,8 +3710,8 @@ def _apply_functor(self, R): TESTS:: - sage: F = CDF.construction()[0] - sage: F(QQ) # indirect doctest + sage: F = CDF.construction()[0] # needs sage.rings.complex_double + sage: F(QQ) # indirect doctest # needs sage.rings.complex_double sage.rings.number_field Algebraic Field """ try: @@ -3611,10 +3731,10 @@ def merge(self, other): TESTS:: sage: x = polygen(QQ, 'x') - sage: K.<a> = NumberField(x^3+x^2+1) - sage: CDF.construction()[0].merge(K.construction()[0]) is None + sage: K.<a> = NumberField(x^3 + x^2 + 1) # needs sage.rings.number_field + sage: CDF.construction()[0].merge(K.construction()[0]) is None # needs sage.rings.number_field True - sage: CDF.construction()[0].merge(CDF.construction()[0]) + sage: CDF.construction()[0].merge(CDF.construction()[0]) # needs sage.rings.complex_double AlgebraicClosureFunctor """ @@ -3637,7 +3757,8 @@ def __init__(self, gens, domain): EXAMPLES:: sage: from sage.categories.pushout import PermutationGroupFunctor - sage: PF = PermutationGroupFunctor([PermutationGroupElement([(1,2)])], [1,2]); PF + sage: PF = PermutationGroupFunctor([PermutationGroupElement([(1,2)])], # needs sage.groups + ....: [1,2]); PF PermutationGroupFunctor[(1,2)] """ Functor.__init__(self, Groups(), Groups()) @@ -3648,9 +3769,9 @@ def _repr_(self): """ EXAMPLES:: - sage: P1 = PermutationGroup([[(1,2)]]) - sage: PF, P = P1.construction() - sage: PF + sage: P1 = PermutationGroup([[(1,2)]]) # needs sage.groups + sage: PF, P = P1.construction() # needs sage.groups + sage: PF # needs sage.groups PermutationGroupFunctor[(1,2)] """ return "PermutationGroupFunctor%s" % list(self.gens()) @@ -3659,9 +3780,9 @@ def __call__(self, R): """ EXAMPLES:: - sage: P1 = PermutationGroup([[(1,2)]]) - sage: PF, P = P1.construction() - sage: PF(P) + sage: P1 = PermutationGroup([[(1,2)]]) # needs sage.groups + sage: PF, P = P1.construction() # needs sage.groups + sage: PF(P) # needs sage.groups Permutation Group with generators [(1,2)] """ from sage.groups.perm_gps.permgroup import PermutationGroup @@ -3672,9 +3793,9 @@ def gens(self): """ EXAMPLES:: - sage: P1 = PermutationGroup([[(1,2)]]) - sage: PF, P = P1.construction() - sage: PF.gens() + sage: P1 = PermutationGroup([[(1,2)]]) # needs sage.groups + sage: PF, P = P1.construction() # needs sage.groups + sage: PF.gens() # needs sage.groups ((1,2),) """ return self._gens @@ -3685,6 +3806,7 @@ def merge(self, other): EXAMPLES:: + sage: # needs sage.groups sage: P1 = PermutationGroup([[(1,2)]]) sage: PF1, P = P1.construction() sage: P2 = PermutationGroup([[(1,3)]]) @@ -3735,6 +3857,7 @@ class EquivariantSubobjectConstructionFunctor(ConstructionFunctor): column (index 1); the order of the extra element 2 in a permutation determines whether it is a symmetry or an antisymmetry:: + sage: # needs sage.groups sage.modules sage: GSym01 = PermutationGroup([[(0,1),(2,),(3,)]]); GSym01 Permutation Group with generators [(0,1)] sage: GASym01 = PermutationGroup([[(0,1),(2,3)]]); GASym01 @@ -3773,7 +3896,8 @@ class EquivariantSubobjectConstructionFunctor(ConstructionFunctor): [1 0] [0 1] [0 0] [0 0], [1 0], [0 1] ] - sage: ASym01 = M.parent().invariant_module(GASym01, action=GASym01_action); ASym01 + sage: ASym01 = M.parent().invariant_module(GASym01, action=GASym01_action) + sage: ASym01 (Permutation Group with generators [(0,1)(2,3)])-invariant submodule of Full MatrixSpace of 2 by 2 dense matrices over Integer Ring sage: list(ASym01.basis()) @@ -3793,6 +3917,7 @@ def __init__(self, S, action=operator.mul, side='left', """ EXAMPLES:: + sage: # needs sage.groups sage.modules sage: G = SymmetricGroup(3); G.rename('S3') sage: M = FreeModule(ZZ, [1,2,3], prefix='M'); M.rename('M') sage: action = lambda g, x: M.term(g(x)) @@ -3817,13 +3942,13 @@ def _apply_functor(self, X): TESTS:: sage: from sage.categories.pushout import EquivariantSubobjectConstructionFunctor - sage: M2 = MatrixSpace(QQ, 2); M2 + sage: M2 = MatrixSpace(QQ, 2); M2 # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: F = EquivariantSubobjectConstructionFunctor(M2, - ....: operator.mul, 'left', - ....: operator.mul, 'right'); F + sage: F = EquivariantSubobjectConstructionFunctor(M2, # needs sage.modules + ....: operator.mul, 'left', + ....: operator.mul, 'right'); F EquivariantSubobjectConstructionFunctor - sage: F(M2) + sage: F(M2) # needs sage.modules Traceback (most recent call last): ... NotImplementedError: non-trivial other_action=<built-in function mul> is not implemented @@ -3846,20 +3971,20 @@ class BlackBoxConstructionFunctor(ConstructionFunctor): sage: FS = BlackBoxConstructionFunctor(singular) sage: FG BlackBoxConstructionFunctor - sage: FG(ZZ) + sage: FG(ZZ) # needs sage.libs.gap Integers - sage: FG(ZZ).parent() + sage: FG(ZZ).parent() # needs sage.libs.gap Gap - sage: FS(QQ['t']) + sage: FS(QQ['t']) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 // block 1 : ordering lp // : names t // block 2 : ordering C - sage: FG == FS + sage: FG == FS # needs sage.libs.gap sage.libs.singular False - sage: FG == loads(dumps(FG)) + sage: FG == loads(dumps(FG)) # needs sage.libs.gap True """ rank = 100 @@ -3870,10 +3995,10 @@ def __init__(self, box): sage: from sage.categories.pushout import BlackBoxConstructionFunctor sage: FG = BlackBoxConstructionFunctor(gap) - sage: FM = BlackBoxConstructionFunctor(maxima) # optional - sage.symbolic - sage: FM == FG # optional - sage.symbolic + sage: FM = BlackBoxConstructionFunctor(maxima) # needs sage.symbolic + sage: FM == FG # needs sage.libs.gap sage.symbolic False - sage: FM == loads(dumps(FM)) # optional - sage.symbolic + sage: FM == loads(dumps(FM)) # needs sage.symbolic True """ ConstructionFunctor.__init__(self, Objects(), Objects()) @@ -3890,7 +4015,7 @@ def _apply_functor(self, R): sage: from sage.categories.pushout import BlackBoxConstructionFunctor sage: f = lambda x: x^2 sage: F = BlackBoxConstructionFunctor(f) - sage: F(ZZ) # indirect doctest + sage: F(ZZ) # indirect doctest # needs sage.modules Ambient free module of rank 2 over the principal ideal domain Integer Ring """ @@ -3902,10 +4027,10 @@ def __eq__(self, other): sage: from sage.categories.pushout import BlackBoxConstructionFunctor sage: FG = BlackBoxConstructionFunctor(gap) - sage: FM = BlackBoxConstructionFunctor(maxima) # optional - sage.symbolic - sage: FM == FG # indirect doctest # optional - sage.symbolic + sage: FM = BlackBoxConstructionFunctor(maxima) # needs sage.symbolic + sage: FM == FG # indirect doctest # needs sage.libs.gap sage.symbolic False - sage: FM == loads(dumps(FM)) # optional - sage.symbolic + sage: FM == loads(dumps(FM)) # needs sage.symbolic True """ if not isinstance(other, BlackBoxConstructionFunctor): @@ -3921,10 +4046,10 @@ def __ne__(self, other): sage: from sage.categories.pushout import BlackBoxConstructionFunctor sage: FG = BlackBoxConstructionFunctor(gap) - sage: FM = BlackBoxConstructionFunctor(maxima) # optional - sage.symbolic - sage: FM != FG # indirect doctest # optional - sage.symbolic + sage: FM = BlackBoxConstructionFunctor(maxima) # needs sage.symbolic + sage: FM != FG # indirect doctest # needs sage.libs.gap sage.symbolic True - sage: FM != loads(dumps(FM)) # optional - sage.symbolic + sage: FM != loads(dumps(FM)) # needs sage.symbolic False """ return not (self == other) @@ -3983,16 +4108,19 @@ def pushout(R, S): which give us `Frac(Poly_x(Complete_7(Frac(\ZZ))))`:: sage: from sage.categories.pushout import pushout - sage: pushout(Qp(7), Frac(ZZ['x'])) - Fraction Field of Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 20 + sage: pushout(Qp(7), Frac(ZZ['x'])) # needs sage.rings.padics + Fraction Field of Univariate Polynomial Ring in x + over 7-adic Field with capped relative precision 20 Note we get the same thing with :: - sage: pushout(Zp(7), Frac(QQ['x'])) - Fraction Field of Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 20 - sage: pushout(Zp(7)['x'], Frac(QQ['x'])) - Fraction Field of Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 20 + sage: pushout(Zp(7), Frac(QQ['x'])) # needs sage.rings.padics + Fraction Field of Univariate Polynomial Ring in x + over 7-adic Field with capped relative precision 20 + sage: pushout(Zp(7)['x'], Frac(QQ['x'])) # needs sage.rings.padics + Fraction Field of Univariate Polynomial Ring in x + over 7-adic Field with capped relative precision 20 Note that polynomial variable ordering must be unambiguously determined. :: @@ -4000,29 +4128,38 @@ def pushout(R, S): sage: pushout(ZZ['x,y,z'], QQ['w,z,t']) Traceback (most recent call last): ... - CoercionException: ('Ambiguous Base Extension', Multivariate Polynomial Ring in x, y, z over Integer Ring, Multivariate Polynomial Ring in w, z, t over Rational Field) + CoercionException: ('Ambiguous Base Extension', + Multivariate Polynomial Ring in x, y, z over Integer Ring, + Multivariate Polynomial Ring in w, z, t over Rational Field) sage: pushout(ZZ['x,y,z'], QQ['w,x,z,t']) Multivariate Polynomial Ring in w, x, y, z, t over Rational Field Some other examples:: - sage: pushout(Zp(7)['y'], Frac(QQ['t'])['x,y,z']) - Multivariate Polynomial Ring in x, y, z over Fraction Field of Univariate Polynomial Ring in t over 7-adic Field with capped relative precision 20 + sage: pushout(Zp(7)['y'], Frac(QQ['t'])['x,y,z']) # needs sage.rings.padics + Multivariate Polynomial Ring in x, y, z + over Fraction Field of Univariate Polynomial Ring in t + over 7-adic Field with capped relative precision 20 sage: pushout(ZZ['x,y,z'], Frac(ZZ['x'])['y']) - Multivariate Polynomial Ring in y, z over Fraction Field of Univariate Polynomial Ring in x over Integer Ring - sage: pushout(MatrixSpace(RDF, 2, 2), Frac(ZZ['x'])) - Full MatrixSpace of 2 by 2 dense matrices over Fraction Field of Univariate Polynomial Ring in x over Real Double Field - sage: pushout(ZZ, MatrixSpace(ZZ[['x']], 3, 3)) - Full MatrixSpace of 3 by 3 dense matrices over Power Series Ring in x over Integer Ring + Multivariate Polynomial Ring in y, z + over Fraction Field of Univariate Polynomial Ring in x over Integer Ring + sage: pushout(MatrixSpace(RDF, 2, 2), Frac(ZZ['x'])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices + over Fraction Field of Univariate Polynomial Ring in x over Real Double Field + sage: pushout(ZZ, MatrixSpace(ZZ[['x']], 3, 3)) # needs sage.modules + Full MatrixSpace of 3 by 3 dense matrices + over Power Series Ring in x over Integer Ring sage: pushout(QQ['x,y'], ZZ[['x']]) - Univariate Polynomial Ring in y over Power Series Ring in x over Rational Field + Univariate Polynomial Ring in y + over Power Series Ring in x over Rational Field sage: pushout(Frac(ZZ['x']), QQ[['x']]) Laurent Series Ring in x over Rational Field - A construction with ``coercion_reversed = True`` (currently only + A construction with ``coercion_reversed=True`` (currently only the :class:`SubspaceFunctor` construction) is only applied if it leads to a valid coercion:: + sage: # needs sage.modules sage: A = ZZ^2 sage: V = span([[1, 2]], QQ) sage: P = sage.categories.pushout.pushout(A, V) @@ -4031,6 +4168,7 @@ def pushout(R, S): sage: P.has_coerce_map_from(A) True + sage: # needs sage.modules sage: V = (QQ^3).span([[1, 2, 3/4]]) sage: A = ZZ^3 sage: pushout(A, V) @@ -4042,7 +4180,7 @@ def pushout(R, S): [1 2 0] [0 0 1] - Some more tests with ``coercion_reversed = True``:: + Some more tests with ``coercion_reversed=True``:: sage: from sage.categories.pushout import ConstructionFunctor sage: class EvenPolynomialRing(type(QQ['x'])): @@ -4066,25 +4204,29 @@ def pushout(R, S): Even Power Univariate Polynomial Ring in x over Rational Field sage: pushout(EvenPolynomialRing(QQ, 'x'), QQ) Even Power Univariate Polynomial Ring in x over Rational Field - sage: pushout(EvenPolynomialRing(QQ, 'x'), RR) + sage: pushout(EvenPolynomialRing(QQ, 'x'), RR) # needs sage.rings.real_mpfr Even Power Univariate Polynomial Ring in x over Real Field with 53 bits of precision sage: pushout(EvenPolynomialRing(QQ, 'x'), ZZ['x']) Univariate Polynomial Ring in x over Rational Field sage: pushout(EvenPolynomialRing(QQ, 'x'), QQ['x']) Univariate Polynomial Ring in x over Rational Field - sage: pushout(EvenPolynomialRing(QQ, 'x'), RR['x']) + sage: pushout(EvenPolynomialRing(QQ, 'x'), RR['x']) # needs sage.rings.real_mpfr Univariate Polynomial Ring in x over Real Field with 53 bits of precision sage: pushout(EvenPolynomialRing(QQ, 'x'), EvenPolynomialRing(QQ, 'x')) Even Power Univariate Polynomial Ring in x over Rational Field - sage: pushout(EvenPolynomialRing(QQ, 'x'), EvenPolynomialRing(RR, 'x')) + sage: pushout(EvenPolynomialRing(QQ, 'x'), EvenPolynomialRing(RR, 'x')) # needs sage.rings.real_mpfr Even Power Univariate Polynomial Ring in x over Real Field with 53 bits of precision - sage: pushout(EvenPolynomialRing(QQ, 'x')^2, RR^2) - Ambient free module of rank 2 over the principal ideal domain Even Power Univariate Polynomial Ring in x over Real Field with 53 bits of precision - sage: pushout(EvenPolynomialRing(QQ, 'x')^2, RR['x']^2) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Real Field with 53 bits of precision + sage: pushout(EvenPolynomialRing(QQ, 'x')^2, RR^2) # needs sage.modules sage.rings.real_mpfr + Ambient free module of rank 2 + over the principal ideal domain Even Power Univariate Polynomial Ring in x + over Real Field with 53 bits of precision + sage: pushout(EvenPolynomialRing(QQ, 'x')^2, RR['x']^2) # needs sage.modules sage.rings.real_mpfr + Ambient free module of rank 2 + over the principal ideal domain Univariate Polynomial Ring in x + over Real Field with 53 bits of precision Some more tests related to univariate/multivariate constructions. We consider a generalization of polynomial rings, @@ -4152,7 +4294,8 @@ def pushout(R, S): sage: pushout(GP_ZZ(ZZ), GP_ZZ(QQ)) Generalized Polynomial Ring in X^(Integer Ring) over Rational Field sage: pushout(GP_ZZ(ZZ['t']), GP_ZZ(QQ)) - Generalized Polynomial Ring in X^(Integer Ring) over Univariate Polynomial Ring in t over Rational Field + Generalized Polynomial Ring in X^(Integer Ring) + over Univariate Polynomial Ring in t over Rational Field sage: pushout(GP_ZZ(ZZ['a,b']), GP_ZZ(ZZ['b,c'])) Generalized Polynomial Ring in X^(Integer Ring) over Multivariate Polynomial Ring in a, b, c over Integer Ring @@ -4196,14 +4339,17 @@ def pushout(R, S): ... CoercionException: ('Ambiguous Base Extension', ...) sage: pushout(GP_ZZt(ZZ['a,b']), GP_QQ(ZZ['b,c'])) - Generalized Polynomial Ring in X^(Univariate Polynomial Ring in t over Rational Field) + Generalized Polynomial Ring + in X^(Univariate Polynomial Ring in t over Rational Field) over Multivariate Polynomial Ring in a, b, c over Integer Ring Some tests with Cartesian products:: sage: from sage.sets.cartesian_product import CartesianProduct - sage: A = CartesianProduct((ZZ['x'], QQ['y'], QQ['z']), Sets().CartesianProducts()) - sage: B = CartesianProduct((ZZ['x'], ZZ['y'], ZZ['t']['z']), Sets().CartesianProducts()) + sage: A = CartesianProduct((ZZ['x'], QQ['y'], QQ['z']), + ....: Sets().CartesianProducts()) + sage: B = CartesianProduct((ZZ['x'], ZZ['y'], ZZ['t']['z']), + ....: Sets().CartesianProducts()) sage: A.construction() (The cartesian_product functorial construction, (Univariate Polynomial Ring in x over Integer Ring, @@ -4213,7 +4359,8 @@ def pushout(R, S): The Cartesian product of (Univariate Polynomial Ring in x over Integer Ring, Univariate Polynomial Ring in y over Rational Field, - Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field) + Univariate Polynomial Ring in z over + Univariate Polynomial Ring in t over Rational Field) sage: pushout(ZZ, cartesian_product([ZZ, QQ])) Traceback (most recent call last): ... @@ -4225,10 +4372,12 @@ def pushout(R, S): sage: from sage.sets.cartesian_product import CartesianProduct sage: class CartesianProductPoly(CartesianProduct): ....: def __init__(self, polynomial_rings): - ....: sort = sorted(polynomial_rings, key=lambda P: P.variable_name()) + ....: sort = sorted(polynomial_rings, + ....: key=lambda P: P.variable_name()) ....: super().__init__(sort, Sets().CartesianProducts()) ....: def vars(self): - ....: return tuple(P.variable_name() for P in self.cartesian_factors()) + ....: return tuple(P.variable_name() + ....: for P in self.cartesian_factors()) ....: def _pushout_(self, other): ....: if isinstance(other, CartesianProductPoly): ....: s_vars = self.vars() @@ -4262,7 +4411,7 @@ def pushout(R, S): (Univariate Polynomial Ring in x over Integer Ring, Univariate Polynomial Ring in y over Integer Ring, Univariate Polynomial Ring in z over Integer Ring) - sage: pushout(CartesianProductPoly((QQ['a,b']['x'], QQ['y'])), # optional - sage.symbolic + sage: pushout(CartesianProductPoly((QQ['a,b']['x'], QQ['y'])), # needs sage.symbolic ....: CartesianProductPoly((ZZ['b,c']['x'], SR['z']))) The Cartesian product of (Univariate Polynomial Ring in x over @@ -4475,14 +4624,16 @@ def pushout_lattice(R, S): EXAMPLES:: sage: from sage.categories.pushout import pushout_lattice - sage: A, B = pushout_lattice(Qp(7), Frac(ZZ['x'])) - sage: A.codomain() - Fraction Field of Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 20 - sage: A.codomain() is B.codomain() + sage: A, B = pushout_lattice(Qp(7), Frac(ZZ['x'])) # needs sage.rings.padics + sage: A.codomain() # needs sage.rings.padics + Fraction Field of Univariate Polynomial Ring in x + over 7-adic Field with capped relative precision 20 + sage: A.codomain() is B.codomain() # needs sage.rings.padics True - sage: A, B = pushout_lattice(ZZ, MatrixSpace(ZZ[['x']], 3, 3)) - sage: B - Identity endomorphism of Full MatrixSpace of 3 by 3 dense matrices over Power Series Ring in x over Integer Ring + sage: A, B = pushout_lattice(ZZ, MatrixSpace(ZZ[['x']], 3, 3)) # needs sage.modules + sage: B # needs sage.modules + Identity endomorphism of Full MatrixSpace of 3 by 3 dense matrices + over Power Series Ring in x over Integer Ring AUTHOR: @@ -4651,8 +4802,13 @@ def construction_tower(R): EXAMPLES:: sage: from sage.categories.pushout import construction_tower - sage: construction_tower(MatrixSpace(FractionField(QQ['t']),2)) - [(None, Full MatrixSpace of 2 by 2 dense matrices over Fraction Field of Univariate Polynomial Ring in t over Rational Field), (MatrixFunctor, Fraction Field of Univariate Polynomial Ring in t over Rational Field), (FractionField, Univariate Polynomial Ring in t over Rational Field), (Poly[t], Rational Field), (FractionField, Integer Ring)] + sage: construction_tower(MatrixSpace(FractionField(QQ['t']), 2)) # needs sage.modules + [(None, Full MatrixSpace of 2 by 2 dense matrices over Fraction Field + of Univariate Polynomial Ring in t over Rational Field), + (MatrixFunctor, Fraction Field + of Univariate Polynomial Ring in t over Rational Field), + (FractionField, Univariate Polynomial Ring in t over Rational Field), + (Poly[t], Rational Field), (FractionField, Integer Ring)] """ tower = [(None, R)] @@ -4690,7 +4846,8 @@ def expand_tower(tower): (FractionField, Integer Ring)] sage: expand_tower(construction_tower(QQ['x,y,z'])) [(None, Multivariate Polynomial Ring in x, y, z over Rational Field), - (MPoly[z], Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field), + (MPoly[z], Univariate Polynomial Ring in y + over Univariate Polynomial Ring in x over Rational Field), (MPoly[y], Univariate Polynomial Ring in x over Rational Field), (MPoly[x], Rational Field), (FractionField, Integer Ring)] @@ -4727,7 +4884,7 @@ def type_to_parent(P): Integer Ring sage: type_to_parent(float) Real Double Field - sage: type_to_parent(complex) + sage: type_to_parent(complex) # needs sage.rings.complex_double Complex Double Field sage: type_to_parent(list) Traceback (most recent call last): diff --git a/src/sage/categories/quantum_group_representations.py b/src/sage/categories/quantum_group_representations.py index 125f06c03fa..fc8a4697941 100644 --- a/src/sage/categories/quantum_group_representations.py +++ b/src/sage/categories/quantum_group_representations.py @@ -38,7 +38,7 @@ def super_categories(self): sage: from sage.categories.quantum_group_representations import QuantumGroupRepresentations sage: QuantumGroupRepresentations(ZZ['q'].fraction_field()).super_categories() [Category of vector spaces over - Fraction Field of Univariate Polynomial Ring in q over Integer Ring] + Fraction Field of Univariate Polynomial Ring in q over Integer Ring] """ return [Modules(self.base_ring())] @@ -51,7 +51,7 @@ def example(self): sage: from sage.categories.quantum_group_representations import QuantumGroupRepresentations sage: Cat = QuantumGroupRepresentations(ZZ['q'].fraction_field()) - sage: Cat.example() + sage: Cat.example() # needs sage.combinat sage.modules V((2, 1, 0)) """ from sage.algebras.quantum_groups.representations import AdjointRepresentation @@ -79,7 +79,7 @@ def extra_super_categories(self): sage: Cat = QuantumGroupRepresentations(ZZ['q'].fraction_field()) sage: Cat.WithBasis().TensorProducts().extra_super_categories() [Category of quantum group representations with basis over - Fraction Field of Univariate Polynomial Ring in q over Integer Ring] + Fraction Field of Univariate Polynomial Ring in q over Integer Ring] """ return [self.base_category()] @@ -96,8 +96,9 @@ def e_on_basis(self, i, b): EXAMPLES:: - sage: from sage.algebras.quantum_groups.representations import \ - ....: MinusculeRepresentation, AdjointRepresentation + sage: # needs sage.combinat sage.modules + sage: from sage.algebras.quantum_groups.representations import ( + ....: MinusculeRepresentation, AdjointRepresentation) sage: R = ZZ['q'].fraction_field() sage: CM = crystals.Tableaux(['D',4], shape=[1]) sage: VM = MinusculeRepresentation(R, CM) @@ -146,8 +147,9 @@ def f_on_basis(self, i, b): EXAMPLES:: - sage: from sage.algebras.quantum_groups.representations import \ - ....: MinusculeRepresentation, AdjointRepresentation + sage: # needs sage.combinat sage.modules + sage: from sage.algebras.quantum_groups.representations import ( + ....: MinusculeRepresentation, AdjointRepresentation) sage: R = ZZ['q'].fraction_field() sage: KM = crystals.KirillovReshetikhin(['B',3,1], 3,1) sage: VM = MinusculeRepresentation(R, KM) @@ -209,8 +211,9 @@ def K_on_basis(self, i, b, power=1): EXAMPLES:: - sage: from sage.algebras.quantum_groups.representations import \ - ....: MinusculeRepresentation, AdjointRepresentation + sage: # needs sage.combinat sage.modules + sage: from sage.algebras.quantum_groups.representations import ( + ....: MinusculeRepresentation, AdjointRepresentation) sage: R = ZZ['q'].fraction_field() sage: CM = crystals.Tableaux(['A',2], shape=[1]) sage: VM = MinusculeRepresentation(R, CM) @@ -241,8 +244,9 @@ def tensor(*factors): EXAMPLES:: - sage: from sage.algebras.quantum_groups.representations import \ - ....: MinusculeRepresentation, AdjointRepresentation + sage: # needs sage.combinat sage.modules + sage: from sage.algebras.quantum_groups.representations import ( + ....: MinusculeRepresentation, AdjointRepresentation) sage: R = ZZ['q'].fraction_field() sage: CM = crystals.Tableaux(['D',4], shape=[1]) sage: CA = crystals.Tableaux(['D',4], shape=[1,1]) @@ -279,6 +283,7 @@ def e(self, i): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: from sage.algebras.quantum_groups.representations import AdjointRepresentation sage: C = crystals.Tableaux(['G',2], shape=[1,1]) sage: R = ZZ['q'].fraction_field() @@ -305,6 +310,7 @@ def f(self, i): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: from sage.algebras.quantum_groups.representations import AdjointRepresentation sage: K = crystals.KirillovReshetikhin(['D',4,1], 2,1) sage: R = ZZ['q'].fraction_field() @@ -338,6 +344,7 @@ def K(self, i, power=1): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: from sage.algebras.quantum_groups.representations import AdjointRepresentation sage: K = crystals.KirillovReshetikhin(['D',4,2], 1,1) sage: R = ZZ['q'].fraction_field() @@ -388,6 +395,7 @@ def cartan_type(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: from sage.algebras.quantum_groups.representations import MinusculeRepresentation sage: C = crystals.Tableaux(['C',2], shape=[1]) sage: R = ZZ['q'].fraction_field() @@ -407,8 +415,9 @@ def _test_representation(self, tester=None, **options): EXAMPLES:: - sage: from sage.algebras.quantum_groups.representations import \ - ....: MinusculeRepresentation, AdjointRepresentation + sage: # needs sage.combinat sage.modules + sage: from sage.algebras.quantum_groups.representations import ( + ....: MinusculeRepresentation, AdjointRepresentation) sage: C = crystals.Tableaux(['G',2], shape=[1,1]) sage: R = ZZ['q'].fraction_field() sage: V = AdjointRepresentation(R, C) @@ -417,8 +426,8 @@ def _test_representation(self, tester=None, **options): We verify that ``C`` does not define a minuscule representation:: - sage: M = MinusculeRepresentation(R, C) - sage: M._test_representation() + sage: M = MinusculeRepresentation(R, C) # needs sage.combinat sage.modules + sage: M._test_representation() # needs sage.combinat sage.modules Traceback (most recent call last): ... AssertionError: [e,f] = (K-K^-1)/(q_i-q_i^-1) -- i: 1 j: 1 @@ -489,6 +498,7 @@ def cartan_type(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: from sage.algebras.quantum_groups.representations import MinusculeRepresentation sage: C = crystals.Tableaux(['C',4], shape=[1]) sage: R = ZZ['q'].fraction_field() @@ -504,6 +514,7 @@ def index_set(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: from sage.algebras.quantum_groups.representations import MinusculeRepresentation sage: C = crystals.Tableaux(['C',4], shape=[1]) sage: R = ZZ['q'].fraction_field() @@ -519,6 +530,7 @@ def q(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: from sage.algebras.quantum_groups.representations import MinusculeRepresentation sage: C = crystals.Tableaux(['C',4], shape=[1]) sage: R = ZZ['q'].fraction_field() diff --git a/src/sage/categories/quotient_fields.py b/src/sage/categories/quotient_fields.py index 5e4cf0c7edc..f5d8495489d 100644 --- a/src/sage/categories/quotient_fields.py +++ b/src/sage/categories/quotient_fields.py @@ -72,6 +72,7 @@ def gcd(self, other): EXAMPLES:: + sage: # needs sage.libs.pari sage: R.<x> = QQ['x'] sage: p = (1+x)^3*(1+2*x^2)/(1-x^5) sage: q = (1+x)^2*(1+3*x^2)/(1-x^4) @@ -79,13 +80,13 @@ def gcd(self, other): (-2) * (x - 1)^-1 * (x + 1)^3 * (x^2 + 1/2) * (x^4 + x^3 + x^2 + x + 1)^-1 sage: factor(q) (-3) * (x - 1)^-1 * (x + 1) * (x^2 + 1)^-1 * (x^2 + 1/3) - sage: gcd(p,q) + sage: gcd(p, q) (x + 1)/(x^7 + x^5 - x^2 - 1) - sage: factor(gcd(p,q)) + sage: factor(gcd(p, q)) (x - 1)^-1 * (x + 1) * (x^2 + 1)^-1 * (x^4 + x^3 + x^2 + x + 1)^-1 - sage: factor(gcd(p,1+x)) + sage: factor(gcd(p, 1 + x)) (x - 1)^-1 * (x + 1) * (x^4 + x^3 + x^2 + x + 1)^-1 - sage: factor(gcd(1+x,q)) + sage: factor(gcd(1 + x, q)) (x - 1)^-1 * (x + 1) * (x^2 + 1)^-1 TESTS: @@ -93,7 +94,8 @@ def gcd(self, other): The following tests that the fraction field returns a correct gcd even if the base ring does not provide lcm and gcd:: - sage: R = ZZ.extension(x^2+1, names='i') + sage: # needs sage.libs.pari sage.rings.number_field + sage: R = ZZ.extension(x^2 + 1, names='i') sage: i = R.1 sage: gcd(5, 3 + 4*i) -i - 2 @@ -101,9 +103,12 @@ def gcd(self, other): sage: gcd(t, i) Traceback (most recent call last): ... - NotImplementedError: Gaussian Integers in Number Field in i with defining polynomial x^2 + 1 does not provide a gcd implementation for univariate polynomials - sage: q = t/(t+1); q.parent() - Fraction Field of Univariate Polynomial Ring in t over Gaussian Integers in Number Field in i with defining polynomial x^2 + 1 + NotImplementedError: Gaussian Integers in Number Field in i with + defining polynomial x^2 + 1 does not provide a gcd implementation + for univariate polynomials + sage: q = t/(t + 1); q.parent() + Fraction Field of Univariate Polynomial Ring in t over Gaussian + Integers in Number Field in i with defining polynomial x^2 + 1 sage: gcd(q, q) 1 sage: q.gcd(0) @@ -174,6 +179,7 @@ def lcm(self, other): Some more involved examples:: + sage: # needs sage.libs.pari sage: R.<x> = QQ[] sage: p = (1+x)^3*(1+2*x^2)/(1-x^5) sage: q = (1+x)^2*(1+3*x^2)/(1-x^4) @@ -181,11 +187,11 @@ def lcm(self, other): (-2) * (x - 1)^-1 * (x + 1)^3 * (x^2 + 1/2) * (x^4 + x^3 + x^2 + x + 1)^-1 sage: factor(q) (-3) * (x - 1)^-1 * (x + 1) * (x^2 + 1)^-1 * (x^2 + 1/3) - sage: factor(lcm(p,q)) + sage: factor(lcm(p, q)) (x - 1)^-1 * (x + 1)^3 * (x^2 + 1/3) * (x^2 + 1/2) - sage: factor(lcm(p,1+x)) + sage: factor(lcm(p, 1 + x)) (x + 1)^3 * (x^2 + 1/2) - sage: factor(lcm(1+x,q)) + sage: factor(lcm(1 + x, q)) (x + 1) * (x^2 + 1/3) TESTS: @@ -193,15 +199,19 @@ def lcm(self, other): The following tests that the fraction field returns a correct lcm even if the base ring does not provide lcm and gcd:: + sage: # needs sage.libs.pari sage.rings.number_field sage: R = ZZ.extension(x^2+1, names='i') sage: i = R.1 sage: P.<t> = R[] sage: lcm(t, i) Traceback (most recent call last): ... - NotImplementedError: Gaussian Integers in Number Field in i with defining polynomial x^2 + 1 does not provide a gcd implementation for univariate polynomials - sage: q = t/(t+1); q.parent() - Fraction Field of Univariate Polynomial Ring in t over Gaussian Integers in Number Field in i with defining polynomial x^2 + 1 + NotImplementedError: Gaussian Integers in Number Field in i with + defining polynomial x^2 + 1 does not provide a gcd implementation + for univariate polynomials + sage: q = t/(t + 1); q.parent() + Fraction Field of Univariate Polynomial Ring in t over Gaussian + Integers in Number Field in i with defining polynomial x^2 + 1 sage: lcm(q, q) 1 sage: q.lcm(0) @@ -266,11 +276,11 @@ def xgcd(self, other): sage: R.<x> = QQ['x'] sage: p = (1+x)^3*(1+2*x^2)/(1-x^5) sage: q = (1+x)^2*(1+3*x^2)/(1-x^4) - sage: factor(p) + sage: factor(p) # needs sage.libs.pari (-2) * (x - 1)^-1 * (x + 1)^3 * (x^2 + 1/2) * (x^4 + x^3 + x^2 + x + 1)^-1 - sage: factor(q) + sage: factor(q) # needs sage.libs.pari (-3) * (x - 1)^-1 * (x + 1) * (x^2 + 1)^-1 * (x^2 + 1/3) - sage: g,s,t = xgcd(p,q) + sage: g, s, t = xgcd(p, q) sage: g (x + 1)/(x^7 + x^5 - x^2 - 1) sage: g == s*p + t*q @@ -278,6 +288,7 @@ def xgcd(self, other): An example without a well defined gcd or xgcd on its base ring:: + sage: # needs sage.rings.number_field sage: K = QuadraticField(5) sage: O = K.maximal_order() sage: R = PolynomialRing(O, 'x') @@ -315,7 +326,7 @@ def xgcd(self, other): return (P(g)/P(lcmD), P(s*selfD)/P(lcmD),P(t*otherD)/P(lcmD)) except (AttributeError, NotImplementedError, TypeError, ValueError): zero = self.parent().zero() - one = self.parent().one() + one = self.parent().one() if self != zero: return (one, ~self, zero) elif other != zero: @@ -340,14 +351,14 @@ def factor(self, *args, **kwds): sage: K.<x> = QQ[] sage: f = (x^3+x)/(x-3) - sage: f.factor() + sage: f.factor() # needs sage.libs.pari (x - 3)^-1 * x * (x^2 + 1) Here is an example to show that :trac:`7868` has been resolved:: sage: R.<x,y> = GF(2)[] sage: f = x*y/(x+y) - sage: f.factor() + sage: f.factor() # needs sage.rings.finite_rings (x + y)^-1 * y * x """ return (self.numerator().factor(*args, **kwds) / @@ -355,21 +366,20 @@ def factor(self, *args, **kwds): def partial_fraction_decomposition(self, decompose_powers=True): """ - Decomposes fraction field element into a whole part and a list of + Decompose fraction field element into a whole part and a list of fraction field elements over prime power denominators. The sum will be equal to the original fraction. INPUT: - - decompose_powers -- whether to decompose prime power - denominators as opposed to having a single - term for each irreducible factor of the - denominator (default: True) + - ``decompose_powers`` -- boolean (default: ``True``); + whether to decompose prime power denominators as opposed to having + a single term for each irreducible factor of the denominator OUTPUT: - - Partial fraction decomposition of self over the base ring. + Partial fraction decomposition of ``self`` over the base ring. AUTHORS: @@ -377,6 +387,7 @@ def partial_fraction_decomposition(self, decompose_powers=True): EXAMPLES:: + sage: # needs sage.libs.pari sage: S.<t> = QQ[] sage: q = 1/(t+1) + 2/(t+2) + 3/(t-3); q (6*t^2 + 4*t - 6)/(t^3 - 7*t - 6) @@ -386,13 +397,15 @@ def partial_fraction_decomposition(self, decompose_powers=True): True sage: q = 1/(t^3+1) + 2/(t^2+2) + 3/(t-3)^5 sage: whole, parts = q.partial_fraction_decomposition(); parts - [1/3/(t + 1), 3/(t^5 - 15*t^4 + 90*t^3 - 270*t^2 + 405*t - 243), (-1/3*t + 2/3)/(t^2 - t + 1), 2/(t^2 + 2)] + [1/3/(t + 1), 3/(t^5 - 15*t^4 + 90*t^3 - 270*t^2 + 405*t - 243), + (-1/3*t + 2/3)/(t^2 - t + 1), 2/(t^2 + 2)] sage: sum(parts) == q True sage: q = 2*t / (t + 3)^2 sage: q.partial_fraction_decomposition() (0, [2/(t + 3), -6/(t^2 + 6*t + 9)]) - sage: for p in q.partial_fraction_decomposition()[1]: print(p.factor()) + sage: for p in q.partial_fraction_decomposition()[1]: + ....: print(p.factor()) (2) * (t + 3)^-1 (-6) * (t + 3)^-2 sage: q.partial_fraction_decomposition(decompose_powers=False) @@ -400,27 +413,27 @@ def partial_fraction_decomposition(self, decompose_powers=True): We can decompose over a given algebraic extension:: - sage: R.<x> = QQ[sqrt(2)][] - sage: r = 1/(x^4+1) - sage: r.partial_fraction_decomposition() + sage: R.<x> = QQ[sqrt(2)][] # needs sage.rings.number_field sage.symbolic + sage: r = 1/(x^4+1) # needs sage.rings.number_field sage.symbolic + sage: r.partial_fraction_decomposition() # needs sage.rings.number_field sage.symbolic (0, [(-1/4*sqrt2*x + 1/2)/(x^2 - sqrt2*x + 1), (1/4*sqrt2*x + 1/2)/(x^2 + sqrt2*x + 1)]) - sage: R.<x> = QQ[I][] # of QQ[sqrt(-1)] - sage: r = 1/(x^4+1) - sage: r.partial_fraction_decomposition() + sage: R.<x> = QQ[I][] # of QQ[sqrt(-1)] # needs sage.rings.number_field sage.symbolic + sage: r = 1/(x^4+1) # needs sage.rings.number_field sage.symbolic + sage: r.partial_fraction_decomposition() # needs sage.rings.number_field sage.symbolic (0, [(-1/2*I)/(x^2 - I), 1/2*I/(x^2 + I)]) We can also ask Sage to find the least extension where the denominator factors in linear terms:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: r = 1/(x^4+2) - sage: N = r.denominator().splitting_field('a') - sage: N + sage: N = r.denominator().splitting_field('a'); N Number Field in a with defining polynomial x^8 - 8*x^6 + 28*x^4 + 16*x^2 + 36 - sage: R1.<x1>=N[] + sage: R1.<x1> = N[] sage: r1 = 1/(x1^4+2) sage: r1.partial_fraction_decomposition() (0, @@ -431,9 +444,9 @@ def partial_fraction_decomposition(self, decompose_powers=True): Or we may work directly over an algebraically closed field:: - sage: R.<x> = QQbar[] - sage: r = 1/(x^4+1) - sage: r.partial_fraction_decomposition() + sage: R.<x> = QQbar[] # needs sage.rings.number_field + sage: r = 1/(x^4+1) # needs sage.rings.number_field + sage: r.partial_fraction_decomposition() # needs sage.rings.number_field (0, [(-0.1767766952966369? - 0.1767766952966369?*I)/(x - 0.7071067811865475? - 0.7071067811865475?*I), (-0.1767766952966369? + 0.1767766952966369?*I)/(x - 0.7071067811865475? + 0.7071067811865475?*I), @@ -442,13 +455,17 @@ def partial_fraction_decomposition(self, decompose_powers=True): We do the best we can over inexact fields:: + sage: # needs sage.rings.number_field sage.rings.real_mpfr sage: R.<x> = RealField(20)[] sage: q = 1/(x^2 + x + 2)^2 + 1/(x-1); q - (x^4 + 2.0000*x^3 + 5.0000*x^2 + 5.0000*x + 3.0000)/(x^5 + x^4 + 3.0000*x^3 - x^2 - 4.0000) + (x^4 + 2.0000*x^3 + + 5.0000*x^2 + 5.0000*x + 3.0000)/(x^5 + x^4 + 3.0000*x^3 - x^2 - 4.0000) sage: whole, parts = q.partial_fraction_decomposition(); parts - [1.0000/(x - 1.0000), 1.0000/(x^4 + 2.0000*x^3 + 5.0000*x^2 + 4.0000*x + 4.0000)] + [1.0000/(x - 1.0000), + 1.0000/(x^4 + 2.0000*x^3 + 5.0000*x^2 + 4.0000*x + 4.0000)] sage: sum(parts) - (x^4 + 2.0000*x^3 + 5.0000*x^2 + 5.0000*x + 3.0000)/(x^5 + x^4 + 3.0000*x^3 - x^2 - 4.0000) + (x^4 + 2.0000*x^3 + + 5.0000*x^2 + 5.0000*x + 3.0000)/(x^5 + x^4 + 3.0000*x^3 - x^2 - 4.0000) TESTS: @@ -456,23 +473,23 @@ def partial_fraction_decomposition(self, decompose_powers=True): sage: R.<x> = ZZ[] sage: q = x^2/(x-1) - sage: q.partial_fraction_decomposition() + sage: q.partial_fraction_decomposition() # needs sage.libs.pari (x + 1, [1/(x - 1)]) sage: q = x^10/(x-1)^5 - sage: whole, parts = q.partial_fraction_decomposition() - sage: whole + sum(parts) == q + sage: whole, parts = q.partial_fraction_decomposition() # needs sage.libs.pari + sage: whole + sum(parts) == q # needs sage.libs.pari True And also over finite fields (see :trac:`6052`, :trac:`9945`):: sage: R.<x> = GF(2)[] sage: q = (x+1)/(x^3+x+1) - sage: q.partial_fraction_decomposition() + sage: q.partial_fraction_decomposition() # needs sage.libs.pari (0, [(x + 1)/(x^3 + x + 1)]) sage: R.<x> = GF(11)[] sage: q = x + 1 + 1/(x+1) + x^2/(x^3 + 2*x + 9) - sage: q.partial_fraction_decomposition() + sage: q.partial_fraction_decomposition() # needs sage.libs.pari (x + 1, [1/(x + 1), x^2/(x^3 + 2*x + 9)]) And even the rationals:: @@ -486,7 +503,7 @@ def partial_fraction_decomposition(self, decompose_powers=True): sage: S.<t> = QQ[] sage: r = t / (t^3+1)^5 - sage: r.partial_fraction_decomposition() + sage: r.partial_fraction_decomposition() # needs sage.libs.pari (0, [-35/729/(t + 1), -35/729/(t^2 + 2*t + 1), @@ -498,7 +515,7 @@ def partial_fraction_decomposition(self, decompose_powers=True): (-1/81*t + 5/81)/(t^6 - 3*t^5 + 6*t^4 - 7*t^3 + 6*t^2 - 3*t + 1), (-2/27*t + 1/9)/(t^8 - 4*t^7 + 10*t^6 - 16*t^5 + 19*t^4 - 16*t^3 + 10*t^2 - 4*t + 1), (-2/27*t + 1/27)/(t^10 - 5*t^9 + 15*t^8 - 30*t^7 + 45*t^6 - 51*t^5 + 45*t^4 - 30*t^3 + 15*t^2 - 5*t + 1)]) - sage: sum(r.partial_fraction_decomposition()[1]) == r + sage: sum(r.partial_fraction_decomposition()[1]) == r # needs sage.libs.pari True Some special cases:: @@ -510,24 +527,25 @@ def partial_fraction_decomposition(self, decompose_powers=True): (0, []) sage: R(1).partial_fraction_decomposition() (1, []) - sage: (1/x).partial_fraction_decomposition() + sage: (1/x).partial_fraction_decomposition() # needs sage.libs.pari (0, [1/x]) - sage: (1/x+1/x^3).partial_fraction_decomposition() + sage: (1/x+1/x^3).partial_fraction_decomposition() # needs sage.libs.pari (0, [1/x, 1/x^3]) This was fixed in :trac:`16240`:: + sage: # needs sage.libs.pari sage: R.<x> = QQ['x'] sage: p = 1/(-x + 1) - sage: whole,parts = p.partial_fraction_decomposition() + sage: whole, parts = p.partial_fraction_decomposition() sage: p == sum(parts) True sage: p = 3/(-x^4 + 1) - sage: whole,parts = p.partial_fraction_decomposition() + sage: whole, parts = p.partial_fraction_decomposition() sage: p == sum(parts) True sage: p = (6*x^2 - 9*x + 5)/(-x^3 + 3*x^2 - 3*x + 1) - sage: whole,parts = p.partial_fraction_decomposition() + sage: whole, parts = p.partial_fraction_decomposition() sage: p == sum(parts) True """ @@ -681,11 +699,11 @@ def _derivative(self, var=None): try: numder = num._derivative(var) dender = den._derivative(var) - d = den.gcd(dender) - den = den // d + d = den.gcd(dender) + den = den // d dender = dender // d - tnum = numder * den - num * dender - tden = self.denominator() * den + tnum = numder * den - num * dender + tden = self.denominator() * den if not tden.is_one() and tden.is_unit(): try: tnum = tnum * tden.inverse_of_unit() diff --git a/src/sage/categories/realizations.py b/src/sage/categories/realizations.py index bbe9a8e8ad4..1c40e597676 100644 --- a/src/sage/categories/realizations.py +++ b/src/sage/categories/realizations.py @@ -66,19 +66,23 @@ def Realizations(self): The category of realizations of some algebra:: sage: Algebras(QQ).Realizations() - Join of Category of algebras over Rational Field and Category of realizations of unital magmas + Join of Category of algebras over Rational Field + and Category of realizations of unital magmas The category of realizations of a given algebra:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: A.Realizations() - Category of realizations of The subset algebra of {1, 2, 3} over Rational Field + sage: A.Realizations() # needs sage.modules + Category of realizations of + The subset algebra of {1, 2, 3} over Rational Field sage: C = GradedHopfAlgebrasWithBasis(QQ).Realizations(); C - Join of Category of graded hopf algebras with basis over Rational Field and Category of realizations of hopf algebras over Rational Field + Join of Category of graded hopf algebras with basis over Rational Field + and Category of realizations of hopf algebras over Rational Field sage: C.super_categories() - [Category of graded hopf algebras with basis over Rational Field, Category of realizations of hopf algebras over Rational Field] + [Category of graded hopf algebras with basis over Rational Field, + Category of realizations of hopf algebras over Rational Field] sage: TestSuite(C).run() @@ -91,13 +95,14 @@ def Realizations(self): Add an optional argument to allow for:: - sage: Realizations(A, category = Blahs()) # todo: not implemented + sage: Realizations(A, category=Blahs()) # todo: not implemented """ if isinstance(self, Category): return RealizationsCategory.category_of(self) else: return getattr(self.__class__, "Realizations")(self) + Category.Realizations = Realizations class Category_realization_of_parent(Category_over_base, BindableClass): @@ -112,7 +117,7 @@ class Category_realization_of_parent(Category_over_base, BindableClass): EXAMPLES:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field The role of this base class is to implement some technical goodies, like @@ -120,8 +125,9 @@ class Category_realization_of_parent(Category_over_base, BindableClass): implemented as a nested class in ``A`` (see the :mod:`code of the example <sage.categories.examples.with_realizations.SubsetAlgebra>`):: - sage: C = A.Realizations(); C - Category of realizations of The subset algebra of {1, 2, 3} over Rational Field + sage: C = A.Realizations(); C # needs sage.modules + Category of realizations of + The subset algebra of {1, 2, 3} over Rational Field as well as the name for that category. """ @@ -129,11 +135,13 @@ def __init__(self, parent_with_realization): """ TESTS:: + sage: # needs sage.combinat sage.modules sage: from sage.categories.realizations import Category_realization_of_parent sage: A = Sets().WithRealizations().example(); A The subset algebra of {1, 2, 3} over Rational Field sage: C = A.Realizations(); C - Category of realizations of The subset algebra of {1, 2, 3} over Rational Field + Category of realizations of + The subset algebra of {1, 2, 3} over Rational Field sage: isinstance(C, Category_realization_of_parent) True sage: C.parent_with_realization @@ -161,8 +169,8 @@ def _get_name(self): sage: from sage.categories.realizations import Category_realization_of_parent sage: class MultiplicativeBasesOnPrimitiveElements(Category_realization_of_parent): ....: def super_categories(self): return [Objects()] - sage: Sym = SymmetricFunctions(QQ); Sym.rename("Sym") - sage: MultiplicativeBasesOnPrimitiveElements(Sym)._get_name() + sage: Sym = SymmetricFunctions(QQ); Sym.rename("Sym") # needs sage.combinat sage.modules + sage: MultiplicativeBasesOnPrimitiveElements(Sym)._get_name() # needs sage.combinat sage.modules 'multiplicative bases on primitive elements' """ import re @@ -179,10 +187,10 @@ def _repr_object_names(self): sage: from sage.categories.realizations import Category_realization_of_parent sage: class MultiplicativeBasesOnPrimitiveElements(Category_realization_of_parent): ....: def super_categories(self): return [Objects()] - sage: Sym = SymmetricFunctions(QQ); Sym.rename("Sym") - sage: C = MultiplicativeBasesOnPrimitiveElements(Sym); C + sage: Sym = SymmetricFunctions(QQ); Sym.rename("Sym") # needs sage.combinat sage.modules + sage: C = MultiplicativeBasesOnPrimitiveElements(Sym); C # needs sage.combinat sage.modules Category of multiplicative bases on primitive elements of Sym - sage: C._repr_object_names() + sage: C._repr_object_names() # needs sage.combinat sage.modules 'multiplicative bases on primitive elements of Sym' """ return "{} of {}".format(self._get_name(), self.base()) diff --git a/src/sage/categories/regular_crystals.py b/src/sage/categories/regular_crystals.py index f5412fe6ab1..297420e5083 100644 --- a/src/sage/categories/regular_crystals.py +++ b/src/sage/categories/regular_crystals.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.graphs r""" Regular Crystals """ @@ -133,21 +134,21 @@ def is_isomorphism(self): EXAMPLES:: - sage: La = RootSystem(['A',2,1]).weight_space(extended=True).fundamental_weights() + sage: A21 = RootSystem(['A',2,1]) + sage: La = A21.weight_space(extended=True).fundamental_weights() sage: B = crystals.LSPaths(La[0]) - sage: La = RootSystem(['A',2,1]).weight_lattice(extended=True).fundamental_weights() + sage: La = A21.weight_lattice(extended=True).fundamental_weights() sage: C = crystals.GeneralizedYoungWalls(2, La[0]) sage: H = Hom(B, C) sage: from sage.categories.highest_weight_crystals import HighestWeightCrystalMorphism sage: class Psi(HighestWeightCrystalMorphism): ....: def is_strict(self): ....: return True - sage: psi = Psi(H, C.module_generators) - sage: psi + sage: psi = Psi(H, C.module_generators); psi ['A', 2, 1] Crystal morphism: From: The crystal of LS paths of type ['A', 2, 1] and weight Lambda[0] - To: Highest weight crystal of generalized Young walls of Cartan type ['A', 2, 1] - and highest weight Lambda[0] + To: Highest weight crystal of generalized Young walls + of Cartan type ['A', 2, 1] and highest weight Lambda[0] Defn: (Lambda[0],) |--> [] sage: psi.is_isomorphism() True @@ -184,25 +185,28 @@ def demazure_operator(self, element, reduced_word): EXAMPLES:: sage: T = crystals.Tableaux(['A',2], shape=[2,1]) - sage: C = CombinatorialFreeModule(QQ,T) + sage: C = CombinatorialFreeModule(QQ, T) sage: t = T.highest_weight_vector() sage: b = 2*C(t) sage: T.demazure_operator(b,[1,2,1]) - 2*B[[[1, 1], [2]]] + 2*B[[[1, 2], [2]]] + 2*B[[[1, 3], [2]]] + 2*B[[[1, 1], [3]]] - + 2*B[[[1, 2], [3]]] + 2*B[[[1, 3], [3]]] + 2*B[[[2, 2], [3]]] + 2*B[[[2, 3], [3]]] + 2*B[[[1, 1], [2]]] + 2*B[[[1, 2], [2]]] + 2*B[[[1, 3], [2]]] + + 2*B[[[1, 1], [3]]] + 2*B[[[1, 2], [3]]] + 2*B[[[1, 3], [3]]] + + 2*B[[[2, 2], [3]]] + 2*B[[[2, 3], [3]]] The Demazure operator is idempotent:: - sage: T = crystals.Tableaux("A1",shape=[4]) - sage: C = CombinatorialFreeModule(QQ,T) + sage: T = crystals.Tableaux("A1", shape=[4]) + sage: C = CombinatorialFreeModule(QQ, T) sage: b = C(T.module_generators[0]); b B[[[1, 1, 1, 1]]] sage: e = T.demazure_operator(b,[1]); e - B[[[1, 1, 1, 1]]] + B[[[1, 1, 1, 2]]] + B[[[1, 1, 2, 2]]] + B[[[1, 2, 2, 2]]] + B[[[2, 2, 2, 2]]] + B[[[1, 1, 1, 1]]] + B[[[1, 1, 1, 2]]] + B[[[1, 1, 2, 2]]] + + B[[[1, 2, 2, 2]]] + B[[[2, 2, 2, 2]]] sage: e == T.demazure_operator(e,[1]) True - sage: all(T.demazure_operator(T.demazure_operator(C(t),[1]),[1]) == T.demazure_operator(C(t),[1]) for t in T) + sage: all(T.demazure_operator(T.demazure_operator(C(t),[1]),[1]) + ....: == T.demazure_operator(C(t),[1]) for t in T) True """ M = element.parent() @@ -306,7 +310,7 @@ def _test_stembridge_local_axioms(self, index_set=None, verbose=False, complete= AssertionError: None """ tester = self._tester(**options) - goodness=True + goodness = True i = 0 for x in self: goodness = x._test_stembridge_local_axioms(index_set, verbose) @@ -711,10 +715,10 @@ def stembridgeTriple(self,i,j): """ if self.e(i) is None: return None - b=self.stembridgeDelta_depth(i,j) - c=self.stembridgeDelta_rise(i,j) - dd=self.cartan_type().dynkin_diagram() - a=dd[j,i] + b = self.stembridgeDelta_depth(i,j) + c = self.stembridgeDelta_rise(i,j) + dd = self.cartan_type().dynkin_diagram() + a = dd[j,i] return (a, b, c) def _test_stembridge_local_axioms(self, index_set=None, verbose=False, **options): @@ -750,38 +754,38 @@ def _test_stembridge_local_axioms(self, index_set=None, verbose=False, **options tester = self._tester(**options) goodness = True if index_set is None: - index_set=self.index_set() + index_set = self.index_set() from sage.combinat.subset import Subsets for (i,j) in Subsets(index_set, 2): if self.e(i) is not None and self.e(j) is not None: - triple=self.stembridgeTriple(i,j) + triple = self.stembridgeTriple(i,j) #Test axioms P3 and P4. - if not triple[0]==triple[1]+triple[2] or triple[1]>0 or triple[2]>0: + if not triple[0] == triple[1]+triple[2] or triple[1] > 0 or triple[2] > 0: if verbose: print('Warning: Failed axiom P3 or P4 at vector ', self, 'i,j=', i, j, 'Stembridge triple:', self.stembridgeTriple(i, j)) - goodness=False + goodness = False else: tester.fail() - if self.stembridgeDelta_depth(i,j)==0: + if self.stembridgeDelta_depth(i,j) == 0: #check E_i E_j(x)= E_j E_i(x) - if self.e(i).e(j)!=self.e(j).e(i) or self.e(i).e(j).stembridgeDel_rise(j, i)!=0: + if self.e(i).e(j) != self.e(j).e(i) or self.e(i).e(j).stembridgeDel_rise(j, i) != 0: if verbose: print('Warning: Failed axiom P5 at: vector ', self, 'i,j=', i, j, 'Stembridge triple:', self.stembridgeTriple(i, j)) - goodness=False + goodness = False else: tester.fail() - if self.stembridgeDelta_depth(i,j)==-1 and self.stembridgeDelta_depth(j,i)==-1: + if self.stembridgeDelta_depth(i,j) == -1 and self.stembridgeDelta_depth(j,i) == -1: #check E_i E_j^2 E_i (x)= E_j E_i^2 E_j (x) - y1=self.e(j).e(i).e(i).e(j) - y2=self.e(j).e(i).e(i).e(j) - a=y1.stembridgeDel_rise(j, i) - b=y2.stembridgeDel_rise(i, j) - if y1!=y2 or a!=-1 or b!=-1: + y1 = self.e(j).e(i).e(i).e(j) + y2 = self.e(j).e(i).e(i).e(j) + a = y1.stembridgeDel_rise(j, i) + b = y2.stembridgeDel_rise(i, j) + if y1 != y2 or a != -1 or b != -1: if verbose: print('Warning: Failed axiom P6 at: vector ', self, 'i,j=', i, j, 'Stembridge triple:', self.stembridgeTriple(i, j)) - goodness=False + goodness = False else: tester.fail() tester.assertTrue(goodness) diff --git a/src/sage/categories/regular_supercrystals.py b/src/sage/categories/regular_supercrystals.py index 2ed4531c673..044f556a1f7 100644 --- a/src/sage/categories/regular_supercrystals.py +++ b/src/sage/categories/regular_supercrystals.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.graphs r""" Regular Supercrystals """ @@ -107,7 +108,7 @@ def epsilon(self, i): EXAMPLES:: - sage: C = crystals.Tableaux(['A',[1,2]], shape = [2,1]) + sage: C = crystals.Tableaux(['A',[1,2]], shape=[2,1]) sage: c = C.an_element(); c [[-2, -2], [-1]] sage: c.epsilon(2) @@ -132,7 +133,7 @@ def phi(self, i): EXAMPLES:: - sage: C = crystals.Tableaux(['A',[1,2]], shape = [2,1]) + sage: C = crystals.Tableaux(['A',[1,2]], shape=[2,1]) sage: c = C.an_element(); c [[-2, -2], [-1]] sage: c.phi(1) diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index 6a7589bb109..60ca92f971b 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -66,6 +66,7 @@ def is_injective(self) -> bool: EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ[] sage: R.hom([x, y^2], R).is_injective() True @@ -120,17 +121,19 @@ def is_injective(self) -> bool: To: Rational function field in x over Rational Field Defn: Conversion via FractionFieldElement_1poly_field map: From: Integer Ring - To: Fraction Field of Univariate Polynomial Ring in x over Rational Field + To: Fraction Field of Univariate Polynomial Ring in x + over Rational Field then Isomorphism: - From: Fraction Field of Univariate Polynomial Ring in x over Rational Field + From: Fraction Field of Univariate Polynomial Ring in x + over Rational Field To: Rational function field in x over Rational Field sage: f.is_injective() True A coercion to the fraction field is injective:: - sage: R = ZpFM(3) + sage: R = ZpFM(3) # needs sage.rings.padics sage: R.fraction_field().coerce_map_from(R).is_injective() True @@ -212,16 +215,17 @@ def extend_to_fraction_field(self): EXAMPLES:: sage: S.<x> = QQ[] - sage: f = S.hom([x+1]); f + sage: f = S.hom([x + 1]); f Ring endomorphism of Univariate Polynomial Ring in x over Rational Field Defn: x |--> x + 1 - sage: g = f.extend_to_fraction_field(); g - Ring endomorphism of Fraction Field of Univariate Polynomial Ring in x over Rational Field + sage: g = f.extend_to_fraction_field(); g # needs sage.libs.singular + Ring endomorphism of Fraction Field of Univariate Polynomial Ring in x + over Rational Field Defn: x |--> x + 1 - sage: g(x) + sage: g(x) # needs sage.libs.singular x + 1 - sage: g(1/x) + sage: g(1/x) # needs sage.libs.singular 1/(x + 1) If this morphism is not injective, it does not extend to the fraction @@ -236,9 +240,10 @@ def extend_to_fraction_field(self): TESTS:: sage: A.<x> = RR[] - sage: phi = A.hom([x+1]) - sage: phi.extend_to_fraction_field() - Ring endomorphism of Fraction Field of Univariate Polynomial Ring in x over Real Field with 53 bits of precision + sage: phi = A.hom([x + 1]) + sage: phi.extend_to_fraction_field() # needs sage.libs.singular + Ring endomorphism of Fraction Field of + Univariate Polynomial Ring in x over Real Field with 53 bits of precision Defn: x |--> x + 1.00000000000000 """ from sage.rings.morphism import RingHomomorphism_from_fraction_field @@ -335,7 +340,7 @@ def is_zero(self) -> bool: sage: R.<x> = GF(101)[] sage: R.quo(77).is_zero() True - sage: R.quo(x^2+1).is_zero() + sage: R.quo(x^2 + 1).is_zero() # needs sage.libs.pari False """ return self.one() == self.zero() @@ -350,18 +355,21 @@ def bracket(self, x, y): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: F = AlgebrasWithBasis(QQ).example() sage: F - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field - sage: a,b,c = F.algebra_generators() - sage: F.bracket(a,b) + An example of an algebra with basis: + the free algebra on the generators ('a', 'b', 'c') over Rational Field + sage: a, b, c = F.algebra_generators() + sage: F.bracket(a, b) B[word: ab] - B[word: ba] This measures the default of commutation between `x` and `y`. `F` endowed with the bracket operation is a Lie algebra; in particular, it satisfies Jacobi's identity:: - sage: F.bracket( F.bracket(a,b), c) + F.bracket(F.bracket(b,c),a) + F.bracket(F.bracket(c,a),b) + sage: (F.bracket(F.bracket(a,b), c) + F.bracket(F.bracket(b,c), a) # needs sage.combinat sage.modules + ....: + F.bracket(F.bracket(c,a), b)) 0 """ return x * y - y * x @@ -386,20 +394,20 @@ def _Hom_(self, Y, category): EXAMPLES:: - sage: H = QQ._Hom_(QQ, category = Rings()); H + sage: H = QQ._Hom_(QQ, category=Rings()); H Set of Homomorphisms from Rational Field to Rational Field sage: H.__class__ <class 'sage.rings.homset.RingHomset_generic_with_category'> TESTS:: - sage: Hom(QQ, QQ, category = Rings()).__class__ + sage: Hom(QQ, QQ, category=Rings()).__class__ <class 'sage.rings.homset.RingHomset_generic_with_category'> - sage: Hom(CyclotomicField(3), QQ, category = Rings()).__class__ + sage: Hom(CyclotomicField(3), QQ, category=Rings()).__class__ # needs sage.rings.number_field <class 'sage.rings.number_field.homset.CyclotomicFieldHomset_with_category'> - sage: TestSuite(Hom(QQ, QQ, category = Rings())).run() # indirect doctest + sage: TestSuite(Hom(QQ, QQ, category=Rings())).run() # indirect doctest """ if category is not None and not category.is_subcategory(Rings()): raise TypeError(f"{category} is not a subcategory of Rings()") @@ -439,12 +447,13 @@ def _mul_(self, x, switch_sides=False): from the base class of rings. This is the case, e.g., for matrix algebras:: - sage: MS = MatrixSpace(QQ,2,2) - sage: isinstance(MS,Ring) + sage: # needs sage.modules + sage: MS = MatrixSpace(QQ, 2, 2) + sage: isinstance(MS, Ring) False sage: MS in Rings() True - sage: MS*2 # indirect doctest + sage: MS * 2 # indirect doctest Left Ideal ( [2 0] @@ -455,7 +464,7 @@ def _mul_(self, x, switch_sides=False): In the next example, the ring and the other factor switch sides in the product:: - sage: [MS.2]*MS + sage: [MS.2] * MS # needs sage.modules Right Ideal ( [0 0] @@ -501,12 +510,12 @@ def __pow__(self, n): EXAMPLES:: - sage: QQ^5 + sage: QQ^5 # needs sage.modules Vector space of dimension 5 over Rational Field - sage: Integers(20)^1000 + sage: Integers(20)^1000 # needs sage.modules Ambient free module of rank 1000 over Ring of integers modulo 20 - sage: QQ^(2,3) + sage: QQ^(2, 3) # needs sage.modules Full MatrixSpace of 2 by 3 dense matrices over Rational Field """ if isinstance(n, tuple): @@ -531,8 +540,9 @@ def ideal_monoid(self): EXAMPLES:: - sage: MS = MatrixSpace(QQ,2,2) - sage: isinstance(MS,Ring) + sage: # needs sage.modules + sage: MS = MatrixSpace(QQ, 2, 2) + sage: isinstance(MS, Ring) False sage: MS in Rings() True @@ -542,7 +552,7 @@ def ideal_monoid(self): Note that the monoid is cached:: - sage: MS.ideal_monoid() is MS.ideal_monoid() + sage: MS.ideal_monoid() is MS.ideal_monoid() # needs sage.modules True """ try: @@ -564,7 +574,7 @@ def characteristic(self): 19 sage: Integers(8).characteristic() 8 - sage: Zp(5).characteristic() + sage: Zp(5).characteristic() # needs sage.rings.padics 0 """ from sage.rings.infinity import infinity @@ -619,8 +629,9 @@ def ideal(self, *args, **kwds): EXAMPLES:: - sage: MS = MatrixSpace(QQ,2,2) - sage: isinstance(MS,Ring) + sage: # needs sage.modules + sage: MS = MatrixSpace(QQ, 2, 2) + sage: isinstance(MS, Ring) False sage: MS in Rings() True @@ -631,7 +642,7 @@ def ideal(self, *args, **kwds): [0 2] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: MS.ideal([MS.0,MS.1],side='right') + sage: MS.ideal([MS.0, MS.1], side='right') Right Ideal ( [1 0] @@ -733,8 +744,8 @@ def _ideal_class_(self, n=0): EXAMPLES:: - sage: MS = MatrixSpace(QQ,2,2) - sage: MS._ideal_class_() + sage: MS = MatrixSpace(QQ, 2, 2) # needs sage.modules + sage: MS._ideal_class_() # needs sage.modules <class 'sage.rings.noncommutative_ideals.Ideal_nc'> We do not know of a commutative ring in Sage that does not inherit @@ -782,19 +793,26 @@ def quotient(self, I, names=None, **kwds): So, we need a bit of effort to make the following example work with the category framework:: + sage: # needs sage.combinat sage.modules sage: F.<x,y,z> = FreeAlgebra(QQ) sage: from sage.rings.noncommutative_ideals import Ideal_nc sage: from itertools import product sage: class PowerIdeal(Ideal_nc): ....: def __init__(self, R, n): ....: self._power = n - ....: Ideal_nc.__init__(self, R, [R.prod(m) for m in product(R.gens(), repeat=n)]) + ....: Ideal_nc.__init__(self, R, [R.prod(m) + ....: for m in product(R.gens(), repeat=n)]) ....: def reduce(self, x): ....: R = self.ring() - ....: return add([c*R(m) for m,c in x if len(m) < self._power], R(0)) - sage: I = PowerIdeal(F,3) + ....: return add([c*R(m) for m, c in x + ....: if len(m) < self._power], R(0)) + sage: I = PowerIdeal(F, 3) sage: Q = Rings().parent_class.quotient(F, I); Q - Quotient of Free Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x^3, x^2*y, x^2*z, x*y*x, x*y^2, x*y*z, x*z*x, x*z*y, x*z^2, y*x^2, y*x*y, y*x*z, y^2*x, y^3, y^2*z, y*z*x, y*z*y, y*z^2, z*x^2, z*x*y, z*x*z, z*y*x, z*y^2, z*y*z, z^2*x, z^2*y, z^3) + Quotient of Free Algebra on 3 generators (x, y, z) over Rational Field + by the ideal (x^3, x^2*y, x^2*z, x*y*x, x*y^2, x*y*z, x*z*x, + x*z*y, x*z^2, y*x^2, y*x*y, y*x*z, y^2*x, y^3, + y^2*z, y*z*x, y*z*y, y*z^2, z*x^2, z*x*y, z*x*z, + z*y*x, z*y^2, z*y*z, z^2*x, z^2*y, z^3) sage: Q.0 xbar sage: Q.1 @@ -814,10 +832,12 @@ def quotient(self, I, names=None, **kwds): sage: S.gens() (a,) - sage: R.<x,y> = PolynomialRing(QQ,2) + sage: # needs sage.libs.singular + sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S.<a,b> = R.quotient((x^2, y)) sage: S - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y) + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2, y) sage: S.gens() (a, 0) sage: a == b @@ -836,8 +856,8 @@ def quo(self, I, names=None, **kwds): EXAMPLES:: - sage: MS = MatrixSpace(QQ,2) - sage: I = MS*MS.gens()*MS + sage: MS = MatrixSpace(QQ, 2) # needs sage.modules + sage: I = MS * MS.gens() * MS # needs sage.modules ``MS`` is not an instance of :class:`~sage.rings.ring.Ring`. @@ -845,12 +865,13 @@ def quo(self, I, names=None, **kwds): category of rings. The quotient method is inherited from there:: - sage: isinstance(MS,sage.rings.ring.Ring) + sage: isinstance(MS, sage.rings.ring.Ring) # needs sage.modules False - sage: isinstance(MS,Rings().parent_class) + sage: isinstance(MS, Rings().parent_class) # needs sage.modules True - sage: MS.quo(I,names = ['a','b','c','d']) - Quotient of Full MatrixSpace of 2 by 2 dense matrices over Rational Field by the ideal + sage: MS.quo(I, names=['a','b','c','d']) # needs sage.modules + Quotient of Full MatrixSpace of 2 by 2 dense matrices + over Rational Field by the ideal ( [1 0] [0 0], @@ -867,10 +888,12 @@ def quo(self, I, names=None, **kwds): A test with a subclass of :class:`~sage.rings.ring.Ring`:: - sage: R.<x,y> = PolynomialRing(QQ,2) + sage: # needs sage.libs.singular + sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S.<a,b> = R.quo((x^2, y)) sage: S - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y) + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2, y) sage: S.gens() (a, 0) sage: a == b @@ -903,19 +926,20 @@ def quotient_ring(self, I, names=None, **kwds): EXAMPLES:: - sage: MS = MatrixSpace(QQ,2) - sage: I = MS*MS.gens()*MS + sage: MS = MatrixSpace(QQ, 2) # needs sage.modules + sage: I = MS * MS.gens() * MS # needs sage.modules ``MS`` is not an instance of :class:`~sage.rings.ring.Ring`, but it is an instance of the parent class of the category of rings. The quotient method is inherited from there:: - sage: isinstance(MS,sage.rings.ring.Ring) + sage: isinstance(MS, sage.rings.ring.Ring) # needs sage.modules False - sage: isinstance(MS,Rings().parent_class) + sage: isinstance(MS, Rings().parent_class) # needs sage.modules True - sage: MS.quotient_ring(I,names = ['a','b','c','d']) - Quotient of Full MatrixSpace of 2 by 2 dense matrices over Rational Field by the ideal + sage: MS.quotient_ring(I, names=['a','b','c','d']) # needs sage.modules + Quotient of Full MatrixSpace of 2 by 2 dense matrices + over Rational Field by the ideal ( [1 0] [0 0], @@ -938,10 +962,12 @@ def quotient_ring(self, I, names=None, **kwds): sage: S.gens() (a,) + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ,2) sage: S.<a,b> = R.quotient_ring((x^2, y)) sage: S - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y) + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2, y) sage: S.gens() (a, 0) sage: a == b @@ -957,9 +983,9 @@ def __truediv__(self, I): EXAMPLES:: - sage: MS = MatrixSpace(QQ,2) - sage: I = MS*MS.gens()*MS - sage: MS/I + sage: MS = MatrixSpace(QQ, 2) # needs sage.modules + sage: I = MS * MS.gens() * MS # needs sage.modules + sage: MS/I # needs sage.modules Traceback (most recent call last): ... TypeError: use self.quotient(I) to construct the quotient ring @@ -1001,19 +1027,23 @@ def __getitem__(self, arg): sage: GF(17)['a,b,c'] Multivariate Polynomial Ring in a, b, c over Finite Field of size 17 sage: GF(17)['a']['b'] - Univariate Polynomial Ring in b over Univariate Polynomial Ring in a over Finite Field of size 17 + Univariate Polynomial Ring in b over + Univariate Polynomial Ring in a over Finite Field of size 17 We can create Ore polynomial rings:: - sage: k.<t> = GF(5^3) - sage: Frob = k.frobenius_endomorphism() - sage: k['x', Frob] - Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + sage: k.<t> = GF(5^3) # needs sage.rings.finite_rings + sage: Frob = k.frobenius_endomorphism() # needs sage.rings.finite_rings + sage: k['x', Frob] # needs sage.rings.finite_rings + Ore Polynomial Ring in x over Finite Field in t of size 5^3 + twisted by t |--> t^5 sage: R.<t> = QQ[] - sage: der = R.derivation() - sage: R['d', der] - Ore Polynomial Ring in d over Univariate Polynomial Ring in t over Rational Field twisted by d/dt + sage: der = R.derivation() # needs sage.modules + sage: R['d', der] # needs sage.modules + Ore Polynomial Ring in d + over Univariate Polynomial Ring in t over Rational Field + twisted by d/dt We can also create power series rings by using double brackets:: @@ -1040,9 +1070,9 @@ def __getitem__(self, arg): Note that the same syntax can be used to create number fields:: - sage: QQ[I] + sage: QQ[I] # needs sage.rings.number_field sage.symbolic Number Field in I with defining polynomial x^2 + 1 with I = 1*I - sage: QQ[I].coerce_embedding() + sage: QQ[I].coerce_embedding() # needs sage.rings.number_field sage.symbolic Generic morphism: From: Number Field in I with defining polynomial x^2 + 1 with I = 1*I To: Complex Lazy Field @@ -1050,32 +1080,38 @@ def __getitem__(self, arg): :: - sage: QQ[sqrt(2)] # optional - sage.symbolic - Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? - sage: QQ[sqrt(2)].coerce_embedding() # optional - sage.symbolic + sage: QQ[sqrt(2)] # needs sage.rings.number_field sage.symbolic + Number Field in sqrt2 with defining polynomial x^2 - 2 + with sqrt2 = 1.414213562373095? + sage: QQ[sqrt(2)].coerce_embedding() # needs sage.rings.number_field sage.symbolic Generic morphism: - From: Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? + From: Number Field in sqrt2 with defining polynomial x^2 - 2 + with sqrt2 = 1.414213562373095? To: Real Lazy Field Defn: sqrt2 -> 1.414213562373095? :: - sage: QQ[sqrt(2), sqrt(3)] # optional - sage.symbolic - Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field + sage: QQ[sqrt(2), sqrt(3)] # needs sage.rings.number_field sage.symbolic + Number Field in sqrt2 + with defining polynomial x^2 - 2 over its base field and orders in number fields:: - sage: ZZ[I] - Order in Number Field in I0 with defining polynomial x^2 + 1 with I0 = 1*I - sage: ZZ[sqrt(5)] # optional - sage.symbolic - Order in Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? - sage: ZZ[sqrt(2) + sqrt(3)] # optional - sage.symbolic - Order in Number Field in a with defining polynomial x^4 - 10*x^2 + 1 with a = 3.146264369941973? + sage: ZZ[I] # needs sage.rings.number_field sage.symbolic + Order in Number Field in I0 + with defining polynomial x^2 + 1 with I0 = 1*I + sage: ZZ[sqrt(5)] # needs sage.rings.number_field sage.symbolic + Order in Number Field in sqrt5 + with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? + sage: ZZ[sqrt(2) + sqrt(3)] # needs sage.rings.number_field sage.symbolic + Order in Number Field in a + with defining polynomial x^4 - 10*x^2 + 1 with a = 3.146264369941973? Embeddings are found for simple extensions (when that makes sense):: - sage: QQi.<i> = QuadraticField(-1, 'i') - sage: QQ[i].coerce_embedding() + sage: QQi.<i> = QuadraticField(-1, 'i') # needs sage.rings.number_field sage.symbolic + sage: QQ[i].coerce_embedding() # needs sage.rings.number_field sage.symbolic Generic morphism: From: Number Field in i with defining polynomial x^2 + 1 with i = 1*I To: Complex Lazy Field @@ -1111,25 +1147,30 @@ def __getitem__(self, arg): Extension towers are built as follows and use distinct generator names:: + sage: # needs sage.rings.number_field sage.symbolic sage: K = QQ[2^(1/3), 2^(1/2), 3^(1/3)] sage: K - Number Field in a with defining polynomial x^3 - 2 over its base field + Number Field in a with defining polynomial x^3 - 2 + over its base field sage: K.base_field() - Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field + Number Field in sqrt2 with defining polynomial x^2 - 2 + over its base field sage: K.base_field().base_field() Number Field in b with defining polynomial x^3 - 3 Embeddings:: - sage: a = 10^100; expr = (2*a + sqrt(2))/(2*a^2-1) # optional - sage.symbolic - sage: QQ[expr].coerce_embedding() is None # optional - sage.symbolic + sage: # needs sage.rings.number_field sage.symbolic + sage: a = 10^100; expr = (2*a + sqrt(2))/(2*a^2-1) + sage: QQ[expr].coerce_embedding() is None False - sage: QQ[sqrt(5)].gen() > 0 # optional - sage.symbolic + sage: QQ[sqrt(5)].gen() > 0 True - sage: expr = sqrt(2) + I*(cos(pi/4, hold=True) - sqrt(2)/2) # optional - sage.symbolic - sage: QQ[expr].coerce_embedding() # optional - sage.symbolic + sage: expr = sqrt(2) + I*(cos(pi/4, hold=True) - sqrt(2)/2) + sage: QQ[expr].coerce_embedding() Generic morphism: - From: Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? + From: Number Field in a with defining polynomial x^2 - 2 + with a = 1.414213562373095? To: Real Lazy Field Defn: a -> 1.414213562373095? """ @@ -1159,7 +1200,10 @@ def normalize_arg(arg): if isinstance(arg, tuple): from sage.categories.morphism import Morphism - from sage.rings.derivation import RingDerivation + try: + from sage.rings.derivation import RingDerivation + except ImportError: + RingDerivation = () if len(arg) == 2 and isinstance(arg[1], (Morphism, RingDerivation)): from sage.rings.polynomial.ore_polynomial_ring import OrePolynomialRing return OrePolynomialRing(self, arg[1], names=arg[0]) @@ -1247,16 +1291,17 @@ def free_module(self, base=None, basis=None, map=True): EXAMPLES:: + sage: # needs sage.modules sage: R.<x> = QQ[[]] sage: V, from_V, to_V = R.free_module(R) - sage: v = to_V(1+x); v + sage: v = to_V(1 + x); v (1 + x) sage: from_V(v) 1 + x - sage: W, from_W, to_W = R.free_module(R, basis=(1-x)) + sage: W, from_W, to_W = R.free_module(R, basis=(1 - x)) sage: W is V True - sage: w = to_W(1+x); w + sage: w = to_W(1 + x); w (1 - x^2) sage: from_W(w) 1 + x + O(x^20) @@ -1300,6 +1345,7 @@ def is_unit(self) -> bool: EXAMPLES:: + sage: # needs sage.modules sage: MS = MatrixSpace(ZZ, 2) sage: MS.one().is_unit() True @@ -1325,8 +1371,8 @@ def inverse_of_unit(self): EXAMPLES:: sage: R.<x> = ZZ[] - sage: S = R.quo(x^2 + x + 1) - sage: S(1).inverse_of_unit() + sage: S = R.quo(x^2 + x + 1) # needs sage.libs.pari + sage: S(1).inverse_of_unit() # needs sage.libs.pari 1 This method fails when the element is not a unit:: @@ -1397,10 +1443,11 @@ def _gen_names(elts): EXAMPLES:: + sage: # needs sage.combinat sage: from sage.categories.rings import _gen_names - sage: list(_gen_names([sqrt(5)])) # optional - sage.symbolic + sage: list(_gen_names([sqrt(5)])) # needs sage.symbolic ['sqrt5'] - sage: list(_gen_names([sqrt(-17), 2^(1/3)])) # optional - sage.symbolic + sage: list(_gen_names([sqrt(-17), 2^(1/3)])) # needs sage.symbolic ['a', 'b'] sage: list(_gen_names((1..27)))[-1] 'aa' diff --git a/src/sage/categories/schemes.py b/src/sage/categories/schemes.py index df2ec0603cf..d27ac1fafd7 100644 --- a/src/sage/categories/schemes.py +++ b/src/sage/categories/schemes.py @@ -140,7 +140,7 @@ def _call_(self, x): from sage.categories.commutative_rings import CommutativeRings from sage.schemes.generic.spec import Spec from sage.categories.map import Map - from sage.categories.all import Rings + from sage.categories.rings import Rings if x in CommutativeRings(): return Spec(x) elif isinstance(x, Map) and x.category_for().is_subcategory(Rings()): @@ -148,7 +148,7 @@ def _call_(self, x): A = Spec(x.codomain()) return A.hom(x) else: - raise TypeError("No way to create an object or morphism in %s from %s"%(self, x)) + raise TypeError("No way to create an object or morphism in %s from %s" % (self, x)) ############################################################# diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index d053b20e3c0..4b85a255568 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -196,30 +196,40 @@ def cayley_graph(self, side="right", simple=False, elements=None, We start with the (right) Cayley graphs of some classical groups:: + sage: # needs sage.graphs sage.groups sage: D4 = DihedralGroup(4); D4 Dihedral group of order 8 as a permutation group sage: G = D4.cayley_graph() - sage: show(G, color_by_label=True, edge_labels=True) + sage: show(G, color_by_label=True, edge_labels=True) # needs sage.plot sage: A5 = AlternatingGroup(5); A5 Alternating group of order 5!/2 as a permutation group sage: G = A5.cayley_graph() - sage: G.show3d(color_by_label=True, edge_size=0.01, edge_size2=0.02, vertex_size=0.03) - sage: G.show3d(vertex_size=0.03, edge_size=0.01, edge_size2=0.02, vertex_colors={(1,1,1):G.vertices(sort=True)}, bgcolor=(0,0,0), color_by_label=True, xres=700, yres=700, iterations=200) # long time (less than a minute) + sage: G.show3d(color_by_label=True, edge_size=0.01, # needs sage.plot + ....: edge_size2=0.02, vertex_size=0.03) + sage: G.show3d(vertex_size=0.03, # long time (less than a minute), needs sage.plot + ....: edge_size=0.01, edge_size2=0.02, + ....: vertex_colors={(1,1,1): G.vertices(sort=True)}, + ....: bgcolor=(0,0,0), color_by_label=True, + ....: xres=700, yres=700, iterations=200) sage: G.num_edges() 120 - sage: w = WeylGroup(['A',3]) + sage: # needs sage.combinat sage.graphs sage.groups + sage: w = WeylGroup(['A', 3]) sage: d = w.cayley_graph(); d Digraph on 24 vertices - sage: d.show3d(color_by_label=True, edge_size=0.01, vertex_size=0.03) + sage: d.show3d(color_by_label=True, edge_size=0.01, vertex_size=0.03) # needs sage.plot Alternative generators may be specified:: + sage: # needs sage.graphs sage.groups sage: G = A5.cayley_graph(generators=[A5.gens()[0]]) sage: G.num_edges() 60 - sage: g = PermutationGroup([(i+1,j+1) for i in range(5) for j in range(5) if j!=i]) - sage: g.cayley_graph(generators=[(1,2),(2,3)]) + sage: g = PermutationGroup([(i + 1, j + 1) + ....: for i in range(5) + ....: for j in range(5) if j != i]) + sage: g.cayley_graph(generators=[(1,2), (2,3)]) Digraph on 120 vertices If ``elements`` is specified, then only the subgraph @@ -227,58 +237,63 @@ def cayley_graph(self, side="right", simple=False, elements=None, display the Cayley graph of the free monoid truncated on the elements of length at most 3:: + sage: # needs sage.combinat sage.graphs sage: M = Monoids().example(); M - An example of a monoid: the free monoid generated by ('a', 'b', 'c', 'd') - sage: elements = [ M.prod(w) for w in sum((list(Words(M.semigroup_generators(),k)) for k in range(4)),[]) ] - sage: G = M.cayley_graph(elements = elements) + An example of a monoid: + the free monoid generated by ('a', 'b', 'c', 'd') + sage: elements = [M.prod(w) + ....: for w in sum((list(Words(M.semigroup_generators(), k)) + ....: for k in range(4)), [])] + sage: G = M.cayley_graph(elements=elements) sage: G.num_verts(), G.num_edges() (85, 84) - sage: G.show3d(color_by_label=True, edge_size=0.001, vertex_size=0.01) + sage: G.show3d(color_by_label=True, edge_size=0.001, vertex_size=0.01) # needs sage.plot We now illustrate the ``side`` and ``simple`` options on a semigroup:: - sage: S = FiniteSemigroups().example(alphabet=('a','b')) - sage: g = S.cayley_graph(simple=True) - sage: g.vertices(sort=True) + sage: S = FiniteSemigroups().example(alphabet=('a', 'b')) + sage: g = S.cayley_graph(simple=True) # needs sage.graphs + sage: g.vertices(sort=True) # needs sage.graphs ['a', 'ab', 'b', 'ba'] - sage: g.edges(sort=True) + sage: g.edges(sort=True) # needs sage.graphs [('a', 'ab', None), ('b', 'ba', None)] :: - sage: g = S.cayley_graph(side="left", simple=True) - sage: g.vertices(sort=True) + sage: g = S.cayley_graph(side="left", simple=True) # needs sage.graphs + sage: g.vertices(sort=True) # needs sage.graphs ['a', 'ab', 'b', 'ba'] - sage: g.edges(sort=True) + sage: g.edges(sort=True) # needs sage.graphs [('a', 'ba', None), ('ab', 'ba', None), ('b', 'ab', None), ('ba', 'ab', None)] :: - sage: g = S.cayley_graph(side="twosided", simple=True) - sage: g.vertices(sort=True) + sage: g = S.cayley_graph(side="twosided", simple=True) # needs sage.graphs + sage: g.vertices(sort=True) # needs sage.graphs ['a', 'ab', 'b', 'ba'] - sage: g.edges(sort=True) + sage: g.edges(sort=True) # needs sage.graphs [('a', 'ab', None), ('a', 'ba', None), ('ab', 'ba', None), ('b', 'ab', None), ('b', 'ba', None), ('ba', 'ab', None)] :: - sage: g = S.cayley_graph(side="twosided") - sage: g.vertices(sort=True) + sage: g = S.cayley_graph(side="twosided") # needs sage.graphs + sage: g.vertices(sort=True) # needs sage.graphs ['a', 'ab', 'b', 'ba'] - sage: g.edges(sort=True) + sage: g.edges(sort=True) # needs sage.graphs [('a', 'a', (0, 'left')), ('a', 'a', (0, 'right')), ('a', 'ab', (1, 'right')), ('a', 'ba', (1, 'left')), ('ab', 'ab', (0, 'left')), ('ab', 'ab', (0, 'right')), ('ab', 'ab', (1, 'right')), ('ab', 'ba', (1, 'left')), ('b', 'ab', (0, 'left')), ('b', 'b', (1, 'left')), ('b', 'b', (1, 'right')), ('b', 'ba', (0, 'right')), ('ba', 'ab', (0, 'left')), ('ba', 'ba', (0, 'right')), ('ba', 'ba', (1, 'left')), ('ba', 'ba', (1, 'right'))] :: - sage: s1 = SymmetricGroup(1); s = s1.cayley_graph(); s.vertices(sort=False) + sage: s1 = SymmetricGroup(1); s = s1.cayley_graph() # needs sage.graphs sage.groups + sage: s.vertices(sort=False) # needs sage.graphs sage.groups [()] TESTS:: - sage: SymmetricGroup(2).cayley_graph(side="both") + sage: SymmetricGroup(2).cayley_graph(side="both") # needs sage.graphs sage.groups Traceback (most recent call last): ... ValueError: option 'side' must be 'left', 'right' or 'twosided' @@ -327,7 +342,7 @@ def cayley_graph(self, side="right", simple=False, elements=None, generators = self.semigroup_generators() if isinstance(generators, (list, tuple)): generators = dict((self(g), self(g)) for g in generators) - left = (side == "left" or side == "twosided") + left = (side == "left" or side == "twosided") right = (side == "right" or side == "twosided") def add_edge(source, target, label, side_label): @@ -375,38 +390,40 @@ def subsemigroup(self, generators, one=None, category=None): EXAMPLES:: sage: R = IntegerModRing(15) - sage: M = R.subsemigroup([R(3),R(5)]); M + sage: M = R.subsemigroup([R(3), R(5)]); M # needs sage.combinat A subsemigroup of (Ring of integers modulo 15) with 2 generators - sage: M.list() + sage: M.list() # needs sage.combinat [3, 5, 9, 0, 10, 12, 6] By default, `M` is just in the category of subsemigroups:: - sage: M in Semigroups().Subobjects() + sage: M in Semigroups().Subobjects() # needs sage.combinat True In the following example, we specify that `M` is a submonoid of the finite monoid `R` (it shares the same unit), and a group by itself:: - sage: M = R.subsemigroup([R(-1)], + sage: M = R.subsemigroup([R(-1)], # needs sage.combinat ....: category=Monoids().Finite().Subobjects() & Groups()); M A submonoid of (Ring of integers modulo 15) with 1 generators - sage: M.list() + sage: M.list() # needs sage.combinat [1, 14] - sage: M.one() + sage: M.one() # needs sage.combinat 1 - In the following example `M` is a group; however its unit + In the following example, `M` is a group; however, its unit does not coincide with that of `R`, so `M` is only a subsemigroup, and we need to specify its unit explicitly:: - sage: M = R.subsemigroup([R(5)], + sage: M = R.subsemigroup([R(5)], # needs sage.combinat ....: category=Semigroups().Finite().Subobjects() & Groups()); M Traceback (most recent call last): ... - ValueError: For a monoid which is just a subsemigroup, the unit should be specified + ValueError: For a monoid which is just a subsemigroup, + the unit should be specified + sage: # needs sage.groups sage: M = R.subsemigroup([R(5)], one=R(10), ....: category=Semigroups().Finite().Subobjects() & Groups()); M A subsemigroup of (Ring of integers modulo 15) with 1 generators @@ -419,7 +436,7 @@ def subsemigroup(self, generators, one=None, category=None): TESTS:: - sage: TestSuite(M).run() + sage: TestSuite(M).run() # needs sage.combinat Failure in _test_inverse: Traceback (most recent call last): ... @@ -449,8 +466,8 @@ def trivial_representation(self, base_ring=None, side="twosided"): EXAMPLES:: - sage: G = groups.permutation.Dihedral(4) - sage: G.trivial_representation() + sage: G = groups.permutation.Dihedral(4) # needs sage.groups + sage: G.trivial_representation() # needs sage.groups Trivial representation of Dihedral group of order 8 as a permutation group over Integer Ring """ @@ -469,8 +486,8 @@ def regular_representation(self, base_ring=None, side="left"): EXAMPLES:: - sage: G = groups.permutation.Dihedral(4) - sage: G.regular_representation() + sage: G = groups.permutation.Dihedral(4) # needs sage.groups + sage: G.regular_representation() # needs sage.groups Left Regular Representation of Dihedral group of order 8 as a permutation group over Integer Ring """ @@ -510,7 +527,6 @@ def _pow_int(self, n): raise ArithmeticError("only positive powers are supported in a semigroup") return generic_power(self, n) - class SubcategoryMethods: @cached_method @@ -881,7 +897,7 @@ def algebra_generators(self): the left regular band generated by ('a', 'b', 'c', 'd') sage: M.semigroup_generators() Family ('a', 'b', 'c', 'd') - sage: M.algebra(ZZ).algebra_generators() + sage: M.algebra(ZZ).algebra_generators() # needs sage.modules Family (B['a'], B['b'], B['c'], B['d']) """ return self.basis().keys().semigroup_generators().map(self.monomial) @@ -896,12 +912,12 @@ def gens(self): EXAMPLES:: - sage: a, b = SL2Z.algebra(ZZ).gens(); a, b + sage: a, b = SL2Z.algebra(ZZ).gens(); a, b # needs sage.groups sage.modules ([ 0 -1] [ 1 0], [1 1] [0 1]) - sage: 2*a + b + sage: 2*a + b # needs sage.groups sage.modules 2*[ 0 -1] [ 1 0] + @@ -916,9 +932,9 @@ def ngens(self): EXAMPLES:: - sage: SL2Z.algebra(ZZ).ngens() + sage: SL2Z.algebra(ZZ).ngens() # needs sage.groups sage.modules 2 - sage: DihedralGroup(4).algebra(RR).ngens() + sage: DihedralGroup(4).algebra(RR).ngens() # needs sage.groups sage.modules 2 """ return self.basis().keys().ngens() @@ -929,8 +945,8 @@ def gen(self, i=0): EXAMPLES:: - sage: A = GL(3, GF(7)).algebra(ZZ) - sage: A.gen(0) + sage: A = GL(3, GF(7)).algebra(ZZ) # needs sage.modules + sage: A.gen(0) # needs sage.groups sage.libs.pari sage.modules [3 0 0] [0 1 0] [0 0 1] @@ -949,10 +965,11 @@ def product_on_basis(self, g1, g2): EXAMPLES:: sage: S = FiniteSemigroups().example(); S - An example of a finite semigroup: the left regular band generated by ('a', 'b', 'c', 'd') - sage: A = S.algebra(QQ) - sage: a,b,c,d = A.algebra_generators() - sage: a * b + b * d * c * d + An example of a finite semigroup: + the left regular band generated by ('a', 'b', 'c', 'd') + sage: A = S.algebra(QQ) # needs sage.modules + sage: a, b, c, d = A.algebra_generators() # needs sage.modules + sage: a * b + b * d * c * d # needs sage.modules B['ab'] + B['bdc'] """ return self.monomial(g1 * g2) @@ -967,10 +984,11 @@ def trivial_representation(self, side="twosided"): EXAMPLES:: + sage: # needs sage.groups sage: G = groups.permutation.Dihedral(4) - sage: A = G.algebra(QQ) - sage: V = A.trivial_representation() - sage: V == G.trivial_representation(QQ) + sage: A = G.algebra(QQ) # needs sage.modules + sage: V = A.trivial_representation() # needs sage.modules + sage: V == G.trivial_representation(QQ) # needs sage.modules True """ S = self.basis().keys() @@ -987,10 +1005,11 @@ def regular_representation(self, side="left"): EXAMPLES:: + sage: # needs sage.groups sage: G = groups.permutation.Dihedral(4) - sage: A = G.algebra(QQ) - sage: V = A.regular_representation() - sage: V == G.regular_representation(QQ) + sage: A = G.algebra(QQ) # needs sage.modules + sage: V = A.regular_representation() # needs sage.modules + sage: V == G.regular_representation(QQ) # needs sage.modules True """ S = self.basis().keys() diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index be7a581c798..9a310614290 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -37,15 +37,15 @@ class SemisimpleAlgebras(Category_over_base_ring): Typically, finite group algebras are semisimple:: - sage: DihedralGroup(5).algebra(QQ) in SemisimpleAlgebras + sage: DihedralGroup(5).algebra(QQ) in SemisimpleAlgebras # needs sage.groups True Unless the characteristic of the field divides the order of the group:: - sage: DihedralGroup(5).algebra(IntegerModRing(5)) in SemisimpleAlgebras + sage: DihedralGroup(5).algebra(IntegerModRing(5)) in SemisimpleAlgebras # needs sage.groups False - sage: DihedralGroup(5).algebra(IntegerModRing(7)) in SemisimpleAlgebras + sage: DihedralGroup(5).algebra(IntegerModRing(7)) in SemisimpleAlgebras # needs sage.groups True .. SEEALSO:: :wikipedia:`Semisimple_algebra` @@ -96,13 +96,13 @@ def radical_basis(self, **keywords): EXAMPLES:: - sage: A = SymmetricGroup(4).algebra(QQ) - sage: A.radical_basis() + sage: A = SymmetricGroup(4).algebra(QQ) # needs sage.groups + sage: A.radical_basis() # needs sage.groups () TESTS:: - sage: A.radical_basis.__module__ + sage: A.radical_basis.__module__ # needs sage.groups 'sage.categories.finite_dimensional_semisimple_algebras_with_basis' """ return () diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 9f9bab84e23..16c117b286e 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -147,7 +147,7 @@ class Sets(Category_singleton): We run some generic checks on P:: - sage: TestSuite(P).run(verbose=True) + sage: TestSuite(P).run(verbose=True) # needs sage.libs.pari running ._test_an_element() . . . pass running ._test_cardinality() . . . pass running ._test_category() . . . pass @@ -867,11 +867,11 @@ def Facade(self): 1. as plain integers:: - sage: P = Poset((divisors(12), attrcall("divides")), facade=True) + sage: P = Poset((divisors(12), attrcall("divides")), facade=True) # needs sage.graphs 2. as integers, modified to be aware that their parent is `P`:: - sage: Q = Poset((divisors(12), attrcall("divides")), facade=False) + sage: Q = Poset((divisors(12), attrcall("divides")), facade=False) # needs sage.graphs The advantage of option 1. is that one needs not do conversions back and forth between `P` and `\ZZ`. The @@ -893,9 +893,9 @@ def Facade(self): the elements know unambiguously how to compare themselves:: - sage: Q(2) < Q(3) + sage: Q(2) < Q(3) # needs sage.graphs False - sage: Q(2) < Q(6) + sage: Q(2) < Q(6) # needs sage.graphs True Beware that ``P(2)`` is still the integer `2`. Therefore @@ -970,17 +970,19 @@ def _element_constructor_(self): sage: S(17) # indirect doctest 17 - sage: A = FreeModule(QQ, 3) - sage: A.element_class + sage: A = FreeModule(QQ, 3) # needs sage.modules + sage: A.element_class # needs sage.modules <class 'sage.modules.vector_rational_dense.Vector_rational_dense'> - sage: A._element_constructor_ - <bound method FreeModule_ambient_field._element_constructor_ of Vector space of dimension 3 over Rational Field> + sage: A._element_constructor_ # needs sage.modules + <bound method FreeModule_ambient_field._element_constructor_ + of Vector space of dimension 3 over Rational Field> - sage: B = SymmetricGroup(3).algebra(ZZ) - sage: B.element_class + sage: B = SymmetricGroup(3).algebra(ZZ) # needs sage.groups sage.modules + sage: B.element_class # needs sage.groups sage.modules <...SymmetricGroupAlgebra_n_with_category.element_class'> - sage: B._element_constructor_ - <bound method SymmetricGroupAlgebra_n._element_constructor_ of Symmetric group algebra of order 3 over Integer Ring> + sage: B._element_constructor_ # needs sage.groups sage.modules + <bound method SymmetricGroupAlgebra_n._element_constructor_ + of Symmetric group algebra of order 3 over Integer Ring> """ if hasattr(self, "element_class"): return self._element_constructor_from_element_class @@ -1068,7 +1070,7 @@ def an_element(self): EXAMPLES:: - sage: CDF.an_element() + sage: CDF.an_element() # needs sage.rings.complex_double 1.0*I sage: ZZ[['t']].an_element() t @@ -1190,12 +1192,12 @@ def _test_elements_eq_reflexive(self, **options): We try a non-reflexive equality:: sage: P = Sets().example("wrapper") - sage: P._test_elements_eq_reflexive() + sage: P._test_elements_eq_reflexive() # needs sage.libs.pari sage: eq = P.element_class.__eq__ sage: P.element_class.__eq__ = (lambda x, y: ....: False if eq(x, P(47)) and eq(y, P(47)) else eq(x, y)) - sage: P._test_elements_eq_reflexive() + sage: P._test_elements_eq_reflexive() # needs sage.libs.pari Traceback (most recent call last): ... AssertionError: 47 != 47 @@ -1226,7 +1228,7 @@ def _test_elements_eq_symmetric(self, **options): We test a non symmetric equality:: sage: P = Sets().example("wrapper") - sage: P._test_elements_eq_symmetric() + sage: P._test_elements_eq_symmetric() # needs sage.libs.pari sage: eq = P.element_class.__eq__ sage: def non_sym_eq(x, y): @@ -1234,7 +1236,7 @@ def _test_elements_eq_symmetric(self, **options): ....: elif eq(x, P(47)) and eq(y, P(53)): return True ....: else: return eq(x, y) sage: P.element_class.__eq__ = non_sym_eq - sage: P._test_elements_eq_symmetric() + sage: P._test_elements_eq_symmetric() # needs sage.libs.pari Traceback (most recent call last): ... AssertionError: non symmetric equality: 47 == 53 but 53 != 47 @@ -1248,7 +1250,7 @@ def _test_elements_eq_symmetric(self, **options): S = list(tester.some_elements()) + [None, 0] from sage.misc.misc import some_tuples for x, y in some_tuples(S, 2, tester._max_runs): - tester.assertEqual(x==y, y==x, + tester.assertEqual(x == y, y == x, LazyFormat("non symmetric equality: %s but %s") % ( print_compare(x, y), print_compare(y, x))) @@ -1267,9 +1269,9 @@ def _test_elements_eq_transitive(self, **options): We test a non transitive equality:: - sage: R = Zp(3) + sage: R = Zp(3) # needs sage.rings.padics sage: test = raw_getattr(Sets().ParentMethods, "_test_elements_eq_transitive") - sage: test(R, elements=[R(3,2),R(3,1),R(0)]) + sage: test(R, elements=[R(3,2), R(3,1), R(0)]) # needs sage.rings.padics Traceback (most recent call last): ... AssertionError: non transitive equality: @@ -1295,7 +1297,7 @@ def _test_elements_eq_transitive(self, **options): continue tester.assertEqual(x, z, LazyFormat("non transitive equality:\n" - "%s and %s but %s")%( + "%s and %s but %s") % ( print_compare(x, y), print_compare(y, z), print_compare(x, z))) @@ -1316,12 +1318,12 @@ def _test_elements_neq(self, **options): We try a broken inequality:: sage: P = Sets().example("wrapper") - sage: P._test_elements_neq() + sage: P._test_elements_neq() # needs sage.libs.pari sage: ne = P.element_class.__ne__ sage: eq = P.element_class.__eq__ sage: P.element_class.__ne__ = lambda x, y: False - sage: P._test_elements_neq() + sage: P._test_elements_neq() # needs sage.libs.pari Traceback (most recent call last): ... AssertionError: __eq__ and __ne__ inconsistency: @@ -1341,7 +1343,7 @@ def _test_elements_neq(self, **options): for x,y in some_tuples(S, 2, tester._max_runs): tester.assertNotEqual(x == y, x != y, LazyFormat("__eq__ and __ne__ inconsistency:\n" - " %s == %s returns %s but %s != %s returns %s")%( + " %s == %s returns %s but %s != %s returns %s") % ( x, y, (x == y), x, y, (x != y))) def some_elements(self): @@ -1402,7 +1404,7 @@ def _test_some_elements(self, **options): # "self.some_elements() should return an iterable, not an iterator") for x in elements: tester.assertIn(x, self, LazyFormat( - "the object %s in self.some_elements() is not in self")%(x,)) + "the object %s in self.some_elements() is not in self") % (x,)) #Note: the four methods 'cardinality', 'is_finite_, 'is_empty' and # 'random_element' might or might not be implemented in the parent @@ -1560,20 +1562,21 @@ def cartesian_product(*parents, **kwargs): EXAMPLES:: sage: C = AlgebrasWithBasis(QQ) - sage: A = C.example(); A.rename("A") - sage: A.cartesian_product(A,A) + sage: A = C.example(); A.rename("A") # needs sage.combinat sage.modules + sage: A.cartesian_product(A, A) # needs sage.combinat sage.modules A (+) A (+) A sage: ZZ.cartesian_product(GF(2), FiniteEnumeratedSet([1,2,3])) - The Cartesian product of (Integer Ring, Finite Field of size 2, {1, 2, 3}) + The Cartesian product of (Integer Ring, + Finite Field of size 2, {1, 2, 3}) - sage: C = ZZ.cartesian_product(A); C + sage: C = ZZ.cartesian_product(A); C # needs sage.combinat sage.modules The Cartesian product of (Integer Ring, A) TESTS:: - sage: type(C) + sage: type(C) # needs sage.combinat sage.modules <class 'sage.sets.cartesian_product.CartesianProduct_with_category'> - sage: C.category() + sage: C.category() # needs sage.combinat sage.modules Join of Category of rings and ... and Category of Cartesian products of commutative additive groups @@ -1626,11 +1629,12 @@ def algebra(self, base_ring, category=None, **kwds): If `S` is a :class:`group <Groups>`, the result is its group algebra `KS`:: + sage: # needs sage.groups sage.modules sage: S = DihedralGroup(4); S - Dihedral group of order 8 as a permutation group + Dihedral group of order 8 as a permutation group sage: A = S.algebra(QQ); A Algebra of Dihedral group of order 8 as a permutation group - over Rational Field + over Rational Field sage: A.category() Category of finite group algebras over Rational Field sage: a = A.an_element(); a @@ -1640,7 +1644,7 @@ def algebra(self, base_ring, category=None, **kwds): by extending by bilinearity the multiplication of `G` to a multiplication on `RG`:: - sage: a * a + sage: a * a # needs sage.groups sage.modules 6*() + 4*(2,4) + 3*(1,2)(3,4) + 12*(1,2,3,4) + 2*(1,3) + 13*(1,3)(2,4) + 6*(1,4,3,2) + 3*(1,4)(2,3) @@ -1648,11 +1652,13 @@ def algebra(self, base_ring, category=None, **kwds): monoid algebra `KS`:: sage: S = Monoids().example(); S - An example of a monoid: the free monoid generated by ('a', 'b', 'c', 'd') - sage: A = S.algebra(QQ); A - Algebra of An example of a monoid: the free monoid generated by ('a', 'b', 'c', 'd') - over Rational Field - sage: A.category() + An example of a monoid: + the free monoid generated by ('a', 'b', 'c', 'd') + sage: A = S.algebra(QQ); A # needs sage.modules + Algebra of + An example of a monoid: the free monoid generated by ('a', 'b', 'c', 'd') + over Rational Field + sage: A.category() # needs sage.modules Category of monoid algebras over Rational Field Similarly, we can construct algebras for additive magmas, @@ -1661,6 +1667,7 @@ def algebra(self, base_ring, category=None, **kwds): One may specify for which category one takes the algebra; here we build the algebra of the additive group `GF_3`:: + sage: # needs sage.modules sage: from sage.categories.additive_groups import AdditiveGroups sage: S = GF(7) sage: A = S.algebra(QQ, category=AdditiveGroups()); A @@ -1668,7 +1675,6 @@ def algebra(self, base_ring, category=None, **kwds): sage: A.category() Category of finite dimensional additive group algebras over Rational Field - sage: a = A(S(1)) sage: a 1 @@ -1715,6 +1721,7 @@ def _sympy_(self): EXAMPLES:: + sage: # needs sympy sage: F = FiniteEnumeratedSets().example(); F An example of a finite enumerated set: {1,2,3} sage: sF = F._sympy_(); sF @@ -1728,18 +1735,18 @@ def _sympy_(self): sage: list(sF) [1, 2, 3] sage: from sympy import FiniteSet - sage: FiniteSet.fromiter(sF) # random - this output format is sympy >= 1.9 + sage: FiniteSet.fromiter(sF) # random - this output is sympy >= 1.9 FiniteSet(1, 2, 3) - sage: RR._sympy_().is_finite_set + sage: RR._sympy_().is_finite_set # needs sympy False sage: F = Family([1, 2]) sage: F is Family([1, 2]) False - sage: sF = F._sympy_(); sF + sage: sF = F._sympy_(); sF # needs sympy SageSet(Family (1, 2)) - sage: sF._sage_() is F + sage: sF._sage_() is F # needs sympy True """ from sage.interfaces.sympy_wrapper import SageSet @@ -1764,9 +1771,9 @@ def cartesian_product(*elements): EXAMPLES:: sage: C = AlgebrasWithBasis(QQ) - sage: A = C.example() - sage: (a,b,c) = A.algebra_generators() - sage: a.cartesian_product(b, c) + sage: A = C.example() # needs sage.combinat sage.modules + sage: a, b, c = A.algebra_generators() # needs sage.combinat sage.modules + sage: a.cartesian_product(b, c) # needs sage.combinat sage.modules B[(0, word: a)] + B[(1, word: b)] + B[(2, word: c)] FIXME: is this a policy that we want to enforce on all parents? @@ -1800,22 +1807,22 @@ def __invert__(self): We now try to inverse a couple of morphisms defined by a matrix:: - sage: H = End(QQ^2) - sage: phi = H(matrix([[1,1],[0,1]])); phi + sage: H = End(QQ^2) # needs sage.modules + sage: phi = H(matrix([[1,1], [0,1]])); phi # needs sage.modules Vector space morphism represented by the matrix: [1 1] [0 1] Domain: Vector space of dimension 2 over Rational Field Codomain: Vector space of dimension 2 over Rational Field - sage: ~phi + sage: ~phi # needs sage.modules Vector space morphism represented by the matrix: [ 1 -1] [ 0 1] Domain: Vector space of dimension 2 over Rational Field Codomain: Vector space of dimension 2 over Rational Field - sage: phi = H(matrix([[1,1],[1,1]])) - sage: ~phi + sage: phi = H(matrix([[1,1], [1,1]])) # needs sage.modules + sage: ~phi # needs sage.modules Traceback (most recent call last): ... ZeroDivisionError: matrix morphism not invertible @@ -1851,11 +1858,12 @@ def image(self, domain_subset=None): EXAMPLES:: + sage: # needs sage.combinat sage: P = Partitions(6) sage: H = Hom(P, ZZ) sage: f = H(ZZ.sum) - sage: X = f.image() - sage: list(X) + sage: X = f.image() # needs sage.libs.flint + sage: list(X) # needs sage.libs.flint [6] """ D = self.domain() @@ -1964,7 +1972,7 @@ def _repr_(self): sage: S._repr_() 'A subquotient of An example of a semigroup: the left zero semigroup' """ - return "A subquotient of %s"%(self.ambient()) + return "A subquotient of %s" % (self.ambient()) @abstract_method def ambient(self): @@ -2006,7 +2014,8 @@ def lift(self, x): sage: S = Semigroups().Subquotients().example() sage: s = S.an_element() sage: s, s.parent() - (42, An example of a (sub)quotient semigroup: a quotient of the left zero semigroup) + (42, An example of a (sub)quotient semigroup: + a quotient of the left zero semigroup) sage: S.lift(s), S.lift(s).parent() (42, An example of a semigroup: the left zero semigroup) sage: s.lift(), s.lift().parent() @@ -2041,7 +2050,8 @@ def retract(self, x): sage: s, s.parent() (42, An example of a semigroup: the left zero semigroup) sage: S.retract(s), S.retract(s).parent() - (42, An example of a (sub)quotient semigroup: a quotient of the left zero semigroup) + (42, An example of a (sub)quotient semigroup: + a quotient of the left zero semigroup) """ class ElementMethods: @@ -2055,7 +2065,8 @@ def lift(self): sage: S = Semigroups().Subquotients().example() sage: s = S.an_element() sage: s, s.parent() - (42, An example of a (sub)quotient semigroup: a quotient of the left zero semigroup) + (42, An example of a (sub)quotient semigroup: + a quotient of the left zero semigroup) sage: S.lift(s), S.lift(s).parent() (42, An example of a semigroup: the left zero semigroup) sage: s.lift(), s.lift().parent() @@ -2132,7 +2143,7 @@ def _repr_(self): EXAMPLES:: sage: from sage.categories.examples.semigroups import IncompleteSubquotientSemigroup - sage: S = IncompleteSubquotientSemigroup(category = Semigroups().Subobjects()) + sage: S = IncompleteSubquotientSemigroup(category=Semigroups().Subobjects()) sage: S._repr_() 'A subobject of An example of a semigroup: the left zero semigroup' """ @@ -2165,7 +2176,7 @@ def _repr_(self): sage: S._repr_() 'The image by some isomorphism of An example of a finite enumerated set: {1,2,3}' """ - return "The image by some isomorphism of %s"%(self.ambient()) + return "The image by some isomorphism of %s" % (self.ambient()) class CartesianProducts(CartesianProductsCategory): """ @@ -2215,7 +2226,6 @@ def example(self): S3 = FiniteEnumeratedSets().example() return cartesian_product([S1, S2, S3]) - class ParentMethods: def __iter__(self): r""" @@ -2232,7 +2242,7 @@ def __iter__(self): Sets are intrinsically unordered:: - sage: for x,y in cartesian_product([Set([1,2]), Set(['a','b'])]): # random + sage: for x,y in cartesian_product([Set([1,2]), Set(['a','b'])]): # random ....: print((x, y)) (1, 'b') (1, 'a') @@ -2256,6 +2266,7 @@ def __iter__(self): sage: list(F22) [(0, 0), (0, 1), (1, 0), (1, 1)] + sage: # needs sage.combinat sage: C = cartesian_product([Permutations(10)]*4) sage: it = iter(C) sage: next(it) @@ -2379,8 +2390,8 @@ def is_finite(self): EXAMPLES:: sage: E = FiniteEnumeratedSet([1,2,3]) - sage: C = cartesian_product([E, SymmetricGroup(4)]) - sage: C.is_finite() + sage: C = cartesian_product([E, SymmetricGroup(4)]) # needs sage.groups + sage: C.is_finite() # needs sage.groups True sage: cartesian_product([ZZ,ZZ]).is_finite() @@ -2407,8 +2418,8 @@ def cardinality(self): EXAMPLES:: sage: E = FiniteEnumeratedSet([1,2,3]) - sage: C = cartesian_product([E,SymmetricGroup(4)]) - sage: C.cardinality() + sage: C = cartesian_product([E, SymmetricGroup(4)]) # needs sage.groups + sage: C.cardinality() # needs sage.groups 72 sage: E = FiniteEnumeratedSet([]) @@ -2563,9 +2574,9 @@ def _sympy_(self): EXAMPLES:: sage: ZZ3 = cartesian_product([ZZ, ZZ, ZZ]) - sage: sZZ3 = ZZ3._sympy_(); sZZ3 + sage: sZZ3 = ZZ3._sympy_(); sZZ3 # needs sympy ProductSet(Integers, Integers, Integers) - sage: (1, 2, 3) in sZZ3 + sage: (1, 2, 3) in sZZ3 # needs sympy True """ from sympy import ProductSet @@ -2586,10 +2597,12 @@ def cartesian_projection(self, i): EXAMPLES:: - sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.__custom_name = "F" - sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.__custom_name = "G" + sage: # needs sage.modules + sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename("F") + sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename("G") sage: S = cartesian_product([F, G]) - sage: x = S.monomial((0,4)) + 2 * S.monomial((0,5)) + 3 * S.monomial((1,6)) + sage: x = (S.monomial((0,4)) + 2 * S.monomial((0,5)) + ....: + 3 * S.monomial((1,6))) sage: x.cartesian_projection(0) B[4] + 2*B[5] sage: x.cartesian_projection(1) @@ -2603,11 +2616,14 @@ def cartesian_factors(self): EXAMPLES:: - sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.__custom_name = "F" - sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.__custom_name = "G" - sage: H = CombinatorialFreeModule(ZZ, [4,7]); H.__custom_name = "H" + sage: # needs sage.modules + sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename("F") + sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename("G") + sage: H = CombinatorialFreeModule(ZZ, [4,7]); H.rename("H") sage: S = cartesian_product([F, G, H]) - sage: x = S.monomial((0,4)) + 2 * S.monomial((0,5)) + 3 * S.monomial((1,6)) + 4 * S.monomial((2,4)) + 5 * S.monomial((2,7)) + sage: x = (S.monomial((0,4)) + 2 * S.monomial((0,5)) + ....: + 3 * S.monomial((1,6)) + 4 * S.monomial((2,4)) + ....: + 5 * S.monomial((2,7))) sage: x.cartesian_factors() (B[4] + 2*B[5], 3*B[6], 4*B[4] + 5*B[7]) sage: [s.parent() for s in x.cartesian_factors()] @@ -2634,7 +2650,7 @@ def extra_super_categories(self): sage: Sets().Algebras(QQ).extra_super_categories() [Category of vector spaces with basis over Rational Field] - sage: Sets().example().algebra(ZZ).categories() + sage: Sets().example().algebra(ZZ).categories() # needs sage.modules [Category of set algebras over Integer Ring, Category of modules with basis over Integer Ring, ... @@ -2651,20 +2667,20 @@ def construction(self): EXAMPLES:: - sage: A = GroupAlgebra(KleinFourGroup(), QQ) - sage: F, arg = A.construction(); F, arg + sage: A = GroupAlgebra(KleinFourGroup(), QQ) # needs sage.groups sage.modules + sage: F, arg = A.construction(); F, arg # needs sage.groups sage.modules (GroupAlgebraFunctor, Rational Field) - sage: F(arg) is A + sage: F(arg) is A # needs sage.groups sage.modules True This also works for structures such as monoid algebras (see :trac:`27937`):: - sage: A = FreeAbelianMonoid('x,y').algebra(QQ) - sage: F, arg = A.construction(); F, arg + sage: A = FreeAbelianMonoid('x,y').algebra(QQ) # needs sage.groups sage.modules + sage: F, arg = A.construction(); F, arg # needs sage.groups sage.modules (The algebra functorial construction, Free abelian monoid on 2 generators (x, y)) - sage: F(arg) is A + sage: F(arg) is A # needs sage.groups sage.modules True """ from sage.categories.algebra_functor import ( @@ -2682,6 +2698,7 @@ def _repr_(self): EXAMPLES:: + sage: # needs sage.groups sage.modules sage: A = Groups().example().algebra(QQ); A Algebra of General Linear Group of degree 4 over Rational Field over Rational Field @@ -2721,10 +2738,10 @@ def example(self, base_ring=None, set=None): EXAMPLES:: - sage: Sets().WithRealizations().example() + sage: Sets().WithRealizations().example() # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: Sets().WithRealizations().example(ZZ, Set([1,2])) + sage: Sets().WithRealizations().example(ZZ, Set([1,2])) # needs sage.modules The subset algebra of {1, 2} over Integer Ring """ from sage.rings.rational_field import QQ @@ -2750,8 +2767,8 @@ def _test_with_realizations(self, **options): EXAMPLES:: - sage: A = Sets().WithRealizations().example() - sage: A._test_with_realizations() + sage: A = Sets().WithRealizations().example() # needs sage.modules + sage: A._test_with_realizations() # needs sage.modules See the documentation for :class:`TestSuite` for more information. @@ -2781,12 +2798,15 @@ def _register_realization(self, realization): """ EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = Sets().WithRealizations().example(QQ['x']); A - The subset algebra of {1, 2, 3} over Univariate Polynomial Ring in x over Rational Field + The subset algebra of {1, 2, 3} + over Univariate Polynomial Ring in x over Rational Field sage: class ANewRealizationOfA(CombinatorialFreeModule): ....: pass - sage: category = A.Realizations() & Algebras(QQ[x]).WithBasis() - sage: R = ANewRealizationOfA(A.base_ring(), A.F().basis().keys(), category = category) + sage: category = A.Realizations() & Algebras(QQ['x']).WithBasis() + sage: R = ANewRealizationOfA(A.base_ring(), A.F().basis().keys(), + ....: category=category) sage: R in A.realizations() # indirect doctest True @@ -2815,25 +2835,32 @@ def inject_shorthands(self, shorthands=None, verbose=True): it is convenient to define shorthands for the various realizations, but cumbersome to do it by hand:: - sage: S = SymmetricFunctions(ZZ); S + sage: S = SymmetricFunctions(ZZ); S # needs sage.combinat sage.modules Symmetric Functions over Integer Ring - sage: s = S.s(); s + sage: s = S.s(); s # needs sage.combinat sage.modules Symmetric Functions over Integer Ring in the Schur basis - sage: e = S.e(); e + sage: e = S.e(); e # needs sage.combinat sage.modules Symmetric Functions over Integer Ring in the elementary basis This method automates the process:: + sage: # needs sage.combinat sage.modules sage: S.inject_shorthands() - Defining e as shorthand for Symmetric Functions over Integer Ring in the elementary basis - Defining f as shorthand for Symmetric Functions over Integer Ring in the forgotten basis - Defining h as shorthand for Symmetric Functions over Integer Ring in the homogeneous basis - Defining m as shorthand for Symmetric Functions over Integer Ring in the monomial basis - Defining p as shorthand for Symmetric Functions over Integer Ring in the powersum basis - Defining s as shorthand for Symmetric Functions over Integer Ring in the Schur basis + Defining e as shorthand for + Symmetric Functions over Integer Ring in the elementary basis + Defining f as shorthand for + Symmetric Functions over Integer Ring in the forgotten basis + Defining h as shorthand for + Symmetric Functions over Integer Ring in the homogeneous basis + Defining m as shorthand for + Symmetric Functions over Integer Ring in the monomial basis + Defining p as shorthand for + Symmetric Functions over Integer Ring in the powersum basis + Defining s as shorthand for + Symmetric Functions over Integer Ring in the Schur basis sage: s[1] + e[2] * p[1,1] + 2*h[3] + m[2,1] - s[1] - 2*s[1, 1, 1] + s[1, 1, 1, 1] + s[2, 1] + 2*s[2, 1, 1] + s[2, 2] + 2*s[3] + s[3, 1] - + s[1] - 2*s[1, 1, 1] + s[1, 1, 1, 1] + s[2, 1] + + 2*s[2, 1, 1] + s[2, 2] + 2*s[3] + s[3, 1] sage: e Symmetric Functions over Integer Ring in the elementary basis sage: p @@ -2845,28 +2872,40 @@ def inject_shorthands(self, shorthands=None, verbose=True): request for all shorthands to be defined, including less common ones:: - sage: S.inject_shorthands("all") - Defining e as shorthand for Symmetric Functions over Integer Ring in the elementary basis - Defining f as shorthand for Symmetric Functions over Integer Ring in the forgotten basis - Defining h as shorthand for Symmetric Functions over Integer Ring in the homogeneous basis - Defining ht as shorthand for Symmetric Functions over Integer Ring in the induced trivial symmetric group character basis - Defining m as shorthand for Symmetric Functions over Integer Ring in the monomial basis - Defining o as shorthand for Symmetric Functions over Integer Ring in the orthogonal basis - Defining p as shorthand for Symmetric Functions over Integer Ring in the powersum basis - Defining s as shorthand for Symmetric Functions over Integer Ring in the Schur basis - Defining sp as shorthand for Symmetric Functions over Integer Ring in the symplectic basis - Defining st as shorthand for Symmetric Functions over Integer Ring in the irreducible symmetric group character basis - Defining w as shorthand for Symmetric Functions over Integer Ring in the Witt basis + sage: S.inject_shorthands("all") # needs sage.combinat sage.modules + Defining e as shorthand for + Symmetric Functions over Integer Ring in the elementary basis + Defining f as shorthand for + Symmetric Functions over Integer Ring in the forgotten basis + Defining h as shorthand for + Symmetric Functions over Integer Ring in the homogeneous basis + Defining ht as shorthand for + Symmetric Functions over Integer Ring in the + induced trivial symmetric group character basis + Defining m as shorthand for + Symmetric Functions over Integer Ring in the monomial basis + Defining o as shorthand for + Symmetric Functions over Integer Ring in the orthogonal basis + Defining p as shorthand for + Symmetric Functions over Integer Ring in the powersum basis + Defining s as shorthand for + Symmetric Functions over Integer Ring in the Schur basis + Defining sp as shorthand for + Symmetric Functions over Integer Ring in the symplectic basis + Defining st as shorthand for + Symmetric Functions over Integer Ring in the + irreducible symmetric group character basis + Defining w as shorthand for + Symmetric Functions over Integer Ring in the Witt basis The messages can be silenced by setting ``verbose=False``:: + sage: # needs sage.combinat sage.modules sage: Q = QuasiSymmetricFunctions(ZZ) sage: Q.inject_shorthands(verbose=False) - sage: F[1,2,1] + 5*M[1,3] + F[2]^2 5*F[1, 1, 1, 1] - 5*F[1, 1, 2] - 3*F[1, 2, 1] + 6*F[1, 3] + 2*F[2, 2] + F[3, 1] + F[4] - sage: F Quasisymmetric functions over the Integer Ring in the Fundamental basis @@ -2876,6 +2915,7 @@ def inject_shorthands(self, shorthands=None, verbose=True): One can also just import a subset of the shorthands:: + sage: # needs sage.combinat sage.modules sage: SQ = SymmetricFunctions(QQ) sage: SQ.inject_shorthands(['p', 's'], verbose=False) sage: p @@ -2885,12 +2925,12 @@ def inject_shorthands(self, shorthands=None, verbose=True): Note that ``e`` is left unchanged:: - sage: e + sage: e # needs sage.combinat sage.modules Symmetric Functions over Integer Ring in the elementary basis TESTS:: - sage: e == S.e(), h == S.h(), m == S.m(), p == SQ.p(), s == SQ.s() + sage: e == S.e(), h == S.h(), m == S.m(), p == SQ.p(), s == SQ.s() # needs sage.combinat sage.modules (True, True, True, True, True) """ from sage.misc.misc import inject_variable @@ -2913,10 +2953,11 @@ def a_realization(self): EXAMPLES:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules + The subset algebra of {1, 2, 3} over Rational Field + sage: A.a_realization() # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: A.a_realization() - The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis + in the Fundamental basis """ def realizations(self): @@ -2926,10 +2967,12 @@ def realizations(self): EXAMPLES:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: A.realizations() - [The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis, The subset algebra of {1, 2, 3} over Rational Field in the In basis, The subset algebra of {1, 2, 3} over Rational Field in the Out basis] + sage: A.realizations() # needs sage.modules + [The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis, + The subset algebra of {1, 2, 3} over Rational Field in the In basis, + The subset algebra of {1, 2, 3} over Rational Field in the Out basis] .. NOTE:: @@ -2946,11 +2989,14 @@ def facade_for(self): EXAMPLES:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: A.facade_for() - [The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis, The subset algebra of {1, 2, 3} over Rational Field in the In basis, The subset algebra of {1, 2, 3} over Rational Field in the Out basis] + sage: A.facade_for() # needs sage.modules + [The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis, + The subset algebra of {1, 2, 3} over Rational Field in the In basis, + The subset algebra of {1, 2, 3} over Rational Field in the Out basis] + sage: # needs sage.combinat sage.modules sage: A = Sets().WithRealizations().example(); A The subset algebra of {1, 2, 3} over Rational Field sage: f = A.F().an_element(); f @@ -2971,9 +3017,9 @@ def super_categories(self): """ EXAMPLES:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: A.Realizations().super_categories() + sage: A.Realizations().super_categories() # needs sage.modules [Category of realizations of sets] """ return [Sets().Realizations()] @@ -2984,9 +3030,9 @@ def _an_element_(self): EXAMPLES:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: A.an_element() # indirect doctest + sage: A.an_element() # indirect doctest # needs sage.modules F[{}] + 2*F[{1}] + 3*F[{2}] + F[{1, 2}] TESTS: @@ -2994,9 +3040,9 @@ def _an_element_(self): Check that we are consistent no matter which basis is created first:: - sage: M = posets.BooleanLattice(4).moebius_algebra(QQ) - sage: I = M.I() - sage: M._an_element_() + sage: M = posets.BooleanLattice(4).moebius_algebra(QQ) # needs sage.combinat sage.graphs sage.modules + sage: I = M.I() # needs sage.combinat sage.graphs sage.modules + sage: M._an_element_() # needs sage.combinat sage.graphs sage.modules 2*E[0] + 2*E[1] + 3*E[2] """ return self.a_realization().an_element() @@ -3009,6 +3055,7 @@ def __contains__(self, x): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = Sets().WithRealizations().example(); A The subset algebra of {1, 2, 3} over Rational Field sage: A.an_element() in A @@ -3036,8 +3083,8 @@ def __init_extra__(self): TESTS:: - sage: A = Sets().WithRealizations().example() - sage: A.realizations() # indirect doctest + sage: A = Sets().WithRealizations().example() # needs sage.modules + sage: A.realizations() # indirect doctest # needs sage.modules [The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis, The subset algebra of {1, 2, 3} over Rational Field in the In basis, The subset algebra of {1, 2, 3} over Rational Field in the Out basis] @@ -3051,11 +3098,11 @@ def realization_of(self): EXAMPLES:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: In = A.In(); In + sage: In = A.In(); In # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field in the In basis - sage: In.realization_of() + sage: In.realization_of() # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field """ for category in self.categories(): @@ -3071,11 +3118,11 @@ def _realization_name(self): EXAMPLES:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: In = A.In(); In + sage: In = A.In(); In # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field in the In basis - sage: In._realization_name() + sage: In._realization_name() # needs sage.modules 'In' """ # The __base__ gets rid of the with_category @@ -3086,9 +3133,9 @@ def _repr_(self): """ EXAMPLES:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field - sage: In = A.In(); In + sage: In = A.In(); In # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field in the In basis In the example above, :meth:`repr` was overridden by @@ -3100,11 +3147,13 @@ def _repr_(self): sage: from sage.categories.realizations import Realizations sage: class Blah(Parent): ....: pass - sage: P = Blah(category = Sets.WithRealizations.ParentMethods.Realizations(A)) - sage: P # indirect doctest + sage: C = Sets.WithRealizations.ParentMethods.Realizations(A) # needs sage.modules + sage: P = Blah(category=C) # needs sage.modules + sage: P # indirect doctest # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field in the realization Blah """ return "{} in the realization {}".format(self.realization_of(), self._realization_name()) + # Moved from sage.categories.cartesian_product to avoid circular import errors cartesian_product = CartesianProductFunctor() diff --git a/src/sage/categories/sets_with_grading.py b/src/sage/categories/sets_with_grading.py index 5d01bfab999..b1e321f67f2 100644 --- a/src/sage/categories/sets_with_grading.py +++ b/src/sage/categories/sets_with_grading.py @@ -161,9 +161,9 @@ def subset(self, *args, **options): EXAMPLES:: - sage: W = WeightedIntegerVectors([3,2,1]); W + sage: W = WeightedIntegerVectors([3,2,1]); W # needs sage.combinat Integer vectors weighted by [3, 2, 1] - sage: W.subset(4) + sage: W.subset(4) # needs sage.combinat Integer vectors of 4 weighted by [3, 2, 1] """ @@ -213,7 +213,7 @@ def generating_series(self): sage: N.generating_series() 1/(-z + 1) - sage: Permutations().generating_series() + sage: Permutations().generating_series() # needs sage.combinat 1 + z + 2*z^2 + 6*z^3 + 24*z^4 + 120*z^5 + 720*z^6 + O(z^7) .. TODO:: diff --git a/src/sage/categories/simplicial_complexes.py b/src/sage/categories/simplicial_complexes.py index 0e35d866239..9750dcab686 100644 --- a/src/sage/categories/simplicial_complexes.py +++ b/src/sage/categories/simplicial_complexes.py @@ -67,8 +67,8 @@ def dimension(self): EXAMPLES:: - sage: S = SimplicialComplex([[1,3,4], [1,2],[2,5],[4,5]]) - sage: S.dimension() + sage: S = SimplicialComplex([[1,3,4], [1,2],[2,5],[4,5]]) # needs sage.graphs + sage: S.dimension() # needs sage.graphs 2 """ return max(c.dimension() for c in self.facets()) @@ -81,8 +81,8 @@ def facets(self): EXAMPLES:: - sage: S = SimplicialComplex([[1,3,4], [1,2],[2,5],[4,5]]) - sage: sorted(S.facets()) + sage: S = SimplicialComplex([[1,3,4], [1,2],[2,5],[4,5]]) # needs sage.graphs + sage: sorted(S.facets()) # needs sage.graphs [(1, 2), (1, 3, 4), (2, 5), (4, 5)] """ @@ -93,8 +93,8 @@ def faces(self): EXAMPLES:: - sage: S = SimplicialComplex([[1,3,4], [1,2],[2,5],[4,5]]) - sage: S.faces() + sage: S = SimplicialComplex([[1,3,4], [1,2],[2,5],[4,5]]) # needs sage.graphs + sage: S.faces() # needs sage.graphs {-1: {()}, 0: {(1,), (2,), (3,), (4,), (5,)}, 1: {(1, 2), (1, 3), (1, 4), (2, 5), (3, 4), (4, 5)}, diff --git a/src/sage/categories/simplicial_sets.py b/src/sage/categories/simplicial_sets.py index 8587e78aebf..c07871402fd 100644 --- a/src/sage/categories/simplicial_sets.py +++ b/src/sage/categories/simplicial_sets.py @@ -1,12 +1,12 @@ """ Simplicial Sets """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 John H. Palmieri <palmieri at math.washington.edu> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.category_singleton import Category_singleton @@ -16,6 +16,7 @@ from sage.rings.infinity import Infinity from sage.rings.integer import Integer + class SimplicialSets(Category_singleton): r""" The category of simplicial sets. @@ -70,10 +71,10 @@ def is_finite(self): EXAMPLES:: - sage: simplicial_sets.Torus().is_finite() + sage: simplicial_sets.Torus().is_finite() # needs sage.graphs True - sage: C5 = groups.misc.MultiplicativeAbelian([5]) - sage: simplicial_sets.ClassifyingSpace(C5).is_finite() + sage: C5 = groups.misc.MultiplicativeAbelian([5]) # needs sage.graphs sage.groups + sage: simplicial_sets.ClassifyingSpace(C5).is_finite() # needs sage.graphs sage.groups False """ return SimplicialSets.Finite() in self.categories() @@ -85,6 +86,7 @@ def is_pointed(self): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0) sage: w = AbstractSimplex(0) @@ -109,6 +111,7 @@ def set_base_point(self, point): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v_0') sage: w = AbstractSimplex(0, name='w_0') @@ -126,12 +129,12 @@ def set_base_point(self, point): TESTS:: - sage: X.set_base_point(e) + sage: X.set_base_point(e) # needs sage.graphs Traceback (most recent call last): ... ValueError: the "point" is not a zero-simplex - sage: pt = AbstractSimplex(0) - sage: X.set_base_point(pt) + sage: pt = AbstractSimplex(0) # needs sage.graphs + sage: X.set_base_point(pt) # needs sage.graphs Traceback (most recent call last): ... ValueError: the point is not a simplex in this simplicial set @@ -153,8 +156,8 @@ def one(self): EXAMPLES:: - sage: T = simplicial_sets.Torus() - sage: Hom(T, T).identity() + sage: T = simplicial_sets.Torus() # needs sage.graphs + sage: Hom(T, T).identity() # needs sage.graphs Simplicial set endomorphism of Torus Defn: Identity map """ @@ -196,6 +199,7 @@ def base_point(self): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='*') sage: e = AbstractSimplex(1) @@ -225,6 +229,7 @@ def base_point_map(self, domain=None): EXAMPLES:: + sage: # needs sage.graphs sage: T = simplicial_sets.Torus() sage: f = T.base_point_map(); f Simplicial set morphism: @@ -235,16 +240,16 @@ def base_point_map(self, domain=None): sage: g = S3.base_point_map() sage: f.domain() == g.domain() True - sage: RP3 = simplicial_sets.RealProjectiveSpace(3) + sage: RP3 = simplicial_sets.RealProjectiveSpace(3) # needs sage.groups sage: temp = simplicial_sets.Simplex(0) sage: pt = temp.set_base_point(temp.n_cells(0)[0]) - sage: h = RP3.base_point_map(domain=pt) - sage: f.domain() == h.domain() + sage: h = RP3.base_point_map(domain=pt) # needs sage.groups + sage: f.domain() == h.domain() # needs sage.groups False - sage: C5 = groups.misc.MultiplicativeAbelian([5]) - sage: BC5 = simplicial_sets.ClassifyingSpace(C5) - sage: BC5.base_point_map() + sage: C5 = groups.misc.MultiplicativeAbelian([5]) # needs sage.graphs sage.groups + sage: BC5 = simplicial_sets.ClassifyingSpace(C5) # needs sage.graphs sage.groups + sage: BC5.base_point_map() # needs sage.graphs sage.groups Simplicial set morphism: From: Point To: Classifying space of Multiplicative Abelian group isomorphic to C5 @@ -284,40 +289,42 @@ def fundamental_group(self, simplify=True): EXAMPLES:: - sage: S1 = simplicial_sets.Sphere(1) - sage: eight = S1.wedge(S1) - sage: eight.fundamental_group() # free group on 2 generators + sage: S1 = simplicial_sets.Sphere(1) # needs sage.graphs + sage: eight = S1.wedge(S1) # needs sage.graphs + sage: eight.fundamental_group() # free group on 2 generators # needs sage.graphs sage.groups Finitely presented group < e0, e1 | > The fundamental group of a disjoint union of course depends on the choice of base point:: - sage: T = simplicial_sets.Torus() - sage: K = simplicial_sets.KleinBottle() - sage: X = T.disjoint_union(K) + sage: T = simplicial_sets.Torus() # needs sage.graphs + sage: K = simplicial_sets.KleinBottle() # needs sage.graphs + sage: X = T.disjoint_union(K) # needs sage.graphs + sage: # needs sage.graphs sage: X_0 = X.set_base_point(X.n_cells(0)[0]) - sage: X_0.fundamental_group().is_abelian() + sage: X_0.fundamental_group().is_abelian() # needs sage.groups True sage: X_1 = X.set_base_point(X.n_cells(0)[1]) - sage: X_1.fundamental_group().is_abelian() + sage: X_1.fundamental_group().is_abelian() # needs sage.groups False - sage: RP3 = simplicial_sets.RealProjectiveSpace(3) - sage: RP3.fundamental_group() + sage: RP3 = simplicial_sets.RealProjectiveSpace(3) # needs sage.graphs sage.groups + sage: RP3.fundamental_group() # needs sage.graphs sage.groups Finitely presented group < e | e^2 > Compute the fundamental group of some classifying spaces:: - sage: C5 = groups.misc.MultiplicativeAbelian([5]) - sage: BC5 = C5.nerve() - sage: BC5.fundamental_group() + sage: C5 = groups.misc.MultiplicativeAbelian([5]) # needs sage.graphs sage.groups + sage: BC5 = C5.nerve() # needs sage.graphs sage.groups + sage: BC5.fundamental_group() # needs sage.graphs sage.groups Finitely presented group < e0 | e0^5 > + sage: # needs sage.graphs sage.groups sage: Sigma3 = groups.permutation.Symmetric(3) sage: BSigma3 = Sigma3.nerve() sage: pi = BSigma3.fundamental_group(); pi - Finitely presented group < e0, e1 | e0^2, e1^3, (e0*e1^-1)^2 > + Finitely presented group < e1, e2 | e2^2, e1^3, (e2*e1)^2 > sage: pi.order() 6 sage: pi.is_abelian() @@ -325,25 +332,41 @@ def fundamental_group(self, simplify=True): The sphere has a trivial fundamental group:: - sage: S2 = simplicial_sets.Sphere(2) - sage: S2.fundamental_group() + sage: S2 = simplicial_sets.Sphere(2) # needs sage.graphs + sage: S2.fundamental_group() # needs sage.graphs sage.groups Finitely presented group < | > """ # Import this here to prevent importing libgap upon startup. from sage.groups.free_group import FreeGroup - skel = self.n_skeleton(2) + if not self.n_cells(1): + return FreeGroup([]).quotient([]) + FG = self._universal_cover_dict()[0] + if simplify: + return FG.simplified() + else: + return FG + + def _universal_cover_dict(self): + r""" + Return the fundamental group and dictionary sending each edge to + the corresponding group element + TESTS:: + + sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # needs sage.groups + sage: RP2._universal_cover_dict() # needs sage.groups + (Finitely presented group < e | e^2 >, {f: e}) + sage: RP2.nondegenerate_simplices() # needs sage.groups + [1, f, f * f] + """ + from sage.groups.free_group import FreeGroup + skel = self.n_skeleton(2) graph = skel.graph() if not skel.is_connected(): graph = graph.subgraph(skel.base_point()) - - edges = [e[2] for e in graph.edges(sort=True)] + edges = [e[2] for e in graph.edges(sort=False)] spanning_tree = [e[2] for e in graph.min_spanning_tree()] gens = [e for e in edges if e not in spanning_tree] - - if not gens: - return FreeGroup([]).quotient([]) - gens_dict = dict(zip(gens, range(len(gens)))) FG = FreeGroup(len(gens), 'e') rels = [] @@ -361,10 +384,195 @@ def fundamental_group(self, simplify=True): # sigma is not in the correct connected component. z[i] = FG.one() rels.append(z[0]*z[1].inverse()*z[2]) - if simplify: - return FG.quotient(rels).simplified() - else: - return FG.quotient(rels) + G = FG.quotient(rels) + char = {g : G.gen(i) for i,g in enumerate(gens)} + for e in edges: + if e not in gens: + char[e] = G.one() + return (G, char) + + def universal_cover_map(self): + r""" + Return the universal covering map of the simplicial set. + + It requires the fundamental group to be finite. + + EXAMPLES:: + + sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # needs sage.groups + sage: phi = RP2.universal_cover_map(); phi # needs sage.groups + Simplicial set morphism: + From: Simplicial set with 6 non-degenerate simplices + To: RP^2 + Defn: [(1, 1), (1, e), (f, 1), (f, e), (f * f, 1), (f * f, e)] + --> [1, 1, f, f, f * f, f * f] + sage: phi.domain().face_data() # needs sage.groups + {(1, 1): None, + (1, e): None, + (f, 1): ((1, e), (1, 1)), + (f, e): ((1, 1), (1, e)), + (f * f, 1): ((f, e), s_0 (1, 1), (f, 1)), + (f * f, e): ((f, 1), s_0 (1, e), (f, e))} + + """ + edges = self.n_cells(1) + if not edges: + return self.identity() + G, char = self._universal_cover_dict() + return self.covering_map(char) + + def covering_map(self, character): + r""" + Return the covering map associated to a character. + + The character is represented by a dictionary that assigns an + element of a finite group to each nondegenerate 1-dimensional + cell. It should correspond to an epimorphism from the fundamental + group. + + INPUT: + + - ``character`` -- a dictionary + + + EXAMPLES:: + + sage: # needs sage.graphs sage.groups + sage: S1 = simplicial_sets.Sphere(1) + sage: W = S1.wedge(S1) + sage: G = CyclicPermutationGroup(3) + sage: a, b = W.n_cells(1) + sage: C = W.covering_map({a : G.gen(0), b : G.one()}); C + Simplicial set morphism: + From: Simplicial set with 9 non-degenerate simplices + To: Wedge: (S^1 v S^1) + Defn: [(*, ()), (*, (1,2,3)), (*, (1,3,2)), (sigma_1, ()), + (sigma_1, ()), (sigma_1, (1,2,3)), (sigma_1, (1,2,3)), + (sigma_1, (1,3,2)), (sigma_1, (1,3,2))] + --> [*, *, *, sigma_1, sigma_1, sigma_1, sigma_1, sigma_1, sigma_1] + sage: C.domain() + Simplicial set with 9 non-degenerate simplices + sage: C.domain().face_data() + {(*, ()): None, + (*, (1,2,3)): None, + (*, (1,3,2)): None, + (sigma_1, ()): ((*, (1,2,3)), (*, ())), + (sigma_1, ()): ((*, ()), (*, ())), + (sigma_1, (1,2,3)): ((*, (1,3,2)), (*, (1,2,3))), + (sigma_1, (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))), + (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))), + (sigma_1, (1,3,2)): ((*, (1,3,2)), (*, (1,3,2)))} + """ + from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet + from sage.topology.simplicial_set_morphism import SimplicialSetMorphism + char = {a: b for (a, b) in character.items()} + G = list(char.values())[0].parent() + if not G.is_finite(): + raise NotImplementedError("can only compute universal covers of spaces with finite fundamental group") + cells_dict = {} + faces_dict = {} + + for s in self.n_cells(0): + for g in G: + cell = AbstractSimplex(0, name="({}, {})".format(s, g)) + cells_dict[(s, g)] = cell + char[s] = G.one() + + for d in range(1, self.dimension() + 1): + for s in self.n_cells(d): + if s not in char.keys(): + if d == 1 and s.is_degenerate(): + char[s] = G.one() + elif s.is_degenerate(): + if 0 in s.degeneracies(): + char[s] = G.one() + else: + char[s] = char[s.nondegenerate()] + else: + char[s] = char[self.face(s, d)] + if s.is_nondegenerate(): + for g in G: + cell = AbstractSimplex(d, name="({}, {})".format(s, g)) + cells_dict[(s, g)] = cell + fd = [] + faces = self.faces(s) + f0 = faces[0] + for h in G: + if h == g*char[s]: + lifted = h + break + grelems = [cells_dict[(f0.nondegenerate(), lifted)].apply_degeneracies(*f0.degeneracies())] + for f in faces[1:]: + grelems.append(cells_dict[(f.nondegenerate(), g)].apply_degeneracies(*f.degeneracies())) + faces_dict[cell] = grelems + cover = SimplicialSet(faces_dict, base_point=cells_dict[(self.base_point(), G.one())]) + cover_map_data = {c : s[0] for (s,c) in cells_dict.items()} + return SimplicialSetMorphism(data=cover_map_data, domain=cover, codomain=self) + + def cover(self, character): + r""" + Return the cover of the simplicial set associated to a character + of the fundamental group. + + The character is represented by a dictionary, that assigns an + element of a finite group to each nondegenerate 1-dimensional + cell. It should correspond to an epimorphism from the fundamental + group. + + INPUT: + + - ``character`` -- a dictionary + + EXAMPLES:: + + sage: # needs sage.graphs sage.groups + sage: S1 = simplicial_sets.Sphere(1) + sage: W = S1.wedge(S1) + sage: G = CyclicPermutationGroup(3) + sage: (a, b) = W.n_cells(1) + sage: C = W.cover({a : G.gen(0), b : G.gen(0)^2}) + sage: C.face_data() + {(*, ()): None, + (*, (1,2,3)): None, + (*, (1,3,2)): None, + (sigma_1, ()): ((*, (1,2,3)), (*, ())), + (sigma_1, ()): ((*, (1,3,2)), (*, ())), + (sigma_1, (1,2,3)): ((*, (1,3,2)), (*, (1,2,3))), + (sigma_1, (1,2,3)): ((*, ()), (*, (1,2,3))), + (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))), + (sigma_1, (1,3,2)): ((*, (1,2,3)), (*, (1,3,2)))} + sage: C.homology(1) # needs sage.modules + Z x Z x Z x Z + sage: C.fundamental_group() + Finitely presented group < e0, e1, e2, e3 | > + """ + return self.covering_map(character).domain() + + def universal_cover(self): + r""" + Return the universal cover of the simplicial set. + The fundamental group must be finite in order to ensure that the + universal cover is a simplicial set of finite type. + + EXAMPLES:: + + sage: # needs sage.groups + sage: RP3 = simplicial_sets.RealProjectiveSpace(3) + sage: C = RP3.universal_cover(); C + Simplicial set with 8 non-degenerate simplices + sage: C.face_data() + {(1, 1): None, + (1, e): None, + (f, 1): ((1, e), (1, 1)), + (f, e): ((1, 1), (1, e)), + (f * f, 1): ((f, e), s_0 (1, 1), (f, 1)), + (f * f, e): ((f, 1), s_0 (1, e), (f, e)), + (f * f * f, 1): ((f * f, e), s_0 (f, 1), s_1 (f, 1), (f * f, 1)), + (f * f * f, e): ((f * f, 1), s_0 (f, e), s_1 (f, e), (f * f, e))} + sage: C.fundamental_group() + Finitely presented group < | > + """ + return self.universal_cover_map().domain() def is_simply_connected(self): """ @@ -380,6 +588,7 @@ def is_simply_connected(self): EXAMPLES:: + sage: # needs sage.graphs sage.groups sage: T = simplicial_sets.Torus() sage: T.is_simply_connected() False @@ -388,18 +597,19 @@ def is_simply_connected(self): sage: simplicial_sets.KleinBottle().is_simply_connected() False + sage: # needs sage.graphs sage: S2 = simplicial_sets.Sphere(2) sage: S3 = simplicial_sets.Sphere(3) - sage: (S2.wedge(S3)).is_simply_connected() + sage: (S2.wedge(S3)).is_simply_connected() # needs sage.groups True sage: X = S2.disjoint_union(S3) sage: X = X.set_base_point(X.n_cells(0)[0]) sage: X.is_simply_connected() False - sage: C3 = groups.misc.MultiplicativeAbelian([3]) - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) - sage: BC3.is_simply_connected() + sage: C3 = groups.misc.MultiplicativeAbelian([3]) # needs sage.graphs sage.groups + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # needs sage.graphs sage.groups + sage: BC3.is_simply_connected() # needs sage.graphs sage.groups False """ if not self.is_connected(): @@ -443,6 +653,7 @@ def connectivity(self, max_dim=None): EXAMPLES:: + sage: # needs sage.graphs sage.groups sage: simplicial_sets.Sphere(3).connectivity() 2 sage: simplicial_sets.Sphere(0).connectivity() @@ -455,9 +666,9 @@ def connectivity(self, max_dim=None): sage: X.connectivity() 2 - sage: C2 = groups.misc.MultiplicativeAbelian([2]) - sage: BC2 = simplicial_sets.ClassifyingSpace(C2) - sage: BC2.connectivity() + sage: C2 = groups.misc.MultiplicativeAbelian([2]) # needs sage.graphs sage.groups + sage: BC2 = simplicial_sets.ClassifyingSpace(C2) # needs sage.graphs sage.groups + sage: BC2.connectivity() # needs sage.graphs sage.groups 0 """ if not self.is_connected(): @@ -491,6 +702,7 @@ def unset_base_point(self): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v_0') sage: w = AbstractSimplex(0, name='w_0') @@ -520,14 +732,15 @@ def fat_wedge(self, n): EXAMPLES:: + sage: # needs sage.graphs sage: S1 = simplicial_sets.Sphere(1) sage: S1.fat_wedge(0) Point sage: S1.fat_wedge(1) S^1 - sage: S1.fat_wedge(2).fundamental_group() + sage: S1.fat_wedge(2).fundamental_group() # needs sage.groups Finitely presented group < e0, e1 | > - sage: S1.fat_wedge(4).homology() + sage: S1.fat_wedge(4).homology() # needs sage.modules {0: 0, 1: Z x Z x Z x Z, 2: Z^6, 3: Z x Z x Z x Z} """ from sage.topology.simplicial_set_examples import Point @@ -547,18 +760,19 @@ def smash_product(self, *others): EXAMPLES:: + sage: # needs sage.graphs sage.groups sage: S1 = simplicial_sets.Sphere(1) sage: RP2 = simplicial_sets.RealProjectiveSpace(2) sage: X = S1.smash_product(RP2) - sage: X.homology(base_ring=GF(2)) + sage: X.homology(base_ring=GF(2)) # needs sage.modules {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 0 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2, 3: Vector space of dimension 1 over Finite Field of size 2} - sage: T = S1.product(S1) - sage: X = T.smash_product(S1) - sage: X.homology(reduced=False) + sage: T = S1.product(S1) # needs sage.graphs sage.groups + sage: X = T.smash_product(S1) # needs sage.graphs sage.groups + sage: X.homology(reduced=False) # needs sage.graphs sage.groups sage.modules {0: Z, 1: 0, 2: Z x Z, 3: Z} """ from sage.topology.simplicial_set_constructions import SmashProductOfSimplicialSets_finite diff --git a/src/sage/categories/super_algebras.py b/src/sage/categories/super_algebras.py index 77fe3a8982b..d63b2cc6da5 100644 --- a/src/sage/categories/super_algebras.py +++ b/src/sage/categories/super_algebras.py @@ -76,6 +76,7 @@ def tensor(*parents, **kwargs): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = ExteriorAlgebra(ZZ); A.rename("A") sage: T = A.tensor(A,A); T A # A # A @@ -88,10 +89,11 @@ def tensor(*parents, **kwargs): This also works when the other elements do not have a signed tensor product (:trac:`31266`):: + sage: # needs sage.combinat sage.modules sage: a = SteenrodAlgebra(3).an_element() sage: M = CombinatorialFreeModule(GF(3), ['s', 't', 'u']) sage: s = M.basis()['s'] - sage: tensor([a, s]) + sage: tensor([a, s]) # needs sage.rings.finite_rings 2*Q_1 Q_3 P(2,1) # B['s'] """ constructor = kwargs.pop('constructor', tensor_signed) diff --git a/src/sage/categories/super_algebras_with_basis.py b/src/sage/categories/super_algebras_with_basis.py index 2cee5d8ad87..014fe6e563e 100644 --- a/src/sage/categories/super_algebras_with_basis.py +++ b/src/sage/categories/super_algebras_with_basis.py @@ -52,8 +52,8 @@ def graded_algebra(self): EXAMPLES:: - sage: W.<x,y> = algebras.DifferentialWeyl(QQ) - sage: W.graded_algebra() + sage: W.<x,y> = algebras.DifferentialWeyl(QQ) # needs sage.modules + sage: W.graded_algebra() # needs sage.combinat sage.modules Graded Algebra of Differential Weyl algebra of polynomials in x, y over Rational Field """ @@ -76,6 +76,7 @@ def supercommutator(self, x): EXAMPLES:: + sage: # needs sage.modules sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: Cl.<x,y,z> = CliffordAlgebra(Q) sage: a = x*y - z @@ -91,6 +92,7 @@ def supercommutator(self, x): sage: a.supercommutator(Cl.zero()) 0 + sage: # needs sage.modules sage: Q = QuadraticForm(ZZ, 2, [-1,1,-3]) sage: Cl.<x,y> = CliffordAlgebra(Q) sage: [a.supercommutator(b) for a in Cl.basis() for b in Cl.basis()] @@ -104,8 +106,8 @@ def supercommutator(self, x): supercommutators work as well. We verify the exterior algebra is supercommutative:: - sage: E.<x,y,z,w> = ExteriorAlgebra(QQ) - sage: all(b1.supercommutator(b2) == 0 + sage: E.<x,y,z,w> = ExteriorAlgebra(QQ) # needs sage.modules + sage: all(b1.supercommutator(b2) == 0 # needs sage.modules ....: for b1 in E.basis() for b2 in E.basis()) True """ diff --git a/src/sage/categories/super_hopf_algebras_with_basis.py b/src/sage/categories/super_hopf_algebras_with_basis.py index 4fd09867b45..afaafc2b8f7 100644 --- a/src/sage/categories/super_hopf_algebras_with_basis.py +++ b/src/sage/categories/super_hopf_algebras_with_basis.py @@ -42,15 +42,15 @@ def antipode(self): EXAMPLES:: - sage: A = SteenrodAlgebra(7) - sage: a = A.an_element() - sage: a, A.antipode(a) + sage: A = SteenrodAlgebra(7) # needs sage.combinat sage.modules + sage: a = A.an_element() # needs sage.combinat sage.modules + sage: a, A.antipode(a) # needs sage.combinat sage.modules (6 Q_1 Q_3 P(2,1), Q_1 Q_3 P(2,1)) TESTS:: - sage: E.<x,y> = ExteriorAlgebra(QQ) - sage: [b.antipode() for b in E.basis()] + sage: E.<x,y> = ExteriorAlgebra(QQ) # needs sage.modules + sage: [b.antipode() for b in E.basis()] # needs sage.modules [1, -x, -y, x*y] """ if self.antipode_on_basis is not NotImplemented: @@ -88,8 +88,8 @@ def _test_antipode(self, **options): TESTS:: - sage: A = SteenrodAlgebra(7) - sage: A._test_antipode() # long time + sage: A = SteenrodAlgebra(7) # needs sage.combinat sage.modules + sage: A._test_antipode() # long time # needs sage.combinat sage.modules """ tester = self._tester(**options) diff --git a/src/sage/categories/super_lie_conformal_algebras.py b/src/sage/categories/super_lie_conformal_algebras.py index 849a0fbdb13..9e38c4aa3e1 100644 --- a/src/sage/categories/super_lie_conformal_algebras.py +++ b/src/sage/categories/super_lie_conformal_algebras.py @@ -27,16 +27,16 @@ class SuperLieConformalAlgebras(SuperModulesCategory): EXAMPLES:: - sage: LieConformalAlgebras(AA).Super() + sage: LieConformalAlgebras(AA).Super() # needs sage.rings.number_field Category of super Lie conformal algebras over Algebraic Real Field Notice that we can force to have a *purely even* super Lie conformal algebra:: - sage: bosondict = {('a','a'):{1:{('K',0):1}}} - sage: R = LieConformalAlgebra(QQ,bosondict,names=('a',), + sage: bosondict = {('a','a'): {1:{('K',0):1}}} + sage: R = LieConformalAlgebra(QQ, bosondict, names=('a',), # needs sage.combinat sage.modules ....: central_elements=('K',), super=True) - sage: [g.is_even_odd() for g in R.gens()] + sage: [g.is_even_odd() for g in R.gens()] # needs sage.combinat sage.modules [0, 0] """ def extra_super_categories(self): @@ -57,7 +57,7 @@ def example(self): EXAMPLES:: - sage: LieConformalAlgebras(QQ).Super().example() + sage: LieConformalAlgebras(QQ).Super().example() # needs sage.combinat sage.modules The Neveu-Schwarz super Lie conformal algebra over Rational Field """ from sage.algebras.lie_conformal_algebras.neveu_schwarz_lie_conformal_algebra\ @@ -79,32 +79,33 @@ def _test_jacobi(self, **options): By default, this method tests only the elements returned by ``self.some_elements()``:: - sage: V = lie_conformal_algebras.Affine(QQ, 'B2') - sage: V._test_jacobi() # long time (6 seconds) + sage: V = lie_conformal_algebras.Affine(QQ, 'B2') # needs sage.combinat sage.modules + sage: V._test_jacobi() # long time (6 seconds) # needs sage.combinat sage.modules It works for super Lie conformal algebras too:: - sage: V = lie_conformal_algebras.NeveuSchwarz(QQ) - sage: V._test_jacobi() + sage: V = lie_conformal_algebras.NeveuSchwarz(QQ) # needs sage.combinat sage.modules + sage: V._test_jacobi() # needs sage.combinat sage.modules We can use specific elements by passing the ``elements`` keyword argument:: - sage: V = lie_conformal_algebras.Affine(QQ, 'A1', names=('e', 'h', 'f')) - sage: V.inject_variables() + sage: V = lie_conformal_algebras.Affine(QQ, 'A1', # needs sage.combinat sage.modules + ....: names=('e', 'h', 'f')) + sage: V.inject_variables() # needs sage.combinat sage.modules Defining e, h, f, K - sage: V._test_jacobi(elements=(e, 2*f+h, 3*h)) + sage: V._test_jacobi(elements=(e, 2*f + h, 3*h)) # needs sage.combinat sage.modules TESTS:: - sage: wrongdict = {('a', 'a'): {0: {('b', 0): 1}}, ('b', 'a'): {0: {('a', 0): 1}}} - sage: V = LieConformalAlgebra(QQ, wrongdict, names=('a', 'b'), parity=(1, 0)) - sage: V._test_jacobi() + sage: wrongdict = {('a', 'a'): {0: {('b', 0): 1}}, + ....: ('b', 'a'): {0: {('a', 0): 1}}} + sage: V = LieConformalAlgebra(QQ, wrongdict, # needs sage.combinat sage.modules + ....: names=('a', 'b'), parity=(1, 0)) + sage: V._test_jacobi() # needs sage.combinat sage.modules Traceback (most recent call last): ... - AssertionError: {(0, 0): -3*a} != {} - - {(0, 0): -3*a} - + {} + AssertionError: {(0, 0): -3*a} != {} - {(0, 0): -3*a} + {} """ tester = self._tester(**options) S = tester.some_elements() @@ -162,10 +163,10 @@ def is_even_odd(self): EXAMPLES:: - sage: R = lie_conformal_algebras.NeveuSchwarz(QQ); - sage: R.inject_variables() + sage: R = lie_conformal_algebras.NeveuSchwarz(QQ) # needs sage.combinat sage.modules + sage: R.inject_variables() # needs sage.combinat sage.modules Defining L, G, C - sage: G.is_even_odd() + sage: G.is_even_odd() # needs sage.combinat sage.modules 1 """ @@ -175,7 +176,7 @@ class Graded(GradedModulesCategory): EXAMPLES:: - sage: LieConformalAlgebras(AA).Super().Graded() + sage: LieConformalAlgebras(AA).Super().Graded() # needs sage.rings.number_field Category of H-graded super Lie conformal algebras over Algebraic Real Field """ def _repr_object_names(self): @@ -184,7 +185,7 @@ def _repr_object_names(self): EXAMPLES:: - sage: LieConformalAlgebras(QQbar).Graded() + sage: LieConformalAlgebras(QQbar).Graded() # needs sage.rings.number_field Category of H-graded Lie conformal algebras over Algebraic Field """ return "H-graded {}".format(self.base_category()._repr_object_names()) diff --git a/src/sage/categories/super_modules.py b/src/sage/categories/super_modules.py index 091b808408e..0fbd94fbf31 100644 --- a/src/sage/categories/super_modules.py +++ b/src/sage/categories/super_modules.py @@ -45,7 +45,7 @@ def default_super_categories(cls, category, *args): EXAMPLES:: - sage: HopfAlgebras(ZZ).WithBasis().FiniteDimensional().Super() # indirect doctest + sage: HopfAlgebras(ZZ).WithBasis().FiniteDimensional().Super() # indirect doctest Category of finite dimensional super hopf algebras with basis over Integer Ring """ axioms = axiom_whitelist.intersection(category.axioms()) @@ -182,6 +182,7 @@ def is_even_odd(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: cat = Algebras(QQ).WithBasis().Super() sage: C = CombinatorialFreeModule(QQ, Partitions(), category=cat) sage: C.degree_on_basis = sum @@ -198,6 +199,7 @@ def is_even(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: cat = Algebras(QQ).WithBasis().Super() sage: C = CombinatorialFreeModule(QQ, Partitions(), category=cat) sage: C.degree_on_basis = sum @@ -214,6 +216,7 @@ def is_odd(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: cat = Algebras(QQ).WithBasis().Super() sage: C = CombinatorialFreeModule(QQ, Partitions(), category=cat) sage: C.degree_on_basis = sum diff --git a/src/sage/categories/super_modules_with_basis.py b/src/sage/categories/super_modules_with_basis.py index 7317d42f95c..ef4bbc048e8 100644 --- a/src/sage/categories/super_modules_with_basis.py +++ b/src/sage/categories/super_modules_with_basis.py @@ -53,6 +53,7 @@ def _even_odd_on_basis(self, m): EXAMPLES:: + sage: # needs sage.modules sage: Q = QuadraticForm(QQ, 2, [1,2,3]) sage: C.<x,y> = CliffordAlgebra(Q) sage: C._even_odd_on_basis((0,)) @@ -70,6 +71,7 @@ def is_super_homogeneous(self): EXAMPLES:: + sage: # needs sage.modules sage: Q = QuadraticForm(QQ, 2, [1,2,3]) sage: C.<x,y> = CliffordAlgebra(Q) sage: a = x + y @@ -86,6 +88,7 @@ def is_super_homogeneous(self): `\ZZ / 2\ZZ` grading. However the definition of homogeneous elements differs because of the different gradings:: + sage: # needs sage.combinat sage.modules sage: E.<x,y> = ExteriorAlgebra(QQ) sage: a = x*y + 4 sage: a.is_super_homogeneous() @@ -110,6 +113,7 @@ def is_even_odd(self): EXAMPLES:: + sage: # needs sage.modules sage: Q = QuadraticForm(QQ, 2, [1,2,3]) sage: C.<x,y> = CliffordAlgebra(Q) sage: a = x + y @@ -124,8 +128,8 @@ def is_even_odd(self): ... ValueError: element is not homogeneous - sage: E.<x,y> = ExteriorAlgebra(QQ) - sage: (x*y).is_even_odd() + sage: E.<x,y> = ExteriorAlgebra(QQ) # needs sage.modules + sage: (x*y).is_even_odd() # needs sage.modules 0 """ if not self.support(): @@ -140,6 +144,7 @@ def even_component(self): EXAMPLES:: + sage: # needs sage.modules sage: Q = QuadraticForm(QQ, 2, [1,2,3]) sage: C.<x,y> = CliffordAlgebra(Q) sage: a = x*y + x - 3*y + 4 @@ -150,8 +155,8 @@ def even_component(self): Check that this really return ``A.zero()`` and not a plain ``0``:: - sage: a = x + y - sage: a.even_component().parent() is C + sage: a = x + y # needs sage.modules + sage: a.even_component().parent() is C # needs sage.modules True """ even_odd = self.parent()._even_odd_on_basis @@ -165,6 +170,7 @@ def odd_component(self): EXAMPLES:: + sage: # needs sage.modules sage: Q = QuadraticForm(QQ, 2, [1,2,3]) sage: C.<x,y> = CliffordAlgebra(Q) sage: a = x*y + x - 3*y + 4 @@ -175,8 +181,8 @@ def odd_component(self): Check that this really return ``A.zero()`` and not a plain ``0``:: - sage: a = x*y - sage: a.odd_component().parent() is C + sage: a = x*y # needs sage.modules + sage: a.odd_component().parent() is C # needs sage.modules True """ even_odd = self.parent()._even_odd_on_basis diff --git a/src/sage/categories/supercommutative_algebras.py b/src/sage/categories/supercommutative_algebras.py index 4cd44e849c9..1928c7057dc 100644 --- a/src/sage/categories/supercommutative_algebras.py +++ b/src/sage/categories/supercommutative_algebras.py @@ -73,15 +73,15 @@ def _test_supercommutativity(self, **options): By default, this method tests only the elements returned by ``self.some_elements()``:: - sage: E.<x,y,z> = ExteriorAlgebra(QQ) - sage: E._test_supercommutativity() + sage: E.<x,y,z> = ExteriorAlgebra(QQ) # needs sage.modules + sage: E._test_supercommutativity() # needs sage.modules However, the elements tested can be customized with the ``elements`` keyword argument, but the elements must be homogeneous:: - sage: E._test_supercommutativity(elements=[x+y, x*y-3*y*z, x*y*z]) - sage: E._test_supercommutativity(elements=[x+x*y]) + sage: E._test_supercommutativity(elements=[x+y, x*y-3*y*z, x*y*z]) # needs sage.modules + sage: E._test_supercommutativity(elements=[x+x*y]) # needs sage.modules Traceback (most recent call last): ... ValueError: element is not homogeneous diff --git a/src/sage/categories/supercrystals.py b/src/sage/categories/supercrystals.py index 1e15c935599..239aa8c0a86 100644 --- a/src/sage/categories/supercrystals.py +++ b/src/sage/categories/supercrystals.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs sage.combinat r""" Supercrystals """ @@ -42,11 +43,13 @@ def tensor(self, *crystals, **options): sage: B = crystals.Letters(['A',[1,2]]) sage: C = crystals.Tableaux(['A',[1,2]], shape = [2,1]) sage: T = C.tensor(B); T - Full tensor product of the crystals [Crystal of BKK tableaux of shape [2, 1] of gl(2|3), - The crystal of letters for type ['A', [1, 2]]] + Full tensor product of the crystals + [Crystal of BKK tableaux of shape [2, 1] of gl(2|3), + The crystal of letters for type ['A', [1, 2]]] sage: S = B.tensor(C); S - Full tensor product of the crystals [The crystal of letters for type ['A', [1, 2]], - Crystal of BKK tableaux of shape [2, 1] of gl(2|3)] + Full tensor product of the crystals + [The crystal of letters for type ['A', [1, 2]], + Crystal of BKK tableaux of shape [2, 1] of gl(2|3)] sage: G = T.digraph() sage: H = S.digraph() sage: G.is_isomorphic(H, edge_labels= True) diff --git a/src/sage/categories/topological_spaces.py b/src/sage/categories/topological_spaces.py index 409e6cdcd8f..7ab806e6a2b 100644 --- a/src/sage/categories/topological_spaces.py +++ b/src/sage/categories/topological_spaces.py @@ -141,7 +141,6 @@ def extra_super_categories(self): """ return [TopologicalSpaces().Connected()] - class Compact(CategoryWithAxiom): """ The category of compact topological spaces. diff --git a/src/sage/categories/triangular_kac_moody_algebras.py b/src/sage/categories/triangular_kac_moody_algebras.py index 95c7881043f..e9c3f1ad167 100644 --- a/src/sage/categories/triangular_kac_moody_algebras.py +++ b/src/sage/categories/triangular_kac_moody_algebras.py @@ -60,10 +60,10 @@ def _part_on_basis(self, m): EXAMPLES:: - sage: L = lie_algebras.so(QQ, 5) - sage: L.f() + sage: L = lie_algebras.so(QQ, 5) # needs sage.combinat sage.modules + sage: L.f() # needs sage.combinat sage.modules Finite family {1: E[-alpha[1]], 2: E[-alpha[2]]} - sage: L.f(1) + sage: L.f(1) # needs sage.combinat sage.modules E[-alpha[1]] """ deg = self.degree_on_basis(m) @@ -100,8 +100,8 @@ def _part_generators(self, positive=False): EXAMPLES:: - sage: L = LieAlgebra(QQ, cartan_type=['E',6]) - sage: list(L._part_generators(False)) + sage: L = LieAlgebra(QQ, cartan_type=['E', 6]) # needs sage.combinat sage.modules + sage: list(L._part_generators(False)) # needs sage.combinat sage.modules [E[-alpha[1]], E[-alpha[2]], E[-alpha[3]], E[-alpha[4]], E[-alpha[5]], E[-alpha[6]]] """ @@ -128,10 +128,10 @@ def e(self, i=None): EXAMPLES:: - sage: L = lie_algebras.so(QQ, 5) - sage: L.e() + sage: L = lie_algebras.so(QQ, 5) # needs sage.combinat sage.modules + sage: L.e() # needs sage.combinat sage.modules Finite family {1: E[alpha[1]], 2: E[alpha[2]]} - sage: L.e(1) + sage: L.e(1) # needs sage.combinat sage.modules E[alpha[1]] """ E = self._part_generators(True) @@ -150,10 +150,10 @@ def f(self, i=None): EXAMPLES:: - sage: L = lie_algebras.so(QQ, 5) - sage: L.f() + sage: L = lie_algebras.so(QQ, 5) # needs sage.combinat sage.modules + sage: L.f() # needs sage.combinat sage.modules Finite family {1: E[-alpha[1]], 2: E[-alpha[2]]} - sage: L.f(1) + sage: L.f(1) # needs sage.combinat sage.modules E[-alpha[1]] """ F = self._part_generators(False) @@ -168,8 +168,8 @@ def _negative_half_index_set(self): EXAMPLES:: - sage: L = lie_algebras.so(QQ, 5) - sage: L._negative_half_index_set() + sage: L = lie_algebras.so(QQ, 5) # needs sage.combinat sage.modules + sage: L._negative_half_index_set() # needs sage.combinat sage.modules [-alpha[2], -alpha[1], -alpha[1] - alpha[2], -alpha[1] - 2*alpha[2]] """ @@ -186,6 +186,7 @@ def _weight_action(self, m, wt): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = lie_algebras.sp(QQ, 6) sage: La = L.cartan_type().root_system().weight_space().fundamental_weights() sage: mu = La[1] - 3/5*La[2] @@ -210,10 +211,11 @@ def verma_module(self, la, basis_key=None, **kwds): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = lie_algebras.sl(QQ, 3) sage: P = L.cartan_type().root_system().weight_lattice() sage: La = P.fundamental_weights() - sage: M = L.verma_module(La[1]+La[2]) + sage: M = L.verma_module(La[1] + La[2]) sage: M Verma module with highest weight Lambda[1] + Lambda[2] of Lie algebra of ['A', 2] in the Chevalley basis @@ -234,6 +236,7 @@ def part(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = LieAlgebra(QQ, cartan_type="F4") sage: L.inject_variables() Defining e1, e2, e3, e4, f1, f2, f3, f4, h1, h2, h3, h4 diff --git a/src/sage/categories/unique_factorization_domains.py b/src/sage/categories/unique_factorization_domains.py index 280320474d8..851bfe80175 100644 --- a/src/sage/categories/unique_factorization_domains.py +++ b/src/sage/categories/unique_factorization_domains.py @@ -65,7 +65,7 @@ def __contains__(self, x): """ EXAMPLES:: - sage: GF(4, "a") in UniqueFactorizationDomains() + sage: GF(4, "a") in UniqueFactorizationDomains() # needs sage.rings.finite_rings True sage: QQ in UniqueFactorizationDomains() True @@ -123,7 +123,8 @@ def is_unique_factorization_domain(self, proof=True): EXAMPLES:: - sage: Parent(QQ,category=UniqueFactorizationDomains()).is_unique_factorization_domain() + sage: UFD = UniqueFactorizationDomains() + sage: Parent(QQ, category=UFD).is_unique_factorization_domain() True """ @@ -154,12 +155,14 @@ def _gcd_univariate_polynomial(self, f, g): sage: q = (-x^2 - 4*x - 5)*T^2 + (6*x^2 + x + 1)*T + 2*x^2 - x sage: quo,rem=p.pseudo_quo_rem(q); quo,rem ((3*x^4 + 13*x^3 + 19*x^2 + 5*x)*T + 18*x^4 + 12*x^3 + 16*x^2 + 16*x, - (-113*x^6 - 106*x^5 - 133*x^4 - 101*x^3 - 42*x^2 - 41*x)*T - 34*x^6 + 13*x^5 + 54*x^4 + 126*x^3 + 134*x^2 - 5*x - 50) + (-113*x^6 - 106*x^5 - 133*x^4 - 101*x^3 - 42*x^2 - 41*x)*T + - 34*x^6 + 13*x^5 + 54*x^4 + 126*x^3 + 134*x^2 - 5*x - 50) sage: (-x^2 - 4*x - 5)^(3-2+1) * p == quo*q + rem True Check that :trac:`23620` has been resolved:: + sage: # needs sage.rings.padics sage: R.<x> = ZpFM(2)[] sage: f = 2*x + 2 sage: g = 4*x + 2 @@ -293,4 +296,4 @@ def squarefree_part(self): """ decomp = self.squarefree_decomposition() - return prod(fac for fac, mult in decomp if mult%2 == 1) + return prod(fac for fac, mult in decomp if mult % 2 == 1) diff --git a/src/sage/categories/unital_algebras.py b/src/sage/categories/unital_algebras.py index d245b4de8c1..8e58f12e167 100644 --- a/src/sage/categories/unital_algebras.py +++ b/src/sage/categories/unital_algebras.py @@ -18,6 +18,7 @@ from sage.categories.homset import Hom from sage.categories.rings import Rings from sage.categories.magmatic_algebras import MagmaticAlgebras +from sage.categories.cartesian_product import CartesianProductsCategory class UnitalAlgebras(CategoryWithAxiom_over_base_ring): @@ -25,7 +26,7 @@ class UnitalAlgebras(CategoryWithAxiom_over_base_ring): The category of non-associative algebras over a given base ring. A non-associative algebra over a ring `R` is a module over `R` - which s also a unital magma. + which is also a unital magma. .. WARNING:: @@ -61,9 +62,10 @@ def from_base_ring(self, r): EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).example(); A - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field - sage: A.from_base_ring(1) + sage: A = AlgebrasWithBasis(QQ).example(); A # needs sage.combinat sage.modules + An example of an algebra with basis: + the free algebra on the generators ('a', 'b', 'c') over Rational Field + sage: A.from_base_ring(1) # needs sage.combinat sage.modules B[word: ] """ return self.one()._lmul_(r) @@ -75,16 +77,18 @@ def __init_extra__(self): EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).example(); A - An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field + sage: A = AlgebrasWithBasis(QQ).example(); A # needs sage.combinat sage.modules + An example of an algebra with basis: + the free algebra on the generators ('a', 'b', 'c') over Rational Field sage: coercion_model = sage.structure.element.get_coercion_model() - sage: coercion_model.discover_coercion(QQ, A) + sage: coercion_model.discover_coercion(QQ, A) # needs sage.combinat sage.modules ((map internal to coercion system -- copy before use) Generic morphism: From: Rational Field - To: An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field, + To: An example of an algebra with basis: + the free algebra on the generators ('a', 'b', 'c') over Rational Field, None) - sage: A(1) # indirect doctest + sage: A(1) # indirect doctest # needs sage.combinat sage.modules B[word: ] TESTS: @@ -92,13 +96,13 @@ def __init_extra__(self): Ensure that :trac:`28328` is fixed and that non-associative algebras are supported:: + sage: # needs sage.modules sage: class Foo(CombinatorialFreeModule): ....: def one(self): ....: return self.monomial(0) - sage: from sage.categories.magmatic_algebras \ - ....: import MagmaticAlgebras + sage: from sage.categories.magmatic_algebras import MagmaticAlgebras sage: C = MagmaticAlgebras(QQ).WithBasis().Unital() - sage: F = Foo(QQ,(1,),category=C) + sage: F = Foo(QQ, (1,), category=C) sage: F(0) 0 sage: F(3) @@ -183,8 +187,8 @@ def _coerce_map_from_base_ring(self): Check that :trac:`29312` is fixed:: - sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') - sage: F._coerce_map_from_base_ring() + sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') # needs sage.combinat sage.modules + sage: F._coerce_map_from_base_ring() # needs sage.combinat sage.modules Generic morphism: From: Rational Field To: Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field @@ -274,6 +278,7 @@ def one_basis(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = AlgebrasWithBasis(QQ).example() sage: A.one_basis() word: @@ -295,6 +300,7 @@ def one_from_one_basis(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = AlgebrasWithBasis(QQ).example() sage: A.one_basis() word: @@ -307,6 +313,7 @@ def one_from_one_basis(self): Try to check that :trac:`5843` Heisenbug is fixed:: + sage: # needs sage.combinat sage.modules sage: A = AlgebrasWithBasis(QQ).example() sage: B = AlgebrasWithBasis(QQ).example(('a', 'c')) sage: A == B @@ -319,9 +326,9 @@ def one_from_one_basis(self): Even if called in the wrong order, they should returns their respective one:: - sage: Bone().parent() is B + sage: Bone().parent() is B # needs sage.combinat sage.modules True - sage: Aone().parent() is A + sage: Aone().parent() is A # needs sage.combinat sage.modules True """ return self.monomial(self.one_basis()) #. @@ -333,10 +340,10 @@ def one(self): EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).example() - sage: A.one_basis() + sage: A = AlgebrasWithBasis(QQ).example() # needs sage.combinat sage.modules + sage: A.one_basis() # needs sage.combinat sage.modules word: - sage: A.one() + sage: A.one() # needs sage.combinat sage.modules B[word: ] """ if self.one_basis is NotImplemented: @@ -348,8 +355,8 @@ def from_base_ring(self): """ TESTS:: - sage: A = AlgebrasWithBasis(QQ).example() - sage: A.from_base_ring(3) + sage: A = AlgebrasWithBasis(QQ).example() # needs sage.combinat sage.modules + sage: A.from_base_ring(3) # needs sage.combinat sage.modules 3*B[word: ] """ if self.one_basis is NotImplemented: @@ -366,6 +373,7 @@ def from_base_ring_from_one_basis(self, r): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A = AlgebrasWithBasis(QQ).example() sage: A.from_base_ring_from_one_basis(3) 3*B[word: ] @@ -375,3 +383,55 @@ def from_base_ring_from_one_basis(self, r): 3*B[word: ] """ return self.term(self.one_basis(), r) + + class CartesianProducts(CartesianProductsCategory): + r""" + The category of unital algebras constructed as Cartesian products + of unital algebras. + + This construction gives the direct product of algebras. See + discussion on: + + - http://groups.google.fr/group/sage-devel/browse_thread/thread/35a72b1d0a2fc77a/348f42ae77a66d16#348f42ae77a66d16 + - :wikipedia:`Direct_product` + """ + def extra_super_categories(self): + """ + A Cartesian product of algebras is endowed with a natural + unital algebra structure. + + EXAMPLES:: + + sage: from sage.categories.unital_algebras import UnitalAlgebras + sage: C = UnitalAlgebras(QQ).CartesianProducts() + sage: C.extra_super_categories() + [Category of unital algebras over Rational Field] + sage: sorted(C.super_categories(), key=str) + [Category of Cartesian products of distributive magmas and additive magmas, + Category of Cartesian products of unital magmas, + Category of Cartesian products of vector spaces over Rational Field, + Category of unital algebras over Rational Field] + """ + return [self.base_category()] + + class ParentMethods: + @cached_method + def one(self): + r""" + Return the multiplicative unit element. + + EXAMPLES:: + + sage: S2 = simplicial_complexes.Sphere(2) + sage: H = S2.cohomology_ring(QQ) + sage: C = cartesian_product([H, H]) + sage: one = C.one() + sage: one + B[(0, (0, 0))] + B[(1, (0, 0))] + sage: one == one * one + True + sage: all(b == b * one for b in C.basis()) + True + """ + data = enumerate(self.cartesian_factors()) + return self._cartesian_product_of_elements([C.one() for i, C in data]) diff --git a/src/sage/categories/vector_bundles.py b/src/sage/categories/vector_bundles.py index d5388e381c1..3f3bed1f2d0 100644 --- a/src/sage/categories/vector_bundles.py +++ b/src/sage/categories/vector_bundles.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.symbolic +# sage.doctest: needs sage.symbolic r""" Vector Bundles """ @@ -97,7 +97,7 @@ def _repr_object_names(self): """ base_space = self._base_space return Category_over_base_ring._repr_object_names(self) + \ - " with base space %s"%base_space + " with base space %s" % base_space class SubcategoryMethods: @cached_method diff --git a/src/sage/categories/vector_spaces.py b/src/sage/categories/vector_spaces.py index 66534879b5a..9497c143862 100644 --- a/src/sage/categories/vector_spaces.py +++ b/src/sage/categories/vector_spaces.py @@ -82,8 +82,8 @@ def __init__(self, K): TESTS:: - sage: C = QQ^10 # vector space - sage: TestSuite(C).run() + sage: C = QQ^10 # vector space # needs sage.modules + sage: TestSuite(C).run() # needs sage.modules sage: TestSuite(VectorSpaces(QQ)).run() """ Category_module.__init__(self, K) @@ -94,15 +94,15 @@ def _call_(self, x): EXAMPLES:: - sage: VectorSpaces(QQ)(ZZ^3) + sage: VectorSpaces(QQ)(ZZ^3) # needs sage.modules Vector space of dimension 3 over Rational Field TESTS: Check whether :trac:`30174` is fixed:: - sage: Q3 = FiniteRankFreeModule(QQ, 3) - sage: Modules(QQ)(Q3) is Q3 + sage: Q3 = FiniteRankFreeModule(QQ, 3) # needs sage.modules + sage: Modules(QQ)(Q3) is Q3 # needs sage.modules True """ @@ -111,7 +111,7 @@ def _call_(self, x): if V.base_field() != self.base_field(): V = V.change_ring(self.base_field()) except (TypeError, AttributeError) as msg: - raise TypeError("%s\nunable to coerce x (=%s) into %s"%(msg,x,self)) + raise TypeError("%s\nunable to coerce x (=%s) into %s" % (msg,x,self)) return V def base_field(self): @@ -162,15 +162,15 @@ def dimension(self): EXAMPLES:: - sage: M = FreeModule(FiniteField(19), 100) - sage: W = M.submodule([M.gen(50)]) - sage: W.dimension() + sage: M = FreeModule(FiniteField(19), 100) # needs sage.modules + sage: W = M.submodule([M.gen(50)]) # needs sage.modules + sage: W.dimension() # needs sage.modules 1 - sage: M = FiniteRankFreeModule(QQ, 3) - sage: M.dimension() + sage: M = FiniteRankFreeModule(QQ, 3) # needs sage.modules + sage: M.dimension() # needs sage.modules 3 - sage: M.tensor_module(1,2).dimension() + sage: M.tensor_module(1, 2).dimension() # needs sage.modules 27 """ @@ -253,7 +253,7 @@ def example(self, base_ring=None): EXAMPLES:: - sage: Modules(QQ).WithBasis().Graded().example() + sage: Modules(QQ).WithBasis().Graded().example() # needs sage.combinat sage.modules An example of a graded module with basis: the free module on partitions over Rational Field """ @@ -274,7 +274,7 @@ def example(self, base_ring=None): EXAMPLES:: - sage: Modules(QQ).WithBasis().Graded().example() + sage: Modules(QQ).WithBasis().Graded().example() # needs sage.combinat sage.modules An example of a graded module with basis: the free module on partitions over Rational Field """ diff --git a/src/sage/categories/weyl_groups.py b/src/sage/categories/weyl_groups.py index c6b0338e441..1322ecd8499 100644 --- a/src/sage/categories/weyl_groups.py +++ b/src/sage/categories/weyl_groups.py @@ -1,12 +1,13 @@ +# sage.doctest: needs sage.combinat sage.groups r""" Weyl Groups """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery <nthiery at users.sf.net> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.misc.cachefunc import cached_method, cached_in_parent_method from sage.misc.lazy_import import LazyImport @@ -182,13 +183,15 @@ def bruhat_cone(self, x, y, side='upper', backend='cdd'): sage: x = W.from_reduced_word([1]) sage: y = W.w0 sage: W.bruhat_cone(x, y) - A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 2 rays + A 2-dimensional polyhedron in QQ^3 + defined as the convex hull of 1 vertex and 2 rays sage: W = WeylGroup(['E',6]) sage: x = W.one() sage: y = W.w0 sage: W.bruhat_cone(x, y, side='lower') - A 6-dimensional polyhedron in QQ^8 defined as the convex hull of 1 vertex and 6 rays + A 6-dimensional polyhedron in QQ^8 + defined as the convex hull of 1 vertex and 6 rays TESTS:: @@ -242,7 +245,9 @@ def quantum_bruhat_graph(self, index_set=()): sage: W = WeylGroup(['A',3], prefix="s") sage: g = W.quantum_bruhat_graph((1,3)) sage: g - Parabolic Quantum Bruhat Graph of Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space) for nodes (1, 3): Digraph on 6 vertices + Parabolic Quantum Bruhat Graph of Weyl Group of type ['A', 3] + (as a matrix group acting on the ambient space) + for nodes (1, 3): Digraph on 6 vertices sage: g.vertices(sort=True) [s2*s3*s1*s2, s3*s1*s2, s1*s2, s3*s2, s2, 1] sage: g.edges(sort=True) @@ -310,7 +315,7 @@ def length(x): from sage.graphs.digraph import DiGraph return DiGraph(visited, - name="Parabolic Quantum Bruhat Graph of %s for nodes %s"%(self, index_set), + name="Parabolic Quantum Bruhat Graph of %s for nodes %s" % (self, index_set), format="dict_of_dicts", data_structure="static_sparse") @@ -349,7 +354,6 @@ def is_pieri_factor(self): return self in self.parent().pieri_factors() - def left_pieri_factorizations(self, max_length=None): r""" Returns all factorizations of ``self`` as `uv`, where `u` @@ -386,14 +390,16 @@ def left_pieri_factorizations(self, max_length=None): 3 sage: W.from_reduced_word([1,2]).left_pieri_factorizations().cardinality() 2 - sage: [W.from_reduced_word([1,2]).left_pieri_factorizations(max_length=i).cardinality() for i in [-1, 0, 1, 2]] + sage: [W.from_reduced_word([1,2]).left_pieri_factorizations(max_length=i).cardinality() + ....: for i in [-1, 0, 1, 2]] [0, 1, 2, 2] sage: W = WeylGroup(['C',4,1]) sage: w = W.from_reduced_word([0,3,2,1,0]) sage: w.left_pieri_factorizations().cardinality() 7 - sage: [(u.reduced_word(),v.reduced_word()) for (u,v) in w.left_pieri_factorizations()] + sage: [(u.reduced_word(),v.reduced_word()) + ....: for (u,v) in w.left_pieri_factorizations()] [([], [3, 2, 0, 1, 0]), ([0], [3, 2, 1, 0]), ([3], [2, 0, 1, 0]), @@ -461,9 +467,11 @@ def stanley_symmetric_function_as_polynomial(self, max_length=None): 2*x1^3 + x1*x2 sage: W.from_reduced_word([1,2,1,0]).stanley_symmetric_function_as_polynomial() 3*x1^4 + 2*x1^2*x2 + x2^2 + x1*x3 - sage: W.from_reduced_word([1,2,3,1,2,1,0]).stanley_symmetric_function_as_polynomial() # long time + sage: x = W.from_reduced_word([1,2,3,1,2,1,0]) + sage: x.stanley_symmetric_function_as_polynomial() # long time 22*x1^7 + 11*x1^5*x2 + 5*x1^3*x2^2 + 3*x1^4*x3 + 2*x1*x2^3 + x1^2*x2*x3 - sage: W.from_reduced_word([3,1,2,0,3,1,0]).stanley_symmetric_function_as_polynomial() # long time + sage: y = W.from_reduced_word([3,1,2,0,3,1,0]) + sage: y.stanley_symmetric_function_as_polynomial() # long time 8*x1^7 + 4*x1^5*x2 + 2*x1^3*x2^2 + x1*x2^3 sage: W = WeylGroup(['C',3,1]) @@ -485,16 +493,15 @@ def stanley_symmetric_function_as_polynomial(self, max_length=None): W = self.parent() pieri_factors = W.pieri_factors() from sage.rings.rational_field import QQ - R = QQ[','.join('x%s'%l for l in range(1,pieri_factors.max_length()+1))] + R = QQ[','.join('x%s' % l for l in range(1, pieri_factors.max_length()+1))] x = R.gens() if self.is_one(): return R.one() return R(sum(2**(pieri_factors.stanley_symm_poly_weight(u))*x[u.length()-1] * v.stanley_symmetric_function_as_polynomial(max_length=u.length()) - for (u,v) in self.left_pieri_factorizations(max_length) + for (u, v) in self.left_pieri_factorizations(max_length) if u != W.one())) - def stanley_symmetric_function(self): r""" Return the affine Stanley symmetric function indexed by ``self``. @@ -518,10 +525,12 @@ def stanley_symmetric_function(self): sage: W = WeylGroup(['A', 3, 1]) sage: W.from_reduced_word([3,1,2,0,3,1,0]).stanley_symmetric_function() - 8*m[1, 1, 1, 1, 1, 1, 1] + 4*m[2, 1, 1, 1, 1, 1] + 2*m[2, 2, 1, 1, 1] + m[2, 2, 2, 1] + 8*m[1, 1, 1, 1, 1, 1, 1] + 4*m[2, 1, 1, 1, 1, 1] + + 2*m[2, 2, 1, 1, 1] + m[2, 2, 2, 1] sage: A = AffinePermutationGroup(['A',3,1]) sage: A.from_reduced_word([3,1,2,0,3,1,0]).stanley_symmetric_function() - 8*m[1, 1, 1, 1, 1, 1, 1] + 4*m[2, 1, 1, 1, 1, 1] + 2*m[2, 2, 1, 1, 1] + m[2, 2, 2, 1] + 8*m[1, 1, 1, 1, 1, 1, 1] + 4*m[2, 1, 1, 1, 1, 1] + + 2*m[2, 2, 1, 1, 1] + m[2, 2, 2, 1] sage: W = WeylGroup(['C',3,1]) sage: W.from_reduced_word([0,2,1,0]).stanley_symmetric_function() @@ -539,10 +548,11 @@ def stanley_symmetric_function(self): sage: A = AffinePermutationGroup(['A',4,1]) sage: a = A([-2,0,1,4,12]) sage: a.stanley_symmetric_function() - 6*m[1, 1, 1, 1, 1, 1, 1, 1] + 5*m[2, 1, 1, 1, 1, 1, 1] + 4*m[2, 2, 1, 1, 1, 1] - + 3*m[2, 2, 2, 1, 1] + 2*m[2, 2, 2, 2] + 4*m[3, 1, 1, 1, 1, 1] + 3*m[3, 2, 1, 1, 1] - + 2*m[3, 2, 2, 1] + 2*m[3, 3, 1, 1] + m[3, 3, 2] + 3*m[4, 1, 1, 1, 1] + 2*m[4, 2, 1, 1] - + m[4, 2, 2] + m[4, 3, 1] + 6*m[1, 1, 1, 1, 1, 1, 1, 1] + 5*m[2, 1, 1, 1, 1, 1, 1] + + 4*m[2, 2, 1, 1, 1, 1] + 3*m[2, 2, 2, 1, 1] + 2*m[2, 2, 2, 2] + + 4*m[3, 1, 1, 1, 1, 1] + 3*m[3, 2, 1, 1, 1] + 2*m[3, 2, 2, 1] + + 2*m[3, 3, 1, 1] + m[3, 3, 2] + 3*m[4, 1, 1, 1, 1] + + 2*m[4, 2, 1, 1] + m[4, 2, 2] + m[4, 3, 1] One more example (:trac:`14095`):: @@ -737,7 +747,7 @@ def bruhat_lower_covers_coroots(self): [(s1*s2*s1, alphacheck[1] + alphacheck[2] + alphacheck[3]), (s3*s2*s1, alphacheck[2]), (s3*s1*s2, alphacheck[1])] """ - return [(x[0],x[1].reflection_to_coroot()) + return [(x[0], x[1].reflection_to_coroot()) for x in self.bruhat_lower_covers_reflections()] def bruhat_upper_covers_coroots(self): @@ -760,7 +770,7 @@ def bruhat_upper_covers_coroots(self): (s3*s4*s1*s2*s1, alphacheck[4]), (s4*s3*s1*s2*s1, alphacheck[1] + alphacheck[2] + alphacheck[3] + alphacheck[4])] """ - return [(x[0],x[1].reflection_to_coroot()) + return [(x[0], x[1].reflection_to_coroot()) for x in self.bruhat_upper_covers_reflections()] def quantum_bruhat_successors(self, index_set=None, roots=False, quantum_only=False): @@ -809,7 +819,8 @@ def quantum_bruhat_successors(self, index_set=None, roots=False, quantum_only=Fa sage: w.quantum_bruhat_successors([1,3]) Traceback (most recent call last): ... - ValueError: s2*s3 is not of minimum length in its coset of the parabolic subgroup generated by the reflections (1, 3) + ValueError: s2*s3 is not of minimum length in its coset + of the parabolic subgroup generated by the reflections (1, 3) """ W = self.parent() if not W.cartan_type().is_finite(): @@ -829,12 +840,12 @@ def quantum_bruhat_successors(self, index_set=None, roots=False, quantum_only=Fa wrc = wr.coset_representative(index_set) if wrc == wr and wr.length() == w_length_plus_one and not quantum_only: if roots: - successors.append((wr,alpha)) + successors.append((wr, alpha)) else: successors.append(wr) elif alpha.quantum_root() and wrc.length() == w_length_plus_one - lattice.nonparabolic_positive_root_sum(index_set).scalar(alpha.associated_coroot()): if roots: - successors.append((wrc,alpha)) + successors.append((wrc, alpha)) else: successors.append(wrc) return successors diff --git a/src/sage/categories/with_realizations.py b/src/sage/categories/with_realizations.py index 7f59b92d72b..d0dc8d148bd 100644 --- a/src/sage/categories/with_realizations.py +++ b/src/sage/categories/with_realizations.py @@ -69,20 +69,20 @@ def WithRealizations(self): represented. Consider for example an algebra `A` which admits several natural bases:: - sage: A = Sets().WithRealizations().example(); A + sage: A = Sets().WithRealizations().example(); A # needs sage.modules The subset algebra of {1, 2, 3} over Rational Field For each such basis `B` one implements a parent `P_B` which realizes `A` with its elements represented by expanding them on the basis `B`:: + sage: # needs sage.modules sage: A.F() The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis sage: A.Out() The subset algebra of {1, 2, 3} over Rational Field in the Out basis sage: A.In() The subset algebra of {1, 2, 3} over Rational Field in the In basis - sage: A.an_element() F[{}] + 2*F[{1}] + 3*F[{2}] + F[{1, 2}] @@ -90,6 +90,7 @@ def WithRealizations(self): to `B'` is implemented by a canonical coercion between `P_B` and `P_{B'}`:: + sage: # needs sage.combinat sage.modules sage: F = A.F(); In = A.In(); Out = A.Out() sage: i = In.an_element(); i In[{}] + 2*In[{1}] + 3*In[{2}] + In[{1, 2}] @@ -102,12 +103,13 @@ def WithRealizations(self): allowing for mixed arithmetic:: - sage: (1 + Out.from_set(1)) * In.from_set(2,3) - Out[{}] + 2*Out[{1}] + 2*Out[{2}] + 2*Out[{3}] + 2*Out[{1, 2}] + 2*Out[{1, 3}] + 4*Out[{2, 3}] + 4*Out[{1, 2, 3}] + sage: (1 + Out.from_set(1)) * In.from_set(2,3) # needs sage.combinat sage.modules + Out[{}] + 2*Out[{1}] + 2*Out[{2}] + 2*Out[{3}] + 2*Out[{1, 2}] + + 2*Out[{1, 3}] + 4*Out[{2, 3}] + 4*Out[{1, 2, 3}] In our example, there are three realizations:: - sage: A.realizations() + sage: A.realizations() # needs sage.modules [The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis, The subset algebra of {1, 2, 3} over Rational Field in the In basis, The subset algebra of {1, 2, 3} over Rational Field in the Out basis] @@ -115,10 +117,13 @@ def WithRealizations(self): Instead of manually defining the shorthands ``F``, ``In``, and ``Out``, as above one can just do:: - sage: A.inject_shorthands() - Defining F as shorthand for The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis - Defining In as shorthand for The subset algebra of {1, 2, 3} over Rational Field in the In basis - Defining Out as shorthand for The subset algebra of {1, 2, 3} over Rational Field in the Out basis + sage: A.inject_shorthands() # needs sage.combinat sage.modules + Defining F as shorthand for + The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis + Defining In as shorthand for + The subset algebra of {1, 2, 3} over Rational Field in the In basis + Defining Out as shorthand for + The subset algebra of {1, 2, 3} over Rational Field in the Out basis .. RUBRIC:: Rationale @@ -138,26 +143,28 @@ def WithRealizations(self): We now illustrate this second point by defining the polynomial ring with coefficients in `A`:: - sage: P = A['x']; P - Univariate Polynomial Ring in x over The subset algebra of {1, 2, 3} over Rational Field - sage: x = P.gen() + sage: P = A['x']; P # needs sage.modules + Univariate Polynomial Ring in x over + The subset algebra of {1, 2, 3} over Rational Field + sage: x = P.gen() # needs sage.modules In the following examples, the coefficients turn out to be all represented in the `F` basis:: - sage: P.one() + sage: P.one() # needs sage.modules F[{}] - sage: (P.an_element() + 1)^2 + sage: (P.an_element() + 1)^2 # needs sage.modules F[{}]*x^2 + 2*F[{}]*x + F[{}] However we can create a polynomial with mixed coefficients, and compute with it:: - sage: p = P([1, In[{1}], Out[{2}] ]); p + sage: p = P([1, In[{1}], Out[{2}] ]); p # needs sage.combinat sage.modules Out[{2}]*x^2 + In[{1}]*x + F[{}] - sage: p^2 + sage: p^2 # needs sage.combinat sage.modules Out[{2}]*x^4 - + (-8*In[{}] + 4*In[{1}] + 8*In[{2}] + 4*In[{3}] - 4*In[{1, 2}] - 2*In[{1, 3}] - 4*In[{2, 3}] + 2*In[{1, 2, 3}])*x^3 + + (-8*In[{}] + 4*In[{1}] + 8*In[{2}] + 4*In[{3}] + - 4*In[{1, 2}] - 2*In[{1, 3}] - 4*In[{2, 3}] + 2*In[{1, 2, 3}])*x^3 + (F[{}] + 3*F[{1}] + 2*F[{2}] - 2*F[{1, 2}] - 2*F[{2, 3}] + 2*F[{1, 2, 3}])*x^2 + (2*F[{}] + 2*F[{1}])*x + F[{}] @@ -169,16 +176,21 @@ def WithRealizations(self): One can easily coerce all coefficient to a given basis with:: - sage: p.map_coefficients(In) - (-4*In[{}] + 2*In[{1}] + 4*In[{2}] + 2*In[{3}] - 2*In[{1, 2}] - In[{1, 3}] - 2*In[{2, 3}] + In[{1, 2, 3}])*x^2 + In[{1}]*x + In[{}] + sage: p.map_coefficients(In) # needs sage.combinat sage.modules + (-4*In[{}] + 2*In[{1}] + 4*In[{2}] + 2*In[{3}] + - 2*In[{1, 2}] - In[{1, 3}] - 2*In[{2, 3}] + In[{1, 2, 3}])*x^2 + + In[{1}]*x + In[{}] Alas, the natural notation for constructing such polynomials does not yet work:: - sage: In[{1}] * x + sage: In[{1}] * x # needs sage.combinat sage.modules Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'The subset algebra of {1, 2, 3} over Rational Field in the In basis' and 'Univariate Polynomial Ring in x over The subset algebra of {1, 2, 3} over Rational Field' + TypeError: unsupported operand parent(s) for *: + 'The subset algebra of {1, 2, 3} over Rational Field in the In basis' + and 'Univariate Polynomial Ring in x over + The subset algebra of {1, 2, 3} over Rational Field' .. RUBRIC:: The category of realizations of `A` @@ -186,17 +198,18 @@ def WithRealizations(self): is a category (whose class inherits from :class:`~sage.categories.realizations.Category_realization_of_parent`):: - sage: A.Realizations() - Category of realizations of The subset algebra of {1, 2, 3} over Rational Field + sage: A.Realizations() # needs sage.modules + Category of realizations of + The subset algebra of {1, 2, 3} over Rational Field The various parent realizing `A` belong to this category:: - sage: A.F() in A.Realizations() + sage: A.F() in A.Realizations() # needs sage.modules True `A` itself is in the category of algebras with realizations:: - sage: A in Algebras(QQ).WithRealizations() + sage: A in Algebras(QQ).WithRealizations() # needs sage.modules True The (mostly technical) ``WithRealizations`` categories are the @@ -216,12 +229,12 @@ def WithRealizations(self): On our example, this simply means that `A` is automatically in the category of rings with realizations (covariance):: - sage: A in Rings().WithRealizations() + sage: A in Rings().WithRealizations() # needs sage.modules True and in the category of algebras (regressiveness):: - sage: A in Algebras(QQ) + sage: A in Algebras(QQ) # needs sage.modules True .. NOTE:: @@ -267,6 +280,7 @@ def WithRealizations(self): """ return WithRealizationsCategory.category_of(self) + Category.WithRealizations = WithRealizations class WithRealizationsCategory(RegressiveCovariantConstructionCategory): diff --git a/src/sage/coding/abstract_code.py b/src/sage/coding/abstract_code.py index 238a165c021..85cdce652b9 100644 --- a/src/sage/coding/abstract_code.py +++ b/src/sage/coding/abstract_code.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Codes @@ -127,7 +128,7 @@ def _explain_constructor(cl): var = "It accepts unspecified arguments as well.\n" else: var = "" - return("{}\n{}\n{}See the documentation of {}.{} for more details."\ + return("{}\n{}\n{}See the documentation of {}.{} for more details." .format(reqs, opts, var, cl.__module__, cl.__name__)) @@ -151,9 +152,9 @@ class AbstractCode(Parent): To implement a code, you need to: - - inherit from AbstractCode + - inherit from :class:`AbstractCode` - - call AbstractCode ``__init__`` method in the subclass constructor. + - call :class:`AbstractCode` ``__init__`` method in the subclass constructor. Example: ``super().__init__(length, "EncoderName", "DecoderName", "metric")``. "EncoderName" and "DecoderName" are set to ``None`` by default, a generic code class such as AbstractCode does @@ -196,9 +197,9 @@ class AbstractCode(Parent): ``MyDecoderClass``. - As AbstractCode is not designed to be implemented, it does not have any - representation methods. You should implement ``_repr_`` and ``_latex_`` - methods in the subclass. + As the class :class:`AbstractCode` is not designed to be instantiated, it + does not have any representation methods. You should implement ``_repr_`` + and ``_latex_`` methods in the subclass. """ def __init__(self, length, default_encoder_name=None, @@ -226,7 +227,7 @@ def __init__(self, length, default_encoder_name=None, EXAMPLES: - The following example demonstrates how to use subclass `AbstractCode` + The following example demonstrates how to use a subclass of ``AbstractCode`` for representing a new family of codes:: sage: from sage.coding.abstract_code import AbstractCode @@ -337,7 +338,7 @@ def __iter__(self): ....: super().__init__(10) We check we get a sensible error message while asking for an - iterator over the elements of our new class: + iterator over the elements of our new class:: sage: C = MyCode() sage: list(C) @@ -365,7 +366,7 @@ def __contains__(self, c): ....: super().__init__(length) We check we get a sensible error message while asking if an element is - in our new class: + in our new class:: sage: C = MyCode(3) sage: vector((1, 0, 0, 0, 0, 1, 1)) in C @@ -461,7 +462,7 @@ def _repr_(self): ....: super().__init__(10) We check we get a sensible error message while asking for a string - representation of an instance of our new class: + representation of an instance of our new class:: sage: C = MyCode() sage: C #random @@ -489,7 +490,7 @@ def _latex_(self): ....: super().__init__(10) We check we get a sensible error message while asking for a string - representation of an instance of our new class: + representation of an instance of our new class:: sage: C = MyCode() sage: latex(C) @@ -665,7 +666,7 @@ def add_encoder(self, name, encoder): def decode_to_code(self, word, decoder_name=None, *args, **kwargs): r""" - Corrects the errors in ``word`` and returns a codeword. + Correct the errors in ``word`` and returns a codeword. INPUT: @@ -683,7 +684,8 @@ def decode_to_code(self, word, decoder_name=None, *args, **kwargs): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: word = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: w_err = word + vector(GF(2), (1, 0, 0, 0, 0, 0, 0)) @@ -720,7 +722,8 @@ def decode_to_message(self, word, decoder_name=None, *args, **kwargs): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: word = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: C.decode_to_message(word) @@ -759,7 +762,8 @@ def decoder(self, decoder_name=None, *args, **kwargs): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: C.decoder() Syndrome decoder for [7, 4] linear code over GF(2) handling errors of weight up to 1 @@ -790,7 +794,8 @@ def decoder(self, decoder_name=None, *args, **kwargs): sage: C.decoder('Try') Traceback (most recent call last): ... - ValueError: There is no Decoder named 'Try'. The known Decoders are: ['InformationSet', 'NearestNeighbor', 'Syndrome'] + ValueError: There is no Decoder named 'Try'. + The known Decoders are: ['InformationSet', 'NearestNeighbor', 'Syndrome'] Some decoders take extra arguments. If the user forgets to supply these, the error message attempts to be helpful:: @@ -798,11 +803,13 @@ def decoder(self, decoder_name=None, *args, **kwargs): sage: C.decoder('InformationSet') Traceback (most recent call last): ... - ValueError: Constructing the InformationSet decoder failed, possibly due to missing or incorrect parameters. + ValueError: Constructing the InformationSet decoder failed, + possibly due to missing or incorrect parameters. The constructor requires the arguments ['number_errors']. It takes the optional arguments ['algorithm']. - It accepts unspecified arguments as well. - See the documentation of sage.coding.information_set_decoder.LinearCodeInformationSetDecoder for more details. + It accepts unspecified arguments as well. See the documentation of + sage.coding.information_set_decoder.LinearCodeInformationSetDecoder + for more details. """ if not self._default_decoder_name: @@ -830,14 +837,15 @@ def decoders_available(self, classes=False): INPUT: - ``classes`` -- (default: ``False``) if ``classes`` is set to ``True``, - return instead a ``dict`` mapping available decoder name to the + return instead a :class:`dict` mapping available decoder name to the associated decoder class. - OUTPUT: a list of strings, or a `dict` mapping strings to classes. + OUTPUT: a list of strings, or a :class:`dict` mapping strings to classes. EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: C.decoders_available() ['InformationSet', 'NearestNeighbor', 'Syndrome'] @@ -878,7 +886,8 @@ def encode(self, word, encoder_name=None, *args, **kwargs): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: word = vector((0, 1, 1, 0)) sage: C.encode(word) @@ -928,7 +937,8 @@ def encoder(self, encoder_name=None, *args, **kwargs): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: C.encoder() Generator matrix-based encoder for [7, 4] linear code over GF(2) @@ -944,7 +954,8 @@ def encoder(self, encoder_name=None, *args, **kwargs): ....: def field(self): ....: return self._field ....: def _repr_(self): - ....: return "%d dummy code over GF(%s)" % (self.length(), self.field().cardinality()) + ....: return "%d dummy code over GF(%s)" % (self.length(), + ....: self.field().cardinality()) sage: D = MyCodeFamily(5, GF(2)) sage: D.encoder() Traceback (most recent call last): @@ -964,7 +975,8 @@ def encoder(self, encoder_name=None, *args, **kwargs): sage: C.encoder('NonExistingEncoder') Traceback (most recent call last): ... - ValueError: There is no Encoder named 'NonExistingEncoder'. The known Encoders are: ['GeneratorMatrix', 'Systematic'] + ValueError: There is no Encoder named 'NonExistingEncoder'. + The known Encoders are: ['GeneratorMatrix', 'Systematic'] Some encoders take extra arguments. If the user incorrectly supplies these, the error message attempts to be helpful:: @@ -972,10 +984,12 @@ def encoder(self, encoder_name=None, *args, **kwargs): sage: C.encoder('Systematic', strange_parameter=True) Traceback (most recent call last): ... - ValueError: Constructing the Systematic encoder failed, possibly due to missing or incorrect parameters. - The constructor requires no arguments. - It takes the optional arguments ['systematic_positions']. - See the documentation of sage.coding.linear_code_no_metric.LinearCodeSystematicEncoder for more details. + ValueError: Constructing the Systematic encoder failed, + possibly due to missing or incorrect parameters. + The constructor requires no arguments. It takes the optional + arguments ['systematic_positions']. See the documentation of + sage.coding.linear_code_no_metric.LinearCodeSystematicEncoder + for more details. """ if not self._default_encoder_name: raise NotImplementedError("No encoder implemented for this code.") @@ -1002,14 +1016,15 @@ def encoders_available(self, classes=False): INPUT: - ``classes`` -- (default: ``False``) if ``classes`` is set to ``True``, - return instead a ``dict`` mapping available encoder name to the + return instead a :class:`dict` mapping available encoder name to the associated encoder class. - OUTPUT: a list of strings, or a `dict` mapping strings to classes. + OUTPUT: a list of strings, or a :class:`dict` mapping strings to classes. EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: C.encoders_available() ['GeneratorMatrix', 'Systematic'] @@ -1051,7 +1066,8 @@ def unencode(self, c, encoder_name=None, nocheck=False, **kwargs): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: C.unencode(c) diff --git a/src/sage/coding/ag_code.py b/src/sage/coding/ag_code.py index 72bf5c37d5f..f705f75d476 100644 --- a/src/sage/coding/ag_code.py +++ b/src/sage/coding/ag_code.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.rings.finite_rings sage.schemes """ AG codes @@ -538,7 +539,8 @@ def basis_differentials(self): sage: Q, = C.places_at_infinity() sage: pls.remove(Q) sage: code = codes.DifferentialAGCode(pls, 3*Q) - sage: matrix([[w.residue(p) for p in pls] for w in code.basis_differentials()]) + sage: matrix([[w.residue(p) for p in pls] + ....: for w in code.basis_differentials()]) [ 1 0 0 0 0 a + 1 a + 1 1] [ 0 1 0 0 0 a + 1 a 0] [ 0 0 1 0 0 a 1 a] diff --git a/src/sage/coding/ag_code_decoders.pyx b/src/sage/coding/ag_code_decoders.pyx index 54e3c1d8810..ccd6c8c6912 100644 --- a/src/sage/coding/ag_code_decoders.pyx +++ b/src/sage/coding/ag_code_decoders.pyx @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.rings.finite_rings sage.schemes r""" Decoders for AG codes @@ -61,7 +61,7 @@ AUTHORS: cimport cython from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.function_field.all import FunctionField +from sage.rings.function_field.constructor import FunctionField from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index 89778395ff3..e5ff88308b7 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -2,7 +2,7 @@ from sage.misc.lazy_import import lazy_import as _lazy_import _lazy_import("sage.coding.code_constructions", ["permutation_action", - "walsh_matrix"]) + "walsh_matrix"]) _lazy_import("sage.coding.linear_code", "LinearCode") diff --git a/src/sage/coding/bch_code.py b/src/sage/coding/bch_code.py index 1666c5c4380..40fa088354a 100644 --- a/src/sage/coding/bch_code.py +++ b/src/sage/coding/bch_code.py @@ -1,7 +1,8 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" BCH code -Let `F = GF(q)` and `\Phi` be the splitting field of `x^{n} - 1` over `F`, with +Let `F = \GF{q}` and `\Phi` be the splitting field of `x^{n} - 1` over `F`, with `n` a positive integer. Let also `\alpha` be an element of multiplicative order `n` in `\Phi`. Finally, let `b, \delta, \ell` be integers such that `0 \le b \le n`, `1 \le \delta \le n` and `\alpha^\ell` generates the multiplicative @@ -27,8 +28,8 @@ from sage.modules.free_module_element import vector from sage.misc.misc_c import prod from sage.categories.fields import Fields -from sage.arith.all import gcd -from sage.rings.all import Zmod +from sage.arith.misc import gcd +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as Zmod from .cyclic_code import CyclicCode from .grs_code import GeneralizedReedSolomonCode @@ -51,7 +52,7 @@ class BCHCode(CyclicCode): splitting field. It has to be of multiplicative order ``length`` over this field. If the splitting field is not ``field``, it also has to be a polynomial in ``zx``, where ``x`` is the degree of the extension field. - For instance, over `GF(16)`, it has to be a polynomial in ``z4``. + For instance, over `\GF{16}`, it has to be a polynomial in ``z4``. - ``offset`` -- (default: ``1``) the first element in the defining set @@ -79,7 +80,7 @@ class BCHCode(CyclicCode): sage: C.generator_polynomial() x^8 + x^7 + x^6 + x^4 + 1 - BCH codes are cyclic, and can be interfaced into the CyclicCode class. + BCH codes are cyclic, and can be interfaced into the :class:`CyclicCode` class. The smallest GRS code which contains a given BCH code can also be computed, and these two codes may be equal:: @@ -158,7 +159,7 @@ def __eq__(self, other): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -172,7 +173,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -186,7 +187,7 @@ def _latex_(self): def jump_size(self): r""" - Returns the jump size between two consecutive elements of the defining + Return the jump size between two consecutive elements of the defining set of ``self``. EXAMPLES:: @@ -199,7 +200,7 @@ def jump_size(self): def offset(self): r""" - Returns the offset which was used to compute the elements in + Return the offset which was used to compute the elements in the defining set of ``self``. EXAMPLES:: @@ -212,7 +213,7 @@ def offset(self): def designed_distance(self): r""" - Returns the designed distance of ``self``. + Return the designed distance of ``self``. EXAMPLES:: @@ -224,7 +225,7 @@ def designed_distance(self): def bch_to_grs(self): r""" - Returns the underlying GRS code from which ``self`` was derived. + Return the underlying GRS code from which ``self`` was derived. EXAMPLES:: @@ -286,7 +287,7 @@ def __init__(self, code, grs_decoder="KeyEquationSyndrome", **kwargs): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -299,7 +300,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -313,7 +314,7 @@ def _latex_(self): def grs_code(self): r""" - Returns the underlying GRS code of :meth:`sage.coding.decoder.Decoder.code`. + Return the underlying GRS code of :meth:`sage.coding.decoder.Decoder.code`. .. NOTE:: @@ -366,7 +367,7 @@ def grs_code(self): def grs_decoder(self): r""" - Returns the decoder used to decode words of :meth:`grs_code`. + Return the decoder used to decode words of :meth:`grs_code`. EXAMPLES:: @@ -379,7 +380,7 @@ def grs_decoder(self): def bch_word_to_grs(self, c): r""" - Returns ``c`` converted as a codeword of :meth:`grs_code`. + Return ``c`` converted as a codeword of :meth:`grs_code`. EXAMPLES:: @@ -397,7 +398,7 @@ def bch_word_to_grs(self, c): def grs_word_to_bch(self, c): r""" - Returns ``c`` converted as a codeword of :meth:`sage.coding.decoder.Decoder.code`. + Return ``c`` converted as a codeword of :meth:`sage.coding.decoder.Decoder.code`. EXAMPLES:: @@ -406,7 +407,8 @@ def grs_word_to_bch(self, c): sage: Cgrs = D.grs_code() sage: Fgrs = Cgrs.base_field() sage: b = Fgrs.gen() - sage: c = vector(Fgrs, [0, b^2 + b, 1, b^2 + b, 0, 1, 1, 1, b^2 + b, 0, 0, b^2 + b + 1, b^2 + b, 0, 1]) + sage: c = vector(Fgrs, [0, b^2 + b, 1, b^2 + b, 0, 1, 1, 1, + ....: b^2 + b, 0, 0, b^2 + b + 1, b^2 + b, 0, 1]) sage: D.grs_word_to_bch(c) (0, a, 1, a, 0, 1, 1, 1, a, 0, 0, a + 1, a, 0, 1) """ @@ -424,7 +426,8 @@ def decode_to_code(self, y): sage: a = F.gen() sage: C = codes.BCHCode(F, 15, 3, jump_size=2) sage: D = codes.decoders.BCHUnderlyingGRSDecoder(C) - sage: y = vector(F, [a, a + 1, 1, a + 1, 1, a, a + 1, a + 1, 0, 1, a + 1, 1, 1, 1, a]) + sage: y = vector(F, [a, a + 1, 1, a + 1, 1, a, a + 1, + ....: a + 1, 0, 1, a + 1, 1, 1, 1, a]) sage: D.decode_to_code(y) (a, a + 1, 1, a + 1, 1, a, a + 1, a + 1, 0, 1, a + 1, 1, 1, 1, a) sage: D.decode_to_code(y) in C @@ -438,12 +441,18 @@ def decode_to_code(self, y): [31, 6] BCH Code over GF(2) with designed distance 15 sage: D = codes.decoders.BCHUnderlyingGRSDecoder(C, "GuruswamiSudan", tau=8) sage: Dgrs = D.grs_decoder() - sage: c = vector(GF(2), [1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0]) - sage: y = vector(GF(2), [1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]) + sage: c = vector(GF(2), [1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, + ....: 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0]) + sage: y = vector(GF(2), [1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, + ....: 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]) sage: print (c in C and (c-y).hamming_weight() == 8) True sage: Dgrs.decode_to_code(y) - [(1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0), (1, z5^3 + z5^2 + z5 + 1, z5^4 + z5^2 + z5, z5^4 + z5^3 + z5^2 + 1, 0, 0, z5^4 + z5 + 1, 1, z5^4 + z5^2 + z5, 0, 1, z5^4 + z5, 1, 0, 1, 1, 1, 0, 0, z5^4 + z5^3 + 1, 1, 0, 1, 1, 1, 1, z5^4 + z5^3 + z5 + 1, 1, 1, 0, 0)] + [(1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, + 0, 1, 1, 0, 1, 0, 0), + (1, z5^3 + z5^2 + z5 + 1, z5^4 + z5^2 + z5, z5^4 + z5^3 + z5^2 + 1, 0, 0, + z5^4 + z5 + 1, 1, z5^4 + z5^2 + z5, 0, 1, z5^4 + z5, 1, 0, 1, 1, 1, 0, + 0, z5^4 + z5^3 + 1, 1, 0, 1, 1, 1, 1, z5^4 + z5^3 + z5 + 1, 1, 1, 0, 0)] sage: D.decode_to_code(y) == [c] True """ @@ -464,7 +473,7 @@ def decode_to_code(self, y): def decoding_radius(self): r""" - Returns maximal number of errors that ``self`` can decode. + Return maximal number of errors that ``self`` can decode. EXAMPLES:: diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index 408c1f55634..c3f9433d07f 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -1,10 +1,11 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Optimized low-level binary code representation -Some computations with linear binary codes. Fix a basis for `GF(2)^n`. -A linear binary code is a linear subspace of `GF(2)^n`, together with +Some computations with linear binary codes. Fix a basis for `\GF{2}^n`. +A linear binary code is a linear subspace of `\GF{2}^n`, together with this choice of basis. A permutation `g \in S_n` of the fixed basis -gives rise to a permutation of the vectors, or words, in `GF(2)^n`, +gives rise to a permutation of the vectors, or words, in `\GF{2}^n`, sending `(w_i)` to `(w_{g(i)})`. The permutation automorphism group of the code `C` is the set of permutations of the basis that bijectively map `C` to itself. Note that if `g` is such a permutation, then @@ -15,7 +16,7 @@ map `C` to itself. Note that if `g` is such a permutation, then Over other fields, it is also required that the map be linear, which as per above boils down to scalar multiplication. However, over -`GF(2),` the only scalars are 0 and 1, so the linearity condition has +`\GF{2},` the only scalars are 0 and 1, so the linearity condition has trivial effect. AUTHOR: @@ -46,7 +47,7 @@ from cpython.object cimport PyObject_RichCompare from cysignals.memory cimport sig_malloc, sig_realloc, sig_free from sage.structure.element import is_Matrix -from sage.misc.misc import cputime +from sage.misc.timing import cputime from sage.rings.integer cimport Integer from copy import copy from sage.data_structures.bitset_base cimport * @@ -87,12 +88,12 @@ cdef int *hamming_weights(): def weight_dist(M): """ - Computes the weight distribution of the row space of M. + Computes the weight distribution of the row space of `M`. EXAMPLES:: sage: from sage.coding.binary_code import weight_dist - sage: M = Matrix(GF(2),[ + sage: M = Matrix(GF(2), [ ....: [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], ....: [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0], ....: [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1], @@ -100,14 +101,14 @@ def weight_dist(M): ....: [0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1]]) sage: weight_dist(M) [1, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 1] - sage: M = Matrix(GF(2),[ + sage: M = Matrix(GF(2), [ ....: [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0], ....: [0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0], ....: [0,0,0,0,0,1,0,1,0,0,0,1,1,1,1,1,1], ....: [0,0,0,1,1,0,0,0,0,1,1,0,1,1,0,1,1]]) sage: weight_dist(M) [1, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 4, 0, 0, 0, 0, 0] - sage: M=Matrix(GF(2),[ + sage: M = Matrix(GF(2), [ ....: [1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,0,0], ....: [0,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,0], ....: [0,0,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0], @@ -155,35 +156,37 @@ def weight_dist(M): return L def test_word_perms(t_limit=5.0): - """ - Tests the WordPermutation structs for at least t_limit seconds. + r""" + Test the :class:`WordPermutation` structs for at least ``t_limit`` seconds. These are structures written in pure C for speed, and are tested from this function, which performs the following tests: - 1. Tests create_word_perm, which creates a WordPermutation from a Python - list L representing a permutation i --> L[i]. Takes a random word and - permutes it by a random list permutation, and tests that the result - agrees with doing it the slow way. + 1. Tests :func:`create_word_perm`, which creates a :class:`WordPermutation` + from a Python list `L` representing a permutation `i \mapsto + L[i]`. Takes a random word and permutes it by a random list permutation, + and tests that the result agrees with doing it the slow way. - 1b. Tests create_array_word_perm, which creates a WordPermutation from a - C array. Does the same as above. + 1b. Tests :func:`create_array_word_perm`, which creates a + :class:`WordPermutation` from a C array. Does the same as above. - 2. Tests create_comp_word_perm, which creates a WordPermutation as a - composition of two WordPermutations. Takes a random word and - two random permutations, and tests that the result of permuting by the - composition is correct. + 2. Tests :func:`create_comp_word_perm`, which creates a + :class:`WordPermutation` as a composition of two + :class:`WordPermutation` objects. Takes a random word and two random + permutations, and tests that the result of permuting by the composition + is correct. - 3. Tests create_inv_word_perm and create_id_word_perm, which create a - WordPermutation as the inverse and identity permutations, resp. - Takes a random word and a random permutation, and tests that the result - permuting by the permutation and its inverse in either order, and - permuting by the identity both return the original word. + 3. Tests :func:`create_inv_word_perm` and :func:`create_id_word_perm`, + which create a :class:`WordPermutation` as the inverse and identity + permutations, resp. Takes a random word and a random permutation, and + tests that the result permuting by the permutation and its inverse in + either order, and permuting by the identity both return the original + word. .. NOTE:: - The functions permute_word_by_wp and dealloc_word_perm are implicitly - involved in each of the above tests. + The functions :func:`permute_word_by_wp` and :func:`dealloc_word_perm` + are implicitly involved in each of the above tests. TESTS:: @@ -202,10 +205,10 @@ def test_word_perms(t_limit=5.0): raise MemoryError("Error allocating memory.") from sage.misc.prandom import randint from sage.combinat.permutation import Permutations - S = Permutations(list(xrange(n))) + S = Permutations(list(range(n))) t = cputime() while cputime(t) < t_limit: - word = [randint(0, 1) for _ in xrange(n)] + word = [randint(0, 1) for _ in range(n)] cw1 = 0 for j from 0 <= j < n: cw1 += (<codeword>word[j]) << (<codeword>j) @@ -298,7 +301,7 @@ cdef WordPermutation *create_word_perm(object list_perm): word_perm.chunk_num = num_chunks words_per_chunk = 1 << chunk_size word_perm.gate = ( (<codeword>1) << chunk_size ) - 1 - list_perm += list(xrange(len(list_perm), chunk_size*num_chunks)) + list_perm += list(range(len(list_perm), chunk_size*num_chunks)) word_perm.chunk_words = words_per_chunk for i from 0 <= i < num_chunks: images_i = <codeword *> sig_malloc(words_per_chunk * sizeof(codeword)) @@ -524,7 +527,7 @@ def test_expand_to_ortho_basis(B=None): INPUT: - - B -- a BinaryCode in standard form + - ``B`` -- a :class:`BinaryCode` in standard form OUTPUT: @@ -536,7 +539,7 @@ def test_expand_to_ortho_basis(B=None): TESTS:: sage: from sage.coding.binary_code import test_expand_to_ortho_basis, BinaryCode - sage: M = Matrix(GF(2), [[1,1,1,1,1,1,0,0,0,0],[0,0,1,1,1,1,1,1,1,1]]) + sage: M = Matrix(GF(2), [[1,1,1,1,1,1,0,0,0,0], [0,0,1,1,1,1,1,1,1,1]]) sage: B = BinaryCode(M) sage: B.put_in_std_form() 0 @@ -661,7 +664,7 @@ cdef codeword *expand_to_ortho_basis(BinaryCode B, int n): for j from i <= j < n: basis[j] = 0 # now basis is length i - perm = list(xrange(B.nrows)) + perm = list(range(B.nrows)) perm_c = [] for j from B.nrows <= j < B.ncols: if (<codeword>1 << j) & pivots: @@ -669,7 +672,7 @@ cdef codeword *expand_to_ortho_basis(BinaryCode B, int n): else: perm_c.append(j) perm.extend(perm_c) - perm.extend(list(xrange(B.ncols, n))) + perm.extend(list(range(B.ncols, n))) perm_c = [0]*n for j from 0 <= j < n: perm_c[perm[j]] = j @@ -865,12 +868,12 @@ cdef class BinaryCode: def matrix(self): """ - Returns the generator matrix of the BinaryCode, i.e. the code is the - rowspace of B.matrix(). + Return the generator matrix of the :class:`BinaryCode`, i.e. the code is + the rowspace of ``B.matrix()``. EXAMPLES:: - sage: M = Matrix(GF(2), [[1,1,1,1,0,0],[0,0,1,1,1,1]]) + sage: M = Matrix(GF(2), [[1,1,1,1,0,0], [0,0,1,1,1,1]]) sage: from sage.coding.binary_code import * sage: B = BinaryCode(M) sage: B.matrix() @@ -1212,7 +1215,7 @@ cdef class BinaryCode: EXAMPLES:: sage: from sage.coding.binary_code import * - sage: M = Matrix(GF(2), [[1,1,1,1,0,0],[0,0,1,1,1,1]]) + sage: M = Matrix(GF(2), [[1,1,1,1,0,0], [0,0,1,1,1,1]]) sage: B = BinaryCode(M); B Binary [6,2] linear code, generator matrix [111100] @@ -2878,7 +2881,8 @@ cdef class PartitionStack: sage: import sage.coding.binary_code sage: from sage.coding.binary_code import * - sage: M = Matrix(GF(2), [[1,1,1,1,0,0,0,0],[0,0,1,1,1,1,0,0],[0,0,0,0,1,1,1,1],[1,0,1,0,1,0,1,0]]) + sage: M = Matrix(GF(2), [[1,1,1,1,0,0,0,0], [0,0,1,1,1,1,0,0], + ....: [0,0,0,0,1,1,1,1], [1,0,1,0,1,0,1,0]]) sage: B = BinaryCode(M) sage: P = PartitionStack(4, 8) sage: P._refine(0, [[0,0],[1,0]], B) @@ -2930,7 +2934,11 @@ cdef class PartitionStack: sage: import sage.coding.binary_code sage: from sage.coding.binary_code import * sage: P = PartitionStack(4, 8) - sage: P._dangerous_dont_use_set_ents_lvls(list(range(8)), list(range(7))+[-1], [4,7,12,11,1,9,3,0,2,5,6,8,10,13,14,15], [0]*16) + sage: P._dangerous_dont_use_set_ents_lvls( + ....: list(range(8)), + ....: list(range(7)) + [-1], + ....: [4,7,12,11,1,9,3,0,2,5,6,8,10,13,14,15], + ....: [0]*16) sage: P ({4},{7},{12},{11},{1},{9},{3},{0},{2},{5},{6},{8},{10},{13},{14},{15}) ({0},{1,2,3,4,5,6,7}) ({4},{7},{12},{11},{1},{9},{3},{0},{2},{5},{6},{8},{10},{13},{14},{15}) ({0},{1},{2,3,4,5,6,7}) @@ -3164,12 +3172,12 @@ cdef class BinaryCodeClassifier: def _aut_gp_and_can_label(self, CC, verbosity=0): """ - Compute the automorphism group and canonical label of the code CC. + Compute the automorphism group and canonical label of the code ``CC``. INPUT: - - CC - a BinaryCode object - - verbosity -- a nonnegative integer + - ``CC`` -- a BinaryCode object + - ``verbosity`` -- a nonnegative integer OUTPUT: a tuple, (gens, labeling, size, base) @@ -3896,17 +3904,17 @@ cdef class BinaryCodeClassifier: def generate_children(self, BinaryCode B, int n, int d=2): """ - Use canonical augmentation to generate children of the code B. + Use canonical augmentation to generate children of the code `B`. INPUT: - - B -- a BinaryCode + - ``B`` -- a :class:`BinaryCode` - - n -- limit on the degree of the code + - ``n`` -- limit on the degree of the code - - d -- test whether new vector has weight divisible by d. If d==4, this - ensures that all doubly-even canonically augmented children are - generated. + - ``d`` -- test whether new vector has weight divisible by `d`. If + `d=4`, this ensures that all doubly-even canonically augmented + children are generated. EXAMPLES:: @@ -3931,7 +3939,8 @@ cdef class BinaryCodeClassifier: sage: for n in range(13): ....: s = 'n=%2d : '%n ....: for k in range(1,7): - ....: s += '%3d '%len([C for C in L if C.length() == n and C.dimension() == k]) + ....: s += '%3d '%len([C for C in L + ....: if C.length() == n and C.dimension() == k]) ....: print(s) n= 0 : 0 0 0 0 0 0 n= 1 : 0 0 0 0 0 0 @@ -4017,7 +4026,7 @@ cdef class BinaryCodeClassifier: for i from 0 <= i < len(aut_gp_gens): - parent_generators[i] = create_word_perm(aut_gp_gens[i] + list(xrange(B.ncols, n))) + parent_generators[i] = create_word_perm(aut_gp_gens[i] + list(range(B.ncols, n))) word = 0 while ortho_basis[k] & (((<codeword>1) << B.ncols) - 1): @@ -4103,7 +4112,6 @@ cdef class BinaryCodeClassifier: m = BinaryCode(matrix(ZZ, rs)) m_aut_gp_gens, m_labeling, m_size, m_base = self._aut_gp_and_can_label(m) - from sage.arith.all import factorial if True: # size*factorial(n-B.ncols) == m_size: if len(m_aut_gp_gens) == 0: @@ -4117,7 +4125,7 @@ cdef class BinaryCodeClassifier: aut_B_aug = libgap(PermutationGroup([PermutationGroupElement([a+1 for a in g]) for g in aug_aut_gp_gens])) H = libgap(aut_m).Intersection2(aut_B_aug) rt_transversal = [[int(a) - 1 for a in g.ListPerm(n)] for g in aut_B_aug.RightTransversal(H) if not g.IsOne()] - rt_transversal.append(list(xrange(n))) + rt_transversal.append(list(range(n))) bingo2 = 0 for coset_rep in rt_transversal: diff --git a/src/sage/coding/bounds_catalog.py b/src/sage/coding/bounds_catalog.py index 25d422afee7..aa4c2dd9996 100644 --- a/src/sage/coding/bounds_catalog.py +++ b/src/sage/coding/bounds_catalog.py @@ -1,15 +1,13 @@ r""" Index of bounds on the parameters of codes -The ``codes.bounds`` object may be used to access the bounds that Sage can compute. +The :obj:`codes.bounds` object may be used to access the bounds that Sage can compute. {INDEX_OF_FUNCTIONS} -.. NOTE:: +To import these names into the global namespace, use:: - To import these names into the global namespace, use: - - sage: from sage.coding.bounds_catalog import * + sage: from sage.coding.bounds_catalog import * """ from sage.misc.lazy_import import lazy_import as _lazy_import _lazy_import("sage.coding.code_bounds", ["codesize_upper_bound", diff --git a/src/sage/coding/channel.py b/src/sage/coding/channel.py index 915982850c9..50ea5f5cb1f 100644 --- a/src/sage/coding/channel.py +++ b/src/sage/coding/channel.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Channels @@ -147,9 +148,9 @@ class Channel(SageObject): This abstract class provides the following parameters: - - ``input_space`` -- the space of the words to transmit + - ``input_space`` -- the space of the words to transmit - - ``output_space`` -- the space of the transmitted words + - ``output_space`` -- the space of the transmitted words """ def __init__(self, input_space, output_space): @@ -277,7 +278,7 @@ def transmit_unsafe(self, message): Return ``message``, modified accordingly with the algorithm of the channel it was transmitted through. - This method does not check if ``message`` belongs to the input space of``self``. + This method does not check if ``message`` belongs to the input space of ``self``. This is an abstract method which should be reimplemented in all the subclasses of Channel. @@ -309,7 +310,7 @@ class StaticErrorRateChannel(Channel): EXAMPLES: - We construct a StaticErrorRateChannel which adds 2 errors + We construct a :class:`StaticErrorRateChannel` which adds 2 errors to any transmitted message:: sage: n_err = 2 @@ -367,7 +368,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -383,12 +384,12 @@ def _latex_(self): def transmit_unsafe(self, message): r""" - Returns ``message`` with as many errors as ``self._number_errors`` in it. + Return ``message`` with as many errors as ``self._number_errors`` in it. If ``self._number_errors`` was passed as a tuple for the number of errors, it will pick a random integer between the bounds of the tuple and use it as the number of errors. - This method does not check if ``message`` belongs to the input space of``self``. + This method does not check if ``message`` belongs to the input space of ``self``. INPUT: @@ -429,7 +430,7 @@ def transmit_unsafe(self, message): def number_errors(self): r""" - Returns the number of errors created by ``self``. + Return the number of errors created by ``self``. EXAMPLES:: @@ -445,8 +446,8 @@ class ErrorErasureChannel(Channel): r""" Channel which adds errors and erases several positions in any message it transmits. - The output space of this channel is a Cartesian product - between its input space and a VectorSpace of the same dimension over GF(2) + The output space of this channel is a Cartesian product between its input + space and a VectorSpace of the same dimension over `\GF{2}`. INPUT: @@ -522,7 +523,7 @@ def __init__(self, space, number_errors, number_erasures): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -541,7 +542,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -560,8 +561,8 @@ def _latex_(self): def transmit_unsafe(self, message): r""" - Returns ``message`` with as many errors as ``self._number_errors`` in it, and as many erasures - as ``self._number_erasures`` in it. + Return ``message`` with as many errors as ``self._number_errors`` in it, + and as many erasures as ``self._number_erasures`` in it. If ``self._number_errors`` was passed as an tuple for the number of errors, it will pick a random integer between the bounds of the tuple and use it as the number of errors. @@ -572,7 +573,7 @@ def transmit_unsafe(self, message): the received message will always contains exactly as many errors and erasures as expected. - This method does not check if ``message`` belongs to the input space of``self``. + This method does not check if ``message`` belongs to the input space of ``self``. INPUT: @@ -582,9 +583,10 @@ def transmit_unsafe(self, message): - a couple of vectors, namely: - - the transmitted message, which is ``message`` with erroneous and erased positions - - the erasure vector, which contains ``1`` at the erased positions of the transmitted message - , 0 elsewhere. + - the transmitted message, which is ``message`` with erroneous and + erased positions + - the erasure vector, which contains ``1`` at the erased positions of + the transmitted message and ``0`` elsewhere. EXAMPLES:: @@ -603,7 +605,7 @@ def transmit_unsafe(self, message): zero = V.base_ring().zero() errors = sample(range(n), number_errors + number_erasures) - error_positions = errors[:number_errors] + error_positions = errors[:number_errors] erasure_positions = errors[number_errors:] error_vector = random_error_vector(n, V.base_ring(), error_positions) @@ -617,7 +619,7 @@ def transmit_unsafe(self, message): def number_errors(self): r""" - Returns the number of errors created by ``self``. + Return the number of errors created by ``self``. EXAMPLES:: @@ -630,7 +632,7 @@ def number_errors(self): def number_erasures(self): r""" - Returns the number of erasures created by ``self``. + Return the number of erasures created by ``self``. EXAMPLES:: @@ -644,10 +646,10 @@ def number_erasures(self): class QarySymmetricChannel(Channel): r""" - The q-ary symmetric, memoryless communication channel. + The `q`-ary symmetric, memoryless communication channel. Given an alphabet `\Sigma` with `|\Sigma| = q` and an error probability - `\epsilon`, a q-ary symmetric channel sends an element of `\Sigma` into the + `\epsilon`, a `q`-ary symmetric channel sends an element of `\Sigma` into the same element with probability `1 - \epsilon`, and any one of the other `q - 1` elements with probability `\frac{\epsilon}{q - 1}`. This implementation operates over vectors in `\Sigma^n`, and "transmits" each element of the @@ -665,20 +667,21 @@ class QarySymmetricChannel(Channel): INPUT: - ``space`` -- the input and output space of the channel. It has to be - `GF(q)^n` for some finite field `GF(q)`. + `\GF{q}^n` for some finite field `\GF{q}`. - ``epsilon`` -- the transmission error probability of the individual elements. EXAMPLES: - We construct a QarySymmetricChannel which corrupts 30% of all transmitted - symbols:: + We construct a :class:`QarySymmetricChannel` which corrupts 30% of all + transmitted symbols:: sage: epsilon = 0.3 sage: Chan = channels.QarySymmetricChannel(GF(59)^50, epsilon) sage: Chan q-ary symmetric channel with error probability 0.300000000000000, - of input and output space Vector space of dimension 50 over Finite Field of size 59 + of input and output space + Vector space of dimension 50 over Finite Field of size 59 """ def __init__(self, space, epsilon): @@ -713,7 +716,7 @@ def __init__(self, space, epsilon): def __repr__(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -728,7 +731,7 @@ def __repr__(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -743,10 +746,10 @@ def _latex_(self): def transmit_unsafe(self, message): r""" - Returns ``message`` where each of the symbols has been changed to another from the alphabet with + Return ``message`` where each of the symbols has been changed to another from the alphabet with probability :meth:`error_probability`. - This method does not check if ``message`` belongs to the input space of``self``. + This method does not check if ``message`` belongs to the input space of ``self``. INPUT: @@ -776,7 +779,7 @@ def transmit_unsafe(self, message): def error_probability(self): r""" - Returns the error probability of a single symbol transmission of + Return the error probability of a single symbol transmission of ``self``. EXAMPLES:: @@ -790,7 +793,7 @@ def error_probability(self): def probability_of_exactly_t_errors(self, t): r""" - Returns the probability ``self`` has to return + Return the probability ``self`` has to return exactly ``t`` errors. INPUT: @@ -810,7 +813,7 @@ def probability_of_exactly_t_errors(self, t): def probability_of_at_most_t_errors(self, t): r""" - Returns the probability ``self`` has to return + Return the probability ``self`` has to return at most ``t`` errors. INPUT: diff --git a/src/sage/coding/channels_catalog.py b/src/sage/coding/channels_catalog.py index ed3aa0ce6c2..b121fe847d8 100644 --- a/src/sage/coding/channels_catalog.py +++ b/src/sage/coding/channels_catalog.py @@ -9,11 +9,9 @@ - :class:`channel.QarySymmetricChannel <sage.coding.channel.QarySymmetricChannel>` - :class:`channel.StaticErrorRateChannel <sage.coding.channel.StaticErrorRateChannel>` -.. NOTE:: +To import these names into the global namespace, use:: - To import these names into the global namespace, use: - - sage: from sage.coding.channels_catalog import * + sage: from sage.coding.channels_catalog import * """ #***************************************************************************** diff --git a/src/sage/coding/code_bounds.py b/src/sage/coding/code_bounds.py index 430f3a44de1..5b9ebedc06e 100644 --- a/src/sage/coding/code_bounds.py +++ b/src/sage/coding/code_bounds.py @@ -94,11 +94,11 @@ Sage, you can determine the best known estimates for this number in 2 ways: -1. Indirectly, using best_known_linear_code_www(n, k, F), - which connects to the website http://www.codetables.de by Markus Grassl; +1. Indirectly, using ``best_known_linear_code_www(n, k, F)``, + which connects to the website http://www.codetables.de by Markus Grassl; -2. codesize_upper_bound(n,d,q), dimension_upper_bound(n,d,q), - and best_known_linear_code(n, k, F). +2. ``codesize_upper_bound(n,d,q)``, ``dimension_upper_bound(n,d,q)``, + and ``best_known_linear_code(n, k, F)``. The output of :func:`best_known_linear_code`, :func:`best_known_linear_code_www`, or :func:`dimension_upper_bound` would @@ -108,52 +108,52 @@ This module implements: -- codesize_upper_bound(n,d,q), for the best known (as of May, - 2006) upper bound A(n,d) for the size of a code of length n, - minimum distance d over a field of size q. +- ``codesize_upper_bound(n,d,q)``, for the best known (as of May, + 2006) upper bound `A(n,d)` for the size of a code of length `n`, + minimum distance `d` over a field of size `q`. -- dimension_upper_bound(n,d,q), an upper bound +- ``dimension_upper_bound(n,d,q)``, an upper bound `B(n,d)=B_q(n,d)` for the dimension of a linear code of - length n, minimum distance d over a field of size q. + length `n`, minimum distance `d` over a field of size `q`. -- gilbert_lower_bound(n,q,d), a lower bound for number of - elements in the largest code of min distance d in +- ``gilbert_lower_bound(n,q,d)``, a lower bound for number of + elements in the largest code of min distance `d` in `\GF{q}^n`. -- gv_info_rate(n,delta,q), `log_q(GLB)/n`, where GLB is - the Gilbert lower bound and delta = d/n. +- ``gv_info_rate(n,delta,q)``, `log_q(GLB)/n`, where GLB is + the Gilbert lower bound and `\delta = d/n`. -- gv_bound_asymp(delta,q), asymptotic analog of Gilbert lower +- ``gv_bound_asymp(delta,q)``, asymptotic analog of Gilbert lower bound. -- plotkin_upper_bound(n,q,d) +- ``plotkin_upper_bound(n,q,d)`` -- plotkin_bound_asymp(delta,q), asymptotic analog of Plotkin +- ``plotkin_bound_asymp(delta,q)``, asymptotic analog of Plotkin bound. -- griesmer_upper_bound(n,q,d) +- ``griesmer_upper_bound(n,q,d)`` -- elias_upper_bound(n,q,d) +- ``elias_upper_bound(n,q,d)`` -- elias_bound_asymp(delta,q), asymptotic analog of Elias bound. +- ``elias_bound_asymp(delta,q)``, asymptotic analog of Elias bound. -- hamming_upper_bound(n,q,d) +- ``hamming_upper_bound(n,q,d)`` -- hamming_bound_asymp(delta,q), asymptotic analog of Hamming +- ``hamming_bound_asymp(delta,q)``, asymptotic analog of Hamming bound. -- singleton_upper_bound(n,q,d) +- ``singleton_upper_bound(n,q,d)`` -- singleton_bound_asymp(delta,q), asymptotic analog of Singleton +- ``singleton_bound_asymp(delta,q)``, asymptotic analog of Singleton bound. -- mrrw1_bound_asymp(delta,q), "first" asymptotic +- ``mrrw1_bound_asymp(delta,q)``, "first" asymptotic McEliese-Rumsey-Rodemich-Welsh bound for the information rate. - Delsarte (a.k.a. Linear Programming (LP)) upper bounds. -PROBLEM: In this module we shall typically either (a) seek bounds -on k, given n, d, q, (b) seek bounds on R, delta, q (assuming n is +PROBLEM: In this module we shall typically either (a) seek bounds on `k`, given +`n`, `d`, `q`, (b) seek bounds on `R`, `\delta`, `q` (assuming `n` is "infinity"). .. TODO:: @@ -173,14 +173,18 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.libs.gap.libgap import libgap -from sage.rings.all import QQ, RR, ZZ, RDF -from sage.arith.misc import is_prime_power -from sage.arith.all import binomial +from sage.arith.misc import binomial, is_prime_power +from sage.features.gap import GapPackage from sage.misc.functional import sqrt, log +from sage.misc.lazy_import import lazy_import +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.real_double import RDF + from .delsarte_bounds import (delsarte_bound_hamming_space, delsarte_bound_additive_hamming_space) -from sage.features.gap import GapPackage + +lazy_import('sage.libs.gap.libgap', 'libgap') def _check_n_q_d(n, q, d, field_based=True): @@ -230,19 +234,19 @@ def codesize_upper_bound(n, d, q, algorithm=None): This function computes the minimum value of the upper bounds of Singleton, Hamming, Plotkin, and Elias. - If algorithm="gap" then this returns the best known upper - bound `A(n,d)=A_q(n,d)` for the size of a code of length n, - minimum distance d over a field of size q. The function first - checks for trivial cases (like d=1 or n=d), and if the value + If ``algorithm="gap"``, then this returns the best known upper + bound `A(n,d)=A_q(n,d)` for the size of a code of length `n`, + minimum distance `d` over a field of size `q`. The function first + checks for trivial cases (like `d=1` or `n=d`), and if the value is in the built-in table. Then it calculates the minimum value of the upper bound using the algorithms of Singleton, Hamming, Johnson, Plotkin and Elias. If the code is binary, `A(n, 2\ell-1) = A(n+1,2\ell)`, so the function takes the minimum of the values obtained from all algorithms for the parameters `(n, 2\ell-1)` and `(n+1, 2\ell)`. This - wraps GUAVA's (i.e. GAP's package Guava) UpperBound( n, d, q ). + wraps GUAVA's (i.e. GAP's package Guava) ``UpperBound(n, d, q)``. - If algorithm="LP" then this returns the Delsarte (a.k.a. Linear + If ``algorithm="LP"``, then this returns the Delsarte (a.k.a. Linear Programming) upper bound. EXAMPLES:: @@ -251,11 +255,11 @@ def codesize_upper_bound(n, d, q, algorithm=None): 93 sage: codes.bounds.codesize_upper_bound(24,8,2,algorithm="LP") 4096 - sage: codes.bounds.codesize_upper_bound(10,3,2,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.codesize_upper_bound(10,3,2,algorithm="gap") # optional - gap_package_guava 85 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm=None) 123361 - sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="gap") # optional - gap_package_guava 123361 sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="LP") 109226 @@ -266,7 +270,7 @@ def codesize_upper_bound(n, d, q, algorithm=None): sage: codes.bounds.codesize_upper_bound(19,10,2) 20 - sage: codes.bounds.codesize_upper_bound(19,10,2,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.codesize_upper_bound(19,10,2,algorithm="gap") # optional - gap_package_guava 20 Meaningless parameters are rejected:: @@ -296,10 +300,11 @@ def dimension_upper_bound(n, d, q, algorithm=None): Return an upper bound for the dimension of a linear code. Return an upper bound `B(n,d) = B_q(n,d)` for the - dimension of a linear code of length n, minimum distance d over a - field of size q. + dimension of a linear code of length `n`, minimum distance `d` over a + field of size `q`. - Parameter "algorithm" has the same meaning as in :func:`codesize_upper_bound` + Parameter ``algorithm`` has the same meaning as in + :func:`codesize_upper_bound` EXAMPLES:: @@ -374,7 +379,7 @@ def plotkin_upper_bound(n,q,d, algorithm=None): sage: codes.bounds.plotkin_upper_bound(10,2,3) 192 - sage: codes.bounds.plotkin_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.plotkin_upper_bound(10,2,3,algorithm="gap") # optional - gap_package_guava 192 """ _check_n_q_d(n, q, d, field_based=False) @@ -392,6 +397,7 @@ def plotkin_upper_bound(n,q,d, algorithm=None): return int(d/( d - t*n)) elif d < t*n + 1: fact = (d-1) / t + from sage.rings.real_mpfr import RR if RR(fact)==RR(int(fact)): fact = int(fact) + 1 return int(d/( d - t * fact)) * q**(n - fact) @@ -424,7 +430,7 @@ def griesmer_upper_bound(n,q,d,algorithm=None): sage: codes.bounds.griesmer_upper_bound(10,2,3) 128 - sage: codes.bounds.griesmer_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.griesmer_upper_bound(10,2,3,algorithm="gap") # optional - gap_package_guava 128 TESTS:: @@ -459,13 +465,13 @@ def elias_upper_bound(n,q,d,algorithm=None): Return the Elias upper bound for number of elements in the largest code of minimum distance `d` in `\GF{q}^n`, cf. [HP2003]_. - If the method is "gap", it wraps GAP's ``UpperBoundElias``. + If ``algorithm="gap"``, it wraps GAP's ``UpperBoundElias``. EXAMPLES:: sage: codes.bounds.elias_upper_bound(10,2,3) 232 - sage: codes.bounds.elias_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.elias_upper_bound(10,2,3,algorithm="gap") # optional - gap_package_guava 232 """ _check_n_q_d(n, q, d, field_based=False) @@ -494,8 +500,8 @@ def hamming_upper_bound(n,q,d): Return the Hamming upper bound. Return the Hamming upper bound for number of elements in the - largest code of length n and minimum distance d over alphabet - of size q. + largest code of length `n` and minimum distance `d` over alphabet + of size `q`. The Hamming bound (also known as the sphere packing bound) returns an upper bound on the size of a code of length `n`, minimum distance @@ -513,7 +519,7 @@ def hamming_upper_bound(n,q,d): where `M` is the maximum number of codewords and `V(n,e)` is - equal to the contents of a ball of radius e. This bound is useful + equal to the contents of a ball of radius `e`. This bound is useful for small values of `d`. Codes for which equality holds are called perfect. See e.g. [HP2003]_. @@ -531,7 +537,7 @@ def singleton_upper_bound(n, q, d): Return the Singleton upper bound. Return the Singleton upper bound for number of elements in a - largest code of minimum distance d in `\GF{q}^n`. + largest code of minimum distance `d` in `\GF{q}^n`. This bound is based on the shortening of codes. By shortening an `(n, M, d)` code `d-1` times, an `(n-d+1,M,1)` code @@ -577,9 +583,9 @@ def entropy(x, q=2): INPUT: - - ``x`` - real number in the interval `[0, 1]`. + - ``x`` -- real number in the interval `[0, 1]`. - - ``q`` - (default: 2) integer greater than 1. This is the base of the + - ``q`` -- (default: 2) integer greater than 1. This is the base of the logarithm. EXAMPLES:: @@ -618,7 +624,7 @@ def entropy(x, q=2): def entropy_inverse(x, q=2): """ - Find the inverse of the ``q``-ary entropy function at the point ``x``. + Find the inverse of the `q`-ary entropy function at the point ``x``. INPUT: @@ -653,7 +659,7 @@ def entropy_inverse(x, q=2): if q < 2: # Here we check that q is actually at least 2 raise ValueError("The value q must be an integer greater than 1") - eps = 4.5e-16 # find_root has about this as the default xtol + eps = 4.5e-16 # find_root has about this as the default xtol ymax = 1 - 1/q if x <= eps: return 0 diff --git a/src/sage/coding/code_constructions.py b/src/sage/coding/code_constructions.py index ec50c75dd9c..2cd68c11a28 100644 --- a/src/sage/coding/code_constructions.py +++ b/src/sage/coding/code_constructions.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Linear code constructors that do not preserve the structural information @@ -40,20 +41,17 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.misc.misc_c import prod -from sage.arith.all import quadratic_residues, gcd - -from sage.structure.sequence import Sequence, Sequence_generic - -from sage.matrix.matrix_space import MatrixSpace +from sage.arith.misc import gcd, quadratic_residues from sage.matrix.constructor import matrix +from sage.matrix.matrix_space import MatrixSpace from sage.matrix.special import random_matrix - +from sage.misc.misc_c import prod from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.rings.finite_rings.integer_mod import Mod from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.structure.sequence import Sequence, Sequence_generic from .linear_code import LinearCode @@ -219,38 +217,40 @@ def _lift2smallest_field(a): def permutation_action(g, v): r""" - Returns permutation of rows g\*v. Works on lists, matrices, + Returns permutation of rows `g * v`. + + Works on lists, matrices, sequences and vectors (by permuting coordinates). The code requires - switching from i to i+1 (and back again) since the SymmetricGroup - is, by convention, the symmetric group on the "letters" 1, 2, ..., - n (not 0, 1, ..., n-1). + switching from `i` to `i+1` (and back again) since the :class:`SymmetricGroup` + is, by convention, the symmetric group on the "letters" `1`, `2`, ..., + `n` (not `0`, `1`, ..., `n-1`). EXAMPLES:: sage: V = VectorSpace(GF(3),5) sage: v = V([0,1,2,0,1]) - sage: G = SymmetricGroup(5) - sage: g = G([(1,2,3)]) - sage: permutation_action(g,v) + sage: G = SymmetricGroup(5) # optional - sage.groups + sage: g = G([(1,2,3)]) # optional - sage.groups + sage: permutation_action(g,v) # optional - sage.groups (1, 2, 0, 0, 1) - sage: g = G([()]) - sage: permutation_action(g,v) + sage: g = G([()]) # optional - sage.groups + sage: permutation_action(g,v) # optional - sage.groups (0, 1, 2, 0, 1) - sage: g = G([(1,2,3,4,5)]) - sage: permutation_action(g,v) + sage: g = G([(1,2,3,4,5)]) # optional - sage.groups + sage: permutation_action(g,v) # optional - sage.groups (1, 2, 0, 1, 0) sage: L = Sequence([1,2,3,4,5]) - sage: permutation_action(g,L) + sage: permutation_action(g,L) # optional - sage.groups [2, 3, 4, 5, 1] sage: MS = MatrixSpace(GF(3),3,7) sage: A = MS([[1,0,0,0,1,1,0],[0,1,0,1,0,1,0],[0,0,0,0,0,0,1]]) - sage: S5 = SymmetricGroup(5) - sage: g = S5([(1,2,3)]) + sage: S5 = SymmetricGroup(5) # optional - sage.groups + sage: g = S5([(1,2,3)]) # optional - sage.groups sage: A [1 0 0 0 1 1 0] [0 1 0 1 0 1 0] [0 0 0 0 0 0 1] - sage: permutation_action(g,A) + sage: permutation_action(g,A) # optional - sage.groups [0 1 0 1 0 1 0] [0 0 0 0 0 0 1] [1 0 0 0 1 1 0] @@ -258,16 +258,16 @@ def permutation_action(g, v): It also works on lists and is a "left action":: sage: v = [0,1,2,0,1] - sage: G = SymmetricGroup(5) - sage: g = G([(1,2,3)]) - sage: gv = permutation_action(g,v); gv + sage: G = SymmetricGroup(5) # optional - sage.groups + sage: g = G([(1,2,3)]) # optional - sage.groups + sage: gv = permutation_action(g,v); gv # optional - sage.groups [1, 2, 0, 0, 1] - sage: permutation_action(g,v) == g(v) + sage: permutation_action(g,v) == g(v) # optional - sage.groups True - sage: h = G([(3,4)]) - sage: gv = permutation_action(g,v) - sage: hgv = permutation_action(h,gv) - sage: hgv == permutation_action(h*g,v) + sage: h = G([(3,4)]) # optional - sage.groups + sage: gv = permutation_action(g,v) # optional - sage.groups + sage: hgv = permutation_action(h,gv) # optional - sage.groups + sage: hgv == permutation_action(h*g,v) # optional - sage.groups True AUTHORS: @@ -370,8 +370,8 @@ def DuadicCodeEvenPair(F,S1,S2): x = P2.gen() gg1 = P2([_lift2smallest_field(c)[0] for c in g1.coefficients(sparse=False)]) gg2 = P2([_lift2smallest_field(c)[0] for c in g2.coefficients(sparse=False)]) - C1 = CyclicCode(length = n, generator_pol = gg1) - C2 = CyclicCode(length = n, generator_pol = gg2) + C1 = CyclicCode(length=n, generator_pol=gg1) + C2 = CyclicCode(length=n, generator_pol=gg2) return C1,C2 def DuadicCodeOddPair(F,S1,S2): @@ -425,8 +425,8 @@ def DuadicCodeOddPair(F,S1,S2): gg2 = P2(coeffs2) gg1 = gcd(gg1, x**n - 1) gg2 = gcd(gg2, x**n - 1) - C1 = CyclicCode(length = n, generator_pol = gg1) - C2 = CyclicCode(length = n, generator_pol = gg2) + C1 = CyclicCode(length=n, generator_pol=gg1) + C2 = CyclicCode(length=n, generator_pol=gg2) return C1,C2 def ExtendedQuadraticResidueCode(n,F): @@ -439,28 +439,28 @@ def ExtendedQuadraticResidueCode(n,F): INPUT: - - ``n`` - an odd prime + - ``n`` -- an odd prime - - ``F`` - a finite prime field F whose order must be a - quadratic residue modulo n. + - ``F`` -- a finite prime field whose order must be a + quadratic residue modulo `n`. OUTPUT: Returns an extended quadratic residue code. EXAMPLES:: - sage: C1 = codes.QuadraticResidueCode(7,GF(2)) + sage: C1 = codes.QuadraticResidueCode(7, GF(2)) sage: C2 = C1.extended_code() - sage: C3 = codes.ExtendedQuadraticResidueCode(7,GF(2)); C3 + sage: C3 = codes.ExtendedQuadraticResidueCode(7, GF(2)); C3 Extension of [7, 4] Cyclic Code over GF(2) sage: C2 == C3 True - sage: C = codes.ExtendedQuadraticResidueCode(17,GF(2)) + sage: C = codes.ExtendedQuadraticResidueCode(17, GF(2)) sage: C Extension of [17, 9] Cyclic Code over GF(2) - sage: C3 = codes.QuadraticResidueCodeOddPair(7,GF(2))[0] + sage: C3 = codes.QuadraticResidueCodeOddPair(7, GF(2))[0] sage: C3x = C3.extended_code() - sage: C4 = codes.ExtendedQuadraticResidueCode(7,GF(2)) + sage: C4 = codes.ExtendedQuadraticResidueCode(7, GF(2)) sage: C3x == C4 True @@ -499,37 +499,37 @@ def QuadraticResidueCode(n,F): A quadratic residue code (or QR code) is a cyclic code whose generator polynomial is the product of the polynomials `x-\alpha^i` (`\alpha` is a primitive - `n^{th}` root of unity; `i` ranges over the set of + `n`'th root of unity; `i` ranges over the set of quadratic residues modulo `n`). - See QuadraticResidueCodeEvenPair and QuadraticResidueCodeOddPair - for a more general construction. + See :class:`QuadraticResidueCodeEvenPair` and + :class:`QuadraticResidueCodeOddPair` for a more general construction. INPUT: - - ``n`` - an odd prime + - ``n`` -- an odd prime - - ``F`` - a finite prime field F whose order must be a - quadratic residue modulo n. + - ``F`` -- a finite prime field whose order must be a + quadratic residue modulo `n`. OUTPUT: Returns a quadratic residue code. EXAMPLES:: - sage: C = codes.QuadraticResidueCode(7,GF(2)) + sage: C = codes.QuadraticResidueCode(7, GF(2)) sage: C [7, 4] Cyclic Code over GF(2) - sage: C = codes.QuadraticResidueCode(17,GF(2)) + sage: C = codes.QuadraticResidueCode(17, GF(2)) sage: C [17, 9] Cyclic Code over GF(2) - sage: C1 = codes.QuadraticResidueCodeOddPair(7,GF(2))[0] - sage: C2 = codes.QuadraticResidueCode(7,GF(2)) + sage: C1 = codes.QuadraticResidueCodeOddPair(7, GF(2))[0] + sage: C2 = codes.QuadraticResidueCode(7, GF(2)) sage: C1 == C2 True - sage: C1 = codes.QuadraticResidueCodeOddPair(17,GF(2))[0] - sage: C2 = codes.QuadraticResidueCode(17,GF(2)) + sage: C1 = codes.QuadraticResidueCodeOddPair(17, GF(2))[0] + sage: C2 = codes.QuadraticResidueCode(17, GF(2)) sage: C1 == C2 True @@ -540,16 +540,16 @@ def QuadraticResidueCode(n,F): return QuadraticResidueCodeOddPair(n,F)[0] def QuadraticResidueCodeEvenPair(n,F): - """ + r""" Quadratic residue codes of a given odd prime length and base ring either don't exist at all or occur as 4-tuples - a pair of "odd-like" codes and a pair of "even-like" codes. If `n > 2` is prime - then (Theorem 6.6.2 in [HP2003]_) a QR code exists over `GF(q)` iff q is a + then (Theorem 6.6.2 in [HP2003]_) a QR code exists over `\GF{q}` iff q is a quadratic residue mod `n`. They are constructed as "even-like" duadic codes associated the - splitting (Q,N) mod n, where Q is the set of non-zero quadratic - residues and N is the non-residues. + splitting `(Q,N)` mod `n`, where `Q` is the set of non-zero quadratic + residues and `N` is the non-residues. EXAMPLES:: @@ -559,16 +559,16 @@ def QuadraticResidueCodeEvenPair(n,F): sage: codes.QuadraticResidueCodeEvenPair(17, GF(2)) ([17, 8] Cyclic Code over GF(2), [17, 8] Cyclic Code over GF(2)) - sage: codes.QuadraticResidueCodeEvenPair(13,GF(9,"z")) # known bug (#25896) + sage: codes.QuadraticResidueCodeEvenPair(13, GF(9,"z")) # known bug (#25896) ([13, 6] Cyclic Code over GF(9), [13, 6] Cyclic Code over GF(9)) - sage: C1,C2 = codes.QuadraticResidueCodeEvenPair(7,GF(2)) + sage: C1,C2 = codes.QuadraticResidueCodeEvenPair(7, GF(2)) sage: C1.is_self_orthogonal() True sage: C2.is_self_orthogonal() True - sage: C3 = codes.QuadraticResidueCodeOddPair(17,GF(2))[0] - sage: C4 = codes.QuadraticResidueCodeEvenPair(17,GF(2))[1] + sage: C3 = codes.QuadraticResidueCodeOddPair(17, GF(2))[0] + sage: C4 = codes.QuadraticResidueCodeEvenPair(17, GF(2))[1] sage: C3.systematic_generator_matrix() == C4.dual_code().systematic_generator_matrix() True @@ -580,11 +580,11 @@ def QuadraticResidueCodeEvenPair(n,F): Traceback (most recent call last): ... ValueError: the argument F must be a finite field - sage: codes.QuadraticResidueCodeEvenPair(14,GF(2)) + sage: codes.QuadraticResidueCodeEvenPair(14, GF(2)) Traceback (most recent call last): ... ValueError: the argument n must be an odd prime - sage: codes.QuadraticResidueCodeEvenPair(5,GF(2)) + sage: codes.QuadraticResidueCodeEvenPair(5, GF(2)) Traceback (most recent call last): ... ValueError: the order of the finite field must be a quadratic residue modulo n @@ -606,16 +606,16 @@ def QuadraticResidueCodeEvenPair(n,F): def QuadraticResidueCodeOddPair(n,F): - """ + r""" Quadratic residue codes of a given odd prime length and base ring either don't exist at all or occur as 4-tuples - a pair of "odd-like" codes and a pair of "even-like" codes. If n 2 is prime - then (Theorem 6.6.2 in [HP2003]_) a QR code exists over GF(q) iff q is a - quadratic residue mod n. + then (Theorem 6.6.2 in [HP2003]_) a QR code exists over `\GF{q} iff `q` is a + quadratic residue mod `n`. They are constructed as "odd-like" duadic codes associated the - splitting (Q,N) mod n, where Q is the set of non-zero quadratic - residues and N is the non-residues. + splitting `(Q,N)` mod `n`, where `Q` is the set of non-zero quadratic + residues and `N` is the non-residues. EXAMPLES:: @@ -644,7 +644,7 @@ def QuadraticResidueCodeOddPair(n,F): TESTS:: - sage: codes.QuadraticResidueCodeOddPair(9,GF(2)) + sage: codes.QuadraticResidueCodeOddPair(9, GF(2)) Traceback (most recent call last): ... ValueError: the argument n must be an odd prime @@ -702,23 +702,23 @@ def ToricCode(P,F): .. MATH:: - \mathrm{eval_T} : V \rightarrow F^n, + \operatorname{eval}_T : V \rightarrow F^n, where `x^e` is the multi-index notation (`x=(x_1,...,x_d)`, `e=(e_1,...,e_d)`, and `x^e = x_1^{e_1}...x_d^{e_d}`), where - `eval_T (f(x)) = (f(t_1),...,f(t_n))`, and where + `\operatorname{eval}_T (f(x)) = (f(t_1),...,f(t_n))`, and where `T=\{t_1,...,t_n\}`. This function returns the toric codes discussed in [Joy2004]_. INPUT: - - ``P`` - all the integer lattice points in a polytope + - ``P`` -- all the integer lattice points in a polytope defining the toric variety. - - ``F`` - a finite field. + - ``F`` -- a finite field. OUTPUT: Returns toric code with length n = , dimension k over field @@ -726,26 +726,27 @@ def ToricCode(P,F): EXAMPLES:: - sage: C = codes.ToricCode([[0,0],[1,0],[2,0],[0,1],[1,1]],GF(7)) + sage: C = codes.ToricCode([[0,0],[1,0],[2,0],[0,1],[1,1]], GF(7)) sage: C [36, 5] linear code over GF(7) sage: C.minimum_distance() 24 - sage: C.minimum_distance(algorithm="guava") # optional - gap_packages (Guava package) - ... - 24 - sage: C = codes.ToricCode([[-2,-2],[-1,-2],[-1,-1],[-1,0],[0,-1],[0,0],[0,1],[1,-1],[1,0]],GF(5)) + sage: C.minimum_distance(algorithm="guava") # optional - gap_package_guava + ...24 + sage: C = codes.ToricCode([[-2,-2],[-1,-2],[-1,-1],[-1,0], + ....: [0,-1],[0,0],[0,1],[1,-1],[1,0]], GF(5)) sage: C [16, 9] linear code over GF(5) sage: C.minimum_distance() 6 - sage: C.minimum_distance(algorithm="guava") # optional - gap_packages (Guava package) + sage: C.minimum_distance(algorithm="guava") # optional - gap_package_guava 6 - sage: C = codes.ToricCode([ [0,0],[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[3,1],[3,2],[4,1]],GF(8,"a")) + sage: C = codes.ToricCode([[0,0],[1,1],[1,2],[1,3],[1,4],[2,1], + ....: [2,2],[2,3],[3,1],[3,2],[4,1]], GF(8,"a")) sage: C [49, 11] linear code over GF(8) - This is in fact a [49,11,28] code over GF(8). If you type next + This is in fact a [49,11,28] code over `\GF{8}`. If you type next ``C.minimum_distance()`` and wait overnight (!), you should get 28. @@ -753,7 +754,7 @@ def ToricCode(P,F): - David Joyner (07-2006) """ - from sage.combinat.all import Tuples + from sage.combinat.tuple import Tuples mset = [x for x in F if x != 0] d = len(P[0]) pts = Tuples(mset, d).list() @@ -787,7 +788,7 @@ def WalshCode(m): [1, 0, 0, 0, 7, 0, 0, 0, 0] sage: C.minimum_distance() 4 - sage: C.minimum_distance(algorithm='gap') # check d=2^(m-1) + sage: C.minimum_distance(algorithm='gap') # check d=2^(m-1) 4 REFERENCES: diff --git a/src/sage/algebras/quatalg/__init__.py b/src/sage/coding/codecan/all.py similarity index 100% rename from src/sage/algebras/quatalg/__init__.py rename to src/sage/coding/codecan/all.py diff --git a/src/sage/coding/codecan/autgroup_can_label.pyx b/src/sage/coding/codecan/autgroup_can_label.pyx index de5db985e0b..29efd21af56 100644 --- a/src/sage/coding/codecan/autgroup_can_label.pyx +++ b/src/sage/coding/codecan/autgroup_can_label.pyx @@ -76,7 +76,7 @@ columns do share the same coloring:: ((1,), (2,), (3, 5, 4), - (6, 19, 16, 9, 21, 10, 8, 15, 14, 11, 20, 13, 12, 7, 17, 18)) + (6, 19, 16, 21, 9, 10, 15, 8, 20, 11, 14, 13, 7, 12, 18, 17)) We can also restrict the group action to linear isometries:: @@ -124,8 +124,8 @@ def _cyclic_shift(n, p): sage: p.action(t) [0, 2, 7, 3, 1, 5, 6, 4, 8, 9] """ - x = list(xrange(1, n + 1)) - for i in xrange(1, len(p)): + x = list(range(1, n + 1)) + for i in range(1, len(p)): x[p[i - 1]] = p[i] + 1 x[p[len(p) - 1]] = p[0] + 1 return Permutation(x) @@ -137,21 +137,21 @@ class LinearCodeAutGroupCanLabel: There are several notions of equivalence for linear codes: Let `C`, `D` be linear codes of length `n` and dimension `k`. - `C` and `D` are said to be + The codes `C` and `D` are said to be - - permutational equivalent, if there is some permutation `\pi \in S_n` - such that `(c_{\pi(0)}, \ldots, c_{\pi(n-1)}) \in D` for all `c \in C`. + - permutational equivalent, if there is some permutation `\pi \in S_n` + such that `(c_{\pi(0)}, \ldots, c_{\pi(n-1)}) \in D` for all `c \in C`. - - linear equivalent, if there is some permutation `\pi \in S_n` and a - vector `\phi \in {\GF{q}^*}^n` of units of length `n` such that - `(c_{\pi(0)} \phi_0^{-1}, \ldots, c_{\pi(n-1)} \phi_{n-1}^{-1}) \in D` - for all `c \in C`. + - linear equivalent, if there is some permutation `\pi \in S_n` and a + vector `\phi \in {\GF{q}^*}^n` of units of length `n` such that + `(c_{\pi(0)} \phi_0^{-1}, \ldots, c_{\pi(n-1)} \phi_{n-1}^{-1}) \in D` + for all `c \in C`. - - semilinear equivalent, if there is some permutation `\pi \in S_n`, a - vector `\phi` of units of length `n` and a field automorphism `\alpha` - such that - `(\alpha(c_{\pi(0)}) \phi_0^{-1}, \ldots, \alpha( c_{\pi(n-1)}) \phi_{n-1}^{-1} ) \in D` - for all `c \in C`. + - semilinear equivalent, if there is some permutation `\pi \in S_n`, a + vector `\phi` of units of length `n` and a field automorphism `\alpha` + such that + `(\alpha(c_{\pi(0)}) \phi_0^{-1}, \ldots, \alpha( c_{\pi(n-1)}) \phi_{n-1}^{-1} ) \in D` + for all `c \in C`. These are group actions. This class provides an algorithm that will compute a unique representative `D` in the orbit of the given linear code `C`. @@ -229,17 +229,17 @@ class LinearCodeAutGroupCanLabel: S = SemimonomialTransformationGroup(F, mat.ncols()) if P is None: - P = [list(xrange(mat.ncols()))] + P = [list(range(mat.ncols()))] pos2P = [-1] * mat.ncols() - for i in xrange(len(P)): + for i in range(len(P)): P[i].sort(reverse=True) for x in P[i]: pos2P[x] = i col_list = mat.columns() - nz = [i for i in xrange(mat.ncols()) if not col_list[i].is_zero()] - z = [(pos2P[i], i) for i in xrange(mat.ncols()) if col_list[i].is_zero()] + nz = [i for i in range(mat.ncols()) if not col_list[i].is_zero()] + z = [(pos2P[i], i) for i in range(mat.ncols()) if col_list[i].is_zero()] z.sort() z = [i for (p, i) in z] @@ -259,7 +259,7 @@ class LinearCodeAutGroupCanLabel: col2pos = [] col2P = [] for c in col_set: - X = [(pos2P[y], y) for y in xrange(mat.ncols()) if col_list[y] == c ] + X = [(pos2P[y], y) for y in range(mat.ncols()) if col_list[y] == c ] X.sort() col2pos.append([b for (a, b) in X ]) col2P.append([a for (a, b) in X ]) @@ -272,7 +272,7 @@ class LinearCodeAutGroupCanLabel: P_refined = [] p = [0] act_qty = col2P[0] - for i in xrange(1, len(col_set)): + for i in range(1, len(col_set)): if act_qty == col2P[i]: p.append(i) else: @@ -357,7 +357,7 @@ class LinearCodeAutGroupCanLabel: perm = [-1] * mat.ncols() mult = [F.one()] * mat.ncols() - for i in xrange(len(can_col_set)): + for i in range(len(can_col_set)): img = can_transp.get_perm()(i + 1) for j in col2pos[img - 1]: pos = P[ pos2P[j] ].pop() @@ -378,7 +378,7 @@ class LinearCodeAutGroupCanLabel: self._full_autom_order *= a - for i in xrange(len(col2P)): + for i in range(len(col2P)): if len(col2P[i]) > 1: A, a = self._compute_trivial_automs(normalization, normalization_inverse, col2pos[i], col2P[i]) @@ -508,11 +508,11 @@ class LinearCodeAutGroupCanLabel: n = S.degree() A = [] for g in gens: - perm = list(xrange(1, n + 1)) + perm = list(range(1, n + 1)) mult = [S.base_ring().one()] * n short_perm = g.get_perm() short_mult = g.get_v() - for i in xrange(len(col2pos)): + for i in range(len(col2pos)): c = col2pos[i] img_iter = iter(col2pos[short_perm(i + 1) - 1]) for x in c: diff --git a/src/sage/coding/codecan/codecan.pyx b/src/sage/coding/codecan/codecan.pyx index 5320a49b179..b0709155b57 100644 --- a/src/sage/coding/codecan/codecan.pyx +++ b/src/sage/coding/codecan/codecan.pyx @@ -96,8 +96,6 @@ from copy import copy from cysignals.memory cimport check_allocarray, sig_free from sage.rings.integer cimport Integer -from sage.matrix.matrix cimport Matrix -from sage.groups.perm_gps.permgroup import PermutationGroup cimport sage.groups.perm_gps.partn_ref2.refinement_generic from sage.modules.finite_submodule_iter cimport FiniteFieldsubspace_projPoint_iterator as FFSS_projPoint from sage.groups.perm_gps.partn_ref.data_structures cimport * @@ -112,10 +110,10 @@ cdef class InnerGroup: Those stabilizers can be stored as triples: - - ``rank`` - an integer in `\{0, \ldots, k\}` - - ``row_partition`` - a partition of `\{0, \ldots, k-1\}` with - discrete cells for all integers `i \geq rank`. - - ``frob_pow`` an integer in `\{0, \ldots, r-1\}` if `q = p^r` + - ``rank`` -- an integer in `\{0, \ldots, k\}` + - ``row_partition`` -- a partition of `\{0, \ldots, k-1\}` with + discrete cells for all integers `i` `\geq` ``rank``. + - ``frob_pow`` -- an integer `s` in `\{0, \ldots, r-1\}` if `q = p^r` The group `G_{\Pi^{(I)}(x)}` contains all elements `(A, \varphi, \alpha) \in G`, where @@ -128,8 +126,8 @@ cdef class InnerGroup: - The support of the columns given by `i \in I` intersect exactly one cell of the partition. The entry `\varphi_i` is equal to the entries of the corresponding diagonal entry of `A`. - - `\alpha` is a power of `\tau^{frob_pow}`, where `\tau` denotes the - Frobenius automorphism of the finite field `\GF{q}`. + - `\alpha` is a power of `\tau^s`, where `\tau` denotes the + Frobenius automorphism of the finite field `\GF{q}` and `s` = ``frob_pow``. See [Feu2009]_ for more details. """ @@ -145,8 +143,8 @@ cdef class InnerGroup: * "semilinear" -- full group * "linear" -- no field automorphisms, i.e. `G = (GL(k,q) \times \GF{q}^n )` * "permutational -- no field automorphisms and no column multiplications - i.e. `G = GL(k,q)` + - ``transporter`` (optional) -- set to an element of the group :class:`sage.groups.semimonomial_transformations.semimonomial_transformation_group.SemimonomialTransformationGroup` if you would like to modify this element simultaneously @@ -757,7 +755,6 @@ cdef class PartitionRefinementLinearCode(PartitionRefinement_generic): This graph will be later used in the refinement procedures. """ - from sage.matrix.constructor import matrix cdef FFSS_projPoint iter = FFSS_projPoint(self._matrix) cdef mp_bitcnt_t i,j diff --git a/src/sage/coding/codes_catalog.py b/src/sage/coding/codes_catalog.py index 9535d364ce7..96021d5fdd3 100644 --- a/src/sage/coding/codes_catalog.py +++ b/src/sage/coding/codes_catalog.py @@ -57,11 +57,9 @@ :meth:`~sage.coding.extended_code.ExtendedCode` @ Extended codes :meth:`~sage.coding.punctured_code.PuncturedCode` @ Puncturedcodes -.. NOTE:: +To import these names into the global namespace, use:: - To import these names into the global namespace, use: - - sage: from sage.coding.codes_catalog import * + sage: from sage.coding.codes_catalog import * """ #***************************************************************************** diff --git a/src/sage/coding/cyclic_code.py b/src/sage/coding/cyclic_code.py index 93ce9730f49..342b40d45c9 100644 --- a/src/sage/coding/cyclic_code.py +++ b/src/sage/coding/cyclic_code.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Cyclic code @@ -41,16 +42,16 @@ from copy import copy from sage.rings.integer import Integer from sage.categories.homset import Hom -from sage.arith.all import gcd +from sage.arith.misc import gcd from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method -from sage.rings.all import Zmod +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as Zmod def find_generator_polynomial(code, check=True): r""" - Returns a possible generator polynomial for ``code``. + Return a possible generator polynomial for ``code``. If the code is cyclic, the generator polynomial is the gcd of all the polynomial forms of the codewords. Conversely, if this gcd exactly @@ -95,7 +96,7 @@ def find_generator_polynomial(code, check=True): def _to_complete_list(poly, length): r""" - Returns the vector of length exactly ``length`` corresponding to the + Return the vector of length exactly ``length`` corresponding to the coefficients of the provided polynomial. If needed, zeros are added. INPUT: @@ -122,7 +123,7 @@ def _to_complete_list(poly, length): def bch_bound(n, D, arithmetic=False): r""" - Returns the BCH bound obtained for a cyclic code of length ``n`` and + Return the BCH bound obtained for a cyclic code of length ``n`` and defining set ``D``. Consider a cyclic code `C`, with defining set `D`, length `n`, and minimum @@ -212,7 +213,7 @@ class CyclicCode(AbstractLinearCode): r""" Representation of a cyclic code. - We propose three different ways to create a new CyclicCode, either by + We propose three different ways to create a new :class:`CyclicCode`, either by providing: - the generator polynomial and the length (1) @@ -224,7 +225,7 @@ class CyclicCode(AbstractLinearCode): cyclic codes such that its length `n` and field order `q` are coprimes. Depending on which behaviour you want, you need to specify the names of the - arguments to CyclicCode. See EXAMPLES section below for details. + arguments to :class:`CyclicCode`. See EXAMPLES section below for details. INPUT: @@ -256,13 +257,13 @@ class CyclicCode(AbstractLinearCode): EXAMPLES: - We can construct a CyclicCode object using three different methods. + We can construct a :class:`CyclicCode` object using three different methods. First (1), we provide a generator polynomial and a code length:: sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: C [7, 4] Cyclic Code over GF(2) @@ -280,7 +281,7 @@ class CyclicCode(AbstractLinearCode): sage: F = GF(16, 'a') sage: n = 15 - sage: Cc = codes.CyclicCode(length = n, field = F, D = [1,2]) + sage: Cc = codes.CyclicCode(length=n, field=F, D = [1,2]) sage: Cc [15, 13] Cyclic Code over GF(16) """ @@ -299,7 +300,7 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, sage: F.<x> = GF(2)[] sage: n = 2 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) Traceback (most recent call last): ... ValueError: Only cyclic codes whose length and field order are coprimes are implemented. @@ -465,7 +466,7 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, def __contains__(self, word): r""" - Returns ``True`` if ``word`` belongs to ``self``, ``False`` otherwise. + Return ``True`` if ``word`` belongs to ``self``, ``False`` otherwise. INPUT: @@ -513,7 +514,7 @@ def __eq__(self, other): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -530,7 +531,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -547,7 +548,7 @@ def _latex_(self): def generator_polynomial(self): r""" - Returns the generator polynomial of ``self``. + Return the generator polynomial of ``self``. EXAMPLES:: @@ -562,7 +563,7 @@ def generator_polynomial(self): def field_embedding(self): r""" - Returns the base field embedding into the splitting field. + Return the base field embedding into the splitting field. EXAMPLES:: @@ -582,7 +583,7 @@ def field_embedding(self): def defining_set(self, primitive_root=None): r""" - Returns the set of exponents of the roots of ``self``'s generator + Return the set of exponents of the roots of ``self``'s generator polynomial over the extension field. Of course, it depends on the choice of the primitive root of the splitting field. @@ -674,7 +675,7 @@ def defining_set(self, primitive_root=None): def primitive_root(self): r""" - Returns the primitive root of the splitting field that is used + Return the primitive root of the splitting field that is used to build the defining set of the code. If it has not been specified by the user, it is set by default with the @@ -692,7 +693,8 @@ def primitive_root(self): sage: F = GF(16, 'a') sage: n = 15 sage: a = F.gen() - sage: Cc = codes.CyclicCode(length = n, field = F, D = [1,2], primitive_root = a^2 + 1) + sage: Cc = codes.CyclicCode(length=n, field=F, D=[1,2], + ....: primitive_root=a^2 + 1) sage: Cc.primitive_root() a^2 + 1 """ @@ -705,7 +707,7 @@ def primitive_root(self): @cached_method def check_polynomial(self): r""" - Returns the check polynomial of ``self``. + Return the check polynomial of ``self``. Let `C` be a cyclic code of length `n` and `g` its generator polynomial. The following: `h = \frac{x^n - 1}{g(x)}` is called `C`'s @@ -716,7 +718,7 @@ def check_polynomial(self): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: h = C.check_polynomial() sage: h == (x**n - 1)/C.generator_polynomial() True @@ -729,7 +731,7 @@ def check_polynomial(self): @cached_method def parity_check_matrix(self): r""" - Returns the parity check matrix of ``self``. + Return the parity check matrix of ``self``. The parity check matrix of a linear code `C` corresponds to the generator matrix of the dual code of `C`. @@ -739,7 +741,7 @@ def parity_check_matrix(self): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: C.parity_check_matrix() [1 0 1 1 1 0 0] [0 1 0 1 1 1 0] @@ -755,7 +757,7 @@ def parity_check_matrix(self): def bch_bound(self, arithmetic=False): r""" - Returns the BCH bound of ``self`` which is a bound on ``self`` + Return the BCH bound of ``self`` which is a bound on ``self`` minimum distance. See :meth:`sage.coding.cyclic_code.bch_bound` for details. @@ -776,14 +778,14 @@ def bch_bound(self, arithmetic=False): sage: F = GF(16, 'a') sage: n = 15 sage: D = [14,1,2,11,12] - sage: C = codes.CyclicCode(field = F, length = n, D = D) + sage: C = codes.CyclicCode(field=F, length=n, D = D) sage: C.bch_bound() (3, (1, 1)) sage: F = GF(16, 'a') sage: n = 15 sage: D = [14,1,2,11,12] - sage: C = codes.CyclicCode(field = F, length = n, D = D) + sage: C = codes.CyclicCode(field=F, length=n, D = D) sage: C.bch_bound(True) (4, (2, 12)) """ @@ -791,7 +793,7 @@ def bch_bound(self, arithmetic=False): def surrounding_bch_code(self): r""" - Returns the surrounding BCH code of ``self``. + Return the surrounding BCH code of ``self``. EXAMPLES:: @@ -818,7 +820,7 @@ class CyclicCodePolynomialEncoder(Encoder): and let `g` be its generator polynomial. This encoder encodes any polynomial `p \in F[x]_{<k}` by computing - `c = p \times g` and returning the vector of its coefficients. + `c = p g` and returning the vector of its coefficients. INPUT: @@ -829,7 +831,7 @@ class CyclicCodePolynomialEncoder(Encoder): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodePolynomialEncoder(C) sage: E Polynomial-style encoder for [7, 4] Cyclic Code over GF(2) @@ -842,7 +844,7 @@ def __init__(self, code): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodePolynomialEncoder(C) sage: E Polynomial-style encoder for [7, 4] Cyclic Code over GF(2) @@ -861,7 +863,7 @@ def __eq__(self, other): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E1 = codes.encoders.CyclicCodePolynomialEncoder(C) sage: E2 = codes.encoders.CyclicCodePolynomialEncoder(C) sage: E1 == E2 @@ -872,14 +874,14 @@ def __eq__(self, other): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodePolynomialEncoder(C) sage: E Polynomial-style encoder for [7, 4] Cyclic Code over GF(2) @@ -888,14 +890,14 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodePolynomialEncoder(C) sage: latex(E) \textnormal{Polynomial-style encoder for }[7, 4] \textnormal{ Cyclic Code over } \Bold{F}_{2} @@ -920,7 +922,7 @@ def encode(self, p): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodePolynomialEncoder(C) sage: m = x ** 2 + 1 sage: E.encode(m) @@ -936,7 +938,7 @@ def encode(self, p): def unencode_nocheck(self, c): r""" - Returns the message corresponding to ``c``. + Return the message corresponding to ``c``. Does not check if ``c`` belongs to the code. INPUT: @@ -952,7 +954,7 @@ def unencode_nocheck(self, c): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodePolynomialEncoder(C) sage: c = vector(GF(2), (1, 1, 1, 0, 0, 1, 0)) sage: E.unencode_nocheck(c) @@ -965,14 +967,14 @@ def unencode_nocheck(self, c): def message_space(self): r""" - Returns the message space of ``self`` + Return the message space of ``self`` EXAMPLES:: sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodePolynomialEncoder(C) sage: E.message_space() Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) @@ -991,8 +993,7 @@ class CyclicCodeVectorEncoder(Encoder): This codeword can be seen as a polynomial over `F[x]`, as follows: `P_m = \Sigma_{i=0}^{k-1} m_i \times x^i`. - To encode `m`, this encoder does the following multiplication: - `P_m \times g`. + To encode `m`, this encoder does the multiplication `P_m g`. INPUT: @@ -1003,7 +1004,7 @@ class CyclicCodeVectorEncoder(Encoder): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodeVectorEncoder(C) sage: E Vector-style encoder for [7, 4] Cyclic Code over GF(2) @@ -1017,7 +1018,7 @@ def __init__(self, code): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodeVectorEncoder(C) sage: E Vector-style encoder for [7, 4] Cyclic Code over GF(2) @@ -1036,7 +1037,7 @@ def __eq__(self, other): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E1 = codes.encoders.CyclicCodeVectorEncoder(C) sage: E2 = codes.encoders.CyclicCodeVectorEncoder(C) sage: E1 == E2 @@ -1047,14 +1048,14 @@ def __eq__(self, other): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodeVectorEncoder(C) sage: E Vector-style encoder for [7, 4] Cyclic Code over GF(2) @@ -1063,14 +1064,14 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodeVectorEncoder(C) sage: latex(E) \textnormal{Vector-style encoder for }[7, 4] \textnormal{ Cyclic Code over } \Bold{F}_{2} @@ -1095,7 +1096,7 @@ def encode(self, m): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodeVectorEncoder(C) sage: m = vector(GF(2), (1, 0, 1, 0)) sage: E.encode(m) @@ -1116,7 +1117,7 @@ def encode(self, m): def unencode_nocheck(self, c): r""" - Returns the message corresponding to ``c``. + Return the message corresponding to ``c``. Does not check if ``c`` belongs to the code. INPUT: @@ -1132,7 +1133,7 @@ def unencode_nocheck(self, c): sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodeVectorEncoder(C) sage: c = vector(GF(2), (1, 1, 1, 0, 0, 1, 0)) sage: E.unencode_nocheck(c) @@ -1148,14 +1149,14 @@ def unencode_nocheck(self, c): @cached_method def generator_matrix(self): r""" - Returns a generator matrix of ``self`` + Return a generator matrix of ``self`` EXAMPLES:: sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodeVectorEncoder(C) sage: E.generator_matrix() [1 1 0 1 0 0 0] @@ -1173,14 +1174,14 @@ def generator_matrix(self): def message_space(self): r""" - Returns the message space of ``self`` + Return the message space of ``self`` EXAMPLES:: sage: F.<x> = GF(2)[] sage: n = 7 sage: g = x ** 3 + x + 1 - sage: C = codes.CyclicCode(generator_pol = g, length = n) + sage: C = codes.CyclicCode(generator_pol=g, length=n) sage: E = codes.encoders.CyclicCodeVectorEncoder(C) sage: E.message_space() Vector space of dimension 4 over Finite Field of size 2 @@ -1239,7 +1240,7 @@ def __eq__(self, other): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -1253,7 +1254,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -1267,7 +1268,7 @@ def _latex_(self): def bch_code(self): r""" - Returns the surrounding BCH code of + Return the surrounding BCH code of :meth:`sage.coding.encoder.Encoder.code`. EXAMPLES:: @@ -1281,14 +1282,15 @@ def bch_code(self): def bch_decoder(self): r""" - Returns the decoder that will be used over the surrounding BCH code. + Return the decoder that will be used over the surrounding BCH code. EXAMPLES:: sage: C = codes.CyclicCode(field=GF(16), length=15, D=[14, 1, 2, 11, 12]) sage: D = codes.decoders.CyclicCodeSurroundingBCHDecoder(C) sage: D.bch_decoder() - Decoder through the underlying GRS code of [15, 12] BCH Code over GF(16) with designed distance 4 + Decoder through the underlying GRS code of [15, 12] BCH Code + over GF(16) with designed distance 4 """ return self._bch_decoder @@ -1302,7 +1304,9 @@ def decode_to_code(self, y): sage: C = codes.CyclicCode(field=F, length=15, D=[14, 1, 2, 11, 12]) sage: a = F.gen() sage: D = codes.decoders.CyclicCodeSurroundingBCHDecoder(C) - sage: y = vector(F, [0, a^3, a^3 + a^2 + a, 1, a^2 + 1, a^3 + a^2 + 1, a^3 + a^2 + a, a^3 + a^2 + a, a^2 + a, a^2 + 1, a^2 + a + 1, a^3 + 1, a^2, a^3 + a, a^3 + a]) + sage: y = vector(F, [0, a^3, a^3 + a^2 + a, 1, a^2 + 1, a^3 + a^2 + 1, + ....: a^3 + a^2 + a, a^3 + a^2 + a, a^2 + a, a^2 + 1, + ....: a^2 + a + 1, a^3 + 1, a^2, a^3 + a, a^3 + a]) sage: D.decode_to_code(y) in C True """ @@ -1310,7 +1314,7 @@ def decode_to_code(self, y): def decoding_radius(self): r""" - Returns maximal number of errors that ``self`` can decode. + Return maximal number of errors that ``self`` can decode. EXAMPLES:: diff --git a/src/sage/coding/databases.py b/src/sage/coding/databases.py index ee753504f8b..7839cd8c693 100644 --- a/src/sage/coding/databases.py +++ b/src/sage/coding/databases.py @@ -1,9 +1,13 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Access functions to online databases for coding theory """ -from sage.libs.gap.libgap import libgap from sage.features.gap import GapPackage +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.libs.gap.libgap', 'libgap') + +del lazy_import # Do not put any global imports here since this module is accessible as # sage.codes.databases.<tab> @@ -31,11 +35,11 @@ def best_linear_code_in_guava(n, k, F): EXAMPLES:: - sage: codes.databases.best_linear_code_in_guava(10,5,GF(2)) # long time; optional - gap_packages (Guava package) + sage: codes.databases.best_linear_code_in_guava(10,5,GF(2)) # long time; optional - gap_package_guava [10, 5] linear code over GF(2) - sage: libgap.LoadPackage('guava') # long time; optional - gap_packages (Guava package) + sage: libgap.LoadPackage('guava') # long time; optional - gap_package_guava ... - sage: libgap.BestKnownLinearCode(10,5,libgap.GF(2)) # long time; optional - gap_packages (Guava package) + sage: libgap.BestKnownLinearCode(10,5,libgap.GF(2)) # long time; optional - gap_package_guava a linear [10,5,4]2..4 shortened code This means that the best possible binary linear code of length 10 and @@ -82,8 +86,8 @@ def bounds_on_minimum_distance_in_guava(n, k, F): EXAMPLES:: - sage: gap_rec = codes.databases.bounds_on_minimum_distance_in_guava(10,5,GF(2)) # optional - gap_packages (Guava package) - sage: gap_rec.Display() # optional - gap_packages (Guava package) + sage: gap_rec = codes.databases.bounds_on_minimum_distance_in_guava(10,5,GF(2)) # optional - gap_package_guava + sage: gap_rec.Display() # optional - gap_package_guava rec( construction := [ <Operation "ShortenedCode">, [ [ <Operation "UUVCode">, @@ -142,8 +146,8 @@ def best_linear_code_in_codetables_dot_de(n, k, F, verbose=False): <BLANKLINE> last modified: 2002-03-20 - This function raises an ``IOError`` if an error occurs downloading data or - parsing it. It raises a ``ValueError`` if the ``q`` input is invalid. + This function raises an :class:`IOError` if an error occurs downloading data or + parsing it. It raises a :class:`ValueError` if the ``q`` input is invalid. AUTHORS: @@ -184,22 +188,22 @@ def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False, INPUT: - - ``n`` - Integer, maximal length + - ``n`` -- Integer, maximal length - - ``k`` - Integer, maximal dimension + - ``k`` -- Integer, maximal dimension - - ``b`` - Integer, requires that the generators all have weight divisible + - ``b`` -- Integer, requires that the generators all have weight divisible by ``b`` (if ``b=2``, all self-orthogonal codes are generated, and if ``b=4``, all doubly even codes are generated). Must be an even positive integer. - - ``parent`` - Used in recursion (default: ``None``) + - ``parent``- - Used in recursion (default: ``None``) - - ``BC`` - Used in recursion (default: ``None``) + - ``BC`` -- Used in recursion (default: ``None``) - - ``equal`` - If ``True`` generates only [n, k] codes (default: ``False``) + - ``equal`` -- If ``True``, generates only [n, k] codes (default: ``False``) - - ``in_test`` - Used in recursion (default: ``None``) + - ``in_test`` -- Used in recursion (default: ``None``) EXAMPLES: @@ -305,6 +309,7 @@ def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False, if out_test(N): yield N + # Import the following function so that it is available as # sage.codes.databases.self_dual_binary_codes sage.codes.databases functions # somewhat like a catalog in this respect. diff --git a/src/sage/coding/decoder.py b/src/sage/coding/decoder.py index 8a8e6496f74..82a07775300 100644 --- a/src/sage/coding/decoder.py +++ b/src/sage/coding/decoder.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Decoders @@ -106,7 +107,7 @@ def decoder_type(cls): sage: codes.decoders.LinearCodeSyndromeDecoder.decoder_type() {'dynamic', 'hard-decision'} - We can also call it on a instance of a Decoder class:: + We can also call it on a instance of a :class:`Decoder` class:: sage: G = Matrix(GF(2), [[1, 0, 0, 1], [0, 1, 1, 1]]) sage: C = LinearCode(G) @@ -222,7 +223,7 @@ def __ne__(self, other): def decode_to_code(self, r): r""" - Correct the errors in ``r`` and returns a codeword. + Correct the errors in ``r`` and return a codeword. This is a default implementation which assumes that the method :meth:`decode_to_message` has been implemented, else it returns an exception. @@ -237,7 +238,8 @@ def decode_to_code(self, r): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: word = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: word in C @@ -261,7 +263,8 @@ def connected_encoder(self): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: D = C.decoder() sage: D.connected_encoder() @@ -287,7 +290,8 @@ def decode_to_message(self, r): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: word = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: w_err = word + vector(GF(2), (1, 0, 0, 0, 0, 0, 0)) @@ -304,7 +308,8 @@ def code(self): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: D = C.decoder() sage: D.code() @@ -318,7 +323,8 @@ def message_space(self): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: D = C.decoder() sage: D.message_space() @@ -332,7 +338,8 @@ def input_space(self): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: D = C.decoder() sage: D.input_space() @@ -343,7 +350,7 @@ def input_space(self): else: raise NotImplementedError("Decoder does not have an _input_space parameter") - @abstract_method(optional = True) + @abstract_method(optional=True) def decoding_radius(self, **kwargs): r""" Return the maximal number of errors that ``self`` is able to correct. @@ -352,7 +359,8 @@ def decoding_radius(self, **kwargs): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: D = codes.decoders.LinearCodeSyndromeDecoder(C) sage: D.decoding_radius() diff --git a/src/sage/coding/decoders_catalog.py b/src/sage/coding/decoders_catalog.py index a95912e51b6..a9f2417880e 100644 --- a/src/sage/coding/decoders_catalog.py +++ b/src/sage/coding/decoders_catalog.py @@ -12,6 +12,7 @@ - :class:`extended_code.ExtendedCodeOriginalCodeDecoder <sage.coding.extended_code.ExtendedCodeOriginalCodeDecoder>` **Subfield subcode decoder** + - :class:`subfield_subcode.SubfieldSubcodeOriginalCodeDecoder <sage.coding.subfield_subcode.SubfieldSubcodeOriginalCodeDecoder>` **Generalized Reed-Solomon code decoders** @@ -45,11 +46,9 @@ - :class:`ag_code_decoders.EvaluationAGCodeUniqueDecoder <sage.coding.ag_code_decoders.EvaluationAGCodeUniqueDecoder>` - :class:`ag_code_decoders.DifferentialAGCodeUniqueDecoder <sage.coding.ag_code_decoders.DifferentialAGCodeUniqueDecoder>` -.. NOTE:: - - To import these names into the global namespace, use: +To import these names into the global namespace, use:: - sage: from sage.coding.decoders_catalog import * + sage: from sage.coding.decoders_catalog import * """ #***************************************************************************** # Copyright (C) 2009 David Joyner <wdjoyner@gmail.com> diff --git a/src/sage/coding/delsarte_bounds.py b/src/sage/coding/delsarte_bounds.py index 15d5ade7887..47c84b2c59b 100644 --- a/src/sage/coding/delsarte_bounds.py +++ b/src/sage/coding/delsarte_bounds.py @@ -31,7 +31,7 @@ def krawtchouk(n, q, l, x, check=True): r""" - Compute ``K^{n,q}_l(x)``, the Krawtchouk (a.k.a. Kravchuk) polynomial. + Compute `K^{n,q}_l(x)`, the Krawtchouk (a.k.a. Kravchuk) polynomial. See :wikipedia:`Kravchuk_polynomials`. @@ -102,7 +102,7 @@ def krawtchouk(n, q, l, x, check=True): ... TypeError: no conversion of this rational to integer """ - from sage.arith.all import binomial + from sage.arith.misc import binomial from sage.arith.srange import srange # Use the expression in equation (55) of MacWilliams & Sloane, pg 151 # We write jth term = some_factor * (j-1)th term @@ -121,7 +121,7 @@ def krawtchouk(n, q, l, x, check=True): def eberlein(n, w, k, u, check=True): r""" - Compute ``E^{n,l}_k(x)``, the Eberlein polynomial. + Compute `E^{w,n}_k(x)`, the Eberlein polynomial. See :wikipedia:`Eberlein_polynomials`. @@ -171,7 +171,7 @@ def eberlein(n, w, k, u, check=True): TypeError: either m or x-m must be an integer """ - from sage.arith.all import binomial + from sage.arith.misc import binomial from sage.arith.srange import srange if 2*w > n: @@ -275,7 +275,7 @@ def _delsarte_cwc_LP_building(n, d, w, solver, isinteger): """ from sage.numerical.mip import MixedIntegerLinearProgram - from sage.arith.all import binomial + from sage.arith.misc import binomial p = MixedIntegerLinearProgram(maximization=True, solver=solver) A = p.new_variable(integer=isinteger, nonnegative=True) @@ -399,7 +399,7 @@ def delsarte_bound_hamming_space(n, d, q, return_data=False, solver="PPL", isint EXAMPLES: - The bound on the size of the `F_2`-codes of length 11 and minimal distance 6:: + The bound on the size of the `\GF{2}`-codes of length 11 and minimal distance 6:: sage: codes.bounds.delsarte_bound_hamming_space(11, 6, 2) 12 @@ -407,7 +407,7 @@ def delsarte_bound_hamming_space(n, d, q, return_data=False, solver="PPL", isint sage: [j for i,j in p.get_values(a).items()] [1, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0] - The bound on the size of the `F_2`-codes of length 24 and minimal distance + The bound on the size of the `\GF{2}`-codes of length 24 and minimal distance 8, i.e. parameters of the extended binary Golay code:: sage: a,p,x = codes.bounds.delsarte_bound_hamming_space(24,8,2,return_data=True) @@ -416,7 +416,7 @@ def delsarte_bound_hamming_space(n, d, q, return_data=False, solver="PPL", isint sage: [j for i,j in p.get_values(a).items()] [1, 0, 0, 0, 0, 0, 0, 0, 759, 0, 0, 0, 2576, 0, 0, 0, 759, 0, 0, 0, 0, 0, 0, 0, 1] - The bound on the size of `F_4`-codes of length 11 and minimal distance 3:: + The bound on the size of `\GF{4}`-codes of length 11 and minimal distance 3:: sage: codes.bounds.delsarte_bound_hamming_space(11,3,4) 327680/3 @@ -457,10 +457,10 @@ def delsarte_bound_hamming_space(n, d, q, return_data=False, solver="PPL", isint def delsarte_bound_additive_hamming_space(n, d, q, d_star=1, q_base=0, return_data=False, solver="PPL", isinteger=False): r""" - Find a modified Delsarte bound on additive codes in Hamming space ``H_q^n`` of minimal distance ``d`` + Find a modified Delsarte bound on additive codes in Hamming space `H_q^n` of minimal distance `d` Find the Delsarte LP bound on ``F_{q_base}``-dimension of additive codes in - Hamming space ``H_q^n`` of minimal distance ``d`` with minimal distance of the dual + Hamming space `H_q^n` of minimal distance ``d`` with minimal distance of the dual code at least ``d_star``. If ``q_base`` is set to non-zero, then ``q`` is a power of ``q_base``, and the code is, formally, linear over ``F_{q_base}``. Otherwise it is assumed that ``q_base==q``. @@ -485,7 +485,7 @@ def delsarte_bound_additive_hamming_space(n, d, q, d_star=1, q_base=0, return_da data. ``W`` need not be a weight distribution of a code, or, if ``isinteger==False``, even have integer entries. - - ``solver`` -- the LP/ILP solver to be used. Defaults to ``PPL``. It is arbitrary + - ``solver`` -- the LP/ILP solver to be used. Defaults to ``'PPL'``. It is arbitrary precision, thus there will be no rounding errors. With other solvers (see :class:`MixedIntegerLinearProgram` for the list), you are on your own! @@ -494,7 +494,7 @@ def delsarte_bound_additive_hamming_space(n, d, q, d_star=1, q_base=0, return_da EXAMPLES: - The bound on dimension of linear `F_2`-codes of length 11 and minimal distance 6:: + The bound on dimension of linear `\GF{2}`-codes of length 11 and minimal distance 6:: sage: codes.bounds.delsarte_bound_additive_hamming_space(11, 6, 2) 3 @@ -503,12 +503,12 @@ def delsarte_bound_additive_hamming_space(n, d, q, d_star=1, q_base=0, return_da sage: [j for i,j in p.get_values(a).items()] [1, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0] - The bound on the dimension of linear `F_4`-codes of length 11 and minimal distance 3:: + The bound on the dimension of linear `\GF{4}`-codes of length 11 and minimal distance 3:: sage: codes.bounds.delsarte_bound_additive_hamming_space(11,3,4) 8 - The bound on the `F_2`-dimension of additive `F_4`-codes of length 11 and minimal + The bound on the `\GF{2}`-dimension of additive `\GF{4}`-codes of length 11 and minimal distance 3:: sage: codes.bounds.delsarte_bound_additive_hamming_space(11,3,4,q_base=2) @@ -602,7 +602,6 @@ def _delsarte_Q_LP_building(q, d, solver, isinteger): EXAMPLES:: sage: from sage.coding.delsarte_bounds import _delsarte_Q_LP_building - sage: from sage.all import * sage: q = Matrix([[codes.bounds.krawtchouk(6,2,i,j) for j in range(7)] for i in range(7)]) sage: _, p = _delsarte_Q_LP_building(q, 2, "PPL", False) sage: p.show() @@ -680,9 +679,10 @@ def delsarte_bound_Q_matrix(q, d, return_data=False, solver="PPL", isinteger=Fal EXAMPLES: - The bound on dimension of linear `F_2`-codes of length 10 and minimal distance 6:: + The bound on dimension of linear `\GF{2}`-codes of length 10 and minimal distance 6:: - sage: q_matrix = Matrix([[codes.bounds.krawtchouk(10,2,i,j) for i in range(11)] for j in range(11)]) + sage: q_matrix = Matrix([[codes.bounds.krawtchouk(10,2,i,j) for i in range(11)] + ....: for j in range(11)]) sage: codes.bounds.delsarte_bound_Q_matrix(q_matrix, 6) 2 diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 56f244e3ab9..b2245e6d653 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Encoders @@ -143,7 +144,8 @@ def encode(self, word): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: word = vector(GF(2), (0, 1, 1, 0)) sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) @@ -156,7 +158,8 @@ def encode(self, word): sage: E.encode(word) Traceback (most recent call last): ... - ValueError: The value to encode must be in Vector space of dimension 4 over Finite Field of size 2 + ValueError: The value to encode must be in + Vector space of dimension 4 over Finite Field of size 2 """ M = self.message_space() if word not in M: @@ -194,7 +197,6 @@ def __call__(self, m): """ return self.encode(m) - def unencode(self, c, nocheck=False): r""" Return the message corresponding to the codeword ``c``. @@ -216,7 +218,8 @@ def unencode(self, c, nocheck=False): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: c in C @@ -300,7 +303,8 @@ def unencode_nocheck(self, c): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: c in C @@ -333,7 +337,8 @@ def code(self): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: E = C.encoder() sage: E.code() == C @@ -349,7 +354,8 @@ def message_space(self): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: E = C.encoder() sage: E.message_space() @@ -357,7 +363,7 @@ def message_space(self): """ return self.code().base_field()**(self.code().dimension()) - @abstract_method(optional = True) + @abstract_method(optional=True) def generator_matrix(self): r""" Returns a generator matrix of the associated code of ``self``. @@ -369,7 +375,8 @@ def generator_matrix(self): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: E = C.encoder() sage: E.generator_matrix() diff --git a/src/sage/coding/encoders_catalog.py b/src/sage/coding/encoders_catalog.py index 9435f72ee33..e6ac68267fd 100644 --- a/src/sage/coding/encoders_catalog.py +++ b/src/sage/coding/encoders_catalog.py @@ -26,11 +26,9 @@ - :class:`punctured_code.PuncturedCodePuncturedMatrixEncoder <sage.coding.punctured_code.PuncturedCodePuncturedMatrixEncoder>` -.. NOTE:: +To import these names into the global namespace, use:: - To import these names into the global namespace, use: - - sage: from sage.coding.encoders_catalog import * + sage: from sage.coding.encoders_catalog import * """ #***************************************************************************** # Copyright (C) 2009 David Joyner <wdjoyner@gmail.com> diff --git a/src/sage/coding/extended_code.py b/src/sage/coding/extended_code.py index 83c3c0143c4..c27acc58066 100644 --- a/src/sage/coding/extended_code.py +++ b/src/sage/coding/extended_code.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Extended code @@ -85,7 +86,7 @@ def __eq__(self, other): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -98,7 +99,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -111,7 +112,7 @@ def _latex_(self): def original_code(self): r""" - Returns the code which was extended to get ``self``. + Return the code which was extended to get ``self``. EXAMPLES:: @@ -125,7 +126,7 @@ def original_code(self): @cached_method def parity_check_matrix(self): r""" - Returns a parity check matrix of ``self``. + Return a parity check matrix of ``self``. This matrix is computed directly from :func:`original_code`. @@ -156,7 +157,7 @@ def parity_check_matrix(self): def random_element(self): r""" - Returns a random element of ``self``. + Return a random element of ``self``. This random element is computed directly from the original code, and does not compute a generator matrix of ``self`` in the process. @@ -179,14 +180,6 @@ def random_element(self): return vector(F, c_list) - - - - - - - - class ExtendedCodeExtendedMatrixEncoder(Encoder): r""" Encoder using original code's generator matrix to compute the extended code's one. @@ -213,7 +206,7 @@ def __init__(self, code): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -227,7 +220,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -260,7 +253,7 @@ def __eq__(self, other): @cached_method def generator_matrix(self): r""" - Returns a generator matrix of the associated code of ``self``. + Return a generator matrix of the associated code of ``self``. EXAMPLES:: @@ -286,14 +279,6 @@ def generator_matrix(self): return M - - - - - - - - class ExtendedCodeOriginalCodeDecoder(Decoder): r""" Decoder which decodes through a decoder over the original code. @@ -314,10 +299,11 @@ class ExtendedCodeOriginalCodeDecoder(Decoder): sage: Ce = codes.ExtendedCode(C) sage: D = codes.decoders.ExtendedCodeOriginalCodeDecoder(Ce) sage: D - Decoder of Extension of [15, 7, 9] Reed-Solomon Code over GF(16) through Gao decoder for [15, 7, 9] Reed-Solomon Code over GF(16) + Decoder of Extension of [15, 7, 9] Reed-Solomon Code over GF(16) + through Gao decoder for [15, 7, 9] Reed-Solomon Code over GF(16) """ - def __init__(self, code, original_decoder = None, **kwargs): + def __init__(self, code, original_decoder=None, **kwargs): r""" TESTS: @@ -350,7 +336,7 @@ def __init__(self, code, original_decoder = None, **kwargs): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -364,7 +350,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -378,7 +364,7 @@ def _latex_(self): def original_decoder(self): r""" - Returns the decoder over the original code that will be used to decode words of + Return the decoder over the original code that will be used to decode words of :meth:`sage.coding.decoder.Decoder.code`. EXAMPLES:: @@ -393,7 +379,7 @@ def original_decoder(self): def decode_to_code(self, y, **kwargs): r""" - Decodes ``y`` to an element in :meth:`sage.coding.decoder.Decoder.code`. + Decode ``y`` to an element in :meth:`sage.coding.decoder.Decoder.code`. EXAMPLES:: @@ -401,7 +387,8 @@ def decode_to_code(self, y, **kwargs): sage: Ce = codes.ExtendedCode(C) sage: D = codes.decoders.ExtendedCodeOriginalCodeDecoder(Ce) sage: c = Ce.random_element() - sage: Chan = channels.StaticErrorRateChannel(Ce.ambient_space(), D.decoding_radius()) + sage: Chan = channels.StaticErrorRateChannel(Ce.ambient_space(), + ....: D.decoding_radius()) sage: y = Chan(c) sage: y in Ce False @@ -412,10 +399,12 @@ def decode_to_code(self, y, **kwargs): sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'a').list()[:15], 7) sage: Ce = codes.ExtendedCode(C) - sage: Dgrs = C.decoder('GuruswamiSudan', tau = 4) - sage: D = codes.decoders.ExtendedCodeOriginalCodeDecoder(Ce, original_decoder = Dgrs) + sage: Dgrs = C.decoder('GuruswamiSudan', tau=4) + sage: D = codes.decoders.ExtendedCodeOriginalCodeDecoder(Ce, + ....: original_decoder=Dgrs) sage: c = Ce.random_element() - sage: Chan = channels.StaticErrorRateChannel(Ce.ambient_space(), D.decoding_radius()) + sage: Chan = channels.StaticErrorRateChannel(Ce.ambient_space(), + ....: D.decoding_radius()) sage: y = Chan(c) sage: y in Ce False @@ -449,7 +438,7 @@ def decode_to_code(self, y, **kwargs): def decoding_radius(self, *args, **kwargs): r""" - Returns maximal number of errors that ``self`` can decode. + Return maximal number of errors that ``self`` can decode. INPUT: diff --git a/src/sage/coding/gabidulin_code.py b/src/sage/coding/gabidulin_code.py index b6d2e2bac4d..0ba1d13ec41 100644 --- a/src/sage/coding/gabidulin_code.py +++ b/src/sage/coding/gabidulin_code.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Gabidulin Code @@ -499,7 +500,8 @@ def generator_matrix(self): sage: Fqm = GF(2^9) sage: Fq = GF(2^3) sage: C = codes.GabidulinCode(Fqm, 3, 3, Fq) - sage: list(C.generator_matrix().row(1)) == [C.evaluation_points()[i]**(2**3) for i in range(3)] + sage: (list(C.generator_matrix().row(1)) + ....: == [C.evaluation_points()[i]**(2**3) for i in range(3)]) True """ from functools import reduce @@ -543,7 +545,8 @@ class GabidulinPolynomialEvaluationEncoder(Encoder): sage: z9 = Fqm.gen() sage: p = (z9^6 + z9^2 + z9 + 1)*x + z9^7 + z9^5 + z9^4 + z9^2 sage: vector(p.multi_point_evaluation(C.evaluation_points())) - doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. + doctest:...: FutureWarning: This class/method/function is marked as experimental. + It, its functionality or its interface might change without a formal deprecation. See https://github.com/sagemath/sage/issues/13215 for details. (z9^7 + z9^6 + z9^5 + z9^4 + z9 + 1, z9^6 + z9^5 + z9^3 + z9) @@ -554,13 +557,15 @@ class GabidulinPolynomialEvaluationEncoder(Encoder): sage: C = codes.GabidulinCode(Fqm, 2, 2, Fq) sage: E = codes.encoders.GabidulinPolynomialEvaluationEncoder(C) sage: E - Polynomial evaluation style encoder for [2, 2, 1] linear Gabidulin code over GF(16)/GF(4) + Polynomial evaluation style encoder for + [2, 2, 1] linear Gabidulin code over GF(16)/GF(4) Alternatively, we can construct the encoder from ``C`` directly:: sage: E = C.encoder("PolynomialEvaluation") sage: E - Polynomial evaluation style encoder for [2, 2, 1] linear Gabidulin code over GF(16)/GF(4) + Polynomial evaluation style encoder for + [2, 2, 1] linear Gabidulin code over GF(16)/GF(4) """ def __init__(self, code): @@ -655,7 +660,8 @@ def message_space(self): sage: C = codes.GabidulinCode(Fqm, 4, 4, Fq) sage: E = codes.encoders.GabidulinPolynomialEvaluationEncoder(C) sage: E.message_space() - Ore Polynomial Ring in x over Finite Field in z20 of size 5^20 twisted by z20 |--> z20^(5^4) + Ore Polynomial Ring in x over Finite Field in z20 of size 5^20 + twisted by z20 |--> z20^(5^4) """ C = self.code() return C.base_field()['x', C.twisting_homomorphism()] diff --git a/src/sage/coding/golay_code.py b/src/sage/coding/golay_code.py index 029c572209e..b55cd8a4f4d 100644 --- a/src/sage/coding/golay_code.py +++ b/src/sage/coding/golay_code.py @@ -118,7 +118,7 @@ def __eq__(self, other): """ return isinstance(other, GolayCode) \ and self.base_field() == other.base_field() \ - and self.length() == other.length() \ + and self.length() == other.length() def _repr_(self): r""" @@ -133,8 +133,8 @@ def _repr_(self): ext = "" if n % 2 == 0: ext = "Extended" - return "[%s, %s, %s] %s Golay code over GF(%s)"\ - % (n, self.dimension(), self.minimum_distance(), ext, self.base_field().cardinality()) + return "[%s, %s, %s] %s Golay code over GF(%s)" % (n, self.dimension(), + self.minimum_distance(), ext, self.base_field().cardinality()) def _latex_(self): r""" @@ -396,8 +396,6 @@ def parity_check_matrix(self): return H - - ####################### registration ############################### GolayCode._registered_encoders["GeneratorMatrix"] = LinearCodeGeneratorMatrixEncoder diff --git a/src/sage/coding/goppa_code.py b/src/sage/coding/goppa_code.py index fbfa74462c4..2a974cf1ef2 100644 --- a/src/sage/coding/goppa_code.py +++ b/src/sage/coding/goppa_code.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Goppa code @@ -139,7 +140,9 @@ def _repr_(self): [8, 2] Goppa code over GF(2) """ return "[{}, {}] Goppa code over GF({})".format( - self.length(), self.dimension(), self.base_field().cardinality()) + self.length(), self.dimension(), + self.base_field().cardinality()) + def _latex_(self): r""" Return a latex representation of ``self``. @@ -433,4 +436,5 @@ def generator_matrix(self): aux = codes.from_parity_check_matrix(pmat) return aux.generator_matrix() + GoppaCode._registered_encoders["GoppaEncoder"] = GoppaCodeEncoder diff --git a/src/sage/coding/grs_code.py b/src/sage/coding/grs_code.py index efbc1d32c5b..b0824a51f62 100644 --- a/src/sage/coding/grs_code.py +++ b/src/sage/coding/grs_code.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Reed-Solomon codes and Generalized Reed-Solomon codes @@ -7,9 +8,9 @@ .. MATH:: - \{ f(\alpha_1), \ldots, f(\alpha_n) \mid f \in F[x], \deg f < k \} + \{ (f(\alpha_1), \ldots, f(\alpha_n)) \mid f \in F[x], \deg f < k \} -An RS code is often called "classical" if `alpha_i = \alpha^{i-1}` and `\alpha` +An RS code is often called "classical" if `\alpha_i = \alpha^{i-1}` and `\alpha` is a primitive `n`'th root of unity. More generally, given also `n` "column multipliers" `\beta_1, \dots, \beta_n`, @@ -18,7 +19,7 @@ .. MATH:: - \{ (\beta_1 f(\alpha_1), \ldots, \beta_n f(\alpha_n) + \{ (\beta_1 f(\alpha_1), \ldots, \beta_n f(\alpha_n)) \mid f \in F[x], \deg f < k \} Here is a list of all content related to GRS codes: @@ -64,9 +65,6 @@ from sage.misc.functional import symbolic_sum from sage.misc.misc_c import prod -from sage.functions.other import binomial -from sage.symbolic.ring import SR - from .linear_code import AbstractLinearCode from .encoder import Encoder from .decoder import Decoder, DecodingError @@ -516,7 +514,7 @@ def weight_distribution(self): sage: F = GF(11) sage: n, k = 10, 5 sage: C = codes.GeneralizedReedSolomonCode(F.list()[:n], k) - sage: C.weight_distribution() + sage: C.weight_distribution() # optional - sage.symbolic [1, 0, 0, 0, 0, 0, 2100, 6000, 29250, 61500, 62200] TESTS: @@ -525,13 +523,16 @@ def weight_distribution(self): sage: F = GF(7) sage: C = codes.GeneralizedReedSolomonCode(F.list(), 3) - sage: C.weight_distribution() == super(codes.GeneralizedReedSolomonCode, C).weight_distribution() # long time + sage: C.weight_distribution() == super(codes.GeneralizedReedSolomonCode, C).weight_distribution() # long time # optional - sage.symbolic True sage: F = GF(8) sage: C = codes.GeneralizedReedSolomonCode(F.list(), 3) - sage: C.weight_distribution() == super(codes.GeneralizedReedSolomonCode, C).weight_distribution() # long time + sage: C.weight_distribution() == super(codes.GeneralizedReedSolomonCode, C).weight_distribution() # long time # optional - sage.symbolic True """ + from sage.symbolic.ring import SR + from sage.functions.other import binomial + d = self.minimum_distance() n = self.length() q = self.base_ring().order() @@ -576,7 +577,7 @@ def ReedSolomonCode(base_field, length, dimension, primitive_root=None): r""" Construct a classical Reed-Solomon code. - A classical `[n,k]` Reed-Solomon code over `GF(q)` with `1 \le k \le n` and + A classical `[n,k]` Reed-Solomon code over `\GF{q}` with `1 \le k \le n` and `n | (q-1)` is a Reed-Solomon code whose evaluation points are the consecutive powers of a primitive `n`'th root of unity `\alpha`, i.e. `\alpha_i = \alpha^{i-1}`, where `\alpha_1, \ldots, \alpha_n` are the @@ -664,13 +665,13 @@ class GRSEvaluationVectorEncoder(Encoder): .. MATH:: - p = \Sigma_{i=1}^{m} m_i \times x^i. + p = \Sigma_{i=1}^{m} m_i x^i. The encoding of `m` will be the following codeword: .. MATH:: - (\beta_1 \times p(\alpha_1), \dots, \beta_n \times p(\alpha_n)). + (\beta_1 p(\alpha_1), \dots, \beta_n p(\alpha_n)). INPUT: @@ -767,7 +768,7 @@ def generator_matrix(self): .. MATH:: - G = [g_{i,j}], g_{i,j} = \beta_j \times \alpha_{j}^{i}. + G = [g_{i,j}], g_{i,j} = \beta_j \alpha_{j}^{i}. This matrix is a Vandermonde matrix. @@ -806,7 +807,7 @@ class GRSEvaluationPolynomialEncoder(Encoder): .. MATH:: - (\beta_1 \times p(\alpha_1), \dots, \beta_n \times p(\alpha_n)). + (\beta_1 p(\alpha_1), \dots, \beta_n p(\alpha_n)). INPUT: @@ -987,7 +988,8 @@ def encode(self, p): sage: E.encode(p) Traceback (most recent call last): ... - ValueError: The value to encode must be in Univariate Polynomial Ring in x over Finite Field of size 11 + ValueError: The value to encode must be in + Univariate Polynomial Ring in x over Finite Field of size 11 TESTS: @@ -1009,7 +1011,7 @@ def encode(self, p): C = self.code() if p.degree() >= C.dimension(): raise ValueError("The polynomial to encode must have degree at most %s" % (C.dimension() - 1)) - alphas = C.evaluation_points() + alphas = C.evaluation_points() col_mults = C.column_multipliers() c = vector(C.base_ring(), [col_mults[i]*p(alphas[i]) for i in range(C.length())]) return c @@ -1057,7 +1059,7 @@ def unencode_nocheck(self, c): """ C = self.code() - alphas = C.evaluation_points() + alphas = C.evaluation_points() col_mults = C.column_multipliers() c = [c[i]/col_mults[i] for i in range(C.length())] @@ -1229,14 +1231,14 @@ def _decode_to_code_and_message(self, r): r_list = copy(r) r_list = [r[i]/col_mults[i] for i in range(0, C.length())] - t = (C.minimum_distance()-1) // 2 + t = (C.minimum_distance()-1) // 2 l0 = n-1-t l1 = n-1-t-(k-1) - S = matrix(C.base_field(), n, l0+l1+2, + S = matrix(C.base_field(), n, l0+l1+2, lambda i, j: (C.evaluation_points()[i])**j if j<(l0+1) else r_list[i]*(C.evaluation_points()[i])**(j-(l0+1))) - S = S.right_kernel() - S = S.basis_matrix().row(0) + S = S.right_kernel() + S = S.basis_matrix().row(0) R = C.base_field()['x'] Q0 = R(S.list_from_positions(range(l0 + 1))) @@ -1277,7 +1279,8 @@ def decode_to_message(self, r): sage: C = codes.GeneralizedReedSolomonCode(F.list()[:n], k) sage: D = codes.decoders.GRSBerlekampWelchDecoder(C) sage: c = C.random_element() - sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), D.decoding_radius()) + sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), + ....: D.decoding_radius()) sage: y = Chan(c) sage: D.connected_encoder().unencode(c) == D.decode_to_message(y) True @@ -1338,7 +1341,8 @@ def decode_to_code(self, r): sage: C = codes.GeneralizedReedSolomonCode(F.list()[:n], k) sage: D = codes.decoders.GRSBerlekampWelchDecoder(C) sage: c = C.random_element() - sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), D.decoding_radius()) + sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), + ....: D.decoding_radius()) sage: y = Chan(c) sage: c == D.decode_to_code(y) True @@ -1539,7 +1543,7 @@ def _partial_xgcd(self, a, b, PolRing): Performs an Euclidean algorithm on ``a`` and ``b`` until a remainder has degree less than `\frac{n+k}{2}`, `n` being the dimension of the code, `k` its dimension, and returns `(r, s)` such that in the step - just before termination, `r = a\times s + b\times t`. + just before termination, `r = a s + b t`. INPUT: @@ -1660,7 +1664,8 @@ def decode_to_message(self, r): sage: C = codes.GeneralizedReedSolomonCode(F.list()[:n], k) sage: D = codes.decoders.GRSGaoDecoder(C) sage: c = C.random_element() - sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), D.decoding_radius()) + sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), + ....: D.decoding_radius()) sage: y = Chan(c) sage: D.connected_encoder().unencode(c) == D.decode_to_message(y) True @@ -1721,7 +1726,8 @@ def decode_to_code(self, r): sage: C = codes.GeneralizedReedSolomonCode(F.list()[:n], k) sage: D = codes.decoders.GRSGaoDecoder(C) sage: c = C.random_element() - sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), D.decoding_radius()) + sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), + ....: D.decoding_radius()) sage: y = Chan(c) sage: c == D.decode_to_code(y) True @@ -1893,11 +1899,11 @@ def decode_to_message(self, word_and_erasure_vector): INPUT: - - word_and_erasure_vector -- a tuple whose: + - ``word_and_erasure_vector`` -- a tuple whose: * first element is an element of the ambient space of the code * second element is a vector over `\GF{2}` whose length is the - same as the code's + same as the code's, containing erasure positions .. NOTE:: @@ -1909,12 +1915,6 @@ def decode_to_message(self, word_and_erasure_vector): In either case, if ``r`` is not a codeword, the output is unspecified. - INPUT: - - - ``word_and_erasure_vector`` -- a pair of vectors, where - first element is a codeword of ``self`` and second element - is a vector of GF(2) containing erasure positions - OUTPUT: - a vector of ``self`` message space @@ -1927,7 +1927,8 @@ def decode_to_message(self, word_and_erasure_vector): sage: D = codes.decoders.GRSErrorErasureDecoder(C) sage: c = C.random_element() sage: n_era = randint(0, C.minimum_distance() - 2) - sage: Chan = channels.ErrorErasureChannel(C.ambient_space(), D.decoding_radius(n_era), n_era) + sage: Chan = channels.ErrorErasureChannel(C.ambient_space(), + ....: D.decoding_radius(n_era), n_era) sage: y = Chan(c) sage: D.connected_encoder().unencode(c) == D.decode_to_message(y) True @@ -2133,7 +2134,7 @@ def _partial_xgcd(self, a, b, PolRing): Performs an Euclidean algorithm on ``a`` and ``b`` until a remainder has degree less than `\frac{n+k}{2}`, `n` being the dimension of the code, `k` its dimension, and returns `(r, t)` such that in the step - just before termination, `r = a\times s + b\times t`. + just before termination, `r = a s + b t`. INPUT: @@ -2272,7 +2273,8 @@ def decode_to_code(self, r): sage: C = codes.GeneralizedReedSolomonCode(F.list()[1:n+1], k) sage: D = codes.decoders.GRSKeyEquationSyndromeDecoder(C) sage: c = C.random_element() - sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), D.decoding_radius()) + sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), + ....: D.decoding_radius()) sage: y = Chan(c) sage: c == D.decode_to_code(y) True @@ -2346,7 +2348,8 @@ def decode_to_message(self, r): sage: C = codes.GeneralizedReedSolomonCode(F.list()[1:n+1], k) sage: D = codes.decoders.GRSKeyEquationSyndromeDecoder(C) sage: c = C.random_element() - sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), D.decoding_radius()) + sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), + ....: D.decoding_radius()) sage: y = Chan(c) sage: D.connected_encoder().unencode(c) == D.decode_to_message(y) True diff --git a/src/sage/coding/guava.py b/src/sage/coding/guava.py index 26d94e068f3..e9f0404b458 100644 --- a/src/sage/coding/guava.py +++ b/src/sage/coding/guava.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.libs.gap sage.modules sage.rings.finite_rings r""" Constructions of generator matrices using the GUAVA package for GAP @@ -45,7 +46,7 @@ def QuasiQuadraticResidueCode(p): Follows the definition of Proposition 2.2 in [BM2003]_. The code has a generator matrix in the block form `G=(Q,N)`. Here `Q` is a `p \times p` circulant matrix whose top row is `(0,x_1,...,x_{p-1})`, where `x_i=1` if and only if - `i` is a quadratic residue `\mod p`, and `N` is a `p \times p` circulant + `i` is a quadratic residue mod `p`, and `N` is a `p \times p` circulant matrix whose top row is `(0,y_1,...,y_{p-1})`, where `x_i+y_i=1` for all `i`. @@ -59,7 +60,7 @@ def QuasiQuadraticResidueCode(p): EXAMPLES:: - sage: C = codes.QuasiQuadraticResidueCode(11); C # optional - gap_packages (Guava package) + sage: C = codes.QuasiQuadraticResidueCode(11); C # optional - gap_package_guava [22, 11] linear code over GF(2) These are self-orthogonal in general and self-dual when `p \equiv 3 \pmod 4`. @@ -92,9 +93,9 @@ def RandomLinearCodeGuava(n, k, F): EXAMPLES:: - sage: C = codes.RandomLinearCodeGuava(30,15,GF(2)); C # optional - gap_packages (Guava package) + sage: C = codes.RandomLinearCodeGuava(30,15,GF(2)); C # optional - gap_package_guava [30, 15] linear code over GF(2) - sage: C = codes.RandomLinearCodeGuava(10,5,GF(4,'a')); C # optional - gap_packages (Guava package) + sage: C = codes.RandomLinearCodeGuava(10,5,GF(4,'a')); C # optional - gap_package_guava [10, 5] linear code over GF(4) AUTHOR: David Joyner (11-2005) diff --git a/src/sage/algebras/steenrod/__init__.py b/src/sage/coding/guruswami_sudan/all.py similarity index 100% rename from src/sage/algebras/steenrod/__init__.py rename to src/sage/coding/guruswami_sudan/all.py diff --git a/src/sage/coding/guruswami_sudan/gs_decoder.py b/src/sage/coding/guruswami_sudan/gs_decoder.py index bfc04fee8ed..3021cbbfab6 100644 --- a/src/sage/coding/guruswami_sudan/gs_decoder.py +++ b/src/sage/coding/guruswami_sudan/gs_decoder.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" Guruswami-Sudan decoder for (Generalized) Reed-Solomon codes @@ -36,9 +37,9 @@ def n_k_params(C, n_k): r""" - Internal helper function for the GRSGuruswamiSudanDecoder class for allowing to - specify either a GRS code `C` or the length and dimensions `n, k` directly, - in all the static functions. + Internal helper function for the :class:`GRSGuruswamiSudanDecoder` class for + allowing to specify either a GRS code `C` or the length and dimensions `n, + k` directly, in all the static functions. If neither `C` or `n,k` were specified to those functions, an appropriate error should be raised. Otherwise, `n, k` of the code or the supplied tuple @@ -46,9 +47,10 @@ def n_k_params(C, n_k): INPUT: - - ``C`` -- A GRS code or `None` + - ``C`` -- A GRS code or ``None`` - - ``n_k`` -- A tuple `(n,k)` being length and dimension of a GRS code, or `None`. + - ``n_k`` -- A tuple `(n,k)` being length and dimension of a GRS code, or + ``None``. OUTPUT: @@ -60,13 +62,13 @@ def n_k_params(C, n_k): sage: n_k_params(None, (10, 5)) (10, 5) sage: C = codes.GeneralizedReedSolomonCode(GF(11).list()[:10], 5) - sage: n_k_params(C,None) + sage: n_k_params(C, None) (10, 5) sage: n_k_params(None,None) Traceback (most recent call last): ... ValueError: Please provide either the code or its length and dimension - sage: n_k_params(C,(12, 2)) + sage: n_k_params(C, (12, 2)) Traceback (most recent call last): ... ValueError: Please provide only the code or its length and dimension @@ -85,7 +87,7 @@ def n_k_params(C, n_k): def roth_ruckenstein_root_finder(p, maxd=None, precision=None): """ Wrapper for Roth-Ruckenstein algorithm to compute the roots of a polynomial - with coefficients in ``F[x]``. + with coefficients in `F[x]`. TESTS:: @@ -104,7 +106,7 @@ def roth_ruckenstein_root_finder(p, maxd=None, precision=None): def alekhnovich_root_finder(p, maxd=None, precision=None): """ Wrapper for Alekhnovich's algorithm to compute the roots of a polynomial - with coefficients in ``F[x]``. + with coefficients in `F[x]`. TESTS:: @@ -155,16 +157,18 @@ class GRSGuruswamiSudanDecoder(Decoder): Guruswami-Sudan algorithm to correct. - ``parameters`` -- (default: ``None``) a pair of integers, where: - - the first integer is the multiplicity parameter, and - - the second integer is the list size parameter. + + - the first integer is the multiplicity parameter, and + - the second integer is the list size parameter. - ``interpolation_alg`` -- (default: ``None``) the interpolation algorithm that will be used. The following possibilities are currently available: - * ``"LinearAlgebra"`` -- uses a linear system solver. - * ``"LeeOSullivan"`` -- uses Lee O'Sullivan method based on row reduction of a matrix - * ``None`` -- one of the above will be chosen based on the size of the - code and the parameters. + * ``"LinearAlgebra"`` -- uses a linear system solver. + * ``"LeeOSullivan"`` -- uses Lee O'Sullivan method based on row reduction + of a matrix + * ``None`` -- one of the above will be chosen based on the size of the + code and the parameters. You can also supply your own function to perform the interpolation. See NOTE section for details on the signature of this function. @@ -172,12 +176,12 @@ class GRSGuruswamiSudanDecoder(Decoder): - ``root_finder`` -- (default: ``None``) the rootfinding algorithm that will be used. The following possibilities are currently available: - * ``"Alekhnovich"`` -- uses Alekhnovich's algorithm. + * ``"Alekhnovich"`` -- uses Alekhnovich's algorithm. - * ``"RothRuckenstein"`` -- uses Roth-Ruckenstein algorithm. + * ``"RothRuckenstein"`` -- uses Roth-Ruckenstein algorithm. - * ``None`` -- one of the above will be chosen based on the size of the - code and the parameters. + * ``None`` -- one of the above will be chosen based on the size of the + code and the parameters. You can also supply your own function to perform the interpolation. See NOTE section for details on the signature of this function. @@ -201,46 +205,48 @@ class GRSGuruswamiSudanDecoder(Decoder): EXAMPLES:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, tau = 97) - sage: D - Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2) + sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, tau=97); D + Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) + decoding 97 errors with parameters (1, 2) One can specify multiplicity and list size instead of ``tau``:: - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters = (1,2)) - sage: D - Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2) + sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters=(1,2)); D + Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) + decoding 97 errors with parameters (1, 2) One can pass a method as ``root_finder`` (works also for ``interpolation_alg``):: sage: from sage.coding.guruswami_sudan.gs_decoder import roth_ruckenstein_root_finder sage: rf = roth_ruckenstein_root_finder - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters = (1,2), root_finder = rf) - sage: D - Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2) + sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters=(1,2), + ....: root_finder=rf); D + Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) + decoding 97 errors with parameters (1, 2) If one wants to use the native Sage algorithms for the root finding step, one can directly pass the string given in the ``Input`` block of this class. This works for ``interpolation_alg`` as well:: - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters = (1,2), root_finder="RothRuckenstein") - sage: D - Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2) + sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, parameters=(1,2), + ....: root_finder="RothRuckenstein"); D + Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) + decoding 97 errors with parameters (1, 2) Actually, we can construct the decoder from ``C`` directly:: - sage: D = C.decoder("GuruswamiSudan", tau = 97) - sage: D - Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2) + sage: D = C.decoder("GuruswamiSudan", tau=97); D + Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) + decoding 97 errors with parameters (1, 2) """ ####################### static methods ############################### @staticmethod - def parameters_given_tau(tau, C = None, n_k = None): + def parameters_given_tau(tau, C=None, n_k=None): r""" - Returns the smallest possible multiplicity and list size given the + Return the smallest possible multiplicity and list size given the given parameters of the code and decoding radius. INPUT: @@ -254,8 +260,9 @@ def parameters_given_tau(tau, C = None, n_k = None): OUTPUT: - ``(s, l)`` -- a pair of integers, where: - - ``s`` is the multiplicity parameter, and - - ``l`` is the list size parameter. + + - ``s`` is the multiplicity parameter, and + - ``l`` is the list size parameter. .. NOTE:: @@ -264,23 +271,25 @@ def parameters_given_tau(tau, C = None, n_k = None): EXAMPLES:: + sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: tau, n, k = 97, 250, 70 - sage: codes.decoders.GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k = (n, k)) + sage: GSD.parameters_given_tau(tau, n_k=(n, k)) (1, 2) Another example with a bigger decoding radius:: sage: tau, n, k = 118, 250, 70 - sage: codes.decoders.GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k = (n, k)) + sage: GSD.parameters_given_tau(tau, n_k=(n, k)) (47, 89) Choosing a decoding radius which is too large results in an errors:: sage: tau = 200 - sage: codes.decoders.GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k = (n, k)) + sage: GSD.parameters_given_tau(tau, n_k=(n, k)) Traceback (most recent call last): ... - ValueError: The decoding radius must be less than the Johnson radius (which is 118.66) + ValueError: The decoding radius must be less than + the Johnson radius (which is 118.66) """ n,k = n_k_params(C, n_k) @@ -307,9 +316,9 @@ def try_l(l): return (s, l) @staticmethod - def guruswami_sudan_decoding_radius(C = None, n_k = None, l = None, s = None): + def guruswami_sudan_decoding_radius(C=None, n_k=None, l=None, s=None): r""" - Returns the maximal decoding radius of the Guruswami-Sudan decoder and + Return the maximal decoding radius of the Guruswami-Sudan decoder and the parameter choices needed for this. If ``s`` is set but ``l`` is not it will return the best decoding radius using this ``s`` @@ -332,27 +341,30 @@ def guruswami_sudan_decoding_radius(C = None, n_k = None, l = None, s = None): OUTPUT: - ``(tau, (s, l))`` -- where - - ``tau`` is the obtained decoding radius, and - - ``s, ell`` are the multiplicity parameter, respectively list size - parameter giving this radius. + + - ``tau`` is the obtained decoding radius, and + + - ``s, ell`` are the multiplicity parameter, respectively list size + parameter giving this radius. EXAMPLES:: + sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: n, k = 250, 70 - sage: codes.decoders.GRSGuruswamiSudanDecoder.guruswami_sudan_decoding_radius(n_k = (n, k)) + sage: GSD.guruswami_sudan_decoding_radius(n_k=(n, k)) (118, (47, 89)) One parameter can be restricted at a time:: sage: n, k = 250, 70 - sage: codes.decoders.GRSGuruswamiSudanDecoder.guruswami_sudan_decoding_radius(n_k = (n, k), s=3) + sage: GSD.guruswami_sudan_decoding_radius(n_k=(n, k), s=3) (109, (3, 5)) - sage: codes.decoders.GRSGuruswamiSudanDecoder.guruswami_sudan_decoding_radius(n_k = (n, k), l=7) + sage: GSD.guruswami_sudan_decoding_radius(n_k=(n, k), l=7) (111, (4, 7)) The function can also just compute the decoding radius given the parameters:: - sage: codes.decoders.GRSGuruswamiSudanDecoder.guruswami_sudan_decoding_radius(n_k = (n, k), s=2, l=6) + sage: GSD.guruswami_sudan_decoding_radius(n_k=(n, k), s=2, l=6) (92, (2, 6)) """ n,k = n_k_params(C, n_k) @@ -364,7 +376,7 @@ def get_tau(s,l): return gilt(n - n/2*(s+1)/(l+1) - (k-1)/2*l/s) if l is None and s is None: tau = gilt(johnson_radius(n, n - k + 1)) - return (tau, GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k = (n, k))) + return (tau, GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k=(n, k))) if l is not None and s is not None: return (get_tau(s,l), (s,l)) @@ -401,7 +413,7 @@ def find_integral_max(real_max, f): return (tau, (s,l)) @staticmethod - def _suitable_parameters_given_tau(tau, C = None, n_k = None): + def _suitable_parameters_given_tau(tau, C=None, n_k=None): r""" Return quite good multiplicity and list size parameters for the code parameters and the decoding radius. @@ -423,8 +435,9 @@ def _suitable_parameters_given_tau(tau, C = None, n_k = None): OUTPUT: - ``(s, l)`` -- a pair of integers, where: - - ``s`` is the multiplicity parameter, and - - ``l`` is the list size parameter. + + - ``s`` is the multiplicity parameter, and + - ``l`` is the list size parameter. .. NOTE:: @@ -436,31 +449,32 @@ def _suitable_parameters_given_tau(tau, C = None, n_k = None): The following is an example where the parameters are optimal:: + sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: tau = 98 sage: n, k = 250, 70 - sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(tau, n_k = (n, k)) + sage: GSD._suitable_parameters_given_tau(tau, n_k=(n, k)) (2, 3) - sage: codes.decoders.GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k = (n, k)) + sage: GSD.parameters_given_tau(tau, n_k=(n, k)) (2, 3) This is an example where they are not:: sage: tau = 97 sage: n, k = 250, 70 - sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(tau, n_k = (n, k)) + sage: GSD._suitable_parameters_given_tau(tau, n_k=(n, k)) (2, 3) - sage: codes.decoders.GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k = (n, k)) + sage: GSD.parameters_given_tau(tau, n_k=(n, k)) (1, 2) We can provide a GRS code instead of `n` and `k` directly:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(tau, C = C) + sage: GSD._suitable_parameters_given_tau(tau, C=C) (2, 3) Another one with a bigger ``tau``:: - sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(118, C = C) + sage: GSD._suitable_parameters_given_tau(118, C=C) (47, 89) """ n,k = n_k_params(C, n_k) @@ -473,9 +487,9 @@ def _suitable_parameters_given_tau(tau, C = None, n_k = None): return (s, l) @staticmethod - def gs_satisfactory(tau, s, l, C = None, n_k = None): + def gs_satisfactory(tau, s, l, C=None, n_k=None): r""" - Returns whether input parameters satisfy the governing equation of + Return whether input parameters satisfy the governing equation of Guruswami-Sudan. See [Nie2013]_ page 49, definition 3.3 and proposition 3.4 for details. @@ -497,21 +511,22 @@ def gs_satisfactory(tau, s, l, C = None, n_k = None): EXAMPLES:: + sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: tau, s, l = 97, 1, 2 sage: n, k = 250, 70 - sage: codes.decoders.GRSGuruswamiSudanDecoder.gs_satisfactory(tau, s, l, n_k = (n, k)) + sage: GSD.gs_satisfactory(tau, s, l, n_k=(n, k)) True One can also pass a GRS code:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: codes.decoders.GRSGuruswamiSudanDecoder.gs_satisfactory(tau, s, l, C = C) + sage: GSD.gs_satisfactory(tau, s, l, C=C) True Another example where ``s`` and ``l`` does not satisfy the equation:: sage: tau, s, l = 118, 47, 80 - sage: codes.decoders.GRSGuruswamiSudanDecoder.gs_satisfactory(tau, s, l, n_k = (n, k)) + sage: GSD.gs_satisfactory(tau, s, l, n_k=(n, k)) False If one provides both ``C`` and ``n_k`` an exception is returned:: @@ -519,14 +534,14 @@ def gs_satisfactory(tau, s, l, C = None, n_k = None): sage: tau, s, l = 97, 1, 2 sage: n, k = 250, 70 sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: codes.decoders.GRSGuruswamiSudanDecoder.gs_satisfactory(tau, s, l, C = C, n_k = (n, k)) + sage: GSD.gs_satisfactory(tau, s, l, C=C, n_k=(n, k)) Traceback (most recent call last): ... ValueError: Please provide only the code or its length and dimension Same if one provides none of these:: - sage: codes.decoders.GRSGuruswamiSudanDecoder.gs_satisfactory(tau, s, l) + sage: GSD.gs_satisfactory(tau, s, l) Traceback (most recent call last): ... ValueError: Please provide either the code or its length and dimension @@ -534,17 +549,16 @@ def gs_satisfactory(tau, s, l, C = None, n_k = None): n,k = n_k_params(C, n_k) return l > 0 and s > 0 and n * s * (s+1) < (l+1) * (2*s*(n-tau) - (k-1) * l) - - ####################### decoder itself ############################### - def __init__(self, code, tau = None, parameters = None, interpolation_alg = None, root_finder = None): + def __init__(self, code, tau=None, parameters=None, interpolation_alg=None, root_finder=None): r""" TESTS: If neither ``tau`` nor ``parameters`` is given, an exception is returned:: + sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C) + sage: D = GSD(C) Traceback (most recent call last): ... ValueError: Specify either tau or parameters @@ -553,7 +567,7 @@ def __init__(self, code, tau = None, parameters = None, interpolation_alg = None an exception is returned:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, tau = 97, interpolation_alg = 42) + sage: D = GSD(C, tau=97, interpolation_alg=42) Traceback (most recent call last): ... ValueError: Please provide a method or one of the allowed strings for interpolation_alg @@ -561,7 +575,7 @@ def __init__(self, code, tau = None, parameters = None, interpolation_alg = None Same thing for ``root_finder``:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, tau = 97, root_finder = "FortyTwo") + sage: D = GSD(C, tau=97, root_finder="FortyTwo") Traceback (most recent call last): ... ValueError: Please provide a method or one of the allowed strings for root_finder @@ -570,7 +584,7 @@ def __init__(self, code, tau = None, parameters = None, interpolation_alg = None error message is returned:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, tau = 142, parameters=(1, 2)) + sage: D = GSD(C, tau=142, parameters=(1, 2)) Traceback (most recent call last): ... ValueError: Impossible parameters for the Guruswami-Sudan algorithm @@ -578,7 +592,7 @@ def __init__(self, code, tau = None, parameters = None, interpolation_alg = None If ``code`` is not a GRS code, an error is raised:: sage: C = codes.random_linear_code(GF(11), 10, 4) - sage: codes.decoders.GRSGuruswamiSudanDecoder(C, tau = 2) + sage: GSD(C, tau=2) Traceback (most recent call last): ... ValueError: code has to be a generalized Reed-Solomon code @@ -587,16 +601,16 @@ def __init__(self, code, tau = None, parameters = None, interpolation_alg = None raise ValueError("code has to be a generalized Reed-Solomon code") n, k = code.length(), code.dimension() if tau and parameters: - if not GRSGuruswamiSudanDecoder.gs_satisfactory(tau, parameters[0], parameters[1], C = code): + if not GRSGuruswamiSudanDecoder.gs_satisfactory(tau, parameters[0], parameters[1], C=code): raise ValueError("Impossible parameters for the Guruswami-Sudan algorithm") self._tau, self._s, self._ell = tau, parameters[0], parameters[1] elif tau: self._tau = tau - self._s, self._ell = GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k = (n, k)) + self._s, self._ell = GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k=(n, k)) elif parameters: self._s = parameters[0] self._ell = parameters[1] - (self._tau,_) = GRSGuruswamiSudanDecoder.guruswami_sudan_decoding_radius(C = code, s=self._s, l=self._ell) + (self._tau,_) = GRSGuruswamiSudanDecoder.guruswami_sudan_decoding_radius(C=code, s=self._s, l=self._ell) else: raise ValueError("Specify either tau or parameters") if callable(interpolation_alg): @@ -619,12 +633,12 @@ def __init__(self, code, tau = None, parameters = None, interpolation_alg = None def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = C.decoder("GuruswamiSudan", tau = 97) + sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D Guruswami-Sudan decoder for [250, 70, 181] Reed-Solomon Code over GF(251) decoding 97 errors with parameters (1, 2) """ @@ -632,12 +646,12 @@ def _repr_(self): def _latex_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = C.decoder("GuruswamiSudan", tau = 97) + sage: D = C.decoder("GuruswamiSudan", tau=97) sage: latex(D) \textnormal{Guruswami-Sudan decoder for } [250, 70, 181] \textnormal{ Reed-Solomon Code over } \Bold{F}_{251}\textnormal{ decoding }97\textnormal{ errors with parameters }(1, 2) """ @@ -650,8 +664,8 @@ def __eq__(self, other): EXAMPLES:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D1 = C.decoder("GuruswamiSudan", tau = 97) - sage: D2 = C.decoder("GuruswamiSudan", tau = 97) + sage: D1 = C.decoder("GuruswamiSudan", tau=97) + sage: D2 = C.decoder("GuruswamiSudan", tau=97) sage: D1.__eq__(D2) True """ @@ -665,7 +679,7 @@ def __eq__(self, other): def interpolation_algorithm(self): r""" - Returns the interpolation algorithm that will be used. + Return the interpolation algorithm that will be used. Remember that its signature has to be: ``my_inter(interpolation_points, tau, s_and_l, wy)``. @@ -675,7 +689,7 @@ def interpolation_algorithm(self): EXAMPLES:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = C.decoder("GuruswamiSudan", tau = 97) + sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.interpolation_algorithm() <function gs_interpolation_lee_osullivan at 0x...> """ @@ -683,7 +697,7 @@ def interpolation_algorithm(self): def rootfinding_algorithm(self): r""" - Returns the rootfinding algorithm that will be used. + Return the rootfinding algorithm that will be used. Remember that its signature has to be: ``my_rootfinder(Q, maxd=default_value, precision=default_value)``. @@ -693,7 +707,7 @@ def rootfinding_algorithm(self): EXAMPLES:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = C.decoder("GuruswamiSudan", tau = 97) + sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.rootfinding_algorithm() <function alekhnovich_root_finder at 0x...> """ @@ -701,26 +715,25 @@ def rootfinding_algorithm(self): def parameters(self): r""" - Returns the multiplicity and list size parameters of ``self``. + Return the multiplicity and list size parameters of ``self``. EXAMPLES:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = C.decoder("GuruswamiSudan", tau = 97) + sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.parameters() (1, 2) """ return (self._s, self._ell) - def multiplicity(self): r""" - Returns the multiplicity parameter of ``self``. + Return the multiplicity parameter of ``self``. EXAMPLES:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = C.decoder("GuruswamiSudan", tau = 97) + sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.multiplicity() 1 """ @@ -728,12 +741,12 @@ def multiplicity(self): def list_size(self): r""" - Returns the list size parameter of ``self``. + Return the list size parameter of ``self``. EXAMPLES:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = C.decoder("GuruswamiSudan", tau = 97) + sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.list_size() 2 """ @@ -741,7 +754,7 @@ def list_size(self): def decode_to_message(self, r): r""" - Decodes ``r`` to the list of polynomials whose encoding by + Decode ``r`` to the list of polynomials whose encoding by :meth:`self.code()` is within Hamming distance :meth:`self.decoding_radius` of ``r``. @@ -752,8 +765,9 @@ def decode_to_message(self, r): EXAMPLES:: + sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: C = codes.GeneralizedReedSolomonCode(GF(17).list()[:15], 6) - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, tau=5) + sage: D = GSD(C, tau=5) sage: F.<x> = GF(17)[] sage: m = 13*x^4 + 7*x^3 + 10*x^2 + 14*x + 3 sage: c = D.connected_encoder().encode(m) @@ -772,7 +786,7 @@ def decode_to_message(self, r): does not fit the allowed signature, an exception will be raised:: sage: C = codes.GeneralizedReedSolomonCode(GF(17).list()[:15], 6) - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, tau=5, root_finder=next_prime) + sage: D = GSD(C, tau=5, root_finder=next_prime) sage: F.<x> = GF(17)[] sage: m = 9*x^5 + 10*x^4 + 9*x^3 + 7*x^2 + 15*x + 2 sage: c = D.connected_encoder().encode(m) @@ -780,7 +794,8 @@ def decode_to_message(self, r): sage: m in D.decode_to_message(r) Traceback (most recent call last): ... - ValueError: The provided root-finding algorithm has a wrong signature. See the documentation of `codes.decoders.GRSGuruswamiSudanDecoder.rootfinding_algorithm()` for details + ValueError: The provided root-finding algorithm has a wrong signature. + See the documentation of `...rootfinding_algorithm()` for details """ return [self.connected_encoder().unencode(c) for c in self.decode_to_code(r)] @@ -795,8 +810,9 @@ def decode_to_code(self, r): EXAMPLES:: + sage: GSD = codes.decoders.GRSGuruswamiSudanDecoder sage: C = codes.GeneralizedReedSolomonCode(GF(17).list()[:15], 6) - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, tau=5) + sage: D = GSD(C, tau=5) sage: c = vector(GF(17), [3,13,12,0,0,7,5,1,8,11,1,9,4,12,14]) sage: c in C True @@ -814,7 +830,7 @@ def decode_to_code(self, r): Check that :trac:`21347` is fixed:: sage: C = codes.GeneralizedReedSolomonCode(GF(13).list()[:10], 3) - sage: D = codes.decoders.GRSGuruswamiSudanDecoder(C, tau = 4) + sage: D = GSD(C, tau=4) sage: c = vector(GF(13), [6, 8, 2, 1, 5, 1, 2, 8, 6, 9]) sage: e = vector(GF(13), [1, 0, 0, 1, 1, 0, 0, 1, 0, 1]) sage: D.decode_to_code(c+e) @@ -837,7 +853,7 @@ def decode_to_code(self, r): raise ValueError("The provided interpolation algorithm has a wrong signature. See the documentation of `codes.decoders.GRSGuruswamiSudanDecoder.interpolation_algorithm()` for details") ## EXAMINE THE FACTORS AND CONVERT TO CODEWORDS try: - polynomials = self.rootfinding_algorithm()(Q, maxd = wy) + polynomials = self.rootfinding_algorithm()(Q, maxd=wy) except TypeError: raise ValueError("The provided root-finding algorithm has a wrong signature. See the documentation of `codes.decoders.GRSGuruswamiSudanDecoder.rootfinding_algorithm()` for details") if not polynomials: @@ -850,19 +866,19 @@ def decode_to_code(self, r): def decoding_radius(self): r""" - Returns the maximal number of errors that ``self`` is able to correct. + Return the maximal number of errors that ``self`` is able to correct. EXAMPLES:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = C.decoder("GuruswamiSudan", tau = 97) + sage: D = C.decoder("GuruswamiSudan", tau=97) sage: D.decoding_radius() 97 An example where tau is not one of the inputs to the constructor:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) - sage: D = C.decoder("GuruswamiSudan", parameters = (2,4)) + sage: D = C.decoder("GuruswamiSudan", parameters=(2,4)) sage: D.decoding_radius() 105 """ diff --git a/src/sage/coding/guruswami_sudan/interpolation.py b/src/sage/coding/guruswami_sudan/interpolation.py index e1f9755faa3..8625bae5b49 100644 --- a/src/sage/coding/guruswami_sudan/interpolation.py +++ b/src/sage/coding/guruswami_sudan/interpolation.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings """ Interpolation algorithms for the Guruswami-Sudan decoder @@ -174,6 +175,7 @@ def _interpolation_matrix_problem(points, tau, parameters, wy): - ``tau`` -- an integer, the number of errors one wants to decode. - ``parameters`` -- (default: ``None``) a pair of integers, where: + - the first integer is the multiplicity parameter of Guruswami-Sudan algorithm and - the second integer is the list size parameter. @@ -184,7 +186,7 @@ def _interpolation_matrix_problem(points, tau, parameters, wy): EXAMPLES: The following parameters arise from Guruswami-Sudan decoding of an [6,2,5] - GRS code over F(11) with multiplicity 2 and list size 4. + GRS code over F(11) with multiplicity 2 and list size 4. :: sage: from sage.coding.guruswami_sudan.interpolation import _interpolation_matrix_problem sage: F = GF(11) @@ -222,10 +224,10 @@ def _interpolation_matrix_problem(points, tau, parameters, wy): def gs_interpolation_linalg(points, tau, parameters, wy): r""" - Compute an interpolation polynomial Q(x,y) for the Guruswami-Sudan algorithm + Compute an interpolation polynomial `Q(x,y)` for the Guruswami-Sudan algorithm by solving a linear system of equations. - ``Q`` is a bivariate polynomial over the field of the points, such that the + `Q` is a bivariate polynomial over the field of the points, such that the polynomial has a zero of multiplicity at least `s` at each of the points, where `s` is the multiplicity parameter. Furthermore, its ``(1, wy)``-weighted degree should be less than @@ -240,11 +242,13 @@ def gs_interpolation_linalg(points, tau, parameters, wy): - ``tau`` -- an integer, the number of errors one wants to decode. - ``parameters`` -- (default: ``None``) a pair of integers, where: - - the first integer is the multiplicity parameter of Guruswami-Sudan algorithm and - - the second integer is the list size parameter. - - ``wy`` -- an integer, the `y`-weight, where we seek ``Q`` of low - ``(1,wy)`` weighted degree. + - the first integer is the multiplicity parameter of Guruswami-Sudan + algorithm and + - the second integer is the list size parameter. + + - ``wy`` -- an integer, the `y`-weight, where we seek `Q` of low + ``(1, wy)``-weighted degree. EXAMPLES: @@ -253,12 +257,14 @@ def gs_interpolation_linalg(points, tau, parameters, wy): sage: from sage.coding.guruswami_sudan.interpolation import gs_interpolation_linalg sage: F = GF(11) - sage: points = [(F(x),F(y)) for (x,y) in [(0, 5), (1, 1), (2, 4), (3, 6), (4, 3), (5, 3)]] + sage: points = [(F(x), F(y)) + ....: for (x, y) in [(0, 5), (1, 1), (2, 4), (3, 6), (4, 3), (5, 3)]] sage: tau = 3 sage: params = (2, 4) sage: wy = 1 sage: Q = gs_interpolation_linalg(points, tau, params, wy); Q - 4*x^5 - 4*x^4*y - 2*x^2*y^3 - x*y^4 + 3*x^4 - 4*x^2*y^2 + 5*y^4 - x^3 + x^2*y + 5*x*y^2 - 5*y^3 + 3*x*y - 2*y^2 + x - 4*y + 1 + 4*x^5 - 4*x^4*y - 2*x^2*y^3 - x*y^4 + 3*x^4 - 4*x^2*y^2 + 5*y^4 - x^3 + x^2*y + + 5*x*y^2 - 5*y^3 + 3*x*y - 2*y^2 + x - 4*y + 1 We verify that the interpolation polynomial has a zero of multiplicity at least 2 in each point:: @@ -286,7 +292,7 @@ def gs_interpolation_linalg(points, tau, parameters, wy): def lee_osullivan_module(points, parameters, wy): r""" - Returns the analytically straight-forward basis for the `\GF q[x]` module + Return the analytically straight-forward basis for the `\GF{q}[x]` module containing all interpolation polynomials, as according to Lee and O'Sullivan. @@ -294,7 +300,7 @@ def lee_osullivan_module(points, parameters, wy): interpolation polynomial through the sought interpolation points `(x_i, y_i)`, i.e. `R(x_i) = y_i`. Let `G(x) = \prod_{i=1}^n (x-x_i)`. Then the `i`'th row of the basis matrix of the module is the coefficient-vector of - the following polynomial in `\GF q[x][y]`: + the following polynomial in `\GF{q}[x][y]`: `P_i(x,y) = G(x)^{[i-s]} (y - R(x))^{i - [i-s]} y^{[i-s]}` , @@ -305,22 +311,24 @@ def lee_osullivan_module(points, parameters, wy): INPUT: - - ``points`` -- a list of tuples ``(xi, yi)`` such that we seek ``Q`` with - ``(xi,yi)`` being a root of ``Q`` with multiplicity ``s``. + - ``points`` -- a list of tuples ``(xi, yi)`` such that we seek `Q` with + ``(xi,yi)`` being a root of `Q` with multiplicity `s`. - ``parameters`` -- (default: ``None``) a pair of integers, where: - - the first integer is the multiplicity parameter `s` of Guruswami-Sudan algorithm and - - the second integer is the list size parameter. - - ``wy`` -- an integer, the `y`-weight, where we seek ``Q`` of low + - the first integer is the multiplicity parameter `s` of Guruswami-Sudan + algorithm and + - the second integer is the list size parameter. + + - ``wy`` -- an integer, the `y`-weight, where we seek `Q` of low ``(1,wy)`` weighted degree. EXAMPLES:: sage: from sage.coding.guruswami_sudan.interpolation import lee_osullivan_module sage: F = GF(11) - sage: points = [(F(0), F(2)), (F(1), F(5)), (F(2), F(0)), (F(3), F(4)), (F(4), F(9))\ - , (F(5), F(1)), (F(6), F(9)), (F(7), F(10))] + sage: points = [(F(0), F(2)), (F(1), F(5)), (F(2), F(0)), (F(3), F(4)), + ....: (F(4), F(9)), (F(5), F(1)), (F(6), F(9)), (F(7), F(10))] sage: params = (1, 1) sage: wy = 1 sage: lee_osullivan_module(points, params, wy) @@ -363,8 +371,10 @@ def gs_interpolation_lee_osullivan(points, tau, parameters, wy): - ``tau`` -- an integer, the number of errors one wants to decode. - ``parameters`` -- (default: ``None``) a pair of integers, where: - - the first integer is the multiplicity parameter of Guruswami-Sudan algorithm and - - the second integer is the list size parameter. + + - the first integer is the multiplicity parameter of Guruswami-Sudan + algorithm and + - the second integer is the list size parameter. - ``wy`` -- an integer, the `y`-weight, where we seek ``Q`` of low ``(1,wy)`` weighted degree. @@ -373,13 +383,13 @@ def gs_interpolation_lee_osullivan(points, tau, parameters, wy): sage: from sage.coding.guruswami_sudan.interpolation import gs_interpolation_lee_osullivan sage: F = GF(11) - sage: points = [(F(0), F(2)), (F(1), F(5)), (F(2), F(0)), (F(3), F(4)), (F(4), F(9))\ - , (F(5), F(1)), (F(6), F(9)), (F(7), F(10))] + sage: points = [(F(0), F(2)), (F(1), F(5)), (F(2), F(0)), (F(3), F(4)), + ....: (F(4), F(9)), (F(5), F(1)), (F(6), F(9)), (F(7), F(10))] sage: tau = 1 sage: params = (1, 1) sage: wy = 1 sage: Q = gs_interpolation_lee_osullivan(points, tau, params, wy) - sage: Q / Q.lc() # make monic + sage: Q / Q.lc() # make monic x^3*y + 2*x^3 - x^2*y + 5*x^2 + 5*x*y - 5*x + 2*y - 4 """ from .utils import _degree_of_vector diff --git a/src/sage/coding/guruswami_sudan/utils.py b/src/sage/coding/guruswami_sudan/utils.py index d53637d933f..d899bd0e12e 100644 --- a/src/sage/coding/guruswami_sudan/utils.py +++ b/src/sage/coding/guruswami_sudan/utils.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Guruswami-Sudan utility methods diff --git a/src/sage/coding/hamming_code.py b/src/sage/coding/hamming_code.py index cf355c2431f..5209a0c3754 100644 --- a/src/sage/coding/hamming_code.py +++ b/src/sage/coding/hamming_code.py @@ -1,7 +1,8 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Hamming codes -Given an integer `r` and a field `F`, such that `F=GF(q)`, the `[n, k, d]` code +Given an integer `r` and a field `F`, such that `F=\GF{q}`, the `[n, k, d]` code with length `n=\frac{q^{r}-1}{q-1}`, dimension `k=\frac{q^{r}-1}{q-1} - r` and minimum distance `d=3` is called the Hamming Code of order `r`. diff --git a/src/sage/coding/information_set_decoder.py b/src/sage/coding/information_set_decoder.py index a2cbf94fc5e..5d4d28a7c47 100644 --- a/src/sage/coding/information_set_decoder.py +++ b/src/sage/coding/information_set_decoder.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Information-set decoding for linear codes @@ -40,7 +40,11 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.all import ZZ, Integer, vector, SageObject, binomial +from sage.rings.integer_ring import ZZ +from sage.rings.integer import Integer +from sage.modules.free_module_element import free_module_element as vector +from sage.structure.sage_object import SageObject +from sage.functions.other import binomial from .decoder import Decoder @@ -92,7 +96,8 @@ class InformationSetAlgorithm(SageObject): sage: from sage.coding.information_set_decoder import LeeBrickellISDAlgorithm sage: LeeBrickellISDAlgorithm(codes.GolayCode(GF(2)), (0,4)) - ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) decoding up to 4 errors + ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) + decoding up to 4 errors A minimal working example of how to sub-class:: @@ -108,10 +113,11 @@ class InformationSetAlgorithm(SageObject): ....: # decoding algorithm here ....: raise DecodingError("I failed") sage: MinimalISD(codes.GolayCode(GF(2)), (0,4)) - ISD Algorithm (MinimalISD) for [24, 12, 8] Extended Golay code over GF(2) decoding up to 4 errors + ISD Algorithm (MinimalISD) for [24, 12, 8] Extended Golay code over GF(2) + decoding up to 4 errors """ - def __init__(self, code, decoding_interval, algorithm_name, parameters = None): + def __init__(self, code, decoding_interval, algorithm_name, parameters=None): r""" TESTS:: @@ -341,8 +347,6 @@ def _latex_(self): return "\\textnormal{{ISD Algorithm ({}) for }}{} \\textnormal{{decoding {} errors}}".format(self._algorithm_name, self.code()._latex_(), _format_decoding_interval(self.decoding_interval())) - - class LeeBrickellISDAlgorithm(InformationSetAlgorithm): r""" The Lee-Brickell algorithm for information-set decoding. @@ -353,7 +357,7 @@ class LeeBrickellISDAlgorithm(InformationSetAlgorithm): This implements the Lee-Brickell variant of ISD, see [LB1988]_ for the original binary case, and [Pet2010]_ for the `q`-ary extension. - Let `C` be a `[n, k]`-linear code over `GF(q)`, and let `r \in GF(q)^{n}` be + Let `C` be a `[n, k]`-linear code over `\GF{q}`, and let `r \in \GF{q}^{n}` be a received word in a transmission. We seek the codeword whose Hamming distance from `r` is minimal. Let `p` and `w` be integers, such that `0\leq p\leq w`, Let `G` be a generator matrix of `C`, and for any set of indices @@ -361,10 +365,10 @@ class LeeBrickellISDAlgorithm(InformationSetAlgorithm): `I`. The Lee-Brickell ISD loops the following until it is successful: 1. Choose an information set `I` of `C`. - 2. Compute `r' = r - r_{I}\times G_I^{-1} \times G` + 2. Compute `r' = r - r_{I} G_I^{-1} G` 3. Consider every size-`p` subset of `I`, `\{a_1, \dots, a_p\}`. - For each `m = (m_1, \dots, m_p) \in GF(q)^{p}`, compute - the error vector `e = r' - \sum_{i=1}^{p} m_i\times g_{a_i}`, + For each `m = (m_1, \dots, m_p) \in \GF{q}^{p}`, compute + the error vector `e = r' - \sum_{i=1}^{p} m_i g_{a_i}`, 4. If `e` has a Hamming weight at most `w`, return `r-e`. INPUT: @@ -386,13 +390,15 @@ class LeeBrickellISDAlgorithm(InformationSetAlgorithm): sage: C = codes.GolayCode(GF(2)) sage: from sage.coding.information_set_decoder import LeeBrickellISDAlgorithm sage: A = LeeBrickellISDAlgorithm(C, (0,4)); A - ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) decoding up to 4 errors + ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) + decoding up to 4 errors sage: C = codes.GolayCode(GF(2)) sage: A = LeeBrickellISDAlgorithm(C, (2,3)); A - ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) decoding between 2 and 3 errors + ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) + decoding between 2 and 3 errors """ - def __init__(self, code, decoding_interval, search_size = None): + def __init__(self, code, decoding_interval, search_size=None): r""" TESTS: @@ -475,16 +481,16 @@ def decode(self, r): # I was not an information set continue Gt = Gi_inv * G - #step 2. + # step 2. y = r - vector([r[i] for i in I]) * Gt g = Gt.rows() - #step 3. - for pi in range(p+1): + # step 3. + for pi in range(p + 1): for A in itertools.combinations(range(k), pi): for m in itertools.product(Fstar, repeat=pi): - e = y - sum(m[i]*g[A[i]] for i in range(pi)) + e = y - sum(m[i] * g[A[i]] for i in range(pi)) errs = e.hamming_weight() - if errs >= tau[0] and errs <= tau[1]: + if tau[0] <= errs <= tau[1]: return r - e def calibrate(self): @@ -523,7 +529,8 @@ def calibrate(self): sage: from sage.coding.information_set_decoder import LeeBrickellISDAlgorithm sage: C = codes.GolayCode(GF(2)) sage: A = LeeBrickellISDAlgorithm(C, (0,3)); A - ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) decoding up to 3 errors + ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) + decoding up to 3 errors sage: A.calibrate() sage: A.parameters() #random {'search_size': 1} @@ -533,7 +540,8 @@ def calibrate(self): If we specify the parameter at construction time, calibrate does not override this choice:: sage: A = LeeBrickellISDAlgorithm(C, (0,3), search_size=2); A - ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) decoding up to 3 errors + ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) + decoding up to 3 errors sage: A.parameters() {'search_size': 2} sage: A.calibrate() @@ -581,7 +589,7 @@ def time_search_loop(p): def compute_estimate(p): iters = 1.* binomial(n, k)/ \ sum( binomial(n-tau, k-i)*binomial(tau,i) for i in range(p+1) ) - estimate = iters*(T + \ + estimate = iters*(T + sum(P[pi] * (q-1)**pi * binomial(k, pi) for pi in range(p+1) )) return estimate @@ -625,8 +633,6 @@ def _calibrate_select(self, estimates): self._time_estimate = estimates[search_size] - - class LinearCodeInformationSetDecoder(Decoder): r""" Information-set decoder for any linear code. @@ -693,16 +699,19 @@ class LinearCodeInformationSetDecoder(Decoder): sage: C = codes.GolayCode(GF(3)) sage: D = C.decoder("InformationSet", 2); D - Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) decoding up to 2 errors + Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) + decoding up to 2 errors You can specify which algorithm you wish to use, and you should do so in order to pass special parameters to it:: sage: C = codes.GolayCode(GF(3)) sage: D2 = C.decoder("InformationSet", 2, algorithm="Lee-Brickell", search_size=2); D2 - Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) decoding up to 2 errors + Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) + decoding up to 2 errors sage: D2.algorithm() - ISD Algorithm (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) decoding up to 2 errors + ISD Algorithm (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) + decoding up to 2 errors sage: D2.algorithm().parameters() {'search_size': 2} @@ -711,7 +720,8 @@ class LinearCodeInformationSetDecoder(Decoder): sage: C.decoder("InformationSet", 2, algorithm="NoSuchThing") Traceback (most recent call last): ... - ValueError: Unknown ISD algorithm 'NoSuchThing'. The known algorithms are ['Lee-Brickell']. + ValueError: Unknown ISD algorithm 'NoSuchThing'. + The known algorithms are ['Lee-Brickell']. You can also construct an ISD algorithm separately and pass that. This is mostly useful if you write your own ISD algorithms:: @@ -719,7 +729,8 @@ class LinearCodeInformationSetDecoder(Decoder): sage: from sage.coding.information_set_decoder import LeeBrickellISDAlgorithm sage: A = LeeBrickellISDAlgorithm(C, (0, 2)) sage: D = C.decoder("InformationSet", 2, algorithm=A); D - Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) decoding up to 2 errors + Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) + decoding up to 2 errors When passing an already constructed ISD algorithm, you can't also pass parameters to the ISD algorithm when constructing the decoder:: @@ -727,22 +738,26 @@ class LinearCodeInformationSetDecoder(Decoder): sage: C.decoder("InformationSet", 2, algorithm=A, search_size=2) Traceback (most recent call last): ... - ValueError: ISD algorithm arguments are not allowed when supplying a constructed ISD algorithm + ValueError: ISD algorithm arguments are not allowed + when supplying a constructed ISD algorithm We can also information-set decode non-binary codes:: sage: C = codes.GolayCode(GF(3)) sage: D = C.decoder("InformationSet", 2); D - Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) decoding up to 2 errors + Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) + decoding up to 2 errors There are two other ways to access this class:: sage: D = codes.decoders.LinearCodeInformationSetDecoder(C, 2); D - Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) decoding up to 2 errors + Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) + decoding up to 2 errors sage: from sage.coding.information_set_decoder import LinearCodeInformationSetDecoder sage: D = LinearCodeInformationSetDecoder(C, 2); D - Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) decoding up to 2 errors + Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) + decoding up to 2 errors """ def __init__(self, code, number_errors, algorithm=None, **kwargs): r""" @@ -846,7 +861,7 @@ def __init__(self, code, number_errors, algorithm=None, **kwargs): self._algorithm = algorithm_names[algorithm](code, number_errors, **kwargs) else: raise ValueError("Unknown ISD algorithm '{}'." - " The known algorithms are {}."\ + " The known algorithms are {}." .format(algorithm, sorted(algorithm_names))) _known_algorithms = { @@ -889,7 +904,8 @@ def algorithm(self): sage: C = codes.GolayCode(GF(2)) sage: D = C.decoder("InformationSet", (2,4), "Lee-Brickell") sage: D.algorithm() - ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) decoding between 2 and 4 errors + ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) + decoding between 2 and 4 errors """ return self._algorithm diff --git a/src/sage/coding/kasami_codes.pyx b/src/sage/coding/kasami_codes.pyx index 8212ae29ded..4c35ed34e33 100644 --- a/src/sage/coding/kasami_codes.pyx +++ b/src/sage/coding/kasami_codes.pyx @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Kasami code @@ -9,10 +9,10 @@ The extended Kasami code with parameters `(s,t)` is defined as .. MATH:: - \{ v \in GF(2)^s \mid - \sum_{a \in GF(s)} v_a = - \sum_{a \in GF(s)} a v_a = - \sum_{a \in GF(s)} a^{t+1} v_a = 0 \} + \{ v \in \GF{2}^s \mid + \sum_{a \in \GF{s}} v_a = + \sum_{a \in \GF{s}} a v_a = + \sum_{a \in \GF{s}} a^{t+1} v_a = 0 \} It follows that these are subfield subcodes of the code having those three @@ -73,16 +73,16 @@ class KasamiCode(AbstractLinearCode): .. MATH:: - \{ v \in GF(2)^s \mid - \sum_{a \in GF(s)} v_a = - \sum_{a \in GF(s)} a v_a = - \sum_{a \in GF(s)} a^{t+1} v_a = 0 \} + \{ v \in \GF{2}^s \mid + \sum_{a \in \GF{s}} v_a = + \sum_{a \in \GF{s}} a v_a = + \sum_{a \in \GF{s}} a^{t+1} v_a = 0 \} The only valid parameters `s,t` are given by the below, where `q` is a power of 2: - * `s = q^{2j+1}`, `t = q^m` with `m \leq j` and `\gcd(m,2j+1) = 1` - * `s = q^2`, `t=q` + * `s = q^{2j+1}`, `t = q^m` with `m \leq j` and `\gcd(m,2j+1) = 1` + * `s = q^2`, `t=q` The Kasami code `(s,t)` is obtained from the extended Kasami code `(s,t)`, via truncation of all words. @@ -294,7 +294,7 @@ class KasamiCode(AbstractLinearCode): We build the parity check matrix given by the three equations that the codewords must satisfy. Then we generate the parity check matrix - over `GF(2)` and from this the obtain the generator matrix for the + over `\GF{2}` and from this the obtain the generator matrix for the extended Kasami codes. For the Kasami codes, we truncate the last column. diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index a3ac3ca1547..ac1581f2691 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Generic structures for linear codes over the Hamming metric @@ -205,32 +205,36 @@ class should inherit from this class. Also ``AbstractLinearCode`` should never import os import subprocess -from io import StringIO from copy import copy +from io import StringIO -from sage.cpython.string import bytes_to_str +from sage.arith.misc import binomial, GCD from sage.categories.cartesian_product import cartesian_product from sage.categories.fields import Fields +from sage.coding.decoder import Decoder +from sage.coding.encoder import Encoder +from sage.coding.linear_code_no_metric import AbstractLinearCodeNoMetric +from sage.combinat.subset import Subsets +from sage.cpython.string import bytes_to_str +from sage.features.gap import GapPackage from sage.matrix.matrix_space import MatrixSpace +from sage.misc.cachefunc import cached_method +from sage.misc.functional import is_even +from sage.misc.lazy_import import lazy_import +from sage.misc.misc_c import prod +from sage.misc.randstate import current_randstate from sage.modules.free_module import VectorSpace from sage.modules.free_module_element import vector -from sage.arith.all import GCD, binomial -from sage.groups.all import SymmetricGroup -from sage.groups.perm_gps.permgroup import PermutationGroup -from sage.rings.rational_field import QQ +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.integer import Integer -from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from sage.misc.misc_c import prod -from sage.misc.functional import is_even -from sage.misc.cachefunc import cached_method -from sage.misc.randstate import current_randstate -from sage.combinat.subset import Subsets -from sage.features.gap import GapPackage -from sage.coding.linear_code_no_metric import AbstractLinearCodeNoMetric -from .encoder import Encoder -from .decoder import Decoder +from sage.rings.rational_field import QQ + +lazy_import('sage.groups.perm_gps.permgroup_named', 'SymmetricGroup') +lazy_import('sage.groups.perm_gps.permgroup', 'PermutationGroup') +lazy_import('sage.interfaces.gap', 'gap') + # ***************************************************************************** # coding theory functions @@ -294,9 +298,9 @@ class AbstractLinearCode(AbstractLinearCodeNoMetric): To implement a linear code, you need to: - - inherit from AbstractLinearCode + - inherit from :class:`AbstractLinearCode` - - call AbstractLinearCode ``__init__`` method in the subclass constructor. Example: + - call :class:`AbstractLinearCode` ``__init__`` method in the subclass constructor. Example: ``super().__init__(base_field, length, "EncoderName", "DecoderName")``. By doing that, your subclass will have its ``length`` parameter initialized and will be properly set as a member of the category framework. @@ -324,7 +328,7 @@ class AbstractLinearCode(AbstractLinearCodeNoMetric): ``MyNewCodeClass`` will be able to use instances of ``MyDecoderClass``. - As AbstractLinearCode is not designed to be implemented, it does not have any representation + As the class :class:`AbstractLinearCode` is not designed to be instantiated, it does not have any representation methods. You should implement ``_repr_`` and ``_latex_`` methods in the subclass. .. NOTE:: @@ -373,7 +377,8 @@ def __init__(self, base_field, length, default_encoder_name, default_decoder_nam sage: class MyCodeFamily(sage.coding.linear_code.AbstractLinearCode): ....: def __init__(self, field, length, dimension, generator_matrix): - ....: sage.coding.linear_code.AbstractLinearCode.__init__(self,field, length, "GeneratorMatrix", "Syndrome") + ....: super().__init__(field, length, + ....: "GeneratorMatrix", "Syndrome") ....: self._dimension = dimension ....: self._generator_matrix = generator_matrix ....: def generator_matrix(self): @@ -405,7 +410,7 @@ def __init__(self, base_field, length, default_encoder_name, default_decoder_nam 1 sage: C.is_self_orthogonal() False - sage: print(C.divisor()) #long time + sage: print(C.divisor()) #long time 1 """ from sage.coding.information_set_decoder import LinearCodeInformationSetDecoder @@ -444,11 +449,11 @@ def automorphism_group_gens(self, equivalence="semilinear"): - ``equivalence`` (optional) -- which defines the acting group, either - * ``permutational`` + * ``"permutational"`` - * ``linear`` + * ``"linear"`` - * ``semilinear`` + * ``"semilinear"`` OUTPUT: @@ -461,34 +466,59 @@ def automorphism_group_gens(self, equivalence="semilinear"): depends on which packages are loaded, so we must re-seed GAP to ensure a consistent result for this example:: - sage: libgap.set_seed(0) + sage: libgap.set_seed(0) # optional - sage.libs.gap 0 sage: C = codes.HammingCode(GF(4, 'z'), 3) sage: C.automorphism_group_gens() - ([((1, 1, 1, 1, 1, z + 1, z, z + 1, z, z, z, 1, 1, z + 1, z + 1, z, z + 1, z, z + 1, z + 1, z + 1); (1,14,6,7,4,10,11,19)(2,8,16,13,3,17,21,15)(9,12,18,20), Ring endomorphism of Finite Field in z of size 2^2 - Defn: z |--> z + 1), - ((z + 1, 1, 1, z, z + 1, z, z, z + 1, z + 1, z + 1, 1, z + 1, z, z, 1, z + 1, 1, z, z + 1, z + 1, z); (1,18,6,19,2,9,17,10,13,14,21,11,4,5,12)(3,20,7,16,8), Ring endomorphism of Finite Field in z of size 2^2 - Defn: z |--> z), - ((z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z); (), Ring endomorphism of Finite Field in z of size 2^2 - Defn: z |--> z)], + ([((1, 1, 1, z, z + 1, 1, 1, 1, 1, z + 1, z, z, z + 1, z + 1, + z + 1, 1, z + 1, z, z, 1, z); + (1,13,14,20)(2,21,8,18,7,16,19,15)(3,10,5,12,17,9,6,4), + Ring endomorphism of Finite Field in z of size 2^2 + Defn: z |--> z + 1), + ((z, 1, z, z, z, z + 1, z, z, z, z, z, z, z + 1, z, z, z, + z, z + 1, z, z, z); + (1,11,5,12,3,19)(2,8)(6,18,13)(7,17,15)(9,10,14,16,20,21), + Ring endomorphism of Finite Field in z of size 2^2 + Defn: z |--> z + 1), + ((z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z); + (), + Ring endomorphism of Finite Field in z of size 2^2 + Defn: z |--> z)], 362880) sage: C.automorphism_group_gens(equivalence="linear") - ([((z + 1, 1, z + 1, z + 1, z + 1, z, 1, z, 1, 1, 1, 1, z + 1, z + 1, z + 1, z, z, 1, z, z, z); (1,15,2,8,16,18,3)(4,9,12,13,20,10,11)(5,21,14,6,7,19,17), Ring endomorphism of Finite Field in z of size 2^2 - Defn: z |--> z), - ((z + 1, z + 1, z + 1, z + 1, z + 1, 1, z, 1, z, z, z, 1, z, 1, 1, 1, z + 1, z + 1, z + 1, 1, z); (1,15,21,8,9)(2,18,5,3,11,16,7,10,19,13,12,4,17,6,20), Ring endomorphism of Finite Field in z of size 2^2 - Defn: z |--> z), - ((z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1); (), Ring endomorphism of Finite Field in z of size 2^2 - Defn: z |--> z)], + ([((z, 1, z + 1, z + 1, 1, z + 1, z, 1, z + 1, z + 1, 1, z, 1, z + 1, + z, 1, z, 1, z + 1, 1, 1); + (1,12,11,10,6,8,9,20,13,21,5,14,3,16,17,19,7,4,2,15,18), + Ring endomorphism of Finite Field in z of size 2^2 + Defn: z |--> z), + ((z + 1, z + 1, z + 1, z, 1, 1, z, z, 1, z + 1, z, 1, 1, z, 1, z + 1, + z, z + 1, z + 1, 1, z); + (1,3,18,2,17,6,19)(4,15,13,20,7,14,16)(5,11,8,21,12,9,10), + Ring endomorphism of Finite Field in z of size 2^2 + Defn: z |--> z), + ((z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, + z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1); + (), + Ring endomorphism of Finite Field in z of size 2^2 + Defn: z |--> z)], 181440) sage: C.automorphism_group_gens(equivalence="permutational") - ([((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); (1,19)(3,17)(4,21)(5,20)(7,14)(9,12)(10,16)(11,15), Ring endomorphism of Finite Field in z of size 2^2 - Defn: z |--> z), - ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); (1,11)(3,10)(4,9)(5,7)(12,21)(14,20)(15,19)(16,17), Ring endomorphism of Finite Field in z of size 2^2 - Defn: z |--> z), - ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); (1,17)(2,8)(3,14)(4,10)(7,12)(9,19)(13,18)(15,20), Ring endomorphism of Finite Field in z of size 2^2 - Defn: z |--> z), - ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); (2,13)(3,14)(4,20)(5,11)(8,18)(9,19)(10,15)(16,21), Ring endomorphism of Finite Field in z of size 2^2 - Defn: z |--> z)], + ([((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + (1,11)(3,10)(4,9)(5,7)(12,21)(14,20)(15,19)(16,17), + Ring endomorphism of Finite Field in z of size 2^2 + Defn: z |--> z), + ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + (2,18)(3,19)(4,10)(5,16)(8,13)(9,14)(11,21)(15,20), + Ring endomorphism of Finite Field in z of size 2^2 + Defn: z |--> z), + ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + (1,19)(3,17)(4,21)(5,20)(7,14)(9,12)(10,16)(11,15), + Ring endomorphism of Finite Field in z of size 2^2 + Defn: z |--> z), + ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + (2,13)(3,14)(4,20)(5,11)(8,18)(9,19)(10,15)(16,21), + Ring endomorphism of Finite Field in z of size 2^2 + Defn: z |--> z)], 64) """ aut_group_can_label = self._canonize(equivalence) @@ -548,7 +578,7 @@ def assmus_mattson_designs(self, t, mode=None): `C=C^*` in this case, so this info is extraneous). The test fails to produce 6-designs (ie, the hypotheses of the theorem fail to hold, not that the 6-designs definitely don't exist). The command - assmus_mattson_designs(C,5,mode="verbose") returns the same value + ``assmus_mattson_designs(C,5,mode="verbose")`` returns the same value but prints out more detailed information. The second example below illustrates the blocks of the 5-(24, 8, 1) @@ -558,17 +588,14 @@ def assmus_mattson_designs(self, t, mode=None): sage: C = codes.GolayCode(GF(2)) # example 1 sage: C.assmus_mattson_designs(5) - ['weights from C: ', - [8, 12, 16, 24], - 'designs from C: ', - [[5, (24, 8, 1)], [5, (24, 12, 48)], [5, (24, 16, 78)], [5, (24, 24, 1)]], - 'weights from C*: ', - [8, 12, 16], - 'designs from C*: ', - [[5, (24, 8, 1)], [5, (24, 12, 48)], [5, (24, 16, 78)]]] + ['weights from C: ', [8, 12, 16, 24], + 'designs from C: ', [[5, (24, 8, 1)], [5, (24, 12, 48)], [5, (24, 16, 78)], + [5, (24, 24, 1)]], + 'weights from C*: ', [8, 12, 16], + 'designs from C*: ', [[5, (24, 8, 1)], [5, (24, 12, 48)], [5, (24, 16, 78)]]] sage: C.assmus_mattson_designs(6) 0 - sage: X = range(24) # example 2 + sage: X = range(24) # example 2 sage: blocks = [c.support() for c in C if c.hamming_weight()==8]; len(blocks) # long time computation 759 """ @@ -618,7 +645,7 @@ def binomial_moment(self, i): where `k_S` is the dimension of the shortened code `C_{J-S}`, `J=[1,2,...,n]`. (The normalized binomial moment is - `b_i(C) = \binom(n,d+i)^{-1}B_{d+i}(C)`.) In other words, `C_{J-S}` + `b_i(C) = \binom{n}{d+i})^{-1}B_{d+i}(C)`.) In other words, `C_{J-S}` is isomorphic to the subcode of C of codewords supported on S. EXAMPLES:: @@ -691,10 +718,10 @@ def _canonize(self, equivalence): sage: C_iso == aut_group_can_label.get_canonical_form() True sage: aut_group_can_label.get_autom_gens() - [((1, 1, 1, 1, 1, z + 1, z, z + 1, z, z, z, 1, 1, z + 1, z + 1, z, z + 1, z, z + 1, z + 1, z + 1); (1,14,6,7,4,10,11,19)(2,8,16,13,3,17,21,15)(9,12,18,20), Ring endomorphism of Finite Field in z of size 2^2 + [((1, 1, 1, z, z + 1, 1, 1, 1, 1, z + 1, z, z, z + 1, z + 1, z + 1, 1, z + 1, z, z, 1, z); (1,13,14,20)(2,21,8,18,7,16,19,15)(3,10,5,12,17,9,6,4), Ring endomorphism of Finite Field in z of size 2^2 + Defn: z |--> z + 1), + ((z, 1, z, z, z, z + 1, z, z, z, z, z, z, z + 1, z, z, z, z, z + 1, z, z, z); (1,11,5,12,3,19)(2,8)(6,18,13)(7,17,15)(9,10,14,16,20,21), Ring endomorphism of Finite Field in z of size 2^2 Defn: z |--> z + 1), - ((z + 1, 1, 1, z, z + 1, z, z, z + 1, z + 1, z + 1, 1, z + 1, z, z, 1, z + 1, 1, z, z + 1, z + 1, z); (1,18,6,19,2,9,17,10,13,14,21,11,4,5,12)(3,20,7,16,8), Ring endomorphism of Finite Field in z of size 2^2 - Defn: z |--> z), ((z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z); (), Ring endomorphism of Finite Field in z of size 2^2 Defn: z |--> z)] """ @@ -716,11 +743,11 @@ def canonical_representative(self, equivalence="semilinear"): - ``equivalence`` (optional) -- which defines the acting group, either - * ``permutational`` + * ``"permutational"`` - * ``linear`` + * ``"linear"`` - * ``semilinear`` + * ``"semilinear"`` OUTPUT: @@ -883,15 +910,15 @@ def covering_radius(self): EXAMPLES:: sage: C = codes.HammingCode(GF(2), 5) - sage: C.covering_radius() # optional - gap_packages (Guava package) - ... - 1 + sage: C.covering_radius() # optional - gap_package_guava + ...1 sage: C = codes.random_linear_code(GF(263), 5, 1) - sage: C.covering_radius() # optional - gap_packages (Guava package) + sage: C.covering_radius() # optional - gap_package_guava Traceback (most recent call last): ... - NotImplementedError: the GAP algorithm that Sage is using is limited to computing with fields of size at most 256 + NotImplementedError: the GAP algorithm that Sage is using + is limited to computing with fields of size at most 256 """ from sage.libs.gap.libgap import libgap GapPackage("guava", spkg="gap_packages").require() @@ -918,7 +945,7 @@ def divisor(self): sage: C = codes.GolayCode(GF(2)) sage: C.divisor() # Type II self-dual 4 - sage: C = codes.QuadraticResidueCodeEvenPair(17,GF(2))[0] + sage: C = codes.QuadraticResidueCodeEvenPair(17, GF(2))[0] sage: C.divisor() 2 """ @@ -951,7 +978,7 @@ def is_projective(self): A non-projective code:: - sage: C = codes.LinearCode(matrix(GF(2),[[1,0,1],[1,1,1]])) + sage: C = codes.LinearCode(matrix(GF(2), [[1,0,1],[1,1,1]])) sage: C.is_projective() False """ @@ -1064,23 +1091,23 @@ def product_code(self, other): Note that the two codes have to be over the same field. - EXAMPLES:: - - sage: C = codes.HammingCode(GF(2), 3) - sage: C - [7, 4] Hamming Code over GF(2) - sage: D = codes.ReedMullerCode(GF(2), 2, 2) - sage: D - Binary Reed-Muller Code of order 2 and number of variables 2 - sage: A = C.product_code(D) - sage: A - [28, 16] linear code over GF(2) - sage: A.length() == C.length()*D.length() - True - sage: A.dimension() == C.dimension()*D.dimension() - True - sage: A.minimum_distance() == C.minimum_distance()*D.minimum_distance() - True + EXAMPLES:: + + sage: C = codes.HammingCode(GF(2), 3) + sage: C + [7, 4] Hamming Code over GF(2) + sage: D = codes.ReedMullerCode(GF(2), 2, 2) + sage: D + Binary Reed-Muller Code of order 2 and number of variables 2 + sage: A = C.product_code(D) + sage: A + [28, 16] linear code over GF(2) + sage: A.length() == C.length()*D.length() + True + sage: A.dimension() == C.dimension()*D.dimension() + True + sage: A.minimum_distance() == C.minimum_distance()*D.minimum_distance() + True """ G1 = self.generator_matrix() @@ -1101,29 +1128,29 @@ def construction_x(self, other, aux): The method will then return a `[n+n_a, k_1, d_a+d_1]` linear code. - EXAMPLES:: - - sage: C = codes.BCHCode(GF(2),15,7) - sage: C - [15, 5] BCH Code over GF(2) with designed distance 7 - sage: D = codes.BCHCode(GF(2),15,5) - sage: D - [15, 7] BCH Code over GF(2) with designed distance 5 - sage: C.is_subcode(D) - True - sage: C.minimum_distance() - 7 - sage: D.minimum_distance() - 5 - sage: aux = codes.HammingCode(GF(2),2) - sage: aux = aux.dual_code() - sage: aux.minimum_distance() - 2 - sage: Cx = D.construction_x(C,aux) - sage: Cx - [18, 7] linear code over GF(2) - sage: Cx.minimum_distance() - 7 + EXAMPLES:: + + sage: C = codes.BCHCode(GF(2),15,7) + sage: C + [15, 5] BCH Code over GF(2) with designed distance 7 + sage: D = codes.BCHCode(GF(2),15,5) + sage: D + [15, 7] BCH Code over GF(2) with designed distance 5 + sage: C.is_subcode(D) + True + sage: C.minimum_distance() + 7 + sage: D.minimum_distance() + 5 + sage: aux = codes.HammingCode(GF(2),2) + sage: aux = aux.dual_code() + sage: aux.minimum_distance() + 2 + sage: Cx = D.construction_x(C,aux) + sage: Cx + [18, 7] linear code over GF(2) + sage: Cx.minimum_distance() + 7 """ if not other.is_subcode(self): raise ValueError("%s is not a subcode of %s" % (self, other)) @@ -1149,12 +1176,12 @@ def construction_x(self, other, aux): def extended_code(self): r""" - Return `self` as an extended code. + Return ``self`` as an extended code. See documentation of :class:`sage.coding.extended_code.ExtendedCode` for details. - EXAMPLES:: + EXAMPLES:: sage: C = codes.HammingCode(GF(4,'a'), 3) sage: C @@ -1244,14 +1271,14 @@ def is_permutation_equivalent(self,other,algorithm=None): EXAMPLES:: sage: P.<x> = PolynomialRing(GF(2),"x") - sage: g = x^3+x+1 - sage: C1 = codes.CyclicCode(length = 7, generator_pol = g); C1 + sage: g = x^3 + x + 1 + sage: C1 = codes.CyclicCode(length=7, generator_pol=g); C1 [7, 4] Cyclic Code over GF(2) sage: C2 = codes.HammingCode(GF(2), 3); C2 [7, 4] Hamming Code over GF(2) sage: C1.is_permutation_equivalent(C2) True - sage: C1.is_permutation_equivalent(C2,algorithm="verbose") + sage: C1.is_permutation_equivalent(C2, algorithm="verbose") (True, (3,4)(5,7,6)) sage: C1 = codes.random_linear_code(GF(2), 10, 5) sage: C2 = codes.random_linear_code(GF(3), 10, 5) @@ -1322,9 +1349,11 @@ def minimum_distance(self, algorithm=None): INPUT: - ``algorithm`` -- (default: ``None``) the name of the algorithm to use - to perform minimum distance computation. If set to ``None``, - GAP methods will be used. ``algorithm`` can be: - - ``"Guava"``, which will use optional GAP package Guava + to perform minimum distance computation. ``algorithm`` can be: + + - ``None``, to use GAP methods (but not Guava) + + - ``"Guava"``, to use the optional GAP package Guava OUTPUT: @@ -1341,12 +1370,11 @@ def minimum_distance(self, algorithm=None): If ``algorithm`` is provided, then the minimum distance will be recomputed even if there is a stored value from a previous run.:: - sage: C.minimum_distance(algorithm="gap") - 3 - sage: libgap.SetAllInfoLevels(0) # to suppress extra info messages - sage: C.minimum_distance(algorithm="guava") # optional - gap_packages (Guava package) - ... + sage: C.minimum_distance(algorithm="gap") # optional - sage.libs.gap 3 + sage: libgap.SetAllInfoLevels(0) # to suppress extra info messages # optional - sage.libs.gap + sage: C.minimum_distance(algorithm="guava") # optional - gap_package_guava + ...3 TESTS:: @@ -1473,10 +1501,11 @@ def module_composition_factors(self, gp): EXAMPLES:: sage: MS = MatrixSpace(GF(2),4,8) - sage: G = MS([[1,0,0,0,1,1,1,0],[0,1,1,1,0,0,0,0],[0,0,0,0,0,0,0,1],[0,0,0,0,0,1,0,0]]) + sage: G = MS([[1,0,0,0,1,1,1,0], [0,1,1,1,0,0,0,0], + ....: [0,0,0,0,0,0,0,1], [0,0,0,0,0,1,0,0]]) sage: C = LinearCode(G) sage: gp = C.permutation_automorphism_group() - sage: C.module_composition_factors(gp) + sage: C.module_composition_factors(gp) # optional - sage.libs.gap [ rec( IsIrreducible := true, IsOverFiniteField := true, @@ -1534,15 +1563,16 @@ def permutation_automorphism_group(self, algorithm="partition"): EXAMPLES:: sage: MS = MatrixSpace(GF(2),4,8) - sage: G = MS([[1,0,0,0,1,1,1,0],[0,1,1,1,0,0,0,0],[0,0,0,0,0,0,0,1],[0,0,0,0,0,1,0,0]]) + sage: G = MS([[1,0,0,0,1,1,1,0], [0,1,1,1,0,0,0,0], + ....: [0,0,0,0,0,0,0,1], [0,0,0,0,0,1,0,0]]) sage: C = LinearCode(G) sage: C [8, 4] linear code over GF(2) - sage: G = C.permutation_automorphism_group() - sage: G.order() + sage: G = C.permutation_automorphism_group() # optional - sage.groups + sage: G.order() # optional - sage.groups 144 - sage: GG = C.permutation_automorphism_group("codecan") - sage: GG == G + sage: GG = C.permutation_automorphism_group("codecan") # optional - sage.groups + sage: GG == G # optional - sage.groups True A less easy example involves showing that the permutation @@ -1552,42 +1582,44 @@ def permutation_automorphism_group(self, algorithm="partition"): :: sage: C = codes.GolayCode(GF(3)) - sage: M11 = MathieuGroup(11) - sage: M11.order() + sage: M11 = MathieuGroup(11) # optional - sage.groups + sage: M11.order() # optional - sage.groups 7920 - sage: G = C.permutation_automorphism_group() # long time (6s on sage.math, 2011) - sage: G.is_isomorphic(M11) # long time + sage: G = C.permutation_automorphism_group() # long time (6s on sage.math, 2011) # optional - sage.groups + sage: G.is_isomorphic(M11) # long time # optional - sage.groups True - sage: GG = C.permutation_automorphism_group("codecan") # long time - sage: GG == G # long time + sage: GG = C.permutation_automorphism_group("codecan") # long time # optional - sage.groups + sage: GG == G # long time # optional - sage.groups True Other examples:: sage: C = codes.GolayCode(GF(2)) - sage: G = C.permutation_automorphism_group() - sage: G.order() + sage: G = C.permutation_automorphism_group() # optional - sage.groups + sage: G.order() # optional - sage.groups 244823040 sage: C = codes.HammingCode(GF(2), 5) - sage: G = C.permutation_automorphism_group() - sage: G.order() + sage: G = C.permutation_automorphism_group() # optional - sage.groups + sage: G.order() # optional - sage.groups 9999360 sage: C = codes.HammingCode(GF(3), 2); C [4, 2] Hamming Code over GF(3) - sage: C.permutation_automorphism_group(algorithm="partition") + sage: C.permutation_automorphism_group(algorithm="partition") # optional - sage.groups Permutation Group with generators [(1,3,4)] sage: C = codes.HammingCode(GF(4,"z"), 2); C [5, 3] Hamming Code over GF(4) - sage: G = C.permutation_automorphism_group(algorithm="partition"); G + sage: G = C.permutation_automorphism_group(algorithm="partition"); G # optional - sage.groups Permutation Group with generators [(1,3)(4,5), (1,4)(3,5)] - sage: GG = C.permutation_automorphism_group(algorithm="codecan") # long time - sage: GG == G # long time + sage: GG = C.permutation_automorphism_group(algorithm="codecan") # long time, optional - sage.groups + sage: GG == G # long time, optional - sage.groups True - sage: C.permutation_automorphism_group(algorithm="gap") # optional - gap_packages (Guava package) + sage: C.permutation_automorphism_group(algorithm="gap") # optional - gap_package_guava sage.groups Permutation Group with generators [(1,3)(4,5), (1,4)(3,5)] sage: C = codes.GolayCode(GF(3), True) - sage: C.permutation_automorphism_group(algorithm="gap") # optional - gap_packages (Guava package) - Permutation Group with generators [(5,7)(6,11)(8,9)(10,12), (4,6,11)(5,8,12)(7,10,9), (3,4)(6,8)(9,11)(10,12), (2,3)(6,11)(8,12)(9,10), (1,2)(5,10)(7,12)(8,9)] + sage: C.permutation_automorphism_group(algorithm="gap") # optional - gap_package_guava sage.groups + Permutation Group with generators + [(5,7)(6,11)(8,9)(10,12), (4,6,11)(5,8,12)(7,10,9), (3,4)(6,8)(9,11)(10,12), + (2,3)(6,11)(8,12)(9,10), (1,2)(5,10)(7,12)(8,9)] However, the option ``algorithm="gap+verbose"``, will print out:: @@ -1682,7 +1714,7 @@ def punctured(self, L): INPUT: - - ``L`` - List of positions to puncture + - ``L`` -- List of positions to puncture OUTPUT: @@ -1747,7 +1779,7 @@ def shortened(self, L): INPUT: - - ``L`` - Subset of `\{1,...,n\}`, where `n` is the length of this code + - ``L`` -- Subset of `\{1,...,n\}`, where `n` is the length of this code OUTPUT: @@ -1773,8 +1805,8 @@ def weight_distribution(self, algorithm=None): INPUT: - - ``algorithm`` - (optional, default: ``None``) If set to ``"gap"``, - call GAP. If set to `"leon"`, call the option GAP package GUAVA and + - ``algorithm`` -- (optional, default: ``None``) If set to ``"gap"``, + call GAP. If set to ``"leon"``, call the option GAP package GUAVA and call a function therein by Jeffrey Leon (see warning below). If set to ``"binary"``, use an algorithm optimized for binary codes. The default is to use ``"binary"`` for binary codes and ``"gap"`` otherwise. @@ -1785,7 +1817,7 @@ def weight_distribution(self, algorithm=None): .. WARNING:: - Specifying ``algorithm = "leon"`` sometimes prints a traceback + Specifying ``algorithm="leon"`` sometimes prints a traceback related to a stack smashing error in the C library. The result appears to be computed correctly, however. It appears to run much faster than the GAP algorithm in small examples and much slower than @@ -1805,27 +1837,28 @@ def weight_distribution(self, algorithm=None): [1, 0, 0, 30, 15, 18] sage: C = codes.HammingCode(GF(2), 3); C [7, 4] Hamming Code over GF(2) - sage: C.weight_distribution(algorithm="leon") # optional - gap_packages (Guava package) + sage: C.weight_distribution(algorithm="leon") # optional - gap_package_guava [1, 0, 0, 7, 7, 0, 0, 1] - sage: C.weight_distribution(algorithm="gap") + sage: C.weight_distribution(algorithm="gap") # optional - sage.libs.gap [1, 0, 0, 7, 7, 0, 0, 1] sage: C.weight_distribution(algorithm="binary") [1, 0, 0, 7, 7, 0, 0, 1] + + sage: # optional - gap_package_guava sage: C = codes.HammingCode(GF(3), 3); C [13, 10] Hamming Code over GF(3) - sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") # optional - gap_packages (Guava package) + sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") True sage: C = codes.HammingCode(GF(5), 2); C [6, 4] Hamming Code over GF(5) - sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") # optional - gap_packages (Guava package) + sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") True sage: C = codes.HammingCode(GF(7), 2); C [8, 6] Hamming Code over GF(7) - sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") # optional - gap_packages (Guava package) + sage: C.weight_distribution() == C.weight_distribution(algorithm="leon") True """ - from sage.libs.gap.libgap import libgap if algorithm is None: if self.base_ring().order() == 2: algorithm = "binary" @@ -1834,6 +1867,7 @@ def weight_distribution(self, algorithm=None): F = self.base_ring() n = self.length() if algorithm=="gap": + from sage.libs.gap.libgap import libgap Gmat = self.generator_matrix() q = self.base_ring().order() z = 0*libgap.Z(q)*([0]*self.length()) # GAP zero vector @@ -1847,6 +1881,7 @@ def weight_distribution(self, algorithm=None): raise NotImplementedError("The algorithm 'leon' is only implemented for q = 2,3,5,7.") # The GAP command DirectoriesPackageLibrary tells the location of the latest # version of the Guava libraries, so gives us the location of the Guava binaries too. + from sage.libs.gap.libgap import libgap guava_bin_dir = libgap.DirectoriesPackagePrograms("guava")[0].Filename("").sage() input = _dump_code_in_leon_format(self) + "::code" lines = subprocess.check_output([os.path.join(guava_bin_dir, 'wtdist'), input]) @@ -1868,7 +1903,7 @@ def weight_distribution(self, algorithm=None): def support(self): r""" Return the set of indices `j` where `A_j` is nonzero, where - `A_j` is the number of codewords in `self` of Hamming weight `j`. + `A_j` is the number of codewords in ``self`` of Hamming weight `j`. OUTPUT: @@ -1892,16 +1927,16 @@ def weight_enumerator(self, names=None, bivariate=True): Return the weight enumerator polynomial of ``self``. This is the bivariate, homogeneous polynomial in `x` and `y` whose - coefficient to `x^i y^{n-i}` is the number of codewords of `self` of - Hamming weight `i`. Here, `n` is the length of `self`. + coefficient to `x^i y^{n-i}` is the number of codewords of ``self`` of + Hamming weight `i`. Here, `n` is the length of ``self``. INPUT: - - ``names`` - (default: ``"xy"``) The names of the variables in the + - ``names`` -- (default: ``"xy"``) The names of the variables in the homogeneous polynomial. Can be given as a single string of length 2, or a single string with a comma, or as a tuple or list of two strings. - - ``bivariate`` - (default: `True`) Whether to return a bivariate, + - ``bivariate`` -- (default: ``True``) Whether to return a bivariate, homogeneous polynomial or just a univariate polynomial. If set to ``False``, then ``names`` will be interpreted as a single variable name and default to ``"x"``. @@ -1955,7 +1990,7 @@ def zeta_polynomial(self, name="T"): INPUT: - - ``name`` - String, variable name (default: ``"T"``) + - ``name`` -- String, variable name (default: ``"T"``) OUTPUT: @@ -1966,14 +2001,17 @@ def zeta_polynomial(self, name="T"): sage: C = codes.HammingCode(GF(2), 3) sage: C.zeta_polynomial() 2/5*T^2 + 2/5*T + 1/5 - sage: C = codes.databases.best_linear_code_in_guava(6,3,GF(2)) # optional - gap_packages (Guava package) - sage: C.minimum_distance() # optional - gap_packages (Guava package) + + sage: C = codes.databases.best_linear_code_in_guava(6, 3, GF(2)) # optional - gap_package_guava + sage: C.minimum_distance() # optional - gap_package_guava 3 - sage: C.zeta_polynomial() # optional - gap_packages (Guava package) + sage: C.zeta_polynomial() # optional - gap_package_guava 2/5*T^2 + 2/5*T + 1/5 + sage: C = codes.HammingCode(GF(2), 4) sage: C.zeta_polynomial() 16/429*T^6 + 16/143*T^5 + 80/429*T^4 + 32/143*T^3 + 30/143*T^2 + 2/13*T + 1/13 + sage: F.<z> = GF(4,"z") sage: MS = MatrixSpace(F, 3, 6) sage: G = MS([[1,0,0,1,z,z],[0,1,0,z,1,z],[0,0,1,z,z,1]]) @@ -2162,7 +2200,7 @@ class LinearCode(AbstractLinearCode): minimum distance, will use generic, slow algorithms. If you are looking for constructing a code from a more specific family, see - if the family has been implemented by investigating `codes.<tab>`. These + if the family has been implemented by investigating ``codes.<tab>``. These more specific classes use properties particular to that family to allow faster algorithms, and could also have family-specific methods. @@ -2466,7 +2504,8 @@ def generator_matrix(self): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E.generator_matrix() @@ -2526,7 +2565,9 @@ class LinearCodeSyndromeDecoder(Decoder): EXAMPLES:: - sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2],[0,1,0,2,2,0,1,1,0],[0,0,1,0,2,2,2,1,2]]) + sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2], + ....: [0,1,0,2,2,0,1,1,0], + ....: [0,0,1,0,2,2,2,1,2]]) sage: C = LinearCode(G) sage: D = codes.decoders.LinearCodeSyndromeDecoder(C) sage: D @@ -2563,7 +2604,7 @@ class LinearCodeSyndromeDecoder(Decoder): We build a first syndrome decoder, and pick a ``maximum_error_weight`` smaller than both the covering radius and half the minimum distance:: - sage: D = C.decoder("Syndrome", maximum_error_weight = 1) + sage: D = C.decoder("Syndrome", maximum_error_weight=1) sage: D.decoder_type() {'always-succeed', 'bounded_distance', 'hard-decision'} sage: D.decoding_radius() @@ -2576,7 +2617,7 @@ class LinearCodeSyndromeDecoder(Decoder): ``maximum_error_weight`` is chosen to be bigger than half the minimum distance, but lower than the covering radius:: - sage: D = C.decoder("Syndrome", maximum_error_weight = 3) + sage: D = C.decoder("Syndrome", maximum_error_weight=3) sage: D.decoder_type() {'bounded_distance', 'hard-decision', 'might-error'} sage: D.decoding_radius() @@ -2590,10 +2631,10 @@ class LinearCodeSyndromeDecoder(Decoder): And now, we build a third syndrome decoder, whose ``maximum_error_weight`` is bigger than both the covering radius and half the minimum distance:: - sage: D = C.decoder("Syndrome", maximum_error_weight = 5) # long time - sage: D.decoder_type() # long time + sage: D = C.decoder("Syndrome", maximum_error_weight=5) # long time + sage: D.decoder_type() # long time {'complete', 'hard-decision', 'might-error'} - sage: D.decoding_radius() # long time + sage: D.decoding_radius() # long time 4 In that case, the decoder might still return an unexpected codeword, but @@ -2830,7 +2871,7 @@ def _build_lookup_table(self): def decode_to_code(self, r): r""" - Corrects the errors in ``word`` and returns a codeword. + Correct the errors in ``word`` and return a codeword. INPUT: @@ -2871,11 +2912,13 @@ def maximum_error_weight(self): Return the maximal number of errors a received word can have and for which ``self`` is guaranteed to return a most likely codeword. - Same as ``self.decoding_radius``. + Same as :meth:`decoding_radius`. EXAMPLES:: - sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2],[0,1,0,2,2,0,1,1,0],[0,0,1,0,2,2,2,1,2]]) + sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2], + ....: [0,1,0,2,2,0,1,1,0], + ....: [0,0,1,0,2,2,2,1,2]]) sage: C = LinearCode(G) sage: D = codes.decoders.LinearCodeSyndromeDecoder(C) sage: D.maximum_error_weight() @@ -2890,7 +2933,9 @@ def decoding_radius(self): EXAMPLES:: - sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2],[0,1,0,2,2,0,1,1,0],[0,0,1,0,2,2,2,1,2]]) + sage: G = Matrix(GF(3), [[1,0,0,1,0,1,0,1,2], + ....: [0,1,0,2,2,0,1,1,0], + ....: [0,0,1,0,2,2,2,1,2]]) sage: C = LinearCode(G) sage: D = codes.decoders.LinearCodeSyndromeDecoder(C) sage: D.decoding_radius() @@ -2904,7 +2949,8 @@ def syndrome_table(self): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: D = codes.decoders.LinearCodeSyndromeDecoder(C) sage: D.syndrome_table() @@ -2999,7 +3045,8 @@ def decode_to_code(self, r): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: D = codes.decoders.LinearCodeNearestNeighborDecoder(C) sage: word = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) @@ -3022,7 +3069,8 @@ def decoding_radius(self): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: D = codes.decoders.LinearCodeNearestNeighborDecoder(C) sage: D.decoding_radius() diff --git a/src/sage/coding/linear_code_no_metric.py b/src/sage/coding/linear_code_no_metric.py index 9610c4e31ce..2ae0879fa74 100644 --- a/src/sage/coding/linear_code_no_metric.py +++ b/src/sage/coding/linear_code_no_metric.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Generic structures for linear codes of any metric @@ -76,9 +77,9 @@ class AbstractLinearCodeNoMetric(AbstractCode, Module): :class:`sage.coding.linear_code.LinearCode`. - As AbstractLinearCodeNoMetric is not designed to be implemented, it does not - have any representation methods. You should implement ``_repr_`` and ``_latex_`` - methods in the subclass. + As the class :class:`AbstractLinearCodeNoMetric` is not designed to be + instantiated, it does not have any representation methods. You should + implement ``_repr_`` and ``_latex_`` methods in the subclass. .. WARNING:: @@ -199,7 +200,8 @@ def base_field(self): EXAMPLES:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], + ....: [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: C.base_field() Finite Field of size 2 @@ -233,7 +235,7 @@ def generator_matrix(self, encoder_name=None, **kwargs): EXAMPLES:: - sage: G = matrix(GF(3),2,[1,-1,1,-1,1,1]) + sage: G = matrix(GF(3), 2, [1,-1,1,-1,1,1]) sage: code = LinearCode(G) sage: code.generator_matrix() [1 2 1] @@ -265,9 +267,9 @@ def __eq__(self, other): False """ # Fail without computing the generator matrix if possible: - if not (isinstance(other, AbstractLinearCodeNoMetric)\ - and self.length() == other.length()\ - and self.dimension() == other.dimension()\ + if not (isinstance(other, AbstractLinearCodeNoMetric) + and self.length() == other.length() + and self.dimension() == other.dimension() and self.base_ring() == other.base_ring()): return False # Check that basis elements of `other` are all in `self.` @@ -276,10 +278,7 @@ def __eq__(self, other): # This implementation may avoid linear algebra altogether, if `self` # implements an efficient way to obtain a parity check matrix, and in # the worst case does only one system solving. - for c in other.gens(): - if not (c in self): - return False - return True + return all(c in self for c in other.gens()) def __ne__(self, other): r""" @@ -307,7 +306,7 @@ def dimension(self): EXAMPLES:: - sage: G = matrix(GF(2),[[1,0,0],[1,1,0]]) + sage: G = matrix(GF(2), [[1,0,0], [1,1,0]]) sage: C = LinearCode(G) sage: C.dimension() 2 @@ -382,7 +381,8 @@ def gens(self): sage: C = codes.HammingCode(GF(2), 3) sage: C.gens() - [(1, 0, 0, 0, 0, 1, 1), (0, 1, 0, 0, 1, 0, 1), (0, 0, 1, 0, 1, 1, 0), (0, 0, 0, 1, 1, 1, 1)] + [(1, 0, 0, 0, 0, 1, 1), (0, 1, 0, 0, 1, 0, 1), + (0, 0, 1, 0, 1, 1, 0), (0, 0, 0, 1, 1, 1, 1)] """ return self.generator_matrix().rows() @@ -409,7 +409,7 @@ def basis(self): """ gens = self.gens() from sage.structure.sequence import Sequence - return Sequence(gens, universe=self.ambient_space(), check = False, immutable=True, cr=True) + return Sequence(gens, universe=self.ambient_space(), check=False, immutable=True, cr=True) @cached_method def parity_check_matrix(self): @@ -538,7 +538,7 @@ def systematic_generator_matrix(self, systematic_positions=None): [1 2 0 1] [0 0 1 2] - Specific systematic positions can also be requested: + Specific systematic positions can also be requested:: sage: C.systematic_generator_matrix(systematic_positions=[3,2]) [1 2 0 1] @@ -662,8 +662,8 @@ def information_set(self): EXAMPLES:: - sage: G = matrix(GF(3),2,[1,2,0,\ - 2,1,1]) + sage: G = matrix(GF(3),2,[1,2,0, + ....: 2,1,1]) sage: code = LinearCode(G) sage: code.systematic_generator_matrix() [1 2 0] @@ -680,7 +680,7 @@ def is_information_set(self, positions): INPUT: - A list of positions, i.e. integers in the range 0 to `n-1` where `n` - is the length of `self`. + is the length of ``self``. OUTPUT: @@ -689,8 +689,8 @@ def is_information_set(self, positions): EXAMPLES:: - sage: G = matrix(GF(3),2,[1,2,0,\ - 2,1,1]) + sage: G = matrix(GF(3),2,[1,2,0, + ....: 2,1,1]) sage: code = LinearCode(G) sage: code.is_information_set([0,1]) False @@ -898,8 +898,8 @@ def is_subcode(self, other): def is_permutation_automorphism(self,g): r""" - Return `1` if `g` is an element of `S_n` (`n` = length of self) and - if `g` is an automorphism of self. + Return `1` if `g` is an element of `S_n` (`n` = length of ``self``) and + if `g` is an automorphism of ``self``. EXAMPLES:: @@ -908,7 +908,8 @@ def is_permutation_automorphism(self,g): sage: C.is_permutation_automorphism(g) 0 sage: MS = MatrixSpace(GF(2),4,8) - sage: G = MS([[1,0,0,0,1,1,1,0],[0,1,1,1,0,0,0,0],[0,0,0,0,0,0,0,1],[0,0,0,0,0,1,0,0]]) + sage: G = MS([[1,0,0,0,1,1,1,0], [0,1,1,1,0,0,0,0], + ....: [0,0,0,0,0,0,0,1], [0,0,0,0,0,1,0,0]]) sage: C = LinearCode(G) sage: S8 = SymmetricGroup(8) sage: g = S8("(2,3)") @@ -936,7 +937,8 @@ def permuted_code(self, p): sage: C = codes.HammingCode(GF(2), 3) sage: G = C.permutation_automorphism_group(); G - Permutation Group with generators [(4,5)(6,7), (4,6)(5,7), (2,3)(6,7), (2,4)(3,5), (1,2)(5,6)] + Permutation Group with generators + [(4,5)(6,7), (4,6)(5,7), (2,3)(6,7), (2,4)(3,5), (1,2)(5,6)] sage: g = G("(2,3)(6,7)") sage: Cg = C.permuted_code(g) sage: Cg @@ -1002,8 +1004,8 @@ def is_self_orthogonal(self): sage: C = codes.HammingCode(GF(2), 3) sage: C.is_self_orthogonal() False - sage: C = codes.QuasiQuadraticResidueCode(11) # optional - gap_packages (Guava package) - sage: C.is_self_orthogonal() # optional - gap_packages (Guava package) + sage: C = codes.QuasiQuadraticResidueCode(11) # optional - gap_package_guava + sage: C.is_self_orthogonal() # optional - gap_package_guava True """ return self.is_subcode(self.dual_code()) @@ -1056,38 +1058,39 @@ class LinearCodeSystematicEncoder(Encoder): the range 0 to `n-1` where `n` is the length of the code and `k` its dimension. The 0th symbol of a message will then be at position ``systematic_positions[0]``, the 1st index at position - ``systematic_positions[1]``, etc. A ``ValueError`` is raised at + ``systematic_positions[1]``, etc. A :class:`ValueError` is raised at construction time if the supplied indices do not form an information set. EXAMPLES: The following demonstrates the basic usage of :class:`LinearCodeSystematicEncoder`:: - sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0,0],\ - [1,0,0,1,1,0,0,0],\ - [0,1,0,1,0,1,0,0],\ - [1,1,0,1,0,0,1,1]]) - sage: C = LinearCode(G) - sage: E = codes.encoders.LinearCodeSystematicEncoder(C) - sage: E.generator_matrix() - [1 0 0 0 0 1 1 1] - [0 1 0 0 1 0 1 1] - [0 0 1 0 1 1 0 0] - [0 0 0 1 1 1 1 1] - sage: E2 = codes.encoders.LinearCodeSystematicEncoder(C, systematic_positions=[5,4,3,2]) - sage: E2.generator_matrix() - [1 0 0 0 0 1 1 1] - [0 1 0 0 1 0 1 1] - [1 1 0 1 0 0 1 1] - [1 1 1 0 0 0 0 0] + sage: LCSE = codes.encoders.LinearCodeSystematicEncoder + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0,0],\ + [1,0,0,1,1,0,0,0],\ + [0,1,0,1,0,1,0,0],\ + [1,1,0,1,0,0,1,1]]) + sage: C = LinearCode(G) + sage: E = LCSE(C) + sage: E.generator_matrix() + [1 0 0 0 0 1 1 1] + [0 1 0 0 1 0 1 1] + [0 0 1 0 1 1 0 0] + [0 0 0 1 1 1 1 1] + sage: E2 = LCSE(C, systematic_positions=[5,4,3,2]) + sage: E2.generator_matrix() + [1 0 0 0 0 1 1 1] + [0 1 0 0 1 0 1 1] + [1 1 0 1 0 0 1 1] + [1 1 1 0 0 0 0 0] An error is raised if one specifies systematic positions which do not form an information set:: - sage: E3 = codes.encoders.LinearCodeSystematicEncoder(C, systematic_positions=[0,1,6,7]) - Traceback (most recent call last): - ... - ValueError: systematic_positions are not an information set + sage: E3 = LCSE(C, systematic_positions=[0,1,6,7]) + Traceback (most recent call last): + ... + ValueError: systematic_positions are not an information set We exemplify how to use :class:`LinearCodeSystematicEncoder` as the default @@ -1095,7 +1098,7 @@ class LinearCodeSystematicEncoder(Encoder): sage: class DualRepetitionCode(sage.coding.linear_code.AbstractLinearCode): ....: def __init__(self, field, length): - ....: sage.coding.linear_code.AbstractLinearCode.__init__(self,field, length, "Systematic", "Syndrome") + ....: super().__init__(field, length, "Systematic", "Syndrome") ....: ....: def parity_check_matrix(self): ....: return Matrix(self.base_field(), [1]*self.length()) @@ -1115,7 +1118,7 @@ class LinearCodeSystematicEncoder(Encoder): sage: class BadCodeFamily(sage.coding.linear_code.AbstractLinearCode): ....: def __init__(self, field, length): - ....: sage.coding.linear_code.AbstractLinearCode.__init__(self, field, length, "Systematic", "Syndrome") + ....: super().__init__(field, length, "Systematic", "Syndrome") ....: ....: def _repr_(self): ....: return "I am a badly defined code" @@ -1123,7 +1126,8 @@ class LinearCodeSystematicEncoder(Encoder): sage: BadCodeFamily(GF(3), 5).generator_matrix() Traceback (most recent call last): ... - ValueError: a parity check matrix must be specified if LinearCodeSystematicEncoder is the default encoder + ValueError: a parity check matrix must be specified + if LinearCodeSystematicEncoder is the default encoder """ def __init__(self, code, systematic_positions=None): @@ -1148,7 +1152,6 @@ def __init__(self, code, systematic_positions=None): # Test that the systematic positions are an information set self.generator_matrix() - def __eq__(self, other): r""" Tests equality between LinearCodeSystematicEncoder objects. @@ -1216,12 +1219,13 @@ def generator_matrix(self): EXAMPLES:: + sage: LCSE = codes.encoders.LinearCodeSystematicEncoder sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],\ [1,0,0,1,1,0,0],\ [0,1,0,1,0,1,0],\ [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) - sage: E = codes.encoders.LinearCodeSystematicEncoder(C) + sage: E = LCSE(C) sage: E.generator_matrix() [1 0 0 0 0 1 1] [0 1 0 0 1 0 1] @@ -1230,7 +1234,7 @@ def generator_matrix(self): We can ask for different systematic positions:: - sage: E2 = codes.encoders.LinearCodeSystematicEncoder(C, systematic_positions=[5,4,3,2]) + sage: E2 = LCSE(C, systematic_positions=[5,4,3,2]) sage: E2.generator_matrix() [1 0 0 0 0 1 1] [0 1 0 0 1 0 1] @@ -1244,7 +1248,7 @@ def generator_matrix(self): [0,0,1,0,0,1,0],\ [0,0,1,0,1,0,1]]) sage: C = LinearCode(G) - sage: E = codes.encoders.LinearCodeSystematicEncoder(C) + sage: E = LCSE(C) sage: E.generator_matrix() [1 1 0 0 0 1 0] [0 0 1 0 0 1 0] @@ -1317,12 +1321,13 @@ def systematic_positions(self): EXAMPLES:: + sage: LCSE = codes.encoders.LinearCodeSystematicEncoder sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],\ [1,0,0,1,1,0,0],\ [0,1,0,1,0,1,0],\ [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) - sage: E = codes.encoders.LinearCodeSystematicEncoder(C) + sage: E = LCSE(C) sage: E.systematic_positions() (0, 1, 2, 3) @@ -1333,7 +1338,7 @@ def systematic_positions(self): [0,0,1,0,0,1,0],\ [0,0,1,0,1,0,1]]) sage: C = LinearCode(G) - sage: E = codes.encoders.LinearCodeSystematicEncoder(C) + sage: E = LCSE(C) sage: E.systematic_positions() (0, 2, 4, 6) @@ -1355,7 +1360,7 @@ def systematic_positions(self): [0,1,0,0],\ [0,0,1,1]]) sage: C = LinearCode(G) - sage: E = codes.encoders.LinearCodeSystematicEncoder(C, systematic_positions=[0,1,3]) + sage: E = LCSE(C, systematic_positions=[0,1,3]) sage: E.systematic_positions() (0, 1, 3) """ diff --git a/src/sage/coding/linear_rank_metric.py b/src/sage/coding/linear_rank_metric.py index 78db1b8c602..babb22ff1ce 100644 --- a/src/sage/coding/linear_rank_metric.py +++ b/src/sage/coding/linear_rank_metric.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Generic structures for linear codes over the rank metric @@ -7,10 +7,10 @@ In coding theory, the most common metric is the Hamming metric, where distance between two codewords is given by the number of positions in which they differ. -An alternative to this is the rank metric. Take two fields, `F_q` and `F_{q^m}`, +An alternative to this is the rank metric. Take two fields, `\GF{q}` and `\GF{q^m}`, and define a code `C` to be a set of vectors of length `n` with entries from -`F_{q^m}`. Let `c` be a codeword. We can represent it as an `m \times n` matrix -`M` over `F_q`. +`\GF{q^m}`. Let `c` be a codeword. We can represent it as an `m \times n` matrix +`M` over `\GF{q}`. A detailed description on the relationship between the two representations can be found in :meth:`sage.coding.linear_rank_metric.to_matrix_representation` @@ -22,9 +22,9 @@ representation of `c`. This module allows representing rank metric codes which are linear over the -big field `F_{q^m}`, i.e. the usual linearity condition when the codewords are +big field `\GF{q^m}`, i.e. the usual linearity condition when the codewords are considered in vector form. One can also consider rank metric codes which are -only linear over `F_q`, but these are not currently supported in SageMath. +only linear over `\GF{q}`, but these are not currently supported in SageMath. Note that linear rank metric codes per the definition of this file are mathematically just linear block codes, and so could be considered as a @@ -127,28 +127,28 @@ def to_matrix_representation(v, sub_field=None, basis=None): Return a matrix representation of ``v`` over ``sub_field`` in terms of ``basis``. - Let `(b_1, b_2, \ldots, b_m)`, `b_i \in GF(q^m)`, be a basis of `GF(q^m)` as - a vector space over `GF(q)`. Take an element `x \in GF(q^m)`. We can write + Let `(b_1, b_2, \ldots, b_m)`, `b_i \in GF(q^m)`, be a basis of `\GF{q^m}` as + a vector space over `\GF{q}`. Take an element `x \in \GF{q^m}`. We can write `x` as `x = u_1 b_1 + u_2 b_2 + \ldots u_m b_m`, where `u_i \in GF(q)`. This - way we can represent an element from `GF(q^m)` as a vector of length `m` - over `GF(q)`. + way we can represent an element from `\GF{q^m}` as a vector of length `m` + over `\GF{q}`. - Given a vector ``v`` of length `n` over some field `F_{q^m}`, we can + Given a vector ``v`` of length `n` over some field `\GF{q^m}`, we can represent each entry as a vector of length `m`, yielding an `m \times n` matrix over ``sub_field``. In case ``sub_field`` is not given, we take the - prime subfield `F_p` of `F_{q^m}`. + prime subfield `\GF{p}` of `\GF{q^m}`. INPUT: - - ``v`` -- a vector over some field `F_{q^m}` + - ``v`` -- a vector over some field `\GF{q^m}` - - ``sub_field`` -- (default: ``None``) a sub field of `F_{q^m}`. If not - specified, it is the prime subfield `F_p` of `F_{q^m}`. + - ``sub_field`` -- (default: ``None``) a sub field of `\GF{q^m}`. If not + specified, it is the prime subfield `\GF{p}` of `\GF{q^m}`. - - ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over + - ``basis`` -- (default: ``None``) a basis of `\GF{q^m}` as a vector space over ``sub_field``. If not specified, given that `q = p^s`, let `1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to - represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. + represent `\GF{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. EXAMPLES:: @@ -181,25 +181,25 @@ def from_matrix_representation(w, base_field=None, basis=None): Return a vector representation of a matrix ``w`` over ``base_field`` in terms of ``basis``. - Given an `m \times n` matrix over `F_q` and some ``basis`` of `F_{q^m}` - over `F_q`, we can represent each of its columns as an element of `F_{q^m}`, - yielding a vector of length `n` over `F_q`. + Given an `m \times n` matrix over `\GF{q}` and some ``basis`` of `\GF{q^m}` + over `\GF{q}`, we can represent each of its columns as an element of `\GF{q^m}`, + yielding a vector of length `n` over `\GF{q}`. - In case ``base_field`` is not given, we take `F_{q^m}`, the field extension of - `F_q` of degree `m`, the number of rows of ``w``. + In case ``base_field`` is not given, we take `\GF{q^m}`, the field extension of + `\GF{q}` of degree `m`, the number of rows of ``w``. INPUT: - - ``w`` -- a matrix over some field `F_q` + - ``w`` -- a matrix over some field `\GF{q}` - - ``base_field`` -- (default: ``None``) an extension field of `F_q`. If not - specified, it is the field `F_{q^m}`, where `m` is the number of rows of + - ``base_field`` -- (default: ``None``) an extension field of `\GF{q}`. If not + specified, it is the field `\GF{q^m}`, where `m` is the number of rows of ``w``. - - ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over - ``F_q``. If not specified, given that `q = p^s`, let + - ``basis`` -- (default: ``None``) a basis of `\GF{q^m}` as a vector space over + `\GF{q}`. If not specified, given that `q = p^s`, let `1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to - represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. + represent `\GF{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. EXAMPLES:: @@ -229,20 +229,20 @@ def rank_weight(c, sub_field=None, basis=None): r""" Return the rank of ``c`` as a matrix over ``sub_field``. - If ``c`` is a vector over some field `F_{q^m}`, the function converts it - into a matrix over `F_q`. + If ``c`` is a vector over some field `\GF{q^m}`, the function converts it + into a matrix over `\GF{q}`. INPUT: - - ``c`` -- a vector over some field `F_{q^m}`; or a matrix over `F_q` + - ``c`` -- a vector over some field `\GF{q^m}`; or a matrix over `\GF{q}` - - ``sub_field`` -- (default: ``None``) a sub field of `F_{q^m}`. If not - specified, it is the prime subfield `F_p` of `F_{q^m}`. + - ``sub_field`` -- (default: ``None``) a sub field of `\GF{q^m}`. If not + specified, it is the prime subfield `\GF{p}` of `\GF{q^m}`. - - ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over + - ``basis`` -- (default: ``None``) a basis of `\GF{q^m}` as a vector space over ``sub_field``. If not specified, given that `q = p^s`, let `1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to - represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. + represent `\GF{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. EXAMPLES:: @@ -260,26 +260,26 @@ def rank_distance(a, b, sub_field=None, basis=None): r""" Return the rank of ``a`` - ``b`` as a matrix over ``sub_field``. - Take two vectors ``a``, ``b`` over some field `F_{q^m}`. This function - converts them to matrices over `F_q` and calculates the rank of their + Take two vectors ``a``, ``b`` over some field `\GF{q^m}`. This function + converts them to matrices over `\GF{q}` and calculates the rank of their difference. - If ``sub_field`` is not specified, we take the prime subfield `F_q` of - `F_{q^m}`. + If ``sub_field`` is not specified, we take the prime subfield `\GF{q}` of + `\GF{q^m}`. INPUT: - - ``a`` -- a vector over some field `F_{q^m}` + - ``a`` -- a vector over some field `\GF{q^m}` - - ``b`` -- a vector over some field `F_{q^m}` + - ``b`` -- a vector over some field `\GF{q^m}` - - ``sub_field`` -- (default: ``None``) a sub field of `F_{q^m}`. If not - specified, it is the prime subfield `F_p` of `F_{q^m}`. + - ``sub_field`` -- (default: ``None``) a sub field of `\GF{q^m}`. If not + specified, it is the prime subfield `\GF{p}` of `\GF{q^m}`. - - ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over + - ``basis`` -- (default: ``None``) a basis of `\GF{q^m}` as a vector space over ``sub_field``. If not specified, given that `q = p^s`, let `1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to - represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. + represent `\GF{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. EXAMPLES:: @@ -331,8 +331,8 @@ class AbstractLinearRankMetricCode(AbstractLinearCodeNoMetric): This class is intended for codes which are linear over the ``base_field``. Codewords of rank metric codes have two representations. They can either be - written as a vector of length `n` over `GF(q^m)`, or an `m \times n` matrix - over `GF(q)`. This implementation principally uses the vector representation. + written as a vector of length `n` over `\GF{q^m}`, or an `m \times n` matrix + over `\GF{q}`. This implementation principally uses the vector representation. However, one can always get the matrix representation using the :meth:`sage.coding.linear_rank_metric.AbstractLinearRankMetricCode.to_matrix` method. To go back to a vector, use the @@ -377,10 +377,10 @@ def __init__(self, base_field, sub_field, length, default_encoder_name, - ``default_decoder_name`` -- the name of the default decoder of ``self`` - - ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over + - ``basis`` -- (default: ``None``) a basis of `\GF{q^m}` as a vector space over ``sub_field``. If not specified, given that `q = p^s`, let `1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to - represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. + represent `\GF{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. EXAMPLES: @@ -391,9 +391,11 @@ def __init__(self, base_field, sub_field, length, default_encoder_name, sage: from sage.coding.linear_rank_metric import AbstractLinearRankMetricCode sage: class RankRepetitionCode(AbstractLinearRankMetricCode): ....: def __init__(self, base_field, sub_field, length): - ....: sage.coding.linear_rank_metric.AbstractLinearRankMetricCode.__init__(self, base_field, sub_field, length, "GeneratorMatrix", "NearestNeighbor") + ....: super().__init__(base_field, sub_field, length, + ....: "GeneratorMatrix", "NearestNeighbor") ....: beta = base_field.gen() - ....: self._generator_matrix = matrix(base_field, [[ beta^i for i in range(length) ]]) + ....: self._generator_matrix = matrix(base_field, + ....: [[beta^i for i in range(length)]]) ....: def generator_matrix(self): ....: return self._generator_matrix ....: def _repr_(self): @@ -436,7 +438,8 @@ def __init__(self, base_field, sub_field, length, default_encoder_name, sage: C.parent() <class '__main__.RankRepetitionCode_with_category'> sage: C.category() - Category of facade finite dimensional vector spaces with basis over Finite Field in z3 of size 2^3 + Category of facade finite dimensional vector spaces with basis + over Finite Field in z3 of size 2^3 And any method that works on rank metric linear codes works for our new dummy code:: @@ -492,7 +495,7 @@ def extension_degree(self): r""" Return `m`, the degree of the field extension of ``self``. - Let ``base_field`` be `GF(q^m)` and ``sub_field`` be `GF(q)`. Then this + Let ``base_field`` be `\GF{q^m}` and ``sub_field`` be `\GF{q}`. Then this function returns `m`. EXAMPLES:: @@ -509,8 +512,8 @@ def field_extension(self): r""" Return the field extension of ``self``. - Let ``base_field`` be some field `F_{q^m}` and ``sub_field`` `F_{q}`. - This function returns the vector space of dimension `m` over `F_{q}`. + Let ``base_field`` be some field `\GF{q^m}` and ``sub_field`` `\GF{q}`. + This function returns the vector space of dimension `m` over `\GF{q}`. EXAMPLES:: @@ -674,10 +677,10 @@ def __init__(self, generator, sub_field=None, basis=None): - ``sub_field`` -- (default: ``None``) the sub field of ``self``, if not specified, it is the prime field of ``base_field`` - - ``basis`` -- (default: ``None``) a basis of `F_{q^m}` as a vector space over + - ``basis`` -- (default: ``None``) a basis of `\GF{q^m}` as a vector space over ``sub_field``. If not specified, given that `q = p^s`, let `1,\beta,\ldots,\beta^{sm}` be the power basis that SageMath uses to - represent `F_{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. + represent `\GF{q^m}`. The default basis is then `1,\beta,\ldots,\beta^{m-1}`. EXAMPLES:: @@ -888,7 +891,8 @@ def decoding_radius(self): sage: D.decoding_radius() 1 """ - return (self.code().minimum_distance()-1) // 2 + return (self.code().minimum_distance() - 1) // 2 + ####################### registration ############################### diff --git a/src/sage/coding/parity_check_code.py b/src/sage/coding/parity_check_code.py index 880de2c00fd..d131ecaf80a 100644 --- a/src/sage/coding/parity_check_code.py +++ b/src/sage/coding/parity_check_code.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Parity-check code @@ -5,8 +6,8 @@ parity check to ensure that the sum of the digits in a transmitted word is even. -A parity-check code of dimension `k` over `F_q` is the set: -`\{(m_1, m_2, \dots, m_k, - \Sigma_{i=1}^k m_i) \mid (m_1, m_2, \dots, m_k) \in F_q^k\}` +A parity-check code of dimension `k` over `\GF{q}` is the set: +`\{(m_1, m_2, \dots, m_k, - \Sigma_{i=1}^k m_i) \mid (m_1, m_2, \dots, m_k) \in \GF{q}^k\}` REFERENCE: @@ -348,6 +349,7 @@ def message_space(self): """ return VectorSpace(self.code().base_field(), self.code().dimension()) + ####################### registration ############################### ParityCheckCode._registered_encoders["ParityCheckCodeGeneratorMatrixEncoder"] = ParityCheckCodeGeneratorMatrixEncoder diff --git a/src/sage/coding/punctured_code.py b/src/sage/coding/punctured_code.py index 4b3ae5f0a39..7aafa4f3f27 100644 --- a/src/sage/coding/punctured_code.py +++ b/src/sage/coding/punctured_code.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Punctured code @@ -28,7 +29,7 @@ def _puncture(v, points): r""" - Returns v punctured as the positions listed in ``points``. + Return v punctured as the positions listed in ``points``. INPUT: @@ -57,9 +58,9 @@ def _puncture(v, points): new_v = [v[i] for i in range(len(v)) if i not in points] return S(new_v) -def _insert_punctured_positions(l, punctured_points, value = None): +def _insert_punctured_positions(l, punctured_points, value=None): r""" - Returns ``l`` with ``value`` inserted in the corresponding + Return ``l`` with ``value`` inserted in the corresponding position from ``punctured_points``. INPUT: @@ -68,8 +69,9 @@ def _insert_punctured_positions(l, punctured_points, value = None): - ``punctured_points`` -- a set of integers - - ``value`` -- (default: ``None``) an element to insert in every position given in``punctured_points``. - If it is let to ``None``, a random value will be chosen for each insertion. + - ``value`` -- (default: ``None``) an element to insert in every position + given in``punctured_points``. If it is let to ``None``, a random value + will be chosen for each insertion. EXAMPLES:: @@ -92,7 +94,6 @@ def _insert_punctured_positions(l, punctured_points, value = None): return final - class PuncturedCode(AbstractLinearCode): r""" Representation of a punctured code. @@ -121,13 +122,15 @@ def __init__(self, C, positions): r""" TESTS: - If one of the positions to puncture is bigger than the length of ``C``, an exception will be raised:: + If one of the positions to puncture is bigger than the length of ``C``, + an exception will be raised:: sage: C = codes.random_linear_code(GF(7), 11, 5) sage: Cp = codes.PuncturedCode(C, {4,8,15}) Traceback (most recent call last): ... - ValueError: Positions to puncture must be positive integers smaller than the length of the provided code + ValueError: Positions to puncture must be positive integers smaller + than the length of the provided code """ if not isinstance(positions, (Integer, int, set, list)): raise TypeError("positions must be either a Sage Integer, a Python int, a set or a list") @@ -164,7 +167,7 @@ def __eq__(self, other): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -178,7 +181,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -192,7 +195,7 @@ def _latex_(self): def punctured_positions(self): r""" - Returns the list of positions which were punctured on the original code. + Return the list of positions which were punctured on the original code. EXAMPLES:: @@ -205,7 +208,7 @@ def punctured_positions(self): def original_code(self): r""" - Returns the linear code which was punctured to get ``self``. + Return the linear code which was punctured to get ``self``. EXAMPLES:: @@ -218,7 +221,7 @@ def original_code(self): def dimension(self): r""" - Returns the dimension of ``self``. + Return the dimension of ``self``. EXAMPLES:: @@ -235,7 +238,7 @@ def dimension(self): def random_element(self, *args, **kwds): r""" - Returns a random codeword of ``self``. + Return a random codeword of ``self``. This method does not trigger the computation of ``self``'s :meth:`sage.coding.linear_code_no_metric.generator_matrix`. @@ -279,7 +282,9 @@ def encode(self, m, original_encode=False, encoder_name=None, **kwargs): EXAMPLES:: - sage: M = matrix(GF(7), [[1, 0, 0, 0, 3, 4, 6], [0, 1, 0, 6, 1, 6, 4], [0, 0, 1, 5, 2, 2, 4]]) + sage: M = matrix(GF(7), [[1, 0, 0, 0, 3, 4, 6], + ....: [0, 1, 0, 6, 1, 6, 4], + ....: [0, 0, 1, 5, 2, 2, 4]]) sage: C_original = LinearCode(M) sage: Cp = codes.PuncturedCode(C_original, 2) sage: m = vector(GF(7), [1, 3, 5]) @@ -294,7 +299,7 @@ def encode(self, m, original_encode=False, encoder_name=None, **kwargs): @cached_method def structured_representation(self): r""" - Returns ``self`` as a structured code object. + Return ``self`` as a structured code object. If ``self`` has a specific structured representation (e.g. a punctured GRS code is a GRS code too), it will return this representation, else it returns a @@ -349,7 +354,8 @@ class PuncturedCodePuncturedMatrixEncoder(Encoder): sage: Cp = codes.PuncturedCode(C, 3) sage: E = codes.encoders.PuncturedCodePuncturedMatrixEncoder(Cp) sage: E - Punctured matrix-based encoder for the Puncturing of [11, 5] linear code over GF(7) on position(s) [3] + Punctured matrix-based encoder for the + Puncturing of [11, 5] linear code over GF(7) on position(s) [3] """ def __init__(self, code): @@ -370,7 +376,7 @@ def __init__(self, code): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -384,7 +390,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -399,7 +405,7 @@ def _latex_(self): @cached_method def generator_matrix(self): r""" - Returns a generator matrix of the associated code of ``self``. + Return a generator matrix of the associated code of ``self``. EXAMPLES:: @@ -425,13 +431,6 @@ def generator_matrix(self): return M - - - - - - - class PuncturedCodeOriginalCodeDecoder(Decoder): r""" Decoder decoding through a decoder over the original code of its punctured code. @@ -443,18 +442,19 @@ class PuncturedCodeOriginalCodeDecoder(Decoder): - ``strategy`` -- (default: ``None``) the strategy used to decode. The available strategies are: - * ``'error-erasure'`` -- uses an error-erasure decoder over the original code if available, - fails otherwise. + * ``'error-erasure'`` -- uses an error-erasure decoder over the original + code if available, fails otherwise. - * ``'random-values'`` -- fills the punctured positions with random elements - in ``code``'s base field and tries to decode using - the default decoder of the original code + * ``'random-values'`` -- fills the punctured positions with random elements + in ``code``'s base field and tries to decode using + the default decoder of the original code - * ``'try-all'`` -- fills the punctured positions with every possible combination of - symbols until decoding succeeds, or until every combination have been tried + * ``'try-all'`` -- fills the punctured positions with every possible + combination of symbols until decoding succeeds, or until every + combination have been tried - * ``None`` -- uses ``error-erasure`` if an error-erasure decoder is available, - switch to ``random-values`` behaviour otherwise + * ``None`` -- uses ``error-erasure`` if an error-erasure decoder is + available, switch to ``random-values`` behaviour otherwise - ``original_decoder`` -- (default: ``None``) the decoder that will be used over the original code. It has to be a decoder object over the original code. @@ -464,36 +464,39 @@ class PuncturedCodeOriginalCodeDecoder(Decoder): - ``**kwargs`` -- all extra arguments are forwarded to original code's decoder - EXAMPLES:: + EXAMPLES:: - sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'a').list()[:15], 7) - sage: Cp = codes.PuncturedCode(C, 3) - sage: codes.decoders.PuncturedCodeOriginalCodeDecoder(Cp) - Decoder of Puncturing of [15, 7, 9] Reed-Solomon Code over GF(16) on position(s) [3] through Error-Erasure decoder for [15, 7, 9] Reed-Solomon Code over GF(16) + sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'a').list()[:15], 7) + sage: Cp = codes.PuncturedCode(C, 3) + sage: codes.decoders.PuncturedCodeOriginalCodeDecoder(Cp) + Decoder of Puncturing of [15, 7, 9] Reed-Solomon Code over GF(16) on position(s) [3] + through Error-Erasure decoder for [15, 7, 9] Reed-Solomon Code over GF(16) - As seen above, if all optional are left blank, and if an error-erasure decoder is - available, it will be chosen as the original decoder. - Now, if one forces ``strategy `` to ``'try-all'`` or ``'random-values'``, the - default decoder of the original code will be chosen, even if an error-erasure is available:: + As seen above, if all optional are left blank, and if an error-erasure + decoder is available, it will be chosen as the original decoder. Now, if + one forces ``strategy`` to ``'try-all'`` or ``'random-values'``, the default + decoder of the original code will be chosen, even if an error-erasure is + available:: - sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'a').list()[:15], 7) - sage: Cp = codes.PuncturedCode(C, 3) - sage: D = codes.decoders.PuncturedCodeOriginalCodeDecoder(Cp, strategy="try-all") - sage: "error-erasure" in D.decoder_type() - False + sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'a').list()[:15], 7) + sage: Cp = codes.PuncturedCode(C, 3) + sage: D = codes.decoders.PuncturedCodeOriginalCodeDecoder(Cp, strategy="try-all") + sage: "error-erasure" in D.decoder_type() + False - And if one fills ``original_decoder`` and ``strategy`` fields with contradictory - elements, the ``original_decoder`` takes precedence:: + And if one fills ``original_decoder`` and ``strategy`` fields with + contradictory elements, the ``original_decoder`` takes precedence:: - sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'a').list()[:15], 7) - sage: Cp = codes.PuncturedCode(C, 3) - sage: Dor = C.decoder("Gao") - sage: D = codes.decoders.PuncturedCodeOriginalCodeDecoder(Cp, original_decoder = Dor, strategy="error-erasure") - sage: D.original_decoder() == Dor - True + sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'a').list()[:15], 7) + sage: Cp = codes.PuncturedCode(C, 3) + sage: Dor = C.decoder("Gao") + sage: D = codes.decoders.PuncturedCodeOriginalCodeDecoder(Cp, original_decoder=Dor, + ....: strategy="error-erasure") + sage: D.original_decoder() == Dor + True """ - def __init__(self, code, strategy = None, original_decoder = None, **kwargs): + def __init__(self, code, strategy=None, original_decoder=None, **kwargs): r""" TESTS: @@ -567,7 +570,7 @@ def __init__(self, code, strategy = None, original_decoder = None, **kwargs): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -580,10 +583,9 @@ def _repr_(self): """ return "Decoder of %s through %s" % (self.code(), self.original_decoder()) - def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -597,7 +599,7 @@ def _latex_(self): def original_decoder(self): r""" - Returns the decoder over the original code that will be used to decode words of + Return the decoder over the original code that will be used to decode words of :meth:`sage.coding.decoder.Decoder.code`. EXAMPLES:: @@ -612,7 +614,7 @@ def original_decoder(self): def decode_to_code(self, y): r""" - Decodes ``y`` to an element in :meth:`sage.coding.decoder.Decoder.code`. + Decode ``y`` to an element in :meth:`sage.coding.decoder.Decoder.code`. EXAMPLES:: @@ -661,7 +663,7 @@ def decode_to_code(self, y): try: shift = 0 for i in list_pts: - yl[i + shift] = values[shift] + yl[i + shift] = values[shift] shift += 1 y = A(yl) values = next(I) @@ -680,9 +682,9 @@ def decode_to_code(self, y): y = A(yl) return _puncture(D.decode_to_code(y), pts) - def decoding_radius(self, number_erasures = None): + def decoding_radius(self, number_erasures=None): r""" - Returns maximal number of errors that ``self`` can decode. + Return the maximal number of errors that ``self`` can decode. EXAMPLES:: @@ -707,6 +709,7 @@ def decoding_radius(self, number_erasures = None): elif "error-erasure" in D.decoder_type() and number_erasures is None: raise ValueError("You must provide the number of erasures") + ####################### registration ############################### PuncturedCode._registered_encoders["PuncturedMatrix"] = PuncturedCodePuncturedMatrixEncoder diff --git a/src/sage/coding/reed_muller_code.py b/src/sage/coding/reed_muller_code.py index 457f90bdab9..6885532757b 100644 --- a/src/sage/coding/reed_muller_code.py +++ b/src/sage/coding/reed_muller_code.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Reed-Muller code @@ -44,7 +45,7 @@ def _binomial_sum(n, k): r""" - Returns the sum of all binomials `\binom{n}{i}`, + Return the sum of all binomials `\binom{n}{i}`, with `i` ranging from `0` to `k` and including `k`. INPUT: @@ -67,7 +68,7 @@ def _binomial_sum(n, k): def _multivariate_polynomial_interpolation(evaluation, order, polynomial_ring): r""" - Returns `f \in \GF{q}[X_1,...,X_m]` such that `f(\mathbf a) = v[i(\mathbf a)]` + Return `f \in \GF{q}[X_1,...,X_m]` such that `f(\mathbf a) = v[i(\mathbf a)]` for all `\mathbf a \in \GF{q^m}`, where `v \in \GF{q}^{q^m}` is a given vector of evaluations, and `i(a)` is a specific ordering of `\GF{q^m}` (see below for details) @@ -132,7 +133,7 @@ def _interpolate(evaluation, num_of_var, order): def ReedMullerCode(base_field, order, num_of_var): r""" - Returns a Reed-Muller code. + Return a Reed-Muller code. A Reed-Muller Code of order `r` and number of variables `m` over a finite field `F` is the set: @@ -145,7 +146,7 @@ def ReedMullerCode(base_field, order, num_of_var): - ``base_field`` -- The finite field `F` over which the code is built. - ``order`` -- The order of the Reed-Muller Code, which is the maximum - degree of the polynomial to be used in the code. + degree of the polynomial to be used in the code. - ``num_of_var`` -- The number of variables used in polynomial. @@ -191,28 +192,30 @@ def ReedMullerCode(base_field, order, num_of_var): class QAryReedMullerCode(AbstractLinearCode): r""" - Representation of a q-ary Reed-Muller code. + Representation of a `q`-ary Reed-Muller code. For details on the definition of Reed-Muller codes, refer to :meth:`ReedMullerCode`. .. NOTE:: - It is better to use the aforementioned method rather than calling - this class directly, as :meth:`ReedMullerCode` creates either - a binary or a q-ary Reed-Muller code according to the arguments it receives. + It is better to use the aforementioned method rather than calling this + class directly, as :meth:`ReedMullerCode` creates either a binary or a + `q`-ary Reed-Muller code according to the arguments it receives. INPUT: - ``base_field`` -- A finite field, which is the base field of the code. - - ``order`` -- The order of the Reed-Muller Code, i.e., the maximum degree of the polynomial to be used in the code. + - ``order`` -- The order of the Reed-Muller Code, i.e., the maximum degree + of the polynomial to be used in the code. - ``num_of_var`` -- The number of variables used in polynomial. .. WARNING:: - For now, this implementation only supports Reed-Muller codes whose order is less than q. + For now, this implementation only supports Reed-Muller codes whose order + is less than q. EXAMPLES:: @@ -271,7 +274,7 @@ def __init__(self, base_field, order, num_of_var): def order(self): r""" - Returns the order of ``self``. + Return the order of ``self``. Order is the maximum degree of the polynomial used in the Reed-Muller code. @@ -287,7 +290,7 @@ def order(self): def number_of_variables(self): r""" - Returns the number of variables of the polynomial ring used in ``self``. + Return the number of variables of the polynomial ring used in ``self``. EXAMPLES:: @@ -301,9 +304,10 @@ def number_of_variables(self): def minimum_distance(self): r""" - Returns the minimum distance between two words in ``self``. + Return the minimum distance between two words in ``self``. - The minimum distance of a q-ary Reed-Muller code with order `d` and number of variables `m` is `(q-d)q^{m-1}` + The minimum distance of a `q`-ary Reed-Muller code with order `d` and + number of variables `m` is `(q-d)q^{m-1}` EXAMPLES:: @@ -320,7 +324,7 @@ def minimum_distance(self): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -335,7 +339,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -378,14 +382,15 @@ class BinaryReedMullerCode(AbstractLinearCode): .. NOTE:: - It is better to use the aforementioned method rather than calling - this class directly, as :meth:`ReedMullerCode` creates either - a binary or a q-ary Reed-Muller code according to the arguments it receives. + It is better to use the aforementioned method rather than calling this + class directly, as :meth:`ReedMullerCode` creates either a binary or a + `q`-ary Reed-Muller code according to the arguments it receives. INPUT: - - ``order`` -- The order of the Reed-Muller Code, i.e., the maximum degree of the polynomial to be used in the code. + - ``order`` -- The order of the Reed-Muller Code, i.e., the maximum degree + of the polynomial to be used in the code. - ``num_of_var`` -- The number of variables used in the polynomial. @@ -436,7 +441,9 @@ def __init__(self, order, num_of_var): def order(self): r""" - Returns the order of ``self``. Order is the maximum degree of the polynomial used in the Reed-Muller code. + Return the order of ``self``. + + Order is the maximum degree of the polynomial used in the Reed-Muller code. EXAMPLES:: @@ -448,7 +455,7 @@ def order(self): def number_of_variables(self): r""" - Returns the number of variables of the polynomial ring used in ``self``. + Return the number of variables of the polynomial ring used in ``self``. EXAMPLES:: @@ -460,8 +467,10 @@ def number_of_variables(self): def minimum_distance(self): r""" - Returns the minimum distance of ``self``. - The minimum distance of a binary Reed-Muller code of order `d` and number of variables `m` is `q^{m-d}` + Return the minimum distance of ``self``. + + The minimum distance of a binary Reed-Muller code of order `d` and + number of variables `m` is `q^{m-d}` EXAMPLES:: @@ -473,7 +482,7 @@ def minimum_distance(self): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -486,7 +495,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -520,12 +529,12 @@ class ReedMullerVectorEncoder(Encoder): Consider a Reed-Muller code of order `r`, number of variables `m`, length `n`, dimension `k` over some finite field `F`. Let those variables be `(x_1, x_2, \dots, x_m)`. - We order the monomials by lowest power on lowest index variables. If we have three monomials - `x_1 \times x_2`, `x_1 \times x_2^2` and `x_1^2 \times x_2`, the ordering is: - `x_1 \times x_2 < x_1 \times x_2^2 < x_1^2 \times x_2` + We order the monomials by lowest power on lowest index variables. If we have + three monomials `x_1 x_2`, `x_1 x_2^2` and `x_1^2 x_2`, the ordering is: + `x_1 x_2 < x_1 x_2^2 < x_1^2 x_2` Let now `(v_1,v_2,\ldots,v_k)` be a vector of `F`, which corresponds to the polynomial - `f = \Sigma^{k}_{i=1} v_i \times x_i`. + `f = \Sigma^{k}_{i=1} v_i x_i`. Let `(\beta_1, \beta_2, \ldots, \beta_q)` be the elements of `F` ordered as they are returned by Sage when calling ``F.list()``. @@ -533,8 +542,9 @@ class ReedMullerVectorEncoder(Encoder): The aforementioned polynomial `f` is encoded as: `(f(\alpha_{11},\alpha_{12},\ldots,\alpha_{1m}),f(\alpha_{21},\alpha_{22},\ldots, - \alpha_{2m}),\ldots,f(\alpha_{q^m1},\alpha_{q^m2},\ldots,\alpha_{q^mm}`, with - `\alpha_{ij}=\beta_{i \ mod \ q^j} \forall (i,j)` + \alpha_{2m}),\ldots,f(\alpha_{q^m1},\alpha_{q^m2},\ldots,\alpha_{q^mm}))` + + with `\alpha_{ij}=\beta_{i \bmod{q^j}}` for all `i`, `j)`. INPUT: @@ -542,21 +552,24 @@ class ReedMullerVectorEncoder(Encoder): EXAMPLES:: - sage: C1=codes.ReedMullerCode(GF(2), 2, 4) - sage: E1=codes.encoders.ReedMullerVectorEncoder(C1) + sage: C1 = codes.ReedMullerCode(GF(2), 2, 4) + sage: E1 = codes.encoders.ReedMullerVectorEncoder(C1) sage: E1 - Evaluation vector-style encoder for Binary Reed-Muller Code of order 2 and number of variables 4 - sage: C2=codes.ReedMullerCode(GF(3), 2, 2) - sage: E2=codes.encoders.ReedMullerVectorEncoder(C2) + Evaluation vector-style encoder for + Binary Reed-Muller Code of order 2 and number of variables 4 + sage: C2 = codes.ReedMullerCode(GF(3), 2, 2) + sage: E2 = codes.encoders.ReedMullerVectorEncoder(C2) sage: E2 - Evaluation vector-style encoder for Reed-Muller Code of order 2 and 2 variables over Finite Field of size 3 + Evaluation vector-style encoder for + Reed-Muller Code of order 2 and 2 variables over Finite Field of size 3 Actually, we can construct the encoder from ``C`` directly:: sage: C=codes.ReedMullerCode(GF(2), 2, 4) sage: E = C.encoder("EvaluationVector") sage: E - Evaluation vector-style encoder for Binary Reed-Muller Code of order 2 and number of variables 4 + Evaluation vector-style encoder for + Binary Reed-Muller Code of order 2 and number of variables 4 """ def __init__(self, code): @@ -582,7 +595,7 @@ def __init__(self, code): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -596,7 +609,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -629,7 +642,7 @@ def __eq__(self, other): @cached_method def generator_matrix(self): r""" - Returns a generator matrix of ``self`` + Return a generator matrix of ``self`` EXAMPLES:: @@ -663,7 +676,8 @@ def generator_matrix(self): def points(self): r""" - Returns the points of `F^m`, where `F` is base field and `m` is the number of variables, in order of which polynomials are evaluated on. + Return the points of `F^m`, where `F` is the base field and `m` is the + number of variables, in order of which polynomials are evaluated on. EXAMPLES:: @@ -686,8 +700,8 @@ class ReedMullerPolynomialEncoder(Encoder): dimension `k` over some finite field `F`. Let those variables be `(x_1, x_2, \dots, x_m)`. We order the monomials by lowest power on lowest index variables. If we have three monomials - `x_1 \times x_2`, `x_1 \times x_2^2` and `x_1^2 \times x_2`, the ordering is: - `x_1 \times x_2 < x_1 \times x_2^2 < x_1^2 \times x_2` + `x_1 x_2`, `x_1 x_2^2` and `x_1^2 x_2`, the ordering is: + `x_1 x_2 < x_1 x_2^2 < x_1^2 x_2` Let now `f` be a polynomial of the multivariate polynomial ring `F[x_1, \dots, x_m]`. @@ -697,42 +711,46 @@ class ReedMullerPolynomialEncoder(Encoder): The aforementioned polynomial `f` is encoded as: `(f(\alpha_{11},\alpha_{12},\ldots,\alpha_{1m}),f(\alpha_{21},\alpha_{22},\ldots, - \alpha_{2m}),\ldots,f(\alpha_{q^m1},\alpha_{q^m2},\ldots,\alpha_{q^mm}`, with - `\alpha_{ij}=\beta_{i \ mod \ q^j} \forall (i,j)` + \alpha_{2m}),\ldots,f(\alpha_{q^m1},\alpha_{q^m2},\ldots,\alpha_{q^mm}))` + with `\alpha_{ij}=\beta_{i \bmod{q^j}}` for all `i`, `j`. INPUT: - ``code`` -- The associated code of this encoder. - -``polynomial_ring`` -- (default:``None``) The polynomial ring from which the message is chosen. - If this is set to ``None``, a polynomial ring in `x` will be built - from the code parameters. + - ``polynomial_ring`` -- (default:``None``) The polynomial ring from which + the message is chosen. If this is set to ``None``, a polynomial ring in + `x` will be built from the code parameters. EXAMPLES:: - sage: C1=codes.ReedMullerCode(GF(2), 2, 4) - sage: E1=codes.encoders.ReedMullerPolynomialEncoder(C1) + sage: C1 = codes.ReedMullerCode(GF(2), 2, 4) + sage: E1 = codes.encoders.ReedMullerPolynomialEncoder(C1) sage: E1 - Evaluation polynomial-style encoder for Binary Reed-Muller Code of order 2 and number of variables 4 - sage: C2=codes.ReedMullerCode(GF(3), 2, 2) - sage: E2=codes.encoders.ReedMullerPolynomialEncoder(C2) + Evaluation polynomial-style encoder for + Binary Reed-Muller Code of order 2 and number of variables 4 + sage: C2 = codes.ReedMullerCode(GF(3), 2, 2) + sage: E2 = codes.encoders.ReedMullerPolynomialEncoder(C2) sage: E2 - Evaluation polynomial-style encoder for Reed-Muller Code of order 2 and 2 variables over Finite Field of size 3 + Evaluation polynomial-style encoder for + Reed-Muller Code of order 2 and 2 variables over Finite Field of size 3 We can also pass a predefined polynomial ring:: - sage: R=PolynomialRing(GF(3), 2, 'y') - sage: C=codes.ReedMullerCode(GF(3), 2, 2) - sage: E=codes.encoders.ReedMullerPolynomialEncoder(C, R) + sage: R = PolynomialRing(GF(3), 2, 'y') + sage: C = codes.ReedMullerCode(GF(3), 2, 2) + sage: E = codes.encoders.ReedMullerPolynomialEncoder(C, R) sage: E - Evaluation polynomial-style encoder for Reed-Muller Code of order 2 and 2 variables over Finite Field of size 3 + Evaluation polynomial-style encoder for + Reed-Muller Code of order 2 and 2 variables over Finite Field of size 3 Actually, we can construct the encoder from ``C`` directly:: sage: E = C1.encoder("EvaluationPolynomial") sage: E - Evaluation polynomial-style encoder for Binary Reed-Muller Code of order 2 and number of variables 4 + Evaluation polynomial-style encoder for + Binary Reed-Muller Code of order 2 and number of variables 4 """ def __init__(self, code, polynomial_ring=None): @@ -776,7 +794,7 @@ def __init__(self, code, polynomial_ring=None): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -790,7 +808,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -846,7 +864,7 @@ def encode(self, p): True If a polynomial with good monomial degree but wrong monomial - degree is given,an error is raised:: + degree is given, an error is raised:: sage: p = x0^2*x1 sage: E.encode(p) @@ -861,7 +879,8 @@ def encode(self, p): sage: E.encode(p) Traceback (most recent call last): ... - ValueError: The value to encode must be in Multivariate Polynomial Ring in x0, x1 over Finite Field of size 3 + ValueError: The value to encode must be in + Multivariate Polynomial Ring in x0, x1 over Finite Field of size 3 """ M = self.message_space() if p not in M: @@ -875,7 +894,7 @@ def encode(self, p): def unencode_nocheck(self, c): r""" - Returns the message corresponding to the codeword ``c``. + Return the message corresponding to the codeword ``c``. Use this method with caution: it does not check if ``c`` belongs to the code, and if this is not the case, the output is @@ -921,7 +940,7 @@ def unencode_nocheck(self, c): def message_space(self): r""" - Returns the message space of ``self`` + Return the message space of ``self`` EXAMPLES:: @@ -935,7 +954,7 @@ def message_space(self): def polynomial_ring(self): r""" - Returns the polynomial ring associated with ``self`` + Return the polynomial ring associated with ``self`` EXAMPLES:: @@ -949,7 +968,7 @@ def polynomial_ring(self): def points(self): r""" - Returns the evaluation points in the appropriate order as used by ``self`` when + Return the evaluation points in the appropriate order as used by ``self`` when encoding a message. EXAMPLES:: diff --git a/src/sage/coding/self_dual_codes.py b/src/sage/coding/self_dual_codes.py index 49125e8fb01..67f90226ccb 100644 --- a/src/sage/coding/self_dual_codes.py +++ b/src/sage/coding/self_dual_codes.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.groups sage.modules r""" Enumerating binary self-dual codes @@ -5,68 +6,67 @@ The main function is ``self_dual_binary_codes``, which is a case-by-case list of entries, each represented by a Python dictionary. -Format of each entry: a Python dictionary with keys "order autgp", "spectrum", -"code", "Comment", "Type", where +Format of each entry: a Python dictionary with keys ``"order autgp"``, ``"spectrum"``, +``"code"``, ``"Comment"``, ``"Type"``, where -- "code" - a sd code C of length n, dim n/2, over GF(2) +- ``"code"`` -- a sd code `C` of length `n`, dim `n/2`, over `\GF{2}` -- "order autgp" - order of the permutation automorphism group of C +- ``"order autgp"`` -- order of the permutation automorphism group of `C` -- "Type" - the type of C (which can be "I" or "II", in the binary case) +- ``"Type"`` -- the type of `C` (which can be ``"I"`` or ``"II"``, in the binary case) -- "spectrum" - the spectrum [A0,A1,...,An] +- ``"spectrum"`` -- the spectrum `[A_0,A_1,...,A_n]` -- "Comment" - possibly an empty string. +- ``"Comment"`` -- possibly an empty string. Python dictionaries were used since they seemed to be both human-readable and allow others to update the database easiest. -- The following double for loop can be time-consuming but should - be run once in awhile for testing purposes. It should only print - True and have no trace-back errors:: +- The following double ``for`` loop can be time-consuming but should + be run once in a while for testing purposes. It should only print + ``True`` and have no trace-back errors:: - for n in [4,6,8,10,12,14,16,18,20,22]: - C = self_dual_binary_codes(n); m = len(C.keys()) - for i in range(m): - C0 = C["%s"%n]["%s"%i]["code"] - print([n,i,C["%s"%n]["%s"%i]["spectrum"] == C0.spectrum()]) - print(C0 == C0.dual_code()) - G = C0.automorphism_group_binary_code() - print(C["%s" % n]["%s" % i]["order autgp"] == G.order()) + sage: for n in [4,6,8,10,12,14,16,18,20,22]: # not tested + ....: C = self_dual_binary_codes(n); m = len(C.keys()) + ....: for i in range(m): + ....: C0 = C["%s"%n]["%s"%i]["code"] + ....: print([n,i,C["%s"%n]["%s"%i]["spectrum"] == C0.spectrum()]) + ....: print(C0 == C0.dual_code()) + ....: G = C0.automorphism_group_binary_code() + ....: print(C["%s" % n]["%s" % i]["order autgp"] == G.order()) - To check if the "Riemann hypothesis" holds, run the following code:: - R = PolynomialRing(CC,"T") - T = R.gen() - for n in [4,6,8,10,12,14,16,18,20,22]: - C = self_dual_binary_codes(n); m = len(C["%s"%n].keys()) - for i in range(m): - C0 = C["%s"%n]["%s"%i]["code"] - if C0.minimum_distance()>2: - f = R(C0.sd_zeta_polynomial()) - print([n,i,[z[0].abs() for z in f.roots()]]) - + sage: R = PolynomialRing(CC,"T") # not tested + sage: T = R.gen() # not tested + sage: for n in [4,6,8,10,12,14,16,18,20,22]: # not tested + ....: C = self_dual_binary_codes(n); m = len(C["%s"%n].keys()) + ....: for i in range(m): + ....: C0 = C["%s"%n]["%s"%i]["code"] + ....: if C0.minimum_distance()>2: + ....: f = R(C0.sd_zeta_polynomial()) + ....: print([n,i,[z[0].abs() for z in f.roots()]]) You should get lists of numbers equal to 0.707106781186548. Here's a rather naive construction of self-dual codes in the binary case: -For even m, let A_m denote the mxm matrix over GF(2) given by adding -the all 1's matrix to the identity matrix (in -``MatrixSpace(GF(2),m,m)`` of course). If M_1, ..., M_r are square -matrices, let `diag(M_1,M_2,...,M_r)` denote the"block diagonal" -matrix with the `M_i` 's on the diagonal and 0's elsewhere. Let +For even `m`, let `A_m` denote the `m\times m` matrix over `\GF{2}` +given by adding the all 1's matrix to the identity matrix (in +``MatrixSpace(GF(2),m,m)`` of course). If `M_1, ..., M_r` are square +matrices, let `diag(M_1,M_2,...,M_r)` denote the "block diagonal" +matrix with the matrices `M_i` on the diagonal and 0's elsewhere. Let `C(m_1,...,m_r,s)` denote the linear code with generator matrix having block form `G = (I, A)`, where `A = diag(A_{m_1},A_{m_2},...,A_{m_r},I_s)`, for some -(even) `m_i` 's and `s`, where +(even) `m_i`'s and `s`, where `m_1+m_2+...+m_r+s=n/2`. Note: Such codes `C(m_1,...,m_r,s)` are SD. SD codes not of this form will be called (for the purpose of -documenting the code below) "exceptional". Except when n is +documenting the code below) "exceptional". Except when `n` is "small", most sd codes are exceptional (based on a counting argument and table 9.1 in the Huffman+Pless [HP2003]_, page 347). @@ -213,13 +213,14 @@ def _And7(): [1 0 1 1 0 0 0] [1 1 0 1 0 0 0] """ - return matrix(_F, [[1, 1, 1, 0, 0, 1, 1],\ - [1, 1, 1, 0, 1, 0, 1],\ - [1, 1, 1, 0, 1, 1, 0],\ - [0, 0, 0, 0, 1, 1, 1],\ - [0, 1, 1, 1, 0, 0, 0],\ - [1, 0, 1, 1, 0, 0, 0],\ - [1, 1, 0, 1, 0, 0, 0]]) + return matrix(_F, [[1, 1, 1, 0, 0, 1, 1], + [1, 1, 1, 0, 1, 0, 1], + [1, 1, 1, 0, 1, 1, 0], + [0, 0, 0, 0, 1, 1, 1], + [0, 1, 1, 1, 0, 0, 0], + [1, 0, 1, 1, 0, 0, 0], + [1, 1, 0, 1, 0, 0, 0]]) + @cached_function def _H8(): @@ -239,14 +240,14 @@ def _H8(): [ 1 1 -1 -1 -1 -1 1 1] [ 1 -1 -1 1 -1 1 1 -1] """ - return matrix(ZZ, [[1, 1, 1, 1, 1, 1, 1, 1],\ - [1, -1, 1, -1, 1, -1, 1, -1],\ - [1, 1, -1, -1, 1, 1, -1, -1],\ - [1, -1, -1, 1, 1, -1, -1, 1],\ - [1, 1, 1, 1, -1, -1, -1, -1],\ - [1, -1, 1, -1, -1, 1, -1, 1],\ - [1, 1, -1, -1, -1, -1, 1, 1],\ - [1, -1, -1, 1, -1, 1, 1, -1]]) # from Guava's Hadamard matrices database + return matrix(ZZ, [[1, 1, 1, 1, 1, 1, 1, 1], + [1, -1, 1, -1, 1, -1, 1, -1], + [1, 1, -1, -1, 1, 1, -1, -1], + [1, -1, -1, 1, 1, -1, -1, 1], + [1, 1, 1, 1, -1, -1, -1, -1], + [1, -1, 1, -1, -1, 1, -1, 1], + [1, 1, -1, -1, -1, -1, 1, 1], + [1, -1, -1, 1, -1, 1, 1, -1]]) # from Guava's Hadamard matrices database # Remark: The above matrix constructions aid in computing some "small" self-dual codes. @@ -254,25 +255,25 @@ def _H8(): def self_dual_binary_codes(n): r""" - Returns the dictionary of inequivalent binary self dual codes of length n. + Return the dictionary of inequivalent binary self dual codes of length `n`. - For n=4 even, returns the sd codes of a given length, up to (perm) + For `n=4` even, returns the sd codes of a given length, up to (perm) equivalence, the (perm) aut gp, and the type. - The number of inequiv "diagonal" sd binary codes in the database of + The number of inequivalent "diagonal" sd binary codes in the database of length n is ("diagonal" is defined by the conjecture above) is the - same as the restricted partition number of n, where only integers - from the set 1,4,6,8,... are allowed. This is the coefficient of + same as the restricted partition number of `n`, where only integers + from the set 1, 4, 6, 8, ... are allowed. This is the coefficient of `x^n` in the series expansion `(1-x)^{-1}\prod_{2^\infty (1-x^{2j})^{-1}}`. Typing the - command f = (1-x)(-1)\*prod([(1-x(2\*j))(-1) for j in range(2,18)]) + command ``f = (1-x)(-1)\*prod([(1-x(2\*j))(-1) for j in range(2,18)])`` into Sage, we obtain for the coeffs of `x^4`, `x^6`, ... [1, 1, 2, 2, 3, 3, 5, 5, 7, 7, 11, 11, 15, 15, 22, 22, 30, 30, 42, 42, 56, 56, 77, 77, 101, 101, 135, 135, 176, 176, 231] These numbers grow too slowly to account for all the sd codes (see Huffman+Pless' Table 9.1, referenced above). In fact, in - Table 9.10 of [HP2003]_, the number B_n of inequivalent sd binary codes - of length n is given:: + Table 9.10 of [HP2003]_, the number `B_n` of inequivalent sd binary codes + of length `n` is given:: n 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 B_n 1 1 1 2 2 3 4 7 9 16 25 55 103 261 731 @@ -287,7 +288,7 @@ def self_dual_binary_codes(n): True sage: C["10"]["1"]["code"] == C["10"]["1"]["code"].dual_code() True - sage: len(C["10"].keys()) # number of inequiv sd codes of length 10 + sage: len(C["10"].keys()) # number of inequiv sd codes of length 10 2 sage: C = codes.databases.self_dual_binary_codes(12) sage: C["12"]["0"]["code"] == C["12"]["0"]["code"].dual_code() @@ -305,7 +306,7 @@ def self_dual_binary_codes(n): genmat = _I2(n).augment(_I2(n)) # G = PermutationGroup([ "(2,4)", "(1,2)(3,4)" ]) spectrum = [1, 0, 2, 0, 1] - self_dual_codes_4_0 = {"order autgp":8,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_4_0 = {"order autgp":8,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Unique."} self_dual_codes["4"] = {"0":self_dual_codes_4_0} return self_dual_codes @@ -316,7 +317,7 @@ def self_dual_binary_codes(n): genmat = _I2(n).augment(_I2(n)) # G = PermutationGroup( ["(3,6)", "(2,3)(5,6)", "(1,2)(4,5)"] ) spectrum = [1, 0, 3, 0, 3, 0, 1] - self_dual_codes_6_0 = {"order autgp":48,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_6_0 = {"order autgp":48,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Unique"} self_dual_codes["6"] = {"0":self_dual_codes_6_0} return self_dual_codes @@ -328,14 +329,14 @@ def self_dual_binary_codes(n): genmat = _I2(n).augment(_I2(n)) # G = PermutationGroup( ["(4,8)", "(3,4)(7,8)", "(2,3)(6,7)", "(1,2)(5,6)"] ) spectrum = [1, 0, 4, 0, 6, 0, 4, 0, 1] - self_dual_codes_8_0 = {"order autgp":384,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_8_0 = {"order autgp":384,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Unique Type I of this length."} # [8,1]: genmat = _I2(n).augment(_matA(n)[4]) # G = PermutationGroup( ["(4,5)(6,7)", "(4,6)(5,7)", "(3,4)(7,8)",\ # "(2,3)(6,7)", "(1,2)(5,6)"] ) spectrum = [1, 0, 0, 0, 14, 0, 0, 0, 1] - self_dual_codes_8_1 = {"order autgp":1344,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_8_1 = {"order autgp":1344,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"II","Comment":"Unique Type II of this length."} self_dual_codes["8"] = {"0":self_dual_codes_8_0,"1":self_dual_codes_8_1} return self_dual_codes @@ -347,14 +348,14 @@ def self_dual_binary_codes(n): # G = PermutationGroup( ["(5,10)", "(4,5)(9,10)", "(3,4)(8,9)",\ # "(2,3)(7,8)", "(1,2)(6,7)"] ) spectrum = [1, 0, 5, 0, 10, 0, 10, 0, 5, 0, 1] - self_dual_codes_10_0 = {"order autgp":3840,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_10_0 = {"order autgp":3840,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"No Type II of this length."} # [10,1]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) # G = PermutationGroup( ["(5,10)", "(4,6)(7,8)", "(4,7)(6,8)", "(3,4)(8,9)",\ # "(2,3)(7,8)", "(1,2)(6,7)"] ) spectrum = [1, 0, 1, 0, 14, 0, 14, 0, 1, 0, 1] - self_dual_codes_10_1 = {"order autgp":2688,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_10_1 = {"order autgp":2688,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Unique lowest weight nonzero codeword."} self_dual_codes["10"] = {"0":self_dual_codes_10_0,"1":self_dual_codes_10_1} return self_dual_codes @@ -366,21 +367,21 @@ def self_dual_binary_codes(n): # G = PermutationGroup( ["(6,12)", "(5,6)(11,12)", "(4,5)(10,11)", "(3,4)(9,10)",\ # "(2,3)(8,9)", "(1,2)(7,8)"] ) spectrum = [1, 0, 6, 0, 15, 0, 20, 0, 15, 0, 6, 0, 1] - self_dual_codes_12_0 = {"order autgp":48080,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_12_0 = {"order autgp":48080,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"No Type II of this length."} # [12,1]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) # G = PermutationGroup( ["(2,3)(4,7)", "(2,4)(3,7)", "(2,4,9)(3,7,8)", "(2,4,8,10)(3,9)",\ # "(1,2,4,7,8,10)(3,9)", "(2,4,8,10)(3,9)(6,12)", "(2,4,8,10)(3,9)(5,6,11,12)"] ) spectrum = [1, 0, 2, 0, 15, 0, 28, 0, 15, 0, 2, 0, 1] - self_dual_codes_12_1 = {"order autgp":10752,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_12_1 = {"order autgp":10752,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Smallest automorphism group of these."} # [12,2]: genmat = _I2(n).augment(_matA(n)[6]) # G = PermutationGroup( ["(5,6)(11,12)", "(5,11)(6,12)", "(4,5)(10,11)", "(3,4)(9,10)",\ # "(2,3)(8,9)", "(1,2)(7,8)"] ) spectrum = [1, 0, 0, 0, 15, 0, 32, 0, 15, 0, 0, 0, 1] - self_dual_codes_12_2 = {"order autgp":23040,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_12_2 = {"order autgp":23040,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Largest minimum distance of these."} self_dual_codes["12"] = {"0":self_dual_codes_12_0,"1":self_dual_codes_12_1,"2":self_dual_codes_12_2} return self_dual_codes @@ -393,21 +394,21 @@ def self_dual_binary_codes(n): # G = PermutationGroup( ["(7,14)", "(6,7)(13,14)", "(5,6)(12,13)", "(4,5)(11,12)",\ # "(3,4)(10,11)", "(2,3)(9,10)", "(1,2)(8,9)"] ) spectrum = [1, 0, 7, 0, 21, 0, 35, 0, 35, 0, 21, 0, 7, 0, 1] - self_dual_codes_14_0 = {"order autgp":645120,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_14_0 = {"order autgp":645120,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"No Type II of this length. Huge aut gp."} # [14,1]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) # G = PermutationGroup( ["(7,14)", "(6,7)(13,14)", "(5,6)(12,13)", "(4,8)(9,10)",\ # "(4,9)(8,10)", "(3,4)(10,11)", "(2,3)(9,10)", "(1,2)(8,9)"] ) spectrum = [1, 0, 3, 0, 17, 0, 43, 0, 43, 0, 17, 0, 3, 0, 1] - self_dual_codes_14_1 = {"order autgp":64512,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_14_1 = {"order autgp":64512,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Automorphism group has order 64512."} # [14,2]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matId(n)[6]])) # G = PermutationGroup( ["(7,14)", "(5,6)(12,13)", "(5,12)(6,13)", "(4,5)(11,12)",\ # "(3,4)(10,11)", "(2,3)(9,10)", "(1,2)(8,9)"] ) spectrum = [1, 0, 1, 0, 15, 0, 47, 0, 47, 0, 15, 0, 1, 0, 1] - self_dual_codes_14_2 = {"order autgp":46080,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_14_2 = {"order autgp":46080,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Unique codeword of weight 2."} # [14,3]: genmat = _I2(n).augment(_And7()) @@ -415,9 +416,9 @@ def self_dual_binary_codes(n): # "(6,10)(9,14)", "(5,6)(8,9)", "(4,5)(9,10), (2,3)(11,12)", "(2,7)(3,13)",\ # "(1,2)(12,13)", "(1,4)(2,5)(3,8)(6,7)(9,13)(10,12)(11,14)"]) spectrum = [1, 0, 0, 0, 14, 0, 49, 0, 49, 0, 14, 0, 0, 0, 1] - self_dual_codes_14_3 = {"order autgp":56448,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_14_3 = {"order autgp":56448,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Largest minimum distance of these."} - self_dual_codes["14"] = {"0":self_dual_codes_14_0,"1":self_dual_codes_14_1,"2":self_dual_codes_14_2,\ + self_dual_codes["14"] = {"0":self_dual_codes_14_0,"1":self_dual_codes_14_1,"2":self_dual_codes_14_2, "3":self_dual_codes_14_3} return self_dual_codes @@ -429,14 +430,14 @@ def self_dual_binary_codes(n): # G = PermutationGroup( [ "(8,16)", "(7,8)(15,16)", "(6,7)(14,15)", "(5,6)(13,14)", # "(4,5)(12,13)", "(3,4)(11,12)", "(2,3)(10,11)", "(1,2)(9,10)"] ) spectrum = [1, 0, 8, 0, 28, 0, 56, 0, 70, 0, 56, 0, 28, 0, 8, 0, 1] - self_dual_codes_16_0 = {"order autgp":10321920,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_16_0 = {"order autgp":10321920,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Huge aut gp."} # [16,1]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) # G = PermutationGroup( [ "(8,16)", "(7,8)(15,16)", "(6,7)(14,15)", "(5,6)(13,14)",\ # "(4,9)(10,11)", "(4,10)(9,11)", "(3,4)(11,12)", "(2,3)(10,11)", "(1,2)(9,10)"] ) spectrum = [1, 0, 4, 0, 20, 0, 60, 0, 86, 0, 60, 0, 20, 0, 4, 0, 1] - self_dual_codes_16_1 = {"order autgp":516096,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_16_1 = {"order autgp":516096,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":""} # [16,2]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matA(n)[4]])) @@ -444,14 +445,14 @@ def self_dual_binary_codes(n): # "(5,6)(13,14)", "(4,9)(10,11)", "(4,10)(9,11)", "(3,4)(11,12)", "(2,3)(10,11)",\ # "(1,2)(9,10)","(1,5)(2,6)(3,7)(4,8)(9,13)(10,14)(11,15)(12,16)"] ) spectrum = [1, 0, 0, 0, 28, 0, 0, 0, 198, 0, 0, 0, 28, 0, 0, 0, 1] - self_dual_codes_16_2 = {"order autgp":3612672,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_16_2 = {"order autgp":3612672,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"II","Comment":"Same spectrum as the other Type II code."} # [16,3]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matId(n)[6]])) # G = PermutationGroup( [ "(8,16)", "(7,8)(15,16)", "(5,6)(13,14)", "(5,13)(6,14)",\ # "(4,5)(12,13)", "(3,4)(11,12)", "(2,3)(10,11)", "(1,2)(9,10)"] ) spectrum = [1, 0, 2, 0, 16, 0, 62, 0, 94, 0, 62, 0, 16, 0, 2, 0, 1] - self_dual_codes_16_3 = {"order autgp":184320,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_16_3 = {"order autgp":184320,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":""} # [16,4]: genmat = _I2(n).augment(_matA(n)[8]) @@ -467,7 +468,7 @@ def self_dual_binary_codes(n): # G = PermutationGroup( [ "(7,8)(15,16)", "(7,15)(8,16)", "(6,7)(14,15)",\ # "(5,6)(13,14)","(4,5)(12,13)","(3,4)(11,12)", "(2,3)(10,11)", "(1,2)(9,10)"] ) spectrum = [1, 0, 0, 0, 28, 0, 0, 0, 198, 0, 0, 0, 28, 0, 0, 0, 1] - self_dual_codes_16_4 = {"order autgp":5160960,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_16_4 = {"order autgp":5160960,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"II","Comment":"Same spectrum as the other Type II code. Large aut gp."} # [16,5]: genmat = _I2(n).augment(block_diagonal_matrix([_And7(),_matId(n)[7]])) @@ -476,7 +477,7 @@ def self_dual_binary_codes(n): # "(2,3)(12,13)", "(2,7)(3,14)", "(1,2)(13,14)",\ # "(1,4)(2,5)(3,9)(6,7)(10,14)(11,13)(12,15)" ] ) spectrum = [1, 0, 1, 0, 14, 0, 63, 0, 98, 0, 63, 0, 14, 0, 1, 0, 1] - self_dual_codes_16_5 = {"order autgp":112896,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_16_5 = {"order autgp":112896,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"'Exceptional' construction."} # [16,6]: J8 = MatrixSpace(ZZ,8,8)(64*[1]) @@ -485,9 +486,9 @@ def self_dual_binary_codes(n): # "(4,6)(11,13)", "(3,5)(12,14)", "(3,12)(5,14)", "(2,3)(14,15)",\ # "(1,2)(8,15)", "(1,4)(2,6)(3,7)(5,16)(8,13)(9,12)(10,14)(11,15)" ] ) spectrum = [1, 0, 0, 0, 12, 0, 64, 0, 102, 0, 64, 0, 12, 0, 0, 0, 1] - self_dual_codes_16_6 = {"order autgp":73728,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_16_6 = {"order autgp":73728,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"'Exceptional' construction. Min dist 4."} - self_dual_codes["16"] = {"0":self_dual_codes_16_0,"1":self_dual_codes_16_1,"2":self_dual_codes_16_2,\ + self_dual_codes["16"] = {"0":self_dual_codes_16_0,"1":self_dual_codes_16_1,"2":self_dual_codes_16_2, "3":self_dual_codes_16_3,"4":self_dual_codes_16_4,"5":self_dual_codes_16_5,"6":self_dual_codes_16_6} return self_dual_codes @@ -500,7 +501,7 @@ def self_dual_binary_codes(n): # G = PermutationGroup( [ "(9,18)", "(8,9)(17,18)", "(7,8)(16,17)", "(6,7)(15,16)",\ # "(5,6)(14,15)", "(4,5)(13,14)", "(3,4)(12,13)", "(2,3)(11,12)", "(1,2)(10,11)" ] ) spectrum = [1, 0, 9, 0, 36, 0, 84, 0, 126, 0, 126, 0, 84, 0, 36, 0, 9, 0, 1] - self_dual_codes_18_0 = {"order autgp":185794560,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_18_0 = {"order autgp":185794560,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "Huge aut gp. S_9x(ZZ/2ZZ)^9?"} # [18,1]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) @@ -508,14 +509,14 @@ def self_dual_binary_codes(n): # "(5,6)(14,15)", "(4,10)(11,12)", "(4,11)(10,12)", "(3,4)(12,13)",\ # "(2,3)(11,12)", "(1,2)(10,11)" ] ) spectrum = [1, 0, 5, 0, 24, 0, 80, 0, 146, 0, 146, 0, 80, 0, 24, 0, 5, 0, 1] - self_dual_codes_18_1 = {"order autgp":5160960,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_18_1 = {"order autgp":5160960,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "Large aut gp."} # [18,2]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matId(n)[6]])) # G = PermutationGroup( [ "(9,18)", "(8,9)(17,18)", "(7,8)(16,17)", "(5,6)(14,15)",\ # "(5,14)(6,15)","(4,5)(13,14)", "(3,4)(12,13)", "(2,3)(11,12)", "(1,2)(10,11)"] ) spectrum = [1, 0, 3, 0, 18, 0, 78, 0, 156, 0, 156, 0, 78, 0, 18, 0, 3, 0, 1] - self_dual_codes_18_2 = {"order autgp":1105920,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_18_2 = {"order autgp":1105920,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": ""} # [18,3]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matA(n)[4],_matId(n)[8]])) @@ -524,7 +525,7 @@ def self_dual_binary_codes(n): # "(3,4)(12,13)", "(2,3)(11,12)","(1,2)(10,11)",\ # "(1,5)(2,6)(3,7)(4,8)(10,14)(11,15)(12,16)(13,17)" ] ) spectrum = [1, 0, 1, 0, 28, 0, 28, 0, 198, 0, 198, 0, 28, 0, 28, 0, 1, 0, 1] - self_dual_codes_18_3 = {"order autgp":7225344,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_18_3 = {"order autgp":7225344,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "Large aut gp. Unique codeword of smallest non-zero wt.\ Same spectrum as '[18,4]' sd code."} # [18,4]: @@ -532,7 +533,7 @@ def self_dual_binary_codes(n): # G = PermutationGroup( [ "(9,18)", "(7,8)(16,17)", "(7,16)(8,17)", "(6,7)(15,16)", \ # "(5,6)(14,15)", "(4,5)(13,14)", "(3,4)(12,13)", "(2,3)(11,12)", "(1,2)(10,11)" ] ) spectrum = [1, 0, 1, 0, 28, 0, 28, 0, 198, 0, 198, 0, 28, 0, 28, 0, 1, 0, 1] - self_dual_codes_18_4 = {"order autgp":10321920,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_18_4 = {"order autgp":10321920,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "Huge aut gp. Unique codeword of smallest non-zero wt.\ Same spectrum as '[18,3]' sd code."} # [18,5]: @@ -546,87 +547,86 @@ def self_dual_binary_codes(n): # "(2,16,14)(3,15,4)(5,11,10,7,12,6,13)(9,18)",\ # "(2,16,14)(3,15,4)(5,11,10,7,12,6,13)(8,9,17,18)" ] ) spectrum = [1, 0, 2, 0, 15, 0, 77, 0, 161, 0, 161, 0, 77, 0, 15, 0, 2, 0, 1] - self_dual_codes_18_5 = {"order autgp":451584,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_18_5 = {"order autgp":451584,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "'Exceptional' construction."} # [18,6]: C = self_dual_binary_codes(n-2)["%s"%(n-2)]["6"]["code"] A0 = C.redundancy_matrix() genmat = _I2(n).augment(block_diagonal_matrix([A0,_matId(n)[8]])) - G = PermutationGroup( [ "(9,18)", "(7,10)(11,17)", "(7,11)(10,17)", "(6,7)(11,12)",\ - "(4,6)(12,14)", "(3,5)(13,15)", "(3,13)(5,15)", "(2,3)(15,16)", "(1,2)(8,16)",\ + G = PermutationGroup( [ "(9,18)", "(7,10)(11,17)", "(7,11)(10,17)", "(6,7)(11,12)", + "(4,6)(12,14)", "(3,5)(13,15)", "(3,13)(5,15)", "(2,3)(15,16)", "(1,2)(8,16)", "(1,4)(2,6)(3,7)(5,17)(8,14)(10,13)(11,15)(12,16)" ] ) spectrum = [1, 0, 1, 0, 12, 0, 76, 0, 166, 0, 166, 0, 76, 0, 12, 0, 1, 0, 1] - self_dual_codes_18_6 = {"order autgp":147456,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_18_6 = {"order autgp":147456,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "'Exceptional'. Unique codeword of smallest non-zero wt."} # [18,7] (equiv to H18 in [P]) - genmat = _MS(n)([[1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0],\ - [0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1],\ - [0,0,1,0,0,0,0,0,0,1,1,1,0,0,1,0,0,1],\ - [0,0,0,1,0,0,0,0,0,1,1,1,1,0,0,0,0,1],\ - [0,0,0,0,1,0,0,0,0,1,1,0,0,1,0,1,1,0],\ - [0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,1,0],\ - [0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0],\ - [0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1],\ - [0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,1]]) + genmat = _MS(n)([[1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0], + [0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1], + [0,0,1,0,0,0,0,0,0,1,1,1,0,0,1,0,0,1], + [0,0,0,1,0,0,0,0,0,1,1,1,1,0,0,0,0,1], + [0,0,0,0,1,0,0,0,0,1,1,0,0,1,0,1,1,0], + [0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,1,0], + [0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0], + [0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1], + [0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,1]]) # G = PermutationGroup( [ "(9,10)(16,18)", "(9,16)(10,18)", "(8,9)(14,16)",\ # "(7,11)(12,17)", "(7,12)(11,17)", "(5,6)(11,12)", "(5,7)(6,17)",\ # "(4,13)(5,8)(6,14)(7,9)(10,12)(11,18)(16,17)", "(3,4)(13,15)",\ # "(1,2)(5,8)(6,14)(7,9)(10,12)(11,18)(16,17)", "(1,3)(2,15)",\ # "(1,5)(2,6)(3,7)(4,11)(10,18)(12,13)(15,17)" ] ) spectrum = [1, 0, 0, 0, 9, 0, 75, 0, 171, 0, 171, 0, 75, 0, 9, 0, 0, 0, 1] - self_dual_codes_18_7 = {"order autgp":82944,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_18_7 = {"order autgp":82944,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "'Exceptional' construction. Min dist 4."} # [18, 8] (equiv to I18 in [P]) - I18 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0],\ - [1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0],\ - [0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1],\ - [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]) - genmat = _MS(n)([[1,0,0,0,0,0,0,0,0, 1, 1, 1, 1, 1, 0, 0, 0, 0],\ - [0,1,0,0,0,0,0,0,0, 1, 0, 1, 1, 1, 0, 1, 1, 1],\ - [0,0,1,0,0,0,0,0,0, 0, 1, 1, 0, 0, 0, 1, 1, 1],\ - [0,0,0,1,0,0,0,0,0, 0, 1, 0, 0, 1, 0, 1, 1, 1],\ - [0,0,0,0,1,0,0,0,0, 0, 1, 0, 1, 0, 0, 1, 1, 1],\ - [0,0,0,0,0,1,0,0,0, 1, 1, 0, 0, 0, 0, 1, 1, 1],\ - [0,0,0,0,0,0,1,0,0, 0, 0, 0, 0, 0, 1, 0, 1, 1],\ - [0,0,0,0,0,0,0,1,0, 0, 0, 0, 0, 0, 1, 1, 0, 1],\ - [0,0,0,0,0,0,0,0,1, 0, 0, 0, 0, 0, 1, 1, 1, 0]]) - G = PermutationGroup( [ "(9,15)(16,17)", "(9,16)(15,17)", "(8,9)(17,18)",\ - "(7,8)(16,17)", "(5,6)(10,13)", "(5,10)(6,13)", "(4,5)(13,14)",\ + I18 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0], + [1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0], + [0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]) + genmat = _MS(n)([[1,0,0,0,0,0,0,0,0, 1, 1, 1, 1, 1, 0, 0, 0, 0], + [0,1,0,0,0,0,0,0,0, 1, 0, 1, 1, 1, 0, 1, 1, 1], + [0,0,1,0,0,0,0,0,0, 0, 1, 1, 0, 0, 0, 1, 1, 1], + [0,0,0,1,0,0,0,0,0, 0, 1, 0, 0, 1, 0, 1, 1, 1], + [0,0,0,0,1,0,0,0,0, 0, 1, 0, 1, 0, 0, 1, 1, 1], + [0,0,0,0,0,1,0,0,0, 1, 1, 0, 0, 0, 0, 1, 1, 1], + [0,0,0,0,0,0,1,0,0, 0, 0, 0, 0, 0, 1, 0, 1, 1], + [0,0,0,0,0,0,0,1,0, 0, 0, 0, 0, 0, 1, 1, 0, 1], + [0,0,0,0,0,0,0,0,1, 0, 0, 0, 0, 0, 1, 1, 1, 0]]) + G = PermutationGroup( [ "(9,15)(16,17)", "(9,16)(15,17)", "(8,9)(17,18)", + "(7,8)(16,17)", "(5,6)(10,13)", "(5,10)(6,13)", "(4,5)(13,14)", "(3,4)(12,14)", "(1,2)(6,10)", "(1,3)(2,12)" ] ) spectrum = [1, 0, 0, 0, 17, 0, 51, 0, 187, 0, 187, 0, 51, 0, 17, 0, 0, 0, 1] - self_dual_codes_18_8 = {"order autgp":322560,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_18_8 = {"order autgp":322560,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "'Exceptional' construction. Min dist 4."} - self_dual_codes["18"] = {"0":self_dual_codes_18_0,"1":self_dual_codes_18_1,"2":self_dual_codes_18_2,\ - "3":self_dual_codes_18_3,"4":self_dual_codes_18_4,"5":self_dual_codes_18_5,\ + self_dual_codes["18"] = {"0":self_dual_codes_18_0,"1":self_dual_codes_18_1,"2":self_dual_codes_18_2, + "3":self_dual_codes_18_3,"4":self_dual_codes_18_4,"5":self_dual_codes_18_5, "6":self_dual_codes_18_6,"7":self_dual_codes_18_7,"8":self_dual_codes_18_8} return self_dual_codes - if n == 20: # all of these of these are Type I; 2 of these codes # are formally equivalent but with different automorphism groups; # one of these has a unique codeword of lowest weight - A10 = MatrixSpace(_F,10,10)([[1, 1, 1, 1, 1, 1, 1, 1, 1, 0],\ - [1, 1, 1, 0, 1, 0, 1, 0, 1, 1],\ - [1, 0, 0, 1, 0, 1, 0, 1, 0, 1],\ - [0, 0, 0, 1, 1, 1, 0, 1, 0, 1],\ - [0, 0, 1, 1, 0, 1, 0, 1, 0, 1],\ - [0, 0, 0, 1, 0, 1, 1, 1, 0, 1],\ - [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],\ - [0, 0, 0, 1, 0, 0, 0, 0, 1, 1],\ - [0, 0, 0, 0, 0, 1, 0, 0, 1, 1],\ - [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]]) + A10 = MatrixSpace(_F,10,10)([[1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [1, 1, 1, 0, 1, 0, 1, 0, 1, 1], + [1, 0, 0, 1, 0, 1, 0, 1, 0, 1], + [0, 0, 0, 1, 1, 1, 0, 1, 0, 1], + [0, 0, 1, 1, 0, 1, 0, 1, 0, 1], + [0, 0, 0, 1, 0, 1, 1, 1, 0, 1], + [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], + [0, 0, 0, 1, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 0, 1, 0, 0, 1, 1], + [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]]) # [20,0]: genmat = _I2(n).augment(_I2(n)) # G = PermutationGroup( ["(10,20)", "(9,10)(19,20)", "(8,9)(18,19)", "(7,8)(17,18)", "(6,7)(16,17)",\ # "(5,6)(15,16)", "(4,5)(14,15)", "(3,4)(13,14)", "(2,3)(12,13)", "(1,2)(11,12)"] ) spectrum = [1, 0, 10, 0, 45, 0, 120, 0, 210, 0, 252, 0, 210, 0, 120, 0, 45, 0, 10, 0, 1] - self_dual_codes_20_0 = {"order autgp":3715891200,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_0 = {"order autgp":3715891200,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "Huge aut gp"} # [20,1]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) @@ -634,7 +634,7 @@ def self_dual_binary_codes(n): # "(5,6)(15,16)", "(4,11)(12,13)", "(4,12)(11,13)", "(3,4)(13,14)",\ # "(2,3)(12,13)", "(1,2)(11,12)"] ) spectrum = [1, 0, 6, 0, 29, 0, 104, 0, 226, 0, 292, 0, 226, 0, 104, 0, 29, 0, 6, 0, 1] - self_dual_codes_20_1 = {"order autgp":61931520,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_1 = {"order autgp":61931520,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":""} # [20,2]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matId(n)[6]])) @@ -642,7 +642,7 @@ def self_dual_binary_codes(n): # "(5,6)(15,16)", "(5,15)(6,16)", "(4,5)(14,15)", "(3,4)(13,14)",\ # "(2,3)(12,13)", "(1,2)(11,12)"] ) spectrum = [1, 0, 4, 0, 21, 0, 96, 0, 234, 0, 312, 0, 234, 0, 96, 0, 21, 0, 4, 0, 1] - self_dual_codes_20_2 = {"order autgp":8847360,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_2 = {"order autgp":8847360,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":""} # [20,3]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matA(n)[4]])) @@ -650,7 +650,7 @@ def self_dual_binary_codes(n): # "(2,3)(12,13)", "(1,2)(11,12)", "(8,17)(9,10)", "(8,10)(9,17)", "(8,10,20)(9,19,17)",\ # "(8,19,20,9,17,10,18)", "(7,8,19,20,9,18)(10,17)"] ) spectrum =[1, 0, 0, 0, 29, 0, 32, 0, 226, 0, 448, 0, 226, 0, 32, 0, 29, 0, 0, 0, 1] - self_dual_codes_20_3 = {"order autgp":30965760,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_3 = {"order autgp":30965760,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Min dist 4."} # [20,4]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matA(n)[4],_matId(n)[8]])) @@ -661,7 +661,7 @@ def self_dual_binary_codes(n): # "(2,3,12)(4,11,14)(5,17,18)(6,15,8)(10,20)",\ # "(2,3,12)(4,11,14)(5,17,18)(6,15,8)(9,10,19,20)"] ) spectrum =[1, 0, 2, 0, 29, 0, 56, 0, 226, 0, 396, 0, 226, 0, 56, 0, 29, 0, 2, 0, 1] - self_dual_codes_20_4 = {"order autgp":28901376,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_4 = {"order autgp":28901376,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":""} # [20,5]: genmat = _I2(n).augment(block_diagonal_matrix([_And7(),_matId(n)[7]])) @@ -670,7 +670,7 @@ def self_dual_binary_codes(n): # "(4,15)(16,17)", "(4,16)(15,17)", "(2,3)(16,17)", "(2,4)(3,15)",\ # "(1,2)(15,16)", "(1,5)(2,6)(3,13)(4,7)(11,16)(12,15)(14,17)" ] ) # order 2709504 spectrum = [1, 0, 3, 0, 17, 0, 92, 0, 238, 0, 322, 0, 238, 0, 92, 0, 17, 0, 3, 0, 1] - self_dual_codes_20_5 = {"order autgp":2709504,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_5 = {"order autgp":2709504,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "'Exceptional' construction."} # [20,6]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[8],_matId(n)[8]])) @@ -678,7 +678,7 @@ def self_dual_binary_codes(n): # "(4,5)(14,15)", "(3,4)(13,14)", "(2,3)(12,13)", "(1,2)(11,12)",\ # "(10,20)", "(9,10,19,20)"] ) spectrum = [1, 0, 2, 0, 29, 0, 56, 0, 226, 0, 396, 0, 226, 0, 56, 0, 29, 0, 2, 0, 1] - self_dual_codes_20_6 = {"order autgp":41287680,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_6 = {"order autgp":41287680,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":""} # [20,7]: A0 = self_dual_binary_codes(n-4)["16"]["6"]["code"].redundancy_matrix() @@ -688,48 +688,48 @@ def self_dual_binary_codes(n): # "(3,14)(5,16)", "(2,3)(16,17)", "(1,2)(8,17)",\ # "(1,4)(2,6)(3,7)(5,18)(8,15)(11,14)(12,16)(13,17)" ] ) spectrum = [1,0,2,0,13,0,88,0,242,0,332,0,242,0,88,0,13,0,2,0,1] - self_dual_codes_20_7 = {"order autgp":589824,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_7 = {"order autgp":589824,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"'Exceptional' construction."} # [20,8]: (genmat, J20, and genmat2 are all equiv) genmat = _I2(n).augment(_matA(n)[10]) - J20 = _MS(n)([[1,1,1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\ - [0,0,1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\ - [0,0,0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\ - [0,0,0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\ - [0,0,0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\ - [0,0,0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],\ - [0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],\ - [0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0],\ - [0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\ + J20 = _MS(n)([[1,1,1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0,0,1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0,0,0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0,0,0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0,0,0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [0,0,0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], + [0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], + [0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], + [0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [1,0,1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]]) - genmat2 = _MS(n)([[1,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1],\ - [0,1,0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1],\ - [0,0,1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],\ - [0,0,0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0],\ - [0,0,0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0],\ - [0,0,0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0],\ - [0,0,0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0],\ - [0,0,0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0],\ - [0,0,0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0],\ + genmat2 = _MS(n)([[1,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [0,1,0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1], + [0,0,1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], + [0,0,0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0], + [0,0,0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0], + [0,0,0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], + [0,0,0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0], + [0,0,0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0], + [0,0,0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0], [0,0,0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1]]) # G = PermutationGroup( [ "(9,10)(19,20)", "(9,19)(10,20)", "(8,9)(18,19)", "(7,8)(17,18)",\ # "(6,7)(16,17)", "(5,6)(15,16)", "(4,5)(14,15)", "(3,4)(13,14)",\ # "(2,3)(12,13)", "(1,2)(11,12)"] ) spectrum =[1, 0, 0, 0, 45, 0, 0, 0, 210, 0, 512, 0, 210, 0, 0, 0, 45, 0, 0, 0, 1] - self_dual_codes_20_8 = {"order autgp":1857945600,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_8 = {"order autgp":1857945600,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Huge aut gp. Min dist 4."} # [20,9]: (genmat, K20 are equiv) genmat = _I2(n).augment(A10) - K20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],\ - [1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,1,0,1,0]]) + K20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], + [1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,1,0,1,0]]) #genmat = K20 # not in standard form # G = PermutationGroup( [ "(4,13)(5,15)", "(4,15)(5,13)", "(3,4,13)(5,11,15)", # "(3,4,6,11,15,17)(5,13)", "(3,5,17,4,12)(6,15,7,11,13)", @@ -738,38 +738,38 @@ def self_dual_binary_codes(n): # "(3,5,17,4,12)(6,15,7,11,13)(9,10)(16,18)", # "(3,5,17,4,12)(6,15,7,11,13)(8,9)(14,16)" ] ) spectrum = [1, 0, 0, 0, 21, 0, 48, 0, 234, 0, 416, 0, 234, 0, 48, 0, 21, 0, 0, 0, 1] - self_dual_codes_20_9 = {"order autgp":4423680,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_9 = {"order autgp":4423680,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "Min dist 4."} # [20,10] - L20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\ - [1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],\ - [0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,1,0,0,0,0],\ - [0,1,0,1,0,1,0,0,0,0,0,0,0,0,1,0,1,0,1,0]]) + L20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], + [0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,1,0,0,0,0], + [0,1,0,1,0,1,0,0,0,0,0,0,0,0,1,0,1,0,1,0]]) genmat = L20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(15,16)(19,20)", # "(15,17)(16,18)", "(10,11)(12,13)", "(10,12)(11,13)", "(9,10)(13,14)", # "(8,9)(12,13)", "(3,4)(5,6)", "(3,5)(4,6)", "(2,3)(6,7)", "(1,2)(5,6)", # "(1,8)(2,9)(3,10)(4,11)(5,12)(6,13)(7,14)(19,20)" ] ) # order 1354752 spectrum = [1, 0, 0, 0, 17, 0, 56, 0, 238, 0, 400, 0, 238, 0, 56, 0, 17, 0, 0, 0, 1] - self_dual_codes_20_10 = {"order autgp":1354752,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_10 = {"order autgp":1354752,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "Min dist 4."} # [20,11] - S20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],\ - [1,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,1,1,0,0],\ - [1,1,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,1,0,0],\ - [1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,1,0]] ) + S20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], + [1,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,1,1,0,0], + [1,1,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,1,0,0], + [1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,1,0]] ) genmat = S20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(13,14)(15,16)", # "(13,15)(14,16)", "(11,12)(15,16)", "(11,13)(12,14)", "(9,10)(15,16)", @@ -777,19 +777,19 @@ def self_dual_binary_codes(n): # "(1,2)(7,8)", "(1,3)(2,4)", "(1,9)(2,10)(3,11)(4,12)(5,13)(6,14)(7,15)(8,16)" ] ) # G.order() = 294912 spectrum = [1, 0, 0, 0, 13, 0, 64, 0, 242, 0, 384, 0, 242, 0, 64, 0, 13, 0, 0, 0, 1] - self_dual_codes_20_11 = {"order autgp":294912,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_11 = {"order autgp":294912,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Min dist 4."} # [20,12] - R20 = _MS(n)([[0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],\ - [0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,1,1,0],\ - [1,1,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0],\ - [1,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1],\ - [1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1]]) + R20 = _MS(n)([[0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], + [0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,1,1,0], + [1,1,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0], + [1,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1], + [1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1]]) genmat = R20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(15,16)(19,20)", # "(15,17)(16,18)", "(11,12)(13,14)", "(11,13)(12,14)", "(9,10)(13,14)", @@ -797,19 +797,19 @@ def self_dual_binary_codes(n): # "(3,9,15)(4,10,16)(5,11,17)(6,12,18)(7,14,19)(8,13,20)", # "(1,2)(7,8)(9,15)(10,16)(11,17)(12,18)(13,19)(14,20)" ] ) # order 82944 spectrum = [1, 0, 0, 0, 9, 0, 72, 0, 246, 0, 368, 0, 246, 0, 72, 0, 9, 0, 0, 0, 1] - self_dual_codes_20_12 = {"order autgp":82944,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_12 = {"order autgp":82944,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Min dist 4."} # [20,13] - M20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0],\ - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],\ - [0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0],\ - [1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0],\ - [0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1],\ - [0,0,1,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0],\ - [0,0,0,0,0,0,1,1,0,1,1,0,1,0,0,1,0,0,0,0]]) + M20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], + [0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0], + [1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0], + [0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1], + [0,0,1,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,1,1,0,1,1,0,1,0,0,1,0,0,0,0]]) genmat = M20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(13,14)(15,16)", # "(13,15)(14,16)", "(9,10)(11,12)", "(9,11)(10,12)", "(5,6)(7,8)", @@ -820,7 +820,7 @@ def self_dual_binary_codes(n): # "(1,2)(6,7)(11,12)(13,17)(14,18)(15,19)(16,20)", # "(1,5)(2,6)(3,7)(4,8)(9,17)(10,18)(11,19)(12,20)" ] ) spectrum = [1, 0, 0, 0, 5, 0, 80, 0, 250, 0, 352, 0, 250, 0, 80, 0, 5, 0, 0, 0, 1] - self_dual_codes_20_13 = {"order autgp":122880,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_13 = {"order autgp":122880,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "Min dist 4."} # [20,14]: # aut gp of this computed using a program by Robert Miller A0 = self_dual_binary_codes(n-2)["18"]["8"]["code"].redundancy_matrix() @@ -839,7 +839,7 @@ def self_dual_binary_codes(n): # "(7,8)(17,18)", "(4,15)(5,14)", "(4,5)(14,15)", "(4,15)(6,11)", "(5,6)(11,14)", # "(3,13)(4,15)", "(3,15)(4,13)", "(1,2)(4,15)", "(1,4)(2,15)(3,5)(13,14)", "(10,20)" ] ) spectrum = [1, 0, 1, 0, 17, 0, 68, 0, 238, 0, 374, 0, 238, 0, 68, 0, 17, 0, 1, 0, 1] - self_dual_codes_20_14 = {"order autgp":645120,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_14 = {"order autgp":645120,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment": "'Exceptional' construction."} # [20,15]: A0 = self_dual_binary_codes(n-2)["18"]["7"]["code"].redundancy_matrix() @@ -860,12 +860,12 @@ def self_dual_binary_codes(n): # "(1,2)(5,8)(6,15)(7,9)(11,13)(12,19)(17,18)", "(1,3)(2,16)", # "(1,5)(2,6)(3,7)(4,12)(11,19)(13,14)(16,18)" ] ) # order 165888 spectrum = [1, 0, 1, 0, 9, 0, 84, 0, 246, 0, 342, 0, 246, 0, 84, 0, 9, 0, 1, 0, 1] - self_dual_codes_20_15 = {"order autgp":165888,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_20_15 = {"order autgp":165888,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"'Exceptional' construction. Unique lowest wt codeword."} - self_dual_codes["20"] = {"0":self_dual_codes_20_0,"1":self_dual_codes_20_1,"2":self_dual_codes_20_2,\ - "3":self_dual_codes_20_3,"4":self_dual_codes_20_4,"5":self_dual_codes_20_5,\ - "6":self_dual_codes_20_6,"7":self_dual_codes_20_7,"8":self_dual_codes_20_8,\ - "9":self_dual_codes_20_9,"10":self_dual_codes_20_10,"11":self_dual_codes_20_11,\ + self_dual_codes["20"] = {"0":self_dual_codes_20_0,"1":self_dual_codes_20_1,"2":self_dual_codes_20_2, + "3":self_dual_codes_20_3,"4":self_dual_codes_20_4,"5":self_dual_codes_20_5, + "6":self_dual_codes_20_6,"7":self_dual_codes_20_7,"8":self_dual_codes_20_8, + "9":self_dual_codes_20_9,"10":self_dual_codes_20_10,"11":self_dual_codes_20_11, "12":self_dual_codes_20_12,"13":self_dual_codes_20_13,"14":self_dual_codes_20_14, "15":self_dual_codes_20_15} return self_dual_codes @@ -880,7 +880,7 @@ def self_dual_binary_codes(n): # "(8,9)(19,20)", "(7,8)(18,19)", "(6,7)(17,18)", "(5,6)(16,17)",\ # "(4,5)(15,16)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) # S_11x(ZZ/2ZZ)^11?? spectrum = [1, 0, 11, 0, 55, 0, 165, 0, 330, 0, 462, 0, 462, 0, 330, 0, 165, 0, 55, 0, 11, 0, 1] - self_dual_codes_22_0 = {"order autgp":81749606400,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_22_0 = {"order autgp":81749606400,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Huge aut gp."} # [22,1]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) @@ -888,7 +888,7 @@ def self_dual_binary_codes(n): # "(8,9)(19,20)", "(7,8)(18,19)", "(6,7)(17,18)", "(5,6)(16,17)",\ # "(4,12)(13,14)", "(4,13)(12,14)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) spectrum = [1, 0, 7, 0, 35, 0, 133, 0, 330, 0, 518, 0, 518, 0, 330, 0, 133, 0, 35, 0, 7, 0, 1] - self_dual_codes_22_1 = {"order autgp":867041280,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_22_1 = {"order autgp":867041280,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":""} # [22,2]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matId(n)[6]])) @@ -896,7 +896,7 @@ def self_dual_binary_codes(n): # "(8,9)(19,20)", "(7,8)(18,19)", "(5,6)(16,17)", "(5,16)(6,17)",\ # "(4,5)(15,16)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) spectrum = [1, 0, 5, 0, 25, 0, 117, 0, 330, 0, 546, 0, 546, 0, 330, 0, 117, 0, 25, 0, 5, 0, 1] - self_dual_codes_22_2 = {"order autgp":88473600,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_22_2 = {"order autgp":88473600,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":""} # [22,3]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[8],_matId(n)[8]])) @@ -904,7 +904,7 @@ def self_dual_binary_codes(n): # "(7,8)(18,19)", "(7,18)(8,19)", "(6,7)(17,18)", "(5,6)(16,17)",\ # "(4,5)(15,16)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) spectrum = [1, 0, 3, 0, 31, 0, 85, 0, 282, 0, 622, 0, 622, 0, 282, 0, 85, 0, 31, 0, 3, 0, 1] - self_dual_codes_22_3 = {"order autgp":247726080,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_22_3 = {"order autgp":247726080,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Same spectrum as the '[20,5]' code."} # [22,4]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[10],_matId(n)[10]])) @@ -912,7 +912,7 @@ def self_dual_binary_codes(n): # "(8,9)(19,20)", "(7,8)(18,19)", "(6,7)(17,18)", "(5,6)(16,17)",\ # "(4,5)(15,16)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) spectrum = [1, 0, 1, 0, 45, 0, 45, 0, 210, 0, 722, 0, 722, 0, 210, 0, 45, 0, 45, 0, 1, 0, 1] - self_dual_codes_22_4 = {"order autgp":3715891200,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_22_4 = {"order autgp":3715891200,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Unique lowest weight codeword."} # [22,5]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matA(n)[4],_matId(n)[8]])) @@ -921,7 +921,7 @@ def self_dual_binary_codes(n): # "(5,6)(16,17)", "(4,12)(13,14)", "(4,13)(12,14)", "(3,4)(14,15)",\ # "(2,3)(13,14)", "(1,2)(12,13)", "(1,5)(2,6)(3,7)(4,8)(12,16)(13,17)(14,18)(15,19)" ] ) spectrum = [1, 0, 3, 0, 31, 0, 85, 0, 282, 0, 622, 0, 622, 0, 282, 0, 85, 0, 31, 0, 3, 0, 1] - self_dual_codes_22_5 = {"order autgp":173408256,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_22_5 = {"order autgp":173408256,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Same spectrum as the '[20,3]' code."} # [22,6]: genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matA(n)[4],_matId(n)[10]])) @@ -929,9 +929,9 @@ def self_dual_binary_codes(n): # "(9,10)(20,21)", "(8,9)(19,20)", "(7,8)(18,19)", "(5,6)(16,17)",\ # "(5,16)(6,17)", "(4,5)(15,16)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) spectrum = [1, 0, 1, 0, 29, 0, 61, 0, 258, 0, 674, 0, 674, 0, 258, 0, 61, 0, 29, 0, 1, 0, 1] - self_dual_codes_22_6 = {"order autgp":61931520,"code":LinearCode(genmat),"spectrum":spectrum,\ + self_dual_codes_22_6 = {"order autgp":61931520,"code":LinearCode(genmat),"spectrum":spectrum, "Type":"I","Comment":"Unique lowest weight codeword."} - self_dual_codes["22"] = {"0":self_dual_codes_22_0,"1":self_dual_codes_22_1,"2":self_dual_codes_22_2,\ - "3":self_dual_codes_22_3,"4":self_dual_codes_22_4,"5":self_dual_codes_22_5,\ + self_dual_codes["22"] = {"0":self_dual_codes_22_0,"1":self_dual_codes_22_1,"2":self_dual_codes_22_2, + "3":self_dual_codes_22_3,"4":self_dual_codes_22_4,"5":self_dual_codes_22_5, "6":self_dual_codes_22_6} return self_dual_codes diff --git a/src/sage/coding/source_coding/huffman.py b/src/sage/coding/source_coding/huffman.py index 59f16555e3a..6c08a4d885a 100644 --- a/src/sage/coding/source_coding/huffman.py +++ b/src/sage/coding/source_coding/huffman.py @@ -32,6 +32,7 @@ from sage.structure.sage_object import SageObject + ########################################################################### # # Helper functions @@ -102,15 +103,15 @@ class Huffman(SageObject): - ``source`` -- can be either - - A string from which the Huffman encoding should be created. + - A string from which the Huffman encoding should be created. - - A dictionary that associates to each symbol of an alphabet a numeric - value. If we consider the frequency of each alphabetic symbol, then - ``source`` is considered as the frequency table of the alphabet with - each numeric (non-negative integer) value being the number of - occurrences of a symbol. The numeric values can also represent weights - of the symbols. In that case, the numeric values are not necessarily - integers, but can be real numbers. + - A dictionary that associates to each symbol of an alphabet a numeric + value. If we consider the frequency of each alphabetic symbol, then + ``source`` is considered as the frequency table of the alphabet with + each numeric (non-negative integer) value being the number of + occurrences of a symbol. The numeric values can also represent weights + of the symbols. In that case, the numeric values are not necessarily + integers, but can be real numbers. In order to construct a Huffman code for an alphabet, we use exactly one of the following methods: @@ -235,7 +236,7 @@ def __init__(self, source): Feeding anything else than a string or a dictionary:: - sage: Huffman(Graph()) + sage: Huffman(Graph()) # optional - sage.graphs Traceback (most recent call last): ... ValueError: Input must be either a string or a dictionary. @@ -510,9 +511,9 @@ def tree(self): sage: from sage.coding.source_coding.huffman import Huffman sage: str = "Sage is my most favorite general purpose computer algebra system" sage: h = Huffman(str) - sage: T = h.tree(); T + sage: T = h.tree(); T # optional - sage.graphs Digraph on 39 vertices - sage: T.show(figsize=[20,20]) + sage: T.show(figsize=[20,20]) # optional - sage.graphs sage.plot <BLANKLINE> """ from sage.graphs.digraph import DiGraph @@ -543,8 +544,8 @@ def _generate_edges(self, tree, parent="", bit=""): sage: from sage.coding.source_coding.huffman import Huffman sage: H = Huffman("Sage") - sage: T = H.tree() - sage: T.edges(sort=True, labels=None) # indirect doctest + sage: T = H.tree() # optional - sage.graphs + sage: T.edges(sort=True, labels=None) # indirect doctest # optional - sage.graphs [('0', 'S: 00'), ('0', 'a: 01'), ('1', 'e: 10'), ('1', 'g: 11'), ('root', '0'), ('root', '1')] """ if parent == "": diff --git a/src/sage/coding/subfield_subcode.py b/src/sage/coding/subfield_subcode.py index b3861707d6b..9ec9650c43a 100644 --- a/src/sage/coding/subfield_subcode.py +++ b/src/sage/coding/subfield_subcode.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Subfield subcode @@ -113,7 +114,7 @@ def __eq__(self, other): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -127,7 +128,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -141,7 +142,7 @@ def _latex_(self): def dimension(self): r""" - Returns the dimension of ``self``. + Return the dimension of ``self``. EXAMPLES:: @@ -154,7 +155,7 @@ def dimension(self): def dimension_upper_bound(self): r""" - Returns an upper bound for the dimension of ``self``. + Return an upper bound for the dimension of ``self``. EXAMPLES:: @@ -167,7 +168,7 @@ def dimension_upper_bound(self): def dimension_lower_bound(self): r""" - Returns a lower bound for the dimension of ``self``. + Return a lower bound for the dimension of ``self``. EXAMPLES:: @@ -184,7 +185,7 @@ def dimension_lower_bound(self): def original_code(self): r""" - Returns the original code of ``self``. + Return the original code of ``self``. EXAMPLES:: @@ -197,7 +198,7 @@ def original_code(self): def embedding(self): r""" - Returns the field embedding between the base field of ``self`` and + Return the field embedding between the base field of ``self`` and the base field of its original code. EXAMPLES:: @@ -215,7 +216,7 @@ def embedding(self): @cached_method def parity_check_matrix(self): r""" - Returns a parity check matrix of ``self``. + Return a parity check matrix of ``self``. EXAMPLES:: @@ -282,10 +283,11 @@ class SubfieldSubcodeOriginalCodeDecoder(Decoder): sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'aa').list()[:13], 5) sage: Cs = codes.SubfieldSubcode(C, GF(4, 'a')) sage: codes.decoders.SubfieldSubcodeOriginalCodeDecoder(Cs) - Decoder of Subfield subcode of [13, 5, 9] Reed-Solomon Code over GF(16) down to GF(4) through Gao decoder for [13, 5, 9] Reed-Solomon Code over GF(16) + Decoder of Subfield subcode of [13, 5, 9] Reed-Solomon Code over GF(16) down to GF(4) + through Gao decoder for [13, 5, 9] Reed-Solomon Code over GF(16) """ - def __init__(self, code, original_decoder = None, **kwargs): + def __init__(self, code, original_decoder=None, **kwargs): r""" TESTS: @@ -296,7 +298,7 @@ def __init__(self, code, original_decoder = None, **kwargs): sage: Cs = codes.SubfieldSubcode(C, GF(4, 'a')) sage: Cbis = codes.GeneralizedReedSolomonCode(GF(16, 'aa').list()[:9], 5) sage: D = Cbis.decoder() - sage: codes.decoders.SubfieldSubcodeOriginalCodeDecoder(Cs, original_decoder = D) + sage: codes.decoders.SubfieldSubcodeOriginalCodeDecoder(Cs, original_decoder=D) Traceback (most recent call last): ... ValueError: original_decoder must have the original code as associated code @@ -318,7 +320,7 @@ def __init__(self, code, original_decoder = None, **kwargs): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: @@ -332,7 +334,7 @@ def _repr_(self): def _latex_(self): r""" - Returns a latex representation of ``self``. + Return a latex representation of ``self``. EXAMPLES:: @@ -346,7 +348,7 @@ def _latex_(self): def original_decoder(self): r""" - Returns the decoder over the original code that will be used to decode words of + Return the decoder over the original code that will be used to decode words of :meth:`sage.coding.decoder.Decoder.code`. EXAMPLES:: @@ -368,7 +370,8 @@ def decode_to_code(self, y): sage: C = codes.GeneralizedReedSolomonCode(GF(16, 'aa').list()[:13], 5) sage: Cs = codes.SubfieldSubcode(C, GF(4, 'a')) sage: D = codes.decoders.SubfieldSubcodeOriginalCodeDecoder(Cs) - sage: Chan = channels.StaticErrorRateChannel(Cs.ambient_space(), D.decoding_radius()) + sage: Chan = channels.StaticErrorRateChannel(Cs.ambient_space(), + ....: D.decoding_radius()) sage: c = Cs.random_element() sage: y = Chan(c) sage: c == D.decode_to_code(y) @@ -399,7 +402,7 @@ def decode_to_code(self, y): def decoding_radius(self, **kwargs): r""" - Returns maximal number of errors ``self`` can decode. + Return the maximal number of errors ``self`` can decode. INPUT: @@ -416,6 +419,7 @@ def decoding_radius(self, **kwargs): """ return self.original_decoder().decoding_radius(**kwargs) + ####################### registration ############################### SubfieldSubcode._registered_decoders["OriginalCode"] = SubfieldSubcodeOriginalCodeDecoder diff --git a/src/sage/coding/two_weight_db.py b/src/sage/coding/two_weight_db.py index 1fb1f90ad84..44695300f33 100644 --- a/src/sage/coding/two_weight_db.py +++ b/src/sage/coding/two_weight_db.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Database of two-weight codes diff --git a/src/sage/combinat/abstract_tree.py b/src/sage/combinat/abstract_tree.py index f5008f1a826..1dd26c41222 100644 --- a/src/sage/combinat/abstract_tree.py +++ b/src/sage/combinat/abstract_tree.py @@ -1555,7 +1555,7 @@ def concat_matrix(mat, mat2): # ==> n & n & ... & n' & n' & ... try: mat[i] += sep + mat2[i] - except Exception: + except IndexError: if i >= lmat: if i != 0: # mat[i] does not exist but @@ -1937,8 +1937,8 @@ def __setitem_rec__(self, idx, i, value): TESTS:: sage: x = OrderedTree([[[], []],[[]]]) - sage: with x.clone() as x: - ....: x[0,1] = OrderedTree([[[]]]) # indirect doctest + sage: with x.clone() as x: # indirect doctest + ....: x[0,1] = OrderedTree([[[]]]) sage: x [[[], [[[]]]], [[]]] """ diff --git a/src/sage/combinat/affine_permutation.py b/src/sage/combinat/affine_permutation.py index 9ae5c240be1..17279fee0e8 100644 --- a/src/sage/combinat/affine_permutation.py +++ b/src/sage/combinat/affine_permutation.py @@ -23,7 +23,7 @@ from sage.rings.integer_ring import ZZ from sage.groups.perm_gps.permgroup_named import SymmetricGroup -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.weyl_group import WeylGroup from sage.combinat.composition import Composition @@ -217,7 +217,7 @@ def __call__(self, i): """ return self.value(i) - def is_i_grassmannian(self, i=0, side="right"): + def is_i_grassmannian(self, i=0, side="right") -> bool: r""" Test whether ``self`` is `i`-grassmannian, i.e., either is the identity or has ``i`` as the sole descent. @@ -277,7 +277,7 @@ def lower_covers(self,side="right"): S = self.descents(side) return [self.apply_simple_reflection(i, side) for i in S] - def is_one(self): + def is_one(self) -> bool: r""" Tests whether the affine permutation is the identity. @@ -394,7 +394,7 @@ def grassmannian_quotient(self, i=0, side='right'): while not (D == [i] or D == []): m = D[0] if m == i: - m=D[1] + m = D[1] if side == 'right': fin = fin.apply_simple_reflection(m, side='left') gr = gr.apply_simple_reflection(m, side='right') @@ -470,7 +470,7 @@ def value(self, i, base_window=False): if base_window: self[i-1] window = (i-1) // (self.k+1) - return self[(i-1)%(self.k+1)] + window*(self.k+1) + return self[(i-1) % (self.k+1)] + window*(self.k+1) def position(self, i): r""" @@ -518,7 +518,7 @@ def apply_simple_reflection_right(self, i): if j == 0: a = l[0] l[0] = l[-1] - (self.k+1) - l[-1] = a +(self.k+1) + l[-1] = a + (self.k+1) else: a = l[j-1] l[j-1] = l[j] @@ -589,7 +589,7 @@ def has_right_descent(self, i) -> bool: sage: p.has_right_descent(0) False """ - return self.value(i)>self.value(i+1) + return self.value(i) > self.value(i+1) def has_left_descent(self, i) -> bool: r""" @@ -706,22 +706,22 @@ def maximal_cyclic_factor(self, typ='decreasing', side='right', verbose=False): y = self.clone().apply_simple_reflection(i,side) T = [i] j = i - for count in range(1, self.k): + for _ in range(1, self.k): if (typ[0],side[0]) == ('d', 'r'): - j=(j+1)%(k+1) + j = (j+1) % (k+1) if (typ[0],side[0]) == ('i', 'r'): - j=(j-1)%(k+1) + j = (j-1) % (k+1) if (typ[0],side[0]) == ('d', 'l'): - j=(j-1)%(k+1) + j = (j-1) % (k+1) if (typ[0],side[0]) == ('i', 'l'): - j=(j+1)%(k+1) + j = (j+1) % (k+1) if y.has_descent(j, side): - y=y.apply_simple_reflection(j,side) - T.append(j%(k+1)) + y = y.apply_simple_reflection(j,side) + T.append(j % (k+1)) if verbose: print(i, T) if len(T) > len(best_T): - best_T=T + best_T = T #if (typ[0],side[0])==('i','r'): best_T.reverse() #if (typ[0],side[0])==('d','l'): best_T.reverse() #if typ[0]=='d': best_T.reverse() @@ -791,7 +791,7 @@ def maximal_cyclic_decomposition(self, typ='decreasing', side='right', verbose=F y = y.apply_simple_reflection_left(i) if verbose: print(S, y.length()) - if side[0]=='r': + if side[0] == 'r': listy.reverse() return listy @@ -848,13 +848,13 @@ def to_lehmer_code(self, typ='decreasing', side='right'): #value than the number in position i. Then cyclically shift #the resulting vector. for i in range(self.k+1): - a=self(i) + a = self(i) for j in range(i-self.k, i): - b=self(j) + b = self(j) # A small rotation is necessary for the reduced word from # the Lehmer code to match the element. if a < b: - code[i-1]+=((b-a)//(self.k+1)+1) + code[i-1] += ((b-a)//(self.k+1)+1) elif typ[0] == 'i' and side[0] == 'l': #Find number of positions to the right of i smaller than i, then #cyclically shift the resulting vector. @@ -866,7 +866,7 @@ def to_lehmer_code(self, typ='decreasing', side='right'): #the lehmer code to match the element. if b < i: code[i-1] += (i-b) // (self.k+1) + 1 - elif typ[0] == 'd' and side[0]=='l': + elif typ[0] == 'd' and side[0] == 'l': #Find number of positions to the left of i larger than i. for i in range(self.k+1): pos = self.position(i) @@ -876,18 +876,21 @@ def to_lehmer_code(self, typ='decreasing', side='right'): code[i] += (b-i) // (self.k+1) + 1 return Composition(code) - def is_fully_commutative(self): + def is_fully_commutative(self) -> bool: r""" - Determine whether ``self`` is fully commutative, i.e., has no - reduced words with a braid. + Determine whether ``self`` is fully commutative. + + This means that it has no reduced word with a braid. + + This uses a specific algorithm. EXAMPLES:: sage: A = AffinePermutationGroup(['A',7,1]) - sage: p=A([3, -1, 0, 6, 5, 4, 10, 9]) + sage: p = A([3, -1, 0, 6, 5, 4, 10, 9]) sage: p.is_fully_commutative() False - sage: q=A([-3, -2, 0, 7, 9, 2, 11, 12]) + sage: q = A([-3, -2, 0, 7, 9, 2, 11, 12]) sage: q.is_fully_commutative() True """ @@ -900,14 +903,12 @@ def is_fully_commutative(self): if c[i] > 0: if firstnonzero is None: firstnonzero = i - if m != -1 and c[i] - (i-m) >= c[m]: + if m != -1 and c[i] - (i - m) >= c[m]: return False m = i - #now check m (the last non-zero) against firstnonzero. - d = self.n-(m-firstnonzero) - if c[firstnonzero]-d >= c[m]: - return False - return True + # now check m (the last non-zero) against first non-zero. + d = self.n - (m - firstnonzero) + return not c[firstnonzero] - d >= c[m] def to_bounded_partition(self, typ='decreasing', side='right'): r""" @@ -916,10 +917,10 @@ def to_bounded_partition(self, typ='decreasing', side='right'): INPUT: - - ``typ`` -- 'increasing' or 'decreasing' (default: 'decreasing'.) + - ``typ`` -- ``'increasing'`` or ``'decreasing'`` (default: ``'decreasing'``.) Chooses whether to find increasing or decreasing sets. - - ``side`` -- 'right' or 'left' (default: 'right'.) Chooses whether to + - ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``.) Chooses whether to find maximal sets starting from the left or the right. EXAMPLES:: @@ -940,9 +941,9 @@ def to_core(self, typ='decreasing', side='right'): INPUT: - - ``typ`` -- 'increasing' or 'decreasing' (default: 'decreasing'.) + - ``typ`` -- ``'increasing'`` or ``'decreasing'`` (default: ``'decreasing'``.) - - ``side`` -- 'right' or 'left' (default: 'right'.) Chooses whether to + - ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``.) Chooses whether to find maximal sets starting from the left or the right. EXAMPLES:: @@ -1028,7 +1029,7 @@ def tableau_of_word(self, w, typ='decreasing', side='right', alpha=None): if x0.length() != len(w): raise ValueError("word was not reduced") if alpha is None: - alpha=Composition([1 for i in w]) + alpha = Composition([1 for i in w]) else: if sum(alpha) != len(w): raise ValueError("size of alpha must match length of w") @@ -1646,7 +1647,7 @@ def check(self): if not len(self) == 6: raise ValueError("length of list must be 6") #Check that we have an even number of 'big' elements left of the 7th entry. - s = sum(i//6 - (i%6 == 0) for i in self if i > 6) + s = sum(i//6 - (i % 6 == 0) for i in self if i > 6) if s % 2: raise ValueError("type G affine permutations have an even number of" " entries greater than 6 to the left of the 7th position") @@ -1677,7 +1678,7 @@ def value(self, i, base_window=False): if base_window: self[i-1] window = (i-1) // N - return self[(i-1)%N] + window*(N) + return self[(i-1) % N] + window*(N) def position(self, i): r""" @@ -1757,28 +1758,28 @@ def apply_simple_reflection_left(self, i): l = [] if i == 1: for m in range(6): - res=self[m]%6 - if res==1 or res==3 or res==5: + res = self[m] % 6 + if res == 1 or res == 3 or res == 5: l.append(self[m]+1) - elif res==2 or res==4 or res==0: + elif res == 2 or res == 4 or res == 0: l.append(self[m]-1) else: l.append(self[m]) elif i == 2: for m in range(6): - res=self[m]%6 - if res==2 or res==4: + res = self[m] % 6 + if res == 2 or res == 4: l.append(self[m]+1) - elif res==3 or res==5: + elif res == 3 or res == 5: l.append(self[m]-1) else: l.append(self[m]) elif i == 0: for m in range(6): - res=self[m]%6 - if res==1 or res==2: + res = self[m] % 6 + if res == 1 or res == 2: l.append(self[m]-2) - elif res==5 or res==0: + elif res == 5 or res == 0: l.append(self[m]+2) else: l.append(self[m]) @@ -1982,9 +1983,9 @@ def AffinePermutationGroup(cartan_type): Type G affine permutation with window [0, 4, -1, 8, 3, 7] """ ct = CartanType(cartan_type) - if ct.letter=='A': + if ct.letter == 'A': return AffinePermutationGroupTypeA(ct) - if ct.letter=='B': + if ct.letter == 'B': return AffinePermutationGroupTypeB(ct) if ct.letter == 'C': return AffinePermutationGroupTypeC(ct) @@ -2139,7 +2140,7 @@ def index_set(self): """ return self.cartan_type().index_set() - _index_set=index_set + _index_set = index_set def reflection_index_set(self): r""" diff --git a/src/sage/combinat/algebraic_combinatorics.py b/src/sage/combinat/algebraic_combinatorics.py index 6a6a25b0907..a024d2fa67d 100644 --- a/src/sage/combinat/algebraic_combinatorics.py +++ b/src/sage/combinat/algebraic_combinatorics.py @@ -39,6 +39,7 @@ - :ref:`sage.combinat.cluster_algebra_quiver.all` - :class:`~sage.combinat.kazhdan_lusztig.KazhdanLusztigPolynomial` - :class:`~sage.combinat.symmetric_group_representations.SymmetricGroupRepresentation` +- :class:`~sage.combinat.specht_module.SpechtModule` - :ref:`sage.combinat.yang_baxter_graph` - :ref:`sage.combinat.hall_polynomial` - :ref:`sage.combinat.key_polynomial` diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 47cd721e0a5..79690ff7305 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -26,7 +26,8 @@ - :ref:`sage.combinat.species.all` - :ref:`sage.combinat.designs.all` - :ref:`sage.combinat.posets.all` -- :ref:`sage.combinat.words` +- :ref:`sage.combinat.words.all` +- :ref:`sage.combinat.bijectionist` Utilities --------- @@ -217,7 +218,7 @@ lazy_import('sage.combinat.multiset_partition_into_sets_ordered', ['OrderedMultisetPartitionIntoSets', 'OrderedMultisetPartitionsIntoSets']) -from .subset import Subsets +from .subset import Subsets, subsets, powerset, uniq from .necklace import Necklaces lazy_import('sage.combinat.dyck_word', ('DyckWords', 'DyckWord')) lazy_import('sage.combinat.nu_dyck_word', ('NuDyckWords', 'NuDyckWord')) @@ -276,7 +277,7 @@ lazy_import('sage.combinat.binary_recurrence_sequences', 'BinaryRecurrenceSequence') lazy_import('sage.combinat.recognizable_series', 'RecognizableSeriesSpace') -lazy_import('sage.combinat.k_regular_sequence', 'kRegularSequenceSpace') +lazy_import('sage.combinat.regular_sequence', 'RegularSequenceRing') # Six Vertex Model lazy_import('sage.combinat.six_vertex_model', 'SixVertexModel') @@ -299,3 +300,6 @@ # Path Tableaux lazy_import('sage.combinat.path_tableaux', 'catalog', as_='path_tableaux') + +# Bijectionist +lazy_import('sage.combinat.bijectionist', 'Bijectionist') diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index fba8f842fc8..80d4ab301b7 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -46,7 +46,7 @@ from sage.modules.free_module_element import zero_vector from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ -from sage.arith.all import factorial +from sage.arith.misc import factorial from sage.rings.integer import Integer from sage.combinat.posets.lattices import LatticePoset from sage.combinat.gelfand_tsetlin_patterns import GelfandTsetlinPatternsTopRow @@ -123,7 +123,7 @@ def __classcall_private__(cls, asm, check=True): """ asm = matrix(ZZ, asm) if not asm.is_square(): - raise ValueError("The alternating sign matrices must be square") + raise ValueError("the alternating sign matrices must be square") return AlternatingSignMatrices(asm.nrows())(asm, check=check) def __init__(self, parent, asm): @@ -922,10 +922,10 @@ def to_permutation(self): sage: asm.to_permutation() Traceback (most recent call last): ... - ValueError: Not a permutation matrix + ValueError: not a permutation matrix """ if not self.is_permutation(): - raise ValueError('Not a permutation matrix') + raise ValueError('not a permutation matrix') asm_matrix = self.to_matrix() return Permutation([j + 1 for (i, j) in asm_matrix.nonzero_positions()]) @@ -1197,7 +1197,7 @@ def _element_constructor_(self, asm, check=True): if isinstance(asm, AlternatingSignMatrix): if asm.parent() is self: return asm - raise ValueError("Cannot convert between alternating sign matrices of different sizes") + raise ValueError("cannot convert between alternating sign matrices of different sizes") try: m = self._matrix_space(asm) except (TypeError, ValueError): @@ -1282,7 +1282,7 @@ def from_monotone_triangle(self, triangle, check=True): """ n = len(triangle) if n != self._n: - raise ValueError("Incorrect size") + raise ValueError("incorrect size") asm = self._matrix_space() for i in range(n - 1): diff --git a/src/sage/combinat/backtrack.py b/src/sage/combinat/backtrack.py index 565b3efa973..777e511531f 100644 --- a/src/sage/combinat/backtrack.py +++ b/src/sage/combinat/backtrack.py @@ -63,7 +63,7 @@ def __iter__(self): sage: from sage.combinat.permutation import PatternAvoider sage: p = PatternAvoider(Permutations(4), [[1,3,2]]) - sage: len(list(p)) + sage: len(list(p)) # optional - sage.combinat 14 """ # Initialize the stack of generators with the initial data. diff --git a/src/sage/combinat/baxter_permutations.py b/src/sage/combinat/baxter_permutations.py index 3fe87a12842..c4f34c073f5 100644 --- a/src/sage/combinat/baxter_permutations.py +++ b/src/sage/combinat/baxter_permutations.py @@ -232,7 +232,7 @@ def cardinality(self): """ if self._n == 0: return 1 - from sage.arith.all import binomial + from sage.arith.misc import binomial return sum((binomial(self._n + 1, k) * binomial(self._n + 1, k + 1) * binomial(self._n + 1, k + 2)) // diff --git a/src/sage/combinat/bijectionist.py b/src/sage/combinat/bijectionist.py new file mode 100644 index 00000000000..68d1f322e9f --- /dev/null +++ b/src/sage/combinat/bijectionist.py @@ -0,0 +1,3229 @@ +r""" +A bijectionist's toolkit + +AUTHORS: + +- Alexander Grosz, Tobias Kietreiber, Stephan Pfannerer and Martin + Rubey (2020-2022): Initial version + +Quick reference +=============== + +.. csv-table:: + :class: contentstable + :widths: 30, 70 + :delim: | + + :meth:`~Bijectionist.set_statistics` | Declare statistics that are preserved by the bijection. + :meth:`~Bijectionist.set_value_restrictions` | Restrict the values of the statistic on an element. + :meth:`~Bijectionist.set_constant_blocks` | Declare that the statistic is constant on some sets. + :meth:`~Bijectionist.set_distributions` | Restrict the distribution of values of the statistic on some elements. + :meth:`~Bijectionist.set_intertwining_relations` | Declare that the statistic intertwines with other maps. + :meth:`~Bijectionist.set_quadratic_relation` | Declare that the statistic satisfies a certain relation. + :meth:`~Bijectionist.set_homomesic` | Declare that the statistic is homomesic with respect to a given set partition. + + + :meth:`~Bijectionist.statistics_table` | Print a table collecting information on the given statistics. + :meth:`~Bijectionist.statistics_fibers` | Collect elements with the same statistics. + + :meth:`~Bijectionist.constant_blocks` | Return the blocks on which the statistic is constant. + :meth:`~Bijectionist.solutions_iterator` | Iterate over all possible solutions. + :meth:`~Bijectionist.possible_values` | Return all possible values for a given element. + :meth:`~Bijectionist.minimal_subdistributions_iterator` | Iterate over the minimal subdistributions. + :meth:`~Bijectionist.minimal_subdistributions_blocks_iterator` | Iterate over the minimal subdistributions. + +A guided tour +============= + +Consider the following combinatorial statistics on a permutation: + + * `wex`, the number of weak excedences, + * `fix`, the number of fixed points, + * `des`, the number of descents (after appending `0`), + * `adj`, the number of adjacencies (after appending `0`), and + * `llis`, the length of a longest increasing subsequence. + +Moreover, let `rot` be action of rotation on a permutation, i.e., the +conjugation with the long cycle. + +It is known that there must exist a statistic `s` on permutations, +which is equidistributed with `llis` but additionally invariant under +`rot`. However, at least very small cases do not contradict the +possibility that one can even find a statistic `s`, invariant under +`rot` and such that `(s, wex, fix) \sim (llis, des, adj)`. Let us +check this for permutations of size at most `3`:: + + sage: N = 3 + sage: A = B = [pi for n in range(N+1) for pi in Permutations(n)] + sage: def alpha1(p): return len(p.weak_excedences()) + sage: def alpha2(p): return len(p.fixed_points()) + sage: def beta1(p): return len(p.descents(final_descent=True)) if p else 0 + sage: def beta2(p): return len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1]) + sage: tau = Permutation.longest_increasing_subsequence_length + sage: def rotate_permutation(p): + ....: cycle = Permutation(tuple(range(1, len(p)+1))) + ....: return Permutation([cycle.inverse()(p(cycle(i))) for i in range(1, len(p)+1)]) + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((len, len), (alpha1, beta1), (alpha2, beta2)) + sage: a, b = bij.statistics_table() + sage: table(a, header_row=True, frame=True) + +-----------+--------+--------+--------+ + | a | ฮฑ_1(a) | ฮฑ_2(a) | ฮฑ_3(a) | + +===========+========+========+========+ + | [] | 0 | 0 | 0 | + +-----------+--------+--------+--------+ + | [1] | 1 | 1 | 1 | + +-----------+--------+--------+--------+ + | [1, 2] | 2 | 2 | 2 | + +-----------+--------+--------+--------+ + | [2, 1] | 2 | 1 | 0 | + +-----------+--------+--------+--------+ + | [1, 2, 3] | 3 | 3 | 3 | + +-----------+--------+--------+--------+ + | [1, 3, 2] | 3 | 2 | 1 | + +-----------+--------+--------+--------+ + | [2, 1, 3] | 3 | 2 | 1 | + +-----------+--------+--------+--------+ + | [2, 3, 1] | 3 | 2 | 0 | + +-----------+--------+--------+--------+ + | [3, 1, 2] | 3 | 1 | 0 | + +-----------+--------+--------+--------+ + | [3, 2, 1] | 3 | 2 | 1 | + +-----------+--------+--------+--------+ + + sage: table(b, header_row=True, frame=True) + +-----------+---+--------+--------+--------+ + | b | ฯ„ | ฮฒ_1(b) | ฮฒ_2(b) | ฮฒ_3(b) | + +===========+===+========+========+========+ + | [] | 0 | 0 | 0 | 0 | + +-----------+---+--------+--------+--------+ + | [1] | 1 | 1 | 1 | 1 | + +-----------+---+--------+--------+--------+ + | [1, 2] | 2 | 2 | 1 | 0 | + +-----------+---+--------+--------+--------+ + | [2, 1] | 1 | 2 | 2 | 2 | + +-----------+---+--------+--------+--------+ + | [1, 2, 3] | 3 | 3 | 1 | 0 | + +-----------+---+--------+--------+--------+ + | [1, 3, 2] | 2 | 3 | 2 | 1 | + +-----------+---+--------+--------+--------+ + | [2, 1, 3] | 2 | 3 | 2 | 1 | + +-----------+---+--------+--------+--------+ + | [2, 3, 1] | 2 | 3 | 2 | 1 | + +-----------+---+--------+--------+--------+ + | [3, 1, 2] | 2 | 3 | 2 | 0 | + +-----------+---+--------+--------+--------+ + | [3, 2, 1] | 1 | 3 | 3 | 3 | + +-----------+---+--------+--------+--------+ + + sage: from sage.combinat.cyclic_sieving_phenomenon import orbit_decomposition + sage: bij.set_constant_blocks(orbit_decomposition(A, rotate_permutation)) + sage: bij.constant_blocks() + {{[1, 3, 2], [2, 1, 3], [3, 2, 1]}} + sage: next(bij.solutions_iterator()) + {[]: 0, + [1]: 1, + [1, 2]: 1, + [1, 2, 3]: 1, + [1, 3, 2]: 2, + [2, 1]: 2, + [2, 1, 3]: 2, + [2, 3, 1]: 2, + [3, 1, 2]: 3, + [3, 2, 1]: 2} + +On the other hand, we can check that there is no rotation invariant +statistic on non-crossing set partitions which is equidistributed +with the Strahler number on ordered trees:: + + sage: N = 8 + sage: A = [SetPartition(d.to_noncrossing_partition()) for n in range(N) for d in DyckWords(n)] + sage: B = [t for n in range(1, N+1) for t in OrderedTrees(n)] + sage: def theta(m): return SetPartition([[i % m.size() + 1 for i in b] for b in m]) + +Code for the Strahler number can be obtained from FindStat. The +following code is equivalent to ``tau = findstat(397)``:: + + sage: def tau(T): + ....: if len(T) == 0: + ....: return 1 + ....: else: + ....: l = [tau(S) for S in T] + ....: m = max(l) + ....: if l.count(m) == 1: + ....: return m + ....: else: + ....: return m+1 + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((lambda a: a.size(), lambda b: b.node_number()-1)) + sage: from sage.combinat.cyclic_sieving_phenomenon import orbit_decomposition + sage: bij.set_constant_blocks(orbit_decomposition(A, theta)) + sage: list(bij.solutions_iterator()) + [] + +Next we demonstrate how to search for a bijection, instead An example +identifying `s` and `S`:: + + sage: N = 4 + sage: A = [dyck_word for n in range(1, N) for dyck_word in DyckWords(n)] + sage: B = [binary_tree for n in range(1, N) for binary_tree in BinaryTrees(n)] + sage: concat_path = lambda D1, D2: DyckWord(list(D1) + list(D2)) + sage: concat_tree = lambda B1, B2: concat_path(B1.to_dyck_word(), + ....: B2.to_dyck_word()).to_binary_tree() + sage: bij = Bijectionist(A, B) + sage: bij.set_intertwining_relations((2, concat_path, concat_tree)) + sage: bij.set_statistics((lambda d: d.semilength(), lambda t: t.node_number())) + sage: for D in sorted(bij.minimal_subdistributions_iterator(), key=lambda x: (len(x[0][0]), x)): + ....: ascii_art(D) + ( [ /\ ], [ o ] ) + ( [ o ] ) + ( [ \ ] ) + ( [ /\/\ ], [ o ] ) + ( [ o ] ) + ( [ /\ ] [ / ] ) + ( [ / \ ], [ o ] ) + ( [ o ] ) + ( [ \ ] ) + ( [ o ] ) + ( [ \ ] ) + ( [ /\/\/\ ], [ o ] ) + ( [ o ] ) + ( [ \ ] ) + ( [ o ] ) + ( [ /\ ] [ / ] ) + ( [ /\/ \ ], [ o ] ) + ( [ o ] ) + ( [ /\ ] [ / \ ] ) + ( [ / \/\ ], [ o o ] ) + ( [ o, o ] ) + ( [ / / ] ) + ( [ /\ ] [ o o ] ) + ( [ /\/\ / \ ] [ \ / ] ) + ( [ / \, / \ ], [ o o ] ) + +The output is in a form suitable for FindStat:: + + sage: findmap(list(bij.minimal_subdistributions_iterator())) # optional -- internet + 0: Mp00034 (quality [100]) + 1: Mp00061oMp00023 (quality [100]) + 2: Mp00018oMp00140 (quality [100]) + +TESTS:: + + sage: N = 4; A = B = [permutation for n in range(N) for permutation in Permutations(n)] + sage: def theta(pi): return Permutation([x+1 if x != len(pi) else 1 for x in pi[-1:]+pi[:-1]]) + sage: def tau(pi): + ....: n = len(pi) + ....: return sum([1 for i in range(1, n+1) for j in range(1, n+1) + ....: if i<j <= pi(i)<pi(j) or pi(i)<pi(j)<i<j]) + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((len, len)) + sage: from sage.combinat.cyclic_sieving_phenomenon import orbit_decomposition + sage: bij.set_constant_blocks(orbit_decomposition(A, theta)) + sage: for solution in sorted(bij.solutions_iterator(), key=lambda d: sorted(d.items())): + ....: print(solution) + {[]: 0, [1]: 0, [1, 2]: 0, [2, 1]: 0, [1, 2, 3]: 0, [1, 3, 2]: 0, [2, 1, 3]: 0, [3, 2, 1]: 0, [2, 3, 1]: 0, [3, 1, 2]: 1} + {[]: 0, [1]: 0, [1, 2]: 0, [2, 1]: 0, [1, 2, 3]: 0, [1, 3, 2]: 0, [2, 1, 3]: 0, [3, 2, 1]: 0, [2, 3, 1]: 1, [3, 1, 2]: 0} + {[]: 0, [1]: 0, [1, 2]: 0, [2, 1]: 0, [1, 2, 3]: 1, [1, 3, 2]: 0, [2, 1, 3]: 0, [3, 2, 1]: 0, [2, 3, 1]: 0, [3, 1, 2]: 0} + +A test including intertwining relations:: + + sage: N = 2; A = B = [dyck_word for n in range(N+1) for dyck_word in DyckWords(n)] + sage: def alpha(D): return (D.area(), D.bounce()) + sage: def beta(D): return (D.bounce(), D.area()) + sage: def tau(D): return D.number_of_touch_points() + +The following looks correct:: + + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((lambda d: d.semilength(), lambda d: d.semilength())) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1, 0]: 1, [1, 0, 1, 0]: 1, [1, 1, 0, 0]: 2} + {[]: 0, [1, 0]: 1, [1, 0, 1, 0]: 2, [1, 1, 0, 0]: 1} + +The following looks correct, because `alpha = beta \circ S` forces +`S([1,0,1,0]) = [1,1,0,0]` and `s = tau \circ S` forces therefore `s([1,0,1,0]) += \tau(S([1,0,1,0])) = \tau([1,1,0,0]) = 1`:: + + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((alpha, beta), (lambda d: d.semilength(), lambda d: d.semilength())) + sage: for solution in bij.solutions_iterator(): + ....: print(solution) + {[]: 0, [1, 0]: 1, [1, 0, 1, 0]: 1, [1, 1, 0, 0]: 2} + +Now we introduce a intertwining relation:: + + sage: concat_path = lambda D1, D2: DyckWord(list(D1) + list(D2)) + sage: pi_rho = (2, concat_path, lambda x, y: x+y) + +Without `\alpha` and `\beta` but with `\pi` and `\rho` the other values are +forced because `s([1,0,1,0]) = s(\pi([1,0], [1,0])) = \rho(s([1,0]), s([1,0])) += 2`:: + + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_intertwining_relations(pi_rho) + sage: bij.set_statistics((lambda d: d.semilength(), lambda d: d.semilength())) + sage: for solution in bij.solutions_iterator(): + ....: print(solution) + {[]: 0, [1, 0]: 1, [1, 0, 1, 0]: 2, [1, 1, 0, 0]: 1} + +Thus the combination of both constraints should be infeasible:: + + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((alpha, beta), (lambda d: d.semilength(), lambda d: d.semilength())) + sage: bij.set_intertwining_relations(pi_rho) + sage: list(bij.solutions_iterator()) + [] + +Repeating some tests, but using the constructor instead of set_XXX() methods: + + sage: N = 2; A = B = [dyck_word for n in range(N+1) for dyck_word in DyckWords(n)] + sage: def alpha(D): return (D.area(), D.bounce()) + sage: def beta(D): return (D.bounce(), D.area()) + sage: def tau(D): return D.number_of_touch_points() + + sage: bij = Bijectionist(A, B, tau, alpha_beta=((lambda d: d.semilength(), lambda d: d.semilength()),)) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1, 0]: 1, [1, 0, 1, 0]: 1, [1, 1, 0, 0]: 2} + {[]: 0, [1, 0]: 1, [1, 0, 1, 0]: 2, [1, 1, 0, 0]: 1} + +Constant blocks:: + + sage: A = B = 'abcd' + sage: def pi(p1, p2): return 'abcdefgh'[A.index(p1) + A.index(p2)] + sage: def rho(s1, s2): return (s1 + s2) % 2 + sage: bij = Bijectionist(A, B, lambda x: B.index(x) % 2, P=[['a', 'c']], pi_rho=((2, pi, rho),)) + sage: list(bij.solutions_iterator()) + [{'a': 0, 'b': 1, 'c': 0, 'd': 1}] + sage: bij.constant_blocks() + {{'a', 'c'}, {'b', 'd'}} + +Distributions:: + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: bij = Bijectionist(A, B, tau, alpha_beta=((len, len),), elements_distributions=(([Permutation([1, 2, 3]), Permutation([1, 3, 2])], [1, 3]),)) + sage: for sol in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(sol) + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 1, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + +Intertwining relations:: + + sage: def concat(p1, p2): return Permutation(p1 + [i + len(p1) for i in p2]) + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: bij = Bijectionist(A, B, Permutation.number_of_fixed_points, alpha_beta=((len, len),), pi_rho=((2, concat, lambda x, y: x + y),)) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 0, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 1, [3, 2, 1]: 0} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 1, [3, 1, 2]: 0, [3, 2, 1]: 0} + +Statistics:: + + sage: N = 4; A = B = [permutation for n in range(N) for permutation in Permutations(n)] + sage: def wex(p): return len(p.weak_excedences()) + sage: def fix(p): return len(p.fixed_points()) + sage: def des(p): return len(p.descents(final_descent=True)) if p else 0 + sage: bij = Bijectionist(A, B, fix, alpha_beta=((wex, des), (len, len))) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 0, [2, 1, 3]: 0, [2, 3, 1]: 1, [3, 1, 2]: 3, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 0, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 3, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 0, [2, 1, 3]: 1, [2, 3, 1]: 1, [3, 1, 2]: 3, [3, 2, 1]: 0} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 1, [2, 1, 3]: 0, [2, 3, 1]: 0, [3, 1, 2]: 3, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 1, [2, 1, 3]: 0, [2, 3, 1]: 1, [3, 1, 2]: 3, [3, 2, 1]: 0} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 3, [3, 2, 1]: 0} + +Value restrictions:: + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: alpha_beta = [(len, len)] + sage: value_restrictions = [(Permutation([1, 2]), [1]), (Permutation([3, 2, 1]), [2, 3, 4])] + sage: bij = Bijectionist(A, B, tau, alpha_beta=alpha_beta, value_restrictions=value_restrictions) + sage: for sol in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(sol) + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 3} + ... + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 1, [3, 2, 1]: 2} + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: bij = Bijectionist(A, B, tau, value_restrictions=((Permutation([1, 2]), [4, 5]),)) + Traceback (most recent call last): + ... + ValueError: no possible values found for singleton block [[1, 2]] + +""" +# **************************************************************************** +# Copyright (C) 2020 Martin Rubey <martin.rubey at tuwien.ac.at> +# Stephan Pfannerer +# Tobias Kietreiber +# Alexander Grosz +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# This code 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. +# +# The full text of the GPL is available at: +# +# https://www.gnu.org/licenses/ +# *************************************************************************** +import itertools +from collections import namedtuple, defaultdict +from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException +from sage.rings.integer_ring import ZZ +from sage.combinat.set_partition import SetPartition, SetPartitions +from sage.sets.disjoint_set import DisjointSet +from sage.structure.sage_object import SageObject +from copy import copy +from sage.misc.verbose import get_verbose + + +class Bijectionist(SageObject): + r""" + A toolbox to list all possible bijections between two finite sets + under various constraints. + + INPUT: + + - ``A``, ``B`` -- sets of equal size, given as a list + + - ``tau`` -- (optional) a function from ``B`` to ``Z``, in case of + ``None``, the identity map ``lambda x: x`` is used + + - ``alpha_beta`` -- (optional) a list of pairs of statistics ``alpha`` from + ``A`` to ``W`` and ``beta`` from ``B`` to ``W`` + + - ``P`` -- (optional) a partition of ``A`` + + - ``pi_rho`` -- (optional) a list of triples ``(k, pi, rho)``, where + + * ``pi`` -- a ``k``-ary operation composing objects in ``A`` and + * ``rho`` -- a ``k``-ary function composing statistic values in ``Z`` + + - ``elements_distributions`` -- (optional) a list of pairs ``(tA, tZ)``, + specifying the distributions of ``tA`` + + - ``value_restrictions`` -- (optional) a list of pairs ``(a, tZ)``, + restricting the possible values of ``a`` + + - ``solver`` -- (optional) the backend used to solve the mixed integer + linear programs + + ``W`` and ``Z`` can be arbitrary sets. As a natural example we may think + of the natural numbers or tuples of integers. + + We are looking for a statistic `s: A\to Z` and a bijection `S: A\to B` such + that + + - `s = \tau \circ S`: the statistics `s` and `\tau` are equidistributed and + `S` is an intertwining bijection. + + - `\alpha = \beta \circ S`: the statistics `\alpha` and `\beta` are + equidistributed and `S` is an intertwining bijection. + + - `s` is constant on the blocks of `P`. + + - `s(\pi(a_1,\dots, a_k)) = \rho(s(a_1),\dots, s(a_k))`. + + Additionally, we may require that + + - `s(a)\in Z_a` for specified sets `Z_a\subseteq Z`, and + + - `s|_{\tilde A}` has a specified distribution for specified sets `\tilde A + \subset A`. + + If `\tau` is the identity, the two unknown functions `s` and `S` coincide. + Although we do not exclude other bijective choices for `\tau`, they + probably do not make sense. + + If we want that `S` is graded, i.e. if elements of `A` and `B` have a + notion of size and `S` should preserve this size, we can add grading + statistics as `\alpha` and `\beta`. Since `\alpha` and `\beta` will be + equidistributed with `S` as an intertwining bijection, `S` will then also + be graded. + + In summary, we have the following two commutative diagrams, where `s` and + `S` are unknown functions. + + .. MATH:: + + \begin{array}{rrl} + & A \\ + {\scriptstyle\alpha}\swarrow & {\scriptstyle S}\downarrow & \searrow{\scriptstyle s}\\ + W \overset{\beta}{\leftarrow} & B & \overset{\tau}{\rightarrow} Z + \end{array} + \qquad + \begin{array}{lcl} + A^k &\overset{\pi}{\rightarrow} & A\\ + \downarrow{\scriptstyle s^k} & & \downarrow{\scriptstyle s}\\ + Z^k &\overset{\rho}{\rightarrow} & Z\\ + \end{array} + + .. NOTE:: + + If `\tau` is the identity map, the partition `P` of `A` necessarily + consists only of singletons. + + .. NOTE:: + + The order of invocation of the methods with prefix ``set``, i.e., + :meth:`set_statistics`, :meth:`set_intertwining_relations`, + :meth:`set_constant_blocks`, etc., is irrelevant. Calling any of these + methods a second time overrides the previous specification. + + """ + def __init__(self, A, B, tau=None, alpha_beta=tuple(), P=None, + pi_rho=tuple(), phi_psi=tuple(), Q=None, + elements_distributions=tuple(), + value_restrictions=tuple(), solver=None, key=None): + """ + Initialize the bijectionist. + + TESTS: + + Check that large input sets are handled well:: + + sage: A = B = range(20000) + sage: bij = Bijectionist(A, B) # long time + """ + # glossary of standard letters: + # A, B, Z, W ... finite sets + # P ... set partition of A + # tA, tB, tZ, tP ... subsets + # a in A, b in B, p in P + # S: A -> B + # alpha: A -> W, beta: B -> W + # s: A -> Z, tau: B -> Z + # k arity of pi and rho + # pi: A^k -> A, rho: Z^k -> Z + # a_tuple in A^k + self._A = list(A) + self._B = list(B) + assert len(self._A) == len(set(self._A)), "A must have distinct items" + assert len(self._B) == len(set(self._B)), "B must have distinct items" + self._bmilp = None + self._sorter = {} + self._sorter["A"] = lambda x: sorted(x, key=self._A.index) + self._sorter["B"] = lambda x: sorted(x, key=self._B.index) + + if tau is None: + self._tau = {b: b for b in self._B} + else: + self._tau = {b: tau(b) for b in self._B} + # we store Z as a list to keep an order + self._Z = set(self._tau.values()) + if key is not None and "Z" in key: + self._sorter["Z"] = lambda x: sorted(x, key=key["Z"]) + self._Z = self._sorter["Z"](self._Z) + else: + try: + self._Z = sorted(self._Z) + self._sorter["Z"] = lambda x: sorted(x) + except TypeError: + self._Z = list(self._Z) + self._sorter["Z"] = lambda x: list(x) + if P is None: + P = [] + + # set optional inputs + self.set_statistics(*alpha_beta) + self.set_value_restrictions(*value_restrictions) + self.set_distributions(*elements_distributions) + self.set_quadratic_relation(*phi_psi) + self.set_homomesic(Q) + self.set_intertwining_relations(*pi_rho) + self.set_constant_blocks(P) + + self._solver = solver + + def set_constant_blocks(self, P): + r""" + Declare that `s: A\to Z` is constant on each block of `P`. + + .. WARNING:: + + Any restriction imposed by a previous invocation of + :meth:`set_constant_blocks` will be overwritten, + including restrictions discovered by + :meth:`set_intertwining_relations` and + :meth:`solutions_iterator`! + + A common example is to use the orbits of a bijection acting + on `A`. This can be achieved using the function + :meth:`~sage.combinat.cyclic_sieving_phenomenon.orbit_decomposition`. + + INPUT: + + - ``P`` -- a set partition of `A`, singletons may be omitted + + EXAMPLES: + + Initially the partitions are set to singleton blocks. The + current partition can be reviewed using + :meth:`constant_blocks`:: + + sage: A = B = 'abcd' + sage: bij = Bijectionist(A, B, lambda x: B.index(x) % 2) + sage: bij.constant_blocks() + {} + + sage: bij.set_constant_blocks([['a', 'c']]) + sage: bij.constant_blocks() + {{'a', 'c'}} + + We now add a map that combines some blocks:: + + sage: def pi(p1, p2): return 'abcdefgh'[A.index(p1) + A.index(p2)] + sage: def rho(s1, s2): return (s1 + s2) % 2 + sage: bij.set_intertwining_relations((2, pi, rho)) + sage: list(bij.solutions_iterator()) + [{'a': 0, 'b': 1, 'c': 0, 'd': 1}] + sage: bij.constant_blocks() + {{'a', 'c'}, {'b', 'd'}} + + Setting constant blocks overrides any previous assignment:: + + sage: bij.set_constant_blocks([['a', 'b']]) + sage: bij.constant_blocks() + {{'a', 'b'}} + + If there is no solution, and the coarsest partition is + requested, an error is raised:: + + sage: bij.constant_blocks(optimal=True) + Traceback (most recent call last): + ... + StopIteration + + """ + self._bmilp = None + self._P = DisjointSet(self._A) + P = sorted(self._sorter["A"](p) for p in P) + for p in P: + for a in p: + self._P.union(p[0], a) + + self._compute_possible_block_values() + + def constant_blocks(self, singletons=False, optimal=False): + r""" + Return the set partition `P` of `A` such that `s: A\to Z` is + known to be constant on the blocks of `P`. + + INPUT: + + - ``singletons`` -- (optional, default: ``False``) whether or not to + include singleton blocks in the output + + - ``optimal`` -- (optional, default: ``False``) whether or not to + compute the coarsest possible partition + + .. NOTE:: + + computing the coarsest possible partition may be + computationally expensive, but may speed up generating + solutions. + + EXAMPLES:: + + sage: A = B = ["a", "b", "c"] + sage: bij = Bijectionist(A, B, lambda x: 0) + sage: bij.set_constant_blocks([["a", "b"]]) + sage: bij.constant_blocks() + {{'a', 'b'}} + + sage: bij.constant_blocks(singletons=True) + {{'a', 'b'}, {'c'}} + + """ + if optimal: + self._forced_constant_blocks() + if singletons: + return SetPartition(self._P) + return SetPartition(p for p in self._P if len(p) > 1) + + def set_statistics(self, *alpha_beta): + r""" + Set constraints of the form `\alpha = \beta\circ S`. + + .. WARNING:: + + Any restriction imposed by a previous invocation of + :meth:`set_statistics` will be overwritten! + + INPUT: + + - ``alpha_beta`` -- one or more pairs `(\alpha: A\to W, + \beta: B\to W)` + + If the statistics `\alpha` and `\beta` are not + equidistributed, an error is raised. + + ALGORITHM: + + We add + + .. MATH:: + + \sum_{a\in A, z\in Z} x_{p(a), z} s^z t^{\alpha(a)} + = \sum_{b\in B} s^{\tau(b)} t(\beta(b)) + + as a matrix equation to the MILP. + + EXAMPLES: + + We look for bijections `S` on permutations such that the + number of weak exceedences of `S(\pi)` equals the number of + descents of `\pi`, and statistics `s`, such that the number + of fixed points of `S(\pi)` equals `s(\pi)`:: + + sage: N = 4; A = B = [permutation for n in range(N) for permutation in Permutations(n)] + sage: def wex(p): return len(p.weak_excedences()) + sage: def fix(p): return len(p.fixed_points()) + sage: def des(p): return len(p.descents(final_descent=True)) if p else 0 + sage: def adj(p): return len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1]) + sage: bij = Bijectionist(A, B, fix) + sage: bij.set_statistics((wex, des), (len, len)) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 0, [2, 1, 3]: 0, [2, 3, 1]: 1, [3, 1, 2]: 3, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 0, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 3, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 0, [2, 1, 3]: 1, [2, 3, 1]: 1, [3, 1, 2]: 3, [3, 2, 1]: 0} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 1, [2, 1, 3]: 0, [2, 3, 1]: 0, [3, 1, 2]: 3, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 1, [2, 1, 3]: 0, [2, 3, 1]: 1, [3, 1, 2]: 3, [3, 2, 1]: 0} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 3, [3, 2, 1]: 0} + + sage: bij = Bijectionist(A, B, fix) + sage: bij.set_statistics((wex, des), (fix, adj), (len, len)) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 0, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 3, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 1, [2, 1, 3]: 0, [2, 3, 1]: 0, [3, 1, 2]: 3, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 3, [3, 2, 1]: 0} + + Calling this with non-equidistributed statistics yields an error:: + + sage: bij = Bijectionist(A, B, fix) + sage: bij.set_statistics((wex, fix)) + Traceback (most recent call last): + ... + ValueError: statistics alpha and beta are not equidistributed + + TESTS: + + Calling ``set_statistics`` without arguments should restore the previous state:: + + sage: N = 3; A = B = [permutation for n in range(N) for permutation in Permutations(n)] + sage: def wex(p): return len(p.weak_excedences()) + sage: def fix(p): return len(p.fixed_points()) + sage: def des(p): return len(p.descents(final_descent=True)) if p else 0 + sage: bij = Bijectionist(A, B, fix) + sage: bij.set_statistics((wex, des), (len, len)) + sage: for solution in bij.solutions_iterator(): + ....: print(solution) + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2} + sage: bij.set_statistics() + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1]: 0, [1, 2]: 1, [2, 1]: 2} + {[]: 0, [1]: 0, [1, 2]: 2, [2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0} + {[]: 0, [1]: 2, [1, 2]: 0, [2, 1]: 1} + {[]: 0, [1]: 2, [1, 2]: 1, [2, 1]: 0} + {[]: 1, [1]: 0, [1, 2]: 0, [2, 1]: 2} + {[]: 1, [1]: 0, [1, 2]: 2, [2, 1]: 0} + {[]: 1, [1]: 2, [1, 2]: 0, [2, 1]: 0} + {[]: 2, [1]: 0, [1, 2]: 0, [2, 1]: 1} + {[]: 2, [1]: 0, [1, 2]: 1, [2, 1]: 0} + {[]: 2, [1]: 1, [1, 2]: 0, [2, 1]: 0} + + """ + self._bmilp = None + self._n_statistics = len(alpha_beta) + # TODO: do we really want to recompute statistics every time? + self._alpha = lambda p: tuple(arg[0](p) for arg in alpha_beta) + self._beta = lambda p: tuple(arg[1](p) for arg in alpha_beta) + + # generate fibers + self._statistics_fibers = {} + for a in self._A: + v = self._alpha(a) + if v not in self._statistics_fibers: + self._statistics_fibers[v] = ([], []) + self._statistics_fibers[v][0].append(a) + + for b in self._B: + v = self._beta(b) + if v not in self._statistics_fibers: + raise ValueError(f"statistics alpha and beta do not have the same image, {v} is not a value of alpha, but of beta") + self._statistics_fibers[v][1].append(b) + + # check compatibility + if not all(len(fiber[0]) == len(fiber[1]) + for fiber in self._statistics_fibers.values()): + raise ValueError("statistics alpha and beta are not equidistributed") + + self._W = list(self._statistics_fibers) + + # the possible values of s(a) are tau(beta^{-1}(alpha(a))) + tau_beta_inverse = {} + self._statistics_possible_values = {} + for a in self._A: + v = self._alpha(a) + if v not in tau_beta_inverse: + tau_beta_inverse[v] = set(self._tau[b] + for b in self._statistics_fibers[v][1]) + self._statistics_possible_values[a] = tau_beta_inverse[v] + + def statistics_fibers(self): + r""" + Return a dictionary mapping statistic values in `W` to their + preimages in `A` and `B`. + + This is a (computationally) fast way to obtain a first + impression which objects in `A` should be mapped to which + objects in `B`. + + EXAMPLES:: + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: def wex(p): return len(p.weak_excedences()) + sage: def fix(p): return len(p.fixed_points()) + sage: def des(p): return len(p.descents(final_descent=True)) if p else 0 + sage: def adj(p): return len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1]) + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((len, len), (wex, des), (fix, adj)) + sage: table([[key, AB[0], AB[1]] for key, AB in bij.statistics_fibers().items()]) + (0, 0, 0) [[]] [[]] + (1, 1, 1) [[1]] [[1]] + (2, 2, 2) [[1, 2]] [[2, 1]] + (2, 1, 0) [[2, 1]] [[1, 2]] + (3, 3, 3) [[1, 2, 3]] [[3, 2, 1]] + (3, 2, 1) [[1, 3, 2], [2, 1, 3], [3, 2, 1]] [[1, 3, 2], [2, 1, 3], [2, 3, 1]] + (3, 2, 0) [[2, 3, 1]] [[3, 1, 2]] + (3, 1, 0) [[3, 1, 2]] [[1, 2, 3]] + + """ + return self._statistics_fibers + + def statistics_table(self, header=True): + r""" + Provide information about all elements of `A` with corresponding + `\alpha` values and all elements of `B` with corresponding + `\beta` and `\tau` values. + + INPUT: + + - ``header`` -- (default: ``True``) whether to include a + header with the standard Greek letters + + OUTPUT: + + A pair of lists suitable for :class:`~sage.misc.table.table`, + where + + - the first contains the elements of `A` together with the + values of `\alpha` + + - the second contains the elements of `B` together with the + values of `\tau` and `\beta` + + EXAMPLES:: + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: def wex(p): return len(p.weak_excedences()) + sage: def fix(p): return len(p.fixed_points()) + sage: def des(p): return len(p.descents(final_descent=True)) if p else 0 + sage: def adj(p): return len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1]) + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((wex, des), (fix, adj)) + sage: a, b = bij.statistics_table() + sage: table(a, header_row=True, frame=True) + +-----------+--------+--------+ + | a | ฮฑ_1(a) | ฮฑ_2(a) | + +===========+========+========+ + | [] | 0 | 0 | + +-----------+--------+--------+ + | [1] | 1 | 1 | + +-----------+--------+--------+ + | [1, 2] | 2 | 2 | + +-----------+--------+--------+ + | [2, 1] | 1 | 0 | + +-----------+--------+--------+ + | [1, 2, 3] | 3 | 3 | + +-----------+--------+--------+ + | [1, 3, 2] | 2 | 1 | + +-----------+--------+--------+ + | [2, 1, 3] | 2 | 1 | + +-----------+--------+--------+ + | [2, 3, 1] | 2 | 0 | + +-----------+--------+--------+ + | [3, 1, 2] | 1 | 0 | + +-----------+--------+--------+ + | [3, 2, 1] | 2 | 1 | + +-----------+--------+--------+ + sage: table(b, header_row=True, frame=True) + +-----------+---+--------+--------+ + | b | ฯ„ | ฮฒ_1(b) | ฮฒ_2(b) | + +===========+===+========+========+ + | [] | 0 | 0 | 0 | + +-----------+---+--------+--------+ + | [1] | 1 | 1 | 1 | + +-----------+---+--------+--------+ + | [1, 2] | 2 | 1 | 0 | + +-----------+---+--------+--------+ + | [2, 1] | 1 | 2 | 2 | + +-----------+---+--------+--------+ + | [1, 2, 3] | 3 | 1 | 0 | + +-----------+---+--------+--------+ + | [1, 3, 2] | 2 | 2 | 1 | + +-----------+---+--------+--------+ + | [2, 1, 3] | 2 | 2 | 1 | + +-----------+---+--------+--------+ + | [2, 3, 1] | 2 | 2 | 1 | + +-----------+---+--------+--------+ + | [3, 1, 2] | 2 | 2 | 0 | + +-----------+---+--------+--------+ + | [3, 2, 1] | 1 | 3 | 3 | + +-----------+---+--------+--------+ + + TESTS: + + If no statistics are given, the table should still be able to be generated:: + + sage: A = B = [permutation for n in range(3) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: bij = Bijectionist(A, B, tau) + sage: a, b = bij.statistics_table() + sage: table(a, header_row=True, frame=True) + +--------+ + | a | + +========+ + | [] | + +--------+ + | [1] | + +--------+ + | [1, 2] | + +--------+ + | [2, 1] | + +--------+ + sage: table(b, header_row=True, frame=True) + +--------+---+ + | b | ฯ„ | + +========+===+ + | [] | 0 | + +--------+---+ + | [1] | 1 | + +--------+---+ + | [1, 2] | 2 | + +--------+---+ + | [2, 1] | 1 | + +--------+---+ + + We can omit the header:: + + sage: bij.statistics_table(header=True)[1] + [['b', 'ฯ„'], [[], 0], [[1], 1], [[1, 2], 2], [[2, 1], 1]] + sage: bij.statistics_table(header=False)[1] + [[[], 0], [[1], 1], [[1, 2], 2], [[2, 1], 1]] + + """ + # table for alpha + n_statistics = self._n_statistics + if header: + output_alphas = [["a"] + ["\u03b1_" + str(i) + "(a)" + for i in range(1, n_statistics + 1)]] + else: + output_alphas = [] + + for a in self._A: + if n_statistics > 0: + output_alphas.append([a] + list(self._alpha(a))) + else: + output_alphas.append([a]) + + # table for beta and tau + if header: + output_tau_betas = [["b", "\u03c4"] + ["\u03b2_" + str(i) + "(b)" + for i in range(1, n_statistics + 1)]] + else: + output_tau_betas = [] + for b in self._B: + if n_statistics > 0: + output_tau_betas.append([b, self._tau[b]] + list(self._beta(b))) + else: + output_tau_betas.append([b, self._tau[b]]) + + return output_alphas, output_tau_betas + + def set_value_restrictions(self, *value_restrictions): + r""" + Restrict the set of possible values `s(a)` for a given element + `a`. + + .. WARNING:: + + Any restriction imposed by a previous invocation of + :meth:`set_value_restrictions` will be overwritten! + + INPUT: + + - ``value_restrictions`` -- one or more pairs `(a\in A, \tilde + Z\subseteq Z)` + + EXAMPLES: + + We may want to restrict the value of a given element to a + single or multiple values. We do not require that the + specified values are in the image of `\tau`. In some + cases, the restriction may not be able to provide a better + solution, as for size 3 in the following example. :: + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((len, len)) + sage: bij.set_value_restrictions((Permutation([1, 2]), [1]), + ....: (Permutation([3, 2, 1]), [2, 3, 4])) + sage: for sol in sorted(bij.solutions_iterator(), key=lambda d: sorted(d.items())): + ....: print(sol) + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 3} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 3, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 3, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 2, [2, 1, 3]: 3, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 1, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 3} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 1, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 3, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 1, [2, 1, 3]: 2, [2, 3, 1]: 3, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 1, [2, 1, 3]: 3, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 2, [2, 1, 3]: 1, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 3} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 2, [2, 1, 3]: 1, [2, 3, 1]: 2, [3, 1, 2]: 3, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 2, [2, 1, 3]: 1, [2, 3, 1]: 3, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 1, [3, 1, 2]: 2, [3, 2, 1]: 3} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 1, [3, 1, 2]: 3, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 1, [3, 2, 1]: 3} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 3, [3, 1, 2]: 1, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 2, [2, 1, 3]: 3, [2, 3, 1]: 1, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 2, [2, 1, 3]: 3, [2, 3, 1]: 2, [3, 1, 2]: 1, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 1, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 1, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 1, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 1, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 1, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 1, [3, 2, 1]: 2} + + However, an error occurs if the set of possible values is + empty. In this example, the image of `\tau` under any + legal bijection is disjoint to the specified values. + + TESTS:: + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_value_restrictions((Permutation([1, 2]), [4, 5])) + sage: bij._compute_possible_block_values() + Traceback (most recent call last): + ... + ValueError: no possible values found for singleton block [[1, 2]] + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_constant_blocks([[permutation for permutation in Permutations(n)] for n in range(4)]) + sage: bij.set_value_restrictions((Permutation([1, 2]), [4, 5])) + sage: bij._compute_possible_block_values() + Traceback (most recent call last): + ... + ValueError: no possible values found for block [[1, 2], [2, 1]] + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_value_restrictions(((1, 2), [4, 5, 6])) + Traceback (most recent call last): + ... + AssertionError: element (1, 2) was not found in A + + """ + # it might be much cheaper to construct the sets as subsets + # of _statistics_possible_values - however, we do not want to + # insist that set_value_restrictions is called after + # set_statistics + self._bmilp = None + set_Z = set(self._Z) + self._restrictions_possible_values = {a: set_Z for a in self._A} + for a, values in value_restrictions: + assert a in self._A, f"element {a} was not found in A" + self._restrictions_possible_values[a] = self._restrictions_possible_values[a].intersection(values) + + def _compute_possible_block_values(self): + r""" + Update the dictionary of possible values of each block. + + This has to be called whenever ``self._P`` was modified. + + It raises a :class:`ValueError`, if the restrictions on a + block are contradictory. + + TESTS:: + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_value_restrictions((Permutation([1, 2]), [4, 5])) + sage: bij._compute_possible_block_values() + Traceback (most recent call last): + ... + ValueError: no possible values found for singleton block [[1, 2]] + + """ + self._possible_block_values = {} # P -> Power(Z) + for p, block in self._P.root_to_elements_dict().items(): + sets = ([self._restrictions_possible_values[a] for a in block] + + [self._statistics_possible_values[a] for a in block]) + self._possible_block_values[p] = _non_copying_intersection(sets) + if not self._possible_block_values[p]: + if len(block) == 1: + raise ValueError(f"no possible values found for singleton block {block}") + else: + raise ValueError(f"no possible values found for block {block}") + + def set_distributions(self, *elements_distributions): + r""" + Specify the distribution of `s` for a subset of elements. + + .. WARNING:: + + Any restriction imposed by a previous invocation of + :meth:`set_distributions` will be overwritten! + + INPUT: + + - one or more pairs of `(\tilde A, \tilde Z)`, where `\tilde + A\subseteq A` and `\tilde Z` is a list of values in `Z` of + the same size as `\tilde A` + + This method specifies that `\{s(a) | a\in\tilde A\}` equals + `\tilde Z` as a multiset for each of the pairs. + + When specifying several distributions, the subsets of `A` do + not have to be disjoint. + + ALGORITHM: + + We add + + .. MATH:: + + \sum_{a\in\tilde A} x_{p(a), z}t^z = \sum_{z\in\tilde Z} t^z, + + where `p(a)` is the block containing `a`, for each given + distribution as a vector equation to the MILP. + + EXAMPLES:: + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((len, len)) + sage: bij.set_distributions(([Permutation([1, 2, 3]), Permutation([1, 3, 2])], [1, 3])) + sage: for sol in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(sol) + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 1, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + + sage: bij.constant_blocks(optimal=True) + {{[2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]}} + sage: sorted(bij.minimal_subdistributions_blocks_iterator(), key=lambda d: (len(d[0]), d[0])) + [([[]], [0]), + ([[1]], [1]), + ([[2, 1, 3]], [2]), + ([[1, 2], [2, 1]], [1, 2]), + ([[1, 2, 3], [1, 3, 2]], [1, 3])] + + We may also specify multiple, possibly overlapping distributions:: + + sage: bij.set_distributions(([Permutation([1, 2, 3]), Permutation([1, 3, 2])], [1, 3]), + ....: ([Permutation([1, 3, 2]), Permutation([3, 2, 1]), + ....: Permutation([2, 1, 3])], [1, 2, 2])) + sage: for sol in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(sol) + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + + sage: bij.constant_blocks(optimal=True) + {{[1], [1, 3, 2]}, {[2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]}} + sage: sorted(bij.minimal_subdistributions_blocks_iterator(), key=lambda d: (len(d[0]), d[0])) + [([[]], [0]), + ([[1]], [1]), + ([[1, 2, 3]], [3]), + ([[2, 3, 1]], [2]), + ([[1, 2], [2, 1]], [1, 2])] + + TESTS: + + Because of the current implementation of the output calculation, we do + not improve our solution if we do not gain any unique solutions:: + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: tau = Permutation.longest_increasing_subsequence_length + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((len, len)) + sage: bij.set_distributions(([Permutation([1, 2, 3]), Permutation([1, 3, 2])], [2, 3])) + sage: for sol in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(sol) + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 1, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 1, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 1, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 1, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 1, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 1, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 1, [2, 1]: 2, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 1, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 1, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 1, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 1, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 1, [3, 1, 2]: 2, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 1, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 1} + + Another example with statistics:: + + sage: bij = Bijectionist(A, B, tau) + sage: def alpha(p): return p(1) if len(p) > 0 else 0 + sage: def beta(p): return p(1) if len(p) > 0 else 0 + sage: bij.set_statistics((alpha, beta), (len, len)) + sage: for sol in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(sol) + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 1, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 2, [1, 3, 2]: 3, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 1, [3, 2, 1]: 2} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 1} + + The solution above is not unique. We can add a feasible distribution to force uniqueness:: + + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((alpha, beta), (len, len)) + sage: bij.set_distributions(([Permutation([1, 2, 3]), Permutation([3, 2, 1])], [1, 3])) + sage: for sol in bij.solutions_iterator(): + ....: print(sol) + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 1, [1, 2, 3]: 3, [1, 3, 2]: 2, [2, 1, 3]: 2, [2, 3, 1]: 2, [3, 1, 2]: 2, [3, 2, 1]: 1} + + Let us try to add a distribution that cannot be satisfied, + because there is no solution where a permutation that starts + with 1 is mapped onto 1:: + + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((alpha, beta), (len, len)) + sage: bij.set_distributions(([Permutation([1, 2, 3]), Permutation([1, 3, 2])], [1, 3])) + sage: list(bij.solutions_iterator()) + [] + + The specified elements have to be in `A` and have to be of the same size:: + + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((len, len)) + sage: bij.set_distributions(([Permutation([1, 2, 3, 4])], [1])) + Traceback (most recent call last): + ... + ValueError: element [1, 2, 3, 4] was not found in A + sage: bij.set_distributions(([Permutation([1, 2, 3])], [-1])) + Traceback (most recent call last): + ... + ValueError: value -1 was not found in tau(A) + + Note that the same error occurs when an element that is not the first element of the list is + not in `A`. + + """ + self._bmilp = None + for tA, tZ in elements_distributions: + assert len(tA) == len(tZ), f"{tA} and {tZ} are not of the same size!" + for a, z in zip(tA, tZ): + if a not in self._A: + raise ValueError(f"element {a} was not found in A") + if z not in self._Z: + raise ValueError(f"value {z} was not found in tau(A)") + self._elements_distributions = tuple(elements_distributions) + + def set_intertwining_relations(self, *pi_rho): + r""" + Add restrictions of the form `s(\pi(a_1,\dots, a_k)) = + \rho(s(a_1),\dots, s(a_k))`. + + .. WARNING:: + + Any restriction imposed by a previous invocation of + :meth:`set_intertwining_relations` will be overwritten! + + INPUT: + + - ``pi_rho`` -- one or more tuples `(k, \pi: A^k\to A, \rho: + Z^k\to Z, \tilde A)` where `\tilde A` (optional) is a + `k`-ary function that returns true if and only if a + `k`-tuple of objects in `A` is in the domain of `\pi` + + ALGORITHM: + + The relation + + .. MATH:: + + s(\pi(a_1,\dots, a_k)) = \rho(s(a_1),\dots, s(a_k)) + + for each pair `(\pi, \rho)` implies immediately that + `s(\pi(a_1,\dots, a_k))` only depends on the blocks of + `a_1,\dots, a_k`. + + The MILP formulation is as follows. Let `a_1,\dots,a_k \in + A` and let `a = \pi(a_1,\dots,a_k)`. Let `z_1,\dots,z_k \in + Z` and let `z = \rho(z_1,\dots,z_k)`. Suppose that `a_i\in + p_i` for all `i` and that `a\in p`. + + We then want to model the implication + + .. MATH:: + + x_{p_1, z_1} = 1,\dots, x_{p_k, z_k} = 1 \Rightarrow x_{p, z} = 1. + + We achieve this by requiring + + .. MATH:: + + x_{p, z}\geq 1 - k + \sum_{i=1}^k x_{p_i, z_i}. + + Note that `z` must be a possible value of `p` and each `z_i` + must be a possible value of `p_i`. + + EXAMPLES: + + We can concatenate two permutations by increasing the values + of the second permutation by the length of the first + permutation:: + + sage: def concat(p1, p2): return Permutation(p1 + [i + len(p1) for i in p2]) + + We may be interested in statistics on permutations which are + equidistributed with the number of fixed points, such that + concatenating permutations corresponds to adding statistic + values:: + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: bij = Bijectionist(A, B, Permutation.number_of_fixed_points) + sage: bij.set_statistics((len, len)) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + ... + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 0, [2, 1, 3]: 0, [2, 3, 1]: 1, [3, 1, 2]: 1, [3, 2, 1]: 3} + ... + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 1, [2, 1, 3]: 3, [2, 3, 1]: 0, [3, 1, 2]: 0, [3, 2, 1]: 1} + ... + + sage: bij.set_intertwining_relations((2, concat, lambda x, y: x + y)) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 0, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 1, [3, 2, 1]: 0} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 1, [3, 1, 2]: 0, [3, 2, 1]: 0} + + The domain of the composition may be restricted. E.g., if we + concatenate only permutations starting with a 1, we obtain + fewer forced elements:: + + sage: in_domain = lambda p1, p2: (not p1 or p1(1) == 1) and (not p2 or p2(1) == 1) + sage: bij.set_intertwining_relations((2, concat, lambda x, y: x + y, in_domain)) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 0, [2, 1, 3]: 0, [2, 3, 1]: 1, [3, 1, 2]: 1, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 0, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 1, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 0, [2, 1, 3]: 1, [2, 3, 1]: 1, [3, 1, 2]: 0, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 0, [2, 1, 3]: 1, [2, 3, 1]: 1, [3, 1, 2]: 1, [3, 2, 1]: 0} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 0, [2, 3, 1]: 0, [3, 1, 2]: 1, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 0, [2, 3, 1]: 1, [3, 1, 2]: 0, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 0, [2, 3, 1]: 1, [3, 1, 2]: 1, [3, 2, 1]: 0} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 0, [3, 2, 1]: 1} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 0, [3, 1, 2]: 1, [3, 2, 1]: 0} + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 0, [1, 2, 3]: 3, [1, 3, 2]: 1, [2, 1, 3]: 1, [2, 3, 1]: 1, [3, 1, 2]: 0, [3, 2, 1]: 0} + + We can also restrict according to several composition + functions. For example, we may additionally concatenate + permutations by incrementing the elements of the first:: + + sage: skew_concat = lambda p1, p2: Permutation([i + len(p2) for i in p1] + list(p2)) + sage: bij.set_intertwining_relations((2, skew_concat, lambda x, y: x + y)) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 0, [1, 3, 2]: 0, [2, 1, 3]: 1, [2, 3, 1]: 1, [3, 1, 2]: 1, [3, 2, 1]: 3} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 0, [1, 3, 2]: 1, [2, 1, 3]: 0, [2, 3, 1]: 1, [3, 1, 2]: 1, [3, 2, 1]: 3} + {[]: 0, [1]: 1, [1, 2]: 0, [2, 1]: 2, [1, 2, 3]: 1, [1, 3, 2]: 0, [2, 1, 3]: 0, [2, 3, 1]: 1, [3, 1, 2]: 1, [3, 2, 1]: 3} + + However, this yields no solution:: + + sage: bij.set_intertwining_relations((2, concat, lambda x, y: x + y), (2, skew_concat, lambda x, y: x + y)) + sage: list(bij.solutions_iterator()) + [] + + """ + self._bmilp = None + Pi_Rho = namedtuple("Pi_Rho", "numargs pi rho domain") + self._pi_rho = [] + + for pi_rho_tuple in pi_rho: + if len(pi_rho_tuple) == 3: + k, pi, rho = pi_rho_tuple + domain = None + else: + k, pi, rho, domain = pi_rho_tuple + + self._pi_rho.append(Pi_Rho(numargs=k, pi=pi, rho=rho, domain=domain)) + + set_semi_conjugacy = set_intertwining_relations + + def set_quadratic_relation(self, *phi_psi): + r""" + Add restrictions of the form `s\circ\psi\circ s = \phi`. + + INPUT: + + - ``phi_psi`` -- (optional) a list of pairs `(\phi, \rho)` where `\phi: + A\to Z` and `\psi: Z\to A` + + ALGORITHM: + + We add + + .. MATH:: + + x_{p(a), z} = x_{p(\psi(z)), \phi(a)} + + for `a\in A` and `z\in Z` to the MILP, where `\phi:A\to Z` + and `\psi:Z\to A`. Note that, in particular, `\phi` must be + constant on blocks. + + + EXAMPLES:: + + sage: A = B = DyckWords(3) + sage: bij = Bijectionist(A, B) + sage: bij.set_statistics((lambda D: D.number_of_touch_points(), lambda D: D.number_of_initial_rises())) + sage: ascii_art(sorted(bij.minimal_subdistributions_iterator())) + [ ( [ /\ ] ) + [ ( [ / \ ] ) ( [ /\ /\ ] [ /\ /\/\ ] ) + [ ( [ /\/\/\ ], [ / \ ] ), ( [ /\/ \, / \/\ ], [ / \/\, / \ ] ), + <BLANKLINE> + ( [ /\ ] ) ] + ( [ /\/\ / \ ] [ /\ ] ) ] + ( [ / \, / \ ], [ /\/\/\, /\/ \ ] ) ] + sage: bij.set_quadratic_relation((lambda D: D, lambda D: D)) + sage: ascii_art(sorted(bij.minimal_subdistributions_iterator())) + [ ( [ /\ ] ) + [ ( [ / \ ] ) ( [ /\ ] [ /\/\ ] ) + [ ( [ /\/\/\ ], [ / \ ] ), ( [ /\/ \ ], [ / \ ] ), + <BLANKLINE> + <BLANKLINE> + ( [ /\ ] [ /\ ] ) ( [ /\/\ ] [ /\ ] ) + ( [ / \/\ ], [ / \/\ ] ), ( [ / \ ], [ /\/ \ ] ), + <BLANKLINE> + ( [ /\ ] ) ] + ( [ / \ ] ) ] + ( [ / \ ], [ /\/\/\ ] ) ] + + """ + self._bmilp = None + self._phi_psi = phi_psi + + def set_homomesic(self, Q): + """ + Assert that the average of `s` on each block of `Q` is + constant. + + INPUT: + + - ``Q`` -- a set partition of ``A`` + + EXAMPLES:: + + sage: A = B = [1,2,3] + sage: bij = Bijectionist(A, B, lambda b: b % 3) + sage: bij.set_homomesic([[1,2], [3]]) + sage: list(bij.solutions_iterator()) + [{1: 2, 2: 0, 3: 1}, {1: 0, 2: 2, 3: 1}] + + """ + self._bmilp = None + if Q is None: + self._Q = None + else: + self._Q = SetPartition(Q) + assert self._Q in SetPartitions(self._A), f"{Q} must be a set partition of A" + + def _forced_constant_blocks(self): + r""" + Modify current partition into blocks to the coarsest possible + one, meaning that after calling this function for every two + distinct blocks `p_1`, `p_2` there exists a solution `s` with + `s(p_1)\neq s(p_2)`. + + ALGORITHM: + + First we generate an initial solution. For all blocks i, j + that have the same value under this initial solution, we add + the constraint `x[i, z] + x[j, z] <= 1` for all possible + values `z\in Z`. This constraint ensures that the `s` differs + on the two blocks. If this modified problem does not have a + solution, we know that the two blocks always have the same + value and join them. Then we save all values of this new + solution and continue looking at pairs of blocks that had the + same value under all calculated solutions, until no blocks + can be joined anymore. + + EXAMPLES: + + The easiest example is given by a constant `tau`, so everything + is forced to be the same value: + + sage: A = B = [permutation for n in range(3) for permutation in Permutations(n)] + sage: bij = Bijectionist(A, B, lambda x: 0) + sage: bij.constant_blocks() + {} + sage: bij.constant_blocks(optimal=True) # indirect doctest + {{[], [1], [1, 2], [2, 1]}} + + In this other example we look at permutations with length 2 and 3:: + + sage: N = 4 + sage: A = B = [permutation for n in range(2, N) for permutation in Permutations(n)] + sage: def tau(p): return p[0] if len(p) else 0 + sage: add_n = lambda p1: Permutation(p1 + [1 + len(p1)]) + sage: add_1 = lambda p1: Permutation([1] + [1 + i for i in p1]) + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_intertwining_relations((1, add_n, lambda x: x + 1), (1, add_1, lambda x: x + 1)) + sage: bij.set_statistics((len, len)) + + sage: bij.constant_blocks() + {} + sage: bij.constant_blocks(optimal=True) + {{[1, 3, 2], [2, 1, 3]}} + + Indeed, ``[1,3,2]`` and ``[2,1,3]`` have the same value in + all solutions, but different values are possible:: + + sage: pi1 = Permutation([1,3,2]); pi2 = Permutation([2,1,3]); + sage: set([(solution[pi1], solution[pi2]) for solution in bij.solutions_iterator()]) + {(2, 2), (3, 3)} + + Another example involving the cycle type of permutations:: + + sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)] + sage: bij = Bijectionist(A, B, lambda x: x.cycle_type()) + + Let us require that each permutation has the same value as its inverse:: + + sage: from sage.combinat.cyclic_sieving_phenomenon import orbit_decomposition + sage: P = orbit_decomposition([permutation for n in range(4) for permutation in Permutations(n)], Permutation.inverse) + sage: bij.set_constant_blocks(P) + sage: bij.constant_blocks() + {{[2, 3, 1], [3, 1, 2]}} + + sage: def concat(p1, p2): return Permutation(p1 + [i + len(p1) for i in p2]) + sage: def union(p1, p2): return Partition(sorted(list(p1) + list(p2), reverse=True)) + sage: bij.set_intertwining_relations((2, concat, union)) + + In this case we do not discover constant blocks by looking at the intertwining_relations only:: + + sage: next(bij.solutions_iterator()) + ... + sage: bij.constant_blocks() + {{[2, 3, 1], [3, 1, 2]}} + + sage: bij.constant_blocks(optimal=True) + {{[1, 3, 2], [2, 1, 3], [3, 2, 1]}, {[2, 3, 1], [3, 1, 2]}} + + TESTS:: + + sage: N = 4 + sage: A = B = [permutation for n in range(N + 1) for permutation in Permutations(n)] + sage: def alpha1(p): return len(p.weak_excedences()) + sage: def alpha2(p): return len(p.fixed_points()) + sage: def beta1(p): return len(p.descents(final_descent=True)) if p else 0 + sage: def beta2(p): return len([e for (e, f) in zip(p, p[1:] + [0]) if e == f + 1]) + sage: tau = Permutation.longest_increasing_subsequence_length + sage: def rotate_permutation(p): + ....: cycle = Permutation(tuple(range(1, len(p) + 1))) + ....: return Permutation([cycle.inverse()(p(cycle(i))) for i in range(1, len(p) + 1)]) + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((alpha1, beta1), (alpha2, beta2)) + sage: from sage.combinat.cyclic_sieving_phenomenon import orbit_decomposition + sage: bij.set_constant_blocks(orbit_decomposition(A, rotate_permutation)) + sage: P = bij.constant_blocks() + sage: P = [sorted(p, key=lambda p: (len(p), p)) for p in P] + sage: P = sorted(P, key=lambda p: (len(next(iter(p))), len(p))) + sage: for p in P: + ....: print(p) + [[1, 3, 2], [2, 1, 3], [3, 2, 1]] + [[1, 4, 3, 2], [3, 2, 1, 4]] + [[2, 1, 4, 3], [4, 3, 2, 1]] + [[1, 2, 4, 3], [1, 3, 2, 4], [2, 1, 3, 4], [4, 2, 3, 1]] + [[1, 3, 4, 2], [2, 3, 1, 4], [2, 4, 3, 1], [3, 2, 4, 1]] + [[1, 4, 2, 3], [3, 1, 2, 4], [4, 1, 3, 2], [4, 2, 1, 3]] + [[2, 4, 1, 3], [3, 1, 4, 2], [3, 4, 2, 1], [4, 3, 1, 2]] + + sage: P = bij.constant_blocks(optimal=True) + sage: P = [sorted(p, key=lambda p: (len(p), p)) for p in P] + sage: P = sorted(P, key=lambda p: (len(next(iter(p))), len(p))) + sage: for p in P: + ....: print(p) + [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]] + [[1, 3, 2], [2, 1, 3], [3, 2, 1], + [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], [1, 4, 3, 2], + [2, 1, 3, 4], [2, 1, 4, 3], [2, 3, 1, 4], [2, 3, 4, 1], + [2, 4, 3, 1], [3, 2, 1, 4], [3, 2, 4, 1], [4, 2, 3, 1], + [4, 3, 2, 1]] + [[1, 4, 2, 3], [2, 4, 1, 3], [3, 1, 2, 4], [3, 1, 4, 2], + [3, 4, 2, 1], [4, 1, 3, 2], [4, 2, 1, 3], [4, 3, 1, 2]] + + The permutation `[2, 1]` is in none of these blocks:: + + sage: bij.set_constant_blocks(orbit_decomposition(A, rotate_permutation)) + sage: all(s[Permutation([2, 1])] == s[Permutation([1])] for s in bij.solutions_iterator()) + False + + sage: all(s[Permutation([2, 1])] == s[Permutation([1, 3, 2])] for s in bij.solutions_iterator()) + False + + sage: all(s[Permutation([2, 1])] == s[Permutation([1, 4, 2, 3])] for s in bij.solutions_iterator()) + False + + sage: A = B = ["a", "b", "c", "d", "e", "f"] + sage: tau = {"a": 1, "b": 1, "c": 3, "d": 4, "e": 5, "f": 6}.get + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_distributions((["a", "b"], [1, 1]), (["c", "d", "e"], [3, 4, 5])) + sage: bij.constant_blocks() + {} + sage: bij.constant_blocks(optimal=True) + {{'a', 'b'}} + + sage: A = B = ["a", "b", "c", "d", "e", "f"] + sage: tau = {"a": 1, "b": 1, "c": 5, "d": 4, "e": 4, "f": 6}.get + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_distributions((["a", "b"], [1, 1]), (["d", "e"], [4, 4])) + sage: bij.constant_blocks(optimal=True) + {{'a', 'b'}, {'d', 'e'}} + + sage: A = B = ["a", "b", "c", "d"] + sage: tau = {"a": 1, "b": 1, "c": 2, "d": 2}.get + sage: bij = Bijectionist(A, B, tau) + sage: bij.constant_blocks(optimal=True) + {} + sage: bij.set_constant_blocks([["a", "b"]]) + sage: bij.constant_blocks() + {{'a', 'b'}} + sage: bij.constant_blocks(optimal=True) + {{'a', 'b'}, {'c', 'd'}} + + """ + if self._bmilp is None: + self._bmilp = _BijectionistMILP(self) + + solution = next(self._bmilp.solutions_iterator(True, [])) + # multiple_preimages[tZ] are the blocks p which have the same + # value tZ[i] in the i-th known solution + multiple_preimages = {(z,): tP + for z, tP in _invert_dict(solution).items() + if len(tP) > 1} + + # _P has to be copied to not mess with the solution process + # since we do not want to regenerate the bmilp in each step, + # so blocks have to stay consistent during the whole process + tmp_P = copy(self._P) + + # check whether blocks p1 and p2 can have different values, + # if so return such a solution + def different_values(p1, p2): + tmp_constraints = [self._bmilp._x[p1, z] + self._bmilp._x[p2, z] <= 1 + for z in self._possible_block_values[p1] + if z in self._possible_block_values[p2]] + return next(self._bmilp.solutions_iterator(True, tmp_constraints)) + + # try to find a pair of blocks having the same value on all + # known solutions, and a solution such that the values are + # different on this solution + def merge_until_split(): + for tZ in list(multiple_preimages): + tP = multiple_preimages[tZ] + for i2 in range(len(tP)-1, -1, -1): + for i1 in range(i2): + try: + solution = different_values(tP[i1], tP[i2]) + except StopIteration: + tmp_P.union(tP[i1], tP[i2]) + if len(multiple_preimages[tZ]) == 2: + del multiple_preimages[tZ] + else: + tP.remove(tP[i2]) + break # skip all pairs (i, j) containing i2 + return solution + + while True: + solution = merge_until_split() + if solution is None: + self._P = tmp_P + # recreate the MILP + self._bmilp = _BijectionistMILP(self, + self._bmilp._solution_cache) + return + + updated_multiple_preimages = defaultdict(list) + for tZ, tP in multiple_preimages.items(): + for p in tP: + updated_multiple_preimages[tZ + (solution[p],)].append(p) + multiple_preimages = updated_multiple_preimages + + def possible_values(self, p=None, optimal=False): + r""" + Return for each block the values of `s` compatible with the + imposed restrictions. + + INPUT: + + - ``p`` -- (optional) a block of `P`, or an element of a + block of `P`, or a list of these + + - ``optimal`` -- (default: ``False``) whether or not to + compute the minimal possible set of statistic values + + .. NOTE:: + + Computing the minimal possible set of statistic values + may be computationally expensive. + + .. TODO:: + + currently, calling this method with ``optimal=True`` does + not update the internal dictionary, because this would + interfere with the variables of the MILP. + + EXAMPLES:: + + sage: A = B = ["a", "b", "c", "d"] + sage: tau = {"a": 1, "b": 1, "c": 1, "d": 2}.get + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_constant_blocks([["a", "b"]]) + sage: bij.possible_values(A) + {'a': {1, 2}, 'b': {1, 2}, 'c': {1, 2}, 'd': {1, 2}} + sage: bij.possible_values(A, optimal=True) + {'a': {1}, 'b': {1}, 'c': {1, 2}, 'd': {1, 2}} + + The internal dictionary is not updated:: + + sage: bij.possible_values(A) + {'a': {1, 2}, 'b': {1, 2}, 'c': {1, 2}, 'd': {1, 2}} + + TESTS:: + + sage: A = B = ["a", "b", "c", "d"] + sage: tau = {"a": 1, "b": 1, "c": 2, "d": 2}.get + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_constant_blocks([["a", "b"]]) + + Test if all formats are really possible:: + + sage: bij.possible_values(p="a") + {'a': {1, 2}, 'b': {1, 2}} + sage: bij.possible_values(p=["a", "b"]) + {'a': {1, 2}, 'b': {1, 2}} + sage: bij.possible_values(p=[["a", "b"]]) + {'a': {1, 2}, 'b': {1, 2}} + sage: bij.possible_values(p=[["a", "b"], ["c"]]) + {'a': {1, 2}, 'b': {1, 2}, 'c': {1, 2}} + + Test an unfeasible problem:: + + sage: A = B = 'ab' + sage: bij = Bijectionist(A, B, lambda x: B.index(x) % 2) + sage: bij.set_constant_blocks([['a', 'b']]) + sage: bij.possible_values(p="a") + {'a': {0, 1}, 'b': {0, 1}} + sage: bij.possible_values(p="a", optimal=True) + {'a': set(), 'b': set()} + + """ + # convert input to set of block representatives + blocks = set() + if p in self._A: + blocks.add(self._P.find(p)) + elif type(p) is list: # TODO: this looks very brittle + for p1 in p: + if p1 in self._A: + blocks.add(self._P.find(p1)) + elif type(p1) is list: + for p2 in p1: + blocks.add(self._P.find(p2)) + + if optimal: + if self._bmilp is None: + self._bmilp = _BijectionistMILP(self) + bmilp = self._bmilp + solutions = defaultdict(set) + try: + solution = next(bmilp.solutions_iterator(True, [])) + except StopIteration: + pass + else: + for p, z in solution.items(): + solutions[p].add(z) + for p in blocks: + tmp_constraints = [bmilp._x[p, z] == 0 for z in solutions[p]] + while True: + try: + solution = next(bmilp.solutions_iterator(True, tmp_constraints)) + except StopIteration: + break + for p0, z in solution.items(): + solutions[p0].add(z) + # veto new value and try again + tmp_constraints.append(bmilp._x[p, solution[p]] == 0) + + # create dictionary to return + possible_values = {} + for p in blocks: + for a in self._P.root_to_elements_dict()[p]: + if optimal: + possible_values[a] = solutions[p] + else: + possible_values[a] = self._possible_block_values[p] + + return possible_values + + def minimal_subdistributions_iterator(self): + r""" + Return all minimal subsets `\tilde A` of `A` + together with submultisets `\tilde Z` with `s(\tilde A) = + \tilde Z` as multisets. + + EXAMPLES:: + + sage: A = B = [permutation for n in range(3) for permutation in Permutations(n)] + sage: bij = Bijectionist(A, B, len) + sage: bij.set_statistics((len, len)) + sage: for sol in bij.solutions_iterator(): + ....: print(sol) + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 2} + sage: sorted(bij.minimal_subdistributions_iterator()) + [([[]], [0]), ([[1]], [1]), ([[1, 2]], [2]), ([[2, 1]], [2])] + + Another example:: + + sage: N = 2; A = B = [dyck_word for n in range(N+1) for dyck_word in DyckWords(n)] + sage: def tau(D): return D.number_of_touch_points() + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((lambda d: d.semilength(), lambda d: d.semilength())) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1, 0]: 1, [1, 0, 1, 0]: 1, [1, 1, 0, 0]: 2} + {[]: 0, [1, 0]: 1, [1, 0, 1, 0]: 2, [1, 1, 0, 0]: 1} + sage: for subdistribution in bij.minimal_subdistributions_iterator(): + ....: print(subdistribution) + ([[]], [0]) + ([[1, 0]], [1]) + ([[1, 0, 1, 0], [1, 1, 0, 0]], [1, 2]) + + An example with two elements of the same block in a subdistribution:: + + sage: A = B = ["a", "b", "c", "d", "e"] + sage: tau = {"a": 1, "b": 1, "c": 2, "d": 2, "e": 3}.get + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_constant_blocks([["a", "b"]]) + sage: bij.set_value_restrictions(("a", [1, 2])) + sage: bij.constant_blocks(optimal=True) + {{'a', 'b'}} + sage: list(bij.minimal_subdistributions_iterator()) + [(['a', 'b', 'c', 'd', 'e'], [1, 1, 2, 2, 3])] + """ + # see + # https://mathoverflow.net/questions/406751/find-a-subdistribution/406975 + # and + # https://gitlab.com/mantepse/bijection-tools/-/issues/29 + + minimal_subdistribution = MixedIntegerLinearProgram(maximization=False, solver=self._solver) + D = minimal_subdistribution.new_variable(binary=True) # the subset of elements + V = minimal_subdistribution.new_variable(integer=True) # the subdistribution + minimal_subdistribution.set_objective(sum(D[a] for a in self._A)) + minimal_subdistribution.add_constraint(sum(D[a] for a in self._A) >= 1) + + if self._bmilp is None: + self._bmilp = _BijectionistMILP(self) + s = next(self._bmilp.solutions_iterator(False, [])) + while True: + for v in self._Z: + minimal_subdistribution.add_constraint(sum(D[a] for a in self._A if s[a] == v) == V[v]) + try: + minimal_subdistribution.solve() + except MIPSolverException: + return + d = minimal_subdistribution.get_values(D, convert=bool, tolerance=0.1) # a dict from A to {0, 1} + new_s = self._find_counterexample(self._A, s, d, False) + if new_s is None: + values = self._sorter["Z"](s[a] for a in self._A if d[a]) + yield ([a for a in self._A if d[a]], values) + + # get all variables with value 1 + active_vars = [D[a] for a in self._A + if minimal_subdistribution.get_values(D[a], convert=bool, tolerance=0.1)] + + # add constraint that not all of these can be 1, thus vetoing + # the current solution + minimal_subdistribution.add_constraint(sum(active_vars) <= len(active_vars) - 1, + name="veto") + else: + s = new_s + + def _find_counterexample(self, P, s0, d, on_blocks): + r""" + Return a solution `s` such that ``d`` is not a subdistribution of + `s0`. + + INPUT: + + - ``P`` -- the representatives of the blocks, or `A` if + ``on_blocks`` is ``False`` + + - ``s0`` -- a solution + + - ``d`` -- a subset of `A`, in the form of a dict from `A` to + `\{0, 1\}` + + - ``on_blocks`` -- whether to return the counterexample on + blocks or on elements + + EXAMPLES:: + + sage: A = B = ["a", "b", "c", "d", "e"] + sage: tau = {"a": 1, "b": 1, "c": 2, "d": 2, "e": 3}.get + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_constant_blocks([["a", "b"]]) + sage: bij.set_value_restrictions(("a", [1, 2])) + sage: next(bij.solutions_iterator()) + {'a': 1, 'b': 1, 'c': 2, 'd': 3, 'e': 2} + + sage: s0 = {'a': 1, 'b': 1, 'c': 2, 'd': 3, 'e': 2} + sage: d = {'a': 1, 'b': 0, 'c': 0, 'd': 0, 'e': 0} + sage: bij._find_counterexample(bij._A, s0, d, False) + {'a': 2, 'b': 2, 'c': 1, 'd': 3, 'e': 1} + + """ + bmilp = self._bmilp + for z in self._Z: + z_in_d_count = sum(d[p] for p in P if s0[p] == z) + if not z_in_d_count: + continue + + # try to find a solution which has a different + # subdistribution on d than s0 + z_in_d = sum(d[p] * bmilp._x[self._P.find(p), z] + for p in P + if z in self._possible_block_values[self._P.find(p)]) + + # it is sufficient to require that z occurs less often as + # a value among {a | d[a] == 1} than it does in + # z_in_d_count, because, if the distributions are + # different, one such z must exist + tmp_constraints = [z_in_d <= z_in_d_count - 1] + try: + solution = next(bmilp.solutions_iterator(on_blocks, tmp_constraints)) + return solution + except StopIteration: + pass + + def minimal_subdistributions_blocks_iterator(self): + r""" + Return all representatives of minimal subsets `\tilde P` + of `P` together with submultisets `\tilde Z` + with `s(\tilde P) = \tilde Z` as multisets. + + .. WARNING:: + + If there are several solutions with the same support + (i.e., the sets of block representatives are the same), + only one of these will be found, even if the + distributions are different, see the doctest below. To + find all solutions, use + :meth:`minimal_subdistributions_iterator`, which is, + however, computationally more expensive. + + EXAMPLES:: + + sage: A = B = [permutation for n in range(3) for permutation in Permutations(n)] + sage: bij = Bijectionist(A, B, len) + sage: bij.set_statistics((len, len)) + sage: for sol in bij.solutions_iterator(): + ....: print(sol) + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 2} + sage: sorted(bij.minimal_subdistributions_blocks_iterator()) + [([[]], [0]), ([[1]], [1]), ([[1, 2]], [2]), ([[2, 1]], [2])] + + Another example:: + + sage: N = 2; A = B = [dyck_word for n in range(N+1) for dyck_word in DyckWords(n)] + sage: def tau(D): return D.number_of_touch_points() + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_statistics((lambda d: d.semilength(), lambda d: d.semilength())) + sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))): + ....: print(solution) + {[]: 0, [1, 0]: 1, [1, 0, 1, 0]: 1, [1, 1, 0, 0]: 2} + {[]: 0, [1, 0]: 1, [1, 0, 1, 0]: 2, [1, 1, 0, 0]: 1} + sage: for subdistribution in bij.minimal_subdistributions_blocks_iterator(): + ....: print(subdistribution) + ([[]], [0]) + ([[1, 0]], [1]) + ([[1, 0, 1, 0], [1, 1, 0, 0]], [1, 2]) + + An example with two elements of the same block in a subdistribution:: + + sage: A = B = ["a", "b", "c", "d", "e"] + sage: tau = {"a": 1, "b": 1, "c": 2, "d": 2, "e": 3}.get + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_constant_blocks([["a", "b"]]) + sage: bij.set_value_restrictions(("a", [1, 2])) + sage: bij.constant_blocks(optimal=True) + {{'a', 'b'}} + sage: list(bij.minimal_subdistributions_blocks_iterator()) + [(['b', 'b', 'c', 'd', 'e'], [1, 1, 2, 2, 3])] + + An example with overlapping minimal subdistributions:: + + sage: A = B = ["a", "b", "c", "d", "e"] + sage: tau = {"a": 1, "b": 1, "c": 2, "d": 2, "e": 3}.get + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_distributions((["a", "b"], [1, 2]), (["a", "c", "d"], [1, 2, 3])) + sage: sorted(bij.solutions_iterator(), key=lambda d: tuple(sorted(d.items()))) + [{'a': 1, 'b': 2, 'c': 2, 'd': 3, 'e': 1}, + {'a': 1, 'b': 2, 'c': 3, 'd': 2, 'e': 1}, + {'a': 2, 'b': 1, 'c': 1, 'd': 3, 'e': 2}, + {'a': 2, 'b': 1, 'c': 3, 'd': 1, 'e': 2}] + sage: bij.constant_blocks(optimal=True) + {{'a', 'e'}} + sage: list(bij.minimal_subdistributions_blocks_iterator()) + [(['a', 'b'], [1, 2]), (['a', 'c', 'd'], [1, 2, 3])] + + Fedor Petrov's example from https://mathoverflow.net/q/424187:: + + sage: A = B = ["a"+str(i) for i in range(1, 9)] + ["b"+str(i) for i in range(3, 9)] + ["d"] + sage: tau = {b: 0 if i < 10 else 1 for i, b in enumerate(B)}.get + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_constant_blocks([["a"+str(i), "b"+str(i)] for i in range(1, 9) if "b"+str(i) in A]) + sage: d = [0]*8+[1]*4 + sage: bij.set_distributions((A[:8] + A[8+2:-1], d), (A[:8] + A[8:-3], d)) + sage: sorted([s[a] for a in A] for s in bij.solutions_iterator()) + [[0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1], + [0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0], + [0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0], + [0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0], + [1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0], + [1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0], + [1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0], + [1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0], + [1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1], + [1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1]] + + sage: sorted(bij.minimal_subdistributions_blocks_iterator()) # random + [(['a1', 'a2', 'a3', 'a4', 'a5', 'a5', 'a6', 'a6', 'a7', 'a7', 'a8', 'a8'], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]), + (['a3', 'a4', 'd'], [0, 0, 1]), + (['a7', 'a8', 'd'], [0, 0, 1])] + + The following solution is not found, because it happens to + have the same support as the other:: + + sage: D = set(A).difference(['b7', 'b8', 'd']) + sage: sorted(a.replace("b", "a") for a in D) + ['a1', 'a2', 'a3', 'a3', 'a4', 'a4', 'a5', 'a5', 'a6', 'a6', 'a7', 'a8'] + sage: set(tuple(sorted(s[a] for a in D)) for s in bij.solutions_iterator()) + {(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1)} + + But it is, by design, included here:: + + sage: sorted(D) in [d for d, _ in bij.minimal_subdistributions_iterator()] + True + + """ + # see + # https://mathoverflow.net/questions/406751/find-a-subdistribution/406975 + # and + # https://gitlab.com/mantepse/bijection-tools/-/issues/29 + # see https://mathoverflow.net/q/424187 for Fedor Petrov's example + + minimal_subdistribution = MixedIntegerLinearProgram(maximization=False, solver=self._solver) + D = minimal_subdistribution.new_variable(integer=True, nonnegative=True) # the submultiset of elements + X = minimal_subdistribution.new_variable(binary=True) # the support of D + V = minimal_subdistribution.new_variable(integer=True, nonnegative=True) # the subdistribution + P = _disjoint_set_roots(self._P) + minimal_subdistribution.set_objective(sum(D[p] for p in P)) + minimal_subdistribution.add_constraint(sum(D[p] for p in P) >= 1) + for p in P: + minimal_subdistribution.add_constraint(D[p] <= len(self._P.root_to_elements_dict()[p])) + minimal_subdistribution.add_constraint(X[p]*len(self._P.root_to_elements_dict()[p]) >= D[p] >= X[p]) + + def add_counter_example_constraint(s): + for v in self._Z: + minimal_subdistribution.add_constraint(sum(D[p] for p in P + if s[p] == v) == V[v]) + + if self._bmilp is None: + self._bmilp = _BijectionistMILP(self) + + s = next(self._bmilp.solutions_iterator(True, [])) + add_counter_example_constraint(s) + while True: + try: + minimal_subdistribution.solve() + except MIPSolverException: + return + d = minimal_subdistribution.get_values(D, convert=ZZ, tolerance=0.1) # a dict from P to multiplicities + new_s = self._find_counterexample(P, s, d, True) + if new_s is None: + yield ([p for p in P for _ in range(ZZ(d[p]))], + self._sorter["Z"](s[p] + for p in P + for _ in range(ZZ(d[p])))) + + support = [X[p] for p in P if d[p]] + # add constraint that the support is different + minimal_subdistribution.add_constraint(sum(support) <= len(support) - 1, + name="veto") + else: + s = new_s + add_counter_example_constraint(s) + + def _preprocess_intertwining_relations(self): + r""" + Make ``self._P`` be the finest set partition coarser + than ``self._P`` such that composing elements preserves + blocks. + + Suppose that `p_1`, `p_2` are blocks of `P`, and `a_1, a'_1 + \in p_1` and `a_2, a'_2\in p_2`. Then, + + .. MATH: + + s(\pi(a_1, a_2)) + = \rho(s(a_1), s(a_2)) + = \rho(s(a'_1), s(a'_2)) + = s(\pi(a'_1, a'_2)). + + Therefore, `\pi(a_1, a_2)` and `\pi(a'_1, a'_2)` are in the + same block. + + In other words, `s(\pi(a_1,\dots,a_k))` only depends on the + blocks of `a_1,\dots,a_k`. + + In particular, if `P` consists only if singletons, this + method has no effect. + + .. TODO:: + + create one test with one and one test with two + intertwining relations + + .. TODO:: + + it is not clear whether this method makes sense + + EXAMPLES:: + + sage: A = B = 'abcd' + sage: bij = Bijectionist(A, B, lambda x: B.index(x) % 2) + sage: def pi(p1, p2): return 'abcdefgh'[A.index(p1) + A.index(p2)] + sage: def rho(s1, s2): return (s1 + s2) % 2 + sage: bij.set_intertwining_relations((2, pi, rho)) + sage: bij._preprocess_intertwining_relations() + sage: bij._P + {{'a'}, {'b'}, {'c'}, {'d'}} + + Let a group act on permutations:: + + sage: A = B = Permutations(3) + sage: bij = Bijectionist(A, B, lambda x: x[0]) + sage: bij.set_intertwining_relations((1, lambda pi: pi.reverse(), lambda z: z)) + sage: bij._preprocess_intertwining_relations() + sage: bij._P + {{[1, 2, 3]}, {[1, 3, 2]}, {[2, 1, 3]}, {[2, 3, 1]}, {[3, 1, 2]}, {[3, 2, 1]}} + + """ + A = self._A + P = self._P + images = defaultdict(set) # A^k -> A, a_1,...,a_k +-> {pi(a_1,...,a_k) for all pi} + for pi_rho in self._pi_rho: + for a_tuple in itertools.product(*([A]*pi_rho.numargs)): + if pi_rho.domain is not None and not pi_rho.domain(*a_tuple): + continue + a = pi_rho.pi(*a_tuple) + if a in A: + images[a_tuple].add(a) + + # merge blocks + something_changed = True + while something_changed: + something_changed = False + # collect (preimage, image) pairs by (representatives) of + # the blocks of the elements of the preimage + updated_images = defaultdict(set) # (p_1,...,p_k) to {a_1,....} + for a_tuple, image_set in images.items(): + representatives = tuple(P.find(a) for a in a_tuple) + updated_images[representatives].update(image_set) + + # merge blocks + for a_tuple, image_set in updated_images.items(): + image = image_set.pop() + while image_set: + P.union(image, image_set.pop()) + something_changed = True + # we keep a representative + image_set.add(image) + + images = updated_images + + def solutions_iterator(self): + r""" + An iterator over all solutions of the problem. + + OUTPUT: An iterator over all possible mappings `s: A\to Z` + + ALGORITHM: + + We solve an integer linear program with a binary variable + `x_{p, z}` for each partition block `p\in P` and each + statistic value `z\in Z`: + + - `x_{p, z} = 1` if and only if `s(a) = z` for all `a\in p`. + + Then we add the constraint `\sum_{x\in V} x<|V|`, where `V` + is the set containing all `x` with `x = 1`, that is, those + indicator variables representing the current solution. + Therefore, a solution of this new program must be different + from all those previously obtained. + + INTEGER LINEAR PROGRAM: + + * Let `m_w(p)`, for a block `p` of `P`, be the multiplicity + of the value `w` in `W` under `\alpha`, that is, the number + of elements `a \in p` with `\alpha(a)=w`. + + * Let `n_w(z)` be the number of elements `b \in B` with + `\beta(b)=w` and `\tau(b)=z` for `w \in W`, `z \in Z`. + + * Let `k` be the arity of a pair `(\pi, \rho)` in an + intertwining relation. + + and the following constraints: + + * because every block is assigned precisely one value, for + all `p\in P`, + + .. MATH:: + + \sum_z x_{p, z} = 1. + + * because the statistics `s` and `\tau` and also `\alpha` and + `\beta` are equidistributed, for all `w\in W` and `z\in Z`, + + .. MATH:: + + \sum_p m_w(p) x_{p, z} = n_w(z). + + * for each intertwining relation `s(\pi(a_1,\dots, a_k)) = + \rho(s(a_1),\dots, s(a_r))`, and for all `k`-combinations + of blocks `p_i\in P` such that there exist `(a_1,\dots, + a_k)\in p_1\times\dots\times p_k` with `\pi(a_1,\dots, + a_k)\in W` and `z = \rho(z_1,\dots, z_k)`, + + .. MATH:: + + x_{p, z} \geq 1-k + \sum_{i=1}^k x_{p_i, z_i}. + + * for each distribution restriction, i.e. a set of elements + `\tilde A` and a distribution of values given by integers + `d_z` representing the multiplicity of each `z \in Z`, and + `r_p = |p \cap\tilde A|` indicating the relative size of + block `p` in the set of elements of the distribution, + + .. MATH:: + + \sum_p r_p x_{p, z} = d_z. + + EXAMPLES:: + + sage: A = B = 'abc' + sage: bij = Bijectionist(A, B, lambda x: B.index(x) % 2, solver="GLPK") + sage: next(bij.solutions_iterator()) + {'a': 0, 'b': 1, 'c': 0} + + sage: list(bij.solutions_iterator()) + [{'a': 0, 'b': 1, 'c': 0}, + {'a': 1, 'b': 0, 'c': 0}, + {'a': 0, 'b': 0, 'c': 1}] + + sage: N = 4 + sage: A = B = [permutation for n in range(N) for permutation in Permutations(n)] + + Let `\tau` be the number of non-left-to-right-maxima of a + permutation:: + + sage: def tau(pi): + ....: pi = list(pi) + ....: i = count = 0 + ....: for j in range(len(pi)): + ....: if pi[j] > i: + ....: i = pi[j] + ....: else: + ....: count += 1 + ....: return count + + We look for a statistic which is constant on conjugacy classes:: + + sage: P = [list(a) for n in range(N) for a in Permutations(n).conjugacy_classes()] + + sage: bij = Bijectionist(A, B, tau, solver="GLPK") + sage: bij.set_statistics((len, len)) + sage: bij.set_constant_blocks(P) + sage: for solution in bij.solutions_iterator(): + ....: print(solution) + {[]: 0, [1]: 0, [1, 2]: 1, [2, 1]: 0, [1, 2, 3]: 0, [1, 3, 2]: 1, [2, 1, 3]: 1, [3, 2, 1]: 1, [2, 3, 1]: 2, [3, 1, 2]: 2} + {[]: 0, [1]: 0, [1, 2]: 0, [2, 1]: 1, [1, 2, 3]: 0, [1, 3, 2]: 1, [2, 1, 3]: 1, [3, 2, 1]: 1, [2, 3, 1]: 2, [3, 1, 2]: 2} + + Changing or re-setting problem parameters clears the internal + cache. Setting the verbosity prints the MILP which is solved.:: + + sage: set_verbose(2) + sage: bij.set_constant_blocks(P) + sage: _ = list(bij.solutions_iterator()) + Constraints are: + block []: 1 <= x_0 <= 1 + block [1]: 1 <= x_1 <= 1 + block [1, 2]: 1 <= x_2 + x_3 <= 1 + block [2, 1]: 1 <= x_4 + x_5 <= 1 + block [1, 2, 3]: 1 <= x_6 + x_7 + x_8 <= 1 + block [1, 3, 2]: 1 <= x_9 + x_10 + x_11 <= 1 + block [2, 3, 1]: 1 <= x_12 + x_13 + x_14 <= 1 + statistics: 1 <= x_0 <= 1 + statistics: 0 <= <= 0 + statistics: 0 <= <= 0 + statistics: 1 <= x_1 <= 1 + statistics: 0 <= <= 0 + statistics: 0 <= <= 0 + statistics: 1 <= x_2 + x_4 <= 1 + statistics: 1 <= x_3 + x_5 <= 1 + statistics: 0 <= <= 0 + statistics: 1 <= x_6 + 3 x_9 + 2 x_12 <= 1 + statistics: 3 <= x_7 + 3 x_10 + 2 x_13 <= 3 + statistics: 2 <= x_8 + 3 x_11 + 2 x_14 <= 2 + Variables are: + x_0: s([]) = 0 + x_1: s([1]) = 0 + x_2: s([1, 2]) = 0 + x_3: s([1, 2]) = 1 + x_4: s([2, 1]) = 0 + x_5: s([2, 1]) = 1 + x_6: s([1, 2, 3]) = 0 + x_7: s([1, 2, 3]) = 1 + x_8: s([1, 2, 3]) = 2 + x_9: s([1, 3, 2]) = s([2, 1, 3]) = s([3, 2, 1]) = 0 + x_10: s([1, 3, 2]) = s([2, 1, 3]) = s([3, 2, 1]) = 1 + x_11: s([1, 3, 2]) = s([2, 1, 3]) = s([3, 2, 1]) = 2 + x_12: s([2, 3, 1]) = s([3, 1, 2]) = 0 + x_13: s([2, 3, 1]) = s([3, 1, 2]) = 1 + x_14: s([2, 3, 1]) = s([3, 1, 2]) = 2 + after vetoing + Constraints are: + block []: 1 <= x_0 <= 1 + block [1]: 1 <= x_1 <= 1 + block [1, 2]: 1 <= x_2 + x_3 <= 1 + block [2, 1]: 1 <= x_4 + x_5 <= 1 + block [1, 2, 3]: 1 <= x_6 + x_7 + x_8 <= 1 + block [1, 3, 2]: 1 <= x_9 + x_10 + x_11 <= 1 + block [2, 3, 1]: 1 <= x_12 + x_13 + x_14 <= 1 + statistics: 1 <= x_0 <= 1 + statistics: 0 <= <= 0 + statistics: 0 <= <= 0 + statistics: 1 <= x_1 <= 1 + statistics: 0 <= <= 0 + statistics: 0 <= <= 0 + statistics: 1 <= x_2 + x_4 <= 1 + statistics: 1 <= x_3 + x_5 <= 1 + statistics: 0 <= <= 0 + statistics: 1 <= x_6 + 3 x_9 + 2 x_12 <= 1 + statistics: 3 <= x_7 + 3 x_10 + 2 x_13 <= 3 + statistics: 2 <= x_8 + 3 x_11 + 2 x_14 <= 2 + veto: x_0 + x_1 + x_3 + x_4 + x_6 + x_10 + x_14 <= 6 + after vetoing + Constraints are: + block []: 1 <= x_0 <= 1 + block [1]: 1 <= x_1 <= 1 + block [1, 2]: 1 <= x_2 + x_3 <= 1 + block [2, 1]: 1 <= x_4 + x_5 <= 1 + block [1, 2, 3]: 1 <= x_6 + x_7 + x_8 <= 1 + block [1, 3, 2]: 1 <= x_9 + x_10 + x_11 <= 1 + block [2, 3, 1]: 1 <= x_12 + x_13 + x_14 <= 1 + statistics: 1 <= x_0 <= 1 + statistics: 0 <= <= 0 + statistics: 0 <= <= 0 + statistics: 1 <= x_1 <= 1 + statistics: 0 <= <= 0 + statistics: 0 <= <= 0 + statistics: 1 <= x_2 + x_4 <= 1 + statistics: 1 <= x_3 + x_5 <= 1 + statistics: 0 <= <= 0 + statistics: 1 <= x_6 + 3 x_9 + 2 x_12 <= 1 + statistics: 3 <= x_7 + 3 x_10 + 2 x_13 <= 3 + statistics: 2 <= x_8 + 3 x_11 + 2 x_14 <= 2 + veto: x_0 + x_1 + x_3 + x_4 + x_6 + x_10 + x_14 <= 6 + veto: x_0 + x_1 + x_2 + x_5 + x_6 + x_10 + x_14 <= 6 + + sage: set_verbose(0) + + TESTS: + + An unfeasible problem:: + + sage: A = ["a", "b", "c", "d"]; B = [1, 2, 3, 4] + sage: bij = Bijectionist(A, B) + sage: bij.set_value_restrictions(("a", [1, 2]), ("b", [1, 2]), ("c", [1, 3]), ("d", [2, 3])) + sage: list(bij.solutions_iterator()) + [] + + Testing interactions between multiple instances using Fedor Petrov's example from https://mathoverflow.net/q/424187:: + + sage: A = B = ["a"+str(i) for i in range(1, 9)] + ["b"+str(i) for i in range(3, 9)] + ["d"] + sage: tau = {b: 0 if i < 10 else 1 for i, b in enumerate(B)}.get + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_constant_blocks([["a"+str(i), "b"+str(i)] for i in range(1, 9) if "b"+str(i) in A]) + sage: d = [0]*8+[1]*4 + sage: bij.set_distributions((A[:8] + A[8+2:-1], d), (A[:8] + A[8:-3], d)) + sage: iterator1 = bij.solutions_iterator() + sage: iterator2 = bij.solutions_iterator() + + Generate a solution in iterator1, iterator2 should generate the same solution and vice versa:: + + sage: s1_1 = next(iterator1) + sage: s2_1 = next(iterator2) + sage: s1_1 == s2_1 + True + sage: s2_2 = next(iterator2) + sage: s1_2 = next(iterator1) + sage: s1_2 == s2_2 + True + + Re-setting the distribution resets the cache, so a new + iterator will generate the first solutions again, but the old + iterator continues:: + + sage: bij.set_distributions((A[:8] + A[8+2:-1], d), (A[:8] + A[8:-3], d)) + sage: iterator3 = bij.solutions_iterator() + + sage: s3_1 = next(iterator3) + sage: s1_1 == s3_1 + True + + sage: s1_3 = next(iterator1) + sage: len(set([tuple(sorted(s.items())) for s in [s1_1, s1_2, s1_3]])) + 3 + + """ + if self._bmilp is None: + self._bmilp = _BijectionistMILP(self) + yield from self._bmilp.solutions_iterator(False, []) + + +class _BijectionistMILP(): + r""" + Wrapper class for the MixedIntegerLinearProgram (MILP). + + This class is used to manage the MILP, add constraints, solve the + problem and check for uniqueness of solution values. + """ + def __init__(self, bijectionist: Bijectionist, solutions=None): + r""" + Initialize the mixed integer linear program. + + INPUT: + + - ``bijectionist`` -- an instance of :class:`Bijectionist`. + + - ``solutions`` -- (optional) a list of solutions of the + problem, each provided as a dictionary mapping `(a, z)` to + a boolean, such that at least one element from each block + of `P` appears as `a`. + + .. TODO:: + + it might be cleaner not to pass the full bijectionist + instance, but only those attributes we actually use + + TESTS:: + + sage: A = B = ["a", "b", "c", "d"] + sage: bij = Bijectionist(A, B) + sage: from sage.combinat.bijectionist import _BijectionistMILP + sage: _BijectionistMILP(bij) + <sage.combinat.bijectionist._BijectionistMILP object at ...> + + """ + # the attributes of the bijectionist class we actually use: + # _possible_block_values + # _elements_distributions + # _W, _Z, _A, _B, _P, _alpha, _beta, _tau, _pi_rho, _phi_psi + self._bijectionist = bijectionist + # the variables of the MILP are indexed by pairs (p, z), for + # p in _P and z an element of _posible_block_values[p]. + # Thus, _P and _posible_block_values have to be fixed before + # creating the MILP. + bijectionist._preprocess_intertwining_relations() + bijectionist._compute_possible_block_values() + + self.milp = MixedIntegerLinearProgram(solver=bijectionist._solver) + self.milp.set_objective(None) + indices = [(p, z) + for p, tZ in bijectionist._possible_block_values.items() + for z in tZ] + self._x = self.milp.new_variable(binary=True, indices=indices) + + tZ = bijectionist._possible_block_values + P = bijectionist._P + for p in _disjoint_set_roots(P): + self.milp.add_constraint(sum(self._x[p, z] for z in tZ[p]) == 1, + name=f"block {p}"[:50]) + self.add_alpha_beta_constraints() + self.add_distribution_constraints() + self.add_quadratic_relation_constraints() + self.add_homomesic_constraints() + self.add_intertwining_relation_constraints() + if get_verbose() >= 2: + self.show() + + self._solution_cache = [] + if solutions is not None: + for solution in solutions: + self._add_solution({(P.find(a), z): value + for (a, z), value in solution.items()}) + + def show(self, variables=True): + r""" + Print the constraints and variables of the MILP together + with some explanations. + + EXAMPLES:: + + sage: A = B = ["a", "b", "c"] + sage: bij = Bijectionist(A, B, lambda x: A.index(x) % 2, solver="GLPK") + sage: bij.set_constant_blocks([["a", "b"]]) + sage: next(bij.solutions_iterator()) + {'a': 0, 'b': 0, 'c': 1} + sage: bij._bmilp.show() + Constraints are: + block a: 1 <= x_0 + x_1 <= 1 + block c: 1 <= x_2 + x_3 <= 1 + statistics: 2 <= 2 x_0 + x_2 <= 2 + statistics: 1 <= 2 x_1 + x_3 <= 1 + veto: x_0 + x_3 <= 1 + Variables are: + x_0: s(a) = s(b) = 0 + x_1: s(a) = s(b) = 1 + x_2: s(c) = 0 + x_3: s(c) = 1 + + """ + print("Constraints are:") + b = self.milp.get_backend() + varid_name = {} + for i in range(b.ncols()): + s = b.col_name(i) + default_name = str(self.milp.linear_functions_parent()({i: 1})) + if s and s != default_name: + varid_name[i] = s + else: + varid_name[i] = default_name + for i, (lb, (indices, values), ub) in enumerate(self.milp.constraints()): + if b.row_name(i): + print(" "+b.row_name(i)+":", end=" ") + if lb is not None: + print(str(ZZ(lb))+" <=", end=" ") + first = True + for j, c in sorted(zip(indices, values)): + c = ZZ(c) + if c == 0: + continue + print((("+ " if (not first and c > 0) else "") + + ("" if c == 1 else + ("- " if c == -1 else + (str(c) + " " if first and c < 0 else + ("- " + str(abs(c)) + " " if c < 0 else str(c) + " ")))) + + varid_name[j]), end=" ") + first = False + # Upper bound + print("<= "+str(ZZ(ub)) if ub is not None else "") + + if variables: + print("Variables are:") + P = self._bijectionist._P.root_to_elements_dict() + for (p, z), v in self._x.items(): + print(f" {v}: " + "".join([f"s({a}) = " + for a in P[p]]) + f"{z}") + + def _prepare_solution(self, on_blocks, solution): + r""" + Return the solution as a dictionary from `A` (or `P`) to + `Z`. + + INPUT: + + - ``on_blocks`` -- whether to return the solution on blocks + or on all elements + + TESTS:: + + sage: A = B = ["a", "b", "c"] + sage: bij = Bijectionist(A, B, lambda x: 0) + sage: bij.set_constant_blocks([["a", "b"]]) + sage: next(bij.solutions_iterator()) + {'a': 0, 'b': 0, 'c': 0} + sage: bmilp = bij._bmilp + sage: bmilp._prepare_solution(True, bmilp._solution_cache[0]) + {'a': 0, 'c': 0} + + """ + P = self._bijectionist._P + tZ = self._bijectionist._possible_block_values + mapping = {} # A -> Z or P -> Z, a +-> s(a) + for p, block in P.root_to_elements_dict().items(): + for z in tZ[p]: + if solution[p, z] == 1: + if on_blocks: + mapping[p] = z + else: + for a in block: + mapping[a] = z + break + return mapping + + def solutions_iterator(self, on_blocks, additional_constraints): + r""" + Iterate over all solutions satisfying the additional constraints. + + INPUT: + + - ``additional_constraints`` -- a list of constraints for the + underlying MILP + + - ``on_blocks``, whether to return the solution on blocks or + on all elements + + TESTS:: + + sage: A = B = 'abc' + sage: bij = Bijectionist(A, B, lambda x: B.index(x) % 2, solver="GLPK") + sage: from sage.combinat.bijectionist import _BijectionistMILP + sage: bmilp = _BijectionistMILP(bij) + sage: it = bmilp.solutions_iterator(False, []) + sage: it2 = bmilp.solutions_iterator(False, [bmilp._x[('c', 1)] == 1]) + sage: next(it) + {'a': 0, 'b': 1, 'c': 0} + sage: next(it2) + {'a': 0, 'b': 0, 'c': 1} + sage: next(it) + {'a': 0, 'b': 0, 'c': 1} + sage: next(it) + {'a': 1, 'b': 0, 'c': 0} + + """ + i = 0 # the first unconsidered element of _solution_cache + while True: + # skip solutions which do not satisfy additional_constraints + while i < len(self._solution_cache): + solution = self._solution_cache[i] + i += 1 + if all(self._is_solution(constraint, solution) + for constraint in additional_constraints): + yield self._prepare_solution(on_blocks, solution) + break + else: + new_indices = [] + for constraint in additional_constraints: + new_indices.extend(self.milp.add_constraint(constraint, + return_indices=True)) + try: + self.milp.solve() + # moving this out of the try...finally block breaks SCIP + solution = self.milp.get_values(self._x, + convert=bool, tolerance=0.1) + except MIPSolverException: + return + finally: + b = self.milp.get_backend() + if hasattr(b, "_get_model"): + m = b._get_model() + if m.getStatus() != 'unknown': + m.freeTransform() + self.milp.remove_constraints(new_indices) + + self._add_solution(solution) + i += 1 + assert i == len(self._solution_cache) + yield self._prepare_solution(on_blocks, solution) + if get_verbose() >= 2: + print("after vetoing") + self.show(variables=False) + + def _add_solution(self, solution): + r""" + Add the ``solution`` to the cache and an appropriate + veto constraint to the MILP. + + INPUT: + + - ``solution`` -- a dictionary from the indices of the MILP to + a boolean + + EXAMPLES:: + + sage: A = B = ["a", "b"] + sage: bij = Bijectionist(A, B) + sage: from sage.combinat.bijectionist import _BijectionistMILP + sage: bmilp = _BijectionistMILP(bij) + sage: bmilp._add_solution({(a, b): a == b for a in A for b in B}) + sage: bmilp.show() # random + Constraints are: + block a: 1 <= x_0 + x_1 <= 1 + block b: 1 <= x_2 + x_3 <= 1 + statistics: 1 <= x_1 + x_3 <= 1 + statistics: 1 <= x_0 + x_2 <= 1 + veto: x_1 + x_2 <= 1 + Variables are: + x_0: s(a) = b + x_1: s(a) = a + x_2: s(b) = b + x_3: s(b) = a + + """ + active_vars = [self._x[p, z] + for p in _disjoint_set_roots(self._bijectionist._P) + for z in self._bijectionist._possible_block_values[p] + if solution[(p, z)]] + self.milp.add_constraint(sum(active_vars) <= len(active_vars) - 1, + name="veto") + self._solution_cache.append(solution) + + def _is_solution(self, constraint, values): + r""" + Evaluate the given function at the given values. + + INPUT: + + - ``constraint`` -- a + :class:`sage.numerical.linear_functions.LinearConstraint`. + + - ``values`` -- a candidate for a solution of the MILP as a + dictionary from pairs `(a, z)\in A\times Z` to `0` or `1`, + specifying whether `a` is mapped to `z`. + + EXAMPLES:: + + sage: A = B = ["a", "b"] + sage: bij = Bijectionist(A, B) + sage: from sage.combinat.bijectionist import _BijectionistMILP + sage: bmilp = _BijectionistMILP(bij) + sage: f = bmilp._x["a", "a"] + bmilp._x["b", "a"] >= bmilp._x["b", "b"] + 1 + sage: v = {('a', 'a'): 1, ('a', 'b'): 0, ('b', 'a'): 1, ('b', 'b'): 1} + sage: bmilp._is_solution(f, v) + True + sage: v = {('a', 'a'): 0, ('a', 'b'): 0, ('b', 'a'): 1, ('b', 'b'): 1} + sage: bmilp._is_solution(f, v) + False + """ + index_block_value_dict = {} + for (p, z), v in self._x.items(): + variable_index = next(iter(v.dict())) + index_block_value_dict[variable_index] = (p, z) + + def evaluate(f): + return sum(coeff if index == -1 else + coeff * values[index_block_value_dict[index]] + for index, coeff in f.dict().items()) + + for lhs, rhs in constraint.equations(): + if evaluate(lhs - rhs): + return False + for lhs, rhs in constraint.inequalities(): + if evaluate(lhs - rhs) > 0: + return False + return True + + def add_alpha_beta_constraints(self): + r""" + Add constraints enforcing that `(alpha, s)` is equidistributed + with `(beta, tau)` and `S` is the intertwining bijection. + + We do this by adding + + .. MATH:: + + \sum_{a\in A, z\in Z} x_{p(a), z} s^z t^{\alpha(a)} + = \sum_{b\in B} s^{\tau(b)} t(\beta(b)) + + as a matrix equation. + + EXAMPLES:: + + sage: A = B = [permutation for n in range(3) for permutation in Permutations(n)] + sage: bij = Bijectionist(A, B, len) + sage: bij.set_statistics((len, len)) + sage: from sage.combinat.bijectionist import _BijectionistMILP + sage: bmilp = _BijectionistMILP(bij) # indirect doctest + sage: next(bmilp.solutions_iterator(False, [])) + {[]: 0, [1]: 1, [1, 2]: 2, [2, 1]: 2} + """ + W = self._bijectionist._W + Z = self._bijectionist._Z + zero = self.milp.linear_functions_parent().zero() + AZ_matrix = [[zero] * len(W) for _ in range(len(Z))] + B_matrix = [[zero] * len(W) for _ in range(len(Z))] + + W_dict = {w: i for i, w in enumerate(W)} + Z_dict = {z: i for i, z in enumerate(Z)} + + for a in self._bijectionist._A: + p = self._bijectionist._P.find(a) + for z in self._bijectionist._possible_block_values[p]: + w_index = W_dict[self._bijectionist._alpha(a)] + z_index = Z_dict[z] + AZ_matrix[z_index][w_index] += self._x[p, z] + + for b in self._bijectionist._B: + w_index = W_dict[self._bijectionist._beta(b)] + z_index = Z_dict[self._bijectionist._tau[b]] + B_matrix[z_index][w_index] += 1 + + for w in range(len(W)): + for z in range(len(Z)): + self.milp.add_constraint(AZ_matrix[z][w] == B_matrix[z][w], + name="statistics") + + def add_distribution_constraints(self): + r""" + Add constraints so the distributions given by + :meth:`set_distributions` are fulfilled. + + To accomplish this we add + + .. MATH:: + + \sum_{a\in\tilde A} x_{p(a), z}t^z = \sum_{z\in\tilde Z} t^z, + + where `p(a)` is the block containing `a`, for each given + distribution as a vector equation. + + EXAMPLES:: + + sage: A = B = Permutations(3) + sage: tau = Permutation.longest_increasing_subsequence_length + sage: bij = Bijectionist(A, B, tau) + sage: bij.set_distributions(([Permutation([1, 2, 3]), Permutation([1, 3, 2])], [1, 3])) + sage: from sage.combinat.bijectionist import _BijectionistMILP + sage: bmilp = _BijectionistMILP(bij) # indirect doctest + sage: next(bmilp.solutions_iterator(False, [])) + {[1, 2, 3]: 3, + [1, 3, 2]: 1, + [2, 1, 3]: 2, + [2, 3, 1]: 2, + [3, 1, 2]: 2, + [3, 2, 1]: 2} + + """ + Z = self._bijectionist._Z + Z_dict = {z: i for i, z in enumerate(Z)} + zero = self.milp.linear_functions_parent().zero() + for tA, tZ in self._bijectionist._elements_distributions: + tA_sum = [zero]*len(Z_dict) + tZ_sum = [zero]*len(Z_dict) + for a in tA: + p = self._bijectionist._P.find(a) + for z in self._bijectionist._possible_block_values[p]: + tA_sum[Z_dict[z]] += self._x[p, z] + for z in tZ: + tZ_sum[Z_dict[z]] += 1 + + for a, z in zip(tA_sum, tZ_sum): + self.milp.add_constraint(a == z, name=f"d: {a} == {z}") + + def add_intertwining_relation_constraints(self): + r""" + Add constraints corresponding to the given intertwining + relations. + + INPUT: + + - origins, a list of triples `((\pi/\rho, p, + (p_1,\dots,p_k))`, where `p` is the block of + `\rho(s(a_1),\dots, s(a_k))`, for any `a_i\in p_i`. + + This adds the constraints imposed by + :meth:`set_intertwining_relations`, + + .. MATH:: + + s(\pi(a_1,\dots, a_k)) = \rho(s(a_1),\dots, s(a_k)) + + for each pair `(\pi, \rho)`. The relation implies + immediately that `s(\pi(a_1,\dots, a_k))` only depends on the + blocks of `a_1,\dots, a_k`. + + The MILP formulation is as follows. Let `a_1,\dots,a_k \in + A` and let `a = \pi(a_1,\dots,a_k)`. Let `z_1,\dots,z_k \in + Z` and let `z = \rho(z_1,\dots,z_k)`. Suppose that `a_i\in + p_i` for all `i` and that `a\in p`. + + We then want to model the implication + + .. MATH:: + + x_{p_1, z_1} = 1,\dots, x_{p_k, z_k} = 1 \Rightarrow x_{p, z} = 1. + + We achieve this by requiring + + .. MATH:: + + x_{p, z}\geq 1 - k + \sum_{i=1}^k x_{p_i, z_i}. + + Note that `z` must be a possible value of `p` and each `z_i` + must be a possible value of `p_i`. + + EXAMPLES:: + + sage: A = B = 'abcd' + sage: bij = Bijectionist(A, B, lambda x: B.index(x) % 2) + sage: def pi(p1, p2): return 'abcdefgh'[A.index(p1) + A.index(p2)] + sage: def rho(s1, s2): return (s1 + s2) % 2 + sage: bij.set_intertwining_relations((2, pi, rho)) + sage: from sage.combinat.bijectionist import _BijectionistMILP + sage: bmilp = _BijectionistMILP(bij) # indirect doctest + sage: next(bmilp.solutions_iterator(False, [])) + {'a': 0, 'b': 1, 'c': 0, 'd': 1} + """ + A = self._bijectionist._A + tZ = self._bijectionist._possible_block_values + P = self._bijectionist._P + for composition_index, pi_rho in enumerate(self._bijectionist._pi_rho): + pi_blocks = set() + for a_tuple in itertools.product(A, repeat=pi_rho.numargs): + if pi_rho.domain is not None and not pi_rho.domain(*a_tuple): + continue + a = pi_rho.pi(*a_tuple) + if a in A: + p_tuple = tuple(P.find(a) for a in a_tuple) + p = P.find(a) + if (p_tuple, p) not in pi_blocks: + pi_blocks.add((p_tuple, p)) + for z_tuple in itertools.product(*[tZ[p] for p in p_tuple]): + rhs = (1 - pi_rho.numargs + + sum(self._x[p_i, z_i] + for p_i, z_i in zip(p_tuple, z_tuple))) + z = pi_rho.rho(*z_tuple) + if z in tZ[p]: + c = self._x[p, z] - rhs + if c.is_zero(): + continue + self.milp.add_constraint(c >= 0, + name=f"pi/rho({composition_index})") + else: + self.milp.add_constraint(rhs <= 0, + name=f"pi/rho({composition_index})") + + def add_quadratic_relation_constraints(self): + r""" + Add constraints enforcing that `s\circ\phi\circ s = + \psi`. + + We do this by adding + + .. MATH:: + + x_{p(a), z} = x_{p(\psi(z)), \phi(a)} + + for `a\in A` and `z\in Z`, where `\phi:A\to Z` and `\psi:Z\to + A`. Note that, in particular, `\phi` must be constant on + blocks. + + EXAMPLES:: + + sage: A = B = DyckWords(3) + sage: bij = Bijectionist(A, B) + sage: bij.set_statistics((lambda D: D.number_of_touch_points(), lambda D: D.number_of_initial_rises())) + sage: ascii_art(sorted(bij.minimal_subdistributions_iterator())) + [ ( [ /\ ] ) + [ ( [ / \ ] ) ( [ /\ /\ ] [ /\ /\/\ ] ) + [ ( [ /\/\/\ ], [ / \ ] ), ( [ /\/ \, / \/\ ], [ / \/\, / \ ] ), + <BLANKLINE> + ( [ /\ ] ) ] + ( [ /\/\ / \ ] [ /\ ] ) ] + ( [ / \, / \ ], [ /\/\/\, /\/ \ ] ) ] + sage: bij.set_quadratic_relation((lambda D: D, lambda D: D)) # indirect doctest + sage: ascii_art(sorted(bij.minimal_subdistributions_iterator())) + [ ( [ /\ ] ) + [ ( [ / \ ] ) ( [ /\ ] [ /\/\ ] ) + [ ( [ /\/\/\ ], [ / \ ] ), ( [ /\/ \ ], [ / \ ] ), + <BLANKLINE> + <BLANKLINE> + ( [ /\ ] [ /\ ] ) ( [ /\/\ ] [ /\ ] ) + ( [ / \/\ ], [ / \/\ ] ), ( [ / \ ], [ /\/ \ ] ), + <BLANKLINE> + ( [ /\ ] ) ] + ( [ / \ ] ) ] + ( [ / \ ], [ /\/\/\ ] ) ] + + """ + P = self._bijectionist._P + for phi, psi in self._bijectionist._phi_psi: + for p, block in P.root_to_elements_dict().items(): + z0 = phi(p) + assert all(phi(a) == z0 for a in block), "phi must be constant on the block %s" % block + for z in self._bijectionist._possible_block_values[p]: + p0 = P.find(psi(z)) + if z0 in self._bijectionist._possible_block_values[p0]: + c = self._x[p, z] - self._x[p0, z0] + if c.is_zero(): + continue + self.milp.add_constraint(c == 0, name=f"i: s({p})={z}<->s(psi({z})=phi({p})") + else: + self.milp.add_constraint(self._x[p, z] == 0, name=f"i: s({p})!={z}") + + def add_homomesic_constraints(self): + r""" + Add constraints enforcing that `s` has constant average + on the blocks of `Q`. + + We do this by adding + + .. MATH:: + + \frac{1}{|q|}\sum_{a\in q} \sum_z z x_{p(a), z} = + \frac{1}{|q_0|}\sum_{a\in q_0} \sum_z z x_{p(a), z}, + + for `q\in Q`, where `q_0` is some fixed block of `Q`. + + EXAMPLES:: + + sage: A = B = [1,2,3] + sage: bij = Bijectionist(A, B, lambda b: b % 3) + sage: bij.set_homomesic([[1,2], [3]]) # indirect doctest + sage: list(bij.solutions_iterator()) + [{1: 2, 2: 0, 3: 1}, {1: 0, 2: 2, 3: 1}] + """ + Q = self._bijectionist._Q + if Q is None: + return + P = self._bijectionist._P + tZ = self._bijectionist._possible_block_values + + def sum_q(q): + return sum(sum(z*self._x[P.find(a), z] for z in tZ[P.find(a)]) + for a in q) + q0 = Q[0] + v0 = sum_q(q0) + for q in Q[1:]: + self.milp.add_constraint(len(q0)*sum_q(q) == len(q)*v0, name=f"h: ({q})~({q0})") + + +def _invert_dict(d): + """ + Return the dictionary whose keys are the values of the input and + whose values are the lists of preimages. + + INPUT: + + - ``d`` -- a dict + + EXAMPLES:: + + sage: from sage.combinat.bijectionist import _invert_dict + sage: _invert_dict({1: "a", 2: "a", 3:"b"}) + {'a': [1, 2], 'b': [3]} + + sage: _invert_dict({}) + {} + """ + preimages = {} + for k, v in d.items(): + preimages[v] = preimages.get(v, []) + [k] + return preimages + + +def _disjoint_set_roots(d): + """ + Return the representatives of the blocks of the disjoint set. + + INPUT: + + - ``d`` -- a :class:`sage.sets.disjoint_set.DisjointSet_of_hashables` + + EXAMPLES:: + + sage: from sage.combinat.bijectionist import _disjoint_set_roots + sage: d = DisjointSet('abcde') + sage: d.union("a", "b") + sage: d.union("a", "c") + sage: d.union("e", "d") + sage: _disjoint_set_roots(d) + dict_keys(['a', 'e']) + """ + return d.root_to_elements_dict().keys() + + +def _non_copying_intersection(sets): + """ + Return the intersection of the sets. + + If the intersection is equal to one of the sets, return this + set. + + EXAMPLES:: + + sage: from sage.combinat.bijectionist import _non_copying_intersection + sage: A = set(range(7000)); B = set(range(8000)); + sage: _non_copying_intersection([A, B]) is A + True + + sage: A = set([1,2]); B = set([2,3]) + sage: _non_copying_intersection([A, B]) + {2} + + """ + sets = sorted(sets, key=len) + result = set.intersection(*sets) + n = len(result) + for s in sets: + N = len(s) + if n < N: + return result + if s == result: + return s + + +""" +TESTS:: + + sage: As = Bs = [[], + ....: [(1,i,j) for i in [-1,0,1] for j in [-1,1]], + ....: [(2,i,j) for i in [-1,0,1] for j in [-1,1]], + ....: [(3,i,j) for i in [-2,-1,0,1,2] for j in [-1,1]]] + +Note that adding ``[(2,-2,-1), (2,2,-1), (2,-2,1), (2,2,1)]`` makes +it take (seemingly) forever:: + + sage: def c1(a, b): return (a[0]+b[0], a[1]*b[1], a[2]*b[2]) + sage: def c2(a): return (a[0], -a[1], a[2]) + + sage: bij = Bijectionist(sum(As, []), sum(Bs, [])) + sage: bij.set_statistics((lambda x: x[0], lambda x: x[0])) + sage: bij.set_intertwining_relations((2, c1, c1), (1, c2, c2)) + sage: l = list(bij.solutions_iterator()); len(l) # long time -- (2.7 seconds with SCIP on AMD Ryzen 5 PRO 3500U w/ Radeon Vega Mobile Gfx) + 64 + +A brute force check would be difficult:: + + sage: prod([factorial(len(A)) for A in As]) + 1881169920000 + +Let us try a smaller example:: + + sage: As = Bs = [[], + ....: [(1,i,j) for i in [-1,0,1] for j in [-1,1]], + ....: [(2,i,j) for i in [-1,1] for j in [-1,1]], + ....: [(3,i,j) for i in [-1,1] for j in [-1,1]]] + + sage: bij = Bijectionist(sum(As, []), sum(Bs, [])) + sage: bij.set_statistics((lambda x: x[0], lambda x: x[0])) + sage: bij.set_intertwining_relations((2, c1, c1), (1, c2, c2)) + sage: l1 = list(bij.solutions_iterator()); len(l1) + 16 + sage: prod([factorial(len(A)) for A in As]) + 414720 + + sage: pis = cartesian_product([Permutations(len(A)) for A in As]) + sage: it = ({a: Bs[n][pi[n][i]-1] for n, A in enumerate(As) for i, a in enumerate(A)} for pi in pis) + sage: A = sum(As, []) + sage: respects_c1 = lambda s: all(c1(a1, a2) not in A or s[c1(a1, a2)] == c1(s[a1], s[a2]) for a1 in A for a2 in A) + sage: respects_c2 = lambda s: all(c2(a1) not in A or s[c2(a1)] == c2(s[a1]) for a1 in A) + sage: l2 = [s for s in it if respects_c1(s) and respects_c2(s)] # long time -- (17 seconds on AMD Ryzen 5 PRO 3500U w/ Radeon Vega Mobile Gfx) + sage: sorted(l1, key=lambda s: tuple(s.items())) == l2 # long time + True + +Our benchmark example:: + + sage: from sage.combinat.cyclic_sieving_phenomenon import orbit_decomposition + sage: def alpha1(p): return len(p.weak_excedences()) + sage: def alpha2(p): return len(p.fixed_points()) + sage: def beta1(p): return len(p.descents(final_descent=True)) if p else 0 + sage: def beta2(p): return len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1]) + sage: gamma = Permutation.longest_increasing_subsequence_length + sage: def rotate_permutation(p): + ....: cycle = Permutation(tuple(range(1, len(p)+1))) + ....: return Permutation([cycle.inverse()(p(cycle(i))) for i in range(1, len(p)+1)]) + + sage: N = 5 + sage: As = [list(Permutations(n)) for n in range(N+1)] + sage: A = B = sum(As, []) + sage: bij = Bijectionist(A, B, gamma) + sage: bij.set_statistics((len, len), (alpha1, beta1), (alpha2, beta2)) + sage: bij.set_constant_blocks(sum([orbit_decomposition(A, rotate_permutation) for A in As], [])) + + sage: P = bij.constant_blocks(optimal=True) + sage: P = [sorted(p, key=lambda p: (len(p), p)) for p in P] + sage: P = sorted(P, key=lambda p: (len(next(iter(p))), len(p))) + sage: for p in P: + ....: print(p) + [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]] + [[2, 1], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 2, 1], ... + [[3, 1, 2], [1, 4, 2, 3], [2, 4, 1, 3], [3, 1, 2, 4], [3, 1, 4, 2], ... + [[4, 1, 2, 3], [1, 5, 2, 3, 4], [4, 1, 2, 3, 5], [4, 5, 1, 2, 3], [5, 1, 2, 4, 3], ... + [[1, 3, 2, 5, 4], [2, 1, 3, 5, 4], [2, 1, 4, 3, 5], [5, 2, 4, 3, 1], [5, 3, 2, 4, 1]] + [[1, 3, 5, 2, 4], [2, 4, 1, 3, 5], [3, 5, 2, 4, 1], [4, 1, 3, 5, 2], [5, 2, 4, 1, 3]] + ... + + sage: for d in sorted(bij.minimal_subdistributions_blocks_iterator(), key=lambda d: (len(d[0]), d[0])): + ....: print(d) + ([[]], [0]) + ([[1]], [1]) + ([[2, 1]], [2]) + ([[3, 1, 2]], [3]) + ([[4, 1, 2, 3]], [4]) + ([[5, 1, 2, 3, 4]], [5]) + ([[2, 3, 1, 5, 4], [2, 4, 5, 3, 1], [2, 5, 4, 1, 3], [3, 4, 1, 5, 2]], [2, 3, 3, 3]) + ([[3, 1, 2, 5, 4], [4, 1, 2, 5, 3], [3, 5, 2, 1, 4], [4, 1, 5, 2, 3]], [3, 3, 4, 4]) + ([[2, 1, 3, 5, 4], [2, 4, 1, 3, 5], [2, 5, 3, 1, 4], [3, 4, 1, 2, 5], [3, 1, 5, 4, 2], [2, 5, 1, 4, 3], [2, 1, 5, 4, 3]], [2, 2, 3, 3, 3, 3, 3]) + + sage: l = list(bij.solutions_iterator()); len(l) # not tested -- (17 seconds with SCIP on AMD Ryzen 5 PRO 3500U w/ Radeon Vega Mobile Gfx) + 504 + + sage: for a, d in bij.minimal_subdistributions_iterator(): # not tested + ....: print(sorted(a), sorted(d)) +""" diff --git a/src/sage/combinat/binary_recurrence_sequences.py b/src/sage/combinat/binary_recurrence_sequences.py index a1f2d969c4c..9527c512360 100644 --- a/src/sage/combinat/binary_recurrence_sequences.py +++ b/src/sage/combinat/binary_recurrence_sequences.py @@ -19,12 +19,12 @@ sage: R.pthpowers(2, 10**10) # long time (7 seconds) -- in fact these are all squares, c.f. [BMS06] [0, 1, 2, 12] - sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence + sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence sage: S.period(73) 148 sage: S(5) % 73 == S(5 +148) %73 True - sage: S.pthpowers(3,10**10) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^10 + sage: S.pthpowers(3, 10**10) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^10 [0, 1, 2] sage: T = BinaryRecurrenceSequence(2,0,1,2) @@ -34,10 +34,11 @@ True sage: T.is_geometric() True - sage: T.pthpowers(7,10**30) + sage: T.pthpowers(7, 10**30) # optional - sage.symbolic Traceback (most recent call last): ... - ValueError: the degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers + ValueError: the degenerate binary recurrence sequence is geometric or quasigeometric + and has many pth powers AUTHORS: @@ -65,7 +66,8 @@ from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.integer import Integer -from sage.arith.all import lcm, next_prime, is_prime, next_prime_power, legendre_symbol +from sage.arith.functions import lcm +from sage.arith.misc import is_prime, next_prime, next_prime_power, legendre_symbol from sage.functions.log import log from sage.misc.functional import sqrt @@ -124,9 +126,9 @@ def __init__(self, b, c, u0=0, u1=1): self.c = c self.u0 = u0 self.u1 = u1 - self._period_dict = {} #dictionary to cache the period of a sequence for future lookup - self._PGoodness = {} #dictionary to cache primes that are "good" by some prime power - self._ell = 1 #variable that keeps track of the last prime power to be used as a goodness + self._period_dict = {} # dictionary to cache the period of a sequence for future lookup + self._PGoodness = {} # dictionary to cache primes that are "good" by some prime power + self._ell = 1 # variable that keeps track of the last prime power to be used as a goodness def __repr__(self): """ @@ -466,7 +468,7 @@ def period(self, m): #expand the list of prime factors so every factor is with multiplicity 1 for i0, i1 in Mfac: - for j in range(i1): + for _ in range(i1): C.append(i0) Mfac = C @@ -517,7 +519,9 @@ def pthpowers(self, p, Bound): OUTPUT: - - A list of the indices of all ``p`` th powers less bounded by ``Bound``. If the sequence is degenerate and there are many ``p`` th powers, raises ``ValueError``. + - A list of the indices of all ``p`` th powers less bounded by + ``Bound``. If the sequence is degenerate and there are many + ``p`` th powers, raises :class:`ValueError`. EXAMPLES:: @@ -543,17 +547,18 @@ def pthpowers(self, p, Bound): True sage: T.is_geometric() True - sage: T.pthpowers(7,10**30) + sage: T.pthpowers(7, 10**30) # optional - sage.symbolic Traceback (most recent call last): ... - ValueError: the degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers + ValueError: the degenerate binary recurrence sequence is geometric or + quasigeometric and has many pth powers sage: L = BinaryRecurrenceSequence(4,0,2,2) sage: [L(i).factor() for i in range(10)] [2, 2, 2^3, 2^5, 2^7, 2^9, 2^11, 2^13, 2^15, 2^17] sage: L.is_quasigeometric() True - sage: L.pthpowers(2,10**30) + sage: L.pthpowers(2, 10**30) # optional - sage.symbolic [] .. NOTE:: @@ -643,10 +648,10 @@ def pthpowers(self, p, Bound): F = GF(ell) a0 = F(self.u0) - a1 = F(self.u1) #a0 and a1 are variables for terms in sequence + a1 = F(self.u1) # a0 and a1 are variables for terms in sequence bf, cf = F(self.b), F(self.c) - for n in range(Bound): # n is the index of the a0 + for n in range(Bound): # n is the index of the a0 #Check whether a0 is a perfect power mod ell if _is_p_power_mod(a0, p, ell): @@ -1050,7 +1055,8 @@ def _estimated_time(M2, M1, length, p): EXAMPLES:: - sage: sage.combinat.binary_recurrence_sequences._estimated_time(2**4*3**2*5*7*11*13*17, 2**4*3**2*5*7*11*13, 20, 7) + sage: from sage.combinat.binary_recurrence_sequences import _estimated_time + sage: _estimated_time(2**4*3**2*5*7*11*13*17, 2**4*3**2*5*7*11*13, 20, 7) # optional - sage.symbolic 106.211159309421 """ @@ -1086,7 +1092,7 @@ def _find_cong1(p, R, ell): EXAMPLES:: sage: R = BinaryRecurrenceSequence(1,1) - sage: sage.combinat.binary_recurrence_sequences._find_cong1(7, R, 29) + sage: sage.combinat.binary_recurrence_sequences._find_cong1(7, R, 29) # optional - sage.rings.finite_rings ([0, 1, 2, 12, 13], 14) """ F = GF(ell) @@ -1136,9 +1142,9 @@ def _is_p_power(a, p): EXAMPLES:: - sage: sage.combinat.binary_recurrence_sequences._is_p_power(2**7,7) + sage: sage.combinat.binary_recurrence_sequences._is_p_power(2**7, 7) # optional - sage.symbolic True - sage: sage.combinat.binary_recurrence_sequences._is_p_power(2**7*3**2,7) + sage: sage.combinat.binary_recurrence_sequences._is_p_power(2**7*3**2, 7) # optional - sage.symbolic False """ return int(a**(1/p))**p == a diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 96ff98d14dd..8e876ab137a 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -867,7 +867,7 @@ def show(self, with_leaves=False): TESTS:: sage: t1 = BinaryTree([[], [[], None]]) - sage: t1.show() + sage: t1.show() # optional - sage.plot """ try: self.graph(with_leaves=with_leaves).show(layout='tree', tree_root=0, tree_orientation="down") @@ -988,13 +988,13 @@ def to_dyck_word_tamari(self): EXAMPLES:: - sage: BinaryTree().to_dyck_word_tamari() + sage: BinaryTree().to_dyck_word_tamari() # optional - sage.combinat [] - sage: BinaryTree([]).to_dyck_word_tamari() + sage: BinaryTree([]).to_dyck_word_tamari() # optional - sage.combinat [1, 0] - sage: BinaryTree([[None,[]],None]).to_dyck_word_tamari() + sage: BinaryTree([[None,[]],None]).to_dyck_word_tamari() # optional - sage.combinat [1, 1, 0, 0, 1, 0] - sage: BinaryTree([[[], [[], None]], [[], []]]).to_dyck_word_tamari() + sage: BinaryTree([[[], [[], None]], [[], []]]).to_dyck_word_tamari() # optional - sage.combinat [1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0] """ return self.to_dyck_word("L1R0") @@ -1128,7 +1128,9 @@ def tamari_join(self, other): ....: return True sage: all( test_uni_join(p, q) for p in BinaryTrees(3) for q in BinaryTrees(3) ) True - sage: p = BinaryTrees(6).random_element(); q = BinaryTrees(6).random_element(); test_uni_join(p, q) + sage: p = BinaryTrees(6).random_element() # optional - sage.combinat + sage: q = BinaryTrees(6).random_element() # optional - sage.combinat + sage: test_uni_join(p, q) # optional - sage.combinat True Border cases:: @@ -1215,7 +1217,9 @@ def tamari_meet(self, other, side="right"): ....: return True sage: all( test_uni_meet(p, q) for p in BinaryTrees(3) for q in BinaryTrees(3) ) True - sage: p = BinaryTrees(6).random_element(); q = BinaryTrees(6).random_element(); test_uni_meet(p, q) + sage: p = BinaryTrees(6).random_element() # optional - sage.combinat + sage: q = BinaryTrees(6).random_element() # optional - sage.combinat + sage: test_uni_meet(p, q) # optional - sage.combinat True Border cases:: @@ -1251,21 +1255,21 @@ def to_dyck_word(self, usemap="1L0R"): EXAMPLES:: - sage: BinaryTree().to_dyck_word() + sage: BinaryTree().to_dyck_word() # optional - sage.combinat [] - sage: BinaryTree([]).to_dyck_word() + sage: BinaryTree([]).to_dyck_word() # optional - sage.combinat [1, 0] - sage: BinaryTree([[[], [[], None]], [[], []]]).to_dyck_word() + sage: BinaryTree([[[], [[], None]], [[], []]]).to_dyck_word() # optional - sage.combinat [1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0] - sage: BinaryTree([[None,[]],None]).to_dyck_word() + sage: BinaryTree([[None,[]],None]).to_dyck_word() # optional - sage.combinat [1, 1, 0, 1, 0, 0] - sage: BinaryTree([[None,[]],None]).to_dyck_word("1R0L") + sage: BinaryTree([[None,[]],None]).to_dyck_word("1R0L") # optional - sage.combinat [1, 0, 1, 1, 0, 0] - sage: BinaryTree([[None,[]],None]).to_dyck_word("L1R0") + sage: BinaryTree([[None,[]],None]).to_dyck_word("L1R0") # optional - sage.combinat [1, 1, 0, 0, 1, 0] - sage: BinaryTree([[None,[]],None]).to_dyck_word("R1L0") + sage: BinaryTree([[None,[]],None]).to_dyck_word("R1L0") # optional - sage.combinat [1, 1, 0, 1, 0, 0] - sage: BinaryTree([[None,[]],None]).to_dyck_word("R10L") + sage: BinaryTree([[None,[]],None]).to_dyck_word("R10L") # optional - sage.combinat Traceback (most recent call last): ... ValueError: R10L is not a correct map @@ -1273,13 +1277,13 @@ def to_dyck_word(self, usemap="1L0R"): TESTS:: sage: bt = BinaryTree([[[], [[], None]], [[], []]]) - sage: bt == bt.to_dyck_word().to_binary_tree() + sage: bt == bt.to_dyck_word().to_binary_tree() # optional - sage.combinat True - sage: bt == bt.to_dyck_word("1R0L").to_binary_tree("1R0L") + sage: bt == bt.to_dyck_word("1R0L").to_binary_tree("1R0L") # optional - sage.combinat True - sage: bt == bt.to_dyck_word("L1R0").to_binary_tree("L1R0") + sage: bt == bt.to_dyck_word("L1R0").to_binary_tree("L1R0") # optional - sage.combinat True - sage: bt == bt.to_dyck_word("R1L0").to_binary_tree("R1L0") + sage: bt == bt.to_dyck_word("R1L0").to_binary_tree("R1L0") # optional - sage.combinat True """ from sage.combinat.dyck_word import DyckWord @@ -1443,9 +1447,9 @@ def tamari_sorting_tuple(self, reverse=False): ((1, 0, 0), 3), ((0, 0, 0), 3)] - sage: t = BinaryTrees(10).random_element() - sage: u = t.left_right_symmetry() - sage: t.tamari_sorting_tuple(True) == u.tamari_sorting_tuple() + sage: t = BinaryTrees(10).random_element() # optional - sage.combinat + sage: u = t.left_right_symmetry() # optional - sage.combinat + sage: t.tamari_sorting_tuple(True) == u.tamari_sorting_tuple() # optional - sage.combinat True REFERENCES: @@ -1518,7 +1522,7 @@ def as_ordered_tree(self, with_leaves=True): children = [child.as_ordered_tree(with_leaves) for child in self] else: if not self: - raise ValueError("The empty binary tree cannot be made into an ordered tree with with_leaves = False") + raise ValueError("the empty binary tree cannot be made into an ordered tree with with_leaves = False") children = [child.as_ordered_tree(with_leaves) for child in self if not child.is_empty()] if self in LabelledBinaryTrees(): from sage.combinat.ordered_tree import LabelledOrderedTree @@ -1612,8 +1616,9 @@ def to_tilting(self): [(0, 1), (2, 3), (4, 5), (6, 7), (4, 7), (8, 9), (10, 11), (8, 11), (4, 11), (12, 13), (4, 13), (2, 13), (0, 13)] - sage: t2 = DyckWord([1,1,1,1,0,1,1,0,0,0,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,0]).to_binary_tree() - sage: len(t2.to_tilting()) == t2.node_number() + sage: w = DyckWord([1,1,1,1,0,1,1,0,0,0,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,0]) # optional - sage.combinat + sage: t2 = w.to_binary_tree() # optional - sage.combinat + sage: len(t2.to_tilting()) == t2.node_number() # optional - sage.combinat True """ if not self: @@ -2827,36 +2832,36 @@ def q_hook_length_fraction(self, q=None, q_factor=False): only one vertex (which is a leaf):: sage: b = BinaryTree() - sage: b.q_hook_length_fraction() + sage: b.q_hook_length_fraction() # optional - sage.combinat 1 - sage: b.q_hook_length_fraction(q_factor=True) + sage: b.q_hook_length_fraction(q_factor=True) # optional - sage.combinat 1 Nothing different for a tree with one node and two leaves:: sage: b = BinaryTree([]); b [., .] - sage: b.q_hook_length_fraction() + sage: b.q_hook_length_fraction() # optional - sage.combinat 1 - sage: b.q_hook_length_fraction(q_factor=True) + sage: b.q_hook_length_fraction(q_factor=True) # optional - sage.combinat 1 Let us get to a more interesting tree:: sage: b = BinaryTree([[[],[]],[[],None]]); b [[[., .], [., .]], [[., .], .]] - sage: b.q_hook_length_fraction()(q=1) + sage: b.q_hook_length_fraction()(q=1) # optional - sage.combinat 20 - sage: b.q_hook_length_fraction() + sage: b.q_hook_length_fraction() # optional - sage.combinat q^7 + 2*q^6 + 3*q^5 + 4*q^4 + 4*q^3 + 3*q^2 + 2*q + 1 - sage: b.q_hook_length_fraction(q_factor=True) + sage: b.q_hook_length_fraction(q_factor=True) # optional - sage.combinat q^10 + 2*q^9 + 3*q^8 + 4*q^7 + 4*q^6 + 3*q^5 + 2*q^4 + q^3 - sage: b.q_hook_length_fraction(q=2) + sage: b.q_hook_length_fraction(q=2) # optional - sage.combinat 465 - sage: b.q_hook_length_fraction(q=2, q_factor=True) + sage: b.q_hook_length_fraction(q=2, q_factor=True) # optional - sage.combinat 3720 sage: q = PolynomialRing(ZZ, 'q').gen() - sage: b.q_hook_length_fraction(q=q**2) + sage: b.q_hook_length_fraction(q=q**2) # optional - sage.combinat q^14 + 2*q^12 + 3*q^10 + 4*q^8 + 4*q^6 + 3*q^4 + 2*q^2 + 1 Let us check the fact that `f_{q} (T)` is the generating function @@ -2875,7 +2880,7 @@ def q_hook_length_fraction(self, q=None, q_factor=False): ....: return all( q_hook_length_fraction_2(T) ....: == T.q_hook_length_fraction(q_factor=True) ....: for T in BinaryTrees(i) ) - sage: test_genfun(4) + sage: test_genfun(4) # optional - sage.combinat True """ from sage.combinat.q_analogues import q_binomial @@ -3394,29 +3399,29 @@ def dendriform_shuffle(self, other): sage: l = BinaryTree([g, u]) sage: r = BinaryTree([u, g]) - sage: list(g.dendriform_shuffle(g)) + sage: list(g.dendriform_shuffle(g)) # optional - sage.combinat [[[., .], .], [., [., .]]] - sage: list(l.dendriform_shuffle(l)) + sage: list(l.dendriform_shuffle(l)) # optional - sage.combinat [[[[[., .], .], .], .], [[[., .], [., .]], .], [[., .], [[., .], .]]] - sage: list(l.dendriform_shuffle(r)) + sage: list(l.dendriform_shuffle(r)) # optional - sage.combinat [[[[., .], .], [., .]], [[., .], [., [., .]]]] TESTS:: - sage: list(u.dendriform_shuffle(u)) + sage: list(u.dendriform_shuffle(u)) # optional - sage.combinat [.] - sage: list(u.dendriform_shuffle(g)) + sage: list(u.dendriform_shuffle(g)) # optional - sage.combinat [[., .]] - sage: list(u.dendriform_shuffle(l)) + sage: list(u.dendriform_shuffle(l)) # optional - sage.combinat [[[., .], .]] - sage: list(u.dendriform_shuffle(r)) + sage: list(u.dendriform_shuffle(r)) # optional - sage.combinat [[., [., .]]] - sage: list(r.dendriform_shuffle(u)) + sage: list(r.dendriform_shuffle(u)) # optional - sage.combinat [[., [., .]]] - sage: list(l.dendriform_shuffle(u)) + sage: list(l.dendriform_shuffle(u)) # optional - sage.combinat [[[., .], .]] """ from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 @@ -3526,32 +3531,32 @@ def sylvester_class(self, left_to_right=False): ....: if not BinaryTree(tree) == t: ....: return False ....: return True - sage: test_bst_of_sc(4, False) + sage: test_bst_of_sc(4, False) # optional - sage.combinat True - sage: test_bst_of_sc(5, False) # long time + sage: test_bst_of_sc(5, False) # long time # optional - sage.combinat True The same with the left-to-right version of binary search:: - sage: test_bst_of_sc(4, True) + sage: test_bst_of_sc(4, True) # optional - sage.combinat True - sage: test_bst_of_sc(5, True) # long time + sage: test_bst_of_sc(5, True) # long time # optional - sage.combinat True Checking that the sylvester class is the set of linear extensions of the poset of the tree:: - sage: all( sorted(t.canonical_labelling().sylvester_class()) + sage: all( sorted(t.canonical_labelling().sylvester_class()) # optional - sage.combinat ....: == sorted(list(v) for v in t.canonical_labelling().to_poset().linear_extensions()) ....: for t in BinaryTrees(4) ) True TESTS:: - sage: list(BinaryTree([[],[]]).sylvester_class()) + sage: list(BinaryTree([[],[]]).sylvester_class()) # optional - sage.combinat [[1, 3, 2], [3, 1, 2]] sage: bt = BinaryTree([[[],None],[[],[]]]) - sage: l = list(bt.sylvester_class()); l + sage: l = list(bt.sylvester_class()); l # optional - sage.combinat [[1, 2, 4, 6, 5, 3], [1, 4, 2, 6, 5, 3], [1, 4, 6, 2, 5, 3], @@ -3572,14 +3577,14 @@ def sylvester_class(self, left_to_right=False): [6, 4, 1, 2, 5, 3], [6, 4, 1, 5, 2, 3], [6, 4, 5, 1, 2, 3]] - sage: len(l) == Integer(bt.q_hook_length_fraction()(q=1)) + sage: len(l) == Integer(bt.q_hook_length_fraction()(q=1)) # optional - sage.combinat True Border cases:: - sage: list(BinaryTree().sylvester_class()) + sage: list(BinaryTree().sylvester_class()) # optional - sage.combinat [[]] - sage: list(BinaryTree([]).sylvester_class()) + sage: list(BinaryTree([]).sylvester_class()) # optional - sage.combinat [[1]] """ if self.is_empty(): @@ -4045,8 +4050,8 @@ def from_tamari_sorting_tuple(key): EXAMPLES:: sage: from sage.combinat.binary_tree import from_tamari_sorting_tuple - sage: t = BinaryTrees(60).random_element() - sage: from_tamari_sorting_tuple(t.tamari_sorting_tuple()[0]) == t + sage: t = BinaryTrees(60).random_element() # optional - sage.combinat + sage: from_tamari_sorting_tuple(t.tamari_sorting_tuple()[0]) == t # optional - sage.combinat True """ if not key: @@ -4250,16 +4255,17 @@ def random_element(self): EXAMPLES:: - sage: BinaryTrees(5).random_element() # random + sage: BinaryTrees(5).random_element() # random # optional - sage.combinat [., [., [., [., [., .]]]]] - sage: BinaryTrees(0).random_element() + sage: BinaryTrees(0).random_element() # optional - sage.combinat . - sage: BinaryTrees(1).random_element() + sage: BinaryTrees(1).random_element() # optional - sage.combinat [., .] TESTS:: - sage: all(BinaryTrees(10).random_element() in BinaryTrees(10) for i in range(20)) + sage: all(BinaryTrees(10).random_element() in BinaryTrees(10) # optional - sage.combinat + ....: for i in range(20)) True """ from sage.combinat.dyck_word import CompleteDyckWords_size @@ -4504,17 +4510,17 @@ def random_element(self): EXAMPLES:: - sage: BinaryTrees(5, full=True).random_element() # random + sage: BinaryTrees(5, full=True).random_element() # random # optional - sage.combinat [[], [[], []]] - sage: BinaryTrees(0, full=True).random_element() + sage: BinaryTrees(0, full=True).random_element() # optional - sage.combinat . - sage: BinaryTrees(1, full=True).random_element() + sage: BinaryTrees(1, full=True).random_element() # optional - sage.combinat [., .] TESTS:: sage: B = BinaryTrees(19, full=True) - sage: all(B.random_element() in B for i in range(20)) + sage: all(B.random_element() in B for i in range(20)) # optional - sage.combinat True """ from sage.combinat.dyck_word import CompleteDyckWords_size diff --git a/src/sage/combinat/blob_algebra.py b/src/sage/combinat/blob_algebra.py index c3d7037ae4c..657c70a5c0e 100644 --- a/src/sage/combinat/blob_algebra.py +++ b/src/sage/combinat/blob_algebra.py @@ -23,8 +23,8 @@ from sage.structure.richcmp import richcmp #from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.cachefunc import cached_method -from sage.misc.misc import powerset -from sage.arith.all import binomial +from sage.combinat.subset import powerset +from sage.arith.misc import binomial from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.algebras import Algebras from sage.combinat.diagram_algebras import (TemperleyLiebDiagrams, diagram_latex, diff --git a/src/sage/combinat/cartesian_product.py b/src/sage/combinat/cartesian_product.py index b03aed1987b..7ab49439557 100644 --- a/src/sage/combinat/cartesian_product.py +++ b/src/sage/combinat/cartesian_product.py @@ -51,27 +51,27 @@ class for ``cartesian_product``; sage: F1 = ['a', 'b'] sage: F2 = [1, 2, 3, 4] - sage: F3 = Permutations(3) + sage: F3 = Permutations(3) # optional - sage.combinat sage: from sage.combinat.cartesian_product import CartesianProduct_iters - sage: C = CartesianProduct_iters(F1, F2, F3) - sage: c = cartesian_product([F1, F2, F3]) + sage: C = CartesianProduct_iters(F1, F2, F3) # optional - sage.combinat + sage: c = cartesian_product([F1, F2, F3]) # optional - sage.combinat - sage: type(C.an_element()) + sage: type(C.an_element()) # optional - sage.combinat <class 'list'> - sage: type(c.an_element()) + sage: type(c.an_element()) # optional - sage.combinat <class 'sage.sets.cartesian_product.CartesianProduct_with_category.element_class'> - sage: l = ['a', 1, Permutation([3,2,1])] - sage: l in C + sage: l = ['a', 1, Permutation([3,2,1])] # optional - sage.combinat + sage: l in C # optional - sage.combinat True - sage: l in c + sage: l in c # optional - sage.combinat False - sage: elt = c(l) - sage: elt + sage: elt = c(l) # optional - sage.combinat + sage: elt # optional - sage.combinat ('a', 1, [3, 2, 1]) - sage: elt in c + sage: elt in c # optional - sage.combinat True - sage: elt.parent() is c + sage: elt.parent() is c # optional - sage.combinat True """ @@ -274,11 +274,11 @@ def is_finite(self): sage: CartesianProduct_iters(4,4).is_finite() Traceback (most recent call last): ... - ValueError: Unable to determine whether this product is finite + ValueError: unable to determine whether this product is finite """ finites = [_is_finite(L, fallback=None) for L in self.iters] if any(f is None for f in finites): - raise ValueError("Unable to determine whether this product is finite") + raise ValueError("unable to determine whether this product is finite") if all(f is True for f in finites): return True lens = [_len(L) for L in self.iters] diff --git a/src/sage/combinat/cluster_algebra_quiver/all.py b/src/sage/combinat/cluster_algebra_quiver/all.py index 40b86813ba0..5b28d09d1c6 100644 --- a/src/sage/combinat/cluster_algebra_quiver/all.py +++ b/src/sage/combinat/cluster_algebra_quiver/all.py @@ -15,3 +15,6 @@ lazy_import("sage.combinat.cluster_algebra_quiver.quiver_mutation_type", "QuiverMutationType") lazy_import("sage.combinat.cluster_algebra_quiver.quiver", "ClusterQuiver") lazy_import("sage.combinat.cluster_algebra_quiver.cluster_seed", "ClusterSeed") + +del install_doc +del lazy_import diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 283f4ab8985..a67af5739ce 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs sage.modules r""" ClusterSeed -A *cluster seed* is a pair `(B,\mathbf{x})` with `B` being a *skew-symmetrizable* `(n+m \times n)` *-matrix* +A *cluster seed* is a pair `(B,\mathbf{x})` with `B` being a *skew-symmetrizable* `(n+m) \times n` *-matrix* and with `\mathbf{x}` being an `n`-tuple of *independent elements* in the field of rational functions in `n` variables. For the compendium on the cluster algebra and quiver package see @@ -43,13 +43,13 @@ from sage.rings.fraction_field import FractionField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.fraction_field_element import FractionFieldElement -from sage.sets.all import Set -from sage.graphs.digraph import DiGraph +from sage.sets.set import Set from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType_Irreducible, QuiverMutationType_Reducible from sage.combinat.cluster_algebra_quiver.mutation_type import is_mutation_finite from random import randint +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod -from sage.matrix.all import identity_matrix +from sage.matrix.special import identity_matrix from sage.matrix.constructor import matrix from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver from sage.rings.integer import Integer @@ -57,6 +57,8 @@ from sage.combinat.cluster_algebra_quiver.interact import cluster_interact +lazy_import('sage.graphs.digraph', 'DiGraph') + class ClusterSeed(SageObject): r""" @@ -66,12 +68,18 @@ class ClusterSeed(SageObject): - ``data`` -- can be any of the following:: - * QuiverMutationType - * str - a string representing a QuiverMutationType or a common quiver type (see Examples) - * ClusterQuiver - * Matrix - a skew-symmetrizable matrix - * DiGraph - must be the input data for a quiver - * List of edges - must be the edge list of a digraph for a quiver + * :class:`QuiverMutationType` + + * :class:`str` -- a string representing a :class:`QuiverMutationType` + or a common quiver type (see Examples) + + * :class:`ClusterQuiver` + + * :class:`Matrix` -- a skew-symmetrizable matrix + + * :class:`DiGraph` -- must be the input data for a quiver + + * List of edges -- must be the edge list of a digraph for a quiver EXAMPLES:: @@ -81,16 +89,16 @@ class ClusterSeed(SageObject): sage: S = ClusterSeed(['A',[2,5],1]); S A seed for a cluster algebra of rank 7 of type ['A', [2, 5], 1] - sage: T = ClusterSeed( S ); T + sage: T = ClusterSeed(S); T A seed for a cluster algebra of rank 7 of type ['A', [2, 5], 1] - sage: T = ClusterSeed( S._M ); T + sage: T = ClusterSeed(S._M); T A seed for a cluster algebra of rank 7 - sage: T = ClusterSeed( S.quiver()._digraph ); T + sage: T = ClusterSeed(S.quiver()._digraph); T A seed for a cluster algebra of rank 7 - sage: T = ClusterSeed( S.quiver()._digraph.edges(sort=True) ); T + sage: T = ClusterSeed(S.quiver()._digraph.edges(sort=True)); T A seed for a cluster algebra of rank 7 sage: S = ClusterSeed(['B',2]); S @@ -110,76 +118,88 @@ class ClusterSeed(SageObject): sage: S = ClusterSeed(['A',4]); S._use_fpolys True - sage: S._use_d_vec True - sage: S._use_g_vec True - sage: S._use_c_vec True sage: S = ClusterSeed(['A', 4]); S.use_fpolys(False); S._use_fpolys False - sage: S = ClusterSeed(DiGraph([['a', 'b'], ['c', 'b'], ['c', 'd'], ['e', 'd']]), frozen = - ....: ['c']); S + sage: S = ClusterSeed(DiGraph([['a', 'b'], ['c', 'b'], ['c', 'd'], ['e', 'd']]), + ....: frozen=['c']); S A seed for a cluster algebra of rank 4 with 1 frozen variable - sage: S = ClusterSeed(['D', 4],user_labels = [-1, 0, 1, 2]);S + sage: S = ClusterSeed(['D', 4], user_labels=[-1, 0, 1, 2]); S A seed for a cluster algebra of rank 4 of type ['D', 4] """ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user_labels_prefix='x'): r""" - - Initializes the ClusterSeed ``self`` with the following range of possible attributes: - - * self._n - the number of mutable elements of the cluster seed. - * self._m - the number of immutable elements of the cluster seed. - * self._nlist - a list of mutable elements of the cluster seed. - * self._mlist - a list of immutable elements of the cluster seed. - * self._M - the 'n + m' x 'n' exchange matrix associated to the cluster seed. - * self._B - the mutable part of self._M. - * self._b_initial - the initial exchange matrix - * self._description - the description of the ClusterSeed - * self._use_fpolys - a boolean tracking whether F-polynomials and cluster variables will be tracked as part of every mutation. - * self._cluster - a list tracking the current names of cluster elements. - * self._user_labels_prefix - the prefix for every named cluster element. Defaults to 'x'. - * self._user_labels - an optional dictionary or list of user - defined names for all cluster elements. Defaults to ``'x_i'`` - for mutable elements and ``'y_i'`` for immutable elements. - All labels should be integers or alphanumeric strings. - * self._init_vars - an internal list for defining ambient the algebraic setting and naming quiver vertices. - * self._init_exch - the dictionary storing the initial mutable cluster variable names. - * self._U - the coefficient tuple of the initial cluster seed. - * self._F - the dictionary of F-polynomials. - * self._R - the ambient polynomial ring. - * self._y - the coefficient tuple for the current cluster seed. - * self._yhat - the mixed coefficient tuple appearing in Proposition 3.9 of [FZ2007] - * self._use_g_vec - a boolean stating if g-vectors for the cluster seed are being tracked. User input overridden as needed. - * self._G - the matrix containing all g-vectors. - * self._use_d_vec - a boolean stating if d-vectors for the cluster seed are being tracked. - * self._D - the matrix containing all d-vectors. - * self._bot_is_c - a boolean stating if the c-vectors are stored on the bottom of the exchange matrix M. - * self._use_c_vec - a boolean stating if c-vectors for the cluster seed are being tracked. User input overridden as needed. - * self._C - the matrix containing all c-vectors. - * self._BC - an extended matrix involving the B and C matrices used for simplifying mutation calculations. - * self._is_principal - a boolean tracking whether the ClusterSeed contains immutable elements coming from a principal extension of the mutable vertices. To be deprecated in future versions. - - * self._quiver - the ClusterQuiver corresponding to the exchange matrix self._M . - * self._mutation_type - the mutation type of self._quiver . - - * self._track_mut - a boolean tracking whether the ClusterSeed's mutation path is being recorded. - * self._mut_path - the list of integers recording the mutation path of a seed - with consecutive repeats deleted since mutations is an involution. + Initialize the ClusterSeed ``self`` with the following range of possible attributes: + + * self._n - the number of mutable elements of the cluster seed. + * self._m - the number of immutable elements of the cluster seed. + * self._nlist - a list of mutable elements of the cluster seed. + * self._mlist - a list of immutable elements of the cluster seed. + * self._M - the 'n + m' x 'n' exchange matrix associated to the cluster seed. + * self._B - the mutable part of self._M. + * self._b_initial - the initial exchange matrix + * self._description - the description of the ClusterSeed + * self._use_fpolys - a boolean tracking whether F-polynomials and cluster + variables will be tracked as part of every mutation. + * self._cluster - a list tracking the current names of cluster elements. + * self._user_labels_prefix - the prefix for every named cluster element. + Defaults to 'x'. + * self._user_labels - an optional dictionary or list of user + defined names for all cluster elements. Defaults to ``'x_i'`` + for mutable elements and ``'y_i'`` for immutable elements. + All labels should be integers or alphanumeric strings. + * self._init_vars - an internal list for defining ambient + the algebraic setting and naming quiver vertices. + * self._init_exch - the dictionary storing the initial + mutable cluster variable names. + * self._U - the coefficient tuple of the initial cluster seed. + * self._F - the dictionary of F-polynomials. + * self._R - the ambient polynomial ring. + * self._y - the coefficient tuple for the current cluster seed. + * self._yhat - the mixed coefficient tuple appearing in + Proposition 3.9 of [FZ2007] + * self._use_g_vec - a boolean stating if g-vectors for the cluster seed + are being tracked. User input overridden as needed. + * self._G - the matrix containing all g-vectors. + * self._use_d_vec - a boolean stating if d-vectors for the cluster seed + are being tracked. + * self._D - the matrix containing all d-vectors. + * self._bot_is_c - a boolean stating if the c-vectors are stored + on the bottom of the exchange matrix M. + * self._use_c_vec - a boolean stating if c-vectors for the cluster seed + are being tracked. User input overridden as needed. + * self._C - the matrix containing all c-vectors. + * self._BC - an extended matrix involving the B and C matrices used + for simplifying mutation calculations. + * self._is_principal - a boolean tracking whether the ClusterSeed + contains immutable elements coming from a principal extension + of the mutable vertices. To be deprecated in future versions. + + * self._quiver - the ClusterQuiver corresponding to the + exchange matrix ``self._M``. + * self._mutation_type - the mutation type of self._quiver . + + * self._track_mut - a boolean tracking whether the ClusterSeed's + mutation path is being recorded. + * self._mut_path - the list of integers recording the mutation path of + a seed - with consecutive repeats deleted since mutations + is an involution. TESTS:: sage: S = ClusterSeed(['A',4]) sage: TestSuite(S).run() """ - #initialize a null state ClusterSeed object so all tests run and fail as appropriate. + # initialize a null state ClusterSeed object so all tests run and fail as appropriate. # numerous doctests if this null state is not first initialized. self._n = 0 self._m = 0 @@ -233,9 +253,9 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user print("The input \'frozen\' is ignored") # Copy the following attributes from data - self._M = copy( data._M ) + self._M = copy(data._M) self._M.set_immutable() - self._B = copy( data._B ) + self._B = copy(data._B) self._n = data._n self._m = data._m self._nlist = list(data._nlist) @@ -256,13 +276,13 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user if data._use_d_vec and (data._D or data._cluster or data._track_mut): self._D = data.d_matrix() - self._cluster = copy( data._cluster) + self._cluster = copy(data._cluster) - self._b_initial = copy( data._b_initial) + self._b_initial = copy(data._b_initial) - self._mutation_type = copy( data._mutation_type) - self._description = copy( data._description) - self._quiver = ClusterQuiver( data._quiver ) if data._quiver else None + self._mutation_type = copy(data._mutation_type) + self._description = copy(data._description) + self._quiver = ClusterQuiver(data._quiver) if data._quiver else None # copy all previous booleans self._use_fpolys = data._use_fpolys @@ -295,7 +315,7 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user self._m = quiver._m self._nlist = copy(quiver._nlist) self._mlist = copy(quiver._mlist) - self._B = copy(self._M[:self._n,:self._n]) # Square Part of the B_matrix + self._B = copy(self._M[:self._n, :self._n]) # Square Part of the B_matrix # If initializing from a ClusterQuiver rather than a ClusterSeed, the initial B-matrix is reset to be the input B-matrix. self._b_initial = copy(self._M) @@ -304,7 +324,7 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user self._quiver = quiver # Sets ``user_labels`` to existing vertex labels - if not user_labels and set(self._nlist + self._mlist) != set(range(self._n+self._m)): + if not user_labels and set(self._nlist + self._mlist) != set(range(self._n + self._m)): user_labels = self._nlist + self._mlist if user_labels: if isinstance(user_labels, dict): @@ -331,29 +351,30 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user self._use_g_vec = True self._BC = copy(self._M).stack(self.c_matrix()) - self._bot_is_c=False + self._bot_is_c = False self._D = -matrix.identity(self._n) self._use_d_vec = True - self._mut_path = [ ] + self._mut_path = [] self._track_mut = True if user_labels: self._sanitize_init_vars(user_labels, user_labels_prefix) else: - xs = {i:'x%s'%i for i in range(self._n)} - ys = {(i+self._n):'y%s'%i for i in range(self._n+self._m)} + xs = {i: f'x{i}' for i in range(self._n)} + ys = {(i + self._n): f'y{i}' for i in range(self._n + self._m)} self._init_vars = copy(xs) self._init_vars.update(ys) self._init_exch = dict(islice(self._init_vars.items(), self._n)) - self._U = PolynomialRing(QQ,['y%s' % i for i in range(self._n)]) - self._F = dict([(i,self._U(1)) for i in self._init_exch.values()]) - self._R = PolynomialRing(QQ,[val for val in self._init_vars.values()]) - self._y = dict([ (self._U.gen(j),prod([self._R.gen(i)**self._M[i,j] for i in range(self._n,self._n+self._m)])) for j in range(self._n)]) - self._yhat = dict([ (self._U.gen(j),prod([self._R.gen(i)**self._M[i,j] for i in range(self._n+self._m)])) for j in range(self._n)]) - #self._cluster = None + self._U = PolynomialRing(QQ, [f'y{i}' for i in range(self._n)]) + self._F = {i: self._U(1) for i in self._init_exch.values()} + self._R = PolynomialRing(QQ, [val for val in self._init_vars.values()]) + self._y = {self._U.gen(j): prod([self._R.gen(i)**self._M[i, j] for i in range(self._n, self._n + self._m)]) + for j in range(self._n)} + self._yhat = {self._U.gen(j): prod([self._R.gen(i)**self._M[i, j] for i in range(self._n + self._m)]) + for j in range(self._n)} self._use_fpolys = True # in all other cases, we construct the corresponding ClusterQuiver first @@ -366,21 +387,27 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user def use_c_vectors(self, use=True, bot_is_c=False, force=False): r""" - Reconstruct c vectors from other data or initialize if no usable data exists. + Reconstruct c-vectors from other data or initialize if no usable data exists. Warning: Initialization may lead to inconsistent data. INPUT: - - ``use`` -- (default:True) If True, will use c vectors - - ``bot_is_c`` -- (default:False) If True and ClusterSeed self has self._m == self._n, then will assume bottom half of the extended exchange matrix is the c-matrix. If true, lets the ClusterSeed know c-vectors can be calculated. + - ``use`` -- (default: ``True``) If ``True``, will use c-vectors + - ``bot_is_c`` -- (default: ``False``) If ``True`` and + :class:`ClusterSeed` ``self`` has ``self._m == self._n``, then will + assume bottom half of the extended exchange matrix is the c-matrix. + If ``True``, lets the :class:`ClusterSeed` know c-vectors can be + calculated. EXAMPLES:: sage: S = ClusterSeed(['A',4]) - sage: S.use_c_vectors(False); S.use_g_vectors(False); S.use_fpolys(False); S.track_mutations(False) + sage: S.use_c_vectors(False); S.use_g_vectors(False) + sage: S.use_fpolys(False); S.track_mutations(False) sage: S.use_c_vectors(True) - Warning: Initializing c-vectors at this point could lead to inconsistent seed data. + Warning: Initializing c-vectors at this point + could lead to inconsistent seed data. sage: S.use_c_vectors(True, force=True) sage: S.c_matrix() @@ -390,7 +417,8 @@ def use_c_vectors(self, use=True, bot_is_c=False, force=False): [0 0 0 1] sage: S = ClusterSeed(['A',4]) - sage: S.use_c_vectors(False); S.use_g_vectors(False); S.use_fpolys(False); S.track_mutations(False) + sage: S.use_c_vectors(False); S.use_g_vectors(False) + sage: S.use_fpolys(False); S.track_mutations(False) sage: S.mutate(1) sage: S.use_c_vectors(True, force=True) sage: S.c_matrix() @@ -398,12 +426,11 @@ def use_c_vectors(self, use=True, bot_is_c=False, force=False): [0 1 0 0] [0 0 1 0] [0 0 0 1] - """ if self._use_c_vec != use: self._use_c_vec = use if self._use_c_vec: - #self._C = matrix.identity(self._n) + # self._C = matrix.identity(self._n) try: self._use_c_vec = False # temporarily turns off c-vectors to see if they can be recovered. self._C = self.c_matrix() # if not just sets it to be identity matrix, i.e. reinitialized. @@ -426,16 +453,16 @@ def use_c_vectors(self, use=True, bot_is_c=False, force=False): else: self._C = None self._BC = copy(self._M) - if self._bot_is_c != bot_is_c: # If we need to do this. It overrides the previous designations. + if self._bot_is_c != bot_is_c: # If we need to do this. It overrides the previous designations. self._bot_is_c = bot_is_c if self._bot_is_c: self._use_c_vec = True - if self._m == self._n: # in this case, the second half of a 2n x n matrix is a c-matrix. - self._C = copy(self._M[self._n:(self._n+self._m),:self._n]) + if self._m == self._n: # in this case, the second half of a 2n x n matrix is a c-matrix. + self._C = copy(self._M[self._n:(self._n + self._m), :self._n]) self._BC = copy(self._M) - else: # self._n != self._m + else: # self._n != self._m raise ValueError('There are immutable elements not in the c-matrix. Storing the c-matrix separately.') - self._C = copy(self._M[self._m:(self._n+self._m),:self._n]) + self._C = copy(self._M[self._m:(self._n + self._m), :self._n]) self._BC = copy(self._M) self._M = self._M[:self._m:self._n] self._M.set_immutable() @@ -443,13 +470,15 @@ def use_c_vectors(self, use=True, bot_is_c=False, force=False): def use_g_vectors(self, use=True, force=False): r""" - Reconstruct g vectors from other data or initialize if no usable data exists. + Reconstruct g-vectors from other data or initialize if no usable data exists. - Warning: Initialization may lead to inconsistent data. + .. warning:: + + Initialization may lead to inconsistent data. INPUT: - - ``use`` -- (default:True) If True, will use g vectors + - ``use`` -- (default: ``True``) If ``True``, will use g-vectors EXAMPLES:: @@ -486,7 +515,8 @@ def use_g_vectors(self, use=True, force=False): sage: S.mutate(1) sage: S.use_c_vectors(False) sage: S.use_g_vectors(True) - Warning: Initializing g-vectors at this point could lead to inconsistent seed data. + Warning: Initializing g-vectors at this point + could lead to inconsistent seed data. sage: S.use_g_vectors(True, force=True) sage: S.g_matrix() @@ -498,7 +528,7 @@ def use_g_vectors(self, use=True, force=False): if self._use_g_vec != use: self._use_g_vec = use if self._use_g_vec: - #self._G = matrix.identity(self._n) if self._use_g_vec else None + # self._G = matrix.identity(self._n) if self._use_g_vec else None try: self._use_g_vec = False # temporarily turns off g-vectors to see if they can be recovered. self._G = self.g_matrix() # if not just sets it to be identity matrix, i.e. reinitialized. @@ -519,18 +549,20 @@ def use_g_vectors(self, use=True, force=False): self._G = None # Initially coded so c_vectors would be turned back on but now each of these boolean flags are independent - #if self._use_g_vec and not self._use_c_vec: + # if self._use_g_vec and not self._use_c_vec: # self.use_c_vectors(True) def use_d_vectors(self, use=True, force=False): r""" - Reconstruct d vectors from other data or initialize if no usable data exists. + Reconstruct d-vectors from other data or initialize if no usable data exists. - Warning: Initialization may lead to inconsistent data. + .. warning:: + + Initialization may lead to inconsistent data. INPUT: - - ``use`` -- (default:True) If True, will use d vectors + - ``use`` -- (default: ``True``) If ``True``, will use d-vectors EXAMPLES:: @@ -542,7 +574,8 @@ def use_d_vectors(self, use=True, force=False): [ 0 0 -1 0] [ 0 0 0 -1] - sage: S = ClusterSeed(['A',4]); S.use_d_vectors(False); S.track_mutations(False); S.mutate(1); S.d_matrix() + sage: S = ClusterSeed(['A',4]); S.use_d_vectors(False) + sage: S.track_mutations(False); S.mutate(1); S.d_matrix() [-1 0 0 0] [ 0 1 0 0] [ 0 0 -1 0] @@ -553,14 +586,16 @@ def use_d_vectors(self, use=True, force=False): ... ValueError: Unable to calculate d-vectors. Need to use d vectors. - sage: S = ClusterSeed(['A',4]); S.use_d_vectors(False); S.track_mutations(False); S.mutate(1); S.d_matrix() + sage: S = ClusterSeed(['A',4]); S.use_d_vectors(False) + sage: S.track_mutations(False); S.mutate(1); S.d_matrix() [-1 0 0 0] [ 0 1 0 0] [ 0 0 -1 0] [ 0 0 0 -1] sage: S.use_fpolys(False) sage: S.use_d_vectors(True) - Warning: Initializing d-vectors at this point could lead to inconsistent seed data. + Warning: Initializing d-vectors at this point + could lead to inconsistent seed data. sage: S.use_d_vectors(True, force=True) sage: S.d_matrix() @@ -574,7 +609,8 @@ def use_d_vectors(self, use=True, force=False): [ 0 1 0 0] [ 0 0 -1 0] [ 0 0 0 -1] - sage: S = ClusterSeed(['A',4]); S.use_d_vectors(True); S.mutate(1); S.d_matrix() + sage: S = ClusterSeed(['A',4]) + sage: S.use_d_vectors(True); S.mutate(1); S.d_matrix() [-1 0 0 0] [ 0 1 0 0] [ 0 0 -1 0] @@ -584,7 +620,7 @@ def use_d_vectors(self, use=True, force=False): self._use_d_vec = use if self._use_d_vec: try: - self._use_d_vec = False # temporarily turns off d-vectors to see if they can be recovered. + self._use_d_vec = False # temporarily turns off d-vectors to see if they can be recovered. self._D = self.d_matrix() self._use_d_vec = True except ValueError: @@ -606,13 +642,16 @@ def use_fpolys(self, use=True, user_labels=None, user_labels_prefix=None): r""" Use F-polynomials in our Cluster Seed - Note: This will automatically try to recompute the cluster variables if possible + Note: This will automatically try to recompute the cluster variables + if possible INPUT: - - ``use`` -- (default:True) If True, will use F-polynomials - - ``user_labels`` -- (default:None) If set will overwrite the default cluster variable labels - - ``user_labels_prefix`` -- (default:None) If set will overwrite the default + - ``use`` -- (default: ``True``) If ``True``, will use F-polynomials + - ``user_labels`` -- (default: ``None``) If set, will overwrite the + default cluster variable labels + - ``user_labels_prefix`` -- (default: ``None``) If set, will overwrite + the default EXAMPLES:: @@ -621,16 +660,17 @@ def use_fpolys(self, use=True, user_labels=None, user_labels_prefix=None): sage: S.cluster() [x0, x1, x2, x3] - sage: S = ClusterSeed(['A',4]); S.use_fpolys(False); S.track_mutations(False); S.mutate(1) + sage: S = ClusterSeed(['A',4]); S.use_fpolys(False); S.track_mutations(False) + sage: S.mutate(1) sage: S.use_fpolys(True) Traceback (most recent call last): ... - ValueError: F-polynomials and Cluster Variables cannot be reconstructed from given data. + ValueError: F-polynomials and Cluster Variables cannot be reconstructed + from given data. sage: S.cluster() Traceback (most recent call last): ... ValueError: Clusters not being tracked - """ if user_labels: self._user_labels = user_labels @@ -644,27 +684,29 @@ def use_fpolys(self, use=True, user_labels=None, user_labels_prefix=None): if user_labels: self._sanitize_init_vars(user_labels, user_labels_prefix) else: - xs = {i:'x%s'%i for i in range(self._n)} - ys = {(i+self._n):'y%s'%i for i in range(self._n+self._m)} + xs = {i: f'x{i}' for i in range(self._n)} + ys = {(i + self._n): f'y{i}' for i in range(self._n + self._m)} self._init_vars = copy(xs) self._init_vars.update(ys) - if self._G == matrix.identity(self._n): # If we are at the root + if self._G == matrix.identity(self._n): # If we are at the root if not self._use_g_vec: self.use_g_vectors(True) self._init_exch = dict(islice(self._init_vars.items(), self._n)) - self._U = PolynomialRing(QQ,['y%s' % i for i in range(self._n)]) - self._F = dict([(i,self._U(1)) for i in self._init_exch.values()]) - self._R = PolynomialRing(QQ,[val for val in self._init_vars.values()]) - self._y = dict([ (self._U.gen(j),prod([self._R.gen(i)**self._M[i,j] for i in range(self._n,self._n+self._m)])) for j in range(self._n)]) - self._yhat = dict([ (self._U.gen(j),prod([self._R.gen(i)**self._M[i,j] for i in range(self._n+self._m)])) for j in range(self._n)]) + self._U = PolynomialRing(QQ, [f'y{i}' for i in range(self._n)]) + self._F = {i: self._U(1) for i in self._init_exch.values()} + self._R = PolynomialRing(QQ, [val for val in self._init_vars.values()]) + self._y = {self._U.gen(j): prod([self._R.gen(i)**self._M[i, j] for i in range(self._n, self._n + self._m)]) + for j in range(self._n)} + self._yhat = {self._U.gen(j): prod([self._R.gen(i)**self._M[i, j] for i in range(self._n + self._m)]) + for j in range(self._n)} elif self._cluster: raise ValueError("should not be possible to have cluster variables without f-polynomials") # added this as a sanity check. This error should never appear however. - elif self._track_mut: # If we can navigate from the root to where we are + elif self._track_mut: # If we can navigate from the root to where we are if not self._use_g_vec: self.use_g_vectors(True) catchup = ClusterSeed(self._b_initial, user_labels=user_labels, user_labels_prefix=user_labels_prefix) - catchup.use_c_vectors(use=self._use_c_vec,bot_is_c=self._bot_is_c) + catchup.use_c_vectors(use=self._use_c_vec, bot_is_c=self._bot_is_c) catchup.mutate(self.mutations()) self._init_exch = catchup._init_exch @@ -695,13 +737,16 @@ def use_fpolys(self, use=True, user_labels=None, user_labels_prefix=None): def track_mutations(self, use=True): r""" - Begins tracking the mutation path. + Begin tracking the mutation path. - Warning: May initialize all other data to ensure that all c, d, and g vectors agree on the start of mutations. + .. warning:: + + May initialize all other data to ensure that all + c-, d-, and g-vectors agree on the start of mutations. INPUT: - - ``use`` -- (default:True) If True, will begin filling the mutation path + - ``use`` -- (default: ``True``) If ``True``, will begin filling the mutation path EXAMPLES:: @@ -722,7 +767,6 @@ def track_mutations(self, use=True): sage: S.mutations() [0, 1] """ - if self._track_mut != use: self._track_mut = use if self._track_mut: @@ -751,14 +795,15 @@ def track_mutations(self, use=True): else: self._mut_path = None - def _sanitize_init_vars(self, user_labels, user_labels_prefix = 'x'): + def _sanitize_init_vars(self, user_labels, user_labels_prefix='x'): r""" Rewrite a user-given set of cluster variable names into a format that Sage can utilize. INPUT: - ``user_labels`` -- The labels that need sanitizing - - ``user_labels_prefix`` -- (default:'x') The prefix to use for labels if integers given for labels + - ``user_labels_prefix`` -- (default: ``'x'``) The prefix to use + for labels if integers given for labels EXAMPLES:: @@ -821,12 +866,12 @@ def _sanitize_init_vars(self, user_labels, user_labels_prefix = 'x'): def set_c_matrix(self, data): r""" - Will force set the c matrix according to a matrix, a quiver, or a seed. + Will force set the c-matrix according to a matrix, a quiver, or a seed. INPUT: - - ``data`` -- The matrix to set the c matrix to. Also allowed - to be a quiver or cluster seed, in which case the b_matrix + - ``data`` -- The matrix to set the c-matrix to. Also allowed + to be a quiver or cluster seed, in which case the b-matrix is used. EXAMPLES:: @@ -841,7 +886,8 @@ def set_c_matrix(self, data): sage: Y = matrix([[-1,0,1],[0,1,0],[1,0,0]]) sage: S.set_c_matrix(Y) - C matrix does not look to be valid - there exists a column containing positive and negative entries. + C matrix does not look to be valid - there exists a column + containing positive and negative entries. Continuing... sage: Z = matrix([[1,0,1],[0,1,0],[2,0,2]]) @@ -852,7 +898,7 @@ def set_c_matrix(self, data): if isinstance(data, ClusterQuiver): data = data.b_matrix() if isinstance(matrix, ClusterSeed): - data=data.b_matrix() + data = data.b_matrix() if data.determinant() == 0: print("C matrix does not look to be valid - not a linearly independent set.") @@ -872,26 +918,26 @@ def set_c_matrix(self, data): def __eq__(self, other): r""" - Returns True iff ``self`` represent the same cluster seed as ``other`` and all tracked data agrees. + Return ``True`` iff ``self`` represent the same cluster seed as ``other`` and all tracked data agrees. EXAMPLES:: sage: S = ClusterSeed(['A',5]) - sage: T = S.mutate( 2, inplace=False ) - sage: S.__eq__( T ) + sage: T = S.mutate(2, inplace=False) + sage: S.__eq__(T) False - sage: T.mutate( 2 ) - sage: S.__eq__( T ) + sage: T.mutate(2) + sage: S.__eq__(T) True sage: S = ClusterSeed(['A',2]) sage: T = ClusterSeed(S) - sage: S.__eq__( T ) + sage: S.__eq__(T) True sage: S.mutate([0,1,0,1,0]) - sage: S.__eq__( T ) + sage: S.__eq__(T) False sage: S.cluster() [x1, x0] @@ -899,7 +945,7 @@ def __eq__(self, other): [x0, x1] sage: S.mutate([0,1,0,1,0]) - sage: S.__eq__( T ) + sage: S.__eq__(T) True sage: S.cluster() [x0, x1] @@ -945,7 +991,7 @@ def __hash__(self): def _repr_(self): r""" - Returns the description of ``self``. + Return the description of ``self``. EXAMPLES:: @@ -960,7 +1006,8 @@ def _repr_(self): """ name = self._description if self._mutation_type: - if type( self._mutation_type ) in [QuiverMutationType_Irreducible,QuiverMutationType_Reducible]: + if isinstance(self._mutation_type, (QuiverMutationType_Irreducible, + QuiverMutationType_Reducible)): name += ' of type ' + str(self._mutation_type) # the following case allows description of 'undetermined finite mutation type' else: @@ -975,25 +1022,31 @@ def _repr_(self): def plot(self, circular=False, mark=None, save_pos=False, force_c=False, with_greens=False, add_labels=False): r""" - Returns the plot of the quiver of ``self``. + Return the plot of the quiver of ``self``. INPUT: - - ``circular`` -- (default:False) if True, the circular plot is chosen, otherwise >>spring<< is used. - - ``mark`` -- (default: None) if set to i, the vertex i is highlighted. - - ``save_pos`` -- (default:False) if True, the positions of the vertices are saved. - - ``force_c`` -- (default:False) if True, will show the frozen vertices even if they were never initialized - - ``with_greens`` -- (default:False) if True, will display the green vertices in green - - ``add_labels`` -- (default:False) if True, will use the initial variables as labels + - ``circular`` -- (default: ``False``) if ``True``, the circular plot + is chosen, otherwise >>spring<< is used. + - ``mark`` -- (default: ``None``) if set to i, the vertex i is + highlighted. + - ``save_pos`` -- (default: ``False``) if ``True``, the positions + of the vertices are saved. + - ``force_c`` -- (default: ``False``) if ``True``, will show the frozen + vertices even if they were never initialized + - ``with_greens`` -- (default: ``False``) if ``True``, will display + the green vertices in green + - ``add_labels`` -- (default: ``False``) if ``True``, will use the + initial variables as labels EXAMPLES:: sage: S = ClusterSeed(['A',5]) - sage: S.plot() + sage: S.plot() # needs sage.plot sage.symbolic Graphics object consisting of 15 graphics primitives - sage: S.plot(circular=True) + sage: S.plot(circular=True) # needs sage.plot sage.symbolic Graphics object consisting of 15 graphics primitives - sage: S.plot(circular=True, mark=1) + sage: S.plot(circular=True, mark=1) # needs sage.plot sage.symbolic Graphics object consisting of 15 graphics primitives """ greens = [] @@ -1017,20 +1070,26 @@ def show(self, fig_size=1, circular=False, mark=None, save_pos=False, force_c=Fa INPUT: - - ``fig_size`` -- (default: 1) factor by which the size of the plot is multiplied. - - ``circular`` -- (default: False) if True, the circular plot is chosen, otherwise >>spring<< is used. - - ``mark`` -- (default: None) if set to i, the vertex i is highlighted. - - ``save_pos`` -- (default:False) if True, the positions of the vertices are saved. - - ``force_c`` -- (default:False) if True, will show the frozen vertices even if they were never initialized - - ``with_greens`` -- (default:False) if True, will display the green vertices in green - - ``add_labels`` -- (default:False) if True, will use the initial variables as labels + - ``fig_size`` -- (default: 1) factor by which the size of the plot + is multiplied. + - ``circular`` -- (default: ``False``) if ``True``, the circular plot + is chosen, otherwise >>spring<< is used. + - ``mark`` -- (default: ``None``) if set to i, the vertex i is + highlighted. + - ``save_pos`` -- (default: ``False``) if ``True``, the positions + of the vertices are saved. + - ``force_c`` -- (default: ``False``) if ``True``, will show the frozen + vertices even if they were never initialized + - ``with_greens`` -- (default: ``False``) if ``True``, will display the + green vertices in green + - ``add_labels`` -- (default: ``False``) if ``True``, will use the + initial variables as labels TESTS:: sage: S = ClusterSeed(['A',5]) - sage: S.show() # long time + sage: S.show() # long time # needs sage.plot sage.symbolic """ - greens = [] if with_greens: greens = self.green_vertices() @@ -1043,7 +1102,8 @@ def show(self, fig_size=1, circular=False, mark=None, save_pos=False, force_c=Fa else: quiver = self.quiver() - quiver.show(fig_size=fig_size, circular=circular,mark=mark,save_pos=save_pos, greens=greens) + quiver.show(fig_size=fig_size, circular=circular, mark=mark, + save_pos=save_pos, greens=greens) def interact(self, fig_size=1, circular=True): r""" @@ -1062,35 +1122,37 @@ def interact(self, fig_size=1, circular=True): TESTS:: sage: S = ClusterSeed(['A',4]) - sage: S.interact() + sage: S.interact() # needs sage.plot sage.symbolic ...VBox(children=... """ return cluster_interact(self, fig_size, circular, kind='seed') def save_image(self, filename, circular=False, mark=None, save_pos=False): r""" - Saves the plot of the underlying digraph of the quiver of ``self``. + Save the plot of the underlying digraph of the quiver of ``self``. INPUT: - ``filename`` -- the filename the image is saved to. - - ``circular`` -- (default: False) if True, the circular plot is chosen, otherwise >>spring<< is used. - - ``mark`` -- (default: None) if set to i, the vertex i is highlighted. - - ``save_pos`` -- (default:False) if True, the positions of the vertices are saved. + - ``circular`` -- (default: ``False``) if ``True``, the circular plot + is chosen, otherwise >>spring<< is used. + - ``mark`` -- (default: ``None``) if set to i, the vertex i is highlighted. + - ``save_pos`` -- (default: ``False``) if ``True``, the positions + of the vertices are saved. EXAMPLES:: sage: S = ClusterSeed(['F',4,[1,2]]) sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot sage.symbolic ....: S.save_image(f.name) """ - graph_plot = self.plot( circular=circular, mark=mark, save_pos=save_pos) - graph_plot.save( filename=filename ) + graph_plot = self.plot(circular=circular, mark=mark, save_pos=save_pos) + graph_plot.save(filename=filename) def b_matrix(self): r""" - Returns the `B` *-matrix* of ``self``. + Return the `B` *-matrix* of ``self``. EXAMPLES:: @@ -1122,7 +1184,7 @@ def b_matrix(self): def ground_field(self): r""" - Returns the *ground field* of the cluster of ``self``. + Return the *ground field* of the cluster of ``self``. EXAMPLES:: @@ -1135,7 +1197,7 @@ def ground_field(self): def x(self, k): r""" Return the `k` *-th initial cluster variable* for the associated cluster seed, - or the cluster variable of the corresponding vertex in self.quiver. + or the cluster variable of the corresponding vertex in ``self.quiver``. EXAMPLES:: @@ -1151,13 +1213,12 @@ def x(self, k): x2 sage: dg = DiGraph([['a', 'b'], ['b', 'c']], format="list_of_edges") - sage: S = ClusterSeed(dg, frozen = ['c']) + sage: S = ClusterSeed(dg, frozen=['c']) sage: S.x(0) a sage: S.x('a') a """ - if self._use_fpolys: if k in range(self._n): x = self._R.gens()[k] @@ -1169,14 +1230,13 @@ def x(self, k): mutation_type=self._mutation_type, variable_type='cluster variable', xdim=self._n) - else: - raise ValueError("The input is not in an index of a cluster variable.") + raise ValueError("the input is not in an index of a cluster variable") def y(self, k): r""" Return the `k` *-th initial coefficient (frozen variable)* for the associated cluster seed, or the cluster variable of the corresponding - vertex in self.quiver. + vertex in ``self.quiver``. EXAMPLES:: @@ -1192,13 +1252,12 @@ def y(self, k): y2 sage: dg = DiGraph([['a', 'b'], ['b', 'c']], format="list_of_edges") - sage: S = ClusterSeed(dg, frozen = ['c']) + sage: S = ClusterSeed(dg, frozen=['c']) sage: S.y(0) c sage: S.y('c') c """ - if self._use_fpolys: if k in range(self._m): x = self._R.gens()[self._n + k] @@ -1209,8 +1268,7 @@ def y(self, k): mutation_type=self._mutation_type, variable_type='frozen variable', xdim=self._n) - else: - raise ValueError("The input is not in an index of a frozen variable.") + raise ValueError("the input is not in an index of a frozen variable") def n(self): r""" @@ -1226,7 +1284,7 @@ def n(self): def m(self): r""" - Returns the number of *frozen variables* of ``self``. + Return the number of *frozen variables* of ``self``. EXAMPLES:: @@ -1250,7 +1308,7 @@ def free_vertices(self): EXAMPLES:: sage: S = ClusterSeed(DiGraph([['a', 'b'], ['c', 'b'], ['c', 'd'], ['e', 'd']]), - ....: frozen = ['b', 'd']) + ....: frozen=['b', 'd']) sage: S.free_vertices() ['a', 'c', 'e'] @@ -1267,7 +1325,7 @@ def frozen_vertices(self): EXAMPLES:: sage: S = ClusterSeed(DiGraph([['a', 'b'], ['c', 'b'], ['c', 'd'], ['e', 'd']]), - ....: frozen = ['b', 'd']) + ....: frozen=['b', 'd']) sage: sorted(S.frozen_vertices()) ['b', 'd'] """ @@ -1319,15 +1377,15 @@ def cluster_variable(self, k): elif k in IE: k = IE.index(k) - g_mon = prod([self._R.gen(i)**self._G[i,k] for i in range(self._n)]) + g_mon = prod([self._R.gen(i)**self._G[i, k] for i in range(self._n)]) F_num = self._F[IE[k]].subs(self._yhat) F_den = self._R(self._F[IE[k]].subs(self._y).denominator()) - cluster_variable = g_mon*F_num*F_den + cluster_variable = g_mon * F_num * F_den - return ClusterVariable(FractionField(self._R), cluster_variable.numerator(), cluster_variable.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable',xdim=self._n) + return ClusterVariable(FractionField(self._R), cluster_variable.numerator(), cluster_variable.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable', xdim=self._n) else: raise ValueError('No cluster variable with index or label ' + str(k) + '.') - elif self._track_mut: # if we can recreate the clusters + elif self._track_mut: # if we can recreate the clusters catchup = ClusterSeed(self._b_initial, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix) catchup.use_c_vectors(use=self._use_c_vec, bot_is_c=self._bot_is_c) catchup.mutate(self.mutations()) @@ -1337,7 +1395,7 @@ def cluster_variable(self, k): def cluster(self): r""" - Returns a copy of the *cluster* of ``self``. + Return a copy of the *cluster* of ``self``. EXAMPLES:: @@ -1359,7 +1417,7 @@ def cluster(self): """ if not self._use_fpolys: - if self._track_mut: # if we can recreate the clusters + if self._track_mut: # if we can recreate the clusters catchup = ClusterSeed(self._b_initial, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix) catchup.use_c_vectors(use=self._use_c_vec, bot_is_c=self._bot_is_c) catchup.mutate(self.mutations()) @@ -1370,7 +1428,7 @@ def cluster(self): self._cluster = [self.cluster_variable(k) for k in range(self._n)] return copy(self._cluster) - def _f_mutate( self, k): + def _f_mutate(self, k): r""" An internal procedure that returns ``self`` with F-polynomials mutated at k. @@ -1397,26 +1455,28 @@ def _f_mutate( self, k): neg = self._U(1) for j in range(self._n): - if C[j,k] > 0: - pos *= self._U.gen(j)**C[j,k] + if C[j, k] > 0: + pos *= self._U.gen(j)**C[j, k] else: - neg *= self._U.gen(j)**(-C[j,k]) - if B[j,k] > 0: - pos *= F[IE[j]]**B[j,k] + neg *= self._U.gen(j)**(-C[j, k]) + if B[j, k] > 0: + pos *= F[IE[j]]**B[j, k] else: - neg *= F[IE[j]]**(-B[j,k]) + neg *= F[IE[j]]**(-B[j, k]) # can the following be improved? - self._F[IE[k]] = (pos+neg)//F[IE[k]] + self._F[IE[k]] = (pos + neg) // F[IE[k]] - def f_polynomial(self,k): + def f_polynomial(self, k): r""" Return the ``k``-th *F-polynomial* of ``self``. It is obtained from the ``k``-th cluster variable by setting all `x_i` to `1`. - Warning: this method assumes the sign-coherence conjecture and that the - input seed is sign-coherent (has an exchange matrix with columns of like signs). - Otherwise, computational errors might arise. + .. warning:: + + This method assumes the sign-coherence conjecture and that the + input seed is sign-coherent (has an exchange matrix with columns of like signs). + Otherwise, computational errors might arise. EXAMPLES:: @@ -1425,7 +1485,8 @@ def f_polynomial(self,k): sage: [S.f_polynomial(k) for k in range(3)] [1, y1*y2 + y2 + 1, y1 + 1] - sage: S = ClusterSeed(Matrix([[0,1],[-1,0],[1,0],[-1,1]])); S.use_c_vectors(bot_is_c=True); S + sage: S = ClusterSeed(Matrix([[0,1],[-1,0],[1,0],[-1,1]])) + sage: S.use_c_vectors(bot_is_c=True); S A seed for a cluster algebra of rank 2 with 2 frozen variables sage: T = ClusterSeed(Matrix([[0,1],[-1,0]])).principal_extension(); T A seed for a cluster algebra of rank 2 with principal coefficients @@ -1443,7 +1504,7 @@ def f_polynomial(self,k): elif k in IE: k = IE.index(k) else: - raise ValueError("The cluster seed does not have a cluster variable of index %s."%k) + raise ValueError("The cluster seed does not have a cluster variable of index %s." % k) return self._F[IE[k]] elif self._track_mut: @@ -1453,16 +1514,18 @@ def f_polynomial(self,k): return catchup.f_polynomial(k) else: - raise ValueError("Turn on use_fpolys to get F polynomial %s."%k) + raise ValueError("Turn on use_fpolys to get F polynomial %s." % k) def f_polynomials(self): r""" Return all *F-polynomials* of ``self``. These are obtained from the cluster variables by setting all `x_i`'s to `1`. - Warning: this method assumes the sign-coherence conjecture and that the - input seed is sign-coherent (has an exchange matrix with columns of like signs). - Otherwise, computational errors might arise. + .. warning:: + + This method assumes the sign-coherence conjecture and that the + input seed is sign-coherent (has an exchange matrix with columns of like signs). + Otherwise, computational errors might arise. EXAMPLES:: @@ -1474,38 +1537,40 @@ def f_polynomials(self): return [self.f_polynomial(i) for i in range(self._n)] - def g_vector(self,k): + def g_vector(self, k): r""" Return the ``k``-th *g-vector* of ``self``. This is the degree vector of the ``k``-th cluster variable after setting all `y_i`'s to `0`. - Warning: this method assumes the sign-coherence conjecture and that the - input seed is sign-coherent (has an exchange matrix with columns of like signs). - Otherwise, computational errors might arise. + .. warning:: + + This method assumes the sign-coherence conjecture and that the + input seed is sign-coherent (has an exchange matrix with columns of like signs). + Otherwise, computational errors might arise. EXAMPLES:: sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutate([2,1,2]) - sage: [ S.g_vector(k) for k in range(3) ] + sage: [S.g_vector(k) for k in range(3)] [(1, 0, 0), (0, 0, -1), (0, -1, 0)] """ if not (self._is_principal or self._use_g_vec or (self._use_fpolys and self._cluster)): raise ValueError("Unable to calculate g-vectors. Need to use g vectors.") if k not in range(self._n): - raise ValueError("The cluster seed does not have a cluster variable of index %s."%k) + raise ValueError("The cluster seed does not have a cluster variable of index %s." % k) - if self._use_g_vec: # This implies the g-matrix is maintained by the mutate function and will always be up to date + if self._use_g_vec: # This implies the g-matrix is maintained by the mutate function and will always be up to date return copy(self._G.column(k)) elif self._use_fpolys and self._cluster: f = copy(self.cluster_variable(k)) - eval_dict = dict( [ ( self.y(i), 0 ) for i in range(self._m) ] ) + eval_dict = {self.y(i): 0 for i in range(self._m)} f0 = f.subs(eval_dict) d1 = f0.numerator().degrees() d2 = f0.denominator().degrees() - return tuple( d1[i] - d2[i] for i in range(self._n) ) - else: # in the is_principal=True case + return tuple(d1[i] - d2[i] for i in range(self._n)) + else: # in the is_principal=True case try: # ensure that we cannot create a loop by calling g_matrix() here by filtering out loop causing conditions in the previous if-elif sections return self.g_matrix().column(k) @@ -1517,9 +1582,11 @@ def g_matrix(self, show_warnings=True): Return the matrix of all *g-vectors* of ``self``. These are the degree vectors of the cluster variables after setting all `y_i`'s to `0`. - Warning: this method assumes the sign-coherence conjecture and that the - input seed is sign-coherent (has an exchange matrix with columns of like signs). - Otherwise, computational errors might arise. + .. warning:: + + This method assumes the sign-coherence conjecture and that the + input seed is sign-coherent (has an exchange matrix with columns of like signs). + Otherwise, computational errors might arise. EXAMPLES:: @@ -1537,14 +1604,16 @@ def g_matrix(self, show_warnings=True): [ 1 0 0] [ 0 0 1] - sage: S = ClusterSeed(['A',4]); S.use_g_vectors(False); S.use_fpolys(False); S.g_matrix() + sage: S = ClusterSeed(['A',4]) + sage: S.use_g_vectors(False); S.use_fpolys(False); S.g_matrix() [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] sage: S = ClusterSeed(['A',4]) - sage: S.use_g_vectors(False); S.use_c_vectors(False); S.use_fpolys(False); S.track_mutations(False); S.g_matrix() + sage: S.use_g_vectors(False); S.use_c_vectors(False); S.use_fpolys(False) + sage: S.track_mutations(False); S.g_matrix() Traceback (most recent call last): ... ValueError: Unable to calculate g-vectors. Need to use g vectors. @@ -1553,8 +1622,8 @@ def g_matrix(self, show_warnings=True): from sage.matrix.constructor import matrix if self._use_g_vec: return copy(self._G) - elif self._use_fpolys and self._cluster: # This only calls g_vector when it will not create a loop. - return matrix( [ self.g_vector(k) for k in range(self._n) ] ).transpose() + elif self._use_fpolys and self._cluster: # This only calls g_vector when it will not create a loop. + return matrix([self.g_vector(k) for k in range(self._n)]).transpose() elif self._use_c_vec: if self.b_matrix().is_skew_symmetric(): return copy(self._C).inverse().transpose() @@ -1565,7 +1634,7 @@ def g_matrix(self, show_warnings=True): seq = iter(self.mutations()) for k in seq: BC1.mutate(k) - return copy(BC1[self._n:2*self._n]).inverse().transpose() + return copy(BC1[self._n:2 * self._n]).inverse().transpose() else: raise ValueError("Unable to calculate g-vectors. Need to use g vectors.") elif self._track_mut: @@ -1607,25 +1676,27 @@ def _g_mutate(self, k): else: eps = -1 for j in range(self._n): - J[j,k] += max(0, -eps*B[j,k]) - J[k,k] = -1 + J[j, k] += max(0, -eps * B[j, k]) + J[k, k] = -1 self._G = self._G * J - def c_vector(self,k): + def c_vector(self, k): r""" Return the ``k``-th *c-vector* of ``self``. It is obtained as the ``k``-th column vector of the bottom part of the ``B``-matrix of ``self``. - Warning: this method assumes the sign-coherence conjecture and that the - input seed is sign-coherent (has an exchange matrix with columns of like signs). - Otherwise, computational errors might arise. + .. warning:: + + This method assumes the sign-coherence conjecture and that the + input seed is sign-coherent (has an exchange matrix with columns of like signs). + Otherwise, computational errors might arise. EXAMPLES:: sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutate([2,1,2]) - sage: [ S.c_vector(k) for k in range(3) ] + sage: [S.c_vector(k) for k in range(3)] [(1, 0, 0), (0, 0, -1), (0, -1, 0)] sage: S = ClusterSeed(Matrix([[0,1],[-1,0],[1,0],[-1,1]])); S @@ -1633,28 +1704,30 @@ def c_vector(self,k): sage: S.c_vector(0) (1, 0) - sage: S = ClusterSeed(Matrix([[0,1],[-1,0],[1,0],[-1,1]])); S.use_c_vectors(bot_is_c=True); S + sage: S = ClusterSeed(Matrix([[0,1],[-1,0],[1,0],[-1,1]])) + sage: S.use_c_vectors(bot_is_c=True); S A seed for a cluster algebra of rank 2 with 2 frozen variables sage: S.c_vector(0) (1, -1) """ if k not in range(self._n): - raise ValueError("The cluster seed does not have a c-vector of index %s."%k) + raise ValueError("The cluster seed does not have a c-vector of index %s." % k) if not (self._is_principal or self._use_c_vec): raise ValueError("Requires C vectors to use.") if self._use_c_vec: return self.c_matrix().column(k) - else: - return tuple( self._M[i,k] for i in range(self._n,self._n+self._m) ) + return tuple(self._M[i, k] for i in range(self._n, self._n + self._m)) - def c_matrix(self,show_warnings=True): + def c_matrix(self, show_warnings=True): r""" Return all *c-vectors* of ``self``. - Warning: this method assumes the sign-coherence conjecture and that the - input seed is sign-coherent (has an exchange matrix with columns of like signs). - Otherwise, computational errors might arise. + .. warning:: + + This method assumes the sign-coherence conjecture and that the + input seed is sign-coherent (has an exchange matrix with columns of like signs). + Otherwise, computational errors might arise. EXAMPLES:: @@ -1666,7 +1739,8 @@ def c_matrix(self,show_warnings=True): [ 0 -1 0] sage: S = ClusterSeed(['A',4]) - sage: S.use_g_vectors(False); S.use_fpolys(False); S.use_c_vectors(False); S.use_d_vectors(False); S.track_mutations(False); + sage: S.use_g_vectors(False); S.use_fpolys(False) + sage: S.use_c_vectors(False); S.use_d_vectors(False); S.track_mutations(False) sage: S.c_matrix() Traceback (most recent call last): ... @@ -1674,10 +1748,10 @@ def c_matrix(self,show_warnings=True): """ if self._bot_is_c: - return copy(self._M[self._m:(self._n+self._m),:self._n]) + return copy(self._M[self._m:(self._n + self._m), :self._n]) elif self._use_c_vec: return copy(self._C) - elif self._use_g_vec or self._use_fpolys: #both of these will populate g_matrix() successfully + elif self._use_g_vec or self._use_fpolys: # both of these will populate g_matrix() successfully if self.b_matrix().is_skew_symmetric(): return self.g_matrix().inverse().transpose() elif self._track_mut: @@ -1686,7 +1760,7 @@ def c_matrix(self,show_warnings=True): seq = iter(self.mutations()) for k in seq: BC1.mutate(k) - return copy(BC1[self._n:2*self._n]) + return copy(BC1[self._n:2 * self._n]) else: raise ValueError("Unable to calculate c-vectors. Need to use c vectors.") elif self._track_mut: @@ -1695,7 +1769,7 @@ def c_matrix(self,show_warnings=True): seq = iter(self.mutations()) for k in seq: BC1.mutate(k) - return copy(BC1[self._n:2*self._n]) + return copy(BC1[self._n:2 * self._n]) elif show_warnings: raise ValueError("Unable to calculate c-vectors. Need to use c vectors.") else: @@ -1710,7 +1784,7 @@ def d_vector(self, k): sage: S = ClusterSeed(['A',3]) sage: S.mutate([2,1,2]) - sage: [ S.d_vector(k) for k in range(3) ] + sage: [S.d_vector(k) for k in range(3)] [(-1, 0, 0), (0, 1, 1), (0, 1, 0)] """ from sage.modules.free_module_element import vector @@ -1731,7 +1805,7 @@ def d_vector(self, k): catchup.mutate(self.mutations()) return copy(catchup._D).column(k) else: - raise ValueError("Unable to calculate d-vector %s. Need to use d vectors."%k) + raise ValueError("Unable to calculate d-vector %s. Need to use d vectors." % k) def d_matrix(self, show_warnings=True): r""" @@ -1753,12 +1827,12 @@ def d_matrix(self, show_warnings=True): """ if not (self._use_d_vec or self._use_fpolys or self._track_mut): - #raise ValueError("No d-vectors initialized.") + # raise ValueError("No d-vectors initialized.") raise ValueError("Unable to calculate d-vectors. Need to use d vectors.") if self._use_d_vec: return copy(self._D) elif self._use_fpolys: - return matrix( [ self.d_vector(k) for k in range(self._n) ] ).transpose() + return matrix([self.d_vector(k) for k in range(self._n)]).transpose() elif self._track_mut: catchup = ClusterSeed(self._b_initial) catchup.use_fpolys(False) @@ -1792,20 +1866,20 @@ def _d_mutate(self, k): B = self.b_matrix() D = copy(self._D) dnew = copy(-D.column(k)) - dp = copy( dnew.parent().zero() ) - dn = copy( dnew.parent().zero() ) - dmax = copy( dnew.parent().zero() ) + dp = copy(dnew.parent().zero()) + dn = copy(dnew.parent().zero()) + dmax = copy(dnew.parent().zero()) for j in range(self._n): - if B[j,k] >0: - dp += B[j,k]*D.column(j) - elif B[j,k] <0: - dn -= B[j,k]*D.column(j) + if B[j, k] > 0: + dp += B[j, k] * D.column(j) + elif B[j, k] < 0: + dn -= B[j, k] * D.column(j) for i in range(self._n): - dmax[i] = max(dp[i],dn[i]) - self._D.set_column(k,dnew+dmax) + dmax[i] = max(dp[i], dn[i]) + self._D.set_column(k, dnew + dmax) - def coefficient(self,k): + def coefficient(self, k): r""" Return the *coefficient* of ``self`` at index ``k``, or vertex ``k`` if ``k`` is not an index. @@ -1814,7 +1888,7 @@ def coefficient(self,k): sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutate([2,1,2]) - sage: [ S.coefficient(k) for k in range(3) ] + sage: [S.coefficient(k) for k in range(3)] [y0, 1/y2, 1/y1] """ from sage.misc.misc_c import prod @@ -1822,7 +1896,7 @@ def coefficient(self,k): if k in self._nlist: k = self._nlist.index(k) if k not in range(self._n): - raise ValueError("The cluster seed does not have a coefficient of index %s."%k) + raise ValueError("The cluster seed does not have a coefficient of index %s." % k) if self._m == 0: return self.x(0)**0 else: @@ -1831,7 +1905,7 @@ def coefficient(self,k): except Exception: # if not try and reconstruct them exp = self.c_matrix().column(k) - return prod( self.y(i)**exp[i] for i in range(self._m) ) + return prod(self.y(i)**exp[i] for i in range(self._m)) def coefficients(self): r""" @@ -1845,7 +1919,7 @@ def coefficients(self): [y0, 1/y2, 1/y1] """ # exceptions are caught in the subroutine. - return [ self.coefficient(k) for k in range(self._n) ] + return [self.coefficient(k) for k in range(self._n)] def quiver(self): r""" @@ -1859,12 +1933,13 @@ def quiver(self): """ from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver if self._quiver is None: - self._quiver = ClusterQuiver(self._M, user_labels=self._nlist+self._mlist) + self._quiver = ClusterQuiver(self._M, + user_labels=self._nlist + self._mlist) return self._quiver - def is_acyclic(self): + def is_acyclic(self) -> bool: r""" - Return True iff self is acyclic (i.e., if the underlying quiver is acyclic). + Return ``True`` iff ``self`` is acyclic (i.e., if the underlying quiver is acyclic). EXAMPLES:: @@ -1877,16 +1952,16 @@ def is_acyclic(self): sage: ClusterSeed([[0,1],[1,2],[2,0]]).is_acyclic() False """ - return self.quiver()._digraph.is_directed_acyclic() - def is_bipartite(self,return_bipartition=False): + def is_bipartite(self, return_bipartition=False): r""" - Return True iff self is bipartite (i.e., if the underlying quiver is bipartite). + Return ``True`` iff ``self`` is bipartite (i.e., if the underlying quiver is bipartite). INPUT: - - return_bipartition -- (default:False) if True, the bipartition is returned in the case of ``self`` being bipartite. + - ``return_bipartition`` -- (default: ``False``) if ``True``, the + bipartition is returned in the case of ``self`` being bipartite. EXAMPLES:: @@ -1896,7 +1971,6 @@ def is_bipartite(self,return_bipartition=False): sage: ClusterSeed(['A',[4,3],1]).is_bipartite() False """ - return self.quiver().is_bipartite(return_bipartition=return_bipartition) def green_vertices(self): @@ -2019,7 +2093,7 @@ def urban_renewals(self, return_first=False): INPUT: - - ``return_first`` -- (default:False) if True, will return the first urban renewal + - ``return_first`` -- (default: ``False``) if ``True``, will return the first urban renewal OUTPUT: @@ -2061,7 +2135,7 @@ def highest_degree_denominator(self, filter=None): INPUT: - - ``filter`` - Filter should be a list or iterable + - ``filter`` -- a list or iterable OUTPUT: @@ -2069,7 +2143,8 @@ def highest_degree_denominator(self, filter=None): EXAMPLES:: - sage: B = matrix([[0,-1,0,-1,1,1],[1,0,1,0,-1,-1],[0,-1,0,-1,1,1],[1,0,1,0,-1,-1],[-1,1,-1,1,0,0],[-1,1,-1,1,0,0]]) + sage: B = matrix([[0,-1,0,-1,1,1], [1,0,1,0,-1,-1], [0,-1,0,-1,1,1], + ....: [1,0,1,0,-1,-1], [-1,1,-1,1,0,0], [-1,1,-1,1,0,0]]) sage: C = ClusterSeed(B).principal_extension(); C.mutate([0,1,2,4,3,2,5,4,3]) sage: C.highest_degree_denominator() 5 @@ -2107,20 +2182,17 @@ def highest_degree_denominator(self, filter=None): def smallest_c_vector(self): r""" - Return the vertex with the smallest c vector. + Return the vertex with the smallest c-vector. - OUTPUT: - - An integer. + OUTPUT: An integer. EXAMPLES:: - sage: B = matrix([[0,2],[-2,0]]) + sage: B = matrix([[0,2], [-2,0]]) sage: C = ClusterSeed(B).principal_extension() sage: C.mutate(0) sage: C.smallest_c_vector() 0 - """ min_sum = infinity vertex_to_mutate = [] @@ -2135,12 +2207,11 @@ def smallest_c_vector(self): min_sum = cur_vertex_sum vertex_to_mutate = [vertex] - return_key = randint(0,len(vertex_to_mutate) - 1) + return_key = randint(0, len(vertex_to_mutate) - 1) return vertex_to_mutate[return_key] def most_decreased_edge_after_mutation(self): r""" - Return the vertex that will produce the least degrees after mutation EXAMPLES:: @@ -2149,12 +2220,11 @@ def most_decreased_edge_after_mutation(self): sage: S.mutate([0,2,3,1,2,3,1,2,0,2,3]) sage: S.most_decreased_edge_after_mutation() 2 - """ analysis = self.mutation_analysis(['edge_diff']) least_edge = infinity least_vertex = [] - for edge,edge_analysis in analysis.items(): + for edge, edge_analysis in analysis.items(): if least_edge == edge_analysis['edge_diff']: least_vertex.append(edge) if least_edge > edge_analysis['edge_diff']: @@ -2170,7 +2240,6 @@ def most_decreased_edge_after_mutation(self): def most_decreased_denominator_after_mutation(self): r""" - Return the vertex that will produce the most decrease in denominator degrees after mutation EXAMPLES:: @@ -2179,13 +2248,12 @@ def most_decreased_denominator_after_mutation(self): sage: S.mutate([0,2,3,1,2,3,1,2,0,2,3]) sage: S.most_decreased_denominator_after_mutation() 2 - """ analysis = self.mutation_analysis(['d_matrix']) least_change = infinity least_vertex = [] current_columns = [sum(i) for i in self.d_matrix().columns()] - for vertex,edge_analysis in analysis.items(): + for vertex, edge_analysis in analysis.items(): mutated_column = sum(edge_analysis['d_matrix'].column(vertex)) diff = mutated_column - current_columns[vertex] @@ -2195,7 +2263,7 @@ def most_decreased_denominator_after_mutation(self): least_change = diff least_vertex = [vertex] - return_key = randint(0,len(least_vertex) - 1) + return_key = randint(0, len(least_vertex) - 1) return least_vertex[return_key] def mutate(self, sequence, inplace=True, input_type=None): @@ -2222,7 +2290,8 @@ def mutate(self, sequence, inplace=True, input_type=None): - ``"green"``: mutates at the first green vertex, - ``"red"``: mutates at the first red vertex, - ``"urban_renewal"`` or ``"urban"``: mutates at first urban renewal vertex, - - ``"all_urban_renewals"`` or ``"all_urban"``: mutates at all urban renewal vertices. + - ``"all_urban_renewals"`` or ``"all_urban"``: mutates at all + urban renewal vertices. For ``input_type``, if no value is given, preference will be given to vertex names, then indices, then cluster variables. @@ -2469,7 +2538,7 @@ def mutate(self, sequence, inplace=True, input_type=None): n, m = seed.n(), seed.m() if (sequence in range(n) or sequence in IE - or isinstance(sequence, str) or sequence in seed._nlist): + or isinstance(sequence, str) or sequence in seed._nlist): seqq = [sequence] else: seqq = sequence @@ -2583,15 +2652,15 @@ def mutate(self, sequence, inplace=True, input_type=None): seed._d_mutate(k) seed._BC.mutate(k) - seed._M = copy(seed._BC[:n+m,:n]) + seed._M = copy(seed._BC[:n + m, :n]) self._M.set_immutable() if seed._use_c_vec: - seed._C = seed._BC[n+m:2*n+m,:n+m] + seed._C = seed._BC[n + m:2 * n + m, :n + m] if seed._track_mut: # delete involutive mutations - if len(seed._mut_path) == 0 or seed._mut_path[len(self._mut_path)-1] != k: + if len(seed._mut_path) == 0 or seed._mut_path[len(self._mut_path) - 1] != k: seed._mut_path.append(k) else: seed._mut_path.pop() @@ -2644,13 +2713,23 @@ def mutation_sequence(self, sequence, show_sequence=False, INPUT: - ``sequence`` -- an iterable of vertices of self. - - ``show_sequence`` -- (default: False) if True, a png containing the associated quivers is shown. - - ``fig_size`` -- (default: 1.2) factor by which the size of the plot is multiplied. - - ``return_output`` -- (default: 'seed') determines what output is to be returned:: - * if 'seed', outputs all the cluster seeds obtained by the ``sequence`` of mutations. - * if 'matrix', outputs a list of exchange matrices. - * if 'var', outputs a list of new cluster variables obtained at each step. + - ``show_sequence`` -- (default: ``False``) if ``True``, a png + containing the associated quivers is shown. + + - ``fig_size`` -- (default: 1.2) factor by which the size of + the plot is multiplied. + + - ``return_output`` -- (default: ``'seed'``) determines what output + is to be returned: + + * if ``'seed'``, outputs all the cluster seeds obtained + by the ``sequence`` of mutations. + + * if ``'matrix'``, outputs a list of exchange matrices. + + * if ``'var'``, outputs a list of new cluster variables obtained + at each step. EXAMPLES:: @@ -2679,7 +2758,7 @@ def mutation_sequence(self, sequence, show_sequence=False, seed_sequence.append(seed) if show_sequence: - self.quiver().mutation_sequence2(sequence=sequence, show_sequence=True, fig_size=fig_size ) + self.quiver().mutation_sequence2(sequence=sequence, show_sequence=True, fig_size=fig_size) if return_output == 'seed': return seed_sequence @@ -2694,12 +2773,15 @@ def mutation_analysis(self, options=['all'], filter=None): r""" Runs an analysis of all potential mutation options. Note that this might take a long time on large seeds. - Notes: Edges are only returned if we have a non-valued quiver. Green and red vertices are only returned if the cluster is principal. + .. note:: + + Edges are only returned if we have a non-valued quiver. + Green and red vertices are only returned if the cluster is principal. INPUT: - - ``options`` -- (default: ['all']) a list of mutation options. - - ``filter`` -- (default: None) A vertex or interval of vertices to limit our search to + - ``options`` -- (default: ``['all']``) a list of mutation options. + - ``filter`` -- (default: ``None``) A vertex or interval of vertices to limit our search to Possible options are: @@ -2722,7 +2804,7 @@ def mutation_analysis(self, options=['all'], filter=None): Outputs a dictionary indexed by the vertex numbers. Each vertex will itself also be a dictionary with each desired option included as a key in the dictionary. As an example - you would get something similar to: {0: {'edges': 1}, 1: {'edges': 2}}. This represents + you would get something similar to: ``{0: {'edges': 1}, 1: {'edges': 2}}``. This represents that if you were to do a mutation at the current seed then mutating at vertex 0 would result in a quiver with 1 edge and mutating at vertex 0 would result in a quiver with 2 edges. @@ -2732,118 +2814,118 @@ def mutation_analysis(self, options=['all'], filter=None): sage: S = ClusterSeed(matrix(B)); S.mutate([2,3,1,2,1,3,0,2]) sage: S.mutation_analysis() {0: {'d_matrix': [ 0 0 1 0] - [ 0 -1 0 0] - [ 0 0 0 -1] - [-1 0 0 0], - 'denominators': [1, 1, x0, 1], - 'edge_diff': 6, - 'edges': 13, - 'green_vertices': [0, 1, 3], - 'green_vertices_diff': {'added': [0], 'removed': []}, - 'red_vertices': [2], - 'red_vertices_diff': {'added': [], 'removed': [0]}, - 'sinks': [], - 'sinks_diff': {'added': [], 'removed': [2]}, - 'sources': [], - 'sources_diff': {'added': [], 'removed': []}, - 'urban_renewals': [], - 'urban_renewals_diff': {'added': [], 'removed': []}}, + [ 0 -1 0 0] + [ 0 0 0 -1] + [-1 0 0 0], + 'denominators': [1, 1, x0, 1], + 'edge_diff': 6, + 'edges': 13, + 'green_vertices': [0, 1, 3], + 'green_vertices_diff': {'added': [0], 'removed': []}, + 'red_vertices': [2], + 'red_vertices_diff': {'added': [], 'removed': [0]}, + 'sinks': [], + 'sinks_diff': {'added': [], 'removed': [2]}, + 'sources': [], + 'sources_diff': {'added': [], 'removed': []}, + 'urban_renewals': [], + 'urban_renewals_diff': {'added': [], 'removed': []}}, 1: {'d_matrix': [ 1 4 1 0] - [ 0 1 0 0] - [ 0 0 0 -1] - [ 1 4 0 0], - 'denominators': [x0*x3, x0^4*x1*x3^4, x0, 1], - 'edge_diff': 2, - 'edges': 9, - 'green_vertices': [0, 3], - 'green_vertices_diff': {'added': [0], 'removed': [1]}, - 'red_vertices': [1, 2], - 'red_vertices_diff': {'added': [1], 'removed': [0]}, - 'sinks': [2], - 'sinks_diff': {'added': [], 'removed': []}, - 'sources': [], - 'sources_diff': {'added': [], 'removed': []}, - 'urban_renewals': [], - 'urban_renewals_diff': {'added': [], 'removed': []}}, + [ 0 1 0 0] + [ 0 0 0 -1] + [ 1 4 0 0], + 'denominators': [x0*x3, x0^4*x1*x3^4, x0, 1], + 'edge_diff': 2, + 'edges': 9, + 'green_vertices': [0, 3], + 'green_vertices_diff': {'added': [0], 'removed': [1]}, + 'red_vertices': [1, 2], + 'red_vertices_diff': {'added': [1], 'removed': [0]}, + 'sinks': [2], + 'sinks_diff': {'added': [], 'removed': []}, + 'sources': [], + 'sources_diff': {'added': [], 'removed': []}, + 'urban_renewals': [], + 'urban_renewals_diff': {'added': [], 'removed': []}}, 2: {'d_matrix': [ 1 0 0 0] - [ 0 -1 0 0] - [ 0 0 0 -1] - [ 1 0 1 0], - 'denominators': [x0*x3, 1, x3, 1], - 'edge_diff': 0, - 'edges': 7, - 'green_vertices': [1, 2, 3], - 'green_vertices_diff': {'added': [2], 'removed': []}, - 'red_vertices': [0], - 'red_vertices_diff': {'added': [], 'removed': [2]}, - 'sinks': [], - 'sinks_diff': {'added': [], 'removed': [2]}, - 'sources': [2], - 'sources_diff': {'added': [2], 'removed': []}, - 'urban_renewals': [], - 'urban_renewals_diff': {'added': [], 'removed': []}}, + [ 0 -1 0 0] + [ 0 0 0 -1] + [ 1 0 1 0], + 'denominators': [x0*x3, 1, x3, 1], + 'edge_diff': 0, + 'edges': 7, + 'green_vertices': [1, 2, 3], + 'green_vertices_diff': {'added': [2], 'removed': []}, + 'red_vertices': [0], + 'red_vertices_diff': {'added': [], 'removed': [2]}, + 'sinks': [], + 'sinks_diff': {'added': [], 'removed': [2]}, + 'sources': [2], + 'sources_diff': {'added': [2], 'removed': []}, + 'urban_renewals': [], + 'urban_renewals_diff': {'added': [], 'removed': []}}, 3: {'d_matrix': [ 1 0 1 1] - [ 0 -1 0 0] - [ 0 0 0 1] - [ 1 0 0 1], - 'denominators': [x0*x3, 1, x0, x0*x2*x3], - 'edge_diff': -1, - 'edges': 6, - 'green_vertices': [1], - 'green_vertices_diff': {'added': [], 'removed': [3]}, - 'red_vertices': [0, 2, 3], - 'red_vertices_diff': {'added': [3], 'removed': []}, - 'sinks': [2], - 'sinks_diff': {'added': [], 'removed': []}, - 'sources': [1], - 'sources_diff': {'added': [1], 'removed': []}, - 'urban_renewals': [], - 'urban_renewals_diff': {'added': [], 'removed': []}}} + [ 0 -1 0 0] + [ 0 0 0 1] + [ 1 0 0 1], + 'denominators': [x0*x3, 1, x0, x0*x2*x3], + 'edge_diff': -1, + 'edges': 6, + 'green_vertices': [1], + 'green_vertices_diff': {'added': [], 'removed': [3]}, + 'red_vertices': [0, 2, 3], + 'red_vertices_diff': {'added': [3], 'removed': []}, + 'sinks': [2], + 'sinks_diff': {'added': [], 'removed': []}, + 'sources': [1], + 'sources_diff': {'added': [1], 'removed': []}, + 'urban_renewals': [], + 'urban_renewals_diff': {'added': [], 'removed': []}}} sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutation_analysis() {0: {'d_matrix': [ 1 0 0] - [ 0 -1 0] - [ 0 0 -1], - 'denominators': [x0, 1, 1], - 'green_vertices': [1, 2], - 'green_vertices_diff': {'added': [], 'removed': [0]}, - 'red_vertices': [0], - 'red_vertices_diff': {'added': [0], 'removed': []}, - 'sinks': [], - 'sinks_diff': {'added': [], 'removed': [1]}, - 'sources': [4, 5], - 'sources_diff': {'added': [], 'removed': [3]}, - 'urban_renewals': [], - 'urban_renewals_diff': {'added': [], 'removed': []}}, + [ 0 -1 0] + [ 0 0 -1], + 'denominators': [x0, 1, 1], + 'green_vertices': [1, 2], + 'green_vertices_diff': {'added': [], 'removed': [0]}, + 'red_vertices': [0], + 'red_vertices_diff': {'added': [0], 'removed': []}, + 'sinks': [], + 'sinks_diff': {'added': [], 'removed': [1]}, + 'sources': [4, 5], + 'sources_diff': {'added': [], 'removed': [3]}, + 'urban_renewals': [], + 'urban_renewals_diff': {'added': [], 'removed': []}}, 1: {'d_matrix': [-1 0 0] - [ 0 1 0] - [ 0 0 -1], - 'denominators': [1, x1, 1], - 'green_vertices': [0, 2], - 'green_vertices_diff': {'added': [], 'removed': [1]}, - 'red_vertices': [1], - 'red_vertices_diff': {'added': [1], 'removed': []}, - 'sinks': [0, 2, 4], - 'sinks_diff': {'added': [0, 2, 4], 'removed': [1]}, - 'sources': [1, 3, 5], - 'sources_diff': {'added': [1], 'removed': [4]}, - 'urban_renewals': [], - 'urban_renewals_diff': {'added': [], 'removed': []}}, + [ 0 1 0] + [ 0 0 -1], + 'denominators': [1, x1, 1], + 'green_vertices': [0, 2], + 'green_vertices_diff': {'added': [], 'removed': [1]}, + 'red_vertices': [1], + 'red_vertices_diff': {'added': [1], 'removed': []}, + 'sinks': [0, 2, 4], + 'sinks_diff': {'added': [0, 2, 4], 'removed': [1]}, + 'sources': [1, 3, 5], + 'sources_diff': {'added': [1], 'removed': [4]}, + 'urban_renewals': [], + 'urban_renewals_diff': {'added': [], 'removed': []}}, 2: {'d_matrix': [-1 0 0] - [ 0 -1 0] - [ 0 0 1], - 'denominators': [1, 1, x2], - 'green_vertices': [0, 1], - 'green_vertices_diff': {'added': [], 'removed': [2]}, - 'red_vertices': [2], - 'red_vertices_diff': {'added': [2], 'removed': []}, - 'sinks': [], - 'sinks_diff': {'added': [], 'removed': [1]}, - 'sources': [3, 4], - 'sources_diff': {'added': [], 'removed': [5]}, - 'urban_renewals': [], - 'urban_renewals_diff': {'added': [], 'removed': []}}} + [ 0 -1 0] + [ 0 0 1], + 'denominators': [1, 1, x2], + 'green_vertices': [0, 1], + 'green_vertices_diff': {'added': [], 'removed': [2]}, + 'red_vertices': [2], + 'red_vertices_diff': {'added': [2], 'removed': []}, + 'sinks': [], + 'sinks_diff': {'added': [], 'removed': [1]}, + 'sources': [3, 4], + 'sources_diff': {'added': [], 'removed': [5]}, + 'urban_renewals': [], + 'urban_renewals_diff': {'added': [], 'removed': []}}} """ V = range(self._n) if filter is None: @@ -2865,14 +2947,14 @@ def mutation_analysis(self, options=['all'], filter=None): if 'sinks_diff' in options or 'all' in options: initial_sinks = self.quiver().sinks() - #instantiate our dictionary + # instantiate our dictionary analysis = {} for i in filter: - #instantiate our dictionary + # instantiate our dictionary analysis[i] = {} - #run mutations not in place as we just want an analysis - current_mutation = self.mutate(i,inplace=False) + # run mutations not in place as we just want an analysis + current_mutation = self.mutate(i, inplace=False) if ('edges' in options or 'all' in options) and self._M.is_skew_symmetric(): analysis[i]['edges'] = current_mutation.quiver().number_of_edges() @@ -2937,7 +3019,7 @@ def exchangeable_part(self): EXAMPLES:: sage: S = ClusterSeed(['A',4]) - sage: T = ClusterSeed( S.quiver().digraph().edges(sort=True), frozen=[3] ) + sage: T = ClusterSeed(S.quiver().digraph().edges(sort=True), frozen=[3]) sage: T.quiver().digraph().edges(sort=True) [(0, 1, (1, -1)), (2, 1, (1, -1)), (2, 3, (1, -1))] @@ -2946,7 +3028,7 @@ def exchangeable_part(self): """ from sage.combinat.cluster_algebra_quiver.mutation_class import _principal_part - eval_dict = dict( [ ( self.y(i), 1 ) for i in range(self._m) ] ) + eval_dict = {self.y(i): 1 for i in range(self._m)} seed = ClusterSeed(_principal_part(self._M), is_principal=True, user_labels=self._nlist, user_labels_prefix=self._user_labels_prefix, @@ -3020,7 +3102,7 @@ def universal_extension(self): [ 0 1] [ 0 -1] - sage: S = ClusterSeed(['A', 5], user_labels = [-2, -1, 0, 1 ,2]) + sage: S = ClusterSeed(['A', 5], user_labels=[-2, -1, 0, 1 ,2]) sage: U = S.universal_extension() sage: U.b_matrix() == ClusterSeed(['A', 5]).universal_extension().b_matrix() True @@ -3039,7 +3121,7 @@ def universal_extension(self): A = 2 - self.b_matrix().apply_map(abs).transpose() # We give the indexing set of the Cartan matrix to be [1, 2, ..., n] - rs = CartanMatrix(A, index_set=list(range(1,A.ncols()+1))).root_space() + rs = CartanMatrix(A, index_set=list(range(1, A.ncols() + 1))).root_space() almost_positive_coroots = rs.almost_positive_roots() sign = [-1 if all(x <= 0 for x in self.b_matrix()[i]) else 1 @@ -3051,11 +3133,11 @@ def universal_extension(self): n = C.nrows() new_labels = None if self._user_labels: - if isinstance(self._user_labels,list): - new_labels = self._user_labels + ['y%s'%i for i in range(n)] - elif isinstance(self._user_labels,dict): + if isinstance(self._user_labels, list): + new_labels = self._user_labels + [f'y{i}' for i in range(n)] + elif isinstance(self._user_labels, dict): new_labels = copy(self._user_labels) - new_labels.update( {(i+self._n):'y%s'%i for i in range(n)} ) + new_labels.update({(i + self._n): f'y{i}' for i in range(n)}) seed = ClusterSeed(M, is_principal=False, user_labels=new_labels, user_labels_prefix=self._user_labels_prefix, frozen=None) @@ -3111,7 +3193,7 @@ def principal_extension(self): sage: T2 == T True """ - from sage.matrix.all import identity_matrix + from sage.matrix.special import identity_matrix if self._m != 0: raise ValueError("the b-matrix is not square") M = self._M.stack(identity_matrix(self._n)) @@ -3119,10 +3201,10 @@ def principal_extension(self): new_labels = None if self._user_labels: if isinstance(self._user_labels, list): - new_labels = self._user_labels + ['y%s'%i for i in range(self._n)] + new_labels = self._user_labels + [f'y{i}' for i in range(self._n)] elif isinstance(self._user_labels, dict): new_labels = copy(self._user_labels) - new_labels.update( {(i+self._n): 'y%s'%i for i in range(self._n)} ) + new_labels.update({(i + self._n): f'y{i}' for i in range(self._n)}) seed = ClusterSeed(M, is_principal=is_principal, user_labels=new_labels, user_labels_prefix=self._user_labels_prefix, frozen=None) seed.use_c_vectors(self._use_c_vec) @@ -3131,23 +3213,27 @@ def principal_extension(self): seed.use_d_vectors(self._use_d_vec) seed.track_mutations(self._track_mut) - #### This should fix principal_extension resetting boolean flags. Might need to update user labels to include new principals with y's. -G + # This should fix principal_extension resetting boolean flags. + # Might need to update user labels to include new principals with y's. seed._mutation_type = self._mutation_type return seed - def reorient( self, data ): + def reorient(self, data): r""" Reorients ``self`` with respect to the given total order, or with respect to an iterator of ordered pairs. - WARNING: + .. warning:: - - This operation might change the mutation type of ``self``. - - Ignores ordered pairs `(i,j)` for which neither `(i,j)` nor `(j,i)` is an edge of ``self``. + - This operation might change the mutation type of ``self``. + - Ignores ordered pairs `(i,j)` for which neither `(i,j)` nor `(j,i)` + is an edge of ``self``. INPUT: - - ``data`` -- an iterator defining a total order on ``self.vertices()``, or an iterator of ordered pairs in ``self`` defining the new orientation of these edges. + - ``data`` -- an iterator defining a total order on ``self.vertices()``, + or an iterator of ordered pairs in ``self`` defining the new + orientation of these edges. EXAMPLES:: @@ -3169,16 +3255,18 @@ def reorient( self, data ): """ if not self._quiver: self.quiver() - self._quiver.reorient( data ) + self._quiver.reorient(data) self._M = self._quiver._M self.reset_cluster() self._mutation_type = None - def set_cluster( self, cluster, force=False ): + def set_cluster(self, cluster, force=False): r""" Sets the cluster for ``self`` to ``cluster``. - Warning: Initialization may lead to inconsistent data. + .. warning:: + + Initialization may lead to inconsistent data. INPUT: @@ -3211,7 +3299,7 @@ def set_cluster( self, cluster, force=False ): raise ValueError('The number of given cluster variables is wrong') if self._use_fpolys: if any(c not in FractionField(self._R) for c in cluster): - raise ValueError('The cluster variables are not all contained in %s'%FractionField(self._R)) + raise ValueError('The cluster variables are not all contained in %s' % FractionField(self._R)) if not force: # if already have f_polynomials, using set_cluster might yield data inconsistent with them. print("Warning: using set_cluster at this point could lead to inconsistent seed data.") else: @@ -3247,7 +3335,8 @@ def reset_cluster(self): sage: T.cluster() [x0, x1, x2] - sage: S = ClusterSeed(['B',3],user_labels=[[1,2],[2,3],[3,4]],user_labels_prefix='p') + sage: S = ClusterSeed(['B',3], user_labels=[[1,2],[2,3],[3,4]], + ....: user_labels_prefix='p') sage: S.mutate([0,1]) sage: S.cluster() [(p_2_3 + 1)/p_1_2, (p_1_2*p_3_4^2 + p_2_3 + 1)/(p_1_2*p_2_3), p_3_4] @@ -3265,16 +3354,21 @@ def reset_cluster(self): if self._use_g_vec: self._G = matrix.identity(self._n) if self._use_fpolys: - self._F = dict([(i,self._U(1)) for i in self._init_exch.values()]) + self._F = {i: self._U(1) for i in self._init_exch.values()} if self._use_fpolys: self.set_cluster(self._R.gens(), force=True) - def reset_coefficients( self ): + def reset_coefficients(self): r""" - Resets the coefficients of ``self`` to the frozen variables but keeps the current cluster. - Raises an error if the number of frozen variables is different than the number of exchangeable variables. + Reset the coefficients of ``self`` to the frozen variables but keep the current cluster. + + This raises an error if the number of frozen variables is different + from the number of exchangeable variables. - WARNING: This command to be phased out since 'use_c_vectors() does this more effectively. + .. warning:: + + This command to be phased out since :meth:`use_c_vectors` + does this more effectively. EXAMPLES:: @@ -3328,11 +3422,17 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, INPUT: - - ``depth`` -- (default: infinity) integer or infinity, only seeds with distance at most ``depth`` from ``self`` are returned. - - ``show_depth`` -- (default: False) if True, the current depth of the mutation is shown while computing. - - ``return_paths`` -- (default: False) if True, a shortest path of mutations from ``self`` to the given quiver is returned as well. - - ``up_to_equivalence`` -- (default: True) if True, only one seed up to simultaneous permutation of rows and columns of the exchange matrix is recorded. - - ``sink_source`` -- (default: False) if True, only mutations at sinks and sources are applied. + - ``depth`` -- (default: infinity) integer or infinity, only seeds with + distance at most ``depth`` from ``self`` are returned. + - ``show_depth`` -- (default: ``False``) if ``True``, the current depth + of the mutation is shown while computing. + - ``return_paths`` -- (default: ``False``) if ``True``, a shortest path + of mutations from ``self`` to the given quiver is returned as well. + - ``up_to_equivalence`` -- (default: ``True``) if ``True``, only one + seed up to simultaneous permutation of rows and columns of the + exchange matrix is recorded. + - ``sink_source`` -- (default: ``False``) if ``True``, only mutations + at sinks and sources are applied. EXAMPLES: @@ -3387,10 +3487,11 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, Finite type examples not considered up to equivalence:: sage: it = S.mutation_class_iter(up_to_equivalence=False) - sage: len( [ T for T in it ] ) + sage: len([T for T in it]) 84 - sage: it = ClusterSeed(['A',2]).mutation_class_iter(return_paths=True,up_to_equivalence=False) + sage: it = ClusterSeed(['A',2]).mutation_class_iter(return_paths=True, + ....: up_to_equivalence=False) sage: mutation_class = list(it) sage: len(mutation_class) 10 @@ -3434,19 +3535,19 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, # set up our initial cluster and grab variables if up_to_equivalence: - cl = Set( self.cluster() ) + cl = Set(self.cluster()) else: - cl = tuple( self.cluster() ) + cl = tuple(self.cluster()) # If we are tracking return paths if return_paths: - yield (self,[]) + yield (self, []) else: yield self # instantiate the variables clusters = {} - clusters[ cl ] = [ self, list(range(n)), [] ] + clusters[cl] = [self, list(range(n)), []] # we get bigger the first time gets_bigger = True @@ -3455,10 +3556,10 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, if show_depth: timer2 = time.time() dc = str(depth_counter) - dc += ' ' * (5-len(dc)) + dc += ' ' * (5 - len(dc)) nr = str(len(clusters)) - nr += ' ' * (10-len(nr)) - print("Depth: %s found: %s Time: %.2f s" % (dc, nr, timer2-timer)) + nr += ' ' * (10 - len(nr)) + print("Depth: %s found: %s Time: %.2f s" % (dc, nr, timer2 - timer)) # Each time we get bigger and we haven't hit the full depth while gets_bigger and depth_counter < depth: @@ -3477,7 +3578,7 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, i = sd[1].pop() # If we aren't only sinking the source - if not only_sink_source or all( entry >= 0 for entry in sd[0]._M.row( i ) ) or all( entry <= 0 for entry in sd[0]._M.row( i ) ): + if not only_sink_source or all(entry >= 0 for entry in sd[0]._M.row(i)) or all(entry <= 0 for entry in sd[0]._M.row(i)): # do an inplace mutation on our cluster (sd[0]) sd2 = sd[0].mutate(i, inplace=False, input_type="indices") @@ -3494,9 +3595,9 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, if only_sink_source: orbits = list(range(n)) else: - orbits = [ index for index in range(n) if index > i or sd2._M[index,i] != 0 ] + orbits = [index for index in range(n) if index > i or sd2._M[index,i] != 0] - clusters[ cl2 ] = [ sd2, orbits, clusters[key][2]+[i] ] + clusters[cl2] = [sd2, orbits, clusters[key][2]+[i]] if return_paths: yield (sd2,clusters[cl2][2]) else: @@ -3548,17 +3649,21 @@ def mutation_class(self, depth=infinity, show_depth=False, return_paths=False, """ if depth is infinity and not self.is_finite(): raise ValueError('The mutation class can - for infinite types - only be computed up to a given depth') - return list( S for S in self.mutation_class_iter( depth=depth, show_depth=show_depth, return_paths=return_paths, up_to_equivalence=up_to_equivalence, only_sink_source=only_sink_source ) ) + return list(self.mutation_class_iter(depth=depth, show_depth=show_depth, return_paths=return_paths, up_to_equivalence=up_to_equivalence, only_sink_source=only_sink_source)) def cluster_class_iter(self, depth=infinity, show_depth=False, up_to_equivalence=True): r""" - Returns an iterator through all clusters in the mutation class of ``self``. + Return an iterator through all clusters in the mutation class of ``self``. INPUT: - - ``depth`` -- (default: infinity) integer or infinity, only seeds with distance at most depth from self are returned - - ``show_depth`` -- (default False) - if True, ignored if depth is set; returns the depth of the mutation class, i.e., the maximal distance from self of an element in the mutation class - - ``up_to_equivalence`` -- (default: True) if True, only clusters up to equivalence are considered. + - ``depth`` -- (default: infinity) integer or infinity, only seeds with + distance at most ``depth`` from ``self`` are returned + - ``show_depth`` -- (default: ``False``) if ``True``, ignored if + ``depth`` is set; returns the depth of the mutation class, i.e., the + maximal distance from ``self`` of an element in the mutation class + - ``up_to_equivalence`` -- (default: ``True``) if ``True``, only + clusters up to equivalence are considered. EXAMPLES: @@ -3594,7 +3699,7 @@ def cluster_class_iter(self, depth=infinity, show_depth=False, up_to_equivalence Finite type examples not considered up to equivalence:: sage: it = S.cluster_class_iter(up_to_equivalence=False) - sage: len( [ T for T in it ] ) + sage: len([T for T in it]) 84 sage: it = ClusterSeed(['A',2]).cluster_class_iter(up_to_equivalence=False) @@ -3634,7 +3739,7 @@ def cluster_class_iter(self, depth=infinity, show_depth=False, up_to_equivalence For a cluster seed from an arbitrarily labelled digraph:: sage: dg = DiGraph([['a', 'b'], ['b', 'c']], format="list_of_edges") - sage: S = ClusterSeed(dg, frozen = ['b']) + sage: S = ClusterSeed(dg, frozen=['b']) sage: S.cluster_class() [[a, c], [a, (b + 1)/c], [(b + 1)/a, c], [(b + 1)/a, (b + 1)/c]] @@ -3642,7 +3747,7 @@ def cluster_class_iter(self, depth=infinity, show_depth=False, up_to_equivalence sage: S2.cluster_class()[0] [a, b, c] """ - mc_iter = self.mutation_class_iter( depth=depth, show_depth=show_depth, up_to_equivalence=up_to_equivalence ) + mc_iter = self.mutation_class_iter(depth=depth, show_depth=show_depth, up_to_equivalence=up_to_equivalence) for c in mc_iter: yield c.cluster() @@ -3652,9 +3757,13 @@ def cluster_class(self, depth=infinity, show_depth=False, up_to_equivalence=True INPUT: - - ``depth`` -- (default: infinity) integer, only seeds with distance at most depth from self are returned - - ``return_depth`` -- (default False) - if True, ignored if depth is set; returns the depth of the mutation class, i.e., the maximal distance from self of an element in the mutation class - - ``up_to_equivalence`` -- (default: True) if True, only clusters up to equivalence are considered. + - ``depth`` -- (default: infinity) integer, only seeds with distance + at most ``depth`` from ``self`` are returned + - ``return_depth`` -- (default: ``False``) - if ``True``, ignored if + ``depth`` is set; returns the depth of the mutation class, i.e., + the maximal distance from ``self`` of an element in the mutation class + - ``up_to_equivalence`` -- (default: ``True``) if ``True``, only + clusters up to equivalence are considered. EXAMPLES: @@ -3667,16 +3776,18 @@ def cluster_class(self, depth=infinity, show_depth=False, up_to_equivalence=True if depth is infinity and not self.is_finite(): raise ValueError('The variable class can - for infinite types - only be computed up to a given depth') - return [ c for c in self.cluster_class_iter(depth=depth, show_depth=show_depth, up_to_equivalence=up_to_equivalence) ] + return [c for c in self.cluster_class_iter(depth=depth, show_depth=show_depth, up_to_equivalence=up_to_equivalence)] def b_matrix_class_iter(self, depth=infinity, up_to_equivalence=True): r""" - Returns an iterator through all `B`-matrices in the mutation class of ``self``. + Return an iterator through all `B`-matrices in the mutation class of ``self``. INPUT: - - ``depth`` -- (default:infinity) integer or infinity, only seeds with distance at most depth from self are returned - - ``up_to_equivalence`` -- (default: True) if True, only 'B'-matrices up to equivalence are considered. + - ``depth`` -- (default:infinity) integer or infinity, only seeds + with distance at most ``depth`` from ``self`` are returned + - ``up_to_equivalence`` -- (default: ``True``) if ``True``, only + `B`-matrices up to equivalence are considered. EXAMPLES: @@ -3755,7 +3866,7 @@ def b_matrix_class_iter(self, depth=infinity, up_to_equivalence=True): sage: S = ClusterSeed(['E',10]) sage: it = S.b_matrix_class_iter(depth=3) - sage: len ( [T for T in it] ) + sage: len ([T for T in it]) 266 For a cluster seed from an arbitrarily labelled digraph:: @@ -3770,17 +3881,19 @@ def b_matrix_class_iter(self, depth=infinity, up_to_equivalence=True): ] """ Q = self.quiver() - for M in Q.mutation_class_iter( depth=depth, up_to_equivalence=up_to_equivalence, data_type='matrix' ): + for M in Q.mutation_class_iter(depth=depth, up_to_equivalence=up_to_equivalence, data_type='matrix'): yield M def b_matrix_class(self, depth=infinity, up_to_equivalence=True): r""" - Returns all `B`-matrices in the mutation class of ``self``. + Return all `B`-matrices in the mutation class of ``self``. INPUT: - - ``depth`` -- (default:infinity) integer or infinity, only seeds with distance at most depth from self are returned - - ``up_to_equivalence`` -- (default: True) if True, only 'B'-matrices up to equivalence are considered. + - ``depth`` -- (default: infinity) integer or infinity, only seeds + with distance at most ``depth`` from ``self`` are returned + - ``up_to_equivalence`` -- (default: ``True``) if ``True``, only + `B`-matrices up to equivalence are considered. EXAMPLES: @@ -3794,16 +3907,18 @@ def b_matrix_class(self, depth=infinity, up_to_equivalence=True): if depth is infinity and not self.is_mutation_finite(): raise ValueError('The B-matrix class can - for infinite mutation types - only be computed up to a given depth') - return [ M for M in self.b_matrix_class_iter( depth=depth, up_to_equivalence=up_to_equivalence ) ] + return list(self.b_matrix_class_iter(depth=depth, up_to_equivalence=up_to_equivalence)) def variable_class_iter(self, depth=infinity, ignore_bipartite_belt=False): r""" - Returns an iterator for all cluster variables in the mutation class of ``self``. + Return an iterator for all cluster variables in the mutation class of ``self``. INPUT: - - ``depth`` -- (default:infinity) integer, only seeds with distance at most depth from self are returned - - ``ignore_bipartite_belt`` -- (default:False) if True, the algorithms does not use the bipartite belt + - ``depth`` -- (default: infinity) integer, only seeds with distance + at most ``depth`` from ``self`` are returned + - ``ignore_bipartite_belt`` -- (default: ``False``) if ``True``, + the algorithm does not use the bipartite belt EXAMPLES: @@ -3826,7 +3941,8 @@ def variable_class_iter(self, depth=infinity, ignore_bipartite_belt=False): sage: it = S.variable_class_iter(depth=1) sage: for T in it: print(T) - Found a bipartite seed - restarting the depth counter at zero and constructing the variable class using its bipartite belt. + Found a bipartite seed - restarting the depth counter at zero + and constructing the variable class using its bipartite belt. x0 x1 x2 @@ -3837,9 +3953,10 @@ def variable_class_iter(self, depth=infinity, ignore_bipartite_belt=False): (x0*x2 + 1)/x1 (x0*x2 + x1 + 1)/(x1*x2) - Note that the notion of *depth* depends on whether a bipartite seed is found or not, or if it is manually ignored:: + Note that the notion of *depth* depends on whether a bipartite seed + is found or not, or if it is manually ignored:: - sage: it = S.variable_class_iter(depth=1,ignore_bipartite_belt=True) + sage: it = S.variable_class_iter(depth=1, ignore_bipartite_belt=True) sage: for T in it: print(T) x0 x1 @@ -3863,7 +3980,8 @@ def variable_class_iter(self, depth=infinity, ignore_bipartite_belt=False): sage: S = ClusterSeed(['A',[1,1],1]) sage: it = S.variable_class_iter(depth=2) sage: for T in it: print(T) - Found a bipartite seed - restarting the depth counter at zero and constructing the variable class using its bipartite belt. + Found a bipartite seed - restarting the depth counter at zero + and constructing the variable class using its bipartite belt. x0 x1 (x1^2 + 1)/x0 @@ -3875,7 +3993,7 @@ def variable_class_iter(self, depth=infinity, ignore_bipartite_belt=False): (x0^8 + 4*x0^6 + 3*x0^4*x1^2 + 2*x0^2*x1^4 + x1^6 + 6*x0^4 + 6*x0^2*x1^2 + 3*x1^4 + 4*x0^2 + 3*x1^2 + 1)/(x0^3*x1^4) (x0^6 + 3*x0^4 + 2*x0^2*x1^2 + x1^4 + 3*x0^2 + 2*x1^2 + 1)/(x0^2*x1^3) """ - mut_iter = self.mutation_class_iter( depth=depth,show_depth=False ) + mut_iter = self.mutation_class_iter(depth=depth,show_depth=False) var_class = set() for seed in mut_iter: @@ -3891,8 +4009,8 @@ def variable_class_iter(self, depth=infinity, ignore_bipartite_belt=False): seed2 = ClusterSeed(seed) for c in seed.cluster(): if c not in var_class: - yield ClusterVariable( FractionField(seed._R), c.numerator(), c.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable',xdim=seed._n ) - var_class = var_class.union( seed.cluster()) + yield ClusterVariable(FractionField(seed._R), c.numerator(), c.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable',xdim=seed._n) + var_class = var_class.union(seed.cluster()) init_cluster = set(seed.cluster()) while not end and depth_counter < depth: @@ -3904,8 +4022,8 @@ def variable_class_iter(self, depth=infinity, ignore_bipartite_belt=False): if not end: for c in seed.cluster(): if c not in var_class: - yield ClusterVariable( FractionField(seed._R), c.numerator(), c.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable',xdim=seed._n ) - var_class = var_class.union( seed.cluster() ) + yield ClusterVariable(FractionField(seed._R), c.numerator(), c.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable',xdim=seed._n) + var_class = var_class.union(seed.cluster()) seed2.mutate(bipartition[1]) seed2.mutate(bipartition[0]) if set(seed2.cluster()) in [set(seed.cluster()),init_cluster]: @@ -3913,23 +4031,25 @@ def variable_class_iter(self, depth=infinity, ignore_bipartite_belt=False): if not end: for c in seed2.cluster(): if c not in var_class: - yield ClusterVariable(FractionField(seed._R), c.numerator(), c.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable',xdim=seed._n ) + yield ClusterVariable(FractionField(seed._R), c.numerator(), c.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable',xdim=seed._n) var_class = var_class.union(seed2.cluster()) return else: for c in seed.cluster(): if c not in var_class: - yield ClusterVariable( FractionField(seed._R), c.numerator(), c.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable',xdim=seed._n) + yield ClusterVariable(FractionField(seed._R), c.numerator(), c.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable',xdim=seed._n) var_class = var_class.union(seed.cluster()) def variable_class(self, depth=infinity, ignore_bipartite_belt=False): r""" - Returns all cluster variables in the mutation class of ``self``. + Return all cluster variables in the mutation class of ``self``. INPUT: - - ``depth`` -- (default:infinity) integer, only seeds with distance at most depth from self are returned - - ``ignore_bipartite_belt`` -- (default:False) if True, the algorithms does not use the bipartite belt + - ``depth`` -- (default: infinity) integer, only seeds with distance + at most ``depth`` from ``self`` are returned + - ``ignore_bipartite_belt`` -- (default: ``False``) if ``True``, the + algorithm does not use the bipartite belt EXAMPLES: @@ -3942,7 +4062,7 @@ def variable_class(self, depth=infinity, ignore_bipartite_belt=False): if depth is infinity and not self.is_finite(): raise ValueError('The variable class can - for infinite types - only be computed up to a given depth') - var_iter = self.variable_class_iter( depth=depth, ignore_bipartite_belt=ignore_bipartite_belt ) + var_iter = self.variable_class_iter(depth=depth, ignore_bipartite_belt=ignore_bipartite_belt) return sorted(var_iter) def is_finite(self) -> bool: @@ -3971,23 +4091,27 @@ def is_finite(self) -> bool: else: return mt.is_finite() - def is_mutation_finite( self, nr_of_checks=None, return_path=False ): + def is_mutation_finite(self, nr_of_checks=None, return_path=False): r""" - Returns True if ``self`` is of finite mutation type. + Return True if ``self`` is of finite mutation type. INPUT: - - ``nr_of_checks`` -- (default: None) number of mutations applied. Standard is 500*(number of vertices of self). - - ``return_path`` -- (default: False) if True, in case of self not being mutation finite, a path from self to a quiver with an edge label (a,-b) and a*b > 4 is returned. + - ``nr_of_checks`` -- (default: ``None``) number of mutations applied. + Standard is 500 times the number of vertices of ``self``. + - ``return_path`` -- (default: ``False``) if ``True``, in case of + ``self`` not being mutation finite, a path from ``self`` to a quiver + with an edge label `(a,-b)` and `a*b > 4` is returned. ALGORITHM: - - A cluster seed is mutation infinite if and only if every `b_{ij}*b_{ji} > -4`. Thus, we apply random mutations in random directions + - A cluster seed is mutation infinite if and only if every + `b_{ij}*b_{ji} > -4`. Thus, we apply random mutations in random directions - WARNING: + .. warning:: - - Uses a non-deterministic method by random mutations in various directions. - - In theory, it can return a wrong True. + - Uses a non-deterministic method by random mutations in various directions. + - In theory, it can return a wrong ``True``. EXAMPLES:: @@ -4008,18 +4132,21 @@ def is_mutation_finite( self, nr_of_checks=None, return_path=False ): def mutation_type(self): r""" - Returns the mutation_type of each connected component of ``self``, if it can be determined. + Return the mutation type of each connected component of ``self``, if it can be determined. + Otherwise, the mutation type of this component is set to be unknown. The mutation types of the components are ordered by vertex labels. - WARNING: + .. warning:: - - All finite types can be detected, - - All affine types can be detected, EXCEPT affine type D (the algorithm is not yet implemented) - - All exceptional types can be detected. + - All finite types can be detected, + - All affine types can be detected, **except** affine type D + (the algorithm is not yet implemented) + - All exceptional types can be detected. - - Might fail to work if it is used within different Sage processes simultaneously (that happened in the doctesting). + - Might fail to work if it is used within different Sage processes + simultaneously (that happened in the doctesting). EXAMPLES: @@ -4034,7 +4161,8 @@ def mutation_type(self): sage: S.mutation_type() ['A', 5] - sage: S = ClusterSeed(DiGraph([['a','b'],['c','b'],['c','d'],['e','d']]), frozen = ['c']) + sage: S = ClusterSeed(DiGraph([['a','b'],['c','b'],['c','d'],['e','d']]), + ....: frozen=['c']) sage: S.mutation_type() [ ['A', 2], ['A', 2] ] @@ -4076,10 +4204,10 @@ def mutation_type(self): def greedy(self, a1, a2, algorithm='by_recursion'): r""" - Returns the greedy element `x[a_1,a_2]` assuming that self is rank two. + Return the greedy element `x[a_1,a_2]` assuming that self is rank two. - The third input can be 'by_recursion', 'by_combinatorics', or - 'just_numbers' to specify if the user wants the element + The third input can be ``'by_recursion'``, ``'by_combinatorics'``, or + ``'just_numbers'`` to specify if the user wants the element computed by the recurrence, combinatorial formula, or wants to set `x_1` and `x_2` to be one. @@ -4089,9 +4217,11 @@ def greedy(self, a1, a2, algorithm='by_recursion'): sage: S = ClusterSeed(['R2', [3, 3]]) sage: S.greedy(4, 4) - (x0^12 + x1^12 + 4*x0^9 + 4*x1^9 + 6*x0^6 + 4*x0^3*x1^3 + 6*x1^6 + 4*x0^3 + 4*x1^3 + 1)/(x0^4*x1^4) + (x0^12 + x1^12 + 4*x0^9 + 4*x1^9 + 6*x0^6 + + 4*x0^3*x1^3 + 6*x1^6 + 4*x0^3 + 4*x1^3 + 1)/(x0^4*x1^4) sage: S.greedy(4, 4, 'by_combinatorics') - (x0^12 + x1^12 + 4*x0^9 + 4*x1^9 + 6*x0^6 + 4*x0^3*x1^3 + 6*x1^6 + 4*x0^3 + 4*x1^3 + 1)/(x0^4*x1^4) + (x0^12 + x1^12 + 4*x0^9 + 4*x1^9 + 6*x0^6 + + 4*x0^3*x1^3 + 6*x1^6 + 4*x0^3 + 4*x1^3 + 1)/(x0^4*x1^4) sage: S.greedy(4, 4, 'just_numbers') 35 sage: S = ClusterSeed(['R2', [2, 2]]) @@ -4161,12 +4291,11 @@ def greedy(self, a1, a2, algorithm='by_recursion'): def oriented_exchange_graph(self): """ - Return the oriented exchange graph of ``self`` as a directed - graph. + Return the oriented exchange graph of ``self`` as a directed graph. The seed must be a cluster seed for a cluster algebra of finite type with principal coefficients (the corresponding - quiver must have mutable vertices 0,1,...,n-1). + quiver must have mutable vertices `0,1,...,n-1`). EXAMPLES:: @@ -4224,7 +4353,7 @@ def oriented_exchange_graph(self): def find_upper_bound(self, verbose=False): r""" - Return the upper bound of the given cluster algebra as a quotient_ring. + Return the upper bound of the given cluster algebra as a quotient ring. The upper bound is the intersection of the Laurent polynomial rings of the initial cluster and its neighboring clusters. As @@ -4257,15 +4386,24 @@ def find_upper_bound(self, verbose=False): sage: S = ClusterSeed(['A',3]) sage: S.find_upper_bound() - Quotient of Multivariate Polynomial Ring in x0, x1, x2, x0p, x1p, x2p, z0 over Rational Field by the ideal (x0*x0p - x1 - 1, x1*x1p - x0*x2 - 1, x2*x2p - x1 - 1, x0*z0 - x2p, x1*z0 + z0 - x0p*x2p, x2*z0 - x0p, x1p*z0 + z0 - x0p*x1p*x2p + x1 + 1) + Quotient of Multivariate Polynomial Ring in x0, x1, x2, x0p, x1p, x2p, z0 + over Rational Field + by the ideal (x0*x0p - x1 - 1, x1*x1p - x0*x2 - 1, x2*x2p - x1 - 1, + x0*z0 - x2p, x1*z0 + z0 - x0p*x2p, x2*z0 - x0p, + x1p*z0 + z0 - x0p*x1p*x2p + x1 + 1) - Markov:: sage: B = matrix([[0,2,-2],[-2,0,2],[2,-2,0]]) sage: S = ClusterSeed(B) sage: S.find_upper_bound() - Quotient of Multivariate Polynomial Ring in x0, x1, x2, x0p, x1p, x2p, z0 over Rational Field by the ideal (x0*x0p - x2^2 - x1^2, x1*x1p - x2^2 - x0^2, x2*x2p - x1^2 - x0^2, x0p*x1p*x2p - x0*x1*x2p - x0*x2*x1p - x1*x2*x0p - 2*x0*x1*x2, x0^3*z0 - x1p*x2p + x1*x2, x0*x1*z0 - x2p - x2, x1^3*z0 - x0p*x2p + x0*x2, x0*x2*z0 - x1p - x1, x1*x2*z0 - x0p - x0, x2^3*z0 - x0p*x1p + x0*x1) - + Quotient of Multivariate Polynomial Ring in x0, x1, x2, x0p, x1p, x2p, z0 + over Rational Field + by the ideal (x0*x0p - x2^2 - x1^2, x1*x1p - x2^2 - x0^2, x2*x2p - x1^2 - x0^2, + x0p*x1p*x2p - x0*x1*x2p - x0*x2*x1p - x1*x2*x0p - 2*x0*x1*x2, + x0^3*z0 - x1p*x2p + x1*x2, x0*x1*z0 - x2p - x2, + x1^3*z0 - x0p*x2p + x0*x2, x0*x2*z0 - x1p - x1, + x1*x2*z0 - x0p - x0, x2^3*z0 - x0p*x1p + x0*x1) """ rank = self.n() @@ -4330,18 +4468,19 @@ def find_upper_bound(self, verbose=False): def get_upper_cluster_algebra_element(self,a): r""" - Computes an element in the upper cluster algebra of `B` corresponding to the vector `a \in \ZZ^n`. + Compute an element in the upper cluster algebra of `B` corresponding to the vector `a \in \ZZ^n`. See [LLM2014]_ for more details. INPUT: - - `B` -- a skew-symmetric matrix. Must have the same number of columns as the length of the vectors in `vd`. - - `a` -- a vector in `\ZZ^n` where `n` is the number of columns in `B`. + - ``B`` -- a skew-symmetric matrix. Must have the same number of columns + as the length of the vectors in `vd`. + - ``a`` -- a vector in `\ZZ^n` where `n` is the number of columns in `B`. OUTPUT: - Returns an element in the upper cluster algebra. Depending on the input it may or may not be irreducible. + Return an element in the upper cluster algebra. Depending on the input it may or may not be irreducible. EXAMPLES:: @@ -4369,13 +4508,13 @@ def get_upper_cluster_algebra_element(self,a): sage: C.get_upper_cluster_algebra_element([1,1,1]) x0^4*x1^2*x2^3 + x0^2*x1^3*x2^4 """ - B=self.b_matrix() - #Checks if the length of the + B = self.b_matrix() + # Checks if the length of the if len(a) != B.ncols(): raise ValueError('The length of the input vector must be the same as the number of columns of B.') - #Runs helper functions. - v=_vector_decomposition(a,B.nrows()) - c=self._compute_compatible_vectors(v) + # Runs helper functions. + v = _vector_decomposition(a,B.nrows()) + c = self._compute_compatible_vectors(v) return self._produce_upper_cluster_algebra_element(v,c) def LLM_gen_set(self, size_limit=-1): @@ -4385,7 +4524,7 @@ def LLM_gen_set(self, size_limit=-1): INPUT: - - `B` -- a skew-symmetric matrix. + - ``B`` -- a skew-symmetric matrix. - ``size_limit`` -- a limit on how many vectors you want the function to return. @@ -4428,9 +4567,11 @@ def _compute_compatible_vectors(self, vd): INPUT: - - `B` -- a skew-symmetric matrix. Must have the same number of columns as the length of the vectors in ``vd``. + - ``B`` -- a skew-symmetric matrix. Must have the same number of columns + as the length of the vectors in ``vd``. - ``vd`` -- a collection of tuples `(v,z)` with `v \in \{0,1\}^n` and `z \in \ZZ`. - `n` must be the number of columns in `B`. Taken from the output of vector_decomposition. + `n` must be the number of columns in `B`. Taken from the output of + :func:`_vector_decomposition`. OUTPUT: @@ -4546,18 +4687,22 @@ def _produce_upper_cluster_algebra_element(self, vd, cList): x1*x3^2)/(x0^2*x2^3) """ B = self.b_matrix() - #Creates a the fraction field of a polynomial ring in which to build the Laurent polynomials. + # Creates a the fraction field of a polynomial ring in which to build the Laurent polynomials. num_cols = B.ncols() num_rows = B.nrows() R = PolynomialRing(QQ, num_rows, 'x') - #Computes the Laurent Polynomial for each vector in the decomposition. + # Computes the Laurent Polynomial for each vector in the decomposition. finalP = [] - #Laurent polynomial for each vector in {0,1}^n + # Laurent polynomial for each vector in {0,1}^n for i in range(len(vd)): numerator = 0 if cList[i]: - #If the vector in vd is negative then it did not contribute any compatible vectors. It will only contribute a Laurent monomial. This is the case when cList[i]=[] - #Each compatible sequence gives a term in the numerator of the Laurent polynomial. + # If the vector in vd is negative then it did not + # contribute any compatible vectors. It will only + # contribute a Laurent monomial. This is the case when + # cList[i]=[] + # Each compatible sequence gives a term in the + # numerator of the Laurent polynomial. for s in cList[i]: term = 1 # Calculates the monomial in the term. @@ -4569,19 +4714,19 @@ def _produce_upper_cluster_algebra_element(self, vd, cList): expn += (vd[i][0][k]-s[k])*max(0, B[j][k])+s[k]*max(0, -B[j][k]) term *= x ** expn numerator += term - #Gives a numerator for the negative vector, or else the product would be zero. + # Gives a numerator for the negative vector, or else the product would be zero. else: numerator = 1 - #Uses the vectors in vd to calculates the denominator of the Laurent. + # Uses the vectors in vd to calculates the denominator of the Laurent. denominator = 1 for l in range(num_cols): denominator = denominator * (R.gen(l))**vd[i][0][l] - #Each copy of a vector in vd contributes a factor of the Laurent polynomial calculated from it. + # Each copy of a vector in vd contributes a factor of the Laurent polynomial calculated from it. final = (numerator/denominator)**vd[i][1] finalP.append(final) laurentP = 1 - #The UCA element for the vector a is the product of the elements produced from the vectors in its decomposition. + # The UCA element for the vector a is the product of the elements produced from the vectors in its decomposition. for p in finalP: laurentP *= p return laurentP @@ -4600,7 +4745,7 @@ def _bino(n, k): 0 """ if n >= 0: - from sage.arith.all import binomial + from sage.arith.misc import binomial return binomial(n, k) else: return 0 @@ -4631,11 +4776,12 @@ def coeff_recurs(p, q, a1, a2, b, c): def PathSubset(n, m): r""" - Encodes a *maximal* Dyck path from (0,0) to (n,m) (for n >= m >= 0) as a subset of {0,1,2,..., 2n-1}. + Encode a *maximal* Dyck path from `(0,0)` to `(n,m)` (for `n \geq m \geq 0`) as a subset of `\{0,1,2,..., 2n-1\}`. + The encoding is given by indexing horizontal edges by odd numbers and vertical edges by evens. - The horizontal between (i,j) and (i+1,j) is indexed by the odd number 2*i+1. - The vertical between (i,j) and (i,j+1) is indexed by the even number 2*j. + The horizontal between `(i,j)` and `(i+1,j)` is indexed by the odd number `2*i+1`. + The vertical between `(i,j)` and `(i,j+1)` is indexed by the even number `2*j`. EXAMPLES:: @@ -4661,7 +4807,7 @@ def PathSubset(n, m): def SetToPath(T): r""" - Rearranges the encoding for a *maximal* Dyck path (as a set) so that it is a list in the proper order of the edges. + Rearrange the encoding for a *maximal* Dyck path (as a set) so that it is a list in the proper order of the edges. EXAMPLES:: @@ -4691,8 +4837,7 @@ def SetToPath(T): def is_LeeLiZel_allowable(T,n,m,b,c): """ - Check if the subset T contributes to the computation of the greedy - element x[m,n] in the rank two (b,c)-cluster algebra. + Check if the subset `T` contributes to the computation of the greedy element `x[m,n]` in the rank two `(b,c)`-cluster algebra. This uses the conditions of Lee-Li-Zelevinsky's paper [LLZ2014]_. @@ -4704,7 +4849,7 @@ def is_LeeLiZel_allowable(T,n,m,b,c): sage: is_LeeLiZel_allowable({1,2,5},3,3,1,1) True """ - horiz = set(T).intersection( PathSubset(n, 0)) + horiz = set(T).intersection(PathSubset(n, 0)) vert = set(T).symmetric_difference(horiz) if len(horiz) == 0 or len(vert) == 0: return True @@ -4746,18 +4891,20 @@ def is_LeeLiZel_allowable(T,n,m,b,c): if nAF1 == b*nAF2 or nEA2 == c*nEA1: uv_okay = True if not uv_okay: - return False + return False return True def get_green_vertices(C): r""" - Get the green vertices from a matrix. Will go through each column and return + Get the green vertices from a matrix. + + Will go through each column and return the ones where no entry is greater than 0. INPUT: - - ``C`` -- The C matrix to check + - ``C`` -- The C-matrix to check EXAMPLES:: @@ -4765,13 +4912,8 @@ def get_green_vertices(C): sage: S = ClusterSeed(['A',4]); S.mutate([1,2,3,2,0,1,2,0,3]) sage: get_green_vertices(S.c_matrix()) [0, 3] - """ - return [ i for (i,v) in enumerate(C.columns()) if any(x > 0 for x in v) ] - ## old code commented out - #import numpy as np - #max_entries = [ np.max(np.array(C.column(i))) for i in range(C.ncols()) ] - #return [i for i in range(C.ncols()) if max_entries[i] > 0] + return [i for i, v in enumerate(C.columns()) if any(x > 0 for x in v)] def get_red_vertices(C): @@ -4783,7 +4925,7 @@ def get_red_vertices(C): INPUT: - - ``C`` -- The C matrix to check + - ``C`` -- The C-matrix to check EXAMPLES:: @@ -4792,11 +4934,7 @@ def get_red_vertices(C): sage: get_red_vertices(S.c_matrix()) [1, 2] """ - return [ i for (i,v) in enumerate(C.columns()) if any(x < 0 for x in v) ] - ## old code commented out - #import numpy as np - #min_entries = [ np.min(np.array(C.column(i))) for i in range(C.ncols()) ] - #return [i for i in range(C.ncols()) if min_entries[i] < 0] + return [i for i, v in enumerate(C.columns()) if any(x < 0 for x in v)] def _vector_decomposition(a, length): @@ -4812,7 +4950,7 @@ def _vector_decomposition(a, length): A decomposition of `a` into vectors `b_i \in \{0,1\}^n` such that `a= \sum c_i b_i` for `c_i \in \ZZ.` - Returns an array of tuples `\right[b_i,c_i\left].` + Return an array of tuples `\right[b_i,c_i\left].` EXAMPLES:: @@ -4942,7 +5080,6 @@ def _power_set(n): [1, 1, 1, 0, 1], [1, 1, 1, 1, 0], [1, 1, 1, 1, 1]] - """ p = _multi_concatenate([[]], [0, 1]) for i in range(n - 1): @@ -5009,7 +5146,7 @@ class ClusterVariable(FractionFieldElement): (x0*x2 + 1)/x1 alpha[2] (x0*x2 + x1 + 1)/(x1*x2) alpha[2] + alpha[3] """ - def __init__( self, parent, numerator, denominator, coerce=True, reduce=True, mutation_type=None, variable_type=None, xdim=0 ): + def __init__(self, parent, numerator, denominator, coerce=True, reduce=True, mutation_type=None, variable_type=None, xdim=0): r""" Initialize a cluster variable in the same way that elements in the field of rational functions are initialized. @@ -5026,12 +5163,12 @@ def __init__( self, parent, numerator, denominator, coerce=True, reduce=True, mu sage: S.variable_class() [(x0 + x1 + 1)/(x0*x1), (x1 + 1)/x0, (x0 + 1)/x1, x1, x0] """ - FractionFieldElement.__init__( self, parent, numerator, denominator, coerce=coerce, reduce=reduce ) + FractionFieldElement.__init__(self, parent, numerator, denominator, coerce=coerce, reduce=reduce) self._n = xdim self._mutation_type = mutation_type self._variable_type = variable_type - def almost_positive_root( self ): + def almost_positive_root(self): r""" Return the *almost positive root* associated to ``self`` if ``self`` is of finite type. @@ -5054,22 +5191,20 @@ def almost_positive_root( self ): raise ValueError('The variable is frozen.') if isinstance(self._mutation_type, str): raise ValueError('The cluster algebra for %s is not of finite type.' % self._repr_()) + if self._mutation_type is None: + self._mutation_type = self.parent().mutation_type() + if self._mutation_type.is_finite(): + from sage.combinat.root_system.root_system import RootSystem + # the import above is used in the line below + mt = self._mutation_type._repr_() + # mt is a string of the shape "['A', 15]" + # where A is a single letter and 15 is an integer + Phi = RootSystem([mt[2: 3], ZZ(mt[6: -1])]) + Phiplus = Phi.root_lattice().simple_roots() + + if self.denominator() == 1: + return -Phiplus[self.numerator().degrees().index(1) + 1] + root = self.denominator().degrees() + return sum([root[i] * Phiplus[i + 1] for i in range(self._n)]) else: - if self._mutation_type is None: - self._mutation_type = self.parent().mutation_type() - if self._mutation_type.is_finite(): - from sage.combinat.root_system.root_system import RootSystem - # the import above is used in the line below - mt = self._mutation_type._repr_() - # mt is a string of the shape "['A', 15]" - # where A is a single letter and 15 is an integer - Phi = RootSystem([mt[2: 3], ZZ(mt[6: -1])]) - Phiplus = Phi.root_lattice().simple_roots() - - if self.denominator() == 1: - return -Phiplus[ self.numerator().degrees().index(1) + 1 ] - else: - root = self.denominator().degrees() - return sum( [ root[i]*Phiplus[ i+1 ] for i in range(self._n) ] ) - else: - raise ValueError('The cluster algebra for %s is not of finite type.' % self._repr_()) + raise ValueError('The cluster algebra for %s is not of finite type.' % self._repr_()) diff --git a/src/sage/combinat/cluster_algebra_quiver/interact.py b/src/sage/combinat/cluster_algebra_quiver/interact.py index 1c88e613b4c..695e3d1d449 100644 --- a/src/sage/combinat/cluster_algebra_quiver/interact.py +++ b/src/sage/combinat/cluster_algebra_quiver/interact.py @@ -10,8 +10,8 @@ def cluster_interact(self, fig_size=1, circular=True, kind='seed'): Only in *Jupyter notebook mode*. - Not to be called directly. Use the interact methods - of ClusterSeed and ClusterQuiver instead. + Not to be called directly. Use the :meth:`interact` methods + of :class:`ClusterSeed` and :class:`ClusterQuiver` instead. INPUT: @@ -25,8 +25,8 @@ def cluster_interact(self, fig_size=1, circular=True, kind='seed'): TESTS:: - sage: S = ClusterSeed(['A',4]) - sage: S.interact() # indirect doctest + sage: S = ClusterSeed(['A',4]) # needs sage.graphs sage.modules + sage: S.interact() # indirect doctest # needs sage.graphs sage.modules sage.symbolic ...VBox(children=... """ if kind not in ['seed', 'quiver']: diff --git a/src/sage/combinat/cluster_algebra_quiver/mutation_class.py b/src/sage/combinat/cluster_algebra_quiver/mutation_class.py index 78cf328747c..33b33087899 100644 --- a/src/sage/combinat/cluster_algebra_quiver/mutation_class.py +++ b/src/sage/combinat/cluster_algebra_quiver/mutation_class.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" mutation_class @@ -41,11 +42,11 @@ def _principal_part(mat): EXAMPLES:: sage: from sage.combinat.cluster_algebra_quiver.mutation_class import _principal_part - sage: M = Matrix([[1,2],[3,4],[5,6]]); M + sage: M = Matrix([[1,2],[3,4],[5,6]]); M # needs sage.modules [1 2] [3 4] [5 6] - sage: _principal_part(M) + sage: _principal_part(M) # needs sage.modules [1 2] [3 4] """ @@ -159,7 +160,7 @@ def _matrix_to_digraph( M ): EXAMPLES:: sage: from sage.combinat.cluster_algebra_quiver.mutation_class import _matrix_to_digraph - sage: _matrix_to_digraph(matrix(3,[0,1,0,-1,0,-1,0,1,0])) + sage: _matrix_to_digraph(matrix(3,[0,1,0,-1,0,-1,0,1,0])) # needs sage.modules Digraph on 3 vertices """ n = M.ncols() @@ -452,7 +453,7 @@ def _dig6_to_matrix( dig6 ): sage: from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver sage: dg = ClusterQuiver(['A',4]).digraph() sage: data = _digraph_to_dig6(dg) - sage: _dig6_to_matrix(data) + sage: _dig6_to_matrix(data) # needs sage.modules [ 0 1 0 0] [-1 0 -1 0] [ 0 1 0 1] diff --git a/src/sage/combinat/cluster_algebra_quiver/mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py index b5eddce4393..3ff53f5dd31 100644 --- a/src/sage/combinat/cluster_algebra_quiver/mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Helper functions for mutation types of quivers @@ -55,20 +56,20 @@ def is_mutation_finite(M, nr_of_checks=None): sage: from sage.combinat.cluster_algebra_quiver.mutation_type import is_mutation_finite sage: Q = ClusterQuiver(['A',10]) - sage: M = Q.b_matrix() - sage: is_mutation_finite(M) + sage: M = Q.b_matrix() # needs sage.modules + sage: is_mutation_finite(M) # needs sage.modules (True, None) sage: Q = ClusterQuiver([(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(2,9)]) - sage: M = Q.b_matrix() - sage: is_mutation_finite(M) # random + sage: M = Q.b_matrix() # needs sage.modules + sage: is_mutation_finite(M) # random # needs sage.modules (False, [9, 6, 9, 8, 9, 4, 0, 4, 5, 2, 1, 0, 1, 0, 7, 1, 9, 2, 5, 7, 8, 6, 3, 0, 2, 5, 4, 2, 6, 9, 2, 7, 3, 5, 3, 7, 9, 5, 9, 0, 2, 7, 9, 2, 4, 2, 1, 6, 9, 4, 3, 5, 0, 8, 2, 9, 5, 3, 7, 0, 1, 8, 3, 7, 2, 7, 3, 4, 8, 0, 4, 9, 5, 2, 8, 4, 8, 1, 7, 8, 9, 1, 5, 0, 8, 7, 4, 8, 9, 8, 0, 7, 4, 7, 1, 2, 8, 6, 1, 3, 9, 3, 9, 1, 3, 2, 4, 9, 5, 1, 2, 9, 4, 8, 5, 3, 4, 6, 8, 9, 2, 5, 9, 4, 6, 2, 1, 4, 9, 6, 0, 9, 8, 0, 4, 7, 9, 2, 1, 6]) Check that :trac:`19495` is fixed:: - sage: dg = DiGraph(); dg.add_vertex(0); S = ClusterSeed(dg); S + sage: dg = DiGraph(); dg.add_vertex(0); S = ClusterSeed(dg); S # needs sage.modules A seed for a cluster algebra of rank 1 - sage: S.is_mutation_finite() + sage: S.is_mutation_finite() # needs sage.modules True """ import random @@ -284,7 +285,7 @@ def _check_special_BC_cases(dg, n, check_letter_list, check_twist_list, return 'unknown' # divides into cases depending on whether or not a list 'conn_vert_list' of connecting vertices is given. if conn_vert_list: - mut_type = _connected_mutation_type_AAtildeD( dg, ret_conn_vert = True ) + mut_type = _connected_mutation_type_AAtildeD( dg, ret_conn_vert=True ) # when 'conn_vert_list' is given, the output of _connected_mutation_type_AAtildeD is # either 'unknown' or a pair (mut_type, conn_verts). Then, it is tested if the vertices can be glued together as desired. if not mut_type == 'unknown': @@ -292,7 +293,7 @@ def _check_special_BC_cases(dg, n, check_letter_list, check_twist_list, else: # when conn_vert_list == False, the output of _connected_mutation_type _AAtildeD is simply 'unknown' or the mutation type. # no 'connecting vertices' need to be computed. - mut_type = _connected_mutation_type_AAtildeD( dg, ret_conn_vert = False ) + mut_type = _connected_mutation_type_AAtildeD( dg, ret_conn_vert=False ) conn_verts = [] # when the mutation type is recognized, program now tries more specifically to figure out 'letter' and 'twist' if not mut_type == 'unknown': @@ -310,7 +311,7 @@ def _check_special_BC_cases(dg, n, check_letter_list, check_twist_list, if conn_vert_list: conn_verts = list(set(dg).difference(conn_verts)) if mut_type._letter == hope_letter and not mut_type._twist and conn_vert.issubset(conn_verts): - if len(check_letter)>1: + if len(check_letter) > 1: check_twist = 1 if check_twist: n -= 1 @@ -763,7 +764,7 @@ def _connected_mutation_type(dg): elif len( exc_labels ) == 1: label = exc_labels[0] v_out = label[0] - v_in = label[1] + v_in = label[1] label = label[2] if label == (1,-2): if dict_in_out[ v_in ][0] == 1 and dict_in_out[ v_in ][1] == 0: @@ -895,7 +896,7 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False): dg_tmp = DiGraph( dg ) dg_tmp.delete_vertices( c1 ) - components = dg_tmp.connected_components() + components = dg_tmp.connected_components(sort=False) # if not len(components) == 2: if len(components) != 2: return _false_return(4) @@ -937,7 +938,7 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False): else: c2.reverse() dg_tmp.delete_edge( tuple( c2 ) ) - components = dg_tmp.connected_components() + components = dg_tmp.connected_components(sort=False) if len(components) != 2: return _false_return(7) else: @@ -1189,7 +1190,7 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False): edge = long_cycle[0][0] sg = DiGraph( dg ) sg. delete_vertices(edge) - connected_components = sg.connected_components() + connected_components = sg.connected_components(sort=False) cycle = [] if connected_components: cycle.append( ( edge[0], edge[1], len( connected_components[0] ) + 1 ) ) @@ -1199,7 +1200,7 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False): for edge in tmp: sg = DiGraph( dg ) sg. delete_vertices(edge) - connected_components = sg.connected_components() + connected_components = sg.connected_components(sort=False) if len( connected_components ) == 2: #if len( list_intersection( [ connected_components[0], list_substract( long_cycle[0], [edge] )[0] ] ) ) > 0: if len( set(connected_components[0]).intersection( set(long_cycle[0]).difference([edge]).pop() ) ) > 0: @@ -1428,7 +1429,7 @@ def _random_tests(mt, k, mut_class=None, nr_mut=5): TESTS:: sage: from sage.combinat.cluster_algebra_quiver.mutation_type import _random_tests - sage: _random_tests( ['A',3], 1) + sage: _random_tests( ['A',3], 1) # needs sage.modules testing ['A', 3] """ from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index ae459dd8838..23d4e5c3a62 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs sage.modules r""" Quiver @@ -36,20 +36,18 @@ # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # **************************************************************************** +from copy import copy +from itertools import product from sage.structure.sage_object import SageObject -from copy import copy from sage.rings.integer_ring import ZZ -from sage.rings.cc import CC from sage.rings.infinity import infinity from sage.graphs.digraph import DiGraph from sage.graphs.graph import Graph from sage.graphs.views import EdgesView from sage.arith.misc import gcd -from sage.modules.free_module_element import vector -from sage.matrix.constructor import matrix -from sage.categories.cartesian_product import cartesian_product from sage.misc.misc_c import prod +from sage.misc.lazy_import import lazy_import from sage.rings.rational_field import QQ from sage.rings.polynomial.polynomial_ring import polygen from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType, QuiverMutationType_Irreducible, QuiverMutationType_Reducible, _edge_list_to_matrix @@ -58,6 +56,9 @@ from sage.combinat.cluster_algebra_quiver.interact import cluster_interact +lazy_import('sage.modules.free_module_element', 'vector') +lazy_import('sage.matrix.constructor', 'matrix') + class ClusterQuiver(SageObject): """ @@ -67,14 +68,14 @@ class ClusterQuiver(SageObject): - ``data`` -- can be any of the following:: - * QuiverMutationType - * str - a string representing a QuiverMutationType or a common quiver type (see Examples) - * ClusterQuiver - * Matrix - a skew-symmetrizable matrix - * DiGraph - must be the input data for a quiver - * List of edges - must be the edge list of a digraph for a quiver + * :class:`QuiverMutationType` + * :class:`str` -- a string representing a :class:`QuiverMutationType` or a common quiver type (see Examples) + * :class:`ClusterQuiver` + * :class:`Matrix` -- a skew-symmetrizable matrix + * :class:`DiGraph` -- must be the input data for a quiver + * List of edges -- must be the edge list of a digraph for a quiver - - ``frozen`` -- (default:``None``) sets the list of frozen variables + - ``frozen`` -- (default: ``None``) sets the list of frozen variables if the input type is a :class:`DiGraph`, it is ignored otherwise - ``user_labels`` -- (default:``None``) sets the names of the labels for @@ -364,7 +365,7 @@ def __init__(self, data, frozen=None, user_labels=None): elif n+m == 1: self._description = 'Quiver on 1 vertex' else: - self._description = 'Quiver on %d vertices' %(n+m) + self._description = 'Quiver on %d vertices' % (n+m) # constructs a quiver from a digraph elif isinstance(data, DiGraph): @@ -549,16 +550,18 @@ def plot(self, circular=True, center=(0, 0), directed=True, mark=None, EXAMPLES:: sage: Q = ClusterQuiver(['A',5]) - sage: Q.plot() + sage: Q.plot() # needs sage.plot sage.symbolic Graphics object consisting of 15 graphics primitives - sage: Q.plot(circular=True) + sage: Q.plot(circular=True) # needs sage.plot sage.symbolic Graphics object consisting of 15 graphics primitives - sage: Q.plot(circular=True, mark=1) + sage: Q.plot(circular=True, mark=1) # needs sage.plot sage.symbolic Graphics object consisting of 15 graphics primitives """ from sage.plot.colors import rainbow from sage.graphs.graph_generators import GraphGenerators - from sage.all import e, pi, I + from sage.symbolic.constants import e, pi + from sage.rings.cc import CC + from sage.rings.imaginary_unit import I graphs = GraphGenerators() # returns positions for graph vertices on two concentric cycles with radius 1 and 2 @@ -698,7 +701,7 @@ def interact(self, fig_size=1, circular=True): TESTS:: sage: S = ClusterQuiver(['A',4]) - sage: S.interact() + sage: S.interact() # needs sage.plot sage.symbolic ...VBox(children=... """ return cluster_interact(self, fig_size, circular, kind="quiver") @@ -716,7 +719,7 @@ def save_image(self, filename, circular=False): sage: Q = ClusterQuiver(['F',4,[1,2]]) sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot sage.symbolic ....: Q.save_image(f.name) """ graph_plot = self.plot(circular=circular) @@ -741,7 +744,7 @@ def qmu_save(self, filename=None): sage: Q = ClusterQuiver(['F',4,[1,2]]) sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".qmu") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".qmu") as f: # needs sage.plot sage.symbolic ....: Q.qmu_save(f.name) Make sure we can save quivers with `m != n` frozen variables, see :trac:`14851`:: @@ -750,7 +753,7 @@ def qmu_save(self, filename=None): sage: T1 = S.principal_extension() sage: Q = T1.quiver() sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".qmu") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".qmu") as f: # needs sage.plot sage.symbolic ....: Q.qmu_save(f.name) """ M = self.b_matrix() @@ -1003,7 +1006,7 @@ def mutation_type(self): # checking the type for each connected component mutation_type = [] - connected_components = sorted(dg.connected_components()) + connected_components = sorted(dg.connected_components(sort=False)) for component in connected_components: # constructing the digraph for this component dg_component = dg.subgraph( component ) @@ -1153,7 +1156,7 @@ def canonical_label(self, certificate=False): if dg.is_connected(): Q._mutation_type = self._mutation_type else: - CC = sorted( self._digraph.connected_components() ) + CC = sorted(self._digraph.connected_components(sort=False)) CC_new = sorted(zip([sorted(iso[i] for i in L) for L in CC], range(len(CC)))) comp_iso = [L[1] for L in CC_new] @@ -1474,14 +1477,16 @@ def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2 ): INPUT: - ``sequence`` -- a list or tuple of vertices of ``self``. - - ``show_sequence`` -- (default: False) if True, a png containing the mutation sequence is shown. + - ``show_sequence`` -- (default: ``False``) if ``True``, a png containing the mutation sequence is shown. - ``fig_size`` -- (default: 1.2) factor by which the size of the sequence is expanded. EXAMPLES:: sage: Q = ClusterQuiver(['A',4]) sage: seq = Q.mutation_sequence([0,1]); seq - [Quiver on 4 vertices of type ['A', 4], Quiver on 4 vertices of type ['A', 4], Quiver on 4 vertices of type ['A', 4]] + [Quiver on 4 vertices of type ['A', 4], + Quiver on 4 vertices of type ['A', 4], + Quiver on 4 vertices of type ['A', 4]] sage: [T.b_matrix() for T in seq] [ [ 0 1 0 0] [ 0 -1 0 0] [ 0 1 -1 0] @@ -1490,8 +1495,6 @@ def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2 ): [ 0 0 -1 0], [ 0 0 -1 0], [ 0 0 -1 0] ] """ - from sage.plot.plot import Graphics - from sage.plot.text import text n = self._n m = self._m if m == 0: @@ -1508,7 +1511,7 @@ def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2 ): raise ValueError('The quiver can only be mutated at a vertex or at a sequence of vertices') if any(v not in V for v in sequence): v = next(v for v in sequence if v not in V) - raise ValueError('The quiver can only be mutated at the vertex %s'%v ) + raise ValueError('The quiver can only be mutated at the vertex %s' % v ) quiver = copy( self ) quiver_sequence = [] @@ -1519,9 +1522,13 @@ def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2 ): quiver_sequence.append( copy( quiver ) ) if show_sequence: + from sage.plot.plot import Graphics + from sage.plot.text import text + def _plot_arrow( v, k, center=(0,0) ): return text(r"$\longleftrightarrow$",(center[0],center[1]), fontsize=25) + text(r"$\mu_"+str(v)+"$",(center[0],center[1]+0.15), fontsize=15) \ + text("$"+str(k)+"$",(center[0],center[1]-0.2), fontsize=15) + plot_sequence = [ quiver_sequence[i].plot( circular=True, center=(i*width_factor,0) ) for i in range(len(quiver_sequence)) ] arrow_sequence = [ _plot_arrow( sequence[i],i+1,center=((i+0.5)*width_factor,0) ) for i in range(len(sequence)) ] sequence = [] @@ -2101,8 +2108,8 @@ def poincare_semistable(self, theta, d): mu_d = theta.dot_product(d) / sum(d) Li = [0 * d] - it = (vector(e) for e in cartesian_product([range(d_i + 1) - for d_i in d])) + it = (vector(e) for e in product(*[range(d_i + 1) + for d_i in d])) Li += [e for e in it if e.dot_product(theta) > mu_d * sum(e)] Li.append(d) N = len(Li) - 1 diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py index 80e66662a2e..60e9e78c3bf 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Quiver mutation types @@ -23,13 +24,15 @@ from copy import copy from sage.structure.unique_representation import UniqueRepresentation from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.graphs.digraph import DiGraph from sage.graphs.graph import Graph -from sage.arith.all import binomial, euler_phi +from sage.arith.misc import binomial, euler_phi from sage.misc.misc_c import prod -from sage.matrix.constructor import matrix + +lazy_import('sage.matrix.constructor', 'matrix') class QuiverMutationTypeFactory(SageObject): @@ -324,7 +327,7 @@ def _samples(self): replacing all positive entries by their negatives and adding `2`'s on the main diagonal. -``QuiverMutationType`` constructs a quiver mutation type object. For +:class:`QuiverMutationType` constructs a quiver mutation type object. For more detail on the possible different types, please see the compendium. @@ -677,7 +680,7 @@ def plot(self, circular=False, directed=True): INPUT: - - ``circular`` -- (default:``False``) if ``True``, the + - ``circular`` -- (default: ``False``) if ``True``, the circular plot is chosen, otherwise >>spring<< is used. - ``directed`` -- (default: ``True``) if ``True``, the @@ -686,8 +689,8 @@ def plot(self, circular=False, directed=True): EXAMPLES:: sage: QMT = QuiverMutationType(['A',5]) - sage: pl = QMT.plot() - sage: pl = QMT.plot(circular=True) + sage: pl = QMT.plot() # needs sage.plot sage.symbolic + sage: pl = QMT.plot(circular=True) # needs sage.plot sage.symbolic """ return self.standard_quiver().plot(circular=circular, directed=directed) @@ -706,7 +709,7 @@ def show(self, circular=False, directed=True): TESTS:: sage: QMT = QuiverMutationType(['A',5]) - sage: QMT.show() # long time + sage: QMT.show() # long time # needs sage.plot sage.symbolic """ self.plot(circular=circular, directed=directed).show() @@ -783,9 +786,9 @@ def b_matrix(self): EXAMPLES:: - sage: mut_type = QuiverMutationType( ['A',5] ); mut_type + sage: mut_type = QuiverMutationType(['A',5]); mut_type ['A', 5] - sage: mut_type.b_matrix() + sage: mut_type.b_matrix() # needs sage.modules [ 0 1 0 0 0] [-1 0 -1 0 0] [ 0 1 0 1 0] @@ -794,7 +797,7 @@ def b_matrix(self): sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type [ ['A', 3], ['B', 3] ] - sage: mut_type.b_matrix() + sage: mut_type.b_matrix() # needs sage.modules [ 0 1 0 0 0 0] [-1 0 -1 0 0 0] [ 0 1 0 0 0 0] @@ -851,7 +854,7 @@ def cartan_matrix(self): sage: mut_type = QuiverMutationType(['A',5]); mut_type ['A', 5] - sage: mut_type.cartan_matrix() + sage: mut_type.cartan_matrix() # needs sage.modules [ 2 -1 0 0 0] [-1 2 -1 0 0] [ 0 -1 2 -1 0] @@ -860,7 +863,7 @@ def cartan_matrix(self): sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type [ ['A', 3], ['B', 3] ] - sage: mut_type.cartan_matrix() + sage: mut_type.cartan_matrix() # needs sage.modules [ 2 -1 0 0 0 0] [-1 2 -1 0 0 0] [ 0 -1 2 0 0 0] @@ -1103,7 +1106,7 @@ def properties(self): class QuiverMutationType_Irreducible(QuiverMutationType_abstract): """ The mutation type for a cluster algebra or a quiver. Should not be - called directly, but through QuiverMutationType. + called directly, but through :class:`QuiverMutationType`. """ def __init__(self, letter, rank, twist=None): @@ -1692,7 +1695,7 @@ def class_size(self): which are mutation equivalent to the standard quiver of ``self`` (up to isomorphism) is returned. - Otherwise, ``NotImplemented`` is returned. + Otherwise, :obj:`NotImplemented` is returned. Formula for finite type A is taken from Torkildsen - Counting cluster-tilted algebras of type `A_n`. @@ -1896,7 +1899,7 @@ def class_size(self): def dual(self): """ - Return the QuiverMutationType which is dual to ``self``. + Return the :class:`QuiverMutationType` which is dual to ``self``. EXAMPLES:: @@ -1960,8 +1963,8 @@ def dual(self): class QuiverMutationType_Reducible(QuiverMutationType_abstract): """ The mutation type for a cluster algebra or a quiver. Should not be - called directly, but through QuiverMutationType. Inherits from - QuiverMutationType_abstract. + called directly, but through :class:`QuiverMutationType`. Inherits from + :class:`QuiverMutationType_abstract`. """ def __init__(self, *args): @@ -2054,7 +2057,7 @@ def class_size(self): which are mutation equivalent to the standard quiver of ``self`` (up to isomorphism) is returned. - Otherwise, ``NotImplemented`` is returned. + Otherwise, :obj:`NotImplemented` is returned. EXAMPLES:: @@ -2093,7 +2096,7 @@ def class_size(self): def dual(self): """ - Return the QuiverMutationType which is dual to ``self``. + Return the :class:`QuiverMutationType` which is dual to ``self``. EXAMPLES:: @@ -2294,7 +2297,7 @@ def save_quiver_data(n, up_to=True, types='ClassicalExceptional', verbose=True): INPUT: - - ``n``: the rank (or the upper limit on the rank) of the mutation + - ``n`` -- the rank (or the upper limit on the rank) of the mutation classes that are being saved. - ``up_to`` -- (default:``True``) if ``True``, saves data for @@ -2435,17 +2438,17 @@ def _edge_list_to_matrix(edges, nlist, mlist) -> matrix: sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _edge_list_to_matrix sage: G = QuiverMutationType(['A', 2])._digraph - sage: _edge_list_to_matrix(G.edges(sort=True), [0, 1], []) + sage: _edge_list_to_matrix(G.edges(sort=True), [0, 1], []) # needs sage.modules [ 0 1] [-1 0] sage: G2 = DiGraph([('a', 'b', 1)]) - sage: _edge_list_to_matrix(G2.edges(sort=True), ['a', 'b'], []) + sage: _edge_list_to_matrix(G2.edges(sort=True), ['a', 'b'], []) # needs sage.modules [ 0 1] [-1 0] sage: G3 = DiGraph([('a', 'b', 1), ('b', 'c', 1)]) - sage: _edge_list_to_matrix(G3.edges(sort=True), ['a', 'b'], ['c']) + sage: _edge_list_to_matrix(G3.edges(sort=True), ['a', 'b'], ['c']) # needs sage.modules [ 0 1] [-1 0] [ 0 -1] diff --git a/src/sage/combinat/cluster_complex.py b/src/sage/combinat/cluster_complex.py index edc4f235aeb..e263d983887 100644 --- a/src/sage/combinat/cluster_complex.py +++ b/src/sage/combinat/cluster_complex.py @@ -222,10 +222,6 @@ def __init__(self, W, k, coxeter_element, algorithm): self._W = W self._w0 = w self._k = k - if k == 1: - self.__custom_name = 'Cluster complex' - else: - self.__custom_name = 'Multi-cluster complex' self.set_immutable() @@ -271,7 +267,10 @@ def _repr_(self): sage: ClusterComplex(['A', 2])._repr_() "Cluster complex of type ['A', 2] with 5 vertices and 5 facets" """ - name = self.__custom_name + if self._k == 1: + name = 'Cluster complex' + else: + name = 'Multi-cluster complex' name += (' of type %s with %s vertices and %s facets' % (self.cartan_type(), len(self.vertices()), len(self._facets))) diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index 28b20e502af..d97624a218d 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -7,6 +7,7 @@ generalized to `G \wr S_n` """ import itertools +from random import choice from sage.structure.element import MultiplicativeGroupElement from sage.structure.parent import Parent @@ -87,6 +88,8 @@ def __len__(self): """ Return the length of the one line form of ``self``. + EXAMPLES:: + sage: C = ColoredPermutations(2, 3) sage: s1,s2,t = C.gens() sage: len(s1) @@ -311,13 +314,13 @@ def has_left_descent(self, i): [False, True, False, True] """ if self.parent()._m == 1: - return self._perm[i-1] > self._perm[i] + return self._perm[i - 1] > self._perm[i] if i == self.parent()._n: return self._colors[-1] != 0 - if self._colors[i-1] != 0: - return self._colors[i] == 0 or self._perm[i-1] < self._perm[i] - return self._colors[i] == 0 and self._perm[i-1] > self._perm[i] + if self._colors[i - 1] != 0: + return self._colors[i] == 0 or self._perm[i - 1] < self._perm[i] + return self._colors[i] == 0 and self._perm[i - 1] > self._perm[i] def reduced_word(self): r""" @@ -561,7 +564,7 @@ def coxeter_matrix(self): """ from sage.combinat.root_system.cartan_type import CartanType if self._m == 1: - return CartanType(['A', self._n-1]).coxeter_matrix() + return CartanType(['A', self._n - 1]).coxeter_matrix() return CartanType(['B', self._n]).coxeter_matrix() @cached_method @@ -578,6 +581,23 @@ def one(self): return self.element_class(self, [self._C.zero()] * self._n, self._P.identity()) + def random_element(self): + """ + Return an element drawn uniformly at random. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s = C.random_element(); s # random + [[0, 2, 1], [2, 1, 3]] + sage: s in C + True + """ + return self.element_class(self, + [self._C.random_element() + for _ in range(self._n)], + self._P.random_element()) + def simple_reflection(self, i): r""" Return the ``i``-th simple reflection of ``self``. @@ -881,7 +901,7 @@ def codegrees(self): True """ # Special case for the usual symmetric group - last = self._n-1 if self._m == 1 else self._n + last = self._n - 1 if self._m == 1 else self._n return tuple(self._m * i for i in reversed(range(last))) def number_of_reflection_hyperplanes(self): @@ -977,8 +997,9 @@ def is_well_generated(self): Element = ColoredPermutation + ##################################################################### -## Signed permutations +# Signed permutations class SignedPermutation(ColoredPermutation, @@ -1120,11 +1141,11 @@ def __call__(self, i): if i in ZZ and 1 <= abs(i) <= len(self): i = ZZ(i) if i < 0: - return -self._colors[-i-1] * self._perm[-i-1] - return self._colors[i-1] * self._perm[i-1] - else: - raise TypeError("i (= %s) must equal +/- an integer between %s and %s" - % (i,1,len(self))) + return -self._colors[-i - 1] * self._perm[-i - 1] + return self._colors[i - 1] * self._perm[i - 1] + + raise TypeError("i (= %s) must equal +/- an integer between %s and %s" + % (i, 1, len(self))) def to_matrix(self): """ @@ -1168,14 +1189,13 @@ def has_left_descent(self, i): return self._colors[i] == 1 or self._perm[i - 1] < self._perm[i] return self._colors[i] == 1 and self._perm[i - 1] > self._perm[i] - def to_cycles(self, singletons=True, use_min=True, negative_singletons=True): - """ + def to_cycles(self, singletons=True, use_min=True, negative_cycles=True): + r""" Return the signed permutation ``self`` as a list of disjoint cycles. The cycles are returned in the order of increasing smallest elements, and each cycle is returned as a tuple which starts - with its smallest positive element. We do not include the - corresponding negative cycles. + with its smallest positive element. INPUT: @@ -1184,18 +1204,30 @@ def to_cycles(self, singletons=True, use_min=True, negative_singletons=True): - ``use_min`` -- (default: ``True``) if ``False``, the cycles are returned in the order of increasing *largest* (not smallest) elements, and each cycle starts with its largest element + - ``negative_cycles`` -- (default: ``True``) if ``False``, for any + two cycles `C^{\pm} = \{\pm c_1, \ldots, \pm c_k\}` such that + `C^+ \neq C^-`, this does not include the cycle `C^-` + + .. WARNING:: + + The arugment ``negative_cycles`` does not refer to the usual + definition of a negative cycle; see :meth:`cycle_type`. EXAMPLES:: sage: pi = SignedPermutations(7)([2,-1,4,-6,-5,-3,7]) sage: pi.to_cycles() - [(1, 2, -1, -2), (3, 4, -6), (5, -5), (7,)] + [(1, 2, -1, -2), (3, 4, -6), (-3, -4, 6), (5, -5), (7,), (-7,)] sage: pi.to_cycles(singletons=False) + [(1, 2, -1, -2), (3, 4, -6), (-3, -4, 6), (5, -5)] + sage: pi.to_cycles(negative_cycles=False) + [(1, 2, -1, -2), (3, 4, -6), (5, -5), (7,)] + sage: pi.to_cycles(singletons=False, negative_cycles=False) [(1, 2, -1, -2), (3, 4, -6), (5, -5)] sage: pi.to_cycles(use_min=False) - [(7,), (6, -3, -4), (5, -5), (2, -1, -2, 1)] + [(7,), (-7,), (6, -3, -4), (-6, 3, 4), (5, -5), (2, -1, -2, 1)] sage: pi.to_cycles(singletons=False, use_min=False) - [(6, -3, -4), (5, -5), (2, -1, -2, 1)] + [(6, -3, -4), (-6, 3, 4), (5, -5), (2, -1, -2, 1)] """ cycles = [] @@ -1214,19 +1246,70 @@ def to_cycles(self, singletons=True, use_min=True, negative_singletons=True): cycle = [cycle_first] l[i], next_val = False, l[i] s = self._colors[i] + add_neg = True while next_val != cycle_first: cycle.append(s * next_val) - s *= self._colors[next_val-1] - l[next_val-1], next_val = False, l[next_val-1] + s *= self._colors[next_val - 1] + l[next_val - 1], next_val = False, l[next_val - 1] if s != 1: cycle.extend([-e for e in cycle]) + add_neg = False # Add the cycle to the list of cycles if singletons or len(cycle) > 1: cycles.append(tuple(cycle)) + if negative_cycles and add_neg: + cycles.append(tuple([-e for e in cycle])) return cycles + def cycle_type(self): + r""" + Return a pair of partitions of ``len(self)`` corresponding to the + signed cycle type of ``self``. + + A *cycle* is a tuple `C = (c_0, \ldots, c_{k-1})` with + `\pi(c_i) = c_{i+1}` for `0 \leq i < k` and `\pi(c_{k-1}) = c_0`. + If `C` is a cycle, `\overline{C} = (-c_0, \ldots, -c_{k-1})` is + also a cycle. A cycle is *negative*, if `C = \overline{C}` up + to cyclic reordering. In this case, `k` is necessarily even + and the length of `C` is `k/2`. A *positive cycle* is a pair + `C \overline{C}`, its length is `k`. + + Let `\alpha` be the partition whose parts are the lengths of the + positive cycles and let `\beta` be the partition whose parts are + the lengths of the negative cycles. Then `(\alpha, \beta)` is + the cycle type of `\pi`. + + EXAMPLES:: + + sage: G = SignedPermutations(7) + sage: pi = G([2, -1, 4, -6, -5, -3, 7]) + sage: pi.cycle_type() + ([3, 1], [2, 1]) + + sage: G = SignedPermutations(5) + sage: all(pi.cycle_type().size() == 5 for pi in G) + True + sage: set(pi.cycle_type() for pi in G) == set(PartitionTuples(2, 5)) + True + """ + cycles = self.to_cycles(negative_cycles=False) + pos_cycles = [] + neg_cycles = [] + for C in cycles: + if (not len(C) % 2) and C[0] == -C[len(C)//2]: + neg_cycles.append(C) + else: + pos_cycles.append(C) + pos_type = [len(C) for C in pos_cycles] + pos_type.sort(reverse=True) + neg_type = [len(C) // 2 for C in neg_cycles] + neg_type.sort(reverse=True) + from sage.combinat.partition_tuple import PartitionTuples + PT = PartitionTuples(2, self.parent()._n) + return PT([pos_type, neg_type]) + def order(self): """ Return the multiplicative order of the signed permutation. @@ -1235,11 +1318,11 @@ def order(self): sage: pi = SignedPermutations(7)([2,-1,4,-6,-5,-3,7]) sage: pi.to_cycles(singletons=False) - [(1, 2, -1, -2), (3, 4, -6), (5, -5)] + [(1, 2, -1, -2), (3, 4, -6), (-3, -4, 6), (5, -5)] sage: pi.order() 12 """ - return lcm(len(c) for c in self.to_cycles(singletons=False)) + return lcm(len(c) for c in self.to_cycles(singletons=False, negative_cycles=False)) class SignedPermutations(ColoredPermutations): @@ -1297,7 +1380,6 @@ class SignedPermutations(ColoredPermutations): - :wikipedia:`Hyperoctahedral_group` """ - def __init__(self, n): """ Initialize ``self``. @@ -1334,6 +1416,23 @@ def one(self): return self.element_class(self, [ZZ.one()] * self._n, self._P.identity()) + def random_element(self): + """ + Return an element drawn uniformly at random. + + EXAMPLES:: + + sage: C = SignedPermutations(7) + sage: s = C.random_element(); s # random + [7, 6, -4, -5, 2, 3, -1] + sage: s in C + True + """ + return self.element_class(self, + [choice([ZZ.one(), -ZZ.one()]) + for _ in range(self._n)], + self._P.random_element()) + def simple_reflection(self, i): r""" Return the ``i``-th simple reflection of ``self``. @@ -1452,7 +1551,7 @@ def _coerce_map_from_(self, C): False """ if isinstance(C, Permutations) and C.n == self._n: - return lambda P, x: P.element_class(P, [1]*P._n, x) + return lambda P, x: P.element_class(P, [1] * P._n, x) if isinstance(C, ColoredPermutations) and C._n == self._n and C._m == 2: return lambda P, x: P.element_class(P, [1 if v == 0 else -1 @@ -1491,10 +1590,73 @@ def long_element(self, index_set=None): return super(SignedPermutations, self).long_element() return self.element_class(self, [-ZZ.one()] * self._n, self._P.one()) + def conjugacy_class_representative(self, nu): + r""" + Return a permutation with (signed) cycle type ``nu``. + + EXAMPLES:: + + sage: G = SignedPermutations(4) + sage: for nu in PartitionTuples(2, 4): + ....: print(nu, G.conjugacy_class_representative(nu)) + ....: assert nu == G.conjugacy_class_representative(nu).cycle_type(), nu + ([4], []) [2, 3, 4, 1] + ([3, 1], []) [2, 3, 1, 4] + ([2, 2], []) [2, 1, 4, 3] + ([2, 1, 1], []) [2, 1, 3, 4] + ([1, 1, 1, 1], []) [1, 2, 3, 4] + ([3], [1]) [2, 3, 1, -4] + ([2, 1], [1]) [2, 1, 3, -4] + ([1, 1, 1], [1]) [1, 2, 3, -4] + ([2], [2]) [2, 1, 4, -3] + ([2], [1, 1]) [2, 1, -3, -4] + ([1, 1], [2]) [1, 2, 4, -3] + ([1, 1], [1, 1]) [1, 2, -3, -4] + ([1], [3]) [1, 3, 4, -2] + ([1], [2, 1]) [1, 3, -2, -4] + ([1], [1, 1, 1]) [1, -2, -3, -4] + ([], [4]) [2, 3, 4, -1] + ([], [3, 1]) [2, 3, -1, -4] + ([], [2, 2]) [2, -1, 4, -3] + ([], [2, 1, 1]) [2, -1, -3, -4] + ([], [1, 1, 1, 1]) [-1, -2, -3, -4] + + TESTS:: + + sage: all(nu == SignedPermutations(n).conjugacy_class_representative(nu).cycle_type() + ....: for n in range(1, 6) for nu in PartitionTuples(2, n)) + True + """ + from sage.combinat.partition_tuple import PartitionTuple + nu = PartitionTuple(nu) + if nu.size() != self._n: + raise ValueError("the size of the partition pair (=%s) must equal" + " the rank (=%s)" % (nu.size(), self._n)) + la, mu = nu + cyc = [] + cnt = 0 + + for i in la: + cyc += [tuple(range(cnt+1, cnt+i+1))] + [tuple(range(-cnt-1, -cnt-i-1, -1))] + cnt += i + for i in mu: + cyc += [tuple(range(cnt+1, cnt+i+1)) + tuple(range(-cnt-1, -cnt-i-1, -1))] + cnt += i + + p = [None] * self._n + for c in cyc: + for i in range(len(c)-1): + if c[i] > 0: + p[c[i]-1] = c[i+1] + if c[-1] > 0: + p[c[-1]-1] = c[0] + + return self(p) + Element = SignedPermutation # TODO: Make this a subgroup -#class EvenSignedPermutations(SignedPermutations): +# class EvenSignedPermutations(SignedPermutations): # """ # Group of even signed permutations. # """ diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index a4ad56b0170..4b763bb5af8 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -64,18 +64,12 @@ **Implemented in other modules (listed for completeness):** -The ``sage.arith.all`` module contains the following +The package :mod:`sage.arith` contains the following combinatorial functions: -- binomial the binomial coefficient (wrapped from PARI) +- :func:`binomial` the binomial coefficient (wrapped from PARI) -- factorial (wrapped from PARI) - -- partition (from the Python Cookbook) Generator of the list of - all the partitions of the integer `n`. - -- :func:`number_of_partitions` (wrapped from PARI) the - *number* of partitions: +- :func:`factorial` (wrapped from PARI) - :func:`falling_factorial` Definition: for integer `a \ge 0` we have `x(x-1) \cdots (x-a+1)`. In all @@ -87,7 +81,12 @@ other cases we use the GAMMA-function: `\frac {\Gamma(x+a)} {\Gamma(x)}`. -- gaussian_binomial the gaussian binomial +From other modules: + +- :func:`number_of_partitions` (wrapped from PARI) the + *number* of partitions: + +- :func:`sage.combinat.q_analogues.gaussian_binomial` the Gaussian binomial .. MATH:: @@ -167,15 +166,13 @@ from __future__ import annotations from typing import Iterator +from sage.arith.misc import bernoulli, factorial from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.integer import Integer from sage.rings.infinity import infinity -from sage.arith.all import bernoulli, factorial from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.libs.pari.all import pari -from sage.misc.prandom import randint from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_function from sage.structure.sage_object import SageObject @@ -187,7 +184,10 @@ from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.element import Element + lazy_import('sage.interfaces.maxima_lib', 'maxima') +lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.misc.prandom', 'randint') def bell_number(n, algorithm='flint', **options) -> Integer: @@ -319,17 +319,17 @@ def bell_number(n, algorithm='flint', **options) -> Integer: EXAMPLES:: - sage: bell_number(10) + sage: bell_number(10) # optional - sage.libs.flint 115975 - sage: bell_number(2) + sage: bell_number(2) # optional - sage.libs.flint 2 - sage: bell_number(-10) + sage: bell_number(-10) # optional - sage.libs.flint Traceback (most recent call last): ... ArithmeticError: Bell numbers not defined for negative indices - sage: bell_number(1) + sage: bell_number(1) # optional - sage.libs.flint 1 - sage: bell_number(1/3) + sage: bell_number(1/3) # optional - sage.libs.flint Traceback (most recent call last): ... TypeError: no conversion of this rational to integer @@ -339,17 +339,17 @@ def bell_number(n, algorithm='flint', **options) -> Integer: first time, we deem the precision too low, we use our guess to (temporarily) raise mpmath's precision and the Bell number is recomputed. :: - sage: k = bell_number(30, 'mpmath'); k + sage: k = bell_number(30, 'mpmath'); k # optional - mpmath 846749014511809332450147 - sage: k == bell_number(30) + sage: k == bell_number(30) # optional - mpmath sage.libs.flint True If you knows what precision is necessary before computing the Bell number, you can use the ``prec`` option:: - sage: k2 = bell_number(30, 'mpmath', prec=30); k2 + sage: k2 = bell_number(30, 'mpmath', prec=30); k2 # optional - mpmath 846749014511809332450147 - sage: k == k2 + sage: k == k2 # optional - mpmath True .. WARNING:: @@ -357,18 +357,19 @@ def bell_number(n, algorithm='flint', **options) -> Integer: Running mpmath with the precision set too low can result in incorrect results:: - sage: k = bell_number(30, 'mpmath', prec=15); k + sage: k = bell_number(30, 'mpmath', prec=15); k # optional - mpmath 846749014511809388871680 - sage: k == bell_number(30) + sage: k == bell_number(30) # optional - mpmath sage.libs.flint False TESTS:: - sage: all(bell_number(n) == bell_number(n,'dobinski') for n in range(100)) + sage: all(bell_number(n) == bell_number(n,'dobinski') for n in range(100)) # optional - sage.libs.flint True - sage: all(bell_number(n) == bell_number(n,'gap') for n in range(100)) + sage: all(bell_number(n) == bell_number(n,'gap') for n in range(100)) # optional - sage.libs.flint sage.libs.gap True - sage: all(bell_number(n) == bell_number(n,'mpmath', prec=500) for n in range(200, 220)) + sage: all(bell_number(n) == bell_number(n,'mpmath', prec=500) # optional - mpmath sage.libs.flint + ....: for n in range(200, 220)) True AUTHORS: @@ -547,12 +548,12 @@ def euler_number(n, algorithm='flint') -> Integer: EXAMPLES:: - sage: [euler_number(i) for i in range(10)] + sage: [euler_number(i) for i in range(10)] # optional - sage.libs.flint [1, 0, -1, 0, 5, 0, -61, 0, 1385, 0] sage: x = PowerSeriesRing(QQ, 'x').gen().O(10) - sage: 2/(exp(x)+exp(-x)) + sage: 2/(exp(x)+exp(-x)) # optional - sage.symbolic 1 - 1/2*x^2 + 5/24*x^4 - 61/720*x^6 + 277/8064*x^8 + O(x^10) - sage: [euler_number(i)/factorial(i) for i in range(11)] + sage: [euler_number(i)/factorial(i) for i in range(11)] # optional - sage.libs.flint [1, 0, -1/2, 0, 5/24, 0, -61/720, 0, 277/8064, 0, -50521/3628800] sage: euler_number(-1) Traceback (most recent call last): @@ -561,7 +562,7 @@ def euler_number(n, algorithm='flint') -> Integer: TESTS:: - sage: euler_number(6, 'maxima') + sage: euler_number(6, 'maxima') # optional - sage.symbolic -61 REFERENCES: @@ -705,21 +706,21 @@ def fibonacci(n, algorithm="pari") -> Integer: EXAMPLES:: - sage: fibonacci(10) + sage: fibonacci(10) # optional - sage.libs.pari 55 - sage: fibonacci(10, algorithm='gap') + sage: fibonacci(10, algorithm='gap') # optional - sage.libs.gap 55 :: - sage: fibonacci(-100) + sage: fibonacci(-100) # optional - sage.libs.pari -354224848179261915075 - sage: fibonacci(100) + sage: fibonacci(100) # optional - sage.libs.pari 354224848179261915075 :: - sage: fibonacci(0) + sage: fibonacci(0) # optional - sage.libs.pari 0 sage: fibonacci(1/2) Traceback (most recent call last): @@ -758,17 +759,17 @@ def lucas_number1(n, P, Q): EXAMPLES:: - sage: lucas_number1(5,1,-1) + sage: lucas_number1(5,1,-1) # optional - sage.libs.gap 5 - sage: lucas_number1(6,1,-1) + sage: lucas_number1(6,1,-1) # optional - sage.libs.gap 8 - sage: lucas_number1(7,1,-1) + sage: lucas_number1(7,1,-1) # optional - sage.libs.gap 13 - sage: lucas_number1(7,1,-2) + sage: lucas_number1(7,1,-2) # optional - sage.libs.gap 43 - sage: lucas_number1(5,2,3/5) + sage: lucas_number1(5,2,3/5) # optional - sage.libs.gap 229/25 - sage: lucas_number1(5,2,1.5) + sage: lucas_number1(5,2,1.5) # optional - sage.libs.gap 1/4 There was a conjecture that the sequence `L_n` defined by @@ -776,8 +777,9 @@ def lucas_number1(n, P, Q): `L_2=3`, has the property that `n` prime implies that `L_n` is prime. :: - sage: lucas = lambda n : Integer((5/2)*lucas_number1(n,1,-1)+(1/2)*lucas_number2(n,1,-1)) - sage: [[lucas(n),is_prime(lucas(n)),n+1,is_prime(n+1)] for n in range(15)] + sage: def lucas(n): + ....: return Integer((5/2)*lucas_number1(n,1,-1) + (1/2)*lucas_number2(n,1,-1)) + sage: [[lucas(n), is_prime(lucas(n)), n+1, is_prime(n+1)] for n in range(15)] # optional - sage.libs.gap [[1, False, 1, False], [3, True, 2, True], [4, False, 3, True], @@ -825,26 +827,26 @@ def lucas_number2(n, P, Q): EXAMPLES:: - sage: [lucas_number2(i,1,-1) for i in range(10)] + sage: [lucas_number2(i,1,-1) for i in range(10)] # optional - sage.libs.gap [2, 1, 3, 4, 7, 11, 18, 29, 47, 76] - sage: [fibonacci(i-1)+fibonacci(i+1) for i in range(10)] + sage: [fibonacci(i-1)+fibonacci(i+1) for i in range(10)] # optional - sage.libs.pari [2, 1, 3, 4, 7, 11, 18, 29, 47, 76] :: - sage: n = lucas_number2(5,2,3); n + sage: n = lucas_number2(5,2,3); n # optional - sage.libs.gap 2 - sage: type(n) + sage: type(n) # optional - sage.libs.gap <class 'sage.rings.integer.Integer'> - sage: n = lucas_number2(5,2,-3/9); n + sage: n = lucas_number2(5,2,-3/9); n # optional - sage.libs.gap 418/9 - sage: type(n) + sage: type(n) # optional - sage.libs.gap <class 'sage.rings.rational.Rational'> The case `P=1`, `Q=-1` is the Lucas sequence in Brualdi's Introductory Combinatorics, 4th ed., Prentice-Hall, 2004:: - sage: [lucas_number2(n,1,-1) for n in range(10)] + sage: [lucas_number2(n,1,-1) for n in range(10)] # optional - sage.libs.gap [2, 1, 3, 4, 7, 11, 18, 29, 47, 76] """ n = ZZ(n) @@ -873,20 +875,20 @@ def stirling_number1(n, k, algorithm="gap") -> Integer: EXAMPLES:: - sage: stirling_number1(3,2) + sage: stirling_number1(3,2) # optional - sage.libs.gap 3 - sage: stirling_number1(5,2) + sage: stirling_number1(5,2) # optional - sage.libs.gap 50 - sage: 9*stirling_number1(9,5)+stirling_number1(9,4) + sage: 9*stirling_number1(9,5) + stirling_number1(9,4) # optional - sage.libs.gap 269325 - sage: stirling_number1(10,5) + sage: stirling_number1(10,5) # optional - sage.libs.gap 269325 Indeed, `S_1(n,k) = S_1(n-1,k-1) + (n-1)S_1(n-1,k)`. TESTS:: - sage: stirling_number1(10,5, algorithm='flint') + sage: stirling_number1(10,5, algorithm='flint') # optional - sage.libs.flint 269325 sage: s_sage = stirling_number1(50,3, algorithm="mutta") @@ -975,20 +977,17 @@ def stirling_number2(n, k, algorithm=None) -> Integer: 13707767141249454929449108424328432845001327479099713037876832759323918134840537229737624018908470350134593241314462032607787062188356702932169472820344473069479621239187226765307960899083230982112046605340713218483809366970996051181537181362810003701997334445181840924364501502386001705718466534614548056445414149016614254231944272872440803657763210998284198037504154374028831561296154209804833852506425742041757849726214683321363035774104866182331315066421119788248419742922490386531970053376982090046434022248364782970506521655684518998083846899028416459701847828711541840099891244700173707021989771147674432503879702222276268661726508226951587152781439224383339847027542755222936463527771486827849728880 sage: stirling_number2(500,31) 5832088795102666690960147007601603328246123996896731854823915012140005028360632199516298102446004084519955789799364757997824296415814582277055514048635928623579397278336292312275467402957402880590492241647229295113001728653772550743446401631832152281610081188041624848850056657889275564834450136561842528589000245319433225808712628826136700651842562516991245851618481622296716433577650218003181535097954294609857923077238362717189185577756446945178490324413383417876364657995818830270448350765700419876347023578011403646501685001538551891100379932684279287699677429566813471166558163301352211170677774072447414719380996777162087158124939742564291760392354506347716119002497998082844612434332155632097581510486912 - sage: n = stirling_number2(20,11) - sage: n + sage: n = stirling_number2(20,11); n 1900842429486 sage: type(n) <class 'sage.rings.integer.Integer'> - sage: n = stirling_number2(20,11,algorithm='gap') - sage: n + sage: n = stirling_number2(20, 11, algorithm='gap'); n # optional - sage.libs.gap 1900842429486 - sage: type(n) + sage: type(n) # optional - sage.libs.gap <class 'sage.rings.integer.Integer'> - sage: n = stirling_number2(20,11,algorithm='flint') - sage: n + sage: n = stirling_number2(20, 11, algorithm='flint'); n # optional - sage.libs.flint 1900842429486 - sage: type(n) + sage: type(n) # optional - sage.libs.flint <class 'sage.rings.integer.Integer'> Sage's implementation splitting the computation of the Stirling @@ -997,7 +996,7 @@ def stirling_number2(n, k, algorithm=None) -> Integer: For `n<200`:: - sage: for n in Subsets(range(100,200), 5).random_element(): + sage: for n in Subsets(range(100,200), 5).random_element(): # optional - sage.libs.flint sage.libs.gap ....: for k in Subsets(range(n), 5).random_element(): ....: s_sage = stirling_number2(n,k) ....: s_flint = stirling_number2(n,k, algorithm = "flint") @@ -1007,7 +1006,7 @@ def stirling_number2(n, k, algorithm=None) -> Integer: For `n\geq 200`:: - sage: for n in Subsets(range(200,300), 5).random_element(): + sage: for n in Subsets(range(200,300), 5).random_element(): # optional - sage.libs.flint sage.libs.gap ....: for k in Subsets(range(n), 5).random_element(): ....: s_sage = stirling_number2(n,k) ....: s_flint = stirling_number2(n,k, algorithm = "flint") @@ -1015,10 +1014,10 @@ def stirling_number2(n, k, algorithm=None) -> Integer: ....: if not (s_sage == s_flint and s_sage == s_gap): ....: print("Error with n<200") - sage: stirling_number2(20,3, algorithm="maxima") + sage: stirling_number2(20, 3, algorithm="maxima") # optional - sage.symbolic 580606446 - sage: s_sage = stirling_number2(5,3, algorithm="namba") + sage: s_sage = stirling_number2(5, 3, algorithm="namba") Traceback (most recent call last): ... ValueError: unknown algorithm: namba @@ -1174,11 +1173,11 @@ def __init__(self, l, copy=True): Test indirectly that we copy the input (see :trac:`18184`):: - sage: L = IntegerListsLex(element_class=Partition) - sage: x = [3, 2, 1] - sage: P = L(x) - sage: x[0] = 5 - sage: list(P) + sage: L = IntegerListsLex(element_class=Partition) # optional - sage.combinat + sage: x = [3, 2, 1] # optional - sage.combinat + sage: P = L(x) # optional - sage.combinat + sage: x[0] = 5 # optional - sage.combinat + sage: list(P) # optional - sage.combinat [3, 2, 1] """ if copy: @@ -1513,12 +1512,12 @@ class CombinatorialElement(CombinatorialObject, Element, EXAMPLES:: sage: from sage.combinat.combinat import CombinatorialElement - sage: e = CombinatorialElement(Partitions(6), [3,2,1]) - sage: e == loads(dumps(e)) + sage: e = CombinatorialElement(Partitions(6), [3,2,1]) # optional - sage.combinat + sage: e == loads(dumps(e)) # optional - sage.combinat True - sage: parent(e) + sage: parent(e) # optional - sage.combinat Partitions of the integer 6 - sage: list(e) + sage: list(e) # optional - sage.combinat [3, 2, 1] Check classcalls:: @@ -1616,7 +1615,7 @@ def is_finite(self) -> bool: EXAMPLES:: - sage: Partitions(5).is_finite() + sage: Partitions(5).is_finite() # optional - sage.combinat True sage: Permutations().is_finite() False @@ -1650,7 +1649,7 @@ def __str__(self) -> str: EXAMPLES:: - sage: str(Partitions(5)) + sage: str(Partitions(5)) # optional - sage.combinat 'Partitions of the integer 5' """ return repr(self) @@ -1659,7 +1658,7 @@ def _repr_(self) -> str: """ EXAMPLES:: - sage: repr(Partitions(5)) # indirect doctest + sage: repr(Partitions(5)) # indirect doctest # optional - sage.combinat 'Partitions of the integer 5' """ if hasattr(self, '_name') and self._name: @@ -1682,7 +1681,7 @@ def __contains__(self, x) -> bool: EXAMPLES:: sage: C = CombinatorialClass() - sage: x in C + sage: x in C # optional - sage.symbolic Traceback (most recent call last): ... NotImplementedError @@ -1697,11 +1696,11 @@ def __eq__(self, other): EXAMPLES:: - sage: p5 = Partitions(5) - sage: p6 = Partitions(6) - sage: repr(p5) == repr(p6) + sage: p5 = Partitions(5) # optional - sage.combinat + sage: p6 = Partitions(6) # optional - sage.combinat + sage: repr(p5) == repr(p6) # optional - sage.combinat False - sage: p5 == p6 + sage: p5 == p6 # optional - sage.combinat False """ return repr(self) == repr(other) @@ -1712,9 +1711,9 @@ def __ne__(self, other): EXAMPLES:: - sage: p5 = Partitions(5) - sage: p6 = Partitions(6) - sage: p5 != p6 + sage: p5 = Partitions(5) # optional - sage.combinat + sage: p6 = Partitions(6) # optional - sage.combinat + sage: p5 != p6 # optional - sage.combinat True """ return not (self == other) @@ -1766,14 +1765,14 @@ def __call__(self, x): EXAMPLES:: - sage: p5 = Partitions(5) - sage: a = [2,2,1] - sage: type(a) + sage: p5 = Partitions(5) # optional - sage.combinat + sage: a = [2,2,1] # optional - sage.combinat + sage: type(a) # optional - sage.combinat <class 'list'> - sage: a = p5(a) - sage: type(a) + sage: a = p5(a) # optional - sage.combinat + sage: type(a) # optional - sage.combinat <class 'sage.combinat.partition.Partitions_n_with_category.element_class'> - sage: p5([2,1]) + sage: p5([2,1]) # optional - sage.combinat Traceback (most recent call last): ... ValueError: [2, 1] is not an element of Partitions of the integer 5 @@ -1795,8 +1794,8 @@ def element_class(self): TESTS:: - sage: P5 = Partitions(5) - sage: P5.element_class + sage: P5 = Partitions(5) # optional - sage.combinat + sage: P5.element_class # optional - sage.combinat <class 'sage.combinat.partition.Partitions_n_with_category.element_class'> """ # assert not isinstance(self, Parent) # Raises an alert if we override the proper definition from Parent @@ -1811,9 +1810,9 @@ def _element_constructor_(self, x): TESTS:: - sage: P5 = Partitions(5) - sage: p = P5([3,2]) # indirect doctest - sage: type(p) + sage: P5 = Partitions(5) # optional - sage.combinat + sage: p = P5([3,2]) # indirect doctest # optional - sage.combinat + sage: type(p) # optional - sage.combinat <class 'sage.combinat.partition.Partitions_n_with_category.element_class'> """ # assert not isinstance(self, Parent) # Raises an alert if we override the proper definition from Parent @@ -1829,7 +1828,7 @@ def __list_from_iterator(self): sage: class C(CombinatorialClass): ....: def __iter__(self): ....: return iter([1,2,3]) - sage: C().list() #indirect doctest + sage: C().list() #indirect doctest [1, 2, 3] """ return [x for x in self] @@ -1949,8 +1948,8 @@ def __iter__(self): EXAMPLES:: - sage: p5 = Partitions(5) - sage: [i for i in p5] + sage: p5 = Partitions(5) # optional - sage.combinat + sage: [i for i in p5] # optional - sage.combinat [[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1]] sage: C = CombinatorialClass() sage: iter(C) @@ -2117,7 +2116,7 @@ def filter(self, f, name=None): sage: from sage.combinat.combinat import Permutations_CC sage: P = Permutations_CC(3).filter(lambda x: x.avoids([1,2])) - sage: P.list() + sage: P.list() # optional - sage.combinat [[3, 2, 1]] """ return FilteredCombinatorialClass(self, f, name=name) @@ -2151,7 +2150,8 @@ class by `f`, as a combinatorial class. EXAMPLES:: sage: R = Permutations(3).map(attrcall('reduced_word')); R - Image of Standard permutations of 3 by The map *.reduced_word() from Standard permutations of 3 + Image of Standard permutations of 3 by + The map *.reduced_word() from Standard permutations of 3 sage: R.cardinality() 6 sage: R.list() @@ -2161,15 +2161,15 @@ class by `f`, as a combinatorial class. If the function is not injective, then there may be repeated elements:: - sage: P = Partitions(4) - sage: P.list() + sage: P = Partitions(4) # optional - sage.combinat + sage: P.list() # optional - sage.combinat [[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]] - sage: P.map(len).list() + sage: P.map(len).list() # optional - sage.combinat [1, 2, 2, 3, 4] Use ``is_injective=False`` to get a correct result in this case:: - sage: P.map(len, is_injective=False).list() + sage: P.map(len, is_injective=False).list() # optional - sage.combinat [1, 2, 3, 4] TESTS:: @@ -2225,9 +2225,9 @@ def __contains__(self, x) -> bool: False sage: [4,3,2,1] in P False - sage: Permutation([1,2,3]) in P + sage: Permutation([1,2,3]) in P # optional - sage.combinat False - sage: Permutation([3,2,1]) in P + sage: Permutation([3,2,1]) in P # optional - sage.combinat True """ return x in self.combinatorial_class and self.f(x) @@ -2238,7 +2238,7 @@ def cardinality(self) -> Integer: sage: from sage.combinat.combinat import Permutations_CC sage: P = Permutations_CC(3).filter(lambda x: x.avoids([1,2])) - sage: P.cardinality() + sage: P.cardinality() # optional - sage.combinat 1 """ c = 0 @@ -2252,7 +2252,7 @@ def __iter__(self) -> Iterator: sage: from sage.combinat.combinat import Permutations_CC sage: P = Permutations_CC(3).filter(lambda x: x.avoids([1,2])) - sage: list(P) + sage: list(P) # optional - sage.combinat [[3, 2, 1]] """ for x in self.combinatorial_class: @@ -2481,13 +2481,13 @@ class MapCombinatorialClass(ImageSubobject, CombinatorialClass): EXAMPLES:: - sage: R = SymmetricGroup(10).map(attrcall('reduced_word')) - sage: R.an_element() + sage: R = SymmetricGroup(10).map(attrcall('reduced_word')) # optional - sage.groups + sage: R.an_element() # optional - sage.groups [9, 8, 7, 6, 5, 4, 3, 2] - sage: R.cardinality() + sage: R.cardinality() # optional - sage.groups 3628800 - sage: i = iter(R) - sage: next(i), next(i), next(i) + sage: i = iter(R) # optional - sage.groups + sage: next(i), next(i), next(i) # optional - sage.groups ([], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1]) """ @@ -2495,7 +2495,7 @@ def __init__(self, cc, f, name=None, *, is_injective=True): """ TESTS:: - sage: Partitions(3).map(attrcall('conjugate')) + sage: Partitions(3).map(attrcall('conjugate')) # optional - sage.combinat Image of Partitions of the integer 3 by The map *.conjugate() from Partitions of the integer 3 """ @@ -2625,9 +2625,9 @@ def tuples(S, k, algorithm='itertools'): :: - sage: K.<a> = GF(4, 'a') - sage: mset = [x for x in K if x != 0] - sage: tuples(mset, 2) + sage: K.<a> = GF(4, 'a') # optional - sage.rings.finite_rings + sage: mset = [x for x in K if x != 0] # optional - sage.rings.finite_rings + sage: tuples(mset, 2) # optional - sage.rings.finite_rings [(a, a), (a, a + 1), (a, 1), (a + 1, a), (a + 1, a + 1), (a + 1, 1), (1, a), (1, a + 1), (1, 1)] @@ -2711,16 +2711,16 @@ def number_of_tuples(S, k, algorithm='naive') -> Integer: sage: S = [1,2,3,4,5] sage: number_of_tuples(S,2) 25 - sage: number_of_tuples(S,2, algorithm="gap") + sage: number_of_tuples(S,2, algorithm="gap") # optional - sage.libs.gap 25 sage: S = [1,1,2,3,4,5] sage: number_of_tuples(S,2) 25 - sage: number_of_tuples(S,2, algorithm="gap") + sage: number_of_tuples(S,2, algorithm="gap") # optional - sage.libs.gap 25 sage: number_of_tuples(S,0) 1 - sage: number_of_tuples(S,0, algorithm="gap") + sage: number_of_tuples(S,0, algorithm="gap") # optional - sage.libs.gap 1 """ if algorithm == 'naive': @@ -2772,7 +2772,7 @@ def unordered_tuples(S, k, algorithm='itertools'): We check that this agrees with GAP:: - sage: unordered_tuples(S, 3, algorithm='gap') + sage: unordered_tuples(S, 3, algorithm='gap') # optional - sage.libs.gap [(1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)] We check the result on strings:: @@ -2780,13 +2780,13 @@ def unordered_tuples(S, k, algorithm='itertools'): sage: S = ["a","b","c"] sage: unordered_tuples(S, 2) [('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'b'), ('b', 'c'), ('c', 'c')] - sage: unordered_tuples(S, 2, algorithm='gap') + sage: unordered_tuples(S, 2, algorithm='gap') # optional - sage.libs.gap [('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'b'), ('b', 'c'), ('c', 'c')] Lastly we check on a multiset:: sage: S = [1,1,2] - sage: unordered_tuples(S, 3) == unordered_tuples(S, 3, 'gap') + sage: unordered_tuples(S, 3) == unordered_tuples(S, 3, 'gap') # optional - sage.libs.gap True sage: unordered_tuples(S, 3) [(1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)] @@ -2827,16 +2827,16 @@ def number_of_unordered_tuples(S, k, algorithm='naive') -> Integer: sage: S = [1,2,3,4,5] sage: number_of_unordered_tuples(S,2) 15 - sage: number_of_unordered_tuples(S,2, algorithm="gap") + sage: number_of_unordered_tuples(S,2, algorithm="gap") # optional - sage.libs.gap 15 sage: S = [1,1,2,3,4,5] sage: number_of_unordered_tuples(S,2) 15 - sage: number_of_unordered_tuples(S,2, algorithm="gap") + sage: number_of_unordered_tuples(S,2, algorithm="gap") # optional - sage.libs.gap 15 sage: number_of_unordered_tuples(S,0) 1 - sage: number_of_unordered_tuples(S,0, algorithm="gap") + sage: number_of_unordered_tuples(S,0, algorithm="gap") # optional - sage.libs.gap 1 """ if algorithm == 'naive': @@ -2892,7 +2892,7 @@ def unshuffle_iterator(a, one=1) -> Iterator: [(((), (3, 1)), 3/2), (((3,), (1,)), 3/2), (((1,), (3,)), -3/2), (((3, 1), ()), 3/2)] """ - from sage.misc.misc import powerset + from sage.combinat.subset import powerset n = len(a) for I in powerset(range(n)): sorted_I = tuple(sorted(I)) @@ -2936,19 +2936,19 @@ def bell_polynomial(n: Integer, k: Integer): EXAMPLES:: - sage: bell_polynomial(6,2) + sage: bell_polynomial(6,2) # optional - sage.combinat 10*x2^2 + 15*x1*x3 + 6*x0*x4 - sage: bell_polynomial(6,3) + sage: bell_polynomial(6,3) # optional - sage.combinat 15*x1^3 + 60*x0*x1*x2 + 15*x0^2*x3 TESTS: Check that :trac:`18338` is fixed:: - sage: bell_polynomial(0,0).parent() + sage: bell_polynomial(0,0).parent() # optional - sage.combinat Multivariate Polynomial Ring in x over Integer Ring - sage: for n in (0..4): + sage: for n in (0..4): # optional - sage.combinat ....: print([bell_polynomial(n,k).coefficients() for k in (0..n)]) [[1]] [[], [1]] @@ -2999,13 +2999,12 @@ def fibonacci_sequence(start, stop=None, algorithm=None) -> Iterator: EXAMPLES:: - sage: fibs = [i for i in fibonacci_sequence(10, 20)] - sage: fibs + sage: fibs = [i for i in fibonacci_sequence(10, 20)]; fibs # optional - sage.libs.pari [55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181] :: - sage: sum([i for i in fibonacci_sequence(100, 110)]) + sage: sum([i for i in fibonacci_sequence(100, 110)]) # optional - sage.libs.pari 69919376923075308730013 .. SEEALSO:: @@ -3039,26 +3038,25 @@ def fibonacci_xrange(start, stop=None, algorithm='pari') -> Iterator: EXAMPLES:: - sage: fibs_in_some_range = [i for i in fibonacci_xrange(10^7, 10^8)] - sage: len(fibs_in_some_range) + sage: fibs_in_some_range = [i for i in fibonacci_xrange(10^7, 10^8)] # optional - sage.libs.pari + sage: len(fibs_in_some_range) # optional - sage.libs.pari 4 - sage: fibs_in_some_range + sage: fibs_in_some_range # optional - sage.libs.pari [14930352, 24157817, 39088169, 63245986] :: - sage: fibs = [i for i in fibonacci_xrange(10, 100)] - sage: fibs + sage: fibs = [i for i in fibonacci_xrange(10, 100)]; fibs # optional - sage.libs.pari [13, 21, 34, 55, 89] :: - sage: list(fibonacci_xrange(13, 34)) + sage: list(fibonacci_xrange(13, 34)) # optional - sage.libs.pari [13, 21] A solution to the second Project Euler problem:: - sage: sum([i for i in fibonacci_xrange(10^6) if is_even(i)]) + sage: sum([i for i in fibonacci_xrange(10^6) if is_even(i)]) # optional - sage.libs.pari 1089154 .. SEEALSO:: @@ -3116,30 +3114,30 @@ def bernoulli_polynomial(x, n: Integer): EXAMPLES:: sage: y = QQ['y'].0 - sage: bernoulli_polynomial(y, 5) + sage: bernoulli_polynomial(y, 5) # optional - sage.libs.flint y^5 - 5/2*y^4 + 5/3*y^3 - 1/6*y - sage: bernoulli_polynomial(y, 5)(12) + sage: bernoulli_polynomial(y, 5)(12) # optional - sage.libs.flint 199870 - sage: bernoulli_polynomial(12, 5) + sage: bernoulli_polynomial(12, 5) # optional - sage.libs.flint 199870 - sage: bernoulli_polynomial(y^2 + 1, 5) + sage: bernoulli_polynomial(y^2 + 1, 5) # optional - sage.libs.flint y^10 + 5/2*y^8 + 5/3*y^6 - 1/6*y^2 sage: P.<t> = ZZ[] - sage: p = bernoulli_polynomial(t, 6) - sage: p.parent() + sage: p = bernoulli_polynomial(t, 6) # optional - sage.libs.flint + sage: p.parent() # optional - sage.libs.flint Univariate Polynomial Ring in t over Rational Field We verify an instance of the formula which is the origin of the Bernoulli polynomials (and numbers):: sage: power_sum = sum(k^4 for k in range(10)) - sage: 5*power_sum == bernoulli_polynomial(10, 5) - bernoulli(5) + sage: 5*power_sum == bernoulli_polynomial(10, 5) - bernoulli(5) # optional - sage.libs.flint True TESTS:: sage: x = polygen(QQ, 'x') - sage: bernoulli_polynomial(x, 0).parent() + sage: bernoulli_polynomial(x, 0).parent() # optional - sage.libs.flint Univariate Polynomial Ring in x over Rational Field REFERENCES: @@ -3151,7 +3149,7 @@ def bernoulli_polynomial(x, n: Integer): if n < 0: raise TypeError except TypeError: - raise ValueError("The second argument must be a non-negative integer") + raise ValueError("the second argument must be a non-negative integer") if n == 0: return x**0 # result should be in the parent of x diff --git a/src/sage/combinat/combinat_cython.pxd b/src/sage/combinat/combinat_cython.pxd index c27be7b0bed..40cae00a781 100644 --- a/src/sage/combinat/combinat_cython.pxd +++ b/src/sage/combinat/combinat_cython.pxd @@ -2,7 +2,4 @@ from sage.libs.gmp.all cimport mpz_t cdef mpz_stirling_s2(mpz_t s, unsigned long n, unsigned long k) -cdef list from_word(list w, list base_set) - cdef list convert(Py_ssize_t* f, Py_ssize_t n) - diff --git a/src/sage/combinat/combinat_cython.pyx b/src/sage/combinat/combinat_cython.pyx index 3d8e8042311..c0905491ac2 100644 --- a/src/sage/combinat/combinat_cython.pyx +++ b/src/sage/combinat/combinat_cython.pyx @@ -1,3 +1,4 @@ +# cython: binding=True """ Fast computation of combinatorial functions (Cython + mpz) @@ -16,12 +17,16 @@ AUTHORS: Lyndon words, and perfect matchings """ -cimport cython - from cysignals.memory cimport check_allocarray, sig_free from sage.libs.gmp.all cimport * from sage.rings.integer cimport Integer +from sage.misc.lazy_import import LazyImport + +set_partition_iterator = LazyImport('sage.combinat.set_partition_iterator', 'set_partition_iterator', deprecation=35741) +set_partition_iterator_blocks = LazyImport('sage.combinat.set_partition_iterator', 'set_partition_iterator_blocks', deprecation=35741) +linear_extension_iterator = LazyImport('sage.combinat.posets.linear_extension_iterator', 'linear_extension_iterator', deprecation=35741) + cdef void mpz_addmul_alt(mpz_t s, mpz_t t, mpz_t u, unsigned long parity): """ @@ -199,133 +204,6 @@ def lyndon_word_iterator(Py_ssize_t n, Py_ssize_t k): while a[i] == n - 1: i -= 1 -##################################################################### -## Set partition iterators - -@cython.wraparound(False) -@cython.boundscheck(False) -cdef list from_word(list w, list base_set): - cdef list sp = [] - cdef Py_ssize_t i - cdef Py_ssize_t b - for i in range(len(w)): - b = <Py_ssize_t> (w[i]) - x = base_set[i] - if len(sp) <= b: - sp.append([x]) - else: - sp[b].append(x) - return sp - -@cython.wraparound(False) -@cython.boundscheck(False) -def set_partition_iterator(base_set): - """ - A fast iterator for the set partitions of the base set, which - returns lists of lists instead of set partitions types. - - EXAMPLES:: - - sage: from sage.combinat.combinat_cython import set_partition_iterator - sage: list(set_partition_iterator([1,-1,x])) - [[[1, -1, x]], - [[1, -1], [x]], - [[1, x], [-1]], - [[1], [-1, x]], - [[1], [-1], [x]]] - """ - cdef list base = list(base_set) - - # Knuth, TAOCP 4A 7.2.1.5, Algorithm H - cdef Py_ssize_t N = len(base) - # H1: initialize - cdef list a = [0] * N - if N <= 1: - yield from_word(a, base) - return - - cdef list b = [1] * N - cdef Py_ssize_t j - cdef Py_ssize_t last = N - 1 - while True: - # H2: visit - yield from_word(a, base) - if a[last] == b[last]: - # H4: find j - j = N - 2 - while a[j] == b[j]: - j -= 1 - # H5: increase a_j - if j == 0: - break - a[j] += 1 - # H6: zero out a_{j+1},...,a_{n-1} - b[last] = b[j] + int(a[j] == b[j]) - j += 1 - while j < N - 1: - a[j] = 0 - b[j] = b[last] - j += 1 - a[last] = 0 - else: - # H3: increase a_{n-1} - a[last] += 1 - -@cython.wraparound(False) -@cython.boundscheck(False) -def _set_partition_block_gen(Py_ssize_t n, Py_ssize_t k, list a): - r""" - Recursively generate set partitions of ``n`` with fixed block - size ``k`` using Algorithm 4.23 from [Rus2003]_. - ``a`` is a list of size ``n``. - - EXAMPLES:: - - sage: from sage.combinat.combinat_cython import _set_partition_block_gen - sage: a = list(range(3)) - sage: for p in _set_partition_block_gen(3, 2, a): - ....: print(p) - [0, 1, 0] - [0, 1, 1] - [0, 0, 1] - """ - cdef Py_ssize_t i - if n == k: - yield a - return - - for i in range(k): - a[n-1] = i - for P in _set_partition_block_gen(n-1, k, a): - yield P - a[n-1] = n-1 - if k > 1: - a[n-1] = k-1 - for P in _set_partition_block_gen(n-1, k-1, a): - yield P - a[n-1] = n-1 - -@cython.wraparound(False) -@cython.boundscheck(False) -def set_partition_iterator_blocks(base_set, Py_ssize_t k): - """ - A fast iterator for the set partitions of the base set into the - specified number of blocks, which returns lists of lists - instead of set partitions types. - - EXAMPLES:: - - sage: from sage.combinat.combinat_cython import set_partition_iterator_blocks - sage: list(set_partition_iterator_blocks([1,-1,x], 2)) - [[[1, x], [-1]], [[1], [-1, x]], [[1, -1], [x]]] - """ - cdef list base = list(base_set) - cdef Py_ssize_t n = len(base) - cdef list a = list(range(n)) - # TODO: implement _set_partition_block_gen as an iterative algorithm - for P in _set_partition_block_gen(n, k, a): - yield from_word(<list> P, base) - ## Perfect matchings iterator def perfect_matchings_iterator(Py_ssize_t n): @@ -410,292 +288,6 @@ cdef list convert(Py_ssize_t* f, Py_ssize_t n): ret.append((i, f[i])) return ret -##################################################################### -## Linear extension iterator - -from copy import copy -def _linear_extension_prepare(D): - r""" - The preprocessing routine in Figure 7 of "Generating Linear - Extensions Fast" by Preusse and Ruskey. - - INPUT: - - - ``D``, the Hasse diagram of a poset - - OUTPUT: - - - a triple ``(le, a, b)``, where ``le`` is the first linear - extension, and ``a`` and ``b`` are lists such that ``a[i]`` and - ``b[i]`` are minimal elements of ``D`` after removing ``a[:i]`` - and ``b[:i]``. - - TESTS:: - - sage: from sage.combinat.combinat_cython import _linear_extension_prepare - sage: D = Poset({ 0:[1,2], 1:[3], 2:[3,4] })._hasse_diagram - sage: _linear_extension_prepare(D) - ([0, 1, 2, 3, 4], [1, 3], [2, 4]) - - """ - dag_copy = copy(D) # this copy is destroyed during preparation - le = [] - a = [] - b = [] - - # the preprocessing routine found in Figure 7 of - # "Generating Linear Extensions Fast" by - # Pruesse and Ruskey - while dag_copy.num_verts() != 0: - # find all the minimal elements of dag_copy - minimal_elements = dag_copy.sources() - if not minimal_elements: - raise ValueError("the digraph must be acyclic to have linear extensions") - elif len(minimal_elements) == 1: - le.append(minimal_elements[0]) - dag_copy.delete_vertex(minimal_elements[0]) - else: - ap = minimal_elements[0] - bp = minimal_elements[1] - a.append(ap) - b.append(bp) - le.append(ap) - le.append(bp) - dag_copy.delete_vertex(ap) - dag_copy.delete_vertex(bp) - - return (le, a, b) - -@cython.wraparound(False) -@cython.boundscheck(False) -cdef void _linear_extension_switch(list _le, list _a, list _b, list _is_plus, Py_ssize_t i): - """ - This implements the ``Switch`` procedure described on page 7 - of "Generating Linear Extensions Fast" by Pruesse and Ruskey. - - If ``i == -1``, then the sign is changed. Otherwise, then - ``_a[i]`` and ``_b[i]`` are transposed. - - """ - cdef Py_ssize_t a_index, b_index - if i == -1: - _is_plus[0] = not _is_plus[0] - else: - a = _a[i] - b = _b[i] - a_index = _le.index(a) - b_index = _le.index(b) - _le[a_index] = b - _le[b_index] = a - _b[i] = a - _a[i] = b - -@cython.wraparound(False) -@cython.boundscheck(False) -cdef bint _linear_extension_right_a(_D, list _le, list _a, list _b, Py_ssize_t i): - """ - Return ``True`` if and only if ``_a[i]`` is incomparable with the - element to its right in ``_le`` and the element to the right is - not ``_b[i]``. - - This is the ``Right`` function described on page 8 of - "Generating Linear Extensions Fast" by Pruesse and Ruskey. - - :: - - sage: D = Poset({ 0:[1,2], 1:[3], 2:[3,4] })._hasse_diagram # not tested - sage: _linear_extension_right_a(D, [0, 1, 2, 4, 3], [1, 4], [2, 3], 0) # not tested - False - sage: _linear_extension_right_a(D, [0, 1, 2, 4, 3], [1, 4], [2, 3], 1) # not tested - False - - """ - cdef Py_ssize_t yindex - x = _a[i] - yindex = _le.index(x) + 1 - if yindex >= len(_le): - return False - y = _le[yindex] - return y != _b[i] and _D.are_incomparable(x, y) - -@cython.wraparound(False) -@cython.boundscheck(False) -cdef bint _linear_extension_right_b(_D, list _le, list _a, list _b, Py_ssize_t i): - """ - Return True if and only if ``_b[i]`` is incomparable with the - elements to its right in ``_le``. - - This is the ``Right`` function described on page 8 of - "Generating Linear Extensions Fast" by Pruesse and Ruskey. - - :: - - sage: D = Poset({ 0:[1,2], 1:[3], 2:[3,4] })._hasse_diagram # not tested - sage: _linear_extension_right_b(D, [0, 1, 2, 4, 3], [1, 4], [2, 3], 0) # not tested - False - sage: _linear_extension_right_b(D, [0, 1, 2, 4, 3], [1, 4], [2, 3], 1) # not tested - False - - """ - cdef Py_ssize_t yindex - x = _b[i] - yindex = _le.index(x) + 1 - if yindex >= len(_le): - return False - y = _le[yindex] - return _D.are_incomparable(x, y) - -@cython.wraparound(False) -@cython.boundscheck(False) -def _linear_extension_gen(_D, list _le, list _a, list _b, list _is_plus, Py_ssize_t i): - """ - This a Python version of the GenLE routine found in Figure 8 - of "Generating Linear Extensions Fast" by Pruesse and Ruskey. - - TESTS:: - - sage: from sage.combinat.combinat_cython import _linear_extension_prepare, _linear_extension_gen - sage: D = Poset({ 0:[1,2], 1:[3], 2:[3,4] })._hasse_diagram - sage: le, a, b = _linear_extension_prepare(D) - sage: [e for e in _linear_extension_gen(D, le, a, b, [True], len(a)-1)] - [[0, 2, 1, 3, 4]] - - """ - cdef int mra, mrb, mla - cdef Py_ssize_t index, index1 - cdef bint typical - if i == -1: - return - - for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): - yield e - mrb = 0 - typical = False - while _linear_extension_right_b(_D, _le, _a, _b, i): - mrb += 1 - # move_right - index = _le.index(_b[i]) - index1 = index + 1 - _le[index] = _le[index1] - _le[index1] = _b[i] - if _is_plus[0]: - yield _le[:] - - for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): - yield e - mra = 0 - while _linear_extension_right_a(_D, _le, _a, _b, i): - typical = True - mra += 1 - # move_right - index = _le.index(_a[i]) - index1 = index+1 - _le[index] = _le[index1] - _le[index1] = _a[i] - if _is_plus[0]: - yield _le[:] - - for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): - yield e - - if typical: - _linear_extension_switch(_le, _a, _b, _is_plus, i-1) - if _is_plus[0]: - yield _le[:] - - for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): - yield e - if mrb % 2 == 1: - mla = mra - 1 - else: - mla = mra + 1 - for _ in range(mla): - # move_left - index = _le.index(_a[i]) - index1 = index-1 - _le[index] = _le[index1] - _le[index1] = _a[i] - if _is_plus[0]: - yield _le[:] - - for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): - yield e - - if typical and (mrb % 2 == 1): - # move_left - index = _le.index(_a[i]) - index1 = index-1 - _le[index] = _le[index1] - _le[index1] = _a[i] - if _is_plus[0]: - yield _le[:] - else: - _linear_extension_switch(_le, _a, _b, _is_plus, i-1) - if _is_plus[0]: - yield _le[:] - for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): - yield e - for _ in range(mrb): - # move_left - index = _le.index(_b[i]) - index1 = index-1 - _le[index] = _le[index1] - _le[index1] = _b[i] - if _is_plus[0]: - yield _le[:] - - for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): - yield e - - -def linear_extension_iterator(D): - """ - Iterate over the linear extensions of the poset. - - The list ``_le`` keeps track of the current linear extensions. The - boolean variable ``is_plus`` keeps track of the "sign". - - INPUT: - - - ``D``, the Hasse diagram of a poset. - - .. WARNING:: - - It is assumed that ``D`` is not modified while the linear - extensions are generated. - - EXAMPLES:: - - sage: from sage.combinat.combinat_cython import linear_extension_iterator - sage: D = Poset({ 0:[1,2], 1:[3], 2:[3,4] })._hasse_diagram - sage: list(linear_extension_iterator(D)) - [[0, 1, 2, 3, 4], - [0, 2, 1, 3, 4], - [0, 2, 1, 4, 3], - [0, 2, 4, 1, 3], - [0, 1, 2, 4, 3]] - - sage: D = posets.BooleanLattice(3)._hasse_diagram - sage: len(list(linear_extension_iterator(D))) - 48 - - sage: D = posets.AntichainPoset(9)._hasse_diagram - sage: len(list(linear_extension_iterator(D))) == factorial(9) # long time - True - """ - _le, _a, _b = _linear_extension_prepare(D) - _max_pair = len(_a) - 1 - _is_plus = [True] # this is modified by _linear_extension_switch - - yield _le[:] - for e in _linear_extension_gen(D, _le, _a, _b, _is_plus, _max_pair): - yield e - _linear_extension_switch(_le, _a, _b, _is_plus, _max_pair) - if _is_plus[0]: - yield _le[:] - for e in _linear_extension_gen(D, _le, _a, _b, _is_plus, _max_pair): - yield e - ##################################################################### ## Set partition composition @@ -711,7 +303,7 @@ def set_partition_composition(tuple sp1, tuple sp2): sage: sp1 = ((1,-2),(2,-1)) sage: sp2 = ((1,-2),(2,-1)) sage: p, c = set_partition_composition(sp1, sp2) - sage: (SetPartition(p), c) == (SetPartition([[1,-1],[2,-2]]), 0) + sage: (SetPartition(p), c) == (SetPartition([[1,-1],[2,-2]]), 0) # optional - sage.combinat True """ cdef int num_loops = 0 # The number of loops removed @@ -762,7 +354,7 @@ def set_partition_composition(tuple sp1, tuple sp2): diagram.append(tuple(block)) # Everything else should be completely contained in the top block - assert all(all(val > 0 for val in top) for top in remaining_top) + assert all(val > 0 for top in remaining_top for val in top) diagram.extend(remaining_top) return (tuple(diagram), num_loops) diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index 810e55308ec..fc8b044d89d 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -28,7 +28,7 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.arith.all import binomial +from sage.arith.misc import binomial from .integer_vector import IntegerVectors from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.structure.parent import Parent @@ -148,15 +148,15 @@ class of combinations of ``mset`` of size ``k``. It is possible to take combinations of Sage objects:: - sage: Combinations([vector([1,1]), vector([2,2]), vector([3,3])], 2).list() + sage: Combinations([vector([1,1]), vector([2,2]), vector([3,3])], 2).list() # optional - sage.modules [[(1, 1), (2, 2)], [(1, 1), (3, 3)], [(2, 2), (3, 3)]] TESTS: We check that the code works even for non mutable objects:: - sage: l = [vector((0,0)), vector((0,1))] - sage: Combinations(l).list() + sage: l = [vector((0,0)), vector((0,1))] # optional - sage.modules + sage: Combinations(l).list() # optional - sage.modules [[], [(0, 0)], [(0, 1)], [(0, 0), (0, 1)]] """ # Check to see if everything in mset is unique @@ -269,7 +269,7 @@ def cardinality(self): sage: Combinations([1,2,3]).cardinality() 8 - sage: Combinations(['a','a','b']).cardinality() + sage: Combinations(['a','a','b']).cardinality() # optional - sage.libs.gap 6 """ c = 0 @@ -431,7 +431,7 @@ def cardinality(self): EXAMPLES:: sage: mset = [1,1,2,3,4,4,5] - sage: Combinations(mset,2).cardinality() + sage: Combinations(mset,2).cardinality() # optional - sage.libs.gap 12 """ from sage.libs.gap.libgap import libgap diff --git a/src/sage/combinat/combinatorial_map.py b/src/sage/combinat/combinatorial_map.py index 2f1055d8793..0ff4ffe34bc 100644 --- a/src/sage/combinat/combinatorial_map.py +++ b/src/sage/combinat/combinatorial_map.py @@ -227,7 +227,7 @@ def __init__(self, f, order=None, name=None): """ import types if not isinstance(f, types.FunctionType): - raise ValueError("Only plain functions are supported") + raise ValueError("only plain functions are supported") self._f = f self._order = order self._name = name @@ -302,9 +302,9 @@ def __call__(self, *args, **kwds): sage: p = Permutation([1,3,2,4]) sage: cm = type(p).left_tableau; cm Combinatorial map: Robinson-Schensted insertion tableau - sage: cm(p) + sage: cm(p) # optional - sage.combinat [[1, 2, 4], [3]] - sage: cm(Permutation([4,3,2,1])) + sage: cm(Permutation([4,3,2,1])) # optional - sage.combinat [[1], [2], [3], [4]] """ if self._inst is not None: diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 0ef49a900b0..829ba9e8a8e 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -172,18 +172,18 @@ def _ascii_art_(self): """ TESTS:: - sage: ascii_art(Compositions(4).list()) + sage: ascii_art(Compositions(4).list()) # optional - sage.combinat [ * ] [ * ** * * ] [ * * ** *** * ** * ] [ *, * , * , * , **, ** , ***, **** ] - sage: Partitions.options(diagram_str='#', convention="French") - sage: ascii_art(Compositions(4).list()) + sage: Partitions.options(diagram_str='#', convention="French") # optional - sage.combinat + sage: ascii_art(Compositions(4).list()) # optional - sage.combinat [ # ] [ # # # ## ] [ # # ## # # ## ### ] [ #, ##, #, ###, #, ##, #, #### ] - sage: Partitions.options._reset() + sage: Partitions.options._reset() # optional - sage.combinat """ from sage.typeset.ascii_art import ascii_art return ascii_art(self.to_skew_partition()) @@ -192,20 +192,20 @@ def _unicode_art_(self): """ TESTS:: - sage: unicode_art(Compositions(4).list()) + sage: unicode_art(Compositions(4).list()) # optional - sage.combinat โŽก โ”Œโ” โŽค โŽข โ”œโ”ค โ”Œโ”ฌโ” โ”Œโ” โ”Œโ” โŽฅ โŽข โ”œโ”ค โ”œโ”ผโ”˜ โ”Œโ”ผโ”ค โ”Œโ”ฌโ”ฌโ” โ”œโ”ค โ”Œโ”ฌโ” โ”Œโ” โŽฅ โŽข โ”œโ”ค โ”œโ”ค โ”œโ”ผโ”˜ โ”œโ”ผโ”ดโ”˜ โ”Œโ”ผโ”ค โ”Œโ”ผโ”ผโ”˜ โ”Œโ”ฌโ”ผโ”ค โ”Œโ”ฌโ”ฌโ”ฌโ” โŽฅ โŽฃ โ””โ”˜, โ””โ”˜ , โ””โ”˜ , โ””โ”˜ , โ””โ”ดโ”˜, โ””โ”ดโ”˜ , โ””โ”ดโ”ดโ”˜, โ””โ”ดโ”ดโ”ดโ”˜ โŽฆ - sage: Partitions.options(diagram_str='#', convention="French") - sage: unicode_art(Compositions(4).list()) + sage: Partitions.options(diagram_str='#', convention="French") # optional - sage.combinat + sage: unicode_art(Compositions(4).list()) # optional - sage.combinat โŽก โ”Œโ” โŽค โŽข โ”œโ”ค โ”Œโ” โ”Œโ” โ”Œโ”ฌโ” โŽฅ โŽข โ”œโ”ค โ”œโ”ค โ”œโ”ผโ” โ”Œโ” โ””โ”ผโ”ค โ”Œโ”ฌโ” โ”Œโ”ฌโ”ฌโ” โŽฅ โŽข โ”œโ”ค โ”œโ”ผโ” โ””โ”ผโ”ค โ”œโ”ผโ”ฌโ” โ”œโ”ค โ””โ”ผโ”ผโ” โ””โ”ดโ”ผโ”ค โ”Œโ”ฌโ”ฌโ”ฌโ” โŽฅ โŽฃ โ””โ”˜, โ””โ”ดโ”˜, โ””โ”˜, โ””โ”ดโ”ดโ”˜, โ””โ”˜, โ””โ”ดโ”˜, โ””โ”˜, โ””โ”ดโ”ดโ”ดโ”˜ โŽฆ - sage: Partitions.options._reset() + sage: Partitions.options._reset() # optional - sage.combinat """ from sage.typeset.unicode_art import unicode_art return unicode_art(self.to_skew_partition()) @@ -254,7 +254,7 @@ def conjugate(self) -> Composition: The ribbon shape of the conjugate of `I` is the conjugate of the ribbon shape of `I`:: - sage: all( I.conjugate().to_skew_partition() + sage: all( I.conjugate().to_skew_partition() # optional - sage.combinat ....: == I.to_skew_partition().conjugate() ....: for I in Compositions(4) ) True @@ -1178,11 +1178,11 @@ def to_partition(self): EXAMPLES:: - sage: Composition([2,1,3]).to_partition() + sage: Composition([2,1,3]).to_partition() # optional - sage.combinat [3, 2, 1] - sage: Composition([4,2,2]).to_partition() + sage: Composition([4,2,2]).to_partition() # optional - sage.combinat [4, 2, 2] - sage: Composition([]).to_partition() + sage: Composition([]).to_partition() # optional - sage.combinat [] """ from sage.combinat.partition import Partition @@ -1202,15 +1202,15 @@ def to_skew_partition(self, overlap=1): EXAMPLES:: - sage: Composition([3,4,1]).to_skew_partition() + sage: Composition([3,4,1]).to_skew_partition() # optional - sage.combinat [6, 6, 3] / [5, 2] - sage: Composition([3,4,1]).to_skew_partition(overlap=0) + sage: Composition([3,4,1]).to_skew_partition(overlap=0) # optional - sage.combinat [8, 7, 3] / [7, 3] - sage: Composition([]).to_skew_partition() + sage: Composition([]).to_skew_partition() # optional - sage.combinat [] / [] - sage: Composition([1,2]).to_skew_partition() + sage: Composition([1,2]).to_skew_partition() # optional - sage.combinat [2, 1] / [] - sage: Composition([2,1]).to_skew_partition() + sage: Composition([2,1]).to_skew_partition() # optional - sage.combinat [2, 2] / [1] """ from sage.combinat.skew_partition import SkewPartition @@ -1264,38 +1264,46 @@ def shuffle_product(self, other, overlap=False): sage: alph = Composition([2,2]) sage: beta = Composition([1,1,3]) - sage: S = alph.shuffle_product(beta); S + sage: S = alph.shuffle_product(beta); S # optional - sage.combinat Shuffle product of [2, 2] and [1, 1, 3] - sage: S.list() - [[2, 2, 1, 1, 3], [2, 1, 2, 1, 3], [2, 1, 1, 2, 3], [2, 1, 1, 3, 2], [1, 2, 2, 1, 3], [1, 2, 1, 2, 3], [1, 2, 1, 3, 2], [1, 1, 2, 2, 3], [1, 1, 2, 3, 2], [1, 1, 3, 2, 2]] + sage: S.list() # optional - sage.combinat + [[2, 2, 1, 1, 3], [2, 1, 2, 1, 3], [2, 1, 1, 2, 3], [2, 1, 1, 3, 2], + [1, 2, 2, 1, 3], [1, 2, 1, 2, 3], [1, 2, 1, 3, 2], [1, 1, 2, 2, 3], + [1, 1, 2, 3, 2], [1, 1, 3, 2, 2]] The *overlapping* shuffle product of `[2,2]` and `[1,1,3]`:: sage: alph = Composition([2,2]) sage: beta = Composition([1,1,3]) - sage: O = alph.shuffle_product(beta, overlap=True); O + sage: O = alph.shuffle_product(beta, overlap=True); O # optional - sage.combinat Overlapping shuffle product of [2, 2] and [1, 1, 3] - sage: O.list() - [[2, 2, 1, 1, 3], [2, 1, 2, 1, 3], [2, 1, 1, 2, 3], [2, 1, 1, 3, 2], [1, 2, 2, 1, 3], [1, 2, 1, 2, 3], [1, 2, 1, 3, 2], [1, 1, 2, 2, 3], [1, 1, 2, 3, 2], [1, 1, 3, 2, 2], [3, 2, 1, 3], [2, 3, 1, 3], [3, 1, 2, 3], [2, 1, 3, 3], [3, 1, 3, 2], [2, 1, 1, 5], [1, 3, 2, 3], [1, 2, 3, 3], [1, 3, 3, 2], [1, 2, 1, 5], [1, 1, 5, 2], [1, 1, 2, 5], [3, 3, 3], [3, 1, 5], [1, 3, 5]] + sage: O.list() # optional - sage.combinat + [[2, 2, 1, 1, 3], [2, 1, 2, 1, 3], [2, 1, 1, 2, 3], [2, 1, 1, 3, 2], + [1, 2, 2, 1, 3], [1, 2, 1, 2, 3], [1, 2, 1, 3, 2], [1, 1, 2, 2, 3], + [1, 1, 2, 3, 2], [1, 1, 3, 2, 2], + [3, 2, 1, 3], [2, 3, 1, 3], [3, 1, 2, 3], [2, 1, 3, 3], [3, 1, 3, 2], + [2, 1, 1, 5], [1, 3, 2, 3], [1, 2, 3, 3], [1, 3, 3, 2], [1, 2, 1, 5], + [1, 1, 5, 2], [1, 1, 2, 5], + [3, 3, 3], [3, 1, 5], [1, 3, 5]] Note that the shuffle product of two compositions can include the same composition more than once since a composition can be a shuffle of two compositions in several ways. For example:: sage: w1 = Composition([1]) - sage: S = w1.shuffle_product(w1); S + sage: S = w1.shuffle_product(w1); S # optional - sage.combinat Shuffle product of [1] and [1] - sage: S.list() + sage: S.list() # optional - sage.combinat [[1, 1], [1, 1]] - sage: O = w1.shuffle_product(w1, overlap=True); O + sage: O = w1.shuffle_product(w1, overlap=True); O # optional - sage.combinat Overlapping shuffle product of [1] and [1] - sage: O.list() + sage: O.list() # optional - sage.combinat [[1, 1], [1, 1], [2]] TESTS:: sage: empty = Composition([]) - sage: empty.shuffle_product(empty).list() + sage: empty.shuffle_product(empty).list() # optional - sage.combinat [[]] """ if overlap: @@ -1386,6 +1394,48 @@ def count(self, n): """ return sum(i == n for i in self) + def specht_module(self, base_ring=None): + r""" + Return the Specht module corresponding to ``self``. + + EXAMPLES:: + + sage: SM = Composition([1,2,2]).specht_module(QQ); SM # optional - sage.combinat sage.modules + Specht module of [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)] over Rational Field + sage: s = SymmetricFunctions(QQ).s() # optional - sage.combinat sage.modules + sage: s(SM.frobenius_image()) # optional - sage.combinat sage.modules + s[2, 2, 1] + """ + from sage.combinat.specht_module import SpechtModule + from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: + from sage.rings.rational_field import QQ + base_ring = QQ + R = SymmetricGroupAlgebra(base_ring, sum(self)) + cells = [] + for i, row in enumerate(self): + for j in range(row): + cells.append((i, j)) + return SpechtModule(R, cells) + + def specht_module_dimension(self, base_ring=None): + r""" + Return the dimension of the Specht module corresponding to ``self``. + + INPUT: + + - ``base_ring`` -- (default: `\QQ`) the base ring + + EXAMPLES:: + + sage: Composition([1,2,2]).specht_module_dimension() # optional - sage.combinat sage.modules + 5 + sage: Composition([1,2,2]).specht_module_dimension(GF(2)) # optional - sage.combinat sage.modules sage.rings.finite_rings + 5 + """ + from sage.combinat.specht_module import specht_module_rank + return specht_module_rank(self, base_ring) + Sequence.register(Composition) ############################################################## @@ -1635,7 +1685,7 @@ def __classcall_private__(self, n=None, **kwargs): """ if n is None: if kwargs: - raise ValueError("Incorrect number of arguments") + raise ValueError("incorrect number of arguments") return Compositions_all() else: if not kwargs: diff --git a/src/sage/combinat/composition_signed.py b/src/sage/combinat/composition_signed.py index 3ba592cd7ae..03e9acfe31e 100644 --- a/src/sage/combinat/composition_signed.py +++ b/src/sage/combinat/composition_signed.py @@ -20,7 +20,7 @@ from sage.rings.integer_ring import ZZ from .composition import Compositions_n, Composition from sage.rings.integer import Integer -from sage.arith.all import binomial +from sage.arith.misc import binomial class SignedCompositions(Compositions_n): diff --git a/src/sage/combinat/constellation.py b/src/sage/combinat/constellation.py index 4bc07a2171b..cbefe06054d 100644 --- a/src/sage/combinat/constellation.py +++ b/src/sage/combinat/constellation.py @@ -48,7 +48,8 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from itertools import repeat +from itertools import repeat, product + from sage.structure.element import parent from sage.structure.parent import Parent from sage.structure.element import Element @@ -475,7 +476,7 @@ def connected_components(self): G.add_vertices(list(range(self.degree()))) for p in self._g: G.add_edges(enumerate(p.domain()), loops=False) - m = G.connected_components() + m = G.connected_components(sort=False) if len(m) == 1: return [self] for mm in m: @@ -776,7 +777,7 @@ def relabel(self, perm=None, return_map=False): # compute canonical labels if not self.is_connected(): - raise ValueError("No canonical labels implemented for" + raise ValueError("no canonical labels implemented for" " non connected constellation") # get the permutations on {0, 1, ..., d-1} @@ -1408,8 +1409,6 @@ def __iter__(self): g1 ('a','d','b')('c') g2 ('a','b')('c','d') """ - from sage.misc.mrange import cartesian_product_iterator - if self._cd._length == 1: if self._cd._degree == 1: yield self([[0]]) @@ -1417,8 +1416,7 @@ def __iter__(self): S = self._cd._sym profile = list(self._profile)[:-1] - for p in cartesian_product_iterator([S.conjugacy_class(pi) - for pi in profile]): + for p in product(*[S.conjugacy_class(pi) for pi in profile]): if self._cd._connected and not perms_are_connected(p, self._cd._degree): continue c = self._cd(list(p) + [None], check=False) diff --git a/src/sage/combinat/core.py b/src/sage/combinat/core.py index 362c169a913..88461d33986 100644 --- a/src/sage/combinat/core.py +++ b/src/sage/combinat/core.py @@ -444,11 +444,11 @@ def weak_le(self, other): sage: c.weak_le(x) Traceback (most recent call last): ... - ValueError: The two cores do not have the same k + ValueError: the two cores do not have the same k """ if type(self) is type(other): if self.k() != other.k(): - raise ValueError("The two cores do not have the same k") + raise ValueError("the two cores do not have the same k") else: other = Core(other, self.k()) w = self.to_grassmannian() @@ -499,11 +499,11 @@ def strong_le(self, other): sage: c.strong_le(x) Traceback (most recent call last): ... - ValueError: The two cores do not have the same k + ValueError: the two cores do not have the same k """ if type(self) is type(other): if self.k() != other.k(): - raise ValueError("The two cores do not have the same k") + raise ValueError("the two cores do not have the same k") else: other = Core(other, self.k()) return other.contains(self) @@ -612,10 +612,9 @@ def Cores(k, length=None, **kwargs): """ if length is None and 'size' in kwargs: return Cores_size(k, kwargs['size']) - elif length is not None: + if length is not None: return Cores_length(k, length) - else: - raise ValueError("You need to either specify the length or size of the cores considered!") + raise ValueError("you need to either specify the length or size of the cores considered") class Cores_length(UniqueRepresentation, Parent): diff --git a/src/sage/combinat/crystals/affine_factorization.py b/src/sage/combinat/crystals/affine_factorization.py index 8db1972f993..f6bbf42966f 100644 --- a/src/sage/combinat/crystals/affine_factorization.py +++ b/src/sage/combinat/crystals/affine_factorization.py @@ -95,7 +95,7 @@ class AffineFactorizationCrystal(UniqueRepresentation, Parent): ValueError: x cannot be in reduced word of s0*s3*s2 """ @staticmethod - def __classcall_private__(cls, w, n, x = None, k = None): + def __classcall_private__(cls, w, n, x=None, k=None): r""" Classcall to mend the input. @@ -120,7 +120,7 @@ def __classcall_private__(cls, w, n, x = None, k = None): w = w0*(w1.inverse()) return super().__classcall__(cls, w, n, x) - def __init__(self, w, n, x = None): + def __init__(self, w, n, x=None): r""" EXAMPLES:: @@ -144,9 +144,9 @@ def __init__(self, w, n, x = None): sage: W = WeylGroup(['A',3,1], prefix='s') sage: w = W.from_reduced_word([2,3,2,1]) sage: B = crystals.AffineFactorization(w,3) - sage: TestSuite(B).run() + sage: TestSuite(B).run() # long time """ - Parent.__init__(self, category = ClassicalCrystals()) + Parent.__init__(self, category=ClassicalCrystals()) self.n = n self.k = w.parent().n-1 self.w = w @@ -250,12 +250,12 @@ def e(self, i): k = self.parent().k n = self.parent().n a = min(b[0]) - left = [j for j in (self.value[n-i-1]).reduced_word() if j != (a+x)%(k+1)] - right = [(j-x)%(k+1) for j in (self.value[n-i]).reduced_word()] - m = max([j for j in range(a) if (j+x)%(k+1) not in left]) + left = [j for j in (self.value[n-i-1]).reduced_word() if j != (a+x) % (k+1)] + right = [(j-x) % (k+1) for j in (self.value[n-i]).reduced_word()] + m = max([j for j in range(a) if (j+x) % (k+1) not in left]) right += [m+1] right.sort(reverse=True) - right = [(j+x)%(k+1) for j in right] + right = [(j+x) % (k+1) for j in right] t = [self.value[j] for j in range(n-i-1)] + [W.from_reduced_word(left)] + [W.from_reduced_word(right)] + [self.value[j] for j in range(n-i+1,n)] return self.parent()(tuple(t)) @@ -284,12 +284,12 @@ def f(self, i): k = self.parent().k n = self.parent().n a = max(b[1]) - right = [j for j in (self.value[n-i]).reduced_word() if j != (a+x)%(k+1)] - left = [(j-x)%(k+1) for j in (self.value[n-i-1]).reduced_word()] - m = min([j for j in range(a+1,k+2) if (j+x)%(k+1) not in right]) + right = [j for j in (self.value[n-i]).reduced_word() if j != (a+x) % (k+1)] + left = [(j-x) % (k+1) for j in (self.value[n-i-1]).reduced_word()] + m = min([j for j in range(a+1,k+2) if (j+x) % (k+1) not in right]) left += [m-1] left.sort(reverse=True) - left = [(j+x)%(k+1) for j in left] + left = [(j+x) % (k+1) for j in left] t = [self.value[j] for j in range(n-i-1)] + [W.from_reduced_word(left)] + [W.from_reduced_word(right)] + [self.value[j] for j in range(n-i+1,n)] return self.parent()(tuple(t)) @@ -311,13 +311,13 @@ def bracketing(self, i): k = self.parent().k right = (self.value[n-i]).reduced_word() left = (self.value[n-i-1]).reduced_word() - right_n = [(j-x)%(k+1) for j in right] - left_n = [(j-x)%(k+1) for j in left] + right_n = [(j-x) % (k+1) for j in right] + left_n = [(j-x) % (k+1) for j in left] left_unbracketed = [] while left_n: m = max(left_n) left_n.remove(m) - l = [j for j in right_n if j>m] + l = [j for j in right_n if j > m] if l: right_n.remove(min(l)) else: @@ -407,7 +407,7 @@ def affine_factorizations(w, l, weight=None): [[s1, s2, s1], [s2, s1, s2]] sage: W = WeylGroup(['A',3], prefix='s') sage: w0 = W.long_element() - sage: affine_factorizations(w0,6,(1,1,1,1,1,1)) + sage: affine_factorizations(w0,6,(1,1,1,1,1,1)) # long time [[s1, s2, s1, s3, s2, s1], [s1, s2, s3, s1, s2, s1], [s1, s2, s3, s2, s1, s2], @@ -428,7 +428,7 @@ def affine_factorizations(w, l, weight=None): [[1, 1, 1, s1, s2*s1, s3*s2*s1]] """ if weight is None: - if l==0: + if l == 0: if w.is_one(): return [[]] else: @@ -438,7 +438,7 @@ def affine_factorizations(w, l, weight=None): else: if l != len(weight): return [] - if l==0: + if l == 0: if w.is_one(): return [[]] else: @@ -498,12 +498,13 @@ def is_isomorphism(self): sage: W = WeylGroup(['A',4,1], prefix='s') sage: w = W.from_reduced_word([2,1,3,2,4,3,2,1]) - sage: B = crystals.AffineFactorization(w, 4) - sage: phi = B._tableaux_isomorphism - sage: all(phi(b).e(i) == phi(b.e(i)) and phi(b).f(i) == phi(b.f(i)) + sage: B = crystals.AffineFactorization(w, 4) # long time + sage: phi = B._tableaux_isomorphism # long time + sage: all(phi(b).e(i) == phi(b.e(i)) and # long time + ....: phi(b).f(i) == phi(b.f(i)) ....: for b in B for i in B.index_set()) True - sage: set(phi(b) for b in B) == set(phi.codomain()) + sage: set(phi(b) for b in B) == set(phi.codomain()) # long time True """ return True diff --git a/src/sage/combinat/crystals/alcove_path.py b/src/sage/combinat/crystals/alcove_path.py index b60717a13ee..aa5dc56d9ca 100644 --- a/src/sage/combinat/crystals/alcove_path.py +++ b/src/sage/combinat/crystals/alcove_path.py @@ -31,7 +31,7 @@ from sage.graphs.digraph import DiGraph from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.root_system import RootSystem -from sage.all import vector +from sage.modules.free_module_element import free_module_element as vector from sage.rings.integer import Integer from sage.combinat.root_system.weyl_group import WeylGroup from sage.misc.misc_c import prod @@ -193,9 +193,9 @@ class CrystalOfAlcovePaths(UniqueRepresentation, Parent): sage: K = crystals.KirillovReshetikhin(['B',3,1],2,1) sage: T = crystals.TensorProduct(K,K) sage: g = T.digraph() #long time - sage: for e in g.edges(sort=False): #long time - ....: if e[0].phi(0) == 1 and e[2] == 0: #long time - ....: g.delete_edge(e) #long time + sage: for e in g.edges(sort=False): #long time + ....: if e[0].phi(0) == 1 and e[2] == 0: + ....: g.delete_edge(e) sage: C = crystals.AlcovePaths(['B',3,1],[0,2,0], highest_weight_crystal=False) sage: g2 = C.digraph() #long time @@ -418,13 +418,13 @@ def vertices(self): # you to the word, it needs to be refreshed #initialization - lst=[] + lst = [] for i in range(len_lambda_chain): associated_reflection = lambda_chain[i].root.associated_reflection() if len(associated_reflection) == 1: lst.append( (prod([ s[j] for j in associated_reflection ]), [i]) ) - l=copy(lst) + l = copy(lst) while True: lst2 = [] @@ -603,7 +603,7 @@ def phi(self, i): highest_weight_crystal = self.parent()._highest_weight_crystal positions, gi = self._gi(i) - m=max(gi) + m = max(gi) if not highest_weight_crystal and i == 0: raise NotImplementedError @@ -629,7 +629,7 @@ def epsilon(self, i): temp = self temp = temp.e(i) while temp is not None: - j+=1 + j += 1 temp = temp.e(i) return j @@ -899,7 +899,7 @@ def e(self, i): else: M = Integer(m)/2 - Integer(1)/2 - KR_test = finite_cartan_type and i==0 and m_index < len(gi) - 1 + KR_test = finite_cartan_type and i == 0 and m_index < len(gi) - 1 KR_test = KR_test and M >= 1 ###################################################################### @@ -909,7 +909,7 @@ def e(self, i): # If m_index == 0 then M >=1 guarantees this ###################################################################### - if ( (not finite_cartan_type or i!=0) and m_index < len(gi)-1 # alpha_i is a simple root + if ( (not finite_cartan_type or i != 0) and m_index < len(gi)-1 # alpha_i is a simple root ) or KR_test: J.remove(positions[m_index]) @@ -1014,7 +1014,7 @@ def f(self, i): positions, gi = self._gi(i) m = max(gi) - m_index=gi.index(m) + m_index = gi.index(m) if finite_cartan_type and i == 0: @@ -1037,7 +1037,7 @@ def f(self, i): # # otherwise if m_index - 1 > 0 then (C2) is enough - if ( (not finite_cartan_type or i!=0) and M > 0 # alpha_i is a simple root + if ( (not finite_cartan_type or i != 0) and M > 0 # alpha_i is a simple root ) or KR_test :# KR case J.append(positions[m_index-1]) @@ -1426,7 +1426,7 @@ class RootsWithHeight(UniqueRepresentation, Parent): """ @staticmethod - def __classcall_private__(cls, starting_weight, cartan_type = None): + def __classcall_private__(cls, starting_weight, cartan_type=None): """ Classcall to mend the input. @@ -1472,7 +1472,7 @@ def __init__(self, weight): sage: R = RootsWithHeight(['A',2],[3,2]) sage: TestSuite(R).run() """ - Parent.__init__(self, category = Sets() ) + Parent.__init__(self, category=Sets() ) cartan_type = weight.parent().cartan_type() self._cartan_type = cartan_type @@ -1573,7 +1573,7 @@ def lambda_chain(self): if not self._root_lattice.cartan_type().is_finite(): raise ValueError("Cartan type {0} is not finite".format(self._root_lattice.cartan_type())) - l=[] + l = [] for i in self._root_lattice.positive_roots(): for j in range(self._max_height(i)): l.append(self(i,j)) @@ -1654,7 +1654,7 @@ def __init__(self, parent, root, height): # roots if not 0 <= height < max_height: - raise ValueError("%d out of allowed range [%d,%d)"%(height, 0, max_height)) + raise ValueError("%d out of allowed range [%d,%d)" % (height, 0, max_height)) v = [height/max_height] v.extend( [ x/max_height for x in root.associated_coroot().to_vector() ] ) @@ -1959,7 +1959,7 @@ def _test_against_tableaux(R, N, k, clss=CrystalOfAlcovePaths): shapes = Partitions(k).list() for shape in shapes: print("** Shape ", shape) - T = CrystalOfTableaux(R, shape = shape) + T = CrystalOfTableaux(R, shape=shape) ct = len(T.list()) print(" T has ", ct, " nodes.") #T.digraph().show(edge_labels=True) diff --git a/src/sage/combinat/crystals/crystals.py b/src/sage/combinat/crystals/crystals.py index 8b965b79c09..dbc2e9a211f 100644 --- a/src/sage/combinat/crystals/crystals.py +++ b/src/sage/combinat/crystals/crystals.py @@ -103,7 +103,7 @@ One can get (currently) crude plotting via:: - sage: Tab.plot() + sage: Tab.plot() # optional - sage.plot Graphics object consisting of 52 graphics primitives If dot2tex is installed, one can obtain nice latex pictures via:: diff --git a/src/sage/combinat/crystals/fast_crystals.py b/src/sage/combinat/crystals/fast_crystals.py index 874f278ee93..8a33913269d 100644 --- a/src/sage/combinat/crystals/fast_crystals.py +++ b/src/sage/combinat/crystals/fast_crystals.py @@ -100,7 +100,7 @@ class FastCrystal(UniqueRepresentation, Parent): [2, 1, 0]] """ @staticmethod - def __classcall__(cls, cartan_type, shape, format = "string"): + def __classcall__(cls, cartan_type, shape, format="string"): """ Normalize the input arguments to ensure unique representation @@ -126,7 +126,7 @@ def __init__(self, ct, shape, format): The fast crystal for A2 with shape [4,1] sage: TestSuite(C).run() """ - Parent.__init__(self, category = ClassicalCrystals()) + Parent.__init__(self, category=ClassicalCrystals()) # super().__init__(category = FiniteEnumeratedSets()) self._cartan_type = ct if ct[1] != 2: @@ -168,14 +168,14 @@ def __init__(self, ct, shape, format): self._rootoperators.append([e1,f1,e2,f2]) - if int(2*l1)%2 == 0: - l1_str = "%d"%l1 - l2_str = "%d"%l2 + if int(2*l1) % 2 == 0: + l1_str = "%d" % l1 + l2_str = "%d" % l2 else: - assert self._cartan_type[0] == 'B' and int(2*l2)%2 == 1 - l1_str = "%d/2"%int(2*l1) - l2_str = "%d/2"%int(2*l2) - self.rename("The fast crystal for %s2 with shape [%s,%s]"%(ct[0],l1_str,l2_str)) + assert self._cartan_type[0] == 'B' and int(2*l2) % 2 == 1 + l1_str = "%d/2" % int(2*l1) + l2_str = "%d/2" % int(2*l2) + self.rename("The fast crystal for %s2 with shape [%s,%s]" % (ct[0],l1_str,l2_str)) self.module_generators = [self(0)] # self._digraph = ClassicalCrystal.digraph(self) self._digraph = super().digraph() diff --git a/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py b/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py index 5861e84493c..b4fbcff59a3 100644 --- a/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py +++ b/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py @@ -358,7 +358,7 @@ def __classcall_private__(cls, w, factors, excess): if isinstance(w.parent(), SymmetricGroup): H = HeckeMonoid(w.parent()) w = H.from_reduced_word(w.reduced_word()) - if (not w.reduced_word()) and excess!=0: + if (not w.reduced_word()) and excess != 0: raise ValueError("excess must be 0 for the empty word") return super().__classcall__(cls, w, factors, excess) @@ -390,7 +390,7 @@ def __init__(self, w, factors, excess): sage: F = DecreasingHeckeFactorizations(w, 3, 1) sage: TestSuite(F).run() """ - Parent.__init__(self, category = FiniteEnumeratedSets()) + Parent.__init__(self, category=FiniteEnumeratedSets()) self.w = tuple(w.reduced_word()) self.factors = factors self.H = w.parent() @@ -504,7 +504,7 @@ def __classcall_private__(cls, w, factors, excess, shape=False): if shape: from sage.combinat.partition import _Partitions from sage.combinat.skew_partition import SkewPartition - cond1 = isinstance(w, (tuple, list)) and len(w)==2 and w[0] in _Partitions and w[1] in _Partitions + cond1 = isinstance(w, (tuple, list)) and len(w) == 2 and w[0] in _Partitions and w[1] in _Partitions cond2 = isinstance(w, SkewPartition) if cond1 or cond2: sh = SkewPartition([w[0], w[1]]) @@ -520,7 +520,7 @@ def __classcall_private__(cls, w, factors, excess, shape=False): if isinstance(w.parent(), SymmetricGroup): H = HeckeMonoid(w.parent()) w = H.from_reduced_word(w.reduced_word()) - if (not w.reduced_word()) and excess!=0: + if (not w.reduced_word()) and excess != 0: raise ValueError("excess must be 0 for the empty word") return super().__classcall__(cls, w, factors, excess) @@ -566,7 +566,7 @@ def __init__(self, w, factors, excess): if p.has_pattern([3,2,1]): raise ValueError("w should be fully commutative") - Parent.__init__(self, category = ClassicalCrystals()) + Parent.__init__(self, category=ClassicalCrystals()) self.w = tuple(word) self.factors = factors self.H = w.parent() @@ -733,7 +733,7 @@ def bracketing(self, i): while left_n: m = max(left_n) left_n.remove(m) - l = [j for j in right_n if j>=m] + l = [j for j in right_n if j >= m] if l: right_n.remove(min(l)) else: @@ -882,7 +882,7 @@ def _generate_decreasing_hecke_factorizations(w, factors, ex, weight=None, paren for word in L: F = _list_all_decreasing_runs(word, factors) for f in F: - t = [[word[j] for j in range(len(word)) if f[j]==i] for i in range(factors, 0, -1)] + t = [[word[j] for j in range(len(word)) if f[j] == i] for i in range(factors, 0, -1)] if weight is None or weight == wt(t): Factors.append(parent.element_class(parent, t)) return sorted(Factors, reverse=True) @@ -1020,7 +1020,7 @@ def _jumps(w): sage: _jumps(w) [2, 4, 8, 10] """ - return [i+1 for i in range(len(w)-1) if w[i]<=w[i+1]] + return [i+1 for i in range(len(w)-1) if w[i] <= w[i+1]] def _is_valid_column_word(w, m=None): diff --git a/src/sage/combinat/crystals/generalized_young_walls.py b/src/sage/combinat/crystals/generalized_young_walls.py index 9503199c28c..59cd7e92050 100644 --- a/src/sage/combinat/crystals/generalized_young_walls.py +++ b/src/sage/combinat/crystals/generalized_young_walls.py @@ -392,9 +392,9 @@ def number_of_parts(self): r = new[i] if r == [] or r in new[i+1:]: new.pop(i) - elif r[0] == n and len(r)%(n+1) == 0: + elif r[0] == n and len(r) % (n+1) == 0: for j in range(n+1): - temp = [k%(n+1) for k in range(j+len(r)/(n+1)-1,j-1,-1)] + temp = [k % (n+1) for k in range(j+len(r)/(n+1)-1,j-1,-1)] if temp not in new: new.insert(i+1, temp) new.pop(i) @@ -425,7 +425,7 @@ def sum_of_weighted_row_lengths(self): 15 """ n = self.parent().cartan_type().rank() - 1 - m = lambda i: len([1 for r in self.data if r and r[0] == (i-1)%(n+1)]) + m = lambda i: len([1 for r in self.data if r and r[0] == (i-1) % (n+1)]) for r in self.data: if r and r[0] == n: raise ValueError('Statistic only valid for generalized Young walls in Y_0') @@ -452,7 +452,7 @@ def e(self, i): """ signature = self.generate_signature(i) raw_signature = signature[0] - lastminus = signature[1].rfind('-') + lastminus = signature[1].rfind('-') newdata = [] if lastminus > -1: deletionrow = raw_signature[lastminus][1] @@ -562,8 +562,8 @@ def weight(self, root_lattice=False): for i in r: W.append(-1*alpha[i]) if not root_lattice: - return E(sum(w for w in W)) - return L(sum(w for w in W)) + return E(sum(W)) + return L(sum(W)) def epsilon(self, i): r""" @@ -725,7 +725,7 @@ def in_highest_weight_crystal(self,La): else: p_not_found = True for p in index_set: - if (j+k) % (n+1) == (p+1) % (n+1) and self.a(j,k) - self.a( (j-1) % (n+1) ,k) <= La.scalar(ac[p]): + if (j+k) % (n+1) == (p+1) % (n+1) and self.a(j,k) - self.a( (j-1) % (n+1) ,k) <= La.scalar(ac[p]): p_not_found = False continue else: diff --git a/src/sage/combinat/crystals/highest_weight_crystals.py b/src/sage/combinat/crystals/highest_weight_crystals.py index 4b6d5bb38bb..1b1d7f315e8 100644 --- a/src/sage/combinat/crystals/highest_weight_crystals.py +++ b/src/sage/combinat/crystals/highest_weight_crystals.py @@ -168,7 +168,7 @@ def HighestWeightCrystal(dominant_weight, model=None): Check that the correct crystal is constructed for the fundamental weights:: - sage: for ct in CartanType.samples(finite=True, crystallographic=True): + sage: for ct in CartanType.samples(finite=True, crystallographic=True): # long time ....: L = ct.root_system().weight_lattice() ....: La = L.fundamental_weights() ....: for model in ['Tableaux', 'NakajimaMonomials', 'AlcovePaths', 'RiggedConfigurations']: @@ -288,7 +288,7 @@ def __init__(self, dominant_weight): self._highest_weight = dominant_weight assert dominant_weight.is_dominant() self.rename() - Parent.__init__(self, category = ClassicalCrystals()) + Parent.__init__(self, category=ClassicalCrystals()) self.module_generators = [self.module_generator()] def _repr_(self): @@ -377,7 +377,7 @@ def __init__(self, dominant_weight): 2430 """ B1 = CrystalOfLetters(['E',6]) - B6 = CrystalOfLetters(['E',6], dual = True) + B6 = CrystalOfLetters(['E',6], dual=True) self.column_crystal = {1 : B1, 6 : B6, 4 : TensorProductOfCrystals(B1,B1,B1,generators=[[B1([-3,4]),B1([-1,3]),B1([1])]]), 3 : TensorProductOfCrystals(B1,B1,generators=[[B1([-1,3]),B1([1])]]), diff --git a/src/sage/combinat/crystals/kirillov_reshetikhin.py b/src/sage/combinat/crystals/kirillov_reshetikhin.py index ee7175e8a03..10de248f868 100644 --- a/src/sage/combinat/crystals/kirillov_reshetikhin.py +++ b/src/sage/combinat/crystals/kirillov_reshetikhin.py @@ -375,21 +375,21 @@ def KashiwaraNakashimaTableaux(cartan_type, r, s): if ct.type() == 'A': return KR_type_A(ct, r, s) elif ct.type() == 'D': - if r<ct.rank()-2: + if r < ct.rank()-2: return KR_type_vertical(ct, r, s) elif r in {ct.rank()-2,ct.rank()-1}: return KR_type_spin(ct, r, s) else: raise ValueError("wrong range of parameters") elif ct.type() == 'B': - if r<ct.rank()-1: + if r < ct.rank()-1: return KR_type_vertical(ct, r, s) elif r == ct.rank()-1: return KR_type_Bn(ct, r, s) else: raise ValueError("wrong range of parameters") elif ct.type() == 'C': - if r<ct.rank()-1: + if r < ct.rank()-1: return KR_type_C(ct, r, s) elif r == ct.rank()-1: return KR_type_Cn(ct, r, s) @@ -409,7 +409,7 @@ def KashiwaraNakashimaTableaux(cartan_type, r, s): elif ct.dual().type() == 'BC': return KR_type_A2(ct, r, s) elif ct.dual().type() == 'C': - if r<ct.rank()-1: + if r < ct.rank()-1: return KR_type_box(ct, r, s) elif r == ct.rank()-1: return KR_type_Dn_twisted(ct, r, s) @@ -973,7 +973,7 @@ def from_highest_weight_vector_to_pm_diagram(self, b): """ n = self.cartan_type().rank() - 1 inner = Partition([Integer(b.weight()[i]) for i in range(1,n+1)]) - inter = Partition([len([i for i in r if i>0]) for r in b.to_tableau()]) + inter = Partition([len([i for i in r if i > 0]) for r in b.to_tableau()]) outer = b.to_tableau().shape() return PMDiagram([self.r(), self.s(), outer, inter, inner], from_shapes=True) @@ -1640,7 +1640,7 @@ def classical_decomposition(self): The crystal of tableaux of type ['B', 2] and shape(s) [[], [2], [2, 2]] """ return CrystalOfTableaux(['B', self.cartan_type().rank()-1], - shapes = horizontal_dominoes_removed(self.r(),self.s())) + shapes=horizontal_dominoes_removed(self.r(),self.s())) def ambient_crystal(self): r""" @@ -1920,7 +1920,7 @@ def classical_decomposition(self): The crystal of tableaux of type ['B', 3] and shape(s) [[], [1], [2], [1, 1], [3], [2, 1], [3, 1], [2, 2], [3, 2], [3, 3]] """ return CrystalOfTableaux(self.cartan_type().classical(), - shapes = partitions_in_box(self.r(),self.s())) + shapes=partitions_in_box(self.r(),self.s())) def ambient_crystal(self): r""" @@ -2443,7 +2443,7 @@ def classical_decomposition(self): sage: K.classical_decomposition() The crystal of tableaux of type ['C', 3] and shape(s) [[2, 2, 2]] """ - return CrystalOfTableaux(self.cartan_type().classical(), shape = [self.s()]*self.r() ) + return CrystalOfTableaux(self.cartan_type().classical(), shape=[self.s()]*self.r() ) def from_highest_weight_vector_to_pm_diagram(self, b): r""" @@ -2469,7 +2469,7 @@ def from_highest_weight_vector_to_pm_diagram(self, b): """ n = self.cartan_type().rank()-1 inner = Partition([Integer(b.weight()[i]) for i in range(1,n+1)]) - inter = Partition([len([i for i in r if i>0]) for r in b.to_tableau()]) + inter = Partition([len([i for i in r if i > 0]) for r in b.to_tableau()]) outer = b.to_tableau().shape() return PMDiagram([self.r(), self.s(), outer, inter, inner], from_shapes=True) @@ -2678,7 +2678,7 @@ def classical_decomposition(self): s = s // 2 else: s = s / 2 - return CrystalOfTableaux(self.cartan_type().classical(), shape = [s]*self.r() ) + return CrystalOfTableaux(self.cartan_type().classical(), shape=[s]*self.r() ) def from_highest_weight_vector_to_pm_diagram(self, b): r""" @@ -2748,15 +2748,15 @@ def from_highest_weight_vector_to_pm_diagram(self, b): inner = Partition(inner) inter = [2*i for i in inter]+[0]*(n-len(inter)) w = t.weight() - if w[0]==0 and w[n-1]==0: + if w[0] == 0 and w[n-1] == 0: v = [0]*n else: v = [1]*n - if w[0]<0 and w[n-1]>0: - v[n-1]=0 - elif w[0]>0 and w[n-1]<0: - v[n-1]=0 - v[n-2]=-1 + if w[0] < 0 and w[n-1] > 0: + v[n-1] = 0 + elif w[0] > 0 and w[n-1] < 0: + v[n-1] = 0 + v[n-2] = -1 inter = Partition([inter[i] + v[i] for i in range(n)]) outer = Partition([s]*n) return PMDiagram([n, s, outer, inter, inner], from_shapes=True) @@ -2781,7 +2781,7 @@ def from_pm_diagram_to_highest_weight_vector(self, pm): ulist = [] plus = pm.heights_of_addable_plus() minus = pm.heights_of_minus() - l = len([i for i in plus if i==rank-1]) + l = len([i for i in plus if i == rank-1]) a = (len(plus) + l) // 2 ulist += sum(([i]*a for i in range(1,rank+1)),[]) a = (len(minus)-l) // 2 @@ -2823,15 +2823,15 @@ def e0(self): pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) [l1,l2] = pm.pm_diagram[n-1] l3 = pm.pm_diagram[n-2][0] - if l1+l2+l3==s and l1==0: + if l1+l2+l3 == s and l1 == 0: return None - if l1+l2+l3<s: + if l1+l2+l3 < s: pm.pm_diagram[n-1][1] = l2+2 pm.pm_diagram[n][0] -= 2 - elif l1>1: + elif l1 > 1: pm.pm_diagram[n-1][0] = l1-2 pm.pm_diagram[n][0] += 2 - elif l1 ==1: + elif l1 == 1: pm.pm_diagram[n-1][0] = 0 pm.pm_diagram[n-1][1] = l2+1 pm = PMDiagram(pm.pm_diagram) @@ -2860,13 +2860,13 @@ def f0(self): l3 = pm.pm_diagram[n-2][0] if l1+l2+l3 == s and l2 == 0: return None - if l1+l2+l3<s: + if l1+l2+l3 < s: pm.pm_diagram[n-1][0] = l1+2 pm.pm_diagram[n][0] -= 2 - elif l2>1: + elif l2 > 1: pm.pm_diagram[n-1][1] = l2-2 pm.pm_diagram[n][0] += 2 - elif l2 ==1: + elif l2 == 1: pm.pm_diagram[n-1][1] = 0 pm.pm_diagram[n-1][0] = l1+1 pm = PMDiagram(pm.pm_diagram) @@ -3273,7 +3273,7 @@ def from_coordinates(self, coords): l = C.letters lst = ([l(1)]*coords[0] + [l(2)]*coords[1] + [l(3)]*(coords[2]//2) - + [l(0)]*(coords[2]%2) + [l(-3)]*(coords[3]//2) + + [l(0)]*(coords[2] % 2) + [l(-3)]*(coords[3]//2) + [l(-2)]*coords[4] + [l(-1)]*coords[5]) return self.element_class(self, C(*lst)) @@ -3733,7 +3733,7 @@ class PMDiagram(CombinatorialObject): True """ - def __init__(self, pm_diagram, from_shapes = None): + def __init__(self, pm_diagram, from_shapes=None): r""" Initialize ``self``. diff --git a/src/sage/combinat/crystals/letters.pyx b/src/sage/combinat/crystals/letters.pyx index 29ca6086c57..921be80c434 100644 --- a/src/sage/combinat/crystals/letters.pyx +++ b/src/sage/combinat/crystals/letters.pyx @@ -319,6 +319,7 @@ class ClassicalCrystalOfLetters(UniqueRepresentation, Parent): # temporary workaround while an_element is overridden by Parent _an_element_ = EnumeratedSets.ParentMethods._an_element_ + # Utility. Note: much of this class should be factored out at some point! cdef class Letter(Element): r""" @@ -1494,7 +1495,7 @@ cdef class Crystal_of_letters_type_E6_element(LetterTuple): sage: all(b.e(i).f(i) == b for i in C.index_set() for b in C if b.e(i) is not None) True sage: G = C.digraph() - sage: G.show(edge_labels=true, figsize=12, vertex_size=1) + sage: G.show(edge_labels=true, figsize=12, vertex_size=1) # optional - sage.plot """ def _repr_(self): @@ -1751,7 +1752,7 @@ cdef class Crystal_of_letters_type_E6_element_dual(LetterTuple): sage: all(b.e(i).f(i) == b for i in C.index_set() for b in C if b.e(i) is not None) True sage: G = C.digraph() - sage: G.show(edge_labels=true, figsize=12, vertex_size=1) + sage: G.show(edge_labels=true, figsize=12, vertex_size=1) # optional - sage.plot """ def _repr_(self): @@ -1911,7 +1912,7 @@ cdef class Crystal_of_letters_type_E7_element(LetterTuple): sage: all(b.e(i).f(i) == b for i in C.index_set() for b in C if b.e(i) is not None) True sage: G = C.digraph() - sage: G.show(edge_labels=true, figsize=12, vertex_size=1) + sage: G.show(edge_labels=true, figsize=12, vertex_size=1) # optional - sage.plot """ def weight(self): @@ -2571,6 +2572,7 @@ class CrystalOfBKKLetters(ClassicalCrystalOfLetters): Element = BKKLetter + ################# # Type q(n) queer ################# @@ -2981,6 +2983,7 @@ cdef class LetterWrapped(Element): """ return self.value.phi(i) + class ClassicalCrystalOfLettersWrapped(ClassicalCrystalOfLetters): r""" Crystal of letters by wrapping another crystal. diff --git a/src/sage/combinat/crystals/littelmann_path.py b/src/sage/combinat/crystals/littelmann_path.py index 89fbf8e4253..c384a818e56 100644 --- a/src/sage/combinat/crystals/littelmann_path.py +++ b/src/sage/combinat/crystals/littelmann_path.py @@ -121,7 +121,7 @@ class CrystalOfLSPaths(UniqueRepresentation, Parent): """ @staticmethod - def __classcall_private__(cls, starting_weight, cartan_type = None, starting_weight_parent = None): + def __classcall_private__(cls, starting_weight, cartan_type=None, starting_weight_parent=None): """ Classcall to mend the input. @@ -150,7 +150,7 @@ def __classcall_private__(cls, starting_weight, cartan_type = None, starting_wei extended = cartan_type.is_affine() R = RootSystem(cartan_type) - P = R.weight_space(extended = extended) + P = R.weight_space(extended=extended) Lambda = P.basis() offset = R.index_set()[Integer(0)] starting_weight = P.sum(starting_weight[j-offset]*Lambda[j] for j in R.index_set()) @@ -162,7 +162,7 @@ def __classcall_private__(cls, starting_weight, cartan_type = None, starting_wei if starting_weight.parent() != starting_weight_parent: raise ValueError("The passed parent is not equal to parent of the inputted weight!") - return super().__classcall__(cls, starting_weight, starting_weight_parent = starting_weight_parent) + return super().__classcall__(cls, starting_weight, starting_weight_parent=starting_weight_parent) def __init__(self, starting_weight, starting_weight_parent): """ @@ -808,8 +808,8 @@ def weight(x): w = x.weight() return P0.sum(int(c)*P0.basis()[i] for i,c in w if i in P0.index_set()) if group_components: - G = self.digraph(index_set = self.cartan_type().classical().index_set()) - C = G.connected_components() + G = self.digraph(index_set=self.cartan_type().classical().index_set()) + C = G.connected_components(sort=False) return sum(q**(c[0].energy_function())*B.sum(B(weight(b)) for b in c) for c in C) return B.sum(q**(b.energy_function())*B(weight(b)) for b in self) @@ -1081,7 +1081,7 @@ def energy_function(self): sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]+La[2]) sage: G = LS.digraph(index_set=[1,2]) - sage: C = G.connected_components() + sage: C = G.connected_components(sort=False) sage: [all(c[0].energy_function()==a.energy_function() for a in c) for c in C] [True, True, True, True] @@ -1093,7 +1093,7 @@ def energy_function(self): sage: [(x.weight(), x.energy_function()) for x in hw] [(-2*Lambda[0] + Lambda[2], 0), (-2*Lambda[0] + Lambda[1], 1), (0, 2)] sage: G = LS.digraph(index_set=J) - sage: C = G.connected_components() + sage: C = G.connected_components(sort=False) sage: [all(c[0].energy_function()==a.energy_function() for a in c) for c in C] [True, True, True] @@ -1101,7 +1101,7 @@ def energy_function(self): sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(La[1]+La[2]) sage: G = LS.digraph(index_set=[1,2]) - sage: C = G.connected_components() + sage: C = G.connected_components(sort=False) sage: [all(c[0].energy_function()==a.energy_function() for a in c) for c in C] # long time [True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True] @@ -1110,7 +1110,7 @@ def energy_function(self): sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]+La[2]) sage: G = LS.digraph(index_set=R.cartan_type().classical().index_set()) - sage: C = G.connected_components() + sage: C = G.connected_components(sort=False) sage: [all(c[0].energy_function()==a.energy_function() for a in c) for c in C] # long time [True, True, True, True, True, True, True, True, True, True, True] @@ -1118,7 +1118,7 @@ def energy_function(self): sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]+La[2]) sage: G = LS.digraph(index_set=R.cartan_type().classical().index_set()) - sage: C = G.connected_components() + sage: C = G.connected_components(sort=False) sage: [all(c[0].energy_function()==a.energy_function() for a in c) for c in C] # long time [True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True] @@ -1330,7 +1330,7 @@ def e(self, i, power=1, length_only=False): return ret WLR = self.parent().weight_lattice_realization() value = list(ret.value) - endpoint = sum(p for p in value) + endpoint = sum(value) rho = WLR.rho() h = WLR.simple_coroots() @@ -1385,7 +1385,7 @@ def f(self, i, power=1, length_only=False): ret = dual_path.dualize() WLR = self.parent().weight_lattice_realization() value = list(ret.value) - endpoint = sum(p for p in value) + endpoint = sum(value) rho = WLR.rho() h = WLR.simple_coroots() diff --git a/src/sage/combinat/crystals/monomial_crystals.py b/src/sage/combinat/crystals/monomial_crystals.py index 44d0c1cb4bd..38ae061355f 100644 --- a/src/sage/combinat/crystals/monomial_crystals.py +++ b/src/sage/combinat/crystals/monomial_crystals.py @@ -302,9 +302,9 @@ def _latex_Y(self): return_str = '' for x in L: if x[1] != 1: - return_str += "Y_{%s,%s}"%(x[0][0],x[0][1]) + "^{%s} "%x[1] + return_str += "Y_{%s,%s}" % (x[0][0],x[0][1]) + "^{%s} " % x[1] else: - return_str += "Y_{%s,%s} "%(x[0][0],x[0][1]) + return_str += "Y_{%s,%s} " % (x[0][0],x[0][1]) return return_str def _latex_A(self): @@ -330,15 +330,15 @@ def _latex_A(self): return_str = '' for x in L: if x[1] != 1: - return_str += "Y_{%s,%s}"%(x[0][0],x[0][1]) + "^{%s} "%x[1] + return_str += "Y_{%s,%s}" % (x[0][0],x[0][1]) + "^{%s} " % x[1] else: - return_str += "Y_{%s,%s} "%(x[0][0],x[0][1]) + return_str += "Y_{%s,%s} " % (x[0][0],x[0][1]) L = sorted(self._A.items(), key=lambda x:(x[0][0],x[0][1])) for x in L: if x[1] != 1: - return_str += "A_{%s,%s}"%(x[0][0],x[0][1]) + "^{%s} "%x[1] + return_str += "A_{%s,%s}" % (x[0][0],x[0][1]) + "^{%s} " % x[1] else: - return_str += "A_{%s,%s} "%(x[0][0],x[0][1]) + return_str += "A_{%s,%s} " % (x[0][0],x[0][1]) return return_str def _classical_weight(self): diff --git a/src/sage/combinat/crystals/mv_polytopes.py b/src/sage/combinat/crystals/mv_polytopes.py index ddcff43c6f4..cd6a4497d8e 100644 --- a/src/sage/combinat/crystals/mv_polytopes.py +++ b/src/sage/combinat/crystals/mv_polytopes.py @@ -85,7 +85,7 @@ def _latex_(self): sage: MV = crystals.infinity.MVPolytopes(['A',2]) sage: u = MV.highest_weight_vector() sage: b = u.f_string([1,2,2,1]) - sage: latex(b) + sage: latex(b) # optional - sage.symbolic \begin{tikzpicture} \draw (0, 0) -- (3/2, -989/1142) -- (3/2, -2967/1142) -- (0, -1978/571); \draw (0, 0) -- (-3/2, -989/1142) -- (-3/2, -2967/1142) -- (0, -1978/571); @@ -218,7 +218,7 @@ def plot(self, P=None, **options): sage: MV = crystals.infinity.MVPolytopes(['C', 2]) sage: b = MV.highest_weight_vector().f_string([1,2,1,2,2,2,1,1,1,1,2,1]) - sage: b.plot() + sage: b.plot() # optional - sage.plot Graphics object consisting of 12 graphics primitives Here is the above example placed inside the ambient space diff --git a/src/sage/combinat/crystals/pbw_crystal.py b/src/sage/combinat/crystals/pbw_crystal.py index b03ace896b4..df359333f6d 100644 --- a/src/sage/combinat/crystals/pbw_crystal.py +++ b/src/sage/combinat/crystals/pbw_crystal.py @@ -89,7 +89,7 @@ def _latex_(self): lusztig_datum = list(pbw_datum.lusztig_datum) al = self.parent()._pbw_datum_parent._root_list_from(self.parent()._default_word) from sage.misc.latex import latex - ret_str = ' '.join("f_{%s}%s"%(latex(al[i]), "^{%s}"%latex(exp) if exp > 1 else "") + ret_str = ' '.join("f_{%s}%s" % (latex(al[i]), "^{%s}" % latex(exp) if exp > 1 else "") for i, exp in enumerate(lusztig_datum) if exp) if ret_str == '': return '1' diff --git a/src/sage/combinat/crystals/pbw_datum.pxd b/src/sage/combinat/crystals/pbw_datum.pxd index 039c197ea90..9c3aab083df 100644 --- a/src/sage/combinat/crystals/pbw_datum.pxd +++ b/src/sage/combinat/crystals/pbw_datum.pxd @@ -1,4 +1,3 @@ cpdef tuple compute_new_lusztig_datum(list enhanced_braid_chain, initial_lusztig_datum) cpdef tuple tropical_plucker_relation(tuple a, lusztig_datum) cpdef list enhance_braid_move_chain(braid_move_chain, cartan_type) - diff --git a/src/sage/combinat/crystals/pbw_datum.pyx b/src/sage/combinat/crystals/pbw_datum.pyx index 55dfd49a0ac..dd27d91294a 100644 --- a/src/sage/combinat/crystals/pbw_datum.pyx +++ b/src/sage/combinat/crystals/pbw_datum.pyx @@ -25,12 +25,12 @@ AUTHORS: #from sage.misc.lazy_attribute import lazy_attribute from sage.misc.cachefunc import cached_method from sage.combinat.root_system.cartan_type import CartanType -from sage.combinat.root_system.coxeter_group import CoxeterGroup from sage.combinat.root_system.root_system import RootSystem from sage.combinat.root_system.braid_move_calculator import BraidMoveCalculator cimport cython + class PBWDatum(): """ Helper class which represents a PBW datum. @@ -278,7 +278,8 @@ class PBWData(): # UniqueRepresentation? w0 = self.weyl_group.long_element() return tuple([i] + (si * w0).reduced_word()) -#enhanced_braid_chain is an ugly data structure. + +# enhanced_braid_chain is an ugly data structure. @cython.boundscheck(False) @cython.wraparound(False) cpdef tuple compute_new_lusztig_datum(list enhanced_braid_chain, initial_lusztig_datum): @@ -315,17 +316,18 @@ cpdef tuple compute_new_lusztig_datum(list enhanced_braid_chain, initial_lusztig """ cdef tuple interval_of_change # Does not currently check that len(initial_lusztig_datum) is appropriate - cdef list new_lusztig_datum = list(initial_lusztig_datum) #shallow copy + cdef list new_lusztig_datum = list(initial_lusztig_datum) # shallow copy cdef int i for i in range(1, len(enhanced_braid_chain)): interval_of_change, type_data = enhanced_braid_chain[i] - a,b = interval_of_change + a, b = interval_of_change old_interval_datum = new_lusztig_datum[a:b] new_interval_datum = tropical_plucker_relation(type_data, old_interval_datum) new_lusztig_datum[a:b] = new_interval_datum return tuple(new_lusztig_datum) -# The tropical plucker relations + +# The tropical Plรผcker relations @cython.boundscheck(False) @cython.wraparound(False) cpdef tuple tropical_plucker_relation(tuple a, lusztig_datum): @@ -396,6 +398,7 @@ cpdef tuple tropical_plucker_relation(tuple a, lusztig_datum): return tuple(reversed(tropical_plucker_relation((a[1], a[0]), reversed_lusztig_datum))) + # Maybe we need to be more specific, and pass not the Cartan type, but the root lattice? # TODO: Move to PBW_data? @cython.boundscheck(False) @@ -450,7 +453,7 @@ cpdef list enhance_braid_move_chain(braid_move_chain, cartan_type): """ cdef int i, j cdef int k, pos, first, last - cdef tuple interval_of_change, cartan_sub_matrix + cdef tuple cartan_sub_matrix cdef list output_list = [] output_list.append( (None, None) ) cdef tuple previous_word = <tuple> (braid_move_chain[0]) diff --git a/src/sage/combinat/crystals/spins.pxd b/src/sage/combinat/crystals/spins.pxd index 4ca5f8a7082..a486aaa2518 100644 --- a/src/sage/combinat/crystals/spins.pxd +++ b/src/sage/combinat/crystals/spins.pxd @@ -18,4 +18,3 @@ cdef class Spin_crystal_type_D_element(Spin): cpdef Spin f(self, int i) cpdef int epsilon(self, int i) cpdef int phi(self, int i) - diff --git a/src/sage/combinat/crystals/spins.pyx b/src/sage/combinat/crystals/spins.pyx index 4e52064f12a..0798a534077 100644 --- a/src/sage/combinat/crystals/spins.pyx +++ b/src/sage/combinat/crystals/spins.pyx @@ -44,7 +44,6 @@ representing the elements of the spin crystal by sequences of signs from cpython.object cimport Py_EQ, Py_NE, Py_LE, Py_GE, Py_LT, Py_GT from cysignals.memory cimport sig_malloc, sig_free -from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent cimport Parent @@ -100,6 +99,7 @@ def CrystalOfSpins(ct): else: raise NotImplementedError + ######################### # Type D spins ######################### @@ -136,6 +136,7 @@ def CrystalOfSpinsPlus(ct): else: raise NotImplementedError + def CrystalOfSpinsMinus(ct): r""" Return the minus spin crystal of the given type D. @@ -169,6 +170,7 @@ def CrystalOfSpinsMinus(ct): else: raise NotImplementedError + class GenericCrystalOfSpins(UniqueRepresentation, Parent): """ A generic crystal of spins. @@ -182,11 +184,11 @@ class GenericCrystalOfSpins(UniqueRepresentation, Parent): """ self._cartan_type = CartanType(ct) if case == "spins": - self.rename("The crystal of spins for type %s"%ct) + self.rename("The crystal of spins for type %s" % ct) elif case == "plus": - self.rename("The plus crystal of spins for type %s"%ct) + self.rename("The plus crystal of spins for type %s" % ct) else: - self.rename("The minus crystal of spins for type %s"%ct) + self.rename("The minus crystal of spins for type %s" % ct) self.Element = element_class Parent.__init__(self, category=ClassicalCrystals()) @@ -251,6 +253,7 @@ class GenericCrystalOfSpins(UniqueRepresentation, Parent): raise ValueError("both elements must be in this crystal") return self._digraph_closure.has_edge(x, y) + cdef class Spin(Element): """ A spin letter in the crystal of spins. diff --git a/src/sage/combinat/crystals/tensor_product.py b/src/sage/combinat/crystals/tensor_product.py index 6748af04b77..bfe1801454d 100644 --- a/src/sage/combinat/crystals/tensor_product.py +++ b/src/sage/combinat/crystals/tensor_product.py @@ -493,7 +493,7 @@ def __init__(self, crystals, generators, cartan_type): assert isinstance(crystals, tuple) assert isinstance(generators, tuple) category = Category.meet([crystal.category() for crystal in crystals]) - Parent.__init__(self, category = category) + Parent.__init__(self, category=category) self.crystals = crystals self._cartan_type = cartan_type self.module_generators = tuple([self(*x) for x in generators]) @@ -891,7 +891,7 @@ class CrystalOfTableaux(CrystalOfWords): """ @staticmethod - def __classcall_private__(cls, cartan_type, shapes = None, shape = None): + def __classcall_private__(cls, cartan_type, shapes=None, shape=None): """ Normalizes the input arguments to ensure unique representation, and to delegate the construction of spin tableaux. @@ -934,7 +934,7 @@ def __classcall_private__(cls, cartan_type, shapes = None, shape = None): n1 = n + 1 else: n1 = n - if not all(all(i == 0 for i in shape[n1:]) for shape in shapes): + if not all(i == 0 for shape in shapes for i in shape[n1:]): raise ValueError("shapes should all have length at most equal to the rank or the rank + 1 in type A") spin_shapes = tuple((tuple(shape) + (0,)*(n1-len(shape)))[:n1] for shape in shapes) try: @@ -969,7 +969,7 @@ def __classcall_private__(cls, cartan_type, shapes = None, shape = None): S = CrystalOfSpins(cartan_type) B = CrystalOfTableaux(cartan_type, shapes=shapes) T = TensorProductOfCrystals(S, B, generators=[[S.module_generators[0],x] for x in B.module_generators]) - T.rename("The crystal of tableaux of type %s and shape(s) %s"%(cartan_type, list(list(shape) for shape in spin_shapes))) + T.rename("The crystal of tableaux of type %s and shape(s) %s" % (cartan_type, list(list(shape) for shape in spin_shapes))) T.shapes = spin_shapes return T @@ -991,7 +991,7 @@ def __init__(self, cartan_type, shapes): sage: TestSuite(T).run() """ # super().__init__(category = FiniteEnumeratedSets()) - Parent.__init__(self, category = ClassicalCrystals()) + Parent.__init__(self, category=ClassicalCrystals()) self.letters = CrystalOfLetters(cartan_type) self.shapes = shapes self.module_generators = tuple(self.module_generator(la) for la in shapes) diff --git a/src/sage/combinat/crystals/tensor_product_element.pxd b/src/sage/combinat/crystals/tensor_product_element.pxd index 53a60d5a327..aae31eb7a03 100644 --- a/src/sage/combinat/crystals/tensor_product_element.pxd +++ b/src/sage/combinat/crystals/tensor_product_element.pxd @@ -32,4 +32,3 @@ cdef class InfinityQueerCrystalOfTableauxElement(TensorProductOfQueerSuperCrysta cdef list _row_lengths cdef Py_ssize_t count_leading(list row, letter) - diff --git a/src/sage/combinat/crystals/tensor_product_element.pyx b/src/sage/combinat/crystals/tensor_product_element.pyx index 8b7bf544d1f..a95d2060b4b 100644 --- a/src/sage/combinat/crystals/tensor_product_element.pyx +++ b/src/sage/combinat/crystals/tensor_product_element.pyx @@ -30,7 +30,6 @@ AUTHORS: # https://www.gnu.org/licenses/ #**************************************************************************** -from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE from sage.structure.parent cimport Parent from sage.misc.cachefunc import cached_method, cached_in_parent_method @@ -1159,7 +1158,7 @@ cdef class InfinityCrystalOfTableauxElementTypeD(InfinityCrystalOfTableauxElemen return ret ##################################################################### -## BKK crystal elements +# BKK crystal elements cdef class TensorProductOfSuperCrystalsElement(TensorProductOfRegularCrystalsElement): r""" @@ -1406,7 +1405,7 @@ cdef class CrystalOfBKKTableauxElement(TensorProductOfSuperCrystalsElement): return Tableau(tab).conjugate() ##################################################################### -## Queer crystal elements +# Queer crystal elements cdef class TensorProductOfQueerSuperCrystalsElement(TensorProductOfRegularCrystalsElement): r""" @@ -1642,7 +1641,7 @@ cdef class TensorProductOfQueerSuperCrystalsElement(TensorProductOfRegularCrysta cdef class InfinityQueerCrystalOfTableauxElement(TensorProductOfQueerSuperCrystalsElement): - def __init__(self, parent, list, row_lengths=[]): + def __init__(self, parent, list, row_lengths=None): """ Initialize ``self``. @@ -1654,6 +1653,8 @@ cdef class InfinityQueerCrystalOfTableauxElement(TensorProductOfQueerSuperCrysta [[4, 4, 4, 4, 2, 1], [3, 3, 3], [2, 2], [1]] sage: TestSuite(t).run() """ + if row_lengths is None: + row_lengths = [] if not row_lengths and list and not isinstance(list[0], parent.letters.element_class): ret = [] L = parent.letters diff --git a/src/sage/combinat/cyclic_sieving_phenomenon.py b/src/sage/combinat/cyclic_sieving_phenomenon.py index e654a8fc94a..d09168791cb 100644 --- a/src/sage/combinat/cyclic_sieving_phenomenon.py +++ b/src/sage/combinat/cyclic_sieving_phenomenon.py @@ -26,7 +26,7 @@ # **************************************************************************** from __future__ import annotations from sage.rings.integer_ring import ZZ -from sage.arith.all import lcm +from sage.arith.functions import lcm from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing diff --git a/src/sage/combinat/decorated_permutation.py b/src/sage/combinat/decorated_permutation.py index f8ca5c8b78b..e7281b7d3bb 100644 --- a/src/sage/combinat/decorated_permutation.py +++ b/src/sage/combinat/decorated_permutation.py @@ -24,7 +24,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.arith.all import factorial +from sage.arith.misc import factorial from sage.rings.integer import Integer from sage.combinat.permutation import Permutations from sage.combinat.subset import Subsets @@ -213,7 +213,7 @@ def _element_constructor_(self, pi, check=True): if isinstance(pi, DecoratedPermutation): if pi.parent() is self: return pi - raise ValueError("Cannot convert between decorated permutations of different sizes") + raise ValueError("cannot convert between decorated permutations of different sizes") pi = tuple(pi) if check and pi not in self: diff --git a/src/sage/combinat/degree_sequences.pyx b/src/sage/combinat/degree_sequences.pyx index ed750198dc7..0ccc2377f2c 100644 --- a/src/sage/combinat/degree_sequences.pyx +++ b/src/sage/combinat/degree_sequences.pyx @@ -264,23 +264,19 @@ Checking the consistency of enumeration and test:: than a couple of minutes. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Nathann Cohen <nathann.cohen@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** - -from libc.string cimport memset from cysignals.memory cimport check_calloc, sig_free from cysignals.signals cimport sig_on, sig_off -from sage.rings.integer cimport Integer - cdef unsigned char * seq cdef list sequences diff --git a/src/sage/combinat/derangements.py b/src/sage/combinat/derangements.py index eeeb73fb7ce..0c4b8a3d9d7 100644 --- a/src/sage/combinat/derangements.py +++ b/src/sage/combinat/derangements.py @@ -66,10 +66,10 @@ def to_permutation(self): sage: D[0].to_permutation() Traceback (most recent call last): ... - ValueError: Can only convert to a permutation for derangements of [1, 2, ..., n] + ValueError: can only convert to a permutation for derangements of [1, 2, ..., n] """ if self.parent()._set != tuple(range(1, len(self) + 1)): - raise ValueError("Can only convert to a permutation for derangements of [1, 2, ..., n]") + raise ValueError("can only convert to a permutation for derangements of [1, 2, ..., n]") return Permutation(list(self)) @@ -199,7 +199,7 @@ def _element_constructor_(self, der): if isinstance(der, Derangement): if der.parent() is self: return der - raise ValueError("Cannot convert %s to an element of %s" % (der, self)) + raise ValueError("cannot convert %s to an element of %s" % (der, self)) return self.element_class(self, der) Element = Derangement @@ -420,7 +420,7 @@ def cardinality(self): sL = set(self._set) A = [self._set.count(i) for i in sL] R = PolynomialRing(QQ, 'x', len(A)) - S = sum(i for i in R.gens()) + S = sum(R.gens()) e = prod((S - x)**y for (x, y) in zip(R.gens(), A)) return Integer(e.coefficient(dict([(x, y) for (x, y) in zip(R.gens(), A)]))) return self._count_der(len(self._set)) diff --git a/src/sage/combinat/descent_algebra.py b/src/sage/combinat/descent_algebra.py index 1245a8d1d59..8945c697c1e 100644 --- a/src/sage/combinat/descent_algebra.py +++ b/src/sage/combinat/descent_algebra.py @@ -19,7 +19,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.algebras import Algebras from sage.categories.realizations import Realizations, Category_realization_of_parent -from sage.categories.all import FiniteDimensionalAlgebrasWithBasis +from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.arith.misc import factorial @@ -718,7 +718,7 @@ def one(self): def one_basis(self): """ The element `1` is not (generally) a basis vector in the `I` - basis, thus this returns a ``TypeError``. + basis, thus this raises a :class:`TypeError`. EXAMPLES:: diff --git a/src/sage/combinat/designs/bibd.py b/src/sage/combinat/designs/bibd.py index 72be454ec63..019c11dbf65 100644 --- a/src/sage/combinat/designs/bibd.py +++ b/src/sage/combinat/designs/bibd.py @@ -4,7 +4,7 @@ This module gathers everything related to Balanced Incomplete Block Designs. One can build a BIBD (or check that it can be built) with :func:`balanced_incomplete_block_design`:: - sage: BIBD = designs.balanced_incomplete_block_design(7,3,1) + sage: BIBD = designs.balanced_incomplete_block_design(7,3,1) # needs sage.schemes In particular, Sage can build a `(v,k,1)`-BIBD when one exists for all `k\leq 5`. The following functions are available: @@ -50,12 +50,16 @@ --------- """ +from sage.arith.misc import binomial, is_prime_power, is_square from sage.categories.sets_cat import EmptySetError +from sage.misc.lazy_import import lazy_import from sage.misc.unknown import Unknown + from .design_catalog import transversal_design # type:ignore -from sage.arith.all import binomial, is_prime_power -from .group_divisible_designs import GroupDivisibleDesign from .designs_pyx import is_pairwise_balanced_design +from .group_divisible_designs import GroupDivisibleDesign + +lazy_import('sage.schemes.plane_conics.constructor', 'Conic') def biplane(n, existence=False): @@ -71,12 +75,12 @@ def biplane(n, existence=False): - ``existence`` (boolean) -- instead of building the design, return: - - ``True`` -- meaning that Sage knows how to build the design + - ``True`` -- meaning that Sage knows how to build the design - - ``Unknown`` -- meaning that Sage does not know how to build the - design, but that the design may exist (see :mod:`sage.misc.unknown`). + - ``Unknown`` -- meaning that Sage does not know how to build the + design, but that the design may exist (see :mod:`sage.misc.unknown`). - - ``False`` -- meaning that the design does not exist. + - ``False`` -- meaning that the design does not exist. .. SEEALSO:: @@ -84,21 +88,22 @@ def biplane(n, existence=False): EXAMPLES:: - sage: designs.biplane(4) + sage: designs.biplane(4) # needs sage.rings.finite_rings (16,6,2)-Balanced Incomplete Block Design - sage: designs.biplane(7, existence=True) + sage: designs.biplane(7, existence=True) # needs sage.schemes True - sage: designs.biplane(11) + sage: designs.biplane(11) # needs sage.schemes (79,13,2)-Balanced Incomplete Block Design TESTS:: - sage: designs.biplane(9) + sage: designs.biplane(9) # needs sage.libs.gap (56,11,2)-Balanced Incomplete Block Design Check all known biplanes:: - sage: [n for n in [0,1,2,3,4,7,9,11] if designs.biplane(n, existence=True) is True] + sage: [n for n in [0,1,2,3,4,7,9,11] # needs sage.schemes + ....: if designs.biplane(n, existence=True) is True] [0, 1, 2, 3, 4, 7, 9, 11] """ k = n+2 @@ -149,9 +154,10 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa EXAMPLES:: - sage: designs.balanced_incomplete_block_design(7, 3, 1).blocks() + sage: designs.balanced_incomplete_block_design(7, 3, 1).blocks() # needs sage.schemes [[0, 1, 3], [0, 2, 4], [0, 5, 6], [1, 2, 6], [1, 4, 5], [2, 3, 5], [3, 4, 6]] - sage: B = designs.balanced_incomplete_block_design(66, 6, 1, use_LJCR=True) # optional - internet + sage: B = designs.balanced_incomplete_block_design(66, 6, 1, # optional - internet + ....: use_LJCR=True) sage: B # optional - internet (66,6,1)-Balanced Incomplete Block Design sage: B.blocks() # optional - internet @@ -165,11 +171,11 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa sage: designs.balanced_incomplete_block_design(85,5,existence=True) True - sage: _ = designs.balanced_incomplete_block_design(85,5) + sage: _ = designs.balanced_incomplete_block_design(85,5) # needs sage.libs.pari A BIBD from a Finite Projective Plane:: - sage: _ = designs.balanced_incomplete_block_design(21,5) + sage: _ = designs.balanced_incomplete_block_design(21,5) # needs sage.schemes Some trivial BIBD:: @@ -180,22 +186,23 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa Existence of BIBD with `k=3,4,5`:: - sage: [v for v in range(50) if designs.balanced_incomplete_block_design(v,3,existence=True)] + sage: [v for v in range(50) if designs.balanced_incomplete_block_design(v,3,existence=True)] # needs sage.schemes [1, 3, 7, 9, 13, 15, 19, 21, 25, 27, 31, 33, 37, 39, 43, 45, 49] - sage: [v for v in range(100) if designs.balanced_incomplete_block_design(v,4,existence=True)] + sage: [v for v in range(100) if designs.balanced_incomplete_block_design(v,4,existence=True)] # needs sage.schemes [1, 4, 13, 16, 25, 28, 37, 40, 49, 52, 61, 64, 73, 76, 85, 88, 97] - sage: [v for v in range(150) if designs.balanced_incomplete_block_design(v,5,existence=True)] + sage: [v for v in range(150) if designs.balanced_incomplete_block_design(v,5,existence=True)] # needs sage.schemes [1, 5, 21, 25, 41, 45, 61, 65, 81, 85, 101, 105, 121, 125, 141, 145] For `k > 5` there are currently very few constructions:: - sage: [v for v in range(300) if designs.balanced_incomplete_block_design(v,6,existence=True) is True] + sage: [v for v in range(300) if designs.balanced_incomplete_block_design(v,6,existence=True) is True] # needs sage.schemes [1, 6, 31, 66, 76, 91, 96, 106, 111, 121, 126, 136, 141, 151, 156, 171, 181, 186, 196, 201, 211, 241, 271] - sage: [v for v in range(300) if designs.balanced_incomplete_block_design(v,6,existence=True) is Unknown] + sage: [v for v in range(300) if designs.balanced_incomplete_block_design(v,6,existence=True) is Unknown] # needs sage.schemes [51, 61, 81, 166, 216, 226, 231, 246, 256, 261, 276, 286, 291] Here are some constructions with `k \geq 7` and `v` a prime power:: + sage: # needs sage.libs.pari sage: designs.balanced_incomplete_block_design(169,7) (169,7,1)-Balanced Incomplete Block Design sage: designs.balanced_incomplete_block_design(617,8) @@ -214,22 +221,22 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa sage: designs.balanced_incomplete_block_design(176, 50, 14, existence=True) True - sage: designs.balanced_incomplete_block_design(64,28,12) + sage: designs.balanced_incomplete_block_design(64,28,12) # needs sage.libs.pari (64,28,12)-Balanced Incomplete Block Design - sage: designs.balanced_incomplete_block_design(37,9,8) + sage: designs.balanced_incomplete_block_design(37,9,8) # needs sage.libs.pari (37,9,8)-Balanced Incomplete Block Design - sage: designs.balanced_incomplete_block_design(15,7,3) + sage: designs.balanced_incomplete_block_design(15,7,3) # needs sage.schemes (15,7,3)-Balanced Incomplete Block Design Some BIBDs from the recursive construction :: - sage: designs.balanced_incomplete_block_design(76,16,4) + sage: designs.balanced_incomplete_block_design(76,16,4) # needs sage.libs.pari (76,16,4)-Balanced Incomplete Block Design - sage: designs.balanced_incomplete_block_design(10,4,2) + sage: designs.balanced_incomplete_block_design(10,4,2) # needs sage.libs.pari (10,4,2)-Balanced Incomplete Block Design - sage: designs.balanced_incomplete_block_design(50,25,24) + sage: designs.balanced_incomplete_block_design(50,25,24) # needs sage.schemes (50,25,24)-Balanced Incomplete Block Design - sage: designs.balanced_incomplete_block_design(29,15,15) + sage: designs.balanced_incomplete_block_design(29,15,15) # needs sage.libs.pari (29,15,15)-Balanced Incomplete Block Design """ # Trivial BIBD @@ -252,8 +259,8 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa # # With lambda>1 other exceptions are # (15,5,2),(21,6,2),(22,7,2),(22,8,4). - (k==6 and v in [36,46]) or - (k==7 and v == 43) or + (k == 6 and v in [36,46]) or + (k == 7 and v == 43) or # Fisher's inequality (lambd*v*(v-1))/(k*(k-1)) < v): if existence: @@ -272,15 +279,15 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa return BIBD(v, [[x, y] for _ in range(lambd) for x in range(v) for y in range(x+1, v) if x != y], lambd=lambd, check=False, copy=True) if k == 3 and lambd == 1: if existence: - return v%6 == 1 or v%6 == 3 + return v % 6 == 1 or v % 6 == 3 return steiner_triple_system(v) if k == 4 and lambd == 1: if existence: - return v%12 == 1 or v%12 == 4 + return v % 12 == 1 or v % 12 == 4 return BIBD(v, v_4_1_BIBD(v), copy=False) if k == 5 and lambd == 1: if existence: - return v%20 == 1 or v%20 == 5 + return v % 20 == 1 or v % 20 == 5 return BIBD(v, v_5_1_BIBD(v), copy=False) from .difference_family import difference_family @@ -333,7 +340,6 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa else: return BIBD(B.ground_set(), B.blocks(), k=k, lambd=1, copy=False) - if ( (k+lambd)*(k+lambd-1) == lambd*(v+k+lambd-1) and balanced_incomplete_block_design(v+k+lambd, k+lambd, lambd, existence=True) is True): # By removing a block and all points of that block from the @@ -384,15 +390,15 @@ def BruckRyserChowla_check(v, k, lambd): Nonexistence of projective planes of order 6 and 14 sage: from sage.combinat.designs.bibd import BruckRyserChowla_check - sage: BruckRyserChowla_check(43,7,1) + sage: BruckRyserChowla_check(43,7,1) # needs sage.schemes False - sage: BruckRyserChowla_check(211,15,1) + sage: BruckRyserChowla_check(211,15,1) # needs sage.schemes False Existence of symmetric BIBDs with parameters `(79,13,2)` and `(56,11,2)` sage: from sage.combinat.designs.bibd import BruckRyserChowla_check - sage: BruckRyserChowla_check(79,13,2) + sage: BruckRyserChowla_check(79,13,2) # needs sage.schemes True sage: BruckRyserChowla_check(56,11,2) True @@ -410,22 +416,20 @@ def BruckRyserChowla_check(v, k, lambd): Clearly wrong parameters satisfying the theorem:: sage: from sage.combinat.designs.bibd import BruckRyserChowla_check - sage: BruckRyserChowla_check(13,25,50) + sage: BruckRyserChowla_check(13,25,50) # needs sage.schemes True """ - from sage.arith.misc import is_square - from sage.schemes.plane_conics.constructor import Conic from sage.rings.rational_field import QQ # design is not symmetric if k*(k-1) != lambd*(v-1): return Unknown - if v%2 == 0: + if v % 2 == 0: return is_square(k-lambd) - g = 1 if v%4 == 1 else -1 + g = 1 if v % 4 == 1 else -1 C = Conic(QQ, [1, lambd - k, -g * lambd]) (flag, sol) = C.has_rational_point(point=True) @@ -487,23 +491,23 @@ def steiner_triple_system(n): name = "Steiner Triple System on "+str(n)+" elements" - if n%6 == 3: + if n % 6 == 3: t = (n-3) // 6 Z = list(range(2 * t + 1)) T = lambda x_y : x_y[0] + (2*t+1)*x_y[1] sts = [[(i,0),(i,1),(i,2)] for i in Z] + \ - [[(i,k),(j,k),(((t+1)*(i+j)) % (2*t+1),(k+1)%3)] for k in range(3) for i in Z for j in Z if i != j] + [[(i,k),(j,k),(((t+1)*(i+j)) % (2*t+1),(k+1) % 3)] for k in range(3) for i in Z for j in Z if i != j] - elif n%6 == 1: + elif n % 6 == 1: t = (n-1) // 6 N = list(range(2 * t)) T = lambda x_y : x_y[0]+x_y[1]*t*2 if x_y != (-1,-1) else n-1 L1 = lambda i,j : (i+j) % ((n-1)//3) - L = lambda i,j : L1(i,j)//2 if L1(i,j)%2 == 0 else t+(L1(i,j)-1)//2 + L = lambda i,j : L1(i,j)//2 if L1(i,j) % 2 == 0 else t+(L1(i,j)-1)//2 sts = [[(i,0),(i,1),(i,2)] for i in range(t)] + \ [[(-1,-1),(i,k),(i-t,(k+1) % 3)] for i in range(t,2*t) for k in [0,1,2]] + \ @@ -568,23 +572,23 @@ def BIBD_from_TD(v,k,existence=False): First construction:: sage: from sage.combinat.designs.bibd import BIBD_from_TD - sage: BIBD_from_TD(25,5,existence=True) + sage: BIBD_from_TD(25,5,existence=True) # needs sage.schemes True - sage: _ = BlockDesign(25,BIBD_from_TD(25,5)) + sage: _ = BlockDesign(25,BIBD_from_TD(25,5)) # needs sage.schemes Second construction:: sage: from sage.combinat.designs.bibd import BIBD_from_TD - sage: BIBD_from_TD(21,5,existence=True) + sage: BIBD_from_TD(21,5,existence=True) # needs sage.schemes True - sage: _ = BlockDesign(21,BIBD_from_TD(21,5)) + sage: _ = BlockDesign(21,BIBD_from_TD(21,5)) # needs sage.schemes Third construction:: sage: from sage.combinat.designs.bibd import BIBD_from_TD - sage: BIBD_from_TD(85,5,existence=True) + sage: BIBD_from_TD(85,5,existence=True) # needs sage.schemes True - sage: _ = BlockDesign(85,BIBD_from_TD(85,5)) + sage: _ = BlockDesign(85,BIBD_from_TD(85,5)) # needs sage.schemes No idea:: @@ -597,7 +601,7 @@ def BIBD_from_TD(v,k,existence=False): NotImplementedError: I do not know how to build a (20,5,1)-BIBD! """ # First construction - if (v%k == 0 and + if (v % k == 0 and balanced_incomplete_block_design(v//k, k, existence=True) is True and transversal_design(k, v//k, existence=True) is True): @@ -613,7 +617,7 @@ def BIBD_from_TD(v,k,existence=False): BIBD.extend([[x+i*v for x in B] for B in BIBDvk]) # Second construction - elif ((v-1)%k == 0 and + elif ((v-1) % k == 0 and balanced_incomplete_block_design((v-1)//k+1,k,existence=True) is True and transversal_design(k,(v-1)//k,existence=True)) is True: @@ -630,7 +634,7 @@ def BIBD_from_TD(v,k,existence=False): BIBD.extend([[inf if x == v else x+i*v for x in B] for B in BIBDv1k]) # Third construction - elif ((v-k)%k == 0 and + elif ((v-k) % k == 0 and balanced_incomplete_block_design((v-k)//k+k,k,existence=True) is True and transversal_design(k,(v-k)//k,existence=True) is True): if existence: @@ -661,7 +665,6 @@ def BIBD_from_TD(v,k,existence=False): return BIBD - def BIBD_from_difference_family(G, D, lambd=None, check=True): r""" Return the BIBD associated to the difference family ``D`` on the group ``G``. @@ -774,8 +777,8 @@ def v_4_1_BIBD(v, check=True): sage: from sage.combinat.designs.bibd import v_4_1_BIBD # long time sage: for n in range(13,100): # long time - ....: if n%12 in [1,4]: # long time - ....: _ = v_4_1_BIBD(n, check = True) # long time + ....: if n%12 in [1,4]: + ....: _ = v_4_1_BIBD(n, check = True) TESTS: @@ -789,13 +792,13 @@ def v_4_1_BIBD(v, check=True): Check some larger `(v,4,1)`-BIBD (see :trac:`17557`):: sage: for v in range(400): # long time - ....: if v%12 in [1,4]: # long time - ....: _ = designs.balanced_incomplete_block_design(v,4) # long time + ....: if v%12 in [1,4]: + ....: _ = designs.balanced_incomplete_block_design(v,4) """ k = 4 if v == 0: return [] - if v <= 12 or v%12 not in [1,4]: + if v <= 12 or v % 12 not in [1,4]: raise EmptySetError("A K_4-decomposition of K_v exists iif v=2,4 mod 12, v>12 or v==0") # Step 1. Base cases. @@ -866,8 +869,8 @@ def BIBD_from_PBD(PBD, v, k, check=True, base_cases=None): sage: from sage.combinat.designs.bibd import PBD_4_5_8_9_12 sage: from sage.combinat.designs.bibd import BIBD_from_PBD sage: from sage.combinat.designs.bibd import is_pairwise_balanced_design - sage: PBD = PBD_4_5_8_9_12(17) - sage: bibd = is_pairwise_balanced_design(BIBD_from_PBD(PBD,52,4),52,[4]) + sage: PBD = PBD_4_5_8_9_12(17) # needs sage.schemes + sage: bibd = is_pairwise_balanced_design(BIBD_from_PBD(PBD,52,4),52,[4]) # needs sage.schemes """ if base_cases is None: base_cases = {} @@ -882,7 +885,7 @@ def BIBD_from_PBD(PBD, v, k, check=True, base_cases=None): for XX in base_cases[n,k]: if N-1 in XX: continue - bibd.append([X[x//(k-1)] + (x%(k-1))*r for x in XX]) + bibd.append([X[x//(k-1)] + (x % (k-1))*r for x in XX]) for x in range(r): bibd.append([x+i*r for i in range(k-1)]+[v-1]) @@ -904,11 +907,11 @@ def _relabel_bibd(B,n,p=None): - ``n`` (integer) -- number of points. - - ``p`` (optional) -- the point that will be labeled with n-1. + - ``p`` (optional) -- the point that will be labeled with `n-1`. EXAMPLES:: - sage: designs.balanced_incomplete_block_design(40,4).blocks() # indirect doctest + sage: designs.balanced_incomplete_block_design(40,4).blocks() # indirect doctest # needs sage.schemes [[0, 1, 2, 12], [0, 3, 6, 9], [0, 4, 8, 10], [0, 5, 7, 11], [0, 13, 26, 39], [0, 14, 25, 28], [0, 15, 27, 38], [0, 16, 22, 32], [0, 17, 23, 34], @@ -950,7 +953,7 @@ def PBD_4_5_8_9_12(v, check=True): EXAMPLES:: - sage: designs.balanced_incomplete_block_design(40,4).blocks() # indirect doctest + sage: designs.balanced_incomplete_block_design(40,4).blocks() # indirect doctest # needs sage.schemes [[0, 1, 2, 12], [0, 3, 6, 9], [0, 4, 8, 10], [0, 5, 7, 11], [0, 13, 26, 39], [0, 14, 25, 28], [0, 15, 27, 38], [0, 16, 22, 32], [0, 17, 23, 34], @@ -959,7 +962,7 @@ def PBD_4_5_8_9_12(v, check=True): Check that :trac:`16476` is fixed:: sage: from sage.combinat.designs.bibd import PBD_4_5_8_9_12 - sage: for v in (0,1,4,5,8,9,12,13,16,17,20,21,24,25): + sage: for v in (0,1,4,5,8,9,12,13,16,17,20,21,24,25): # needs sage.schemes ....: _ = PBD_4_5_8_9_12(v) """ if v % 4 not in [0, 1]: @@ -976,14 +979,14 @@ def PBD_4_5_8_9_12(v, check=True): PBD = TD47 + four_more_sets elif v == 41: TD59 = transversal_design(5,9) - PBD = ([[x for x in X if x<41] for X in TD59] - +[[i*9+j for j in range(9)] for i in range(4)] - +[[36,37,38,39,40]]) + PBD = ([[x for x in X if x < 41] for X in TD59] + + [[i*9+j for j in range(9)] for i in range(4)] + + [[36,37,38,39,40]]) elif v == 44: TD59 = transversal_design(5,9) - PBD = ([[x for x in X if x<44] for X in TD59] - +[[i*9+j for j in range(9)] for i in range(4)] - +[[36,37,38,39,40,41,42,43]]) + PBD = ([[x for x in X if x < 44] for X in TD59] + + [[i*9+j for j in range(9)] for i in range(4)] + + [[36,37,38,39,40,41,42,43]]) elif v == 45: TD59 = transversal_design(5,9)._blocks PBD = (TD59+[[i*9+j for j in range(9)] for i in range(5)]) @@ -1005,7 +1008,7 @@ def PBD_4_5_8_9_12(v, check=True): else: t,u = _get_t_u(v) TD = transversal_design(5,t) - TD = [[x for x in X if x<4*t+u] for X in TD] + TD = [[x for x in X if x < 4*t+u] for X in TD] for B in [list(range(t*i,t*(i+1))) for i in range(4)]: TD.extend(_PBD_4_5_8_9_12_closure([B])) @@ -1029,7 +1032,7 @@ def _PBD_4_5_8_9_12_closure(B): EXAMPLES:: - sage: designs.balanced_incomplete_block_design(40,4).blocks() # indirect doctest + sage: designs.balanced_incomplete_block_design(40,4).blocks() # indirect doctest # needs sage.schemes [[0, 1, 2, 12], [0, 3, 6, 9], [0, 4, 8, 10], [0, 5, 7, 11], [0, 13, 26, 39], [0, 14, 25, 28], [0, 15, 27, 38], [0, 16, 22, 32], [0, 17, 23, 34], @@ -1038,13 +1041,14 @@ def _PBD_4_5_8_9_12_closure(B): BB = [] for X in B: if len(X) not in [4,5,8,9,12]: - PBD = PBD_4_5_8_9_12(len(X), check = False) + PBD = PBD_4_5_8_9_12(len(X), check=False) X = [[X[i] for i in XX] for XX in PBD] BB.extend(X) else: BB.append(X) return BB + table_7_1 = { 0:{'t':-4,'u':16,'s':2}, 1:{'t':-4,'u':17,'s':2}, @@ -1090,7 +1094,7 @@ def _get_t_u(v): # Table 7.1 v = int(v) global table_7_1 - d = table_7_1[v%48] + d = table_7_1[v % 48] s = v//48 if s < d['s']: raise RuntimeError("This should not have happened.") @@ -1121,7 +1125,7 @@ def v_5_1_BIBD(v, check=True): sage: from sage.combinat.designs.bibd import v_5_1_BIBD sage: i = 0 - sage: while i<200: + sage: while i<200: # needs sage.libs.pari ....: i += 20 ....: _ = v_5_1_BIBD(i+1) ....: _ = v_5_1_BIBD(i+5) @@ -1130,17 +1134,17 @@ def v_5_1_BIBD(v, check=True): Check that the needed difference families are there:: - sage: for v in [21,41,61,81,141,161,281]: + sage: for v in [21,41,61,81,141,161,281]: # needs sage.libs.pari ....: assert designs.difference_family(v,5,existence=True) ....: _ = designs.difference_family(v,5) """ v = int(v) assert (v > 1) - assert (v%20 == 5 or v%20 == 1) # note: equivalent to (v-1)%4 == 0 and (v*(v-1))%20 == 0 + assert (v % 20 == 5 or v % 20 == 1) # note: equivalent to (v-1)%4 == 0 and (v*(v-1))%20 == 0 # Lemma 27 - if v%5 == 0 and (v//5)%4 == 1 and is_prime_power(v//5): + if v % 5 == 0 and (v//5) % 4 == 1 and is_prime_power(v//5): bibd = BIBD_5q_5_for_q_prime_power(v//5) # Lemma 28 elif v in [21,41,61,81,141,161,281]: @@ -1195,7 +1199,7 @@ def _get_r_s_t_u(v): """ r = int((v-1)/4) s = r//150 - x = r%150 + x = r % 150 if x == 0: t,u = 30*s-5, 25 @@ -1243,10 +1247,10 @@ def PBD_from_TD(k,t,u): """ from .orthogonal_arrays import transversal_design TD = transversal_design(k+bool(u),t, check=False) - TD = [[x for x in X if x<k*t+u] for X in TD] + TD = [[x for x in X if x < k*t+u] for X in TD] for i in range(k): TD.append(list(range(t*i,t*i+t))) - if u>=2: + if u >= 2: TD.append(list(range(k*t,k*t+u))) return TD @@ -1264,11 +1268,11 @@ def BIBD_5q_5_for_q_prime_power(q): sage: from sage.combinat.designs.bibd import BIBD_5q_5_for_q_prime_power sage: for q in [25, 45, 65, 85, 125, 145, 185, 205, 305, 405, 605]: # long time - ....: _ = BIBD_5q_5_for_q_prime_power(q/5) # long time + ....: _ = BIBD_5q_5_for_q_prime_power(q/5) """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - if q%4 != 1 or not is_prime_power(q): + if q % 4 != 1 or not is_prime_power(q): raise ValueError("q is not a prime power or q%4!=1.") d = (q-1)//4 @@ -1281,10 +1285,10 @@ def BIBD_5q_5_for_q_prime_power(q): for i in range(5): for j in range(d): B.append([ i*q + L[b ], - ((i+1)%5)*q + L[ a**j+b ], - ((i+1)%5)*q + L[-a**j+b ], - ((i+4)%5)*q + L[ a**(j+d)+b], - ((i+4)%5)*q + L[-a**(j+d)+b], + ((i+1) % 5)*q + L[ a**j+b ], + ((i+1) % 5)*q + L[-a**j+b ], + ((i+4) % 5)*q + L[ a**(j+d)+b], + ((i+4) % 5)*q + L[-a**(j+d)+b], ]) return B @@ -1316,14 +1320,14 @@ def BIBD_from_arc_in_desarguesian_projective_plane(n,k,existence=False): sage: from sage.combinat.designs.bibd import BIBD_from_arc_in_desarguesian_projective_plane sage: from sage.combinat.designs.bibd import BalancedIncompleteBlockDesign - sage: D = BIBD_from_arc_in_desarguesian_projective_plane(232,8) - sage: BalancedIncompleteBlockDesign(232,D) + sage: D = BIBD_from_arc_in_desarguesian_projective_plane(232,8) # needs sage.libs.gap sage.modules sage.rings.finite_rings + sage: BalancedIncompleteBlockDesign(232,D) # needs sage.libs.gap sage.modules sage.rings.finite_rings (232,8,1)-Balanced Incomplete Block Design A `(120,8,1)`-BIBD:: - sage: D = BIBD_from_arc_in_desarguesian_projective_plane(120,8) - sage: BalancedIncompleteBlockDesign(120,D) + sage: D = BIBD_from_arc_in_desarguesian_projective_plane(120,8) # needs sage.libs.gap sage.modules sage.rings.finite_rings + sage: BalancedIncompleteBlockDesign(120,D) # needs sage.libs.gap sage.modules sage.rings.finite_rings (120,8,1)-Balanced Incomplete Block Design Other parameters:: @@ -1374,15 +1378,15 @@ def BIBD_from_arc_in_desarguesian_projective_plane(n,k,existence=False): from sage.libs.gap.libgap import libgap from sage.matrix.constructor import Matrix - K = GF(q,'a') + K = GF(q,'a') one = K.one() # An irreducible quadratic form over K[X,Y] GO = libgap.GeneralOrthogonalGroup(-1,2,q) - M = libgap.InvariantQuadraticForm(GO)['matrix'] - M = Matrix(M) - M = M.change_ring(K) - Q = lambda xx,yy : M[0,0]*xx**2+(M[0,1]+M[1,0])*xx*yy+M[1,1]*yy**2 + M = libgap.InvariantQuadraticForm(GO)['matrix'] + M = Matrix(M) + M = M.change_ring(K) + Q = lambda xx,yy : M[0,0]*xx**2+(M[0,1]+M[1,0])*xx*yy+M[1,1]*yy**2 # Here, the additive subgroup H (of order n) of K mentioned in # [Denniston69] is the set of all elements of K of degree < log_n @@ -1569,14 +1573,13 @@ def arc(self, s=2, solver=None, verbose=0, *, integrality_tolerance=1e-3): EXAMPLES:: + sage: # needs sage.schemes sage: B = designs.balanced_incomplete_block_design(21, 5) - sage: a2 = B.arc() - sage: a2 # random + sage: a2 = B.arc(); a2 # random [5, 9, 10, 12, 15, 20] sage: len(a2) 6 - sage: a4 = B.arc(4) - sage: a4 # random + sage: a4 = B.arc(4); a4 # random [0, 1, 2, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20] sage: len(a4) 16 @@ -1591,13 +1594,14 @@ def arc(self, s=2, solver=None, verbose=0, *, integrality_tolerance=1e-3): sage: 1 + r*3 16 - sage: B.trace(a2).is_t_design(2, return_parameters=True) + sage: B.trace(a2).is_t_design(2, return_parameters=True) # needs sage.schemes (True, (2, 6, 2, 1)) - sage: B.trace(a4).is_t_design(2, return_parameters=True) + sage: B.trace(a4).is_t_design(2, return_parameters=True) # needs sage.schemes (True, (2, 16, 4, 1)) Some other examples which are not maximal:: + sage: # needs sage.numerical.mip sage: B = designs.balanced_incomplete_block_design(25, 4) sage: a2 = B.arc(2) sage: r = (25-1)//(4-1) @@ -1609,6 +1613,7 @@ def arc(self, s=2, solver=None, verbose=0, *, integrality_tolerance=1e-3): sage: B.trace(a2).is_t_design(2) False + sage: # needs sage.numerical.mip sage: a3 = B.arc(3) sage: len(a3), 1 + 2*r (15, 17) @@ -1622,9 +1627,9 @@ def arc(self, s=2, solver=None, verbose=0, *, integrality_tolerance=1e-3): Test consistency with relabeling:: - sage: b = designs.balanced_incomplete_block_design(7,3) - sage: b.relabel(list("abcdefg")) - sage: set(b.arc()).issubset(b.ground_set()) + sage: b = designs.balanced_incomplete_block_design(7,3) # needs sage.schemes + sage: b.relabel(list("abcdefg")) # needs sage.schemes + sage: set(b.arc()).issubset(b.ground_set()) # needs sage.schemes True """ s = int(s) @@ -1648,4 +1653,5 @@ def arc(self, s=2, solver=None, verbose=0, *, integrality_tolerance=1e-3): values = p.get_values(b, convert=bool, tolerance=integrality_tolerance) return [self._points[i] for (i,j) in values.items() if j] + BIBD = BalancedIncompleteBlockDesign diff --git a/src/sage/combinat/designs/block_design.py b/src/sage/combinat/designs/block_design.py index abdaca1e17b..17720d6ca92 100644 --- a/src/sage/combinat/designs/block_design.py +++ b/src/sage/combinat/designs/block_design.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.rings.finite_rings r""" Block designs @@ -52,16 +52,19 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ #***************************************************************************** -from sage.modules.free_module import VectorSpace +from sage.arith.misc import binomial, integer_floor, is_prime_power +from sage.categories.sets_cat import EmptySetError +from sage.misc.lazy_import import lazy_import +from sage.misc.unknown import Unknown from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.arith.all import binomial, integer_floor, is_prime_power + from .incidence_structures import IncidenceStructure -from sage.rings.finite_rings.finite_field_constructor import FiniteField -from sage.categories.sets_cat import EmptySetError -from sage.misc.unknown import Unknown -from sage.matrix.matrix_space import MatrixSpace -from sage.libs.gap.libgap import libgap + +lazy_import('sage.libs.gap.libgap', 'libgap') +lazy_import('sage.matrix.matrix_space', 'MatrixSpace') +lazy_import('sage.modules.free_module', 'VectorSpace') +lazy_import('sage.rings.finite_rings.finite_field_constructor', 'FiniteField') BlockDesign = IncidenceStructure @@ -75,7 +78,7 @@ def tdesign_params(t, v, k, L): EXAMPLES:: - sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]]) + sage: BD = BlockDesign(7, [[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]]) sage: from sage.combinat.designs.block_design import tdesign_params sage: tdesign_params(2,7,3,1) (2, 7, 7, 3, 3, 1) @@ -114,17 +117,19 @@ def are_hyperplanes_in_projective_geometry_parameters(v, k, lmbda, return_parame EXAMPLES:: sage: from sage.combinat.designs.block_design import are_hyperplanes_in_projective_geometry_parameters - sage: are_hyperplanes_in_projective_geometry_parameters(40,13,4) + sage: are_hyperplanes_in_projective_geometry_parameters(40, 13, 4) True - sage: are_hyperplanes_in_projective_geometry_parameters(40,13,4,return_parameters=True) + sage: are_hyperplanes_in_projective_geometry_parameters(40, 13, 4, + ....: return_parameters=True) (True, (3, 3)) - sage: PG = designs.ProjectiveGeometryDesign(3,2,GF(3)) + sage: PG = designs.ProjectiveGeometryDesign(3, 2, GF(3)) sage: PG.is_t_design(return_parameters=True) (True, (2, 40, 13, 4)) - sage: are_hyperplanes_in_projective_geometry_parameters(15,3,1) + sage: are_hyperplanes_in_projective_geometry_parameters(15, 3, 1) False - sage: are_hyperplanes_in_projective_geometry_parameters(15,3,1,return_parameters=True) + sage: are_hyperplanes_in_projective_geometry_parameters(15, 3, 1, + ....: return_parameters=True) (False, (None, None)) TESTS:: @@ -167,7 +172,7 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, ch Return a projective geometry design. The projective geometry design `PG_d(n,q)` has for points the lines of - `\GF{q}^{n+1}`, and for blocks the `d+1`-dimensional subspaces of + `\GF{q}^{n+1}`, and for blocks the `(d+1)`-dimensional subspaces of `\GF{q}^{n+1}`, each of which contains `\frac {|\GF{q}|^{d+1}-1} {|\GF{q}|-1}` lines. It is a `2`-design with parameters @@ -189,9 +194,9 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, ch INPUT: - - ``n`` is the projective dimension + - ``n`` -- the projective dimension - - ``d`` is the dimension of the subspaces which make up the blocks. + - ``d`` -- the dimension of the subspaces which make up the blocks. - ``F`` -- a finite field or a prime power. @@ -212,8 +217,7 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, ch The set of `d`-dimensional subspaces in a `n`-dimensional projective space forms `2`-designs (or balanced incomplete block designs):: - sage: PG = designs.ProjectiveGeometryDesign(4, 2, GF(2)) - sage: PG + sage: PG = designs.ProjectiveGeometryDesign(4, 2, GF(2)); PG Incidence structure with 31 points and 155 blocks sage: PG.is_t_design(return_parameters=True) (True, (2, 31, 7, 7)) @@ -224,8 +228,7 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, ch Check with ``F`` being a prime power:: - sage: PG = designs.ProjectiveGeometryDesign(3, 2, 4) - sage: PG + sage: PG = designs.ProjectiveGeometryDesign(3, 2, 4); PG Incidence structure with 85 points and 85 blocks Use coordinates:: @@ -236,14 +239,14 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, ch Use indexing by integers:: - sage: PG = designs.ProjectiveGeometryDesign(2,1,GF(3),point_coordinates=0) + sage: PG = designs.ProjectiveGeometryDesign(2, 1, GF(3), point_coordinates=0) sage: PG.blocks()[0] [0, 1, 2, 12] Check that the constructor using gap also works:: - sage: BD = designs.ProjectiveGeometryDesign(2, 1, GF(2), algorithm="gap") # optional - gap_packages (design package) - sage: BD.is_t_design(return_parameters=True) # optional - gap_packages (design package) + sage: BD = designs.ProjectiveGeometryDesign(2, 1, GF(2), algorithm="gap") # optional - gap_package_design + sage: BD.is_t_design(return_parameters=True) # optional - gap_package_design (True, (2, 7, 3, 1)) """ try: @@ -304,7 +307,7 @@ def DesarguesianProjectivePlaneDesign(n, point_coordinates=True, check=True): - ``n`` -- an integer which must be a power of a prime number - - ``point_coordinates`` (boolean) -- whether to label the points with their + - ``point_coordinates`` -- (boolean) whether to label the points with their homogeneous coordinates (default) or with integers. - ``check`` -- (boolean) Whether to check that output is correct before @@ -343,11 +346,11 @@ def DesarguesianProjectivePlaneDesign(n, point_coordinates=True, check=True): # we relabel the points with the integers from 0 to n^2 + n as follows: # - the affine plane is the set of points [x:y:1] (i.e. the third coordinate # is non-zero) and gets relabeled from 0 to n^2-1 - affine_plane = lambda x,y: relabel[x] + n * relabel[y] + affine_plane = lambda x,y: relabel[x] + n * relabel[y] # - the affine line is the set of points [x:1:0] (i.e. the third coordinate is # zero but not the second one) and gets relabeled from n^2 to n^2 + n - 1 - line_infinity = lambda x: n2 + relabel[x] + line_infinity = lambda x: n2 + relabel[x] # - the point is [1:0:0] and gets relabeled n^2 + n point_infinity = n2 + n @@ -380,13 +383,13 @@ def DesarguesianProjectivePlaneDesign(n, point_coordinates=True, check=True): if point_coordinates: zero = K.zero() - one = K.one() + one = K.one() d = {affine_plane(x,y): (x,y,one) for x in Kiter for y in Kiter} d.update({line_infinity(x): (x,one,zero) for x in Kiter}) - d[n2+n]=(one,zero,zero) + d[n2+n] = (one,zero,zero) B.relabel(d) return B @@ -395,7 +398,7 @@ def q3_minus_one_matrix(K): r""" Return a companion matrix in `GL(3, K)` whose multiplicative order is `q^3 - 1`. - This function is used in :func:`HughesPlane` + This function is used in :func:`HughesPlane`. EXAMPLES:: @@ -404,7 +407,7 @@ def q3_minus_one_matrix(K): sage: m.multiplicative_order() == 3**3 - 1 True - sage: m = q3_minus_one_matrix(GF(4,'a')) + sage: m = q3_minus_one_matrix(GF(4, 'a')) sage: m.multiplicative_order() == 4**3 - 1 True @@ -412,7 +415,7 @@ def q3_minus_one_matrix(K): sage: m.multiplicative_order() == 5**3 - 1 True - sage: m = q3_minus_one_matrix(GF(9,'a')) + sage: m = q3_minus_one_matrix(GF(9, 'a')) sage: m.multiplicative_order() == 9**3 - 1 True """ @@ -450,21 +453,21 @@ def normalize_hughes_plane_point(p, q): INPUT: - - ``p`` - point with the coordinates (x,y,z) (a list, a vector, a tuple...) + - ``p`` -- point with the coordinates `(x,y,z)` (a list, a vector, a tuple...) - - ``q`` - cardinality of the underlying finite field + - ``q`` -- cardinality of the underlying finite field EXAMPLES:: sage: from sage.combinat.designs.block_design import normalize_hughes_plane_point sage: K = FiniteField(9,'x') sage: x = K.gen() - sage: normalize_hughes_plane_point((x, x+1, x), 9) + sage: normalize_hughes_plane_point((x, x + 1, x), 9) (1, x, 1) sage: normalize_hughes_plane_point(vector((x,x,x)), 9) (1, 1, 1) sage: zero = K.zero() - sage: normalize_hughes_plane_point((2*x+2, zero, zero), 9) + sage: normalize_hughes_plane_point((2*x + 2, zero, zero), 9) (1, 0, 0) sage: one = K.one() sage: normalize_hughes_plane_point((2*x, one, zero), 9) @@ -526,8 +529,7 @@ def HughesPlane(q2, check=True): EXAMPLES:: - sage: H = designs.HughesPlane(9) - sage: H + sage: H = designs.HughesPlane(9); H (91,10,1)-Balanced Incomplete Block Design We prove in the following computations that the Desarguesian plane ``H`` is @@ -586,7 +588,7 @@ def HughesPlane(q2, check=True): """ if not q2.is_square(): raise EmptySetError("No Hughes plane of non-square order exists.") - if q2%2 == 0: + if q2 % 2 == 0: raise EmptySetError("No Hughes plane of even order exists.") q = q2.sqrt() K = FiniteField(q2, prefix='x') @@ -632,9 +634,9 @@ def projective_plane_to_OA(pplane, pt=None, check=True): INPUT: - - ``pplane`` - a projective plane as a 2-design + - ``pplane`` -- a projective plane as a 2-design - - ``pt`` - a point in the projective plane ``pplane``. If it is not provided + - ``pt`` -- a point in the projective plane ``pplane``. If it is not provided, then it is set to `n^2 + n`. - ``check`` -- (boolean) Whether to check that output is correct before @@ -645,10 +647,10 @@ def projective_plane_to_OA(pplane, pt=None, check=True): EXAMPLES:: sage: from sage.combinat.designs.block_design import projective_plane_to_OA - sage: p2 = designs.DesarguesianProjectivePlaneDesign(2,point_coordinates=False) + sage: p2 = designs.DesarguesianProjectivePlaneDesign(2, point_coordinates=False) sage: projective_plane_to_OA(p2) [[0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 0]] - sage: p3 = designs.DesarguesianProjectivePlaneDesign(3,point_coordinates=False) + sage: p3 = designs.DesarguesianProjectivePlaneDesign(3, point_coordinates=False) sage: projective_plane_to_OA(p3) [[0, 0, 0, 0], [0, 1, 2, 1], @@ -660,7 +662,7 @@ def projective_plane_to_OA(pplane, pt=None, check=True): [2, 1, 0, 2], [2, 2, 2, 0]] - sage: pp = designs.DesarguesianProjectivePlaneDesign(16,point_coordinates=False) + sage: pp = designs.DesarguesianProjectivePlaneDesign(16, point_coordinates=False) sage: _ = projective_plane_to_OA(pp, pt=0) sage: _ = projective_plane_to_OA(pp, pt=3) sage: _ = projective_plane_to_OA(pp, pt=7) @@ -695,9 +697,9 @@ def projective_plane(n, check=True, existence=False): `n^2+n+1` points. For more information on finite projective planes, see the :wikipedia:`Projective_plane#Finite_projective_planes`. - If no construction is possible, then the function raises a ``EmptySetError`` - whereas if no construction is available the function raises a - ``NotImplementedError``. + If no construction is possible, then the function raises a :class:`EmptySetError`, + whereas if no construction is available, the function raises a + :class:`NotImplementedError`. INPUT: @@ -720,11 +722,14 @@ def projective_plane(n, check=True, existence=False): sage: designs.projective_plane(10) Traceback (most recent call last): ... - EmptySetError: No projective plane of order 10 exists by C. Lam, L. Thiel and S. Swiercz "The nonexistence of finite projective planes of order 10" (1989), Canad. J. Math. + EmptySetError: No projective plane of order 10 exists by + C. Lam, L. Thiel and S. Swiercz "The nonexistence of finite + projective planes of order 10" (1989), Canad. J. Math. sage: designs.projective_plane(12) Traceback (most recent call last): ... - NotImplementedError: If such a projective plane exists, we do not know how to build it. + NotImplementedError: If such a projective plane exists, + we do not know how to build it. sage: designs.projective_plane(14) Traceback (most recent call last): ... @@ -753,7 +758,7 @@ def projective_plane(n, check=True, existence=False): return False ref = ("C. Lam, L. Thiel and S. Swiercz \"The nonexistence of finite " "projective planes of order 10\" (1989), Canad. J. Math.") - raise EmptySetError("No projective plane of order 10 exists by %s"%ref) + raise EmptySetError("No projective plane of order 10 exists by %s" % ref) if BruckRyserChowla_check(n*n+n+1, n+1, 1) is False: if existence: @@ -829,9 +834,11 @@ def AffineGeometryDesign(n, d, F, point_coordinates=True, check=True): Testing the option ``point_coordinates``:: - sage: designs.AffineGeometryDesign(3, 1, GF(2), point_coordinates=True).blocks()[0] + sage: designs.AffineGeometryDesign(3, 1, GF(2), + ....: point_coordinates=True).blocks()[0] [(0, 0, 0), (0, 0, 1)] - sage: designs.AffineGeometryDesign(3, 1, GF(2), point_coordinates=False).blocks()[0] + sage: designs.AffineGeometryDesign(3, 1, GF(2), + ....: point_coordinates=False).blocks()[0] [0, 1] """ try: @@ -882,7 +889,7 @@ def AffineGeometryDesign(n, d, F, point_coordinates=True, check=True): def CremonaRichmondConfiguration(): r""" - Return the Cremona-Richmond configuration + Return the Cremona-Richmond configuration. The Cremona-Richmond configuration is a set system whose incidence graph is equal to the @@ -894,10 +901,10 @@ def CremonaRichmondConfiguration(): EXAMPLES:: - sage: H = designs.CremonaRichmondConfiguration(); H + sage: H = designs.CremonaRichmondConfiguration(); H # needs networkx Incidence structure with 15 points and 15 blocks - sage: g = graphs.TutteCoxeterGraph() - sage: H.incidence_graph().is_isomorphic(g) + sage: g = graphs.TutteCoxeterGraph() # needs networkx + sage: H.incidence_graph().is_isomorphic(g) # needs networkx True """ from sage.graphs.generators.smallgraphs import TutteCoxeterGraph @@ -927,12 +934,12 @@ def WittDesign(n): EXAMPLES:: - sage: BD = designs.WittDesign(9) # optional - gap_packages (design package) - sage: BD.is_t_design(return_parameters=True) # optional - gap_packages (design package) + sage: BD = designs.WittDesign(9) # optional - gap_package_design + sage: BD.is_t_design(return_parameters=True) # optional - gap_package_design (True, (2, 9, 3, 1)) - sage: BD # optional - gap_packages (design package) + sage: BD # optional - gap_package_design Incidence structure with 9 points and 12 blocks - sage: print(BD) # optional - gap_packages (design package) + sage: print(BD) # optional - gap_package_design Incidence structure with 9 points and 12 blocks """ libgap.load_package("design") @@ -950,16 +957,16 @@ def HadamardDesign(n): EXAMPLES:: - sage: designs.HadamardDesign(7) + sage: designs.HadamardDesign(7) # needs sage.modules Incidence structure with 7 points and 7 blocks - sage: print(designs.HadamardDesign(7)) + sage: print(designs.HadamardDesign(7)) # needs sage.modules Incidence structure with 7 points and 7 blocks - For example, the Hadamard 2-design with `n = 11` is a design whose parameters are 2-(11, 5, 2). + For example, the Hadamard 2-design with `n = 11` is a design whose parameters are `2-(11, 5, 2)`. We verify that `NJ = 5J` for this design. :: - sage: D = designs.HadamardDesign(11); N = D.incidence_matrix() - sage: J = matrix(ZZ, 11, 11, [1]*11*11); N*J + sage: D = designs.HadamardDesign(11); N = D.incidence_matrix() # needs sage.modules + sage: J = matrix(ZZ, 11, 11, [1]*11*11); N*J # needs sage.modules [5 5 5 5 5 5 5 5 5 5 5] [5 5 5 5 5 5 5 5 5 5 5] [5 5 5 5 5 5 5 5 5 5 5] @@ -1003,7 +1010,7 @@ def Hadamard3Design(n): EXAMPLES:: - sage: designs.Hadamard3Design(12) + sage: designs.Hadamard3Design(12) # needs sage.modules Incidence structure with 12 points and 22 blocks We verify that any two blocks of the Hadamard `3`-design `3-(8, 4, 1)` @@ -1013,9 +1020,9 @@ def Hadamard3Design(n): :: - sage: D = designs.Hadamard3Design(8) - sage: N = D.incidence_matrix() - sage: N.transpose()*N + sage: D = designs.Hadamard3Design(8) # needs sage.modules + sage: N = D.incidence_matrix() # needs sage.modules + sage: N.transpose()*N # needs sage.modules [4 2 2 2 2 2 2 2 2 2 2 2 2 0] [2 4 2 2 2 2 2 2 2 2 2 2 0 2] [2 2 4 2 2 2 2 2 2 2 2 0 2 2] diff --git a/src/sage/combinat/designs/covering_design.py b/src/sage/combinat/designs/covering_design.py index 1c0dfa47628..fd7172ac876 100644 --- a/src/sage/combinat/designs/covering_design.py +++ b/src/sage/combinat/designs/covering_design.py @@ -51,7 +51,7 @@ from sage.misc.sage_eval import sage_eval from sage.structure.sage_object import SageObject from sage.rings.rational import Rational -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.combinat.combination import Combinations from sage.combinat.designs.incidence_structures import IncidenceStructure from sage.cpython.string import bytes_to_str @@ -518,7 +518,7 @@ def best_known_covering_design_www(v, k, t, verbose=False): 2 3 6 2 4 5 - A ValueError is raised if the ``(v, k, t)`` parameters are not + A :class:`ValueError` is raised if the ``(v, k, t)`` parameters are not found in the database. """ v = int(v) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 564f1ea141a..d06578ccc22 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -81,13 +81,13 @@ def _MOLS_from_string(s,k): EXAMPLES:: - sage: _ = designs.mutually_orthogonal_latin_squares(2,10) # indirect doctest + sage: _ = designs.mutually_orthogonal_latin_squares(2,10) # indirect doctest # needs sage.modules """ from sage.matrix.constructor import Matrix matrices = [[] for _ in range(k)] for i,l in enumerate(s.split()): l = [ord(x) - 97 for x in l] - matrices[i%k].append(l) + matrices[i % k].append(l) return [Matrix(_) for _ in matrices] def MOLS_10_2(): @@ -101,8 +101,8 @@ def MOLS_10_2(): sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares sage: from sage.combinat.designs.database import MOLS_10_2 - sage: MOLS = MOLS_10_2() - sage: print(are_mutually_orthogonal_latin_squares(MOLS)) + sage: MOLS = MOLS_10_2() # needs sage.modules + sage: print(are_mutually_orthogonal_latin_squares(MOLS)) # needs sage.modules True The design is available from the general constructor:: @@ -143,8 +143,8 @@ def MOLS_12_5(): sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares sage: from sage.combinat.designs.database import MOLS_12_5 - sage: MOLS = MOLS_12_5() - sage: print(are_mutually_orthogonal_latin_squares(MOLS)) + sage: MOLS = MOLS_12_5() # needs sage.modules + sage: print(are_mutually_orthogonal_latin_squares(MOLS)) # needs sage.modules True """ M = """ @@ -175,13 +175,13 @@ def MOLS_14_4(): sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares sage: from sage.combinat.designs.database import MOLS_14_4 - sage: MOLS = MOLS_14_4() - sage: print(are_mutually_orthogonal_latin_squares(MOLS)) + sage: MOLS = MOLS_14_4() # needs sage.modules + sage: print(are_mutually_orthogonal_latin_squares(MOLS)) # needs sage.modules True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(4,14) + sage: designs.orthogonal_arrays.is_available(4,14) # needs sage.schemes True REFERENCE: @@ -219,13 +219,13 @@ def MOLS_15_4(): sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares sage: from sage.combinat.designs.database import MOLS_15_4 - sage: MOLS = MOLS_15_4() - sage: print(are_mutually_orthogonal_latin_squares(MOLS)) + sage: MOLS = MOLS_15_4() # needs sage.modules + sage: print(are_mutually_orthogonal_latin_squares(MOLS)) # needs sage.modules True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(4,15) + sage: designs.orthogonal_arrays.is_available(4,15) # needs sage.schemes True """ M = """ @@ -258,8 +258,8 @@ def MOLS_18_3(): sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares sage: from sage.combinat.designs.database import MOLS_18_3 - sage: MOLS = MOLS_18_3() - sage: print(are_mutually_orthogonal_latin_squares(MOLS)) + sage: MOLS = MOLS_18_3() # needs sage.modules + sage: print(are_mutually_orthogonal_latin_squares(MOLS)) # needs sage.modules True The design is available from the general constructor:: @@ -296,6 +296,7 @@ def MOLS_18_3(): # # This dictionary is used by designs.mutually_orthogonal_latin_squares(k,n). + MOLS_constructions = { 10 : (2, MOLS_10_2), 12 : (5, MOLS_12_5), @@ -328,7 +329,7 @@ def OA_7_18(): The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(7,18) + sage: designs.orthogonal_arrays.is_available(7,18) # needs sage.schemes True """ M = """ @@ -359,7 +360,7 @@ def OA_7_18(): g + G((0, 0 ,2*y))]) M = OA_from_quasi_difference_matrix(Mb,G,add_col=False) - M = [M[i] for i in range(len(M)) if i%18<9] # only develop w.r.t the last two coordinates + M = [M[i] for i in range(len(M)) if i % 18 < 9] # only develop w.r.t the last two coordinates return M def OA_9_40(): @@ -377,13 +378,13 @@ def OA_9_40(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_9_40 - sage: OA = OA_9_40() - sage: is_orthogonal_array(OA,9,40,2) + sage: OA = OA_9_40() # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,9,40,2) # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(9,40) + sage: designs.orthogonal_arrays.is_available(9,40) # needs sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -416,24 +417,24 @@ def OA_7_66(): sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array sage: from sage.combinat.designs.database import OA_7_66 - sage: OA = OA_7_66() - sage: is_orthogonal_array(OA,7,66,2) + sage: OA = OA_7_66() # needs sage.schemes + sage: is_orthogonal_array(OA,7,66,2) # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(7,66) + sage: designs.orthogonal_arrays.is_available(7,66) # needs sage.schemes True """ # base block of a (73,9,1) BIBD B = [0, 19, 26, 14, 63, 15, 32, 35, 65] # The corresponding BIBD - BIBD = [[(x+i)%73 for x in B] for i in range(73)] + BIBD = [[(x+i) % 73 for x in B] for i in range(73)] # the first 7 elements of an oval # # (this is the only difference with the OA(7,68) construction) - oval = [(-x)%73 for x in B][:7] + oval = [(-x) % 73 for x in B][:7] # PBD minus the oval PBD = [[x for x in B if x not in oval] for B in BIBD] # We relabel the points to 0,1,2,... @@ -456,24 +457,24 @@ def OA_7_68(): sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array sage: from sage.combinat.designs.database import OA_7_68 - sage: OA = OA_7_68() - sage: is_orthogonal_array(OA,7,68,2) + sage: OA = OA_7_68() # needs sage.schemes + sage: is_orthogonal_array(OA,7,68,2) # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(7,68) + sage: designs.orthogonal_arrays.is_available(7,68) # needs sage.schemes True """ # base block of a (73,9,1) BIBD B = [0, 19, 26, 14, 63, 15, 32, 35, 65] # The corresponding BIBD - BIBD = [[(x+i)%73 for x in B] for i in range(73)] + BIBD = [[(x+i) % 73 for x in B] for i in range(73)] # the first 5 elements of an oval # # (this is the only difference with the OA(7,66) construction) - oval = [(-x)%73 for x in B][:5] + oval = [(-x) % 73 for x in B][:5] # PBD minus the oval PBD = [[x for x in B if x not in oval] for B in BIBD] # We relabel the points to 0,1,2,... @@ -496,25 +497,25 @@ def OA_8_69(): sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array sage: from sage.combinat.designs.database import OA_8_69 - sage: OA = OA_8_69() - sage: is_orthogonal_array(OA,8,69,2) + sage: OA = OA_8_69() # needs sage.schemes + sage: is_orthogonal_array(OA,8,69,2) # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(8,69) + sage: designs.orthogonal_arrays.is_available(8,69) # needs sage.schemes True """ # base block of a (73,9,1) BIBD B = [1,2,4,8,16,32,37,55,64] # The corresponding BIBD - BIBD = [[(x+i)%73 for x in B] for i in range(73)] + BIBD = [[(x+i) % 73 for x in B] for i in range(73)] oval = [72,71,69,65] # PBD minus the oval PBD = [[x for x in B if x not in oval] for B in BIBD] sets_of_size_seven = [R for R in PBD if len(R) == 7] - others = [R for R in PBD if len(R) != 7] + others = [R for R in PBD if len(R) != 7] # 68, 27, and 52 are the only elements appearing twice in the rows of # sets_of_size_seven, and each row contains exactly one of them. @@ -543,7 +544,6 @@ def OA_8_69(): for BB in OA_8_7: OA.append([B[i] for i in BB]) - # Adding the missing 0..0,1..1,... rows done = sum(O1,[])+sum(O2,[]) missing = [x for x in range(73) if x not in done and x not in oval] @@ -569,22 +569,22 @@ def OA_7_74(): sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array sage: from sage.combinat.designs.database import OA_7_74 - sage: OA = OA_7_74() - sage: is_orthogonal_array(OA,7,74,2) + sage: OA = OA_7_74() # needs sage.schemes + sage: is_orthogonal_array(OA,7,74,2) # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(7,74) + sage: designs.orthogonal_arrays.is_available(7,74) # needs sage.schemes True """ # base block of a (91,10,1) BIBD B = [0,1,3,9,27,81,61,49,56,77] # The corresponding BIBD - BIBD = [[(x+i)%91 for x in B] for i in range(91)] + BIBD = [[(x+i) % 91 for x in B] for i in range(91)] # an oval - oval = [(-x)%91 for x in B][-7:] + oval = [(-x) % 91 for x in B][-7:] # PBD minus the oval+B to_delete = oval + B PBD = [[x for x in B if x not in to_delete] for B in BIBD] @@ -609,19 +609,19 @@ def OA_8_76(): sage: from sage.combinat.designs.orthogonal_arrays import is_orthogonal_array sage: from sage.combinat.designs.database import OA_8_76 - sage: OA = OA_8_76() - sage: is_orthogonal_array(OA,8,76,2) + sage: OA = OA_8_76() # needs sage.schemes + sage: is_orthogonal_array(OA,8,76,2) # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(8,76) + sage: designs.orthogonal_arrays.is_available(8,76) # needs sage.schemes True """ # base block of a (91,10,1) BIBD B = [0,1,3,9,27,81,61,49,56,77] # The corresponding BIBD - BIBD = [[(x+i)%91 for x in B] for i in range(91)] + BIBD = [[(x+i) % 91 for x in B] for i in range(91)] oval = [2,4,5,12,24] to_remove = oval + B # PBD minus the oval @@ -629,7 +629,7 @@ def OA_8_76(): PBD.remove([]) sets_of_size_seven = [R for R in PBD if len(R) == 7] - others = [R for R in PBD if len(R) != 7] + others = [R for R in PBD if len(R) != 7] # critical_points are the 10 elements appearing twice in the rows of the 10 # sets_of_size_seven, and each row contains exactly two of them @@ -638,8 +638,8 @@ def OA_8_76(): # We reorder the rows such that every element of critical_points is exactly # once the first element of a row. for i,x in zip(critical_points,sets_of_size_seven): - x.sort(key=lambda x:-int(x==i)) - assert x[0]==i + x.sort(key=lambda x:-int(x == i)) + assert x[0] == i # Blocks of "others", without the 0..0,1..1,2..2 ... rows OA = OA_from_PBD(8,76,others,check=False)[:-76] @@ -677,13 +677,13 @@ def OA_11_80(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_11_80 - sage: OA = OA_11_80() - sage: is_orthogonal_array(OA,11,80,2) + sage: OA = OA_11_80() # needs sage.rings.finite_rings sage.schemes + sage: is_orthogonal_array(OA,11,80,2) # needs sage.rings.finite_rings sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(11,80) + sage: designs.orthogonal_arrays.is_available(11,80) # needs sage.rings.finite_rings sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -719,13 +719,13 @@ def OA_15_112(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_15_112 - sage: OA = OA_15_112() - sage: is_orthogonal_array(OA,15,112,2) + sage: OA = OA_15_112() # needs sage.rings.finite_rings sage.schemes + sage: is_orthogonal_array(OA,15,112,2) # needs sage.rings.finite_rings sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(15,112) + sage: designs.orthogonal_arrays.is_available(15,112) # needs sage.rings.finite_rings sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -769,13 +769,13 @@ def OA_9_120(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_9_120 - sage: OA = OA_9_120() - sage: is_orthogonal_array(OA,9,120,2) + sage: OA = OA_9_120() # needs sage.modules sage.schemes + sage: is_orthogonal_array(OA,9,120,2) # needs sage.modules sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(9,120) + sage: designs.orthogonal_arrays.is_available(9,120) # needs sage.schemes True """ RBIBD_120 = RBIBD_120_8_1() @@ -817,20 +817,19 @@ def OA_9_135(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_9_135 - sage: OA = OA_9_135() - sage: is_orthogonal_array(OA,9,135,2) + sage: OA = OA_9_135() # needs sage.rings.finite_rings sage.schemes + sage: is_orthogonal_array(OA,9,135,2) # needs sage.rings.finite_rings sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(9,135) + sage: designs.orthogonal_arrays.is_available(9,135) # needs sage.schemes True As this orthogonal array requires a `(273,17,1)` cyclic difference set, we check that it is available:: - sage: G,D = designs.difference_family(273,17,1) - sage: G + sage: G,D = designs.difference_family(273,17,1); G # needs sage.libs.pari Ring of integers modulo 273 """ from .bibd import BIBD_from_difference_family @@ -845,20 +844,20 @@ def OA_9_135(): # 0,1, or 3 points. The set of points congruent to 0 mod 39 does the job! # # ... check that it works - assert all(sum((x%39 == 0) for x in B) in [0,1,3] for B in PG16) + assert all(sum((x % 39 == 0) for x in B) in [0,1,3] for B in PG16) # We now build an OA(17,16) from our PG16, in such a way that all points of # our PG(2,2) are in different columns. For this, we need to find a point p # that is not located on any of the lines defined by the points of the # PG(2,2). - lines = [B for B in PG16 if sum((x%39 == 0) for x in B) == 3] + lines = [B for B in PG16 if sum((x % 39 == 0) for x in B) == 3] p = set(range(237)).difference(*lines).pop() # We can now build a TD from our PG16 by removing p. for B in PG16: - B.sort(key=lambda x:int(x%39 != 0)) - PG16.sort(key=lambda B:sum((x%39 == 0) for x in B)) + B.sort(key=lambda x:int(x % 39 != 0)) + PG16.sort(key=lambda B:sum((x % 39 == 0) for x in B)) r = {} for B in PG16: @@ -871,13 +870,13 @@ def OA_9_135(): # The columns containing points from PG2 will be the last 7 assert all(r[x*39] >= (n-1)-16*7 for x in range(7)) # Those points are the first of each column - assert all(r[x*39]%16 == 0 for x in range(7)) + assert all(r[x*39] % 16 == 0 for x in range(7)) PG = [sorted([r[x] for x in B]) for B in PG16] - OA = [[x%16 for x in B] for B in PG if n-1 not in B] + OA = [[x % 16 for x in B] for B in PG if n-1 not in B] # We truncate the last 7 columns to size 1. We also drop the first column - truncated_OA = [B[1:-7]+[x if x==0 else None for x in B[-7:]] for B in OA] + truncated_OA = [B[1:-7]+[x if x == 0 else None for x in B[-7:]] for B in OA] # And call Wilson's construction return wilson_construction(truncated_OA, 9, 16, 8, (1,)*7, check=False) @@ -897,13 +896,13 @@ def OA_11_160(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_11_160 - sage: OA = OA_11_160() - sage: is_orthogonal_array(OA,11,160,2) + sage: OA = OA_11_160() # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,11,160,2) # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(11,160) + sage: designs.orthogonal_arrays.is_available(11,160) # needs sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -940,13 +939,13 @@ def OA_16_176(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_16_176 - sage: OA = OA_16_176() - sage: is_orthogonal_array(OA,16,176,2) + sage: OA = OA_16_176() # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,16,176,2) # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(16,176) + sage: designs.orthogonal_arrays.is_available(16,176) # needs sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -999,13 +998,13 @@ def OA_11_185(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_11_185 - sage: OA = OA_11_185() - sage: is_orthogonal_array(OA,11,185,2) + sage: OA = OA_11_185() # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,11,185,2) # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(11,185) + sage: designs.orthogonal_arrays.is_available(11,185) # needs sage.schemes True """ @@ -1017,10 +1016,10 @@ def OA_11_185(): # All points congruent to 0 mod[39] form a Fano subplane with the property # that each block of the PG(2,16) intersect the Fano subplane in either 0,1 # or 3 points - assert all(sum(x%39==0 for x in B) in [0,1,3] for B in BIBD) + assert all(sum(x % 39 == 0 for x in B) in [0,1,3] for B in BIBD) # Lines of the Fano subplane that are contained in blocks - fano_lines = [B for B in BIBD if sum(x%39==0 for x in B) == 3] + fano_lines = [B for B in BIBD if sum(x % 39 == 0 for x in B) == 3] # Points on a line of the Fano subplane on_a_fano_line = set().union(*fano_lines) @@ -1032,13 +1031,13 @@ def OA_11_185(): ground_set = not_on_a_fano_line.union(fano_lines[0]) PBD = [ground_set.intersection(B) for B in BIBD] relabel = {v:i for i,v in enumerate(ground_set)} - PBD = [[relabel[x] for x in B] for B in PBD if len(B)>1] + PBD = [[relabel[x] for x in B] for B in PBD if len(B) > 1] special_set = [relabel[x] for x in fano_lines[0]] # Check that everything is fine assert all(len(B) in (11,13) or set(B) == set(special_set) for B in PBD) - OA = OA_from_PBD(11,185,[B for B in PBD if len(B)<17],check=False)[:-185] + OA = OA_from_PBD(11,185,[B for B in PBD if len(B) < 17],check=False)[:-185] OA.extend([[i]*11 for i in range(185) if i not in special_set]) OA.extend([[special_set[x] for x in B] for B in orthogonal_array(11,17)]) return OA @@ -1075,13 +1074,13 @@ def OA_10_205(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_10_205 - sage: OA = OA_10_205() - sage: is_orthogonal_array(OA,10,205,2) + sage: OA = OA_10_205() # needs sage.schemes + sage: is_orthogonal_array(OA,10,205,2) # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(10,205) + sage: designs.orthogonal_arrays.is_available(10,205) # needs sage.schemes True """ # Base block of a cyclic PG(2,4^2) @@ -1089,7 +1088,7 @@ def OA_10_205(): baer_subplane_size = 4**2+4+1 B = [0, 1, 22, 33, 83, 122, 135, 141, 145, 159, 175, 200, 226, 229, 231, 238, 246] - pplane = [[(xx+i)%pplane_size for xx in B] for i in range(pplane_size)] + pplane = [[(xx+i) % pplane_size for xx in B] for i in range(pplane_size)] baer_subplane = set([i*pplane_size/baer_subplane_size for i in range(baer_subplane_size)]) p = list(baer_subplane)[0] @@ -1112,7 +1111,7 @@ def OA_10_205(): blocks_of_size_9 = [B for B in GDD if len(B) == 9] blocks_of_size_9_union = sum(blocks_of_size_9,[]) - OA = OA_from_PBD(10,205,[B for B in GDD if len(B)!=9],check=False)[:-205] + OA = OA_from_PBD(10,205,[B for B in GDD if len(B) != 9],check=False)[:-205] OA.extend([[B[xx] for xx in R] for R in orthogonal_array(10,9) @@ -1139,13 +1138,13 @@ def OA_16_208(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_16_208 - sage: OA = OA_16_208() # not tested -- too long - sage: is_orthogonal_array(OA,16,208,2) # not tested -- too long + sage: OA = OA_16_208() # not tested (too long) # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,16,208,2) # not tested (too long) # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(16,208) + sage: designs.orthogonal_arrays.is_available(16,208) # needs sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -1198,13 +1197,13 @@ def OA_15_224(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_15_224 - sage: OA = OA_15_224() # not tested -- too long - sage: is_orthogonal_array(OA,15,224,2) # not tested -- too long + sage: OA = OA_15_224() # not tested (too long) # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,15,224,2) # not tested (too long) # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(15,224) + sage: designs.orthogonal_arrays.is_available(15,224) # needs sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -1249,23 +1248,23 @@ def OA_11_254(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_11_254 - sage: OA = OA_11_254() - sage: is_orthogonal_array(OA,11,254,2) + sage: OA = OA_11_254() # needs sage.schemes + sage: is_orthogonal_array(OA,11,254,2) # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(11,254) + sage: designs.orthogonal_arrays.is_available(11,254) # needs sage.schemes True """ # Base block of a PG(2,19) B = (0,1,19,28,96,118,151,153,176,202,240,254,290,296,300,307,337,361,366,369) - BIBD = [[(x+i)%381 for x in B] for i in range(381)] + BIBD = [[(x+i) % 381 for x in B] for i in range(381)] # We only keep points congruent to 0,1 mod 3 and relabel the PBD. The result is # a (254,{11,13,16})-PBD - BIBD = [[2*(x//3)+x%3 for x in B if x%3<2] for B in BIBD] + BIBD = [[2*(x//3)+x % 3 for x in B if x % 3 < 2] for B in BIBD] return OA_from_PBD(11,254,BIBD,check=False) @@ -1284,13 +1283,13 @@ def OA_20_352(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_20_352 - sage: OA = OA_20_352() # not tested (~25s) - sage: is_orthogonal_array(OA,20,352,2) # not tested (~25s) + sage: OA = OA_20_352() # not tested (~25s) # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,20,352,2) # not tested (~25s) # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(20,352) + sage: designs.orthogonal_arrays.is_available(20,352) # needs sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -1343,19 +1342,19 @@ def OA_20_416(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_20_416 - sage: OA = OA_20_416() # not tested (~35s) - sage: is_orthogonal_array(OA,20,416,2) # not tested + sage: OA = OA_20_416() # not tested (~35s) # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,20,416,2) # not tested # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(20,416) + sage: designs.orthogonal_arrays.is_available(20,416) # needs sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField Z = None - A=[ + A = [ [(0,Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (1 , Z), (4 , Z), (9 , Z), (3 , Z), (12, Z)], [(0,Z), (1 , Z), (2 ,18), (3 , 2), (4 ,20), (5 ,22), (6 ,11), (7 ,19), (8 , 0), (9 ,26), (10, Z), (11, 5), (12,27), (1 ,17), (0 ,30), (1 ,22), (4 ,29), (9 , 6), (3 ,19)], [(0,Z), (2 , 4), (4 ,21), (6 ,10), (8 ,24), (10,13), (12, 7), (1 ,11), (3 ,29), (5 ,12), (7 ,21), (9 , 2), (11,11), (4 , 5), (1 ,11), (0 ,23), (1 ,13), (4 , 6), (9 ,15)], @@ -1403,20 +1402,20 @@ def OA_20_544(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_20_544 - sage: OA = OA_20_544() # not tested (too long ~1mn) - sage: is_orthogonal_array(OA,20,544,2) # not tested + sage: OA = OA_20_544() # not tested (too long ~1mn) # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,20,544,2) # not tested # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(20,544) + sage: designs.orthogonal_arrays.is_available(20,544) # needs sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField Z = None - A=[ + A = [ [(0,Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(1 , Z)], [(0,Z),(1 , 4),(2 , 7),(3 ,30),(4 ,17),(5 , 2),(6 ,22),(7 ,23),(8 ,28),(9 , 2),(10,27),(11,26),(12,13),(13,25),(14,18),(15,15),(16,18),(1 ,14),(0 , 1)], [(0,Z),(2 , 4),(4 ,20),(6 ,29),(8 ,27),(10, 7),(12,20),(14,19),(16,26),(1 ,28),(3 , Z),(5 ,27),(7 , Z),(9 ,11),(11, Z),(13,17),(15, 1),(4 ,14),(1 ,14)], @@ -1467,22 +1466,22 @@ def OA_17_560(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_17_560 - sage: OA = OA_17_560() - sage: is_orthogonal_array(OA,17,560,2) + sage: OA = OA_17_560() # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,17,560,2) # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(17,560) + sage: designs.orthogonal_arrays.is_available(17,560) # needs sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF alpha = 5 - beta = 4 - p = 2 - k = 17 - m = 16 - n = p**alpha + beta = 4 + p = 2 + k = 17 + m = 16 + n = p**alpha G = GF((p, alpha), prefix='x') G_set = sorted(G) # sorted by lexicographic order, G[1] = 1 @@ -1531,13 +1530,13 @@ def OA_11_640(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_11_640 - sage: OA = OA_11_640() # not tested (too long) - sage: is_orthogonal_array(OA,11,640,2) # not tested (too long) + sage: OA = OA_11_640() # not tested (too long) # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,11,640,2) # not tested (too long) # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(11,640) + sage: designs.orthogonal_arrays.is_available(11,640) # needs sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -1581,13 +1580,13 @@ def OA_10_796(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_10_796 - sage: OA = OA_10_796() - sage: is_orthogonal_array(OA,10,796,2) + sage: OA = OA_10_796() # needs sage.schemes + sage: is_orthogonal_array(OA,10,796,2) # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(10,796) + sage: designs.orthogonal_arrays.is_available(10,796) # needs sage.schemes True """ from sage.combinat.designs.orthogonal_arrays import OA_relabel @@ -1596,9 +1595,9 @@ def OA_10_796(): OA = orthogonal_array(17,47) OA = OA_relabel(OA,17,47,blocks=[OA[0]]) # making sure [46]*17 is a block - PBD = [[i*47+x for i,x in enumerate(B) if (x<46 or i<13)] for B in OA] + PBD = [[i*47+x for i,x in enumerate(B) if (x < 46 or i < 13)] for B in OA] extra_point = 10000 - PBD.extend([list(range(i*47,(i+1)*47-int(i>=13)))+[extra_point] for i in range(17)]) # Adding the columns + PBD.extend([list(range(i*47,(i+1)*47-int(i >= 13)))+[extra_point] for i in range(17)]) # Adding the columns rel = {v:i for i,v in enumerate(set(range(17*47)).difference([(i+1)*47-1 for i in range(13,17)]))} rel[extra_point] = len(rel) @@ -1615,7 +1614,7 @@ def OA_10_796(): for B in PBD: if len(B) >= 47: - B.sort(key=lambda x:int(x==extra_point)) + B.sort(key=lambda x:int(x == extra_point)) OA.extend([[B[i] for i in BB] for BB in iOA[len(B)]]) span.update(B[:-1]) else: @@ -1659,13 +1658,13 @@ def OA_10_469(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_10_469 - sage: OA = OA_10_469() - sage: is_orthogonal_array(OA,10,469,2) + sage: OA = OA_10_469() # long time # needs sage.schemes + sage: is_orthogonal_array(OA,10,469,2) # long time # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(10,469) + sage: designs.orthogonal_arrays.is_available(10,469) # needs sage.schemes True """ from .orthogonal_arrays_build_recursive import _reorder_matrix @@ -1678,10 +1677,10 @@ def OA_10_469(): 731,824,837,848,932,1002,1051,1055,1089,1105,1145,1165,1196,1217,1226, 1274,1281,1309,1405) - BIBD = [[(x+i)%1407 for x in B] for i in range(1407)] + BIBD = [[(x+i) % 1407 for x in B] for i in range(1407)] # Only keep points v congruent to 0 mod 3 and relabel - PBD = [[x//3 for x in B if x%3==0] for B in BIBD] + PBD = [[x//3 for x in B if x % 3 == 0] for B in BIBD] # Split the block according to their size blocks = {9:[],13:[],16:[]} @@ -1755,8 +1754,8 @@ def OA_520_plus_x(x): # corresponding to each (possibly truncated) group extended with a new # point. The result is a (520+x,{9+x,16,17,31,32})-PBD. new_point = 31*17 - PBD = [[i*31+xx for i,xx in enumerate(B) if i<9+x or xx<30] for B in OA] # truncated blocks - PBD.extend([list(range(i*31,i*31+30+bool(i<9+x)))+[new_point] for i in range(17)]) # extended (+truncated) groups + PBD = [[i*31+xx for i,xx in enumerate(B) if i < 9+x or xx < 30] for B in OA] # truncated blocks + PBD.extend([list(range(i*31,i*31+30+bool(i < 9+x)))+[new_point] for i in range(17)]) # extended (+truncated) groups relabel = {v:i for i,v in enumerate(sorted(set().union(*PBD)))} PBD = [[relabel[xx] for xx in B] for B in PBD] @@ -1788,13 +1787,13 @@ def OA_10_520(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_10_520 - sage: OA = OA_10_520() - sage: is_orthogonal_array(OA,10,520,2) + sage: OA = OA_10_520() # needs sage.schemes + sage: is_orthogonal_array(OA,10,520,2) # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(10,520) + sage: designs.orthogonal_arrays.is_available(10,520) # needs sage.schemes True """ return OA_520_plus_x(0) @@ -1810,13 +1809,13 @@ def OA_12_522(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_12_522 - sage: OA = OA_12_522() - sage: is_orthogonal_array(OA,12,522,2) + sage: OA = OA_12_522() # needs sage.schemes + sage: is_orthogonal_array(OA,12,522,2) # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(12,522) + sage: designs.orthogonal_arrays.is_available(12,522) # needs sage.schemes True """ return OA_520_plus_x(2) @@ -1832,13 +1831,13 @@ def OA_14_524(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_14_524 - sage: OA = OA_14_524() - sage: is_orthogonal_array(OA,14,524,2) + sage: OA = OA_14_524() # needs sage.schemes + sage: is_orthogonal_array(OA,14,524,2) # needs sage.schemes True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(14,524) + sage: designs.orthogonal_arrays.is_available(14,524) # needs sage.schemes True """ return OA_520_plus_x(4) @@ -1858,13 +1857,13 @@ def OA_15_896(): sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: from sage.combinat.designs.database import OA_15_896 - sage: OA = OA_15_896() # not tested -- too long (~2min) - sage: is_orthogonal_array(OA,15,896,2) # not tested -- too long + sage: OA = OA_15_896() # not tested (too long, ~2min) # needs sage.rings.finite_rings + sage: is_orthogonal_array(OA,15,896,2) # not tested (too long) # needs sage.rings.finite_rings True The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(15,896) + sage: designs.orthogonal_arrays.is_available(15,896) # needs sage.schemes True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -1915,7 +1914,7 @@ def OA_9_1078(): The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(9,1078) + sage: designs.orthogonal_arrays.is_available(9,1078) # needs sage.schemes True """ return wilson_construction(None,9,11,89,[[(11,9)]]) @@ -1941,7 +1940,7 @@ def OA_25_1262(): The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(25,1262) + sage: designs.orthogonal_arrays.is_available(25,1262) # needs sage.schemes True """ @@ -1951,9 +1950,9 @@ def OA_25_1262(): 1217, 1219, 1220, 1261, 1306, 1349, 1370, 1400, 1461, 1480, 1517, 1714, 1768, 1827, 1833, 1866) - BIBD = [[(x+i)%1893 for x in B] for i in range(1893)] # a (1893,44,1)-BIBD - PBD = [[x for x in B if (x%3)<2] for B in BIBD] # We only keep the x with x%3=0,1 - PBD = [[2*(x//3)+(x%3) for x in B] for B in PBD] # The (1262, {25, 31,32})-PBD + BIBD = [[(x+i) % 1893 for x in B] for i in range(1893)] # a (1893,44,1)-BIBD + PBD = [[x for x in B if (x % 3) < 2] for B in BIBD] # We only keep the x with x%3=0,1 + PBD = [[2*(x//3)+(x % 3) for x in B] for B in PBD] # The (1262, {25, 31,32})-PBD return OA_from_PBD(25,1262,PBD,check=False) @@ -1982,7 +1981,7 @@ def OA_9_1612(): The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(9,1612) + sage: designs.orthogonal_arrays.is_available(9,1612) # needs sage.schemes True """ return wilson_construction(None,9,17,89,[[(11,9)]]) @@ -2012,7 +2011,7 @@ def OA_10_1620(): The design is available from the general constructor:: - sage: designs.orthogonal_arrays.is_available(10,1620) + sage: designs.orthogonal_arrays.is_available(10,1620) # needs sage.schemes True """ return wilson_construction(None,10,11,144,[[(9,4)]]) @@ -2023,6 +2022,7 @@ def OA_10_1620(): # # This dictionary is used by designs.orthogonal_array(k,n). + OA_constructions = { 18 : (7 , OA_7_18), 40 : (9 , OA_9_40), @@ -2079,23 +2079,24 @@ def QDM_19_6_1_1_1(): True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic - M=[[None, 7, 13, 1, 16, 9, 2], - [ 0, 1, 15, 7, 17, 6, 14], - [ 0, 11, 10, 11, 5, 4, 3], - [ 7,None, 13, 16, 1, 2, 9], - [ 1, 0, 15, 17, 7, 14, 6], - [ 11, 0, 10, 5, 11, 3, 4]] + M = [[None, 7, 13, 1, 16, 9, 2], + [ 0, 1, 15, 7, 17, 6, 14], + [ 0, 11, 10, 11, 5, 4, 3], + [ 7,None, 13, 16, 1, 2, 9], + [ 1, 0, 15, 17, 7, 14, 6], + [ 11, 0, 10, 5, 11, 3, 4]] - Mb=[] + Mb = [] for R in zip(*M): - a,b,c,d,e,f = R - Mb.append([a,b,c,d,e,f]) - Mb.append([b,c,a,f,d,e]) - Mb.append([c,a,b,e,f,d]) + a, b, c, d, e, f = R + Mb.append([a, b, c, d, e, f]) + Mb.append([b, c, a, f, d, e]) + Mb.append([c, a, b, e, f, d]) return AdditiveCyclic(19), Mb + def QDM_21_5_1_1_1(): r""" Return a `(21,5;1,1;1)`-quasi-difference matrix. @@ -2122,7 +2123,7 @@ def QDM_21_5_1_1_1(): [ 12, 9, 19, 16, 5, 2, 0], ] - Mb=[[0,7,14,None,0], + Mb = [[0,7,14,None,0], [0,14,7,0,None]] for R in zip(*M): @@ -2170,7 +2171,7 @@ def QDM_21_6_1_1_5(): from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(21) - Mb=[[0,0,0,0,0,0]] + Mb = [[0,0,0,0,0,0]] for R in zip(*M): a,b,c,d,e,f = R @@ -2195,8 +2196,8 @@ def QDM_25_6_1_1_5(): sage: from sage.combinat.designs.database import QDM_25_6_1_1_5 sage: from sage.combinat.designs.designs_pyx import is_quasi_difference_matrix - sage: G,M = QDM_25_6_1_1_5() - sage: is_quasi_difference_matrix(M,G,6,1,1,5) + sage: G,M = QDM_25_6_1_1_5() # needs sage.modules + sage: is_quasi_difference_matrix(M,G,6,1,1,5) # needs sage.modules True """ M = [ @@ -2213,7 +2214,7 @@ def QDM_25_6_1_1_5(): G = AdditiveAbelianGroup([5,5]) M = [[None if x is None else G(vector(x)) for x in L] for L in M] - Mb=[] + Mb = [] for R in zip(*M): a,b,c,d,e,f = R @@ -2299,7 +2300,7 @@ def QDM_37_6_1_1_1(): from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(37) - Mb=[] + Mb = [] for R in zip(*M): a,b,c,d,e,f = R @@ -2338,7 +2339,7 @@ def QDM_35_7_1_1_7(): from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(35) - Mb=[] + Mb = [] for R in zip(*M): for i in range(7): @@ -2375,7 +2376,7 @@ def QDM_45_7_1_1_9(): [ 30, 16, 33, 27, -30, -16, -33, -27, 0], ] - Mb=[] + Mb = [] for R in zip(*M): for c in range(7): @@ -2412,7 +2413,7 @@ def QDM_54_7_1_1_8(): [41 , 11 , 1 , 17 , -41 , -11 , - 1 , -17, 28 , 11 ] ] - Mb=[] + Mb = [] for R in zip(*M): for c in range(7): @@ -2432,8 +2433,8 @@ def QDM_57_9_1_1_8(): sage: from sage.combinat.designs.database import QDM_57_9_1_1_8 sage: from sage.combinat.designs.designs_pyx import is_quasi_difference_matrix - sage: G,M = QDM_57_9_1_1_8() - sage: is_quasi_difference_matrix(M,G,9,1,1,8) + sage: G,M = QDM_57_9_1_1_8() # needs sage.schemes + sage: is_quasi_difference_matrix(M,G,9,1,1,8) # needs sage.schemes True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as G @@ -2457,6 +2458,7 @@ def QDM_57_9_1_1_8(): # } # } + QDM: dict[tuple[int, int], dict] = {} for ((n,k,lmbda,mu,u),f) in [((19,6,1,1,1), QDM_19_6_1_1_1), ((21,5,1,1,1), QDM_21_5_1_1_1), @@ -2719,7 +2721,7 @@ def QDM_57_9_1_1_8(): sage: from sage.combinat.designs.designs_pyx import is_quasi_difference_matrix sage: from sage.combinat.designs.orthogonal_arrays import QDM_from_Vmt sage: from sage.combinat.designs.database import Vmt_vectors - sage: for (m,t),(vec,source) in sorted(Vmt_vectors.items()): + sage: for (m,t),(vec,source) in sorted(Vmt_vectors.items()): # needs sage.rings.finite_rings ....: G,M = QDM_from_Vmt(m,t,vec) ....: if m*t < 600: ....: assert is_quasi_difference_matrix(M,G,m+2,1,1,t,verbose=1),(m,t) @@ -3190,7 +3192,7 @@ def DM_21_6_1(): Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(21,6) + sage: _ = designs.difference_matrix(21,6) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic M = [[ 8, 17, 20, 2], @@ -3227,19 +3229,19 @@ def DM_24_8_1(): sage: _ = designs.difference_matrix(24,8) """ - M = ("0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "+ - "0000 0010 0100 0110 1000 1010 1100 1110 2000 2010 2100 2110 "+ - "0000 0011 1001 2110 0111 2011 2111 1000 0100 1100 1101 2010 "+ - "0000 1010 1011 2000 1101 2110 0001 0101 2100 2001 0111 1100 "+ - "0000 0001 2010 1111 2111 2100 1101 0011 1010 2101 1000 0110 "+ - "0000 1000 2001 1011 0100 1100 0110 2101 2111 0010 1111 2011 "+ - "0000 1001 0111 2100 2000 0010 1110 2011 1100 1011 0101 2111 "+ + M = ("0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + + "0000 0010 0100 0110 1000 1010 1100 1110 2000 2010 2100 2110 " + + "0000 0011 1001 2110 0111 2011 2111 1000 0100 1100 1101 2010 " + + "0000 1010 1011 2000 1101 2110 0001 0101 2100 2001 0111 1100 " + + "0000 0001 2010 1111 2111 2100 1101 0011 1010 2101 1000 0110 " + + "0000 1000 2001 1011 0100 1100 0110 2101 2111 0010 1111 2011 " + + "0000 1001 0111 2100 2000 0010 1110 2011 1100 1011 0101 2111 " + "0000 1011 2101 0100 2110 1001 2000 0110 0101 1111 2011 1010 ") from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic from sage.categories.cartesian_product import cartesian_product G = cartesian_product([AdditiveCyclic(_) for _ in [2, 2, 6]]) - rlabel = {(x%2,x%3):x for x in range(6)} + rlabel = {(x % 2,x % 3):x for x in range(6)} M = [G([int(c),int(d),rlabel[int(b),int(a)]]) for a,b,c,d in M.split()] M = [M[i*12:(i+1)*12] for i in range(8)] Mb = [] @@ -3266,15 +3268,15 @@ def DM_28_6_1(): sage: from sage.combinat.designs.designs_pyx import is_difference_matrix sage: from sage.combinat.designs.database import DM_28_6_1 - sage: G,M = DM_28_6_1() - sage: is_difference_matrix(M,G,6,1) + sage: G,M = DM_28_6_1() # needs sage.modules + sage: is_difference_matrix(M,G,6,1) # needs sage.modules True Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(28,6) + sage: _ = designs.difference_matrix(28,6) # needs sage.modules """ - z=2 + z = 2 M = [ [(0,0), (z+1,6),(1,1) ,(1,1) ,(1,3) ,(1,4) ,(0,0) ,(1,4), (z,5) ], [(z,2), (0,0) ,(1,5) ,(z,1) ,(z,2) ,(z,6) ,(z+1,3),(0,0), (z,1) ], @@ -3287,9 +3289,9 @@ def DM_28_6_1(): from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup from sage.modules.free_module_element import free_module_element as vector G = AdditiveAbelianGroup([2,2,7]) - M = [[G(vector([x//2,x%2,y])) for x,y in L] for L in M] + M = [[G(vector([x//2,x % 2,y])) for x,y in L] for L in M] - Mb=[[0,0,0,0,0,0]] + Mb = [[0,0,0,0,0,0]] for R in zip(*M): a,b,c,d,e,f = R @@ -3315,7 +3317,7 @@ def DM_33_6_1(): Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(33,6) + sage: _ = designs.difference_matrix(33,6) # needs sage.rings.finite_rings """ M = [ [ 0, 0, 0, 0, 0, 0], @@ -3357,7 +3359,7 @@ def DM_35_6_1(): Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(35,6) + sage: _ = designs.difference_matrix(35,6) # needs sage.rings.finite_rings """ M = [ [ 0, 15, 30, 10, 25, 1, 16, 31, 11, 26, 2, 17, 32, 12, 6, 3, 18, 33, 27, 21, 4, 19, 13, 7, 22, 5, 34, 28, 8, 23, 20, 14, 29, 9, 24], @@ -3383,13 +3385,13 @@ def DM_36_9_1(): sage: from sage.combinat.designs.designs_pyx import is_difference_matrix sage: from sage.combinat.designs.database import DM_36_9_1 - sage: G,M = DM_36_9_1() - sage: is_difference_matrix(M,G,9,1) + sage: G,M = DM_36_9_1() # needs sage.modules + sage: is_difference_matrix(M,G,9,1) # needs sage.modules True Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(36,9) + sage: _ = designs.difference_matrix(36,9) # needs sage.modules """ M = [ [(0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0)], @@ -3408,7 +3410,7 @@ def DM_36_9_1(): G = AdditiveAbelianGroup([2,2,3,3]) M = [[G(vector(x)) for x in L] for L in M] - Mb=[] + Mb = [] for R in zip(*M): a,b,c,d,e,f,g,h,i = R @@ -3442,7 +3444,7 @@ def DM_39_6_1(): The design is available from the general constructor:: - sage: designs.difference_matrix(39,6,existence=True) + sage: designs.difference_matrix(39,6,existence=True) # needs sage.rings.finite_rings True """ M = [ @@ -3457,7 +3459,7 @@ def DM_39_6_1(): from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(39) - Mb=[[ 0, 0, 0, 0, 0, 0], + Mb = [[ 0, 0, 0, 0, 0, 0], [ 1, 16, 22, 17, 38, 23], [-1,-16,-22,-17,-38,-23]] @@ -3506,7 +3508,7 @@ def DM_44_6_1(): M = [[G2211(x) for x in L] for L in M] - Mb=[] + Mb = [] for R in zip(*M): for c in range(5): @@ -3548,7 +3550,7 @@ def DM_45_7_1(): Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(45,7) + sage: _ = designs.difference_matrix(45,7) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.categories.cartesian_product import cartesian_product @@ -3570,7 +3572,7 @@ def DM_45_7_1(): M[6].extend(M[6][1:8]) - Mb=[] + Mb = [] for R in zip(*M): (x1,y1,z1),(x2,y2,z2),(x3,y3,z3),(x4,y4,z4),(x5,y5,z5),(x6,y6,z6),(x7,y7,z7) = R @@ -3595,13 +3597,13 @@ def DM_48_9_1(): sage: from sage.combinat.designs.designs_pyx import is_difference_matrix sage: from sage.combinat.designs.database import DM_48_9_1 - sage: G,M = DM_48_9_1() - sage: is_difference_matrix(M,G,9,1) + sage: G,M = DM_48_9_1() # needs sage.rings.finite_rings + sage: is_difference_matrix(M,G,9,1) # needs sage.rings.finite_rings True Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(48,9) + sage: _ = designs.difference_matrix(48,9) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.finite_field_constructor import FiniteField F16 = FiniteField(16,'x') @@ -3650,7 +3652,7 @@ def DM_51_6_1(): Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(51,6) + sage: _ = designs.difference_matrix(51,6) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(51) @@ -3663,7 +3665,7 @@ def DM_51_6_1(): [ 34, 32, 36, 26, 20] ] - Mb=[[0,0,0,0,0]] + Mb = [[0,0,0,0,0]] for R in zip(*M): for i in range(5): @@ -3686,16 +3688,16 @@ def DM_52_6_1(): sage: from sage.combinat.designs.designs_pyx import is_difference_matrix sage: from sage.combinat.designs.database import DM_52_6_1 - sage: G,M = DM_52_6_1() - sage: is_difference_matrix(M,G,6,1) + sage: G,M = DM_52_6_1() # needs sage.rings.finite_rings + sage: is_difference_matrix(M,G,6,1) # needs sage.rings.finite_rings True Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(52,6) + sage: _ = designs.difference_matrix(52,6) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - F4 = FiniteField(4,'z') + F4 = FiniteField(4,'z') G13 = FiniteField(13) G = F4.cartesian_product(G13) z = F4('z') @@ -3720,9 +3722,9 @@ def DM_52_6_1(): ] M = [[G(x) for x in L] for L in M] - M2= [[G(x) for x in L] for L in M2] + M2 = [[G(x) for x in L] for L in M2] - Mb=[[(0,0)]*6] + Mb = [[(0,0)]*6] from itertools import product @@ -3764,7 +3766,7 @@ def DM_55_7_1(): Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(55,7) + sage: _ = designs.difference_matrix(55,7) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(55) @@ -3778,7 +3780,7 @@ def DM_55_7_1(): [ 16 , 49 , 47 , 29 , 31 , 4 , 44 , 21 , 18] ] - Mb=[[0,0,0,0,0,0,0]] + Mb = [[0,0,0,0,0,0,0]] for R in zip(*M): R = list(R) @@ -3797,18 +3799,18 @@ def DM_56_8_1(): sage: from sage.combinat.designs.designs_pyx import is_difference_matrix sage: from sage.combinat.designs.database import DM_56_8_1 - sage: G,M = DM_56_8_1() - sage: is_difference_matrix(M,G,8,1) + sage: G,M = DM_56_8_1() # needs sage.rings.finite_rings + sage: is_difference_matrix(M,G,8,1) # needs sage.rings.finite_rings True Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(56,8) + sage: _ = designs.difference_matrix(56,8) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - F8 = FiniteField(8,'z') - F7 = FiniteField(7) - G = F8.cartesian_product(F7) + F8 = FiniteField(8,'z') + F7 = FiniteField(7) + G = F8.cartesian_product(F7) w = F8.primitive_element() assert w**3 == w+1 @@ -3824,7 +3826,7 @@ def DM_56_8_1(): [(1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0)] ] - Mb=[] + Mb = [] for R in zip(*M): for _ in range(7): @@ -3844,16 +3846,16 @@ def DM_57_8_1(): sage: from sage.combinat.designs.designs_pyx import is_difference_matrix sage: from sage.combinat.designs.database import DM_57_8_1 - sage: G,M = DM_57_8_1() - sage: is_difference_matrix(M,G,8,1) + sage: G,M = DM_57_8_1() # needs sage.rings.finite_rings + sage: is_difference_matrix(M,G,8,1) # needs sage.rings.finite_rings True Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(57,8) + sage: _ = designs.difference_matrix(57,8) # needs sage.rings.finite_rings """ M = orthogonal_array(8,8) - M = [R for R in M if any(x!=R[0] for x in R)] # removing the 0..0, 1..1, 7..7 rows. + M = [R for R in M if any(x != R[0] for x in R)] # removing the 0..0, 1..1, 7..7 rows. B = (1,6,7,9,19,38,42,49) # base block of a (57,8,1) BIBD M = [[B[x] for x in R] for R in M] M.append([0]*8) @@ -3900,7 +3902,7 @@ def DM_60_6_1(): from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic from sage.categories.cartesian_product import cartesian_product G = cartesian_product((AdditiveCyclic(2),AdditiveCyclic(30))) - M60b=[] + M60b = [] onezero = G((1,0)) for R in zip(*M60): @@ -3930,14 +3932,14 @@ def DM_75_8_1(): Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(75,8) + sage: _ = designs.difference_matrix(75,8) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.categories.cartesian_product import cartesian_product F3 = FiniteField(3) F5 = FiniteField(5) - G = cartesian_product((F3,F5,F5)) + G = cartesian_product((F3,F5,F5)) M = [ [(2,0,0), (0,0,0), (0,0,0), (1,0,0), (0,0,0), (1,0,0), (1,0,0), (0,0,0)], @@ -3953,7 +3955,7 @@ def DM_75_8_1(): for i in range(8): M[i].extend(M[7-i][:7]) - Mb=[] + Mb = [] for R in zip(*M): for x in range(5): @@ -3972,16 +3974,16 @@ def DM_273_17_1(): sage: from sage.combinat.designs.designs_pyx import is_difference_matrix sage: from sage.combinat.designs.database import DM_273_17_1 - sage: G,M = DM_273_17_1() - sage: is_difference_matrix(M,G,17,1) + sage: G,M = DM_273_17_1() # needs sage.schemes + sage: is_difference_matrix(M,G,17,1) # needs sage.schemes True Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(273,17) + sage: _ = designs.difference_matrix(273,17) # needs sage.schemes """ M = orthogonal_array(17,17) - M = [R for R in M if any(x!=R[0] for x in R)] # removing the 0..0, 1..1, ... rows. + M = [R for R in M if any(x != R[0] for x in R)] # removing the 0..0, 1..1, ... rows. B = (1,2,4,8,16,32,64,91,117,128,137,182,195,205,234,239,256) # (273,17,1) difference set M = [[B[x] for x in R] for R in M] M.append([0]*17) @@ -4000,16 +4002,16 @@ def DM_993_32_1(): sage: from sage.combinat.designs.designs_pyx import is_difference_matrix sage: from sage.combinat.designs.database import DM_993_32_1 - sage: G,M = DM_993_32_1() - sage: is_difference_matrix(M,G,32,1) + sage: G,M = DM_993_32_1() # needs sage.schemes + sage: is_difference_matrix(M,G,32,1) # needs sage.schemes True Can be obtained from the constructor:: - sage: _ = designs.difference_matrix(993,32) + sage: _ = designs.difference_matrix(993,32) # needs sage.schemes """ M = orthogonal_array(32,32) - M = [R for R in M if any(x!=R[0] for x in R)] # removing the 0..0, 1..1, ... rows. + M = [R for R in M if any(x != R[0] for x in R)] # removing the 0..0, 1..1, ... rows. B = (0,74,81,126,254,282,308,331,344,375,387,409,525,563, # (993,32,1) difference set 572,611,631,661,694,702,734,763,798,809,814,851,906, 908,909,923,927,933) @@ -4020,6 +4022,7 @@ def DM_993_32_1(): G = AdditiveCyclic(993) return G, M + DM = { (12 ,1) : (6 ,DM_12_6_1), (21 ,1) : (6 ,DM_21_6_1), @@ -4045,7 +4048,7 @@ def DM_993_32_1(): # Create the list of DM for the documentation _all_l = sorted(set(l for v,l in DM.keys())) -LIST_OF_DM = "\n".join(r" - `\lambda={}`:\n ".format(l)+ +LIST_OF_DM = "\n".join(r" - `\lambda={}`:\n ".format(l) + ", ".join("`({},{},{})`".format(v,k,l) for (v,_),(k,__) in sorted(DM.items()) if _ == l) for l in _all_l) @@ -4081,26 +4084,26 @@ def RBIBD_120_8_1(): sage: from sage.combinat.designs.database import RBIBD_120_8_1 sage: from sage.combinat.designs.bibd import is_pairwise_balanced_design - sage: RBIBD = RBIBD_120_8_1() - sage: is_pairwise_balanced_design(RBIBD,120,[8]) + sage: RBIBD = RBIBD_120_8_1() # needs sage.modules + sage: is_pairwise_balanced_design(RBIBD,120,[8]) # needs sage.modules True It is indeed resolvable, and the parallel classes are given by 17 slices of consecutive 15 blocks:: - sage: for i in range(17): + sage: for i in range(17): # needs sage.modules ....: assert len(set(sum(RBIBD[i*15:(i+1)*15],[]))) == 120 The BIBD is available from the constructor:: - sage: _ = designs.balanced_incomplete_block_design(120,8) + sage: _ = designs.balanced_incomplete_block_design(120,8) # needs sage.modules """ from .incidence_structures import IncidenceStructure - n=273 + n = 273 # Base block of a cyclic BIBD(273,16,1) B = [1,2,4,8,16,32,64,91,117,128,137,182,195,205,234,239,256] - BIBD = [[(x+c)%n for x in B] for c in range(n)] + BIBD = [[(x+c) % n for x in B] for c in range(n)] # A (precomputed) set that every block of the BIBD intersects on 0 or 2 points hyperoval = [128, 192, 194, 4, 262, 140, 175, 48, 81, 180, 245, 271, 119, 212, 249, 189, 62, 255] @@ -4122,7 +4125,7 @@ def RBIBD_120_8_1(): BIBD = new_BIBD r = {v:i for i,v in enumerate(x for x in range(n) if x not in hyperoval)} - BIBD = [[r[x] for x in B] for B in BIBD ] + BIBD = [[r[x] for x in B] for B in BIBD ] equiv = [[r[x] for x in B] for B in equiv] BIBD = IncidenceStructure(range(255),BIBD) @@ -4149,15 +4152,15 @@ def BIBD_45_9_8(from_code=False): sage: from sage.combinat.designs.database import BIBD_45_9_8 sage: from sage.combinat.designs.bibd import BalancedIncompleteBlockDesign - sage: B = BalancedIncompleteBlockDesign(45, BIBD_45_9_8(),lambd=8); B + sage: B = BalancedIncompleteBlockDesign(45, BIBD_45_9_8(), lambd=8); B (45,9,8)-Balanced Incomplete Block Design TESTS: From the definition (takes around 12s):: - sage: B2 = Hypergraph(BIBD_45_9_8(from_code=True)) # not tested - sage: B2.is_isomorphic(B) # not tested + sage: B2 = Hypergraph(BIBD_45_9_8(from_code=True)) # not tested # needs sage.rings.finite_rings + sage: B2.is_isomorphic(B) # not tested # needs sage.rings.finite_rings True REFERENCE: @@ -4174,7 +4177,7 @@ def BIBD_45_9_8(from_code=False): C = ExtendedQuadraticResidueCode(47,FiniteField(2)) min_weight = [map(int,x)[3:] for x in C if x.hamming_weight() == 12 and - x[0]==1 and x[1]==1 and x[2]==1] + x[0] == 1 and x[1] == 1 and x[2] == 1] return [[i for i,v in enumerate(x) if v] for x in min_weight] @@ -4224,7 +4227,7 @@ def BIBD_66_6_1(): sage: BalancedIncompleteBlockDesign(66, BIBD_66_6_1()) (66,6,1)-Balanced Incomplete Block Design """ - BIBD = [frozenset([(x+i*5)%65 if x<65 else x for x in b]) + BIBD = [frozenset([(x+i*5) % 65 if x < 65 else x for x in b]) for i in range(65) for b in [[6, 38, 42, 46, 53, 62], [9, 11, 21, 49, 56, 60], [18, 31, 37, 44, 52, 60], @@ -4248,7 +4251,7 @@ def BIBD_76_6_1(): sage: BalancedIncompleteBlockDesign(76, BIBD_76_6_1()) (76,6,1)-Balanced Incomplete Block Design """ - BIBD = [frozenset([(x+i*4)%76 if x<76 else x for x in b]) + BIBD = [frozenset([(x+i*4) % 76 if x < 76 else x for x in b]) for i in range(76) for b in [[3, 5, 21, 33, 72, 73], [4, 37, 57, 58, 64, 75], [7, 14, 44, 47, 59, 63], @@ -4272,7 +4275,7 @@ def BIBD_96_6_1(): sage: BalancedIncompleteBlockDesign(96, BIBD_96_6_1()) (96,6,1)-Balanced Incomplete Block Design """ - BIBD = [frozenset([(x+i*2)%96 if x<96 else x for x in b]) + BIBD = [frozenset([(x+i*2) % 96 if x < 96 else x for x in b]) for i in range(96) for b in [[3, 13, 32, 47, 68, 87], [9, 36, 70, 75, 81, 88], [22, 52, 72, 76, 78, 79], @@ -4302,7 +4305,7 @@ def BIBD_106_6_1(): ((0,0), ( 2,1), ( 7,1), (25,1), (29,1), (49,1)), ((0,0), ( 9,0), (21,0), (12,1), (13,1), (27,1))] - return [[((x+i)%53+y*53) for x,y in B] for i in range(53) for B in bibd] + return [[((x+i) % 53+y*53) for x,y in B] for i in range(53) for B in bibd] def BIBD_111_6_1(): r""" @@ -4319,18 +4322,22 @@ def BIBD_111_6_1(): """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from .incidence_structures import IncidenceStructure - bibd = [(( 0,0), ( 1,0), ( 3,0), ( 7,0), (17,0), ( 0,1)), - (( 0,0), ( 5,0), (19,1), (28,1), (10,2), (30,2)), - (( 5,0), (33,0), (13,1), (34,1), (19,2), ( 7,2)), - (( 9,0), (27,0), (16,1), (11,1), (12,2), (36,2)), - ((10,0), (23,0), (26,1), ( 8,1), ( 1,2), ( 6,2)), - ((13,0), (24,0), (19,1), (18,1), ( 5,2), (32,2)), - ((26,0), (34,0), ( 1,1), ( 7,1), (10,2), (33,2))] - gens = lambda B: [frozenset(((x*10)%37,(y+1)%3) for x,y in B), - frozenset(((x+1) %37, y) for x,y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) + bibd = [(( 0, 0), ( 1, 0), ( 3, 0), ( 7, 0), (17, 0), ( 0, 1)), + (( 0, 0), ( 5, 0), (19, 1), (28, 1), (10, 2), (30, 2)), + (( 5, 0), (33, 0), (13, 1), (34, 1), (19, 2), ( 7, 2)), + (( 9, 0), (27, 0), (16, 1), (11, 1), (12, 2), (36, 2)), + ((10, 0), (23, 0), (26, 1), ( 8, 1), ( 1, 2), ( 6, 2)), + ((13, 0), (24, 0), (19, 1), (18, 1), ( 5, 2), (32, 2)), + ((26, 0), (34, 0), ( 1, 1), ( 7, 1), (10, 2), (33, 2))] + gens = lambda B: [frozenset(((x * 10) % 37, (y + 1) % 3) + for x, y in B), + frozenset(((x + 1) % 37, y) + for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], + successors=gens) return IncidenceStructure(bibd)._blocks + def BIBD_126_6_1(): r""" Return a (126,6,1)-BIBD. @@ -4345,7 +4352,7 @@ def BIBD_126_6_1(): (126,6,1)-Balanced Incomplete Block Design """ from itertools import product - bibd = [[((x+xx)%5, (y+yy)%5, (z+zz)%5) for x,y,z in B] + bibd = [[((x+xx) % 5, (y+yy) % 5, (z+zz) % 5) for x,y,z in B] for xx,yy,zz in product(range(5),repeat=3) for B in [[(0,0,1),(0,0,4),(1,2,2),(1,3,3),(4,2,1),(4,3,4)], @@ -4373,16 +4380,19 @@ def BIBD_136_6_1(): """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from .incidence_structures import IncidenceStructure - inf=(None,None) + inf = (None,None) bibd = [((0,0), ( 3,0), (15,0), (35,0), ( 6,2), (10,2)), ((0,0), (22,0), (11,1), (30,1), ( 1,2), (18,2)), ((0,0), ( 5,0), (18,1), (41,1), (13,2), (42,2)), ((0,0), (11,0), (17,0), ( 4,2), ( 5,2), (28,2)), ((0,0), ( 1,0), ( 0,1), (16,1), ( 0,2), (31,2)), ( inf ,( 0,0), ( 9,0), (18,0), (27,0), (36,0))] - gens = lambda B: [frozenset(((x*16)%45,(y+1)%3) if (x,y)!=inf else inf for x,y in B), - frozenset(((x+1) %45,y) if (x,y)!=inf else inf for x,y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) + gens = lambda B: [frozenset(((x * 16) % 45,(y + 1) % 3) + if (x, y) != inf else inf for x, y in B), + frozenset(((x + 1) % 45,y) + if (x, y) != inf else inf for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], + successors=gens) return IncidenceStructure(bibd)._blocks @@ -4412,11 +4422,15 @@ def BIBD_141_6_1(): ( inf ,( 0,0), ( 7,0), (14,0), (21,0), (28,0)), ( inf ,( 0,a), ( 7,a), (14,a), (21,a), (28,a))] - gens = lambda B: [frozenset(((x*16)%35,(y+1)%3 if y!=a else a) if (x,y)!=inf else inf for x,y in B), - frozenset(((x+1) %35, y ) if (x,y)!=inf else inf for x,y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) + gens = lambda B: [frozenset(((x * 16) % 35, (y + 1) % 3 if y != a else a) + if (x, y) != inf else inf for x, y in B), + frozenset(((x + 1) % 35, y) + if (x, y) != inf else inf for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], + successors=gens) return IncidenceStructure(bibd)._blocks + def BIBD_171_6_1(): r""" Return a (171,6,1)-BIBD. @@ -4440,11 +4454,15 @@ def BIBD_171_6_1(): (( 0,0), (12,0), ( 0,1), (27,1), ( 0,2), (18,2)), ((37,0), (42,0), (31,1), ( 9,1), (46,2), ( 6,2))] - gens = lambda B: [frozenset(((x*7) %57,(y+1)%3) for x,y in B), - frozenset(((x+1) %57, y) for x,y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) + gens = lambda B: [frozenset(((x * 7) % 57, (y + 1) % 3) + for x, y in B), + frozenset(((x + 1) % 57, y) + for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], + successors=gens) return IncidenceStructure(bibd)._blocks + def HigmanSimsDesign(): r""" Return the Higman-Sims designs, which is a `(176, 50, 14)`-BIBD. @@ -4466,9 +4484,9 @@ def HigmanSimsDesign(): EXAMPLES:: - sage: H = designs.HigmanSimsDesign(); H # optional - gap_packages + sage: H = designs.HigmanSimsDesign(); H # optional - gap_package_design Incidence structure with 176 points and 176 blocks - sage: H.is_t_design(return_parameters=1) # optional - gap_packages + sage: H.is_t_design(return_parameters=1) # optional - gap_package_design (True, (2, 176, 50, 14)) Make sure that the automorphism group of this designs is isomorphic to the @@ -4477,9 +4495,9 @@ def HigmanSimsDesign(): first of those permutation groups acts on 176 points, while the second acts on 100:: - sage: gH = H.automorphism_group() # optional - gap_packages - sage: gG = graphs.HigmanSimsGraph().automorphism_group() # optional - gap_packages - sage: gG.is_isomorphic(gG) # long time # optional - gap_packages + sage: gH = H.automorphism_group() # optional - gap_package_design + sage: gG = graphs.HigmanSimsGraph().automorphism_group() # optional - gap_package_design + sage: gG.is_isomorphic(gG) # long time, optional - gap_package_design True REFERENCE: @@ -4533,11 +4551,15 @@ def BIBD_196_6_1(): ((0,0), ( 1,0), ( 0,1), (30,1), ( 0,2), (18,2)), ((8,0), (19,0), (44,1), (31,1), (46,2), (48,2))] - gens = lambda B: [frozenset(((x*30)%49,(y+1)%3 if y!=a else a) for x,y in B), - frozenset(((x+1) %49, y) for x,y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) + gens = lambda B: [frozenset(((x * 30) % 49, (y + 1) % 3 if y != a else a) + for x, y in B), + frozenset(((x + 1) % 49, y) + for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], + successors=gens) return IncidenceStructure(bibd)._blocks + def BIBD_201_6_1(): r""" Return a (201,6,1)-BIBD. @@ -4562,11 +4584,15 @@ def BIBD_201_6_1(): ((3,1), (20,1), (44,1), (36,2), (39,2), (59,2)), ((0,0), ( 0,1), (30,1), (38,1), (66,1), ( 0,2))] - gens = lambda B: [frozenset(((x*29)%67,y) for x,y in B), - frozenset(((x+1) %67,y) for x,y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) + gens = lambda B: [frozenset(((x * 29) % 67, y) + for x, y in B), + frozenset(((x + 1) % 67, y) + for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], + successors=gens) return IncidenceStructure(bibd)._blocks + def BIBD_79_13_2(): r""" Return a symmetric `(79,13,2)`-BIBD. @@ -4581,8 +4607,8 @@ def BIBD_79_13_2(): EXAMPLES: sage: from sage.combinat.designs.database import BIBD_79_13_2 - sage: D = IncidenceStructure(BIBD_79_13_2()) - sage: D.is_t_design(t=2, v=79, k=13, l=2) + sage: D = IncidenceStructure(BIBD_79_13_2()) # needs sage.libs.gap + sage: D.is_t_design(t=2, v=79, k=13, l=2) # needs sage.libs.gap True """ from sage.libs.gap.libgap import libgap @@ -4659,8 +4685,8 @@ def BIBD_56_11_2(): EXAMPLES: sage: from sage.combinat.designs.database import BIBD_56_11_2 - sage: D = IncidenceStructure(BIBD_56_11_2()) - sage: D.is_t_design(t=2, v=56, k=11, l=2) + sage: D = IncidenceStructure(BIBD_56_11_2()) # needs sage.libs.gap + sage: D.is_t_design(t=2, v=56, k=11, l=2) # needs sage.libs.gap True """ from sage.libs.gap.libgap import libgap @@ -4688,6 +4714,7 @@ def BIBD_56_11_2(): D = IncidenceStructure(libgap.Orbit(G, B, libgap.OnSets)) return D._blocks + # Index of the BIBD constructions # # Associates to triple (v,k,lambda) a function that return a @@ -4740,7 +4767,7 @@ def BIBD_56_11_2(): R = PolynomialRing(ZZ,'a') a = R.gen() -EDS={ +EDS = { 4:{ 13: (None, [0, 1, 11, 5]), 25: (a**2 + 4*a + 2, [0, 1, a, 3*a + 4]), @@ -5009,13 +5036,13 @@ def BIBD_56_11_2(): for k in sorted(EDS)) __doc__ = __doc__.format( - LIST_OF_OA_CONSTRUCTIONS = LIST_OF_OA_CONSTRUCTIONS, - LIST_OF_MOLS_CONSTRUCTIONS = LIST_OF_MOLS_CONSTRUCTIONS, - LIST_OF_VMT_VECTORS = LIST_OF_VMT_VECTORS, - LIST_OF_BIBD = LIST_OF_BIBD, - LIST_OF_DF = LIST_OF_DF, - LIST_OF_DM = LIST_OF_DM, - LIST_OF_QDM = LIST_OF_QDM, - LIST_OF_EDS = LIST_OF_EDS) + LIST_OF_OA_CONSTRUCTIONS=LIST_OF_OA_CONSTRUCTIONS, + LIST_OF_MOLS_CONSTRUCTIONS=LIST_OF_MOLS_CONSTRUCTIONS, + LIST_OF_VMT_VECTORS=LIST_OF_VMT_VECTORS, + LIST_OF_BIBD=LIST_OF_BIBD, + LIST_OF_DF=LIST_OF_DF, + LIST_OF_DM=LIST_OF_DM, + LIST_OF_QDM=LIST_OF_QDM, + LIST_OF_EDS=LIST_OF_EDS) del LIST_OF_OA_CONSTRUCTIONS, LIST_OF_MOLS_CONSTRUCTIONS, LIST_OF_VMT_VECTORS,LIST_OF_DF, LIST_OF_DM, LIST_OF_QDM, LIST_OF_EDS, LIST_OF_BIBD del PolynomialRing, ZZ, a, diff --git a/src/sage/combinat/designs/design_catalog.py b/src/sage/combinat/designs/design_catalog.py index a9572e119c0..8bf7f14fd0b 100644 --- a/src/sage/combinat/designs/design_catalog.py +++ b/src/sage/combinat/designs/design_catalog.py @@ -4,7 +4,7 @@ This module gathers all designs that can be reached through ``designs.<tab>``. Example with the Witt design on 24 points:: - sage: designs.WittDesign(24) # optional - gap_packages + sage: designs.WittDesign(24) # optional - gap_package_design Incidence structure with 24 points and 759 blocks Or a Steiner Triple System on 19 points:: diff --git a/src/sage/combinat/designs/designs_pyx.pyx b/src/sage/combinat/designs/designs_pyx.pyx index c72baf64b6b..565b7d83184 100644 --- a/src/sage/combinat/designs/designs_pyx.pyx +++ b/src/sage/combinat/designs/designs_pyx.pyx @@ -36,6 +36,7 @@ def is_orthogonal_array(OA, int k, int n, int t=2, verbose=False, terminology="O EXAMPLES:: + sage: # needs sage.schemes sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array sage: OA = designs.orthogonal_arrays.build(8,9) sage: is_orthogonal_array(OA,8,9) @@ -48,26 +49,27 @@ def is_orthogonal_array(OA, int k, int n, int t=2, verbose=False, terminology="O sage: is_orthogonal_array(OA,8,9,verbose=True) Columns 0 and 3 are not orthogonal False - sage: is_orthogonal_array(OA,8,9,verbose=True,terminology="MOLS") + sage: is_orthogonal_array(OA,8,9, verbose=True, terminology="MOLS") Squares 0 and 3 are not orthogonal False TESTS:: - sage: is_orthogonal_array(OA,8,9,t=3) + sage: # needs sage.schemes + sage: is_orthogonal_array(OA,8,9, t=3) Traceback (most recent call last): ... NotImplementedError: only implemented for t=2 - sage: is_orthogonal_array([[3]*8],8,9,verbose=True) + sage: is_orthogonal_array([[3]*8],8,9, verbose=True) The number of rows is 1 instead of 9^2=81 False - sage: is_orthogonal_array([[3]*8],8,9,verbose=True,terminology="MOLS") + sage: is_orthogonal_array([[3]*8],8,9, verbose=True, terminology="MOLS") All squares do not have dimension n^2=9^2 False - sage: is_orthogonal_array([[3]*7],8,9,verbose=True) + sage: is_orthogonal_array([[3]*7],8,9, verbose=True) Some row does not have length 8 False - sage: is_orthogonal_array([[3]*7],8,9,verbose=True,terminology="MOLS") + sage: is_orthogonal_array([[3]*7],8,9, verbose=True, terminology="MOLS") The number of squares is not 6 False @@ -77,7 +79,7 @@ def is_orthogonal_array(OA, int k, int n, int t=2, verbose=False, terminology="O sage: from itertools import product sage: n = 0 - sage: for a in product(product((0,1), repeat=3), repeat=4): + sage: for a in product(product((0,1), repeat=3), repeat=4): # needs sage.schemes ....: if is_orthogonal_array(a,3,2): ....: n += 1 sage: n @@ -183,16 +185,16 @@ def is_group_divisible_design(groups,blocks,v,G=None,K=None,lambd=1,verbose=Fals EXAMPLES:: sage: from sage.combinat.designs.designs_pyx import is_group_divisible_design - sage: TD = designs.transversal_design(4,10) + sage: TD = designs.transversal_design(4,10) # needs sage.modules sage: groups = [list(range(i*10,(i+1)*10)) for i in range(4)] - sage: is_group_divisible_design(groups,TD,40,lambd=1) + sage: is_group_divisible_design(groups,TD,40,lambd=1) # needs sage.modules True TESTS:: - sage: TD = designs.transversal_design(4,10) + sage: TD = designs.transversal_design(4,10) # needs sage.modules sage: groups = [list(range(i*10,(i+1)*10)) for i in range(4)] - sage: is_group_divisible_design(groups,TD,40,lambd=2,verbose=True) + sage: is_group_divisible_design(groups, TD, 40, lambd=2, verbose=True) # needs sage.modules the pair (0,10) has been seen 1 times but lambda=2 False sage: is_group_divisible_design([[1,2],[3,4]],[[1,2]],40,lambd=1,verbose=True) @@ -214,6 +216,7 @@ def is_group_divisible_design(groups,blocks,v,G=None,K=None,lambd=1,verbose=Fals a block has size 2 while K=[1] False + sage: # needs sage.schemes sage: p = designs.projective_plane(3) sage: is_group_divisible_design(None, p.blocks(), 13) (True, [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12]]) @@ -224,7 +227,7 @@ def is_group_divisible_design(groups,blocks,v,G=None,K=None,lambd=1,verbose=Fals (True, [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12]]) """ cdef int n = v - cdef int i,ii,j,jj,s,isok + cdef int i,ii,j,jj,s cdef int l = lambd cdef bint guess_groups = groups is None @@ -362,24 +365,24 @@ def is_pairwise_balanced_design(blocks,v,K=None,lambd=1,verbose=False): sage: sts = designs.steiner_triple_system(9) sage: is_pairwise_balanced_design(sts,9,[3],1) True - sage: TD = designs.transversal_design(4,10).blocks() + sage: TD = designs.transversal_design(4,10).blocks() # needs sage.modules sage: groups = [list(range(i*10,(i+1)*10)) for i in range(4)] - sage: is_pairwise_balanced_design(TD+groups,40,[4,10],1,verbose=True) + sage: is_pairwise_balanced_design(TD + groups, 40, [4,10], 1, verbose=True) # needs sage.modules True TESTS:: sage: from sage.combinat.designs.designs_pyx import is_pairwise_balanced_design - sage: is_pairwise_balanced_design(TD+groups,40,[4,10],2,verbose=True) + sage: is_pairwise_balanced_design(TD + groups, 40, [4,10], 2, verbose=True) # needs sage.modules the pair (0,1) has been seen 1 times but lambda=2 False - sage: is_pairwise_balanced_design(TD+groups,40,[10],1,verbose=True) + sage: is_pairwise_balanced_design(TD + groups, 40, [10], 1, verbose=True) # needs sage.modules a block has size 4 while K=[10] False - sage: is_pairwise_balanced_design([[2,2]],40,[2],1,verbose=True) + sage: is_pairwise_balanced_design([[2,2]], 40, [2], 1, verbose=True) The following block has repeated elements: [2, 2] False - sage: is_pairwise_balanced_design([["e",2]],40,[2],1,verbose=True) + sage: is_pairwise_balanced_design([["e",2]], 40, [2], 1, verbose=True) e does not belong to [0,...,39] False """ @@ -415,11 +418,12 @@ def is_projective_plane(blocks, verbose=False): EXAMPLES:: sage: from sage.combinat.designs.designs_pyx import is_projective_plane - sage: p = designs.projective_plane(4) - sage: b = p.blocks() - sage: is_projective_plane(b, verbose=True) + sage: p = designs.projective_plane(4) # needs sage.schemes + sage: b = p.blocks() # needs sage.schemes + sage: is_projective_plane(b, verbose=True) # needs sage.schemes True + sage: # needs sage.schemes sage: p = designs.projective_plane(2) sage: b = p.blocks() sage: is_projective_plane(b) @@ -437,6 +441,7 @@ def is_projective_plane(blocks, verbose=False): First block has less than 3 points. False + sage: # needs sage.schemes sage: p = designs.projective_plane(2) sage: b = p.blocks() sage: b[2].append(4) @@ -486,9 +491,9 @@ def is_difference_matrix(M,G,k,lmbda=1,verbose=False): sage: from sage.combinat.designs.designs_pyx import is_difference_matrix sage: q = 3**3 - sage: F = GF(q,'x') - sage: M = [[x*y for y in F] for x in F] - sage: is_difference_matrix(M,F,q,verbose=1) + sage: F = GF(q,'x') # needs sage.rings.finite_rings + sage: M = [[x*y for y in F] for x in F] # needs sage.rings.finite_rings + sage: is_difference_matrix(M,F,q,verbose=1) # needs sage.rings.finite_rings True sage: B = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -501,6 +506,7 @@ def is_difference_matrix(M,G,k,lmbda=1,verbose=False): Bad input:: + sage: # needs sage.rings.finite_rings sage: for R in M: R.append(None) sage: is_difference_matrix(M,F,q,verbose=1) The matrix has 28 columns but k=27 @@ -518,7 +524,8 @@ def is_difference_matrix(M,G,k,lmbda=1,verbose=False): sage: for R in M: R[-1] = 1 sage: M[-1][-1] = 0 sage: is_difference_matrix(M,F,q,verbose=1) - Columns 0 and 26 do not generate all elements of G exactly lambda(=1) times. The element x appeared 0 times as a difference. + Columns 0 and 26 do not generate all elements of G exactly lambda(=1) times. + The element x appeared 0 times as a difference. False """ return is_quasi_difference_matrix(M,G,k,lmbda=lmbda,mu=lmbda,u=0,verbose=verbose) @@ -559,9 +566,9 @@ def is_quasi_difference_matrix(M,G,int k,int lmbda,int mu,int u,verbose=False): sage: from sage.combinat.designs.designs_pyx import is_quasi_difference_matrix sage: q = 3**3 - sage: F = GF(q,'x') - sage: M = [[x*y for y in F] for x in F] - sage: is_quasi_difference_matrix(M,F,q,1,1,0,verbose=1) + sage: F = GF(q,'x') # needs sage.rings.finite_rings + sage: M = [[x*y for y in F] for x in F] # needs sage.rings.finite_rings + sage: is_quasi_difference_matrix(M,F,q,1,1,0,verbose=1) # needs sage.rings.finite_rings True sage: B = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 410bb446fee..b737b90b820 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -5,7 +5,7 @@ This module gathers everything related to difference families. One can build a difference family (or check that it can be built) with :func:`difference_family`:: - sage: G,F = designs.difference_family(13,4,1) + sage: G,F = designs.difference_family(13,4,1) # needs sage.libs.pari sage.modules It defines the following functions: @@ -70,9 +70,9 @@ def group_law(G): sage: from sage.combinat.designs.difference_family import group_law sage: group_law(Zmod(3)) (0, <built-in function add>, <built-in function neg>) - sage: group_law(SymmetricGroup(5)) + sage: group_law(SymmetricGroup(5)) # needs sage.groups ((), <built-in function mul>, <built-in function inv>) - sage: group_law(VectorSpace(QQ,3)) + sage: group_law(VectorSpace(QQ, 3)) # needs sage.modules ((0, 0, 0), <built-in function add>, <built-in function neg>) """ import operator @@ -84,7 +84,7 @@ def group_law(G): elif G in AdditiveGroups(): # additive groups return (G.zero(), operator.add, operator.neg) else: - raise ValueError("%s does not seem to be a group"%G) + raise ValueError("%s does not seem to be a group" % G) def block_stabilizer(G, B): r""" @@ -95,9 +95,8 @@ def block_stabilizer(G, B): INPUT: - - ``G`` -- a group (additive or multiplicative). - - - ``B`` -- a subset of ``G``. + - ``G`` -- a group (additive or multiplicative) + - ``B`` -- a subset of ``G`` EXAMPLES:: @@ -137,12 +136,10 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): INPUT: - ``G`` -- group of cardinality ``v`` - - ``D`` -- a set of ``k``-subsets of ``G`` - - ``v``, ``k`` and ``l`` -- optional parameters of the difference family - - - ``verbose`` - whether to print additional information + - ``verbose`` -- boolean (default: ``False``); whether to print additional + information .. SEEALSO:: @@ -179,6 +176,7 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): sage: is_difference_family(G, D) True + sage: # needs sage.modules sage: G = AdditiveAbelianGroup([3]*4) sage: a,b,c,d = G.gens() sage: D = [[d, -a+d, -c+d, a-b-d, b+c+d], @@ -198,6 +196,7 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): The function also supports multiplicative groups (non necessarily Abelian):: + sage: # needs sage.groups sage: G = DihedralGroup(8) sage: x,y = G.gens() sage: i = G.one() @@ -205,10 +204,11 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): sage: is_difference_family(G, D1, 16, 3, 2) True sage: from sage.combinat.designs.bibd import BIBD_from_difference_family - sage: bibd = BIBD_from_difference_family(G,D1,lambd=2) + sage: bibd = BIBD_from_difference_family(G, D1, lambd=2) TESTS:: + sage: # needs sage.rings.finite_rings sage: K = GF(3^2,'z') sage: z = K.gen() sage: D = [[1,z+1,2]] @@ -270,7 +270,7 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): # Check that every x \in G-{0},occurs exactly l times as a difference counter = {g: 0 for g in Glist} - where = {g: set() for g in Glist} + where = {g: set() for g in Glist} del counter[identity] for i,d in enumerate(D): @@ -296,7 +296,7 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): counter[gg] += tmp_counter[gg]//stabi # Check the counter and report any error - too_few = [] + too_few = [] too_much = [] for g in Glist: if g == identity: @@ -356,23 +356,23 @@ def singer_difference_set(q,d): EXAMPLES:: sage: from sage.combinat.designs.difference_family import singer_difference_set, is_difference_family - sage: G,D = singer_difference_set(3,2) - sage: is_difference_family(G,D,verbose=True) + sage: G,D = singer_difference_set(3,2) # needs sage.rings.finite_rings + sage: is_difference_family(G, D, verbose=True) # needs sage.rings.finite_rings It is a (13,4,1)-difference family True - sage: G,D = singer_difference_set(4,2) - sage: is_difference_family(G,D,verbose=True) + sage: G,D = singer_difference_set(4,2) # needs sage.rings.finite_rings + sage: is_difference_family(G, D, verbose=True) # needs sage.rings.finite_rings It is a (21,5,1)-difference family True - sage: G,D = singer_difference_set(3,3) - sage: is_difference_family(G,D,verbose=True) + sage: G,D = singer_difference_set(3,3) # needs sage.rings.finite_rings + sage: is_difference_family(G, D, verbose=True) # needs sage.rings.finite_rings It is a (40,13,4)-difference family True - sage: G,D = singer_difference_set(9,3) - sage: is_difference_family(G,D,verbose=True) + sage: G,D = singer_difference_set(9,3) # needs sage.rings.finite_rings + sage: is_difference_family(G, D, verbose=True) # needs sage.rings.finite_rings It is a (820,91,10)-difference family True """ @@ -420,9 +420,11 @@ def df_q_6_1(K, existence=False, check=True): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.combinat.designs.difference_family import is_difference_family, df_q_6_1 sage: prime_powers = [v for v in range(31,500,30) if is_prime_power(v)] - sage: parameters = [v for v in prime_powers if df_q_6_1(GF(v,'a'), existence=True) is True] + sage: parameters = [v for v in prime_powers + ....: if df_q_6_1(GF(v,'a'), existence=True) is True] sage: parameters [31, 151, 181, 211, 241, 271, 331, 361, 421] sage: for v in parameters: @@ -481,13 +483,13 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): sage: from sage.combinat.designs.difference_family import radical_difference_set - sage: D = radical_difference_set(GF(7), 3, 1); D + sage: D = radical_difference_set(GF(7), 3, 1); D # needs sage.rings.finite_rings [[1, 2, 4]] - sage: sorted(x-y for x in D[0] for y in D[0] if x != y) + sage: sorted(x-y for x in D[0] for y in D[0] if x != y) # needs sage.rings.finite_rings [1, 2, 3, 4, 5, 6] - sage: D = radical_difference_set(GF(16,'a'), 6, 2) - sage: sorted(x-y for x in D[0] for y in D[0] if x != y) + sage: D = radical_difference_set(GF(16,'a'), 6, 2) # needs sage.rings.finite_rings + sage: sorted(x-y for x in D[0] for y in D[0] if x != y) # needs sage.rings.finite_rings [1, 1, a, @@ -500,7 +502,7 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): a^3 + a^2 + a + 1, a^3 + a^2 + a + 1] - sage: for k in range(2,50): + sage: for k in range(2,50): # needs sage.rings.finite_rings ....: for l in reversed(divisors(k*(k-1))): ....: v = k*(k-1)//l + 1 ....: if is_prime_power(v) and radical_difference_set(GF(v,'a'),k,l,existence=True) is True: @@ -554,25 +556,25 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): add_zero = False # q = 3 mod 4 - elif v%4 == 3 and k == (v-1)//2: + elif v % 4 == 3 and k == (v-1)//2: if existence: return True add_zero = False # q = 3 mod 4 - elif v%4 == 3 and k == (v+1)//2: + elif v % 4 == 3 and k == (v+1)//2: if existence: return True add_zero = True # q = 4t^2 + 1, t odd - elif v%8 == 5 and k == (v-1)//4 and arith.is_square((v-1)//4): + elif v % 8 == 5 and k == (v-1)//4 and arith.is_square((v-1)//4): if existence: return True add_zero = False # q = 4t^2 + 9, t odd - elif v%8 == 5 and k == (v+3)//4 and arith.is_square((v-9)//4): + elif v % 8 == 5 and k == (v+3)//4 and arith.is_square((v-9)//4): if existence: return True add_zero = True @@ -594,8 +596,8 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): x = K.multiplicative_generator() D = K.cyclotomic_cosets(x**((v-1)//k), [K.one()]) if is_difference_family(K, D, v, k, l): - print("** You found a new example of radical difference set **\n"\ - "** for the parameters (v,k,l)=({},{},{}). **\n"\ + print("** You found a new example of radical difference set **\n" + "** for the parameters (v,k,l)=({},{},{}). **\n" "** Please contact sage-devel@googlegroups.com **\n".format(v, k, l)) if existence: return True @@ -605,8 +607,8 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): D = K.cyclotomic_cosets(x**((v-1)//(k-1)), [K.one()]) D[0].insert(0,K.zero()) if is_difference_family(K, D, v, k, l): - print("** You found a new example of radical difference set **\n"\ - "** for the parameters (v,k,l)=({},{},{}). **\n"\ + print("** You found a new example of radical difference set **\n" + "** for the parameters (v,k,l)=({},{},{}). **\n" "** Please contact sage-devel@googlegroups.com **\n".format(v, k, l)) if existence: return True @@ -684,7 +686,7 @@ def one_cyclic_tiling(A,n): # 1972 article n = int(n) d = len(A) - if len(set(a%d for a in A)) == d: + if len(set(a % d for a in A)) == d: return [i*d for i in range(n//d)] # next, we consider an exhaustive search @@ -692,7 +694,7 @@ def one_cyclic_tiling(A,n): rows = [] for i in range(n): - rows.append([i+1, [(i+a)%n+1 for a in A]]) + rows.append([i+1, [(i+a) % n+1 for a in A]]) M = DLXMatrix(rows) for c in M: return [i-1 for i in c] @@ -708,9 +710,8 @@ def one_radical_difference_family(K, k): INPUT: - - ``K`` -- a finite field of cardinality `q`. - - - ``k`` -- a positive integer so that `k(k-1)` divides `q-1`. + - ``K`` -- a finite field of cardinality `q` + - ``k`` -- a positive integer so that `k(k-1)` divides `q-1` OUTPUT: @@ -760,12 +761,12 @@ def one_radical_difference_family(K, k): ....: one_radical_difference_family, ....: is_difference_family) - sage: one_radical_difference_family(GF(13),4) + sage: one_radical_difference_family(GF(13),4) # needs sage.rings.finite_rings [[0, 1, 3, 9]] The parameters that appear in [Bu95]_:: - sage: df = one_radical_difference_family(GF(449), 8); df + sage: df = one_radical_difference_family(GF(449), 8); df # needs sage.rings.finite_rings [[0, 1, 18, 25, 176, 324, 359, 444], [0, 9, 88, 162, 222, 225, 237, 404], [0, 11, 140, 198, 275, 357, 394, 421], @@ -774,19 +775,19 @@ def one_radical_difference_family(K, k): [0, 70, 99, 197, 230, 362, 403, 435], [0, 121, 141, 193, 293, 331, 335, 382], [0, 191, 285, 295, 321, 371, 390, 392]] - sage: is_difference_family(GF(449), df, 449, 8, 1) + sage: is_difference_family(GF(449), df, 449, 8, 1) # needs sage.rings.finite_rings True """ q = K.cardinality() x = K.multiplicative_generator() e = k*(k-1) - if q%e != 1: + if q % e != 1: raise ValueError("q%e is not 1") # We define A by (see the function's documentation): # ฮ”B = C.A - if k%2 == 1: + if k % 2 == 1: m = (k-1) // 2 r = x ** ((q-1) // k) # k-th root of unity A = [r**i - 1 for i in range(1,m+1)] @@ -800,7 +801,7 @@ def one_radical_difference_family(K, k): # discrete logarithm to convert everything into the additive group Z/cZ c = m * (q-1) // e # cardinal of ยฑC from sage.groups.generic import discrete_log - logA = [discrete_log(a,x)%c for a in A] + logA = [discrete_log(a,x) % c for a in A] # if two elements of A are equal modulo c then no tiling is possible if len(set(logA)) != m: @@ -812,7 +813,7 @@ def one_radical_difference_family(K, k): return None D = K.cyclotomic_cosets(r, [x**i for i in tiling]) - if k%2 == 0: + if k % 2 == 0: for d in D: d.insert(K.zero(),0) return D @@ -833,27 +834,23 @@ def radical_difference_family(K, k, l=1, existence=False, check=True): INPUT: - ``K`` - a finite field - - - ``k`` -- positive integer, the size of the blocks - - - ``l`` -- the `\lambda` parameter (default to `1`) - + - ``k`` -- positive integer; the size of the blocks + - ``l`` -- integer (default: ``1``); the `\lambda` parameter - ``existence`` -- if ``True``, then return either ``True`` if Sage knows how to build such design, ``Unknown`` if it does not and ``False`` if it - knows that the design does not exist. - - - ``check`` -- boolean (default: ``True``). If ``True`` then the result of + knows that the design does not exist + - ``check`` -- boolean (default: ``True``); if ``True`` then the result of the computation is checked before being returned. This should not be - needed but ensures that the output is correct. + needed but ensures that the output is correct EXAMPLES:: sage: from sage.combinat.designs.difference_family import radical_difference_family - sage: radical_difference_family(GF(73),9) + sage: radical_difference_family(GF(73), 9) # needs sage.rings.finite_rings [[1, 2, 4, 8, 16, 32, 37, 55, 64]] - sage: radical_difference_family(GF(281),5) + sage: radical_difference_family(GF(281), 5) # needs sage.rings.finite_rings [[1, 86, 90, 153, 232], [4, 50, 63, 79, 85], [5, 36, 149, 169, 203], @@ -869,7 +866,7 @@ def radical_difference_family(K, k, l=1, existence=False, check=True): [111, 123, 155, 181, 273], [156, 209, 224, 264, 271]] - sage: for k in range(5,10): + sage: for k in range(5,10): # needs sage.rings.finite_rings ....: print("k = {}".format(k)) ....: list_q = [] ....: for q in range(k*(k-1)+1, 2000, k*(k-1)): @@ -923,7 +920,6 @@ def radical_difference_family(K, k, l=1, existence=False, check=True): elif existence: return True - if check and not is_difference_family(K, D, v, k, l): raise RuntimeError("radical_difference_family produced a wrong " "difference family with parameters v={}, " @@ -947,14 +943,14 @@ def twin_prime_powers_difference_set(p, check=True): INPUT: - - ``check`` -- boolean (default: ``True``). If ``True`` then the result of + - ``check`` -- boolean (default: ``True``); if ``True``, then the result of the computation is checked before being returned. This should not be - needed but ensures that the output is correct. + needed but ensures that the output is correct EXAMPLES:: sage: from sage.combinat.designs.difference_family import twin_prime_powers_difference_set - sage: G,D = twin_prime_powers_difference_set(3) + sage: G, D = twin_prime_powers_difference_set(3) sage: G The Cartesian product of (Finite Field of size 3, Finite Field of size 5) sage: D @@ -996,16 +992,16 @@ def are_mcfarland_1973_parameters(v, k, lmbda, return_parameters=False): INPUT: - - ``v``, ``k``, ``lmbda`` - (integers) parameters of the difference family - - - ``return_parameters`` -- (boolean, default ``False``) if ``True`` return a + - ``v``, ``k``, ``lmbda`` - integers; parameters of the difference family + - ``return_parameters`` -- boolean (default ``False``); if ``True``, return a pair ``(True, (q, s))`` so that ``(q,s)`` can be used in the function :func:`mcfarland_1973_construction` to actually build a ``(v,k,lmbda)``-difference family. Or ``(False, None)`` if the - construction is not possible. + construction is not possible EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.combinat.designs.difference_family import are_mcfarland_1973_parameters sage: are_mcfarland_1973_parameters(64, 28, 12) True @@ -1019,7 +1015,7 @@ def are_mcfarland_1973_parameters(v, k, lmbda, return_parameters=False): (True, (5, 3)) sage: from sage.combinat.designs.difference_family import are_mcfarland_1973_parameters - sage: for v in range(1, 100): + sage: for v in range(1, 100): # needs sage.rings.finite_rings ....: for k in range(1,30): ....: for l in range(1,15): ....: if are_mcfarland_1973_parameters(v,k,l): @@ -1038,13 +1034,13 @@ def are_mcfarland_1973_parameters(v, k, lmbda, return_parameters=False): k = ZZ(k) lmbda = ZZ(lmbda) qs,r = (k - lmbda).sqrtrem() # sqrt(k-l) should be q^s - if r or (qs*(qs-1))%lmbda: + if r or (qs*(qs-1)) % lmbda: return (False,None) if return_parameters else False q = qs*(qs-1) // lmbda + 1 if (q <= 1 or v * (q-1) != qs*q * (qs*q+q-2) or - k * (q-1)!= qs * (qs*q-1)): + k * (q-1) != qs * (qs*q-1)): return (False,None) if return_parameters else False # NOTE: below we compute the value of s so that qs = q^s. If the method @@ -1054,7 +1050,7 @@ def are_mcfarland_1973_parameters(v, k, lmbda, return_parameters=False): p1,a1 = qs.is_prime_power(get_data=True) p2,a2 = q.is_prime_power(get_data=True) - if a1 == 0 or a2 == 0 or p1 != p2 or a1%a2: + if a1 == 0 or a2 == 0 or p1 != p2 or a1 % a2: return (False,None) if return_parameters else False return (True, (q, a1//a2)) if return_parameters else True @@ -1075,7 +1071,7 @@ def mcfarland_1973_construction(q, s): INPUT: - - ``q``, ``s`` - (integers) parameters for the difference set (see the above + - ``q``, ``s`` - integers; parameters for the difference set (see the above formulas for the expression of ``v``, ``k``, ``l`` in terms of ``q`` and ``s``) @@ -1097,11 +1093,11 @@ def mcfarland_1973_construction(q, s): sage: from sage.combinat.designs.difference_family import ( ....: mcfarland_1973_construction, is_difference_family) - sage: G,D = mcfarland_1973_construction(3, 1) - sage: assert is_difference_family(G, D, 45, 12, 3) + sage: G,D = mcfarland_1973_construction(3, 1) # needs sage.modules + sage: assert is_difference_family(G, D, 45, 12, 3) # needs sage.modules - sage: G,D = mcfarland_1973_construction(2, 2) - sage: assert is_difference_family(G, D, 64, 28, 12) + sage: G,D = mcfarland_1973_construction(2, 2) # needs sage.modules + sage: assert is_difference_family(G, D, 64, 28, 12) # needs sage.modules """ from sage.rings.finite_rings.finite_field_constructor import GF from sage.modules.free_module import VectorSpace @@ -1160,7 +1156,7 @@ def hadamard_difference_set_product_parameters(N): EXAMPLES:: sage: from sage.combinat.designs.difference_family import hadamard_difference_set_product_parameters - sage: hadamard_difference_set_product_parameters(8) + sage: hadamard_difference_set_product_parameters(8) # needs sage.rings.finite_rings (2, 2) """ if N % 2: @@ -1200,16 +1196,16 @@ def hadamard_difference_set_product(G1, D1, G2, D2): sage: from sage.combinat.designs.difference_family import hadamard_difference_set_product sage: from sage.combinat.designs.difference_family import is_difference_family - sage: G1,D1 = designs.difference_family(16,6,2) - sage: G2,D2 = designs.difference_family(36,15,6) + sage: G1,D1 = designs.difference_family(16,6,2) # needs sage.rings.finite_rings + sage: G2,D2 = designs.difference_family(36,15,6) # needs sage.rings.finite_rings - sage: G11,D11 = hadamard_difference_set_product(G1,D1,G1,D1) - sage: assert is_difference_family(G11, D11, 256, 120, 56) - sage: assert designs.difference_family(256, 120, 56, existence=True) is True + sage: G11,D11 = hadamard_difference_set_product(G1,D1,G1,D1) # needs sage.rings.finite_rings + sage: assert is_difference_family(G11, D11, 256, 120, 56) # needs sage.rings.finite_rings + sage: assert designs.difference_family(256, 120, 56, existence=True) is True # needs sage.rings.finite_rings - sage: G12,D12 = hadamard_difference_set_product(G1,D1,G2,D2) - sage: assert is_difference_family(G12, D12, 576, 276, 132) - sage: assert designs.difference_family(576, 276, 132, existence=True) is True + sage: G12,D12 = hadamard_difference_set_product(G1,D1,G2,D2) # needs sage.rings.finite_rings + sage: assert is_difference_family(G12, D12, 576, 276, 132) # needs sage.rings.finite_rings + sage: assert designs.difference_family(576, 276, 132, existence=True) is True # needs sage.rings.finite_rings """ from sage.categories.cartesian_product import cartesian_product @@ -1235,7 +1231,7 @@ def turyn_1965_3x3xK(k=4): - ``k`` -- either ``2`` (to get a difference set in `C_3 \times C_3 \times C_2 \times C_2`) or ``4`` (to get a difference set in `C_3 \times C_3 - \times C_3 \times C_4`). + \times C_3 \times C_4`) EXAMPLES:: @@ -1267,16 +1263,16 @@ def turyn_1965_3x3xK(k=4): def _is_periodic_sequence(seq, period): - r"""Check if the sequence is periodic with correct period. + r""" + Check if the sequence is periodic with correct period. The sequence should have length at least twice the period, so that periodicity can be checked. INPUT: - - ``seq`` -- the sequence to be tested (must have length at least twice the period). - - - ``period`` -- integer, the period that the sequence should have. + - ``seq`` -- the sequence to be tested (must have length at least twice the period) + - ``period`` -- integer; the period that the sequence should have EXAMPLES:: @@ -1294,41 +1290,41 @@ def _is_periodic_sequence(seq, period): first = seq[:per] periodic = True for j in range(1, len(seq)//per): - if seq[j*per:(j+1)*per] != first: + if seq[j*per : (j+1)*per] != first: periodic = False break if periodic: return False - if seq[:period] != seq[period:2*period]: + if seq[:period] != seq[period : 2*period]: return False return True def _create_m_sequence(q, n, check=True): - r"""Create an m-sequence over GF(q) with period `q^n-1`. + r""" + Create an m-sequence over GF(q) with period `q^n - 1`. Given a prime power `q`, the m-sequence is created as described by [Zie1959]_ from a primitive function over the finite field `GF(q)`. - Given a primitive function `f=c_0+c_1x+...+c_nx^n` over `K=GF(q)` of degree `n`, - the recurrence is given by: `a_i = -c_0^{-1}(c_1a_{i-1}+...+c_na{i-n})`. - The first `n` elements will be `0,0,...,0,1` and these will give a maximal length recurrence sequence + Given a primitive function `f=c_0+c_1x+...+c_nx^n` over `K = GF(q)` of degree `n`, + the recurrence is given by: `a_i = -c_0^{-1}(c_1a_{i-1} + ... + c_na{i-n})`. + The first `n` elements will be `0, 0, ..., 0, 1` and these will give a maximal length recurrence sequence as shown in [Mit2008]_. INPUT: - - ``q`` -- a prime power. - - - ``n`` -- a nonnegative number. - - - ``check`` -- boolean (dafault True): if true, check that the result is a seqauence with correct period. - Setting it to false may speed up considerably the computation. + - ``q`` -- a prime power + - ``n`` -- a nonnegative number + - ``check`` -- boolean (default: ``True``); if ``True``, check that the + result is a sequence with correct period; detting it to ``False`` may + speed up considerably the computation EXAMPLES:: sage: from sage.combinat.designs.difference_family import _create_m_sequence - sage: _create_m_sequence(3, 2) #random + sage: _create_m_sequence(3, 2) # random # needs sage.rings.finite_rings [1, 0, 1, 2, 2, 0, 2, 1] - sage: _create_m_sequence(4, 2, check=False) #random + sage: _create_m_sequence(4, 2, check=False) # random # needs sage.rings.finite_rings [1, 0, a, a + 1, a, a, 0, a + 1, 1, a + 1, a + 1, 0, 1, a, 1] sage: _create_m_sequence(6, 2) Traceback (most recent call last): @@ -1354,37 +1350,38 @@ def _create_m_sequence(q, n, check=True): period = q**n - 1 seq_len = period*2 if check else period - seq = [1]+[0]*(n-1) + seq = [1] + [0]*(n-1) while len(seq) < seq_len: nxt = 0 for i, coeff in zip(exps[1:], coeffs[1:]): - nxt += coeff*seq[-i] - seq.append(-coeffs[0].inverse()*nxt) + nxt += coeff * seq[-i] + seq.append(-coeffs[0].inverse() * nxt) if check: assert _is_periodic_sequence(seq, period) return seq[:period] def _get_submodule_of_order(G, order): - r"""Construct a submodule of the given order from group `G`. + r""" + Construct a submodule of the given order from group ``G``. This method tries to construct submodules from various elements of `G` until a submodule of the correct order is found. INPUT: - - ``G`` -- an additive abelian group. - - - ``order`` -- integer, the order of the desired syubmodule. + - ``G`` -- an additive abelian group + - ``order`` -- integer; the order of the desired submodule TESTS: + sage: # needs sage.modules sage: from sage.combinat.designs.difference_family import _get_submodule_of_order sage: G = AdditiveAbelianGroup([48]) sage: _get_submodule_of_order(G, 6).order() 6 - sage: G = AdditiveAbelianGroup([13^2-1]) + sage: G = AdditiveAbelianGroup([13^2 - 1]) sage: _get_submodule_of_order(G, 12).order() 12 """ @@ -1394,8 +1391,9 @@ def _get_submodule_of_order(G, order): return H return None -def relative_difference_set_from_m_sequence(q, N, check=True): - r"""Construct `R((q^N-1)/(q-1), q-1, q^{N-1}, q^{N-2})` where `q` is a prime power and `N\ge 2`. +def relative_difference_set_from_m_sequence(q, N, check=True, return_group=False): + r""" + Construct `R((q^N-1)/(q-1), q-1, q^{N-1}, q^{N-2})` where ``q`` is a prime power and `N\ge 2`. The relative difference set is constructed over the set of additive integers modulo `q^N-1`, as described in Theorem 5.1 of [EB1966]_. Given an m-sequence `(a_i)` of period `q^N-1`, the @@ -1403,21 +1401,28 @@ def relative_difference_set_from_m_sequence(q, N, check=True): INPUT: - - ``q`` -- a prime power. + - ``q`` -- a prime power + - ``N`` -- a nonnegative number + - ``check`` -- boolean (default: ``True``); if ``True``, check that the + result is a relative difference set before returning it + - ``return_group`` -- boolean (default: ``False``); if ``True``, the function + will also return the group from which the set is created - - ``N`` -- a nonnegative number. + OUTPUT: - - ``check`` -- boolean (default True). If true, check that the result is a relative difference - set before returning it. + If ``return_group=False``, the function return only the relative difference + set. Otherwise, it returns a tuple containing the group and the set. EXAMPLES:: sage: from sage.combinat.designs.difference_family import relative_difference_set_from_m_sequence - sage: relative_difference_set_from_m_sequence(2, 4) #random - [(0), (4), (5), (6), (7), (9), (11), (12)] - sage: relative_difference_set_from_m_sequence(8, 2, check=False) #random + sage: relative_difference_set_from_m_sequence(2, 4, # random # needs sage.modules sage.rings.finite_rings + ....: return_group=True) + (Additive abelian group isomorphic to Z/15, + [(0), (4), (5), (6), (7), (9), (11), (12)]) + sage: relative_difference_set_from_m_sequence(8, 2, check=False) # random # needs sage.modules sage.rings.finite_rings [(0), (6), (30), (40), (41), (44), (56), (61)] - sage: relative_difference_set_from_m_sequence(6, 2) + sage: relative_difference_set_from_m_sequence(6, 2) # needs sage.modules Traceback (most recent call last): ... ValueError: q must be a prime power @@ -1426,14 +1431,18 @@ def relative_difference_set_from_m_sequence(q, N, check=True): sage: from sage.combinat.designs.difference_family import is_relative_difference_set, _get_submodule_of_order sage: q, N = 5, 3 - sage: G = AdditiveAbelianGroup([q^N-1]) - sage: H = _get_submodule_of_order(G, q-1) - sage: is_relative_difference_set(relative_difference_set_from_m_sequence(q, N), G, H, ((q^N-1)//(q-1), q-1, q^(N-1), q^(N-2))) + sage: G, D = relative_difference_set_from_m_sequence(q, N, check=False, # needs sage.modules sage.rings.finite_rings + ....: return_group=True) + sage: H = _get_submodule_of_order(G, q-1) # needs sage.modules sage.rings.finite_rings + sage: is_relative_difference_set(D, G, H, # needs sage.modules sage.rings.finite_rings + ....: ((q^N-1)//(q-1), q-1, q^(N-1), q^(N-2))) True sage: q, N = 13, 2 - sage: G = AdditiveAbelianGroup([q^N-1]) - sage: H = _get_submodule_of_order(G, q-1) - sage: is_relative_difference_set(relative_difference_set_from_m_sequence(q, N), G, H, ((q^N-1)//(q-1), q-1, q^(N-1), q^(N-2))) + sage: G, D = relative_difference_set_from_m_sequence(q, N, check=False, # needs sage.modules sage.rings.finite_rings + ....: return_group=True) + sage: H = _get_submodule_of_order(G, q-1) # needs sage.modules sage.rings.finite_rings + sage: is_relative_difference_set(D, G, H, # needs sage.modules sage.rings.finite_rings + ....: ((q^N-1)//(q-1), q-1, q^(N-1), q^(N-2))) True """ from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup @@ -1444,41 +1453,51 @@ def relative_difference_set_from_m_sequence(q, N, check=True): raise ValueError('N must be at least 2') m_seq = _create_m_sequence(q, N, check=False) - period = q**N-1 + period = q**N - 1 G = AdditiveAbelianGroup([period]) set1 = [i for i in G if m_seq[i[0]] == 1] if check: H = _get_submodule_of_order(G, q-1) - assert is_relative_difference_set(set1, G, H, (period//(q-1), q-1, q**(N-1), q**(N-2))) + assert is_relative_difference_set(set1, G, H, (period // (q-1), q - 1, q**(N-1), q**(N-2))) + + if return_group: + return G, set1 return set1 -def relative_difference_set_from_homomorphism(q, N, d, check=True): - r"""Construct `R((q^N-1)/(q-1), n, q^{N-1}, q^{N-2}d)` where `nd = q-1`. +def relative_difference_set_from_homomorphism(q, N, d, check=True, return_group=False): + r""" + Construct `R((q^N-1)/(q-1), n, q^{N-1}, q^{N-2}d)` where `nd = q-1`. Given a prime power `q`, a number `N \ge 2` and integers `d` such that `d | q-1` we create the relative difference set using the construction from Corollary 5.1.1 of [EB1966]_. INPUT: - - ``q`` -- a prime power. - - - ``N`` -- an integer greater than 1. + - ``q`` -- a prime power + - ``N`` -- an integer greater than 1 + - ``d`` -- an integer which divides `q-1` + - ``check`` -- boolean (default: ``True``); if ``True``, check that the + result is a relative difference set before returning it + - ``return_group`` -- boolean (default: ``False``); if ``True``, the function + will also return the group from which the set is created - - ``d`` -- an integer which divides `q-1`. + OUTPUT: - - ``check`` -- boolean (default True). If true, check that the result is a relative difference - set before returning it. + If ``return_group=False``, the function return only the relative difference + set. Otherwise, it returns a tuple containing the group and the set. EXAMPLES:: sage: from sage.combinat.designs.difference_family import relative_difference_set_from_homomorphism - sage: relative_difference_set_from_homomorphism(7, 2, 3) #random + sage: relative_difference_set_from_homomorphism(7, 2, 3) # random # needs sage.modules sage.rings.finite_rings [(0), (3), (4), (2), (13), (7), (14)] - sage: relative_difference_set_from_homomorphism(9, 2, 4, check=False) #random - [(0), (4), (6), (13), (7), (12), (15), (8), (9)] - sage: relative_difference_set_from_homomorphism(9, 2, 5) + sage: relative_difference_set_from_homomorphism(9, 2, 4, # random # needs sage.modules sage.rings.finite_rings + ....: check=False, return_group=True) + (Additive abelian group isomorphic to Z/80, + [(0), (4), (6), (13), (7), (12), (15), (8), (9)]) + sage: relative_difference_set_from_homomorphism(9, 2, 5) # needs sage.modules sage.rings.finite_rings Traceback (most recent call last): ... ValueError: q-1 must be a multiple of d @@ -1487,14 +1506,18 @@ def relative_difference_set_from_homomorphism(q, N, d, check=True): sage: from sage.combinat.designs.difference_family import is_relative_difference_set, _get_submodule_of_order sage: q, N, d = 11, 2, 5 - sage: G = AdditiveAbelianGroup([(q^N-1)//d]) - sage: H = _get_submodule_of_order(G, (q-1)//d) - sage: is_relative_difference_set(relative_difference_set_from_homomorphism(q, N, d), G, H, ((q**N-1)//(q-1), (q-1)//d, q**(N-1), q**(N-2)*d)) + sage: G, D = relative_difference_set_from_homomorphism(q, N, d, check=False, # needs sage.modules sage.rings.finite_rings + ....: return_group=True) + sage: H = _get_submodule_of_order(G, (q-1)//d) # needs sage.modules sage.rings.finite_rings + sage: is_relative_difference_set(D, G, H, # needs sage.modules sage.rings.finite_rings + ....: ((q**N-1)//(q-1), (q-1)//d, q**(N-1), q**(N-2)*d)) True sage: q, N, d = 9, 2, 4 - sage: G = AdditiveAbelianGroup([(q^N-1)//d]) - sage: H = _get_submodule_of_order(G, (q-1)//d) - sage: is_relative_difference_set(relative_difference_set_from_homomorphism(q, N, d), G, H, ((q**N-1)//(q-1), (q-1)//d, q**(N-1), q**(N-2)*d)) + sage: G, D = relative_difference_set_from_homomorphism(q, N, d, check=False, # needs sage.modules sage.rings.finite_rings + ....: return_group=True) + sage: H = _get_submodule_of_order(G, (q-1)//d) # needs sage.modules sage.rings.finite_rings + sage: is_relative_difference_set(D, G, H, # needs sage.modules sage.rings.finite_rings + ....: ((q**N-1)//(q-1), (q-1)//d, q**(N-1), q**(N-2)*d)) True """ from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup @@ -1503,10 +1526,10 @@ def relative_difference_set_from_homomorphism(q, N, d, check=True): raise ValueError('q must be a prime power') if N < 2: raise ValueError('N must be at least 2') - if (q-1)%d != 0: + if (q-1) % d != 0: raise ValueError('q-1 must be a multiple of d') - G = AdditiveAbelianGroup([q**N-1]) + G = AdditiveAbelianGroup([q**N - 1]) K = _get_submodule_of_order(G, d) assert K is not None, 'Could not find kernel' @@ -1517,12 +1540,17 @@ def relative_difference_set_from_homomorphism(q, N, d, check=True): second_diff_set = [theta(x) for x in diff_set] if check: - H = _get_submodule_of_order(G2, (q-1)//d) - assert is_relative_difference_set(second_diff_set, G2, H, ((q**N-1)//(q-1), (q-1)//d, q**(N-1), q**(N-2)*d)) + H = _get_submodule_of_order(G2, (q-1) // d) + assert is_relative_difference_set(second_diff_set, G2, H, ((q**N-1) // (q-1), (q-1) // d, q**(N-1), q**(N-2) * d)) + + if return_group: + return G2, second_diff_set return second_diff_set -def is_relative_difference_set(R, G, H, params, verbose =False): - r"""Check if `R` is a difference set of `G` relative to `H`, with the given parameters. + +def is_relative_difference_set(R, G, H, params, verbose=False): + r""" + Check if ``R`` is a difference set of ``G`` relative to ``H``, with the given parameters. This function checks that `G`, `H` and `R` have the orders specified in the parameters, and that `R` satisfies the definition of relative difference set (from [EB1966]_): the collection of @@ -1531,37 +1559,32 @@ def is_relative_difference_set(R, G, H, params, verbose =False): INPUT: - - ``R`` -- list, the relative diffeence set of length `k`. - - - ``G`` -- an additive abelian group of order `mn`. - - - ``H`` -- a submodule of ``G`` of order `n`. - - - ``params`` -- a tuple in the form `(m, n, k, d)`. - - - ``verbose`` -- boolean (default False). If true the function will be verbose - when the sequences do not satisfy the contraints. + - ``R`` -- list; the relative diffeence set of length `k` + - ``G`` -- an additive abelian group of order `mn` + - ``H`` -- list; a submodule of ``G`` of order `n` + - ``params`` -- a tuple in the form `(m, n, k, d)` + - ``verbose`` -- boolean (default: ``False``); if ``True``, the function + will be verbose when the sequences do not satisfy the contraints EXAMPLES:: sage: from sage.combinat.designs.difference_family import _get_submodule_of_order, relative_difference_set_from_m_sequence, is_relative_difference_set sage: q, N = 5, 2 - sage: G = AdditiveAbelianGroup([q^N-1]) - sage: H = _get_submodule_of_order(G, q-1) - sage: params = ((q^N-1)//(q-1), q-1, q^(N-1), q^(N-2)) - sage: R = relative_difference_set_from_m_sequence(q, N) - sage: is_relative_difference_set(R, G, H, params) + sage: params = ((q^N-1) // (q-1), q - 1, q^(N-1), q^(N-2)) + sage: G, R = relative_difference_set_from_m_sequence(q, N, return_group=True) # needs sage.libs.pari sage.modules + sage: H = _get_submodule_of_order(G, q - 1) # needs sage.libs.pari sage.modules + sage: is_relative_difference_set(R, G, H, params) # needs sage.libs.pari sage.modules True If we pass the ``verbose`` argument, the function will explain why it failed:: - sage: R2 = [G[1], G[2], G[3], G[5], G[6]] - sage: is_relative_difference_set(R2, G, H, params, verbose=True) + sage: R2 = [G[1], G[2], G[3], G[5], G[6]] # needs sage.libs.pari sage.modules + sage: is_relative_difference_set(R2, G, H, params, verbose=True) # needs sage.libs.pari sage.modules There is a value in the difference set which is not repeated d times False """ m, n, k, d = params - if G.order() != m*n: + if G.order() != m * n: if verbose: print('Incorrect order of G:', G.order()) return False @@ -1579,7 +1602,7 @@ def is_relative_difference_set(R, G, H, params, verbose =False): for el1 in R: for el2 in R: if el1 != el2: - idx = el1-el2 + idx = el1 - el2 if idx not in diff_set: diff_set[idx] = 0 diff_set[idx] += 1 @@ -1601,59 +1624,103 @@ def is_relative_difference_set(R, G, H, params, verbose =False): return True -def is_supplementary_difference_set(Ks, v, lmbda): - r"""Check that the sets in ``Ks`` are `n-\{v; k_1,...,k_n; \lambda \}` supplementary difference sets. - From the definition in [Spe1975]_: let `S_1, S_2, ..., S_n` be `n` subsets of an additive abelian group `G` of order `v` - such that `|S_i|= k_i`. If, for each `g\in G`, `g \neq 0`, the total number of solutions of `a_i-a'_i = g`, with - `a_i,a'_i \in S_i` is `\lambda`, then `S_1, S_2, ..., S_n` are `n-\{v; k_1,...,k_n;\lambda\}` supplementary difference sets. +def is_supplementary_difference_set(Ks, v=None, lmbda=None, G=None, verbose=False): + r""" + Check that the sets in ``Ks`` are `n-\{v; k_1, ..., k_n; \lambda \}` supplementary + difference sets over group ``G`` of order ``v``. - INPUT: + From the definition in [Spe1975]_: let `S_1, S_2, ..., S_n` be `n` subsets of a group `G` of order `v` + such that `|S_i| = k_i`. If, for each `g \in G`, `g \neq 0`, the total number of solutions of `a_i - a'_i = g`, with + `a_i, a'_i \in S_i` is `\lambda`, then `S_1, S_2, ..., S_n` are `n-\{v; k_1, ..., k_n; \lambda\}` supplementary difference sets. - - ``Ks`` -- a list of sets to be checked. + One of the parameters ``v`` or ``G`` must always be specified. If ``G`` is not + given, the function will use an ``AdditiveAbelianGroup`` of order ``v``. - - ``v`` -- integer, the parameter `v` of the supplementary difference sets. + INPUT: - - ``lmbda`` -- integer, the parameter `\lambda` of the supplementary difference sets. + - ``Ks`` -- a list of sets to be checked + - ``v`` -- integer; the parameter `v` of the supplementary difference sets + - ``lmbda`` -- integer; the parameter `\lambda` of the supplementary difference sets + - ``G`` -- a group of order `v` + - ``verbose`` -- boolean (default: ``False``); if ``True``, the function will + be verbose when the sets do not satisfy the contraints EXAMPLES:: - sage: from sage.combinat.designs.difference_family import supplementary_difference_set, is_supplementary_difference_set - sage: S1, S2, S3, S4 = supplementary_difference_set(17) - sage: is_supplementary_difference_set([S1, S2, S3, S4], 16, 16) + sage: from sage.combinat.designs.difference_family import supplementary_difference_set_from_rel_diff_set, is_supplementary_difference_set + sage: G, [S1, S2, S3, S4] = supplementary_difference_set_from_rel_diff_set(17) # needs sage.modules sage.rings.finite_rings + sage: is_supplementary_difference_set([S1, S2, S3, S4], lmbda=16, G=G) # needs sage.modules sage.rings.finite_rings True - sage: is_supplementary_difference_set([S1, S2, S3, S4], 16, 14) + + The parameter ``v`` can be given instead of ``G``:: + + sage: is_supplementary_difference_set([S1, S2, S3, S4], v=16, lmbda=16) # needs sage.modules sage.rings.finite_rings + True + sage: is_supplementary_difference_set([S1, S2, S3, S4], v=20, lmbda=16) # needs sage.modules sage.rings.finite_rings False - sage: is_supplementary_difference_set([S1, S2, S3, S4], 20, 16) + + If ``verbose=True``, the function will be verbose:: + + sage: is_supplementary_difference_set([S1, S2, S3, S4], lmbda=14, G=G, # needs sage.modules sage.rings.finite_rings + ....: verbose=True) + Number of pairs with difference (1) is 16, but lambda is 14 False + TESTS:: + + sage: # needs sage.modules sage.rings.finite_rings + sage: is_supplementary_difference_set([[1], [1]], lmbda=0, G=Zmod(3)) + True + sage: is_supplementary_difference_set([S1, S2, S3, S4], v=17, lmbda=16, G=G) + False + sage: is_supplementary_difference_set([S1, S2, S3, S4], G=G) + True + sage: is_supplementary_difference_set([S1, S2, S3, S4], lmbda=16) + Traceback (most recent call last): + ... + ValueError: one of G or v must be specified + .. SEEALSO:: - :func:`supplementary_difference_set` + :func:`supplementary_difference_set_from_rel_diff_set` """ - from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup - G = AdditiveAbelianGroup([v]) - differences_counter = {} + if G is None and v is None: + raise ValueError('one of G or v must be specified') + + if G is None: + from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup + G = AdditiveAbelianGroup([v]) + + if v is not None and G.order() != v: + if verbose: + print(f'G has order {G.order()}, but it should be {v}') + return False + + differences_counter = {el: 0 for el in G} for K in Ks: for el1 in K: for el2 in K: - diff = G[el1]-G[el2] - - if diff not in differences_counter: - differences_counter[diff] = 0 + diff = G(el1) - G(el2) differences_counter[diff] += 1 - for el in G: - if el == 0: + for key, diff in differences_counter.items(): + if key == 0: continue - elif el not in differences_counter or lmbda != differences_counter[el]: + if lmbda is None: + lmbda = diff + if diff != lmbda: + if verbose: + print(f'Number of pairs with difference {key} is {diff}, but lambda is {lmbda}') return False return True -def supplementary_difference_set(q, existence=False, check=True): - r"""Construct `4-\{2v; v, v+1, v, v; 2v\}` supplementary difference sets where `q=2v+1`. + +def supplementary_difference_set_from_rel_diff_set(q, existence=False, check=True): + r""" + Construct `4-\{2v; v, v+1, v, v; 2v\}` supplementary difference sets where `q=2v+1`. The sets are created from relative difference sets as detailed in Theorem 3.3 of [Spe1975]_. this construction requires that `q` is an odd prime power and that there exists `s \ge 0` such that `(q-(2^{s+1}+1))/2^{s+1}` is @@ -1666,69 +1733,76 @@ def supplementary_difference_set(q, existence=False, check=True): INPUT: - - ``q`` -- an odd prime power. - - - ``existence`` -- boolean (dafault False). If true, only check whether the supplementary difference sets - can be constructed. - - - ``check`` -- boolean (default True). If true, check that the sets are supplementary difference sets - before returning them. + - ``q`` -- an odd prime power + - ``existence`` -- boolean (default: ``False``); If ``True``, only check + whether the supplementary difference sets can be constructed + - ``check`` -- boolean (default: ``True``); If ``True``, check that the sets + are supplementary difference sets before returning them OUTPUT: - If ``existence`` is false, the function returns the 4 sets (containing integers), or raises an - error if ``q`` does not satify the constraints. - If ``existence`` is true, the function returns a boolean representing whether supplementary difference - sets can be constructed. + If ``existence=False``, the function returns the 4 sets (containing integers), + or raises an error if ``q`` does not satify the constraints. + If ``existence=True``, the function returns a boolean representing whether + supplementary difference sets can be constructed. EXAMPLES:: - sage: from sage.combinat.designs.difference_family import supplementary_difference_set - sage: supplementary_difference_set(17) #random - ([0, 2, 5, 6, 8, 10, 13, 14], - [0, 1, 2, 6, 7, 9, 10, 14, 15], - [0, 1, 2, 6, 11, 12, 13, 15], - [0, 2, 6, 9, 11, 12, 13, 15]) + sage: from sage.combinat.designs.difference_family import supplementary_difference_set_from_rel_diff_set + sage: supplementary_difference_set_from_rel_diff_set(17) #random # needs sage.libs.pari + (Additive abelian group isomorphic to Z/16, + [[(1), (5), (6), (7), (9), (13), (14), (15)], + [(0), (2), (3), (5), (6), (10), (11), (13), (14)], + [(0), (1), (2), (3), (5), (6), (7), (12)], + [(0), (2), (3), (5), (6), (7), (9), (12)]]) - If existence is ``True``, the function returns a boolean:: + If ``existence=True``, the function returns a boolean:: - sage: supplementary_difference_set(7, existence=True) + sage: supplementary_difference_set_from_rel_diff_set(7, existence=True) False - sage: supplementary_difference_set(17, existence=True) + sage: supplementary_difference_set_from_rel_diff_set(17, existence=True) True TESTS:: + sage: # needs sage.libs.pari sage: from sage.combinat.designs.difference_family import is_supplementary_difference_set - sage: is_supplementary_difference_set(supplementary_difference_set(17), 16, 16) + sage: G, sets = supplementary_difference_set_from_rel_diff_set(17, check=False) + sage: is_supplementary_difference_set(sets, lmbda=16, G=G) True - sage: is_supplementary_difference_set(supplementary_difference_set(9), 8, 8) + sage: G, sets = supplementary_difference_set_from_rel_diff_set(9, check=False) + sage: is_supplementary_difference_set(sets, lmbda=8, G=G) True - sage: supplementary_difference_set(7) + sage: supplementary_difference_set_from_rel_diff_set(7) Traceback (most recent call last): ... ValueError: There is no s for which m-1 is an odd prime power - sage: supplementary_difference_set(8) + sage: supplementary_difference_set_from_rel_diff_set(8) Traceback (most recent call last): ... ValueError: q must be an odd prime power - sage: supplementary_difference_set(8, existence=True) + sage: supplementary_difference_set_from_rel_diff_set(8, existence=True) False - sage: supplementary_difference_set(7, existence=True) + sage: supplementary_difference_set_from_rel_diff_set(7, existence=True) False - sage: supplementary_difference_set(1, existence=True) + sage: supplementary_difference_set_from_rel_diff_set(1, existence=True) False + Check that the function works even when s > 1:: + + sage: G, sets = supplementary_difference_set_from_rel_diff_set(353, check=False) # long time, needs sage.libs.pari + sage: is_supplementary_difference_set(sets, lmbda=352, G=G) # long time, needs sage.libs.pari + True + .. SEEALSO:: :func:`is_supplementary_difference_set` - """ s = 0 m = -1 while q > 2**(s+1) and (q-1) % 2**(s+1) == 0: - prime_pow = (q-1)//2**(s+1)-1 + prime_pow = (q-1)//2**(s+1) - 1 if is_prime_power(prime_pow) and prime_pow % 2 == 1: m = (q - (2**(s+1) + 1)) // 2**(s+1) + 1 break @@ -1742,7 +1816,7 @@ def supplementary_difference_set(q, existence=False, check=True): if m == -1: raise ValueError('There is no s for which m-1 is an odd prime power') - set1 = relative_difference_set_from_homomorphism(m-1, 2, (m-2)//2, check=False) + set1 = relative_difference_set_from_homomorphism(m - 1, 2, (m-2) // 2, check=False) from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing P = PolynomialRing(ZZ, 'x') @@ -1752,39 +1826,40 @@ def supplementary_difference_set(q, existence=False, check=True): for d in set1: hall += P.monomial(d[0]) - T_2m = 0 - for i in range(2*m): - T_2m += P.monomial(i) + def get_T(k): + T = P.monomial(0) - 1 + for i in range(k): + T += P.monomial(i) + return T - modulo = P.monomial(2*m)-1 + modulo = P.monomial(2*m) - 1 - diff = T_2m - (1+P.monomial(m))*hall + diff = get_T(2*m) - (1+P.monomial(m))*hall diff = diff.mod(modulo) exp1, exp2 = diff.exponents() - a = (exp1+exp2-m)//2 + a = (exp1+exp2-m) // 2 - alfa3 = (P.monomial(a) + hall).mod(modulo) - alfa4 = (P.monomial(a+m) + hall).mod(modulo) + psi3 = (P.monomial(a) + hall).mod(modulo) + psi4 = (P.monomial(a+m) + hall).mod(modulo) - psi3 = alfa3 - psi4 = alfa4 for i in range(s): - psi3 = (alfa3(P.monomial(2))+P.monomial(1)*alfa4(P.monomial(2))).mod(P.monomial(4*m)-1) - psi4 = (alfa3(P.monomial(2)) + P.monomial(1)*(T_2m(P.monomial(2)) - alfa4(P.monomial(2)))).mod(P.monomial(4*m)-1) + m_start = 2**i * m + psi3, psi4 = (psi3(P.monomial(2)) + P.monomial(1)*psi4(P.monomial(2))).mod(P.monomial(4*m_start)-1), \ + (psi3(P.monomial(2)) + P.monomial(1)*(get_T(2*m_start)(P.monomial(2)) - psi4(P.monomial(2)))).mod(P.monomial(4*m_start)-1) # Construction of psi1, psi2 - set2 = relative_difference_set_from_m_sequence(q, 2, check=False) - s3 = _get_fixed_relative_difference_set(set2) + G2, set2 = relative_difference_set_from_m_sequence(q, 2, check=False, return_group=True) + s3 = get_fixed_relative_difference_set(G2, set2) phi_exps = [] for i in range(len(s3)): for j in range(i+1, len(s3)): - diff = (s3[i]-s3[j]) - if diff%(q-1) == 0 and diff%(q**2-1) != 0: + diff = s3[i] - s3[j] + if diff % (q-1) == 0 and diff % (q**2-1) != 0: phi_exps.append(s3[i]) - exps1 = [(x+1)//2 for x in phi_exps if x%2 == 1] - exps2 = [x//2 for x in phi_exps if x%2 == 0] + exps1 = [(x+1)//2 for x in phi_exps if x % 2 == 1] + exps2 = [x//2 for x in phi_exps if x % 2 == 0] theta1 = 0 for exp in exps1: @@ -1794,95 +1869,109 @@ def supplementary_difference_set(q, existence=False, check=True): theta2 = 0 for exp in exps2: theta2 += P.monomial(exp) - theta2 = theta2.mod(P.monomial(q-1)-1) - - phi1 = 0 - phi2 = 0 - for exp in phi_exps: - if exp%2 == 0: - phi2 += P.monomial(exp) - else: - phi1 += P.monomial(exp) + theta2 = theta2.mod(P.monomial(q-1) - 1) psi1 = ((1 + P.monomial((q-1)//2)) * theta1).mod(P.monomial(q-1) - 1) psi2 = (1 + (1 + P.monomial((q-1)//2)) * theta2).mod(P.monomial(q-1) - 1) + from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup + G = AdditiveAbelianGroup([q-1]) + K1 = [G[x] for x in psi1.exponents()] + K2 = [G[x] for x in psi2.exponents()] + K3 = [G[x] for x in psi3.exponents()] + K4 = [G[x] for x in psi4.exponents()] - K1 = list(map(Integer, psi1.exponents())) - K2 = list(map(Integer, psi2.exponents())) - K3 = list(map(Integer, psi3.exponents())) - K4 = list(map(Integer, psi4.exponents())) if check: - assert is_supplementary_difference_set([K1, K2, K3, K4], q-1, q-1) + assert is_supplementary_difference_set([K1, K2, K3, K4], lmbda=q-1, G=G) - return K1, K2, K3, K4 + return G, [K1, K2, K3, K4] -def _get_fixed_relative_difference_set(rel_diff_set, as_elements=False): - r"""Contruct an equivalent relative difference set fixed by the size of the set. + +def supplementary_difference_set(q, existence=False, check=True): + r""" + Construct `4-\{2v; v, v+1, v, v; 2v\}` supplementary difference sets where `q=2v+1`. + + This is a deprecated version of :func:`supplementary_difference_set_from_rel_diff_set`, + please use that instead. + """ + from sage.misc.superseded import deprecation + deprecation(35211, 'This function is deprecated, please use supplementary_difference_set_from_rel_diff_set instead.') + + if existence: + return supplementary_difference_set_from_rel_diff_set(q, existence=True) + _, s = supplementary_difference_set_from_rel_diff_set(q, check=check) + return s + + +def get_fixed_relative_difference_set(G, rel_diff_set, as_elements=False): + r""" + Construct an equivalent relative difference set fixed by the size of the set. Given a relative difference set `R(q+1, q-1, q, 1)`, it is possible to find a translation of this set fixed by `q` (see Section 3 of [Spe1975]_). We say that a set is fixed by `t` if `\{td | d\in R\}= R`. In addition, the set returned by this function will contain the element `0`. This is needed in the - construction of supplementary difference sets (see :func:`supplementary_difference_set`). + construction of supplementary difference sets (see :func:`supplementary_difference_set_from_rel_diff_set`). INPUT: - - ``rel_diff_set`` -- the relative difference set. - - - ``as_elements`` -- boolean (default False). If true, the list returned will contain elements of the - abelian group (this may slow down the computation considerably). + - ``G`` -- a group, of which ``rel_diff_set`` is a subset + - ``rel_diff_set`` -- the relative difference set + - ``as_elements`` -- boolean (default: ``False``); if ``True``, the list + returned will contain elements of the abelian group (this may slow down + the computation considerably) OUTPUT: - By default, this function returns the set as a list of integers. However, if ``as_elements`` - is set to true it will return the set as a list containing elements of the abelian group. + By default, this function returns the set as a list of integers. However, if + ``as_elements=True`` it will return the set as a list containing elements of + the abelian group. If no such set can be found, the function will raise an error. EXAMPLES:: - sage: from sage.combinat.designs.difference_family import relative_difference_set_from_m_sequence, _get_fixed_relative_difference_set - sage: s1 = relative_difference_set_from_m_sequence(5, 2) - sage: _get_fixed_relative_difference_set(s1) #random + sage: from sage.combinat.designs.difference_family import relative_difference_set_from_m_sequence, get_fixed_relative_difference_set + sage: G, s1 = relative_difference_set_from_m_sequence(5, 2, return_group=True) # needs sage.libs.pari sage.modules + sage: get_fixed_relative_difference_set(G, s1) # random # needs sage.libs.pari sage.modules [2, 10, 19, 23, 0] - If ``as_elements`` is true, the reuslt will contain elements of the group:: + If ``as_elements=True``, the result will contain elements of the group:: - sage: _get_fixed_relative_difference_set(s1, as_elements=True) #random + sage: get_fixed_relative_difference_set(G, s1, as_elements=True) # random # needs sage.libs.pari sage.modules [(2), (10), (19), (23), (0)] TESTS:: - sage: from sage.combinat.designs.difference_family import _is_fixed_relative_difference_set - sage: s1 = relative_difference_set_from_m_sequence(5, 2) - sage: s2 = _get_fixed_relative_difference_set(s1, as_elements=True) - sage: _is_fixed_relative_difference_set(s2, len(s2)) + sage: # needs sage.libs.pari sage.modules + sage: from sage.combinat.designs.difference_family import is_fixed_relative_difference_set + sage: G, s1 = relative_difference_set_from_m_sequence(5, 2, return_group=True) + sage: s2 = get_fixed_relative_difference_set(G, s1, as_elements=True) + sage: is_fixed_relative_difference_set(s2, len(s2)) True - sage: s1 = relative_difference_set_from_m_sequence(9, 2) - sage: s2 = _get_fixed_relative_difference_set(s1, as_elements=True) - sage: _is_fixed_relative_difference_set(s2, len(s2)) + sage: G, s1 = relative_difference_set_from_m_sequence(9, 2, return_group=True) + sage: s2 = get_fixed_relative_difference_set(G, s1, as_elements=True) + sage: is_fixed_relative_difference_set(s2, len(s2)) True sage: type(s2[0]) <class 'sage.groups.additive_abelian.additive_abelian_group.AdditiveAbelianGroup_fixed_gens_with_category.element_class'> - sage: s2 = _get_fixed_relative_difference_set(s1) + sage: s2 = get_fixed_relative_difference_set(G, s1) sage: type(s2[0]) <class 'sage.rings.integer.Integer'> """ - G = rel_diff_set[0].parent() q = len(rel_diff_set) s2 = None for el in G: fixed_set = [el+x for x in rel_diff_set] - if _is_fixed_relative_difference_set(fixed_set, q): + if is_fixed_relative_difference_set(fixed_set, q): s2 = fixed_set break assert s2 is not None, 'Cannot find fixed translation of the set' s3 = None for i in range(G.order()): - temp = [((q+1)*i+x[0])%G.order() for x in s2] + temp = [((q+1)*i+x[0]) % G.order() for x in s2] if 0 in temp: s3 = temp break @@ -1892,76 +1981,273 @@ def _get_fixed_relative_difference_set(rel_diff_set, as_elements=False): return [G[x] for x in s3] return s3 -def _is_fixed_relative_difference_set(R, q): - r"""Check if the relative difference set `R` is fixed by `q`. - A relative difference set `R` is fixed by `q` if `\{qd | d\in R\}= R` (see Section 3 of [Spe1975]_). +def is_fixed_relative_difference_set(R, q): + r""" + Check if the relative difference set ``R`` is fixed by ``q``. - INPUT: + A relative difference set `R` is fixed by `q` if `\{qd | d \in R\}= R` (see Section 3 of [Spe1975]_). - - ``R`` -- the relative difference sets, as a list containing elements of the abelian group. + INPUT: - - ``q`` -- an integer. + - ``R`` -- a list containing elements of an abelian group; the relative + difference set + - ``q`` -- an integer EXAMPLES:: - sage: from sage.combinat.designs.difference_family import relative_difference_set_from_m_sequence, _get_fixed_relative_difference_set, _is_fixed_relative_difference_set - sage: s1 = relative_difference_set_from_m_sequence(7, 2) - sage: s2 = _get_fixed_relative_difference_set(s1, as_elements=True) - sage: _is_fixed_relative_difference_set(s2, len(s2)) + sage: # needs sage.modules + sage: from sage.combinat.designs.difference_family import relative_difference_set_from_m_sequence, get_fixed_relative_difference_set, is_fixed_relative_difference_set + sage: G, s1 = relative_difference_set_from_m_sequence(7, 2, return_group=True) # needs sage.libs.pari + sage: s2 = get_fixed_relative_difference_set(G, s1, as_elements=True) # needs sage.libs.pari + sage: is_fixed_relative_difference_set(s2, len(s2)) # needs sage.libs.pari True sage: G = AdditiveAbelianGroup([15]) sage: s3 = [G[1], G[2], G[3], G[4]] - sage: _is_fixed_relative_difference_set(s3, len(s3)) + sage: is_fixed_relative_difference_set(s3, len(s3)) False If the relative difference set does not contain elements of the group, the method returns false:: - sage: s1 = relative_difference_set_from_m_sequence(7, 2) - sage: s2 = _get_fixed_relative_difference_set(s1, as_elements=False) - sage: _is_fixed_relative_difference_set(s2, len(s2)) + sage: G, s1 = relative_difference_set_from_m_sequence(7, 2, return_group=True) # needs sage.libs.pari sage.modules + sage: s2 = get_fixed_relative_difference_set(G, s1, as_elements=False) # needs sage.libs.pari sage.modules + sage: is_fixed_relative_difference_set(s2, len(s2)) # needs sage.libs.pari sage.modules False - - """ for el in R: - if q*el not in R: + if q * el not in R: return False return True -def skew_supplementary_difference_set(n, existence=False, check=True): - r"""Construct `4-\{n; n_1, n_2, n_3, n_4; \lambda\}` supplementary difference sets where `S_1` is skew and `n_1+n_2+n_3+n_4= n+\lambda`. +def skew_supplementary_difference_set_over_polynomial_ring(n, existence=False, check=True): + r""" + Construct skew supplementary difference sets over a polynomial ring of order ``n``. + + The skew supplementary difference sets for `n=81, 169` are taken from [Djo1994a]_. + + INPUT: + + - ``n`` -- integer; the parameter of the supplementary difference sets + - ``existence`` -- boolean (default: ``False``); if ``True``, only check + whether the supplementary difference sets can be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the sets + are supplementary difference sets with `S_1` skew before returning them; + setting this parameter to ``False`` may speed up the computation considerably + + OUTPUT: + + If ``existence=False``, the function returns a Polynomial Ring of order ``n`` + and a list containing 4 sets, or raises an error if data for the given ``n`` + is not available. + If ``existence=True``, the function returns a boolean representing whether + skew supplementary difference sets can be constructed. + + EXAMPLES:: + + sage: from sage.combinat.designs.difference_family import skew_supplementary_difference_set_over_polynomial_ring + sage: G, [S1, S2, S3, S4] = skew_supplementary_difference_set_over_polynomial_ring(81) # needs sage.libs.pari + + If ``existence=True``, the function returns a boolean:: + + sage: skew_supplementary_difference_set_over_polynomial_ring(81, existence=True) + True + sage: skew_supplementary_difference_set_over_polynomial_ring(17, existence=True) + False + + TESTS:: + + sage: skew_supplementary_difference_set_over_polynomial_ring(7) + Traceback (most recent call last): + ... + NotImplementedError: skew SDS of order 7 not yet implemented + """ + data = { + 81: (3, lambda x: x**4 - x**3 - 1, 16, 5, + [1, 2, 4, 6, 8, 10, 12, 14], [1, 2, 3, 4, 10, 11, 13], + [4, 5, 6, 8, 12, 13, 14], [2, 4, 5, 6, 7, 11, 12, 13, 15]), + 169: (13, lambda x: x**2 - 4*x + 6, 24, 7, + [0, 2, 5, 7, 9, 10, 12, 15, 16, 18, 21, 22], [0, 1, 2, 7, 8, 9, 13, 14, 18, 20, 23], + [1, 4, 6, 7, 9, 14, 16, 17, 20, 21, 23], [3, 5, 6, 9, 10, 12, 13, 14, 15, 17, 20]) + } + + if existence: + return n in data + + if n not in data: + raise NotImplementedError(f'skew SDS of order {n} not yet implemented') + + mod, poly, exp, order, ind1, ind2, ind3, ind4 = data[n] + + from sage.rings.finite_rings.integer_mod_ring import Zmod + + Z3 = Zmod(mod) + R = ZZ['x'] + x = R.gen() + F = Z3.extension(poly(x)) + + H = [F.gen() ** (exp * i) for i in range(order)] + + cosets = [] + for i in range((n - 1) // (2 * order)): + cosets.append([F.gen()**i * el for el in H]) + cosets.append([-F.gen()**i * el for el in H]) + + def generate_set(index_set, cosets): + return sum((cosets[idx] for idx in index_set), []) - These sets are constructed from available data, as described in [Djo1994]_. The set `S_1 \subset G` is - always skew, i.e. `S_1 \cap (-S_1) = \emptyset` and `S_1 \cup (-S_1) = G\setminus\{0\}`. + S1 = generate_set(ind1, cosets) + S2 = generate_set(ind2, cosets) + S3 = generate_set(ind3, cosets) + S4 = generate_set(ind4, cosets) - The data for `n = 103, 151` is taken from [Djo1994]_ and the data for `n = 67, 113, 127, 157, 163, 181, 241` - is taken from [Djo1992]_. + if check: + lmbda = len(S1) + len(S2) + len(S3) + len(S4) - n + assert is_supplementary_difference_set([S1, S2, S3, S4], lmbda=lmbda, G=F) + assert _is_skew_set(F, S1) + + return F, [S1, S2, S3, S4] + + +def skew_supplementary_difference_set_with_paley_todd(n, existence=False, check=True): + r""" + Construct `4-\{n; n_1, n_2, n_3, n_4; \lambda\}` skew supplementary difference sets where `S_1` is the Paley-Todd difference set. + + The skew SDS returned have the property that `n_1 + n_2 + n_3 + n_4 = n + \lambda`. + + This construction is described in [DK2016]_. The function contains, for each + value of `n`, a set `H` containing integers modulo `n`, and four sets `J, K, L`. + Then, these are used to construct `(n; k_2, k_3, k_4; \lambda_2)` difference family, + with `\lambda_2 = k_2 + k_3 + k_4 + (3n - 1) / 4`. Finally, these sets together + with the Paley-Todd difference set form a skew supplementary difference set. INPUT: - - ``n`` -- integer, the parameter of the supplementary difference set. + - ``n`` -- integer; the parameter of the supplementary difference set + - ``existence`` -- boolean (default: ``False``); if ``True``, only check + whether the supplementary difference sets can be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the sets + are supplementary difference sets with `S_1` skew before returning them; + setting this parameter to ``False`` may speed up the computation considerably + + OUTPUT: + + If ``existence=False``, the function returns the group G of integers modulo + ``n`` and a list containing 4 sets, or raises an error if data for the given + ``n`` is not available. + If ``existence=True``, the function returns a boolean representing whether + skew supplementary difference sets can be constructed. + + EXAMPLES:: - - ``existence`` -- boolean (dafault False). If true, only check whether the supplementary difference sets - can be constructed. + sage: from sage.combinat.designs.difference_family import skew_supplementary_difference_set_with_paley_todd + sage: G, [S1, S2, S3, S4] = skew_supplementary_difference_set_with_paley_todd(239) - - ``check`` -- boolean (default True). If true, check that the sets are supplementary difference sets - with `S_1` skew before returning them. Setting this parameter to False may speed up the computation considerably. + If existence is ``True``, the function returns a boolean:: + + sage: skew_supplementary_difference_set_with_paley_todd(239, existence=True) + True + sage: skew_supplementary_difference_set_with_paley_todd(17, existence=True) + False + + TESTS:: + + sage: skew_supplementary_difference_set_with_paley_todd(7) + Traceback (most recent call last): + ... + NotImplementedError: data for skew SDS of order 7 not yet implemented + """ + H_db = { + 239: [1, 10, 24, 44, 98, 100, 201], + } + + indices = { + 239: [[1, 3, 5, 6, 15, 17, 19, 28, 34, 38, 39, 57, 58, 63, 85, 95, 107], + [1, 3, 4, 5, 15, 16, 17, 18, 19, 21, 23, 29, 35, 45, 58, 63], + [0, 1, 4, 6, 7, 8, 13, 16, 18, 34, 35, 45, 47, 58, 63, 95]], + } + + if existence: + return n in H_db + + if n not in H_db: + raise NotImplementedError(f'data for skew SDS of order {n} not yet implemented') + + G = Zmod(n) + H = {G(el) for el in H_db[n]} + + def generate_subset(indices, H): + return list({el * idx for el in H for idx in indices}) + + from sage.arith.misc import quadratic_residues + + S1 = [G(el) for el in quadratic_residues(n) if el != 0] + S2 = generate_subset(indices[n][0], H) + S3 = generate_subset(indices[n][1], H) + S4 = generate_subset(indices[n][2], H) + + if check: + lmbda = len(S1) + len(S2) + len(S3) + len(S4) - n + assert is_supplementary_difference_set([S1, S2, S3, S4], lmbda=lmbda, G=G) + assert _is_skew_set(G, S1) + + return G, [S1, S2, S3, S4] + + +def skew_supplementary_difference_set(n, existence=False, check=True, return_group=False): + r""" + Construct `4-\{n; n_1, n_2, n_3, n_4; \lambda\}` supplementary difference sets, + where `S_1` is skew and `n_1 + n_2 + n_3 + n_4 = n+\lambda`. + + These sets are constructed from available data, as described in [Djo1994a]_. The set `S_1 \subset G` is + always skew, i.e. `S_1 \cap (-S_1) = \emptyset` and `S_1 \cup (-S_1) = G \setminus \{0\}`. + + The data is taken from: + + * `n = 103, 151`: [Djo1994a]_ + * `n = 67, 113, 127, 157, 163, 181, 241`: [Djo1992a]_ + * `n = 37, 43`: [Djo1992b]_ + * `n = 39, 49, 65, 93, 121, 129, 133, 217, 219, 267`: [Djo1992c]_ + * `n = 97`: [Djo2008a]_ + * `n = 109, 145, 247`: [Djo2008b]_ + * `n = 73`: [Djo2023b]_ + * `n = 213, 631`: [DGK2014]_ + * `n = 331`: [DK2016]_ + + Additional skew Supplementary difference sets are built using the function + :func:`skew_supplementary_difference_set_over_polynomial_ring`, and + :func:`skew_supplementary_difference_set_with_paley_todd`. + + INPUT: + + - ``n`` -- integer; the parameter of the supplementary difference set + - ``existence`` -- boolean (default: ``False``); if ``True``, only check + whether the supplementary difference sets can be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the sets + are supplementary difference sets with `S_1` skew before returning them; + setting this parameter to ``False`` may speed up the computation considerably + - ``return_group`` -- boolean (default: ``False``); if ``True``, the function + will also return the group from which the sets are created OUTPUT: - If ``existence`` is false, the function returns the 4 sets (containing integers modulo `n`), or raises an - error if data for the given ``n`` is not available. - If ``existence`` is true, the function returns a boolean representing whether skew supplementary difference - sets can be constructed. + If ``existence=False``, the function returns a list containing 4 sets, + or raises an error if data for the given ``n`` is not available. If + ``return_group=True`` the function will additionally return the group from + which the sets are created. + If ``existence=True``, the function returns a boolean representing whether + skew supplementary difference sets can be constructed. EXAMPLES:: sage: from sage.combinat.designs.difference_family import skew_supplementary_difference_set - sage: S1, S2, S3, S4 = skew_supplementary_difference_set(103) + sage: [S1, S2, S3, S4] = skew_supplementary_difference_set(39) + + If ``return_group=True``, the function will also return the group:: - If existence is ``True``, the function returns a boolean :: + sage: G, [S1, S2, S3, S4] = skew_supplementary_difference_set(103, return_group=True) + + If ``existence=True``, the function returns a boolean:: sage: skew_supplementary_difference_set(103, existence=True) True @@ -1971,15 +2257,15 @@ def skew_supplementary_difference_set(n, existence=False, check=True): TESTS:: sage: from sage.combinat.designs.difference_family import is_supplementary_difference_set, _is_skew_set - sage: S1, S2, S3, S4 = skew_supplementary_difference_set(113, check=False) - sage: is_supplementary_difference_set([S1, S2, S3, S4], 113, len(S1)+len(S2)+len(S3)+len(S4)-113) + sage: G, [S1, S2, S3, S4] = skew_supplementary_difference_set(113, check=False, return_group=True) + sage: is_supplementary_difference_set([S1, S2, S3, S4], lmbda=len(S1)+len(S2)+len(S3)+len(S4)-113, G=G) True - sage: _is_skew_set(S1, 113) + sage: _is_skew_set(G, S1) True - sage: S1, S2, S3, S4 = skew_supplementary_difference_set(67, check=False) - sage: is_supplementary_difference_set([S1, S2, S3, S4], 67, len(S1)+len(S2)+len(S3)+len(S4)-67) + sage: G, [S1, S2, S3, S4] = skew_supplementary_difference_set(67, check=False, return_group=True) + sage: is_supplementary_difference_set([S1, S2, S3, S4], lmbda=len(S1)+len(S2)+len(S3)+len(S4)-67, G=G) True - sage: _is_skew_set(S1, 67) + sage: _is_skew_set(G, S1) True sage: skew_supplementary_difference_set(7) Traceback (most recent call last): @@ -1989,134 +2275,454 @@ def skew_supplementary_difference_set(n, existence=False, check=True): False sage: skew_supplementary_difference_set(127, existence=True) True - """ + sage: skew_supplementary_difference_set(81, existence=True) + True + .. NOTE:: + The data for `n=247` in [Djo2008b]_ contains a typo: the set `\alpha_2` should contain `223` instead of `233`. + This can be verified by checking the resulting sets, which are given explicitly in the paper. + """ + + # If -1 is present in an index set, it means that {0} should be added to that set indices = { - 67: [[0,3,5,6,9,10,13,14,17,18,20], - [0,2,4,9,11,12,13,16,19,21], - [1,3,6,10,11,13,14,16,20,21], - [2,4,6,8,9,11,14,17,19]], - 103: [[1,3,4,6,8,11,12,14,17,18,20,22,25,27,28,30,32], - [2,9,10,12,13,14,15,16,20,21,22,23,24,26,28,29,30], - [0,1,2,3,4,11,12,13,16,17,19,20,21,24,25,26,28,30,31], - [0,1,2,3,4,5,6,13,15,18,19,20,23,24,25,26,27,28,29,31]], - 113: [[0,3,4,6,8,10,13,14], - [1,3,8,9,10,11,12,13], - [0,2,3,5,6,7,12], - [1,2,3,5,8,9,15]], - 127: [[0,3,5,7,8,10,12,14,16], - [0,1,3,6,7,9,10,12,14,15], - [0,1,3,4,5,7,8,9,15,16], - [1,4,5,6,9,10,13,14,15,16]], - 151: [[0,3,5,6,8,11,13,14,16,19,21,23,25,27,28], - [2,3,6,13,16,17,20,23,25,26,27,28,29], - [0,1,2,3,4,6,7,8,9,10,11,12,23,24,27,28], - [1,4,5,10,11,12,13,14,16,18,19,22,25,26,27,28]], - 157:[[0,2,5,7,8,11], - [0,4,5,6,9,11], - [6,7,8,9,10,11], - [0,5,6,7,8,10,11]], - 163: [[0,2,5,6,9,10,13,14,17], - [0,1,7,10,12,15,16,17], - [0,1,3,5,8,13,15,16,17], - [3,6,7,8,11,12,13,14,16,17]], - 181: [[0,3,5,6,8,10,13,15,16,19], - [4,5,7,8,11,14,15,16,18,19], - [0,4,10,11,13,15,16,18,19], - [2,4,5,7,11,13,15,17,19]], - 241: [[0,2,4,6,8,11,12,14], - [1,3,4,6,7,13,14,15], - [6,8,9,10,12,13,14,15], - [3,4,5,9,10,13,14]], + 37: [[0, 3, 5, 7, 9, 10], [0, 5, 6, 7, 8], + [1, 2, 6, 7, 9], [2, 6, 8, 9, 10]], + 39: [[1, 3, 5, 6, 8, 10, 12], [0, 1, 5, 8, 12, 13], + [1, 3, 4, 7, 9, 12, 13], [0, 1, 2, 3, 7, 8]], + 43: [[1, 2, 4], [1, 2, 4], [0, 2, 3], [3, 4, -1]], + 49: [[1, 2, 5, 7, 8, 10, 13, 14], [4, 5, 6, 7, 10, 11], + [0, 1, 2, 4, 6, 7, 12, 14], [1, 2, 3, 5, 6, 10, 12, 13, 14]], + 65: [[1, 3, 5, 6, 8, 10, 13, 14, 17, 18, 20, 22], + [0, 3, 7, 10, 16, 17, 18, 20, 21], + [2, 4, 6, 8, 9, 10, 14, 15, 16, 17, 18, 20], + [5, 7, 8, 9, 11, 12, 13, 14, 16, 18, 19, 20, 21]], + 67: [[0, 3, 5, 6, 9, 10, 13, 14, 17, 18, 20], + [0, 2, 4, 9, 11, 12, 13, 16, 19, 21], + [1, 3, 6, 10, 11, 13, 14, 16, 20, 21], + [2, 4, 6, 8, 9, 11, 14, 17, 19]], + 73: [[4, 6, 8, 14], [8, 10, 12, 14], [4, 6, 10, 12], [-1, 0, 2, 10]], + 93: [[0, 3, 4, 6, 9, 10, 12, 14, 17, 18], + [2, 3, 4, 5, 9, 13, 15, 18, 19], + [1, 2, 3, 4, 5, 6, 7, 8, 16], + [1, 4, 6, 11, 12, 13, 15, 16, 17, 18]], + 97: [[1, 2, 4, 6, 9, 11, 13, 14, 17, 18, 21, 23, 25, 27, 29, 30], + [1, 2, 6, 7, 8, 9, 10, 11, 12, 13, 23, 27, 29], + [0, 1, 2, 5, 6, 12, 13, 15, 16, 20, 24, 25, 26, 29, 30, 31], + [0, 2, 3, 4, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 23, 28, 29]], + 103: [[1, 3, 4, 6, 8, 11, 12, 14, 17, 18, 20, 22, 25, 27, 28, 30, 32], + [2, 9, 10, 12, 13, 14, 15, 16, 20, 21, 22, 23, 24, 26, 28, 29, 30], + [0, 1, 2, 3, 4, 11, 12, 13, 16, 17, 19, 20, 21, 24, 25, 26, 28, 30, 31], + [0, 1, 2, 3, 4, 5, 6, 13, 15, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29, 31]], + 109: [[0, 2, 5, 7, 8, 10, 12, 15, 16, 19, 20, 23, 24, 26, 29, 30, 33, 34], + [4, 5, 6, 7, 11, 15, 18, 19, 20, 22, 25, 30, 32, 33, 35], + [0, 1, 5, 6, 9, 10, 11, 14, 17, 20, 24, 26, 27, 28, 29, 31, 32], + [0, 3, 4, 6, 7, 9, 10, 12, 13, 22, 24, 25, 26, 27, 28, 29, 31, 33, 35]], + 113: [[0, 3, 4, 6, 8, 10, 13, 14], + [1, 3, 8, 9, 10, 11, 12, 13], + [0, 2, 3, 5, 6, 7, 12], + [1, 2, 3, 5, 8, 9, 15]], + 121: [[0, 2, 4, 7, 8, 11, 13, 14, 16, 19, 20, 22], + [0, 1, 4, 5, 8, 9, 10, 15, 17, 20, 23], + [1, 2, 3, 7, 9, 16, 18, 19, 20, 21, 22, 23], + [0, 2, 9, 10, 11, 12, 13, 14, 15, 17, 18, 21, 22, 23]], + 127: [[0, 3, 5, 7, 8, 10, 12, 14, 16], + [0, 1, 3, 6, 7, 9, 10, 12, 14, 15], + [0, 1, 3, 4, 5, 7, 8, 9, 15, 16], + [1, 4, 5, 6, 9, 10, 13, 14, 15, 16]], + 129: [[1, 2, 4, 7, 9, 11, 12, 14, 16, 18], + [0, 1, 2, 3, 9, 11, 14, 15, 19], + [0, 1, 3, 6, 8, 10, 12, 16, 18, 19], + [0, 3, 7, 8, 9, 10, 12, 14, 15, 17]], + 133: [[1, 2, 5, 6, 9, 11, 12, 14], [1, 4, 7, 9, 10, 12, 13, 15], + [0, 5, 6, 8, 11, 12, 13, 15], [0, 1, 2, 5, 7, 8, 9, 13, 14, 15]], + 145: [[1, 2, 4, 7, 9, 10, 13, 14, 16, 19, 20, 22], [0, 2, 4, 7, 10, 11, 14, 18, 19, 20, 21, 22], + [1, 3, 6, 9, 12, 13, 14, 17, 19, 20, 21, 22, 23], [2, 3, 5, 6, 7, 9, 12, 13, 15, 16, 19, 20, 21, 22, 23]], + 151: [[0, 3, 5, 6, 8, 11, 13, 14, 16, 19, 21, 23, 25, 27, 28], + [2, 3, 6, 13, 16, 17, 20, 23, 25, 26, 27, 28, 29], + [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 23, 24, 27, 28], + [1, 4, 5, 10, 11, 12, 13, 14, 16, 18, 19, 22, 25, 26, 27, 28]], + 157: [[0, 2, 5, 7, 8, 11], + [0, 4, 5, 6, 9, 11], + [6, 7, 8, 9, 10, 11], + [0, 5, 6, 7, 8, 10, 11]], + 163: [[0, 2, 5, 6, 9, 10, 13, 14, 17], + [0, 1, 7, 10, 12, 15, 16, 17], + [0, 1, 3, 5, 8, 13, 15, 16, 17], + [3, 6, 7, 8, 11, 12, 13, 14, 16, 17]], + 181: [[0, 3, 5, 6, 8, 10, 13, 15, 16, 19], + [4, 5, 7, 8, 11, 14, 15, 16, 18, 19], + [0, 4, 10, 11, 13, 15, 16, 18, 19], + [2, 4, 5, 7, 11, 13, 15, 17, 19]], + 213: [[1, 2, 5, 6, 9, 11, 12, 14, 16, 19, 20, 23, 24, 26, 29, 30], + [3, 6, 8, 12, 13, 14, 15, 17, 20, 22, 23, 25, 26, 27, 28, 31], + [2, 3, 5, 7, 9, 13, 16, 17, 19, 21, 23, 24, 27, 28, 29], + [0, 5, 6, 9, 11, 13, 14, 17, 20, 22, 23, 26, 29, 31]], + 217: [[0, 3, 5, 7, 8, 11, 12, 14], [1, 3, 4, 7, 9, 11, 12, 15], + [3, 4, 5, 6, 7, 9, 10, 14, 15], [1, 3, 4, 5, 7, 8, 11, 13, 14]], + 219: [[1, 3, 5, 6, 8, 11, 12, 15, 17, 18, 21, 22, 24], + [2, 6, 8, 10, 11, 12, 13, 16, 19, 22, 23, 24], + [0, 1, 5, 6, 10, 11, 13, 14, 17, 20, 21, 24, 25], + [0, 2, 3, 4, 5, 6, 7, 11, 12, 13, 16, 20, 23]], + 241: [[0, 2, 4, 6, 8, 11, 12, 14], + [1, 3, 4, 6, 7, 13, 14, 15], + [6, 8, 9, 10, 12, 13, 14, 15], + [3, 4, 5, 9, 10, 13, 14]], + 247: [[0, 2, 4, 7, 8, 10, 12, 15, 16, 18, 20, 23, 25, 27, 29], + [0, 2, 7, 9, 11, 12, 14, 15, 16, 18, 20, 22, 26], + [2, 3, 4, 12, 13, 14, 15, 16, 18, 20, 23, 24, 26, 27, 29], + [0, 3, 4, 6, 10, 11, 12, 14, 18, 19, 20, 22, 25, 29]], + 267: [[0, 3, 4, 7, 8, 11, 13, 15, 16, 19, 21, 22, 25], + [0, 1, 4, 5, 6, 8, 14, 15, 18, 21, 23], + [0, 2, 4, 5, 7, 9, 10, 11, 14, 15, 16, 17, 25], + [0, 1, 3, 4, 6, 14, 15, 16, 17, 18, 20, 22, 23, 25]], + 331: [[1, 2, 4, 7, 9, 10, 12, 15, 16, 18, 21, 22, 24, 26, 28], + [-1, 0, 2, 6, 9, 11, 12, 14, 15, 17, 20, 21, 24, 25, 28], + [-1, 0, 1, 5, 6, 7, 8, 9, 10, 12, 15, 18, 23, 28, 29], + [-1, 0, 3, 7, 8, 10, 11, 12, 14, 16, 19, 20, 21, 26, 29]], + 631: [[0, 2, 4, 6, 9, 10, 12, 15, 16, 18, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 40], + [0, 1, 2, 4, 6, 8, 9, 10, 11, 12, 13, 14, 16, 20, 23, 28, 29, 30, 32, 36, 38, 41], + [0, 2, 3, 4, 6, 9, 10, 12, 14, 15, 16, 17, 18, 19, 20, 22, 24, 25, 26, 29, 34, 40], + [0, 2, 4, 5, 6, 7, 8, 10, 15, 16, 18, 22, 23, 24, 26, 30, 31, 33, 35, 36, 37, 38]], } + # If the element is a list, that is the coset. cosets_gens = { - 67: [1,2,3,4,5,6,8,10,12,15,17], + 37: [1, 2, 3, 5, 6, 9], + 39: [1, 2, 3, 4, 6, 8, [13]], + 43: [1, 3, 7], + 49: [1, 2, 3, 4, 6, 7, 9, 12], + 65: [1, 2, 3, 5, 6, 7, 9, 10, 11, [13], 22, [26]], + 67: [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17], + 73: [1, 3, 5, 9, 11, 13, 17, 25], + 93: [1, 2, 3, 5, 7, 9, 10, 14, 15, [31]], + 97: [1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 13, 15, 18, 20, 23, 26], 103: [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 15, 17, 19, 21, 23, 30], + 109: [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 13, 15, 16, 18, 20, 23, 25, 30], 113: [1, 2, 3, 5, 6, 9, 10, 13], + 121: [1, 2, 4, 5, 7, 8, 10, 11, 16, 17, 19, 20], 127: [1, 3, 5, 7, 9, 11, 13, 19, 21], - 151: [1, 2, 3 ,4, 5, 6, 9, 10, 11, 12, 15, 22, 27, 29, 30], + 129: [1, 3, 5, 7, 9, 11, 13, 19, 21, [43]], + 133: [1, 2, 3, 6, 7, 9, 18, [19, 38, 76]], + 145: [1, [2, 17, 32, 72, 77, 127, 137], [3, 43, 48, 98, 108, 118, 133], [6, 51, 71, 86, 91, 96, 121], + [7, 52, 82, 107, 112, 117, 132], [11, 21, 31, 46, 61, 101, 106], [14, 19, 69, 79, 89, 104, 119], + [22, 42, 57, 62, 67, 92, 122], [5, 35, 80, 100, 115, 120, 125], [10, 15, 55, 70, 85, 95, 105], + [29], [58]], + 151: [1, 2, 3, 4, 5, 6, 9, 10, 11, 12, 15, 22, 27, 29, 30], 157: [1, 2, 3, 5, 9, 15], 163: [1, 2, 3, 5, 6, 9, 10, 15, 18], 181: [1, 2, 3, 4, 6, 7, 8, 12, 13, 24], + 213: [1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 15, 20, 22, 30, 43, 71], + 217: [1, 2, 4, 5, 7, 10, 19, [31, 62, 124]], + 219: [1, 2, 3, 5, 7, 9, 11, 15, 19, 22, 23, 33, [73]], 241: [1, 2, 4, 5, 7, 13, 19, 35], + 247: [1, [2, 18, 31, 32, 41, 110, 122, 162, 223], [3, 27, 48, 165, 170, 183, 185, 211, 243], + [5, 28, 45, 58, 80, 158, 187, 201, 226], [6, 54, 83, 93, 96, 119, 123, 175, 239], [7, 20, 63, 73, 112, 138, 163, 180, 232], + [10, 56, 69, 90, 116, 127, 155, 160, 205], [11, 47, 99, 102, 111, 115, 150, 176, 177], [13, 52, 65, 78, 91, 117, 143, 208, 221], + [14, 29, 40, 79, 113, 126, 146, 217, 224], [17, 25, 43, 49, 140, 142, 153, 194, 225], [19, 57, 171], + [33, 34, 37, 50, 59, 86, 98, 141, 203], [35, 66, 68, 74, 100, 118, 159, 172, 196], [38, 95, 114]], + 267: [1, 2, 3, 5, 7, 9, 10, 13, 14, 15, 19, 39, [89]], + 331: [1, 2, 4, 5, 7, 8, 10, 13, 14, 16, 19, 20, 28, 32, 56], + 631: [1, 2, 3, 4, 5, 6, 7, 9, 12, 14, 17, 18, 19, 21, 23, 27, 31, 35, 38, 42, 62], } H_db = { + 37: [1, 10, -11], + 39: [1, 16, 22], + 43: [1, 4, 11, 16, 21, -2, -8], + 49: [1, 18, 30], + 65: [1, 16, 61], 67: [1, 29, 37], + 73: [1, 2, 4, 8, 16, 32, 64, 55, 37], + 93: [1, 4, 16, 64, 70], + 97: [1, 35, 61], 103: [1, 46, 56], - 113: [1,16,28,30,49,106,109], - 127: [1,2,4,8,16,32,64], - 151: [1, 8,19,59, 64], - 157: [1,14,16,39,46,67,75,93,99,101,108,130,153], - 163: [1,38,40,53,58,85,104,133,140], - 181: [1,39,43,48,62,65,73,80,132], - 241: [1,15,24,54,87,91,94,98,100,119,160,183,205,225,231], + 109: [1, 45, 63], + 113: [1, 16, 28, 30, 49, 106, 109], + 121: [1, 3, 9, 27, 81], + 127: [1, 2, 4, 8, 16, 32, 64], + 129: [1, 4, 16, 64, 97, 121, 127], + 133: [1, 4, 16, 25, 64, 93, 100, 106, 123], + 145: [1, 16, 36, 81, 111, 136, 141], + 151: [1, 8, 19, 59, 64], + 157: [1, 14, 16, 39, 46, 67, 75, 93, 99, 101, 108, 130, 153], + 163: [1, 38, 40, 53, 58, 85, 104, 133, 140], + 181: [1, 39, 43, 48, 62, 65, 73, 80, 132], + 213: [1, 37, 91, 103, 172, 187, 190], + 217: [1, 8, 9, 25, 51, 64, 72, 78, 81, 142, 190, 191, 193, 200, 214], + 219: [1, 4, 16, 37, 55, 64, 148, 154, 178], + 241: [1, 15, 24, 54, 87, 91, 94, 98, 100, 119, 160, 183, 205, 225, 231], + 247: [1, 9, 16, 55, 61, 81, 139, 144, 235], + 267: [1, 4, 16, 64, 67, 91, 97, 121, 217, 223, 256], + 331: [1, 74, 80, 85, 111, 120, 167, 180, 270, 274, 293], + 631: [1, 8, 43, 64, 79, 188, 228, 242, 279, 310, 339, 344, 512, 562, 587], } - def generate_set(index_set, cosets): - S = [] - for idx in index_set: - S += cosets[idx] - return S + G, S1, S2, S3, S4 = None, [], [], [], [] + if n in indices: + if existence: + return True + G, [S1, S2, S3, S4] = _construction_supplementary_difference_set(n, H_db[n], indices[n], cosets_gens[n], check=False) + elif skew_supplementary_difference_set_over_polynomial_ring(n, existence=True): + if existence: + return True + G, [S1, S2, S3, S4] = skew_supplementary_difference_set_over_polynomial_ring(n, check=False) + elif skew_supplementary_difference_set_with_paley_todd(n, existence=True): + if existence: + return True + G, [S1, S2, S3, S4] = skew_supplementary_difference_set_with_paley_todd(n, check=False) if existence: - return n in indices + return False - if n not in indices: + if G is None: raise ValueError(f'Skew SDS of order {n} not yet implemented.') + if check: + lmbda = len(S1) + len(S2) + len(S3) + len(S4) - n + assert is_supplementary_difference_set([S1, S2, S3, S4], lmbda=lmbda, G=G) + assert _is_skew_set(G, S1) + + if return_group: + return G, [S1, S2, S3, S4] + return [S1, S2, S3, S4] + + +def _construction_supplementary_difference_set(n, H, indices, cosets_gen, check=True): + r""" + Construct `4-\{n; n_1, n_2, n_3, n_4; \lambda\}` supplementary difference sets, + where `n_1 + n_2 + n_3 + n_4 = n+\lambda`. + + This construction is described in [Djo1994a]_. + + Let H be a subgroup of Zmod(n) of order `t`. We construct the `2s = n/t` cosets + `\alpha_0, .., \alpha_{2s-1}` by using the elements contained in a sequence `A`: + `\alpha_{2i} = a_iH` and `\alpha_{2i+1} = -\alpha_{2i}`. + + Then, we use four indices sets `J_1, J_2, J_3, J_4` to construct the four + supplementary difference sets: `S_i = \bigcup_{j\in J__i} \alpha_i`. Note that + if `J_i` contains the value `-1`, this function will add `0` to the set `S_i`. + + To construct a coset `\alpha_{2i}` by listing it directly, replace the `2i`-th + element of the list `A` with the desired set. + + INPUT: + + - ``n`` -- integer; the parameter of the supplementary difference set + - ``H`` -- list of integers; the set `H` used to construct the cosets + - ``indices`` -- list containing four lists of integers; the sets + `J_1, J_2, J_3, J_4` described above + - ``cosets_gen`` -- list containing integers or list of integers; the set `A` + described above + - ``check`` -- boolean (default: ``True``); if ``True``, check that the sets + are supplementary difference sets; setting this parameter to ``False`` may + speed up the computation considerably + + OUTPUT: + + The function returns the ring of integers modulo ``n`` and a list containing + the 4 sets. + + TESTS:: + + sage: from sage.combinat.designs.difference_family import is_supplementary_difference_set, _construction_supplementary_difference_set + sage: H = [1, 10, -11] + sage: cosets_gen = [1, 2, 3, 5, 6, 9] + sage: indices = [[0, 3, 5, 7, 9, 10], [0, 5, 6, 7, 8], [1, 2, 6, 7, 9], [2, 6, 8, 9, 10]] + sage: _construction_supplementary_difference_set(37, H, indices, cosets_gen) + (Ring of integers modulo 37, + [[32, 1, 33, 35, 34, 7, 9, 10, 12, 14, 16, 17, 18, 22, 24, 26, 29, 31], + [32, 1, 33, 34, 5, 6, 7, 8, 10, 13, 18, 19, 23, 24, 26], + [32, 2, 36, 5, 11, 13, 14, 15, 18, 19, 20, 24, 27, 29, 31], + [2, 5, 6, 8, 9, 12, 13, 14, 15, 16, 19, 20, 23, 29, 31]]) + sage: H = [1, 16, 22] + sage: cosets_gen = [1, 2, 3, 4, 6, 8, [13]] + sage: indices = [[1, 3, 5, 6, 8, 10, 12], [0, 1, 5, 8, 12, 13], [1, 3, 4, 7, 9, 12, 13], [0, 1, 2, 3, 7, 8]] + sage: _construction_supplementary_difference_set(39, H, indices, cosets_gen) + (Ring of integers modulo 39, + [[4, 6, 7, 8, 10, 11, 12, 13, 15, 17, 18, 20, 23, 25, 30, 34, 36, 37, 38], + [1, 36, 38, 6, 12, 13, 15, 16, 17, 18, 22, 23, 26, 30], + [3, 7, 9, 13, 14, 17, 21, 23, 24, 26, 27, 29, 33, 34, 35, 37, 38], + [32, 1, 2, 34, 35, 5, 38, 37, 7, 6, 14, 15, 16, 17, 18, 22, 23, 29]]) + sage: H = [1, 4, 11, 16, 21, -2, -8] + sage: cosets_gen = [1, 3, 7] + sage: indices = [[1, 2, 4], [1, 2, 4], [0, 2, 3], [3, 4, -1]] + sage: G, sets = _construction_supplementary_difference_set(43, H, indices, cosets_gen, check=False) + sage: is_supplementary_difference_set(sets, lmbda=35, G=G) + True + + .. SEEALSO:: + + :func:`skew_supplementary_difference_set` + """ + def generate_set(index_set, cosets): + S = set() + for idx in index_set: + if idx == -1: + S.add(Z(0)) + else: + S = S.union(cosets[idx]) + return list(S) + Z = Zmod(n) - H = list(map(Z, H_db[n])) + H = set(map(Z, H)) cosets = [] - for el in cosets_gens[n]: - even_coset = [] - odd_coset = [] - for x in H: - even_coset.append(x*el) - odd_coset.append(-x*el) + for el in cosets_gen: + if isinstance(el, list): + even_coset = {Z(x) for x in el} + else: + even_coset = {x*el for x in H} + odd_coset = {-x for x in even_coset} cosets.append(even_coset) cosets.append(odd_coset) - S1 = generate_set(indices[n][0], cosets) - S2 = generate_set(indices[n][1], cosets) - S3 = generate_set(indices[n][2], cosets) - S4 = generate_set(indices[n][3], cosets) + S1 = generate_set(indices[0], cosets) + S2 = generate_set(indices[1], cosets) + S3 = generate_set(indices[2], cosets) + S4 = generate_set(indices[3], cosets) if check: - lmbda = len(S1)+len(S2)+len(S3)+len(S4) - n - assert is_supplementary_difference_set([S1, S2, S3, S4], n, lmbda) - assert _is_skew_set(S1, n) + lmbda = len(S1) + len(S2) + len(S3) + len(S4) - n + assert is_supplementary_difference_set([S1, S2, S3, S4], lmbda=lmbda, G=Z) - return S1, S2, S3, S4 + return Z, [S1, S2, S3, S4] -def _is_skew_set(S, n): - r"""Check if `S` is a skew set over the set of integers modulo `n`. - From [Djo1994]_, a set `S \subset G` (where `G` is a finite abelian group of order `n`) is of skew - type if `S_1 \cap (-S_1) = \emptyset` and `S_1 \cup (-S_1) = G\setminus \{0\}`. +def supplementary_difference_set_hadamard(n, existence=False, check=True): + r""" + Construct `4-\{n; n_1, n_2, n_3, n_4; \lambda\}` supplementary difference sets, + where `n_1 + n_2 + n_3 + n_4 = n+\lambda`. + + These sets are constructed from available data, as described in [Djo1994a]_. + The data is taken from: + + * `n = 191`: [Djo2008c]_ + * `n = 239`: [Djo1994b]_ + * `n = 251`: [DGK2014]_ + + Additional SDS are constructed using :func:`skew_supplementary_difference_set`. INPUT: - - ``S`` -- the set to be checked, containing integers modulo `n`. + - ``n`` -- integer; the parameter of the supplementary difference set + - ``existence`` -- boolean (default: ``False``); if ``True``, only check + whether the supplementary difference sets can be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the sets + are supplementary difference sets before returning them; Setting this + parameter to ``False`` may speed up the computation considerably - - ``n`` -- the order of `G`. + OUTPUT: + + If ``existence=False``, the function returns the ring of integers modulo + ``n`` and a list containing the 4 sets, or raises an error if data for the + given ``n`` is not available. + If ``existence=True``, the function returns a boolean representing whether + skew supplementary difference sets can be constructed. + + EXAMPLES:: + + sage: from sage.combinat.designs.difference_family import supplementary_difference_set_hadamard + sage: G, [S1, S2, S3, S4] = supplementary_difference_set_hadamard(191) + + If ``existence=True``, the function returns a boolean:: + + sage: supplementary_difference_set_hadamard(191, existence=True) + True + sage: supplementary_difference_set_hadamard(17, existence=True) + False + + TESTS:: + + sage: from sage.combinat.designs.difference_family import is_supplementary_difference_set + sage: G, [S1, S2, S3, S4] = supplementary_difference_set_hadamard(191, check=False) + sage: is_supplementary_difference_set([S1, S2, S3, S4], lmbda=len(S1)+len(S2)+len(S3)+len(S4)-191, G=G) + True + sage: G, [S1, S2, S3, S4] = supplementary_difference_set_hadamard(37, check=False) + sage: is_supplementary_difference_set([S1, S2, S3, S4], lmbda=len(S1)+len(S2)+len(S3)+len(S4)-37, G=G) + True + sage: supplementary_difference_set_hadamard(7) + Traceback (most recent call last): + ... + ValueError: SDS of order 7 not yet implemented. + sage: supplementary_difference_set_hadamard(7, existence=True) + False + sage: supplementary_difference_set_hadamard(127, existence=True) + True + """ + + indices = { + 191: [[1, 7, 9, 10, 11, 13, 17, 18, 25, 26, 30, 31, 33, 34, 35, 36, 37], + [1, 4, 7, 9, 11, 12, 13, 14, 19, 21, 22, 23, 24, 25, 26, 29, 36, 37], + [0, 3, 4, 5, 7, 8, 9, 16, 17, 19, 24, 25, 29, 30, 31, 33, 35, 37], + [1, 3, 4, 5, 8, 11, 14, 18, 19, 20, 21, 23, 24, 25, 28, 29, 30, 32, 34, 35]], + 239: [[0, 1, 2, 3, 4, 5, 6, 7, 14, 18, 19, 21, 24, 25, 29, 30], + [0, 1, 3, 7, 9, 12, 15, 18, 20, 22, 26, 28, 29, 30, 31, 32, 33], + [2, 3, 4, 5, 8, 9, 10, 11, 13, 17, 19, 21, 22, 24, 27, 31, 32], + [0, 1, 2, 3, 6, 7, 8, 11, 13, 15, 17, 18, 19, 22, 25, 26, 27, 32, 33]], + 251: [[2, 6, 8, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 27, 28, 35, 36, 39, 41, 43, 44, 47, 48], + [2, 5, 10, 11, 17, 18, 21, 23, 24, 25, 26, 28, 29, 30, 34, 35, 38, 39, 40, 41, 42, 43, 44, 49], + [0, 2, 6, 7, 10, 11, 14, 15, 16, 18, 21, 22, 24, 26, 30, 35, 37, 38, 45, 46, 47, 48, 49], + [1, 2, 3, 4, 8, 9, 12, 17, 21, 22, 27, 28, 29, 30, 33, 34, 39, 41, 42, 43, 46, 47, 48]], + } + + cosets_gens = { + 191: [1, 2, 3, 4, 6, 8, 9, 11, 12, 13, 16, 17, 18, 19, 22, 32, 36, 38, 41], + 239: [1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14, 15, 18, 21, 28, 35, 42], + 251: [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 14, 15, 17, 18, 19, 21, 28, 30, 33, 34, 35, 41, 43, 45, 68], + } + + H_db = { + 191: [1, 39, 184, 109, 49], + 239: [1, 10, 24, 44, 98, 100, 201], + 251: [1, 20, 113, 149, 219], + } + + if existence: + return n in indices or skew_supplementary_difference_set(n, existence=True) + + sets = None + G = None + if n in indices: + G, sets = _construction_supplementary_difference_set(n, H_db[n], indices[n], cosets_gens[n], check=False) + elif skew_supplementary_difference_set(n, existence=True): + G, sets = skew_supplementary_difference_set(n, check=False, return_group=True) + + if sets is None: + raise ValueError(f'SDS of order {n} not yet implemented.') + + S1, S2, S3, S4 = sets + if check: + lmbda = len(S1) + len(S2) + len(S3) + len(S4) - n + assert is_supplementary_difference_set([S1, S2, S3, S4], lmbda=lmbda, G=G) + + return G, [S1, S2, S3, S4] + + +def _is_skew_set(G, S): + r""" + Check if ``S`` is a skew set over the group ``G``. + + From [Djo1994a]_, a set `S \subset G` (where `G` is a finite abelian group of order `n`) is of skew + type if `S_1 \cap (-S_1) = \emptyset` and `S_1 \cup (-S_1) = G\setminus \{0\}`. + + INPUT: + + - ``G`` -- a group + - ``S`` -- list containing elements of ``G``; the set to be checked EXAMPLES:: sage: from sage.combinat.designs.difference_family import _is_skew_set sage: Z5 = Zmod(5) - sage: _is_skew_set([Z5(1), Z5(2)], 5) + sage: _is_skew_set(Z5, [Z5(1), Z5(2)]) True - sage: _is_skew_set([Z5(1), Z5(2), Z5(3)], 5) + sage: _is_skew_set(Z5, [Z5(1), Z5(2), Z5(3)]) False - sage: _is_skew_set([Z5(1)], 5) + sage: _is_skew_set(Z5, [Z5(1)]) False """ - G = Zmod(n) for el in S: if -el in S: return False @@ -2127,6 +2733,396 @@ def _is_skew_set(S, n): return False return True + +def are_complementary_difference_sets(G, A, B, verbose=False): + r""" + Check if ``A`` and ``B`` are complementary difference sets over the group ``G``. + + According to [Sze1971]_, two sets `A`, `B` of size `m` are complementary + difference sets over a group `G` of size `2m+1` if: + + 1. they are `2-\{2m+1; m, m; m-1\}` supplementary difference sets + 2. `A` is skew, i.e. `a \in A` implies `-a \not \in A` + + INPUT: + + - ``G`` -- a group of odd order + - ``A`` -- a set of elements of ``G`` + - ``B`` -- a set of elements of ``G`` + - ``verbose`` -- boolean (default: ``False``); if ``True`` the function will + be verbose when the sets do not satisfy the contraints + + EXAMPLES:: + + sage: from sage.combinat.designs.difference_family import are_complementary_difference_sets + sage: are_complementary_difference_sets(Zmod(7), [1, 2, 4], [1, 2, 4]) + True + + If ``verbose=True``, the function will be verbose:: + + sage: are_complementary_difference_sets(Zmod(7), [1, 2, 5], [1, 2, 4], verbose=True) + The sets are not supplementary difference sets with lambda = 2 + False + + TESTS:: + + sage: are_complementary_difference_sets(Zmod(16), [1, 2, 4], [1, 2, 4]) + False + sage: are_complementary_difference_sets(Zmod(7), [1, 2, 4], [1, 2, 3, 4]) + False + sage: are_complementary_difference_sets(Zmod(19), [1, 4, 5, 6, 7, 9, 11, 16, 17], [1, 4, 5, 6, 7, 9, 11, 16, 17]) + True + + .. SEEALSO:: + + :func:`is_supplementary_difference_set` + """ + n = G.order() + + if n % 2 != 1: + if verbose: + print('G must have odd order') + return False + + m = (n - 1) // 2 + + if len(A) != m or len(B) != m: + if verbose: + print(f'A and B must have size {m}') + return False + + if not is_supplementary_difference_set([A, B], lmbda=m-1, G=G): + if verbose: + print(f'The sets are not supplementary difference sets with lambda = {m-1}') + return False + + if not _is_skew_set(G, A): + if verbose: + print('The set A is not skew') + return False + + return True + + +def complementary_difference_setsI(n, check=True): + r""" + Construct complementary difference sets in a group of order `n \cong 3 \mod 4`, `n` a prime power. + + Let `G` be a Galois Field of order `n`, where `n` satisfies the requirements + above. Let `A` be the set of non-zero quadratic elements in `G`, and `B = A`. + Then `A` and `B` are complementary difference sets over a group of order `n`. + This construction is described in [Sze1971]_. + + INPUT: + + - ``n`` -- integer; the order of the group `G` + - ``check`` -- boolean (default: ``True``); if ``True``, check that the sets + are complementary difference sets before returning them + + OUTPUT: + + The function returns the Galois field of order ``n`` and the two sets, or raises + an error if ``n`` does not satisfy the requirements of this construction. + + EXAMPLES:: + + sage: from sage.combinat.designs.difference_family import complementary_difference_setsI + sage: complementary_difference_setsI(19) + (Finite Field of size 19, + [1, 4, 5, 6, 7, 9, 11, 16, 17], + [1, 4, 5, 6, 7, 9, 11, 16, 17]) + + TESTS:: + + sage: from sage.combinat.designs.difference_family import are_complementary_difference_sets + sage: G, A, B = complementary_difference_setsI(23, check=False) + sage: are_complementary_difference_sets(G, A, B) + True + sage: complementary_difference_setsI(17) + Traceback (most recent call last): + ... + ValueError: the parameter 17 is not valid + sage: complementary_difference_setsI(15) # needs sage.libs.pari + Traceback (most recent call last): + ... + ValueError: the parameter 15 is not valid + + .. SEEALSO:: + + :func:`are_complementary_difference_sets` + :func:`complementary_difference_sets` + """ + if not (n % 4 == 3 and is_prime_power(n)): + raise ValueError(f'the parameter {n} is not valid') + + from sage.rings.finite_rings.finite_field_constructor import GF + + G = GF(n, 'a') + A = list({x**2 for x in G if x**2 != 0}) + B = A + if check: + assert are_complementary_difference_sets(G, A, B) + + return G, A, B + + +def complementary_difference_setsII(n, check=True): + r""" + Construct complementary difference sets in a group of order `n = p^t`, where `p \cong 5 \mod 8` and `t \cong 1, 2, 3 \mod 4`. + + Consider a finite field `G` of order `n` and let `\rho` be the generator of + the corresponding multiplicative group. Then, there are two different constructions, + depending on whether `t` is even or odd. + + If `t \cong 2 \mod 4`, let `C_0` be the set of non-zero octic residues in `G`, + and let `C_i = \rho^i C_0` for `1 \le i \le 7`. + Then, `A = C_0 \cup C_1 \cup C_2 \cup C_3` and `B = C_0 \cup C_1 \cup C_6 \cup C_7`. + + If `t` is odd, let `C_0` be the set of non-zero fourth powers in `G`, and let + `C_i = \rho^i C_0` for `1 \le i \le 3`. + Then, `A = C_0 \cup C_1` and `B = C_0 \cup C_3`. + + For more details on this construction, see [Sze1971]_. + + INPUT: + + - ``n`` -- integer; the order of the group `G` + - ``check`` -- boolean (default: ``True``); if ``True``, check that the sets + are complementary difference sets before returning them; setting this to + ``False`` might speed up the computation for large values of ``n`` + + OUTPUT: + + The function returns the Galois field of order ``n`` and the two sets, or raises + an error if ``n`` does not satisfy the requirements of this construction. + + EXAMPLES:: + + sage: from sage.combinat.designs.difference_family import complementary_difference_setsII + sage: complementary_difference_setsII(5) # needs sage.libs.pari + (Finite Field of size 5, [1, 2], [1, 3]) + + TESTS:: + + sage: # needs sage.libs.pari + sage: from sage.combinat.designs.difference_family import are_complementary_difference_sets + sage: G, A, B = complementary_difference_setsII(25, check=False) + sage: are_complementary_difference_sets(G, A, B) + True + sage: G, A, B = complementary_difference_setsII(13, check=False) + sage: are_complementary_difference_sets(G, A, B) + True + sage: complementary_difference_setsII(49) + Traceback (most recent call last): + ... + ValueError: the parameter 49 is not valid + sage: complementary_difference_setsII(15) + Traceback (most recent call last): + ... + ValueError: the parameter 15 is not valid + + .. SEEALSO:: + + :func:`are_complementary_difference_sets` + :func:`complementary_difference_sets` + """ + p, t = is_prime_power(n, get_data=True) + if not (p % 8 == 5 and t > 0 and t % 4 in [1, 2, 3]): + raise ValueError(f'the parameter {n} is not valid') + + from sage.rings.finite_rings.finite_field_constructor import GF + G = GF(n, 'a') + A, B = None, None + + if t % 2 == 0: + rho = G.multiplicative_generator() + C0 = list({el**8 for el in G if el != 0}) + C1, C2, C3, C6, C7 = map(lambda i: [rho**i * el for el in C0], [1, 2, 3, 6, 7]) + A = C0 + C1 + C2 + C3 + B = C0 + C1 + C6 + C7 + else: + rho = G.multiplicative_generator() + C0 = list({el**4 for el in G if el**4 != 0}) + C1 = [rho * el for el in C0] + C3 = [rho**3 * el for el in C0] + A = C0 + C1 + B = C0 + C3 + + if check: + assert are_complementary_difference_sets(G, A, B) + + return G, A, B + + +def complementary_difference_setsIII(n, check=True): + r""" + Construct complementary difference sets in a group of order `n = 2m + 1`, where `4m + 3` is a prime power. + + Consider a finite field `G` of order `n` and let `\rho` be a primite element + of this group. Now let `Q` be the set of non zero quadratic residues in `G`, + and let `A = \{ a | \rho^{2a} - 1 \in Q\}`, `B' = \{ b | -(\rho^{2b} + 1) \in Q\}`. + Then `A` and `B = Q \setminus B'` are complementary difference sets over the ring + of integers modulo `n`. For more details, see [Sz1969]_. + + INPUT: + + - ``n`` -- integer; the order of the group over which the sets are constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the sets + are complementary difference sets before returning them; setting this to + ``False`` might speed up the computation for large values of ``n`` + + OUTPUT: + + The function returns the Galois field of order ``n`` and the two sets, or raises + an error if ``n`` does not satisfy the requirements of this construction. + + EXAMPLES:: + + sage: from sage.combinat.designs.difference_family import complementary_difference_setsIII + sage: complementary_difference_setsIII(11) # needs sage.libs.pari + (Ring of integers modulo 11, [1, 2, 5, 7, 8], [0, 1, 3, 8, 10]) + + TESTS:: + + sage: from sage.combinat.designs.difference_family import are_complementary_difference_sets + sage: G, A, B = complementary_difference_setsIII(21, check=False) # needs sage.libs.pari + sage: are_complementary_difference_sets(G, A, B) # needs sage.libs.pari + True + sage: G, A, B = complementary_difference_setsIII(65, check=False) # needs sage.libs.pari + sage: are_complementary_difference_sets(G, A, B) # needs sage.libs.pari + True + sage: complementary_difference_setsIII(10) + Traceback (most recent call last): + ... + ValueError: the parameter 10 is not valid + sage: complementary_difference_setsIII(17) # needs sage.libs.pari + Traceback (most recent call last): + ... + ValueError: the parameter 17 is not valid + + .. SEEALSO:: + + :func:`are_complementary_difference_sets` + :func:`complementary_difference_sets` + """ + m = (n - 1) // 2 + q = 4*m + 3 + if n % 2 != 1 or not is_prime_power(q): + raise ValueError(f'the parameter {n} is not valid') + + from sage.rings.finite_rings.finite_field_constructor import GF + G = Zmod(n) + G2 = GF(q) + rho = G2.primitive_element() + + Q = [rho ** (2*b) for b in range(1, n+1)] + + A = [G(a) for a in range(n) if rho**(2*a) - 1 in Q] + B = [G(b) for b in range(n) if -rho**(2*b) - 1 not in Q] + + if check: + assert are_complementary_difference_sets(G, A, B) + + return G, A, B + + +def complementary_difference_sets(n, existence=False, check=True): + r""" + Compute complementary difference sets over a group of order `n = 2m + 1`. + + According to [Sze1971]_, two sets `A`, `B` of size `m` are complementary + difference sets over a group `G` of size `n = 2m + 1` if: + + 1. they are `2-\{2m+1; m, m; m-1\}` supplementary difference sets + 2. `A` is skew, i.e. `a \in A` implies `-a \not \in A` + + This method tries to call :func:`complementary_difference_setsI`, + :func:`complementary_difference_setsII` or :func:`complementary_difference_setsIII` + if the parameter `n` satisfies the requirements of one of these functions. + + INPUT: + + - ``n`` -- integer; the order of the group over which the sets are constructed + - ``existence`` -- boolean (default: ``False``); if ``True``, only check + whether the supplementary difference sets can be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the sets + are complementary difference sets before returning them; setting this to + ``False`` might speed up the computation for large values of ``n`` + + OUTPUT: + + If ``existence=False``, the function returns group ``G`` and two complementary + difference sets, or raises an error if data for the given ``n`` is not available. + If ``existence=True``, the function returns a boolean representing whether + complementary difference sets can be constructed for the given ``n``. + + EXAMPLES:: + + sage: from sage.combinat.designs.difference_family import complementary_difference_sets + sage: complementary_difference_sets(15) # needs sage.libs.pari + (Ring of integers modulo 15, [1, 2, 4, 6, 7, 10, 12], [0, 1, 2, 6, 9, 13, 14]) + + If ``existence=True``, the function returns a boolean:: + + sage: complementary_difference_sets(15, existence=True) # needs sage.libs.pari + True + sage: complementary_difference_sets(16, existence=True) + False + + TESTS:: + + sage: from sage.combinat.designs.difference_family import are_complementary_difference_sets + sage: G, A, B = complementary_difference_sets(29) # needs sage.libs.pari + sage: are_complementary_difference_sets(G, A, B) # needs sage.libs.pari + True + sage: G, A, B = complementary_difference_sets(65) # needs sage.libs.pari + sage: are_complementary_difference_sets(G, A, B) # needs sage.libs.pari + True + sage: complementary_difference_sets(10) + Traceback (most recent call last): + ... + ValueError: the parameter n must be odd + sage: complementary_difference_sets(17) # needs sage.libs.pari + Traceback (most recent call last): + ... + NotImplementedError: complementary difference sets of order 17 are not implemented yet + + .. SEEALSO:: + + :func:`are_complementary_difference_sets` + """ + if n % 2 == 0: + if existence: + return False + raise ValueError('the parameter n must be odd') + + p, t = is_prime_power(n, get_data=True) + G, A, B = None, None, None + + if n % 4 == 3 and t > 0: + if existence: + return True + G, A, B = complementary_difference_setsI(n, check=False) + elif p % 8 == 5 and t > 0 and t % 4 in [1, 2, 3]: + if existence: + return True + G, A, B = complementary_difference_setsII(n, check=False) + elif is_prime_power(2*n + 1): + if existence: + return True + G, A, B = complementary_difference_setsIII(n, check=False) + + if existence: + return False + + if G is None: + raise NotImplementedError(f'complementary difference sets of order {n} are not implemented yet') + + if check: + assert are_complementary_difference_sets(G, A, B) + return G, A, B + + def difference_family(v, k, l=1, existence=False, explain_construction=False, check=True): r""" Return a (``k``, ``l``)-difference family on an Abelian group of cardinality ``v``. @@ -2149,31 +3145,28 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch INPUT: - ``v,k,l`` -- parameters of the difference family. If ``l`` is not provided - it is assumed to be ``1``. - + it is assumed to be ``1`` - ``existence`` -- if ``True``, then return either ``True`` if Sage knows how to build such design, ``Unknown`` if it does not and ``False`` if it - knows that the design does not exist. - + knows that the design does not exist - ``explain_construction`` -- instead of returning a difference family, - returns a string that explains the construction used. - - - ``check`` -- boolean (default: ``True``). If ``True`` then the result of + returns a string that explains the construction used + - ``check`` -- boolean (default: ``True``); if ``True``, then the result of the computation is checked before being returned. This should not be - needed but ensures that the output is correct. + needed but ensures that the output is correct OUTPUT: A pair ``(G,D)`` made of a group `G` and a difference family `D` on that - group. Or, if ``existence`` is ``True`` a troolean or if - ``explain_construction`` is ``True`` a string. + group. Or, if ``existence=True``` a troolean or if + ``explain_construction=True`` a string. EXAMPLES:: - sage: G,D = designs.difference_family(73,4) - sage: G + sage: G,D = designs.difference_family(73,4) # needs sage.libs.pari + sage: G # needs sage.libs.pari Finite Field of size 73 - sage: D + sage: D # needs sage.libs.pari [[0, 1, 5, 18], [0, 3, 15, 54], [0, 9, 45, 16], @@ -2184,6 +3177,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch sage: print(designs.difference_family(73, 4, explain_construction=True)) The database contains a (73,4)-evenly distributed set + sage: # needs sage.libs.pari sage: G,D = designs.difference_family(15,7,3) sage: G Ring of integers modulo 15 @@ -2192,11 +3186,11 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch sage: print(designs.difference_family(15,7,3,explain_construction=True)) Singer difference set - sage: print(designs.difference_family(91,10,1,explain_construction=True)) + sage: print(designs.difference_family(91,10,1,explain_construction=True)) # needs sage.libs.pari Singer difference set - sage: print(designs.difference_family(64,28,12, explain_construction=True)) + sage: print(designs.difference_family(64,28,12, explain_construction=True)) # needs sage.libs.pari McFarland 1973 construction - sage: print(designs.difference_family(576, 276, 132, explain_construction=True)) + sage: print(designs.difference_family(576, 276, 132, explain_construction=True)) # needs sage.libs.pari Hadamard difference set product from N1=2 and N2=3 For `k=6,7` we look at the set of small prime powers for which a @@ -2211,7 +3205,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch sage: from itertools import islice sage: l6 = {True:[], False: [], Unknown: []} - sage: for q in islice(prime_power_mod(1,30), int(60)): + sage: for q in islice(prime_power_mod(1,30), int(60)): # needs sage.libs.pari ....: l6[designs.difference_family(q,6,existence=True)].append(q) sage: l6[True] [31, 121, 151, 181, 211, ..., 3061, 3121, 3181] @@ -2221,7 +3215,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch [] sage: l7 = {True: [], False: [], Unknown: []} - sage: for q in islice(prime_power_mod(1,42), int(60)): + sage: for q in islice(prime_power_mod(1,42), int(60)): # needs sage.libs.pari ....: l7[designs.difference_family(q,7,existence=True)].append(q) sage: l7[True] [169, 337, 379, 421, 463, 547, 631, 673, 757, 841, 883, 967, ..., 4621, 4957, 5167] @@ -2232,7 +3226,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch List available constructions:: - sage: for v in range(2,100): + sage: for v in range(2,100): # needs sage.libs.pari ....: constructions = [] ....: for k in range(2,10): ....: for l in range(1,10): @@ -2252,7 +3246,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch 10: (9,8) 11: (2,1), (4,6), (5,2), (5,4), (6,3) 13: (2,1), (3,1), (3,2), (4,1), (4,3), (5,5), (6,5) - 15: (3,1), (4,6), (5,6), (7,3) + 15: (3,1), (4,6), (5,6), (7,3), (7,6) 16: (3,2), (5,4), (6,2) 17: (2,1), (4,3), (5,5), (8,7) 19: (2,1), (3,1), (3,2), (4,2), (6,5), (9,4), (9,8) @@ -2309,7 +3303,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch sage: Q15 = [76231] sage: Q4 = [13, 73, 97, 109, 181, 229, 241, 277, 337, 409, 421, 457] sage: Q8 = [1009, 3137, 3697] - sage: for Q,k in [(Q4,4),(Q5,5),(Q8,8),(Q9,9),(Q15,15)]: + sage: for Q,k in [(Q4,4),(Q5,5),(Q8,8),(Q9,9),(Q15,15)]: # needs sage.libs.pari ....: for q in Q: ....: assert designs.difference_family(q,k,1,existence=True) is True ....: _ = designs.difference_family(q,k,1) @@ -2318,7 +3312,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch sage: sgp = lambda q,d: ((q**(d+1)-1)//(q-1), (q**d-1)//(q-1), (q**(d-1)-1)//(q-1)) - sage: for q in range(2,10): + sage: for q in range(2,10): # needs sage.libs.pari ....: if is_prime_power(q): ....: for d in [2,3,4]: ....: v,k,l = sgp(q,d) @@ -2327,10 +3321,15 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch Check twin primes difference sets:: - sage: for p in [3,5,7,9,11]: + sage: for p in [3,5,7,9,11]: # needs sage.libs.pari ....: v = p*(p+2); k = (v-1)/2; lmbda = (k-1)/2 ....: G,D = designs.difference_family(v,k,lmbda) + Check Complementary difference sets:: + + sage: for v in [15, 33, 35, 39, 51]: # needs sage.libs.pari + ....: G, D = designs.difference_family(v, (v-1)//2, (v-1)//2-1) + Check the database:: sage: from sage.combinat.designs.database import DF,EDS @@ -2338,14 +3337,14 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch ....: assert designs.difference_family(v,k,l,existence=True) is True ....: df = designs.difference_family(v,k,l,check=True) - sage: for k in EDS: + sage: for k in EDS: # needs sage.libs.pari ....: for v in EDS[k]: ....: assert designs.difference_family(v,k,1,existence=True) is True ....: df = designs.difference_family(v,k,1,check=True) Check the known Hadamard parameters:: - sage: for N in range(2,21): + sage: for N in range(2,21): # needs sage.libs.pari ....: v = 4*N^2; k = 2*N^2-N; l = N^2-N ....: status = designs.difference_family(v,k,l,existence=True) ....: print("{:2} {}".format(N,designs.difference_family(v,k,l,explain_construction=True) if status is True else status)) @@ -2384,7 +3383,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch sage: designs.difference_family(3, 2, 1, explain_construction=True) 'Trivial difference family' - sage: for _ in range(100): + sage: for _ in range(100): # needs sage.libs.pari ....: v = randint(1, 30) ....: k = randint(2, 30) ....: l = randint(1, 30) @@ -2467,7 +3466,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch if existence: return True from sage.rings.finite_rings.integer_mod_ring import Zmod - l = [0] if k ==1 else [] + l = [0] if k == 1 else [] return Zmod(1),[l] if existence: @@ -2585,6 +3584,15 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch p,q = q,p G,D = twin_prime_powers_difference_set(p,check=False) + elif (v-1)//2 == k and (v-1)//2-1 == l and complementary_difference_sets(v, existence=True): + if existence: + return True + elif explain_construction: + return "Complementary difference sets" + else: + G, A, B = complementary_difference_sets(v) + D = [A, B] + else: if existence: return Unknown @@ -2598,6 +3606,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch return G, D + from sage.misc.rest_index_of_methods import gen_rest_table_index import sys __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(sys.modules[__name__])) diff --git a/src/sage/combinat/designs/difference_matrices.py b/src/sage/combinat/designs/difference_matrices.py index 03aeb966af5..25986ca2c79 100644 --- a/src/sage/combinat/designs/difference_matrices.py +++ b/src/sage/combinat/designs/difference_matrices.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Difference Matrices @@ -10,11 +11,11 @@ --------- """ +from sage.arith.misc import divisors, is_prime_power from sage.misc.unknown import Unknown from sage.misc.cachefunc import cached_function from sage.categories.sets_cat import EmptySetError from sage.rings.finite_rings.finite_field_constructor import FiniteField -from sage.arith.all import is_prime_power, divisors from .designs_pyx import is_difference_matrix from .database import DM as DM_constructions @@ -146,12 +147,12 @@ def difference_matrix(g,k,lmbda=1,existence=False,check=True): - ``existence`` (boolean) -- instead of building the design, return: - - ``True`` -- meaning that Sage knows how to build the design + - ``True`` -- meaning that Sage knows how to build the design - - ``Unknown`` -- meaning that Sage does not know how to build the - design, but that the design may exist (see :mod:`sage.misc.unknown`). + - ``Unknown`` -- meaning that Sage does not know how to build the + design, but that the design may exist (see :mod:`sage.misc.unknown`). - - ``False`` -- meaning that the design does not exist. + - ``False`` -- meaning that the design does not exist. .. NOTE:: @@ -218,7 +219,7 @@ def difference_matrix(g,k,lmbda=1,existence=False,check=True): NotImplementedError: I don't know how to build a (10,9,1)-Difference Matrix! """ - if lmbda == 1 and k is not None and k>g: + if lmbda == 1 and k is not None and k > g: if existence: return False raise EmptySetError("No ({},{},{})-Difference Matrix exists as k(={})>g(={})".format(g,k,lmbda,k,g)) @@ -232,8 +233,8 @@ def difference_matrix(g,k,lmbda=1,existence=False,check=True): k = g elif existence: return True - F = FiniteField(g,'x') - F_set = list(F) + F = FiniteField(g,'x') + F_set = list(F) F_k_set = F_set[:k] G = F @@ -248,7 +249,7 @@ def difference_matrix(g,k,lmbda=1,existence=False,check=True): return i-1 # From the database - elif (g,lmbda) in DM_constructions and DM_constructions[g,lmbda][0]>=k: + elif (g,lmbda) in DM_constructions and DM_constructions[g,lmbda][0] >= k: if existence: return True _,f = DM_constructions[g,lmbda] diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index 5eeb02df81e..36d48d50b30 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.rings.finite_rings r""" Evenly distributed sets in finite fields @@ -23,7 +23,7 @@ from libc.string cimport memset, memcpy from cysignals.memory cimport check_malloc, check_calloc, sig_free -from sage.rings.integer cimport Integer,smallInteger +from sage.rings.integer cimport smallInteger cdef class EvenlyDistributedSetsBacktracker: r""" @@ -212,7 +212,7 @@ cdef class EvenlyDistributedSetsBacktracker: self.up_to_isom = bool(up_to_isomorphism) self.count = 0 - cdef unsigned int i,j,ell + cdef unsigned int i,j if not K.is_field(): raise ValueError("{} is not a field".format(K)) @@ -359,7 +359,8 @@ cdef class EvenlyDistributedSetsBacktracker: sage: EvenlyDistributedSetsBacktracker(GF(25,'a'), 4) 4-evenly distributed sets (up to isomorphism) in Finite Field in a of size 5^2 - sage: EvenlyDistributedSetsBacktracker(GF(25,'a'), 4, up_to_isomorphism=False) + sage: EvenlyDistributedSetsBacktracker(GF(25,'a'), 4, + ....: up_to_isomorphism=False) 4-evenly distributed sets in Finite Field in a of size 5^2 """ return "{}-evenly distributed sets {} in {}".format( @@ -378,13 +379,14 @@ cdef class EvenlyDistributedSetsBacktracker: sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker - sage: E = EvenlyDistributedSetsBacktracker(GF(25,'a'),4) - sage: E - 4-evenly distributed sets (up to isomorphism) in Finite Field in a of size 5^2 + sage: E = EvenlyDistributedSetsBacktracker(GF(25,'a'), 4); E + 4-evenly distributed sets (up to isomorphism) + in Finite Field in a of size 5^2 sage: E.cardinality() 4 - sage: E = EvenlyDistributedSetsBacktracker(GF(25,'a'), 4, up_to_isomorphism=False) + sage: E = EvenlyDistributedSetsBacktracker(GF(25,'a'), 4, + ....: up_to_isomorphism=False) sage: E.cardinality() 40 """ diff --git a/src/sage/combinat/designs/ext_rep.py b/src/sage/combinat/designs/ext_rep.py index 2a463bc793e..0f5bdf339fa 100644 --- a/src/sage/combinat/designs/ext_rep.py +++ b/src/sage/combinat/designs/ext_rep.py @@ -45,8 +45,8 @@ from sage.misc.temporary_file import tmp_filename -XML_NAMESPACE = 'http://designtheory.org/xml-namespace' -DTRS_PROTOCOL = '2.0' +XML_NAMESPACE = 'http://designtheory.org/xml-namespace' +DTRS_PROTOCOL = '2.0' # The following string is the file # http://designtheory.org/database/v-b-k/v2-b2-k2.icgsa.txt.bz2 @@ -565,6 +565,7 @@ def open_extrep_url(url): else: return f.read() + pattern_integer = re.compile(r'\d+$') pattern_decimal = re.compile(r'-?\d+\.\d+$') pattern_rational = re.compile(r'-?\d+/\d+$') @@ -660,7 +661,6 @@ def __init__(self, node): ('block', {}, [[6, 8, 10]])] """ - if isinstance(node, str): node = (node, {}, []) name, attributes, children = node diff --git a/src/sage/combinat/designs/gen_quadrangles_with_spread.pyx b/src/sage/combinat/designs/gen_quadrangles_with_spread.pyx index 1d2035eeba0..26da661f3cd 100644 --- a/src/sage/combinat/designs/gen_quadrangles_with_spread.pyx +++ b/src/sage/combinat/designs/gen_quadrangles_with_spread.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.gap r""" Database of generalised quadrangles with spread @@ -286,7 +287,6 @@ def generalised_quadrangle_hermitian_with_ovoid(const int q): from sage.arith.misc import is_prime_power GU = libgap.GU(4, q) - H = libgap.InvariantSesquilinearForm(GU)["matrix"] Fq = libgap.GF(q * q) zero = libgap.Zero(Fq) one = libgap.One(Fq) @@ -310,14 +310,13 @@ def generalised_quadrangle_hermitian_with_ovoid(const int q): lines = [list(map(lambda x: int(x - 1), b)) for b in lines] # convert to int # lines defines the GQ H(3, q^2) - # to find an ovoid, we embed H(3,q^2) in H(4,q^2) # the embedding is (a,b,c,d) -> (a,b,0,c,d) # then we find a point in the latter and not in the former # this point will be collinear (in H(3,q^2)) to all points in an ovoid if q % 2 == 1: - (p, k) = is_prime_power(q, get_data=True) - a = (p-1) // 2 + p, _ = is_prime_power(q, get_data=True) + a = (p - 1) // 2 aGap = zero for i in range(a): aGap += one diff --git a/src/sage/combinat/designs/group_divisible_designs.py b/src/sage/combinat/designs/group_divisible_designs.py index 6bb032a793d..e1d90155920 100644 --- a/src/sage/combinat/designs/group_divisible_designs.py +++ b/src/sage/combinat/designs/group_divisible_designs.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Group-Divisible Designs (GDD) @@ -31,7 +32,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.arith.all import is_prime_power +from sage.arith.misc import is_prime_power from sage.misc.unknown import Unknown from .incidence_structures import IncidenceStructure @@ -97,15 +98,15 @@ def group_divisible_design(v,K,G,existence=False,check=False): if existence: return balanced_incomplete_block_design(v+1,k,existence=True) BIBD = balanced_incomplete_block_design(v+1,k) - groups = [[x for x in S if x!=v] for S in BIBD if v in S] + groups = [[x for x in S if x != v] for S in BIBD if v in S] d = {p:i for i,p in enumerate(sum(groups,[]))} - d[v]=v + d[v] = v BIBD.relabel(d) groups = [list(range((k-1)*i,(k-1)*(i+1))) for i in range(v//(k-1))] blocks = [S for S in BIBD if v not in S] # (v,{4},{2})-GDD - elif (v%2==0 and + elif (v % 2 == 0 and K == [4] and G == [2] and GDD_4_2(v//2,existence=True)): @@ -114,20 +115,20 @@ def group_divisible_design(v,K,G,existence=False,check=False): return GDD_4_2(v//2,check=check) # From a TD(k,g) - elif (len(G) == 1 and - len(K) == 1 and + elif (len(G) == 1 and + len(K) == 1 and K[0]*G[0] == v): from .orthogonal_arrays import transversal_design return transversal_design(k=K[0],n=G[0],existence=existence) if blocks: return GroupDivisibleDesign(v, - groups = groups, - blocks = blocks, - G = G, - K = K, - check = check, - copy = True) + groups=groups, + blocks=blocks, + G=G, + K=K, + check=check, + copy=True) if existence: return Unknown @@ -171,7 +172,7 @@ def GDD_4_2(q,existence=False,check=True): ... NotImplementedError """ - if q <=1 or q%6 != 1 or not is_prime_power(q): + if q <= 1 or q % 6 != 1 or not is_prime_power(q): if existence: return Unknown raise NotImplementedError @@ -188,17 +189,17 @@ def GDD_4_2(q,existence=False,check=True): for i in range((q - 1) // 6)] label = {p:i for i,p in enumerate(G)} - classes = [[[2*label[x[1]+g]+(x[0]+j)%2 for x in S] + classes = [[[2*label[x[1]+g]+(x[0]+j) % 2 for x in S] for S in first_class] for g in G for j in range(2)] return GroupDivisibleDesign(2*q, - groups = [[i,i+1] for i in range(0,2*q,2)], - blocks = sum(classes,[]), - K = [4], - G = [2], - check = check, - copy = False) + groups=[[i,i+1] for i in range(0,2*q,2)], + blocks=sum(classes,[]), + K=[4], + G=[2], + check=check, + copy=False) class GroupDivisibleDesign(IncidenceStructure): r""" diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index dfb6c90f652..e2dc0a17278 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -39,10 +39,13 @@ # https://www.gnu.org/licenses/ # # ************************************************************************** from __future__ import annotations -from sage.rings.integer import Integer + from sage.misc.latex import latex +from sage.misc.lazy_import import lazy_import +from sage.rings.integer import Integer from sage.sets.set import Set -from sage.libs.gap.libgap import libgap + +lazy_import('sage.libs.gap.libgap', 'libgap') class IncidenceStructure(): @@ -102,8 +105,8 @@ class IncidenceStructure(): Or by its adjacency matrix (a `\{0,1\}`-matrix in which rows are indexed by points and columns by blocks):: - sage: m = matrix([[0,1,0],[0,0,1],[1,0,1],[1,1,1]]) - sage: IncidenceStructure(m) + sage: m = matrix([[0,1,0],[0,0,1],[1,0,1],[1,1,1]]) # needs sage.modules + sage: IncidenceStructure(m) # needs sage.modules Incidence structure with 4 points and 3 blocks The points can be any (hashable) object:: @@ -157,9 +160,10 @@ def __init__(self, points=None, blocks=None, incidence_matrix=None, We avoid to convert to integers when the points are not (but compare equal to integers because of coercion):: + sage: # needs sage.rings.finite_rings sage: V = GF(5) sage: e0,e1,e2,e3,e4 = V - sage: [e0,e1,e2,e3,e4] == list(range(5)) # coercion makes them equal + sage: [e0,e1,e2,e3,e4] == list(range(5)) # coercion makes them equal True sage: blocks = [[e0,e1,e2],[e0,e1],[e2,e4]] sage: I = IncidenceStructure(V, blocks) @@ -173,7 +177,6 @@ def __init__(self, points=None, blocks=None, incidence_matrix=None, sage: IncidenceStructure([]) Incidence structure with 0 points and 0 blocks """ - from sage.matrix.constructor import matrix from sage.structure.element import Matrix # Reformatting input @@ -189,6 +192,7 @@ def __init__(self, points=None, blocks=None, incidence_matrix=None, assert incidence_matrix is None, "'incidence_matrix' cannot be defined when 'points' is defined" if incidence_matrix: + from sage.matrix.constructor import matrix M = matrix(incidence_matrix) v = M.nrows() self._points = list(range(v)) @@ -279,9 +283,9 @@ def __eq__(self, other): sage: blocks = [[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]] sage: BD1 = IncidenceStructure(7, blocks) - sage: M = BD1.incidence_matrix() - sage: BD2 = IncidenceStructure(incidence_matrix=M) - sage: BD1 == BD2 + sage: M = BD1.incidence_matrix() # needs sage.modules + sage: BD2 = IncidenceStructure(incidence_matrix=M) # needs sage.modules + sage: BD1 == BD2 # needs sage.modules True sage: e1 = frozenset([0,1]) @@ -323,9 +327,9 @@ def __ne__(self, other): EXAMPLES:: sage: BD1 = IncidenceStructure(7, [[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]]) - sage: M = BD1.incidence_matrix() - sage: BD2 = IncidenceStructure(incidence_matrix=M) - sage: BD1 != BD2 + sage: M = BD1.incidence_matrix() # needs sage.modules + sage: BD2 = IncidenceStructure(incidence_matrix=M) # needs sage.modules + sage: BD1 != BD2 # needs sage.modules False """ return not self == other @@ -360,8 +364,9 @@ def __contains__(self, block): True sage: ["Am", "I", "finally", "done ?"] in IS False - sage: IS = designs.ProjectiveGeometryDesign(3, 1, GF(2), point_coordinates=False) - sage: [3,8,7] in IS + sage: IS = designs.ProjectiveGeometryDesign(3, 1, GF(2), # needs sage.rings.finite_rings + ....: point_coordinates=False) + sage: [3,8,7] in IS # needs sage.rings.finite_rings True sage: [3,8,9] in IS False @@ -390,6 +395,7 @@ def canonical_label(self): EXAMPLES:: + sage: # needs sage.schemes sage: fano1 = designs.balanced_incomplete_block_design(7,3) sage: fano2 = designs.projective_plane(2) sage: fano1 == fano2 @@ -424,6 +430,7 @@ def is_isomorphic(self, other, certificate=False): EXAMPLES:: + sage: # needs sage.schemes sage: fano1 = designs.balanced_incomplete_block_design(7,3) sage: fano2 = designs.projective_plane(2) sage: fano1.is_isomorphic(fano2) @@ -433,28 +440,32 @@ def is_isomorphic(self, other, certificate=False): TESTS:: - sage: IS = IncidenceStructure([["A",5,pi],["A",5,"Wouhou"],["A","Wouhou",(9,9)],[pi,12]]) + sage: # needs sage.symbolic + sage: IS = IncidenceStructure([["A",5,pi],["A",5,"Wouhou"], + ....: ["A","Wouhou",(9,9)],[pi,12]]) sage: IS2 = IS.copy() sage: IS2.relabel(IS2.canonical_label()) sage: IS.is_isomorphic(IS2) True - sage: canon = IS.is_isomorphic(IS2,certificate=True) + sage: canon = IS.is_isomorphic(IS2, certificate=True) sage: IS.relabel(canon) sage: IS==IS2 True sage: IS2 = IncidenceStructure([[1,2]]) - sage: IS2.is_isomorphic(IS) + sage: IS2.is_isomorphic(IS) # needs sage.symbolic False - sage: IS2.is_isomorphic(IS,certificate=True) + sage: IS2.is_isomorphic(IS, certificate=True) # needs sage.symbolic {} Checking whether two :class:`IncidenceStructure` are isomorphic incidentally computes their canonical label (if necessary). Thus, subsequent calls to :meth:`is_isomorphic` will be faster:: + sage: # needs sage.schemes sage: IS1 = designs.projective_plane(3) - sage: IS2 = IS1.relabel(Permutations(IS1.ground_set()).random_element(),inplace=False) + sage: IS2 = IS1.relabel(Permutations(IS1.ground_set()).random_element(), + ....: inplace=False) sage: IS2 = IncidenceStructure(IS2.blocks()) sage: IS1._canonical_label is None and IS2._canonical_label is None True @@ -544,10 +555,10 @@ def isomorphic_substructures_iterator(self, H2,induced=False): The number of copies of `H` in itself is the size of its automorphism group:: - sage: H = designs.projective_plane(3) - sage: sum(1 for _ in H.isomorphic_substructures_iterator(H)) + sage: H = designs.projective_plane(3) # needs sage.schemes + sage: sum(1 for _ in H.isomorphic_substructures_iterator(H)) # needs sage.schemes 5616 - sage: H.automorphism_group().cardinality() + sage: H.automorphism_group().cardinality() # needs sage.groups sage.schemes 5616 """ from sage.combinat.designs.subhypergraph_search import SubHypergraphSearch @@ -669,6 +680,7 @@ def trace(self, points, min_size=1, multiset=True): A Baer subplane of order 2 (i.e. a Fano plane) in a projective plane of order 4:: + sage: # needs sage.schemes sage: P4 = designs.projective_plane(4) sage: F = designs.projective_plane(2) sage: for x in Subsets(P4.ground_set(),7): @@ -681,6 +693,7 @@ def trace(self, points, min_size=1, multiset=True): TESTS:: + sage: # needs sage.schemes sage: F.trace([0..50]) Traceback (most recent call last): ... @@ -708,7 +721,7 @@ def trace(self, points, min_size=1, multiset=True): blocks = [int_points.intersection(S) for S in self._blocks] if min_size: - blocks = [S for S in blocks if len(S)>=min_size] + blocks = [S for S in blocks if len(S) >= min_size] if not multiset: blocks = set(blocks) IS = IncidenceStructure(blocks) @@ -822,7 +835,7 @@ def degree(self, p=None, subset=False): if self._point_to_index: p = self._point_to_index.get(p,-1) else: - p = p if (p>=0 and p<len(self._points)) else -1 + p = p if (p >= 0 and p < len(self._points)) else -1 return sum((p in b) for b in self._blocks) if p != -1 else 0 # degree of a set @@ -830,7 +843,7 @@ def degree(self, p=None, subset=False): if self._point_to_index: p = set(self._point_to_index.get(x,-1) for x in p) else: - p = set(p) if all(x>=0 and x<len(self._points) for x in p) else set([-1]) + p = set(p) if all(x >= 0 and x < len(self._points) for x in p) else set([-1]) return sum(p.issubset(b) for b in self._blocks) if -1 not in p else 0 @@ -883,7 +896,7 @@ def degrees(self, size=None): d = {t:0 for t in combinations(range(self.num_points()),size)} for b in self._blocks: for s in combinations(b,size): - d[s]+=1 + d[s] += 1 if self._point_to_index: return {tuple([self._points[x] for x in s]):v for s,v in d.items()} else: @@ -925,11 +938,11 @@ def is_regular(self, r=None) -> bool | int: EXAMPLES:: - sage: designs.balanced_incomplete_block_design(7,3).is_regular() + sage: designs.balanced_incomplete_block_design(7,3).is_regular() # needs sage.schemes 3 - sage: designs.balanced_incomplete_block_design(7,3).is_regular(r=3) + sage: designs.balanced_incomplete_block_design(7,3).is_regular(r=3) # needs sage.schemes True - sage: designs.balanced_incomplete_block_design(7,3).is_regular(r=4) + sage: designs.balanced_incomplete_block_design(7,3).is_regular(r=4) # needs sage.schemes False TESTS:: @@ -976,11 +989,11 @@ def is_uniform(self, k=None) -> bool | int: EXAMPLES:: - sage: designs.balanced_incomplete_block_design(7,3).is_uniform() + sage: designs.balanced_incomplete_block_design(7,3).is_uniform() # needs sage.schemes 3 - sage: designs.balanced_incomplete_block_design(7,3).is_uniform(k=3) + sage: designs.balanced_incomplete_block_design(7,3).is_uniform(k=3) # needs sage.schemes True - sage: designs.balanced_incomplete_block_design(7,3).is_uniform(k=4) + sage: designs.balanced_incomplete_block_design(7,3).is_uniform(k=4) # needs sage.schemes False TESTS:: @@ -1062,7 +1075,7 @@ def _libgap_(self): EXAMPLES:: sage: D = IncidenceStructure(4, [[0,2],[1,2,3],[2,3]]) - sage: D._libgap_() # optional - gap_packages + sage: D._libgap_() # optional - gap_package_design rec( blocks := [ [ 1, 3 ], [ 2, 3, 4 ], [ 3, 4 ] ], isBlockDesign := true, v := 4 ) """ @@ -1115,10 +1128,11 @@ def incidence_matrix(self): EXAMPLES:: - sage: BD = IncidenceStructure(7, [[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]]) + sage: BD = IncidenceStructure(7, [[0,1,2],[0,3,4],[0,5,6],[1,3,5], + ....: [1,4,6],[2,3,6],[2,4,5]]) sage: BD.block_sizes() [3, 3, 3, 3, 3, 3, 3] - sage: BD.incidence_matrix() + sage: BD.incidence_matrix() # needs sage.modules [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] [1 0 0 0 0 1 1] @@ -1128,7 +1142,7 @@ def incidence_matrix(self): [0 0 1 0 1 1 0] sage: I = IncidenceStructure('abc', ('ab','abc','ac','c')) - sage: I.incidence_matrix() + sage: I.incidence_matrix() # needs sage.modules [1 1 1 0] [1 1 0 0] [0 1 1 1] @@ -1153,26 +1167,28 @@ def incidence_graph(self,labels=False): - ``labels`` (boolean) -- whether to return a graph whose vertices are integers, or labelled elements. - - ``labels is False`` (default) -- in this case the first vertices - of the graphs are the elements of :meth:`ground_set`, and appear - in the same order. Similarly, the following vertices represent the - elements of :meth:`blocks`, and appear in the same order. + - ``labels is False`` (default) -- in this case the first vertices + of the graphs are the elements of :meth:`ground_set`, and appear + in the same order. Similarly, the following vertices represent the + elements of :meth:`blocks`, and appear in the same order. - - ``labels is True``, the points keep their original labels, and the - blocks are :func:`Set <Set>` objects. + - ``labels is True``, the points keep their original labels, and the + blocks are :func:`Set <Set>` objects. - Note that the labelled incidence graph can be incorrect when - blocks are repeated, and on some (rare) occasions when the - elements of :meth:`ground_set` mix :func:`Set` and non-:func:`Set - <Set>` objects. + Note that the labelled incidence graph can be incorrect when + blocks are repeated, and on some (rare) occasions when the + elements of :meth:`ground_set` mix :func:`Set` and non-:func:`Set + <Set>` objects. EXAMPLES:: - sage: BD = IncidenceStructure(7, [[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]]) - sage: BD.incidence_graph() + sage: BD = IncidenceStructure(7, [[0,1,2],[0,3,4],[0,5,6],[1,3,5], + ....: [1,4,6],[2,3,6],[2,4,5]]) + sage: BD.incidence_graph() # needs sage.modules Bipartite graph on 14 vertices - sage: A = BD.incidence_matrix() - sage: Graph(block_matrix([[A*0,A],[A.transpose(),A*0]])) == BD.incidence_graph() + sage: A = BD.incidence_matrix() # needs sage.modules + sage: Graph(block_matrix([[A*0, A], # needs sage.modules + ....: [A.transpose(),A*0]])) == BD.incidence_graph() True TESTS: @@ -1215,9 +1231,9 @@ def is_berge_cyclic(self): EXAMPLES:: - sage: Hypergraph(5, [[1, 2, 3], [2, 3 ,4]]).is_berge_cyclic() + sage: Hypergraph(5, [[1, 2, 3], [2, 3, 4]]).is_berge_cyclic() # needs sage.modules True - sage: Hypergraph(6, [[1, 2, 3], [3 ,4, 5]]).is_berge_cyclic() + sage: Hypergraph(6, [[1, 2, 3], [3, 4, 5]]).is_berge_cyclic() # needs sage.modules False TESTS:: @@ -1256,10 +1272,10 @@ def complement(self,uniform=False): :class:`~sage.combinat.designs.bibd.BalancedIncompleteBlockDesign` is also a `2`-design:: - sage: bibd = designs.balanced_incomplete_block_design(13,4) - sage: bibd.is_t_design(return_parameters=True) + sage: bibd = designs.balanced_incomplete_block_design(13,4) # needs sage.schemes + sage: bibd.is_t_design(return_parameters=True) # needs sage.schemes (True, (2, 13, 4, 1)) - sage: bibd.complement().is_t_design(return_parameters=True) + sage: bibd.complement().is_t_design(return_parameters=True) # needs sage.schemes (True, (2, 13, 9, 6)) The "uniform" complement of a graph is a graph:: @@ -1275,8 +1291,8 @@ def complement(self,uniform=False): TESTS:: - sage: bibd.relabel({i:str(i) for i in bibd.ground_set()}) - sage: bibd.complement().ground_set() + sage: bibd.relabel({i:str(i) for i in bibd.ground_set()}) # needs sage.schemes + sage: bibd.complement().ground_set() # needs sage.schemes ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'] sage: I = IncidenceStructure('abc', ['ab','ac','bc']) @@ -1294,9 +1310,9 @@ def complement(self,uniform=False): from itertools import combinations for B in combinations(range(self.num_points()),k): B = list(B) - while i<num_blocks and self._blocks[i] < B: + while i < num_blocks and self._blocks[i] < B: i += 1 - if i<num_blocks and self._blocks[i] == B: + if i < num_blocks and self._blocks[i] == B: i += 1 continue blocks.append(B) @@ -1332,17 +1348,19 @@ def relabel(self, perm=None, inplace=True): EXAMPLES:: - sage: TD=designs.transversal_design(5,5) - sage: TD.relabel({i:chr(97+i) for i in range(25)}) + sage: # needs sage.schemes + sage: TD = designs.transversal_design(5,5) + sage: TD.relabel({i: chr(97+i) for i in range(25)}) sage: TD.ground_set() - ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y'] + ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y'] sage: TD.blocks()[:3] [['a', 'f', 'k', 'p', 'u'], ['a', 'g', 'm', 's', 'y'], ['a', 'h', 'o', 'q', 'x']] Relabel to integer points:: - sage: TD.relabel() - sage: TD.blocks()[:3] + sage: TD.relabel() # needs sage.schemes + sage: TD.blocks()[:3] # needs sage.schemes [[0, 5, 10, 15, 20], [0, 6, 12, 18, 24], [0, 7, 14, 16, 23]] TESTS: @@ -1361,7 +1379,7 @@ def relabel(self, perm=None, inplace=True): And one can also verify that we have exactly two automorphisms:: - sage: I.automorphism_group() + sage: I.automorphism_group() # needs sage.groups Permutation Group with generators [(2,4)] """ if not inplace: @@ -1427,10 +1445,10 @@ def packing(self, solver=None, verbose=0, *, integrality_tolerance=1e-3): EXAMPLES:: - sage: P = IncidenceStructure([[1,2],[3,4],[2,3]]).packing() - sage: sorted(sorted(b) for b in P) + sage: P = IncidenceStructure([[1,2],[3,4],[2,3]]).packing() # needs sage.numerical.mip + sage: sorted(sorted(b) for b in P) # needs sage.numerical.mip [[1, 2], [3, 4]] - sage: len(designs.steiner_triple_system(9).packing()) + sage: len(designs.steiner_triple_system(9).packing()) # needs sage.numerical.mip 3 """ from sage.numerical.mip import MixedIntegerLinearProgram @@ -1495,7 +1513,7 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): sage: BD.is_t_design(0,6,3,7) or BD.is_t_design(0,7,4,7) or BD.is_t_design(0,7,3,8) False - sage: BD = designs.AffineGeometryDesign(3, 1, GF(2)) + sage: BD = designs.AffineGeometryDesign(3, 1, GF(2)) # needs sage.rings.finite_rings sage: BD.is_t_design(1) True sage: BD.is_t_design(2) @@ -1520,13 +1538,13 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): Some examples of Witt designs that need the gap database:: - sage: BD = designs.WittDesign(9) # optional - gap_packages - sage: BD.is_t_design(2,9,3,1) # optional - gap_packages + sage: BD = designs.WittDesign(9) # optional - gap_package_design + sage: BD.is_t_design(2,9,3,1) # optional - gap_package_design True - sage: W12 = designs.WittDesign(12) # optional - gap_packages - sage: W12.is_t_design(5,12,6,1) # optional - gap_packages + sage: W12 = designs.WittDesign(12) # optional - gap_package_design + sage: W12.is_t_design(5,12,6,1) # optional - gap_package_design True - sage: W12.is_t_design(4) # optional - gap_packages + sage: W12.is_t_design(4) # optional - gap_package_design True Further examples:: @@ -1564,12 +1582,15 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): [(8, 4, 7)] sage: [(v,k,l) for v in R for k in R for l in R if S4_8.is_t_design(0,v,k,l)] [(8, 4, 14)] + + sage: # needs sage.rings.finite_rings sage: A = designs.AffineGeometryDesign(3, 1, GF(2)) sage: A.is_t_design(return_parameters=True) (True, (2, 8, 2, 1)) sage: A = designs.AffineGeometryDesign(4, 2, GF(2)) sage: A.is_t_design(return_parameters=True) (True, (3, 16, 4, 1)) + sage: I = IncidenceStructure(2, []) sage: I.is_t_design(return_parameters=True) (True, (0, 2, 0, 0)) @@ -1577,7 +1598,7 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): sage: I.is_t_design(return_parameters=True) (False, (0, 0, 0, 0)) """ - from sage.arith.all import binomial + from sage.arith.misc import binomial # Missing parameters ? if v is None: @@ -1597,14 +1618,14 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): return (False, (0,0,0,0)) if return_parameters else False # Trivial case t>k - if (t is not None and t>k): + if (t is not None and t > k): if (l is None or l == 0): return (True, (t,v,k,0)) if return_parameters else True else: return (False, (0,0,0,0)) if return_parameters else False # Trivial case k=0 - if k==0: + if k == 0: if (l is None or l == 0): return (True, (0,v,k,b)) if return_parameters else True else: @@ -1643,8 +1664,8 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): ll = b*binomial(k,tt) // binomial(v,tt) - if ((t is not None and t!=tt) or - (l is not None and l!=ll)): + if ((t is not None and t != tt) or + (l is not None and l != ll)): return (False, (0,0,0,0)) if return_parameters else False else: if tt == 0: @@ -1691,30 +1712,31 @@ def is_generalized_quadrangle(self, verbose=False, parameters=False): EXAMPLES:: - sage: h = designs.CremonaRichmondConfiguration() - sage: h.is_generalized_quadrangle() + sage: h = designs.CremonaRichmondConfiguration() # needs networkx + sage: h.is_generalized_quadrangle() # needs networkx True This is actually a *regular* generalized quadrangle:: - sage: h.is_generalized_quadrangle(parameters=True) + sage: h.is_generalized_quadrangle(parameters=True) # needs networkx (2, 2) TESTS:: sage: H = IncidenceStructure((2*graphs.CompleteGraph(3)).edges(sort=True, labels=False)) - sage: H.is_generalized_quadrangle(verbose=True) + sage: H.is_generalized_quadrangle(verbose=True) # needs sage.modules Some point is at distance >3 from some block. False sage: G = graphs.CycleGraph(5) - sage: B = list(G.subgraph_search_iterator(graphs.PathGraph(3), return_graphs=False)) - sage: H = IncidenceStructure(B) - sage: H.is_generalized_quadrangle(verbose=True) + sage: B = list(G.subgraph_search_iterator(graphs.PathGraph(3), # needs sage.modules + ....: return_graphs=False)) + sage: H = IncidenceStructure(B) # needs sage.modules + sage: H.is_generalized_quadrangle(verbose=True) # needs sage.modules Two blocks intersect on >1 points. False - sage: hypergraphs.CompleteUniform(4,2).is_generalized_quadrangle(verbose=1) + sage: hypergraphs.CompleteUniform(4,2).is_generalized_quadrangle(verbose=1) # needs sage.modules Some point has two projections on some line. False """ @@ -1741,8 +1763,8 @@ def is_generalized_quadrangle(self, verbose=False, parameters=False): if parameters: s = self.is_uniform() t = self.is_regular() - s = s-1 if (s is not False and s>=2) else False - t = t-1 if (t is not False and t>=2) else False + s = s-1 if (s is not False and s >= 2) else False + t = t-1 if (t is not False and t >= 2) else False return (s,t) else: return True @@ -1765,26 +1787,24 @@ def dual(self, algorithm=None): The dual of a projective plane is a projective plane:: - sage: PP = designs.DesarguesianProjectivePlaneDesign(4) - sage: PP.dual().is_t_design(return_parameters=True) + sage: PP = designs.DesarguesianProjectivePlaneDesign(4) # needs sage.rings.finite_rings + sage: PP.dual().is_t_design(return_parameters=True) # needs sage.modules sage.rings.finite_rings (True, (2, 21, 5, 1)) TESTS:: - sage: D = IncidenceStructure(4, [[0,2],[1,2,3],[2,3]]) - sage: D + sage: D = IncidenceStructure(4, [[0,2],[1,2,3],[2,3]]); D Incidence structure with 4 points and 3 blocks - sage: D.dual() + sage: D.dual() # needs sage.modules Incidence structure with 3 points and 4 blocks - sage: print(D.dual(algorithm="gap")) # optional - gap_packages + sage: print(D.dual(algorithm="gap")) # optional - gap_package_design Incidence structure with 3 points and 4 blocks sage: blocks = [[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]] - sage: BD = IncidenceStructure(7, blocks, name="FanoPlane") - sage: BD + sage: BD = IncidenceStructure(7, blocks, name="FanoPlane"); BD Incidence structure with 7 points and 7 blocks - sage: print(BD.dual(algorithm="gap")) # optional - gap_packages + sage: print(BD.dual(algorithm="gap")) # optional - gap_package_design Incidence structure with 7 points and 7 blocks - sage: BD.dual() + sage: BD.dual() # needs sage.modules Incidence structure with 7 points and 7 blocks REFERENCE: @@ -1811,6 +1831,7 @@ def automorphism_group(self): EXAMPLES:: + sage: # needs sage.groups sage.rings.finite_rings sage: P = designs.DesarguesianProjectivePlaneDesign(2); P (7,3,1)-Balanced Incomplete Block Design sage: G = P.automorphism_group() @@ -1824,17 +1845,17 @@ def automorphism_group(self): A non self-dual example:: sage: IS = IncidenceStructure(list(range(4)), [[0,1,2,3],[1,2,3]]) - sage: IS.automorphism_group().cardinality() + sage: IS.automorphism_group().cardinality() # needs sage.groups 6 - sage: IS.dual().automorphism_group().cardinality() + sage: IS.dual().automorphism_group().cardinality() # needs sage.groups sage.modules 1 Examples with non-integer points:: sage: I = IncidenceStructure('abc', ('ab','ac','bc')) - sage: I.automorphism_group() + sage: I.automorphism_group() # needs sage.groups Permutation Group with generators [('b','c'), ('a','b')] - sage: IncidenceStructure([[(1,2),(3,4)]]).automorphism_group() + sage: IncidenceStructure([[(1,2),(3,4)]]).automorphism_group() # needs sage.groups Permutation Group with generators [((1,2),(3,4))] """ from sage.graphs.graph import Graph @@ -1846,11 +1867,11 @@ def automorphism_group(self): list(range(n,n+self.num_blocks()))]) if self._point_to_index: - gens = [[tuple([self._points[i] for i in cycle if (not cycle or cycle[0]<n)]) + gens = [[tuple([self._points[i] for i in cycle if (not cycle or cycle[0] < n)]) for cycle in g.cycle_tuples()] for g in ag.gens()] else: - gens = [[tuple(cycle) for cycle in g.cycle_tuples() if (not cycle or cycle[0]<n)] + gens = [[tuple(cycle) for cycle in g.cycle_tuples() if (not cycle or cycle[0] < n)] for g in ag.gens()] return PermutationGroup(gens, domain=self._points) @@ -1903,19 +1924,19 @@ def is_resolvable(self, certificate=False, solver=None, verbose=0, check=True, sage: TD.is_resolvable() True - sage: AG = designs.AffineGeometryDesign(3,1,GF(2)) - sage: AG.is_resolvable() + sage: AG = designs.AffineGeometryDesign(3,1,GF(2)) # needs sage.rings.finite_rings + sage: AG.is_resolvable() # needs sage.rings.finite_rings True Their classes:: - sage: b,cls = TD.is_resolvable(True) + sage: b, cls = TD.is_resolvable(True) sage: b True sage: cls # random [[[0, 3], [1, 2]], [[1, 3], [0, 2]]] - sage: b,cls = AG.is_resolvable(True) + sage: b, cls = AG.is_resolvable(True) # needs sage.rings.finite_rings sage: b True sage: cls # random @@ -1929,17 +1950,17 @@ def is_resolvable(self, certificate=False, solver=None, verbose=0, check=True, A non-resolvable design:: - sage: Fano = designs.balanced_incomplete_block_design(7,3) - sage: Fano.is_resolvable() + sage: Fano = designs.balanced_incomplete_block_design(7,3) # needs sage.schemes + sage: Fano.is_resolvable() # needs sage.schemes False - sage: Fano.is_resolvable(True) + sage: Fano.is_resolvable(True) # needs sage.schemes (False, []) TESTS:: - sage: _,cls1 = AG.is_resolvable(certificate=True) - sage: _,cls2 = AG.is_resolvable(certificate=True) - sage: cls1 is cls2 + sage: _, cls1 = AG.is_resolvable(certificate=True) # needs sage.rings.finite_rings + sage: _, cls2 = AG.is_resolvable(certificate=True) # needs sage.rings.finite_rings + sage: cls1 is cls2 # needs sage.rings.finite_rings False """ if self._classes is None: @@ -2000,7 +2021,6 @@ def is_resolvable(self, certificate=False, solver=None, verbose=0, check=True, else: return True - def coloring(self, k=None, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" @@ -2037,12 +2057,12 @@ def coloring(self, k=None, solver=None, verbose=0, The Fano plane has chromatic number 3:: - sage: len(designs.steiner_triple_system(7).coloring()) + sage: len(designs.steiner_triple_system(7).coloring()) # needs sage.numerical.mip 3 One admissible 3-coloring:: - sage: designs.steiner_triple_system(7).coloring() # not tested - architecture-dependent + sage: designs.steiner_triple_system(7).coloring() # not tested # needs sage.numerical.mip [[0, 2, 5, 1], [4, 3], [6]] The chromatic number of a graph is equal to the chromatic number of its @@ -2052,7 +2072,7 @@ def coloring(self, k=None, solver=None, verbose=0, sage: H = IncidenceStructure(g.edges(sort=True, labels=False)) sage: len(g.coloring()) 3 - sage: len(H.coloring()) + sage: len(H.coloring()) # needs sage.numerical.mip 3 """ if k is None: @@ -2070,7 +2090,7 @@ def coloring(self, k=None, solver=None, verbose=0, raise RuntimeError("No coloring can be defined " "when there is a set of size 1") elif k == 1: - if any(x for x in self._blocks): + if any(self._blocks): raise ValueError("This hypergraph contains a set. " "It is not 1-chromatic") return [self.ground_set()] @@ -2147,10 +2167,11 @@ def _spring_layout(self): EXAMPLES:: + sage: # needs sage.plot sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H Incidence structure with 6 points and 4 blocks sage: L = H._spring_layout() - sage: L # random + sage: L # random {1: (0.238, -0.926), 2: (0.672, -0.518), 3: (0.449, -0.225), @@ -2163,7 +2184,7 @@ def _spring_layout(self): {1, 2, 3}: (0.393, -0.617)} sage: all(v in L for v in H.ground_set()) True - sage: all(v in L for v in map(Set,H.blocks())) + sage: all(v in L for v in map(Set, H.blocks())) True """ from sage.graphs.graph import Graph @@ -2173,7 +2194,7 @@ def _spring_layout(self): for x in s: g.add_edge((0, s), (1, x)) - _ = g.plot(iterations = 50000,save_pos=True) + _ = g.plot(iterations=50000,save_pos=True) # The values are rounded as TikZ does not like accuracy. return {k[1]: (round(x, 3), round(y, 3)) @@ -2193,16 +2214,17 @@ def _latex_(self): sage: g = graphs.Grid2dGraph(5,5) sage: C4 = graphs.CycleGraph(4) - sage: sets = Set(map(Set,list(g.subgraph_search_iterator(C4, return_graphs=False)))) - sage: H = Hypergraph(sets) - sage: view(H) # not tested + sage: sets = Set(map(Set, g.subgraph_search_iterator(C4, # needs sage.modules + ....: return_graphs=False))) + sage: H = Hypergraph(sets) # needs sage.modules + sage: view(H) # not tested # needs sage.modules sage.plot TESTS:: # verify that :trac:`30976` is fixed sage: IS = IncidenceStructure([1,2,3], [[1,2], [2,3]]) sage: if latex.has_file("tikz.sty"): # optional - latex - ....: IS._latex_() # optional - latex + ....: IS._latex_() ...UserWarning: The hypergraph is drawn as a set of closed curves... \begin{tikzpicture}... @@ -2239,12 +2261,12 @@ def _latex_(self): # Prints each set with its color for s,i in colored_sets: - current_color = colors[i%len(colors)] + current_color = colors[i % len(colors)] if len(s) == 2: s = list(s) - tex += ("\\draw[color="+str(current_color)+","+ - "line width=.1cm,opacity = .6] "+ + tex += ("\\draw[color="+str(current_color)+"," + + "line width=.1cm,opacity = .6] " + str(pos[s[0]])+" -- "+str(pos[s[1]])+";\n") continue @@ -2258,7 +2280,7 @@ def _latex_(self): # "center", i.e. the vertex representing the set s cx, cy = pos[Set(s)] s = [pos[_] for _ in s] - s = sorted(s, key = lambda x_y: arctan2(x_y[0] - cx, x_y[1] - cy)) + s = sorted(s, key=lambda x_y: arctan2(x_y[0] - cx, x_y[1] - cy)) for x in s: tex += str(x)+" " diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index 9daa508e07d..f67a2317a17 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -1,11 +1,11 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.modules r""" Mutually Orthogonal Latin Squares (MOLS) The main function of this module is :func:`mutually_orthogonal_latin_squares` and can be can be used to generate MOLS (or check that they exist):: - sage: MOLS = designs.mutually_orthogonal_latin_squares(4,8) + sage: MOLS = designs.mutually_orthogonal_latin_squares(4,8) # needs sage.schemes For more information on MOLS, see the :wikipedia:`Wikipedia entry on MOLS <Graeco-Latin_square#Mutually_orthogonal_Latin_squares>`. If you are only @@ -155,8 +155,8 @@ def are_mutually_orthogonal_latin_squares(l, verbose=False): Squares 0 and 2 are not orthogonal False - sage: m = designs.mutually_orthogonal_latin_squares(7,8) - sage: are_mutually_orthogonal_latin_squares(m) + sage: m = designs.mutually_orthogonal_latin_squares(7,8) # needs sage.schemes + sage: are_mutually_orthogonal_latin_squares(m) # needs sage.schemes True TESTS: @@ -239,7 +239,7 @@ def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): EXAMPLES:: - sage: designs.mutually_orthogonal_latin_squares(4,5) + sage: designs.mutually_orthogonal_latin_squares(4,5) # needs sage.schemes [ [0 2 4 1 3] [0 3 1 4 2] [0 4 3 2 1] [0 1 2 3 4] [4 1 3 0 2] [3 1 4 2 0] [2 1 0 4 3] [4 0 1 2 3] @@ -248,7 +248,7 @@ def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): [1 3 0 2 4], [2 0 3 1 4], [3 2 1 0 4], [1 2 3 4 0] ] - sage: designs.mutually_orthogonal_latin_squares(3,7) + sage: designs.mutually_orthogonal_latin_squares(3,7) # needs sage.schemes [ [0 2 4 6 1 3 5] [0 3 6 2 5 1 4] [0 4 1 5 2 6 3] [6 1 3 5 0 2 4] [5 1 4 0 3 6 2] [4 1 5 2 6 3 0] @@ -259,7 +259,7 @@ def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): [1 3 5 0 2 4 6], [2 5 1 4 0 3 6], [3 0 4 1 5 2 6] ] - sage: designs.mutually_orthogonal_latin_squares(2,5,partitions=True) + sage: designs.mutually_orthogonal_latin_squares(2,5,partitions=True) # needs sage.schemes [[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], @@ -283,7 +283,7 @@ def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): What is the maximum number of MOLS of size 8 that Sage knows how to build?:: - sage: designs.orthogonal_arrays.largest_available_k(8)-2 + sage: designs.orthogonal_arrays.largest_available_k(8)-2 # needs sage.schemes 7 If you only want to know if Sage is able to build a given set of @@ -291,12 +291,12 @@ def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): sage: designs.orthogonal_arrays.is_available(5+2, 5) # 5 MOLS of order 5 False - sage: designs.orthogonal_arrays.is_available(4+2,6) # 4 MOLS of order 6 + sage: designs.orthogonal_arrays.is_available(4+2,6) # 4 MOLS of order 6 # needs sage.schemes False Sage, however, is not able to prove that the second MOLS do not exist:: - sage: designs.orthogonal_arrays.exists(4+2,6) # 4 MOLS of order 6 + sage: designs.orthogonal_arrays.exists(4+2,6) # 4 MOLS of order 6 # needs sage.schemes Unknown If you ask for such a MOLS then you will respectively get an informative @@ -306,7 +306,7 @@ def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): Traceback (most recent call last): ... EmptySetError: there exist at most n-1 MOLS of size n if n>=2 - sage: designs.mutually_orthogonal_latin_squares(4,6) + sage: designs.mutually_orthogonal_latin_squares(4,6) # needs sage.schemes Traceback (most recent call last): ... NotImplementedError: I don't know how to build 4 MOLS of order 6 @@ -431,8 +431,8 @@ def latin_square_product(M, N, *others): EXAMPLES:: sage: from sage.combinat.designs.latin_squares import latin_square_product - sage: m=designs.mutually_orthogonal_latin_squares(3,4)[0] - sage: latin_square_product(m,m,m) + sage: m=designs.mutually_orthogonal_latin_squares(3,4)[0] # needs sage.schemes + sage: latin_square_product(m,m,m) # needs sage.schemes 64 x 64 sparse matrix over Integer Ring (use the '.str()' method to see the entries) """ from sage.matrix.constructor import Matrix @@ -476,6 +476,7 @@ def MOLS_table(start,stop=None,compare=False,width=None): EXAMPLES:: + sage: # needs sage.schemes sage: from sage.combinat.designs.latin_squares import MOLS_table sage: MOLS_table(100) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @@ -512,10 +513,10 @@ def MOLS_table(start,stop=None,compare=False,width=None): if stop is None: start,stop = 0,start # make start and stop be congruent to 0 mod 20 - start = start - (start%20) - stop = stop-1 - stop = stop + (20-(stop%20)) - assert start%20 == 0 and stop%20 == 0 + start = start - (start % 20) + stop = stop-1 + stop = stop + (20-(stop % 20)) + assert start % 20 == 0 and stop % 20 == 0 if stop <= start: return diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index 388a3a777cc..c4936f79853 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Orthogonal arrays (OA) @@ -360,7 +361,7 @@ def transversal_design(k, n, resolvable=False, check=True, existence=False): return False raise EmptySetError("There exists no TD({},{})!".format(k,n)) - OA = orthogonal_array(k,n, check = False) + OA = orthogonal_array(k,n, check=False) TD = [[i*n+c for i,c in enumerate(l)] for l in OA] else: @@ -407,9 +408,9 @@ def __init__(self, blocks, k=None,n=None,check=True,**kwds): from math import sqrt if k is None: if blocks: - k=len(blocks[0]) + k = len(blocks[0]) else: - k=0 + k = 0 if n is None: n = round(sqrt(len(blocks))) @@ -473,7 +474,7 @@ def is_transversal_design(B, k, n, verbose=False): sage: is_transversal_design(TD, 4, 4) False """ - return is_orthogonal_array([[x%n for x in R] for R in B],k,n,verbose=verbose) + return is_orthogonal_array([[x % n for x in R] for R in B],k,n,verbose=verbose) def wilson_construction(OA,k,r,m,u,check=True,explain_construction=False): r""" @@ -613,7 +614,7 @@ def wilson_construction(OA,k,r,m,u,check=True,explain_construction=False): master_design = OA for c in u: - assert all(m_ij>=0 and h_size>=0 for m_ij,h_size in c) + assert all(m_ij >= 0 and h_size >= 0 for m_ij,h_size in c) assert sum(h_size for m_ij,h_size in c) <= r # Associates a point ij from a truncated column k+i to @@ -622,7 +623,7 @@ def wilson_construction(OA,k,r,m,u,check=True,explain_construction=False): # - its corresponding set of points in the final design. point_to_mij = [] point_to_point_set = [] - n=r*m + n = r*m for i,partition in enumerate(u): column_i_point_to_mij = [] column_i_point_to_point_set = [] @@ -630,7 +631,7 @@ def wilson_construction(OA,k,r,m,u,check=True,explain_construction=False): for _ in range(h_size): column_i_point_to_mij.append(mij) column_i_point_to_point_set.append(list(range(n,n+mij))) - n+=mij + n += mij point_to_mij.append(column_i_point_to_mij) point_to_point_set.append(column_i_point_to_point_set) @@ -832,11 +833,11 @@ def orthogonal_array(k,n,t=2,resolvable=False, check=True,existence=False,explai True sage: _ = designs.orthogonal_arrays.build(t,5,t) """ - assert n>=0, "n(={}) must be nonnegative".format(n) + assert n >= 0, "n(={}) must be nonnegative".format(n) # A resolvable OA(k,n) is an OA(k+1,n) if resolvable: - assert t==2, "resolvable designs are only handled when t=2" + assert t == 2, "resolvable designs are only handled when t=2" if existence and k is not None: return orthogonal_array(k+1,n,existence=True) if k is None: @@ -909,7 +910,7 @@ def orthogonal_array(k,n,t=2,resolvable=False, check=True,existence=False,explai return True if explain_construction: return "Cyclic latin square" - return [[i,j,(i+j)%n] for i in range(n) for j in range(n)] + return [[i,j,(i+j) % n] for i in range(n) for j in range(n)] # projective spaces are equivalent to OA(n+1,n,2) elif (projective_plane(n, existence=True) is True or @@ -961,12 +962,12 @@ def orthogonal_array(k,n,t=2,resolvable=False, check=True,existence=False,explai # Constructions from the database III (Quasi-difference matrices) elif (may_be_available and (n,1) in QDM and - any(kk>=k and mu<=lmbda and (orthogonal_array(k,u,existence=True) is True) for (_,lmbda,mu,u),(kk,_) in QDM[n,1].items())): + any(kk >= k and mu <= lmbda and (orthogonal_array(k,u,existence=True) is True) for (_,lmbda,mu,u),(kk,_) in QDM[n,1].items())): _OA_cache_set(k,n,True) for (nn,lmbda,mu,u),(kk,f) in QDM[n,1].items(): - if (kk>=k and - mu<=lmbda and + if (kk >= k and + mu <= lmbda and (orthogonal_array(k,u,existence=True) is True)): if existence: return True @@ -1037,9 +1038,9 @@ def largest_available_k(n,t=2): ValueError: n(=-1) was expected to be >=0 """ from .block_design import projective_plane - if n<0: + if n < 0: raise ValueError("n(={}) was expected to be >=0".format(n)) - if t<0: + if t < 0: raise ValueError("t(={}) was expected to be >=0".format(t)) if n == 0 or n == 1: from sage.rings.infinity import Infinity @@ -1048,11 +1049,11 @@ def largest_available_k(n,t=2): if projective_plane(n,existence=True) is True: return n+1 else: - k=1 + k = 1 while _OA_cache_construction_available(k+1,n) is True: - k=k+1 + k = k+1 else: - k=t-1 + k = t-1 while orthogonal_array(k+1,n,t,existence=True) is True: k += 1 @@ -1180,11 +1181,12 @@ def incomplete_orthogonal_array(k,n,holes,resolvable=False, existence=False): 10 holes of size 9 through the product construction:: - sage: iOA = designs.incomplete_orthogonal_array(10,153,[9]*10) # long time - sage: OA9 = designs.orthogonal_arrays.build(10,9) # long time - sage: for i in range(10): # long time - ....: iOA.extend([[153-9*(i+1)+x for x in B] for B in OA9]) # long time - sage: is_orthogonal_array(iOA,10,153) # long time + sage: # long time + sage: iOA = designs.incomplete_orthogonal_array(10,153,[9]*10) + sage: OA9 = designs.orthogonal_arrays.build(10,9) + sage: for i in range(10): + ....: iOA.extend([[153-9*(i+1)+x for x in B] for B in OA9]) + sage: is_orthogonal_array(iOA,10,153) True An `OA(9,82)-OA(9,9)-OA(9,1)`:: @@ -1219,18 +1221,18 @@ def incomplete_orthogonal_array(k,n,holes,resolvable=False, existence=False): """ from sage.combinat.designs.database import QDM for h in holes: - if h<0: + if h < 0: raise ValueError("Holes must have size >=0, but {} was in the list").format(h) - holes = [h for h in holes if h>0] + holes = [h for h in holes if h > 0] if not holes: return orthogonal_array(k,n,existence=existence,resolvable=resolvable) - sum_of_holes = sum(holes) + sum_of_holes = sum(holes) number_of_holes = len(holes) - max_hole = max(holes) - min_hole = min(holes) + max_hole = max(holes) + min_hole = min(holes) if sum_of_holes > n: if existence: @@ -1245,7 +1247,7 @@ def incomplete_orthogonal_array(k,n,holes,resolvable=False, existence=False): raise EmptySetError("There is no resolvable incomplete OA({},{}) whose holes' sizes sum to {}<n(={})".format(k,n,sum_of_holes,n)) # resolvable OA(k,n)-n.OA(k,1) ==> equivalent to OA(k+1,n) - if max_hole==1 and resolvable: + if max_hole == 1 and resolvable: if existence: return orthogonal_array(k+1,n,existence=True) @@ -1265,7 +1267,7 @@ def incomplete_orthogonal_array(k,n,holes,resolvable=False, existence=False): return OA[:-n] # Easy case - elif max_hole==1 and number_of_holes <= 1: + elif max_hole == 1 and number_of_holes <= 1: if existence: return orthogonal_array(k,n,existence=True) OA = orthogonal_array(k,n) @@ -1297,7 +1299,7 @@ def incomplete_orthogonal_array(k,n,holes,resolvable=False, existence=False): # place the first hole of size 1 i = holes.index(1) for h1 in IOA: - if all(x<n-max_hole for x in h1): + if all(x < n-max_hole for x in h1): break holes[i] = [h1] IOA.remove(h1) @@ -1306,7 +1308,7 @@ def incomplete_orthogonal_array(k,n,holes,resolvable=False, existence=False): if number_of_holes == 3: i = holes.index(1) for h2 in IOA: - if all(h1[j] != x and x<n-max_hole for j,x in enumerate(h2)): + if all(h1[j] != x and x < n-max_hole for j,x in enumerate(h2)): break holes[i] = [h2] IOA.remove(h2) @@ -1325,21 +1327,21 @@ def incomplete_orthogonal_array(k,n,holes,resolvable=False, existence=False): IOA = OA_relabel(IOA,k,n,matrix=holes) return IOA - elif max_hole==1 and number_of_holes >= 2 and k == n+1: + elif max_hole == 1 and number_of_holes >= 2 and k == n+1: if existence: return False raise EmptySetError(("There is no OA(n+1,n) - {}.OA(n+1,1) as all blocks " "intersect in a projective plane.").format(number_of_holes)) # Holes of size 1 from OA(k+1,n) - elif max_hole==1 and orthogonal_array(k+1,n,existence=True) is True: + elif max_hole == 1 and orthogonal_array(k+1,n,existence=True) is True: if existence: return True OA = orthogonal_array(k+1,n) independent_set = [B[:-1] for B in OA if B[-1] == 0][:number_of_holes] OA = [B[:-1] for B in OA] - elif max_hole==1 and orthogonal_array(k,n,existence=True) is True: + elif max_hole == 1 and orthogonal_array(k,n,existence=True) is True: OA = orthogonal_array(k,n) try: independent_set = OA_find_disjoint_blocks(OA,k,n,number_of_holes) @@ -1351,7 +1353,7 @@ def incomplete_orthogonal_array(k,n,holes,resolvable=False, existence=False): return True independent_set = OA_find_disjoint_blocks(OA,k,n,number_of_holes) - elif max_hole==1 and not orthogonal_array(k,n,existence=True) is True: + elif max_hole == 1 and not orthogonal_array(k,n,existence=True) is True: return orthogonal_array(k,n,existence=existence) # From a quasi-difference matrix @@ -1362,7 +1364,7 @@ def incomplete_orthogonal_array(k,n,holes,resolvable=False, existence=False): if uu == sum_of_holes and mu <= 1 and lmbda == 1 and k <= kk + 1: break G,M = f() - OA = OA_from_quasi_difference_matrix(M,G,fill_hole=False) + OA = OA_from_quasi_difference_matrix(M,G,fill_hole=False) return [B[:k] for B in OA] # Equal holes [h,h,...] with h>1 through OA product construction @@ -1370,12 +1372,12 @@ def incomplete_orthogonal_array(k,n,holes,resolvable=False, existence=False): # (i.e. OA(k,n1)-x.OA(k,1) and OA(k,n2) ==> OA(k,n1.n2)-x.OA(k,n2) ) elif (min_hole > 1 and max_hole == min_hole and - n%min_hole == 0 and # h divides n - orthogonal_array(k,min_hole,existence=True) and # OA(k,h) + n % min_hole == 0 and # h divides n + orthogonal_array(k,min_hole,existence=True) and # OA(k,h) incomplete_orthogonal_array(k,n//min_hole,[1]*number_of_holes,existence=True)): # OA(k,n/h)-x.OA(k,1) if existence: return True - h = min_hole + h = min_hole iOA1 = incomplete_orthogonal_array(k,n//holes[0],[1]*number_of_holes) iOA2 = orthogonal_array(k,h) @@ -1843,7 +1845,7 @@ def OA_from_Vmt(m,t,V): sage: _ = designs.orthogonal_arrays.build(6,46) # indirect doctest """ Fq, M = QDM_from_Vmt(m,t,V) - return OA_from_quasi_difference_matrix(M,Fq,add_col = False) + return OA_from_quasi_difference_matrix(M,Fq,add_col=False) def QDM_from_Vmt(m,t,V): @@ -1954,7 +1956,8 @@ def OA_from_PBD(k,n,PBD, check=True): sage: OA_from_PBD(4,10,pbd) Traceback (most recent call last): ... - EmptySetError: There is no OA(n+1,n) - 3.OA(n+1,1) as all blocks intersect in a projective plane. + EmptySetError: There is no OA(n+1,n) - 3.OA(n+1,1) + as all blocks intersect in a projective plane. Or an `OA(3,6)` (as the PBD has 10 points):: @@ -2088,7 +2091,7 @@ def __init__(self,*args,**kwds): """ raise RuntimeError("This is not a function but a class. You want to call the designs.orthogonal_arrays.* functions") - largest_available_k = staticmethod(largest_available_k) + largest_available_k = staticmethod(largest_available_k) @staticmethod def explain_construction(k,n,t=2): diff --git a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py index 526487adb97..1f434d49494 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py +++ b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Orthogonal arrays (build recursive constructions) @@ -77,14 +78,14 @@ def construction_3_3(k,n,m,i,explain_construction=False): from .orthogonal_arrays import wilson_construction, OA_relabel, incomplete_orthogonal_array if explain_construction: return (("Construction 3.3 with n={},m={},i={} from:\n" - " Julian R. Abel, Nicholas Cavenagh\n"+ - " Concerning eight mutually orthogonal latin squares,\n"+ - " Vol. 15, n.3, pp. 255-261,\n"+ + " Julian R. Abel, Nicholas Cavenagh\n" + + " Concerning eight mutually orthogonal latin squares,\n" + + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n,m,i)) # Builds an OA(k+i,n) containing a block [0]*(k+i) OA = incomplete_orthogonal_array(k+i,n,(1,)) - OA = [[(x+1)%n for x in B] for B in OA] + OA = [[(x+1) % n for x in B] for B in OA] # Truncated version OA = [B[:k]+[0 if x == 0 else None for x in B[k:]] for B in OA] @@ -145,14 +146,14 @@ def construction_3_4(k,n,m,r,s,explain_construction=False): Journal of Combinatorial Designs, 2007 """ if explain_construction: - return ("Construction 3.4 with n={},m={},r={},s={} from:\n"+ - " Julian R. Abel, Nicholas Cavenagh\n"+ - " Concerning eight mutually orthogonal latin squares,\n"+ - " Vol. 15, n.3, pp. 255-261,\n"+ + return ("Construction 3.4 with n={},m={},r={},s={} from:\n" + + " Julian R. Abel, Nicholas Cavenagh\n" + + " Concerning eight mutually orthogonal latin squares,\n" + + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n,m,r,s) from .orthogonal_arrays import wilson_construction, OA_relabel - assert s<n + assert s < n master_design = orthogonal_array(k+r+1,n) # Defines the first k+r columns of the matrix of labels @@ -227,9 +228,9 @@ def construction_3_5(k,n,m,r,s,t,explain_construction=False): if explain_construction: return (("Construction 3.5 with n={},m={},r={},s={},t={} from:\n" - " Julian R. Abel, Nicholas Cavenagh\n"+ - " Concerning eight mutually orthogonal latin squares,\n"+ - " Vol. 15, n.3, pp. 255-261,\n"+ + " Julian R. Abel, Nicholas Cavenagh\n" + + " Concerning eight mutually orthogonal latin squares,\n" + + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n,m,r,s,t)) master_design = orthogonal_array(k+3,q) @@ -313,15 +314,15 @@ def construction_3_6(k,n,m,i,explain_construction=False): """ if explain_construction: return (("Construction 3.6 with n={},m={},i={} from:\n" - " Julian R. Abel, Nicholas Cavenagh\n"+ - " Concerning eight mutually orthogonal latin squares,\n"+ - " Vol. 15, n.3, pp. 255-261,\n"+ + " Julian R. Abel, Nicholas Cavenagh\n" + + " Concerning eight mutually orthogonal latin squares,\n" + + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n,m,i)) from .orthogonal_arrays import wilson_construction OA = OA_and_oval(n) OA = [B[:k+i] for B in OA] - OA = [B[:k] + [x if x==0 else None for x in B[k:]] for B in OA] + OA = [B[:k] + [x if x == 0 else None for x in B[k:]] for B in OA] OA = wilson_construction(OA,k,n,m,[1]*i) assert is_orthogonal_array(OA,k,n*m+i) return OA @@ -365,7 +366,7 @@ def OA_and_oval(q, *, solver=None, integrality_tolerance=1e-3): sage: _ = OA_and_oval """ - from sage.arith.all import is_prime_power + from sage.arith.misc import is_prime_power from sage.combinat.designs.block_design import projective_plane from .orthogonal_arrays import OA_relabel @@ -419,13 +420,13 @@ def OA_and_oval(q, *, solver=None, integrality_tolerance=1e-3): oval.sort() # Turning the TD into an OA - BB = [[xx%q for xx in b] for b in BB] - oval = [xx%q for xx in oval] + BB = [[xx % q for xx in b] for b in BB] + oval = [xx % q for xx in oval] assert len(oval) == q # We relabel the "oval" as relabelled as [0,...,0] OA = OA_relabel(BB+([[0]+oval]),q+1,q,blocks=[[0]+oval]) - OA = [[(x+1)%q for x in B] for B in OA] + OA = [[(x+1) % q for x in B] for B in OA] OA.remove([0]*(q+1)) assert all(sum([xx == 0 for xx in b[1:]]) <= 2 for b in OA) @@ -517,10 +518,10 @@ def construction_q_x(k, q, x, check=True, explain_construction=False): from sage.combinat.designs.orthogonal_arrays import incomplete_orthogonal_array if explain_construction: - return ("(q-x)-construction with q={},x={} from:\n"+ - " Malcolm Greig,\n"+ - " Designs from projective planes and PBD bases,\n"+ - " vol. 7, num. 5, pp. 341--374,\n"+ + return ("(q-x)-construction with q={},x={} from:\n" + + " Malcolm Greig,\n" + + " Designs from projective planes and PBD bases,\n" + + " vol. 7, num. 5, pp. 341--374,\n" + " Journal of Combinatorial Designs, 1999").format(q, x) n = (q-1)*(q-x)+x+2 @@ -550,7 +551,7 @@ def construction_q_x(k, q, x, check=True, explain_construction=False): PBD = [[relabel[xx] for xx in B if xx not in points_to_delete] for B in TD] # Taking the unique block of size x+2 - assert list(map(len,PBD)).count(x+2)==1 + assert list(map(len,PBD)).count(x+2) == 1 for B in PBD: if len(B) == x+2: break @@ -668,8 +669,8 @@ def thwart_lemma_3_5(k,n,m,a,b,c,d=0,complement=False,explain_construction=False ....: [10, 13, 78, 9, 9, 13, 1], ....: [10, 13, 79, 9, 9, 13, 1]] sage: for k,n,m,a,b,c,d in l: # not tested -- too long - ....: OA = thwart_lemma_3_5(k,n,m,a,b,c,d,complement=True) # not tested -- too long - ....: assert is_orthogonal_array(OA,k,n*m+a+b+c+d,verbose=True) # not tested -- too long + ....: OA = thwart_lemma_3_5(k,n,m,a,b,c,d,complement=True) + ....: assert is_orthogonal_array(OA,k,n*m+a+b+c+d,verbose=True) sage: print(designs.orthogonal_arrays.explain_construction(10,1046)) Lemma 3.5 with n=13,m=79,a=9,b=1,c=0,d=9 from: @@ -683,21 +684,21 @@ def thwart_lemma_3_5(k,n,m,a,b,c,d=0,complement=False,explain_construction=False Charles J.Colbourn, Jeffrey H. Dinitz, Mieczyslaw Wojtas. Designs, Codes and Cryptography 5, no. 3 (1995): 189-197. """ - from sage.arith.all import is_prime_power + from sage.arith.misc import is_prime_power from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF if complement: a,b,c = n-a,n-b,n-c if explain_construction: - return ("Lemma 3.5 with n={},m={},a={},b={},c={},d={} from:\n"+ - " Charles J.Colbourn, Jeffrey H. Dinitz, Mieczyslaw Wojtas,\n"+ - " Thwarts in transversal designs,\n"+ + return ("Lemma 3.5 with n={},m={},a={},b={},c={},d={} from:\n" + + " Charles J.Colbourn, Jeffrey H. Dinitz, Mieczyslaw Wojtas,\n" + + " Thwarts in transversal designs,\n" + " Designs, Codes and Cryptography 5, no. 3 (1995): 189-197.").format(n,m,a,b,c,d) assert is_prime_power(n), "n(={}) must be a prime power".format(n) - assert a<=n and b<=n and c<=n and d<=n, "a,b,c,d (={},{},{},{}) must be <=n(={})".format(a,b,c,d,n) - assert a+b+c<=n+1, "{}={}+{}+{}=a+b+c>n+1={}+1 violates the assumptions".format(a+b+c,a,b,c,n) + assert a <= n and b <= n and c <= n and d <= n, "a,b,c,d (={},{},{},{}) must be <=n(={})".format(a,b,c,d,n) + assert a+b+c <= n+1, "{}={}+{}+{}=a+b+c>n+1={}+1 violates the assumptions".format(a+b+c,a,b,c,n) assert k+3+bool(d) <= n+1, "There exists no OA({},{}).".format(k+3+bool(d),n) G = GF(n,prefix='x') G_set = sorted(G) # sorted by lexicographic order, G[1] = 1 @@ -724,11 +725,11 @@ def thwart_lemma_3_5(k,n,m,a,b,c,d=0,complement=False,explain_construction=False assert n - len(third_complement) >= c # The keepers - first_set = list(range(a)) + first_set = list(range(a)) second_set = list(range(b)) - third_set = [x for x in range(n) if x not in third_complement][:c] + third_set = [x for x in range(n) if x not in third_complement][:c] - last_sets = [first_set, second_set, third_set] + last_sets = [first_set, second_set, third_set] if complement: last_sets = [set(range(n)).difference(s) for s in last_sets] @@ -797,14 +798,14 @@ def thwart_lemma_4_1(k,n,m,explain_construction=False): Canad. Math. Bull vol7 num.4 (1964) """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - from sage.arith.all import is_prime_power + from sage.arith.misc import is_prime_power from .block_design import DesarguesianProjectivePlaneDesign from itertools import chain if explain_construction: - return ("Lemma 4.1 with n={},m={} from:\n"+ - " Charles J.Colbourn, Jeffrey H. Dinitz, Mieczyslaw Wojtas,\n"+ - " Thwarts in transversal designs,\n"+ + return ("Lemma 4.1 with n={},m={} from:\n" + + " Charles J.Colbourn, Jeffrey H. Dinitz, Mieczyslaw Wojtas,\n" + + " Thwarts in transversal designs,\n" + " Designs, Codes and Cryptography 5, no. 3 (1995): 189-197.").format(n,m) assert is_prime_power(n), "n(={}) must be a prime power" @@ -833,11 +834,11 @@ def thwart_lemma_4_1(k,n,m,explain_construction=False): points = [[K(_) for _ in t] for t in points] # triples of K^3 AG_2_3 = [] for x,y,z in points: - if z!=0: + if z != 0: x,y,z = x/z,y/z,z/z AG_2_3.append(relabel[x]+n*relabel[y]) - elif y!=0: - x,y,z=x/y,y/y,z + elif y != 0: + x,y,z = x/y,y/y,z AG_2_3.append(q**2+relabel[x]) else: AG_2_3.append(q**2+q) @@ -870,7 +871,7 @@ def thwart_lemma_4_1(k,n,m,explain_construction=False): TD = [sorted(relabel[x] for x in B) for B in blocks] # We build the OA, removing unnecessary columns - OA = [[x%q for x in B[-k-4:]] for B in TD] + OA = [[x % q for x in B[-k-4:]] for B in TD] for B in OA: for i in range(4): if B[k+i] >= n-2: @@ -1001,9 +1002,9 @@ def three_factor_product(k,n1,n2,n3,check=False,explain_construction=False): assert n1 <= n2 and n2 <= n3 if explain_construction: - return ("Three-factor product with n={}.{}.{} from:\n"+ - " Peter J. Dukes, Alan C.H. Ling,\n"+ - " A three-factor product construction for mutually orthogonal latin squares,\n"+ + return ("Three-factor product with n={}.{}.{} from:\n" + + " Peter J. Dukes, Alan C.H. Ling,\n" + + " A three-factor product construction for mutually orthogonal latin squares,\n" + " https://arxiv.org/abs/1401.1466").format(n1, n2, n3) def assert_c_partition(classs,k,n,c): @@ -1012,10 +1013,10 @@ def assert_c_partition(classs,k,n,c): ``B[i]`` covers `[n]` exactly `c` times for every index `i`. """ c = int(c) - assert all(len(B)==k for B in classs), "A block has length {}!=k(={})".format(len(B),k) + assert all(len(B) == k for B in classs), "A block has length {}!=k(={})".format(len(B),k) assert len(classs) == n*c, "not the right number of blocks" for p in zip(*classs): - assert all(x==i//c for i,x in enumerate(sorted(p))), "A class is not c(={})-parallel".format(c) + assert all(x == i//c for i,x in enumerate(sorted(p))), "A class is not c(={})-parallel".format(c) def product_with_parallel_classes(OA1,k,g1,g2,g1_parall,parall,check=True): r""" @@ -1064,7 +1065,7 @@ def product_with_parallel_classes(OA1,k,g1,g2,g1_parall,parall,check=True): assert max(shift) < g1 for B1 in OA1: - copy_of_OA1.append([x2*g1+(x1+sh)%g1 for sh,x1,x2 in zip(shift,B1,B2)]) + copy_of_OA1.append([x2*g1+(x1+sh) % g1 for sh,x1,x2 in zip(shift,B1,B2)]) copies_of_OA1.append(copy_of_OA1) @@ -1109,7 +1110,7 @@ def product_with_parallel_classes(OA1,k,g1,g2,g1_parall,parall,check=True): # Leftover blocks become parallel classes. We must split them into slices of # length n3 - OA3_parall = [OA3[i:i+n3] for i in range(len(OA3_n1_parall)*n1*n3, len(OA3), n3)] + OA3_parall = [OA3[i:i+n3] for i in range(len(OA3_n1_parall)*n1*n3, len(OA3), n3)] # First product: OA1 and OA3 n1_parall, parall = product_with_parallel_classes(OA1,k,n1,n3,OA3_n1_parall,OA3_parall,check=check) @@ -1189,8 +1190,8 @@ def _reorder_matrix(matrix): matching = g.matching(algorithm="LP") col = [0]*N for x,i,_ in matching: - if i<N: - x,i=i,x + if i < N: + x,i = i,x col[i-N] = x matrix.append(col) g.delete_edges(matching) @@ -1387,34 +1388,34 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct from sage.combinat.designs.orthogonal_arrays import OA_from_PBD from .difference_family import difference_family from .orthogonal_arrays import incomplete_orthogonal_array - from sage.arith.all import is_prime_power + from sage.arith.misc import is_prime_power if explain_construction: - return ("Brouwer's separable design construction with t={},q={},x={} from:\n"+ - " Andries E. Brouwer,\n"+ - " A series of separable designs with application to pairwise orthogonal Latin squares\n"+ - " Vol. 1, n. 1, pp. 39-41,\n"+ + return ("Brouwer's separable design construction with t={},q={},x={} from:\n" + + " Andries E. Brouwer,\n" + + " A series of separable designs with application to pairwise orthogonal Latin squares\n" + + " Vol. 1, n. 1, pp. 39-41,\n" + " European Journal of Combinatorics, 1980").format(t,q,x) ########################################################### # Part 1: compute the separable PBD on t(q^2+q+1) points. # ########################################################### - assert t<q**2-q+1 - assert x>=0 + assert t < q**2-q+1 + assert x >= 0 assert is_prime_power(q) N2 = q**4+q**2+1 - N1 = q**2+ q +1 + N1 = q**2 + q + 1 # A projective plane on (q^2-q+1)*(q^2+q+1)=q^4+q^2+1 points B = difference_family(N2,q**2+1,1)[1][0] - BIBD = [[(xx+i)%N2 for xx in B] for i in range(N2)] + BIBD = [[(xx+i) % N2 for xx in B] for i in range(N2)] # Each congruence class mod q^2-q+1 yields a Baer subplane. Let's check that: m = q**2-q+1 for i in range(m): for B in BIBD: - assert sum((xx%m)==i for xx in B) in [1,q+1], sum((xx%m)==i for xx in B) + assert sum((xx % m) == i for xx in B) in [1,q+1], sum((xx % m) == i for xx in B) # We are only interested by the points of the first t Baer subplanes (each # has size q**2+q+1). Note that each block of the projective plane: @@ -1438,14 +1439,14 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct for B in BIBD: # Find the Baer subplane which B intersects on more than 1 point - B_mod = sorted(xx%m for xx in B) + B_mod = sorted(xx % m for xx in B) while B_mod.pop(0) != B_mod[0]: pass plane = B_mod[0] if plane < t: - blocks_of_size_q_plus_t.append([relabel[xx] for xx in B if xx%m<t]) + blocks_of_size_q_plus_t.append([relabel[xx] for xx in B if xx % m < t]) else: - partition_of_blocks_of_size_t[plane-t].append([relabel[xx] for xx in B if xx%m<t]) + partition_of_blocks_of_size_t[plane-t].append([relabel[xx] for xx in B if xx % m < t]) ############################################################################### # Separable design built ! @@ -1470,7 +1471,7 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct e2 = int(x != 1) e3 = int(x != q**2) e4 = int(x != t+q+1) - N = t*N1+x + N = t*N1+x # i) if x == 0: @@ -1540,8 +1541,8 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct # an OA(k,t) can be used instead of an OA(k+1,t) if x == q**2: - assert e3==0, "equivalent to x==q^2" - assert len(partition_of_blocks_of_size_t)==1, "also equivalent to exactly one partition into sets of size t" + assert e3 == 0, "equivalent to x==q^2" + assert len(partition_of_blocks_of_size_t) == 1, "also equivalent to exactly one partition into sets of size t" OA = [[B[xx] for xx in R] for R in orthogonal_array(k,t) for B in partition_of_blocks_of_size_t[0]] else: OA = OA_from_PBD(k,N,sum(partition_of_blocks_of_size_t,[]),check=False)[:-N] @@ -1561,7 +1562,7 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct blocks_of_size_q_plus_t = _reorder_matrix(blocks_of_size_q_plus_t) for i,classs in enumerate(OA_tq1_classes): - OA.extend([R[xx] if xx<t+q else N-i-1 for xx in B] for R in blocks_of_size_q_plus_t for B in classs) + OA.extend([R[xx] if xx < t+q else N-i-1 for xx in B] for R in blocks_of_size_q_plus_t for B in classs) # The set of size x OA.extend([N-1-xx for xx in R] for R in orthogonal_array(k,x)) @@ -1584,7 +1585,7 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct # There is one partition into blocks of size t, which we extend with # the new vertex. The OA on t+1 points does not have to be resolvable. - OA.extend([B[xx] if xx<t else N-1 for xx in R] + OA.extend([B[xx] if xx < t else N-1 for xx in R] for R in incomplete_orthogonal_array(k,t+1,[1]) for B in partition_of_blocks_of_size_t[0]) @@ -1604,15 +1605,14 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct # The set of size x OA.extend([N-xx-1 for xx in B] for B in orthogonal_array(k,x)) - # iv) - elif (x == q**2+1 and - orthogonal_array( k , x ,existence=True) and # d0 - orthogonal_array(k+e4, t+1 ,existence=True) and # d2-e4 - orthogonal_array(k+ 1,t+q+1,existence=True)): # d4-1 + elif (x == q**2 + 1 and + orthogonal_array(k, x, existence=True) and # d0 + orthogonal_array(k + e4, t + 1, existence=True) and # d2 - e4 + orthogonal_array(k + 1, t + q + 1, existence=True)): # d4 - 1 if verbose: - print("Case iv) with k={},q={},t={},x={},e4={}".format(k,q,t,x,e4)) + print(f"Case iv) with k={k},q={q},t={t},x={x},e4={e4}") # Sets of size t: # @@ -1620,7 +1620,7 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct if e4 == 0: # Only one partition into t-sets. The OA(k,t+1) needs not be resolvable - OA = [[B[xx] if xx<t else N-x for xx in R] + OA = [[B[xx] if xx < t else N-x for xx in R] for R in incomplete_orthogonal_array(k,t+1,[1]) for B in partition_of_blocks_of_size_t[0]] else: @@ -1643,14 +1643,14 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct blocks_of_size_q_plus_t = _reorder_matrix(blocks_of_size_q_plus_t) for i,classs in enumerate(OA_tq1_classes): - OA.extend([R[xx] if xx<t+q else N-i-1 for xx in B] for R in blocks_of_size_q_plus_t for B in classs) + OA.extend([R[xx] if xx < t+q else N-i-1 for xx in B] for R in blocks_of_size_q_plus_t for B in classs) # Set of size x OA_k_x = orthogonal_array(k,x) OA.extend([N-i-1 for i in R] for R in OA_k_x) # v) - elif (0<x and x<q**2-q+1-t and (e1 or e2) and # The result is wrong when e1=e2=0 + elif (0 < x and x < q**2-q+1-t and (e1 or e2) and # The result is wrong when e1=e2=0 orthogonal_array(k ,x ,existence=True) and # d0 orthogonal_array(k+e1,t ,existence=True) and # d1-e1 orthogonal_array(k+e2,t+1,existence=True) and # d2-e2 @@ -1664,14 +1664,14 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct # # We extend x partitions into blocks of size t with the new x elements if e2: - assert x!=1, "equivalent to e2==1" + assert x != 1, "equivalent to e2==1" for i,classs in enumerate(partition_of_blocks_of_size_t[:x]): for B in classs: B.append(N-1-i) OA.extend(OA_from_PBD(k,N,sum(partition_of_blocks_of_size_t[:x],[]),check=False)[:-N]) else: - assert x==1, "equivalent to e2==0" + assert x == 1, "equivalent to e2==0" # Only one class, the OA(k,t+1) need not be resolvable. OA.extend([B[xx] if xx < t else N-1 for xx in R] for R in incomplete_orthogonal_array(k,t+1,[1]) @@ -1679,10 +1679,10 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct # Sets of size t if e1: - assert x!=q**2-q-t, "equivalent to e1=1" + assert x != q**2-q-t, "equivalent to e1=1" OA.extend(OA_from_PBD(k,N,sum(partition_of_blocks_of_size_t[x:],[]),check=False)[:-N]) else: - assert x==q**2-q-t, "equivalent to e1=0" + assert x == q**2-q-t, "equivalent to e1=0" # Only one class. The OA(k,t) needs not be resolvable OA.extend([B[xx] for xx in R] for R in orthogonal_array(k,t) for B in partition_of_blocks_of_size_t[-1]) @@ -1699,7 +1699,7 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct OA.extend([N-i-1 for i in R] for R in orthogonal_array(k,x)) # vi) - elif (t+q<x and x<q**2+1 and (e3 or e4) and # The result is wrong when e3=e4=0 + elif (t+q < x and x < q**2+1 and (e3 or e4) and # The result is wrong when e3=e4=0 orthogonal_array(k ,x ,existence=True) and # d0 orthogonal_array(k+e3,t ,existence=True) and # d1-e3 orthogonal_array(k+e4,t+1 ,existence=True) and # d2-e4 @@ -1722,7 +1722,7 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct else: assert x == q+t+1, "equivalent to e4=0" # Only one class. The OA(k,t+1) needs not be resolvable. - OA.extend([B[xx] if xx<t else N-x for xx in R] + OA.extend([B[xx] if xx < t else N-x for xx in R] for R in incomplete_orthogonal_array(k,t+1,[1]) for B in partition_of_blocks_of_size_t[0]) @@ -1757,7 +1757,7 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct blocks_of_size_q_plus_t = _reorder_matrix(blocks_of_size_q_plus_t) for i,classs in enumerate(OA_tq1_classes): - OA.extend([R[xx] if xx<t+q else N-i-1 for xx in B] + OA.extend([R[xx] if xx < t+q else N-i-1 for xx in B] for R in blocks_of_size_q_plus_t for B in classs) diff --git a/src/sage/combinat/designs/orthogonal_arrays_find_recursive.pyx b/src/sage/combinat/designs/orthogonal_arrays_find_recursive.pyx index d1d4eb10828..1843cbe00e8 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +++ b/src/sage/combinat/designs/orthogonal_arrays_find_recursive.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings # cython: cdivision=True r""" Orthogonal arrays (find recursive constructions) @@ -47,8 +48,8 @@ Functions from sage.misc.cachefunc import cached_function from .orthogonal_arrays import orthogonal_array -from sage.rings.integer cimport Integer, smallInteger -from sage.arith.all import prime_powers +from sage.rings.integer cimport smallInteger +from sage.arith.misc import prime_powers @cached_function def find_recursive_construction(k, n): @@ -541,7 +542,7 @@ cpdef find_thwart_lemma_3_5(int k,int N): 12 3994 (12, 19, 207, 16, 13, 13, 19, True) sage: for k,n in kn: # not tested -- too long - ....: assert designs.orthogonal_array(k,n,existence=True) is True # not tested -- too long + ....: assert designs.orthogonal_array(k,n,existence=True) is True """ from .orthogonal_arrays_build_recursive import thwart_lemma_3_5 cdef int n,m,a,b,c,d,NN,na,nb,nc diff --git a/src/sage/combinat/designs/resolvable_bibd.py b/src/sage/combinat/designs/resolvable_bibd.py index 7085e2d9ab1..4af0bed4bb6 100644 --- a/src/sage/combinat/designs/resolvable_bibd.py +++ b/src/sage/combinat/designs/resolvable_bibd.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Resolvable Balanced Incomplete Block Design (RBIBD) @@ -48,7 +49,7 @@ --------- """ from itertools import repeat -from sage.arith.all import is_prime_power +from sage.arith.misc import is_prime_power from sage.combinat.designs.bibd import BalancedIncompleteBlockDesign from sage.categories.sets_cat import EmptySetError from .bibd import balanced_incomplete_block_design @@ -95,44 +96,44 @@ def resolvable_balanced_incomplete_block_design(v,k,existence=False): ....: _ = designs.resolvable_balanced_incomplete_block_design(v,k) """ # Trivial cases - if v==1 or k==v: + if v == 1 or k == v: return balanced_incomplete_block_design(v,k,existence=existence) # Non-existence of resolvable BIBD if (v < k or k < 2 or - v%k != 0 or + v % k != 0 or (v-1) % (k-1) != 0 or (v*(v-1)) % (k*(k-1)) != 0 or # From the Handbook of combinatorial designs: # # With lambda>1 the other exceptions is # (15,5,2) - (k==6 and v == 36) or + (k == 6 and v == 36) or # Fisher's inequality (v*(v-1))/(k*(k-1)) < v): if existence: return False raise EmptySetError("There exists no ({},{},{})-RBIBD".format(v,k,1)) - if k==2: + if k == 2: if existence: return True - classes = [[[(c+i)%(v-1),(c+v-i)%(v-1)] for i in range(1, v//2)] + classes = [[[(c+i) % (v-1),(c+v-i) % (v-1)] for i in range(1, v//2)] for c in range(v-1)] for i,classs in enumerate(classes): classs.append([v-1,i]) B = BalancedIncompleteBlockDesign(v, sum(classes,[]), - k = k, + k=k, check=True, copy=False) B._classes = classes return B - elif k==3: + elif k == 3: return kirkman_triple_system(v,existence=existence) - elif k==4: + elif k == 4: return v_4_1_rbibd(v,existence=existence) else: if existence: @@ -182,7 +183,7 @@ def kirkman_triple_system(v,existence=False): sage: for i in range(3,300,6): ....: _ = designs.kirkman_triple_system(i) """ - if v%6 != 3: + if v % 6 != 3: if existence: return False raise ValueError("There is no KTS({}) as v!=3 mod(6)".format(v)) @@ -205,7 +206,7 @@ def kirkman_triple_system(v,existence=False): # Construction 1.1 from [Stinson91] (originally Theorem 6 from [RCW71]) # # For all prime powers q=1 mod 6, there exists a KTS(2q+1) - elif ((v-1)//2)%6 == 1 and is_prime_power((v-1)//2): + elif ((v-1)//2) % 6 == 1 and is_prime_power((v-1)//2): from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF q = (v-1)//2 K = GF(q,'x') @@ -250,16 +251,16 @@ def kirkman_triple_system(v,existence=False): # Construction 1.2 from [Stinson91] (originally Theorem 5 from [RCW71]) # # For all prime powers q=1 mod 6, there exists a KTS(3q) - elif (v//3)%6 == 1 and is_prime_power(v//3): + elif (v//3) % 6 == 1 and is_prime_power(v//3): from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF q = v//3 K = GF(q,'x') a = K.primitive_element() t = (q - 1) // 6 A0 = [(0,0),(0,1),(0,2)] - B = [[(a**i,j),(a**(i+2*t),j),(a**(i+4*t),j)] for j in range(3) + B = [[(a**i,j),(a**(i+2*t),j),(a**(i+4*t),j)] for j in range(3) for i in range(t)] - A = [[(a**i,0),(a**(i+2*t),1),(a**(i+4*t),2)] for i in range(6*t)] + A = [[(a**i,0),(a**(i+2*t),1),(a**(i+4*t),2)] for i in range(6*t)] # Action of K on the points action = lambda v,x: (v+x[0],x[1]) @@ -269,7 +270,7 @@ def kirkman_triple_system(v,existence=False): for i,p in enumerate(K) for j in range(3)} - B0 = [A0] + B + A[t:2*t] + A[3*t:4*t] + A[5*t:6*t] + B0 = [A0] + B + A[t:2*t] + A[3*t:4*t] + A[5*t:6*t] # Classes classes = [[[relabel[action(p,x)] for x in tr] for tr in B0] @@ -348,14 +349,14 @@ def kirkman_triple_system(v,existence=False): gdd = {4: gdd4, 7: gdd7} for B in PBD_4_7((v-1)//2,check=False): for i,classs in enumerate(gdd[len(B)]): - classes[B[i]].extend([[2*B[x//2]+x%2 for x in BB] for BB in classs]) + classes[B[i]].extend([[2*B[x//2]+x % 2 for x in BB] for BB in classs]) # The {x,x',\infty} blocks for i,classs in enumerate(classes): classs.append([2*i,2*i+1,v-1]) KTS = BalancedIncompleteBlockDesign(v, - blocks = [tr for cl in classes for tr in cl], + blocks=[tr for cl in classes for tr in cl], k=3, lambd=1, check=True, @@ -399,12 +400,12 @@ def v_4_1_rbibd(v,existence=False): TESTS:: - sage: for q in prime_powers(2,30): + sage: for q in prime_powers(2,30): # indirect doctest ....: if (3*q+1)%12 == 4: - ....: _ = designs.resolvable_balanced_incomplete_block_design(3*q+1,4) # indirect doctest + ....: _ = designs.resolvable_balanced_incomplete_block_design(3*q+1,4) """ # Volume 1, VII.7.5.a from [BJL99]_ - if v%3 != 1 or not is_prime_power((v-1)//3): + if v % 3 != 1 or not is_prime_power((v-1)//3): if existence: return Unknown raise NotImplementedError("I don't know how to build a ({},{},1)-RBIBD!".format(v,4)) @@ -423,12 +424,12 @@ def v_4_1_rbibd(v,existence=False): label = {p:i for i,p in enumerate(G)} - classes = [[[v-1 if x=='inf' else (x[1]%3)*q+label[x[0]+g] for x in S] + classes = [[[v-1 if x == 'inf' else (x[1] % 3)*q+label[x[0]+g] for x in S] for S in first_class] for g in G] BIBD = BalancedIncompleteBlockDesign(v, - blocks = sum(classes,[]), + blocks=sum(classes,[]), k=4, check=True, copy=False) @@ -462,7 +463,7 @@ def PBD_4_7(v,check=True, existence=False): ....: assert PBD_4_7(i,existence=True) is True ....: _ = PBD_4_7(i,check=True) """ - if v%3 != 1 or v in [10,19,31]: + if v % 3 != 1 or v in [10,19,31]: if existence: return Unknown raise NotImplementedError @@ -492,7 +493,7 @@ def PBD_4_7(v,check=True, existence=False): C = [[(x+i+j,y+2*i+j) for x,y in C]+[30+j] for i in range(9) for j in range(3)] D = [[(x+i, y+i) for x,y in D]+[33] for i in range(9)] - blocks = [[int(x) if not isinstance(x,tuple) else (x[1]%3)*9+(x[0]%9) for x in S] + blocks = [[int(x) if not isinstance(x,tuple) else (x[1] % 3)*9+(x[0] % 9) for x in S] for S in A+B+C+D+[list(range(27,34))]] elif v == 46: # [BJL99] (p527,vol1), but originally Brouwer @@ -508,7 +509,7 @@ def PBD_4_7(v,check=True, existence=False): D = [[(x+i, y+j) for x,y in D]+[42+j] for i in range(13) for j in range(3)] E = [[(x+i, y+i) for x,y in E]+[45] for i in range(13)] - blocks = [[int(x) if not isinstance(x,tuple) else (x[1]%3)*13+(x[0]%13) for x in S] + blocks = [[int(x) if not isinstance(x,tuple) else (x[1] % 3)*13+(x[0] % 13) for x in S] for S in A+B+C+D+E+[list(range(39, 46))]] elif v == 58: @@ -527,7 +528,7 @@ def PBD_4_7(v,check=True, existence=False): E = [[(x+i, y+j) for x,y in E]+[54+j] for i in range(17) for j in range(3)] F = [[(x+i, y+i) for x,y in F]+[57] for i in range(17)] - blocks = [[int(x) if not isinstance(x,tuple) else (x[1]%3)*17+(x[0]%17) for x in S] + blocks = [[int(x) if not isinstance(x,tuple) else (x[1] % 3)*17+(x[0] % 17) for x in S] for S in A+B+C+D+E+F+[list(range(51,58))]] elif v == 70: @@ -548,7 +549,7 @@ def PBD_4_7(v,check=True, existence=False): F = [[(x+3*i+j, y+ii+j) for x,y in F]+[66+j] for i in range( 7) for j in range(3) for ii in range(3)] H = [[(x+i, y+i) for x,y in H]+[69] for i in range(21)] - blocks = [[int(x) if not isinstance(x,tuple) else (x[1]%3)*21+(x[0]%21) + blocks = [[int(x) if not isinstance(x,tuple) else (x[1] % 3)*21+(x[0] % 21) for x in S] for S in A+B+C+D+E+F+H+[list(range(63,70))]] @@ -559,10 +560,10 @@ def PBD_4_7(v,check=True, existence=False): from .group_divisible_designs import group_divisible_design from .orthogonal_arrays import transversal_design GDD = group_divisible_design(3*5,K=[4],G=[3],check=False) - TD = transversal_design(5,5) + TD = transversal_design(5,5) # A (75,{4},{15})-GDD - GDD2 = [[3*B[x//3]+x%3 for x in BB] for B in TD for BB in GDD] + GDD2 = [[3*B[x//3]+x % 3 for x in BB] for B in TD for BB in GDD] # We now complete the (75,{4},{15})-GDD into a (82,{4,7})-PBD. For this, # we add 7 new points that are added to all groups of size 15. @@ -577,7 +578,7 @@ def PBD_4_7(v,check=True, existence=False): if B == S: continue for i in range(5): - GDD2.append([x+i*15 if x<15 else x+60 for x in B]) + GDD2.append([x+i*15 if x < 15 else x+60 for x in B]) GDD2.append(list(range(75,82))) blocks = GDD2 @@ -592,19 +593,19 @@ def PBD_4_7(v,check=True, existence=False): parall = [] plus_one = None for S in AF: - if all(all(x not in SS for x in S) for SS in parall): + if all(x not in SS for SS in parall for x in S): parall.append(S) elif plus_one is None: plus_one = S if len(parall) == 4 and plus_one is not None: break - X = set(sum(parall,plus_one)) + X = set(sum(parall, plus_one)) S_4_5_7 = [X.intersection(S) for S in AF] - S_4_5_7 = [S for S in S_4_5_7 if len(S)>1] + S_4_5_7 = [S for S in S_4_5_7 if len(S) > 1] S_4_5_7 = PairwiseBalancedDesign(X, - blocks = S_4_5_7, - K = [4,5,7], + blocks=S_4_5_7, + K=[4,5,7], check=False) S_4_5_7.relabel() return PBD_4_7_from_Y(S_4_5_7,check=check) @@ -616,7 +617,7 @@ def PBD_4_7(v,check=True, existence=False): # (42,{4,5},{1,2,7})-GDD or a (47,{4,5},{1,2,7})-GDD points_to_add = 2 if v == 127 else 7 rBIBD4 = v_4_1_rbibd(40) - GDD = [S+[40+i] if i<points_to_add else S + GDD = [S+[40+i] if i < points_to_add else S for i,classs in enumerate(rBIBD4._classes) for S in classs] if points_to_add == 7: @@ -626,11 +627,11 @@ def PBD_4_7(v,check=True, existence=False): groups = [[x] for x in range(40)] groups.append(list(range(40,40+points_to_add))) GDD = GroupDivisibleDesign(40+points_to_add, - groups = groups, - blocks = GDD, - K = [2,4,5,7], - check = False, - copy = False) + groups=groups, + blocks=GDD, + K=[2,4,5,7], + check=False, + copy=False) return PBD_4_7_from_Y(GDD,check=check) @@ -669,18 +670,18 @@ def PBD_4_7(v,check=True, existence=False): domain = set(range(vv)) GDD = transversal_design(5,g) GDD = GroupDivisibleDesign(vv, - groups = [[x for x in gr if x in domain] for gr in GDD.groups()], - blocks = [[x for x in B if x in domain] for B in GDD], - G = set([g,u]), - K = [4,5], + groups=[[x for x in gr if x in domain] for gr in GDD.groups()], + blocks=[[x for x in B if x in domain] for B in GDD], + G=set([g,u]), + K=[4,5], check=False) return PBD_4_7_from_Y(GDD,check=check) return PairwiseBalancedDesign(v, - blocks = blocks, - K = [4,7], - check = check, - copy = False) + blocks=blocks, + K=[4,7], + check=check, + copy=False) def PBD_4_7_from_Y(gdd,check=True): r""" @@ -760,18 +761,18 @@ def PBD_4_7_from_Y(gdd,check=True): # The blocks for B in gdd: for B_GDD in GDD[len(B)]: - PBD.append([3*B[x//3]+(x%3) for x in B_GDD]) + PBD.append([3*B[x//3]+(x % 3) for x in B_GDD]) # The groups group_PBD = {gs:PBD_4_7(3*gs+1) for gs in group_sizes} for G in gdd.groups(): gs = len(G) for B in group_PBD[gs]: - PBD.append([3*G[x//3]+(x%3) if x < 3*gs else 3*gdd.num_points() + PBD.append([3*G[x//3]+(x % 3) if x < 3*gs else 3*gdd.num_points() for x in B]) return PairwiseBalancedDesign(3*gdd.num_points()+1, - blocks = PBD, - K = [4,7], - check = check, - copy = False) + blocks=PBD, + K=[4,7], + check=check, + copy=False) diff --git a/src/sage/combinat/designs/steiner_quadruple_systems.py b/src/sage/combinat/designs/steiner_quadruple_systems.py index 2a8713fe323..8312f2f92c8 100644 --- a/src/sage/combinat/designs/steiner_quadruple_systems.py +++ b/src/sage/combinat/designs/steiner_quadruple_systems.py @@ -90,7 +90,7 @@ def two_n(B): for a in range(2): for b in range(2): for c in range(2): - d = (a+b+c)%2 + d = (a+b+c) % 2 Y.append([x+a*n,y+b*n,z+c*n,t+d*n]) # Line 2 @@ -122,13 +122,13 @@ def three_n_minus_two(B): A = n-1 Y = [] # relabel function - r = lambda i,x : (i%3)*(n-1)+x + r = lambda i,x : (i % 3)*(n-1)+x for x,y,z,t in B._blocks: if t == A: # Line 2. for a in range(3): for b in range(3): - c = -(a+b)%3 + c = -(a+b) % 3 Y.append([r(a,x),r(b,y),r(c,z),3*n-3]) # Line 3. @@ -141,7 +141,7 @@ def three_n_minus_two(B): for a in range(3): for b in range(3): for c in range(3): - d = -(a+b+c)%3 + d = -(a+b+c) % 3 Y.append([r(a,x),r(b,y),r(c,z),r(d,t)]) # Line 4. @@ -176,11 +176,11 @@ def three_n_minus_eight(B): """ n = B.num_points() - if (n%12) != 2: + if (n % 12) != 2: raise ValueError("n must be equal to 2 mod 12") B = relabel_system(B) - r = lambda i,x : (i%3)*(n-4)+(x%(n-4)) + r = lambda i,x : (i % 3)*(n-4)+(x % (n-4)) # Line 1. Y = [[x+2*(n-4) for x in B._blocks[-1]]] @@ -188,23 +188,21 @@ def three_n_minus_eight(B): # Line 2. for s in B._blocks[:-1]: for i in range(3): - Y.append([r(i,x) if x<= n-5 else x+2*(n-4) for x in s]) - + Y.append([r(i,x) if x <= n-5 else x+2*(n-4) for x in s]) # Line 3. for a in range(4): for aa in range(n-4): for aaa in range(n-4): - aaaa = -(a+aa+aaa)%(n-4) + aaaa = -(a+aa+aaa) % (n-4) Y.append([r(0,aa),r(1,aaa), r(2,aaaa),3*(n-4)+a]) - # Line 4. k = (n-14) // 12 for i in range(3): for b in range(n-4): for bb in range(n-4): - bbb = -(b+bb)%(n-4) + bbb = -(b+bb) % (n-4) for d in range(2*k+1): Y.append([r(i+2,bbb), r(i, b+2*k+1+i*(4*k+2)-d) , r(i, b+2*k+2+i*(4*k+2)+d), r(i+1,bb)]) @@ -239,17 +237,17 @@ def three_n_minus_four(B): """ n = B.num_points() - if n%12 != 10: + if n % 12 != 10: raise ValueError("n must be equal to 10 mod 12") B = relabel_system(B) - r = lambda i,x : (i%3)*(n-2)+(x%(n-2)) + r = lambda i,x : (i % 3)*(n-2)+(x % (n-2)) # Line 1/2. Y = [] for s in B._blocks: for i in range(3): - Y.append([r(i,x) if x<= n-3 else x+2*(n-2) for x in s]) + Y.append([r(i,x) if x <= n-3 else x+2*(n-2) for x in s]) # Line 3. for a in range(2): @@ -263,7 +261,7 @@ def three_n_minus_four(B): for i in range(3): for b in range(n-2): for bb in range(n-2): - bbb = -(b+bb)%(n-2) + bbb = -(b+bb) % (n-2) for d in range(2*k+1): Y.append([r(i+2,bbb), r(i, b+2*k+1+i*(4*k+2)-d) , r(i, b+2*k+2+i*(4*k+2)+d), r(i+1,bb)]) @@ -303,14 +301,14 @@ def four_n_minus_six(B): """ n = B.num_points() f = n-2 - r = lambda i,ii,x : (2*(i%2)+(ii%2))*(n-2)+(x)%(n-2) + r = lambda i,ii,x : (2*(i % 2)+(ii % 2))*(n-2)+(x) % (n-2) # Line 1. Y = [] for s in B._blocks: for i in range(2): for ii in range(2): - Y.append([r(i,ii,x) if x<= n-3 else x+3*(n-2) for x in s]) + Y.append([r(i,ii,x) if x <= n-3 else x+3*(n-2) for x in s]) # Line 2/3/4/5 k = f // 2 @@ -318,7 +316,7 @@ def four_n_minus_six(B): for eps in range(2): for c in range(k): for cc in range(k): - ccc = -(c+cc)%k + ccc = -(c+cc) % k Y.append([4*(n-2)+l, r(0,0,2*c) , r(0,1,2*cc-eps) , r(1,eps,2*ccc+l) ]) Y.append([4*(n-2)+l, r(0,0,2*c+1), r(0,1,2*cc-1-eps), r(1,eps,2*ccc+1-l)]) Y.append([4*(n-2)+l, r(1,0,2*c) , r(1,1,2*cc-eps) , r(0,eps,2*ccc+1-l)]) @@ -331,23 +329,20 @@ def four_n_minus_six(B): assert len(barP(ccc,k)) == k-1 for rc,sc in barP(ccc,k): for c in range(k): - cc = -(c+ccc)%k + cc = -(c+ccc) % k Y.append([r(h,0,2*c+eps) , r(h,1,2*cc-eps), r(h+1,0,rc), r(h+1,0,sc)]) Y.append([r(h,0,2*c-1+eps), r(h,1,2*cc-eps), r(h+1,1,rc), r(h+1,1,sc)]) - - # Line 8/9 for h in range(2): for eps in range(2): for ccc in range(k): for rc,sc in barP(k+ccc,k): for c in range(k): - cc = -(c+ccc)%k + cc = -(c+ccc) % k Y.append([r(h,0,2*c+eps) , r(h,1,2*cc-eps), r(h+1,1,rc), r(h+1,1,sc)]) Y.append([r(h,0,2*c-1+eps), r(h,1,2*cc-eps), r(h+1,0,rc), r(h+1,0,sc)]) - # Line 10 for h in range(2): for alpha in range(n-3): @@ -378,22 +373,22 @@ def twelve_n_minus_ten(B): """ n = B.num_points() B14 = steiner_quadruple_system(14) - r = lambda i,x : i%(n-1)+(x%12)*(n-1) + r = lambda i,x : i % (n-1)+(x % 12)*(n-1) # Line 1. Y = [] for s in B14._blocks: for i in range(n-1): - Y.append([r(i,x) if x<= 11 else r(n-2,11)+x-11 for x in s]) + Y.append([r(i,x) if x <= 11 else r(n-2,11)+x-11 for x in s]) for s in B._blocks: if s[-1] == n-1: u,v,w,B = s dd = {0:u,1:v,2:w} - d = lambda x:dd[x%3] + d = lambda x:dd[x % 3] for b in range(12): for bb in range(12): - bbb = -(b+bb)%12 + bbb = -(b+bb) % 12 for h in range(2): # Line 2 Y.append([r(n-2,11)+1+h,r(u,b),r(v,bb),r(w,bbb+3*h)]) @@ -451,7 +446,7 @@ def twelve_n_minus_ten(B): for a in range(12): for aa in range(12): for aaa in range(12): - aaaa = -(a+aa+aaa)%12 + aaaa = -(a+aa+aaa) % 12 # Line 3 Y.append([r(x,a), r(y,aa), r(z,aaa), r(t,aaaa)]) return IncidenceStructure(12*n-10,Y,check=False,copy=False) @@ -506,31 +501,31 @@ def P(alpha, m): """ if alpha >= 2*m-1: raise Exception - if m%2==0: + if m % 2 == 0: if alpha < m: - if alpha%2 == 0: + if alpha % 2 == 0: b = alpha // 2 - return [(2*a, (2*a + 2*b + 1)%(2*m)) for a in range(m)] + return [(2*a, (2*a + 2*b + 1) % (2*m)) for a in range(m)] else: b = (alpha-1) // 2 - return [(2*a, (2*a - 2*b - 1)%(2*m)) for a in range(m)] + return [(2*a, (2*a - 2*b - 1) % (2*m)) for a in range(m)] else: y = alpha - m - pairs = [(b,(2*y-b)%(2*m)) for b in range(y)] - pairs += [(c,(2*m+2*y-c-2)%(2*m)) for c in range(2*y+1,m+y-1)] + pairs = [(b,(2*y-b) % (2*m)) for b in range(y)] + pairs += [(c,(2*m+2*y-c-2) % (2*m)) for c in range(2*y+1,m+y-1)] pairs += [(2*m+int(-1.5-.5*(-1)**y),y),(2*m+int(-1.5+.5*(-1)**y),m+y-1)] return pairs else: if alpha < m-1: if alpha % 2 == 0: b = alpha // 2 - return [(2*a,(2*a+2*b+1)%(2*m)) for a in range(m)] + return [(2*a,(2*a+2*b+1) % (2*m)) for a in range(m)] else: b = (alpha-1) // 2 - return [(2*a,(2*a-2*b-1)%(2*m)) for a in range(m)] + return [(2*a,(2*a-2*b-1) % (2*m)) for a in range(m)] else: y = alpha-m+1 - pairs = [(b,2*y-b) for b in range(y)] + pairs = [(b,2*y-b) for b in range(y)] pairs += [(c,2*m+2*y-c) for c in range(2*y+1,m+y)] pairs += [(y,m+y)] return pairs @@ -596,8 +591,8 @@ def barP_system(m): # pairs. Those are added to 'last', a new list of pairs last = [] for n in range(1, (m-2)//2+1): - pairs.append([p for p in P(2*n,m) if not isequal(p,(2*n,(4*n+1)%(2*m)))]) - last.append((2*n,(4*n+1)%(2*m))) + pairs.append([p for p in P(2*n,m) if not isequal(p,(2*n,(4*n+1) % (2*m)))]) + last.append((2*n,(4*n+1) % (2*m))) pairs.append([p for p in P(2*n-1,m) if not isequal(p,(2*m-2-2*n,2*m-1-4*n))]) last.append((2*m-2-2*n,2*m-1-4*n)) @@ -623,12 +618,12 @@ def barP_system(m): # Now the points must be relabeled relabel = {} for n in range(1, (m-2)//2+1): - relabel[2*n] = (4*n)%(2*m) - relabel[4*n+1] = (4*n+1)%(2*m) - relabel[2*m-2-2*n] = (4*n-2)%(2*m) - relabel[2*m-1-4*n] = (4*n-1)%(2*m) + relabel[2*n] = (4*n) % (2*m) + relabel[4*n+1] = (4*n+1) % (2*m) + relabel[2*m-2-2*n] = (4*n-2) % (2*m) + relabel[2*m-1-4*n] = (4*n-1) % (2*m) - relabel[2*m-2] = (1)%(2*m) + relabel[2*m-2] = (1) % (2*m) relabel[0] = 0 relabel[2*m-1] = 2*m-1 relabel[1] = 2*m-2 @@ -639,8 +634,8 @@ def barP_system(m): last = [] for n in range((m - 3) // 2 + 1): - pairs.append([p for p in P(2*n,m) if not isequal(p,(2*n,(4*n+1)%(2*m)))]) - last.append((2*n,(4*n+1)%(2*m))) + pairs.append([p for p in P(2*n,m) if not isequal(p,(2*n,(4*n+1) % (2*m)))]) + last.append((2*n,(4*n+1) % (2*m))) pairs.append([p for p in P(2*n+1,m) if not isequal(p,(2*m-2-2*n,2*m-3-4*n))]) last.append((2*m-2-2*n,2*m-3-4*n)) @@ -661,11 +656,11 @@ def barP_system(m): # Now the points must be relabeled relabel = {} for n in range((m - 3) // 2 + 1): - relabel[2*n] = (4*n)%(2*m) - relabel[4*n+1] = (4*n+1)%(2*m) - relabel[2*m-2-2*n] = (4*n+2)%(2*m) - relabel[2*m-3-4*n] = (4*n+3)%(2*m) - relabel[m-1] = (2*m-2)%(2*m) + relabel[2*n] = (4*n) % (2*m) + relabel[4*n+1] = (4*n+1) % (2*m) + relabel[2*m-2-2*n] = (4*n+2) % (2*m) + relabel[2*m-3-4*n] = (4*n+3) % (2*m) + relabel[m-1] = (2*m-2) % (2*m) relabel[2*m-1] = 2*m-1 assert len(relabel) == 2*m @@ -682,7 +677,7 @@ def barP_system(m): return pairs @cached_function -def steiner_quadruple_system(n, check = False): +def steiner_quadruple_system(n, check=False): r""" Return a Steiner Quadruple System on `n` points. @@ -710,36 +705,36 @@ def steiner_quadruple_system(n, check = False): TESTS:: sage: for n in range(4, 100): # long time - ....: if (n%6) in [2,4]: # long time - ....: sqs = designs.steiner_quadruple_system(n, check=True) # long time + ....: if (n%6) in [2,4]: + ....: sqs = designs.steiner_quadruple_system(n, check=True) """ n = int(n) - if not ((n%6) in [2, 4]): + if not ((n % 6) in [2, 4]): raise ValueError("n mod 6 must be equal to 2 or 4") elif n == 4: - sqs = IncidenceStructure(4, [[0,1,2,3]], copy = False, check = False) + sqs = IncidenceStructure(4, [[0,1,2,3]], copy=False, check=False) elif n == 14: - sqs = IncidenceStructure(14, _SQS14(), copy = False, check = False) + sqs = IncidenceStructure(14, _SQS14(), copy=False, check=False) elif n == 38: - sqs = IncidenceStructure(38, _SQS38(), copy = False, check = False) - elif n%12 in [4, 8]: - nn = n // 2 - sqs = two_n(steiner_quadruple_system(nn, check = False)) - elif n%18 in [4,10]: + sqs = IncidenceStructure(38, _SQS38(), copy=False, check=False) + elif n % 12 in [4, 8]: + nn = n // 2 + sqs = two_n(steiner_quadruple_system(nn, check=False)) + elif n % 18 in [4,10]: nn = (n+2) // 3 - sqs = three_n_minus_two(steiner_quadruple_system(nn, check = False)) - elif (n%36) == 34: + sqs = three_n_minus_two(steiner_quadruple_system(nn, check=False)) + elif (n % 36) == 34: nn = (n+8) // 3 - sqs = three_n_minus_eight(steiner_quadruple_system(nn, check = False)) - elif (n%36) == 26: + sqs = three_n_minus_eight(steiner_quadruple_system(nn, check=False)) + elif (n % 36) == 26: nn = (n+4) // 3 - sqs = three_n_minus_four(steiner_quadruple_system(nn, check = False)) - elif n%24 in [2, 10]: + sqs = three_n_minus_four(steiner_quadruple_system(nn, check=False)) + elif n % 24 in [2, 10]: nn = (n+6) // 4 - sqs = four_n_minus_six(steiner_quadruple_system(nn, check = False)) - elif n%72 in [14, 38]: + sqs = four_n_minus_six(steiner_quadruple_system(nn, check=False)) + elif n % 72 in [14, 38]: nn = (n+10) // 12 - sqs = twelve_n_minus_ten(steiner_quadruple_system(nn, check = False)) + sqs = twelve_n_minus_ten(steiner_quadruple_system(nn, check=False)) else: raise ValueError("this should never happen") diff --git a/src/sage/combinat/designs/subhypergraph_search.pyx b/src/sage/combinat/designs/subhypergraph_search.pyx index 0b48819e15a..ace387a4bf2 100644 --- a/src/sage/combinat/designs/subhypergraph_search.pyx +++ b/src/sage/combinat/designs/subhypergraph_search.pyx @@ -119,7 +119,7 @@ Methods from libc.stdlib cimport qsort from libc.stdint cimport uint64_t -from cysignals.memory cimport sig_malloc, sig_calloc, sig_realloc, sig_free +from cysignals.memory cimport sig_malloc, sig_calloc, sig_free ctypedef struct hypergraph: int n @@ -444,8 +444,8 @@ cdef class SubHypergraphSearch: EXAMPLES:: - sage: d = designs.projective_plane(3) - sage: d.isomorphic_substructures_iterator(d).relabel_heuristic() + sage: d = designs.projective_plane(3) # needs sage.schemes + sage: d.isomorphic_substructures_iterator(d).relabel_heuristic() # needs sage.schemes """ cdef hypergraph h2 = self.h2 cdef int x,y,i @@ -490,7 +490,6 @@ cdef class SubHypergraphSearch: cdef hypergraph h1 = self.h1 cdef hypergraph h2 = self.h2 cdef hypergraph tmp1 = self.tmp1 - cdef hypergraph tmp2 = self.tmp2 cdef int * step = self.step if h1.n<h2.n or h1.m<h2.m: diff --git a/src/sage/combinat/designs/twographs.py b/src/sage/combinat/designs/twographs.py index 56c01c4bc5e..5c9a90afbcd 100644 --- a/src/sage/combinat/designs/twographs.py +++ b/src/sage/combinat/designs/twographs.py @@ -84,8 +84,8 @@ def __init__(self, points=None, blocks=None, incidence_matrix=None, Traceback (most recent call last): ... AssertionError: the structure is not a 2-graph! - sage: p=graphs.PetersenGraph().twograph() - sage: TwoGraph(p, check=True) + sage: p = graphs.PetersenGraph().twograph() # needs sage.modules + sage: TwoGraph(p, check=True) # needs sage.modules Incidence structure with 10 points and 60 blocks """ IncidenceStructure.__init__(self, points=points, blocks=blocks, @@ -108,12 +108,13 @@ def is_regular_twograph(self, alpha=False): EXAMPLES:: - sage: p=graphs.PetersenGraph().twograph() + sage: # needs sage.modules + sage: p = graphs.PetersenGraph().twograph() sage: p.is_regular_twograph(alpha=True) 4 sage: p.is_regular_twograph() True - sage: p=graphs.PathGraph(5).twograph() + sage: p = graphs.PathGraph(5).twograph() sage: p.is_regular_twograph(alpha=True) False sage: p.is_regular_twograph() @@ -139,8 +140,8 @@ def descendant(self, v): EXAMPLES:: - sage: p = graphs.PetersenGraph().twograph().descendant(0) - sage: p.is_strongly_regular(parameters=True) + sage: p = graphs.PetersenGraph().twograph().descendant(0) # needs sage.modules + sage: p.is_strongly_regular(parameters=True) # needs sage.modules (9, 4, 1, 2) """ from sage.graphs.graph import Graph @@ -159,14 +160,14 @@ def complement(self): EXAMPLES:: - sage: p = graphs.CompleteGraph(8).line_graph().twograph() - sage: pc = p.complement(); pc + sage: p = graphs.CompleteGraph(8).line_graph().twograph() # needs sage.modules + sage: pc = p.complement(); pc # needs sage.modules Incidence structure with 28 points and 1260 blocks TESTS:: sage: from sage.combinat.designs.twographs import is_twograph - sage: is_twograph(pc) + sage: is_twograph(pc) # needs sage.modules True """ return super().complement(uniform=True) @@ -192,7 +193,7 @@ def taylor_twograph(q): EXAMPLES:: sage: from sage.combinat.designs.twographs import taylor_twograph - sage: T=taylor_twograph(3); T + sage: T = taylor_twograph(3); T # needs sage.rings.finite_rings Incidence structure with 28 points and 1260 blocks """ from sage.graphs.generators.classical_geometries import TaylorTwographSRG @@ -211,8 +212,8 @@ def is_twograph(T): a two-graph from a graph:: sage: from sage.combinat.designs.twographs import (is_twograph, TwoGraph) - sage: p=graphs.PetersenGraph().twograph() - sage: is_twograph(p) + sage: p = graphs.PetersenGraph().twograph() # needs sage.modules + sage: is_twograph(p) # needs sage.modules True a non-regular 2-uniform hypergraph which is a two-graph:: @@ -224,12 +225,12 @@ def is_twograph(T): wrong size of blocks:: - sage: is_twograph(designs.projective_plane(3)) + sage: is_twograph(designs.projective_plane(3)) # needs sage.schemes False a triple system which is not a two-graph:: - sage: is_twograph(designs.projective_plane(2)) + sage: is_twograph(designs.projective_plane(2)) # needs sage.schemes False """ if not T.is_uniform(3): @@ -277,22 +278,22 @@ def twograph_descendant(G, v, name=None): one of s.r.g.'s from the :mod:`database <sage.graphs.strongly_regular_db>`:: sage: from sage.combinat.designs.twographs import twograph_descendant - sage: A=graphs.strongly_regular_graph(280,135,70) # optional - gap_packages internet - sage: twograph_descendant(A, 0).is_strongly_regular(parameters=True) # optional - gap_packages internet + sage: A = graphs.strongly_regular_graph(280,135,70) # optional - gap_package_design internet + sage: twograph_descendant(A, 0).is_strongly_regular(parameters=True) # optional - gap_package_design internet (279, 150, 85, 75) TESTS:: sage: T8 = graphs.CompleteGraph(8).line_graph() sage: v = T8.vertices(sort=True)[0] - sage: twograph_descendant(T8, v)==T8.twograph().descendant(v) + sage: twograph_descendant(T8, v) == T8.twograph().descendant(v) # needs sage.modules True sage: twograph_descendant(T8, v).is_strongly_regular(parameters=True) (27, 16, 10, 8) sage: p = graphs.PetersenGraph() - sage: twograph_descendant(p,5) + sage: twograph_descendant(p, 5) Graph on 9 vertices - sage: twograph_descendant(p,5,name=True) + sage: twograph_descendant(p, 5, name=True) descendant of Petersen graph at 5: Graph on 9 vertices """ G = G.seidel_switching(G.neighbors(v),inplace=False) diff --git a/src/sage/combinat/diagram.py b/src/sage/combinat/diagram.py index d2213120724..00b94920726 100644 --- a/src/sage/combinat/diagram.py +++ b/src/sage/combinat/diagram.py @@ -23,6 +23,7 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from itertools import product from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.composition import Composition @@ -42,10 +43,10 @@ class Diagram(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" - Combinatorial diagrams with positions indexed by rows in columns. + Combinatorial diagrams with positions indexed by rows and columns. The positions are indexed by rows and columns as in a matrix. For example, - a Ferrer's diagram is a diagram obtained from a partition + a Ferrers diagram is a diagram obtained from a partition `\lambda = (\lambda_0, \lambda_1, \ldots, \lambda_{\ell})`, where the cells are in rows `i` for `0 \leq i \leq \ell` and the cells in row `i` consist of `(i,j)` for `0 \leq j < \lambda_i`. In English notation, the @@ -57,7 +58,7 @@ class Diagram(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): EXAMPLES: - To create an arbirtrary diagram, pass a list of all cells:: + To create an arbitrary diagram, pass a list of all cells:: sage: from sage.combinat.diagram import Diagram sage: cells = [(0,0), (0,1), (1,0), (1,1), (4,4), (4,5), (4,6), (5,4), (7, 6)] @@ -152,7 +153,7 @@ def __init__(self, parent, cells, n_rows=None, n_cols=None, check=True): # minimum possible number of rows/cols N_rows = max(c[0] for c in self._cells) N_cols = max(c[1] for c in self._cells) - else: # if there are no cells + else: # if there are no cells N_rows = -1 N_cols = -1 @@ -344,18 +345,22 @@ def _latex_(self): def end_line(r): # give the line ending to row ``r`` if r == 0: - return "".join(r'\cline{%s-%s}'%(i+1, i+1) for i,j in enumerate(array[0]) if j is not None) + return "".join(r'\cline{%s-%s}' % (i+1, i+1) + for i, j in enumerate(array[0]) if j is not None) elif r == len(array): - return r"\\" + "".join(r'\cline{%s-%s}'%(i+1, i+1) for i,j in enumerate(array[r-1]) if j is not None) + return r"\\" + "".join(r'\cline{%s-%s}' % (i+1, i+1) + for i, j in enumerate(array[r-1]) if j is not None) else: - out = r"\\" + "".join(r'\cline{%s-%s}'%(i+1, i+1) for i,j in enumerate(array[r-1]) if j is not None) - out += "".join(r'\cline{%s-%s}'%(i+1, i+1) for i,j in enumerate(array[r]) if j is not None) + out = r"\\" + "".join(r'\cline{%s-%s}' % (i+1, i+1) + for i, j in enumerate(array[r-1]) if j is not None) + out += "".join(r'\cline{%s-%s}' % (i+1, i+1) + for i, j in enumerate(array[r]) if j is not None) return out - tex=r'\raisebox{-.6ex}{$\begin{array}[b]{*{%s}{p{0.6ex}}}'%(max(map(len,array))) - tex+=end_line(0)+'\n' + tex = r'\raisebox{-.6ex}{$\begin{array}[b]{*{%s}{p{0.6ex}}}' % (max(map(len, array))) + tex += end_line(0)+'\n' for r in range(len(array)): - tex+='&'.join('' if c is None else r'\lr{%s}'%(c,) for c in array[r]) + tex += '&'.join('' if c is None else r'\lr{%s}' % (c,) for c in array[r]) tex += end_line(r+1)+'\n' return '{%s\n%s\n}' % (lr, tex+r'\end{array}$}') @@ -469,13 +474,13 @@ def check(self): sage: D.check() In the next two examples, a bad diagram is passed. - The first example fails because one cells is indexed by negative + The first example fails because one cell is indexed by negative integers:: sage: D = Diagram([(0,0), (0,-3), (2,2), (2,4)]) Traceback (most recent call last): ... - ValueError: Diagrams must be indexed by non-negative integers + ValueError: diagrams must be indexed by non-negative integers The next example fails because one cell is indexed by rational numbers:: @@ -483,12 +488,53 @@ def check(self): sage: D = Diagram([(0,0), (0,3), (2/3,2), (2,4)]) Traceback (most recent call last): ... - ValueError: Diagrams must be indexed by non-negative integers + ValueError: diagrams must be indexed by non-negative integers """ from sage.sets.non_negative_integers import NonNegativeIntegers NN = NonNegativeIntegers() - if not all(all(list(i in NN for i in c)) for c in self._cells): - raise ValueError("Diagrams must be indexed by non-negative integers") + if not all(i in NN for c in self._cells for i in c): + raise ValueError("diagrams must be indexed by non-negative integers") + + def specht_module(self, base_ring=None): + r""" + Return the Specht module corresponding to ``self``. + + EXAMPLES:: + + sage: from sage.combinat.diagram import Diagram + sage: D = Diagram([(0,0), (1,1), (2,2), (2,3)]) + sage: SM = D.specht_module(QQ) # needs sage.modules + sage: s = SymmetricFunctions(QQ).s() # needs sage.modules + sage: s(SM.frobenius_image()) # needs sage.modules + s[2, 1, 1] + s[2, 2] + 2*s[3, 1] + s[4] + """ + from sage.combinat.specht_module import SpechtModule + from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: + from sage.rings.rational_field import QQ + base_ring = QQ + R = SymmetricGroupAlgebra(base_ring, len(self)) + return SpechtModule(R, self) + + def specht_module_dimension(self, base_ring=None): + r""" + Return the dimension of the Specht module corresponding to ``self``. + + INPUT: + + - ``base_ring`` -- (default: `\QQ`) the base ring + + EXAMPLES:: + + sage: from sage.combinat.diagram import Diagram + sage: D = Diagram([(0,0), (1,1), (2,2), (2,3)]) + sage: D.specht_module_dimension() # needs sage.modules + 12 + sage: D.specht_module(QQ).dimension() # needs sage.modules + 12 + """ + from sage.combinat.specht_module import specht_module_rank + return specht_module_rank(self, base_ring) class Diagrams(UniqueRepresentation, Parent): @@ -575,7 +621,7 @@ def __iter__(self): """ from sage.sets.non_negative_integers import NonNegativeIntegers from sage.categories.cartesian_product import cartesian_product - from sage.misc.misc import subsets + from sage.combinat.subset import subsets # the product of positive integers automatically implements an # an enumeration which allows us to get out of the first column N = NonNegativeIntegers() @@ -584,7 +630,7 @@ def __iter__(self): while True: cells = next(X) try: - yield self.element_class(self, tuple((i, j) for i,j in cells)) + yield self.element_class(self, tuple((i, j) for i, j in cells)) except ValueError: # if cells causes the .check method of a # subclass to fail, just go to the next one @@ -616,9 +662,9 @@ def _element_constructor_(self, cells, n_rows=None, n_cols=None, check=True): . . O - sage: from sage.combinat.tiling import Polyomino - sage: p = Polyomino([(0,0),(1,0),(1,1),(1,2)]) - sage: Dgms(p).pp() + sage: from sage.combinat.tiling import Polyomino # needs sage.modules + sage: p = Polyomino([(0,0),(1,0),(1,1),(1,2)]) # needs sage.modules + sage: Dgms(p).pp() # needs sage.modules O . . O O O @@ -631,8 +677,8 @@ def _element_constructor_(self, cells, n_rows=None, n_cols=None, check=True): O O . . O O O O - sage: M = Matrix([[1,1,1,1],[1,1,0,0],[0,0,0,0],[1,1,0,0],[1,1,1,1]]) - sage: Dgms(M).pp() + sage: M = Matrix([[1,1,1,1],[1,1,0,0],[0,0,0,0],[1,1,0,0],[1,1,1,1]]) # needs sage.modules + sage: Dgms(M).pp() # needs sage.modules O O O O O O . . . . . . @@ -676,23 +722,23 @@ def from_polyomino(self, p): EXAMPLES:: - sage: from sage.combinat.tiling import Polyomino - sage: p = Polyomino([(0,0),(1,0),(1,1),(1,2)]) + sage: from sage.combinat.tiling import Polyomino # needs sage.modules + sage: p = Polyomino([(0,0),(1,0),(1,1),(1,2)]) # needs sage.modules sage: from sage.combinat.diagram import Diagrams - sage: Diagrams()(p).pp() + sage: Diagrams()(p).pp() # needs sage.modules O . . O O O We can also call this method directly:: - sage: Diagrams().from_polyomino(p).pp() + sage: Diagrams().from_polyomino(p).pp() # needs sage.modules O . . O O O This only works for a 2d :class:`~sage.combinat.tiling.Polyomino`:: - sage: p = Polyomino([(0,0,0), (0,1,0), (1,1,0), (1,1,1)], color='blue') - sage: Diagrams().from_polyomino(p) + sage: p = Polyomino([(0,0,0), (0,1,0), (1,1,0), (1,1,1)], color='blue') # needs sage.modules + sage: Diagrams().from_polyomino(p) # needs sage.modules Traceback (most recent call last): ... ValueError: the polyomino must be 2 dimensional @@ -737,17 +783,17 @@ def from_zero_one_matrix(self, M, check=True): EXAMPLES:: - sage: M = matrix([[1,0,1,1],[0,1,1,0]]) + sage: M = matrix([[1,0,1,1],[0,1,1,0]]) # needs sage.modules sage: from sage.combinat.diagram import Diagrams - sage: Diagrams()(M).pp() + sage: Diagrams()(M).pp() # needs sage.modules O . O O . O O . - sage: Diagrams().from_zero_one_matrix(M).pp() + sage: Diagrams().from_zero_one_matrix(M).pp() # needs sage.modules O . O O . O O . - sage: M = matrix([[1, 0, 0], [1, 0, 0], [0, 0, 0]]) - sage: Diagrams()(M).pp() + sage: M = matrix([[1, 0, 0], [1, 0, 0], [0, 0, 0]]) # needs sage.modules + sage: Diagrams()(M).pp() # needs sage.modules O . . O . . . . . @@ -760,9 +806,9 @@ def from_zero_one_matrix(self, M, check=True): one = M.base_ring().one() for i in range(n_rows): for j in range(n_cols): - if not (M[i,j] == zero or M[i,j] == one): - raise ValueError("Matrix entries must be 0 or 1") - cells = [(i, j) for i in range(n_rows) for j in range(n_cols) if M[i,j]] + if not (M[i, j] == zero or M[i, j] == one): + raise ValueError("matrix entries must be 0 or 1") + cells = [(i, j) for i in range(n_rows) for j in range(n_cols) if M[i, j]] return self.element_class(self, cells, n_rows, n_cols, check=False) @@ -844,7 +890,7 @@ def check(self): sage: NorthwestDiagram([(0,1/2)]) Traceback (most recent call last): ... - ValueError: Diagrams must be indexed by non-negative integers + ValueError: diagrams must be indexed by non-negative integers """ from itertools import combinations Diagram.check(self) @@ -1395,10 +1441,10 @@ def from_parallelogram_polyomino(self, p): EXAMPLES:: - sage: p = ParallelogramPolyomino([[0, 0, 1, 0, 0, 0, 1, 1], + sage: p = ParallelogramPolyomino([[0, 0, 1, 0, 0, 0, 1, 1], # needs sage.modules ....: [1, 1, 0, 1, 0, 0, 0, 0]]) sage: from sage.combinat.diagram import NorthwestDiagrams - sage: NorthwestDiagrams().from_parallelogram_polyomino(p).pp() + sage: NorthwestDiagrams().from_parallelogram_polyomino(p).pp() # needs sage.modules O O . O O O . O O @@ -1454,8 +1500,8 @@ def RotheDiagram(w): :class:`sage.combinat.permutations.Permutations` are supported. In particular, elements of permutation groups are not supported:: - sage: w = SymmetricGroup(9).an_element() - sage: RotheDiagram(w) + sage: w = SymmetricGroup(9).an_element() # needs sage.groups + sage: RotheDiagram(w) # needs sage.groups Traceback (most recent call last): ... ValueError: w must be a permutation @@ -1478,8 +1524,7 @@ def RotheDiagram(w): N = w.size() winv = w.inverse() - from sage.misc.mrange import cartesian_product_iterator - cells = [c for c in cartesian_product_iterator((range(N), range(N))) + cells = [c for c in product(range(N), range(N)) if c[0] + 1 < winv(c[1] + 1) and c[1] + 1 < w(c[0] + 1)] return NorthwestDiagram(cells, n_rows=N, n_cols=N, check=False) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index bd281fdbb77..693b8dfe269 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -31,9 +31,10 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.combinat.combinat import bell_number, catalan_number from sage.structure.global_options import GlobalOptions -from sage.combinat.combinat_cython import (set_partition_iterator, perfect_matchings_iterator, +from sage.combinat.combinat_cython import (perfect_matchings_iterator, set_partition_composition) from sage.combinat.set_partition import SetPartitions, AbstractSetPartition +from sage.combinat.set_partition_iterator import set_partition_iterator from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra_n from sage.combinat.permutation import Permutations from sage.graphs.graph import Graph @@ -231,7 +232,7 @@ def planar_partitions_rec(X): if len(X) > 1: yield ([X[0]], [X[1]]) return - from sage.misc.misc import powerset + from sage.combinat.subset import powerset from itertools import product for S in powerset(range(len(X)-1)): if not S: @@ -2053,9 +2054,9 @@ def order(self): EXAMPLES:: - sage: q = var('q') - sage: PA = PartitionAlgebra(2, q) - sage: PA.order() + sage: q = var('q') # optional - sage.symbolic + sage: PA = PartitionAlgebra(2, q) # optional - sage.symbolic + sage: PA.order() # optional - sage.symbolic 2 """ return self._k @@ -2412,23 +2413,24 @@ class PartitionAlgebra(DiagramBasis, UnitDiagramMixin): :: - sage: q = var('q') - sage: PA = PartitionAlgebra(2, q); PA + sage: q = var('q') # optional - sage.symbolic + sage: PA = PartitionAlgebra(2, q); PA # optional - sage.symbolic Partition Algebra of rank 2 with parameter q over Symbolic Ring - sage: PA([[1,2],[-2,-1]])^2 == q*PA([[1,2],[-2,-1]]) + sage: PA([[1,2],[-2,-1]])^2 == q*PA([[1,2],[-2,-1]]) # optional - sage.symbolic True - sage: (PA([[2, -2], [1, -1]]) - 2*PA([[-2, -1], [1, 2]]))^2 == (4*q-4)*PA([[1, 2], [-2, -1]]) + PA([[2, -2], [1, -1]]) + sage: ((PA([[2, -2], [1, -1]]) - 2*PA([[-2, -1], [1, 2]]))^2 # optional - sage.symbolic + ....: == (4*q-4)*PA([[1, 2], [-2, -1]]) + PA([[2, -2], [1, -1]])) True The identity element of the partition algebra is the set partition `\{\{1,-1\}, \{2,-2\}, \ldots, \{k,-k\}\}`:: - sage: P = PA.basis().list() - sage: PA.one() + sage: P = PA.basis().list() # optional - sage.symbolic + sage: PA.one() # optional - sage.symbolic P{{-2, 2}, {-1, 1}} - sage: PA.one() * P[7] == P[7] + sage: PA.one() * P[7] == P[7] # optional - sage.symbolic True - sage: P[7] * PA.one() == P[7] + sage: P[7] * PA.one() == P[7] # optional - sage.symbolic True We now give some further examples of the use of the other arguments. @@ -2445,21 +2447,22 @@ class PartitionAlgebra(DiagramBasis, UnitDiagramMixin): sage: PA = PartitionAlgebra(2, 5, base_ring=ZZ, prefix='B') sage: PA Partition Algebra of rank 2 with parameter 5 over Integer Ring - sage: (PA([[2, -2], [1, -1]]) - 2*PA([[-2, -1], [1, 2]]))^2 == 16*PA([[-2, -1], [1, 2]]) + PA([[2, -2], [1, -1]]) + sage: ((PA([[2, -2], [1, -1]]) - 2*PA([[-2, -1], [1, 2]]))^2 + ....: == 16*PA([[-2, -1], [1, 2]]) + PA([[2, -2], [1, -1]])) True Symmetric group algebra elements and elements from other subalgebras of the partition algebra (e.g., ``BrauerAlgebra`` and ``TemperleyLiebAlgebra``) can also be coerced into the partition algebra:: - sage: S = SymmetricGroupAlgebra(SR, 2) - sage: B = BrauerAlgebra(2, x, SR) - sage: A = PartitionAlgebra(2, x, SR) - sage: S([2,1])*A([[1,-1],[2,-2]]) + sage: S = SymmetricGroupAlgebra(SR, 2) # optional - sage.symbolic + sage: B = BrauerAlgebra(2, x, SR) # optional - sage.symbolic + sage: A = PartitionAlgebra(2, x, SR) # optional - sage.symbolic + sage: S([2,1]) * A([[1,-1],[2,-2]]) # optional - sage.symbolic P{{-2, 1}, {-1, 2}} - sage: B([[-1,-2],[2,1]]) * A([[1],[-1],[2,-2]]) + sage: B([[-1,-2],[2,1]]) * A([[1],[-1],[2,-2]]) # optional - sage.symbolic P{{-2}, {-1}, {1, 2}} - sage: A([[1],[-1],[2,-2]]) * B([[-1,-2],[2,1]]) + sage: A([[1],[-1],[2,-2]]) * B([[-1,-2],[2,1]]) # optional - sage.symbolic P{{-2, -1}, {1}, {2}} The same is true if the elements come from a subalgebra of a partition @@ -2470,7 +2473,7 @@ class PartitionAlgebra(DiagramBasis, UnitDiagramMixin): sage: S = SymmetricGroupAlgebra(ZZ, 2) sage: B = BrauerAlgebra(2, q, ZZ[q]) sage: A = PartitionAlgebra(3, q, R) - sage: S([2,1])*A([[1,-1],[2,-3],[3,-2]]) + sage: S([2,1]) * A([[1,-1],[2,-3],[3,-2]]) P{{-3, 1}, {-2, 3}, {-1, 2}} sage: A(B([[-1,-2],[2,1]])) P{{-3, 3}, {-2, -1}, {1, 2}} @@ -2490,21 +2493,21 @@ class PartitionAlgebra(DiagramBasis, UnitDiagramMixin): Shorthands for working with basis elements are as follows:: sage: S = SymmetricGroupAlgebra(ZZ, 3) - sage: A = PartitionAlgebra(3, x, SR) + sage: A = PartitionAlgebra(3, x, SR) # optional - sage.symbolic - sage: A([[1,3],[-1],[-3]]) # pair up the omitted nodes as `{-i, i}`, if possible + sage: A([[1,3],[-1],[-3]]) # pair up the omitted nodes as `{-i, i}`, if possible # optional - sage.symbolic P{{-3}, {-2, 2}, {-1}, {1, 3}} - sage: A([[1,3],[-1],[-3]]) == A[[1,3],[-1],[-3]] + sage: A([[1,3],[-1],[-3]]) == A[[1,3],[-1],[-3]] # optional - sage.symbolic True - sage: A([[1,2]]) + sage: A([[1,2]]) # optional - sage.symbolic P{{-3, 3}, {-2}, {-1}, {1, 2}} - sage: A([[1,2]]) == A[[1,2]] + sage: A([[1,2]]) == A[[1,2]] # optional - sage.symbolic True - sage: A([2,3,1]) # permutations in one-line notation are imported as well + sage: A([2,3,1]) # permutations in one-line notation are imported as well # optional - sage.symbolic P{{-3, 2}, {-2, 1}, {-1, 3}} - sage: A([2,3,1]) == A(S([2,3,1])) + sage: A([2,3,1]) == A(S([2,3,1])) # optional - sage.symbolic True """ @staticmethod @@ -3592,9 +3595,9 @@ def ambient(self): EXAMPLES:: - sage: x = var('x') - sage: BA = BrauerAlgebra(2, x) - sage: BA.ambient() + sage: x = var('x') # optional - sage.symbolic + sage: BA = BrauerAlgebra(2, x) # optional - sage.symbolic + sage: BA.ambient() # optional - sage.symbolic Partition Algebra of rank 2 with parameter x over Symbolic Ring """ return self.lift.codomain() @@ -3833,11 +3836,11 @@ def jucys_murphy(self, j): EXAMPLES:: - sage: z = var('z') - sage: B = BrauerAlgebra(3,z) - sage: B.jucys_murphy(1) + sage: z = var('z') # optional - sage.symbolic + sage: B = BrauerAlgebra(3,z) # optional - sage.symbolic + sage: B.jucys_murphy(1) # optional - sage.symbolic (1/2*z-1/2)*B{{-3, 3}, {-2, 2}, {-1, 1}} - sage: B.jucys_murphy(3) + sage: B.jucys_murphy(3) # optional - sage.symbolic -B{{-3, -2}, {-1, 1}, {2, 3}} - B{{-3, -1}, {-2, 2}, {1, 3}} + B{{-3, 1}, {-2, 2}, {-1, 3}} + B{{-3, 2}, {-2, 3}, {-1, 1}} + (1/2*z-1/2)*B{{-3, 3}, {-2, 2}, {-1, 1}} diff --git a/src/sage/combinat/dlx.py b/src/sage/combinat/dlx.py index 6a6d0d15c11..d243abbc9c2 100644 --- a/src/sage/combinat/dlx.py +++ b/src/sage/combinat/dlx.py @@ -474,11 +474,11 @@ def AllExactCovers(M): EXAMPLES:: - sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) #no exact covers - sage: for cover in AllExactCovers(M): + sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) # no exact covers # optional - sage.modules + sage: for cover in AllExactCovers(M): # optional - sage.modules ....: print(cover) - sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) #two exact covers - sage: for cover in AllExactCovers(M): + sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) # two exact covers # optional - sage.modules + sage: for cover in AllExactCovers(M): # optional - sage.modules ....: print(cover) [(1, 1, 0), (0, 0, 1)] [(1, 0, 1), (0, 1, 0)] @@ -503,11 +503,11 @@ def OneExactCover(M): EXAMPLES:: - sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) # no exact covers - sage: OneExactCover(M) + sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) # no exact covers # optional - sage.modules + sage: OneExactCover(M) # optional - sage.modules - sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) # two exact covers - sage: OneExactCover(M) + sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) # two exact covers # optional - sage.modules + sage: OneExactCover(M) # optional - sage.modules [(1, 1, 0), (0, 0, 1)] """ for s in AllExactCovers(M): diff --git a/src/sage/combinat/dyck_word.py b/src/sage/combinat/dyck_word.py index beb6b4404f6..80911865d49 100644 --- a/src/sage/combinat/dyck_word.py +++ b/src/sage/combinat/dyck_word.py @@ -89,7 +89,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets -from sage.categories.all import Posets +from sage.categories.posets import Posets from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -539,7 +539,7 @@ def _repr_lattice(self, type=None, labelling=None, underpath=True) -> str: final_fall = " " else: final_fall = " _" + "__" * (length_of_final_fall - 1) - row = " "*(n - alst[-1] - 1) + final_fall + "\n" + row = " " * (n - alst[-1] - 1) + final_fall + "\n" for i in range(n - 1): c = 0 row = row + " "*(n-i-2-alst[-i-2]) @@ -957,7 +957,7 @@ def plot(self, **kwds): EXAMPLES:: sage: w = DyckWords(100).random_element() - sage: w.plot() + sage: w.plot() # optional - sage.plot Graphics object consisting of 1 graphics primitive """ from sage.plot.plot import list_plot @@ -1979,26 +1979,33 @@ def number_of_parking_functions(self) -> int: sage: DyckWord(area_sequence=[0,0,0]).number_of_parking_functions() 6 """ - from sage.arith.all import multinomial + from sage.arith.misc import multinomial return multinomial(self.rise_composition()) - def list_parking_functions(self): + def list_parking_functions(self) -> list: r""" Return all parking functions whose supporting Dyck path is ``self``. EXAMPLES:: sage: DyckWord([1,1,0,0,1,0]).list_parking_functions() - Permutations of the multi-set [1, 1, 3] - sage: DyckWord([1,1,1,0,0,0]).list_parking_functions() - Permutations of the multi-set [1, 1, 1] - sage: DyckWord([1,0,1,0,1,0]).list_parking_functions() - Standard permutations of 3 + [[1, 1, 3], [1, 3, 1], [3, 1, 1]] """ + return list(self.parking_functions()) + + def parking_functions(self): + r""" + Iterate over parking functions whose supporting Dyck path is ``self``. + + EXAMPLES:: + + sage: list(DyckWord([1,1,0,1,0,0]).parking_functions()) + [[1, 1, 2], [1, 2, 1], [2, 1, 1]] + """ + from sage.combinat.parking_functions import ParkingFunction alist = self._area_sequence_iter() - return Permutations([i - ai + 1 for i, ai in enumerate(alist)]) - # TODO: upon implementation of ParkingFunction class - # map(ParkingFunction, Permutations([i - alist[i]+1 for i in range(len(alist))])) + for pi in Permutations([i - ai + 1 for i, ai in enumerate(alist)]): + yield ParkingFunction(pi) def reading_permutation(self) -> Permutation: r""" @@ -2194,7 +2201,7 @@ def to_noncrossing_permutation(self) -> Permutation: pi[touches[i] - 1] = pi[touches[i + 1] - 1] pi[touches[-1] - 1] = a D, touch_sequence = pealing(D, return_touches=True) - return Permutations()(pi, check_input=False) + return Permutations()(pi, check=False) @combinatorial_map(name='to 321 avoiding permutation') def to_321_avoiding_permutation(self) -> Permutation: @@ -3778,7 +3785,7 @@ def cardinality(self) -> int: ....: for p in range(7)) True """ - from sage.arith.all import binomial + from sage.arith.misc import binomial return (self.k1 - self.k2 + 1) * binomial(self.k1 + self.k2, self.k2) // (self.k1 + 1) ################################################################ diff --git a/src/sage/combinat/e_one_star.py b/src/sage/combinat/e_one_star.py index 31f24495c23..cb6e5607931 100644 --- a/src/sage/combinat/e_one_star.py +++ b/src/sage/combinat/e_one_star.py @@ -159,9 +159,9 @@ sage: P = Patch([Face([0,0], 1), Face([0,0], 2)]) sage: E = E1Star(WordMorphism({1:[1,2],2:[1]})) sage: F = E1Star(WordMorphism({1:[1,1,2],2:[2,1]})) - sage: E(P,5).plot() + sage: E(P,5).plot() # optional - sage.plot Graphics object consisting of 21 graphics primitives - sage: F(P,3).plot() + sage: F(P,3).plot() # optional - sage.plot Graphics object consisting of 34 graphics primitives Everything works in any dimension (except for the plotting features @@ -288,7 +288,7 @@ def __init__(self, v, t, color=None): self._vector.set_immutable() if not((t in ZZ) and 1 <= t <= len(v)): - raise ValueError('The type must be an integer between 1 and len(v)') + raise ValueError('the type must be an integer between 1 and len(v)') self._type = t if color is None: @@ -490,12 +490,12 @@ def _plot(self, projmat, face_contour, opacity) -> Graphics: sage: face_contour[1] = map(vector, [(0,0,0),(0,1,0),(0,1,1),(0,0,1)]) sage: face_contour[2] = map(vector, [(0,0,0),(0,0,1),(1,0,1),(1,0,0)]) sage: face_contour[3] = map(vector, [(0,0,0),(1,0,0),(1,1,0),(0,1,0)]) - sage: G = f._plot(projmat, face_contour, 0.75) + sage: G = f._plot(projmat, face_contour, 0.75) # optional - sage.plot :: sage: f = Face((0,0), 2) - sage: f._plot(None, None, 1) + sage: f._plot(None, None, 1) # optional - sage.plot Graphics object consisting of 1 graphics primitive """ v = self.vector() @@ -514,7 +514,7 @@ def _plot(self, projmat, face_contour, opacity) -> Graphics: thickness=1, rgbcolor=self.color()) else: - raise NotImplementedError("Plotting is implemented only for patches in two or three dimensions.") + raise NotImplementedError("plotting is implemented only for patches in two or three dimensions.") return G @@ -1071,14 +1071,14 @@ def repaint(self, cmap='Set1') -> None: from matplotlib import cm assert cm is not None if cmap not in cm.datad: - raise RuntimeError("Color map %s not known (type sorted(colors) for valid names)" % cmap) + raise RuntimeError("color map %s not known (type sorted(colors) for valid names)" % cmap) cmap = cm.__dict__[cmap] dim = float(len(self)) for i, f in enumerate(self): f.color(cmap(i / dim)[:3]) else: - raise TypeError("Type of cmap (=%s) must be dict, list or str" % cmap) + raise TypeError("type of cmap (=%s) must be dict, list or str" % cmap) def plot(self, projmat=None, opacity=0.75) -> Graphics: r""" @@ -1102,7 +1102,7 @@ def plot(self, projmat=None, opacity=0.75) -> Graphics: sage: from sage.combinat.e_one_star import E1Star, Face, Patch sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]]) - sage: P.plot() + sage: P.plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives :: @@ -1111,7 +1111,7 @@ def plot(self, projmat=None, opacity=0.75) -> Graphics: sage: E = E1Star(sigma) sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]]) sage: P = E(P, 5) - sage: P.plot() + sage: P.plot() # optional - sage.plot Graphics object consisting of 57 graphics primitives Plot with a different projection matrix:: @@ -1121,7 +1121,7 @@ def plot(self, projmat=None, opacity=0.75) -> Graphics: sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]]) sage: M = matrix(2, 3, [1,0,-1,0.3,1,-3]) sage: P = E(P, 3) - sage: P.plot(projmat=M) + sage: P.plot(projmat=M) # optional - sage.plot Graphics object consisting of 17 graphics primitives Plot patches made of unit segments:: @@ -1129,9 +1129,9 @@ def plot(self, projmat=None, opacity=0.75) -> Graphics: sage: P = Patch([Face([0,0], 1), Face([0,0], 2)]) sage: E = E1Star(WordMorphism({1:[1,2],2:[1]})) sage: F = E1Star(WordMorphism({1:[1,1,2],2:[2,1]})) - sage: E(P,5).plot() + sage: E(P,5).plot() # optional - sage.plot Graphics object consisting of 21 graphics primitives - sage: F(P,3).plot() + sage: F(P,3).plot() # optional - sage.plot Graphics object consisting of 34 graphics primitives """ if self.dimension() == 2: @@ -1154,7 +1154,7 @@ def plot(self, projmat=None, opacity=0.75) -> Graphics: return G else: - raise NotImplementedError("Plotting is implemented only for patches in two or three dimensions.") + raise NotImplementedError("plotting is implemented only for patches in two or three dimensions.") def plot3d(self): r""" @@ -1180,7 +1180,7 @@ def plot3d(self): sage: P.plot3d() #not tested """ if self.dimension() != 3: - raise NotImplementedError("3D plotting is implemented only for patches in three dimensions.") + raise NotImplementedError("3D plotting is implemented only for patches in three dimensions") face_list = [face._plot3d(self._face_contour) for face in self] G = sum(face_list) @@ -1302,7 +1302,7 @@ def plot_tikz(self, projmat=None, print_tikz_env=True, edgecolor='black', \end{tikzpicture} """ if self.dimension() != 3: - raise NotImplementedError("Tikz Plotting is implemented only for patches in three dimensions.") + raise NotImplementedError("Tikz plotting is implemented only for patches in three dimensions") if projmat is None: projmat = matrix(2, [-1.7320508075688772 * 0.5, @@ -1412,14 +1412,14 @@ def __init__(self, sigma, method='suffix'): raise TypeError("sigma (=%s) must be an instance of WordMorphism" % sigma) if sigma.domain().alphabet() != sigma.codomain().alphabet(): - raise ValueError("The domain and codomain of (%s) must be the same." % sigma) + raise ValueError("the domain and codomain of (%s) must be the same" % sigma) if abs(det(matrix(sigma))) != 1: - raise ValueError("The substitution (%s) must be unimodular." % sigma) + raise ValueError("the substitution (%s) must be unimodular" % sigma) first_letter = sigma.codomain().alphabet()[0] if not (first_letter in ZZ) or (first_letter < 1): - raise ValueError("The substitution (%s) must be defined on positive integers." % sigma) + raise ValueError("the substitution (%s) must be defined on positive integers" % sigma) self._sigma = WordMorphism(sigma) self._d = self._sigma.domain().alphabet().cardinality() @@ -1436,7 +1436,7 @@ def __init__(self, sigma, method='suffix'): elif method == 'prefix': image_word = subst_im[:n] else: - raise ValueError("Option 'method' can only be 'prefix' or 'suffix'.") + raise ValueError("option 'method' can only be 'prefix' or 'suffix'") if letter not in X: X[letter] = [] v = self.inverse_matrix() * vector(image_word.abelian_vector()) @@ -1505,10 +1505,10 @@ def __call__(self, patch, iterations=1) -> Patch: if iterations == 0: return Patch(patch) elif iterations < 0: - raise ValueError("iterations (=%s) must be >= 0." % iterations) + raise ValueError("iterations (=%s) must be >= 0" % iterations) else: old_faces = patch - for i in range(iterations): + for _ in range(iterations): new_faces = [] for f in old_faces: new_faces.extend(self._call_on_face(f, color=f.color())) @@ -1582,7 +1582,7 @@ def _call_on_face(self, face, color=None): [[(3, 0, -3), 1]*, [(2, 1, -3), 2]*, [(2, 0, -2), 3]*] """ if len(face.vector()) != self._d: - raise ValueError("The dimension of the faces must be equal to the size of the alphabet of the substitution.") + raise ValueError("the dimension of the faces must be equal to the size of the alphabet of the substitution") x_new = self.inverse_matrix() * face.vector() t = face.type() return (Face(x_new + v, k, color=color) for v, k in self._base_iter[t]) diff --git a/src/sage/combinat/enumeration_mod_permgroup.pyx b/src/sage/combinat/enumeration_mod_permgroup.pyx index 312026ca4c6..3e0b891165f 100644 --- a/src/sage/combinat/enumeration_mod_permgroup.pyx +++ b/src/sage/combinat/enumeration_mod_permgroup.pyx @@ -274,7 +274,6 @@ cpdef set orbit(list sgs, ClonableIntArray v): cdef set to_analyse, new_to_analyse cdef ClonableIntArray list_test, child cdef PermutationGroupElement x - cdef list out l = len(v) to_analyse = set([v]) for i in range(l-1): diff --git a/src/sage/combinat/expnums.pyx b/src/sage/combinat/expnums.pyx index e3cbbc6757e..bff30b763d7 100644 --- a/src/sage/combinat/expnums.pyx +++ b/src/sage/combinat/expnums.pyx @@ -11,7 +11,7 @@ from cysignals.memory cimport check_allocarray, sig_free from sage.libs.gmp.mpz cimport * from sage.rings.integer cimport Integer -from sage.rings.integer_ring import ZZ + def expnums(int n, int aa): r""" diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 29671fb28ed..494e8154c80 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -944,7 +944,6 @@ from sage.misc.latex import latex from sage.misc.verbose import verbose from sage.misc.sageinspect import sage_getargspec -from sage.rings.qqbar import QQbar from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR from sage.structure.sage_object import SageObject @@ -5755,7 +5754,7 @@ def is_deterministic(self): state.transitions, key=lambda t: t.word_in) - for key, transition_class in transition_classes_by_word_in: + for _, transition_class in transition_classes_by_word_in: if len(transition_class) > 1: return False return True @@ -6447,14 +6446,14 @@ def _iter_process_simple_(self, iterator): "'simple' iterator cannot be used " "here." % (len(current),)) - pos, states = next(iter(current.items())) + _, states = next(iter(current.items())) if len(states) > 1: raise RuntimeError("Process has branched " "(visiting %s states in branch). The " "'simple' iterator cannot be used " "here." % (len(states),)) - state, branch = next(iter(states.items())) + _, branch = next(iter(states.items())) if len(branch.outputs) > 1: raise RuntimeError("Process has branched. " "(%s different outputs in branch). The " @@ -8217,7 +8216,7 @@ def function(transition1, transition2): for state_result in result.iter_states(): state = state_result.label()[0] if state.is_final: - accept, state_to, output = self.process( + accept, _, output = self.process( state.final_word_out, initial_state=self.state(state_result.label()[1])) if not accept: @@ -9708,7 +9707,7 @@ def plot(self): TESTS:: - sage: FiniteStateMachine([('A', 'A', 0)]).plot() + sage: FiniteStateMachine([('A', 'A', 0)]).plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives """ return self.graph(edge_labels='words_in_out').plot() @@ -9885,7 +9884,7 @@ def number_of_words(self, variable=None, from sage.arith.misc import binomial from sage.symbolic.ring import SR if base_ring is None: - base_ring = QQbar + from sage.rings.qqbar import QQbar as base_ring if variable is None: variable = SR.symbol('n') @@ -10437,11 +10436,11 @@ def moments_waiting_time(self, test=bool, is_zero=None, and the variance are `\sum_{k\ge 1} k2^{-k}=2` and `\sum_{k\ge 1} (k-2)^2 2^{-k}=2`:: - sage: var('k') + sage: var('k') # optional - sage.symbolic k - sage: sum(k * 2^(-k), k, 1, infinity) + sage: sum(k * 2^(-k), k, 1, infinity) # optional - sage.symbolic 2 - sage: sum((k-2)^2 * 2^(-k), k, 1, infinity) + sage: sum((k-2)^2 * 2^(-k), k, 1, infinity) # optional - sage.symbolic 2 We now compute the same expectation and variance by using a @@ -11810,7 +11809,7 @@ def _process_convert_output_(self, output_data, **kwargs): if kwargs['always_include_output']: return super()._process_convert_output_( output_data, **kwargs) - accept_input, current_state, output = output_data + accept_input, current_state, _ = output_data if kwargs['full_output']: return (accept_input, current_state) else: @@ -11846,13 +11845,13 @@ def shannon_parry_markov_chain(self): sage: NAF = Automaton([(0, 0, 0), (0, 1, 1), (0, 1, -1), ....: (1, 0, 0)], initial_states=[0], ....: final_states=[0, 1]) - sage: P_NAF = NAF.shannon_parry_markov_chain() - sage: P_NAF.transitions() + sage: P_NAF = NAF.shannon_parry_markov_chain() # optional - sage.symbolic + sage: P_NAF.transitions() # optional - sage.symbolic [Transition from 0 to 0: 1/2|0, Transition from 0 to 1: 1/4|1, Transition from 0 to 1: 1/4|-1, Transition from 1 to 0: 1|0] - sage: for s in P_NAF.iter_states(): + sage: for s in P_NAF.iter_states(): # optional - sage.symbolic ....: print(s.color) 3/4 3/2 @@ -11860,7 +11859,7 @@ def shannon_parry_markov_chain(self): The stationary distribution is also computed and saved as the initial probabilities of the returned Markov chain:: - sage: for s in P_NAF.states(): + sage: for s in P_NAF.states(): # optional - sage.symbolic ....: print("{} {}".format(s, s.initial_probability)) 0 2/3 1 1/3 @@ -13770,8 +13769,8 @@ def compare_to_tape(self, track_number, word): next(it_word) # check letters not already cached - for letter_in_word in it_word: - successful, letter_on_track = self.read(track_number) + for _ in it_word: + successful, _ = self.read(track_number) if not successful: return False return True @@ -14121,8 +14120,8 @@ def __repr__(self): sage: T = Transducer([(0, 0, 0, 0)], ....: initial_states=[0], final_states=[0]) sage: it = FSMProcessIterator(T, input_tape=[0, 0]) - sage: for current in it: - ....: print(current) # indirect doctest + sage: for current in it: # indirect doctest + ....: print(current) process (1 branch) + at state 0 +-- tape at 1, [[0]] @@ -14289,10 +14288,10 @@ def _push_branch_(self, state, tape_cache, outputs): +-- tape at 0, [[]] + at state 'b' +-- tape at 0, [[]] - sage: it._push_branches_( + sage: it._push_branches_( # indirect doctest ....: A.state('c'), ....: deepcopy(it._current_[((0, 0),)][A.state('a')][0]), - ....: [[]]) # indirect doctest + ....: [[]]) sage: it._current_ process (3 branches) + at state 'a' diff --git a/src/sage/combinat/finite_state_machine_generators.py b/src/sage/combinat/finite_state_machine_generators.py index 4a5a875796b..b5b8abbbd9e 100644 --- a/src/sage/combinat/finite_state_machine_generators.py +++ b/src/sage/combinat/finite_state_machine_generators.py @@ -276,7 +276,7 @@ def Word(self, word, input_alphabet=None): letters = list(word) length = len(letters) from sage.rings.integer_ring import ZZ - return Automaton([(ZZ(i), ZZ(i+1), letter) + return Automaton([(ZZ(i), ZZ(i + 1), letter) for i, letter in enumerate(letters)], initial_states=[ZZ(0)], final_states=[ZZ(length)], @@ -1079,15 +1079,15 @@ def _parse_recursion_equation_(self, equation, base, function, var, EXAMPLES:: - sage: var('n') + sage: var('n') # optional - sage.symbolic n - sage: function('f') + sage: function('f') # optional - sage.symbolic f - sage: transducers._parse_recursion_equation_( + sage: transducers._parse_recursion_equation_( # optional - sage.symbolic ....: f(8*n + 7) == f(2*n + 3) + 5, ....: 2, f, n) RecursionRule(K=3, r=7, k=1, s=3, t=[5]) - sage: transducers._parse_recursion_equation_( + sage: transducers._parse_recursion_equation_( # optional - sage.symbolic ....: f(42) == 5, ....: 2, f, n) {42: [5]} @@ -1096,14 +1096,14 @@ def _parse_recursion_equation_(self, equation, base, function, var, The following tests check that the equations are well-formed:: - sage: transducers._parse_recursion_equation_(f(4*n + 1), 2, f, n) + sage: transducers._parse_recursion_equation_(f(4*n + 1), 2, f, n) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: f(4*n + 1) is not an equation with ==. :: - sage: transducers._parse_recursion_equation_(f(n) + 1 == f(2*n), + sage: transducers._parse_recursion_equation_(f(n) + 1 == f(2*n), # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1111,7 +1111,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(2*n, 5) == 3, + sage: transducers._parse_recursion_equation_(f(2*n, 5) == 3, # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1119,7 +1119,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(1/n) == f(n) + 3, + sage: transducers._parse_recursion_equation_(f(1/n) == f(n) + 3, # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1127,7 +1127,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(n^2 + 5) == 3, + sage: transducers._parse_recursion_equation_(f(n^2 + 5) == 3, # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1135,7 +1135,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(3*n + 5) == f(n) + 7, + sage: transducers._parse_recursion_equation_(f(3*n + 5) == f(n) + 7, # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1143,7 +1143,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(n + 5) == f(n) + 7, + sage: transducers._parse_recursion_equation_(f(n + 5) == f(n) + 7, # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1151,7 +1151,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_( + sage: transducers._parse_recursion_equation_( # optional - sage.symbolic ....: f(2*n + 1) == f(n + 1) + f(n) + 2, ....: 2, f, n) Traceback (most recent call last): @@ -1161,7 +1161,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(2*n + 1) == sin(n) + 2, + sage: transducers._parse_recursion_equation_(f(2*n + 1) == sin(n) + 2, # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1170,7 +1170,8 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(2*n + 1) == f(n) + n + 2, + sage: transducers._parse_recursion_equation_( # optional - sage.symbolic + ....: f(2*n + 1) == f(n) + n + 2, ....: 2, f, n) Traceback (most recent call last): ... @@ -1178,7 +1179,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(2*n + 1) == sin(n), + sage: transducers._parse_recursion_equation_(f(2*n + 1) == sin(n), # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1186,7 +1187,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(2*n + 1) == f(n, 2), + sage: transducers._parse_recursion_equation_(f(2*n + 1) == f(n, 2), # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1194,7 +1195,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(2*n + 1) == f(1/n), + sage: transducers._parse_recursion_equation_(f(2*n + 1) == f(1/n), # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1202,7 +1203,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(2*n + 1) == f(n^2 + 5), + sage: transducers._parse_recursion_equation_(f(2*n + 1) == f(n^2 + 5), # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1210,7 +1211,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(2*n + 1) == f(3*n + 5), + sage: transducers._parse_recursion_equation_(f(2*n + 1) == f(3*n + 5), # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1218,7 +1219,8 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(2*n + 1) == f((1/2)*n + 5), + sage: transducers._parse_recursion_equation_( # optional - sage.symbolic + ....: f(2*n + 1) == f((1/2)*n + 5), ....: QQ(2), f, n) Traceback (most recent call last): ... @@ -1226,7 +1228,7 @@ def _parse_recursion_equation_(self, equation, base, function, var, :: - sage: transducers._parse_recursion_equation_(f(2*n + 1) == f(2*n + 5), + sage: transducers._parse_recursion_equation_(f(2*n + 1) == f(2*n + 5), # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1241,7 +1243,7 @@ def convert_output(output): for ring in output_rings: try: return ring(output) - except (ValueError,TypeError): + except (ValueError, TypeError): pass return output @@ -1353,12 +1355,12 @@ def to_list(output): assert equation == parsed_equation, \ "Parsing of %s failed for unknown reasons." % (equation,) - rule = self.RecursionRule(K=K,r=r, k=k, s=s, t=to_list(t)) + rule = self.RecursionRule(K=K, r=r, k=k, s=s, t=to_list(t)) return rule def Recursion(self, recursions, base, function=None, var=None, input_alphabet=None, word_function=None, - is_zero=None, output_rings=[ZZ, QQ]): + is_zero=None, output_rings=[ZZ, QQ]): r""" Return a transducer realizing the given recursion when reading the digit expansion with base ``base``. @@ -1432,17 +1434,17 @@ def Recursion(self, recursions, base, function=None, var=None, - The following example computes the Hamming weight of the ternary expansion of integers. :: - sage: function('f') + sage: function('f') # optional - sage.symbolic f - sage: var('n') + sage: var('n') # optional - sage.symbolic n - sage: T = transducers.Recursion([ + sage: T = transducers.Recursion([ # optional - sage.symbolic ....: f(3*n + 1) == f(n) + 1, ....: f(3*n + 2) == f(n) + 1, ....: f(3*n) == f(n), ....: f(0) == 0], ....: 3, f, n) - sage: T.transitions() + sage: T.transitions() # optional - sage.symbolic [Transition from (0, 0) to (0, 0): 0|-, Transition from (0, 0) to (0, 0): 1|1, Transition from (0, 0) to (0, 0): 2|1] @@ -1450,13 +1452,13 @@ def Recursion(self, recursions, base, function=None, var=None, To illustrate what this transducer does, we consider the example of `n=601`:: - sage: ternary_expansion = 601.digits(base=3) - sage: ternary_expansion + sage: ternary_expansion = 601.digits(base=3) # optional - sage.symbolic + sage: ternary_expansion # optional - sage.symbolic [1, 2, 0, 1, 1, 2] - sage: weight_sequence = T(ternary_expansion) - sage: weight_sequence + sage: weight_sequence = T(ternary_expansion) # optional - sage.symbolic + sage: weight_sequence # optional - sage.symbolic [1, 1, 1, 1, 1] - sage: sum(weight_sequence) + sage: sum(weight_sequence) # optional - sage.symbolic 5 Note that the digit zero does not show up in the output because @@ -1466,24 +1468,24 @@ def Recursion(self, recursions, base, function=None, var=None, - The following example computes the Hamming weight of the non-adjacent form, cf. the :wikipedia:`Non-adjacent_form`. :: - sage: function('f') + sage: function('f') # optional - sage.symbolic f - sage: var('n') + sage: var('n') # optional - sage.symbolic n - sage: T = transducers.Recursion([ + sage: T = transducers.Recursion([ # optional - sage.symbolic ....: f(4*n + 1) == f(n) + 1, ....: f(4*n - 1) == f(n) + 1, ....: f(2*n) == f(n), ....: f(0) == 0], ....: 2, f, n) - sage: T.transitions() + sage: T.transitions() # optional - sage.symbolic [Transition from (0, 0) to (0, 0): 0|-, Transition from (0, 0) to (1, 1): 1|-, Transition from (1, 1) to (0, 0): 0|1, Transition from (1, 1) to (1, 0): 1|1, Transition from (1, 0) to (1, 1): 0|-, Transition from (1, 0) to (1, 0): 1|-] - sage: [(s.label(), s.final_word_out) + sage: [(s.label(), s.final_word_out) # optional - sage.symbolic ....: for s in T.iter_final_states()] [((0, 0), []), ((1, 1), [1]), @@ -1505,9 +1507,9 @@ def Recursion(self, recursions, base, function=None, var=None, sage: binary_expansion = 29.digits(base=2) sage: binary_expansion [1, 0, 1, 1, 1] - sage: T(binary_expansion) + sage: T(binary_expansion) # optional - sage.symbolic [1, 1, 1] - sage: sum(T(binary_expansion)) + sage: sum(T(binary_expansion)) # optional - sage.symbolic 3 Indeed, the given non-adjacent form has three non-zero @@ -1533,11 +1535,11 @@ def Recursion(self, recursions, base, function=None, var=None, the point of view of this method---is a contradicting recursion. We override this by the parameter ``is_zero``. :: - sage: var('n') + sage: var('n') # optional - sage.symbolic n - sage: function('f w') + sage: function('f w') # optional - sage.symbolic (f, w) - sage: T = transducers.Recursion([ + sage: T = transducers.Recursion([ # optional - sage.symbolic ....: f(2*n) == f(n) + w(0), ....: f(4*n + 1) == f(n) + w(1, 0), ....: f(4*n - 1) == f(n) + w(-1, 0), @@ -1545,14 +1547,14 @@ def Recursion(self, recursions, base, function=None, var=None, ....: 2, f, n, ....: word_function=w, ....: is_zero=lambda x: sum(x).is_zero()) - sage: T.transitions() + sage: T.transitions() # optional - sage.symbolic [Transition from (0, 0) to (0, 0): 0|0, Transition from (0, 0) to (1, 1): 1|-, Transition from (1, 1) to (0, 0): 0|1,0, Transition from (1, 1) to (1, 0): 1|-1,0, Transition from (1, 0) to (1, 1): 0|-, Transition from (1, 0) to (1, 0): 1|0] - sage: for s in T.iter_states(): + sage: for s in T.iter_states(): # optional - sage.symbolic ....: print("{} {}".format(s, s.final_word_out)) (0, 0) [] (1, 1) [1, 0] @@ -1560,7 +1562,7 @@ def Recursion(self, recursions, base, function=None, var=None, We again consider the example of `n=29`:: - sage: T(29.digits(base=2)) + sage: T(29.digits(base=2)) # optional - sage.symbolic [1, 0, -1, 0, 0, 1, 0] The same transducer can also be entered bypassing the @@ -1574,22 +1576,22 @@ def Recursion(self, recursions, base, function=None, var=None, ....: (0, [])], ....: 2, ....: is_zero=lambda x: sum(x).is_zero()) - sage: TR == T + sage: TR == T # optional - sage.symbolic True - Here is an artificial example where some of the `s` are negative:: - sage: function('f') + sage: function('f') # optional - sage.symbolic f - sage: var('n') + sage: var('n') # optional - sage.symbolic n - sage: T = transducers.Recursion([ + sage: T = transducers.Recursion([ # optional - sage.symbolic ....: f(2*n + 1) == f(n-1) + 1, ....: f(2*n) == f(n), ....: f(1) == 1, ....: f(0) == 0], 2, f, n) - sage: T.transitions() + sage: T.transitions() # optional - sage.symbolic [Transition from (0, 0) to (0, 0): 0|-, Transition from (0, 0) to (1, 1): 1|-, Transition from (1, 1) to (-1, 1): 0|1, @@ -1600,7 +1602,7 @@ def Recursion(self, recursions, base, function=None, var=None, Transition from (-1, 2) to (0, 0): 1|1, Transition from (1, 2) to (-1, 2): 0|1, Transition from (1, 2) to (1, 2): 1|1] - sage: [(s.label(), s.final_word_out) + sage: [(s.label(), s.final_word_out) # optional - sage.symbolic ....: for s in T.iter_final_states()] [((0, 0), []), ((1, 1), [1]), @@ -1611,7 +1613,7 @@ def Recursion(self, recursions, base, function=None, var=None, - Abelian complexity of the paperfolding sequence (cf. [HKP2015]_, Example 2.8):: - sage: T = transducers.Recursion([ + sage: T = transducers.Recursion([ # optional - sage.symbolic ....: f(4*n) == f(2*n), ....: f(4*n+2) == f(2*n+1)+1, ....: f(16*n+1) == f(8*n+1), @@ -1621,7 +1623,7 @@ def Recursion(self, recursions, base, function=None, var=None, ....: f(1) == 2, f(0) == 0] ....: + [f(16*n+jj) == f(2*n+1)+2 for jj in [3,7,9,13]], ....: 2, f, n) - sage: T.transitions() + sage: T.transitions() # optional - sage.symbolic [Transition from (0, 0) to (0, 1): 0|-, Transition from (0, 0) to (1, 1): 1|-, Transition from (0, 1) to (0, 1): 0|-, @@ -1642,7 +1644,7 @@ def Recursion(self, recursions, base, function=None, var=None, Transition from (7, 3) to (2, 1): 1|1, Transition from (2, 1) to (1, 1): 0|1, Transition from (2, 1) to (2, 1): 1|-] - sage: for s in T.iter_states(): + sage: for s in T.iter_states(): # optional - sage.symbolic ....: print("{} {}".format(s, s.final_word_out)) (0, 0) [] (0, 1) [] @@ -1654,52 +1656,52 @@ def Recursion(self, recursions, base, function=None, var=None, (3, 3) [2, 2] (7, 3) [2, 2] (2, 1) [1, 2] - sage: list(sum(T(n.bits())) for n in srange(1, 21)) + sage: list(sum(T(n.bits())) for n in srange(1, 21)) # optional - sage.symbolic [2, 3, 4, 3, 4, 5, 4, 3, 4, 5, 6, 5, 4, 5, 4, 3, 4, 5, 6, 5] - We now demonstrate the use of the ``output_rings`` parameter. If no ``output_rings`` are specified, the output labels are converted into ``ZZ``:: - sage: function('f') + sage: function('f') # optional - sage.symbolic f - sage: var('n') + sage: var('n') # optional - sage.symbolic n - sage: T = transducers.Recursion([ + sage: T = transducers.Recursion([ # optional - sage.symbolic ....: f(2*n + 1) == f(n) + 1, ....: f(2*n) == f(n), ....: f(0) == 2], ....: 2, f, n) - sage: for t in T.transitions(): + sage: for t in T.transitions(): # optional - sage.symbolic ....: print([x.parent() for x in t.word_out]) [] [Integer Ring] - sage: [x.parent() for x in T.states()[0].final_word_out] + sage: [x.parent() for x in T.states()[0].final_word_out] # optional - sage.symbolic [Integer Ring] In contrast, if ``output_rings`` is set to the empty list, the results are not converted:: - sage: T = transducers.Recursion([ + sage: T = transducers.Recursion([ # optional - sage.symbolic ....: f(2*n + 1) == f(n) + 1, ....: f(2*n) == f(n), ....: f(0) == 2], ....: 2, f, n, output_rings=[]) - sage: for t in T.transitions(): + sage: for t in T.transitions(): # optional - sage.symbolic ....: print([x.parent() for x in t.word_out]) [] [Symbolic Ring] - sage: [x.parent() for x in T.states()[0].final_word_out] + sage: [x.parent() for x in T.states()[0].final_word_out] # optional - sage.symbolic [Symbolic Ring] Finally, we use a somewhat questionable conversion:: - sage: T = transducers.Recursion([ + sage: T = transducers.Recursion([ # optional - sage.rings.finite_rings sage.symbolic ....: f(2*n + 1) == f(n) + 1, ....: f(2*n) == f(n), ....: f(0) == 0], ....: 2, f, n, output_rings=[GF(5)]) - sage: for t in T.transitions(): + sage: for t in T.transitions(): # optional - sage.rings.finite_rings sage.symbolic ....: print([x.parent() for x in t.word_out]) [] [Finite Field of size 5] @@ -1726,11 +1728,11 @@ def Recursion(self, recursions, base, function=None, var=None, The following tests fail due to missing or superfluous recursions or initial conditions. :: - sage: var('n') + sage: var('n') # optional - sage.symbolic n - sage: function('f') + sage: function('f') # optional - sage.symbolic f - sage: transducers.Recursion([f(2*n) == f(n)], + sage: transducers.Recursion([f(2*n) == f(n)], # optional - sage.symbolic ....: 2, f, n) Traceback (most recent call last): ... @@ -1739,9 +1741,9 @@ def Recursion(self, recursions, base, function=None, var=None, :: - sage: transducers.Recursion([f(2*n + 1) == f(n), + sage: transducers.Recursion([f(2*n + 1) == f(n), # optional - sage.symbolic ....: f(4*n) == f(2*n) + 1, - ....: f(2*n) == f(n) +1], + ....: f(2*n) == f(n) + 1], ....: 2, f, n) Traceback (most recent call last): ... @@ -1749,7 +1751,7 @@ def Recursion(self, recursions, base, function=None, var=None, :: - sage: transducers.Recursion([f(2*n + 1) == f(n) + 1, + sage: transducers.Recursion([f(2*n + 1) == f(n) + 1, # optional - sage.symbolic ....: f(2*n) == f(n), ....: f(0) == 0, ....: f(42) == 42], 2, f, n) @@ -1759,7 +1761,7 @@ def Recursion(self, recursions, base, function=None, var=None, :: - sage: transducers.Recursion([f(2*n + 1) == f(n) + 1, + sage: transducers.Recursion([f(2*n + 1) == f(n) + 1, # optional - sage.symbolic ....: f(2*n) == f(n - 2) + 4, ....: f(0) == 0], 2, f, n) Traceback (most recent call last): @@ -1769,7 +1771,7 @@ def Recursion(self, recursions, base, function=None, var=None, Here is an example of a transducer with a conflicting rule (it cannot hold for `n = 0`):: - sage: T = transducers.Recursion([ + sage: T = transducers.Recursion([ # optional - sage.symbolic ....: f(2*n + 1) == f(n - 1), ....: f(2*n) == f(n) + 1, ....: f(1) == 1, @@ -1815,11 +1817,11 @@ def Recursion(self, recursions, base, function=None, var=None, for given_rule in rules: q, remainder = given_rule.r.quo_rem(base**given_rule.K) - rule=self.RecursionRule(K=given_rule.K, - r=remainder, - k=given_rule.k, - s=given_rule.s - base**given_rule.k*q, - t=given_rule.t) + rule = self.RecursionRule(K=given_rule.K, + r=remainder, + k=given_rule.k, + s=given_rule.s - base**given_rule.k * q, + t=given_rule.t) for m in range(max_K - rule.K + 1): for ell in range(base**m): R = rule.r + base**rule.K * ell @@ -1988,9 +1990,8 @@ def f(n): "Too many initial conditions, only give one of %s." % cycle[1:]) required_initial_values.update(intersection) - output_sum = sum([edge[2] - for edge in recursion_digraph.\ - outgoing_edge_iterator(cycle[1:])], + output_sum = sum([e[2] + for e in recursion_digraph.outgoing_edge_iterator(cycle[1:])], []) if not is_zero(output_sum): raise ValueError( diff --git a/src/sage/combinat/fqsym.py b/src/sage/combinat/fqsym.py index 14d39076494..03c53e6520b 100644 --- a/src/sage/combinat/fqsym.py +++ b/src/sage/combinat/fqsym.py @@ -1089,11 +1089,11 @@ def _M_to_F_on_basis(self, w): sage: M = FQSym.M() sage: F(M[3, 2, 1] - 4 * F[4, 2, 1, 3]) F[3, 2, 1] - 4*F[4, 2, 1, 3] - sage: all(F(M._M_to_F_on_basis(w)) == M[w] for i in range(5) + sage: all(F(M._M_to_F_on_basis(w)) == M[w] for i in range(5) # indirect doctest ....: for w in Permutations(i)) True sage: all(M(F(M[w])) == M[w] for i in range(5) - ....: for w in Permutations(i)) # indirect doctest + ....: for w in Permutations(i)) True sage: M[3, 2, 1] == F[3, 2, 1] True diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index c8269e5f96f..5c196c6cbf4 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -24,7 +24,10 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.categories.morphism import SetMorphism -from sage.categories.all import Category, Sets, ModulesWithBasis, GradedAlgebrasWithBasis +from sage.categories.category import Category +from sage.categories.sets_cat import Sets +from sage.categories.modules_with_basis import ModulesWithBasis +from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis from sage.categories.tensor import tensor import sage.data_structures.blas_dict as blas from sage.typeset.ascii_art import AsciiArt, ascii_art @@ -148,7 +151,7 @@ class CombinatorialFreeModule(UniqueRepresentation, Module, IndexedGenerators): The constructed module is in the category of modules with basis over the base ring:: - sage: CombinatorialFreeModule(QQ, Partitions()).category() + sage: CombinatorialFreeModule(QQ, Partitions()).category() # optional - sage.combinat Category of vector spaces with basis over Rational Field If furthermore the index set is finite (i.e. in the category @@ -157,7 +160,7 @@ class CombinatorialFreeModule(UniqueRepresentation, Module, IndexedGenerators): sage: CombinatorialFreeModule(QQ, [1,2,3,4]).category() Category of finite dimensional vector spaces with basis over Rational Field - sage: CombinatorialFreeModule(QQ, Partitions(3), + sage: CombinatorialFreeModule(QQ, Partitions(3), # optional - sage.combinat ....: category=Algebras(QQ).WithBasis()).category() Category of finite dimensional algebras with basis over Rational Field @@ -249,11 +252,11 @@ class CombinatorialFreeModule(UniqueRepresentation, Module, IndexedGenerators): TESTS:: - sage: XQ = SchubertPolynomialRing(QQ) - sage: XZ = SchubertPolynomialRing(ZZ) - sage: XQ == XZ + sage: XQ = SchubertPolynomialRing(QQ) # optional - sage.combinat + sage: XZ = SchubertPolynomialRing(ZZ) # optional - sage.combinat + sage: XQ == XZ # optional - sage.combinat False - sage: XQ == XQ + sage: XQ == XQ # optional - sage.combinat True We check that issue :trac:`28681` is fixed:: @@ -285,16 +288,16 @@ def __classcall_private__(cls, base_ring, basis_keys=None, category=None, We check that the category is properly straightened:: sage: F = CombinatorialFreeModule(QQ, ['a','b']) - sage: F1 = CombinatorialFreeModule(QQ, ['a','b'], category = ModulesWithBasis(QQ)) - sage: F2 = CombinatorialFreeModule(QQ, ['a','b'], category = [ModulesWithBasis(QQ)]) - sage: F3 = CombinatorialFreeModule(QQ, ['a','b'], category = (ModulesWithBasis(QQ),)) - sage: F4 = CombinatorialFreeModule(QQ, ['a','b'], category = (ModulesWithBasis(QQ),CommutativeAdditiveSemigroups())) - sage: F5 = CombinatorialFreeModule(QQ, ['a','b'], category = (ModulesWithBasis(QQ),Category.join((LeftModules(QQ), RightModules(QQ))))) + sage: F1 = CombinatorialFreeModule(QQ, ['a','b'], category=ModulesWithBasis(QQ)) + sage: F2 = CombinatorialFreeModule(QQ, ['a','b'], category=[ModulesWithBasis(QQ)]) + sage: F3 = CombinatorialFreeModule(QQ, ['a','b'], category=(ModulesWithBasis(QQ),)) + sage: F4 = CombinatorialFreeModule(QQ, ['a','b'], category=(ModulesWithBasis(QQ),CommutativeAdditiveSemigroups())) + sage: F5 = CombinatorialFreeModule(QQ, ['a','b'], category=(ModulesWithBasis(QQ),Category.join((LeftModules(QQ), RightModules(QQ))))) sage: F6 = CombinatorialFreeModule(QQ, ['a','b'], category=ModulesWithBasis(QQ).FiniteDimensional()) sage: F1 is F, F2 is F, F3 is F, F4 is F, F5 is F, F6 is F (True, True, True, True, True, True) - sage: G = CombinatorialFreeModule(QQ, ['a','b'], category = AlgebrasWithBasis(QQ)) + sage: G = CombinatorialFreeModule(QQ, ['a','b'], category=AlgebrasWithBasis(QQ)) sage: F is G False """ @@ -344,21 +347,21 @@ def element_class(self): EXAMPLES:: - sage: A = Algebras(QQ).WithBasis().example(); A + sage: A = Algebras(QQ).WithBasis().example(); A # optional - sage.combinat An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field - sage: A.element_class.mro() + sage: A.element_class.mro() # optional - sage.combinat [<class 'sage.categories.examples.algebras_with_basis.FreeAlgebra_with_category.element_class'>, <class 'sage.modules.with_basis.indexed_element.IndexedFreeModuleElement'>, ...] - sage: a,b,c = A.algebra_generators() - sage: a * b + sage: a,b,c = A.algebra_generators() # optional - sage.combinat + sage: a * b # optional - sage.combinat B[word: ab] TESTS:: - sage: A.__class__.element_class.__module__ + sage: A.__class__.element_class.__module__ # optional - sage.combinat 'sage.combinat.free_module' """ return self.__make_element_class__(self.Element, @@ -382,12 +385,13 @@ def __init__(self, R, basis_keys=None, element_class=None, category=None, sage: F.category() Category of finite dimensional algebras with basis over Rational Field - sage: F = CombinatorialFreeModule(GF(3), ['a','b','c'], - ....: category=(Modules(GF(3)).WithBasis(), Semigroups())) - sage: F.category() - Join of Category of finite semigroups and Category of finite dimensional vector spaces with basis over Finite Field of size 3 + sage: F = CombinatorialFreeModule(GF(3), ['a','b','c'], # optional - sage.rings.finite_rings + ....: category=(Modules(GF(3)).WithBasis(), Semigroups())) + sage: F.category() # optional - sage.rings.finite_rings + Join of Category of finite semigroups + and Category of finite dimensional vector spaces with basis over Finite Field of size 3 - sage: F = CombinatorialFreeModule(QQ, ['a','b','c'], category = FiniteDimensionalModulesWithBasis(QQ)) + sage: F = CombinatorialFreeModule(QQ, ['a','b','c'], category=FiniteDimensionalModulesWithBasis(QQ)) sage: F.basis() Finite family {'a': B['a'], 'b': B['b'], 'c': B['c']} sage: F.category() @@ -482,6 +486,29 @@ def construction(self): return VectorFunctor(None, True, None, with_basis='standard', basis_keys=self.basis().keys()), self.base_ring() + def change_ring(self, R): + r""" + Return the base change of ``self`` to `R`. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(ZZ, ['a','b','c']); F + Free module generated by {'a', 'b', 'c'} over Integer Ring + sage: F_QQ = F.change_ring(QQ); F_QQ + Free module generated by {'a', 'b', 'c'} over Rational Field + sage: F_QQ.change_ring(ZZ) == F + True + """ + if R is self.base_ring(): + return self + construction = self.construction() + if construction is not None: + functor, _ = construction + from sage.categories.pushout import VectorFunctor + if isinstance(functor, VectorFunctor): + return functor(R) + raise NotImplementedError('the method change_ring() has not yet been implemented') + # For backwards compatibility _repr_term = IndexedGenerators._repr_generator _latex_term = IndexedGenerators._latex_generator @@ -492,8 +519,8 @@ def _ascii_art_term(self, m): TESTS:: - sage: R = NonCommutativeSymmetricFunctions(QQ).R() - sage: ascii_art(R.one()) # indirect doctest + sage: R = NonCommutativeSymmetricFunctions(QQ).R() # optional - sage.combinat + sage: ascii_art(R.one()) # indirect doctest # optional - sage.combinat 1 """ try: @@ -509,8 +536,8 @@ def _unicode_art_term(self, m): TESTS:: - sage: R = NonCommutativeSymmetricFunctions(QQ).R() - sage: unicode_art(R.one()) # indirect doctest + sage: R = NonCommutativeSymmetricFunctions(QQ).R() # optional - sage.combinat + sage: unicode_art(R.one()) # indirect doctest # optional - sage.combinat 1 """ try: @@ -594,26 +621,26 @@ def _element_constructor_(self, x): EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ,["a", "b"]) + sage: F = CombinatorialFreeModule(QQ, ["a", "b"]) sage: F(F.monomial("a")) # indirect doctest B['a'] Do not rely on the following feature which may be removed in the future:: - sage: QS3 = SymmetricGroupAlgebra(QQ,3) - sage: QS3([2,3,1]) # indirect doctest + sage: QS3 = SymmetricGroupAlgebra(QQ,3) # optional - sage.combinat + sage: QS3([2,3,1]) # indirect doctest # optional - sage.combinat [2, 3, 1] instead, use:: - sage: P = QS3.basis().keys() - sage: QS3.monomial(P([2,3,1])) # indirect doctest + sage: P = QS3.basis().keys() # optional - sage.combinat + sage: QS3.monomial(P([2,3,1])) # indirect doctest # optional - sage.combinat [2, 3, 1] or:: - sage: B = QS3.basis() - sage: B[P([2,3,1])] + sage: B = QS3.basis() # optional - sage.combinat + sage: B[P([2,3,1])] # optional - sage.combinat [2, 3, 1] TODO: The symmetric group algebra (and in general, @@ -644,16 +671,19 @@ def _element_constructor_(self, x): are systematically defined (and mathematically meaningful) for algebras. - Conversions between distinct free modules are not allowed any - more:: + A coercion between free modules with the same indices exists + whenever a coercion map is defined between their base rings:: sage: F = CombinatorialFreeModule(ZZ, ["a", "b"]); F.rename("F") sage: G = CombinatorialFreeModule(QQ, ["a", "b"]); G.rename("G") - sage: H = CombinatorialFreeModule(ZZ, ["a", "b", "c"]); H.rename("H") sage: G(F.monomial("a")) - Traceback (most recent call last): - ... - TypeError: do not know how to make x (= B['a']) an element of self (=G) + B['a'] + sage: G(-3*F.monomial("a")) + -3*B['a'] + + Otherwise, there is no conversion between distinct free modules:: + + sage: H = CombinatorialFreeModule(ZZ, ["a", "b", "c"]); H.rename("H") sage: H(F.monomial("a")) Traceback (most recent call last): ... @@ -662,31 +692,32 @@ def _element_constructor_(self, x): Here is a real life example illustrating that this yielded mathematically wrong results:: - sage: S = SymmetricFunctions(QQ) - sage: s = S.s(); p = S.p() - sage: ss = tensor([s,s]); pp = tensor([p,p]) - sage: a = tensor((s[2],s[2])) + sage: S = SymmetricFunctions(QQ) # optional - sage.combinat + sage: s = S.s(); p = S.p() # optional - sage.combinat + sage: ss = tensor([s,s]); pp = tensor([p,p]) # optional - sage.combinat + sage: a = tensor((s[2],s[2])) # optional - sage.combinat The following originally used to yield ``p[[2]] # p[[2]]``, and if there was no natural coercion between ``s`` and ``p``, this would raise a ``NotImplementedError``. Since :trac:`15305`, this takes the coercion between ``s`` and ``p`` and lifts it to the tensor product. :: - sage: pp(a) + sage: pp(a) # optional - sage.combinat 1/4*p[1, 1] # p[1, 1] + 1/4*p[1, 1] # p[2] + 1/4*p[2] # p[1, 1] + 1/4*p[2] # p[2] - Extensions of the ground ring should probably be reintroduced + General extensions of the ground ring should probably be reintroduced at some point, but via coercions, and with stronger sanity checks (ensuring that the codomain is really obtained by extending the scalar of the domain; checking that they share the same class is not sufficient). + TESTS: Conversion from the ground ring is implemented for algebras:: - sage: QS3 = SymmetricGroupAlgebra(QQ,3) - sage: QS3(2) + sage: QS3 = SymmetricGroupAlgebra(QQ,3) # optional - sage.combinat + sage: QS3(2) # optional - sage.combinat 2*[1, 2, 3] """ R = self.base_ring() @@ -767,8 +798,8 @@ def _first_ngens(self, n): sage: C._first_ngens(3) (B[0], B[1], B[-1]) - sage: R.<x,y> = FreeAlgebra(QQ, 2) - sage: x,y + sage: R.<x,y> = FreeAlgebra(QQ, 2) # optional - sage.combinat + sage: x,y # optional - sage.combinat (x, y) """ try: @@ -781,6 +812,49 @@ def _first_ngens(self, n): it = iter(self._indices) return tuple(B[next(it)] for i in range(n)) + def _coerce_map_from_(self, R): + """ + Return ``True`` if there is a coercion map from ``R`` into ``self``. + + There exists a coercion map from: + + - a free module whose base ring coerces into the base ring of + ``self``, and which has the same indices as ``self`` + + EXAMPLES:: + + sage: C = CombinatorialFreeModule(ZZ, Set([1,2])) + sage: CQ = CombinatorialFreeModule(QQ, Set([1,2])) + sage: CQ.has_coerce_map_from(C) + True + sage: c = C.monomial(2) + sage: cq = CQ(c); cq + B[2] + sage: cq.leading_coefficient().parent() + Rational Field + sage: C.has_coerce_map_from(CQ) + False + + sage: CF2 = CombinatorialFreeModule(GF(2), Set([1,2])) # optional - sage.rings.finite_rings + sage: CF2.has_coerce_map_from(C) # optional - sage.rings.finite_rings + True + sage: c = C.monomial(1) # optional - sage.rings.finite_rings + sage: CF2(2*c) # optional - sage.rings.finite_rings + 0 + sage: CF2(3*c) # optional - sage.rings.finite_rings + B[1] + """ + if isinstance(R, CombinatorialFreeModule): + try: + CR = R.base_extend(self.base_ring()) + except (NotImplementedError, TypeError): + pass + else: + if CR == self: + return lambda parent, x: self._from_dict(x._monomial_coefficients, + coerce=True, remove_zeros=True) + return super()._coerce_map_from_(R) + def dimension(self): """ Return the dimension of the free module (which is given @@ -803,8 +877,8 @@ def dimension(self): :: - sage: s = SymmetricFunctions(QQ).schur() - sage: s.dimension() + sage: s = SymmetricFunctions(QQ).schur() # optional - sage.combinat + sage: s.dimension() # optional - sage.combinat +Infinity """ return self._indices.cardinality() @@ -819,11 +893,11 @@ def is_exact(self): EXAMPLES:: - sage: GroupAlgebra(GL(3, GF(7))).is_exact() + sage: GroupAlgebra(GL(3, GF(7))).is_exact() # optional - sage.groups sage.rings.finite_rings True - sage: GroupAlgebra(GL(3, GF(7)), RR).is_exact() + sage: GroupAlgebra(GL(3, GF(7)), RR).is_exact() # optional - sage.groups sage.rings.finite_rings False - sage: GroupAlgebra(GL(3, pAdicRing(7))).is_exact() # not implemented correctly (not my fault)! + sage: GroupAlgebra(GL(3, pAdicRing(7))).is_exact() # not implemented correctly (not my fault)! # optional - sage.groups sage.rings.padics False """ # The index set may not have a check for exactness @@ -853,11 +927,11 @@ def set_order(self, order): EXAMPLES:: - sage: QS2 = SymmetricGroupAlgebra(QQ,2) - sage: b = list(QS2.basis().keys()) - sage: b.reverse() - sage: QS2.set_order(b) - sage: QS2.get_order() + sage: QS2 = SymmetricGroupAlgebra(QQ,2) # optional - sage.combinat + sage: b = list(QS2.basis().keys()) # optional - sage.combinat + sage: b.reverse() # optional - sage.combinat + sage: QS2.set_order(b) # optional - sage.combinat + sage: QS2.get_order() # optional - sage.combinat [[2, 1], [1, 2]] """ self._order = order @@ -871,8 +945,8 @@ def get_order(self): EXAMPLES:: - sage: QS2 = SymmetricGroupAlgebra(QQ,2) - sage: QS2.get_order() # note: order changed on 2009-03-13 + sage: QS2 = SymmetricGroupAlgebra(QQ,2) # optional - sage.combinat + sage: QS2.get_order() # note: order changed on 2009-03-13 # optional - sage.combinat [[2, 1], [1, 2]] """ if self._order is None: @@ -928,11 +1002,11 @@ def from_vector(self, vector, order=None, coerce=True): EXAMPLES:: - sage: QS3 = SymmetricGroupAlgebra(QQ, 3) - sage: b = QS3.from_vector(vector((2, 0, 0, 0, 0, 4))); b + sage: QS3 = SymmetricGroupAlgebra(QQ, 3) # optional - sage.combinat + sage: b = QS3.from_vector(vector((2, 0, 0, 0, 0, 4))); b # optional - sage.combinat 2*[1, 2, 3] + 4*[3, 2, 1] - sage: a = 2*QS3([1,2,3])+4*QS3([3,2,1]) - sage: a == b + sage: a = 2*QS3([1,2,3]) + 4*QS3([3,2,1]) # optional - sage.combinat + sage: a == b # optional - sage.combinat True """ if order is None: @@ -984,7 +1058,7 @@ def linear_combination(self, iter_of_elements_coeff, factor_on_left=True): EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ,[1,2]) + sage: F = CombinatorialFreeModule(QQ, [1,2]) sage: f = F.an_element(); f 2*B[1] + 2*B[2] sage: F.linear_combination( (f,i) for i in range(5) ) @@ -1059,8 +1133,8 @@ def _sum_of_monomials(self, indices): sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) sage: F._sum_of_monomials(['a', 'b', 'b']) B['a'] + 2*B['b'] - sage: F = CombinatorialFreeModule(GF(3), ['a', 'b', 'c']) - sage: F._sum_of_monomials(['a', 'b', 'b', 'b']) + sage: F = CombinatorialFreeModule(GF(3), ['a', 'b', 'c']) # optional - sage.rings.finite_rings + sage: F._sum_of_monomials(['a', 'b', 'b', 'b']) # optional - sage.rings.finite_rings B['a'] """ R = self.base_ring() @@ -1135,26 +1209,26 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): EXAMPLES:: - sage: e = SymmetricFunctions(QQ).elementary() - sage: s = SymmetricFunctions(QQ).schur() - sage: a = e([2,1]) + e([1,1,1]); a + sage: e = SymmetricFunctions(QQ).elementary() # optional - sage.combinat + sage: s = SymmetricFunctions(QQ).schur() # optional - sage.combinat + sage: a = e([2,1]) + e([1,1,1]); a # optional - sage.combinat e[1, 1, 1] + e[2, 1] - sage: s._from_dict(a.monomial_coefficients()) + sage: s._from_dict(a.monomial_coefficients()) # optional - sage.combinat s[1, 1, 1] + s[2, 1] If the optional argument ``coerce`` is ``True``, then the coefficients are coerced into the base ring of ``self``:: - sage: part = Partition([2,1]) - sage: d = {part:1} - sage: a = s._from_dict(d,coerce=True); a + sage: part = Partition([2,1]) # optional - sage.combinat + sage: d = {part: 1} # optional - sage.combinat + sage: a = s._from_dict(d, coerce=True); a # optional - sage.combinat s[2, 1] - sage: a.coefficient(part).parent() + sage: a.coefficient(part).parent() # optional - sage.combinat Rational Field With ``remove_zeros=True``, zero coefficients are removed:: - sage: s._from_dict({part:0}) + sage: s._from_dict({part: 0}) # optional - sage.combinat 0 .. WARNING:: @@ -1163,7 +1237,7 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): coefficient of the dictionary is zero. Otherwise, this may lead to illegal results:: - sage: list(s._from_dict({part:0}, remove_zeros=False)) + sage: list(s._from_dict({part: 0}, remove_zeros=False)) # optional - sage.combinat [([2, 1], 0)] """ assert isinstance(d, dict) @@ -1189,7 +1263,8 @@ class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): F # G sage: T.category() - Category of tensor products of finite dimensional modules with basis over Integer Ring + Category of tensor products of + finite dimensional modules with basis over Integer Ring sage: T.construction() # todo: not implemented [tensor, ] @@ -1202,7 +1277,8 @@ class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): The basis of T is indexed by tuples of basis indices of F and G:: sage: T.basis().keys() - Image of Cartesian product of {1, 2}, {3, 4} by The map <class 'tuple'> from Cartesian product of {1, 2}, {3, 4} + Image of Cartesian product of {1, 2}, {3, 4} + by The map <class 'tuple'> from Cartesian product of {1, 2}, {3, 4} sage: T.basis().keys().list() [(1, 3), (1, 4), (2, 3), (2, 4)] @@ -1351,9 +1427,9 @@ def _ascii_art_(self, term): """ TESTS:: - sage: R = NonCommutativeSymmetricFunctions(QQ).R() - sage: Partitions.options(diagram_str="#", convention="french") - sage: s = ascii_art(tensor((R[1,2], R[3,1,2]))); s + sage: R = NonCommutativeSymmetricFunctions(QQ).R() # optional - sage.combinat + sage: Partitions.options(diagram_str="#", convention="french") # optional - sage.combinat + sage: s = ascii_art(tensor((R[1,2], R[3,1,2]))); s # optional - sage.combinat R # R # ### ## # @@ -1361,7 +1437,7 @@ def _ascii_art_(self, term): Check that the breakpoints are correct (:trac:`29202`):: - sage: s._breakpoints + sage: s._breakpoints # optional - sage.combinat [6] """ if hasattr(self, "_print_options"): @@ -1380,9 +1456,9 @@ def _unicode_art_(self, term): """ TESTS:: - sage: R = NonCommutativeSymmetricFunctions(QQ).R() - sage: Partitions.options(diagram_str="#", convention="french") - sage: s = unicode_art(tensor((R[1,2], R[3,1,2]))); s + sage: R = NonCommutativeSymmetricFunctions(QQ).R() # optional - sage.combinat + sage: Partitions.options(diagram_str="#", convention="french") # optional - sage.combinat + sage: s = unicode_art(tensor((R[1,2], R[3,1,2]))); s # optional - sage.combinat R โŠ— R โ”Œโ” โ”Œโ”ฌโ”ฌโ” โ”œโ”ผโ” โ””โ”ดโ”ผโ”ค @@ -1391,7 +1467,7 @@ def _unicode_art_(self, term): Check that the breakpoints are correct (:trac:`29202`):: - sage: s._breakpoints + sage: s._breakpoints # optional - sage.combinat [7] """ if hasattr(self, "_print_options"): @@ -1475,22 +1551,26 @@ def tensor_constructor(self, modules): sage: G = CombinatorialFreeModule(ZZ, [3,4]); G.rename("G") sage: H = CombinatorialFreeModule(ZZ, [5,6]); H.rename("H") - sage: f = F.monomial(1) + 2 * F.monomial(2) - sage: g = 2*G.monomial(3) + G.monomial(4) - sage: h = H.monomial(5) + H.monomial(6) - sage: FG = tensor([F, G ]) + sage: f = F.monomial(1) + 2*F.monomial(2) + sage: g = 2*G.monomial(3) + G.monomial(4) + sage: h = H.monomial(5) + H.monomial(6) + sage: FG = tensor([F, G]) sage: phi_fg = FG.tensor_constructor((F, G)) - sage: phi_fg(f,g) + sage: phi_fg(f, g) 2*B[1] # B[3] + B[1] # B[4] + 4*B[2] # B[3] + 2*B[2] # B[4] sage: FGH = tensor([F, G, H]) sage: phi_fgh = FGH.tensor_constructor((F, G, H)) sage: phi_fgh(f, g, h) - 2*B[1] # B[3] # B[5] + 2*B[1] # B[3] # B[6] + B[1] # B[4] # B[5] + B[1] # B[4] # B[6] + 4*B[2] # B[3] # B[5] + 4*B[2] # B[3] # B[6] + 2*B[2] # B[4] # B[5] + 2*B[2] # B[4] # B[6] + 2*B[1] # B[3] # B[5] + 2*B[1] # B[3] # B[6] + B[1] # B[4] # B[5] + + B[1] # B[4] # B[6] + 4*B[2] # B[3] # B[5] + 4*B[2] # B[3] # B[6] + + 2*B[2] # B[4] # B[5] + 2*B[2] # B[4] # B[6] sage: phi_fg_h = FGH.tensor_constructor((FG, H)) sage: phi_fg_h(phi_fg(f, g), h) - 2*B[1] # B[3] # B[5] + 2*B[1] # B[3] # B[6] + B[1] # B[4] # B[5] + B[1] # B[4] # B[6] + 4*B[2] # B[3] # B[5] + 4*B[2] # B[3] # B[6] + 2*B[2] # B[4] # B[5] + 2*B[2] # B[4] # B[6] + 2*B[1] # B[3] # B[5] + 2*B[1] # B[3] # B[6] + B[1] # B[4] # B[5] + + B[1] # B[4] # B[6] + 4*B[2] # B[3] # B[5] + 4*B[2] # B[3] # B[6] + + 2*B[2] # B[4] # B[5] + 2*B[2] # B[4] # B[6] """ assert(module in ModulesWithBasis(self.base_ring()) for module in modules) assert(tensor(modules) == self) @@ -1654,7 +1734,9 @@ class CombinatorialFreeModule_CartesianProduct(CombinatorialFreeModule): sage: S F (+) G sage: S.basis() - Lazy family (Term map from Disjoint union of Family ({4, 5}, {4, 6}) to F (+) G(i))_{i in Disjoint union of Family ({4, 5}, {4, 6})} + Lazy family (Term map + from Disjoint union of Family ({4, 5}, {4, 6}) + to F (+) G(i))_{i in Disjoint union of Family ({4, 5}, {4, 6})} Note that the indices of the basis elements of F and G intersect non trivially. This is handled by forcing the union to be disjoint:: @@ -1664,19 +1746,19 @@ class CombinatorialFreeModule_CartesianProduct(CombinatorialFreeModule): We now compute the Cartesian product of elements of free modules:: - sage: f = F.monomial(4) + 2 * F.monomial(5) - sage: g = 2*G.monomial(4) + G.monomial(6) - sage: h = H.monomial(4) + H.monomial(7) - sage: cartesian_product([f,g]) + sage: f = F.monomial(4) + 2*F.monomial(5) + sage: g = 2*G.monomial(4) + G.monomial(6) + sage: h = H.monomial(4) + H.monomial(7) + sage: cartesian_product([f, g]) B[(0, 4)] + 2*B[(0, 5)] + 2*B[(1, 4)] + B[(1, 6)] - sage: cartesian_product([f,g,h]) + sage: cartesian_product([f, g, h]) B[(0, 4)] + 2*B[(0, 5)] + 2*B[(1, 4)] + B[(1, 6)] + B[(2, 4)] + B[(2, 7)] - sage: cartesian_product([f,g,h]).parent() + sage: cartesian_product([f, g, h]).parent() F (+) G (+) H TODO: choose an appropriate semantic for Cartesian products of Cartesian products (associativity?):: - sage: S = cartesian_product([cartesian_product([F, G]), H]) # todo: not implemented + sage: S = cartesian_product([cartesian_product([F, G]), H]) # todo: not implemented F (+) G (+) H """ @@ -1808,8 +1890,8 @@ def _cartesian_product_of_elements(self, elements): sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename("F") sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename("G") sage: S = cartesian_product([F, G]) - sage: f = F.monomial(4) + 2 * F.monomial(5) - sage: g = 2*G.monomial(4) + G.monomial(6) + sage: f = F.monomial(4) + 2*F.monomial(5) + sage: g = 2*G.monomial(4) + G.monomial(6) sage: S._cartesian_product_of_elements([f, g]) B[(0, 4)] + 2*B[(0, 5)] + 2*B[(1, 4)] + B[(1, 6)] sage: S._cartesian_product_of_elements([f, g]).parent() == S diff --git a/src/sage/combinat/fully_commutative_elements.py b/src/sage/combinat/fully_commutative_elements.py index bb46692a8b7..79237fefe42 100644 --- a/src/sage/combinat/fully_commutative_elements.py +++ b/src/sage/combinat/fully_commutative_elements.py @@ -153,44 +153,23 @@ def is_fully_commutative(self): sage: x = FC.element_class(FC, [1, 2, 1], check=False); x.is_fully_commutative() False """ - matrix = self.parent().coxeter_group().coxeter_matrix() - w = tuple(self) - - # The following function detects 'braid' words. - def contains_long_braid(w): - for i in range(len(w) - 2): - a = w[i] - b = w[i + 1] - m = matrix[a, b] - if m > 2 and i + m <= len(w): - ab_braid = (a, b) * (m // 2) + ((a,) if m % 2 else ()) - if w[i:i + m] == ab_braid: - return True - return False + word = list(self) + from sage.combinat.root_system.braid_orbit import is_fully_commutative as is_fully_comm - # The following function applies a commutation relation on a word. - def commute_once(word, i): - return word[:i] + (word[i + 1], word[i]) + word[i + 2:] + group = self.parent().coxeter_group() + braid_rels = group.braid_relations() + I = group.index_set() - # A word is the reduced word of an FC element iff no sequence of - # commutation relations on it yields a word with a 'braid' word: - if contains_long_braid(w): - return False - else: - l, checked, queue = len(w), {w}, deque([w]) - while queue: - word = queue.pop() - for i in range(l - 1): - a, b = word[i], word[i + 1] - if matrix[a, b] == 2: - new_word = commute_once(word, i) - if new_word not in checked: - if contains_long_braid(new_word): - return False - else: - checked.add(new_word) - queue.appendleft(new_word) - return True + from sage.rings.integer_ring import ZZ + be_careful = any(i not in ZZ for i in I) + + if be_careful: + Iinv = {i: j for j, i in enumerate(I)} + word = [Iinv[i] for i in word] + braid_rels = [[[Iinv[i] for i in l], + [Iinv[i] for i in r]] for l, r in braid_rels] + + return is_fully_comm(word, braid_rels) # Representing FC elements: Heaps def heap(self, **kargs): @@ -268,7 +247,7 @@ def plot_heap(self): EXAMPLES:: sage: FC = CoxeterGroup(['B', 5]).fully_commutative_elements() - sage: FC([3,2,4,3,1]).plot_heap() + sage: FC([3,2,4,3,1]).plot_heap() # optional - sage.plot Graphics object consisting of 15 graphics primitives .. PLOT:: @@ -628,13 +607,13 @@ def _still_reduced_fc_after_prepending(self, s): # Find the first letter in that doesn't commute with s. try: - (j, t) = next((i, x) for (i, x) in enumerate(self) if m[s, x] >= 3) + j, t = next((i, x) for i, x in enumerate(self) if m[s, x] >= 3) except StopIteration: return True u = self.clone() u._set_list(self[j:]) - x, y = u.coset_decomposition({s, t}) + x, _ = u.coset_decomposition({s, t}) return len(x) != m[s, t] - 1 ########################################################################### diff --git a/src/sage/combinat/fully_packed_loop.py b/src/sage/combinat/fully_packed_loop.py index b24d6e19ce1..de1bf3e5269 100644 --- a/src/sage/combinat/fully_packed_loop.py +++ b/src/sage/combinat/fully_packed_loop.py @@ -38,7 +38,7 @@ from sage.misc.decorators import options from sage.matrix.constructor import matrix -from sage.arith.all import factorial +from sage.arith.misc import factorial from sage.rings.integer import Integer from sage.misc.misc_c import prod @@ -49,19 +49,19 @@ D = (0, -1) FPL_edges = ( -# 0 UD 1 RD, 2 UR, 3 LR, 4 LD 5 LU - ((D,U), (L,D), (D,R), (R,L), (L,U), (R,U)), # even - ((R,L), (R,U), (L,U), (D,U), (D,R), (L,D)) # odd - ) + # 0 UD 1 RD, 2 UR, 3 LR, 4 LD 5 LU + ((D, U), (L, D), (D, R), (R, L), (L, U), (R, U)), # even + ((R, L), (R, U), (L, U), (D, U), (D, R), (L, D)) # odd +) FPL_turns = ( -# 0 UD 1 RD 2 UR 3 LR 4 LD 5 LU - ({U: U, D: D}, {R: D, U: L}, {U: R, L: D}, {L: L, R: R}, {R: U, D: L}, {L: U, D: R}), # even - ({L: L, R: R}, {L: U, D: R}, {R: U, D: L}, {U: U, D: D}, {U: R, L: D}, {R: D, U: L}) # odd - ) + # 0 UD 1 RD 2 UR 3 LR 4 LD 5 LU + ({U: U, D: D}, {R: D, U: L}, {U: R, L: D}, {L: L, R: R}, {R: U, D: L}, {L: U, D: R}), # even + ({L: L, R: R}, {L: U, D: R}, {R: U, D: L}, {U: U, D: D}, {U: R, L: D}, {R: D, U: L}) # odd +) -def _make_color_list(n, colors=None, color_map=None, randomize=False): +def _make_color_list(n, colors=None, color_map=None, randomize=False): r""" TESTS:: @@ -157,7 +157,7 @@ class FullyPackedLoop(Element, metaclass=InheritComparisonClasscallMetaclass): The class also has a plot method:: - sage: fpl.plot() + sage: fpl.plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives which gives: @@ -468,7 +468,7 @@ class FullyPackedLoop(Element, metaclass=InheritComparisonClasscallMetaclass): sage: fpl = FullyPackedLoop((1, 2, 3)) Traceback (most recent call last): ... - ValueError: The alternating sign matrices must be square + ValueError: the alternating sign matrices must be square sage: SVM = SixVertexModel(3)[0] sage: FullyPackedLoop(SVM) @@ -530,7 +530,7 @@ def __classcall_private__(cls, generator): M = generator.to_alternating_sign_matrix().to_matrix() AlternatingSignMatrix(M) SVM = generator - else: # Not ASM nor SVM + else: # Not ASM nor SVM try: SVM = AlternatingSignMatrix(generator).to_six_vertex_model() except (TypeError, ValueError): @@ -608,22 +608,22 @@ def _repr_(self): # List are in the order of URDL # One set of rules for how to draw around even vertex, one set of rules for odd vertex n = len(self._six_vertex_model) - 1 - ascii1 = [[r' ', ' -', r' ', '- '], # LR - [r' | ', ' ', r' ', '- '], # LU - [r' ', ' ', r' | ', '- '], # LD - [r' | ', ' ', r' | ', ' '], # UD - [r' | ', ' -', r' ', ' '], # UR - [r' ', ' -', r' | ', ' ']] # RD - - ascii2 = [[r' | ', ' ', r' | ', ' '], # LR - [r' ', ' -', r' | ', ' '], # LU - [r' | ', ' -', r' ', ' '], # LD - [r' ', ' -', r' ', '- '], # UD - [r' ', ' ', r' | ', '- '], # UR - [r' | ', ' ', r' ', '- ']] # RD + ascii1 = [[r' ', ' -', r' ', '- '], # LR + [r' | ', ' ', r' ', '- '], # LU + [r' ', ' ', r' | ', '- '], # LD + [r' | ', ' ', r' | ', ' '], # UD + [r' | ', ' -', r' ', ' '], # UR + [r' ', ' -', r' | ', ' ']] # RD + + ascii2 = [[r' | ', ' ', r' | ', ' '], # LR + [r' ', ' -', r' | ', ' '], # LU + [r' | ', ' -', r' ', ' '], # LD + [r' ', ' -', r' ', '- '], # UD + [r' ', ' ', r' | ', '- '], # UR + [r' | ', ' ', r' ', '- ']] # RD ret = ' ' # Do the top line - for i,entry in enumerate(self._six_vertex_model[0]): + for i, entry in enumerate(self._six_vertex_model[0]): if i % 2 == 0: ret += ' | ' else: @@ -632,10 +632,10 @@ def _repr_(self): plus_sign = '+' # Do the meat of the ascii art - for j,row in enumerate(self._six_vertex_model): + for j, row in enumerate(self._six_vertex_model): ret += '\n ' # Do the top row - for i,entry in enumerate(row): + for i, entry in enumerate(row): if (i + j) % 2 == 0: ret += ascii1[entry][0] else: @@ -643,36 +643,36 @@ def _repr_(self): ret += '\n' # Do the left-most entry - if (j) % 2 == 0: + if j % 2 == 0: ret += ' ' else: ret += ' -' # Do the middle row - for i,entry in enumerate(row): + for i, entry in enumerate(row): if (i + j) % 2 == 0: ret += ascii1[entry][3] + plus_sign + ascii1[entry][1] else: ret += ascii2[entry][3] + plus_sign + ascii2[entry][1] # Do the right-most entry - if (j+n) % 2 ==0: + if (j+n) % 2 == 0: ret += ' ' else: ret += '- ' # Do the bottom row ret += '\n ' - for i,entry in enumerate(row): - if (i + j) % 2 ==0: + for i, entry in enumerate(row): + if (i + j) % 2 == 0: ret += ascii1[entry][2] else: ret += ascii2[entry][2] # Do the bottom line ret += '\n ' - for i,entry in enumerate(self._six_vertex_model[-1]): - if (i+n+1) % 2 ==0: + for i, entry in enumerate(self._six_vertex_model[-1]): + if (i+n+1) % 2 == 0: ret += ' ' else: ret += ' | ' @@ -781,7 +781,7 @@ def plot(self, **options): sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]]) sage: fpl = FullyPackedLoop(A) - sage: fpl.plot() + sage: fpl.plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives The resulting graphics is as follows @@ -798,7 +798,7 @@ def plot(self, **options): sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]]) sage: fpl = FullyPackedLoop(A) - sage: fpl.plot(link_color_map='rainbow') + sage: fpl.plot(link_color_map='rainbow') # optional - sage.plot Graphics object consisting of 3 graphics primitives .. PLOT:: @@ -811,8 +811,9 @@ def plot(self, **options): You can plot the 42 fully packed loops of size `4 \times 4` using:: - sage: G = [fpl.plot(link_color_map='winter', loop_color='black') for fpl in FullyPackedLoops(4)] - sage: graphics_array(G, 7, 6) + sage: G = [fpl.plot(link_color_map='winter', loop_color='black') # optional - sage.plot + ....: for fpl in FullyPackedLoops(4)] + sage: graphics_array(G, 7, 6) # optional - sage.plot Graphics Array of size 7 x 6 .. PLOT:: @@ -833,7 +834,7 @@ def plot(self, **options): ....: 00000000+-0000+00000000000000+0000000000" sage: a = matrix(20, [{'0':0, '+':1, '-': -1}[i] for i in s]) sage: fpl = FullyPackedLoop(a) - sage: fpl.plot(loop_fill=True, loop_color_map='rainbow') + sage: fpl.plot(loop_fill=True, loop_color_map='rainbow') # optional - sage.plot Graphics object consisting of 27 graphics primitives .. PLOT:: @@ -878,12 +879,12 @@ def plot(self, **options): unrank = self.parent()._boundary seen = [False] * (2*n) - squares = set((i,j) for i in range(n) for j in range(n)) + squares = set((i, j) for i in range(n) for j in range(n)) colors = _make_color_list(2*n, - colors = link_options.pop('colors', None), - color_map = link_options.pop('color_map', None), - randomize = link_options.pop('color_randomize', False)) + colors=link_options.pop('colors', None), + color_map=link_options.pop('color_map', None), + randomize=link_options.pop('color_randomize', False)) G = Graphics() for i in range(2*n): @@ -910,9 +911,9 @@ def plot(self, **options): if loop: colors = _make_color_list(len(loops), - colors = loop_options.pop('colors', None), - color_map = loop_options.pop('color_map', None), - randomize = loop_options.pop('color_randomize', False)) + colors=loop_options.pop('colors', None), + color_map=loop_options.pop('color_map', None), + randomize=loop_options.pop('color_randomize', False)) fill = loop_options.pop('fill') @@ -921,7 +922,7 @@ def plot(self, **options): loop_options['color'] = colors.pop() # make it upside down - orbit = [(j, n - i - 1) for i,j in orbit] + orbit = [(j, n - i - 1) for i, j in orbit] if fill: G += polygon2d(orbit, **loop_options) @@ -1024,13 +1025,13 @@ def _link_or_loop_from(self, pos, d0=None): raise RuntimeError if i == -1 or j == -1 or i == n or j == n: - i0,j0 = orbit[0] + i0, j0 = orbit[0] if d0 is None and i0 != -1 and i0 != n and j0 != -1 and j0 != n: # only half of a link -> compute the other half - i1,j1 = orbit[1] + i1, j1 = orbit[1] d = (i0-i1, j0-j1) orbit2 = self._link_or_loop_from(orbit[1], d) - assert orbit2[0] == (i1,j1) and orbit2[1] == (i0,j0) + assert orbit2[0] == (i1, j1) and orbit2[1] == (i0, j0) return orbit2[:1:-1] + orbit return orbit else: @@ -1155,7 +1156,7 @@ def link_pattern(self): if seen[k]: continue - i,j = unrank(k) + i, j = unrank(k) # initial direction if i == -1: @@ -1179,7 +1180,7 @@ def link_pattern(self): d = FPL_turns[parity][conf][d] # update seen and link_pattern - l = rank((i,j)) + l = rank((i, j)) seen[k] = seen[l] = True link_pattern.append((k+1, l+1)) @@ -1293,7 +1294,7 @@ def _repr_(self): sage: FPLs = FullyPackedLoops(4); FPLs Fully packed loops on a 4x4 grid """ - return "Fully packed loops on a %sx%s grid" % (self._n,self._n) + return "Fully packed loops on a %sx%s grid" % (self._n, self._n) def __contains__(self, fpl): """ @@ -1367,7 +1368,7 @@ def _element_constructor_(self, generator): if isinstance(generator, AlternatingSignMatrix): SVM = generator.to_six_vertex_model() elif isinstance(generator, SquareIceModel.Element) or \ - isinstance(generator, SixVertexConfiguration): + isinstance(generator, SixVertexConfiguration): SVM = generator else: # Not ASM nor SVM try: @@ -1406,11 +1407,11 @@ def cardinality(self): EXAMPLES:: - sage: [AlternatingSignMatrices(n).cardinality() for n in range(11)] - [1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700] + sage: [AlternatingSignMatrices(n).cardinality() for n in range(10)] + [1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460] """ - return Integer(prod( [ factorial(3*k+1)/factorial(self._n+k) - for k in range(self._n)] )) + return Integer(prod(factorial(3 * k + 1) / factorial(self._n + k) + for k in range(self._n))) def _an_element_(self): """ @@ -1432,9 +1433,9 @@ def _an_element_(self): | | | | """ - #ASM = AlternatingSignMatrix(matrix.identity(self._n)) - #SVM = ASM.to_six_vertex_model() - SVM = SixVertexModel(self._n,boundary_conditions='ice').an_element() + # ASM = AlternatingSignMatrix(matrix.identity(self._n)) + # SVM = ASM.to_six_vertex_model() + SVM = SixVertexModel(self._n, boundary_conditions='ice').an_element() return self.element_class(self, SVM) def _boundary(self, k): @@ -1456,19 +1457,19 @@ def _boundary(self, k): True """ n = self._n - n_LR = n//2 if n%2 == 0 else (n+1) // 2 - n_TB = n//2 if n%2 == 0 else (n-1) // 2 + n_LR = n//2 if n % 2 == 0 else (n+1) // 2 + n_TB = n//2 if n % 2 == 0 else (n-1) // 2 if k < n_LR: return (-1, 2*k) k -= n_LR if k < n_TB: - return (n%2 + 2*k, n) + return (n % 2 + 2*k, n) k -= n_TB if k < n_LR: return (n, n - 1 - 2*k) k -= n_LR if k < n_TB: - return (n - 1 - n%2 - 2*k, -1) + return (n - 1 - n % 2 - 2*k, -1) def _boundary_index(self, pos): r""" diff --git a/src/sage/combinat/gelfand_tsetlin_patterns.py b/src/sage/combinat/gelfand_tsetlin_patterns.py index eda712ded06..676c1685484 100644 --- a/src/sage/combinat/gelfand_tsetlin_patterns.py +++ b/src/sage/combinat/gelfand_tsetlin_patterns.py @@ -53,7 +53,7 @@ class GelfandTsetlinPattern(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): + metaclass=InheritComparisonClasscallMetaclass): r""" A Gelfand-Tsetlin (sometimes written as Gelfand-Zetlin or Gelfand-Cetlin) pattern. They were originally defined in [GC50]_. @@ -197,7 +197,7 @@ def _repr_diagram(self) -> str: for i, row in enumerate(self): if i != 0: ret += '\n' - ret += ' '*i + ret += ' ' * i ret += ' '.join('%3s' % val for val in row) return ret @@ -234,13 +234,13 @@ def _latex_(self) -> str: n = len(self) if n == 0: return "\\emptyset" - ret = "\\begin{array}{" + 'c'*(n*2-1) + "}\n" + ret = "\\begin{array}{" + 'c' * (n * 2 - 1) + "}\n" for i, row in enumerate(self): if i > 0: ret += " \\\\\n" - ret += "& "*i + ret += "& " * i ret += " & & ".join(repr(val) for val in row) - ret += " &"*i + ret += " &" * i return ret + "\n\\end{array}" @combinatorial_map(name='to semistandard tableau') @@ -282,9 +282,9 @@ def to_tableau(self): if j >= len(ret): if val == 0: break - ret.append([i+1]*val) + ret.append([i + 1] * val) else: - ret[j].extend([i+1]*(val-len(ret[j]))) + ret[j].extend([i + 1] * (val - len(ret[j]))) S = SemistandardTableaux(max_entry=len(self)) return S(ret) @@ -306,7 +306,7 @@ def boxed_entries(self) -> tuple: ret = [] for i in range(1, len(self)): for j in range(len(self[i])): - if self[i][j] == self[i-1][j]: + if self[i][j] == self[i - 1][j]: ret.append((i, j)) return tuple(ret) @@ -328,7 +328,7 @@ def circled_entries(self) -> tuple: ret = [] for i in range(1, len(self)): for j in range(len(self[i])): - if self[i][j] == self[i-1][j+1]: + if self[i][j] == self[i - 1][j + 1]: ret.append((i, j)) return tuple(ret) @@ -457,7 +457,7 @@ def weight(self) -> tuple: sage: G.weight() (2, 2, 3) """ - wt = [self.row_sums()[-1]] + [self.row_sums()[i-1]-self.row_sums()[i] for i in reversed(range(1, len(self[0])))] + wt = [self.row_sums()[-1]] + [self.row_sums()[i - 1] - self.row_sums()[i] for i in reversed(range(1, len(self[0])))] return tuple(wt) def Tokuyama_coefficient(self, name='t'): @@ -502,7 +502,7 @@ def Tokuyama_coefficient(self, name='t'): t = R.gen(0) if not self.is_strict(): return R.zero() - return (t+1)**(self.number_of_special_entries()) * t**(self.number_of_boxes()) + return (t + 1)**self.number_of_special_entries() * t**self.number_of_boxes() @combinatorial_map(order=2, name='Bender-Knuth involution') def bender_knuth_involution(self, i) -> GelfandTsetlinPattern: @@ -544,7 +544,6 @@ def bender_knuth_involution(self, i) -> GelfandTsetlinPattern: Traceback (most recent call last): ... ValueError: must have 0 < 3 < 3 - """ n = len(self) @@ -638,7 +637,7 @@ def __classcall_private__(cls, n=None, k=None, strict=False, top_row=None): if top_row is not None: top_row = tuple(top_row) if any(top_row[i] < top_row[i+1] for i in range(len(top_row)-1)): - raise ValueError("The top row must be weakly decreasing") + raise ValueError("the top row must be weakly decreasing") if n is not None and n != len(top_row): raise ValueError("n must be the length of the specified top row") return GelfandTsetlinPatternsTopRow(top_row, strict) @@ -704,15 +703,16 @@ def __contains__(self, gt): if self._n is not None and len(gt) != self._n: return False # Check if it has the correct maximum value - if self._k is not None and any( val > self._k for row in gt for val in row ): + if self._k is not None and any(val > self._k for row in gt + for val in row): return False # Check if it is a GT pattern - if not all( gt[i-1][j] >= gt[i][j] >= gt[i-1][j+1] - for i in range(1, len(gt)) for j in range(len(gt[i])) ): + if not all(gt[i-1][j] >= gt[i][j] >= gt[i-1][j+1] + for i in range(1, len(gt)) for j in range(len(gt[i]))): return False # Check if it is strict if applicable - if self._strict and any( gt[i][j] == gt[i][j-1] for i in range(len(gt)) - for j in range(1, len(gt[i])) ): + if self._strict and any(gt[i][j] == gt[i][j-1] for i in range(len(gt)) + for j in range(1, len(gt[i]))): return False return True @@ -966,7 +966,7 @@ def _top_row_iter(self, n): continue # If it would create an invalid entry, backstep if (pos > 0 and (row[pos] >= row[pos-1] - or (self._strict and row[pos] == row[pos-1]-1)) ) \ + or (self._strict and row[pos] == row[pos-1]-1))) \ or (self._k is not None and row[pos] >= self._k): row[pos] = -1 pos -= 1 @@ -994,7 +994,7 @@ def _row_iter(self, upper_row): [2, 0] [2, 1] """ - row = [x-1 for x in upper_row[1:]] + row = [x - 1 for x in upper_row[1:]] row_len = len(row) pos = 0 while pos >= 0: @@ -1003,11 +1003,11 @@ def _row_iter(self, upper_row): pos -= 1 continue # If it would create an invalid entry, backstep - if ( pos > 0 and (row[pos] >= row[pos-1] \ - or (self._strict and row[pos] == row[pos-1]-1)) ) \ + if (pos > 0 and (row[pos] >= row[pos - 1] + or (self._strict and row[pos] == row[pos - 1] - 1))) \ or row[pos] >= upper_row[pos] \ or (self._k is not None and row[pos] >= self._k): - row[pos] = upper_row[pos+1] - 1 + row[pos] = upper_row[pos + 1] - 1 pos -= 1 continue row[pos] += 1 @@ -1053,8 +1053,7 @@ def _toggle_markov_chain(self, chain_state, row, col, direction): sage: G._toggle_markov_chain(state, 0, 2, 0) sage: state [[4, 2, 0], [3, 2], [2]] - - """ + """ if direction == 1: upbound = self._k if row != 0: @@ -1131,8 +1130,7 @@ def _cftp(self, start_row): True """ from sage.misc.randstate import current_randstate - from sage.misc.randstate import seed - from sage.misc.randstate import random + from sage.misc.randstate import seed, random count = self._n * self._k seedlist = [(current_randstate().long_seed(), count)] @@ -1149,7 +1147,8 @@ def _cftp(self, start_row): direction = random() % 2 self._toggle_markov_chain(upper, row, col, direction) self._toggle_markov_chain(lower, row, col, direction) - if all(all(x == y for x, y in zip(l1, l2)) for l1, l2 in zip(upper, lower)): + if all(x == y for l1, l2 in zip(upper, lower) + for x, y in zip(l1, l2)): break count = seedlist[0][1] * 2 seedlist.insert(0, (current_randstate().long_seed(), count)) @@ -1186,14 +1185,14 @@ def random_element(self) -> GelfandTsetlinPattern: True """ if self._n is not None and self._k is not None: - if self._strict and self._k+1 < self._n: - raise ValueError('Cannot sample from empty set') + if self._strict and self._k + 1 < self._n: + raise ValueError('cannot sample from empty set') elif self._k < 0: - raise ValueError('Cannot sample from empty set') + raise ValueError('cannot sample from empty set') else: return self._cftp(0) else: - raise ValueError('Cannot sample from infinite set') + raise ValueError('cannot sample from infinite set') class GelfandTsetlinPatternsTopRow(GelfandTsetlinPatterns): @@ -1284,7 +1283,7 @@ def __iter__(self): [[4, 2, 1], [4, 2], [4]]] """ # If we enforce strictness, check to see if a specified top row is strict - if self._strict and any(self._row[i] == self._row[i+1] for i in range(self._n-1)): + if self._strict and any(self._row[i] == self._row[i + 1] for i in range(self._n - 1)): return if self._n == 0: yield self.element_class(self, []) @@ -1293,8 +1292,8 @@ def __iter__(self): yield self.element_class(self, [list(self._row)]) return # Setup the first row - iters = [None]*self._n - ret = [None]*self._n + iters = [None] * self._n + ret = [None] * self._n ret[0] = list(self._row) min_pos = 1 iters[1] = self._row_iter(ret[0]) @@ -1308,7 +1307,7 @@ def __iter__(self): yield self.element_class(self, ret[:]) pos -= 1 continue - iters[pos] = self._row_iter(ret[pos-1]) + iters[pos] = self._row_iter(ret[pos - 1]) except StopIteration: pos -= 1 @@ -1359,12 +1358,12 @@ def Tokuyama_formula(self, name='t'): 0 """ n = self._n - variables = [name] + ["x%d" % i for i in range(1, n+1)] + variables = [name] + ["x%d" % i for i in range(1, n + 1)] R = PolynomialRing(ZZ, names=variables) t = R.gen(0) x = R.gens()[1:] GT = GelfandTsetlinPatterns(top_row=self._row, strict=True) - return sum((t+1)**(gt.number_of_special_entries()) * t**(gt.number_of_boxes()) * prod(x[i]**gt.weight()[i] for i in range(n)) for gt in GT) + return sum((t + 1)**gt.number_of_special_entries() * t**gt.number_of_boxes() * prod(x[i]**gt.weight()[i] for i in range(n)) for gt in GT) def _cftp_upper(self) -> list: """ diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index 763f8f7e482..cf8d18c1764 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -797,8 +797,8 @@ def rotate(self): """ l = self._lambda[0] h = len(self._lambda) - shape_lambda = [l-p for p in self._mu] + [l]*(h-len(self._mu)) - shape_mu = [l-p for p in self._lambda] + shape_lambda = [l - p for p in self._mu] + [l] * (h - len(self._mu)) + shape_mu = [l - p for p in self._lambda] shape = SkewPartition([shape_lambda[::-1], shape_mu[::-1]]) F = {(l-i-1, h-j-1): v for (i,j),v in self._filling.items()} return GrowthDiagram(self.rule, @@ -1128,7 +1128,7 @@ def __eq__(self, other): sage: G1 == G2 False """ - return (type(self) == type(other) and + return (type(self) is type(other) and self.rule == other.rule and self._lambda == other._lambda and self._mu == other._mu and @@ -2608,7 +2608,7 @@ def forward_rule(self, y, e, t, f, x, content): # the addable cell with largest content at most e cprime = sorted([c for c in y.to_partition().addable_cells() if c[1]-c[0] <= e], - key = lambda c: -(c[1]-c[0]))[0] + key=lambda c: -(c[1]-c[0]))[0] h = cprime[1] - cprime[0] z = y.affine_symmetric_group_simple_action(h % self.k) diff --git a/src/sage/combinat/integer_lists/base.pxd b/src/sage/combinat/integer_lists/base.pxd index ecb5550a9cf..3d373a64fe0 100644 --- a/src/sage/combinat/integer_lists/base.pxd +++ b/src/sage/combinat/integer_lists/base.pxd @@ -12,4 +12,4 @@ cdef class IntegerListsBackend(): cdef readonly min_part, max_part cdef readonly min_slope, max_slope cdef readonly Envelope floor, ceiling - cdef public dict __cached_methods # Support cached_method + cdef public dict _cached_methods # Support cached_method diff --git a/src/sage/combinat/integer_lists/base.pyx b/src/sage/combinat/integer_lists/base.pyx index bfdfc5b7d7e..91b372d2392 100644 --- a/src/sage/combinat/integer_lists/base.pyx +++ b/src/sage/combinat/integer_lists/base.pyx @@ -8,7 +8,7 @@ Enumerated set of lists of integers with constraints: base classes function under constraints. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Bryan Gillespie <Brg008@gmail.com> # Nicolas M. Thiery <nthiery at users.sf.net> # Anne Schilling <anne@math.ucdavis.edu> @@ -18,11 +18,11 @@ Enumerated set of lists of integers with constraints: base classes # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE +from cpython.object cimport Py_LE, Py_EQ, Py_NE, Py_GE from sage.misc.constant_function import ConstantFunction from sage.structure.element cimport RingElement from sage.rings.integer cimport Integer diff --git a/src/sage/combinat/integer_lists/invlex.pyx b/src/sage/combinat/integer_lists/invlex.pyx index 2f12ada7438..c94a024c040 100644 --- a/src/sage/combinat/integer_lists/invlex.pyx +++ b/src/sage/combinat/integer_lists/invlex.pyx @@ -560,7 +560,7 @@ class IntegerListsLex(IntegerLists, metaclass=ClasscallMetaclass): :: - sage: Partitions(2, max_slope=-1, length=2).list() + sage: Partitions(2, max_slope=-1, length=2).list() # optional - sage.combinat [] sage: list(IntegerListsLex(0, floor=ConstantFunction(1), min_slope=0)) [[]] @@ -1215,9 +1215,9 @@ class IntegerListsLexIter(builtins.object): max_sum = self.backend.max_sum min_length = self.backend.min_length max_length = self.backend.max_length - if self._j+1 >= max_length: + if self._j + 1 >= max_length: return False - if self._j+1 >= min_length and self._current_sum == max_sum: + if self._j + 1 >= min_length and self._current_sum == max_sum: # Cannot add trailing zeroes return False diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index 82d4886f100..65eb4dfc4e9 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -42,7 +42,7 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.rings.infinity import PlusInfinity -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.rings.integer_ring import ZZ from sage.rings.semirings.non_negative_integer_semiring import NN from sage.rings.integer import Integer @@ -92,11 +92,11 @@ def is_gale_ryser(r,s): EXAMPLES:: sage: from sage.combinat.integer_vector import is_gale_ryser - sage: is_gale_ryser([4,2,2],[3,3,1,1]) + sage: is_gale_ryser([4,2,2], [3,3,1,1]) # optional - sage.combinat True - sage: is_gale_ryser([4,2,1,1],[3,3,1,1]) + sage: is_gale_ryser([4,2,1,1], [3,3,1,1]) # optional - sage.combinat True - sage: is_gale_ryser([3,2,1,1],[3,3,1,1]) + sage: is_gale_ryser([3,2,1,1], [3,3,1,1]) # optional - sage.combinat False REMARK: In the literature, what we are calling a @@ -111,8 +111,8 @@ def is_gale_ryser(r,s): # builds the corresponding partitions, i.e. # removes the 0 and sorts the sequences from sage.combinat.partition import Partition - r2 = Partition(sorted([x for x in r if x>0], reverse=True)) - s2 = Partition(sorted([x for x in s if x>0], reverse=True)) + r2 = Partition(sorted([x for x in r if x > 0], reverse=True)) + s2 = Partition(sorted([x for x in s if x > 0], reverse=True)) # If the two sequences only contained zeroes if len(r2) == 0 and len(s2) == 0: @@ -207,14 +207,14 @@ def gale_ryser_theorem(p1, p2, algorithm="gale", sage: from sage.combinat.integer_vector import gale_ryser_theorem sage: p1 = [2,2,1] sage: p2 = [2,2,1] - sage: print(gale_ryser_theorem(p1, p2)) # not tested + sage: print(gale_ryser_theorem(p1, p2)) # not tested # optional - sage.combinat [1 1 0] [1 0 1] [0 1 0] - sage: A = gale_ryser_theorem(p1, p2) - sage: rs = [sum(x) for x in A.rows()] - sage: cs = [sum(x) for x in A.columns()] - sage: p1 == rs; p2 == cs + sage: A = gale_ryser_theorem(p1, p2) # optional - sage.combinat + sage: rs = [sum(x) for x in A.rows()] # optional - sage.combinat + sage: cs = [sum(x) for x in A.columns()] # optional - sage.combinat + sage: p1 == rs; p2 == cs # optional - sage.combinat True True @@ -224,27 +224,27 @@ def gale_ryser_theorem(p1, p2, algorithm="gale", sage: from sage.combinat.integer_vector import gale_ryser_theorem sage: p1 = [3,3,1,1] sage: p2 = [3,3,1,1] - sage: gale_ryser_theorem(p1, p2, algorithm = "ryser") + sage: gale_ryser_theorem(p1, p2, algorithm="ryser") # optional - sage.combinat [1 1 1 0] [1 1 0 1] [1 0 0 0] [0 1 0 0] sage: p1 = [4,2,2] sage: p2 = [3,3,1,1] - sage: gale_ryser_theorem(p1, p2, algorithm = "ryser") + sage: gale_ryser_theorem(p1, p2, algorithm="ryser") # optional - sage.combinat [1 1 1 1] [1 1 0 0] [1 1 0 0] sage: p1 = [4,2,2,0] sage: p2 = [3,3,1,1,0,0] - sage: gale_ryser_theorem(p1, p2, algorithm = "ryser") + sage: gale_ryser_theorem(p1, p2, algorithm="ryser") # optional - sage.combinat [1 1 1 1 0 0] [1 1 0 0 0 0] [1 1 0 0 0 0] [0 0 0 0 0 0] sage: p1 = [3,3,2,1] sage: p2 = [3,2,2,1,1] - sage: print(gale_ryser_theorem(p1, p2, algorithm="gale")) # not tested + sage: print(gale_ryser_theorem(p1, p2, algorithm="gale")) # not tested # optional - sage.combinat [1 1 1 0 0] [1 1 0 0 1] [1 0 1 0 0] @@ -253,7 +253,7 @@ def gale_ryser_theorem(p1, p2, algorithm="gale", With `0` in the sequences, and with unordered inputs:: sage: from sage.combinat.integer_vector import gale_ryser_theorem - sage: gale_ryser_theorem([3,3,0,1,1,0], [3,1,3,1,0], algorithm="ryser") + sage: gale_ryser_theorem([3,3,0,1,1,0], [3,1,3,1,0], algorithm="ryser") # optional - sage.combinat [1 1 1 0 0] [1 0 1 1 0] [0 0 0 0 0] @@ -261,7 +261,7 @@ def gale_ryser_theorem(p1, p2, algorithm="gale", [0 0 1 0 0] [0 0 0 0 0] sage: p1 = [3,1,1,1,1]; p2 = [3,2,2,0] - sage: gale_ryser_theorem(p1, p2, algorithm="ryser") + sage: gale_ryser_theorem(p1, p2, algorithm="ryser") # optional - sage.combinat [1 1 1 0] [1 0 0 0] [1 0 0 0] @@ -288,17 +288,17 @@ def gale_ryser_theorem(p1, p2, algorithm="gale", ....: print("Algorithm %s failed with this input:" % algorithm) ....: print(s1, s2) - sage: for algorithm in ["gale", "ryser"]: # long time - ....: for i in range(50): # long time - ....: test_algorithm(algorithm, 3, 10) # long time + sage: for algorithm in ["gale", "ryser"]: # long time # optional - sage.combinat + ....: for i in range(50): + ....: test_algorithm(algorithm, 3, 10) Null matrix:: - sage: gale_ryser_theorem([0,0,0],[0,0,0,0], algorithm="gale") + sage: gale_ryser_theorem([0,0,0],[0,0,0,0], algorithm="gale") # optional - sage.combinat [0 0 0 0] [0 0 0 0] [0 0 0 0] - sage: gale_ryser_theorem([0,0,0],[0,0,0,0], algorithm="ryser") + sage: gale_ryser_theorem([0,0,0],[0,0,0,0], algorithm="ryser") # optional - sage.combinat [0 0 0 0] [0 0 0 0] [0 0 0 0] @@ -361,13 +361,13 @@ def gale_ryser_theorem(p1, p2, algorithm="gale", elif algorithm == "gale": from sage.numerical.mip import MixedIntegerLinearProgram - k1, k2=len(p1), len(p2) + k1, k2 = len(p1), len(p2) p = MixedIntegerLinearProgram(solver=solver) - b = p.new_variable(binary = True) + b = p.new_variable(binary=True) for (i,c) in enumerate(p1): - p.add_constraint(p.sum([b[i,j] for j in range(k2)]) ==c) + p.add_constraint(p.sum([b[i,j] for j in range(k2)]) == c) for (i,c) in enumerate(p2): - p.add_constraint(p.sum([b[j,i] for j in range(k1)]) ==c) + p.add_constraint(p.sum([b[j,i] for j in range(k1)]) == c) p.set_objective(None) p.solve() b = p.get_values(b, convert=ZZ, tolerance=integrality_tolerance) @@ -511,6 +511,44 @@ def trim(self): v = v[:-1] return P.element_class(P, v, check=False) + def specht_module(self, base_ring=None): + r""" + Return the Specht module corresponding to ``self``. + + EXAMPLES:: + + sage: SM = IntegerVectors()([2,0,1,0,2]).specht_module(QQ); SM # optional - sage.combinat + Specht module of [(0, 0), (0, 1), (2, 0), (4, 0), (4, 1)] over Rational Field + sage: s = SymmetricFunctions(QQ).s() # optional - sage.combinat + sage: s(SM.frobenius_image()) # optional - sage.combinat + s[2, 2, 1] + """ + from sage.combinat.specht_module import SpechtModule + from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: + from sage.rings.rational_field import QQ + base_ring = QQ + R = SymmetricGroupAlgebra(base_ring, sum(self)) + return SpechtModule(R, self) + + def specht_module_dimension(self, base_ring=None): + r""" + Return the dimension of the Specht module corresponding to ``self``. + + INPUT: + + - ``BR`` -- (default: `\QQ`) the base ring + + EXAMPLES:: + + sage: IntegerVectors()([2,0,1,0,2]).specht_module_dimension() # optional - sage.combinat + 5 + sage: IntegerVectors()([2,0,1,0,2]).specht_module_dimension(GF(2)) # optional - sage.combinat sage.rings.finite_rings + 5 + """ + from sage.combinat.specht_module import specht_module_rank + return specht_module_rank(self, base_ring) + class IntegerVectors(Parent, metaclass=ClasscallMetaclass): """ @@ -556,7 +594,7 @@ class IntegerVectors(Parent, metaclass=ClasscallMetaclass): Note that trailing zeros are ignored so that ``[3, 0]`` does not show up in the following list (since ``[3]`` does):: - sage: IntegerVectors(3, max_length=2).list() + sage: IntegerVectors(3, max_length=2).list() # optional - sage.combinat [[3], [2, 1], [1, 2], [0, 3]] If ``n`` and ``k`` are both specified, then it returns the class @@ -575,9 +613,9 @@ class IntegerVectors(Parent, metaclass=ClasscallMetaclass): Further examples:: - sage: IntegerVectors(-1, 0, min_part = 1).list() + sage: IntegerVectors(-1, 0, min_part=1).list() [] - sage: IntegerVectors(-1, 2, min_part = 1).list() + sage: IntegerVectors(-1, 2, min_part=1).list() [] sage: IntegerVectors(0, 0, min_part=1).list() [[]] @@ -628,14 +666,14 @@ class IntegerVectors(Parent, metaclass=ClasscallMetaclass): An example showing the same output by using IntegerListsLex:: - sage: IntegerVectors(4, max_length=2).list() + sage: IntegerVectors(4, max_length=2).list() # optional - sage.combinat [[4], [3, 1], [2, 2], [1, 3], [0, 4]] - sage: list(IntegerListsLex(4, max_length=2)) + sage: list(IntegerListsLex(4, max_length=2)) # optional - sage.combinat [[4], [3, 1], [2, 2], [1, 3], [0, 4]] .. SEEALSO:: - :class: `sage.combinat.integer_lists.invlex.IntegerListsLex`. + :class:`sage.combinat.integer_lists.invlex.IntegerListsLex` """ @staticmethod def __classcall_private__(cls, n=None, k=None, **kwargs): @@ -1353,12 +1391,12 @@ def __contains__(self, x): """ TESTS:: - sage: [3,2,2,1] in IntegerVectors(8,4, min_part = 1) + sage: [3,2,2,1] in IntegerVectors(8, 4, min_part=1) # optional - sage.combinat True - sage: [3,2,2,1] in IntegerVectors(8,4, min_part = 2) + sage: [3,2,2,1] in IntegerVectors(8, 4, min_part=2) # optional - sage.combinat False - sage: [0,3,0,1,2] in IntegerVectors(6, max_length=3) + sage: [0,3,0,1,2] in IntegerVectors(6, max_length=3) # optional - sage.combinat False """ if isinstance(x, IntegerVector) and x.parent() is self: @@ -1382,17 +1420,17 @@ def cardinality(self): EXAMPLES:: - sage: IntegerVectors(3, 3, min_part=1).cardinality() + sage: IntegerVectors(3, 3, min_part=1).cardinality() # optional - sage.combinat 1 - sage: IntegerVectors(5, 3, min_part=1).cardinality() + sage: IntegerVectors(5, 3, min_part=1).cardinality() # optional - sage.combinat 6 - sage: IntegerVectors(13, 4, max_part=4).cardinality() + sage: IntegerVectors(13, 4, max_part=4).cardinality() # optional - sage.combinat 20 - sage: IntegerVectors(k=4, max_part=3).cardinality() + sage: IntegerVectors(k=4, max_part=3).cardinality() # optional - sage.combinat 256 - sage: IntegerVectors(k=3, min_part=2, max_part=4).cardinality() + sage: IntegerVectors(k=3, min_part=2, max_part=4).cardinality() # optional - sage.combinat 27 - sage: IntegerVectors(13, 4, min_part=2, max_part=4).cardinality() + sage: IntegerVectors(13, 4, min_part=2, max_part=4).cardinality() # optional - sage.combinat 16 """ if self.k is None: @@ -1416,17 +1454,19 @@ def cardinality(self): return Integer(binomial(self.n + self.k - 1, self.n)) # do by inclusion / exclusion on the number # i of parts greater than m - return Integer(sum( (-1)**i * binomial(self.n+self.k-1-i*(m+1), self.k-1) \ - * binomial(self.k,i) for i in range(self.n/(m+1)+1) )) + n, k = self.n, self.k + return Integer(sum( + (-1)**i * binomial(n + k - 1 - i * (m + 1), k - 1) + * binomial(k, i) for i in range(self.n // (m + 1) + 1))) return ZZ.sum(ZZ.one() for x in self) def __iter__(self): """ EXAMPLES:: - sage: IntegerVectors(-1, 0, min_part = 1).list() + sage: IntegerVectors(-1, 0, min_part=1).list() [] - sage: IntegerVectors(-1, 2, min_part = 1).list() + sage: IntegerVectors(-1, 2, min_part=1).list() [] sage: IntegerVectors(0, 0, min_part=1).list() [[]] @@ -1471,7 +1511,7 @@ def __iter__(self): sage: all(map(lambda x: x.cardinality() == len(x.list()), iv)) True sage: essai = [[1,1,1], [2,5,6], [6,5,2]] - sage: iv = [ IntegerVectors(x[0], x[1], max_part = x[2]-1) for x in essai ] + sage: iv = [ IntegerVectors(x[0], x[1], max_part=x[2]-1) for x in essai ] sage: all(map(lambda x: x.cardinality() == len(x.list()), iv)) True """ diff --git a/src/sage/combinat/integer_vector_weighted.py b/src/sage/combinat/integer_vector_weighted.py index a03314b6bf7..bd2198f29da 100644 --- a/src/sage/combinat/integer_vector_weighted.py +++ b/src/sage/combinat/integer_vector_weighted.py @@ -20,13 +20,15 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.sets_with_grading import SetsWithGrading +from sage.misc.lazy_import import lazy_import from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.combinat.integer_vector import IntegerVector -from sage.combinat.words.word import Word from sage.combinat.permutation import Permutation +lazy_import('sage.combinat.words.word', 'Word') + class WeightedIntegerVectors(Parent, UniqueRepresentation): r""" @@ -282,7 +284,8 @@ def __init__(self, weight): sage: TestSuite(C).run() """ self._weights = weight - from sage.sets.all import Family, NonNegativeIntegers + from sage.sets.family import Family + from sage.sets.non_negative_integers import NonNegativeIntegers # Use "partial" to make the basis function (with the weights # argument specified) pickleable. Otherwise, it seems to # cause problems... @@ -318,7 +321,7 @@ def __contains__(self, x): and len(x) == len(self._weights) and all(i in ZZ and i >= 0 for i in x)) - def subset(self, size = None): + def subset(self, size=None): """ EXAMPLES:: diff --git a/src/sage/combinat/integer_vectors_mod_permgroup.py b/src/sage/combinat/integer_vectors_mod_permgroup.py index 539fc59b9c0..8503bd978c5 100644 --- a/src/sage/combinat/integer_vectors_mod_permgroup.py +++ b/src/sage/combinat/integer_vectors_mod_permgroup.py @@ -1,3 +1,4 @@ +# optional - sage.combinat sage.groups r""" Integer vectors modulo the action of a permutation group """ @@ -278,7 +279,7 @@ def __init__(self, G, sgs=None): Category of infinite enumerated quotients of sets sage: TestSuite(I).run() """ - RecursivelyEnumeratedSet_forest.__init__(self, algorithm = 'breadth', category = InfiniteEnumeratedSets().Quotients()) + RecursivelyEnumeratedSet_forest.__init__(self, algorithm='breadth', category=InfiniteEnumeratedSets().Quotients()) self._permgroup = G self.n = G.degree() @@ -430,8 +431,8 @@ def is_canonical(self, v, check=True): False """ if check: - assert isinstance(v, (ClonableIntArray, list)), '%s should be a list or a integer vector'%v - assert (self.n == len(v)), '%s should be of length %s'%(v, self.n) + assert isinstance(v, (ClonableIntArray, list)), '%s should be a list or a integer vector' % v + assert (self.n == len(v)), '%s should be of length %s' % (v, self.n) for p in v: assert (p == NN(p)), 'Elements of %s should be integers' % v return is_canonical(self._sgs, self.element_class(self, list(v), check=False)) @@ -472,7 +473,7 @@ def __call__(self, v, check=True): if v.parent() is self: return v else: - raise ValueError('%s should be a Python list of integer'%(v)) + raise ValueError('%s should be a Python list of integer' % (v)) except Exception: return self.element_class(self, list(v), check=check) @@ -498,7 +499,7 @@ def orbit(self, v): sage: I.orbit([1,1,1,1]) {[1, 1, 1, 1]} """ - assert isinstance(v, (list, ClonableIntArray)), '%s should be a Python list or an element of %s'%(v, self) + assert isinstance(v, (list, ClonableIntArray)), '%s should be a Python list or an element of %s' % (v, self) try: if v.parent() is self: return orbit(self._sgs, v) @@ -602,7 +603,7 @@ def __init__(self, G, d, max_part, sgs=None): sage: I = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]]), 6, max_part=4) """ - RecursivelyEnumeratedSet_forest.__init__(self, algorithm = 'breadth', category = (FiniteEnumeratedSets(), FiniteEnumeratedSets().Quotients())) + RecursivelyEnumeratedSet_forest.__init__(self, algorithm='breadth', category=(FiniteEnumeratedSets(), FiniteEnumeratedSets().Quotients())) self._permgroup = G self.n = G.degree() self._sum = d @@ -719,7 +720,7 @@ def __call__(self, v, check=True): if v.parent() is self: return v else: - raise ValueError('%s should be a Python list of integer'%(v)) + raise ValueError('%s should be a Python list of integer' % (v)) except Exception: return self.element_class(self, list(v), check=check) @@ -757,7 +758,7 @@ def __iter__(self): else: SF = RecursivelyEnumeratedSet_forest((self([0]*(self.n), check=False),), lambda x : [self(y, check=False) for y in canonical_children(self._sgs, x, self._max_part)], - algorithm = 'breadth') + algorithm='breadth') if self._sum is None: return iter(SF) else: diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index e8168802800..3c8e85061f3 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -36,7 +36,7 @@ from sage.categories.enumerated_sets import EnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.posets import Posets -from sage.categories.all import Monoids +from sage.categories.monoids import Monoids from sage.combinat.posets.posets import Poset, FinitePoset from sage.categories.finite_posets import FinitePosets from sage.combinat.binary_tree import BinaryTrees @@ -61,7 +61,7 @@ class TamariIntervalPoset(Element, - metaclass=InheritComparisonClasscallMetaclass): + metaclass=InheritComparisonClasscallMetaclass): r""" The class of Tamari interval-posets. @@ -437,20 +437,20 @@ def plot(self, **kwds): EXAMPLES:: sage: ti = TamariIntervalPosets(4)[2] - sage: ti.plot() + sage: ti.plot() # optional - sage.plot Graphics object consisting of 6 graphics primitives TESTS:: sage: ti = TamariIntervalPoset(3, [[2,1], [2,3]]) - sage: ti.plot() + sage: ti.plot() # optional - sage.plot Graphics object consisting of 6 graphics primitives """ c0 = 'blue' # self.latex_options()["color_increasing"] c1 = 'red' # self.latex_options()["color_decreasing"] G = self.poset().hasse_diagram() G.set_pos(self._find_node_positions()) - for a, b, c in G.edges(sort=False): + for a, b in G.edges(sort=False, labels=False): if a < b: G.set_edge_label(a, b, 0) else: @@ -611,11 +611,11 @@ def factor(self) -> list[TamariIntervalPoset]: TESTS:: - sage: T = TamariIntervalPosets(20).random_element() - sage: facs = factor(T) - sage: all(U.is_connected() for U in facs) + sage: T = TamariIntervalPosets(20).random_element() # optional - sage.combinat + sage: facs = factor(T) # optional - sage.combinat + sage: all(U.is_connected() for U in facs) # optional - sage.combinat True - sage: T == prod(facs) + sage: T == prod(facs) # optional - sage.combinat True """ hasse = self.poset().hasse_diagram() @@ -1030,10 +1030,10 @@ def cubical_coordinates(self) -> tuple[int, ...]: sage: ip = TamariIntervalPoset(3,[]) sage: ip.cubical_coordinates() (0, 0) - sage: ip = TamariIntervalPosets(10).random_element() - sage: len(ip.cubical_coordinates()) + sage: ip = TamariIntervalPosets(10).random_element() # optional - sage.combinat + sage: len(ip.cubical_coordinates()) # optional - sage.combinat 9 - sage: sorted(ip.cubical_coordinates() for ip in TamariIntervalPosets(2)) + sage: sorted(ip.cubical_coordinates() for ip in TamariIntervalPosets(2)) # optional - sage.combinat [(-1,), (0,), (1,)] REFERENCES: @@ -1136,7 +1136,8 @@ def rise_contact_involution(self) -> TIP: (4, 3), (3, 2), (2, 1)] sage: t.rise_contact_involution() == tip True - sage: tip.lower_dyck_word().number_of_touch_points() == t.upper_dyck_word().number_of_initial_rises() + sage: (tip.lower_dyck_word().number_of_touch_points() # optional - sage.combinat + ....: == t.upper_dyck_word().number_of_initial_rises()) True sage: tip.number_of_tamari_inversions() == t.number_of_tamari_inversions() True @@ -1232,7 +1233,7 @@ def insertion(self, i) -> TIP: ....: print(T, i) ....: return False ....: return True - sage: test_equivalence(3) + sage: test_equivalence(3) # optional - sage.combinat True sage: ti = TamariIntervalPosets(3).an_element() @@ -1674,17 +1675,17 @@ def contains_dyck_word(self, dyck_word) -> bool: EXAMPLES:: sage: ip = TamariIntervalPoset(4,[(2,4),(3,4),(2,1),(3,1)]) - sage: ip.contains_dyck_word(DyckWord([1,1,1,0,0,0,1,0])) + sage: ip.contains_dyck_word(DyckWord([1,1,1,0,0,0,1,0])) # optional - sage.combinat True - sage: ip.contains_dyck_word(DyckWord([1,1,0,1,0,1,0,0])) + sage: ip.contains_dyck_word(DyckWord([1,1,0,1,0,1,0,0])) # optional - sage.combinat True - sage: ip.contains_dyck_word(DyckWord([1,0,1,1,0,1,0,0])) + sage: ip.contains_dyck_word(DyckWord([1,0,1,1,0,1,0,0])) # optional - sage.combinat False - sage: ip.contains_dyck_word(ip.lower_dyck_word()) + sage: ip.contains_dyck_word(ip.lower_dyck_word()) # optional - sage.combinat True - sage: ip.contains_dyck_word(ip.upper_dyck_word()) + sage: ip.contains_dyck_word(ip.upper_dyck_word()) # optional - sage.combinat True - sage: all(ip.contains_dyck_word(bt) for bt in ip.dyck_words()) + sage: all(ip.contains_dyck_word(bt) for bt in ip.dyck_words()) # optional - sage.combinat True """ return self.contains_binary_tree(dyck_word.to_binary_tree_tamari()) @@ -1779,14 +1780,16 @@ def is_initial_interval(self) -> bool: sage: ip = TamariIntervalPoset(4, [(1, 2), (2, 4), (3, 4)]) sage: ip.is_initial_interval() True - sage: ip.lower_dyck_word() + sage: ip.lower_dyck_word() # optional - sage.combinat [1, 0, 1, 0, 1, 0, 1, 0] sage: ip = TamariIntervalPoset(4, [(1, 2), (2, 4), (3, 4), (3, 2)]) sage: ip.is_initial_interval() False - sage: ip.lower_dyck_word() + sage: ip.lower_dyck_word() # optional - sage.combinat [1, 0, 1, 1, 0, 0, 1, 0] - sage: all(DyckWord([1,0,1,0,1,0]).tamari_interval(dw).is_initial_interval() for dw in DyckWords(3)) + sage: all(DyckWord([1,0,1,0,1,0]).tamari_interval(dw) # optional - sage.combinat + ....: .is_initial_interval() + ....: for dw in DyckWords(3)) True """ return not self.decreasing_cover_relations() @@ -1807,14 +1810,16 @@ def is_final_interval(self) -> bool: sage: ip = TamariIntervalPoset(4, [(4, 3), (3, 1), (2, 1)]) sage: ip.is_final_interval() True - sage: ip.upper_dyck_word() + sage: ip.upper_dyck_word() # optional - sage.combinat [1, 1, 1, 1, 0, 0, 0, 0] sage: ip = TamariIntervalPoset(4, [(4, 3), (3, 1), (2, 1), (2, 3)]) sage: ip.is_final_interval() False - sage: ip.upper_dyck_word() + sage: ip.upper_dyck_word() # optional - sage.combinat [1, 1, 0, 1, 1, 0, 0, 0] - sage: all(dw.tamari_interval(DyckWord([1, 1, 1, 0, 0, 0])).is_final_interval() for dw in DyckWords(3)) + sage: all(dw.tamari_interval(DyckWord([1, 1, 1, 0, 0, 0])) # optional - sage.combinat + ....: .is_final_interval() + ....: for dw in DyckWords(3)) True """ return not self.increasing_cover_relations() @@ -1854,13 +1859,16 @@ def lower_dyck_word(self): EXAMPLES:: - sage: ip = TamariIntervalPoset(6,[(3,2),(4,3),(5,2),(6,5),(1,2),(4,5)]); ip - The Tamari interval of size 6 induced by relations [(1, 2), (4, 5), (6, 5), (5, 2), (4, 3), (3, 2)] - sage: ip.lower_dyck_word() + sage: ip = TamariIntervalPoset(6, [(3,2),(4,3),(5,2),(6,5),(1,2),(4,5)]); ip + The Tamari interval of size 6 induced by relations + [(1, 2), (4, 5), (6, 5), (5, 2), (4, 3), (3, 2)] + sage: ip.lower_dyck_word() # optional - sage.combinat [1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0] - sage: TamariIntervalPosets.final_forest(ip.lower_dyck_word()) == ip.final_forest() + sage: ldw_ff = TamariIntervalPosets.final_forest(ip.lower_dyck_word()) # optional - sage.combinat + sage: ldw_ff == ip.final_forest() # optional - sage.combinat True - sage: ip == TamariIntervalPosets.from_dyck_words(ip.lower_dyck_word(),ip.upper_dyck_word()) + sage: ip == TamariIntervalPosets.from_dyck_words(ip.lower_dyck_word(), # optional - sage.combinat + ....: ip.upper_dyck_word()) True """ return self.lower_binary_tree().to_dyck_word_tamari() @@ -1901,12 +1909,15 @@ def upper_dyck_word(self): EXAMPLES:: sage: ip = TamariIntervalPoset(6,[(3,2),(4,3),(5,2),(6,5),(1,2),(4,5)]); ip - The Tamari interval of size 6 induced by relations [(1, 2), (4, 5), (6, 5), (5, 2), (4, 3), (3, 2)] - sage: ip.upper_dyck_word() + The Tamari interval of size 6 induced by relations + [(1, 2), (4, 5), (6, 5), (5, 2), (4, 3), (3, 2)] + sage: ip.upper_dyck_word() # optional - sage.combinat [1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0] - sage: TamariIntervalPosets.initial_forest(ip.upper_dyck_word()) == ip.initial_forest() + sage: udw_if = TamariIntervalPosets.initial_forest(ip.upper_dyck_word()) # optional - sage.combinat + sage: udw_if == ip.initial_forest() # optional - sage.combinat True - sage: ip == TamariIntervalPosets.from_dyck_words(ip.lower_dyck_word(),ip.upper_dyck_word()) + sage: ip == TamariIntervalPosets.from_dyck_words(ip.lower_dyck_word(), # optional - sage.combinat + ....: ip.upper_dyck_word()) True """ return self.upper_binary_tree().to_dyck_word_tamari() @@ -2074,11 +2085,11 @@ def linear_extensions(self) -> Iterator[Permutation]: EXAMPLES:: - sage: ip = TamariIntervalPoset(3,[(1,2),(3,2)]) - sage: list(ip.linear_extensions()) + sage: ip = TamariIntervalPoset(3, [(1,2),(3,2)]) + sage: list(ip.linear_extensions()) # optional - sage.rings.finite_rings sage.modules [[3, 1, 2], [1, 3, 2]] - sage: ip = TamariIntervalPoset(4,[(1,2),(2,3),(4,3)]) - sage: list(ip.linear_extensions()) + sage: ip = TamariIntervalPoset(4, [(1,2),(2,3),(4,3)]) + sage: list(ip.linear_extensions()) # optional - sage.rings.finite_rings sage.modules [[4, 1, 2, 3], [1, 2, 4, 3], [1, 4, 2, 3]] """ for ext in self._poset.linear_extensions(): @@ -2146,31 +2157,26 @@ def add_relations(poset, n, m): if poset.le(n, m): # there is already a link n->m, so we go to the next n - for pos in add_relations(poset, n - 1, m): - yield pos + yield from add_relations(poset, n - 1, m) elif poset.le(m, n): # there is an inverse link m->n, we know we won't be able # to create a link i->m with i<=n, so we go to the next m - for pos in add_relations(poset, m, m + 1): - yield pos + yield from add_relations(poset, m, m + 1) else: # there is no link n->m # first option : we don't create the link and go to the next m # (since the lack of a link n->m forbids any links i->m # with i<n) - for pos in add_relations(poset, m, m + 1): - yield pos + yield from add_relations(poset, m, m + 1) # second option : we create the link # (this is allowed because links i->m already exist for all # n<i<m, or else we wouldn't be here) poset = TamariIntervalPoset(poset.size(), poset._cover_relations + ((n, m),)) yield poset # and then, we go to the next n - for pos in add_relations(poset, n - 1, m): - yield pos + yield from add_relations(poset, n - 1, m) - for inter in add_relations(self, 1, 2): - yield inter + yield from add_relations(self, 1, 2) def interval_cardinality(self) -> Integer: r""" @@ -2220,12 +2226,12 @@ def dyck_words(self) -> Iterator: EXAMPLES:: - sage: list(TamariIntervalPoset(4,[(2,4),(3,4),(2,1),(3,1)]).dyck_words()) + sage: list(TamariIntervalPoset(4,[(2,4),(3,4),(2,1),(3,1)]).dyck_words()) # optional - sage.combinat [[1, 1, 1, 0, 0, 1, 0, 0], [1, 1, 1, 0, 0, 0, 1, 0], [1, 1, 0, 1, 0, 1, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0]] - sage: set(TamariIntervalPoset(4,[]).dyck_words()) == set(DyckWords(4)) + sage: set(TamariIntervalPoset(4,[]).dyck_words()) == set(DyckWords(4)) # optional - sage.combinat True """ for ip in self.lower_contained_intervals(): @@ -2302,10 +2308,10 @@ def maximal_chain_dyck_words(self) -> Iterator: EXAMPLES:: sage: ip = TamariIntervalPoset(4,[(2,4),(3,4),(2,1),(3,1)]) - sage: list(ip.maximal_chain_dyck_words()) + sage: list(ip.maximal_chain_dyck_words()) # optional - sage.combinat [[1, 1, 0, 1, 0, 0, 1, 0], [1, 1, 0, 1, 0, 1, 0, 0], [1, 1, 1, 0, 0, 1, 0, 0]] sage: ip = TamariIntervalPoset(4,[]) - sage: list(ip.maximal_chain_dyck_words()) + sage: list(ip.maximal_chain_dyck_words()) # optional - sage.combinat [[1, 0, 1, 0, 1, 0, 1, 0], [1, 1, 0, 0, 1, 0, 1, 0], [1, 1, 0, 1, 0, 0, 1, 0], @@ -2371,9 +2377,13 @@ def tamari_inversions(self) -> list[tuple[int, int]]: sage: ip = TamariIntervalPoset(4,[]) sage: ip.tamari_inversions() [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - sage: all(len(TamariIntervalPosets.from_binary_trees(bt,bt).tamari_inversions())==0 for bt in BinaryTrees(3)) + sage: all(not TamariIntervalPosets.from_binary_trees(bt,bt) # optional - sage.combinat + ....: .tamari_inversions() + ....: for bt in BinaryTrees(3)) True - sage: all(len(TamariIntervalPosets.from_binary_trees(bt,bt).tamari_inversions())==0 for bt in BinaryTrees(4)) + sage: all(not TamariIntervalPosets.from_binary_trees(bt,bt) # optional - sage.combinat + ....: .tamari_inversions() + ....: for bt in BinaryTrees(4)) True """ return list(self.tamari_inversions_iter()) @@ -2494,18 +2504,18 @@ def new_decomposition(self) -> list[TIP]: sage: ex = TamariIntervalPosets(4)[11] sage: ex.number_of_new_components() 3 - sage: ex.new_decomposition() + sage: ex.new_decomposition() # optional - sage.combinat [The Tamari interval of size 1 induced by relations [], The Tamari interval of size 2 induced by relations [], The Tamari interval of size 1 induced by relations []] TESTS:: - sage: ex = TamariIntervalPosets(4).random_element() - sage: dec = ex.new_decomposition() - sage: len(dec) == ex.number_of_new_components() + sage: ex = TamariIntervalPosets(4).random_element() # optional - sage.combinat + sage: dec = ex.new_decomposition() # optional - sage.combinat + sage: len(dec) == ex.number_of_new_components() # optional - sage.combinat True - sage: all(u.is_new() for u in dec) + sage: all(u.is_new() for u in dec) # optional - sage.combinat True """ from sage.combinat.binary_tree import BinaryTree @@ -3026,11 +3036,11 @@ def final_forest(element) -> TIP: From Dyck words:: - sage: dw = DyckWord([1,0]) - sage: TamariIntervalPosets.final_forest(dw) + sage: dw = DyckWord([1,0]) # optional - sage.combinat + sage: TamariIntervalPosets.final_forest(dw) # optional - sage.combinat The Tamari interval of size 1 induced by relations [] - sage: dw = DyckWord([1,1,0,1,0,0,1,1,0,0]) - sage: TamariIntervalPosets.final_forest(dw) + sage: dw = DyckWord([1,1,0,1,0,0,1,1,0,0]) # optional - sage.combinat + sage: TamariIntervalPosets.final_forest(dw) # optional - sage.combinat The Tamari interval of size 5 induced by relations [(5, 4), (3, 1), (2, 1)] TESTS:: @@ -3042,7 +3052,13 @@ def final_forest(element) -> TIP: """ if isinstance(element, TamariIntervalPoset): return element.final_forest() - if element in DyckWords(): + + try: + DW = DyckWords() + except ImportError: + DW = () + + if element in DW: binary_tree = element.to_binary_tree_tamari() elif element in BinaryTrees() or element in LabelledBinaryTrees(): binary_tree = element @@ -3133,11 +3149,11 @@ def initial_forest(element) -> TIP: from Dyck words:: - sage: dw = DyckWord([1,0]) - sage: TamariIntervalPosets.initial_forest(dw) + sage: dw = DyckWord([1,0]) # optional - sage.combinat + sage: TamariIntervalPosets.initial_forest(dw) # optional - sage.combinat The Tamari interval of size 1 induced by relations [] - sage: dw = DyckWord([1,1,0,1,0,0,1,1,0,0]) - sage: TamariIntervalPosets.initial_forest(dw) + sage: dw = DyckWord([1,1,0,1,0,0,1,1,0,0]) # optional - sage.combinat + sage: TamariIntervalPosets.initial_forest(dw) # optional - sage.combinat The Tamari interval of size 5 induced by relations [(1, 4), (2, 3), (3, 4)] TESTS:: @@ -3149,7 +3165,13 @@ def initial_forest(element) -> TIP: """ if isinstance(element, TamariIntervalPoset): return element.initial_forest() - if element in DyckWords(): + + try: + DW = DyckWords() + except ImportError: + DW = () + + if element in DW: binary_tree = element.to_binary_tree_tamari() elif element in BinaryTrees() or element in LabelledBinaryTrees(): binary_tree = element @@ -3231,7 +3253,7 @@ def from_binary_trees(tree1, tree2) -> TIP: final_forest = TamariIntervalPosets.final_forest(tree1) try: return initial_forest.intersection(final_forest) - except Exception: + except ValueError: raise ValueError("the two binary trees are not comparable on the Tamari lattice") @staticmethod @@ -3252,26 +3274,27 @@ def from_dyck_words(dw1, dw2) -> TIP: EXAMPLES:: - sage: dw1 = DyckWord([1,0,1,0]) - sage: dw2 = DyckWord([1,1,0,0]) - sage: TamariIntervalPosets.from_dyck_words(dw1,dw2) + sage: dw1 = DyckWord([1,0,1,0]) # optional - sage.combinat + sage: dw2 = DyckWord([1,1,0,0]) # optional - sage.combinat + sage: TamariIntervalPosets.from_dyck_words(dw1, dw2) # optional - sage.combinat The Tamari interval of size 2 induced by relations [] - sage: TamariIntervalPosets.from_dyck_words(dw1,dw1) + sage: TamariIntervalPosets.from_dyck_words(dw1,dw1) # optional - sage.combinat The Tamari interval of size 2 induced by relations [(1, 2)] - sage: TamariIntervalPosets.from_dyck_words(dw2,dw2) + sage: TamariIntervalPosets.from_dyck_words(dw2,dw2) # optional - sage.combinat The Tamari interval of size 2 induced by relations [(2, 1)] - sage: dw1 = DyckWord([1,0,1,1,1,0,0,1,1,0,0,0]) - sage: dw2 = DyckWord([1,1,1,1,0,1,1,0,0,0,0,0]) - sage: TamariIntervalPosets.from_dyck_words(dw1,dw2) - The Tamari interval of size 6 induced by relations [(4, 5), (6, 5), (5, 2), (4, 3), (3, 2)] + sage: dw1 = DyckWord([1,0,1,1,1,0,0,1,1,0,0,0]) # optional - sage.combinat + sage: dw2 = DyckWord([1,1,1,1,0,1,1,0,0,0,0,0]) # optional - sage.combinat + sage: TamariIntervalPosets.from_dyck_words(dw1,dw2) # optional - sage.combinat + The Tamari interval of size 6 induced by relations + [(4, 5), (6, 5), (5, 2), (4, 3), (3, 2)] - sage: dw3 = DyckWord([1,1,1,0,1,1,1,0,0,0,0,0]) - sage: TamariIntervalPosets.from_dyck_words(dw1,dw3) + sage: dw3 = DyckWord([1,1,1,0,1,1,1,0,0,0,0,0]) # optional - sage.combinat + sage: TamariIntervalPosets.from_dyck_words(dw1,dw3) # optional - sage.combinat Traceback (most recent call last): ... ValueError: the two Dyck words are not comparable on the Tamari lattice - sage: TamariIntervalPosets.from_dyck_words(dw1,DyckWord([1,0])) + sage: TamariIntervalPosets.from_dyck_words(dw1,DyckWord([1,0])) # optional - sage.combinat Traceback (most recent call last): ... ValueError: the two Dyck words are not comparable on the Tamari lattice @@ -3280,7 +3303,7 @@ def from_dyck_words(dw1, dw2) -> TIP: tree2 = dw2.to_binary_tree_tamari() try: return TamariIntervalPosets.from_binary_trees(tree1, tree2) - except Exception: + except ValueError: raise ValueError("the two Dyck words are not comparable on the Tamari lattice") @staticmethod @@ -3380,7 +3403,7 @@ def from_minimal_schnyder_wood(graph) -> TIP: sage: TIP = TamariIntervalPosets sage: G = DiGraph([(0,-1,0),(0,-2,1),(0,-3,2)], format='list_of_edges') sage: G.set_embedding({-1:[0],-2:[0],-3:[0],0:[-1,-2,-3]}) - sage: TIP.from_minimal_schnyder_wood(G) + sage: TIP.from_minimal_schnyder_wood(G) # optional - sage.combinat The Tamari interval of size 1 induced by relations [] An example from page 14 of [BeBo2009]_:: @@ -3398,8 +3421,9 @@ def from_minimal_schnyder_wood(graph) -> TIP: sage: for k in range(6): ....: embed[k] = data_emb[k] sage: G.set_embedding(embed) - sage: TIP.from_minimal_schnyder_wood(G) - The Tamari interval of size 6 induced by relations [(1, 4), (2, 4), (3, 4), (5, 6), (6, 4), (5, 4), (3, 1), (2, 1)] + sage: TIP.from_minimal_schnyder_wood(G) # optional - sage.combinat + The Tamari interval of size 6 induced by relations + [(1, 4), (2, 4), (3, 4), (5, 6), (6, 4), (5, 4), (3, 1), (2, 1)] An example from page 18 of [BeBo2009]_:: @@ -3416,8 +3440,9 @@ def from_minimal_schnyder_wood(graph) -> TIP: sage: for k in range(6): ....: embed[k] = data_emb[k] sage: G.set_embedding(embed) - sage: TIP.from_minimal_schnyder_wood(G) - The Tamari interval of size 6 induced by relations [(1, 3), (2, 3), (4, 5), (5, 3), (4, 3), (2, 1)] + sage: TIP.from_minimal_schnyder_wood(G) # optional - sage.combinat + The Tamari interval of size 6 induced by relations + [(1, 3), (2, 3), (4, 5), (5, 3), (4, 3), (2, 1)] Another small example:: @@ -3433,7 +3458,7 @@ def from_minimal_schnyder_wood(graph) -> TIP: sage: for k in range(3): ....: embed[k] = data_emb[k] sage: G.set_embedding(embed) - sage: TIP.from_minimal_schnyder_wood(G) + sage: TIP.from_minimal_schnyder_wood(G) # optional - sage.combinat The Tamari interval of size 3 induced by relations [(2, 3), (2, 1)] """ from sage.combinat.dyck_word import DyckWord @@ -3539,7 +3564,7 @@ def le(self, el1, el2) -> bool: The comparison is first by size, then using the cubical coordinates. - .. SEEALSO:: :meth:`cubical_coordinates` + .. SEEALSO:: :meth:`~TamariIntervalPoset.cubical_coordinates` INPUT: @@ -3709,7 +3734,7 @@ def cardinality(self) -> Integer: sage: [TamariIntervalPosets(i).cardinality() for i in range(6)] [1, 1, 3, 13, 68, 399] """ - from sage.arith.all import binomial + from sage.arith.misc import binomial n = self._size if n == 0: return Integer(1) @@ -3797,14 +3822,14 @@ def random_element(self) -> TIP: EXAMPLES:: - sage: T = TamariIntervalPosets(4).random_element() - sage: T.parent() + sage: T = TamariIntervalPosets(4).random_element() # optional - sage.combinat + sage: T.parent() # optional - sage.combinat Interval-posets - sage: u = T.lower_dyck_word(); u # random + sage: u = T.lower_dyck_word(); u # random # optional - sage.combinat [1, 1, 0, 1, 0, 0, 1, 0] - sage: v = T.lower_dyck_word(); v # random + sage: v = T.lower_dyck_word(); v # random # optional - sage.combinat [1, 1, 0, 1, 0, 0, 1, 0] - sage: len(u) + sage: len(u) # optional - sage.combinat 8 """ from sage.graphs.schnyder import minimal_schnyder_wood diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py deleted file mode 100644 index 50ae558aaad..00000000000 --- a/src/sage/combinat/k_regular_sequence.py +++ /dev/null @@ -1,3151 +0,0 @@ -r""" -`k`-regular Sequences - -An introduction and formal definition of `k`-regular sequences can be -found, for example, on the :wikipedia:`k-regular_sequence` or in -[AS2003]_. - - -.. WARNING:: - - As this code is experimental, warnings are thrown when a - `k`-regular sequence space is created for the first time in a - session (see :class:`sage.misc.superseded.experimental`). - - TESTS:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - doctest:...: FutureWarning: This class/method/function is - marked as experimental. It, its functionality or its interface - might change without a formal deprecation. - See https://github.com/sagemath/sage/issues/21202 for details. - - -Examples -======== - -Binary sum of digits --------------------- - -The binary sum of digits `S(n)` of a nonnegative integer `n` satisfies -`S(2n) = S(n)` and `S(2n+1) = S(n) + 1`. We model this by the following:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), - ....: left=vector([0, 1]), right=vector([1, 0])) - sage: S - 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... - sage: all(S[n] == sum(n.digits(2)) for n in srange(10)) - True - -Number of odd entries in Pascal's triangle ------------------------------------------- - -Let us consider the number of odd entries in the first `n` rows -of Pascals's triangle:: - - sage: @cached_function - ....: def u(n): - ....: if n <= 1: - ....: return n - ....: return 2 * u(n // 2) + u((n+1) // 2) - sage: tuple(u(n) for n in srange(10)) - (0, 1, 3, 5, 9, 11, 15, 19, 27, 29) - -There is a `2`-recursive sequence describing the numbers above as well:: - - sage: U = Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])), - ....: left=vector([0, 1]), right=vector([1, 0])).transposed() - sage: all(U[n] == u(n) for n in srange(30)) - True - - -Various -======= - -.. SEEALSO:: - - :mod:`recognizable series <sage.combinat.recognizable_series>`, - :mod:`sage.rings.cfinite_sequence`, - :mod:`sage.combinat.binary_recurrence_sequences`. - -AUTHORS: - -- Daniel Krenn (2016, 2021) -- Gabriel F. Lipnik (2021) - -ACKNOWLEDGEMENT: - -- Daniel Krenn is supported by the - Austrian Science Fund (FWF): P 24644-N26. -- Gabriel F. Lipnik is supported by the - Austrian Science Fund (FWF): W 1230. - - -Classes and Methods -=================== -""" -# **************************************************************************** -# Copyright (C) 2016 Daniel Krenn <dev@danielkrenn.at> -# 2021 Gabriel F. Lipnik <dev@gabriellipnik.at> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# https://www.gnu.org/licenses/ -# **************************************************************************** -from .recognizable_series import RecognizableSeries -from .recognizable_series import RecognizableSeriesSpace -from .recognizable_series import minimize_result -from sage.misc.cachefunc import cached_function, cached_method - - -class kRegularSequence(RecognizableSeries): - def __init__(self, parent, mu, left=None, right=None): - r""" - A `k`-regular sequence. - - INPUT: - - - ``parent`` -- an instance of :class:`kRegularSequenceSpace` - - - ``mu`` -- a family of square matrices, all of which have the - same dimension. The indices of this family are `0,...,k-1`. - ``mu`` may be a list or tuple of cardinality `k` - as well. See also - :meth:`~sage.combinat.recognizable_series.RecognizableSeries.mu`. - - - ``left`` -- (default: ``None``) a vector. - When evaluating the sequence, this vector is multiplied - from the left to the matrix product. If ``None``, then this - multiplication is skipped. - - - ``right`` -- (default: ``None``) a vector. - When evaluating the sequence, this vector is multiplied - from the right to the matrix product. If ``None``, then this - multiplication is skipped. - - EXAMPLES:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: S = Seq2((Matrix([[3, 6], [0, 1]]), Matrix([[0, -6], [1, 5]])), - ....: vector([0, 1]), vector([1, 0])).transposed(); S - 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ... - - We can access the coefficients of a sequence by - :: - - sage: S[5] - 11 - - or iterating over the first, say `10`, by - :: - - sage: from itertools import islice - sage: list(islice(S, 10)) - [0, 1, 3, 5, 9, 11, 15, 19, 27, 29] - - .. SEEALSO:: - - :doc:`k-regular sequence <k_regular_sequence>`, - :class:`kRegularSequenceSpace`. - """ - super().__init__(parent=parent, mu=mu, left=left, right=right) - - def _repr_(self): - r""" - Return a representation string of this `k`-regular sequence. - - OUTPUT: a string - - TESTS:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: s = Seq2((Matrix([[3, 6], [0, 1]]), Matrix([[0, -6], [1, 5]])), - ....: vector([0, 1]), vector([1, 0])).transposed() - sage: repr(s) # indirect doctest - '2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ...' - """ - from sage.misc.lazy_list import lazy_list_formatter - return lazy_list_formatter( - self, - name='{}-regular sequence'.format(self.parent().k), - opening_delimiter='', closing_delimiter='', - preview=10) - - @cached_method - def __getitem__(self, n, **kwds): - r""" - Return the `n`-th entry of this sequence. - - INPUT: - - - ``n`` -- a nonnegative integer - - OUTPUT: an element of the universe of the sequence - - EXAMPLES:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])), - ....: left=vector([0, 1]), right=vector([1, 0])) - sage: S[7] - 3 - - TESTS:: - - sage: S[-1] - Traceback (most recent call last): - ... - ValueError: value -1 of index is negative - - :: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: W = Seq2.indices() - sage: M0 = Matrix([[1, 0], [0, 1]]) - sage: M1 = Matrix([[0, -1], [1, 2]]) - sage: S = Seq2((M0, M1), vector([0, 1]), vector([1, 1])) - sage: S._mu_of_word_(W(0.digits(2))) == M0 - True - sage: S._mu_of_word_(W(1.digits(2))) == M1 - True - sage: S._mu_of_word_(W(3.digits(2))) == M1^2 - True - """ - return self.coefficient_of_word(self.parent()._n_to_index_(n), **kwds) - - def __iter__(self): - r""" - Return an iterator over the coefficients of this sequence. - - EXAMPLES:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])), - ....: left=vector([0, 1]), right=vector([1, 0])) - sage: from itertools import islice - sage: tuple(islice(S, 10)) - (0, 1, 1, 2, 1, 2, 2, 3, 1, 2) - - TESTS:: - - sage: it = iter(S) - sage: iter(it) is it - True - sage: iter(S) is not it - True - """ - from itertools import count - return iter(self[n] for n in count()) - - @minimize_result - def subsequence(self, a, b): - r""" - Return the subsequence with indices `an+b` of this - `k`-regular sequence. - - INPUT: - - - ``a`` -- a nonnegative integer - - - ``b`` -- an integer - - Alternatively, this is allowed to be a dictionary - `b_j \mapsto c_j`. If so and applied on `f(n)`, - the result will be the sum of all `c_j \cdot f(an+b_j)`. - - - ``minimize`` -- (default: ``None``) a boolean or ``None``. - If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, - if ``False``, then not. If this argument is ``None``, then - the default specified by the parent's ``minimize_results`` is used. - - OUTPUT: - - A :class:`kRegularSequence` - - .. NOTE:: - - If `b` is negative (i.e., right-shift), then the - coefficients when accessing negative indices are `0`. - - EXAMPLES:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - - We consider the sequence `C` with `C(n) = n` and - the following linear representation - corresponding to the vector `(n, 1)`:: - - sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])), - ....: vector([1, 0]), vector([0, 1])); C - 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... - - We now extract various subsequences of `C`:: - - sage: C.subsequence(2, 0) - 2-regular sequence 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, ... - - sage: S31 = C.subsequence(3, 1); S31 - 2-regular sequence 1, 4, 7, 10, 13, 16, 19, 22, 25, 28, ... - sage: S31.linear_representation() - ((1, 0), - Finite family {0: [ 0 1] - [-2 3], - 1: [ 6 -2] - [10 -3]}, - (1, 1)) - - sage: C.subsequence(3, 2) - 2-regular sequence 2, 5, 8, 11, 14, 17, 20, 23, 26, 29, ... - - :: - - sage: Srs = C.subsequence(1, -1); Srs - 2-regular sequence 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ... - sage: Srs.linear_representation() - ((1, 0, 0), - Finite family {0: [ 0 1 0] - [-2 3 0] - [-4 4 1], - 1: [ -2 2 0] - [ 0 0 1] - [ 12 -12 5]}, - (0, 0, 1)) - - We can build :meth:`backward_differences` manually by passing - a dictionary for the parameter ``b``:: - - sage: Sbd = C.subsequence(1, {0: 1, -1: -1}); Sbd - 2-regular sequence 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... - - TESTS: - - We check if the linear representation of the subsequences above - indeed represent the correct vector valued sequences:: - - sage: var('n') - n - - sage: def v(n): - ....: return vector([3*n + 1, 6*n + 1]) - sage: S31.mu[0] * v(n) == v(2*n) - True - sage: S31.mu[1] * v(n) == v(2*n + 1) - True - - sage: function('delta_0') - delta_0 - - sage: def simplify_delta(expr): - ....: return expr.subs({delta_0(2*n): delta_0(n), delta_0(2*n + 1): 0}) - - sage: def v(n): - ....: return vector([n -1 + delta_0(n), 2*n - 1 + delta_0(n), 4*n + 1]) - sage: simplify_delta(v(2*n) - Srs.mu[0]*v(n)).is_zero() - True - sage: simplify_delta(v(2*n + 1) - Srs.mu[1]*v(n)).is_zero() - True - - sage: def v(n): - ....: return vector([1 - delta_0(n), 1]) - - sage: simplify_delta(v(2*n) - Sbd.mu[0]*v(n)).is_zero() - True - sage: simplify_delta(v(2*n + 1) - Sbd.mu[1]*v(n)).is_zero() - True - - We check some corner-cases:: - - sage: C.subsequence(0, 4) - 2-regular sequence 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, ... - - :: - - sage: C.subsequence(1, 0, minimize=False) is C - True - - The following test that the range for `c` in the code - is sufficient:: - - sage: C.subsequence(1, -1, minimize=False) - 2-regular sequence 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ... - sage: C.subsequence(1, -2, minimize=False) - 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, ... - sage: C.subsequence(2, -1, minimize=False) - 2-regular sequence 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, ... - sage: C.subsequence(2, -2, minimize=False) - 2-regular sequence 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, ... - - sage: C.subsequence(2, 21, minimize=False) - 2-regular sequence 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, ... - sage: C.subsequence(2, 20, minimize=False) - 2-regular sequence 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, ... - sage: C.subsequence(2, 19, minimize=False) - 2-regular sequence 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, ... - sage: C.subsequence(2, -9, minimize=False) - 2-regular sequence 0, 0, 0, 0, 0, 1, 3, 5, 7, 9, ... - - sage: C.subsequence(3, 21, minimize=False) - 2-regular sequence 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, ... - sage: C.subsequence(3, 20, minimize=False) - 2-regular sequence 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, ... - sage: C.subsequence(3, 19, minimize=False) - 2-regular sequence 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, ... - sage: C.subsequence(3, 18, minimize=False) - 2-regular sequence 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, ... - - sage: C.subsequence(10, 2, minimize=False) - 2-regular sequence 2, 12, 22, 32, 42, 52, 62, 72, 82, 92, ... - sage: C.subsequence(10, 1, minimize=False) - 2-regular sequence 1, 11, 21, 31, 41, 51, 61, 71, 81, 91, ... - sage: C.subsequence(10, 0, minimize=False) - 2-regular sequence 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, ... - sage: C.subsequence(10, -1, minimize=False) - 2-regular sequence 0, 9, 19, 29, 39, 49, 59, 69, 79, 89, ... - sage: C.subsequence(10, -2, minimize=False) - 2-regular sequence 0, 8, 18, 28, 38, 48, 58, 68, 78, 88, ... - - :: - - sage: C.subsequence(-1, 0) - Traceback (most recent call last): - ... - ValueError: a=-1 is not nonnegative. - """ - from itertools import chain - from sage.rings.integer_ring import ZZ - - zero = ZZ(0) - a = ZZ(a) - if not isinstance(b, dict): - b = {ZZ(b): ZZ(1)} - - if a == 0: - return sum(c_j * self[b_j] * self.parent().one_hadamard() - for b_j, c_j in b.items()) - elif a == 1 and len(b) == 1 and zero in b: - return b[zero] * self - elif a < 0: - raise ValueError('a={} is not nonnegative.'.format(a)) - - from sage.matrix.constructor import Matrix - from sage.modules.free_module_element import vector - P = self.parent() - A = P.alphabet() - k = P.k - - # Below, we use a dynamic approach to find the shifts of the - # sequences in the kernel. Note that according to [AS2003]_, - # the static range - # [min(b, 0), max(a, a + b)) - # suffices. With B = |b| and A = max(a, B), we here obtain the range - # [-B, A] - # because of the following estimates: - # Let -B <= c <= A und set d = floor((ar+c) / k). Then - # -B = floor(-B) - # <= floor(-B / k) - # <= floor(c / k) - # <= d - # <= (ar+c) / k - # <= (A(k-1) + A) / k - # = A - # holds. - # For list-valued b, we use B = max{|beta| : beta in b} above. - - kernel = list(b) - - zero_M = self.mu[0].parent().zero() - zero_R = self.right.parent().zero() - # Let v(n) = self.__getitem__(n, multiply_left=False) - rule = {} - # We will construct `kernel` and `rule` in such a way that for all - # c in `kernel`, - # rule[r, c] = (f, d) - # holds for some 0 <= f < r and some d in `kernel` such that - # v(a(kn+r)+c) [a(kn+r) +c >= 0] = mu[f] v(an+d) [an+d >= 0]. - - ci = 0 - while ci < len(kernel): - c = kernel[ci] - for r in A: - # We now compute the contributions of v(an+c)[an >= 0] to - # the linear representation by using - # v(a(kn+r)+c) [a(kn+r)+c >= 0] - # = v(kan+ar+c) [kan+ar+c >= 0] - # = v(k(an+d)+f) [an+d >= 0] - # = mu[f] v(an+d) [an+d >= 0]. - d, f = (a * r + c).quo_rem(k) - if d not in kernel: - kernel.append(d) - rule[r, c] = (d, f) - ci += 1 - - def matrix_row(r, c): - d, f = rule[r, c] - return [self.mu[f] if d == j else zero_M for j in kernel] - - result = P.element_class( - P, - {r: Matrix.block([matrix_row(r, c) for c in kernel]) - for r in A}, - vector(chain.from_iterable( - b.get(c, 0) * self.left - for c in kernel)), - vector(chain.from_iterable( - (self.__getitem__(c, multiply_left=False) if c >= 0 else zero_R) - for c in kernel))) - - return result - - def shift_left(self, b=1, **kwds): - r""" - Return the sequence obtained by shifting - this `k`-regular sequence `b` steps to the left. - - INPUT: - - - ``b`` -- an integer - - - ``minimize`` -- (default: ``None``) a boolean or ``None``. - If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, - if ``False``, then not. If this argument is ``None``, then - the default specified by the parent's ``minimize_results`` is used. - - OUTPUT: - - A :class:`kRegularSequence` - - .. NOTE:: - - If `b` is negative (i.e., actually a right-shift), then the - coefficients when accessing negative indices are `0`. - - EXAMPLES:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])), - ....: vector([1, 0]), vector([0, 1])); C - 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... - - sage: C.shift_left() - 2-regular sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ... - sage: C.shift_left(3) - 2-regular sequence 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ... - sage: C.shift_left(-2) - 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, ... - - TESTS:: - - sage: C.shift_left(0) == C - True - sage: C.shift_left(2).shift_right(2) - 2-regular sequence 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, ... - """ - return self.subsequence(1, b, **kwds) - - def shift_right(self, b=1, **kwds): - r""" - Return the sequence obtained by shifting - this `k`-regular sequence `b` steps to the right. - - INPUT: - - - ``b`` -- an integer - - - ``minimize`` -- (default: ``None``) a boolean or ``None``. - If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, - if ``False``, then not. If this argument is ``None``, then - the default specified by the parent's ``minimize_results`` is used. - - OUTPUT: - - A :class:`kRegularSequence` - - .. NOTE:: - - If `b` is positive (i.e., indeed a right-shift), then the - coefficients when accessing negative indices are `0`. - - EXAMPLES:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])), - ....: vector([1, 0]), vector([0, 1])); C - 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... - - sage: C.shift_right() - 2-regular sequence 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ... - sage: C.shift_right(3) - 2-regular sequence 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, ... - sage: C.shift_right(-2) - 2-regular sequence 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... - - TESTS:: - - sage: C.shift_right(0) == C - True - sage: C.shift_right().shift_left() - 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... - sage: C.shift_right(2).shift_left(2) - 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... - sage: _ == C - True - """ - return self.subsequence(1, -b, **kwds) - - def backward_differences(self, **kwds): - r""" - Return the sequence of backward differences of this - `k`-regular sequence. - - INPUT: - - - ``minimize`` -- (default: ``None``) a boolean or ``None``. - If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, - if ``False``, then not. If this argument is ``None``, then - the default specified by the parent's ``minimize_results`` is used. - - OUTPUT: - - A :class:`kRegularSequence` - - .. NOTE:: - - The coefficient to the index `-1` is `0`. - - EXAMPLES:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])), - ....: vector([1, 0]), vector([0, 1])) - sage: C - 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... - sage: C.backward_differences() - 2-regular sequence 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... - - :: - - sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), - ....: vector([1, 0]), vector([1, 1])) - sage: E - 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ... - sage: E.backward_differences() - 2-regular sequence 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, ... - """ - return self.subsequence(1, {0: 1, -1: -1}, **kwds) - - def forward_differences(self, **kwds): - r""" - Return the sequence of forward differences of this - `k`-regular sequence. - - INPUT: - - - ``minimize`` -- (default: ``None``) a boolean or ``None``. - If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, - if ``False``, then not. If this argument is ``None``, then - the default specified by the parent's ``minimize_results`` is used. - - OUTPUT: - - A :class:`kRegularSequence` - - EXAMPLES:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])), - ....: vector([1, 0]), vector([0, 1])) - sage: C - 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... - sage: C.forward_differences() - 2-regular sequence 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... - - :: - - sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), - ....: vector([1, 0]), vector([1, 1])) - sage: E - 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ... - sage: E.forward_differences() - 2-regular sequence -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, ... - """ - return self.subsequence(1, {1: 1, 0: -1}, **kwds) - - @minimize_result - def partial_sums(self, include_n=False): - r""" - Return the sequence of partial sums of this - `k`-regular sequence. That is, the `n`th entry of the result - is the sum of the first `n` entries in the original sequence. - - INPUT: - - - ``include_n`` -- (default: ``False``) a boolean. If set, then - the `n`-th entry of the result is the sum of the entries up - to index `n` (included). - - - ``minimize`` -- (default: ``None``) a boolean or ``None``. - If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, - if ``False``, then not. If this argument is ``None``, then - the default specified by the parent's ``minimize_results`` is used. - - OUTPUT: - - A :class:`kRegularSequence` - - EXAMPLES:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - - sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), - ....: vector([1, 0]), vector([1, 1])) - sage: E - 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ... - sage: E.partial_sums() - 2-regular sequence 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, ... - sage: E.partial_sums(include_n=True) - 2-regular sequence 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, ... - - :: - - sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])), - ....: vector([1, 0]), vector([0, 1])) - sage: C - 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... - sage: C.partial_sums() - 2-regular sequence 0, 0, 1, 3, 6, 10, 15, 21, 28, 36, ... - sage: C.partial_sums(include_n=True) - 2-regular sequence 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, ... - - TESTS:: - - sage: E.linear_representation() - ((1, 0), - Finite family {0: [0 1] - [0 1], - 1: [0 0] - [0 1]}, - (1, 1)) - sage: P = E.partial_sums(minimize=False) - sage: P.linear_representation() - ((1, 0, -1, 0), - Finite family {0: [ 0 1| 0 0] - [ 0 2| 0 -1] - [-----+-----] - [ 0 0| 0 1] - [ 0 0| 0 1], - 1: [0 1|0 0] - [0 2|0 0] - [---+---] - [0 0|0 0] - [0 0|0 1]}, - (1, 1, 1, 1)) - """ - from itertools import chain - from sage.matrix.constructor import Matrix - from sage.matrix.special import zero_matrix - from sage.modules.free_module_element import vector - - P = self.parent() - A = P.alphabet() - k = P.k - dim = self.dimension() - - B = {r: sum(self.mu[a] for a in A[r:]) for r in A} - Z = zero_matrix(dim) - B[k] = Z - - result = P.element_class( - P, - {r: Matrix.block([[B[0], -B[r + 1]], [Z, self.mu[r]]]) for r in A}, - vector(chain(self.left, - (dim * (0,) if include_n else -self.left))), - vector(chain(self.right, self.right))) - - return result - - -def _pickle_kRegularSequenceSpace(k, coefficients, category): - r""" - Pickle helper. - - TESTS:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: from sage.combinat.k_regular_sequence import _pickle_kRegularSequenceSpace - sage: _pickle_kRegularSequenceSpace( - ....: Seq2.k, Seq2.coefficient_ring(), Seq2.category()) - Space of 2-regular sequences over Integer Ring - """ - return kRegularSequenceSpace(k, coefficients, category=category) - - -class kRegularSequenceSpace(RecognizableSeriesSpace): - r""" - The space of `k`-regular Sequences over the given ``coefficient_ring``. - - INPUT: - - - ``k`` -- an integer at least `2` specifying the base - - - ``coefficient_ring`` -- a (semi-)ring - - - ``category`` -- (default: ``None``) the category of this - space - - EXAMPLES:: - - sage: kRegularSequenceSpace(2, ZZ) - Space of 2-regular sequences over Integer Ring - sage: kRegularSequenceSpace(3, ZZ) - Space of 3-regular sequences over Integer Ring - - .. SEEALSO:: - - :doc:`k-regular sequence <k_regular_sequence>`, - :class:`kRegularSequence`. - """ - Element = kRegularSequence - - @classmethod - def __normalize__(cls, k, coefficient_ring, **kwds): - r""" - Normalizes the input in order to ensure a unique - representation. - - For more information see :class:`kRegularSequenceSpace`. - - TESTS:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: Seq2.category() - Category of modules over Integer Ring - sage: Seq2.alphabet() - {0, 1} - """ - from sage.arith.srange import srange - nargs = super().__normalize__(coefficient_ring, - alphabet=srange(k), **kwds) - return (k,) + nargs - - def __init__(self, k, *args, **kwds): - r""" - See :class:`kRegularSequenceSpace` for details. - - INPUT: - - - ``k`` -- an integer at least `2` specifying the base - - Other input arguments are passed on to - :meth:`~sage.combinat.recognizable_series.RecognizableSeriesSpace.__init__`. - - TESTS:: - - sage: kRegularSequenceSpace(2, ZZ) - Space of 2-regular sequences over Integer Ring - sage: kRegularSequenceSpace(3, ZZ) - Space of 3-regular sequences over Integer Ring - - :: - - sage: from itertools import islice - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: TestSuite(Seq2).run( # long time - ....: elements=tuple(islice(Seq2.some_elements(), 4))) - - .. SEEALSO:: - - :doc:`k-regular sequence <k_regular_sequence>`, - :class:`kRegularSequence`. - """ - self.k = k - super().__init__(*args, **kwds) - - def __reduce__(self): - r""" - Pickling support. - - TESTS:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: loads(dumps(Seq2)) # indirect doctest - Space of 2-regular sequences over Integer Ring - """ - return _pickle_kRegularSequenceSpace, \ - (self.k, self.coefficient_ring(), self.category()) - - def _repr_(self): - r""" - Return a representation string of this `k`-regular sequence space. - - OUTPUT: a string - - TESTS:: - - sage: repr(kRegularSequenceSpace(2, ZZ)) # indirect doctest - 'Space of 2-regular sequences over Integer Ring' - """ - return 'Space of {}-regular sequences over {}'.format(self.k, self.base()) - - def _n_to_index_(self, n): - r""" - Convert `n` to an index usable by the underlying - recognizable series. - - INPUT: - - - ``n`` -- a nonnegative integer - - OUTPUT: a word - - TESTS:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: Seq2._n_to_index_(6) - word: 011 - sage: Seq2._n_to_index_(-1) - Traceback (most recent call last): - ... - ValueError: value -1 of index is negative - """ - from sage.rings.integer_ring import ZZ - n = ZZ(n) - W = self.indices() - try: - return W(n.digits(self.k)) - except OverflowError: - raise ValueError('value {} of index is negative'.format(n)) from None - - def from_recurrence(self, *args, **kwds): - r""" - Construct the unique `k`-regular sequence which fulfills the given - recurrence relations and initial values. The recurrence relations have to - have the specific shape of `k`-recursive sequences as described in [HKL2021]_, - and are either given as symbolic equations, e.g., - - :: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: var('n') - n - sage: function('f') - f - sage: Seq2.from_recurrence([ - ....: f(2*n) == 2*f(n), f(2*n + 1) == 3*f(n) + 4*f(n - 1), - ....: f(0) == 0, f(1) == 1], f, n) - 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 10, 6, 17, ... - - or via the parameters of the `k`-recursive sequence as described in the input - block below:: - - sage: Seq2.from_recurrence(M=1, m=0, - ....: coeffs={(0, 0): 2, (1, 0): 3, (1, -1): 4}, - ....: initial_values={0: 0, 1: 1}) - 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 10, 6, 17, ... - - INPUT: - - Positional arguments: - - If the recurrence relations are represented by symbolic equations, then - the following arguments are required: - - - ``equations`` -- A list of equations where the elements have - either the form - - - `f(k^M n + r) = c_{r,l} f(k^m n + l) + c_{r,l + 1} f(k^m n - + l + 1) + ... + c_{r,u} f(k^m n + u)` for some integers - `0 \leq r < k^M`, `M > m \geq 0` and `l \leq u`, and some - coefficients `c_{r,j}` from the (semi)ring ``coefficients`` - of the corresponding :class:`kRegularSequenceSpace`, valid - for all integers `n \geq \text{offset}` for some integer - `\text{offset} \geq \max(-l/k^m, 0)` (default: ``0``), and - there is an equation of this form (with the same - parameters `M` and `m`) for all `r` - - or the form - - - ``f(k) == t`` for some integer ``k`` and some ``t`` from the (semi)ring - ``coefficient_ring``. - - The recurrence relations above uniquely determine a `k`-regular sequence; - see [HKL2021]_ for further information. - - - ``function`` -- symbolic function ``f`` occurring in the equations - - - ``var`` -- symbolic variable (``n`` in the above description of - ``equations``) - - The following second representation of the recurrence relations is - particularly useful for cases where ``coefficient_ring`` is not - compatible with :class:`sage.symbolic.ring.SymbolicRing`. Then the - following arguments are required: - - - ``M`` -- parameter of the recursive sequences, - see [HKL2021]_, Definition 3.1, as well as in the description of - ``equations`` above - - - ``m`` -- parameter of the recursive sequences, - see [HKL2021]_, Definition 3.1, as well as in the description of - ``equations`` above - - - ``coeffs`` -- a dictionary where ``coeffs[(r, j)]`` is the - coefficient `c_{r,j}` as given in the description of ``equations`` above. - If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``, then it is - assumed to be zero. - - - ``initial_values`` -- a dictionary mapping integers ``n`` to the - ``n``-th value of the sequence - - Optional keyword-only argument: - - - ``offset`` -- (default: ``0``) an integer. See explanation of - ``equations`` above. - - - ``inhomogeneities`` -- (default: ``{}``) a dictionary - mapping integers ``r`` to the inhomogeneity `g_r` as given - in [HKL2021]_, Corollary D. All inhomogeneities have to be - regular sequences from ``self`` or elements of ``coefficient_ring``. - - OUTPUT: a :class:`kRegularSequence` - - EXAMPLES: - - Stern--Brocot Sequence:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: var('n') - n - sage: function('f') - f - sage: SB = Seq2.from_recurrence([ - ....: f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1), - ....: f(0) == 0, f(1) == 1], f, n) - sage: SB - 2-regular sequence 0, 1, 1, 2, 1, 3, 2, 3, 1, 4, ... - - Number of Odd Entries in Pascal's Triangle:: - - sage: Seq2.from_recurrence([ - ....: f(2*n) == 3*f(n), f(2*n + 1) == 2*f(n) + f(n + 1), - ....: f(0) == 0, f(1) == 1], f, n) - 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ... - - Number of Unbordered Factors in the Thue--Morse Sequence:: - - sage: UB = Seq2.from_recurrence([ - ....: f(8*n) == 2*f(4*n), - ....: f(8*n + 1) == f(4*n + 1), - ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3), - ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2), - ....: f(8*n + 4) == 2*f(4*n + 2), - ....: f(8*n + 5) == f(4*n + 3), - ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3), - ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), - ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, - ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, - ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, - ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, - ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3) - sage: UB - 2-regular sequence 1, 2, 2, 4, 2, 4, 6, 0, 4, 4, ... - - Binary sum of digits `S(n)`, characterized by the recurrence relations - `S(4n) = S(2n)`, `S(4n + 1) = S(2n + 1)`, `S(4n + 2) = S(2n + 1)` and - `S(4n + 3) = -S(2n) + 2S(2n + 1)`:: - - sage: S = Seq2.from_recurrence([ - ....: f(4*n) == f(2*n), - ....: f(4*n + 1) == f(2*n + 1), - ....: f(4*n + 2) == f(2*n + 1), - ....: f(4*n + 3) == -f(2*n) + 2*f(2*n + 1), - ....: f(0) == 0, f(1) == 1], f, n) - sage: S - 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... - - In order to check if this sequence is indeed the binary sum of digits, - we construct it directly via its linear representation and compare it - with ``S``:: - - sage: S2 = Seq2( - ....: (Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), - ....: left=vector([0, 1]), right=vector([1, 0])) - sage: (S - S2).is_trivial_zero() - True - - Alternatively, we can also use the simpler but inhomogeneous recurrence relations - `S(2n) = S(n)` and `S(2n+1) = S(n) + 1` via direct parameters:: - - sage: S3 = Seq2.from_recurrence(M=1, m=0, - ....: coeffs={(0, 0): 1, (1, 0): 1}, - ....: initial_values={0: 0, 1: 1}, - ....: inhomogeneities={1: 1}) - sage: S3 - 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... - sage: (S3 - S2).is_trivial_zero() - True - - Number of Non-Zero Elements in the Generalized Pascal's Triangle (see [LRS2017]_):: - - sage: Seq2 = kRegularSequenceSpace(2, QQ) - sage: P = Seq2.from_recurrence([ - ....: f(4*n) == 5/3*f(2*n) - 1/3*f(2*n + 1), - ....: f(4*n + 1) == 4/3*f(2*n) + 1/3*f(2*n + 1), - ....: f(4*n + 2) == 1/3*f(2*n) + 4/3*f(2*n + 1), - ....: f(4*n + 3) == -1/3*f(2*n) + 5/3*f(2*n + 1), - ....: f(0) == 1, f(1) == 2], f, n) - sage: P - 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... - - Finally, the same sequence can also be obtained via direct parameters - without symbolic equations:: - - sage: Seq2.from_recurrence(M=2, m=1, - ....: coeffs={(0, 0): 5/3, (0, 1): -1/3, - ....: (1, 0): 4/3, (1, 1): 1/3, - ....: (2, 0): 1/3, (2, 1): 4/3, - ....: (3, 0): -1/3, (3, 1): 5/3}, - ....: initial_values={0: 1, 1: 2}) - 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... - - TESTS:: - - sage: Seq2.from_recurrence([ - ....: f(4*n) == f(2*n), - ....: f(4*n + 1) == f(2*n), - ....: f(4*n + 2) == f(2*n), - ....: f(4*n + 3) == f(2*n + 1024), - ....: f(0) == 1, f(1) == 1], f, n, offset=2) - Traceback (most recent call last): - ... - ValueError: Initial values for arguments in [2, ..., 2044] are missing. - - :: - - sage: S = Seq2.from_recurrence([ - ....: f(4*n) == f(2*n), - ....: f(4*n + 1) == f(2*n), - ....: f(4*n + 2) == f(2*n), - ....: f(4*n + 3) == f(2*n + 16), - ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3, f(4) == 4, - ....: f(5) == 5, f(6) == 6, f(7) == 7, f(16) == 4, f(18) == 4, - ....: f(20) == 4, f(22) == 4, f(24) == 6, f(26) == 6, f(28) == 6], - ....: f, n, offset=2) - sage: all([S[4*i] == S[2*i] and - ....: S[4*i + 1] == S[2*i] and - ....: S[4*i + 2] == S[2*i] and - ....: S[4*i + 3] == S[2*i + 16] for i in srange(2, 100)]) - True - - :: - - sage: S = Seq2.from_recurrence([ - ....: f(4*n) == f(2*n), - ....: f(4*n + 1) == f(2*n), - ....: f(4*n + 2) == f(2*n), - ....: f(4*n + 3) == f(2*n - 16), - ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3, f(4) == 4, - ....: f(5) == 5, f(6) == 6, f(7) == 7, f(8) == 8, f(9) == 9, - ....: f(10) == 10, f(11) == 11, f(12) == 12, f(13) == 13, - ....: f(14) == 14, f(15) == 15, f(16) == 16, f(17) == 17, - ....: f(18) == 18, f(19) == 19, f(20) == 20, f(21) == 21, - ....: f(22) == 22, f(23) == 23, f(24) == 24, f(25) == 25, - ....: f(26) == 26, f(27) == 27, f(28) == 28, f(29) == 29, - ....: f(30) == 30, f(31) == 31], f, n, offset=8) - sage: all([S[4*i] == S[2*i] and - ....: S[4*i + 1] == S[2*i] and - ....: S[4*i + 2] == S[2*i] and - ....: S[4*i + 3] == S[2*i - 16] for i in srange(8, 100)]) - True - - Same test with different variable and function names:: - - sage: var('m') - m - sage: function('g') - g - sage: T = Seq2.from_recurrence([ - ....: g(4*m) == g(2*m), - ....: g(4*m + 1) == g(2*m), - ....: g(4*m + 2) == g(2*m), - ....: g(4*m + 3) == g(2*m - 16), - ....: g(0) == 1, g(1) == 1, g(2) == 2, g(3) == 3, g(4) == 4, - ....: g(5) == 5, g(6) == 6, g(7) == 7, g(8) == 8, g(9) == 9, - ....: g(10) == 10, g(11) == 11, g(12) == 12, g(13) == 13, - ....: g(14) == 14, g(15) == 15, g(16) == 16, g(17) == 17, - ....: g(18) == 18, g(19) == 19, g(20) == 20, g(21) == 21, - ....: g(22) == 22, g(23) == 23, g(24) == 24, g(25) == 25, - ....: g(26) == 26, g(27) == 27, g(28) == 28, g(29) == 29, - ....: g(30) == 30, g(31) == 31], g, m, offset=8) - sage: (S - T).is_trivial_zero() - True - - Zero-sequence with non-zero initial values:: - - sage: Seq2.from_recurrence([ - ....: f(2*n) == 0, f(2*n + 1) == 0, - ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n) - Traceback (most recent call last): - ... - ValueError: Initial value for argument 0 does not match with the given recurrence relations. - - :: - - sage: Seq2.from_recurrence([ - ....: f(2*n) == 0, f(2*n + 1) == 0, - ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n, offset=2) - 2-regular sequence 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, ... - - Check if inhomogeneities `0` do not change the sequence:: - - sage: Seq2.from_recurrence([ - ....: f(2*n) == 0, f(2*n + 1) == 0, - ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n, offset=2, - ....: inhomogeneities={0: 0, 1: Seq2.zero()}) - 2-regular sequence 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, ... - - :: - - sage: S = Seq2([matrix([[3/2, -1, 1], [0, 1/2, 1/2], [0, -1, 2]]), - ....: matrix([[-1, 0, 1], [1, 5, -5], [-4, 0, 0]])], - ....: left=vector([1, 2, 3]), - ....: right=vector([0, 1, 1])) - sage: T = Seq2.from_recurrence(M=3, m=2, - ....: coeffs={}, - ....: initial_values={0: S[0]}, - ....: inhomogeneities={i: S.subsequence(2**3, i) for i in srange(2**3)}) - sage: (S - T).is_trivial_zero() - True - - Connection between the Stern--Brocot sequence and the number - of non-zero elements in the generalized Pascal's triangle (see - [LRS2017]_):: - - sage: U = Seq2.from_recurrence(M=1, m=0, - ....: coeffs={(0, 0): 1}, - ....: initial_values={0: 0, 1: 1}, - ....: inhomogeneities={1: P}) - sage: (U - Seq2(SB)).is_trivial_zero() - True - - :: - - sage: U = Seq2.from_recurrence(M=1, m=0, - ....: coeffs={}, - ....: initial_values={0: 0, 1: 1}, - ....: inhomogeneities={0: SB, 1: P}) - sage: (U - Seq2(SB)).is_trivial_zero() - True - - Number of Unbordered Factors in the Thue--Morse Sequence, but partly - encoded with inhomogeneities:: - - sage: UB2 = Seq2.from_recurrence([ - ....: f(8*n) == 2*f(4*n), - ....: f(8*n + 1) == f(4*n + 1), - ....: f(8*n + 2) == f(4*n + 1), - ....: f(8*n + 3) == f(4*n + 2), - ....: f(8*n + 4) == 2*f(4*n + 2), - ....: f(8*n + 5) == f(4*n + 3), - ....: f(8*n + 6) == -f(4*n + 1), - ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), - ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, - ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, - ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, - ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, - ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3, - ....: inhomogeneities={2: UB.subsequence(4, 3), 3: -UB.subsequence(4, 1), - ....: 6: UB.subsequence(4, 2) + UB.subsequence(4, 3)}) - sage: (UB2 - Seq2(UB)).is_trivial_zero() - True - """ - RP = RecurrenceParser(self.k, self.coefficient_ring()) - mu, left, right = RP(*args, **kwds) - return self(mu, left, right) - - -class RecurrenceParser(): - r""" - A parser for recurrence relations that allow - the construction of a `k`-linear representation - for the sequence satisfying these recurrence relations. - - This is used by :meth:`kRegularSequenceSpace.from_recurrence` - to construct a :class:`kRegularSequence`. - """ - - def __init__(self, k, coefficient_ring): - r""" - See :class:`RecurrenceParser`. - - INPUT: - - - ``k`` -- an integer at least `2` specifying the base - - - ``coefficient_ring`` -- a ring. - - These are the same parameters used when creating - a :class:`kRegularSequenceSpace`. - - TESTS:: - - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RecurrenceParser(2, ZZ) - <sage.combinat.k_regular_sequence.RecurrenceParser object at 0x...> - """ - self.k = k - self.coefficient_ring = coefficient_ring - - def parse_recurrence(self, equations, function, var): - r""" - Parse recurrence relations as admissible in :meth:`kRegularSequenceSpace.from_recurrence`. - - INPUT: - - All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. - - OUTPUT: a tuple consisting of - - - ``M``, ``m`` -- see :meth:`kRegularSequenceSpace.from_recurrence` - - - ``coeffs`` -- see :meth:`kRegularSequenceSpace.from_recurrence` - - - ``initial_values`` -- see :meth:`kRegularSequenceSpace.from_recurrence` - - EXAMPLES:: - - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RP = RecurrenceParser(2, ZZ) - sage: var('n') - n - sage: function('f') - f - sage: RP.parse_recurrence([ - ....: f(4*n) == f(2*n) + 2*f(2*n + 1) + 3*f(2*n - 2), - ....: f(4*n + 1) == 4*f(2*n) + 5*f(2*n + 1) + 6*f(2*n - 2), - ....: f(4*n + 2) == 7*f(2*n) + 8*f(2*n + 1) + 9*f(2*n - 2), - ....: f(4*n + 3) == 10*f(2*n) + 11*f(2*n + 1) + 12*f(2*n - 2), - ....: f(0) == 1, f(1) == 2, f(2) == 1], f, n) - (2, 1, {(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4, - (1, 1): 5, (2, -2): 9, (2, 0): 7, (2, 1): 8, (3, -2): 12, (3, 0): 10, - (3, 1): 11}, {0: 1, 1: 2, 2: 1}) - - Stern--Brocot Sequence:: - - sage: RP.parse_recurrence([ - ....: f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1), - ....: f(0) == 0, f(1) == 1], f, n) - (1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 0, 1: 1}) - - .. SEEALSO:: - - :meth:`kRegularSequenceSpace.from_recurrence` - - TESTS: - - The following tests check that the equations are well-formed:: - - sage: RP.parse_recurrence([], f, n) - Traceback (most recent call last): - ... - ValueError: List of recurrence equations is empty. - - :: - - sage: RP.parse_recurrence([f(4*n + 1)], f, n) - Traceback (most recent call last): - ... - ValueError: f(4*n + 1) is not an equation with ==. - - :: - - sage: RP.parse_recurrence([42], f, n) - Traceback (most recent call last): - ... - ValueError: 42 is not a symbolic expression. - - :: - - sage: RP.parse_recurrence([f(2*n) + 1 == f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(2*n) + 1 in the equation f(2*n) + 1 == f(n) is - not an evaluation of f. - - :: - - sage: RP.parse_recurrence([f(2*n, 5) == 3], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(2*n, 5) in the equation f(2*n, 5) == 3 does not - have one argument. - - :: - - sage: RP.parse_recurrence([f() == 3], f, n) - Traceback (most recent call last): - ... - ValueError: Term f() in the equation f() == 3 does not have one - argument. - - :: - - sage: RP.parse_recurrence([f(1/n + 1) == f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(1/n + 1) in the equation f(1/n + 1) == f(n): - 1/n + 1 is not a polynomial in n with integer coefficients. - - :: - - sage: RP.parse_recurrence([f(2*n + 1/2) == f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(2*n + 1/2) in the equation f(2*n + 1/2) == f(n): - 2*n + 1/2 is not a polynomial in n with integer coefficients. - - :: - - sage: RP.parse_recurrence([f(4*n^2) == f(2*n^2)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(4*n^2) in the equation f(4*n^2) == f(2*n^2): - 4*n^2 is not a polynomial in n of degree smaller than 2. - - :: - - sage: RP.parse_recurrence([f(42) == 1/2], f, n) - Traceback (most recent call last): - ... - ValueError: Initial value 1/2 given by the equation f(42) == (1/2) - is not in Integer Ring. - - :: - - sage: RP.parse_recurrence([f(42) == 0, f(42) == 1], f, n) - Traceback (most recent call last): - ... - ValueError: Initial value f(42) is given twice. - - :: - - sage: RP.parse_recurrence([f(42) == f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Initial value f(n) given by the equation f(42) == f(n) - is not in Integer Ring. - - :: - - sage: RP.parse_recurrence([f(4*n) == f(n), f(2*n) == f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(2*n) in the equation f(2*n) == f(n): 2 does not - equal 4. Expected subsequence modulo 4 as in another equation, got - subsequence modulo 2. - - :: - - sage: RP.parse_recurrence([f(3*n + 1) == f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(3*n + 1) in the equation f(3*n + 1) == f(n): - 3 is not a power of 2. - - :: - - sage: RP.parse_recurrence([f(n + 1) == f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(n + 1) in the equation f(n + 1) == f(n): - 1 is less than 2. Modulus must be at least 2. - - :: - - sage: RP.parse_recurrence([f(2*n) == f(n), f(2*n) == 0], f, n) - Traceback (most recent call last): - ... - ValueError: There are more than one recurrence relation for f(2*n). - - :: - - sage: RP.parse_recurrence([f(2*n + 2) == f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(2*n + 2) in the equation f(2*n + 2) == f(n): - remainder 2 is not smaller than modulus 2. - - :: - - sage: RP.parse_recurrence([f(2*n - 1) == f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(2*n - 1) in the equation f(2*n - 1) == f(n): - remainder -1 is smaller than 0. - - :: - - sage: RP.parse_recurrence([f(2*n) == 2*n], f, n) - Traceback (most recent call last): - ... - ValueError: Term 2*n in the equation f(2*n) == 2*n does not - contain f. - - :: - - sage: RP.parse_recurrence([f(2*n) == 1/2*f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term 1/2*f(n) in the equation f(2*n) == 1/2*f(n): - 1/2 is not a valid coefficient since it is not in Integer Ring. - - :: - - sage: RP.parse_recurrence([f(2*n) == 1/f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: 1/f(n) is not a valid right hand side. - - :: - - sage: RP.parse_recurrence([f(2*n) == 2*n*f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: 2*n*f(n) is not a valid right hand side. - - :: - - sage: RP.parse_recurrence([f(2*n) == 2*f(n, 5)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(n, 5) in the equation f(2*n) == 2*f(n, 5) - has more than one argument. - - :: - - sage: RP.parse_recurrence([f(2*n) == 2*f()], f, n) - Traceback (most recent call last): - ... - ValueError: Term f() in the equation f(2*n) == 2*f() has no argument. - - :: - - sage: RP.parse_recurrence([f(2*n) == 1/f(n) + 2*f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term 1/f(n) in the equation f(2*n) == 1/f(n) + 2*f(n) - is not a valid summand. - - :: - - sage: RP.parse_recurrence([f(2*n) == 2*f(1/n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(1/n) in the equation f(2*n) == 2*f(1/n): - 1/n is not a polynomial in n with integer coefficients. - - :: - - sage: RP.parse_recurrence([f(2*n) == f(n + 1/2)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(n + 1/2) in the equation f(2*n) == f(n + 1/2): - n + 1/2 is not a polynomial in n with integer coefficients. - - :: - - sage: RP.parse_recurrence([f(2*n) == f(1/2*n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(1/2*n) in the equation f(2*n) == f(1/2*n): - 1/2*n is not a polynomial in n with integer coefficients. - - :: - - sage: RP.parse_recurrence([f(2*n) == f(n^2 + 1)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(n^2 + 1) in the equation f(2*n) == f(n^2 + 1): - polynomial n^2 + 1 does not have degree 1. - - :: - - sage: RP.parse_recurrence([f(2*n) == f(1)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(1) in the equation f(2*n) == f(1): - polynomial 1 does not have degree 1. - - :: - - sage: RP.parse_recurrence([f(4*n) == f(2*n) + f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(n) in the equation f(4*n) == f(2*n) + f(n): - 1 does not equal 2. Expected subsequence modulo 2 as in another - summand or equation, got subsequence modulo 1. - - :: - - sage: RP.parse_recurrence([f(4*n) == f(2*n), f(4*n + 1) == f(n)], - ....: f, n) - Traceback (most recent call last): - ... - ValueError: Term f(n) in the equation f(4*n + 1) == f(n): 1 does not - equal 2. Expected subsequence modulo 2 as in another summand or - equation, got subsequence modulo 1. - - :: - - sage: RP.parse_recurrence([f(4*n) == f(3*n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(3*n) in the equation f(4*n) == f(3*n): 3 is not - a power of 2. - - :: - - sage: RP.parse_recurrence([f(2*n) == f(4*n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(4*n) in the equation f(2*n) == f(4*n): - 4 is not smaller than 2. - - :: - - sage: RP.parse_recurrence([f(2*n) == f(2*n)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(2*n) in the equation f(2*n) == f(2*n): - 2 is not smaller than 2. - - :: - - sage: RP.parse_recurrence([f(2*n) == f(n)], f, n) - Traceback (most recent call last): - ... - ValueError: Recurrence relations for [f(2*n + 1)] are missing. - - :: - - sage: RP.parse_recurrence([f(4*n) == f(n), f(4*n + 3) == 0], f, n) - Traceback (most recent call last): - ... - ValueError: Recurrence relations for [f(4*n + 1), f(4*n + 2)] - are missing. - - :: - - sage: RP.parse_recurrence([f(42) == 0], f, n) - Traceback (most recent call last): - ... - ValueError: No recurrence relations are given. - - :: - - sage: RP.parse_recurrence( - ....: [f(4*n + r) == f(n) for r in srange(4)], f, n) - (2, 0, {(0, 0): 1, (1, 0): 1, (2, 0): 1, (3, 0): 1}, {}) - - :: - - sage: RP.parse_recurrence( - ....: [f(8*n) == f(n)] + - ....: [f(8*n + r) == f(2*n) for r in srange(1,8)], f, n) - Traceback (most recent call last): - ... - ValueError: Term f(2*n) in the equation f(8*n + 1) == f(2*n): - 2 does not equal 1. Expected subsequence modulo 1 as in another - summand or equation, got subsequence modulo 2. - - Finally, also for the zero-sequence the output is as expected:: - - sage: RP.parse_recurrence([f(2*n) == 0, f(2*n + 1) == 0], f, n) - (1, 0, {}, {}) - - We check that the output is of the correct type (:trac:`33158`):: - - sage: RP = RecurrenceParser(2, QQ) - sage: equations = [ - ....: f(4*n) == 5/3*f(2*n) - 1/3*f(2*n + 1), - ....: f(4*n + 1) == 4/3*f(2*n) + 1/3*f(2*n + 1), - ....: f(4*n + 2) == 1/3*f(2*n) + 4/3*f(2*n + 1), - ....: f(4*n + 3) == -1/3*f(2*n) + 5/3*f(2*n + 1), - ....: f(0) == 1, f(1) == 2] - sage: M, m, coeffs, initial_values = RP.parse_recurrence(equations, f, n) - sage: M.parent() - Integer Ring - sage: m.parent() - Integer Ring - sage: all(v.parent() == QQ for v in coeffs.values()) - True - sage: all(v.parent() == QQ for v in initial_values.values()) - True - - This results in giving the correct (see :trac:`33158`) minimization in:: - - sage: Seq2 = kRegularSequenceSpace(2, QQ) - sage: P = Seq2.from_recurrence(equations, f, n) - sage: P - 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... - sage: P.minimized() - 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... - """ - from sage.arith.srange import srange - from sage.functions.log import log - from sage.rings.integer_ring import ZZ - from sage.symbolic.operators import add_vararg, mul_vararg, operator - - k = self.k - coefficient_ring = self.coefficient_ring - M = None - m = None - coeffs = {} - initial_values = {} - remainders = set() - - def parse_multiplication(op, eq): - operands = op.operands() - assert op.operator() == mul_vararg and len(operands) == 2 - if operands[1].operator() == function: - return [operands[0], operands[1]] - elif operands[0].operator() == function: - return [operands[1], operands[0]] - else: - raise ValueError('Term %s in the equation %s ' - 'does not contain %s.' - % (op, eq, function)) - - def parse_one_summand(summand, eq): - if summand.operator() == mul_vararg: - coeff, op = parse_multiplication(summand, eq) - elif summand.operator() == function: - coeff, op = 1, summand - else: - raise ValueError('Term %s in the equation %s is not a valid summand.' - % (summand, eq)) - try: - coeff = coefficient_ring(coeff) - except (TypeError, ValueError): - raise ValueError("Term %s in the equation %s: " - "%s is not a valid coefficient " - "since it is not in %s." - % (summand, eq, coeff, coefficient_ring)) from None - if len(op.operands()) > 1: - raise ValueError('Term %s in the equation %s has more than one argument.' - % (op, eq)) - elif len(op.operands()) == 0: - raise ValueError('Term %s in the equation %s has no argument.' - % (op, eq)) - try: - poly = ZZ[var](op.operands()[0]) - except TypeError: - raise ValueError('Term %s in the equation %s: ' - '%s is not a polynomial in %s with integer coefficients.' - % (op, eq, op.operands()[0], var)) from None - if poly.degree() != 1: - raise ValueError("Term %s in the equation %s: " - "polynomial %s does not have degree 1." - % (op, eq, poly)) - d, base_power_m = list(poly) - m = log(base_power_m, base=k) - try: - m = ZZ(m) - except (TypeError, ValueError): - raise ValueError("Term %s in the equation %s: " - "%s is not a power of %s." - % (summand, eq, - k**m, k)) from None - return [coeff, m, d] - - if not equations: - raise ValueError("List of recurrence equations is empty.") - - for eq in equations: - try: - if eq.operator() != operator.eq: - raise ValueError("%s is not an equation with ==." - % eq) - except AttributeError: - raise ValueError("%s is not a symbolic expression." - % eq) from None - left_side, right_side = eq.operands() - if left_side.operator() != function: - raise ValueError("Term %s in the equation %s is not an evaluation of %s." - % (left_side, eq, function)) - if len(left_side.operands()) != 1: - raise ValueError("Term %s in the equation %s does not have " - "one argument." - % (left_side, eq)) - try: - polynomial_left = ZZ[var](left_side.operands()[0]) - except TypeError: - raise ValueError("Term %s in the equation %s: " - "%s is not a polynomial in %s with " - "integer coefficients." - % (left_side, eq, - left_side.operands()[0], var)) from None - if polynomial_left.degree() > 1: - raise ValueError("Term %s in the equation %s: " - "%s is not a polynomial in %s of degree smaller than 2." - % (left_side, eq, polynomial_left, var)) - if polynomial_left in ZZ: - try: - right_side = coefficient_ring(right_side) - except (TypeError, ValueError): - raise ValueError("Initial value %s given by the equation %s " - "is not in %s." - % (right_side, eq, coefficient_ring)) from None - if (polynomial_left in initial_values.keys() and - initial_values[polynomial_left] != right_side): - raise ValueError("Initial value %s is given twice." - % (function(polynomial_left))) - initial_values.update({polynomial_left: right_side}) - else: - [r, base_power_M] = list(polynomial_left) - M_new = log(base_power_M, base=k) - try: - M_new = ZZ(M_new) - except (TypeError, ValueError): - raise ValueError("Term %s in the equation %s: " - "%s is not a power of %s." - % (left_side, eq, - base_power_M, k)) from None - if M is not None and M != M_new: - raise ValueError(("Term {0} in the equation {1}: " - "{2} does not equal {3}. Expected " - "subsequence modulo {3} as in another " - "equation, got subsequence modulo {2}.").format( - left_side, eq, - base_power_M, k**M)) - elif M is None: - M = M_new - if M < 1: - raise ValueError(("Term {0} in the equation {1}: " - "{2} is less than {3}. Modulus must " - "be at least {3}.").format( - left_side, eq, - base_power_M, k)) - if r in remainders: - raise ValueError("There are more than one recurrence relation for %s." - % (left_side,)) - if r >= k**M: - raise ValueError("Term %s in the equation %s: " - "remainder %s is not smaller than modulus %s." - % (left_side, eq, r, k**M)) - elif r < 0: - raise ValueError("Term %s in the equation %s: " - "remainder %s is smaller than 0." - % (left_side, eq, r)) - else: - remainders.add(r) - if right_side != 0: - if (len(right_side.operands()) == 1 and right_side.operator() == function - or right_side.operator() == mul_vararg and len(right_side.operands()) == 2): - summands = [right_side] - elif right_side.operator() == add_vararg: - summands = right_side.operands() - else: - raise ValueError("%s is not a valid right hand side." - % (right_side,)) - for summand in summands: - coeff, new_m, d = parse_one_summand(summand, eq) - if m is not None and m != new_m: - raise ValueError(("Term {0} in the equation {1}: " - "{2} does not equal {3}. Expected " - "subsequence modulo {3} as in another " - "summand or equation, got subsequence " - "modulo {2}.").format( - summand, eq, - k**new_m, k**m)) - elif m is None: - m = new_m - if M <= m: - raise ValueError("Term %s in the equation %s: " - "%s is not smaller than %s." - % (summand, eq, - k**m, k**M)) - coeffs.update({(r, d): coeff}) - - if not M: - raise ValueError("No recurrence relations are given.") - elif M and m is None: # for the zero sequence - m = M - 1 - - missing_remainders = [rem for rem in srange(k**M) - if rem not in remainders] - if missing_remainders: - raise ValueError("Recurrence relations for %s are missing." - % ([function(k**M*var + rem) - for rem in missing_remainders],)) - - return (M, m, coeffs, initial_values) - - def parse_direct_arguments(self, M, m, coeffs, initial_values): - r""" - Check whether the direct arguments as admissible in - :meth:`kRegularSequenceSpace.from_recurrence` are valid. - - INPUT: - - All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. - - OUTPUT: a tuple consisting of the input parameters - - EXAMPLES:: - - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RP = RecurrenceParser(2, ZZ) - sage: RP.parse_direct_arguments(2, 1, - ....: {(0, -2): 3, (0, 0): 1, (0, 1): 2, - ....: (1, -2): 6, (1, 0): 4, (1, 1): 5, - ....: (2, -2): 9, (2, 0): 7, (2, 1): 8, - ....: (3, -2): 12, (3, 0): 10, (3, 1): 11}, - ....: {0: 1, 1: 2, 2: 1}) - (2, 1, {(0, -2): 3, (0, 0): 1, (0, 1): 2, - (1, -2): 6, (1, 0): 4, (1, 1): 5, - (2, -2): 9, (2, 0): 7, (2, 1): 8, - (3, -2): 12, (3, 0): 10, (3, 1): 11}, - {0: 1, 1: 2, 2: 1}) - - Stern--Brocot Sequence:: - - sage: RP.parse_direct_arguments(1, 0, - ....: {(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: {0: 0, 1: 1}) - (1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 0, 1: 1}) - - .. SEEALSO:: - - :meth:`kRegularSequenceSpace.from_recurrence` - - TESTS: - - The following tests check that the equations are well-formed:: - - sage: RP.parse_direct_arguments(1/2, 0, {}, {}) - Traceback (most recent call last): - ... - ValueError: 1/2 is not a positive integer. - - :: - - sage: RP.parse_direct_arguments(0, 0, {}, {}) - Traceback (most recent call last): - .... - ValueError: 0 is not a positive integer. - - :: - - sage: RP.parse_direct_arguments(1, 1/2, {}, {}) - Traceback (most recent call last): - ... - ValueError: 1/2 is not a non-negative integer. - - :: - - sage: RP.parse_direct_arguments(1, -1, {}, {}) - Traceback (most recent call last): - ... - ValueError: -1 is not a non-negative integer. - - :: - - sage: RP.parse_direct_arguments(1, 1, {}, {}) - Traceback (most recent call last): - ... - ValueError: 1 is not larger than 1. - - :: - - sage: RP.parse_direct_arguments(1, 42, {}, {}) - Traceback (most recent call last): - ... - ValueError: 1 is not larger than 42. - - :: - - sage: RP.parse_direct_arguments(2, 1, {(0, 0): 1/2, (1, 0): i}, {}) - Traceback (most recent call last): - ... - ValueError: Coefficients [1/2, I] are not valid since they are not - in Integer Ring. - - :: - - sage: RP.parse_direct_arguments(2, 1, {(i, 0): 0, (0, 1/2): 0}, {}) - Traceback (most recent call last): - ... - ValueError: Keys [(I, 0), (0, 1/2)] for coefficients are not valid - since one of their components is no integer. - - :: - - sage: RP.parse_direct_arguments(2, 1, {(-1, 0): 0, (42, 0): 0}, {}) - Traceback (most recent call last): - ... - ValueError: Keys [(-1, 0), (42, 0)] for coefficients are not valid since - their first component is either smaller than 0 or larger than - or equal to 4. - - :: - - sage: RP.parse_direct_arguments(2, 1, {}, {0: 1/2, 1: i}) - Traceback (most recent call last): - ... - ValueError: Initial values [1/2, I] are not valid since they are - not in Integer Ring. - - :: - - sage: RP.parse_direct_arguments(2, 1, {}, {1/2: 0, i: 0}) - Traceback (most recent call last): - ... - ValueError: Keys [1/2, I] for the initial values are not valid since - they are no integers. - """ - from sage.rings.integer_ring import ZZ - - if M not in ZZ or M < 1: - raise ValueError("%s is not a positive integer." - % (M,)) from None - if m not in ZZ or m < 0: - raise ValueError("%s is not a non-negative integer." - % (m,)) from None - if M <= m: - raise ValueError("%s is not larger than %s." - % (M, m)) from None - - coefficient_ring = self.coefficient_ring - k = self.k - - invalid_coeffs = [coeff for coeff in coeffs.values() - if coeff not in coefficient_ring] - if invalid_coeffs: - raise ValueError("Coefficients %s are not valid " - "since they are not in %s." - % (invalid_coeffs, coefficient_ring)) from None - - coeffs_keys = coeffs.keys() - invalid_coeffs_keys = [key for key in coeffs_keys - if key[0] not in ZZ or key[1] not in ZZ] - if invalid_coeffs_keys: - raise ValueError("Keys %s for coefficients are not valid " - "since one of their components is no integer." - % (invalid_coeffs_keys,)) from None - - invalid_coeffs_keys = [key for key in coeffs_keys if key[0] < 0 or key[0] >= k**M] - if invalid_coeffs_keys: - raise ValueError("Keys %s for coefficients are not valid " - "since their first component is either smaller than 0 " - " or larger than or equal to %s." - % (invalid_coeffs_keys, k**M)) from None - - invalid_initial_values = [value for value in initial_values.values() - if value not in coefficient_ring] - if invalid_initial_values: - raise ValueError("Initial values %s are not valid " - "since they are not in %s." - % (invalid_initial_values, coefficient_ring)) from None - - invalid_initial_keys = [key for key in initial_values.keys() - if key not in ZZ] - if invalid_initial_keys: - raise ValueError("Keys %s for the initial values are not valid " - "since they are no integers." - % (invalid_initial_keys,)) from None - - return (M, m, coeffs, initial_values) - - def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}): - r""" - Determine parameters from recurrence relations as admissible in - :meth:`kRegularSequenceSpace.from_recurrence`. - - INPUT: - - All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. - - OUTPUT: a namedtuple ``recurrence_rules`` consisting of - - - ``M``, ``m``, ``l``, ``u``, ``offset`` -- parameters of the recursive - sequences, see [HKL2021]_, Definition 3.1 - - - ``ll``, ``uu``, ``n1``, ``dim`` -- parameters and dimension of the - resulting linear representation, see [HKL2021]_, Theorem A - - - ``coeffs`` -- a dictionary mapping ``(r, j)`` to the coefficients - `c_{r, j}` as given in [HKL2021]_, Equation (3.1). - If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``, - then it is assumed to be zero. - - - ``initial_values`` -- a dictionary mapping integers ``n`` to the - ``n``-th value of the sequence - - - ``inhomogeneities`` -- a dictionary mapping integers ``r`` - to the inhomogeneity `g_r` as given in [HKL2021]_, Corollary D. - - EXAMPLES:: - - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RP = RecurrenceParser(2, ZZ) - sage: RP.parameters(2, 1, - ....: {(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4, - ....: (1, 1): 5, (2, -2): 9, (2, 0): 7, (2, 1): 8, (3, -2): 12, - ....: (3, 0): 10, (3, 1): 11}, {0: 1, 1: 2, 2: 1, 3: 4}, 0, {0: 1}) - recurrence_rules(M=2, m=1, l=-2, u=1, ll=-6, uu=3, dim=14, - coeffs={(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4, - (1, 1): 5, (2, -2): 9, (2, 0): 7, (2, 1): 8, (3, -2): 12, - (3, 0): 10, (3, 1): 11}, initial_values={0: 1, 1: 2, 2: 1, 3: 4, - 4: 13, 5: 30, 6: 48, 7: 66, 8: 77, 9: 208, 10: 340, 11: 472, - 12: 220, 13: 600, -6: 0, -5: 0, -4: 0, -3: 0, -2: 0, -1: 0}, - offset=1, n1=3, inhomogeneities={0: 2-regular sequence 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, ...}) - - .. SEEALSO:: - - :meth:`kRegularSequenceSpace.from_recurrence` - - TESTS:: - - sage: var('n') - n - sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, - ....: {-1: 0, 1: 0, 10: 0, I: 0, n: 0}) - Traceback (most recent call last): - ... - ValueError: Indices [-1, 10, I, n] for inhomogeneities are - no integers between 0 and 1. - - :: - - sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, - ....: {0: n}) - Traceback (most recent call last): - ... - ValueError: Inhomogeneities {0: n} are neither 2-regular sequences - nor elements of Integer Ring. - - :: - - sage: Seq3 = kRegularSequenceSpace(3, ZZ) - sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, - ....: {0: Seq3.zero()}) - Traceback (most recent call last): - ... - ValueError: Inhomogeneities {0: 3-regular sequence 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, ...} are neither 2-regular sequences nor elements of - Integer Ring. - - :: - - sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0) - Traceback (most recent call last): - ... - ValueError: No initial values are given. - - :: - - sage: RP.parameters(1, 0, - ....: {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 1/2, 1: 2*i}, 0) - Traceback (most recent call last): - ... - ValueError: Initial values for arguments in [0, 1] are not in Integer Ring. - - :: - - sage: RP.parameters(1, 0, {(0, 0): 1}, - ....: {0: 1, 1: 0}, 0) - recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1, - coeffs={(0, 0): 1}, initial_values={0: 1, 1: 0}, offset=0, n1=0, - inhomogeneities={}) - - Finally, also for the zero-sequence the output is as expected:: - - sage: RP.parameters(1, 0, {}, {0: 0}, 0) - recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1, - coeffs={}, initial_values={0: 0}, offset=0, n1=0, inhomogeneities={}) - - :: - - sage: RP.parameters(1, 0, - ....: {(0, 0): 0, (1, 1): 0}, {0: 0}, 0) - recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1, - coeffs={(0, 0): 0, (1, 1): 0}, initial_values={0: 0}, - offset=0, n1=0, inhomogeneities={}) - """ - from collections import namedtuple - - from sage.arith.srange import srange - from sage.functions.other import ceil, floor - - coefficient_ring = self.coefficient_ring - k = self.k - keys_coeffs = coeffs.keys() - indices_right = [key[1] for key in keys_coeffs if coeffs[key]] - - if not indices_right: # the sequence is the zero sequence - l = 0 - u = 0 - else: - l = min(indices_right) - u = max(indices_right) - - if offset < max(0, -l/k**m): - offset = max(0, ceil(-l/k**m)) - - ll = (floor((l*k**(M-m) - k**M + 1)/(k**(M-m) - 1)) + 1)*(l < 0) - uu = max([ceil((u*k**(M-m) + k**M - k**m)/(k**(M-m) - 1)) - 1, k**m - 1]) - n1 = offset - floor(ll/k**M) - dim = (k**M - 1)/(k - 1) + (M - m)*(uu - ll - k**m + 1) + n1 - - if inhomogeneities: - invalid_indices = [i for i in inhomogeneities - if i not in srange(k**M)] - if invalid_indices: - raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no " - f"integers between 0 and {k**M - 1}.") - - Seq = kRegularSequenceSpace(k, coefficient_ring) - inhomogeneities.update({i: inhomogeneities[i] * Seq.one_hadamard() - for i in inhomogeneities - if inhomogeneities[i] in coefficient_ring}) - invalid = {i: inhomogeneities[i] for i in inhomogeneities - if not (isinstance(inhomogeneities[i].parent(), kRegularSequenceSpace) and - inhomogeneities[i].parent().k == k)} - if invalid: - raise ValueError(f"Inhomogeneities {invalid} are neither {k}-regular " - f"sequences nor elements of {coefficient_ring}.") - - if not initial_values: - raise ValueError("No initial values are given.") - keys_initial = initial_values.keys() - values_not_in_ring = [] - - def converted_value(n, v): - try: - return coefficient_ring(v) - except (TypeError, ValueError): - values_not_in_ring.append(n) - initial_values = {n: converted_value(n, v) - for n, v in initial_values.items()} - if values_not_in_ring: - raise ValueError("Initial values for arguments in %s are not in %s." - % (values_not_in_ring, coefficient_ring)) - - last_value_needed = max( - k**(M-1) - k**m + uu + (n1 > 0)*k**(M-1)*(k*(n1 - 1) + k - 1), # for matrix W - k**m*offset + u, - max(keys_initial)) - initial_values = self.values( - M=M, m=m, l=l, u=u, ll=ll, coeffs=coeffs, - initial_values=initial_values, last_value_needed=last_value_needed, - offset=offset, inhomogeneities=inhomogeneities) - - recurrence_rules = namedtuple('recurrence_rules', - ['M', 'm', 'l', 'u', 'll', 'uu', 'dim', - 'coeffs', 'initial_values', 'offset', 'n1', - 'inhomogeneities']) - - return recurrence_rules(M=M, m=m, l=l, u=u, ll=ll, uu=uu, dim=dim, - coeffs=coeffs, initial_values=initial_values, - offset=offset, n1=n1, inhomogeneities=inhomogeneities) - - def values(self, *, M, m, l, u, ll, coeffs, - initial_values, last_value_needed, offset, inhomogeneities): - r""" - Determine enough values of the corresponding recursive sequence by - applying the recurrence relations given in :meth:`kRegularSequenceSpace.from_recurrence` - to the values given in ``initial_values``. - - INPUT: - - - ``M``, ``m``, ``l``, ``u``, ``offset`` -- parameters of the - recursive sequences, see [HKL2021]_, Definition 3.1 - - - ``ll`` -- parameter of the resulting linear representation, - see [HKL2021]_, Theorem A - - - ``coeffs`` -- a dictionary where ``coeffs[(r, j)]`` is the - coefficient `c_{r,j}` as given in :meth:`kRegularSequenceSpace.from_recurrence`. - If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``, - then it is assumed to be zero. - - - ``initial_values`` -- a dictionary mapping integers ``n`` to the - ``n``-th value of the sequence - - - ``last_value_needed`` -- last initial value which is needed to - determine the linear representation - - - ``inhomogeneities`` -- a dictionary mapping integers ``r`` - to the inhomogeneity `g_r` as given in [HKL2021]_, Corollary D. - - OUTPUT: - - A dictionary mapping integers ``n`` to the ``n``-th value of the - sequence for all ``n`` up to ``last_value_needed``. - - EXAMPLES: - - Stern--Brocot Sequence:: - - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RP = RecurrenceParser(2, ZZ) - sage: RP.values(M=1, m=0, l=0, u=1, ll=0, - ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: initial_values={0: 0, 1: 1, 2: 1}, last_value_needed=20, - ....: offset=0, inhomogeneities={}) - {0: 0, 1: 1, 2: 1, 3: 2, 4: 1, 5: 3, 6: 2, 7: 3, 8: 1, 9: 4, 10: 3, - 11: 5, 12: 2, 13: 5, 14: 3, 15: 4, 16: 1, 17: 5, 18: 4, 19: 7, 20: 3} - - .. SEEALSO:: - - :meth:`kRegularSequenceSpace.from_recurrence` - - TESTS: - - For the equations `f(2n) = f(n)` and `f(2n + 1) = f(n) + f(n + 1)`:: - - sage: RP.values(M=1, m=0, l=0, u=1, ll=0, - ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: initial_values={0: 0, 1: 2}, last_value_needed=20, - ....: offset=0, inhomogeneities={}) - {0: 0, 1: 2, 2: 2, 3: 4, 4: 2, 5: 6, 6: 4, 7: 6, 8: 2, 9: 8, 10: 6, - 11: 10, 12: 4, 13: 10, 14: 6, 15: 8, 16: 2, 17: 10, 18: 8, 19: 14, - 20: 6} - - :: - - sage: RP.values(M=1, m=0, l=0, u=1, ll=0, - ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: initial_values={}, last_value_needed=20, offset=0, - ....: inhomogeneities={}) - Traceback (most recent call last): - ... - ValueError: Initial values for arguments in [0, 1] are missing. - - :: - - sage: RP.values(M=1, m=0, l=0, u=1, ll=0, - ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: initial_values={0: 0}, last_value_needed=20, offset=0, - ....: inhomogeneities={}) - Traceback (most recent call last): - ... - ValueError: Initial values for arguments in [1] are missing. - - :: - - sage: RP.values(M=1, m=0, l=0, u=1, ll=0, - ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: initial_values={0: 0, 2: 1}, last_value_needed=20, - ....: offset=0, inhomogeneities={}) - Traceback (most recent call last): - ... - ValueError: Initial values for arguments in [1] are missing. - - :: - - sage: RP.values(M=1, m=0, l=0, u=1, ll=0, - ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: initial_values={0: 0, 1: 2, 2:0}, last_value_needed=20, - ....: offset=0, inhomogeneities={}) - Traceback (most recent call last): - ... - ValueError: Initial value for argument 2 does not match with the given - recurrence relations. - - :: - - sage: RP.values(M=1, m=0, l=-2, u=2, ll=-2, - ....: coeffs={(0, -2): 1, (0, 2): 1, (1, -2): 1, (1, 2): 1}, - ....: initial_values={0: 0, 1: 2, 2: 4, 3: 3, 4: 2}, - ....: last_value_needed=20, offset=2, inhomogeneities={}) - {-2: 0, -1: 0, 0: 0, 1: 2, 2: 4, 3: 3, 4: 2, 5: 2, 6: 4, 7: 4, - 8: 8, 9: 8, 10: 7, 11: 7, 12: 10, 13: 10, 14: 10, 15: 10, 16: 11, - 17: 11, 18: 11, 19: 11, 20: 18} - - Finally, also for the zero-sequence the output is as expected:: - - sage: RP.values(M=1, m=0, l=0, u=0, ll=0, - ....: coeffs={}, initial_values={}, last_value_needed=10, - ....: offset=0, inhomogeneities={}) - {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0} - - :: - - sage: RP.values(M=1, m=0, l=0, u=0, ll=0, - ....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={}, - ....: last_value_needed=10, offset=0, inhomogeneities={}) - {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0} - - :: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: RP.values(M=1, m=0, l=0, u=0, ll=0, - ....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={}, - ....: last_value_needed=10, offset=0, - ....: inhomogeneities={0: Seq2.one_hadamard()}) - {0: 1, 1: 0, 2: 1, 3: 0, 4: 1, 5: 0, 6: 1, 7: 0, 8: 1, 9: 0, 10: 1} - """ - from sage.arith.srange import srange - from sage.rings.integer_ring import ZZ - - k = self.k - keys_initial = initial_values.keys() - - values = {n: None if n not in keys_initial else initial_values[n] - for n in srange(last_value_needed + 1)} - missing_values = [] - - @cached_function - def coeff(r, k): - try: - return coeffs[(r, k)] - except KeyError: - return 0 - - @cached_function - def inhomogeneity(r, n): - try: - return inhomogeneities[r][n] - except KeyError: - return 0 - - def f(n): - f_n = values[n] - if f_n is not None and f_n != "pending": - return f_n - elif f_n == "pending": - missing_values.append(n) - return 0 - else: - values.update({n: "pending"}) - q, r = ZZ(n).quo_rem(k**M) - if q < offset: - missing_values.append(n) - return sum([coeff(r, j)*f(k**m*q + j) - for j in srange(l, u + 1) - if coeff(r, j)]) + inhomogeneity(r, q) - - for n in srange(last_value_needed + 1): - values.update({n: f(n)}) - - if missing_values: - raise ValueError("Initial values for arguments in %s are missing." - % (list(set(missing_values)),)) - - for n in keys_initial: - q, r = ZZ(n).quo_rem(k**M) - if (q >= offset and - values[n] != (sum([coeff(r, j)*values[k**m*q + j] - for j in srange(l, u + 1)])) + inhomogeneity(r, q)): - raise ValueError("Initial value for argument %s does not match with " - "the given recurrence relations." - % (n,)) - - values.update({n: 0 for n in srange(ll, 0)}) - - return values - - @cached_method - def ind(self, M, m, ll, uu): - r""" - Determine the index operator corresponding to the recursive - sequence as defined in [HKL2021]_. - - INPUT: - - - ``M``, ``m`` -- parameters of the recursive sequences, - see [HKL2021]_, Definition 3.1 - - - ``ll``, ``uu`` -- parameters of the resulting linear representation, - see [HKL2021]_, Theorem A - - OUTPUT: - - A dictionary which maps both row numbers to subsequence parameters and - vice versa, i.e., - - - ``ind[i]`` -- a pair ``(j, d)`` representing the sequence `x(k^j n + d)` - in the `i`-th component (0-based) of the resulting linear representation, - - - ``ind[(j, d)]`` -- the (0-based) row number of the sequence - `x(k^j n + d)` in the linear representation. - - EXAMPLES:: - - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RP = RecurrenceParser(2, ZZ) - sage: RP.ind(3, 1, -3, 3) - {(0, 0): 0, (1, -1): 3, (1, -2): 2, (1, -3): 1, - (1, 0): 4, (1, 1): 5, (1, 2): 6, (1, 3): 7, (2, -1): 10, - (2, -2): 9, (2, -3): 8, (2, 0): 11, (2, 1): 12, (2, 2): 13, - (2, 3): 14, (2, 4): 15, (2, 5): 16, 0: (0, 0), 1: (1, -3), - 10: (2, -1), 11: (2, 0), 12: (2, 1), 13: (2, 2), 14: (2, 3), - 15: (2, 4), 16: (2, 5), 2: (1, -2), 3: (1, -1), 4: (1, 0), - 5: (1, 1), 6: (1, 2), 7: (1, 3), 8: (2, -3), 9: (2, -2)} - - .. SEEALSO:: - - :meth:`kRegularSequenceSpace.from_recurrence` - """ - from sage.arith.srange import srange - - k = self.k - ind = {} - - pos = 0 - for j in srange(m): - for d in srange(k**j): - ind.update({(j, d): pos, pos: (j, d)}) - pos += 1 - for j in srange(m, M): - for d in srange(ll, k**j - k**m + uu + 1): - ind.update({(j, d): pos, pos: (j, d)}) - pos += 1 - - return ind - - @cached_method(key=lambda self, recurrence_rules: - (recurrence_rules.M, - recurrence_rules.m, - recurrence_rules.ll, - recurrence_rules.uu, - tuple(recurrence_rules.inhomogeneities.items()))) - def shifted_inhomogeneities(self, recurrence_rules): - r""" - Return a dictionary of all needed shifted inhomogeneities as described - in the proof of Coroallary D in [HKL2021]_. - - INPUT: - - - ``recurrence_rules`` -- a namedtuple generated by - :meth:`parameters` - - OUTPUT: - - A dictionary mapping `r` to the regular sequence - `\sum_i g_r(n + i)` for `g_r` as given in [HKL2021]_, Corollary D, - and `i` between `\lfloor\ell'/k^{M}\rfloor` and - `\lfloor (k^{M-1} - k^{m} + u')/k^{M}\rfloor + 1`; see [HKL2021]_, - proof of Corollary D. The first blocks of the corresponding - vector-valued sequence (obtained from its linear - representation) correspond to the sequences `g_r(n + i)` where - `i` is as in the sum above; the remaining blocks consist of - other shifts which are required for the regular sequence. - - EXAMPLES:: - - sage: from collections import namedtuple - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RP = RecurrenceParser(2, ZZ) - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), - ....: left=vector([0, 1]), right=vector([1, 0])) - sage: S - 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... - sage: RR = namedtuple('recurrence_rules', - ....: ['M', 'm', 'll', 'uu', 'inhomogeneities']) - sage: recurrence_rules = RR(M=3, m=0, ll=-14, uu=14, - ....: inhomogeneities={0: S, 1: S}) - sage: SI = RP.shifted_inhomogeneities(recurrence_rules) - sage: SI - {0: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ..., - 1: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ...} - - The first blocks of the corresponding vector-valued sequence correspond - to the corresponding shifts of the inhomogeneity. In this particular - case, there are no other blocks:: - - sage: lower = -2 - sage: upper = 3 - sage: SI[0].dimension() == S.dimension() * (upper - lower + 1) - True - sage: all( - ....: Seq2( - ....: SI[0].mu, - ....: vector((i - lower)*[0, 0] + list(S.left) + (upper - i)*[0, 0]), - ....: SI[0].right) - ....: == S.subsequence(1, i) - ....: for i in range(lower, upper+1)) - True - - TESTS:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: var('n') - n - sage: function('f') - f - sage: UB = Seq2.from_recurrence([ - ....: f(8*n) == 2*f(4*n), - ....: f(8*n + 1) == f(4*n + 1), - ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3), - ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2), - ....: f(8*n + 4) == 2*f(4*n + 2), - ....: f(8*n + 5) == f(4*n + 3), - ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3), - ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), - ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, - ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, - ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, - ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, - ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3) - sage: inhomogeneities={2: UB.subsequence(4, 3), 3: -UB.subsequence(4, 1), - ....: 6: UB.subsequence(4, 2) + UB.subsequence(4, 3)} - sage: recurrence_rules_UB = RR(M=3, m=2, ll=0, uu=9, - ....: inhomogeneities=inhomogeneities) - sage: shifted_inhomog = RP.shifted_inhomogeneities(recurrence_rules_UB) - sage: shifted_inhomog - {2: 2-regular sequence 8, 8, 8, 12, 12, 16, 12, 16, 12, 24, ..., - 3: 2-regular sequence -10, -8, -8, -8, -8, -8, -8, -8, -8, -12, ..., - 6: 2-regular sequence 20, 22, 24, 28, 28, 32, 28, 32, 32, 48, ...} - sage: shifted_inhomog[2].mu[0].ncols() == 3*inhomogeneities[2].mu[0].ncols() - True - - .. SEEALSO:: - - :meth:`kRegularSequenceSpace.from_recurrence` - """ - from sage.arith.srange import srange - from sage.functions.other import floor - - k = self.k - M = recurrence_rules.M - m = recurrence_rules.m - ll = recurrence_rules.ll - uu = recurrence_rules.uu - inhomogeneities = recurrence_rules.inhomogeneities - - lower = floor(ll/k**M) - upper = floor((k**(M-1) - k**m + uu)/k**M) + 1 - - return {i: inhomogeneities[i].subsequence(1, {b: 1 for b in srange(lower, upper + 1)}, - minimize=False) - for i in inhomogeneities} - - def v_eval_n(self, recurrence_rules, n): - r""" - Return the vector `v(n)` as given in [HKL2021]_, Theorem A. - - INPUT: - - - ``recurrence_rules`` -- a namedtuple generated by - :meth:`parameters` - - - ``n`` -- an integer - - OUTPUT: a vector - - EXAMPLES: - - Stern--Brocot Sequence:: - - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RP = RecurrenceParser(2, ZZ) - sage: SB_rules = RP.parameters( - ....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: {0: 0, 1: 1, 2: 1}, 0) - sage: RP.v_eval_n(SB_rules, 0) - (0, 1, 1) - - .. SEEALSO:: - - :meth:`kRegularSequenceSpace.from_recurrence` - """ - from itertools import chain - - from sage.arith.srange import srange - from sage.modules.free_module_element import vector - from sage.rings.integer_ring import ZZ - - k = self.k - M = recurrence_rules.M - m = recurrence_rules.m - ll = recurrence_rules.ll - uu = recurrence_rules.uu - dim = recurrence_rules.dim - recurrence_rules.n1 - initial_values = recurrence_rules.initial_values - inhomogeneities = recurrence_rules.inhomogeneities - ind = self.ind(M, m, ll, uu) - - v = vector([initial_values[k**ind[i][0]*n + ind[i][1]] for i in srange(dim)]) - - if not all(S.is_trivial_zero() for S in inhomogeneities.values()): - Seq = list(inhomogeneities.values())[0].parent() - W = Seq.indices() - shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) - vv = [(S.coefficient_of_word(W(ZZ(n).digits(k)), multiply_left=False)) - for S in shifted_inhomogeneities.values()] - v = vector(chain(v, *vv)) - - return v - - def matrix(self, recurrence_rules, rem, correct_offset=True): - r""" - Construct the matrix for remainder ``rem`` of the linear - representation of the sequence represented by ``recurrence_rules``. - - INPUT: - - - ``recurrence_rules`` -- a namedtuple generated by - :meth:`parameters` - - - ``rem`` -- an integer between ``0`` and ``k - 1`` - - - ``correct_offset`` -- (default: ``True``) a boolean. If - ``True``, then the resulting linear representation has no - offset. See [HKL2021]_ for more information. - - OUTPUT: a matrix - - EXAMPLES: - - The following example illustrates how the coefficients in the - right-hand sides of the recurrence relations correspond to the entries of - the matrices. :: - - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RP = RecurrenceParser(2, ZZ) - sage: var('n') - n - sage: function('f') - f - sage: M, m, coeffs, initial_values = RP.parse_recurrence([ - ....: f(8*n) == -1*f(2*n - 1) + 1*f(2*n + 1), - ....: f(8*n + 1) == -11*f(2*n - 1) + 10*f(2*n) + 11*f(2*n + 1), - ....: f(8*n + 2) == -21*f(2*n - 1) + 20*f(2*n) + 21*f(2*n + 1), - ....: f(8*n + 3) == -31*f(2*n - 1) + 30*f(2*n) + 31*f(2*n + 1), - ....: f(8*n + 4) == -41*f(2*n - 1) + 40*f(2*n) + 41*f(2*n + 1), - ....: f(8*n + 5) == -51*f(2*n - 1) + 50*f(2*n) + 51*f(2*n + 1), - ....: f(8*n + 6) == -61*f(2*n - 1) + 60*f(2*n) + 61*f(2*n + 1), - ....: f(8*n + 7) == -71*f(2*n - 1) + 70*f(2*n) + 71*f(2*n + 1), - ....: f(0) == 0, f(1) == 1, f(2) == 2, f(3) == 3, f(4) == 4, - ....: f(5) == 5, f(6) == 6, f(7) == 7], f, n) - sage: rules = RP.parameters( - ....: M, m, coeffs, initial_values, 0) - sage: RP.matrix(rules, 0, False) - [ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0] - [ 0 -51 50 51 0 0 0 0 0 0 0 0 0 0 0 0 0] - [ 0 -61 60 61 0 0 0 0 0 0 0 0 0 0 0 0 0] - [ 0 -71 70 71 0 0 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -1 0 1 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -11 10 11 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -21 20 21 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -31 30 31 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -41 40 41 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -51 50 51 0 0 0 0 0 0 0 0 0 0 0] - sage: RP.matrix(rules, 1, False) - [ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1] - [ 0 0 0 -11 10 11 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -21 20 21 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -31 30 31 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -41 40 41 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -51 50 51 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -61 60 61 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -71 70 71 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 -1 0 1 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 -11 10 11 0 0 0 0 0 0 0 0 0] - - Stern--Brocot Sequence:: - - sage: SB_rules = RP.parameters( - ....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: {0: 0, 1: 1, 2: 1}, 0) - sage: RP.matrix(SB_rules, 0) - [1 0 0] - [1 1 0] - [0 1 0] - sage: RP.matrix(SB_rules, 1) - [1 1 0] - [0 1 0] - [0 1 1] - - Number of Unbordered Factors in the Thue--Morse Sequence:: - - sage: M, m, coeffs, initial_values = RP.parse_recurrence([ - ....: f(8*n) == 2*f(4*n), - ....: f(8*n + 1) == f(4*n + 1), - ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3), - ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2), - ....: f(8*n + 4) == 2*f(4*n + 2), - ....: f(8*n + 5) == f(4*n + 3), - ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3), - ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), - ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, - ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, - ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, - ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, - ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n) - sage: UB_rules = RP.parameters( - ....: M, m, coeffs, initial_values, 3) - sage: RP.matrix(UB_rules, 0) - [ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 2 0 0 0 0 0 0 0 0 0 -1 0 0] - [ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 1 0 1 0 0 0 0 0 0 -4 0 0] - [ 0 0 0 0 -1 1 0 0 0 0 0 0 0 4 2 0] - [ 0 0 0 0 0 2 0 0 0 0 0 0 0 -2 0 0] - [ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 -1 1 1 0 0 0 0 0 0 2 2 0] - [ 0 0 0 0 2 0 1 0 0 0 0 0 0 -8 -4 -4] - [ 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0] - sage: RP.matrix(UB_rules, 1) - [ 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 2 0 0 0 0 0 0 0 -2 0 0] - [ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 -1 1 1 0 0 0 0 0 0 2 2 0] - [ 0 0 0 0 2 0 1 0 0 0 0 0 0 -8 -4 -4] - [ 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 -1 1 0 0 0 2 0 0] - [ 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0] - [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] - - .. SEEALSO:: - - :meth:`kRegularSequenceSpace.from_recurrence` - """ - from itertools import chain - - from sage.arith.srange import srange - from sage.functions.other import floor - from sage.matrix.constructor import Matrix - from sage.matrix.special import block_matrix, block_diagonal_matrix, zero_matrix - from sage.modules.free_module_element import vector - - coefficient_ring = self.coefficient_ring - k = self.k - M = recurrence_rules.M - m = recurrence_rules.m - l = recurrence_rules.l - ll = recurrence_rules.ll - uu = recurrence_rules.uu - dim = recurrence_rules.dim - n1 = recurrence_rules.n1 - dim_without_corr = dim - n1 - coeffs = recurrence_rules.coeffs - inhomogeneities = recurrence_rules.inhomogeneities - ind = self.ind(M, m, ll, uu) - - @cached_function - def coeff(r, k): - try: - return coeffs[(r, k)] - except KeyError: - return 0 - - def entry(i, kk): - j, d = ind[i] - if j < M - 1: - return int(kk == ind[(j + 1, k**j*rem + d)]) - else: - rem_d = k**(M-1)*rem + (d % k**M) - dd = d // k**M - if rem_d < k**M: - lambd = l - ind[(m, (k**m)*dd + l)] - return coeff(rem_d, kk + lambd) - else: - lambd = l - ind[(m, k**m*dd + k**m + l)] - return coeff(rem_d - k**M, kk + lambd) - - mat = Matrix(coefficient_ring, dim_without_corr, dim_without_corr, entry) - - if not all(S.is_trivial_zero() for S in inhomogeneities.values()): - shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) - lower = floor(ll/k**M) - upper = floor((k**(M-1) - k**m + uu)/k**M) + 1 - - def wanted_inhomogeneity(row): - j, d = ind[row] - if j != M - 1: - return (None, None) - rem_d = k**(M-1)*rem + (d % k**M) - dd = d // k**M - if rem_d < k**M: - return (rem_d, dd) - elif rem_d >= k**M: - return (rem_d - k**M, dd + 1) - else: - return (None, None) - - def left_for_inhomogeneity(wanted): - return list(chain(*[(wanted == (r, i))*inhomogeneity.left - for r, inhomogeneity in inhomogeneities.items() - for i in srange(lower, upper + 1)])) - - def matrix_row(row): - wanted = wanted_inhomogeneity(row) - return left_for_inhomogeneity(wanted) - - mat_upper_right = Matrix([matrix_row(row) for row in srange(dim_without_corr)]) - mat_inhomog = block_diagonal_matrix([S.mu[rem] - for S in shifted_inhomogeneities.values()], - subdivide=False) - - mat = block_matrix([[mat, mat_upper_right], - [zero_matrix(mat_inhomog.nrows(), dim_without_corr), - mat_inhomog]], subdivide=False) - - dim_without_corr = mat.ncols() - dim = dim_without_corr + n1 - - if n1 > 0 and correct_offset: - W = Matrix(coefficient_ring, dim_without_corr, 0) - for i in srange(n1): - W = W.augment( - self.v_eval_n(recurrence_rules, k*i + rem) - - mat*self.v_eval_n(recurrence_rules, i)) - - J = Matrix(coefficient_ring, 0, n1) - for i in srange(n1): - J = J.stack(vector([int(j*k == i - rem) for j in srange(n1)])) - - Z = zero_matrix(coefficient_ring, n1, dim_without_corr) - mat = block_matrix([[mat, W], [Z, J]], subdivide=False) - - return mat - - def left(self, recurrence_rules): - r""" - Construct the vector ``left`` of the linear representation of - recursive sequences. - - INPUT: - - - ``recurrence_rules`` -- a namedtuple generated by - :meth:`parameters`; it only needs to contain a field - ``dim`` (a positive integer) - - OUTPUT: a vector - - EXAMPLES:: - - sage: from collections import namedtuple - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RP = RecurrenceParser(2, ZZ) - sage: RRD = namedtuple('recurrence_rules_dim', - ....: ['dim', 'inhomogeneities']) - sage: recurrence_rules = RRD(dim=5, inhomogeneities={}) - sage: RP.left(recurrence_rules) - (1, 0, 0, 0, 0) - - :: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: RRD = namedtuple('recurrence_rules_dim', - ....: ['M', 'm', 'll', 'uu', 'dim', 'inhomogeneities']) - sage: recurrence_rules = RRD(M=3, m=2, ll=0, uu=9, dim=5, - ....: inhomogeneities={0: Seq2.one_hadamard()}) - sage: RP.left(recurrence_rules) - (1, 0, 0, 0, 0, 0, 0, 0) - - .. SEEALSO:: - - :meth:`kRegularSequenceSpace.from_recurrence` - """ - from sage.modules.free_module_element import vector - - dim = recurrence_rules.dim - inhomogeneities = recurrence_rules.inhomogeneities - - if not all(S.is_trivial_zero() for S in inhomogeneities.values()): - shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) - dim += sum(shifted_inhomogeneities[i].mu[0].ncols() - for i in shifted_inhomogeneities) - - return vector([1] + (dim - 1)*[0]) - - def right(self, recurrence_rules): - r""" - Construct the vector ``right`` of the linear - representation of the sequence induced by ``recurrence_rules``. - - INPUT: - - - ``recurrence_rules`` -- a namedtuple generated by - :meth:`parameters` - - OUTPUT: a vector - - .. SEEALSO:: - - :meth:`kRegularSequenceSpace.from_recurrence` - - TESTS: - - Stern--Brocot Sequence:: - - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RP = RecurrenceParser(2, ZZ) - sage: var('n') - n - sage: function('f') - f - sage: SB_rules = RP.parameters( - ....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: {0: 0, 1: 1, 2: 1}, 0) - sage: RP.right(SB_rules) - (0, 1, 1) - - Number of Unbordered Factors in the Thue--Morse Sequence:: - - sage: M, m, coeffs, initial_values = RP.parse_recurrence([ - ....: f(8*n) == 2*f(4*n), - ....: f(8*n + 1) == f(4*n + 1), - ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3), - ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2), - ....: f(8*n + 4) == 2*f(4*n + 2), - ....: f(8*n + 5) == f(4*n + 3), - ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3), - ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), - ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, - ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, - ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, - ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, - ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n) - sage: UB_rules = RP.parameters( - ....: M, m, coeffs, initial_values, 3) - sage: RP.right(UB_rules) - (1, 1, 2, 1, 2, 2, 4, 2, 4, 6, 0, 4, 4, 1, 0, 0) - """ - from sage.modules.free_module_element import vector - - n1 = recurrence_rules.n1 - right = self.v_eval_n(recurrence_rules, 0) - - if n1 >= 1: - right = vector(list(right) + [1] + (n1 - 1)*[0]) - - return right - - def __call__(self, *args, **kwds): - r""" - Construct a `k`-linear representation that fulfills the recurrence relations - given in ``equations``. - - This is the main method of :class:`RecurrenceParser` and - is called by :meth:`kRegularSequenceSpace.from_recurrence` - to construct a :class:`kRegularSequence`. - - INPUT: - - All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. - - OUTPUT: a linear representation ``(left, mu, right)`` - - Many examples can be found in - :meth:`kRegularSequenceSpace.from_recurrence`. - - TESTS:: - - sage: from sage.combinat.k_regular_sequence import RecurrenceParser - sage: RP = RecurrenceParser(2, ZZ) - sage: var('n') - n - sage: function('f') - f - - sage: RP([f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1), - ....: f(0) == 0, f(1) == 1], f, n) - ([ - [1 0 0] [1 1 0] - [1 1 0] [0 1 0] - [0 1 0], [0 1 1] - ], - (1, 0, 0), - (0, 1, 1)) - - sage: RP(equations=[f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1), - ....: f(0) == 0, f(1) == 1], function=f, var=n) - ([ - [1 0 0] [1 1 0] - [1 1 0] [0 1 0] - [0 1 0], [0 1 1] - ], - (1, 0, 0), - (0, 1, 1)) - - sage: RP(1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 0, 1: 1}) - ([ - [1 0 0] [1 1 0] - [1 1 0] [0 1 0] - [0 1 0], [0 1 1] - ], - (1, 0, 0), - (0, 1, 1)) - - sage: RP(M=1, m=0, - ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: initial_values={0: 0, 1: 1}) - ([ - [1 0 0] [1 1 0] - [1 1 0] [0 1 0] - [0 1 0], [0 1 1] - ], - (1, 0, 0), - (0, 1, 1)) - """ - from sage.arith.srange import srange - - k = self.k - if len(args) == 3: - M, m, coeffs, initial_values = self.parse_recurrence(*args) - elif len(args) == 0 and all(kwd in kwds for kwd in ['equations', 'function', 'var']): - args = (kwds.pop('equations'), - kwds.pop('function'), - kwds.pop('var')) - M, m, coeffs, initial_values = self.parse_recurrence(*args) - elif len(args) == 4: - M, m, coeffs, initial_values = self.parse_direct_arguments(*args) - elif len(args) == 0 and all(kwd in kwds for kwd in ['M', 'm', 'coeffs', 'initial_values']): - args = (kwds.pop('M'), - kwds.pop('m'), - kwds.pop('coeffs'), - kwds.pop('initial_values')) - M, m, coeffs, initial_values = self.parse_direct_arguments(*args) - else: - raise ValueError("Number of positional arguments must be three or four or all arguments provided as keywords.") - - recurrence_rules = self.parameters(M, m, coeffs, initial_values, **kwds) - - mu = [self.matrix(recurrence_rules, rem) - for rem in srange(k)] - - left = self.left(recurrence_rules) - right = self.right(recurrence_rules) - - return (mu, left, right) diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index 24f00e12926..3aeeb543567 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -48,7 +48,7 @@ import copy -def WeakTableau(t, k, inner_shape = [], representation = "core"): +def WeakTableau(t, k, inner_shape=[], representation="core"): r""" This is the dispatcher method for the element class of weak `k`-tableaux. @@ -188,12 +188,12 @@ def WeakTableau(t, k, inner_shape = [], representation = "core"): elif representation == "bounded": return WeakTableau_bounded(t, k) elif representation == "factorized_permutation": - return WeakTableau_factorized_permutation(t, k, inner_shape = inner_shape) + return WeakTableau_factorized_permutation(t, k, inner_shape=inner_shape) else: raise NotImplementedError("The representation option needs to be 'core', 'bounded', or 'factorized_permutation'") -def WeakTableaux(k, shape , weight, representation = "core"): +def WeakTableaux(k, shape , weight, representation="core"): r""" This is the dispatcher method for the parent class of weak `k`-tableaux. @@ -205,7 +205,7 @@ def WeakTableaux(k, shape , weight, representation = "core"): for the 'bounded' representation, the shape is inputted as a `k`-bounded partition; for skew tableaux, the shape is inputted as a tuple of the outer and inner shape - ``weight`` -- the weight of the weak `k`-tableaux as a list or tuple - - ``representation`` -- 'core', 'bounded', or 'factorized_permutation' (default: 'core') + - ``representation`` -- ``'core'``, ``'bounded'``, or ``'factorized_permutation'`` (default: ``'core'``) EXAMPLES:: @@ -469,7 +469,7 @@ def chi(x): return "" if x in ZZ: return x - return "%s"%x + return "%s" % x if self.parent()._representation in ['core', 'bounded']: t = [[chi(x) for x in row] for row in self] from .output import tex_from_array @@ -477,7 +477,7 @@ def chi(x): else: return "["+"".join(self[i]._latex_()+',' for i in range(len(self)-1))+self[len(self)-1]._latex_()+"]" - def representation(self, representation = 'core'): + def representation(self, representation='core'): r""" Return the analogue of ``self`` in the specified representation. @@ -605,7 +605,7 @@ def size(self): else: return self._outer_shape.length() - self._inner_shape.length() - def representation(self, representation = 'core'): + def representation(self, representation='core'): r""" Return the analogue of ``self`` in the specified representation. @@ -656,7 +656,7 @@ def representation(self, representation = 'core'): if self._representation == 'bounded' and (representation in ['core', 'factorized_permutation']): outer_shape = outer_shape.to_core(self.k) inner_shape = inner_shape.to_core(self.k) - return WeakTableaux(self.k, [outer_shape, inner_shape], weight, representation = representation) + return WeakTableaux(self.k, [outer_shape, inner_shape], weight, representation=representation) #Weak Tableaux in terms of cores @@ -898,7 +898,7 @@ def to_factorized_permutation_tableau(self): """ shapes = [ Core(p,self.k+1).to_grassmannian() for p in self.intermediate_shapes() ] perms = [ shapes[i]*(shapes[i-1].inverse()) for i in range(len(shapes)-1,0,-1)] - return WeakTableau_factorized_permutation(perms, self.k, inner_shape = self.parent()._inner_shape) + return WeakTableau_factorized_permutation(perms, self.k, inner_shape=self.parent()._inner_shape) def residues_of_entries(self, v): r""" @@ -960,8 +960,8 @@ def dictionary_of_coordinates_at_residues(self, v): d[r] = [] for i in range(len(self)): for j in range(len(self[i])): - if self[i][j]==v and (j - i)%(self.k+1) == r: - d[r]+=[(i,j)] + if self[i][j] == v and (j - i) % (self.k+1) == r: + d[r] += [(i,j)] return d def list_of_standard_cells(self): @@ -1027,13 +1027,13 @@ def list_of_standard_cells(self): D = self.dictionary_of_coordinates_at_residues(v+1) new_D = {a: b for (a, b) in D.items() if all(x not in already_used for x in b)} - r = (r - min([self.k+1 - (x-r)%(self.k+1) for x in new_D]))%(self.k+1) + r = (r - min([self.k+1 - (x-r) % (self.k+1) for x in new_D])) % (self.k+1) standard_cells.append(new_D[r][-1]) already_used += new_D[r] out.append(standard_cells) return out - def k_charge(self, algorithm = "I"): + def k_charge(self, algorithm="I"): r""" Return the `k`-charge of ``self``. @@ -1165,8 +1165,8 @@ def k_charge_J(self): Ji = 0 for i in range(len(sw)-1): c = (self._height_of_restricted_subword(sw,i+2)+1,0) - cdi = self.parent().circular_distance((-c[0])%(self.k+1),(sw[i][1]-sw[i][0])%(self.k+1)) - cdi1 = self.parent().circular_distance((-c[0])%(self.k+1),(sw[i+1][1]-sw[i+1][0])%(self.k+1)) + cdi = self.parent().circular_distance((-c[0]) % (self.k+1),(sw[i][1]-sw[i][0]) % (self.k+1)) + cdi1 = self.parent().circular_distance((-c[0]) % (self.k+1),(sw[i+1][1]-sw[i+1][0]) % (self.k+1)) if (cdi > cdi1): Ji += 1 kch += Ji + self.parent().diag(sw[i+1],c) @@ -1215,7 +1215,6 @@ def _height_of_restricted_subword(self, sw, r): return max(v[0] for v in L + R) - class WeakTableaux_core(WeakTableaux_abstract): r""" The class of (skew) weak `k`-tableaux in the core representation of shape ``shape`` @@ -1290,7 +1289,7 @@ def __init__(self, k, shape, weight): self._shape = (self._outer_shape, self._inner_shape) self._weight = weight self._representation = 'core' - Parent.__init__(self, category = FiniteEnumeratedSets()) + Parent.__init__(self, category=FiniteEnumeratedSets()) def _repr_(self): """ @@ -1366,7 +1365,7 @@ def circular_distance(self, cr, r): sage: T.circular_distance(8, 9) 10 """ - return self.k - ((r+self.k-cr)%(self.k+1)) + return self.k - ((r+self.k-cr) % (self.k+1)) Element = WeakTableau_core @@ -1408,7 +1407,7 @@ def __classcall_private__(cls, t, k): inner = tab.inner_shape() weight = tuple(tab.weight()) if outer.conjugate().length() > k: - raise ValueError("The shape of %s is not %s-bounded"%(t, k)) + raise ValueError("The shape of %s is not %s-bounded" % (t, k)) return WeakTableaux_bounded(k, [outer, inner], weight)(t) def __init__(self, parent, t): @@ -1451,7 +1450,7 @@ def __init__(self, parent, t): k = parent.k self.k = k if parent._outer_shape.conjugate().length() > k: - raise ValueError("%s is not a %s-bounded tableau"%(t, k)) + raise ValueError("%s is not a %s-bounded tableau" % (t, k)) ClonableList.__init__(self, parent, [list(r) for r in t]) def _repr_diagram(self): @@ -1654,7 +1653,7 @@ def from_core_tableau(cls, t, k): l = l_new return cls(l, k) - def k_charge(self, algorithm = 'I'): + def k_charge(self, algorithm='I'): r""" Return the `k`-charge of ``self``. @@ -1681,7 +1680,7 @@ def k_charge(self, algorithm = 'I'): sage: t.k_charge() 12 """ - return self.to_core_tableau().k_charge(algorithm = algorithm) + return self.to_core_tableau().k_charge(algorithm=algorithm) class WeakTableaux_bounded(WeakTableaux_abstract): @@ -1756,7 +1755,7 @@ def __init__(self, k, shape, weight): self._shape = (self._outer_shape, self._inner_shape) self._weight = tuple(weight) self._representation = 'bounded' - Parent.__init__(self, category = FiniteEnumeratedSets()) + Parent.__init__(self, category=FiniteEnumeratedSets()) def _repr_(self): """ @@ -1838,7 +1837,7 @@ def straighten_input(t, k): return w_tuple @staticmethod - def __classcall_private__(cls, t, k, inner_shape = []): + def __classcall_private__(cls, t, k, inner_shape=[]): r""" Implements the shortcut ``WeakTableau_factorized_permutation(t, k)`` to ``WeakTableaux_factorized_permutation(k, shape, weight)(t)`` @@ -2086,9 +2085,9 @@ def from_core_tableau(cls, t, k): t = SkewTableau(list(t)) shapes = [ Core(p, k+1).to_grassmannian() for p in intermediate_shapes(t) ] #t.to_chain() ] perms = [ shapes[i]*(shapes[i-1].inverse()) for i in range(len(shapes)-1,0,-1)] - return cls(perms, k, inner_shape = t.inner_shape()) + return cls(perms, k, inner_shape=t.inner_shape()) - def k_charge(self, algorithm = 'I'): + def k_charge(self, algorithm='I'): r""" Return the `k`-charge of ``self``. @@ -2108,7 +2107,7 @@ def k_charge(self, algorithm = 'I'): sage: t.k_charge() 12 """ - return self.to_core_tableau().k_charge(algorithm = algorithm) + return self.to_core_tableau().k_charge(algorithm=algorithm) class WeakTableaux_factorized_permutation(WeakTableaux_abstract): @@ -2179,7 +2178,7 @@ def __init__(self, k, shape, weight): self._shape = (self._outer_shape, self._inner_shape) self._weight = weight self._representation = 'factorized_permutation' - Parent.__init__(self, category = FiniteEnumeratedSets()) + Parent.__init__(self, category=FiniteEnumeratedSets()) def _repr_(self): """ @@ -2390,8 +2389,8 @@ def __classcall_private__(cls, T, k, weight=None): if weight is not None and tuple(weight) != count_marks: raise ValueError("Weight = %s and tableau = %s do not agree" % (weight, T)) tijseq = StrongTableaux.marked_CST_to_transposition_sequence(T, k) - if tijseq is None or len(tijseq)<sum(list(count_marks)): - raise ValueError("Unable to parse strong marked tableau : %s"%T) + if tijseq is None or len(tijseq) < sum(list(count_marks)): + raise ValueError("Unable to parse strong marked tableau : %s" % T) T = StrongTableaux.transpositions_to_standard_strong( tijseq, k, [[None]*r for r in inner_shape] ) # build from scratch T = T.set_weight( count_marks ) return T @@ -2454,7 +2453,7 @@ def check(self): raise ValueError("The marks in %s are not correctly placed." % (self.to_standard_list())) if not self._is_valid_standard(): raise ValueError("At least one shape in %s is not a valid %s-core." % (self.to_standard_list(), self.k+1)) - if not self.outer_shape().length()-self.inner_shape().length()==self.size(): + if not self.outer_shape().length()-self.inner_shape().length() == self.size(): raise ValueError("The size of the tableau %s and weight %s do not match" % (self.to_standard_list(),self.weight())) if not self.is_column_strict_with_weight( self.weight() ): raise ValueError("The weight=%s and the markings on the standard tableau=%s do not agree." % (self.weight(),self.to_standard_list())) @@ -2534,7 +2533,7 @@ def _is_valid_marked( self ): for i in range(len(T)): for j in range(len(T[i])): v = T[i][j] - if v is not None and v<0 and ((i!=0 and T[i-1][j]==abs(v)) or (j<len(T[i])-1 and T[i][j+1]==abs(v))): + if v is not None and v < 0 and ((i != 0 and T[i-1][j] == abs(v)) or (j < len(T[i])-1 and T[i][j+1] == abs(v))): return False return True @@ -2728,11 +2727,11 @@ def cell_of_marked_head(self, v): (0, 0) """ T = self.to_standard_list() - if T==[]: + if T == []: return (0,0) for i in range(len(T)): for j in range(len(T[i])): - if T[i][j]==-v: + if T[i][j] == -v: return (i,j) return (0,len(T[0])) @@ -2817,8 +2816,8 @@ def cells_of_marked_ribbon(self, v): T = SkewTableau(self.to_unmarked_standard_list()) cells = [] while d is not None: - adt=[c for c in T.cells_by_content(d) if T[c[0]][c[1]]==v] - if adt==[]: + adt = [c for c in T.cells_by_content(d) if T[c[0]][c[1]] == v] + if adt == []: d = None else: d -= 1 @@ -2859,15 +2858,15 @@ def cell_of_highest_head( self, v ): (0, 0) """ Tlist = SkewTableau(self.to_standard_list()) - if Tlist==[]: + if Tlist == []: return (0, 0) r = len(Tlist[0]) dout = (0, r) for d in range(-len(Tlist),r+1): for c in Tlist.cells_by_content(d): - if nabs(Tlist[c[0]][c[1]])==v: + if nabs(Tlist[c[0]][c[1]]) == v: dout = c - if dout!=(0, r) and dout[1]-dout[0]!=d: + if dout != (0, r) and dout[1]-dout[0] != d: return dout return dout @@ -3228,10 +3227,10 @@ def number_of_connected_components(self, v): 0 """ sz = len(self.cells_of_marked_ribbon(v)) - if sz==0: + if sz == 0: return 0 T = self.to_standard_list() - nocells = len([i for i in range(len(T)) for j in range(len(T[i])) if T[i][j]==v])+1 + nocells = len([i for i in range(len(T)) for j in range(len(T[i])) if T[i][j] == v])+1 return ZZ(nocells/sz) def intermediate_shapes(self): @@ -3482,7 +3481,7 @@ def f(v): if v is None: return None else: - return sgn(v)*min([i for i in range(len(self.weight())+1) if sum(self.weight()[:i])>=abs(v)]) + return sgn(v)*min([i for i in range(len(self.weight())+1) if sum(self.weight()[:i]) >= abs(v)]) return [[f(v) for v in row] for row in self.to_standard_list()] def to_unmarked_list( self ): @@ -3629,11 +3628,11 @@ def chi(x): if x is None: return "" if x in ZZ: - s = "%s"%abs(x) - if x<0: + s = "%s" % abs(x) + if x < 0: s += "^\\ast" return s - return "%s"%x + return "%s" % x T = [[chi(x) for x in row] for row in self.to_list()] from .output import tex_from_array return tex_from_array(T) @@ -3675,7 +3674,7 @@ def restrict( self, r ): [] """ rr = sum(self.weight()[:r]) - rest_tab = [y for y in ([x for x in row if x is None or abs(x)<=rr] for row in self.to_standard_list()) if y] + rest_tab = [y for y in ([x for x in row if x is None or abs(x) <= rr] for row in self.to_standard_list()) if y] new_parent = StrongTableaux( self.k, (Core([len(x) for x in rest_tab], self.k+1), self.inner_shape()), self.weight()[:r] ) return new_parent(rest_tab) @@ -3711,7 +3710,7 @@ def set_weight( self, mu ): sage: StrongTableau([],4).set_weight([]) [] """ - if sum(mu)!=self.size() or self.is_column_strict_with_weight( mu ): + if sum(mu) != self.size() or self.is_column_strict_with_weight( mu ): return StrongTableaux.__classcall__(StrongTableaux, self.k, (self.outer_shape(), self.inner_shape()), tuple(mu))(self.to_standard_list()) else: raise ValueError("%s is not a semistandard strong tableau with respect to the partition %s" % (self, mu)) @@ -3946,7 +3945,7 @@ def __init__( self, k, shape, weight ): self._weight = (1,)*(self._outer_shape.length()-self._inner_shape.length()) else: self._weight = weight - Parent.__init__(self, category = FiniteEnumeratedSets()) + Parent.__init__(self, category=FiniteEnumeratedSets()) @staticmethod def __classcall_private__(cls, k, shape, weight=None): @@ -3958,9 +3957,9 @@ def __classcall_private__(cls, k, shape, weight=None): sage: ST3 = StrongTableaux(3, [2,2], weight=[1,1,1,1]) sage: TestSuite(ST3).run() """ - if k<=0: + if k <= 0: raise ValueError("The input k has to be a positive integer") - if shape==[] or shape[0] in ZZ: + if shape == [] or shape[0] in ZZ: outer_shape = Core(shape,k+1) inner_shape = Core([],k+1) else: @@ -3985,13 +3984,13 @@ def _repr_( self ): sage: StrongTableaux(3, [[],[]], weight=[]) Set of strong 3-tableaux of shape [] and of weight () """ - if self._inner_shape==Core([],self.k+1): + if self._inner_shape == Core([],self.k+1): s = "Set of strong %s-tableaux" % self.k - s +=" of shape %s" % self._outer_shape + s += " of shape %s" % self._outer_shape else: s = "Set of strong %s-tableaux" % self.k - s +=" of shape [%s, %s]" % (self._outer_shape, self._inner_shape) - s +="%sand of weight %s" % (" ",self._weight) + s += " of shape [%s, %s]" % (self._outer_shape, self._inner_shape) + s += "%sand of weight %s" % (" ",self._weight) return s options = Tableaux.options @@ -4100,7 +4099,7 @@ def __iter__(self): [[]] """ size = sum(self._weight) - if size==0: + if size == 0: yield self([[None]*(row) for row in self._inner_shape]) else: for unT in StrongTableaux.standard_unmarked_iterator( self.k, size, self._outer_shape, self._inner_shape ): @@ -4154,7 +4153,7 @@ def standard_unmarked_iterator( cls, k, size, outer_shape=None, inner_shape=[] ) sage: list(StrongTableaux.standard_unmarked_iterator(4,0, outer_shape=[])) [[]] """ - if size==0: + if size == 0: if outer_shape is None or Core(outer_shape,k+1).contains(inner_shape): yield [[None]*(inner_shape[i]) for i in range(len(inner_shape))] else: @@ -4217,7 +4216,7 @@ def marked_given_unmarked_and_weight_iterator(cls, unmarkedT, k, weight): import itertools dsc = Composition(weight).descents() for m in itertools.product(*[td[key] for key in sorted(td)]): - if all(((m[i][1]-m[i][0]<m[i+1][1]-m[i+1][0]) or (i in dsc)) + if all(((m[i][1]-m[i][0] < m[i+1][1]-m[i+1][0]) or (i in dsc)) for i in range(len(m)-1)): yield StrongTableaux.add_marking(unmarkedT, m, k, weight) @@ -4305,16 +4304,16 @@ def _left_action_list( cls, Tlist, tij, v, k ): """ innershape = Core([len(r) for r in Tlist], k + 1) outershape = innershape.affine_symmetric_group_action(tij, transposition=True) - if outershape.length()==innershape.length()+1: + if outershape.length() == innershape.length()+1: for c in SkewPartition([outershape.to_partition(),innershape.to_partition()]).cells(): - while c[0]>=len(Tlist): + while c[0] >= len(Tlist): Tlist.append([]) Tlist[c[0]].append( v ) - if len(Tlist[c[0]])-c[0]==tij[1]: + if len(Tlist[c[0]])-c[0] == tij[1]: Tlist[c[0]][-1] = -Tlist[c[0]][-1] #mark the cell that is on the j-1 diagonal return Tlist else: - raise ValueError("%s is not a single step up in the strong lattice"%tij) + raise ValueError("%s is not a single step up in the strong lattice" % tij) @classmethod def follows_tableau_unsigned_standard( cls, Tlist, k ): @@ -4515,7 +4514,7 @@ def marked_CST_to_transposition_sequence(self, T, k): LL = list(T) if not LL or all(v is None for v in sum(LL,[])): return [] - marks = [v for row in T for v in row if v is not None and v<0] + [0] + marks = [v for row in T for v in row if v is not None and v < 0] + [0] m = -min(marks) # the largest marked cell transeq = [] # start with the empty list and append on the right sh = Core([len(r) for r in T], k + 1) @@ -4592,7 +4591,7 @@ def transpositions_to_standard_strong( self, transeq, k, emptyTableau=[] ): out = copy.deepcopy(emptyTableau) for i in range(1,len(transeq)+1): out = StrongTableaux._left_action_list(out, transeq[-i], i, k) - return StrongTableau(out, k, weight = (1,)*len(transeq)) + return StrongTableau(out, k, weight=(1,)*len(transeq)) Element = StrongTableau diff --git a/src/sage/combinat/kazhdan_lusztig.py b/src/sage/combinat/kazhdan_lusztig.py index e5a1456b7de..0c213ea9013 100644 --- a/src/sage/combinat/kazhdan_lusztig.py +++ b/src/sage/combinat/kazhdan_lusztig.py @@ -20,7 +20,7 @@ #***************************************************************************** -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_element import Polynomial from sage.misc.cachefunc import cached_method from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial from sage.structure.sage_object import SageObject @@ -76,7 +76,7 @@ def __init__(self, W, q, trace=False): self._trace = trace self._one = W.one() self._base_ring = q.parent() - if is_Polynomial(q): + if isinstance(q, Polynomial): self._base_ring_type = "polynomial" elif isinstance(q, LaurentPolynomial): self._base_ring_type = "laurent" diff --git a/src/sage/combinat/key_polynomial.py b/src/sage/combinat/key_polynomial.py index be4d5aa8c04..d132b037de3 100644 --- a/src/sage/combinat/key_polynomial.py +++ b/src/sage/combinat/key_polynomial.py @@ -29,6 +29,7 @@ # **************************************************************************** from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis +from sage.misc.cachefunc import cached_method from sage.combinat.integer_vector import IntegerVectors from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.permutation import Permutation @@ -558,6 +559,7 @@ def __getitem__(self, c): c = C(c) return self._monomial(c) + @cached_method def one_basis(self): r""" Return the basis element indexing the identity. @@ -576,6 +578,22 @@ def one_basis(self): return self._indices([0] * self._k) return self._indices([]) + def degree_on_basis(self, alpha): + """ + Return the degree of the basis element indexed by ``alpha``. + + EXAMPLES:: + + sage: k = KeyPolynomials(QQ) + sage: k.degree_on_basis([2,1,0,2]) + 5 + + sage: k = KeyPolynomials(QQ, 5) + sage: k.degree_on_basis([2,1,0,2,0]) + 5 + """ + return ZZ(sum(alpha)) + def polynomial_ring(self): r""" Return the polynomial ring associated to ``self``. @@ -776,6 +794,7 @@ def divided_difference(f, i): si_f = f.subs({z[i]: z[i-1], z[i-1]: z[i]}) return (si_f - f) // (z[i] - z[i-1]) + def isobaric_divided_difference(f, w): r""" Apply the isobaric divided difference operator `\pi_w` to the @@ -821,6 +840,7 @@ def isobaric_divided_difference(f, w): f = (si_fp - fp) // (z[i] - z[i-1]) return f + def sorting_word(alpha): r""" Get a reduced word for the permutation which sorts ``alpha`` diff --git a/src/sage/combinat/knutson_tao_puzzles.py b/src/sage/combinat/knutson_tao_puzzles.py index 13df595dce4..72c3ea9c52e 100644 --- a/src/sage/combinat/knutson_tao_puzzles.py +++ b/src/sage/combinat/knutson_tao_puzzles.py @@ -1195,7 +1195,7 @@ def is_completed(self): sage: puzzle.is_completed() True """ - (i, j) = self.kink_coordinates() + i, _ = self.kink_coordinates() return i == self._n + 1 def south_labels(self): @@ -1225,7 +1225,7 @@ def add_piece(self, piece): sage: P.add_piece(piece); P {(1, 4): 1/0\0} """ - (i, j) = self.kink_coordinates() + i, j = self.kink_coordinates() self._squares[i, j] = piece if isinstance(piece, DeltaPiece): i += 1 @@ -1253,7 +1253,7 @@ def add_pieces(self, pieces): sage: P {(1, 4): 1/0\0, (2, 4): 1/0\0} """ - (i, j) = self.kink_coordinates() + i, j = self.kink_coordinates() for piece in pieces: self._squares[i, j] = piece if isinstance(piece, DeltaPiece): @@ -2178,7 +2178,7 @@ def _fill_puzzle_by_strips(self, lamda, mu): queue = [PuzzleFilling(lamda, mu)] while queue: PP = queue.pop() - (i, j) = PP.kink_coordinates() + i, _ = PP.kink_coordinates() # grab nw labels if i == 1: diff --git a/src/sage/combinat/matrices/dancing_links.pyx b/src/sage/combinat/matrices/dancing_links.pyx index 9b5ee82aa81..df6cb7915f8 100644 --- a/src/sage/combinat/matrices/dancing_links.pyx +++ b/src/sage/combinat/matrices/dancing_links.pyx @@ -330,7 +330,6 @@ cdef class dancing_linksWrapper: """ return PyObject_RichCompare(left._rows, right._rows, op) - def get_solution(self): """ Return the current solution. @@ -473,7 +472,7 @@ cdef class dancing_linksWrapper: from copy import copy rows = copy(self._rows) ncols = self.ncols() - for i,row_index in enumerate(indices): + for i, row_index in enumerate(indices): # in the line below we want the creation of a new list rows[row_index] = rows[row_index] + [ncols+i] return dlx_solver(rows) @@ -546,8 +545,8 @@ cdef class dancing_linksWrapper: if not 0 <= column < self.ncols(): raise ValueError("column(={}) must be in range(ncols) " "where ncols={}".format(column, self.ncols())) - indices = [i for (i,row) in enumerate(self._rows) if column in row] - return {i:self.restrict([i]) for i in indices} + indices = (i for i, row in enumerate(self._rows) if column in row) + return {i: self.restrict([i]) for i in indices} def solutions_iterator(self): r""" @@ -792,7 +791,7 @@ cdef class dancing_linksWrapper: L.append(dlx.get_solution()) return L - indices = [i for (i,row) in enumerate(self._rows) if column in row] + indices = [i for i, row in enumerate(self._rows) if column in row] L = [] for (args_kwds, val) in all_solutions(indices): L.extend(val) @@ -892,7 +891,7 @@ cdef class dancing_linksWrapper: N += 1 return N - indices = [i for (i,row) in enumerate(self._rows) if column in row] + indices = [i for i, row in enumerate(self._rows) if column in row] return sum(val for (args_kwds, val) in nb_sol(indices)) @cached_method @@ -935,7 +934,7 @@ cdef class dancing_linksWrapper: # Note that row number i is associated to SAT variable i+1 to # avoid a variable zero columns = [[] for _ in range(self.ncols())] - for i,row in enumerate(self.rows(), start=1): + for i, row in enumerate(self.rows(), start=1): for a in row: columns[a].append(i) @@ -946,8 +945,8 @@ cdef class dancing_linksWrapper: # At most one 1 in each column import itertools for clause in columns: - for p,q in itertools.combinations(clause, 2): - sub_clause = [-p,-q] + for p, q in itertools.combinations(clause, 2): + sub_clause = [-p, -q] s.add_clause(sub_clause) return s @@ -995,13 +994,12 @@ cdef class dancing_linksWrapper: sage: d = dlx_solver(rows) sage: d.one_solution_using_sat_solver() is None True - """ sat_solver = self.to_sat_solver(solver) solution = sat_solver() if not solution: return None - return [key for (key,val) in enumerate(solution, start=-1) if val] + return [key for key, val in enumerate(solution, start=-1) if val] @cached_method def to_milp(self, solver=None): @@ -1030,7 +1028,7 @@ cdef class dancing_linksWrapper: sage: d = dlx_solver(rows) sage: p,x = d.to_milp() sage: p - Boolean Program (no objective, 4 variables, 4 constraints) + Boolean Program (no objective, 4 variables, ... constraints) sage: x MIPVariable with 4 binary components @@ -1041,7 +1039,7 @@ cdef class dancing_linksWrapper: Maximization: <BLANKLINE> <BLANKLINE> - Constraints: + Constraints:... one 1 in 0-th column: 1.0 <= x_0 + x_1 <= 1.0 one 1 in 1-th column: 1.0 <= x_0 + x_2 <= 1.0 one 1 in 2-th column: 1.0 <= x_0 + x_1 <= 1.0 @@ -1123,18 +1121,17 @@ cdef class dancing_linksWrapper: sage: d = dlx_solver(rows) sage: d.one_solution_using_milp_solver() is None True - """ from sage.numerical.mip import MIPSolverException - p,x = self.to_milp(solver) + p, x = self.to_milp(solver) try: p.solve() except MIPSolverException: return None - else: - soln = p.get_values(x, convert=bool, tolerance=integrality_tolerance) - support = sorted(key for key in soln if soln[key]) - return support + + soln = p.get_values(x, convert=bool, tolerance=integrality_tolerance) + return sorted(key for key in soln if soln[key]) + def dlx_solver(rows): """ diff --git a/src/sage/combinat/matrices/dlxcpp.py b/src/sage/combinat/matrices/dlxcpp.py index 4e12b98e325..e235f885188 100644 --- a/src/sage/combinat/matrices/dlxcpp.py +++ b/src/sage/combinat/matrices/dlxcpp.py @@ -92,14 +92,14 @@ def AllExactCovers(M): EXAMPLES: No exact covers:: - sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) - sage: [cover for cover in AllExactCovers(M)] + sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) # optional - sage.modules + sage: [cover for cover in AllExactCovers(M)] # optional - sage.modules [] Two exact covers:: - sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) - sage: [cover for cover in AllExactCovers(M)] + sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) # optional - sage.modules + sage: [cover for cover in AllExactCovers(M)] # optional - sage.modules [[(1, 1, 0), (0, 0, 1)], [(1, 0, 1), (0, 1, 0)]] """ rows = [] @@ -119,11 +119,11 @@ def OneExactCover(M): EXAMPLES:: - sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) #no exact covers - sage: print(OneExactCover(M)) + sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) # no exact covers # optional - sage.modules + sage: print(OneExactCover(M)) # optional - sage.modules None - sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) #two exact covers - sage: OneExactCover(M) + sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) # two exact covers # optional - sage.modules + sage: OneExactCover(M) # optional - sage.modules [(1, 1, 0), (0, 0, 1)] """ diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 91f73d29101..6174fe3df50 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -29,13 +29,35 @@ matrix of order `n` exists if and only if `n= 1, 2` or `n` is a multiple of `4`. -The module below implements the Paley constructions (see for example -[Hora]_) and the Sylvester construction. It also allows you to pull a -Hadamard matrix from the database at [SloaHada]_. +The module below implements constructions of Hadamard and skew Hadamard matrices +for all known orders `\le 1000`, plus some more greater than `1000`. It also +allows you to pull a Hadamard matrix from the database at [SloaHada]_. + +The following code will test that a construction for all known orders `\le 4k` +is implemented. The assertion above can be verified by setting ``k=250`` +(note that it will take a long time to run):: + + sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix, + ....: skew_hadamard_matrix, is_hadamard_matrix, + ....: is_skew_hadamard_matrix) + sage: k = 20 + sage: unknown_hadamard = [668, 716, 892] + sage: unknown_skew_hadamard = [356, 404, 428, 476, 596, 612, 668, 708, 712, 716, + ....: 764, 772, 804, 808, 820, 836, 856, 892, 900, 916, + ....: 932, 940, 952, 980, 996] + sage: for n in range(1, k+1): + ....: if 4*n not in unknown_hadamard: + ....: H = hadamard_matrix(4*n, check=False) + ....: assert is_hadamard_matrix(H) + ....: if 4*n not in unknown_skew_hadamard: + ....: H = skew_hadamard_matrix(4*n, check=False) + ....: assert is_skew_hadamard_matrix(H) AUTHORS: - David Joyner (2009-05-17): initial version +- Matteo Cati (2023-03-18): implemented more constructions for Hadamard and skew + Hadamard matrices, to cover all known orders up to 1000. REFERENCES: @@ -46,51 +68,77 @@ - [Hora]_ """ -#***************************************************************************** +# ***************************************************************************** # 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. # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** +from math import sqrt from urllib.request import urlopen -from sage.combinat.designs.difference_family import skew_supplementary_difference_set +from sage.arith.misc import divisors, is_prime_power, is_square, is_prime +from sage.combinat.designs.difference_family import (get_fixed_relative_difference_set, + relative_difference_set_from_homomorphism, + skew_supplementary_difference_set, + complementary_difference_sets) +from sage.combinat.t_sequences import T_sequences_smallcases +from sage.cpython.string import bytes_to_str from sage.rings.integer_ring import ZZ -from sage.matrix.constructor import matrix, block_matrix, block_diagonal_matrix, diagonal_matrix -from sage.arith.all import is_square, is_prime_power, divisors -from math import sqrt -from sage.matrix.constructor import identity_matrix as I -from sage.matrix.constructor import ones_matrix as J -from sage.matrix.constructor import zero_matrix +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.matrix.constructor import (block_matrix, + block_diagonal_matrix, + diagonal_matrix, + identity_matrix as I, + ones_matrix as J, + matrix, + matrix_method, + zero_matrix) from sage.misc.unknown import Unknown -from sage.cpython.string import bytes_to_str from sage.modules.free_module_element import vector -from sage.combinat.t_sequences import T_sequences_smallcases -def normalise_hadamard(H): +def normalise_hadamard(H, skew=False): r""" Return the normalised Hadamard matrix corresponding to ``H``. The normalised Hadamard matrix corresponding to a Hadamard matrix `H` is a matrix whose every entry in the first row and column is +1. + If ``skew`` is True, the matrix returned will be skew-normal: a skew Hadamard + matrix with first row of all `+1`. + EXAMPLES:: - sage: from sage.combinat.matrices.hadamard_matrix import normalise_hadamard + sage: from sage.combinat.matrices.hadamard_matrix import normalise_hadamard, is_hadamard_matrix, skew_hadamard_matrix sage: H = normalise_hadamard(hadamard_matrix(4)) sage: H == hadamard_matrix(4) True + sage: H = normalise_hadamard(skew_hadamard_matrix(20, skew_normalize=False), skew=True) + sage: is_hadamard_matrix(H, skew=True, normalized=True) + True + + If ``skew`` is True but the Hadamard matrix is not skew, the matrix returned + will not be normalized:: + + sage: H = normalise_hadamard(hadamard_matrix(92), skew=True) + sage: is_hadamard_matrix(H, normalized=True) + False """ - for i in range(H.ncols()): - if H[0, i] < 0: - H.rescale_col(i, -1) - for i in range(H.nrows()): - if H[i, 0] < 0: - H.rescale_row(i, -1) - return H + + if skew: + dd = diagonal_matrix(H[0]) + return dd*H*dd + else: + for i in range(H.ncols()): + if H[0, i] < 0: + H.rescale_col(i, -1) + for i in range(H.nrows()): + if H[i, 0] < 0: + H.rescale_row(i, -1) + return H def hadamard_matrix_paleyI(n, normalize=True): @@ -103,8 +151,7 @@ def hadamard_matrix_paleyI(n, normalize=True): INPUT: - ``n`` -- the matrix size - - - ``normalize`` (boolean) -- whether to normalize the result. + - ``normalize``-- boolean (default: ``True``); whether to normalize the result EXAMPLES: @@ -140,26 +187,76 @@ def hadamard_matrix_paleyI(n, normalize=True): True """ p = n - 1 - if not(is_prime_power(p) and (p % 4 == 3)): + if not (is_prime_power(p) and (p % 4 == 3)): raise ValueError("The order %s is not covered by the Paley type I construction." % n) from sage.rings.finite_rings.finite_field_constructor import FiniteField - K = FiniteField(p,'x') + K = FiniteField(p, 'x') K_list = list(K) - K_list.insert(0,K.zero()) + K_list.insert(0, K.zero()) H = matrix(ZZ, [[(1 if (x-y).is_square() else -1) for x in K_list] for y in K_list]) for i in range(n): - H[i,0] = -1 - H[0,i] = 1 + H[i, 0] = -1 + H[0, i] = 1 if normalize: for i in range(n): - H[i,i] = -1 + H[i, i] = -1 H = normalise_hadamard(H) return H +def symmetric_conference_matrix_paley(n): + r""" + Construct a symmetric conference matrix of order n. + + A conference matrix is an `n\times n` matrix `C` with 0s on the main diagonal + and 1s and -1s elsewhere, satisfying `CC^\top=(n-1)I`. This construction assumes + that `q = n-1` is a prime power, with `q \cong 1 \mod 4`. See [Hora]_ or [Lon2013]_. + + These matrices are used in :func:`hadamard_matrix_paleyII`. + + INPUT: + + - ``n`` -- integer; the order of the symmetric conference matrix to construct + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import symmetric_conference_matrix_paley + sage: symmetric_conference_matrix_paley(6) + [ 0 1 1 1 1 1] + [ 1 0 1 -1 -1 1] + [ 1 1 0 1 -1 -1] + [ 1 -1 1 0 1 -1] + [ 1 -1 -1 1 0 1] + [ 1 1 -1 -1 1 0] + + TESTS:: + + sage: symmetric_conference_matrix_paley(5) + Traceback (most recent call last): + ... + ValueError: The order 5 is not covered by Paley construction of symmetric conference matrices. + """ + q = n - 1 + if not (is_prime_power(q) and (q % 4 == 1)): + raise ValueError("The order %s is not covered by Paley construction of symmetric conference matrices." % n) + + from sage.rings.finite_rings.finite_field_constructor import FiniteField + K = FiniteField(q, 'x') + K_list = list(K) + K_list.insert(0, K.zero()) + H = matrix(ZZ, [[(1 if (x-y).is_square() else -1) + for x in K_list] + for y in K_list]) + for i in range(n): + H[0, i] = 1 + H[i, 0] = 1 + H[i, i] = 0 + return H + + def hadamard_matrix_paleyII(n): r""" Implement the Paley type II construction. @@ -204,29 +301,127 @@ def hadamard_matrix_paleyII(n): True """ q = n//2 - 1 - if not(n%2==0 and is_prime_power(q) and (q % 4 == 1)): + if not (n % 2 == 0 and is_prime_power(q) and (q % 4 == 1)): raise ValueError("The order %s is not covered by the Paley type II construction." % n) - from sage.rings.finite_rings.finite_field_constructor import FiniteField - K = FiniteField(q,'x') - K_list = list(K) - K_list.insert(0,K.zero()) - H = matrix(ZZ, [[(1 if (x-y).is_square() else -1) - for x in K_list] - for y in K_list]) - for i in range(q+1): - H[0,i] = 1 - H[i,0] = 1 - H[i,i] = 0 + H = symmetric_conference_matrix_paley(q+1) - tr = { 0: matrix(2,2,[ 1,-1,-1,-1]), - 1: matrix(2,2,[ 1, 1, 1,-1]), - -1: matrix(2,2,[-1,-1,-1, 1])} + tr = { 0: matrix(2, 2, [ 1, -1, -1, -1]), + 1: matrix(2, 2, [ 1, 1, 1, -1]), + -1: matrix(2, 2, [-1, -1, -1, 1])} - H = block_matrix(q+1,q+1,[tr[v] for r in H for v in r]) + H = block_matrix(q+1, q+1, [tr[v] for r in H for v in r]) return normalise_hadamard(H) + +def hadamard_matrix_miyamoto_construction(n, existence=False, check=True): + r""" + Construct Hadamard matrix using the Miyamoto construction. + + If `q = n/4` is a prime power, and there exists an Hadamard matrix of order + `q-1`, then a Hadamard matrix of order `n` can be constructed (see [Miy1991]_). + + INPUT: + + - ``n`` -- integer; the order of the matrix to be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the matrix + is a Hadamard before returning + - ``existence`` -- boolean (default: ``False``); if ``True``, only check if + the matrix exists + + OUTPUT: + + If ``existence=False``, returns the Hadamard matrix of order `n`. It raises + an error if no data is available to construct the matrix of the given order, + or if `n` does not satisfies the constraints. + If ``existence=True``, returns a boolean representing whether the matrix + can be constructed or not. + + EXAMPLES: + + By default the function returns the Hadamard matrix :: + + sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_miyamoto_construction + sage: hadamard_matrix_miyamoto_construction(20) + 20 x 20 dense matrix over Integer Ring... + + If ``existence`` is set to True, the function returns a boolean :: + + sage: hadamard_matrix_miyamoto_construction(36, existence=True) + True + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix + sage: is_hadamard_matrix(hadamard_matrix_miyamoto_construction(68, check=False)) + True + sage: hadamard_matrix_miyamoto_construction(64, existence=True) + False + sage: hadamard_matrix_miyamoto_construction(64) + Traceback (most recent call last): + ... + ValueError: The order 64 is not covered by Miyamoto construction. + sage: hadamard_matrix_miyamoto_construction(14) + Traceback (most recent call last): + ... + ValueError: No Hadamard matrix of order 14 exists. + """ + if n < 0 or n % 4 != 0: + raise ValueError(f'No Hadamard matrix of order {n} exists.') + + q = n // 4 + if existence: + return is_prime_power(q) and q % 4 == 1 and hadamard_matrix(q-1, existence=True) is True + + if not (is_prime_power(q) and q % 4 == 1 and hadamard_matrix(q-1, existence=True)): + raise ValueError(f'The order {n} is not covered by Miyamoto construction.') + + m = (q-1) // 2 + + C = symmetric_conference_matrix_paley(q + 1) + + neg = [i for i in range(2, m+2) if C[1, i] == -1] + pos = [i for i in range(m+2, 2*m+2) if C[1, i] == 1] + + for i, j in zip(neg, pos): + C.swap_rows(i, j) + C.swap_columns(i, j) + + C1 = -C.submatrix(row=2, col=2, nrows=m, ncols=m) + C2 = C.submatrix(row=2, col=m+2, nrows=m, ncols=m) + C4 = C.submatrix(row=m+2, col=m+2, nrows=m, ncols=m) + + K = hadamard_matrix(q - 1) + K1 = K.submatrix(row=0, col=0, nrows=(q-1)//2, ncols=(q-1)//2) + K2 = K.submatrix(row=0, col=(q-1)//2, nrows=(q-1)//2, ncols=(q-1)//2) + K3 = -K.submatrix(row=(q-1)//2, col=0, nrows=(q-1)//2, ncols=(q-1)//2) + K4 = K.submatrix(row=(q-1)//2, col=(q-1)//2, nrows=(q-1)//2, ncols=(q-1)//2) + + Zr = zero_matrix(m) + Us = [[C1, C2, Zr, Zr], [C2.T, C4, Zr, Zr], [Zr, Zr, C1, C2], [Zr, Zr, C2.T, C4]] + Vs = [[I(m), Zr, K1, K2], [Zr, I(m), K3, K4], [K1.T, K3.T, I(m), Zr], [K2.T, K4.T, Zr, I(m)]] + + def T(i, j): + return block_matrix([[Us[i][j]+Vs[i][j], Us[i][j]-Vs[i][j]], + [Us[i][j]-Vs[i][j], Us[i][j]+Vs[i][j]]]) + + e = matrix([[1] * (2*m)]) + one = matrix([1]) + H = block_matrix([[ one, -e, one, e, one, e, one, e], + [-e.T, T(0, 0), e.T, T(0, 1), e.T, T(0, 2), e.T, T(0, 3)], + [-one, -e, one, -e, one, e, -one, -e], + [-e.T, -T(1, 0), -e.T, T(1, 1), e.T, T(1, 2), -e.T, -T(1, 3)], + [-one, -e, -one, -e, one, -e, one, e], + [-e.T, -T(2, 0), -e.T, -T(2, 1), -e.T, T(2, 2), e.T, T(2, 3)], + [-one, -e, one, e, -one, -e, one, -e], + [-e.T, -T(3, 0), e.T, T(3, 1), -e.T, -T(3, 2), -e.T, T(3, 3)]]) + + if check: + assert is_hadamard_matrix(H) + return H + + def hadamard_matrix_williamson_type(a, b, c, d, check=True): r""" Construction of Williamson type Hadamard matrix. @@ -237,15 +432,12 @@ def hadamard_matrix_williamson_type(a, b, c, d, check=True): INPUT: - - ``a`` -- (1,-1) list specifying the 1st row of `A`. - - - ``b`` -- (1,-1) list specifying the 1st row of `B`. - - - ``d`` -- (1,-1) list specifying the 1st row of `C`. - - - ``c`` -- (1,-1) list specifying the 1st row of `D`. - - - ``check`` (boolean) -- Whether to check that the output is an Hadamard matrix before returning it. + - ``a`` -- (1,-1) list; the 1st row of `A` + - ``b`` -- (1,-1) list; the 1st row of `B` + - ``d`` -- (1,-1) list; the 1st row of `C` + - ``c`` -- (1,-1) list; the 1st row of `D` + - ``check`` -- boolean (default: ``True``); whether to check that the output + is an Hadamard matrix before returning it EXAMPLES:: @@ -280,16 +472,17 @@ def hadamard_matrix_williamson_type(a, b, c, d, check=True): n = len(a) assert len(a) == len(b) == len(c) == len(d) - assert A*A.T+B*B.T+C*C.T+D*D.T==4*n*I(n) + assert A*A.T+B*B.T+C*C.T+D*D.T == 4*n*I(n) M = block_matrix([[ A, B, C, D], [-B, A, -D, C], [-C, D, A, -B], - [-D, -C, B, A]]) + [-D, -C, B, A]]) if check: assert is_hadamard_matrix(M, normalized=False, skew=False) return M + def williamson_type_quadruples_smallcases(n, existence=False): r""" Quadruples of matrices that can be used to construct Williamson type Hadamard matrices. @@ -298,13 +491,14 @@ def williamson_type_quadruples_smallcases(n, existence=False): Williamson construction of Hadamard matrices. Namely, the function returns the first row of 4 `n\times n` circulant matrices with the properties described in :func:`sage.combinat.matrices.hadamard_matrix.hadamard_matrix_williamson_type`. - The matrices for n=29 and n=43 are given in [Ha83]_. + The matrices for `n = 3, 5, ..., 29, 37, 43` are given in [Ha83]_. The matrices + for `n = 31, 33, 39, 41, 45, 49, 51, 55, 57, 61, 63` are given in [Lon2013]_. INPUT: - - ``n`` -- the order of the matrices to be returned - - - ``existence`` -- if true, only check that we have the quadruple (default false). + - ``n`` -- integer; the order of the matrices to be returned + - ``existence`` -- boolean (dafault: ``False``); if ``True``, only check that + we have the quadruple OUTPUT: @@ -333,33 +527,70 @@ def williamson_type_quadruples_smallcases(n, existence=False): ValueError: The Williamson type quadruple of order 123 is not yet implemented. """ db = { - 1: ([1], [1], [1], [1]), - 7: ([1, -1, -1, 1, 1, -1, -1], - [1, -1, 1, -1, -1, 1, -1], - [1, 1, -1, -1, -1, -1, 1], - [1, -1, -1, -1, -1, -1, -1]), - 9: ([1, -1, -1, -1, 1, 1, -1, -1, -1], - [1, -1, -1, 1, -1, -1, 1, -1, -1], - [1, -1, 1, -1, -1, -1, -1, 1, -1], - [1, 1, -1, -1, -1, -1, -1, -1, 1]), - 29: ([1, 1, 1,-1,-1,-1, 1, 1,-1,-1, 1,-1, 1,-1,-1,-1,-1, 1,-1, 1,-1,-1, 1, 1,-1,-1,-1, 1, 1], - [1,-1, 1,-1,-1,-1, 1, 1,-1,-1, 1,-1, 1, 1, 1, 1, 1, 1,-1, 1,-1,-1, 1, 1,-1,-1,-1, 1,-1], - [1, 1, 1, 1,-1, 1, 1,-1, 1,-1,-1,-1, 1, 1, 1, 1, 1, 1,-1,-1,-1, 1,-1, 1, 1,-1, 1, 1, 1], - [1, 1,-1,-1, 1,-1,-1, 1,-1, 1, 1, 1,-1, 1, 1, 1, 1,-1, 1, 1, 1,-1, 1,-1,-1, 1,-1,-1, 1]), - 43: ([1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1], - [1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1], - [1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1], - [1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1]), + 1: ('+', '+', '+', '+'), + 3: ('+++', '+--', '+--', '+--'), + 5: ('+-++-', '++--+', '+----', '+----'), + 7: ('+--++--', '+-+--+-', '++----+', '+------'), + 9: ('+---++---', '+--+--+--', '+-+----+-', '++------+'), + 11: ('++--------+', '++-+-++-+-+', '++-++--++-+', '+-++----++-'), + 13: ('++++-+--+-+++', '+---+-++-+---', '++---+--+---+', '++---+--+---+'), + 15: ('+-+---++++---+-', '++-++------++-+', + '++-++++--++++-+', '++-++-+--+-++-+'), + 17: ('+---+++----+++---', '++-+---+--+---+-+', + '+--+-++++++++-+--', '+-++-+++--+++-++-'), + 19: ('++--+++-+--+-+++--+', '++-++--+-++-+--++-+', + '+-+---++++++++---+-', '++--+-++++++++-+--+'), + 21: ('+--++++---++---++++--', '++++-+---+--+---+-+++', + '++--+-+-++--++-+-+--+', '++-+++++-+--+-+++++-+'), + 23: ('++---+---+-++-+---+---+', '+-++-++--++++++--++-++-', + '+++---++-+-++-+-++---++', '+++-+++-+------+-+++-++'), + 25: ('++++-+-+-+--++--+-+-+-+++', '++--+--+-++++++++-+--+--+', + '+++--+--++++--++++--+--++', '+-+--+++--++++++--+++--+-'), + 27: ('+--+--+-+++--++--+++-+--+--', '+++-++-+---++--++---+-++-++', + '+---+++++-+-++++-+-+++++---', '+---+++++-+-++++-+-+++++---'), + 29: ('+++---++--+-+----+-+--++---++', '+-+---++--+-++++++-+--++---+-', + '++++-++-+---++++++---+-++-+++', '++--+--+-+++-++++-+++-+--+--+'), + 31: ('++++++-+--+---++++---+--+-+++++', '+--++---+-+-++----++-+-+---++--', + '+--++---+-+-++----++-+-+---++--', '+-----+-++-+++----+++-++-+-----'), + 33: ('++++++-+-+-+++------+++-+-+-+++++', '++-+-++-+----+++--+++----+-++-+-+', + '++--++-+++-+--+-++-+--+-+++-++--+', '+--++--+++++-++----++-+++++--++--'), + 37: ('+--+-+-+-++---+--++++--+---++-+-+-+--', '+---++-++--+-+-++----++-+-+--++-++---', + '+++++-+-----++----++----++-----+-++++', '+--+++-+-----+----++----+-----+-+++--'), + 39: ('+++--+-+-----+--++----++--+-----+-+--++', '+++--++-+---+-+--+----+--+-+---+-++--++', + '++++---+--++----+-+--+-+----++--+---+++', '+---++-+-+-----+++-++-+++-----+-+-++---'), + 41: ('++++--+-++++-++--++----++--++-++++-+--+++', '++++--+-++++-++--++----++--++-++++-+--+++', + '+++-++-+-+-+-----+++--+++-----+-+-+-++-++', '+--+--+-+-+-+++++---++---+++++-+-+-+--+--'), + 43: ('++---++++-+--+--++--------++--+--+-++++---+', '+++-+-++--+-+-++++-+----+-++++-+-+--++-+-++', + '++-++++++----+-+--++-++-++--+-+----++++++-+', '+---++--++++-+-+++-++--++-+++-+-++++--++---'), + 45: ('+++++-++----+-++--++-++-++--++-+----++-++++', '+++---++--+-+-+-++--------++-+-+-+--++---++', + '++-+-++++-+--+--+++--++--+++--+--+-++++-+-+', '+-++-----++++-+-+++-++++-+++-+-++++-----++-'), + 49: ('++++-++-+---++-+++---++-++-++---+++-++---+-++-+++', '++++-++-+---++-+++---++-++-++---+++-++---+-++-+++', + '+----+-++++--+-+++-+-+++--+++-+-+++-+--++++-+----', '+++++-+----++-+---+-+---++---+-+---+-++----+-++++'), + 51: ('+---+++-++-+-+++--+++++--++--+++++--+++-+-++-+++---', '----+++-++-+-+++--+++++--++--+++++--+++-+-++-+++---', + '-+--+----+-+++-+-+++++--+--+--+++++-+-+++-+----+--+', '-+--+----+-+++-+-+++++--+--+--+++++-+-+++-+----+--+'), + 55: ('+-+--+-+-++--+-+++++-+++--++++--+++-+++++-+--++-+-+--+-', '--+--+-+-++--+-+++++-+++--++++--+++-+++++-+--++-+-+--+-', + '+++----++-++--++----+-+-++++++++-+-+----++--++-++----++', '+++----++-++--++----+-+-++++++++-+-+----++--++-++----++'), + 57: ('+---++-+--++++-+++-++---+-++++++-+---++-+++-++++--+-++---', '----++-+--++++-+++-++---+-++++++-+---++-+++-++++--+-++---', + '--+-+-+++--+--+-++---+++++-++++-+++++---++-+--+--+++-+-+-', '--+-+-+++--+--+-++---+++++-++++-+++++---++-+--+--+++-+-+-'), + 61: ('++--+--++--+-+-++++--+-----+------+-----+--++++-+-+--++--+--+', '++--+--++--+-+-++++--+-----+------+-----+--++++-+-+--++--+--+', + '+---+-+-++++---++--+-++-+---++++++---+-++-+--++---++++-+-+---', '++++-+-+----+++--++-+--+-+++------+++-+--+-++--+++----+-+-+++'), + 63: ('++-+++--++-++--+--+-++-+-+++--------+++-+-++-+--+--++-++--+++-+', '-+-+++--++-++--+--+-++-+-+++--------+++-+-++-+--+--++-++--+++-+', + '++++-++-+-++++-+---+---+++---++++++---+++---+---+-++++-+-++-+++', '++++-++-+-++++-+---+---+++---++++++---+++---+---+-++++-+-++-+++'), } + def pmtoZ(s): + return [1 if x == '+' else -1 for x in s] + if existence: return n in db if n not in db: raise ValueError("The Williamson type quadruple of order %s is not yet implemented." % n) - a, b, c, d = map(vector, db[n]) + + a, b, c, d = map(lambda s: vector(pmtoZ(s)), db[n]) return a, b, c, d + def williamson_hadamard_matrix_smallcases(n, existence=False, check=True): r""" Construct Williamson type Hadamard matrices for some small values of n. @@ -371,11 +602,10 @@ def williamson_hadamard_matrix_smallcases(n, existence=False, check=True): INPUT: - - ``n`` -- the order of the matrix. - - - ``existence`` -- if true, only check that we can do the construction (default false). - - - ``check`` -- if true (default), check the result. + - ``n`` -- integer; the order of the matrix + - ``existence`` -- boolean (dafault: ``False``); if ``True``, only check that + we can do the construction + - ``check`` -- boolean (default: ``True``); if ``True`` check the result TESTS:: @@ -384,14 +614,14 @@ def williamson_hadamard_matrix_smallcases(n, existence=False, check=True): 116 x 116 dense matrix over Integer Ring... sage: williamson_hadamard_matrix_smallcases(172) 172 x 172 dense matrix over Integer Ring... - sage: williamson_hadamard_matrix_smallcases(100) + sage: williamson_hadamard_matrix_smallcases(1000) Traceback (most recent call last): ... - ValueError: The Williamson type Hadamard matrix of order 100 is not yet implemented. + ValueError: The Williamson type Hadamard matrix of order 1000 is not yet implemented. """ - assert n%4 == 0 + assert n % 4 == 0 - if not williamson_type_quadruples_smallcases(n//4, existence=True): + if not williamson_type_quadruples_smallcases(n // 4, existence=True): if existence: return False raise ValueError("The Williamson type Hadamard matrix of order %s is not yet implemented." % n) @@ -419,25 +649,26 @@ def hadamard_matrix_156(): sage: hadamard_matrix_156() 156 x 156 dense matrix over Integer Ring... """ - a = [1, 1,-1,-1, 1,-1, 1, 1,-1, 1,-1,-1, 1] - b = [1,-1,-1,-1, 1, 1, 1, 1, 1, 1,-1,-1,-1] - c = [1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, 1, 1] - d = [1, 1,-1, 1,-1, 1, 1, 1, 1,-1, 1,-1, 1] + a = [1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1] + b = [1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1] + c = [1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1] + d = [1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1] A, B, C, D = map(matrix.circulant, [a, b, c, d]) - return block_matrix([[ A, A, A, B,-B, C,-C,-D, B, C,-D,-D], - [ A,-A, B,-A,-B,-D, D,-C,-B,-D,-C,-C], - [ A,-B,-A, A,-D, D,-B, B,-C,-D, C,-C], - [ B, A,-A,-A, D, D, D, C, C,-B,-B,-C], - [ B,-D, D, D, A, A, A, C,-C, B,-C, B], - [ B, C,-D, D, A,-A, C,-A,-D, C, B,-B], - [ D,-C, B,-B, A,-C,-A, A, B, C, D,-D], - [-C,-D,-C,-D, C, A,-A,-A,-D, B,-B,-B], - [ D,-C,-B,-B,-B, C, C,-D, A, A, A, D], - [-D,-B, C, C, C, B, B,-D, A,-A, D,-A], - [ C,-B,-C, C, D,-B,-D,-B, A,-D,-A, A], - [-C,-D,-D, C,-C,-B, B, B, D, A,-A,-A]]) + return block_matrix([[ A, A, A, B, -B, C, -C, -D, B, C, -D, -D], + [ A, -A, B, -A, -B, -D, D, -C, -B, -D, -C, -C], + [ A, -B, -A, A, -D, D, -B, B, -C, -D, C, -C], + [ B, A, -A, -A, D, D, D, C, C, -B, -B, -C], + [ B, -D, D, D, A, A, A, C, -C, B, -C, B], + [ B, C, -D, D, A, -A, C, -A, -D, C, B, -B], + [ D, -C, B, -B, A, -C, -A, A, B, C, D, -D], + [-C, -D, -C, -D, C, A, -A, -A, -D, B, -B, -B], + [ D, -C, -B, -B, -B, C, C, -D, A, A, A, D], + [-D, -B, C, C, C, B, B, -D, A, -A, D, -A], + [ C, -B, -C, C, D, -B, -D, -B, A, -D, -A, A], + [-C, -D, -D, C, -C, -B, B, B, D, A, -A, -A]]) + def construction_four_symbol_delta_code_I(X, Y, Z, W): r""" @@ -469,13 +700,10 @@ def construction_four_symbol_delta_code_I(X, Y, Z, W): INPUT: - - ``X`` -- a list, representing the first sequence (length `n+1`). - - - ``Y`` -- a list, representing the second sequence (length `n+1`). - - - ``Z`` -- a list, representing the third sequence (length `n`). - - - ``W`` -- a list, representing the fourth sequence (length `n`). + - ``X`` -- list; the first sequence (length `n+1`) + - ``Y`` -- list; the second sequence (length `n+1`) + - ``Z`` -- list; the third sequence (length `n`) + - ``W`` -- list; the fourth sequence (length `n`) OUTPUT: A tuple containing the 4-symbol `\delta` code of length `2n+1`. @@ -500,7 +728,8 @@ def construction_four_symbol_delta_code_I(X, Y, Z, W): n = len(X) assert len(Y) == n and len(Z) == n-1 and len(W) == n-1 - autocorrelation = lambda seq, j: sum([seq[i]*seq[i+j] for i in range(len(seq)-j)]) + def autocorrelation(seq, j): + return sum([seq[i]*seq[i+j] for i in range(len(seq)-j)]) for j in range(1, n): assert sum(map(lambda seq: autocorrelation(seq, j), [X, Y, Z, W])) == 0 @@ -541,13 +770,10 @@ def construction_four_symbol_delta_code_II(X, Y, Z, W): INPUT: - - ``X`` -- a list, representing the first sequence (length `n+1`). - - - ``Y`` -- a list, representing the second sequence (length `n+1`). - - - ``Z`` -- a list, representing the third sequence (length `n`). - - - ``W`` -- a list, representing the fourth sequence (length `n`). + - ``X`` -- list; the first sequence (length `n+1`) + - ``Y`` -- list; the second sequence (length `n+1`) + - ``Z`` -- list; the third sequence (length `n`) + - ``W`` -- list; the fourth sequence (length `n`) OUTPUT: A tuple containing the four 4-symbol `\delta` code of length `4n+3`. @@ -577,12 +803,14 @@ def construction_four_symbol_delta_code_II(X, Y, Z, W): n = len(Z) assert len(X) == n+1 and len(Y) == n+1 and len(W) == n - autocorrelation = lambda seq, j: sum([seq[i]*seq[i+j] for i in range(len(seq)-j)]) + def autocorrelation(seq, j): + return sum([seq[i]*seq[i+j] for i in range(len(seq)-j)]) + for j in range(1, n): assert sum(map(lambda seq: autocorrelation(seq, j), [X, Y, Z, W])) == 0 def alternate(seq1, seq2): - return [seq1[i//2] if i%2 == 0 else seq2[(i-1)//2] for i in range(len(seq1)+len(seq2))] + return [seq1[i//2] if i % 2 == 0 else seq2[(i-1)//2] for i in range(len(seq1)+len(seq2))] XaltZ = alternate(X, Z) Wneg = [-w for w in W] @@ -594,9 +822,10 @@ def alternate(seq1, seq2): T4 = XaltZ + alternate(Yneg, W) + [-1] return T1, T2, T3, T4 + def four_symbol_delta_code_smallcases(n, existence=False): r""" - Return the 4-symobl `\delta` code of length `n` if available. + Return the 4-symobl `\delta` code of length ``n`` if available. The 4-symbol `\delta` codes are constructed using :func:`construction_four_symbol_delta_code_I` or :func:`construction_four_symbol_delta_code_II`. @@ -604,9 +833,9 @@ def four_symbol_delta_code_smallcases(n, existence=False): INPUT: - - ``n`` -- integer, the length of the desired 4-symbol `\delta` code. - - - ``existence`` -- boolean, if true only check if the sequences are available. + - ``n`` -- integer; the length of the desired 4-symbol `\delta` code + - ``existence`` -- boolean (default: ``False``); if ``True``, only check if + the sequences are available EXAMPLES:: @@ -628,18 +857,18 @@ def four_symbol_delta_code_smallcases(n, existence=False): db = { 1: ([1, -1], [1, 1], [1], [1]), 14: ([1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1], - [1, 1, 1,-1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1], - [1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1], - [1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1]) + [1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1], + [1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1], + [1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1]) } T1, T2, T3, T4 = None, None, None, None - if n%2 == 1 and (n-1)//2 in db: + if n % 2 == 1 and (n-1)//2 in db: if existence: return True X, Y, Z, W = db[(n-1)//2] T1, T2, T3, T4 = construction_four_symbol_delta_code_I(X, Y, Z, W) - elif n%4 == 3 and (n-3)//4 in db: + elif n % 4 == 3 and (n-3) // 4 in db: if existence: return True X, Y, Z, W = db[(n-3)//4] @@ -653,7 +882,8 @@ def four_symbol_delta_code_smallcases(n, existence=False): return T1, T2, T3, T4 -def _construction_goethals_seidel_matrix(A, B ,C, D): + +def _construction_goethals_seidel_matrix(A, B, C, D): r""" Construct the Goethals Seidel matrix. @@ -674,13 +904,10 @@ def _construction_goethals_seidel_matrix(A, B ,C, D): INPUT: - - ``A`` -- The first matrix used in the construction. - - - ``B`` -- The second matrix used in the construction. - - - ``C`` -- The third matrix used in the construction. - - - ``D`` -- The fourth matrix used in the construction. + - ``A`` -- The first matrix used in the construction + - ``B`` -- The second matrix used in the construction + - ``C`` -- The third matrix used in the construction + - ``D`` -- The fourth matrix used in the construction TESTS:: @@ -703,43 +930,122 @@ def _construction_goethals_seidel_matrix(A, B ,C, D): [-1 1| 1 -1| 1 -1| 1 1] """ n = len(A[0]) - R = matrix(ZZ, n, n, lambda i,j: 1 if i+j==n-1 else 0) + R = matrix(ZZ, n, n, lambda i, j: 1 if i+j == n-1 else 0) return block_matrix([[ A, B*R, C*R, D*R], [-B*R, A, -D.T*R, C.T*R], [-C*R, D.T*R, A, -B.T*R], [-D*R, -C.T*R, B.T*R, A]]) -def hadamard_matrix_cooper_wallis_construction(x1, x2, x3, x4, A, B, C, D, check=True): + +def hadamard_matrix_from_sds(n, existence=False, check=True): r""" - Create an Hadamard matrix using the contruction detailed in [CW1972]_. + Construction of Hadamard matrices from supplementary difference sets. - Given four circulant matrices `X_1`, X_2, X_3, X_4` of order `n` with entries (0, 1, -1) - such that the entrywise product of two distinct matrices is always equal to `0` and that - `\sum_{i=1}^{4}X_iX_i^\top = nI_n` holds, and four matrices `A, B, C, D` of order `m` with - elements (1, -1) such that `MN^\top = NM^\top` for all distinct `M`, `N` and - `AA^\top + BB^\top + CC^\top + DD^\top = 4mI_n` holds, we construct an Hadamard matrix - of order `4nm`. + Given four SDS with parameters `4-\{n; n_1, n_2, n_3, n_4; \lambda\}` with + `n_1 + n_2 + n_3 + n_4 = n+\lambda` we can construct four (-1,+1) sequences `a_i = (a_{i,0},...,a_{i,n-1})` + where `a_{i,j} = -1` iff `j \in S_i`. These will be the fist rows of four circulant + matrices `A_1, A_2, A_3, A_4` which, when plugged into the Goethals-Seidel array, create an + Hadamard matrix of order `4n` (see [Djo1994b]_). + + The supplementary difference sets are taken from + :func:`sage.combinat.designs.difference_family.supplementary_difference_set`. INPUT: - - ``x1`` -- a list or vector, representing the first row of the circulant matrix `X_1`. + - ``n`` -- integer; the order of the matrix to be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the matrix + is a Hadamard before returning + - ``existence`` -- boolean (default: ``False``); if ``True``, only check if the + matrix exists + + OUTPUT: + + If ``existence=False``, returns the Hadamard matrix of order `n`. It raises + an error if no data is available to construct the matrix of the given order, + or if `n` is not a multiple of `4`. + If ``existence=True``, returns a boolean representing whether the matrix + can be constructed or not. + + EXAMPLES: + + By default The function returns the Hadamard matrix :: + + sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_from_sds + sage: hadamard_matrix_from_sds(148) + 148 x 148 dense matrix over Integer Ring... + + If ``existence`` is set to True, the function returns a boolean :: + + sage: hadamard_matrix_from_sds(764, existence=True) + True + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_from_sds, is_hadamard_matrix + sage: is_hadamard_matrix(hadamard_matrix_from_sds(172)) + True + sage: hadamard_matrix_from_sds(64, existence=True) + False + sage: hadamard_matrix_from_sds(64) + Traceback (most recent call last): + ... + ValueError: SDS of order 16 not yet implemented. + sage: hadamard_matrix_from_sds(14) + Traceback (most recent call last): + ... + ValueError: n must be a positive multiple of four. + """ + from sage.combinat.designs.difference_family import supplementary_difference_set_hadamard + + if n <= 0 or n % 4 != 0: + raise ValueError(f'n must be a positive multiple of four.') + t = n // 4 + + if existence: + return supplementary_difference_set_hadamard(t, existence=True) + + _, [S1, S2, S3, S4] = supplementary_difference_set_hadamard(t, check=False) + a = [-1 if i in S1 else 1 for i in range(t)] + b = [-1 if i in S2 else 1 for i in range(t)] + c = [-1 if i in S3 else 1 for i in range(t)] + d = [-1 if i in S4 else 1 for i in range(t)] - - ``x2`` -- a list or vector, representing the first row of the circulant matrix `X_2`. + if n == 956: + a, b, c, d = [-el for el in d], a, b, c - - ``x3`` -- a list or vector, representing the first row of the circulant matrix `X_3`. + A, B, C, D = map(matrix.circulant, [a, b, c, d]) + if check: + assert A*A.T+B*B.T+C*C.T+D*D.T == 4*t*I(t) - - ``x4`` -- a list or vector, representing the first row of the circulant matrix `X_4`. + H = _construction_goethals_seidel_matrix(A, B, C, D) + if check: + assert is_hadamard_matrix(H) + return H - - ``A`` -- the matrix described above. - - ``B`` -- the matrix described above. +def hadamard_matrix_cooper_wallis_construction(x1, x2, x3, x4, A, B, C, D, check=True): + r""" + Create an Hadamard matrix using the contruction detailed in [CW1972]_. - - ``C`` -- the matrix described above. + Given four circulant matrices `X_1`, X_2, X_3, X_4` of order `n` with entries (0, 1, -1) + such that the entrywise product of two distinct matrices is always equal to `0` and that + `\sum_{i=1}^{4}X_iX_i^\top = nI_n` holds, and four matrices `A, B, C, D` of order `m` with + elements (1, -1) such that `MN^\top = NM^\top` for all distinct `M`, `N` and + `AA^\top + BB^\top + CC^\top + DD^\top = 4mI_n` holds, we construct an Hadamard matrix + of order `4nm`. - - ``D`` -- the matrix described above. + INPUT: - - ``check`` -- a boolean, if true (default) check that the resulting matrix is Hadamard - before returing it. + - ``x1`` -- list or vector; the first row of the circulant matrix `X_1` + - ``x2`` -- list or vector; the first row of the circulant matrix `X_2` + - ``x3`` -- list or vector; the first row of the circulant matrix `X_3` + - ``x4`` -- list or vector; the first row of the circulant matrix `X_4` + - ``A`` -- the matrix described above + - ``B`` -- the matrix described above + - ``C`` -- the matrix described above + - ``D`` -- the matrix described above + - ``check`` -- boolean (default: ``True``); if ``True``, check that the resulting + matrix is Hadamard before returing it. EXAMPLES:: @@ -797,6 +1103,7 @@ def hadamard_matrix_cooper_wallis_construction(x1, x2, x3, x4, A, B, C, D, check assert is_hadamard_matrix(H) return H + def hadamard_matrix_cooper_wallis_smallcases(n, check=True, existence=False): r""" Construct Hadamard matrices using the Cooper-Wallis construction for some small values of `n`. @@ -811,17 +1118,17 @@ def hadamard_matrix_cooper_wallis_smallcases(n, check=True, existence=False): INPUT: - - ``n`` -- integer, the order of the matrix to be constructed. - - - ``check`` -- boolean: if True (default), check the the matrix is an Hadamard matrix before returning. - - - ``existence`` -- boolean (default False): if True, only check if matrix exists. + - ``n`` -- integer; the order of the matrix to be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the matrix + is an Hadamard matrix before returning + - ``existence`` -- boolean (default: ``False``); if ``True``, only check if + the matrix exists. OUTPUT: - If ``existence`` is false, returns the Hadamard matrix of order `n`. It raises an error if no data + If ``existence=False``, returns the Hadamard matrix of order `n`. It raises an error if no data is available to construct the matrix of the given order. - If ``existence`` is true, returns a boolean representing whether the matrix can be constructed or not. + If ``existence=True``, returns a boolean representing whether the matrix can be constructed or not. .. SEEALSO:: @@ -856,7 +1163,7 @@ def hadamard_matrix_cooper_wallis_smallcases(n, check=True, existence=False): ... AssertionError """ - assert n%4 == 0 and n > 0 + assert n % 4 == 0 and n > 0 db = { 67: ( @@ -868,7 +1175,7 @@ def hadamard_matrix_cooper_wallis_smallcases(n, check=True, existence=False): } for T_seq_len in divisors(n//4): - will_size = n//(4* T_seq_len) + will_size = n // (4*T_seq_len) if (T_seq_len in db or T_sequences_smallcases(T_seq_len, existence=True)) and williamson_type_quadruples_smallcases(will_size, existence=True): if existence: return True @@ -891,6 +1198,7 @@ def hadamard_matrix_cooper_wallis_smallcases(n, check=True, existence=False): return False raise ValueError("The Cooper-Wallis construction for Hadamard matrices of order %s is not yet implemented." % n) + def _get_baumert_hall_units(n, existence=False): r""" Construct Baumert-Hall units of size `n` from available 4-symbol `\delta` codes. @@ -902,14 +1210,15 @@ def _get_baumert_hall_units(n, existence=False): INPUT: - - ``n`` -- integer, the size of the Baumert-Hall units. - - - ``existence`` -- boolean (default False): if true only check whether the units can be contructed. + - ``n`` -- integer; the size of the Baumert-Hall units + - ``existence`` -- boolean (default: ``False``); if ``True``, only check whether + the units can be contructed OUTPUT: - If ``existence`` is true, return a boolean representing whether the Baumert-Hall units can - be constructed. Otherwise, return a tuple containing the four Baumert-Hall units. + If ``existence=True``, return a boolean representing whether the Baumert-Hall + units can be constructed. Otherwise, return a tuple containing the four + Baumert-Hall units. EXAMPLES:: @@ -935,8 +1244,7 @@ def _get_baumert_hall_units(n, existence=False): ... ValueError: The Baumert-Hall units of size 200 have not yet been implemented """ - assert n%4 == 0 and n > 0 - + assert n % 4 == 0 and n > 0 delta_codes_len = n//4 if not four_symbol_delta_code_smallcases(delta_codes_len, existence=True): @@ -964,6 +1272,7 @@ def _get_baumert_hall_units(n, existence=False): e4 = _construction_goethals_seidel_matrix(M4hat, M3hat, -M2hat, M1hat) return e1, e2, e3, e4 + def hadamard_matrix_turyn_type(a, b, c, d, e1, e2, e3, e4, check=True): r""" Construction of Turyn type Hadamard matrix. @@ -975,23 +1284,16 @@ def hadamard_matrix_turyn_type(a, b, c, d, e1, e2, e3, e4, check=True): INPUT: - - ``a`` -- 1,-1 list specifying the 1st row of `A`. - - - ``b`` -- 1,-1 list specifying the 1st row of `B`. - - - ``d`` -- 1,-1 list specifying the 1st row of `C`. - - - ``c`` -- 1,-1 list specifying the 1st row of `D`. - - - ``e1`` -- Matrix representing the first Baumert-Hall unit. - - - ``e2`` -- Matrix representing the second Baumert-Hall unit. - - - ``e3`` -- Matrix representing the third Baumert-Hall unit. - - - ``e4`` -- Matrix representing the fourth Baumert-Hall unit. - - - ``check`` -- Whether to check that the output is an Hadamard matrix before returning it. + - ``a`` -- 1,-1 list; the 1st row of `A` + - ``b`` -- 1,-1 list; the 1st row of `B` + - ``d`` -- 1,-1 list; the 1st row of `C` + - ``c`` -- 1,-1 list; the 1st row of `D` + - ``e1`` -- Matrix; the first Baumert-Hall unit + - ``e2`` -- Matrix; the second Baumert-Hall unit + - ``e3`` -- Matrix; the third Baumert-Hall unit + - ``e4`` -- Matrix; the fourth Baumert-Hall unit + - ``check`` -- boolean (default: ``True``); whether to check that the output + is an Hadamard matrix before returning it EXAMPLES:: @@ -1019,11 +1321,11 @@ def hadamard_matrix_turyn_type(a, b, c, d, e1, e2, e3, e4, check=True): n = len(a) assert len(a) == len(b) == len(c) == len(d) - assert A*A.T+B*B.T+C*C.T+D*D.T==4*n*I(n) + assert A*A.T+B*B.T+C*C.T+D*D.T == 4*n*I(n) t4 = len(e1[0]) - assert t4 %4 == 0 - t = t4//4 + assert t4 % 4 == 0 + t = t4 // 4 # Check that e1, e2, e3, e4 are valid Baumert-Hall units for i in range(t4): @@ -1037,12 +1339,12 @@ def hadamard_matrix_turyn_type(a, b, c, d, e1, e2, e3, e4, check=True): for j in range(i+1, len(units)): assert units[i]*units[j].T + units[j]*units[i].T == 0*I(t4) - H = e1.tensor_product(A) + e2.tensor_product(B) + e3.tensor_product(C) + e4.tensor_product(D) if check: assert is_hadamard_matrix(H) return H + def turyn_type_hadamard_matrix_smallcases(n, existence=False, check=True): r""" Construct an Hadamard matrix of order `n` from available 4-symbol `\delta` codes and Williamson quadruples. @@ -1054,11 +1356,11 @@ def turyn_type_hadamard_matrix_smallcases(n, existence=False, check=True): INPUT: - - ``n`` -- integer, the order of the matrix to be constructed. - - - ``existence`` -- boolean (default False): if True, only check if matrix exists. - - - ``check`` -- bolean: if True (default), check the the matrix is an Hadamard matrix before returning. + - ``n`` -- integer; the order of the matrix to be constructed + - ``existence`` -- boolean (default: ``False``): if ``True``, only check if + the matrix exists + - ``check`` -- boolean (default: ``True``): if ``True``, check that the matrix + is an Hadamard matrix before returning EXAMPLES:: @@ -1080,7 +1382,7 @@ def turyn_type_hadamard_matrix_smallcases(n, existence=False, check=True): ... ValueError: The Turyn type construction for Hadamard matrices of order 64 is not yet implemented. """ - assert n%4 == 0 and n > 0 + assert n % 4 == 0 and n > 0 for delta_code_len in divisors(n//4): units_size = delta_code_len*4 @@ -1097,25 +1399,28 @@ def turyn_type_hadamard_matrix_smallcases(n, existence=False, check=True): return False raise ValueError("The Turyn type construction for Hadamard matrices of order %s is not yet implemented." % n) + def hadamard_matrix_spence_construction(n, existence=False, check=True): - r"""Create an Hadamard matrix of order `n` using Spence construction. + r""" + Create an Hadamard matrix of order `n` using the Spence construction. This construction (detailed in [Spe1975]_), uses supplementary difference sets implemented in - :func:`sage.combinat.designs.difference_family.supplementary_difference_set` to create the + :func:`sage.combinat.designs.difference_family.supplementary_difference_set_from_rel_diff_set` to create the desired matrix. INPUT: - - ``n`` -- integer, the order of the matrix to be constructed. - - - ``existence`` -- boolean (default False): if True, only check if matrix exists. - - - ``check`` -- bolean: if True (default), check the the matrix is an Hadamard matrix before returning. + - ``n`` -- integer; the order of the matrix to be constructed + - ``existence`` -- boolean (default: ``False``); if ``True``, only check if + the matrix exists + - ``check`` -- bolean (default: ``True``); if ``True``, check that the matrix + is an Hadamard matrix before returning OUTPUT: - If ``existence`` is true, returns a boolean representing whether the Hadamard matrix can - be constructed. Otherwise, returns the Hadamard matrix, or raises an error if it cannot be constructed. + If ``existence=True``, returns a boolean representing whether the Hadamard + matrix can be constructed. Otherwise, returns the Hadamard matrix, or raises + an error if it cannot be constructed. EXAMPLES:: @@ -1148,26 +1453,27 @@ def hadamard_matrix_spence_construction(n, existence=False, check=True): ... AssertionError """ - from sage.combinat.designs.difference_family import supplementary_difference_set + from sage.combinat.designs.difference_family import supplementary_difference_set_from_rel_diff_set - assert n%4 == 0 and n > 0 + assert n % 4 == 0 and n > 0 q = n//4 if existence: - return supplementary_difference_set(q, existence=True) + return supplementary_difference_set_from_rel_diff_set(q, existence=True) - if not supplementary_difference_set(q, existence=True): + if not supplementary_difference_set_from_rel_diff_set(q, existence=True): raise ValueError(f'The order {n} is not covered by Spence construction.') - S1, S2, S3, S4 = supplementary_difference_set(q, check=False) + G, [S1, S2, S3, S4] = supplementary_difference_set_from_rel_diff_set(q, check=False) - A1 = matrix.circulant([1 if j in S1 else -1 for j in range(q-1)]) - A2 = matrix.circulant([1 if j in S4 else -1 for j in range(q-1)]) - A3 = matrix.circulant([1 if j in S3 else -1 for j in range(q-1)]) - A4 = matrix.circulant([1 if j in S2 else -1 for j in range(q-1)]) + Glist = list(G) + A1 = matrix.circulant([1 if j in S1 else -1 for j in Glist]) + A2 = matrix.circulant([1 if j in S4 else -1 for j in Glist]) + A3 = matrix.circulant([1 if j in S3 else -1 for j in Glist]) + A4 = matrix.circulant([1 if j in S2 else -1 for j in Glist]) - P = matrix(ZZ, [[1 if (i + j)%(q-1) == 0 else 0 for i in range(1, q)] for j in range(1, q)]) + P = matrix(ZZ, [[1 if (i + j) % (q-1) == 0 else 0 for i in range(1, q)] for j in range(1, q)]) e = matrix([1]*(q-1)) m1 = matrix([-1]) @@ -1185,22 +1491,20 @@ def hadamard_matrix_spence_construction(n, existence=False, check=True): return H + def is_hadamard_matrix(M, normalized=False, skew=False, verbose=False): r""" - Test if `M` is a Hadamard matrix. + Test if ``M`` is a Hadamard matrix. INPUT: - ``M`` -- a matrix - - - ``normalized`` (boolean) -- whether to test if ``M`` is a normalized - Hadamard matrix, i.e. has its first row/column filled with +1. - - - ``skew`` (boolean) -- whether to test if ``M`` is a skew - Hadamard matrix, i.e. `M=S+I` for `-S=S^\top`, and `I` the identity matrix. - - - ``verbose`` (boolean) -- whether to be verbose when the matrix is not - Hadamard. + - ``normalized`` -- boolean (default: ``False``); whether to test if ``M`` + is a normalized Hadamard matrix, i.e. has its first row/column filled with +1 + - ``skew`` -- boolean (default: ``False``); whether to test if ``M`` is a skew + Hadamard matrix, i.e. `M=S+I` for `-S=S^\top`, and `I` the identity matrix + - ``verbose`` -- boolean (default: ``False``); whether to be verbose when + the matrix is not Hadamard EXAMPLES:: @@ -1243,6 +1547,14 @@ def is_hadamard_matrix(M, normalized=False, skew=False, verbose=False): False sage: is_hadamard_matrix(h, skew=False, verbose=True) True + sage: h = skew_hadamard_matrix(20, skew_normalize=False) + sage: is_hadamard_matrix(h, skew=True, normalized=True, verbose=True) + The matrix is not skew-normalized + False + sage: from sage.combinat.matrices.hadamard_matrix import normalise_hadamard + sage: h = normalise_hadamard(h, skew=True) + sage: is_hadamard_matrix(h, skew=True, normalized=True, verbose=True) + True """ n = M.ncols() if n != M.nrows(): @@ -1261,16 +1573,17 @@ def is_hadamard_matrix(M, normalized=False, skew=False, verbose=False): return False prod = (M*M.transpose()).dict() - if (len(prod) != n or - set(prod.values()) != {n} or - any((i, i) not in prod for i in range(n))): + if (len(prod) != n or set(prod.values()) != {n} or any((i, i) not in prod for i in range(n))): if verbose: print("The product M*M.transpose() is not equal to nI") return False if normalized: - if (set(M.row(0) ) != {1} or - set(M.column(0)) != {1}): + if skew and (set(M.row(0)) != {1}): + if verbose: + print("The matrix is not skew-normalized") + return False + elif not skew and (set(M.row(0)) != {1} or set(M.column(0)) != {1}): if verbose: print("The matrix is not normalized") return False @@ -1278,42 +1591,73 @@ def is_hadamard_matrix(M, normalized=False, skew=False, verbose=False): if skew: for i in range(n-1): for j in range(i+1, n): - if M[i,j] != -M[j,i]: + if M[i, j] != -M[j, i]: if verbose: print("The matrix is not skew") return False for i in range(n): - if M[i,i] != 1: + if M[i, i] != 1: if verbose: print("The matrix is not skew - diagonal entries must be all 1") return False return True -from sage.matrix.constructor import matrix_method + +def is_skew_hadamard_matrix(M, normalized=False, verbose=False): + r""" + Test if ``M`` is a skew Hadamard matrix. + + this is a wrapper around the function :func:`is_hadamard_matrix` + + INPUT: + + - ``M`` -- a matrix + - ``normalized`` -- boolean (default: ``False``); whether to test if ``M`` + is a skew-normalized Hadamard matrix, i.e. has its first row filled with +1 + - ``verbose`` -- boolean (default: ``False``); whether to be verbose when the + matrix is not skew Hadamard + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import is_skew_hadamard_matrix, skew_hadamard_matrix + sage: h = matrix.hadamard(12) + sage: is_skew_hadamard_matrix(h, verbose=True) + The matrix is not skew + False + sage: h = skew_hadamard_matrix(12) + sage: is_skew_hadamard_matrix(h) + True + sage: from sage.combinat.matrices.hadamard_matrix import normalise_hadamard + sage: h = normalise_hadamard(skew_hadamard_matrix(12), skew=True) + sage: is_skew_hadamard_matrix(h, verbose=True, normalized=True) + True + """ + return is_hadamard_matrix(M, skew=True, normalized=normalized, verbose=verbose) + + @matrix_method -def hadamard_matrix(n,existence=False, check=True): +def hadamard_matrix(n, existence=False, check=True): r""" Tries to construct a Hadamard matrix using the available methods. - INPUT: + Currently all orders `\le 1000` for which a construction is + known are implemented. For `n > 1000`, only some orders are available. - - ``n`` (integer) -- dimension of the matrix + INPUT: - - ``existence`` (boolean) -- whether to build the matrix or merely query if - a construction is available in Sage. When set to ``True``, the function - returns: + - ``n`` -- integer; dimension of the matrix + - ``existence`` -- boolean (default: ``False``); whether to build the matrix + or merely query if a construction is available in Sage. When set to ``True``, + the function returns: - ``True`` -- meaning that Sage knows how to build the matrix - - ``Unknown`` -- meaning that Sage does not know how to build the matrix, although the matrix may exist (see :mod:`sage.misc.unknown`). - - ``False`` -- meaning that the matrix does not exist. - - ``check`` (boolean) -- whether to check that output is correct before + - ``check`` -- boolean (default: ``True``); whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious - guys), you may want to disable it whenever you want speed. Set to ``True`` - by default. + guys), you may want to disable it whenever you want speed. EXAMPLES:: @@ -1379,7 +1723,7 @@ def hadamard_matrix(n,existence=False, check=True): sage: matrix.hadamard(324, existence=True) True """ - if not(n % 4 == 0) and (n > 2): + if not (n % 4 == 0) and (n > 2): if existence: return False raise ValueError("The Hadamard matrix of order %s does not exist" % n) @@ -1395,10 +1739,10 @@ def hadamard_matrix(n,existence=False, check=True): if existence: return True M = hadamard_matrix_paleyII(n) - elif n == 4 or n % 8 == 0 and hadamard_matrix(n//2,existence=True) is True: + elif n == 4 or n % 8 == 0 and hadamard_matrix(n//2, existence=True) is True: if existence: return True - had = hadamard_matrix(n//2,check=False) + had = hadamard_matrix(n//2, check=False) chad1 = matrix([list(r) + list(r) for r in had.rows()]) mhad = (-1) * had R = len(had.rows()) @@ -1425,7 +1769,15 @@ def hadamard_matrix(n,existence=False, check=True): if existence: return True M = turyn_type_hadamard_matrix_smallcases(n, check=False) - elif hadamard_matrix_spence_construction(n ,existence=True): + elif hadamard_matrix_miyamoto_construction(n, existence=True): + if existence: + return True + M = hadamard_matrix_miyamoto_construction(n, check=False) + elif hadamard_matrix_from_sds(n, existence=True): + if existence: + return True + M = hadamard_matrix_from_sds(n, check=False) + elif hadamard_matrix_spence_construction(n, existence=True): if existence: return True M = hadamard_matrix_spence_construction(n, check=False) @@ -1504,7 +1856,7 @@ def hadamard_matrix_www(url_file, comments=False): _rshcd_cache = {} -def regular_symmetric_hadamard_matrix_with_constant_diagonal(n,e,existence=False): +def regular_symmetric_hadamard_matrix_with_constant_diagonal(n, e, existence=False): r""" Return a Regular Symmetric Hadamard Matrix with Constant Diagonal. @@ -1519,9 +1871,8 @@ def regular_symmetric_hadamard_matrix_with_constant_diagonal(n,e,existence=False INPUT: - - ``n`` (integer) -- side of the matrix - - - ``e`` -- one of `-1` or `+1`, equal to the value of `\epsilon` + - ``n`` -- integer; side of the matrix + - ``e`` -- `-1` or `+1`; the value of `\epsilon` EXAMPLES:: @@ -1573,13 +1924,13 @@ def regular_symmetric_hadamard_matrix_with_constant_diagonal(n,e,existence=False - [HX2010]_ """ - if existence and (n,e) in _rshcd_cache: - return _rshcd_cache[n,e] + if existence and (n, e) in _rshcd_cache: + return _rshcd_cache[n, e] from sage.graphs.strongly_regular_db import strongly_regular_graph def true(): - _rshcd_cache[n,e] = True + _rshcd_cache[n, e] = True return True M = None @@ -1588,7 +1939,7 @@ def true(): sqn = None if is_square(n): sqn = int(sqrt(n)) - if n<0: + if n < 0: if existence: return False raise ValueError @@ -1596,31 +1947,31 @@ def true(): if existence: return true() if e == 1: - M = J(4)-2*matrix(4,[[int(i+j == 3) for i in range(4)] for j in range(4)]) + M = J(4)-2*matrix(4, [[int(i+j == 3) for i in range(4)] for j in range(4)]) else: M = -J(4)+2*I(4) - elif n == 36: + elif n == 36: if existence: return true() if e == 1: M = strongly_regular_graph(36, 15, 6, 6).adjacency_matrix() M = J(36) - 2*M else: - M = strongly_regular_graph(36,14,4,6).adjacency_matrix() - M = -J(36) + 2*M + 2*I(36) + M = strongly_regular_graph(36, 14, 4, 6).adjacency_matrix() + M = -J(36) + 2*M + 2*I(36) elif n == 100: if existence: return true() if e == -1: - M = strongly_regular_graph(100,44,18,20).adjacency_matrix() + M = strongly_regular_graph(100, 44, 18, 20).adjacency_matrix() M = 2*M - J(100) + 2*I(100) else: - M = strongly_regular_graph(100,45,20,20).adjacency_matrix() + M = strongly_regular_graph(100, 45, 20, 20).adjacency_matrix() M = J(100) - 2*M elif n == 196 and e == 1: if existence: return true() - M = strongly_regular_graph(196,91,42,42).adjacency_matrix() + M = strongly_regular_graph(196, 91, 42, 42).adjacency_matrix() M = J(196) - 2*M elif n == 324: if existence: @@ -1638,7 +1989,7 @@ def true(): elif (e == 1 and sqn is not None and sqn % 4 == 2 and - strongly_regular_graph(sqn-1,(sqn-2)//2,(sqn-6)//4, + strongly_regular_graph(sqn-1, (sqn-2)//2, (sqn-6)//4, existence=True) is True and is_prime_power(ZZ(sqn + 1))): if existence: @@ -1648,30 +1999,31 @@ def true(): # Recursive construction: the Kronecker product of two RSHCD is a RSHCD else: from itertools import product - for n1,e1 in product(divisors(n)[1:-1],[-1,1]): + for n1, e1 in product(divisors(n)[1:-1], [-1, 1]): e2 = e1*e n2 = n//n1 - if (regular_symmetric_hadamard_matrix_with_constant_diagonal(n1,e1,existence=True) is True and - regular_symmetric_hadamard_matrix_with_constant_diagonal(n2,e2,existence=True)) is True: + if (regular_symmetric_hadamard_matrix_with_constant_diagonal(n1, e1, existence=True) is True and + regular_symmetric_hadamard_matrix_with_constant_diagonal(n2, e2, existence=True)) is True: if existence: return true() - M1 = regular_symmetric_hadamard_matrix_with_constant_diagonal(n1,e1) - M2 = regular_symmetric_hadamard_matrix_with_constant_diagonal(n2,e2) - M = M1.tensor_product(M2) + M1 = regular_symmetric_hadamard_matrix_with_constant_diagonal(n1, e1) + M2 = regular_symmetric_hadamard_matrix_with_constant_diagonal(n2, e2) + M = M1.tensor_product(M2) break if M is None: from sage.misc.unknown import Unknown - _rshcd_cache[n,e] = Unknown + _rshcd_cache[n, e] = Unknown if existence: return Unknown - raise ValueError("I do not know how to build a {}-RSHCD".format((n,e))) + raise ValueError("I do not know how to build a {}-RSHCD".format((n, e))) assert M*M.transpose() == n*I(n) - assert set(map(sum,M)) == {ZZ(e*sqn)} + assert set(map(sum, M)) == {ZZ(e*sqn)} return M + def RSHCD_324(e): r""" Return a size 324x324 Regular Symmetric Hadamard Matrix with Constant Diagonal. @@ -1696,7 +2048,7 @@ def RSHCD_324(e): INPUT: - - ``e`` -- one of `-1` or `+1`, equal to the value of `\epsilon` + - ``e`` -- `-1` or `+1`; the value of `\epsilon` TESTS:: @@ -1717,15 +2069,16 @@ def RSHCD_324(e): from sage.graphs.generators.smallgraphs import JankoKharaghaniTonchevGraph as JKTG M = JKTG().adjacency_matrix() M = J(324) - 2*M - if e==-1: - M1=M[:162].T - M2=M[162:].T - M11=M1[:162] - M12=M1[162:].T - M21=M2[:162].T - M=block_matrix([[M12,-M11],[-M11.T,M21]]) + if e == -1: + M1 = M[:162].T + M2 = M[162:].T + M11 = M1[:162] + M12 = M1[162:].T + M21 = M2[:162].T + M = block_matrix([[M12, -M11], [-M11.T, M21]]) return M + def _helper_payley_matrix(n, zero_position=True): r""" Return the matrix constructed in Lemma 1.19 page 291 of [SWW1972]_. @@ -1741,10 +2094,9 @@ def _helper_payley_matrix(n, zero_position=True): INPUT: - - ``n`` -- an odd prime power. - - - ``zero_position`` -- if it is true (default), place 0 of ``F_n`` in the middle, - otherwise place it first. + - ``n`` -- an odd prime power + - ``zero_position`` -- boolean (default: ``True``); if it is true, place 0 + of ``F_n`` in the middle, otherwise place it first .. SEEALSO:: @@ -1852,23 +2204,23 @@ def rshcd_from_close_prime_powers(n): - [SWW1972]_ """ - if n%4: + if n % 4: raise ValueError("n(={}) must be congruent to 0 mod 4") - a,b = sorted([n-1,n+1],key=lambda x:-x%4) - Sa = _helper_payley_matrix(a) - Sb = _helper_payley_matrix(b) - U = matrix(a,[[int(i+j == a-1) for i in range(a)] for j in range(a)]) + a, b = sorted([n-1, n+1], key=lambda x: -x % 4) + Sa = _helper_payley_matrix(a) + Sb = _helper_payley_matrix(b) + U = matrix(a, [[int(i+j == a-1) for i in range(a)] for j in range(a)]) K = (U*Sa).tensor_product(Sb) + U.tensor_product(J(b)-I(b)) - J(a).tensor_product(I(b)) - F = lambda x:diagonal_matrix([-(-1)**i for i in range(x)]) - G = block_diagonal_matrix([J(1),I(a).tensor_product(F(b))]) - e = matrix(a*b,[1]*(a*b)) - H = block_matrix(2,[-J(1),e.transpose(),e,K]) + F = lambda x: diagonal_matrix([-(-1)**i for i in range(x)]) + G = block_diagonal_matrix([J(1), I(a).tensor_product(F(b))]) + e = matrix(a*b, [1]*(a*b)) + H = block_matrix(2, [-J(1), e.transpose(), e, K]) HH = G*H*G - assert len(set(map(sum,HH))) == 1 + assert len(set(map(sum, HH))) == 1 assert HH**2 == n**2*I(n**2) return HH @@ -1883,13 +2235,12 @@ def williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=True): INPUT: - - ``a`` -- 1,-1 list specifying the 1st row of `A` - - - ``b`` -- 1,-1 list specifying the 1st row of `B` - - - ``d`` -- 1,-1 list specifying the 1st row of `C` - - - ``c`` -- 1,-1 list specifying the 1st row of `D` + - ``a`` -- 1,-1 list; the 1st row of `A` + - ``b`` -- 1,-1 list; the 1st row of `B` + - ``d`` -- 1,-1 list; the 1st row of `C` + - ``c`` -- 1,-1 list; the 1st row of `D` + - ``check`` -- boolean (default: ``True``); if ``True``, check that the + resulting matrix is skew Hadamard before returning it EXAMPLES:: @@ -1909,120 +2260,820 @@ def williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=True): - [KoSt08]_ """ n = len(a) - A,B,C,D=map(matrix.circulant, [a,b,c,d]) + A, B, C, D = map(matrix.circulant, [a, b, c, d]) if check: - assert A*A.T+B*B.T+C*C.T+D*D.T==4*n*I(n) - assert A+A.T==2*I(n) + assert A*A.T+B*B.T+C*C.T+D*D.T == 4*n*I(n) + assert A+A.T == 2*I(n) M = _construction_goethals_seidel_matrix(A, B, C, D) if check: assert is_hadamard_matrix(M, normalized=False, skew=True) return M -def GS_skew_hadamard_smallcases(n, existence=False, check=True): - r""" - Data for Williamson-Goethals-Seidel construction of skew Hadamard matrices - Here we keep the data for this construction. - Namely, it needs 4 circulant matrices with extra properties, as described in - :func:`sage.combinat.matrices.hadamard_matrix.williamson_goethals_seidel_skew_hadamard_matrix` - Matrices for `n=36` and `52` are given in [GS70s]_. Matrices for `n=92` are given - in [Wall71]_. +def skew_hadamard_matrix_spence_construction(n, check=True): + r""" + Construct skew Hadamard matrix of order `n` using Spence constrution. - Additional data is obtained from skew supplementary difference sets contained in - :func:`sage.combinat.designs.difference_family.skew_supplementary_difference_set`, using the - construction described in [Djo1992]_. + This function will construct skew Hadamard matrix of order `n=2(q+1)` where `q` is + a prime power with `q = 5` (mod 8). The construction is taken from [Spe1977]_, and the + relative difference sets are constructed using :func:`sage.combinat.designs.difference_family.relative_difference_set_from_homomorphism`. INPUT: - - ``n`` -- the order of the matrix + - ``n`` -- positive integer + - ``check`` -- boolean (default: ``True``); if ``True``, check that the + resulting matrix is Hadamard before returning it + + OUTPUT: + + If ``n`` satisfies the requirements described above, the function returns a + `n\times n` Hadamard matrix. Otherwise, an exception is raised. - - ``existence`` -- if true (default), only check that we can do the construction + EXAMPLES:: - - ``check`` -- if true (default), check the result. + sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix_spence_construction + sage: skew_hadamard_matrix_spence_construction(28) + 28 x 28 dense matrix over Integer Ring... TESTS:: - sage: from sage.combinat.matrices.hadamard_matrix import GS_skew_hadamard_smallcases - sage: GS_skew_hadamard_smallcases(36) + sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix + sage: is_hadamard_matrix(skew_hadamard_matrix_spence_construction(12, check=False), skew=True) + True + sage: is_hadamard_matrix(skew_hadamard_matrix_spence_construction(60, check=False), skew=True) + True + sage: skew_hadamard_matrix_spence_construction(31) + Traceback (most recent call last): + ... + ValueError: The order 31 is not covered by the Spence construction. + sage: skew_hadamard_matrix_spence_construction(16) + Traceback (most recent call last): + ... + ValueError: The order 16 is not covered by the Spence construction. + """ + q = n//2 - 1 + m = (q+1)//2 + if n % 4 != 0 or not is_prime_power(q) or q % 8 != 5: + raise ValueError(f'The order {n} is not covered by the Spence construction.') + + G, D = relative_difference_set_from_homomorphism(q, 2, (q-1)//4, check=False, return_group=True) + D_fixed = get_fixed_relative_difference_set(G, D) + D_union = D_fixed + [q+1+el for el in D_fixed] + D_union = list(set([el % (4*(q+1)) for el in D_union])) + + def find_a(i): + for a in range(8): + if (a*(q+1)//2+i) % 8 == 0: + return a + + ai = [find_a(0), find_a(1), find_a(2), find_a(3)] + P = PolynomialRing(ZZ, 'x') + + Tm = 0 + for i in range(m): + Tm += P.monomial(i) + + Ds = [[] for i in range(4)] + + for el in D_union: + i = el % 8 + if i > 3: + continue + Ds[i].append(((el + ai[i] * m) // 8) % m) + + psis = [0 for i in range(4)] + for i in range(4): + for el in Ds[i]: + psis[i] += P.monomial(el) + + diffs = [(2*psis[i] - Tm).mod(P.monomial(m)-1) for i in range(4)] + a = [-el for el in diffs[1].coefficients()] + b = diffs[0].coefficients() + c = diffs[2].coefficients() + d = diffs[3].coefficients() + + return williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=check) + + +def skew_hadamard_matrix_spence_1975(n, existence=False, check=True): + r""" + Construct a skew Hadamard matrix of order `n = 4(1 + q + q^2)` using the + Spence construction. + + If `n = 4(1 + q + q^2)` where `q` is a prime power such that either + `1 + q + q^2` is a prime congruent to `3, 5, 7 \mod 8` or `3 + 2q + 2q^2` is + a prime power, then a skew Hadamard matrix of order `n` can be constructed using + the Goethals Seidel array. The four matrices `A, B, C, D` plugged into the + GS-array are created using complementary difference sets of order `1 + q + q^2` + (which exist if `q` satisfies the conditions above), and a cyclic planar + difference set with parameters `(1 + q^2 + q^4, 1 + q^2, 1)`. + These are constructed by the functions :func:`sage.combinat.designs.difference_family.complementary_difference_sets` + and :func:`sage.combinat.designs.difference_family.difference_family`. + + For more details, see [Spe1975b]_. + + INPUT: + + - ``n`` -- positive integer; the order of the matrix to be constructed + - ``existence`` -- boolean (default: ``False``); if ``True``, only return + whether the Hadamard matrix can be constructed + - ``check`` -- boolean (default: ``True``); check that the result + is a skew Hadamard matrix before returning it + + OUTPUT: + + If ``existence=False``, returns the skew Hadamard matrix of order `n`. It + raises an error if `n` does not satisfy the required conditions. + If ``existence=True``, returns a boolean representing whether the matrix + can be constructed or not. + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix_spence_1975 + sage: skew_hadamard_matrix_spence_1975(52) + 52 x 52 dense matrix over Integer Ring... + + If ``existence`` is True, the function returns a boolean:: + + sage: skew_hadamard_matrix_spence_1975(52, existence=True) + True + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import is_skew_hadamard_matrix + sage: is_skew_hadamard_matrix(skew_hadamard_matrix_spence_1975(52, check=False)) + True + sage: skew_hadamard_matrix_spence_1975(100, existence=True) + False + sage: skew_hadamard_matrix_spence_1975(31) + Traceback (most recent call last): + ... + ValueError: n is not in the form 4*(1+q+q^2) + sage: skew_hadamard_matrix_spence_1975(16) + Traceback (most recent call last): + ... + ValueError: n is not in the form 4*(1+q+q^2) + sage: skew_hadamard_matrix_spence_1975(292) + Traceback (most recent call last): + ... + ValueError: q=8 is not a valid parameter for this construction + """ + from sage.combinat.designs.difference_family import is_fixed_relative_difference_set, difference_family, complementary_difference_sets + + q = None + m = n // 4 + for i in range(m): + if 1 + i + i**2 == m and is_prime_power(i): + q = i + break + + if n % 4 != 0 or q is None: + if existence: + return False + raise ValueError('n is not in the form 4*(1+q+q^2)') + + is_valid = (is_prime(m) and m % 8 in [3, 5, 7]) or is_prime_power(3 + 2*q + 2*q**2) + if existence: + return is_valid + + if not is_valid: + raise ValueError(f'q={q} is not a valid parameter for this construction') + + G, sets = difference_family(1 + q**2 + q**4, 1 + q**2, 1) + + def get_fixed_set(s, G, q): + for el in G: + fixed_set = [el + x for x in s] + if is_fixed_relative_difference_set(fixed_set, q): + return fixed_set + assert False + + D = get_fixed_set(sets[0], G, q) + + D1 = [d for d in D if d % (1 - q + q**2) == 0] + Dnot = [el for el in D if el not in D1] + D2 = [] + + indices = set() + for i in range(len(Dnot)): + if i in indices: + continue + indices.add(i) + for j in range(i+1, len(Dnot)): + if j not in indices and Dnot[i] % m == Dnot[j] % m: + indices.add(j) + D2.append(Dnot[i]) + + D2 = [d % m for d in D2] + D1 = [d % m for d in D1] + + G2, U, V = complementary_difference_sets(m, check=False) + G2list = list(G2) + p = [-1 if j in U else 1 for j in G2list] + q = [-1 if j in V else 1 for j in G2list] + r = [1 if j % m in D1 or j % m in D2 else -1 for j in range(m)] + s = [1 if j % m in D2 else -1 for j in range(m)] + + return williamson_goethals_seidel_skew_hadamard_matrix(p, q, r, s, check=check) + + +def GS_skew_hadamard_smallcases(n, existence=False, check=True): + r""" + Data for Williamson-Goethals-Seidel construction of skew Hadamard matrices + + Here we keep the data for this construction. + Namely, it needs 4 circulant matrices with extra properties, as described in + :func:`sage.combinat.matrices.hadamard_matrix.williamson_goethals_seidel_skew_hadamard_matrix` + Matrices are taken from: + + * `n=36, 52`: [GS70s]_ + * `n=92`: [Wall71]_ + * `n=188`: [Djo2008a]_ + * `n=236`: [FKS2004]_ + * `n=276`: [Djo2023a]_ + + Additional data is obtained from skew supplementary difference sets contained in + :func:`sage.combinat.designs.difference_family.skew_supplementary_difference_set`, using the + construction described in [Djo1992a]_. + + INPUT: + + - ``n`` -- integer; the order of the matrix + - ``existence`` -- boolean (default: ``True``); if ``True``, only check that + we can do the construction + - ``check`` -- boolean (default: ``False``): if ``True``, check the result + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import GS_skew_hadamard_smallcases, is_skew_hadamard_matrix + sage: GS_skew_hadamard_smallcases(36) 36 x 36 dense matrix over Integer Ring... sage: GS_skew_hadamard_smallcases(52) 52 x 52 dense matrix over Integer Ring... sage: GS_skew_hadamard_smallcases(92) 92 x 92 dense matrix over Integer Ring... sage: GS_skew_hadamard_smallcases(100) + sage: is_skew_hadamard_matrix(GS_skew_hadamard_smallcases(324, check=False)) + True + sage: is_skew_hadamard_matrix(GS_skew_hadamard_smallcases(156, check=False)) + True """ WGS = williamson_goethals_seidel_skew_hadamard_matrix def pmtoZ(s): return [1 if x == '+' else -1 for x in s] - if existence: - return n in [36, 52, 92] or skew_supplementary_difference_set(n//4, existence=True) + db = { + 36: ['+++-+-+--', '+-++--++-', '--++++++-', '+++-++-++'], + 52: ['++++-++--+---', '-+-++----++-+', '--+-+++++-+++', '--+-+++++-+++'], + 92: ['+-------++-+-+--+++++++', '++--+--++++--++++--+--+', '++---+-+-+-++-+-+-+---+', '+----+--+--++--+--+----'], + 188: ['+----+----++-+-+---++-++--+--+++-+-+--++++-++++', + '++--+---+------++------++-+-++--+-+-+----+---++', + '+-+-++---++-+---+++---++-++-++-++-+++++-+-+----', + '+++-++-+-+---+-+++++--+-----++---+--+++++--++-+'], + 236: ['+-+---+-+-++-++---+----++-----+++++--++++-+++--+--+-+-+++-+', + '+-+---+-+-++-++---+----++-----+++++--++++-+++--+--+-+-+++-+', + '+++-++----+++-+-+++--+--++------+---+-----+--+-+--+---+----', + '++++++--+++--+---++-+-+-+---+-+----++++-++-+--++-+--+------'], + 276: ['+--+++--+-+++--+---++-+++++-+++-++-+--+---+-----+--+++-++---+-++---++', + '+-++--+-+----++-+---++++-+---+-++++++++-+---+-++++---+-++----+-+--++-', + '--+--+-++---+--++--+-+-+++-+--++---++++-+-+-+--+-++-+++++++--+--+++++', + '-+---+++-----++---+++-+++--+++++--+---+-+-++++-++++-++-++-+-+++++++++'] + } - if n == 36: - a = [ 1, 1, 1, -1, 1, -1, 1, -1, -1] - b = [ 1, -1, 1, 1, -1, -1, 1, 1, -1] - c = [-1, -1]+[1]*6+[-1] - d = [ 1, 1, 1, -1, 1, 1, -1, 1, 1] - return WGS(a, b, c, d, check=check) + if existence: + return n in db or skew_supplementary_difference_set(n//4, existence=True) - if n == 52: - a = pmtoZ('++++-++--+---') - b = pmtoZ('-+-++----++-+') - c = pmtoZ('--+-+++++-+++') - return WGS(a, b, c, c, check=check) - - if n == 92: - a = [1,-1,-1,-1,-1,-1,-1,-1, 1, 1,-1, 1,-1, 1,-1,-1, 1, 1, 1, 1, 1, 1, 1] - b = [1, 1,-1,-1, 1,-1,-1, 1, 1, 1, 1,-1,-1, 1, 1, 1, 1,-1,-1, 1,-1,-1, 1] - c = [1, 1,-1,-1,-1, 1,-1, 1,-1, 1,-1, 1, 1,-1, 1,-1, 1,-1, 1,-1,-1,-1, 1] - d = [1,-1,-1,-1,-1, 1,-1,-1, 1,-1,-1, 1, 1,-1,-1, 1,-1,-1, 1,-1,-1,-1,-1] + if n in db: + a, b, c, d = map(pmtoZ, db[n]) return WGS(a, b, c, d, check=check) if skew_supplementary_difference_set(n//4, existence=True): t = n//4 - S1, S2, S3, S4 = skew_supplementary_difference_set(t, check=False) - a = [-1 if i in S1 else 1 for i in range(t)] - b = [-1 if i in S2 else 1 for i in range(t)] - c = [-1 if i in S3 else 1 for i in range(t)] - d = [-1 if i in S4 else 1 for i in range(t)] - return WGS(a, b, c, d, check=check) + + G, [S1, S2, S3, S4] = skew_supplementary_difference_set(t, check=False, return_group=True) + Glist = list(G) + + A = matrix([[-1 if y-x in S1 else +1 for y in Glist] for x in Glist]) + B = matrix([[-1 if y-x in S2 else +1 for y in Glist] for x in Glist]) + C = matrix([[-1 if y-x in S3 else +1 for y in Glist] for x in Glist]) + D = matrix([[-1 if y-x in S4 else +1 for y in Glist] for x in Glist]) + + H = _construction_goethals_seidel_matrix(A, B, C, D) + if check: + assert is_skew_hadamard_matrix(H) + return H return None -_skew_had_cache={} -def skew_hadamard_matrix(n,existence=False, skew_normalize=True, check=True): +def skew_hadamard_matrix_from_orthogonal_design(n, existence=False, check=True): r""" - Tries to construct a skew Hadamard matrix + Construct skew Hadamard matrices of order `mn(n - 1)` if suitable orthogonal designs exist. - A Hadamard matrix `H` is called skew if `H=S-I`, for `I` the identity matrix - and `-S=S^\top`. Currently constructions from Section 14.1 of [Ha83]_ and few - more exotic ones are implemented. + In [Seb1978]_ is proved that if amicable Hadamard matrices of order `n` and an orthogonal + design of type `(1, m, mn - m - 1)` in order `mn` exist, then a skew Hadamard matrix + of order `mn(n - 1)` can be constructed. The paper uses amicable orthogonal designs + instead of amicable Hadamard matrices, but the two are equivalent (see [Seb2017]_). + + Amicable Hadamard matrices are constructed using :func:`amicable_hadamard_matrices`, + and the orthogonal designs are constructed using the Goethals-Seidel array, + with data taken from [Seb2017]_. INPUT: - - ``n`` (integer) -- dimension of the matrix + - ``n`` -- positive integer; the order of the matrix to be constructed + - ``existence`` -- boolean (default: ``False``); if ``True``, only return + whether the skew Hadamard matrix can be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the result + is a skew Hadamard matrix before returning it - - ``existence`` (boolean) -- whether to build the matrix or merely query if - a construction is available in Sage. When set to ``True``, the function - returns: + OUTPUT: - - ``True`` -- meaning that Sage knows how to build the matrix + If ``existence=False``, returns the skew Hadamard matrix of order `n`. It + raises an error if a construction for order `n` is not yet implemented, or if + `n` does not satisfy the constraint. + If ``existence=True``, returns a boolean representing whether the matrix + can be constructed or not. + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix_from_orthogonal_design + sage: skew_hadamard_matrix_from_orthogonal_design(756) + 756 x 756 dense matrix over Integer Ring... + + If ``existence`` is True, the function returns a boolean:: + + sage: skew_hadamard_matrix_from_orthogonal_design(200, existence=True) + False + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import is_skew_hadamard_matrix + sage: is_skew_hadamard_matrix(skew_hadamard_matrix_from_orthogonal_design(756, check=False)) + True + sage: skew_hadamard_matrix_from_orthogonal_design(31) + Traceback (most recent call last): + ... + ValueError: n must be a multiple of 4 + sage: skew_hadamard_matrix_from_orthogonal_design(16) + Traceback (most recent call last): + ... + NotImplementedError: orthogonal designs for matrix of order 16 not yet implemented + """ + # We use value i to represent entries where variable x_i should be, and -i for -x_i + orthogonal_designs = { + (1, 1, 26): [[1, 3, 3, -3, 3, -3, -3], [2, 3, 3, -3, 3, -3, -3], + [3, 3, 3, -3, 3, 3, 3], [3, 3, -3, -3, -3, 3, -3]] + } + + if n % 4 != 0: + raise ValueError('n must be a multiple of 4') + + m1, m2 = None, None + for d in divisors(n)[1:-1]: + if (n//d) % (d-1) != 0: + continue + d1 = n // (d*(d - 1)) + if (1, d1, d1*d - d1 - 1) in orthogonal_designs and amicable_hadamard_matrices(d, existence=True): + m1 = d1 + m2 = d + + if m2 is None or m1 is None: + if existence: + return False + raise NotImplementedError(f'orthogonal designs for matrix of order {n} not yet implemented') + + if existence: + return True + + M, N = amicable_hadamard_matrices(m2, check=False) + M = normalise_hadamard(M, skew=True) + N = normalise_hadamard(N) + + P = M[1:, 1:] - I(m2 - 1) + D = N[1:, 1:] + + A1, A2, A3, A4 = map(matrix.circulant, orthogonal_designs[(1, m1, m1*m2 - m1 - 1)]) + OD = _construction_goethals_seidel_matrix(A1, A2, A3, A4) + + blocks = {1: P, -1: -P, 2: J(m2 - 1), -2: -J(m2 - 1), 3: D, -3: -D} + H = block_matrix([[blocks[el] for el in row] for row in OD]) + I(n) + + if check: + assert is_skew_hadamard_matrix(H) + + return H + + +def skew_hadamard_matrix_from_complementary_difference_sets(n, existence=False, check=True): + r""" + Construct a skew Hadamard matrix of order `n=4(m+1)` from complementary difference sets. + + If `A, B` are complementary difference sets over a group of order `2m+1`, then + they can be used to construct a skew Hadamard matrix, as described in [BS1969]_. + + The complementary difference sets are constructed using the function + :func:`sage.combinat.designs.difference_family.complementary_difference_sets`. + + INPUT: + + - ``n`` -- positive integer; the order of the matrix to be constructed + - ``existence`` -- boolean (default: ``False``); if ``True``, only return + whether the skew Hadamard matrix can be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the + result is a skew Hadamard matrix before returning it + + OUTPUT: + + If ``existence=False``, returns the skew Hadamard matrix of order `n`. It + raises an error if `n` does not satisfy the required conditions. + If ``existence=True``, returns a boolean representing whether the matrix + can be constructed or not. + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix_from_complementary_difference_sets + sage: skew_hadamard_matrix_from_complementary_difference_sets(20) + 20 x 20 dense matrix over Integer Ring... + sage: skew_hadamard_matrix_from_complementary_difference_sets(52, existence=True) + True + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import is_skew_hadamard_matrix + sage: is_skew_hadamard_matrix(skew_hadamard_matrix_from_complementary_difference_sets(24, check=False)) + True + sage: is_skew_hadamard_matrix(skew_hadamard_matrix_from_complementary_difference_sets(12, check=False)) + True + sage: skew_hadamard_matrix_from_complementary_difference_sets(31) + Traceback (most recent call last): + ... + ValueError: n must be 1, 2 or a multiple of four. + sage: skew_hadamard_matrix_from_complementary_difference_sets(100) + Traceback (most recent call last): + ... + NotImplementedError: hadamard matrix of order 100 from complementary difference sets is not implemented yet + sage: skew_hadamard_matrix_from_complementary_difference_sets(100, existence=True) + False + """ + + if n <= 0 or (n > 2 and n % 4 != 0): + raise ValueError('n must be 1, 2 or a multiple of four.') + + m = n//4 - 1 + + if existence: + return complementary_difference_sets(2*m+1, existence=True) + + if not complementary_difference_sets(2*m+1, existence=True): + raise NotImplementedError(f'hadamard matrix of order {n} from complementary difference sets is not implemented yet') + + G, A, B = complementary_difference_sets(2*m+1, check=False) + + m = n//4 - 1 + Glist = list(G) + + S = [[0 for i in range(n)] for j in range(n)] + for i in range(2*m + 1): + for j in range(2*m + 1): + S[2*m + 1 + i][2*m + 1 + j] = -1 if Glist[j] - Glist[i] in A else 1 + S[i][j] = -S[2*m + 1 + i][2*m + 1 + j] + S[2*m + 1 + j][i] = -1 if Glist[j] - Glist[i] in B else 1 + S[i][2*m + 1 + j] = -S[2*m + 1 + j][i] + S[4*m + 2][i] = -1 + S[4*m + 2][2*m + 1 + i] = 1 + S[i][4*m + 2] = 1 + S[i + 2*m + 1][4*m + 2] = -1 + for i in range(4*m + 3): + S[4*m + 3][i] = 1 + S[i][4*m + 3] = -1 + for i in range(4*m + 4): + S[i][i] = 1 + + H = matrix(S) + + if check: + assert is_hadamard_matrix(H, skew=True) + return H + + +def skew_hadamard_matrix_whiteman_construction(n, existence=False, check=True): + r""" + Construct a skew Hadamard matrix of order `n=2(q+1)` where `q=p^t` is a prime power with `p \cong 5 \mod 8` and `t \cong 2 \mod 4`. + + Assuming `n` satisfies the conditions above, it is possible to construct two supplementary difference sets + `A, B` (see [Whi1971]_), and these can be used to construct a skew Hadamard matrix, as described in [BS1969]_. + + INPUT: + + - ``n`` -- positive integer; the order of the matrix to be constructed + - ``existence`` -- boolean (default: ``False``); If ``True``, only return + whether the Hadamard matrix can be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the result + is a skew Hadamard matrix before returning it + + OUTPUT: + + If ``existence=False``, returns the skew Hadamard matrix of order `n`. It + raises an error if `n` does not satisfy the required conditions. + If ``existence=True``, returns a boolean representing whether the matrix can + be constructed or not. + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix_whiteman_construction + sage: skew_hadamard_matrix_whiteman_construction(52) + 52 x 52 dense matrix over Integer Ring... + sage: skew_hadamard_matrix_whiteman_construction(52, existence=True) + True + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix + sage: is_hadamard_matrix(skew_hadamard_matrix_whiteman_construction(52, check=False), skew=True) + True + sage: is_hadamard_matrix(skew_hadamard_matrix_whiteman_construction(340, check=False), skew=True) + True + sage: skew_hadamard_matrix_whiteman_construction(31) + Traceback (most recent call last): + ... + ValueError: The order 31 is not covered by the Whiteman construction. + sage: skew_hadamard_matrix_whiteman_construction(100) + Traceback (most recent call last): + ... + ValueError: The order 100 is not covered by the Whiteman construction. + sage: skew_hadamard_matrix_whiteman_construction(100, existence=True) + False + + .. NOTE:: + + A more general version of this construction is :func:`skew_hadamard_matrix_from_complementary_difference_sets`. + """ + + q = n // 2 - 1 + p, t = is_prime_power(q, get_data=True) + + is_order_valid = n % 4 == 0 and t > 0 and p % 8 == 5 and t % 4 == 2 + if existence: + return is_order_valid + + if not is_order_valid: + raise ValueError(f'The order {n} is not covered by the Whiteman construction.') + + from sage.rings.finite_rings.finite_field_constructor import GF + G = GF(q) + f = (q-1) // 8 + Cs = {i: [G.gen()**(8*s+i) for s in range(f)] for i in [0, 1, 2, 3, 6, 7]} + A = Cs[0] + Cs[1] + Cs[2] + Cs[3] + B = Cs[0] + Cs[1] + Cs[6] + Cs[7] + + m = n//4 - 1 + Glist = list(G) + + S = [[0 for i in range(n)] for j in range(n)] + for i in range(2*m + 1): + for j in range(2*m + 1): + S[2*m + 1 + i][2*m + 1 + j] = -1 if Glist[j] - Glist[i] in A else 1 + S[i][j] = -S[2*m + 1 + i][2*m + 1 + j] + S[2*m + 1 + j][i] = -1 if Glist[j] - Glist[i] in B else 1 + S[i][2*m + 1 + j] = -S[2*m + 1 + j][i] + S[4*m + 2][i] = -1 + S[4*m + 2][2*m + 1 + i] = 1 + S[i][4*m + 2] = 1 + S[i + 2*m + 1][4*m + 2] = -1 + for i in range(4*m + 3): + S[4*m + 3][i] = 1 + S[i][4*m + 3] = -1 + for i in range(4*m + 4): + S[i][i] = 1 + + H = matrix(S) + + if check: + assert is_hadamard_matrix(H, skew=True) + return H + + +def skew_hadamard_matrix_from_good_matrices(a, b, c, d, check=True): + r""" + Construct skew Hadamard matrix from good matrices. + + Given good matrices `A`, `B`, `C`, `D` (`A` circulant, `B, C, D` back-circulant) they can be used to construct + a skew Hadamard matrix using the following block matrix (as described in [Sze1988]_): + + .. MATH:: + + \left(\begin{array}{rrrr} + A & B & C & D \\ + -B & A & D & -C \\ + -C & -D & A & B \\ + -D & C & -B & A + \end{array}\right) + + INPUT: + + - ``a`` -- (1,-1) list; the 1st row of `A` + - ``b`` -- (1,-1) list; the 1st row of `B` + - ``d`` -- (1,-1) list; the 1st row of `C` + - ``c`` -- (1,-1) list; the 1st row of `D` + - ``check`` -- boolean (default: ``True``); if ``True``, check that the matrix + is a skew Hadamard matrix before returning it + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix_from_good_matrices + sage: a, b, c, d = ([1, 1, 1, -1, -1], [1, -1, 1, 1, -1], [1, -1, -1, -1, -1], [1, -1, -1, -1, -1]) + sage: skew_hadamard_matrix_from_good_matrices(a, b, c, d) + 20 x 20 dense matrix over Integer Ring... + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix + sage: a, b, c, d = ([1, 1, 1, -1, -1], [1, -1, 1, 1, -1], [1, -1, -1, -1, -1], [1, -1, -1, -1, -1]) + sage: is_hadamard_matrix(skew_hadamard_matrix_from_good_matrices(a, b, c, d, check=False), skew=True) + True + sage: a, b, c, d = ([1, 1, 1, -1, -1], [1, -1, 1, 1, -1], [1, -1, -1, -1, -1], [1, -1, -1, -1, 1]) + sage: skew_hadamard_matrix_from_good_matrices(a, b, c, d) + Traceback (most recent call last): + ... + AssertionError + sage: a, b, c, d = ([1, 1, 1], [1, -1, 1, 1, -1], [1, -1, -1, -1, -1], [1, -1, -1, -1, -1]) + sage: skew_hadamard_matrix_from_good_matrices(a, b, c, d) + Traceback (most recent call last): + ... + AssertionError + """ + n = len(a) + m = (n-1) // 2 + + assert len(a) == len(b) == len(c) == len(d) + assert a[0] == 1 and b[0] == 1 and c[0] == 1 and d[0] == 1 + for i in range(1, m+1): + assert a[i] == -a[n-i] and b[i] == b[n-i] and c[i] == c[n-i] and d[i] == d[n-i] + + def back_circulant(row): + length = len(row) + return matrix([[row[(j+i) % length] for j in range(length)] for i in range(length)]) + + A = matrix.circulant(a) + B = back_circulant(b) + C = back_circulant(c) + D = back_circulant(d) + + H = block_matrix([[ A, B, C, D], + [-B, A, D, -C], + [-C, -D, A, B], + [-D, C, -B, A]]) + + if check: + assert is_hadamard_matrix(H, skew=True) + return H + + +def skew_hadamard_matrix_from_good_matrices_smallcases(n, existence=False, check=True): + r""" + Construct skew Hadamard matrices from good matrices for some small values of `n=4m`, with `m` odd. + + The function stores good matrices of odd orders `\le 31`, taken from [Sze1988]_. + These are used to create skew Hadamard matrices of order `4m`, `1 \le m \le 31` (`m` odd), using the function + :func:`skew_hadamard_matrix_from_good_matrices`. + + ALGORITHM: + + Given four sequences (stored in ``E_sequences``) of length `m`, they can be used to construct four `E-sequences` + of length `n=2m+1`, as follows: + + .. MATH:: + + \begin{aligned} + a &= 1, a_0, a_1, ..., a_m, -a_m, -a_{m-1}, ..., -a_0 \\ + b &= 1, b_0, b_1, ..., b_m, b_m, b_{m-1}, ..., b_0 \\ + c &= 1, c_0, c_1, ..., c_m, c_m, c_{m-1}, ..., c_0 \\ + d &= 1, d_0, d_1, ..., d_m, d_m, d_{m-1}, ..., d_0 \\ + \end{aligned} + + These E-sequences will be the first rows of the four good matrices needed to construct a skew Hadamard matrix + of order `4n`. + + INPUT: + + - ``n`` -- integer; the order of the skew Hadamard matrix to be constructed + - ``existence`` -- boolean (default: ``False``); If ``True``, only return + whether the Hadamard matrix can be constructed + - ``check`` -- boolean (default: ``True``): if ``True``, check that the matrix + is an Hadamard matrix before returning it + + OUTPUT: + + If ``existence=False``, returns the skew Hadamard matrix of order `n`. It + raises an error if no data is available to construct the matrix of the given + order. + If ``existence=True``, returns a boolean representing whether the matrix can + be constructed or not. + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix_from_good_matrices_smallcases + sage: skew_hadamard_matrix_from_good_matrices_smallcases(20) + 20 x 20 dense matrix over Integer Ring... + sage: skew_hadamard_matrix_from_good_matrices_smallcases(20, existence=True) + True + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix + sage: is_hadamard_matrix(skew_hadamard_matrix_from_good_matrices_smallcases(28, check=False), skew=True) + True + sage: skew_hadamard_matrix_from_good_matrices_smallcases(140) + Traceback (most recent call last): + ... + ValueError: The Good matrices of order 35 are not yet implemented. + sage: skew_hadamard_matrix_from_good_matrices_smallcases(14) + Traceback (most recent call last): + ... + ValueError: The skew Hadamard matrix of order 14 from good matrices does not exist. + sage: skew_hadamard_matrix_from_good_matrices_smallcases(140, existence=True) + False + sage: skew_hadamard_matrix_from_good_matrices_smallcases(14, existence=True) + False + """ + E_sequences = { + 0: ['', '', '', ''], + 1: ['+', '-', '-', '+'], + 2: ['++', '-+', '--', '--'], + 3: ['++-', '++-', '+-+', '-++'], + 4: ['+++-', '+-+-', '---+', '++-+'], + 5: ['+-+--', '+++--', '-+++-', '---+-'], + 6: ['+-+---', '---+++', '+-+--+', '----+-'], + 7: ['+++++--', '-++--++', '----+-+', '-+---+-'], + 8: ['+--++-+-', '+--+----', '++----+-', '+---+-+-'], + 9: ['-+-----++', '+-+++++--', '-+----++-', '--+-+-++-'], + 10: ['+--+++++++', '++--++++-+', '--++-+-+-+', '---+++-+-+'], + 11: ['++-+-------', '+----+--+--', '+-+--++---+', '--++-+-+-++'], + 12: ['+-----+-+---', '+-++++-+-++-', '---+--++++--', '--+-+++--+--'], + 13: ['+---+-+--++-+', '+++---++-++-+', '+++-+++-++---', '+---++++-+-+-'], + 14: ['+--+----+-+-++', '+---++++-++--+', '+-+----++-+--+', '++++++---+-+-+'], + 15: ['+--++----+---+-', '-++-+---+-+++--', '++---+--+--+++-', '-++++++++--+-+-'] + } + + def pm_to_good_matrix(s, sign=1): + e1 = [1 if x == '+' else -1 for x in s] + e2 = [sign * (1 if x == '+' else -1) for x in s] + e2.reverse() + return [1] + e1 + e2 + + if not (n % 4 == 0 and (n//4) % 2 == 1): + if existence: + return False + raise ValueError("The skew Hadamard matrix of order %s from good matrices does not exist." % n) + + m = n//4 + l = (m-1) // 2 + + if existence: + return l in E_sequences + + if l not in E_sequences: + raise ValueError("The Good matrices of order %s are not yet implemented." % m) + + e1, e2, e3, e4 = E_sequences[l] + a = pm_to_good_matrix(e1, sign=-1) + b = pm_to_good_matrix(e2) + c = pm_to_good_matrix(e3) + d = pm_to_good_matrix(e4) + return skew_hadamard_matrix_from_good_matrices(a, b, c, d, check=check) + + +_skew_had_cache = {} + + +def skew_hadamard_matrix(n, existence=False, skew_normalize=True, check=True): + r""" + Tries to construct a skew Hadamard matrix. + + A Hadamard matrix `H` is called skew if `H=S-I`, for `I` the identity matrix + and `-S=S^\top`. Currently all orders `\le 1000` for which a construction is + known are implemented. For `n > 1000`, only some orders are available. + + INPUT: + + - ``n`` -- integer; dimension of the matrix + - ``existence`` -- boolean (default: ``False``); whether to build the matrix + or merely query if a construction is available in Sage. When set to ``True``, + the function returns: + + - ``True`` -- meaning that Sage knows how to build the matrix - ``Unknown`` -- meaning that Sage does not know how to build the matrix, but that the design may exist (see :mod:`sage.misc.unknown`). - - ``False`` -- meaning that the matrix does not exist. - - ``skew_normalize`` (boolean) -- whether to make the 1st row all-one, and - adjust the 1st column accordingly. Set to ``True`` by default. - - - ``check`` (boolean) -- whether to check that output is correct before - returning it. As this is expected to be useless (but we are cautious - guys), you may want to disable it whenever you want speed. Set to ``True`` - by default. + - ``skew_normalize`` -- boolean (default: ``True``); whether to make the 1st + row all-one, and adjust the 1st column accordingly + - ``check`` -- boolean (default: ``True``); whether to check that output is + correct before returning it. As this is expected to be useless (but we are + cautious guys), you may want to disable it whenever you want speed EXAMPLES:: @@ -2059,11 +3110,11 @@ def skew_hadamard_matrix(n,existence=False, skew_normalize=True, check=True): 92 x 92 dense matrix over Integer Ring... sage: skew_hadamard_matrix(816) # long time 816 x 816 dense matrix over Integer Ring... - sage: skew_hadamard_matrix(100) + sage: skew_hadamard_matrix(356) Traceback (most recent call last): ... - ValueError: A skew Hadamard matrix of order 100 is not yet implemented. - sage: skew_hadamard_matrix(100,existence=True) + ValueError: A skew Hadamard matrix of order 356 is not yet implemented. + sage: skew_hadamard_matrix(356,existence=True) Unknown Check that :trac:`28526` is fixed:: @@ -2086,7 +3137,7 @@ def true(): M = None if existence and n in _skew_had_cache: return True - if not(n % 4 == 0) and (n > 2): + if not (n % 4 == 0) and (n > 2): if existence: return False raise ValueError("A skew Hadamard matrix of order %s does not exist" % n) @@ -2098,35 +3149,54 @@ def true(): if existence: return true() M = matrix([1]) + elif skew_hadamard_matrix_from_good_matrices_smallcases(n, existence=True): + if existence: + return true() + M = skew_hadamard_matrix_from_good_matrices_smallcases(n, check=False) elif is_prime_power(n - 1) and ((n - 1) % 4 == 3): if existence: return true() M = hadamard_matrix_paleyI(n, normalize=False) - + elif is_prime_power(n//2 - 1) and (n//2 - 1) % 8 == 5: + if existence: + return true() + M = skew_hadamard_matrix_spence_construction(n, check=False) + elif skew_hadamard_matrix_from_complementary_difference_sets(n, existence=True): + if existence: + return true() + M = skew_hadamard_matrix_from_complementary_difference_sets(n, check=False) + elif skew_hadamard_matrix_spence_1975(n, existence=True): + if existence: + return true() + M = skew_hadamard_matrix_spence_1975(n, check=False) + elif skew_hadamard_matrix_from_orthogonal_design(n, existence=True): + if existence: + return true() + M = skew_hadamard_matrix_from_orthogonal_design(n, check=False) elif n % 8 == 0: - if skew_hadamard_matrix(n//2,existence=True) is True: # (Lemma 14.1.6 in [Ha83]_) + if skew_hadamard_matrix(n//2, existence=True) is True: # (Lemma 14.1.6 in [Ha83]_) if existence: return true() - H = skew_hadamard_matrix(n//2,check=False) - M = block_matrix([[H,H], [-H.T,H.T]]) + H = skew_hadamard_matrix(n//2, check=False) + M = block_matrix([[H, H], [-H.T, H.T]]) - else: # try Williamson construction (Lemma 14.1.5 in [Ha83]_) - for d in divisors(n)[2:-2]: # skip 1, 2, n/2, and n + else: # try Williamson construction (Lemma 14.1.5 in [Ha83]_) + for d in divisors(n)[2:-2]: # skip 1, 2, n/2, and n n1 = n//d if is_prime_power(d - 1) and (d % 4 == 0) and (n1 % 4 == 0)\ - and skew_hadamard_matrix(n1,existence=True) is True: + and skew_hadamard_matrix(n1, existence=True) is True: if existence: return true() H = skew_hadamard_matrix(n1, check=False)-I(n1) - U = matrix(ZZ, d, lambda i, j: -1 if i==j==0 else\ - 1 if i==j==1 or (i>1 and j-1==d-i)\ + U = matrix(ZZ, d, lambda i, j: -1 if i == j == 0 else + 1 if i == j == 1 or (i > 1 and j-1 == d-i) else 0) - A = block_matrix([[matrix([0]), matrix(ZZ,1,d-1,[1]*(d-1))], - [ matrix(ZZ,d-1,1,[-1]*(d-1)), - _helper_payley_matrix(d-1,zero_position=0)]])+I(d) + A = block_matrix([[matrix([0]), matrix(ZZ, 1, d-1, [1]*(d-1))], + [matrix(ZZ, d-1, 1, [-1]*(d-1)), + _helper_payley_matrix(d-1, zero_position=0)]])+I(d) M = A.tensor_product(I(n1))+(U*A).tensor_product(H) break - if M is None: # try Williamson-Goethals-Seidel construction + if M is None: # try Williamson-Goethals-Seidel construction if GS_skew_hadamard_smallcases(n, existence=True) is True: if existence: return true() @@ -2137,15 +3207,13 @@ def true(): return Unknown raise ValueError("A skew Hadamard matrix of order %s is not yet implemented." % n) if skew_normalize: - dd = diagonal_matrix(M[0]) - M = dd*M*dd + M = normalise_hadamard(M, skew=True) if check: - assert is_hadamard_matrix(M, normalized=False, skew=True) - if skew_normalize: - assert M[0]==vector([1]*n) - _skew_had_cache[n]=True + assert is_hadamard_matrix(M, normalized=skew_normalize, skew=True) + _skew_had_cache[n] = True return M + def symmetric_conference_matrix(n, check=True): r""" Tries to construct a symmetric conference matrix @@ -2159,12 +3227,10 @@ def symmetric_conference_matrix(n, check=True): INPUT: - - ``n`` (integer) -- dimension of the matrix - - - ``check`` (boolean) -- whether to check that output is correct before - returning it. As this is expected to be useless (but we are cautious - guys), you may want to disable it whenever you want speed. Set to ``True`` - by default. + - ``n`` -- integer; dimension of the matrix + - ``check`` -- boolean (default: ``True``); whether to check that output is + correct before returning it. As this is expected to be useless (but we are + cautious guys), you may want to disable it whenever you want speed EXAMPLES:: @@ -2185,12 +3251,12 @@ def symmetric_conference_matrix(n, check=True): """ from sage.graphs.strongly_regular_db import strongly_regular_graph as srg try: - m = srg(n-1,(n-2)/2,(n-6)/4,(n-2)/4) + m = srg(n-1, (n-2)/2, (n-6)/4, (n-2)/4) except ValueError: raise C = matrix([0]+[1]*(n-1)).stack(matrix([1]*(n-1)).stack(m.seidel_adjacency_matrix()).T) if check: - assert (C==C.T and C**2==(n-1)*I(n)) + assert (C == C.T and C**2 == (n-1)*I(n)) return C @@ -2212,9 +3278,9 @@ def szekeres_difference_set_pair(m, check=True): INPUT: - - ``m`` (integer) -- dimension of the matrix - - - ``check`` (default: ``True``) -- whether to check `A` and `B` for correctness + - ``m`` -- integer; dimension of the matrix + - ``check`` -- boolean (default: ``True``); whether to check `A` and `B` for + correctness EXAMPLES:: @@ -2235,16 +3301,16 @@ def szekeres_difference_set_pair(m, check=True): B = [b for b in G if b + F.one() in sG] if check: from itertools import product, chain - assert(len(A) == len(B) == m) + assert (len(A) == len(B) == m) if m > 1: - assert(sG == set([xy[0] / xy[1] + assert (sG == set([xy[0] / xy[1] for xy in chain(product(A, A), product(B, B))])) - assert(all(F.one() / b + F.one() in sG for b in B)) - assert(not any(F.one() / a - F.one() in sG for a in A)) + assert (all(F.one() / b + F.one() in sG for b in B)) + assert (not any(F.one() / a - F.one() in sG for a in A)) return G, A, B -def typeI_matrix_difference_set(G,A): +def typeI_matrix_difference_set(G, A): r""" (1,-1)-incidence type I matrix of a difference set `A` in `G` @@ -2264,7 +3330,8 @@ def typeI_matrix_difference_set(G,A): [-1 -1 1 1 -1] """ n = len(G) - return matrix(n,n, lambda i,j: 1 if G[i]/G[j] in A else -1) + return matrix(n, n, lambda i, j: 1 if G[i]/G[j] in A else -1) + def rshcd_from_prime_power_and_conference_matrix(n): r""" @@ -2317,28 +3384,258 @@ def rshcd_from_prime_power_and_conference_matrix(n): - [WW1972]_ """ from sage.graphs.strongly_regular_db import strongly_regular_graph as srg - if is_prime_power(n) and 2==(n-1)%4: + if is_prime_power(n) and 2 == (n-1) % 4: try: - M = srg(n-2,(n-3)//2,(n-7)//4) + M = srg(n-2, (n-3)//2, (n-7)//4) except ValueError: return m = (n-3)//4 - Q,X,Y = szekeres_difference_set_pair(m) - B = typeI_matrix_difference_set(Q,X) - A = -typeI_matrix_difference_set(Q,Y) # must be symmetric + Q, X, Y = szekeres_difference_set_pair(m) + B = typeI_matrix_difference_set(Q, X) + A = -typeI_matrix_difference_set(Q, Y) # must be symmetric W = M.seidel_adjacency_matrix() - f = J(1,4*m+1) - e = J(1,2*m+1) + f = J(1, 4*m+1) + e = J(1, 2*m+1) JJ = J(2*m+1, 2*m+1) II = I(n-2) Ib = I(2*m+1) - J4m = J(4*m+1,4*m+1) + J4m = J(4*m+1, 4*m+1) H34 = -(B+Ib).tensor_product(W)+Ib.tensor_product(J4m)+(Ib-JJ).tensor_product(II) A_t_W = A.tensor_product(W) e_t_f = e.tensor_product(f) H = block_matrix([ - [J(1,1), f, e_t_f, -e_t_f], + [J(1, 1), f, e_t_f, -e_t_f], [f.T, J4m, e.tensor_product(W-II), e.tensor_product(W+II)], [ e_t_f.T, (e.T).tensor_product(W-II), A_t_W+JJ.tensor_product(II), H34], [-e_t_f.T, (e.T).tensor_product(W+II), H34.T, -A_t_W+JJ.tensor_product(II)]]) return H + + +def are_amicable_hadamard_matrices(M, N, verbose=False): + r""" + Check if ``M`` and ``N`` are amicable Hadamard matrices. + + Two matrices `M` and `N` of order `n` are called amicable if they + satisfy the following conditions (see [Seb2017]_): + + * `M` is a skew Hadamard matrix + * `N` is a symmetric Hadamard matrix + * `MN^T = NM^T` + + INPUT: + + - ``M`` -- a square matrix + - ``N`` -- a square matrix + - ``verbose`` -- boolean (default ``False``); whether to be verbose when the + matrices are not amicable Hadamard matrices + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import are_amicable_hadamard_matrices + sage: M = matrix([[1, 1], [-1, 1]]) + sage: N = matrix([[1, 1], [1, -1]]) + sage: are_amicable_hadamard_matrices(M, N) + True + + If ``verbose`` is true, the function will be verbose when returning False:: + + sage: N = matrix([[1, 1], [1, 1]]) + sage: are_amicable_hadamard_matrices(M, N, verbose=True) + The second matrix is not Hadamard + False + + TESTS:: + + sage: N = matrix.hadamard(12) + sage: are_amicable_hadamard_matrices(M, N) + False + """ + if not is_skew_hadamard_matrix(M): + if verbose: + print('The first matrix is not skew Hadamard') + return False + + if not is_hadamard_matrix(N): + if verbose: + print('The second matrix is not Hadamard') + return False + + if not N.is_symmetric(): + if verbose: + print('The second matrix is not symmetric') + return False + + if len(M[0]) != len(N[0]): + if verbose: + print('M*N.transpose() is not equal to N*M.transpose()') + return False + + return True + + +def amicable_hadamard_matrices_wallis(n, check=True): + r""" + Construct amicable Hadamard matrices of order `n = q + 1` where `q` is a prime power. + + If `q` is a prime power `\equiv 3 \mod 4`, then amicable Hadamard matrices + of order `q+1` can be constructed as described in [Wal1970b]_. + + INPUT: + + - ``n`` -- integer; the order of the matrices to be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the + resulting matrices are amicable Hadamard before returning them + + OUTPUT: + + The function returns two amicable Hadamard matrices, or raises an error if such + matrices cannot be created using this construction. + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import amicable_hadamard_matrices_wallis + sage: M, N = amicable_hadamard_matrices_wallis(28) + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import are_amicable_hadamard_matrices + sage: M, N = amicable_hadamard_matrices_wallis(20, check=False) + sage: are_amicable_hadamard_matrices(M, N) + True + sage: amicable_hadamard_matrices_wallis(18) + Traceback (most recent call last): + ... + ValueError: n must be a positive multiple of 4 + sage: amicable_hadamard_matrices_wallis(16) + Traceback (most recent call last): + ... + ValueError: q = n-1 must be a prime power + """ + if n % 4 != 0 or n < 0: + raise ValueError('n must be a positive multiple of 4') + + q = n - 1 + if not is_prime_power(q): + raise ValueError('q = n-1 must be a prime power') + + from sage.rings.finite_rings.finite_field_constructor import GF + + G = GF(q) + + ls1, ls2 = [], [] + elements_added = set() + for el in G: + if el == 0 or el in elements_added: + continue + elements_added.add(el) + ls1.append(el) + elements_added.add(-el) + ls2 = [-el] + ls2 + Glist = [0] + ls1 + ls2 + + squares = [] + for el in Glist: + squares.append(el*el) + + def chi(el): + if el == 0: + return 0 + if el in squares: + return 1 + return -1 + + S = matrix([[chi(Glist[i] - Glist[j]) for j in range(q)] for i in range(q)]) + R = matrix([[1 if (i, j) == (0, 0) else 1 if j == q-i else 0 for j in range(q)] for i in range(q)]) + + P = S + I(q) + D = R + R*S + + e = matrix([1 for _ in range(q)]) + one = matrix([1]) + + M = block_matrix([[ one, e], + [-e.T, P]]) + N = block_matrix([[-one, -e], + [-e.T, D]]) + + if check: + assert are_amicable_hadamard_matrices(M, N) + return M, N + + +def amicable_hadamard_matrices(n, existence=False, check=True): + r""" + Construct amicable Hadamard matrices of order ``n`` using the available methods. + + INPUT: + + - ``n`` -- positive integer; the order of the amicable Hadamard matrices + - ``existence`` -- boolean (default: ``False``); if ``True``, only return + whether amicable Hadamard matrices of order `n` can be constructed + - ``check`` -- boolean (default: ``True``); if ``True``, check that the + matrices are amicable Hadamard matrices before returning them + + OUTPUT: + + If ``existence`` is true, the function returns a boolean representing whether + amicable Hadamard matrices of order `n` can be constructed. + If ``existence`` is false, returns two amicable Hadamard matrices, or raises + an error if the matrices cannot be constructed. + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import amicable_hadamard_matrices + sage: amicable_hadamard_matrices(2) + ( + [ 1 1] [ 1 1] + [-1 1], [ 1 -1] + ) + + If ``existence`` is true, the function returns a boolean:: + + sage: amicable_hadamard_matrices(16, existence=True) + False + + TESTS:: + + sage: M, N = amicable_hadamard_matrices(20) + sage: amicable_hadamard_matrices(18) + Traceback (most recent call last): + ... + ValueError: Hadamard matrices of order 18 do not exist + sage: amicable_hadamard_matrices(16) + Traceback (most recent call last): + ... + NotImplementedError: construction for amicable Hadamard matrices of order 16 not yet implemented + """ + if not ((n % 4 == 0 and n > 2) or n in [1, 2]): + if existence: + return False + raise ValueError(f"Hadamard matrices of order {n} do not exist") + + M = None + N = None + if n == 1: + if existence: + return True + M = matrix([1]) + N = matrix([1]) + elif n == 2: + if existence: + return True + M = matrix([[1, 1], [-1, 1]]) + N = matrix([[1, 1], [1, -1]]) + elif is_prime_power(n-1): + if existence: + return True + M, N = amicable_hadamard_matrices_wallis(n, check=False) + + if existence: + return False + + if M is None: + raise NotImplementedError(f'construction for amicable Hadamard matrices of order {n} not yet implemented') + + if check: + assert are_amicable_hadamard_matrices(M, N) + return M, N diff --git a/src/sage/combinat/matrices/latin.py b/src/sage/combinat/matrices/latin.py index 82e6ff65311..b2b21ff12d2 100644 --- a/src/sage/combinat/matrices/latin.py +++ b/src/sage/combinat/matrices/latin.py @@ -135,11 +135,11 @@ from sage.matrix.matrix_integer_dense import Matrix_integer_dense from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.groups.perm_gps.constructor import PermutationGroupElement as PermutationConstructor -from sage.interfaces.gap import GapElement +from sage.libs.gap.libgap import libgap +from sage.libs.gap.element import GapElement from sage.combinat.permutation import Permutation -from sage.interfaces.gap import gap from sage.groups.perm_gps.permgroup import PermutationGroup -from sage.arith.all import is_prime +from sage.arith.misc import is_prime from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.misc.flatten import flatten @@ -2327,14 +2327,14 @@ def group_to_LatinSquare(G): :: - sage: G = gap.Group(PermutationGroupElement((1,2,3))) + sage: G = libgap.Group(PermutationGroupElement((1,2,3))) sage: group_to_LatinSquare(G) [0 1 2] [1 2 0] [2 0 1] """ if isinstance(G, GapElement): - rows = (list(x) for x in list(gap.MultiplicationTable(G))) + rows = (list(x) for x in list(libgap.MultiplicationTable(G))) new_rows = [] for x in rows: @@ -2454,15 +2454,15 @@ def p3_group_bitrade_generators(p): sage: from sage.combinat.matrices.latin import * sage: p3_group_bitrade_generators(3) - ((2,6,7)(3,8,9), (1,2,3)(4,7,8)(5,6,9), (1,9,2)(3,7,4)(5,8,6), Permutation Group with generators [(2,6,7)(3,8,9), (1,2,3)(4,7,8)(5,6,9)]) + ((2,6,7)(3,8,9), + (1,2,3)(4,7,8)(5,6,9), + (1,9,2)(3,7,4)(5,8,6), + Permutation Group with generators [(2,6,7)(3,8,9), (1,2,3)(4,7,8)(5,6,9)]) """ assert is_prime(p) - F = gap.new("FreeGroup(3)") - - a = F.gen(1) - b = F.gen(2) - c = F.gen(3) + F = libgap.FreeGroup(3) + a, b, c = F.GeneratorsOfGroup() rels = [] rels.append(a**p) @@ -2473,11 +2473,12 @@ def p3_group_bitrade_generators(p): rels.append(c*b*((b*c)**(-1))) G = F.FactorGroupFpGroupByRels(rels) + u, v, _ = G.GeneratorsOfGroup() - iso = gap.IsomorphismPermGroup(G) + iso = libgap.IsomorphismPermGroup(G) - x = PermutationConstructor(gap.Image(iso, G.gen(1))) - y = PermutationConstructor(gap.Image(iso, G.gen(2))) + x = PermutationConstructor(libgap.Image(iso, u)) + y = PermutationConstructor(libgap.Image(iso, v)) return (x, y, (x*y)**(-1), PermutationGroup([x, y])) @@ -2504,7 +2505,7 @@ def check_bitrade_generators(a, b, c): if a*b != c**(-1): return False - X = gap.Intersection(gap.Intersection(A, B), C) + X = libgap.Intersection(libgap.Intersection(A, B), C) return X.Size() == 1 @@ -2648,11 +2649,11 @@ def bitrade_from_group(a, b, c, G): [ 2 1 3 -1] [ 0 3 -1 2] """ - hom = gap.ActionHomomorphism(G, gap.RightCosets(G, gap.TrivialSubgroup(G)), gap.OnRight) + hom = libgap.ActionHomomorphism(G, libgap.RightCosets(G, libgap.TrivialSubgroup(G)), libgap.OnRight) - t1 = gap.Image(hom, a) - t2 = gap.Image(hom, b) - t3 = gap.Image(hom, c) + t1 = libgap.Image(hom, a) + t2 = libgap.Image(hom, b) + t3 = libgap.Image(hom, c) t1 = Permutation(str(t1).replace('\n', '')) t2 = Permutation(str(t2).replace('\n', '')) diff --git a/src/sage/combinat/multiset_partition_into_sets_ordered.py b/src/sage/combinat/multiset_partition_into_sets_ordered.py index 6f5495f36e9..7bcdfbb92a5 100755 --- a/src/sage/combinat/multiset_partition_into_sets_ordered.py +++ b/src/sage/combinat/multiset_partition_into_sets_ordered.py @@ -45,29 +45,26 @@ Crystal of ordered multiset partitions into sets on the alphabet `\{1,2,3\}` with 4 letters divided into 2 blocks:: - sage: crystals.Minimaj(3, 4, 2).list() + sage: crystals.Minimaj(3, 4, 2).list() # optional - sage.modules [((2, 3, 1), (1,)), ((2, 3), (1, 2)), ((2, 3), (1, 3)), ((2, 1), (1, 2)), ((3, 1), (1, 2)), ((3, 1, 2), (2,)), ((3, 1), (1, 3)), ((3, 1), (2, 3)), ((3, 2), (2, 3)), ((2, 1), (1, 3)), ((2,), (1, 2, 3)), ((3,), (1, 2, 3)), ((1,), (1, 2, 3)), ((1, 2), (2, 3)), ((1, 2, 3), (3,))] """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2018 Aaron Lauve <lauve at math.luc.edu> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** - - from functools import reduce -from itertools import chain +from itertools import chain, product from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.categories.cartesian_product import cartesian_product from sage.categories.classical_crystals import ClassicalCrystals from sage.categories.tensor import tensor from sage.structure.unique_representation import UniqueRepresentation @@ -81,7 +78,7 @@ from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.power_series_ring import PowerSeriesRing -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.combinat.subset import Subsets_sk from sage.combinat.composition import Composition, Compositions, composition_iterator_fast @@ -672,7 +669,7 @@ def split_blocks(self, k=2): return {tuple([self]*k): 1} out = {} - for t in cartesian_product([_split_block(block, k) for block in self]): + for t in product(*[_split_block(block, k) for block in self]): tt = tuple([P([l for l in c if l]) for c in zip(*t)]) out[tt] = out.get(tt, 0) + 1 return out @@ -711,8 +708,8 @@ def finer(self, strong=False): if not self: return set([self]) - CP = cartesian_product([_refine_block(block, strong) for block in self]) - return set(P(_concatenate(map(list,c))) for c in CP) + CP = product(*[_refine_block(block, strong) for block in self]) + return set(P(_concatenate(map(list, c))) for c in CP) def is_finer(self, co): """ @@ -803,7 +800,7 @@ def fatten(self, grouping): str_rep = '[' for i in range(len(grouping)): st = ",".join(str(k) for k in result[i]) - str_rep += "{" + st+ "}" + str_rep += "{" + st + "}" str_rep = str_rep.replace("}{", "}, {") + "]" raise ValueError("%s is not a valid ordered multiset partition into sets" % (str_rep)) else: @@ -1554,7 +1551,7 @@ def __init__(self, is_finite=None, **constraints): constraints.pop("max_order", None) min_ord = constraints.get("min_order", 0) max_ord = constraints.get("max_order", infinity) - assert min_ord <= max_ord, "min_order=%s <= max_order=%s"%(min_ord, max_ord) + assert min_ord <= max_ord, "min_order=%s <= max_order=%s" % (min_ord, max_ord) if min_ord == max_ord: constraints["order"] = constraints.pop("min_order", constraints.pop("max_order")) @@ -2226,7 +2223,7 @@ def _repr_(self): 'Ordered Multiset Partitions into Sets of multiset {{1, 1, 4}}' """ ms_rep = "{{" + ", ".join(map(str, self._Xtup)) + "}}" - return "Ordered Multiset Partitions into Sets" + " of multiset %s"%ms_rep + return "Ordered Multiset Partitions into Sets" + " of multiset %s" % ms_rep def __contains__(self, x): """ @@ -2396,7 +2393,7 @@ def _repr_(self): cdict = dict(self.constraints) cdict.pop("weight", None) ms_rep = "{{" + ", ".join(map(str, self._Xtup)) + "}}" - base_repr = "Ordered Multiset Partitions into Sets" + " of multiset %s"%ms_rep + base_repr = "Ordered Multiset Partitions into Sets" + " of multiset %s" % ms_rep return base_repr + self._constraint_repr_(cdict) ############### @@ -2441,7 +2438,7 @@ def _repr_(self): 'Ordered Multiset Partitions into Sets of order 2 over alphabet {1, 3}' """ A_rep = "Ordered Multiset Partitions into Sets of order " + str(self._order) - A_rep += " over alphabet {%s}"%(", ".join(map(str, sorted(self._alphabet)))) + A_rep += " over alphabet {%s}" % (", ".join(map(str, sorted(self._alphabet)))) return A_rep def _an_element_(self): @@ -2583,7 +2580,7 @@ def _repr_(self): cdict.pop("alphabet", None) cdict.pop("order", None) base_repr = "Ordered Multiset Partitions into Sets of order " + str(self._order) - base_repr += " over alphabet {%s}"%(", ".join(map(str, sorted(self._alphabet)))) + base_repr += " over alphabet {%s}" % (", ".join(map(str, sorted(self._alphabet)))) return base_repr + self._constraint_repr_(cdict) ############### @@ -2787,8 +2784,8 @@ def _base_iterator(constraints): if min_ord: min_k = max(1, min_k, min_ord // len(A)) if infinity not in (max_k, max_ord): - return chain(*(_iterator_order(A, ord, range(min_k, max_k+1)) \ - for ord in range(min_ord, max_ord+1))) + return chain(*(_iterator_order(A, ord, range(min_k, max_k + 1)) + for ord in range(min_ord, max_ord + 1))) # else return None @@ -2892,16 +2889,16 @@ def _iterator_size(size, length=None, alphabet=None): max_p = max(alphabet) for alpha in IntegerListsLex(size, length=length, min_part=1, max_part=min(size, sum(alphabet))): - for p in cartesian_product([IntegerListsLex(a, min_slope=1, - min_part=min_p, - max_part=min(a, max_p)) - for a in alpha]): + for p in product(*[IntegerListsLex(a, min_slope=1, + min_part=min_p, + max_part=min(a, max_p)) + for a in alpha]): if frozenset(_concatenate(p)).issubset(frozenset(alphabet)): yield tuple(frozenset(k) for k in p) else: for alpha in IntegerListsLex(size, length=length, min_part=1, max_part=size): - for p in cartesian_product([IntegerListsLex(a, min_slope=1, - min_part=1) for a in alpha]): + for p in product(*[IntegerListsLex(a, min_slope=1, + min_part=1) for a in alpha]): yield tuple(frozenset(k) for k in p) @@ -2967,11 +2964,11 @@ def _iterator_order(A, d, lengths=None): yield () else: for alpha in IntegerListsLex(d, length=k, min_part=1, max_part=n): - for co in cartesian_product([Subsets_sk(A, a) for a in alpha]): + for co in product(*[Subsets_sk(A, a) for a in alpha]): yield tuple(frozenset(X) for X in co) -def _descents(w): +def _descents(w) -> list: r""" Return descent positions in the word ``w``. @@ -2983,7 +2980,7 @@ def _descents(w): sage: _descents([]) [] """ - return [j for j in range(len(w)-1) if w[j] > w[j+1]] + return [j for j in range(len(w) - 1) if w[j] > w[j + 1]] def _break_at_descents(alpha, weak=True): @@ -3200,14 +3197,14 @@ class MinimajCrystal(UniqueRepresentation, Parent): EXAMPLES:: - sage: list(crystals.Minimaj(2,3,2)) + sage: list(crystals.Minimaj(2,3,2)) # optional - sage.modules [((2, 1), (1,)), ((2,), (1, 2)), ((1,), (1, 2)), ((1, 2), (2,))] - sage: b = crystals.Minimaj(3, 5, 2).an_element(); b + sage: b = crystals.Minimaj(3, 5, 2).an_element(); b # optional - sage.modules ((2, 3, 1), (1, 2)) - sage: b.f(2) + sage: b.f(2) # optional - sage.modules ((2, 3, 1), (1, 3)) - sage: b.e(2) + sage: b.e(2) # optional - sage.modules """ def __init__(self, n, ell, k): @@ -3216,17 +3213,17 @@ def __init__(self, n, ell, k): TESTS:: - sage: B = crystals.Minimaj(2,3,2) - sage: TestSuite(B).run() + sage: B = crystals.Minimaj(2,3,2) # optional - sage.modules + sage: TestSuite(B).run() # optional - sage.modules - sage: B = crystals.Minimaj(3, 5, 2) - sage: TestSuite(B).run() + sage: B = crystals.Minimaj(3, 5, 2) # optional - sage.modules + sage: TestSuite(B).run() # optional - sage.modules - sage: list(crystals.Minimaj(2,6,3)) + sage: list(crystals.Minimaj(2,6,3)) # optional - sage.modules [((1, 2), (2, 1), (1, 2))] - sage: list(crystals.Minimaj(2,5,2)) # blocks too fat for alphabet + sage: list(crystals.Minimaj(2,5,2)) # blocks too fat for alphabet # optional - sage.modules [] - sage: list(crystals.Minimaj(4,2,3)) # more blocks than letters + sage: list(crystals.Minimaj(4,2,3)) # more blocks than letters # optional - sage.modules Traceback (most recent call last): ... ValueError: n (=4), ell (=2), and k (=3) must all be positive integers @@ -3236,9 +3233,9 @@ def __init__(self, n, ell, k): self.ell = ell self.k = k if not all([n in ZZ, ell in ZZ, k in ZZ]): - raise TypeError("n (=%s), ell (=%s), and k (=%s) must all be positive integers"%(n, ell, k)) + raise TypeError("n (=%s), ell (=%s), and k (=%s) must all be positive integers" % (n, ell, k)) if not all([n > 0, ell >= k, k > 0]): - raise ValueError("n (=%s), ell (=%s), and k (=%s) must all be positive integers"%(n, ell, k)) + raise ValueError("n (=%s), ell (=%s), and k (=%s) must all be positive integers" % (n, ell, k)) self._cartan_type = CartanType(['A',n-1]) B = Letters(['A', n-1]) T = tensor([B]*ell) @@ -3259,7 +3256,7 @@ def _repr_(self): EXAMPLES:: - sage: B = crystals.Minimaj(3,4,2); B + sage: B = crystals.Minimaj(3,4,2); B # optional - sage.modules Minimaj Crystal of type A_2 of words of length 4 into 2 blocks """ return ("Minimaj Crystal of type A_%s of words of length %s into %s blocks" @@ -3271,14 +3268,14 @@ def _an_element_(self): EXAMPLES:: - sage: B = crystals.Minimaj(4,5,3) - sage: B.an_element() + sage: B = crystals.Minimaj(4,5,3) # optional - sage.modules + sage: B.an_element() # optional - sage.modules ((2, 3, 1), (1,), (1,)) - sage: B = crystals.Minimaj(2,2,1) - sage: B.an_element() + sage: B = crystals.Minimaj(2,2,1) # optional - sage.modules + sage: B.an_element() # optional - sage.modules ((1, 2),) - sage: B = crystals.Minimaj(1,2,1) - sage: B.an_element() + sage: B = crystals.Minimaj(1,2,1) # optional - sage.modules + sage: B.an_element() # optional - sage.modules Traceback (most recent call last): ... EmptySetError @@ -3294,14 +3291,14 @@ def _element_constructor_(self, x): EXAMPLES:: - sage: B1 = crystals.Minimaj(4,5,3); b = B1.an_element(); b + sage: B1 = crystals.Minimaj(4,5,3); b = B1.an_element(); b # optional - sage.modules ((2, 3, 1), (1,), (1,)) - sage: B1._element_constructor_(list(b)) + sage: B1._element_constructor_(list(b)) # optional - sage.modules ((2, 3, 1), (1,), (1,)) - sage: B1._element_constructor_([[1,2,3], [2], [2]]) + sage: B1._element_constructor_([[1,2,3], [2], [2]]) # optional - sage.modules ((3, 1, 2), (2,), (2,)) - sage: B2 = crystals.Minimaj(5,5,3) - sage: B2._element_constructor_(b) + sage: B2 = crystals.Minimaj(5,5,3) # optional - sage.modules + sage: B2._element_constructor_(b) # optional - sage.modules ((2, 3, 1), (1,), (1,)) """ # Allow ``x`` to be either of: @@ -3316,7 +3313,7 @@ def _element_constructor_(self, x): B,T = self._BT return self.element_class(self, (T(*[B(a) for a in _concatenate(t)]), breaks)) else: - raise ValueError("cannot convert %s into an element of %s"%(x, self)) + raise ValueError("cannot convert %s into an element of %s" % (x, self)) def __contains__(self, x): """ @@ -3325,17 +3322,17 @@ def __contains__(self, x): EXAMPLES:: - sage: B1 = crystals.Minimaj(2,5,3); b1 = B1.an_element(); b1 + sage: B1 = crystals.Minimaj(2,5,3); b1 = B1.an_element(); b1 # optional - sage.modules ((1, 2), (2, 1), (1,)) - sage: B2 = crystals.Minimaj(5,5,3); b2 = B2.an_element(); b2 + sage: B2 = crystals.Minimaj(5,5,3); b2 = B2.an_element(); b2 # optional - sage.modules ((2, 3, 1), (1,), (1,)) - sage: b2a = B2(((1,2), (1,), (1,2))); b2a + sage: b2a = B2(((1,2), (1,), (1,2))); b2a # optional - sage.modules ((2, 1), (1,), (1, 2)) - sage: b1 in B2 + sage: b1 in B2 # optional - sage.modules True - sage: b2 in B1 + sage: b2 in B1 # optional - sage.modules False - sage: b2a in B1 + sage: b2a in B1 # optional - sage.modules True """ if isinstance(x, MinimajCrystal.Element): @@ -3356,24 +3353,24 @@ def from_tableau(self, t): EXAMPLES:: - sage: B = crystals.Minimaj(3,6,3) - sage: b = B.an_element(); b + sage: B = crystals.Minimaj(3,6,3) # optional - sage.modules + sage: b = B.an_element(); b # optional - sage.modules ((3, 1, 2), (2, 1), (1,)) - sage: t = b.to_tableaux_words(); t + sage: t = b.to_tableaux_words(); t # optional - sage.modules [[1], [2, 1], [], [3, 2, 1]] - sage: B.from_tableau(t) + sage: B.from_tableau(t) # optional - sage.modules ((3, 1, 2), (2, 1), (1,)) - sage: B.from_tableau(t) == b + sage: B.from_tableau(t) == b # optional - sage.modules True TESTS:: - sage: B = crystals.Minimaj(3,6,3) - sage: all(mu == B.from_tableau(mu.to_tableaux_words()) for mu in B) + sage: B = crystals.Minimaj(3,6,3) # optional - sage.modules + sage: all(mu == B.from_tableau(mu.to_tableaux_words()) for mu in B) # optional - sage.modules True - sage: t = B.an_element().to_tableaux_words() - sage: B1 = crystals.Minimaj(3,6,2) - sage: B1.from_tableau(t) + sage: t = B.an_element().to_tableaux_words() # optional - sage.modules + sage: B1 = crystals.Minimaj(3,6,2) # optional - sage.modules + sage: B1.from_tableau(t) # optional - sage.modules Traceback (most recent call last): ... ValueError: ((3, 1, 2), (2, 1), (1,)) is not an element of @@ -3393,8 +3390,8 @@ def val(self, q='q'): Verifying Example 4.5 from [BCHOPSY2017]_:: - sage: B = crystals.Minimaj(3, 4, 2) # for `Val_{4,1}^{(3)}` - sage: B.val() + sage: B = crystals.Minimaj(3, 4, 2) # for `Val_{4,1}^{(3)}` # optional - sage.modules + sage: B.val() # optional - sage.modules (q^2+q+1)*s[2, 1, 1] + q*s[2, 2] """ H = [self._OMPs(list(b)) for b in self.highest_weight_vectors()] @@ -3428,7 +3425,7 @@ def _repr_(self): EXAMPLES:: - sage: crystals.Minimaj(4,5,3).an_element() + sage: crystals.Minimaj(4,5,3).an_element() # optional - sage.modules ((2, 3, 1), (1,), (1,)) """ return repr(self._minimaj_blocks_from_word_pair()) @@ -3439,11 +3436,11 @@ def __iter__(self): EXAMPLES:: - sage: b = crystals.Minimaj(4,5,3).an_element(); b + sage: b = crystals.Minimaj(4,5,3).an_element(); b # optional - sage.modules ((2, 3, 1), (1,), (1,)) - sage: b.value + sage: b.value # optional - sage.modules ([1, 3, 2, 1, 1], (0, 1, 2, 5)) - sage: list(b) + sage: list(b) # optional - sage.modules [(2, 3, 1), (1,), (1,)] """ return self._minimaj_blocks_from_word_pair().__iter__() @@ -3454,9 +3451,9 @@ def _latex_(self): EXAMPLES:: - sage: b = crystals.Minimaj(4,5,3).an_element(); b + sage: b = crystals.Minimaj(4,5,3).an_element(); b # optional - sage.modules ((2, 3, 1), (1,), (1,)) - sage: latex(b) + sage: latex(b) # optional - sage.modules \left(\left(2, 3, 1\right), \left(1\right), \left(1\right)\right) """ return latex(self._minimaj_blocks_from_word_pair()) @@ -3468,10 +3465,10 @@ def _minimaj_blocks_from_word_pair(self): EXAMPLES:: - sage: B = crystals.Minimaj(4,5,3) - sage: b = B.an_element(); b.value + sage: B = crystals.Minimaj(4,5,3) # optional - sage.modules + sage: b = B.an_element(); b.value # optional - sage.modules ([1, 3, 2, 1, 1], (0, 1, 2, 5)) - sage: b._minimaj_blocks_from_word_pair() + sage: b._minimaj_blocks_from_word_pair() # optional - sage.modules ((2, 3, 1), (1,), (1,)) """ return _to_minimaj_blocks(self.to_tableaux_words()) @@ -3483,15 +3480,15 @@ def to_tableaux_words(self): EXAMPLES:: - sage: B = crystals.Minimaj(4,5,3) - sage: b = B.an_element(); b + sage: B = crystals.Minimaj(4,5,3) # optional - sage.modules + sage: b = B.an_element(); b # optional - sage.modules ((2, 3, 1), (1,), (1,)) - sage: b.to_tableaux_words() + sage: b.to_tableaux_words() # optional - sage.modules [[1], [3], [2, 1, 1]] - sage: b = B([[1,3,4], [3], [3]]); b + sage: b = B([[1,3,4], [3], [3]]); b # optional - sage.modules ((4, 1, 3), (3,), (3,)) - sage: b.to_tableaux_words() + sage: b.to_tableaux_words() # optional - sage.modules [[3, 1], [], [4, 3, 3]] """ w, breaks = self.value @@ -3504,10 +3501,10 @@ def e(self, i): EXAMPLES:: - sage: B = crystals.Minimaj(4,3,2) - sage: b = B([[2,3], [3]]); b + sage: B = crystals.Minimaj(4,3,2) # optional - sage.modules + sage: b = B([[2,3], [3]]); b # optional - sage.modules ((2, 3), (3,)) - sage: [b.e(i) for i in range(1,4)] + sage: [b.e(i) for i in range(1,4)] # optional - sage.modules [((1, 3), (3,)), ((2,), (2, 3)), None] """ P = self.parent() @@ -3523,10 +3520,10 @@ def f(self,i): EXAMPLES:: - sage: B = crystals.Minimaj(4,3,2) - sage: b = B([[2,3], [3]]); b + sage: B = crystals.Minimaj(4,3,2) # optional - sage.modules + sage: b = B([[2,3], [3]]); b # optional - sage.modules ((2, 3), (3,)) - sage: [b.f(i) for i in range(1,4)] + sage: [b.f(i) for i in range(1,4)] # optional - sage.modules [None, None, ((2, 3), (4,))] """ P = self.parent() diff --git a/src/sage/combinat/ncsf_qsym/combinatorics.py b/src/sage/combinat/ncsf_qsym/combinatorics.py index cddfdc1ef2c..cba0de3d45b 100644 --- a/src/sage/combinat/ncsf_qsym/combinatorics.py +++ b/src/sage/combinat/ncsf_qsym/combinatorics.py @@ -255,7 +255,7 @@ def number_of_fCT(content_comp, shape_comp): return 1 else: return 0 - C = Compositions(content_comp.size()-content_comp[-1], outer = list(shape_comp)) + C = Compositions(content_comp.size()-content_comp[-1], outer=list(shape_comp)) s = 0 for x in C: if len(x) >= len(shape_comp)-1: diff --git a/src/sage/combinat/ncsf_qsym/generic_basis_code.py b/src/sage/combinat/ncsf_qsym/generic_basis_code.py index 8763a8e1bee..505b77d42e3 100644 --- a/src/sage/combinat/ncsf_qsym/generic_basis_code.py +++ b/src/sage/combinat/ncsf_qsym/generic_basis_code.py @@ -34,7 +34,7 @@ from sage.combinat.partition import Partition from sage.combinat.permutation import Permutations from sage.rings.integer import Integer -from sage.categories.all import AlgebrasWithBasis +from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.misc.lazy_attribute import lazy_attribute from sage.misc.abstract_method import abstract_method from sage.categories.category_types import Category_over_base_ring @@ -234,7 +234,7 @@ def alternating_sum_of_compositions(self, n): return (-ring.one())**(n)*self.sum_of_terms( (compo, ring((-1)**(len(compo)))) for compo in Compositions(n) ) - def alternating_sum_of_finer_compositions(self, composition, conjugate = False): + def alternating_sum_of_finer_compositions(self, composition, conjugate=False): """ Return the alternating sum of finer compositions in a basis of the non-commutative symmetric functions. @@ -472,8 +472,9 @@ def skew(self, x, y, side='left'): x = self(x) y = self.dual()(y) v = 1 if side == 'left' else 0 - return self.sum(coeff * y[IJ[1-v]] * self[IJ[v]] \ - for (IJ, coeff) in x.coproduct() if IJ[1-v] in y.support()) + return self.sum(coeff * y[IJ[1-v]] * self[IJ[v]] + for (IJ, coeff) in x.coproduct() + if IJ[1-v] in y.support()) else: return self._skew_by_coercion(x, y, side=side) @@ -710,9 +711,9 @@ def duality_pairing_matrix(self, basis, degree): # TODO: generalize to keys indexing the basis of the graded component from sage.combinat.composition import Compositions return matrix(self.base_ring(), - [[self.duality_pairing(self[I], basis[J]) \ - for J in Compositions(degree)] \ - for I in Compositions(degree)]) + [[self.duality_pairing(self[I], basis[J]) + for J in Compositions(degree)] + for I in Compositions(degree)]) def counit_on_basis(self, I): r""" @@ -795,7 +796,7 @@ def degree_negation(self, element): Generalize this to all graded vector spaces? """ - return self.sum_of_terms([ (lam, (-1)**(sum(lam)%2) * a) + return self.sum_of_terms([ (lam, (-1)**(sum(lam) % 2) * a) for lam, a in self(element) ], distinct=True) @@ -839,7 +840,7 @@ def degree_negation(self): Generalize this to all graded vector spaces? """ - return self.parent().sum_of_terms([ (lam, (-1)**(sum(lam)%2) * a) + return self.parent().sum_of_terms([ (lam, (-1)**(sum(lam) % 2) * a) for lam, a in self ], distinct=True) @@ -995,7 +996,7 @@ class AlgebraMorphism(ModuleMorphismByLinearity): # Find a better name A class for algebra morphism defined on a free algebra from the image of the generators """ - def __init__(self, domain, on_generators, position = 0, codomain = None, category = None, anti = False): + def __init__(self, domain, on_generators, position=0, codomain=None, category=None, anti=False): """ Given a map on the multiplicative basis of a free algebra, this method returns the algebra morphism that is the linear extension of its image diff --git a/src/sage/combinat/ncsf_qsym/ncsf.py b/src/sage/combinat/ncsf_qsym/ncsf.py index f1fd9622bae..f9aafb014aa 100644 --- a/src/sage/combinat/ncsf_qsym/ncsf.py +++ b/src/sage/combinat/ncsf_qsym/ncsf.py @@ -2208,7 +2208,7 @@ def to_symmetric_function(self): h[1, 1, 1, 1] - 3*h[2, 1, 1] + 3*h[3, 1] """ codom = self.to_symmetric_function_on_generators(1).parent() - return self.algebra_morphism(self.to_symmetric_function_on_generators, codomain = codom) + return self.algebra_morphism(self.to_symmetric_function_on_generators, codomain=codom) @lazy_attribute def antipode(self): @@ -2232,7 +2232,7 @@ def antipode(self): Generic endomorphism of Non-Commutative Symmetric Functions over the Rational Field in the Complete basis """ if hasattr(self, "antipode_on_generators"): - return self.algebra_morphism(self.antipode_on_generators, codomain = self, anti = True) + return self.algebra_morphism(self.antipode_on_generators, codomain=self, anti=True) else: return NotImplemented @@ -2254,9 +2254,9 @@ def coproduct(self): From: Non-Commutative Symmetric Functions over the Rational Field in the Complete basis To: Non-Commutative Symmetric Functions over the Rational Field in the Complete basis # Non-Commutative Symmetric Functions over the Rational Field in the Complete basis """ - from sage.categories.all import tensor + from sage.categories.tensor import tensor if hasattr(self, "coproduct_on_generators"): - return self.algebra_morphism(self.coproduct_on_generators, codomain = tensor([self, self])) + return self.algebra_morphism(self.coproduct_on_generators, codomain=tensor([self, self])) else: return NotImplemented @@ -2500,7 +2500,7 @@ def coproduct_on_generators(self, i): if i < 1: raise ValueError("Not a positive integer: {}".format(i)) x = self.algebra_generators()[i] - from sage.categories.all import tensor + from sage.categories.tensor import tensor return tensor([self.one(), x]) + tensor([x, self.one()]) class Ribbon(CombinatorialFreeModule, BindableClass): @@ -4521,15 +4521,15 @@ def __init__(self, NCSF): S = NCSF.complete() Psi = NCSF.Psi() to_S = self.module_morphism( - on_basis = self._to_complete_on_basis, - codomain = S, - category = category) + on_basis=self._to_complete_on_basis, + codomain=S, + category=category) to_S.register_as_coercion() from_psi = Psi.module_morphism( - on_basis = self._from_psi_on_basis, - codomain = self, - category = category) + on_basis=self._from_psi_on_basis, + codomain=self, + category=category) from_psi.register_as_coercion() def _to_complete_on_basis(self, I): @@ -4680,15 +4680,15 @@ def __init__(self, NCSF): category = self.category() S = self.realization_of().complete() to_S = self.module_morphism( - on_basis = self._to_complete_on_basis, - codomain = S, - category = category) + on_basis=self._to_complete_on_basis, + codomain=S, + category=category) to_S.register_as_coercion() from_S = S.module_morphism( - on_basis = self._from_complete_on_basis, - codomain = self, - category = category) + on_basis=self._from_complete_on_basis, + codomain=self, + category=category) from_S.register_as_coercion() def _realization_name(self): @@ -4968,15 +4968,15 @@ def __init__(self, NCSF): category = self.category() self._S = self.realization_of().complete() to_S = self.module_morphism( - on_basis = self._to_complete_on_basis, - codomain = self._S, - category = category) + on_basis=self._to_complete_on_basis, + codomain=self._S, + category=category) to_S.register_as_coercion() from_S = self._S.module_morphism( - on_basis = self._from_complete_on_basis, - codomain = self, - category = category) + on_basis=self._from_complete_on_basis, + codomain=self, + category=category) from_S.register_as_coercion() def _realization_name(self): diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index 08633d12c4e..fe4e58277b1 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -561,13 +561,13 @@ def __init__(self, R): self._base = R # Won't be needed once CategoryObject won't override base_ring category = GradedHopfAlgebras(R).Commutative() self._category = category - Parent.__init__(self, category = category.WithRealizations()) + Parent.__init__(self, category=category.WithRealizations()) # Bases - Monomial = self.Monomial() + Monomial = self.Monomial() Fundamental = self.Fundamental() dualImmaculate = self.dualImmaculate() - QS = self.Quasisymmetric_Schur() + QS = self.Quasisymmetric_Schur() # Change of bases Fundamental.module_morphism(Monomial.sum_of_finer_compositions, @@ -578,11 +578,11 @@ def __init__(self, R): ).register_as_coercion() #This changes dualImmaculate into Monomial dualImmaculate.module_morphism(dualImmaculate._to_Monomial_on_basis, - codomain = Monomial, category = category + codomain=Monomial, category=category ).register_as_coercion() #This changes Monomial into dualImmaculate Monomial.module_morphism(dualImmaculate._from_Monomial_on_basis, - codomain = dualImmaculate, category = category + codomain=dualImmaculate, category=category ).register_as_coercion() #This changes Quasisymmetric Schur into Monomial QS .module_morphism(QS._to_monomial_on_basis, @@ -1922,7 +1922,7 @@ def lambda_of_monomial(self, I, n): QQ_result *= (-1) ** n # QQ_result is now \lambda^n(M_I) over QQ. result = self.sum_of_terms([(J, ZZ(coeff)) for (J, coeff) in QQ_result], - distinct = True) + distinct=True) return result class Element(CombinatorialFreeModule.Element): @@ -2052,7 +2052,7 @@ def on_basis(comp, i): return x[i-1]**comp[-1] * on_basis(comp[:-1], i-1) + \ on_basis(comp, i-1) return M._apply_module_morphism(self, lambda comp: on_basis(comp,n), - codomain = P) + codomain=P) def is_symmetric( self ): r""" @@ -3380,11 +3380,11 @@ def __init_extra__(self): category = self.realization_of()._category # This changes Monomial into Hazewinkel Lambda M.module_morphism(self._from_Monomial_on_basis, - codomain = self, category = category + codomain=self, category=category ).register_as_coercion() # This changes Hazewinkel Lambda into Monomial self.module_morphism(self._to_Monomial_on_basis, - codomain = M, category = category + codomain=M, category=category ).register_as_coercion() # cache for the coordinates of the elements @@ -3688,7 +3688,7 @@ def _precompute_M(self, n): M = self.realization_of().M() if l <= n: from sage.misc.cachefunc import cached_function - from sage.arith.all import gcd + from sage.arith.misc import gcd @cached_function def monolambda(I): diff --git a/src/sage/combinat/ncsym/bases.py b/src/sage/combinat/ncsym/bases.py index 25f3bece38e..8b703487547 100644 --- a/src/sage/combinat/ncsym/bases.py +++ b/src/sage/combinat/ncsym/bases.py @@ -18,7 +18,9 @@ from sage.misc.bindable_class import BindableClass from sage.categories.graded_hopf_algebras import GradedHopfAlgebras from sage.categories.realizations import Category_realization_of_parent -from sage.categories.all import ModulesWithBasis, tensor, Hom +from sage.categories.modules_with_basis import ModulesWithBasis +from sage.categories.tensor import tensor +from sage.categories.homset import Hom from sage.combinat.set_partition import SetPartition, SetPartitions from sage.combinat.free_module import CombinatorialFreeModule diff --git a/src/sage/combinat/ncsym/ncsym.py b/src/sage/combinat/ncsym/ncsym.py index 551ca834b1d..64772ade2d7 100644 --- a/src/sage/combinat/ncsym/ncsym.py +++ b/src/sage/combinat/ncsym/ncsym.py @@ -297,7 +297,7 @@ def __init__(self, R): assert(R in Fields() or R in Rings()) # side effect of this statement assures MRO exists for R self._base = R # Won't be needed once CategoryObject won't override base_ring category = GradedHopfAlgebras(R) # TODO: .Cocommutative() - Parent.__init__(self, category = category.WithRealizations()) + Parent.__init__(self, category=category.WithRealizations()) def _repr_(self): r""" diff --git a/src/sage/combinat/necklace.py b/src/sage/combinat/necklace.py index a065cabdd2c..32d345c7e11 100644 --- a/src/sage/combinat/necklace.py +++ b/src/sage/combinat/necklace.py @@ -22,15 +22,15 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.combinat.composition import Composition +from sage.arith.misc import divisors, euler_phi, factorial, gcd from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.combinat.composition import Composition +from sage.combinat.misc import DoublyLinkedList +from sage.misc.misc_c import prod +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.arith.all import euler_phi, factorial, divisors, gcd -from sage.rings.integer_ring import ZZ -from sage.rings.integer import Integer -from sage.misc.misc_c import prod -from sage.combinat.misc import DoublyLinkedList def Necklaces(content): @@ -295,8 +295,7 @@ def _ffc(content, equality=False): if not e[0]: # == 0 dll.hide(0) - for x in _fast_fixed_content(a, e, 2, 1, k, r, 2, dll, equality=equality): - yield x + yield from _fast_fixed_content(a, e, 2, 1, k, r, 2, dll, equality=equality) def _fast_fixed_content(a, content, t, p, k, r, s, dll, equality=False): @@ -347,13 +346,13 @@ def _fast_fixed_content(a, content, t, p, k, r, s, dll, equality=False): sp = t + 1 if j == a[t - p - 1]: - for x in _fast_fixed_content(a[:], content, t + 1, p, - k, r, sp, dll, equality=equality): - yield x + yield from _fast_fixed_content(a[:], content, t + 1, p, + k, r, sp, dll, + equality=equality) else: - for x in _fast_fixed_content(a[:], content, t + 1, t, - k, r, sp, dll, equality=equality): - yield x + yield from _fast_fixed_content(a[:], content, t + 1, t, + k, r, sp, dll, + equality=equality) if not content[j]: # == 0 dll.unhide(j) @@ -392,8 +391,7 @@ def _lfc(content, equality=False): if not content[0]: # == 0 dll.hide(0) - for z in _list_fixed_content(a, content, 2, 1, k, dll, equality=equality): - yield z + yield from _list_fixed_content(a, content, 2, 1, k, dll, equality=equality) def _list_fixed_content(a, content, t, p, k, dll, equality=False): @@ -434,13 +432,11 @@ def _list_fixed_content(a, content, t, p, k, dll, equality=False): dll.hide(j) if j == a[t - p - 1]: - for z in _list_fixed_content(a[:], content[:], t + 1, p, - k, dll, equality=equality): - yield z + yield from _list_fixed_content(a[:], content[:], t + 1, p, + k, dll, equality=equality) else: - for z in _list_fixed_content(a[:], content[:], t + 1, t, - k, dll, equality=equality): - yield z + yield from _list_fixed_content(a[:], content[:], t + 1, t, + k, dll, equality=equality) if not content[j]: # == 0 dll.unhide(j) @@ -519,13 +515,11 @@ def _simple_fixed_content(a, content, t, p, k, equality=False): a[t - 1] = j content[j] -= 1 if j == a[t - p - 1]: - for z in _simple_fixed_content(a[:], content, t + 1, p, - k, equality=equality): - yield z + yield from _simple_fixed_content(a[:], content, t + 1, p, + k, equality=equality) else: - for z in _simple_fixed_content(a[:], content, t + 1, t, - k, equality=equality): - yield z + yield from _simple_fixed_content(a[:], content, t + 1, t, + k, equality=equality) content[j] += 1 diff --git a/src/sage/combinat/non_decreasing_parking_function.py b/src/sage/combinat/non_decreasing_parking_function.py index 9b04286372c..532b4bf8762 100644 --- a/src/sage/combinat/non_decreasing_parking_function.py +++ b/src/sage/combinat/non_decreasing_parking_function.py @@ -419,8 +419,7 @@ def __iter__(self): [[], [1], [1, 1], [1, 2], [1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2, 2]] """ for n in NN: - for pf in NonDecreasingParkingFunctions_n(n): - yield pf + yield from NonDecreasingParkingFunctions_n(n) def graded_component(self, n): """ diff --git a/src/sage/combinat/nu_dyck_word.py b/src/sage/combinat/nu_dyck_word.py index b319f1326fe..efb0af7f572 100644 --- a/src/sage/combinat/nu_dyck_word.py +++ b/src/sage/combinat/nu_dyck_word.py @@ -873,7 +873,7 @@ def plot(self, **kwds): EXAMPLES:: sage: NDW = NuDyckWord('010','010') - sage: NDW.plot() + sage: NDW.plot() # optional - sage.plot Graphics object consisting of 1 graphics primitive """ from sage.plot.plot import list_plot diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index fce1668bd22..0b2fa87e3c7 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -224,7 +224,7 @@ def _auto_parent(cls): .. NOTE:: - It is possible to bypass the automatic parent mechanism using: + It is possible to bypass the automatic parent mechanism using:: sage: t1 = OrderedTree.__new__(OrderedTree, Parent(), []) sage: t1.__init__(Parent(), []) @@ -353,26 +353,27 @@ def to_parallelogram_polyomino(self, bijection=None): INPUT: - - ``bijection`` -- (default:``'Boussicault-Socci'``) is the name of the + - ``bijection`` -- (default: ``'Boussicault-Socci'``) is the name of the bijection to use. Possible values are ``'Boussicault-Socci'``, ``'via dyck and Delest-Viennot'``. EXAMPLES:: sage: T = OrderedTree([[[], [[], [[]]]], [], [[[],[]]], [], []]) - sage: T.to_parallelogram_polyomino( bijection='Boussicault-Socci' ) - [[0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1], [1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0]] + sage: T.to_parallelogram_polyomino(bijection='Boussicault-Socci') # optional - sage.combinat + [[0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1], + [1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0]] sage: T = OrderedTree( [] ) - sage: T.to_parallelogram_polyomino() + sage: T.to_parallelogram_polyomino() # optional - sage.combinat [[1], [1]] sage: T = OrderedTree( [[]] ) - sage: T.to_parallelogram_polyomino() + sage: T.to_parallelogram_polyomino() # optional - sage.combinat [[0, 1], [1, 0]] sage: T = OrderedTree( [[],[]] ) - sage: T.to_parallelogram_polyomino() + sage: T.to_parallelogram_polyomino() # optional - sage.combinat [[0, 1, 1], [1, 1, 0]] sage: T = OrderedTree( [[[]]] ) - sage: T.to_parallelogram_polyomino() + sage: T.to_parallelogram_polyomino() # optional - sage.combinat [[0, 0, 1], [1, 0, 0]] """ if (bijection is None) or (bijection == 'Boussicault-Socci'): @@ -391,19 +392,19 @@ def _to_parallelogram_polyomino_Boussicault_Socci(self): sage: T = OrderedTree( ....: [[[], [[], [[]]]], [], [[[],[]]], [], []] ....: ) - sage: T._to_parallelogram_polyomino_Boussicault_Socci() + sage: T._to_parallelogram_polyomino_Boussicault_Socci() # optional - sage.combinat [[0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1], [1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0]] sage: T = OrderedTree( [] ) - sage: T._to_parallelogram_polyomino_Boussicault_Socci() + sage: T._to_parallelogram_polyomino_Boussicault_Socci() # optional - sage.combinat [[1], [1]] sage: T = OrderedTree( [[]] ) - sage: T._to_parallelogram_polyomino_Boussicault_Socci() + sage: T._to_parallelogram_polyomino_Boussicault_Socci() # optional - sage.combinat [[0, 1], [1, 0]] sage: T = OrderedTree( [[],[]] ) - sage: T._to_parallelogram_polyomino_Boussicault_Socci() + sage: T._to_parallelogram_polyomino_Boussicault_Socci() # optional - sage.combinat [[0, 1, 1], [1, 1, 0]] sage: T = OrderedTree( [[[]]] ) - sage: T._to_parallelogram_polyomino_Boussicault_Socci() + sage: T._to_parallelogram_polyomino_Boussicault_Socci() # optional - sage.combinat [[0, 0, 1], [1, 0, 0]] """ from sage.combinat.parallelogram_polyomino import ParallelogramPolyomino @@ -500,13 +501,13 @@ def to_dyck_word(self): EXAMPLES:: sage: T = OrderedTree([[],[]]) - sage: T.to_dyck_word() + sage: T.to_dyck_word() # optional - sage.combinat [1, 0, 1, 0] sage: T = OrderedTree([[],[[]]]) - sage: T.to_dyck_word() + sage: T.to_dyck_word() # optional - sage.combinat [1, 0, 1, 1, 0, 0] sage: T = OrderedTree([[], [[], []], [[], [[]]]]) - sage: T.to_dyck_word() + sage: T.to_dyck_word() # optional - sage.combinat [1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0] """ word = [] @@ -674,7 +675,7 @@ def plot(self): o o o | o - sage: p.plot() + sage: p.plot() # optional - sage.plot Graphics object consisting of 10 graphics primitives .. PLOT:: @@ -691,7 +692,7 @@ def plot(self): 2 3 5 | 4 - sage: g.plot() + sage: g.plot() # optional - sage.plot Graphics object consisting of 10 graphics primitives .. PLOT:: @@ -1087,22 +1088,23 @@ def random_element(self): EXAMPLES:: - sage: OrderedTrees(5).random_element() # random + sage: OrderedTrees(5).random_element() # random # optional - sage.combinat [[[], []], []] - sage: OrderedTrees(0).random_element() + sage: OrderedTrees(0).random_element() # optional - sage.combinat Traceback (most recent call last): ... - EmptySetError: There are no ordered trees of size 0 - sage: OrderedTrees(1).random_element() + EmptySetError: there are no ordered trees of size 0 + sage: OrderedTrees(1).random_element() # optional - sage.combinat [] TESTS:: - sage: all(OrderedTrees(10).random_element() in OrderedTrees(10) for i in range(20)) + sage: all(OrderedTrees(10).random_element() in OrderedTrees(10) # optional - sage.combinat + ....: for i in range(20)) True """ if self._size == 0: - raise EmptySetError("There are no ordered trees of size 0") + raise EmptySetError("there are no ordered trees of size 0") return CompleteDyckWords_size(self._size - 1).random_element().to_ordered_tree() def __iter__(self): diff --git a/src/sage/combinat/output.py b/src/sage/combinat/output.py index 2e2a8aa5f39..6e9d2943cfd 100644 --- a/src/sage/combinat/output.py +++ b/src/sage/combinat/output.py @@ -169,9 +169,73 @@ def tex_from_array(array, with_lines=True): &&\lr{3}\\ \end{array}$} } + sage: Tableaux.options.convention="russian" + sage: print(tex_from_array([[1,2,3],[4,5]])) + {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{3}c}\cline{1-2} + \lr{\rotatebox{-45}{4}}&\lr{\rotatebox{-45}{5}}\\\cline{1-3} + \lr{\rotatebox{-45}{1}}&\lr{\rotatebox{-45}{2}}&\lr{\rotatebox{-45}{3}}\\\cline{1-3} + \end{array}$}} + } + sage: print(tex_from_array([[1,2,3],[4,5]], with_lines=False)) + {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{3}c}\\ + \lr{\rotatebox{-45}{4}}&\lr{\rotatebox{-45}{5}}\\ + \lr{\rotatebox{-45}{1}}&\lr{\rotatebox{-45}{2}}&\lr{\rotatebox{-45}{3}}\\ + \end{array}$}} + } + sage: print(tex_from_array([[1,2,3],[4,5,6,7],[8]])) + {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{4}c}\cline{1-1} + \lr{\rotatebox{-45}{8}}\\\cline{1-4} + \lr{\rotatebox{-45}{4}}&\lr{\rotatebox{-45}{5}}&\lr{\rotatebox{-45}{6}}&\lr{\rotatebox{-45}{7}}\\\cline{1-4} + \lr{\rotatebox{-45}{1}}&\lr{\rotatebox{-45}{2}}&\lr{\rotatebox{-45}{3}}\\\cline{1-3} + \end{array}$}} + } + sage: print(tex_from_array([[1,2,3],[4,5,6,7],[8]], with_lines=False)) + {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{4}c}\\ + \lr{\rotatebox{-45}{8}}\\ + \lr{\rotatebox{-45}{4}}&\lr{\rotatebox{-45}{5}}&\lr{\rotatebox{-45}{6}}&\lr{\rotatebox{-45}{7}}\\ + \lr{\rotatebox{-45}{1}}&\lr{\rotatebox{-45}{2}}&\lr{\rotatebox{-45}{3}}\\ + \end{array}$}} + } + sage: print(tex_from_array([[None,None,3],[None,5,6,7],[8]])) + {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{4}c}\cline{1-1} + \lr{\rotatebox{-45}{8}}\\\cline{1-4} + &\lr{\rotatebox{-45}{5}}&\lr{\rotatebox{-45}{6}}&\lr{\rotatebox{-45}{7}}\\\cline{2-4} + &&\lr{\rotatebox{-45}{3}}\\\cline{3-3} + \end{array}$}} + } + sage: print(tex_from_array([[None,None,3],[None,5,6,7],[None,8]])) + {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{4}c}\cline{2-2} + &\lr{\rotatebox{-45}{8}}\\\cline{2-4} + &\lr{\rotatebox{-45}{5}}&\lr{\rotatebox{-45}{6}}&\lr{\rotatebox{-45}{7}}\\\cline{2-4} + &&\lr{\rotatebox{-45}{3}}\\\cline{3-3} + \end{array}$}} + } + sage: print(tex_from_array([[None,None,3],[None,5,6,7],[8]], with_lines=False)) + {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{4}c}\\ + \lr{\rotatebox{-45}{8}}\\ + &\lr{\rotatebox{-45}{5}}&\lr{\rotatebox{-45}{6}}&\lr{\rotatebox{-45}{7}}\\ + &&\lr{\rotatebox{-45}{3}}\\ + \end{array}$}} + } + sage: print(tex_from_array([[None,None,3],[None,5,6,7],[None,8]], with_lines=False)) + {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{4}c}\\ + &\lr{\rotatebox{-45}{8}}\\ + &\lr{\rotatebox{-45}{5}}&\lr{\rotatebox{-45}{6}}&\lr{\rotatebox{-45}{7}}\\ + &&\lr{\rotatebox{-45}{3}}\\ + \end{array}$}} + } + sage: Tableaux.options._reset() """ - lr=lr_macro.substitute(bar='|' if with_lines else '') + lr = lr_macro.substitute(bar='|' if with_lines else '') if Tableaux.options.convention == "English": return '{%s\n%s\n}' % (lr, tex_from_skew_array(array, with_lines)) else: @@ -239,15 +303,39 @@ def tex_from_array_tuple(a_tuple, with_lines=True): &\lr{6}&\lr{7}\\ \end{array}$} } + sage: Tableaux.options.convention="russian" + sage: print(tex_from_array_tuple([[[1,2,3],[4,5]],[],[[None,6,7],[None,8],[9]]])) + {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{3}c}\cline{1-2} + \lr{\rotatebox{-45}{4}}&\lr{\rotatebox{-45}{5}}\\\cline{1-3} + \lr{\rotatebox{-45}{1}}&\lr{\rotatebox{-45}{2}}&\lr{\rotatebox{-45}{3}}\\\cline{1-3} + \end{array}$}},\emptyset,\raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{3}c}\cline{1-1} + \lr{\rotatebox{-45}{9}}\\\cline{1-2} + &\lr{\rotatebox{-45}{8}}\\\cline{2-3} + &\lr{\rotatebox{-45}{6}}&\lr{\rotatebox{-45}{7}}\\\cline{2-3} + \end{array}$}} + } + sage: print(tex_from_array_tuple([[[1,2,3],[4,5]],[],[[None,6,7],[None,8],[9]]], with_lines=False)) + {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{3}c}\\ + \lr{\rotatebox{-45}{4}}&\lr{\rotatebox{-45}{5}}\\ + \lr{\rotatebox{-45}{1}}&\lr{\rotatebox{-45}{2}}&\lr{\rotatebox{-45}{3}}\\ + \end{array}$}},\emptyset,\raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{3}c}\\ + \lr{\rotatebox{-45}{9}}\\ + &\lr{\rotatebox{-45}{8}}\\ + &\lr{\rotatebox{-45}{6}}&\lr{\rotatebox{-45}{7}}\\ + \end{array}$}} + } + sage: Tableaux.options._reset() """ - lr=lr_macro.substitute(bar='|' if with_lines else '') + lr = lr_macro.substitute(bar='|' if with_lines else '') if Tableaux.options.convention == "English": return '{%s\n%s\n}' % (lr, ','.join( - r'\emptyset' if comp==[] else tex_from_skew_array(comp, with_lines) for comp in a_tuple)) + r'\emptyset' if comp == [] else tex_from_skew_array(comp, with_lines) for comp in a_tuple)) else: return '{%s\n%s\n}' % (lr, ','.join( - r'\emptyset' if comp==[] else tex_from_skew_array(comp[::-1], with_lines, align='t') for comp in a_tuple)) + r'\emptyset' if comp == [] else tex_from_skew_array(comp[::-1], with_lines, align='t') for comp in a_tuple)) def tex_from_skew_array(array, with_lines=False, align='b'): @@ -294,25 +382,35 @@ def tex_from_skew_array(array, with_lines=False, align='b'): def end_line(r): # in a slightly unpythonic way, we label the lines as 0, 1, ..., len(array) - if r==0: - return r'\cline{%s-%s}'%(nones[0],len(array[0])) - elif r==len(array): - start=nones[r-1] - finish=len(array[r-1]) + if r == 0: + return r'\cline{%s-%s}' % (nones[0], len(array[0])) + elif r == len(array): + start = nones[r-1] + finish = len(array[r-1]) else: - start=min(nones[r], nones[r-1]) - finish=max(len(array[r]), len(array[r-1])) - return r'\\' if start>finish else r'\\\cline{%s-%s}'%(start, finish) + start = min(nones[r], nones[r-1]) + finish = max(len(array[r]), len(array[r-1])) + return r'\\' if start > finish else r'\\\cline{%s-%s}' % (start, finish) else: - end_line=lambda r: r'\\' + end_line = lambda r: r'\\' # now we draw the array - tex=r'\raisebox{-.6ex}{$\begin{array}[%s]{*{%s}c}'%(align,max(map(len,array))) - tex+=end_line(0)+'\n' + raisebox_start = r'\raisebox{-.6ex}{' + raisebox_end = r'}' + lr_start = r'\lr{' + lr_end = r'}' + if Tableaux.options.convention == "Russian": + raisebox_start += r'\rotatebox{45}{' + raisebox_end += r'}' + lr_start += r'\rotatebox{-45}{' + lr_end += r'}' + + tex = r'%s$\begin{array}[%s]{*{%s}c}' % (raisebox_start, align, max(map(len, array))) + tex += end_line(0)+'\n' for r in range(len(array)): - tex+='&'.join('' if c is None else r'\lr{%s}'%(c,) for c in array[r]) - tex+=end_line(r+1)+'\n' - return tex+r'\end{array}$}' + tex += '&'.join('' if c is None else r'%s%s%s' % (lr_start, c, lr_end) for c in array[r]) + tex += end_line(r+1)+'\n' + return tex+r'\end{array}$'+raisebox_end def ascii_art_table(data, use_unicode=False, convention="English"): @@ -367,10 +465,13 @@ def ascii_art_table(data, use_unicode=False, convention="English"): โ”‚ 2 โ”‚ โ””โ”€โ”€โ”€โ”˜ """ + if convention == "Russian": + return ascii_art_table_russian(data, use_unicode) + if use_unicode: import unicodedata - v = unicodedata.lookup('BOX DRAWINGS LIGHT VERTICAL') - h = unicodedata.lookup('BOX DRAWINGS LIGHT HORIZONTAL') + v = unicodedata.lookup('BOX DRAWINGS LIGHT VERTICAL') + h = unicodedata.lookup('BOX DRAWINGS LIGHT HORIZONTAL') dl = unicodedata.lookup('BOX DRAWINGS LIGHT DOWN AND LEFT') dr = unicodedata.lookup('BOX DRAWINGS LIGHT DOWN AND RIGHT') ul = unicodedata.lookup('BOX DRAWINGS LIGHT UP AND LEFT') @@ -388,7 +489,8 @@ def ascii_art_table(data, use_unicode=False, convention="English"): from sage.typeset.ascii_art import ascii_art as art if not data: - return dr + dl + '\n' + ur + ul + # return dr + dl + '\n' + ur + ul + return '' # Convert the input into a rectangular array with the top and bottom row # being all None's for ease later on. @@ -410,17 +512,17 @@ def get_len(e): return 0 return len(e) for row in str_tab: - for i,e in enumerate(row): + for i, e in enumerate(row): col_widths[i] = max(col_widths[i], get_len(e)) matr = [] # just the list of lines - for nrow,row in enumerate(str_tab): - if nrow == 0: # skip the first row + for nrow, row in enumerate(str_tab): + if nrow == 0: # skip the first row continue l1 = "" l2 = "" - for i,(e,w) in enumerate(zip(row, col_widths)): + for i, (e, w) in enumerate(zip(row, col_widths)): prev_row = str_tab[nrow-1] if i == 0: if e is None: @@ -472,7 +574,7 @@ def get_len(e): l1 += vh + h*(2+w) else: if prev_row[i-1] is None and prev_row[i] is None: - l1 += dh + h*(2+w) + l1 += dh + h*(2+w) else: l1 += vh + h*(2+w) l2 += "{} {:^{width}} ".format(v, e, width=w) @@ -507,3 +609,195 @@ def get_len(e): return output.translate(tr) else: return output + + +def ascii_art_table_russian(data, use_unicode=False, compact=False): + r""" + Return an ascii art table of ``data`` for the russian convention. + + EXAMPLES:: + + sage: from sage.combinat.output import ascii_art_table_russian + sage: data = [[None, None, 1], [2, 2], [3,4,5], [None, None, 10], [], [6]] + sage: print(ascii_art_table_russian(data)) + / \ / \ + / \ / \ + \ 6 / \ 10 \ + \ / \ / \ + \ / \ / \ + X 5 / + / \ / + / \ / + / 4 X + / \ / \ / \ + / \ / \ / \ + \ 3 X 2 X 1 / + \ / \ / \ / + \ / \ / \ / + \ 2 / + \ / + \ / + sage: print(ascii_art_table_russian(data, use_unicode=True)) + โ•ฑ โ•ฒ โ•ฑ โ•ฒ + โ•ฑ โ•ฒ โ•ฑ โ•ฒ + โ•ฒ 6 โ•ฑ โ•ฒ 10 โ•ฒ + โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ + โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ + โ•ณ 5 โ•ฑ + โ•ฑ โ•ฒ โ•ฑ + โ•ฑ โ•ฒ โ•ฑ + โ•ฑ 4 โ•ณ + โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ + โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ + โ•ฒ 3 โ•ณ 2 โ•ณ 1 โ•ฑ + โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ + โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ + โ•ฒ 2 โ•ฑ + โ•ฒ โ•ฑ + โ•ฒ โ•ฑ + sage: data = [[1, None, 2], [None, 2]] + sage: print(ascii_art_table_russian(data)) + / \ / \ + \ 2 X 2 / + \ / \ / + X + / \ + \ 1 / + \ / + sage: print(ascii_art_table_russian(data, use_unicode=True)) + โ•ฑ โ•ฒ โ•ฑ โ•ฒ + โ•ฒ 2 โ•ณ 2 โ•ฑ + โ•ฒ โ•ฑ โ•ฒ โ•ฑ + โ•ณ + โ•ฑ โ•ฒ + โ•ฒ 1 โ•ฑ + โ•ฒ โ•ฑ + """ + if use_unicode: + import unicodedata + urdl = unicodedata.lookup('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT') + uldr = unicodedata.lookup('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT') + x = unicodedata.lookup('BOX DRAWINGS LIGHT DIAGONAL CROSS') + else: + urdl = '/' + uldr = '\\' + x = 'X' + + if not data: + # return urdl + uldr + '\n' + uldr + urdl + return '' + + if use_unicode: + # Special handling of overline not adding to printed length + def get_len(e): + if e is None: + return 0 + return len(e) - list(str(e)).count(u"\u0304") + else: + def get_len(e): + if e is None: + return 0 + return len(e) + + # Length of max string (ensure it's odd) + str_tab = [[str(val) if val is not None else None for val in row] for row in data] + max_str = max([max([1] + [get_len(e) for e in row]) for row in str_tab]) + max_str = max_str + 1 - (max_str % 2) + + if compact: + diag_length = max_str + else: + diag_length = max_str + 2 # space on both sides + + row_height = int((diag_length + 1) // 2) + max_height = max(a + len(val) for a, val in enumerate(str_tab)) + str_list = [] + for k in range(max_height, -1, -1): + for i in range(row_height): + if k == max_height and i == 0: + continue + st = ' ' * ((max_height - k) * row_height) + for j in range(k + 1): + N_box = box_exists(str_tab, k-j+1, j) + S_box = box_exists(str_tab, k-j, j-1) + SE_box = box_exists(str_tab, k-j-1, j) + E_box = box_exists(str_tab, k-j, j) + W_box = box_exists(str_tab, k-j+1, j-1) + if i == 0: + if (N_box and S_box) or (W_box and E_box): + st += x + elif (E_box and S_box) or (W_box and N_box): + st += urdl + elif (E_box and N_box) or (W_box and S_box): + st += uldr + elif E_box: + st += uldr + elif W_box: + st += urdl + else: + st += ' ' + if E_box: + st_num = str_tab[k-j][j] + ln_left = int((len(st_num) - (len(st_num) % 2))/2) + st += st_num.rjust(row_height - 1 - ln_left + len(st_num), ' ').ljust(diag_length, ' ') + else: + st += ' ' * diag_length + if j == k and E_box: + st += urdl + else: + lstr = ' ' + rstr = ' ' + if E_box or S_box: + lstr = uldr + if E_box or SE_box: + rstr = urdl + st += ' ' * i + st += lstr + st += ' ' * (2 * (row_height - i) - 1) + st += rstr + st += ' ' * (i-1) + str_list.append(st) + + import re + mm = min(len(re.search('^ +', l)[0]) for l in str_list) - 1 + str_list = [l[mm:].rstrip() for l in str_list] + while str_list[-1] == '': + str_list.pop() + return "\n".join(str_list) + + +def box_exists(tab, i, j): + r""" + Return ``True`` if ``tab[i][j]`` exists and is not ``None``; in particular this + allows for `tab[i][j]` to be ``''`` or ``0``. + + INPUT: + + - ``tab`` -- a list of lists + - ``i`` -- first coordinate + - ``j`` -- second coordinate + + TESTS:: + + sage: from sage.combinat.output import box_exists + sage: tab = [[1,None,'', 0],[None]] + sage: box_exists(tab, 0, 0) + True + sage: box_exists(tab, 0, 1) + False + sage: box_exists(tab, 0, 2) + True + sage: box_exists(tab, 0, 3) + True + sage: box_exists(tab, 0, 4) + False + sage: box_exists(tab, 1, 0) + False + sage: box_exists(tab, 1, 1) + False + sage: box_exists(tab, 0, -1) + False + """ + if j < 0 or i < 0: + return False + return len(tab) > i and len(tab[i]) > j and tab[i][j] is not None diff --git a/src/sage/combinat/parallelogram_polyomino.py b/src/sage/combinat/parallelogram_polyomino.py index 40ab068f205..9c4ceedfd19 100644 --- a/src/sage/combinat/parallelogram_polyomino.py +++ b/src/sage/combinat/parallelogram_polyomino.py @@ -1024,44 +1024,44 @@ def check(self): sage: pp = ParallelogramPolyomino([[0, 1], [1, 0]]) sage: pp = ParallelogramPolyomino([[1], [1]]) - sage: pp = ParallelogramPolyomino( + sage: pp = ParallelogramPolyomino( # indirect doctest ....: [[1, 0], [0, 1]] - ....: ) # indirect doctest + ....: ) Traceback (most recent call last): ... ValueError: the lower and upper paths are crossing - sage: pp = ParallelogramPolyomino([[1], [0, 1]]) # indirect doctest + sage: pp = ParallelogramPolyomino([[1], [0, 1]]) # indirect doctest Traceback (most recent call last): ... ValueError: the lower and upper paths have different sizes (2 != 1) - sage: pp = ParallelogramPolyomino([[1], [0]]) # indirect doctest + sage: pp = ParallelogramPolyomino([[1], [0]]) # indirect doctest Traceback (most recent call last): ... ValueError: the two paths have distinct ends - sage: pp = ParallelogramPolyomino([[0], [1]]) # indirect doctest + sage: pp = ParallelogramPolyomino([[0], [1]]) # indirect doctest Traceback (most recent call last): ... ValueError: the two paths have distinct ends - sage: pp = ParallelogramPolyomino([[0], [0]]) # indirect doctest + sage: pp = ParallelogramPolyomino([[0], [0]]) # indirect doctest Traceback (most recent call last): ... ValueError: the lower or the upper path can...t be equal to [0] - sage: pp = ParallelogramPolyomino([[], [0]]) # indirect doctest + sage: pp = ParallelogramPolyomino([[], [0]]) # indirect doctest Traceback (most recent call last): ... ValueError: the lower or the upper path can...t be equal to [] - sage: pp = ParallelogramPolyomino([[0], []]) # indirect doctest + sage: pp = ParallelogramPolyomino([[0], []]) # indirect doctest Traceback (most recent call last): ... ValueError: the lower or the upper path can...t be equal to [] - sage: pp = ParallelogramPolyomino([[], []]) # indirect doctest + sage: pp = ParallelogramPolyomino([[], []]) # indirect doctest Traceback (most recent call last): ... ValueError: the lower or the upper path can...t be equal to [] @@ -1173,7 +1173,7 @@ def __init__(self, parent, value, check=True): if check: if not isinstance(value, (list, tuple)): raise ValueError( - "Value %s must be a list or a tuple." % value) + "value %s must be a list or a tuple" % value) self.check() self._options = None @@ -1330,7 +1330,7 @@ def to_dyck_word(self, bijection=None): return self._to_dyck_delest_viennot() if bijection == 'Delest-Viennot-beta': return self._to_dyck_delest_viennot_peaks_valleys() - raise ValueError("The given bijection is not valid.") + raise ValueError("the given bijection is not valid") @staticmethod def _from_dyck_word_delest_viennot(dyck): @@ -1457,7 +1457,7 @@ def from_dyck_word(dyck, bijection=None): return ParallelogramPolyomino._from_dyck_word_delest_viennot(dyck) if bijection == 'Delest-Viennot-beta': return ParallelogramPolyomino._from_dyck_word_delest_viennot_peaks_valleys(dyck) - raise ValueError("The given bijection is not valid.") + raise ValueError("the given bijection is not valid") def _to_binary_tree_Aval_Boussicault(self, position=None): r""" @@ -2652,7 +2652,7 @@ def area(self): sage: pp.area() 0 """ - return sum(h for h in self.heights()) + return sum(self.heights()) def _repr_(self) -> str: r""" @@ -3703,14 +3703,14 @@ def _plot_diagram(self): sage: pp = ParallelogramPolyomino( ....: [[0, 1, 1, 1, 1], [1, 1, 1, 1, 0]] ....: ) - sage: pp._plot_diagram() + sage: pp._plot_diagram() # optional - sage.plot Graphics object consisting of 7 graphics primitives sage: pp = ParallelogramPolyomino([ ....: [0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1], ....: [1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0] ....: ]) - sage: pp._plot_diagram() + sage: pp._plot_diagram() # optional - sage.plot Graphics object consisting of 25 graphics primitives """ G = Graphics() @@ -3755,14 +3755,14 @@ def _plot_bounce(self, directions=None): sage: pp = ParallelogramPolyomino( ....: [[0, 1, 1, 1, 1], [1, 1, 1, 1, 0]] ....: ) - sage: pp._plot_bounce(directions=[1]) + sage: pp._plot_bounce(directions=[1]) # optional - sage.plot Graphics object consisting of 1 graphics primitive sage: pp = ParallelogramPolyomino([ ....: [0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1], ....: [1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0] ....: ]) - sage: pp._plot_bounce(directions=[0,1]) + sage: pp._plot_bounce(directions=[0,1]) # optional - sage.plot Graphics object consisting of 9 graphics primitives """ @@ -3798,14 +3798,14 @@ def _plot_bounce_values(self, bounce=0): sage: pp = ParallelogramPolyomino( ....: [[0, 1, 1, 1, 1], [1, 1, 1, 1, 0]] ....: ) - sage: pp._plot_bounce_values() + sage: pp._plot_bounce_values() # optional - sage.plot Graphics object consisting of 4 graphics primitives sage: pp = ParallelogramPolyomino([ ....: [0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1], ....: [1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0] ....: ]) - sage: pp._plot_bounce_values(bounce=1) + sage: pp._plot_bounce_values(bounce=1) # optional - sage.plot Graphics object consisting of 10 graphics primitives """ G = Graphics() @@ -3847,14 +3847,14 @@ def _plot_tree(self): sage: pp = ParallelogramPolyomino( ....: [[0, 1, 1, 1, 1], [1, 1, 1, 1, 0]] ....: ) - sage: pp._plot_tree() + sage: pp._plot_tree() # optional - sage.plot Graphics object consisting of 2 graphics primitives sage: pp = ParallelogramPolyomino([ ....: [0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1], ....: [1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0] ....: ]) - sage: pp._plot_tree() + sage: pp._plot_tree() # optional - sage.plot Graphics object consisting of 2 graphics primitives """ G = Graphics() @@ -3869,17 +3869,17 @@ def plot(self): EXAMPLES:: sage: pp = ParallelogramPolyomino([[0,1],[1,0]]) - sage: pp.plot() + sage: pp.plot() # optional - sage.plot Graphics object consisting of 4 graphics primitives sage: pp.set_options( ....: drawing_components=dict( - ....: diagram = True - ....: , bounce_0 = True - ....: , bounce_1 = True - ....: , bounce_values = 0 + ....: diagram=True, + ....: bounce_0=True, + ....: bounce_1=True, + ....: bounce_values=0, ....: ) ....: ) - sage: pp.plot() + sage: pp.plot() # optional - sage.plot Graphics object consisting of 7 graphics primitives """ G = Graphics() @@ -4045,8 +4045,8 @@ def __call__(self, size=None, policy=None): return ParallelogramPolyominoes_size(size, policy) if size is None: return ParallelogramPolyominoes_all(policy) - raise ValueError("Invalid argument for Parallelogram Polyominoes " - "Factory.") + raise ValueError("invalid argument for Parallelogram Polyominoes " + "Factory") @lazy_attribute def _default_policy(self): @@ -4149,9 +4149,9 @@ def check_element(self, el, check): EXAMPLES:: sage: PPS = ParallelogramPolyominoes(3) - sage: ParallelogramPolyomino( + sage: ParallelogramPolyomino( # indirect doctest ....: [[0, 1, 1], [1, 1, 0]] - ....: ) in PPS # indirect doctest + ....: ) in PPS True """ if el.size() != self.size(): @@ -4322,9 +4322,9 @@ def check_element(self, el, check): EXAMPLES:: sage: PPS = ParallelogramPolyominoes() - sage: ParallelogramPolyomino( + sage: ParallelogramPolyomino( # indirect doctest ....: [[0, 1, 1], [1, 1, 0]] - ....: ) in PPS # indirect doctest + ....: ) in PPS True """ pass diff --git a/src/sage/combinat/parking_functions.py b/src/sage/combinat/parking_functions.py index bd67b573238..d356cedb2b7 100644 --- a/src/sage/combinat/parking_functions.py +++ b/src/sage/combinat/parking_functions.py @@ -222,11 +222,17 @@ def __init__(self, parent, lst): <class 'sage.combinat.parking_functions.ParkingFunctions_n_with_category.element_class'> sage: type(b) <class 'sage.combinat.parking_functions.ParkingFunctions_n_with_category.element_class'> + + Some checks for more general inputs:: + + sage: PF = ParkingFunction((1, 1, 2, 2, 5, 6)) + sage: PF = ParkingFunction(Permutation([4,2,3,1])) """ - if isinstance(lst, ParkingFunction): - lst = list(lst) if not isinstance(lst, list): - raise TypeError('input must be a list') + try: + lst = list(lst) + except TypeError: + raise TypeError('input must be convertible to a list') if parent is None: parent = ParkingFunctions_n(len(lst)) ClonableArray.__init__(self, parent, lst) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index cf1b0c2aee9..3c5535c88c1 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -283,10 +283,9 @@ from copy import copy from itertools import accumulate +from sage.arith.misc import binomial, factorial, gcd, multinomial from sage.libs.pari.all import pari from sage.libs.flint.arith import number_of_partitions as flint_number_of_partitions - -from sage.arith.misc import multinomial from sage.structure.global_options import GlobalOptions from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -308,7 +307,6 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.semirings.non_negative_integer_semiring import NN -from sage.arith.all import factorial, gcd from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer from sage.rings.infinity import infinity @@ -326,7 +324,6 @@ from sage.combinat.combinatorial_map import combinatorial_map from sage.groups.perm_gps.permgroup import PermutationGroup from sage.graphs.dot2tex_utils import have_dot2tex -from sage.arith.all import binomial class Partition(CombinatorialElement): @@ -717,7 +714,7 @@ def _repr_exp_low(self): if not self._list: return '-' exp = self.to_exp() - return '%s' % ', '.join('%s%s' % (m+1, '' if e==1 else '^%s'%e) + return '%s' % ', '.join('%s%s' % (m+1, '' if e == 1 else '^%s' % e) for (m,e) in enumerate(exp) if e > 0) def _repr_exp_high(self): @@ -755,7 +752,7 @@ def _repr_compact_low(self): if not self._list: return '-' exp = self.to_exp() - return '%s' % ','.join('%s%s' % (m+1, '' if e==1 else '^%s'%e) + return '%s' % ','.join('%s%s' % (m+1, '' if e == 1 else '^%s' % e) for (m,e) in enumerate(exp) if e > 0) def _repr_compact_high(self): @@ -773,9 +770,9 @@ def _repr_compact_high(self): if not self._list: return '-' exp = self.to_exp()[::-1] # reversed list of exponents - M=max(self) - return '%s' % ','.join('%s%s' % (M-m, '' if e==1 else '^%s'%e) - for (m,e) in enumerate(exp) if e>0) + M = max(self) + return '%s' % ','.join('%s%s' % (M-m, '' if e == 1 else '^%s' % e) + for (m,e) in enumerate(exp) if e > 0) def _repr_diagram(self): r""" @@ -949,7 +946,7 @@ def _latex_exp_low(self): if not self._list: return "{\\emptyset}" exp = self.to_exp() - return '%s' % ','.join('%s%s' % (m+1, '' if e==1 else '^{%s}'%e) + return '%s' % ','.join('%s%s' % (m+1, '' if e == 1 else '^{%s}' % e) for (m,e) in enumerate(exp) if e > 0) def _latex_exp_high(self): @@ -967,8 +964,8 @@ def _latex_exp_high(self): return "{\\emptyset}" exp = self.to_exp()[::-1] # reversed list of exponents M = max(self) - return '%s' % ','.join('%s%s' % (M-m, '' if e==1 else '^{%s}'%e) - for (m,e) in enumerate(exp) if e>0) + return '%s' % ','.join('%s%s' % (M-m, '' if e == 1 else '^{%s}' % e) + for (m,e) in enumerate(exp) if e > 0) def ferrers_diagram(self): r""" @@ -1091,15 +1088,14 @@ def power(self, k): Now let us compare this to the power map on `S_8`:: - sage: G = SymmetricGroup(8) - sage: g = G([(1,2,3,4,5),(6,7,8)]) - sage: g + sage: G = SymmetricGroup(8) # optional - sage.groups + sage: g = G([(1,2,3,4,5),(6,7,8)]); g # optional - sage.groups (1,2,3,4,5)(6,7,8) - sage: g^2 + sage: g^2 # optional - sage.groups (1,3,5,2,4)(6,8,7) - sage: g^3 + sage: g^3 # optional - sage.groups (1,4,2,5,3) - sage: g^4 + sage: g^4 # optional - sage.groups (1,5,4,3,2)(6,7,8) :: @@ -1218,10 +1214,10 @@ def sign(self): :: - sage: F = GF(11) - sage: a = F.multiplicative_generator();a + sage: F = GF(11) # optional - sage.rings.finite_rings + sage: a = F.multiplicative_generator();a # optional - sage.rings.finite_rings 2 - sage: plist = [int(a*F(x)) for x in range(1,11)]; plist + sage: plist = [int(a*F(x)) for x in range(1,11)]; plist # optional - sage.rings.finite_rings [2, 4, 6, 8, 10, 1, 3, 5, 7, 9] This corresponds to the permutation (1, 2, 4, 8, 5, 10, 9, 7, 3, 6) @@ -1230,8 +1226,8 @@ def sign(self): :: - sage: p = PermutationGroupElement('(1, 2, 4, 8, 5, 10, 9, 7, 3, 6)') - sage: p.sign() + sage: p = PermutationGroupElement('(1, 2, 4, 8, 5, 10, 9, 7, 3, 6)') # optional - sage.groups + sage: p.sign() # optional - sage.groups -1 sage: Partition([10]).sign() -1 @@ -1240,12 +1236,12 @@ def sign(self): Now replace `2` by `3`:: - sage: plist = [int(F(3*x)) for x in range(1,11)]; plist + sage: plist = [int(F(3*x)) for x in range(1,11)]; plist # optional - sage.rings.finite_rings [3, 6, 9, 1, 4, 7, 10, 2, 5, 8] sage: list(range(1, 11)) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - sage: p = PermutationGroupElement('(3,4,8,7,9)') - sage: p.sign() + sage: p = PermutationGroupElement('(3,4,8,7,9)') # optional - sage.groups + sage: p.sign() # optional - sage.groups 1 sage: kronecker_symbol(3,11) 1 @@ -1888,55 +1884,55 @@ def cell_poset(self, orientation="SE"): EXAMPLES:: sage: p = Partition([3,3,1]) - sage: Q = p.cell_poset(); Q + sage: Q = p.cell_poset(); Q # optional - sage.graphs Finite poset containing 7 elements - sage: sorted(Q) + sage: sorted(Q) # optional - sage.graphs [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0)] - sage: sorted(Q.maximal_elements()) + sage: sorted(Q.maximal_elements()) # optional - sage.graphs [(1, 2), (2, 0)] - sage: Q.minimal_elements() + sage: Q.minimal_elements() # optional - sage.graphs [(0, 0)] - sage: sorted(Q.upper_covers((1, 0))) + sage: sorted(Q.upper_covers((1, 0))) # optional - sage.graphs [(1, 1), (2, 0)] - sage: Q.upper_covers((1, 1)) + sage: Q.upper_covers((1, 1)) # optional - sage.graphs [(1, 2)] - sage: P = p.cell_poset(orientation="NW"); P + sage: P = p.cell_poset(orientation="NW"); P # optional - sage.graphs Finite poset containing 7 elements - sage: sorted(P) + sage: sorted(P) # optional - sage.graphs [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0)] - sage: sorted(P.minimal_elements()) + sage: sorted(P.minimal_elements()) # optional - sage.graphs [(1, 2), (2, 0)] - sage: P.maximal_elements() + sage: P.maximal_elements() # optional - sage.graphs [(0, 0)] - sage: P.upper_covers((2, 0)) + sage: P.upper_covers((2, 0)) # optional - sage.graphs [(1, 0)] - sage: sorted(P.upper_covers((1, 2))) + sage: sorted(P.upper_covers((1, 2))) # optional - sage.graphs [(0, 2), (1, 1)] - sage: sorted(P.upper_covers((1, 1))) + sage: sorted(P.upper_covers((1, 1))) # optional - sage.graphs [(0, 1), (1, 0)] - sage: sorted([len(P.upper_covers(v)) for v in P]) + sage: sorted([len(P.upper_covers(v)) for v in P]) # optional - sage.graphs [0, 1, 1, 1, 1, 2, 2] - sage: R = p.cell_poset(orientation="NE"); R + sage: R = p.cell_poset(orientation="NE"); R # optional - sage.graphs Finite poset containing 7 elements - sage: sorted(R) + sage: sorted(R) # optional - sage.graphs [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0)] - sage: R.maximal_elements() + sage: R.maximal_elements() # optional - sage.graphs [(0, 2)] - sage: R.minimal_elements() + sage: R.minimal_elements() # optional - sage.graphs [(2, 0)] - sage: sorted([len(R.upper_covers(v)) for v in R]) + sage: sorted([len(R.upper_covers(v)) for v in R]) # optional - sage.graphs [0, 1, 1, 1, 1, 2, 2] - sage: R.is_isomorphic(P) + sage: R.is_isomorphic(P) # optional - sage.graphs False - sage: R.is_isomorphic(P.dual()) + sage: R.is_isomorphic(P.dual()) # optional - sage.graphs False Linear extensions of ``p.cell_poset()`` are in 1-to-1 correspondence with standard Young tableaux of shape `p`:: - sage: all( len(p.cell_poset().linear_extensions()) + sage: all( len(p.cell_poset().linear_extensions()) # optional - sage.graphs ....: == len(p.standard_tableaux()) ....: for n in range(8) for p in Partitions(n) ) True @@ -1944,7 +1940,7 @@ def cell_poset(self, orientation="SE"): This is not the case for northeast orientation:: sage: q = Partition([3, 1]) - sage: q.cell_poset(orientation="NE").is_chain() + sage: q.cell_poset(orientation="NE").is_chain() # optional - sage.graphs True TESTS: @@ -1961,7 +1957,7 @@ def cell_poset(self, orientation="SE"): ....: and c[1] >= d[1]): ....: return False ....: return True - sage: all( check_NW(n) for n in range(8) ) + sage: all( check_NW(n) for n in range(8) ) # optional - sage.graphs True sage: def check_NE(n): @@ -1973,7 +1969,7 @@ def cell_poset(self, orientation="SE"): ....: and c[1] <= d[1]): ....: return False ....: return True - sage: all( check_NE(n) for n in range(8) ) + sage: all( check_NE(n) for n in range(8) ) # optional - sage.graphs True sage: def test_duality(n, ori1, ori2): @@ -1985,11 +1981,11 @@ def cell_poset(self, orientation="SE"): ....: if P.lt(c, d) != Q.lt(d, c): ....: return False ....: return True - sage: all( test_duality(n, "NW", "SE") for n in range(8) ) + sage: all( test_duality(n, "NW", "SE") for n in range(8) ) # optional - sage.graphs True - sage: all( test_duality(n, "NE", "SW") for n in range(8) ) + sage: all( test_duality(n, "NE", "SW") for n in range(8) ) # optional - sage.graphs True - sage: all( test_duality(n, "NE", "SE") for n in range(4) ) + sage: all( test_duality(n, "NE", "SE") for n in range(4) ) # optional - sage.graphs False """ from sage.combinat.posets.posets import Poset @@ -2072,11 +2068,11 @@ def frobenius_coordinates(self): mu = self muconj = mu.conjugate() # Naive implementation if len(mu) <= len(muconj): - a = [x for x in (val-i-1 for i, val in enumerate(mu)) if x>=0] - b = [x for x in (muconj[i]-i-1 for i in range(len(a))) if x>=0] + a = [x for x in (val-i-1 for i, val in enumerate(mu)) if x >= 0] + b = [x for x in (muconj[i]-i-1 for i in range(len(a))) if x >= 0] else: - b = [x for x in (val-i-1 for i, val in enumerate(muconj)) if x>=0] - a = [x for x in (mu[i]-i-1 for i in range(len(b))) if x>=0] + b = [x for x in (val-i-1 for i, val in enumerate(muconj)) if x >= 0] + a = [x for x in (mu[i]-i-1 for i in range(len(b))) if x >= 0] return (a,b) def frobenius_rank(self): @@ -2746,11 +2742,11 @@ def garnir_tableau(self, *cell): if row + 1 >= len(self) or col >= self[row+1]: raise ValueError('(row+1, col) must be inside the diagram') - g=self.initial_tableau().to_list() - a=g[row][col] + g = self.initial_tableau().to_list() + a = g[row][col] g[row][col:] = list(range(a+col+1,g[row+1][col]+1)) g[row+1][:col+1] = list(range(a,a+col+1)) - g=tableau.Tableau(g) + g = tableau.Tableau(g) g._garnir_cell = (row, col) return g @@ -2812,26 +2808,26 @@ def top_garnir_tableau(self,e,cell): - [KMR2012]_ """ - (row,col)=cell - if row+1>=len(self) or col>=self[row+1]: - raise ValueError('(%s,%s)=(row+1,col) must be inside the diagram' %(row+1,col)) + (row,col) = cell + if row+1 >= len(self) or col >= self[row+1]: + raise ValueError('(%s,%s)=(row+1,col) must be inside the diagram' % (row+1,col)) - g=self.garnir_tableau(cell) # start with the Garnir tableau and modify + g = self.garnir_tableau(cell) # start with the Garnir tableau and modify - if e==0: + if e == 0: return g # no more dominant tableau of the same residue - a=e*int((self[row]-col)/e) # number of cells in the e-bricks in row `row` - b=e*int((col+1)/e) # number of cells in the e-bricks in row `row+1` + a = e*int((self[row]-col)/e) # number of cells in the e-bricks in row `row` + b = e*int((col+1)/e) # number of cells in the e-bricks in row `row+1` - if a==0 or b==0: + if a == 0 or b == 0: return g - t=g.to_list() - m=g[row+1][0] # smallest number in 0-Garnir belt + t = g.to_list() + m = g[row+1][0] # smallest number in 0-Garnir belt # now we will put the number m,m+1,...,t[row+1][col] in order into t - t[row][col:a+col]=[m+col-b+1+i for i in range(a)] - t[row+1][col-b+1:col+1]=[m+a+col-b+1+i for i in range(b)] + t[row][col:a+col] = [m+col-b+1+i for i in range(a)] + t[row+1][col-b+1:col+1] = [m+a+col-b+1+i for i in range(b)] return tableau.StandardTableau(t) @cached_method @@ -2856,14 +2852,14 @@ def young_subgroup(self): EXAMPLES:: - sage: Partition([4,2]).young_subgroup() + sage: Partition([4,2]).young_subgroup() # optional - sage.groups Permutation Group with generators [(), (5,6), (3,4), (2,3), (1,2)] """ - gens=[] - m=0 + gens = [] + m = 0 for row in self: gens.extend([ (c,c+1) for c in range(m+1,m+row)]) - m+=row + m += row gens.append(list(range(1,self.size() + 1))) # to ensure we get a subgroup of Sym_n return PermutationGroup( gens ) @@ -3282,9 +3278,9 @@ def hook_product(self, a): EXAMPLES:: - sage: Partition([3,2,1]).hook_product(x) + sage: Partition([3,2,1]).hook_product(x) # optional - sage.symbolic (2*x + 3)*(x + 2)^2 - sage: Partition([2,2]).hook_product(x) + sage: Partition([2,2]).hook_product(x) # optional - sage.symbolic 2*(x + 2)*(x + 1) """ @@ -3425,7 +3421,7 @@ def upper_hook(self, i, j, alpha): 3 sage: p.hook_length(0,0) 3 - sage: [ p.upper_hook(i,j,x) for i,j in p.cells() ] + sage: [ p.upper_hook(i,j,x) for i,j in p.cells() ] # optional - sage.symbolic [2*x + 1, x, x] """ p = self @@ -3447,7 +3443,7 @@ def upper_hook_lengths(self, alpha): EXAMPLES:: - sage: Partition([3,2,1]).upper_hook_lengths(x) + sage: Partition([3,2,1]).upper_hook_lengths(x) # optional - sage.symbolic [[3*x + 2, 2*x + 1, x], [2*x + 1, x], [x]] sage: Partition([3,2,1]).upper_hook_lengths(1) [[5, 3, 1], [3, 1], [1]] @@ -3477,7 +3473,7 @@ def lower_hook(self, i, j, alpha): 3 sage: p.hook_length(0,0) 3 - sage: [ p.lower_hook(i,j,x) for i,j in p.cells() ] + sage: [ p.lower_hook(i,j,x) for i,j in p.cells() ] # optional - sage.symbolic [x + 2, 1, 1] """ p = self @@ -3499,7 +3495,7 @@ def lower_hook_lengths(self, alpha): EXAMPLES:: - sage: Partition([3,2,1]).lower_hook_lengths(x) + sage: Partition([3,2,1]).lower_hook_lengths(x) # optional - sage.symbolic [[2*x + 3, x + 2, 1], [x + 2, 1], [1]] sage: Partition([3,2,1]).lower_hook_lengths(1) [[5, 3, 1], [3, 1], [1]] @@ -4406,7 +4402,7 @@ def k_boundary(self, k): """ return SkewPartition([self, self.k_interior(k)]) - def add_cell(self, i, j = None): + def add_cell(self, i, j=None): r""" Return a partition corresponding to ``self`` with a cell added in row ``i``. (This does not change ``self``.) @@ -4608,9 +4604,9 @@ def from_kbounded_to_reduced_word(self, k): result = [] while not p.is_empty(): corners = p.corners() - c = p.content(corners[0][0],corners[0][1])%(k+1) + c = p.content(corners[0][0],corners[0][1]) % (k+1) result.append(Integer(c)) - list = [x for x in corners if p.content(x[0],x[1])%(k+1) ==c] + list = [x for x in corners if p.content(x[0],x[1]) % (k+1) == c] for x in list: p = p.remove_cell(x[0]) return result @@ -4626,12 +4622,12 @@ def from_kbounded_to_grassmannian(self, k): EXAMPLES:: sage: p = Partition([2,1,1]) - sage: p.from_kbounded_to_grassmannian(2) + sage: p.from_kbounded_to_grassmannian(2) # optional - sage.modules [-1 1 1] [-2 2 1] [-2 1 2] sage: p = Partition([]) - sage: p.from_kbounded_to_grassmannian(2) + sage: p.from_kbounded_to_grassmannian(2) # optional - sage.modules [1 0 0] [0 1 0] [0 0 1] @@ -5072,15 +5068,15 @@ def jacobi_trudi(self): EXAMPLES:: sage: part = Partition([3,2,1]) - sage: jt = part.jacobi_trudi(); jt + sage: jt = part.jacobi_trudi(); jt # optional - sage.modules [h[3] h[1] 0] [h[4] h[2] h[]] [h[5] h[3] h[1]] - sage: s = SymmetricFunctions(QQ).schur() - sage: h = SymmetricFunctions(QQ).homogeneous() - sage: h( s(part) ) + sage: s = SymmetricFunctions(QQ).schur() # optional - sage.modules + sage: h = SymmetricFunctions(QQ).homogeneous() # optional - sage.modules + sage: h( s(part) ) # optional - sage.modules h[3, 2, 1] - h[3, 3] - h[4, 1, 1] + h[5, 1] - sage: jt.det() + sage: jt.det() # optional - sage.modules h[3, 2, 1] - h[3, 3] - h[4, 1, 1] + h[5, 1] """ return SkewPartition([ self, [] ]).jacobi_trudi() @@ -5111,11 +5107,11 @@ def character_polynomial(self): EXAMPLES:: - sage: Partition([1]).character_polynomial() + sage: Partition([1]).character_polynomial() # optional - sage.modules x - 1 - sage: Partition([1,1]).character_polynomial() + sage: Partition([1,1]).character_polynomial() # optional - sage.modules 1/2*x0^2 - 3/2*x0 - x1 + 1 - sage: Partition([2,1]).character_polynomial() + sage: Partition([2,1]).character_polynomial() # optional - sage.modules 1/3*x0^3 - 2*x0^2 + 8/3*x0 - x2 """ # Create the polynomial ring we will use @@ -5313,22 +5309,23 @@ def outline(self, variable=None): EXAMPLES:: - sage: [Partition([5,4]).outline()(x=i) for i in range(-10,11)] + sage: [Partition([5,4]).outline()(x=i) for i in range(-10,11)] # optional - sage.symbolic [10, 9, 8, 7, 6, 5, 6, 5, 6, 5, 4, 3, 2, 3, 4, 5, 6, 7, 8, 9, 10] - sage: Partition([]).outline() + sage: Partition([]).outline() # optional - sage.symbolic abs(x) - sage: Partition([1]).outline() + sage: Partition([1]).outline() # optional - sage.symbolic abs(x + 1) + abs(x - 1) - abs(x) - sage: y = SR.var("y") - sage: Partition([6,5,1]).outline(variable=y) - abs(y + 6) - abs(y + 5) + abs(y + 4) - abs(y + 3) + abs(y - 1) - abs(y - 2) + abs(y - 3) + sage: y = SR.var("y") # optional - sage.symbolic + sage: Partition([6,5,1]).outline(variable=y) # optional - sage.symbolic + abs(y + 6) - abs(y + 5) + abs(y + 4) - abs(y + 3) + + abs(y - 1) - abs(y - 2) + abs(y - 3) TESTS:: - sage: integrate(Partition([1]).outline()-abs(x),(x,-10,10)) + sage: integrate(Partition([1]).outline()-abs(x),(x,-10,10)) # optional - sage.symbolic 2 """ if variable is None: @@ -5336,7 +5333,7 @@ def outline(self, variable=None): outside_contents = [self.content(*c) for c in self.outside_corners()] inside_contents = [self.content(*c) for c in self.corners()] return sum(abs(variable+c) for c in outside_contents)\ - -sum(abs(variable+c) for c in inside_contents) + - sum(abs(variable+c) for c in inside_contents) def dual_equivalence_graph(self, directed=False, coloring=None): r""" @@ -5392,16 +5389,16 @@ def dual_equivalence_graph(self, directed=False, coloring=None): EXAMPLES:: sage: P = Partition([3,1,1]) - sage: G = P.dual_equivalence_graph() - sage: G.edges(sort=True) + sage: G = P.dual_equivalence_graph() # optional - sage.graphs + sage: G.edges(sort=True) # optional - sage.graphs [([[1, 2, 3], [4], [5]], [[1, 2, 4], [3], [5]], 3), ([[1, 2, 4], [3], [5]], [[1, 2, 5], [3], [4]], 4), ([[1, 2, 4], [3], [5]], [[1, 3, 4], [2], [5]], 2), ([[1, 2, 5], [3], [4]], [[1, 3, 5], [2], [4]], 2), ([[1, 3, 4], [2], [5]], [[1, 3, 5], [2], [4]], 4), ([[1, 3, 5], [2], [4]], [[1, 4, 5], [2], [3]], 3)] - sage: G = P.dual_equivalence_graph(directed=True) - sage: G.edges(sort=True) + sage: G = P.dual_equivalence_graph(directed=True) # optional - sage.graphs + sage: G.edges(sort=True) # optional - sage.graphs [([[1, 2, 4], [3], [5]], [[1, 2, 3], [4], [5]], 3), ([[1, 2, 5], [3], [4]], [[1, 2, 4], [3], [5]], 4), ([[1, 3, 4], [2], [5]], [[1, 2, 4], [3], [5]], 2), @@ -5411,19 +5408,20 @@ def dual_equivalence_graph(self, directed=False, coloring=None): TESTS:: - sage: G = Partition([1]).dual_equivalence_graph() - sage: G.vertices(sort=False) + sage: G = Partition([1]).dual_equivalence_graph() # optional - sage.graphs + sage: G.vertices(sort=False) # optional - sage.graphs [[[1]]] - sage: G = Partition([]).dual_equivalence_graph() - sage: G.vertices(sort=False) + sage: G = Partition([]).dual_equivalence_graph() # optional - sage.graphs + sage: G.vertices(sort=False) # optional - sage.graphs [[]] sage: P = Partition([3,1,1]) - sage: G = P.dual_equivalence_graph(coloring=lambda x: 'red') - sage: G2 = P.dual_equivalence_graph(coloring={2: 'black', 3: 'blue', 4: 'cyan', 5: 'grey'}) - sage: G is G2 + sage: G = P.dual_equivalence_graph(coloring=lambda x: 'red') # optional - sage.graphs + sage: G2 = P.dual_equivalence_graph(coloring={2: 'black', 3: 'blue', # optional - sage.graphs + ....: 4: 'cyan', 5: 'grey'}) + sage: G is G2 # optional - sage.graphs False - sage: G == G2 + sage: G == G2 # optional - sage.graphs True """ # We do some custom caching to not recreate the graph, but to make @@ -5486,6 +5484,51 @@ def coloring(i): immutable=True, multiedges=True) return self.dual_equivalence_graph(directed, coloring) + def specht_module(self, base_ring=None): + r""" + Return the Specht module corresponding to ``self``. + + EXAMPLES:: + + sage: SM = Partition([2,2,1]).specht_module(QQ); SM # optional - sage.modules + Specht module of [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0)] over Rational Field + sage: s = SymmetricFunctions(QQ).s() # optional - sage.modules + sage: s(SM.frobenius_image()) # optional - sage.modules + s[2, 2, 1] + """ + from sage.combinat.specht_module import SpechtModule + from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: + from sage.rings.rational_field import QQ + base_ring = QQ + R = SymmetricGroupAlgebra(base_ring, sum(self)) + return SpechtModule(R, self) + + def specht_module_dimension(self, base_ring=None): + r""" + Return the dimension of the Specht module corresponding to ``self``. + + This is equal to the number of standard tableaux of shape ``self`` when + over a field of characteristic `0`. + + INPUT: + + - ``BR`` -- (default: `\QQ`) the base ring + + EXAMPLES:: + + sage: Partition([2,2,1]).specht_module_dimension() + 5 + sage: Partition([2,2,1]).specht_module_dimension(GF(2)) # optional - sage.rings.finite_rings + 5 + """ + from sage.categories.fields import Fields + if base_ring is None or (base_ring in Fields() and base_ring.characteristic() == 0): + from sage.combinat.tableau import StandardTableaux + return StandardTableaux(self).cardinality() + from sage.combinat.specht_module import specht_module_rank + return specht_module_rank(self, base_ring) + ############## # Partitions # @@ -5596,16 +5639,20 @@ class Partitions(UniqueRepresentation, Parent): The number of partitions of `n` into odd parts equals the number of partitions into distinct parts. Let's test that for `n` from 10 to 20:: - sage: test = lambda n: Partitions(n, max_slope=-1).cardinality() == Partitions(n, parts_in=[1,3..n]).cardinality() - sage: all(test(n) for n in [10..20]) + sage: def test(n): + ....: return (Partitions(n, max_slope=-1).cardinality() + ....: == Partitions(n, parts_in=[1,3..n]).cardinality()) + sage: all(test(n) for n in [10..20]) # optional - sage.libs.gap True The number of partitions of `n` into distinct parts that differ by at least 2 equals the number of partitions into parts that equal 1 or 4 modulo 5; this is one of the Rogers-Ramanujan identities:: - sage: test = lambda n: Partitions(n, max_slope=-2).cardinality() == Partitions(n, parts_in=([1,6..n] + [4,9..n])).cardinality() - sage: all(test(n) for n in [10..20]) + sage: def test(n): + ....: return (Partitions(n, max_slope=-2).cardinality() + ....: == Partitions(n, parts_in=([1,6..n] + [4,9..n])).cardinality()) + sage: all(test(n) for n in [10..20]) # optional - sage.libs.gap True Here are some more examples illustrating ``min_part``, ``max_part``, @@ -5826,7 +5873,7 @@ def __classcall_private__(cls, n=None, **kwargs): ('parts_in' in kwargs or 'starting' in kwargs or 'ending' in kwargs)): - raise ValueError("the parameters 'parts_in', 'starting' and "+ + raise ValueError("the parameters 'parts_in', 'starting' and " + "'ending' cannot be combined with anything else") if 'parts_in' in kwargs: @@ -5841,7 +5888,7 @@ def __classcall_private__(cls, n=None, **kwargs): return RestrictedPartitions_n(n, kwargs['restricted']) # FIXME: should inherit from IntegerListLex, and implement repr, or _name as a lazy attribute - kwargs['name'] = "Partitions of the integer %s satisfying constraints %s"%(n, ", ".join( ["%s=%s"%(key, kwargs[key]) for key in sorted(kwargs)] )) + kwargs['name'] = "Partitions of the integer %s satisfying constraints %s" % (n, ", ".join( ["%s=%s" % (key, kwargs[key]) for key in sorted(kwargs)] )) # min_part is at least 1, and it is 1 by default kwargs['min_part'] = max(1, kwargs.get('min_part', 1)) @@ -6016,7 +6063,7 @@ def __reversed__(self): [[1, 1, 1, 1], [2, 1, 1], [2, 2], [3, 1], [4]] """ if not self.is_finite(): - raise NotImplementedError("The set is infinite. This needs a custom reverse iterator") + raise NotImplementedError("the set is infinite, so this needs a custom reverse iterator") for i in reversed(range(self.cardinality())): yield self[i] @@ -6282,7 +6329,7 @@ def from_beta_numbers(self, beta): beta.sort() # put them into increasing order just in case offset = 0 while offset < len(beta)-1 and beta[offset] == offset: - offset+=1 + offset += 1 beta = beta[offset:] mu = [beta[i]-offset-i for i in range(len(beta))] return self.element_class(self, list(reversed(mu))) @@ -6385,7 +6432,7 @@ def from_core_and_quotient(self, core, quotient): """ from .partition_tuple import PartitionTuple, PartitionTuples if quotient not in PartitionTuples(): - raise ValueError('the quotient %s must be a tuple of partitions'%quotient) + raise ValueError('the quotient %s must be a tuple of partitions' % quotient) components = PartitionTuple(quotient).components() length = len(components) k = length*max(len(q) for q in components) + len(core) @@ -6627,7 +6674,7 @@ def cardinality(self, algorithm='flint'): raise ValueError("unknown algorithm '%s'" % algorithm) - def random_element(self, measure = 'uniform'): + def random_element(self, measure='uniform'): """ Return a random partitions of `n` for the specified measure. @@ -6715,7 +6762,7 @@ def random_element_uniform(self): rand -= d * cached_number_of_partitions(r) if rand < 0: break - d +=1 + d += 1 r -= j else: continue @@ -7069,7 +7116,7 @@ class Partitions_parts_in(Partitions): TESTS:: - sage: TestSuite( sage.combinat.partition.Partitions_parts_in(6, parts=[2,1]) ).run() + sage: TestSuite( sage.combinat.partition.Partitions_parts_in(6, parts=[2,1]) ).run() # optional - sage.libs.gap """ @staticmethod @@ -7093,7 +7140,7 @@ def __init__(self, n, parts): TESTS:: - sage: TestSuite(Partitions(5, parts_in=[1,2,3])).run() + sage: TestSuite(Partitions(5, parts_in=[1,2,3])).run() # optional - sage.libs.gap """ Partitions.__init__(self) self.n = n @@ -7128,12 +7175,13 @@ def cardinality(self): EXAMPLES:: - sage: Partitions(15, parts_in=[2,3,7]).cardinality() + sage: Partitions(15, parts_in=[2,3,7]).cardinality() # optional - sage.libs.gap 5 If you can use all parts 1 through `n`, we'd better get `p(n)`:: - sage: Partitions(20, parts_in=[1..20]).cardinality() == Partitions(20).cardinality() + sage: (Partitions(20, parts_in=[1..20]).cardinality() # optional - sage.libs.gap + ....: == Partitions(20).cardinality()) True TESTS: @@ -7142,19 +7190,19 @@ def cardinality(self): algorithm that actually generates the partitions:: sage: ps = Partitions(15, parts_in=[1,2,3]) - sage: ps.cardinality() == len(ps.list()) + sage: ps.cardinality() == len(ps.list()) # optional - sage.libs.gap True sage: ps = Partitions(15, parts_in=[]) - sage: ps.cardinality() == len(ps.list()) + sage: ps.cardinality() == len(ps.list()) # optional - sage.libs.gap True sage: ps = Partitions(3000, parts_in=[50,100,500,1000]) - sage: ps.cardinality() == len(ps.list()) + sage: ps.cardinality() == len(ps.list()) # optional - sage.libs.gap True sage: ps = Partitions(10, parts_in=[3,6,9]) - sage: ps.cardinality() == len(ps.list()) + sage: ps.cardinality() == len(ps.list()) # optional - sage.libs.gap True sage: ps = Partitions(0, parts_in=[1,2]) - sage: ps.cardinality() == len(ps.list()) + sage: ps.cardinality() == len(ps.list()) # optional - sage.libs.gap True """ # GAP complains if you give it an empty list @@ -7408,6 +7456,22 @@ def __init__(self, n, starting_partition): sage: Partitions(3, starting=[2,1]).list() [[2, 1], [1, 1, 1]] + sage: Partitions(7, starting=[2,2,1]).list() + [[2, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1]] + + sage: Partitions(7, starting=[3,2]).list() + [[3, 1, 1, 1, 1], + [2, 2, 2, 1], + [2, 2, 1, 1, 1], + [2, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1]] + + sage: Partitions(4, starting=[3,2]).list() + [[3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]] + + sage: Partitions(3, starting=[1,1]).list() + [] + TESTS:: sage: p = Partitions(3, starting=[2,1]) @@ -7454,8 +7518,24 @@ def first(self): sage: Partitions(3, starting=[2,1]).first() [2, 1] + sage: Partitions(3, starting=[1,1,1]).first() + [1, 1, 1] + sage: Partitions(3, starting=[1,1]).first() + False + sage: Partitions(3, starting=[3,1]).first() + [3] + sage: Partitions(3, starting=[2,2]).first() + [2, 1] """ - return self._starting + if sum(self._starting) == self.n: + return self._starting + + if (k := self._starting.size()) < self.n: + mu = list(self._starting) + [1] * (self.n - k) + return next(Partition(mu)) + + #if self._starting.size() > self.n: + return self.element_class(self, Partitions(self.n, outer=self._starting).first()) def next(self, part): """ @@ -7502,6 +7582,8 @@ def __init__(self, n, ending_partition): [[4], [3, 1], [2, 2]] sage: Partitions(4, ending=[4]).list() [[4]] + sage: Partitions(4, ending=[5]).list() + [] TESTS:: @@ -7511,6 +7593,7 @@ def __init__(self, n, ending_partition): Partitions.__init__(self) self.n = n self._ending = ending_partition + self._ending_size_is_not_same = (n != sum(self._ending)) def _repr_(self): """ @@ -7547,7 +7630,11 @@ def first(self): sage: Partitions(4, ending=[1,1,1,1]).first() [4] + sage: Partitions(4, ending=[5]).first() is None + True """ + if self._ending and self.n <= self._ending[0] and not (self.n == self._ending[0] and len(self._ending) == 1): + return None return self.element_class(self, [self.n]) def next(self, part): @@ -7555,15 +7642,26 @@ def next(self, part): Return the next partition after ``part`` in ``self``. EXAMPLES:: - + sage: Partitions(4, ending=[1,1,1,1,1]).next(Partition([4])) + [3, 1] + sage: Partitions(4, ending=[3,2]).next(Partition([3,1])) is None + True sage: Partitions(4, ending=[1,1,1,1]).next(Partition([4])) [3, 1] sage: Partitions(4, ending=[1,1,1,1]).next(Partition([1,1,1,1])) is None True + sage: Partitions(4, ending=[3]).next(Partition([3,1])) is None + True """ + # if we have passed the last Partition, there is no next partition if part == self._ending: return None - return next(part) + + # if self._ending is a different size, we should make the comparison + mu = next(part) + if self._ending_size_is_not_same and mu < self._ending: + return None + return mu class PartitionsInBox(Partitions): @@ -7656,7 +7754,7 @@ def list(self): new_list += add(element) l = new_list - return [self.element_class(self, [x for x in p if x!=0]) for p in l] + return [self.element_class(self, [x for x in p if x != 0]) for p in l] def cardinality(self): """ @@ -8267,16 +8365,16 @@ class OrderedPartitions(Partitions): sage: OrderedPartitions(3) Ordered partitions of 3 - sage: OrderedPartitions(3).list() + sage: OrderedPartitions(3).list() # optional - sage.libs.gap [[3], [2, 1], [1, 2], [1, 1, 1]] sage: OrderedPartitions(3,2) Ordered partitions of 3 of length 2 - sage: OrderedPartitions(3,2).list() + sage: OrderedPartitions(3,2).list() # optional - sage.libs.gap [[2, 1], [1, 2]] - sage: OrderedPartitions(10,k=2).list() + sage: OrderedPartitions(10, k=2).list() # optional - sage.libs.gap [[9, 1], [8, 2], [7, 3], [6, 4], [5, 5], [4, 6], [3, 7], [2, 8], [1, 9]] - sage: OrderedPartitions(4).list() + sage: OrderedPartitions(4).list() # optional - sage.libs.gap [[4], [3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]] """ @@ -8307,7 +8405,7 @@ def __init__(self, n, k): TESTS:: - sage: TestSuite( OrderedPartitions(5,3) ).run() + sage: TestSuite( OrderedPartitions(5,3) ).run() # optional - sage.libs.gap """ Partitions.__init__(self) self.n = n @@ -8352,9 +8450,9 @@ def list(self): EXAMPLES:: - sage: OrderedPartitions(3).list() + sage: OrderedPartitions(3).list() # optional - sage.libs.gap [[3], [2, 1], [1, 2], [1, 1, 1]] - sage: OrderedPartitions(3,2).list() + sage: OrderedPartitions(3,2).list() # optional - sage.libs.gap [[2, 1], [1, 2]] """ from sage.libs.gap.libgap import libgap @@ -8374,13 +8472,13 @@ def cardinality(self): EXAMPLES:: - sage: OrderedPartitions(3).cardinality() + sage: OrderedPartitions(3).cardinality() # optional - sage.libs.gap 4 - sage: OrderedPartitions(3,2).cardinality() + sage: OrderedPartitions(3,2).cardinality() # optional - sage.libs.gap 2 - sage: OrderedPartitions(10,2).cardinality() + sage: OrderedPartitions(10,2).cardinality() # optional - sage.libs.gap 9 - sage: OrderedPartitions(15).cardinality() + sage: OrderedPartitions(15).cardinality() # optional - sage.libs.gap 16384 """ from sage.libs.gap.libgap import libgap @@ -8454,12 +8552,12 @@ def cardinality(self): EXAMPLES:: - sage: PartitionsGreatestLE(9, 5).cardinality() + sage: PartitionsGreatestLE(9, 5).cardinality() # optional - sage.libs.gap 23 TESTS:: - sage: all(PartitionsGreatestLE(n, a).cardinality() == + sage: all(PartitionsGreatestLE(n, a).cardinality() == # optional - sage.libs.gap ....: len(PartitionsGreatestLE(n, a).list()) ....: for n in range(20) for a in range(6)) True @@ -8970,19 +9068,19 @@ def number_of_partitions_length(n, k, algorithm='hybrid'): EXAMPLES:: sage: from sage.combinat.partition import number_of_partitions_length - sage: number_of_partitions_length(5, 2) + sage: number_of_partitions_length(5, 2) # optional - sage.libs.gap 2 - sage: number_of_partitions_length(10, 2) + sage: number_of_partitions_length(10, 2) # optional - sage.libs.gap 5 - sage: number_of_partitions_length(10, 4) + sage: number_of_partitions_length(10, 4) # optional - sage.libs.gap 9 - sage: number_of_partitions_length(10, 0) + sage: number_of_partitions_length(10, 0) # optional - sage.libs.gap 0 - sage: number_of_partitions_length(10, 1) + sage: number_of_partitions_length(10, 1) # optional - sage.libs.gap 1 - sage: number_of_partitions_length(0, 0) + sage: number_of_partitions_length(0, 0) # optional - sage.libs.gap 1 - sage: number_of_partitions_length(0, 1) + sage: number_of_partitions_length(0, 1) # optional - sage.libs.gap 0 """ if algorithm == 'hybrid': diff --git a/src/sage/combinat/partition_algebra.py b/src/sage/combinat/partition_algebra.py index fcece47fbf8..0b7eb06c3a5 100644 --- a/src/sage/combinat/partition_algebra.py +++ b/src/sage/combinat/partition_algebra.py @@ -15,18 +15,18 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from .combinat import catalan_number -from sage.combinat.free_module import CombinatorialFreeModule +from sage.arith.misc import binomial, factorial from sage.categories.algebras_with_basis import AlgebrasWithBasis +from sage.combinat.combinat import catalan_number +from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.permutation import Permutations from sage.combinat.set_partition import SetPartition, SetPartitions, SetPartitions_set -from sage.sets.set import Set, Set_generic +from sage.combinat.subset import Subsets +from sage.functions.all import ceil from sage.graphs.graph import Graph -from sage.arith.all import factorial, binomial -from .permutation import Permutations from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from .subset import Subsets -from sage.functions.all import ceil +from sage.sets.set import Set, Set_generic def _int_or_half_int(k): @@ -1974,7 +1974,7 @@ def set_partition_composition(sp1, sp2): True """ g = pair_to_graph(sp1, sp2) - connected_components = g.connected_components() + connected_components = g.connected_components(sort=False) res = [] total_removed = 0 diff --git a/src/sage/combinat/partition_kleshchev.py b/src/sage/combinat/partition_kleshchev.py index bc4963aa6cf..06781aa96ed 100644 --- a/src/sage/combinat/partition_kleshchev.py +++ b/src/sage/combinat/partition_kleshchev.py @@ -994,7 +994,7 @@ def e(self, i): cell = self.good_cells(i) if cell is None: return None - r,c = cell + r, _ = cell mu = list(self) mu[r] -= 1 return type(self)(P, mu) @@ -1055,7 +1055,7 @@ def e(self, i): cell = self.good_cells(i) if cell is None: return None - k,r,c = cell + k, r, _ = cell mu = self.to_list() mu[k][r] -= 1 return type(self)(P, mu) @@ -1286,11 +1286,11 @@ def _element_constructor_(self, mu): return mu if KPmu._level != self._level or KPmu._e != self._e: - raise ValueError('%s is not an element of %s'%(mu, self)) + raise ValueError('%s is not an element of %s' % (mu, self)) if KPmu._convention[1] != self._convention[1]: mu = [nu.conjugate() for nu in mu] - if self._level>1 and KPmu._convention[0] == self._convention[0]: + if self._level > 1 and KPmu._convention[0] == self._convention[0]: mu = mu[::-1] return super()._element_constructor_(mu) @@ -1483,7 +1483,7 @@ def _repr_(self): return 'Kleshchev partitions with e=%s' % (self._e) return 'Kleshchev partitions with e=%s and multicharge=(%s)' % ( - self._e,','.join('%s'%m for m in self._multicharge)) + self._e,','.join('%s' % m for m in self._multicharge)) def __contains__(self, mu): """ @@ -1707,7 +1707,7 @@ def _repr_(self): return 'Kleshchev partitions with e=%s and size %s' % (self._e, self._size) return 'Kleshchev partitions with e=%s and multicharge=(%s) and size %s' % ( - self._e,','.join('%s'%m for m in self._multicharge), self._size + self._e,','.join('%s' % m for m in self._multicharge), self._size ) def __contains__(self, mu): @@ -1938,7 +1938,7 @@ def _is_regular(kpt, multicharge, convention): convention = convention[0] + 'G' cell = _a_good_cell(kpt, multicharge, convention) while cell is not None: - k,r,c = cell + k, r, _ = cell if kpt[k][r] == 1: kpt[k].pop() else: @@ -1964,15 +1964,15 @@ def _is_restricted(kpt, multicharge, convention): sage: _is_restricted([[], []], [I3(0),I3(2)], 'RG') True """ - if all(part == [] for part in kpt): + if all(not part for part in kpt): return True convention = convention[0] + 'S' cell = _a_good_cell(kpt, multicharge, convention) while cell is not None: - k,r,c = cell + k, r, _ = cell if kpt[k][r] == 1: kpt[k].pop() else: kpt[k][r] -= 1 cell = _a_good_cell(kpt, multicharge, convention) - return all(part == [] for part in kpt) + return all(not part for part in kpt) diff --git a/src/sage/combinat/partition_tuple.py b/src/sage/combinat/partition_tuple.py index 4fbf6b91723..5766027efbc 100644 --- a/src/sage/combinat/partition_tuple.py +++ b/src/sage/combinat/partition_tuple.py @@ -794,9 +794,9 @@ def diagram(self): # There should be a fancier list compression for this but I couldn't get # one to work in the cases where a component was the empty partition diag = [] - diag_str=PartitionTuples.options('diagram_str') + diag_str = PartitionTuples.options('diagram_str') for row in range(row_max): - line='' + line = '' for c in range(len(self)): if row == 0 and self[c] == []: line += ' -' @@ -880,8 +880,8 @@ def up(self): """ for c in range(len(self)): for nu in self[c].up(): - up=[tau for tau in self] - up[c]=nu + up = [tau for tau in self] + up[c] = nu yield PartitionTuple(up) def up_list(self): @@ -914,8 +914,8 @@ def down(self): """ for c in range(len(self)): for nu in self[c].down(): - down=[tau for tau in self] - down[c]=nu + down = [tau for tau in self] + down[c] = nu yield PartitionTuple(down) def down_list(self): @@ -1054,7 +1054,7 @@ def dominates(self, mu): True """ try: - mu=PartitionTuple(mu) + mu = PartitionTuple(mu) except ValueError: raise ValueError('%s must be a PartitionTuple' % mu) @@ -1063,21 +1063,21 @@ def dominates(self, mu): level = 0 ssum = 0 # sum of successive rows in self musum = 0 # sum of successive rows in self - while level<self.level() and level<mu.level(): - row=0 - while row<len(self[level]) and row<len(mu[level]): - ssum+=self[level][row] - musum+=mu[level][row] - if musum>ssum: + while level < self.level() and level < mu.level(): + row = 0 + while row < len(self[level]) and row < len(mu[level]): + ssum += self[level][row] + musum += mu[level][row] + if musum > ssum: return False - row+=1 - if row<len(self[level]): - ssum+=sum(self[level][row:]) - elif row<len(mu[level]): - musum+=sum(mu[level][row:]) - if musum>ssum: + row += 1 + if row < len(self[level]): + ssum += sum(self[level][row:]) + elif row < len(mu[level]): + musum += sum(mu[level][row:]) + if musum > ssum: return False - level+=1 + level += 1 return True @cached_method @@ -1177,11 +1177,11 @@ def garnir_tableau(self, *cell): - :meth:`top_garnir_tableau` """ try: - (comp, row,col)=cell + (comp, row,col) = cell except ValueError: - (comp, row,col)=cell[0] + (comp, row,col) = cell[0] - if comp>=len(self) or row+1>=len(self[comp]) or col>=self[comp][row+1]: + if comp >= len(self) or row+1 >= len(self[comp]) or col >= self[comp][row+1]: raise ValueError('(comp, row+1, col) must be inside the diagram') g = self.initial_tableau().to_list() a = g[comp][row][col] @@ -1246,26 +1246,26 @@ def top_garnir_tableau(self,e,cell): - :meth:`~sage.combinat.partition.Partition_tuple.garnir_tableau` """ - (comp,row,col)=cell - if comp>=len(self) or row+1>=len(self[comp]) or col>=self[comp][row+1]: + (comp,row,col) = cell + if comp >= len(self) or row+1 >= len(self[comp]) or col >= self[comp][row+1]: raise ValueError('(comp, row+1, col) must be inside the diagram') - g=self.garnir_tableau(cell) + g = self.garnir_tableau(cell) - if e==0: + if e == 0: return # no more dominant tableau of the same residue - a=e*int((self[comp][row]-col)/e) # number of cells in the e-bricks in row `row` - b=e*int((col+1)/e) # number of cells in the e-bricks in row `row+1` + a = e*int((self[comp][row]-col)/e) # number of cells in the e-bricks in row `row` + b = e*int((col+1)/e) # number of cells in the e-bricks in row `row+1` - if a==0 or b==0: + if a == 0 or b == 0: return self.garnir_tableau(cell) - t=g.to_list() - m=t[comp][row+1][0] # smallest number of 0-Garnir belt + t = g.to_list() + m = t[comp][row+1][0] # smallest number of 0-Garnir belt # now we will put the number m,m+1,...,t[row+1][col] in order into t - t[comp][row][col:a+col]=[m+col-b+1+i for i in range(a)] - t[comp][row+1][col-b+1:col+1]=[m+a+col-b+1+i for i in range(b)] + t[comp][row][col:a+col] = [m+col-b+1+i for i in range(a)] + t[comp][row+1][col-b+1:col+1] = [m+a+col-b+1+i for i in range(b)] from .tableau_tuple import StandardTableauTuple return StandardTableauTuple(t) @@ -1299,7 +1299,7 @@ def arm_length(self, k,r,c): try: return self[k][r]-(c+1) except IndexError: - raise ValueError("The cell %s is not in the diagram" %((k,r,c),)) + raise ValueError("The cell %s is not in the diagram" % ((k,r,c),)) def leg_length(self, k,r,c): """ @@ -1346,7 +1346,7 @@ def contains(self, mu): sage: PartitionTuple([[1,1],[2],[2,1]]).contains( PartitionTuple([[1,1],[2],[2,1]]) ) True """ - return mu.level()<=self.level() and all(self[c].contains(mu[c]) for c in range(len(mu))) + return mu.level() <= self.level() and all(self[c].contains(mu[c]) for c in range(len(mu))) def hook_length(self, k,r,c): r""" @@ -1597,7 +1597,7 @@ def degree(self, e): for some integer `N`. Compare with :meth:`prime_degree`. """ - multicharge=tuple([i*self.size() for i in range(self.size())]) + multicharge = tuple([i*self.size() for i in range(self.size())]) return sum(t.degree(e, multicharge) for t in self.standard_tableaux()) def prime_degree(self, p): @@ -1648,7 +1648,7 @@ def prime_degree(self, p): while ps[-1]*p < self.size(): ps.append(ps[-1] * p) - multicharge=tuple([i*self.size() for i in range(self.size())]) + multicharge = tuple([i*self.size() for i in range(self.size())]) return sum(t.degree(pk, multicharge) for pk in ps for t in self.standard_tableaux()) @cached_method @@ -2005,23 +2005,23 @@ def __getitem__(self, r): if isinstance(r,(int,Integer)): return self.unrank(r) elif isinstance(r,slice): - start=0 if r.start is None else r.start - stop=r.stop + start = 0 if r.start is None else r.start + stop = r.stop if stop is None and not self.is_finite(): raise ValueError('infinite set') else: raise ValueError('r must be an integer or a slice') - count=0 - parts=[] + count = 0 + parts = [] for t in self: - if count==stop: + if count == stop: break - if count>=start: + if count >= start: parts.append(t) - count+=1 + count += 1 # this is to cope with empty slice endpoints like [6:] or [:] - if count==stop or stop is None: + if count == stop or stop is None: return parts raise IndexError('value out of range') @@ -2449,10 +2449,10 @@ def _an_element_(self): mu = [[] for _ in itertools.repeat(None, self._level)] if self._size > 0: if self._level == 1: - mu=[self._size-1,1] + mu = [self._size-1,1] else: - mu[0]=[1] - mu[-1]=[self._size-1] + mu[0] = [1] + mu[-1] = [self._size-1] return self.element_class(self, mu) def cardinality(self): @@ -2501,9 +2501,9 @@ def __setstate__(self, state): Partition tuples of level 7 and size 3 """ if isinstance(state, dict): # for old pickles from Tableau_class - parts=PartitionTuples(state['k'], state['n']) - self.__class__=parts.__class__ - self.__dict__=parts.__dict__ + parts = PartitionTuples(state['k'], state['n']) + self.__class__ = parts.__class__ + self.__dict__ = parts.__dict__ else: super().__setstate__(state) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 1706a5cd4e1..23ff179039c 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -84,9 +84,10 @@ class FriezePattern(PathTableau, metaclass=InheritComparisonClasscallMetaclass): This constructs the examples from [HJ18]_:: - sage: K.<sqrt3> = NumberField(x^2-3) - sage: t = path_tableaux.FriezePattern([1,sqrt3,2,sqrt3,1,1], field=K) - sage: path_tableaux.CylindricalDiagram(t) + sage: x = polygen(ZZ, 'x') + sage: K.<sqrt3> = NumberField(x^2 - 3) # optional - sage.rings.number_field + sage: t = path_tableaux.FriezePattern([1,sqrt3,2,sqrt3,1,1], field=K) # optional - sage.rings.number_field + sage: path_tableaux.CylindricalDiagram(t) # optional - sage.rings.number_field [ 0, 1, sqrt3, 2, sqrt3, 1, 1, 0] [ , 0, 1, sqrt3, 2, sqrt3, sqrt3 + 1, 1, 0] [ , , 0, 1, sqrt3, 2, sqrt3 + 2, sqrt3, 1, 0] @@ -96,11 +97,12 @@ class FriezePattern(PathTableau, metaclass=InheritComparisonClasscallMetaclass): [ , , , , , , 0, 1, sqrt3 + 1, sqrt3 + 2, sqrt3 + 2, sqrt3 + 1, 1, 0] [ , , , , , , , 0, 1, sqrt3, 2, sqrt3, 1, 1, 0] - sage: TestSuite(t).run() + sage: TestSuite(t).run() # optional - sage.rings.number_field - sage: K.<sqrt2> = NumberField(x^2-2) - sage: t = path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K) - sage: path_tableaux.CylindricalDiagram(t) + sage: K.<sqrt2> = NumberField(x^2 - 2) # optional - sage.rings.number_field + sage: t = path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], # optional - sage.rings.number_field + ....: field=K) + sage: path_tableaux.CylindricalDiagram(t) # optional - sage.rings.number_field [ 0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] [ , 0, 1, sqrt2, 3, 5*sqrt2, 7, 9*sqrt2, 11, 2*sqrt2, 1, 0] [ , , 0, 1, 2*sqrt2, 7, 5*sqrt2, 13, 8*sqrt2, 3, sqrt2, 1, 0] @@ -113,7 +115,7 @@ class FriezePattern(PathTableau, metaclass=InheritComparisonClasscallMetaclass): [ , , , , , , , , , 0, 1, 2*sqrt2, 3, sqrt2, 1, sqrt2, 1, sqrt2, 1, 0] [ , , , , , , , , , , 0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] - sage: TestSuite(t).run() + sage: TestSuite(t).run() # optional - sage.rings.number_field """ @staticmethod def __classcall_private__(cls, fp, field=QQ): @@ -132,13 +134,14 @@ def __classcall_private__(cls, fp, field=QQ): ... ValueError: invalid input 2 - sage: K.<sqrt3> = NumberField(x^2-3) - sage: t = path_tableaux.FriezePattern([1,sqrt3,2,sqrt3,1,1]) + sage: x = polygen(ZZ, 'x') + sage: K.<sqrt3> = NumberField(x^2 - 3) # optional - sage.rings.number_field + sage: t = path_tableaux.FriezePattern([1,sqrt3,2,sqrt3,1,1]) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: [1, sqrt3, 2, sqrt3, 1, 1] is not a sequence in the field Rational Field - sage: path_tableaux.FriezePattern([1,2,1,2,3,1],field=Integers()) + sage: path_tableaux.FriezePattern([1,2,1,2,3,1], field=Integers()) Traceback (most recent call last): ... ValueError: Integer Ring must be a field @@ -274,8 +277,9 @@ def is_positive(self): sage: path_tableaux.FriezePattern([1,-3,4,5,1]).is_positive() False - sage: K.<sqrt3> = NumberField(x^2-3) - sage: path_tableaux.FriezePattern([1,sqrt3,1],K).is_positive() + sage: x = polygen(ZZ, 'x') + sage: K.<sqrt3> = NumberField(x^2 - 3) # optional - sage.rings.number_field + sage: path_tableaux.FriezePattern([1,sqrt3,1], K).is_positive() # optional - sage.rings.number_field True """ return all(a > 0 for a in self[1:-1]) @@ -295,7 +299,8 @@ def is_integral(self): """ n = len(self) cd = CylindricalDiagram(self).diagram - return all(all(k in ZZ for k in a[i+1:n+i-2]) for i, a in enumerate(cd)) + return all(k in ZZ for i, a in enumerate(cd) + for k in a[i + 1:n + i - 2]) def triangulation(self): r""" @@ -311,14 +316,17 @@ def triangulation(self): EXAMPLES:: - sage: path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).triangulation() + sage: path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).triangulation() # optional - sage.plot sage.symbolic Graphics object consisting of 25 graphics primitives - sage: path_tableaux.FriezePattern([1,2,1/7,5,3]).triangulation() + sage: path_tableaux.FriezePattern([1,2,1/7,5,3]).triangulation() # optional - sage.plot sage.symbolic Graphics object consisting of 12 graphics primitives - sage: K.<sqrt2> = NumberField(x^2-2) - sage: path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K).triangulation() + + sage: x = polygen(ZZ, 'x') + sage: K.<sqrt2> = NumberField(x^2 - 2) # optional - sage.rings.number_field + sage: path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], # optional - sage.plot sage.rings.number_field sage.symbolic + ....: field=K).triangulation() Graphics object consisting of 24 graphics primitives """ n = len(self)-1 @@ -327,7 +335,7 @@ def triangulation(self): from sage.plot.line import line from sage.plot.text import text from sage.functions.trig import sin, cos - from sage.all import pi + from sage.symbolic.constants import pi G = Graphics() G.set_aspect_ratio(1.0) @@ -371,17 +379,17 @@ def plot(self, model='UHP'): EXAMPLES:: sage: t = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]) - sage: t.plot() + sage: t.plot() # optional - sage.plot sage.symbolic Graphics object consisting of 18 graphics primitives - sage: t.plot(model='UHP') + sage: t.plot(model='UHP') # optional - sage.plot sage.symbolic Graphics object consisting of 18 graphics primitives - sage: t.plot(model='PD') + sage: t.plot(model='PD') # optional - sage.plot sage.symbolic Traceback (most recent call last): ... TypeError: '>' not supported between instances of 'NotANumber' and 'Pi' - sage: t.plot(model='KM') + sage: t.plot(model='KM') # optional - sage.plot sage.symbolic Graphics object consisting of 18 graphics primitives """ from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane diff --git a/src/sage/combinat/path_tableaux/semistandard.py b/src/sage/combinat/path_tableaux/semistandard.py index 5fefebfe51a..f92dfcdd6c8 100644 --- a/src/sage/combinat/path_tableaux/semistandard.py +++ b/src/sage/combinat/path_tableaux/semistandard.py @@ -246,7 +246,7 @@ def is_skew(self): """ return bool(self[0]) - def is_integral(self): + def is_integral(self) -> bool: """ Return ``True`` if all entries are non-negative integers. @@ -259,7 +259,7 @@ def is_integral(self): sage: path_tableaux.SemistandardPathTableau([[],[3],[3,-2]]).is_integral() False """ - return all(all(i in NN for i in a) for a in self) + return all(i in NN for a in self for i in a) def local_rule(self, i): r""" diff --git a/src/sage/combinat/perfect_matching.py b/src/sage/combinat/perfect_matching.py index 383f6522903..c663a689f31 100644 --- a/src/sage/combinat/perfect_matching.py +++ b/src/sage/combinat/perfect_matching.py @@ -224,7 +224,7 @@ def _latex_(self): EXAMPLES:: sage: P = PerfectMatching([(1,3),(2,5),(4,6)]) - sage: latex(P) # random + sage: latex(P) # random # optional - sage.graphs \begin{tikzpicture} ... \end{tikzpicture} @@ -234,7 +234,7 @@ def _latex_(self): Above we added ``random`` since warnings might be displayed once. The second time, there should be no warnings:: - sage: print(P._latex_()) + sage: print(P._latex_()) # optional - sage.graphs \begin{tikzpicture} ... \end{tikzpicture} @@ -377,10 +377,12 @@ def loops(self, other=None): sage: loops = sorted(loops, key=len) sage: sorted(loops[0]) ['d', 'f'] - sage: G = SymmetricGroup(4) - sage: g = G([(1,2,3,4)]) - sage: ((loops[1] in [permutation_action(g**i, ['a', 'e', 'c', 'b']) for i in range(4)]) - ....: or (loops[1] in [permutation_action(g**i, ['a', 'b', 'c', 'e']) for i in range(4)])) + sage: G = SymmetricGroup(4) # optional - sage.groups + sage: g = G([(1,2,3,4)]) # optional - sage.groups + sage: ((loops[1] in [permutation_action(g**i, ['a', 'e', 'c', 'b']) # optional - sage.groups + ....: for i in range(4)]) + ....: or (loops[1] in [permutation_action(g**i, ['a', 'b', 'c', 'e']) + ....: for i in range(4)])) True """ return list(self.loops_iterator(other)) @@ -453,11 +455,11 @@ def Weingarten_function(self, d, other=None): EXAMPLES:: - sage: var('N') + sage: var('N') # optional - sage.symbolic N sage: m = PerfectMatching([(1,3),(2,4)]) sage: n = PerfectMatching([(1,2),(3,4)]) - sage: factor(m.Weingarten_function(N,n)) + sage: factor(m.Weingarten_function(N, n)) # optional - sage.symbolic -1/((N + 2)*(N - 1)*N) """ if other is None: @@ -475,11 +477,13 @@ def to_graph(self): EXAMPLES:: - sage: PerfectMatching([[1,3], [4,2]]).to_graph().edges(sort=True, labels=False) + sage: PerfectMatching([[1,3], [4,2]]).to_graph().edges(sort=True, # optional - sage.graphs + ....: labels=False) [(1, 3), (2, 4)] - sage: PerfectMatching([[1,4], [3,2]]).to_graph().edges(sort=True, labels=False) + sage: PerfectMatching([[1,4], [3,2]]).to_graph().edges(sort=True, # optional - sage.graphs + ....: labels=False) [(1, 4), (2, 3)] - sage: PerfectMatching([]).to_graph().edges(sort=True, labels=False) + sage: PerfectMatching([]).to_graph().edges(sort=True, labels=False) # optional - sage.graphs [] """ from sage.graphs.graph import Graph @@ -764,8 +768,8 @@ def Weingarten_matrix(self, N): EXAMPLES:: - sage: M = PerfectMatchings(4).Weingarten_matrix(var('N')) - sage: N*(N-1)*(N+2)*M.apply_map(factor) + sage: M = PerfectMatchings(4).Weingarten_matrix(var('N')) # optional - sage.symbolic + sage: N*(N-1)*(N+2)*M.apply_map(factor) # optional - sage.symbolic [N + 1 -1 -1] [ -1 N + 1 -1] [ -1 -1 N + 1] diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index ec1958ee313..5cf89374de9 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -76,6 +76,8 @@ :meth:`~sage.combinat.permutation.Permutation.reduced_words_iterator` | An iterator for the reduced words of the permutation ``self``. :meth:`~sage.combinat.permutation.Permutation.reduced_word_lexmin` | Returns a lexicographically minimal reduced word of a permutation ``self``. :meth:`~sage.combinat.permutation.Permutation.fixed_points` | Returns a list of the fixed points of the permutation ``self``. + :meth:`~sage.combinat.permutation.Permutation.is_derangement` | Returns ``True`` if the permutation ``self`` is a derangement, and ``False`` otherwise. + :meth:`~sage.combinat.permutation.Permutation.is_simple` | Returns ``True`` if the permutation ``self`` is simple, and ``False`` otherwise. :meth:`~sage.combinat.permutation.Permutation.number_of_fixed_points` | Returns the number of fixed points of the permutation ``self``. :meth:`~sage.combinat.permutation.Permutation.recoils` | Returns the list of the positions of the recoils of the permutation ``self``. :meth:`~sage.combinat.permutation.Permutation.number_of_recoils` | Returns the number of recoils of the permutation ``self``. @@ -239,37 +241,45 @@ # **************************************************************************** from __future__ import annotations from typing import Iterator +import itertools +import operator -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation -from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +from sage.arith.misc import factorial, multinomial from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.categories.sets_with_grading import SetsWithGrading -from sage.categories.finite_weyl_groups import FiniteWeylGroups from sage.categories.finite_permutation_groups import FinitePermutationGroups -from sage.structure.list_clone import ClonableArray -from sage.structure.global_options import GlobalOptions -from sage.libs.gap.libgap import libgap +from sage.categories.finite_weyl_groups import FiniteWeylGroups +from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +from sage.categories.sets_with_grading import SetsWithGrading +from sage.combinat.backtrack import GenericBacktracker +from sage.combinat.combinat import CombinatorialElement, catalan_number +from sage.combinat.combinatorial_map import combinatorial_map +from sage.combinat.composition import Composition +from sage.combinat.permutation_cython import (left_action_product, right_action_product, + left_action_same_n, right_action_same_n, + map_to_list, next_perm) +from sage.combinat.tools import transitive_ideal +from sage.misc.cachefunc import cached_method +from sage.misc.decorators import rename_keyword +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.arith.all import factorial, multinomial -from sage.matrix.matrix_space import MatrixSpace -from sage.combinat.tools import transitive_ideal -from sage.combinat.composition import Composition -from sage.groups.perm_gps.permgroup_named import SymmetricGroup -from sage.groups.perm_gps.permgroup_element import PermutationGroupElement -from sage.misc.prandom import sample -from sage.graphs.digraph import DiGraph -import itertools -from .combinat import CombinatorialElement, catalan_number -from sage.misc.cachefunc import cached_method -from .backtrack import GenericBacktracker -from sage.combinat.combinatorial_map import combinatorial_map -from sage.combinat.rsk import RSK, RSK_inverse -from sage.combinat.permutation_cython import (left_action_product, - right_action_product, left_action_same_n, right_action_same_n, - map_to_list, next_perm) +from sage.structure.global_options import GlobalOptions +from sage.structure.list_clone import ClonableArray +from sage.structure.parent import Parent +from sage.structure.element import Element, get_coercion_model +from sage.structure.unique_representation import UniqueRepresentation + +lazy_import('sage.combinat.rsk', ['RSK', 'RSK_inverse']) +lazy_import('sage.combinat.tableau', 'Tableau') +lazy_import('sage.combinat.words.finite_word', 'evaluation_dict') +lazy_import('sage.graphs.digraph', 'DiGraph') +lazy_import('sage.groups.cactus_group', 'CactusGroup') +lazy_import('sage.groups.perm_gps.permgroup_element', 'PermutationGroupElement') +lazy_import('sage.groups.perm_gps.permgroup_named', 'SymmetricGroup') +lazy_import('sage.libs.gap.libgap', 'libgap') +lazy_import('sage.matrix.matrix_space', 'MatrixSpace') +lazy_import('sage.misc.prandom', 'sample') class Permutation(CombinatorialElement): @@ -286,7 +296,7 @@ class Permutation(CombinatorialElement): - list of integers, viewed as one-line permutation notation. The construction checks that you give an acceptable entry. To avoid - the check, use the ``check_input`` option. + the check, use the ``check`` option. - string, expressing the permutation in cycle notation. @@ -299,7 +309,7 @@ class Permutation(CombinatorialElement): the permutation obtained from the pair using the inverse of the Robinson-Schensted algorithm. - - ``check_input`` (boolean) -- whether to check that input is correct. Slows + - ``check`` (boolean) -- whether to check that input is correct. Slows the function down, but ensures that nothing bad happens. This is set to ``True`` by default. @@ -308,7 +318,7 @@ class Permutation(CombinatorialElement): Since :trac:`13742` the input is checked for correctness : it is not accepted unless it actually is a permutation on `\{1, \ldots, n\}`. It means that some :meth:`Permutation` objects cannot be created anymore - without setting ``check_input = False``, as there is no certainty that + without setting ``check=False``, as there is no certainty that its functions can handle them, and this should be fixed in a much better way ASAP (the functions should be rewritten to handle those cases, and new tests be added). @@ -386,8 +396,8 @@ class Permutation(CombinatorialElement): We construct a :class:`Permutation` from a :class:`PermutationGroupElement`:: - sage: g = PermutationGroupElement([2,1,3]) - sage: Permutation(g) + sage: g = PermutationGroupElement([2,1,3]) # optional - sage.groups + sage: Permutation(g) # optional - sage.groups [2, 1, 3] From a pair of tableaux of the same shape. This uses the inverse @@ -395,15 +405,15 @@ class Permutation(CombinatorialElement): sage: p = [[1, 4, 7], [2, 5], [3], [6]] sage: q = [[1, 2, 5], [3, 6], [4], [7]] - sage: P = Tableau(p) - sage: Q = Tableau(q) - sage: Permutation( (p, q) ) + sage: P = Tableau(p) # optional - sage.combinat + sage: Q = Tableau(q) # optional - sage.combinat + sage: Permutation( (p, q) ) # optional - sage.combinat [3, 6, 5, 2, 7, 4, 1] - sage: Permutation( [p, q] ) + sage: Permutation( [p, q] ) # optional - sage.combinat [3, 6, 5, 2, 7, 4, 1] - sage: Permutation( (P, Q) ) + sage: Permutation( (P, Q) ) # optional - sage.combinat [3, 6, 5, 2, 7, 4, 1] - sage: Permutation( [P, Q] ) + sage: Permutation( [P, Q] ) # optional - sage.combinat [3, 6, 5, 2, 7, 4, 1] TESTS:: @@ -419,13 +429,14 @@ class Permutation(CombinatorialElement): From a pair of empty tableaux :: - sage: Permutation( ([], []) ) + sage: Permutation( ([], []) ) # optional - sage.combinat [] - sage: Permutation( [[], []] ) + sage: Permutation( [[], []] ) # optional - sage.combinat [] """ @staticmethod - def __classcall_private__(cls, l, check_input = True): + @rename_keyword(deprecation=35233, check_input='check') + def __classcall_private__(cls, l, check=True): """ Return a permutation in the general permutations parent. @@ -436,7 +447,6 @@ def __classcall_private__(cls, l, check_input = True): sage: P.parent() Standard permutations """ - import sage.combinat.tableau as tableau if isinstance(l, Permutation): return l elif isinstance(l, PermutationGroupElement): @@ -456,18 +466,18 @@ def __classcall_private__(cls, l, check_input = True): #if l is a pair of standard tableaux or a pair of lists elif isinstance(l, (tuple, list)) and len(l) == 2 and \ - all(isinstance(x, tableau.Tableau) for x in l): + all(isinstance(x, Tableau) for x in l): return RSK_inverse(*l, output='permutation') elif isinstance(l, (tuple, list)) and len(l) == 2 and \ all(isinstance(x, list) for x in l): - P,Q = [tableau.Tableau(_) for _ in l] + P,Q = [Tableau(_) for _ in l] return RSK_inverse(P, Q, 'permutation') # if it's a tuple or nonempty list of tuples, also assume cycle # notation elif isinstance(l, tuple) or \ (isinstance(l, list) and l and all(isinstance(x, tuple) for x in l)): - if l and (isinstance(l[0], (int,Integer)) or len(l[0]) > 0): + if l and (isinstance(l[0], (int, Integer)) or len(l[0]) > 0): if isinstance(l[0], tuple): n = max(max(x) for x in l) return from_cycles(n, [list(x) for x in l]) @@ -477,12 +487,13 @@ def __classcall_private__(cls, l, check_input = True): elif len(l) <= 1: return Permutations()([]) else: - raise ValueError("cannot convert l (= %s) to a Permutation"%l) + raise ValueError("cannot convert l (= %s) to a Permutation" % l) # otherwise, it gets processed by CombinatorialElement's __init__. - return Permutations()(l, check_input=check_input) + return Permutations()(l, check=check) - def __init__(self, parent, l, check_input=True): + @rename_keyword(deprecation=35233, check_input='check') + def __init__(self, parent, l, check=True): """ Constructor. Checks that INPUT is not a mess, and calls :class:`CombinatorialElement`. It should not, because @@ -492,7 +503,7 @@ def __init__(self, parent, l, check_input=True): - ``l`` -- a list of ``int`` variables - - ``check_input`` (boolean) -- whether to check that input is + - ``check`` (boolean) -- whether to check that input is correct. Slows the function down, but ensures that nothing bad happens. @@ -519,7 +530,7 @@ def __init__(self, parent, l, check_input=True): """ l = list(l) - if check_input and len(l) > 0: + if check and len(l) > 0: # Make a copy to sort later lst = list(l) @@ -537,10 +548,10 @@ def __init__(self, parent, l, check_input=True): # Is the maximum element of the permutation the length of input, # or is some integer missing ? if int(lst[-1]) != len(lst): - raise ValueError("The permutation has length "+str(len(lst))+ - " but its maximal element is "+ - str(int(lst[-1]))+". Some element "+ - "may be repeated, or an element is missing"+ + raise ValueError("The permutation has length "+str(len(lst)) + + " but its maximal element is " + + str(int(lst[-1]))+". Some element " + + "may be repeated, or an element is missing" + ", but there is something wrong with its length.") # Do the elements appear only once ? @@ -588,7 +599,7 @@ def __hash__(self): """ try: return hash(tuple(self._list)) - except Exception: + except TypeError: return hash(str(self._list)) def __str__(self) -> str: @@ -691,11 +702,11 @@ def _gap_(self, gap): EXAMPLES:: - sage: gap(Permutation([1,2,3])) + sage: gap(Permutation([1,2,3])) # optional - sage.libs.gap () - sage: gap(Permutation((1,2,3))) + sage: gap(Permutation((1,2,3))) # optional - sage.libs.gap (1,2,3) - sage: type(_) + sage: type(_) # optional - sage.libs.gap <class 'sage.interfaces.gap.GapElement'> """ return self.to_permutation_group_element()._gap_(gap) @@ -782,7 +793,7 @@ def __next__(self): #Reverse the list between first and the end first_half = p[:first+1] - last_half = p[first+1:] + last_half = p[first+1:] last_half.reverse() p = first_half + last_half @@ -833,17 +844,17 @@ def prev(self): if first == -1: return False - #Starting from the end, find the first j such that p[j] < p[first] + # Starting from the end, find the first j such that p[j] < p[first] j = n - 1 while p[j] > p[first]: j -= 1 - #Swap positions first and j + # Swap positions first and j (p[j], p[first]) = (p[first], p[j]) - #Reverse the list between first+1 and end + # Reverse the list between first+1 and end first_half = p[:first+1] - last_half = p[first+1:] + last_half = p[first+1:] last_half.reverse() p = first_half + last_half @@ -859,21 +870,20 @@ def to_tableau_by_shape(self, shape): EXAMPLES:: - sage: Permutation([3,4,1,2,5]).to_tableau_by_shape([3,2]) + sage: T = Permutation([3,4,1,2,5]).to_tableau_by_shape([3,2]); T # optional - sage.combinat [[1, 2, 5], [3, 4]] - sage: Permutation([3,4,1,2,5]).to_tableau_by_shape([3,2]).reading_word_permutation() + sage: T.reading_word_permutation() # optional - sage.combinat [3, 4, 1, 2, 5] """ - import sage.combinat.tableau as tableau if sum(shape) != len(self): raise ValueError("the size of the partition must be the size of self") t = [] w = list(self) for i in reversed(shape): - t = [ w[:i] ] + t + t = [w[:i]] + t w = w[i:] - return tableau.Tableau(t) + return Tableau(t) def to_cycles(self, singletons=True, use_min=True): """ @@ -970,8 +980,8 @@ def to_cycles(self, singletons=True, use_min=True): cycle = [cycleFirst] l[i], next = False, l[i] while next != cycleFirst: - cycle.append( next ) - l[next - 1], next = False, l[next - 1] + cycle.append(next) + l[next - 1], next = False, l[next - 1] # Add the cycle to the list of cycles if singletons or len(cycle) > 1: cycles.append(tuple(cycle)) @@ -994,8 +1004,8 @@ def _to_cycles_orig(self, singletons=True): cycles = [] toConsider = -1 - #Create the list [1,2,...,len(p)] - l = [ i+1 for i in range(len(p))] + # Create the list [1,2,...,len(p)] + l = [i + 1 for i in range(len(p))] cycle = [] #Go through until we've considered every number between @@ -1014,7 +1024,7 @@ def _to_cycles_orig(self, singletons=True): #Start with the first element in the list toConsider = l[0] l.remove(toConsider) - cycle = [ toConsider ] + cycle = [toConsider] cycleFirst = toConsider #Figure out where the element under consideration @@ -1026,8 +1036,8 @@ def _to_cycles_orig(self, singletons=True): if next == cycleFirst: toConsider = -1 else: - cycle.append( next ) - l.remove( next ) + cycle.append(next) + l.remove(next) toConsider = next # When we're finished, add the last cycle @@ -1061,7 +1071,7 @@ def _to_cycles_set(self, singletons=True): if not singletons: #remove the fixed points - L = set( i+1 for i,pi in enumerate(p) if pi != i+1 ) + L = set(i+1 for i,pi in enumerate(p) if pi != i+1) else: L = set(range(1,len(p)+1)) @@ -1131,9 +1141,9 @@ def to_permutation_group_element(self): EXAMPLES:: - sage: Permutation([2,1,4,3]).to_permutation_group_element() + sage: Permutation([2,1,4,3]).to_permutation_group_element() # optional - sage.groups (1,2)(3,4) - sage: Permutation([1,2,3]).to_permutation_group_element() + sage: Permutation([1,2,3]).to_permutation_group_element() # optional - sage.groups () """ grp = SymmetricGroup(len(self)) @@ -1182,14 +1192,14 @@ def to_matrix(self): EXAMPLES:: - sage: Permutation([1,2,3]).to_matrix() + sage: Permutation([1,2,3]).to_matrix() # optional - sage.modules [1 0 0] [0 1 0] [0 0 1] Alternatively:: - sage: matrix(Permutation([1,3,2])) + sage: matrix(Permutation([1,3,2])) # optional - sage.modules [1 0 0] [0 0 1] [0 1 0] @@ -1202,16 +1212,16 @@ def to_matrix(self): sage: Permutations.options.mult='r2l' sage: p = Permutation([2,1,3]) sage: q = Permutation([3,1,2]) - sage: (p*q).to_matrix() + sage: (p*q).to_matrix() # optional - sage.modules [0 0 1] [0 1 0] [1 0 0] - sage: p.to_matrix()*q.to_matrix() + sage: p.to_matrix()*q.to_matrix() # optional - sage.modules [0 0 1] [0 1 0] [1 0 0] sage: Permutations.options.mult='l2r' - sage: (p*q).to_matrix() + sage: (p*q).to_matrix() # optional - sage.modules [1 0 0] [0 0 1] [0 1 0] @@ -1232,17 +1242,33 @@ def to_alternating_sign_matrix(self): EXAMPLES:: - sage: m = Permutation([1,2,3]).to_alternating_sign_matrix(); m + sage: m = Permutation([1,2,3]).to_alternating_sign_matrix(); m # optional - sage.combinat sage.modules [1 0 0] [0 1 0] [0 0 1] - sage: parent(m) + sage: parent(m) # optional - sage.combinat sage.modules Alternating sign matrices of size 3 """ from sage.combinat.alternating_sign_matrix import AlternatingSignMatrix return AlternatingSignMatrix(self.to_matrix().rows()) - def __mul__(self, rp) -> Permutation: + def __mul__(self, rp): + """ + TESTS:: + + sage: SGA = SymmetricGroupAlgebra(QQ, 3) # optional - sage.combinat sage.modules + sage: SM = SGA.specht_module([2,1]) # optional - sage.combinat sage.modules + sage: p213 = Permutations(3)([2,1,3]) # optional - sage.combinat sage.modules + sage: p213 * SGA.an_element() # optional - sage.combinat sage.modules + 3*[1, 2, 3] + [1, 3, 2] + [2, 1, 3] + 2*[3, 1, 2] + sage: p213 * SM.an_element() # optional - sage.combinat sage.modules + 2*B[0] - 4*B[1] + """ + if not isinstance(rp, Permutation) and isinstance(rp, Element): + return get_coercion_model().bin_op(self, rp, operator.mul) + return Permutation._mul_(self, rp) + + def _mul_(self, rp) -> Permutation: """ TESTS:: @@ -1261,8 +1287,6 @@ def __mul__(self, rp) -> Permutation: else: return self._left_to_right_multiply_on_left(rp) - _mul_ = __mul__ # For ``prod()`` - def __rmul__(self, lp) -> Permutation: """ TESTS:: @@ -1276,7 +1300,13 @@ def __rmul__(self, lp) -> Permutation: sage: p213*p312 [3, 2, 1] sage: Permutations.options.mult='l2r' + + sage: SGA = SymmetricGroupAlgebra(QQ, 3) # optional - sage.combinat sage.modules + sage: SGA.an_element() * Permutations(3)(p213) # optional - sage.combinat sage.modules + 3*[1, 2, 3] + [2, 1, 3] + 2*[2, 3, 1] + [3, 2, 1] """ + if not isinstance(lp, Permutation) and isinstance(lp, Element): + return get_coercion_model().bin_op(lp, self, operator.mul) if self.parent().options.mult == 'l2r': return self._left_to_right_multiply_on_left(lp) else: @@ -1376,10 +1406,9 @@ def __call__(self, i): ... TypeError: i (= 10) must be between 1 and 7 """ - if isinstance(i,(int,Integer)) and 1 <= i <= len(self): - return self[i-1] - else: - raise TypeError("i (= %s) must be between %s and %s" % (i,1,len(self))) + if isinstance(i, (int, Integer)) and 1 <= i <= len(self): + return self[i - 1] + raise TypeError("i (= %s) must be between 1 and %s" % (i, len(self))) ######## # Rank # @@ -1447,26 +1476,25 @@ def to_inversion_vector(self): l = len(p) # lightning fast if the length is less than 3 # (is it really useful?) - if l<4: - if l==0: + if l < 4: + if l == 0: return [] - if l==1: + if l == 1: return [0] - if l==2: - return [p[0]-1,0] - if l==3: - if p[0]==1: - return [0,p[1]-2,0] - if p[0]==2: - if p[1]==1: - return [1,0,0] - return [2,0,0] - return [p[1],1,0] + if l == 2: + return [p[0] - 1, 0] + if l == 3: + if p[0] == 1: + return [0, p[1] - 2, 0] + if p[0] == 2: + if p[1] == 1: + return [1, 0, 0] + return [2, 0, 0] + return [p[1], 1, 0] # choose the best one - if l<411: + if l < 411: return self._to_inversion_vector_small() - else: - return self._to_inversion_vector_divide_and_conquer() + return self._to_inversion_vector_divide_and_conquer() def _to_inversion_vector_orig(self): r""" @@ -1489,8 +1517,8 @@ def _to_inversion_vector_orig(self): iv = [0]*len(p) for i in range(len(p)): for pj in p: - if pj>i+1: - iv[i]+=1 + if pj > i+1: + iv[i] += 1 elif pj == i+1: break return iv @@ -1570,21 +1598,21 @@ def merge_and_countv(ivA_A, ivB_B): def base_case(L): s = sorted(L) - d = dict((j,i) for (i,j) in enumerate(s)) + d = dict((j, i) for i, j in enumerate(s)) iv = [0]*len(L) checked = [1]*len(L) for pi in reversed(L): dpi = d[pi] checked[dpi] = 0 iv[dpi] = sum(checked[dpi:]) - return iv,s + return iv, s def sort_and_countv(L): - if len(L)<250: + if len(L) < 250: return base_case(L) - l = len(L)//2 - return merge_and_countv( sort_and_countv(L[:l]), - sort_and_countv(L[l:]) ) + l = len(L) // 2 + return merge_and_countv(sort_and_countv(L[:l]), + sort_and_countv(L[l:])) return sort_and_countv(self._list)[0] @@ -1603,7 +1631,7 @@ def inversions(self) -> list: p = self[:] n = len(p) return [tuple([i+1,j+1]) for i in range(n-1) for j in range(i+1,n) - if p[i]>p[j]] + if p[i] > p[j]] def stack_sort(self) -> Permutation: """ @@ -1654,18 +1682,19 @@ def to_digraph(self) -> DiGraph: EXAMPLES:: - sage: d = Permutation([3, 1, 2]).to_digraph() - sage: d.edges(sort=True, labels=False) + sage: d = Permutation([3, 1, 2]).to_digraph() # optional - sage.graphs + sage: d.edges(sort=True, labels=False) # optional - sage.graphs [(1, 3), (2, 1), (3, 2)] sage: P = Permutations(range(1, 10)) - sage: d = Permutation(P.random_element()).to_digraph() - sage: all(c.is_cycle() for c in d.strongly_connected_components_subgraphs()) + sage: d = Permutation(P.random_element()).to_digraph() # optional - sage.graphs + sage: all(c.is_cycle() # optional - sage.graphs + ....: for c in d.strongly_connected_components_subgraphs()) True TESTS:: - sage: d = Permutation([1]).to_digraph() - sage: d.edges(sort=True, labels=False) + sage: d = Permutation([1]).to_digraph() # optional - sage.graphs + sage: d.edges(sort=True, labels=False) # optional - sage.graphs [(1, 1)] """ return DiGraph([self, enumerate(self, start=1)], @@ -1696,14 +1725,16 @@ def show(self, representation="cycles", orientation="landscape", **args): EXAMPLES:: - sage: Permutations(20).random_element().show(representation = "cycles") - sage: Permutations(20).random_element().show(representation = "chord-diagram") - sage: Permutations(20).random_element().show(representation = "braid") - sage: Permutations(20).random_element().show(representation = "braid", orientation='portrait') + sage: P20 = Permutations(20) + sage: P20.random_element().show(representation="cycles") # optional - sage.graphs sage.plot + sage: P20.random_element().show(representation="chord-diagram") # optional - sage.graphs sage.plot + sage: P20.random_element().show(representation="braid") # optional - sage.plot + sage: P20.random_element().show(representation="braid", # optional - sage.plot + ....: orientation='portrait') TESTS:: - sage: Permutations(20).random_element().show(representation = "modern_art") + sage: P20.random_element().show(representation="modern_art") Traceback (most recent call last): ... ValueError: The value of 'representation' must be equal to 'cycles', 'chord-diagram' or 'braid' @@ -1714,7 +1745,7 @@ def show(self, representation="cycles", orientation="landscape", **args): if representation == "cycles": d.show(**args) else: - d.show(layout = "circular", **args) + d.show(layout="circular", **args) elif representation == "braid": from sage.plot.line import line @@ -1725,20 +1756,20 @@ def show(self, representation="cycles", orientation="landscape", **args): elif orientation == "portrait": r = lambda x,y : (-y,x) else: - raise ValueError("The value of 'orientation' must be either "+ + raise ValueError("The value of 'orientation' must be either " + "'landscape' or 'portrait'.") p = self[:] - L = line([r(1,1)]) + L = line([r(1, 1)]) for i in range(len(p)): - L += line([r(i,1.0), r(p[i]-1,0)]) - L += text(str(i), r(i,1.05)) + text(str(i), r(p[i]-1,-.05)) + L += line([r(i, 1.0), r(p[i]-1, 0)]) + L += text(str(i), r(i, 1.05)) + text(str(i), r(p[i]-1, -.05)) - return L.show(axes = False, **args) + return L.show(axes=False, **args) else: - raise ValueError("The value of 'representation' must be equal to "+ + raise ValueError("The value of 'representation' must be equal to " + "'cycles', 'chord-diagram' or 'braid'") def number_of_inversions(self) -> Integer: @@ -1882,7 +1913,7 @@ def absolute_length(self) -> Integer: EXAMPLES:: - sage: Permutation([4,2,3,1]).absolute_length() + sage: Permutation([4,2,3,1]).absolute_length() # optional - sage.combinat 1 """ return self.size() - len(self.cycle_type()) @@ -1902,8 +1933,8 @@ def inverse(self) -> Permutation: [3, 1, 5, 2, 4] """ w = list(range(len(self))) - for i,j in enumerate(self): - w[j-1] = i+1 + for i, j in enumerate(self): + w[j - 1] = i + 1 return Permutations()(w) __invert__ = inverse @@ -1947,9 +1978,9 @@ def _icondition(self, i): """ if i not in range(2, len(self)): raise ValueError("i (= %s) must be between 2 and n-1" % i) - pos_i = self.index(i) - pos_ip1 = self.index(i+1) - pos_im1 = self.index(i-1) + pos_i = self.index(i) + pos_ip1 = self.index(i + 1) + pos_im1 = self.index(i - 1) if pos_i < pos_im1 and pos_im1 < pos_ip1: state = '213' @@ -2001,22 +2032,22 @@ def ishift(self, i): state, pos_im1, pos_i, pos_ip1 = state l = list(self) - if state == '213': #goes to 132 - l[pos_i] = i-1 - l[pos_im1] = i+1 + if state == '213': # goes to 132 + l[pos_i] = i - 1 + l[pos_im1] = i + 1 l[pos_ip1] = i - elif state == '132': #goes to 213 + elif state == '132': # goes to 213 l[pos_im1] = i - l[pos_ip1] = i-1 - l[pos_i] = i+1 - elif state == '231': #goes to 312 - l[pos_i] = i+1 - l[pos_ip1] = i-1 + l[pos_ip1] = i - 1 + l[pos_i] = i + 1 + elif state == '231': # goes to 312 + l[pos_i] = i + 1 + l[pos_ip1] = i - 1 l[pos_im1] = i - elif state == '312': #goes to 231 + elif state == '312': # goes to 231 l[pos_ip1] = i - l[pos_im1] = i+1 - l[pos_i] = i-1 + l[pos_im1] = i + 1 + l[pos_i] = i - 1 else: # This branch should never occur, no matter what the user does. raise ValueError("invalid state") @@ -2055,7 +2086,7 @@ def iswitch(self, i): [1, 2, 3] """ if i not in range(2, len(self)): - raise ValueError("i (= %s) must between 2 and n-1"%i) + raise ValueError("i (= %s) must between 2 and n-1" % i) state = self._icondition(i) if state[0] is None: @@ -2064,18 +2095,18 @@ def iswitch(self, i): state, pos_im1, pos_i, pos_ip1 = state l = list(self) - if state == '213': #goes to 312 - l[pos_i] = i+1 + if state == '213': # goes to 312 + l[pos_i] = i + 1 l[pos_ip1] = i - elif state == '132': #goes to 231 + elif state == '132': # goes to 231 l[pos_im1] = i - l[pos_i] = i-1 - elif state == '231': #goes to 132 - l[pos_i] = i-1 + l[pos_i] = i - 1 + elif state == '231': # goes to 132 + l[pos_i] = i - 1 l[pos_im1] = i - elif state == '312': #goes to 213 + elif state == '312': # goes to 213 l[pos_ip1] = i - l[pos_i] = i+1 + l[pos_i] = i + 1 else: # This branch should never occur, no matter what the user does. raise ValueError("invalid state") @@ -2191,7 +2222,8 @@ def longest_increasing_subsequence_length(self) -> Integer: sage: Permutation([2,3,1,4]).longest_increasing_subsequence_length() 3 - sage: all(i.longest_increasing_subsequence_length() == len(RSK(i)[0][0]) for i in Permutations(5)) + sage: all(i.longest_increasing_subsequence_length() == len(RSK(i)[0][0]) # optional - sage.combinat + ....: for i in Permutations(5)) True sage: Permutation([]).longest_increasing_subsequence_length() 0 @@ -2222,9 +2254,9 @@ def longest_increasing_subsequences(self): EXAMPLES:: - sage: Permutation([2,3,4,1]).longest_increasing_subsequences() + sage: Permutation([2,3,4,1]).longest_increasing_subsequences() # optional - sage.graphs [[2, 3, 4]] - sage: Permutation([5, 7, 1, 2, 6, 4, 3]).longest_increasing_subsequences() + sage: Permutation([5, 7, 1, 2, 6, 4, 3]).longest_increasing_subsequences() # optional - sage.graphs [[1, 2, 6], [1, 2, 4], [1, 2, 3]] .. NOTE:: @@ -2282,16 +2314,17 @@ def longest_increasing_subsequences_number(self): The algorithm is similar to :meth:`longest_increasing_subsequences`. Namely, the longest increasing subsequences are encoded as increasing sequences in a ranked poset from a smallest to a largest element. Their - number can be obtained via dynamic programming : for each `v` in the poset + number can be obtained via dynamic programming: for each `v` in the poset we compute the number of paths from a smallest element to `v`. EXAMPLES:: - sage: sum(p.longest_increasing_subsequences_number() for p in Permutations(8)) + sage: sum(p.longest_increasing_subsequences_number() + ....: for p in Permutations(8)) 120770 sage: p = Permutations(50).random_element() - sage: (len(p.longest_increasing_subsequences()) == + sage: (len(p.longest_increasing_subsequences()) == # optional - sage.graphs ....: p.longest_increasing_subsequences_number()) True """ @@ -2330,7 +2363,7 @@ def cycle_type(self): EXAMPLES:: - sage: Permutation([3,1,2,4]).cycle_type() + sage: Permutation([3,1,2,4]).cycle_type() # optional - sage.combinat [3, 1] """ cycle_type = [len(c) for c in self.to_cycles()] @@ -2388,9 +2421,9 @@ def forget_cycles(self): results as a poset under the Bruhat order:: sage: l = [p.forget_cycles().inverse() for p in l] - sage: B = Poset([l, lambda x,y: x.bruhat_lequal(y)]) + sage: B = Poset([l, lambda x,y: x.bruhat_lequal(y)]) # optional - sage.combinat sage.graphs sage: R.<q> = QQ[] - sage: sum(q^B.rank_function()(x) for x in B) + sage: sum(q^B.rank_function()(x) for x in B) # optional - sage.combinat sage.graphs q^5 + 2*q^4 + 3*q^3 + 3*q^2 + 2*q + 1 We check the statement in [CC2013]_ that the posets @@ -2398,8 +2431,8 @@ def forget_cycles(self): sage: l2 = [p for p in P if [len(t) for t in p.to_cycles()] == [1,3,1,1]] sage: l2 = [p.forget_cycles().inverse() for p in l2] - sage: B2 = Poset([l2, lambda x,y: x.bruhat_lequal(y)]) - sage: B.is_isomorphic(B2) + sage: B2 = Poset([l2, lambda x,y: x.bruhat_lequal(y)]) # optional - sage.combinat sage.graphs + sage: B.is_isomorphic(B2) # optional - sage.combinat sage.graphs True .. SEEALSO:: @@ -2710,7 +2743,7 @@ def destandardize(self, weight, ordered_alphabet=None): - ``weight`` -- list or tuple of nonnegative integers that sum to `n` if ``self`` is a permutation in `S_n`. - - ``ordered_alphabet`` -- (default: None) a list or tuple specifying the ordered alphabet the + - ``ordered_alphabet`` -- (default: ``None``) a list or tuple specifying the ordered alphabet the destandardized word is over OUTPUT: word over the ``ordered_alphabet`` which standardizes to ``self`` @@ -2725,7 +2758,7 @@ def destandardize(self, weight, ordered_alphabet=None): EXAMPLES:: sage: p = Permutation([1,2,5,3,6,4]) - sage: p.destandardize([3,1,2]) + sage: p.destandardize([3,1,2]) # optional - sage.combinat word: 113132 sage: p = Permutation([2,1,3]) sage: p.destandardize([2,1]) @@ -2736,7 +2769,7 @@ def destandardize(self, weight, ordered_alphabet=None): TESTS:: sage: p = Permutation([4,1,2,3,5,6]) - sage: p.destandardize([2,1,3], ordered_alphabet = [1,'a',3]) + sage: p.destandardize([2,1,3], ordered_alphabet = [1,'a',3]) # optional - sage.combinat word: 311a33 sage: p.destandardize([2,1,3], ordered_alphabet = [1,'a']) Traceback (most recent call last): @@ -2800,7 +2833,7 @@ def to_lehmer_code(self) -> list: """ l = len(self._list) # choose the best implementations - if l<577: + if l < 577: return self._to_lehmer_code_small() else: return self.inverse().to_inversion_vector() @@ -2982,7 +3015,7 @@ def reduced_word_lexmin(self): rw = [] for i in range(len(cocode)): - piece = [j+1 for j in range(i-cocode[i],i)] + piece = [j + 1 for j in range(i-cocode[i], i)] piece.reverse() rw += piece @@ -2995,9 +3028,9 @@ def rothe_diagram(self): EXAMPLES:: sage: p = Permutation([4,2,1,3]) - sage: D = p.rothe_diagram(); D + sage: D = p.rothe_diagram(); D # optional - sage.combinat [(0, 0), (0, 1), (0, 2), (1, 0)] - sage: D.pp() + sage: D.pp() # optional - sage.combinat O O O . O . . . . . . . @@ -3014,7 +3047,7 @@ def number_of_reduced_words(self): EXAMPLES:: sage: p = Permutation([6,4,2,5,1,8,3,7]) - sage: len(p.reduced_words()) == p.number_of_reduced_words() + sage: len(p.reduced_words()) == p.number_of_reduced_words() # optional - sage.combinat True """ Tx = self.rothe_diagram().peelable_tableaux() @@ -3054,7 +3087,7 @@ def number_of_fixed_points(self) -> Integer: def is_derangement(self) -> bool: r""" - Return if ``self`` is a derangement. + Return whether ``self`` is a derangement. A permutation `\sigma` is a derangement if `\sigma` has no fixed points. @@ -3070,6 +3103,74 @@ def is_derangement(self) -> bool: """ return not self.fixed_points() + def is_simple(self) -> bool: + """ + Return whether ``self`` is simple. + + A permutation is simple if it does not send any proper sub-interval + to a sub-interval. + + For instance, ``[6,1,3,5,2,4]`` is not simple because it maps the + interval ``[3,4,5,6]`` to ``[2,3,4,5]``, whereas ``[2,6,3,5,1,4]`` is + simple. + + See :oeis:`A111111` + + EXAMPLES:: + + sage: g = Permutation([4,2,3,1]) + sage: g.is_simple() + False + + sage: g = Permutation([6,1,3,5,2,4]) + sage: g.is_simple() + False + + sage: g = Permutation([2,6,3,5,1,4]) + sage: g.is_simple() + True + + sage: [len([pi for pi in Permutations(n) if pi.is_simple()]) + ....: for n in range(6)] + [1, 1, 2, 0, 2, 6] + """ + n = len(self) + if n <= 2: + return True + + # testing intervals starting at position 0 + left = right = self._list[0] + end = 1 + while end < n - 1: + elt = self._list[end] + if elt < left: + left = elt + elif elt > right: + right = elt + if right - left == end: + return False + elif right - left == n - 1: + break + end += 1 + + # testing intervals starting at later positions + for start in range(1, n - 1): + left = right = self._list[start] + end = start + 1 + while end < n: + elt = self._list[end] + if elt < left: + left = elt + elif elt > right: + right = elt + if right - left == end - start: + return False + elif right - left > n - 1 - start: + break + end += 1 + + return True + ############ # Recoils # ############ @@ -3092,9 +3193,9 @@ def recoils(self) -> list: [] """ p = self - recoils = [] + recoils = [] for i in range(len(p)): - if p[i] != len(self) and self.index(p[i]+1) < i: + if p[i] != len(self) and self.index(p[i] + 1) < i: recoils.append(i) return recoils @@ -3729,16 +3830,16 @@ def bruhat_inversions_iterator(self): p = self n = len(p) - for i in range(n-1): - for j in range(i+1,n): + for i in range(n - 1): + for j in range(i + 1, n): if p[i] > p[j]: ok = True - for k in range(i+1, j): + for k in range(i + 1, j): if p[i] > p[k] and p[k] > p[j]: ok = False break if ok: - yield [i,j] + yield [i, j] def bruhat_succ(self) -> list: r""" @@ -4129,8 +4230,10 @@ def right_permutohedron_interval_iterator(self, other): EXAMPLES:: - sage: Permutation([2, 1, 4, 5, 3]).right_permutohedron_interval(Permutation([2, 5, 4, 1, 3])) # indirect doctest - [[2, 4, 5, 1, 3], [2, 4, 1, 5, 3], [2, 1, 4, 5, 3], [2, 1, 5, 4, 3], [2, 5, 1, 4, 3], [2, 5, 4, 1, 3]] + sage: p = Permutation([2, 1, 4, 5, 3]); q = Permutation([2, 5, 4, 1, 3]) + sage: p.right_permutohedron_interval(q) # indirect doctest # optional - sage.graphs sage.modules sage.rings.finite_rings + [[2, 4, 5, 1, 3], [2, 4, 1, 5, 3], [2, 1, 4, 5, 3], + [2, 1, 5, 4, 3], [2, 5, 1, 4, 3], [2, 5, 4, 1, 3]] """ if len(self) != len(other): raise ValueError("len({}) and len({}) must be equal".format(self, other)) @@ -4154,24 +4257,28 @@ def right_permutohedron_interval(self, other): EXAMPLES:: - sage: Permutation([2, 1, 4, 5, 3]).right_permutohedron_interval(Permutation([2, 5, 4, 1, 3])) - [[2, 4, 5, 1, 3], [2, 4, 1, 5, 3], [2, 1, 4, 5, 3], [2, 1, 5, 4, 3], [2, 5, 1, 4, 3], [2, 5, 4, 1, 3]] + sage: p = Permutation([2, 1, 4, 5, 3]); q = Permutation([2, 5, 4, 1, 3]) + sage: p.right_permutohedron_interval(q) # optional - sage.graphs sage.modules sage.rings.finite_rings + [[2, 4, 5, 1, 3], [2, 4, 1, 5, 3], [2, 1, 4, 5, 3], + [2, 1, 5, 4, 3], [2, 5, 1, 4, 3], [2, 5, 4, 1, 3]] TESTS:: - sage: Permutation([]).right_permutohedron_interval(Permutation([])) + sage: Permutation([]).right_permutohedron_interval(Permutation([])) # optional - sage.graphs sage.modules sage.rings.finite_rings [[]] - sage: Permutation([3, 1, 2]).right_permutohedron_interval(Permutation([3, 1, 2])) + sage: Permutation([3, 1, 2]).right_permutohedron_interval(Permutation([3, 1, 2])) # optional - sage.graphs sage.modules sage.rings.finite_rings [[3, 1, 2]] - sage: Permutation([1, 3, 2, 4]).right_permutohedron_interval(Permutation([3, 4, 2, 1])) - [[3, 1, 4, 2], [3, 4, 1, 2], [3, 4, 2, 1], [1, 3, 4, 2], [1, 3, 2, 4], [3, 2, 4, 1], [3, 2, 1, 4], [3, 1, 2, 4]] - sage: Permutation([2, 1, 4, 5, 3]).right_permutohedron_interval(Permutation([2, 5, 4, 1, 3])) - [[2, 4, 5, 1, 3], [2, 4, 1, 5, 3], [2, 1, 4, 5, 3], [2, 1, 5, 4, 3], [2, 5, 1, 4, 3], [2, 5, 4, 1, 3]] - sage: Permutation([2, 5, 4, 1, 3]).right_permutohedron_interval(Permutation([2, 1, 4, 5, 3])) + sage: Permutation([1, 3, 2, 4]).right_permutohedron_interval(Permutation([3, 4, 2, 1])) # optional - sage.graphs sage.modules sage.rings.finite_rings + [[3, 1, 4, 2], [3, 4, 1, 2], [3, 4, 2, 1], [1, 3, 4, 2], + [1, 3, 2, 4], [3, 2, 4, 1], [3, 2, 1, 4], [3, 1, 2, 4]] + sage: Permutation([2, 1, 4, 5, 3]).right_permutohedron_interval(Permutation([2, 5, 4, 1, 3])) # optional - sage.graphs sage.modules sage.rings.finite_rings + [[2, 4, 5, 1, 3], [2, 4, 1, 5, 3], [2, 1, 4, 5, 3], + [2, 1, 5, 4, 3], [2, 5, 1, 4, 3], [2, 5, 4, 1, 3]] + sage: Permutation([2, 5, 4, 1, 3]).right_permutohedron_interval(Permutation([2, 1, 4, 5, 3])) # optional - sage.graphs sage.modules sage.rings.finite_rings Traceback (most recent call last): ... ValueError: [2, 5, 4, 1, 3] must be lower or equal than [2, 1, 4, 5, 3] for the right permutohedron order - sage: Permutation([2, 4, 1, 3]).right_permutohedron_interval(Permutation([2, 1, 4, 5, 3])) + sage: Permutation([2, 4, 1, 3]).right_permutohedron_interval(Permutation([2, 1, 4, 5, 3])) # optional - sage.graphs sage.modules sage.rings.finite_rings Traceback (most recent call last): ... ValueError: len([2, 4, 1, 3]) and len([2, 1, 4, 5, 3]) must be equal @@ -4271,7 +4378,7 @@ def permutohedron_join(self, other, side="right") -> Permutation: sage: p.permutohedron_join(p) [1] - The left permutohedron: + The left permutohedron:: sage: p = Permutation([3,1,2]) sage: q = Permutation([1,3,2]) @@ -4387,7 +4494,7 @@ def permutohedron_meet(self, other, side="right") -> Permutation: sage: p.permutohedron_meet(p) [1] - The left permutohedron: + The left permutohedron:: sage: p = Permutation([3,1,2]) sage: q = Permutation([1,3,2]) @@ -4410,7 +4517,7 @@ def has_pattern(self, patt) -> bool: EXAMPLES:: - sage: Permutation([3,5,1,4,6,2]).has_pattern([1,3,2]) + sage: Permutation([3,5,1,4,6,2]).has_pattern([1,3,2]) # optional - sage.combinat True """ p = self @@ -4430,11 +4537,11 @@ def avoids(self, patt) -> bool: EXAMPLES:: - sage: Permutation([6,2,5,4,3,1]).avoids([4,2,3,1]) + sage: Permutation([6,2,5,4,3,1]).avoids([4,2,3,1]) # optional - sage.combinat False - sage: Permutation([6,1,2,5,4,3]).avoids([4,2,3,1]) + sage: Permutation([6,1,2,5,4,3]).avoids([4,2,3,1]) # optional - sage.combinat True - sage: Permutation([6,1,2,5,4,3]).avoids([3,4,1,2]) + sage: Permutation([6,1,2,5,4,3]).avoids([3,4,1,2]) # optional - sage.combinat True """ return not self.has_pattern(patt) @@ -4446,7 +4553,7 @@ def pattern_positions(self, patt) -> list: EXAMPLES:: - sage: Permutation([3,5,1,4,6,2]).pattern_positions([1,3,2]) + sage: Permutation([3,5,1,4,6,2]).pattern_positions([1,3,2]) # optional - sage.combinat [[0, 1, 3], [2, 3, 5], [2, 4, 5]] """ p = self @@ -4471,7 +4578,7 @@ def simion_schmidt(self, avoid=[1,2,3]): sage: P = Permutations(6) sage: p = P([4,5,1,6,3,2]) sage: pl = [ [1,2,3], [1,3,2], [3,1,2], [3,2,1] ] - sage: for q in pl: + sage: for q in pl: # optional - sage.combinat ....: s = p.simion_schmidt(q) ....: print("{} {}".format(s, s.has_pattern(q))) [4, 6, 1, 5, 3, 2] False @@ -4555,20 +4662,23 @@ def permutation_poset(self): EXAMPLES:: - sage: Permutation([3,1,5,4,2]).permutation_poset().cover_relations() + sage: Permutation([3,1,5,4,2]).permutation_poset().cover_relations() # optional - sage.combinat sage.graphs [[(2, 1), (5, 2)], [(2, 1), (3, 5)], [(2, 1), (4, 4)], [(1, 3), (3, 5)], [(1, 3), (4, 4)]] - sage: Permutation([]).permutation_poset().cover_relations() + sage: Permutation([]).permutation_poset().cover_relations() # optional - sage.combinat sage.graphs [] - sage: Permutation([1,3,2]).permutation_poset().cover_relations() + sage: Permutation([1,3,2]).permutation_poset().cover_relations() # optional - sage.combinat sage.graphs [[(1, 1), (2, 3)], [(1, 1), (3, 2)]] - sage: Permutation([1,2]).permutation_poset().cover_relations() + sage: Permutation([1,2]).permutation_poset().cover_relations() # optional - sage.combinat sage.graphs [[(1, 1), (2, 2)]] - sage: P = Permutation([1,5,2,4,3]) - sage: P.permutation_poset().greene_shape() == P.RS_partition() # This should hold for any P. + sage: P = Permutation([1,5,2,4,3]) # optional - sage.combinat sage.graphs + + This should hold for any `P`:: + + sage: P.permutation_poset().greene_shape() == P.RS_partition() # optional - sage.combinat sage.graphs True """ from sage.combinat.posets.posets import Poset @@ -4640,7 +4750,7 @@ def robinson_schensted(self): EXAMPLES:: - sage: Permutation([6,2,3,1,7,5,4]).robinson_schensted() + sage: Permutation([6,2,3,1,7,5,4]).robinson_schensted() # optional - sage.combinat [[[1, 3, 4], [2, 5], [6, 7]], [[1, 3, 5], [2, 6], [4, 7]]] """ return RSK(self, check_standard=True) @@ -4672,7 +4782,7 @@ def left_tableau(self): EXAMPLES:: - sage: Permutation([1,4,3,2]).left_tableau() + sage: Permutation([1,4,3,2]).left_tableau() # optional - sage.combinat [[1, 2], [3], [4]] """ return RSK(self, check_standard=True)[0] @@ -4685,7 +4795,7 @@ def right_tableau(self): EXAMPLES:: - sage: Permutation([1,4,3,2]).right_tableau() + sage: Permutation([1,4,3,2]).right_tableau() # optional - sage.combinat [[1, 2], [3], [4]] """ return RSK(self, check_standard=True)[1] @@ -4696,17 +4806,17 @@ def increasing_tree(self, compare=min): EXAMPLES:: - sage: Permutation([1,4,3,2]).increasing_tree() + sage: Permutation([1,4,3,2]).increasing_tree() # optional - sage.graphs 1[., 2[3[4[., .], .], .]] - sage: Permutation([4,1,3,2]).increasing_tree() + sage: Permutation([4,1,3,2]).increasing_tree() # optional - sage.graphs 1[4[., .], 2[3[., .], .]] By passing the option ``compare=max`` one can have the decreasing tree instead:: - sage: Permutation([2,3,4,1]).increasing_tree(max) + sage: Permutation([2,3,4,1]).increasing_tree(max) # optional - sage.graphs 4[3[2[., .], .], 1[., .]] - sage: Permutation([2,3,1,4]).increasing_tree(max) + sage: Permutation([2,3,1,4]).increasing_tree(max) # optional - sage.graphs 4[3[2[., .], 1[., .]], .] """ from sage.combinat.binary_tree import LabelledBinaryTree as LBT @@ -4716,7 +4826,7 @@ def rec(perm): return LBT(None) mn = compare(perm) k = perm.index(mn) - return LBT([rec(perm[:k]), rec(perm[k + 1:])], label = mn) + return LBT([rec(perm[:k]), rec(perm[k + 1:])], label=mn) return rec(self) @combinatorial_map(name="Increasing tree") @@ -4727,17 +4837,17 @@ def increasing_tree_shape(self, compare=min): EXAMPLES:: - sage: Permutation([1,4,3,2]).increasing_tree_shape() + sage: Permutation([1,4,3,2]).increasing_tree_shape() # optional - sage.graphs [., [[[., .], .], .]] - sage: Permutation([4,1,3,2]).increasing_tree_shape() + sage: Permutation([4,1,3,2]).increasing_tree_shape() # optional - sage.graphs [[., .], [[., .], .]] By passing the option ``compare=max`` one can have the decreasing tree instead:: - sage: Permutation([2,3,4,1]).increasing_tree_shape(max) + sage: Permutation([2,3,4,1]).increasing_tree_shape(max) # optional - sage.graphs [[[., .], .], [., .]] - sage: Permutation([2,3,1,4]).increasing_tree_shape(max) + sage: Permutation([2,3,1,4]).increasing_tree_shape(max) # optional - sage.graphs [[[., .], [., .]], .] """ return self.increasing_tree(compare).shape() @@ -4763,22 +4873,22 @@ def binary_search_tree(self, left_to_right=True): EXAMPLES:: - sage: Permutation([1,4,3,2]).binary_search_tree() + sage: Permutation([1,4,3,2]).binary_search_tree() # optional - sage.graphs 1[., 4[3[2[., .], .], .]] - sage: Permutation([4,1,3,2]).binary_search_tree() + sage: Permutation([4,1,3,2]).binary_search_tree() # optional - sage.graphs 4[1[., 3[2[., .], .]], .] By passing the option ``left_to_right=False`` one can have the insertion going from right to left:: - sage: Permutation([1,4,3,2]).binary_search_tree(False) + sage: Permutation([1,4,3,2]).binary_search_tree(False) # optional - sage.graphs 2[1[., .], 3[., 4[., .]]] - sage: Permutation([4,1,3,2]).binary_search_tree(False) + sage: Permutation([4,1,3,2]).binary_search_tree(False) # optional - sage.graphs 2[1[., .], 3[., 4[., .]]] TESTS:: - sage: Permutation([]).binary_search_tree() + sage: Permutation([]).binary_search_tree() # optional - sage.graphs . """ from sage.combinat.binary_tree import LabelledBinaryTree as LBT @@ -4791,7 +4901,7 @@ def binary_search_tree(self, left_to_right=True): res = res.binary_search_insert(i) return res - @combinatorial_map(name = "Binary search tree (left to right)") + @combinatorial_map(name="Binary search tree (left to right)") def binary_search_tree_shape(self, left_to_right=True): r""" Return the shape of the binary search tree of the permutation @@ -4799,17 +4909,17 @@ def binary_search_tree_shape(self, left_to_right=True): EXAMPLES:: - sage: Permutation([1,4,3,2]).binary_search_tree_shape() + sage: Permutation([1,4,3,2]).binary_search_tree_shape() # optional - sage.graphs [., [[[., .], .], .]] - sage: Permutation([4,1,3,2]).binary_search_tree_shape() + sage: Permutation([4,1,3,2]).binary_search_tree_shape() # optional - sage.graphs [[., [[., .], .]], .] By passing the option ``left_to_right=False`` one can have the insertion going from right to left:: - sage: Permutation([1,4,3,2]).binary_search_tree_shape(False) + sage: Permutation([1,4,3,2]).binary_search_tree_shape(False) # optional - sage.graphs [[., .], [., [., .]]] - sage: Permutation([4,1,3,2]).binary_search_tree_shape(False) + sage: Permutation([4,1,3,2]).binary_search_tree_shape(False) # optional - sage.graphs [[., .], [., [., .]]] """ from sage.combinat.binary_tree import binary_search_tree_shape @@ -4856,7 +4966,7 @@ def sylvester_class(self, left_to_right=False): The sylvester class of a permutation in `S_5`:: sage: p = Permutation([3, 5, 1, 2, 4]) - sage: sorted(p.sylvester_class()) + sage: sorted(p.sylvester_class()) # optional - sage.combinat [[1, 3, 2, 5, 4], [1, 3, 5, 2, 4], [1, 5, 3, 2, 4], @@ -4868,20 +4978,20 @@ def sylvester_class(self, left_to_right=False): The sylvester class of a permutation `p` contains `p`:: - sage: all( p in p.sylvester_class() for p in Permutations(4) ) + sage: all(p in p.sylvester_class() for p in Permutations(4)) # optional - sage.combinat sage.graphs True Small cases:: - sage: list(Permutation([]).sylvester_class()) + sage: list(Permutation([]).sylvester_class()) # optional - sage.combinat sage.graphs [[]] - sage: list(Permutation([1]).sylvester_class()) + sage: list(Permutation([1]).sylvester_class()) # optional - sage.combinat sage.graphs [[1]] The sylvester classes in `S_3`:: - sage: [sorted(p.sylvester_class()) for p in Permutations(3)] + sage: [sorted(p.sylvester_class()) for p in Permutations(3)] # optional - sage.combinat sage.graphs [[[1, 2, 3]], [[1, 3, 2], [3, 1, 2]], [[2, 1, 3]], @@ -4891,7 +5001,8 @@ def sylvester_class(self, left_to_right=False): The left sylvester classes in `S_3`:: - sage: [sorted(p.sylvester_class(left_to_right=True)) for p in Permutations(3)] + sage: [sorted(p.sylvester_class(left_to_right=True)) # optional - sage.combinat sage.graphs + ....: for p in Permutations(3)] [[[1, 2, 3]], [[1, 3, 2]], [[2, 1, 3], [2, 3, 1]], @@ -4902,7 +5013,7 @@ def sylvester_class(self, left_to_right=False): A left sylvester class in `S_5`:: sage: p = Permutation([4, 2, 1, 5, 3]) - sage: sorted(p.sylvester_class(left_to_right=True)) + sage: sorted(p.sylvester_class(left_to_right=True)) # optional - sage.combinat sage.graphs [[4, 2, 1, 3, 5], [4, 2, 1, 5, 3], [4, 2, 3, 1, 5], @@ -4925,7 +5036,7 @@ def RS_partition(self): EXAMPLES:: - sage: Permutation([1,4,3,2]).RS_partition() + sage: Permutation([1,4,3,2]).RS_partition() # optional - sage.combinat [2, 1, 1] """ return RSK(self)[1].shape() @@ -5147,15 +5258,16 @@ def hyperoctahedral_double_coset_type(self): EXAMPLES:: - sage: Permutation([3, 4, 6, 1, 5, 7, 2, 8]).hyperoctahedral_double_coset_type() + sage: p = Permutation([3, 4, 6, 1, 5, 7, 2, 8]) + sage: p.hyperoctahedral_double_coset_type() # optional - sage.combinat [3, 1] - sage: all(p.hyperoctahedral_double_coset_type() == + sage: all(p.hyperoctahedral_double_coset_type() == # optional - sage.combinat ....: p.inverse().hyperoctahedral_double_coset_type() ....: for p in Permutations(4)) True - sage: Permutation([]).hyperoctahedral_double_coset_type() + sage: Permutation([]).hyperoctahedral_double_coset_type() # optional - sage.combinat [] - sage: Permutation([3,1,2]).hyperoctahedral_double_coset_type() + sage: Permutation([3,1,2]).hyperoctahedral_double_coset_type() # optional - sage.combinat Traceback (most recent call last): ... ValueError: [3, 1, 2] is a permutation of odd size and has no coset-type @@ -5171,7 +5283,7 @@ def hyperoctahedral_double_coset_type(self): # Binary operations # ##################### - def shifted_concatenation(self, other, side = "right"): + def shifted_concatenation(self, other, side="right"): r""" Return the right (or left) shifted concatenation of ``self`` with a permutation ``other``. These operations are also known @@ -5232,21 +5344,23 @@ def shifted_shuffle(self, other): EXAMPLES:: - sage: Permutation([]).shifted_shuffle(Permutation([])) + sage: Permutation([]).shifted_shuffle(Permutation([])) # optional - sage.graphs [[]] - sage: Permutation([1, 2, 3]).shifted_shuffle(Permutation([1])) + sage: Permutation([1, 2, 3]).shifted_shuffle(Permutation([1])) # optional - sage.graphs sage.modules sage.rings.finite_rings [[4, 1, 2, 3], [1, 2, 3, 4], [1, 2, 4, 3], [1, 4, 2, 3]] - sage: Permutation([1, 2]).shifted_shuffle(Permutation([2, 1])) - [[4, 1, 3, 2], [4, 3, 1, 2], [1, 4, 3, 2], [1, 4, 2, 3], [1, 2, 4, 3], [4, 1, 2, 3]] - sage: Permutation([1]).shifted_shuffle([1]) + sage: Permutation([1, 2]).shifted_shuffle(Permutation([2, 1])) # optional - sage.graphs sage.modules sage.rings.finite_rings + [[4, 1, 3, 2], [4, 3, 1, 2], [1, 4, 3, 2], + [1, 4, 2, 3], [1, 2, 4, 3], [4, 1, 2, 3]] + sage: Permutation([1]).shifted_shuffle([1]) # optional - sage.graphs sage.modules sage.rings.finite_rings [[2, 1], [1, 2]] - sage: len(Permutation([3, 1, 5, 4, 2]).shifted_shuffle(Permutation([2, 1, 4, 3]))) + sage: p = Permutation([3, 1, 5, 4, 2]) + sage: len(p.shifted_shuffle(Permutation([2, 1, 4, 3]))) # optional - sage.graphs sage.modules sage.rings.finite_rings 126 The shifted shuffle product is associative. We can test this on an admittedly toy example:: - sage: all( all( all( sorted(flatten([abs.shifted_shuffle(c) + sage: all( all( all( sorted(flatten([abs.shifted_shuffle(c) # optional - sage.graphs sage.modules sage.rings.finite_rings ....: for abs in a.shifted_shuffle(b)])) ....: == sorted(flatten([a.shifted_shuffle(bcs) ....: for bcs in b.shifted_shuffle(c)])) @@ -5259,7 +5373,7 @@ def shifted_shuffle(self, other): permutations as the ``shifted_shuffle`` method on words (but is faster):: - sage: all( all( sorted(p1.shifted_shuffle(p2)) + sage: all( all( sorted(p1.shifted_shuffle(p2)) # optional - sage.graphs sage.modules sage.rings.finite_rings ....: == sorted([Permutation(p) for p in ....: Word(p1).shifted_shuffle(Word(p2))]) ....: for p2 in Permutations(3) ) @@ -5276,9 +5390,9 @@ def _tableau_contribution(T): EXAMPLES:: - sage: T = Tableau([[1,1,1],[2]]) + sage: T = Tableau([[1,1,1],[2]]) # optional - sage.combinat sage: from sage.combinat.permutation import _tableau_contribution - sage: _tableau_contribution(T) + sage: _tableau_contribution(T) # optional - sage.combinat 3 """ from sage.combinat.tableau import StandardTableaux @@ -5368,7 +5482,7 @@ class Permutations(UniqueRepresentation, Parent): sage: p = Permutations(['c', 'a', 't'], 2); p Permutations of the set ['c', 'a', 't'] of length 2 - sage: p.list() + sage: p.list() # optional - sage.libs.gap [['c', 'a'], ['c', 't'], ['a', 'c'], ['a', 't'], ['t', 'c'], ['t', 'a']] :: @@ -5382,27 +5496,29 @@ class Permutations(UniqueRepresentation, Parent): sage: p = Permutations([1,1,2], 2); p Permutations of the multi-set [1, 1, 2] of length 2 - sage: p.list() + sage: p.list() # optional - sage.libs.gap [[1, 1], [1, 2], [2, 1]] :: sage: p = Permutations(descents=([1], 4)); p Standard permutations of 4 with descents [1] - sage: p.list() + sage: p.list() # optional - sage.graphs sage.modules sage.rings.finite_rings [[2, 4, 1, 3], [3, 4, 1, 2], [1, 4, 2, 3], [1, 3, 2, 4], [2, 3, 1, 4]] :: sage: p = Permutations(bruhat_smaller=[1,3,2,4]); p - Standard permutations that are less than or equal to [1, 3, 2, 4] in the Bruhat order + Standard permutations that are less than or equal + to [1, 3, 2, 4] in the Bruhat order sage: p.list() [[1, 2, 3, 4], [1, 3, 2, 4]] :: sage: p = Permutations(bruhat_greater=[4,2,3,1]); p - Standard permutations that are greater than or equal to [4, 2, 3, 1] in the Bruhat order + Standard permutations that are greater than or equal + to [4, 2, 3, 1] in the Bruhat order sage: p.list() [[4, 2, 3, 1], [4, 3, 2, 1]] @@ -5410,28 +5526,28 @@ class Permutations(UniqueRepresentation, Parent): sage: p = Permutations(recoils_finer=[2,1]); p Standard permutations whose recoils composition is finer than [2, 1] - sage: p.list() + sage: p.list() # optional - sage.graphs sage.modules sage.rings.finite_rings [[3, 1, 2], [1, 2, 3], [1, 3, 2]] :: sage: p = Permutations(recoils_fatter=[2,1]); p Standard permutations whose recoils composition is fatter than [2, 1] - sage: p.list() + sage: p.list() # optional - sage.graphs [[3, 1, 2], [3, 2, 1], [1, 3, 2]] :: sage: p = Permutations(recoils=[2,1]); p Standard permutations whose recoils composition is [2, 1] - sage: p.list() + sage: p.list() # optional - sage.graphs [[3, 1, 2], [1, 3, 2]] :: sage: p = Permutations(4, avoiding=[1,3,2]); p Standard permutations of 4 avoiding [[1, 3, 2]] - sage: p.list() + sage: p.list() # optional - sage.combinat [[4, 1, 2, 3], [4, 2, 1, 3], [4, 2, 3, 1], @@ -5451,9 +5567,9 @@ class Permutations(UniqueRepresentation, Parent): sage: p = Permutations(5, avoiding=[[3,4,1,2], [4,2,3,1]]); p Standard permutations of 5 avoiding [[3, 4, 1, 2], [4, 2, 3, 1]] - sage: p.cardinality() + sage: p.cardinality() # optional - sage.combinat 88 - sage: p.random_element().parent() is p + sage: p.random_element().parent() is p # optional - sage.combinat True """ @staticmethod @@ -5484,7 +5600,7 @@ def __classcall_private__(cls, n=None, k=None, **kwargs): #Make sure that exactly one keyword was passed for key in kwargs: if key not in valid_args: - raise ValueError("unknown keyword argument: %s"%key) + raise ValueError("unknown keyword argument: %s" % key) if key not in [ 'avoiding' ]: number_of_arguments += 1 @@ -5533,7 +5649,7 @@ def __classcall_private__(cls, n=None, k=None, **kwargs): a = tuple(map(Permutation, a)) return StandardPermutations_avoiding_generic(n, a) else: - raise ValueError("do not know how to avoid %s"%a) + raise ValueError("do not know how to avoid %s" % a) else: return StandardPermutations_n(n) else: @@ -5738,7 +5854,7 @@ def __iter__(self) -> Iterator[Permutation]: [] """ for x in itertools.permutations(range(1,self.n+1), int(self._k)): - yield self.element_class(self, x) + yield self.element_class(self, x, check=False) def cardinality(self) -> Integer: """ @@ -5800,14 +5916,14 @@ class Permutations_mset(Permutations): [2, 2, 1, 1, 2], [2, 2, 1, 2, 1], [2, 2, 2, 1, 1]] - sage: MS = MatrixSpace(GF(2),2,2) - sage: A = MS([1,0,1,1]) - sage: rows = A.rows() - sage: rows[0].set_immutable() - sage: rows[1].set_immutable() - sage: P = Permutations_mset(rows); P + sage: MS = MatrixSpace(GF(2), 2, 2) # optional - sage.modules sage.rings.finite_rings + sage: A = MS([1,0,1,1]) # optional - sage.modules sage.rings.finite_rings + sage: rows = A.rows() # optional - sage.modules sage.rings.finite_rings + sage: rows[0].set_immutable() # optional - sage.modules sage.rings.finite_rings + sage: rows[1].set_immutable() # optional - sage.modules sage.rings.finite_rings + sage: P = Permutations_mset(rows); P # optional - sage.modules sage.rings.finite_rings Permutations of the multi-set [(1, 0), (1, 1)] - sage: sorted(P) + sage: sorted(P) # optional - sage.modules sage.rings.finite_rings [[(1, 0), (1, 1)], [(1, 1), (1, 0)]] """ @staticmethod @@ -5888,7 +6004,7 @@ def _repr_(self) -> str: sage: Permutations(['c','a','c']) Permutations of the multi-set ['c', 'a', 'c'] """ - return "Permutations of the multi-set %s"%list(self.mset) + return "Permutations of the multi-set %s" % list(self.mset) def __iter__(self): r""" @@ -6228,7 +6344,7 @@ def _repr_(self) -> str: sage: Permutations(['c','a','t']) Permutations of the set ['c', 'a', 't'] """ - return "Permutations of the set %s"%list(self._set) + return "Permutations of the set %s" % list(self._set) class Element(ClonableArray): """ @@ -6265,7 +6381,7 @@ def __iter__(self) -> Iterator: ['t', 'a', 'c']] """ for p in itertools.permutations(self._set, len(self._set)): - yield self.element_class(self, p) + yield self.element_class(self, p, check=False) def cardinality(self) -> Integer: """ @@ -6317,7 +6433,7 @@ def __init__(self, mset, k): TESTS:: sage: P = Permutations([1,2,2],2) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.libs.gap """ Permutations_mset.__init__(self, mset) self._k = k @@ -6350,7 +6466,7 @@ def _repr_(self): """ TESTS:: - sage: Permutations([1,2,2],2) + sage: Permutations([1,2,2], 2) Permutations of the multi-set [1, 2, 2] of length 2 """ return "Permutations of the multi-set %s of length %s" % (list(self.mset), self._k) @@ -6361,7 +6477,7 @@ def cardinality(self): EXAMPLES:: - sage: Permutations([1,2,2],2).cardinality() + sage: Permutations([1,2,2], 2).cardinality() # optional - sage.libs.gap 3 """ return ZZ.sum(1 for z in self) @@ -6370,7 +6486,7 @@ def __iter__(self): """ EXAMPLES:: - sage: Permutations([1,2,2],2).list() + sage: Permutations([1,2,2], 2).list() # optional - sage.libs.gap [[1, 2], [2, 1], [2, 2]] """ mset = self.mset @@ -6378,7 +6494,8 @@ def __iter__(self): mset_list = [lmset.index(x) for x in lmset] indices = libgap.Arrangements(mset_list, self._k).sage() for ktuple in indices: - yield self.element_class(self, [lmset[x] for x in ktuple]) + yield self.element_class(self, [lmset[x] for x in ktuple], + check=False) class Permutations_setk(Permutations_set): @@ -6450,7 +6567,7 @@ def __iter__(self): [[1, 2], [1, 4], [2, 1], [2, 4], [4, 1], [4, 2]] """ for perm in itertools.permutations(self._set, int(self._k)): - yield self.element_class(self, perm) + yield self.element_class(self, perm, check=False) def random_element(self): """ @@ -6478,7 +6595,7 @@ class Arrangements(Permutations): EXAMPLES:: sage: mset = [1,1,2,3,4,4,5] - sage: Arrangements(mset,2).list() + sage: Arrangements(mset, 2).list() # optional - sage.libs.gap [[1, 1], [1, 2], [1, 3], @@ -6501,11 +6618,11 @@ class Arrangements(Permutations): [5, 2], [5, 3], [5, 4]] - sage: Arrangements(mset,2).cardinality() + sage: Arrangements(mset, 2).cardinality() # optional - sage.libs.gap 22 - sage: Arrangements( ["c","a","t"], 2 ).list() + sage: Arrangements( ["c","a","t"], 2 ).list() # optional - sage.libs.gap [['c', 'a'], ['c', 't'], ['a', 'c'], ['a', 't'], ['t', 'c'], ['t', 'a']] - sage: Arrangements( ["c","a","t"], 3 ).list() + sage: Arrangements( ["c","a","t"], 3 ).list() # optional - sage.libs.gap [['c', 'a', 't'], ['c', 't', 'a'], ['a', 'c', 't'], @@ -6537,7 +6654,7 @@ def cardinality(self): EXAMPLES:: sage: A = Arrangements([1,1,2,3,4,4,5], 2) - sage: A.cardinality() + sage: A.cardinality() # optional - sage.libs.gap 22 """ one = ZZ.one() @@ -6646,7 +6763,7 @@ def __iter__(self): n = 0 while True: for p in itertools.permutations(range(1, n + 1)): - yield self.element_class(self, p) + yield self.element_class(self, p, check=False) n += 1 def graded_component(self, n): @@ -6692,7 +6809,8 @@ def __init__(self, n, category=None): category = FiniteEnumeratedSets() Permutations.__init__(self, category=category) - def _element_constructor_(self, x, check_input=True): + @rename_keyword(deprecation=35233, check_input='check') + def _element_constructor_(self, x, check=True): """ Construct an element of ``self`` from ``x``. @@ -6702,26 +6820,26 @@ def _element_constructor_(self, x, check_input=True): sage: P([2,3,1]) [2, 3, 1, 4, 5] - sage: G = SymmetricGroup(4) + sage: G = SymmetricGroup(4) # optional - sage.groups sage: P = Permutations(4) - sage: x = G([4,3,1,2]); x + sage: x = G([4,3,1,2]); x # optional - sage.groups (1,4,2,3) - sage: P(x) + sage: P(x) # optional - sage.groups [4, 3, 1, 2] - sage: G(P(x)) + sage: G(P(x)) # optional - sage.groups (1,4,2,3) - sage: P = PermutationGroup([[(1,3,5),(2,4)],[(1,3)]]) - sage: x = P([(3,5),(2,4)]); x + sage: P = PermutationGroup([[(1,3,5),(2,4)],[(1,3)]]) # optional - sage.groups + sage: x = P([(3,5),(2,4)]); x # optional - sage.groups (2,4)(3,5) - sage: Permutations(6)(SymmetricGroup(6)(x)) + sage: Permutations(6)(SymmetricGroup(6)(x)) # optional - sage.groups [1, 4, 5, 2, 3, 6] - sage: Permutations(6)(x) # known bug + sage: Permutations(6)(x) # known bug # optional - sage.groups [1, 4, 5, 2, 3, 6] """ if len(x) < self.n: x = list(x) + list(range(len(x) + 1, self.n + 1)) - return self.element_class(self, x, check_input=check_input) + return self.element_class(self, x, check=check) def __contains__(self, x): """ @@ -6785,7 +6903,7 @@ def __iter__(self): [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] """ for p in itertools.permutations(range(1, self.n + 1)): - yield self.element_class(self, p) + yield self.element_class(self, p, check=False) def _coerce_map_from_(self, G): """ @@ -6807,20 +6925,20 @@ def _coerce_map_from_(self, G): EXAMPLES:: sage: P = Permutations(6) - sage: P.has_coerce_map_from(SymmetricGroup(6)) + sage: P.has_coerce_map_from(SymmetricGroup(6)) # optional - sage.groups True - sage: P.has_coerce_map_from(SymmetricGroup(5)) + sage: P.has_coerce_map_from(SymmetricGroup(5)) # optional - sage.groups True - sage: P.has_coerce_map_from(SymmetricGroup(7)) + sage: P.has_coerce_map_from(SymmetricGroup(7)) # optional - sage.groups False sage: P.has_coerce_map_from(Permutations(5)) True sage: P.has_coerce_map_from(Permutations(7)) False - sage: P.has_coerce_map_from(groups.misc.Cactus(5)) + sage: P.has_coerce_map_from(groups.misc.Cactus(5)) # optional - sage.groups True - sage: P.has_coerce_map_from(groups.misc.Cactus(7)) + sage: P.has_coerce_map_from(groups.misc.Cactus(7)) # optional - sage.groups False """ if isinstance(G, SymmetricGroup): @@ -6830,7 +6948,6 @@ def _coerce_map_from_(self, G): return self._from_permutation_group_element if isinstance(G, StandardPermutations_n) and G.n <= self.n: return True - from sage.groups.cactus_group import CactusGroup if isinstance(G, CactusGroup) and G.n() <= self.n: return self._from_cactus_group_element return super()._coerce_map_from_(G) @@ -6842,9 +6959,9 @@ def _from_permutation_group_element(self, x): TESTS:: sage: P = Permutations(4) - sage: G = SymmetricGroup(4) - sage: x = G([4,3,1,2]) - sage: P._from_permutation_group_element(x) + sage: G = SymmetricGroup(4) # optional - sage.groups + sage: x = G([4,3,1,2]) # optional - sage.groups + sage: P._from_permutation_group_element(x) # optional - sage.groups [4, 3, 1, 2] """ return self(x.domain()) @@ -6855,11 +6972,11 @@ def _from_cactus_group_element(self, x): EXAMPLES:: - sage: J3 = groups.misc.Cactus(3) - sage: s12,s13,s23 = J3.gens() - sage: elt = s12 * s23 * s13 - sage: P5 = Permutations(5) - sage: P5._from_cactus_group_element(elt) + sage: J3 = groups.misc.Cactus(3) # optional - sage.groups + sage: s12,s13,s23 = J3.gens() # optional - sage.groups + sage: elt = s12 * s23 * s13 # optional - sage.groups + sage: P5 = Permutations(5) # optional - sage.groups + sage: P5._from_cactus_group_element(elt) # optional - sage.groups [1, 3, 2, 4, 5] """ return self(x.to_permutation()) @@ -6871,12 +6988,11 @@ def as_permutation_group(self): EXAMPLES:: sage: P = Permutations(4) - sage: PG = P.as_permutation_group() - sage: PG + sage: PG = P.as_permutation_group(); PG # optional - sage.groups Symmetric group of order 4! as a permutation group - sage: G = SymmetricGroup(4) - sage: PG is G + sage: G = SymmetricGroup(4) # optional - sage.groups + sage: PG is G # optional - sage.groups True """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -6893,7 +7009,7 @@ def identity(self): sage: Permutations(0).identity() [] """ - return self.element_class(self, range(1,self.n+1)) + return self.element_class(self, range(1,self.n+1), check=False) one = identity @@ -6951,7 +7067,8 @@ def random_element(self): sage: s in Permutations(4) True """ - return self.element_class(self, sample(range(1,self.n+1), self.n)) + return self.element_class(self, sample(range(1, self.n+1), self.n), + check=False) def cardinality(self): """ @@ -7024,14 +7141,18 @@ def element_in_conjugacy_classes(self, nu): EXAMPLES:: sage: PP = Permutations(5) - sage: PP.element_in_conjugacy_classes([2,2]) + sage: PP.element_in_conjugacy_classes([2,2]) # optional - sage.combinat [2, 1, 4, 3, 5] + sage: PP.element_in_conjugacy_classes([5, 5]) + Traceback (most recent call last): + ... + ValueError: the size of the partition (=10) should be at most the size of the permutations (=5) """ from sage.combinat.partition import Partition nu = Partition(nu) if nu.size() > self.n: - raise ValueError("The size of the partition (=%s) should be lower or equal" - " to the size of the permutations (=%s)"%(nu.size,self.n)) + raise ValueError("the size of the partition (=%s) should be at most" + " the size of the permutations (=%s)" % (nu.size(), self.n)) l = [] i = 0 for nui in nu: @@ -7041,7 +7162,7 @@ def element_in_conjugacy_classes(self, nu): i += nui for i in range(nu.size(), self.n): l.append(i+1) - return self.element_class(self, l) + return self.element_class(self, l, check=False) def conjugacy_classes_representatives(self): r""" @@ -7056,7 +7177,7 @@ def conjugacy_classes_representatives(self): EXAMPLES:: sage: G = Permutations(5) - sage: G.conjugacy_classes_representatives() + sage: G.conjugacy_classes_representatives() # optional - sage.combinat [[1, 2, 3, 4, 5], [2, 1, 3, 4, 5], [2, 1, 4, 3, 5], @@ -7070,10 +7191,10 @@ def conjugacy_classes_representatives(self): Check some border cases:: sage: S = Permutations(0) - sage: S.conjugacy_classes_representatives() + sage: S.conjugacy_classes_representatives() # optional - sage.combinat [[]] sage: S = Permutations(1) - sage: S.conjugacy_classes_representatives() + sage: S.conjugacy_classes_representatives() # optional - sage.combinat [[1]] """ from sage.combinat.partition import Partitions_n @@ -7087,7 +7208,7 @@ def conjugacy_classes_iterator(self): EXAMPLES:: sage: G = Permutations(4) - sage: list(G.conjugacy_classes_iterator()) == G.conjugacy_classes() + sage: list(G.conjugacy_classes_iterator()) == G.conjugacy_classes() # optional - sage.combinat sage.graphs True """ from sage.combinat.partition import Partitions_n @@ -7102,7 +7223,7 @@ def conjugacy_classes(self): EXAMPLES:: sage: G = Permutations(4) - sage: G.conjugacy_classes() + sage: G.conjugacy_classes() # optional - sage.combinat sage.graphs [Conjugacy class of cycle type [1, 1, 1, 1] in Standard permutations of 4, Conjugacy class of cycle type [2, 1, 1] in Standard permutations of 4, Conjugacy class of cycle type [2, 2] in Standard permutations of 4, @@ -7123,9 +7244,9 @@ def conjugacy_class(self, g): sage: G = Permutations(5) sage: g = G([2,3,4,1,5]) - sage: G.conjugacy_class(g) + sage: G.conjugacy_class(g) # optional - sage.combinat sage.graphs Conjugacy class of cycle type [4, 1] in Standard permutations of 5 - sage: G.conjugacy_class(Partition([2, 1, 1, 1])) + sage: G.conjugacy_class(Partition([2, 1, 1, 1])) # optional - sage.combinat sage.graphs Conjugacy class of cycle type [2, 1, 1, 1] in Standard permutations of 5 """ from sage.groups.perm_gps.symgp_conjugacy_class import PermutationsConjugacyClass @@ -7143,15 +7264,16 @@ def algebra(self, base_ring, category=None): EXAMPLES:: sage: P = Permutations(4) - sage: A = P.algebra(QQ); A + sage: A = P.algebra(QQ); A # optional - sage.combinat sage.modules Symmetric group algebra of order 4 over Rational Field - sage: A.category() + sage: A.category() # optional - sage.combinat sage.modules Join of Category of coxeter group algebras over Rational Field and Category of finite group algebras over Rational Field - and Category of finite dimensional cellular algebras with basis over Rational Field - sage: A = P.algebra(QQ, category=Monoids()) - sage: A.category() + and Category of finite dimensional cellular algebras + with basis over Rational Field + sage: A = P.algebra(QQ, category=Monoids()) # optional - sage.combinat sage.modules + sage: A.category() # optional - sage.combinat sage.modules Category of finite dimensional cellular monoid algebras over Rational Field """ from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra @@ -7180,13 +7302,13 @@ def cartan_type(self): EXAMPLES:: - sage: A = SymmetricGroup([2,3,7]); A.cartan_type() + sage: A = SymmetricGroup([2,3,7]); A.cartan_type() # optional - sage.combinat sage.groups ['A', 2] - sage: A = SymmetricGroup([]); A.cartan_type() + sage: A = SymmetricGroup([]); A.cartan_type() # optional - sage.combinat sage.groups ['A', 0] """ from sage.combinat.root_system.cartan_type import CartanType - return CartanType(['A', max(self.n - 1,0)]) + return CartanType(['A', max(self.n - 1, 0)]) def simple_reflection(self, i): r""" @@ -7205,7 +7327,7 @@ def simple_reflection(self, i): g = list(range(1, self.n+1)) g[i-1] = i+1 g[i] = i - return self.element_class(self, g) + return self.element_class(self, g, check=False) class Element(Permutation): def has_left_descent(self, i, mult=None): @@ -7328,9 +7450,10 @@ def __mul__(self, other): """ if not isinstance(other, StandardPermutations_n.Element): return Permutation.__mul__(self, other) - if other.parent() is not self.parent(): + P = self.parent() + if other.parent() is not P: # They have different parents (but both are (like) Permutations of n) - mul_order = self.parent().options.mult + mul_order = P.options.mult if mul_order == 'l2r': p = right_action_product(self._list, other._list) elif mul_order == 'r2l': @@ -7373,8 +7496,8 @@ def inverse(self): [4, 2, 1, 3] """ w = list(range(len(self))) - for i,j in enumerate(self): - w[j-1] = i+1 + for i, j in enumerate(self): + w[j - 1] = i + 1 return self.__class__(self.parent(), w) __invert__ = inverse @@ -7446,12 +7569,12 @@ def from_permutation_group_element(pge, parent=None): EXAMPLES:: sage: import sage.combinat.permutation as permutation - sage: pge = PermutationGroupElement([(1,2),(3,4)]) - sage: permutation.from_permutation_group_element(pge) + sage: pge = PermutationGroupElement([(1,2),(3,4)]) # optional - sage.groups + sage: permutation.from_permutation_group_element(pge) # optional - sage.groups [2, 1, 4, 3] """ if not isinstance(pge, PermutationGroupElement): - raise TypeError("pge (= %s) must be a PermutationGroupElement"%pge) + raise TypeError("pge (= %s) must be a PermutationGroupElement" % pge) if parent is None: parent = Permutations( len(pge.domain()) ) @@ -7518,8 +7641,8 @@ def from_inversion_vector(iv, parent=None): """ p = iv[:] open_spots = list(range(len(iv))) - for i,ivi in enumerate(iv): - p[open_spots.pop(ivi)] = i+1 + for i, ivi in enumerate(iv): + p[open_spots.pop(ivi)] = i + 1 if parent is None: parent = Permutations() @@ -7608,7 +7731,7 @@ def from_cycles(n, cycles, parent=None): for i in range(n): if p[i] is None: p[i] = ZZ(i + 1) - return parent(p, check_input=False) + return parent(p, check=False) def from_lehmer_code(lehmer, parent=None): @@ -7691,7 +7814,7 @@ def from_reduced_word(rw, parent=None): return parent(p) -def bistochastic_as_sum_of_permutations(M, check = True): +def bistochastic_as_sum_of_permutations(M, check=True): r""" Return the positive sum of permutations corresponding to the bistochastic matrix ``M``. @@ -7756,25 +7879,26 @@ def bistochastic_as_sum_of_permutations(M, check = True): sage: L.append((6,Permutation([5, 3, 4, 1, 2]))) sage: L.append((3,Permutation([3, 1, 4, 2, 5]))) sage: L.append((2,Permutation([1, 4, 2, 3, 5]))) - sage: M = sum([c * p.to_matrix() for (c,p) in L]) - sage: decomp = bistochastic_as_sum_of_permutations(M) - sage: print(decomp) - 2*B[[1, 4, 2, 3, 5]] + 3*B[[3, 1, 4, 2, 5]] + 9*B[[4, 1, 3, 5, 2]] + 6*B[[5, 3, 4, 1, 2]] + sage: M = sum([c * p.to_matrix() for (c,p) in L]) # optional - sage.modules + sage: decomp = bistochastic_as_sum_of_permutations(M) # optional - sage.graphs sage.modules + sage: print(decomp) # optional - sage.graphs sage.modules + 2*B[[1, 4, 2, 3, 5]] + 3*B[[3, 1, 4, 2, 5]] + + 9*B[[4, 1, 3, 5, 2]] + 6*B[[5, 3, 4, 1, 2]] An exception is raised when the matrix is not positive and bistochastic:: - sage: M = Matrix([[2,3],[2,2]]) - sage: decomp = bistochastic_as_sum_of_permutations(M) + sage: M = Matrix([[2,3],[2,2]]) # optional - sage.modules + sage: decomp = bistochastic_as_sum_of_permutations(M) # optional - sage.graphs sage.modules Traceback (most recent call last): ... ValueError: The matrix is not bistochastic - sage: bistochastic_as_sum_of_permutations(Matrix(GF(7), 2, [2,1,1,2])) + sage: bistochastic_as_sum_of_permutations(Matrix(GF(7), 2, [2,1,1,2])) # optional - sage.graphs sage.modules sage.rings.finite_rings Traceback (most recent call last): ... ValueError: The base ring of the matrix must have a coercion map to RR - sage: bistochastic_as_sum_of_permutations(Matrix(ZZ, 2, [2,-1,-1,2])) + sage: bistochastic_as_sum_of_permutations(Matrix(ZZ, 2, [2,-1,-1,2])) # optional - sage.graphs sage.modules Traceback (most recent call last): ... ValueError: The matrix should have nonnegative entries @@ -7791,7 +7915,7 @@ def bistochastic_as_sum_of_permutations(M, check = True): if not all(x >= 0 for x in M.list()): raise ValueError("The matrix should have nonnegative entries") - if check and not M.is_bistochastic(normalized = False): + if check and not M.is_bistochastic(normalized=False): raise ValueError("The matrix is not bistochastic") if not RR.has_coerce_map_from(M.base_ring()): @@ -7841,12 +7965,12 @@ def bounded_affine_permutation(A): EXAMPLES:: sage: from sage.combinat.permutation import bounded_affine_permutation - sage: A = Matrix(ZZ, [[1,0,0,0], [0,1,0,0]]) - sage: bounded_affine_permutation(A) + sage: A = Matrix(ZZ, [[1,0,0,0], [0,1,0,0]]) # optional - sage.modules + sage: bounded_affine_permutation(A) # optional - sage.modules [5, 6, 3, 4] - sage: A = Matrix(ZZ, [[0,1,0,1,0], [0,0,1,1,0]]) - sage: bounded_affine_permutation(A) + sage: A = Matrix(ZZ, [[0,1,0,1,0], [0,0,1,1,0]]) # optional - sage.modules + sage: bounded_affine_permutation(A) # optional - sage.modules [1, 4, 7, 8, 5] REFERENCES: @@ -7906,7 +8030,7 @@ def __init__(self, d, n): TESTS:: sage: P = Permutations(descents=([1,0,2], 5)) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.graphs """ StandardPermutations_n_abstract.__init__(self, n) self._d = d @@ -7942,14 +8066,15 @@ def cardinality(self): sage: Permutations(descents=([1,4], 6)).cardinality() 40 - sage: P = lambda D, n: Permutations(descents=(D, n+1)) - sage: all(P(D, n).cardinality() == len(P(D, n).list()) + sage: def P(D, n): + ....: return Permutations(descents=(D, n + 1)) + sage: all(P(D, n).cardinality() == len(P(D, n).list()) # optional - sage.graphs sage.modules sage.rings.finite_rings ....: for n in range(5) for D in subsets(range(n))) True - sage: n = 20; + sage: n = 20 sage: D = [6, 8, 10, 11, 12, 13, 14, 15, 17, 19] - sage: P(D, n).cardinality() + sage: P(D, n).cardinality() # optional - sage.graphs 125291047596 """ @@ -8008,7 +8133,7 @@ def __iter__(self): EXAMPLES:: - sage: Permutations(descents=([2,0],5)).list() + sage: Permutations(descents=([2,0],5)).list() # optional - sage.graphs sage.modules sage.rings.finite_rings [[5, 2, 4, 1, 3], [5, 3, 4, 1, 2], [4, 3, 5, 1, 2], @@ -8037,7 +8162,7 @@ def descents_composition_list(dc): EXAMPLES:: sage: import sage.combinat.permutation as permutation - sage: permutation.descents_composition_list([1,2,2]) + sage: permutation.descents_composition_list([1,2,2]) # optional - sage.graphs sage.modules sage.rings.finite_rings [[5, 2, 4, 1, 3], [5, 3, 4, 1, 2], [4, 3, 5, 1, 2], @@ -8078,9 +8203,9 @@ def descents_composition_first(dc): cpl = [x for x in reversed(dc.conjugate())] res = [] s = 0 - for i in range(len(cpl)): - res += [s + cpl[i]-j for j in range(cpl[i])] - s += cpl[i] + for cpli in cpl: + s += cpli + res += [s - j for j in range(cpli)] return Permutations()(res) @@ -8130,7 +8255,7 @@ def __init__(self, recoils): TESTS:: sage: P = Permutations(recoils_finer=[2,2]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.graphs """ Permutations.__init__(self, category=FiniteEnumeratedSets()) self.recoils = recoils @@ -8151,7 +8276,7 @@ def __iter__(self): EXAMPLES:: - sage: Permutations(recoils_finer=[2,2]).list() + sage: Permutations(recoils_finer=[2,2]).list() # optional - sage.graphs sage.modules sage.rings.finite_rings [[3, 1, 4, 2], [3, 4, 1, 2], [1, 3, 4, 2], @@ -8175,7 +8300,7 @@ def __iter__(self): pos += 1 for le in dag.topological_sort_generator(): - yield self.element_class(self, le) + yield self.element_class(self, le, check=False) class StandardPermutations_recoilsfatter(Permutations): @@ -8198,7 +8323,7 @@ def __init__(self, recoils): TESTS:: sage: P = Permutations(recoils_fatter=[2,2]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.graphs """ Permutations.__init__(self, category=FiniteEnumeratedSets()) self.recoils = recoils @@ -8219,7 +8344,7 @@ def __iter__(self): EXAMPLES:: - sage: Permutations(recoils_fatter=[2,2]).list() + sage: Permutations(recoils_fatter=[2,2]).list() # optional - sage.graphs sage.modules sage.rings.finite_rings [[4, 3, 2, 1], [3, 2, 1, 4], [3, 2, 4, 1], @@ -8247,7 +8372,7 @@ def __iter__(self): dag.add_edge(pos+1, pos) for le in dag.topological_sort_generator(): - yield self.element_class(self, le) + yield self.element_class(self, le, check=False) class StandardPermutations_recoils(Permutations): @@ -8273,7 +8398,7 @@ def __init__(self, recoils): TESTS:: sage: P = Permutations(recoils=[2,2]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.graphs """ Permutations.__init__(self, category=FiniteEnumeratedSets()) self.recoils = recoils @@ -8294,7 +8419,7 @@ def __iter__(self): EXAMPLES:: - sage: Permutations(recoils=[2,2]).list() + sage: Permutations(recoils=[2,2]).list() # optional - sage.graphs [[3, 1, 4, 2], [3, 4, 1, 2], [1, 3, 4, 2], [1, 3, 2, 4], [3, 1, 2, 4]] """ recoils = self.recoils @@ -8319,7 +8444,7 @@ def __iter__(self): dag.add_edge(pos+1, pos) for le in dag.topological_sort_generator(): - yield self.element_class(self, le) + yield self.element_class(self, le, check=False) def from_major_code(mc, final_descent=False): @@ -8382,7 +8507,7 @@ def from_major_code(mc, final_descent=False): #Lemma 2.2 in Skandera #Get the descents of w and place them in reverse order - d = Permutation(w, check_input=False).descents(final_descent=final_descent) + d = Permutation(w, check=False).descents(final_descent=final_descent) d.reverse() #a is the list of all positions which are not descents @@ -8394,7 +8519,7 @@ def from_major_code(mc, final_descent=False): indices = d + a w.insert(indices[l], i) - return Permutation(w, check_input = False) + return Permutation(w, check=False) ################ # Bruhat Order # @@ -8586,8 +8711,6 @@ def permutohedron_lequal(p1, p2, side="right"): ############ # Patterns # ############ -from sage.combinat.words.finite_word import evaluation_dict - def to_standard(p, key=None): r""" @@ -8602,15 +8725,15 @@ def to_standard(p, key=None): EXAMPLES:: sage: import sage.combinat.permutation as permutation - sage: permutation.to_standard([4,2,7]) + sage: permutation.to_standard([4,2,7]) # optional - sage.combinat [2, 1, 3] - sage: permutation.to_standard([1,2,3]) + sage: permutation.to_standard([1,2,3]) # optional - sage.combinat [1, 2, 3] - sage: permutation.to_standard([]) + sage: permutation.to_standard([]) # optional - sage.combinat [] - sage: permutation.to_standard([1,2,3], key=lambda x: -x) + sage: permutation.to_standard([1,2,3], key=lambda x: -x) # optional - sage.combinat [3, 2, 1] - sage: permutation.to_standard([5,8,2,5], key=lambda x: -x) + sage: permutation.to_standard([5,8,2,5], key=lambda x: -x) # optional - sage.combinat [2, 1, 4, 3] TESTS: @@ -8618,7 +8741,7 @@ def to_standard(p, key=None): Does not mutate the list:: sage: a = [1,2,4] - sage: permutation.to_standard(a) + sage: permutation.to_standard(a) # optional - sage.combinat [1, 2, 3] sage: a [1, 2, 4] @@ -8637,8 +8760,8 @@ def to_standard(p, key=None): ....: i += 1 ....: c[smallest_index] = biggest ....: return Permutations()(s) - sage: p = list(Words(100, 1000).random_element()) - sage: std(p) == permutation.to_standard(p) + sage: p = list(Words(100, 1000).random_element()) # optional - sage.combinat + sage: std(p) == permutation.to_standard(p) # optional - sage.combinat True """ ev_dict = evaluation_dict(p) @@ -8668,14 +8791,14 @@ class CyclicPermutations(Permutations_mset): EXAMPLES:: - sage: CyclicPermutations(range(4)).list() + sage: CyclicPermutations(range(4)).list() # optional - sage.combinat [[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1], [0, 3, 1, 2], [0, 3, 2, 1]] - sage: CyclicPermutations([1,1,1]).list() + sage: CyclicPermutations([1,1,1]).list() # optional - sage.combinat [[1, 1, 1]] """ @staticmethod @@ -8704,22 +8827,22 @@ def _repr_(self): sage: CyclicPermutations(range(4)) Cyclic permutations of [0, 1, 2, 3] """ - return "Cyclic permutations of %s"%list(self.mset) + return "Cyclic permutations of %s" % list(self.mset) def __iter__(self, distinct=False): """ EXAMPLES:: - sage: CyclicPermutations(range(4)).list() # indirect doctest + sage: CyclicPermutations(range(4)).list() # indirect doctest # optional - sage.combinat [[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1], [0, 3, 1, 2], [0, 3, 2, 1]] - sage: CyclicPermutations([1,1,1]).list() + sage: CyclicPermutations([1,1,1]).list() # optional - sage.combinat [[1, 1, 1]] - sage: CyclicPermutations([1,1,1]).list(distinct=True) + sage: CyclicPermutations([1,1,1]).list(distinct=True) # optional - sage.combinat [[1, 1, 1], [1, 1, 1]] """ if distinct: @@ -8740,7 +8863,7 @@ def list(self, distinct=False): """ EXAMPLES:: - sage: CyclicPermutations(range(4)).list() + sage: CyclicPermutations(range(4)).list() # optional - sage.combinat [[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], @@ -8761,7 +8884,7 @@ class CyclicPermutationsOfPartition(Permutations): EXAMPLES:: - sage: CyclicPermutationsOfPartition([[1,2,3,4],[5,6,7]]).list() + sage: CyclicPermutationsOfPartition([[1,2,3,4],[5,6,7]]).list() # optional - sage.combinat [[[1, 2, 3, 4], [5, 6, 7]], [[1, 2, 4, 3], [5, 6, 7]], [[1, 3, 2, 4], [5, 6, 7]], @@ -8777,7 +8900,7 @@ class CyclicPermutationsOfPartition(Permutations): :: - sage: CyclicPermutationsOfPartition([[1,2,3,4],[4,4,4]]).list() + sage: CyclicPermutationsOfPartition([[1,2,3,4],[4,4,4]]).list() # optional - sage.combinat [[[1, 2, 3, 4], [4, 4, 4]], [[1, 2, 4, 3], [4, 4, 4]], [[1, 3, 2, 4], [4, 4, 4]], @@ -8787,12 +8910,12 @@ class CyclicPermutationsOfPartition(Permutations): :: - sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list() + sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list() # optional - sage.combinat [[[1, 2, 3], [4, 4, 4]], [[1, 3, 2], [4, 4, 4]]] :: - sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list(distinct=True) + sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list(distinct=True) # optional - sage.combinat [[[1, 2, 3], [4, 4, 4]], [[1, 3, 2], [4, 4, 4]], [[1, 2, 3], [4, 4, 4]], @@ -8820,7 +8943,7 @@ def __init__(self, partition): sage: CP = CyclicPermutationsOfPartition([[1,2,3,4],[5,6,7]]) sage: CP Cyclic permutations of partition [[1, 2, 3, 4], [5, 6, 7]] - sage: TestSuite(CP).run() + sage: TestSuite(CP).run() # optional - sage.combinat """ self.partition = partition Permutations.__init__(self, category=FiniteEnumeratedSets()) @@ -8837,8 +8960,8 @@ def check(self): EXAMPLES:: sage: CP = CyclicPermutationsOfPartition([[1,2,3,4],[5,6,7]]) - sage: elt = CP[0] - sage: elt.check() + sage: elt = CP[0] # optional - sage.combinat + sage: elt.check() # optional - sage.combinat """ if [sorted(_) for _ in self] != [sorted(_) for _ in self.parent().partition]: raise ValueError("Invalid cyclic permutation of the partition" % self.parent().partition) @@ -8861,7 +8984,8 @@ def __iter__(self, distinct=False): EXAMPLES:: - sage: CyclicPermutationsOfPartition([[1,2,3,4],[5,6,7]]).list() # indirect doctest + sage: CyclicPermutationsOfPartition([[1,2,3,4], # indirect doctest # optional - sage.combinat + ....: [5,6,7]]).list() [[[1, 2, 3, 4], [5, 6, 7]], [[1, 2, 4, 3], [5, 6, 7]], [[1, 3, 2, 4], [5, 6, 7]], @@ -8877,7 +9001,7 @@ def __iter__(self, distinct=False): :: - sage: CyclicPermutationsOfPartition([[1,2,3,4],[4,4,4]]).list() + sage: CyclicPermutationsOfPartition([[1,2,3,4],[4,4,4]]).list() # optional - sage.combinat [[[1, 2, 3, 4], [4, 4, 4]], [[1, 2, 4, 3], [4, 4, 4]], [[1, 3, 2, 4], [4, 4, 4]], @@ -8887,12 +9011,12 @@ def __iter__(self, distinct=False): :: - sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list() + sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list() # optional - sage.combinat [[[1, 2, 3], [4, 4, 4]], [[1, 3, 2], [4, 4, 4]]] :: - sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list(distinct=True) + sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list(distinct=True) # optional - sage.combinat [[[1, 2, 3], [4, 4, 4]], [[1, 3, 2], [4, 4, 4]], [[1, 2, 3], [4, 4, 4]], @@ -8900,11 +9024,11 @@ def __iter__(self, distinct=False): """ if len(self.partition) == 1: for i in CyclicPermutations(self.partition[0]).iterator(distinct=distinct): - yield self.element_class(self, [i]) + yield self.element_class(self, [i], check=False) else: for right in CyclicPermutationsOfPartition(self.partition[1:]).iterator(distinct=distinct): for perm in CyclicPermutations(self.partition[0]).iterator(distinct=distinct): - yield self.element_class(self, [perm] + list(right)) + yield self.element_class(self, [perm] + list(right), check=False) iterator = __iter__ @@ -8912,9 +9036,9 @@ def list(self, distinct=False): """ EXAMPLES:: - sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list() + sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list() # optional - sage.combinat [[[1, 2, 3], [4, 4, 4]], [[1, 3, 2], [4, 4, 4]]] - sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list(distinct=True) + sage: CyclicPermutationsOfPartition([[1,2,3],[4,4,4]]).list(distinct=True) # optional - sage.combinat [[[1, 2, 3], [4, 4, 4]], [[1, 3, 2], [4, 4, 4]], [[1, 2, 3], [4, 4, 4]], @@ -8950,7 +9074,7 @@ def __init__(self, a): TESTS:: sage: P = Permutations(avoiding=[[2,1,3],[1,2,3]]) - sage: TestSuite(P).run(max_runs=25) + sage: TestSuite(P).run(max_runs=25) # optional - sage.combinat """ Permutations.__init__(self, category=InfiniteEnumeratedSets()) self._a = a @@ -8980,13 +9104,13 @@ def __contains__(self, x): """ TESTS:: - sage: [1,3,2] in Permutations(avoiding=[1,3,2]) + sage: [1,3,2] in Permutations(avoiding=[1,3,2]) # optional - sage.combinat False - sage: [1,3,2] in Permutations(avoiding=[[1,3,2]]) + sage: [1,3,2] in Permutations(avoiding=[[1,3,2]]) # optional - sage.combinat False - sage: [2,1,3] in Permutations(avoiding=[[1,3,2],[1,2,3]]) + sage: [2,1,3] in Permutations(avoiding=[[1,3,2],[1,2,3]]) # optional - sage.combinat True - sage: [2,1,3] in Permutations(avoiding=[]) + sage: [2,1,3] in Permutations(avoiding=[]) # optional - sage.combinat True """ if not super().__contains__(x): @@ -9001,7 +9125,7 @@ def __iter__(self): TESTS:: sage: it = iter(Permutations(avoiding=[[2,1,3],[1,2,3]])) - sage: [next(it) for i in range(10)] + sage: [next(it) for i in range(10)] # optional - sage.combinat [[], [1], [1, 2], @@ -9016,7 +9140,7 @@ def __iter__(self): n = 0 while True: for x in itertools.permutations(range(1, n + 1)): - x = self.element_class(self, x) + x = self.element_class(self, x, check=False) if all(x.avoids(p) for p in self._a): yield x n += 1 @@ -9046,7 +9170,7 @@ def __init__(self, n, a): EXAMPLES:: sage: P = Permutations(3, avoiding=[[2,1,3],[1,2,3]]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.combinat sage: type(P) <class 'sage.combinat.permutation.StandardPermutations_avoiding_generic_with_category'> """ @@ -9087,13 +9211,13 @@ def __contains__(self, x): """ TESTS:: - sage: [1,3,2] in Permutations(3, avoiding=[1,3,2]) + sage: [1,3,2] in Permutations(3, avoiding=[1,3,2]) # optional - sage.combinat False - sage: [1,3,2] in Permutations(3, avoiding=[[1,3,2]]) + sage: [1,3,2] in Permutations(3, avoiding=[[1,3,2]]) # optional - sage.combinat False - sage: [2,1,3] in Permutations(3, avoiding=[[1,3,2],[1,2,3]]) + sage: [2,1,3] in Permutations(3, avoiding=[[1,3,2],[1,2,3]]) # optional - sage.combinat True - sage: [2,1,3] in Permutations(3, avoiding=[]) + sage: [2,1,3] in Permutations(3, avoiding=[]) # optional - sage.combinat True """ if not super().__contains__(x): @@ -9114,14 +9238,14 @@ def __iter__(self): """ EXAMPLES:: - sage: Permutations(3, avoiding=[[2, 1, 3],[1,2,3]]).list() + sage: Permutations(3, avoiding=[[2, 1, 3],[1,2,3]]).list() # optional - sage.combinat [[1, 3, 2], [3, 1, 2], [2, 3, 1], [3, 2, 1]] - sage: Permutations(0, avoiding=[[2, 1, 3],[1,2,3]]).list() + sage: Permutations(0, avoiding=[[2, 1, 3],[1,2,3]]).list() # optional - sage.combinat [[]] """ if self.n > 0: return iter(PatternAvoider(self, self._a)) - return iter([self.element_class(self, [])]) + return iter([self.element_class(self, [], check=False)]) def cardinality(self): """ @@ -9130,7 +9254,7 @@ def cardinality(self): EXAMPLES:: sage: P = Permutations(3, avoiding=[[2, 1, 3],[1,2,3]]) - sage: P.cardinality() + sage: P.cardinality() # optional - sage.combinat 4 """ one = ZZ.one() @@ -9143,7 +9267,7 @@ def __init__(self, n): TESTS:: sage: P = Permutations(3, avoiding=[1, 2]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.combinat """ super().__init__(n, (Permutations()([1, 2]),)) @@ -9151,10 +9275,10 @@ def __iter__(self): """ EXAMPLES:: - sage: Permutations(3, avoiding=[1,2]).list() + sage: Permutations(3, avoiding=[1,2]).list() # optional - sage.combinat [[3, 2, 1]] """ - yield self.element_class(self, range(self.n, 0, -1)) + yield self.element_class(self, range(self.n, 0, -1), check=False) def cardinality(self): """ @@ -9163,7 +9287,7 @@ def cardinality(self): EXAMPLES:: sage: P = Permutations(3, avoiding=[1, 2]) - sage: P.cardinality() + sage: P.cardinality() # optional - sage.combinat 1 """ return ZZ.one() @@ -9175,7 +9299,7 @@ def __init__(self, n): TESTS:: sage: P = Permutations(3, avoiding=[2, 1]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.combinat """ super().__init__(n, (Permutations()([2, 1]),)) @@ -9183,10 +9307,10 @@ def __iter__(self): """ EXAMPLES:: - sage: Permutations(3, avoiding=[2,1]).list() + sage: Permutations(3, avoiding=[2,1]).list() # optional - sage.combinat [[1, 2, 3]] """ - yield self.element_class(self, range(1, self.n+1)) + yield self.element_class(self, range(1, self.n+1), check=False) def cardinality(self): """ @@ -9195,7 +9319,7 @@ def cardinality(self): EXAMPLES:: sage: P = Permutations(3, avoiding=[2, 1]) - sage: P.cardinality() + sage: P.cardinality() # optional - sage.combinat 1 """ return ZZ.one() @@ -9207,7 +9331,7 @@ def __init__(self, n): TESTS:: sage: P = Permutations(3, avoiding=[1, 3, 2]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.combinat """ super().__init__(n, (Permutations()([1, 3, 2]),)) @@ -9217,7 +9341,7 @@ def cardinality(self): sage: Permutations(5, avoiding=[1, 3, 2]).cardinality() 42 - sage: len( Permutations(5, avoiding=[1, 3, 2]).list() ) + sage: len( Permutations(5, avoiding=[1, 3, 2]).list() ) # optional - sage.combinat 42 """ return catalan_number(self.n) @@ -9226,9 +9350,9 @@ def __iter__(self): """ EXAMPLES:: - sage: Permutations(3, avoiding=[1,3,2]).list() # indirect doctest + sage: Permutations(3, avoiding=[1,3,2]).list() # indirect doctest # optional - sage.combinat [[1, 2, 3], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] - sage: Permutations(4, avoiding=[1,3,2]).list() + sage: Permutations(4, avoiding=[1,3,2]).list() # optional - sage.combinat [[4, 1, 2, 3], [4, 2, 1, 3], [4, 2, 3, 1], @@ -9249,28 +9373,33 @@ def __iter__(self): elif self.n < 3: for p in itertools.permutations(range(1, self.n + 1)): - yield self.element_class(self, p) + yield self.element_class(self, p, check=False) return elif self.n == 3: for p in itertools.permutations(range(1, self.n + 1)): if p != (1, 3, 2): - yield self.element_class(self, p) + yield self.element_class(self, p, check=False) return #Yield all the 132 avoiding permutations to the right. for right in StandardPermutations_avoiding_132(self.n - 1): - yield self.element_class(self, [self.n] + list(right)) + yield self.element_class(self, [self.n] + list(right), + check=False) #yi for i in range(1, self.n-1): for left in StandardPermutations_avoiding_132(i): for right in StandardPermutations_avoiding_132(self.n-i-1): - yield self.element_class(self, [x+(self.n-i-1) for x in left] + [self.n] + list(right) ) + yield self.element_class(self, + [x + (self.n-i-1) for x in left] + + [self.n] + list(right), + check=False) #Yield all the 132 avoiding permutations to the left for left in StandardPermutations_avoiding_132(self.n - 1): - yield self.element_class(self, list(left) + [self.n]) + yield self.element_class(self, list(left) + [self.n], + check=False) class StandardPermutations_avoiding_123(StandardPermutations_avoiding_generic): @@ -9279,7 +9408,7 @@ def __init__(self, n): TESTS:: sage: P = Permutations(3, avoiding=[2, 1, 3]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.combinat """ super().__init__(n, (Permutations()([1, 2, 3]),)) @@ -9287,9 +9416,9 @@ def cardinality(self) -> Integer: """ EXAMPLES:: - sage: Permutations(5, avoiding=[1, 2, 3]).cardinality() + sage: Permutations(5, avoiding=[1, 2, 3]).cardinality() # optional - sage.combinat 42 - sage: len( Permutations(5, avoiding=[1, 2, 3]).list() ) + sage: len( Permutations(5, avoiding=[1, 2, 3]).list() ) # optional - sage.combinat 42 """ return catalan_number(self.n) @@ -9298,11 +9427,11 @@ def __iter__(self): """ EXAMPLES:: - sage: Permutations(3, avoiding=[1, 2, 3]).list() # indirect doctest + sage: Permutations(3, avoiding=[1, 2, 3]).list() # indirect doctest # optional - sage.combinat [[1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] - sage: Permutations(2, avoiding=[1, 2, 3]).list() + sage: Permutations(2, avoiding=[1, 2, 3]).list() # optional - sage.combinat [[1, 2], [2, 1]] - sage: Permutations(3, avoiding=[1, 2, 3]).list() + sage: Permutations(3, avoiding=[1, 2, 3]).list() # optional - sage.combinat [[1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] """ if self.n == 0: @@ -9310,13 +9439,13 @@ def __iter__(self): elif self.n < 3: for p in itertools.permutations(range(1, self.n + 1)): - yield self.element_class(self, p) + yield self.element_class(self, p, check=False) return elif self.n == 3: for p in itertools.permutations(range(1, self.n + 1)): if p != (1, 2, 3): - yield self.element_class(self, p) + yield self.element_class(self, p, check=False) return for p in StandardPermutations_avoiding_132(self.n): @@ -9342,7 +9471,7 @@ def __iter__(self): new_p.append( non_minima[b] ) b += 1 - yield self.element_class(self, new_p) + yield self.element_class(self, new_p, check=False) class StandardPermutations_avoiding_321(StandardPermutations_avoiding_generic): @@ -9351,7 +9480,7 @@ def __init__(self, n): TESTS:: sage: P = Permutations(3, avoiding=[3, 2, 1]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.combinat """ super().__init__(n, (Permutations()([3, 2, 1]),)) @@ -9359,9 +9488,9 @@ def cardinality(self): """ EXAMPLES:: - sage: Permutations(5, avoiding=[3, 2, 1]).cardinality() + sage: Permutations(5, avoiding=[3, 2, 1]).cardinality() # optional - sage.combinat 42 - sage: len( Permutations(5, avoiding=[3, 2, 1]).list() ) + sage: len( Permutations(5, avoiding=[3, 2, 1]).list() ) # optional - sage.combinat 42 """ return catalan_number(self.n) @@ -9370,11 +9499,11 @@ def __iter__(self): """ EXAMPLES:: - sage: Permutations(3, avoiding=[3, 2, 1]).list() #indirect doctest + sage: Permutations(3, avoiding=[3, 2, 1]).list() # indirect doctest # optional - sage.combinat [[2, 3, 1], [3, 1, 2], [1, 3, 2], [2, 1, 3], [1, 2, 3]] """ for p in StandardPermutations_avoiding_123(self.n): - yield self.element_class(self, p.reverse()) + yield self.element_class(self, p.reverse(), check=False) class StandardPermutations_avoiding_231(StandardPermutations_avoiding_generic): @@ -9383,7 +9512,7 @@ def __init__(self, n): TESTS:: sage: P = Permutations(3, avoiding=[2, 3, 1]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.combinat """ super().__init__(n, (Permutations()([2, 3, 1]),)) @@ -9391,9 +9520,9 @@ def cardinality(self): """ EXAMPLES:: - sage: Permutations(5, avoiding=[2, 3, 1]).cardinality() + sage: Permutations(5, avoiding=[2, 3, 1]).cardinality() # optional - sage.combinat 42 - sage: len( Permutations(5, avoiding=[2, 3, 1]).list() ) + sage: len( Permutations(5, avoiding=[2, 3, 1]).list() ) # optional - sage.combinat 42 """ return catalan_number(self.n) @@ -9402,11 +9531,11 @@ def __iter__(self): """ EXAMPLES:: - sage: Permutations(3, avoiding=[2, 3, 1]).list() + sage: Permutations(3, avoiding=[2, 3, 1]).list() # optional - sage.combinat [[3, 2, 1], [3, 1, 2], [1, 3, 2], [2, 1, 3], [1, 2, 3]] """ for p in StandardPermutations_avoiding_132(self.n): - yield self.element_class(self, p.reverse()) + yield self.element_class(self, p.reverse(), check=False) class StandardPermutations_avoiding_312(StandardPermutations_avoiding_generic): @@ -9415,7 +9544,7 @@ def __init__(self, n): TESTS:: sage: P = Permutations(3, avoiding=[3, 1, 2]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.combinat """ super().__init__(n, (Permutations()([3, 1, 2]),)) @@ -9425,7 +9554,7 @@ def cardinality(self): sage: Permutations(5, avoiding=[3, 1, 2]).cardinality() 42 - sage: len( Permutations(5, avoiding=[3, 1, 2]).list() ) + sage: len( Permutations(5, avoiding=[3, 1, 2]).list() ) # optional - sage.combinat 42 """ return catalan_number(self.n) @@ -9434,11 +9563,11 @@ def __iter__(self): """ EXAMPLES:: - sage: Permutations(3, avoiding=[3, 1, 2]).list() + sage: Permutations(3, avoiding=[3, 1, 2]).list() # optional - sage.combinat [[3, 2, 1], [2, 3, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3]] """ for p in StandardPermutations_avoiding_132(self.n): - yield self.element_class(self, p.complement()) + yield self.element_class(self, p.complement(), check=False) class StandardPermutations_avoiding_213(StandardPermutations_avoiding_generic): @@ -9447,7 +9576,7 @@ def __init__(self, n): TESTS:: sage: P = Permutations(3, avoiding=[2, 1, 3]) - sage: TestSuite(P).run() + sage: TestSuite(P).run() # optional - sage.combinat """ super().__init__(n, (Permutations()([2, 1, 3]),)) @@ -9457,7 +9586,7 @@ def cardinality(self): sage: Permutations(5, avoiding=[2, 1, 3]).cardinality() 42 - sage: len( Permutations(5, avoiding=[2, 1, 3]).list() ) + sage: len( Permutations(5, avoiding=[2, 1, 3]).list() ) # optional - sage.combinat 42 """ return catalan_number(self.n) @@ -9466,7 +9595,7 @@ def __iter__(self): """ EXAMPLES:: - sage: Permutations(3, avoiding=[2, 1, 3]).list() + sage: Permutations(3, avoiding=[2, 1, 3]).list() # optional - sage.combinat [[1, 2, 3], [1, 3, 2], [3, 1, 2], [2, 3, 1], [3, 2, 1]] """ for p in StandardPermutations_avoiding_132(self.n): @@ -9495,7 +9624,7 @@ def _rec(self, obj, state): sage: from sage.combinat.permutation import PatternAvoider sage: P = Permutations(4) sage: p = PatternAvoider(P, [[1,2]]) - sage: list(p._rec([1], 2)) + sage: list(p._rec([1], 2)) # optional - sage.combinat [([2, 1], 3, False)] """ i = state @@ -9508,8 +9637,10 @@ def _rec(self, obj, state): yld = True for pos in reversed(range(len(obj)+1)): - new_obj = self._parent.element_class(self._parent, obj[:pos] + [i] + obj[pos:]) - if all( not new_obj.has_pattern(p) for p in self._patterns): + new_obj = self._parent.element_class(self._parent, + obj[:pos] + [i] + obj[pos:], + check=False) + if all(not new_obj.has_pattern(p) for p in self._patterns): yield new_obj, new_state, yld diff --git a/src/sage/combinat/permutation_cython.pyx b/src/sage/combinat/permutation_cython.pyx index 5947b9705c9..1a0b02ac734 100644 --- a/src/sage/combinat/permutation_cython.pyx +++ b/src/sage/combinat/permutation_cython.pyx @@ -22,7 +22,7 @@ speed, we provide a class that wraps our struct. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Tom Boothby <tomas.boothby@gmail.com> # Copyright (C) 2017 Travis Scrimshaw <tscrim@ucdavis.edu> # Copyright (C) 2017 Vincent Delecroix <20100.delecroix@gmail.com> @@ -30,13 +30,11 @@ speed, we provide a class that wraps our struct. # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** cimport cython -from cpython.object cimport PyObject - from cysignals.memory cimport check_allocarray, sig_free diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index c8b29e06294..14d284b77c6 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Plane Partitions @@ -6,10 +5,12 @@ - Jang Soo Kim (2016): Initial implementation - Jessica Striker (2016): Added additional methods +- Kevin Dilks (2021): Added symmetry classes """ # **************************************************************************** # Copyright (C) 2016 Jang Soo Kim <jangsookim@skku.edu>, # 2016 Jessica Striker <jessicapalencia@gmail.com> +# 2021 Kevin Dilks <kdilks@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # @@ -22,23 +23,28 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** + from __future__ import annotations -from typing import Iterator +from typing import NewType, Iterator +from sage.structure.richcmp import richcmp, richcmp_method from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.combinat.posets.posets import Poset from sage.combinat.tableau import Tableau from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modules.free_module_element import vector from sage.rings.integer import Integer from sage.structure.list_clone import ClonableArray from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -lazy_import("sage.plot.plot3d.platonic", "cube") +from sage.rings.integer_ring import ZZ +from sage.arith.misc import Sigma, binomial, factorial +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets +from sage.sets.family import Family +from sage.sets.non_negative_integers import NonNegativeIntegers +@richcmp_method class PlanePartition(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" @@ -49,7 +55,6 @@ class PlanePartition(ClonableArray, INPUT: - ``PP`` -- a list of lists which represents a tableau - - ``box_size`` -- (optional) a list ``[A, B, C]`` of 3 positive integers, where ``A``, ``B``, ``C`` are the lengths of the box in the `x`-axis, `y`-axis, `z`-axis, respectively; if this is not given, it is @@ -69,6 +74,7 @@ class PlanePartition(ClonableArray, sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: TestSuite(PP).run() + sage: hash(PP) # random """ @staticmethod def __classcall_private__(cls, PP, box_size=None): @@ -77,30 +83,110 @@ def __classcall_private__(cls, PP, box_size=None): EXAMPLES:: - sage: PP = PlanePartition([[4,3,3,1], [2,1,1], [1,1]]) - sage: PP.parent() is PlanePartitions((3,4,4)) + sage: p = PlanePartition([[2,1],[1]]) + sage: TestSuite(p).run() + + sage: p.parent() + Plane partitions + sage: p.category() + Category of elements of Plane partitions + sage: type(p) + <class 'sage.combinat.plane_partition.PlanePartitions_all_with_category.element_class'> + """ + if isinstance(PP, PlanePartition) and box_size is None: + return PP + pp = PlanePartitions(box_size=box_size) + return pp.element_class(pp, PP) # The check() will raise the appropriate error + + def __init__(self, parent, pp, check=True): + r""" + Initialize a plane partition. + + TESTS:: + + sage: a = PlanePartitions()([[2,1],[1]]) + sage: b = PlanePartitions([2,2,2])([[2,1],[1]]) + sage: c = PlanePartitions(4)([[2,1],[1]]) + sage: a == b True + sage: a is b + False + sage: a == c + True + sage: a is c + False """ - if box_size is None: - if PP: - box_size = (len(PP), len(PP[0]), PP[0][0]) + if isinstance(pp, PlanePartition): + ClonableArray.__init__(self, parent, pp, check=False) + else: + pp = [list(row) for row in pp] + if pp: + for i in reversed(range(len(pp))): + while pp[i] and not pp[i][-1]: + del pp[i][-1] + if not pp[i]: + pp.pop(i) + pp = [tuple(row) for row in pp] + ClonableArray.__init__(self, parent, pp, check=check) + if self.parent()._box is None: + if pp: + self._max_x = len(pp) + self._max_y = len(pp[0]) + self._max_z = pp[0][0] else: - box_size = (0, 0, 0) - return PlanePartitions(box_size)(PP) + self._max_x = 0 + self._max_y = 0 + self._max_z = 0 + else: + (self._max_x, self._max_y, self._max_z) = self.parent()._box - def __init__(self, parent, PP, check=True): - """ - Initialize ``self``. + def __richcmp__(self, other, op): + r""" + Compare ``self`` to ``other``. - EXAMPLES:: + .. TODO:: - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: TestSuite(PP).run() + This overwrites the comparison check of + :class:`~sage.structure.list_clone.ClonableArray` + in order to circumvent the coercion framework. + Eventually this should be solved more elegantly, + for example along the lines of what was done for + `k`-tableaux. + + For now, this compares two elements by their underlying + defining lists. + + INPUT: + + - ``other`` -- the element that ``self`` is compared to + + OUTPUT: + + A boolean. + + TESTS:: + + sage: t = PlanePartition([[2,1],[1]]) + sage: t == 0 + False + sage: t == PlanePartitions(4)([[2,1],[1]]) + True + + sage: s = PlanePartition([[3,1],[1]]) + sage: s != [] + True + + sage: t < s + True + sage: s < t + False + sage: s > t + True """ - ClonableArray.__init__(self, parent, PP, check=check) - self._max_x = parent._box[0] - self._max_y = parent._box[1] - self._max_z = parent._box[2] + if isinstance(other, PlanePartition): + return self._richcmp_(other, op) + + return richcmp(list(self), other, op) def check(self): """ @@ -108,17 +194,36 @@ def check(self): EXAMPLES:: - sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: PP.check() + sage: a = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) + sage: a.check() + sage: b = PlanePartition([[1,2],[1]]) + Traceback (most recent call last): + ... + ValueError: not weakly decreasing along rows + sage: c = PlanePartition([[1,1],[2]]) + Traceback (most recent call last): + ... + ValueError: not weakly decreasing along columns + sage: d = PlanePartition([[2,-1],[-2]]) + Traceback (most recent call last): + ... + ValueError: entries not all nonnegative + sage: e = PlanePartition([[3/2,1],[.5]]) + Traceback (most recent call last): + ... + ValueError: entries not all integers + """ - if len(self) == 0: - return - if len(self) > self.parent()._box[0]: - raise ValueError("too big in z direction") - if len(self[0]) > self.parent()._box[1]: - raise ValueError("too big in y direction") - if self[0][0] > self.parent()._box[2]: - raise ValueError("too big in x direction") + if not all(a in ZZ for b in self for a in b): + raise ValueError("entries not all integers") + for row in self: + if not all(c >= 0 for c in row): + raise ValueError("entries not all nonnegative") + if not all(row[i] >= row[i+1] for i in range(len(row)-1)): + raise ValueError("not weakly decreasing along rows") + for row, next in zip(self, self[1:]): + if not all(row[c] >= next[c] for c in range(len(next))): + raise ValueError("not weakly decreasing along columns") def _repr_(self) -> str: """ @@ -129,7 +234,7 @@ def _repr_(self) -> str: sage: PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) Plane partition [[4, 3, 3, 1], [2, 1, 1], [1, 1]] """ - return "Plane partition {}".format(list(self)) + return "Plane partition {}".format([list(row) for row in self]) def to_tableau(self) -> Tableau: r""" @@ -143,10 +248,15 @@ def to_tableau(self) -> Tableau: """ return Tableau(self) # type:ignore - def z_tableau(self): + def z_tableau(self, tableau=True) -> Tableau: r""" Return the projection of ``self`` in the `z` direction. + If ``tableau`` is set to ``False``, then only the list of lists + consisting of the projection of boxes size onto the `xy`-plane + is returned instead of a :class:`Tableau` object. This output will + not have empty trailing rows or trailing zeros removed. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -156,12 +266,19 @@ def z_tableau(self): Z = [[0 for i in range(self._max_y)] for j in range(self._max_x)] for C in self.cells(): Z[C[0]][C[1]] += 1 + if tableau: + return Tableau(Z) return Z - def y_tableau(self): + def y_tableau(self, tableau=True) -> Tableau: r""" Return the projection of ``self`` in the `y` direction. + If ``tableau`` is set to ``False``, then only the list of lists + consisting of the projection of boxes size onto the `xz`-plane + is returned instead of a :class:`Tableau` object. This output will + not have empty trailing rows or trailing zeros removed. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -171,12 +288,19 @@ def y_tableau(self): Y = [[0 for i in range(self._max_x)] for j in range(self._max_z)] for C in self.cells(): Y[C[2]][C[0]] += 1 + if tableau: + return Tableau(Y) return Y - def x_tableau(self): + def x_tableau(self, tableau=True) -> Tableau: r""" Return the projection of ``self`` in the `x` direction. + If ``tableau`` is set to ``False``, then only the list of lists + consisting of the projection of boxes size onto the `yz`-plane + is returned instead of a :class:`Tableau` object. This output will + not have empty trailing rows or trailing zeros removed. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -186,6 +310,8 @@ def x_tableau(self): X = [[0 for i in range(self._max_z)] for j in range(self._max_y)] for C in self.cells(): X[C[1]][C[2]] += 1 + if tableau: + return Tableau(X) return X def cells(self) -> list[list[int]]: @@ -205,6 +331,18 @@ def cells(self) -> list[list[int]]: L.append([r, c, h]) return L + def number_of_boxes(self) -> Integer: + r""" + Return the number of boxes in the plane partition. + + EXAMPLES:: + + sage: PP = PlanePartition([[3,1],[2]]) + sage: PP.number_of_boxes() + 6 + """ + return sum(sum(row) for row in self) + def _repr_diagram(self, show_box=False, use_unicode=False) -> str: r""" Return a string of the 3D diagram of ``self``. @@ -314,8 +452,8 @@ def add_leftside(i, j, k): return u"โˆ…" if use_unicode else "" if use_unicode: - return u'\n'.join(u"".join(s for s in row) for row in drawing) - return '\n'.join("".join(s for s in row) for row in drawing) + return u'\n'.join(u"".join(row) for row in drawing) + return '\n'.join("".join(row) for row in drawing) def _ascii_art_(self): r""" @@ -429,7 +567,9 @@ def _repr_svg_(self) -> str: vx = -vector([0.866, -0.5]) vy = -vector([-0.866, -0.5]) vz = -vector([0, 1]) - Nx, Ny, Nz = self.parent().box() + # Since we currently don't display the bounding box, just + # use the smallest one possible. + Nx, Ny, Nz = self.bounding_box() resu += '\"%.3f %.3f %.3f %.3f \">' % (-0.866 * Nx, -Nz, 0.866 * Nx + 0.866 * Ny, @@ -471,7 +611,6 @@ def _latex_(self, show_box=False, - ``show_box`` -- boolean (default: ``False``); if ``True``, also shows the visible tiles on the `xy`-, `yz`-, `zx`-planes - - ``colors`` -- (default: ``["white", "lightgray", "darkgray"]``) list ``[A, B, C]`` of 3 strings representing colors @@ -524,14 +663,13 @@ def plot(self, show_box=False, colors=None): - ``show_box`` -- boolean (default: ``False``); if ``True``, also shows the visible tiles on the `xy`-, `yz`-, `zx`-planes - - ``colors`` -- (default: ``["white", "lightgray", "darkgray"]``) list ``[A, B, C]`` of 3 strings representing colors EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: PP.plot() + sage: PP.plot() # optional - sage.plot Graphics object consisting of 27 graphics primitives """ from sage.functions.trig import cos, sin @@ -582,6 +720,40 @@ def add_rightside(i, j, k): TP.axes(show=False) return TP + def contains(self, PP) -> bool: + r""" + Return ``True`` if ``PP`` is a plane partition that fits + inside ``self``. + + Specifically, ``self`` contains ``PP`` if, for all `i`, `j`, + the height of ``PP`` at `ij` is less than or equal to the + height of ``self`` at `ij`. + + EXAMPLES:: + + sage: P1 = PlanePartition([[5,4,3], [3,2,2], [1]]) + sage: P2 = PlanePartition([[3,2], [1,1], [0,0], [0,0]]) + sage: P3 = PlanePartition([[5,5,5], [2,1,0]]) + sage: P1.contains(P2) + True + sage: P2.contains(P1) + False + sage: P1.contains(P3) + False + sage: P3.contains(P2) + True + """ + if not isinstance(PP, PlanePartition): + PP = PlanePartition(PP) + if len(self) < len(PP): + return False + for rowself, rowPP in zip(self, PP): + if len(rowself) < len(rowPP): + return False + if any(valself < valPP for valself, valPP in zip(rowself, rowPP)): + return False + return True + def plot3d(self, colors=None): r""" Return a 3D-plot of ``self``. @@ -594,24 +766,35 @@ def plot3d(self, colors=None): EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) - sage: PP.plot3d() + sage: PP.plot3d() # optional - sage.plot Graphics3d Object """ if colors is None: colors = ["white", "lightgray", "darkgray"] + from sage.plot.plot3d.platonic import cube return sum(cube(c, color=colors, frame_thickness=2, frame_color='black', frame=False) for c in self.cells()) - def complement(self, tableau_only=False): + def complement(self, tableau_only=False) -> PP: r""" Return the complement of ``self``. + If the parent of ``self`` consists only of partitions inside a given + box, then the complement is taken in this box. Otherwise, the + complement is taken in the smallest box containing the plane partition. + The empty plane partition with no box specified is its own complement. + + If ``tableau_only`` is set to ``True``, then only the tableau + consisting of the projection of boxes size onto the `xy`-plane + is returned instead of a :class:`PlanePartition`. This output will + not have empty trailing rows or trailing zeros removed. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.complement() - Plane partition [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1, 0]] + Plane partition [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1]] sage: PP.complement(True) [[4, 4, 3, 3], [4, 3, 3, 2], [3, 1, 1, 0]] """ @@ -622,33 +805,52 @@ def complement(self, tableau_only=False): z_tab = self.z_tableau() for r in range(A): for c in range(B): - T[A - 1 - r][B - 1 - c] = C - z_tab[r][c] + T[A-1-r][B-1-c] = C - z_tab[r][c] if tableau_only: return T - else: - return type(self)(self.parent(), T, check=False) + P = self.parent() + if not P._box: + pp = PlanePartitions() + return pp.element_class(pp, T) + return P.element_class(P, T, check=False) - def transpose(self, tableau_only=False): + def transpose(self, tableau_only=False) -> PP: r""" Return the transpose of ``self``. + If ``tableau_only`` is set to ``True``, then only the tableau + consisting of the projection of boxes size onto the `xy`-plane + is returned instead of a :class:`PlanePartition`. This will + not necessarily have trailing rows or trailing zeros removed. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.transpose() - Plane partition [[4, 2, 1], [3, 1, 1], [3, 1, 0], [1, 0, 0]] + Plane partition [[4, 2, 1], [3, 1, 1], [3, 1], [1]] sage: PP.transpose(True) [[4, 2, 1], [3, 1, 1], [3, 1, 0], [1, 0, 0]] + + sage: PPP = PlanePartitions([1, 2, 3]) + sage: PP = PPP([[1, 1]]) + sage: PT = PP.transpose(); PT + Plane partition [[1], [1]] + sage: PT.parent() + Plane partitions inside a 2 x 1 x 3 box """ T = [[0 for i in range(self._max_x)] for j in range(self._max_y)] z_tab = self.z_tableau() for r in range(len(z_tab)): for c in range(len(z_tab[r])): T[c][r] = z_tab[r][c] + P = self.parent() if tableau_only: return T - else: - return type(self)(self.parent(), T, check=False) + elif P._box is None or P._box[0] == P._box[1]: + return P.element_class(P, T, check=False) + new_box = (P._box[1], P._box[0], P._box[2]) + newP = PlanePartitions(new_box, symmetry=P._symmetry) + return newP.element_class(newP, T) def is_SPP(self) -> bool: r""" @@ -677,7 +879,14 @@ def is_SPP(self) -> bool: sage: PP = PlanePartition([[3,2],[2,0],[0,0]]) sage: PP.is_SPP() True + + TESTS:: + + sage: PlanePartition([]).is_SPP() + True """ + if not self: + return True Z = self.z_tableau() c1 = len(Z) c2 = len(Z[0]) @@ -705,6 +914,11 @@ def is_CSPP(self) -> bool: sage: PP = PlanePartition([[3,2,2],[3,1,0],[1,1,0]]) sage: PP.is_CSPP() True + + TESTS:: + + sage: PlanePartition([]).is_CSPP() + True """ if self.z_tableau() == self.y_tableau(): return True @@ -725,6 +939,11 @@ def is_TSPP(self) -> bool: sage: PP = PlanePartition([[3,3,3],[3,3,2],[3,2,1]]) sage: PP.is_TSPP() True + + TESTS:: + + sage: PlanePartition([]).is_TSPP() + True """ return self.is_CSPP() and self.is_SPP() @@ -732,6 +951,11 @@ def is_SCPP(self) -> bool: r""" Return whether ``self`` is a self-complementary plane partition. + Note that the complement of a plane partition (and thus the property of + being self-complementary) is dependent on the choice of a box that it is + contained in. If no parent/bounding box is specified, the box is taken + to be the smallest box that contains the plane partition. + EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) @@ -739,9 +963,17 @@ def is_SCPP(self) -> bool: False sage: PP = PlanePartition([[4,4,4,4],[4,4,2,0],[4,2,0,0],[0,0,0,0]]) sage: PP.is_SCPP() + False + sage: PP = PlanePartitions([4,4,4])([[4,4,4,4],[4,4,2,0],[4,2,0,0],[0,0,0,0]]) + sage: PP.is_SCPP() + True + + TESTS:: + + sage: PlanePartition([]).is_SCPP() True """ - return self.z_tableau() == self.complement(True) + return self.z_tableau(tableau=False) == self.complement(tableau_only=True) def is_TCPP(self) -> bool: r""" @@ -755,6 +987,11 @@ def is_TCPP(self) -> bool: sage: PP = PlanePartition([[4,4,3,2],[4,4,2,1],[4,2,0,0],[2,0,0,0]]) sage: PP.is_TCPP() True + + TESTS:: + + sage: PlanePartition([]).is_TCPP() + True """ return self.transpose(True) == self.complement(True) @@ -780,6 +1017,11 @@ def is_SSCPP(self) -> bool: sage: PP = PlanePartition([[4,2,2,2],[2,2,2,2],[2,2,2,2],[2,2,2,0]]) sage: PP.is_SSCPP() True + + TESTS:: + + sage: PlanePartition([]).is_SSCPP() + True """ return self.is_SPP() and self.is_SCPP() @@ -796,6 +1038,11 @@ def is_CSTCPP(self) -> bool: sage: PP = PlanePartition([[4,4,3,2],[4,3,2,1],[3,2,1,0],[2,1,0,0]]) sage: PP.is_CSTCPP() True + + TESTS:: + + sage: PlanePartition([]).is_CSTCPP() + True """ return self.is_CSPP() and self.is_TCPP() @@ -812,6 +1059,11 @@ def is_CSSCPP(self) -> bool: sage: PP = PlanePartition([[4,4,4,1],[3,3,2,1],[3,2,1,1],[3,0,0,0]]) sage: PP.is_CSSCPP() True + + TESTS:: + + sage: PlanePartition([]).is_CSSCPP() + True """ return self.is_CSPP() and self.is_SCPP() @@ -828,64 +1080,474 @@ def is_TSSCPP(self) -> bool: sage: PP = PlanePartition([[4,4,3,2],[4,3,2,1],[3,2,1,0],[2,1,0,0]]) sage: PP.is_TSSCPP() True + + TESTS:: + + sage: PlanePartition([]).is_TSSCPP() + True """ return self.is_TSPP() and self.is_SCPP() + def to_order_ideal(self): + r""" + Return the order ideal corresponding to ``self``. + + .. TODO:: + + As many families of symmetric plane partitions are in bijection + with order ideals in an associated poset, this function could + feasibly have options to send symmetric plane partitions + to the associated order ideal in that poset, instead. + + EXAMPLES:: + + sage: PlanePartition([[3,2,1],[2,2],[2]]).to_order_ideal() + [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 2, 0), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (2, 0, 0), (2, 0, 1)] + sage: PlanePartition([[2,1],[1],[1]]).to_order_ideal() + [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (2, 0, 0)] + """ + from sage.combinat.posets.poset_examples import posets + (a, b, c) = (self._max_x, self._max_y, self._max_z) + Q = posets.ProductOfChains([a, b, c]) + count = 0 + generate = [] + for i, row in enumerate(self): + for j, val in enumerate(row): + if val > 0: + generate.append((i, j, val-1)) + count += 1 + oi = Q.order_ideal(generate) + return oi + + def maximal_boxes(self) -> list: + r""" + Return the coordinates of the maximal boxes of ``self``. + + The maximal boxes of a plane partitions are the boxes that can be + removed from a plane partition and still yield a valid plane partition. + + EXAMPLES:: + + sage: sorted(PlanePartition([[3,2,1],[2,2],[2]]).maximal_boxes()) + [[0, 0, 2], [0, 2, 0], [1, 1, 1], [2, 0, 1]] + sage: sorted(PlanePartition([[2,1],[1],[1]]).maximal_boxes()) + [[0, 0, 1], [0, 1, 0], [2, 0, 0]] + """ + generate = [] + for i, row in enumerate(self): + for j, entry in enumerate(row): + if (i == len(self)-1 or len(self[i+1])-1 < j or self[i+1][j] < entry) and (j == len(row)-1 or row[j+1] < entry): + generate.append([i, j, entry-1]) + return generate + + def cyclically_rotate(self, preserve_parent=False) -> PP: + r""" + Return the cyclic rotation of ``self``. + + By default, if the parent of ``self`` consists of plane + partitions inside an `a \times b \times c` box, the result + will have a parent consisting of partitions inside + a `c \times a \times b` box, unless the optional parameter + ``preserve_parent`` is set to ``True``. Enabling this setting + may give an element that is **not** an element of its parent. + + EXAMPLES:: + + sage: PlanePartition([[3,2,1],[2,2],[2]]).cyclically_rotate() + Plane partition [[3, 3, 1], [2, 2], [1]] + sage: PP = PlanePartition([[4,1],[1],[1]]) + sage: PP.cyclically_rotate() + Plane partition [[3, 1, 1, 1], [1]] + sage: PP == PP.cyclically_rotate().cyclically_rotate().cyclically_rotate() + True + sage: PP = PlanePartitions([4,3,2]).random_element() + sage: PP.cyclically_rotate().parent() + Plane partitions inside a 2 x 4 x 3 box + sage: PP = PlanePartitions([3,4,2])([[2,2,2,2],[2,2,2,2],[2,2,2,2]]) + sage: PP_rotated = PP.cyclically_rotate(preserve_parent=True) + sage: PP_rotated in PP_rotated.parent() + False + """ + b = self._max_y + c = self._max_z + new_antichain = [] + for elem in self.maximal_boxes(): + new = (elem[1], elem[2], elem[0]) + new_antichain.append(new) + pp_matrix = [[0] * (c) for i in range(b)] + for box in new_antichain: + y = box[0] + z = box[1] + x = box[2] + pp_matrix[y][z] = x + 1 + if new_antichain: + for i in range(b): + i = b - (i+1) + for j in range(c): + j = c - (j+1) + if pp_matrix[i][j] == 0: + iValue = 0 + jValue = 0 + if i < b-1: + iValue = pp_matrix[i+1][j] + if j < c-1: + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) + # Start code for determining correct parent + P = self.parent() + if P._box is None or preserve_parent or (P._box[0] == P._box[1] == P._box[2]): + return P.element_class(P, pp_matrix, check=preserve_parent) + new_box = (P._box[2], P._box[0], P._box[1]) + newP = PlanePartitions(new_box, symmetry=P._symmetry) + return newP.element_class(newP, pp_matrix) + + def bounding_box(self): + r""" + Return the smallest box `(a, b, c)` that ``self`` is contained in. + + EXAMPLES:: + + sage: PP = PlanePartition([[5,2,1,1], [2,2], [2]]) + sage: PP.bounding_box() + (3, 4, 5) + """ + if not self: + return (0, 0, 0) + return (len(self), len(self[0]), self[0][0]) -PP = PlanePartition + +PP = NewType('PP', PlanePartition) class PlanePartitions(UniqueRepresentation, Parent): r""" - All plane partitions inside a rectangular box of given side lengths. + Plane partitions. - INPUT: + ``PlanePartitions()`` returns the class of all plane partitions. - - ``box_size`` -- a triple of positive integers indicating the size - of the box containing the plane partition + ``PlanePartitions(n)`` return the class of all plane partitions with + precisely `n` boxes. + + ``PlanePartitions([a, b, c])`` returns the class of plane partitions + that fit inside an `a \times b \times c` box. + + ``PlanePartitions([a, b, c])`` has the optional keyword ``symmetry``, which + restricts the plane partitions inside a box of the specified size satisfying + certain symmetry conditions. + + - ``symmetry='SPP'`` gives the class of symmetric plane partitions. which + is all plane partitions fixed under reflection across the diagonal. + Requires that `a = b`. + + - ``symmetry='CSPP'`` gives the class of cyclic plane partitions, which + is all plane partitions fixed under cyclic rotation of coordinates. + Requires that `a = b = c`. + + - ``symmetry='TSPP'`` gives the class of totally symmetric plane partitions, + which is all plane partitions fixed under any interchanging of coordinates. + Requires that `a = b = c`. + + - ``symmetry='SCPP'`` gives the class of self-complementary plane partitions. + which is all plane partitions that are equal to their own complement + in the specified box. Requires at least one of `a,b,c` be even. + + - ``symmetry='TCPP'`` gives the class of transpose complement plane + partitions, which is all plane partitions whose complement in the box + of the specified size is equal to their transpose. Requires `a = b` and + at least one of `a, b, c` be even. + + - ``symmetry='SSCPP'`` gives the class of symmetric self-complementary + plane partitions, which is all plane partitions that are both + symmetric and self-complementary. Requires `a = b` and at least one of + `a, b, c` be even. + + - ``symmetry='CSTCPP'`` gives the class of cyclically symmetric transpose + complement plane partitions, which is all plane partitions that are + both symmetric and equal to the transpose of their complement. Requires + `a = b = c`. + + - ``symmetry='CSSCPP'`` gives the class of cyclically symmetric + self-complementary plane partitions, which is all plane partitions that + are both cyclically symmetric and self-complementary. Requires `a = b = c` + and all `a, b, c` be even. + + - ``symmetry='TSSCPP'`` gives the class of totally symmetric + self-complementary plane partitions, which is all plane partitions that + are totally symmetric and also self-complementary. Requires `a = b = c` + and all `a, b, c` be even. EXAMPLES: - This will create an instance to manipulate the plane partitions - in a `4 \times 3 \times 2` box:: + If no arguments are passed, then the class of all plane partitions + is returned:: + + sage: PlanePartitions() + Plane partitions + sage: [[2,1],[1]] in PlanePartitions() + True + + If an integer `n` is passed, then the class of plane partitions of `n` + is returned:: + + sage: PlanePartitions(3) + Plane partitions of size 3 + sage: PlanePartitions(3).list() + [Plane partition [[3]], + Plane partition [[2, 1]], + Plane partition [[1, 1, 1]], + Plane partition [[2], [1]], + Plane partition [[1, 1], [1]], + Plane partition [[1], [1], [1]]] + + If a three-element tuple or list `[a,b,c]` is passed, then the class of all + plane partitions that fit inside and `a \times b \times c` box is returned:: + + sage: PlanePartitions([2,2,2]) + Plane partitions inside a 2 x 2 x 2 box + sage: [[2,1],[1]] in PlanePartitions([2,2,2]) + True - sage: P = PlanePartitions((4,3,2)) - sage: P - Plane partitions inside a 4 x 3 x 2 box - sage: P.cardinality() - 490 + If an additional keyword ``symmetry`` is pass along with a three-element + tuple or list `[a, b,c ]`, then the class of all plane partitions that fit + inside an `a \times b \times c` box with the specified symmetry is returned:: + + sage: PlanePartitions([2,2,2], symmetry='CSPP') + Cyclically symmetric plane partitions inside a 2 x 2 x 2 box + sage: [[2,1],[1]] in PlanePartitions([2,2,2], symmetry='CSPP') + True .. SEEALSO:: - :class:`PlanePartition` + - :class:`PlanePartition` + - :class:`PlanePartitions_all` + - :class:`PlanePartitions_n` + - :class:`PlanePartitions_box` + - :class:`PlanePartitions_SPP` + - :class:`PlanePartitions_CSPP` + - :class:`PlanePartitions_TSPP` + - :class:`PlanePartitions_SCPP` + - :class:`PlanePartitions_TCPP` + - :class:`PlanePartitions_SSCPP` + - :class:`PlanePartitions_CSTCPP` + - :class:`PlanePartitions_CSSCPP` + - :class:`PlanePartitions_TSSCPP` """ @staticmethod - def __classcall_private__(cls, box_size): + def __classcall_private__(cls, *args, **kwds): + r""" + Return the appropriate parent based on arguments. + + See the documentation for :class:`PlanePartitions` for more information. + + TESTS:: + + sage: PlanePartitions() + Plane partitions + sage: PlanePartitions([3,3,3]) + Plane partitions inside a 3 x 3 x 3 box + sage: PlanePartitions(3) + Plane partitions of size 3 + sage: PlanePartitions([4,4,4], symmetry='TSSCPP') + Totally symmetric self-complementary plane partitions inside a 4 x 4 x 4 box + sage: PlanePartitions(4, symmetry='TSSCPP') + Traceback (most recent call last): + ... + ValueError: the number of boxes may only be specified if no symmetry is required + """ + symmetry = kwds.get('symmetry', None) + box_size = kwds.get('box_size', None) + + if not args and symmetry is None and box_size is None: + return PlanePartitions_all() + + if args and box_size is None: + # The first arg could be either a size or a box size + if isinstance(args[0], (int, Integer)): + if symmetry is None: + return PlanePartitions_n(args[0]) + else: + raise ValueError("the number of boxes may only be specified if no symmetry is required") + box_size = args[0] + + box_size = tuple(box_size) + if symmetry is None: + return PlanePartitions_box(box_size) + elif symmetry == 'SPP': + return PlanePartitions_SPP(box_size) + elif symmetry == 'CSPP': + return PlanePartitions_CSPP(box_size) + elif symmetry == 'TSPP': + return PlanePartitions_TSPP(box_size) + elif symmetry == 'SCPP': + return PlanePartitions_SCPP(box_size) + elif symmetry == 'TCPP': + return PlanePartitions_TCPP(box_size) + elif symmetry == 'SSCPP': + return PlanePartitions_SSCPP(box_size) + elif symmetry == 'CSTCPP': + return PlanePartitions_CSTCPP(box_size) + elif symmetry == 'CSSCPP': + return PlanePartitions_CSSCPP(box_size) + elif symmetry == 'TSSCPP': + return PlanePartitions_TSSCPP(box_size) + + raise ValueError("invalid symmetry class option") + + def __init__(self, box_size=None, symmetry=None, category=None): + r""" + Initialize ``self``. + + TESTS:: + + sage: PP = PlanePartitions(box_size=[2,2,1]) + sage: TestSuite(PP).run() + """ + if box_size is not None and len(box_size) != 3: + raise ValueError("invalid box size") + self._box = box_size + self._symmetry = symmetry + Parent.__init__(self, category=category) + + Element = PlanePartition + + def __contains__(self, pp): + """ + Check to see that ``pp`` is a valid plane partition. + + EXAMPLES:: + + sage: [[3,2,1],[2,1]] in PlanePartitions() + True + sage: [[3,2,1],[1,2]] in PlanePartitions() + False + sage: [[3,2,1],[3,3]] in PlanePartitions() + False + """ + if isinstance(pp, PlanePartition): + return True + if isinstance(pp, (list, tuple)): + if not pp: + return True + if not all(a in ZZ for b in pp for a in b): + return False + for row in pp: + if not all(c >= 0 for c in row): + return False + if not all(row[i] >= row[i+1] for i in range(len(row)-1)): + return False + for row, nxt in zip(pp, pp[1:]): + if not all(row[c] >= nxt[c] for c in range(len(nxt))): + return False + return True + return False + + def box(self) -> tuple: + """ + Return the size of the box of the plane partition of ``self`` + is contained in. + + EXAMPLES:: + + sage: P = PlanePartitions([4,3,5]) + sage: P.box() + (4, 3, 5) + + sage: PP = PlanePartitions() + sage: PP.box() is None + True + """ + return self._box + + def symmetry(self) -> str: """ - Normalize input to ensure a unique representation. + Return the symmetry class of ``self``. EXAMPLES:: - sage: P1 = PlanePartitions((4,3,2)) - sage: P2 = PlanePartitions([4,3,2]) - sage: P1 is P2 + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: PP.symmetry() + 'SPP' + sage: PP = PlanePartitions() + sage: PP.symmetry() is None True """ - return super().__classcall__(cls, tuple(box_size)) + return self._symmetry + + +class PlanePartitions_all(PlanePartitions, DisjointUnionEnumeratedSets): + r""" + All plane partitions. + """ + def __init__(self): + r""" + Initializes the class of all plane partitions. + + .. WARNING:: + + Input is not checked; please use :class:`PlanePartitions` to + ensure the options are properly parsed. + + TESTS:: + + sage: from sage.combinat.plane_partition import PlanePartitions_all + sage: P = PlanePartitions_all() + sage: TestSuite(P).run() + """ + # We manually set these here rather than invoking the super().__init__(). + # This is so DisjointUnionEnumeratedSets can make the Parent.__init__() call. + self._box = None + self._symmetry = None + # super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) + + DisjointUnionEnumeratedSets.__init__(self, + Family(NonNegativeIntegers(), + PlanePartitions_n), + facade=True, + keepkey=False) + def _repr_(self) -> str: + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: PlanePartitions() + Plane partitions + """ + return "Plane partitions" + + def an_element(self): + r""" + Return a particular element of the class. + + TESTS:: + + sage: P = PlanePartitions() + sage: P.an_element() + Plane partition [[2, 1], [1]] + """ + return self.element_class(self, [[2, 1], [1]]) + + +class PlanePartitions_box(PlanePartitions): + r""" + All plane partitions that fit inside a box of a specified size. + + By convention, a plane partition in an `a \times b \times c` box + will have at most `a` rows, of lengths at most `b`, with entries + at most `c`. + """ def __init__(self, box_size): r""" - Initialize ``self`` + Initializes the class of plane partitions that fit in a box of a + specified size. EXAMPLES:: - sage: PP = PlanePartitions((4,3,2)) - sage: TestSuite(PP).run() + sage: PP = PlanePartitions([4,3,2]) + sage: TestSuite(PP).run() # long time """ - if len(box_size) != 3: - raise ValueError("invalid box size") - self._box = box_size - Parent.__init__(self, category=FiniteEnumeratedSets()) + super().__init__(box_size, category=FiniteEnumeratedSets()) def _repr_(self) -> str: """ @@ -893,26 +1555,121 @@ def _repr_(self) -> str: EXAMPLES:: - sage: PlanePartitions((4,3,2)) + sage: PlanePartitions([4,3,2]) Plane partitions inside a 4 x 3 x 2 box """ return "Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __iter__(self) -> Iterator[PP]: + def __contains__(self, x): + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions([2,2,2]) + True + sage: [[3,1],[1]] in PlanePartitions([2,2,2]) + False + sage: [[2,1],[1],[1]] in PlanePartitions([2,2,2]) + False + sage: [[2,1,1],[1]] in PlanePartitions([2,2,2]) + False + """ + if len(x) == 0: + return True + return PlanePartitions.__contains__(self, x) and len(x) <= self._box[0] and len(x[0]) <= self._box[1] and x[0][0] <= self._box[2] + + def to_poset(self): + r""" + Return the product of three chains poset, whose order ideals are + naturally in bijection with plane partitions inside a box. + + EXAMPLES:: + + sage: PlanePartitions([2,2,2]).to_poset() + Finite lattice containing 8 elements + """ + a = self._box[0] + b = self._box[1] + c = self._box[2] + from sage.combinat.posets.poset_examples import posets + return posets.ProductOfChains([a, b, c]) + + def from_order_ideal(self, I) -> PP: + r""" + Return the plane partition corresponding to an order ideal in the + poset given in :meth:`to_poset`. + + EXAMPLES:: + + sage: I = [(1, 0, 0), (1, 0, 1), (1, 1, 0), (0, 1, 0), (0, 0, 0), (0, 0, 1), (0, 1, 1)] + sage: PlanePartitions([2,2,2]).from_order_ideal(I) + Plane partition [[2, 2], [2, 1]] + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def from_antichain(self, A) -> PP: + r""" + Return the plane partition corresponding to an antichain in the poset + given in :meth:`to_poset`. + + EXAMPLES:: + + sage: A = [(1,0,1), (0,1,1), (1,1,0)] + sage: PlanePartitions([2,2,2]).from_antichain(A) + Plane partition [[2, 2], [2, 1]] """ - Iterate over ``self``. + a = self._box[0] + b = self._box[1] + # Creates a matrix for the plane partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + pp_matrix = [[0] * (b) for i in range(a)] + + # ac format ex: [x,y,z] + # iterate through each antichain, assigning the y,z position in pp_matrix = the height of the stack (x + 1) + for ac in A: + x = ac[0] + y = ac[1] + z = ac[2] + pp_matrix[x][y] = z + 1 + + # For each value in current antichain, fill in the rest of the matrix by + # rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format + if A: + for i in range(a): + i = a - (i + 1) + for j in range(b): + j = b - (j + 1) + if pp_matrix[i][j] == 0: + iValue = 0 + jValue = 0 + if i < a-1: + iValue = pp_matrix[i+1][j] + if j < b-1: + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) + return self.element_class(self, pp_matrix) + + def __iter__(self) -> Iterator: + r""" + Iterate over all partitions that fit inside a box. EXAMPLES:: - sage: list(PlanePartitions((1,2,1))) - [Plane partition [[0, 0]], - Plane partition [[1, 0]], - Plane partition [[1, 1]]] + sage: list(PlanePartitions([1,2,1])) + [Plane partition [], Plane partition [[1]], Plane partition [[1, 1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() + ....: for b in cartesian_product([range(4)]*3) + ....: if (PP := PlanePartitions(b))) + True """ A = self._box[0] B = self._box[1] C = self._box[2] + if not A: + yield self.element_class(self, [], check=False) + return from sage.combinat.tableau import SemistandardTableaux as SST for T in SST([B for i in range(A)], max_entry=C + A): # type:ignore PP = [[0 for _ in range(B)] for _ in range(A)] @@ -935,34 +1692,25 @@ def cardinality(self) -> Integer: EXAMPLES:: - sage: P = PlanePartitions((4,3,5)) + sage: P = PlanePartitions([4,3,5]) sage: P.cardinality() 116424 """ A = self._box[0] B = self._box[1] C = self._box[2] - return Integer(prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) + return Integer(prod(i + j + k - 1 + for i in range(1, A + 1) + for j in range(1, B + 1) + for k in range(1, C + 1)) // + prod(i + j + k - 2 for i in range(1, A + 1) for j in range(1, B + 1) for k in range(1, C + 1))) - def box(self) -> tuple: - """ - Return the sizes of the box of the plane partitions of ``self`` - are contained in. - - EXAMPLES:: - - sage: P = PlanePartitions((4,3,5)) - sage: P.box() - (4, 3, 5) - """ - return self._box - def random_element(self) -> PP: r""" - Return a uniformly random element of ``self``. + Return a uniformly random plane partition inside a box. ALGORITHM: @@ -972,21 +1720,1579 @@ def random_element(self) -> PP: EXAMPLES:: - sage: P = PlanePartitions((4,3,5)) - sage: p = P.random_element() - sage: p.parent() is P - True + sage: P = PlanePartitions([4,3,5]) + sage: P.random_element() # random + Plane partition [[4, 3, 3], [4], [2]] """ - def leq(thing1, thing2): - return all(thing1[i] <= thing2[i] for i in range(len(thing1))) - elem = [(i, j, k) for i in range(self._box[0]) - for j in range(self._box[1]) - for k in range(self._box[2])] - myposet = Poset((elem, leq)) - R = myposet.random_order_ideal() - Z = [[0 for i in range(self._box[1])] for j in range(self._box[0])] - for C in R: - Z[C[0]][C[1]] += 1 + Z = self.from_order_ideal(self.to_poset().random_order_ideal()) return self.element_class(self, Z, check=False) - Element = PlanePartition + +class PlanePartitions_n(PlanePartitions): + """ + Plane partitions with a fixed number of boxes. + """ + def __init__(self, n): + r""" + Initializes the class of plane partitions with ``n`` boxes. + + .. WARNING:: + + Input is not checked; please use :class:`PlanePartitions` to + ensure the options are properly parsed. + + TESTS:: + + sage: PP = PlanePartitions(4) + sage: type(PP) + <class 'sage.combinat.plane_partition.PlanePartitions_n_with_category'> + sage: TestSuite(PP).run() + """ + super(PlanePartitions_n, self).__init__(category=FiniteEnumeratedSets()) + self._n = n + + def _repr_(self) -> str: + """ + TESTS:: + + sage: PlanePartitions(3) + Plane partitions of size 3 + """ + return "Plane partitions of size {}".format(self._n) + + def __contains__(self, x) -> bool: + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions(4) + True + sage: [[2,1],[1]] in PlanePartitions(3) + False + """ + return PlanePartitions.__contains__(self, x) and PlanePartition(x).number_of_boxes() == self._n + + def __iter__(self) -> Iterator: + r""" + Iterate over all plane partitions of a fixed size. + + EXAMPLES:: + + sage: list(PlanePartitions(2)) + [Plane partition [[2]], Plane partition [[1, 1]], Plane partition [[1], [1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() for n in range(9) if (PP := PlanePartitions(n))) + True + """ + from sage.combinat.partition import Partitions + + def P_in_shape_iter(n, la): + if n < 0 or sum(la) < n: + return + if n == 0: + yield [] + return + if len(la) == 1: + if la[0] >= n: + yield [n] + return + if sum(la) == n: + yield la + return + for mu_0 in range(min(n, la[0]), 0, -1): + new_la = [min(mu_0, la[i]) for i in range(1, len(la))] + for mu in P_in_shape_iter(n-mu_0, new_la): + yield [mu_0] + mu + + def PP_first_row_iter(n, la): + m = n - sum(la) + if m < 0: + return + if m == 0: + yield [la] + return + for k in range(m, 0, -1): + for mu in P_in_shape_iter(k, la): + for PP in PP_first_row_iter(m, mu): + yield [la] + PP + + n = self._n + if not n: + yield PlanePartition([]) + return + + for m in range(n, 0, -1): + for la in Partitions(m): + for a in PP_first_row_iter(n, la): + yield self.element_class(self, a, check=False) + + def cardinality(self) -> Integer: + r""" + Return the number of plane partitions with ``n`` boxes. + + Calculated using the recurrence relation + + .. MATH:: + + PL(n) = \sum_{k=1}^n PL(n-k) \sigma_2(k), + + where `\sigma_k(n)` is the sum of the `k`-th powers of + divisors of `n`. + + EXAMPLES:: + + sage: P = PlanePartitions(17) + sage: P.cardinality() + 18334 + + """ + PPn = [1] + for i in range(1, 1+self._n): + nextPPn = sum(PPn[i-k] * Sigma()(k, 2) for k in range(1, i+1)) / i + PPn.append(nextPPn) + return Integer(PPn[-1]) + + +# Symmetry classes are enumerated and labelled in order as in Proofs and +# Confirmations/Stanley (with all plane partitions being the first class) + +# Class 2 +# Symmetric Plane Partitions +class PlanePartitions_SPP(PlanePartitions): + r""" + Plane partitions that fit inside a box of a specified size that are + symmetric. + """ + def __init__(self, box_size): + """ + Initialize ``self``. + + TESTS:: + + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='SPP') + Traceback (most recent call last): + ... + ValueError: x and y dimensions (4 and 3) must be equal + """ + if box_size[0] != box_size[1]: + raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) + super().__init__(box_size, "SPP", category=FiniteEnumeratedSets()) + + def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([3,3,2], symmetry='SPP') + Symmetric plane partitions inside a 3 x 3 x 2 box + """ + return "Symmetric plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __contains__(self, x) -> bool: + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions([2,2,2], symmetry='SPP') + True + sage: [[2,1],[1]] in PlanePartitions([1,1,1], symmetry='SPP') + False + sage: [[2,1],[2]] in PlanePartitions([2,2,2], symmetry='SPP') + False + """ + P = PlanePartition(x) + max = (P._max_x, P._max_y, P._max_z) + return (PlanePartitions.__contains__(self, x) + and P.is_SPP() + and all(a <= b for a, b in zip(max, self._box))) + + def to_poset(self): + r""" + Return a poset whose order ideals are in bijection with + symmetric plane partitions. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: PP.to_poset() + Finite poset containing 12 elements + sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() + True + """ + a = self._box[0] + c = self._box[2] + + def comp(x, y): + return all(a <= b for a, b in zip(x, y)) + + pl = [(x, y, z) for x in range(a) for y in range(x + 1) + for z in range(c)] + from sage.combinat.posets.posets import Poset + return Poset((pl, comp)) + + def from_order_ideal(self, I) -> PP: + r""" + Return the symmetric plane partition corresponding to an order ideal + in the poset given in :meth:`to_poset()`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: I = [(0, 0, 0), (1, 0, 0), (1, 1, 0), (2, 0, 0)] + sage: PP.from_order_ideal(I) + Plane partition [[1, 1, 1], [1, 1], [1]] + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def from_antichain(self, A) -> PP: + r""" + Return the symmetric plane partition corresponding to an antichain + in the poset given in :meth:`to_poset()`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: A = [(2, 2, 0), (1, 0, 1), (1, 1, 0)] + sage: PP.from_antichain(A) + Plane partition [[2, 2, 1], [2, 1, 1], [1, 1, 1]] + """ + # Initialize an empty plane partition + a = self._box[0] + b = self._box[1] + pp_matrix = [[0] * (b) for i in range(a)] + # Antichain indicates where the 'corners' will be in the plane partition + for ac in A: + x = ac[0] + y = ac[1] + z = ac[2] + pp_matrix[x][y] = z + 1 + # Fill out the rest of the plane partition using symmetry and the + # rule pp[i][j]=max(pp[i][j+1],pp[i+1][j]) + if A: + for i in range(a): + i = a - (i + 1) + for j in range(b): + j = b - (j + 1) + if pp_matrix[i][j] == 0 and i >= j: + iValue = 0 + jValue = 0 + if i < a - 1: + iValue = pp_matrix[i+1][j] + if j < b - 1: + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) + elif j > i: + pp_matrix[i][j] = pp_matrix[j][i] + return self.element_class(self, pp_matrix) + + def __iter__(self) -> Iterator: + """ + Iterate over all symmetric plane partitions. + + EXAMPLES:: + + sage: list(PlanePartitions([2,2,1], symmetry='SPP')) + [Plane partition [], + Plane partition [[1, 1], [1, 1]], + Plane partition [[1, 1], [1]], + Plane partition [[1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() + ....: for a, b in cartesian_product([range(4)]*2) + ....: if (PP := PlanePartitions([a, a, b], symmetry='SPP'))) + True + """ + for acl in self.to_poset().antichains_iterator(): + yield self.from_antichain(acl) + + def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of symmetric plane partitions inside an `a \times a \times b` + box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{a} \frac{2i + b - 1}{2i - 1}\right) + \left(\prod_{1 \leq i < j \leq a} \frac{i+j+b-1}{i+j-1}\right). + + EXAMPLES:: + + sage: P = PlanePartitions([3,3,2], symmetry='SPP') + sage: P.cardinality() + 35 + """ + a = self._box[0] + c = self._box[2] + left_prod_num = prod(2*i + c - 1 for i in range(1, a+1)) + left_prod_den = prod(2*i - 1 for i in range(1, a+1)) + right_prod_num = prod(i + j + c - 1 + for j in range(1, a+1) + for i in range(1, j)) + right_prod_den = prod(i + j - 1 + for j in range(1, a+1) + for i in range(1, j)) + return Integer(left_prod_num * right_prod_num // left_prod_den // right_prod_den) + + def random_element(self) -> PP: + r""" + Return a uniformly random element of ``self``. + + ALGORITHM: + + This uses the + :meth:`~sage.combinat.posets.posets.FinitePoset.random_order_ideal` + method and the natural bijection between symmetric plane partitions + and order ideals in an associated poset. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,2], symmetry='SPP') + sage: PP.random_element() # random + Plane partition [[2, 2, 2], [2, 2], [2]] + """ + Z = self.from_order_ideal(self.to_poset().random_order_ideal()) + return self.element_class(self, Z, check=False) + + +# Class 3 +# Cyclically Symmetric Plane Partitions +class PlanePartitions_CSPP(PlanePartitions): + r""" + Plane partitions that fit inside a box of a specified size that are + cyclically symmetric. + """ + def __init__(self, box_size): + """ + Initialize ``self``. + + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') + sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='CSPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (4,3,2) must all be equal + """ + if box_size[0] != box_size[1] or box_size[1] != box_size[2]: + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(*box_size)) + super().__init__(box_size, "CSPP", category=FiniteEnumeratedSets()) + + def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([3,3,3], symmetry='CSPP') + Cyclically symmetric plane partitions inside a 3 x 3 x 3 box + """ + return "Cyclically symmetric plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __contains__(self, x) -> bool: + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions([2,2,2], symmetry='CSPP') + True + sage: [[2,1],[1]] in PlanePartitions([1,1,1], symmetry='CSPP') + False + sage: [[2,1],[2]] in PlanePartitions([2,2,2], symmetry='CSPP') + False + """ + P = PlanePartition(x) + max = (P._max_x, P._max_y, P._max_z) + return (PlanePartitions.__contains__(self, x) + and P.is_CSPP() + and all(a <= b for a, b in zip(max, self._box))) + + def to_poset(self): + """ + Return a partially ordered set whose order ideals are in bijection with + cyclically symmetric plane partitions. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') + sage: PP.to_poset() + Finite poset containing 11 elements + sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() + True + """ + a = self._box[0] + b = self._box[1] + c = self._box[2] + + def comp(x, y): + return all(a <= b for a, b in zip(x, y)) + + def comp2(x, y): + return comp(x, y) or comp(x, (y[2], y[0], y[1])) or comp(x, (y[1], y[2], y[0])) + + pl = [(x, y, z) for x in range(a) for y in range(b) for z in range(x, c) + if y <= z and (x != z or y == x)] + from sage.combinat.posets.posets import Poset + return Poset((pl, comp2)) + + def from_antichain(self, acl) -> PP: + r""" + Return the cyclically symmetric plane partition corresponding to an + antichain in the poset given in :meth:`to_poset()`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') + sage: A = [(0, 2, 2), (1, 1, 1)] + sage: PP.from_antichain(A) + Plane partition [[3, 3, 3], [3, 2, 1], [3, 1, 1]] + """ + b = self._box[1] + c = self._box[2] + pp_matrix = [[0] * (c) for i in range(b)] + # creates a matrix for the plane partition populated by 0s + # EX: [[0,0,0], [0,0,0], [0,0,0]] + # ac format ex: [x,y,z] + for ac in acl: + x = ac[0] + y = ac[1] + z = ac[2] + pp_matrix[y][z] = (x+1) + pp_matrix[z][x] = (y+1) + pp_matrix[x][y] = (z+1) + + # For each value in current antichain, fill in the rest of the + # matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is + # now in plane partition format. + if acl != []: + for i in range(b): + i = b - (i + 1) + for j in range(c): + j = c - (j + 1) + if pp_matrix[i][j] == 0: + iValue = 0 + jValue = 0 + if i < b - 1: + iValue = pp_matrix[i+1][j] + if j < c - 1: + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) + return self.element_class(self, pp_matrix) + + def from_order_ideal(self, I) -> PP: + r""" + Return the cylically symmetric plane partition corresponding + to an order ideal in the poset given in :meth:`to_poset`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') + sage: I = [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1), (0, 1, 2), + ....: (1, 0, 2), (0, 2, 2), (1, 1, 1), (1, 1, 2), (1, 2, 2)] + sage: PP.from_order_ideal(I) + Plane partition [[3, 3, 3], [3, 3, 3], [3, 3, 2]] + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def random_element(self) -> PP: + r""" + Return a uniformly random element of ``self``. + + ALGORITHM: + + This uses the + :meth:`~sage.combinat.posets.posets.FinitePoset.random_order_ideal` + method and the natural bijection between cyclically symmetric plane + partitions and order ideals in an associated poset. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='CSPP') + sage: PP.random_element() # random + Plane partition [[3, 2, 2], [3, 1], [1, 1]] + """ + Z = self.from_order_ideal(self.to_poset().random_order_ideal()) + return self.element_class(self, Z, check=False) + + def __iter__(self) -> Iterator: + """ + Iterate over all cyclically symmetric plane partitions. + + EXAMPLES:: + + sage: list(PlanePartitions([2,2,2], symmetry='CSPP')) + [Plane partition [], + Plane partition [[2, 2], [2, 2]], + Plane partition [[2, 2], [2, 1]], + Plane partition [[2, 1], [1]], + Plane partition [[1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() for n in range(5) if (PP := PlanePartitions([n]*3, symmetry='CSPP'))) + True + """ + for acl in self.to_poset().antichains_iterator(): + yield self.from_antichain(acl) + + def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of cyclically symmetric plane partitions inside an + `a \times a \times a` box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{a} \frac{3i - 1}{3i - 2}\right) + \left(\prod_{1 \leq i < j \leq a} \frac{i+j+a-1}{2i+j-1}\right). + + EXAMPLES:: + + sage: P = PlanePartitions([4,4,4], symmetry='CSPP') + sage: P.cardinality() + 132 + """ + a = self._box[0] + num = (prod(3*i - 1 for i in range(1, a + 1)) + * prod(i + j + a - 1 for j in range(1, a + 1) + for i in range(1, j + 1))) + den = (prod(3*i - 2 for i in range(1, a + 1)) + * prod(2*i + j - 1 for j in range(1, a + 1) + for i in range(1, j + 1))) + return Integer(num // den) + + +# Class 4 +# Totally Symmetric Plane Partitions +class PlanePartitions_TSPP(PlanePartitions): + r""" + Plane partitions that fit inside a box of a specified size that are + totally symmetric. + """ + def __init__(self, box_size): + """ + Initialize ``self``. + + TESTS:: + + sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') + sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='TSPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (4,3,2) must all be equal + """ + if box_size[0] != box_size[1] or box_size[1] != box_size[2]: + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(box_size[0], box_size[1], box_size[2])) + super().__init__(box_size, "TSPP", category=FiniteEnumeratedSets()) + + def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([3,3,3], symmetry='TSPP') + Totally symmetric plane partitions inside a 3 x 3 x 3 box + """ + return "Totally symmetric plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __contains__(self, x) -> bool: + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions([2,2,2], symmetry='TSPP') + True + sage: [[2,1],[1]] in PlanePartitions([1,1,1], symmetry='TSPP') + False + sage: [[2,1],[2]] in PlanePartitions([2,2,2], symmetry='TSPP') + False + """ + P = PlanePartition(x) + maxval = (P._max_x, P._max_y, P._max_z) + return (PlanePartitions.__contains__(self, x) and P.is_TSPP() + and all(a <= b for a, b in zip(maxval, self._box))) + + def to_poset(self): + r""" + Return a poset whose order ideals are in bijection with totally + symmetric plane partitions. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') + sage: PP.to_poset() + Finite poset containing 10 elements + sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() + True + """ + a = self._box[0] + b = self._box[1] + c = self._box[2] + + def comp(x, y): + return all(a <= b for a, b in zip(x, y)) + + pl = [(x, y, z) for x in range(a) for y in range(x, b) for z in range(y, c)] + from sage.combinat.posets.posets import Poset + return Poset((pl, comp)) + + def from_antichain(self, acl) -> PP: + r""" + Return the totally symmetric plane partition corresponding to an + antichain in the poset given in :meth:`to_poset()`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') + sage: A = [(0, 0, 2), (0, 1, 1)] + sage: PP.from_antichain(A) + Plane partition [[3, 2, 1], [2, 1], [1]] + """ + b = self._box[1] + c = self._box[2] + pp_matrix = [[0] * (c) for i in range(b)] # creates a matrix for the plane + # partition populated by 0s EX: [[0,0,0], [0,0,0], [0,0,0]] + for ac in acl: + x = ac[0] + y = ac[1] + z = ac[2] + + pp_matrix[y][z] = x + 1 # x,y,z + pp_matrix[z][x] = y + 1 # y,z,x + pp_matrix[x][y] = z + 1 # z,x,y + + pp_matrix[z][y] = x + 1 # x,z,y + pp_matrix[x][z] = y + 1 # y,x,z + pp_matrix[y][x] = z + 1 # z,y,x + + # for each value in current antichain, fill in the rest of the matrix by + # rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichiain is now in plane partition format + if acl != []: + for i in range(b): + i = b - (i + 1) + for j in range(c): + j = c - (j + 1) + if pp_matrix[i][j] == 0: + iValue = 0 + jValue = 0 + if i < b - 1: + iValue = pp_matrix[i+1][j] + if j < c - 1: + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) + return self.element_class(self, pp_matrix) + + def from_order_ideal(self, I) -> PP: + r""" + Return the totally symmetric plane partition corresponding + to an order ideal in the poset given in :meth:`to_poset`. + + EXAMPLES:: + + sage: PP = PlanePartitions([3,3,3], symmetry='TSPP') + sage: I = [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1)] + sage: PP.from_order_ideal(I) + Plane partition [[3, 2, 1], [2, 1], [1]] + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def __iter__(self) -> Iterator: + """ + An iterator for totally symmetric plane partitions. + + EXAMPLES:: + + sage: list(PlanePartitions([2,2,2], symmetry='TSPP')) + [Plane partition [], + Plane partition [[2, 2], [2, 2]], + Plane partition [[2, 2], [2, 1]], + Plane partition [[2, 1], [1]], + Plane partition [[1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() for n in range(5) if (PP := PlanePartitions([n]*3, symmetry='TSPP'))) + True + """ + for acl in self.to_poset().antichains_iterator(): + yield self.from_antichain(acl) + + def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of totally symmetric plane partitions inside an + `a \times a \times a` box is equal to + + .. MATH:: + + \prod_{1 \leq i \leq j \leq a} \frac{i+j+a-1}{i+2j-2}. + + EXAMPLES:: + + sage: P = PlanePartitions([4,4,4], symmetry='TSPP') + sage: P.cardinality() + 66 + """ + a = self._box[0] + num = prod(i + j + a - 1 for j in range(1, a + 1) for i in range(1, j + 1)) + den = prod(i + 2*j - 2 for j in range(1, a + 1) for i in range(1, j + 1)) + return Integer(num // den) + + +# Class 5 +# Self-complementary Plane Partitions +class PlanePartitions_SCPP(PlanePartitions): + r""" + Plane partitions that fit inside a box of a specified size that are + self-complementary. + """ + def __init__(self, box_size): + """ + Initialize ``self``. + + TESTS:: + + sage: PP = PlanePartitions([4,3,2], symmetry='SCPP') + sage: TestSuite(PP).run() + sage: PlanePartitions([5,3,1], symmetry='SCPP') + Traceback (most recent call last): + ... + ValueError: dimensions (5,3,1) cannot all be odd + """ + if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): + raise ValueError("dimensions ({},{},{}) cannot all be odd".format(*box_size)) + super().__init__(box_size, "SCPP", category=FiniteEnumeratedSets()) + + def __contains__(self, x) -> bool: + """ + TESTS:: + + sage: [[2,1],[1]] in PlanePartitions([2,2,2], symmetry='SCPP') + True + sage: [[2,1],[1]] in PlanePartitions([3,2,2], symmetry='SCPP') + False + sage: [[2,1],[1]] in PlanePartitions([2,1,1], symmetry='SCPP') + False + sage: [[2,1],[2]] in PlanePartitions([2,2,2], symmetry='SCPP') + False + """ + # P = PlanePartitions(self._box)(x) + # max = (P._max_x, P._max_y, P._max_z) + # return PlanePartitions.__contains__(self, x) and P.is_SCPP() and all( a<=b for a,b in zip(max,self._box)) + return x in PlanePartitions(self._box) and PlanePartitions(self._box)(x).is_SCPP() + + def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([4,3,2], symmetry='SCPP') + Self-complementary plane partitions inside a 4 x 3 x 2 box + """ + return "Self-complementary plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __iter__(self) -> Iterator: + """ + An iterator for self-complementary plane partitions. + + EXAMPLES:: + + sage: list(PlanePartitions([3,2,2], symmetry='SCPP')) + [Plane partition [[1, 1], [1, 1], [1, 1]], + Plane partition [[2, 1], [1, 1], [1]], + Plane partition [[2, 2], [1, 1]], + Plane partition [[2], [2], [2]], + Plane partition [[2, 1], [2], [1]], + Plane partition [[2, 2], [2]]] + + TESTS:: + + sage: PP = PlanePartitions([3,4,5], symmetry='SCPP') + sage: len(set(PP)) == PP.cardinality() + True + + sage: all(len(set(PP)) == PP.cardinality() + ....: for b in cartesian_product([range(4)]*3) + ....: if is_even(prod(b)) and (PP := PlanePartitions(b, symmetry='SCPP'))) + True + """ + b = self._box[0] + a = self._box[1] + c = self._box[2] + + def Partitions_inside_lambda(la): + """ + Iterate over all partitions contained in la with the same number + of parts including 0s. + """ + from sage.combinat.partition import Partitions + for k in range(sum(la), -1, -1): + for mu in Partitions(k, outer=la): + yield mu + [0]*(len(la)-len(mu)) + + def Partitions_inside_lambda_with_smallest_at_least_k(la, k): + """ + Iterate over all partitions contained in la with the smallest + entry at least k. + """ + for mu in Partitions_inside_lambda([val - k for val in la]): + yield [mu[i] + k for i in range(len(la))] + + def possible_middle_row_for_b_odd(a, c): + """ + Iterate over all possible middle row for SCPP inside box(a,b,c) + when b is odd. + """ + if a * c % 2 == 1: + yield + return + for mu in Partitions_inside_lambda([c // 2 for i in range(a // 2)]): + nu = [c - mu[len(mu)-1-i] for i in range(len(mu))] + if not a % 2: + la = nu + mu + else: + la = nu + [c // 2] + mu + yield la + + def possible_middle_row_for_b_even(a, c): + """ + Iterate over all possible middle ((b/2)+1)st row for SCPP inside + box(a,b,c) when b is even. + """ + for mu in Partitions_inside_lambda([c // 2 for i in range((a+1) // 2)]): + if not mu: + yield [] + continue + nu = [c - mu[len(mu)-1-i] for i in range(a // 2)] + for tau in Partitions_inside_lambda_with_smallest_at_least_k(nu, mu[0]): + la = tau + mu + yield la + + def PPs_with_first_row_la_and_with_k_rows(la, k): + "Iterate over PPs with first row la and with k rows in total." + if k == 0: + yield [] + return + if k == 1: + yield [la] + return + for mu in Partitions_inside_lambda(la): + for PP in PPs_with_first_row_la_and_with_k_rows(mu, k-1): + yield [la] + PP + + def complement(PP, c): + "Return the complement of PP with respect to height c" + b = len(PP) + if not b: + return [] + a = len(PP[0]) + return [[c - PP[b-1-i][a-1-j] for j in range(a)] for i in range(b)] + + if b % 2 == 1: + # la is the middle row of SCPP + for la in possible_middle_row_for_b_odd(a, c): + for PP in PPs_with_first_row_la_and_with_k_rows(la, (b+1) // 2): + PP_below = PP[1:] + PP_above = complement(PP_below, c) + yield self.element_class(self, PP_above + [la] + PP_below) + else: + # la is the middle ((a/2)+1)st row of SCPP + for la in possible_middle_row_for_b_even(a, c): + for PP in PPs_with_first_row_la_and_with_k_rows(la, b // 2): + PP_below = PP + PP_above = complement(PP_below, c) + yield self.element_class(self, PP_above + PP_below) + + def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of self complementary plane partitions inside a + `2a \times 2b \times 2c` box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{r}\prod_{j=1}^{b} + \frac{i + j + c - 1}{i + j - 1}\right)^2. + + The number of self complementary plane partitions inside an + `(2a+1) \times 2b \times 2c` box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{a} \prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) + \left(\prod_{i=1}^{a+1} \prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right). + + The number of self complementary plane partitions inside an + `(2a+1) \times (2b+1) \times 2c` box is equal to + + .. MATH:: + + \left(\prod_{i=1}^{a+1} \prod_{j=1}^{b} \frac{i+j+c-1}{i+j-1} \right) + \left(\prod_{i=1}^{a} \prod_{j=1}^{b+1} \frac{i+j+c-1}{i+j-1} \right). + + EXAMPLES:: + + sage: P = PlanePartitions([4,4,4], symmetry='SCPP') + sage: P.cardinality() + 400 + + sage: P = PlanePartitions([5,4,4], symmetry='SCPP') + sage: P.cardinality() + 1000 + sage: P = PlanePartitions([4,5,4], symmetry='SCPP') + sage: P.cardinality() + 1000 + sage: P = PlanePartitions([4,4,5], symmetry='SCPP') + sage: P.cardinality() + 1000 + + sage: P = PlanePartitions([5,5,4], symmetry='SCPP') + sage: P.cardinality() + 2500 + sage: P = PlanePartitions([5,4,5], symmetry='SCPP') + sage: P.cardinality() + 2500 + sage: P = PlanePartitions([4,5,5], symmetry='SCPP') + sage: P.cardinality() + 2500 + """ + r = self._box[0] + s = self._box[1] + t = self._box[2] + if r % 2 == 0: + R = r // 2 + if s % 2 == 0: + S = s // 2 + if t % 2 == 0: + T = t // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1))) + else: + T = (t-1) // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+2))) + else: + S = (s-1) // 2 + if t % 2 == 0: + T = t // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+1) for j in range(1, S+2) for k in range(1, T+1))) + else: + T = (t-1) // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+1) for j in range(1, S+2) for k in range(1, T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+2))) + # r is odd + R = (r-1) // 2 + if s % 2 == 0: + S = s // 2 + if t % 2 == 0: + T = t // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+2) for j in range(1, S+1) for k in range(1, T+1))) + else: + T = (t-1) // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+2) for j in range(1, S+1) for k in range(1, T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+2))) + # r and s are both odd + S = (s-1) // 2 + if t % 2 == 0: + T = t // 2 + return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+2) for j in range(1, S+1) for k in range(1, T+1)) + * prod(Integer(i+j+k-1) / Integer(i+j+k-2) + for i in range(1, R+1) for j in range(1, S+2) for k in range(1, T+1))) + + # Should never reach here as r, s, t are all odd, which the constructor should reject + return Integer(0) + + +# Class 6 +# Transpose-complement Plane Partitions +class PlanePartitions_TCPP(PlanePartitions): + r""" + Plane partitions that fit inside a box of a specified size that are + transpose-complement. + """ + def __init__(self, box_size): + """ + Initialize ``self``. + + TESTS:: + + sage: PP = PlanePartitions([3,3,2], symmetry='TCPP') + sage: TestSuite(PP).run() + + sage: PlanePartitions([3,3,3], symmetry='TCPP') + Traceback (most recent call last): + ... + ValueError: z dimension (3) must be even + + sage: PlanePartitions([4,3,2], symmetry='TCPP') + Traceback (most recent call last): + ... + ValueError: x and y dimensions (4 and 3) must be equal + """ + if box_size[2] % 2 == 1: + raise ValueError("z dimension ({}) must be even".format(box_size[2])) + if box_size[0] != box_size[1]: + raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) + super().__init__(box_size, "TCPP", category=FiniteEnumeratedSets()) + + def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([3,3,2], symmetry='TCPP') + Transpose complement plane partitions inside a 3 x 3 x 2 box + """ + return "Transpose complement plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __iter__(self) -> Iterator: + r""" + Iterate over all transpose complement plane partitions. + + EXAMPLES:: + + sage: list(PlanePartitions([3,3,2], symmetry='TCPP')) + [Plane partition [[2, 2, 1], [2, 1], [1]], + Plane partition [[2, 1, 1], [2, 1, 1], [1]], + Plane partition [[2, 2, 1], [1, 1], [1, 1]], + Plane partition [[2, 1, 1], [1, 1, 1], [1, 1]], + Plane partition [[1, 1, 1], [1, 1, 1], [1, 1, 1]]] + """ + for p in PlanePartitions(self._box): + if p.is_TCPP(): + yield self.element_class(self, p) + + def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of transpose complement plane partitions inside an + `a \times a \times 2b` box is equal to + + .. MATH:: + + \binom{b+1-1}{a-1} \prod_{1\leq i,j \leq a-2} + \frac{i + j + 2b - 1}{i + j - 1}. + + EXAMPLES:: + + sage: P = PlanePartitions([3,3,2], symmetry='TCPP') + sage: P.cardinality() + 5 + """ + a = self._box[0] + c = self._box[2] + return Integer(binomial(c // 2 + a - 1, a - 1) + * prod(c + i + j + 1 + for j in range(1, a - 1) for i in range(1, 1 + j)) + // prod(i + j + 1 + for j in range(1, a - 1) for i in range(1, 1 + j))) + + +# Class 7 +# Symmetric Self-complementary Plane Partitions +class PlanePartitions_SSCPP(PlanePartitions): + r""" + Plane partitions that fit inside a box of a specified size that are + symmetric self-complementary. + """ + def __init__(self, box_size): + """ + Initialize ``self``. + + TESTS:: + + sage: PP = PlanePartitions([2, 2, 4], symmetry='SSCPP') + sage: TestSuite(PP).run() + + sage: PP = PlanePartitions([4, 4, 2], symmetry='SSCPP') + sage: TestSuite(PP).run() + + sage: PlanePartitions([4, 2, 2], symmetry='SSCPP') + Traceback (most recent call last): + ... + ValueError: x and y dimensions (4 and 2) must be equal + + sage: PlanePartitions([4, 4, 3], symmetry='SSCPP') + Traceback (most recent call last): + ... + ValueError: z dimension (3) must be even + """ + if box_size[0] != box_size[1]: + raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) + if (box_size[2] % 2 == 1): + raise ValueError("z dimension ({}) must be even".format(box_size[2])) + super().__init__(box_size, "SSCPP", category=FiniteEnumeratedSets()) + + def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([4, 4, 2], symmetry='SSCPP') + Symmetric self-complementary plane partitions inside a 4 x 4 x 2 box + """ + return "Symmetric self-complementary plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __iter__(self) -> Iterator: + """ + Iterate over all symmetric self-complementary plane partitions. + + EXAMPLES:: + + sage: list(PlanePartitions([4,4,2], symmetry='SSCPP')) + [Plane partition [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], + Plane partition [[2, 2, 2, 1], [2, 1, 1], [2, 1, 1], [1]], + Plane partition [[2, 2, 1, 1], [2, 2, 1, 1], [1, 1], [1, 1]], + Plane partition [[2, 2, 2, 1], [2, 2, 1], [2, 1], [1]], + Plane partition [[2, 2, 1, 1], [2, 1, 1, 1], [1, 1, 1], [1, 1]], + Plane partition [[2, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() + ....: for a, b in cartesian_product([range(5), range(0, 5, 2)]) + ....: if (PP := PlanePartitions([a, a, b], symmetry='SSCPP'))) + True + """ + # any SSCPP is a SPP + for p in PlanePartitions(self._box, symmetry='SPP'): + if p.is_SSCPP(): + yield self.element_class(self, p) + + def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of symmetric self-complementary plane partitions inside a + `2a \times 2a \times 2b` box is equal to + + .. MATH:: + + \prod_{i=1}^a \prod_{j=1}^a \frac{i + j + b - 1}{i + j - 1}. + + The number of symmetric self-complementary plane partitions inside a + `(2a+1) \times (2a+1) \times 2b` box is equal to + + .. MATH:: + + \prod_{i=1}^a \prod_{j=1}^{a+1} \frac{i + j + b - 1}{i + j - 1}. + + EXAMPLES:: + + sage: P = PlanePartitions([4,4,2], symmetry='SSCPP') + sage: P.cardinality() + 6 + sage: Q = PlanePartitions([3,3,2], symmetry='SSCPP') + sage: Q.cardinality() + 3 + """ + a = self._box[0] + c = self._box[2] + num = prod(i + j + k - 1 + for i in range(1, 1 + a // 2) + for j in range(1, 1 + (a + 1) // 2) + for k in range(1, 1 + c // 2)) + den = prod(i + j + k - 2 + for i in range(1, 1 + a // 2) + for j in range(1, 1 + (a + 1) // 2) + for k in range(1, 1 + c // 2)) + return Integer(num // den) + + +# Class 8 +# Cyclically Symmetric Transpose-complement Partitions +class PlanePartitions_CSTCPP(PlanePartitions): + r""" + Plane partitions that fit inside a box of a specified size that are + cyclically symmetric and transpose-complement. + """ + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([2,2,2], symmetry='CSTCPP') + sage: TestSuite(PP).run() + + sage: PlanePartitions([4,3,2], symmetry='CSTCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (4,3,2) must all be equal + + sage: PlanePartitions([3,3,3], symmetry='CSTCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (3,3,3) must all be even + """ + if box_size[0] != box_size[1] or box_size[1] != box_size[2]: + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(*box_size)) + if box_size[0] % 2 == 1: + raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(*box_size)) + super().__init__(box_size, "CSTPP", category=FiniteEnumeratedSets()) + + def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([4,4,4], symmetry='CSTCPP') + Cyclically symmetric transpose complement plane partitions inside a 4 x 4 x 4 box + """ + return "Cyclically symmetric transpose complement plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __iter__(self) -> Iterator: + """ + Iterate over all cyclically symmetry transpose complement plane partitions. + + EXAMPLES:: + + sage: list(PlanePartitions([2,2,2], symmetry='CSTCPP')) + [Plane partition [[2, 1], [1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() + ....: for n in range(0, 5, 2) + ....: if (PP := PlanePartitions([n]*3, symmetry='CSTCPP'))) + True + """ + # any CSTCPP is a TSPP, a SSCPP and a CSSCPP + for p in PlanePartitions(self._box, symmetry='TSPP'): + if p.is_CSTCPP(): + yield self.element_class(self, p) + + def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of cyclically symmetric transpose complement plane partitions + inside a `2a \times 2a \times 2a` box is equal to + + .. MATH:: + + \prod_{i=0}^{a-1} \frac{(3i+1)(6i)!(2i)!}{(4i+1)!(4i)!}. + + EXAMPLES:: + + sage: P = PlanePartitions([6,6,6], symmetry='CSTCPP') + sage: P.cardinality() + 11 + """ + a = self._box[0] // 2 + num = prod((3*i + 1) * factorial(6*i) * factorial(2*i) for i in range(a)) + den = prod((factorial(4*i + 1) * factorial(4*i)) for i in range(a)) + return Integer(num // den) + + +# Class 9 +# Cyclically Symmetric Self-complementary Plane Partitions +class PlanePartitions_CSSCPP(PlanePartitions): + r""" + Plane partitions that fit inside a box of a specified size that are + cyclically symmetric self-complementary. + """ + def __init__(self, box_size): + r""" + Initialize ``self``. + + TESTS:: + + sage: PP = PlanePartitions([2,2,2], symmetry='CSSCPP') + sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='CSSCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (4,3,2) must all be equal + sage: PlanePartitions([3,3,3], symmetry='CSSCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (3,3,3) must all be even + """ + if box_size[0] != box_size[1] or box_size[1] != box_size[2]: + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(*box_size)) + if box_size[0] % 2 == 1: + raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(*box_size)) + super().__init__(box_size, "CSSCPP", category=FiniteEnumeratedSets()) + + def _repr_(self) -> str: + """ + EXAMPLES:: + + sage: PlanePartitions([4,4,4], symmetry='CSSCPP') + Cyclically symmetric self-complementary plane partitions inside a 4 x 4 x 4 box + """ + return "Cyclically symmetric self-complementary plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def __iter__(self) -> Iterator: + """ + Iterate over all cyclically symmetric self-complementary plane partitions. + + EXAMPLES:: + + sage: list(PlanePartitions([2,2,2], symmetry='CSSCPP')) + [Plane partition [[2, 1], [1]]] + """ + # any CSSCPP is a SCPP and an CSPP, there are much fewer CSPP + for p in PlanePartitions(self._box, symmetry='CSPP'): + if p.is_CSSCPP(): + yield self.element_class(self, p) + + def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of cyclically symmetric self-complementary plane partitions + inside a `2a \times 2a \times 2a` box is equal to + + .. MATH:: + + \left( \prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!} \right)^2. + + EXAMPLES:: + + sage: P = PlanePartitions([6,6,6], symmetry='CSSCPP') + sage: P.cardinality() + 49 + """ + a = self._box[0] // 2 + num = prod(factorial(3*i + 1)**2 for i in range(a)) + den = prod(factorial(a + i)**2 for i in range(a)) + return Integer(num // den) + + +# Class 10 +# Totally Symmetric Self-complementary Plane Partitions +class PlanePartitions_TSSCPP(PlanePartitions): + r""" + Plane partitions that fit inside a box of a specified size that are + totally symmetric self-complementary. + """ + def __init__(self, box_size): + """ + TESTS:: + + sage: PP = PlanePartitions([4,4,4], symmetry='TSSCPP') + sage: TestSuite(PP).run() + sage: PlanePartitions([4,3,2], symmetry='TSSCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (4,3,2) must all be equal + sage: PlanePartitions([3,3,3], symmetry='TSSCPP') + Traceback (most recent call last): + ... + ValueError: x, y, and z dimensions (3,3,3) must all be even + """ + if box_size[0] != box_size[1] or box_size[1] != box_size[2]: + raise ValueError("x, y, and z dimensions ({},{},{}) must all be equal".format(*box_size)) + if box_size[0] % 2 == 1: + raise ValueError("x, y, and z dimensions ({},{},{}) must all be even".format(*box_size)) + super().__init__(box_size, "TSSCPP", category=FiniteEnumeratedSets()) + + def _repr_(self) -> str: + r""" + EXAMPLES:: + + sage: PlanePartitions([4,4,4], symmetry='TSSCPP') + Totally symmetric self-complementary plane partitions inside a 4 x 4 x 4 box + """ + return "Totally symmetric self-complementary plane partitions inside a {} x {} x {} box".format( + self._box[0], self._box[1], self._box[2]) + + def to_poset(self): + r""" + Return a poset whose order ideals are in bijection with + totally symmetric self-complementary plane partitions. + + EXAMPLES:: + + sage: PP = PlanePartitions([6,6,6], symmetry='TSSCPP') + sage: PP.to_poset() + Finite poset containing 4 elements + sage: PP.to_poset().order_ideals_lattice().cardinality() == PP.cardinality() + True + """ + from sage.combinat.posets.posets import Poset + a = self._box[0] + b = self._box[1] + c = self._box[2] + if a != b or b != c or a != c: + return Poset() + + def comp(x, y): + return all(xx <= yy for xx, yy in zip(x, y)) + + A = a // 2 + pl = [(x, y, z) for x in range(A-1) for y in range(x, A-1) + for z in range(A-1) if z <= A - 2 - y] + return Poset((pl, comp)) + + def from_antichain(self, acl) -> PP: + r""" + Return the totally symmetric self-complementary plane partition + corresponding to an antichain in the poset given in :meth:`to_poset()`. + + EXAMPLES:: + + sage: PP = PlanePartitions([6,6,6], symmetry='TSSCPP') + sage: A = [(0, 0, 1), (1, 1, 0)] + sage: PP.from_antichain(A) + Plane partition [[6, 6, 6, 5, 5, 3], [6, 5, 5, 4, 3, 1], [6, 5, 4, 3, 2, 1], [5, 4, 3, 2, 1], [5, 3, 2, 1, 1], [3, 1, 1]] + """ + # ac format ex: [x,y,z] + a = self._box[0] + b = self._box[1] + c = self._box[2] + n = a + N = n // 2 + pp_matrix = [[0] * (c) for i in range(b)] + # creates a matrix for the plane parition populated by 0s + # EX: [[0,0,0], [0,0,0], [0,0,0]] + width = N - 1 + height = N - 1 + + # generate inner triangle + # FIXME: Make this iterator more efficient + for i in range(width): + for j in range(i, height): + for ac in acl: + if ac[0] == i and ac[1] == j: + zVal = ac[2] + matrixVal = pp_matrix[j+N][i+N] + if zVal + 1 > matrixVal: + pp_matrix[j+N][i+N] = zVal + 1 + + # fill back + for i in range(width): + i = width - (i + 1) + i = i + N + for j in range(height): + j = height - (j + 1) + j = j + N + if pp_matrix[i][j] == 0: + if i >= j: + iValue = 0 + jValue = 0 + if i < n: + iValue = pp_matrix[i+1][j] + if j < n: + jValue = pp_matrix[i][j+1] + pp_matrix[i][j] = max(iValue, jValue) + + # fill half of triangle symmetrically + for i in range(width): + i += N + for j in range(height): + j += N + if i >= j: + pp_matrix[j][i] = pp_matrix[i][j] + + # upper left box + for i in range(N): + for j in range(N): + pp_matrix[i][j] = n - pp_matrix[n-(i+1)][n-(j+1)] + + # fill in lower left cube with values n/2 + for i in range(N): + for j in range(N): + x = i + y = j + if pp_matrix[x][y+N] == 0: + pp_matrix[x][y+N] = N + if pp_matrix[x+N][y] == 0: + pp_matrix[x+N][y] = N + + # add and subtract values from lower left cube to be rotation of lower right cube + for i in range(N): + for j in range(N): + x = i + N + y = j + N + if pp_matrix[x][y] > 0: + z = pp_matrix[x][y] + for cVal in range(z): + # build onto lower left cube + pp_matrix[x][0+cVal] += 1 + # carve out of lower left cube + pp_matrix[n-(1+cVal)][N-(j+1)] -= 1 + + # fill in upper right cube symmetrically with lower left + for i in range(N): + for j in range(N): + pp_matrix[j][i+N] = pp_matrix[i+N][j] + return self.element_class(self, pp_matrix) + + def from_order_ideal(self, I) -> PP: + r""" + Return the totally symmetric self-complementary plane partition + corresponding to an order ideal in the poset given in :meth:`to_poset`. + + EXAMPLES:: + + sage: PP = PlanePartitions([6,6,6], symmetry='TSSCPP') + sage: I = [(0, 0, 0), (0, 1, 0), (1, 1, 0)] + sage: PP.from_order_ideal(I) + Plane partition [[6, 6, 6, 5, 5, 3], [6, 5, 5, 3, 3, 1], [6, 5, 5, 3, 3, 1], [5, 3, 3, 1, 1], [5, 3, 3, 1, 1], [3, 1, 1]] + """ + return self.from_antichain(self.to_poset().order_ideal_generators(I)) + + def __iter__(self) -> Iterator: + """ + Iterate over all totally symmetric self-complementary plane partitions. + + EXAMPLES:: + + sage: list(PlanePartitions([4,4,4], symmetry='TSSCPP')) + [Plane partition [[4, 4, 2, 2], [4, 4, 2, 2], [2, 2], [2, 2]], + Plane partition [[4, 4, 3, 2], [4, 3, 2, 1], [3, 2, 1], [2, 1]]] + + TESTS:: + + sage: all(len(set(PP)) == PP.cardinality() for n in range(0,11,2) if (PP := PlanePartitions([n]*3, symmetry='TSSCPP'))) + True + """ + for acl in self.to_poset().antichains_iterator(): + yield self.from_antichain(acl) + + def cardinality(self) -> Integer: + r""" + Return the cardinality of ``self``. + + The number of totally symmetric self-complementary plane partitions + inside a `2a \times 2a \times 2a` box is equal to + + .. MATH:: + + \prod_{i=0}^{a-1} \frac{(3i+1)!}{(a+i)!}. + + EXAMPLES:: + + sage: P = PlanePartitions([6,6,6], symmetry='TSSCPP') + sage: P.cardinality() + 7 + """ + a = self._box[0] // 2 + num = prod(factorial(3*i + 1) for i in range(a)) + den = prod(factorial(a + i) for i in range(a)) + return Integer(num // den) diff --git a/src/sage/combinat/posets/d_complete.py b/src/sage/combinat/posets/d_complete.py index 210317f2b44..6bfe6eca61e 100644 --- a/src/sage/combinat/posets/d_complete.py +++ b/src/sage/combinat/posets/d_complete.py @@ -59,8 +59,8 @@ def _hooks(self): sage: P._hooks {0: 1, 1: 2, 2: 2, 3: 3} sage: from sage.combinat.posets.poset_examples import Posets - sage: P = DCompletePoset(Posets.YoungDiagramPoset(Partition([3,2,1]))._hasse_diagram.reverse()) - sage: P._hooks + sage: P = DCompletePoset(Posets.YoungDiagramPoset(Partition([3,2,1]))._hasse_diagram.reverse()) # optional - sage.combinat + sage: P._hooks # optional - sage.combinat {0: 5, 1: 3, 2: 1, 3: 3, 4: 1, 5: 1} """ hooks = {} @@ -89,18 +89,20 @@ def _hooks(self): # Check if any of these make a longer double tailed diamond found_diamond = False - for (mn, mx) in [(i, j) for i in potential_min for j in potential_max]: - if len(H.neighbors_in(mx)) != 1: + for mx in potential_max: + if H.in_degree(mx) != 1: continue - if len(H.all_paths(mn, mx)) == 2: - # Success - min_elmt = mn - max_elmt = mx - - min_diamond[mx] = mn - max_diamond[mn] = mx - diamond_index[mx] = index - found_diamond = True + for mn in potential_min: + if len(H.all_paths(mn, mx)) == 2: + # Success + min_elmt = mn + max_elmt = mx + min_diamond[mx] = mn + max_diamond[mn] = mx + diamond_index[mx] = index + found_diamond = True + break + if found_diamond: break if not found_diamond: break @@ -150,8 +152,9 @@ def get_hooks(self): sage: P.get_hooks() {0: 1, 1: 2, 2: 2, 3: 3} sage: from sage.combinat.posets.poset_examples import Posets - sage: P = DCompletePoset(Posets.YoungDiagramPoset(Partition([3,2,1]))._hasse_diagram.reverse()) - sage: P.get_hooks() + sage: YDP321 = Posets.YoungDiagramPoset(Partition([3,2,1])) # optional - sage.combinat + sage: P = DCompletePoset(YDP321._hasse_diagram.reverse()) # optional - sage.combinat + sage: P.get_hooks() # optional - sage.combinat {0: 5, 1: 3, 2: 1, 3: 3, 4: 1, 5: 1} """ return dict(self._hooks) @@ -166,8 +169,9 @@ def hook_product(self): sage: P = DCompletePoset(DiGraph({0: [1, 2], 1: [3], 2: [3], 3: []})) sage: P.hook_product() 12 - sage: P = DCompletePoset(posets.YoungDiagramPoset(Partition([3,2,1]), dual=True)) - sage: P.hook_product() + sage: P = DCompletePoset(posets.YoungDiagramPoset(Partition([3,2,1]), # optional - sage.combinat + ....: dual=True)) + sage: P.hook_product() # optional - sage.combinat 45 """ if not self._hasse_diagram: diff --git a/src/sage/combinat/posets/elements.py b/src/sage/combinat/posets/elements.py index 00b0707d8e1..4cfb0b28ae0 100644 --- a/src/sage/combinat/posets/elements.py +++ b/src/sage/combinat/posets/elements.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules r""" Elements of posets, lattices, semilattices, etc. """ @@ -78,9 +79,9 @@ def _latex_(self): EXAMPLES:: - sage: m = matrix(2,[1,2,3,4]) + sage: m = matrix(2, [1,2,3,4]) sage: m.set_immutable() - sage: P = Poset(([m],[]), facade = False) + sage: P = Poset(([m],[]), facade=False) sage: [e] = P sage: type(e) <class 'sage.combinat.posets.posets.FinitePoset_with_category.element_class'> @@ -243,7 +244,7 @@ def __mul__(self, other): EXAMPLES:: - sage: D = posets.DiamondPoset(5,facade=False) + sage: D = posets.DiamondPoset(5, facade=False) sage: D(1) * D(2) 0 sage: D(1) * D(1) diff --git a/src/sage/combinat/posets/hasse_cython.pyx b/src/sage/combinat/posets/hasse_cython.pyx index 0e4d13ff033..8f7a869fc17 100644 --- a/src/sage/combinat/posets/hasse_cython.pyx +++ b/src/sage/combinat/posets/hasse_cython.pyx @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# cython: binding=True r""" Some fast computations for finite posets """ @@ -11,146 +11,14 @@ Some fast computations for finite posets # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from cysignals.signals cimport sig_check -from cysignals.memory cimport sig_malloc, sig_free - -from sage.libs.flint.fmpz cimport * -from sage.libs.flint.fmpz_mat cimport * - -from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense - -from sage.rings.integer_ring import ZZ -from sage.matrix.matrix_space import MatrixSpace from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.misc.lazy_import import LazyImport from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest - -cpdef Matrix_integer_dense moebius_matrix_fast(list positions): - """ - Compute the Mรถbius matrix of a poset by a specific triangular inversion. - - INPUT: - - a list of sets of integers describing the poset, as given by the - lazy attribute ``_leq_storage`` of Hasse diagrams. - - OUTPUT: - - a dense matrix - - EXAMPLES:: - - sage: from sage.combinat.posets.hasse_cython import moebius_matrix_fast - sage: D = [{0,1},{1}] - sage: moebius_matrix_fast(D) - [ 1 -1] - [ 0 1] - sage: P = posets.TamariLattice(5) - sage: H = P._hasse_diagram - sage: D = H._leq_storage - sage: moebius_matrix_fast(D) - 42 x 42 dense matrix over Integer Ring (...) - """ - cdef Matrix_integer_dense A - cdef Py_ssize_t n = len(positions) - cdef Py_ssize_t i - cdef int j, k - A = Matrix_integer_dense.__new__(Matrix_integer_dense, - MatrixSpace(ZZ, n, n), None, None, None) - fmpz_mat_one(A._matrix) - cdef Py_ssize_t *pos_lens = <Py_ssize_t*> sig_malloc(n*sizeof(Py_ssize_t)) - cdef int **pos_array = <int**> sig_malloc(n*sizeof(int*)) - cdef Py_ssize_t jind, kind - for i in range(n): - pos_lens[i] = len(positions[i]) - pos_array[i] = <int*> sig_malloc(pos_lens[i]*sizeof(int)) - for jind,j in enumerate(positions[i]): - pos_array[i][jind] = j - - for i in range(n - 1, -1, -1): - sig_check() - for jind in range(pos_lens[i]): - j = pos_array[i][jind] - if j != i: - for kind in range(pos_lens[j]): - k = pos_array[j][kind] - fmpz_sub(fmpz_mat_entry(A._matrix, i, k), - fmpz_mat_entry(A._matrix, i, k), - fmpz_mat_entry(A._matrix, j, k)) - for i in range(n): - sig_free(pos_array[i]) - sig_free(pos_array) - sig_free(pos_lens) - return A - - -cpdef Matrix_integer_dense coxeter_matrix_fast(list positions): - """ - Compute the Coxeter matrix of a poset by a specific algorithm. - - INPUT: - - a list of sets of integers describing the poset, as given by the - lazy attribute ``_leq_storage`` of Hasse diagrams. - - OUTPUT: - - a dense matrix - - EXAMPLES:: - - sage: from sage.combinat.posets.hasse_cython import coxeter_matrix_fast - sage: D = [{0,1},{1}] - sage: coxeter_matrix_fast(D) - [ 0 -1] - [ 1 -1] - sage: P = posets.TamariLattice(5) - sage: H = P._hasse_diagram - sage: D = H._leq_storage - sage: coxeter_matrix_fast(D) - 42 x 42 dense matrix over Integer Ring (...) - """ - cdef Matrix_integer_dense A - cdef Py_ssize_t n = len(positions) - cdef Py_ssize_t i - cdef int j, k - A = Matrix_integer_dense.__new__(Matrix_integer_dense, - MatrixSpace(ZZ, n, n), None, None, None) - fmpz_mat_one(A._matrix) - cdef Py_ssize_t *pos_lens = <Py_ssize_t*> sig_malloc(n*sizeof(Py_ssize_t)) - cdef int **pos_array = <int**> sig_malloc(n*sizeof(int*)) - cdef Py_ssize_t jind, kind - for i in range(n): - pos_lens[i] = len(positions[i]) - pos_array[i] = <int*> sig_malloc(pos_lens[i]*sizeof(int)) - for jind,j in enumerate(positions[i]): - pos_array[i][jind] = j - - for i in range(n - 1, -1, -1): - sig_check() - for jind in range(pos_lens[i]): - j = pos_array[i][jind] - if j != i: - for kind in range(pos_lens[j]): - k = pos_array[j][kind] - fmpz_sub(fmpz_mat_entry(A._matrix, k, i), - fmpz_mat_entry(A._matrix, k, i), - fmpz_mat_entry(A._matrix, k, j)) - for i in range(n): - sig_check() - for jind in range(pos_lens[i]): - j = pos_array[i][jind] - if j != i: - for k in range(n): - fmpz_add(fmpz_mat_entry(A._matrix, i, k), - fmpz_mat_entry(A._matrix, i, k), - fmpz_mat_entry(A._matrix, j, k)) - for i in range(n): - sig_free(pos_array[i]) - sig_free(pos_array) - sig_free(pos_lens) - fmpz_mat_scalar_mul_si(A._matrix, A._matrix, -1) - return A +coxeter_matrix_fast = LazyImport('sage.combinat.posets.hasse_cython_flint', 'coxeter_matrix_fast', + deprecation=35741) +moebius_matrix_fast = LazyImport('sage.combinat.posets.hasse_cython_flint', 'moebius_matrix_fast', + deprecation=35741) class IncreasingChains(RecursivelyEnumeratedSet_forest): diff --git a/src/sage/combinat/posets/hasse_cython_flint.pyx b/src/sage/combinat/posets/hasse_cython_flint.pyx new file mode 100644 index 00000000000..0b33eed0b3f --- /dev/null +++ b/src/sage/combinat/posets/hasse_cython_flint.pyx @@ -0,0 +1,149 @@ +# cython: binding=True +r""" +Some fast computations for finite posets using FLINT matrices +""" +# **************************************************************************** +# Copyright (C) 2020 Frรฉdรฉric Chapoton <chapoton@unistra.fr> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** +from cysignals.signals cimport sig_check +from cysignals.memory cimport sig_malloc, sig_free + +from sage.libs.flint.fmpz cimport * +from sage.libs.flint.fmpz_mat cimport * +from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense +from sage.matrix.matrix_space import MatrixSpace +from sage.rings.integer_ring import ZZ + + +cpdef Matrix_integer_dense moebius_matrix_fast(list positions): + """ + Compute the Mรถbius matrix of a poset by a specific triangular inversion. + + INPUT: + + a list of sets of integers describing the poset, as given by the + lazy attribute ``_leq_storage`` of Hasse diagrams. + + OUTPUT: + + a dense matrix + + EXAMPLES:: + + sage: from sage.combinat.posets.hasse_cython_flint import moebius_matrix_fast + sage: D = [{0,1},{1}] + sage: moebius_matrix_fast(D) + [ 1 -1] + [ 0 1] + sage: P = posets.TamariLattice(5) + sage: H = P._hasse_diagram + sage: D = H._leq_storage + sage: moebius_matrix_fast(D) + 42 x 42 dense matrix over Integer Ring (...) + """ + cdef Matrix_integer_dense A + cdef Py_ssize_t n = len(positions) + cdef Py_ssize_t i + cdef int j, k + A = Matrix_integer_dense.__new__(Matrix_integer_dense, + MatrixSpace(ZZ, n, n), None, None, None) + fmpz_mat_one(A._matrix) + cdef Py_ssize_t *pos_lens = <Py_ssize_t*> sig_malloc(n*sizeof(Py_ssize_t)) + cdef int **pos_array = <int**> sig_malloc(n*sizeof(int*)) + cdef Py_ssize_t jind, kind + for i in range(n): + pos_lens[i] = len(positions[i]) + pos_array[i] = <int*> sig_malloc(pos_lens[i]*sizeof(int)) + for jind,j in enumerate(positions[i]): + pos_array[i][jind] = j + + for i in range(n - 1, -1, -1): + sig_check() + for jind in range(pos_lens[i]): + j = pos_array[i][jind] + if j != i: + for kind in range(pos_lens[j]): + k = pos_array[j][kind] + fmpz_sub(fmpz_mat_entry(A._matrix, i, k), + fmpz_mat_entry(A._matrix, i, k), + fmpz_mat_entry(A._matrix, j, k)) + for i in range(n): + sig_free(pos_array[i]) + sig_free(pos_array) + sig_free(pos_lens) + return A + + +cpdef Matrix_integer_dense coxeter_matrix_fast(list positions): + """ + Compute the Coxeter matrix of a poset by a specific algorithm. + + INPUT: + + a list of sets of integers describing the poset, as given by the + lazy attribute ``_leq_storage`` of Hasse diagrams. + + OUTPUT: + + a dense matrix + + EXAMPLES:: + + sage: from sage.combinat.posets.hasse_cython_flint import coxeter_matrix_fast + sage: D = [{0,1},{1}] + sage: coxeter_matrix_fast(D) + [ 0 -1] + [ 1 -1] + sage: P = posets.TamariLattice(5) + sage: H = P._hasse_diagram + sage: D = H._leq_storage + sage: coxeter_matrix_fast(D) + 42 x 42 dense matrix over Integer Ring (...) + """ + cdef Matrix_integer_dense A + cdef Py_ssize_t n = len(positions) + cdef Py_ssize_t i + cdef int j, k + A = Matrix_integer_dense.__new__(Matrix_integer_dense, + MatrixSpace(ZZ, n, n), None, None, None) + fmpz_mat_one(A._matrix) + cdef Py_ssize_t *pos_lens = <Py_ssize_t*> sig_malloc(n*sizeof(Py_ssize_t)) + cdef int **pos_array = <int**> sig_malloc(n*sizeof(int*)) + cdef Py_ssize_t jind, kind + for i in range(n): + pos_lens[i] = len(positions[i]) + pos_array[i] = <int*> sig_malloc(pos_lens[i]*sizeof(int)) + for jind,j in enumerate(positions[i]): + pos_array[i][jind] = j + + for i in range(n - 1, -1, -1): + sig_check() + for jind in range(pos_lens[i]): + j = pos_array[i][jind] + if j != i: + for kind in range(pos_lens[j]): + k = pos_array[j][kind] + fmpz_sub(fmpz_mat_entry(A._matrix, k, i), + fmpz_mat_entry(A._matrix, k, i), + fmpz_mat_entry(A._matrix, k, j)) + for i in range(n): + sig_check() + for jind in range(pos_lens[i]): + j = pos_array[i][jind] + if j != i: + for k in range(n): + fmpz_add(fmpz_mat_entry(A._matrix, i, k), + fmpz_mat_entry(A._matrix, i, k), + fmpz_mat_entry(A._matrix, j, k)) + for i in range(n): + sig_free(pos_array[i]) + sig_free(pos_array) + sig_free(pos_lens) + fmpz_mat_scalar_mul_si(A._matrix, A._matrix, -1) + return A diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index f59f4fd951f..1c61cee4760 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Hasse diagrams of posets @@ -17,19 +16,21 @@ # **************************************************************************** from __future__ import annotations +from collections import deque + +from sage.arith.misc import binomial +from sage.combinat.posets.hasse_cython import IncreasingChains from sage.graphs.digraph import DiGraph -from sage.matrix.constructor import matrix -from sage.rings.integer_ring import ZZ -from sage.rings.finite_rings.finite_field_constructor import GF -from sage.misc.lazy_attribute import lazy_attribute from sage.misc.cachefunc import cached_method -from sage.arith.all import binomial +from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.lazy_import import lazy_import from sage.misc.rest_index_of_methods import gen_rest_table_index -from sage.combinat.posets.hasse_cython import (moebius_matrix_fast, - coxeter_matrix_fast, - IncreasingChains) +from sage.rings.integer_ring import ZZ -from collections import deque +lazy_import('sage.combinat.posets.hasse_cython_flint', + ['moebius_matrix_fast', 'coxeter_matrix_fast']) +lazy_import('sage.matrix.constructor', 'matrix') +lazy_import('sage.rings.finite_rings.finite_field_constructor', 'GF') class LatticeError(ValueError): @@ -123,10 +124,10 @@ def linear_extensions(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,2],1:[3],2:[3],3:[]}) - sage: list(H.linear_extensions()) + sage: list(H.linear_extensions()) # optional - sage.modules [[0, 1, 2, 3], [0, 2, 1, 3]] """ - from sage.combinat.combinat_cython import linear_extension_iterator + from sage.combinat.posets.linear_extension_iterator import linear_extension_iterator return linear_extension_iterator(self) def greedy_linear_extensions_iterator(self): @@ -419,6 +420,7 @@ def maximal_elements(self): """ return self.sinks() + @cached_method def bottom(self): """ Return the bottom element of the poset, if it exists. @@ -558,21 +560,21 @@ def dual(self): EXAMPLES:: - sage: P = posets.IntegerPartitions(4) - sage: H = P._hasse_diagram; H + sage: P = posets.IntegerPartitions(4) # optional - sage.combinat + sage: H = P._hasse_diagram; H # optional - sage.combinat Hasse diagram of a poset containing 5 elements - sage: H.dual() + sage: H.dual() # optional - sage.combinat Hasse diagram of a poset containing 5 elements TESTS:: - sage: H = posets.IntegerPartitions(4)._hasse_diagram - sage: H.is_isomorphic( H.dual().dual() ) + sage: H = posets.IntegerPartitions(4)._hasse_diagram # optional - sage.combinat + sage: H.is_isomorphic( H.dual().dual() ) # optional - sage.combinat True - sage: H.is_isomorphic( H.dual() ) + sage: H.is_isomorphic( H.dual() ) # optional - sage.combinat False """ - H = self.reverse() + H = self.reverse(immutable=False) H.relabel(perm=list(range(H.num_verts() - 1, -1, -1)), inplace=True) return HasseDiagram(H) @@ -587,16 +589,16 @@ def _precompute_intervals(self): EXAMPLES:: sage: B4 = posets.BooleanLattice(4) - sage: B4.is_isoform() # Slow + sage: B4.is_isoform() # Slow # optional - sage.combinat True sage: B4._hasse_diagram._precompute_intervals() sage: B4 = posets.BooleanLattice(4) - sage: B4.is_isoform() # Faster now + sage: B4.is_isoform() # Faster now # optional - sage.combinat True """ n = self.order() v_up = (frozenset(self.depth_first_search(v)) for v in range(n)) - v_down = [frozenset(self.depth_first_search(v, neighbors=self.neighbors_in)) + v_down = [frozenset(self.depth_first_search(v, neighbors=self.neighbor_in_iterator)) for v in range(n)] self._intervals = [[sorted(up.intersection(down)) for down in v_down] for up in v_up] @@ -888,8 +890,7 @@ def upper_covers_iterator(self, element): sage: list(H.upper_covers_iterator(7)) [] """ - for x in self.neighbor_out_iterator(element): - yield x + yield from self.neighbor_out_iterator(element) def lower_covers_iterator(self, element): r""" @@ -904,8 +905,7 @@ def lower_covers_iterator(self, element): sage: list(H.lower_covers_iterator(4)) [1, 2] """ - for x in self.neighbor_in_iterator(element): - yield x + yield from self.neighbor_in_iterator(element) def cardinality(self): r""" @@ -968,6 +968,64 @@ def moebius_function(self, i, j): # dumb algorithm self._moebius_function_values[(i, j)] = -sum(self.moebius_function(i, k) for k in ci[:-1]) return self._moebius_function_values[(i, j)] + def bottom_moebius_function(self, j): + r""" + Return the value of the Mรถbius function of the poset + on the elements ``zero`` and ``j``, where ``zero`` is + ``self.bottom()``, the unique minimal element of the poset. + + EXAMPLES:: + + sage: P = Poset({0: [1,2]}) + sage: hasse = P._hasse_diagram + sage: hasse.bottom_moebius_function(1) + -1 + sage: hasse.bottom_moebius_function(2) + -1 + sage: P = Poset({0: [1,3], 1:[2], 2:[4], 3:[4]}) + sage: hasse = P._hasse_diagram + sage: for i in range(5): + ....: print(hasse.bottom_moebius_function(i)) + 1 + -1 + 0 + -1 + 1 + + TESTS:: + + sage: P = Poset({0:[2], 1:[2]}) + sage: hasse = P._hasse_diagram + sage: hasse.bottom_moebius_function(1) + Traceback (most recent call last): + ... + ValueError: the poset does not have a bottom element + """ + zero = self.bottom() + if zero is None: + raise ValueError("the poset does not have a bottom element") + # if the value has already been computed, either by self.moebius_function + # or by self.bottom_moebius_function, then just use the cached value. + try: + return self._moebius_function_values[(zero, j)] + # if the dict has not been initialized, do that and try again + except AttributeError: + self._moebius_function_values = {} + return self.bottom_moebius_function(j) + # if mu(zero, j) has not already been computed, we'll get a key error. + except KeyError: + if zero == j: + self._moebius_function_values[(zero, j)] = 1 + # since zero is the minimal element, we can ignore the case that zero > j, + # and move on to computing the interval, which is exactly the order ideal. + else: + # do the depth_first_search over order_ideal, because we don't care + # about sorting the elements of the order ideal. + ci = self._backend.depth_first_search(j, reverse=True) + next(ci) # throw out the first element, which is j + self._moebius_function_values[(zero, j)] = -sum(self.bottom_moebius_function(k) for k in ci) + return self._moebius_function_values[(zero, j)] + def moebius_function_matrix(self, algorithm='cython'): r""" Return the matrix of the Mรถbius function of this poset. @@ -998,7 +1056,7 @@ def moebius_function_matrix(self, algorithm='cython'): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,3,2],1:[4],2:[4,5,6],3:[6],4:[7],5:[7],6:[7],7:[]}) - sage: H.moebius_function_matrix() + sage: H.moebius_function_matrix() # optional - sage.libs.flint sage.modules [ 1 -1 -1 -1 1 0 1 0] [ 0 1 0 0 -1 0 0 0] [ 0 0 1 0 -1 -1 -1 2] @@ -1010,14 +1068,13 @@ def moebius_function_matrix(self, algorithm='cython'): TESTS:: + sage: # needs sage.modules sage.libs.flint sage: H.moebius_function_matrix().is_immutable() True sage: hasattr(H,'_moebius_function_matrix') True - sage: H.moebius_function == H._moebius_function_from_matrix True - sage: H = posets.TamariLattice(3)._hasse_diagram sage: M = H.moebius_function_matrix('matrix'); M [ 1 -1 -1 0 1] @@ -1102,6 +1159,7 @@ def coxeter_transformation(self, algorithm='cython'): EXAMPLES:: + sage: # needs sage.libs.flint sage.modules sage: P = posets.PentagonPoset()._hasse_diagram sage: M = P.coxeter_transformation(); M [ 0 0 0 0 -1] @@ -1115,6 +1173,7 @@ def coxeter_transformation(self, algorithm='cython'): TESTS:: + sage: # needs sage.libs.flint sage.modules sage: P = posets.PentagonPoset()._hasse_diagram sage: M = P.coxeter_transformation() sage: M**8 == 1 @@ -1173,7 +1232,7 @@ def order_ideal(self, elements): [0, 1, 2, 3, 4, 5, 6, 7, 8, 10] """ return sorted(self.depth_first_search(elements, - neighbors=self.neighbors_in)) + neighbors=self.neighbor_in_iterator)) def order_ideal_cardinality(self, elements): r""" @@ -1197,7 +1256,7 @@ def order_ideal_cardinality(self, elements): continue size += 1 seen.add(v) - q.extend(self.neighbors_in(v)) + q.extend(self.neighbor_in_iterator(v)) return ZZ(size) @@ -1252,7 +1311,7 @@ def _leq_matrix_boolean(self): sage: P = Poset([[1,3,2],[4],[4,5,6],[6],[7],[7],[7],[]]) sage: H = P._hasse_diagram - sage: M = H._leq_matrix_boolean; M + sage: M = H._leq_matrix_boolean; M # optional - sage.modules sage.rings.finite_rings [1 1 1 1 1 1 1 1] [0 1 0 1 0 0 0 1] [0 0 1 1 1 0 1 1] @@ -1261,7 +1320,7 @@ def _leq_matrix_boolean(self): [0 0 0 0 0 1 1 1] [0 0 0 0 0 0 1 1] [0 0 0 0 0 0 0 1] - sage: M.base_ring() + sage: M.base_ring() # optional - sage.modules sage.rings.finite_rings Finite Field of size 2 """ n = self.order() @@ -1285,7 +1344,7 @@ def _leq_matrix(self): sage: P = Poset([[1,3,2],[4],[4,5,6],[6],[7],[7],[7],[]]) sage: H = P._hasse_diagram - sage: M = H._leq_matrix; M + sage: M = H._leq_matrix; M # optional - sage.modules [1 1 1 1 1 1 1 1] [0 1 0 1 0 0 0 1] [0 0 1 1 1 0 1 1] @@ -1294,7 +1353,7 @@ def _leq_matrix(self): [0 0 0 0 0 1 1 1] [0 0 0 0 0 0 1 1] [0 0 0 0 0 0 0 1] - sage: M.base_ring() + sage: M.base_ring() # optional - sage.modules Integer Ring """ n = self.order() @@ -1321,7 +1380,7 @@ def lequal_matrix(self, boolean=False): sage: P = Poset([[1,3,2],[4],[4,5,6],[6],[7],[7],[7],[]]) sage: H = P._hasse_diagram - sage: M = H.lequal_matrix(); M + sage: M = H.lequal_matrix(); M # optional - sage.modules [1 1 1 1 1 1 1 1] [0 1 0 1 0 0 0 1] [0 0 1 1 1 0 1 1] @@ -1330,18 +1389,18 @@ def lequal_matrix(self, boolean=False): [0 0 0 0 0 1 1 1] [0 0 0 0 0 0 1 1] [0 0 0 0 0 0 0 1] - sage: M.base_ring() + sage: M.base_ring() # optional - sage.modules Integer Ring sage: P = posets.DiamondPoset(6) sage: H = P._hasse_diagram - sage: M = H.lequal_matrix(boolean=True) - sage: M.base_ring() + sage: M = H.lequal_matrix(boolean=True) # optional - sage.modules sage.rings.finite_rings + sage: M.base_ring() # optional - sage.modules sage.rings.finite_rings Finite Field of size 2 TESTS:: - sage: H.lequal_matrix().is_immutable() + sage: H.lequal_matrix().is_immutable() # optional - sage.modules True """ if boolean: @@ -1363,7 +1422,7 @@ def _alternate_is_lequal(self, i, j): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) - sage: H.lequal_matrix() + sage: H.lequal_matrix() # optional - sage.modules [1 0 1 1 1] [0 1 1 1 1] [0 0 1 1 1] @@ -1449,7 +1508,7 @@ def _meet(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,3,2],1:[4],2:[4,5,6],3:[6],4:[7],5:[7],6:[7],7:[]}) - sage: H._meet + sage: H._meet # optional - sage.modules [0 0 0 0 0 0 0 0] [0 1 0 0 1 0 0 1] [0 0 2 0 2 2 2 2] @@ -1460,14 +1519,14 @@ def _meet(self): [0 1 2 3 4 5 6 7] sage: H = HasseDiagram({0:[2,3],1:[2,3]}) - sage: H._meet + sage: H._meet # optional - sage.modules [ 0 -1 0 0] [-1 1 1 1] [ 0 1 2 -1] [ 0 1 -1 3] sage: H = HasseDiagram({0:[1,2],1:[3,4],2:[3,4]}) - sage: H._meet + sage: H._meet # optional - sage.modules [ 0 0 0 0 0] [ 0 1 0 1 1] [ 0 0 2 2 2] @@ -1477,9 +1536,9 @@ def _meet(self): TESTS:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram - sage: L = LatticePoset({0:[1,2,3],1:[4],2:[4],3:[4]}) - sage: P = L.dual() - sage: P.meet(2,3) + sage: L = LatticePoset({0:[1,2,3],1:[4],2:[4],3:[4]}) # optional - sage.modules + sage: P = L.dual() # optional - sage.modules + sage: P.meet(2,3) # optional - sage.modules 4 """ self._meet_semilattice_failure = () @@ -1529,7 +1588,7 @@ def meet_matrix(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,3,2],1:[4],2:[4,5,6],3:[6],4:[7],5:[7],6:[7],7:[]}) - sage: H.meet_matrix() + sage: H.meet_matrix() # optional - sage.modules [0 0 0 0 0 0 0 0] [0 1 0 0 1 0 0 1] [0 0 2 0 2 2 2 2] @@ -1557,7 +1616,7 @@ def meet_matrix(self): ValueError: not a meet-semilattice: no bottom element sage: H = HasseDiagram({0:[1,2],1:[3,4],2:[3,4]}) - sage: H.meet_matrix() + sage: H.meet_matrix() # optional - sage.modules Traceback (most recent call last): ... LatticeError: no meet for ... @@ -1581,19 +1640,19 @@ def is_meet_semilattice(self) -> bool: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,3,2],1:[4],2:[4,5,6],3:[6],4:[7],5:[7],6:[7],7:[]}) - sage: H.is_meet_semilattice() + sage: H.is_meet_semilattice() # optional - sage.modules True sage: H = HasseDiagram({0:[1,2],1:[3],2:[3],3:[]}) - sage: H.is_meet_semilattice() + sage: H.is_meet_semilattice() # optional - sage.modules True sage: H = HasseDiagram({0:[2,3],1:[2,3]}) - sage: H.is_meet_semilattice() + sage: H.is_meet_semilattice() # optional - sage.modules False sage: H = HasseDiagram({0:[1,2],1:[3,4],2:[3,4]}) - sage: H.is_meet_semilattice() + sage: H.is_meet_semilattice() # optional - sage.modules False """ try: @@ -1613,7 +1672,7 @@ def _join(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,3,2],1:[4],2:[4,5,6],3:[6],4:[7],5:[7],6:[7],7:[]}) - sage: H._join + sage: H._join # optional - sage.modules [0 1 2 3 4 5 6 7] [1 1 4 7 4 7 7 7] [2 4 2 6 4 5 6 7] @@ -1624,14 +1683,14 @@ def _join(self): [7 7 7 7 7 7 7 7] sage: H = HasseDiagram({0:[2,3],1:[2,3]}) - sage: H._join + sage: H._join # optional - sage.modules [ 0 -1 2 3] [-1 1 2 3] [ 2 2 2 -1] [ 3 3 -1 3] sage: H = HasseDiagram({0:[2,3],1:[2,3],2:[4],3:[4]}) - sage: H._join + sage: H._join # optional - sage.modules [ 0 -1 2 3 4] [-1 1 2 3 4] [ 2 2 2 4 4] @@ -1641,9 +1700,9 @@ def _join(self): TESTS:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram - sage: L = LatticePoset({0:[1,2,3],1:[4],2:[4],3:[4]}) - sage: P = L.dual() - sage: P.join(2,3) + sage: L = LatticePoset({0:[1,2,3],1:[4],2:[4],3:[4]}) # optional - sage.modules + sage: P = L.dual() # optional - sage.modules + sage: P.join(2,3) # optional - sage.modules 0 """ self._join_semilattice_failure = () @@ -1694,7 +1753,7 @@ def join_matrix(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,3,2],1:[4],2:[4,5,6],3:[6],4:[7],5:[7],6:[7],7:[]}) - sage: H.join_matrix() + sage: H.join_matrix() # optional - sage.modules [0 1 2 3 4 5 6 7] [1 1 4 7 4 7 7 7] [2 4 2 6 4 5 6 7] @@ -1714,7 +1773,7 @@ def join_matrix(self): ValueError: not a join-semilattice: no top element sage: H = HasseDiagram({0:[2,3],1:[2,3],2:[4],3:[4]}) - sage: H.join_matrix() + sage: H.join_matrix() # optional - sage.modules Traceback (most recent call last): ... LatticeError: no join for ... @@ -1738,13 +1797,13 @@ def is_join_semilattice(self) -> bool: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,3,2],1:[4],2:[4,5,6],3:[6],4:[7],5:[7],6:[7],7:[]}) - sage: H.is_join_semilattice() + sage: H.is_join_semilattice() # optional - sage.modules True sage: H = HasseDiagram({0:[2,3],1:[2,3]}) - sage: H.is_join_semilattice() + sage: H.is_join_semilattice() # optional - sage.modules False sage: H = HasseDiagram({0:[2,3],1:[2,3],2:[4],3:[4]}) - sage: H.is_join_semilattice() + sage: H.is_join_semilattice() # optional - sage.modules False """ try: @@ -1778,9 +1837,9 @@ def find_nonsemidistributive_elements(self, meet_or_join): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1, 2], 1:[3, 4], 2:[4, 5], 3:[6], ....: 4:[6], 5:[6]}) - sage: H.find_nonsemidistributive_elements('join') is None + sage: H.find_nonsemidistributive_elements('join') is None # optional - sage.modules False - sage: H.find_nonsemidistributive_elements('meet') is None + sage: H.find_nonsemidistributive_elements('meet') is None # optional - sage.modules True """ if meet_or_join == 'join': @@ -1865,11 +1924,11 @@ def is_complemented(self) -> int | None: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1, 2], 1:[3], 2:[3], 3:[4]}) - sage: H.is_complemented() + sage: H.is_complemented() # optional - sage.modules 1 sage: H = HasseDiagram({0:[1, 2, 3], 1:[4], 2:[4], 3:[4]}) - sage: H.is_complemented() is None + sage: H.is_complemented() is None # optional - sage.modules True """ mt = self.meet_matrix() @@ -1910,11 +1969,11 @@ def pseudocomplement(self, element): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0: [1, 2], 1: [3], 2: [4], 3: [4]}) - sage: H.pseudocomplement(2) + sage: H.pseudocomplement(2) # optional - sage.modules 3 sage: H = HasseDiagram({0: [1, 2, 3], 1: [4], 2: [4], 3: [4]}) - sage: H.pseudocomplement(2) is None + sage: H.pseudocomplement(2) is None # optional - sage.modules True """ e = self.order() - 1 @@ -1941,7 +2000,7 @@ def orthocomplementations_iterator(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,2], 1:[3,4], 3:[5], 4:[5], 2:[6,7], ....: 6:[8], 7:[8], 5:[9], 8:[9]}) - sage: list(H.orthocomplementations_iterator()) + sage: list(H.orthocomplementations_iterator()) # optional - sage.groups [[9, 8, 5, 6, 7, 2, 3, 4, 1, 0], [9, 8, 5, 7, 6, 2, 4, 3, 1, 0]] ALGORITHM: @@ -1962,54 +2021,54 @@ def orthocomplementations_iterator(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram() # Empty - sage: list(H.orthocomplementations_iterator()) + sage: list(H.orthocomplementations_iterator()) # optional - sage.groups [[]] sage: H = HasseDiagram({0:[]}) # One element - sage: list(H.orthocomplementations_iterator()) + sage: list(H.orthocomplementations_iterator()) # optional - sage.groups [[0]] sage: H = HasseDiagram({0:[1]}) # Two elements - sage: list(H.orthocomplementations_iterator()) + sage: list(H.orthocomplementations_iterator()) # optional - sage.groups [[1, 0]] Trivial cases: odd number of elements, not self-dual, not complemented:: sage: H = posets.DiamondPoset(5)._hasse_diagram - sage: list(H.orthocomplementations_iterator()) + sage: list(H.orthocomplementations_iterator()) # optional - sage.groups [] sage: H = posets.ChainPoset(4)._hasse_diagram - sage: list(H.orthocomplementations_iterator()) + sage: list(H.orthocomplementations_iterator()) # optional - sage.groups [] sage: H = HasseDiagram( ([[0, 1], [0, 2], [0, 3], [1, 4], [1, 8], [4, 6], [4, 7], [6, 9], [7, 9], [2, 5], [3, 5], [5, 8], [8, 9]]) ) - sage: list(H.orthocomplementations_iterator()) + sage: list(H.orthocomplementations_iterator()) # optional - sage.groups [] sage: H = HasseDiagram({0:[1, 2, 3], 1: [4], 2:[4], 3: [5], 4:[5]}) - sage: list(H.orthocomplementations_iterator()) + sage: list(H.orthocomplementations_iterator()) # optional - sage.groups [] Complemented, self-dual and even number of elements, but not orthocomplemented:: sage: H = HasseDiagram( ([[0, 1], [1, 2], [2, 3], [0, 4], [4, 5], [0, 6], [3, 7], [5, 7], [6, 7]]) ) - sage: list(H.orthocomplementations_iterator()) + sage: list(H.orthocomplementations_iterator()) # optional - sage.groups [] Unique orthocomplementations; second is not uniquely complemented, - but has only one orthocomplementation. + but has only one orthocomplementation:: sage: H = posets.BooleanLattice(4)._hasse_diagram # Uniquely complemented - sage: len(list(H.orthocomplementations_iterator())) + sage: len(list(H.orthocomplementations_iterator())) # optional - sage.groups 1 sage: H = HasseDiagram({0:[1, 2], 1:[3], 2:[4], 3:[5], 4:[5]}) - sage: len([_ for _ in H.orthocomplementations_iterator()]) + sage: len([_ for _ in H.orthocomplementations_iterator()]) # optional - sage.groups 1 "Lengthening diamond" must keep the number of orthocomplementations:: sage: H = HasseDiagram( ([[0, 1], [0, 2], [0, 3], [0, 4], [1, 5], [2, 5], [3, 5], [4, 5]]) ) - sage: n = len([_ for _ in H.orthocomplementations_iterator()]); n + sage: n = len([_ for _ in H.orthocomplementations_iterator()]); n # optional - sage.groups 3 sage: H = HasseDiagram('M]??O?@??C??OA???OA??@?A??C?A??O??') - sage: len([_ for _ in H.orthocomplementations_iterator()]) == n + sage: len([_ for _ in H.orthocomplementations_iterator()]) == n # optional - sage.groups True This lattice has an unique "possible orthocomplement" for every @@ -2018,7 +2077,7 @@ def orthocomplementations_iterator(self): for chain 0-1-6-11 would be 11-7-8-0, which is not a chain:: sage: H = HasseDiagram('KTGG_?AAC?O?o?@?@?E?@?@??') - sage: list(H.orthocomplementations_iterator()) + sage: list(H.orthocomplementations_iterator()) # optional - sage.groups [] """ n = self.order() @@ -2108,7 +2167,7 @@ def find_nonsemimodular_pair(self, upper): INPUT: - - upper, a Boolean -- if ``True``, test whether the lattice is + - ``upper``, a Boolean -- if ``True``, test whether the lattice is upper semimodular; otherwise test whether the lattice is lower semimodular. @@ -2164,22 +2223,20 @@ def antichains_iterator(self): EXAMPLES:: + sage: # needs sage.modules sage: P = posets.PentagonPoset() sage: H = P._hasse_diagram sage: H.antichains_iterator() <generator object ...antichains_iterator at ...> sage: list(H.antichains_iterator()) [[], [4], [3], [2], [1], [1, 3], [1, 2], [0]] - sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,2],1:[4],2:[3],3:[4]}) sage: list(H.antichains_iterator()) [[], [4], [3], [2], [1], [1, 3], [1, 2], [0]] - sage: H = HasseDiagram({0:[],1:[],2:[]}) sage: list(H.antichains_iterator()) [[], [2], [1], [1, 2], [0], [0, 2], [0, 1], [0, 1, 2]] - sage: H = HasseDiagram({0:[1],1:[2],2:[3],3:[4]}) sage: list(H.antichains_iterator()) [[], [4], [3], [2], [1], [0]] @@ -2187,7 +2244,7 @@ def antichains_iterator(self): TESTS:: sage: H = Poset()._hasse_diagram - sage: list(H.antichains_iterator()) + sage: list(H.antichains_iterator()) # optional - sage.modules [[]] """ # NOTE: Ordering of antichains as a prefix tree is crucial for @@ -2221,6 +2278,7 @@ def are_incomparable(self, i, j): EXAMPLES:: + sage: # needs sage.modules sage: P = posets.PentagonPoset() sage: H = P._hasse_diagram sage: H.are_incomparable(1,2) @@ -2246,13 +2304,16 @@ def are_comparable(self, i, j): EXAMPLES:: + sage: # needs sage.modules sage: P = posets.PentagonPoset() sage: H = P._hasse_diagram sage: H.are_comparable(1,2) False sage: V = H.vertices(sort=True) sage: [ (i,j) for i in V for j in V if H.are_comparable(i,j)] - [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 4), (2, 0), (2, 2), (2, 3), (2, 4), (3, 0), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)] + [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 4), + (2, 0), (2, 2), (2, 3), (2, 4), (3, 0), (3, 2), (3, 3), (3, 4), + (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)] """ if i == j: return True @@ -2271,6 +2332,7 @@ def antichains(self, element_class=list): EXAMPLES:: + sage: # needs sage.modules sage: P = posets.PentagonPoset() sage: H = P._hasse_diagram sage: A = H.antichains() @@ -2285,8 +2347,8 @@ def antichains(self, element_class=list): TESTS:: + sage: # needs sage.modules sage: TestSuite(A).run() - sage: A = Poset()._hasse_diagram.antichains() sage: list(A) [[]] @@ -2322,11 +2384,14 @@ def chains(self, element_class=list, exclude=None, conversion=None): EXAMPLES:: + sage: # needs sage.modules sage: P = posets.PentagonPoset() sage: H = P._hasse_diagram sage: A = H.chains() sage: list(A) - [[], [0], [0, 1], [0, 1, 4], [0, 2], [0, 2, 3], [0, 2, 3, 4], [0, 2, 4], [0, 3], [0, 3, 4], [0, 4], [1], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]] + [[], [0], [0, 1], [0, 1, 4], [0, 2], [0, 2, 3], [0, 2, 3, 4], [0, 2, 4], + [0, 3], [0, 3, 4], [0, 4], [1], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4], + [3], [3, 4], [4]] sage: A.cardinality() 20 sage: [1,3] in A @@ -2336,6 +2401,7 @@ def chains(self, element_class=list, exclude=None, conversion=None): One can exclude some vertices:: + sage: # needs sage.modules sage: list(H.chains(exclude=[4, 3])) [[], [0], [0, 1], [0, 2], [1], [2]] @@ -2364,7 +2430,7 @@ def is_linear_interval(self, t_min, t_max) -> bool: This means that this interval is a total order. EXAMPLES:: - + sage: # needs sage.modules sage: P = posets.PentagonPoset() sage: H = P._hasse_diagram sage: H.is_linear_interval(0, 4) @@ -2445,9 +2511,9 @@ def diamonds(self): sage: H.diamonds() ([(0, 1, 2, 3)], True) - sage: P = posets.YoungDiagramPoset(Partition([3, 2, 2])) - sage: H = P._hasse_diagram - sage: H.diamonds() + sage: P = posets.YoungDiagramPoset(Partition([3, 2, 2])) # optional - sage.combinat + sage: H = P._hasse_diagram # optional - sage.combinat + sage: H.diamonds() # optional - sage.combinat ([(0, 1, 3, 4), (3, 4, 5, 6)], False) """ diamonds = [] @@ -2475,13 +2541,13 @@ def common_upper_covers(self, vertices): [3] sage: from sage.combinat.posets.poset_examples import Posets - sage: H = Posets.YoungDiagramPoset(Partition([3, 2, 2]))._hasse_diagram - sage: H.common_upper_covers([4, 5]) + sage: H = Posets.YoungDiagramPoset(Partition([3, 2, 2]))._hasse_diagram # optional - sage.combinat + sage: H.common_upper_covers([4, 5]) # optional - sage.combinat [6] """ - covers = set(self.neighbors_out(vertices.pop())) + covers = set(self.neighbor_out_iterator(vertices.pop())) for v in vertices: - covers = covers.intersection(self.neighbors_out(v)) + covers = covers.intersection(self.neighbor_out_iterator(v)) return list(covers) def common_lower_covers(self, vertices): @@ -2496,13 +2562,13 @@ def common_lower_covers(self, vertices): [0] sage: from sage.combinat.posets.poset_examples import Posets - sage: H = Posets.YoungDiagramPoset(Partition([3, 2, 2]))._hasse_diagram - sage: H.common_lower_covers([4, 5]) + sage: H = Posets.YoungDiagramPoset(Partition([3, 2, 2]))._hasse_diagram # optional - sage.combinat + sage: H.common_lower_covers([4, 5]) # optional - sage.combinat [3] """ - covers = set(self.neighbors_in(vertices.pop())) + covers = set(self.neighbor_in_iterator(vertices.pop())) for v in vertices: - covers = covers.intersection(self.neighbors_in(v)) + covers = covers.intersection(self.neighbor_in_iterator(v)) return list(covers) def _trivial_nonregular_congruence(self): @@ -2573,9 +2639,9 @@ def sublattices_iterator(self, elms, min_e): sage: H = HasseDiagram({0: [1, 2], 1:[3], 2:[3]}) sage: it = H.sublattices_iterator(set(), 0); it <generator object ...sublattices_iterator at ...> - sage: next(it) + sage: next(it) # optional - sage.modules set() - sage: next(it) + sage: next(it) # optional - sage.modules {0} """ yield elms @@ -2605,9 +2671,9 @@ def maximal_sublattices(self): EXAMPLES:: - sage: L = posets.PentagonPoset() - sage: ms = L._hasse_diagram.maximal_sublattices() - sage: sorted(ms, key=sorted) + sage: L = posets.PentagonPoset() # optional - sage.modules + sage: ms = L._hasse_diagram.maximal_sublattices() # optional - sage.modules + sage: sorted(ms, key=sorted) # optional - sage.modules [{0, 1, 2, 4}, {0, 1, 3, 4}, {0, 2, 3, 4}] """ jn = self.join_matrix() @@ -2698,7 +2764,7 @@ def sublattice(elms, e): break # Special case to handle at last. - if len(self.neighbors_out(0)) == 1: + if self.out_degree(0) == 1: result.append(set(range(1, N))) return result @@ -2709,8 +2775,8 @@ def frattini_sublattice(self): EXAMPLES:: - sage: H = posets.PentagonPoset()._hasse_diagram - sage: H.frattini_sublattice() + sage: H = posets.PentagonPoset()._hasse_diagram # optional - sage.modules + sage: H.frattini_sublattice() # optional - sage.modules [0, 4] """ # Just a direct computation, no optimization at all. @@ -2764,8 +2830,8 @@ def kappa_dual(self, a): uc = next(self.neighbor_out_iterator(a)) if self.in_degree(uc) == 1: return uc - lt_a = set(self.depth_first_search(a, neighbors=self.neighbors_in)) - tmp = list(self.depth_first_search(uc, neighbors=lambda v: [v_ for v_ in self.neighbor_in_iterator(v) if v_ not in lt_a])) + lt_a = set(self.depth_first_search(a, neighbors=self.neighbor_in_iterator)) + tmp = set(self.depth_first_search(uc, neighbors=lambda v: [v_ for v_ in self.neighbor_in_iterator(v) if v_ not in lt_a])) result = None for e in tmp: if all(x not in tmp for x in self.neighbor_in_iterator(e)): @@ -2794,7 +2860,7 @@ def skeleton(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0: [1, 2], 1: [3, 4], 2: [4], ....: 3: [5], 4: [5]}) - sage: H.skeleton() + sage: H.skeleton() # optional - sage.modules [5, 2, 0, 3] """ p_atoms = [] @@ -2886,8 +2952,8 @@ def neutral_elements(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0: [1, 2], 1: [4], 2: [3], 3: [4, 5], - ....: 4: [6], 5:[6]}) - sage: sorted(H.neutral_elements()) + ....: 4: [6], 5: [6]}) + sage: sorted(H.neutral_elements()) # optional - sage.modules [0, 4, 6] ALGORITHM: @@ -2924,7 +2990,7 @@ def neutral_elements(self): def is_neutral(a): noncomp = all_elements.difference(self.depth_first_search(a)) - noncomp.difference_update(self.depth_first_search(a, neighbors=self.neighbors_in)) + noncomp.difference_update(self.depth_first_search(a, neighbors=self.neighbor_in_iterator)) for x in noncomp.intersection(todo): meet_ax = mt[a, x] @@ -3005,7 +3071,7 @@ def kappa(self, a): if self.out_degree(lc) == 1: return lc gt_a = set(self.depth_first_search(a)) - tmp = list(self.depth_first_search(lc, neighbors=lambda v: [v_ for v_ in self.neighbor_out_iterator(v) if v_ not in gt_a])) + tmp = set(self.depth_first_search(lc, neighbors=lambda v: [v_ for v_ in self.neighbor_out_iterator(v) if v_ not in gt_a])) result = None for e in tmp: if all(x not in tmp for x in self.neighbor_out_iterator(e)): @@ -3034,10 +3100,10 @@ def atoms_of_congruence_lattice(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: N5 = HasseDiagram({0: [1, 2], 1: [4], 2: [3], 3:[4]}) - sage: N5.atoms_of_congruence_lattice() + sage: N5.atoms_of_congruence_lattice() # optional - sage.combinat [{{0}, {1}, {2, 3}, {4}}] sage: Hex = HasseDiagram({0: [1, 2], 1: [3], 2: [4], 3: [5], 4: [5]}) - sage: Hex.atoms_of_congruence_lattice() + sage: Hex.atoms_of_congruence_lattice() # optional - sage.combinat [{{0}, {1}, {2, 4}, {3}, {5}}, {{0}, {1, 3}, {2}, {4}, {5}}] ALGORITHM: @@ -3111,32 +3177,32 @@ def congruence(self, parts, start=None, stop_pairs=[]): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0: [1, 2], 1: [3], 2: [4], 3: [4]}) - sage: cong = H.congruence([[0, 1]]); cong + sage: cong = H.congruence([[0, 1]]); cong # optional - sage.modules {{0, 1, 3}, {2, 4}} - sage: H.congruence([[0, 2]], start=cong) + sage: H.congruence([[0, 2]], start=cong) # optional - sage.modules {{0, 1, 2, 3, 4}} - sage: H.congruence([[0, 1]], stop_pairs=[(1, 3)]) is None + sage: H.congruence([[0, 1]], stop_pairs=[(1, 3)]) is None # optional - sage.modules True TESTS:: sage: H = HasseDiagram('HT@O?GO?OE?G@??') - sage: H.congruence([[0, 1]]).number_of_subsets() + sage: H.congruence([[0, 1]]).number_of_subsets() # optional - sage.modules 1 sage: H = HasseDiagram('HW_oC?@@O@?O@??') - sage: H.congruence([[0, 1]]).number_of_subsets() + sage: H.congruence([[0, 1]]).number_of_subsets() # optional - sage.modules 1 Check :trac:`21861`:: sage: H = HasseDiagram({0: [1, 2], 1: [3], 2: [4], 3: [4]}) - sage: tmp = H.congruence([[1, 3]]) - sage: tmp.number_of_subsets() + sage: tmp = H.congruence([[1, 3]]) # optional - sage.modules + sage: tmp.number_of_subsets() # optional - sage.modules 4 - sage: H.congruence([[0, 1]], start=tmp).number_of_subsets() + sage: H.congruence([[0, 1]], start=tmp).number_of_subsets() # optional - sage.modules 2 - sage: tmp.number_of_subsets() + sage: tmp.number_of_subsets() # optional - sage.modules 4 """ from sage.sets.disjoint_set import DisjointSet @@ -3254,11 +3320,11 @@ def find_nontrivial_congruence(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0: [1, 2], 1: [5], 2: [3, 4], 3: [5], 4: [5]}) - sage: H.find_nontrivial_congruence() + sage: H.find_nontrivial_congruence() # optional - sage.modules {{0, 1}, {2, 3, 4, 5}} sage: H = HasseDiagram({0: [1, 2, 3], 1: [4], 2: [4], 3: [4]}) - sage: H.find_nontrivial_congruence() is None + sage: H.find_nontrivial_congruence() is None # optional - sage.modules True ALGORITHM: @@ -3280,9 +3346,9 @@ def find_nontrivial_congruence(self): join_irreducibles = [v for v in self if self.in_degree(v) == 1] meet_irreducibles = [v for v in self if self.out_degree(v) == 1] if len(join_irreducibles) < len(meet_irreducibles): - irr = [(v, self.neighbors_in(v)[0]) for v in join_irreducibles] + irr = [(v, next(self.neighbor_in_iterator(v))) for v in join_irreducibles] else: - irr = [(self.neighbors_out(v)[0], v) for v in meet_irreducibles] + irr = [(next(self.neighbor_out_iterator(v)), v) for v in meet_irreducibles] irr.sort(key=lambda x: x[0] - x[1]) tried = [] for pair in irr: @@ -3313,12 +3379,12 @@ def principal_congruences_poset(self): sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: N5 = HasseDiagram({0: [1, 2], 1: [4], 2: [3], 3: [4]}) - sage: P, D = N5.principal_congruences_poset() - sage: P + sage: P, D = N5.principal_congruences_poset() # optional - sage.combinat + sage: P # optional - sage.combinat Finite poset containing 3 elements - sage: P.bottom() + sage: P.bottom() # optional - sage.combinat (2, 3) - sage: D[(2, 3)] + sage: D[(2, 3)] # optional - sage.combinat {{0}, {1}, {2, 3}, {4}} """ from sage.combinat.set_partition import SetPartition, SetPartitions @@ -3360,7 +3426,7 @@ def congruences_iterator(self): sage: H = HasseDiagram('GY@OQ?OW@?O?') sage: it = H.congruences_iterator(); it <generator object ...> - sage: sorted([cong.number_of_subsets() for cong in it]) + sage: sorted([cong.number_of_subsets() for cong in it]) # optional - sage.combinat [1, 2, 2, 2, 4, 4, 4, 8] """ from sage.sets.disjoint_set import DisjointSet @@ -3395,26 +3461,26 @@ def is_congruence_normal(self) -> bool: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram('IX?Q@?AG?OG?W?O@??') - sage: H.is_congruence_normal() + sage: H.is_congruence_normal() # optional - sage.combinat True The 5-element diamond is the smallest non-example:: sage: H = HasseDiagram({0: [1, 2, 3], 1: [4], 2: [4], 3: [4]}) - sage: H.is_congruence_normal() + sage: H.is_congruence_normal() # optional - sage.combinat False This is done by doubling a non-convex subset:: sage: H = HasseDiagram('OQC?a?@CO?G_C@?GA?O??_??@?BO?A_?G??C??_?@???') - sage: H.is_congruence_normal() + sage: H.is_congruence_normal() # optional - sage.combinat False TESTS:: - sage: HasseDiagram().is_congruence_normal() + sage: HasseDiagram().is_congruence_normal() # optional - sage.combinat True - sage: HasseDiagram({0: []}).is_congruence_normal() + sage: HasseDiagram({0: []}).is_congruence_normal() # optional - sage.combinat True ALGORITHM: diff --git a/src/sage/combinat/posets/incidence_algebras.py b/src/sage/combinat/posets/incidence_algebras.py index 2d621cef967..204c4661b3b 100644 --- a/src/sage/combinat/posets/incidence_algebras.py +++ b/src/sage/combinat/posets/incidence_algebras.py @@ -425,8 +425,9 @@ def __invert__(self): raise ValueError("element is not invertible") inv = ~M L = self.parent()._linear_extension - return self.parent().sum_of_terms(((L[i], L[j]), inv[i, j]) - for i, j in inv.nonzero_positions(copy=False)) + return self.parent().sum_of_terms( + ((L[i], L[j]), inv[i, j]) + for i, j in inv.nonzero_positions(copy=False)) class ReducedIncidenceAlgebra(CombinatorialFreeModule): diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index 985b61cd6ca..99e403765f8 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -993,7 +993,7 @@ def is_join_distributive(self, certificate=False): (False, 2) """ if ((self.is_ranked() and len(self.meet_irreducibles()) == self.rank()) or - self.cardinality() == 0): + self.cardinality() == 0): return (True, None) if certificate else True if not certificate: return False @@ -1081,7 +1081,7 @@ def is_meet_distributive(self, certificate=False): (False, 6) """ if ((self.is_ranked() and len(self.join_irreducibles()) == self.rank()) or - self.cardinality() == 0): + self.cardinality() == 0): return (True, None) if certificate else True if not certificate: return False @@ -1250,8 +1250,8 @@ def is_distributive(self, certificate=False): return ok if (self.is_graded() and - self.rank() == len(self.join_irreducibles()) == - len(self.meet_irreducibles())): + self.rank() == len(self.join_irreducibles()) == + len(self.meet_irreducibles())): return ok if not certificate: @@ -1695,7 +1695,7 @@ def is_cosectionally_complemented(self, certificate=False): n = H.order() for e in range(n - 2, -1, -1): t = 0 - for uc in H.neighbors_out(e): + for uc in H.neighbor_out_iterator(e): t = jn[t, uc] if t == n - 1: break @@ -1805,13 +1805,13 @@ def is_relatively_complemented(self, certificate=False): return False for e1 in range(n - 1): - C = Counter(flatten([H.neighbors_out(e2) for e2 in H.neighbors_out(e1)])) + C = Counter(flatten([H.neighbors_out(e2) for e2 in H.neighbor_out_iterator(e1)])) for e3, c in C.items(): if c == 1 and len(H.closed_interval(e1, e3)) == 3: if not certificate: return False - for e2 in H.neighbors_in(e3): - if e2 in H.neighbors_out(e1): + for e2 in H.neighbor_in_iterator(e3): + if e2 in H.neighbor_out_iterator(e1): break return (False, (self._vertex_to_element(e1), self._vertex_to_element(e2), @@ -1885,7 +1885,7 @@ def is_sectionally_complemented(self, certificate=False): n = H.order() - 1 for e in range(2, n + 1): t = n - for lc in H.neighbors_in(e): + for lc in H.neighbor_in_iterator(e): t = mt[t, lc] if t == 0: break @@ -1988,8 +1988,8 @@ def join(L): # Get elements more than B levels below it. too_close = set(H.breadth_first_search(j, - neighbors=H.neighbors_in, - distance=B - 2)) + neighbors=H.neighbor_in_iterator, + distance=B - 2)) elems = [e for e in H.order_ideal([j]) if e not in too_close] achains = PairwiseCompatibleSubsets(elems, @@ -2378,7 +2378,7 @@ def is_atomic(self, certificate=False): if self.cardinality() < 3: return (True, None) H = self._hasse_diagram - atoms = set(H.neighbors_out(0)) + atoms = set(H.neighbor_out_iterator(0)) for v in H: if H.in_degree(v) == 1 and v not in atoms: return (False, self._vertex_to_element(v)) @@ -2436,7 +2436,7 @@ def is_coatomic(self, certificate=False): if self.cardinality() < 3: return (True, None) H = self._hasse_diagram - coatoms = set(H.neighbors_in(n - 1)) + coatoms = set(H.neighbor_in_iterator(n - 1)) for v in H: if H.out_degree(v) == 1 and v not in coatoms: return (False, self._vertex_to_element(v)) @@ -2649,7 +2649,7 @@ def is_modular(self, L=None, certificate=False): for x in self.principal_lower_set(b): for a in self: if (self.join(x, self.meet(a, b)) != - self.meet(self.join(x, a), b)): + self.meet(self.join(x, a), b)): if certificate: return (False, (x, a, b)) return False @@ -3259,7 +3259,7 @@ def is_sublattice(self, other): for i in range(n): for j in range(i): if (o_meet(self[i], self[j]) not in self or - o_join(self[i], self[j]) not in self): + o_join(self[i], self[j]) not in self): return False return True @@ -3782,8 +3782,8 @@ def is_dismantlable(self, certificate=False): if certificate: cert.append(e) if i == 1 and o == 1: # Remove inside the lattice - lower = H.neighbors_in(e)[0] - upper = H.neighbors_out(e)[0] + lower = next(H.neighbor_in_iterator(e)) + upper = next(H.neighbor_out_iterator(e)) H.delete_vertex(e) if upper not in H.depth_first_search(lower): H.add_edge(lower, upper) @@ -4125,9 +4125,12 @@ def canonical_meetands(self, e): H = self._hasse_diagram e = self._element_to_vertex(e) meetands = [] - for a in H.neighbors_out(e): - above_a = list(H.depth_first_search(a)) - go_up = lambda v: [v_ for v_ in H.neighbors_out(v) if v_ not in above_a] + for a in H.neighbor_out_iterator(e): + above_a = set(H.depth_first_search(a)) + + def go_up(v): + return [v_ for v_ in H.neighbor_out_iterator(v) if v_ not in above_a] + result = None for v in H.depth_first_search(e, neighbors=go_up): if H.out_degree(v) == 1 and next(H.neighbor_out_iterator(v)) in above_a: @@ -4188,9 +4191,12 @@ def canonical_joinands(self, e): H = self._hasse_diagram e = self._element_to_vertex(e) joinands = [] - for a in H.neighbors_in(e): - below_a = list(H.depth_first_search(a, neighbors=H.neighbors_in)) - go_down = lambda v: [v_ for v_ in H.neighbors_in(v) if v_ not in below_a] + for a in H.neighbor_in_iterator(e): + below_a = set(H.depth_first_search(a, neighbors=H.neighbor_in_iterator)) + + def go_down(v): + return [v_ for v_ in H.neighbor_in_iterator(v) if v_ not in below_a] + result = None for v in H.depth_first_search(e, neighbors=go_down): if H.in_degree(v) == 1 and next(H.neighbor_in_iterator(v)) in below_a: @@ -4200,7 +4206,7 @@ def canonical_joinands(self, e): joinands.append(result) return [self._vertex_to_element(v) for v in joinands] - def is_constructible_by_doublings(self, type): + def is_constructible_by_doublings(self, type) -> bool: r""" Return ``True`` if the lattice is constructible by doublings, and ``False`` otherwise. @@ -4945,6 +4951,109 @@ def congruences_lattice(self, labels='congruence'): return L.relabel(lambda e: SetPartition([[self._vertex_to_element(v) for v in p] for p in C[e]])) + def feichtner_yuzvinsky_ring(self, G, use_defining=False, base_ring=None): + r""" + Return the Feichtner-Yuzvinsky ring of ``self`` and ``G``. + + Let `R` be a commutative ring, `L` a lattice, and `G \subseteq L`. + The *Feichtner-Yuzvinsky ring* is the quotient of the polynomial + ring `R[h_g \mid g \in G]` by the ideal generated by + + - `h_a` for every atom `a \in L \cap G` and + - for every antichain `A` of the subposet `G` such that + `g := \bigvee A \in G` (with the join taken in `L`) + + .. MATH:: + + \prod_{a \in A} (h_g - h_a). + + This was originally described for `G` such that `(L, G)` is a built + lattice in the sense of [FY2004]_ (which has a geometric motivation), + but this has been extended to `G` being an arbitrary subset. + + This is not the original definition, which uses the nested subsets + of `G` (see [FY2004]_ for the definition). However, the original + construction, which we call the *defining* presentation and use the + variables `\{x_g \mid g \in G\}`, can be recovered by setting + `h_g = \sum_{g' \geq g} x_{g'}` (where `g' \in G`). + + INPUT: + + - ``G`` -- a subset of elements of ``self`` + - ``use_defining`` -- (default: ``False``) whether or not to use + the defining presentation in `x_g` + - ``base_ring`` -- (default: `\QQ`) the base ring + + The order on the variables is equal to the ordering of the + elements in ``G``. + + EXAMPLES:: + + sage: B2 = posets.BooleanLattice(2) + sage: FY = B2.feichtner_yuzvinsky_ring(B2[1:]) + sage: FY + Quotient of Multivariate Polynomial Ring in h0, h1, h2 over Rational Field + by the ideal (h0, h1, h0*h1 - h0*h2 - h1*h2 + h2^2) + + sage: FY = B2.feichtner_yuzvinsky_ring(B2[1:], use_defining=True) + sage: FY + Quotient of Multivariate Polynomial Ring in x0, x1, x2 over Rational Field + by the ideal (x0 + x2, x1 + x2, x0*x1) + + We reproduce the example from Section 5 of [Coron2023]_:: + + sage: H.<a,b,c,d> = HyperplaneArrangements(QQ) + sage: Arr = H(a-b, b-c, c-d, d-a) + sage: P = LatticePoset(Arr.intersection_poset()) + sage: FY = P.feichtner_yuzvinsky_ring([P.top(),5,1,2,3,4]) + sage: FY.defining_ideal().groebner_basis() + [h0^2 - h0*h1, h1^2, h2, h3, h4, h5] + + TESTS:: + + sage: B2 = posets.BooleanLattice(2) + sage: B2.feichtner_yuzvinsky_ring([1,2,1]) + Traceback (most recent call last): + ... + ValueError: the input set G must not contain duplicates + """ + if base_ring is None: + from sage.rings.rational_field import QQ + base_ring = QQ + + G = tuple(G) + Gmap = {g: i for i, g in enumerate(G)} + if len(G) != len(Gmap): + raise ValueError("the input set G must not contain duplicates") + GP = self.subposet(G) + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + if use_defining: + R = PolynomialRing(base_ring, 'x', len(G)) + gens = R.gens() + gens = [R.sum(gens[Gmap[gp]] for gp in GP.order_filter([g])) + for g in G] + else: + R = PolynomialRing(base_ring, 'h', len(G)) + gens = R.gens() + I = [] + atoms = set(self.atoms()) + for i, g in enumerate(G): + if g in atoms: + I.append(gens[i]) + for A in GP.antichains_iterator(): + if len(A) <= 1: + # skip trivial cases + continue + gp = A[0] + for y in A[1:]: + gp = self.join(gp, y) + if gp not in Gmap: + continue + i = Gmap[gp] + I.append(R.prod(gens[i] - gens[Gmap[a]] for a in A)) + return R.quotient(I) + def _log_2(n): """ diff --git a/src/sage/combinat/posets/linear_extension_iterator.pyx b/src/sage/combinat/posets/linear_extension_iterator.pyx new file mode 100644 index 00000000000..5eb101b32e2 --- /dev/null +++ b/src/sage/combinat/posets/linear_extension_iterator.pyx @@ -0,0 +1,288 @@ +# cython: binding=True +r""" +Fast linear extension iterator +""" +cimport cython + +from copy import copy +def _linear_extension_prepare(D): + r""" + The preprocessing routine in Figure 7 of "Generating Linear + Extensions Fast" by Preusse and Ruskey. + + INPUT: + + - ``D``, the Hasse diagram of a poset + + OUTPUT: + + - a triple ``(le, a, b)``, where ``le`` is the first linear + extension, and ``a`` and ``b`` are lists such that ``a[i]`` and + ``b[i]`` are minimal elements of ``D`` after removing ``a[:i]`` + and ``b[:i]``. + + TESTS:: + + sage: from sage.combinat.posets.linear_extension_iterator import _linear_extension_prepare + sage: D = Poset({ 0:[1,2], 1:[3], 2:[3,4] })._hasse_diagram + sage: _linear_extension_prepare(D) + ([0, 1, 2, 3, 4], [1, 3], [2, 4]) + + """ + dag_copy = copy(D) # this copy is destroyed during preparation + le = [] + a = [] + b = [] + + # the preprocessing routine found in Figure 7 of + # "Generating Linear Extensions Fast" by + # Pruesse and Ruskey + while dag_copy.num_verts() != 0: + # find all the minimal elements of dag_copy + minimal_elements = dag_copy.sources() + if not minimal_elements: + raise ValueError("the digraph must be acyclic to have linear extensions") + elif len(minimal_elements) == 1: + le.append(minimal_elements[0]) + dag_copy.delete_vertex(minimal_elements[0]) + else: + ap = minimal_elements[0] + bp = minimal_elements[1] + a.append(ap) + b.append(bp) + le.append(ap) + le.append(bp) + dag_copy.delete_vertex(ap) + dag_copy.delete_vertex(bp) + + return (le, a, b) + +@cython.wraparound(False) +@cython.boundscheck(False) +cdef void _linear_extension_switch(list _le, list _a, list _b, list _is_plus, Py_ssize_t i): + """ + This implements the ``Switch`` procedure described on page 7 + of "Generating Linear Extensions Fast" by Pruesse and Ruskey. + + If ``i == -1``, then the sign is changed. Otherwise, then + ``_a[i]`` and ``_b[i]`` are transposed. + + """ + cdef Py_ssize_t a_index, b_index + if i == -1: + _is_plus[0] = not _is_plus[0] + else: + a = _a[i] + b = _b[i] + a_index = _le.index(a) + b_index = _le.index(b) + _le[a_index] = b + _le[b_index] = a + _b[i] = a + _a[i] = b + +@cython.wraparound(False) +@cython.boundscheck(False) +cdef bint _linear_extension_right_a(_D, list _le, list _a, list _b, Py_ssize_t i): + """ + Return ``True`` if and only if ``_a[i]`` is incomparable with the + element to its right in ``_le`` and the element to the right is + not ``_b[i]``. + + This is the ``Right`` function described on page 8 of + "Generating Linear Extensions Fast" by Pruesse and Ruskey. + + :: + + sage: D = Poset({ 0:[1,2], 1:[3], 2:[3,4] })._hasse_diagram # not tested + sage: _linear_extension_right_a(D, [0, 1, 2, 4, 3], [1, 4], [2, 3], 0) # not tested + False + sage: _linear_extension_right_a(D, [0, 1, 2, 4, 3], [1, 4], [2, 3], 1) # not tested + False + + """ + cdef Py_ssize_t yindex + x = _a[i] + yindex = _le.index(x) + 1 + if yindex >= len(_le): + return False + y = _le[yindex] + return y != _b[i] and _D.are_incomparable(x, y) + +@cython.wraparound(False) +@cython.boundscheck(False) +cdef bint _linear_extension_right_b(_D, list _le, list _a, list _b, Py_ssize_t i): + """ + Return True if and only if ``_b[i]`` is incomparable with the + elements to its right in ``_le``. + + This is the ``Right`` function described on page 8 of + "Generating Linear Extensions Fast" by Pruesse and Ruskey. + + :: + + sage: D = Poset({ 0:[1,2], 1:[3], 2:[3,4] })._hasse_diagram # not tested + sage: _linear_extension_right_b(D, [0, 1, 2, 4, 3], [1, 4], [2, 3], 0) # not tested + False + sage: _linear_extension_right_b(D, [0, 1, 2, 4, 3], [1, 4], [2, 3], 1) # not tested + False + + """ + cdef Py_ssize_t yindex + x = _b[i] + yindex = _le.index(x) + 1 + if yindex >= len(_le): + return False + y = _le[yindex] + return _D.are_incomparable(x, y) + +@cython.wraparound(False) +@cython.boundscheck(False) +def _linear_extension_gen(_D, list _le, list _a, list _b, list _is_plus, Py_ssize_t i): + """ + This a Python version of the GenLE routine found in Figure 8 + of "Generating Linear Extensions Fast" by Pruesse and Ruskey. + + TESTS:: + + sage: from sage.combinat.posets.linear_extension_iterator import _linear_extension_prepare, _linear_extension_gen + sage: D = Poset({ 0:[1,2], 1:[3], 2:[3,4] })._hasse_diagram + sage: le, a, b = _linear_extension_prepare(D) + sage: [e for e in _linear_extension_gen(D, le, a, b, [True], len(a)-1)] + [[0, 2, 1, 3, 4]] + + """ + cdef int mra, mrb, mla + cdef Py_ssize_t index, index1 + cdef bint typical + if i == -1: + return + + for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): + yield e + mrb = 0 + typical = False + while _linear_extension_right_b(_D, _le, _a, _b, i): + mrb += 1 + # move_right + index = _le.index(_b[i]) + index1 = index + 1 + _le[index] = _le[index1] + _le[index1] = _b[i] + if _is_plus[0]: + yield _le[:] + + for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): + yield e + mra = 0 + while _linear_extension_right_a(_D, _le, _a, _b, i): + typical = True + mra += 1 + # move_right + index = _le.index(_a[i]) + index1 = index+1 + _le[index] = _le[index1] + _le[index1] = _a[i] + if _is_plus[0]: + yield _le[:] + + for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): + yield e + + if typical: + _linear_extension_switch(_le, _a, _b, _is_plus, i-1) + if _is_plus[0]: + yield _le[:] + + for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): + yield e + if mrb % 2 == 1: + mla = mra - 1 + else: + mla = mra + 1 + for _ in range(mla): + # move_left + index = _le.index(_a[i]) + index1 = index-1 + _le[index] = _le[index1] + _le[index1] = _a[i] + if _is_plus[0]: + yield _le[:] + + for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): + yield e + + if typical and (mrb % 2 == 1): + # move_left + index = _le.index(_a[i]) + index1 = index-1 + _le[index] = _le[index1] + _le[index1] = _a[i] + if _is_plus[0]: + yield _le[:] + else: + _linear_extension_switch(_le, _a, _b, _is_plus, i-1) + if _is_plus[0]: + yield _le[:] + for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): + yield e + for _ in range(mrb): + # move_left + index = _le.index(_b[i]) + index1 = index-1 + _le[index] = _le[index1] + _le[index1] = _b[i] + if _is_plus[0]: + yield _le[:] + + for e in _linear_extension_gen(_D, _le, _a, _b, _is_plus, i-1): + yield e + + +def linear_extension_iterator(D): + """ + Iterate over the linear extensions of the poset. + + The list ``_le`` keeps track of the current linear extensions. The + boolean variable ``is_plus`` keeps track of the "sign". + + INPUT: + + - ``D``, the Hasse diagram of a poset. + + .. WARNING:: + + It is assumed that ``D`` is not modified while the linear + extensions are generated. + + EXAMPLES:: + + sage: from sage.combinat.posets.linear_extension_iterator import linear_extension_iterator + sage: D = Poset({ 0:[1,2], 1:[3], 2:[3,4] })._hasse_diagram + sage: list(linear_extension_iterator(D)) + [[0, 1, 2, 3, 4], + [0, 2, 1, 3, 4], + [0, 2, 1, 4, 3], + [0, 2, 4, 1, 3], + [0, 1, 2, 4, 3]] + + sage: D = posets.BooleanLattice(3)._hasse_diagram + sage: len(list(linear_extension_iterator(D))) + 48 + + sage: D = posets.AntichainPoset(9)._hasse_diagram + sage: len(list(linear_extension_iterator(D))) == factorial(9) # long time + True + """ + _le, _a, _b = _linear_extension_prepare(D) + _max_pair = len(_a) - 1 + _is_plus = [True] # this is modified by _linear_extension_switch + + yield _le[:] + for e in _linear_extension_gen(D, _le, _a, _b, _is_plus, _max_pair): + yield e + _linear_extension_switch(_le, _a, _b, _is_plus, _max_pair) + if _is_plus[0]: + yield _le[:] + for e in _linear_extension_gen(D, _le, _a, _b, _is_plus, _max_pair): + yield e diff --git a/src/sage/combinat/posets/linear_extensions.py b/src/sage/combinat/posets/linear_extensions.py index 48ca0af51d5..47792a7118f 100644 --- a/src/sage/combinat/posets/linear_extensions.py +++ b/src/sage/combinat/posets/linear_extensions.py @@ -40,7 +40,7 @@ class LinearExtensionOfPoset(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): + metaclass=InheritComparisonClasscallMetaclass): r""" A linear extension of a finite poset `P` of size `n` is a total ordering `\pi := \pi_0 \pi_1 \ldots \pi_{n-1}` of its elements @@ -232,8 +232,8 @@ def is_greedy(self): EXAMPLES:: - sage: P = posets.PentagonPoset() - sage: for l in P.linear_extensions(): + sage: P = posets.PentagonPoset() # optional - sage.modules + sage: for l in P.linear_extensions(): # optional - sage.modules ....: if not l.is_greedy(): ....: print(l) [0, 2, 1, 3, 4] @@ -255,15 +255,15 @@ def is_greedy(self): def is_supergreedy(self): r""" Return ``True`` if the linear extension is supergreedy. - - A linear extension `[x_1<x_2<...<x_t]` of a finite ordered - set `P=(P, <)` is *super greedy* if it can be obtained using - the following procedure: Choose `x_1` to be a minimal - element of `P`; suppose `x_1,...,x_i` have been chosen; - define `p(x)` to be the largest `j\leq i` such that `x_j<x` - if such a `j` exists and 0 otherwise; choose `x_{i+1}` - to be a minimal element of `P-\{x_1,...,x_i\}` which - maximizes `p`. + + A linear extension of a poset `P` with elements `\{x_1,x_2,...,x_t\}` + is *super greedy*, if it can be obtained using the following + algorithm: choose `x_1` to be a minimal element of `P`; + suppose `X = \{x_1,...,x_i\}` have been chosen; let `M` be + the set of minimal elements of `P\setminus X`. If there is an element + of `M` which covers an element `x_j` in `X`, then let `x_{i+1}` + be one of these such that `j` is maximal; otherwise, choose `x_{i+1}` + to be any element of `M`. Informally, a linear extension is supergreedy if it "always goes up and receedes the least"; in other words, supergreedy @@ -271,19 +271,19 @@ def is_supergreedy(self): For more details see [KTZ1987]_. EXAMPLES:: - + sage: X = [0,1,2,3,4,5,6] sage: Y = [[0,5],[1,4],[1,5],[3,6],[4,3],[5,6],[6,2]] - sage: P = Poset((X,Y), cover_relations = True, facade=False) - sage: for l in P.linear_extensions(): + sage: P = Poset((X,Y), cover_relations=True, facade=False) + sage: for l in P.linear_extensions(): # optional - sage.modules sage.rings.finite_rings ....: if l.is_supergreedy(): ....: print(l) [1, 4, 3, 0, 5, 6, 2] [0, 1, 4, 3, 5, 6, 2] [0, 1, 5, 4, 3, 6, 2] - sage: Q = posets.PentagonPoset() - sage: for l in Q.linear_extensions(): + sage: Q = posets.PentagonPoset() # optional - sage.modules + sage: for l in Q.linear_extensions(): # optional - sage.modules sage.rings.finite_rings ....: if not l.is_supergreedy(): ....: print(l) [0, 2, 1, 3, 4] @@ -294,31 +294,23 @@ def is_supergreedy(self): sage: T.linear_extensions()[0].is_supergreedy() True """ - P = self.poset() - H = P.hasse_diagram() - - def next_elements(H, linext): - k = len(linext) - S = [] - while not S: - if not k: - S = [x for x in H.sources() if x not in linext] - else: - S = [x for x in H.neighbor_out_iterator(linext[k-1]) if x not in linext and all(low in linext for low in H.neighbor_in_iterator(x))] - k -= 1 - return S - if not self: - return True - if self[0] not in H.sources(): - return False - for i in range(len(self)-2): - X = next_elements(H,self[:i+1]) - if self[i+1] in X: - continue - else: + H = self.poset().hasse_diagram() + L = sources = H.sources() + linext = [] + for e in self: + if e not in L: return False + linext.append(e) + for y in reversed(linext): + L = [x for x in H.neighbor_out_iterator(y) + if x not in linext + and all(low in linext for low in H.neighbor_in_iterator(x))] + if L: + break + else: + L = sources = [x for x in sources if x not in linext] return True - + def tau(self, i): r""" Return the operator `\tau_i` on linear extensions ``self`` of a poset. @@ -340,7 +332,7 @@ def tau(self, i): [1, 2, 3, 4] sage: l.tau(1) [2, 1, 3, 4] - sage: for p in L: + sage: for p in L: # optional - sage.modules sage.rings.finite_rings ....: for i in range(1,4): ....: print("{} {} {}".format(i, p, p.tau(i))) 1 [1, 2, 3, 4] [2, 1, 3, 4] @@ -497,7 +489,7 @@ class LinearExtensionsOfPoset(UniqueRepresentation, Parent): The set of all linear extensions of Finite poset containing 4 elements with distinguished linear extension sage: L.cardinality() 5 - sage: L.list() + sage: L.list() # optional - sage.modules sage.rings.finite_rings [[1, 2, 3, 4], [2, 1, 3, 4], [2, 1, 4, 3], [1, 4, 2, 3], [1, 2, 4, 3]] sage: L.an_element() [1, 2, 3, 4] @@ -672,10 +664,10 @@ def __iter__(self): sage: rels = [[1,3],[1,4],[2,3]] sage: P = Poset((elms, rels), linear_extension=True) sage: L = P.linear_extensions() - sage: list(L) + sage: list(L) # optional - sage.modules sage.rings.finite_rings [[1, 2, 3, 4], [2, 1, 3, 4], [2, 1, 4, 3], [1, 4, 2, 3], [1, 2, 4, 3]] """ - from sage.combinat.combinat_cython import linear_extension_iterator + from sage.combinat.posets.linear_extension_iterator import linear_extension_iterator vertex_to_element = self._poset._vertex_to_element for lin_ext in linear_extension_iterator(self._poset._hasse_diagram): yield self._element_constructor_([vertex_to_element(_) for _ in lin_ext]) @@ -830,28 +822,28 @@ def markov_chain_transition_matrix(self, action='promotion', labeling='identity' sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]), linear_extension = True) sage: L = P.linear_extensions() - sage: L.markov_chain_transition_matrix() + sage: L.markov_chain_transition_matrix() # optional - sage.modules [-x0 - x1 - x2 x2 x0 + x1 0 0] [ x1 + x2 -x0 - x1 - x2 0 x0 0] [ 0 x1 -x0 - x1 0 x0] [ 0 x0 0 -x0 - x1 - x2 x1 + x2] [ x0 0 0 x1 + x2 -x0 - x1 - x2] - sage: L.markov_chain_transition_matrix(labeling = 'source') + sage: L.markov_chain_transition_matrix(labeling='source') # optional - sage.modules [-x0 - x1 - x2 x3 x0 + x3 0 0] [ x1 + x2 -x0 - x1 - x3 0 x1 0] [ 0 x1 -x0 - x3 0 x1] [ 0 x0 0 -x0 - x1 - x2 x0 + x3] [ x0 0 0 x0 + x2 -x0 - x1 - x3] - sage: L.markov_chain_transition_matrix(action = 'tau') + sage: L.markov_chain_transition_matrix(action='tau') # optional - sage.modules [ -x0 - x2 x2 0 x0 0] [ x2 -x0 - x1 - x2 x1 0 x0] [ 0 x1 -x1 0 0] [ x0 0 0 -x0 - x2 x2] [ 0 x0 0 x2 -x0 - x2] - sage: L.markov_chain_transition_matrix(action = 'tau', labeling = 'source') + sage: L.markov_chain_transition_matrix(action='tau', labeling='source') # optional - sage.modules [ -x0 - x2 x3 0 x1 0] [ x2 -x0 - x1 - x3 x3 0 x1] [ 0 x1 -x3 0 0] @@ -930,8 +922,8 @@ def cardinality(self): EXAMPLES:: sage: from sage.combinat.posets.poset_examples import Posets - sage: P = Posets.YoungDiagramPoset(Partition([3,2]), dual=True) - sage: P.linear_extensions().cardinality() + sage: P = Posets.YoungDiagramPoset(Partition([3,2]), dual=True) # optional - sage.combinat + sage: P.linear_extensions().cardinality() # optional - sage.combinat sage.modules 5 """ num_elmts = self._poset.cardinality() @@ -957,11 +949,11 @@ def cardinality(self): sage: from sage.combinat.posets.forest import ForestPoset sage: from sage.combinat.posets.poset_examples import Posets sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) - sage: P.linear_extensions().cardinality() + sage: P.linear_extensions().cardinality() # optional - sage.modules 4 sage: Q = Poset({0: [1], 1: [2, 3], 2: [], 3: [], 4: [5, 6], 5: [], 6: []}) - sage: Q.linear_extensions().cardinality() + sage: Q.linear_extensions().cardinality() # optional - sage.modules 140 """ return sum(self.atkinson(self._elements[0])) @@ -982,17 +974,18 @@ def cardinality(self): sage: from sage.combinat.posets.mobile import MobilePoset sage: M = MobilePoset(DiGraph([[0,1,2,3,4,5,6,7,8], [(1,0),(3,0),(2,1),(2,3),(4, ....: 3), (5,4),(5,6),(7,4),(7,8)]])) - sage: M.linear_extensions().cardinality() + sage: M.linear_extensions().cardinality() # optional - sage.modules 1098 sage: M1 = posets.RibbonPoset(6, [1,3]) - sage: M1.linear_extensions().cardinality() + sage: M1.linear_extensions().cardinality() # optional - sage.modules 61 - sage: P = posets.MobilePoset(posets.RibbonPoset(7, [1,3]), {1: - ....: [posets.YoungDiagramPoset([3, 2], dual=True)], 3: [posets.DoubleTailedDiamond(6)]}, - ....: anchor=(4, 2, posets.ChainPoset(6))) - sage: P.linear_extensions().cardinality() + sage: P = posets.MobilePoset(posets.RibbonPoset(7, [1,3]), # optional - sage.combinat + ....: {1: [posets.YoungDiagramPoset([3, 2], dual=True)], + ....: 3: [posets.DoubleTailedDiamond(6)]}, + ....: anchor=(4, 2, posets.ChainPoset(6))) + sage: P.linear_extensions().cardinality() # optional - sage.combinat sage.modules 361628701868606400 """ import sage.combinat.posets.d_complete as dc diff --git a/src/sage/combinat/posets/mobile.py b/src/sage/combinat/posets/mobile.py index 26e793c96d2..321942a0fd7 100644 --- a/src/sage/combinat/posets/mobile.py +++ b/src/sage/combinat/posets/mobile.py @@ -28,13 +28,13 @@ class MobilePoset(FinitePoset): EXAMPLES:: - sage: P = posets.MobilePoset(posets.RibbonPoset(7, [1,3]), + sage: P = posets.MobilePoset(posets.RibbonPoset(7, [1,3]), # optional - sage.combinat ....: {1: [posets.YoungDiagramPoset([3, 2], dual=True)], ....: 3: [posets.DoubleTailedDiamond(6)]}, ....: anchor=(4, 2, posets.ChainPoset(6))) - sage: len(P._ribbon) + sage: len(P._ribbon) # optional - sage.combinat 8 - sage: P._anchor + sage: P._anchor # optional - sage.combinat (4, 5) This example is Example 5.9 in [GGMM2020]_:: @@ -53,7 +53,7 @@ class MobilePoset(FinitePoset): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] sage: P2._anchor (8, (8, 0)) - sage: P2.linear_extensions().cardinality() + sage: P2.linear_extensions().cardinality() # optional - sage.modules 21399440939 sage: EP = posets.MobilePoset(posets.ChainPoset(0), {}) @@ -112,18 +112,18 @@ def _is_valid_ribbon(self, ribbon): num_anchors = 0 for r in ribbon: - anchor_neighbors = set(G.neighbors_out(r)).difference(set(R.neighbors_out(r))) + anchor_neighbors = set(G.neighbor_out_iterator(r)).difference(set(R.neighbor_out_iterator(r))) if len(anchor_neighbors) == 1: num_anchors += 1 elif len(anchor_neighbors) > 1: return False - for lc in G.neighbors_in(r): + for lc in G.neighbor_in_iterator(r): if lc in ribbon: continue G_un.delete_edge(lc, r) - P = Poset(G.subgraph(G_un.connected_component_containing_vertex(lc))) + P = Poset(G.subgraph(G_un.connected_component_containing_vertex(lc, sort=False))) if P.top() != lc or not P.is_d_complete(): return False G_un.add_edge(lc, r) @@ -151,7 +151,7 @@ def _anchor(self): # Find the anchor vertex, if it exists, and return the edge for r in ribbon: - anchor_neighbors = set(H.neighbors_out(r)).difference(set(R.neighbors_out(r))) + anchor_neighbors = set(H.neighbor_out_iterator(r)).difference(set(R.neighbor_out_iterator(r))) if len(anchor_neighbors) == 1: anchor = (r, anchor_neighbors.pop()) break diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index 7f1fcf1e633..f565c7f9903 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.modules r""" Catalog of posets and lattices @@ -106,6 +107,51 @@ from sage.categories.finite_lattice_posets import FiniteLatticePosets from sage.graphs.digraph import DiGraph from sage.rings.integer import Integer +from sage.sets.non_negative_integers import NonNegativeIntegers + + +def check_int(n, minimum=0): + """ + Check that ``n`` is an integer at least equal to ``minimum``. + + This is a boilerplate function ensuring input safety. + + INPUT: + + - ``n`` -- anything + + - ``minimum`` -- an optional integer (default: 0) + + EXAMPLES:: + + sage: from sage.combinat.posets.poset_examples import check_int + sage: check_int(6, 3) + 6 + sage: check_int(6) + 6 + + sage: check_int(-1) + Traceback (most recent call last): + ... + ValueError: number of elements must be a non-negative integer, not -1 + + sage: check_int(1, 3) + Traceback (most recent call last): + ... + ValueError: number of elements must be an integer at least 3, not 1 + + sage: check_int('junk') + Traceback (most recent call last): + ... + ValueError: number of elements must be a non-negative integer, not junk + """ + if minimum == 0: + msg = "a non-negative integer" + else: + msg = f"an integer at least {minimum}" + if n not in NonNegativeIntegers() or n < minimum: + raise ValueError("number of elements must be " + msg + f", not {n}") + return Integer(n) class Posets(metaclass=ClasscallMetaclass): @@ -155,12 +201,7 @@ def __classcall__(cls, n=None): """ if n is None: return sage.categories.posets.Posets() - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {0}".format(n)) - if n < 0: - raise ValueError("number of elements must be non-negative, not {0}".format(n)) + n = check_int(n) return FinitePosets_n(n) @staticmethod @@ -203,12 +244,7 @@ def BooleanLattice(n, facade=None, use_subsets=False): sage: list(posets.BooleanLattice(1, use_subsets=True)) [{}, {1}] """ - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {0}".format(n)) - if n < 0: - raise ValueError("number of elements must be non-negative, not {0}".format(n)) + n = check_int(n) if n == 0: if use_subsets: from sage.sets.set import Set @@ -282,12 +318,7 @@ def ChainPoset(n, facade=None): sage: C.cover_relations() [[0, 1]] """ - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {0}".format(n)) - if n < 0: - raise ValueError("number of elements must be non-negative, not {0}".format(n)) + n = check_int(n) D = DiGraph([range(n), [[x, x + 1] for x in range(n - 1)]], format='vertices_and_edges') return FiniteLatticePoset(hasse_diagram=D, @@ -335,12 +366,7 @@ def AntichainPoset(n, facade=None): sage: C.cover_relations() [] """ - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {0}".format(n)) - if n < 0: - raise ValueError("number of elements must be non-negative, not {0}".format(n)) + n = check_int(n) return Poset((range(n), []), facade=facade) @staticmethod @@ -398,12 +424,7 @@ def DiamondPoset(n, facade=None): sage: posets.DiamondPoset(7) Finite lattice containing 7 elements """ - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {0}".format(n)) - if n <= 2: - raise ValueError("n must be an integer at least 3") + n = check_int(n, 3) c = [[n - 1] for x in range(n)] c[0] = [x for x in range(1, n - 1)] c[n - 1] = [] @@ -435,12 +456,7 @@ def Crown(n, facade=None): sage: posets.Crown(3) Finite poset containing 6 elements """ - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {0}".format(n)) - if n < 2: - raise ValueError("n must be an integer at least 2") + n = check_int(n, 2) D = {i: [i + n, i + n + 1] for i in range(n - 1)} D[n - 1] = [n, n + n - 1] return FinitePoset(hasse_diagram=DiGraph(D), category=FinitePosets(), @@ -478,12 +494,7 @@ def DivisorLattice(n, facade=None): Finite lattice containing 1 elements with distinguished linear extension """ from sage.arith.misc import divisors, is_prime - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {0}".format(n)) - if n <= 0: - raise ValueError("n must be a positive integer") + n = check_int(n, 1) Div_n = divisors(n) hasse = DiGraph([Div_n, lambda a, b: b % a == 0 and is_prime(b // a)]) return FiniteLatticePoset(hasse, elements=Div_n, facade=facade, @@ -623,9 +634,7 @@ def IntegerPartitionsDominanceOrder(n): [[4, 2], [5, 1]], [[5, 1], [6]]] """ - from sage.rings.semirings.non_negative_integer_semiring import NN - if n not in NN: - raise ValueError('n must be an integer') + n = check_int(n) from sage.combinat.partition import Partitions, Partition return LatticePoset((Partitions(n), Partition.dominates)).dual() @@ -663,14 +672,7 @@ def PowerPoset(n): 0 """ # Todo: Make this faster. - - try: - n = Integer(n) - except TypeError: - raise TypeError("parameter n must be an integer, not {0}".format(n)) - if n < 0: - raise ValueError("parameter n must be non-negative, not {0}".format(n)) - + n = check_int(n) all_pos_n = set() Pn = list(Posets(n)) for P in Pn: @@ -726,7 +728,9 @@ def ProductOfChains(chain_lengths, facade=None): return LatticePoset(facade=facade) from sage.categories.cartesian_product import cartesian_product elements = cartesian_product([range(i) for i in l]) - compare = lambda a, b: all(x <= y for x, y in zip(a, b)) + + def compare(a, b): + return all(x <= y for x, y in zip(a, b)) return LatticePoset([elements, compare], facade=facade) @staticmethod @@ -759,16 +763,6 @@ def RandomPoset(n, p): TESTS:: - sage: posets.RandomPoset('junk', 0.5) - Traceback (most recent call last): - ... - TypeError: number of elements must be an integer, not junk - - sage: posets.RandomPoset(-6, 0.5) - Traceback (most recent call last): - ... - ValueError: number of elements must be non-negative, not -6 - sage: posets.RandomPoset(6, 'garbage') Traceback (most recent call last): ... @@ -783,16 +777,10 @@ def RandomPoset(n, p): Finite poset containing 0 elements """ from sage.misc.prandom import random - - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {0}".format(n)) - if n < 0: - raise ValueError("number of elements must be non-negative, not {0}".format(n)) + n = check_int(n) try: p = float(p) - except Exception: + except (TypeError, ValueError): raise TypeError("probability must be a real number, not {0}".format(p)) if p < 0 or p > 1: raise ValueError("probability must be between 0 and 1, not {0}".format(p)) @@ -800,7 +788,7 @@ def RandomPoset(n, p): D = DiGraph(loops=False, multiedges=False) D.add_vertices(range(n)) for i in range(n): - for j in range(i+1, n): + for j in range(i + 1, n): if random() < p: D.add_edge(i, j) D.relabel(list(Permutations(n).random_element())) @@ -856,16 +844,6 @@ def RandomLattice(n, p, properties=None): TESTS:: - sage: posets.RandomLattice('junk', 0.5) - Traceback (most recent call last): - ... - TypeError: number of elements must be an integer, not junk - - sage: posets.RandomLattice(-6, 0.5) - Traceback (most recent call last): - ... - ValueError: number of elements must be non-negative, not -6 - sage: posets.RandomLattice(6, 'garbage') Traceback (most recent call last): ... @@ -885,13 +863,7 @@ def RandomLattice(n, p, properties=None): Finite lattice containing 0 elements """ from copy import copy - - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {0}".format(n)) - if n < 0: - raise ValueError("number of elements must be non-negative, not {0}".format(n)) + n = check_int(n) try: p = float(p) except Exception: @@ -906,7 +878,7 @@ def RandomLattice(n, p, properties=None): covers = _random_lattice(n, p) covers_dict = {i: covers[i] for i in range(n)} D = DiGraph(covers_dict) - D.relabel([i-1 for i in Permutations(n).random_element()]) + D.relabel([i - 1 for i in Permutations(n).random_element()]) return LatticePoset(D, cover_relations=True) if isinstance(properties, str): @@ -937,23 +909,23 @@ def RandomLattice(n, p, properties=None): if properties == set(['planar']): D = _random_planar_lattice(n) - D.relabel([i-1 for i in Permutations(n).random_element()]) + D.relabel([i - 1 for i in Permutations(n).random_element()]) return LatticePoset(D) if properties == set(['dismantlable']): D = _random_dismantlable_lattice(n) - D.relabel([i-1 for i in Permutations(n).random_element()]) + D.relabel([i - 1 for i in Permutations(n).random_element()]) return LatticePoset(D) if properties == set(['stone']): D = _random_stone_lattice(n) - D.relabel([i-1 for i in Permutations(n).random_element()]) + D.relabel([i - 1 for i in Permutations(n).random_element()]) return LatticePoset(D) if properties == set(['distributive']): tmp = Poset(_random_distributive_lattice(n)).order_ideals_lattice(as_ideals=False) D = copy(tmp._hasse_diagram) - D.relabel([i-1 for i in Permutations(n).random_element()]) + D.relabel([i - 1 for i in Permutations(n).random_element()]) return LatticePoset(D) raise AssertionError("bug in RandomLattice()") @@ -973,15 +945,13 @@ def SetPartitions(n): sage: posets.SetPartitions(4) Finite lattice containing 15 elements """ - from sage.rings.semirings.non_negative_integer_semiring import NN - if n not in NN: - raise ValueError('n must be an integer') from sage.combinat.set_partition import SetPartitions + n = check_int(n) S = SetPartitions(n) def covers(x): for i, s in enumerate(x): - for j in range(i+1, len(x)): + for j in range(i + 1, len(x)): L = list(x) L[i] = s.union(x[j]) L.pop(j) @@ -1021,7 +991,7 @@ def SSTPoset(s, f=None): sage: posets.SSTPoset([2,1],2).cover_relations() [[[[1, 1], [2]], [[1, 2], [2]]]] - sage: posets.SSTPoset([3,2]).bottom() # long time (6s on sage.math, 2012) + sage: posets.SSTPoset([3,2]).bottom() # long time (6s on sage.math, 2012) [[1, 1, 1], [2, 2]] sage: posets.SSTPoset([3,2],4).maximal_elements() @@ -1033,7 +1003,7 @@ def tableaux_is_less_than(a, b): return all(ix <= iy for x, y in zip(a, b) for ix, iy in zip(x, y)) if f is None: - f = sum(i for i in s) + f = sum(s) E = SemistandardTableaux(s, max_entry=f) return LatticePoset((E, tableaux_is_less_than)) @@ -1083,14 +1053,9 @@ def StandardExample(n, facade=None): sage: P(4) < P(3), P(4) > P(3) (False, False) """ - try: - n = Integer(n) - except TypeError: - raise TypeError("dimension must be an integer, not {0}".format(n)) - if n < 2: - raise ValueError("dimension must be at least 2, not {0}".format(n)) - return Poset((range(2*n), [[i, j+n] for i in range(n) - for j in range(n) if i != j]), + n = check_int(n, 2) + return Poset((range(2 * n), [[i, j + n] for i in range(n) + for j in range(n) if i != j]), facade=facade) @staticmethod @@ -1244,17 +1209,20 @@ def TetrahedralPoset(n, *colors, **labels): sage: tet = posets.TetrahedralPoset(3, 'green','yellow','blue','orange') sage: ji.is_isomorphic(tet) True + + TESTS:: + + sage: posets.TetrahedralPoset(4,'scarlet') + Traceback (most recent call last): + ... + ValueError: color input must be among: 'green', 'red', 'yellow', + 'orange', 'silver', and 'blue' """ + n = check_int(n, 2) n = n - 1 - try: - n = Integer(n) - except TypeError: - raise TypeError("n must be an integer") - if n < 2: - raise ValueError("n must be greater than 2") for c in colors: if c not in ('green', 'red', 'yellow', 'orange', 'silver', 'blue'): - raise ValueError("color input must be from the following: 'green', 'red', 'yellow', 'orange', 'silver', and 'blue'") + raise ValueError("color input must be among: 'green', 'red', 'yellow', 'orange', 'silver', and 'blue'") elem = [(i, j, k) for i in range(n) for j in range(n - i) for k in range(n - i - j)] rels = [] @@ -1309,12 +1277,12 @@ def CoxeterGroupAbsoluteOrderPoset(W, use_reduced_words=True): EXAMPLES:: - sage: W = CoxeterGroup(['B', 3]) - sage: posets.CoxeterGroupAbsoluteOrderPoset(W) + sage: W = CoxeterGroup(['B', 3]) # needs sage.groups + sage: posets.CoxeterGroupAbsoluteOrderPoset(W) # needs sage.groups Finite poset containing 48 elements - sage: W = WeylGroup(['B', 2], prefix='s') - sage: posets.CoxeterGroupAbsoluteOrderPoset(W, False) + sage: W = WeylGroup(['B', 2], prefix='s') # needs sage.groups + sage: posets.CoxeterGroupAbsoluteOrderPoset(W, False) # needs sage.groups Finite poset containing 8 elements """ if use_reduced_words: @@ -1333,12 +1301,12 @@ def NoncrossingPartitions(W): EXAMPLES:: - sage: W = CoxeterGroup(['A', 3]) - sage: posets.NoncrossingPartitions(W) + sage: W = CoxeterGroup(['A', 3]) # needs sage.groups + sage: posets.NoncrossingPartitions(W) # needs sage.groups Finite lattice containing 14 elements - sage: W = WeylGroup(['B', 2], prefix='s') - sage: posets.NoncrossingPartitions(W) + sage: W = WeylGroup(['B', 2], prefix='s') # needs sage.groups + sage: posets.NoncrossingPartitions(W) # needs sage.groups Finite lattice containing 6 elements """ return W.noncrossing_partition_lattice() @@ -1364,11 +1332,11 @@ def SymmetricGroupAbsoluteOrderPoset(n, labels="permutations"): EXAMPLES:: - sage: posets.SymmetricGroupAbsoluteOrderPoset(4) + sage: posets.SymmetricGroupAbsoluteOrderPoset(4) # needs sage.groups Finite poset containing 24 elements - sage: posets.SymmetricGroupAbsoluteOrderPoset(3, labels="cycles") + sage: posets.SymmetricGroupAbsoluteOrderPoset(3, labels="cycles") # needs sage.groups Finite poset containing 6 elements - sage: posets.SymmetricGroupAbsoluteOrderPoset(3, labels="reduced_words") + sage: posets.SymmetricGroupAbsoluteOrderPoset(3, labels="reduced_words") # needs sage.groups Finite poset containing 6 elements """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -1421,12 +1389,7 @@ def UpDownPoset(n, m=1): sage: P = posets.UpDownPoset(0); P Finite poset containing 0 elements """ - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {0}".format(n)) - if n < 0: - raise ValueError("number of elements must be non-negative, not {0}".format(n)) + n = check_int(n) try: m = Integer(m) except TypeError: @@ -1581,32 +1544,27 @@ def YoungFibonacci(n): from sage.categories.finite_posets import FinitePosets from sage.combinat.words.word import Word - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {0}".format(n)) - if n < 0: - raise ValueError("number of elements must be non-negative, not {0}".format(n)) + n = check_int(n) if n == 0: return MeetSemilattice({'': []}) covers = [] current_level = [''] - for i in range(1, n+1): + for i in range(1, n + 1): new_level = set() for low in current_level: ind = low.find('1') if ind != -1: # = found a '1' -> change first '1' to '2' - up = low[:ind]+'2'+low[ind+1:] + up = low[:ind] + '2' + low[ind + 1:] new_level.add(up) covers.append((low, up)) else: # no '1' in low ind = len(low) # add '1' to every position not after first existing '1' - for j in range(ind+1): - up = '2'*j + '1' + low[j:len(low)] + for j in range(ind + 1): + up = '2' * j + '1' + low[j:len(low)] new_level.add(up) covers.append((low, up)) @@ -1632,17 +1590,12 @@ def DoubleTailedDiamond(n): sage: P.cover_relations() [[1, 2], [2, 3], [2, 4], [3, 5], [4, 5], [5, 6]] """ - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {}".format(n)) - if n <= 0: - raise ValueError("number of elements must be nonnegative, not {}".format(n)) - - edges = [(i, i+1) for i in range(1, n)] - edges.extend([(n, n+1), (n, n+2), (n+1, n+3), (n+2, n+3)]) - edges.extend([(i, i+1) for i in range(n+3, 2*n+2)]) - p = DiGraph([list(range(1, 2*n + 3)), edges]) + n = check_int(n, 1) + + edges = [(i, i + 1) for i in range(1, n)] + edges.extend([(n, n + 1), (n, n + 2), (n + 1, n + 3), (n + 2, n + 3)]) + edges.extend([(i, i + 1) for i in range(n + 3, 2 * n + 2)]) + p = DiGraph([list(range(1, 2 * n + 3)), edges]) return DCompletePoset(p) @staticmethod @@ -1680,12 +1633,7 @@ def PermutationPattern(n): sage: posets.PermutationPattern(2) Finite poset containing 3 elements """ - try: - n = Integer(n) - except TypeError: - raise TypeError("number of elements must be an integer, not {}".format(n)) - if n <= 0: - raise ValueError("number of elements must be nonnegative, not {}".format(n)) + n = check_int(n, 1) elem = [] for i in range(1, n + 1): elem += Permutations(i) @@ -1749,7 +1697,7 @@ def PermutationPatternInterval(bottom, top): # Try and remove the ith element from the permutation lower = list(upper) j = lower.pop(i) - for k in range(len(top)-level-1): # Standardize result + for k in range(len(top) - level - 1): # Standardize result if lower[k] > j: lower[k] = lower[k] - 1 lower_perm = P(lower) @@ -1804,13 +1752,13 @@ def PermutationPatternOccurrenceInterval(bottom, top, pos): while len(top) - len(bottom) >= level + 1: elem.append([]) # Add a new empty level for upper in elem[level]: - for i in range(len(top)-level): + for i in range(len(top) - level): # Try and remove the ith element from the permutation if i in upper[1]: continue lower_perm = list(upper[0]) j = lower_perm.pop(i) - for e in range(len(top)-level-1): + for e in range(len(top) - level - 1): if lower_perm[e] > j: lower_perm[e] = lower_perm[e] - 1 lower_pos = list(upper[1]) @@ -1841,6 +1789,7 @@ def RibbonPoset(n, descents): sage: sorted(R.cover_relations()) [[0, 1], [2, 1], [3, 2], [3, 4]] """ + n = check_int(n) return Mobile(DiGraph([list(range(n)), [(i + 1, i) if i in descents else (i, i + 1) for i in range(n - 1)]])) @@ -1955,9 +1904,9 @@ def _random_lattice(n, p): # Look for an admissible lower cover for the next element i while True: # Generate a random antichain - lc_list = [i-1-floor(i*sqrt(random()))] + lc_list = [i - 1 - floor(i * sqrt(random()))] while random() < p and 0 not in lc_list: - new = i-1-floor(i*sqrt(random())) + new = i - 1 - floor(i * sqrt(random())) if any(meets[new][lc] in [new, lc] for lc in lc_list): continue lc_list.append(new) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 239258cb42c..c31597c72e9 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs sage.modules r""" Finite posets @@ -287,12 +288,13 @@ from __future__ import annotations from collections import defaultdict from copy import copy, deepcopy +from itertools import product from typing import List from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.categories.category import Category from sage.categories.sets_cat import Sets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -433,6 +435,7 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio With a function that identifies the cover relations: the set partitions of `\{1, 2, 3\}` ordered by refinement:: + sage: # needs sage.combinat sage: elms = SetPartitions(3) sage: def fcn(A, B): ....: if len(A) != len(B)+1: @@ -877,7 +880,7 @@ class FinitePoset(UniqueRepresentation, Parent): Conversion to some other software is possible:: sage: P = posets.TamariLattice(3) - sage: libgap(P) # optional - gap_packages + sage: libgap(P) # optional - gap_package_qpa <A poset on 5 points> sage: P = Poset({1:[2],2:[]}) @@ -1368,11 +1371,11 @@ def _latex_(self): EXAMPLES:: sage: P = Poset(([1,2], [[1,2]]), cover_relations = True) - sage: print(P._latex_()) #optional - dot2tex graphviz + sage: print(P._latex_()) # optional - dot2tex graphviz \begin{tikzpicture}[>=latex,line join=bevel,] %% - \node (node_...) at (6.0...bp,...bp) [draw,draw=none] {$...$}; - \node (node_...) at (6.0...bp,...bp) [draw,draw=none] {$...$}; + \node (node_...) at (5...bp,...bp) [draw,draw=none] {$...$}; + \node (node_...) at (5...bp,...bp) [draw,draw=none] {$...$}; \draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...); % \end{tikzpicture} @@ -1685,8 +1688,8 @@ def spectrum(self, a): sage: P.spectrum(5) [0, 0, 0, 4, 12, 16, 16, 0] - sage: P = posets.YoungDiagramPoset(Partition([3,2,1])) - sage: P.spectrum((0,1)) + sage: P = posets.YoungDiagramPoset(Partition([3,2,1])) # needs sage.combinat + sage: P.spectrum((0,1)) # needs sage.combinat [0, 8, 6, 2, 0, 0] sage: P = posets.AntichainPoset(4) @@ -1853,10 +1856,10 @@ def is_linear_extension(self, l) -> bool: sage: P.is_linear_extension(['David', 'McNeil', 'La', 'Lamentable', 'Aventure', 'de', 'Simon', 'Wiesenthal']) False """ - index = {x: i for (i, x) in enumerate(l)} + index = {x: i for i, x in enumerate(l)} return (len(l) == self.cardinality() and all(x in index for x in self) and - all(index[i] < index[j] for (i, j) in self.cover_relations())) + all(index[i] < index[j] for i, j in self.cover_relations())) def list(self): """ @@ -1931,35 +1934,40 @@ def plot(self, label_elements=True, element_labels=None, This function can be used without any parameters:: + sage: # needs sage.plot sage: D12 = posets.DivisorLattice(12) sage: D12.plot() Graphics object consisting of 14 graphics primitives Just the abstract form of the poset; examples of relabeling:: + sage: # needs sage.plot sage: D12.plot(label_elements=False) Graphics object consisting of 8 graphics primitives sage: d = {1: 0, 2: 'a', 3: 'b', 4: 'c', 6: 'd', 12: 1} sage: D12.plot(element_labels=d) Graphics object consisting of 14 graphics primitives - sage: d = {i:str(factor(i)) for i in D12} + sage: d = {i: str(factor(i)) for i in D12} sage: D12.plot(element_labels=d) Graphics object consisting of 14 graphics primitives Some settings for coverings:: + sage: # needs sage.plot sage: d = {(a, b): b/a for a, b in D12.cover_relations()} sage: D12.plot(cover_labels=d, cover_color='gray', cover_style='dotted') Graphics object consisting of 21 graphics primitives To emphasize some elements and show some options:: + sage: # needs sage.plot sage: L = LatticePoset({0: [1, 2, 3, 4], 1: [12], 2: [6, 7], ....: 3: [5, 9], 4: [5, 6, 10, 11], 5: [13], ....: 6: [12], 7: [12, 8, 9], 8: [13], 9: [13], ....: 10: [12], 11: [12], 12: [13]}) sage: F = L.frattini_sublattice() - sage: F_internal = [c for c in F.cover_relations() if c in L.cover_relations()] + sage: F_internal = [c for c in F.cover_relations() + ....: if c in L.cover_relations()] sage: L.plot(figsize=12, border=True, element_shape='s', ....: element_size=400, element_color='white', ....: element_colors={'blue': F, 'green': L.double_irreducibles()}, @@ -1971,7 +1979,10 @@ def plot(self, label_elements=True, element_labels=None, We check that ``label_elements`` and ``element_labels`` are honored:: - sage: def get_plot_labels(P): return sorted(t.string for t in P if isinstance(t, sage.plot.text.Text)) + sage: # needs sage.plot + sage: def get_plot_labels(P): + ....: return sorted(t.string for t in P + ....: if isinstance(t, sage.plot.text.Text)) sage: P1 = Poset({ 0:[1,2], 1:[3], 2:[3,4] }) sage: P2 = Poset({ 0:[1,2], 1:[3], 2:[3,4] }, facade=True) sage: get_plot_labels(P1.plot(label_elements=False)) @@ -1986,6 +1997,7 @@ def plot(self, label_elements=True, element_labels=None, The following checks that :trac:`18936` has been fixed and labels still work:: + sage: # needs sage.plot sage: P = Poset({0: [1,2], 1:[3]}) sage: heights = {1 : [0], 2 : [1], 3 : [2,3]} sage: P.plot(heights=heights) @@ -1996,24 +2008,25 @@ def plot(self, label_elements=True, element_labels=None, The following checks that equal labels are allowed (:trac:`15206`):: + sage: # needs sage.plot sage: P = Poset({1: [2,3]}) - sage: labs = {i: P.rank(i) for i in range(1, 4)} - sage: labs + sage: labs = {i: P.rank(i) for i in range(1, 4)}; labs {1: 0, 2: 1, 3: 1} sage: P.plot(element_labels=labs) Graphics object consisting of 6 graphics primitives The following checks that non-hashable labels are allowed (:trac:`15206`):: + sage: # needs sage.plot sage: P = Poset({1: [2,3]}) - sage: labs = {1: [2, 3], 2: [], 3: []} - sage: labs + sage: labs = {1: [2, 3], 2: [], 3: []}; labs {1: [2, 3], 2: [], 3: []} sage: P.plot(element_labels=labs) Graphics object consisting of 6 graphics primitives Plot of the empty poset:: + sage: # needs sage.plot sage: P = Poset({}) sage: P.plot() Graphics object consisting of 0 graphics primitives @@ -2045,7 +2058,7 @@ def plot(self, label_elements=True, element_labels=None, if label_elements and element_labels is not None: from sage.misc.element_with_label import ElementWithLabel relabeling = {self(element): ElementWithLabel(self(element), label) - for (element, label) in element_labels.items()} + for element, label in element_labels.items()} graph = graph.relabel(relabeling, inplace=False) if heights is not None: for key in heights: @@ -2053,14 +2066,14 @@ def plot(self, label_elements=True, element_labels=None, if cover_labels is not None: if callable(cover_labels): - for (v, w) in graph.edges(sort=True, labels=False): + for v, w in graph.edges(sort=False, labels=False): graph.set_edge_label(v, w, cover_labels(v, w)) elif isinstance(cover_labels, dict): - for (v, w) in cover_labels: + for v, w in cover_labels: graph.set_edge_label(self(v), self(w), cover_labels[(v, w)]) else: - for (v, w, l) in cover_labels: + for v, w, l in cover_labels: graph.set_edge_label(self(v), self(w), l) cover_labels = True else: @@ -2101,6 +2114,7 @@ def show(self, label_elements=True, element_labels=None, EXAMPLES:: + sage: # needs sage.plot sage: D = Poset({ 0:[1,2], 1:[3], 2:[3,4] }) sage: D.plot(label_elements=False) Graphics object consisting of 6 graphics primitives @@ -2110,9 +2124,9 @@ def show(self, label_elements=True, element_labels=None, One more example with cover labels:: + sage: # needs sage.plot sage: P = posets.PentagonPoset() sage: P.show(cover_labels=lambda a, b: a - b) - """ # We split the arguments into those meant for plot() and those meant for show() # @@ -2286,8 +2300,8 @@ def diamonds(self): sage: P.diamonds() ([(0, 1, 2, 3)], True) - sage: P = posets.YoungDiagramPoset(Partition([3, 2, 2])) - sage: P.diamonds() + sage: P = posets.YoungDiagramPoset(Partition([3, 2, 2])) # needs sage.combinat + sage: P.diamonds() # needs sage.combinat ([((0, 0), (0, 1), (1, 0), (1, 1)), ((1, 0), (1, 1), (2, 0), (2, 1))], False) """ diamonds, all_diamonds_completed = self._hasse_diagram.diamonds() @@ -2415,8 +2429,8 @@ def is_d_complete(self) -> bool: sage: D.is_d_complete() False - sage: P = Posets.YoungDiagramPoset(Partition([3, 2, 2]), dual=True) - sage: P.is_d_complete() + sage: P = Posets.YoungDiagramPoset(Partition([3, 2, 2]), dual=True) # needs sage.combinat + sage: P.is_d_complete() # needs sage.combinat True """ min_diamond = {} # Maps max of double-tailed diamond to min of double-tailed diamond @@ -2440,7 +2454,7 @@ def is_d_complete(self) -> bool: min_elmt = d[0] max_elmt = d[3] - if len(H.neighbors_in(max_elmt)) != 2: + if H.in_degree(max_elmt) != 2: # Top of a diamond cannot cover anything but the two side elements return False @@ -2456,7 +2470,7 @@ def is_d_complete(self) -> bool: continue for mx in potential_max: if len(H.all_paths(mn, mx)) == 2: - if len(H.neighbors_in(mx)) != 1: + if H.in_degree(mx) != 1: # Max element covers something outside of double tailed diamond return False # Success @@ -2562,7 +2576,7 @@ def intervals_poset(self): ints = [tuple(u) for u in self.relations()] covers = [] - for (a, b) in ints: + for a, b in ints: covers.extend([[(a, b), (a, bb)] for bb in self.upper_covers(b)]) if a != b: covers.extend([[(a, b), (aa, b)] for aa in self.upper_covers(a) @@ -2753,10 +2767,10 @@ def is_incomparable_chain_free(self, m, n=None) -> bool: sage: B3.is_incomparable_chain_free(2, 2) False - sage: IP6 = posets.IntegerPartitions(6) - sage: IP6.is_incomparable_chain_free(1, 3) + sage: IP6 = posets.IntegerPartitions(6) # needs sage.combinat + sage: IP6.is_incomparable_chain_free(1, 3) # needs sage.combinat False - sage: IP6.is_incomparable_chain_free(2, 2) + sage: IP6.is_incomparable_chain_free(2, 2) # needs sage.combinat True A list of pairs as an argument:: @@ -2777,13 +2791,15 @@ def is_incomparable_chain_free(self, m, n=None) -> bool: sage: Poset().is_incomparable_chain_free(1,1) # Test empty poset True - sage: [len([p for p in Posets(n) if p.is_incomparable_chain_free(((3, 1), (2, 2)))]) for n in range(6)] # long time + sage: [len([p for p in Posets(n) # long time + ....: if p.is_incomparable_chain_free(((3, 1), (2, 2)))]) + ....: for n in range(6)] [1, 1, 2, 5, 14, 42] sage: Q = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) sage: Q.is_incomparable_chain_free(2, 20/10) True - sage: Q.is_incomparable_chain_free(2, pi) + sage: Q.is_incomparable_chain_free(2, pi) # needs sage.symbolic Traceback (most recent call last): ... TypeError: 2 and pi must be integers @@ -3617,7 +3633,7 @@ def dimension(self, certificate=False, *, solver=None, integrality_tolerance=1e- P = Poset(self._hasse_diagram) # work on an int-labelled poset hasse_diagram = P.hasse_diagram() inc_graph = P.incomparability_graph() - inc_P = inc_graph.edges(sort=True, labels=False) + inc_P = inc_graph.edges(sort=False, labels=False) # cycles is the list of all cycles found during the execution of the # algorithm @@ -3701,6 +3717,7 @@ def magnitude(self) -> Integer: EXAMPLES:: + sage: # needs sage.groups sage.libs.flint sage: P = posets.PentagonPoset() sage: P.magnitude() 1 @@ -3718,6 +3735,7 @@ def magnitude(self) -> Integer: TESTS:: + sage: # needs sage.groups sage.libs.flint sage: P1 = posets.RandomPoset(20, 0.05) sage: P2 = posets.RandomPoset(20, 0.05) sage: m1 = P1.magnitude() @@ -4214,20 +4232,20 @@ def moebius_function_matrix(self, ring=ZZ, sparse=False): sage: x,y = (P.linear_extension()[0],P.linear_extension()[1]) sage: P.moebius_function(x,y) -1 - sage: M = P.moebius_function_matrix(); M + sage: M = P.moebius_function_matrix(); M # needs sage.libs.flint [ 1 -1 -1 -1 2] [ 0 1 0 0 -1] [ 0 0 1 0 -1] [ 0 0 0 1 -1] [ 0 0 0 0 1] - sage: M[0,4] + sage: M[0,4] # needs sage.libs.flint 2 - sage: M[0,1] + sage: M[0,1] # needs sage.libs.flint -1 We now demonstrate the usage of the optional parameters:: - sage: P.moebius_function_matrix(ring=QQ, sparse=False).parent() + sage: P.moebius_function_matrix(ring=QQ, sparse=False).parent() # needs sage.libs.flint Full MatrixSpace of 5 by 5 dense matrices over Rational Field """ M = self._hasse_diagram.moebius_function_matrix() @@ -4251,7 +4269,7 @@ def lequal_matrix(self, ring=ZZ, sparse=False): EXAMPLES:: - sage: P = Poset([[1,3,2],[4],[4,5,6],[6],[7],[7],[7],[]], facade = False) + sage: P = Poset([[1,3,2],[4],[4,5,6],[6],[7],[7],[7],[]], facade=False) sage: LEQM = P.lequal_matrix(); LEQM [1 1 1 1 1 1 1 1] [0 1 0 1 0 0 0 1] @@ -4272,7 +4290,7 @@ def lequal_matrix(self, ring=ZZ, sparse=False): We now demonstrate the usage of the optional parameters:: - sage: P.lequal_matrix(ring=QQ, sparse=False).parent() + sage: P.lequal_matrix(ring=QQ, sparse=False).parent() # needs sage.libs.flint Full MatrixSpace of 8 by 8 dense matrices over Rational Field """ M = self._hasse_diagram.lequal_matrix(boolean=False) @@ -4335,8 +4353,8 @@ def coxeter_polynomial(self): sage: P.coxeter_polynomial() x^5 + x^4 + x + 1 - sage: p = posets.SymmetricGroupWeakOrderPoset(3) - sage: p.coxeter_polynomial() + sage: p = posets.SymmetricGroupWeakOrderPoset(3) # needs sage.groups + sage: p.coxeter_polynomial() # needs sage.groups x^6 + x^5 - x^3 + x + 1 .. SEEALSO:: @@ -4372,11 +4390,11 @@ def coxeter_smith_form(self, algorithm='singular'): EXAMPLES:: sage: P = posets.PentagonPoset() - sage: P.coxeter_smith_form() + sage: P.coxeter_smith_form() # needs sage.libs.singular [1, 1, 1, 1, x^5 + x^4 + x + 1] sage: P = posets.DiamondPoset(7) - sage: prod(P.coxeter_smith_form()) == P.coxeter_polynomial() + sage: prod(P.coxeter_smith_form()) == P.coxeter_polynomial() # needs sage.libs.singular True TESTS:: @@ -4384,15 +4402,15 @@ def coxeter_smith_form(self, algorithm='singular'): sage: P = posets.PentagonPoset() sage: P.coxeter_smith_form(algorithm='sage') [1, 1, 1, 1, x^5 + x^4 + x + 1] - sage: P.coxeter_smith_form(algorithm='gap') + sage: P.coxeter_smith_form(algorithm='gap') # needs sage.libs.gap [1, 1, 1, 1, x^5 + x^4 + x + 1] - sage: P.coxeter_smith_form(algorithm='pari') + sage: P.coxeter_smith_form(algorithm='pari') # needs sage.libs.pari [1, 1, 1, 1, x^5 + x^4 + x + 1] - sage: P.coxeter_smith_form(algorithm='fricas') # optional - fricas + sage: P.coxeter_smith_form(algorithm='fricas') # optional - fricas [1, 1, 1, 1, x^5 + x^4 + x + 1] - sage: P.coxeter_smith_form(algorithm='maple') # optional - maple + sage: P.coxeter_smith_form(algorithm='maple') # optional - maple [1, 1, 1, 1, x^5 + x^4 + x + 1] - sage: P.coxeter_smith_form(algorithm='magma') # optional - magma + sage: P.coxeter_smith_form(algorithm='magma') # optional - magma [1, 1, 1, 1, x^5 + x^4 + x + 1] .. SEEALSO:: @@ -4475,8 +4493,8 @@ def is_meet_semilattice(self, certificate=False): sage: Q.is_meet_semilattice() False - sage: V = posets.IntegerPartitions(5) - sage: V.is_meet_semilattice(certificate=True) + sage: V = posets.IntegerPartitions(5) # needs sage.combinat + sage: V.is_meet_semilattice(certificate=True) # needs sage.combinat (False, ((2, 2, 1), (3, 1, 1))) .. SEEALSO:: @@ -4928,7 +4946,9 @@ def chains(self, element_constructor=type([]), exclude=None): sage: C = posets.PentagonPoset().chains(); C Set of chains of Finite lattice containing 5 elements sage: list(C) - [[], [0], [0, 1], [0, 1, 4], [0, 2], [0, 2, 3], [0, 2, 3, 4], [0, 2, 4], [0, 3], [0, 3, 4], [0, 4], [1], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]] + [[], [0], [0, 1], [0, 1, 4], [0, 2], [0, 2, 3], [0, 2, 3, 4], [0, 2, 4], + [0, 3], [0, 3, 4], [0, 4], [1], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4], + [3], [3, 4], [4]] Exclusion of elements, tuple (instead of list) as constructor:: @@ -4943,7 +4963,7 @@ def chains(self, element_constructor=type([]), exclude=None): Eventually the following syntax will be accepted:: - sage: C.subset(size = 2) # todo: not implemented + sage: C.subset(size = 2) # not implemented .. SEEALSO:: :meth:`maximal_chains`, :meth:`antichains` """ @@ -5277,7 +5297,6 @@ def factor(self): Discrete Applied Mathematics 15 (1986) 105-110 :doi:`10.1016/0166-218X(86)90023-5` """ - from sage.misc.mrange import cartesian_product_iterator from sage.graphs.graph import Graph from sage.misc.flatten import flatten dg = self._hasse_diagram @@ -5304,11 +5323,11 @@ def edge_color(va, vb): for i0, i1 in Subsets(factors_range, 2): for x in prod_dg: - neigh0 = [y for y in prod_dg.neighbors(x) + neigh0 = [y for y in prod_dg.neighbor_iterator(x) if edge_color(x, y) == i0] - neigh1 = [z for z in prod_dg.neighbors(x) + neigh1 = [z for z in prod_dg.neighbor_iterator(x) if edge_color(x, z) == i1] - for x0, x1 in cartesian_product_iterator([neigh0, neigh1]): + for x0, x1 in product(neigh0, neigh1): x2 = list(x0) x2[i1] = x1[i1] x2 = tuple(x2) @@ -5325,7 +5344,7 @@ def edge_color(va, vb): fusion = fusion.transitive_closure() resu = [] - for s in fusion.connected_components(): + for s in fusion.connected_components(sort=False): subg = [x for x in prod_dg if all(x[i] == v0[i] for i in factors_range if i not in s)] resu.append(Poset(prod_dg.subgraph(subg))) @@ -5630,7 +5649,7 @@ def star_product(self, other, labels='pairs'): sage: B3 = posets.BooleanLattice(3) sage: P = B2.star_product(B3); P Finite poset containing 10 elements - sage: P.is_eulerian() + sage: P.is_eulerian() # needs sage.libs.flint True We can get elements as pairs or as integers:: @@ -5721,7 +5740,8 @@ def lexicographic_sum(self, P): EXAMPLES:: sage: N = Poset({1: [3, 4], 2: [4]}) - sage: P = {1: posets.PentagonPoset(), 2: N, 3: posets.ChainPoset(3), 4: posets.AntichainPoset(4)} + sage: P = {1: posets.PentagonPoset(), 2: N, + ....: 3: posets.ChainPoset(3), 4: posets.AntichainPoset(4)} sage: NP = N.lexicographic_sum(P); NP Finite poset containing 16 elements sage: sorted(NP.minimal_elements()) @@ -5987,7 +6007,7 @@ def without_bounds(self): This is useful as an input for the method :meth:`order_complex`. If there is either no top or no bottom element, this - raises a ``TypeError``. + raises a :class:`TypeError`. EXAMPLES:: @@ -6145,7 +6165,8 @@ def relabel(self, relabeling=None): True """ from sage.combinat.posets.lattices import (FiniteLatticePoset, - FiniteMeetSemilattice, FiniteJoinSemilattice) + FiniteMeetSemilattice, + FiniteJoinSemilattice) if isinstance(self, FiniteLatticePoset): constructor = FiniteLatticePoset @@ -6406,8 +6427,8 @@ def random_subposet(self, p): TESTS:: - sage: P = posets.IntegerPartitions(4) - sage: P.random_subposet(1) == P + sage: P = posets.IntegerPartitions(4) # needs sage.combinat + sage: P.random_subposet(1) == P # needs sage.combinat True """ from sage.misc.randstate import current_randstate @@ -6702,12 +6723,14 @@ def order_ideal_plot(self, elements): EXAMPLES:: + sage: # needs sage.plot sage: P = Poset((divisors(1000), attrcall("divides"))) sage: P.order_ideal_plot([20, 25]) Graphics object consisting of 41 graphics primitives TESTS:: + sage: # needs sage.plot sage: P = Poset() # Test empty poset sage: P.order_ideal_plot([]) Graphics object consisting of 0 graphics primitives @@ -6750,7 +6773,7 @@ def interval(self, x, y): """ return [self._vertex_to_element(w) for w in self._hasse_diagram.interval( - self._element_to_vertex(x), self._element_to_vertex(y))] + self._element_to_vertex(x), self._element_to_vertex(y))] def closed_interval(self, x, y): r""" @@ -7137,22 +7160,22 @@ def order_polytope(self): EXAMPLES:: sage: P = posets.AntichainPoset(3) - sage: Q = P.order_polytope();Q + sage: Q = P.order_polytope(); Q # needs sage.geometry.polyhedron A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices sage: P = posets.PentagonPoset() - sage: Q = P.order_polytope();Q + sage: Q = P.order_polytope(); Q # needs sage.geometry.polyhedron A 5-dimensional polyhedron in ZZ^5 defined as the convex hull of 8 vertices sage: P = Poset([[1,2,3],[[1,2],[1,3]]]) - sage: Q = P.order_polytope() - sage: Q.contains((1,0,0)) + sage: Q = P.order_polytope() # needs sage.geometry.polyhedron + sage: Q.contains((1,0,0)) # needs sage.geometry.polyhedron False - sage: Q.contains((0,1,1)) + sage: Q.contains((0,1,1)) # needs sage.geometry.polyhedron True """ from sage.geometry.polyhedron.constructor import Polyhedron ineqs = [[0] + [ZZ(j == v) - ZZ(j == u) for j in self] - for u, v, w in self.hasse_diagram().edges(sort=True)] + for u, v in self.hasse_diagram().edges(sort=False, labels=False)] for i in self.maximal_elements(): ineqs += [[1] + [-ZZ(j == i) for j in self]] for i in self.minimal_elements(): @@ -7183,15 +7206,15 @@ def chain_polytope(self): EXAMPLES:: sage: P = posets.AntichainPoset(3) - sage: Q = P.chain_polytope();Q + sage: Q = P.chain_polytope();Q # needs sage.geometry.polyhedron A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices sage: P = posets.PentagonPoset() - sage: Q = P.chain_polytope();Q + sage: Q = P.chain_polytope();Q # needs sage.geometry.polyhedron A 5-dimensional polyhedron in ZZ^5 defined as the convex hull of 8 vertices """ from sage.geometry.polyhedron.constructor import Polyhedron ineqs = [[1] + [-ZZ(j in chain) for j in self] - for chain in self.maximal_chains_iterator()] + for chain in self.maximal_chains_iterator()] for i in self: ineqs += [[0] + [ZZ(j == i) for j in self]] return Polyhedron(ieqs=ineqs, base_ring=ZZ) @@ -7279,13 +7302,13 @@ def M_triangle(self): EXAMPLES:: sage: P = posets.DiamondPoset(5) - sage: P.M_triangle() + sage: P.M_triangle() # needs sage.combinat M: x^2*y^2 - 3*x*y^2 + 3*x*y + 2*y^2 - 3*y + 1 TESTS:: sage: P = posets.PentagonPoset() - sage: P.M_triangle() + sage: P.M_triangle() # needs sage.combinat Traceback (most recent call last): ... ValueError: the poset is not graded @@ -7295,10 +7318,10 @@ def M_triangle(self): rk = hasse.rank_function() if rk is None: raise ValueError('the poset is not graded') - x, y = polygen(ZZ, 'x,y') - p = sum(hasse.moebius_function(a, b) * x**rk(a) * y**rk(b) - for a in hasse - for b in hasse.principal_order_filter(a)) + ring = PolynomialRing(ZZ, 'x,y') + p = ring.sum(hasse.moebius_function(a, b) * ring.monomial(rk(a), rk(b)) + for a in hasse + for b in hasse.principal_order_filter(a)) return M_triangle(p) def f_polynomial(self): @@ -7407,6 +7430,7 @@ def h_polynomial(self): :meth:`sage.topology.simplicial_complex.SimplicialComplex.h_vector` """ q = polygen(ZZ, 'q') + ring = q.parent() hasse = self._hasse_diagram if len(hasse) == 1: return q.parent().one() @@ -7414,10 +7438,11 @@ def h_polynomial(self): mini = hasse.bottom() if (mini is None) or (maxi is None): raise ValueError("the poset is not bounded") - f = sum(q**(len(ch)) for ch in hasse.chains(exclude=[mini, maxi])) + f = ring.sum(ring.monomial(len(ch)) + for ch in hasse.chains(exclude=[mini, maxi])) d = f.degree() f = (1 - q)**d * q * f(q=q / (1 - q)) - return q.parent(f) + return ring(f) def flag_f_polynomial(self): r""" @@ -7607,16 +7632,16 @@ def characteristic_polynomial(self): sage: P.characteristic_polynomial() 1 """ - hasse = self._hasse_diagram - rk = hasse.rank_function() + H = self._hasse_diagram + rk = H.rank_function() if not self.is_graded(): raise ValueError("the poset is not graded") if not self.has_bottom(): - raise ValueError("the poset has not a bottom element") - n = rk(hasse.maximal_elements()[0]) - x0 = hasse.minimal_elements()[0] - q = polygen(ZZ, 'q') - return sum(hasse.moebius_function(x0, x) * q**(n - rk(x)) for x in hasse) + raise ValueError("the poset does not have a bottom element") + n = rk(H.maximal_elements()[0]) + ring = PolynomialRing(ZZ, 'q') + return ring.sum(H.bottom_moebius_function(x) * ring.monomial(n - rk(x)) + for x in H) def chain_polynomial(self): """ @@ -7965,6 +7990,7 @@ def is_slender(self, certificate=False): sage: P.is_slender() False + sage: # needs sage.groups sage: W = WeylGroup(['A', 2]) sage: G = W.bruhat_poset() sage: G.is_slender() @@ -7974,8 +8000,8 @@ def is_slender(self, certificate=False): sage: G.is_slender() True - sage: P = posets.IntegerPartitions(6) - sage: P.is_slender(certificate=True) + sage: P = posets.IntegerPartitions(6) # needs sage.combinat + sage: P.is_slender(certificate=True) # needs sage.combinat (False, ((6,), (3, 2, 1))) TESTS:: @@ -8019,7 +8045,7 @@ def is_sperner(self): EXAMPLES:: - sage: posets.SetPartitions(3).is_sperner() + sage: posets.SetPartitions(3).is_sperner() # needs sage.combinat True sage: P = Poset({0:[3,4,5],1:[5],2:[5]}) @@ -8085,8 +8111,8 @@ def is_eulerian(self, k=None, certificate=False): Canonical examples of Eulerian posets are the face lattices of convex polytopes:: - sage: P = polytopes.cube().face_lattice() - sage: P.is_eulerian() + sage: P = polytopes.cube().face_lattice() # needs sage.geometry.polyhedron + sage: P.is_eulerian() # needs sage.geometry.polyhedron True A poset that is 3- but not 4-eulerian:: @@ -8337,14 +8363,13 @@ def frank_network(self): - Darij Grinberg (2013-05-09) """ - from sage.graphs.digraph import DiGraph P0 = [(0, i) for i in self] pdict = {(-1, 0): P0, (2, 0): []} for i in self: pdict[(0, i)] = [(1, j) for j in self if self.ge(i, j)] pdict[(1, i)] = [(2, 0)] G = DiGraph(pdict, format="dict_of_lists") - a = {(u, v): 0 for (u, v, l) in G.edge_iterator()} + a = {e: 0 for e in G.edge_iterator(labels=False)} for i in self: a[((0, i), (1, i))] = 1 return (G, a) @@ -8365,13 +8390,15 @@ def greene_shape(self): EXAMPLES:: - sage: P = Poset([[3,2,1],[[3,1],[2,1]]]) + sage: # needs sage.combinat + sage: P = Poset([[3,2,1], [[3,1],[2,1]]]) sage: P.greene_shape() [2, 1] - sage: P = Poset([[1,2,3,4],[[1,4],[2,4],[4,3]]]) + sage: P = Poset([[1,2,3,4], [[1,4],[2,4],[4,3]]]) sage: P.greene_shape() [3, 1] - sage: P = Poset([[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22],[[1,4],[2,4],[4,3]]]) + sage: P = Poset([[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22], + ....: [[1,4],[2,4],[4,3]]]) sage: P.greene_shape() [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] sage: P = Poset([[],[]]) @@ -8383,15 +8410,15 @@ def greene_shape(self): - Darij Grinberg (2013-05-09) """ from sage.combinat.partition import Partition - (G, a) = self.frank_network() + G, a = self.frank_network() n = len(self) chron = _ford_fulkerson_chronicle(G, (-1, 0), (2, 0), a) size = 0 ps = [] part = 0 - (pold, vold) = (0, 0) + pold, vold = (0, 0) while size != n: - (p, v) = next(chron) + p, v = next(chron) if v > vold: size += p if part > 0: @@ -8458,34 +8485,42 @@ def p_partition_enumerator(self, tup, R, weights=None, check=False): EXAMPLES:: sage: P = Poset([[1,2,3,4],[[1,4],[2,4],[4,3]]]) - sage: FP = P.p_partition_enumerator((3,1,2,4), QQ, check=True); FP + sage: FP = P.p_partition_enumerator((3,1,2,4), QQ, check=True); FP # needs sage.combinat 2*M[1, 1, 1, 1] + 2*M[1, 2, 1] + M[2, 1, 1] + M[3, 1] - sage: expansion = FP.expand(5) - sage: xs = expansion.parent().gens() - sage: expansion == sum([xs[a]*xs[b]*xs[c]*xs[d] for a in range(5) for b in range(5) for c in range(5) for d in range(5) if a <= b and c <= b and b < d]) + sage: expansion = FP.expand(5) # needs sage.combinat + sage: xs = expansion.parent().gens() # needs sage.combinat + sage: expansion == sum(xs[a]*xs[b]*xs[c]*xs[d] # needs sage.combinat + ....: for a in range(5) for b in range(5) + ....: for c in range(5) for d in range(5) + ....: if a <= b and c <= b and b < d) True sage: P = Poset([[],[]]) - sage: FP = P.p_partition_enumerator((), QQ, check=True); FP + sage: FP = P.p_partition_enumerator((), QQ, check=True); FP # needs sage.combinat M[] With the ``weights`` parameter:: sage: P = Poset([[1,2,3,4],[[1,4],[2,4],[4,3]]]) - sage: FP = P.p_partition_enumerator((3,1,2,4), QQ, weights={1: 1, 2: 2, 3: 1, 4: 1}, check=True); FP + sage: FP = P.p_partition_enumerator((3,1,2,4), QQ, # needs sage.combinat + ....: weights={1: 1, 2: 2, 3: 1, 4: 1}, check=True); FP M[1, 2, 1, 1] + M[1, 3, 1] + M[2, 1, 1, 1] + M[2, 2, 1] + M[3, 1, 1] + M[4, 1] - sage: FP = P.p_partition_enumerator((3,1,2,4), QQ, weights={2: 2}, check=True); FP + sage: FP = P.p_partition_enumerator((3,1,2,4), QQ, # needs sage.combinat + ....: weights={2: 2}, check=True); FP M[1, 2, 1, 1] + M[1, 3, 1] + M[2, 1, 1, 1] + M[2, 2, 1] + M[3, 1, 1] + M[4, 1] sage: P = Poset([['a','b','c'], [['a','b'], ['a','c']]]) - sage: FP = P.p_partition_enumerator(('b','c','a'), QQ, weights={'a': 3, 'b': 5, 'c': 7}, check=True); FP + sage: FP = P.p_partition_enumerator(('b','c','a'), QQ, # needs sage.combinat + ....: weights={'a': 3, 'b': 5, 'c': 7}, check=True); FP M[3, 5, 7] + M[3, 7, 5] + M[3, 12] sage: P = Poset([['a','b','c'], [['a','c'], ['b','c']]]) - sage: FP = P.p_partition_enumerator(('b','c','a'), QQ, weights={'a': 3, 'b': 5, 'c': 7}, check=True); FP + sage: FP = P.p_partition_enumerator(('b','c','a'), QQ, # needs sage.combinat + ....: weights={'a': 3, 'b': 5, 'c': 7}, check=True); FP M[3, 5, 7] + M[3, 12] + M[5, 3, 7] + M[8, 7] - sage: FP = P.p_partition_enumerator(('a','b','c'), QQ, weights={'a': 3, 'b': 5, 'c': 7}, check=True); FP + sage: FP = P.p_partition_enumerator(('a','b','c'), QQ, # needs sage.combinat + ....: weights={'a': 3, 'b': 5, 'c': 7}, check=True); FP M[3, 5, 7] + M[3, 12] + M[5, 3, 7] + M[5, 10] + M[8, 7] + M[15] """ if check: @@ -8729,7 +8764,7 @@ def kazhdan_lusztig_polynomial(self, x=None, y=None, q=None, canonical_labels=No sage: y = '3421' sage: L.kazhdan_lusztig_polynomial(x, y) -q + 1 - sage: L.kazhdan_lusztig_polynomial(x, y, var('t')) + sage: L.kazhdan_lusztig_polynomial(x, y, var('t')) # needs sage.symbolic -t + 1 AUTHORS: @@ -8810,11 +8845,11 @@ def _libgap_(self): EXAMPLES:: sage: P = posets.TamariLattice(3) - sage: libgap(P) # optional - gap_packages + sage: libgap(P) # optional - gap_package_qpa <A poset on 5 points> - sage: A = libgap(GF(2)).PosetAlgebra(P); A # optional - gap_packages - <GF(2)[<quiver with 5 vertices and 5 arrows>]/<two-sided ideal in <GF(2)[<quiver with 5 vertices and 5 arrows>]>, (1 generators)>> - sage: A.Dimension() # optional - gap_packages + sage: A = libgap(GF(2)).PosetAlgebra(P); A # optional - gap_package_qpa + <GF(2)[<quiver with 5 vertices and 5 arrows>]/<two-sided ideal in <GF(2)[<quiver with 5 vertices and 5 arrows>]>, (1 generator)>> + sage: A.Dimension() # optional - gap_package_qpa 13 """ from sage.libs.gap.libgap import libgap @@ -8954,8 +8989,8 @@ def cardinality(self, from_iterator=False): # Obtained from The On-Line Encyclopedia of Integer Sequences; # this is sequence number A000112. known_values = [1, 1, 2, 5, 16, 63, 318, 2045, 16999, 183231, - 2567284, 46749427, 1104891746, 33823827452, 1338193159771, - 68275077901156, 4483130665195087] + 2567284, 46749427, 1104891746, 33823827452, 1338193159771, + 68275077901156, 4483130665195087] if not from_iterator and self._n < len(known_values): return Integer(known_values[self._n]) else: @@ -9072,22 +9107,20 @@ def _ford_fulkerson_chronicle(G, s, t, a): sage: next(ffc) (11, 2) """ - from sage.graphs.digraph import DiGraph - # pi: potential function as a dictionary. - pi = {v: 0 for v in G.vertex_iterator()} + pi = {v: 0 for v in G} # p: value of the potential pi. p = 0 # f: flow function as a dictionary. - f = {(u, v): 0 for (u, v, l) in G.edge_iterator()} + f = {edge: 0 for edge in G.edge_iterator(labels=False)} # val: value of the flow f. (Cannot call it v due to Python's asinine # handling of for loops.) val = 0 # capacity: capacity function as a dictionary. Here, just the # indicator function of the set of arcs of G. - capacity = {(u, v): 1 for (u, v, l) in G.edge_iterator()} + capacity = {edge: 1 for edge in G.edge_iterator(labels=False)} while True: @@ -9095,30 +9128,29 @@ def _ford_fulkerson_chronicle(G, s, t, a): # Gprime: directed graph G' from Britz-Fomin, Section 7. Gprime = DiGraph() - Gprime.add_vertices(G.vertices(sort=False)) - for (u, v, l) in G.edge_iterator(): + Gprime.add_vertices(G) + for u, v in G.edge_iterator(labels=False): if pi[v] - pi[u] == a[(u, v)]: if f[(u, v)] < capacity[(u, v)]: Gprime.add_edge(u, v) elif f[(u, v)] > 0: Gprime.add_edge(v, u) - # X: list of vertices of G' reachable from s, along with - # the shortest paths from s to them. - X = Gprime.shortest_paths(s) + # X: list of vertices of G' reachable from s + X = set(Gprime.depth_first_search(s)) if t in X: # Step MC2a in Britz-Fomin, Algorithm 7.2. - shortest_path = X[t] + shortest_path = Gprime.shortest_path(s, t, by_weight=False) shortest_path_in_edges = zip(shortest_path[:-1], shortest_path[1:]) - for (u, v) in shortest_path_in_edges: - if v in G.neighbors_out(u): + for u, v in shortest_path_in_edges: + if v in G.neighbor_out_iterator(u): f[(u, v)] += 1 else: f[(v, u)] -= 1 val += 1 else: # Step MC2b in Britz-Fomin, Algorithm 7.2. - for v in G.vertex_iterator(): + for v in G: if v not in X: pi[v] += 1 p += 1 diff --git a/src/sage/combinat/q_analogues.py b/src/sage/combinat/q_analogues.py index 0b204630b93..541fc98353c 100644 --- a/src/sage/combinat/q_analogues.py +++ b/src/sage/combinat/q_analogues.py @@ -248,18 +248,18 @@ def q_binomial(n, k, q=None, algorithm='auto'): This also works for variables in the symbolic ring:: - sage: z = var('z') - sage: factor(q_binomial(4, 2, z)) + sage: z = var('z') # optional - sage.symbolic + sage: factor(q_binomial(4, 2, z)) # optional - sage.symbolic (z^2 + z + 1)*(z^2 + 1) This also works for complex roots of unity:: - sage: q_binomial(10, 4, QQbar(I)) + sage: q_binomial(10, 4, QQbar(I)) # optional - sage.rings.number_field 2 Note that the symbolic computation works (see :trac:`14982`):: - sage: q_binomial(10, 4, I) + sage: q_binomial(10, 4, I) # optional - sage.rings.number_field 2 Check that the algorithm does not matter:: @@ -578,7 +578,7 @@ def q_pochhammer(n, a, q=None): 1 sage: q_pochhammer(0, 1) 1 - sage: q_pochhammer(0, var('a')) + sage: q_pochhammer(0, var('a')) # optional - sage.symbolic 1 We check that :trac:`25715` is fixed:: @@ -637,7 +637,7 @@ def q_jordan(t, q=None): [615195, 40635, 5643, 2331, 1491, 515, 147, 87, 47, 11, 1] sage: q_jordan([3,2,1]) 16*q^4 + 24*q^3 + 14*q^2 + 5*q + 1 - sage: q_jordan([2,1], x) + sage: q_jordan([2,1], x) # optional - sage.symbolic 2*x + 1 If the partition is trivial (i.e. has only one part), we get diff --git a/src/sage/combinat/quickref.py b/src/sage/combinat/quickref.py index ea2aba8915a..351563cec6c 100644 --- a/src/sage/combinat/quickref.py +++ b/src/sage/combinat/quickref.py @@ -46,7 +46,7 @@ sage: points = random_matrix(ZZ, 6, 3, x=7).rows() sage: L = LatticePolytope(points) - sage: L.npoints(); L.plot3d() # random + sage: L.npoints(); L.plot3d() # random # optional - sage.plot :ref:`Root systems, Coxeter and Weyl groups <sage.combinat.root_system.all>`:: diff --git a/src/sage/combinat/ranker.py b/src/sage/combinat/ranker.py index f1e8928f73e..6d7fb2998a2 100644 --- a/src/sage/combinat/ranker.py +++ b/src/sage/combinat/ranker.py @@ -207,7 +207,7 @@ def unrank(L, i): Enumerated sets:: - sage: unrank(GF(7), 2) + sage: unrank(GF(7), 2) # optional - sage.rings.finite_rings 2 sage: unrank(IntegerModRing(29), 10) 10 @@ -267,4 +267,4 @@ def unrank(L, i): return next(it) except StopIteration: raise IndexError("index out of range") - raise ValueError("Don't know how to unrank on {}".format(L)) + raise ValueError("do not know how to unrank on {}".format(L)) diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index 7f1f03aba06..ca2f11bd6ff 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Recognizable Series @@ -26,27 +27,13 @@ In particular, minimization is called before checking if a series is nonzero. -.. WARNING:: - - As this code is experimental, warnings are thrown when a - recognizable series space is created for the first time in a - session (see :class:`sage.misc.superseded.experimental`). - - TESTS:: - - sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1]) - doctest:...: FutureWarning: This class/method/function is - marked as experimental. It, its functionality or its interface - might change without a formal deprecation. - See https://github.com/sagemath/sage/issues/21202 for details. - Various ======= .. SEEALSO:: - :mod:`k-regular sequence <sage.combinat.k_regular_sequence>`, + :mod:`k-regular sequence <sage.combinat.regular_sequence>`, :mod:`sage.rings.cfinite_sequence`, :mod:`sage.combinat.binary_recurrence_sequences`. @@ -65,20 +52,19 @@ Classes and Methods =================== """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Daniel Krenn <dev@danielkrenn.at> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from functools import wraps from sage.misc.cachefunc import cached_method -from sage.misc.superseded import experimental from sage.structure.element import ModuleElement from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -180,13 +166,13 @@ def add(self, w, check=True): sage: P.add(W([1, 1])) Traceback (most recent call last): ... - ValueError: Cannot add as not all prefixes of 11 are included yet. + ValueError: cannot add as not all prefixes of 11 are included yet """ if check and any(p not in self.elements for p in w.prefixes_iterator() if p != w): - raise ValueError('Cannot add as not all prefixes of ' - '{} are included yet.'.format(w)) + raise ValueError('cannot add as not all prefixes of ' + '{} are included yet'.format(w)) self.elements.append(w) def iterate_possible_additions(self): @@ -263,7 +249,7 @@ def iterate_possible_additions(self): while n < len(self.elements): try: nn = next(it) - yield self.elements[n] + nn #next(it) + yield self.elements[n] + nn # next(it) except StopIteration: n += 1 it = self.words.iterate_by_length(1) @@ -317,6 +303,12 @@ def minimize_result(operation): if ``False``, then not. If this argument is ``None``, then the default specified by the parent's ``minimize_results`` is used. + .. NOTE:: + + If the result of ``operation`` is ``self``, then minimization is + not applied unless ``minimize=True`` is explicitly set, + in particular, independent of the parent's ``minimize_results``. + TESTS:: sage: from sage.combinat.recognizable_series import minimize_result @@ -351,14 +343,39 @@ def minimize_result(operation): some result minimized sage: S('some').operation(minimize=False) some result + + :: + + sage: class T(S): + ....: @minimize_result + ....: def nooperation(self): + ....: return self + sage: t = T('some') + sage: p.minimize_results = True + sage: t.nooperation() is t + True + sage: t.nooperation(minimize=True) is t + False + sage: t.nooperation(minimize=False) is t + True + sage: p.minimize_results = False + sage: t.nooperation() is t + True + sage: t.nooperation(minimize=True) is t + False + sage: t.nooperation(minimize=False) is t + True """ @wraps(operation) def minimized(self, *args, **kwds): minimize = kwds.pop('minimize', None) - if minimize is None: - minimize = self.parent().minimize_results result = operation(self, *args, **kwds) + if minimize is not True and result is self: + return result + + if minimize is None: + minimize = self.parent().minimize_results if minimize: result = result.minimized() @@ -441,6 +458,7 @@ def __init__(self, parent, mu, left, right): super(RecognizableSeries, self).__init__(parent=parent) from copy import copy + from sage.matrix.constructor import Matrix from sage.modules.free_module_element import vector from sage.sets.family import Family @@ -456,11 +474,11 @@ def immutable(m): return m if isinstance(mu, dict): - mu = dict((a, immutable(M)) for a, M in mu.items()) + mu = {a: Matrix(M, immutable=True) for a, M in mu.items()} mu = Family(mu) if not mu.is_finite(): - raise NotImplementedError('mu is not a finite family of matrices.') + raise NotImplementedError('mu is not a finite family of matrices') self._left_ = immutable(vector(left)) self._mu_ = mu @@ -753,11 +771,11 @@ def _mu_of_word_(self, w): sage: S._mu_of_word_(-1) Traceback (most recent call last): ... - ValueError: Index -1 is not in Finite words over {0, 1}. + ValueError: index -1 is not in Finite words over {0, 1} """ W = self.parent().indices() if w not in W: - raise ValueError('Index {} is not in {}.'.format(w, W)) + raise ValueError('index {} is not in {}'.format(w, W)) from sage.misc.misc_c import prod return prod((self.mu[a] for a in w), z=self._mu_of_empty_word_()) @@ -1043,9 +1061,11 @@ def tr(M): T = M.transpose() T.set_immutable() return T - return self.parent()(self.mu.map(tr), - left=self.right, - right=self.left) + + P = self.parent() + return P.element_class(P, self.mu.map(tr), + left=self.right, + right=self.left) @cached_method def minimized(self): @@ -1105,6 +1125,12 @@ def minimized(self): sage: all(c == d and v == w ....: for (c, v), (d, w) in islice(zip(iter(S), iter(M)), 20)) True + + TESTS:: + + sage: Rec((Matrix([[0]]), Matrix([[0]])), + ....: vector([1]), vector([0])).minimized().linear_representation() + ((), Finite family {0: [], 1: []}, ()) """ return self._minimized_right_()._minimized_left_() @@ -1211,11 +1237,11 @@ def alpha(c): mu_prime = [] for a in self.parent().alphabet(): a = self.parent().indices()([a]) - M = Matrix([alpha(c) if c in C else tuple(ZZ(c==q) for q in P) + M = Matrix([alpha(c) if c in C else tuple(ZZ(c == q) for q in P) for c in (p + a for p in P)]) mu_prime.append(M) - left_prime = vector([ZZ(1)] + (len(P)-1)*[ZZ(0)]) + left_prime = vector([ZZ.one()] + (len(P) - 1) * [ZZ.zero()]) right_prime = vector(self.coefficient_of_word(p) for p in P) P = self.parent() @@ -1256,7 +1282,7 @@ def _add_(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: E @@ -1279,7 +1305,7 @@ def _add_(self, other): result = P.element_class( P, - dict((a, self.mu[a].block_sum(other.mu[a])) for a in P.alphabet()), + {a: self.mu[a].block_sum(other.mu[a]) for a in P.alphabet()}, vector(tuple(self.left) + tuple(other.left)), vector(tuple(self.right) + tuple(other.right))) @@ -1295,7 +1321,7 @@ def _neg_(self): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: -E @@ -1322,7 +1348,7 @@ def _rmul_(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: M = 2 * E # indirect doctest @@ -1341,6 +1367,11 @@ def _rmul_(self, other): sage: 1 * E is E True + :: + + sage: 0 * E is Seq2.zero() + True + We test that ``_rmul_`` and ``_lmul_`` are actually called:: sage: def print_name(f): @@ -1359,10 +1390,12 @@ def _rmul_(self, other): _lmul_ 2-regular sequence 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, ... """ + P = self.parent() + if other.is_zero(): + return P._zero_() if other.is_one(): return self - P = self.parent() - return P.element_class(P, self.mu, other*self.left, self.right) + return P.element_class(P, self.mu, other * self.left, self.right) def _lmul_(self, other): r""" @@ -1379,7 +1412,7 @@ def _lmul_(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: M = E * 2 # indirect doctest @@ -1398,6 +1431,11 @@ def _lmul_(self, other): sage: E * 1 is E True + :: + + sage: E * 0 is Seq2.zero() + True + The following is not tested, as `MS^i` for integers `i` does not work, thus ``vector([m])`` fails. (See :trac:`21317` for details.) @@ -1414,10 +1452,12 @@ def _lmul_(self, other): sage: M # not tested sage: M.linear_representation() # not tested """ + P = self.parent() + if other.is_zero(): + return P._zero_() if other.is_one(): return self - P = self.parent() - return P.element_class(P, self.mu, self.left, self.right*other) + return P.element_class(P, self.mu, self.left, self.right * other) @minimize_result def hadamard_product(self, other): @@ -1442,7 +1482,7 @@ def hadamard_product(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) @@ -1522,8 +1562,7 @@ def tensor_product(left, right): return T result = P.element_class( P, - dict((a, tensor_product(self.mu[a], other.mu[a])) - for a in P.alphabet()), + {a: tensor_product(self.mu[a], other.mu[a]) for a in P.alphabet()}, vector(tensor_product(Matrix(self.left), Matrix(other.left))), vector(tensor_product(Matrix(self.right), Matrix(other.right)))) @@ -1644,7 +1683,7 @@ def __normalize__(cls, sage: RecognizableSeriesSpace([0, 1], [0, 1]) Traceback (most recent call last): ... - ValueError: Coefficient ring [0, 1] is not a semiring. + ValueError: coefficient ring [0, 1] is not a semiring :: @@ -1652,42 +1691,41 @@ def __normalize__(cls, sage: RecognizableSeriesSpace(ZZ) Traceback (most recent call last): ... - ValueError: Specify either 'alphabet' or 'indices'. + ValueError: specify either 'alphabet' or 'indices' sage: RecognizableSeriesSpace(ZZ, alphabet=[0, 1], indices=W) Traceback (most recent call last): ... - ValueError: Specify either 'alphabet' or 'indices'. + ValueError: specify either 'alphabet' or 'indices' sage: RecognizableSeriesSpace(alphabet=[0, 1]) Traceback (most recent call last): ... - ValueError: No coefficient ring specified. + ValueError: no coefficient ring specified sage: RecognizableSeriesSpace(ZZ, indices=Words(ZZ)) Traceback (most recent call last): ... - NotImplementedError: Alphabet is not finite. + NotImplementedError: alphabet is not finite """ if (alphabet is None) == (indices is None): - raise ValueError("Specify either 'alphabet' or 'indices'.") + raise ValueError("specify either 'alphabet' or 'indices'") if indices is None: from sage.combinat.words.words import Words indices = Words(alphabet, infinite=False) if not indices.alphabet().is_finite(): - raise NotImplementedError('Alphabet is not finite.') + raise NotImplementedError('alphabet is not finite') if coefficient_ring is None: - raise ValueError('No coefficient ring specified.') + raise ValueError('no coefficient ring specified') from sage.categories.semirings import Semirings if coefficient_ring not in Semirings(): raise ValueError( - 'Coefficient ring {} is not a semiring.'.format(coefficient_ring)) + 'coefficient ring {} is not a semiring'.format(coefficient_ring)) from sage.categories.modules import Modules category = category or Modules(coefficient_ring) return (coefficient_ring, indices, category, minimize_results) - @experimental(issue_number=21202) def __init__(self, coefficient_ring, indices, category, minimize_results): r""" See :class:`RecognizableSeriesSpace` for details. @@ -1865,16 +1903,20 @@ def _an_element_(self): z = self.coefficient_ring().zero() o = self.coefficient_ring().one() e = self.coefficient_ring().an_element() - return self(list(Matrix([[o, z], [i*o, o]]) + return self(list(Matrix([[o, z], [i * o, o]]) for i, _ in enumerate(self.alphabet())), vector([z, e]), right=vector([e, z])) - def some_elements(self): + def some_elements(self, **kwds): r""" Return some elements of this recognizable series space. See :class:`TestSuite` for a typical use case. + INPUT: + + - ``kwds`` are passed on to the element constructor + OUTPUT: An iterator @@ -1911,7 +1953,60 @@ def some_elements(self): LR = list(islice(elements_V, 2)) if len(mu) != k or len(LR) != 2: break - yield self(mu, *LR) + yield self(mu, *LR, **kwds) + + @cached_method + def _zero_(self): + r""" + Return the zero element of this :class:`RecognizableSeriesSpace`, + i.e. the unique neutral element for `+`. + + TESTS:: + + sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1]) + sage: Z = Rec._zero_(); Z + 0 + sage: Z.linear_representation() + ((), Finite family {0: [], 1: []}, ()) + """ + from sage.matrix.constructor import Matrix + from sage.modules.free_module_element import vector + from sage.sets.family import Family + + return self.element_class( + self, Family(self.alphabet(), lambda a: Matrix()), + vector([]), vector([])) + + @cached_method + def one(self): + r""" + Return the one element of this :class:`RecognizableSeriesSpace`, + i.e. the embedding of the one of the coefficient ring into + this :class:`RecognizableSeriesSpace`. + + EXAMPLES:: + + sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1]) + sage: O = Rec.one(); O + [] + ... + sage: O.linear_representation() + ((1), Finite family {0: [0], 1: [0]}, (1)) + + TESTS:: + + sage: Rec.one() is Rec.one() + True + """ + from sage.matrix.constructor import Matrix + from sage.modules.free_module_element import vector + + R = self.coefficient_ring() + one = R.one() + zero = R.zero() + return self.element_class(self, + len(self.alphabet())*[Matrix([[zero]])], + vector([one]), + vector([one])) @cached_method def one_hadamard(self): @@ -1940,7 +2035,7 @@ def one_hadamard(self): from sage.modules.free_module_element import vector one = self.coefficient_ring()(1) - return self(dict((a, Matrix([[one]])) for a in self.alphabet()), + return self({a: Matrix([[one]]) for a in self.alphabet()}, vector([one]), vector([one])) def _element_constructor_(self, data, @@ -1967,42 +2062,53 @@ def _element_constructor_(self, data, sage: Rec(S) is S True + :: + + sage: A = Rec(42); A + 42*[] + ... + sage: A.linear_representation() + ((42), Finite family {0: [0], 1: [0]}, (1)) + sage: Z = Rec(0); Z + 0 + sage: Z.linear_representation() + ((), Finite family {0: [], 1: []}, ()) + + :: + sage: Rec((M0, M1)) Traceback (most recent call last): ... - ValueError: Left or right vector is None. + ValueError: left or right vector is None sage: Rec((M0, M1), [0, 1]) Traceback (most recent call last): ... - ValueError: Left or right vector is None. + ValueError: left or right vector is None sage: Rec((M0, M1), left=[0, 1]) Traceback (most recent call last): ... - ValueError: Left or right vector is None. + ValueError: left or right vector is None sage: Rec((M0, M1), right=[0, 1]) Traceback (most recent call last): ... - ValueError: Left or right vector is None. + ValueError: left or right vector is None """ if isinstance(data, int) and data == 0: - from sage.matrix.constructor import Matrix - from sage.modules.free_module_element import vector - from sage.sets.family import Family + return self._zero_() - return self.element_class( - self, Family(self.alphabet(), lambda a: Matrix()), - vector([]), vector([])) - - if type(data) == self.element_class and data.parent() == self: + if isinstance(data, self.element_class) and data.parent() == self: element = data elif isinstance(data, RecognizableSeries): element = self.element_class(self, data.mu, data.left, data.right) + elif data in self.coefficient_ring(): + c = self.coefficient_ring()(data) + return c * self.one() + else: mu = data if left is None or right is None: - raise ValueError('Left or right vector is None.') + raise ValueError('left or right vector is None') element = self.element_class(self, mu, left, right) diff --git a/src/sage/combinat/regular_sequence.py b/src/sage/combinat/regular_sequence.py new file mode 100644 index 00000000000..afb83bed6f7 --- /dev/null +++ b/src/sage/combinat/regular_sequence.py @@ -0,0 +1,4222 @@ +# sage.doctest: optional - sage.combinat sage.modules sage.symbolic +r""" +`k`-regular sequences + +An introduction and formal definition of `k`-regular sequences can be +found, for example, on the :wikipedia:`k-regular_sequence` or in +[AS2003]_. + +:: + + sage: import logging + sage: logging.basicConfig() + +Examples +======== + +Binary sum of digits +-------------------- + +The binary sum of digits `S(n)` of a nonnegative integer `n` satisfies +`S(2n) = S(n)` and `S(2n+1) = S(n) + 1`. We model this by the following:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), + ....: left=vector([0, 1]), right=vector([1, 0])) + sage: S + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... + sage: all(S[n] == sum(n.digits(2)) for n in srange(10)) + True + +Number of odd entries in Pascal's triangle +------------------------------------------ + +Let us consider the number of odd entries in the first `n` rows +of Pascals's triangle:: + + sage: @cached_function + ....: def u(n): + ....: if n <= 1: + ....: return n + ....: return 2 * u(n // 2) + u((n+1) // 2) + sage: tuple(u(n) for n in srange(10)) + (0, 1, 3, 5, 9, 11, 15, 19, 27, 29) + +There is a `2`-regular sequence describing the numbers above as well:: + + sage: U = Seq2((Matrix([[3, 0], [2, 1]]), Matrix([[2, 1], [0, 3]])), + ....: left=vector([1, 0]), right=vector([0, 1])) + sage: all(U[n] == u(n) for n in srange(30)) + True + + +Various +======= + +.. SEEALSO:: + + :mod:`recognizable series <sage.combinat.recognizable_series>`, + :mod:`sage.rings.cfinite_sequence`, + :mod:`sage.combinat.binary_recurrence_sequences`. + +AUTHORS: + +- Daniel Krenn (2016, 2021) +- Gabriel F. Lipnik (2021) + +ACKNOWLEDGEMENT: + +- Daniel Krenn is supported by the + Austrian Science Fund (FWF): P 24644-N26. +- Gabriel F. Lipnik is supported by the + Austrian Science Fund (FWF): W 1230. + + +Classes and Methods +=================== +""" +# **************************************************************************** +# Copyright (C) 2016 Daniel Krenn <dev@danielkrenn.at> +# 2021 Gabriel F. Lipnik <dev@gabriellipnik.at> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** +from .recognizable_series import RecognizableSeries +from .recognizable_series import RecognizableSeriesSpace +from .recognizable_series import minimize_result +from sage.misc.cachefunc import cached_function, cached_method + + +def pad_right(T, length, zero=0): + r""" + Pad ``T`` to the right by using ``zero`` to have + at least the given ``length``. + + INPUT: + + - ``T`` -- A tuple, list or other iterable + + - ``length`` -- a nonnegative integer + + - ``zero`` -- (default: ``0``) the elements to pad with + + OUTPUT: + + An object of the same type as ``T`` + + EXAMPLES:: + + sage: from sage.combinat.regular_sequence import pad_right + sage: pad_right((1, 2, 3), 10) + (1, 2, 3, 0, 0, 0, 0, 0, 0, 0) + sage: pad_right((1, 2, 3), 2) + (1, 2, 3) + sage: pad_right([(1, 2), (3, 4)], 4, (0, 0)) + [(1, 2), (3, 4), (0, 0), (0, 0)] + + TESTS:: + + sage: pad_right([1, 2, 3], 10) + [1, 2, 3, 0, 0, 0, 0, 0, 0, 0] + """ + return T + type(T)(zero for _ in range(length - len(T))) + + +def value(D, k): + r""" + Return the value of the expansion with digits `D` in base `k`, i.e. + + .. MATH:: + + \sum_{0\leq j < \operatorname{len}D} D[j] k^j. + + INPUT: + + - ``D`` -- a tuple or other iterable + + - ``k`` -- the base + + OUTPUT: + + An element in the common parent of the base `k` and of the entries + of `D` + + EXAMPLES:: + + sage: from sage.combinat.regular_sequence import value + sage: value(42.digits(7), 7) + 42 + """ + return sum(d * k**j for j, d in enumerate(D)) + + +class DegeneratedSequenceError(RuntimeError): + r""" + Exception raised if a degenerated sequence + (see :meth:`~RegularSequence.is_degenerated`) is detected. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1])) + Traceback (most recent call last): + ... + DegeneratedSequenceError: degenerated sequence: mu[0]*right != right. + Using such a sequence might lead to wrong results. + You can use 'allow_degenerated_sequence=True' followed + by a call of method .regenerated() for correcting this. + """ + pass + + +class RegularSequence(RecognizableSeries): + def __init__(self, parent, mu, left=None, right=None): + r""" + A `k`-regular sequence. + + INPUT: + + - ``parent`` -- an instance of :class:`RegularSequenceRing` + + - ``mu`` -- a family of square matrices, all of which have the + same dimension. The indices of this family are `0,...,k-1`. + ``mu`` may be a list or tuple of cardinality `k` + as well. See also + :meth:`~sage.combinat.recognizable_series.RecognizableSeries.mu`. + + - ``left`` -- (default: ``None``) a vector. + When evaluating the sequence, this vector is multiplied + from the left to the matrix product. If ``None``, then this + multiplication is skipped. + + - ``right`` -- (default: ``None``) a vector. + When evaluating the sequence, this vector is multiplied + from the right to the matrix product. If ``None``, then this + multiplication is skipped. + + When created via the parent :class:`RegularSequenceRing`, then + the following option is available. + + - ``allow_degenerated_sequence`` -- (default: ``False``) a boolean. If set, then + there will be no check if the input is a degenerated sequence + (see :meth:`is_degenerated`). + Otherwise the input is checked and a :class:`DegeneratedSequenceError` + is raised if such a sequence is detected. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: S = Seq2((Matrix([[3, 0], [6, 1]]), Matrix([[0, 1], [-6, 5]])), + ....: vector([1, 0]), vector([0, 1])); S + 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ... + + We can access the coefficients of a sequence by + :: + + sage: S[5] + 11 + + or iterating over the first, say `10`, by + :: + + sage: from itertools import islice + sage: list(islice(S, 10)) + [0, 1, 3, 5, 9, 11, 15, 19, 27, 29] + + .. SEEALSO:: + + :doc:`k-regular sequence <regular_sequence>`, + :class:`RegularSequenceRing`. + + TESTS:: + + sage: Seq2(([[1, 0], [0, 1]], [[1, 1], [0, 1]]), (1, 0), (0, 1)) + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... + """ + super().__init__(parent=parent, mu=mu, left=left, right=right) + + def _repr_(self): + r""" + Return a representation string of this `k`-regular sequence. + + OUTPUT: a string + + TESTS:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: s = Seq2((Matrix([[3, 0], [6, 1]]), Matrix([[0, 1], [-6, 5]])), + ....: vector([1, 0]), vector([0, 1])) + sage: repr(s) # indirect doctest + '2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ...' + """ + from sage.misc.lazy_list import lazy_list_formatter + return lazy_list_formatter( + self, + name='{}-regular sequence'.format(self.parent().k), + opening_delimiter='', closing_delimiter='', + preview=10) + + @cached_method + def coefficient_of_n(self, n, **kwds): + r""" + Return the `n`-th entry of this sequence. + + INPUT: + + - ``n`` -- a nonnegative integer + + OUTPUT: an element of the universe of the sequence + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])), + ....: left=vector([0, 1]), right=vector([1, 0])) + sage: S[7] + 3 + + This is equivalent to:: + + sage: S.coefficient_of_n(7) + 3 + + TESTS:: + + sage: S[-1] + Traceback (most recent call last): + ... + ValueError: value -1 of index is negative + + :: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: W = Seq2.indices() + sage: M0 = Matrix([[1, 0], [0, 1]]) + sage: M1 = Matrix([[0, -1], [1, 2]]) + sage: S = Seq2((M0, M1), vector([0, 1]), vector([1, 1])) + sage: S._mu_of_word_(W(0.digits(2))) == M0 + True + sage: S._mu_of_word_(W(1.digits(2))) == M1 + True + sage: S._mu_of_word_(W(3.digits(2))) == M1^2 + True + """ + return self.coefficient_of_word(self.parent()._n_to_index_(n), **kwds) + + __getitem__ = coefficient_of_n + + def __iter__(self): + r""" + Return an iterator over the coefficients of this sequence. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])), + ....: left=vector([0, 1]), right=vector([1, 0])) + sage: from itertools import islice + sage: tuple(islice(S, 10)) + (0, 1, 1, 2, 1, 2, 2, 3, 1, 2) + + TESTS:: + + sage: it = iter(S) + sage: iter(it) is it + True + sage: iter(S) is not it + True + """ + from itertools import count + return iter(self[n] for n in count()) + + @cached_method + def is_degenerated(self): + r""" + Return whether this `k`-regular sequence is degenerated, + i.e., whether this `k`-regular sequence does not satisfiy + `\mu[0] \mathit{right} = \mathit{right}`. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1])) # indirect doctest + Traceback (most recent call last): + ... + DegeneratedSequenceError: degenerated sequence: mu[0]*right != right. + Using such a sequence might lead to wrong results. + You can use 'allow_degenerated_sequence=True' followed + by a call of method .regenerated() for correcting this. + sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]), + ....: allow_degenerated_sequence=True) + sage: S + 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ... + sage: S.is_degenerated() + True + + :: + + sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])), + ....: vector([1, 0]), vector([0, 1])) + sage: C.is_degenerated() + False + """ + from sage.rings.integer_ring import ZZ + return (self.mu[ZZ(0)] * self.right) != self.right + + def _error_if_degenerated_(self): + r""" + Raise an error if this `k`-regular sequence is degenerated, + i.e., if this `k`-regular sequence does not satisfiy + `\mu[0] \mathit{right} = \mathit{right}`. + + TESTS:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])), # indirect doctest + ....: left=vector([0, 1]), right=vector([1, 0])) + Traceback (most recent call last): + ... + DegeneratedSequenceError: degenerated sequence: mu[0]*right != right. + Using such a sequence might lead to wrong results. + You can use 'allow_degenerated_sequence=True' followed + by a call of method .regenerated() for correcting this. + """ + if self.is_degenerated(): + raise DegeneratedSequenceError( + "degenerated sequence: mu[0]*right != right. " + "Using such a sequence might lead to wrong results. " + "You can use 'allow_degenerated_sequence=True' followed by " + "a call of method .regenerated() " + "for correcting this.") + + @cached_method + @minimize_result + def regenerated(self): + r""" + Return a `k`-regular sequence that satisfies + `\mu[0] \mathit{right} = \mathit{right}` with the same values as + this sequence. + + INPUT: + + - ``minimize`` -- (default: ``None``) a boolean or ``None``. + If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, + if ``False``, then not. If this argument is ``None``, then + the default specified by the parent's ``minimize_results`` is used. + + OUTPUT: + + A :class:`RegularSequence` + + ALGORITHM: + + Theorem B of [HKL2022]_ with `n_0 = 1`. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + + The following linear representation of `S` is chosen badly (is + degenerated, see :meth:`is_degenerated`), as `\mu(0)` applied on + `\mathit{right}` does not equal `\mathit{right}`:: + + sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]), + ....: allow_degenerated_sequence=True) + sage: S + 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ... + sage: S.is_degenerated() + True + + However, we can regenerate the sequence `S`:: + + sage: H = S.regenerated() + sage: H + 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ... + sage: H.linear_representation() + ((1, 0), + Finite family {0: [ 0 1] + [-2 3], + 1: [3 0] + [6 0]}, + (1, 1)) + sage: H.is_degenerated() + False + + TESTS:: + + sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]), + ....: allow_degenerated_sequence=True) + sage: H = S.regenerated(minimize=False) + sage: H.linear_representation() + ((1, 0), + Finite family {0: [ 2|-1] + [--+--] + [ 0| 1], + 1: [3|0] + [-+-] + [0|0]}, + (1, 1)) + sage: H.is_degenerated() + False + """ + if not self.is_degenerated(): + return self + + from sage.matrix.constructor import Matrix + from sage.matrix.special import zero_matrix, identity_matrix + from sage.modules.free_module_element import vector + + P = self.parent() + dim = self.dimension() + Zc = zero_matrix(dim, 1) + Zr = zero_matrix(1, dim) + I = identity_matrix(dim) + + itA = iter(P.alphabet()) + z = next(itA) + W0 = Matrix(dim, 1, (I - self.mu[z]) * self.right) + mu = {z: Matrix.block([[self.mu[z], W0], [Zr, 1]])} + mu.update((r, Matrix.block([[self.mu[r], Zc], [Zr, 0]])) + for r in itA) + + return P.element_class( + P, mu, + vector(tuple(self.left) + (0,)), + vector(tuple(self.right) + (1,))) + + def transposed(self, allow_degenerated_sequence=False): + r""" + Return the transposed sequence. + + INPUT: + + - ``allow_degenerated_sequence`` -- (default: ``False``) a boolean. If set, then + there will be no check if the transposed sequence is a degenerated sequence + (see :meth:`is_degenerated`). + Otherwise the transposed sequence is checked and a :class:`DegeneratedSequenceError` + is raised if such a sequence is detected. + + OUTPUT: + + A :class:`RegularSequence` + + Each of the matrices in :meth:`mu <mu>` is transposed. Additionally + the vectors :meth:`left <left>` and :meth:`right <right>` are switched. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: U = Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])), + ....: left=vector([0, 1]), right=vector([1, 0]), + ....: allow_degenerated_sequence=True) + sage: U.is_degenerated() + True + sage: Ut = U.transposed() + sage: Ut.linear_representation() + ((1, 0), + Finite family {0: [3 0] + [2 1], + 1: [2 1] + [0 3]}, + (0, 1)) + sage: Ut.is_degenerated() + False + + sage: Ut.transposed() + Traceback (most recent call last): + ... + DegeneratedSequenceError: degenerated sequence: mu[0]*right != right. + Using such a sequence might lead to wrong results. + You can use 'allow_degenerated_sequence=True' followed + by a call of method .regenerated() for correcting this. + sage: Utt = Ut.transposed(allow_degenerated_sequence=True) + sage: Utt.is_degenerated() + True + + .. SEEALSO:: + + :meth:`RecognizableSeries.transposed <sage.combinat.recognizable_series.RecognizableSeries.transposed>` + """ + element = super().transposed() + if not allow_degenerated_sequence: + element._error_if_degenerated_() + return element + + def _minimized_right_(self): + r""" + Return a regular sequence equivalent to this series, but + with a right minimized linear representation. + + OUTPUT: + + A :class:`RegularSequence` + + .. SEEALSO:: + + :meth:`RecognizableSeries._minimized_right_ <sage.combinat.recognizable_series.RecognizableSeries._minimized_right_>` + + TESTS:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: Seq2((Matrix([[3, 0], [2, 1]]), Matrix([[2, 1], [0, 3]])), # indirect doctest + ....: left=vector([1, 0]), right=vector([0, 1])).minimized() + 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ... + """ + return self.transposed(allow_degenerated_sequence=True)._minimized_left_().transposed(allow_degenerated_sequence=True) + + @minimize_result + def subsequence(self, a, b): + r""" + Return the subsequence with indices `an+b` of this + `k`-regular sequence. + + INPUT: + + - ``a`` -- a nonnegative integer + + - ``b`` -- an integer + + Alternatively, this is allowed to be a dictionary + `b_j \mapsto c_j`. If so and applied on `f(n)`, + the result will be the sum of all `c_j \cdot f(an+b_j)`. + + - ``minimize`` -- (default: ``None``) a boolean or ``None``. + If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, + if ``False``, then not. If this argument is ``None``, then + the default specified by the parent's ``minimize_results`` is used. + + OUTPUT: + + A :class:`RegularSequence` + + .. NOTE:: + + If `b` is negative (i.e., right-shift), then the + coefficients when accessing negative indices are `0`. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + + We consider the sequence `C` with `C(n) = n` and + the following linear representation + corresponding to the vector `(n, 1)`:: + + sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])), + ....: vector([1, 0]), vector([0, 1])); C + 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + + We now extract various subsequences of `C`:: + + sage: C.subsequence(2, 0) + 2-regular sequence 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, ... + + sage: S31 = C.subsequence(3, 1); S31 + 2-regular sequence 1, 4, 7, 10, 13, 16, 19, 22, 25, 28, ... + sage: S31.linear_representation() + ((1, 0), + Finite family {0: [ 0 1] + [-2 3], + 1: [ 6 -2] + [10 -3]}, + (1, 1)) + + sage: C.subsequence(3, 2) + 2-regular sequence 2, 5, 8, 11, 14, 17, 20, 23, 26, 29, ... + + :: + + sage: Srs = C.subsequence(1, -1); Srs + 2-regular sequence 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ... + sage: Srs.linear_representation() + ((1, 0, 0), + Finite family {0: [ 0 1 0] + [-2 3 0] + [-4 4 1], + 1: [ -2 2 0] + [ 0 0 1] + [ 12 -12 5]}, + (0, 0, 1)) + + We can build :meth:`backward_differences` manually by passing + a dictionary for the parameter ``b``:: + + sage: Sbd = C.subsequence(1, {0: 1, -1: -1}); Sbd + 2-regular sequence 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... + + TESTS: + + We check if the linear representation of the subsequences above + indeed represent the correct vector valued sequences:: + + sage: var('n') + n + + sage: def v(n): + ....: return vector([3*n + 1, 6*n + 1]) + sage: S31.mu[0] * v(n) == v(2*n) + True + sage: S31.mu[1] * v(n) == v(2*n + 1) + True + + sage: function('delta_0') + delta_0 + + sage: def simplify_delta(expr): + ....: return expr.subs({delta_0(2*n): delta_0(n), delta_0(2*n + 1): 0}) + + sage: def v(n): + ....: return vector([n -1 + delta_0(n), 2*n - 1 + delta_0(n), 4*n + 1]) + sage: simplify_delta(v(2*n) - Srs.mu[0]*v(n)).is_zero() + True + sage: simplify_delta(v(2*n + 1) - Srs.mu[1]*v(n)).is_zero() + True + + sage: def v(n): + ....: return vector([1 - delta_0(n), 1]) + + sage: simplify_delta(v(2*n) - Sbd.mu[0]*v(n)).is_zero() + True + sage: simplify_delta(v(2*n + 1) - Sbd.mu[1]*v(n)).is_zero() + True + + We check some corner-cases:: + + sage: C.subsequence(0, 4) + 2-regular sequence 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, ... + + :: + + sage: C.subsequence(1, 0, minimize=False) is C + True + + The following test that the range for `c` in the code + is sufficient:: + + sage: C.subsequence(1, -1, minimize=False) + 2-regular sequence 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ... + sage: C.subsequence(1, -2, minimize=False) + 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, ... + sage: C.subsequence(2, -1, minimize=False) + 2-regular sequence 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, ... + sage: C.subsequence(2, -2, minimize=False) + 2-regular sequence 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, ... + + sage: C.subsequence(2, 21, minimize=False) + 2-regular sequence 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, ... + sage: C.subsequence(2, 20, minimize=False) + 2-regular sequence 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, ... + sage: C.subsequence(2, 19, minimize=False) + 2-regular sequence 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, ... + sage: C.subsequence(2, -9, minimize=False) + 2-regular sequence 0, 0, 0, 0, 0, 1, 3, 5, 7, 9, ... + + sage: C.subsequence(3, 21, minimize=False) + 2-regular sequence 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, ... + sage: C.subsequence(3, 20, minimize=False) + 2-regular sequence 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, ... + sage: C.subsequence(3, 19, minimize=False) + 2-regular sequence 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, ... + sage: C.subsequence(3, 18, minimize=False) + 2-regular sequence 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, ... + + sage: C.subsequence(10, 2, minimize=False) + 2-regular sequence 2, 12, 22, 32, 42, 52, 62, 72, 82, 92, ... + sage: C.subsequence(10, 1, minimize=False) + 2-regular sequence 1, 11, 21, 31, 41, 51, 61, 71, 81, 91, ... + sage: C.subsequence(10, 0, minimize=False) + 2-regular sequence 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, ... + sage: C.subsequence(10, -1, minimize=False) + 2-regular sequence 0, 9, 19, 29, 39, 49, 59, 69, 79, 89, ... + sage: C.subsequence(10, -2, minimize=False) + 2-regular sequence 0, 8, 18, 28, 38, 48, 58, 68, 78, 88, ... + + :: + + sage: C.subsequence(-1, 0) + Traceback (most recent call last): + ... + ValueError: a=-1 is not nonnegative. + + The following linear representation of `S` is chosen badly (is + degenerated, see :meth:`is_degenerated`), as `\mu(0)` applied on + `\mathit{right}` does not equal `\mathit{right}`:: + + sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]), + ....: allow_degenerated_sequence=True) + sage: S + 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ... + + This leads to the wrong result + :: + + sage: S.subsequence(1, -4) + 2-regular sequence 0, 0, 0, 0, 8, 12, 12, 18, 24, 36, ... + + We get the correct result by + :: + + sage: S.regenerated().subsequence(1, -4) + 2-regular sequence 0, 0, 0, 0, 1, 3, 6, 9, 12, 18, ... + """ + from itertools import chain + from sage.rings.integer_ring import ZZ + + zero = ZZ(0) + a = ZZ(a) + if not isinstance(b, dict): + b = {ZZ(b): ZZ(1)} + + if a == 0: + return sum(c_j * self[b_j] * self.parent().one_hadamard() + for b_j, c_j in b.items()) + elif a == 1 and len(b) == 1 and zero in b: + return b[zero] * self + elif a < 0: + raise ValueError('a={} is not nonnegative.'.format(a)) + + from sage.matrix.constructor import Matrix + from sage.modules.free_module_element import vector + P = self.parent() + A = P.alphabet() + k = P.k + + # Below, we use a dynamic approach to find the shifts of the + # sequences in the kernel. Note that according to [AS2003]_, + # the static range + # [min(b, 0), max(a, a + b)) + # suffices. With B = |b| and A = max(a, B), we here obtain the range + # [-B, A] + # because of the following estimates: + # Let -B <= c <= A und set d = floor((ar+c) / k). Then + # -B = floor(-B) + # <= floor(-B / k) + # <= floor(c / k) + # <= d + # <= (ar+c) / k + # <= (A(k-1) + A) / k + # = A + # holds. + # For list-valued b, we use B = max{|beta| : beta in b} above. + + kernel = list(b) + + zero_M = self.mu[0].parent().zero() + zero_R = self.right.parent().zero() + # Let v(n) = self.coefficient_of_n(n, multiply_left=False) + rule = {} + # We will construct `kernel` and `rule` in such a way that for all + # c in `kernel`, + # rule[r, c] = (f, d) + # holds for some 0 <= f < r and some d in `kernel` such that + # v(a(kn+r)+c) [a(kn+r) +c >= 0] = mu[f] v(an+d) [an+d >= 0]. + + ci = 0 + while ci < len(kernel): + c = kernel[ci] + for r in A: + # We now compute the contributions of v(an+c)[an >= 0] to + # the linear representation by using + # v(a(kn+r)+c) [a(kn+r)+c >= 0] + # = v(kan+ar+c) [kan+ar+c >= 0] + # = v(k(an+d)+f) [an+d >= 0] + # = mu[f] v(an+d) [an+d >= 0]. + d, f = (a * r + c).quo_rem(k) + if d not in kernel: + kernel.append(d) + rule[r, c] = (d, f) + ci += 1 + + def matrix_row(r, c): + d, f = rule[r, c] + return [self.mu[f] if d == j else zero_M for j in kernel] + + result = P.element_class( + P, + {r: Matrix.block([matrix_row(r, c) for c in kernel]) + for r in A}, + vector(chain.from_iterable( + b.get(c, 0) * self.left + for c in kernel)), + vector(chain.from_iterable( + (self.coefficient_of_n(c, multiply_left=False) if c >= 0 else zero_R) + for c in kernel))) + + return result + + def shift_left(self, b=1, **kwds): + r""" + Return the sequence obtained by shifting + this `k`-regular sequence `b` steps to the left. + + INPUT: + + - ``b`` -- an integer + + - ``minimize`` -- (default: ``None``) a boolean or ``None``. + If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, + if ``False``, then not. If this argument is ``None``, then + the default specified by the parent's ``minimize_results`` is used. + + OUTPUT: + + A :class:`RegularSequence` + + .. NOTE:: + + If `b` is negative (i.e., actually a right-shift), then the + coefficients when accessing negative indices are `0`. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])), + ....: vector([1, 0]), vector([0, 1])); C + 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + + sage: C.shift_left() + 2-regular sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ... + sage: C.shift_left(3) + 2-regular sequence 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ... + sage: C.shift_left(-2) + 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, ... + + TESTS:: + + sage: C.shift_left(0) == C + True + sage: C.shift_left(2).shift_right(2) + 2-regular sequence 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, ... + """ + return self.subsequence(1, b, **kwds) + + def shift_right(self, b=1, **kwds): + r""" + Return the sequence obtained by shifting + this `k`-regular sequence `b` steps to the right. + + INPUT: + + - ``b`` -- an integer + + - ``minimize`` -- (default: ``None``) a boolean or ``None``. + If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, + if ``False``, then not. If this argument is ``None``, then + the default specified by the parent's ``minimize_results`` is used. + + OUTPUT: + + A :class:`RegularSequence` + + .. NOTE:: + + If `b` is positive (i.e., indeed a right-shift), then the + coefficients when accessing negative indices are `0`. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])), + ....: vector([1, 0]), vector([0, 1])); C + 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + + sage: C.shift_right() + 2-regular sequence 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ... + sage: C.shift_right(3) + 2-regular sequence 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, ... + sage: C.shift_right(-2) + 2-regular sequence 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... + + TESTS:: + + sage: C.shift_right(0) == C + True + sage: C.shift_right().shift_left() + 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + sage: C.shift_right(2).shift_left(2) + 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + sage: _ == C + True + """ + return self.subsequence(1, -b, **kwds) + + def backward_differences(self, **kwds): + r""" + Return the sequence of backward differences of this + `k`-regular sequence. + + INPUT: + + - ``minimize`` -- (default: ``None``) a boolean or ``None``. + If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, + if ``False``, then not. If this argument is ``None``, then + the default specified by the parent's ``minimize_results`` is used. + + OUTPUT: + + A :class:`RegularSequence` + + .. NOTE:: + + The coefficient to the index `-1` is `0`. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])), + ....: vector([1, 0]), vector([0, 1])) + sage: C + 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + sage: C.backward_differences() + 2-regular sequence 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... + + :: + + sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), + ....: vector([1, 0]), vector([1, 1])) + sage: E + 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ... + sage: E.backward_differences() + 2-regular sequence 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, ... + """ + return self.subsequence(1, {0: 1, -1: -1}, **kwds) + + def forward_differences(self, **kwds): + r""" + Return the sequence of forward differences of this + `k`-regular sequence. + + INPUT: + + - ``minimize`` -- (default: ``None``) a boolean or ``None``. + If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, + if ``False``, then not. If this argument is ``None``, then + the default specified by the parent's ``minimize_results`` is used. + + OUTPUT: + + A :class:`RegularSequence` + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])), + ....: vector([1, 0]), vector([0, 1])) + sage: C + 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + sage: C.forward_differences() + 2-regular sequence 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... + + :: + + sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), + ....: vector([1, 0]), vector([1, 1])) + sage: E + 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ... + sage: E.forward_differences() + 2-regular sequence -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, ... + """ + return self.subsequence(1, {1: 1, 0: -1}, **kwds) + + @minimize_result + def _mul_(self, other): + r""" + Return the product of this `k`-regular sequence with ``other``, + where the multiplication is convolution of power series. + + The operator `*` is mapped to :meth:`convolution`. + + INPUT: + + - ``other`` -- a :class:`RegularSequence` + + - ``minimize`` -- (default: ``None``) a boolean or ``None``. + If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, + if ``False``, then not. If this argument is ``None``, then + the default specified by the parent's ``minimize_results`` is used. + + OUTPUT: + + A :class:`RegularSequence` + + ALGORITHM: + + See pdf attached to + `github pull request #35894 <https://github.com/sagemath/sage/pull/35894>`_ + which contains a draft describing the details of the used algorithm. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), + ....: vector([1, 0]), vector([1, 1])) + sage: E + 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ... + + We can build the convolution (in the sense of power-series) of `E` by + itself via:: + + sage: E.convolution(E) + 2-regular sequence 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, ... + + This is the same as using multiplication operator:: + + sage: E * E + 2-regular sequence 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, ... + + Building :meth:`partial_sums` can also be seen as a convolution:: + + sage: o = Seq2.one_hadamard() + sage: E * o + 2-regular sequence 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, ... + sage: E * o == E.partial_sums(include_n=True) + True + + TESTS:: + + sage: E * o == o * E + True + """ + from sage.arith.srange import srange + from sage.matrix.constructor import Matrix + from sage.matrix.special import zero_matrix + from sage.modules.free_module_element import vector + + P = self.parent() + k = P.k + + def tensor_product(left, right): + T = left.tensor_product(right) + T.subdivide() + return T + + matrices_0 = {r: sum(tensor_product(self.mu[s], other.mu[r-s]) + for s in srange(0, r+1)) + for r in P.alphabet()} + matrices_1 = {r: sum(tensor_product(self.mu[s], other.mu[k+r-s]) + for s in srange(r+1, k)) + for r in P.alphabet()} + left = vector(tensor_product(Matrix(self.left), Matrix(other.left))) + right = vector(tensor_product(Matrix(self.right), Matrix(other.right))) + + def linear_representation_morphism_recurrence_order_1(C, D): + r""" + Return the morphism of a linear representation + for the sequence `z_n` satisfying + `z_{kn+r} = C_r z_n + D_r z_{n-1}`. + """ + Z = zero_matrix(C[0].dimensions()[0]) + + def blocks(r): + upper = list([C[s], D[s], Z] + for s in reversed(srange(max(0, r-2), r+1))) + lower = list([Z, C[s], D[s]] + for s in reversed(srange(k-3+len(upper), k))) + return upper + lower + + return {r: Matrix.block(blocks(r)) for r in P.alphabet()} + + result = P.element_class( + P, + linear_representation_morphism_recurrence_order_1(matrices_0, + matrices_1), + vector(list(left) + (2*len(list(left)))*[0]), + vector(list(right) + (2*len(list(right)))*[0])) + + return result + + convolution = _mul_ + + @minimize_result + def partial_sums(self, include_n=False): + r""" + Return the sequence of partial sums of this + `k`-regular sequence. That is, the `n`-th entry of the result + is the sum of the first `n` entries in the original sequence. + + INPUT: + + - ``include_n`` -- (default: ``False``) a boolean. If set, then + the `n`-th entry of the result is the sum of the entries up + to index `n` (included). + + - ``minimize`` -- (default: ``None``) a boolean or ``None``. + If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, + if ``False``, then not. If this argument is ``None``, then + the default specified by the parent's ``minimize_results`` is used. + + OUTPUT: + + A :class:`RegularSequence` + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + + sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), + ....: vector([1, 0]), vector([1, 1])) + sage: E + 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ... + sage: E.partial_sums() + 2-regular sequence 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, ... + sage: E.partial_sums(include_n=True) + 2-regular sequence 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, ... + + :: + + sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])), + ....: vector([1, 0]), vector([0, 1])) + sage: C + 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + sage: C.partial_sums() + 2-regular sequence 0, 0, 1, 3, 6, 10, 15, 21, 28, 36, ... + sage: C.partial_sums(include_n=True) + 2-regular sequence 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, ... + + The following linear representation of `S` is chosen badly (is + degenerated, see :meth:`is_degenerated`), as `\mu(0)` applied on + `\mathit{right}` does not equal `\mathit{right}`:: + + sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]), + ....: allow_degenerated_sequence=True) + sage: S + 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ... + + Therefore, building partial sums produces a wrong result:: + + sage: H = S.partial_sums(include_n=True, minimize=False) + sage: H + 2-regular sequence 1, 5, 16, 25, 62, 80, 98, 125, 274, 310, ... + sage: H = S.partial_sums(minimize=False) + sage: H + 2-regular sequence 0, 2, 10, 16, 50, 62, 80, 98, 250, 274, ... + + We can :meth:`~RegularSequenceRing.guess` the correct representation:: + + sage: from itertools import islice + sage: L = []; ps = 0 + sage: for s in islice(S, 110): + ....: ps += s + ....: L.append(ps) + sage: G = Seq2.guess(lambda n: L[n]) + sage: G + 2-regular sequence 1, 4, 10, 19, 31, 49, 67, 94, 118, 154, ... + sage: G.linear_representation() + ((1, 0, 0, 0), + Finite family {0: [ 0 1 0 0] + [ 0 0 0 1] + [ -5 5 1 0] + [ 10 -17 0 8], + 1: [ 0 0 1 0] + [ -5 3 3 0] + [ -5 0 6 0] + [-30 21 10 0]}, + (1, 1, 4, 1)) + sage: G.minimized().dimension() == G.dimension() + True + + Or we regenerate the sequence `S` first:: + + sage: S.regenerated().partial_sums(include_n=True, minimize=False) + 2-regular sequence 1, 4, 10, 19, 31, 49, 67, 94, 118, 154, ... + sage: S.regenerated().partial_sums(minimize=False) + 2-regular sequence 0, 1, 4, 10, 19, 31, 49, 67, 94, 118, ... + + TESTS:: + + sage: E.linear_representation() + ((1, 0), + Finite family {0: [0 1] + [0 1], + 1: [0 0] + [0 1]}, + (1, 1)) + + sage: P = E.partial_sums(minimize=False) + sage: P.linear_representation() + ((1, 0, 0, 0), + Finite family {0: [0 1|0 0] + [0 2|0 0] + [---+---] + [0 0|0 1] + [0 0|0 1], + 1: [0 1|0 1] + [0 2|0 1] + [---+---] + [0 0|0 0] + [0 0|0 1]}, + (0, 0, 1, 1)) + + sage: P = E.partial_sums(include_n=True, minimize=False) + sage: P.linear_representation() + ((1, 0, 1, 0), + Finite family {0: [0 1|0 0] + [0 2|0 0] + [---+---] + [0 0|0 1] + [0 0|0 1], + 1: [0 1|0 1] + [0 2|0 1] + [---+---] + [0 0|0 0] + [0 0|0 1]}, + (0, 0, 1, 1)) + """ + from itertools import chain + from sage.matrix.constructor import Matrix + from sage.matrix.special import zero_matrix + from sage.modules.free_module_element import vector + + P = self.parent() + A = P.alphabet() + k = P.k + dim = self.dimension() + Z = zero_matrix(dim) + + z = A[0] + assert z == 0 + B = {z: Z} + for r in A: + B[r+1] = B[r] + self.mu[r] + C = B[k] + + result = P.element_class( + P, + {r: Matrix.block([[C, B[r]], [Z, self.mu[r]]]) for r in A}, + vector(chain(self.left, + (dim * (0,) if not include_n else self.left))), + vector(chain(dim * (0,), self.right))) + + return result + + +def _pickle_RegularSequenceRing(k, coefficients, category): + r""" + Pickle helper. + + TESTS:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: from sage.combinat.regular_sequence import _pickle_RegularSequenceRing + sage: _pickle_RegularSequenceRing( + ....: Seq2.k, Seq2.coefficient_ring(), Seq2.category()) + Space of 2-regular sequences over Integer Ring + """ + return RegularSequenceRing(k, coefficients, category=category) + + +class RegularSequenceRing(RecognizableSeriesSpace): + r""" + The space of `k`-regular Sequences over the given ``coefficient_ring``. + + INPUT: + + - ``k`` -- an integer at least `2` specifying the base + + - ``coefficient_ring`` -- a (semi-)ring + + - ``category`` -- (default: ``None``) the category of this + space + + EXAMPLES:: + + sage: RegularSequenceRing(2, ZZ) + Space of 2-regular sequences over Integer Ring + sage: RegularSequenceRing(3, ZZ) + Space of 3-regular sequences over Integer Ring + + .. SEEALSO:: + + :doc:`k-regular sequence <regular_sequence>`, + :class:`RegularSequence`. + """ + Element = RegularSequence + + @classmethod + def __normalize__(cls, k, + coefficient_ring, + category=None, + **kwds): + r""" + Normalizes the input in order to ensure a unique + representation. + + For more information see :class:`RegularSequenceRing`. + + TESTS:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: Seq2.category() + Category of algebras over Integer Ring + sage: Seq2.alphabet() + {0, 1} + """ + from sage.arith.srange import srange + from sage.categories.algebras import Algebras + category = category or Algebras(coefficient_ring) + nargs = super().__normalize__(coefficient_ring, + alphabet=srange(k), + category=category, + **kwds) + return (k,) + nargs + + def __init__(self, k, *args, **kwds): + r""" + See :class:`RegularSequenceRing` for details. + + INPUT: + + - ``k`` -- an integer at least `2` specifying the base + + Other input arguments are passed on to + :meth:`~sage.combinat.recognizable_series.RecognizableSeriesSpace.__init__`. + + TESTS:: + + sage: RegularSequenceRing(2, ZZ) + Space of 2-regular sequences over Integer Ring + sage: RegularSequenceRing(3, ZZ) + Space of 3-regular sequences over Integer Ring + + :: + + sage: from itertools import islice + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: TestSuite(Seq2).run( # long time + ....: elements=tuple(islice(Seq2.some_elements(), 4))) + + .. SEEALSO:: + + :doc:`k-regular sequence <regular_sequence>`, + :class:`RegularSequence`. + """ + self.k = k + super().__init__(*args, **kwds) + + def __reduce__(self): + r""" + Pickling support. + + TESTS:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: loads(dumps(Seq2)) # indirect doctest + Space of 2-regular sequences over Integer Ring + """ + return _pickle_RegularSequenceRing, \ + (self.k, self.coefficient_ring(), self.category()) + + def _repr_(self): + r""" + Return a representation string of this `k`-regular sequence space. + + OUTPUT: a string + + TESTS:: + + sage: repr(RegularSequenceRing(2, ZZ)) # indirect doctest + 'Space of 2-regular sequences over Integer Ring' + """ + return 'Space of {}-regular sequences over {}'.format(self.k, self.base()) + + def _n_to_index_(self, n): + r""" + Convert `n` to an index usable by the underlying + recognizable series. + + INPUT: + + - ``n`` -- a nonnegative integer + + OUTPUT: a word + + TESTS:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: Seq2._n_to_index_(6) + word: 011 + sage: Seq2._n_to_index_(-1) + Traceback (most recent call last): + ... + ValueError: value -1 of index is negative + """ + from sage.rings.integer_ring import ZZ + n = ZZ(n) + W = self.indices() + try: + return W(n.digits(self.k)) + except OverflowError: + raise ValueError('value {} of index is negative'.format(n)) from None + + @cached_method + def one(self): + r""" + Return the one element of this :class:`RegularSequenceRing`, + i.e. the unique neutral element for `*` and also + the embedding of the one of the coefficient ring into + this :class:`RegularSequenceRing`. + + EXAMPLES:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: O = Seq2.one(); O + 2-regular sequence 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... + sage: O.linear_representation() + ((1), Finite family {0: [1], 1: [0]}, (1)) + + TESTS:: + + sage: Seq2.one() is Seq2.one() + True + """ + from sage.matrix.constructor import Matrix + from sage.modules.free_module_element import vector + + R = self.coefficient_ring() + one = R.one() + zero = R.zero() + return self.element_class(self, + [Matrix([[one]])] + + (self.k-1)*[Matrix([[zero]])], + vector([one]), + vector([one])) + + def some_elements(self): + r""" + Return some elements of this `k`-regular sequence. + + See :class:`TestSuite` for a typical use case. + + OUTPUT: + + An iterator + + EXAMPLES:: + + sage: tuple(RegularSequenceRing(2, ZZ).some_elements()) + (2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ..., + 2-regular sequence 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, ..., + 2-regular sequence 1, 1, 0, 1, -1, 0, 0, 1, -2, -1, ..., + 2-regular sequence 2, -1, 0, 0, 0, -1, 0, 0, 0, 0, ..., + 2-regular sequence 1, 1, 0, 1, 5, 0, 0, 1, -33, 5, ..., + 2-regular sequence -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, ..., + 2-regular sequence -59, -20, 0, -20, 0, 0, 0, -20, 0, 0, ..., + ... + 2-regular sequence 2210, 170, 0, 0, 0, 0, 0, 0, 0, 0, ...) + """ + return iter(element.regenerated() + for element + in super(RegularSequenceRing, self).some_elements( + allow_degenerated_sequence=True)) + + def _element_constructor_(self, *args, **kwds): + r""" + Return a `k`-regular sequence. + + See :class:`RegularSequenceRing` for details. + + TESTS:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1])) + Traceback (most recent call last): + ... + DegeneratedSequenceError: degenerated sequence: mu[0]*right != right. + Using such a sequence might lead to wrong results. + You can use 'allow_degenerated_sequence=True' followed + by a call of method .regenerated() for correcting this. + sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]), + ....: allow_degenerated_sequence=True) + 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ... + sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]), + ....: allow_degenerated_sequence=True).regenerated() + 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ... + """ + allow_degenerated_sequence = kwds.pop('allow_degenerated_sequence', False) + element = super(RegularSequenceRing, self)._element_constructor_(*args, **kwds) + if not allow_degenerated_sequence: + element._error_if_degenerated_() + return element + + def guess(self, f, n_verify=100, max_exponent=10, sequence=None): + r""" + Guess a `k`-regular sequence whose first terms coincide with `(f(n))_{n\geq0}`. + + INPUT: + + - ``f`` -- a function (callable) which determines the sequence. + It takes nonnegative integers as an input + + - ``n_verify`` -- (default: ``100``) a positive integer. The resulting + `k`-regular sequence coincides with `f` on the first ``n_verify`` + terms. + + - ``max_exponent`` -- (default: ``10``) a positive integer specifying + the maximum exponent of `k` which is tried when guessing the sequence, + i.e., relations between `f(k^t n+r)` are used for + `0\le t\le \mathtt{max\_exponent}` and `0\le r < k^j` + + - ``sequence`` -- (default: ``None``) a `k`-regular sequence used + for bootstrapping the guessing by adding information of the + linear representation of ``sequence`` to the guessed representation + + OUTPUT: + + A :class:`RegularSequence` + + ALGORITHM: + + For the purposes of this description, the right vector valued sequence + associated with a regular sequence consists of the + corresponding matrix product multiplied by the right vector, + but without the left vector of the regular sequence. + + The algorithm maintains a right vector valued sequence consisting + of the right vector valued sequence of the argument ``sequence`` + (replaced by an empty tuple if ``sequence`` is ``None``) plus several + components of the shape `m \mapsto f(k^t\cdot m +r)` for suitable + ``t`` and ``r``. + + Implicitly, the algorithm also maintains a `d \times n_\mathrm{verify}` matrix ``A`` + (where ``d`` is the dimension of the right vector valued sequence) + whose columns are the current right vector valued sequence evaluated at + the non-negative integers less than `n_\mathrm{verify}` and ensures that this + matrix has full row rank. + + EXAMPLES: + + Binary sum of digits:: + + sage: @cached_function + ....: def s(n): + ....: if n == 0: + ....: return 0 + ....: return s(n//2) + ZZ(is_odd(n)) + sage: all(s(n) == sum(n.digits(2)) for n in srange(10)) + True + sage: [s(n) for n in srange(10)] + [0, 1, 1, 2, 1, 2, 2, 3, 1, 2] + + Let us guess a `2`-linear representation for `s(n)`:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: import logging + sage: logging.getLogger().setLevel(logging.INFO) + sage: S1 = Seq2.guess(s); S1 + INFO:...:including f_{1*m+0} + INFO:...:including f_{2*m+1} + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... + sage: S1.linear_representation() + ((1, 0), + Finite family {0: [1 0] + [0 1], + 1: [ 0 1] + [-1 2]}, + (0, 1)) + + The ``INFO`` messages mean that the right vector valued sequence is the sequence `(s(n), s(2n+1))^\top`. + + We guess again, but this time, we use a constant sequence + for bootstrapping the guessing process:: + + sage: C = Seq2.one_hadamard(); C + 2-regular sequence 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... + sage: S2 = Seq2.guess(s, sequence=C); S2 + INFO:...:including 2-regular sequence 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... + INFO:...:including f_{1*m+0} + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... + sage: S2.linear_representation() + ((0, 1), + Finite family {0: [1 0] + [0 1], + 1: [1 0] + [1 1]}, + (1, 0)) + sage: S1 == S2 + True + + The sequence of all natural numbers:: + + sage: S = Seq2.guess(lambda n: n); S + INFO:...:including f_{1*m+0} + INFO:...:including f_{2*m+1} + 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + sage: S.linear_representation() + ((1, 0), + Finite family {0: [2 0] + [2 1], + 1: [ 0 1] + [-2 3]}, + (0, 1)) + + The indicator function of the even integers:: + + sage: S = Seq2.guess(lambda n: ZZ(is_even(n))); S + INFO:...:including f_{1*m+0} + INFO:...:including f_{2*m+0} + 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ... + sage: S.linear_representation() + ((1, 0), + Finite family {0: [0 1] + [0 1], + 1: [0 0] + [0 1]}, + (1, 1)) + + The indicator function of the odd integers:: + + sage: S = Seq2.guess(lambda n: ZZ(is_odd(n))); S + INFO:...:including f_{1*m+0} + INFO:...:including f_{2*m+1} + 2-regular sequence 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, ... + sage: S.linear_representation() + ((1, 0), + Finite family {0: [0 0] + [0 1], + 1: [0 1] + [0 1]}, + (0, 1)) + sage: logging.getLogger().setLevel(logging.WARN) + + The following linear representation of `S` is chosen badly (is + degenerated, see :meth:`is_degenerated`), as `\mu(0)` applied on + `\mathit{right}` does not equal `\mathit{right}`:: + + sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]), + ....: allow_degenerated_sequence=True) + sage: S + 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ... + sage: S.is_degenerated() + True + + However, we can :meth:`~RegularSequenceRing.guess` a `2`-regular sequence of dimension `2`:: + + sage: G = Seq2.guess(lambda n: S[n]) + sage: G + 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ... + sage: G.linear_representation() + ((1, 0), + Finite family {0: [ 0 1] + [-2 3], + 1: [3 0] + [6 0]}, + (1, 1)) + + sage: G == S.regenerated() + True + + TESTS:: + + sage: from importlib import reload + sage: logging.shutdown(); _ = reload(logging) + sage: logging.basicConfig(level=logging.DEBUG) + sage: Seq2.guess(s) + INFO:...:including f_{1*m+0} + DEBUG:...:M_0: f_{2*m+0} = (1) * F_m + INFO:...:including f_{2*m+1} + DEBUG:...:M_1: f_{2*m+1} = (0, 1) * F_m + DEBUG:...:M_0: f_{4*m+1} = (0, 1) * F_m + DEBUG:...:M_1: f_{4*m+3} = (-1, 2) * F_m + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... + sage: from importlib import reload + sage: logging.shutdown(); _ = reload(logging) + + :: + + sage: S = Seq2.guess(lambda n: 2, sequence=C) + sage: S + 2-regular sequence 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ... + sage: S.linear_representation() + ((2), + Finite family {0: [1], + 1: [1]}, + (1)) + + We :meth:`~RegularSequenceRing.guess` some partial sums sequences:: + + sage: S = Seq2((Matrix([1]), Matrix([2])), vector([1]), vector([1])) + sage: S + 2-regular sequence 1, 2, 2, 4, 2, 4, 4, 8, 2, 4, ... + sage: from itertools import islice + sage: L = []; ps = 0 + sage: for j in islice(S, 110): + ....: ps += j + ....: L.append(ps) + sage: G = Seq2.guess(lambda n: L[n]) + sage: G + 2-regular sequence 1, 3, 5, 9, 11, 15, 19, 27, 29, 33, ... + sage: G.linear_representation() + ((1, 0), + Finite family {0: [ 0 1] + [-3 4], + 1: [3 0] + [3 2]}, + (1, 1)) + sage: G == S.partial_sums(include_n=True) + True + + :: + + sage: Seq3 = RegularSequenceRing(3, QQ) + sage: S = Seq3((Matrix([1]), Matrix([3]), Matrix([2])), vector([1]), vector([1])) + sage: S + 3-regular sequence 1, 3, 2, 3, 9, 6, 2, 6, 4, 3, ... + sage: from itertools import islice + sage: L = []; ps = 0 + sage: for j in islice(S, 110): + ....: ps += j + ....: L.append(ps) + sage: G = Seq3.guess(lambda n: L[n]) + sage: G + 3-regular sequence 1, 4, 6, 9, 18, 24, 26, 32, 36, 39, ... + sage: G.linear_representation() + ((1, 0), + Finite family {0: [ 0 1] + [-6 7], + 1: [18/5 2/5] + [18/5 27/5], + 2: [ 6 0] + [24 2]}, + (1, 1)) + sage: G == S.partial_sums(include_n=True) + True + + :: + + sage: Seq2.guess(s, max_exponent=1) + Traceback (most recent call last): + ... + RuntimeError: aborting as exponents would be larger than max_exponent=1 + + :: + + sage: R = RegularSequenceRing(2, QQ) + sage: one = R.one_hadamard() + sage: S = R.guess(lambda n: sum(n.bits()), sequence=one) + one + sage: T = R.guess(lambda n: n*n, sequence=S, n_verify=4); T + 2-regular sequence 0, 1, 4, 9, 16, 25, 36, 163/3, 64, 89, ... + sage: T.linear_representation() + ((0, 0, 1), + Finite family {0: [1 0 0] + [0 1 0] + [0 0 4], + 1: [ 0 1 0] + [ -1 2 0] + [13/3 -5/3 16/3]}, + (1, 2, 0)) + + :: + + sage: two = Seq2.one_hadamard() * 2 + sage: two.linear_representation() + ((1), Finite family {0: [1], 1: [1]}, (2)) + sage: two_again = Seq2.guess(lambda n: 2, sequence=two) + sage: two_again.linear_representation() + ((1), Finite family {0: [1], 1: [1]}, (2)) + + :: + + sage: def s(k): + ....: return k + sage: S1 = Seq2.guess(s) + sage: S2 = Seq2.guess(s, sequence=S1) + sage: S1 + 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + sage: S2 + 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + + :: + + sage: A = Seq2( + ....: (Matrix([[1, 1], [1, 1]]), Matrix([[1, 1], [1, 1]])), + ....: left=(1, 1), right=(1, 1), + ....: allow_degenerated_sequence=True) + sage: Seq2.guess(lambda n: n, sequence=A, n_verify=5) + Traceback (most recent call last): + ... + RuntimeError: no invertible submatrix found + """ + import logging + logger = logging.getLogger(__name__) + + from sage.arith.srange import srange, xsrange + from sage.matrix.constructor import Matrix + from sage.misc.mrange import cantor_product + from sage.modules.free_module_element import vector + + k = self.k + domain = self.coefficient_ring() + if sequence is None: + mu = [[] for _ in srange(k)] + seq = lambda m: vector([]) + else: + mu = [M.rows() for M in sequence.mu] + seq = lambda m: sequence.coefficient_of_n(m, multiply_left=False) + logger.info('including %s', sequence) + + zero = domain(0) + one = domain(1) + + # A `line` will be a pair `(t, r)` corresponding to an entry + # `k**t * m + r` + + # The elements of `lines` will correspond to the current components + # of the right vector valued sequence described in the algorithm section + # of the docstring. + + def values(m, lines): + """ + Return current (as defined by ``lines``) right vector valued + sequence for argument ``m``. + """ + return tuple(seq(m)) + tuple(f(k**t_R * m + r_R) for t_R, r_R in lines) + + @cached_function(key=lambda lines: len(lines)) + # we assume that existing lines are not changed + # (we allow appending of new lines) + def some_inverse_U_matrix(lines): + r""" + Find an invertible `d \times d` submatrix of the matrix + ``A`` described in the algorithm section of the docstring. + + The output is the inverse of the invertible submatrix and + the corresponding list of column indices (i.e., arguments to + the current right vector valued sequence). + """ + d = len(seq(0)) + len(lines) + + # The following search for an inverse works but is inefficient; + # see :trac:`35748` for details. + for m_indices in cantor_product(xsrange(n_verify), repeat=d, min_slope=1): + # Iterate over all increasing lists of length d consisting + # of non-negative integers less than `n_verify`. + + U = Matrix(domain, d, d, [values(m, lines) for m in m_indices]).transpose() + try: + return U.inverse(), m_indices + except ZeroDivisionError: + pass + else: + raise RuntimeError('no invertible submatrix found') + + def linear_combination_candidate(t_L, r_L, lines): + r""" + Based on an invertible submatrix of ``A`` as described in the + algorithm section of the docstring, find a candidate for a + linear combination of the rows of ``A`` yielding the subsequence + with parameters ``t_L`` and ``r_L``, i.e., + `m \mapsto f(k**t_L * m + r_L)`. + """ + iU, m_indices = some_inverse_U_matrix(lines) + X_L = vector(f(k**t_L * m + r_L) for m in m_indices) + return X_L * iU + + def verify_linear_combination(t_L, r_L, linear_combination, lines): + r""" + Determine whether the subsequence with parameters ``t_L`` and + ``r_L``, i.e., `m \mapsto f(k**t_L * m + r_L)`, is the linear + combination ``linear_combination`` of the current vector valued + sequence. + + Note that we only evaluate the subsequence of ``f`` where arguments + of ``f`` are at most ``n_verify``. This might lead to detection of + linear dependence which would not be true for higher values, but this + coincides with the documentation of ``n_verify``. + However, this is not a guarantee that the given function will never + be evaluated beyond ``n_verify``, determining an invertible submatrix + in ``some_inverse_U_matrix`` might require us to do so. + """ + return all(f(k**t_L * m + r_L) == + linear_combination * vector(values(m, lines)) + for m in xsrange(0, (n_verify - r_L) // k**t_L + 1)) + + class NoLinearCombination(RuntimeError): + pass + + def find_linear_combination(t_L, r_L, lines): + linear_combination = linear_combination_candidate(t_L, r_L, lines) + if not verify_linear_combination(t_L, r_L, linear_combination, lines): + raise NoLinearCombination + return linear_combination + + if seq(0).is_zero(): + left = None + else: + try: + left = vector(find_linear_combination(0, 0, [])) + except NoLinearCombination: + left = None + + to_branch = [] + lines = [] + + def include(t, r): + to_branch.append((t, r)) + lines.append((t, r)) + logger.info('including f_{%s*m+%s}', k**t, r) + + if left is None: + include(0, 0) # entries (t, r) --> k**t * m + r + assert len(lines) == 1 + left = vector(len(seq(0))*(zero,) + (one,)) + + while to_branch: + t_R, r_R = to_branch.pop(0) + if t_R >= max_exponent: + raise RuntimeError(f'aborting as exponents would be larger ' + f'than max_exponent={max_exponent}') + + t_L = t_R + 1 + for s_L in srange(k): + r_L = k**t_R * s_L + r_R + try: + linear_combination = find_linear_combination(t_L, r_L, lines) + except NoLinearCombination: + include(t_L, r_L) # entries (t, r) --> k**t * m + r + linear_combination = (len(lines)-1)*(zero,) + (one,) + logger.debug('M_%s: f_{%s*m+%s} = %s * F_m', + s_L, k**t_L, r_L, linear_combination) + mu[s_L].append(linear_combination) + + d = len(seq(0)) + len(lines) + mu = tuple(Matrix(domain, [pad_right(tuple(row), d, zero=zero) for row in M]) + for M in mu) + right = vector(values(0, lines)) + left = vector(pad_right(tuple(left), d, zero=zero)) + return self(mu, left, right) + + def from_recurrence(self, *args, **kwds): + r""" + Construct the unique `k`-regular sequence which fulfills the given + recurrence relations and initial values. The recurrence relations have to + have the specific shape of `k`-recursive sequences as described in [HKL2022]_, + and are either given as symbolic equations, e.g., + + :: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: var('n') + n + sage: function('f') + f + sage: Seq2.from_recurrence([ + ....: f(2*n) == 2*f(n), f(2*n + 1) == 3*f(n) + 4*f(n - 1), + ....: f(0) == 0, f(1) == 1], f, n) + 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 10, 6, 17, ... + + or via the parameters of the `k`-recursive sequence as described in the input + block below:: + + sage: Seq2.from_recurrence(M=1, m=0, + ....: coeffs={(0, 0): 2, (1, 0): 3, (1, -1): 4}, + ....: initial_values={0: 0, 1: 1}) + 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 10, 6, 17, ... + + INPUT: + + Positional arguments: + + If the recurrence relations are represented by symbolic equations, then + the following arguments are required: + + - ``equations`` -- A list of equations where the elements have + either the form + + - `f(k^M n + r) = c_{r,l} f(k^m n + l) + c_{r,l + 1} f(k^m n + + l + 1) + ... + c_{r,u} f(k^m n + u)` for some integers + `0 \leq r < k^M`, `M > m \geq 0` and `l \leq u`, and some + coefficients `c_{r,j}` from the (semi)ring ``coefficients`` + of the corresponding :class:`RegularSequenceRing`, valid + for all integers `n \geq \text{offset}` for some integer + `\text{offset} \geq \max(-l/k^m, 0)` (default: ``0``), and + there is an equation of this form (with the same + parameters `M` and `m`) for all `r` + + or the form + + - ``f(k) == t`` for some integer ``k`` and some ``t`` from the (semi)ring + ``coefficient_ring``. + + The recurrence relations above uniquely determine a `k`-regular sequence; + see [HKL2022]_ for further information. + + - ``function`` -- symbolic function ``f`` occurring in the equations + + - ``var`` -- symbolic variable (``n`` in the above description of + ``equations``) + + The following second representation of the recurrence relations is + particularly useful for cases where ``coefficient_ring`` is not + compatible with :class:`sage.symbolic.ring.SymbolicRing`. Then the + following arguments are required: + + - ``M`` -- parameter of the recursive sequences, + see [HKL2022]_, Definition 3.1, as well as in the description of + ``equations`` above + + - ``m`` -- parameter of the recursive sequences, + see [HKL2022]_, Definition 3.1, as well as in the description of + ``equations`` above + + - ``coeffs`` -- a dictionary where ``coeffs[(r, j)]`` is the + coefficient `c_{r,j}` as given in the description of ``equations`` above. + If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``, then it is + assumed to be zero. + + - ``initial_values`` -- a dictionary mapping integers ``n`` to the + ``n``-th value of the sequence + + Optional keyword-only argument: + + - ``offset`` -- (default: ``0``) an integer. See explanation of + ``equations`` above. + + - ``inhomogeneities`` -- (default: ``{}``) a dictionary + mapping integers ``r`` to the inhomogeneity `g_r` as given + in [HKL2022]_, Corollary D. All inhomogeneities have to be + regular sequences from ``self`` or elements of ``coefficient_ring``. + + OUTPUT: a :class:`RegularSequence` + + EXAMPLES: + + Stern--Brocot Sequence:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: var('n') + n + sage: function('f') + f + sage: SB = Seq2.from_recurrence([ + ....: f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1), + ....: f(0) == 0, f(1) == 1], f, n) + sage: SB + 2-regular sequence 0, 1, 1, 2, 1, 3, 2, 3, 1, 4, ... + + Number of Odd Entries in Pascal's Triangle:: + + sage: Seq2.from_recurrence([ + ....: f(2*n) == 3*f(n), f(2*n + 1) == 2*f(n) + f(n + 1), + ....: f(0) == 0, f(1) == 1], f, n) + 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ... + + Number of Unbordered Factors in the Thue--Morse Sequence:: + + sage: UB = Seq2.from_recurrence([ + ....: f(8*n) == 2*f(4*n), + ....: f(8*n + 1) == f(4*n + 1), + ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3), + ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2), + ....: f(8*n + 4) == 2*f(4*n + 2), + ....: f(8*n + 5) == f(4*n + 3), + ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3), + ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), + ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, + ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, + ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, + ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, + ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3) + sage: UB + 2-regular sequence 1, 2, 2, 4, 2, 4, 6, 0, 4, 4, ... + + Binary sum of digits `S(n)`, characterized by the recurrence relations + `S(4n) = S(2n)`, `S(4n + 1) = S(2n + 1)`, `S(4n + 2) = S(2n + 1)` and + `S(4n + 3) = -S(2n) + 2S(2n + 1)`:: + + sage: S = Seq2.from_recurrence([ + ....: f(4*n) == f(2*n), + ....: f(4*n + 1) == f(2*n + 1), + ....: f(4*n + 2) == f(2*n + 1), + ....: f(4*n + 3) == -f(2*n) + 2*f(2*n + 1), + ....: f(0) == 0, f(1) == 1], f, n) + sage: S + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... + + In order to check if this sequence is indeed the binary sum of digits, + we construct it directly via its linear representation and compare it + with ``S``:: + + sage: S2 = Seq2( + ....: (Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), + ....: left=vector([0, 1]), right=vector([1, 0])) + sage: (S - S2).is_trivial_zero() + True + + Alternatively, we can also use the simpler but inhomogeneous recurrence relations + `S(2n) = S(n)` and `S(2n+1) = S(n) + 1` via direct parameters:: + + sage: S3 = Seq2.from_recurrence(M=1, m=0, + ....: coeffs={(0, 0): 1, (1, 0): 1}, + ....: initial_values={0: 0, 1: 1}, + ....: inhomogeneities={1: 1}) + sage: S3 + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... + sage: (S3 - S2).is_trivial_zero() + True + + Number of Non-Zero Elements in the Generalized Pascal's Triangle (see [LRS2017]_):: + + sage: Seq2 = RegularSequenceRing(2, QQ) + sage: P = Seq2.from_recurrence([ + ....: f(4*n) == 5/3*f(2*n) - 1/3*f(2*n + 1), + ....: f(4*n + 1) == 4/3*f(2*n) + 1/3*f(2*n + 1), + ....: f(4*n + 2) == 1/3*f(2*n) + 4/3*f(2*n + 1), + ....: f(4*n + 3) == -1/3*f(2*n) + 5/3*f(2*n + 1), + ....: f(0) == 1, f(1) == 2], f, n) + sage: P + 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... + + Finally, the same sequence can also be obtained via direct parameters + without symbolic equations:: + + sage: Seq2.from_recurrence(M=2, m=1, + ....: coeffs={(0, 0): 5/3, (0, 1): -1/3, + ....: (1, 0): 4/3, (1, 1): 1/3, + ....: (2, 0): 1/3, (2, 1): 4/3, + ....: (3, 0): -1/3, (3, 1): 5/3}, + ....: initial_values={0: 1, 1: 2}) + 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... + + TESTS:: + + sage: Seq2.from_recurrence([ # long time + ....: f(4*n) == f(2*n), + ....: f(4*n + 1) == f(2*n), + ....: f(4*n + 2) == f(2*n), + ....: f(4*n + 3) == f(2*n + 1024), + ....: f(0) == 1, f(1) == 1], f, n, offset=2) + Traceback (most recent call last): + ... + ValueError: Initial values for arguments in [2, ..., 2044] are missing. + + :: + + sage: S = Seq2.from_recurrence([ + ....: f(4*n) == f(2*n), + ....: f(4*n + 1) == f(2*n), + ....: f(4*n + 2) == f(2*n), + ....: f(4*n + 3) == f(2*n + 16), + ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3, f(4) == 4, + ....: f(5) == 5, f(6) == 6, f(7) == 7, f(16) == 4, f(18) == 4, + ....: f(20) == 4, f(22) == 4, f(24) == 6, f(26) == 6, f(28) == 6], + ....: f, n, offset=2) + sage: all([S[4*i] == S[2*i] and + ....: S[4*i + 1] == S[2*i] and + ....: S[4*i + 2] == S[2*i] and + ....: S[4*i + 3] == S[2*i + 16] for i in srange(2, 100)]) + True + + :: + + sage: S = Seq2.from_recurrence([ + ....: f(4*n) == f(2*n), + ....: f(4*n + 1) == f(2*n), + ....: f(4*n + 2) == f(2*n), + ....: f(4*n + 3) == f(2*n - 16), + ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3, f(4) == 4, + ....: f(5) == 5, f(6) == 6, f(7) == 7, f(8) == 8, f(9) == 9, + ....: f(10) == 10, f(11) == 11, f(12) == 12, f(13) == 13, + ....: f(14) == 14, f(15) == 15, f(16) == 16, f(17) == 17, + ....: f(18) == 18, f(19) == 19, f(20) == 20, f(21) == 21, + ....: f(22) == 22, f(23) == 23, f(24) == 24, f(25) == 25, + ....: f(26) == 26, f(27) == 27, f(28) == 28, f(29) == 29, + ....: f(30) == 30, f(31) == 31], f, n, offset=8) + sage: all([S[4*i] == S[2*i] and + ....: S[4*i + 1] == S[2*i] and + ....: S[4*i + 2] == S[2*i] and + ....: S[4*i + 3] == S[2*i - 16] for i in srange(8, 100)]) + True + + Same test with different variable and function names:: + + sage: var('m') + m + sage: function('g') + g + sage: T = Seq2.from_recurrence([ + ....: g(4*m) == g(2*m), + ....: g(4*m + 1) == g(2*m), + ....: g(4*m + 2) == g(2*m), + ....: g(4*m + 3) == g(2*m - 16), + ....: g(0) == 1, g(1) == 1, g(2) == 2, g(3) == 3, g(4) == 4, + ....: g(5) == 5, g(6) == 6, g(7) == 7, g(8) == 8, g(9) == 9, + ....: g(10) == 10, g(11) == 11, g(12) == 12, g(13) == 13, + ....: g(14) == 14, g(15) == 15, g(16) == 16, g(17) == 17, + ....: g(18) == 18, g(19) == 19, g(20) == 20, g(21) == 21, + ....: g(22) == 22, g(23) == 23, g(24) == 24, g(25) == 25, + ....: g(26) == 26, g(27) == 27, g(28) == 28, g(29) == 29, + ....: g(30) == 30, g(31) == 31], g, m, offset=8) + sage: (S - T).is_trivial_zero() # long time + True + + Zero-sequence with non-zero initial values:: + + sage: Seq2.from_recurrence([ + ....: f(2*n) == 0, f(2*n + 1) == 0, + ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n) + Traceback (most recent call last): + ... + ValueError: Initial value for argument 0 does not match with the given recurrence relations. + + :: + + sage: Seq2.from_recurrence([ + ....: f(2*n) == 0, f(2*n + 1) == 0, + ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n, offset=2) + 2-regular sequence 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, ... + + Check if inhomogeneities `0` do not change the sequence:: + + sage: Seq2.from_recurrence([ + ....: f(2*n) == 0, f(2*n + 1) == 0, + ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n, offset=2, + ....: inhomogeneities={0: 0, 1: Seq2.zero()}) + 2-regular sequence 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, ... + + :: + + sage: S = Seq2([matrix([[3/2, -1, 1], [0, 1/2, 1/2], [0, -1, 2]]), + ....: matrix([[-1, 0, 1], [1, 5, -5], [-4, 0, 0]])], + ....: left=vector([1, 2, 3]), + ....: right=vector([0, 1, 1])) + sage: T = Seq2.from_recurrence(M=3, m=2, + ....: coeffs={}, + ....: initial_values={0: S[0]}, + ....: inhomogeneities={i: S.subsequence(2**3, i) for i in srange(2**3)}) + sage: (S - T).is_trivial_zero() + True + + Connection between the Stern--Brocot sequence and the number + of non-zero elements in the generalized Pascal's triangle (see + [LRS2017]_):: + + sage: U = Seq2.from_recurrence(M=1, m=0, + ....: coeffs={(0, 0): 1}, + ....: initial_values={0: 0, 1: 1}, + ....: inhomogeneities={1: P}) + sage: (U - Seq2(SB)).is_trivial_zero() + True + + :: + + sage: U = Seq2.from_recurrence(M=1, m=0, + ....: coeffs={}, + ....: initial_values={0: 0, 1: 1}, + ....: inhomogeneities={0: SB, 1: P}) + sage: (U - Seq2(SB)).is_trivial_zero() + True + + Number of Unbordered Factors in the Thue--Morse Sequence, but partly + encoded with inhomogeneities:: + + sage: UB2 = Seq2.from_recurrence([ + ....: f(8*n) == 2*f(4*n), + ....: f(8*n + 1) == f(4*n + 1), + ....: f(8*n + 2) == f(4*n + 1), + ....: f(8*n + 3) == f(4*n + 2), + ....: f(8*n + 4) == 2*f(4*n + 2), + ....: f(8*n + 5) == f(4*n + 3), + ....: f(8*n + 6) == -f(4*n + 1), + ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), + ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, + ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, + ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, + ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, + ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3, + ....: inhomogeneities={2: UB.subsequence(4, 3), 3: -UB.subsequence(4, 1), + ....: 6: UB.subsequence(4, 2) + UB.subsequence(4, 3)}) + sage: (UB2 - Seq2(UB)).is_trivial_zero() + True + """ + RP = RecurrenceParser(self.k, self.coefficient_ring()) + mu, left, right = RP(*args, **kwds) + return self(mu, left, right) + + +class RecurrenceParser(): + r""" + A parser for recurrence relations that allow + the construction of a `k`-linear representation + for the sequence satisfying these recurrence relations. + + This is used by :meth:`RegularSequenceRing.from_recurrence` + to construct a :class:`RegularSequence`. + """ + + def __init__(self, k, coefficient_ring): + r""" + See :class:`RecurrenceParser`. + + INPUT: + + - ``k`` -- an integer at least `2` specifying the base + + - ``coefficient_ring`` -- a ring. + + These are the same parameters used when creating + a :class:`RegularSequenceRing`. + + TESTS:: + + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RecurrenceParser(2, ZZ) + <sage.combinat.regular_sequence.RecurrenceParser object at 0x...> + """ + self.k = k + self.coefficient_ring = coefficient_ring + + def parse_recurrence(self, equations, function, var): + r""" + Parse recurrence relations as admissible in :meth:`RegularSequenceRing.from_recurrence`. + + INPUT: + + All parameters are explained in the high-level method + :meth:`RegularSequenceRing.from_recurrence`. + + OUTPUT: a tuple consisting of + + - ``M``, ``m`` -- see :meth:`RegularSequenceRing.from_recurrence` + + - ``coeffs`` -- see :meth:`RegularSequenceRing.from_recurrence` + + - ``initial_values`` -- see :meth:`RegularSequenceRing.from_recurrence` + + EXAMPLES:: + + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: var('n') + n + sage: function('f') + f + sage: RP.parse_recurrence([ + ....: f(4*n) == f(2*n) + 2*f(2*n + 1) + 3*f(2*n - 2), + ....: f(4*n + 1) == 4*f(2*n) + 5*f(2*n + 1) + 6*f(2*n - 2), + ....: f(4*n + 2) == 7*f(2*n) + 8*f(2*n + 1) + 9*f(2*n - 2), + ....: f(4*n + 3) == 10*f(2*n) + 11*f(2*n + 1) + 12*f(2*n - 2), + ....: f(0) == 1, f(1) == 2, f(2) == 1], f, n) + (2, 1, {(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4, + (1, 1): 5, (2, -2): 9, (2, 0): 7, (2, 1): 8, (3, -2): 12, (3, 0): 10, + (3, 1): 11}, {0: 1, 1: 2, 2: 1}) + + Stern--Brocot Sequence:: + + sage: RP.parse_recurrence([ + ....: f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1), + ....: f(0) == 0, f(1) == 1], f, n) + (1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 0, 1: 1}) + + .. SEEALSO:: + + :meth:`RegularSequenceRing.from_recurrence` + + TESTS: + + The following tests check that the equations are well-formed:: + + sage: RP.parse_recurrence([], f, n) + Traceback (most recent call last): + ... + ValueError: List of recurrence equations is empty. + + :: + + sage: RP.parse_recurrence([f(4*n + 1)], f, n) + Traceback (most recent call last): + ... + ValueError: f(4*n + 1) is not an equation with ==. + + :: + + sage: RP.parse_recurrence([42], f, n) + Traceback (most recent call last): + ... + ValueError: 42 is not a symbolic expression. + + :: + + sage: RP.parse_recurrence([f(2*n) + 1 == f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(2*n) + 1 in the equation f(2*n) + 1 == f(n) is + not an evaluation of f. + + :: + + sage: RP.parse_recurrence([f(2*n, 5) == 3], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(2*n, 5) in the equation f(2*n, 5) == 3 does not + have one argument. + + :: + + sage: RP.parse_recurrence([f() == 3], f, n) + Traceback (most recent call last): + ... + ValueError: Term f() in the equation f() == 3 does not have one + argument. + + :: + + sage: RP.parse_recurrence([f(1/n + 1) == f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(1/n + 1) in the equation f(1/n + 1) == f(n): + 1/n + 1 is not a polynomial in n with integer coefficients. + + :: + + sage: RP.parse_recurrence([f(2*n + 1/2) == f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(2*n + 1/2) in the equation f(2*n + 1/2) == f(n): + 2*n + 1/2 is not a polynomial in n with integer coefficients. + + :: + + sage: RP.parse_recurrence([f(4*n^2) == f(2*n^2)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(4*n^2) in the equation f(4*n^2) == f(2*n^2): + 4*n^2 is not a polynomial in n of degree smaller than 2. + + :: + + sage: RP.parse_recurrence([f(42) == 1/2], f, n) + Traceback (most recent call last): + ... + ValueError: Initial value 1/2 given by the equation f(42) == (1/2) + is not in Integer Ring. + + :: + + sage: RP.parse_recurrence([f(42) == 0, f(42) == 1], f, n) + Traceback (most recent call last): + ... + ValueError: Initial value f(42) is given twice. + + :: + + sage: RP.parse_recurrence([f(42) == f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Initial value f(n) given by the equation f(42) == f(n) + is not in Integer Ring. + + :: + + sage: RP.parse_recurrence([f(4*n) == f(n), f(2*n) == f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(2*n) in the equation f(2*n) == f(n): 2 does not + equal 4. Expected subsequence modulo 4 as in another equation, got + subsequence modulo 2. + + :: + + sage: RP.parse_recurrence([f(3*n + 1) == f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(3*n + 1) in the equation f(3*n + 1) == f(n): + 3 is not a power of 2. + + :: + + sage: RP.parse_recurrence([f(n + 1) == f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(n + 1) in the equation f(n + 1) == f(n): + 1 is less than 2. Modulus must be at least 2. + + :: + + sage: RP.parse_recurrence([f(2*n) == f(n), f(2*n) == 0], f, n) + Traceback (most recent call last): + ... + ValueError: There are more than one recurrence relation for f(2*n). + + :: + + sage: RP.parse_recurrence([f(2*n + 2) == f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(2*n + 2) in the equation f(2*n + 2) == f(n): + remainder 2 is not smaller than modulus 2. + + :: + + sage: RP.parse_recurrence([f(2*n - 1) == f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(2*n - 1) in the equation f(2*n - 1) == f(n): + remainder -1 is smaller than 0. + + :: + + sage: RP.parse_recurrence([f(2*n) == 2*n], f, n) + Traceback (most recent call last): + ... + ValueError: Term 2*n in the equation f(2*n) == 2*n does not + contain f. + + :: + + sage: RP.parse_recurrence([f(2*n) == 1/2*f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term 1/2*f(n) in the equation f(2*n) == 1/2*f(n): + 1/2 is not a valid coefficient since it is not in Integer Ring. + + :: + + sage: RP.parse_recurrence([f(2*n) == 1/f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: 1/f(n) is not a valid right hand side. + + :: + + sage: RP.parse_recurrence([f(2*n) == 2*n*f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: 2*n*f(n) is not a valid right hand side. + + :: + + sage: RP.parse_recurrence([f(2*n) == 2*f(n, 5)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(n, 5) in the equation f(2*n) == 2*f(n, 5) + has more than one argument. + + :: + + sage: RP.parse_recurrence([f(2*n) == 2*f()], f, n) + Traceback (most recent call last): + ... + ValueError: Term f() in the equation f(2*n) == 2*f() has no argument. + + :: + + sage: RP.parse_recurrence([f(2*n) == 1/f(n) + 2*f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term 1/f(n) in the equation f(2*n) == 1/f(n) + 2*f(n) + is not a valid summand. + + :: + + sage: RP.parse_recurrence([f(2*n) == 2*f(1/n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(1/n) in the equation f(2*n) == 2*f(1/n): + 1/n is not a polynomial in n with integer coefficients. + + :: + + sage: RP.parse_recurrence([f(2*n) == f(n + 1/2)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(n + 1/2) in the equation f(2*n) == f(n + 1/2): + n + 1/2 is not a polynomial in n with integer coefficients. + + :: + + sage: RP.parse_recurrence([f(2*n) == f(1/2*n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(1/2*n) in the equation f(2*n) == f(1/2*n): + 1/2*n is not a polynomial in n with integer coefficients. + + :: + + sage: RP.parse_recurrence([f(2*n) == f(n^2 + 1)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(n^2 + 1) in the equation f(2*n) == f(n^2 + 1): + polynomial n^2 + 1 does not have degree 1. + + :: + + sage: RP.parse_recurrence([f(2*n) == f(1)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(1) in the equation f(2*n) == f(1): + polynomial 1 does not have degree 1. + + :: + + sage: RP.parse_recurrence([f(4*n) == f(2*n) + f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(n) in the equation f(4*n) == f(2*n) + f(n): + 1 does not equal 2. Expected subsequence modulo 2 as in another + summand or equation, got subsequence modulo 1. + + :: + + sage: RP.parse_recurrence([f(4*n) == f(2*n), f(4*n + 1) == f(n)], + ....: f, n) + Traceback (most recent call last): + ... + ValueError: Term f(n) in the equation f(4*n + 1) == f(n): 1 does not + equal 2. Expected subsequence modulo 2 as in another summand or + equation, got subsequence modulo 1. + + :: + + sage: RP.parse_recurrence([f(4*n) == f(3*n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(3*n) in the equation f(4*n) == f(3*n): 3 is not + a power of 2. + + :: + + sage: RP.parse_recurrence([f(2*n) == f(4*n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(4*n) in the equation f(2*n) == f(4*n): + 4 is not smaller than 2. + + :: + + sage: RP.parse_recurrence([f(2*n) == f(2*n)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(2*n) in the equation f(2*n) == f(2*n): + 2 is not smaller than 2. + + :: + + sage: RP.parse_recurrence([f(2*n) == f(n)], f, n) + Traceback (most recent call last): + ... + ValueError: Recurrence relations for [f(2*n + 1)] are missing. + + :: + + sage: RP.parse_recurrence([f(4*n) == f(n), f(4*n + 3) == 0], f, n) + Traceback (most recent call last): + ... + ValueError: Recurrence relations for [f(4*n + 1), f(4*n + 2)] + are missing. + + :: + + sage: RP.parse_recurrence([f(42) == 0], f, n) + Traceback (most recent call last): + ... + ValueError: No recurrence relations are given. + + :: + + sage: RP.parse_recurrence( + ....: [f(4*n + r) == f(n) for r in srange(4)], f, n) + (2, 0, {(0, 0): 1, (1, 0): 1, (2, 0): 1, (3, 0): 1}, {}) + + :: + + sage: RP.parse_recurrence( + ....: [f(8*n) == f(n)] + + ....: [f(8*n + r) == f(2*n) for r in srange(1,8)], f, n) + Traceback (most recent call last): + ... + ValueError: Term f(2*n) in the equation f(8*n + 1) == f(2*n): + 2 does not equal 1. Expected subsequence modulo 1 as in another + summand or equation, got subsequence modulo 2. + + Finally, also for the zero-sequence the output is as expected:: + + sage: RP.parse_recurrence([f(2*n) == 0, f(2*n + 1) == 0], f, n) + (1, 0, {}, {}) + + We check that the output is of the correct type (:trac:`33158`):: + + sage: RP = RecurrenceParser(2, QQ) + sage: equations = [ + ....: f(4*n) == 5/3*f(2*n) - 1/3*f(2*n + 1), + ....: f(4*n + 1) == 4/3*f(2*n) + 1/3*f(2*n + 1), + ....: f(4*n + 2) == 1/3*f(2*n) + 4/3*f(2*n + 1), + ....: f(4*n + 3) == -1/3*f(2*n) + 5/3*f(2*n + 1), + ....: f(0) == 1, f(1) == 2] + sage: M, m, coeffs, initial_values = RP.parse_recurrence(equations, f, n) + sage: M.parent() + Integer Ring + sage: m.parent() + Integer Ring + sage: all(v.parent() == QQ for v in coeffs.values()) + True + sage: all(v.parent() == QQ for v in initial_values.values()) + True + + This results in giving the correct (see :trac:`33158`) minimization in:: + + sage: Seq2 = RegularSequenceRing(2, QQ) + sage: P = Seq2.from_recurrence(equations, f, n) + sage: P + 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... + sage: P.minimized() + 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... + """ + from sage.arith.srange import srange + from sage.functions.log import log + from sage.rings.integer_ring import ZZ + from sage.symbolic.operators import add_vararg, mul_vararg, operator + + k = self.k + coefficient_ring = self.coefficient_ring + M = None + m = None + coeffs = {} + initial_values = {} + remainders = set() + + def parse_multiplication(op, eq): + operands = op.operands() + assert op.operator() == mul_vararg and len(operands) == 2 + if operands[1].operator() == function: + return [operands[0], operands[1]] + elif operands[0].operator() == function: + return [operands[1], operands[0]] + else: + raise ValueError('Term %s in the equation %s ' + 'does not contain %s.' + % (op, eq, function)) + + def parse_one_summand(summand, eq): + if summand.operator() == mul_vararg: + coeff, op = parse_multiplication(summand, eq) + elif summand.operator() == function: + coeff, op = 1, summand + else: + raise ValueError('Term %s in the equation %s is not a valid summand.' + % (summand, eq)) + try: + coeff = coefficient_ring(coeff) + except (TypeError, ValueError): + raise ValueError("Term %s in the equation %s: " + "%s is not a valid coefficient " + "since it is not in %s." + % (summand, eq, coeff, coefficient_ring)) from None + if len(op.operands()) > 1: + raise ValueError('Term %s in the equation %s has more than one argument.' + % (op, eq)) + elif len(op.operands()) == 0: + raise ValueError('Term %s in the equation %s has no argument.' + % (op, eq)) + try: + poly = ZZ[var](op.operands()[0]) + except TypeError: + raise ValueError('Term %s in the equation %s: ' + '%s is not a polynomial in %s with integer coefficients.' + % (op, eq, op.operands()[0], var)) from None + if poly.degree() != 1: + raise ValueError("Term %s in the equation %s: " + "polynomial %s does not have degree 1." + % (op, eq, poly)) + d, base_power_m = list(poly) + m = log(base_power_m, base=k) + try: + m = ZZ(m) + except (TypeError, ValueError): + raise ValueError("Term %s in the equation %s: " + "%s is not a power of %s." + % (summand, eq, + k**m, k)) from None + return [coeff, m, d] + + if not equations: + raise ValueError("List of recurrence equations is empty.") + + for eq in equations: + try: + if eq.operator() != operator.eq: + raise ValueError("%s is not an equation with ==." + % eq) + except AttributeError: + raise ValueError("%s is not a symbolic expression." + % eq) from None + left_side, right_side = eq.operands() + if left_side.operator() != function: + raise ValueError("Term %s in the equation %s is not an evaluation of %s." + % (left_side, eq, function)) + if len(left_side.operands()) != 1: + raise ValueError("Term %s in the equation %s does not have " + "one argument." + % (left_side, eq)) + try: + polynomial_left = ZZ[var](left_side.operands()[0]) + except TypeError: + raise ValueError("Term %s in the equation %s: " + "%s is not a polynomial in %s with " + "integer coefficients." + % (left_side, eq, + left_side.operands()[0], var)) from None + if polynomial_left.degree() > 1: + raise ValueError("Term %s in the equation %s: " + "%s is not a polynomial in %s of degree smaller than 2." + % (left_side, eq, polynomial_left, var)) + if polynomial_left in ZZ: + try: + right_side = coefficient_ring(right_side) + except (TypeError, ValueError): + raise ValueError("Initial value %s given by the equation %s " + "is not in %s." + % (right_side, eq, coefficient_ring)) from None + if (polynomial_left in initial_values.keys() and + initial_values[polynomial_left] != right_side): + raise ValueError("Initial value %s is given twice." + % (function(polynomial_left))) + initial_values.update({polynomial_left: right_side}) + else: + [r, base_power_M] = list(polynomial_left) + M_new = log(base_power_M, base=k) + try: + M_new = ZZ(M_new) + except (TypeError, ValueError): + raise ValueError("Term %s in the equation %s: " + "%s is not a power of %s." + % (left_side, eq, + base_power_M, k)) from None + if M is not None and M != M_new: + raise ValueError(("Term {0} in the equation {1}: " + "{2} does not equal {3}. Expected " + "subsequence modulo {3} as in another " + "equation, got subsequence modulo {2}.").format( + left_side, eq, + base_power_M, k**M)) + elif M is None: + M = M_new + if M < 1: + raise ValueError(("Term {0} in the equation {1}: " + "{2} is less than {3}. Modulus must " + "be at least {3}.").format( + left_side, eq, + base_power_M, k)) + if r in remainders: + raise ValueError("There are more than one recurrence relation for %s." + % (left_side,)) + if r >= k**M: + raise ValueError("Term %s in the equation %s: " + "remainder %s is not smaller than modulus %s." + % (left_side, eq, r, k**M)) + elif r < 0: + raise ValueError("Term %s in the equation %s: " + "remainder %s is smaller than 0." + % (left_side, eq, r)) + else: + remainders.add(r) + if right_side != 0: + if (len(right_side.operands()) == 1 and right_side.operator() == function + or right_side.operator() == mul_vararg and len(right_side.operands()) == 2): + summands = [right_side] + elif right_side.operator() == add_vararg: + summands = right_side.operands() + else: + raise ValueError("%s is not a valid right hand side." + % (right_side,)) + for summand in summands: + coeff, new_m, d = parse_one_summand(summand, eq) + if m is not None and m != new_m: + raise ValueError(("Term {0} in the equation {1}: " + "{2} does not equal {3}. Expected " + "subsequence modulo {3} as in another " + "summand or equation, got subsequence " + "modulo {2}.").format( + summand, eq, + k**new_m, k**m)) + elif m is None: + m = new_m + if M <= m: + raise ValueError("Term %s in the equation %s: " + "%s is not smaller than %s." + % (summand, eq, + k**m, k**M)) + coeffs.update({(r, d): coeff}) + + if not M: + raise ValueError("No recurrence relations are given.") + elif M and m is None: # for the zero sequence + m = M - 1 + + missing_remainders = [rem for rem in srange(k**M) + if rem not in remainders] + if missing_remainders: + raise ValueError("Recurrence relations for %s are missing." + % ([function(k**M*var + rem) + for rem in missing_remainders],)) + + return (M, m, coeffs, initial_values) + + def parse_direct_arguments(self, M, m, coeffs, initial_values): + r""" + Check whether the direct arguments as admissible in + :meth:`RegularSequenceRing.from_recurrence` are valid. + + INPUT: + + All parameters are explained in the high-level method + :meth:`RegularSequenceRing.from_recurrence`. + + OUTPUT: a tuple consisting of the input parameters + + EXAMPLES:: + + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: RP.parse_direct_arguments(2, 1, + ....: {(0, -2): 3, (0, 0): 1, (0, 1): 2, + ....: (1, -2): 6, (1, 0): 4, (1, 1): 5, + ....: (2, -2): 9, (2, 0): 7, (2, 1): 8, + ....: (3, -2): 12, (3, 0): 10, (3, 1): 11}, + ....: {0: 1, 1: 2, 2: 1}) + (2, 1, {(0, -2): 3, (0, 0): 1, (0, 1): 2, + (1, -2): 6, (1, 0): 4, (1, 1): 5, + (2, -2): 9, (2, 0): 7, (2, 1): 8, + (3, -2): 12, (3, 0): 10, (3, 1): 11}, + {0: 1, 1: 2, 2: 1}) + + Stern--Brocot Sequence:: + + sage: RP.parse_direct_arguments(1, 0, + ....: {(0, 0): 1, (1, 0): 1, (1, 1): 1}, + ....: {0: 0, 1: 1}) + (1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 0, 1: 1}) + + .. SEEALSO:: + + :meth:`RegularSequenceRing.from_recurrence` + + TESTS: + + The following tests check that the equations are well-formed:: + + sage: RP.parse_direct_arguments(1/2, 0, {}, {}) + Traceback (most recent call last): + ... + ValueError: 1/2 is not a positive integer. + + :: + + sage: RP.parse_direct_arguments(0, 0, {}, {}) + Traceback (most recent call last): + .... + ValueError: 0 is not a positive integer. + + :: + + sage: RP.parse_direct_arguments(1, 1/2, {}, {}) + Traceback (most recent call last): + ... + ValueError: 1/2 is not a non-negative integer. + + :: + + sage: RP.parse_direct_arguments(1, -1, {}, {}) + Traceback (most recent call last): + ... + ValueError: -1 is not a non-negative integer. + + :: + + sage: RP.parse_direct_arguments(1, 1, {}, {}) + Traceback (most recent call last): + ... + ValueError: 1 is not larger than 1. + + :: + + sage: RP.parse_direct_arguments(1, 42, {}, {}) + Traceback (most recent call last): + ... + ValueError: 1 is not larger than 42. + + :: + + sage: RP.parse_direct_arguments(2, 1, {(0, 0): 1/2, (1, 0): i}, {}) + Traceback (most recent call last): + ... + ValueError: Coefficients [1/2, I] are not valid since they are not + in Integer Ring. + + :: + + sage: RP.parse_direct_arguments(2, 1, {(i, 0): 0, (0, 1/2): 0}, {}) + Traceback (most recent call last): + ... + ValueError: Keys [(I, 0), (0, 1/2)] for coefficients are not valid + since one of their components is no integer. + + :: + + sage: RP.parse_direct_arguments(2, 1, {(-1, 0): 0, (42, 0): 0}, {}) + Traceback (most recent call last): + ... + ValueError: Keys [(-1, 0), (42, 0)] for coefficients are not valid since + their first component is either smaller than 0 or larger than + or equal to 4. + + :: + + sage: RP.parse_direct_arguments(2, 1, {}, {0: 1/2, 1: i}) + Traceback (most recent call last): + ... + ValueError: Initial values [1/2, I] are not valid since they are + not in Integer Ring. + + :: + + sage: RP.parse_direct_arguments(2, 1, {}, {1/2: 0, i: 0}) + Traceback (most recent call last): + ... + ValueError: Keys [1/2, I] for the initial values are not valid since + they are no integers. + """ + from sage.rings.integer_ring import ZZ + + if M not in ZZ or M < 1: + raise ValueError("%s is not a positive integer." + % (M,)) from None + if m not in ZZ or m < 0: + raise ValueError("%s is not a non-negative integer." + % (m,)) from None + if M <= m: + raise ValueError("%s is not larger than %s." + % (M, m)) from None + + coefficient_ring = self.coefficient_ring + k = self.k + + invalid_coeffs = [coeff for coeff in coeffs.values() + if coeff not in coefficient_ring] + if invalid_coeffs: + raise ValueError("Coefficients %s are not valid " + "since they are not in %s." + % (invalid_coeffs, coefficient_ring)) from None + + coeffs_keys = coeffs.keys() + invalid_coeffs_keys = [key for key in coeffs_keys + if key[0] not in ZZ or key[1] not in ZZ] + if invalid_coeffs_keys: + raise ValueError("Keys %s for coefficients are not valid " + "since one of their components is no integer." + % (invalid_coeffs_keys,)) from None + + invalid_coeffs_keys = [key for key in coeffs_keys if key[0] < 0 or key[0] >= k**M] + if invalid_coeffs_keys: + raise ValueError("Keys %s for coefficients are not valid " + "since their first component is either smaller than 0 " + " or larger than or equal to %s." + % (invalid_coeffs_keys, k**M)) from None + + invalid_initial_values = [value for value in initial_values.values() + if value not in coefficient_ring] + if invalid_initial_values: + raise ValueError("Initial values %s are not valid " + "since they are not in %s." + % (invalid_initial_values, coefficient_ring)) from None + + invalid_initial_keys = [key for key in initial_values.keys() + if key not in ZZ] + if invalid_initial_keys: + raise ValueError("Keys %s for the initial values are not valid " + "since they are no integers." + % (invalid_initial_keys,)) from None + + return (M, m, coeffs, initial_values) + + def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}): + r""" + Determine parameters from recurrence relations as admissible in + :meth:`RegularSequenceRing.from_recurrence`. + + INPUT: + + All parameters are explained in the high-level method + :meth:`RegularSequenceRing.from_recurrence`. + + OUTPUT: a namedtuple ``recurrence_rules`` consisting of + + - ``M``, ``m``, ``l``, ``u``, ``offset`` -- parameters of the recursive + sequences, see [HKL2022]_, Definition 3.1 + + - ``ll``, ``uu``, ``n1``, ``dim`` -- parameters and dimension of the + resulting linear representation, see [HKL2022]_, Theorem A + + - ``coeffs`` -- a dictionary mapping ``(r, j)`` to the coefficients + `c_{r, j}` as given in [HKL2022]_, Equation (3.1). + If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``, + then it is assumed to be zero. + + - ``initial_values`` -- a dictionary mapping integers ``n`` to the + ``n``-th value of the sequence + + - ``inhomogeneities`` -- a dictionary mapping integers ``r`` + to the inhomogeneity `g_r` as given in [HKL2022]_, Corollary D. + + EXAMPLES:: + + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: RP.parameters(2, 1, + ....: {(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4, + ....: (1, 1): 5, (2, -2): 9, (2, 0): 7, (2, 1): 8, (3, -2): 12, + ....: (3, 0): 10, (3, 1): 11}, {0: 1, 1: 2, 2: 1, 3: 4}, 0, {0: 1}) + recurrence_rules(M=2, m=1, l=-2, u=1, ll=-6, uu=3, dim=14, + coeffs={(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4, + (1, 1): 5, (2, -2): 9, (2, 0): 7, (2, 1): 8, (3, -2): 12, + (3, 0): 10, (3, 1): 11}, initial_values={0: 1, 1: 2, 2: 1, 3: 4, + 4: 13, 5: 30, 6: 48, 7: 66, 8: 77, 9: 208, 10: 340, 11: 472, + 12: 220, 13: 600, -6: 0, -5: 0, -4: 0, -3: 0, -2: 0, -1: 0}, + offset=1, n1=3, inhomogeneities={0: 2-regular sequence 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, ...}) + + .. SEEALSO:: + + :meth:`RegularSequenceRing.from_recurrence` + + TESTS:: + + sage: var('n') + n + sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, + ....: {-1: 0, 1: 0, 10: 0, I: 0, n: 0}) + Traceback (most recent call last): + ... + ValueError: Indices [-1, 10, I, n] for inhomogeneities are + no integers between 0 and 1. + + :: + + sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, + ....: {0: n}) + Traceback (most recent call last): + ... + ValueError: Inhomogeneities {0: n} are neither 2-regular sequences + nor elements of Integer Ring. + + :: + + sage: Seq3 = RegularSequenceRing(3, ZZ) + sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, + ....: {0: Seq3.zero()}) + Traceback (most recent call last): + ... + ValueError: Inhomogeneities {0: 3-regular sequence 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, ...} are neither 2-regular sequences nor elements of + Integer Ring. + + :: + + sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0) + Traceback (most recent call last): + ... + ValueError: No initial values are given. + + :: + + sage: RP.parameters(1, 0, + ....: {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 1/2, 1: 2*i}, 0) + Traceback (most recent call last): + ... + ValueError: Initial values for arguments in [0, 1] are not in Integer Ring. + + :: + + sage: RP.parameters(1, 0, {(0, 0): 1}, + ....: {0: 1, 1: 0}, 0) + recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1, + coeffs={(0, 0): 1}, initial_values={0: 1, 1: 0}, offset=0, n1=0, + inhomogeneities={}) + + Finally, also for the zero-sequence the output is as expected:: + + sage: RP.parameters(1, 0, {}, {0: 0}, 0) + recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1, + coeffs={}, initial_values={0: 0}, offset=0, n1=0, inhomogeneities={}) + + :: + + sage: RP.parameters(1, 0, + ....: {(0, 0): 0, (1, 1): 0}, {0: 0}, 0) + recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1, + coeffs={(0, 0): 0, (1, 1): 0}, initial_values={0: 0}, + offset=0, n1=0, inhomogeneities={}) + """ + from collections import namedtuple + + from sage.arith.srange import srange + from sage.functions.other import ceil, floor + + coefficient_ring = self.coefficient_ring + k = self.k + keys_coeffs = coeffs.keys() + indices_right = [key[1] for key in keys_coeffs if coeffs[key]] + + if not indices_right: # the sequence is the zero sequence + l = 0 + u = 0 + else: + l = min(indices_right) + u = max(indices_right) + + if offset < max(0, -l/k**m): + offset = max(0, ceil(-l/k**m)) + + ll = (floor((l*k**(M-m) - k**M + 1)/(k**(M-m) - 1)) + 1)*(l < 0) + uu = max([ceil((u*k**(M-m) + k**M - k**m)/(k**(M-m) - 1)) - 1, k**m - 1]) + n1 = offset - floor(ll/k**M) + dim = (k**M - 1)/(k - 1) + (M - m)*(uu - ll - k**m + 1) + n1 + + if inhomogeneities: + invalid_indices = [i for i in inhomogeneities + if i not in srange(k**M)] + if invalid_indices: + raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no " + f"integers between 0 and {k**M - 1}.") + + Seq = RegularSequenceRing(k, coefficient_ring) + inhomogeneities.update({i: inhomogeneities[i] * Seq.one_hadamard() + for i in inhomogeneities + if inhomogeneities[i] in coefficient_ring}) + invalid = {i: inhomogeneities[i] for i in inhomogeneities + if not (isinstance(inhomogeneities[i].parent(), RegularSequenceRing) and + inhomogeneities[i].parent().k == k)} + if invalid: + raise ValueError(f"Inhomogeneities {invalid} are neither {k}-regular " + f"sequences nor elements of {coefficient_ring}.") + + if not initial_values: + raise ValueError("No initial values are given.") + keys_initial = initial_values.keys() + values_not_in_ring = [] + + def converted_value(n, v): + try: + return coefficient_ring(v) + except (TypeError, ValueError): + values_not_in_ring.append(n) + initial_values = {n: converted_value(n, v) + for n, v in initial_values.items()} + if values_not_in_ring: + raise ValueError("Initial values for arguments in %s are not in %s." + % (values_not_in_ring, coefficient_ring)) + + last_value_needed = max( + k**(M-1) - k**m + uu + (n1 > 0)*k**(M-1)*(k*(n1 - 1) + k - 1), # for matrix W + k**m*offset + u, + max(keys_initial)) + initial_values = self.values( + M=M, m=m, l=l, u=u, ll=ll, coeffs=coeffs, + initial_values=initial_values, last_value_needed=last_value_needed, + offset=offset, inhomogeneities=inhomogeneities) + + recurrence_rules = namedtuple('recurrence_rules', + ['M', 'm', 'l', 'u', 'll', 'uu', 'dim', + 'coeffs', 'initial_values', 'offset', 'n1', + 'inhomogeneities']) + + return recurrence_rules(M=M, m=m, l=l, u=u, ll=ll, uu=uu, dim=dim, + coeffs=coeffs, initial_values=initial_values, + offset=offset, n1=n1, inhomogeneities=inhomogeneities) + + def values(self, *, M, m, l, u, ll, coeffs, + initial_values, last_value_needed, offset, inhomogeneities): + r""" + Determine enough values of the corresponding recursive sequence by + applying the recurrence relations given in :meth:`RegularSequenceRing.from_recurrence` + to the values given in ``initial_values``. + + INPUT: + + - ``M``, ``m``, ``l``, ``u``, ``offset`` -- parameters of the + recursive sequences, see [HKL2022]_, Definition 3.1 + + - ``ll`` -- parameter of the resulting linear representation, + see [HKL2022]_, Theorem A + + - ``coeffs`` -- a dictionary where ``coeffs[(r, j)]`` is the + coefficient `c_{r,j}` as given in :meth:`RegularSequenceRing.from_recurrence`. + If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``, + then it is assumed to be zero. + + - ``initial_values`` -- a dictionary mapping integers ``n`` to the + ``n``-th value of the sequence + + - ``last_value_needed`` -- last initial value which is needed to + determine the linear representation + + - ``inhomogeneities`` -- a dictionary mapping integers ``r`` + to the inhomogeneity `g_r` as given in [HKL2022]_, Corollary D. + + OUTPUT: + + A dictionary mapping integers ``n`` to the ``n``-th value of the + sequence for all ``n`` up to ``last_value_needed``. + + EXAMPLES: + + Stern--Brocot Sequence:: + + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: RP.values(M=1, m=0, l=0, u=1, ll=0, + ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, + ....: initial_values={0: 0, 1: 1, 2: 1}, last_value_needed=20, + ....: offset=0, inhomogeneities={}) + {0: 0, 1: 1, 2: 1, 3: 2, 4: 1, 5: 3, 6: 2, 7: 3, 8: 1, 9: 4, 10: 3, + 11: 5, 12: 2, 13: 5, 14: 3, 15: 4, 16: 1, 17: 5, 18: 4, 19: 7, 20: 3} + + .. SEEALSO:: + + :meth:`RegularSequenceRing.from_recurrence` + + TESTS: + + For the equations `f(2n) = f(n)` and `f(2n + 1) = f(n) + f(n + 1)`:: + + sage: RP.values(M=1, m=0, l=0, u=1, ll=0, + ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, + ....: initial_values={0: 0, 1: 2}, last_value_needed=20, + ....: offset=0, inhomogeneities={}) + {0: 0, 1: 2, 2: 2, 3: 4, 4: 2, 5: 6, 6: 4, 7: 6, 8: 2, 9: 8, 10: 6, + 11: 10, 12: 4, 13: 10, 14: 6, 15: 8, 16: 2, 17: 10, 18: 8, 19: 14, + 20: 6} + + :: + + sage: RP.values(M=1, m=0, l=0, u=1, ll=0, + ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, + ....: initial_values={}, last_value_needed=20, offset=0, + ....: inhomogeneities={}) + Traceback (most recent call last): + ... + ValueError: Initial values for arguments in [0, 1] are missing. + + :: + + sage: RP.values(M=1, m=0, l=0, u=1, ll=0, + ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, + ....: initial_values={0: 0}, last_value_needed=20, offset=0, + ....: inhomogeneities={}) + Traceback (most recent call last): + ... + ValueError: Initial values for arguments in [1] are missing. + + :: + + sage: RP.values(M=1, m=0, l=0, u=1, ll=0, + ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, + ....: initial_values={0: 0, 2: 1}, last_value_needed=20, + ....: offset=0, inhomogeneities={}) + Traceback (most recent call last): + ... + ValueError: Initial values for arguments in [1] are missing. + + :: + + sage: RP.values(M=1, m=0, l=0, u=1, ll=0, + ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, + ....: initial_values={0: 0, 1: 2, 2:0}, last_value_needed=20, + ....: offset=0, inhomogeneities={}) + Traceback (most recent call last): + ... + ValueError: Initial value for argument 2 does not match with the given + recurrence relations. + + :: + + sage: RP.values(M=1, m=0, l=-2, u=2, ll=-2, + ....: coeffs={(0, -2): 1, (0, 2): 1, (1, -2): 1, (1, 2): 1}, + ....: initial_values={0: 0, 1: 2, 2: 4, 3: 3, 4: 2}, + ....: last_value_needed=20, offset=2, inhomogeneities={}) + {-2: 0, -1: 0, 0: 0, 1: 2, 2: 4, 3: 3, 4: 2, 5: 2, 6: 4, 7: 4, + 8: 8, 9: 8, 10: 7, 11: 7, 12: 10, 13: 10, 14: 10, 15: 10, 16: 11, + 17: 11, 18: 11, 19: 11, 20: 18} + + Finally, also for the zero-sequence the output is as expected:: + + sage: RP.values(M=1, m=0, l=0, u=0, ll=0, + ....: coeffs={}, initial_values={}, last_value_needed=10, + ....: offset=0, inhomogeneities={}) + {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0} + + :: + + sage: RP.values(M=1, m=0, l=0, u=0, ll=0, + ....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={}, + ....: last_value_needed=10, offset=0, inhomogeneities={}) + {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0} + + :: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: RP.values(M=1, m=0, l=0, u=0, ll=0, + ....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={}, + ....: last_value_needed=10, offset=0, + ....: inhomogeneities={0: Seq2.one_hadamard()}) + {0: 1, 1: 0, 2: 1, 3: 0, 4: 1, 5: 0, 6: 1, 7: 0, 8: 1, 9: 0, 10: 1} + """ + from sage.arith.srange import srange + from sage.rings.integer_ring import ZZ + + k = self.k + keys_initial = initial_values.keys() + + values = {n: None if n not in keys_initial else initial_values[n] + for n in srange(last_value_needed + 1)} + missing_values = [] + + @cached_function + def coeff(r, k): + try: + return coeffs[(r, k)] + except KeyError: + return 0 + + @cached_function + def inhomogeneity(r, n): + try: + return inhomogeneities[r][n] + except KeyError: + return 0 + + def f(n): + f_n = values[n] + if f_n is not None and f_n != "pending": + return f_n + elif f_n == "pending": + missing_values.append(n) + return 0 + else: + values.update({n: "pending"}) + q, r = ZZ(n).quo_rem(k**M) + if q < offset: + missing_values.append(n) + return sum([coeff(r, j)*f(k**m*q + j) + for j in srange(l, u + 1) + if coeff(r, j)]) + inhomogeneity(r, q) + + for n in srange(last_value_needed + 1): + values.update({n: f(n)}) + + if missing_values: + raise ValueError("Initial values for arguments in %s are missing." + % (list(set(missing_values)),)) + + for n in keys_initial: + q, r = ZZ(n).quo_rem(k**M) + if (q >= offset and + values[n] != (sum([coeff(r, j)*values[k**m*q + j] + for j in srange(l, u + 1)])) + inhomogeneity(r, q)): + raise ValueError("Initial value for argument %s does not match with " + "the given recurrence relations." + % (n,)) + + values.update({n: 0 for n in srange(ll, 0)}) + + return values + + @cached_method + def ind(self, M, m, ll, uu): + r""" + Determine the index operator corresponding to the recursive + sequence as defined in [HKL2022]_. + + INPUT: + + - ``M``, ``m`` -- parameters of the recursive sequences, + see [HKL2022]_, Definition 3.1 + + - ``ll``, ``uu`` -- parameters of the resulting linear representation, + see [HKL2022]_, Theorem A + + OUTPUT: + + A dictionary which maps both row numbers to subsequence parameters and + vice versa, i.e., + + - ``ind[i]`` -- a pair ``(j, d)`` representing the sequence `x(k^j n + d)` + in the `i`-th component (0-based) of the resulting linear representation, + + - ``ind[(j, d)]`` -- the (0-based) row number of the sequence + `x(k^j n + d)` in the linear representation. + + EXAMPLES:: + + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: RP.ind(3, 1, -3, 3) + {(0, 0): 0, (1, -1): 3, (1, -2): 2, (1, -3): 1, + (1, 0): 4, (1, 1): 5, (1, 2): 6, (1, 3): 7, (2, -1): 10, + (2, -2): 9, (2, -3): 8, (2, 0): 11, (2, 1): 12, (2, 2): 13, + (2, 3): 14, (2, 4): 15, (2, 5): 16, 0: (0, 0), 1: (1, -3), + 10: (2, -1), 11: (2, 0), 12: (2, 1), 13: (2, 2), 14: (2, 3), + 15: (2, 4), 16: (2, 5), 2: (1, -2), 3: (1, -1), 4: (1, 0), + 5: (1, 1), 6: (1, 2), 7: (1, 3), 8: (2, -3), 9: (2, -2)} + + .. SEEALSO:: + + :meth:`RegularSequenceRing.from_recurrence` + """ + from sage.arith.srange import srange + + k = self.k + ind = {} + + pos = 0 + for j in srange(m): + for d in srange(k**j): + ind.update({(j, d): pos, pos: (j, d)}) + pos += 1 + for j in srange(m, M): + for d in srange(ll, k**j - k**m + uu + 1): + ind.update({(j, d): pos, pos: (j, d)}) + pos += 1 + + return ind + + @cached_method(key=lambda self, recurrence_rules: + (recurrence_rules.M, + recurrence_rules.m, + recurrence_rules.ll, + recurrence_rules.uu, + tuple(recurrence_rules.inhomogeneities.items()))) + def shifted_inhomogeneities(self, recurrence_rules): + r""" + Return a dictionary of all needed shifted inhomogeneities as described + in the proof of Corollary D in [HKL2022]_. + + INPUT: + + - ``recurrence_rules`` -- a namedtuple generated by + :meth:`parameters` + + OUTPUT: + + A dictionary mapping `r` to the regular sequence + `\sum_i g_r(n + i)` for `g_r` as given in [HKL2022]_, Corollary D, + and `i` between `\lfloor\ell'/k^{M}\rfloor` and + `\lfloor (k^{M-1} - k^{m} + u')/k^{M}\rfloor + 1`; see [HKL2022]_, + proof of Corollary D. The first blocks of the corresponding + vector-valued sequence (obtained from its linear + representation) correspond to the sequences `g_r(n + i)` where + `i` is as in the sum above; the remaining blocks consist of + other shifts which are required for the regular sequence. + + EXAMPLES:: + + sage: from collections import namedtuple + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), + ....: left=vector([0, 1]), right=vector([1, 0])) + sage: S + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... + sage: RR = namedtuple('recurrence_rules', + ....: ['M', 'm', 'll', 'uu', 'inhomogeneities']) + sage: recurrence_rules = RR(M=3, m=0, ll=-14, uu=14, + ....: inhomogeneities={0: S, 1: S}) + sage: SI = RP.shifted_inhomogeneities(recurrence_rules) + sage: SI + {0: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ..., + 1: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ...} + + The first blocks of the corresponding vector-valued sequence correspond + to the corresponding shifts of the inhomogeneity. In this particular + case, there are no other blocks:: + + sage: lower = -2 + sage: upper = 3 + sage: SI[0].dimension() == S.dimension() * (upper - lower + 1) + True + sage: all( + ....: Seq2( + ....: SI[0].mu, + ....: vector((i - lower)*[0, 0] + list(S.left) + (upper - i)*[0, 0]), + ....: SI[0].right) + ....: == S.subsequence(1, i) + ....: for i in range(lower, upper+1)) + True + + TESTS:: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: var('n') + n + sage: function('f') + f + sage: UB = Seq2.from_recurrence([ + ....: f(8*n) == 2*f(4*n), + ....: f(8*n + 1) == f(4*n + 1), + ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3), + ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2), + ....: f(8*n + 4) == 2*f(4*n + 2), + ....: f(8*n + 5) == f(4*n + 3), + ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3), + ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), + ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, + ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, + ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, + ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, + ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3) + sage: inhomogeneities={2: UB.subsequence(4, 3), 3: -UB.subsequence(4, 1), + ....: 6: UB.subsequence(4, 2) + UB.subsequence(4, 3)} + sage: recurrence_rules_UB = RR(M=3, m=2, ll=0, uu=9, + ....: inhomogeneities=inhomogeneities) + sage: shifted_inhomog = RP.shifted_inhomogeneities(recurrence_rules_UB) + sage: shifted_inhomog + {2: 2-regular sequence 8, 8, 8, 12, 12, 16, 12, 16, 12, 24, ..., + 3: 2-regular sequence -10, -8, -8, -8, -8, -8, -8, -8, -8, -12, ..., + 6: 2-regular sequence 20, 22, 24, 28, 28, 32, 28, 32, 32, 48, ...} + sage: shifted_inhomog[2].mu[0].ncols() == 3*inhomogeneities[2].mu[0].ncols() + True + + .. SEEALSO:: + + :meth:`RegularSequenceRing.from_recurrence` + """ + from sage.arith.srange import srange + from sage.functions.other import floor + + k = self.k + M = recurrence_rules.M + m = recurrence_rules.m + ll = recurrence_rules.ll + uu = recurrence_rules.uu + inhomogeneities = recurrence_rules.inhomogeneities + + lower = floor(ll/k**M) + upper = floor((k**(M-1) - k**m + uu)/k**M) + 1 + + return {i: inhomogeneities[i].subsequence(1, {b: 1 for b in srange(lower, upper + 1)}, + minimize=False) + for i in inhomogeneities} + + def v_eval_n(self, recurrence_rules, n): + r""" + Return the vector `v(n)` as given in [HKL2022]_, Theorem A. + + INPUT: + + - ``recurrence_rules`` -- a namedtuple generated by + :meth:`parameters` + + - ``n`` -- an integer + + OUTPUT: a vector + + EXAMPLES: + + Stern--Brocot Sequence:: + + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: SB_rules = RP.parameters( + ....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, + ....: {0: 0, 1: 1, 2: 1}, 0) + sage: RP.v_eval_n(SB_rules, 0) + (0, 1, 1) + + .. SEEALSO:: + + :meth:`RegularSequenceRing.from_recurrence` + """ + from itertools import chain + + from sage.arith.srange import srange + from sage.modules.free_module_element import vector + from sage.rings.integer_ring import ZZ + + k = self.k + M = recurrence_rules.M + m = recurrence_rules.m + ll = recurrence_rules.ll + uu = recurrence_rules.uu + dim = recurrence_rules.dim - recurrence_rules.n1 + initial_values = recurrence_rules.initial_values + inhomogeneities = recurrence_rules.inhomogeneities + ind = self.ind(M, m, ll, uu) + + v = vector([initial_values[k**ind[i][0]*n + ind[i][1]] for i in srange(dim)]) + + if not all(S.is_trivial_zero() for S in inhomogeneities.values()): + Seq = list(inhomogeneities.values())[0].parent() + W = Seq.indices() + shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) + vv = [(S.coefficient_of_word(W(ZZ(n).digits(k)), multiply_left=False)) + for S in shifted_inhomogeneities.values()] + v = vector(chain(v, *vv)) + + return v + + def matrix(self, recurrence_rules, rem, correct_offset=True): + r""" + Construct the matrix for remainder ``rem`` of the linear + representation of the sequence represented by ``recurrence_rules``. + + INPUT: + + - ``recurrence_rules`` -- a namedtuple generated by + :meth:`parameters` + + - ``rem`` -- an integer between ``0`` and ``k - 1`` + + - ``correct_offset`` -- (default: ``True``) a boolean. If + ``True``, then the resulting linear representation has no + offset. See [HKL2022]_ for more information. + + OUTPUT: a matrix + + EXAMPLES: + + The following example illustrates how the coefficients in the + right-hand sides of the recurrence relations correspond to the entries of + the matrices. :: + + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: var('n') + n + sage: function('f') + f + sage: M, m, coeffs, initial_values = RP.parse_recurrence([ + ....: f(8*n) == -1*f(2*n - 1) + 1*f(2*n + 1), + ....: f(8*n + 1) == -11*f(2*n - 1) + 10*f(2*n) + 11*f(2*n + 1), + ....: f(8*n + 2) == -21*f(2*n - 1) + 20*f(2*n) + 21*f(2*n + 1), + ....: f(8*n + 3) == -31*f(2*n - 1) + 30*f(2*n) + 31*f(2*n + 1), + ....: f(8*n + 4) == -41*f(2*n - 1) + 40*f(2*n) + 41*f(2*n + 1), + ....: f(8*n + 5) == -51*f(2*n - 1) + 50*f(2*n) + 51*f(2*n + 1), + ....: f(8*n + 6) == -61*f(2*n - 1) + 60*f(2*n) + 61*f(2*n + 1), + ....: f(8*n + 7) == -71*f(2*n - 1) + 70*f(2*n) + 71*f(2*n + 1), + ....: f(0) == 0, f(1) == 1, f(2) == 2, f(3) == 3, f(4) == 4, + ....: f(5) == 5, f(6) == 6, f(7) == 7], f, n) + sage: rules = RP.parameters( + ....: M, m, coeffs, initial_values, 0) + sage: RP.matrix(rules, 0, False) + [ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0] + [ 0 -51 50 51 0 0 0 0 0 0 0 0 0 0 0 0 0] + [ 0 -61 60 61 0 0 0 0 0 0 0 0 0 0 0 0 0] + [ 0 -71 70 71 0 0 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -1 0 1 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -11 10 11 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -21 20 21 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -31 30 31 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -41 40 41 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -51 50 51 0 0 0 0 0 0 0 0 0 0 0] + sage: RP.matrix(rules, 1, False) + [ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1] + [ 0 0 0 -11 10 11 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -21 20 21 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -31 30 31 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -41 40 41 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -51 50 51 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -61 60 61 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 -71 70 71 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 -1 0 1 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 -11 10 11 0 0 0 0 0 0 0 0 0] + + Stern--Brocot Sequence:: + + sage: SB_rules = RP.parameters( + ....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, + ....: {0: 0, 1: 1, 2: 1}, 0) + sage: RP.matrix(SB_rules, 0) + [1 0 0] + [1 1 0] + [0 1 0] + sage: RP.matrix(SB_rules, 1) + [1 1 0] + [0 1 0] + [0 1 1] + + Number of Unbordered Factors in the Thue--Morse Sequence:: + + sage: M, m, coeffs, initial_values = RP.parse_recurrence([ + ....: f(8*n) == 2*f(4*n), + ....: f(8*n + 1) == f(4*n + 1), + ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3), + ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2), + ....: f(8*n + 4) == 2*f(4*n + 2), + ....: f(8*n + 5) == f(4*n + 3), + ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3), + ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), + ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, + ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, + ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, + ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, + ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n) + sage: UB_rules = RP.parameters( + ....: M, m, coeffs, initial_values, 3) + sage: RP.matrix(UB_rules, 0) + [ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 2 0 0 0 0 0 0 0 0 0 -1 0 0] + [ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 1 0 1 0 0 0 0 0 0 -4 0 0] + [ 0 0 0 0 -1 1 0 0 0 0 0 0 0 4 2 0] + [ 0 0 0 0 0 2 0 0 0 0 0 0 0 -2 0 0] + [ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 -1 1 1 0 0 0 0 0 0 2 2 0] + [ 0 0 0 0 2 0 1 0 0 0 0 0 0 -8 -4 -4] + [ 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0] + sage: RP.matrix(UB_rules, 1) + [ 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 2 0 0 0 0 0 0 0 -2 0 0] + [ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 -1 1 1 0 0 0 0 0 0 2 2 0] + [ 0 0 0 0 2 0 1 0 0 0 0 0 0 -8 -4 -4] + [ 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 -1 1 0 0 0 2 0 0] + [ 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + + .. SEEALSO:: + + :meth:`RegularSequenceRing.from_recurrence` + """ + from itertools import chain + + from sage.arith.srange import srange + from sage.functions.other import floor + from sage.matrix.constructor import Matrix + from sage.matrix.special import block_matrix, block_diagonal_matrix, zero_matrix + from sage.modules.free_module_element import vector + + coefficient_ring = self.coefficient_ring + k = self.k + M = recurrence_rules.M + m = recurrence_rules.m + l = recurrence_rules.l + ll = recurrence_rules.ll + uu = recurrence_rules.uu + dim = recurrence_rules.dim + n1 = recurrence_rules.n1 + dim_without_corr = dim - n1 + coeffs = recurrence_rules.coeffs + inhomogeneities = recurrence_rules.inhomogeneities + ind = self.ind(M, m, ll, uu) + + @cached_function + def coeff(r, k): + try: + return coeffs[(r, k)] + except KeyError: + return 0 + + def entry(i, kk): + j, d = ind[i] + if j < M - 1: + return int(kk == ind[(j + 1, k**j*rem + d)]) + else: + rem_d = k**(M-1)*rem + (d % k**M) + dd = d // k**M + if rem_d < k**M: + lambd = l - ind[(m, (k**m)*dd + l)] + return coeff(rem_d, kk + lambd) + else: + lambd = l - ind[(m, k**m*dd + k**m + l)] + return coeff(rem_d - k**M, kk + lambd) + + mat = Matrix(coefficient_ring, dim_without_corr, dim_without_corr, entry) + + if not all(S.is_trivial_zero() for S in inhomogeneities.values()): + shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) + lower = floor(ll/k**M) + upper = floor((k**(M-1) - k**m + uu)/k**M) + 1 + + def wanted_inhomogeneity(row): + j, d = ind[row] + if j != M - 1: + return (None, None) + rem_d = k**(M-1)*rem + (d % k**M) + dd = d // k**M + if rem_d < k**M: + return (rem_d, dd) + elif rem_d >= k**M: + return (rem_d - k**M, dd + 1) + else: + return (None, None) + + def left_for_inhomogeneity(wanted): + return list(chain(*[(wanted == (r, i))*inhomogeneity.left + for r, inhomogeneity in inhomogeneities.items() + for i in srange(lower, upper + 1)])) + + def matrix_row(row): + wanted = wanted_inhomogeneity(row) + return left_for_inhomogeneity(wanted) + + mat_upper_right = Matrix([matrix_row(row) for row in srange(dim_without_corr)]) + mat_inhomog = block_diagonal_matrix([S.mu[rem] + for S in shifted_inhomogeneities.values()], + subdivide=False) + + mat = block_matrix([[mat, mat_upper_right], + [zero_matrix(mat_inhomog.nrows(), dim_without_corr), + mat_inhomog]], subdivide=False) + + dim_without_corr = mat.ncols() + dim = dim_without_corr + n1 + + if n1 > 0 and correct_offset: + W = Matrix(coefficient_ring, dim_without_corr, 0) + for i in srange(n1): + W = W.augment( + self.v_eval_n(recurrence_rules, k*i + rem) - + mat*self.v_eval_n(recurrence_rules, i)) + + J = Matrix(coefficient_ring, 0, n1) + for i in srange(n1): + J = J.stack(vector([int(j*k == i - rem) for j in srange(n1)])) + + Z = zero_matrix(coefficient_ring, n1, dim_without_corr) + mat = block_matrix([[mat, W], [Z, J]], subdivide=False) + + return mat + + def left(self, recurrence_rules): + r""" + Construct the vector ``left`` of the linear representation of + recursive sequences. + + INPUT: + + - ``recurrence_rules`` -- a namedtuple generated by + :meth:`parameters`; it only needs to contain a field + ``dim`` (a positive integer) + + OUTPUT: a vector + + EXAMPLES:: + + sage: from collections import namedtuple + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: RRD = namedtuple('recurrence_rules_dim', + ....: ['dim', 'inhomogeneities']) + sage: recurrence_rules = RRD(dim=5, inhomogeneities={}) + sage: RP.left(recurrence_rules) + (1, 0, 0, 0, 0) + + :: + + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: RRD = namedtuple('recurrence_rules_dim', + ....: ['M', 'm', 'll', 'uu', 'dim', 'inhomogeneities']) + sage: recurrence_rules = RRD(M=3, m=2, ll=0, uu=9, dim=5, + ....: inhomogeneities={0: Seq2.one_hadamard()}) + sage: RP.left(recurrence_rules) + (1, 0, 0, 0, 0, 0, 0, 0) + + .. SEEALSO:: + + :meth:`RegularSequenceRing.from_recurrence` + """ + from sage.modules.free_module_element import vector + + dim = recurrence_rules.dim + inhomogeneities = recurrence_rules.inhomogeneities + + if not all(S.is_trivial_zero() for S in inhomogeneities.values()): + shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) + dim += sum(shifted_inhomogeneities[i].mu[0].ncols() + for i in shifted_inhomogeneities) + + return vector([1] + (dim - 1)*[0]) + + def right(self, recurrence_rules): + r""" + Construct the vector ``right`` of the linear + representation of the sequence induced by ``recurrence_rules``. + + INPUT: + + - ``recurrence_rules`` -- a namedtuple generated by + :meth:`parameters` + + OUTPUT: a vector + + .. SEEALSO:: + + :meth:`RegularSequenceRing.from_recurrence` + + TESTS: + + Stern--Brocot Sequence:: + + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: var('n') + n + sage: function('f') + f + sage: SB_rules = RP.parameters( + ....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, + ....: {0: 0, 1: 1, 2: 1}, 0) + sage: RP.right(SB_rules) + (0, 1, 1) + + Number of Unbordered Factors in the Thue--Morse Sequence:: + + sage: M, m, coeffs, initial_values = RP.parse_recurrence([ + ....: f(8*n) == 2*f(4*n), + ....: f(8*n + 1) == f(4*n + 1), + ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3), + ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2), + ....: f(8*n + 4) == 2*f(4*n + 2), + ....: f(8*n + 5) == f(4*n + 3), + ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3), + ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), + ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, + ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, + ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, + ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, + ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n) + sage: UB_rules = RP.parameters( + ....: M, m, coeffs, initial_values, 3) + sage: RP.right(UB_rules) + (1, 1, 2, 1, 2, 2, 4, 2, 4, 6, 0, 4, 4, 1, 0, 0) + """ + from sage.modules.free_module_element import vector + + n1 = recurrence_rules.n1 + right = self.v_eval_n(recurrence_rules, 0) + + if n1 >= 1: + right = vector(list(right) + [1] + (n1 - 1)*[0]) + + return right + + def __call__(self, *args, **kwds): + r""" + Construct a `k`-linear representation that fulfills the recurrence relations + given in ``equations``. + + This is the main method of :class:`RecurrenceParser` and + is called by :meth:`RegularSequenceRing.from_recurrence` + to construct a :class:`RegularSequence`. + + INPUT: + + All parameters are explained in the high-level method + :meth:`RegularSequenceRing.from_recurrence`. + + OUTPUT: a linear representation ``(left, mu, right)`` + + Many examples can be found in + :meth:`RegularSequenceRing.from_recurrence`. + + TESTS:: + + sage: from sage.combinat.regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: var('n') + n + sage: function('f') + f + + sage: RP([f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1), + ....: f(0) == 0, f(1) == 1], f, n) + ([ + [1 0 0] [1 1 0] + [1 1 0] [0 1 0] + [0 1 0], [0 1 1] + ], + (1, 0, 0), + (0, 1, 1)) + + sage: RP(equations=[f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1), + ....: f(0) == 0, f(1) == 1], function=f, var=n) + ([ + [1 0 0] [1 1 0] + [1 1 0] [0 1 0] + [0 1 0], [0 1 1] + ], + (1, 0, 0), + (0, 1, 1)) + + sage: RP(1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 0, 1: 1}) + ([ + [1 0 0] [1 1 0] + [1 1 0] [0 1 0] + [0 1 0], [0 1 1] + ], + (1, 0, 0), + (0, 1, 1)) + + sage: RP(M=1, m=0, + ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, + ....: initial_values={0: 0, 1: 1}) + ([ + [1 0 0] [1 1 0] + [1 1 0] [0 1 0] + [0 1 0], [0 1 1] + ], + (1, 0, 0), + (0, 1, 1)) + """ + from sage.arith.srange import srange + + k = self.k + if len(args) == 3: + M, m, coeffs, initial_values = self.parse_recurrence(*args) + elif len(args) == 0 and all(kwd in kwds for kwd in ['equations', 'function', 'var']): + args = (kwds.pop('equations'), + kwds.pop('function'), + kwds.pop('var')) + M, m, coeffs, initial_values = self.parse_recurrence(*args) + elif len(args) == 4: + M, m, coeffs, initial_values = self.parse_direct_arguments(*args) + elif len(args) == 0 and all(kwd in kwds for kwd in ['M', 'm', 'coeffs', 'initial_values']): + args = (kwds.pop('M'), + kwds.pop('m'), + kwds.pop('coeffs'), + kwds.pop('initial_values')) + M, m, coeffs, initial_values = self.parse_direct_arguments(*args) + else: + raise ValueError("Number of positional arguments must be three or four or all arguments provided as keywords.") + + recurrence_rules = self.parameters(M, m, coeffs, initial_values, **kwds) + + mu = [self.matrix(recurrence_rules, rem) + for rem in srange(k)] + + left = self.left(recurrence_rules) + right = self.right(recurrence_rules) + + return (mu, left, right) diff --git a/src/sage/combinat/ribbon_shaped_tableau.py b/src/sage/combinat/ribbon_shaped_tableau.py index ef860b9703d..a5bfc841e7b 100644 --- a/src/sage/combinat/ribbon_shaped_tableau.py +++ b/src/sage/combinat/ribbon_shaped_tableau.py @@ -1,7 +1,7 @@ r""" Ribbon Shaped Tableaux """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>, # # Distributed under the terms of the GNU General Public License (GPL) @@ -13,8 +13,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.skew_tableau import SkewTableau, SkewTableaux, StandardSkewTableaux from sage.combinat.tableau import Tableaux @@ -78,6 +78,18 @@ def __classcall_private__(cls, rows): sage: RibbonShapedTableau([[2,3],[1,4,5]]) [[None, None, 2, 3], [1, 4, 5]] + + TESTS:: + + sage: RibbonShapedTableau([4,5]) + Traceback (most recent call last): + ... + TypeError: rows must be lists of positive integers + + sage: RibbonShapedTableau([[2,3],[-4,5]]) + Traceback (most recent call last): + ... + TypeError: r must be a list of positive integers """ try: r = [tuple(r) for r in rows] @@ -85,7 +97,8 @@ def __classcall_private__(cls, rows): raise TypeError("rows must be lists of positive integers") if not r: return StandardRibbonShapedTableaux()(r) - if all(all(j is None or (isinstance(j, (int, Integer)) and j>0) for j in i) for i in r): + if all(j is None or (isinstance(j, (int, Integer)) and j > 0) + for i in r for j in i): return StandardRibbonShapedTableaux()(r) raise TypeError("r must be a list of positive integers") @@ -99,13 +112,13 @@ def __init__(self, parent, t): sage: TestSuite(R).run() """ if not isinstance(t, SkewTableau): - #scrubing None - t = [ [i for i in row if i is not None] for row in t] + # scrubbing None + t = [[i for i in row if i is not None] for row in t] st = [] space_count = 0 for row in reversed(t): - st.append( [None]*space_count + row ) + st.append([None] * space_count + row) space_count += len(row) - 1 st.reverse() t = st @@ -136,7 +149,7 @@ def spin(self): sage: RibbonShapedTableau([[2,3],[1,4,5]]).spin() 1/2 """ - return Integer(self.height()-1)/2 + return Integer(self.height() - 1) / 2 def width(self): """ @@ -173,9 +186,9 @@ class based on input. sage: S1 is S2 True """ - #if shape is not None: - # from sage.combinat.partition import Partition - # return RibbonShapedTableaux_shape(Partition(shape)) + # if shape is not None: + # from sage.combinat.partition import Partition + # return RibbonShapedTableaux_shape(Partition(shape)) # Otherwise arg0 takes the place of the category in pickling return super(RibbonShapedTableaux, cls).__classcall__(cls, **kwds) @@ -218,7 +231,7 @@ def from_shape_and_word(self, shape, word): pos = 0 r = [] for l in shape: - r.append(word[pos:pos+l]) + r.append(word[pos:pos + l]) pos += l return self.element_class(self, r) @@ -313,7 +326,7 @@ def from_shape_and_word(self, shape, word): pos = 0 r = [] for l in shape: - r.append(word[pos:pos+l]) + r.append(word[pos:pos + l]) pos += l return self.element_class(self, r) @@ -344,9 +357,9 @@ def from_permutation(self, p): r = [] r.append([p[j] for j in range(comp[0])]) - for i in range(len(comp)-1): - r.append([ p[j] for j in range(comp[i],comp[i+1]) ]) - r.append( [ p[j] for j in range(comp[-1], len(p))] ) + for i in range(len(comp) - 1): + r.append([p[j] for j in range(comp[i], comp[i + 1])]) + r.append([p[j] for j in range(comp[-1], len(p))]) r.reverse() return self.element_class(self, r) @@ -405,7 +418,7 @@ def _repr_(self): sage: StandardRibbonShapedTableaux([2,2]) Standard ribbon shaped tableaux of shape [2, 2] """ - return "Standard ribbon shaped tableaux of shape %s"%list(self.shape) + return "Standard ribbon shaped tableaux of shape %s" % list(self.shape) def first(self): """ diff --git a/src/sage/combinat/ribbon_tableau.py b/src/sage/combinat/ribbon_tableau.py index a2955884c7d..843626c4752 100644 --- a/src/sage/combinat/ribbon_tableau.py +++ b/src/sage/combinat/ribbon_tableau.py @@ -664,19 +664,19 @@ def spin_polynomial(part, weight, length): EXAMPLES:: sage: from sage.combinat.ribbon_tableau import spin_polynomial - sage: spin_polynomial([6,6,6],[4,2],3) + sage: spin_polynomial([6,6,6],[4,2],3) # optional - sage.symbolic t^6 + t^5 + 2*t^4 + t^3 + t^2 - sage: spin_polynomial([6,6,6],[4,1,1],3) + sage: spin_polynomial([6,6,6],[4,1,1],3) # optional - sage.symbolic t^6 + 2*t^5 + 3*t^4 + 2*t^3 + t^2 - sage: spin_polynomial([3,3,3,2,1], [2,2], 3) + sage: spin_polynomial([3,3,3,2,1], [2,2], 3) # optional - sage.symbolic t^(7/2) + t^(5/2) - sage: spin_polynomial([3,3,3,2,1], [2,1,1], 3) + sage: spin_polynomial([3,3,3,2,1], [2,1,1], 3) # optional - sage.symbolic 2*t^(7/2) + 2*t^(5/2) + t^(3/2) - sage: spin_polynomial([3,3,3,2,1], [1,1,1,1], 3) + sage: spin_polynomial([3,3,3,2,1], [1,1,1,1], 3) # optional - sage.symbolic 3*t^(7/2) + 5*t^(5/2) + 3*t^(3/2) + sqrt(t) - sage: spin_polynomial([5,4,3,2,1,1,1], [2,2,1], 3) + sage: spin_polynomial([5,4,3,2,1,1,1], [2,2,1], 3) # optional - sage.symbolic 2*t^(9/2) + 6*t^(7/2) + 2*t^(5/2) - sage: spin_polynomial([[6]*6, [3,3]], [4,4,2], 3) + sage: spin_polynomial([[6]*6, [3,3]], [4,4,2], 3) # optional - sage.symbolic 3*t^9 + 5*t^8 + 9*t^7 + 6*t^6 + 3*t^5 """ from sage.symbolic.ring import SR @@ -1083,7 +1083,9 @@ def __contains__(self, x): return all(xi.is_semistandard() for xi in x) def __iter__(self): - """ + r""" + Iterate over ``self``. + EXAMPLES:: sage: sp = SkewPartitions(3).list() @@ -1098,6 +1100,21 @@ def __iter__(self): 34 sage: RibbonTableaux(a,weight,k).cardinality() 34 + + TESTS: + + Check that :issue:`36196` is fixed:: + + sage: shapes = [[[1], [0]], [[1], [0]], [[1], [0]]] + sage: weight = [1, 1, 1] + sage: SMST = SemistandardMultiSkewTableaux(shapes, weight) + sage: list(SMST) + [[[[1]], [[2]], [[3]]], + [[[2]], [[1]], [[3]]], + [[[1]], [[3]], [[2]]], + [[[2]], [[3]], [[1]]], + [[[3]], [[1]], [[2]]], + [[[3]], [[2]], [[1]]]] """ parts = self._shape mu = self._weight @@ -1122,9 +1139,12 @@ def __iter__(self): S = SkewTableaux() for lk in l: pos = 0 # Double check this - restmp = [S.from_shape_and_word(parts[0], [lk[j] for j in range(s[0])])] + lk = list(lk) + w = lk[:s[0]] + restmp = [S.from_shape_and_word(parts[0], w)] for i in range(1, len(parts)): - w = [lk[j] for j in range(pos + s[i - 1], pos + s[i - 1] + s[i])] + pos += s[i-1] + w = lk[pos: pos + s[i]] restmp.append(S.from_shape_and_word(parts[i], w)) yield self.element_class(self, restmp) diff --git a/src/sage/combinat/rigged_configurations/bij_abstract_class.py b/src/sage/combinat/rigged_configurations/bij_abstract_class.py index c06680c4cf2..66ad0ac37ce 100644 --- a/src/sage/combinat/rigged_configurations/bij_abstract_class.py +++ b/src/sage/combinat/rigged_configurations/bij_abstract_class.py @@ -17,7 +17,7 @@ - Travis Scrimshaw (2011-04-15): Initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011, 2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -29,8 +29,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from copy import deepcopy from sage.misc.abstract_method import abstract_method @@ -120,19 +120,19 @@ def run(self, verbose=False): """ if verbose: from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element \ - import TensorProductOfKirillovReshetikhinTableauxElement + import TensorProductOfKirillovReshetikhinTableauxElement for cur_crystal in reversed(self.tp_krt): target = cur_crystal.parent()._r # Iterate through the columns for col_number, cur_column in enumerate(reversed(cur_crystal.to_array(False))): - self.cur_path.insert(0, []) # Prepend an empty list + self.cur_path.insert(0, []) # Prepend an empty list self.cur_dims.insert(0, [0, 1]) for letter in reversed(cur_column): self.cur_dims[0][0] = self._next_index(self.cur_dims[0][0], target) - val = letter.value # Convert from a CrystalOfLetter to an Integer + val = letter.value # Convert from a CrystalOfLetter to an Integer if verbose: print("====================") @@ -142,7 +142,7 @@ def run(self, verbose=False): print("--------------------\n") # Build the next state - self.cur_path[0].insert(0, [letter]) # Prepend the value + self.cur_path[0].insert(0, [letter]) # Prepend the value self.next_state(val) # If we've split off a column, we need to merge the current column @@ -166,7 +166,7 @@ def run(self, verbose=False): for a in range(self.n): self._update_vacancy_nums(a) - self.ret_rig_con.set_immutable() # Return it to immutable + self.ret_rig_con.set_immutable() # Return it to immutable return self.ret_rig_con @abstract_method @@ -220,7 +220,7 @@ def _update_vacancy_nums(self, a): """ # Check to make sure we have a valid index (currently removed) # If the current tableau is empty, there is nothing to do - if not self.ret_rig_con[a]: # Check to see if we have vacancy numbers + if not self.ret_rig_con[a]: # Check to see if we have vacancy numbers return # Setup the first block @@ -268,7 +268,7 @@ def _update_partition_values(self, a): pos = 0 width = rigged_partition[index] val = rigged_partition.rigging[index] - for i in reversed(range(index-1)): + for i in reversed(range(index - 1)): if rigged_partition[i] > width or rigged_partition.rigging[i] >= val: pos = i + 1 break @@ -333,7 +333,7 @@ def __init__(self, RC_element): # This is a dummy edge to start the process cp = RC_element.__copy__() cp.set_immutable() - self._graph = [ [[], (cp, 0)] ] + self._graph = [[[], (cp, 0)]] def __eq__(self, rhs): r""" @@ -414,7 +414,7 @@ def run(self, verbose=False, build_graph=False): y = self.rigged_con.parent()(*[x._clone() for x in self.cur_partitions], use_vacancy_numbers=True) self._graph.append([self._graph[-1][1], (y, len(self._graph)), 'ls']) - while self.cur_dims[0][0]: # > 0: + while self.cur_dims[0][0]: # > 0: if verbose: print("====================") print(repr(self.rigged_con.parent()(*self.cur_partitions, use_vacancy_numbers=True))) @@ -427,16 +427,16 @@ def run(self, verbose=False, build_graph=False): b = self.next_state(ht) # Make sure we have a crystal letter - ret_crystal_path[-1].append(letters(b)) # Append the rank + ret_crystal_path[-1].append(letters(b)) # Append the rank if build_graph: y = self.rigged_con.parent()(*[x._clone() for x in self.cur_partitions], use_vacancy_numbers=True) self._graph.append([self._graph[-1][1], (y, len(self._graph)), letters(b)]) - self.cur_dims.pop(0) # Pop off the leading column + self.cur_dims.pop(0) # Pop off the leading column if build_graph: - self._graph.pop(0) # Remove the dummy at the start + self._graph.pop(0) # Remove the dummy at the start from sage.graphs.digraph import DiGraph from sage.graphs.dot2tex_utils import have_dot2tex self._graph = DiGraph(self._graph, format="list_of_edges") diff --git a/src/sage/combinat/rigged_configurations/bij_infinity.py b/src/sage/combinat/rigged_configurations/bij_infinity.py index fa1067ccd93..8d9700e168a 100644 --- a/src/sage/combinat/rigged_configurations/bij_infinity.py +++ b/src/sage/combinat/rigged_configurations/bij_infinity.py @@ -175,13 +175,13 @@ def _call_(self, x): if ct.type() == 'D': lam[-2] = max(lam[-2], lam[-1]) lam.pop() - l = sum([ [[r+1,1]]*v for r,v in enumerate(lam[:-1]) ], []) + l = sum([[[r+1, 1]]*v for r, v in enumerate(lam[:-1])], []) n = len(I) - l = l + sum([ [[n,1], [n-1,1]] for k in range(lam[-1])], []) + l = l + sum([[[n,1], [n-1,1]] for k in range(lam[-1])], []) else: if ct.type() == 'B': lam[-1] *= 2 - l = sum([ [[r,1]]*lam[i] for i,r in enumerate(I) ], []) + l = sum([[[r, 1]]*lam[i] for i, r in enumerate(I)], []) RC = RiggedConfigurations(ct.affine(), reversed(l)) elt = RC(x) diff --git a/src/sage/combinat/rigged_configurations/bij_type_A.py b/src/sage/combinat/rigged_configurations/bij_type_A.py index a700b0b4ba7..198ba0fc433 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_A.py +++ b/src/sage/combinat/rigged_configurations/bij_type_A.py @@ -21,7 +21,7 @@ sage: TestSuite(bijection).run() """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011, 2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -33,8 +33,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.rigged_configurations.bij_abstract_class import KRTToRCBijectionAbstract from sage.combinat.rigged_configurations.bij_abstract_class import RCToKRTBijectionAbstract @@ -122,7 +122,7 @@ def next_state(self, height): sage: bijection.next_state(1) 5 """ - height -= 1 # indexing + height -= 1 # indexing n = self.n ell = [None] * n b = None @@ -158,4 +158,4 @@ def next_state(self, height): if row_num is not None: self.cur_partitions[n - 1].rigging[row_num] = self.cur_partitions[n - 1].vacancy_numbers[row_num] - return(b) + return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py b/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py index 934a92851a5..dee72713e12 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py +++ b/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py @@ -20,7 +20,7 @@ sage: TestSuite(bijection).run() """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -32,8 +32,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.rigged_configurations.bij_type_C import KRTToRCBijectionTypeC from sage.combinat.rigged_configurations.bij_type_C import RCToKRTBijectionTypeC @@ -155,7 +155,7 @@ def next_state(self, val): else: j = i - 1 while j >= 0 and partition._list[j] <= max_width + 2: - partition.rigging[j+1] = partition.rigging[j] # Shuffle it along + partition.rigging[j+1] = partition.rigging[j] # Shuffle it along j -= 1 partition._list.pop(i) partition._list.insert(j+1, max_width + 2) @@ -219,7 +219,7 @@ def next_state(self, height): sage: bijection.next_state(2) -1 """ - height -= 1 # indexing + height -= 1 # indexing n = self.n ell = [None] * (2*n) case_S = [False] * n @@ -333,4 +333,4 @@ def next_state(self, height): else: self.cur_partitions[n-1].rigging[row_num_bar_next] = self.cur_partitions[n-1].vacancy_numbers[row_num_bar_next] - return(b) + return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_A2_even.py b/src/sage/combinat/rigged_configurations/bij_type_A2_even.py index 76dcca00f1f..1c0d587139a 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_A2_even.py +++ b/src/sage/combinat/rigged_configurations/bij_type_A2_even.py @@ -20,7 +20,7 @@ sage: TestSuite(bijection).run() """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -32,8 +32,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.rigged_configurations.bij_type_A import KRTToRCBijectionTypeA from sage.combinat.rigged_configurations.bij_type_C import KRTToRCBijectionTypeC @@ -139,7 +139,7 @@ def next_state(self, height): sage: bijection.next_state(2) -1 """ - height -= 1 # indexing + height -= 1 # indexing n = self.n ell = [None] * (2*n) case_S = [False] * n @@ -213,4 +213,4 @@ def next_state(self, height): if row_num_bar is not None: self.cur_partitions[n-1].rigging[row_num_bar] = self.cur_partitions[n-1].vacancy_numbers[row_num_bar] - return(b) + return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_A2_odd.py b/src/sage/combinat/rigged_configurations/bij_type_A2_odd.py index 477cbf6f9ab..42a8cf956fb 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_A2_odd.py +++ b/src/sage/combinat/rigged_configurations/bij_type_A2_odd.py @@ -20,7 +20,7 @@ sage: TestSuite(bijection).run() """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -32,8 +32,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.rigged_configurations.bij_type_A import KRTToRCBijectionTypeA from sage.combinat.rigged_configurations.bij_type_A import RCToKRTBijectionTypeA @@ -126,7 +126,7 @@ def next_state(self, height): sage: bijection.next_state(1) -2 """ - height -= 1 # indexing + height -= 1 # indexing n = self.n ell = [None] * (2*n) b = None @@ -194,4 +194,4 @@ def next_state(self, height): if ret_row_next is not None: self.cur_partitions[n-1].rigging[ret_row_next] = self.cur_partitions[n-1].vacancy_numbers[ret_row_next] - return(b) + return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_B.py b/src/sage/combinat/rigged_configurations/bij_type_B.py index 0f672e8fc2b..fd924150380 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_B.py +++ b/src/sage/combinat/rigged_configurations/bij_type_B.py @@ -20,7 +20,7 @@ sage: TestSuite(bijection).run() """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -32,8 +32,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.rigged_configurations.bij_type_A import KRTToRCBijectionTypeA from sage.combinat.rigged_configurations.bij_type_C import KRTToRCBijectionTypeC @@ -92,7 +92,7 @@ def run(self, verbose=False): """ if verbose: from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element \ - import TensorProductOfKirillovReshetikhinTableauxElement + import TensorProductOfKirillovReshetikhinTableauxElement for cur_crystal in reversed(self.tp_krt): r = cur_crystal.parent().r() @@ -108,7 +108,7 @@ def run(self, verbose=False): if verbose: print("====================") if len(self.cur_path) == 0: - print(repr([])) # Special case for displaying when the rightmost factor is a spinor + print(repr([])) # Special case for displaying when the rightmost factor is a spinor else: print(repr(TensorProductOfKirillovReshetikhinTableauxElement(self.tp_krt.parent(), self.cur_path))) print("--------------------") @@ -143,14 +143,14 @@ def run(self, verbose=False): r = cur_crystal.parent().r() # Iterate through the columns for col_number, cur_column in enumerate(reversed(cur_crystal.to_array(False))): - bij.cur_path.insert(0, []) # Prepend an empty list + bij.cur_path.insert(0, []) # Prepend an empty list bij.cur_dims.insert(0, [0, 1]) # Note that we do not need to worry about iterating over columns # (see previous note about the data structure). for letter in reversed(cur_column): bij.cur_dims[0][0] += 1 - val = letter.value # Convert from a CrystalOfLetter to an Integer + val = letter.value # Convert from a CrystalOfLetter to an Integer if verbose: print("====================") @@ -160,7 +160,7 @@ def run(self, verbose=False): print("--------------------\n") # Build the next state - bij.cur_path[0].insert(0, [letter]) # Prepend the value + bij.cur_path[0].insert(0, [letter]) # Prepend the value bij.next_state(val) # If we've split off a column, we need to merge the current column @@ -201,14 +201,14 @@ def run(self, verbose=False): # Perform the regular type B_n^{(1)} bijection # Iterate through the columns for col_number, cur_column in enumerate(reversed(cur_crystal.to_array(False))): - self.cur_path.insert(0, []) # Prepend an empty list + self.cur_path.insert(0, []) # Prepend an empty list self.cur_dims.insert(0, [0, 1]) # Note that we do not need to worry about iterating over columns # (see previous note about the data structure). for letter in reversed(cur_column): self.cur_dims[0][0] += 1 - val = letter.value # Convert from a CrystalOfLetter to an Integer + val = letter.value # Convert from a CrystalOfLetter to an Integer if verbose: print("====================") @@ -218,7 +218,7 @@ def run(self, verbose=False): print("--------------------\n") # Build the next state - self.cur_path[0].insert(0, [letter]) # Prepend the value + self.cur_path[0].insert(0, [letter]) # Prepend the value self.next_state(val) # If we've split off a column, we need to merge the current column @@ -241,7 +241,7 @@ def run(self, verbose=False): # And perform the inverse column splitting map on the RC for a in range(self.n): self._update_vacancy_nums(a) - self.ret_rig_con.set_immutable() # Return it to immutable + self.ret_rig_con.set_immutable() # Return it to immutable return self.ret_rig_con def next_state(self, val): @@ -371,7 +371,7 @@ def next_state(self, val): # Add 2 boxes j = i - 1 while j >= 0 and p._list[j] <= max_width + 2: - p.rigging[j+1] = p.rigging[j] # Shuffle it along + p.rigging[j+1] = p.rigging[j] # Shuffle it along j -= 1 p._list.pop(i) p._list.insert(j+1, max_width + 2) @@ -379,7 +379,7 @@ def next_state(self, val): break if p._list[i] == max_width and not singular_max_width: - p._list[i] += 1 # We always at least add a box to the first singular value + p._list[i] += 1 # We always at least add a box to the first singular value p.rigging[i] = None if case_QS: width_n = p._list[i] @@ -402,7 +402,7 @@ def next_state(self, val): # to attempt both # Make a *deep* copy of the element cp = self.ret_rig_con.__copy__() - for i,rp in enumerate(cp): + for i, rp in enumerate(cp): cp[i] = rp._clone() # We attempt case (S) first self._insert_cell_case_S(p) @@ -493,7 +493,7 @@ def other_outcome(self, rc, pos_val, width_n): p.rigging[i] = None case_QS = True break - if not case_QS: # we have not added a box yet + if not case_QS: # we have not added a box yet p._list.append(1) p.rigging.append(None) p.vacancy_numbers.append(None) @@ -641,7 +641,7 @@ def run(self, verbose=False, build_graph=False): y = self.rigged_con.parent()(*[x._clone() for x in self.cur_partitions], use_vacancy_numbers=True) self._graph.append([self._graph[-1][1], (y, len(self._graph)), 'ls']) - while bij.cur_dims[0][0]: # > 0: + while bij.cur_dims[0][0]: # > 0: if verbose: print("====================") print(repr(RC(*bij.cur_partitions, use_vacancy_numbers=True))) @@ -653,15 +653,15 @@ def run(self, verbose=False, build_graph=False): bij.cur_dims[0][0] = bij._next_index(ht) b = bij.next_state(ht) # Make sure we have a crystal letter - ret_crystal_path[-1].append(letters(b)) # Append the rank + ret_crystal_path[-1].append(letters(b)) # Append the rank if build_graph: y = self.rigged_con.parent()(*[x._clone() for x in self.cur_partitions], use_vacancy_numbers=True) self._graph.append([self._graph[-1][1], (y, len(self._graph)), letters(b)]) - bij.cur_dims.pop(0) # Pop off the leading column + bij.cur_dims.pop(0) # Pop off the leading column - self.cur_dims.pop(0) # Pop off the spin rectangle + self.cur_dims.pop(0) # Pop off the spin rectangle self.cur_partitions = bij.cur_partitions # Convert the n-th partition back into the special type B one @@ -712,7 +712,7 @@ def run(self, verbose=False, build_graph=False): y = self.rigged_con.parent()(*[x._clone() for x in self.cur_partitions], use_vacancy_numbers=True) self._graph.append([self._graph[-1][1], (y, len(self._graph)), '2x']) - while self.cur_dims[0][0]: #> 0: + while self.cur_dims[0][0]: # > 0: if verbose: print("====================") print(repr(self.rigged_con.parent()(*self.cur_partitions, use_vacancy_numbers=True))) @@ -720,20 +720,20 @@ def run(self, verbose=False, build_graph=False): print(ret_crystal_path) print("--------------------\n") - self.cur_dims[0][0] -= 1 # This takes care of the indexing + self.cur_dims[0][0] -= 1 # This takes care of the indexing b = self.next_state(self.cur_dims[0][0]) # Make sure we have a crystal letter - ret_crystal_path[-1].append(letters(b)) # Append the rank + ret_crystal_path[-1].append(letters(b)) # Append the rank if build_graph: y = self.rigged_con.parent()(*[x._clone() for x in self.cur_partitions], use_vacancy_numbers=True) self._graph.append([self._graph[-1][1], (y, len(self._graph)), letters(b)]) - self.cur_dims.pop(0) # Pop off the leading column + self.cur_dims.pop(0) # Pop off the leading column if build_graph: - self._graph.pop(0) # Remove the dummy at the start + self._graph.pop(0) # Remove the dummy at the start from sage.graphs.digraph import DiGraph from sage.graphs.dot2tex_utils import have_dot2tex self._graph = DiGraph(self._graph) @@ -796,7 +796,7 @@ def next_state(self, height): last_size = partition[j] case_S = True break - if not case_Q: # We found a singular string above the quasi-singular one + if not case_Q: # We found a singular string above the quasi-singular one break ell[n-1] = i last_size = partition[i] @@ -882,7 +882,7 @@ def next_state(self, height): self._update_vacancy_numbers(n - 1) if row_num_next is not None: self.cur_partitions[n-1].rigging[row_num_next] = self.cur_partitions[n-1].vacancy_numbers[row_num_next] - if row_num_bar_next is not None: # If we enter here, it means case (Q, S) holds + if row_num_bar_next is not None: # If we enter here, it means case (Q, S) holds vac_num = self.cur_partitions[n-1].vacancy_numbers[row_num_bar_next] self.cur_partitions[n-1].rigging[row_num_bar_next] = vac_num if make_quasisingular: @@ -895,4 +895,4 @@ def next_state(self, height): j += 1 self.cur_partitions[n-1].rigging[j-1] = vac_num - 1 - return(b) + return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_C.py b/src/sage/combinat/rigged_configurations/bij_type_C.py index 0d18e575043..d04267b5569 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_C.py +++ b/src/sage/combinat/rigged_configurations/bij_type_C.py @@ -20,7 +20,7 @@ sage: TestSuite(bijection).run() """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -32,8 +32,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.rigged_configurations.bij_type_A import KRTToRCBijectionTypeA from sage.combinat.rigged_configurations.bij_type_A import RCToKRTBijectionTypeA @@ -151,7 +151,7 @@ def _insert_cell_case_S(self, partition): if partition.rigging[i] is None: j = i - 1 while j >= 0 and partition._list[j] == partition._list[i]: - partition.rigging[j+1] = partition.rigging[j] # Shuffle it along + partition.rigging[j+1] = partition.rigging[j] # Shuffle it along j -= 1 partition._list[j+1] += 1 partition.rigging[j+1] = None @@ -176,7 +176,7 @@ def next_state(self, height): sage: bijection.next_state(1) -1 """ - height -= 1 # indexing + height -= 1 # indexing n = self.n ell = [None] * (2*n) case_S = [False] * n @@ -214,7 +214,7 @@ def next_state(self, height): if a >= height and self.cur_partitions[a][ell[a]] == last_size: ell[n+a] = ell[a] case_S[a] = True - else: # note last_size > 1 + else: # note last_size > 1 ell[n+a] = self._find_singular_string(self.cur_partitions[a], last_size) if ell[n + a] is None: @@ -262,4 +262,4 @@ def next_state(self, height): if row_num_next is not None: self.cur_partitions[n-1].rigging[row_num_next] = self.cur_partitions[n-1].vacancy_numbers[row_num_next] - return(b) + return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_D.py b/src/sage/combinat/rigged_configurations/bij_type_D.py index a09c9383f1c..12fb6c6be2c 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_D.py +++ b/src/sage/combinat/rigged_configurations/bij_type_D.py @@ -20,7 +20,7 @@ sage: TestSuite(bijection).run() """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011, 2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -32,8 +32,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.rigged_configurations.bij_type_A import KRTToRCBijectionTypeA from sage.combinat.rigged_configurations.bij_type_A import RCToKRTBijectionTypeA @@ -83,7 +83,7 @@ def run(self, verbose=False): r = cur_crystal.parent().r() # Iterate through the columns for col_number, cur_column in enumerate(reversed(cur_crystal.to_array(False))): - self.cur_path.insert(0, []) # Prepend an empty list + self.cur_path.insert(0, []) # Prepend an empty list # Check to see if we are a spinor column if r >= self.n-1: @@ -102,7 +102,7 @@ def run(self, verbose=False): # This check is needed for the n-1 spin column if self.cur_dims[0][0] < r: self.cur_dims[0][0] += 1 - val = letter.value # Convert from a CrystalOfLetter to an Integer + val = letter.value # Convert from a CrystalOfLetter to an Integer if verbose: print("====================") @@ -112,7 +112,7 @@ def run(self, verbose=False): print("--------------------\n") # Build the next state - self.cur_path[0].insert(0, [letter]) # Prepend the value + self.cur_path[0].insert(0, [letter]) # Prepend the value self.next_state(val) # Check to see if we are a spinor column @@ -139,7 +139,7 @@ def run(self, verbose=False): for a in range(self.n): self._update_vacancy_nums(a) - self.ret_rig_con.set_immutable() # Return it to immutable + self.ret_rig_con.set_immutable() # Return it to immutable return self.ret_rig_con def next_state(self, val): @@ -495,7 +495,7 @@ def run(self, verbose=False, build_graph=False): b = self.next_state(self.n) if b == self.n: b = -self.n - ret_crystal_path[-1].append(letters(b)) # Append the rank + ret_crystal_path[-1].append(letters(b)) # Append the rank if build_graph: y = self.rigged_con.parent()(*[x._clone() for x in self.cur_partitions], use_vacancy_numbers=True) @@ -509,7 +509,7 @@ def run(self, verbose=False, build_graph=False): print(ret_crystal_path) print("--------------------\n") - self.cur_dims[0][0] -= 1 # This takes care of the indexing + self.cur_dims[0][0] -= 1 # This takes care of the indexing b = self.next_state(self.cur_dims[0][0]) # Corrections for spinor @@ -518,13 +518,13 @@ def run(self, verbose=False, build_graph=False): b = -(self.n-1) # Make sure we have a crystal letter - ret_crystal_path[-1].append(letters(b)) # Append the rank + ret_crystal_path[-1].append(letters(b)) # Append the rank if build_graph: y = self.rigged_con.parent()(*[x._clone() for x in self.cur_partitions], use_vacancy_numbers=True) self._graph.append([self._graph[-1][1], (y, len(self._graph)), letters(b)]) - self.cur_dims.pop(0) # Pop off the leading column + self.cur_dims.pop(0) # Pop off the leading column # Check to see if we were a spinor if dim[0] >= self.n-1: @@ -677,7 +677,7 @@ def next_state(self, height): self.cur_partitions[n - 1].rigging[ret_row_bar_next] = \ self.cur_partitions[n - 1].vacancy_numbers[ret_row_bar_next] - return(b) + return b def doubling_map(self): r""" diff --git a/src/sage/combinat/rigged_configurations/bij_type_D_tri.py b/src/sage/combinat/rigged_configurations/bij_type_D_tri.py index e0796bf880d..f143b3ce38a 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_D_tri.py +++ b/src/sage/combinat/rigged_configurations/bij_type_D_tri.py @@ -20,7 +20,7 @@ sage: TestSuite(bijection).run() """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -32,8 +32,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.rigged_configurations.bij_type_A import KRTToRCBijectionTypeA from sage.combinat.rigged_configurations.bij_type_A import RCToKRTBijectionTypeA @@ -169,7 +169,7 @@ def next_state(self, val): else: j = i - 1 while j >= 0 and P._list[j] <= max_width + 2: - P.rigging[j+1] = P.rigging[j] # Shuffle it along + P.rigging[j+1] = P.rigging[j] # Shuffle it along j -= 1 P._list.pop(i) P._list.insert(j+1, max_width + 2) @@ -193,7 +193,7 @@ def next_state(self, val): if P.rigging[i] is None: j = i - 1 while j >= 0 and P._list[j] == P._list[i]: - P.rigging[j+1] = P.rigging[j] # Shuffle it along + P.rigging[j+1] = P.rigging[j] # Shuffle it along j -= 1 P._list[j+1] += 1 P.rigging[j+1] = None @@ -210,7 +210,7 @@ def next_state(self, val): if P.rigging[i] is None: j = i - 1 while j >= 0 and P._list[j] == P._list[i]: - P.rigging[j+1] = P.rigging[j] # Shuffle it along + P.rigging[j+1] = P.rigging[j] # Shuffle it along j -= 1 P._list[j+1] += 1 P.rigging[j+1] = None @@ -254,7 +254,7 @@ def next_state(self, height): sage: bijection.next_state(2) -3 """ - height -= 1 # indexing + height -= 1 # indexing ell = [None] * 6 case_S = [False] * 3 case_Q = False @@ -305,7 +305,7 @@ def next_state(self, height): else: b = 0 - if b is None: # Going back + if b is None: # Going back if self.cur_partitions[1][ell[1]] == last_size: ell[4] = ell[1] case_S[1] = True @@ -317,7 +317,7 @@ def next_state(self, height): else: last_size = self.cur_partitions[1][ell[4]] - if b is None: # Final partition + if b is None: # Final partition P = self.cur_partitions[0] if ell[0] is not None and P[ell[0]] == last_size: ell[5] = ell[0] @@ -346,7 +346,7 @@ def next_state(self, height): if case_S[0]: row0 = [self.cur_partitions[0].remove_cell(ell[5], 2)] - row0.append( self.cur_partitions[0].remove_cell(ell[3], 2) ) + row0.append(self.cur_partitions[0].remove_cell(ell[3], 2)) else: if case_Q: if ell[0] is None or ell[0] < ell[2]: @@ -360,9 +360,9 @@ def next_state(self, height): else: row0 = [self.cur_partitions[0].remove_cell(ell[0])] if case_S[2]: - row0.append( self.cur_partitions[0].remove_cell(ell[3], 2) ) + row0.append(self.cur_partitions[0].remove_cell(ell[3], 2)) - row0.append( self.cur_partitions[0].remove_cell(ell[5]) ) + row0.append(self.cur_partitions[0].remove_cell(ell[5])) self._update_vacancy_numbers(0) self._update_vacancy_numbers(1) @@ -387,4 +387,4 @@ def next_state(self, height): j += 1 P.rigging[j-1] = vac_num - 1 - return(b) + return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_D_twisted.py b/src/sage/combinat/rigged_configurations/bij_type_D_twisted.py index e9c13e4b54d..dbc049d6ae0 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_D_twisted.py +++ b/src/sage/combinat/rigged_configurations/bij_type_D_twisted.py @@ -20,7 +20,7 @@ sage: TestSuite(bijection).run() """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011, 2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -32,8 +32,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.rigged_configurations.bij_type_A import KRTToRCBijectionTypeA from sage.combinat.rigged_configurations.bij_type_A2_even import KRTToRCBijectionTypeA2Even @@ -84,7 +84,7 @@ def run(self, verbose=False): r = cur_crystal.parent().r() # Iterate through the columns for col_number, cur_column in enumerate(reversed(cur_crystal.to_array(False))): - self.cur_path.insert(0, []) # Prepend an empty list + self.cur_path.insert(0, []) # Prepend an empty list # Check to see if we are a spinor column if r == self.n: @@ -101,7 +101,7 @@ def run(self, verbose=False): for letter in reversed(cur_column): self.cur_dims[0][0] += 1 - val = letter.value # Convert from a CrystalOfLetter to an Integer + val = letter.value # Convert from a CrystalOfLetter to an Integer if verbose: print("====================") @@ -111,7 +111,7 @@ def run(self, verbose=False): print("--------------------\n") # Build the next state - self.cur_path[0].insert(0, [letter]) # Prepend the value + self.cur_path[0].insert(0, [letter]) # Prepend the value self.next_state(val) # Check to see if we are a spinor column @@ -138,7 +138,7 @@ def run(self, verbose=False): for a in range(self.n): self._update_vacancy_nums(a) - self.ret_rig_con.set_immutable() # Return it to immutable + self.ret_rig_con.set_immutable() # Return it to immutable return self.ret_rig_con def next_state(self, val): @@ -571,4 +571,4 @@ def next_state(self, height): else: self.cur_partitions[n-1].rigging[row_num_bar_next] = self.cur_partitions[n-1].vacancy_numbers[row_num_bar_next] - return(b) + return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_E67.py b/src/sage/combinat/rigged_configurations/bij_type_E67.py index 6fedd39c5a0..3d258443276 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_E67.py +++ b/src/sage/combinat/rigged_configurations/bij_type_E67.py @@ -20,7 +20,7 @@ sage: TestSuite(bijection).run() """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011, 2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -32,8 +32,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.rigged_configurations.bij_abstract_class import KRTToRCBijectionAbstract from sage.combinat.rigged_configurations.bij_abstract_class import RCToKRTBijectionAbstract @@ -91,8 +91,8 @@ def find_singular_string(p, max_width): if not data: break - max_val = max(l for a,l in data) - for a,l in data: + max_val = max(l for a, l in data) + for a, l in data: if l == max_val: self.ret_rig_con[a-1].insert_cell(max_width) max_width = l @@ -153,7 +153,7 @@ def _next_index(self, r, target): return 2 if r == 2: return 5 - else: # rank == 7 + else: # rank == 7 # 1-2-3 # / # 0-7-6-5-4 @@ -240,12 +240,12 @@ def next_state(self, r): data = [(a, self._find_singular_string(self.cur_partitions[a-1], last_size)) for a in b.value if a > 0] data = [(val, a, self.cur_partitions[a-1][val]) - for a,val in data if val is not None] + for a, val in data if val is not None] if not data: break - min_val = min(l for i,a,l in data) - for i,a,l in data: + min_val = min(l for i, a, l in data) + for i, a, l in data: if l == min_val: found = True last_size = l @@ -253,13 +253,13 @@ def next_state(self, r): b = b.f(a) break - for a,p in enumerate(self.cur_partitions): + for a, p in enumerate(self.cur_partitions): self._update_vacancy_numbers(a) for i in range(len(p)): if p.rigging[i] is None: p.rigging[i] = p.vacancy_numbers[i] - return(b) + return b def _next_index(self, r): """ @@ -290,7 +290,7 @@ def _next_index(self, r): return 2 if r == 6: return 1 - else: # rank == 7 + else: # rank == 7 # 1-2-3 # / # 0-7-6-5-4 @@ -346,7 +346,7 @@ def endpoint6(r): sage: endpoint6(6) (-1, 6) """ - C = CrystalOfLetters(['E',6]) + C = CrystalOfLetters(['E', 6]) if r == 1: return C.module_generators[0] # C((1,)) elif r == 2: @@ -383,7 +383,7 @@ def endpoint7(r): sage: endpoint7(7) (7,) """ - C = CrystalOfLetters(['E',7]) + C = CrystalOfLetters(['E', 7]) if r == 1: return C((-7, 1)) elif r == 2: diff --git a/src/sage/combinat/rigged_configurations/kleber_tree.py b/src/sage/combinat/rigged_configurations/kleber_tree.py index e6c73af4d50..6d056b6c678 100644 --- a/src/sage/combinat/rigged_configurations/kleber_tree.py +++ b/src/sage/combinat/rigged_configurations/kleber_tree.py @@ -71,7 +71,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.latex import latex from sage.misc.misc_c import prod -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.features import FeatureNotPresentError from sage.rings.integer import Integer @@ -121,13 +121,13 @@ def _draw_tree(tree_node, node_label=True, style_point=None, style_node='fill=wh start = [0., 0.] if rpos is None: rpos = [0., 0.] - draw_point = lambda point: '(%.3f, %.3f)'%(point[0],point[1]) + draw_point = lambda point: '(%.3f, %.3f)' % (point[0],point[1]) if not tree_node.children: r = '' node_name = node_prefix + str(node_id) - r = "\\node (%s) at %s"%(node_name, draw_point(start)) + r = "\\node (%s) at %s" % (node_name, draw_point(start)) if node_label: - r += "{$%s$};\n"%tree_node._latex_() + r += "{$%s$};\n" % tree_node._latex_() else: r += "{};\n" rpos[0] = start[0] @@ -139,7 +139,7 @@ def _draw_tree(tree_node, node_label=True, style_point=None, style_node='fill=wh if style_line is None: style_line_str = '' else: - style_line_str = "[%s]"%style_line + style_line_str = "[%s]" % style_line if node_label: node_place_str = '' else: @@ -166,29 +166,29 @@ def _draw_tree(tree_node, node_label=True, style_point=None, style_node='fill=wh edge_str = latex(child.up_root.to_vector()) else: edge_str = latex(child.up_root) - lines_str += "\\draw%s (%s%s) to node[sloped,above]{\\tiny $%s$} (%s%s%s);\n"%(style_line_str, node_name, node_place_str, edge_str, node_name, i, node_place_str) + lines_str += "\\draw%s (%s%s) to node[sloped,above]{\\tiny $%s$} (%s%s%s);\n" % (style_line_str, node_name, node_place_str, edge_str, node_name, i, node_place_str) else: - lines_str += "\\draw%s (%s%s) -- (%s%s%s);\n"%(style_line_str, node_name, node_place_str, node_name, i, node_place_str) + lines_str += "\\draw%s (%s%s) -- (%s%s%s);\n" % (style_line_str, node_name, node_place_str, node_name, i, node_place_str) - #drawing root + # drawing root if style_node is None: style_node = '' else: - style_node = "[%s]"%style_node + style_node = "[%s]" % style_node if style_point is None: style_point = '' else: - style_point = "[%s]"%style_point + style_point = "[%s]" % style_point start[1] -= vspace rpos[0] = pos[0] rpos[1] = pos[1] point_str = '' - node_str = "\\node%s (%s) at %s"%(style_node, node_name, draw_point(pos)) + node_str = "\\node%s (%s) at %s" % (style_node, node_name, draw_point(pos)) if node_label: - node_str += "{$%s$};\n"%tree_node._latex_() + node_str += "{$%s$};\n" % tree_node._latex_() else: node_str += "{};\n" - point_str = "\\draw%s (%s) circle;\n"%(style_point, node_name) + point_str = "\\draw%s (%s) circle;\n" % (style_point, node_name) res = node_str res += children_str @@ -429,8 +429,8 @@ def _repr_(self): sage: KT.root Kleber tree node with weight [0, 2, 0, 2, 0] and upwards edge root [0, 0, 0, 0, 0] """ - return "Kleber tree node with weight %s and upwards edge root %s"%( - list(self.weight.to_vector()), list(self.up_root.to_vector()) ) + return "Kleber tree node with weight %s and upwards edge root %s" % ( + list(self.weight.to_vector()), list(self.up_root.to_vector())) def _latex_(self): r""" @@ -999,7 +999,7 @@ def _repr_(self): sage: KleberTree(['D', 4, 1], [[2, 2]]) # indirect doctest Kleber tree of Cartan type ['D', 4, 1] and B = ((2, 2),) """ - return "Kleber tree of Cartan type %s and B = %s"%(repr(self._cartan_type), self.B) + return "Kleber tree of Cartan type %s and B = %s" % (repr(self._cartan_type), self.B) def cartan_type(self): r""" @@ -1045,7 +1045,7 @@ def plot(self, **options): sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree sage: KT = KleberTree(['D', 4, 1], [[2, 2]]) - sage: print(KT.plot()) + sage: print(KT.plot()) # optional - sage.plot Graphics object consisting of 8 graphics primitives """ return self.digraph().plot(edge_labels=True, vertex_size=0, **options) @@ -1193,7 +1193,7 @@ def _repr_(self): sage: VirtualKleberTree(['C', 4, 1], [[2, 2]]) Virtual Kleber tree of Cartan type ['C', 4, 1] and B = ((2, 2),) """ - return "Virtual Kleber tree of Cartan type %s and B = %s"%(repr(self._cartan_type), self.base_dims) + return "Virtual Kleber tree of Cartan type %s and B = %s" % (repr(self._cartan_type), self.base_dims) def _prune(self, new_child, depth): r""" diff --git a/src/sage/combinat/rigged_configurations/rc_crystal.py b/src/sage/combinat/rigged_configurations/rc_crystal.py index fbd149f6c0c..dbd7fd047fe 100644 --- a/src/sage/combinat/rigged_configurations/rc_crystal.py +++ b/src/sage/combinat/rigged_configurations/rc_crystal.py @@ -179,7 +179,7 @@ def __init__(self, wt, WLR): else: category = (RegularCrystals(), HighestWeightCrystals(), InfiniteEnumeratedSets()) Parent.__init__(self, category=category) - n = self._cartan_type.rank() #== len(self._cartan_type.index_set()) + n = self._cartan_type.rank() # == len(self._cartan_type.index_set()) self.module_generators = (self.element_class(self, partition_list=[[] for _ in repeat(None, n)]),) options = RiggedConfigurations.options @@ -444,7 +444,7 @@ def from_virtual(self, vrc): sage: elt == RC.from_virtual(RC.to_virtual(elt)) True """ - gamma = list(self._folded_ct.scaling_factors()) #map(int, self._folded_ct.scaling_factors()) + gamma = list(self._folded_ct.scaling_factors()) # map(int, self._folded_ct.scaling_factors()) sigma = self._folded_ct._orbit n = self._cartan_type.rank() partitions = [None] * n diff --git a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py index 727322f0efd..542649cf9dd 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py +++ b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py @@ -232,8 +232,8 @@ def __init__(self, parent, rigged_partitions=[], **options): nu = [] for i in range(n): nu.append(RiggedPartition()) - #raise ValueError("Invalid input") - #raise ValueError("Incorrect number of rigged partitions") + # raise ValueError("Invalid input") + # raise ValueError("Incorrect number of rigged partitions") # Set the vacancy numbers for a, partition in enumerate(nu): @@ -330,7 +330,7 @@ def _repr_vertical(self): ret_str = "" for tableau in self: ret_str += "\n" + repr(tableau) - return(ret_str) + return ret_str def _repr_horizontal(self): """ @@ -1039,7 +1039,7 @@ def f(self, a): return self.parent().from_virtual(virtual_rc) ########################################################## -## Highest weight crystal rigged configuration elements ## +# Highest weight crystal rigged configuration elements # ########################################################## @@ -1229,7 +1229,7 @@ def weight(self): return self.parent()._wt - sum(sum(x) * alpha[i] for i,x in enumerate(self)) ############################################## -## KR crystal rigged configuration elements ## +# KR crystal rigged configuration elements # ############################################## @@ -2278,7 +2278,7 @@ def cocharge(self): sage: RC(partition_list=[[1,1],[2,1],[1,1]]).cocharge() 1 """ - #return self.to_virtual_configuration().cocharge() / self.parent()._folded_ct.gamma[0] + # return self.to_virtual_configuration().cocharge() / self.parent()._folded_ct.gamma[0] vct = self.parent()._folded_ct cc = ZZ.zero() rigging_sum = ZZ.zero() diff --git a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py index 7f66de8c32d..ce4c2ad2ab4 100644 --- a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +++ b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py @@ -45,7 +45,7 @@ False """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010-2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -57,8 +57,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.cachefunc import cached_method from sage.structure.unique_representation import UniqueRepresentation @@ -68,9 +68,9 @@ from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element \ - import TensorProductOfKirillovReshetikhinTableauxElement + import TensorProductOfKirillovReshetikhinTableauxElement from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableaux, \ - KirillovReshetikhinTableauxElement + KirillovReshetikhinTableauxElement from sage.rings.integer import Integer @@ -320,12 +320,12 @@ def __init__(self, cartan_type, B): FullTensorProductOfRegularCrystals.__init__(self, tensor_prod, cartan_type=cartan_type) # This is needed to override the module_generators set in FullTensorProductOfRegularCrystals self.module_generators = HighestWeightTensorKRT(self) - self.rename("Tensor product of Kirillov-Reshetikhin tableaux of type %s and factor(s) %s"%(\ - cartan_type, B)) + self.rename("Tensor product of Kirillov-Reshetikhin tableaux " + f"of type {cartan_type} and factor(s) {B}") def __iter__(self): """ - Returns the iterator of ``self``. + Return the iterator of ``self``. EXAMPLES:: @@ -339,8 +339,8 @@ def __iter__(self): index_set = self._cartan_type.classical().index_set() from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet return RecursivelyEnumeratedSet(self.module_generators, - lambda x: [x.f(i) for i in index_set], - structure=None).naive_search_iterator() + lambda x: [x.f(i) for i in index_set], + structure=None).naive_search_iterator() def _test_bijection(self, **options): r""" @@ -360,7 +360,7 @@ def _test_bijection(self, **options): if z != x: rejects.append((x, z)) - tester.assertEqual(len(rejects), 0, "Bijection is not correct: %s"%rejects) + tester.assertEqual(len(rejects), 0, "Bijection is not correct: %s" % rejects) if rejects: return rejects @@ -415,7 +415,7 @@ def _module_generators_brute_force(self): """ index_set = self.cartan_type().classical().index_set() return tuple(x for x in FullTensorProductOfRegularCrystals.__iter__(self) - if x.is_highest_weight(index_set)) + if x.is_highest_weight(index_set)) @cached_method def rigged_configurations(self): diff --git a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py index fb43642a004..c816d2140a6 100644 --- a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py +++ b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py @@ -9,7 +9,7 @@ - Travis Scrimshaw (2010-09-26): Initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010, 2011, 2012 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -21,8 +21,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.crystals.tensor_product import TensorProductOfRegularCrystalsElement @@ -158,7 +158,7 @@ def _repr_(self): ret_str = repr(self[0]) for i in range(1, len(self)): ret_str += " (X) " + repr(self[i]) - return(ret_str) + return ret_str def _repr_diagram(self): """ @@ -179,7 +179,7 @@ def _repr_diagram(self): sage: Partitions.options._reset() """ comp = [crys._repr_diagram().splitlines() for crys in self] - num_comp = len(comp) # number of components + num_comp = len(comp) # number of components col_len = [len(t) > 0 and len(t[0]) or 1 for t in comp] # columns per component num_rows = max(len(t) for t in comp) # number of rows @@ -190,11 +190,11 @@ def _repr_diagram(self): diag += '\n' for c in range(num_comp): if c > 0: - diag += ' ' # For the tensor symbol + diag += ' ' # For the tensor symbol if row < len(comp[c]): diag += comp[c][row] else: - diag += ' '*col_len[c] + diag += ' ' * col_len[c] return diag def pp(self): @@ -244,7 +244,7 @@ def lusztig_involution(self): Tensor product of Kirillov-Reshetikhin tableaux of type ['A', 3, 1] and factor(s) ((1, 3), (2, 2)) """ from sage.combinat.rigged_configurations.tensor_product_kr_tableaux \ - import TensorProductOfKirillovReshetikhinTableaux + import TensorProductOfKirillovReshetikhinTableaux P = self.parent() P = TensorProductOfKirillovReshetikhinTableaux(P._cartan_type, reversed(P.dims)) return P(*[x.lusztig_involution() for x in reversed(self)]) @@ -266,11 +266,11 @@ def left_split(self): P = self.parent() if P.dims[0][1] == 1: raise ValueError("cannot split a single column") - r,s = P.dims[0] - B = [[r,1], [r,s-1]] + r, s = P.dims[0] + B = [[r, 1], [r, s - 1]] B.extend(P.dims[1:]) from sage.combinat.rigged_configurations.tensor_product_kr_tableaux \ - import TensorProductOfKirillovReshetikhinTableaux + import TensorProductOfKirillovReshetikhinTableaux TP = TensorProductOfKirillovReshetikhinTableaux(P._cartan_type, B) x = self[0].left_split() return TP(*(list(x) + self[1:])) @@ -298,12 +298,12 @@ def right_split(self): P = self.parent() if P.dims[-1][1] == 1: raise ValueError("cannot split a single column") - r,s = P.dims[-1] + r, s = P.dims[-1] B = list(P.dims[:-1]) - B.append([r, s-1]) + B.append([r, s - 1]) B.append([r, 1]) from sage.combinat.rigged_configurations.tensor_product_kr_tableaux \ - import TensorProductOfKirillovReshetikhinTableaux + import TensorProductOfKirillovReshetikhinTableaux TP = TensorProductOfKirillovReshetikhinTableaux(P._cartan_type, B) x = self[-1].right_split() return TP(*(self[:-1] + list(x))) diff --git a/src/sage/combinat/root_system/ambient_space.py b/src/sage/combinat/root_system/ambient_space.py index b5e4a90e6ad..c9696b98fdb 100644 --- a/src/sage/combinat/root_system/ambient_space.py +++ b/src/sage/combinat/root_system/ambient_space.py @@ -117,9 +117,13 @@ def _test_norm_of_simple_roots(self, **options): """ tester = self._tester(**options) T = self.cartan_type() - D = T.symmetrizer() - alpha = self.simple_roots() - for C in T.dynkin_diagram().connected_components(): + try: + D = T.symmetrizer() + alpha = self.simple_roots() + DD = T.dynkin_diagram() + except ImportError: # Dynkin diagrams need sage.graphs + return + for C in DD.connected_components(sort=False): tester.assertEqual(len( set( alpha[i].scalar(alpha[i]) / D[i] for i in C ) ), 1) # FIXME: attribute or method? diff --git a/src/sage/combinat/root_system/associahedron.py b/src/sage/combinat/root_system/associahedron.py index 578007985fd..b0739695810 100644 --- a/src/sage/combinat/root_system/associahedron.py +++ b/src/sage/combinat/root_system/associahedron.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.geometry.polyhedron r""" Associahedron diff --git a/src/sage/combinat/root_system/braid_move_calculator.py b/src/sage/combinat/root_system/braid_move_calculator.py index 10991bf2504..e932662bd5d 100644 --- a/src/sage/combinat/root_system/braid_move_calculator.py +++ b/src/sage/combinat/root_system/braid_move_calculator.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.gap """ Braid Move Calculator diff --git a/src/sage/combinat/root_system/braid_orbit.pyx b/src/sage/combinat/root_system/braid_orbit.pyx index f3efeb357ce..d95bc388f83 100644 --- a/src/sage/combinat/root_system/braid_orbit.pyx +++ b/src/sage/combinat/root_system/braid_orbit.pyx @@ -74,6 +74,61 @@ cpdef set BraidOrbit(list word, list rels): return words +cpdef bint is_fully_commutative(list word, list rels): + r""" + Check if the braid orbit of ``word`` is using a braid relation. + + INPUT: + + - ``word`` -- list of integers + + - ``rels`` -- list of pairs ``(A, B)``, where ``A`` and ``B`` are + lists of integers the same length + + EXAMPLES:: + + sage: from sage.combinat.root_system.braid_orbit import is_fully_commutative + sage: rels = [[[2, 1, 2], [1, 2, 1]], [[3, 1], [1, 3]], [[3, 2, 3], [2, 3, 2]]] + sage: word = [1,2,1,3,2,1] + sage: is_fully_commutative(word, rels) + False + sage: word = [1,2,3] + sage: is_fully_commutative(word, rels) + True + """ + cdef int i, l, rel_l, loop_ind, list_len + cdef tuple left, right, test_word, new_word + cdef list rel + + l = len(word) + cdef set words = set( [tuple(word)] ) + cdef list test_words = [ tuple(word) ] + + rels = rels + [[b, a] for a, b in rels] + rels = [[tuple(a), tuple(b), len(a)] for a, b in rels] + + loop_ind = 0 + list_len = 1 + while loop_ind < list_len: + sig_check() + test_word = <tuple> test_words[loop_ind] + loop_ind += 1 + for rel in rels: + left = <tuple> rel[0] + right = <tuple> rel[1] + rel_l = <int> rel[2] + for i in range(l-rel_l+1): + if pattern_match(test_word, i, left, rel_l): + if rel_l > 2: + return False + new_word = test_word[:i] + right + test_word[i+rel_l:] + if new_word not in words: + words.add(new_word) + test_words.append(new_word) + list_len += 1 + return True + + cdef inline bint pattern_match(tuple L, int i, tuple X, int l): r""" Return ``True`` if ``L[i:i+l] == X``. diff --git a/src/sage/combinat/root_system/branching_rules.py b/src/sage/combinat/root_system/branching_rules.py index 9c8967331b8..d92d08a8eed 100644 --- a/src/sage/combinat/root_system/branching_rules.py +++ b/src/sage/combinat/root_system/branching_rules.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.gap """ Branching Rules """ @@ -54,7 +55,7 @@ def branch_weyl_character(chi, R, S, rule="default"): * ``"triality"`` * ``"miscellaneous"`` - The ``BranchingRule`` class is a wrapper for functions + The :class:`BranchingRule` class is a wrapper for functions from the weight lattice of `G` to the weight lattice of `H`. An instance of this class encodes an embedding of `H` into `G`. The usual way to specify an embedding is to supply a diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index 2cf987db202..c1ce04fba38 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -28,21 +28,29 @@ from sage.misc.cachefunc import cached_method from sage.matrix.constructor import matrix +from sage.misc.lazy_import import lazy_import from sage.structure.element import is_Matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.classcall_metaclass import typecall -from sage.misc.misc import powerset -from sage.matrix.matrix_integer_sparse import Matrix_integer_sparse +from sage.combinat.subset import powerset from sage.rings.integer_ring import ZZ from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract from sage.combinat.root_system.root_system import RootSystem from sage.sets.family import Family -from sage.graphs.digraph import DiGraph +lazy_import('sage.graphs.digraph', 'DiGraph') +lazy_import('sage.combinat.root_system.dynkin_diagram', 'DynkinDiagram_class') -class CartanMatrix(Matrix_integer_sparse, CartanType_abstract, - metaclass=InheritComparisonClasscallMetaclass): + +try: + from sage.matrix.matrix_integer_sparse import Matrix_integer_sparse as Base +except ImportError: + from sage.matrix.matrix_generic_sparse import Matrix_generic_sparse as Base + + +class CartanMatrix(Base, CartanType_abstract, + metaclass=InheritComparisonClasscallMetaclass): r""" A (generalized) Cartan matrix. @@ -81,6 +89,7 @@ class CartanMatrix(Matrix_integer_sparse, CartanType_abstract, EXAMPLES:: + sage: # needs sage.graphs sage: CartanMatrix(['A', 4]) [ 2 -1 0 0] [-1 2 -1 0] @@ -140,6 +149,7 @@ class CartanMatrix(Matrix_integer_sparse, CartanType_abstract, :: + sage: # needs sage.graphs sage: CartanMatrix(['G', 2]) [ 2 -3] [-1 2] @@ -207,10 +217,10 @@ class CartanMatrix(Matrix_integer_sparse, CartanType_abstract, Examples of Borcherds-Cartan matrices:: - sage: CartanMatrix([[2,-1],[-1,-2]], borcherds=True) + sage: CartanMatrix([[2,-1],[-1,-2]], borcherds=True) # needs sage.graphs [ 2 -1] [-1 -2] - sage: CartanMatrix('B3', borcherds=[-4,-6,2]) + sage: CartanMatrix('B3', borcherds=[-4,-6,2]) # needs sage.graphs [-4 -1 0] [-1 -6 -1] [ 0 -2 2] @@ -237,6 +247,7 @@ def __classcall_private__(cls, data=None, index_set=None, EXAMPLES:: + sage: # needs sage.graphs sage: C = CartanMatrix(['A',1,1]) sage: C2 = CartanMatrix([[2, -2], [-2, 2]]) sage: C3 = CartanMatrix(matrix([[2, -2], [-2, 2]]), [0, 1]) @@ -247,6 +258,7 @@ def __classcall_private__(cls, data=None, index_set=None, Check that :trac:`15740` is fixed:: + sage: # needs sage.graphs sage: d = DynkinDiagram() sage: d.add_edge('a', 'b', 2) sage: d.index_set() @@ -274,7 +286,6 @@ def __classcall_private__(cls, data=None, index_set=None, dynkin_diagram = None subdivisions = None - from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class if isinstance(data, DynkinDiagram_class): dynkin_diagram = data cartan_type = data._cartan_type @@ -346,6 +357,7 @@ def matrix_space(self, nrows=None, ncols=None, sparse=None): EXAMPLES:: + sage: # needs sage.graphs sage: cm = CartanMatrix(['A', 3]) sage: cm.matrix_space() Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring @@ -374,8 +386,8 @@ def _CM_init(self, cartan_type, index_set, cartan_type_check): TESTS:: - sage: C = CartanMatrix(['A',1,1]) # indirect doctest - sage: TestSuite(C).run(skip=["_test_category", "_test_change_ring"]) + sage: C = CartanMatrix(['A',1,1]) # indirect doctest # needs sage.graphs + sage: TestSuite(C).run(skip=["_test_category", "_test_change_ring"]) # needs sage.graphs """ self._index_set = index_set self.set_immutable() @@ -398,9 +410,9 @@ def __reduce__(self): TESTS:: - sage: CM = CartanMatrix(['A',4]) - sage: x = loads(dumps(CM)) - sage: x._index_set + sage: CM = CartanMatrix(['A',4]) # needs sage.graphs + sage: x = loads(dumps(CM)) # needs sage.graphs + sage: x._index_set # needs sage.graphs (1, 2, 3, 4) """ if self._cartan_type: @@ -413,8 +425,8 @@ def root_system(self): EXAMPLES:: - sage: C = CartanMatrix(['A',3]) - sage: C.root_system() + sage: C = CartanMatrix(['A',3]) # needs sage.graphs + sage: C.root_system() # needs sage.graphs Root system of type ['A', 3] """ if self._cartan_type is not None: @@ -427,8 +439,8 @@ def root_space(self): EXAMPLES:: - sage: C = CartanMatrix(['A',3]) - sage: C.root_space() + sage: C = CartanMatrix(['A',3]) # needs sage.graphs + sage: C.root_space() # needs sage.graphs Root space over the Rational Field of the Root system of type ['A', 3] """ return self.root_system().root_space() @@ -439,8 +451,8 @@ def reflection_group(self, type="matrix"): EXAMPLES:: - sage: C = CartanMatrix(['A',3]) - sage: C.reflection_group() + sage: C = CartanMatrix(['A',3]) # needs sage.graphs + sage: C.reflection_group() # needs sage.graphs Weyl Group of type ['A', 3] (as a matrix group acting on the root space) """ RS = self.root_space() @@ -468,8 +480,8 @@ def symmetrizer(self): EXAMPLES:: - sage: cm = CartanMatrix([[2,-5],[-2,2]]) - sage: cm.symmetrizer() + sage: cm = CartanMatrix([[2,-5],[-2,2]]) # needs sage.graphs + sage: cm.symmetrizer() # needs sage.graphs Finite family {0: 2, 1: 5} TESTS: @@ -478,9 +490,9 @@ def symmetrizer(self): with the values given by the Cartan type:: sage: ct = CartanType(['B',4,1]) - sage: ct.symmetrizer() + sage: ct.symmetrizer() # needs sage.graphs Finite family {0: 2, 1: 2, 2: 2, 3: 2, 4: 1} - sage: ct.cartan_matrix().symmetrizer() + sage: ct.cartan_matrix().symmetrizer() # needs sage.graphs Finite family {0: 2, 1: 2, 2: 2, 3: 2, 4: 1} """ sym = self.is_symmetrizable(True) @@ -489,7 +501,7 @@ def symmetrizer(self): iset = self.index_set() # The result from is_symmetrizable needs to be scaled # to integer coefficients - from sage.arith.all import LCM + from sage.arith.functions import lcm as LCM from sage.rings.rational_field import QQ scalar = LCM([QQ(x).denominator() for x in sym]) return Family( {iset[i]: ZZ(val*scalar) for i, val in enumerate(sym)} ) @@ -501,8 +513,8 @@ def symmetrized_matrix(self): EXAMPLES:: - sage: cm = CartanMatrix(['B',4,1]) - sage: cm.symmetrized_matrix() + sage: cm = CartanMatrix(['B',4,1]) # needs sage.graphs + sage: cm.symmetrized_matrix() # needs sage.graphs [ 4 0 -2 0 0] [ 0 4 -2 0 0] [-2 -2 4 -2 0] @@ -522,6 +534,7 @@ def index_set(self): EXAMPLES:: + sage: # needs sage.graphs sage: C = CartanMatrix(['A',1,1]) sage: C.index_set() (0, 1) @@ -537,14 +550,14 @@ def cartan_type(self): EXAMPLES:: - sage: C = CartanMatrix(['A',4,1]) - sage: C.cartan_type() + sage: C = CartanMatrix(['A',4,1]) # needs sage.graphs + sage: C.cartan_type() # needs sage.graphs ['A', 4, 1] If the Cartan type is unknown:: - sage: C = CartanMatrix([[2,-1,-2], [-1,2,-1], [-2,-1,2]]) - sage: C.cartan_type() + sage: C = CartanMatrix([[2,-1,-2], [-1,2,-1], [-2,-1,2]]) # needs sage.graphs + sage: C.cartan_type() # needs sage.graphs [ 2 -1 -2] [-1 2 -1] [-2 -1 2] @@ -564,6 +577,7 @@ def subtype(self, index_set): EXAMPLES:: + sage: # needs sage.graphs sage: C = CartanMatrix(['F',4]) sage: S = C.subtype([1,2,3]) sage: S @@ -583,9 +597,9 @@ def rank(self): EXAMPLES:: - sage: CartanMatrix(['C',3]).rank() + sage: CartanMatrix(['C',3]).rank() # needs sage.graphs 3 - sage: CartanMatrix(["A2","B2","F4"]).rank() + sage: CartanMatrix(["A2","B2","F4"]).rank() # needs sage.graphs 8 """ return self.ncols() @@ -596,6 +610,7 @@ def relabel(self, relabelling): EXAMPLES:: + sage: # needs sage.graphs sage: CM = CartanMatrix(['C',3]) sage: R = CM.relabel({1:0, 2:4, 3:1}); R [ 2 0 -1] @@ -617,6 +632,7 @@ def dynkin_diagram(self): EXAMPLES:: + sage: # needs sage.graphs sage: C = CartanMatrix(['A',2]) sage: C.dynkin_diagram() O---O @@ -642,7 +658,7 @@ def cartan_matrix(self): EXAMPLES:: - sage: CartanMatrix(['C',3]).cartan_matrix() + sage: CartanMatrix(['C',3]).cartan_matrix() # needs sage.graphs [ 2 -1 0] [-1 2 -2] [ 0 -1 2] @@ -656,6 +672,7 @@ def dual(self): EXAMPLES:: + sage: # needs sage.graphs sage: ct = CartanType(['C',3]) sage: M = CartanMatrix(ct); M [ 2 -1 0] @@ -672,6 +689,7 @@ def dual(self): An example with arbitrary Cartan matrices:: + sage: # needs sage.graphs sage: cm = CartanMatrix([[2,-5], [-2, 2]]); cm [ 2 -5] [-2 2] @@ -696,8 +714,9 @@ def is_simply_laced(self): EXAMPLES:: - sage: cm = CartanMatrix([[2, -1, -1, -1], [-1, 2, -1, -1], [-1, -1, 2, -1], [-1, -1, -1, 2]]) - sage: cm.is_simply_laced() + sage: cm = CartanMatrix([[2, -1, -1, -1], [-1, 2, -1, -1], # needs sage.graphs + ....: [-1, -1, 2, -1], [-1, -1, -1, 2]]) + sage: cm.is_simply_laced() # needs sage.graphs True """ for i in range(self.nrows()): @@ -714,7 +733,7 @@ def is_crystallographic(self): EXAMPLES:: - sage: CartanMatrix(['F',4]).is_crystallographic() + sage: CartanMatrix(['F',4]).is_crystallographic() # needs sage.graphs True """ return self.is_symmetrizable() @@ -726,8 +745,8 @@ def column_with_indices(self, j): EXAMPLES:: - sage: M = CartanMatrix(['B',4]) - sage: [ (i,a) for (i,a) in M.column_with_indices(3) ] + sage: M = CartanMatrix(['B',4]) # needs sage.graphs + sage: [ (i,a) for (i,a) in M.column_with_indices(3) ] # needs sage.graphs [(3, 2), (2, -1), (4, -2)] """ return self.dynkin_diagram().column(j) @@ -739,8 +758,8 @@ def row_with_indices(self, i): EXAMPLES:: - sage: M = CartanMatrix(['C',4]) - sage: [ (i,a) for (i,a) in M.row_with_indices(3) ] + sage: M = CartanMatrix(['C',4]) # needs sage.graphs + sage: [ (i,a) for (i,a) in M.row_with_indices(3) ] # needs sage.graphs [(3, 2), (2, -1), (4, -2)] """ return self.dynkin_diagram().row(i) @@ -758,6 +777,7 @@ def is_finite(self): EXAMPLES:: + sage: # needs sage.graphs sage: M = CartanMatrix(['C',4]) sage: M.is_finite() True @@ -785,6 +805,7 @@ def is_affine(self): EXAMPLES:: + sage: # needs sage.graphs sage: M = CartanMatrix(['C',4]) sage: M.is_affine() False @@ -822,6 +843,7 @@ def is_hyperbolic(self, compact=False): EXAMPLES:: + sage: # needs sage.graphs sage: M = CartanMatrix([[2,-2,0],[-2,2,-1],[0,-1,2]]) sage: M.is_hyperbolic() True @@ -858,6 +880,7 @@ def is_lorentzian(self): EXAMPLES:: + sage: # needs sage.graphs sage: M = CartanMatrix([[2,-3],[-3,2]]) sage: M.is_lorentzian() True @@ -876,6 +899,7 @@ def is_indefinite(self): EXAMPLES:: + sage: # needs sage.graphs sage: M = CartanMatrix([[2,-3],[-3,2]]) sage: M.is_indefinite() True @@ -892,6 +916,7 @@ def is_indecomposable(self): EXAMPLES:: + sage: # needs sage.graphs sage: M = CartanMatrix(['A',5]) sage: M.is_indecomposable() True @@ -912,6 +937,7 @@ def coxeter_matrix(self): EXAMPLES:: + sage: # needs sage.graphs sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]]) sage: cm.coxeter_matrix() [ 1 -1 2] @@ -949,6 +975,7 @@ def coxeter_diagram(self): EXAMPLES:: + sage: # needs sage.graphs sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]]) sage: G = cm.coxeter_diagram(); G Graph on 3 vertices @@ -972,13 +999,13 @@ def principal_submatrices(self, proper=False): EXAMPLES:: - sage: M = CartanMatrix(['A',2]) - sage: M.principal_submatrices() + sage: M = CartanMatrix(['A',2]) # needs sage.graphs + sage: M.principal_submatrices() # needs sage.graphs [ [ 2 -1] [], [2], [2], [-1 2] ] - sage: M.principal_submatrices(proper=True) + sage: M.principal_submatrices(proper=True) # needs sage.graphs [[], [2], [2]] """ @@ -996,6 +1023,7 @@ def indecomposable_blocks(self): EXAMPLES:: + sage: # needs sage.graphs sage: M = CartanMatrix(['A',2]) sage: M.indecomposable_blocks() ( @@ -1097,6 +1125,7 @@ def find_cartan_type_from_matrix(CM): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.combinat.root_system.cartan_matrix import find_cartan_type_from_matrix sage: CM = CartanMatrix([[2,-1,-1], [-1,2,-1], [-1,-1,2]]) sage: find_cartan_type_from_matrix(CM) diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index 825fc95ee16..727319bc230 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -16,13 +16,12 @@ Let us consider, for example, the Cartan type `A_4`:: - sage: T = CartanType(['A', 4]) - sage: T + sage: T = CartanType(['A', 4]); T ['A', 4] It is the name of the following Dynkin diagram:: - sage: DynkinDiagram(T) + sage: DynkinDiagram(T) # needs sage.graphs O---O---O---O 1 2 3 4 A4 @@ -31,15 +30,15 @@ For convenience, the following shortcuts are available:: - sage: DynkinDiagram(['A',4]) + sage: DynkinDiagram(['A',4]) # needs sage.graphs O---O---O---O 1 2 3 4 A4 - sage: DynkinDiagram('A4') + sage: DynkinDiagram('A4') # needs sage.graphs O---O---O---O 1 2 3 4 A4 - sage: T.dynkin_diagram() + sage: T.dynkin_diagram() # needs sage.graphs O---O---O---O 1 2 3 4 A4 @@ -55,10 +54,9 @@ The associated Weyl group of `A_n` is the symmetric group `S_{n+1}`:: - sage: W = WeylGroup(T) - sage: W + sage: W = WeylGroup(T); W # needs sage.libs.gap Weyl Group of type ['A', 4] (as a matrix group acting on the ambient space) - sage: W.cardinality() + sage: W.cardinality() # needs sage.libs.gap 120 while the Lie algebra is `sl_{n+1}`, and the Lie group `SL_{n+1}` @@ -67,22 +65,20 @@ One may also construct crystals associated to various Dynkin diagrams. For example:: - sage: C = crystals.Letters(T) - sage: C + sage: C = crystals.Letters(T); C # needs sage.combinat The crystal of letters for type ['A', 4] - sage: C.list() + sage: C.list() # needs sage.combinat [1, 2, 3, 4, 5] - sage: C = crystals.Tableaux(T, shape=[2]) - sage: C + sage: C = crystals.Tableaux(T, shape=[2]); C # needs sage.combinat The crystal of tableaux of type ['A', 4] and shape(s) [[2]] - sage: C.cardinality() + sage: C.cardinality() # needs sage.combinat 15 Here is a sample of all the finite irreducible crystallographic Cartan types:: - sage: CartanType.samples(finite = True, crystallographic = True) + sage: CartanType.samples(finite=True, crystallographic=True) [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2]] @@ -92,15 +88,17 @@ sage: [latex(ct) for ct in CartanType.samples(crystallographic=True)] [A_{1}, A_{5}, B_{1}, B_{5}, C_{1}, C_{5}, D_{2}, D_{3}, D_{5}, E_6, E_7, E_8, F_4, G_2, - A_{1}^{(1)}, A_{5}^{(1)}, B_{1}^{(1)}, B_{5}^{(1)}, C_{1}^{(1)}, C_{5}^{(1)}, D_{3}^{(1)}, D_{5}^{(1)}, + A_{1}^{(1)}, A_{5}^{(1)}, B_{1}^{(1)}, B_{5}^{(1)}, + C_{1}^{(1)}, C_{5}^{(1)}, D_{3}^{(1)}, D_{5}^{(1)}, E_6^{(1)}, E_7^{(1)}, E_8^{(1)}, F_4^{(1)}, G_2^{(1)}, BC_{1}^{(2)}, BC_{5}^{(2)}, - B_{5}^{(1)\vee}, C_{4}^{(1)\vee}, F_4^{(1)\vee}, G_2^{(1)\vee}, BC_{1}^{(2)\vee}, BC_{5}^{(2)\vee}] + B_{5}^{(1)\vee}, C_{4}^{(1)\vee}, F_4^{(1)\vee}, + G_2^{(1)\vee}, BC_{1}^{(2)\vee}, BC_{5}^{(2)\vee}] sage: view([DynkinDiagram(ct) for ct in CartanType.samples(crystallographic=True)]) # not tested Non-crystallographic Cartan types are also partially supported:: - sage: CartanType.samples(finite = True, crystallographic = False) + sage: CartanType.samples(finite=True, crystallographic=False) [['I', 5], ['H', 3], ['H', 4]] In Sage, a Cartan type is used as a database of type-specific @@ -118,7 +116,7 @@ Elements of Mathematics, Springer (2002). ISBN 978-3540426509. For example:: sage: T = CartanType(['D', 4]) - sage: DynkinDiagram(T) + sage: DynkinDiagram(T) # needs sage.graphs O 4 | | @@ -127,7 +125,7 @@ D4 sage: E6 = CartanType(['E',6]) - sage: DynkinDiagram(E6) + sage: DynkinDiagram(E6) # needs sage.graphs O 2 | | @@ -142,11 +140,11 @@ For example, in type `C_2`, we have:: - sage: C2 = DynkinDiagram(['C',2]); C2 + sage: C2 = DynkinDiagram(['C',2]); C2 # needs sage.graphs O=<=O 1 2 C2 - sage: C2.cartan_matrix() + sage: C2.cartan_matrix() # needs sage.graphs [ 2 -2] [-1 2] @@ -162,7 +160,7 @@ If desired, other node labelling conventions can be achieved. For example the Kac labelling for type `E_6` can be obtained via:: - sage: E6.relabel({1:1,2:6,3:2,4:3,5:4,6:5}).dynkin_diagram() + sage: E6.relabel({1:1,2:6,3:2,4:3,5:4,6:5}).dynkin_diagram() # needs sage.graphs O 6 | | @@ -183,25 +181,25 @@ Kac, Infinite Dimensional Lie Algebras. We start with an empty Dynkin diagram, and add a couple nodes:: - sage: g = DynkinDiagram() - sage: g.add_vertices([1,2,3]) + sage: g = DynkinDiagram() # needs sage.graphs + sage: g.add_vertices([1,2,3]) # needs sage.graphs Note that the diagonal of the Cartan matrix is already initialized:: - sage: g.cartan_matrix() + sage: g.cartan_matrix() # needs sage.graphs [2 0 0] [0 2 0] [0 0 2] Then we add a couple edges:: - sage: g.add_edge(1,2,2) - sage: g.add_edge(1,3) - sage: g.add_edge(2,3) + sage: g.add_edge(1,2,2) # needs sage.graphs + sage: g.add_edge(1,3) # needs sage.graphs + sage: g.add_edge(2,3) # needs sage.graphs and we get the desired Cartan matrix:: - sage: g.cartan_matrix() + sage: g.cartan_matrix() # needs sage.graphs [2 0 0] [0 2 0] [0 0 2] @@ -216,18 +214,18 @@ Here, we can work around this by clearing the cache:: - sage: delattr(g, 'cartan_matrix') + sage: delattr(g, 'cartan_matrix') # needs sage.graphs Now we get the desired Cartan matrix:: - sage: g.cartan_matrix() + sage: g.cartan_matrix() # needs sage.graphs [ 2 -1 -1] [-2 2 -1] [-1 -1 2] Note that backward edges have been automatically added:: - sage: g.edges(sort=True) + sage: g.edges(sort=True) # needs sage.graphs [(1, 2, 2), (1, 3, 1), (2, 1, 1), (2, 3, 1), (3, 1, 1), (3, 2, 1)] .. rubric:: Reducible Cartan types @@ -284,7 +282,7 @@ groups: each affine type is either untwisted (that is arise from the natural affinisation of a finite Cartan type):: - sage: CartanType(["A", 4, 1]).dynkin_diagram() + sage: CartanType(["A", 4, 1]).dynkin_diagram() # needs sage.graphs 0 O-----------+ | | @@ -292,7 +290,7 @@ O---O---O---O 1 2 3 4 A4~ - sage: CartanType(["B", 4, 1]).dynkin_diagram() + sage: CartanType(["B", 4, 1]).dynkin_diagram() # needs sage.graphs O 0 | | @@ -302,7 +300,7 @@ or dual thereof:: - sage: CartanType(["B", 4, 1]).dual().dynkin_diagram() + sage: CartanType(["B", 4, 1]).dual().dynkin_diagram() # needs sage.graphs O 0 | | @@ -313,18 +311,18 @@ or is of type `\widetilde{BC}_n` (which yields an irreducible, but nonreduced root system):: - sage: CartanType(["BC", 4, 2]).dynkin_diagram() + sage: CartanType(["BC", 4, 2]).dynkin_diagram() # needs sage.graphs O=<=O---O---O=<=O 0 1 2 3 4 BC4~ This includes the two degenerate cases:: - sage: CartanType(["A", 1, 1]).dynkin_diagram() + sage: CartanType(["A", 1, 1]).dynkin_diagram() # needs sage.graphs O<=>O 0 1 A1~ - sage: CartanType(["BC", 1, 2]).dynkin_diagram() + sage: CartanType(["BC", 1, 2]).dynkin_diagram() # needs sage.graphs 4 O=<=O 0 1 @@ -333,6 +331,7 @@ For the user convenience, Kac's notations for twisted affine types are automatically translated into the previous ones:: + sage: # needs sage.graphs sage: CartanType(["A", 9, 2]) ['B', 5, 1]^* sage: CartanType(["A", 9, 2]).dynkin_diagram() @@ -362,6 +361,7 @@ Additionally one can set the notation option to use Kac's notation:: + sage: # needs sage.graphs sage: CartanType.options['notation'] = 'Kac' sage: CartanType(["A", 9, 2]) ['A', 9, 2] @@ -546,7 +546,7 @@ def __call__(self, *args): sage: CT = CartanType([['A',2]]) sage: CT.is_irreducible() True - sage: CT.cartan_matrix() + sage: CT.cartan_matrix() # needs sage.graphs [ 2 -1] [-1 2] sage: CT = CartanType(['A2']) @@ -726,7 +726,7 @@ def __call__(self, *args): if len(t) == 2 and len(n) == 2: from . import type_super_A return type_super_A.CartanType(n[0], n[1]) - raise ValueError("%s is not a valid super Cartan type"%t) + raise ValueError("%s is not a valid super Cartan type" % t) # As the Cartan type has not been recognised try subtypes - but check # for the error noted in trac:??? @@ -734,7 +734,7 @@ def __call__(self, *args): try: return type_reducible.CartanType([ CartanType(subtype) for subtype in t ]) except (SyntaxError, ValueError): - raise ValueError("%s is not a valid Cartan type"%t) + raise ValueError("%s is not a valid Cartan type" % t) def _repr_(self): """ @@ -898,7 +898,7 @@ class options(GlobalOptions): sage: ct = CartanType(['D',5,2]); ct ['C', 4, 1]^* - sage: ct.dynkin_diagram() + sage: ct.dynkin_diagram() # needs sage.graphs O=<=O---O---O=>=O 0 1 2 3 4 C4~* @@ -907,7 +907,7 @@ class options(GlobalOptions): sage: CartanType.options(dual_str='#', dual_latex='\\ast',) sage: ct ['C', 4, 1]^# - sage: ct.dynkin_diagram() + sage: ct.dynkin_diagram() # needs sage.graphs O=<=O---O---O=>=O 0 1 2 3 4 C4~# @@ -916,7 +916,7 @@ class options(GlobalOptions): sage: CartanType.options(notation='kac', mark_special_node='both') sage: ct ['D', 5, 2] - sage: ct.dynkin_diagram() + sage: ct.dynkin_diagram() # needs sage.graphs @=<=O---O---O=>=O 0 1 2 3 4 D5^2 @@ -930,7 +930,7 @@ class options(GlobalOptions): ['A', 8, 2]^+ sage: latex(dct) A_{8}^{(2)\dagger} - sage: dct.dynkin_diagram() + sage: dct.dynkin_diagram() # needs sage.graphs @=>=O---O---O=>=O 0 1 2 3 4 A8^2+ @@ -1083,7 +1083,7 @@ def _latex_draw_arrow_tip(self, x, y, rot=0): sage: CartanType(['B',2])._latex_draw_arrow_tip(1, 0, 180) '\\draw[shift={(1, 0)}, rotate=180] (135 : 0.45cm) -- (0,0) -- (-135 : 0.45cm);\n' """ - return "\\draw[shift={(%s, %s)}, rotate=%s] (135 : 0.45cm) -- (0,0) -- (-135 : 0.45cm);\n"%(x, y, rot) + return "\\draw[shift={(%s, %s)}, rotate=%s] (135 : 0.45cm) -- (0,0) -- (-135 : 0.45cm);\n" % (x, y, rot) @abstract_method def rank(self): @@ -1142,13 +1142,14 @@ def index_set(self): # be used for Coxeter groups etc. (experimental feature) _index_set_coloring = {1:"blue", 2:"red", 3:"green"} - @abstract_method(optional = True) + @abstract_method(optional=True) def coxeter_diagram(self): """ Return the Coxeter diagram for ``self``. EXAMPLES:: + sage: # needs sage.graphs sage: CartanType(['B',3]).coxeter_diagram() Graph on 3 vertices sage: CartanType(['A',3]).coxeter_diagram().edges(sort=True) @@ -1168,7 +1169,7 @@ def coxeter_matrix(self): EXAMPLES:: - sage: CartanType(['A', 4]).coxeter_matrix() + sage: CartanType(['A', 4]).coxeter_matrix() # needs sage.graphs [1 3 2 2] [3 1 3 2] [2 3 1 3] @@ -1228,7 +1229,7 @@ def relabel(self, relabelling): EXAMPLES:: - sage: CartanType(['F',4]).relabel({ 1:4, 2:3, 3:2, 4:1 }).dynkin_diagram() + sage: CartanType(['F',4]).relabel({ 1:4, 2:3, 3:2, 4:1 }).dynkin_diagram() # needs sage.graphs O---O=>=O---O 4 3 2 1 F4 relabelled by {1: 4, 2: 3, 3: 2, 4: 1} @@ -1246,11 +1247,11 @@ def subtype(self, index_set): EXAMPLES:: sage: ct = CartanType(['A',6,2]) - sage: ct.dynkin_diagram() + sage: ct.dynkin_diagram() # needs sage.graphs O=<=O---O=<=O 0 1 2 3 BC3~ - sage: ct.subtype([1,2,3]) + sage: ct.subtype([1,2,3]) # needs sage.graphs ['C', 3] """ return self.cartan_matrix().subtype(index_set).cartan_type() @@ -1265,7 +1266,7 @@ def marked_nodes(self, marked_nodes): EXAMPLES:: - sage: CartanType(['F',4]).marked_nodes([1, 3]).dynkin_diagram() + sage: CartanType(['F',4]).marked_nodes([1, 3]).dynkin_diagram() # needs sage.graphs X---O=>=X---O 1 2 3 4 F4 with nodes (1, 3) marked @@ -1416,7 +1417,8 @@ def is_simply_laced(self): [['C', 1], True], [['C', 5], False], [['D', 2], True], [['D', 3], True], [['D', 5], True], [['E', 6], True], [['E', 7], True], [['E', 8], True], - [['F', 4], False], [['G', 2], False], [['I', 5], False], [['H', 3], False], [['H', 4], False], + [['F', 4], False], [['G', 2], False], [['I', 5], False], + [['H', 3], False], [['H', 4], False], [['A', 1, 1], False], [['A', 5, 1], True], [['B', 1, 1], False], [['B', 5, 1], False], [['C', 1, 1], False], [['C', 5, 1], False], @@ -1424,7 +1426,8 @@ def is_simply_laced(self): [['E', 6, 1], True], [['E', 7, 1], True], [['E', 8, 1], True], [['F', 4, 1], False], [['G', 2, 1], False], [['BC', 1, 2], False], [['BC', 5, 2], False], - [['B', 5, 1]^*, False], [['C', 4, 1]^*, False], [['F', 4, 1]^*, False], [['G', 2, 1]^*, False], + [['B', 5, 1]^*, False], [['C', 4, 1]^*, False], + [['F', 4, 1]^*, False], [['G', 2, 1]^*, False], [['BC', 1, 2]^*, False], [['BC', 5, 2]^*, False]] """ return False @@ -1516,8 +1519,8 @@ def _default_folded_cartan_type(self): EXAMPLES:: - sage: D = CartanMatrix([[2, -3], [-2, 2]]).dynkin_diagram() - sage: D._default_folded_cartan_type() + sage: D = CartanMatrix([[2, -3], [-2, 2]]).dynkin_diagram() # needs sage.graphs + sage: D._default_folded_cartan_type() # needs sage.graphs Dynkin diagram of rank 2 as a folding of Dynkin diagram of rank 2 """ from sage.combinat.root_system.type_folded import CartanTypeFolded @@ -1558,9 +1561,9 @@ def ascii_art(self, label='lambda x: x', node=None): The label option is useful to visualize various statistics on the nodes of the Dynkin diagram:: - sage: a = cartan_type.col_annihilator(); a + sage: a = cartan_type.col_annihilator(); a # needs sage.graphs Finite family {0: 1, 1: 1, 2: 2, 3: 2, 4: 2, 5: 2} - sage: print(CartanType(['B',5,1]).ascii_art(label=a.__getitem__)) + sage: print(CartanType(['B',5,1]).ascii_art(label=a.__getitem__)) # needs sage.graphs O 1 | | @@ -1588,7 +1591,7 @@ def _latex_dynkin_diagram(self, label='lambda i: i', EXAMPLES:: - sage: latex(CartanType(['A',4]).dynkin_diagram()) # indirect doctest + sage: latex(CartanType(['A',4]).dynkin_diagram()) # indirect doctest # needs sage.graphs \begin{tikzpicture}[scale=0.5] \draw (-1,0) node[anchor=east] {$A_{4}$}; \draw (0 cm,0) -- (6 cm,0); @@ -1606,7 +1609,7 @@ def dynkin_diagram(self): EXAMPLES:: - sage: CartanType(['A',4]).dynkin_diagram() + sage: CartanType(['A',4]).dynkin_diagram() # needs sage.graphs O---O---O---O 1 2 3 4 A4 @@ -1624,7 +1627,7 @@ def cartan_matrix(self): EXAMPLES:: - sage: CartanType(['A',4]).cartan_matrix() + sage: CartanType(['A',4]).cartan_matrix() # needs sage.graphs [ 2 -1 0 0] [-1 2 -1 0] [ 0 -1 2 -1] @@ -1643,6 +1646,7 @@ def coxeter_diagram(self): EXAMPLES:: + sage: # needs sage.graphs sage: CartanType(['A',3]).coxeter_diagram() Graph on 3 vertices sage: CartanType(['A',3]).coxeter_diagram().edges(sort=True) @@ -1689,30 +1693,30 @@ def symmetrizer(self): EXAMPLES:: - sage: CartanType(["B",5]).symmetrizer() + sage: CartanType(["B",5]).symmetrizer() # needs sage.graphs Finite family {1: 2, 2: 2, 3: 2, 4: 2, 5: 1} Here is a neat trick to visualize it better:: sage: T = CartanType(["B",5]) - sage: print(T.ascii_art(T.symmetrizer().__getitem__)) + sage: print(T.ascii_art(T.symmetrizer().__getitem__)) # needs sage.graphs O---O---O---O=>=O 2 2 2 2 1 sage: T = CartanType(["BC",5, 2]) - sage: print(T.ascii_art(T.symmetrizer().__getitem__)) + sage: print(T.ascii_art(T.symmetrizer().__getitem__)) # needs sage.graphs O=<=O---O---O---O=<=O 1 2 2 2 2 4 Here is the symmetrizer of some reducible Cartan types:: sage: T = CartanType(["D", 2]) - sage: print(T.ascii_art(T.symmetrizer().__getitem__)) + sage: print(T.ascii_art(T.symmetrizer().__getitem__)) # needs sage.graphs O O 1 1 sage: T = CartanType(["B",5],["BC",5, 2]) - sage: print(T.ascii_art(T.symmetrizer().__getitem__)) + sage: print(T.ascii_art(T.symmetrizer().__getitem__)) # needs sage.graphs O---O---O---O=>=O 2 2 2 2 1 O=<=O---O---O---O=<=O @@ -1722,7 +1726,7 @@ def symmetrizer(self): of the simple roots in the ambient space:: sage: T = CartanType(["C",5]) - sage: print(T.ascii_art(T.symmetrizer().__getitem__)) + sage: print(T.ascii_art(T.symmetrizer().__getitem__)) # needs sage.graphs O---O---O---O=<=O 1 1 1 1 2 @@ -1734,12 +1738,12 @@ def symmetrizer(self): from sage.matrix.constructor import matrix, diagonal_matrix m = self.cartan_matrix() n = m.nrows() - M = matrix(ZZ, n, n*n, sparse = True) + M = matrix(ZZ, n, n*n, sparse=True) for (i,j) in m.nonzero_positions(): - M[i, n * i + j] = m[i,j] + M[i, n * i + j] = m[i,j] M[j, n * i + j] -= m[j,i] kern = M.integer_kernel() - c = len(self.dynkin_diagram().connected_components()) + c = len(self.dynkin_diagram().connected_components(sort=False)) if kern.dimension() < c: # the Cartan matrix is not symmetrizable return None @@ -1766,10 +1770,10 @@ def index_set_bipartition(self): EXAMPLES:: - sage: CartanType(['A',5]).index_set_bipartition() + sage: CartanType(['A',5]).index_set_bipartition() # needs sage.graphs ({1, 3, 5}, {2, 4}) - sage: CartanType(['A',2,1]).index_set_bipartition() + sage: CartanType(['A',2,1]).index_set_bipartition() # needs sage.graphs Traceback (most recent call last): ... ValueError: the Dynkin diagram must be bipartite @@ -1937,7 +1941,7 @@ def is_untwisted_affine(self): sage: CartanType(['A', 3, 1]).is_untwisted_affine() True - sage: CartanType(['A', 3, 1]).dual().is_untwisted_affine() # this one is self dual! + sage: CartanType(['A', 3, 1]).dual().is_untwisted_affine() # this one is self dual! True sage: CartanType(['B', 3, 1]).dual().is_untwisted_affine() False @@ -1979,6 +1983,7 @@ def special_nodes(self): EXAMPLES:: + sage: # needs sage.graphs sage.groups sage: CartanType(['A',3,1]).special_nodes() (0, 1, 2, 3) sage: CartanType(['C',2,1]).special_nodes() @@ -2036,7 +2041,7 @@ def classical(self): :meth:`sage.combinat.root_system.cartan_type.CartanType_crystallographic.dynkin_diagram`, and :meth:`special_node` are consistent:: - sage: for ct in CartanType.samples(affine = True): + sage: for ct in CartanType.samples(affine=True): # needs sage.graphs ....: g1 = ct.classical().dynkin_diagram() ....: g2 = ct.dynkin_diagram() ....: g2.delete_vertex(ct.special_node()) @@ -2082,7 +2087,7 @@ def basic_untwisted(self): ['D', 4] """ - def row_annihilator(self, m = None): + def row_annihilator(self, m=None): r""" Return the unique minimal non trivial annihilating linear combination of `\alpha_0, \alpha_1, \ldots, \alpha_n` with @@ -2096,6 +2101,7 @@ def row_annihilator(self, m = None): EXAMPLES:: + sage: # needs sage.graphs sage: RootSystem(['C',2,1]).cartan_type().acheck() Finite family {0: 1, 1: 1, 2: 1} sage: RootSystem(['D',4,1]).cartan_type().acheck() @@ -2107,7 +2113,7 @@ def row_annihilator(self, m = None): ``acheck`` is a shortcut for row_annihilator:: - sage: RootSystem(['BC',4,2]).cartan_type().row_annihilator() + sage: RootSystem(['BC',4,2]).cartan_type().row_annihilator() # needs sage.graphs Finite family {0: 1, 1: 2, 2: 2, 3: 2, 4: 2} FIXME: @@ -2145,6 +2151,7 @@ def col_annihilator(self): EXAMPLES:: + sage: # needs sage.graphs sage: RootSystem(['C',2,1]).cartan_type().a() Finite family {0: 1, 1: 2, 2: 1} sage: RootSystem(['D',4,1]).cartan_type().a() @@ -2156,7 +2163,7 @@ def col_annihilator(self): ``a`` is a shortcut for col_annihilator:: - sage: RootSystem(['BC',4,2]).cartan_type().col_annihilator() + sage: RootSystem(['BC',4,2]).cartan_type().col_annihilator() # needs sage.graphs Finite family {0: 2, 1: 2, 2: 2, 3: 2, 4: 1} """ return self.row_annihilator(self.cartan_matrix().transpose()) @@ -2174,6 +2181,7 @@ def c(self): EXAMPLES:: + sage: # needs sage.graphs sage: RootSystem(['C',2,1]).cartan_type().c() Finite family {0: 1, 1: 2, 2: 1} sage: RootSystem(['D',4,1]).cartan_type().c() @@ -2185,7 +2193,7 @@ def c(self): TESTS:: - sage: CartanType(["B", 3, 1]).c().map(parent) + sage: CartanType(["B", 3, 1]).c().map(parent) # needs sage.graphs Finite family {0: Integer Ring, 1: Integer Ring, 2: Integer Ring, 3: Integer Ring} REFERENCES: @@ -2230,6 +2238,7 @@ def translation_factors(self): EXAMPLES:: + sage: # needs sage.graphs sage: CartanType(['C',2,1]).translation_factors() Finite family {0: 1, 1: 2, 2: 1} sage: CartanType(['C',2,1]).dual().translation_factors() @@ -2244,6 +2253,7 @@ def translation_factors(self): We proceed with systematic tests taken from MuPAD-Combinat's testsuite:: + sage: # needs sage.graphs sage: list(CartanType(["A", 1, 1]).translation_factors()) [1, 1] sage: list(CartanType(["A", 5, 1]).translation_factors()) @@ -2288,37 +2298,37 @@ def translation_factors(self): along `\Lambda_0`:: sage: R = RootSystem(["BC",2,2]) - sage: alpha = R.weight_space().simple_roots() + sage: alpha = R.weight_space().simple_roots() # needs sage.graphs sage: alphacheck = R.coroot_space().simple_roots() sage: Lambda = R.weight_space().fundamental_weights() Here are the levels of the fundamental weights:: - sage: Lambda[0].level(), Lambda[1].level(), Lambda[2].level() + sage: Lambda[0].level(), Lambda[1].level(), Lambda[2].level() # needs sage.graphs (1, 2, 2) So the "center" of the fundamental polygon at level `1` is:: sage: O = Lambda[0] - sage: O.level() + sage: O.level() # needs sage.graphs 1 We take the projection `\omega_1` at level `0` of `\Lambda_1` as unit vector on the `x`-axis, and the projection `\omega_2` at level 0 of `\Lambda_2` as unit vector of the `y`-axis:: - sage: omega1 = Lambda[1]-2*Lambda[0] - sage: omega2 = Lambda[2]-2*Lambda[0] - sage: omega1.level(), omega2.level() + sage: omega1 = Lambda[1] - 2*Lambda[0] + sage: omega2 = Lambda[2] - 2*Lambda[0] + sage: omega1.level(), omega2.level() # needs sage.graphs (0, 0) The projections of the simple roots can be read off:: - sage: alpha[0] + sage: alpha[0] # needs sage.graphs 2*Lambda[0] - Lambda[1] - sage: alpha[1] + sage: alpha[1] # needs sage.graphs -2*Lambda[0] + 2*Lambda[1] - Lambda[2] - sage: alpha[2] + sage: alpha[2] # needs sage.graphs -2*Lambda[1] + 2*Lambda[2] Namely `\alpha_0 = -\omega_1`, `\alpha_1 = 2\omega_1 - @@ -2350,14 +2360,14 @@ def translation_factors(self): smallest with this property. Hence, the translation factors for affine type `BC` are `t_0=1, t_1=1, t_2=1/2`:: - sage: CartanType(['BC',2,2]).translation_factors() + sage: CartanType(['BC',2,2]).translation_factors() # needs sage.graphs Finite family {0: 1, 1: 1, 2: 1/2} TESTS:: - sage: CartanType(["B", 3, 1]).translation_factors().map(parent) + sage: CartanType(["B", 3, 1]).translation_factors().map(parent) # needs sage.graphs Finite family {0: Integer Ring, 1: Integer Ring, 2: Integer Ring, 3: Integer Ring} - sage: CartanType(["BC", 3, 2]).translation_factors().map(parent) + sage: CartanType(["BC", 3, 2]).translation_factors().map(parent) # needs sage.graphs Finite family {0: Integer Ring, 1: Integer Ring, 2: Integer Ring, 3: Rational Field} REFERENCES: @@ -2423,7 +2433,7 @@ def other_affinization(self): class CartanType_standard(UniqueRepresentation, SageObject): # Technical methods - def _repr_(self, compact = False): + def _repr_(self, compact=False): """ TESTS:: @@ -2434,7 +2444,7 @@ def _repr_(self, compact = False): 'A3' """ format = '%s%s' if compact else "['%s', %s]" - return format%(self.letter, self.n) + return format % (self.letter, self.n) def __len__(self): """ @@ -2625,7 +2635,7 @@ def dual_coxeter_number(self): def type(self): """ - Returns the type of ``self``. + Return the type of ``self``. EXAMPLES:: @@ -2639,7 +2649,7 @@ def type(self): @cached_method def opposition_automorphism(self): r""" - Returns the opposition automorphism + Return the opposition automorphism The *opposition automorphism* is the automorphism `i \mapsto i^*` of the vertices Dynkin diagram such that, @@ -2651,19 +2661,19 @@ def opposition_automorphism(self): EXAMPLES:: sage: ct = CartanType(['A', 5]) - sage: ct.opposition_automorphism() + sage: ct.opposition_automorphism() # needs sage.libs.gap Finite family {1: 5, 2: 4, 3: 3, 4: 2, 5: 1} sage: ct = CartanType(['D', 4]) - sage: ct.opposition_automorphism() + sage: ct.opposition_automorphism() # needs sage.libs.gap Finite family {1: 1, 2: 2, 3: 3, 4: 4} sage: ct = CartanType(['D', 5]) - sage: ct.opposition_automorphism() + sage: ct.opposition_automorphism() # needs sage.libs.gap Finite family {1: 1, 2: 2, 3: 3, 4: 5, 5: 4} sage: ct = CartanType(['C', 4]) - sage: ct.opposition_automorphism() + sage: ct.opposition_automorphism() # needs sage.libs.gap Finite family {1: 1, 2: 2, 3: 3, 4: 4} """ Q = self.root_system().root_lattice() @@ -2681,7 +2691,7 @@ class CartanType_standard_affine(CartanType_standard, CartanType_affine): A concrete class for affine simple Cartan types. """ - def __init__(self, letter, n, affine = 1): + def __init__(self, letter, n, affine=1): """ EXAMPLES:: @@ -2706,7 +2716,7 @@ def __init__(self, letter, n, affine = 1): self.n = n self.affine = affine - def _repr_(self, compact = False): + def _repr_(self, compact=False): """ TESTS:: @@ -3016,7 +3026,7 @@ def index_set(self): class SuperCartanType_standard(UniqueRepresentation, SageObject): # Technical methods - def _repr_(self, compact = False): + def _repr_(self, compact=False): """ TESTS:: @@ -3027,7 +3037,7 @@ def _repr_(self, compact = False): 'A3|2' """ formatstr = '%s%s|%s' if compact else "['%s', [%s, %s]]" - return formatstr%(self.letter, self.m, self.n) + return formatstr % (self.letter, self.m, self.n) def __len__(self): """ @@ -3083,7 +3093,7 @@ def __setstate__(self, dict): sage: si1 ['A', 4] - sage: si1.dynkin_diagram() + sage: si1.dynkin_diagram() # needs sage.graphs O---O---O---O 1 2 3 4 A4 diff --git a/src/sage/combinat/root_system/coxeter_group.py b/src/sage/combinat/root_system/coxeter_group.py index 8c7e6306508..f33003b35f6 100644 --- a/src/sage/combinat/root_system/coxeter_group.py +++ b/src/sage/combinat/root_system/coxeter_group.py @@ -9,9 +9,11 @@ # https://www.gnu.org/licenses/ # *************************************************************************** -from sage.combinat.root_system.weyl_group import WeylGroup -from sage.combinat.root_system.reflection_group_real import ReflectionGroup from sage.combinat.root_system.cartan_type import CartanType +from sage.misc.lazy_import import lazy_import + +lazy_import('from sage.combinat.root_system.reflection_group_real', 'ReflectionGroup') +lazy_import('sage.combinat.root_system.weyl_group', 'WeylGroup') def CoxeterGroup(data, implementation="reflection", base_ring=None, index_set=None): @@ -46,78 +48,75 @@ def CoxeterGroup(data, implementation="reflection", base_ring=None, index_set=No ``implementation`` is not specified, the reflection representation is returned:: - sage: W = CoxeterGroup(["A",2]) - sage: W + sage: W = CoxeterGroup(["A",2]); W # needs sage.libs.gap Finite Coxeter group over Integer Ring with Coxeter matrix: [1 3] [3 1] - sage: W = CoxeterGroup(["A",3,1]); W + sage: W = CoxeterGroup(["A",3,1]); W # needs sage.libs.gap Coxeter group over Integer Ring with Coxeter matrix: [1 3 2 3] [3 1 3 2] [2 3 1 3] [3 2 3 1] - sage: W = CoxeterGroup(['H',3]); W - Finite Coxeter group over Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? with Coxeter matrix: + sage: W = CoxeterGroup(['H',3]); W # needs sage.libs.gap + Finite Coxeter group over Number Field in a with defining polynomial x^2 - 5 + with a = 2.236067977499790? with Coxeter matrix: [1 3 2] [3 1 5] [2 5 1] We now use the ``implementation`` option:: - sage: W = CoxeterGroup(["A",2], implementation = "permutation") # optional - gap3 - sage: W # optional - gap3 + sage: W = CoxeterGroup(["A",2], implementation="permutation"); W # optional - gap3 Permutation Group with generators [(1,4)(2,3)(5,6), (1,3)(2,5)(4,6)] - sage: W.category() # optional - gap3 + sage: W.category() # optional - gap3 Join of Category of finite enumerated permutation groups - and Category of finite weyl groups - and Category of well generated finite irreducible complex reflection groups + and Category of finite weyl groups + and Category of well generated finite irreducible complex reflection groups - sage: W = CoxeterGroup(["A",2], implementation="matrix") - sage: W + sage: W = CoxeterGroup(["A",2], implementation="matrix"); W # needs sage.libs.gap Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space) - sage: W = CoxeterGroup(["H",3], implementation="matrix") - sage: W - Finite Coxeter group over Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? with Coxeter matrix: + sage: W = CoxeterGroup(["H",3], implementation="matrix"); W # needs sage.libs.gap sage.rings.number_field + Finite Coxeter group over Number Field in a with defining polynomial x^2 - 5 + with a = 2.236067977499790? with Coxeter matrix: [1 3 2] [3 1 5] [2 5 1] - sage: W = CoxeterGroup(["H",3], implementation="reflection") - sage: W - Finite Coxeter group over Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? with Coxeter matrix: + sage: W = CoxeterGroup(["H",3], implementation="reflection"); W # needs sage.rings.number_field + Finite Coxeter group over Number Field in a with defining polynomial x^2 - 5 + with a = 2.236067977499790? with Coxeter matrix: [1 3 2] [3 1 5] [2 5 1] - sage: W = CoxeterGroup(["A",4,1], implementation="permutation") + sage: W = CoxeterGroup(["A",4,1], implementation="permutation") # needs sage.libs.gap Traceback (most recent call last): ... ValueError: the type must be finite - sage: W = CoxeterGroup(["A",4], implementation="chevie"); W # optional - gap3 + sage: W = CoxeterGroup(["A",4], implementation="chevie"); W # optional - gap3 Irreducible real reflection group of rank 4 and type A4 We use the different options for the "reflection" implementation:: - sage: W = CoxeterGroup(["H",3], implementation="reflection", base_ring=RR) - sage: W + sage: W = CoxeterGroup(["H",3], implementation="reflection", base_ring=RR); W # needs sage.libs.gap Finite Coxeter group over Real Field with 53 bits of precision with Coxeter matrix: [1 3 2] [3 1 5] [2 5 1] - sage: W = CoxeterGroup([[1,10],[10,1]], implementation="reflection", index_set=['a','b'], base_ring=SR) - sage: W + sage: W = CoxeterGroup([[1,10],[10,1]], implementation="reflection", # needs sage.symbolics + ....: index_set=['a','b'], base_ring=SR); W Finite Coxeter group over Symbolic Ring with Coxeter matrix: [ 1 10] [10 1] TESTS:: - sage: W = groups.misc.CoxeterGroup(["H",3]) + sage: W = groups.misc.CoxeterGroup(["H",3]) # needs sage.groups """ if implementation not in ["permutation", "matrix", "coxeter3", "reflection", "chevie", None]: raise ValueError("invalid type implementation") diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 9ae647552e2..719d23c3409 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs """ Coxeter Matrices """ @@ -22,8 +23,8 @@ from sage.matrix.constructor import matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall +from sage.misc.lazy_import import lazy_import from sage.matrix.matrix_generic_dense import Matrix_generic_dense -from sage.graphs.graph import Graph from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RR @@ -31,6 +32,8 @@ from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.coxeter_type import CoxeterType +lazy_import('sage.graphs.graph', 'Graph') + class CoxeterMatrix(CoxeterType, metaclass=ClasscallMetaclass): r""" diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 9c10c3c04db..ef1d4beb922 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -17,17 +17,20 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import sage.rings.abc + +from sage.combinat.root_system.cartan_type import CartanType from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.misc.classcall_metaclass import ClasscallMetaclass -from sage.combinat.root_system.cartan_type import CartanType -import sage.rings.abc from sage.matrix.args import SparseEntry -from sage.matrix.all import Matrix -from sage.symbolic.ring import SR +from sage.matrix.constructor import Matrix +from sage.misc.lazy_import import lazy_import from sage.structure.unique_representation import UniqueRepresentation from sage.structure.sage_object import SageObject +lazy_import('sage.rings.universal_cyclotomic_field', 'UniversalCyclotomicField') + class CoxeterType(SageObject, metaclass=ClasscallMetaclass): """ @@ -242,11 +245,11 @@ def coxeter_matrix(self): EXAMPLES:: - sage: CoxeterType(['A', 3]).coxeter_matrix() + sage: CoxeterType(['A', 3]).coxeter_matrix() # needs sage.graphs [1 3 2] [3 1 3] [2 3 1] - sage: CoxeterType(['A', 3, 1]).coxeter_matrix() + sage: CoxeterType(['A', 3, 1]).coxeter_matrix() # needs sage.graphs [1 3 2 3] [3 1 3 2] [2 3 1 3] @@ -260,9 +263,9 @@ def coxeter_graph(self): EXAMPLES:: - sage: CoxeterType(['A', 3]).coxeter_graph() + sage: CoxeterType(['A', 3]).coxeter_graph() # needs sage.graphs Graph on 3 vertices - sage: CoxeterType(['A', 3, 1]).coxeter_graph() + sage: CoxeterType(['A', 3, 1]).coxeter_graph() # needs sage.graphs Graph on 4 vertices """ @@ -354,6 +357,7 @@ def bilinear_form(self, R=None): EXAMPLES:: + sage: # needs sage.graphs sage.rings.number_field sage: CoxeterType(['A', 2, 1]).bilinear_form() [ 1 -1/2 -1/2] [-1/2 1 -1/2] @@ -372,19 +376,12 @@ def bilinear_form(self, R=None): n = self.rank() mat = self.coxeter_matrix()._matrix - from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField - UCF = UniversalCyclotomicField() - if R is None: - R = UCF - # if UCF.has_coerce_map_from(base_ring): - # R = UCF - # else: - # R = base_ring + R = UniversalCyclotomicField() # Compute the matrix with entries `- \cos( \pi / m_{ij} )`. - E = UCF.gen - if R is UCF: + if isinstance(R, sage.rings.abc.UniversalCyclotomicField): + E = R.gen def val(x): if x > -1: @@ -392,6 +389,7 @@ def val(x): else: return R(x) elif isinstance(R, sage.rings.abc.NumberField_quadratic): + E = UniversalCyclotomicField().gen def val(x): if x > -1: @@ -401,6 +399,7 @@ def val(x): else: from sage.functions.trig import cos from sage.symbolic.constants import pi + from sage.symbolic.ring import SR def val(x): if x > -1: @@ -481,7 +480,7 @@ def coxeter_matrix(self): EXAMPLES:: sage: C = CoxeterType(['H',3]) - sage: C.coxeter_matrix() + sage: C.coxeter_matrix() # needs sage.graphs [1 3 2] [3 1 5] [2 5 1] @@ -495,7 +494,7 @@ def coxeter_graph(self): EXAMPLES:: sage: C = CoxeterType(['H',3]) - sage: C.coxeter_graph().edges(sort=True) + sage: C.coxeter_graph().edges(sort=True) # needs sage.graphs [(1, 2, 3), (2, 3, 5)] """ return self._cartan_type.coxeter_diagram() diff --git a/src/sage/combinat/root_system/dynkin_diagram.py b/src/sage/combinat/root_system/dynkin_diagram.py index 89826d15d12..fe5f93549ef 100644 --- a/src/sage/combinat/root_system/dynkin_diagram.py +++ b/src/sage/combinat/root_system/dynkin_diagram.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.graphs """ Dynkin diagrams @@ -28,10 +29,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.structure.element import is_Matrix from sage.graphs.digraph import DiGraph from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract -from sage.combinat.root_system.cartan_matrix import CartanMatrix + +lazy_import('sage.combinat.root_system.cartan_matrix', 'CartanMatrix') def DynkinDiagram(*args, **kwds): @@ -186,7 +189,7 @@ def DynkinDiagram(*args, **kwds): return mat.cartan_type().dynkin_diagram() except AttributeError: ct = CartanType(*args) - raise ValueError("Dynkin diagram data not yet hardcoded for type %s"%ct) + raise ValueError("Dynkin diagram data not yet hardcoded for type %s" % ct) if len(args) > 1: index_set = tuple(args[1]) elif "index_set" in kwds: @@ -202,7 +205,7 @@ def DynkinDiagram(*args, **kwds): try: return ct.dynkin_diagram() except AttributeError: - raise ValueError("Dynkin diagram data not yet hardcoded for type %s"%ct) + raise ValueError("Dynkin diagram data not yet hardcoded for type %s" % ct) class DynkinDiagram_class(DiGraph, CartanType_abstract): @@ -287,7 +290,7 @@ def _repr_(self, compact=False): G2 """ ct = self.cartan_type() - result = ct.ascii_art() +"\n" if hasattr(ct, "ascii_art") else "" + result = ct.ascii_art() + "\n" if hasattr(ct, "ascii_art") else "" if ct is None or isinstance(ct, CartanMatrix): return result+"Dynkin diagram of rank %s" % self.rank() @@ -875,23 +878,23 @@ def precheck(t, letter=None, length=None, affine=None, n_ge=None, n=None): """ if letter is not None: if t[0] != letter: - raise ValueError("t[0] must be = '%s'"%letter) + raise ValueError("t[0] must be = '%s'" % letter) if length is not None: if len(t) != length: - raise ValueError("len(t) must be = %s"%length) + raise ValueError("len(t) must be = %s" % length) if affine is not None: try: if t[2] != affine: - raise ValueError("t[2] must be = %s"%affine) + raise ValueError("t[2] must be = %s" % affine) except IndexError: - raise ValueError("t[2] must be = %s"%affine) + raise ValueError("t[2] must be = %s" % affine) if n_ge is not None: if t[1] < n_ge: - raise ValueError("t[1] must be >= %s"%n_ge) + raise ValueError("t[1] must be >= %s" % n_ge) if n is not None: if t[1] != n: - raise ValueError("t[1] must be = %s"%n) + raise ValueError("t[1] must be = %s" % n) diff --git a/src/sage/combinat/root_system/extended_affine_weyl_group.py b/src/sage/combinat/root_system/extended_affine_weyl_group.py index f4a2e54a88e..e81477653c2 100644 --- a/src/sage/combinat/root_system/extended_affine_weyl_group.py +++ b/src/sage/combinat/root_system/extended_affine_weyl_group.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.gap r""" Extended Affine Weyl Groups @@ -55,7 +56,7 @@ def ExtendedAffineWeylGroup(cartan_type, general_linear=None, **print_options): - ``cartan_type`` -- An affine or finite Cartan type (a finite Cartan type is an abbreviation for its untwisted affinization) - - ``general_linear`` -- (default: None) If True and ``cartan_type`` indicates + - ``general_linear`` -- (default: ``None``) If ``True`` and ``cartan_type`` indicates untwisted type A, returns the universal central extension - ``print_options`` -- Special instructions for printing elements (see below) @@ -75,8 +76,8 @@ def ExtendedAffineWeylGroup(cartan_type, general_linear=None, **print_options): Recognized arguments for ``print_options`` are: - - ``print_tuple`` -- True or False (default: False) If True, elements are printed - `(a,b)`, otherwise as `a * b` + - ``print_tuple`` -- ``True`` or ``False`` (default: ``False``) + If ``True``, elements are printed `(a,b)`, otherwise as `a * b` - ``affine`` -- Prefix for simple reflections in the affine Weyl group - ``classical`` -- Prefix for simple reflections in the classical Weyl group - ``translation`` -- Prefix for the translation elements @@ -203,23 +204,37 @@ def ExtendedAffineWeylGroup(cartan_type, general_linear=None, **print_options): sage: type(E) <class 'sage.combinat.root_system.extended_affine_weyl_group.ExtendedAffineWeylGroup_Class_with_category'> - sage: PW0=E.PW0(); PW0 - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Multiplicative form of Coweight lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) + sage: PW0 = E.PW0(); PW0 + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Multiplicative form of Coweight lattice of the Root system of type ['A', 2] + acted upon by Weyl Group of type ['A', 2] + (as a matrix group acting on the coweight lattice) sage: W0P = E.W0P(); W0P - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) acting on Multiplicative form of Coweight lattice of the Root system of type ['A', 2] + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) + acting on Multiplicative form of Coweight lattice of the Root system of type ['A', 2] sage: PvW0 = E.PvW0(); PvW0 - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Multiplicative form of Weight lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the weight lattice) + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Multiplicative form of Weight lattice of the Root system of type ['A', 2] + acted upon by Weyl Group of type ['A', 2] + (as a matrix group acting on the weight lattice) sage: W0Pv = E.W0Pv(); W0Pv - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the weight lattice) acting on Multiplicative form of Weight lattice of the Root system of type ['A', 2] + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Weyl Group of type ['A', 2] (as a matrix group acting on the weight lattice) + acting on Multiplicative form of Weight lattice of the Root system of type ['A', 2] sage: WF = E.WF(); WF - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) acted upon by Fundamental group of type ['A', 2, 1] + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) + acted upon by Fundamental group of type ['A', 2, 1] sage: FW = E.FW(); FW - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Fundamental group of type ['A', 2, 1] acting on Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Fundamental group of type ['A', 2, 1] acting on Weyl Group of type ['A', 2, 1] + (as a matrix group acting on the root lattice) When the realizations are constructed from each other as above, there are built-in coercions between them. :: @@ -330,10 +345,10 @@ def ExtendedAffineWeylGroup(cartan_type, general_linear=None, **print_options): Here is a demonstration of the printing options:: - sage: E = ExtendedAffineWeylGroup(["A",2,1], affine="sx", classical="Sx",translation="x",fundamental="pix") + sage: E = ExtendedAffineWeylGroup(["A",2,1], affine="sx", classical="Sx", + ....: translation="x", fundamental="pix") sage: PW0 = E.PW0() - sage: y = PW0(E.lattice_basis()[1]) - sage: y + sage: y = PW0(E.lattice_basis()[1]); y x[Lambdacheck[1]] sage: FW = E.FW() sage: FW(y) @@ -376,7 +391,9 @@ def ExtendedAffineWeylGroup(cartan_type, general_linear=None, **print_options): of `GL_n`, which is usually identified with the lattice `\ZZ^n` of `n`-tuples of integers:: sage: PW0 = E.PW0(); PW0 - Extended affine Weyl group of GL(3) realized by Semidirect product of Multiplicative form of Ambient space of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space) + Extended affine Weyl group of GL(3) realized by Semidirect product of + Multiplicative form of Ambient space of the Root system of type ['A', 2] acted upon + by Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space) sage: PW0.an_element() t[(2, 2, 3)] * s1*s2 @@ -395,7 +412,9 @@ def ExtendedAffineWeylGroup(cartan_type, general_linear=None, **print_options): and the indices of the simple reflections are taken modulo `n`:: sage: FW = E.FW(); FW - Extended affine Weyl group of GL(3) realized by Semidirect product of Fundamental group of GL(3) acting on Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) + Extended affine Weyl group of GL(3) realized by + Semidirect product of Fundamental group of GL(3) acting on + Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) sage: FW.an_element() pi[5] * S0*S1*S2 @@ -485,7 +504,7 @@ def __init__(self, cartan_type, general_linear, **print_options): self._prefixcl = "s" self._ct0 = cartan_type.classical() - self._R0 = self._ct0.root_system() + self._R0 = self._ct0.root_system() self._I0 = self._ct0.index_set() self._ct0v = self._ct0.dual() self._R0v = self._ct0v.root_system() @@ -574,7 +593,7 @@ def __init__(self, cartan_type, general_linear, **print_options): self._extended = True - Parent.__init__(self, category = Groups().WithRealizations().Infinite()) + Parent.__init__(self, category=Groups().WithRealizations().Infinite()) # create the realizations (they are cached) PW0 = self.PW0() @@ -672,7 +691,10 @@ def PW0(self): EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).PW0() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Multiplicative form of Coweight lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) + Extended affine Weyl group of type ['A', 2, 1] realized by + Semidirect product of Multiplicative form of + Coweight lattice of the Root system of type ['A', 2] acted upon by + Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) """ return self.ExtendedAffineWeylGroupPW0() @@ -683,7 +705,9 @@ def W0P(self): EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).W0P() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) acting on Multiplicative form of Coweight lattice of the Root system of type ['A', 2] + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) + acting on Multiplicative form of Coweight lattice of the Root system of type ['A', 2] """ return self.ExtendedAffineWeylGroupW0P() @@ -694,7 +718,9 @@ def WF(self): EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).WF() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) acted upon by Fundamental group of type ['A', 2, 1] + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) + acted upon by Fundamental group of type ['A', 2, 1] """ return self.ExtendedAffineWeylGroupWF() @@ -705,7 +731,9 @@ def FW(self): EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).FW() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Fundamental group of type ['A', 2, 1] acting on Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Fundamental group of type ['A', 2, 1] acting on + Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) """ return self.ExtendedAffineWeylGroupFW() @@ -716,7 +744,9 @@ def PvW0(self): EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).PvW0() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Multiplicative form of Weight lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the weight lattice) + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Multiplicative form of Weight lattice of the Root system of type ['A', 2] + acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the weight lattice) """ return self.ExtendedAffineWeylGroupPvW0() @@ -727,7 +757,9 @@ def W0Pv(self): EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).W0Pv() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the weight lattice) acting on Multiplicative form of Weight lattice of the Root system of type ['A', 2] + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Weyl Group of type ['A', 2] (as a matrix group acting on the weight lattice) + acting on Multiplicative form of Weight lattice of the Root system of type ['A', 2] """ return self.ExtendedAffineWeylGroupW0Pv() @@ -782,7 +814,8 @@ def lattice(self): Weight lattice of the Root system of type ['C', 2] sage: ExtendedAffineWeylGroup(CartanType(['A',4,2]).dual()).lattice() Coweight lattice of the Root system of type ['B', 2] - sage: ExtendedAffineWeylGroup(CartanType(['A',2,1]), general_linear=True).lattice() + sage: ExtendedAffineWeylGroup(CartanType(['A',2,1]), + ....: general_linear=True).lattice() Ambient space of the Root system of type ['A', 2] """ @@ -938,7 +971,9 @@ def a_realization(self): EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).a_realization() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Multiplicative form of Coweight lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Multiplicative form of Coweight lattice of the Root system of type ['A', 2] + acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) """ return self.PW0() @@ -1010,7 +1045,7 @@ def WF_to_PW0_func(self, x): # the element is in the fundamental group PW0 = self.PW0() ispecial = f.value() - W=self.classical_weyl() + W = self.classical_weyl() if self._general_linear: r = ZZ(Mod(ispecial, self._n)) weight = self.lattice().from_vector(vector([ZZ((ispecial-r)/self._n)]*self._n)) @@ -1058,9 +1093,15 @@ def from_fundamental(self, x): sage: F = E.fundamental_group() sage: Is = F.special_nodes() sage: [(i, PW0.from_fundamental(F(i))) for i in Is] - [(0, 1), (1, t[Lambdacheck[1]] * s1*s2*s3), (2, t[Lambdacheck[2]] * s2*s3*s1*s2), (3, t[Lambdacheck[3]] * s3*s2*s1)] + [(0, 1), + (1, t[Lambdacheck[1]] * s1*s2*s3), + (2, t[Lambdacheck[2]] * s2*s3*s1*s2), + (3, t[Lambdacheck[3]] * s3*s2*s1)] sage: [(i, E.W0P().from_fundamental((F(i)))) for i in Is] - [(0, 1), (1, s1*s2*s3 * t[-Lambdacheck[3]]), (2, s2*s3*s1*s2 * t[-Lambdacheck[2]]), (3, s3*s2*s1 * t[-Lambdacheck[1]])] + [(0, 1), + (1, s1*s2*s3 * t[-Lambdacheck[3]]), + (2, s2*s3*s1*s2 * t[-Lambdacheck[2]]), + (3, s3*s2*s1 * t[-Lambdacheck[1]])] sage: [(i, E.WF().from_fundamental(F(i))) for i in Is] [(0, 1), (1, pi[1]), (2, pi[2]), (3, pi[3])] @@ -1085,13 +1126,13 @@ def from_translation(self, la): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1]); PW0=E.PW0() + sage: E = ExtendedAffineWeylGroup(['A',2,1]); PW0 = E.PW0() sage: b = E.lattice_basis(); b Finite family {1: Lambdacheck[1], 2: Lambdacheck[2]} - sage: x = PW0.from_translation(2*b[1]-b[2]); x + sage: x = PW0.from_translation(2*b[1] - b[2]); x t[2*Lambdacheck[1] - Lambdacheck[2]] sage: FW = E.FW() - sage: y = FW.from_translation(2*b[1]-b[2]); y + sage: y = FW.from_translation(2*b[1] - b[2]); y S0*S2*S0*S1 sage: FW(x) == y True @@ -1118,10 +1159,10 @@ def from_dual_translation(self, la): sage: E = ExtendedAffineWeylGroup(['A',2,1]); PvW0 = E.PvW0() sage: bv = E.dual_lattice_basis(); bv Finite family {1: Lambda[1], 2: Lambda[2]} - sage: x = PvW0.from_dual_translation(2*bv[1]-bv[2]); x + sage: x = PvW0.from_dual_translation(2*bv[1] - bv[2]); x t[2*Lambda[1] - Lambda[2]] sage: FW = E.FW() - sage: y = FW.from_dual_translation(2*bv[1]-bv[2]); y + sage: y = FW.from_dual_translation(2*bv[1] - bv[2]); y S0*S2*S0*S1 sage: FW(x) == y True @@ -1137,15 +1178,22 @@ def simple_reflections(self): EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',3,1]).W0P().simple_reflections() - Finite family {0: s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]], 1: s1, 2: s2, 3: s3} + Finite family {0: s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]], + 1: s1, 2: s2, 3: s3} sage: ExtendedAffineWeylGroup(['A',3,1]).WF().simple_reflections() Finite family {0: S0, 1: S1, 2: S2, 3: S3} - sage: ExtendedAffineWeylGroup(['A',3,1], print_tuple=True).FW().simple_reflections() - Finite family {0: (pi[0], S0), 1: (pi[0], S1), 2: (pi[0], S2), 3: (pi[0], S3)} - sage: ExtendedAffineWeylGroup(['A',3,1],fundamental="f",print_tuple=True).FW().simple_reflections() - Finite family {0: (f[0], S0), 1: (f[0], S1), 2: (f[0], S2), 3: (f[0], S3)} + sage: ExtendedAffineWeylGroup(['A',3,1], + ....: print_tuple=True).FW().simple_reflections() + Finite family {0: (pi[0], S0), 1: (pi[0], S1), + 2: (pi[0], S2), 3: (pi[0], S3)} + sage: ExtendedAffineWeylGroup(['A',3,1], + ....: fundamental="f", + ....: print_tuple=True).FW().simple_reflections() + Finite family {0: (f[0], S0), 1: (f[0], S1), + 2: (f[0], S2), 3: (f[0], S3)} sage: ExtendedAffineWeylGroup(['A',3,1]).PvW0().simple_reflections() - Finite family {0: t[Lambda[1] + Lambda[3]] * s1*s2*s3*s2*s1, 1: s1, 2: s2, 3: s3} + Finite family {0: t[Lambda[1] + Lambda[3]] * s1*s2*s3*s2*s1, + 1: s1, 2: s2, 3: s3} """ def simple_reflection(self, i): @@ -1155,7 +1203,7 @@ def simple_reflection(self, i): INPUT: - ``self`` -- a realization of the extended affine Weyl group - - `i` -- An affine Dynkin node + - ``i`` -- An affine Dynkin node EXAMPLES:: @@ -1240,7 +1288,7 @@ def from_affine_weyl(self, w): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',3,1]); PW0=E.PW0() + sage: E = ExtendedAffineWeylGroup(['A',3,1]); PW0 = E.PW0() sage: W = E.affine_weyl() sage: w = W.from_reduced_word([2,1,3,0]) sage: x = PW0.from_affine_weyl(w); x @@ -1284,15 +1332,15 @@ def has_descent(self, i, side='right', positive=False): OPTIONAL: - - ``side`` -- 'right' or 'left' (default: 'right') - - ``positive`` -- True or False (default: False) + - ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``) + - ``positive`` -- ``True`` or ``False`` (default: ``False``) - If ``side``='left' then the reflection acts - on the left. If ``positive`` = True then the inequality is reversed. + If ``side='left'``, then the reflection acts + on the left. If ``positive=True``, then the inequality is reversed. EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',3,1]); WF=E.WF() + sage: E = ExtendedAffineWeylGroup(['A',3,1]); WF = E.WF() sage: F = E.fundamental_group() sage: x = WF.an_element(); x S0*S1*S2*S3 * pi[3] @@ -1316,11 +1364,11 @@ def first_descent(self, side='right', positive=False, index_set=None): INPUT: - - ``side`` -- 'left' or 'right' (default: 'right') - - ``positive`` -- True or False (default: False) + - ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``) + - ``positive`` -- ``True`` or ``False`` (default: ``False``) - ``index_set`` -- an optional subset of Dynkin nodes - If ``index_set`` is not None, then the descent must be in the ``index_set``. + If ``index_set`` is not ``None``, then the descent must be in the ``index_set``. EXAMPLES:: @@ -1370,8 +1418,11 @@ def apply_simple_projection(self, i, side='right', length_increasing=True): - ``self`` -- an element of the extended affine Weyl group - `i` -- a Dynkin node (index of a simple reflection `s_i`) - - ``side`` -- 'right' or 'left' (default: 'right') according to which side of ``self`` the reflection `s_i` should be multiplied - - ``length_increasing`` -- True or False (default True). If False do the above with the word "greater" replaced by "less". + - ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``) + according to which side of ``self`` the reflection `s_i` + should be multiplied + - ``length_increasing`` -- ``True`` or ``False`` (default ``True``). + If ``False``, do the above with the word "greater" replaced by "less". EXAMPLES:: @@ -1447,8 +1498,10 @@ def to_affine_weyl_left(self): sage: E = ExtendedAffineWeylGroup(['A',3,1]); PW0 = E.PW0() sage: b = E.lattice_basis() - sage: [(x,PW0.from_translation(x).to_affine_weyl_left()) for x in b] - [(Lambdacheck[1], S0*S3*S2), (Lambdacheck[2], S0*S3*S1*S0), (Lambdacheck[3], S0*S1*S2)] + sage: [(x, PW0.from_translation(x).to_affine_weyl_left()) for x in b] + [(Lambdacheck[1], S0*S3*S2), + (Lambdacheck[2], S0*S3*S1*S0), + (Lambdacheck[3], S0*S1*S2)] .. WARNING:: @@ -1464,10 +1517,12 @@ def to_affine_weyl_right(self): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',3,1]); PW0=E.PW0() + sage: E = ExtendedAffineWeylGroup(['A',3,1]); PW0 = E.PW0() sage: b = E.lattice_basis() - sage: [(x,PW0.from_translation(x).to_affine_weyl_right()) for x in b] - [(Lambdacheck[1], S3*S2*S1), (Lambdacheck[2], S2*S3*S1*S2), (Lambdacheck[3], S1*S2*S3)] + sage: [(x, PW0.from_translation(x).to_affine_weyl_right()) for x in b] + [(Lambdacheck[1], S3*S2*S1), + (Lambdacheck[2], S2*S3*S1*S2), + (Lambdacheck[3], S1*S2*S3)] .. WARNING:: @@ -1550,7 +1605,7 @@ def length(self): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',3,1]); PW0=E.PW0() + sage: E = ExtendedAffineWeylGroup(['A',3,1]); PW0 = E.PW0() sage: I0 = E.cartan_type().classical().index_set() sage: [PW0.from_translation(E.lattice_basis()[i]).length() for i in I0] [3, 4, 3] @@ -1566,7 +1621,8 @@ def coset_representative(self, index_set, side='right'): - ``self`` -- an element of the extended affine Weyl group - ``index_set`` -- a subset of the set of Dynkin nodes - - ``side`` -- 'right' or 'left' (default: 'right') the side on which the subgroup acts + - ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``) + the side on which the subgroup acts EXAMPLES:: @@ -1589,7 +1645,7 @@ def is_grassmannian(self, index_set, side='right'): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',3,1]); PW0=E.PW0() + sage: E = ExtendedAffineWeylGroup(['A',3,1]); PW0 = E.PW0() sage: x = PW0.from_translation(E.lattice_basis()[1]); x t[Lambdacheck[1]] sage: I = E.cartan_type().index_set() @@ -1609,7 +1665,8 @@ def to_affine_grassmannian(self): sage: elts = ExtendedAffineWeylGroup(['A',2,1]).PW0().some_elements() sage: [(x, x.to_affine_grassmannian()) for x in elts] - [(t[2*Lambdacheck[1] + 2*Lambdacheck[2]] * s1*s2, t[2*Lambdacheck[1] + 2*Lambdacheck[2]] * s1*s2*s1)] + [(t[2*Lambdacheck[1] + 2*Lambdacheck[2]] * s1*s2, + t[2*Lambdacheck[1] + 2*Lambdacheck[2]] * s1*s2*s1)] """ return self.coset_representative(index_set=self.parent().realization_of().cartan_type().classical().index_set()) @@ -1620,7 +1677,7 @@ def is_affine_grassmannian(self): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1]); PW0=E.PW0() + sage: E = ExtendedAffineWeylGroup(['A',2,1]); PW0 = E.PW0() sage: F = E.fundamental_group() sage: [(x,PW0.from_fundamental(x).is_affine_grassmannian()) for x in F] [(pi[0], True), (pi[1], True), (pi[2], True)] @@ -1642,7 +1699,7 @@ def bruhat_le(self, x): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1],print_tuple=True); WF=E.WF() + sage: E = ExtendedAffineWeylGroup(['A',2,1], print_tuple=True); WF = E.WF() sage: W = E.affine_weyl() sage: v = W.from_reduced_word([2,1,0]) sage: w = W.from_reduced_word([2,0,1,0]) @@ -1674,7 +1731,7 @@ def is_translation(self): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1]); FW=E.FW() + sage: E = ExtendedAffineWeylGroup(['A',2,1]); FW = E.FW() sage: F = E.fundamental_group() sage: FW.from_affine_weyl(E.affine_weyl().from_reduced_word([1,2,1,0])).is_translation() True @@ -1693,18 +1750,20 @@ def action(self, la): INPUT: - ``self`` -- an element of the extended affine Weyl group - - ``la`` -- an element of the translation lattice of the extended affine Weyl group, the lattice denoted by the mnemonic "P" in the documentation for :meth:`ExtendedAffineWeylGroup`. + - ``la`` -- an element of the translation lattice of the extended + affine Weyl group, the lattice denoted by the mnemonic "P" in the + documentation for :meth:`ExtendedAffineWeylGroup`. EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1],affine="s") + sage: E = ExtendedAffineWeylGroup(['A',2,1], affine="s") sage: x = E.FW().an_element(); x pi[2] * s0*s1*s2 sage: la = E.lattice().an_element(); la 2*Lambdacheck[1] + 2*Lambdacheck[2] sage: x.action(la) 5*Lambdacheck[1] - 3*Lambdacheck[2] - sage: E = ExtendedAffineWeylGroup(['C',2,1],affine="s") + sage: E = ExtendedAffineWeylGroup(['C',2,1], affine="s") sage: x = E.PW0().from_translation(E.lattice_basis()[1]) sage: x.action(E.lattice_basis()[2]) Lambdacheck[1] + Lambdacheck[2] @@ -1723,18 +1782,20 @@ def dual_action(self, la): INPUT: - ``self`` -- an element of the extended affine Weyl group - - ``la`` -- an element of the dual translation lattice of the extended affine Weyl group, the lattice denoted by the mnemonic "Pv" in the documentation for :meth:`ExtendedAffineWeylGroup`. + - ``la`` -- an element of the dual translation lattice of the extended + affine Weyl group, the lattice denoted by the mnemonic "Pv" in + the documentation for :meth:`ExtendedAffineWeylGroup`. EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1],affine="s") + sage: E = ExtendedAffineWeylGroup(['A',2,1], affine="s") sage: x = E.FW().an_element(); x pi[2] * s0*s1*s2 sage: la = E.dual_lattice().an_element(); la 2*Lambda[1] + 2*Lambda[2] sage: x.dual_action(la) 5*Lambda[1] - 3*Lambda[2] - sage: E = ExtendedAffineWeylGroup(['C',2,1],affine="s") + sage: E = ExtendedAffineWeylGroup(['C',2,1], affine="s") sage: x = E.PvW0().from_dual_translation(E.dual_lattice_basis()[1]) sage: x.dual_action(E.dual_lattice_basis()[2]) Lambda[1] + Lambda[2] @@ -1775,7 +1836,7 @@ def face_data(self, i): INPUT: - ``self`` -- An element of the extended affine Weyl group - - `i` -- an affine Dynkin node + - ``i`` -- an affine Dynkin node OUTPUT: @@ -1842,7 +1903,7 @@ def alcove_walk_signs(self): w = gw.cartesian_projection(1) rw = w.reduced_word() u_curr = We.from_fundamental(g.value()) - signs=[] + signs = [] for i in rw: m, beta = u_curr.face_data(i) if beta.is_positive_root(): @@ -1863,12 +1924,12 @@ def has_descent(self, i, side='right', positive=False): INPUT: - - `i` -- an affine Dynkin node + - ``i`` -- an affine Dynkin node OPTIONAL: - - ``side`` -- 'left' or 'right' (default: 'right') - - ``positive`` -- True or False (default: False) + - ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``) + - ``positive`` -- ``True`` or ``False`` (default: ``False``) EXAMPLES:: @@ -1905,7 +1966,7 @@ def action(self, la): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1]); PW0=E.PW0() + sage: E = ExtendedAffineWeylGroup(['A',2,1]); PW0 = E.PW0() sage: x = PW0.an_element(); x t[2*Lambdacheck[1] + 2*Lambdacheck[2]] * s1*s2 sage: la = E.lattice().an_element(); la @@ -1952,12 +2013,15 @@ class ExtendedAffineWeylGroupPW0(GroupSemidirectProduct, BindableClass): INPUT: - - `E` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class` + - ``E`` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class` EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).PW0() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Multiplicative form of Coweight lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Multiplicative form of Coweight lattice of the Root system of type ['A', 2] + acted upon by Weyl Group of type ['A', 2] + (as a matrix group acting on the coweight lattice) """ def __init__(self, E): @@ -1974,7 +2038,7 @@ def __init__(self, E): def twist(w,l): return E.exp_lattice()(w.action(l.value)) - GroupSemidirectProduct.__init__(self, E.exp_lattice(), E.classical_weyl(), twist = twist, act_to_right=False, prefix0=E._prefixt, print_tuple = E._print_tuple, category=E.Realizations()) + GroupSemidirectProduct.__init__(self, E.exp_lattice(), E.classical_weyl(), twist=twist, act_to_right=False, prefix0=E._prefixt, print_tuple=E._print_tuple, category=E.Realizations()) self._style = "PW0" def _repr_(self): @@ -1994,7 +2058,8 @@ def from_translation(self, la): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1], translation="tau", print_tuple = True) + sage: E = ExtendedAffineWeylGroup(['A',2,1], translation="tau", + ....: print_tuple=True) sage: la = E.lattice().an_element(); la 2*Lambdacheck[1] + 2*Lambdacheck[2] sage: E.PW0().from_translation(la) @@ -2041,7 +2106,8 @@ def simple_reflections(self): EXAMPLES:: sage: ExtendedAffineWeylGroup("A3").PW0().simple_reflections() - Finite family {0: t[Lambdacheck[1] + Lambdacheck[3]] * s1*s2*s3*s2*s1, 1: s1, 2: s2, 3: s3} + Finite family {0: t[Lambdacheck[1] + Lambdacheck[3]] * s1*s2*s3*s2*s1, + 1: s1, 2: s2, 3: s3} """ return Family(self.realization_of().cartan_type().index_set(), self.simple_reflection) @@ -2068,12 +2134,12 @@ def has_descent(self, i, side='right', positive=False): INPUT: - - `i` - an index. + - ``i`` -- an index. OPTIONAL: - - ``side`` - 'left' or 'right' (default: 'right') - - ``positive`` - True or False (default: False) + - ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``) + - ``positive`` -- ``True`` or ``False`` (default: ``False``) EXAMPLES:: @@ -2137,12 +2203,14 @@ class ExtendedAffineWeylGroupW0P(GroupSemidirectProduct, BindableClass): INPUT: - - `E` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class` + - ``E`` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class` EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).W0P() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) acting on Multiplicative form of Coweight lattice of the Root system of type ['A', 2] + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) + acting on Multiplicative form of Coweight lattice of the Root system of type ['A', 2] """ def __init__(self, E): @@ -2189,7 +2257,8 @@ def simple_reflection(self, i): sage: E = ExtendedAffineWeylGroup(['A',3,1]); W0P = E.W0P() sage: [(i, W0P.simple_reflection(i)) for i in E.cartan_type().index_set()] - [(0, s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]]), (1, s1), (2, s2), (3, s3)] + [(0, s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]]), + (1, s1), (2, s2), (3, s3)] """ if i == 0: return self.S0() @@ -2204,7 +2273,8 @@ def simple_reflections(self): EXAMPLES:: sage: ExtendedAffineWeylGroup(["A",3,1]).W0P().simple_reflections() - Finite family {0: s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]], 1: s1, 2: s2, 3: s3} + Finite family {0: s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]], + 1: s1, 2: s2, 3: s3} """ return Family(self.realization_of().cartan_type().index_set(), self.simple_reflection) @@ -2243,12 +2313,12 @@ def has_descent(self, i, side='right', positive=False): INPUT: - - `i` -- an affine Dynkin index + - ``i`` -- an affine Dynkin index OPTIONAL: - - ``side`` -- 'left' or 'right' (default: 'right') - - ``positive`` -- True or False (default: False) + - ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``) + - ``positive`` -- ``True`` or ``False`` (default: ``False``) EXAMPLES:: @@ -2298,7 +2368,8 @@ def bruhat_le(self, x): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1],affine="s", print_tuple=True); WF=E.WF() + sage: E = ExtendedAffineWeylGroup(['A',2,1], affine="s", + ....: print_tuple=True); WF = E.WF() sage: r = E.affine_weyl().from_reduced_word sage: v = r([1,0]) sage: w = r([1,2,0]) @@ -2330,12 +2401,14 @@ class ExtendedAffineWeylGroupWF(GroupSemidirectProduct, BindableClass): INPUT: - - `E` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class` + - ``E`` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class` EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).WF() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) acted upon by Fundamental group of type ['A', 2, 1] + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) + acted upon by Fundamental group of type ['A', 2, 1] """ def __init__(self, E): @@ -2348,7 +2421,7 @@ def __init__(self, E): def twist(g,w): return g.act_on_affine_weyl(w) - GroupSemidirectProduct.__init__(self, E.affine_weyl(), E.fundamental_group(), twist = twist, act_to_right=False, print_tuple = E._print_tuple, category=E.Realizations()) + GroupSemidirectProduct.__init__(self, E.affine_weyl(), E.fundamental_group(), twist=twist, act_to_right=False, print_tuple=E._print_tuple, category=E.Realizations()) self._style = "WF" def _repr_(self): @@ -2368,7 +2441,7 @@ def from_affine_weyl(self, w): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['C',2,1],print_tuple=True) + sage: E = ExtendedAffineWeylGroup(['C',2,1], print_tuple=True) sage: E.WF().from_affine_weyl(E.affine_weyl().from_reduced_word([1,2,1,0])) (S1*S2*S1*S0, pi[0]) """ @@ -2381,7 +2454,7 @@ def simple_reflections(self): EXAMPLES:: - sage: ExtendedAffineWeylGroup(["A",3,1],affine="r").WF().simple_reflections() + sage: ExtendedAffineWeylGroup(["A",3,1], affine="r").WF().simple_reflections() Finite family {0: r0, 1: r1, 2: r2, 3: r3} """ E = self.realization_of() @@ -2396,8 +2469,9 @@ def from_fundamental(self, f): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['E',6,1],print_tuple=True); WF = E.WF(); F = E.fundamental_group() - sage: [(x,WF.from_fundamental(x)) for x in F] + sage: E = ExtendedAffineWeylGroup(['E',6,1], print_tuple=True); WF = E.WF() + sage: F = E.fundamental_group() + sage: [(x, WF.from_fundamental(x)) for x in F] [(pi[0], (1, pi[0])), (pi[1], (1, pi[1])), (pi[6], (1, pi[6]))] """ return self((self.cartesian_factors()[0].one(),f)) @@ -2417,8 +2491,8 @@ def has_descent(self, i, side='right', positive=False): OPTIONAL: - - ``side`` -- 'left' or 'right' (default: 'right') - - ``positive`` -- True or False (default: False) + - ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``) + - ``positive`` -- ``True`` or ``False`` (default: ``False``) EXAMPLES:: @@ -2468,7 +2542,7 @@ def action_on_affine_roots(self, beta): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1],affine="s") + sage: E = ExtendedAffineWeylGroup(['A',2,1], affine="s") sage: x = E.FW().an_element(); x pi[2] * s0*s1*s2 sage: v = RootSystem(['A',2,1]).root_lattice().an_element(); v @@ -2487,12 +2561,14 @@ class ExtendedAffineWeylGroupFW(GroupSemidirectProduct, BindableClass): INPUT: - - `E` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class` + - ``E`` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class` EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).FW() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Fundamental group of type ['A', 2, 1] acting on Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Fundamental group of type ['A', 2, 1] acting on Weyl Group of type ['A', 2, 1] + (as a matrix group acting on the root lattice) """ def __init__(self, E): @@ -2506,7 +2582,7 @@ def __init__(self, E): def twist(g,w): return g.act_on_affine_weyl(w) - GroupSemidirectProduct.__init__(self, E.fundamental_group(), E.affine_weyl(), twist = twist, act_to_right=True, print_tuple = E._print_tuple, category=E.Realizations()) + GroupSemidirectProduct.__init__(self, E.fundamental_group(), E.affine_weyl(), twist=twist, act_to_right=True, print_tuple=E._print_tuple, category=E.Realizations()) self._style = "FW" def _repr_(self): @@ -2541,7 +2617,7 @@ def from_affine_weyl(self, w): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1],print_tuple=True) + sage: E = ExtendedAffineWeylGroup(['A',2,1], print_tuple=True) sage: E.FW().from_affine_weyl(E.affine_weyl().from_reduced_word([0,2,1])) (pi[0], S0*S2*S1) """ @@ -2554,7 +2630,7 @@ def from_fundamental(self, f): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1],print_tuple=True) + sage: E = ExtendedAffineWeylGroup(['A',2,1], print_tuple=True) sage: E.FW().from_fundamental(E.fundamental_group()(2)) (pi[2], 1) """ @@ -2571,12 +2647,12 @@ def has_descent(self, i, side='right', positive=False): INPUT: - - `i` - an affine Dynkin index + - ``i`` - an affine Dynkin index OPTIONAL: - - ``side`` -- 'left' or 'right' (default: 'right') - - ``positive`` -- True or False (default: False) + - ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``) + - ``positive`` -- ``True`` or ``False`` (default: ``False``) EXAMPLES:: @@ -2657,12 +2733,14 @@ class ExtendedAffineWeylGroupPvW0(GroupSemidirectProduct, BindableClass): INPUT: - - `E` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class` + - ``E`` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class` EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).PvW0() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Multiplicative form of Weight lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the weight lattice) + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Multiplicative form of Weight lattice of the Root system of type ['A', 2] acted + upon by Weyl Group of type ['A', 2] (as a matrix group acting on the weight lattice) """ def __init__(self, E): @@ -2678,7 +2756,7 @@ def __init__(self, E): def twist(w,l): return E.exp_dual_lattice()(w.action(l.value)) - GroupSemidirectProduct.__init__(self, E.exp_dual_lattice(), E.dual_classical_weyl(), twist = twist, act_to_right=False, prefix0=E._prefixt, print_tuple = E._print_tuple, category=E.Realizations()) + GroupSemidirectProduct.__init__(self, E.exp_dual_lattice(), E.dual_classical_weyl(), twist=twist, act_to_right=False, prefix0=E._prefixt, print_tuple=E._print_tuple, category=E.Realizations()) self._style = "PvW0" def _repr_(self): @@ -2698,7 +2776,8 @@ def from_dual_translation(self, la): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1], translation="tau", print_tuple = True) + sage: E = ExtendedAffineWeylGroup(['A',2,1], translation="tau", + ....: print_tuple=True) sage: la = E.dual_lattice().an_element(); la 2*Lambda[1] + 2*Lambda[2] sage: E.PvW0().from_dual_translation(la) @@ -2715,7 +2794,8 @@ def simple_reflections(self): EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',3,1]).PvW0().simple_reflections() - Finite family {0: t[Lambda[1] + Lambda[3]] * s1*s2*s3*s2*s1, 1: s1, 2: s2, 3: s3} + Finite family {0: t[Lambda[1] + Lambda[3]] * s1*s2*s3*s2*s1, + 1: s1, 2: s2, 3: s3} """ E = self.realization_of() return Family(E.cartan_type().index_set(), lambda i: self(E.PW0().simple_reflection(i))) @@ -2726,8 +2806,9 @@ def from_dual_classical_weyl(self, w): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',3,1],print_tuple=True) - sage: E.PvW0().from_dual_classical_weyl(E.dual_classical_weyl().from_reduced_word([1,2])) + sage: E = ExtendedAffineWeylGroup(['A',3,1], print_tuple=True) + sage: E.PvW0().from_dual_classical_weyl( + ....: E.dual_classical_weyl().from_reduced_word([1,2])) (t[0], s1*s2) """ return self((self.cartesian_factors()[0].one(),w)) @@ -2829,7 +2910,9 @@ class ExtendedAffineWeylGroupW0Pv(GroupSemidirectProduct, BindableClass): EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',2,1]).W0Pv() - Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the weight lattice) acting on Multiplicative form of Weight lattice of the Root system of type ['A', 2] + Extended affine Weyl group of type ['A', 2, 1] realized by Semidirect product of + Weyl Group of type ['A', 2] (as a matrix group acting on the weight lattice) + acting on Multiplicative form of Weight lattice of the Root system of type ['A', 2] """ def __init__(self, E): @@ -2844,7 +2927,7 @@ def __init__(self, E): def twist(w,l): return E.exp_dual_lattice()(w.action(l.value)) - GroupSemidirectProduct.__init__(self, E.dual_classical_weyl(), E.exp_dual_lattice(), twist = twist, act_to_right=True, prefix1=E._prefixt, print_tuple = E._print_tuple, category=E.Realizations()) + GroupSemidirectProduct.__init__(self, E.dual_classical_weyl(), E.exp_dual_lattice(), twist=twist, act_to_right=True, prefix1=E._prefixt, print_tuple=E._print_tuple, category=E.Realizations()) self._style = "W0Pv" def _repr_(self): @@ -2864,7 +2947,8 @@ def from_dual_translation(self, la): EXAMPLES:: - sage: E = ExtendedAffineWeylGroup(['A',2,1], translation="tau", print_tuple = True) + sage: E = ExtendedAffineWeylGroup(['A',2,1], translation="tau", + ....: print_tuple=True) sage: la = E.dual_lattice().an_element(); la 2*Lambda[1] + 2*Lambda[2] sage: E.W0Pv().from_dual_translation(la) @@ -2881,7 +2965,8 @@ def simple_reflections(self): EXAMPLES:: sage: ExtendedAffineWeylGroup(['A',3,1]).W0Pv().simple_reflections() - Finite family {0: s1*s2*s3*s2*s1 * t[-Lambda[1] - Lambda[3]], 1: s1, 2: s2, 3: s3} + Finite family {0: s1*s2*s3*s2*s1 * t[-Lambda[1] - Lambda[3]], + 1: s1, 2: s2, 3: s3} """ E = self.realization_of() return Family(E.cartan_type().index_set(), lambda i: self(E.PW0().simple_reflection(i))) diff --git a/src/sage/combinat/root_system/fundamental_group.py b/src/sage/combinat/root_system/fundamental_group.py index 87b6e1094e0..65426b786e3 100644 --- a/src/sage/combinat/root_system/fundamental_group.py +++ b/src/sage/combinat/root_system/fundamental_group.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Fundamental Group of an Extended Affine Weyl Group @@ -324,6 +325,21 @@ def act_on_affine_lattice(self, wt): """ return wt.map_support(self.parent().action(self.value())) + def __hash__(self): + r""" + Return the hash of ``self``. + + TESTS: + + Check that :issue:`36121` is fixed:: + + sage: W = ExtendedAffineWeylGroup('A4') + sage: fun = W.fundamental_group().an_element() + sage: hash(fun) == hash(fun.value()) + True + """ + return hash(self.value()) + class FundamentalGroupOfExtendedAffineWeylGroup_Class(UniqueRepresentation, Parent): @@ -406,7 +422,7 @@ def leading_support(beta): EnumeratedSets())) else: cat = Groups().Commutative().Infinite() - Parent.__init__(self, category = cat) + Parent.__init__(self, category=cat) @cached_method def one(self): diff --git a/src/sage/combinat/root_system/hecke_algebra_representation.py b/src/sage/combinat/root_system/hecke_algebra_representation.py index 6b756bafc30..1dc8d16ad59 100644 --- a/src/sage/combinat/root_system/hecke_algebra_representation.py +++ b/src/sage/combinat/root_system/hecke_algebra_representation.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.gap sage.groups r""" Hecke algebra representations """ @@ -112,7 +113,7 @@ def _repr_(self): on Algebra of Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space) over Rational Field" """ - return "A representation of the %s-Hecke algebra of type %s on %s"%((self._q1,self._q2), self.cartan_type(), self.domain()) + return "A representation of the %s-Hecke algebra of type %s on %s" % ((self._q1,self._q2), self.cartan_type(), self.domain()) @cached_method def parameters(self, i): @@ -167,7 +168,8 @@ def domain(self): sage: H = WeylGroup(["A",3]).algebra(QQ).demazure_lusztig_operators(-1,1) sage: H.domain() - Algebra of Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space) over Rational Field + Algebra of Weyl Group of type ['A', 3] (as a matrix group + acting on the ambient space) over Rational Field """ return self._domain @@ -357,7 +359,7 @@ def Tw(self, word, signs=None, scalar=None): sage: q1, q2 = K.gens() sage: KW = W.algebra(K) sage: x = KW.an_element(); x - 123 + 3*32 + 2*3 + e + 123 + 3*2312 + 2*31 + e sage: T = KW.demazure_lusztig_operators(q1,q2) sage: T12 = T.Tw( (1,2) ) @@ -392,7 +394,7 @@ def Tw(self, word, signs=None, scalar=None): """ word = self.straighten_word(word) result = self._domain.module_morphism(functools.partial(self.on_basis, word=word, signs=signs, scalar=scalar), - codomain = self._domain) + codomain=self._domain) # For debugging purpose, make the parameters easily accessible: result.word = word result.signs = signs @@ -428,7 +430,8 @@ def Tw_inverse(self, word): sage: x = KW.monomial(W.an_element()); x 123 sage: rho.Tw_inverse(word)(x) - 1/q2^2*12321 + ((-q1-q2)/(q1*q2^2))*1231 + ((-q1-q2)/(q1*q2^2))*1232 + ((q1^2+2*q1*q2+q2^2)/(q1^2*q2^2))*123 + 1/q2^2*12321 + ((-q1-q2)/(q1*q2^2))*1231 + ((-q1-q2)/(q1*q2^2))*1232 + + ((q1^2+2*q1*q2+q2^2)/(q1^2*q2^2))*123 sage: rho.Tw(word)(_) 123 """ @@ -464,26 +467,30 @@ def _test_relations(self, **options): def Ti(x,i,c): return T[i](x)+c*x - # Check the quadratic relation - for i in cartan_type.index_set(): - for x in elements: - tester.assertTrue(Ti(Ti(x,i,-q2),i,-q1).is_zero()) - G = cartan_type.coxeter_diagram() - # Check the braid relation - for (i, j) in Subsets(cartan_type.index_set(), 2): - if G.has_edge(i,j): - o = G.edge_label(i,j) - else: - o = 2 - if o == infinity: - continue - for x in elements: - y = x - for k in range(o): - x = T[i](x) - y = T[j](y) - y,x = x,y - tester.assertEqual(x, y) + + try: + # Check the quadratic relation + for i in cartan_type.index_set(): + for x in elements: + tester.assertTrue(Ti(Ti(x,i,-q2),i,-q1).is_zero()) + G = cartan_type.coxeter_diagram() + # Check the braid relation + for (i, j) in Subsets(cartan_type.index_set(), 2): + if G.has_edge(i,j): + o = G.edge_label(i,j) + else: + o = 2 + if o == infinity: + continue + for x in elements: + y = x + for k in range(o): + x = T[i](x) + y = T[j](y) + y,x = x,y + tester.assertEqual(x, y) + except ImportError: + pass def _test_inverse(self, **options): r""" @@ -502,14 +509,17 @@ def _test_inverse(self, **options): elements = self.domain().some_elements() q1 = self._q1 q2 = self._q2 - if q1.is_unit() and q2.is_unit(): - I = self.cartan_type().index_set() - for w in [[i] for i in I] + [tuple(I)]: - Tw = self.Tw(w) - Tw_inverse = self.Tw_inverse(w) - for x in elements: - tester.assertEqual(Tw_inverse(Tw(x)), x) - tester.assertEqual(Tw(Tw_inverse(x)), x) + try: + if q1.is_unit() and q2.is_unit(): + I = self.cartan_type().index_set() + for w in [[i] for i in I] + [tuple(I)]: + Tw = self.Tw(w) + Tw_inverse = self.Tw_inverse(w) + for x in elements: + tester.assertEqual(Tw_inverse(Tw(x)), x) + tester.assertEqual(Tw(Tw_inverse(x)), x) + except ImportError: + pass def Y_lambdacheck(self, lambdacheck): r""" @@ -540,9 +550,12 @@ def Y_lambdacheck(self, lambdacheck): sage: x = KW.monomial(W.an_element()); x 12 sage: Y1(x) - ((-q1^2-2*q1*q2-q2^2)/(-q2^2))*2121 + ((q1^3+q1^2*q2+q1*q2^2+q2^3)/(-q1*q2^2))*121 + ((q1^2+q1*q2)/(-q2^2))*212 + ((-q1^2)/(-q2^2))*12 + ((-q1^2-2*q1*q2-q2^2)/(-q2^2))*2121 + + ((q1^3+q1^2*q2+q1*q2^2+q2^3)/(-q1*q2^2))*121 + + ((q1^2+q1*q2)/(-q2^2))*212 + ((-q1^2)/(-q2^2))*12 sage: Y2(x) - ((-q1^4-q1^3*q2-q1*q2^3-q2^4)/(-q1^3*q2))*2121 + ((q1^3+q1^2*q2+q1*q2^2+q2^3)/(-q1^2*q2))*121 + (q2^3/(-q1^3))*12 + ((-q1^4-q1^3*q2-q1*q2^3-q2^4)/(-q1^3*q2))*2121 + + ((q1^3+q1^2*q2+q1*q2^2+q2^3)/(-q1^2*q2))*121 + (q2^3/(-q1^3))*12 sage: Y1(Y2(x)) ((q1*q2+q2^2)/q1^2)*212 + ((-q2)/q1)*12 sage: Y2(Y1(x)) @@ -742,9 +755,11 @@ def Y_eigenvectors(self): sage: [E[w] for w in W] [2121 - 121 - 212 + 12 + 21 - 1 - 2 + , -2121 + 212, - (q2/(q1-q2))*2121 + (q2/(-q1+q2))*121 + (q2/(-q1+q2))*212 - 12 + ((-q2)/(-q1+q2))*21 + 2, + (q2/(q1-q2))*2121 + (q2/(-q1+q2))*121 + + (q2/(-q1+q2))*212 - 12 + ((-q2)/(-q1+q2))*21 + 2, ((-q2^2)/(-q1^2+q1*q2-q2^2))*2121 - 121 + (q2^2/(-q1^2+q1*q2-q2^2))*212 + 21, - ((-q1^2-q2^2)/(q1^2-q1*q2+q2^2))*2121 + ((-q1^2-q2^2)/(-q1^2+q1*q2-q2^2))*121 + ((-q2^2)/(-q1^2+q1*q2-q2^2))*212 + (q2^2/(-q1^2+q1*q2-q2^2))*12 - 21 + 1, + ((-q1^2-q2^2)/(q1^2-q1*q2+q2^2))*2121 + ((-q1^2-q2^2)/(-q1^2+q1*q2-q2^2))*121 + + ((-q2^2)/(-q1^2+q1*q2-q2^2))*212 + (q2^2/(-q1^2+q1*q2-q2^2))*12 - 21 + 1, 2121, (q2/(-q1+q2))*2121 + ((-q2)/(-q1+q2))*121 - 212 + 12, -2121 + 121] @@ -802,7 +817,7 @@ class CherednikOperatorsEigenvectors(UniqueRepresentation, SageObject): classical operators `T_1, \ldots, T_n` from `T` and `T_Y` coincide. """ - def __init__(self, T, T_Y = None, normalized = True): + def __init__(self, T, T_Y=None, normalized=True): r""" INPUT: @@ -830,7 +845,8 @@ def __init__(self, T, T_Y = None, normalized = True): sage: E.keys() Weyl Group of type ['B', 3] (as a matrix group acting on the ambient space) sage: E.domain() - Algebra of Weyl Group of type ['B', 3] (as a matrix group acting on the ambient space) over Fraction Field of Multivariate Polynomial Ring in q1, q2 over Rational Field + Algebra of Weyl Group of type ['B', 3] (as a matrix group acting on the ambient space) + over Fraction Field of Multivariate Polynomial Ring in q1, q2 over Rational Field sage: E._T == E._T_Y True """ @@ -855,7 +871,7 @@ def cartan_type(self): sage: E.cartan_type() ['B', 3, 1] - sage: NonSymmetricMacdonaldPolynomials(["B", 2, 1]).cartan_type() + sage: NonSymmetricMacdonaldPolynomials(["B", 2, 1]).cartan_type() # needs sage.graphs ['B', 2, 1] """ return self._T_Y.cartan_type() @@ -872,7 +888,9 @@ def domain(self): sage: KW = W.algebra(K) sage: E = KW.demazure_lusztig_eigenvectors(q1, q2) sage: E.domain() - Algebra of Weyl Group of type ['B', 3] (as a matrix group acting on the ambient space) over Multivariate Polynomial Ring in q1, q2 over Rational Field + Algebra of Weyl Group of type ['B', 3] + (as a matrix group acting on the ambient space) + over Multivariate Polynomial Ring in q1, q2 over Rational Field """ return self._T.domain() diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 687a3b7abf7..0278617a2e5 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs sage.modules """ Integrable Representations of Affine Lie Algebras """ diff --git a/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py b/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py index ae39e62ce01..a29b26fdde3 100644 --- a/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +++ b/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Nonsymmetric Macdonald polynomials @@ -72,7 +73,8 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): `[2,0,1]`:: sage: E[L0([2,0,1])] - ((-q*q1-q*q2)/(-q*q1-q2))*B[(1, 1, 1)] + ((-q1-q2)/(-q*q1-q2))*B[(2, 1, 0)] + B[(2, 0, 1)] + ((-q*q1-q*q2)/(-q*q1-q2))*B[(1, 1, 1)] + + ((-q1-q2)/(-q*q1-q2))*B[(2, 1, 0)] + B[(2, 0, 1)] It can be seen as a polynomial (or in general a Laurent polynomial) by interpreting each term as an exponent vector. The @@ -93,8 +95,8 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: E[L0([2,0,1])].expand(vars) (t - 1)/(q*t - 1)*x0^2*x1 + x0^2*x2 + (q*t - q)/(q*t - 1)*x0*x1*x2 - sage: from sage.combinat.sf.ns_macdonald import E - sage: E([2,0,1]) + sage: from sage.combinat.sf.ns_macdonald import E # needs sage.combinat + sage: E([2,0,1]) # needs sage.combinat sage.groups (t - 1)/(q*t - 1)*x0^2*x1 + x0^2*x2 + (q*t - q)/(q*t - 1)*x0*x1*x2 Here is a type `G_2^{(1)}` nonsymmetric Macdonald polynomial:: @@ -103,7 +105,8 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: L0 = E.keys() sage: omega = L0.fundamental_weights() sage: E[ omega[2]-omega[1] ] - ((-q*q1^3*q2-q*q1^2*q2^2)/(q*q1^4-q2^4))*B[(0, 0, 0)] + B[(1, -1, 0)] + ((-q1*q2^3-q2^4)/(q*q1^4-q2^4))*B[(1, 0, -1)] + ((-q*q1^3*q2-q*q1^2*q2^2)/(q*q1^4-q2^4))*B[(0, 0, 0)] + + B[(1, -1, 0)] + ((-q1*q2^3-q2^4)/(q*q1^4-q2^4))*B[(1, 0, -1)] Many more examples are given after the background section. @@ -119,9 +122,9 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): The nonsymmetric Macdonald polynomials are a distinguished basis of the "polynomial" module of the affine Hecke algebra. Given:: - - a ground ring `K`, which contains the input parameters `q, q_1, q_2` - - an affine root system, specified by a Cartan type `C` - - a realization `L` of the weight lattice of type `C` + - a ground ring `K`, which contains the input parameters `q, q_1, q_2` + - an affine root system, specified by a Cartan type `C` + - a realization `L` of the weight lattice of type `C` the polynomial module is the group algebra `K[L_0]` of the classical weight lattice `L_0` with coefficients in `K`. It is isomorphic to the @@ -139,7 +142,9 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: L.simple_roots() Finite family {0: -2*e[0] + e['delta'], 1: e[0] - e[1], 2: 2*e[1]} sage: omega = L.fundamental_weights(); omega - Finite family {0: e['deltacheck'], 1: e[0] + e['deltacheck'], 2: e[0] + e[1] + e['deltacheck']} + Finite family {0: e['deltacheck'], + 1: e[0] + e['deltacheck'], + 2: e[0] + e[1] + e['deltacheck']} sage: L0 = L.classical(); L0 Ambient space of the Root system of type ['C', 2] @@ -194,7 +199,9 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): defined by the action of their `T`-generators.:: sage: T - A representation of the (q1, q2)-Hecke algebra of type ['C', 2, 1] on Algebra of the Ambient space of the Root system of type ['C', 2, 1] over Fraction Field of Multivariate Polynomial Ring in q, q1, q2 over Rational Field + A representation of the (q1, q2)-Hecke algebra of type ['C', 2, 1] on + Algebra of the Ambient space of the Root system of type ['C', 2, 1] over + Fraction Field of Multivariate Polynomial Ring in q, q1, q2 over Rational Field sage: type(T) <class 'sage.combinat.root_system.hecke_algebra_representation.HeckeAlgebraRepresentation'> sage: T._test_relations() # long time (1.3s) @@ -283,7 +290,8 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): having `\mu` as leading term:: sage: E = NonSymmetricMacdonaldPolynomials(KL, q, q1, q2); E - The family of the Macdonald polynomials of type ['C', 2, 1] with parameters q, q1, q2 + The family of the Macdonald polynomials of type ['C', 2, 1] + with parameters q, q1, q2 Or for short:: @@ -368,7 +376,8 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: E = NonSymmetricMacdonaldPolynomials(['D',3,1], q, u, -1/u) sage: omega = E.keys().fundamental_weights() sage: E[omega[1]+omega[3]] - ((-q*u^2+q)/(-q*u^4+1))*B[(1/2, -1/2, 1/2)] + ((-q*u^2+q)/(-q*u^4+1))*B[(1/2, 1/2, -1/2)] + B[(3/2, 1/2, 1/2)] + ((-q*u^2+q)/(-q*u^4+1))*B[(1/2, -1/2, 1/2)] + + ((-q*u^2+q)/(-q*u^4+1))*B[(1/2, 1/2, -1/2)] + B[(3/2, 1/2, 1/2)] sage: KL = RootSystem(["D",3,1]).ambient_space().algebra(K) sage: P = NonSymmetricMacdonaldPolynomials(KL, q, u, -1/u) @@ -393,6 +402,8 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: E = NonSymmetricMacdonaldPolynomials(KL,q, q1, q2) sage: omega = E.keys().fundamental_weights() sage: w = omega[1] + + sage: # needs sage.combinat sage.groups sage: import sage.combinat.sf.ns_macdonald as NS sage: p = NS.E([1,0,0]); p x0 @@ -402,6 +413,7 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: def eig(l): return E.eigenvalues(KL0.from_polynomial(NS.E(l))) + sage: # needs sage.combinat sage.groups sage: eig([1,0,0]) [t, (-1)/(-q*t^2), t] sage: eig([2,0,0]) @@ -421,53 +433,57 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: KL0 = KL.classical() sage: P = K['x0,x1'] sage: def EE(weight): return E[L0(weight)].expand(P.gens()) + + sage: # needs sage.combinat sage: import sage.combinat.sf.ns_macdonald as NS sage: EE([0,0]) 1 - sage: NS.E([0,0]) + sage: NS.E([0,0]) # needs sage.groups 1 sage: EE([1,0]) x0 - sage: NS.E([1,0]) + sage: NS.E([1,0]) # needs sage.groups x0 sage: EE([0,1]) (t - 1)/(q*t - 1)*x0 + x1 - sage: NS.E([0,1]) + sage: NS.E([0,1]) # needs sage.groups (t - 1)/(q*t - 1)*x0 + x1 - - sage: NS.E([2,0]) - x0^2 + (q*t - q)/(q*t - 1)*x0*x1 sage: EE([2,0]) x0^2 + (q*t - q)/(q*t - 1)*x0*x1 + sage: NS.E([2,0]) # needs sage.groups + x0^2 + (q*t - q)/(q*t - 1)*x0*x1 The same, directly in the ambient lattice with several shifts:: - sage: E[L0([2,0])] + sage: E[L0([2,0])] # needs sage.combinat ((-q*t+q)/(-q*t+1))*B[(1, 1)] + B[(2, 0)] - sage: E[L0([1,-1])] + sage: E[L0([1,-1])] # needs sage.combinat ((-q*t+q)/(-q*t+1))*B[(0, 0)] + B[(1, -1)] - sage: E[L0([0,-2])] + sage: E[L0([0,-2])] # needs sage.combinat ((-q*t+q)/(-q*t+1))*B[(-1, -1)] + B[(0, -2)] Systematic checks with Sage's implementation of [HHL06]_:: - sage: assert all(EE([x,y]) == NS.E([x,y]) for d in range(5) for x,y in IntegerVectors(d,2)) + sage: assert all(EE([x,y]) == NS.E([x,y]) # needs sage.combinat + ....: for d in range(5) for x,y in IntegerVectors(d,2)) With the current implementation, we can compute nonsymmetric Macdonald polynomials for any type, for example for type `E_6^{(1)}`:: - sage: K=QQ['q,u'].fraction_field() + sage: K = QQ['q,u'].fraction_field() sage: q, u = K.gens() sage: KL = RootSystem(["E",6,1]).weight_space(extended=True).algebra(K) sage: E = NonSymmetricMacdonaldPolynomials(KL,q,u,-1/u) sage: L0 = E.keys() sage: E[L0.fundamental_weight(1).weyl_action([2,4,3,2,1])] - ((-u^2+1)/(-q*u^16+1))*B[-Lambda[1] + Lambda[3]] + ((-u^2+1)/(-q*u^16+1))*B[Lambda[1]] - + B[-Lambda[2] + Lambda[5]] + ((-u^2+1)/(-q*u^16+1))*B[Lambda[2] - Lambda[4] + Lambda[5]] + ((-u^2+1)/(-q*u^16+1))*B[-Lambda[1] + Lambda[3]] + + ((-u^2+1)/(-q*u^16+1))*B[Lambda[1]] + + B[-Lambda[2] + Lambda[5]] + + ((-u^2+1)/(-q*u^16+1))*B[Lambda[2] - Lambda[4] + Lambda[5]] + ((-u^2+1)/(-q*u^16+1))*B[-Lambda[3] + Lambda[4]] - sage: E[L0.fundamental_weight(2).weyl_action([2,5,3,4,2])] # long time (6s) + sage: E[L0.fundamental_weight(2).weyl_action([2,5,3,4,2])] # long time (6s) ((-q^2*u^20+q^2*u^18+q*u^2-q)/(-q^2*u^32+2*q*u^16-1))*B[0] + B[Lambda[1] - Lambda[3] + Lambda[4] - Lambda[5] + Lambda[6]] + ((-u^2+1)/(-q*u^16+1))*B[Lambda[1] - Lambda[3] + Lambda[5]] @@ -475,45 +491,50 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): + ((-q*u^20+q*u^18+u^2-1)/(-q^2*u^32+2*q*u^16-1))*B[Lambda[2]] + ((u^4-2*u^2+1)/(q^2*u^32-2*q*u^16+1))*B[Lambda[3] - Lambda[4] + Lambda[5]] + ((-u^2+1)/(-q*u^16+1))*B[Lambda[3] - Lambda[5] + Lambda[6]] - - sage: E[L0.fundamental_weight(1)+L0.fundamental_weight(6)] # long time (13s) + sage: E[L0.fundamental_weight(1)+L0.fundamental_weight(6)] # long time (13s) ((q^2*u^10-q^2*u^8-q^2*u^2+q^2)/(q^2*u^26-q*u^16-q*u^10+1))*B[0] + ((-q*u^2+q)/(-q*u^10+1))*B[Lambda[1] - Lambda[2] + Lambda[6]] + ((-q*u^2+q)/(-q*u^10+1))*B[Lambda[1] + Lambda[2] - Lambda[4] + Lambda[6]] + ((-q*u^2+q)/(-q*u^10+1))*B[Lambda[1] - Lambda[3] + Lambda[4] - Lambda[5] + Lambda[6]] - + ((-q*u^2+q)/(-q*u^10+1))*B[Lambda[1] - Lambda[3] + Lambda[5]] + B[Lambda[1] + Lambda[6]] - + ((-q*u^2+q)/(-q*u^10+1))*B[-Lambda[2] + Lambda[4]] + ((-q*u^2+q)/(-q*u^10+1))*B[Lambda[2]] + + ((-q*u^2+q)/(-q*u^10+1))*B[Lambda[1] - Lambda[3] + Lambda[5]] + + B[Lambda[1] + Lambda[6]] + + ((-q*u^2+q)/(-q*u^10+1))*B[-Lambda[2] + Lambda[4]] + + ((-q*u^2+q)/(-q*u^10+1))*B[Lambda[2]] + ((-q*u^2+q)/(-q*u^10+1))*B[Lambda[3] - Lambda[4] + Lambda[5]] + ((-q*u^2+q)/(-q*u^10+1))*B[Lambda[3] - Lambda[5] + Lambda[6]] We test various other types:: - sage: K=QQ['q,u'].fraction_field() + sage: K = QQ['q,u'].fraction_field() sage: q, u = K.gens() sage: KL = RootSystem(["A",5,2]).ambient_space().algebra(K) sage: E = NonSymmetricMacdonaldPolynomials(KL, q, u, -1/u) sage: L0 = E.keys() sage: E[L0.fundamental_weight(2)] ((-q*u^2+q)/(-q*u^8+1))*B[(0, 0, 0)] + B[(1, 1, 0)] - sage: E[L0((0,-1,1))] # long time (1.5s) + sage: E[L0((0,-1,1))] # long time (1.5s) ((-q^2*u^10+q^2*u^8-q*u^6+q*u^4+q*u^2+u^2-q-1)/(-q^3*u^12+q^2*u^8+q*u^4-1))*B[(0, 0, 0)] + ((-u^2+1)/(-q*u^4+1))*B[(1, -1, 0)] + ((u^6-u^4-u^2+1)/(q^3*u^12-q^2*u^8-q*u^4+1))*B[(1, 1, 0)] + ((u^4-2*u^2+1)/(q^3*u^12-q^2*u^8-q*u^4+1))*B[(1, 0, -1)] - + ((q^2*u^12-q^2*u^10-u^2+1)/(q^3*u^12-q^2*u^8-q*u^4+1))*B[(1, 0, 1)] + B[(0, -1, 1)] + + ((q^2*u^12-q^2*u^10-u^2+1)/(q^3*u^12-q^2*u^8-q*u^4+1))*B[(1, 0, 1)] + + B[(0, -1, 1)] + ((-u^2+1)/(-q^2*u^8+1))*B[(0, 1, -1)] + ((-u^2+1)/(-q^2*u^8+1))*B[(0, 1, 1)] - - sage: K=QQ['q,u'].fraction_field() + sage: K = QQ['q,u'].fraction_field() sage: q, u = K.gens() sage: KL = RootSystem(["E",6,2]).ambient_space().algebra(K) sage: E = NonSymmetricMacdonaldPolynomials(KL,q,u,-1/u) sage: L0 = E.keys() - sage: E[L0.fundamental_weight(4)] # long time (5s) + sage: E[L0.fundamental_weight(4)] # long time (5s) ((-q^3*u^20+q^3*u^18+q^2*u^2-q^2)/(-q^3*u^28+q^2*u^22+q*u^6-1))*B[(0, 0, 0, 0)] - + ((-q*u^2+q)/(-q*u^6+1))*B[(1/2, 1/2, -1/2, -1/2)] + ((-q*u^2+q)/(-q*u^6+1))*B[(1/2, 1/2, -1/2, 1/2)] - + ((-q*u^2+q)/(-q*u^6+1))*B[(1/2, 1/2, 1/2, -1/2)] + ((-q*u^2+q)/(-q*u^6+1))*B[(1/2, 1/2, 1/2, 1/2)] - + ((q*u^2-q)/(q*u^6-1))*B[(1, 0, 0, 0)] + B[(1, 1, 0, 0)] + ((-q*u^2+q)/(-q*u^6+1))*B[(0, 1, 0, 0)] - sage: E[L0((1,-1,0,0))] # long time (23s) + + ((-q*u^2+q)/(-q*u^6+1))*B[(1/2, 1/2, -1/2, -1/2)] + + ((-q*u^2+q)/(-q*u^6+1))*B[(1/2, 1/2, -1/2, 1/2)] + + ((-q*u^2+q)/(-q*u^6+1))*B[(1/2, 1/2, 1/2, -1/2)] + + ((-q*u^2+q)/(-q*u^6+1))*B[(1/2, 1/2, 1/2, 1/2)] + + ((q*u^2-q)/(q*u^6-1))*B[(1, 0, 0, 0)] + + B[(1, 1, 0, 0)] + + ((-q*u^2+q)/(-q*u^6+1))*B[(0, 1, 0, 0)] + sage: E[L0((1,-1,0,0))] # long time (23s) ((q^3*u^18-q^3*u^16+q*u^4-q^2*u^2-2*q*u^2+q^2+q)/(q^3*u^18-q^2*u^12-q*u^6+1))*B[(0, 0, 0, 0)] + ((-q^3*u^18+q^3*u^16+q*u^2-q)/(-q^3*u^18+q^2*u^12+q*u^6-1))*B[(1/2, -1/2, -1/2, -1/2)] + ((-q^3*u^18+q^3*u^16+q*u^2-q)/(-q^3*u^18+q^2*u^12+q*u^6-1))*B[(1/2, -1/2, -1/2, 1/2)] @@ -524,9 +545,12 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): + ((-q*u^8+q*u^6+q*u^2-q)/(-q^3*u^18+q^2*u^12+q*u^6-1))*B[(1/2, 1/2, 1/2, -1/2)] + ((-q*u^8+q*u^6+q*u^2-q)/(-q^3*u^18+q^2*u^12+q*u^6-1))*B[(1/2, 1/2, 1/2, 1/2)] + ((-q^2*u^18+q^2*u^16-q*u^8+q*u^6+q*u^2+u^2-q-1)/(-q^3*u^18+q^2*u^12+q*u^6-1))*B[(1, 0, 0, 0)] - + B[(1, -1, 0, 0)] + ((-u^2+1)/(-q^2*u^12+1))*B[(1, 1, 0, 0)] + ((-u^2+1)/(-q^2*u^12+1))*B[(1, 0, -1, 0)] - + ((u^2-1)/(q^2*u^12-1))*B[(1, 0, 1, 0)] + ((-u^2+1)/(-q^2*u^12+1))*B[(1, 0, 0, -1)] - + ((-u^2+1)/(-q^2*u^12+1))*B[(1, 0, 0, 1)] + ((-q*u^2+q)/(-q*u^6+1))*B[(0, -1, 0, 0)] + + B[(1, -1, 0, 0)] + ((-u^2+1)/(-q^2*u^12+1))*B[(1, 1, 0, 0)] + + ((-u^2+1)/(-q^2*u^12+1))*B[(1, 0, -1, 0)] + + ((u^2-1)/(q^2*u^12-1))*B[(1, 0, 1, 0)] + + ((-u^2+1)/(-q^2*u^12+1))*B[(1, 0, 0, -1)] + + ((-u^2+1)/(-q^2*u^12+1))*B[(1, 0, 0, 1)] + + ((-q*u^2+q)/(-q*u^6+1))*B[(0, -1, 0, 0)] + ((-q*u^4+2*q*u^2-q)/(-q^3*u^18+q^2*u^12+q*u^6-1))*B[(0, 1, 0, 0)] + ((-q*u^4+2*q*u^2-q)/(-q^3*u^18+q^2*u^12+q*u^6-1))*B[(0, 0, -1, 0)] + ((-q*u^4+2*q*u^2-q)/(-q^3*u^18+q^2*u^12+q*u^6-1))*B[(0, 0, 1, 0)] @@ -543,29 +567,50 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): B[(1, 0, 0)] sage: E[-omega[1]] - B[(-1, 0, 0)] + ((q*q1^6+q*q1^5*q2+q1*q2^5+q2^6)/(q^3*q1^6+q^2*q1^5*q2+q*q1*q2^5+q2^6))*B[(1, 0, 0)] + ((q1+q2)/(q*q1+q2))*B[(0, -1, 0)] + ((q1+q2)/(q*q1+q2))*B[(0, 1, 0)] + ((q1+q2)/(q*q1+q2))*B[(0, 0, -1)] + ((q1+q2)/(q*q1+q2))*B[(0, 0, 1)] + B[(-1, 0, 0)] + + ((q*q1^6+q*q1^5*q2+q1*q2^5+q2^6)/(q^3*q1^6+q^2*q1^5*q2+q*q1*q2^5+q2^6))*B[(1, 0, 0)] + + ((q1+q2)/(q*q1+q2))*B[(0, -1, 0)] + ((q1+q2)/(q*q1+q2))*B[(0, 1, 0)] + + ((q1+q2)/(q*q1+q2))*B[(0, 0, -1)] + ((q1+q2)/(q*q1+q2))*B[(0, 0, 1)] sage: E[omega[2]] ((-q1*q2^3-q2^4)/(q*q1^4-q2^4))*B[(1, 0, 0)] + B[(0, 1, 0)] sage: E[-omega[2]] - ((q^2*q1^7+q^2*q1^6*q2-q1*q2^6-q2^7)/(q^3*q1^7-q^2*q1^5*q2^2+q*q1^2*q2^5-q2^7))*B[(1, 0, 0)] + B[(0, -1, 0)] + ((q^2*q1^7+q^2*q1^6*q2-q1*q2^6-q2^7)/(q^3*q1^7-q^2*q1^5*q2^2+q*q1^2*q2^5-q2^7))*B[(1, 0, 0)] + + B[(0, -1, 0)] + ((q*q1^5*q2^2+q*q1^4*q2^3-q1*q2^6-q2^7)/(q^3*q1^7-q^2*q1^5*q2^2+q*q1^2*q2^5-q2^7))*B[(0, 1, 0)] - + ((-q1*q2-q2^2)/(q*q1^2-q2^2))*B[(0, 0, -1)] + ((q1*q2+q2^2)/(-q*q1^2+q2^2))*B[(0, 0, 1)] + + ((-q1*q2-q2^2)/(q*q1^2-q2^2))*B[(0, 0, -1)] + + ((q1*q2+q2^2)/(-q*q1^2+q2^2))*B[(0, 0, 1)] sage: E[-omega[1]-omega[2]] - ((q^3*q1^6+q^3*q1^5*q2+2*q^2*q1^6+3*q^2*q1^5*q2-q^2*q1^4*q2^2-2*q^2*q1^3*q2^3-q*q1^5*q2-2*q*q1^4*q2^2+q*q1^3*q2^3+2*q*q1^2*q2^4-q*q1*q2^5-q*q2^6+q1^3*q2^3+q1^2*q2^4-2*q1*q2^5-2*q2^6)/(q^4*q1^6+q^3*q1^5*q2-q^3*q1^4*q2^2+q*q1^2*q2^4-q*q1*q2^5-q2^6))*B[(0, 0, 0)] + B[(-1, -1, 0)] + ((q*q1^4+q*q1^3*q2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(-1, 1, 0)] + ((q1+q2)/(q*q1+q2))*B[(-1, 0, -1)] + ((-q1-q2)/(-q*q1-q2))*B[(-1, 0, 1)] + ((q*q1^4+q*q1^3*q2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(1, -1, 0)] + ((q^2*q1^6+q^2*q1^5*q2+q*q1^5*q2-q*q1^3*q2^3-q1^5*q2-q1^4*q2^2+q1^3*q2^3+q1^2*q2^4-q1*q2^5-q2^6)/(q^4*q1^6+q^3*q1^5*q2-q^3*q1^4*q2^2+q*q1^2*q2^4-q*q1*q2^5-q2^6))*B[(1, 1, 0)] + ((q*q1^4+2*q*q1^3*q2+q*q1^2*q2^2-q1^3*q2-q1^2*q2^2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(1, 0, -1)] + ((q*q1^4+2*q*q1^3*q2+q*q1^2*q2^2-q1^3*q2-q1^2*q2^2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(1, 0, 1)] + ((q1+q2)/(q*q1+q2))*B[(0, -1, -1)] + ((q1+q2)/(q*q1+q2))*B[(0, -1, 1)] + ((q*q1^4+2*q*q1^3*q2+q*q1^2*q2^2-q1^3*q2-q1^2*q2^2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(0, 1, -1)] + ((q*q1^4+2*q*q1^3*q2+q*q1^2*q2^2-q1^3*q2-q1^2*q2^2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(0, 1, 1)] + ((q^3*q1^6+q^3*q1^5*q2+2*q^2*q1^6+3*q^2*q1^5*q2-q^2*q1^4*q2^2-2*q^2*q1^3*q2^3-q*q1^5*q2-2*q*q1^4*q2^2+q*q1^3*q2^3+2*q*q1^2*q2^4-q*q1*q2^5-q*q2^6+q1^3*q2^3+q1^2*q2^4-2*q1*q2^5-2*q2^6)/(q^4*q1^6+q^3*q1^5*q2-q^3*q1^4*q2^2+q*q1^2*q2^4-q*q1*q2^5-q2^6))*B[(0, 0, 0)] + + B[(-1, -1, 0)] + + ((q*q1^4+q*q1^3*q2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(-1, 1, 0)] + + ((q1+q2)/(q*q1+q2))*B[(-1, 0, -1)] + + ((-q1-q2)/(-q*q1-q2))*B[(-1, 0, 1)] + + ((q*q1^4+q*q1^3*q2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(1, -1, 0)] + + ((q^2*q1^6+q^2*q1^5*q2+q*q1^5*q2-q*q1^3*q2^3-q1^5*q2-q1^4*q2^2+q1^3*q2^3+q1^2*q2^4-q1*q2^5-q2^6)/(q^4*q1^6+q^3*q1^5*q2-q^3*q1^4*q2^2+q*q1^2*q2^4-q*q1*q2^5-q2^6))*B[(1, 1, 0)] + + ((q*q1^4+2*q*q1^3*q2+q*q1^2*q2^2-q1^3*q2-q1^2*q2^2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(1, 0, -1)] + + ((q*q1^4+2*q*q1^3*q2+q*q1^2*q2^2-q1^3*q2-q1^2*q2^2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(1, 0, 1)] + + ((q1+q2)/(q*q1+q2))*B[(0, -1, -1)] + + ((q1+q2)/(q*q1+q2))*B[(0, -1, 1)] + + ((q*q1^4+2*q*q1^3*q2+q*q1^2*q2^2-q1^3*q2-q1^2*q2^2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(0, 1, -1)] + + ((q*q1^4+2*q*q1^3*q2+q*q1^2*q2^2-q1^3*q2-q1^2*q2^2+q1*q2^3+q2^4)/(q^3*q1^4+q^2*q1^3*q2+q*q1*q2^3+q2^4))*B[(0, 1, 1)] sage: E[omega[1]-omega[2]] - ((q^3*q1^7+q^3*q1^6*q2-q*q1*q2^6-q*q2^7)/(q^3*q1^7-q^2*q1^5*q2^2+q*q1^2*q2^5-q2^7))*B[(0, 0, 0)] + B[(1, -1, 0)] - + ((q*q1^5*q2^2+q*q1^4*q2^3-q1*q2^6-q2^7)/(q^3*q1^7-q^2*q1^5*q2^2+q*q1^2*q2^5-q2^7))*B[(1, 1, 0)] + ((-q1*q2-q2^2)/(q*q1^2-q2^2))*B[(1, 0, -1)] + ((q^3*q1^7+q^3*q1^6*q2-q*q1*q2^6-q*q2^7)/(q^3*q1^7-q^2*q1^5*q2^2+q*q1^2*q2^5-q2^7))*B[(0, 0, 0)] + + B[(1, -1, 0)] + + ((q*q1^5*q2^2+q*q1^4*q2^3-q1*q2^6-q2^7)/(q^3*q1^7-q^2*q1^5*q2^2+q*q1^2*q2^5-q2^7))*B[(1, 1, 0)] + + ((-q1*q2-q2^2)/(q*q1^2-q2^2))*B[(1, 0, -1)] + ((q1*q2+q2^2)/(-q*q1^2+q2^2))*B[(1, 0, 1)] sage: E[omega[3]] - ((-q1*q2^2-q2^3)/(-q*q1^3-q2^3))*B[(1, 0, 0)] + ((-q1*q2^2-q2^3)/(-q*q1^3-q2^3))*B[(0, 1, 0)] + B[(0, 0, 1)] + ((-q1*q2^2-q2^3)/(-q*q1^3-q2^3))*B[(1, 0, 0)] + + ((-q1*q2^2-q2^3)/(-q*q1^3-q2^3))*B[(0, 1, 0)] + B[(0, 0, 1)] sage: E[-omega[3]] - ((q*q1^4*q2+q*q1^3*q2^2-q1*q2^4-q2^5)/(-q^2*q1^5-q2^5))*B[(1, 0, 0)] + ((q*q1^4*q2+q*q1^3*q2^2-q1*q2^4-q2^5)/(-q^2*q1^5-q2^5))*B[(0, 1, 0)] + ((q*q1^4*q2+q*q1^3*q2^2-q1*q2^4-q2^5)/(-q^2*q1^5-q2^5))*B[(1, 0, 0)] + + ((q*q1^4*q2+q*q1^3*q2^2-q1*q2^4-q2^5)/(-q^2*q1^5-q2^5))*B[(0, 1, 0)] + B[(0, 0, -1)] + ((-q1*q2^4-q2^5)/(-q^2*q1^5-q2^5))*B[(0, 0, 1)] .. RUBRIC:: Comparison with the energy function of crystals @@ -580,19 +625,20 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: KL = RootSystem(["A",5,2]).ambient_space().algebra(K) sage: E = NonSymmetricMacdonaldPolynomials(KL, q, t, -1) sage: omega = E.keys().fundamental_weights() - sage: E[-omega[1]].map_coefficients(lambda x:x.subs(t=0)) - B[(-1, 0, 0)] + B[(1, 0, 0)] + B[(0, -1, 0)] + B[(0, 1, 0)] + B[(0, 0, -1)] + B[(0, 0, 1)] - sage: E[-omega[2]].map_coefficients(lambda x:x.subs(t=0)) # long time (3s) + sage: E[-omega[1]].map_coefficients(lambda x: x.subs(t=0)) + B[(-1, 0, 0)] + B[(1, 0, 0)] + B[(0, -1, 0)] + B[(0, 1, 0)] + + B[(0, 0, -1)] + B[(0, 0, 1)] + sage: E[-omega[2]].map_coefficients(lambda x: x.subs(t=0)) # long time (3s) (q+2)*B[(0, 0, 0)] + B[(-1, -1, 0)] + B[(-1, 1, 0)] + B[(-1, 0, -1)] - + B[(-1, 0, 1)] + B[(1, -1, 0)] + B[(1, 1, 0)] + B[(1, 0, -1)] + B[(1, 0, 1)] - + B[(0, -1, -1)] + B[(0, -1, 1)] + B[(0, 1, -1)] + B[(0, 1, 1)] + + B[(-1, 0, 1)] + B[(1, -1, 0)] + B[(1, 1, 0)] + B[(1, 0, -1)] + B[(1, 0, 1)] + + B[(0, -1, -1)] + B[(0, -1, 1)] + B[(0, 1, -1)] + B[(0, 1, 1)] :: sage: KL = RootSystem(["C",3,1]).ambient_space().algebra(K) - sage: E = NonSymmetricMacdonaldPolynomials(KL,q, t,-1) + sage: E = NonSymmetricMacdonaldPolynomials(KL, q, t, -1) sage: omega = E.keys().fundamental_weights() - sage: E[-omega[2]].map_coefficients(lambda x:x.subs(t=0)) # long time (5s) + sage: E[-omega[2]].map_coefficients(lambda x: x.subs(t=0)) # long time (5s) 2*B[(0, 0, 0)] + B[(-1, -1, 0)] + B[(-1, 1, 0)] + B[(-1, 0, -1)] + B[(-1, 0, 1)] + B[(1, -1, 0)] + B[(1, 1, 0)] + B[(1, 0, -1)] + B[(1, 0, 1)] + B[(0, -1, -1)] + B[(0, -1, 1)] + B[(0, 1, -1)] + B[(0, 1, 1)] @@ -601,69 +647,79 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: R = RootSystem(['C',3,1]) sage: KL = R.weight_lattice(extended=True).algebra(K) - sage: E = NonSymmetricMacdonaldPolynomials(KL,q, t,-1) + sage: E = NonSymmetricMacdonaldPolynomials(KL, q, t, -1) sage: omega = E.keys().fundamental_weights() sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]) - sage: E[-2*omega[1]].map_coefficients(lambda x:x.subs(t=0)) == LS.one_dimensional_configuration_sum(q) # long time (15s) + sage: (E[-2*omega[1]].map_coefficients(lambda x: x.subs(t=0)) # long time (15s) + ....: == LS.one_dimensional_configuration_sum(q)) True - sage: LS = crystals.ProjectedLevelZeroLSPaths(La[1]+La[2]) - sage: E[-omega[1]-omega[2]].map_coefficients(lambda x:x.subs(t=0)) == LS.one_dimensional_configuration_sum(q) # long time (45s) + sage: LS = crystals.ProjectedLevelZeroLSPaths(La[1] + La[2]) + sage: (E[-omega[1] - omega[2]].map_coefficients(lambda x: x.subs(t=0)) # long time (45s) + ....: == LS.one_dimensional_configuration_sum(q)) True :: sage: R = RootSystem(['C',2,1]) sage: KL = R.weight_lattice(extended=True).algebra(K) - sage: E = NonSymmetricMacdonaldPolynomials(KL,q, t,-1) + sage: E = NonSymmetricMacdonaldPolynomials(KL, q, t, -1) sage: omega = E.keys().fundamental_weights() sage: La = R.weight_space().basis() - sage: for d in range(1,3): # long time (10s) + sage: for d in range(1,3): # long time (45s) ....: for x,y in IntegerVectors(d,2): ....: weight = x*La[1]+y*La[2] ....: weight0 = -x*omega[1]-y*omega[2] ....: LS = crystals.ProjectedLevelZeroLSPaths(weight) - ....: assert E[weight0].map_coefficients(lambda x:x.subs(t=0)) == LS.one_dimensional_configuration_sum(q) + ....: assert (E[weight0].map_coefficients(lambda x:x.subs(t=0)) + ....: == LS.one_dimensional_configuration_sum(q)) :: sage: R = RootSystem(['B',3,1]) sage: KL = R.weight_lattice(extended=True).algebra(K) - sage: E = NonSymmetricMacdonaldPolynomials(KL,q, t,-1) + sage: E = NonSymmetricMacdonaldPolynomials(KL, q, t, -1) sage: omega = E.keys().fundamental_weights() sage: La = R.weight_space().basis() + + sage: # needs sage.combinat sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]) - sage: E[-2*omega[1]].map_coefficients(lambda x:x.subs(t=0)) == LS.one_dimensional_configuration_sum(q) # long time (23s) + sage: (E[-2*omega[1]].map_coefficients(lambda x: x.subs(t=0)) # long time (23s) + ....: == LS.one_dimensional_configuration_sum(q)) True sage: B = crystals.KirillovReshetikhin(['B',3,1],1,1) sage: T = crystals.TensorProduct(B,B) - sage: T.one_dimensional_configuration_sum(q) == LS.one_dimensional_configuration_sum(q) # long time (2s) + sage: (T.one_dimensional_configuration_sum(q) # long time (2s) + ....: == LS.one_dimensional_configuration_sum(q)) True :: sage: R = RootSystem(['BC',3,2]) sage: KL = R.weight_lattice(extended=True).algebra(K) - sage: E = NonSymmetricMacdonaldPolynomials(KL,q, t,-1) + sage: E = NonSymmetricMacdonaldPolynomials(KL, q, t, -1) sage: omega = E.keys().fundamental_weights() sage: La = R.weight_space().basis() - sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]) - sage: E[-2*omega[1]].map_coefficients(lambda x:x.subs(t=0)) == LS.one_dimensional_configuration_sum(q) # long time (21s) + sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]) # needs sage.combinat + sage: (E[-2*omega[1]].map_coefficients(lambda x: x.subs(t=0)) # long time (21s), needs sage.combinat + ....: == LS.one_dimensional_configuration_sum(q)) True :: sage: R = RootSystem(CartanType(['BC',3,2]).dual()) sage: KL = R.weight_space(extended=True).algebra(K) - sage: E = NonSymmetricMacdonaldPolynomials(KL,q, t,-1) + sage: E = NonSymmetricMacdonaldPolynomials(KL, q, t, -1) sage: omega = E.keys().fundamental_weights() sage: La = R.weight_space().basis() + + sage: # long time, needs sage.combinat sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]) - sage: g = E[-2*omega[1]].map_coefficients(lambda x:x.subs(t=0)) # long time (30s) - sage: f = LS.one_dimensional_configuration_sum(q) # long time (1.5s) - sage: P = g.support()[0].parent() # long time - sage: B = P.algebra(q.parent()) # long time - sage: sum(p[1]*B(P(p[0])) for p in f) == g # long time + sage: g = E[-2*omega[1]].map_coefficients(lambda x: x.subs(t=0)) # 30s + sage: f = LS.one_dimensional_configuration_sum(q) # 1.5s + sage: P = g.support()[0].parent() + sage: B = P.algebra(q.parent()) + sage: sum(p[1]*B(P(p[0])) for p in f) == g True :: @@ -673,41 +729,47 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: K = QQ['q,t'].fraction_field() sage: q,t = K.gens() sage: KL = R.weight_lattice(extended=True).algebra(K) - sage: E = NonSymmetricMacdonaldPolynomials(KL, q, t,-1) + sage: E = NonSymmetricMacdonaldPolynomials(KL, q, t, -1) sage: omega = E.keys().fundamental_weights() sage: La = R.weight_space().basis() + + sage: # needs sage.combinat sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]) - sage: E[-2*omega[1]].map_coefficients(lambda x:x.subs(t=0)) == LS.one_dimensional_configuration_sum(q) # not tested, long time (20s) + sage: (E[-2*omega[1]].map_coefficients(lambda x: x.subs(t=0)) # long time (20s), not tested + ....: == LS.one_dimensional_configuration_sum(q) True - sage: LS = crystals.ProjectedLevelZeroLSPaths(La[1]+La[2]) - sage: E[-omega[1]-omega[2]].map_coefficients(lambda x:x.subs(t=0)) == LS.one_dimensional_configuration_sum(q) # not tested, long time (23s) + sage: LS = crystals.ProjectedLevelZeroLSPaths(La[1] + La[2]) + sage: (E[-omega[1]-omega[2]].map_coefficients(lambda x: x.subs(t=0)) # long time (23s), not tested + ....: == LS.one_dimensional_configuration_sum(q)) True The next test breaks if the energy is not scaled by the translation factor for dual type `G_2^{(1)}`:: - sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]+La[2]) - sage: E[-2*omega[1]-omega[2]].map_coefficients(lambda x:x.subs(t=0)) == LS.one_dimensional_configuration_sum(q) # not tested, very long time (100s) + sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]+La[2]) # needs sage.combinat + sage: (E[-2*omega[1]-omega[2]].map_coefficients(lambda x: x.subs(t=0)) # long time (100s), not tested, needs sage.combinat + ....: == LS.one_dimensional_configuration_sum(q) True sage: R = RootSystem(['D',4,1]) sage: KL = R.weight_lattice(extended=True).algebra(K) - sage: E = NonSymmetricMacdonaldPolynomials(KL, q, t,-1) + sage: E = NonSymmetricMacdonaldPolynomials(KL, q, t, -1) sage: omega = E.keys().fundamental_weights() sage: La = R.weight_space().basis() - sage: for d in range(1,2): # long time (41s) + sage: for d in range(1,2): # long time (41s) ....: for a,b,c,d in IntegerVectors(d,4): - ....: weight = a*La[1]+b*La[2]+c*La[3]+d*La[4] - ....: weight0 = -a*omega[1]-b*omega[2]-c*omega[3]-d*omega[4] + ....: weight = a*La[1] + b*La[2] + c*La[3] + d*La[4] + ....: weight0 = -a*omega[1] - b*omega[2] - c*omega[3] - d*omega[4] ....: LS = crystals.ProjectedLevelZeroLSPaths(weight) - ....: assert E[weight0].map_coefficients(lambda x:x.subs(t=0)) == LS.one_dimensional_configuration_sum(q) + ....: assert (E[weight0].map_coefficients(lambda x: x.subs(t=0)) + ....: == LS.one_dimensional_configuration_sum(q)) TESTS: Calculations checked with Bogdan Ion 2013/04/18:: sage: K = QQ['q,t'].fraction_field() - sage: q,t=K.gens() + sage: q,t = K.gens() sage: E = NonSymmetricMacdonaldPolynomials(["B",2,1], q=q,q1=t,q2=-1/t) sage: L0 = E.keys() sage: omega = L0.fundamental_weights() @@ -717,16 +779,20 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: E[omega[2]] B[(1/2, 1/2)] sage: E[-omega[1]] - ((-q^2*t^8+q^2*t^6-q*t^6+2*q*t^4-q*t^2+t^2-1)/(-q^3*t^8+q^2*t^6+q*t^2-1))*B[(0, 0)] + B[(-1, 0)] + ((-q*t^8+q*t^6+t^2-1)/(-q^3*t^8+q^2*t^6+q*t^2-1))*B[(1, 0)] + ((-t^2+1)/(-q*t^2+1))*B[(0, -1)] + ((t^2-1)/(q*t^2-1))*B[(0, 1)] + ((-q^2*t^8+q^2*t^6-q*t^6+2*q*t^4-q*t^2+t^2-1)/(-q^3*t^8+q^2*t^6+q*t^2-1))*B[(0, 0)] + + B[(-1, 0)] + ((-q*t^8+q*t^6+t^2-1)/(-q^3*t^8+q^2*t^6+q*t^2-1))*B[(1, 0)] + + ((-t^2+1)/(-q*t^2+1))*B[(0, -1)] + ((t^2-1)/(q*t^2-1))*B[(0, 1)] sage: E[L0([0,1])] ((-q*t^4+q*t^2)/(-q*t^4+1))*B[(0, 0)] + ((-t^2+1)/(-q*t^4+1))*B[(1, 0)] + B[(0, 1)] sage: E[L0([1,1])] - ((q*t^2-q)/(q*t^2-1))*B[(0, 0)] + ((-q*t^2+q)/(-q*t^2+1))*B[(1, 0)] + B[(1, 1)] + ((-q*t^2+q)/(-q*t^2+1))*B[(0, 1)] + ((q*t^2-q)/(q*t^2-1))*B[(0, 0)] + ((-q*t^2+q)/(-q*t^2+1))*B[(1, 0)] + + B[(1, 1)] + ((-q*t^2+q)/(-q*t^2+1))*B[(0, 1)] sage: E = NonSymmetricMacdonaldPolynomials(["A",2,1], q=q,q1=t,q2=-1/t) sage: L0 = E.keys() sage: factor(E[L0([-1,0,1])][L0.zero()]) - (t - 1) * (t + 1) * (q*t^2 - 1)^-3 * (q*t^2 + 1)^-1 * (q^3*t^6 + 2*q^2*t^6 - 3*q^2*t^4 - 2*q*t^2 - t^2 + q + 2) + (t - 1) * (t + 1) * (q*t^2 - 1)^-3 * (q*t^2 + 1)^-1 + * (q^3*t^6 + 2*q^2*t^6 - 3*q^2*t^4 - 2*q*t^2 - t^2 + q + 2) Checking step by step calculations in type `BC` with Bogdan Ion 2013/04/18:: @@ -791,8 +857,22 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: E[omega[1]] ((-q*q1*q2^3-q*q2^4)/(q^2*q1^4-q2^4))*B[(0, 0)] + B[(1, 0)] - sage: E[2*omega[2]] # long time # not checked against Bogdan's notes, but a good self-consistency test - ((-q^12*q1^6-q^12*q1^5*q2+2*q^10*q1^5*q2+5*q^10*q1^4*q2^2+3*q^10*q1^3*q2^3+2*q^8*q1^5*q2+4*q^8*q1^4*q2^2+q^8*q1^3*q2^3-q^8*q1^2*q2^4+q^8*q1*q2^5+q^8*q2^6-q^6*q1^3*q2^3+q^6*q1^2*q2^4+4*q^6*q1*q2^5+2*q^6*q2^6+q^4*q1^3*q2^3+3*q^4*q1^2*q2^4+4*q^4*q1*q2^5+2*q^4*q2^6)/(-q^12*q1^6-q^10*q1^5*q2-q^8*q1^3*q2^3+q^6*q1^4*q2^2-q^6*q1^2*q2^4+q^4*q1^3*q2^3+q^2*q1*q2^5+q2^6))*B[(0, 0)] + ((q^7*q1^2*q2+2*q^7*q1*q2^2+q^7*q2^3+q^5*q1^2*q2+2*q^5*q1*q2^2+q^5*q2^3)/(-q^8*q1^3-q^6*q1^2*q2+q^2*q1*q2^2+q2^3))*B[(-1, 0)] + ((-q^6*q1*q2-q^6*q2^2)/(q^6*q1^2-q2^2))*B[(-1, -1)] + ((q^6*q1^2*q2+2*q^6*q1*q2^2+q^6*q2^3+q^4*q1^2*q2+2*q^4*q1*q2^2+q^4*q2^3)/(-q^8*q1^3-q^6*q1^2*q2+q^2*q1*q2^2+q2^3))*B[(-1, 1)] + ((-q^3*q1*q2-q^3*q2^2)/(q^6*q1^2-q2^2))*B[(-1, 2)] + ((q^7*q1^3+q^7*q1^2*q2-q^7*q1*q2^2-q^7*q2^3-2*q^5*q1^2*q2-4*q^5*q1*q2^2-2*q^5*q2^3-2*q^3*q1^2*q2-4*q^3*q1*q2^2-2*q^3*q2^3)/(q^8*q1^3+q^6*q1^2*q2-q^2*q1*q2^2-q2^3))*B[(1, 0)] + ((q^6*q1^2*q2+2*q^6*q1*q2^2+q^6*q2^3+q^4*q1^2*q2+2*q^4*q1*q2^2+q^4*q2^3)/(-q^8*q1^3-q^6*q1^2*q2+q^2*q1*q2^2+q2^3))*B[(1, -1)] + ((q^8*q1^3+q^8*q1^2*q2+q^6*q1^3+q^6*q1^2*q2-q^6*q1*q2^2-q^6*q2^3-2*q^4*q1^2*q2-4*q^4*q1*q2^2-2*q^4*q2^3-q^2*q1^2*q2-3*q^2*q1*q2^2-2*q^2*q2^3)/(q^8*q1^3+q^6*q1^2*q2-q^2*q1*q2^2-q2^3))*B[(1, 1)] + ((q^5*q1^2+q^5*q1*q2-q^3*q1*q2-q^3*q2^2-q*q1*q2-q*q2^2)/(q^6*q1^2-q2^2))*B[(1, 2)] + ((-q^6*q1^2-q^6*q1*q2+q^4*q1*q2+q^4*q2^2+q^2*q1*q2+q^2*q2^2)/(-q^6*q1^2+q2^2))*B[(2, 0)] + ((-q^3*q1*q2-q^3*q2^2)/(q^6*q1^2-q2^2))*B[(2, -1)] + ((-q^5*q1^2-q^5*q1*q2+q^3*q1*q2+q^3*q2^2+q*q1*q2+q*q2^2)/(-q^6*q1^2+q2^2))*B[(2, 1)] + B[(2, 2)] + ((q^7*q1^2*q2+2*q^7*q1*q2^2+q^7*q2^3+q^5*q1^2*q2+2*q^5*q1*q2^2+q^5*q2^3)/(-q^8*q1^3-q^6*q1^2*q2+q^2*q1*q2^2+q2^3))*B[(0, -1)] + ((q^7*q1^3+q^7*q1^2*q2-q^7*q1*q2^2-q^7*q2^3-2*q^5*q1^2*q2-4*q^5*q1*q2^2-2*q^5*q2^3-2*q^3*q1^2*q2-4*q^3*q1*q2^2-2*q^3*q2^3)/(q^8*q1^3+q^6*q1^2*q2-q^2*q1*q2^2-q2^3))*B[(0, 1)] + ((q^6*q1^2+q^6*q1*q2-q^4*q1*q2-q^4*q2^2-q^2*q1*q2-q^2*q2^2)/(q^6*q1^2-q2^2))*B[(0, 2)] + sage: E[2*omega[2]] # not checked against Bogdan's notes, but a good self-consistency test # long time + ((-q^12*q1^6-q^12*q1^5*q2+2*q^10*q1^5*q2+5*q^10*q1^4*q2^2+3*q^10*q1^3*q2^3+2*q^8*q1^5*q2+4*q^8*q1^4*q2^2+q^8*q1^3*q2^3-q^8*q1^2*q2^4+q^8*q1*q2^5+q^8*q2^6-q^6*q1^3*q2^3+q^6*q1^2*q2^4+4*q^6*q1*q2^5+2*q^6*q2^6+q^4*q1^3*q2^3+3*q^4*q1^2*q2^4+4*q^4*q1*q2^5+2*q^4*q2^6)/(-q^12*q1^6-q^10*q1^5*q2-q^8*q1^3*q2^3+q^6*q1^4*q2^2-q^6*q1^2*q2^4+q^4*q1^3*q2^3+q^2*q1*q2^5+q2^6))*B[(0, 0)] + + ((q^7*q1^2*q2+2*q^7*q1*q2^2+q^7*q2^3+q^5*q1^2*q2+2*q^5*q1*q2^2+q^5*q2^3)/(-q^8*q1^3-q^6*q1^2*q2+q^2*q1*q2^2+q2^3))*B[(-1, 0)] + + ((-q^6*q1*q2-q^6*q2^2)/(q^6*q1^2-q2^2))*B[(-1, -1)] + + ((q^6*q1^2*q2+2*q^6*q1*q2^2+q^6*q2^3+q^4*q1^2*q2+2*q^4*q1*q2^2+q^4*q2^3)/(-q^8*q1^3-q^6*q1^2*q2+q^2*q1*q2^2+q2^3))*B[(-1, 1)] + + ((-q^3*q1*q2-q^3*q2^2)/(q^6*q1^2-q2^2))*B[(-1, 2)] + + ((q^7*q1^3+q^7*q1^2*q2-q^7*q1*q2^2-q^7*q2^3-2*q^5*q1^2*q2-4*q^5*q1*q2^2-2*q^5*q2^3-2*q^3*q1^2*q2-4*q^3*q1*q2^2-2*q^3*q2^3)/(q^8*q1^3+q^6*q1^2*q2-q^2*q1*q2^2-q2^3))*B[(1, 0)] + ((q^6*q1^2*q2+2*q^6*q1*q2^2+q^6*q2^3+q^4*q1^2*q2+2*q^4*q1*q2^2+q^4*q2^3)/(-q^8*q1^3-q^6*q1^2*q2+q^2*q1*q2^2+q2^3))*B[(1, -1)] + + ((q^8*q1^3+q^8*q1^2*q2+q^6*q1^3+q^6*q1^2*q2-q^6*q1*q2^2-q^6*q2^3-2*q^4*q1^2*q2-4*q^4*q1*q2^2-2*q^4*q2^3-q^2*q1^2*q2-3*q^2*q1*q2^2-2*q^2*q2^3)/(q^8*q1^3+q^6*q1^2*q2-q^2*q1*q2^2-q2^3))*B[(1, 1)] + + ((q^5*q1^2+q^5*q1*q2-q^3*q1*q2-q^3*q2^2-q*q1*q2-q*q2^2)/(q^6*q1^2-q2^2))*B[(1, 2)] + + ((-q^6*q1^2-q^6*q1*q2+q^4*q1*q2+q^4*q2^2+q^2*q1*q2+q^2*q2^2)/(-q^6*q1^2+q2^2))*B[(2, 0)] + + ((-q^3*q1*q2-q^3*q2^2)/(q^6*q1^2-q2^2))*B[(2, -1)] + + ((-q^5*q1^2-q^5*q1*q2+q^3*q1*q2+q^3*q2^2+q*q1*q2+q*q2^2)/(-q^6*q1^2+q2^2))*B[(2, 1)] + + B[(2, 2)] + + ((q^7*q1^2*q2+2*q^7*q1*q2^2+q^7*q2^3+q^5*q1^2*q2+2*q^5*q1*q2^2+q^5*q2^3)/(-q^8*q1^3-q^6*q1^2*q2+q^2*q1*q2^2+q2^3))*B[(0, -1)] + + ((q^7*q1^3+q^7*q1^2*q2-q^7*q1*q2^2-q^7*q2^3-2*q^5*q1^2*q2-4*q^5*q1*q2^2-2*q^5*q2^3-2*q^3*q1^2*q2-4*q^3*q1*q2^2-2*q^3*q2^3)/(q^8*q1^3+q^6*q1^2*q2-q^2*q1*q2^2-q2^3))*B[(0, 1)] + + ((q^6*q1^2+q^6*q1*q2-q^4*q1*q2-q^4*q2^2-q^2*q1*q2-q^2*q2^2)/(q^6*q1^2-q2^2))*B[(0, 2)] sage: E.recursion(2*omega[2]) [0, 1, 0, 2, 1, 0, 2, 1, 0] @@ -800,17 +880,17 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): defining the `Y` s in terms of them:: sage: T = E._T_Y - sage: Ye1 = T.Tw((1,2,1,0), scalar = (-1/(q1*q2))^2) - sage: Ye2 = T.Tw((2,1,0,1), signs = (1,1,1,-1), scalar = (-1/(q1*q2))) - sage: Yalpha0 = T.Tw((0,1,2,1), signs = (-1,-1,-1,-1), scalar = q^-1*(-q1*q2)^2) - sage: Yalpha1 = T.Tw((1,2,0,1,2,0), signs=(1,1,-1,1,-1,1), scalar = -1/(q1*q2)) - sage: Yalpha2 = T.Tw((2,1,0,1,2,1,0,1), signs = (1,1,1,-1,1,1,1,-1), scalar = (1/(q1*q2))^2) + sage: Ye1 = T.Tw((1,2,1,0), scalar=(-1/(q1*q2))^2) + sage: Ye2 = T.Tw((2,1,0,1), signs=(1,1,1,-1), scalar=(-1/(q1*q2))) + sage: Yalpha0 = T.Tw((0,1,2,1), signs=(-1,-1,-1,-1), scalar=q^-1*(-q1*q2)^2) + sage: Yalpha1 = T.Tw((1,2,0,1,2,0), signs=(1,1,-1,1,-1,1), scalar=-1/(q1*q2)) + sage: Yalpha2 = T.Tw((2,1,0,1,2,1,0,1), signs=(1,1,1,-1,1,1,1,-1), + ....: scalar=(1/(q1*q2))^2) sage: Ye1(KL0.one()) q1^2/q2^2*B[(0, 0)] sage: Ye2(KL0.one()) ((-q1)/q2)*B[(0, 0)] - sage: Yalpha0(KL0.one()) q2^2/(q*q1^2)*B[(0, 0)] sage: Yalpha1(KL0.one()) @@ -830,12 +910,11 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): e[0] - e[1] sage: L(alpha[2]) e[1] - sage: Y[alpha[0]].word (0, 1, 2, 1) sage: Y[alpha[0]].signs (-1, -1, -1, -1) - sage: Y[alpha[0]].scalar # mind that Sage's q is the usual q^{1/2} + sage: Y[alpha[0]].scalar # mind that Sage's q is the usual q^{1/2} q1^2*q2^2/q sage: Y[alpha[0]](KL0.one()) q2^2/(q*q1^2)*B[(0, 0)] @@ -847,7 +926,7 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: Y[alpha[1]].scalar 1/(-q1*q2) - sage: Y[alpha[2]].word # Bogdan says it should be the square of that; do we need to take translation factors into account or not? + sage: Y[alpha[2]].word # Bogdan says it should be the square of that; do we need to take translation factors into account or not? (2, 1, 0, 1) sage: Y[alpha[2]].signs (1, 1, 1, -1) @@ -865,11 +944,11 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): Checking T0check:: sage: T0check_on_basis = KL.T0_check_on_basis(q1,q2, convention="dominant") - sage: T0check_on_basis.phi # note: this is in fact a0 phi + sage: T0check_on_basis.phi # note: this is in fact a0 phi (2, 0) - sage: T0check_on_basis.v # what to match it with? + sage: T0check_on_basis.v # what to match it with? (1,) - sage: T0check_on_basis.j # what to match it with? + sage: T0check_on_basis.j # what to match it with? 2 sage: T0check_on_basis(KL0.basis().keys().zero()) ((-q1^2)/q2)*B[(1, 0)] @@ -898,7 +977,6 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: x.parent() Algebra of the Weight lattice of the Root system of type ['A', 1] over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field - sage: E[omega[1]] B[Lambda[1]] sage: E.eigenvalues(_) @@ -908,15 +986,24 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: E.eigenvalues(_) [q*t, 1/(q^2*t)] sage: E[3*omega[1]] - ((-q^2*t+q^2)/(-q^2*t+1))*B[-Lambda[1]] + ((-q^2*t+q^2-q*t+q)/(-q^2*t+1))*B[Lambda[1]] + B[3*Lambda[1]] + ((-q^2*t+q^2)/(-q^2*t+1))*B[-Lambda[1]] + + ((-q^2*t+q^2-q*t+q)/(-q^2*t+1))*B[Lambda[1]] + B[3*Lambda[1]] sage: E.eigenvalues(_) [q^2*t, 1/(q^3*t)] sage: E[4*omega[1]] - ((q^5*t^2-q^5*t+q^4*t^2-2*q^4*t+q^3*t^2+q^4-2*q^3*t+q^3-q^2*t+q^2)/(q^5*t^2-q^3*t-q^2*t+1))*B[0] + ((-q^3*t+q^3)/(-q^3*t+1))*B[-2*Lambda[1]] + ((-q^3*t+q^3-q^2*t+q^2-q*t+q)/(-q^3*t+1))*B[2*Lambda[1]] + B[4*Lambda[1]] + ((q^5*t^2-q^5*t+q^4*t^2-2*q^4*t+q^3*t^2+q^4-2*q^3*t+q^3-q^2*t+q^2)/(q^5*t^2-q^3*t-q^2*t+1))*B[0] + + ((-q^3*t+q^3)/(-q^3*t+1))*B[-2*Lambda[1]] + + ((-q^3*t+q^3-q^2*t+q^2-q*t+q)/(-q^3*t+1))*B[2*Lambda[1]] + + B[4*Lambda[1]] sage: E.eigenvalues(_) [q^3*t, 1/(q^4*t)] sage: E[6*omega[1]] - ((-q^12*t^3+q^12*t^2-q^11*t^3+2*q^11*t^2-2*q^10*t^3-q^11*t+4*q^10*t^2-2*q^9*t^3-2*q^10*t+5*q^9*t^2-2*q^8*t^3-4*q^9*t+6*q^8*t^2-q^7*t^3+q^9-5*q^8*t+5*q^7*t^2-q^6*t^3+q^8-6*q^7*t+4*q^6*t^2+2*q^7-5*q^6*t+2*q^5*t^2+2*q^6-4*q^5*t+q^4*t^2+2*q^5-2*q^4*t+q^4-q^3*t+q^3)/(-q^12*t^3+q^9*t^2+q^8*t^2+q^7*t^2-q^5*t-q^4*t-q^3*t+1))*B[0] + ((-q^5*t+q^5)/(-q^5*t+1))*B[-4*Lambda[1]] + ((q^9*t^2-q^9*t+q^8*t^2-2*q^8*t+q^7*t^2+q^8-2*q^7*t+q^6*t^2+q^7-2*q^6*t+q^5*t^2+q^6-2*q^5*t+q^5-q^4*t+q^4)/(q^9*t^2-q^5*t-q^4*t+1))*B[-2*Lambda[1]] + ((q^9*t^2-q^9*t+q^8*t^2-2*q^8*t+2*q^7*t^2+q^8-3*q^7*t+2*q^6*t^2+q^7-4*q^6*t+2*q^5*t^2+2*q^6-4*q^5*t+q^4*t^2+2*q^5-3*q^4*t+q^3*t^2+2*q^4-2*q^3*t+q^3-q^2*t+q^2)/(q^9*t^2-q^5*t-q^4*t+1))*B[2*Lambda[1]] + ((q^5*t-q^5+q^4*t-q^4+q^3*t-q^3+q^2*t-q^2+q*t-q)/(q^5*t-1))*B[4*Lambda[1]] + B[6*Lambda[1]] + ((-q^12*t^3+q^12*t^2-q^11*t^3+2*q^11*t^2-2*q^10*t^3-q^11*t+4*q^10*t^2-2*q^9*t^3-2*q^10*t+5*q^9*t^2-2*q^8*t^3-4*q^9*t+6*q^8*t^2-q^7*t^3+q^9-5*q^8*t+5*q^7*t^2-q^6*t^3+q^8-6*q^7*t+4*q^6*t^2+2*q^7-5*q^6*t+2*q^5*t^2+2*q^6-4*q^5*t+q^4*t^2+2*q^5-2*q^4*t+q^4-q^3*t+q^3)/(-q^12*t^3+q^9*t^2+q^8*t^2+q^7*t^2-q^5*t-q^4*t-q^3*t+1))*B[0] + + ((-q^5*t+q^5)/(-q^5*t+1))*B[-4*Lambda[1]] + + ((q^9*t^2-q^9*t+q^8*t^2-2*q^8*t+q^7*t^2+q^8-2*q^7*t+q^6*t^2+q^7-2*q^6*t+q^5*t^2+q^6-2*q^5*t+q^5-q^4*t+q^4)/(q^9*t^2-q^5*t-q^4*t+1))*B[-2*Lambda[1]] + + ((q^9*t^2-q^9*t+q^8*t^2-2*q^8*t+2*q^7*t^2+q^8-3*q^7*t+2*q^6*t^2+q^7-4*q^6*t+2*q^5*t^2+2*q^6-4*q^5*t+q^4*t^2+2*q^5-3*q^4*t+q^3*t^2+2*q^4-2*q^3*t+q^3-q^2*t+q^2)/(q^9*t^2-q^5*t-q^4*t+1))*B[2*Lambda[1]] + + ((q^5*t-q^5+q^4*t-q^4+q^3*t-q^3+q^2*t-q^2+q*t-q)/(q^5*t-1))*B[4*Lambda[1]] + + B[6*Lambda[1]] sage: E.eigenvalues(_) [q^5*t, 1/(q^6*t)] sage: E[-omega[1]] @@ -961,24 +1048,29 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): x0^2 + (q*t - q)/(q*t - 1)*x0*x1 + (q*t - q)/(q*t - 1)*x0*x2 sage: EE([0,2,0]) - (t - 1)/(q^2*t^2 - 1)*x0^2 + (q^2*t^3 - q^2*t^2 + q*t^2 - 2*q*t + q - t + 1)/(q^3*t^3 - q^2*t^2 - q*t + 1)*x0*x1 + x1^2 + (q*t^2 - 2*q*t + q)/(q^3*t^3 - q^2*t^2 - q*t + 1)*x0*x2 + (q*t - q)/(q*t - 1)*x1*x2 + (t - 1)/(q^2*t^2 - 1)*x0^2 + + (q^2*t^3 - q^2*t^2 + q*t^2 - 2*q*t + q - t + 1)/(q^3*t^3 - q^2*t^2 - q*t + 1)*x0*x1 + + x1^2 + + (q*t^2 - 2*q*t + q)/(q^3*t^3 - q^2*t^2 - q*t + 1)*x0*x2 + + (q*t - q)/(q*t - 1)*x1*x2 Systematic checks with Sage's implementation of [HHL06]_:: - sage: import sage.combinat.sf.ns_macdonald as NS - sage: assert all(EE([x,y,z]) == NS.E([x,y,z]) for d in range(5) for x,y,z in IntegerVectors(d,3)) # long time (9s) + sage: import sage.combinat.sf.ns_macdonald as NS # needs sage.combinat + sage: assert all(EE([x,y,z]) == NS.E([x,y,z]) for d in range(5) # long time (9s), needs sage.combinat + ....: for x,y,z in IntegerVectors(d,3)) We check that we get eigenvectors for generic `q_1`, `q_2`:: sage: K = QQ['q,q1,q2'].fraction_field() sage: q,q1,q2 = K.gens() sage: KL = RootSystem(["A",2,1]).ambient_space().algebra(K) - sage: E = NonSymmetricMacdonaldPolynomials(KL,q, q1, q2) + sage: E = NonSymmetricMacdonaldPolynomials(KL, q, q1, q2) sage: L0 = E.keys() sage: omega = L0.fundamental_weights() sage: E[2*omega[2]] ((-q*q1-q*q2)/(-q*q1-q2))*B[(1, 2, 1)] + ((-q*q1-q*q2)/(-q*q1-q2))*B[(2, 1, 1)] + B[(2, 2, 0)] - sage: for d in range(4): # long time (9s) + sage: for d in range(4): # long time (9s) ....: for weight in IntegerVectors(d,3).map(list).map(L0): ....: eigenvalues = E.eigenvalues(E[L0(weight)]) @@ -999,28 +1091,36 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: E.eigenvalues(_) # not checked [t, 1/(q*t^3), t] - sage: E[-omega[1]] # consistent with before refactoring - B[(-1, 0)] + ((-t+1)/(-q*t+1))*B[(1, 0)] + ((-t+1)/(-q*t+1))*B[(0, -1)] + ((t-1)/(q*t-1))*B[(0, 1)] + sage: E[-omega[1]] # consistent with before refactoring + B[(-1, 0)] + ((-t+1)/(-q*t+1))*B[(1, 0)] + + ((-t+1)/(-q*t+1))*B[(0, -1)] + ((t-1)/(q*t-1))*B[(0, 1)] sage: E.eigenvalues(_) # not checked [(-1)/(-q^2*t^3), q*t, t] - sage: E[-omega[1]+omega[2]] # consistent with before refactoring + sage: E[-omega[1]+omega[2]] # consistent with before refactoring ((-t+1)/(-q*t^3+1))*B[(1, 0)] + B[(0, 1)] sage: E.eigenvalues(_) # not checked [t, q*t^3, (-1)/(-q*t^2)] - sage: E[omega[1]-omega[2]] # consistent with before refactoring + sage: E[omega[1]-omega[2]] # consistent with before refactoring ((-t+1)/(-q*t^2+1))*B[(1, 0)] + B[(0, -1)] + ((-t+1)/(-q*t^2+1))*B[(0, 1)] sage: E.eigenvalues(_) # not checked [1/(q^2*t^3), 1/(q*t), q*t^2] sage: E[-omega[2]] - ((-q^2*t^4+q^2*t^3-q*t^3+2*q*t^2-q*t+t-1)/(-q^3*t^4+q^2*t^3+q*t-1))*B[(0, 0)] + B[(-1, -1)] + ((-t+1)/(-q*t+1))*B[(-1, 1)] + ((t-1)/(q*t-1))*B[(1, -1)] + ((-q*t^4+q*t^3+t-1)/(-q^3*t^4+q^2*t^3+q*t-1))*B[(1, 1)] - sage: E.eigenvalues(_) # not checked # long time (1s) + ((-q^2*t^4+q^2*t^3-q*t^3+2*q*t^2-q*t+t-1)/(-q^3*t^4+q^2*t^3+q*t-1))*B[(0, 0)] + + B[(-1, -1)] + ((-t+1)/(-q*t+1))*B[(-1, 1)] + ((t-1)/(q*t-1))*B[(1, -1)] + + ((-q*t^4+q*t^3+t-1)/(-q^3*t^4+q^2*t^3+q*t-1))*B[(1, 1)] + sage: E.eigenvalues(_) # not checked # long time (1s) [1/(q^3*t^3), t, q*t] sage: E[-omega[2]].map_coefficients(lambda c: c.subs(t=0)) # checking against crystals B[(0, 0)] + B[(-1, -1)] + B[(-1, 1)] + B[(1, -1)] + B[(1, 1)] sage: E[2*omega[2]] - ((-q^6*t^7+q^6*t^6-q^5*t^6+2*q^5*t^5-q^4*t^5-q^5*t^3+3*q^4*t^4-3*q^4*t^3+q^3*t^4+q^4*t^2-2*q^3*t^2+q^3*t-q^2*t+q^2)/(-q^6*t^7+q^5*t^6+q^4*t^4+q^3*t^4-q^3*t^3-q^2*t^3-q*t+1))*B[(0, 0)] + ((-q^3*t^2+q^3*t)/(-q^3*t^3+1))*B[(-1, -1)] + ((-q^3*t^3+2*q^3*t^2-q^3*t)/(-q^4*t^4+q^3*t^3+q*t-1))*B[(-1, 1)] + ((-q^3*t^3+2*q^3*t^2-q^3*t)/(-q^4*t^4+q^3*t^3+q*t-1))*B[(1, -1)] + ((-q^4*t^4+q^4*t^3-q^3*t^3+2*q^3*t^2-q^2*t^3-q^3*t+2*q^2*t^2-q^2*t+q*t-q)/(-q^4*t^4+q^3*t^3+q*t-1))*B[(1, 1)] + ((q*t-q)/(q*t-1))*B[(2, 0)] + B[(2, 2)] + ((-q*t+q)/(-q*t+1))*B[(0, 2)] + ((-q^6*t^7+q^6*t^6-q^5*t^6+2*q^5*t^5-q^4*t^5-q^5*t^3+3*q^4*t^4-3*q^4*t^3+q^3*t^4+q^4*t^2-2*q^3*t^2+q^3*t-q^2*t+q^2)/(-q^6*t^7+q^5*t^6+q^4*t^4+q^3*t^4-q^3*t^3-q^2*t^3-q*t+1))*B[(0, 0)] + + ((-q^3*t^2+q^3*t)/(-q^3*t^3+1))*B[(-1, -1)] + + ((-q^3*t^3+2*q^3*t^2-q^3*t)/(-q^4*t^4+q^3*t^3+q*t-1))*B[(-1, 1)] + + ((-q^3*t^3+2*q^3*t^2-q^3*t)/(-q^4*t^4+q^3*t^3+q*t-1))*B[(1, -1)] + + ((-q^4*t^4+q^4*t^3-q^3*t^3+2*q^3*t^2-q^2*t^3-q^3*t+2*q^2*t^2-q^2*t+q*t-q)/(-q^4*t^4+q^3*t^3+q*t-1))*B[(1, 1)] + + ((q*t-q)/(q*t-1))*B[(2, 0)] + B[(2, 2)] + ((-q*t+q)/(-q*t+1))*B[(0, 2)] sage: E.eigenvalues(_) # not checked [q^3*t^3, t, (-1)/(-q^2*t^2)] @@ -1033,7 +1133,8 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: E.eigenvalues(E11) [q*t^3, t, (-1)/(-q*t^2)] - sage: E1m1 = KL0.sum_of_terms([[L0([1,-1]), 1], [L0([1,1]), (1-t)/(1-q*t^2)], [L0([0,0]), q*t*(1-t)/(1-q*t^2)] ]) + sage: E1m1 = KL0.sum_of_terms([[L0([1,-1]), 1], [L0([1,1]), (1-t)/(1-q*t^2)], + ....: [L0([0,0]), q*t*(1-t)/(1-q*t^2)]]) sage: E1m1 == E[2*omega[1]-omega[2]] True sage: E.eigenvalues(E1m1) @@ -1057,11 +1158,13 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): [q*t^2, 1/(q^2*t^3), t] sage: E[-omega[1]] - ((-q*t+q-t+1)/(-q^2*t+1))*B[(0, 0)] + B[(-1, 0)] + ((-t+1)/(-q^2*t+1))*B[(1, 0)] + ((-t+1)/(-q^2*t+1))*B[(0, -1)] + ((t-1)/(q^2*t-1))*B[(0, 1)] + ((-q*t+q-t+1)/(-q^2*t+1))*B[(0, 0)] + B[(-1, 0)] + ((-t+1)/(-q^2*t+1))*B[(1, 0)] + + ((-t+1)/(-q^2*t+1))*B[(0, -1)] + ((t-1)/(q^2*t-1))*B[(0, 1)] sage: E.eigenvalues(_) [(-1)/(-q^3*t^2), q^2*t, t] sage: E[-omega[1]+omega[2]] - B[(-1/2, 1/2)] + ((-t+1)/(-q^2*t^3+1))*B[(1/2, -1/2)] + ((-q*t^3+q*t^2-t+1)/(-q^2*t^3+1))*B[(1/2, 1/2)] + B[(-1/2, 1/2)] + ((-t+1)/(-q^2*t^3+1))*B[(1/2, -1/2)] + + ((-q*t^3+q*t^2-t+1)/(-q^2*t^3+1))*B[(1/2, 1/2)] sage: E.eigenvalues(_) [(-1)/(-q^2*t^2), q^2*t^3, (-1)/(-q*t)] sage: E[omega[1]-omega[2]] @@ -1073,30 +1176,33 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): sage: K = QQ['q','t'].fraction_field() sage: q,t = K.gens() - sage: def to_SR(x): return x.expand([SR.var('x%s'%i) for i in range(1,x.parent().basis().keys().dimension()+1)]).subs(q=SR.var('q'), t=SR.var('t')) - sage: var('x1,x2,x3') + sage: def to_SR(x): + ....: dim = x.parent().basis().keys().dimension() + ....: x_expanded = x.expand([SR.var('x%s'%i) for i in range(1, dim + 1)]) + ....: return x_expanded.subs(q=SR.var('q'), t=SR.var('t')) + sage: var('x1,x2,x3') # needs sage.symbolic (x1, x2, x3) - sage: E = NonSymmetricMacdonaldPolynomials(["BC",2,2], q=q, q1=t^2,q2=-1) - sage: omega=E.keys().fundamental_weights() - sage: expected = (t-1)*(t+1)*(2+q^4+2*q^2-2*t^2-2*q^2*t^2-t^4*q^2-q^4*t^4+t^4-3*q^6*t^6-2*q^4*t^6+2*q^6*t^8+2*q^4*t^8+t^10*q^8)*q^4/((q^2*t^3-1)*(q^2*t^3+1)*(t*q-1)*(t*q+1)*(t^2*q^3+1)*(t^2*q^3-1))+(t-1)^2*(t+1)^2*(2*q^2+q^4+2+q^4*t^2)*q^3*x1/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1))+(t-1)^2*(t+1)^2*(q^2+1)*q^5/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1)*x1)+(t-1)^2*(t+1)^2*(q^2+1)*q^4*x2/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1)*x1)+(t-1)^2*(t+1)^2*(2*q^2+q^4+2+q^4*t^2)*q^3*x2/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1))+(t-1)^2*(t+1)^2*(q^2+1)*q^5/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1)*x2)+x1^2*x2^2+(t-1)*(t+1)*(-2*q^2-q^4-2+2*q^2*t^2+t^2+q^6*t^4+q^4*t^4)*q^2*x2*x1/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1))+(t-1)*(t+1)*(q^2+1+q^4*t^2)*q*x2^2*x1/((t^2*q^3-1)*(t^2*q^3+1))+(t-1)*(t+1)*q^3*x1^2/((t^2*q^3-1)*(t^2*q^3+1)*x2)+(t-1)*(t+1)*(q^2+1+q^4*t^2)*q*x2*x1^2/((t^2*q^3-1)*(t^2*q^3+1))+(t-1)*(t+1)*q^6/((t^2*q^3+1)*(t^2*q^3-1)*x1*x2)+(t-1)*(t+1)*(q^2+1+q^4*t^2)*q^2*x1^2/((t^2*q^3-1)*(t^2*q^3+1))+(t-1)*(t+1)*(q^2+1+q^4*t^2)*q^2*x2^2/((t^2*q^3-1)*(t^2*q^3+1))+(t-1)*(t+1)*q^3*x2^2/((t^2*q^3-1)*(t^2*q^3+1)*x1)+(t-1)^2*(t+1)^2*(q^2+1)*q^4*x1/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1)*x2) - sage: to_SR(E[2*omega[2]]) - expected # long time (3.5s) + sage: E = NonSymmetricMacdonaldPolynomials(["BC",2,2], q=q, q1=t^2, q2=-1) + sage: omega = E.keys().fundamental_weights() + sage: expected = (t-1)*(t+1)*(2+q^4+2*q^2-2*t^2-2*q^2*t^2-t^4*q^2-q^4*t^4+t^4-3*q^6*t^6-2*q^4*t^6+2*q^6*t^8+2*q^4*t^8+t^10*q^8)*q^4/((q^2*t^3-1)*(q^2*t^3+1)*(t*q-1)*(t*q+1)*(t^2*q^3+1)*(t^2*q^3-1))+(t-1)^2*(t+1)^2*(2*q^2+q^4+2+q^4*t^2)*q^3*x1/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1))+(t-1)^2*(t+1)^2*(q^2+1)*q^5/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1)*x1)+(t-1)^2*(t+1)^2*(q^2+1)*q^4*x2/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1)*x1)+(t-1)^2*(t+1)^2*(2*q^2+q^4+2+q^4*t^2)*q^3*x2/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1))+(t-1)^2*(t+1)^2*(q^2+1)*q^5/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1)*x2)+x1^2*x2^2+(t-1)*(t+1)*(-2*q^2-q^4-2+2*q^2*t^2+t^2+q^6*t^4+q^4*t^4)*q^2*x2*x1/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1))+(t-1)*(t+1)*(q^2+1+q^4*t^2)*q*x2^2*x1/((t^2*q^3-1)*(t^2*q^3+1))+(t-1)*(t+1)*q^3*x1^2/((t^2*q^3-1)*(t^2*q^3+1)*x2)+(t-1)*(t+1)*(q^2+1+q^4*t^2)*q*x2*x1^2/((t^2*q^3-1)*(t^2*q^3+1))+(t-1)*(t+1)*q^6/((t^2*q^3+1)*(t^2*q^3-1)*x1*x2)+(t-1)*(t+1)*(q^2+1+q^4*t^2)*q^2*x1^2/((t^2*q^3-1)*(t^2*q^3+1))+(t-1)*(t+1)*(q^2+1+q^4*t^2)*q^2*x2^2/((t^2*q^3-1)*(t^2*q^3+1))+(t-1)*(t+1)*q^3*x2^2/((t^2*q^3-1)*(t^2*q^3+1)*x1)+(t-1)^2*(t+1)^2*(q^2+1)*q^4*x1/((t^2*q^3+1)*(t^2*q^3-1)*(t*q-1)*(t*q+1)*x2) # needs sage.symbolic + sage: to_SR(E[2*omega[2]]) - expected # long time (3.5s) # needs sage.symbolic 0 - sage: E = NonSymmetricMacdonaldPolynomials(["BC",3,2], q=q, q1=t^2,q2=-1) + sage: E = NonSymmetricMacdonaldPolynomials(["BC",3,2], q=q, q1=t^2, q2=-1) sage: omega=E.keys().fundamental_weights() sage: mu = -3*omega[1] + 3*omega[2] - omega[3]; mu (-1, 2, -1) - sage: expected = (t-1)^2*(t+1)^2*(3*q^2+q^4+1+t^2*q^4+q^2*t^2-3*t^4*q^2-5*t^6*q^4+2*t^8*q^4-4*t^8*q^6-q^8*t^10+2*t^10*q^6-2*q^8*t^12+t^14*q^8-t^14*q^10+q^10*t^16+q^8*t^16+q^10*t^18+t^18*q^12)*x2*x1/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(q^2*t^6+2*t^6*q^4-q^4*t^4+t^4*q^2-q^2*t^2+t^2-2-q^2)*q^2*x1/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)^2*(t+1)^2*(-q^2-1+t^4*q^2-q^4*t^4+2*t^6*q^4)*x1^2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t+1)*(t-1)*x2^2*x3/((t*q-1)*(t*q+1)*x1)+(t-1)^2*(t+1)^2*(3*q^2+q^4+2+t^2*q^4+2*q^2*t^2-4*t^4*q^2+q^4*t^4-6*t^6*q^4+t^8*q^4-4*t^8*q^6-q^8*t^10+t^10*q^6-3*q^8*t^12-2*t^14*q^10+2*t^14*q^8+2*q^10*t^16+q^8*t^16+t^18*q^12+2*q^10*t^18)*q*x2/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(1+q^4+2*q^2+t^2*q^4-3*t^4*q^2+q^2*t^6-5*t^6*q^4+3*t^8*q^4-4*t^8*q^6+2*t^10*q^6-q^8*t^12-t^14*q^10+t^14*q^8+q^10*t^16+t^18*q^12)*x3*x1/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(2*q^2+1+q^4+t^2*q^4-t^2+q^2*t^2-4*t^4*q^2+q^4*t^4+q^2*t^6-5*t^6*q^4+3*t^8*q^4-4*t^8*q^6+2*t^10*q^6+q^6*t^12-2*q^8*t^12-2*t^14*q^10+2*t^14*q^8+q^10*t^16+t^18*q^12)*q*x3/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(1+t^2+t^4*q^2)*q*x3*x2^2/((t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1))+(t-1)^2*(t+1)^2*(-q^2-2-q^2*t^2+t^4-q^4*t^4-t^4*q^2+3*q^2*t^6-t^6*q^4-t^8*q^6+t^8*q^4+t^10*q^4+2*q^6*t^12-q^8*t^12+t^14*q^8)*q*x3*x2*x1/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t-1)*(t+1)*x1^2/((q^3*t^5-1)*(q^3*t^5+1)*x3*x2)+(t-1)*(t+1)*(-q^2-1+t^4*q^2-q^4*t^4+2*t^6*q^4)*x2^2/((t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1))+(t-1)*(t+1)*(t^3*q-1)*(t^3*q+1)*x3*x2^2*x1/((t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1))+(t-1)^2*(t+1)^2*(q^2+1)*q*x1/((t*q+1)*(t*q-1)*(q^3*t^5+1)*(q^3*t^5-1)*x3*x2)+(t-1)^2*(t+1)^2*(t^3*q-1)*(t^3*q+1)*x3*x2*x1^2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t-1)^2*(t+1)^2*q^3*x3/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x1*x2)+(t-1)*(t+1)*(-1-q^2+q^2*t^2+t^10*q^6)*q*x2/((t*q+1)*(t*q-1)*(q^3*t^5+1)*(q^3*t^5-1)*x3*x1)+x2^2/(x1*x3)+(t-1)*(t+1)*q*x2^2/((t*q-1)*(t*q+1)*x3)+(t-1)^3*(t+1)^3*(1+t^2+t^4*q^2)*q*x2*x1^2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t-1)^2*(t+1)^2*q*x1^2/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t-1)^2*(t+1)^2*(q^2*t^6+2*t^6*q^4-q^4*t^4+t^4*q^2-q^2*t^2+t^2-2-q^2)*q^3/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)*(t+1)*(q^2+2-t^2+q^4*t^4-t^4*q^2-3*t^6*q^4+t^8*q^4-2*t^10*q^6-q^8*t^12+q^6*t^12+q^8*t^16+q^10*t^16)*q^2*x2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x1)+(t-1)^2*(t+1)^2*(q^2+1)*q^2/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3*x2)+(t-1)*(t+1)*(1+q^4+2*q^2-2*q^2*t^2+t^4*q^6-q^4*t^4-3*q^6*t^6-t^6*q^4+2*t^8*q^6-t^10*q^6-q^8*t^10-t^14*q^10+t^14*q^8+2*q^10*t^16)*x2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t-1)^2*(t+1)^2*(-q^2-2-q^2*t^2-q^4*t^4+2*t^6*q^4+t^10*q^6+q^8*t^12+t^14*q^8)*q^3/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x1)+(t-1)^2*(t+1)^2*(-1-q^2-q^2*t^2+t^2+t^4*q^2-q^4*t^4+2*t^6*q^4)*q^2*x3/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)*(t+1)*q*x2^2/((t*q-1)*(t*q+1)*x1)+(t-1)^2*(t+1)^2*(1+t^2+t^4*q^2)*q*x2^2*x1/((t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1))+(t-1)^2*(t+1)^2*q*x1^2/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)^2*(t+1)^2*(-1-q^4-2*q^2-t^2*q^4-q^2*t^2+t^4*q^2-t^4*q^6-2*q^4*t^4+3*t^6*q^4-q^6*t^6-t^8*q^8+t^8*q^6+2*t^10*q^6-q^10*t^12+3*q^8*t^12+2*t^14*q^10)*x3*x2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t-1)*(t+1)*(q^2+1-t^2+q^4*t^4-t^4*q^2+q^2*t^6-3*t^6*q^4+t^8*q^4-t^10*q^6+q^6*t^12-q^8*t^12+q^10*t^16)*q^2*x3/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x1)+(t-1)*(t+1)*(-1-q^2+q^2*t^2+t^10*q^6)*q^2/((t*q-1)*(t*q+1)*(q^3*t^5+1)*(q^3*t^5-1)*x1*x3)+(t-1)*(t+1)*(1+q^4+2*q^2-3*q^2*t^2+t^4*q^6-q^4*t^4-3*q^6*t^6-t^6*q^4+t^8*q^4+2*t^8*q^6-t^10*q^6+t^14*q^8-t^14*q^10+q^10*t^16)*x1/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t-1)^2*(t+1)^2*(3*q^2+q^4+2+q^2*t^2-t^2+t^2*q^4-6*t^4*q^2+q^4*t^4-7*t^6*q^4+q^2*t^6+3*t^8*q^4-4*t^8*q^6+t^10*q^4+3*t^10*q^6-q^8*t^12-t^14*q^10+t^14*q^8+q^8*t^16+q^10*t^18)*q*x1/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(-q^2-2-q^2*t^2-q^4*t^4+2*t^6*q^4+t^10*q^6+q^6*t^12+t^14*q^8)*q*x2*x1/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t+1)*(t-1)*x2^2*x1/((t*q-1)*(t*q+1)*x3)+(t-1)^3*(t+1)^3*(1+t^2+t^4*q^2)*q*x3*x1^2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t-1)*(t+1)*q^3/((q^3*t^5+1)*(q^3*t^5-1)*x1*x2*x3)+(t-1)^2*(t+1)^2*(3+3*q^2+q^4+2*q^2*t^2-t^2+t^2*q^4-6*t^4*q^2+q^4*t^4-8*t^6*q^4+q^2*t^6+2*t^8*q^4-4*t^8*q^6+t^10*q^4+2*t^10*q^6-2*q^8*t^12-t^14*q^10+t^14*q^8+q^8*t^16+q^10*t^16+2*q^10*t^18)*q^2/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(-q^4-2*q^2-1-t^2*q^4-t^4*q^6+2*q^6*t^6+t^6*q^4+t^10*q^6+q^8*t^12+t^14*q^10)*q/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t-1)^2*(t+1)^2*(-1-q^2-q^2*t^2+t^2+t^4*q^2-q^4*t^4+2*t^6*q^4)*q*x3*x1/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)^2*(t+1)^2*x2*x1^2/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t-1)^2*(t+1)^2*x3*x1^2/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)^2*(t+1)^2*q^4/((t*q+1)*(t*q-1)*(q^3*t^5+1)*(q^3*t^5-1)*x1*x2)+(t-1)^2*(t+1)^2*(-q^2-1-q^2*t^2-q^4*t^4+t^6*q^4+t^10*q^6+q^8*t^12+t^14*q^10)*q*x3*x2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x1) - sage: to_SR(E[mu]) - expected # long time (20s) + sage: expected = (t-1)^2*(t+1)^2*(3*q^2+q^4+1+t^2*q^4+q^2*t^2-3*t^4*q^2-5*t^6*q^4+2*t^8*q^4-4*t^8*q^6-q^8*t^10+2*t^10*q^6-2*q^8*t^12+t^14*q^8-t^14*q^10+q^10*t^16+q^8*t^16+q^10*t^18+t^18*q^12)*x2*x1/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(q^2*t^6+2*t^6*q^4-q^4*t^4+t^4*q^2-q^2*t^2+t^2-2-q^2)*q^2*x1/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)^2*(t+1)^2*(-q^2-1+t^4*q^2-q^4*t^4+2*t^6*q^4)*x1^2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t+1)*(t-1)*x2^2*x3/((t*q-1)*(t*q+1)*x1)+(t-1)^2*(t+1)^2*(3*q^2+q^4+2+t^2*q^4+2*q^2*t^2-4*t^4*q^2+q^4*t^4-6*t^6*q^4+t^8*q^4-4*t^8*q^6-q^8*t^10+t^10*q^6-3*q^8*t^12-2*t^14*q^10+2*t^14*q^8+2*q^10*t^16+q^8*t^16+t^18*q^12+2*q^10*t^18)*q*x2/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(1+q^4+2*q^2+t^2*q^4-3*t^4*q^2+q^2*t^6-5*t^6*q^4+3*t^8*q^4-4*t^8*q^6+2*t^10*q^6-q^8*t^12-t^14*q^10+t^14*q^8+q^10*t^16+t^18*q^12)*x3*x1/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(2*q^2+1+q^4+t^2*q^4-t^2+q^2*t^2-4*t^4*q^2+q^4*t^4+q^2*t^6-5*t^6*q^4+3*t^8*q^4-4*t^8*q^6+2*t^10*q^6+q^6*t^12-2*q^8*t^12-2*t^14*q^10+2*t^14*q^8+q^10*t^16+t^18*q^12)*q*x3/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(1+t^2+t^4*q^2)*q*x3*x2^2/((t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1))+(t-1)^2*(t+1)^2*(-q^2-2-q^2*t^2+t^4-q^4*t^4-t^4*q^2+3*q^2*t^6-t^6*q^4-t^8*q^6+t^8*q^4+t^10*q^4+2*q^6*t^12-q^8*t^12+t^14*q^8)*q*x3*x2*x1/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t-1)*(t+1)*x1^2/((q^3*t^5-1)*(q^3*t^5+1)*x3*x2)+(t-1)*(t+1)*(-q^2-1+t^4*q^2-q^4*t^4+2*t^6*q^4)*x2^2/((t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1))+(t-1)*(t+1)*(t^3*q-1)*(t^3*q+1)*x3*x2^2*x1/((t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1))+(t-1)^2*(t+1)^2*(q^2+1)*q*x1/((t*q+1)*(t*q-1)*(q^3*t^5+1)*(q^3*t^5-1)*x3*x2)+(t-1)^2*(t+1)^2*(t^3*q-1)*(t^3*q+1)*x3*x2*x1^2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t-1)^2*(t+1)^2*q^3*x3/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x1*x2)+(t-1)*(t+1)*(-1-q^2+q^2*t^2+t^10*q^6)*q*x2/((t*q+1)*(t*q-1)*(q^3*t^5+1)*(q^3*t^5-1)*x3*x1)+x2^2/(x1*x3)+(t-1)*(t+1)*q*x2^2/((t*q-1)*(t*q+1)*x3)+(t-1)^3*(t+1)^3*(1+t^2+t^4*q^2)*q*x2*x1^2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t-1)^2*(t+1)^2*q*x1^2/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t-1)^2*(t+1)^2*(q^2*t^6+2*t^6*q^4-q^4*t^4+t^4*q^2-q^2*t^2+t^2-2-q^2)*q^3/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)*(t+1)*(q^2+2-t^2+q^4*t^4-t^4*q^2-3*t^6*q^4+t^8*q^4-2*t^10*q^6-q^8*t^12+q^6*t^12+q^8*t^16+q^10*t^16)*q^2*x2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x1)+(t-1)^2*(t+1)^2*(q^2+1)*q^2/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3*x2)+(t-1)*(t+1)*(1+q^4+2*q^2-2*q^2*t^2+t^4*q^6-q^4*t^4-3*q^6*t^6-t^6*q^4+2*t^8*q^6-t^10*q^6-q^8*t^10-t^14*q^10+t^14*q^8+2*q^10*t^16)*x2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t-1)^2*(t+1)^2*(-q^2-2-q^2*t^2-q^4*t^4+2*t^6*q^4+t^10*q^6+q^8*t^12+t^14*q^8)*q^3/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x1)+(t-1)^2*(t+1)^2*(-1-q^2-q^2*t^2+t^2+t^4*q^2-q^4*t^4+2*t^6*q^4)*q^2*x3/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)*(t+1)*q*x2^2/((t*q-1)*(t*q+1)*x1)+(t-1)^2*(t+1)^2*(1+t^2+t^4*q^2)*q*x2^2*x1/((t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1))+(t-1)^2*(t+1)^2*q*x1^2/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)^2*(t+1)^2*(-1-q^4-2*q^2-t^2*q^4-q^2*t^2+t^4*q^2-t^4*q^6-2*q^4*t^4+3*t^6*q^4-q^6*t^6-t^8*q^8+t^8*q^6+2*t^10*q^6-q^10*t^12+3*q^8*t^12+2*t^14*q^10)*x3*x2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t-1)*(t+1)*(q^2+1-t^2+q^4*t^4-t^4*q^2+q^2*t^6-3*t^6*q^4+t^8*q^4-t^10*q^6+q^6*t^12-q^8*t^12+q^10*t^16)*q^2*x3/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x1)+(t-1)*(t+1)*(-1-q^2+q^2*t^2+t^10*q^6)*q^2/((t*q-1)*(t*q+1)*(q^3*t^5+1)*(q^3*t^5-1)*x1*x3)+(t-1)*(t+1)*(1+q^4+2*q^2-3*q^2*t^2+t^4*q^6-q^4*t^4-3*q^6*t^6-t^6*q^4+t^8*q^4+2*t^8*q^6-t^10*q^6+t^14*q^8-t^14*q^10+q^10*t^16)*x1/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t-1)^2*(t+1)^2*(3*q^2+q^4+2+q^2*t^2-t^2+t^2*q^4-6*t^4*q^2+q^4*t^4-7*t^6*q^4+q^2*t^6+3*t^8*q^4-4*t^8*q^6+t^10*q^4+3*t^10*q^6-q^8*t^12-t^14*q^10+t^14*q^8+q^8*t^16+q^10*t^18)*q*x1/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(-q^2-2-q^2*t^2-q^4*t^4+2*t^6*q^4+t^10*q^6+q^6*t^12+t^14*q^8)*q*x2*x1/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t+1)*(t-1)*x2^2*x1/((t*q-1)*(t*q+1)*x3)+(t-1)^3*(t+1)^3*(1+t^2+t^4*q^2)*q*x3*x1^2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1))+(t-1)*(t+1)*q^3/((q^3*t^5+1)*(q^3*t^5-1)*x1*x2*x3)+(t-1)^2*(t+1)^2*(3+3*q^2+q^4+2*q^2*t^2-t^2+t^2*q^4-6*t^4*q^2+q^4*t^4-8*t^6*q^4+q^2*t^6+2*t^8*q^4-4*t^8*q^6+t^10*q^4+2*t^10*q^6-2*q^8*t^12-t^14*q^10+t^14*q^8+q^8*t^16+q^10*t^16+2*q^10*t^18)*q^2/((q^3*t^5+1)*(q^3*t^5-1)*(t*q-1)*(t*q+1)*(t^3*q^2+1)*(t^3*q^2-1)*(t^2*q-1)*(t^2*q+1))+(t-1)^2*(t+1)^2*(-q^4-2*q^2-1-t^2*q^4-t^4*q^6+2*q^6*t^6+t^6*q^4+t^10*q^6+q^8*t^12+t^14*q^10)*q/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t-1)^2*(t+1)^2*(-1-q^2-q^2*t^2+t^2+t^4*q^2-q^4*t^4+2*t^6*q^4)*q*x3*x1/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)^2*(t+1)^2*x2*x1^2/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x3)+(t-1)^2*(t+1)^2*x3*x1^2/((t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x2)+(t-1)^2*(t+1)^2*q^4/((t*q+1)*(t*q-1)*(q^3*t^5+1)*(q^3*t^5-1)*x1*x2)+(t-1)^2*(t+1)^2*(-q^2-1-q^2*t^2-q^4*t^4+t^6*q^4+t^10*q^6+q^8*t^12+t^14*q^10)*q*x3*x2/((t^3*q^2-1)*(t^3*q^2+1)*(t*q+1)*(t*q-1)*(q^3*t^5-1)*(q^3*t^5+1)*x1) # needs sage.symbolic + sage: to_SR(E[mu]) - expected # long time (20s) # needs sage.symbolic 0 - sage: E = NonSymmetricMacdonaldPolynomials(["BC",1,2], q=q, q1=t^2,q2=-1) - sage: omega=E.keys().fundamental_weights() + sage: E = NonSymmetricMacdonaldPolynomials(["BC",1,2], q=q, q1=t^2, q2=-1) + sage: omega = E.keys().fundamental_weights() sage: mu = -4*omega[1]; mu (-4) - sage: expected = (t-1)*(t+1)*(-1+q^2*t^2-q^2-3*q^10-7*q^26*t^8+5*t^2*q^6-q^16-3*q^4+4*t^10*q^30-4*t^6*q^22-10*q^20*t^6+2*q^32*t^10-3*q^6-4*q^8+q^34*t^10-4*t^8*q^24-2*q^12-q^14+2*q^22*t^10+4*q^26*t^10+4*q^28*t^10+t^6*q^30-2*q^32*t^8-2*t^8*q^22+2*q^24*t^10-q^20*t^2-2*t^6*q^12+t^8*q^14+2*t^4*q^24-4*t^8*q^30+2*t^8*q^20-9*t^6*q^16+3*q^26*t^6+q^28*t^6+3*t^2*q^4+2*q^18*t^8-6*t^6*q^14+4*t^4*q^22-2*q^24*t^6+3*t^2*q^12+7*t^4*q^20-t^2*q^16+11*q^18*t^4-2*t^2*q^18+9*q^16*t^4-t^4*q^6+6*q^8*t^2+5*q^10*t^2-6*q^28*t^8+q^12*t^4+8*t^4*q^14-10*t^6*q^18-q^4*t^4+q^16*t^8-2*t^4*q^8)/((t*q^4-1)*(t*q^4+1)*(q^7*t^2-1)*(q^7*t^2+1)*(t*q^3-1)*(t*q^3+1)*(q^5*t^2+1)*(q^5*t^2-1))+(q^2+1)*(q^4+1)*(t-1)*(t+1)*(-1+q^2*t^2-q^2+t^2*q^6-q^4+t^6*q^22+3*q^10*t^4+t^2-q^8-2*t^8*q^24+q^22*t^10+q^26*t^10-2*t^8*q^22+q^24*t^10-4*t^6*q^12-2*t^8*q^20-3*t^6*q^16+2*t^2*q^4-t^6*q^10-2*t^6*q^14+t^8*q^12-t^2*q^12+2*q^16*t^4+q^8*t^2-q^10*t^2+3*q^12*t^4+2*t^4*q^14+t^6*q^18-2*q^4*t^4+q^16*t^8+q^20*t^10)*q*x1/((t*q^4-1)*(t*q^4+1)*(q^7*t^2-1)*(q^7*t^2+1)*(t*q^3-1)*(t*q^3+1)*(q^5*t^2+1)*(q^5*t^2-1))+(q^2+1)*(q^4+1)*(t-1)*(t+1)*(1+q^8+q^4+q^2-q^8*t^2-2*t^2*q^4-t^2*q^6+t^2*q^12-t^2+t^4*q^6-2*q^16*t^4-t^4*q^14-2*q^12*t^4+t^6*q^12+t^6*q^16+t^6*q^18+t^6*q^14)*q/((t*q^4-1)*(t*q^4+1)*(q^7*t^2-1)*(q^7*t^2+1)*(t*q^3-1)*(t*q^3+1)*x1)+(t-1)*(t+1)*(-1-q^2-q^6-q^4-q^8+t^2*q^4-t^2*q^14+t^2*q^6-q^10*t^2+q^8*t^2-t^2*q^12+q^12*t^4+q^10*t^4+q^16*t^4+2*t^4*q^14)*(q^4+1)/((q^7*t^2+1)*(q^7*t^2-1)*(t*q^4-1)*(t*q^4+1)*x1^2)+(t-1)*(t+1)*(q^4+1)*(q^2+1)*q/((t*q^4-1)*(t*q^4+1)*x1^3)+(q^4+1)*(t-1)*(t+1)*(1+q^6+q^8+q^2+q^4-q^2*t^2-3*t^2*q^4+q^10*t^2+t^2*q^12-2*t^2*q^6-q^8*t^2-2*q^16*t^4+q^4*t^4+t^4*q^6-q^10*t^4-2*q^12*t^4-2*t^4*q^14+t^6*q^12+t^6*q^18+2*t^6*q^16+t^6*q^14)*x1^2/((t*q^4-1)*(t*q^4+1)*(q^7*t^2-1)*(q^7*t^2+1)*(t*q^3-1)*(t*q^3+1))+(t-1)*(t+1)*(-1-t^2*q^6+t^2+t^4*q^8)*(q^4+1)*(q^2+1)*q*x1^3/((q^7*t^2+1)*(q^7*t^2-1)*(t*q^4-1)*(t*q^4+1))+1/x1^4+(t-1)*(t+1)*x1^4/((t*q^4-1)*(t*q^4+1)) - sage: to_SR(E[mu]) - expected + sage: expected = (t-1)*(t+1)*(-1+q^2*t^2-q^2-3*q^10-7*q^26*t^8+5*t^2*q^6-q^16-3*q^4+4*t^10*q^30-4*t^6*q^22-10*q^20*t^6+2*q^32*t^10-3*q^6-4*q^8+q^34*t^10-4*t^8*q^24-2*q^12-q^14+2*q^22*t^10+4*q^26*t^10+4*q^28*t^10+t^6*q^30-2*q^32*t^8-2*t^8*q^22+2*q^24*t^10-q^20*t^2-2*t^6*q^12+t^8*q^14+2*t^4*q^24-4*t^8*q^30+2*t^8*q^20-9*t^6*q^16+3*q^26*t^6+q^28*t^6+3*t^2*q^4+2*q^18*t^8-6*t^6*q^14+4*t^4*q^22-2*q^24*t^6+3*t^2*q^12+7*t^4*q^20-t^2*q^16+11*q^18*t^4-2*t^2*q^18+9*q^16*t^4-t^4*q^6+6*q^8*t^2+5*q^10*t^2-6*q^28*t^8+q^12*t^4+8*t^4*q^14-10*t^6*q^18-q^4*t^4+q^16*t^8-2*t^4*q^8)/((t*q^4-1)*(t*q^4+1)*(q^7*t^2-1)*(q^7*t^2+1)*(t*q^3-1)*(t*q^3+1)*(q^5*t^2+1)*(q^5*t^2-1))+(q^2+1)*(q^4+1)*(t-1)*(t+1)*(-1+q^2*t^2-q^2+t^2*q^6-q^4+t^6*q^22+3*q^10*t^4+t^2-q^8-2*t^8*q^24+q^22*t^10+q^26*t^10-2*t^8*q^22+q^24*t^10-4*t^6*q^12-2*t^8*q^20-3*t^6*q^16+2*t^2*q^4-t^6*q^10-2*t^6*q^14+t^8*q^12-t^2*q^12+2*q^16*t^4+q^8*t^2-q^10*t^2+3*q^12*t^4+2*t^4*q^14+t^6*q^18-2*q^4*t^4+q^16*t^8+q^20*t^10)*q*x1/((t*q^4-1)*(t*q^4+1)*(q^7*t^2-1)*(q^7*t^2+1)*(t*q^3-1)*(t*q^3+1)*(q^5*t^2+1)*(q^5*t^2-1))+(q^2+1)*(q^4+1)*(t-1)*(t+1)*(1+q^8+q^4+q^2-q^8*t^2-2*t^2*q^4-t^2*q^6+t^2*q^12-t^2+t^4*q^6-2*q^16*t^4-t^4*q^14-2*q^12*t^4+t^6*q^12+t^6*q^16+t^6*q^18+t^6*q^14)*q/((t*q^4-1)*(t*q^4+1)*(q^7*t^2-1)*(q^7*t^2+1)*(t*q^3-1)*(t*q^3+1)*x1)+(t-1)*(t+1)*(-1-q^2-q^6-q^4-q^8+t^2*q^4-t^2*q^14+t^2*q^6-q^10*t^2+q^8*t^2-t^2*q^12+q^12*t^4+q^10*t^4+q^16*t^4+2*t^4*q^14)*(q^4+1)/((q^7*t^2+1)*(q^7*t^2-1)*(t*q^4-1)*(t*q^4+1)*x1^2)+(t-1)*(t+1)*(q^4+1)*(q^2+1)*q/((t*q^4-1)*(t*q^4+1)*x1^3)+(q^4+1)*(t-1)*(t+1)*(1+q^6+q^8+q^2+q^4-q^2*t^2-3*t^2*q^4+q^10*t^2+t^2*q^12-2*t^2*q^6-q^8*t^2-2*q^16*t^4+q^4*t^4+t^4*q^6-q^10*t^4-2*q^12*t^4-2*t^4*q^14+t^6*q^12+t^6*q^18+2*t^6*q^16+t^6*q^14)*x1^2/((t*q^4-1)*(t*q^4+1)*(q^7*t^2-1)*(q^7*t^2+1)*(t*q^3-1)*(t*q^3+1))+(t-1)*(t+1)*(-1-t^2*q^6+t^2+t^4*q^8)*(q^4+1)*(q^2+1)*q*x1^3/((q^7*t^2+1)*(q^7*t^2-1)*(t*q^4-1)*(t*q^4+1))+1/x1^4+(t-1)*(t+1)*x1^4/((t*q^4-1)*(t*q^4+1)) # needs sage.symbolic + sage: to_SR(E[mu]) - expected # needs sage.symbolic 0 Type `BC` dual, comparison with hand calculations by Bogdan Ion:: @@ -1128,7 +1234,8 @@ class NonSymmetricMacdonaldPolynomials(CherednikOperatorsEigenvectors): B[(0, 0)] sage: E[omega[1]] ((-q^2*q1^3*q2-q^2*q1^2*q2^2)/(q^2*q1^4-q2^4))*B[(0, 0)] + B[(1, 0)] - sage: Eomega1 = KL.one() * (q^2*(-q1/q2)^2*(1-(-q1/q2))) / (1-q^2*(-q1/q2)^4) + KL.monomial(omega[1]) + sage: Eomega1 = (KL.one() * (q^2*(-q1/q2)^2*(1-(-q1/q2))) / (1-q^2*(-q1/q2)^4) + ....: + KL.monomial(omega[1])) sage: E[omega[1]] == Eomega1 True @@ -1419,6 +1526,7 @@ def Q_to_Qcheck(self): alphacheck[1] + 2*alphacheck[2] sage: _.parent() Coroot lattice of the Root system of type ['C', 2, 1] + """ #assert self.cartan_type().is_untwisted_affine() Qcheck = self._T_Y.Y().keys() @@ -1436,12 +1544,10 @@ def Y(self): Lazy family (<lambda>(i))_{i in Root lattice of the Root system of type ['B', 2, 1]} sage: _.keys().classical() Root lattice of the Root system of type ['B', 2] - sage: NonSymmetricMacdonaldPolynomials("C2~*").Y() Lazy family (<...Y_lambdacheck...>(i))_{i in Coroot lattice of the Root system of type ['C', 2, 1]^*} sage: _.keys().classical() Root lattice of the Root system of type ['C', 2] - sage: NonSymmetricMacdonaldPolynomials(["BC", 3, 2]).Y() Lazy family (<...Y_lambdacheck...>(i))_{i in Coroot lattice of the Root system of type ['BC', 3, 2]} sage: _.keys().classical() @@ -1505,8 +1611,10 @@ def twist(self, mu, i): EXAMPLES:: + sage: # needs sage.libs.gap sage: W = WeylGroup(["B",3]) - sage: W.element_class._repr_=lambda x: "".join(str(i) for i in x.reduced_word()) + sage: W.element_class._repr_ = lambda x: "".join(str(i) + ....: for i in x.reduced_word()) sage: K = QQ['q1,q2'] sage: q1, q2 = K.gens() sage: KW = W.algebra(K) @@ -1574,9 +1682,12 @@ def __getitem__(self, mu): sage: E[omega[2]] Traceback (most recent call last): ... - ValueError: 1/2*e[0] + 1/2*e[1] does not lift to a level 0 element of the affine weight lattice + ValueError: 1/2*e[0] + 1/2*e[1] does not lift to a level 0 element + of the affine weight lattice sage: E[2*omega[2]] - ((q^2*q1^2+q^2*q1*q2)/(q^2*q1^2-q2^2))*B[(0, 0)] + ((-q^2*q1^2-q^2*q1*q2)/(-q^2*q1^2+q2^2))*B[(1, 0)] + B[(1, 1)] + ((-q^2*q1^2-q^2*q1*q2)/(-q^2*q1^2+q2^2))*B[(0, 1)] + ((q^2*q1^2+q^2*q1*q2)/(q^2*q1^2-q2^2))*B[(0, 0)] + + ((-q^2*q1^2-q^2*q1*q2)/(-q^2*q1^2+q2^2))*B[(1, 0)] + B[(1, 1)] + + ((-q^2*q1^2-q^2*q1*q2)/(-q^2*q1^2+q2^2))*B[(0, 1)] """ muaff = self._L.embed_at_level(mu, 0) if not all(muaff.scalar(coroot) in ZZ for coroot in self._L.simple_coroots()): @@ -1594,14 +1705,14 @@ def rho_prime(self): # Should be rho_prime_check Untwisted case:: - sage: NonSymmetricMacdonaldPolynomials("B2~").rho_prime() # CHECKME + sage: NonSymmetricMacdonaldPolynomials("B2~").rho_prime() # CHECKME 3/2*e[0] + 1/2*e[1] sage: NonSymmetricMacdonaldPolynomials("B2~").rho_prime().parent() Coambient space of the Root system of type ['C', 2, 1] Twisted case:: - sage: NonSymmetricMacdonaldPolynomials("B2~*").rho_prime() # CHECKME + sage: NonSymmetricMacdonaldPolynomials("B2~*").rho_prime() # CHECKME 2*e[0] + e[1] sage: NonSymmetricMacdonaldPolynomials("B2~*").rho_prime().parent() Ambient space of the Root system of type ['B', 2, 1]^* @@ -1640,7 +1751,7 @@ def eigenvalue_experimental(self, mu, l): sage: KL = RootSystem(["A",1,1]).ambient_space().algebra(K) sage: E = NonSymmetricMacdonaldPolynomials(KL,q, q1, q2) sage: L0 = E.keys() - sage: E.eigenvalues(L0([0,0])) # Checked by hand by Mark and Arun + sage: E.eigenvalues(L0([0,0])) # Checked by hand by Mark and Arun [1/(q*t), t] sage: alpha = E.Y().keys().simple_roots() sage: E.eigenvalue_experimental(L0([0,0]), alpha[0]) # todo: not implemented @@ -1676,13 +1787,15 @@ def eigenvalue_experimental(self, mu, l): sage: E = NonSymmetricMacdonaldPolynomials(KL,q, q1, q2) sage: L0 = E.keys() sage: alpha = L.simple_coroots() - sage: E.eigenvalue(L0((0,0)), alpha[0]) # not checked # not tested + + sage: # not tested + sage: E.eigenvalue(L0((0,0)), alpha[0]) # not checked q/t - sage: E.eigenvalue(L0((1,0)), alpha[1]) # What Mark got by hand # not tested + sage: E.eigenvalue(L0((1,0)), alpha[1]) # What Mark got by hand q - sage: E.eigenvalue(L0((1,0)), alpha[2]) # not checked # not tested + sage: E.eigenvalue(L0((1,0)), alpha[2]) # not checked t - sage: E.eigenvalue(L0((1,0)), alpha[0]) # not checked # not tested + sage: E.eigenvalue(L0((1,0)), alpha[0]) # not checked 1 sage: L = RootSystem("B2~*").ambient_space() @@ -1770,18 +1883,26 @@ def symmetric_macdonald_polynomial(self, mu): sage: E.symmetric_macdonald_polynomial(om[2]) B[(1, 1, 0)] + B[(1, 0, 1)] + B[(0, 1, 1)] sage: E.symmetric_macdonald_polynomial(2*om[1]) - ((q*v^2+v^2-q-1)/(q*v^2-1))*B[(1, 1, 0)] + ((q*v^2+v^2-q-1)/(q*v^2-1))*B[(1, 0, 1)] + B[(2, 0, 0)] + ((q*v^2+v^2-q-1)/(q*v^2-1))*B[(0, 1, 1)] + B[(0, 2, 0)] + B[(0, 0, 2)] + ((q*v^2+v^2-q-1)/(q*v^2-1))*B[(1, 1, 0)] + + ((q*v^2+v^2-q-1)/(q*v^2-1))*B[(1, 0, 1)] + B[(2, 0, 0)] + + ((q*v^2+v^2-q-1)/(q*v^2-1))*B[(0, 1, 1)] + B[(0, 2, 0)] + B[(0, 0, 2)] sage: f = E.symmetric_macdonald_polynomial(E.L0()((2,1,0))); f - ((2*q*v^4+v^4-q*v^2+v^2-q-2)/(q*v^4-1))*B[(1, 1, 1)] + B[(1, 2, 0)] + B[(1, 0, 2)] + B[(2, 1, 0)] + B[(2, 0, 1)] + B[(0, 1, 2)] + B[(0, 2, 1)] + ((2*q*v^4+v^4-q*v^2+v^2-q-2)/(q*v^4-1))*B[(1, 1, 1)] + B[(1, 2, 0)] + + B[(1, 0, 2)] + B[(2, 1, 0)] + B[(2, 0, 1)] + B[(0, 1, 2)] + B[(0, 2, 1)] We compare with the type `A` Macdonald polynomials coming from symmetric functions:: + sage: # needs sage.combinat sage: P = SymmetricFunctions(K).macdonald().P() sage: g = P[2,1].expand(3); g - x0^2*x1 + x0*x1^2 + x0^2*x2 + (2*q*t^2 - q*t - q + t^2 + t - 2)/(q*t^2 - 1)*x0*x1*x2 + x1^2*x2 + x0*x2^2 + x1*x2^2 + x0^2*x1 + x0*x1^2 + x0^2*x2 + + (2*q*t^2 - q*t - q + t^2 + t - 2)/(q*t^2 - 1)*x0*x1*x2 + + x1^2*x2 + x0*x2^2 + x1*x2^2 sage: fe = f.expand(g.parent().gens()); fe - x0^2*x1 + x0*x1^2 + x0^2*x2 + (2*q*v^4 - q*v^2 - q + v^4 + v^2 - 2)/(q*v^4 - 1)*x0*x1*x2 + x1^2*x2 + x0*x2^2 + x1*x2^2 + x0^2*x1 + x0*x1^2 + x0^2*x2 + + (2*q*v^4 - q*v^2 - q + v^4 + v^2 - 2)/(q*v^4 - 1)*x0*x1*x2 + + x1^2*x2 + x0*x2^2 + x1*x2^2 sage: g.map_coefficients(lambda x: x.subs(t=v*v)) == fe True diff --git a/src/sage/combinat/root_system/pieri_factors.py b/src/sage/combinat/root_system/pieri_factors.py index 106b5e0efd8..d2627a36413 100644 --- a/src/sage/combinat/root_system/pieri_factors.py +++ b/src/sage/combinat/root_system/pieri_factors.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.gap r""" Pieri Factors """ @@ -13,6 +14,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.constant_function import ConstantFunction from sage.misc.call import attrcall +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.structure.parent import Parent @@ -24,9 +26,10 @@ import sage.combinat.ranker from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from sage.combinat.root_system.root_system import RootSystem -from sage.combinat.root_system.dynkin_diagram import DynkinDiagram from sage.combinat.root_system.weyl_group import WeylGroup -from sage.graphs.digraph import DiGraph + +lazy_import('sage.graphs.digraph', 'DiGraph') +lazy_import('sage.combinat.root_system.dynkin_diagram', 'DynkinDiagram') class PieriFactors(UniqueRepresentation, Parent): @@ -175,7 +178,7 @@ def __iter__(self): """ return iter(self.elements()) - def generating_series(self, weight = None): + def generating_series(self, weight=None): r""" Return a length generating series for the elements of ``self``. @@ -731,7 +734,7 @@ def __getitem__(self, support): """ index_set = sorted(self.W.index_set()) - support = sorted(support) + support = sorted(support) if not set(support).issubset(set(index_set)) or support == index_set: raise ValueError("the support must be a proper subset of the index set") if not support: @@ -752,10 +755,10 @@ def cardinality(self): sage: WeylGroup(["A", 3, 1]).pieri_factors().cardinality() 15 """ - if self._min_length == len(self._min_support) and self._max_length == len(self._max_support) -1: + if self._min_length == len(self._min_support) and self._max_length == len(self._max_support) - 1: return Integer(2**(len(self._extra_support)) - 1) else: - return self.generating_series(weight = ConstantFunction(1)) + return self.generating_series(weight=ConstantFunction(1)) def generating_series(self, weight=None): r""" diff --git a/src/sage/combinat/root_system/plot.py b/src/sage/combinat/root_system/plot.py index ce3cce65ef4..34c178cef8f 100644 --- a/src/sage/combinat/root_system/plot.py +++ b/src/sage/combinat/root_system/plot.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.plot sage.symbolic r""" Tutorial: visualizing root systems @@ -5,7 +6,7 @@ space, and form the fundamental combinatorial data underlying Coxeter and Weyl groups, Lie algebras and groups, etc. The theory can be a bit intimidating at first because of the many technical gadgets (roots, -coroots, weights, ...). Vizualizing them goes a long way toward +coroots, weights, ...). Visualizing them goes a long way toward building a geometric intuition. This tutorial starts from simple plots and guides you all the way to @@ -149,7 +150,8 @@ sage: L = RootSystem(["E",8]).ambient_space() sage: L.dimension() 8 - sage: L.plot(roots="all", reflection_hyperplanes=False, projection=lambda v: M*vector(v), labels=False) # long time + sage: L.plot(roots="all", reflection_hyperplanes=False, # long time + ....: projection=lambda v: M*vector(v), labels=False) Graphics3d Object .. PLOT:: @@ -184,7 +186,8 @@ elements of the Weyl group. We enlarge a bit the bounding box to make sure everything fits in the picture:: - sage: RootSystem(["G",2]).ambient_space().plot(alcoves=True, alcove_labels=True, bounding_box=5) + sage: RootSystem(["G",2]).ambient_space().plot(alcoves=True, + ....: alcove_labels=True, bounding_box=5) Graphics object consisting of 37 graphics primitives .. PLOT:: @@ -213,7 +216,7 @@ We now draw the usual alcove picture for affine type `A_2^{(1)}`:: sage: L = RootSystem(["A",2,1]).ambient_space() - sage: L.plot() # long time + sage: L.plot() # long time Graphics object consisting of 160 graphics primitives .. PLOT:: @@ -231,7 +234,7 @@ we are visualizing here what's happening at level `1`. Here is the full picture in 3D:: - sage: L.plot(bounding_box=[[-3,3],[-3,3],[-1,1]], affine=False) # long time + sage: L.plot(bounding_box=[[-3,3],[-3,3],[-1,1]], affine=False) # long time Graphics3d Object .. PLOT:: @@ -246,7 +249,7 @@ It's usually more readable to only draw the intersection of the reflection hyperplanes with the level `1` hyperplane:: - sage: L.plot(affine=False, level=1) # long time + sage: L.plot(affine=False, level=1) # long time Graphics3d Object .. PLOT:: @@ -289,7 +292,7 @@ `u = vs_i`; the color of that wall is given by `i`:: sage: L = RootSystem(["C",2,1]).ambient_space() - sage: L.plot(coroots="simple", alcove_labels=True) # long time + sage: L.plot(coroots="simple", alcove_labels=True) # long time Graphics object consisting of 216 graphics primitives .. PLOT:: @@ -346,11 +349,12 @@ sage: positive_coroots = RecursivelyEnumeratedSet(seed, succ, structure='graded') sage: it = iter(positive_coroots) sage: first_positive_coroots = [next(it) for i in range(20)] - sage: p = L.plot(fundamental_chamber=True, reflection_hyperplanes=first_positive_coroots, + sage: p = L.plot(fundamental_chamber=True, + ....: reflection_hyperplanes=first_positive_coroots, ....: affine=False, alcove_labels=1, ....: bounding_box=[[-9,9],[-1,2]], ....: projection=lambda x: matrix([[1,-1],[1,1]])*vector(x)) - sage: p.show(figsize=20) # long time + sage: p.show(figsize=20) # long time Higher dimension affine pictures @@ -360,7 +364,7 @@ tiled by the alcoves, each of which is a 3D simplex:: sage: L = RootSystem(["A",3,1]).ambient_space() - sage: L.plot(reflection_hyperplanes=False, bounding_box=85/100) # long time + sage: L.plot(reflection_hyperplanes=False, bounding_box=85/100) # long time Graphics3d Object .. PLOT:: @@ -409,7 +413,8 @@ sage: L = RootSystem(["B",3,1]).ambient_space() sage: W = L.weyl_group() - sage: alcoves = [~w for d in range(12) for w in W.affine_grassmannian_elements_of_given_length(d)] + sage: alcoves = [~w for d in range(12) + ....: for w in W.affine_grassmannian_elements_of_given_length(d)] sage: p = L.plot_fundamental_chamber("classical") sage: p += L.plot_alcoves(alcoves=alcoves, wireframe=True) sage: p += L.plot_fundamental_weights() @@ -448,7 +453,7 @@ sage: L = RootSystem(["A",2,1]).ambient_space() sage: w1 = [0,2,1,2,0,2,1,0,2,1,2,1,2,0,2,0,1,2,0] - sage: L.plot(alcove_walk=w1, bounding_box=6) # long time + sage: L.plot(alcove_walk=w1, bounding_box=6) # long time Graphics object consisting of 535 graphics primitives .. PLOT:: @@ -498,12 +503,15 @@ :meth:`~sage.combinat.root_system.root_lattice_realizations.RootLatticeRealizations.ParentMethods.plot_parse_options`, and pass it down to each piece. We use this to plot our two walks:: + sage: # long time sage: plot_options = L.plot_parse_options(bounding_box=[[-2,5],[-2,6]]) sage: w2 = [2,1,2,0,2,0,2,1,2,0,1,2,1,2,1,0,1,2,0,2,0,1,2,0,2] - sage: p = L.plot_alcoves(plot_options=plot_options) # long time - sage: p += L.plot_alcove_walk(w1, color="green", plot_options=plot_options) # long time - sage: p += L.plot_alcove_walk(w2, color="orange", plot_options=plot_options) # long time - sage: p # long time + sage: p = L.plot_alcoves(plot_options=plot_options) + sage: p += L.plot_alcove_walk(w1, color="green", + ....: plot_options=plot_options) + sage: p += L.plot_alcove_walk(w2, color="orange", + ....: plot_options=plot_options) + sage: p Graphics object consisting of ... graphics primitives .. PLOT:: @@ -520,7 +528,8 @@ And another with some foldings:: sage: p += L.plot_alcove_walk([0,1,2,0,2,0,1,2,0,1], - ....: foldings=[False, False, True, False, False, False, True, False, True, False], + ....: foldings=[False, False, True, False, False, + ....: False, True, False, True, False], ....: color="purple") sage: p.axes(False) sage: p.show(figsize=20) @@ -544,18 +553,20 @@ Here we show a weight at level `0` and the reduced word implementing the translation by this weight:: + sage: # long time sage: L = RootSystem(["A",2,1]).ambient_space() sage: P = RootSystem(["A",2,1]).weight_space(extended=True) sage: Lambda = P.fundamental_weights() sage: t = 6*Lambda[1] - 2*Lambda[2] - 4*Lambda[0] sage: walk = L.reduced_word_of_translation(L(t)) sage: plot_options = L.plot_parse_options(bounding_box=[[-2,5],[-2,5]]) - sage: p = L.plot(plot_options=plot_options) # long time - sage: p += L.plot_alcove_walk(walk, color="green", plot_options=plot_options) # long time - sage: p += plot_options.family_of_vectors({t: L(t)}) # long time - sage: plot_options.finalize(p) # long time + sage: p = L.plot(plot_options=plot_options) + sage: p += L.plot_alcove_walk(walk, color="green", + ....: plot_options=plot_options) + sage: p += plot_options.family_of_vectors({t: L(t)}) + sage: plot_options.finalize(p) Graphics object consisting of ... graphics primitives - sage: p # long time + sage: p Graphics object consisting of ... graphics primitives .. PLOT:: @@ -583,7 +594,8 @@ sage: L = RootSystem(["B",3,1]).ambient_space() sage: w3 = [0,2,1,3,2,0,2,1,0,2,3,1,2,1,3,2,0,2,0,1,2,0] - sage: L.plot_fundamental_weights() + L.plot_reflection_hyperplanes(bounding_box=2) + L.plot_alcove_walk(w3) + sage: (L.plot_fundamental_weights() + ....: + L.plot_reflection_hyperplanes(bounding_box=2) + L.plot_alcove_walk(w3)) Graphics3d Object .. PLOT:: @@ -610,7 +622,8 @@ sage: L = RootSystem(["A",3,1]).ambient_space() sage: alcoves = cartesian_product([[0,1],[0,1],[0,1]]) sage: color = lambda i: "black" if i==0 else None - sage: L.plot_alcoves(alcoves=alcoves, color=color, bounding_box=10,wireframe=True).show(frame=False) # long time + sage: L.plot_alcoves(alcoves=alcoves, color=color, # long time + ....: bounding_box=10, wireframe=True).show(frame=False) .. PLOT:: :width: 300 px @@ -635,8 +648,9 @@ Now you can create your own customized color Coxeter graph paper:: sage: L = RootSystem(["C",2,1]).ambient_space() - sage: p = L.plot(bounding_box=[[-8,9],[-5,7]], coroots="simple") # long time (10 s) - sage: p # long time + sage: p = L.plot(bounding_box=[[-8,9],[-5,7]], # long time (10 s) + ....: coroots="simple") + sage: p # long time Graphics object consisting of ... graphics primitives .. PLOT:: @@ -649,7 +663,7 @@ if printed on paper. Instead, we recommend saving the picture in postscript or svg before printing it:: - sage: p.save("C21paper.eps") # not tested + sage: p.save("C21paper.eps") # not tested .. NOTE:: @@ -677,7 +691,7 @@ sage: g = W.cayley_graph(side="right") sage: positions = {w: plot_options.projection(w.action(rho)) for w in W} sage: p = L.plot_alcoves() - sage: p += g.plot(pos = positions, vertex_size=0, + sage: p += g.plot(pos=positions, vertex_size=0, ....: color_by_label=plot_options.color) sage: p.axes(False) sage: p @@ -781,7 +795,7 @@ sage: L = C.weight_lattice_realization() sage: plot_options = L.plot_parse_options() sage: g = C.digraph() - sage: positions = {x:plot_options.projection(x.weight()) for x in C} + sage: positions = {x: plot_options.projection(x.weight()) for x in C} sage: p = L.plot(reflection_hyperplanes=False, fundamental_weights=False) sage: p += g.plot3d(pos3d=positions, vertex_labels=True, ....: color_by_label=plot_options.color, edge_labels=True) @@ -847,7 +861,8 @@ def __init__(self, space, 2 sage: options._projections [Weight space over the Rational Field of the Root system of type ['B', 2], - <bound method RootLatticeRealizations.ParentMethods._plot_projection of Weight space over the Rational Field of the Root system of type ['B', 2]>] + <bound method RootLatticeRealizations.ParentMethods._plot_projection + of Weight space over the Rational Field of the Root system of type ['B', 2]>] sage: L = RootSystem(['B',2,1]).ambient_space() sage: options = L.plot_parse_options() @@ -855,24 +870,29 @@ def __init__(self, space, 2 sage: options._projections [Ambient space of the Root system of type ['B', 2], - <bound method RootLatticeRealizations.ParentMethods._plot_projection of Ambient space of the Root system of type ['B', 2]>] + <bound method RootLatticeRealizations.ParentMethods._plot_projection + of Ambient space of the Root system of type ['B', 2]>] sage: options = L.plot_parse_options(affine=True) sage: options.dimension 2 sage: options._projections [Ambient space of the Root system of type ['B', 2], - <bound method RootLatticeRealizations.ParentMethods._plot_projection of Ambient space of the Root system of type ['B', 2]>] + <bound method RootLatticeRealizations.ParentMethods._plot_projection + of Ambient space of the Root system of type ['B', 2]>] sage: options = L.plot_parse_options(affine=False) sage: options._projections - [<bound method AmbientSpace._plot_projection of Ambient space of the Root system of type ['B', 2, 1]>] + [<bound method AmbientSpace._plot_projection + of Ambient space of the Root system of type ['B', 2, 1]>] sage: options.dimension 3 - sage: options = L.plot_parse_options(affine=False, projection='barycentric') + sage: options = L.plot_parse_options(affine=False, + ....: projection='barycentric') sage: options._projections - [<bound method RootLatticeRealizations.ParentMethods._plot_projection_barycentric of Ambient space of the Root system of type ['B', 2, 1]>] + [<bound method RootLatticeRealizations.ParentMethods._plot_projection_barycentric + of Ambient space of the Root system of type ['B', 2, 1]>] sage: options.dimension 3 """ @@ -891,10 +911,10 @@ def __init__(self, space, level = 1 if not space.cartan_type().is_affine(): raise ValueError("affine option only valid for affine types") - projections=[space.classical()] + projections = [space.classical()] projection_space = space.classical() else: - projections=[] + projections = [] projection_space = space self.affine = affine @@ -916,15 +936,15 @@ def __init__(self, space, # Bounding box from sage.rings.real_mpfr import RR - from sage.geometry.polyhedron.all import Polyhedron + from sage.geometry.polyhedron.constructor import Polyhedron from itertools import product if bounding_box in RR: bounding_box = [[-bounding_box,bounding_box]] * self.dimension else: if not len(bounding_box) == self.dimension: raise TypeError("bounding_box argument doesn't match with the plot dimension") - elif not all(len(b)==2 for b in bounding_box): - raise TypeError("Invalid bounding box %s"%bounding_box) + elif not all(len(b) == 2 for b in bounding_box): + raise TypeError("Invalid bounding box %s" % bounding_box) self.bounding_box = Polyhedron(vertices=product(*bounding_box)) @cached_method @@ -975,7 +995,7 @@ def text(self, label, position, rgbcolor=(0,0,0)): sage: list(options.text(L.simple_root(2), [1,0], rgbcolor=(1,0.5,0))) [Text '$\alpha_{2}$' at the point (1.0,0.0)] - sage: options = RootSystem(["A",2]).root_lattice().plot_parse_options(labels=False) + sage: options = L.plot_parse_options(labels=False) sage: options.text("coucou", [0,1]) 0 @@ -1278,7 +1298,8 @@ def family_of_vectors(self, vectors): Handling of colors and labels:: - sage: color=lambda i: "purple" if i==1 else None + sage: def color(i): + ....: return "purple" if i==1 else None sage: options = L.plot_parse_options(labels=False, color=color) sage: p = options.family_of_vectors(alpha) sage: list(p) @@ -1351,26 +1372,30 @@ def cone(self, rays=[], lines=[], color="black", thickness=1, alpha=1, wireframe sage: L = RootSystem(["A",2]).root_lattice() sage: options = L.plot_parse_options() sage: alpha = L.simple_roots() - sage: p = options.cone(rays=[alpha[1]], lines=[alpha[2]], color='green', label=2) - sage: p + sage: p = options.cone(rays=[alpha[1]], lines=[alpha[2]], + ....: color='green', label=2); p Graphics object consisting of 2 graphics primitives sage: list(p) [Polygon defined by 4 points, Text '$2$' at the point (3.15...,3.15...)] - sage: options.cone(rays=[alpha[1]], lines=[alpha[2]], color='green', label=2, as_polyhedron=True) + sage: options.cone(rays=[alpha[1]], lines=[alpha[2]], + ....: color='green', label=2, as_polyhedron=True) A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line An empty result, being outside of the bounding box:: - sage: options = L.plot_parse_options(labels=True, bounding_box=[[-10,-9]]*2) - sage: options.cone(rays=[alpha[1]], lines=[alpha[2]], color='green', label=2) + sage: options = L.plot_parse_options(labels=True, + ....: bounding_box=[[-10,-9]]*2) + sage: options.cone(rays=[alpha[1]], lines=[alpha[2]], + ....: color='green', label=2) 0 Test that the options are properly passed down:: sage: L = RootSystem(["A",2]).root_lattice() sage: options = L.plot_parse_options() - sage: p = options.cone(rays=[alpha[1]+alpha[2]], color='green', label=2, thickness=4, alpha=.5) + sage: p = options.cone(rays=[alpha[1] + alpha[2]], + ....: color='green', label=2, thickness=4, alpha=.5) sage: list(p) [Line defined by 2 points, Text '$2$' at the point (3.15...,3.15...)] sage: sorted(p[0].options().items()) @@ -1383,7 +1408,7 @@ def cone(self, rays=[], lines=[], color="black", thickness=1, alpha=1, wireframe """ if color is None: return self.empty() - from sage.geometry.polyhedron.all import Polyhedron + from sage.geometry.polyhedron.constructor import Polyhedron # TODO: we currently convert lines into rays, which simplify a # bit the calculation of the intersection. But it would be # nice to benefit from the new ``lines`` option of Polyhedra @@ -1393,8 +1418,8 @@ def cone(self, rays=[], lines=[], color="black", thickness=1, alpha=1, wireframe if self.level: old_rays = rays vertices = [self.intersection_at_level_1(ray) for ray in old_rays if ray.level() > 0] - rays = [ray for ray in old_rays if ray.level() == 0] - rays += [vertex - self.intersection_at_level_1(ray) for ray in old_rays if ray.level() < 0 for vertex in vertices] + rays = [ray for ray in old_rays if ray.level() == 0] + rays += [vertex - self.intersection_at_level_1(ray) for ray in old_rays if ray.level() < 0 for vertex in vertices] else: vertices = [] @@ -1404,20 +1429,20 @@ def cone(self, rays=[], lines=[], color="black", thickness=1, alpha=1, wireframe rays = [ ray for ray in rays if ray ] # Polyhedron does not accept yet zero rays # Build the polyhedron - p = Polyhedron(vertices=vertices, rays = rays) + p = Polyhedron(vertices=vertices, rays=rays) if as_polyhedron: return p # Compute the intersection with the bounding box q = p & self.bounding_box - if q.dim() >= 0 and p.dim() >= 0 and (draw_degenerate or p.dim()==q.dim()): + if q.dim() >= 0 and p.dim() >= 0 and (draw_degenerate or p.dim() == q.dim()): if wireframe: options = dict(point=False, line=dict(width=10), polygon=False) center = q.center() q = q.translation(-center).dilation(ZZ(95)/ZZ(100)).translation(center) else: options = dict(wireframe=False, line={"thickness":thickness}) - result = q.plot(color = color, alpha=alpha, **options) + result = q.plot(color=color, alpha=alpha, **options) if label is not None: # Put the label on the vertex having largest z, then y, then x coordinate. vertices = sorted([vector(v) for v in q.vertices()], @@ -1452,7 +1477,8 @@ def reflection_hyperplane(self, coroot, as_polyhedron=False): sage: L = RootSystem(["A",3,1]).ambient_space() sage: alphacheck = L.simple_coroots() sage: options = L.plot_parse_options() - sage: H = options.reflection_hyperplane(alphacheck[1], as_polyhedron=True); H + sage: H = options.reflection_hyperplane(alphacheck[1], + ....: as_polyhedron=True); H A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 2 lines sage: H.lines() (A line in the direction (0, 0, 1), A line in the direction (0, 1, 0)) @@ -1489,14 +1515,14 @@ def reflection_hyperplane(self, coroot, as_polyhedron=False): text_label = "H_%s$" % (str(label)) else: text_label = "$H_{%s}$" % (latex(label)) - return self.cone(lines = basis, color = self.color(label), label=text_label, + return self.cone(lines=basis, color=self.color(label), label=text_label, as_polyhedron=as_polyhedron) @cached_function def barycentric_projection_matrix(n, angle=0): r""" - Returns a family of `n+1` vectors evenly spaced in a real vector space of dimension `n` + Return a family of `n+1` vectors evenly spaced in a real vector space of dimension `n`. Those vectors are of norm `1`, the scalar product between any two vector is `1/n`, thus the distance between two tips is constant. diff --git a/src/sage/combinat/root_system/reflection_group_c.pyx b/src/sage/combinat/root_system/reflection_group_c.pyx index 49175591edc..247e9a62c02 100644 --- a/src/sage/combinat/root_system/reflection_group_c.pyx +++ b/src/sage/combinat/root_system/reflection_group_c.pyx @@ -90,7 +90,7 @@ cdef class Iterator(): # self.noncom = self.noncom_letters() cdef list succ(self, PermutationGroupElement u, int first): - cdef PermutationGroupElement u1, si + cdef PermutationGroupElement si cdef int i cdef list successors = [] cdef tuple S = self.S @@ -111,7 +111,7 @@ cdef class Iterator(): cdef list succ_words(self, PermutationGroupElement u, list word, int first): cdef PermutationGroupElement u1, si - cdef int i, j + cdef int i cdef list successors = [] cdef list word_new cdef tuple S = self.S @@ -126,7 +126,7 @@ cdef class Iterator(): u1._reduced_word = word_new successors.append((u1, word_new, i)) for i in range(first+1, self.n): - if u.perm[i] < self.N: + if u.perm[i] < N: si = <PermutationGroupElement>(S[i]) if self.test(u, si, i): u1 = <PermutationGroupElement>(_new_mul_(si,u)) @@ -150,18 +150,20 @@ cdef class Iterator(): """ EXAMPLES:: + sage: # optional - gap3 sage: from sage.combinat.root_system.reflection_group_c import Iterator - sage: W = ReflectionGroup(["B", 4]) # optional - gap3 - sage: N = W.number_of_reflections() # optional - gap3 - sage: I = Iterator(W, N) # optional - gap3 - sage: len(list(I)) == W.cardinality() # optional - gap3 + sage: W = ReflectionGroup(["B", 4]) + sage: N = W.number_of_reflections() + sage: I = Iterator(W, N) + sage: len(list(I)) == W.cardinality() True - sage: I = Iterator(W, N, "breadth", False) # optional - gap3 - sage: len(list(I)) == W.cardinality() # optional - gap3 + sage: # optional - gap3 + sage: I = Iterator(W, N, "breadth", False) + sage: len(list(I)) == W.cardinality() True - sage: I = Iterator(W, N, "parabolic") # optional - gap3 - sage: len(list(I)) == W.cardinality() # optional - gap3 + sage: I = Iterator(W, N, "parabolic") + sage: len(list(I)) == W.cardinality() True """ # the breadth search iterator is ~2x slower as it @@ -198,7 +200,6 @@ cdef class Iterator(): (2,8)(3,7)(4,6), (1,5)(2,6)(3,7)(4,8)] """ - cdef tuple node cdef list cur = [(self.S[0].parent().one(), -1)] cdef PermutationGroupElement u cdef int first @@ -235,7 +236,6 @@ cdef class Iterator(): [1, 0, 1] [0, 1, 0, 1] """ - cdef tuple node cdef list cur, word cdef PermutationGroupElement u @@ -276,7 +276,6 @@ cdef class Iterator(): (1,7)(3,5)(4,8), (1,5)(2,6)(3,7)(4,8)] """ - cdef tuple node cdef list cur = [(self.S[0].parent().one(), -1)] cdef PermutationGroupElement u cdef int first @@ -313,7 +312,6 @@ cdef class Iterator(): [0, 1, 0] [0, 1, 0, 1] """ - cdef tuple node cdef list cur, word cdef PermutationGroupElement u cdef int first @@ -357,7 +355,7 @@ cdef class Iterator(): (1,7)(3,5)(4,8), (1,7,5,3)(2,4,6,8)] """ - cdef int i,j + cdef int i cdef list coset_reps W = self.S[0].parent() diff --git a/src/sage/combinat/root_system/reflection_group_complex.py b/src/sage/combinat/root_system/reflection_group_complex.py index 626c7e2c2a8..03fde46bf8d 100644 --- a/src/sage/combinat/root_system/reflection_group_complex.py +++ b/src/sage/combinat/root_system/reflection_group_complex.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.gap r""" Finite complex reflection groups ---------------------------------- @@ -21,17 +22,18 @@ or with Shephard-Todd types:: - sage: ReflectionGroup((1,1,3)) # optional - gap3 + sage: # optional - gap3 + sage: ReflectionGroup((1,1,3)) Irreducible real reflection group of rank 2 and type A2 - sage: ReflectionGroup((2,1,3)) # optional - gap3 + sage: ReflectionGroup((2,1,3)) Irreducible real reflection group of rank 3 and type B3 - sage: ReflectionGroup((3,1,3)) # optional - gap3 + sage: ReflectionGroup((3,1,3)) Irreducible complex reflection group of rank 3 and type G(3,1,3) - sage: ReflectionGroup((4,2,3)) # optional - gap3 + sage: ReflectionGroup((4,2,3)) Irreducible complex reflection group of rank 3 and type G(4,2,3) - sage: ReflectionGroup(4) # optional - gap3 + sage: ReflectionGroup(4) Irreducible complex reflection group of rank 2 and type ST4 - sage: ReflectionGroup(31) # optional - gap3 + sage: ReflectionGroup(31) Irreducible complex reflection group of rank 4 and type ST31 Also reducible types are allowed using concatenation:: @@ -208,13 +210,12 @@ from sage.combinat.permutation import Permutation from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.matrix.all import Matrix, identity_matrix +from sage.matrix.constructor import Matrix +from sage.matrix.special import identity_matrix from sage.structure.element import is_Matrix from sage.interfaces.gap3 import gap3 -from sage.rings.universal_cyclotomic_field import E from sage.modules.free_module_element import vector from sage.combinat.root_system.cartan_matrix import CartanMatrix -from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField from sage.misc.sage_eval import sage_eval @@ -399,14 +400,15 @@ def index_set(self): EXAMPLES:: - sage: W = ReflectionGroup((1,1,4)) # optional - gap3 - sage: W.index_set() # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup((1,1,4)) + sage: W.index_set() (1, 2, 3) - sage: W = ReflectionGroup((1,1,4), index_set=[1,3,'asdf']) # optional - gap3 - sage: W.index_set() # optional - gap3 + sage: W = ReflectionGroup((1,1,4), index_set=[1,3,'asdf']) + sage: W.index_set() (1, 3, 'asdf') - sage: W = ReflectionGroup((1,1,4), index_set=('a', 'b', 'c')) # optional - gap3 - sage: W.index_set() # optional - gap3 + sage: W = ReflectionGroup((1,1,4), index_set=('a', 'b', 'c')) + sage: W.index_set() ('a', 'b', 'c') """ return self._index_set @@ -451,14 +453,15 @@ def hyperplane_index_set(self): EXAMPLES:: - sage: W = ReflectionGroup((1,1,4)) # optional - gap3 - sage: W.hyperplane_index_set() # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup((1,1,4)) + sage: W.hyperplane_index_set() (1, 2, 3, 4, 5, 6) - sage: W = ReflectionGroup((1,1,4), hyperplane_index_set=[1,3,'asdf',7,9,11]) # optional - gap3 - sage: W.hyperplane_index_set() # optional - gap3 + sage: W = ReflectionGroup((1,1,4), hyperplane_index_set=[1,3,'asdf',7,9,11]) + sage: W.hyperplane_index_set() (1, 3, 'asdf', 7, 9, 11) - sage: W = ReflectionGroup((1,1,4),hyperplane_index_set=('a','b','c','d','e','f')) # optional - gap3 - sage: W.hyperplane_index_set() # optional - gap3 + sage: W = ReflectionGroup((1,1,4),hyperplane_index_set=('a','b','c','d','e','f')) + sage: W.hyperplane_index_set() ('a', 'b', 'c', 'd', 'e', 'f') """ return self._hyperplane_index_set @@ -519,12 +522,13 @@ def distinguished_reflection(self, i): EXAMPLES:: - sage: W = ReflectionGroup((1,1,3)) # optional - gap3 - sage: W.distinguished_reflection(1) # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup((1,1,3)) + sage: W.distinguished_reflection(1) (1,4)(2,3)(5,6) - sage: W.distinguished_reflection(2) # optional - gap3 + sage: W.distinguished_reflection(2) (1,3)(2,5)(4,6) - sage: W.distinguished_reflection(3) # optional - gap3 + sage: W.distinguished_reflection(3) (1,5)(2,4)(3,6) sage: W = ReflectionGroup((3,1,1),hyperplane_index_set=['a']) # optional - gap3 @@ -533,7 +537,7 @@ def distinguished_reflection(self, i): sage: W = ReflectionGroup((1,1,3),(3,1,2)) # optional - gap3 sage: for i in range(W.number_of_reflection_hyperplanes()): # optional - gap3 - ....: W.distinguished_reflection(i+1) # optional - gap3 + ....: W.distinguished_reflection(i+1) (1,6)(2,5)(7,8) (1,5)(2,7)(6,8) (3,9,15)(4,10,16)(12,17,23)(14,18,24)(20,25,29)(21,22,26)(27,28,30) @@ -652,14 +656,15 @@ def reflection_index_set(self): EXAMPLES:: - sage: W = ReflectionGroup((1,1,4)) # optional - gap3 - sage: W.reflection_index_set() # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup((1,1,4)) + sage: W.reflection_index_set() (1, 2, 3, 4, 5, 6) - sage: W = ReflectionGroup((1,1,4), reflection_index_set=[1,3,'asdf',7,9,11]) # optional - gap3 - sage: W.reflection_index_set() # optional - gap3 + sage: W = ReflectionGroup((1,1,4), reflection_index_set=[1,3,'asdf',7,9,11]) + sage: W.reflection_index_set() (1, 3, 'asdf', 7, 9, 11) - sage: W = ReflectionGroup((1,1,4), reflection_index_set=('a','b','c','d','e','f')) # optional - gap3 - sage: W.reflection_index_set() # optional - gap3 + sage: W = ReflectionGroup((1,1,4), reflection_index_set=('a','b','c','d','e','f')) + sage: W.reflection_index_set() ('a', 'b', 'c', 'd', 'e', 'f') """ return self._reflection_index_set @@ -709,12 +714,13 @@ def reflection(self,i): EXAMPLES:: - sage: W = ReflectionGroup((1,1,3)) # optional - gap3 - sage: W.reflection(1) # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup((1,1,3)) + sage: W.reflection(1) (1,4)(2,3)(5,6) - sage: W.reflection(2) # optional - gap3 + sage: W.reflection(2) (1,3)(2,5)(4,6) - sage: W.reflection(3) # optional - gap3 + sage: W.reflection(3) (1,5)(2,4)(3,6) sage: W = ReflectionGroup((3,1,1),reflection_index_set=['a','b']) # optional - gap3 @@ -763,7 +769,7 @@ def discriminant(self): sage: W.discriminant() # optional - gap3 x0^6*x1^2 - 6*x0^5*x1^3 + 13*x0^4*x1^4 - 12*x0^3*x1^5 + 4*x0^2*x1^6 """ - from sage.rings.polynomial.all import PolynomialRing + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing n = self.rank() P = PolynomialRing(QQ, 'x', n) x = P.gens() @@ -1008,17 +1014,18 @@ def rank(self): EXAMPLES:: - sage: W = ReflectionGroup((1,1,3)) # optional - gap3 - sage: W.rank() # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup((1,1,3)) + sage: W.rank() 2 - sage: W = ReflectionGroup((2,1,3)) # optional - gap3 - sage: W.rank() # optional - gap3 + sage: W = ReflectionGroup((2,1,3)) + sage: W.rank() 3 - sage: W = ReflectionGroup((4,1,3)) # optional - gap3 - sage: W.rank() # optional - gap3 + sage: W = ReflectionGroup((4,1,3)) + sage: W.rank() 3 - sage: W = ReflectionGroup((4,2,3)) # optional - gap3 - sage: W.rank() # optional - gap3 + sage: W = ReflectionGroup((4,2,3)) + sage: W.rank() 3 """ return self._rank @@ -1135,7 +1142,7 @@ def reflection_eigenvalues_family(self): sage: W = ReflectionGroup((3,1,2)) # optional - gap3 sage: reflection_eigenvalues = W.reflection_eigenvalues_family() # optional - gap3 sage: for elt in sorted(reflection_eigenvalues.keys()): # optional - gap3 - ....: print('%s %s'%(elt, reflection_eigenvalues[elt])) # optional - gap3 + ....: print('%s %s'%(elt, reflection_eigenvalues[elt])) () [0, 0] (1,3,9)(2,4,10)(6,11,17)(8,12,18)(14,19,23)(15,16,20)(21,22,24) [1/3, 0] (1,3,9)(2,16,24)(4,20,21)(5,7,13)(6,12,23)(8,19,17)(10,15,22)(11,18,14) [1/3, 1/3] @@ -1149,7 +1156,7 @@ def reflection_eigenvalues_family(self): sage: W = ReflectionGroup(23) # optional - gap3 sage: reflection_eigenvalues = W.reflection_eigenvalues_family() # optional - gap3 sage: for elt in sorted(reflection_eigenvalues.keys()): # optional - gap3 - ....: print('%s %s'%(elt, reflection_eigenvalues[elt])) # optional - gap3 + ....: print('%s %s'%(elt, reflection_eigenvalues[elt])) () [0, 0, 0] (1,8,4)(2,21,3)(5,10,11)(6,18,17)(7,9,12)(13,14,15)(16,23,19)(20,25,26)(22,24,27)(28,29,30) [1/3, 2/3, 0] (1,16)(2,5)(4,7)(6,9)(8,10)(11,13)(12,14)(17,20)(19,22)(21,24)(23,25)(26,28)(27,29) [1/2, 0, 0] @@ -1182,7 +1189,7 @@ def reflection_eigenvalues(self, w, is_class_representative=False): sage: W = ReflectionGroup((1,1,3)) # optional - gap3 sage: for w in W: # optional - gap3 - ....: print('%s %s'%(w.reduced_word(), W.reflection_eigenvalues(w))) # optional - gap3 + ....: print('%s %s'%(w.reduced_word(), W.reflection_eigenvalues(w))) [] [0, 0] [2] [1/2, 0] [1] [1/2, 0] @@ -1228,12 +1235,13 @@ def simple_root(self, i): EXAMPLES:: - sage: W = ReflectionGroup(['A',3]) # optional - gap3 - sage: W.simple_root(1) # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(['A',3]) + sage: W.simple_root(1) (1, 0, 0) - sage: W.simple_root(2) # optional - gap3 + sage: W.simple_root(2) (0, 1, 0) - sage: W.simple_root(3) # optional - gap3 + sage: W.simple_root(3) (0, 0, 1) TESTS:: @@ -1415,20 +1423,20 @@ def fundamental_invariants(self): (x0^3 + x1^3, x0^3*x1^3) """ import re - from sage.rings.polynomial.all import PolynomialRing + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing if not self.is_irreducible(): return sum([W.fundamental_invariants() for W in self.irreducible_components() ],tuple()) I = [ str(p) for p in gap3('List(Invariants(%s),x->ApplyFunc(x,List([0..%s],i->Mvp(SPrint("x",i)))))' % (self._gap_group._name, self.rank()-1)) ] - P = PolynomialRing(QQ,['x%s'%i for i in range(self.rank())]) + P = PolynomialRing(QQ,['x%s' % i for i in range(self.rank())]) x = P.gens() for i in range(len(I)): I[i] = I[i].replace('^','**') I[i] = re.compile(r'E(\d\d*)').sub(r'E(\1)', I[i]) I[i] = re.compile(r'(\d)E\(').sub(r'\1*E(', I[i]) for j in range(len(x)): - I[i] = I[i].replace('x%s'%j,'*x[%s]'%j) + I[i] = I[i].replace('x%s' % j,'*x[%s]' % j) I[i] = I[i].replace("+*","+").replace("-*","-").replace("ER(5)","*(E(5)-E(5)**2-E(5)**3+E(5)**4)").lstrip("*") # sage_eval is used since eval kills the rational entries! I = [sage_eval(p, locals={'x': x}) for p in I] @@ -1554,7 +1562,7 @@ def cartan_matrix(self): if self.is_crystallographic(): from sage.combinat.root_system.cartan_matrix import CartanMatrix as CartanMat else: - from sage.matrix.all import Matrix as CartanMat + from sage.matrix.constructor import Matrix as CartanMat return CartanMat(self._gap_group.CartanMat().sage()) def invariant_form(self, brute_force=False): @@ -1586,13 +1594,14 @@ def invariant_form(self, brute_force=False): sage: all( F == S[i].matrix()*F*S[i].matrix().transpose() for i in W.index_set() ) # optional - gap3 True - sage: W = ReflectionGroup(['B',3]) # optional - gap3 - sage: F = W.invariant_form(); F # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(['B',3]) + sage: F = W.invariant_form(); F [ 1 -1 0] [-1 2 -1] [ 0 -1 2] - sage: w = W.an_element().to_matrix() # optional - gap3 - sage: w * F * w.transpose().conjugate() == F # optional - gap3 + sage: w = W.an_element().to_matrix() + sage: w * F * w.transpose().conjugate() == F True sage: S = W.simple_reflections() # optional - gap3 @@ -1633,10 +1642,10 @@ def invariant_form(self, brute_force=False): sage: tests = [['A',3],['B',3],['F',4],(4,2,2),4,7] # optional - gap3 sage: for ty in tests: # optional - gap3 - ....: W = ReflectionGroup(ty) # optional - gap3 - ....: A = W.invariant_form() # optional - gap3 - ....: B = W.invariant_form(brute_force=True) # optional - gap3 - ....: print("{} {}".format(ty, A == B/B[0,0])) # optional - gap3 + ....: W = ReflectionGroup(ty) + ....: A = W.invariant_form() + ....: B = W.invariant_form(brute_force=True) + ....: print("{} {}".format(ty, A == B/B[0,0])) ['A', 3] True ['B', 3] True ['F', 4] True @@ -1709,6 +1718,8 @@ def _invariant_form_brute_force(self): [1 0] [0 1] """ + from sage.rings.universal_cyclotomic_field import E + base_change = self.base_change_matrix() Delta = tuple(self.independent_roots()) basis_is_Delta = base_change.is_one() @@ -1736,7 +1747,7 @@ def invariant_value(i,j): coeffs = [] for i in self.index_set(): - coeff = 1-E(S[i].order()) + coeff = 1 - E(S[i].order()) if coeff in QQ: coeff = QQ(coeff) coeffs.append(coeff) @@ -1763,20 +1774,22 @@ def invariant_form_standardization(self): EXAMPLES:: - sage: W = ReflectionGroup((4,2,5)) # optional - gap3 - sage: I = W.invariant_form() # optional - gap3 - sage: A = W.invariant_form_standardization() # optional - gap3 - sage: A^2 == I # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup((4,2,5)) + sage: I = W.invariant_form() + sage: A = W.invariant_form_standardization() + sage: A^2 == I True TESTS:: - sage: W = ReflectionGroup(9) # optional - gap3 - sage: A = W.invariant_form_standardization() # optional - gap3 - sage: S = W.simple_reflections() # optional - gap3 - sage: Ainv = A.inverse() # optional - gap3 - sage: T = {i: Ainv * S[i] * A for i in W.index_set()} # optional - gap3 - sage: all(T[i] * T[i].conjugate_transpose() # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(9) + sage: A = W.invariant_form_standardization() + sage: S = W.simple_reflections() + sage: Ainv = A.inverse() + sage: T = {i: Ainv * S[i] * A for i in W.index_set()} + sage: all(T[i] * T[i].conjugate_transpose() ....: == 1 for i in W.index_set() ) True """ @@ -1905,14 +1918,15 @@ def coxeter_number(self, chi=None): EXAMPLES:: - sage: W = ReflectionGroup(["H",4]) # optional - gap3 - sage: W.coxeter_number() # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(["H",4]) + sage: W.coxeter_number() 30 - sage: all(W.coxeter_number(chi).is_integer() # optional - gap3 + sage: all(W.coxeter_number(chi).is_integer() ....: for chi in W.irreducible_characters()) True - sage: W = ReflectionGroup(14) # optional - gap3 - sage: W.coxeter_number() # optional - gap3 + sage: W = ReflectionGroup(14) + sage: W.coxeter_number() 24 """ if chi is None: @@ -1940,7 +1954,7 @@ def conjugacy_class_representative(self): sage: W = ReflectionGroup((1,1,3)) # optional - gap3 sage: for w in W: # optional - gap3 - ....: print('%s %s'%(w.reduced_word(), w.conjugacy_class_representative().reduced_word())) # optional - gap3 + ....: print('%s %s'%(w.reduced_word(), w.conjugacy_class_representative().reduced_word())) [] [] [2] [1] [1] [1] @@ -1952,7 +1966,7 @@ def conjugacy_class_representative(self): for w in W._conjugacy_classes: if self in W._conjugacy_classes[w]: return w - return W.conjugacy_classes_representatives()[ gap3("PositionClass(%s,%s)"%(W._gap_group._name,self)).sage()-1 ] + return W.conjugacy_classes_representatives()[ gap3("PositionClass(%s,%s)" % (W._gap_group._name,self)).sage()-1 ] def conjugacy_class(self): r""" @@ -2084,7 +2098,7 @@ def is_coxeter_element(self, which_primitive=1, is_class_representative=False): sage: W = ReflectionGroup((1,1,3)) # optional - gap3 sage: for w in W: # optional - gap3 - ....: print('%s %s'%(w.reduced_word(), w.is_coxeter_element())) # optional - gap3 + ....: print('%s %s'%(w.reduced_word(), w.is_coxeter_element())) [] False [2] False [1] False @@ -2112,7 +2126,7 @@ def is_h_regular(self, is_class_representative=False): sage: W = ReflectionGroup((1,1,3)) # optional - gap3 sage: for w in W: # optional - gap3 - ....: print('%s %s'%(w.reduced_word(), w.is_h_regular())) # optional - gap3 + ....: print('%s %s'%(w.reduced_word(), w.is_h_regular())) [] False [2] False [1] False @@ -2156,8 +2170,8 @@ def is_regular(self, h, is_class_representative=False): sage: W = ReflectionGroup(23); h = W.coxeter_number() # optional - gap3 sage: for w in W: # optional - gap3 - ....: if w.is_regular(h): # optional - gap3 - ....: w.reduced_word() # optional - gap3 + ....: if w.is_regular(h): + ....: w.reduced_word() [1, 2, 3] [2, 1, 3] [1, 3, 2] @@ -2185,14 +2199,17 @@ def is_regular(self, h, is_class_representative=False): Check that :trac:`25478` is fixed:: - sage: W = ReflectionGroup(["A",5]) # optional - gap3 - sage: w = W.from_reduced_word([1,2,3,5]) # optional - gap3 - sage: w.is_regular(4) # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(["A",5]) + sage: w = W.from_reduced_word([1,2,3,5]) + sage: w.is_regular(4) False - sage: W = ReflectionGroup(["A",3]) # optional - gap3 - sage: len([w for w in W if w.is_regular(w.order())]) # optional - gap3 + sage: W = ReflectionGroup(["A",3]) + sage: len([w for w in W if w.is_regular(w.order())]) 18 """ + from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField, E + evs = self.reflection_eigenvalues(is_class_representative=is_class_representative) P = self.parent() I = identity_matrix(P.rank()) diff --git a/src/sage/combinat/root_system/reflection_group_element.pyx b/src/sage/combinat/root_system/reflection_group_element.pyx index 02761726799..8f5a61ff0a2 100644 --- a/src/sage/combinat/root_system/reflection_group_element.pyx +++ b/src/sage/combinat/root_system/reflection_group_element.pyx @@ -22,18 +22,14 @@ AUTHORS: # https://www.gnu.org/licenses/ # *************************************************************************** -from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod from sage.arith.functions import lcm -from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.interfaces.gap3 import gap3 -from sage.combinat.root_system.cartan_matrix import CartanMatrix -from sage.misc.sage_eval import sage_eval from sage.combinat.root_system.reflection_group_c import reduced_word_c, reduce_in_coset -from sage.matrix.all import Matrix, identity_matrix +from sage.matrix.constructor import Matrix +from sage.matrix.special import identity_matrix cdef class ComplexReflectionGroupElement(PermutationGroupElement): @@ -74,15 +70,16 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): Check that :trac:`34912` is fixed:: - sage: G4 = ReflectionGroup(4) # optional - gap3 - sage: g0, g1 = G4.gens() # optional - gap3 - sage: elt = g0^2 * g1 * g0^2 * g1 # optional - gap3 - sage: elt # optional - gap3 + sage: # optional - gap3 + sage: G4 = ReflectionGroup(4) + sage: g0, g1 = G4.gens() + sage: elt = g0^2 * g1 * g0^2 * g1 + sage: elt (1,12)(2,24)(3,19)(4,22)(5,17)(6,20)(7,23)(8,9)(10,21)(11,13)(14,18)(15,16) - sage: y = (elt * G4.gen(1)) * G4.gen(1) * G4.gen(1) # optional - gap3 - sage: elt == y # optional - gap3 + sage: y = (elt * G4.gen(1)) * G4.gen(1) * G4.gen(1) + sage: elt == y True - sage: hash(elt) == hash(y) # optional - gap3 + sage: hash(elt) == hash(y) True """ return hash(self._parent) | super().__hash__() @@ -196,11 +193,11 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): EXAMPLES:: - sage: W = ReflectionGroup((3,1,2)) # optional - gap3 + sage: W = ReflectionGroup((3,1,2)) # optional - gap3 sage: data = {w: [w.to_matrix(), w.to_matrix(on_space="dual")] for w in W} # optional - gap3 - sage: for w in W.iteration_tracking_words(): # optional - gap3 - ....: w.reduced_word() # optional - gap3 - ....: mats = [w.to_matrix(), w.to_matrix(on_space="dual")] # optional - gap3 + sage: for w in W.iteration_tracking_words(): # optional - gap3 + ....: w.reduced_word() + ....: mats = [w.to_matrix(), w.to_matrix(on_space="dual")] ....: mats ....: assert data[w] == mats [] @@ -368,7 +365,7 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): sage: W = ReflectionGroup((3,1,2)) # optional - gap3 sage: w = W.from_reduced_word([1, 2, 1, 1, 2]) # optional - gap3 sage: for alpha in W.independent_roots(): # optional - gap3 - ....: print("%s -> %s"%(alpha,w.action(alpha))) # optional - gap3 + ....: print("%s -> %s"%(alpha,w.action(alpha))) (1, 0) -> (E(3), 0) (-1, 1) -> (-E(3), E(3)^2) """ @@ -391,7 +388,7 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): sage: W = ReflectionGroup((3,1,2)) # optional - gap3 sage: w = W.from_reduced_word([1, 2, 1, 1, 2]) # optional - gap3 sage: for alpha in W.independent_roots(): # optional - gap3 - ....: print("%s -> %s"%(alpha, w * alpha)) # optional - gap3 + ....: print("%s -> %s"%(alpha, w * alpha)) (1, 0) -> (E(3), 0) (-1, 1) -> (-E(3), E(3)^2) """ @@ -409,16 +406,18 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): EXAMPLES:: - sage: W = ReflectionGroup(['A',3]) # optional - gap3 - sage: w = W.w0 # optional - gap3 - sage: N = len(W.roots()) # optional - gap3 - sage: [w.action_on_root_indices(i) for i in range(N)] # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(['A',3]) + sage: w = W.w0 + sage: N = len(W.roots()) + sage: [w.action_on_root_indices(i) for i in range(N)] [8, 7, 6, 10, 9, 11, 2, 1, 0, 4, 3, 5] - sage: W = ReflectionGroup(['A',2], reflection_index_set=['A','B','C']) # optional - gap3 - sage: w = W.w0 # optional - gap3 - sage: N = len(W.roots()) # optional - gap3 - sage: [w.action_on_root_indices(i) for i in range(N)] # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(['A',2], reflection_index_set=['A','B','C']) + sage: w = W.w0 + sage: N = len(W.roots()) + sage: [w.action_on_root_indices(i) for i in range(N)] [4, 3, 5, 1, 0, 2] TESTS:: @@ -443,8 +442,8 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): sage: W = ReflectionGroup(['A',2]) # optional - gap3 sage: for w in W: # optional - gap3 - ....: print("%s %s"%(w.reduced_word(), # optional - gap3 - ....: [w.action_on_root(beta,side="left") for beta in W.positive_roots()])) # optional - gap3 + ....: print("%s %s"%(w.reduced_word(), + ....: [w.action_on_root(beta,side="left") for beta in W.positive_roots()])) [] [(1, 0), (0, 1), (1, 1)] [2] [(1, 1), (0, -1), (1, 0)] [1] [(-1, 0), (1, 1), (0, 1)] @@ -494,8 +493,8 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): sage: W = ReflectionGroup((1,1,3)) # optional - gap3 sage: for w in W: # optional - gap3 - ....: w.reduced_word() # optional - gap3 - ....: w.fix_space() # optional - gap3 + ....: w.reduced_word() + ....: w.fix_space() [] Vector space of degree 2 and dimension 2 over Rational Field Basis matrix: @@ -754,7 +753,7 @@ cdef class RealReflectionGroupElement(ComplexReflectionGroupElement): sage: W = ReflectionGroup(['A',2]) # optional - gap3 sage: for w in W: # optional - gap3 - ....: print("%s %s"%(w.reduced_word(), w.length())) # optional - gap3 + ....: print("%s %s"%(w.reduced_word(), w.length())) [] 0 [2] 1 [1] 1 @@ -773,11 +772,12 @@ cdef class RealReflectionGroupElement(ComplexReflectionGroupElement): EXAMPLES:: - sage: W = ReflectionGroup(["A",3]) # optional - gap3 - sage: s = W.simple_reflections() # optional - gap3 - sage: (s[1]*s[2]).has_left_descent(1) # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(["A",3]) + sage: s = W.simple_reflections() + sage: (s[1]*s[2]).has_left_descent(1) True - sage: (s[1]*s[2]).has_left_descent(2) # optional - gap3 + sage: (s[1]*s[2]).has_left_descent(2) False """ W = self._parent @@ -799,11 +799,12 @@ cdef class RealReflectionGroupElement(ComplexReflectionGroupElement): EXAMPLES:: - sage: W = ReflectionGroup(["A",3]) # optional - gap3 - sage: s = W.simple_reflections() # optional - gap3 - sage: (s[1]*s[2]).has_descent(1) # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(["A",3]) + sage: s = W.simple_reflections() + sage: (s[1]*s[2]).has_descent(1) True - sage: (s[1]*s[2]).has_descent(2) # optional - gap3 + sage: (s[1]*s[2]).has_descent(2) False """ if not isinstance(positive, bool): @@ -884,8 +885,8 @@ cdef class RealReflectionGroupElement(ComplexReflectionGroupElement): sage: W = ReflectionGroup(['A',2]) # optional - gap3 sage: for w in W: # optional - gap3 - ....: w.reduced_word() # optional - gap3 - ....: [w.to_matrix(), w.to_matrix(on_space="dual")] # optional - gap3 + ....: w.reduced_word() + ....: [w.to_matrix(), w.to_matrix(on_space="dual")] [] [ [1 0] [1 0] @@ -976,8 +977,8 @@ cdef class RealReflectionGroupElement(ComplexReflectionGroupElement): sage: W = ReflectionGroup(['A',2]) # optional - gap3 sage: for w in W: # optional - gap3 - ....: print("%s %s"%(w.reduced_word(), # optional - gap3 - ....: [w.action(weight,side="left") for weight in W.fundamental_weights()])) # optional - gap3 + ....: print("%s %s"%(w.reduced_word(), + ....: [w.action(weight,side="left") for weight in W.fundamental_weights()])) [] [(2/3, 1/3), (1/3, 2/3)] [2] [(2/3, 1/3), (1/3, -1/3)] [1] [(-1/3, 1/3), (1/3, 2/3)] @@ -989,10 +990,10 @@ cdef class RealReflectionGroupElement(ComplexReflectionGroupElement): sage: W = ReflectionGroup(['B',3]) # optional - gap3 sage: all(w.action(alpha,side="right") == w.action_on_root(alpha,side="right") # optional - gap3 - ....: for w in W for alpha in W.simple_roots()) # optional - gap3 + ....: for w in W for alpha in W.simple_roots()) True sage: all(w.action(alpha,side="left") == w.action_on_root(alpha,side="left") #optional - gap3 - ....: for w in W for alpha in W.simple_roots()) # optional - gap3 + ....: for w in W for alpha in W.simple_roots()) True """ W = self._parent @@ -1036,13 +1037,13 @@ cdef class RealReflectionGroupElement(ComplexReflectionGroupElement): sage: W = ReflectionGroup(['A',2]) # optional - gap3 sage: w = W.from_reduced_word([1,2]) # optional - gap3 sage: for root in W.positive_roots(): # optional - gap3 - ....: print("%s -> %s"%(root, w*root)) # optional - gap3 + ....: print("%s -> %s"%(root, w*root)) (1, 0) -> (0, 1) (0, 1) -> (-1, -1) (1, 1) -> (-1, 0) sage: for root in W.positive_roots(): # optional - gap3 - ....: print("%s -> %s"%(root, root*w)) # optional - gap3 + ....: print("%s -> %s"%(root, root*w)) (1, 0) -> (-1, -1) (0, 1) -> (1, 0) (1, 1) -> (0, -1) @@ -1065,16 +1066,18 @@ cdef class RealReflectionGroupElement(ComplexReflectionGroupElement): EXAMPLES:: - sage: W = ReflectionGroup(['A',3]) # optional - gap3 - sage: w = W.w0 # optional - gap3 - sage: N = len(W.roots()) # optional - gap3 - sage: [w.action_on_root_indices(i,side="left") for i in range(N)] # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(['A',3]) + sage: w = W.w0 + sage: N = len(W.roots()) + sage: [w.action_on_root_indices(i,side="left") for i in range(N)] [8, 7, 6, 10, 9, 11, 2, 1, 0, 4, 3, 5] - sage: W = ReflectionGroup(['A',2], reflection_index_set=['A','B','C']) # optional - gap3 - sage: w = W.w0 # optional - gap3 - sage: N = len(W.roots()) # optional - gap3 - sage: [w.action_on_root_indices(i,side="left") for i in range(N)] # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(['A',2], reflection_index_set=['A','B','C']) + sage: w = W.w0 + sage: N = len(W.roots()) + sage: [w.action_on_root_indices(i,side="left") for i in range(N)] [4, 3, 5, 1, 0, 2] """ cdef RealReflectionGroupElement w @@ -1101,8 +1104,8 @@ cdef class RealReflectionGroupElement(ComplexReflectionGroupElement): sage: W = ReflectionGroup(['A',2]) # optional - gap3 sage: for w in W: # optional - gap3 - ....: print("%s %s"%(w.reduced_word(), # optional - gap3 - ....: [w.action_on_root(beta,side="left") for beta in W.positive_roots()])) # optional - gap3 + ....: print("%s %s"%(w.reduced_word(), + ....: [w.action_on_root(beta,side="left") for beta in W.positive_roots()])) [] [(1, 0), (0, 1), (1, 1)] [2] [(1, 1), (0, -1), (1, 0)] [1] [(-1, 0), (1, 1), (0, 1)] @@ -1112,8 +1115,8 @@ cdef class RealReflectionGroupElement(ComplexReflectionGroupElement): sage: W = ReflectionGroup(['A',2]) # optional - gap3 sage: for w in W: # optional - gap3 - ....: print("%s %s"%(w.reduced_word(), # optional - gap3 - ....: [w.action_on_root(beta,side="right") for beta in W.positive_roots()])) # optional - gap3 + ....: print("%s %s"%(w.reduced_word(), + ....: [w.action_on_root(beta,side="right") for beta in W.positive_roots()])) [] [(1, 0), (0, 1), (1, 1)] [2] [(1, 1), (0, -1), (1, 0)] [1] [(-1, 0), (1, 1), (0, 1)] @@ -1135,7 +1138,7 @@ cdef class RealReflectionGroupElement(ComplexReflectionGroupElement): sage: W = ReflectionGroup(['A',2]) # optional - gap3 sage: for w in W: # optional - gap3 - ....: print("%s %s"%(w.reduced_word(), w.inversion_set())) # optional - gap3 + ....: print("%s %s"%(w.reduced_word(), w.inversion_set())) [] [] [2] [(0, 1)] [1] [(1, 0)] @@ -1172,6 +1175,8 @@ def _gap_factorization(w, gens): sage: [_gap_factorization(w,gens) for w in W] # optional - gap3 [[], [1], [0], [0, 1], [1, 0], [0, 1, 0]] """ + from sage.interfaces.gap3 import gap3 + gap3.execute('W := GroupWithGenerators(%s)'%str(gens)) gap3.execute(_gap_factorization_code) fac = gap3('MinimalWord(W,%s)'%str(w)).sage() diff --git a/src/sage/combinat/root_system/reflection_group_real.py b/src/sage/combinat/root_system/reflection_group_real.py index 9d7c9a92bbf..aee6b1d9bd9 100644 --- a/src/sage/combinat/root_system/reflection_group_real.py +++ b/src/sage/combinat/root_system/reflection_group_real.py @@ -47,7 +47,6 @@ from sage.misc.cachefunc import cached_function, cached_method, cached_in_parent_method from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract from sage.rings.integer_ring import ZZ -from sage.interfaces.gap3 import gap3 from sage.combinat.root_system.reflection_group_complex import ComplexReflectionGroup, IrreducibleComplexReflectionGroup from sage.misc.sage_eval import sage_eval from sage.combinat.root_system.reflection_group_element import RealReflectionGroupElement @@ -124,6 +123,8 @@ def ReflectionGroup(*args,**kwds): """ if not is_chevie_available(): raise ImportError("the GAP3 package 'chevie' is needed to work with (complex) reflection groups") + + from sage.interfaces.gap3 import gap3 gap3.load_package("chevie") error_msg = "the input data (%s) is not valid for reflection groups" @@ -223,6 +224,7 @@ def is_chevie_available(): EXAMPLES:: + sage: # needs sage.groups sage: from sage.combinat.root_system.reflection_group_real import is_chevie_available sage: is_chevie_available() # random False @@ -271,9 +273,9 @@ def __init__(self, W_types, index_set=None, hyperplane_index_set=None, reflectio cls = IrreducibleComplexReflectionGroup else: cls = ComplexReflectionGroup - cls.__init__(self, W_types, index_set = index_set, - hyperplane_index_set = hyperplane_index_set, - reflection_index_set = reflection_index_set) + cls.__init__(self, W_types, index_set=index_set, + hyperplane_index_set=hyperplane_index_set, + reflection_index_set=reflection_index_set) def _repr_(self): r""" @@ -326,7 +328,7 @@ def iteration(self, algorithm="breadth", tracking_words=True): sage: W = ReflectionGroup(["B",2]) # optional - gap3 sage: for w in W.iteration("breadth",True): # optional - gap3 - ....: print("%s %s"%(w, w._reduced_word)) # optional - gap3 + ....: print("%s %s"%(w, w._reduced_word)) () [] (1,3)(2,6)(5,7) [1] (1,5)(2,4)(6,8) [0] @@ -563,11 +565,12 @@ def fundamental_weights(self): sage: W.fundamental_weights() # optional - gap3 Finite family {1: (3/4, 1/2, 1/4), 2: (1/2, 1, 1/2), 3: (1/4, 1/2, 3/4)} - sage: W = ReflectionGroup(['A',3]) # optional - gap3 - sage: S = W.simple_reflections() # optional - gap3 - sage: N = W.fundamental_weights() # optional - gap3 - sage: for i in W.index_set(): # optional - gap3 - ....: for j in W.index_set(): # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(['A',3]) + sage: S = W.simple_reflections() + sage: N = W.fundamental_weights() + sage: for i in W.index_set(): + ....: for j in W.index_set(): ....: print("{} {} {} {}".format(i, j, N[i], N[i]*S[j].to_matrix())) 1 1 (3/4, 1/2, 1/4) (-1/4, 1/2, 1/4) 1 2 (3/4, 1/2, 1/4) (3/4, 1/2, 1/4) @@ -733,24 +736,27 @@ def bruhat_cone(self, x, y, side='upper', backend='cdd'): EXAMPLES:: - sage: W = ReflectionGroup(['A',2]) # optional - gap3 - sage: x = W.from_reduced_word([1]) # optional - gap3 - sage: y = W.w0 # optional - gap3 - sage: W.bruhat_cone(x, y) # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(['A',2]) + sage: x = W.from_reduced_word([1]) + sage: y = W.w0 + sage: W.bruhat_cone(x, y) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays - sage: W = ReflectionGroup(['E',6]) # optional - gap3 - sage: x = W.one() # optional - gap3 - sage: y = W.w0 # optional - gap3 - sage: W.bruhat_cone(x, y, side='lower') # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(['E',6]) + sage: x = W.one() + sage: y = W.w0 + sage: W.bruhat_cone(x, y, side='lower') A 6-dimensional polyhedron in QQ^6 defined as the convex hull of 1 vertex and 6 rays TESTS:: - sage: W = ReflectionGroup(['A',2]) # optional - gap3 - sage: x = W.one() # optional - gap3 - sage: y = W.w0 # optional - gap3 - sage: W.bruhat_cone(x, y, side='nonsense') # optional - gap3 + sage: # optional - gap3 + sage: W = ReflectionGroup(['A',2]) + sage: x = W.one() + sage: y = W.w0 + sage: W.bruhat_cone(x, y, side='nonsense') Traceback (most recent call last): ... ValueError: side must be either 'upper' or 'lower' @@ -801,9 +807,9 @@ def right_coset_representatives(self): sage: W = ReflectionGroup(['A',2]) # optional - gap3 sage: for w in W: # optional - gap3 - ....: rcr = w.right_coset_representatives() # optional - gap3 - ....: print("%s %s"%(w.reduced_word(), # optional - gap3 - ....: [v.reduced_word() for v in rcr])) # optional - gap3 + ....: rcr = w.right_coset_representatives() + ....: print("%s %s"%(w.reduced_word(), + ....: [v.reduced_word() for v in rcr])) [] [[], [2], [1], [2, 1], [1, 2], [1, 2, 1]] [2] [[], [2], [1]] [1] [[], [1], [1, 2]] @@ -830,9 +836,9 @@ def left_coset_representatives(self): sage: W = ReflectionGroup(['A',2]) # optional - gap3 sage: for w in W: # optional - gap3 - ....: lcr = w.left_coset_representatives() # optional - gap3 - ....: print("%s %s"%(w.reduced_word(), # optional - gap3 - ....: [v.reduced_word() for v in lcr])) # optional - gap3 + ....: lcr = w.left_coset_representatives() + ....: print("%s %s"%(w.reduced_word(), + ....: [v.reduced_word() for v in lcr])) [] [[], [2], [1], [1, 2], [2, 1], [1, 2, 1]] [2] [[], [2], [1]] [1] [[], [1], [2, 1]] diff --git a/src/sage/combinat/root_system/root_lattice_realization_algebras.py b/src/sage/combinat/root_system/root_lattice_realization_algebras.py index 3e70a2e8fd9..62bfff6060a 100644 --- a/src/sage/combinat/root_system/root_lattice_realization_algebras.py +++ b/src/sage/combinat/root_system/root_lattice_realization_algebras.py @@ -52,21 +52,25 @@ def some_elements(self): sage: A = RootSystem(["A",2,1]).ambient_space().algebra(QQ) sage: A.some_elements() + [B[2*e[0] + 2*e[1] + 3*e[2]]...] + sage: A.some_elements() # needs sage.graphs [B[2*e[0] + 2*e[1] + 3*e[2]], - B[-e[0] + e[2] + e['delta']], - B[e[0] - e[1]], - B[e[1] - e[2]], - B[e['deltacheck']], - B[e[0] + e['deltacheck']], - B[e[0] + e[1] + e['deltacheck']]] + B[-e[0] + e[2] + e['delta']], + B[e[0] - e[1]], + B[e[1] - e[2]], + B[e['deltacheck']], + B[e[0] + e['deltacheck']], + B[e[0] + e[1] + e['deltacheck']]] sage: A = RootSystem(["B",2]).weight_space().algebra(QQ) sage: A.some_elements() + [B[2*Lambda[1] + 2*Lambda[2]], ... B[Lambda[1]], B[Lambda[2]]] + sage: A.some_elements() # needs sage.graphs [B[2*Lambda[1] + 2*Lambda[2]], - B[2*Lambda[1] - 2*Lambda[2]], - B[-Lambda[1] + 2*Lambda[2]], - B[Lambda[1]], - B[Lambda[2]]] + B[2*Lambda[1] - 2*Lambda[2]], + B[-Lambda[1] + 2*Lambda[2]], + B[Lambda[1]], + B[Lambda[2]]] """ return [self.monomial(weight) for weight in self.basis().keys().some_elements()] @@ -238,32 +242,34 @@ def demazure_operators(self): sage: L = RootSystem(["A",2]).ambient_lattice() sage: KL = L.algebra(QQ) - sage: w0 = tuple(L.weyl_group().long_element().reduced_word()) + sage: w0 = tuple(L.weyl_group().long_element().reduced_word()) # needs sage.libs.gap sage: pi = KL.demazure_operators() - sage: pi0 = pi[w0] - sage: pi0(KL.monomial(L((2,1)))) - 2*B[(1, 1, 1)] + B[(1, 2, 0)] + B[(1, 0, 2)] + B[(2, 1, 0)] + B[(2, 0, 1)] + B[(0, 1, 2)] + B[(0, 2, 1)] + sage: pi0 = pi[w0] # needs sage.libs.gap + sage: pi0(KL.monomial(L((2,1)))) # needs sage.libs.gap + 2*B[(1, 1, 1)] + B[(1, 2, 0)] + B[(1, 0, 2)] + B[(2, 1, 0)] + + B[(2, 0, 1)] + B[(0, 1, 2)] + B[(0, 2, 1)] Let us make the result into an actual polynomial:: sage: P = QQ['x,y,z'] - sage: pi0(KL.monomial(L((2,1)))).expand(P.gens()) + sage: pi0(KL.monomial(L((2,1)))).expand(P.gens()) # needs sage.libs.gap x^2*y + x*y^2 + x^2*z + 2*x*y*z + y^2*z + x*z^2 + y*z^2 This is indeed a Schur function:: - sage: s = SymmetricFunctions(QQ).s() - sage: s[2,1].expand(3, P.variable_names()) + sage: s = SymmetricFunctions(QQ).s() # needs sage.combinat + sage: s[2,1].expand(3, P.variable_names()) # needs sage.combinat x^2*y + x*y^2 + x^2*z + 2*x*y*z + y^2*z + x*z^2 + y*z^2 Let us check this systematically on Schur functions of degree 6:: - sage: for p in Partitions(6, max_length=3).list(): - ....: assert s.monomial(p).expand(3, P.variable_names()) == pi0(KL.monomial(L(tuple(p)))).expand(P.gens()) + sage: for p in Partitions(6, max_length=3).list(): # needs sage.combinat sage.libs.gap + ....: assert (s.monomial(p).expand(3, P.variable_names()) + ....: == pi0(KL.monomial(L(tuple(p)))).expand(P.gens())) We check systematically that these operators satisfy the Iwahori-Hecke algebra relations:: - sage: for cartan_type in CartanType.samples(crystallographic=True): # long time 12s + sage: for cartan_type in CartanType.samples(crystallographic=True): # long time (12s) ....: L = RootSystem(cartan_type).weight_lattice() ....: KL = L.algebra(QQ) ....: T = KL.demazure_operators() @@ -300,21 +306,24 @@ def _test_demazure_operators(self, **options): sage: RootSystem(["A",2]).root_lattice().algebra(QQ)._test_demazure_operators() """ tester = self._tester(**options) - pi = self.demazure_operators() - L = self.basis().keys() - alpha = L.simple_roots() - alphacheck = L.simple_coroots() - s = L.simple_reflections() - for i in self.cartan_type().index_set(): - emalphai = self.monomial(-alpha[i]) # X^{-\alpha_i} - for weight in L.some_elements(): - if not weight.scalar(alphacheck[i]) in ZZ: - # Demazure operators are not defined in this case - continue - x = self.monomial(weight) - result = pi[i](x) - tester.assertEqual(result * (self.one()-emalphai), - x - emalphai * x.map_support(s[i])) + try: + pi = self.demazure_operators() + L = self.basis().keys() + alpha = L.simple_roots() + alphacheck = L.simple_coroots() + s = L.simple_reflections() + for i in self.cartan_type().index_set(): + emalphai = self.monomial(-alpha[i]) # X^{-\alpha_i} + for weight in L.some_elements(): + if not weight.scalar(alphacheck[i]) in ZZ: + # Demazure operators are not defined in this case + continue + x = self.monomial(weight) + result = pi[i](x) + tester.assertEqual(result * (self.one()-emalphai), + x - emalphai * x.map_support(s[i])) + except ImportError: + pass def demazure_lusztig_operator_on_basis(self, weight, i, q1, q2, convention="antidominant"): r""" @@ -324,8 +333,8 @@ def demazure_lusztig_operator_on_basis(self, weight, i, q1, q2, convention="anti - ``weight`` -- an element `\lambda` of the weight lattice - ``i`` -- an element of the index set - - ``q1,q2`` -- two elements of the ground ring - - ``convention`` -- "antidominant", "bar", or "dominant" (default: "antidominant") + - ``q1``, ``q2`` -- two elements of the ground ring + - ``convention`` -- ``"antidominant"``, ``"bar"``, or ``"dominant"`` (default: ``"antidominant"``) See :meth:`demazure_lusztig_operators` for the details. @@ -440,7 +449,8 @@ def demazure_lusztig_operators(self, q1, q2, convention="antidominant"): sage: KL = L.algebra(K) sage: T = KL.demazure_lusztig_operators(q1, q2) sage: Tbar = KL.demazure_lusztig_operators(q1, q2, convention="bar") - sage: Tdominant = KL.demazure_lusztig_operators(q1, q2, convention="dominant") + sage: Tdominant = KL.demazure_lusztig_operators(q1, q2, + ....: convention="dominant") sage: x = KL.monomial(L((3,0))) sage: T[1](x) (q1+q2)*B[(1, 2)] + (q1+q2)*B[(2, 1)] + (q1+q2)*B[(3, 0)] + q1*B[(0, 3)] @@ -462,13 +472,16 @@ def demazure_lusztig_operators(self, q1, q2, convention="antidominant"): sage: KL = L.algebra(K) sage: T = KL.demazure_lusztig_operators(q1, q2) sage: Tbar = KL.demazure_lusztig_operators(q1, q2, convention="bar") - sage: Tdominant = KL.demazure_lusztig_operators(q1, q2, convention="dominant") + sage: Tdominant = KL.demazure_lusztig_operators(q1, q2, + ....: convention="dominant") sage: e = L.basis() sage: x = KL.monomial(3*e[0]) sage: T[1](x) - (q1+q2)*B[e[0] + 2*e[1]] + (q1+q2)*B[2*e[0] + e[1]] + (q1+q2)*B[3*e[0]] + q1*B[3*e[1]] + (q1+q2)*B[e[0] + 2*e[1]] + (q1+q2)*B[2*e[0] + e[1]] + + (q1+q2)*B[3*e[0]] + q1*B[3*e[1]] sage: Tbar[1](x) - (-q1-q2)*B[e[0] + 2*e[1]] + (-q1-q2)*B[2*e[0] + e[1]] + (-q1-2*q2)*B[3*e[1]] + (-q1-q2)*B[e[0] + 2*e[1]] + (-q1-q2)*B[2*e[0] + e[1]] + + (-q1-2*q2)*B[3*e[1]] sage: Tbar[1](x) + T[1](x) (q1+q2)*B[3*e[0]] + (-2*q2)*B[3*e[1]] sage: Tdominant[1](x) @@ -501,31 +514,33 @@ def demazure_lusztig_operators(self, q1, q2, convention="antidominant"): And the `\bar{T}` are basically the inverses of the `T` s:: - sage: Tinv = KL.demazure_lusztig_operators(2/q1+1/q2,-1/q1,convention="bar") - sage: [Tinv[1](T[1](x))-x for x in KL.some_elements()] + sage: Tinv = KL.demazure_lusztig_operators(2/q1 + 1/q2, -1/q1, + ....: convention="bar") + sage: [Tinv[1](T[1](x)) - x for x in KL.some_elements()] # needs sage.graphs [0, 0, 0, 0, 0, 0, 0] We check that `\Lambda_1-\Lambda_0` is an eigenvector for the `Y` s in affine type:: sage: K = QQ['q,q1,q2'].fraction_field() - sage: q,q1,q2=K.gens() + sage: q,q1,q2 = K.gens() sage: L = RootSystem(["A",2,1]).ambient_space() sage: L0 = L.classical() - sage: Lambda = L.fundamental_weights() + sage: Lambda = L.fundamental_weights() # needs sage.graphs sage: alphacheck = L0.simple_coroots() sage: KL = L.algebra(K) sage: T = KL.demazure_lusztig_operators(q1, q2, convention="dominant") sage: Y = T.Y() - sage: alphacheck = Y.keys().alpha() # alpha of coroot lattice is alphacheck + sage: alphacheck = Y.keys().alpha() # alpha of coroot lattice is alphacheck sage: alphacheck Finite family {0: alphacheck[0], 1: alphacheck[1], 2: alphacheck[2]} - sage: x = KL.monomial(Lambda[1]-Lambda[0]); x + sage: x = KL.monomial(Lambda[1] - Lambda[0]); x # needs sage.graphs B[e[0]] In fact it is not exactly an eigenvector, but the extra '\delta` term is to be interpreted as a `q` parameter:: + sage: # needs sage.graphs sage: Y[alphacheck[0]](KL.one()) q2^2/q1^2*B[0] sage: Y[alphacheck[1]](x) @@ -535,6 +550,7 @@ def demazure_lusztig_operators(self, q1, q2, convention="antidominant"): sage: KL.q_project(Y[alphacheck[1]](x),q) ((-q2^2)/(-q*q1^2))*B[(1, 0, 0)] + sage: # needs sage.graphs sage: KL.q_project(x, q) B[(1, 0, 0)] sage: KL.q_project(Y[alphacheck[0]](x),q) @@ -577,7 +593,7 @@ def demazure_lusztig_operators(self, q1, q2, convention="antidominant"): ....: T._test_relations(elements=elements) """ T_on_basis = functools.partial(self.demazure_lusztig_operator_on_basis, - q1 = q1, q2 = q2, convention = convention) + q1=q1, q2=q2, convention=convention) return HeckeAlgebraRepresentation(self, T_on_basis, self.cartan_type(), q1, q2, side="left") def demazure_lusztig_operator_on_classical_on_basis(self, weight, i, q, q1, q2, convention="antidominant"): @@ -589,7 +605,7 @@ def demazure_lusztig_operator_on_classical_on_basis(self, weight, i, q, q1, q2, - ``weight`` -- a classical weight `\lambda` - ``i`` -- an element of the index set - ``q1,q2`` -- two elements of the ground ring - - ``convention`` -- "antidominant", "bar", or "dominant" (default: "antidominant") + - ``convention`` -- ``"antidominant"``, ``"bar"``, or ``"dominant"`` (default: ``"antidominant"``) See :meth:`demazure_lusztig_operators` for the details. @@ -611,21 +627,25 @@ def demazure_lusztig_operator_on_classical_on_basis(self, weight, i, q, q1, q2, These operators coincide with the usual Demazure-Lusztig operators:: - sage: KL.demazure_lusztig_operator_on_classical_on_basis(L0((2,2)), 1, q, q1, q2) + sage: KL.demazure_lusztig_operator_on_classical_on_basis(L0((2,2)), # needs sage.graphs + ....: 1, q, q1, q2) q1*B[(2, 2)] sage: KL0.demazure_lusztig_operator_on_basis(L0((2,2)), 1, q1, q2) q1*B[(2, 2)] - sage: KL.demazure_lusztig_operator_on_classical_on_basis(L0((3,0)), 1, q, q1, q2) + sage: KL.demazure_lusztig_operator_on_classical_on_basis(L0((3,0)), # needs sage.graphs + ....: 1, q, q1, q2) (q1+q2)*B[(1, 2)] + (q1+q2)*B[(2, 1)] + (q1+q2)*B[(3, 0)] + q1*B[(0, 3)] sage: KL0.demazure_lusztig_operator_on_basis(L0((3,0)), 1, q1, q2) (q1+q2)*B[(1, 2)] + (q1+q2)*B[(2, 1)] + (q1+q2)*B[(3, 0)] + q1*B[(0, 3)] except that we now have an action of `T_0`, which introduces some `q` s:: - sage: KL.demazure_lusztig_operator_on_classical_on_basis(L0((2,2)), 0, q, q1, q2) + sage: KL.demazure_lusztig_operator_on_classical_on_basis(L0((2,2)), # needs sage.graphs + ....: 0, q, q1, q2) q1*B[(2, 2)] - sage: KL.demazure_lusztig_operator_on_classical_on_basis(L0((3,0)), 0, q, q1, q2) + sage: KL.demazure_lusztig_operator_on_classical_on_basis(L0((3,0)), # needs sage.graphs + ....: 0, q, q1, q2) (-q^2*q1-q^2*q2)*B[(1, 2)] + (-q*q1-q*q2)*B[(2, 1)] + (-q^3*q2)*B[(0, 3)] """ L = self.basis().keys() @@ -639,7 +659,7 @@ def demazure_lusztig_operators_on_classical(self, q, q1, q2, convention="antidom INPUT: - ``q,q1,q2`` -- three elements of the ground ring - - ``convention`` -- "antidominant", "bar", or "dominant" (default: "antidominant") + - ``convention`` -- ``"antidominant"``, ``"bar"``, or ``"dominant"`` (default: ``"antidominant"``) Let `KL` be the group algebra of an affine weight lattice realization `L`. The Demazure-Lusztig operators for `KL` @@ -661,32 +681,32 @@ def demazure_lusztig_operators_on_classical(self, q, q1, q2, convention="antidom sage: KL = L.algebra(K) sage: KL0 = KL.classical() sage: L0 = KL0.basis().keys() - sage: T = KL.demazure_lusztig_operators_on_classical(q, q1, q2) + sage: T = KL.demazure_lusztig_operators_on_classical(q, q1, q2) # needs sage.graphs sage: x = KL0.monomial(L0((3,0))); x B[(3, 0)] For `T_1,\dots` we recover the usual Demazure-Lusztig operators:: - sage: T[1](x) + sage: T[1](x) # needs sage.graphs (q1+q2)*B[(1, 2)] + (q1+q2)*B[(2, 1)] + (q1+q2)*B[(3, 0)] + q1*B[(0, 3)] For `T_0`, we can note that, in the projection, `\delta` is mapped to `q`:: - sage: T[0](x) + sage: T[0](x) # needs sage.graphs (-q^2*q1-q^2*q2)*B[(1, 2)] + (-q*q1-q*q2)*B[(2, 1)] + (-q^3*q2)*B[(0, 3)] Note that there is no translation part, and in particular 1 is an eigenvector for all `T_i`'s:: + sage: # needs sage.graphs sage: T[0](KL0.one()) q1*B[(0, 0)] sage: T[1](KL0.one()) q1*B[(0, 0)] - sage: Y = T.Y() - sage: alphacheck=Y.keys().simple_roots() + sage: alphacheck = Y.keys().simple_roots() sage: Y[alphacheck[0]](KL0.one()) ((-q2)/(q*q1))*B[(0, 0)] @@ -699,30 +719,30 @@ def demazure_lusztig_operators_on_classical(self, q, q1, q2, convention="antidom sage: KL0 = KL.classical() sage: L0 = KL0.basis().keys() sage: omega = L0.fundamental_weights() - sage: T = KL.demazure_lusztig_operators_on_classical(q, u, -1/u, convention="dominant") + + sage: # needs sage.graphs + sage: T = KL.demazure_lusztig_operators_on_classical(q, u, -1/u, + ....: convention="dominant") sage: Y = T.Y() sage: alphacheck = Y.keys().simple_roots() - sage: Ydelta = Y[Y.keys().null_root()] sage: Ydelta.word, Ydelta.signs, Ydelta.scalar ((), (), 1/q) - sage: Y1 = Y[alphacheck[1]] - sage: Y1.word, Y1.signs, Y1.scalar # This is T_0 T_1 (T_1 acts first, then T_0); Ion gets T_1 T_0 + sage: Y1.word, Y1.signs, Y1.scalar # This is T_0 T_1 (T_1 acts first, then T_0); Ion gets T_1 T_0 ((1, 0), (1, 1), 1) - sage: Y0 = Y[alphacheck[0]] - sage: Y0.word, Y0.signs, Y0.scalar # This is 1/q T_1^-1 T_0^-1 + sage: Y0.word, Y0.signs, Y0.scalar # This is 1/q T_1^-1 T_0^-1 ((0, 1), (-1, -1), 1/q) Note that the following computations use the "dominant" convention:: + sage: # needs sage.graphs sage: T0 = T.Tw(0) sage: T0(KL0.monomial(omega[1])) q*u*B[-Lambda[1]] + ((u^2-1)/u)*B[Lambda[1]] sage: T0(KL0.monomial(2*omega[1])) ((q*u^2-q)/u)*B[0] + q^2*u*B[-2*Lambda[1]] + ((u^2-1)/u)*B[2*Lambda[1]] - sage: T0(KL0.monomial(-omega[1])) 1/(q*u)*B[Lambda[1]] sage: T0(KL0.monomial(-2*omega[1])) @@ -766,22 +786,22 @@ def T0_check_on_basis(self, q1, q2, convention="antidominant"): sage: L = RootSystem(["A",1,1]).ambient_space() sage: L0 = L.classical() sage: KL = L.algebra(K) - sage: some_weights = L.fundamental_weights() - sage: f = KL.T0_check_on_basis(q1,q2, convention="dominant") - sage: f(L0.zero()) + sage: some_weights = L.fundamental_weights() # needs sage.graphs + sage: f = KL.T0_check_on_basis(q1,q2, convention="dominant") # needs sage.graphs + sage: f(L0.zero()) # needs sage.graphs (q1+q2)*B[(0, 0)] + q1*B[(1, -1)] sage: L = RootSystem(["A",3,1]).ambient_space() sage: L0 = L.classical() sage: KL = L.algebra(K) sage: some_weights = L0.fundamental_weights() - sage: f = KL.T0_check_on_basis(q1,q2, convention="dominant") - sage: f(L0.zero()) # not checked + sage: f = KL.T0_check_on_basis(q1,q2, convention="dominant") # needs sage.graphs + sage: f(L0.zero()) # not checked # needs sage.graphs (q1+q2)*B[(0, 0, 0, 0)] + q1^3/q2^2*B[(1, 0, 0, -1)] The following results have not been checked:: - sage: for x in some_weights: + sage: for x in some_weights: # needs sage.graphs ....: print("{} : {}".format(x, f(x))) (1, 0, 0, 0) : q1*B[(1, 0, 0, 0)] (1, 1, 0, 0) : q1*B[(1, 1, 0, 0)] @@ -798,14 +818,14 @@ def T0_check_on_basis(self, q1, q2, convention="antidominant"): sage: q2 = -1/u sage: KL = L.algebra(K) sage: KL0 = KL.classical() - sage: f = KL.T0_check_on_basis(q1,q2, convention="dominant") + sage: f = KL.T0_check_on_basis(q1,q2, convention="dominant") # needs sage.graphs sage: T = KL.twisted_demazure_lusztig_operators(q1,q2, convention="dominant") Direct calculation:: - sage: T.Tw(0)(KL0.monomial(L0([0,0]))) + sage: T.Tw(0)(KL0.monomial(L0([0,0]))) # needs sage.graphs ((u^2-1)/u)*B[(0, 0)] + u^3*B[(1, 1)] - sage: KL.T0_check_on_basis(q1,q2, convention="dominant")(L0([0,0])) + sage: KL.T0_check_on_basis(q1,q2, convention="dominant")(L0([0,0])) # needs sage.graphs ((u^2-1)/u)*B[(0, 0)] + u^3*B[(1, 1)] Step by step calculation, comparing by hand with Mark Shimozono:: @@ -888,7 +908,8 @@ def q_project_on_basis(self, l, q): sage: KL = RootSystem(["A",2,1]).ambient_space().algebra(K) sage: L = KL.basis().keys() sage: e = L.basis() - sage: KL.q_project_on_basis( 4*e[1] + 3*e[2] + e['deltacheck'] - 2*e['delta'], q) + sage: KL.q_project_on_basis(4*e[1] + 3*e[2] + ....: + e['deltacheck'] - 2*e['delta'], q) 1/q^2*B[(0, 4, 3)] """ KL0 = self.classical() @@ -915,16 +936,22 @@ def q_project(self, x, q): sage: KL = RootSystem(["A",2,1]).ambient_space().algebra(K) sage: L = KL.basis().keys() sage: e = L.basis() - sage: x = KL.an_element() + KL.monomial(4*e[1] + 3*e[2] + e['deltacheck'] - 2*e['delta']); x - B[2*e[0] + 2*e[1] + 3*e[2]] + B[4*e[1] + 3*e[2] - 2*e['delta'] + e['deltacheck']] + sage: x = (KL.an_element() + ....: + KL.monomial(4*e[1] + 3*e[2] + ....: + e['deltacheck'] - 2*e['delta'])); x + B[2*e[0] + 2*e[1] + 3*e[2]] + + B[4*e[1] + 3*e[2] - 2*e['delta'] + e['deltacheck']] sage: KL.q_project(x, q) B[(2, 2, 3)] + 1/q^2*B[(0, 4, 3)] sage: KL = RootSystem(["BC",3,2]).ambient_space().algebra(K) sage: L = KL.basis().keys() sage: e = L.basis() - sage: x = KL.an_element() + KL.monomial(4*e[1] + 3*e[2] + e['deltacheck'] - 2*e['delta']); x - B[2*e[0] + 2*e[1] + 3*e[2]] + B[4*e[1] + 3*e[2] - 2*e['delta'] + e['deltacheck']] + sage: x = (KL.an_element() + ....: + KL.monomial(4*e[1] + 3*e[2] + ....: + e['deltacheck'] - 2*e['delta'])); x + B[2*e[0] + 2*e[1] + 3*e[2]] + + B[4*e[1] + 3*e[2] - 2*e['delta'] + e['deltacheck']] sage: KL.q_project(x, q) B[(2, 2, 3)] + 1/q^2*B[(0, 4, 3)] @@ -937,7 +964,7 @@ def q_project(self, x, q): denoted `q` is in fact ``q^a[0]`` in Sage's notations, to avoid manipulating square roots:: - sage: KL.q_project(KL.monomial(L.null_root()),q) + sage: KL.q_project(KL.monomial(L.null_root()),q) # needs sage.graphs q^2*B[(0, 0, 0)] """ L0 = self.classical() @@ -952,7 +979,7 @@ def twisted_demazure_lusztig_operator_on_basis(self, weight, i, q1, q2, conventi - ``weight`` -- an element `\lambda` of the weight lattice - ``i`` -- an element of the index set - ``q1,q2`` -- two elements of the ground ring - - ``convention`` -- "antidominant", "bar", or "dominant" (default: "antidominant") + - ``convention`` -- ``"antidominant"``, ``"bar"``, or ``"dominant"`` (default: ``"antidominant"``) .. SEEALSO:: :meth:`twisted_demazure_lusztig_operators` @@ -964,16 +991,23 @@ def twisted_demazure_lusztig_operator_on_basis(self, weight, i, q1, q2, conventi sage: q1, q2 = K.gens() sage: KL = L.algebra(K) sage: Lambda = L.classical().fundamental_weights() - sage: KL.twisted_demazure_lusztig_operator_on_basis(Lambda[1]+2*Lambda[2], 1, q1, q2, convention="dominant") + sage: KL.twisted_demazure_lusztig_operator_on_basis( + ....: Lambda[1] + 2*Lambda[2], 1, q1, q2, convention="dominant") (-q2)*B[(2, 3, 0, 0)] - sage: KL.twisted_demazure_lusztig_operator_on_basis(Lambda[1]+2*Lambda[2], 2, q1, q2, convention="dominant") + sage: KL.twisted_demazure_lusztig_operator_on_basis( + ....: Lambda[1] + 2*Lambda[2], 2, q1, q2, convention="dominant") (-q1-q2)*B[(3, 1, 1, 0)] + (-q2)*B[(3, 0, 2, 0)] - sage: KL.twisted_demazure_lusztig_operator_on_basis(Lambda[1]+2*Lambda[2], 3, q1, q2, convention="dominant") + sage: KL.twisted_demazure_lusztig_operator_on_basis( + ....: Lambda[1] + 2*Lambda[2], 3, q1, q2, convention="dominant") q1*B[(3, 2, 0, 0)] - sage: KL.twisted_demazure_lusztig_operator_on_basis(Lambda[1]+2*Lambda[2], 0, q1, q2, convention="dominant") - ((q1*q2+q2^2)/q1)*B[(1, 2, 1, 1)] + ((q1*q2+q2^2)/q1)*B[(1, 2, 2, 0)] + q2^2/q1*B[(1, 2, 0, 2)] - + ((q1^2+2*q1*q2+q2^2)/q1)*B[(2, 1, 1, 1)] + ((q1^2+2*q1*q2+q2^2)/q1)*B[(2, 1, 2, 0)] - + ((q1*q2+q2^2)/q1)*B[(2, 1, 0, 2)] + ((q1^2+2*q1*q2+q2^2)/q1)*B[(2, 2, 1, 0)] + ((q1*q2+q2^2)/q1)*B[(2, 2, 0, 1)] + sage: KL.twisted_demazure_lusztig_operator_on_basis( # needs sage.graphs + ....: Lambda[1]+2*Lambda[2], 0, q1, q2, convention="dominant") + ((q1*q2+q2^2)/q1)*B[(1, 2, 1, 1)] + ((q1*q2+q2^2)/q1)*B[(1, 2, 2, 0)] + + q2^2/q1*B[(1, 2, 0, 2)] + ((q1^2+2*q1*q2+q2^2)/q1)*B[(2, 1, 1, 1)] + + ((q1^2+2*q1*q2+q2^2)/q1)*B[(2, 1, 2, 0)] + + ((q1*q2+q2^2)/q1)*B[(2, 1, 0, 2)] + + ((q1^2+2*q1*q2+q2^2)/q1)*B[(2, 2, 1, 0)] + + ((q1*q2+q2^2)/q1)*B[(2, 2, 0, 1)] """ if i == 0: # should use the special node if convention != "dominant": @@ -990,12 +1024,12 @@ def twisted_demazure_lusztig_operators(self, q1, q2, convention="antidominant"): INPUT: - ``q1,q2`` -- two elements of the ground ring - - ``convention`` -- "antidominant", "bar", or "dominant" (default: "antidominant") + - ``convention`` -- ``"antidominant"``, ``"bar"``, or ``"dominant"`` (default: ``"antidominant"``) .. WARNING:: - the code is currently only tested for `q_1q_2=-1` - - only the "dominant" convention is functional for `i=0` + - only the ``"dominant"`` convention is functional for `i=0` For `T_1,\ldots,T_n`, these operators are the usual Demazure-Lusztig operators. On the other hand, the @@ -1030,7 +1064,7 @@ def twisted_demazure_lusztig_operators(self, q1, q2, convention="antidominant"): (-q1-q2)*B[(0, 0)] + (-q2)*B[(-1, 1)] sage: T.Ti_inverse_on_basis(alpha[1], 1) ((q1+q2)/(q1*q2))*B[(0, 0)] + 1/q1*B[(-1, 1)] + ((q1+q2)/(q1*q2))*B[(1, -1)] - sage: T.Ti_on_basis(L0.zero(), 0) + sage: T.Ti_on_basis(L0.zero(), 0) # needs sage.graphs (q1+q2)*B[(0, 0)] + q1*B[(1, -1)] The next computations were checked with Mark Shimozono for type `A_2^{(1)}`:: @@ -1086,7 +1120,7 @@ def twisted_demazure_lusztig_operators(self, q1, q2, convention="antidominant"): sage: cartan_type = CartanType(["BC",1,2]) sage: KL = RootSystem(cartan_type).weight_lattice().algebra(K) sage: T = KL.twisted_demazure_lusztig_operators(q1,q2, convention="dominant") - sage: T._test_relations() + sage: T._test_relations() # needs sage.graphs Traceback (most recent call last): ... tester.assertTrue(Ti(Ti(x,i,-q2),i,-q1).is_zero()) ... AssertionError: False is not true @@ -1103,12 +1137,13 @@ def twisted_demazure_lusztig_operators(self, q1, q2, convention="antidominant"): sage: L0 = L.classical() sage: T = KL.demazure_lusztig_operators(q1,q2, convention="dominant") sage: def T0(*l0): return KL.q_project(T[0].on_basis()(L.embed_at_level(L0(l0), 1)), q) - sage: T0_check_on_basis = KL.T0_check_on_basis(q1, q2, convention="dominant") + sage: T0_check_on_basis = KL.T0_check_on_basis(q1, q2, # needs sage.graphs + ....: convention="dominant") sage: def T0c(*l0): return T0_check_on_basis(L0(l0)) - sage: T0(0,0,1) # not double checked + sage: T0(0,0,1) # not double checked # needs sage.graphs ((-t+1)/q)*B[(1, 0, 0)] + 1/q^2*B[(2, 0, -1)] - sage: T0c(0,0,1) + sage: T0c(0,0,1) # needs sage.graphs (t^2-t)*B[(1, 0, 0)] + (t^2-t)*B[(1, 1, -1)] + t^2*B[(2, 0, -1)] + (t-1)*B[(0, 0, 1)] """ T_on_basis = functools.partial(self.twisted_demazure_lusztig_operator_on_basis, @@ -1117,7 +1152,7 @@ def twisted_demazure_lusztig_operators(self, q1, q2, convention="antidominant"): T_on_basis, self.cartan_type().classical().dual().affine().dual(), q1, q2, - side = "left") + side="left") class ElementMethods: @@ -1132,15 +1167,15 @@ def acted_upon(self, w): EXAMPLES:: sage: L = RootSystem(["A",3]).ambient_space() - sage: W = L.weyl_group() + sage: W = L.weyl_group() # needs sage.libs.gap sage: M = L.algebra(QQ['q','t']) sage: m = M.an_element(); m # TODO: investigate why we don't get something more interesting B[(2, 2, 3, 0)] sage: m = (m+1)^2; m B[(0, 0, 0, 0)] + 2*B[(2, 2, 3, 0)] + B[(4, 4, 6, 0)] - sage: w = W.an_element(); w.reduced_word() + sage: w = W.an_element(); w.reduced_word() # needs sage.libs.gap [1, 2, 3] - sage: m.acted_upon(w) + sage: m.acted_upon(w) # needs sage.libs.gap B[(0, 0, 0, 0)] + 2*B[(0, 2, 2, 3)] + B[(0, 4, 4, 6)] """ return self.map_support(w.action) @@ -1166,13 +1201,13 @@ def expand(self, alphabet): TESTS:: sage: type(p.expand(F.gens())) - <class 'sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair'> + <class 'sage.rings.polynomial.laurent_polynomial_mpair.LaurentPolynomial_mpair'> sage: p = KL.zero() sage: p.expand(F.gens()) 0 sage: type(p.expand(F.gens())) - <class 'sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair'> + <class 'sage.rings.polynomial.laurent_polynomial_mpair.LaurentPolynomial_mpair'> """ codomain = alphabet[0].parent() return codomain.sum(c * prod(X**int(n) diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index fb63471ffb0..80ed38c982f 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -80,7 +80,7 @@ class RootLatticeRealizations(Category_over_base_ring): alpha[2] + 2*alpha[5] sage: L = R.weight_lattice() - sage: L(x) + sage: L(x) # needs sage.graphs -Lambda[1] + 2*Lambda[2] - Lambda[3] - 2*Lambda[4] + 4*Lambda[5] - 2*Lambda[6] sage: L = R.ambient_space() @@ -94,7 +94,7 @@ class RootLatticeRealizations(Category_over_base_ring): sage: x = alpha[2] + 1/2 * alpha[5] sage: L = R.weight_space() - sage: L(x) + sage: L(x) # needs sage.graphs -Lambda[1] + 2*Lambda[2] - Lambda[3] - 1/2*Lambda[4] + Lambda[5] - 1/2*Lambda[6] sage: L = R.ambient_space() @@ -107,7 +107,8 @@ class RootLatticeRealizations(Category_over_base_ring): sage: L(x) Traceback (most recent call last): ... - TypeError: do not know how to make x (= alpha[2] + 1/2*alpha[5]) an element of self (=Weight lattice of the Root system of type ['A', 7]) + TypeError: do not know how to make x (= alpha[2] + 1/2*alpha[5]) + an element of self (=Weight lattice of the Root system of type ['A', 7]) If `K_1` is a subring of `K_2`, then one could in theory have an embedding from the root space over `K_1` to any root @@ -118,14 +119,16 @@ class RootLatticeRealizations(Category_over_base_ring): sage: L = R.weight_space(K2) sage: alpha = R.root_space(K2).simple_roots() - sage: L(alpha[1]) + sage: L(alpha[1]) # needs sage.graphs 2*Lambda[1] - Lambda[2] sage: alpha = R.root_space(K1).simple_roots() sage: L(alpha[1]) Traceback (most recent call last): ... - TypeError: do not know how to make x (= alpha[1]) an element of self (=Weight space over the Univariate Polynomial Ring in q over Rational Field of the Root system of type ['A', 7]) + TypeError: do not know how to make x (= alpha[1]) an element of self + (=Weight space over the Univariate Polynomial Ring in q + over Rational Field of the Root system of type ['A', 7]) By a slight abuse, the embedding of the root lattice is not actually required to be faithful. Typically for an affine root system, the @@ -133,14 +136,14 @@ class RootLatticeRealizations(Category_over_base_ring): lattice:: sage: R = RootSystem(["A", 3, 1]) - sage: delta = R.root_lattice().null_root() + sage: delta = R.root_lattice().null_root() # needs sage.graphs sage: L = R.weight_lattice() - sage: L(delta) + sage: L(delta) # needs sage.graphs 0 TESTS:: - sage: TestSuite(L).run() + sage: TestSuite(L).run() # needs sage.graphs """ @cached_method @@ -173,7 +176,7 @@ def __init_extra__(self): sage: R = RootSystem(["A",3]) sage: alpha = R.root_lattice().simple_roots() sage: L = R.weight_lattice() - sage: L(alpha[2]) + sage: L(alpha[2]) # needs sage.graphs -Lambda[1] + 2*Lambda[2] - Lambda[3] .. NOTE:: @@ -195,7 +198,7 @@ def __init_extra__(self): # Build and register the embeddings for domain in domains: domain.module_morphism(self.simple_root, - codomain = self + codomain=self ).register_as_coercion() if self.cartan_type().is_affine(): self._to_classical.register_as_conversion() @@ -225,7 +228,7 @@ def dynkin_diagram(self): EXAMPLES:: sage: r = RootSystem(['A',4]).root_space() - sage: r.dynkin_diagram() + sage: r.dynkin_diagram() # needs sage.graphs O---O---O---O 1 2 3 4 A4 @@ -277,20 +280,27 @@ def _name_string_helper(self, name, capitalize=True, base_ring=True, type=True, def some_elements(self): """ - Return some elements of this root lattice realization + Return some elements of this root lattice realization. EXAMPLES:: sage: L = RootSystem(["A",2]).weight_lattice() - sage: L.some_elements() - [2*Lambda[1] + 2*Lambda[2], 2*Lambda[1] - Lambda[2], -Lambda[1] + 2*Lambda[2], Lambda[1], Lambda[2]] + sage: L.some_elements() # needs sage.graphs + [2*Lambda[1] + 2*Lambda[2], 2*Lambda[1] - Lambda[2], + -Lambda[1] + 2*Lambda[2], Lambda[1], Lambda[2]] sage: L = RootSystem(["A",2]).root_lattice() sage: L.some_elements() [2*alpha[1] + 2*alpha[2], alpha[1], alpha[2]] """ - result = [self.an_element()]+list(self.simple_roots()) - if hasattr(self, "fundamental_weights"): - result += list(self.fundamental_weights()) + result = [self.an_element()] + try: + result.extend(self.simple_roots()) + except ImportError: + pass + try: + result.extend(self.fundamental_weights()) + except (AttributeError, ImportError): + pass return result ########################################################################## @@ -299,7 +309,7 @@ def some_elements(self): def _test_root_lattice_realization(self, **options): """ - Runs sanity checks on this root lattice realization + Run sanity checks on this root lattice realization - embedding of the root lattice - embedding of the root space over the same base ring @@ -313,8 +323,11 @@ def _test_root_lattice_realization(self, **options): sage: RootSystem(['A',3]).root_lattice()._test_root_lattice_realization() """ tester = self._tester(**options) - alpha = self.simple_roots() - alphacheck = self.simple_coroots() + try: + alpha = self.simple_roots() + alphacheck = self.simple_coroots() + except ImportError: + return R = self.base_ring() tester.assertEqual(alpha .keys(), self.index_set()) tester.assertEqual(alphacheck.keys(), self.index_set()) @@ -334,7 +347,10 @@ def _test_root_lattice_realization(self, **options): tester.assertEqual(self(root_space .simple_root(i)), alpha[i]) # Check that the scalar products match with the Dynkin diagram - dynkin_diagram = self.dynkin_diagram() + try: + dynkin_diagram = self.dynkin_diagram() + except ImportError: + return for i in self.index_set(): for j in self.index_set(): tester.assertEqual(alpha[j].scalar(alphacheck[i]), R(dynkin_diagram[i,j])) @@ -369,14 +385,14 @@ def _test_root_lattice_realization(self, **options): @cached_method def highest_root(self): """ - Returns the highest root (for an irreducible finite root system) + Return the highest root (for an irreducible finite root system). EXAMPLES:: sage: RootSystem(['A',4]).ambient_space().highest_root() (1, 0, 0, 0, -1) - sage: RootSystem(['E',6]).weight_space().highest_root() + sage: RootSystem(['E',6]).weight_space().highest_root() # needs sage.graphs Lambda[2] """ @@ -389,32 +405,36 @@ def highest_root(self): @cached_method def a_long_simple_root(self): """ - Returns a long simple root, corresponding to the highest outgoing edge + Return a long simple root, corresponding to the highest outgoing edge in the Dynkin diagram. - Caveat: this may be break in affine type `A_{2n}^{(2)}` + .. warning:: - Caveat: meaningful/broken for non irreducible? + This may be broken in affine type `A_{2n}^{(2)}` - TODO: implement CartanType.nodes_by_length as in - MuPAD-Combinat (using CartanType.symmetrizer), and use it - here. + Is it meaningful/broken for non irreducible? + + .. TODO:: + + implement CartanType.nodes_by_length as in + MuPAD-Combinat (using CartanType.symmetrizer), and use it + here. TESTS:: - sage: X=RootSystem(['A',1]).weight_space() - sage: X.a_long_simple_root() + sage: X = RootSystem(['A',1]).weight_space() + sage: X.a_long_simple_root() # needs sage.graphs 2*Lambda[1] - sage: X=RootSystem(['A',5]).weight_space() - sage: X.a_long_simple_root() + sage: X = RootSystem(['A',5]).weight_space() + sage: X.a_long_simple_root() # needs sage.graphs 2*Lambda[1] - Lambda[2] """ if self.dynkin_diagram().rank() == 1: return self.simple_roots()[self.index_set()[0]] - longest=next(self.dynkin_diagram().edge_iterator()) + longest = next(self.dynkin_diagram().edge_iterator()) for j in self.dynkin_diagram().edge_iterator(): - if j[2]>longest[2]: - longest=j + if j[2] > longest[2]: + longest = j return self.simple_roots()[longest[0]] ########################################################################## @@ -424,7 +444,7 @@ def a_long_simple_root(self): @abstract_method def simple_root(self, i): """ - Returns the `i^{th}` simple root. + Return the `i`-th simple root. This should be overridden by any subclass, and typically implemented as a cached method for efficiency. @@ -446,7 +466,7 @@ def simple_root(self, i): @cached_method def simple_roots(self): r""" - Returns the family `(\alpha_i)_{i\in I}` of the simple roots. + Return the family `(\alpha_i)_{i\in I}` of the simple roots. EXAMPLES:: @@ -464,7 +484,7 @@ def simple_roots(self): @cached_method def alpha(self): r""" - Returns the family `(\alpha_i)_{i\in I}` of the simple roots, + Return the family `(\alpha_i)_{i\in I}` of the simple roots, with the extra feature that, for simple irreducible root systems, `\alpha_0` yields the opposite of the highest root. @@ -473,15 +493,14 @@ def alpha(self): sage: alpha = RootSystem(["A",2]).root_lattice().alpha() sage: alpha[1] alpha[1] - sage: alpha[0] + sage: alpha[0] # needs sage.graphs -alpha[1] - alpha[2] - """ if self.root_system.is_finite() and self.root_system.is_irreducible(): - return Family(self.index_set(), self.simple_root, \ - hidden_keys = [0], hidden_function = lambda i: - self.highest_root()) - else: - return self.simple_roots() + return Family(self.index_set(), self.simple_root, + hidden_keys=[0], + hidden_function=lambda i: - self.highest_root()) + return self.simple_roots() @cached_method def basic_imaginary_roots(self): @@ -498,10 +517,11 @@ def basic_imaginary_roots(self): sage: RootSystem(['A', 2]).root_lattice().basic_imaginary_roots() () sage: Q = RootSystem(['A', 2, 1]).root_lattice() - sage: Q.basic_imaginary_roots() + sage: Q.basic_imaginary_roots() # needs sage.graphs (alpha[0] + alpha[1] + alpha[2],) - sage: delta = Q.basic_imaginary_roots()[0] - sage: all(delta.scalar(Q.simple_coroot(i)) <= 0 for i in Q.index_set()) + sage: delta = Q.basic_imaginary_roots()[0] # needs sage.graphs + sage: all(delta.scalar(Q.simple_coroot(i)) <= 0 # needs sage.graphs + ....: for i in Q.index_set()) True """ if self.cartan_type().is_finite(): @@ -534,15 +554,19 @@ def simple_roots_tilde(self): In simply laced cases, this is boring:: - sage: RootSystem(["A",3, 1]).root_lattice().simple_roots_tilde() + sage: RootSystem(["A",3, 1]).root_lattice().simple_roots_tilde() # needs sage.graphs Finite family {0: alpha[0], 1: alpha[1], 2: alpha[2], 3: alpha[3]} This was checked by hand:: - sage: RootSystem(["C",2,1]).coroot_lattice().simple_roots_tilde() - Finite family {0: alphacheck[0] - alphacheck[2], 1: alphacheck[1], 2: alphacheck[2]} - sage: RootSystem(["B",2,1]).coroot_lattice().simple_roots_tilde() - Finite family {0: alphacheck[0] - alphacheck[1], 1: alphacheck[1], 2: alphacheck[2]} + sage: RootSystem(["C",2,1]).coroot_lattice().simple_roots_tilde() # needs sage.graphs + Finite family {0: alphacheck[0] - alphacheck[2], + 1: alphacheck[1], + 2: alphacheck[2]} + sage: RootSystem(["B",2,1]).coroot_lattice().simple_roots_tilde() # needs sage.graphs + Finite family {0: alphacheck[0] - alphacheck[1], + 1: alphacheck[1], + 2: alphacheck[2]} What about type BC? """ @@ -552,7 +576,7 @@ def simple_roots_tilde(self): b = other_affinization.col_annihilator() alpha = self.simple_roots() result = { i: alpha[i] for i in I0 } - result[i0] = (self.null_root() - self.linear_combination( (alpha[i], b[i]) for i in I0))/ b[i0] + result[i0] = (self.null_root() - self.linear_combination( (alpha[i], b[i]) for i in I0)) / b[i0] return Family(result) ########################################################################## @@ -570,8 +594,9 @@ def roots(self): This matches with :wikipedia:`Root_systems`:: - sage: for T in CartanType.samples(finite = True, crystallographic = True): - ....: print("%s %3s %3s"%(T, len(RootSystem(T).root_lattice().roots()), len(RootSystem(T).weight_lattice().roots()))) + sage: for T in CartanType.samples(finite=True, crystallographic=True): # needs sage.graphs + ....: print("%s %3s %3s"%(T, len(RootSystem(T).root_lattice().roots()), + ....: len(RootSystem(T).weight_lattice().roots()))) ['A', 1] 2 2 ['A', 5] 30 30 ['B', 1] 2 2 @@ -595,7 +620,7 @@ def roots(self): if not self.cartan_type().is_finite(): from sage.sets.disjoint_union_enumerated_sets \ import DisjointUnionEnumeratedSets - D = DisjointUnionEnumeratedSets([self.positive_roots(), + D = DisjointUnionEnumeratedSets([self.positive_roots(), self.negative_roots()]) D.rename("All roots of type {}".format(self.cartan_type())) return D @@ -609,7 +634,7 @@ def short_roots(self): EXAMPLES:: sage: L = RootSystem(['B',3]).root_lattice() - sage: sorted(L.short_roots()) + sage: sorted(L.short_roots()) # needs sage.graphs [-alpha[1] - alpha[2] - alpha[3], alpha[1] + alpha[2] + alpha[3], -alpha[2] - alpha[3], @@ -628,7 +653,7 @@ def long_roots(self): EXAMPLES:: sage: L = RootSystem(['B',3]).root_lattice() - sage: sorted(L.long_roots()) + sage: sorted(L.long_roots()) # needs sage.graphs [-alpha[1], -alpha[1] - 2*alpha[2] - 2*alpha[3], -alpha[1] - alpha[2], -alpha[1] - alpha[2] - 2*alpha[3], alpha[1], alpha[1] + alpha[2], @@ -654,20 +679,20 @@ def positive_roots(self, index_set=None): EXAMPLES:: sage: L = RootSystem(['A',3]).root_lattice() - sage: sorted(L.positive_roots()) + sage: sorted(L.positive_roots()) # needs sage.graphs [alpha[1], alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3], alpha[2], alpha[2] + alpha[3], alpha[3]] - sage: sorted(L.positive_roots((1,2))) + sage: sorted(L.positive_roots((1,2))) # needs sage.graphs [alpha[1], alpha[1] + alpha[2], alpha[2]] - sage: sorted(L.positive_roots(())) + sage: sorted(L.positive_roots(())) # needs sage.graphs [] sage: L = RootSystem(['A',3,1]).root_lattice() - sage: PR = L.positive_roots(); PR + sage: PR = L.positive_roots(); PR # needs sage.graphs Disjoint union of Family (Positive real roots of type ['A', 3, 1], Positive imaginary roots of type ['A', 3, 1]) - sage: [PR.unrank(i) for i in range(10)] + sage: [PR.unrank(i) for i in range(10)] # needs sage.graphs [alpha[1], alpha[2], alpha[3], @@ -694,12 +719,12 @@ def positive_roots(self, index_set=None): structure='graded', enumeration='breadth') @cached_method - def nonparabolic_positive_roots(self, index_set = None): + def nonparabolic_positive_roots(self, index_set=None): r""" Return the positive roots of ``self`` that are not in the parabolic subsystem indicated by ``index_set``. - If ``index_set`` is None, as in :meth:`positive_roots` + If ``index_set`` is ``None``, as in :meth:`positive_roots` it is assumed to be the entire Dynkin node set. Then the parabolic subsystem consists of all positive roots and the empty list is returned. @@ -707,12 +732,13 @@ def nonparabolic_positive_roots(self, index_set = None): EXAMPLES:: sage: L = RootSystem(['A',3]).root_lattice() - sage: L.nonparabolic_positive_roots() + sage: L.nonparabolic_positive_roots() # needs sage.graphs [] - sage: sorted(L.nonparabolic_positive_roots((1,2))) + sage: sorted(L.nonparabolic_positive_roots((1,2))) # needs sage.graphs [alpha[1] + alpha[2] + alpha[3], alpha[2] + alpha[3], alpha[3]] - sage: sorted(L.nonparabolic_positive_roots(())) - [alpha[1], alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3], alpha[2], alpha[2] + alpha[3], alpha[3]] + sage: sorted(L.nonparabolic_positive_roots(())) # needs sage.graphs + [alpha[1], alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3], + alpha[2], alpha[2] + alpha[3], alpha[3]] """ if not self.cartan_type().is_finite(): @@ -733,11 +759,11 @@ def nonparabolic_positive_root_sum(self, index_set=None): EXAMPLES:: sage: Q = RootSystem(['A',3]).root_lattice() - sage: Q.nonparabolic_positive_root_sum((1,2)) + sage: Q.nonparabolic_positive_root_sum((1,2)) # needs sage.graphs alpha[1] + 2*alpha[2] + 3*alpha[3] - sage: Q.nonparabolic_positive_root_sum() + sage: Q.nonparabolic_positive_root_sum() # needs sage.graphs 0 - sage: Q.nonparabolic_positive_root_sum(()) + sage: Q.nonparabolic_positive_root_sum(()) # needs sage.graphs 3*alpha[1] + 4*alpha[2] + 3*alpha[3] """ @@ -750,14 +776,14 @@ def positive_real_roots(self): EXAMPLES:: sage: L = RootSystem(['A',3]).root_lattice() - sage: sorted(L.positive_real_roots()) + sage: sorted(L.positive_real_roots()) # needs sage.graphs [alpha[1], alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3], alpha[2], alpha[2] + alpha[3], alpha[3]] sage: L = RootSystem(['A',3,1]).root_lattice() - sage: PRR = L.positive_real_roots(); PRR + sage: PRR = L.positive_real_roots(); PRR # needs sage.graphs Positive real roots of type ['A', 3, 1] - sage: [PRR.unrank(i) for i in range(10)] + sage: [PRR.unrank(i) for i in range(10)] # needs sage.graphs [alpha[1], alpha[2], alpha[3], @@ -770,8 +796,8 @@ def positive_real_roots(self): alpha[0] + 2*alpha[1] + 2*alpha[2] + alpha[3]] sage: Q = RootSystem(['A',4,2]).root_lattice() - sage: PR = Q.positive_roots() - sage: [PR.unrank(i) for i in range(5)] + sage: PR = Q.positive_roots() # needs sage.graphs + sage: [PR.unrank(i) for i in range(5)] # needs sage.graphs [alpha[1], alpha[2], alpha[1] + alpha[2], @@ -779,8 +805,8 @@ def positive_real_roots(self): alpha[0] + alpha[1] + alpha[2]] sage: Q = RootSystem(['D',3,2]).root_lattice() - sage: PR = Q.positive_roots() - sage: [PR.unrank(i) for i in range(5)] + sage: PR = Q.positive_roots() # needs sage.graphs + sage: [PR.unrank(i) for i in range(5)] # needs sage.graphs [alpha[1], alpha[2], alpha[1] + 2*alpha[2], @@ -850,9 +876,9 @@ def positive_imaginary_roots(self): () sage: L = RootSystem(['A',3,1]).root_lattice() - sage: PIR = L.positive_imaginary_roots(); PIR + sage: PIR = L.positive_imaginary_roots(); PIR # needs sage.graphs Positive imaginary roots of type ['A', 3, 1] - sage: [PIR.unrank(i) for i in range(5)] + sage: [PIR.unrank(i) for i in range(5)] # needs sage.graphs [alpha[0] + alpha[1] + alpha[2] + alpha[3], 2*alpha[0] + 2*alpha[1] + 2*alpha[2] + 2*alpha[3], 3*alpha[0] + 3*alpha[1] + 3*alpha[2] + 3*alpha[3], @@ -870,9 +896,9 @@ def positive_imaginary_roots(self): return F @cached_method - def positive_roots_by_height(self, increasing = True): + def positive_roots_by_height(self, increasing=True): r""" - Returns a list of positive roots in increasing order by height. + Return a list of positive roots in increasing order by height. If ``increasing`` is False, returns them in decreasing order. @@ -883,13 +909,13 @@ def positive_roots_by_height(self, increasing = True): EXAMPLES:: sage: L = RootSystem(['C',2]).root_lattice() - sage: L.positive_roots_by_height() + sage: L.positive_roots_by_height() # needs sage.graphs [alpha[2], alpha[1], alpha[1] + alpha[2], 2*alpha[1] + alpha[2]] - sage: L.positive_roots_by_height(increasing = False) + sage: L.positive_roots_by_height(increasing=False) # needs sage.graphs [2*alpha[1] + alpha[2], alpha[1] + alpha[2], alpha[2], alpha[1]] sage: L = RootSystem(['A',2,1]).root_lattice() - sage: L.positive_roots_by_height() + sage: L.positive_roots_by_height() # needs sage.graphs Traceback (most recent call last): ... NotImplementedError: Only implemented for finite Cartan type @@ -907,23 +933,26 @@ def positive_roots_by_height(self, increasing = True): return [x.element for x in roots] @cached_method - def positive_roots_parabolic(self, index_set = None): + def positive_roots_parabolic(self, index_set=None): r""" Return the set of positive roots for the parabolic subsystem with Dynkin node set ``index_set``. INPUT: - - ``index_set`` -- (default:None) the Dynkin node set of the parabolic subsystem. It should be a tuple. The default value implies the entire Dynkin node set + - ``index_set`` -- (default: ``None``) the Dynkin node set of the + parabolic subsystem. It should be a tuple. The default value + implies the entire Dynkin node set EXAMPLES:: sage: lattice = RootSystem(['A',3]).root_lattice() - sage: sorted(lattice.positive_roots_parabolic((1,3)), key=str) + sage: sorted(lattice.positive_roots_parabolic((1,3)), key=str) # needs sage.graphs [alpha[1], alpha[3]] - sage: sorted(lattice.positive_roots_parabolic((2,3)), key=str) + sage: sorted(lattice.positive_roots_parabolic((2,3)), key=str) # needs sage.graphs [alpha[2], alpha[2] + alpha[3], alpha[3]] - sage: sorted(lattice.positive_roots_parabolic(), key=str) - [alpha[1], alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3], alpha[2], alpha[2] + alpha[3], alpha[3]] + sage: sorted(lattice.positive_roots_parabolic(), key=str) # needs sage.graphs + [alpha[1], alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3], + alpha[2], alpha[2] + alpha[3], alpha[3]] .. WARNING:: @@ -942,19 +971,23 @@ def parabolic_covers(alpha): structure='graded', enumeration='breadth') @cached_method - def positive_roots_nonparabolic(self, index_set = None): + def positive_roots_nonparabolic(self, index_set=None): r""" - Returns the set of positive roots outside the parabolic subsystem with Dynkin node set ``index_set``. + Return the set of positive roots outside the parabolic subsystem with Dynkin node set ``index_set``. INPUT: - - ``index_set`` -- (default:None) the Dynkin node set of the parabolic subsystem. It should be a tuple. The default value implies the entire Dynkin node set + - ``index_set`` -- (default: ``None``) the Dynkin node set of the + parabolic subsystem. It should be a tuple. The default value + implies the entire Dynkin node set EXAMPLES:: - sage: lattice = RootSystem(['A',3]).root_lattice() + sage: # needs sage.graphs + sage: lattice = RootSystem(['A',3]).root_lattice() sage: sorted(lattice.positive_roots_nonparabolic((1,3)), key=str) - [alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3], alpha[2], alpha[2] + alpha[3]] + [alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3], + alpha[2], alpha[2] + alpha[3]] sage: sorted(lattice.positive_roots_nonparabolic((2,3)), key=str) [alpha[1], alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3]] sage: lattice.positive_roots_nonparabolic() @@ -974,17 +1007,20 @@ def positive_roots_nonparabolic(self, index_set = None): return [x for x in self.positive_roots() if not x.is_parabolic_root(index_set)] @cached_method - def positive_roots_nonparabolic_sum(self, index_set = None): + def positive_roots_nonparabolic_sum(self, index_set=None): r""" - Returns the sum of positive roots outside the parabolic subsystem with Dynkin node set ``index_set``. + Return the sum of positive roots outside the parabolic subsystem with Dynkin node set ``index_set``. INPUT: - - ``index_set`` -- (default:None) the Dynkin node set of the parabolic subsystem. It should be a tuple. The default value implies the entire Dynkin node set + - ``index_set`` -- (default: ``None``) the Dynkin node set of the + parabolic subsystem. It should be a tuple. The default value + implies the entire Dynkin node set EXAMPLES:: - sage: lattice = RootSystem(['A',3]).root_lattice() + sage: # needs sage.graphs + sage: lattice = RootSystem(['A',3]).root_lattice() sage: lattice.positive_roots_nonparabolic_sum((1,3)) 2*alpha[1] + 4*alpha[2] + 2*alpha[3] sage: lattice.positive_roots_nonparabolic_sum((2,3)) @@ -1010,34 +1046,32 @@ def positive_roots_nonparabolic_sum(self, index_set = None): def root_poset(self, restricted=False, facade=False): r""" - Returns the (restricted) root poset associated to ``self``. + Return the (restricted) root poset associated to ``self``. The elements are given by the positive roots (resp. non-simple, positive roots), and `\alpha \leq \beta` iff `\beta - \alpha` is a non-negative linear combination of simple roots. INPUT: - - ``restricted`` -- (default:False) if True, only non-simple roots are considered. - - ``facade`` -- (default:False) passes facade option to the poset generator. + - ``restricted`` -- (default: ``False``) if ``True``, only non-simple roots are considered. + - ``facade`` -- (default: ``False``) passes facade option to the poset generator. EXAMPLES:: + sage: # needs sage.graphs sage: Phi = RootSystem(['A',1]).root_poset(); Phi Finite poset containing 1 elements sage: Phi.cover_relations() [] - sage: Phi = RootSystem(['A',2]).root_poset(); Phi Finite poset containing 3 elements - sage: sorted(Phi.cover_relations(), key=str) [[alpha[1], alpha[1] + alpha[2]], [alpha[2], alpha[1] + alpha[2]]] - sage: Phi = RootSystem(['A',3]).root_poset(restricted=True); Phi Finite poset containing 3 elements sage: sorted(Phi.cover_relations(), key=str) - [[alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3]], [alpha[2] + alpha[3], alpha[1] + alpha[2] + alpha[3]]] - + [[alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3]], + [alpha[2] + alpha[3], alpha[1] + alpha[2] + alpha[3]]] sage: Phi = RootSystem(['B',2]).root_poset(); Phi Finite poset containing 4 elements sage: sorted(Phi.cover_relations(), key=str) @@ -1049,7 +1083,7 @@ def root_poset(self, restricted=False, facade=False): Check that :trac:`17982` is fixed:: - sage: RootSystem(['A', 2]).ambient_space().root_poset() + sage: RootSystem(['A', 2]).ambient_space().root_poset() # needs sage.graphs Finite poset containing 3 elements """ from sage.combinat.posets.posets import Poset @@ -1067,7 +1101,7 @@ def root_poset(self, restricted=False, facade=False): def nonnesting_partition_lattice(self, facade=False): r""" - Return the lattice of nonnesting partitions + Return the lattice of nonnesting partitions. This is the lattice of order ideals of the root poset. @@ -1081,11 +1115,12 @@ def nonnesting_partition_lattice(self, facade=False): sage: R = RootSystem(['A', 3]) sage: RS = R.root_lattice() - sage: P = RS.nonnesting_partition_lattice(); P + sage: P = RS.nonnesting_partition_lattice(); P # needs sage.graphs Finite lattice containing 14 elements - sage: P.coxeter_transformation()**10 == 1 + sage: P.coxeter_transformation()**10 == 1 # needs sage.graphs True + sage: # needs sage.graphs sage: R = RootSystem(['B', 3]) sage: RS = R.root_lattice() sage: P = RS.nonnesting_partition_lattice(); P @@ -1104,7 +1139,7 @@ def nonnesting_partition_lattice(self, facade=False): def generalized_nonnesting_partition_lattice(self, m, facade=False): r""" - Return the lattice of `m`-nonnesting partitions + Return the lattice of `m`-nonnesting partitions. This has been defined by Athanasiadis, see chapter 5 of [Arm06]_. @@ -1120,9 +1155,9 @@ def generalized_nonnesting_partition_lattice(self, m, facade=False): sage: R = RootSystem(['A', 2]) sage: RS = R.root_lattice() - sage: P = RS.generalized_nonnesting_partition_lattice(2); P + sage: P = RS.generalized_nonnesting_partition_lattice(2); P # needs sage.graphs Finite lattice containing 12 elements - sage: P.coxeter_transformation()**20 == 1 + sage: P.coxeter_transformation()**20 == 1 # needs sage.graphs True """ Phi_plus = self.positive_roots() @@ -1164,7 +1199,7 @@ def is_componentwise_subset(chain1, chain2): def almost_positive_roots(self): r""" - Returns the almost positive roots of ``self`` + Return the almost positive roots of ``self``. These are the positive roots together with the simple negative roots. @@ -1173,7 +1208,7 @@ def almost_positive_roots(self): EXAMPLES:: sage: L = RootSystem(['A',2]).root_lattice() - sage: L.almost_positive_roots() + sage: L.almost_positive_roots() # needs sage.graphs [-alpha[1], alpha[1], alpha[1] + alpha[2], -alpha[2], alpha[2]] """ if not self.cartan_type().is_finite(): @@ -1182,12 +1217,12 @@ def almost_positive_roots(self): def negative_roots(self): r""" - Returns the negative roots of self. + Return the negative roots of ``self``. EXAMPLES:: sage: L = RootSystem(['A', 2]).weight_lattice() - sage: sorted(L.negative_roots()) + sage: sorted(L.negative_roots()) # needs sage.graphs [-2*Lambda[1] + Lambda[2], -Lambda[1] - Lambda[2], Lambda[1] - 2*Lambda[2]] Algorithm: negate the positive roots @@ -1203,7 +1238,7 @@ def negative_roots(self): def coroot_lattice(self): """ - Returns the coroot lattice. + Return the coroot lattice. EXAMPLES:: @@ -1213,7 +1248,7 @@ def coroot_lattice(self): """ return self.root_system.coroot_lattice() - def coroot_space(self, base_ring = QQ): + def coroot_space(self, base_ring=QQ): r""" Return the coroot space over ``base_ring``. @@ -1227,10 +1262,11 @@ def coroot_space(self, base_ring = QQ): Coroot space over the Rational Field of the Root system of type ['A', 2] sage: RootSystem(['A',2]).root_lattice().coroot_space(QQ['q']) - Coroot space over the Univariate Polynomial Ring in q over Rational Field of the Root system of type ['A', 2] + Coroot space over the Univariate Polynomial Ring in q over Rational Field + of the Root system of type ['A', 2] """ - return self.root_system.coroot_space(base_ring = base_ring) + return self.root_system.coroot_space(base_ring=base_ring) def simple_coroot(self, i): """ @@ -1301,7 +1337,7 @@ def alphacheck(self): @cached_method def cohighest_root(self): """ - Returns the associated coroot of the highest root. + Return the associated coroot of the highest root. .. note:: this is usually not the highest coroot. @@ -1319,17 +1355,19 @@ def cohighest_root(self): @cached_method def null_root(self): """ - Returns the null root of self. The null root is the smallest - non trivial positive root which is orthogonal to all simple - coroots. It exists for any affine root system. + Return the null root of ``self``. + + The null root is the smallest non trivial positive root which is + orthogonal to all simple coroots. It exists for any affine root + system. EXAMPLES:: - sage: RootSystem(['C',2,1]).root_lattice().null_root() + sage: RootSystem(['C',2,1]).root_lattice().null_root() # needs sage.graphs alpha[0] + 2*alpha[1] + alpha[2] - sage: RootSystem(['D',4,1]).root_lattice().null_root() + sage: RootSystem(['D',4,1]).root_lattice().null_root() # needs sage.graphs alpha[0] + alpha[1] + 2*alpha[2] + alpha[3] + alpha[4] - sage: RootSystem(['F',4,1]).root_lattice().null_root() + sage: RootSystem(['F',4,1]).root_lattice().null_root() # needs sage.graphs alpha[0] + 2*alpha[1] + 3*alpha[2] + 4*alpha[3] + 2*alpha[4] """ if self.cartan_type().is_affine(): @@ -1343,20 +1381,22 @@ def null_root(self): @cached_method def null_coroot(self): """ - Returns the null coroot of self. + Return the null coroot of ``self``. - The null coroot is the smallest non trivial positive - coroot which is orthogonal to all simple roots. It exists - for any affine root system. + The null coroot is the smallest non trivial positive coroot which is + orthogonal to all simple roots. It exists for any affine root + system. EXAMPLES:: - sage: RootSystem(['C',2,1]).root_lattice().null_coroot() + sage: RootSystem(['C',2,1]).root_lattice().null_coroot() # needs sage.graphs alphacheck[0] + alphacheck[1] + alphacheck[2] - sage: RootSystem(['D',4,1]).root_lattice().null_coroot() - alphacheck[0] + alphacheck[1] + 2*alphacheck[2] + alphacheck[3] + alphacheck[4] - sage: RootSystem(['F',4,1]).root_lattice().null_coroot() - alphacheck[0] + 2*alphacheck[1] + 3*alphacheck[2] + 2*alphacheck[3] + alphacheck[4] + sage: RootSystem(['D',4,1]).root_lattice().null_coroot() # needs sage.graphs + alphacheck[0] + alphacheck[1] + 2*alphacheck[2] + + alphacheck[3] + alphacheck[4] + sage: RootSystem(['F',4,1]).root_lattice().null_coroot() # needs sage.graphs + alphacheck[0] + 2*alphacheck[1] + 3*alphacheck[2] + + 2*alphacheck[3] + alphacheck[4] """ if not self.cartan_type().is_affine(): raise ValueError("%s is not an affine Cartan type" % (self.cartan_type())) @@ -1381,11 +1421,11 @@ def fundamental_weights_from_simple_roots(self): In the root space, we retrieve the inverse of the Cartan matrix:: sage: L = RootSystem(["B",3]).root_space() - sage: L.fundamental_weights_from_simple_roots() + sage: L.fundamental_weights_from_simple_roots() # needs sage.graphs Finite family {1: alpha[1] + alpha[2] + alpha[3], 2: alpha[1] + 2*alpha[2] + 2*alpha[3], 3: 1/2*alpha[1] + alpha[2] + 3/2*alpha[3]} - sage: ~L.cartan_type().cartan_matrix() + sage: ~L.cartan_type().cartan_matrix() # needs sage.graphs [ 1 1 1/2] [ 1 2 1] [ 1 2 3/2] @@ -1394,37 +1434,41 @@ def fundamental_weights_from_simple_roots(self): the fundamental weights:: sage: L = RootSystem(["B",3]).weight_lattice() - sage: L.fundamental_weights_from_simple_roots() + sage: L.fundamental_weights_from_simple_roots() # needs sage.graphs Finite family {1: Lambda[1], 2: Lambda[2], 3: Lambda[3]} sage: L = RootSystem(["B",3]).ambient_space() sage: L.fundamental_weights() Finite family {1: (1, 0, 0), 2: (1, 1, 0), 3: (1/2, 1/2, 1/2)} - sage: L.fundamental_weights_from_simple_roots() + sage: L.fundamental_weights_from_simple_roots() # needs sage.graphs Finite family {1: (1, 0, 0), 2: (1, 1, 0), 3: (1/2, 1/2, 1/2)} However the fundamental weights do not belong to the root lattice:: sage: L = RootSystem(["B",3]).root_lattice() - sage: L.fundamental_weights_from_simple_roots() + sage: L.fundamental_weights_from_simple_roots() # needs sage.graphs Traceback (most recent call last): ... - ValueError: The fundamental weights do not live in this realization of the root lattice + ValueError: The fundamental weights do not live in this realization + of the root lattice Beware of the usual `GL_n` vs `SL_n` catch in type `A`:: sage: L = RootSystem(["A",3]).ambient_space() sage: L.fundamental_weights() Finite family {1: (1, 0, 0, 0), 2: (1, 1, 0, 0), 3: (1, 1, 1, 0)} - sage: L.fundamental_weights_from_simple_roots() - Finite family {1: (3/4, -1/4, -1/4, -1/4), 2: (1/2, 1/2, -1/2, -1/2), 3: (1/4, 1/4, 1/4, -3/4)} + sage: L.fundamental_weights_from_simple_roots() # needs sage.graphs + Finite family {1: (3/4, -1/4, -1/4, -1/4), + 2: (1/2, 1/2, -1/2, -1/2), + 3: (1/4, 1/4, 1/4, -3/4)} sage: L = RootSystem(["A",3]).ambient_lattice() - sage: L.fundamental_weights_from_simple_roots() + sage: L.fundamental_weights_from_simple_roots() # needs sage.graphs Traceback (most recent call last): ... - ValueError: The fundamental weights do not live in this realization of the root lattice + ValueError: The fundamental weights do not live in this realization + of the root lattice """ # We first scale the inverse of the Cartan matrix to be # with integer coefficients; then the linear combination @@ -1449,15 +1493,15 @@ def fundamental_weights_from_simple_roots(self): def reflection(self, root, coroot=None): """ - Returns the reflection along the root, and across the - hyperplane define by coroot, as a function from - self to self. + Return the reflection along the ``root``, and across the hyperplane + defined by ``coroot``, as a function from ``self`` to ``self``. EXAMPLES:: + sage: # needs sage.graphs sage: space = RootSystem(['A',2]).weight_lattice() - sage: x=space.simple_roots()[1] - sage: y=space.simple_coroots()[1] + sage: x = space.simple_roots()[1] + sage: y = space.simple_coroots()[1] sage: s = space.reflection(x,y) sage: x 2*Lambda[1] - Lambda[2] @@ -1473,19 +1517,18 @@ def reflection(self, root, coroot=None): @cached_method def simple_reflection(self, i): """ - Returns the `i^{th}` simple reflection, as a function from - self to self. + Return the `i`-th simple reflection, as a function from + ``self`` to ``self``. INPUT: - - ``i`` - i is in self's index set + - ``i`` -- an element of the index set of ``self`` EXAMPLES:: sage: space = RootSystem(['A',2]).ambient_lattice() sage: s = space.simple_reflection(1) - sage: x = space.simple_roots()[1] - sage: x + sage: x = space.simple_roots()[1]; x (1, -1, 0) sage: s(x) (-1, 1, 0) @@ -1502,7 +1545,7 @@ def simple_reflections(self): sage: r = RootSystem(["A", 2]).root_lattice() sage: s = r.simple_reflections() - sage: s[1]( r.simple_root(1) ) + sage: s[1]( r.simple_root(1) ) # needs sage.graphs -alpha[1] TESTS:: @@ -1510,7 +1553,7 @@ def simple_reflections(self): sage: s simple reflections """ - res = self.alpha().zip(self.reflection, self.alphacheck()) + res = self.alpha().zip(self.reflection, self.alphacheck()) # Should we use rename to set a nice name for this family? res.rename("simple reflections") return res @@ -1523,19 +1566,22 @@ def simple_reflections(self): def projection(self, root, coroot=None, to_negative=True): r""" - Returns the projection along the root, and across the - hyperplane define by coroot, as a function `\pi` from self to - self. `\pi` is a half-linear map which stabilizes the negative - half space, and acts by reflection on the positive half space. + Return the projection along the ``root``, and across the + hyperplane defined by ``coroot``, as a function `\pi` from ``self`` to + ``self``. - If to_negative is False, then this project onto the positive + `\pi` is a half-linear map which stabilizes the negative + half space and acts by reflection on the positive half space. + + If ``to_negative`` is ``False``, then project onto the positive half space instead. EXAMPLES:: + sage: # needs sage.graphs sage: space = RootSystem(['A',2]).weight_lattice() - sage: x=space.simple_roots()[1] - sage: y=space.simple_coroots()[1] + sage: x = space.simple_roots()[1] + sage: y = space.simple_coroots()[1] sage: pi = space.projection(x,y) sage: x 2*Lambda[1] - Lambda[2] @@ -1555,16 +1601,17 @@ def projection(self, root, coroot=None, to_negative=True): @cached_method def simple_projection(self, i, to_negative=True): """ - Returns the projection along the `i^{th}` simple root, and across the - hyperplane define by the `i^{th}` simple coroot, as a function from - self to self. + Return the projection along the `i`-th simple root, and across the + hyperplane define by the `i`-th simple coroot, as a function from + ``self`` to ``self``. INPUT: - - ``i`` - i is in self's index set + - ``i`` -- an element of the index set of ``self`` EXAMPLES:: + sage: # needs sage.graphs sage: space = RootSystem(['A',2]).weight_lattice() sage: x = space.simple_roots()[1] sage: pi = space.simple_projection(1) @@ -1583,20 +1630,20 @@ def simple_projection(self, i, to_negative=True): @cached_method def simple_projections(self, to_negative=True): r""" - Returns the family `(s_i)_{i\in I}` of the simple projections - of this root system + Return the family `(s_i)_{i\in I}` of the simple projections + of this root system. EXAMPLES:: sage: space = RootSystem(['A',2]).weight_lattice() - sage: pi = space.simple_projections() - sage: x = space.simple_roots() - sage: pi[1](x[2]) + sage: pi = space.simple_projections() # needs sage.graphs + sage: x = space.simple_roots() # needs sage.graphs + sage: pi[1](x[2]) # needs sage.graphs -Lambda[1] + 2*Lambda[2] TESTS:: - sage: pi + sage: pi # needs sage.graphs pi """ if to_negative is not True: @@ -1612,13 +1659,13 @@ def simple_projections(self, to_negative=True): def weyl_group(self, prefix=None): """ - Returns the Weyl group associated to self. + Return the Weyl group associated to ``self``. EXAMPLES:: - sage: RootSystem(['F',4]).ambient_space().weyl_group() + sage: RootSystem(['F',4]).ambient_space().weyl_group() # needs sage.libs.gap Weyl Group of type ['F', 4] (as a matrix group acting on the ambient space) - sage: RootSystem(['F',4]).root_space().weyl_group() + sage: RootSystem(['F',4]).root_space().weyl_group() # needs sage.libs.gap Weyl Group of type ['F', 4] (as a matrix group acting on the root space) """ @@ -1635,7 +1682,7 @@ def weyl_group(self, prefix=None): # create conflicts def tau_epsilon_operator_on_almost_positive_roots(self, J): r""" - The `\tau_\epsilon` operator on almost positive roots + The `\tau_\epsilon` operator on almost positive roots. Given a subset `J` of non adjacent vertices of the Dynkin diagram, this constructs the operator on the almost positive @@ -1651,22 +1698,22 @@ def tau_epsilon_operator_on_almost_positive_roots(self, J): EXAMPLES:: sage: L = RootSystem(['A',4]).root_lattice() - sage: tau = L.tau_epsilon_operator_on_almost_positive_roots([1,3]) - sage: alpha = L.simple_roots() + sage: tau = L.tau_epsilon_operator_on_almost_positive_roots([1,3]) # needs sage.libs.gap + sage: alpha = L.simple_roots() # needs sage.graphs The action on a negative simple root not in `J`:: - sage: tau(-alpha[2]) + sage: tau(-alpha[2]) # needs sage.graphs sage.libs.gap -alpha[2] The action on a negative simple root in `J`:: - sage: tau(-alpha[1]) + sage: tau(-alpha[1]) # needs sage.graphs sage.libs.gap alpha[1] The action on all almost positive roots:: - sage: for root in L.almost_positive_roots(): + sage: for root in L.almost_positive_roots(): # needs sage.graphs sage.libs.gap ....: print('tau({:<41}) = {}'.format(str(root), tau(root))) tau(-alpha[1] ) = alpha[1] tau(alpha[1] ) = -alpha[1] @@ -1686,8 +1733,8 @@ def tau_epsilon_operator_on_almost_positive_roots(self, J): This method works on any root lattice realization:: sage: L = RootSystem(['B',3]).ambient_space() - sage: tau = L.tau_epsilon_operator_on_almost_positive_roots([1,3]) - sage: for root in L.almost_positive_roots(): + sage: tau = L.tau_epsilon_operator_on_almost_positive_roots([1,3]) # needs sage.libs.gap + sage: for root in L.almost_positive_roots(): # needs sage.graphs sage.libs.gap ....: print('tau({:<41}) = {}'.format(str(root), tau(root))) tau((-1, 1, 0) ) = (1, -1, 0) tau((1, 0, 0) ) = (0, 1, 0) @@ -1718,7 +1765,7 @@ def tau_epsilon(alpha): def tau_plus_minus(self): r""" - Returns the `\tau^+` and `\tau^-` piecewise linear operators on ``self`` + Return the `\tau^+` and `\tau^-` piecewise linear operators on ``self``. Those operators are induced by the bipartition `\{L,R\}` of the simple roots of ``self``, and stabilize the almost @@ -1742,8 +1789,9 @@ def tau_plus_minus(self): We explore the example of [CFZ2002]_ Eq.(1.3):: sage: S = RootSystem(['A',2]).root_lattice() - sage: taup, taum = S.tau_plus_minus() - sage: for beta in S.almost_positive_roots(): print("{} , {} , {}".format(beta, taup(beta), taum(beta))) + sage: taup, taum = S.tau_plus_minus() # needs sage.graphs + sage: for beta in S.almost_positive_roots(): # needs sage.graphs + ....: print("{} , {} , {}".format(beta, taup(beta), taum(beta))) -alpha[1] , alpha[1] , -alpha[1] alpha[1] , -alpha[1] , alpha[1] + alpha[2] alpha[1] + alpha[2] , alpha[2] , alpha[1] @@ -1756,7 +1804,7 @@ def tau_plus_minus(self): def almost_positive_roots_decomposition(self): r""" - Returns the decomposition of the almost positive roots of ``self`` + Return the decomposition of the almost positive roots of ``self``. This is the list of the orbits of the almost positive roots under the action of the dihedral group generated by the @@ -1769,15 +1817,17 @@ def almost_positive_roots_decomposition(self): EXAMPLES:: - sage: RootSystem(['A',2]).root_lattice().almost_positive_roots_decomposition() + sage: RootSystem(['A',2]).root_lattice().almost_positive_roots_decomposition() # needs sage.graphs [[-alpha[1], alpha[1], alpha[1] + alpha[2], alpha[2], -alpha[2]]] - sage: RootSystem(['B',2]).root_lattice().almost_positive_roots_decomposition() - [[-alpha[1], alpha[1], alpha[1] + 2*alpha[2]], [-alpha[2], alpha[2], alpha[1] + alpha[2]]] + sage: RootSystem(['B',2]).root_lattice().almost_positive_roots_decomposition() # needs sage.graphs + [[-alpha[1], alpha[1], alpha[1] + 2*alpha[2]], + [-alpha[2], alpha[2], alpha[1] + alpha[2]]] - sage: RootSystem(['D',4]).root_lattice().almost_positive_roots_decomposition() + sage: RootSystem(['D',4]).root_lattice().almost_positive_roots_decomposition() # needs sage.graphs [[-alpha[1], alpha[1], alpha[1] + alpha[2], alpha[2] + alpha[3] + alpha[4]], - [-alpha[2], alpha[2], alpha[1] + alpha[2] + alpha[3] + alpha[4], alpha[1] + 2*alpha[2] + alpha[3] + alpha[4]], + [-alpha[2], alpha[2], alpha[1] + alpha[2] + alpha[3] + alpha[4], + alpha[1] + 2*alpha[2] + alpha[3] + alpha[4]], [-alpha[3], alpha[3], alpha[2] + alpha[3], alpha[1] + alpha[2] + alpha[4]], [-alpha[4], alpha[4], alpha[2] + alpha[4], alpha[1] + alpha[2] + alpha[3]]] """ @@ -1871,7 +1921,7 @@ def _to_classical(self): sage: L._to_classical(e[2]) (0, 0, 1) """ - return self.module_morphism(self._to_classical_on_basis, codomain = self.classical()) + return self.module_morphism(self._to_classical_on_basis, codomain=self.classical()) def _classical_alpha_0(self): """ @@ -1885,22 +1935,22 @@ def _classical_alpha_0(self): This is the opposite of the highest root in the untwisted case:: sage: L = RootSystem(["B",3,1]).root_space() - sage: L._classical_alpha_0() + sage: L._classical_alpha_0() # needs sage.graphs -alpha[1] - 2*alpha[2] - 2*alpha[3] - sage: L._to_classical_on_basis(0) + sage: L._to_classical_on_basis(0) # needs sage.graphs -alpha[1] - 2*alpha[2] - 2*alpha[3] - sage: L.classical().highest_root() + sage: L.classical().highest_root() # needs sage.graphs alpha[1] + 2*alpha[2] + 2*alpha[3] But not in the other cases:: sage: L = RootSystem(CartanType(["B",3,1]).dual()).root_space() - sage: L._to_classical_on_basis(0) + sage: L._to_classical_on_basis(0) # needs sage.graphs -alpha[1] - 2*alpha[2] - alpha[3] - sage: L.classical().highest_root() + sage: L.classical().highest_root() # needs sage.graphs 2*alpha[1] + 2*alpha[2] + alpha[3] """ - cartan_type = self.cartan_type() + cartan_type = self.cartan_type() special_node = cartan_type.special_node() a = self.cartan_type().col_annihilator() classical = self.classical() @@ -2030,7 +2080,7 @@ def plot(self, EXAMPLES:: - sage: L = RootSystem(["A",2,1]).ambient_space().plot() # long time + sage: L = RootSystem(["A",2,1]).ambient_space().plot() # long time, needs sage.plot sage.symbolic .. SEEALSO:: @@ -2095,8 +2145,7 @@ def plot_parse_options(self, **args): EXAMPLES:: sage: L = RootSystem(["A",2,1]).ambient_space() - sage: options = L.plot_parse_options() - sage: options + sage: options = L.plot_parse_options(); options # needs sage.symbolic <sage.combinat.root_system.plot.PlotOptions object at ...> .. SEEALSO:: @@ -2121,7 +2170,7 @@ def _plot_projection(self, x): sage: L = RootSystem(["B",3]).root_lattice() sage: l = L.an_element(); l 2*alpha[1] + 2*alpha[2] + 3*alpha[3] - sage: L._plot_projection(l) + sage: L._plot_projection(l) # needs sage.symbolic 2*alpha[1] + 2*alpha[2] + 3*alpha[3] In the ambient space of type `A_2`, this is the @@ -2155,6 +2204,7 @@ def _plot_projection_barycentric_matrix(self): EXAMPLES:: + sage: # needs sage.symbolic sage: RootSystem(["A",0]).ambient_space()._plot_projection_barycentric_matrix() [] sage: m = RootSystem(["A",1]).ambient_space()._plot_projection_barycentric_matrix(); m @@ -2181,7 +2231,7 @@ def _plot_projection_barycentric_matrix(self): # original matrix and for the current rational # approximation. We tidy up the work by replacing the # first column by the opposite of the sum of the others. - if self.dimension()>1: # not needed in the trivial cases + if self.dimension() > 1: # not needed in the trivial cases m.set_column(0, -sum(m[:,1:].columns())) m.set_immutable() return m @@ -2198,11 +2248,11 @@ def _plot_projection_barycentric(self, x): sage: L = RootSystem(["A",2]).ambient_space() sage: e = L.basis() - sage: L._plot_projection_barycentric(e[0]) + sage: L._plot_projection_barycentric(e[0]) # needs sage.symbolic (1/2, 989/1142) - sage: L._plot_projection_barycentric(e[1]) + sage: L._plot_projection_barycentric(e[1]) # needs sage.symbolic (-1, 0) - sage: L._plot_projection_barycentric(e[2]) + sage: L._plot_projection_barycentric(e[2]) # needs sage.symbolic (1/2, -989/1142) .. SEEALSO:: @@ -2236,36 +2286,36 @@ def plot_roots(self, collection="simple", **options): EXAMPLES:: - sage: RootSystem(["B",3]).ambient_space().plot_roots() + sage: RootSystem(["B",3]).ambient_space().plot_roots() # needs sage.plot Graphics3d Object - sage: RootSystem(["B",3]).ambient_space().plot_roots("all") + sage: RootSystem(["B",3]).ambient_space().plot_roots("all") # needs sage.plot Graphics3d Object TESTS:: - sage: list(RootSystem(["A",2]).root_lattice().plot_roots()) + sage: list(RootSystem(["A",2]).root_lattice().plot_roots()) # needs sage.plot sage.symbolic [Arrow from (0.0,0.0) to (1.0,0.0), Text '$\alpha_{1}$' at the point (1.05,0.0), Arrow from (0.0,0.0) to (0.0,1.0), Text '$\alpha_{2}$' at the point (0.0,1.05)] - sage: list(RootSystem(["A",2]).weight_lattice().plot_roots(labels=False)) + sage: list(RootSystem(["A",2]).weight_lattice().plot_roots(labels=False)) # needs sage.plot sage.symbolic [Arrow from (0.0,0.0) to (2.0,-1.0), Arrow from (0.0,0.0) to (-1.0,2.0)] - sage: list(RootSystem(["A",2]).ambient_lattice().plot_roots()) + sage: list(RootSystem(["A",2]).ambient_lattice().plot_roots()) # needs sage.plot sage.symbolic [Arrow from (0.0,0.0) to (1.5,0.86...), Text '$\alpha_{1}$' at the point (1.575...,0.90...), Arrow from (0.0,0.0) to (-1.5,0.86...), Text '$\alpha_{2}$' at the point (-1.575...,0.90...)] - sage: list(RootSystem(["B",2]).ambient_space().plot_roots()) + sage: list(RootSystem(["B",2]).ambient_space().plot_roots()) # needs sage.plot sage.symbolic [Arrow from (0.0,0.0) to (1.0,-1.0), Text '$\alpha_{1}$' at the point (1.05,-1.05), Arrow from (0.0,0.0) to (0.0,1.0), Text '$\alpha_{2}$' at the point (0.0,1.05)] - sage: list(RootSystem(["A",2]).root_lattice().plot_roots("all")) + sage: list(RootSystem(["A",2]).root_lattice().plot_roots("all")) # needs sage.plot sage.symbolic [Arrow from (0.0,0.0) to (1.0,0.0), Text '$\alpha_{1}$' at the point (1.05,0.0), Arrow from (0.0,0.0) to (0.0,1.0), @@ -2294,7 +2344,7 @@ def plot_roots(self, collection="simple", **options): elif isinstance(collection, (list, tuple)): roots = collection else: - raise ValueError("Unknown value: %s"%collection) + raise ValueError("Unknown value: %s" % collection) roots = Family(roots, self) return plot_options.family_of_vectors(roots) @@ -2321,12 +2371,12 @@ def plot_coroots(self, collection="simple", **options): EXAMPLES:: - sage: RootSystem(["B",3]).ambient_space().plot_coroots() + sage: RootSystem(["B",3]).ambient_space().plot_coroots() # needs sage.plot sage.symbolic Graphics3d Object TESTS:: - sage: list(RootSystem(["B",2]).ambient_space().plot_coroots()) + sage: list(RootSystem(["B",2]).ambient_space().plot_coroots()) # needs sage.plot sage.symbolic [Arrow from (0.0,0.0) to (1.0,-1.0), Text '$\alpha^\vee_{1}$' at the point (1.05,-1.05), Arrow from (0.0,0.0) to (0.0,2.0), @@ -2351,7 +2401,7 @@ def plot_coroots(self, collection="simple", **options): elif isinstance(collection, (list, tuple)): coroots = collection else: - raise ValueError("Unknown value: %s"%collection) + raise ValueError("Unknown value: %s" % collection) coroots = Family(coroots, self) return plot_options.family_of_vectors(coroots) @@ -2371,18 +2421,18 @@ def plot_fundamental_weights(self, **options): EXAMPLES:: - sage: RootSystem(["B",3]).ambient_space().plot_fundamental_weights() + sage: RootSystem(["B",3]).ambient_space().plot_fundamental_weights() # needs sage.plot Graphics3d Object TESTS:: - sage: sorted(RootSystem(["A",2]).weight_lattice().plot_fundamental_weights(), key=str) + sage: sorted(RootSystem(["A",2]).weight_lattice().plot_fundamental_weights(), key=str) # needs sage.plot sage.symbolic [Arrow from (0.0,0.0) to (0.0,1.0), Arrow from (0.0,0.0) to (1.0,0.0), Text '$\Lambda_{1}$' at the point (1.05,0.0), Text '$\Lambda_{2}$' at the point (0.0,1.05)] - sage: sorted(RootSystem(["A",2]).ambient_lattice().plot_fundamental_weights(), key=str) + sage: sorted(RootSystem(["A",2]).ambient_lattice().plot_fundamental_weights(), key=str) # needs sage.plot sage.symbolic [Arrow from (0.0,0.0) to (-0.5,0.86602451838...), Arrow from (0.0,0.0) to (0.5,0.86602451838...), Text '$\Lambda_{1}$' at the point (0.525,0.909325744308...), @@ -2424,6 +2474,7 @@ def plot_reflection_hyperplanes(self, collection="simple", **options): EXAMPLES:: + sage: # needs sage.plot sage.symbolic sage: RootSystem(["A",2,1]).ambient_space().plot_reflection_hyperplanes() Graphics object consisting of 6 graphics primitives sage: RootSystem(["G",2,1]).ambient_space().plot_reflection_hyperplanes() @@ -2444,13 +2495,13 @@ def plot_reflection_hyperplanes(self, collection="simple", **options): TESTS:: sage: L = RootSystem(["A",2]).ambient_space() - sage: print(L.plot_reflection_hyperplanes().description()) + sage: print(L.plot_reflection_hyperplanes().description()) # needs sage.plot sage.symbolic Text '$H_{\alpha^\vee_{1}}$' at the point (-1.81...,3.15...) Text '$H_{\alpha^\vee_{2}}$' at the point (1.81...,3.15...) Line defined by 2 points: [(-1.73..., 3.0), (1.73..., -3.0)] Line defined by 2 points: [(1.73..., 3.0), (-1.73..., -3.0)] - sage: print(L.plot_reflection_hyperplanes("all").description()) + sage: print(L.plot_reflection_hyperplanes("all").description()) # needs sage.plot sage.symbolic Text '$H_{\alpha^\vee_{1} + \alpha^\vee_{2}}$' at the point (3.15...,0.0) Text '$H_{\alpha^\vee_{1}}$' at the point (-1.81...,3.15...) Text '$H_{\alpha^\vee_{2}}$' at the point (1.81...,3.15...) @@ -2459,7 +2510,7 @@ def plot_reflection_hyperplanes(self, collection="simple", **options): Line defined by 2 points: [(3.0, 0.0), (-3.0, 0.0)] sage: L = RootSystem(["A",2,1]).ambient_space() - sage: print(L.plot_reflection_hyperplanes().description()) + sage: print(L.plot_reflection_hyperplanes().description()) # needs sage.plot sage.symbolic Text '$H_{\alpha^\vee_{0}}$' at the point (3.15...,0.90...) Text '$H_{\alpha^\vee_{1}}$' at the point (-1.81...,3.15...) Text '$H_{\alpha^\vee_{2}}$' at the point (1.81...,3.15...) @@ -2486,7 +2537,7 @@ def plot_reflection_hyperplanes(self, collection="simple", **options): elif isinstance(collection, (list, tuple)): coroots = collection else: - raise ValueError("Unknown value: %s"%collection) + raise ValueError("Unknown value: %s" % collection) G = plot_options.empty() for coroot in coroots: @@ -2508,6 +2559,7 @@ def plot_hedron(self, **options): EXAMPLES:: + sage: # needs sage.plot sage.symbolic sage: RootSystem(["A",2]).ambient_space().plot_hedron() Graphics object consisting of 8 graphics primitives sage: RootSystem(["A",3]).ambient_space().plot_hedron() @@ -2522,13 +2574,13 @@ def plot_hedron(self, **options): Surprise: polyhedra of large dimension know how to project themselves nicely:: - sage: RootSystem(["F",4]).ambient_space().plot_hedron() # long time + sage: RootSystem(["F",4]).ambient_space().plot_hedron() # long time, needs sage.plot sage.symbolic Graphics3d Object TESTS:: sage: L = RootSystem(["B",2]).ambient_space() - sage: print(L.plot_hedron().description()) + sage: print(L.plot_hedron().description()) # needs sage.plot sage.symbolic Polygon defined by 8 points: [(1.5, 0.5), (0.5, 1.5), (-0.5, 1.5), (-1.5, 0.5), (-1.5, -0.5), (-0.5, -1.5), (0.5, -1.5), (1.5, -0.5)] Line defined by 2 points: [(-0.5, -1.5), (0.5, -1.5)] Line defined by 2 points: [(-0.5, 1.5), (0.5, 1.5)] @@ -2540,7 +2592,7 @@ def plot_hedron(self, **options): Line defined by 2 points: [(1.5, -0.5), (1.5, 0.5)] Point set defined by 8 point(s): [(-1.5, -0.5), (-1.5, 0.5), (-0.5, -1.5), (-0.5, 1.5), (0.5, -1.5), (0.5, 1.5), (1.5, -0.5), (1.5, 0.5)] """ - from sage.geometry.polyhedron.all import Polyhedron + from sage.geometry.polyhedron.constructor import Polyhedron plot_options = self.plot_parse_options(**options) if not self.cartan_type().is_finite(): raise ValueError("the Cartan type must be finite") @@ -2568,23 +2620,23 @@ def plot_fundamental_chamber(self, style="normal", **options): 2D plots:: - sage: RootSystem(["B",2]).ambient_space().plot_fundamental_chamber() + sage: RootSystem(["B",2]).ambient_space().plot_fundamental_chamber() # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: RootSystem(["B",2,1]).ambient_space().plot_fundamental_chamber() + sage: RootSystem(["B",2,1]).ambient_space().plot_fundamental_chamber() # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: RootSystem(["B",2,1]).ambient_space().plot_fundamental_chamber("classical") + sage: RootSystem(["B",2,1]).ambient_space().plot_fundamental_chamber("classical") # needs sage.plot Graphics object consisting of 1 graphics primitive 3D plots:: - sage: RootSystem(["A",3,1]).weight_space() .plot_fundamental_chamber() + sage: RootSystem(["A",3,1]).weight_space() .plot_fundamental_chamber() # needs sage.plot Graphics3d Object - sage: RootSystem(["B",3,1]).ambient_space().plot_fundamental_chamber() + sage: RootSystem(["B",3,1]).ambient_space().plot_fundamental_chamber() # needs sage.plot Graphics3d Object This feature is currently not available in the root lattice/space:: - sage: list(RootSystem(["A",2]).root_lattice().plot_fundamental_chamber()) + sage: list(RootSystem(["A",2]).root_lattice().plot_fundamental_chamber()) # needs sage.plot Traceback (most recent call last): ... TypeError: classical fundamental chamber not yet available in the root lattice @@ -2592,10 +2644,10 @@ def plot_fundamental_chamber(self, style="normal", **options): TESTS:: sage: L = RootSystem(["B",2,1]).ambient_space() - sage: print(L.plot_fundamental_chamber().description()) + sage: print(L.plot_fundamental_chamber().description()) # needs sage.plot Polygon defined by 3 points: [(0.5, 0.5), (1.0, 0.0), (0.0, 0.0)] - sage: print(L.plot_fundamental_chamber(style="classical").description()) + sage: print(L.plot_fundamental_chamber(style="classical").description()) # needs sage.plot Polygon defined by 3 points: [(0.0, 0.0), (3.0, 3.0), (3.0, 0.0)] """ plot_options = self.plot_parse_options(**options) @@ -2603,7 +2655,7 @@ def plot_fundamental_chamber(self, style="normal", **options): raise TypeError("classical fundamental chamber not yet available in the root lattice") Lambda = self.fundamental_weights() cartan_type = self.cartan_type() - if style=="classical": + if style == "classical": if not cartan_type.is_affine(): raise TypeError("classical fundamental chamber only available in affine type") I = cartan_type.classical().index_set() @@ -2611,7 +2663,7 @@ def plot_fundamental_chamber(self, style="normal", **options): else: I = cartan_type.index_set() lines = [] - return plot_options.cone(rays = [Lambda[i] for i in I], + return plot_options.cone(rays=[Lambda[i] for i in I], lines=lines, color="lightgrey", alpha=.3) @@ -2640,28 +2692,28 @@ def plot_alcoves(self, alcoves=True, alcove_labels=False, wireframe=False, **opt 2D plots:: - sage: RootSystem(["B",2,1]).ambient_space().plot_alcoves() # long time (3s) + sage: RootSystem(["B",2,1]).ambient_space().plot_alcoves() # long time (3s), needs sage.plot sage.symbolic Graphics object consisting of 228 graphics primitives 3D plots:: - sage: RootSystem(["A",2,1]).weight_space() .plot_alcoves(affine=False) # long time (3s) + sage: RootSystem(["A",2,1]).weight_space() .plot_alcoves(affine=False) # long time (3s), needs sage.plot sage.symbolic Graphics3d Object - sage: RootSystem(["G",2,1]).ambient_space().plot_alcoves(affine=False, level=1) # long time (3s) + sage: RootSystem(["G",2,1]).ambient_space().plot_alcoves(affine=False, level=1) # long time (3s), needs sage.plot sage.symbolic Graphics3d Object Here we plot a single alcove:: sage: L = RootSystem(["A",3,1]).ambient_space() - sage: W = L.weyl_group() - sage: L.plot(alcoves=[W.one()], reflection_hyperplanes=False, bounding_box=2) + sage: W = L.weyl_group() # needs sage.libs.gap + sage: L.plot(alcoves=[W.one()], reflection_hyperplanes=False, bounding_box=2) # needs sage.libs.gap sage.plot sage.symbolic Graphics3d Object TESTS:: sage: L = RootSystem(["A",2,1]).weight_space() - sage: p = L.plot_alcoves(alcoves=[[0,0]]) - sage: print(p.description()) + sage: p = L.plot_alcoves(alcoves=[[0,0]]) # needs sage.plot sage.symbolic + sage: print(p.description()) # needs sage.plot sage.symbolic Line defined by 2 points: [(-1.0, 0.0), (0.0, -1.0)] Line defined by 2 points: [(-1.0, 1.0), (-1.0, 0.0)] Line defined by 2 points: [(-1.0, 1.0), (0.0, 0.0)] @@ -2674,7 +2726,7 @@ def plot_alcoves(self, alcoves=True, alcove_labels=False, wireframe=False, **opt Line defined by 2 points: [(1.0, -1.0), (0.0, -1.0)] Line defined by 2 points: [(1.0, 0.0), (0.0, 0.0)] Line defined by 2 points: [(1.0, 0.0), (1.0, -1.0)] - sage: sorted((line.options()['rgbcolor'], line.options()['thickness']) for line in p) + sage: sorted((line.options()['rgbcolor'], line.options()['thickness']) for line in p) # needs sage.plot sage.symbolic [('black', 2), ('black', 2), ('black', 2), ('black', 2), ('black', 2), ('black', 2), ('blue', 1), ('blue', 1), ('blue', 1), @@ -2834,12 +2886,12 @@ def plot_bounding_box(self, **options): EXAMPLES:: sage: L = RootSystem(["A",2,1]).ambient_space() - sage: L.plot_bounding_box() + sage: L.plot_bounding_box() # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive TESTS:: - sage: list(L.plot_bounding_box()) + sage: list(L.plot_bounding_box()) # needs sage.plot sage.symbolic [Polygon defined by 4 points] """ plot_options = self.plot_parse_options(**options) @@ -2868,32 +2920,34 @@ def plot_alcove_walk(self, word, start=None, foldings=None, color="orange", **op sage: L = RootSystem(["A",2,1]).ambient_space() sage: w1 = [0,2,1,2,0,2,1,0,2,1,2,1,2,0,2,0,1,2,0] - sage: p = L.plot_alcoves(bounding_box=5) # long time (5s) - sage: p += L.plot_alcove_walk(w1) # long time - sage: p # long time + sage: p = L.plot_alcoves(bounding_box=5) # long time (5s) # needs sage.plot sage.symbolic + sage: p += L.plot_alcove_walk(w1) # long time # needs sage.plot sage.symbolic + sage: p # long time # needs sage.plot sage.symbolic Graphics object consisting of 375 graphics primitives The same plot with another alcove walk:: sage: w2 = [2,1,2,0,2,0,2,1,2,0,1,2,1,2,1,0,1,2,0,2,0,1,2,0,2] - sage: p += L.plot_alcove_walk(w2, color="orange") # long time + sage: p += L.plot_alcove_walk(w2, color="orange") # long time, needs sage.plot sage.symbolic And another with some foldings:: - sage: pic = L.plot_alcoves(bounding_box=3) # long time - sage: pic += L.plot_alcove_walk([0,1,2,0,2,0,1,2,0,1], # long time (3s) - ....: foldings = [False, False, True, False, False, False, True, False, True, False], + sage: pic = L.plot_alcoves(bounding_box=3) # long time, needs sage.plot sage.symbolic + sage: pic += L.plot_alcove_walk([0,1,2,0,2,0,1,2,0,1], # long time (3s), needs sage.plot sage.symbolic + ....: foldings=[False, False, True, False, False, + ....: False, True, False, True, False], ....: color="green"); pic Graphics object consisting of 155 graphics primitives TESTS:: sage: L = RootSystem(["A",2,1]).weight_space() - sage: p = L.plot_alcove_walk([0,1,2,0,2,0,1,2,0,1], - ....: foldings = [False, False, True, False, False, False, True, False, True, False], + sage: p = L.plot_alcove_walk([0,1,2,0,2,0,1,2,0,1], # needs sage.plot sage.symbolic + ....: foldings=[False, False, True, False, False, + ....: False, True, False, True, False], ....: color="green", ....: start=L.rho()) - sage: print(p.description()) + sage: print(p.description()) # needs sage.plot sage.symbolic Line defined by 2 points: [(-1.0, 8.0), (-1.5, 9.0)] Line defined by 2 points: [(1.0, 4.0), (1.5, 4.5)] Line defined by 2 points: [(1.0, 7.0), (1.5, 6.0)] @@ -2981,16 +3035,16 @@ def plot_ls_paths(self, paths, plot_labels=None, colored_labels=True, **options) EXAMPLES:: - sage: B = crystals.LSPaths(['A',2], [1,1]) + sage: B = crystals.LSPaths(['A',2], [1,1]) # needs sage.combinat sage: L = RootSystem(['A',2]).ambient_space() - sage: L.plot_fundamental_weights() + L.plot_ls_paths(B) + sage: L.plot_fundamental_weights() + L.plot_ls_paths(B) # needs sage.combinat sage.plot sage.symbolic Graphics object consisting of 14 graphics primitives This also works in 3 dimensions:: - sage: B = crystals.LSPaths(['B',3], [2,0,0]) + sage: B = crystals.LSPaths(['B',3], [2,0,0]) # needs sage.combinat sage: L = RootSystem(['B',3]).ambient_space() - sage: L.plot_ls_paths(B) + sage: L.plot_ls_paths(B) # needs sage.combinat sage.plot sage.symbolic Graphics3d Object """ if not isinstance(paths, (list, tuple, set)): @@ -3048,21 +3102,21 @@ def plot_mv_polytope(self, mv_polytope, mark_endpoints=True, EXAMPLES:: - sage: B = crystals.infinity.MVPolytopes(['C',2]) + sage: B = crystals.infinity.MVPolytopes(['C',2]) # needs sage.combinat sage: L = RootSystem(['C',2]).ambient_space() - sage: p = B.highest_weight_vector().f_string([1,2,1,2]) - sage: L.plot_fundamental_weights() + L.plot_mv_polytope(p) + sage: p = B.highest_weight_vector().f_string([1,2,1,2]) # needs sage.combinat + sage: L.plot_fundamental_weights() + L.plot_mv_polytope(p) # needs sage.combinat sage.geometry.polyhedron sage.plot sage.symbolic Graphics object consisting of 14 graphics primitives This also works in 3 dimensions:: - sage: B = crystals.infinity.MVPolytopes(['A',3]) + sage: B = crystals.infinity.MVPolytopes(['A',3]) # needs sage.combinat sage: L = RootSystem(['A',3]).ambient_space() - sage: p = B.highest_weight_vector().f_string([2,1,3,2]) - sage: L.plot_mv_polytope(p) + sage: p = B.highest_weight_vector().f_string([2,1,3,2]) # needs sage.combinat + sage: L.plot_mv_polytope(p) # needs sage.combinat sage.geometry.polyhedron sage.plot sage.symbolic Graphics3d Object """ - from sage.geometry.polyhedron.all import Polyhedron + from sage.geometry.polyhedron.constructor import Polyhedron plot_options = self.plot_parse_options(**options) # Setup the shift for plotting @@ -3127,6 +3181,7 @@ def plot_crystal(self, crystal, EXAMPLES:: + sage: # needs sage.combinat sage.plot sage.symbolic sage: L = RootSystem(['A',2]).ambient_space() sage: C = crystals.Tableaux(['A',2], shape=[2,1]) sage: L.plot_crystal(C, plot_labels='multiplicities') @@ -3138,17 +3193,18 @@ def plot_crystal(self, crystal, A 3-dimensional example:: sage: L = RootSystem(['B',3]).ambient_space() - sage: C = crystals.Tableaux(['B',3], shape=[2,1]) - sage: L.plot_crystal(C, plot_labels='circles', edge_labels=True) # long time + sage: C = crystals.Tableaux(['B',3], shape=[2,1]) # needs sage.combinat + sage: L.plot_crystal(C, plot_labels='circles', # long time # needs sage.combinat sage.plot sage.symbolic + ....: edge_labels=True) Graphics3d Object TESTS: Check that :trac:`29548` is fixed:: - sage: LS = crystals.LSPaths(['A',2], [1,1]) + sage: LS = crystals.LSPaths(['A',2], [1,1]) # needs sage.combinat sage: L = RootSystem(['A',2]).ambient_space() - sage: L.plot_crystal(LS) + sage: L.plot_crystal(LS) # needs sage.combinat sage.plot sage.symbolic Graphics object consisting of 16 graphics primitives """ from sage.plot.arrow import arrow @@ -3219,7 +3275,7 @@ def plot_crystal(self, crystal, @cached_method def dual_type_cospace(self): r""" - Returns the cospace of dual type. + Return the cospace of dual type. For example, if invoked on the root lattice of type `['B',2]`, returns the coroot lattice of type `['C',2]`. @@ -3233,7 +3289,8 @@ def dual_type_cospace(self): sage: CartanType(['B',2]).root_system().root_lattice().dual_type_cospace() Coroot lattice of the Root system of type ['C', 2] sage: CartanType(['F',4]).root_system().coweight_lattice().dual_type_cospace() - Weight lattice of the Root system of type ['F', 4] relabelled by {1: 4, 2: 3, 3: 2, 4: 1} + Weight lattice of the Root system of type ['F', 4] + relabelled by {1: 4, 2: 3, 3: 2, 4: 1} """ from .root_space import RootSpace @@ -3258,18 +3315,19 @@ def to_ambient_space_morphism(self): EXAMPLES:: - sage: CartanType(['B',2]).root_system().root_lattice().to_ambient_space_morphism() + sage: B2rs = CartanType(['B',2]).root_system() + sage: B2rs.root_lattice().to_ambient_space_morphism() Generic morphism: - From: Root lattice of the Root system of type ['B', 2] - To: Ambient space of the Root system of type ['B', 2] - sage: CartanType(['B',2]).root_system().coroot_lattice().to_ambient_space_morphism() + From: Root lattice of the Root system of type ['B', 2] + To: Ambient space of the Root system of type ['B', 2] + sage: B2rs.coroot_lattice().to_ambient_space_morphism() Generic morphism: - From: Coroot lattice of the Root system of type ['B', 2] - To: Ambient space of the Root system of type ['B', 2] - sage: CartanType(['B',2]).root_system().weight_lattice().to_ambient_space_morphism() + From: Coroot lattice of the Root system of type ['B', 2] + To: Ambient space of the Root system of type ['B', 2] + sage: B2rs.weight_lattice().to_ambient_space_morphism() Generic morphism: - From: Weight lattice of the Root system of type ['B', 2] - To: Ambient space of the Root system of type ['B', 2] + From: Weight lattice of the Root system of type ['B', 2] + To: Ambient space of the Root system of type ['B', 2] """ @@ -3294,11 +3352,11 @@ def scalar(self, lambdacheck): sage: L = RootSystem(['A',4]).root_lattice() sage: alpha = L.simple_roots() sage: alphacheck = L.simple_coroots() - sage: alpha[1].scalar(alphacheck[1]) + sage: alpha[1].scalar(alphacheck[1]) # needs sage.graphs 2 - sage: alpha[1].scalar(alphacheck[2]) + sage: alpha[1].scalar(alphacheck[2]) # needs sage.graphs -1 - sage: matrix([ [ alpha[i].scalar(alphacheck[j]) + sage: matrix([ [ alpha[i].scalar(alphacheck[j]) # needs sage.graphs ....: for i in L.index_set() ] ....: for j in L.index_set() ]) [ 2 -1 0 0] @@ -3330,6 +3388,7 @@ def symmetric_form(self, alpha): EXAMPLES:: + sage: # needs sage.graphs sage: Q = RootSystem(['B',2,1]).root_lattice() sage: alpha = Q.simple_roots() sage: alpha[1].symmetric_form(alpha[0]) @@ -3341,15 +3400,16 @@ def symmetric_form(self, alpha): -14 sage: elt.symmetric_form(alpha[0]+2*alpha[2]) 14 + sage: Q = RootSystem(CartanType(['A',4,2]).dual()).root_lattice() sage: Qc = RootSystem(['A',4,2]).coroot_lattice() sage: alpha = Q.simple_roots() sage: alphac = Qc.simple_roots() sage: elt = alpha[0] + 2*alpha[1] + 2*alpha[2] sage: eltc = alphac[0] + 2*alphac[1] + 2*alphac[2] - sage: elt.symmetric_form(alpha[1]) + sage: elt.symmetric_form(alpha[1]) # needs sage.graphs 0 - sage: eltc.symmetric_form(alphac[1]) + sage: eltc.symmetric_form(alphac[1]) # needs sage.graphs 0 """ cm = self.parent().dynkin_diagram().cartan_matrix() @@ -3365,6 +3425,7 @@ def norm_squared(self): EXAMPLES:: + sage: # needs sage.graphs sage: Q = RootSystem(['B',2,1]).root_lattice() sage: alpha = Q.simple_roots() sage: alpha[1].norm_squared() @@ -3377,15 +3438,16 @@ def norm_squared(self): sage: elt = alpha[0] + alpha[1] + 2*alpha[2] sage: elt.norm_squared() 0 + sage: Q = RootSystem(CartanType(['A',4,2]).dual()).root_lattice() sage: Qc = RootSystem(['A',4,2]).coroot_lattice() sage: alpha = Q.simple_roots() sage: alphac = Qc.simple_roots() sage: elt = alpha[0] + 2*alpha[1] + 2*alpha[2] sage: eltc = alphac[0] + 2*alphac[1] + 2*alphac[2] - sage: elt.norm_squared() + sage: elt.norm_squared() # needs sage.graphs 0 - sage: eltc.norm_squared() + sage: eltc.norm_squared() # needs sage.graphs 0 """ return self.symmetric_form(self) @@ -3396,18 +3458,18 @@ def norm_squared(self): def simple_reflection(self, i): r""" - Returns the image of ``self`` by the `i`-th simple reflection. + Return the image of ``self`` by the `i`-th simple reflection. EXAMPLES:: sage: alpha = RootSystem(["A", 3]).root_lattice().alpha() - sage: alpha[1].simple_reflection(2) + sage: alpha[1].simple_reflection(2) # needs sage.graphs alpha[1] + alpha[2] - sage: Q = RootSystem(['A', 3, 1]).weight_lattice(extended = True) + sage: Q = RootSystem(['A', 3, 1]).weight_lattice(extended=True) sage: Lambda = Q.fundamental_weights() - sage: L = Lambda[0] + Q.null_root() - sage: L.simple_reflection(0) + sage: L = Lambda[0] + Q.null_root() # needs sage.graphs + sage: L.simple_reflection(0) # needs sage.graphs -Lambda[0] + Lambda[1] + Lambda[3] """ # Subclasses should optimize whenever possible! @@ -3415,12 +3477,12 @@ def simple_reflection(self, i): def simple_reflections(self): """ - The images of self by all the simple reflections + The images of ``self`` by all the simple reflections EXAMPLES:: sage: alpha = RootSystem(["A", 3]).root_lattice().alpha() - sage: alpha[1].simple_reflections() + sage: alpha[1].simple_reflections() # needs sage.graphs [-alpha[1], alpha[1] + alpha[2], alpha[1]] """ return [s(self) for s in self.parent().simple_reflections()] @@ -3458,11 +3520,11 @@ def orbit(self): (2, 0, 1), (0, 1, 2), (0, 2, 1)] sage: L = RootSystem(["A", 3]).weight_lattice() - sage: len(L.rho().orbit()) + sage: len(L.rho().orbit()) # needs sage.graphs 24 - sage: len(L.fundamental_weights()[1].orbit()) + sage: len(L.fundamental_weights()[1].orbit()) # needs sage.graphs 4 - sage: len(L.fundamental_weights()[2].orbit()) + sage: len(L.fundamental_weights()[2].orbit()) # needs sage.graphs 6 TESTS:: @@ -3511,12 +3573,12 @@ def dot_orbit(self): EXAMPLES:: sage: L = RootSystem(['A', 2]).ambient_lattice() - sage: sorted(L.rho().dot_orbit()) # the output order is not specified + sage: sorted(L.rho().dot_orbit()) # the output order is not specified # needs sage.graphs [(-2, 1, 4), (-2, 3, 2), (2, -1, 2), (2, 1, 0), (0, -1, 4), (0, 3, 0)] sage: L = RootSystem(['B',2]).weight_lattice() - sage: sorted(L.fundamental_weights()[1].dot_orbit()) # the output order is not specified + sage: sorted(L.fundamental_weights()[1].dot_orbit()) # the output order is not specified # needs sage.graphs [-4*Lambda[1], -4*Lambda[1] + 4*Lambda[2], -3*Lambda[1] - 2*Lambda[2], -3*Lambda[1] + 4*Lambda[2], Lambda[1], Lambda[1] - 6*Lambda[2], @@ -3524,6 +3586,7 @@ def dot_orbit(self): We compare the dot action orbit to the regular orbit:: + sage: # needs sage.graphs sage: L = RootSystem(['A', 3]).weight_lattice() sage: len(L.rho().dot_orbit()) 24 @@ -3554,20 +3617,20 @@ def dot_orbit(self): @abstract_method(optional=True) def associated_coroot(self): """ - Returns the coroot associated to this root + Return the coroot associated to this root. EXAMPLES:: sage: alpha = RootSystem(["A", 3]).root_space().simple_roots() - sage: alpha[1].associated_coroot() + sage: alpha[1].associated_coroot() # needs sage.graphs alphacheck[1] """ - def reflection(self, root, use_coroot = False): + def reflection(self, root, use_coroot=False): r""" - Reflects ``self`` across the hyperplane orthogonal to ``root``. + Reflect ``self`` across the hyperplane orthogonal to ``root``. - If ``use_coroot`` is True, ``root`` is interpreted as a coroot. + If ``use_coroot`` is ``True``, ``root`` is interpreted as a coroot. EXAMPLES:: @@ -3576,11 +3639,11 @@ def reflection(self, root, use_coroot = False): sage: mu = weight_lattice.from_vector(vector([0,0,1,2])) sage: coroot_lattice = R.coroot_lattice() sage: alphavee = coroot_lattice.from_vector(vector([0,0,1,1])) - sage: mu.reflection(alphavee, use_coroot=True) + sage: mu.reflection(alphavee, use_coroot=True) # needs sage.graphs 6*Lambda[2] - 5*Lambda[3] + 2*Lambda[4] sage: root_lattice = R.root_lattice() sage: beta = root_lattice.from_vector(vector([0,1,1,0])) - sage: mu.reflection(beta) + sage: mu.reflection(beta) # needs sage.graphs Lambda[1] - Lambda[2] + 3*Lambda[4] """ if use_coroot: @@ -3594,17 +3657,18 @@ def reflection(self, root, use_coroot = False): def has_descent(self, i, positive=False): """ - Test if self has a descent at position `i`, that is if self is - on the strict negative side of the `i^{th}` simple reflection + Test if ``self`` has a descent at position `i`, that is, if ``self`` is + on the strict negative side of the `i`-th simple reflection hyperplane. - If positive if True, tests if it is on the strict positive + If positive is ``True``, tests if it is on the strict positive side instead. EXAMPLES:: - sage: space=RootSystem(['A',5]).weight_space() - sage: alpha=RootSystem(['A',5]).weight_space().simple_roots() + sage: # needs sage.graphs + sage: space = RootSystem(['A',5]).weight_space() + sage: alpha = RootSystem(['A',5]).weight_space().simple_roots() sage: [alpha[i].has_descent(1) for i in space.index_set()] [False, True, False, False, False] sage: [(-alpha[i]).has_descent(1) for i in space.index_set()] @@ -3628,15 +3692,16 @@ def has_descent(self, i, positive=False): def first_descent(self, index_set=None, positive=False): """ - Returns the first descent of pt + Return the first descent of pt - One can use the index_set option to restrict to the parabolic - subgroup indexed by index_set. + One can use the ``index_set`` option to restrict to the parabolic + subgroup indexed by ``index_set``. EXAMPLES:: - sage: space=RootSystem(['A',5]).weight_space() - sage: alpha=space.simple_roots() + sage: # needs sage.graphs + sage: space = RootSystem(['A',5]).weight_space() + sage: alpha = space.simple_roots() sage: (alpha[1]+alpha[2]+alpha[4]).first_descent() 3 sage: (alpha[1]+alpha[2]+alpha[4]).first_descent([1,2,5]) @@ -3653,29 +3718,29 @@ def first_descent(self, index_set=None, positive=False): def descents(self, index_set=None, positive=False): """ - Returns the descents of pt + Return the descents of pt EXAMPLES:: sage: space=RootSystem(['A',5]).weight_space() - sage: alpha=space.simple_roots() - sage: (alpha[1]+alpha[2]+alpha[4]).descents() + sage: alpha = space.simple_roots() # needs sage.graphs + sage: (alpha[1]+alpha[2]+alpha[4]).descents() # needs sage.graphs [3, 5] """ if index_set is None: - index_set=self.parent().index_set() + index_set = self.parent().index_set() return [ i for i in index_set if self.has_descent(i, positive) ] - def to_dominant_chamber(self, index_set = None, positive = True, reduced_word = False): + def to_dominant_chamber(self, index_set=None, positive=True, reduced_word=False): r""" - Returns the unique dominant element in the Weyl group orbit of the vector ``self``. + Return the unique dominant element in the Weyl group orbit of the vector ``self``. - If ``positive`` is False, returns the antidominant orbit element. + If ``positive`` is ``False``, returns the antidominant orbit element. With the ``index_set`` optional parameter, this is done with respect to the corresponding parabolic subgroup. - If ``reduced_word`` is True, returns the 2-tuple (``weight``, ``direction``) + If ``reduced_word`` is ``True``, returns the 2-tuple (``weight``, ``direction``) where ``weight`` is the (anti)dominant orbit element and ``direction`` is a reduced word for the Weyl group element sending ``weight`` to ``self``. @@ -3695,17 +3760,19 @@ def to_dominant_chamber(self, index_set = None, positive = True, reduced_word = EXAMPLES:: - sage: space=RootSystem(['A',5]).weight_space() - sage: alpha=RootSystem(['A',5]).weight_space().simple_roots() + sage: # needs sage.graphs + sage: space = RootSystem(['A',5]).weight_space() + sage: alpha = RootSystem(['A',5]).weight_space().simple_roots() sage: alpha[1].to_dominant_chamber() Lambda[1] + Lambda[5] sage: alpha[1].to_dominant_chamber([1,2]) Lambda[1] + Lambda[2] - Lambda[3] - sage: wl=RootSystem(['A',2,1]).weight_lattice(extended=True) - sage: mu=wl.from_vector(vector([1,-3,0])) - sage: mu.to_dominant_chamber(positive=False, reduced_word = True) + sage: wl = RootSystem(['A',2,1]).weight_lattice(extended=True) + sage: mu = wl.from_vector(vector([1,-3,0])) + sage: mu.to_dominant_chamber(positive=False, reduced_word=True) (-Lambda[1] - Lambda[2] - delta, [0, 2]) + sage: # needs sage.graphs sage: R = RootSystem(['A',1,1]) sage: rl = R.root_lattice() sage: nu = rl.zero() @@ -3760,9 +3827,9 @@ def to_dominant_chamber(self, index_set = None, positive = True, reduced_word = direction.append(i) self = self.simple_reflection(i) - def reduced_word(self, index_set = None, positive = True): + def reduced_word(self, index_set=None, positive=True): r""" - Returns a reduced word for the inverse of the shortest Weyl group element that sends the vector ``self`` into the dominant chamber. + Return a reduced word for the inverse of the shortest Weyl group element that sends the vector ``self`` into the dominant chamber. With the ``index_set`` optional parameter, this is done with respect to the corresponding parabolic subgroup. @@ -3771,23 +3838,23 @@ def reduced_word(self, index_set = None, positive = True): EXAMPLES:: - sage: space=RootSystem(['A',5]).weight_space() - sage: alpha=RootSystem(['A',5]).weight_space().simple_roots() - sage: alpha[1].reduced_word() + sage: space = RootSystem(['A',5]).weight_space() + sage: alpha = RootSystem(['A',5]).weight_space().simple_roots() # needs sage.graphs + sage: alpha[1].reduced_word() # needs sage.graphs [2, 3, 4, 5] - sage: alpha[1].reduced_word([1,2]) + sage: alpha[1].reduced_word([1,2]) # needs sage.graphs [2] """ - return self.to_dominant_chamber(index_set=index_set,positive=positive,reduced_word = True)[1] + return self.to_dominant_chamber(index_set=index_set,positive=positive,reduced_word=True)[1] - def is_dominant(self, index_set = None, positive = True): + def is_dominant(self, index_set=None, positive=True): r""" - Returns whether self is dominant. + Return whether ``self`` is dominant. - This is done with respect to the subrootsystem indicated by the subset of Dynkin nodes - index_set. If index_set is None then the entire Dynkin node set is used. - If positive is False then the dominance condition is replaced by antidominance. + This is done with respect to the sub--root system indicated by the subset of Dynkin nodes + ``index_set``. If ``index_set`` is ``None``, then the entire Dynkin node set is used. + If positive is ``False``, then the dominance condition is replaced by antidominance. EXAMPLES:: @@ -3854,7 +3921,7 @@ def succ(self, index_set=None): INPUT: - - ``index_set`` - a subset (as a list or iterable) of the + - ``index_set`` -- a subset (as a list or iterable) of the nodes of the Dynkin diagram; (default: ``None`` for all of them) If ``index_set`` is specified, the successors for the @@ -3862,12 +3929,15 @@ def succ(self, index_set=None): EXAMPLES:: + sage: # needs sage.graphs sage: L = RootSystem(['A',3]).weight_lattice() sage: Lambda = L.fundamental_weights() sage: Lambda[1].succ() [-Lambda[1] + Lambda[2]] sage: L.rho().succ() - [-Lambda[1] + 2*Lambda[2] + Lambda[3], 2*Lambda[1] - Lambda[2] + 2*Lambda[3], Lambda[1] + 2*Lambda[2] - Lambda[3]] + [-Lambda[1] + 2*Lambda[2] + Lambda[3], + 2*Lambda[1] - Lambda[2] + 2*Lambda[3], + Lambda[1] + 2*Lambda[2] - Lambda[3]] sage: (-L.rho()).succ() [] sage: L.rho().succ(index_set=[1]) @@ -3883,7 +3953,7 @@ def pred(self, index_set=None): INPUT: - - ``index_set`` - a subset (as a list or iterable) of the + - ``index_set`` -- a subset (as a list or iterable) of the nodes of the Dynkin diagram; (default: ``None`` for all of them) If ``index_set`` is specified, the successors for the @@ -3897,17 +3967,19 @@ def pred(self, index_set=None): [] sage: L.rho().pred() [] - sage: (-L.rho()).pred() - [Lambda[1] - 2*Lambda[2] - Lambda[3], -2*Lambda[1] + Lambda[2] - 2*Lambda[3], -Lambda[1] - 2*Lambda[2] + Lambda[3]] - sage: (-L.rho()).pred(index_set=[1]) + sage: (-L.rho()).pred() # needs sage.graphs + [Lambda[1] - 2*Lambda[2] - Lambda[3], + -2*Lambda[1] + Lambda[2] - 2*Lambda[3], + -Lambda[1] - 2*Lambda[2] + Lambda[3]] + sage: (-L.rho()).pred(index_set=[1]) # needs sage.graphs [Lambda[1] - 2*Lambda[2] - Lambda[3]] """ return [ self.simple_reflection(i) for i in self.descents(index_set) ] def greater(self): r""" - Returns the elements in the orbit of self which are - greater than self in the weak order. + Return the elements in the orbit of ``self`` which are + greater than ``self`` in the weak order. EXAMPLES:: @@ -3927,8 +3999,8 @@ def greater(self): def smaller(self): r""" - Returns the elements in the orbit of self which are - smaller than self in the weak order. + Return the elements in the orbit of ``self`` which are + smaller than ``self`` in the weak order. EXAMPLES:: @@ -3960,7 +4032,7 @@ def extraspecial_pair(self): EXAMPLES:: sage: Q = RootSystem(['G', 2]).root_lattice() - sage: Q.highest_root().extraspecial_pair() + sage: Q.highest_root().extraspecial_pair() # needs sage.graphs (alpha[2], 3*alpha[1] + alpha[2]) """ if self.is_positive_root(): @@ -3986,7 +4058,7 @@ def height(self): EXAMPLES:: sage: Q = RootSystem(['G', 2]).root_lattice() - sage: Q.highest_root().height() + sage: Q.highest_root().height() # needs sage.graphs 5 """ return sum(self.coefficients()) @@ -4000,7 +4072,7 @@ def level(self): EXAMPLES:: sage: L = RootSystem(['A',2,1]).weight_lattice() - sage: L.rho().level() + sage: L.rho().level() # needs sage.graphs 3 """ if not self.parent().cartan_type().is_affine(): @@ -4020,7 +4092,7 @@ def to_simple_root(self, reduced_word=False): OUTPUT: - The index `i` of a simple root `\alpha_i`. - If ``reduced_word`` is True, this returns instead a pair + If ``reduced_word`` is ``True``, this returns instead a pair ``(i, word)``, where word is a sequence of reflections mapping `\alpha_i` up the root poset to ``self``. @@ -4028,7 +4100,7 @@ def to_simple_root(self, reduced_word=False): sage: L = RootSystem(["A",3]).root_lattice() sage: positive_roots = L.positive_roots() - sage: for alpha in sorted(positive_roots): + sage: for alpha in sorted(positive_roots): # needs sage.graphs ....: print("{} {}".format(alpha, alpha.to_simple_root())) alpha[1] 1 alpha[1] + alpha[2] 2 @@ -4036,7 +4108,7 @@ def to_simple_root(self, reduced_word=False): alpha[2] 2 alpha[2] + alpha[3] 3 alpha[3] 3 - sage: for alpha in sorted(positive_roots): + sage: for alpha in sorted(positive_roots): # needs sage.graphs ....: print("{} {}".format(alpha, alpha.to_simple_root(reduced_word=True))) alpha[1] (1, ()) alpha[1] + alpha[2] (2, (1,)) @@ -4064,8 +4136,8 @@ def to_simple_root(self, reduced_word=False): positive root. For a finite root system, this is currently caught (albeit with a not perfect message):: - sage: alpha = L.simple_roots() - sage: (2*alpha[1]).to_simple_root() + sage: alpha = L.simple_roots() # needs sage.graphs + sage: (2*alpha[1]).to_simple_root() # needs sage.graphs Traceback (most recent call last): ... ValueError: -2*alpha[1] - 2*alpha[2] - 2*alpha[3] is not a positive root @@ -4095,15 +4167,16 @@ def to_simple_root(self, reduced_word=False): @cached_in_parent_method def associated_reflection(self): r""" - Given a positive root ``self``, returns a reduced word for the reflection orthogonal to ``self``. + Given a positive root ``self``, return a reduced word for the reflection orthogonal to ``self``. Since the answer is cached, it is a tuple instead of a list. EXAMPLES:: - sage: RootSystem(['C',3]).root_lattice().simple_root(3).weyl_action([1,2]).associated_reflection() + sage: C3_rl = RootSystem(['C',3]).root_lattice() # needs sage.graphs + sage: C3_rl.simple_root(3).weyl_action([1,2]).associated_reflection() # needs sage.graphs (1, 2, 3, 2, 1) - sage: RootSystem(['C',3]).root_lattice().simple_root(2).associated_reflection() + sage: C3_rl.simple_root(2).associated_reflection() # needs sage.graphs (2,) """ @@ -4112,43 +4185,43 @@ def associated_reflection(self): def translation(self, x): """ + Return `x` translated by `t`, that is, `x+level(x) t`. + INPUT: - ``self`` -- an element `t` at level `0` - ``x`` -- an element of the same space - Returns `x` translated by `t`, that is `x+level(x) t` - EXAMPLES:: sage: L = RootSystem(['A',2,1]).weight_lattice() - sage: alpha = L.simple_roots() - sage: Lambda = L.fundamental_weights() - sage: t = alpha[2] + sage: alpha = L.simple_roots() # needs sage.graphs + sage: Lambda = L.fundamental_weights() # needs sage.graphs + sage: t = alpha[2] # needs sage.graphs Let us look at the translation of an element of level `1`:: - sage: Lambda[1].level() + sage: Lambda[1].level() # needs sage.graphs 1 - sage: t.translation(Lambda[1]) + sage: t.translation(Lambda[1]) # needs sage.graphs -Lambda[0] + 2*Lambda[2] - sage: Lambda[1] + t + sage: Lambda[1] + t # needs sage.graphs -Lambda[0] + 2*Lambda[2] and of an element of level `0`:: - sage: alpha [1].level() + sage: alpha[1].level() # needs sage.graphs 0 - sage: t.translation(alpha [1]) + sage: t.translation(alpha [1]) # needs sage.graphs -Lambda[0] + 2*Lambda[1] - Lambda[2] - sage: alpha[1] + 0*t + sage: alpha[1] + 0*t # needs sage.graphs -Lambda[0] + 2*Lambda[1] - Lambda[2] The arguments are given in this seemingly unnatural order to make it easy to construct the translation function:: - sage: f = t.translation - sage: f(Lambda[1]) + sage: f = t.translation # needs sage.graphs + sage: f(Lambda[1]) # needs sage.graphs -Lambda[0] + 2*Lambda[2] """ if not self.level().is_zero(): @@ -4174,32 +4247,34 @@ def weyl_action(self, element, inverse=False): sage: mu = wl.from_vector(vector([1,0,-2])) sage: mu Lambda[1] - 2*Lambda[3] - sage: mudom, rw = mu.to_dominant_chamber(positive=False, reduced_word = True) - sage: mudom, rw + sage: mudom, rw = mu.to_dominant_chamber(positive=False, # needs sage.graphs + ....: reduced_word=True) + sage: mudom, rw # needs sage.graphs (-Lambda[2] - Lambda[3], [1, 2]) Acting by a (reduced) word:: - sage: mudom.weyl_action(rw) + sage: mudom.weyl_action(rw) # needs sage.graphs Lambda[1] - 2*Lambda[3] - sage: mu.weyl_action(rw, inverse = True) + sage: mu.weyl_action(rw, inverse=True) # needs sage.graphs -Lambda[2] - Lambda[3] Acting by an element of the Coxeter or Weyl group on a vector in its own lattice of definition (implemented by matrix multiplication on a vector):: - sage: w = wl.weyl_group().from_reduced_word([1, 2]) - sage: mudom.weyl_action(w) + sage: w = wl.weyl_group().from_reduced_word([1, 2]) # needs sage.graphs + sage: mudom.weyl_action(w) # needs sage.graphs Lambda[1] - 2*Lambda[3] Acting by an element of an isomorphic Coxeter or Weyl group (implemented by the action of a corresponding reduced word):: + sage: # needs sage.libs.gap sage: W = WeylGroup(['A',3], prefix="s") sage: w = W.from_reduced_word([1, 2]) sage: wl.weyl_group() == W False - sage: mudom.weyl_action(w) + sage: mudom.weyl_action(w) # needs sage.graphs Lambda[1] - 2*Lambda[3] """ # TODO, some day: accept an iterator @@ -4208,10 +4283,10 @@ def weyl_action(self, element, inverse=False): the_word = [x for x in element] I = self.parent().index_set() if not all(i in I for i in the_word): - raise ValueError("Not all members of %s are in the index set of the %s"%(element, self.parent())) + raise ValueError("Not all members of %s are in the index set of the %s" % (element, self.parent())) else: if not isinstance(element, Element): - raise TypeError("%s should be an element of a Coxeter group"%(element)) + raise TypeError("%s should be an element of a Coxeter group" % (element)) W = element.parent() if W is self.parent().weyl_group(): # Action by an element of the Coxeter or Weyl group of ``self`` @@ -4221,7 +4296,7 @@ def weyl_action(self, element, inverse=False): else: # Action by an element of an isomorphic Coxeter or Weyl group if not (W in CoxeterGroups() and W.cartan_type() == self.parent().cartan_type()): - raise TypeError("%s should be an element of a Coxeter group of type %s"%(element, self.parent().cartan_type())) + raise TypeError("%s should be an element of a Coxeter group of type %s" % (element, self.parent().cartan_type())) the_word = element.reduced_word() if inverse is False: the_word.reverse() @@ -4231,17 +4306,17 @@ def weyl_action(self, element, inverse=False): def weyl_stabilizer(self, index_set=None): r""" - Returns the subset of Dynkin nodes whose reflections fix ``self``. + Return the subset of Dynkin nodes whose reflections fix ``self``. - If ``index_set`` is not None, only consider nodes in this set. + If ``index_set`` is not ``None``, only consider nodes in this set. Note that if ``self`` is dominant or antidominant, then its stabilizer is the parabolic subgroup defined by the returned node set. EXAMPLES:: - sage: wl = RootSystem(['A',2,1]).weight_lattice(extended = True) - sage: al = wl.null_root() - sage: al.weyl_stabilizer() + sage: wl = RootSystem(['A',2,1]).weight_lattice(extended=True) + sage: al = wl.null_root() # needs sage.graphs + sage: al.weyl_stabilizer() # needs sage.graphs [0, 1, 2] sage: wl = RootSystem(['A',4]).weight_lattice() sage: mu = wl.from_vector(vector([1,1,0,0])) @@ -4251,7 +4326,6 @@ def weyl_stabilizer(self, index_set=None): [3] """ - if index_set is None: index_set = self.parent().cartan_type().index_set() alphavee = self.parent().coroot_lattice().basis() @@ -4284,16 +4358,16 @@ def dot_action(self, w, inverse=False): sage: P = RootSystem(['B',3]).weight_lattice() sage: La = P.fundamental_weights() sage: mu = La[1] + 2*La[2] - 3*La[3] - sage: mu.dot_action([1]) + sage: mu.dot_action([1]) # needs sage.graphs -3*Lambda[1] + 4*Lambda[2] - 3*Lambda[3] - sage: mu.dot_action([3]) + sage: mu.dot_action([3]) # needs sage.graphs Lambda[1] + Lambda[3] - sage: mu.dot_action([1,2,3]) + sage: mu.dot_action([1,2,3]) # needs sage.graphs -4*Lambda[1] + Lambda[2] + 3*Lambda[3] We check that the origin of this action is at `-\rho`:: - sage: all((-P.rho()).dot_action([i]) == -P.rho() + sage: all((-P.rho()).dot_action([i]) == -P.rho() # needs sage.graphs ....: for i in P.index_set()) True @@ -4306,7 +4380,9 @@ def dot_action(self, w, inverse=False): def is_parabolic_root(self, index_set): r""" - Supposing that ``self`` is a root, is it in the parabolic subsystem with Dynkin nodes ``index_set``? + Return whether ``root`` is in the parabolic subsystem with Dynkin nodes ``index_set``. + + This assumes that ``self`` is a root. INPUT: @@ -4334,12 +4410,13 @@ def is_short_root(self): r""" Return ``True`` if ``self`` is a short (real) root. - Returns False unless the parent is an irreducible root system of finite type + Returns ``False`` unless the parent is an irreducible root system of finite type having two root lengths and ``self`` is of the shorter length. There is no check of whether ``self`` is actually a root. EXAMPLES:: + sage: # needs sage.graphs sage: Q = RootSystem(['C',2]).root_lattice() sage: al = Q.simple_root(1).weyl_action([1,2]); al alpha[1] + alpha[2] @@ -4354,6 +4431,7 @@ def is_short_root(self): An example in affine type:: + sage: # needs sage.graphs sage: Q = RootSystem(['B',2,1]).root_lattice() sage: alpha = Q.simple_roots() sage: alpha[0].is_short_root() @@ -4417,13 +4495,13 @@ def to_classical(self): sage: R = CartanType(['A',3,1]).root_system() sage: alpha = R.root_lattice().an_element(); alpha 2*alpha[0] + 2*alpha[1] + 3*alpha[2] - sage: alb = alpha.to_classical(); alb + sage: alb = alpha.to_classical(); alb # needs sage.graphs alpha[2] - 2*alpha[3] - sage: alb.parent() + sage: alb.parent() # needs sage.graphs Root lattice of the Root system of type ['A', 3] sage: v = R.ambient_space().an_element(); v 2*e[0] + 2*e[1] + 3*e[2] - sage: v.to_classical() + sage: v.to_classical() # needs sage.graphs (2, 2, 3, 0) """ @@ -4436,19 +4514,20 @@ def to_ambient(self): EXAMPLES:: - sage: alpha = CartanType(['B',4]).root_system().root_lattice().an_element(); alpha + sage: B4_rs = CartanType(['B',4]).root_system() + sage: alpha = B4_rs.root_lattice().an_element(); alpha 2*alpha[1] + 2*alpha[2] + 3*alpha[3] sage: alpha.to_ambient() (2, 0, 1, -3) - sage: mu = CartanType(['B',4]).root_system().weight_lattice().an_element(); mu + sage: mu = B4_rs.weight_lattice().an_element(); mu 2*Lambda[1] + 2*Lambda[2] + 3*Lambda[3] sage: mu.to_ambient() (7, 5, 3, 0) - sage: v = CartanType(['B',4]).root_system().ambient_space().an_element(); v + sage: v = B4_rs.ambient_space().an_element(); v (2, 2, 3, 0) sage: v.to_ambient() (2, 2, 3, 0) - sage: alphavee = CartanType(['B',4]).root_system().coroot_lattice().an_element(); alphavee + sage: alphavee = B4_rs.coroot_lattice().an_element(); alphavee 2*alphacheck[1] + 2*alphacheck[2] + 3*alphacheck[3] sage: alphavee.to_ambient() (2, 0, 1, -3) @@ -4463,11 +4542,11 @@ def is_long_root(self): sage: Q = RootSystem(['B',2,1]).root_lattice() sage: alpha = Q.simple_roots() - sage: alpha[0].is_long_root() + sage: alpha[0].is_long_root() # needs sage.graphs True - sage: alpha[1].is_long_root() + sage: alpha[1].is_long_root() # needs sage.graphs True - sage: alpha[2].is_long_root() + sage: alpha[2].is_long_root() # needs sage.graphs False """ alpha = self.parent().simple_roots() @@ -4479,17 +4558,17 @@ def is_imaginary_root(self): r""" Return ``True`` if ``self`` is an imaginary root. - A root `\alpha` is imaginary if it is not `W` conjugate + A root `\alpha` is imaginary if it is not `W`-conjugate to a simple root where `W` is the corresponding Weyl group. EXAMPLES:: sage: Q = RootSystem(['B',2,1]).root_lattice() sage: alpha = Q.simple_roots() - sage: alpha[0].is_imaginary_root() + sage: alpha[0].is_imaginary_root() # needs sage.graphs False sage: elt = alpha[0] + alpha[1] + 2*alpha[2] - sage: elt.is_imaginary_root() + sage: elt.is_imaginary_root() # needs sage.graphs True """ return self.norm_squared() <= 0 @@ -4498,17 +4577,17 @@ def is_real_root(self): r""" Return ``True`` if ``self`` is a real root. - A root `\alpha` is real if it is `W` conjugate to a simple + A root `\alpha` is real if it is `W`-conjugate to a simple root where `W` is the corresponding Weyl group. EXAMPLES:: sage: Q = RootSystem(['B',2,1]).root_lattice() sage: alpha = Q.simple_roots() - sage: alpha[0].is_real_root() + sage: alpha[0].is_real_root() # needs sage.graphs True sage: elt = alpha[0] + alpha[1] + 2*alpha[2] - sage: elt.is_real_root() + sage: elt.is_real_root() # needs sage.graphs False """ return self.norm_squared() > 0 diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py index d4e6f8746d2..b2359c547d5 100644 --- a/src/sage/combinat/root_system/root_space.py +++ b/src/sage/combinat/root_system/root_space.py @@ -64,9 +64,9 @@ def __init__(self, root_system, base_ring): self.root_system = root_system CombinatorialFreeModule.__init__(self, base_ring, root_system.index_set(), - prefix = "alphacheck" if root_system.dual_side else "alpha", - latex_prefix = "\\alpha^\\vee" if root_system.dual_side else "\\alpha", - category = RootLatticeRealizations(base_ring)) + prefix="alphacheck" if root_system.dual_side else "alpha", + latex_prefix="\\alpha^\\vee" if root_system.dual_side else "\\alpha", + category=RootLatticeRealizations(base_ring)) if base_ring is not ZZ: # Register the partial conversion back from ``self`` to the root lattice # See :meth:`_to_root_lattice` for tests @@ -115,31 +115,31 @@ def to_coroot_space_morphism(self): sage: R = RootSystem(['A',3]).root_space() sage: alpha = R.simple_roots() - sage: f = R.to_coroot_space_morphism() - sage: f(alpha[1]) + sage: f = R.to_coroot_space_morphism() # needs sage.graphs + sage: f(alpha[1]) # needs sage.graphs alphacheck[1] - sage: f(alpha[1]+alpha[2]) + sage: f(alpha[1] + alpha[2]) # needs sage.graphs alphacheck[1] + alphacheck[2] sage: R = RootSystem(['A',3]).root_lattice() sage: alpha = R.simple_roots() - sage: f = R.to_coroot_space_morphism() - sage: f(alpha[1]) + sage: f = R.to_coroot_space_morphism() # needs sage.graphs + sage: f(alpha[1]) # needs sage.graphs alphacheck[1] - sage: f(alpha[1]+alpha[2]) + sage: f(alpha[1] + alpha[2]) # needs sage.graphs alphacheck[1] + alphacheck[2] sage: S = RootSystem(['G',2]).root_space() sage: alpha = S.simple_roots() - sage: f = S.to_coroot_space_morphism() - sage: f(alpha[1]) + sage: f = S.to_coroot_space_morphism() # needs sage.graphs + sage: f(alpha[1]) # needs sage.graphs alphacheck[1] - sage: f(alpha[1]+alpha[2]) + sage: f(alpha[1] + alpha[2]) # needs sage.graphs alphacheck[1] + 3*alphacheck[2] """ R = self.base_ring() C = self.cartan_type().symmetrizer().map(R) - return self.module_morphism(diagonal = C.__getitem__, + return self.module_morphism(diagonal=C.__getitem__, codomain=self.coroot_space(R)) def _to_root_lattice(self, x): @@ -194,7 +194,7 @@ def _to_classical_on_basis(self, i): EXAMPLES:: sage: L = RootSystem(["A",3,1]).root_space() - sage: L._to_classical_on_basis(0) + sage: L._to_classical_on_basis(0) # needs sage.graphs -alpha[1] - alpha[2] - alpha[3] sage: L._to_classical_on_basis(1) alpha[1] @@ -228,7 +228,7 @@ def to_ambient_space_morphism(self): def basis_value(basis, i): return basis[i] - return self.module_morphism(on_basis = functools.partial(basis_value, basis) , codomain=L) + return self.module_morphism(on_basis=functools.partial(basis_value, basis) , codomain=L) class RootSpaceElement(CombinatorialFreeModule.Element): @@ -242,15 +242,15 @@ def scalar(self, lambdacheck): sage: L = RootSystem(['B',4]).root_lattice() sage: alpha = L.simple_roots() sage: alphacheck = L.simple_coroots() - sage: alpha[1].scalar(alphacheck[1]) + sage: alpha[1].scalar(alphacheck[1]) # needs sage.graphs 2 - sage: alpha[1].scalar(alphacheck[2]) + sage: alpha[1].scalar(alphacheck[2]) # needs sage.graphs -1 The scalar products between the roots and coroots are given by the Cartan matrix:: - sage: matrix([ [ alpha[i].scalar(alphacheck[j]) + sage: matrix([ [ alpha[i].scalar(alphacheck[j]) # needs sage.graphs ....: for i in L.index_set() ] ....: for j in L.index_set() ]) [ 2 -1 0 0] @@ -258,7 +258,7 @@ def scalar(self, lambdacheck): [ 0 -1 2 -1] [ 0 0 -2 2] - sage: L.cartan_type().cartan_matrix() + sage: L.cartan_type().cartan_matrix() # needs sage.graphs [ 2 -1 0 0] [-1 2 -1 0] [ 0 -1 2 -1] @@ -266,7 +266,7 @@ def scalar(self, lambdacheck): """ # Find some better test if not (lambdacheck in self.parent().coroot_lattice() or lambdacheck in self.parent().coroot_space()): - raise TypeError("%s is not in a coroot lattice/space"%(lambdacheck)) + raise TypeError("%s is not in a coroot lattice/space" % (lambdacheck)) zero = self.parent().base_ring().zero() cartan_matrix = self.parent().dynkin_diagram() return sum( (sum( (lambdacheck[i]*s for i,s in cartan_matrix.column(j)), zero) * c for j,c in self), zero) @@ -278,16 +278,16 @@ def is_positive_root(self): EXAMPLES:: - sage: R=RootSystem(['A',3,1]).root_space() - sage: B=R.basis() - sage: w=B[0]+B[3] + sage: R = RootSystem(['A',3,1]).root_space() + sage: B = R.basis() + sage: w = B[0] + B[3] sage: w.is_positive_root() True - sage: w=B[1]-B[2] + sage: w = B[1] - B[2] sage: w.is_positive_root() False """ - return all( c>= 0 for c in self.coefficients() ) + return all( c >= 0 for c in self.coefficients() ) @cached_in_parent_method def associated_coroot(self): @@ -304,20 +304,20 @@ def associated_coroot(self): sage: L = RootSystem(["B", 3]).root_space() sage: alpha = L.simple_roots() - sage: alpha[1].associated_coroot() + sage: alpha[1].associated_coroot() # needs sage.graphs alphacheck[1] - sage: alpha[1].associated_coroot().parent() + sage: alpha[1].associated_coroot().parent() # needs sage.graphs Coroot space over the Rational Field of the Root system of type ['B', 3] - sage: L.highest_root() + sage: L.highest_root() # needs sage.graphs alpha[1] + 2*alpha[2] + 2*alpha[3] - sage: L.highest_root().associated_coroot() + sage: L.highest_root().associated_coroot() # needs sage.graphs alphacheck[1] + 2*alphacheck[2] + alphacheck[3] sage: alpha = RootSystem(["B", 3]).root_lattice().simple_roots() - sage: alpha[1].associated_coroot() + sage: alpha[1].associated_coroot() # needs sage.graphs alphacheck[1] - sage: alpha[1].associated_coroot().parent() + sage: alpha[1].associated_coroot().parent() # needs sage.graphs Coroot lattice of the Root system of type ['B', 3] """ @@ -328,13 +328,15 @@ def associated_coroot(self): def quantum_root(self): r""" - Returns True if ``self`` is a quantum root and False otherwise. + Check whether ``self`` is a quantum root. INPUT: - ``self`` -- an element of the nonnegative integer span of simple roots. - A root `\alpha` is a quantum root if `\ell(s_\alpha) = \langle 2 \rho, \alpha^\vee \rangle - 1` where `\ell` is the length function, `s_\alpha` is the reflection across the hyperplane orthogonal to `\alpha`, and `2\rho` is the sum of positive roots. + A root `\alpha` is a quantum root if `\ell(s_\alpha) = \langle 2 \rho, \alpha^\vee \rangle - 1` + where `\ell` is the length function, `s_\alpha` is the reflection across the hyperplane + orthogonal to `\alpha`, and `2\rho` is the sum of positive roots. .. warning:: @@ -346,7 +348,7 @@ def quantum_root(self): sage: Q = RootSystem(['C',2]).root_lattice() sage: positive_roots = Q.positive_roots() - sage: for x in sorted(positive_roots): + sage: for x in sorted(positive_roots): # needs sage.graphs ....: print("{} {}".format(x, x.quantum_root())) alpha[1] True alpha[1] + alpha[2] False @@ -357,7 +359,7 @@ def quantum_root(self): def max_coroot_le(self): r""" - Returns the highest positive coroot whose associated root is less than or equal to ``self``. + Return the highest positive coroot whose associated root is less than or equal to ``self``. INPUT: @@ -374,6 +376,7 @@ def max_coroot_le(self): EXAMPLES:: + sage: # needs sage.graphs sage: root_lattice = RootSystem(['C',2]).root_lattice() sage: root_lattice.from_vector(vector([1,1])).max_coroot_le() alphacheck[1] + 2*alphacheck[2] @@ -385,14 +388,14 @@ def max_coroot_le(self): sage: root_lattice.from_vector(vector([1,2])).max_coroot_le() 2*alphacheck[1] + alphacheck[2] - sage: root_lattice.zero().max_coroot_le() is None + sage: root_lattice.zero().max_coroot_le() is None # needs sage.graphs True - sage: root_lattice.from_vector(vector([-1,0])).max_coroot_le() + sage: root_lattice.from_vector(vector([-1,0])).max_coroot_le() # needs sage.graphs Traceback (most recent call last): ... ValueError: -alpha[1] is not in the positive cone of roots sage: root_lattice = RootSystem(['A',2,1]).root_lattice() - sage: root_lattice.simple_root(1).max_coroot_le() + sage: root_lattice.simple_root(1).max_coroot_le() # needs sage.graphs Traceback (most recent call last): ... NotImplementedError: Only implemented for finite Cartan type @@ -411,7 +414,9 @@ def max_coroot_le(self): def max_quantum_element(self): r""" - Returns a reduced word for the longest element of the Weyl group whose shortest path in the quantum Bruhat graph to the identity, has sum of quantum coroots at most ``self``. + Return a reduced word for the longest element of the Weyl group + whose shortest path in the quantum Bruhat graph to the identity + has sum of quantum coroots at most ``self``. INPUT: @@ -426,11 +431,11 @@ def max_quantum_element(self): EXAMPLES:: sage: Qvee = RootSystem(['C',2]).coroot_lattice() - sage: Qvee.from_vector(vector([1,2])).max_quantum_element() + sage: Qvee.from_vector(vector([1,2])).max_quantum_element() # needs sage.graphs [2, 1, 2, 1] - sage: Qvee.from_vector(vector([1,1])).max_quantum_element() + sage: Qvee.from_vector(vector([1,1])).max_quantum_element() # needs sage.graphs [1, 2, 1] - sage: Qvee.from_vector(vector([0,2])).max_quantum_element() + sage: Qvee.from_vector(vector([0,2])).max_quantum_element() # needs sage.graphs [2] """ diff --git a/src/sage/combinat/root_system/root_system.py b/src/sage/combinat/root_system/root_system.py index fc84a35b4c1..a26b9afa75c 100644 --- a/src/sage/combinat/root_system/root_system.py +++ b/src/sage/combinat/root_system/root_system.py @@ -33,15 +33,14 @@ class RootSystem(UniqueRepresentation, SageObject): We construct the root system for type `B_3`:: - sage: R=RootSystem(['B',3]); R + sage: R = RootSystem(['B',3]); R Root system of type ['B', 3] ``R`` models the root system abstractly. It comes equipped with various realizations of the root and weight lattices, where all computations take place. Let us play first with the root lattice:: - sage: space = R.root_lattice() - sage: space + sage: space = R.root_lattice(); space Root lattice of the Root system of type ['B', 3] This is the free `\ZZ`-module `\bigoplus_i \ZZ.\alpha_i` spanned @@ -77,8 +76,7 @@ class RootSystem(UniqueRepresentation, SageObject): `\bigoplus_i \ZZ.\Lambda_i`, the weight space `\bigoplus_i \QQ.\Lambda_i`. For example:: - sage: space = R.weight_space() - sage: space + sage: space = R.weight_space(); space Weight space over the Rational Field of the Root system of type ['B', 3] :: @@ -90,8 +88,8 @@ class RootSystem(UniqueRepresentation, SageObject): :: - sage: alpha = space.simple_roots() - sage: alpha[1] + alpha[2] + sage: alpha = space.simple_roots() # needs sage.graphs + sage: alpha[1] + alpha[2] # needs sage.graphs Lambda[1] + Lambda[2] - 2*Lambda[3] The fundamental weights are the dual basis of the coroots:: @@ -102,8 +100,8 @@ class RootSystem(UniqueRepresentation, SageObject): :: - sage: alphacheck = space.simple_coroots() - sage: list(alphacheck) + sage: alphacheck = space.simple_coroots() # needs sage.graphs + sage: list(alphacheck) # needs sage.graphs [alphacheck[1], alphacheck[2], alphacheck[3]] :: @@ -121,7 +119,7 @@ class RootSystem(UniqueRepresentation, SageObject): `\alpha_i`, where `c` is the coefficient of `i` in `x`:: - sage: s = space.simple_reflections() + sage: # needs sage.graphs sage: Lambda[1].simple_reflection(1) -Lambda[1] + Lambda[2] sage: Lambda[2].simple_reflection(1) @@ -134,6 +132,7 @@ class RootSystem(UniqueRepresentation, SageObject): It can be convenient to manipulate the simple reflections themselves:: + sage: # needs sage.graphs sage: s = space.simple_reflections() sage: s[1](Lambda[1]) -Lambda[1] + Lambda[2] @@ -159,7 +158,7 @@ class RootSystem(UniqueRepresentation, SageObject): In finite type `A`, we recover the natural representation of the symmetric group as group of permutation matrices:: - sage: RootSystem(["A",2]).ambient_space().weyl_group().simple_reflections() + sage: RootSystem(["A",2]).ambient_space().weyl_group().simple_reflections() # needs sage.libs.pari Finite family {1: [0 1 0] [1 0 0] [0 0 1], @@ -170,7 +169,7 @@ class RootSystem(UniqueRepresentation, SageObject): In type `B`, `C`, and `D`, we recover the natural representation of the Weyl group as groups of signed permutation matrices:: - sage: RootSystem(["B",3]).ambient_space().weyl_group().simple_reflections() + sage: RootSystem(["B",3]).ambient_space().weyl_group().simple_reflections() # needs sage.libs.pari Finite family {1: [0 1 0] [1 0 0] [0 0 1], @@ -190,35 +189,35 @@ class RootSystem(UniqueRepresentation, SageObject): Define the "identity" by an appropriate vector at level `-3`:: - sage: e = L.basis(); Lambda = L.fundamental_weights() - sage: id = e[0] + 2*e[1] + 3*e[2] - 3*Lambda[0] + sage: e = L.basis(); Lambda = L.fundamental_weights() # needs sage.graphs + sage: id = e[0] + 2*e[1] + 3*e[2] - 3*Lambda[0] # needs sage.graphs The corresponding permutation is obtained by projecting it onto the classical ambient space:: sage: L.classical() Ambient space of the Root system of type ['A', 2] - sage: L.classical()(id) + sage: L.classical()(id) # needs sage.graphs (1, 2, 3) Here is the orbit of the identity under the action of the finite group:: - sage: W = L.weyl_group() - sage: S3 = [ w.action(id) for w in W.classical() ] - sage: [L.classical()(x) for x in S3] + sage: W = L.weyl_group() # needs sage.libs.pari + sage: S3 = [ w.action(id) for w in W.classical() ] # needs sage.graphs sage.libs.pari + sage: [L.classical()(x) for x in S3] # needs sage.graphs sage.libs.pari [(1, 2, 3), (3, 1, 2), (2, 3, 1), (2, 1, 3), (1, 3, 2), (3, 2, 1)] And the action of `s_0` on these yields:: - sage: s = W.simple_reflections() - sage: [L.classical()(s[0].action(x)) for x in S3] + sage: s = W.simple_reflections() # needs sage.libs.pari + sage: [L.classical()(s[0].action(x)) for x in S3] # needs sage.graphs sage.libs.pari [(0, 2, 4), (-1, 1, 6), (-2, 3, 5), (0, 1, 5), (-1, 3, 4), (-2, 2, 6)] We can also plot various components of the ambient spaces:: sage: L = RootSystem(['A',2]).ambient_space() - sage: L.plot() + sage: L.plot() # needs sage.plot sage.symbolic Graphics object consisting of 13 graphics primitives For more on plotting, see :ref:`sage.combinat.root_system.plot`. @@ -266,11 +265,11 @@ class RootSystem(UniqueRepresentation, SageObject): TESTS:: sage: R = RootSystem(['C',3]) - sage: TestSuite(R).run() + sage: TestSuite(R).run() # needs sage.graphs sage: L = R.ambient_space() sage: s = L.simple_reflections() # this used to break the testsuite below due to caching an unpicklable method sage: s = L.simple_projections() # todo: not implemented - sage: TestSuite(L).run() + sage: TestSuite(L).run() # needs sage.graphs sage: L = R.root_space() sage: s = L.simple_reflections() sage: TestSuite(L).run() @@ -345,7 +344,7 @@ def _test_root_lattice_realizations(self, **options): EXAMPLES:: - sage: RootSystem(["A",3])._test_root_lattice_realizations() + sage: RootSystem(["A",3])._test_root_lattice_realizations() # needs sage.graphs .. SEEALSO:: :class:`TestSuite`. """ @@ -379,7 +378,7 @@ def _repr_(self): def cartan_type(self): """ - Returns the Cartan type of the root system. + Return the Cartan type of the root system. EXAMPLES:: @@ -392,12 +391,12 @@ def cartan_type(self): @cached_method def dynkin_diagram(self): """ - Returns the Dynkin diagram of the root system. + Return the Dynkin diagram of the root system. EXAMPLES:: sage: R = RootSystem(['A',3]) - sage: R.dynkin_diagram() + sage: R.dynkin_diagram() # needs sage.graphs O---O---O 1 2 3 A3 @@ -409,7 +408,7 @@ def cartan_matrix(self): """ EXAMPLES:: - sage: RootSystem(['A',3]).cartan_matrix() + sage: RootSystem(['A',3]).cartan_matrix() # needs sage.graphs [ 2 -1 0] [-1 2 -1] [ 0 -1 2] @@ -429,7 +428,7 @@ def index_set(self): @cached_method def is_finite(self): """ - Returns True if self is a finite root system. + Return ``True`` if ``self`` is a finite root system. EXAMPLES:: @@ -443,7 +442,7 @@ def is_finite(self): @cached_method def is_irreducible(self): """ - Returns True if self is an irreducible root system. + Return ``True`` if ``self`` is an irreducible root system. EXAMPLES:: @@ -456,7 +455,7 @@ def is_irreducible(self): def root_lattice(self): """ - Returns the root lattice associated to self. + Return the root lattice associated to ``self``. EXAMPLES:: @@ -468,7 +467,7 @@ def root_lattice(self): @cached_method def root_space(self, base_ring=QQ): """ - Returns the root space associated to self. + Return the root space associated to ``self``. EXAMPLES:: @@ -479,7 +478,7 @@ def root_space(self, base_ring=QQ): def root_poset(self, restricted=False, facade=False): r""" - Returns the (restricted) root poset associated to ``self``. + Return the (restricted) root poset associated to ``self``. The elements are given by the positive roots (resp. non-simple, positive roots), and `\alpha \leq \beta` iff `\beta - \alpha` is a non-negative linear combination of simple roots. @@ -491,26 +490,28 @@ def root_poset(self, restricted=False, facade=False): EXAMPLES:: - sage: Phi = RootSystem(['A',2]).root_poset(); Phi + sage: Phi = RootSystem(['A',2]).root_poset(); Phi # needs sage.graphs Finite poset containing 3 elements - sage: sorted(Phi.cover_relations(), key=str) + sage: sorted(Phi.cover_relations(), key=str) # needs sage.graphs [[alpha[1], alpha[1] + alpha[2]], [alpha[2], alpha[1] + alpha[2]]] - sage: Phi = RootSystem(['A',3]).root_poset(restricted=True); Phi + sage: Phi = RootSystem(['A',3]).root_poset(restricted=True); Phi # needs sage.graphs Finite poset containing 3 elements - sage: sorted(Phi.cover_relations(), key=str) - [[alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3]], [alpha[2] + alpha[3], alpha[1] + alpha[2] + alpha[3]]] + sage: sorted(Phi.cover_relations(), key=str) # needs sage.graphs + [[alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3]], + [alpha[2] + alpha[3], alpha[1] + alpha[2] + alpha[3]]] - sage: Phi = RootSystem(['B',2]).root_poset(); Phi + sage: Phi = RootSystem(['B',2]).root_poset(); Phi # needs sage.graphs Finite poset containing 4 elements - sage: Phi.cover_relations() - [[alpha[2], alpha[1] + alpha[2]], [alpha[1], alpha[1] + alpha[2]], [alpha[1] + alpha[2], alpha[1] + 2*alpha[2]]] + sage: Phi.cover_relations() # needs sage.graphs + [[alpha[2], alpha[1] + alpha[2]], [alpha[1], alpha[1] + alpha[2]], + [alpha[1] + alpha[2], alpha[1] + 2*alpha[2]]] """ return self.root_lattice().root_poset(restricted=restricted, facade=facade) def coroot_lattice(self): """ - Returns the coroot lattice associated to self. + Return the coroot lattice associated to ``self``. EXAMPLES:: @@ -521,7 +522,7 @@ def coroot_lattice(self): def coroot_space(self, base_ring=QQ): """ - Returns the coroot space associated to self. + Return the coroot space associated to ``self``. EXAMPLES:: @@ -531,9 +532,9 @@ def coroot_space(self, base_ring=QQ): return self.dual.root_space(base_ring) @cached_method - def weight_lattice(self, extended = False): + def weight_lattice(self, extended=False): """ - Returns the weight lattice associated to self. + Return the weight lattice associated to ``self``. .. SEEALSO:: @@ -546,15 +547,16 @@ def weight_lattice(self, extended = False): sage: RootSystem(['A',3]).weight_lattice() Weight lattice of the Root system of type ['A', 3] - sage: RootSystem(['A',3,1]).weight_space(extended = True) - Extended weight space over the Rational Field of the Root system of type ['A', 3, 1] + sage: RootSystem(['A',3,1]).weight_space(extended=True) + Extended weight space over the Rational Field + of the Root system of type ['A', 3, 1] """ - return WeightSpace(self, ZZ, extended = extended) + return WeightSpace(self, ZZ, extended=extended) @cached_method - def weight_space(self, base_ring=QQ, extended = False): + def weight_space(self, base_ring=QQ, extended=False): """ - Returns the weight space associated to self. + Returns the weight space associated to ``self``. .. SEEALSO:: @@ -567,14 +569,15 @@ def weight_space(self, base_ring=QQ, extended = False): sage: RootSystem(['A',3]).weight_space() Weight space over the Rational Field of the Root system of type ['A', 3] - sage: RootSystem(['A',3,1]).weight_space(extended = True) - Extended weight space over the Rational Field of the Root system of type ['A', 3, 1] + sage: RootSystem(['A',3,1]).weight_space(extended=True) + Extended weight space over the Rational Field + of the Root system of type ['A', 3, 1] """ - return WeightSpace(self, base_ring, extended = extended) + return WeightSpace(self, base_ring, extended=extended) - def coweight_lattice(self, extended = False): + def coweight_lattice(self, extended=False): """ - Returns the coweight lattice associated to self. + Return the coweight lattice associated to ``self``. This is the weight lattice of the dual root system. @@ -589,14 +592,14 @@ def coweight_lattice(self, extended = False): sage: RootSystem(['A',3]).coweight_lattice() Coweight lattice of the Root system of type ['A', 3] - sage: RootSystem(['A',3,1]).coweight_lattice(extended = True) + sage: RootSystem(['A',3,1]).coweight_lattice(extended=True) Extended coweight lattice of the Root system of type ['A', 3, 1] """ - return self.dual.weight_lattice(extended = extended) + return self.dual.weight_lattice(extended=extended) - def coweight_space(self, base_ring=QQ, extended = False): + def coweight_space(self, base_ring=QQ, extended=False): """ - Returns the coweight space associated to self. + Return the coweight space associated to ``self``. This is the weight space of the dual root system. @@ -612,9 +615,10 @@ def coweight_space(self, base_ring=QQ, extended = False): Coweight space over the Rational Field of the Root system of type ['A', 3] sage: RootSystem(['A',3,1]).coweight_space(extended=True) - Extended coweight space over the Rational Field of the Root system of type ['A', 3, 1] + Extended coweight space over the Rational Field + of the Root system of type ['A', 3, 1] """ - return self.dual.weight_space(base_ring, extended = extended) + return self.dual.weight_space(base_ring, extended=extended) def ambient_lattice(self): r""" @@ -720,7 +724,7 @@ def ambient_space(self, base_ring=QQ): An alternative base ring can be provided as an option:: sage: e = RootSystem(['B',3]).ambient_space(RR) - sage: TestSuite(e).run() + sage: TestSuite(e).run() # needs sage.graphs It should contain the smallest ring over which the ambient space can be defined (`\ZZ` in type `A` or `\QQ` otherwise). @@ -733,7 +737,7 @@ def ambient_space(self, base_ring=QQ): you are welcome to experiment:: sage: e = RootSystem(['G',2]).ambient_space(RR) - sage: TestSuite(e).run() + sage: TestSuite(e).run() # needs sage.graphs Failure in _test_root_lattice_realization: Traceback (most recent call last): ... @@ -787,9 +791,9 @@ def WeylDim(ct, coeffs): INPUT: - - ``type`` - a Cartan type + - ``ct`` -- a Cartan type - - ``coeffs`` - a list of nonnegative integers + - ``coeffs`` -- a list of nonnegative integers The length of the list must equal the rank type[1]. A dominant @@ -802,17 +806,20 @@ def WeylDim(ct, coeffs): For `SO(7)`, the Cartan type is `B_3`, so:: - sage: WeylDim(['B',3],[1,0,0]) # standard representation of SO(7) + sage: WeylDim(['B',3],[1,0,0]) # standard representation of SO(7) 7 - sage: WeylDim(['B',3],[0,1,0]) # exterior square + sage: WeylDim(['B',3],[0,1,0]) # exterior square 21 - sage: WeylDim(['B',3],[0,0,1]) # spin representation of spin(7) + sage: WeylDim(['B',3],[0,0,1]) # spin representation of spin(7) 8 - sage: WeylDim(['B',3],[1,0,1]) # sum of the first and third fundamental weights + sage: WeylDim(['B',3],[1,0,1]) # sum of the first and third fundamental weights 48 sage: [WeylDim(['F',4],x) for x in ([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1])] [52, 1274, 273, 26] - sage: [WeylDim(['E', 6], x) for x in ([0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 2], [0, 0, 0, 0, 1, 0], [0, 0, 1, 0, 0, 0], [1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1], [2, 0, 0, 0, 0, 0])] + sage: [WeylDim(['E', 6], x) + ....: for x in ([0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1], + ....: [0, 0, 0, 0, 0, 2], [0, 0, 0, 0, 1, 0], [0, 0, 1, 0, 0, 0], + ....: [1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1], [2, 0, 0, 0, 0, 0])] [1, 78, 27, 351, 351, 351, 27, 650, 351] """ ct = CartanType(ct) diff --git a/src/sage/combinat/root_system/type_A.py b/src/sage/combinat/root_system/type_A.py index e48524ffbcc..96bcec25f39 100644 --- a/src/sage/combinat/root_system/type_A.py +++ b/src/sage/combinat/root_system/type_A.py @@ -22,10 +22,11 @@ class AmbientSpace(ambient_space.AmbientSpace): sage: R = RootSystem(["A",3]) sage: e = R.ambient_space(); e Ambient space of the Root system of type ['A', 3] - sage: TestSuite(e).run() + sage: TestSuite(e).run() # needs sage.graphs By default, this ambient space uses the barycentric projection for plotting:: + sage: # needs sage.symbolic sage: L = RootSystem(["A",2]).ambient_space() sage: e = L.basis() sage: L._plot_projection(e[0]) @@ -253,22 +254,20 @@ def dynkin_diagram(self): EXAMPLES:: - sage: a = CartanType(['A',3]).dynkin_diagram() - sage: a + sage: a = CartanType(['A',3]).dynkin_diagram(); a # needs sage.graphs O---O---O 1 2 3 A3 - sage: a.edges(sort=True) + sage: a.edges(sort=True) # needs sage.graphs [(1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 1)] TESTS:: - sage: a = DynkinDiagram(['A',1]) - sage: a + sage: a = DynkinDiagram(['A',1]); a # needs sage.graphs O 1 A1 - sage: a.vertices(sort=False), a.edges(sort=False) + sage: a.vertices(sort=False), a.edges(sort=False) # needs sage.graphs ([1], []) """ from .dynkin_diagram import DynkinDiagram_class @@ -335,7 +334,7 @@ def ascii_art(self, label=lambda i: i, node=None): return "" if node is None: node = self._ascii_art_node - ret = "---".join(node(label(i)) for i in range(1,n+1)) + "\n" + ret = "---".join(node(label(i)) for i in range(1,n+1)) + "\n" ret += "".join("{!s:4}".format(label(i)) for i in range(1,n+1)) return ret diff --git a/src/sage/combinat/root_system/type_A_affine.py b/src/sage/combinat/root_system/type_A_affine.py index e5fc4d00935..f10d15c7f0e 100644 --- a/src/sage/combinat/root_system/type_A_affine.py +++ b/src/sage/combinat/root_system/type_A_affine.py @@ -72,8 +72,7 @@ def dynkin_diagram(self): EXAMPLES:: - sage: a = CartanType(['A',3,1]).dynkin_diagram() - sage: a + sage: a = CartanType(['A',3,1]).dynkin_diagram(); a # needs sage.graphs 0 O-------+ | | @@ -81,7 +80,7 @@ def dynkin_diagram(self): O---O---O 1 2 3 A3~ - sage: a.edges(sort=True) + sage: a.edges(sort=True) # needs sage.graphs [(0, 1, 1), (0, 3, 1), (1, 0, 1), @@ -91,12 +90,11 @@ def dynkin_diagram(self): (3, 0, 1), (3, 2, 1)] - sage: a = DynkinDiagram(['A',1,1]) - sage: a + sage: a = DynkinDiagram(['A',1,1]); a # needs sage.graphs O<=>O 0 1 A1~ - sage: a.edges(sort=True) + sage: a.edges(sort=True) # needs sage.graphs [(0, 1, 2), (1, 0, 2)] """ from .dynkin_diagram import DynkinDiagram_class @@ -133,8 +131,8 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2): if node is None: node = self._latex_draw_node if self.n == 1: - ret = "\\draw (0, 0.1 cm) -- +(%s cm,0);\n"%node_dist - ret += "\\draw (0, -0.1 cm) -- +(%s cm,0);\n"%node_dist + ret = "\\draw (0, 0.1 cm) -- +(%s cm,0);\n" % node_dist + ret += "\\draw (0, -0.1 cm) -- +(%s cm,0);\n" % node_dist ret += self._latex_draw_arrow_tip(0.33*node_dist-0.2, 0, 180) ret += self._latex_draw_arrow_tip(0.66*node_dist+0.2, 0, 0) ret += node(0, 0, label(0)) @@ -142,9 +140,9 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2): return ret rt_most = (self.n-1)*node_dist mid = 0.5 * rt_most - ret = "\\draw (0 cm,0) -- (%s cm,0);\n"%rt_most - ret += "\\draw (0 cm,0) -- (%s cm, 1.2 cm);\n"%mid - ret += "\\draw (%s cm, 1.2 cm) -- (%s cm, 0);\n"%(mid, rt_most) + ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % rt_most + ret += "\\draw (0 cm,0) -- (%s cm, 1.2 cm);\n" % mid + ret += "\\draw (%s cm, 1.2 cm) -- (%s cm, 0);\n" % (mid, rt_most) for i in range(self.n): ret += node(i*node_dist, 0, label(i+1)) ret += node(mid, 1.2, label(0), 'anchor=south east') @@ -187,7 +185,7 @@ def ascii_art(self, label=lambda i: i, node=None): l0 = label(0) l1 = label(1) return "{}<=>{}\n{!s:4}{}".format(node(l0), node(l1), l0, l1) - ret = "{}\n{}".format(label(0), node(label(0))) + ret = "{}\n{}".format(label(0), node(label(0))) ret += "----"*(n-2) + "---+\n|" + " "*(n-2) + " |\n|" + " "*(n-2) + " |\n" ret += "---".join(node(label(i)) for i in range(1,n+1)) + "\n" ret += "".join("{!s:4}".format(label(i)) for i in range(1,n+1)) diff --git a/src/sage/combinat/root_system/type_B.py b/src/sage/combinat/root_system/type_B.py index 9175d87bfa7..67794141adc 100644 --- a/src/sage/combinat/root_system/type_B.py +++ b/src/sage/combinat/root_system/type_B.py @@ -222,20 +222,18 @@ def dynkin_diagram(self): EXAMPLES:: - sage: b = CartanType(['B',3]).dynkin_diagram() - sage: b + sage: b = CartanType(['B',3]).dynkin_diagram(); b # needs sage.graphs O---O=>=O 1 2 3 B3 - sage: b.edges(sort=True) + sage: b.edges(sort=True) # needs sage.graphs [(1, 2, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1)] - sage: b = CartanType(['B',1]).dynkin_diagram() - sage: b + sage: b = CartanType(['B',1]).dynkin_diagram(); b # needs sage.graphs O 1 B1 - sage: b.edges(sort=True) + sage: b.edges(sort=True) # needs sage.graphs [] """ from .dynkin_diagram import DynkinDiagram_class @@ -340,7 +338,6 @@ def _default_folded_cartan_type(self): [[i] for i in range(1, n)] + [[n, n + 1]]) - # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.combinat.root_system.type_B', diff --git a/src/sage/combinat/root_system/type_BC_affine.py b/src/sage/combinat/root_system/type_BC_affine.py index aaa101b3350..bbc261902fb 100644 --- a/src/sage/combinat/root_system/type_BC_affine.py +++ b/src/sage/combinat/root_system/type_BC_affine.py @@ -22,9 +22,9 @@ def __init__(self, n): sage: ct = CartanType(['BC',4,2]) sage: ct ['BC', 4, 2] - sage: ct._repr_(compact = True) + sage: ct._repr_(compact=True) 'BC4~' - sage: ct.dynkin_diagram() + sage: ct.dynkin_diagram() # needs sage.graphs O=<=O---O---O=<=O 0 1 2 3 4 BC4~ @@ -43,19 +43,19 @@ def __init__(self, n): ['C', 4] sage: dual = ct.dual() - sage: dual.dynkin_diagram() + sage: dual.dynkin_diagram() # needs sage.graphs O=>=O---O---O=>=O 0 1 2 3 4 BC4~* sage: dual.special_node() 0 - sage: dual.classical().dynkin_diagram() + sage: dual.classical().dynkin_diagram() # needs sage.graphs O---O---O=>=O 1 2 3 4 B4 - sage: CartanType(['BC',1,2]).dynkin_diagram() + sage: CartanType(['BC',1,2]).dynkin_diagram() # needs sage.graphs 4 O=<=O 0 1 @@ -74,37 +74,34 @@ def dynkin_diagram(self): EXAMPLES:: - sage: c = CartanType(['BC',3,2]).dynkin_diagram() - sage: c + sage: c = CartanType(['BC',3,2]).dynkin_diagram(); c # needs sage.graphs O=<=O---O=<=O 0 1 2 3 BC3~ - sage: c.edges(sort=True) + sage: c.edges(sort=True) # needs sage.graphs [(0, 1, 1), (1, 0, 2), (1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 2)] - sage: c = CartanType(["A", 6, 2]).dynkin_diagram() # should be the same as above; did fail at some point! - sage: c + sage: c = CartanType(["A", 6, 2]).dynkin_diagram() # should be the same as above; did fail at some point! # needs sage.graphs + sage: c # needs sage.graphs O=<=O---O=<=O 0 1 2 3 BC3~ - sage: c.edges(sort=True) + sage: c.edges(sort=True) # needs sage.graphs [(0, 1, 1), (1, 0, 2), (1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 2)] - sage: c = CartanType(['BC',2,2]).dynkin_diagram() - sage: c + sage: c = CartanType(['BC',2,2]).dynkin_diagram(); c # needs sage.graphs O=<=O=<=O 0 1 2 BC2~ - sage: c.edges(sort=True) + sage: c.edges(sort=True) # needs sage.graphs [(0, 1, 1), (1, 0, 2), (1, 2, 1), (2, 1, 2)] - sage: c = CartanType(['BC',1,2]).dynkin_diagram() - sage: c + sage: c = CartanType(['BC',1,2]).dynkin_diagram(); c # needs sage.graphs 4 O=<=O 0 1 BC1~ - sage: c.edges(sort=True) + sage: c.edges(sort=True) # needs sage.graphs [(0, 1, 1), (1, 0, 4)] """ @@ -186,10 +183,10 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2, dual= if node is None: node = self._latex_draw_node if self.n == 1: - ret = "\\draw (0, 0.05 cm) -- +(%s cm,0);\n"%node_dist - ret += "\\draw (0, -0.05 cm) -- +(%s cm,0);\n"%node_dist - ret += "\\draw (0, 0.15 cm) -- +(%s cm,0);\n"%node_dist - ret += "\\draw (0, -0.15 cm) -- +(%s cm,0);\n"%node_dist + ret = "\\draw (0, 0.05 cm) -- +(%s cm,0);\n" % node_dist + ret += "\\draw (0, -0.05 cm) -- +(%s cm,0);\n" % node_dist + ret += "\\draw (0, 0.15 cm) -- +(%s cm,0);\n" % node_dist + ret += "\\draw (0, -0.15 cm) -- +(%s cm,0);\n" % node_dist if dual: ret += self._latex_draw_arrow_tip(0.5*node_dist+0.2, 0, 0) else: @@ -198,13 +195,13 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2, dual= ret += node(node_dist, 0, label(1)) return ret - ret = "\\draw (0, 0.1 cm) -- +(%s cm,0);\n"%node_dist - ret += "\\draw (0, -0.1 cm) -- +(%s cm,0);\n"%node_dist + ret = "\\draw (0, 0.1 cm) -- +(%s cm,0);\n" % node_dist + ret += "\\draw (0, -0.1 cm) -- +(%s cm,0);\n" % node_dist if dual: ret += self._latex_draw_arrow_tip(0.5*node_dist+0.2, 0, 0) else: ret += self._latex_draw_arrow_tip(0.5*node_dist-0.2, 0, 180) - ret += "{\n\\pgftransformxshift{%s cm}\n"%node_dist + ret += "{\n\\pgftransformxshift{%s cm}\n" % node_dist ret += self.classical()._latex_dynkin_diagram(label, node, node_dist, dual=dual) ret += "}\n" + node(0, 0, label(0)) return ret diff --git a/src/sage/combinat/root_system/type_B_affine.py b/src/sage/combinat/root_system/type_B_affine.py index fd709894a6e..6cfe46255ae 100644 --- a/src/sage/combinat/root_system/type_B_affine.py +++ b/src/sage/combinat/root_system/type_B_affine.py @@ -54,8 +54,8 @@ def dynkin_diagram(self): EXAMPLES:: - sage: b = CartanType(['B',3,1]).dynkin_diagram() - sage: b + sage: # needs sage.graphs + sage: b = CartanType(['B',3,1]).dynkin_diagram(); b O 0 | | @@ -64,14 +64,12 @@ def dynkin_diagram(self): B3~ sage: b.edges(sort=True) [(0, 2, 1), (1, 2, 1), (2, 0, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1)] - sage: b = CartanType(['B',2,1]).dynkin_diagram(); b O=>=O=<=O 0 2 1 B2~ sage: b.edges(sort=True) [(0, 2, 2), (1, 2, 2), (2, 0, 1), (2, 1, 1)] - sage: b = CartanType(['B',1,1]).dynkin_diagram(); b O<=>O 0 1 @@ -142,17 +140,17 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2, dual= return cartan_type.CartanType(["C",2,1])._latex_dynkin_diagram(label, node, node_dist, dual) n = self.n single_end = (n-2)*node_dist # Where the single line ends - ret = "\\draw (0,0.7 cm) -- (%s cm,0);\n"%node_dist - ret += "\\draw (0,-0.7 cm) -- (%s cm,0);\n"%node_dist - ret += "\\draw (%s cm,0) -- (%s cm,0);\n"%(node_dist, single_end) - ret += "\\draw (%s cm, 0.1 cm) -- +(%s cm,0);\n"%(single_end, node_dist) - ret += "\\draw (%s cm, -0.1 cm) -- +(%s cm,0);\n"%(single_end, node_dist) + ret = "\\draw (0,0.7 cm) -- (%s cm,0);\n" % node_dist + ret += "\\draw (0,-0.7 cm) -- (%s cm,0);\n" % node_dist + ret += "\\draw (%s cm,0) -- (%s cm,0);\n" % (node_dist, single_end) + ret += "\\draw (%s cm, 0.1 cm) -- +(%s cm,0);\n" % (single_end, node_dist) + ret += "\\draw (%s cm, -0.1 cm) -- +(%s cm,0);\n" % (single_end, node_dist) if dual: ret += self._latex_draw_arrow_tip(single_end+0.5*node_dist-0.2, 0, 180) else: ret += self._latex_draw_arrow_tip(single_end+0.5*node_dist+0.2, 0, 0) ret += node(0, 0.7, label(0), 'left=3pt') - ret +=node(0, -0.7, label(1), 'left=3pt') + ret += node(0, -0.7, label(1), 'left=3pt') for i in range(1, n): ret += node(i*node_dist, 0, label(i+1)) return ret @@ -192,7 +190,7 @@ def ascii_art(self, label=lambda i: i, node=None): return CartanType(["A",1,1]).ascii_art(label, node) if n == 2: return CartanType(["C",2,1]).relabel({0:0, 1:2, 2:1}).ascii_art(label, node) - ret = " {} {}\n |\n |\n".format(node(label(0)), label(0)) + ret = " {} {}\n |\n |\n".format(node(label(0)), label(0)) ret += "---".join(node(label(i)) for i in range(1,n)) + "=>={}\n".format(node(label(n))) ret += "".join("{!s:4}".format(label(i)) for i in range(1,n+1)) return ret diff --git a/src/sage/combinat/root_system/type_C.py b/src/sage/combinat/root_system/type_C.py index 57fdde0b5a5..57669883bea 100644 --- a/src/sage/combinat/root_system/type_C.py +++ b/src/sage/combinat/root_system/type_C.py @@ -31,7 +31,7 @@ class AmbientSpace(ambient_space.AmbientSpace): TESTS:: - sage: TestSuite(e).run() + sage: TestSuite(e).run() # needs sage.graphs """ def dimension(self): @@ -216,20 +216,18 @@ def dynkin_diagram(self): EXAMPLES:: - sage: c = CartanType(['C',3]).dynkin_diagram() - sage: c + sage: c = CartanType(['C',3]).dynkin_diagram(); c # needs sage.graphs O---O=<=O 1 2 3 C3 - sage: c.edges(sort=True) + sage: c.edges(sort=True) # needs sage.graphs [(1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 2)] - sage: b = CartanType(['C',1]).dynkin_diagram() - sage: b + sage: b = CartanType(['C',1]).dynkin_diagram(); b # needs sage.graphs O 1 C1 - sage: b.edges(sort=True) + sage: b.edges(sort=True) # needs sage.graphs [] """ return self.dual().dynkin_diagram().dual() diff --git a/src/sage/combinat/root_system/type_C_affine.py b/src/sage/combinat/root_system/type_C_affine.py index 481626372bd..72843b4d0a9 100644 --- a/src/sage/combinat/root_system/type_C_affine.py +++ b/src/sage/combinat/root_system/type_C_affine.py @@ -54,12 +54,11 @@ def dynkin_diagram(self): EXAMPLES:: - sage: c = CartanType(['C',3,1]).dynkin_diagram() - sage: c + sage: c = CartanType(['C',3,1]).dynkin_diagram(); c # needs sage.graphs O=>=O---O=<=O 0 1 2 3 C3~ - sage: c.edges(sort=True) + sage: c.edges(sort=True) # needs sage.graphs [(0, 1, 2), (1, 0, 1), (1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 2)] """ @@ -124,13 +123,13 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2, dual= from . import cartan_type return cartan_type.CartanType(["A",1,1])._latex_dynkin_diagram(label, node, node_dist) - ret = "\\draw (0, 0.1 cm) -- +(%s cm,0);\n"%node_dist - ret += "\\draw (0, -0.1 cm) -- +(%s cm,0);\n"%node_dist + ret = "\\draw (0, 0.1 cm) -- +(%s cm,0);\n" % node_dist + ret += "\\draw (0, -0.1 cm) -- +(%s cm,0);\n" % node_dist if dual: ret += self._latex_draw_arrow_tip(0.5*node_dist-0.2, 0, 180) else: ret += self._latex_draw_arrow_tip(0.5*node_dist+0.2, 0, 0) - ret += "{\n\\pgftransformxshift{%s cm}\n"%node_dist + ret += "{\n\\pgftransformxshift{%s cm}\n" % node_dist ret += self.classical()._latex_dynkin_diagram(label, node, node_dist, dual) ret += "}\n" + node(0, 0, label(0)) return ret diff --git a/src/sage/combinat/root_system/type_D.py b/src/sage/combinat/root_system/type_D.py index be106a845a7..28d4cd29cb2 100644 --- a/src/sage/combinat/root_system/type_D.py +++ b/src/sage/combinat/root_system/type_D.py @@ -116,7 +116,6 @@ def fundamental_weight(self, i): return self.sum(self.monomial(j) for j in range(i)) - from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.combinat.root_system.type_A', 'ambient_space', AmbientSpace) @@ -225,42 +224,43 @@ def dynkin_diagram(self): EXAMPLES:: - sage: d = CartanType(['D',5]).dynkin_diagram(); d + sage: d = CartanType(['D',5]).dynkin_diagram(); d # needs sage.graphs O 5 | | O---O---O---O 1 2 3 4 D5 - sage: d.edges(sort=True) - [(1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 1), (3, 4, 1), (3, 5, 1), (4, 3, 1), (5, 3, 1)] + sage: d.edges(sort=True) # needs sage.graphs + [(1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 1), + (3, 4, 1), (3, 5, 1), (4, 3, 1), (5, 3, 1)] - sage: d = CartanType(['D',4]).dynkin_diagram(); d + sage: d = CartanType(['D',4]).dynkin_diagram(); d # needs sage.graphs O 4 | | O---O---O 1 2 3 D4 - sage: d.edges(sort=True) + sage: d.edges(sort=True) # needs sage.graphs [(1, 2, 1), (2, 1, 1), (2, 3, 1), (2, 4, 1), (3, 2, 1), (4, 2, 1)] - sage: d = CartanType(['D',3]).dynkin_diagram(); d + sage: d = CartanType(['D',3]).dynkin_diagram(); d # needs sage.graphs O 3 | | O---O 1 2 D3 - sage: d.edges(sort=True) + sage: d.edges(sort=True) # needs sage.graphs [(1, 2, 1), (1, 3, 1), (2, 1, 1), (3, 1, 1)] - sage: d = CartanType(['D',2]).dynkin_diagram(); d + sage: d = CartanType(['D',2]).dynkin_diagram(); d # needs sage.graphs O O 1 2 D2 - sage: d.edges(sort=True) + sage: d.edges(sort=True) # needs sage.graphs [] """ from .dynkin_diagram import DynkinDiagram_class @@ -296,9 +296,9 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2): return ret rt_most = (self.n-2) * node_dist center_point = rt_most - node_dist - ret = "\\draw (0 cm,0) -- (%s cm,0);\n"%center_point - ret += "\\draw (%s cm,0) -- (%s cm,0.7 cm);\n"%(center_point, rt_most) - ret += "\\draw (%s cm,0) -- (%s cm,-0.7 cm);\n"%(center_point, rt_most) + ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % center_point + ret += "\\draw (%s cm,0) -- (%s cm,0.7 cm);\n" % (center_point, rt_most) + ret += "\\draw (%s cm,0) -- (%s cm,-0.7 cm);\n" % (center_point, rt_most) for i in range(self.n-2): ret += node(i*node_dist, 0, label(i+1)) ret += node(rt_most, 0.7, label(self.n), 'right=3pt') @@ -342,9 +342,9 @@ def ascii_art(self, label=lambda i: i, node=None): if n == 2: ret = "{} {}\n".format(node(label(1)), node(label(2))) return ret + "{!s:4}{!s:4}".format(label(1), label(2)) - ret = (4*(n-3))*" "+"{} {}\n".format(node(label(n)), label(n)) - ret += ((4*(n-3))*" " +"|\n")*2 - ret += "---".join(node(label(i)) for i in range(1, n)) +"\n" + ret = (4*(n-3))*" "+"{} {}\n".format(node(label(n)), label(n)) + ret += ((4*(n-3))*" " + "|\n")*2 + ret += "---".join(node(label(i)) for i in range(1, n)) + "\n" ret += "".join("{!s:4}".format(label(i)) for i in range(1,n)) return ret diff --git a/src/sage/combinat/root_system/type_D_affine.py b/src/sage/combinat/root_system/type_D_affine.py index ae1b67812ff..3ea86f32438 100644 --- a/src/sage/combinat/root_system/type_D_affine.py +++ b/src/sage/combinat/root_system/type_D_affine.py @@ -54,20 +54,18 @@ def dynkin_diagram(self): EXAMPLES:: - sage: d = CartanType(['D', 6, 1]).dynkin_diagram() - sage: d + sage: d = CartanType(['D', 6, 1]).dynkin_diagram(); d # needs sage.graphs 0 O O 6 | | | | O---O---O---O---O 1 2 3 4 5 D6~ - sage: d.edges(sort=True) + sage: d.edges(sort=True) # needs sage.graphs [(0, 2, 1), (1, 2, 1), (2, 0, 1), (2, 1, 1), (2, 3, 1), (3, 2, 1), (3, 4, 1), (4, 3, 1), (4, 5, 1), (4, 6, 1), (5, 4, 1), (6, 4, 1)] - sage: d = CartanType(['D', 4, 1]).dynkin_diagram() - sage: d + sage: d = CartanType(['D', 4, 1]).dynkin_diagram(); d # needs sage.graphs O 4 | | @@ -76,7 +74,7 @@ def dynkin_diagram(self): | O 0 D4~ - sage: d.edges(sort=True) + sage: d.edges(sort=True) # needs sage.graphs [(0, 2, 1), (1, 2, 1), (2, 0, 1), @@ -86,8 +84,7 @@ def dynkin_diagram(self): (3, 2, 1), (4, 2, 1)] - sage: d = CartanType(['D', 3, 1]).dynkin_diagram() - sage: d + sage: d = CartanType(['D', 3, 1]).dynkin_diagram(); d # needs sage.graphs 0 O-------+ | | @@ -95,8 +92,9 @@ def dynkin_diagram(self): O---O---O 3 1 2 D3~ - sage: d.edges(sort=True) - [(0, 2, 1), (0, 3, 1), (1, 2, 1), (1, 3, 1), (2, 0, 1), (2, 1, 1), (3, 0, 1), (3, 1, 1)] + sage: d.edges(sort=True) # needs sage.graphs + [(0, 2, 1), (0, 3, 1), (1, 2, 1), (1, 3, 1), + (2, 0, 1), (2, 1, 1), (3, 0, 1), (3, 1, 1)] """ from .dynkin_diagram import DynkinDiagram_class @@ -141,11 +139,11 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2, dual= return cartan_type.CartanType(["A",3,1]).relabel(relabel)._latex_dynkin_diagram(node_dist=node_dist) rt_most = (n - 2) * node_dist center_point = rt_most - node_dist - ret = "\\draw (0,0.7 cm) -- (%s cm,0);\n"%node_dist - ret += "\\draw (0,-0.7 cm) -- (%s cm,0);\n"%node_dist - ret += "\\draw (%s cm,0) -- (%s cm,0);\n"%(node_dist, center_point) - ret += "\\draw (%s cm,0) -- (%s cm,0.7 cm);\n"%(center_point, rt_most) - ret += "\\draw (%s cm,0) -- (%s cm,-0.7 cm);\n"%(center_point, rt_most) + ret = "\\draw (0,0.7 cm) -- (%s cm,0);\n" % node_dist + ret += "\\draw (0,-0.7 cm) -- (%s cm,0);\n" % node_dist + ret += "\\draw (%s cm,0) -- (%s cm,0);\n" % (node_dist, center_point) + ret += "\\draw (%s cm,0) -- (%s cm,0.7 cm);\n" % (center_point, rt_most) + ret += "\\draw (%s cm,0) -- (%s cm,-0.7 cm);\n" % (center_point, rt_most) ret += node(0, 0.7, label(0), "left=3pt") ret += node(0, -0.7, label(1), "left=3pt") for i in range(1, self.n-2): diff --git a/src/sage/combinat/root_system/type_E.py b/src/sage/combinat/root_system/type_E.py index 05b81a31c60..478c628a5e9 100644 --- a/src/sage/combinat/root_system/type_E.py +++ b/src/sage/combinat/root_system/type_E.py @@ -384,18 +384,18 @@ def positive_roots(self): self.PosRoots = ( [ self.root(i,j) for i in range(self.rank-1) for j in range(i+1,self.rank-1) ] + [ self.root(i,j,p1=1) for i in range(self.rank-1) for j in range(i+1,self.rank-1) ] + [ v*(self.root(7)-self.root(6)-self.root(5)+self.root(0,1,2,3,4,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5)) - for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] if (p1+p2+p3+p4+p5)%2 == 0 ]) + for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] if (p1+p2+p3+p4+p5) % 2 == 0 ]) elif self.rank == 7: self.PosRoots = ( [ self.root(i,j) for i in range(self.rank-1) for j in range(i+1,self.rank-1) ] + [ self.root(i,j,p1=1) for i in range(self.rank-1) for j in range(i+1,self.rank-1) ] + [ self.root(6,7,p1=1) ] + [ v*(self.root(7)-self.root(6)+self.root(0,1,2,3,4,5,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5,p6=p6)) - for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] for p6 in [0,1] if (p1+p2+p3+p4+p5+p6)%2 == 1 ]) + for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] for p6 in [0,1] if (p1+p2+p3+p4+p5+p6) % 2 == 1 ]) elif self.rank == 8: self.PosRoots = ( [ self.root(i,j) for i in range(self.rank) for j in range(i+1,self.rank) ] + [ self.root(i,j,p1=1) for i in range(self.rank) for j in range(i+1,self.rank) ] + [ v*(self.root(7)+self.root(0,1,2,3,4,5,6,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5,p6=p6,p7=p7)) - for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] for p6 in [0,1] for p7 in [0,1] if (p1+p2+p3+p4+p5+p6+p7)%2 == 0 ]) + for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] for p6 in [0,1] for p7 in [0,1] if (p1+p2+p3+p4+p5+p6+p7) % 2 == 0 ]) return self.PosRoots @@ -530,8 +530,8 @@ def dynkin_diagram(self): EXAMPLES:: - sage: e = CartanType(['E',6]).dynkin_diagram() - sage: e + sage: # needs sage.graphs + sage: e = CartanType(['E',6]).dynkin_diagram(); e O 2 | | @@ -539,9 +539,9 @@ def dynkin_diagram(self): 1 3 4 5 6 E6 sage: e.edges(sort=True) - [(1, 3, 1), (2, 4, 1), (3, 1, 1), (3, 4, 1), (4, 2, 1), (4, 3, 1), (4, 5, 1), (5, 4, 1), (5, 6, 1), (6, 5, 1)] - sage: e = CartanType(['E',7]).dynkin_diagram() - sage: e + [(1, 3, 1), (2, 4, 1), (3, 1, 1), (3, 4, 1), (4, 2, 1), + (4, 3, 1), (4, 5, 1), (5, 4, 1), (5, 6, 1), (6, 5, 1)] + sage: e = CartanType(['E',7]).dynkin_diagram(); e O 2 | | @@ -552,8 +552,7 @@ def dynkin_diagram(self): [(1, 3, 1), (2, 4, 1), (3, 1, 1), (3, 4, 1), (4, 2, 1), (4, 3, 1), (4, 5, 1), (5, 4, 1), (5, 6, 1), (6, 5, 1), (6, 7, 1), (7, 6, 1)] - sage: e = CartanType(['E',8]).dynkin_diagram() - sage: e + sage: e = CartanType(['E',8]).dynkin_diagram(); e O 2 | | @@ -594,8 +593,8 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2): """ if node is None: node = self._latex_draw_node - ret = "\\draw (0 cm,0) -- (%s cm,0);\n"%((self.n-2)*node_dist) - ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n"%(2*node_dist, node_dist) + ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % ((self.n-2)*node_dist) + ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n" % (2*node_dist, node_dist) ret += node(0, 0, label(1)) for i in range(1, self.n-1): ret += node(i*node_dist, 0, label(i+2)) diff --git a/src/sage/combinat/root_system/type_E_affine.py b/src/sage/combinat/root_system/type_E_affine.py index d7b8bbb2a34..ac64cbfbdde 100644 --- a/src/sage/combinat/root_system/type_E_affine.py +++ b/src/sage/combinat/root_system/type_E_affine.py @@ -66,8 +66,7 @@ def dynkin_diagram(self): EXAMPLES:: - sage: e = CartanType(['E', 6, 1]).dynkin_diagram() - sage: e + sage: e = CartanType(['E', 6, 1]).dynkin_diagram(); e # needs sage.graphs O 0 | | @@ -77,7 +76,7 @@ def dynkin_diagram(self): O---O---O---O---O 1 3 4 5 6 E6~ - sage: e.edges(sort=True) + sage: e.edges(sort=True) # needs sage.graphs [(0, 2, 1), (1, 3, 1), (2, 0, 1), @@ -91,8 +90,8 @@ def dynkin_diagram(self): (5, 6, 1), (6, 5, 1)] - sage: e = CartanType(['E', 7, 1]).dynkin_diagram() - sage: e + sage: # needs sage.graphs + sage: e = CartanType(['E', 7, 1]).dynkin_diagram(); e O 2 | | @@ -103,8 +102,7 @@ def dynkin_diagram(self): [(0, 1, 1), (1, 0, 1), (1, 3, 1), (2, 4, 1), (3, 1, 1), (3, 4, 1), (4, 2, 1), (4, 3, 1), (4, 5, 1), (5, 4, 1), (5, 6, 1), (6, 5, 1), (6, 7, 1), (7, 6, 1)] - sage: e = CartanType(['E', 8, 1]).dynkin_diagram() - sage: e + sage: e = CartanType(['E', 8, 1]).dynkin_diagram(); e O 2 | | @@ -158,8 +156,8 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2): node = self._latex_draw_node if n == 7: - ret = "\\draw (0 cm,0) -- (%s cm,0);\n"%((n-1)*node_dist) - ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n"%(3*node_dist, node_dist) + ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % ((n-1)*node_dist) + ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n" % (3*node_dist, node_dist) ret += node(0, 0, label(0)) ret += node(node_dist, 0, label(1)) for i in range(2, n): @@ -167,14 +165,14 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2): ret += node(3*node_dist, node_dist, label(2), "right=3pt") return ret - ret = "\\draw (0 cm,0) -- (%s cm,0);\n"%((n-2)*node_dist) - ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n"%(2*node_dist, node_dist) + ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % ((n-2)*node_dist) + ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n" % (2*node_dist, node_dist) if n == 6: - ret += "\\draw (%s cm, %s cm) -- +(0,%s cm);\n"%(2*node_dist, node_dist, node_dist) + ret += "\\draw (%s cm, %s cm) -- +(0,%s cm);\n" % (2*node_dist, node_dist, node_dist) ret += node(2*node_dist, 2*node_dist, label(0), "right=3pt") else: # n == 8 - ret += "\\draw (%s cm,0) -- +(%s cm,0);\n"%((n-2)*node_dist, node_dist) + ret += "\\draw (%s cm,0) -- +(%s cm,0);\n" % ((n-2)*node_dist, node_dist) ret += node((n-1)*node_dist, 0, label(0)) ret += node(0, 0, label(1)) diff --git a/src/sage/combinat/root_system/type_F.py b/src/sage/combinat/root_system/type_F.py index a7ab233b1b2..ac33d97fbee 100644 --- a/src/sage/combinat/root_system/type_F.py +++ b/src/sage/combinat/root_system/type_F.py @@ -37,7 +37,7 @@ def __init__(self, root_system, base_ring): TESTS:: - sage: TestSuite(e).run() + sage: TestSuite(e).run() # needs sage.graphs """ ambient_space.AmbientSpace.__init__(self, root_system, base_ring) v = ZZ(1)/ZZ(2) @@ -275,12 +275,11 @@ def dynkin_diagram(self): EXAMPLES:: - sage: f = CartanType(['F',4]).dynkin_diagram() - sage: f + sage: f = CartanType(['F',4]).dynkin_diagram(); f # needs sage.graphs O---O=>=O---O 1 2 3 4 F4 - sage: f.edges(sort=True) + sage: f.edges(sort=True) # needs sage.graphs [(1, 2, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1), (3, 4, 1), (4, 3, 1)] """ @@ -311,10 +310,10 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2, dual= """ if node is None: node = self._latex_draw_node - ret = "\\draw (0 cm,0) -- (%s cm,0);\n"%node_dist - ret += "\\draw (%s cm, 0.1 cm) -- +(%s cm,0);\n"%(node_dist, node_dist) - ret += "\\draw (%s cm, -0.1 cm) -- +(%s cm,0);\n"%(node_dist, node_dist) - ret += "\\draw (%s cm,0) -- +(%s cm,0);\n"%(node_dist*2.0, node_dist) + ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % node_dist + ret += "\\draw (%s cm, 0.1 cm) -- +(%s cm,0);\n" % (node_dist, node_dist) + ret += "\\draw (%s cm, -0.1 cm) -- +(%s cm,0);\n" % (node_dist, node_dist) + ret += "\\draw (%s cm,0) -- +(%s cm,0);\n" % (node_dist*2.0, node_dist) if dual: ret += self._latex_draw_arrow_tip(1.5*node_dist-0.2, 0, 180) else: @@ -355,11 +354,11 @@ def dual(self): sage: F4.dual() ['F', 4] relabelled by {1: 4, 2: 3, 3: 2, 4: 1} - sage: F4.dynkin_diagram() + sage: F4.dynkin_diagram() # needs sage.graphs O---O=>=O---O 1 2 3 4 F4 - sage: F4.dual().dynkin_diagram() + sage: F4.dual().dynkin_diagram() # needs sage.graphs O---O=>=O---O 4 3 2 1 F4 relabelled by {1: 4, 2: 3, 3: 2, 4: 1} diff --git a/src/sage/combinat/root_system/type_F_affine.py b/src/sage/combinat/root_system/type_F_affine.py index 5e27c4c6aff..403c5b6e8ad 100644 --- a/src/sage/combinat/root_system/type_F_affine.py +++ b/src/sage/combinat/root_system/type_F_affine.py @@ -55,13 +55,13 @@ def dynkin_diagram(self): EXAMPLES:: - sage: f = CartanType(['F', 4, 1]).dynkin_diagram() - sage: f + sage: f = CartanType(['F', 4, 1]).dynkin_diagram(); f # needs sage.graphs O---O---O=>=O---O 0 1 2 3 4 F4~ - sage: f.edges(sort=True) - [(0, 1, 1), (1, 0, 1), (1, 2, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1), (3, 4, 1), (4, 3, 1)] + sage: f.edges(sort=True) # needs sage.graphs + [(0, 1, 1), (1, 0, 1), (1, 2, 1), (2, 1, 1), + (2, 3, 2), (3, 2, 1), (3, 4, 1), (4, 3, 1)] """ from .dynkin_diagram import DynkinDiagram_class @@ -97,8 +97,8 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2, dual= """ if node is None: node = self._latex_draw_node - ret = "\\draw (0 cm,0) -- (%s cm,0);\n"%node_dist - ret += "{\n\\pgftransformxshift{%s cm}\n"%node_dist + ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % node_dist + ret += "{\n\\pgftransformxshift{%s cm}\n" % node_dist ret += self.classical()._latex_dynkin_diagram(label, node, node_dist, dual) ret += "}\n" + node(0, 0, label(0)) return ret diff --git a/src/sage/combinat/root_system/type_G.py b/src/sage/combinat/root_system/type_G.py index ce953036dc1..15da57bc11c 100644 --- a/src/sage/combinat/root_system/type_G.py +++ b/src/sage/combinat/root_system/type_G.py @@ -32,6 +32,7 @@ class AmbientSpace(ambient_space.AmbientSpace): By default, this ambient space uses the barycentric projection for plotting:: + sage: # needs sage.symbolic sage: L = RootSystem(["G",2]).ambient_space() sage: e = L.basis() sage: L._plot_projection(e[0]) @@ -185,13 +186,12 @@ def dynkin_diagram(self): EXAMPLES:: - sage: g = CartanType(['G',2]).dynkin_diagram() - sage: g + sage: g = CartanType(['G',2]).dynkin_diagram(); g # needs sage.graphs 3 O=<=O 1 2 G2 - sage: g.edges(sort=True) + sage: g.edges(sort=True) # needs sage.graphs [(1, 2, 1), (2, 1, 3)] """ from .dynkin_diagram import DynkinDiagram_class @@ -217,9 +217,9 @@ def _latex_dynkin_diagram(self, label=lambda i: i, node=None, node_dist=2, dual= """ if node is None: node = self._latex_draw_node - ret = "\\draw (0,0) -- (%s cm,0);\n"%node_dist - ret += "\\draw (0, 0.15 cm) -- +(%s cm,0);\n"%node_dist - ret += "\\draw (0, -0.15 cm) -- +(%s cm,0);\n"%node_dist + ret = "\\draw (0,0) -- (%s cm,0);\n" % node_dist + ret += "\\draw (0, 0.15 cm) -- +(%s cm,0);\n" % node_dist + ret += "\\draw (0, -0.15 cm) -- +(%s cm,0);\n" % node_dist if dual: ret += self._latex_draw_arrow_tip(0.5*node_dist+0.2, 0, 0) else: @@ -256,12 +256,12 @@ def dual(self): sage: G2.dual() ['G', 2] relabelled by {1: 2, 2: 1} - sage: G2.dynkin_diagram() + sage: G2.dynkin_diagram() # needs sage.graphs 3 O=<=O 1 2 G2 - sage: G2.dual().dynkin_diagram() + sage: G2.dual().dynkin_diagram() # needs sage.graphs 3 O=<=O 2 1 diff --git a/src/sage/combinat/root_system/type_G_affine.py b/src/sage/combinat/root_system/type_G_affine.py index cde34a41753..2cb1487dfd8 100644 --- a/src/sage/combinat/root_system/type_G_affine.py +++ b/src/sage/combinat/root_system/type_G_affine.py @@ -55,13 +55,12 @@ def dynkin_diagram(self): EXAMPLES:: - sage: g = CartanType(['G',2,1]).dynkin_diagram() - sage: g + sage: g = CartanType(['G',2,1]).dynkin_diagram(); g # needs sage.graphs 3 O=<=O---O 1 2 0 G2~ - sage: g.edges(sort=True) + sage: g.edges(sort=True) # needs sage.graphs [(0, 2, 1), (1, 2, 1), (2, 0, 1), (2, 1, 3)] """ from .dynkin_diagram import DynkinDiagram_class @@ -92,9 +91,9 @@ def _latex_dynkin_diagram(self, label=lambda x: x, node=None, node_dist=2, dual= """ if node is None: node = self._latex_draw_node - ret = "\\draw (%s cm,0) -- (%s cm,0);\n"%(node_dist, node_dist*2.0) - ret += "\\draw (0, 0.15 cm) -- +(%s cm,0);\n"%node_dist - ret += "\\draw (0, -0.15 cm) -- +(%s cm,0);\n"%node_dist + ret = "\\draw (%s cm,0) -- (%s cm,0);\n" % (node_dist, node_dist*2.0) + ret += "\\draw (0, 0.15 cm) -- +(%s cm,0);\n" % node_dist + ret += "\\draw (0, -0.15 cm) -- +(%s cm,0);\n" % node_dist ret += self.classical()._latex_dynkin_diagram(label, node, node_dist, dual) ret += node(2*node_dist, 0, label(0)) return ret diff --git a/src/sage/combinat/root_system/type_H.py b/src/sage/combinat/root_system/type_H.py index 13d5b6eb04a..44f4b15db55 100644 --- a/src/sage/combinat/root_system/type_H.py +++ b/src/sage/combinat/root_system/type_H.py @@ -60,21 +60,21 @@ def coxeter_diagram(self): EXAMPLES:: sage: ct = CartanType(['H',3]) - sage: ct.coxeter_diagram() + sage: ct.coxeter_diagram() # needs sage.graphs Graph on 3 vertices - sage: ct.coxeter_diagram().edges(sort=True) + sage: ct.coxeter_diagram().edges(sort=True) # needs sage.graphs [(1, 2, 3), (2, 3, 5)] - sage: ct.coxeter_matrix() + sage: ct.coxeter_matrix() # needs sage.graphs [1 3 2] [3 1 5] [2 5 1] sage: ct = CartanType(['H',4]) - sage: ct.coxeter_diagram() + sage: ct.coxeter_diagram() # needs sage.graphs Graph on 4 vertices - sage: ct.coxeter_diagram().edges(sort=True) + sage: ct.coxeter_diagram().edges(sort=True) # needs sage.graphs [(1, 2, 3), (2, 3, 3), (3, 4, 5)] - sage: ct.coxeter_matrix() + sage: ct.coxeter_matrix() # needs sage.graphs [1 3 2 2] [3 1 3 2] [2 3 1 5] diff --git a/src/sage/combinat/root_system/type_I.py b/src/sage/combinat/root_system/type_I.py index bafa43b8410..76a24817bf9 100644 --- a/src/sage/combinat/root_system/type_I.py +++ b/src/sage/combinat/root_system/type_I.py @@ -84,11 +84,11 @@ def coxeter_diagram(self): EXAMPLES:: sage: ct = CartanType(['I', 4]) - sage: ct.coxeter_diagram() + sage: ct.coxeter_diagram() # needs sage.graphs Graph on 2 vertices - sage: ct.coxeter_diagram().edges(sort=True) + sage: ct.coxeter_diagram().edges(sort=True) # needs sage.graphs [(1, 2, 4)] - sage: ct.coxeter_matrix() + sage: ct.coxeter_matrix() # needs sage.graphs [1 4] [4 1] """ diff --git a/src/sage/combinat/root_system/type_Q.py b/src/sage/combinat/root_system/type_Q.py index a8884c8905a..b2aa3748e71 100644 --- a/src/sage/combinat/root_system/type_Q.py +++ b/src/sage/combinat/root_system/type_Q.py @@ -49,7 +49,7 @@ def __init__(self, m): assert m >= 2 CartanType_standard_finite.__init__(self, "Q", m-1) - def _repr_(self, compact = False): + def _repr_(self, compact=False): """ TESTS:: @@ -60,7 +60,7 @@ def _repr_(self, compact = False): 'Q4' """ format = '%s%s' if compact else "['%s', %s]" - return format%(self.letter, self.n+1) + return format % (self.letter, self.n+1) def __reduce__(self): """ diff --git a/src/sage/combinat/root_system/type_affine.py b/src/sage/combinat/root_system/type_affine.py index 12bf38eb52a..fd0695ee257 100644 --- a/src/sage/combinat/root_system/type_affine.py +++ b/src/sage/combinat/root_system/type_affine.py @@ -37,7 +37,7 @@ class AmbientSpace(CombinatorialFreeModule): In type `BC`, the null root is in fact:: sage: R = RootSystem(["BC",3,2]).ambient_space() - sage: R.null_root() + sage: R.null_root() # needs sage.graphs 2*e['delta'] .. WARNING:: @@ -51,19 +51,19 @@ class AmbientSpace(CombinatorialFreeModule): \delta,\delta\rangle=0` and similarly for the null coroot. In the current implementation, `\Lambda_0` and the null coroot - are identified: + are identified:: sage: L = RootSystem(["A",3,1]).ambient_space() - sage: Lambda = L.fundamental_weights() - sage: Lambda[0] + sage: Lambda = L.fundamental_weights() # needs sage.graphs + sage: Lambda[0] # needs sage.graphs e['deltacheck'] - sage: L.null_coroot() + sage: L.null_coroot() # needs sage.graphs e['deltacheck'] Therefore the scalar product of the null coroot with itself differs from the larger ambient space:: - sage: L.null_coroot().scalar(L.null_coroot()) + sage: L.null_coroot().scalar(L.null_coroot()) # needs sage.graphs 1 In general, scalar products between two elements that do not @@ -108,7 +108,7 @@ class AmbientSpace(CombinatorialFreeModule): TESTS:: - sage: Lambda[1] + sage: Lambda[1] # needs sage.graphs e[0] + e['deltacheck'] """ @classmethod @@ -158,10 +158,10 @@ def sortkey(x): return (1 if isinstance(x, str) else 0, x) CombinatorialFreeModule.__init__(self, base_ring, basis_keys, - prefix = "e", - latex_prefix = "e", + prefix="e", + latex_prefix="e", sorting_key=sortkey, - category = WeightLatticeRealizations(base_ring)) + category=WeightLatticeRealizations(base_ring)) self._weight_space = self.root_system.weight_space(base_ring=base_ring,extended=True) self.classical().module_morphism(self.monomial, codomain=self).register_as_coercion() # Duplicated from ambient_space.AmbientSpace @@ -214,7 +214,7 @@ def _to_classical_on_basis(self, i): sage: L._to_classical_on_basis(2) (0, 0, 1) """ - if i=="delta" or i=="deltacheck": + if i == "delta" or i == "deltacheck": return self.classical().zero() else: return self.classical().monomial(i) @@ -247,22 +247,28 @@ def fundamental_weight(self, i): EXAMPLES:: - sage: RootSystem(['A',3,1]).ambient_space().fundamental_weight(2) + sage: RootSystem(['A',3,1]).ambient_space().fundamental_weight(2) # needs sage.graphs e[0] + e[1] + e['deltacheck'] - sage: RootSystem(['A',3,1]).ambient_space().fundamental_weights() - Finite family {0: e['deltacheck'], 1: e[0] + e['deltacheck'], - 2: e[0] + e[1] + e['deltacheck'], 3: e[0] + e[1] + e[2] + e['deltacheck']} + sage: RootSystem(['A',3,1]).ambient_space().fundamental_weights() # needs sage.graphs + Finite family {0: e['deltacheck'], + 1: e[0] + e['deltacheck'], + 2: e[0] + e[1] + e['deltacheck'], + 3: e[0] + e[1] + e[2] + e['deltacheck']} sage: RootSystem(['A',3]).ambient_space().fundamental_weights() Finite family {1: (1, 0, 0, 0), 2: (1, 1, 0, 0), 3: (1, 1, 1, 0)} - sage: RootSystem(['A',3,1]).weight_lattice().fundamental_weights().map(attrcall("level")) + sage: A31wl = RootSystem(['A',3,1]).weight_lattice() + sage: A31wl.fundamental_weights().map(attrcall("level")) # needs sage.graphs Finite family {0: 1, 1: 1, 2: 1, 3: 1} - sage: RootSystem(['B',3,1]).ambient_space().fundamental_weights() - Finite family {0: e['deltacheck'], 1: e[0] + e['deltacheck'], - 2: e[0] + e[1] + 2*e['deltacheck'], 3: 1/2*e[0] + 1/2*e[1] + 1/2*e[2] + e['deltacheck']} + sage: RootSystem(['B',3,1]).ambient_space().fundamental_weights() # needs sage.graphs + Finite family {0: e['deltacheck'], + 1: e[0] + e['deltacheck'], + 2: e[0] + e[1] + 2*e['deltacheck'], + 3: 1/2*e[0] + 1/2*e[1] + 1/2*e[2] + e['deltacheck']} sage: RootSystem(['B',3]).ambient_space().fundamental_weights() Finite family {1: (1, 0, 0), 2: (1, 1, 0), 3: (1/2, 1/2, 1/2)} - sage: RootSystem(['B',3,1]).weight_lattice().fundamental_weights().map(attrcall("level")) + sage: B31wl = RootSystem(['B',3,1]).weight_lattice() + sage: B31wl.fundamental_weights().map(attrcall("level")) # needs sage.graphs Finite family {0: 1, 1: 1, 2: 2, 3: 1} In type `BC` dual, the coefficient of '\delta^\vee' is the level @@ -270,13 +276,14 @@ def fundamental_weight(self, i): `2\delta^\vee`:: sage: R = CartanType(['BC',3,2]).dual().root_system() - sage: R.ambient_space().fundamental_weights() - Finite family {0: e['deltacheck'], 1: e[0] + e['deltacheck'], + sage: R.ambient_space().fundamental_weights() # needs sage.graphs + Finite family {0: e['deltacheck'], + 1: e[0] + e['deltacheck'], 2: e[0] + e[1] + e['deltacheck'], 3: 1/2*e[0] + 1/2*e[1] + 1/2*e[2] + 1/2*e['deltacheck']} - sage: R.weight_lattice().fundamental_weights().map(attrcall("level")) + sage: R.weight_lattice().fundamental_weights().map(attrcall("level")) # needs sage.graphs Finite family {0: 2, 1: 2, 2: 2, 3: 1} - sage: R.ambient_space().null_coroot() + sage: R.ambient_space().null_coroot() # needs sage.graphs 2*e['deltacheck'] By a slight naming abuse this function also accepts "delta" as @@ -314,22 +321,26 @@ def simple_root(self, i): sage: RootSystem(["A",3]).ambient_space().simple_roots() Finite family {1: (1, -1, 0, 0), 2: (0, 1, -1, 0), 3: (0, 0, 1, -1)} - sage: RootSystem(["A",3,1]).ambient_space().simple_roots() - Finite family {0: -e[0] + e[3] + e['delta'], 1: e[0] - e[1], 2: e[1] - e[2], 3: e[2] - e[3]} + sage: RootSystem(["A",3,1]).ambient_space().simple_roots() # needs sage.graphs + Finite family {0: -e[0] + e[3] + e['delta'], 1: e[0] - e[1], + 2: e[1] - e[2], 3: e[2] - e[3]} Here is a twisted affine example:: - sage: RootSystem(CartanType(["B",3,1]).dual()).ambient_space().simple_roots() - Finite family {0: -e[0] - e[1] + e['delta'], 1: e[0] - e[1], 2: e[1] - e[2], 3: 2*e[2]} + sage: B31v = RootSystem(CartanType(["B",3,1]).dual()) + sage: B31v.ambient_space().simple_roots() # needs sage.graphs + Finite family {0: -e[0] - e[1] + e['delta'], 1: e[0] - e[1], + 2: e[1] - e[2], 3: 2*e[2]} In fact `\delta` is really `1/a_0` times the null root (see the discussion in :class:`~sage.combinat.root_system.weight_space.WeightSpace`) but this only makes a difference in type `BC`:: sage: L = RootSystem(CartanType(["BC",3,2])).ambient_space() - sage: L.simple_roots() - Finite family {0: -e[0] + e['delta'], 1: e[0] - e[1], 2: e[1] - e[2], 3: 2*e[2]} - sage: L.null_root() + sage: L.simple_roots() # needs sage.graphs + Finite family {0: -e[0] + e['delta'], 1: e[0] - e[1], + 2: e[1] - e[2], 3: 2*e[2]} + sage: L.null_root() # needs sage.graphs 2*e['delta'] .. NOTE:: @@ -347,7 +358,7 @@ def simple_root(self, i): - :meth:`CartanType.col_annihilator` - :meth:`null_root` """ - cartan_type = self.cartan_type() + cartan_type = self.cartan_type() special_node = cartan_type.special_node() if i == special_node: return self(self._classical_alpha_0()) + self.monomial("delta") @@ -367,10 +378,12 @@ def simple_coroot(self, i): It is built as the coroot associated to the simple root `\alpha_i`:: - sage: RootSystem(["B",3,1]).ambient_space().simple_roots() - Finite family {0: -e[0] - e[1] + e['delta'], 1: e[0] - e[1], 2: e[1] - e[2], 3: e[2]} - sage: RootSystem(["B",3,1]).ambient_space().simple_coroots() - Finite family {0: -e[0] - e[1] + e['deltacheck'], 1: e[0] - e[1], 2: e[1] - e[2], 3: 2*e[2]} + sage: RootSystem(["B",3,1]).ambient_space().simple_roots() # needs sage.graphs + Finite family {0: -e[0] - e[1] + e['delta'], 1: e[0] - e[1], + 2: e[1] - e[2], 3: e[2]} + sage: RootSystem(["B",3,1]).ambient_space().simple_coroots() # needs sage.graphs + Finite family {0: -e[0] - e[1] + e['deltacheck'], 1: e[0] - e[1], + 2: e[1] - e[2], 3: 2*e[2]} .. TODO:: Factor out this code with the classical ambient space. """ @@ -403,6 +416,7 @@ def _plot_projection(self, x): EXAMPLES:: + sage: # needs sage.symbolic sage: L = RootSystem(["B",2,1]).ambient_space() sage: e = L.basis() sage: L._plot_projection(e[0]) @@ -414,6 +428,7 @@ def _plot_projection(self, x): sage: L._plot_projection(e["deltacheck"]) (0, 0, 1) + sage: # needs sage.symbolic sage: L = RootSystem(["A",2,1]).ambient_space() sage: e = L.basis() sage: L._plot_projection(e[0]) @@ -475,6 +490,7 @@ def associated_coroot(self): EXAMPLES:: + sage: # needs sage.graphs sage: alpha = RootSystem(['C',2,1]).ambient_space().simple_roots() sage: alpha Finite family {0: -2*e[0] + e['delta'], 1: e[0] - e[1], 2: 2*e[1]} diff --git a/src/sage/combinat/root_system/type_dual.py b/src/sage/combinat/root_system/type_dual.py index 8922a4cd9ac..c2ea5d978d3 100644 --- a/src/sage/combinat/root_system/type_dual.py +++ b/src/sage/combinat/root_system/type_dual.py @@ -163,7 +163,7 @@ def __init__(self, type): _stable_abstract_classes = [ cartan_type.CartanType_simple] - def _repr_(self, compact = False): + def _repr_(self, compact=False): """ EXAMPLES:: @@ -338,7 +338,7 @@ def dynkin_diagram(self): EXAMPLES:: sage: ct = CartanType(['F', 4, 1]).dual() - sage: ct.dynkin_diagram() + sage: ct.dynkin_diagram() # needs sage.graphs O---O---O=<=O---O 0 1 2 3 4 F4~* @@ -379,7 +379,7 @@ class AmbientSpace(ambient_space.AmbientSpace): sage: ct = sage.combinat.root_system.type_dual.CartanType(CartanType(['F',4])) sage: L = ct.root_system().ambient_space(); L Ambient space of the Root system of type ['F', 4]^* - sage: TestSuite(L).run(skip=["_test_elements","_test_pickling"]) + sage: TestSuite(L).run(skip=["_test_elements","_test_pickling"]) # needs sage.graphs """ @lazy_attribute @@ -472,7 +472,7 @@ def fundamental_weights(self): sage: ct = sage.combinat.root_system.type_dual.CartanType(CartanType(['F',4])) sage: L = ct.root_system().ambient_space() - sage: L.fundamental_weights() + sage: L.fundamental_weights() # needs sage.graphs Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3, 1, 1, 1), 4: (2, 0, 0, 0)} Note that this ambient space is isomorphic, but not equal, to @@ -657,9 +657,9 @@ def _latex_(self): result = self._type._latex_() import re if re.match(r".*\^{\(\d\)}$", result): - return "%s%s}"%(result[:-1], self.options('dual_latex')) + return "%s%s}" % (result[:-1], self.options('dual_latex')) else: - return "{%s}^%s"%(result, self.options('dual_latex')) + return "{%s}^%s" % (result, self.options('dual_latex')) def _default_folded_cartan_type(self): """ diff --git a/src/sage/combinat/root_system/type_folded.py b/src/sage/combinat/root_system/type_folded.py index bfb0d1513c6..58f4911c361 100644 --- a/src/sage/combinat/root_system/type_folded.py +++ b/src/sage/combinat/root_system/type_folded.py @@ -116,7 +116,7 @@ class CartanTypeFolded(UniqueRepresentation, SageObject): sage: fct = CartanType(['C',4,1]).as_folding(); fct ['C', 4, 1] as a folding of ['A', 7, 1] - sage: fct.scaling_factors() + sage: fct.scaling_factors() # needs sage.graphs Finite family {0: 2, 1: 1, 2: 1, 3: 1, 4: 2} sage: fct.folding_orbit() Finite family {0: (0,), 1: (1, 7), 2: (2, 6), 3: (3, 5), 4: (4,)} @@ -126,7 +126,7 @@ class CartanTypeFolded(UniqueRepresentation, SageObject): sage: fct = CartanType(['A',4,1]).as_folding(); fct ['A', 4, 1] as a folding of ['A', 4, 1] - sage: fct.scaling_factors() + sage: fct.scaling_factors() # needs sage.graphs Finite family {0: 1, 1: 1, 2: 1, 3: 1, 4: 1} sage: fct.folding_orbit() Finite family {0: (0,), 1: (1,), 2: (2,), 3: (3,), 4: (4,)} @@ -270,6 +270,7 @@ def scaling_factors(self): EXAMPLES:: + sage: # needs sage.graphs sage: fct = CartanType(['C', 4, 1]).as_folding() sage: fct.scaling_factors() Finite family {0: 2, 1: 1, 2: 1, 3: 1, 4: 2} diff --git a/src/sage/combinat/root_system/type_marked.py b/src/sage/combinat/root_system/type_marked.py index a15eb8d1547..5d80ca1052a 100644 --- a/src/sage/combinat/root_system/type_marked.py +++ b/src/sage/combinat/root_system/type_marked.py @@ -30,7 +30,7 @@ class CartanType(cartan_type.CartanType_decorator): We take the Cartan type `B_4`:: sage: T = CartanType(['B',4]) - sage: T.dynkin_diagram() + sage: T.dynkin_diagram() # needs sage.graphs O---O---O=>=O 1 2 3 4 B4 @@ -38,14 +38,14 @@ class CartanType(cartan_type.CartanType_decorator): And mark some of its nodes:: sage: T = T.marked_nodes([2,3]) - sage: T.dynkin_diagram() + sage: T.dynkin_diagram() # needs sage.graphs O---X---X=>=O 1 2 3 4 B4 with nodes (2, 3) marked Markings are not additive:: - sage: T.marked_nodes([1,4]).dynkin_diagram() + sage: T.marked_nodes([1,4]).dynkin_diagram() # needs sage.graphs X---O---O=>=X 1 2 3 4 B4 with nodes (1, 4) marked @@ -53,7 +53,7 @@ class CartanType(cartan_type.CartanType_decorator): And trivial relabelling are honoured nicely:: sage: T = T.marked_nodes([]) - sage: T.dynkin_diagram() + sage: T.dynkin_diagram() # needs sage.graphs O---O---O=>=O 1 2 3 4 B4 @@ -160,14 +160,14 @@ def _repr_(self, compact=False): sage: CartanType(['F', 4, 1]).marked_nodes([0, 2])._repr_(compact = True) 'F4~ with nodes (0, 2) marked' - sage: D = DynkinDiagram("A2") - sage: D.marked_nodes([1]) + sage: D = DynkinDiagram("A2") # needs sage.graphs + sage: D.marked_nodes([1]) # needs sage.graphs O---O 1 2 A2 with node 1 marked - sage: CM = CartanMatrix([[2,-4],[-5,2]]) - sage: CM.marked_nodes([1]) + sage: CM = CartanMatrix([[2,-4],[-5,2]]) # needs sage.graphs + sage: CM.marked_nodes([1]) # needs sage.graphs [ 2 -4] [-5 2] with node 1 marked """ @@ -330,7 +330,7 @@ def dynkin_diagram(self): EXAMPLES:: - sage: CartanType(["G", 2]).marked_nodes([2]).dynkin_diagram() + sage: CartanType(["G", 2]).marked_nodes([2]).dynkin_diagram() # needs sage.graphs 3 O=<=X 1 2 @@ -340,11 +340,11 @@ def dynkin_diagram(self): To be compared with the examples in :meth:`ascii_art`:: - sage: CartanType(["G", 2]).relabel({1:2,2:1}).dynkin_diagram().edges(sort=True) + sage: CartanType(["G", 2]).relabel({1:2,2:1}).dynkin_diagram().edges(sort=True) # needs sage.graphs [(1, 2, 3), (2, 1, 1)] - sage: CartanType(["B", 3, 1]).relabel([1,3,2,0]).dynkin_diagram().edges(sort=True) + sage: CartanType(["B", 3, 1]).relabel([1,3,2,0]).dynkin_diagram().edges(sort=True) # needs sage.graphs [(0, 2, 1), (1, 2, 1), (2, 0, 2), (2, 1, 1), (2, 3, 1), (3, 2, 1)] - sage: CartanType(["F", 4, 1]).relabel(lambda n: 4-n).dynkin_diagram().edges(sort=True) + sage: CartanType(["F", 4, 1]).relabel(lambda n: 4-n).dynkin_diagram().edges(sort=True) # needs sage.graphs [(0, 1, 1), (1, 0, 1), (1, 2, 1), (2, 1, 2), (2, 3, 1), (3, 2, 1), (3, 4, 1), (4, 3, 1)] """ result = self._type.dynkin_diagram().copy() @@ -360,11 +360,11 @@ def dual(self): EXAMPLES:: sage: T = CartanType(["BC",3, 2]) - sage: T.marked_nodes([1,3]).dual().dynkin_diagram() + sage: T.marked_nodes([1,3]).dual().dynkin_diagram() # needs sage.graphs O=>=X---O=>=X 0 1 2 3 BC3~* with nodes (1, 3) marked - sage: T.dual().marked_nodes([1,3]).dynkin_diagram() + sage: T.dual().marked_nodes([1,3]).dynkin_diagram() # needs sage.graphs O=>=X---O=>=X 0 1 2 3 BC3~* with nodes (1, 3) marked @@ -378,11 +378,11 @@ def relabel(self, relabelling): EXAMPLES:: sage: T = CartanType(["BC",3, 2]) - sage: T.marked_nodes([1,3]).relabel(lambda x: x+2).dynkin_diagram() + sage: T.marked_nodes([1,3]).relabel(lambda x: x+2).dynkin_diagram() # needs sage.graphs O=<=X---O=<=X 2 3 4 5 BC3~ relabelled by {0: 2, 1: 3, 2: 4, 3: 5} with nodes (3, 5) marked - sage: T.relabel(lambda x: x+2).marked_nodes([3,5]).dynkin_diagram() + sage: T.relabel(lambda x: x+2).marked_nodes([3,5]).dynkin_diagram() # needs sage.graphs O=<=X---O=<=X 2 3 4 5 BC3~ relabelled by {0: 2, 1: 3, 2: 4, 3: 5} with nodes (3, 5) marked @@ -425,7 +425,7 @@ def _default_folded_cartan_type(self): Finite family {0: (0,), 1: (2,), 2: (1, 3, 4)} sage: CartanType(['G',2,1]).dual()._default_folded_cartan_type().folding_orbit() Finite family {0: (0,), 1: (1, 3, 4), 2: (2,)} - sage: CartanType(['C',3,1]).relabel({0:1, 1:0, 2:3, 3:2}).as_folding().scaling_factors() + sage: CartanType(['C',3,1]).relabel({0:1, 1:0, 2:3, 3:2}).as_folding().scaling_factors() # needs sage.graphs Finite family {0: 1, 1: 2, 2: 2, 3: 1} """ from sage.combinat.root_system.type_folded import CartanTypeFolded @@ -461,7 +461,7 @@ class AmbientSpace(ambient_space.AmbientSpace): sage: L = CartanType(["F",4]).marked_nodes([1,3]).root_system().ambient_space(); L Ambient space of the Root system of type ['F', 4] with nodes (1, 3) marked - sage: TestSuite(L).run() + sage: TestSuite(L).run() # needs sage.graphs """ @lazy_attribute def _space(self): @@ -567,11 +567,11 @@ def affine(self): EXAMPLES:: sage: B4 = CartanType(['B',4]).marked_nodes([1,3]) - sage: B4.dynkin_diagram() + sage: B4.dynkin_diagram() # needs sage.graphs X---O---X=>=O 1 2 3 4 B4 with nodes (1, 3) marked - sage: B4.affine().dynkin_diagram() + sage: B4.affine().dynkin_diagram() # needs sage.graphs O 0 | | @@ -670,7 +670,7 @@ def classical(self): EXAMPLES:: sage: T = CartanType(['A',4,1]).marked_nodes([0,2,4]) - sage: T.dynkin_diagram() + sage: T.dynkin_diagram() # needs sage.graphs 0 X-----------+ | | @@ -679,10 +679,9 @@ def classical(self): 1 2 3 4 A4~ with nodes (0, 2, 4) marked - sage: T0 = T.classical() - sage: T0 + sage: T0 = T.classical(); T0 ['A', 4] with nodes (2, 4) marked - sage: T0.dynkin_diagram() + sage: T0.dynkin_diagram() # needs sage.graphs O---X---O---X 1 2 3 4 A4 with nodes (2, 4) marked diff --git a/src/sage/combinat/root_system/type_reducible.py b/src/sage/combinat/root_system/type_reducible.py index 527447b0e41..0f84b3f3b90 100644 --- a/src/sage/combinat/root_system/type_reducible.py +++ b/src/sage/combinat/root_system/type_reducible.py @@ -66,7 +66,7 @@ class CartanType(SageObject, CartanType_abstract): sage: t.index_set() (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13) - sage: t.dynkin_diagram() + sage: t.dynkin_diagram() # needs sage.graphs O---O---O---O 1 2 3 4 O=<=O---O---O---O=<=O @@ -256,18 +256,18 @@ def cartan_matrix(self, subdivide=True): EXAMPLES:: sage: ct = CartanType("A2","B2") - sage: ct.cartan_matrix() + sage: ct.cartan_matrix() # needs sage.graphs [ 2 -1| 0 0] [-1 2| 0 0] [-----+-----] [ 0 0| 2 -1] [ 0 0|-2 2] - sage: ct.cartan_matrix(subdivide=False) + sage: ct.cartan_matrix(subdivide=False) # needs sage.graphs [ 2 -1 0 0] [-1 2 0 0] [ 0 0 2 -1] [ 0 0 -2 2] - sage: ct.index_set() == ct.cartan_matrix().index_set() + sage: ct.index_set() == ct.cartan_matrix().index_set() # needs sage.graphs True """ from sage.combinat.root_system.cartan_matrix import CartanMatrix @@ -280,8 +280,7 @@ def dynkin_diagram(self): EXAMPLES:: - sage: dd = CartanType("A2xB2xF4").dynkin_diagram() - sage: dd + sage: dd = CartanType("A2xB2xF4").dynkin_diagram(); dd # needs sage.graphs O---O 1 2 O=>=O @@ -289,10 +288,11 @@ def dynkin_diagram(self): O---O=>=O---O 5 6 7 8 A2xB2xF4 - sage: dd.edges(sort=True) - [(1, 2, 1), (2, 1, 1), (3, 4, 2), (4, 3, 1), (5, 6, 1), (6, 5, 1), (6, 7, 2), (7, 6, 1), (7, 8, 1), (8, 7, 1)] + sage: dd.edges(sort=True) # needs sage.graphs + [(1, 2, 1), (2, 1, 1), (3, 4, 2), (4, 3, 1), (5, 6, 1), + (6, 5, 1), (6, 7, 2), (7, 6, 1), (7, 8, 1), (8, 7, 1)] - sage: CartanType("F4xA2").dynkin_diagram() + sage: CartanType("F4xA2").dynkin_diagram() # needs sage.graphs O---O=>=O---O 1 2 3 4 O---O @@ -432,18 +432,17 @@ def coxeter_diagram(self): EXAMPLES:: - sage: cd = CartanType("A2xB2xF4").coxeter_diagram() - sage: cd + sage: cd = CartanType("A2xB2xF4").coxeter_diagram(); cd # needs sage.graphs Graph on 8 vertices - sage: cd.edges(sort=True) + sage: cd.edges(sort=True) # needs sage.graphs [(1, 2, 3), (3, 4, 4), (5, 6, 3), (6, 7, 4), (7, 8, 3)] - sage: CartanType("F4xA2").coxeter_diagram().edges(sort=True) + sage: CartanType("F4xA2").coxeter_diagram().edges(sort=True) # needs sage.graphs [(1, 2, 3), (2, 3, 4), (3, 4, 3), (5, 6, 3)] - sage: cd = CartanType("A1xH3").coxeter_diagram(); cd + sage: cd = CartanType("A1xH3").coxeter_diagram(); cd # needs sage.graphs Graph on 4 vertices - sage: cd.edges(sort=True) + sage: cd.edges(sort=True) # needs sage.graphs [(2, 3, 3), (3, 4, 5)] """ from sage.graphs.graph import Graph diff --git a/src/sage/combinat/root_system/type_relabel.py b/src/sage/combinat/root_system/type_relabel.py index f37c6a724e6..142ddeffa45 100644 --- a/src/sage/combinat/root_system/type_relabel.py +++ b/src/sage/combinat/root_system/type_relabel.py @@ -75,7 +75,7 @@ def __init__(self, type, relabelling): We take the Cartan type `B_4`:: sage: T = CartanType(['B',4]) - sage: T.dynkin_diagram() + sage: T.dynkin_diagram() # needs sage.graphs O---O---O=>=O 1 2 3 4 B4 @@ -85,23 +85,23 @@ def __init__(self, type, relabelling): sage: cycle = {1:2, 2:3, 3:4, 4:1} sage: T = T.relabel(cycle) - sage: T.dynkin_diagram() + sage: T.dynkin_diagram() # needs sage.graphs O---O---O=>=O 2 3 4 1 B4 relabelled by {1: 2, 2: 3, 3: 4, 4: 1} - sage: T.dynkin_diagram().edges(sort=True) + sage: T.dynkin_diagram().edges(sort=True) # needs sage.graphs [(1, 4, 1), (2, 3, 1), (3, 2, 1), (3, 4, 1), (4, 1, 2), (4, 3, 1)] Multiple relabelling are recomposed into a single one:: sage: T = T.relabel(cycle) - sage: T.dynkin_diagram() + sage: T.dynkin_diagram() # needs sage.graphs O---O---O=>=O 3 4 1 2 B4 relabelled by {1: 3, 2: 4, 3: 1, 4: 2} sage: T = T.relabel(cycle) - sage: T.dynkin_diagram() + sage: T.dynkin_diagram() # needs sage.graphs O---O---O=>=O 4 1 2 3 B4 relabelled by {1: 4, 2: 1, 3: 2, 4: 3} @@ -109,7 +109,7 @@ def __init__(self, type, relabelling): And trivial relabelling are honoured nicely:: sage: T = T.relabel(cycle) - sage: T.dynkin_diagram() + sage: T.dynkin_diagram() # needs sage.graphs O---O---O=>=O 1 2 3 4 B4 @@ -149,19 +149,19 @@ def __init__(self, type, relabelling): Check for the original issues of :trac:`13724`:: sage: A3 = CartanType("A3") - sage: A3.cartan_matrix() + sage: A3.cartan_matrix() # needs sage.graphs [ 2 -1 0] [-1 2 -1] [ 0 -1 2] sage: A3r = A3.relabel({1:2,2:3,3:1}) - sage: A3r.cartan_matrix() + sage: A3r.cartan_matrix() # needs sage.graphs [ 2 0 -1] [ 0 2 -1] [-1 -1 2] sage: ct = CartanType(["D",4,3]).classical(); ct ['G', 2] - sage: ct.symmetrizer() + sage: ct.symmetrizer() # needs sage.graphs Finite family {1: 1, 2: 3} Check the underlying issue of :trac:`24892`, that the root system @@ -229,7 +229,7 @@ def _repr_(self, compact=False): return 'D4^3' return "['D', 4, 3]" relab = pformat(self._relabelling) - return self._type._repr_(compact = compact) + " relabelled by {}".format(relab) + return self._type._repr_(compact=compact) + " relabelled by {}".format(relab) def _latex_(self): r""" @@ -317,7 +317,7 @@ def dynkin_diagram(self): EXAMPLES:: - sage: CartanType(["G", 2]).relabel({1:2,2:1}).dynkin_diagram() + sage: CartanType(["G", 2]).relabel({1:2,2:1}).dynkin_diagram() # needs sage.graphs 3 O=<=O 2 1 @@ -327,11 +327,11 @@ def dynkin_diagram(self): To be compared with the examples in :meth:`ascii_art`:: - sage: CartanType(["G", 2]).relabel({1:2,2:1}).dynkin_diagram().edges(sort=True) + sage: CartanType(["G", 2]).relabel({1:2,2:1}).dynkin_diagram().edges(sort=True) # needs sage.graphs [(1, 2, 3), (2, 1, 1)] - sage: CartanType(["B", 3, 1]).relabel([1,3,2,0]).dynkin_diagram().edges(sort=True) + sage: CartanType(["B", 3, 1]).relabel([1,3,2,0]).dynkin_diagram().edges(sort=True) # needs sage.graphs [(0, 2, 1), (1, 2, 1), (2, 0, 2), (2, 1, 1), (2, 3, 1), (3, 2, 1)] - sage: CartanType(["F", 4, 1]).relabel(lambda n: 4-n).dynkin_diagram().edges(sort=True) + sage: CartanType(["F", 4, 1]).relabel(lambda n: 4-n).dynkin_diagram().edges(sort=True) # needs sage.graphs [(0, 1, 1), (1, 0, 1), (1, 2, 1), (2, 1, 2), (2, 3, 1), (3, 2, 1), (3, 4, 1), (4, 3, 1)] """ # Maybe we want to move this up as a relabel method for Dynkin diagram @@ -361,11 +361,11 @@ def dual(self): sage: T = CartanType(["BC",3, 2]) sage: cycle = {1:2, 2:3, 3:0, 0:1} - sage: T.relabel(cycle).dual().dynkin_diagram() + sage: T.relabel(cycle).dual().dynkin_diagram() # needs sage.graphs O=>=O---O=>=O 1 2 3 0 BC3~* relabelled by {0: 1, 1: 2, 2: 3, 3: 0} - sage: T.dual().relabel(cycle).dynkin_diagram() + sage: T.dual().relabel(cycle).dynkin_diagram() # needs sage.graphs O=>=O---O=>=O 1 2 3 0 BC3~* relabelled by {0: 1, 1: 2, 2: 3, 3: 0} @@ -384,7 +384,7 @@ def _default_folded_cartan_type(self): Finite family {0: (0,), 1: (2,), 2: (1, 3, 4)} sage: CartanType(['G',2,1]).dual()._default_folded_cartan_type().folding_orbit() Finite family {0: (0,), 1: (1, 3, 4), 2: (2,)} - sage: CartanType(['C',3,1]).relabel({0:1, 1:0, 2:3, 3:2}).as_folding().scaling_factors() + sage: CartanType(['C',3,1]).relabel({0:1, 1:0, 2:3, 3:2}).as_folding().scaling_factors() # needs sage.graphs Finite family {0: 1, 1: 2, 2: 2, 3: 1} """ from sage.combinat.root_system.type_folded import CartanTypeFolded @@ -413,9 +413,9 @@ def coxeter_diagram(self): EXAMPLES:: sage: ct = CartanType(['H', 3]).relabel({1:3,2:2,3:1}) - sage: G = ct.coxeter_diagram(); G + sage: G = ct.coxeter_diagram(); G # needs sage.graphs Graph on 3 vertices - sage: G.edges(sort=True) + sage: G.edges(sort=True) # needs sage.graphs [(1, 2, 5), (2, 3, 3)] """ return self._type.coxeter_diagram().relabel(self._relabelling, inplace=False, immutable=True) @@ -436,7 +436,7 @@ class AmbientSpace(ambient_space.AmbientSpace): sage: cycle = {1:2, 2:3, 3:4, 4:1} sage: L = CartanType(["F",4]).relabel(cycle).root_system().ambient_space(); L Ambient space of the Root system of type ['F', 4] relabelled by {1: 2, 2: 3, 3: 4, 4: 1} - sage: TestSuite(L).run() + sage: TestSuite(L).run() # needs sage.graphs """ @lazy_attribute @@ -555,11 +555,11 @@ def affine(self): EXAMPLES:: sage: B4 = CartanType(['B',4]) - sage: B4.dynkin_diagram() + sage: B4.dynkin_diagram() # needs sage.graphs O---O---O=>=O 1 2 3 4 B4 - sage: B4.affine().dynkin_diagram() + sage: B4.affine().dynkin_diagram() # needs sage.graphs O 0 | | @@ -569,11 +569,11 @@ def affine(self): If possible, this reuses the original label for the special node:: - sage: T = B4.relabel({1:2, 2:3, 3:4, 4:1}); T.dynkin_diagram() + sage: T = B4.relabel({1:2, 2:3, 3:4, 4:1}); T.dynkin_diagram() # needs sage.graphs O---O---O=>=O 2 3 4 1 B4 relabelled by {1: 2, 2: 3, 3: 4, 4: 1} - sage: T.affine().dynkin_diagram() + sage: T.affine().dynkin_diagram() # needs sage.graphs O 0 | | @@ -583,11 +583,11 @@ def affine(self): Otherwise, it chooses a label for the special_node in `0,1,...`:: - sage: T = B4.relabel({1:0, 2:1, 3:2, 4:3}); T.dynkin_diagram() + sage: T = B4.relabel({1:0, 2:1, 3:2, 4:3}); T.dynkin_diagram() # needs sage.graphs O---O---O=>=O 0 1 2 3 B4 relabelled by {1: 0, 2: 1, 3: 2, 4: 3} - sage: T.affine().dynkin_diagram() + sage: T.affine().dynkin_diagram() # needs sage.graphs O 4 | | @@ -645,7 +645,7 @@ def classical(self): EXAMPLES:: sage: A41 = CartanType(['A',4,1]) - sage: A41.dynkin_diagram() + sage: A41.dynkin_diagram() # needs sage.graphs 0 O-----------+ | | @@ -657,7 +657,7 @@ def classical(self): sage: T = A41.relabel({0:1, 1:2, 2:3, 3:4, 4:0}) sage: T ['A', 4, 1] relabelled by {0: 1, 1: 2, 2: 3, 3: 4, 4: 0} - sage: T.dynkin_diagram() + sage: T.dynkin_diagram() # needs sage.graphs 1 O-----------+ | | @@ -669,7 +669,7 @@ def classical(self): sage: T0 = T.classical() sage: T0 ['A', 4] relabelled by {1: 2, 2: 3, 3: 4, 4: 0} - sage: T0.dynkin_diagram() + sage: T0.dynkin_diagram() # needs sage.graphs O---O---O---O 2 3 4 0 A4 relabelled by {1: 2, 2: 3, 3: 4, 4: 0} diff --git a/src/sage/combinat/root_system/type_super_A.py b/src/sage/combinat/root_system/type_super_A.py index c014dfa7ee5..dedc56b9011 100644 --- a/src/sage/combinat/root_system/type_super_A.py +++ b/src/sage/combinat/root_system/type_super_A.py @@ -599,37 +599,36 @@ def dynkin_diagram(self): EXAMPLES:: - sage: a = CartanType(['A', [4,2]]).dynkin_diagram() - sage: a + sage: a = CartanType(['A', [4,2]]).dynkin_diagram(); a # needs sage.graphs O---O---O---O---X---O---O -4 -3 -2 -1 0 1 2 A4|2 - sage: a.edges(sort=True) + sage: a.edges(sort=True) # needs sage.graphs [(-4, -3, 1), (-3, -4, 1), (-3, -2, 1), (-2, -3, 1), (-2, -1, 1), (-1, -2, 1), (-1, 0, 1), (0, -1, 1), (0, 1, 1), (1, 0, -1), (1, 2, 1), (2, 1, 1)] TESTS:: - sage: a = DynkinDiagram(['A', [0,0]]); a + sage: a = DynkinDiagram(['A', [0,0]]); a # needs sage.graphs X 0 A0|0 - sage: a.vertices(sort=False), a.edges(sort=False) + sage: a.vertices(sort=False), a.edges(sort=False) # needs sage.graphs ([0], []) - sage: a = DynkinDiagram(['A', [1,0]]); a + sage: a = DynkinDiagram(['A', [1,0]]); a # needs sage.graphs O---X -1 0 A1|0 - sage: a.vertices(sort=True), a.edges(sort=True) + sage: a.vertices(sort=True), a.edges(sort=True) # needs sage.graphs ([-1, 0], [(-1, 0, 1), (0, -1, 1)]) - sage: a = DynkinDiagram(['A', [0,1]]); a + sage: a = DynkinDiagram(['A', [0,1]]); a # needs sage.graphs X---O 0 1 A0|1 - sage: a.vertices(sort=True), a.edges(sort=True) + sage: a.vertices(sort=True), a.edges(sort=True) # needs sage.graphs ([0, 1], [(0, 1, 1), (1, 0, -1)]) """ from .dynkin_diagram import DynkinDiagram_class @@ -652,7 +651,7 @@ def cartan_matrix(self): EXAMPLES:: sage: ct = CartanType(['A', [2,3]]) - sage: ct.cartan_matrix() + sage: ct.cartan_matrix() # needs sage.graphs [ 2 -1 0 0 0 0] [-1 2 -1 0 0 0] [ 0 -1 0 1 0 0] @@ -663,16 +662,16 @@ def cartan_matrix(self): TESTS:: sage: ct = CartanType(['A', [0,0]]) - sage: ct.cartan_matrix() + sage: ct.cartan_matrix() # needs sage.graphs [0] sage: ct = CartanType(['A', [1,0]]) - sage: ct.cartan_matrix() + sage: ct.cartan_matrix() # needs sage.graphs [ 2 -1] [-1 0] sage: ct = CartanType(['A', [0,1]]) - sage: ct.cartan_matrix() + sage: ct.cartan_matrix() # needs sage.graphs [ 0 1] [-1 2] """ @@ -696,14 +695,14 @@ def relabel(self, relabelling): EXAMPLES:: sage: ct = CartanType(['A', [1,2]]) - sage: ct.dynkin_diagram() + sage: ct.dynkin_diagram() # needs sage.graphs O---X---O---O -1 0 1 2 A1|2 - sage: f={1:2,2:1,0:0,-1:-1} + sage: f = {1:2, 2:1, 0:0, -1:-1} sage: ct.relabel(f) ['A', [1, 2]] relabelled by {-1: -1, 0: 0, 1: 2, 2: 1} - sage: ct.relabel(f).dynkin_diagram() + sage: ct.relabel(f).dynkin_diagram() # needs sage.graphs O---X---O---O -1 0 2 1 A1|2 relabelled by {-1: -1, 0: 0, 1: 2, 2: 1} @@ -815,7 +814,7 @@ def ascii_art(self, label=lambda i: i, node=None): """ if node is None: node = lambda i: 'O' - ret = "---".join(node(label(i)) for i in range(1,self.m+1)) + ret = "---".join(node(label(i)) for i in range(1,self.m+1)) if self.m == 0: if self.n == 0: ret = "X" diff --git a/src/sage/combinat/root_system/weight_lattice_realizations.py b/src/sage/combinat/root_system/weight_lattice_realizations.py index a088fd912c8..25dd3c90acf 100644 --- a/src/sage/combinat/root_system/weight_lattice_realizations.py +++ b/src/sage/combinat/root_system/weight_lattice_realizations.py @@ -93,7 +93,8 @@ class WeightLatticeRealizations(Category_over_base_ring): sage: L(x) Traceback (most recent call last): ... - TypeError: do not know how to make x (= Lambda[2] + 1/2*Lambda[5]) an element of self (=Ambient lattice of the Root system of type ['A', 7]) + TypeError: do not know how to make x (= Lambda[2] + 1/2*Lambda[5]) + an element of self (=Ambient lattice of the Root system of type ['A', 7]) If `K_1` is a subring of `K_2`, then one could in theory have an embedding from the weight space over `K_1` to any weight lattice @@ -111,7 +112,8 @@ class WeightLatticeRealizations(Category_over_base_ring): sage: L(Lambda[1]) Traceback (most recent call last): ... - TypeError: do not know how to make x (= Lambda[1]) an element of self (=Ambient space of the Root system of type ['A', 7]) + TypeError: do not know how to make x (= Lambda[1]) an element + of self (=Ambient space of the Root system of type ['A', 7]) """ @cached_method @@ -228,7 +230,7 @@ def __init_extra__(self): # Build and register the embeddings for domain in domains: domain.module_morphism(self.fundamental_weight, - codomain = self + codomain=self ).register_as_coercion() def _test_weight_lattice_realization(self, **options): @@ -243,12 +245,17 @@ def _test_weight_lattice_realization(self, **options): EXAMPLES:: - sage: RootSystem(['A',3]).weight_lattice()._test_weight_lattice_realization() + sage: RootSystem(['A',3]).weight_lattice()._test_weight_lattice_realization() # needs sage.graphs """ from sage.rings.integer_ring import ZZ tester = self._tester(**options) - Lambda = self.fundamental_weights() - alphacheck = self.simple_coroots() + + try: + Lambda = self.fundamental_weights() + alphacheck = self.simple_coroots() + except ImportError: + return + tester.assertEqual(tuple(Lambda.keys()), self.index_set()) # Check the consistency between simple_root and simple_roots @@ -287,11 +294,14 @@ def _test_weight_lattice_realization(self, **options): for i in self.index_set(): assert(Lambda[i].is_dominant()) for j in self.index_set(): - tester.assertEqual(Lambda[j].scalar(alphacheck[i]), (1 if i==j else 0)) + tester.assertEqual(Lambda[j].scalar(alphacheck[i]), (1 if i == j else 0)) tester.assertTrue(self.rho().is_dominant()) if self.root_system.is_finite() and self.root_system.is_irreducible(): - tester.assertTrue(self.highest_root().is_dominant()) + try: + tester.assertTrue(self.highest_root().is_dominant()) + except ImportError: # when sage.graphs is missing (Dynkin diagram) + pass @cached_method def fundamental_weights(self): @@ -320,23 +330,23 @@ def simple_root(self, i): EXAMPLES: Since all the weight lattice realizations in Sage currently - implement a simple_root method, we have to call this one by + implement a ``simple_root`` method, we have to call this one by hand:: sage: from sage.combinat.root_system.weight_lattice_realizations import WeightLatticeRealizations sage: simple_root = WeightLatticeRealizations(QQ).parent_class.simple_root.f sage: L = RootSystem("A3").ambient_space() - sage: simple_root(L, 1) + sage: simple_root(L, 1) # needs sage.graphs (1, -1, 0, 0) - sage: simple_root(L, 2) + sage: simple_root(L, 2) # needs sage.graphs (0, 1, -1, 0) - sage: simple_root(L, 3) + sage: simple_root(L, 3) # needs sage.graphs (1, 1, 2, 0) Note that this last root differs from the one implemented in ``L`` by a multiple of the vector ``(1,1,1,1)``:: - sage: L.simple_roots() + sage: L.simple_roots() # needs sage.graphs Finite family {1: (1, -1, 0, 0), 2: (0, 1, -1, 0), 3: (0, 0, 1, -1)} This is a harmless artefact of the `SL` versus `GL` @@ -416,16 +426,16 @@ def reduced_word_of_alcove_morphism(self, f): coweight lattice:: sage: R = RootSystem(["A",2,1]).weight_lattice() - sage: alpha = R.simple_roots() + sage: alpha = R.simple_roots() # needs sage.graphs sage: Lambda = R.fundamental_weights() We consider first translations by elements of the root lattice:: - sage: R.reduced_word_of_alcove_morphism(alpha[0].translation) + sage: R.reduced_word_of_alcove_morphism(alpha[0].translation) # needs sage.graphs [1, 2, 1, 0] - sage: R.reduced_word_of_alcove_morphism(alpha[1].translation) + sage: R.reduced_word_of_alcove_morphism(alpha[1].translation) # needs sage.graphs [0, 2, 0, 1] - sage: R.reduced_word_of_alcove_morphism(alpha[2].translation) + sage: R.reduced_word_of_alcove_morphism(alpha[2].translation) # needs sage.graphs [0, 1, 0, 2] We continue with translations by elements of the classical @@ -434,9 +444,9 @@ def reduced_word_of_alcove_morphism(self, f): sage: omega1 = Lambda[1] - Lambda[0] sage: omega2 = Lambda[2] - Lambda[0] - sage: R.reduced_word_of_alcove_morphism(omega1.translation) + sage: R.reduced_word_of_alcove_morphism(omega1.translation) # needs sage.graphs [0, 2] - sage: R.reduced_word_of_alcove_morphism(omega2.translation) + sage: R.reduced_word_of_alcove_morphism(omega2.translation) # needs sage.graphs [0, 1] The following tests ensure that the code agrees with the tables @@ -444,6 +454,7 @@ def reduced_word_of_alcove_morphism(self, f): TESTS:: + sage: # needs sage.graphs sage: R = RootSystem(['A',5,1]).weight_lattice() sage: alpha = R.simple_roots() sage: Lambda = R.fundamental_weights() @@ -453,6 +464,7 @@ def reduced_word_of_alcove_morphism(self, f): sage: R.reduced_word_of_alcove_morphism(alpha[0].translation) [1, 2, 3, 4, 5, 4, 3, 2, 1, 0] + sage: # needs sage.graphs sage: R = RootSystem(['C',3,1]).weight_lattice() sage: alpha = R.simple_roots() sage: Lambda = R.fundamental_weights() @@ -465,15 +477,18 @@ def reduced_word_of_alcove_morphism(self, f): [0, 1, 0, 2, 1, 3, 2, 1, 3, 2] sage: R.reduced_word_of_alcove_morphism(omega3.translation) [0, 1, 0, 2, 1, 0] + + sage: # needs sage.libs.gap sage: W = WeylGroup(['C',3,1]) sage: s = W.simple_reflections() sage: w = s[0]*s[1]*s[2]*s[3]*s[2] - sage: W.from_reduced_word(R.reduced_word_of_alcove_morphism(omega2.translation)) == w*w + sage: W.from_reduced_word(R.reduced_word_of_alcove_morphism(omega2.translation)) == w*w # needs sage.graphs True sage: w = s[0]*s[1]*s[2]*s[0]*s[1]*s[0] - sage: W.from_reduced_word(R.reduced_word_of_alcove_morphism(omega3.translation)) == w + sage: W.from_reduced_word(R.reduced_word_of_alcove_morphism(omega3.translation)) == w # needs sage.graphs True + sage: # needs sage.graphs sage: R = RootSystem(['D',4,1]).weight_lattice() sage: Lambda = R.fundamental_weights() sage: omega1 = Lambda[1] - Lambda[0] @@ -488,24 +503,28 @@ def reduced_word_of_alcove_morphism(self, f): [0, 2, 1, 4, 2, 0] sage: R.reduced_word_of_alcove_morphism(omega4.translation) [0, 2, 1, 3, 2, 0] + + sage: # needs sage.libs.gap sage: W = WeylGroup(['D',4,1]) sage: s = W.simple_reflections() sage: w = s[0]*s[2]*s[3]*s[4]*s[2] sage: w1= s[1]*s[2]*s[3]*s[4]*s[2] - sage: W.from_reduced_word(R.reduced_word_of_alcove_morphism(omega2.translation)) == w*w1 + sage: W.from_reduced_word(R.reduced_word_of_alcove_morphism(omega2.translation)) == w*w1 # needs sage.graphs True sage: R = RootSystem(['D',5,1]).weight_lattice() sage: Lambda = R.fundamental_weights() sage: omega1 = Lambda[1] - Lambda[0] sage: omega2 = Lambda[2] - 2*Lambda[0] - sage: R.reduced_word_of_alcove_morphism(omega1.translation) + sage: R.reduced_word_of_alcove_morphism(omega1.translation) # needs sage.graphs [0, 2, 3, 4, 5, 3, 2, 0] + + sage: # needs sage.libs.gap sage: W = WeylGroup(['D',5,1]) sage: s = W.simple_reflections() sage: w = s[0]*s[2]*s[3]*s[4]*s[5]*s[3]*s[2] sage: w1= s[1]*s[2]*s[3]*s[4]*s[5]*s[3]*s[2] - sage: W.from_reduced_word(R.reduced_word_of_alcove_morphism(omega2.translation)) == w*w1 + sage: W.from_reduced_word(R.reduced_word_of_alcove_morphism(omega2.translation)) == w*w1 # needs sage.graphs True """ return f(self.rho()).reduced_word() @@ -526,12 +545,13 @@ def dynkin_diagram_automorphism_of_alcove_morphism(self, f): EXAMPLES:: sage: R = RootSystem(["A",2,1]).weight_lattice() - sage: alpha = R.simple_roots() + sage: alpha = R.simple_roots() # needs sage.graphs sage: Lambda = R.fundamental_weights() Translations by elements of the root lattice induce a trivial Dynkin diagram automorphism:: + sage: # needs sage.graphs sage: R.dynkin_diagram_automorphism_of_alcove_morphism(alpha[0].translation) {0: 0, 1: 1, 2: 2} sage: R.dynkin_diagram_automorphism_of_alcove_morphism(alpha[1].translation) @@ -545,16 +565,19 @@ def dynkin_diagram_automorphism_of_alcove_morphism(self, f): sage: omega1 = Lambda[1] - Lambda[0] sage: omega2 = Lambda[2] - Lambda[0] + sage: # needs sage.graphs sage: R.dynkin_diagram_automorphism_of_alcove_morphism(omega1.translation) {0: 1, 1: 2, 2: 0} sage: R.dynkin_diagram_automorphism_of_alcove_morphism(omega2.translation) {0: 2, 1: 0, 2: 1} + sage: # needs sage.graphs sage: R = RootSystem(['C',2,1]).weight_lattice() sage: alpha = R.simple_roots() sage: R.dynkin_diagram_automorphism_of_alcove_morphism(alpha[1].translation) {0: 2, 1: 1, 2: 0} + sage: # needs sage.graphs sage: R = RootSystem(['D',5,1]).weight_lattice() sage: Lambda = R.fundamental_weights() sage: omega1 = Lambda[1] - Lambda[0] @@ -597,6 +620,7 @@ def reduced_word_of_translation(self, t): EXAMPLES:: + sage: # needs sage.graphs sage: R = RootSystem(["A",2,1]).weight_lattice() sage: alpha = R.simple_roots() sage: R.reduced_word_of_translation(alpha[1]) @@ -610,21 +634,20 @@ def reduced_word_of_translation(self, t): sage: Lambda = R.fundamental_weights() sage: omega1 = Lambda[1] - Lambda[0] sage: omega2 = Lambda[2] - 2*Lambda[0] - sage: R.reduced_word_of_translation(omega1) + sage: R.reduced_word_of_translation(omega1) # needs sage.graphs [0, 2, 3, 4, 5, 3, 2, 0] - sage: R.reduced_word_of_translation(omega2) + sage: R.reduced_word_of_translation(omega2) # needs sage.graphs [0, 2, 1, 3, 2, 4, 3, 5, 3, 2, 1, 4, 3, 2] A non simply laced case:: sage: R = RootSystem(["C",2,1]).weight_lattice() sage: Lambda = R.fundamental_weights() - sage: c = R.cartan_type().translation_factors() - sage: c + sage: c = R.cartan_type().translation_factors(); c # needs sage.graphs Finite family {0: 1, 1: 2, 2: 1} - sage: R.reduced_word_of_translation((Lambda[1]-Lambda[0]) * c[1]) + sage: R.reduced_word_of_translation((Lambda[1]-Lambda[0]) * c[1]) # needs sage.graphs [0, 1, 2, 1] - sage: R.reduced_word_of_translation((Lambda[2]-Lambda[0]) * c[2]) + sage: R.reduced_word_of_translation((Lambda[2]-Lambda[0]) * c[2]) # needs sage.graphs [0, 1, 0] See also :meth:`_test_reduced_word_of_translation`. @@ -648,14 +671,17 @@ def _test_reduced_word_of_translation(self, elements=None, **options): EXAMPLES:: sage: R = RootSystem(['D',4,1]).weight_lattice() - sage: R._test_reduced_word_of_translation() + sage: R._test_reduced_word_of_translation() # needs sage.graphs See the documentation for :class:`TestSuite` for more information. """ tester = self._tester(**options) if not self.cartan_type().is_affine(): # won't be necessary anymore once root systems are categorified return - alpha = self.simple_roots() + try: + alpha = self.simple_roots() + except ImportError: # when sage.graphs is not available + return Lambda = self.fundamental_weights() rho = self.rho() G = self.dynkin_diagram() @@ -746,15 +772,15 @@ def signs_of_alcovewalk(self, walk): EXAMPLES:: sage: L = RootSystem(['C',2,1]).weight_lattice() - sage: L.signs_of_alcovewalk([1,2,0,1,2,1,2,0,1,2]) + sage: L.signs_of_alcovewalk([1,2,0,1,2,1,2,0,1,2]) # needs sage.libs.gap [-1, -1, 1, -1, 1, 1, 1, 1, 1, 1] sage: L = RootSystem(['A',2,1]).weight_lattice() - sage: L.signs_of_alcovewalk([0,1,2,1,2,0,1,2,0,1,2,0]) + sage: L.signs_of_alcovewalk([0,1,2,1,2,0,1,2,0,1,2,0]) # needs sage.libs.gap [1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1] sage: L = RootSystem(['B',2,1]).coweight_lattice() - sage: L.signs_of_alcovewalk([0,1,2,0,1,2]) + sage: L.signs_of_alcovewalk([0,1,2,0,1,2]) # needs sage.libs.gap [1, -1, 1, -1, 1, 1] .. WARNING:: @@ -790,10 +816,10 @@ def rho_classical(self): EXAMPLES:: - sage: RootSystem(['C',4,1]).weight_lattice().rho_classical() + sage: RootSystem(['C',4,1]).weight_lattice().rho_classical() # needs sage.graphs -4*Lambda[0] + Lambda[1] + Lambda[2] + Lambda[3] + Lambda[4] sage: L = RootSystem(['D',4,1]).weight_lattice() - sage: L.rho_classical().scalar(L.null_coroot()) + sage: L.rho_classical().scalar(L.null_coroot()) # needs sage.graphs 0 .. WARNING:: @@ -801,10 +827,10 @@ def rho_classical(self): In affine type BC dual, this does not live in the weight lattice:: sage: L = CartanType(["BC",2,2]).dual().root_system().weight_space() - sage: L.rho_classical() + sage: L.rho_classical() # needs sage.graphs -3/2*Lambda[0] + Lambda[1] + Lambda[2] sage: L = CartanType(["BC",2,2]).dual().root_system().weight_lattice() - sage: L.rho_classical() + sage: L.rho_classical() # needs sage.graphs Traceback (most recent call last): ... ValueError: 5 is not divisible by 2 @@ -813,7 +839,7 @@ def rho_classical(self): Lambda = self.fundamental_weights() return rho - Lambda[0] * rho.level() / Lambda[0].level() - def embed_at_level(self, x, level = 1): + def embed_at_level(self, x, level=1): r""" Embed the classical weight `x` in the level ``level`` hyperplane @@ -828,6 +854,7 @@ def embed_at_level(self, x, level = 1): EXAMPLES:: + sage: # needs sage.graphs sage: L = RootSystem(["B",3,1]).weight_space() sage: L0 = L.classical() sage: alpha = L0.simple_roots() @@ -860,7 +887,7 @@ def weyl_dimension(self, highest_weight): 20 sage: P = RootSystem(['C',2]).weight_lattice() sage: La = P.basis() - sage: P.weyl_dimension(La[1]+La[2]) + sage: P.weyl_dimension(La[1]+La[2]) # needs sage.graphs 16 sage: type(RootSystem(['A',3]).ambient_lattice().weyl_dimension([2,1,0,0])) @@ -899,24 +926,24 @@ def _symmetric_form_matrix(self): EXAMPLES:: sage: P = RootSystem(['B',2]).weight_lattice() - sage: P._symmetric_form_matrix + sage: P._symmetric_form_matrix # needs sage.graphs [2 1] [1 1] sage: P = RootSystem(['C',2]).weight_lattice() - sage: P._symmetric_form_matrix + sage: P._symmetric_form_matrix # needs sage.graphs [1 1] [1 2] sage: P = RootSystem(['C',2,1]).weight_lattice() - sage: P._symmetric_form_matrix + sage: P._symmetric_form_matrix # needs sage.graphs [0 0 0 1] [0 1 1 1] [0 1 2 1] [1 1 1 0] sage: P = RootSystem(['A',4,2]).weight_lattice() - sage: P._symmetric_form_matrix + sage: P._symmetric_form_matrix # needs sage.graphs [ 0 0 0 1/2] [ 0 2 2 1] [ 0 2 4 1] @@ -967,6 +994,7 @@ def symmetric_form(self, la): EXAMPLES:: + sage: # needs sage.graphs sage: P = RootSystem(['C',2]).weight_lattice() sage: al = P.simple_roots() sage: al[1].symmetric_form(al[1]) @@ -981,6 +1009,7 @@ def symmetric_form(self, la): ....: for i in P.index_set() for j in P.index_set()) True + sage: # needs sage.graphs sage: P = RootSystem(['C',2,1]).weight_lattice(extended=True) sage: al = P.simple_roots() sage: al[1].symmetric_form(al[1]) @@ -1004,9 +1033,9 @@ def symmetric_form(self, la): sage: P = RootSystem(['C',2,1]).weight_lattice() sage: Q = RootSystem(['C',2,1]).root_lattice() - sage: al = P.simple_roots() - sage: alQ = Q.simple_roots() - sage: all(al[i].symmetric_form(al[j]) == alQ[i].symmetric_form(alQ[j]) + sage: al = P.simple_roots() # needs sage.graphs + sage: alQ = Q.simple_roots() # needs sage.graphs + sage: all(al[i].symmetric_form(al[j]) == alQ[i].symmetric_form(alQ[j]) # needs sage.graphs ....: for i in P.index_set() for j in P.index_set()) True @@ -1015,7 +1044,7 @@ def symmetric_form(self, la): lattice:: sage: La = P.basis() - sage: [La[0].symmetric_form(al) for al in P.simple_roots()] + sage: [La[0].symmetric_form(al) for al in P.simple_roots()] # needs sage.graphs [0, 0, 0] TESTS: @@ -1023,8 +1052,8 @@ def symmetric_form(self, la): We check that `A_{2n}^{(2)}` has 3 different root lengths:: sage: P = RootSystem(['A',4,2]).weight_lattice() - sage: al = P.simple_roots() - sage: [al[i].symmetric_form(al[i]) for i in P.index_set()] + sage: al = P.simple_roots() # needs sage.graphs + sage: [al[i].symmetric_form(al[i]) for i in P.index_set()] # needs sage.graphs [2, 4, 8] Check that :trac:`31410` is fixed, and the symmetric form @@ -1043,7 +1072,8 @@ def symmetric_form(self, la): ....: rho = 1/2*sum(P) ....: return [beta.symmetric_form(rho) for beta in P] - sage: all(s1(ct) == s2(ct) for ct in CartanType.samples(finite=True, crystallographic=True)) + sage: all(s1(ct) == s2(ct) # needs sage.graphs + ....: for ct in CartanType.samples(finite=True, crystallographic=True)) True """ @@ -1065,7 +1095,7 @@ def symmetric_form(self, la): # assert( t == self.plus(t.scalar(alphac[i]) * Lambda[i] for i in self.index_set() ) ) # t = self.plus( t.scalar(alphac[i]) * c[i] * Lambda[i] for i in self.index_set() ) - def to_weight_space(self, base_ring = None): + def to_weight_space(self, base_ring=None): r""" Map ``self`` to the weight space. diff --git a/src/sage/combinat/root_system/weight_space.py b/src/sage/combinat/root_system/weight_space.py index 808067aef1f..8a5118714c7 100644 --- a/src/sage/combinat/root_system/weight_space.py +++ b/src/sage/combinat/root_system/weight_space.py @@ -40,12 +40,14 @@ class WeightSpace(CombinatorialFreeModule): sage: Q = RootSystem(['A', 3]).weight_lattice(); Q Weight lattice of the Root system of type ['A', 3] - sage: Q.simple_roots() - Finite family {1: 2*Lambda[1] - Lambda[2], 2: -Lambda[1] + 2*Lambda[2] - Lambda[3], 3: -Lambda[2] + 2*Lambda[3]} + sage: Q.simple_roots() # needs sage.graphs + Finite family {1: 2*Lambda[1] - Lambda[2], + 2: -Lambda[1] + 2*Lambda[2] - Lambda[3], + 3: -Lambda[2] + 2*Lambda[3]} sage: Q = RootSystem(['A', 3, 1]).weight_lattice(); Q Weight lattice of the Root system of type ['A', 3, 1] - sage: Q.simple_roots() + sage: Q.simple_roots() # needs sage.graphs Finite family {0: 2*Lambda[0] - Lambda[1] - Lambda[3], 1: -Lambda[0] + 2*Lambda[1] - Lambda[2], 2: -Lambda[1] + 2*Lambda[2] - Lambda[3], @@ -54,12 +56,12 @@ class WeightSpace(CombinatorialFreeModule): For infinite types, the Cartan matrix is singular, and therefore the embedding of the root lattice is not faithful:: - sage: sum(Q.simple_roots()) + sage: sum(Q.simple_roots()) # needs sage.graphs 0 In particular, the null root is zero:: - sage: Q.null_root() + sage: Q.null_root() # needs sage.graphs 0 This can be compensated by extending the basis of the weight space @@ -69,7 +71,7 @@ class WeightSpace(CombinatorialFreeModule): types. In that case, if ``extended`` is set, then the basis of the weight space is extended by an element `\delta`:: - sage: Q = RootSystem(['A', 3, 1]).weight_lattice(extended = True); Q + sage: Q = RootSystem(['A', 3, 1]).weight_lattice(extended=True); Q Extended weight lattice of the Root system of type ['A', 3, 1] sage: Q.basis().keys() {0, 1, 2, 3, 'delta'} @@ -77,7 +79,7 @@ class WeightSpace(CombinatorialFreeModule): And the simple root `\alpha_0` associated to the special node is deformed as follows:: - sage: Q.simple_roots() + sage: Q.simple_roots() # needs sage.graphs Finite family {0: 2*Lambda[0] - Lambda[1] - Lambda[3] + delta, 1: -Lambda[0] + 2*Lambda[1] - Lambda[2], 2: -Lambda[1] + 2*Lambda[2] - Lambda[3], @@ -85,7 +87,7 @@ class WeightSpace(CombinatorialFreeModule): Now, the null root is nonzero:: - sage: Q.null_root() + sage: Q.null_root() # needs sage.graphs delta .. WARNING:: @@ -98,9 +100,9 @@ class WeightSpace(CombinatorialFreeModule): `A_{2n}^{(2)}`). Therefore we currently have:: sage: Q = RootSystem(["A",4,2]).weight_lattice(extended=True) - sage: Q.simple_root(0) + sage: Q.simple_root(0) # needs sage.graphs 2*Lambda[0] - Lambda[1] + delta - sage: Q.null_root() + sage: Q.null_root() # needs sage.graphs 2*delta whereas, with the standard notations from the literature, one @@ -125,15 +127,16 @@ class WeightSpace(CombinatorialFreeModule): extended weight lattice on that basis element can be recovered with:: - sage: Q.null_root()[index] + sage: Q.null_root()[index] # needs sage.graphs 2 TESTS:: - sage: for ct in CartanType.samples(crystallographic=True)+[CartanType(["A",2],["C",5,1])]: + sage: for ct in (CartanType.samples(crystallographic=True) # needs sage.graphs + ....: + [CartanType(["A",2], ["C",5,1])]): ....: TestSuite(ct.root_system().weight_lattice()).run() ....: TestSuite(ct.root_system().weight_space()).run() - sage: for ct in CartanType.samples(affine=True): + sage: for ct in CartanType.samples(affine=True): # needs sage.graphs ....: if ct.is_implemented(): ....: P = ct.root_system().weight_space(extended=True) ....: TestSuite(P).run() @@ -163,9 +166,9 @@ def __init__(self, root_system, base_ring, extended): sage: from sage.combinat.root_system.weight_space import WeightSpace sage: Q = WeightSpace(R, QQ); Q Weight space over the Rational Field of the Root system of type ['A', 4] - sage: TestSuite(Q).run() + sage: TestSuite(Q).run() # needs sage.graphs - sage: WeightSpace(R, QQ, extended = True) + sage: WeightSpace(R, QQ, extended=True) Traceback (most recent call last): ... ValueError: extended weight lattices are only implemented for affine root systems @@ -187,17 +190,17 @@ def sortkey(x): self.root_system = root_system CombinatorialFreeModule.__init__(self, base_ring, basis_keys, - prefix = "Lambdacheck" if root_system.dual_side else "Lambda", - latex_prefix = "\\Lambda^\\vee" if root_system.dual_side else "\\Lambda", + prefix="Lambdacheck" if root_system.dual_side else "Lambda", + latex_prefix="\\Lambda^\\vee" if root_system.dual_side else "\\Lambda", sorting_key=sortkey, - category = WeightLatticeRealizations(base_ring)) + category=WeightLatticeRealizations(base_ring)) if root_system.cartan_type().is_affine() and not extended: # For an affine type, register the quotient map from the # extended weight lattice/space to the weight lattice/space domain = root_system.weight_space(base_ring, extended=True) domain.module_morphism(self.fundamental_weight, - codomain = self + codomain=self ).register_as_coercion() def is_extended(self): @@ -315,13 +318,13 @@ def simple_root(self, j): EXAMPLES:: sage: L = RootSystem(["C",4]).weight_lattice() - sage: L.simple_root(3) + sage: L.simple_root(3) # needs sage.graphs -Lambda[2] + 2*Lambda[3] - Lambda[4] Its coefficients are given by the corresponding column of the Cartan matrix:: - sage: L.cartan_type().cartan_matrix()[:,2] + sage: L.cartan_type().cartan_matrix()[:,2] # needs sage.graphs [ 0] [-1] [ 2] @@ -329,7 +332,7 @@ def simple_root(self, j): Here are all simple roots:: - sage: L.simple_roots() + sage: L.simple_roots() # needs sage.graphs Finite family {1: 2*Lambda[1] - Lambda[2], 2: -Lambda[1] + 2*Lambda[2] - Lambda[3], 3: -Lambda[2] + 2*Lambda[3] - Lambda[4], @@ -340,7 +343,7 @@ def simple_root(self, j): `\delta`, where `\delta` is the null root:: sage: L = RootSystem(["C",4,1]).weight_lattice(extended=True) - sage: L.simple_root(0) + sage: L.simple_root(0) # needs sage.graphs 2*Lambda[0] - 2*Lambda[1] + delta In fact `\delta` is really `1/a_0` times the null root (see @@ -348,9 +351,9 @@ def simple_root(self, j): but this only makes a difference in type `BC`:: sage: L = RootSystem(CartanType(["BC",4,2])).weight_lattice(extended=True) - sage: L.simple_root(0) + sage: L.simple_root(0) # needs sage.graphs 2*Lambda[0] - Lambda[1] + delta - sage: L.null_root() + sage: L.null_root() # needs sage.graphs 2*delta .. SEEALSO:: @@ -373,11 +376,11 @@ def _repr_term(self, m): EXAMPLES:: sage: L = RootSystem(["C",4,1]).weight_lattice(extended=True) - sage: L.simple_root(0) # indirect doctest + sage: L.simple_root(0) # indirect doctest # needs sage.graphs 2*Lambda[0] - 2*Lambda[1] + delta sage: L = RootSystem(["C",4,1]).coweight_lattice(extended=True) - sage: L.simple_root(0) # indirect doctest + sage: L.simple_root(0) # indirect doctest # needs sage.graphs 2*Lambdacheck[0] - Lambdacheck[1] + deltacheck """ if m == "delta": @@ -391,11 +394,11 @@ def _latex_term(self, m): EXAMPLES:: sage: L = RootSystem(["C",4,1]).weight_lattice(extended=True) - sage: latex(L.simple_root(0)) # indirect doctest + sage: latex(L.simple_root(0)) # indirect doctest # needs sage.graphs 2 \Lambda_{0} - 2 \Lambda_{1} + \delta sage: L = RootSystem(["C",4,1]).coweight_lattice(extended=True) - sage: latex(L.simple_root(0)) # indirect doctest + sage: latex(L.simple_root(0)) # indirect doctest # needs sage.graphs 2 \Lambda^\vee_{0} - \Lambda^\vee_{1} + \delta^\vee """ if m == "delta": @@ -451,7 +454,7 @@ def to_ambient_space_morphism(self): def basis_value(basis, i): return basis[i] - return self.module_morphism(on_basis = functools.partial(basis_value, basis), codomain=L) + return self.module_morphism(on_basis=functools.partial(basis_value, basis), codomain=L) class WeightSpaceElement(CombinatorialFreeModule.Element): @@ -494,12 +497,13 @@ def scalar(self, lambdacheck): won't be the job of this method:: sage: R = RootSystem(["A",3]) - sage: alpha = R.weight_space().roots() - sage: alphacheck = R.coweight_space().roots() - sage: alpha[1].scalar(alphacheck[1]) + sage: alpha = R.weight_space().roots() # needs sage.graphs + sage: alphacheck = R.coweight_space().roots() # needs sage.graphs + sage: alpha[1].scalar(alphacheck[1]) # needs sage.graphs Traceback (most recent call last): ... - ValueError: -Lambdacheck[1] + 2*Lambdacheck[2] - Lambdacheck[3] is not in the coroot space + ValueError: -Lambdacheck[1] + 2*Lambdacheck[2] - Lambdacheck[3] + is not in the coroot space """ # TODO: Find some better test if lambdacheck not in self.parent().coroot_lattice() and lambdacheck not in self.parent().coroot_space(): @@ -519,22 +523,22 @@ def is_dominant(self): sage: W = RootSystem(['A',3]).weight_space() sage: Lambda = W.basis() - sage: w = Lambda[1]+Lambda[3] + sage: w = Lambda[1] + Lambda[3] sage: w.is_dominant() True - sage: w = Lambda[1]-Lambda[2] + sage: w = Lambda[1] - Lambda[2] sage: w.is_dominant() False In the extended affine weight lattice, 'delta' is orthogonal to the positive coroots, so adding or subtracting it should not - effect dominance :: + affect dominance :: sage: P = RootSystem(['A',2,1]).weight_lattice(extended=true) sage: Lambda = P.fundamental_weights() - sage: delta = P.null_root() - sage: w = Lambda[1]-delta - sage: w.is_dominant() + sage: delta = P.null_root() # needs sage.graphs + sage: w = Lambda[1] - delta # needs sage.graphs + sage: w.is_dominant() # needs sage.graphs True """ diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index f306df7eddf..51baa89b661 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups sage.modules """ Weyl Character Rings """ @@ -10,7 +11,8 @@ # **************************************************************************** import sage.combinat.root_system.branching_rules -from sage.categories.all import Algebras, AlgebrasWithBasis +from sage.categories.algebras import Algebras +from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.root_system import RootSystem @@ -124,7 +126,7 @@ def __init__(self, ct, base_ring=ZZ, prefix=None, style="lattice", k=None, conju self._origin = self._space.zero() if prefix is None: if ct.is_atomic(): - prefix = ct[0]+str(ct[1]) + prefix = ct[0] + str(ct[1]) else: prefix = repr(ct) self._prefix = prefix @@ -154,9 +156,11 @@ def next_level(wt): else: B = self._space - cat = AlgebrasWithBasis(base_ring).Subobjects() + cat = AlgebrasWithBasis(base_ring).Commutative() if k is None: - cat = cat.Graded() + cat = cat.Subobjects().Graded() + else: + cat = cat.FiniteDimensional() CombinatorialFreeModule.__init__(self, base_ring, B, category=cat) # Register the embedding of self into ambient as a coercion @@ -507,7 +511,7 @@ def product_on_basis(self, a, b): # smaller character is the one that is decomposed # into weights. if sum(a.coefficients()) > sum(b.coefficients()): - a,b = b,a + a, b = b, a return self._product_helper(self._irr_weights(a), b) def _product_helper(self, d1, b): @@ -532,12 +536,12 @@ def _product_helper(self, d1, b): """ d = {} for k in d1: - [epsilon,g] = self.dot_reduce(b+k) + [epsilon, g] = self.dot_reduce(b + k) if epsilon == 1: - d[g] = d.get(g,0) + d1[k] + d[g] = d.get(g, 0) + d1[k] elif epsilon == -1: - d[g] = d.get(g,0) - d1[k] - return self._from_dict(d) + d[g] = d.get(g, 0) - d1[k] + return self._from_dict(d, coerce=True) def dot_reduce(self, a): r""" @@ -573,31 +577,32 @@ def dot_reduce(self, a): return [0, self._space.zero()] elif c < -1: epsilon = -epsilon - ret -= (1+c)*alpha[i] + ret -= (1 + c) * alpha[i] done = False break if self._k is not None: l = self.level(ret) k = self._k if l > k: - if l == k+1: + if l == k + 1: return [0, self._space.zero()] else: epsilon = -epsilon - ret = self.affine_reflect(ret,k+1) + ret = self.affine_reflect(ret, k + 1) done = False return [epsilon, ret] def affine_reflect(self, wt, k=0): r""" + Return the reflection of wt in the hyperplane `\theta`. + + Optionally, this also shifts by a multiple `k` of `\theta`. + INPUT: - ``wt`` -- a weight - ``k`` -- (optional) a positive integer - Returns the reflection of wt in the hyperplane - `\theta`. Optionally shifts by a multiple `k`of `\theta`. - EXAMPLES:: sage: B22 = FusionRing("B2",2) @@ -606,8 +611,8 @@ def affine_reflect(self, wt, k=0): sage: [B22.affine_reflect(x,2) for x in fw] [(2, 1), (3/2, 3/2)] """ - coef = ZZ(2*wt.inner_product(self._highest)/self._hip) - return wt+(k-coef)*self._highest + coef = ZZ(2 * wt.inner_product(self._highest) / self._hip) + return wt + (k - coef) * self._highest def some_elements(self): """ @@ -715,8 +720,15 @@ def _demazure_helper(self, dd, word="long", debug=False): alpha = self._space.simple_roots() r = self.rank() cm = {} + supp = [] for i in index_set: - cm[i] = tuple(int(alpha[i].inner_product(alphacheck[j])) for j in index_set) + temp = [] + cm[i] = [0] * r + for ind, j in enumerate(index_set): + cm[i][ind] = int(alpha[i].inner_product(alphacheck[j])) + if cm[i][ind]: + temp.append(ind) + supp.append(temp) if debug: print("cm[%s]=%s" % (i, cm[i])) accum = dd @@ -727,21 +739,27 @@ def _demazure_helper(self, dd, word="long", debug=False): print("i=%s" % i) next = {} for v in accum: - coroot = v[i-1] + coroot = v[i - 1] if debug: print(" v=%s, coroot=%s" % (v, coroot)) if coroot >= 0: mu = v - for j in range(coroot+1): - next[mu] = next.get(mu,0)+accum[v] + for j in range(coroot + 1): + next[mu] = next.get(mu, 0) + accum[v] if debug: print(" mu=%s, next[mu]=%s" % (mu, next[mu])) - mu = tuple(mu[k] - cm[i][k] for k in range(r)) + mu = list(mu) + for k in supp[i - 1]: + mu[k] -= cm[i][k] + mu = tuple(mu) else: mu = v - for j in range(-1-coroot): - mu = tuple(mu[k] + cm[i][k] for k in range(r)) - next[mu] = next.get(mu,0)-accum[v] + for j in range(-1 - coroot): + mu = list(mu) + for k in supp[i - 1]: + mu[k] += cm[i][k] + mu = tuple(mu) + next[mu] = next.get(mu, 0) - accum[v] if debug: print(" mu=%s, next[mu]=%s" % (mu, next[mu])) accum = {} @@ -773,9 +791,9 @@ def _weight_multiplicities(self, x): d1 = self._irr_weights(k) for l in d1: if l in d: - d[l] += c*d1[l] + d[l] += c * d1[l] else: - d[l] = c*d1[l] + d[l] = c * d1[l] for k in list(d): if d[k] == 0: del d[k] @@ -808,7 +826,7 @@ def irr_repr(self, hwv): sage: [B3.irr_repr(v) for v in B3.fundamental_weights()] ['B3(1,0,0)', 'B3(0,1,0)', 'B3(0,0,1)'] """ - return self._prefix+self._wt_repr(hwv) + return self._prefix + self._wt_repr(hwv) def level(self, wt): """ @@ -822,7 +840,7 @@ def level(self, wt): sage: [CartanType("F4~").dual().a()[x] for x in [1..4]] [2, 3, 2, 1] """ - return ZZ(2*wt.inner_product(self._highest)/self._hip) + return ZZ(2 * wt.inner_product(self._highest) / self._hip) def _dual_helper(self, wt): """ @@ -841,7 +859,7 @@ def _dual_helper(self, wt): alphacheck = self._space.simple_coroots() fw = self._space.fundamental_weights() for i in self._space.index_set(): - ret += wt.inner_product(alphacheck[i])*fw[self._opposition[i]] + ret += wt.inner_product(alphacheck[i]) * fw[self._opposition[i]] return ret def _wt_repr(self, wt): @@ -1062,7 +1080,7 @@ def _char_from_weights(self, mdict): hdict = {} ddict = mdict.copy() while ddict: - highest = max((x.inner_product(self._space.rho()),x) for x in ddict)[1] + highest = max((x.inner_product(self._space.rho()), x) for x in ddict)[1] if not highest.is_dominant(): raise ValueError("multiplicity dictionary may not be Weyl group invariant") sdict = self._irr_weights(highest) @@ -1263,8 +1281,10 @@ def dual(self): def highest_weight(self): """ - This method is only available for basis elements. Returns the - parametrizing dominant weight of an irreducible character. + Return the parametrizing dominant weight + of an irreducible character. + + This method is only available for basis elements. EXAMPLES:: @@ -1307,7 +1327,7 @@ def __pow__(self, n): n = -n res = self - for i in range(n-1): + for i in range(n - 1): res = self * res return res @@ -1355,13 +1375,12 @@ def symmetric_power(self, k): if k == 1: return self ret = par.zero() - for r in range(1, k+1): - adam_r = self._adams_operation_helper(r) - ret += par.linear_combination((par._product_helper(adam_r, l), c) for (l, c) in self.symmetric_power(k-r)) - dd = {} + for r in range(1, k + 1): + adam_r = self._adams_operator_helper(r) + ret += par.linear_combination((par._product_helper(adam_r, l), c) + for l, c in self.symmetric_power(k - r)) m = ret.weight_multiplicities() - for l in m: - dd[l] = m[l]/k + dd = {key: val / k for key, val in m.items()} return self.parent().char_from_weights(dd) @cached_method @@ -1394,8 +1413,8 @@ def exterior_power(self, k): if k == 1: return self ret = par.zero() - for r in range(1,k+1): - adam_r = self._adams_operation_helper(r) + for r in range(1, k + 1): + adam_r = self._adams_operator_helper(r) if is_even(r): ret -= par.linear_combination((par._product_helper(adam_r, l), c) for (l, c) in self.exterior_power(k-r)) else: @@ -1406,7 +1425,7 @@ def exterior_power(self, k): dd[l] = m[l]/k return self.parent().char_from_weights(dd) - def adams_operation(self, r): + def adams_operator(self, r): """ Return the `r`-th Adams operation of ``self``. @@ -1420,12 +1439,14 @@ def adams_operation(self, r): EXAMPLES:: sage: A2 = WeylCharacterRing("A2") - sage: A2(1,1,0).adams_operation(3) + sage: A2(1,1,0).adams_operator(3) A2(2,2,2) - A2(3,2,1) + A2(3,3,0) """ - return self.parent().char_from_weights(self._adams_operation_helper(r)) + return self.parent().char_from_weights(self._adams_operator_helper(r)) - def _adams_operation_helper(self, r): + adams_operation = adams_operator + + def _adams_operator_helper(self, r): """ Helper function for Adams operations. @@ -1439,14 +1460,11 @@ def _adams_operation_helper(self, r): EXAMPLES:: sage: A2 = WeylCharacterRing("A2") - sage: A2(1,1,0)._adams_operation_helper(3) + sage: A2(1,1,0)._adams_operator_helper(3) {(3, 3, 0): 1, (3, 0, 3): 1, (0, 3, 3): 1} """ d = self.weight_multiplicities() - dd = {} - for k in d: - dd[r*k] = d[k] - return dd + return {r * key: val for key, val in d.items()} def symmetric_square(self): """ @@ -1685,14 +1703,14 @@ def irreducible_character_freudenthal(hwv, debug=False): for alpha in positive_roots: mu_plus_i_alpha = mu + alpha while mu_plus_i_alpha in mdict: - accum += mdict[mu_plus_i_alpha]*(mu_plus_i_alpha).inner_product(alpha) + accum += mdict[mu_plus_i_alpha] * (mu_plus_i_alpha).inner_product(alpha) mu_plus_i_alpha += alpha if accum == 0: next_layer[mu] = 0 else: hwv_plus_rho = hwv + rho mu_plus_rho = mu + rho - next_layer[mu] = ZZ(2*accum)/ZZ((hwv_plus_rho).inner_product(hwv_plus_rho)-(mu_plus_rho).inner_product(mu_plus_rho)) + next_layer[mu] = ZZ(2 * accum) / ZZ((hwv_plus_rho).inner_product(hwv_plus_rho) - (mu_plus_rho).inner_product(mu_plus_rho)) current_layer = next_layer return mdict @@ -1770,7 +1788,7 @@ def __init__(self, parent, prefix): self._base_ring = parent._base_ring if prefix is None: # TODO: refactor this fragile logic into CartanType's - if self._parent._prefix.replace('x','_').isupper(): + if self._parent._prefix.replace('x', '_').isupper(): # The 'x' workaround above is to support reducible Cartan types like 'A1xB2' prefix = self._parent._prefix.lower() elif self._parent._prefix.islower(): @@ -1779,7 +1797,7 @@ def __init__(self, parent, prefix): # TODO: this only works for irreducible Cartan types! prefix = (self._cartan_type[0].lower() + str(self._rank)) self._prefix = prefix - category = AlgebrasWithBasis(self._base_ring) + category = AlgebrasWithBasis(self._base_ring).Commutative() CombinatorialFreeModule.__init__(self, self._base_ring, self._space, category=category) def _repr_(self): @@ -1862,7 +1880,7 @@ def product_on_basis(self, a, b): sage: a2(1,0,0) * a2(0,1,0) # indirect doctest a2(1,1,0) """ - return self(a+b) + return self(a + b) def some_elements(self): """ @@ -1996,7 +2014,7 @@ def wt_repr(self, wt): sage: [G2.ambient().wt_repr(x) for x in G2.fundamental_weights()] ['g2(1,0)', 'g2(0,1)'] """ - return self._prefix+self.parent()._wt_repr(wt) + return self._prefix + self.parent()._wt_repr(wt) def _repr_term(self, t): """ @@ -2102,9 +2120,7 @@ def shift(self, mu): [g2(2,2), g2(1,3)] """ d1 = self.monomial_coefficients() - d2 = {} - for nu in d1: - d2[mu + nu] = d1[nu] + d2 = {mu + nu: val for nu, val in d1.items()} return self.parent()._from_dict(d2) def demazure(self, w, debug=False): @@ -2212,7 +2228,7 @@ def demazure_lusztig(self, i, v): if i in self.parent().space().index_set(): rho = self.parent().space().from_vector_notation(self.parent().space().rho(), style="coroots") inv = self.scale(-1) - return (-inv.shift(-rho).demazure([i]).shift(rho)+v * inv.demazure([i])).scale(-1) + return (-inv.shift(-rho).demazure([i]).shift(rho) + v * inv.demazure([i])).scale(-1) elif isinstance(i, list): if not i: return self diff --git a/src/sage/combinat/root_system/weyl_group.py b/src/sage/combinat/root_system/weyl_group.py index d64d2c1f366..c2e9b8dc59d 100644 --- a/src/sage/combinat/root_system/weyl_group.py +++ b/src/sage/combinat/root_system/weyl_group.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups sage.modules """ Weyl Groups @@ -16,14 +17,14 @@ sage: w = WeylGroup(['A',3]) sage: d = w.cayley_graph(); d Digraph on 24 vertices - sage: d.show3d(color_by_label=True, edge_size=0.01, vertex_size=0.03) + sage: d.show3d(color_by_label=True, edge_size=0.01, vertex_size=0.03) # needs sage.plot The Cayley graph of the Weyl Group of type ['D', 4]:: sage: w = WeylGroup(['D',4]) sage: d = w.cayley_graph(); d Digraph on 192 vertices - sage: d.show3d(color_by_label=True, edge_size=0.01, vertex_size=0.03) #long time (less than one minute) + sage: d.show3d(color_by_label=True, edge_size=0.01, vertex_size=0.03) # long time (less than one minute), needs sage.plot .. TODO:: @@ -39,12 +40,12 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap -from sage.groups.matrix_gps.group_element import MatrixGroupElement_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.group_element_gap import MatrixGroupElement_gap from sage.groups.perm_gps.permgroup import PermutationGroup_generic from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.interfaces.gap import gap +from sage.libs.gap.libgap import libgap from sage.misc.cachefunc import cached_method from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.cartan_matrix import CartanMatrix @@ -53,7 +54,9 @@ from sage.combinat.root_system.root_lattice_realizations import RootLatticeRealizations from sage.structure.unique_representation import UniqueRepresentation from sage.structure.richcmp import richcmp, richcmp_not_equal -from sage.categories.all import WeylGroups, FiniteWeylGroups, AffineWeylGroups +from sage.categories.weyl_groups import WeylGroups +from sage.categories.finite_weyl_groups import FiniteWeylGroups +from sage.categories.affine_weyl_groups import AffineWeylGroups from sage.categories.permutation_groups import PermutationGroups from sage.sets.family import Family from sage.matrix.constructor import Matrix @@ -74,6 +77,7 @@ def WeylGroup(x, prefix=None, implementation='matrix'): to products of simple reflections - ``implementation`` -- one of the following: + * ``'matrix'`` - as matrices acting on a root system * ``"permutation"`` - as a permutation group acting on the roots @@ -183,7 +187,7 @@ def WeylGroup(x, prefix=None, implementation='matrix'): TESTS:: sage: TestSuite(WeylGroup(["A",3])).run() - sage: TestSuite(WeylGroup(["A",3,1])).run() # long time + sage: TestSuite(WeylGroup(["A",2,1])).run() # long time sage: W = WeylGroup(['A',3,1]) sage: s = W.simple_reflections() @@ -197,7 +201,7 @@ def WeylGroup(x, prefix=None, implementation='matrix'): """ if implementation == "permutation": return WeylGroup_permutation(x, prefix) - elif implementation != "matrix": + if implementation != "matrix": raise ValueError("invalid implementation") if x in RootLatticeRealizations: @@ -228,6 +232,10 @@ def __init__(self, domain, prefix): sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]]) sage: W = WeylGroup(cm) sage: TestSuite(W).run() # long time + + TESTS:: + + sage: W = WeylGroup(SymmetricGroup(1)) """ self._domain = domain if self.cartan_type().is_affine(): @@ -244,8 +252,10 @@ def __init__(self, domain, prefix): # FinitelyGeneratedMatrixGroup_gap takes plain matrices as input gens_matrix = [self.morphism_matrix(self.domain().simple_reflection(i)) for i in self.index_set()] - from sage.libs.gap.libgap import libgap - libgap_group = libgap.Group(gens_matrix) + if not gens_matrix: + libgap_group = libgap.Group([], matrix(ZZ, 1, 1, [1])) + else: + libgap_group = libgap.Group(gens_matrix) degree = ZZ(self.domain().dimension()) ring = self.domain().base_ring() FinitelyGeneratedMatrixGroup_gap.__init__( @@ -282,8 +292,9 @@ def index_set(self): # Should be implemented in (morphisms of) modules with basis def morphism_matrix(self, f): - return matrix(self.domain().base_ring(), [f(b).to_vector() - for b in self.domain().basis()]).transpose() + return matrix(self.domain().base_ring(), + [f(b).to_vector() + for b in self.domain().basis()]).transpose() def from_morphism(self, f): return self._element_constructor_(self.morphism_matrix(f)) @@ -394,10 +405,10 @@ def _repr_(self): sage: WeylGroup(['A', 3, 1]) Weyl Group of type ['A', 3, 1] (as a matrix group acting on the root space) """ - return "Weyl Group of type %s (as a matrix group acting on the %s)" % (self.cartan_type(), - self._domain._name_string(capitalize=False, - base_ring=False, - type=False)) + domain = self._domain._name_string(capitalize=False, + base_ring=False, + type=False) + return "Weyl Group of type %s (as a matrix group acting on the %s)" % (self.cartan_type(), domain) def character_table(self): """ @@ -423,8 +434,8 @@ def character_table(self): X.4 3 -1 1 . -1 X.5 1 1 1 1 1 """ - gens_str = ', '.join(str(g.gap()) for g in self.gens()) - ctbl = gap('CharacterTable(Group({0}))'.format(gens_str)) + G = libgap.Group([libgap(g) for g in self.gens()]) + ctbl = libgap.CharacterTable(G) return ctbl.Display() @cached_method @@ -502,19 +513,19 @@ def long_element_hardcoded(self): sage: all(WeylGroup(t).long_element() == WeylGroup(t).long_element_hardcoded() for t in types) # long time (17s on sage.math, 2011) True """ - type = self.cartan_type() - if type[0] == 'D' and type[1] % 2: + typ = self.cartan_type() + if typ[0] == 'D' and typ[1] % 2: l = [-1 for i in range(self.n - 1)] l.append(1) m = diagonal_matrix(QQ, l) - elif type[0] == 'A': + elif typ[0] == 'A': l = [0 for k in range((self.n)**2)] for k in range(self.n - 1, (self.n)**2 - 1, self.n - 1): l[k] = 1 m = matrix(QQ, self.n, l) - elif type[0] == 'E': - if type[1] == 6: - half = ZZ(1) / ZZ(2) + elif typ[0] == 'E': + if typ[1] == 6: + half = QQ((1, 2)) l = [[-half, -half, -half, half, 0, 0, 0, 0], [-half, -half, half, -half, 0, 0, 0, 0], [-half, half, -half, -half, 0, 0, 0, 0], @@ -526,15 +537,15 @@ def long_element_hardcoded(self): m = matrix(QQ, 8, l) else: raise NotImplementedError("not implemented yet for this type") - elif type[0] == 'G': - third = ZZ(1) / ZZ(3) - twothirds = ZZ(2) / ZZ(3) + elif typ[0] == 'G': + third = QQ((1, 3)) + twothirds = QQ((2, 3)) l = [[-third, twothirds, twothirds], [twothirds, -third, twothirds], [twothirds, twothirds, -third]] m = matrix(QQ, 3, l) else: - m = diagonal_matrix([-1 for i in range(self.n)]) + m = diagonal_matrix([-1] * self.n) return self(m) def classical(self): @@ -544,7 +555,7 @@ def classical(self): Caveat: we assume that 0 is a special node of the Dynkin diagram - TODO: extract parabolic subgroup method + .. TODO:: extract parabolic subgroup method EXAMPLES:: @@ -640,10 +651,10 @@ def __repr__(self): sage: RootSystem(['C',4,1]).coweight_lattice().weyl_group().classical() Parabolic Subgroup of the Weyl Group of type ['C', 4, 1]^* (as a matrix group acting on the coweight lattice) """ - return "Parabolic Subgroup of the Weyl Group of type %s (as a matrix group acting on the %s)" % (self.domain().cartan_type(), - self._domain._name_string(capitalize=False, - base_ring=False, - type=False)) + domain = self._domain._name_string(capitalize=False, + base_ring=False, + type=False) + return "Parabolic Subgroup of the Weyl Group of type %s (as a matrix group acting on the %s)" % (self.domain().cartan_type(), domain) def weyl_group(self, prefix="hereditary"): """ @@ -738,15 +749,14 @@ def _repr_(self): """ if self._parent._prefix is None: return MatrixGroupElement_gap._repr_(self) - else: - redword = self.reduced_word() - if len(redword) == 0: - return "1" - else: - ret = "" - for i in redword[:-1]: - ret += "%s%d*" % (self._parent._prefix, i) - return ret + "%s%d" % (self._parent._prefix, redword[-1]) + + redword = self.reduced_word() + if len(redword) == 0: + return "1" + + ret = "".join("%s%d*" % (self._parent._prefix, i) + for i in redword[:-1]) + return ret + "%s%d" % (self._parent._prefix, redword[-1]) def _latex_(self): r""" @@ -769,13 +779,12 @@ def _latex_(self): """ if self._parent._prefix is None: return MatrixGroupElement_gap._latex_(self) - else: - redword = self.reduced_word() - if not redword: - return "1" - else: - return "".join("%s_{%d}" % (self._parent._prefix, i) - for i in redword) + + redword = self.reduced_word() + if not redword: + return "1" + + return "".join("%s_{%d}" % (self._parent._prefix, i) for i in redword) def __eq__(self, other): """ @@ -847,7 +856,7 @@ def action(self, v): # Descents # ####################################################################### - def has_descent(self, i, positive=False, side="right"): + def has_descent(self, i, positive=False, side="right") -> bool: """ Test if ``self`` has a descent at position ``i``. @@ -909,13 +918,12 @@ def has_descent(self, i, positive=False, side="right"): else: use_rho = side == "left" - if use_rho is not (side == "left"): - self = ~self + element = self if use_rho is (side == "left") else ~self if use_rho: - s = self.action(L.rho()).scalar(L.alphacheck()[i]) >= 0 + s = element.action(L.rho()).scalar(L.alphacheck()[i]) >= 0 else: - s = self.action(L.alpha()[i]).is_positive_root() + s = element.action(L.alpha()[i]).is_positive_root() return s is positive @@ -965,12 +973,7 @@ def apply_simple_reflection(self, i, side="right"): s = self.parent().simple_reflections() if side == "right": return self * s[i] - else: - return s[i] * self - -# TODO -# The methods first_descent, descents, reduced_word appear almost verbatim in -# root_lattice_realizations and need to be factored out! + return s[i] * self def to_permutation(self): """ diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index fa260e70343..e8a44b1b163 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -522,10 +522,10 @@ def __init__(self): """ TESTS:: - sage: sum(x**len(t) for t in - ....: set(RootedTree(t) for t in OrderedTrees(6))) + sage: sum(x**len(t) # optional - sage.symbolic + ....: for t in set(RootedTree(t) for t in OrderedTrees(6))) x^5 + x^4 + 3*x^3 + 6*x^2 + 9*x - sage: sum(x**len(t) for t in RootedTrees(6)) + sage: sum(x**len(t) for t in RootedTrees(6)) # optional - sage.symbolic x^5 + x^4 + 3*x^3 + 6*x^2 + 9*x sage: TestSuite(RootedTrees()).run() # long time @@ -625,14 +625,14 @@ class RootedTrees_size(RootedTrees): TESTS:: sage: from sage.combinat.rooted_tree import RootedTrees_size - sage: for i in range(1, 6): TestSuite(RootedTrees_size(i)).run() + sage: for i in range(1, 6): TestSuite(RootedTrees_size(i)).run() # optional - sage.combinat """ def __init__(self, n): """ TESTS:: - sage: for i in range(1, 6): + sage: for i in range(1, 6): # optional - sage.combinat ....: TestSuite(RootedTrees(i)).run() """ super().__init__(category=FiniteEnumeratedSets()) @@ -663,7 +663,7 @@ def _an_element_(self): """ TESTS:: - sage: RootedTrees(4).an_element() # indirect doctest + sage: RootedTrees(4).an_element() # indirect doctest # optional - sage.combinat [[[[]]]] """ return self.first() @@ -681,11 +681,11 @@ def __iter__(self): sage: from sage.combinat.rooted_tree import * sage: RootedTrees(1).list() [[]] - sage: RootedTrees(2).list() + sage: RootedTrees(2).list() # optional - sage.combinat [[[]]] - sage: RootedTrees(3).list() + sage: RootedTrees(3).list() # optional - sage.combinat [[[[]]], [[], []]] - sage: RootedTrees(4).list() + sage: RootedTrees(4).list() # optional - sage.combinat [[[[[]]]], [[[], []]], [[], [[]]], [[], [], []]] """ if self._n == 1: @@ -757,7 +757,7 @@ def element_class(self): sage: S = RootedTrees(3) sage: S.element_class <class 'sage.combinat.rooted_tree.RootedTrees_all_with_category.element_class'> - sage: S.first().__class__ == RootedTrees().first().__class__ + sage: S.first().__class__ == RootedTrees().first().__class__ # optional - sage.combinat True """ return self._parent_for.element_class diff --git a/src/sage/combinat/rsk.py b/src/sage/combinat/rsk.py index eb3d2880727..1a4ae2e548f 100644 --- a/src/sage/combinat/rsk.py +++ b/src/sage/combinat/rsk.py @@ -397,7 +397,7 @@ def backward_rule(self, p, q, output): return self._backward_format_output(rev_word, None, output, p.is_standard(), True) if q not in SemistandardTableaux(): - raise ValueError("q(=%s) must be a semistandard tableau" %q) + raise ValueError("q(=%s) must be a semistandard tableau" % q) # Thus, q is semistandard but not standard. @@ -513,7 +513,7 @@ def _backward_format_output(self, lower_row, upper_row, output, return [list(reversed(upper_row)), list(reversed(lower_row))] if output in ['permutation', 'word']: raise TypeError( - "q must be standard to have a %s as valid output" %output) + "q must be standard to have a %s as valid output" % output) raise ValueError("invalid output option") @@ -2276,7 +2276,7 @@ def insertion(self, j, r, epsilon=0): bisect = bisect_right if epsilon == 0 else bisect_left if (r[-1] < j) or (r[-1] == j and epsilon == 0): - return None, len(r) # j needs to be added at the end of the list r. + return None, len(r) # j needs to be added at the end of the list r. # Figure out where to insert j into the list r. The # bisect command returns the position of the least # element of r greater than j. We will call it y. @@ -2380,7 +2380,7 @@ def backward_rule(self, p, q, output='array'): if vi in iter_dict: iter_dict[vi].append(k) else: - iter_dict[vi]=[k] + iter_dict[vi] = [k] for key in sorted(iter_dict, reverse=True): for rows in iter_dict[key]: row_index, col_index = (rows, key) if epsilon == 0 else (key, rows) @@ -2489,7 +2489,7 @@ def _backward_format_output(self, lower_row, upper_row, output, return Word(reversed(lower_row)) else: raise TypeError("q must be standard to have a %s as " - "valid output" %output) + "valid output" % output) raise ValueError("invalid output option") @@ -2586,7 +2586,7 @@ class RuleStar(Rule): ....: for T in SemistandardTableaux(shape, max_entry=4) ....: if fc(row_reading(T.conjugate()))] sage: Checks = [] - sage: for T in FC_tabs: + sage: for T in FC_tabs: # long time ....: shape = T.shape().conjugate() ....: P = T.conjugate() ....: Checks += [all((P,Q) == tuple(RSK(*RSK_inverse(P, Q, @@ -2596,7 +2596,7 @@ class RuleStar(Rule): sage: all(Checks) True sage: Checks = [] - sage: for T in FC_tabs: + sage: for T in FC_tabs: # long time ....: shape = T.shape().conjugate() ....: P = T.conjugate() ....: Checks += [all((P,Q) == tuple(RSK(RSK_inverse(P, Q, @@ -2727,7 +2727,7 @@ def forward_rule(self, obj1, obj2=None, check_braid=True): obj1 = list(range(1, len(obj1)+1)) else: h = obj1 - obj1 = sum([[h.factors-i]*len(h.value[i]) for i in reversed(range(h.factors))],[]) + obj1 = sum([[h.factors-i]*len(h.value[i]) for i in reversed(range(h.factors))], []) obj2 = [i for f in h.value[::-1] for i in reversed(f)] if len(obj1) != len(obj2): raise ValueError(f"{obj1} and {obj2} have different number of elements") @@ -2742,7 +2742,7 @@ def forward_rule(self, obj1, obj2=None, check_braid=True): h = H.from_reduced_word(obj2) from sage.combinat import permutation p = permutation.from_reduced_word(h.reduced_word()) - if p.has_pattern([3,2,1]): + if p.has_pattern([3, 2, 1]): raise ValueError("the Star insertion is not defined for non-fully commutative words") p = [] # the "insertion" tableau @@ -2834,7 +2834,7 @@ def backward_rule(self, p, q, output='array'): h = H.from_reduced_word(row_reading) from sage.combinat import permutation w = permutation.from_reduced_word(h.reduced_word()) - if w.has_pattern([3,2,1]): + if w.has_pattern([3, 2, 1]): raise ValueError(f"the row reading word of the insertion tableau {p} is not fully-commutative") p_copy = p.to_list() @@ -2859,7 +2859,7 @@ def backward_rule(self, p, q, output='array'): x = self.reverse_insertion(x, row) line2.append(x) line1.append(value) - return self._backward_format_output(line1[::-1],line2[::-1],output) + return self._backward_format_output(line1[::-1], line2[::-1], output) def insertion(self, b, r): r""" @@ -2887,7 +2887,7 @@ def insertion(self, b, r): k -= 1 k += 1 else: - y_pos = bisect_right(r,b) + y_pos = bisect_right(r, b) k = r[y_pos] r[y_pos] = b return k @@ -2955,7 +2955,7 @@ def _backward_format_output(self, obj1, obj2, output): if j == 0: df.append([]) if j > 0 and obj1[j] < obj1[j-1]: - for a in range(obj1[j-1]-obj1[j]): + for _ in range(obj1[j-1]-obj1[j]): df.append([]) df[-1].append(obj2[j]) if obj1: diff --git a/src/sage/combinat/schubert_polynomial.py b/src/sage/combinat/schubert_polynomial.py index 7e9164db5de..441dbbe3317 100644 --- a/src/sage/combinat/schubert_polynomial.py +++ b/src/sage/combinat/schubert_polynomial.py @@ -73,17 +73,17 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.categories.all import GradedAlgebrasWithBasis + +from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.key_polynomial import KeyPolynomial from sage.combinat.permutation import Permutations, Permutation from sage.misc.cachefunc import cached_method from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial_sparse +from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.polynomial.multi_polynomial import is_MPolynomial - +from sage.rings.polynomial.multi_polynomial import MPolynomial import sage.libs.symmetrica.all as symmetrica @@ -150,7 +150,7 @@ def expand(self): x0 """ p = symmetrica.t_SCHUBERT_POLYNOM(self) - if not is_MPolynomial(p): + if not isinstance(p, MPolynomial): R = PolynomialRing(self.parent().base_ring(), 1, 'x0') p = R(p) return p @@ -436,7 +436,7 @@ def _element_constructor_(self, x): sage: X._element_constructor_([1,2,1]) Traceback (most recent call last): ... - ValueError: The input [1, 2, 1] is not a valid permutation + ValueError: the input [1, 2, 1] is not a valid permutation Now we check for correct handling of the empty permutation (:trac:`23443`):: @@ -456,15 +456,15 @@ def _element_constructor_(self, x): if isinstance(x, list): # checking the input to avoid symmetrica crashing Sage, see trac 12924 if x not in Permutations(): - raise ValueError("The input %s is not a valid permutation" % x) + raise ValueError(f"the input {x} is not a valid permutation") perm = Permutation(x).remove_extra_fixed_points() return self._from_dict({perm: self.base_ring().one()}) elif isinstance(x, Permutation): perm = x.remove_extra_fixed_points() return self._from_dict({perm: self.base_ring().one()}) - elif is_MPolynomial(x): + elif isinstance(x, MPolynomial): return symmetrica.t_POLYNOM_SCHUBERT(x) - elif isinstance(x, InfinitePolynomial_sparse): + elif isinstance(x, InfinitePolynomial): R = x.polynomial().parent() # massage the term order to be what symmetrica expects S = PolynomialRing(R.base_ring(), diff --git a/src/sage/combinat/set_partition.py b/src/sage/combinat/set_partition.py index e4eb46f5d40..4fda6338b57 100644 --- a/src/sage/combinat/set_partition.py +++ b/src/sage/combinat/set_partition.py @@ -30,30 +30,31 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +import itertools from itertools import repeat from sage.sets.set import Set, Set_generic -import itertools - from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.list_clone import ClonableArray from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.misc.lazy_import import lazy_import from sage.rings.infinity import infinity from sage.rings.integer import Integer from sage.combinat.combinatorial_map import combinatorial_map -from sage.combinat.combinat_cython import (set_partition_iterator, - set_partition_iterator_blocks) +from sage.combinat.set_partition_iterator import (set_partition_iterator, + set_partition_iterator_blocks) from sage.combinat.partition import Partition, Partitions -from sage.combinat.combinat import bell_number, stirling_number2 +from sage.combinat.combinat import bell_number, stirling_number2 as stirling2 from sage.combinat.permutation import Permutation from sage.arith.misc import factorial from sage.misc.prandom import random, randint, sample -from sage.probability.probability_distribution import GeneralDiscreteDistribution from sage.sets.disjoint_set import DisjointSet -from sage.combinat.posets.hasse_diagram import HasseDiagram + +lazy_import('sage.combinat.posets.hasse_diagram', 'HasseDiagram') +lazy_import('sage.probability.probability_distribution', 'GeneralDiscreteDistribution') class AbstractSetPartition(ClonableArray, @@ -117,7 +118,6 @@ def __eq__(self, y): sage: p2 = SetPartition([[b], [a]]) sage: p1 == p2 False - """ if not isinstance(y, AbstractSetPartition): return False @@ -405,7 +405,7 @@ def base_set(self): sage: SetPartition([]).base_set() {} """ - return Set([e for p in self for e in p]) + return Set(e for p in self for e in p) def base_set_cardinality(self): """ @@ -455,7 +455,7 @@ def union(s): for part in s: cur = [] for i in part: - cur.extend(self[i-1]) # -1 for indexing + cur.extend(self[i - 1]) # -1 for indexing ret.append(cur) return ret return [self.parent()(union(s)) for s in SP] @@ -490,7 +490,7 @@ def conjugate(self): OUTPUT: - - a set partition + a set partition EXAMPLES:: @@ -501,13 +501,13 @@ def conjugate(self): sage: SetPartition([]).conjugate() {} """ - def next(a, support): - return support[(support.index(a)+1) % len(support)] + def next_one(a, support): + return support[(support.index(a) + 1) % len(support)] def addback(S, terminals, rsupport): out = list(S) - for a in terminals*2: - if a not in out and next(a, rsupport) in out: + for a in terminals * 2: + if a not in out and next_one(a, rsupport) in out: out.append(a) return out @@ -517,18 +517,18 @@ def pre_conjugate(sp): if sp.max_block_size() == 1: return SetPartition([sp.base_set()]) support = sorted(a for S in sp for a in S) - initials = [a for S in sp for a in S if next(a,support) in S] + initials = [a for S in sp for a in S if next_one(a, support) in S] singletons = [a for S in sp for a in S if len(S) == 1] if not initials and not singletons: return sp rho = pre_conjugate( SetPartition([[a for a in S if a not in initials] - for S in sp if len(S)>1 and any(a not in initials for a in S)])) + for S in sp if len(S) > 1 and any(a not in initials for a in S)])) # add back initials as singletons and singletons as terminals return SetPartition([addback(S, singletons, support[::-1]) - for S in rho]+[[a] for a in initials]) + for S in rho] + [[a] for a in initials]) support = sorted(a for S in self for a in S) - return SetPartition([[support[-support.index(a)-1] for a in S] + return SetPartition([[support[-support.index(a) - 1] for a in S] for S in pre_conjugate(self)]) @@ -619,7 +619,6 @@ def __init__(self, parent, s, check=True): sage: TestSuite(s).run() sage: SetPartition([]) {} - """ self._latex_options = {} ClonableArray.__init__(self, parent, sorted(map(frozenset, s), key=min), check=check) @@ -687,22 +686,20 @@ def set_latex_options(self, **kwargs): 'radius': '1cm', 'show_labels': True, 'tikz_scale': 2} - """ valid_args = ['tikz_scale', 'plot', 'color', 'fill', 'show_labels', 'radius', 'angle'] for key in kwargs: if key not in valid_args: - raise ValueError("unknown keyword argument: %s"%key) + raise ValueError(f"unknown keyword argument: {key}") if key == 'plot': if not (kwargs['plot'] == 'cyclic' or kwargs['plot'] == 'linear' or kwargs['plot'] is None): raise ValueError("plot must be None, 'cyclic', or 'linear'") - for opt in kwargs: - self._latex_options[opt] = kwargs[opt] + self._latex_options.update(kwargs) def latex_options(self): r""" @@ -789,7 +786,7 @@ def _latex_(self): """ latex_options = self.latex_options() if latex_options["plot"] is None: - return repr(self).replace("{",r"\{").replace("}",r"\}") + return repr(self).replace("{", r"\{").replace("}", r"\}") from sage.misc.latex import latex latex.add_package_to_preamble_if_available("tikz") @@ -812,7 +809,7 @@ def _latex_(self): res += "\\draw (0,0) circle [radius={}];\n".format(radius) # Add nodes - for k,i in enumerate(base_set): + for k, i in enumerate(base_set): location = (cardinality - k) * degrees - 270 if latex_options['show_labels']: res += "\\node[label={}:{}]".format(location, i) @@ -822,7 +819,7 @@ def _latex_(self): # Setup partitions for partition in sorted(self, key=str): - res += "\\draw[-,thick,color="+color + res += "\\draw[-,thick,color=" + color if latex_options['fill'] is not False: if isinstance(latex_options['fill'], str): res += ",fill=" + latex_options['fill'] @@ -841,7 +838,7 @@ def _latex_(self): elif latex_options['plot'] == 'linear': angle = latex_options['angle'] # setup line - for k,i in enumerate(base_set): + for k, i in enumerate(base_set): if latex_options['show_labels']: res += "\\node[below=.05cm] at ({},0) {{${}$}};\n".format(k, i) res += "\\node[draw,circle, inner sep=0pt, minimum width=4pt, fill=black] " @@ -854,8 +851,8 @@ def _latex_(self): continue for k in range(1, len(p)): res += "\\draw[color={}] ({})".format(color, base_set.index(p[k])) - res += " to [out={},in={}] ".format(90+angle, 90-angle) - res += "({});\n".format(base_set.index(p[k-1])) + res += " to [out={},in={}] ".format(90 + angle, 90 - angle) + res += "({});\n".format(base_set.index(p[k - 1])) else: raise ValueError("plot must be None, 'cyclic', or 'linear'") @@ -904,7 +901,7 @@ def pipe(self, other): parts = list(self) n = self.base_set_cardinality() for newpart in other: - raised_newpart = Set([i + n for i in newpart]) + raised_newpart = Set(i + n for i in newpart) parts.append(raised_newpart) return SetPartition(parts) @@ -944,9 +941,8 @@ def to_permutation(self): sage: s = SetPartition([[1,3],[2,4]]) sage: s.to_permutation() [3, 4, 1, 2] - """ - return Permutation(tuple( map(tuple, self.standard_form()) )) + return Permutation(tuple(map(tuple, self.standard_form()))) def to_restricted_growth_word(self, bijection="blocks"): r""" @@ -1002,14 +998,12 @@ def to_restricted_growth_word(self, bijection="blocks"): sage: S = SetPartitions(5, 2) sage: all(S.from_restricted_growth_word(P.to_restricted_growth_word("intertwining"), "intertwining") == P for P in S) True - """ if bijection == "blocks": return self.to_restricted_growth_word_blocks() - elif bijection == "intertwining": + if bijection == "intertwining": return self.to_restricted_growth_word_intertwining() - else: - raise ValueError("The given bijection is not valid.") + raise ValueError("the given bijection is not valid") def to_restricted_growth_word_blocks(self): r""" @@ -1023,7 +1017,7 @@ def to_restricted_growth_word_blocks(self): OUTPUT: - - a restricted growth word. + a restricted growth word. .. SEEALSO:: @@ -1035,13 +1029,12 @@ def to_restricted_growth_word_blocks(self): sage: P = SetPartition([[1,4],[2,8],[3,5,6,9],[7]]) sage: P.to_restricted_growth_word_blocks() [0, 1, 2, 0, 2, 2, 3, 1, 2] - """ w = [0] * self.size() # we can assume that the blocks are sorted by minimal element for i, B in enumerate(self): for j in B: - w[j-1] = i + w[j - 1] = i return w def to_restricted_growth_word_intertwining(self): @@ -1057,7 +1050,7 @@ def to_restricted_growth_word_intertwining(self): OUTPUT: - - a restricted growth word. + a restricted growth word. .. SEEALSO:: @@ -1069,16 +1062,15 @@ def to_restricted_growth_word_intertwining(self): sage: P = SetPartition([[1,4],[2,8],[3,5,6,9],[7]]) sage: P.to_restricted_growth_word_intertwining() [0, 1, 2, 2, 1, 0, 3, 3, 2] - """ A = sorted(self.arcs()) - O = [min(B) for B in self] # openers - C = [max(B) for B in self] # closers - I = [0]*self.size() + O = (min(B) for B in self) # openers + C = [max(B) for B in self] # closers + I = [0] * self.size() for i in O: - I[i-1] = sum(1 for k,l in A if k < i < l) + sum(1 for k in C if k < i) - for (i,j) in A: - I[j-1] = sum(1 for k,l in A if i < k < j < l) + sum(1 for k in C if i < k < j) + I[i - 1] = sum(1 for k, l in A if k < i < l) + sum(1 for k in C if k < i) + for i, j in A: + I[j - 1] = sum(1 for k, l in A if i < k < j < l) + sum(1 for k in C if i < k < j) return I def openers(self): @@ -1139,18 +1131,16 @@ def to_rook_placement(self, bijection="arcs"): [(1, 2), (2, 6), (3, 4), (4, 10), (5, 9), (6, 7), (10, 11), (11, 13)] sage: P.to_rook_placement("psi") [(1, 2), (2, 6), (3, 4), (5, 9), (6, 7), (7, 10), (9, 11), (11, 13)] - """ if bijection == "arcs": return self.arcs() - elif bijection == "gamma": + if bijection == "gamma": return self.to_rook_placement_gamma() - elif bijection == "rho": + if bijection == "rho": return self.to_rook_placement_rho() - elif bijection == "psi": + if bijection == "psi": return self.to_rook_placement_psi() - else: - raise ValueError("The given map is not valid.") + raise ValueError("the given map is not valid") def to_rook_placement_gamma(self): """ @@ -1199,17 +1189,16 @@ def to_rook_placement_gamma(self): sage: S = SetPartitions(5, 2) sage: all(S.from_rook_placement(P.to_rook_placement("gamma"), "gamma") == P for P in S) True - """ n = self.size() if n == 0: return [] w = self.to_restricted_growth_word_blocks() # the set of openers - leftmost occurrences of a letter in w - EC = sorted([w.index(i) for i in range(max(w)+1)]) - rooks = [] # pairs (row i, column j) - R = [] # attacked rows - for c in range(n): # columns from left to right + EC = sorted([w.index(i) for i in range(max(w) + 1)]) + rooks = [] # pairs (row i, column j) + R = [] # attacked rows + for c in range(n): # columns from left to right if c not in EC: r = 0 w_c = w[c] @@ -1217,7 +1206,7 @@ def to_rook_placement_gamma(self): if r not in R: w_c -= 1 r += 1 - rooks.append((n-c, n-r)) + rooks.append((n - c, n - r)) R.append(r) return sorted(rooks) @@ -1281,7 +1270,6 @@ def to_rook_placement_rho(self): sage: S = SetPartitions(5, 2) sage: all(S.from_rook_placement(P.to_rook_placement("rho"), "rho") == P for P in S) True - """ n = self.size() if n == 0: @@ -1289,17 +1277,17 @@ def to_rook_placement_rho(self): w = self.to_restricted_growth_word_blocks() w_rev = w[::-1] # the set of closers - rightmost occurrences of a letter in w - R = sorted([n-w_rev.index(i)-1 for i in range(max(w)+1)]) + R = sorted([n - w_rev.index(i) - 1 for i in range(max(w) + 1)]) # the number of closers which are larger than i and whose # block is before the block of i rs = [sum(1 for j in R if j > i and w[j] < w[i]) for i in range(n)] - EC = [n-j for j in R] # empty columns - rooks = [] # pairs (row i, column j) - for i in range(1,n): - U = [j for j in range(n+1-i, n+1) if j not in EC] + EC = [n - j for j in R] # empty columns + rooks = [] # pairs (row i, column j) + for i in range(1, n): + U = [j for j in range(n + 1 - i, n + 1) if j not in EC] if rs[i] < len(U): j = U[rs[i]] - rooks.append((n+1-j, i+1)) + rooks.append((n + 1 - j, i + 1)) EC.append(j) return sorted(rooks) @@ -1337,7 +1325,6 @@ def to_rook_placement_psi(self): sage: S = SetPartitions(5,2) sage: all(S.from_rook_placement(P.to_rook_placement("psi"), "psi") == P for P in S) True - """ # Yip draws the diagram as an upper triangular matrix, thus # we refer to the cell in row i and column j with (i, j) @@ -1355,7 +1342,7 @@ def to_rook_placement_psi(self): P = sorted(P, key=lambda B: (-len(B), min(B))) b = P.index(B) i = j - b - 1 - degrees.append((j,i)) + degrees.append((j, i)) # reconstruct rooks from degree sequence rooks = [] attacked_rows = [] @@ -1364,7 +1351,7 @@ def to_rook_placement_psi(self): while d > i + sum(1 for r in attacked_rows if r > i): i += 1 attacked_rows.append(i) - rooks.append((i,j)) + rooks.append((i, j)) return sorted(rooks) def apply_permutation(self, p): @@ -1418,11 +1405,11 @@ def crossings_iterator(self): # each arc is sorted, but the set of arcs might not be arcs = sorted(self.arcs(), key=min) while arcs: - i1,j1 = arcs.pop(0) - for i2,j2 in arcs: + i1, j1 = arcs.pop(0) + for i2, j2 in arcs: # we know that i1 < i2 and i1 < j1 and i2 < j2 if i2 < j1 < j2: - yield ((i1,j1), (i2,j2)) + yield ((i1, j1), (i2, j2)) def crossings(self): r""" @@ -1472,9 +1459,9 @@ def number_of_crossings(self): sage: n.number_of_crossings() 1 """ - return Integer( len(list(self.crossings_iterator())) ) + return Integer(len(list(self.crossings_iterator()))) - def is_noncrossing(self): + def is_noncrossing(self) -> bool: r""" Check if ``self`` is noncrossing. @@ -1535,11 +1522,11 @@ def nestings_iterator(self): # each arc is sorted, but the set of arcs might not be arcs = sorted(self.arcs(), key=min) while arcs: - i1,j1 = arcs.pop(0) - for i2,j2 in arcs: + i1, j1 = arcs.pop(0) + for i2, j2 in arcs: # we know that i1 < i2 and i1 < j1 and i2 < j2 if i2 < j2 < j1: - yield ((i1,j1), (i2,j2)) + yield ((i1, j1), (i2, j2)) def nestings(self): r""" @@ -1596,7 +1583,7 @@ def number_of_nestings(self): c += one return c - def is_nonnesting(self): + def is_nonnesting(self) -> bool: r""" Return if ``self`` is nonnesting or not. @@ -1624,7 +1611,7 @@ def is_nonnesting(self): return True return False - def is_atomic(self): + def is_atomic(self) -> bool: r""" Return if ``self`` is an atomic set partition. @@ -1682,7 +1669,7 @@ def standardization(self): sage: SetPartition([('c','b'),('d','f'),('e','a')]).standardization() {{1, 5}, {2, 3}, {4, 6}} """ - r = {e: i for i,e in enumerate(sorted(self.base_set()), 1)} + r = {e: i for i, e in enumerate(sorted(self.base_set()), 1)} return SetPartitions(len(r))([[r[e] for e in b] for b in self]) def restriction(self, I): @@ -1782,7 +1769,7 @@ def ordered_set_partition_action(self, s): cur = 1 ret = [] for part in s: - sub_parts = [list(self[i-1]) for i in part] # -1 for indexing + sub_parts = [list(self[i - 1]) for i in part] # -1 for indexing # Standardizing sub_parts (the cur variable not being reset # to 1 gives us the offset we want): mins = [min(i) for i in sub_parts] @@ -1854,16 +1841,16 @@ def strict_coarsenings(self): while todo: A = todo.pop() for i, part in enumerate(A): - for j, other in enumerate(A[i+1:]): + for j, other in enumerate(A[i + 1:]): if max(part) < min(other): - next = A[:i] - next.append(part.union(other)) - next += A[i+1:i+1+j] + A[i+j+2:] - next = SetPartition(next) - if next not in visited: - todo.append(next) - visited.add(next) - ret.append(next) + next_pi = A[:i] + next_pi.append(part.union(other)) + next_pi += A[i + 1:i + 1 + j] + A[i + j + 2:] + next_pi = SetPartition(next_pi) + if next_pi not in visited: + todo.append(next_pi) + visited.add(next_pi) + ret.append(next_pi) return ret def arcs(self): @@ -1885,8 +1872,8 @@ def arcs(self): arcs = [] for p in self: p = sorted(p) - for i in range(len(p)-1): - arcs.append((p[i], p[i+1])) + for i in range(len(p) - 1): + arcs.append((p[i], p[i + 1])) return arcs def plot(self, angle=None, color='black', base_set_dict=None): @@ -1906,7 +1893,7 @@ def plot(self, angle=None, color='black', base_set_dict=None): EXAMPLES:: sage: p = SetPartition([[1,10,11],[2,3,7],[4,5,6],[8,9]]) - sage: p.plot() + sage: p.plot() # optional - sage.plot sage.symbolic Graphics object consisting of 29 graphics primitives .. PLOT:: @@ -1917,7 +1904,7 @@ def plot(self, angle=None, color='black', base_set_dict=None): :: sage: p = SetPartition([[1,3,4],[2,5]]) - sage: print(p.plot().description()) + sage: print(p.plot().description()) # optional - sage.plot sage.symbolic Point set defined by 1 point(s): [(0.0, 0.0)] Point set defined by 1 point(s): [(1.0, 0.0)] Point set defined by 1 point(s): [(2.0, 0.0)] @@ -1935,7 +1922,7 @@ def plot(self, angle=None, color='black', base_set_dict=None): Arc with center (2.5,-1.5) radii (2.1213203435...,2.1213203435...) angle 0.0 inside the sector (0.785398163397...,2.35619449019...) sage: p = SetPartition([['a','c'],['b','d'],['e']]) - sage: print(p.plot().description()) + sage: print(p.plot().description()) # optional - sage.plot sage.symbolic Point set defined by 1 point(s): [(0.0, 0.0)] Point set defined by 1 point(s): [(1.0, 0.0)] Point set defined by 1 point(s): [(2.0, 0.0)] @@ -1951,7 +1938,8 @@ def plot(self, angle=None, color='black', base_set_dict=None): Arc with center (2.0,-1.0) radii (1.41421356237...,1.41421356237...) angle 0.0 inside the sector (0.785398163397...,2.35619449019...) sage: p = SetPartition([['a','c'],['b','d'],['e']]) - sage: print(p.plot(base_set_dict={'a':0,'b':1,'c':2,'d':-2.3,'e':5.4}).description()) + sage: print(p.plot(base_set_dict={'a':0,'b':1,'c':2, # optional - sage.plot sage.symbolic + ....: 'd':-2.3,'e':5.4}).description()) Point set defined by 1 point(s): [(-2.3, 0.0)] Point set defined by 1 point(s): [(0.0, 0.0)] Point set defined by 1 point(s): [(1.0, 0.0)] @@ -1985,19 +1973,21 @@ def plot(self, angle=None, color='black', base_set_dict=None): if base_set_dict is not None: vertices_dict = base_set_dict else: - vertices_dict = {val: pos for pos,val in enumerate(sorted_vertices_list)} + vertices_dict = {val: pos for pos, val in enumerate(sorted_vertices_list)} for elt in vertices_dict: pos = vertices_dict[elt] - diag += point((pos,0), size=30, color=color) - diag += text(elt, (pos, -sgn(angle)*0.1), color=color) + diag += point((pos, 0), size=30, color=color) + diag += text(elt, (pos, -sgn(angle) * 0.1), color=color) # TODO: change 0.1 to something proportional to the height of the picture - for (k,j) in self.arcs(): - pos_k,pos_j = float(vertices_dict[k]),float(vertices_dict[j]) - center = ((pos_k+pos_j) / 2, -abs(pos_j-pos_k) / (2*tan(angle))) - r1 = abs((pos_j-pos_k) / (2*sin(angle))) - sector = (sgn(angle) * (pi/2 - angle), sgn(angle) * (pi/2 + angle)) + for k, j in self.arcs(): + pos_k, pos_j = float(vertices_dict[k]), float(vertices_dict[j]) + center = ((pos_k + pos_j) / 2, + -abs(pos_j - pos_k) / (2 * tan(angle))) + r1 = abs((pos_j - pos_k) / (2 * sin(angle))) + sector = (sgn(angle) * (pi / 2 - angle), + sgn(angle) * (pi / 2 + angle)) diag += arc(center=center, r1=r1, sector=sector, color=color) diag.axes(False) @@ -2062,11 +2052,11 @@ def __classcall_private__(cls, s=None, part=None): if s is None: return SetPartitions_all() if isinstance(s, (int, Integer)): - s = frozenset(range(1, s+1)) + s = frozenset(range(1, s + 1)) else: try: if s.cardinality() == infinity: - raise ValueError("The set must be finite") + raise ValueError("the set must be finite") except AttributeError: pass s = frozenset(s) @@ -2079,7 +2069,7 @@ def __classcall_private__(cls, s=None, part=None): else: part = sorted(part, reverse=True) if part not in Partitions(len(s)): - raise ValueError("part must be an integer partition of %s"%len(s)) + raise ValueError("part must be an integer partition of %s" % len(s)) return SetPartitions_setparts(s, Partition(part)) else: return SetPartitions_set(s) @@ -2104,7 +2094,7 @@ def __contains__(self, x): return False # Check that all parts are disjoint - base_set = set([e for p in x for e in p]) + base_set = set(e for p in x for e in p) if len(base_set) != sum(map(len, x)): return False @@ -2138,7 +2128,7 @@ def _element_constructor_(self, s, check=True): if isinstance(s, SetPartition): if isinstance(s.parent(), SetPartitions): return self.element_class(self, s, check=check) - raise ValueError("cannot convert %s into an element of %s"%(s, self)) + raise ValueError("cannot convert %s into an element of %s" % (s, self)) return self.element_class(self, s, check=check) Element = SetPartition @@ -2179,14 +2169,12 @@ def from_restricted_growth_word(self, w, bijection="blocks"): sage: SetPartitions().from_restricted_growth_word([0, 0, 1, 0, 2, 2, 0, 3, 1, 2, 2, 4, 2], "intertwining") {{1, 2, 6, 7, 9}, {3, 4}, {5, 10, 13}, {8, 11}, {12}} - """ if bijection == "blocks": return self.from_restricted_growth_word_blocks(w) - elif bijection == "intertwining": + if bijection == "intertwining": return self.from_restricted_growth_word_intertwining(w) - else: - raise ValueError("The given bijection is not valid.") + raise ValueError("the given bijection is not valid") def from_restricted_growth_word_blocks(self, w): r""" @@ -2214,7 +2202,6 @@ def from_restricted_growth_word_blocks(self, w): sage: SetPartitions().from_restricted_growth_word_blocks([0, 0, 1, 0, 2, 2, 0, 3, 1, 2, 2, 4, 2]) {{1, 2, 4, 7}, {3, 9}, {5, 6, 10, 11, 13}, {8}, {12}} - """ R = [] for i, B in enumerate(w, 1): @@ -2252,24 +2239,23 @@ def from_restricted_growth_word_intertwining(self, w): sage: SetPartitions().from_restricted_growth_word_intertwining([0, 0, 1, 0, 2, 2, 0, 3, 1, 2, 2, 4, 2]) {{1, 2, 6, 7, 9}, {3, 4}, {5, 10, 13}, {8, 11}, {12}} - """ if len(w) == 0: return self.element_class(self, []) R = [[1]] - C = [1] # closers, always reverse sorted - m = 0 # max - for i in range(1,len(w)): - if w[i] == 1 + m: # i+1 is an opener + C = [1] # closers, always reverse sorted + m = 0 # max + for i in range(1, len(w)): + if w[i] == 1 + m: # i+1 is an opener m += 1 - R.append([i+1]) + R.append([i + 1]) else: # add i+1 to the block, such that there are I[i] closers thereafter l = C[w[i]] B = next(B for B in R if l in B) - B.append(i+1) + B.append(i + 1) C.remove(l) - C = [i+1] + C + C = [i + 1] + C return self.element_class(self, R) def from_rook_placement(self, rooks, bijection="arcs", n=None): @@ -2326,27 +2312,22 @@ def from_rook_placement(self, rooks, bijection="arcs", n=None): {{1}, {2}} sage: SetPartitions().from_rook_placement([], "psi", 2) {{1}, {2}} - """ if n is None: try: n = self.base_set_cardinality() except AttributeError: - if len(rooks) == 0: - n = 0 - else: - n = max(max(r) for r in rooks) + n = max((max(r) for r in rooks), default=0) if bijection == "arcs": return self.from_arcs(rooks, n) - elif bijection == "rho": + if bijection == "rho": return self.from_rook_placement_rho(rooks, n) - elif bijection == "gamma": + if bijection == "gamma": return self.from_rook_placement_gamma(rooks, n) - elif bijection == "psi": + if bijection == "psi": return self.from_rook_placement_psi(rooks, n) - else: - raise ValueError("The given bijection is not valid.") + raise ValueError("the given bijection is not valid") def from_arcs(self, arcs, n): r""" @@ -2372,9 +2353,9 @@ def from_arcs(self, arcs, n): sage: SetPartitions().from_arcs([(2,3)], 5) {{1}, {2, 3}, {4}, {5}} """ - P = DisjointSet(range(1,n+1)) - for i,j in arcs: - P.union(i,j) + P = DisjointSet(range(1, n + 1)) + for i, j in arcs: + P.union(i, j) return self.element_class(self, P) def from_rook_placement_gamma(self, rooks, n): @@ -2418,19 +2399,18 @@ def from_rook_placement_gamma(self, rooks, n): sage: SetPartitions().from_rook_placement_gamma(r, 13) {{1, 2, 4, 7}, {3, 9}, {5, 6, 10, 11, 13}, {8}, {12}} - """ if n == 0: return self.element_class(self, []) # the columns of the board, beginning with column n-1 - C = [set(range(n+1-j, n+1)) for j in range(1,n)] + C = [set(range(n + 1 - j, n + 1)) for j in range(1, n)] # delete cells north and east of each rook - for (j,i) in rooks: + for j, i in rooks: # north - C[n-j-1].difference_update(range(j+1, i+1)) + C[n - j - 1].difference_update(range(j + 1, i + 1)) # east - for l in range(n+1-j, n+1): - C[l-2].discard(i) + for l in range(n + 1 - j, n + 1): + C[l - 2].discard(i) w = [0] + [len(c) for c in C] return self.from_restricted_growth_word_blocks(w) @@ -2478,24 +2458,25 @@ def from_rook_placement_rho(self, rooks, n): """ # the closers correspond to the empty columns cols = [j for j, _ in rooks] - R = [j for j in range(1,n+1) if j not in cols] + R = [j for j in range(1, n + 1) if j not in cols] # the columns of the board, beginning with column n-1 - C = [set(range(n+1-j, n+1)) if n-j not in R else set() for j in range(1,n)] - for (j,i) in rooks: # column j from right, row i from top + C = [set(range(n + 1 - j, n + 1)) if n - j not in R else set() + for j in range(1, n)] + for j, i in rooks: # column j from right, row i from top # south - C[n-j-1].difference_update(range(i, n+1)) + C[n - j - 1].difference_update(range(i, n + 1)) # east - for l in range(n+1-j, n+1): - C[l-2].discard(i) + for l in range(n + 1 - j, n + 1): + C[l - 2].discard(i) C_flat = [i for c in C for i in c] # the number of closers which are larger than i and whose # block is before the block of i - rs = [C_flat.count(i) for i in range(1,n+1)] + rs = [C_flat.count(i) for i in range(1, n + 1)] # create the blocks P = [[] for _ in R] - for i in range(1, n+1): - k = rs[i-1] + for i in range(1, n + 1): + k = rs[i - 1] # find k-th block which does not yet have a closer b = 0 while k > 0 or (P[b] and P[b][-1] in R): @@ -2536,31 +2517,30 @@ def from_rook_placement_psi(self, rooks, n): sage: r = [(4,5), (1,7), (3, 8), (7,9)] sage: SetPartitions().from_rook_placement_psi(r, 9) {{1, 5}, {2}, {3, 8, 9}, {4}, {6, 7}} - """ # Yip draws the diagram as an upper triangular matrix, thus # we refer to the cell in row i and column j with (i, j) P = [] rooks_by_column = {j: i for (i, j) in rooks} - for c in range(1, n+1): + for c in range(1, n + 1): # determine the weight of column c try: r = rooks_by_column[c] n_rooks = 1 - ne = r-1 + sum(1 for i,j in rooks if i > r and j < c) + ne = r - 1 + sum(1 for i, j in rooks if i > r and j < c) except KeyError: n_rooks = 0 - ne = sum(1 for i,j in rooks if j < c) + ne = sum(1 for i, j in rooks if j < c) b = c - n_rooks - ne - if len(P) == b-1: + if len(P) == b - 1: P.append([c]) else: - P[b-1].append(c) + P[b - 1].append(c) P = sorted(P, key=lambda B: (-len(B), min(B))) return self.element_class(self, P) - def is_less_than(self, s, t): + def is_less_than(self, s, t) -> bool: r""" Check if `s < t` in the refinement ordering on set partitions. @@ -2609,7 +2589,7 @@ def is_less_than(self, s, t): lt = is_less_than - def is_strict_refinement(self, s, t): + def is_strict_refinement(self, s, t) -> bool: r""" Return ``True`` if ``s`` is a strict refinement of ``t`` and satisfies `s \neq t`. @@ -2653,9 +2633,10 @@ def is_strict_refinement(self, s, t): return False for p in t: - L = [x for x in list(s) if x.issubset(p)] + L = [x for x in s if x.issubset(p)] if sum(len(x) for x in L) != len(p) \ - or any(max(L[i]) > min(L[i+1]) for i in range(len(L)-1)): + or any(max(L[i]) > min(L[i + 1]) + for i in range(len(L) - 1)): return False return True @@ -2715,7 +2696,7 @@ def __iter__(self): """ n = 0 while True: - for x in SetPartitions_set(frozenset(range(1, n+1))): + for x in SetPartitions_set(frozenset(range(1, n + 1))): yield self.element_class(self, list(x)) n += 1 @@ -2762,7 +2743,7 @@ def _repr_(self): sage: SetPartitions([1,2,3]) Set partitions of {1, 2, 3} """ - return "Set partitions of %s"%(Set(self._set)) + return "Set partitions of %s" % (Set(self._set)) def __contains__(self, x): """ @@ -2787,10 +2768,7 @@ def __contains__(self, x): return False # Make sure that the union of all the sets is the original set - if Set([e for p in x for e in p]) != Set(self._set): - return False - - return True + return Set(e for p in x for e in p) == Set(self._set) def random_element(self): r""" @@ -2816,13 +2794,13 @@ def random_element(self): base_set = list(self.base_set()) N = len(base_set) from sage.symbolic.constants import e - c = float(e)*bell_number(N) + c = float(e) * bell_number(N) # it would be much better to generate M in the way Knuth # recommends, the following is a waste - G = GeneralDiscreteDistribution([float(m)**N/(c*factorial(m)) for m in range(4*N)]) - M = G.get_random_element()-1 - l = [randint(0, M) for i in range(N)] - p = dict() + G = GeneralDiscreteDistribution([float(m)**N / (c * factorial(m)) for m in range(4 * N)]) + M = G.get_random_element() - 1 + l = (randint(0, M) for i in range(N)) + p = {} for i, b in enumerate(l): if b in p: p[b].append(base_set[i]) @@ -2939,24 +2917,7 @@ def _repr_(self): sage: SetPartitions(4, [2,2]) Set partitions of {1, 2, 3, 4} with sizes in [2, 2] """ - return "Set partitions of %s with sizes in %s"%(Set(self._set), self._parts) - - @property - def parts(self): - r""" - ``self.parts`` is deprecated; use :meth:`shape` instead. - - TESTS:: - - sage: SetPartitions(5, [2,2,1]).parts - doctest:...: DeprecationWarning: The attribute parts for the partition of block sizes is deprecated, use the method shape instead. - See https://github.com/sagemath/sage/issues/25865 for details. - [2, 2, 1] - """ - from sage.misc.superseded import deprecation - deprecation(25865, "The attribute parts for the partition of block sizes is deprecated," - " use the method shape instead.") - return self.shape() + return "Set partitions of %s with sizes in %s" % (Set(self._set), self._parts) def shape(self): r""" @@ -3031,10 +2992,9 @@ def _set_partition_poset(self): ....: len(list(SetPartitions(n, mu)._set_partition_poset().linear_extensions())) ....: for mu in Partitions(n)) True - """ c = self._parts.to_exp_dict() - covers = dict() + covers = {} i = 0 for s in sorted(c): # s is the block size @@ -3048,11 +3008,11 @@ def _set_partition_poset(self): if s == 1: covers[i] = [] else: - for j in range(s-1): - covers[i] = [i+1] + for _ in range(s - 1): + covers[i] = [i + 1] i += 1 i += 1 - if m < c[s]-1: + if m < c[s] - 1: covers[first].append(i) return HasseDiagram(covers) @@ -3074,7 +3034,6 @@ def __iter__(self): sage: n = 8 sage: all(SetPartitions(n, mu).cardinality() == len(list(SetPartitions(n, mu))) for mu in Partitions(n)) True - """ # Ruskey, Combinatorial Generation, sec. 5.10.1 and Knuth TAOCP 4A 7.2.1.5, Exercise 6 k = len(self._parts) @@ -3090,10 +3049,11 @@ def __iter__(self): sums.append(sums[-1] + b) for ext in P.linear_extensions(): - pi = [None]*n + pi = [None] * n for i in range(n): pi[ext[i]] = s[i] - sp = [[pi[j] for j in range(sums[i], sums[i+1])] for i in range(k)] + sp = [[pi[j] for j in range(sums[i], sums[i + 1])] + for i in range(k)] yield self.element_class(self, sp, check=False) def __contains__(self, x): @@ -3190,24 +3150,7 @@ def _repr_(self): sage: SetPartitions(5, 3) Set partitions of {1, 2, 3, 4, 5} with 3 parts """ - return "Set partitions of %s with %s parts"%(Set(self._set), self._k) - - @property - def n(self): - r""" - ``self.n`` is deprecated; use :meth:`number_of_blocks` instead. - - TESTS:: - - sage: SetPartitions(5, 3).n - doctest:...: DeprecationWarning: The attribute n for the number of blocks is deprecated, use the method number_of_blocks instead. - See https://github.com/sagemath/sage/issues/25462 for details. - 3 - """ - from sage.misc.superseded import deprecation - deprecation(25462, "The attribute n for the number of blocks is deprecated," - " use the method number_of_blocks instead.") - return self.number_of_blocks() + return "Set partitions of %s with %s parts" % (Set(self._set), self._k) def number_of_blocks(self): r""" @@ -3232,7 +3175,7 @@ def cardinality(self): sage: stirling_number2(5,3) 25 """ - return stirling_number2(len(self._set), self._k) + return stirling2(len(self._set), self._k) def __iter__(self): """ @@ -3296,14 +3239,14 @@ def random_element(self): def re(N, k): if N == 0: return [[]] - elif N == 1: + if N == 1: return [[0]] - elif float(stirling_number2(N-1, k-1))/float(stirling_number2(N, k)) > random(): - return [[N-1]] + re(N-1, k-1) - else: - p = re(N-1, k) - p[randint(0, len(p)-1)].append(N-1) - return p + if stirling2(N - 1, k - 1) > random() * stirling2(N, k): + return [[N - 1]] + re(N - 1, k - 1) + + p = re(N - 1, k) + p[randint(0, len(p) - 1)].append(N - 1) + return p base_set = list(self.base_set()) N = len(base_set) diff --git a/src/sage/combinat/set_partition_iterator.pyx b/src/sage/combinat/set_partition_iterator.pyx new file mode 100644 index 00000000000..fff6a71fefe --- /dev/null +++ b/src/sage/combinat/set_partition_iterator.pyx @@ -0,0 +1,130 @@ +# cython: binding=True +r""" +Fast set partition iterators +""" +cimport cython + + +@cython.wraparound(False) +@cython.boundscheck(False) +cdef list from_word(list w, list base_set): + cdef list sp = [] + cdef Py_ssize_t i + cdef Py_ssize_t b + for i in range(len(w)): + b = <Py_ssize_t> (w[i]) + x = base_set[i] + if len(sp) <= b: + sp.append([x]) + else: + sp[b].append(x) + return sp + +@cython.wraparound(False) +@cython.boundscheck(False) +def set_partition_iterator(base_set): + """ + A fast iterator for the set partitions of the base set, which + returns lists of lists instead of set partitions types. + + EXAMPLES:: + + sage: from sage.combinat.set_partition_iterator import set_partition_iterator + sage: list(set_partition_iterator([1,-1,x])) # optional - sage.symbolic + [[[1, -1, x]], + [[1, -1], [x]], + [[1, x], [-1]], + [[1], [-1, x]], + [[1], [-1], [x]]] + """ + cdef list base = list(base_set) + + # Knuth, TAOCP 4A 7.2.1.5, Algorithm H + cdef Py_ssize_t N = len(base) + # H1: initialize + cdef list a = [0] * N + if N <= 1: + yield from_word(a, base) + return + + cdef list b = [1] * N + cdef Py_ssize_t j + cdef Py_ssize_t last = N - 1 + while True: + # H2: visit + yield from_word(a, base) + if a[last] == b[last]: + # H4: find j + j = N - 2 + while a[j] == b[j]: + j -= 1 + # H5: increase a_j + if j == 0: + break + a[j] += 1 + # H6: zero out a_{j+1},...,a_{n-1} + b[last] = b[j] + int(a[j] == b[j]) + j += 1 + while j < N - 1: + a[j] = 0 + b[j] = b[last] + j += 1 + a[last] = 0 + else: + # H3: increase a_{n-1} + a[last] += 1 + +@cython.wraparound(False) +@cython.boundscheck(False) +def _set_partition_block_gen(Py_ssize_t n, Py_ssize_t k, list a): + r""" + Recursively generate set partitions of ``n`` with fixed block + size ``k`` using Algorithm 4.23 from [Rus2003]_. + ``a`` is a list of size ``n``. + + EXAMPLES:: + + sage: from sage.combinat.set_partition_iterator import _set_partition_block_gen + sage: a = list(range(3)) + sage: for p in _set_partition_block_gen(3, 2, a): + ....: print(p) + [0, 1, 0] + [0, 1, 1] + [0, 0, 1] + """ + cdef Py_ssize_t i + if n == k: + yield a + return + + for i in range(k): + a[n-1] = i + for P in _set_partition_block_gen(n-1, k, a): + yield P + a[n-1] = n-1 + if k > 1: + a[n-1] = k-1 + for P in _set_partition_block_gen(n-1, k-1, a): + yield P + a[n-1] = n-1 + +@cython.wraparound(False) +@cython.boundscheck(False) +def set_partition_iterator_blocks(base_set, Py_ssize_t k): + """ + A fast iterator for the set partitions of the base set into the + specified number of blocks, which returns lists of lists + instead of set partitions types. + + EXAMPLES:: + + sage: from sage.combinat.set_partition_iterator import set_partition_iterator_blocks + sage: list(set_partition_iterator_blocks([1,-1,x], 2)) # optional - sage.symbolic + [[[1, x], [-1]], [[1], [-1, x]], [[1, -1], [x]]] + """ + cdef list base = list(base_set) + cdef Py_ssize_t n = len(base) + cdef list a = list(range(n)) + # TODO: implement _set_partition_block_gen as an iterative algorithm + for P in _set_partition_block_gen(n, k, a): + yield from_word(<list> P, base) diff --git a/src/sage/combinat/set_partition_ordered.py b/src/sage/combinat/set_partition_ordered.py index 268126d65ef..186835f7129 100644 --- a/src/sage/combinat/set_partition_ordered.py +++ b/src/sage/combinat/set_partition_ordered.py @@ -24,8 +24,9 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.all import factorial, multinomial -from sage.categories.cartesian_product import cartesian_product +from itertools import product + +from sage.arith.misc import factorial, multinomial from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.combinat import stirling_number2 @@ -452,7 +453,7 @@ def finer(self): if not self: return FiniteEnumeratedSet([self]) return FiniteEnumeratedSet([par(sum((list(i) for i in C), [])) - for C in cartesian_product([OrderedSetPartitions(X) for X in self])]) + for C in product(*[OrderedSetPartitions(X) for X in self])]) def is_finer(self, co2): """ @@ -548,7 +549,7 @@ def fatten(self, grouping): result = [None] * len(grouping) j = 0 for i in range(len(grouping)): - result[i] = set().union(*self[j:j+grouping[i]]) + result[i] = set().union(*self[j:j + grouping[i]]) j += grouping[i] return parent(self)(result) @@ -636,7 +637,7 @@ def bottom_up_osp(X, comp): result = [None] * len(comp) j = 0 for i in range(len(comp)): - result[i] = set(xs[j:j+comp[i]]) + result[i] = set(xs[j:j + comp[i]]) j += comp[i] return OrderedSetPartitions(X)(result) @@ -671,7 +672,7 @@ def strongly_finer(self): return FiniteEnumeratedSet([self]) buo = OrderedSetPartition.bottom_up_osp return FiniteEnumeratedSet([par(sum((list(P) for P in C), [])) - for C in cartesian_product([[buo(X, comp) for comp in Compositions(len(X))] for X in self])]) + for C in product(*[[buo(X, comp) for comp in Compositions(len(X))] for X in self])]) def is_strongly_finer(self, co2): r""" @@ -779,7 +780,7 @@ def strongly_fatter(self): # arbitrarily, and then concatenate the results. fattenings = [list(subcomp.fatter()) for subcomp in subcomps] return FiniteEnumeratedSet([OrderedSetPartition(sum([list(gg) for gg in fattening], [])) - for fattening in cartesian_product(fattenings)]) + for fattening in product(*fattenings)]) @combinatorial_map(name='to packed word') def to_packed_word(self): @@ -1114,6 +1115,13 @@ def __iter__(self): [{1, 3}, {2}], [{2, 3}, {1}], [{1, 2, 3}]] + + TESTS: + + Test for :issue:`35654`:: + + sage: OrderedSetPartitions(set(),[0,0,0]).list() + [[{}, {}, {}]] """ for x in Compositions(len(self._set)): for z in OrderedSetPartitions(self._set, x): @@ -1379,11 +1387,18 @@ def multiset_permutation_next_lex(l): [2, 1, 0, 0, 1] [2, 1, 0, 1, 0] [2, 1, 1, 0, 0] + + TESTS: + + Test for :issue:`35654`:: + + sage: multiset_permutation_next_lex([]) + 0 """ i = len(l) - 2 while i >= 0 and l[i] >= l[i + 1]: i -= 1 - if i == -1: + if i <= -1: return 0 j = len(l) - 1 while l[j] <= l[i]: diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index c3b2ba786ce..eda80d2d1c3 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -27,11 +27,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.combinat.sf.sfa import SymmetricFunctionAlgebra_generic as SFA_generic -from sage.misc.cachefunc import cached_method +from sage.arith.misc import binomial, divisors, moebius from sage.categories.homset import Hom from sage.categories.morphism import SetMorphism -from sage.arith.all import divisors, moebius, binomial +from sage.combinat.sf.sfa import SymmetricFunctionAlgebra_generic as SFA_generic +from sage.misc.cachefunc import cached_method from sage.rings.integer import Integer diff --git a/src/sage/combinat/sf/classical.py b/src/sage/combinat/sf/classical.py index eda10b82730..73bf285c14f 100644 --- a/src/sage/combinat/sf/classical.py +++ b/src/sage/combinat/sf/classical.py @@ -17,8 +17,8 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from sage.rings.integer import Integer -from sage.rings.integer_ring import IntegerRing -from sage.rings.rational_field import RationalField +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.combinat.partition import _Partitions @@ -29,9 +29,6 @@ from . import jack from . import orthotriang -ZZ = IntegerRing() -QQ = RationalField() - translate = {'monomial':'MONOMIAL', 'homogeneous':'HOMSYM', 'powersum':'POWSYM', 'elementary':'ELMSYM', 'Schur':'SCHUR'} conversion_functions = {} @@ -305,7 +302,7 @@ def _element_constructor_(self, x): else: try: c = R(x) - except Exception: + except (TypeError, ValueError): raise TypeError("do not know how to make x (= {}) an element of self".format(x)) else: if not c: diff --git a/src/sage/combinat/sf/dual.py b/src/sage/combinat/sf/dual.py index 837dc57e0b7..90ed7f7ac8c 100644 --- a/src/sage/combinat/sf/dual.py +++ b/src/sage/combinat/sf/dual.py @@ -214,7 +214,7 @@ def _self_to_dual(self, x): sage: h._self_to_dual(h([2,1]) + 3*h[1,1,1]) 21*m[1, 1, 1] + 11*m[2, 1] + 4*m[3] - This is for internal use only. Please use instead: + This is for internal use only. Please use instead:: sage: m(h([2,1]) + 3*h[1,1,1]) 21*m[1, 1, 1] + 11*m[2, 1] + 4*m[3] diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 8ec26324de0..a7e5d9cf44c 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -17,12 +17,13 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** -from . import multiplicative, classical +from sage.arith.misc import binomial, factorial from sage.combinat.partition import Partition +from sage.combinat.sf import multiplicative, classical from sage.misc.misc_c import prod -from sage.arith.all import factorial, binomial from sage.rings.infinity import infinity + ################################### # # # Elementary Symmetric Functions # @@ -369,7 +370,7 @@ def principal_specialization(self, n=infinity, q=None): By default, we return a rational functions in `q`. Sometimes it is better to obtain an element of the symbolic ring:: - sage: x.principal_specialization(q=var("q")) + sage: x.principal_specialization(q=var("q")) # optional - sage.symbolic -3*q/((q^2 - 1)*(q - 1)^2) - 5/(q - 1)^3 + 1 TESTS:: @@ -467,7 +468,7 @@ def exponential_specialization(self, t=None, q=1): sage: x.exponential_specialization() 1/12*t^5 sage: x = 5*e[2] + 3*e[1] + 1 - sage: x.exponential_specialization(t=var("t"), q=var("q")) + sage: x.exponential_specialization(t=var("t"), q=var("q")) # optional - sage.symbolic 5*q*t^2/(q + 1) + 3*t + 1 TESTS:: diff --git a/src/sage/combinat/sf/hall_littlewood.py b/src/sage/combinat/sf/hall_littlewood.py index 9cb70465fe8..1397e5686f3 100644 --- a/src/sage/combinat/sf/hall_littlewood.py +++ b/src/sage/combinat/sf/hall_littlewood.py @@ -88,8 +88,8 @@ def __init__(self, Sym, t='t'): self._sym = Sym self.t = Sym.base_ring()(t) self._name_suffix = "" - if str(t) !='t': - self._name_suffix += " with t=%s"%t + if str(t) != 't': + self._name_suffix += " with t=%s" % t self._name = "Hall-Littlewood polynomials"+self._name_suffix def symmetric_function_ring( self ): @@ -370,7 +370,7 @@ def __init__(self, hall_littlewood): sfa.SymmetricFunctionAlgebra_generic.__init__( self, hall_littlewood._sym, basis_name="Hall-Littlewood " + s + hall_littlewood._name_suffix, - prefix="HL" +s) + prefix="HL" + s) self.t = hall_littlewood.t self._sym = hall_littlewood._sym self._hall_littlewood = hall_littlewood diff --git a/src/sage/combinat/sf/hecke.py b/src/sage/combinat/sf/hecke.py index 2fda46380a3..514a2cbf1d8 100644 --- a/src/sage/combinat/sf/hecke.py +++ b/src/sage/combinat/sf/hecke.py @@ -191,7 +191,7 @@ def _p_to_qbar_on_generator(self, n): return self([1]) q = self.q if q**n == self.base_ring().one(): - raise ValueError("the parameter q=%s must not be a %s root of unity"%(q,n)) + raise ValueError("the parameter q=%s must not be a %s root of unity" % (q,n)) out = n * self([n]) - sum((q**i-1) * self._p_to_qbar_on_generator(i) * self([n-i]) for i in range(1,n) if q**i != 1) return out*(q-1) / (q**n-1) diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index d339118ccc7..da55fef0426 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -25,11 +25,11 @@ # Homogeneous Symmetric Functions # # # #################################### -from . import multiplicative, classical +from sage.arith.misc import binomial, factorial from sage.combinat.partition import Partition -from sage.rings.infinity import infinity +from sage.combinat.sf import multiplicative, classical from sage.misc.misc_c import prod -from sage.arith.all import factorial, binomial +from sage.rings.infinity import infinity class SymmetricFunctionAlgebra_homogeneous(multiplicative.SymmetricFunctionAlgebra_multiplicative): @@ -280,7 +280,7 @@ def principal_specialization(self, n=infinity, q=None): sage: x.principal_specialization(3) q^6 + 2*q^5 + 4*q^4 + 4*q^3 + 4*q^2 + 2*q + 1 sage: x = 3*h[2] + 2*h[1] + 1 - sage: x.principal_specialization(3, q=var("q")) + sage: x.principal_specialization(3, q=var("q")) # optional - sage.symbolic 2*(q^3 - 1)/(q - 1) + 3*(q^4 - 1)*(q^3 - 1)/((q^2 - 1)*(q - 1)) + 1 TESTS:: @@ -384,7 +384,7 @@ def exponential_specialization(self, t=None, q=1): We also support the `q`-exponential_specialization:: - sage: factor(h[3].exponential_specialization(q=var("q"), t=var("t"))) + sage: factor(h[3].exponential_specialization(q=var("q"), t=var("t"))) # optional - sage.symbolic t^3/((q^2 + q + 1)*(q + 1)) TESTS:: diff --git a/src/sage/combinat/sf/jack.py b/src/sage/combinat/sf/jack.py index 617f31f7f1d..9d479f930a8 100644 --- a/src/sage/combinat/sf/jack.py +++ b/src/sage/combinat/sf/jack.py @@ -33,7 +33,8 @@ import sage.categories.all from sage.rings.integer import Integer from sage.rings.rational_field import QQ -from sage.arith.all import gcd, lcm +from sage.arith.misc import gcd +from sage.arith.functions import lcm from sage.rings.fraction_field import is_FractionField from sage.misc.misc_c import prod from sage.categories.morphism import SetMorphism @@ -70,8 +71,8 @@ def __init__(self, Sym, t='t'): self._sym = Sym self.t = Sym.base_ring()(t) self._name_suffix = "" - if str(t) !='t': - self._name_suffix += " with t=%s"%t + if str(t) != 't': + self._name_suffix += " with t=%s" % t self._name = "Jack polynomials"+self._name_suffix+" over "+repr(Sym.base_ring()) def __repr__(self): @@ -1083,7 +1084,7 @@ def __init__(self, jack): codomain=self._P, category=category) # should use module_morphism(on_coeffs = ...) once it exists self._P.register_coercion(self._P._normalize_morphism(category) * phi) - self .register_coercion(self ._normalize_morphism(category) *~phi) + self .register_coercion(self ._normalize_morphism(category) * ~phi) class Element(JackPolynomials_generic.Element): pass diff --git a/src/sage/combinat/sf/k_dual.py b/src/sage/combinat/sf/k_dual.py index 84577daf725..787ed2051ad 100644 --- a/src/sage/combinat/sf/k_dual.py +++ b/src/sage/combinat/sf/k_dual.py @@ -31,7 +31,7 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.categories.all import GradedHopfAlgebras +from sage.categories.graded_hopf_algebras import GradedHopfAlgebras from sage.combinat.partition import Partition, Partitions, Partitions_all_bounded, PartitionsGreatestLE from sage.combinat.free_module import CombinatorialFreeModule from sage.categories.realizations import Realizations, Category_realization_of_parent @@ -127,7 +127,7 @@ def __init__(self, Sym, k, t='t'): self.t = R(t) self._base = R # Won't be needed when CategoryObject won't override anymore base_ring self._sym = Sym - if t==1: + if t == 1: self._quotient_basis = Sym.m() else: self._quotient_basis = Sym.hall_littlewood(t=self.t).P() @@ -165,7 +165,7 @@ def a_realization(self): sage: Q.a_realization() 3-Bounded Quotient of Symmetric Functions over Rational Field with t=2 in the 3-bounded Hall-Littlewood P basis """ - if self.t==1: + if self.t == 1: return self.kmonomial() else: return self.kHallLittlewoodP() @@ -1167,7 +1167,7 @@ def _HLP_to_mk_on_basis(self, la): mk = self._kBoundedRing.km() if la not in self._kbounded_partitions: return mk.zero() - if self.t==1: + if self.t == 1: return mk(la) else: HLP = self._kBoundedRing._quotient_basis diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index 47eca5e9470..fe7e17aa58d 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -40,12 +40,12 @@ from sage.rings.rational_field import QQ # cache for H spin basis -hsp_to_m_cache={} -m_to_hsp_cache={} +hsp_to_m_cache = {} +m_to_hsp_cache = {} # cache for H cospin basis -hcosp_to_m_cache={} -m_to_hcosp_cache={} +hcosp_to_m_cache = {} +m_to_hcosp_cache = {} QQt = QQ['t'].fraction_field() # This is to become the "abstract algebra" for llt polynomials @@ -256,7 +256,7 @@ def _llt_generic(self, skp, stat): elif isinstance(skp, list) and skp[0] in sage.combinat.skew_partition.SkewPartitions(): #skp is a list of skew partitions - skp2 = [Partition(core=[], quotient=[skp[i][0] for i in range(len(skp))])] + skp2 = [Partition(core=[], quotient=[skp[i][0] for i in range(len(skp))])] skp2 += [Partition(core=[], quotient=[skp[i][1] for i in range(len(skp))])] mu = Partitions(ZZ((skp2[0].size()-skp2[1].size()) / self.level())) skp = skp2 @@ -265,7 +265,7 @@ def _llt_generic(self, skp, stat): skp = Partition(core=[], quotient=skp) mu = Partitions( ZZ(sum(skp) / self.level()) ) else: - raise ValueError("LLT polynomials not defined for %s"%skp) + raise ValueError("LLT polynomials not defined for %s" % skp) BR = self.base_ring() return sum([ BR(stat(skp,nu,self.level()).subs(t=self.t))*self._m(nu) for nu in mu]) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 5702e469658..4c85c726a8a 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -53,7 +53,7 @@ from sage.categories.modules_with_basis import ModulesWithBasis from . import sfa from sage.combinat.partition import Partitions_n, _Partitions -from sage.matrix.all import MatrixSpace +from sage.matrix.matrix_space import MatrixSpace from sage.rings.rational_field import QQ from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_function @@ -123,12 +123,12 @@ def __init__(self, Sym, q='q', t='t'): self._name_suffix = "" if str(q) != 'q': self._name_suffix += " with q=%s" % q - if str(t) !='t': + if str(t) != 't': self._name_suffix += " and " - if str(t) !='t': - if str(q) =='q': + if str(t) != 't': + if str(q) == 'q': self._name_suffix += " with " - self._name_suffix += "t=%s"%t + self._name_suffix += "t=%s" % t self._name = "Macdonald polynomials"+self._name_suffix+" over "+repr(Sym.base_ring()) def base_ring( self ): diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index ea1b9da133d..36f91772d4d 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -175,7 +175,7 @@ def from_polynomial(self, f, check=True): """ assert self.base_ring() == f.base_ring() if check and not f.is_symmetric(): - raise ValueError("%s is not a symmetric polynomial"%f) + raise ValueError("%s is not a symmetric polynomial" % f) out = self._from_dict({_Partitions.element_class(_Partitions, list(e)): c for (e,c) in f.dict().items() if all(e[i+1] <= e[i] for i in range(len(e)-1))}, @@ -365,7 +365,7 @@ def principal_specialization(self, n=infinity, q=None): q^7 + q^6 + q^5 + q^3 + q^2 + q sage: x = 5*m[2] + 3*m[1] + 1 - sage: x.principal_specialization(3, q=var("q")) + sage: x.principal_specialization(3, q=var("q")) # optional - sage.symbolic -10*(q^3 - 1)*q/(q - 1) + 5*(q^3 - 1)^2/(q - 1)^2 + 3*(q^3 - 1)/(q - 1) + 1 TESTS:: @@ -451,7 +451,7 @@ def exponential_specialization(self, t=None, q=1): We also support the `q`-exponential_specialization:: - sage: factor(m[3].exponential_specialization(q=var("q"), t=var("t"))) + sage: factor(m[3].exponential_specialization(q=var("q"), t=var("t"))) # optional - sage.symbolic (q - 1)^2*t^3/(q^2 + q + 1) TESTS:: diff --git a/src/sage/combinat/sf/ns_macdonald.py b/src/sage/combinat/sf/ns_macdonald.py index 1013718d4b5..44075c054cf 100644 --- a/src/sage/combinat/sf/ns_macdonald.py +++ b/src/sage/combinat/sf/ns_macdonald.py @@ -533,8 +533,8 @@ def coeff(self, q, t): EXAMPLES:: sage: a = AugmentedLatticeDiagramFilling([[1,6],[2],[3,4,2],[],[],[5,5]]) - sage: q,t = var('q,t') - sage: a.coeff(q,t) + sage: q,t = var('q,t') # optional - sage.symbolic + sage: a.coeff(q,t) # optional - sage.symbolic (t - 1)^4/((q^2*t^3 - 1)^2*(q*t^2 - 1)^2) """ res = 1 @@ -554,8 +554,8 @@ def coeff_integral(self, q, t): EXAMPLES:: sage: a = AugmentedLatticeDiagramFilling([[1,6],[2],[3,4,2],[],[],[5,5]]) - sage: q,t = var('q,t') - sage: a.coeff_integral(q,t) + sage: q,t = var('q,t') # optional - sage.symbolic + sage: a.coeff_integral(q,t) # optional - sage.symbolic (q^2*t^3 - 1)^2*(q*t^2 - 1)^2*(t - 1)^4 """ res = 1 @@ -806,15 +806,15 @@ def _check_muqt(mu, q, t, pi=None): :: - sage: q,t = var('q,t') - sage: P, q, t, n, R, x = _check_muqt([0,0,1],q,None) + sage: q,t = var('q,t') # optional - sage.symbolic + sage: P, q, t, n, R, x = _check_muqt([0,0,1],q,None) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: you must specify either both q and t or neither of them :: - sage: P, q, t, n, R, x = _check_muqt([0,0,1],q,2) + sage: P, q, t, n, R, x = _check_muqt([0,0,1],q,2) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: the parents of q and t must be the same diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index ab216cf3e84..fb9ecb31e91 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -19,7 +19,7 @@ #***************************************************************************** from . import sfa, multiplicative, classical from sage.combinat.partition import Partition -from sage.arith.all import divisors +from sage.arith.misc import divisors from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.misc.misc_c import prod @@ -760,11 +760,11 @@ def principal_specialization(self, n=infinity, q=None): sage: p = SymmetricFunctions(QQ).p() sage: x = p[8,7,3,1] - sage: x.principal_specialization(3, q=var("q")) + sage: x.principal_specialization(3, q=var("q")) # optional - sage.symbolic (q^24 - 1)*(q^21 - 1)*(q^9 - 1)/((q^8 - 1)*(q^7 - 1)*(q - 1)) sage: x = 5*p[1,1,1] + 3*p[2,1] + 1 - sage: x.principal_specialization(3, q=var("q")) + sage: x.principal_specialization(3, q=var("q")) # optional - sage.symbolic 5*(q^3 - 1)^3/(q - 1)^3 + 3*(q^6 - 1)*(q^3 - 1)/((q^2 - 1)*(q - 1)) + 1 By default, we return a rational function in `q`:: @@ -774,7 +774,7 @@ def principal_specialization(self, n=infinity, q=None): If ``n`` is not given we return the stable principal specialization:: - sage: x.principal_specialization(q=var("q")) + sage: x.principal_specialization(q=var("q")) # optional - sage.symbolic 3/((q^2 - 1)*(q - 1)) - 5/(q - 1)^3 + 1 TESTS:: @@ -881,12 +881,12 @@ def exponential_specialization(self, t=None, q=1): sage: x.exponential_specialization() 0 sage: x = p[3] + 5*p[1,1] + 2*p[1] + 1 - sage: x.exponential_specialization(t=var("t")) + sage: x.exponential_specialization(t=var("t")) # optional - sage.symbolic 5*t^2 + 2*t + 1 We also support the `q`-exponential_specialization:: - sage: factor(p[3].exponential_specialization(q=var("q"), t=var("t"))) + sage: factor(p[3].exponential_specialization(q=var("q"), t=var("t"))) # optional - sage.symbolic (q - 1)^2*t^3/(q^2 + q + 1) TESTS:: diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 914d5aef8d6..202c31d7cee 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -661,10 +661,10 @@ def principal_specialization(self, n=infinity, q=None): q^4 + q^3 + 2*q^2 + q + 1 sage: x = 3*s[2,2] + 2*s[1] + 1 - sage: x.principal_specialization(3, q=var("q")) + sage: x.principal_specialization(3, q=var("q")) # optional - sage.symbolic 3*(q^4 - 1)*(q^3 - 1)*q^2/((q^2 - 1)*(q - 1)) + 2*(q^3 - 1)/(q - 1) + 1 - sage: x.principal_specialization(q=var("q")) + sage: x.principal_specialization(q=var("q")) # optional - sage.symbolic -2/(q - 1) + 3*q^2/((q^3 - 1)*(q^2 - 1)^2*(q - 1)) + 1 TESTS:: @@ -805,7 +805,7 @@ def exponential_specialization(self, t=None, q=1): We also support the `q`-exponential_specialization:: - sage: factor(s[3].exponential_specialization(q=var("q"), t=var("t"))) + sage: factor(s[3].exponential_specialization(q=var("q"), t=var("t"))) # optional - sage.symbolic t^3/((q^2 + q + 1)*(q + 1)) TESTS:: diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index b435764a746..432fbd06ef5 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -217,8 +217,8 @@ from sage.rings.integer import Integer from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.polynomial.polynomial_element import is_Polynomial -from sage.rings.polynomial.multi_polynomial import is_MPolynomial +from sage.rings.polynomial.polynomial_element import Polynomial +from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.combinat.partition import _Partitions, Partitions, Partitions_n, Partition from sage.categories.hopf_algebras import HopfAlgebras from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis @@ -403,10 +403,8 @@ def is_integral_domain(self, proof=True): sage: s.is_integral_domain() True - The following doctest is disabled pending :trac:`15475`:: - - sage: s = SymmetricFunctions(Zmod(14)).s() # not tested - sage: s.is_integral_domain() # not tested + sage: s = SymmetricFunctions(Zmod(14)).s() + sage: s.is_integral_domain() False """ return self.base_ring().is_integral_domain() @@ -501,7 +499,7 @@ def _repr_(self): sage: Sym.macdonald(q=1,t=3).P() Sym in the Macdonald P with q=1 and t=3 basis - Hall-Littlewood polynomials: + Hall-Littlewood polynomials:: sage: Sym.hall_littlewood().P() Sym in the Hall-Littlewood P basis @@ -1015,7 +1013,7 @@ def gessel_reutenauer(self, lam): m = lam.to_exp_dict() # == {i: m_i | i occurs in lam} p = self.realization_of().power() h = self.realization_of().complete() - from sage.arith.all import moebius, squarefree_divisors + from sage.arith.misc import moebius, squarefree_divisors mu = moebius def component(i, g): # == h_g[L_i] @@ -1703,7 +1701,7 @@ def degree_negation(self, element): sage: m.degree_negation(m(e[3])) -m[1, 1, 1] """ - return self.sum_of_terms([ (lam, (-1)**(sum(lam)%2) * a) + return self.sum_of_terms([ (lam, (-1)**(sum(lam) % 2) * a) for lam, a in self(element) ]) class ElementMethods: @@ -1730,7 +1728,7 @@ def degree_negation(self): sage: parent(x) is m True """ - return self.parent().sum_of_terms([ (lam, (-1)**(sum(lam)%2) * a) + return self.parent().sum_of_terms([ (lam, (-1)**(sum(lam) % 2) * a) for lam, a in self ]) def degree_zero_coefficient(self): @@ -1809,12 +1807,12 @@ def __init__(self, Sym, basis_name=None, prefix=None, graded=True): sage: TestSuite(s).run() """ R = Sym.base_ring() - from sage.categories.all import CommutativeRings + from sage.categories.commutative_rings import CommutativeRings if R not in CommutativeRings(): raise TypeError("argument R must be a commutative ring") try: R(Integer(1)) - except Exception: + except (TypeError, ValueError): raise ValueError("R must have a unit element") if basis_name is not None: @@ -2090,19 +2088,20 @@ def _from_cache(self, element, cache_function, cache_dict, **subs_dict): # needed for the old kschur functions - TCS part = _Partitions(part) for part2, c2 in cache_dict[sum(part)][part].items(): - if hasattr(c2,'subs'): # c3 may be in the base ring - c3 = c*BR(c2.subs(**subs_dict)) + if hasattr(c2, 'subs'): # c3 may be in the base ring + c3 = c * BR(c2.subs(**subs_dict)) else: - c3 = c*BR(c2) + c3 = c * BR(c2) # c3 = c*c2 # if hasattr(c3,'subs'): # c3 may be in the base ring # c3 = c3.subs(**subs_dict) - z_elt[ part2 ] = z_elt.get(part2, zero) + BR(c3) + z_elt[part2] = z_elt.get(part2, zero) + BR(c3) return self._from_dict(z_elt) - def _invert_morphism(self, n, base_ring, self_to_other_cache, other_to_self_cache,\ - to_other_function=None, to_self_function=None, \ - upper_triangular=False, lower_triangular=False, \ + def _invert_morphism(self, n, base_ring, + self_to_other_cache, other_to_self_cache, + to_other_function=None, to_self_function=None, + upper_triangular=False, lower_triangular=False, ones_on_diagonal=False): r""" Compute the inverse of a morphism between ``self`` and ``other`` @@ -2245,12 +2244,12 @@ def _invert_morphism(self, n, base_ring, self_to_other_cache, other_to_self_cach #Decide whether we know how to go from self to other or #from other to self if to_other_function is not None: - known_cache = self_to_other_cache #the known direction - unknown_cache = other_to_self_cache #the unknown direction + known_cache = self_to_other_cache #the known direction + unknown_cache = other_to_self_cache #the unknown direction known_function = to_other_function else: - unknown_cache = self_to_other_cache #the known direction - known_cache = other_to_self_cache #the unknown direction + unknown_cache = self_to_other_cache #the known direction + known_cache = other_to_self_cache #the unknown direction known_function = to_self_function #Do nothing if we've already computed the inverse @@ -2264,7 +2263,7 @@ def _invert_morphism(self, n, base_ring, self_to_other_cache, other_to_self_cach #should use that. #Zt = ZZ['t'] #t = Zt.gen() - one = base_ring.one() + one = base_ring.one() zero = base_ring.zero() #Get and store the list of partitions we'll need @@ -2279,9 +2278,9 @@ def _invert_morphism(self, n, base_ring, self_to_other_cache, other_to_self_cach known_cache_part = {} f = known_function(pn[i]) for j in range(len_pn): - if lower_triangular and j>i: + if lower_triangular and j > i: break - if upper_triangular and i>j: + if upper_triangular and i > j: continue value = f(pn[j]) if value != zero: @@ -2711,7 +2710,7 @@ def _inner_plethysm_pnu_g(self, p_x, cache, nu): ext = self([]) else: ext = 0 - return ext + self(sum([s([n]) for n in degrees if n!=0])) + return ext + self(sum([s([n]) for n in degrees if n != 0])) #For each k in nu, we compute the inner plethysm of #p_k with p_x @@ -2719,7 +2718,7 @@ def _inner_plethysm_pnu_g(self, p_x, cache, nu): #To get the final answer, we compute the inner tensor product #of all the symmetric functions in res - return self(reduce(lambda x, y: 0 if x==0 else x.itensor(y), res)) + return self(reduce(lambda x, y: 0 if x == 0 else x.itensor(y), res)) def _dual_basis_default(self): """ @@ -4711,7 +4710,8 @@ def arithmetic_product(self, x): parent = self.parent() if parent.has_coerce_map_from(QQ): from sage.combinat.partition import Partition - from sage.arith.all import gcd, lcm + from sage.arith.misc import gcd + from sage.arith.functions import lcm from itertools import product, repeat, chain p = parent.realization_of().power() @@ -4915,8 +4915,8 @@ def scalar_qt(self, x, q=None, t=None): -q^3 + 2*q^2 - 2*q + 1 sage: a.scalar_qt(a,5,7) # q=5 and t=7 490/1539 - sage: (x,y) = var('x,y') - sage: a.scalar_qt(a,q=x,t=y) + sage: (x,y) = var('x,y') # optional - sage.symbolic + sage: a.scalar_qt(a, q=x, t=y) # optional - sage.symbolic 1/3*(x^3 - 1)/(y^3 - 1) + 2/3*(x - 1)^3/(y - 1)^3 sage: Rn = QQ['q','t','y','z'].fraction_field() sage: (q,t,y,z) = Rn.gens() @@ -5978,8 +5978,9 @@ def character_to_frobenius_image(self, n): 2*s[2, 2, 1] + s[3, 1, 1] + 4*s[3, 2] + 3*s[4, 1] + 2*s[5] """ p = self.parent().symmetric_function_ring().p() - return self.parent()(p.sum(self.eval_at_permutation_roots(rho) \ - *p(rho)/rho.centralizer_size() for rho in Partitions(n))) + return self.parent()(p.sum(self.eval_at_permutation_roots(rho) + * p(rho) / rho.centralizer_size() + for rho in Partitions(n))) def principal_specialization(self, n=infinity, q=None): r""" @@ -6028,7 +6029,7 @@ def principal_specialization(self, n=infinity, q=None): it is better to obtain an element of the symbolic ring:: sage: h = SymmetricFunctions(QQ).h() - sage: (h[3]+h[2]).principal_specialization(q=var("q")) + sage: (h[3]+h[2]).principal_specialization(q=var("q")) # optional - sage.symbolic 1/((q^2 - 1)*(q - 1)) - 1/((q^3 - 1)*(q^2 - 1)*(q - 1)) In case ``q`` is in the base ring, it must be passed explicitly:: @@ -6289,11 +6290,11 @@ def exponential_specialization(self, t=None, q=1): sage: x = m[3]+m[2,1]+m[1,1,1] sage: d = x.homogeneous_degree() - sage: var("q t") + sage: var("q t") # optional - sage.symbolic (q, t) - sage: factor((x.principal_specialization()*(1-q)^d*t^d)) + sage: factor((x.principal_specialization()*(1-q)^d*t^d)) # optional - sage.symbolic t^3/((q^2 + q + 1)*(q + 1)) - sage: factor(x.exponential_specialization(q=q, t=t)) + sage: factor(x.exponential_specialization(q=q, t=t)) # optional - sage.symbolic t^3/((q^2 + q + 1)*(q + 1)) TESTS:: @@ -6409,7 +6410,7 @@ def _nonnegative_coefficients(x): sage: _nonnegative_coefficients(x^2-4) False """ - if is_Polynomial(x) or is_MPolynomial(x): + if isinstance(x, Polynomial) or isinstance(x, MPolynomial): return all(c >= 0 for c in x.coefficients(sparse=False)) else: return x >= 0 diff --git a/src/sage/combinat/sf/witt.py b/src/sage/combinat/sf/witt.py index a129a267229..cceebed7889 100644 --- a/src/sage/combinat/sf/witt.py +++ b/src/sage/combinat/sf/witt.py @@ -757,7 +757,7 @@ def _precompute_p(self, n): """ l = len(self._p_transition_matrices) if l <= n: - from sage.arith.all import divisors + from sage.arith.misc import divisors from sage.combinat.partition import Partition from sage.misc.cachefunc import cached_function @@ -1149,7 +1149,7 @@ def wsum(m): # expansion of h_m in w-basis, for m > 0 return result if parent_name == "powersum": - from sage.arith.all import divisors + from sage.arith.misc import divisors from sage.combinat.partition import Partition @cached_function diff --git a/src/sage/combinat/shifted_primed_tableau.py b/src/sage/combinat/shifted_primed_tableau.py index 5b3354953f4..2ca02da12da 100644 --- a/src/sage/combinat/shifted_primed_tableau.py +++ b/src/sage/combinat/shifted_primed_tableau.py @@ -2673,8 +2673,8 @@ def _add_strip(sub_tab, full_tab, length): sage: list(ShiftedPrimedTableaux([3,1], weight=(2,2))) # indirect doctest [[(1, 1, 2), (2,)], [(1, 1, 2'), (2,)]] - sage: list(ShiftedPrimedTableaux([3,1], weight=(2,2), - ....: primed_diagonal=True)) # indirect doctest + sage: list(ShiftedPrimedTableaux([3,1], weight=(2,2), # indirect doctest + ....: primed_diagonal=True)) [[(1, 1, 2), (2,)], [(1, 1, 2), (2',)], [(1, 1, 2'), (2,)], diff --git a/src/sage/combinat/sidon_sets.py b/src/sage/combinat/sidon_sets.py index ec5038eb2c4..9ba6bdb5c71 100644 --- a/src/sage/combinat/sidon_sets.py +++ b/src/sage/combinat/sidon_sets.py @@ -16,7 +16,7 @@ from sage.rings.integer import Integer -def sidon_sets(N, g = 1): +def sidon_sets(N, g=1): r""" Return the set of all Sidon-`g` sets that have elements less than or equal to `N`. diff --git a/src/sage/combinat/similarity_class_type.py b/src/sage/combinat/similarity_class_type.py index cf32b79905c..94e87115ea3 100644 --- a/src/sage/combinat/similarity_class_type.py +++ b/src/sage/combinat/similarity_class_type.py @@ -189,22 +189,22 @@ class type, it is also possible to compute the number of classes of that type # **************************************************************************** from itertools import chain, product -from sage.misc.misc_c import prod -from sage.arith.misc import factorial -from sage.arith.all import moebius, divisors -from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.structure.element import Element, is_Matrix -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation + +from sage.arith.misc import divisors, factorial, moebius from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.combinat import CombinatorialElement +from sage.combinat.misc import IterableFunctionCall from sage.combinat.partition import Partitions, Partition +from sage.misc.cachefunc import cached_in_parent_method, cached_function +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.misc.misc_c import prod from sage.rings.fraction_field import FractionField from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ -from sage.misc.cachefunc import cached_in_parent_method, cached_function -from sage.combinat.misc import IterableFunctionCall from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ +from sage.structure.element import Element, is_Matrix +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation @cached_function @@ -1430,7 +1430,7 @@ def input_parsing(data): data = PrimarySimilarityClassType(*data) case = 'pri' except(TypeError, ValueError): - raise ValueError("Expected a Partition, a SimilarityClassType or a PrimarySimilarityClassType, got a %s" % type(data)) + raise ValueError("expected a Partition, a SimilarityClassType or a PrimarySimilarityClassType, got a %s" % type(data)) return case, data diff --git a/src/sage/combinat/six_vertex_model.py b/src/sage/combinat/six_vertex_model.py index 9bd289ff221..cec485f23c7 100644 --- a/src/sage/combinat/six_vertex_model.py +++ b/src/sage/combinat/six_vertex_model.py @@ -149,7 +149,7 @@ def plot(self, color='sign'): EXAMPLES:: sage: M = SixVertexModel(2, boundary_conditions='ice') - sage: print(M[0].plot().description()) + sage: print(M[0].plot().description()) # optional - sage.plot Arrow from (-1.0,0.0) to (0.0,0.0) Arrow from (-1.0,1.0) to (0.0,1.0) Arrow from (0.0,0.0) to (0.0,-1.0) @@ -438,7 +438,7 @@ def __classcall_private__(cls, n, m=None, boundary_conditions=None): cond = [] for dummy in range(2): val = [] - for k in range(m): + for _ in range(m): val.append(bdry) bdry = not bdry cond.append(tuple(val)) @@ -650,7 +650,7 @@ def partition_function(self, beta, epsilon): EXAMPLES:: sage: M = SixVertexModel(3, boundary_conditions='ice') - sage: M.partition_function(2, [1,2,1,2,1,2]) + sage: M.partition_function(2, [1,2,1,2,1,2]) # optional - sage.symbolic e^(-24) + 2*e^(-28) + e^(-30) + 2*e^(-32) + e^(-36) REFERENCES: diff --git a/src/sage/combinat/skew_partition.py b/src/sage/combinat/skew_partition.py index 7c002e151ad..92979d13a82 100644 --- a/src/sage/combinat/skew_partition.py +++ b/src/sage/combinat/skew_partition.py @@ -1068,18 +1068,18 @@ def to_dag(self, format="string"): EXAMPLES:: - sage: dag = SkewPartition([[3, 3, 1], [1, 1]]).to_dag() - sage: dag.edges(sort=True) + sage: dag = SkewPartition([[3, 3, 1], [1, 1]]).to_dag() # optional - sage.graphs + sage: dag.edges(sort=True) # optional - sage.graphs [('0,1', '0,2', None), ('0,1', '1,1', None), ('0,2', '1,2', None), ('1,1', '1,2', None)] - sage: dag.vertices(sort=True) + sage: dag.vertices(sort=True) # optional - sage.graphs ['0,1', '0,2', '1,1', '1,2', '2,0'] - sage: dag = SkewPartition([[3, 2, 1], [1, 1]]).to_dag(format="tuple") - sage: dag.edges(sort=True) + sage: dag = SkewPartition([[3, 2, 1], [1, 1]]).to_dag(format="tuple") # optional - sage.graphs + sage: dag.edges(sort=True) # optional - sage.graphs [((0, 1), (0, 2), None), ((0, 1), (1, 1), None)] - sage: dag.vertices(sort=True) + sage: dag.vertices(sort=True) # optional - sage.graphs [(0, 1), (0, 2), (1, 1), (2, 0)] """ outer = list(self.outer()) @@ -1275,6 +1275,63 @@ def outside_corners(self): """ return self.outer().outside_corners() + def specht_module(self, base_ring=None): + r""" + Return the Specht module corresponding to ``self``. + + EXAMPLES:: + + sage: mu = SkewPartition([[3,2,1], [2]]) + sage: SM = mu.specht_module(QQ) + sage: s = SymmetricFunctions(QQ).s() + sage: s(SM.frobenius_image()) + s[2, 1, 1] + s[2, 2] + s[3, 1] + + We verify that the Frobenius image is the corresponding + skew Schur function:: + + sage: s[3,2,1].skew_by(s[2]) + s[2, 1, 1] + s[2, 2] + s[3, 1] + + :: + + sage: mu = SkewPartition([[4,2,1], [2,1]]) + sage: SM = mu.specht_module(QQ) + sage: s(SM.frobenius_image()) + s[2, 1, 1] + s[2, 2] + 2*s[3, 1] + s[4] + sage: s(mu) + s[2, 1, 1] + s[2, 2] + 2*s[3, 1] + s[4] + """ + from sage.combinat.specht_module import SpechtModule + from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: + from sage.rings.rational_field import QQ + base_ring = QQ + R = SymmetricGroupAlgebra(base_ring, self.size()) + return SpechtModule(R, self.cells()) + + def specht_module_dimension(self, base_ring=None): + r""" + Return the dimension of the Specht module corresponding to ``self``. + + This is equal to the number of standard (skew) tableaux of + shape ``self``. + + EXAMPLES:: + + sage: mu = SkewPartition([[3,2,1], [2]]) + sage: mu.specht_module_dimension() + 8 + sage: mu.specht_module_dimension(GF(2)) + 8 + """ + from sage.categories.fields import Fields + if base_ring is None or (base_ring in Fields() and base_ring.characteristic() == 0): + from sage.combinat.skew_tableau import StandardSkewTableaux + return StandardSkewTableaux(self).cardinality() + from sage.combinat.specht_module import specht_module_rank + return specht_module_rank(self, base_ring) + def row_lengths_aux(skp): """ @@ -1538,11 +1595,11 @@ def from_row_and_column_length(self, rowL, colL): sage: S.from_row_and_column_length([1,2],[1,3]) Traceback (most recent call last): ... - ValueError: Sum mismatch : [1, 2] and [1, 3] + ValueError: sum mismatch: [1, 2] and [1, 3] sage: S.from_row_and_column_length([3,2,1,2],[2,3,1,1,1]) Traceback (most recent call last): ... - ValueError: Incompatible row and column length : [3, 2, 1, 2] and [2, 3, 1, 1, 1] + ValueError: incompatible row and column length : [3, 2, 1, 2] and [2, 3, 1, 1, 1] .. WARNING:: @@ -1565,14 +1622,14 @@ def from_row_and_column_length(self, rowL, colL): TESTS:: sage: all(SkewPartitions().from_row_and_column_length(p.row_lengths(), p.column_lengths()) == p - ....: for i in range(8) for p in SkewPartitions(i)) + ....: for i in range(7) for p in SkewPartitions(i)) True """ if sum(rowL) != sum(colL): - raise ValueError("Sum mismatch : %s and %s"%(rowL, colL)) - if not all(i>0 for i in rowL) or not all(i>0 for i in colL): + raise ValueError(f"sum mismatch: {rowL} and {colL}") + if not all(i > 0 for i in rowL) or not all(i > 0 for i in colL): raise ValueError("row and column length must be positive") - if rowL == []: + if not rowL: return self.element_class(self, [[], []]) colL_new = colL[:] resIn = [] @@ -1581,14 +1638,14 @@ def from_row_and_column_length(self, rowL, colL): for row in rowL: inP = len(colL_new) - row if inP < 0 or inP > inPOld: - raise ValueError("Incompatible row and column length : %s and %s"%(rowL, colL)) + raise ValueError("incompatible row and column length : %s and %s" % (rowL, colL)) inPOld = inP resIn.append(inP) resOut.append(len(colL_new)) for iCol in range(inP, len(colL_new)): colL_new[iCol] -= 1 if colL_new[iCol] < 0: - raise ValueError("Incompatible row and column length : %s and %s"%(rowL, colL)) + raise ValueError("incompatible row and column length : %s and %s" % (rowL, colL)) while colL_new and colL_new[-1] == 0: colL_new.pop() return self.element_class(self, [resOut, [x for x in resIn if x]]) @@ -1817,7 +1874,7 @@ def cardinality(self): return ZZ.one() if self.overlap > 0: - gg = Compositions(self.n, min_part = max(1, self.overlap)) + gg = Compositions(self.n, min_part=max(1, self.overlap)) else: gg = Compositions(self.n) @@ -1868,7 +1925,7 @@ def __iter__(self): sage: SkewPartitions(3, overlap=4).list() [] """ - for co in Compositions(self.n, min_part = max(1, self.overlap)): + for co in Compositions(self.n, min_part=max(1, self.overlap)): for sp in SkewPartitions(row_lengths=co, overlap=self.overlap): yield self.element_class(self, sp) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 66c0a410f8f..3c5282eae8e 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -36,9 +36,9 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.arith.all import factorial +from sage.arith.misc import factorial from sage.rings.infinity import PlusInfinity -from sage.matrix.all import zero_matrix +from sage.matrix.special import zero_matrix from sage.structure.list_clone import ClonableList from sage.combinat.partition import Partition @@ -148,11 +148,11 @@ def __eq__(self, other): INPUT: - ``other`` -- the element that ``self`` is compared to + - ``other`` -- the element that ``self`` is compared to OUTPUT: - A Boolean. + A boolean. TESTS:: @@ -161,6 +161,10 @@ def __eq__(self, other): False sage: t == SkewTableaux()([[None,1,2]]) True + sage: t == [(None,1,2)] + True + sage: t == [[None,1,2]] + True sage: s = SkewTableau([[1,2]]) sage: s == 0 @@ -171,7 +175,7 @@ def __eq__(self, other): if isinstance(other, (Tableau, SkewTableau)): return list(self) == list(other) else: - return list(self) == other + return list(self) == other or list(list(row) for row in self) == other def __ne__(self, other): r""" @@ -181,22 +185,33 @@ def __ne__(self, other): INPUT: - ``other`` -- the element that ``self`` is compared to + - ``other`` -- the element that ``self`` is compared to OUTPUT: - A Boolean. + A boolean. TESTS:: - sage: t = Tableau([[2,3],[1]]) + sage: t = SkewTableau([[None,1,2]]) sage: t != [] True """ - if isinstance(other, (Tableau, SkewTableau)): - return list(self) != list(other) - else: - return list(self) != other + return not (self == other) + + def __hash__(self): + """ + Return the hash of ``self``. + + EXAMPLES: + + Check that :trac:`35137` is fixed:: + + sage: t = SkewTableau([[None,1,2]]) + sage: hash(t) == hash(tuple(t)) + True + """ + return hash(tuple(self)) def check(self): r""" @@ -1093,10 +1108,11 @@ def rectify(self, algorithm=None): if algorithm == 'jdt': rect = self - for i in range(mu_size): + for _ in range(mu_size): rect = rect.slide() elif algorithm == 'schensted': - w = [x for row in reversed(self) for x in row if x is not None] + w = [x for row in reversed(self) for x in row + if x is not None] rect = Tableau([]).insert_word(w) else: raise ValueError("algorithm must be 'jdt', 'schensted', or None") @@ -1935,7 +1951,7 @@ class StandardSkewTableaux(SkewTableaux): sage: S = StandardSkewTableaux(2); S Standard skew tableaux of size 2 - sage: S.cardinality() + sage: S.cardinality() # optional - sage.modules 4 :: @@ -1969,7 +1985,7 @@ def __classcall_private__(cls, skp=None): elif skp in SkewPartitions(): return StandardSkewTableaux_shape(skp) else: - raise TypeError("Invalid argument") + raise TypeError("invalid argument") def __contains__(self, x): """ @@ -2000,7 +2016,7 @@ def __init__(self): EXAMPLES:: sage: s = StandardSkewTableaux() - sage: TestSuite(s).run() + sage: TestSuite(s).run() # optional - sage.graphs """ StandardSkewTableaux.__init__(self, category=InfiniteEnumeratedSets()) @@ -2022,7 +2038,7 @@ def __iter__(self): EXAMPLES:: sage: it = StandardSkewTableaux().__iter__() - sage: [next(it) for x in range(10)] + sage: [next(it) for x in range(10)] # optional - sage.graphs [[], [[1]], [[1, 2]], [[1], [2]], [[None, 2], [1]], [[None, 1], [2]], @@ -2045,7 +2061,7 @@ def __init__(self, n): EXAMPLES:: sage: S = StandardSkewTableaux(3) - sage: TestSuite(S).run() + sage: TestSuite(S).run() # optional - sage.graphs """ self.n = n StandardSkewTableaux.__init__(self, category=FiniteEnumeratedSets()) @@ -2063,13 +2079,13 @@ def cardinality(self): """ EXAMPLES:: - sage: StandardSkewTableaux(1).cardinality() + sage: StandardSkewTableaux(1).cardinality() # optional - sage.modules 1 - sage: StandardSkewTableaux(2).cardinality() + sage: StandardSkewTableaux(2).cardinality() # optional - sage.modules 4 - sage: StandardSkewTableaux(3).cardinality() + sage: StandardSkewTableaux(3).cardinality() # optional - sage.modules 24 - sage: StandardSkewTableaux(4).cardinality() + sage: StandardSkewTableaux(4).cardinality() # optional - sage.modules 194 """ count = 0 @@ -2086,10 +2102,10 @@ def __iter__(self): EXAMPLES:: - sage: StandardSkewTableaux(2).list() + sage: StandardSkewTableaux(2).list() # optional - sage.graphs [[[1, 2]], [[1], [2]], [[None, 2], [1]], [[None, 1], [2]]] - sage: StandardSkewTableaux(3).list() + sage: StandardSkewTableaux(3).list() # optional - sage.graphs [[[1, 2, 3]], [[1, 2], [3]], [[1, 3], [2]], [[None, 2, 3], [1]], [[None, 1, 2], [3]], [[None, 1, 3], [2]], @@ -2134,7 +2150,7 @@ def __init__(self, skp): TESTS:: sage: S = StandardSkewTableaux([[3, 2, 1], [1, 1]]) - sage: TestSuite(S).run() + sage: TestSuite(S).run() # optional - sage.graphs sage.modules """ self.skp = skp StandardSkewTableaux.__init__(self, category=FiniteEnumeratedSets()) @@ -2158,7 +2174,7 @@ def cardinality(self): EXAMPLES:: - sage: StandardSkewTableaux([[3, 2, 1], [1, 1]]).cardinality() + sage: StandardSkewTableaux([[3, 2, 1], [1, 1]]).cardinality() # optional - sage.modules 8 """ outer, inner = self.skp @@ -2185,7 +2201,7 @@ def __iter__(self): EXAMPLES:: - sage: StandardSkewTableaux([[3, 2, 1], [1, 1]]).list() + sage: StandardSkewTableaux([[3, 2, 1], [1, 1]]).list() # optional - sage.graphs [[[None, 2, 3], [None, 4], [1]], [[None, 1, 2], [None, 3], [4]], [[None, 1, 2], [None, 4], [3]], @@ -2318,7 +2334,7 @@ def __classcall_private__(cls, p=None, mu=None, max_entry=None): if p is None: if mu is None: return SemistandardSkewTableaux_all(max_entry) - raise ValueError("You must specify either a size or a shape") + raise ValueError("you must specify either a size or a shape") if isinstance(p, (int, Integer)): if mu is None: @@ -2332,7 +2348,7 @@ def __classcall_private__(cls, p=None, mu=None, max_entry=None): else: return SemistandardSkewTableaux_shape_weight(p, mu) - raise ValueError("Invalid input") + raise ValueError("invalid input") def __contains__(self, x): """ diff --git a/src/sage/combinat/sloane_functions.py b/src/sage/combinat/sloane_functions.py index ba937db12ff..e5c99b71fe7 100644 --- a/src/sage/combinat/sloane_functions.py +++ b/src/sage/combinat/sloane_functions.py @@ -600,10 +600,8 @@ def _eval(self, n): sage: [sloane.A000008._eval(n) for n in range(14)] [1, 1, 2, 2, 3, 4, 5, 6, 7, 8, 11, 12, 15, 16] """ - from sage.rings.big_oh import O - R, x = QQ[['x']].objgen() - p = 1/((1-x)*(1-x**2)*(1-x**5)*(1-x**10)+O(x**(n+4))) - return ZZ(p.coefficients()[n]) + from sage.combinat.partition import Partitions + return Partitions(n, parts_in=[1, 2, 5, 10]).cardinality() class A000009(SloaneSequence): @@ -657,7 +655,7 @@ def cf(self): sage: [next(it) for i in range(14)] [1, 1, 1, 2, 2, 3, 4, 5, 6, 8, 10, 12, 15, 18] """ - R, x = QQ['x'].objgen() + _, x = QQ['x'].objgen() k = 0 yield ZZ.one() p = 1 @@ -8327,7 +8325,7 @@ def perm_mh(m, h): for i in range(m): for j in range(n): if i <= j and j <= i + h: - A[i,j] = 1 + A[i, j] = 1 return A.permanent() @@ -9171,7 +9169,7 @@ def __getattribute__(self, name): :: sage: sloane.__repr__ - <method-wrapper '__repr__' of Sloane object at 0x...> + <built-in method __repr__ of Sloane object at 0x...> sage: sloane.__name__ Traceback (most recent call last): ... diff --git a/src/sage/combinat/specht_module.py b/src/sage/combinat/specht_module.py new file mode 100644 index 00000000000..678933d78fb --- /dev/null +++ b/src/sage/combinat/specht_module.py @@ -0,0 +1,458 @@ +r""" +Specht Modules + +AUTHORS: + +- Travis Scrimshaw (2023-1-22): initial version +""" + +# **************************************************************************** +# Copyright (C) 2023 Travis Scrimshaw <tcscrims (at) gmail.com> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.combinat.diagram import Diagram +from sage.sets.family import Family +from sage.matrix.constructor import matrix +from sage.rings.rational_field import QQ +from sage.modules.with_basis.subquotient import SubmoduleWithBasis +from sage.categories.modules_with_basis import ModulesWithBasis + + +class SpechtModule(SubmoduleWithBasis): + r""" + A Specht module. + + Let `S_n` be the symmetric group on `n` letters and `R` be a commutative + ring. The *Specht module* `S^D` for a diagram `D` is an `S_n`-module + defined as follows. Let + + .. MATH:: + + R(D) := \sum_{w \in R_D} w, + \qquad\qquad + C(D) := \sum_{w \in C_D} (-1)^w w, + + where `R_D` (resp. `C_D`) is the row (resp. column) stabilizer of `D`. + Then, we construct the Specht module `S^D` as the left ideal + + .. MATH:: + + S^D = R[S_n] C(D) R(D), + + where `R[S_n]` is the group algebra of `S_n` over `R`. + + INPUT: + + - ``SGA`` -- a symmetric group algebra + - ``D`` -- a diagram + + EXAMPLES: + + We begin by constructing all irreducible Specht modules for the symmetric + group `S_4` and show that they give a full set of irreducible + representations both by having distinct Frobenius characters and the + sum of the square of their dimensions is equal to `4!`:: + + sage: SP = [la.specht_module(QQ) for la in Partitions(4)] + sage: s = SymmetricFunctions(QQ).s() + sage: [s(S.frobenius_image()) for S in SP] + [s[4], s[3, 1], s[2, 2], s[2, 1, 1], s[1, 1, 1, 1]] + sage: sum(S.dimension()^2 for S in SP) + 24 + + Next, we compute the Specht module for a more general diagram + for `S_5` and compute its irreducible decomposition by using + its Frobenius character:: + + sage: D = [(0,0), (0,1), (1,1), (1,2), (0,3)] + sage: SGA = SymmetricGroupAlgebra(QQ, 5) + sage: SM = SGA.specht_module(D) + sage: SM.dimension() + 9 + sage: s(SM.frobenius_image()) + s[3, 2] + s[4, 1] + + This carries a natural (left) action of the symmetric group (algebra):: + + sage: S5 = SGA.group() + sage: v = SM.an_element(); v + 2*B[0] + 2*B[1] + 3*B[2] + sage: S5([2,1,5,3,4]) * v + 3*B[0] + 2*B[1] + 2*B[2] + sage: x = SGA.an_element(); x + [1, 2, 3, 4, 5] + 2*[1, 2, 3, 5, 4] + 3*[1, 2, 4, 3, 5] + [5, 1, 2, 3, 4] + sage: x * v + 15*B[0] + 14*B[1] + 16*B[2] - 7*B[5] + 2*B[6] + 2*B[7] + + .. SEEALSO:: + + :class:`~sage.combinat.symmetric_group_representations.SpechtRepresentation` + for an implementation of the representation by matrices. + """ + @staticmethod + def __classcall_private__(cls, SGA, D): + r""" + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: from sage.combinat.specht_module import SpechtModule + sage: from sage.combinat.diagram import Diagram + sage: SGA = SymmetricGroupAlgebra(QQ, 3) + sage: D = [(0,0), (1,1), (1,2)] + sage: SM1 = SpechtModule(SGA, D) + sage: SM2 = SpechtModule(SGA, Diagram(D)) + sage: SM1 is SM2 + True + sage: SM1 is SpechtModule(SGA, [[1,1], [1,2], [0,0]]) + True + + sage: SpechtModule(SGA, [[0,0], [1,1]]) + Traceback (most recent call last): + ... + ValueError: the domain size (=3) does not match the number of boxes (=2) of the diagram + """ + D = _to_diagram(D) + D = Diagram(D) + n = len(D) + if SGA.group().rank() != n - 1: + rk = SGA.group().rank() + 1 + raise ValueError(f"the domain size (={rk}) does not match the number of boxes (={n}) of the diagram") + return super().__classcall__(cls, SGA, D) + + def __init__(self, SGA, D): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: SGA = SymmetricGroupAlgebra(QQ, 4) + sage: SM = SGA.specht_module([(0,0), (1,1), (1,2), (2,1)]) + sage: TestSuite(SM).run() + """ + self._diagram = D + Mod = ModulesWithBasis(SGA.category().base_ring()) + span_set = specht_module_spanning_set(D, SGA) + support_order = SGA.get_order() + basis = SGA.echelon_form(span_set, False, order=support_order) + basis = Family(basis) + SubmoduleWithBasis.__init__(self, basis, support_order, ambient=SGA, + unitriangular=False, category=Mod.Subobjects()) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: SGA = SymmetricGroupAlgebra(QQ, 4) + sage: SGA.specht_module([(0,0), (1,1), (1,2), (2,1)]) + Specht module of [(0, 0), (1, 1), (1, 2), (2, 1)] over Rational Field + """ + return f"Specht module of {self._diagram} over {self.base_ring()}" + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: SGA = SymmetricGroupAlgebra(QQ, 4) + sage: SM = SGA.specht_module([(0,0), (1,1), (1,2), (2,1)]) + sage: latex(SM) + S^{{\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{$\begin{array}[b]{*{3}{p{0.6ex}}}\cline{1-1} + \lr{\phantom{x}}&&\\\cline{1-1}\cline{2-2}\cline{3-3} + &\lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{2-2}\cline{3-3}\cline{2-2} + &\lr{\phantom{x}}&\\\cline{2-2} + \end{array}$} + }} + """ + from sage.misc.latex import latex + return f"S^{{{latex(self._diagram)}}}" + + def _ascii_art_(self): + r""" + Return an ascii art representation of ``self``. + + EXAMPLES:: + + sage: SGA = SymmetricGroupAlgebra(QQ, 4) + sage: SM = SGA.specht_module([(0,0), (1,1), (1,2), (2,1)]) + sage: ascii_art(SM) + O . . + . O O + . O . + S + """ + from sage.typeset.ascii_art import ascii_art + return ascii_art("S", baseline=0) + ascii_art(self._diagram, baseline=-1) + + def _unicode_art_(self): + r""" + Return a unicode art representation of ``self``. + + EXAMPLES:: + + sage: SGA = SymmetricGroupAlgebra(QQ, 4) + sage: SM = SGA.specht_module([(0,0), (1,1), (1,2), (2,1)]) + sage: unicode_art(SM) + โ”Œโ”€โ”ฌโ”€โ”ฌโ”€โ” + โ”‚Xโ”‚ โ”‚ โ”‚ + โ”œโ”€โ”ผโ”€โ”ผโ”€โ”ค + โ”‚ โ”‚Xโ”‚Xโ”‚ + โ”œโ”€โ”ผโ”€โ”ผโ”€โ”ค + โ”‚ โ”‚Xโ”‚ โ”‚ + โ””โ”€โ”ดโ”€โ”ดโ”€โ”˜ + S + """ + from sage.typeset.unicode_art import unicode_art + return unicode_art("S", baseline=0) + unicode_art(self._diagram, baseline=-1) + + def representation_matrix(self, elt): + r""" + Return the matrix corresponding to the left action of the symmetric + group (algebra) element ``elt`` on ``self``. + + .. SEEALSO:: + + :class:`~sage.combinat.symmetric_group_representations.SpechtRepresentation` + + EXAMPLES:: + + sage: SM = Partition([3,1,1]).specht_module(QQ) + sage: SM.representation_matrix(Permutation([2,1,3,5,4])) + [-1 0 0 1 -1 0] + [ 0 0 1 0 -1 1] + [ 0 1 0 -1 0 1] + [ 0 0 0 0 -1 0] + [ 0 0 0 -1 0 0] + [ 0 0 0 0 0 -1] + sage: SGA = SymmetricGroupAlgebra(QQ, 5) + sage: SM.representation_matrix(SGA([3,1,5,2,4])) + [ 0 -1 0 1 0 -1] + [ 0 0 0 0 0 -1] + [ 0 0 0 -1 0 0] + [ 0 0 -1 0 1 -1] + [ 1 0 0 -1 1 0] + [ 0 0 0 0 1 0] + """ + SGA = self._ambient + return matrix(self.base_ring(), [self.retract(SGA(elt) * b.lift()).to_vector() + for b in self.basis()]) + + @cached_method + def frobenius_image(self): + r""" + Return the Frobenius image of ``self``. + + The Frobenius map is defined as the map to symmetric functions + + .. MATH:: + + F(\chi) = \frac{1}{n!} \sum_{w \in S_n} \chi(w) p_{\rho(w)}, + + where `\chi` is the character of the `S_n`-module ``self``, + `p_{\lambda}` is the powersum symmetric function basis element + indexed by `\lambda`, and `\rho(w)` is partition of the cycle type + of `w`. Specifically, this map takes irreducible representations + indexed by `\lambda` to the Schur function `s_{\lambda}`. + + EXAMPLES:: + + sage: s = SymmetricFunctions(QQ).s() + sage: SM = Partition([2,2,1]).specht_module(QQ) + sage: s(SM.frobenius_image()) + s[2, 2, 1] + sage: SM = Partition([4,1]).specht_module(CyclotomicField(5)) + sage: s(SM.frobenius_image()) + s[4, 1] + + We verify the regular representation:: + + sage: from sage.combinat.diagram import Diagram + sage: D = Diagram([(0,0), (1,1), (2,2), (3,3), (4,4)]) + sage: F = s(D.specht_module(QQ).frobenius_image()); F + s[1, 1, 1, 1, 1] + 4*s[2, 1, 1, 1] + 5*s[2, 2, 1] + + 6*s[3, 1, 1] + 5*s[3, 2] + 4*s[4, 1] + s[5] + sage: F == sum(StandardTableaux(la).cardinality() * s[la] + ....: for la in Partitions(5)) + True + sage: all(s[la] == s(la.specht_module(QQ).frobenius_image()) + ....: for n in range(1, 5) for la in Partitions(n)) + True + + sage: D = Diagram([(0,0), (1,1), (1,2), (2,3), (2,4)]) + sage: SM = D.specht_module(QQ) + sage: s(SM.frobenius_image()) + s[2, 2, 1] + s[3, 1, 1] + 2*s[3, 2] + 2*s[4, 1] + s[5] + """ + from sage.combinat.sf.sf import SymmetricFunctions + BR = self._ambient.base_ring() + p = SymmetricFunctions(BR).p() + G = self._ambient.group() + CCR = [(elt, elt.cycle_type()) for elt in G.conjugacy_classes_representatives()] + return p.sum(self.representation_matrix(elt).trace() / la.centralizer_size() * p[la] + for elt, la in CCR) + + class Element(SubmoduleWithBasis.Element): + def _acted_upon_(self, x, self_on_left=False): + """ + Return the action of ``x`` on ``self``. + + INPUT: + + - ``x`` -- an element of the base ring or can be converted into + the defining symmetric group algebra + - ``self_on_left`` -- boolean (default: ``False``); which side + ``self`` is on for the action + + EXAMPLES:: + + sage: SGA = SymmetricGroupAlgebra(QQ, 4) + sage: SM = SGA.specht_module([3,1]) + sage: SGA.an_element() * SM.an_element() + 14*B[0] + 18*B[1] + 8*B[2] + sage: 4 * SM.an_element() + 8*B[0] + 8*B[1] + 12*B[2] + """ + # Check for a scalar first + ret = super()._acted_upon_(x, self_on_left) + if ret is not None: + return ret + # Check if it is in the symmetric group algebra + P = self.parent() + if x in P._ambient or x in P._ambient.group(): + if self_on_left: # it is only a left module + return None + else: + return P.retract(P._ambient(x) * self.lift()) + return None + + +def _to_diagram(D): + r""" + Convert ``D`` to a list of cells representing a diagram. + + TESTS:: + + sage: from sage.combinat.specht_module import _to_diagram + sage: _to_diagram(Partition([3,1,1])) + [(0, 0), (0, 1), (0, 2), (1, 0), (2, 0)] + sage: _to_diagram(SkewPartition([[5,3,1,1],[2,2,1]])) + [(0, 2), (0, 3), (0, 4), (1, 2), (3, 0)] + sage: _to_diagram([1,2,0,2]) + [(0, 0), (1, 0), (1, 1), (3, 0), (3, 1)] + sage: _to_diagram(Composition([2,1,3])) + [(0, 0), (0, 1), (1, 0), (2, 0), (2, 1), (2, 2)] + sage: _to_diagram([(1,2), (2,2)]) + [(1, 2), (2, 2)] + """ + from sage.combinat.integer_vector import IntegerVectors + from sage.combinat.skew_partition import SkewPartitions + from sage.combinat.partition import _Partitions + if isinstance(D, Diagram): + return D + if D in _Partitions: + D = _Partitions(D).cells() + elif D in SkewPartitions(): + D = SkewPartitions()(D).cells() + elif D in IntegerVectors(): + cells = [] + for i, row in enumerate(D): + for j in range(row): + cells.append((i, j)) + D = cells + else: + D = [tuple(cell) for cell in D] + return D + + +def specht_module_spanning_set(D, SGA=None): + r""" + Return a spanning set of the Specht module of diagram ``D``. + + INPUT: + + - ``D`` -- a list of cells ``(r,c)`` for row ``r`` and column ``c`` + - ``SGA`` -- optional; a symmetric group algebra + + EXAMPLES:: + + sage: from sage.combinat.specht_module import specht_module_spanning_set + sage: specht_module_spanning_set([(0,0), (1,1), (2,2)]) + ([1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]) + sage: specht_module_spanning_set([(0,0), (1,1), (2,1)]) + ([1, 2, 3] - [1, 3, 2], -[1, 2, 3] + [1, 3, 2], [2, 1, 3] - [3, 1, 2], + [2, 3, 1] - [3, 2, 1], -[2, 1, 3] + [3, 1, 2], -[2, 3, 1] + [3, 2, 1]) + + sage: SGA = SymmetricGroup(3).algebra(QQ) + sage: specht_module_spanning_set([(0,0), (1,1), (2,1)], SGA) + (() - (2,3), -(1,2) + (1,3,2), (1,2,3) - (1,3), + -() + (2,3), -(1,2,3) + (1,3), (1,2) - (1,3,2)) + + TESTS: + + Verify that diagrams bigger than the rank work:: + + sage: specht_module_spanning_set([(0,0), (3,5)]) + ([1, 2], [2, 1]) + sage: specht_module_spanning_set([(0,0), (5,3)]) + ([1, 2], [2, 1]) + """ + n = len(D) + if SGA is None: + from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + SGA = SymmetricGroupAlgebra(QQ, n) + elif SGA.group().rank() != n - 1: + raise ValueError("the rank does not match the size of the diagram") + nr = max((c[0] for c in D), default=0) + 1 + nc = max((c[1] for c in D), default=0) + 1 + row_diagram = [set() for _ in range(nr)] + col_diagram = [set() for _ in range(nc)] + for i, cell in enumerate(D): + x, y = cell + row_diagram[x].add(i) + col_diagram[y].add(i) + # Construct the row and column stabilizer elements + row_stab = SGA.zero() + col_stab = SGA.zero() + B = SGA.basis() + for w in B.keys(): + # Remember that the permutation w is 1-based + row_perm = [set() for _ in range(nr)] + col_perm = [set() for _ in range(nc)] + for i, cell in enumerate(D): + x, y = cell + row_perm[x].add(w(i + 1) - 1) + col_perm[y].add(w(i + 1) - 1) + if row_diagram == row_perm: + row_stab += B[w] + if col_diagram == col_perm: + col_stab += w.sign() * B[w] + gen = col_stab * row_stab + return tuple([b * gen for b in B]) + + +def specht_module_rank(D, base_ring=None): + r""" + Return the rank of the Specht module of diagram ``D``. + + EXAMPLES:: + + sage: from sage.combinat.specht_module import specht_module_rank + sage: specht_module_rank([(0,0), (1,1), (2,2)]) + 6 + """ + D = _to_diagram(D) + span_set = specht_module_spanning_set(D) + if base_ring is None: + base_ring = QQ + return matrix(base_ring, [v.to_vector() for v in span_set]).rank() diff --git a/src/sage/combinat/species/characteristic_species.py b/src/sage/combinat/species/characteristic_species.py index 910ce3e96fc..e529dc97bd1 100644 --- a/src/sage/combinat/species/characteristic_species.py +++ b/src/sage/combinat/species/characteristic_species.py @@ -88,7 +88,7 @@ def automorphism_group(self): sage: a.automorphism_group() Symmetric group of order 3! as a permutation group """ - from sage.groups.all import SymmetricGroup + from sage.groups.perm_gps.permgroup_named import SymmetricGroup return SymmetricGroup(len(self._labels)) @@ -133,7 +133,7 @@ def __init__(self, n, min=None, max=None, weight=None): False """ self._n = n - self._name = "Characteristic species of order %s"%n + self._name = "Characteristic species of order %s" % n self._state_info = [n] GenericCombinatorialSpecies.__init__(self, min=min, max=max, weight=weight) diff --git a/src/sage/combinat/species/composition_species.py b/src/sage/combinat/species/composition_species.py index 18aca4861d7..c96f3161ba5 100644 --- a/src/sage/combinat/species/composition_species.py +++ b/src/sage/combinat/species/composition_species.py @@ -45,7 +45,7 @@ def __repr__(self): F-structure: {{'a', 'b', 'c'}}; G-structures: (('a', 'b', 'c'),) """ f, gs = self._list - return "F-structure: %s; G-structures: %s"%(repr(f), repr(gs)) + return "F-structure: %s; G-structures: %s" % (repr(f), repr(gs)) def transport(self, perm): """ @@ -123,7 +123,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): """ self._F = F self._G = G - self._name = "Composition of (%s) and (%s)"%(F, G) + self._name = "Composition of (%s) and (%s)" % (F, G) self._state_info = [F, G] GenericCombinatorialSpecies.__init__(self, min=None, max=None, weight=None) diff --git a/src/sage/combinat/species/cycle_species.py b/src/sage/combinat/species/cycle_species.py index a0afba3b1d0..335223143ed 100644 --- a/src/sage/combinat/species/cycle_species.py +++ b/src/sage/combinat/species/cycle_species.py @@ -12,11 +12,11 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from .species import GenericCombinatorialSpecies -from .structure import GenericSpeciesStructure -from sage.structure.unique_representation import UniqueRepresentation -from sage.arith.all import divisors, euler_phi +from sage.arith.misc import divisors, euler_phi from sage.combinat.species.misc import accept_size +from sage.combinat.species.species import GenericCombinatorialSpecies +from sage.combinat.species.structure import GenericSpeciesStructure +from sage.structure.unique_representation import UniqueRepresentation class CycleSpeciesStructure(GenericSpeciesStructure): @@ -54,7 +54,7 @@ def permutation_group_element(self): sage: a.permutation_group_element() (1,2,3) """ - from sage.groups.all import PermutationGroupElement + from sage.groups.perm_gps.constructor import PermutationGroupElement return PermutationGroupElement(tuple(self._list)) def transport(self, perm): @@ -96,7 +96,8 @@ def automorphism_group(self): sage: [a.transport(perm) for perm in a.automorphism_group()] [(1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4)] """ - from sage.groups.all import SymmetricGroup, PermutationGroup + from sage.groups.perm_gps.permgroup_named import SymmetricGroup + from sage.groups.perm_gps.permgroup import PermutationGroup S = SymmetricGroup(len(self._labels)) p = self.permutation_group_element() return PermutationGroup(S.centralizer(p).gens()) diff --git a/src/sage/combinat/species/empty_species.py b/src/sage/combinat/species/empty_species.py index a6eb69597bc..e66019360ac 100644 --- a/src/sage/combinat/species/empty_species.py +++ b/src/sage/combinat/species/empty_species.py @@ -113,7 +113,7 @@ def _gs(self, series_ring, base_ring): return series_ring.zero() _itgs = _gs - _cis = _gs + _cis = _gs def _structures(self, structure_class, labels): """ diff --git a/src/sage/combinat/species/functorial_composition_species.py b/src/sage/combinat/species/functorial_composition_species.py index d97460e29e4..118e924d426 100644 --- a/src/sage/combinat/species/functorial_composition_species.py +++ b/src/sage/combinat/species/functorial_composition_species.py @@ -71,8 +71,7 @@ def _structures(self, structure_class, s): {{1, 2}*{3}, {1, 3}*{2}, {2, 3}*{1}}] """ gs = self._G.structures(s).list() - for f in self._F.structures(gs): - yield f + yield from self._F.structures(gs) def _isotypes(self, structure_class, s): """ diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index 7f2d1f27c38..e7f7c8ee978 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -16,18 +16,18 @@ TESTS:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: p = SymmetricFunctions(QQ).power() + sage: p = SymmetricFunctions(QQ).power() # optional - sage.modules sage: CIS = CycleIndexSeriesRing(QQ) - sage: geo1 = CIS(lambda i: p([1])^i) - sage: geo2 = CIS(lambda i: p([2])^(i // 2) if is_even(i) else 0) - sage: s = geo1 * geo2 - sage: s[0] + sage: geo1 = CIS(lambda i: p([1])^i) # optional - sage.modules + sage: geo2 = CIS(lambda i: p([2])^(i // 2) if is_even(i) else 0) # optional - sage.modules + sage: s = geo1 * geo2 # optional - sage.modules + sage: s[0] # optional - sage.modules p[] - sage: s[1] + sage: s[1] # optional - sage.modules p[1] - sage: s[2] + sage: s[2] # optional - sage.modules p[1, 1] + p[2] - sage: s[3] + sage: s[3] # optional - sage.modules p[1, 1, 1] + p[2, 1] REFERENCES: @@ -53,7 +53,7 @@ from sage.rings.lazy_series_ring import LazyPowerSeriesRing, LazySymmetricFunctions from sage.rings.integer import Integer from sage.rings.rational_field import QQ -from sage.arith.all import divisors +from sage.arith.misc import divisors from sage.combinat.partition import Partition, Partitions from sage.combinat.sf.sf import SymmetricFunctions from sage.misc.cachefunc import cached_function @@ -292,14 +292,14 @@ def count(self, t): EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: p = SymmetricFunctions(QQ).power() + sage: p = SymmetricFunctions(QQ).power() # optional - sage.modules sage: CIS = CycleIndexSeriesRing(QQ) - sage: f = CIS([0, p([1]), 2*p([1,1]), 3*p([2,1])]) - sage: f.count([1]) + sage: f = CIS([0, p([1]), 2*p([1,1]), 3*p([2,1])]) # optional - sage.modules + sage: f.count([1]) # optional - sage.modules 1 - sage: f.count([1,1]) + sage: f.count([1,1]) # optional - sage.modules 4 - sage: f.count([2,1]) + sage: f.count([2,1]) # optional - sage.modules 6 """ t = Partition(t) @@ -312,14 +312,14 @@ def coefficient_cycle_type(self, t): EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: p = SymmetricFunctions(QQ).power() + sage: p = SymmetricFunctions(QQ).power() # optional - sage.modules sage: CIS = CycleIndexSeriesRing(QQ) - sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])]) - sage: f.coefficient_cycle_type([1]) + sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])]) # optional - sage.modules + sage: f.coefficient_cycle_type([1]) # optional - sage.modules 1 - sage: f.coefficient_cycle_type([1,1]) + sage: f.coefficient_cycle_type([1,1]) # optional - sage.modules 2 - sage: f.coefficient_cycle_type([2,1]) + sage: f.coefficient_cycle_type([2,1]) # optional - sage.modules 3 """ t = Partition(t) @@ -535,10 +535,10 @@ class CycleIndexSeriesRing(LazySymmetricFunctions): EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: R = CycleIndexSeriesRing(QQ); R + sage: R = CycleIndexSeriesRing(QQ); R # optional - sage.modules Cycle Index Series Ring over Rational Field - sage: p = SymmetricFunctions(QQ).p() - sage: R(lambda n: p[n]) + sage: p = SymmetricFunctions(QQ).p() # optional - sage.modules + sage: R(lambda n: p[n]) # optional - sage.modules p[] + p[1] + p[2] + p[3] + p[4] + p[5] + p[6] + O^7 TESTS: @@ -558,8 +558,8 @@ def __init__(self, base_ring, sparse=True): sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: CycleIndexSeriesRing.options.halting_precision(12) - sage: R = CycleIndexSeriesRing(QQ) - sage: TestSuite(R).run() + sage: R = CycleIndexSeriesRing(QQ) # optional - sage.modules + sage: TestSuite(R).run() # optional - sage.modules sage: CycleIndexSeriesRing.options._reset() # reset options """ @@ -573,7 +573,7 @@ def _repr_(self): EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: CycleIndexSeriesRing(QQ) + sage: CycleIndexSeriesRing(QQ) # optional - sage.modules Cycle Index Series Ring over Rational Field """ return "Cycle Index Series Ring over %s" % self.base_ring() @@ -588,7 +588,7 @@ def _exp_term(n, R=QQ): EXAMPLES:: sage: from sage.combinat.species.generating_series import _exp_term - sage: [_exp_term(i) for i in range(4)] + sage: [_exp_term(i) for i in range(4)] # optional - sage.modules [p[], p[1], 1/2*p[1, 1] + 1/2*p[2], 1/6*p[1, 1, 1] + 1/2*p[2, 1] + 1/3*p[3]] """ p = SymmetricFunctions(R).power() @@ -610,7 +610,7 @@ def ExponentialCycleIndexSeries(R=QQ): EXAMPLES:: sage: from sage.combinat.species.generating_series import ExponentialCycleIndexSeries - sage: ExponentialCycleIndexSeries()[:5] + sage: ExponentialCycleIndexSeries()[:5] # optional - sage.modules [p[], p[1], 1/2*p[1, 1] + 1/2*p[2], 1/6*p[1, 1, 1] + 1/2*p[2, 1] + 1/3*p[3], 1/24*p[1, 1, 1, 1] + 1/4*p[2, 1, 1] + 1/8*p[2, 2] + 1/3*p[3, 1] + 1/4*p[4]] @@ -629,7 +629,7 @@ def _cl_term(n, R=QQ): EXAMPLES:: sage: from sage.combinat.species.generating_series import _cl_term - sage: [_cl_term(i) for i in range(4)] + sage: [_cl_term(i) for i in range(4)] # optional - sage.modules [0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]] """ n = Integer(n) # check that n is an integer @@ -661,7 +661,7 @@ def LogarithmCycleIndexSeries(R=QQ): its cycle index has negative coefficients:: sage: from sage.combinat.species.generating_series import LogarithmCycleIndexSeries - sage: LogarithmCycleIndexSeries()[0:4] + sage: LogarithmCycleIndexSeries()[0:4] # optional - sage.modules [0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]] Its defining property is that `\Omega \circ E^{+} = E^{+} \circ \Omega = X` @@ -669,7 +669,7 @@ def LogarithmCycleIndexSeries(R=QQ): multiplicative identity `X`):: sage: Eplus = sage.combinat.species.set_species.SetSpecies(min=1).cycle_index_series() - sage: LogarithmCycleIndexSeries()(Eplus)[0:4] + sage: LogarithmCycleIndexSeries()(Eplus)[0:4] # optional - sage.modules [0, p[1], 0, 0] """ CIS = CycleIndexSeriesRing(R) diff --git a/src/sage/combinat/species/linear_order_species.py b/src/sage/combinat/species/linear_order_species.py index 3f8690da3c2..a62fde28fb5 100644 --- a/src/sage/combinat/species/linear_order_species.py +++ b/src/sage/combinat/species/linear_order_species.py @@ -63,7 +63,7 @@ def automorphism_group(self): sage: a.automorphism_group() Symmetric group of order 1! as a permutation group """ - from sage.groups.all import SymmetricGroup + from sage.groups.perm_gps.permgroup_named import SymmetricGroup return SymmetricGroup(1) diff --git a/src/sage/combinat/species/misc.py b/src/sage/combinat/species/misc.py index f31a0939477..7296c77e54d 100644 --- a/src/sage/combinat/species/misc.py +++ b/src/sage/combinat/species/misc.py @@ -16,7 +16,10 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.groups.all import PermutationGroup, PermutationGroup_generic, PermutationGroupElement, SymmetricGroup +from sage.groups.perm_gps.permgroup import PermutationGroup +from sage.groups.perm_gps.permgroup import PermutationGroup_generic +from sage.groups.perm_gps.constructor import PermutationGroupElement +from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.misc.misc_c import prod from functools import wraps diff --git a/src/sage/combinat/species/partition_species.py b/src/sage/combinat/species/partition_species.py index 7ddd9812ba1..c9b08f1b4bb 100644 --- a/src/sage/combinat/species/partition_species.py +++ b/src/sage/combinat/species/partition_species.py @@ -102,7 +102,7 @@ def automorphism_group(self): sage: a.automorphism_group() Permutation Group with generators [(1,2)] """ - from sage.groups.all import SymmetricGroup + from sage.groups.perm_gps.permgroup_named import SymmetricGroup return reduce(lambda a,b: a.direct_product(b, maps=False), [SymmetricGroup(block._list) for block in self._list]) diff --git a/src/sage/combinat/species/permutation_species.py b/src/sage/combinat/species/permutation_species.py index 9c34eeb9c98..aeb7ad3ca3b 100644 --- a/src/sage/combinat/species/permutation_species.py +++ b/src/sage/combinat/species/permutation_species.py @@ -97,7 +97,8 @@ def automorphism_group(self): ['a', 'c', 'b', 'd'], ['a', 'c', 'b', 'd']] """ - from sage.groups.all import SymmetricGroup, PermutationGroup + from sage.groups.perm_gps.permgroup_named import SymmetricGroup + from sage.groups.perm_gps.permgroup import PermutationGroup S = SymmetricGroup(len(self._labels)) p = self.permutation_group_element() return PermutationGroup(S.centralizer(p).gens()) diff --git a/src/sage/combinat/species/product_species.py b/src/sage/combinat/species/product_species.py index 74004849b79..0989d2a8f8c 100644 --- a/src/sage/combinat/species/product_species.py +++ b/src/sage/combinat/species/product_species.py @@ -176,7 +176,8 @@ def automorphism_group(self): sage: [a.transport(g) for g in a.automorphism_group()] [{2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}] """ - from sage.groups.all import PermutationGroupElement, PermutationGroup + from sage.groups.perm_gps.constructor import PermutationGroupElement + from sage.groups.perm_gps.permgroup import PermutationGroup from sage.combinat.species.misc import change_support left, right = self._list diff --git a/src/sage/combinat/species/recursive_species.py b/src/sage/combinat/species/recursive_species.py index a361bdfad20..3cd073f9f9c 100644 --- a/src/sage/combinat/species/recursive_species.py +++ b/src/sage/combinat/species/recursive_species.py @@ -230,7 +230,7 @@ def _gs(self, series_ring, base_ring): sage: F = CombinatorialSpecies() sage: F.generating_series() - Uninitialized Lazy Laurent Series + Uninitialized Lazy Series """ if base_ring not in self._generating_series: self._generating_series[base_ring] = series_ring.undefined(valuation=(0 if self._min is None else self._min)) @@ -247,7 +247,7 @@ def _itgs(self, series_ring, base_ring): sage: F = CombinatorialSpecies() sage: F.isotype_generating_series() - Uninitialized Lazy Laurent Series + Uninitialized Lazy Series """ if base_ring not in self._isotype_generating_series: self._isotype_generating_series[base_ring] = series_ring.undefined(valuation=(0 if self._min is None else self._min)) @@ -264,7 +264,7 @@ def _cis(self, series_ring, base_ring): sage: F = CombinatorialSpecies() sage: F.cycle_index_series() - Uninitialized Lazy Laurent Series + Uninitialized Lazy Series """ if base_ring not in self._cycle_index_series: self._cycle_index_series[base_ring] = series_ring.undefined(valuation=(0 if self._min is None else self._min)) @@ -401,6 +401,15 @@ def define(self, x): [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] sage: F.isotype_generating_series()[0:10] [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] + + Check that :issue:`35071` is fixed:: + + sage: X = species.SingletonSpecies() + sage: E = species.SetSpecies(max=3) + sage: B = species.CombinatorialSpecies(min=1) + sage: B.define(X*E(B)) + sage: B.generating_series() + z + z^2 + 3/2*z^3 + 5/2*z^4 + 9/2*z^5 + 17/2*z^6 + 133/8*z^7 + O(z^8) """ if not isinstance(x, GenericCombinatorialSpecies): raise TypeError("x must be a combinatorial species") diff --git a/src/sage/combinat/species/set_species.py b/src/sage/combinat/species/set_species.py index 4bc94c220f8..c4942dc653d 100644 --- a/src/sage/combinat/species/set_species.py +++ b/src/sage/combinat/species/set_species.py @@ -77,7 +77,7 @@ def automorphism_group(self): sage: a.automorphism_group() Symmetric group of order 3! as a permutation group """ - from sage.groups.all import SymmetricGroup + from sage.groups.perm_gps.permgroup_named import SymmetricGroup return SymmetricGroup(max(1,len(self._labels))) diff --git a/src/sage/combinat/species/structure.py b/src/sage/combinat/species/structure.py index 371d78eef9d..a4de6349c6d 100644 --- a/src/sage/combinat/species/structure.py +++ b/src/sage/combinat/species/structure.py @@ -12,11 +12,12 @@ Here we define this species using the default structures:: - sage: ball = species.SingletonSpecies(); o = var('o') + sage: ball = species.SingletonSpecies() sage: bar = species.EmptySetSpecies() sage: BB = CombinatorialSpecies() sage: BB.define(ball + ball*BB + ball*bar*BB) - sage: BB.isotypes([o]*3).list() + sage: o = var('o') # optional - sage.symbolic + sage: BB.isotypes([o]*3).list() # optional - sage.symbolic [o*(o*o), o*((o*{})*o), (o*{})*(o*o), (o*{})*((o*{})*o)] If we ignore the parentheses, we can read off that the integer diff --git a/src/sage/combinat/species/subset_species.py b/src/sage/combinat/species/subset_species.py index 25f4862f4be..2bd89885533 100644 --- a/src/sage/combinat/species/subset_species.py +++ b/src/sage/combinat/species/subset_species.py @@ -102,7 +102,8 @@ def automorphism_group(self): sage: [a.transport(g) for g in a.automorphism_group()] [{1, 3}, {1, 3}, {1, 3}, {1, 3}] """ - from sage.groups.all import SymmetricGroup, PermutationGroup + from sage.groups.perm_gps.permgroup_named import SymmetricGroup + from sage.groups.perm_gps.permgroup import PermutationGroup a = SymmetricGroup(self._list) b = SymmetricGroup(self.complement()._list) return PermutationGroup(a.gens() + b.gens()) diff --git a/src/sage/combinat/subset.py b/src/sage/combinat/subset.py index 5cae6958510..add81ab8707 100644 --- a/src/sage/combinat/subset.py +++ b/src/sage/combinat/subset.py @@ -1,7 +1,7 @@ r""" Subsets -The set of subsets of a finite set. The set can be given as a list or a Set +The set of subsets of a finite set. The set can be given as a list or a :class:`Set` or else as an integer `n` which encodes the set `\{1,2,...,n\}`. See :class:`Subsets` for more information and examples. @@ -38,8 +38,7 @@ from sage.structure.element import Element from sage.sets.set import Set, Set_object_enumerated -from sage.arith.all import binomial -from sage.misc.misc import _stable_uniq as uniq +from sage.arith.misc import binomial from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer from . import combination @@ -186,11 +185,11 @@ class Subsets_s(Parent): {1, 2, 3}, {1, 2, 4}, {1, 3, 4}, {2, 3, 4}, {1, 2, 3, 4}] - sage: S = Subsets(Subsets(Subsets(GF(3)))); S + sage: S = Subsets(Subsets(Subsets(GF(3)))); S # optional - sage.rings.finite_rings Subsets of Subsets of Subsets of Finite Field of size 3 - sage: S.cardinality() + sage: S.cardinality() # optional - sage.rings.finite_rings 115792089237316195423570985008687907853269984665640564039457584007913129639936 - sage: S.unrank(3149254230) # random + sage: S.unrank(3149254230) # random # optional - sage.rings.finite_rings {{{1}, {0, 2}}, {{0, 1, 2}, {0, 1}, {1}, {1, 2}}, {{2}, {1, 2}, {0, 1, 2}, {0, 2}, {1}, {}}, {{1, 2}, {0}}, @@ -248,7 +247,7 @@ def underlying_set(self): EXAMPLES:: - sage: Subsets(GF(13)).underlying_set() + sage: Subsets(GF(13)).underlying_set() # optional - sage.rings.finite_rings {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} """ return self.element_class(self._s) @@ -342,9 +341,9 @@ def cardinality(self): sage: Subsets(3).cardinality() 8 - TESTS:: + TESTS: - ``__len__`` should return a Python int. + ``__len__`` should return a Python int:: sage: S = Subsets(Set([1,2,3])) sage: len(S) @@ -550,10 +549,10 @@ def lattice(self): EXAMPLES:: sage: X = Subsets([7,8,9]) - sage: X.lattice() + sage: X.lattice() # optional - sage.combinat sage.graphs Finite lattice containing 8 elements sage: Y = Subsets(0) - sage: Y.lattice() + sage: Y.lattice() # optional - sage.combinat sage.graphs Finite lattice containing 1 elements """ @@ -874,8 +873,8 @@ def an_element(self): def dict_to_list(d): r""" - Return a list whose elements are the elements of i of d repeated with - multiplicity d[i]. + Return a list whose elements are the elements of ``i`` of ``d`` repeated with + multiplicity ``d[i]``. EXAMPLES:: @@ -1062,7 +1061,7 @@ def cardinality(self): sage: len(S.list()) 24 """ - from sage.all import prod + from sage.misc.misc_c import prod return Integer(prod(k + 1 for k in self._d.values())) def random_element(self): @@ -1130,8 +1129,7 @@ def __iter__(self): [1, 2, 2, 3]] """ for k in range(len(self._l) + 1): - for s in SubMultiset_sk(self._l, k): - yield s + yield from SubMultiset_sk(self._l, k) def __call__(self, el): r""" @@ -1168,7 +1166,7 @@ def _element_constructor_(self,X): class SubMultiset_sk(SubMultiset_s): """ - The combinatorial class of the subsets of size k of a multiset s. Note + The combinatorial class of the subsets of size ``k`` of a multiset ``s``. Note that each subset is represented by a list of the elements rather than a set since we can have multiplicities (no multiset data structure yet in sage). @@ -1291,7 +1289,7 @@ def __contains__(self, s): def random_element(self): r""" - Return a random submultiset of given length + Return a random submultiset of given length. EXAMPLES:: @@ -1471,3 +1469,93 @@ def _element_constructor_(self, x): [(), (0,), (1,), (2,), (0, 1), (0, 2), (1, 2), (0, 1, 2)] """ return self.element_class(sorted(set(x))) + + +def powerset(X): + r""" + Iterator over the *list* of all subsets of the iterable ``X``, in no + particular order. Each list appears exactly once, up to order. + + INPUT: + + - ``X`` - an iterable + + OUTPUT: iterator of lists + + EXAMPLES:: + + sage: list(powerset([1,2,3])) + [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] + sage: [z for z in powerset([0,[1,2]])] + [[], [0], [[1, 2]], [0, [1, 2]]] + + Iterating over the power set of an infinite set is also allowed:: + + sage: i = 0 + sage: L = [] + sage: for x in powerset(ZZ): + ....: if i > 10: + ....: break + ....: else: + ....: i += 1 + ....: L.append(x) + sage: print(" ".join(str(x) for x in L)) + [] [0] [1] [0, 1] [-1] [0, -1] [1, -1] [0, 1, -1] [2] [0, 2] [1, 2] + + You may also use subsets as an alias for powerset:: + + sage: subsets([1,2,3]) + <generator object ...powerset at 0x...> + sage: list(subsets([1,2,3])) + [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] + + The reason we return lists instead of sets is that the elements of + sets must be hashable and many structures on which one wants the + powerset consist of non-hashable objects. + + AUTHORS: + + - William Stein + + - Nils Bruin (2006-12-19): rewrite to work for not-necessarily + finite objects X. + """ + yield [] + pairs = [] + power2 = 1 + for x in X: + pairs.append((power2, x)) + next_power2 = power2 << 1 + for w in range(power2, next_power2): + yield [x for m, x in pairs if m & w] + power2 = next_power2 + + +subsets = powerset + + +def uniq(L): + """ + Iterate over the elements of ``L``, yielding every element at most + once: keep only the first occurrence of any item. + + The items must be hashable. + + INPUT: + + - ``L`` -- iterable + + EXAMPLES:: + + sage: L = [1, 1, 8, -5, 3, -5, 'a', 'x', 'a'] + sage: it = uniq(L); it + <generator object uniq at ...> + sage: list(it) + [1, 8, -5, 3, 'a', 'x'] + """ + seen = set() + for x in L: + if x in seen: + continue + yield x + seen.add(x) diff --git a/src/sage/combinat/subsets_hereditary.py b/src/sage/combinat/subsets_hereditary.py index 5a1347c5218..7a9e238679c 100644 --- a/src/sage/combinat/subsets_hereditary.py +++ b/src/sage/combinat/subsets_hereditary.py @@ -1,15 +1,15 @@ r""" Subsets satisfying a hereditary property """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Nathann Cohen <nathann.cohen@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** -def subsets_with_hereditary_property(f,X,max_obstruction_size=None,ncpus=1): +def subsets_with_hereditary_property(f, X, max_obstruction_size=None, ncpus=1): r""" Return all subsets `S` of `X` such that `f(S)` is true. @@ -57,13 +57,14 @@ def subsets_with_hereditary_property(f,X,max_obstruction_size=None,ncpus=1): Sets whose elements all have the same remainder mod 2:: sage: from sage.combinat.subsets_hereditary import subsets_with_hereditary_property - sage: f = lambda x: (not x) or all(xx%2 == x[0]%2 for xx in x) - sage: list(subsets_with_hereditary_property(f,range(4))) + sage: def f(x): + ....: return (not x) or all(xx % 2 == x[0] % 2 for xx in x) + sage: list(subsets_with_hereditary_property(f, range(4))) [[], [0], [1], [2], [3], [0, 2], [1, 3]] Same, on two threads:: - sage: sorted(subsets_with_hereditary_property(f,range(4),ncpus=2)) + sage: sorted(subsets_with_hereditary_property(f, range(4), ncpus=2)) [[], [0], [0, 2], [1], [1, 3], [2], [3]] One can use this function to compute the independent sets of a graph. We @@ -71,33 +72,35 @@ def subsets_with_hereditary_property(f,X,max_obstruction_size=None,ncpus=1): have size 2. We can thus set ``max_obstruction_size=2``, which reduces the number of calls to `f` from 91 to 56:: - sage: num_calls=0 - sage: g = graphs.PetersenGraph() + sage: num_calls = 0 + sage: g = graphs.PetersenGraph() # optional - sage.graphs sage: def is_independent_set(S): ....: global num_calls - ....: num_calls+=1 - ....: return g.subgraph(S).size()==0 - sage: l1=list(subsets_with_hereditary_property(is_independent_set, g.vertices(sort=False))) - sage: num_calls + ....: num_calls += 1 + ....: return g.subgraph(S).size() == 0 + sage: l1 = list(subsets_with_hereditary_property(is_independent_set, # optional - sage.graphs + ....: g.vertices(sort=False))) + sage: num_calls # optional - sage.graphs 91 - sage: num_calls=0 - sage: l2=list(subsets_with_hereditary_property(is_independent_set, g.vertices(sort=False), max_obstruction_size=2)) - sage: num_calls + sage: num_calls = 0 + sage: l2 = list(subsets_with_hereditary_property(is_independent_set, # optional - sage.graphs + ....: g.vertices(sort=False), + ....: max_obstruction_size=2)) + sage: num_calls # optional - sage.graphs 56 - sage: l1==l2 + sage: l1 == l2 # optional - sage.graphs True TESTS:: - sage: list(subsets_with_hereditary_property(lambda x:False,range(4))) + sage: list(subsets_with_hereditary_property(lambda x: False, range(4))) [] - sage: list(subsets_with_hereditary_property(lambda x:len(x)<1,range(4))) + sage: list(subsets_with_hereditary_property(lambda x: len(x)<1, range(4))) [[]] - sage: list(subsets_with_hereditary_property(lambda x:True,range(2))) + sage: list(subsets_with_hereditary_property(lambda x: True, range(2))) [[], [0], [1], [0, 1]] """ from sage.data_structures.bitset import Bitset - from sage.parallel.decorate import parallel # About the implementation: # # 1) We work on X={0,...,n-1} but remember X to return correctly @@ -117,26 +120,26 @@ def subsets_with_hereditary_property(f,X,max_obstruction_size=None,ncpus=1): if max_obstruction_size is None: max_obstruction_size = n - bs = [Bitset([],1) for _ in range(n)] # collection of no-set - nforb=1 # number of no-sets stored - current_layer = [[]] # all yes-sets of size 'current_size' - current_size = 0 + bs = [Bitset([], 1) for _ in range(n)] # collection of no-set + nforb = 1 # number of no-sets stored + current_layer = [[]] # all yes-sets of size 'current_size' + current_size = 0 def explore_neighbors(s): r""" - Explores the successors of a set s. + Explore the successors of a set s. The successors of a set s are all the sets s+[i] where max(s)<i. This function returns them all as a partition `(yes_sets,no_sets)`. """ - new_yes_sets = [] - new_no_sets = [] - for i in range((s[-1]+1 if s else 0),n): # all ways to extend it - s_plus_i = s+[i] # the extended set - s_plus_i_c = Bitset(s_plus_i,n).complement() # .. and its complement + new_yes_sets = [] + new_no_sets = [] + for i in range((s[-1] + 1 if s else 0), n): # all ways to extend it + s_plus_i = s + [i] # the extended set + s_plus_i_c = Bitset(s_plus_i, n).complement() # .. and its complement # Filter a no-set using the data collected so far. - inter = Bitset([],nforb).complement() + inter = Bitset([], nforb).complement() for j in s_plus_i_c: inter.intersection_update(bs[j]) @@ -146,7 +149,7 @@ def explore_neighbors(s): new_yes_sets.append(s_plus_i) else: new_no_sets.append(s_plus_i) - return (new_yes_sets,new_no_sets) + return (new_yes_sets, new_no_sets) # The empty set if f([]): @@ -155,21 +158,22 @@ def explore_neighbors(s): return if ncpus != 1: + from sage.parallel.decorate import parallel explore_neighbors_paral = parallel(ncpus=ncpus)(explore_neighbors) # All sets of size 0, then size 1, then ... set_size = -1 while current_layer: - set_size += 1 - new_no_sets = [] - new_yes_sets = [] + set_size += 1 + new_no_sets = [] + new_yes_sets = [] if ncpus == 1: yes_no_iter = (explore_neighbors(s) for s in current_layer) else: - yes_no_iter = ((yes,no) for (_,(yes,no)) in explore_neighbors_paral(current_layer)) + yes_no_iter = ((yes, no) for (_, (yes, no)) in explore_neighbors_paral(current_layer)) - for yes,no in yes_no_iter: + for yes, no in yes_no_iter: new_yes_sets.extend(yes) new_no_sets.extend(no) for s in yes: @@ -179,13 +183,13 @@ def explore_neighbors(s): # Update bs with the new no-sets new_nforb = nforb + len(new_no_sets) - for b in bs: # resize the bitsets + for b in bs: # resize the bitsets b.add(new_nforb) b.discard(new_nforb) - for i,s in enumerate(new_no_sets): # Fill the new entries + for i, s in enumerate(new_no_sets): # Fill the new entries for j in X.difference(s): - bs[j].add(i+nforb) - nforb=new_nforb + bs[j].add(i + nforb) + nforb = new_nforb current_size += 1 # Did we forget to return X itself ? diff --git a/src/sage/combinat/subsets_pairwise.py b/src/sage/combinat/subsets_pairwise.py index fc64df2e48f..ed5613157f2 100644 --- a/src/sage/combinat/subsets_pairwise.py +++ b/src/sage/combinat/subsets_pairwise.py @@ -105,7 +105,7 @@ def __init__(self, ambient, predicate, maximal=False, element_class=Set_object_e # TODO: use self.element_class for consistency # At this point (2011/03) TestSuite fails if we do so self._element_class = element_class - RecursivelyEnumeratedSet_forest.__init__(self, algorithm = 'depth', category = FiniteEnumeratedSets()) + RecursivelyEnumeratedSet_forest.__init__(self, algorithm='depth', category=FiniteEnumeratedSets()) def __eq__(self, other): """ diff --git a/src/sage/combinat/subword_complex.py b/src/sage/combinat/subword_complex.py index b5455260aaa..de7eefe946e 100644 --- a/src/sage/combinat/subword_complex.py +++ b/src/sage/combinat/subword_complex.py @@ -83,13 +83,13 @@ sage: W = CoxeterGroup(['A',3]); I = list(W.index_set()) sage: Q = I + W.w0.coxeter_sorting_word(I) sage: S = SubwordComplex(Q,W.w0) - sage: S.brick_polytope() + sage: S.brick_polytope() # optional - sage.geometry.polyhedron A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 14 vertices sage: W = CoxeterGroup(['H',3]); I = list(W.index_set()) sage: Q = I + W.w0.coxeter_sorting_word(I) sage: S = SubwordComplex(Q,W.w0) - sage: S.brick_polytope() + sage: S.brick_polytope() # optional - sage.geometry.polyhedron doctest:...: RuntimeWarning: the polytope is built with rational vertices A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 32 vertices @@ -754,20 +754,20 @@ def plot(self, list_colors=None, labels=[], thickness=3, fontsize=14, sage: W = ReflectionGroup(['A',2]) # optional - gap3 sage: w = W.from_reduced_word([1,2,1]) # optional - gap3 sage: SC = SubwordComplex([1,2,1,2,1],w) # optional - gap3 - sage: F = SC([1,2]); F.plot() # optional - gap3 + sage: F = SC([1,2]); F.plot() # optional - gap3 sage.plot Graphics object consisting of 26 graphics primitives sage: W = CoxeterGroup(['A',2]) sage: w = W.from_reduced_word([1,2,1]) sage: SC = SubwordComplex([1,2,1,2,1],w) - sage: F = SC([1,2]); F.plot() + sage: F = SC([1,2]); F.plot() # optional - sage.plot Graphics object consisting of 26 graphics primitives sage: W = ReflectionGroup(['B',3]) # optional - gap3 sage: c = W.from_reduced_word([1,2,3]) # optional - gap3 sage: Q = c.reduced_word()*2 + W.w0.coxeter_sorting_word(c) # optional - gap3 sage: SC = SubwordComplex(Q, W.w0) # optional - gap3 - sage: F = SC[15]; F.plot() # optional - gap3 + sage: F = SC[15]; F.plot() # optional - gap3 sage.plot Graphics object consisting of 53 graphics primitives TESTS:: @@ -776,7 +776,7 @@ def plot(self, list_colors=None, labels=[], thickness=3, fontsize=14, sage: c = W.from_reduced_word([1,2,3,4]) # optional - gap3 sage: Q = c.reduced_word() + W.w0.coxeter_sorting_word(c) # optional - gap3 sage: SC = SubwordComplex(Q, W.w0) # optional - gap3 - sage: F = SC[1]; F.plot() # optional - gap3 + sage: F = SC[1]; F.plot() # optional - gap3 sage.plot Traceback (most recent call last): ... ValueError: plotting is currently only implemented for irreducibles types A, B, and C. @@ -785,7 +785,7 @@ def plot(self, list_colors=None, labels=[], thickness=3, fontsize=14, sage: c = W.from_reduced_word([1,2,3,4]) sage: Q = c.reduced_word() + W.w0.coxeter_sorting_word(c) sage: SC = SubwordComplex(Q, W.w0) - sage: F = SC[1]; F.plot() + sage: F = SC[1]; F.plot() # optional - sage.plot Traceback (most recent call last): ... ValueError: plotting is currently only implemented for irreducibles types A, B, and C. @@ -1131,7 +1131,6 @@ def __init__(self, Q, w, algorithm="inductive"): SimplicialComplex.__init__(self, maximal_faces=Fs, maximality_check=False, category=cat) - self.__custom_name = 'Subword complex' self._W = W try: T = W.coxeter_matrix().coxeter_type() diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index b8a0bebab44..3884747f825 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -1,3 +1,4 @@ +# optional - sage.combinat sage.modules sage.groups r""" Symmetric Group Algebra """ @@ -21,7 +22,7 @@ from sage.categories.weyl_groups import WeylGroups from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ -from sage.arith.all import factorial +from sage.arith.misc import factorial from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector from sage.groups.perm_gps.permgroup_element import PermutationGroupElement @@ -101,7 +102,7 @@ def SymmetricGroupAlgebra(R, W, category=None): sage: SGA.group() Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space) sage: SGA.an_element() - s1*s2*s3 + 3*s3*s2 + 2*s3 + 1 + s1*s2*s3 + 3*s2*s3*s1*s2 + 2*s3*s1 + 1 The preferred way to construct the symmetric group algebra is to go through the usual ``algebra`` method:: @@ -418,7 +419,7 @@ def _sibling(self, n): """ try: W = self.basis().keys().__class__(n) - except Exception: + except (AttributeError, TypeError, ValueError): raise NotImplementedError("Constructing the sibling algebra of a different order " "only implemented for PermutationGroup and SymmetricGroup") return SymmetricGroupAlgebra(self.base_ring(), W) @@ -1165,9 +1166,9 @@ def central_orthogonal_idempotent(self, la, block=True): big_coeff = character_table[lam_index][0] / denom character_row = character_table[lam_index] iaxpy(1, - {g: big_coeff * character_row[ind] - for ind in cycles for g in cycles[ind]}, - cpi) + {g: big_coeff * character_row[ind] + for ind in cycles for g in cycles[ind]}, + cpi) if not all(R(cpi[g].denominator()) for g in cpi): return None @@ -1339,14 +1340,13 @@ def rsw_shuffling_element(self, k): sage: def test_rsw_comm(n): ....: QSn = SymmetricGroupAlgebra(QQ, n) ....: rsws = [QSn.rsw_shuffling_element(k) for k in range(2, n)] - ....: return all( all( rsws[i] * rsws[j] == rsws[j] * rsws[i] - ....: for j in range(i) ) - ....: for i in range(len(rsws)) ) + ....: return all(ri * rsws[j] == rsws[j] * ri + ....: for i, ri in enumerate(rsws) for j in range(i)) sage: test_rsw_comm(3) True - sage: test_rsw_comm(4) + sage: test_rsw_comm(4) # long time True - sage: test_rsw_comm(5) # long time + sage: test_rsw_comm(5) # not tested True .. NOTE:: @@ -1544,6 +1544,46 @@ def complement(xs): return self.sum_of_monomials([self._indices(P(list(q) + complement(q))) for q in itertools.combinations(range(1, n + 1), int(k))]) + def specht_module(self, D): + r""" + Return the Specht module of ``self`` indexed by the diagram ``D``. + + EXAMPLES:: + + sage: SGA = SymmetricGroupAlgebra(QQ, 5) + sage: SM = SGA.specht_module(Partition([3,1,1])) + sage: SM + Specht module of [(0, 0), (0, 1), (0, 2), (1, 0), (2, 0)] over Rational Field + sage: s = SymmetricFunctions(QQ).s() + sage: s(SM.frobenius_image()) + s[3, 1, 1] + + sage: SM = SGA.specht_module([(1,1),(1,3),(2,2),(3,1),(3,2)]) + sage: SM + Specht module of [(1, 1), (1, 3), (2, 2), (3, 1), (3, 2)] over Rational Field + sage: s(SM.frobenius_image()) + s[2, 2, 1] + s[3, 1, 1] + s[3, 2] + """ + from sage.combinat.specht_module import SpechtModule + return SpechtModule(self, D) + + def specht_module_dimension(self, D): + r""" + Return the dimension of the Specht module of ``self`` indexed by ``D``. + + EXAMPLES:: + + sage: SGA = SymmetricGroupAlgebra(QQ, 5) + sage: SGA.specht_module_dimension(Partition([3,1,1])) + 6 + sage: SGA.specht_module_dimension([(1,1),(1,3),(2,2),(3,1),(3,2)]) + 16 + """ + from sage.combinat.specht_module import specht_module_spanning_set, _to_diagram + D = _to_diagram(D) + span_set = specht_module_spanning_set(D, self) + return matrix(self.base_ring(), [v.to_vector() for v in span_set]).rank() + def jucys_murphy(self, k): r""" Return the Jucys-Murphy element `J_k` (also known as a diff --git a/src/sage/combinat/symmetric_group_representations.py b/src/sage/combinat/symmetric_group_representations.py index 8a6b58ae87c..ee518756525 100644 --- a/src/sage/combinat/symmetric_group_representations.py +++ b/src/sage/combinat/symmetric_group_representations.py @@ -75,28 +75,28 @@ def SymmetricGroupRepresentation(partition, implementation="specht", :: - sage: orth = SymmetricGroupRepresentation([2,1], "orthogonal"); orth + sage: orth = SymmetricGroupRepresentation([2,1], "orthogonal"); orth # optional - sage.symbolic Orthogonal representation of the symmetric group corresponding to [2, 1] - sage: all(a*a.transpose() == a.parent().identity_matrix() for a in orth) + sage: all(a*a.transpose() == a.parent().identity_matrix() for a in orth) # optional - sage.symbolic True :: - sage: orth = SymmetricGroupRepresentation([3,2], "orthogonal"); orth + sage: orth = SymmetricGroupRepresentation([3,2], "orthogonal"); orth # optional - sage.symbolic Orthogonal representation of the symmetric group corresponding to [3, 2] - sage: orth([2,1,3,4,5]) + sage: orth([2,1,3,4,5]) # optional - sage.symbolic [ 1 0 0 0 0] [ 0 1 0 0 0] [ 0 0 -1 0 0] [ 0 0 0 1 0] [ 0 0 0 0 -1] - sage: orth([1,3,2,4,5]) + sage: orth([1,3,2,4,5]) # optional - sage.symbolic [ 1 0 0 0 0] [ 0 -1/2 1/2*sqrt(3) 0 0] [ 0 1/2*sqrt(3) 1/2 0 0] [ 0 0 0 -1/2 1/2*sqrt(3)] [ 0 0 0 1/2*sqrt(3) 1/2] - sage: orth([1,2,4,3,5]) + sage: orth([1,2,4,3,5]) # optional - sage.symbolic [ -1/3 2/3*sqrt(2) 0 0 0] [2/3*sqrt(2) 1/3 0 0 0] [ 0 0 1 0 0] @@ -200,13 +200,13 @@ def SymmetricGroupRepresentations(n, implementation="specht", ring=None, :: - sage: orth = SymmetricGroupRepresentations(3, "orthogonal"); orth + sage: orth = SymmetricGroupRepresentations(3, "orthogonal"); orth # optional - sage.symbolic Orthogonal representations of the symmetric group of order 3! over Symbolic Ring - sage: orth.list() + sage: orth.list() # optional - sage.symbolic [Orthogonal representation of the symmetric group corresponding to [3], Orthogonal representation of the symmetric group corresponding to [2, 1], Orthogonal representation of the symmetric group corresponding to [1, 1, 1]] - sage: orth([2,1])([1,2,3]) + sage: orth([2,1])([1,2,3]) # optional - sage.symbolic [1 0] [0 1] @@ -516,8 +516,8 @@ def __iter__(self): EXAMPLES:: - sage: orth = SymmetricGroupRepresentations(3, "orthogonal") - sage: for x in orth: print(x) + sage: orth = SymmetricGroupRepresentations(3, "orthogonal") # optional - sage.symbolic + sage: for x in orth: print(x) # optional - sage.symbolic Orthogonal representation of the symmetric group corresponding to [3] Orthogonal representation of the symmetric group corresponding to [2, 1] Orthogonal representation of the symmetric group corresponding to [1, 1, 1] @@ -540,8 +540,8 @@ def _yang_baxter_graph(self): EXAMPLES:: - sage: orth = SymmetricGroupRepresentation([3,2], "orthogonal") - sage: orth._yang_baxter_graph + sage: orth = SymmetricGroupRepresentation([3,2], "orthogonal") # optional - sage.symbolic + sage: orth._yang_baxter_graph # optional - sage.symbolic Yang-Baxter graph of [3, 2], with top vertex (0, -1, 2, 1, 0) """ Y = YangBaxterGraph_partition(self._partition) @@ -565,8 +565,8 @@ def _tableau_dict(self): EXAMPLES:: - sage: orth = SymmetricGroupRepresentation([3,2], "orthogonal") - sage: orth._tableau_dict + sage: orth = SymmetricGroupRepresentation([3,2], "orthogonal") # optional - sage.symbolic + sage: orth._tableau_dict # optional - sage.symbolic {(0, -1, 2, 1, 0): [[1, 2, 3], [4, 5]], (0, 2, -1, 1, 0): [[1, 2, 4], [3, 5]], (0, 2, 1, -1, 0): [[1, 3, 4], [2, 5]], @@ -576,7 +576,7 @@ def _tableau_dict(self): # construct a dictionary pairing vertices with tableau t = StandardTableaux(self._partition).last() tableau_dict = {self._yang_baxter_graph.root(): t} - for (u, w, (i, beta)) in self._yang_baxter_graph._edges_in_bfs(): + for u, w, (i, _) in self._yang_baxter_graph._edges_in_bfs(): # TODO: improve the following si = PermutationConstructor((i, i + 1)) tableau_dict[w] = Tableau([[si(b) for b in row] @@ -591,8 +591,8 @@ def _word_dict(self): EXAMPLES:: - sage: orth = SymmetricGroupRepresentation([3,2], "orthogonal") - sage: orth._word_dict + sage: orth = SymmetricGroupRepresentation([3,2], "orthogonal") # optional - sage.symbolic + sage: orth._word_dict # optional - sage.symbolic {(0, -1, 2, 1, 0): (4, 5, 1, 2, 3), (0, 2, -1, 1, 0): (3, 5, 1, 2, 4), (0, 2, 1, -1, 0): (2, 5, 1, 3, 4), @@ -610,11 +610,11 @@ def representation_matrix_for_simple_transposition(self, i): EXAMPLES:: - sage: orth = SymmetricGroupRepresentation([2,1], "orthogonal") - sage: orth.representation_matrix_for_simple_transposition(1) + sage: orth = SymmetricGroupRepresentation([2,1], "orthogonal") # optional - sage.symbolic + sage: orth.representation_matrix_for_simple_transposition(1) # optional - sage.symbolic [ 1 0] [ 0 -1] - sage: orth.representation_matrix_for_simple_transposition(2) + sage: orth.representation_matrix_for_simple_transposition(2) # optional - sage.symbolic [ -1/2 1/2*sqrt(3)] [1/2*sqrt(3) 1/2] @@ -663,11 +663,11 @@ def _representation_matrix_uncached(self, permutation): EXAMPLES:: - sage: orth = SymmetricGroupRepresentation([2,1], "orthogonal") - sage: orth._representation_matrix_uncached(Permutation([2,1,3])) + sage: orth = SymmetricGroupRepresentation([2,1], "orthogonal") # optional - sage.symbolic + sage: orth._representation_matrix_uncached(Permutation([2,1,3])) # optional - sage.symbolic [ 1 0] [ 0 -1] - sage: orth._representation_matrix_uncached(Permutation([1,3,2])) + sage: orth._representation_matrix_uncached(Permutation([1,3,2])) # optional - sage.symbolic [ -1/2 1/2*sqrt(3)] [1/2*sqrt(3) 1/2] @@ -696,11 +696,11 @@ def representation_matrix(self, permutation): EXAMPLES:: - sage: orth = SymmetricGroupRepresentation([2,1], "orthogonal") - sage: orth.representation_matrix(Permutation([2,1,3])) + sage: orth = SymmetricGroupRepresentation([2,1], "orthogonal") # optional - sage.symbolic + sage: orth.representation_matrix(Permutation([2,1,3])) # optional - sage.symbolic [ 1 0] [ 0 -1] - sage: orth.representation_matrix(Permutation([1,3,2])) + sage: orth.representation_matrix(Permutation([1,3,2])) # optional - sage.symbolic [ -1/2 1/2*sqrt(3)] [1/2*sqrt(3) 1/2] @@ -779,7 +779,7 @@ def _repr_(self): EXAMPLES:: - sage: SymmetricGroupRepresentation([2,1], "orthogonal") + sage: SymmetricGroupRepresentation([2,1], "orthogonal") # optional - sage.symbolic Orthogonal representation of the symmetric group corresponding to [2, 1] """ return "Orthogonal representation of the symmetric group corresponding to {}".format(self._partition) @@ -796,8 +796,8 @@ def _2x2_matrix_entries(self, beta): EXAMPLES:: - sage: orth = SymmetricGroupRepresentation([2,1], "orthogonal") - sage: orth._2x2_matrix_entries(1/2) + sage: orth = SymmetricGroupRepresentation([2,1], "orthogonal") # optional - sage.symbolic + sage: orth._2x2_matrix_entries(1/2) # optional - sage.symbolic (-1/2, 1/2*sqrt(3), 1/2*sqrt(3), 1/2) """ return (-beta, sqrt(1 - beta**2), sqrt(1 - beta**2), beta) @@ -815,7 +815,7 @@ def _repr_(self): EXAMPLES:: sage: from sage.combinat.symmetric_group_representations import YoungRepresentations_Orthogonal - sage: YoungRepresentations_Orthogonal(3) + sage: YoungRepresentations_Orthogonal(3) # optional - sage.symbolic Orthogonal representations of the symmetric group of order 3! over Symbolic Ring """ return "Orthogonal representations of the symmetric group of order %s! over %s" % (self._n, self._ring) diff --git a/src/sage/combinat/t_sequences.py b/src/sage/combinat/t_sequences.py index 883d55c87bd..7f0e8492ca4 100644 --- a/src/sage/combinat/t_sequences.py +++ b/src/sage/combinat/t_sequences.py @@ -44,7 +44,7 @@ from sage.structure.sequence import Sequence -def _nonperiodic_autocorrelation(sequences, j): +def _nonperiodic_autocorrelation(sequences, j): r""" Compute the nonperiodic autocorrelation of a familiy of sequences. @@ -66,11 +66,12 @@ def _nonperiodic_autocorrelation(sequences, j): t = len(sequences[0]) result = 0 - for i in range(t-j): + for i in range(t - j): for seq in sequences: - result += seq[i]*seq[i+j] + result += seq[i] * seq[i + j] return result + def is_skew(seq, verbose=False): r""" Check if the given sequence is skew. @@ -102,10 +103,9 @@ def is_skew(seq, verbose=False): Sequence should be of even length False """ - n = len(seq) - if n%2 == 1: + if n % 2: if verbose: print('Sequence should be of even length') return False @@ -117,7 +117,8 @@ def is_skew(seq, verbose=False): return False return True -def is_symmetric(seq, verbose=False): + +def is_symmetric(seq, verbose=False) -> bool: r""" Check if the given sequence is symmetric. @@ -148,10 +149,9 @@ def is_symmetric(seq, verbose=False): Sequence should be of odd length False """ - n = len(seq) - if n%2 == 0: + if n % 2 == 0: if verbose: print('Sequence should be of odd length') return False @@ -215,7 +215,6 @@ def is_T_sequences_set(sequences, verbose=False): print(f"T-Sequence should contain 4 sequences, found {len(sequences)} instead") return False - t = len(sequences[0]) for i in range(t): @@ -240,6 +239,7 @@ def is_T_sequences_set(sequences, verbose=False): return True + def turyn_sequences_smallcases(l, existence=False): r""" Construction of Turyn sequences for small values of `l`. @@ -297,6 +297,7 @@ def turyn_sequences_smallcases(l, existence=False): return list(map(Sequence, db[l])) + def T_sequences_construction_from_base_sequences(base_sequences, check=True): r""" Construct T-sequences of length `2n+p` from base sequences of length `n+p, n+p, n, n`. @@ -375,6 +376,7 @@ def zero_seq(n): assert is_T_sequences_set(res) return res + def T_sequences_construction_from_turyn_sequences(turyn_sequences, check=True): r""" Construct T-sequences of length `4l-1` from Turyn sequences of length `l`. @@ -431,13 +433,13 @@ def zero_seq(n): def interleave(seq1, seq2): res = [] for i in range(len(seq1) + len(seq2)): - if i%2 == 0: + if i % 2 == 0: res.append(seq1[i//2]) else: res.append(seq2[i//2]) return res - X1 = Sequence([1]+ zero_seq(4*l-2)) + X1 = Sequence([1] + zero_seq(4*l-2)) X2 = Sequence([0] + interleave(X, Y) + zero_seq(2*l-1)) X3 = Sequence(zero_seq(2*l) + interleave(U, zero_seq(l-1))) X4 = Sequence(zero_seq(2*l) + interleave(zero_seq(l), V)) @@ -447,6 +449,7 @@ def interleave(seq1, seq2): assert is_T_sequences_set(res) return res + def T_sequences_smallcases(t, existence=False, check=True): r""" Construct T-sequences for some small values of `t`. @@ -502,7 +505,7 @@ def T_sequences_smallcases(t, existence=False, check=True): [1,-1,-1,0,0,-1,1,-1]+[0]*8+[1,-1,-1,0,0,-1,-1]+[0]*24, [0,0,0,-1,1,0,0,0,-1,-1,-1,1,1,1,1,1,0,0,0,1,-1,0,0,1]+[0]*23, [0]*26+[-1,0,1,0,0,0,0,1,-1,1,1,1,0,0,0,0,1,0,-1,0,0], - [0]*24+ [1,1,0,-1,0,-1,1,1,-1,0,0,0,0,0,-1,1,-1,-1,0,-1,0,-1,1] + [0]*24 + [1,1,0,-1,0,-1,1,1,-1,0,0,0,0,0,-1,1,-1,-1,0,-1,0,-1,1] ], 65: [ [0]*33+[1,1,1,1,1,-1,-1,1,1,-1,1,-1,1,1,-1,-1,1,1,1,1,1,-1,-1,1,-1,1,-1,1,-1,-1,1,1], @@ -521,17 +524,17 @@ def T_sequences_smallcases(t, existence=False, check=True): if t in db: if existence: return True - sequences = list(map(Sequence, db[t])) + sequences = list(map(Sequence, db[t])) if check: assert is_T_sequences_set(sequences) return sequences - if (t+1) %2 == 0 and turyn_sequences_smallcases((t+1)//2, existence=True): + if (t+1) % 2 == 0 and turyn_sequences_smallcases((t+1)//2, existence=True): if existence: return True turyn_seqs = turyn_sequences_smallcases((t+1)//2) return T_sequences_construction_from_base_sequences(turyn_seqs, check=check) - if (t+1)%4 == 0 and turyn_sequences_smallcases((t+1)//4, existence=True): + if (t+1) % 4 == 0 and turyn_sequences_smallcases((t+1)//4, existence=True): if existence: return True turyn_seqs = turyn_sequences_smallcases((t+1)//4) @@ -539,7 +542,7 @@ def T_sequences_smallcases(t, existence=False, check=True): for p in range(1, t): n = (t-p)//2 - if (t-p)%2 == 0 and base_sequences_smallcases(n, p, existence=True): + if (t-p) % 2 == 0 and base_sequences_smallcases(n, p, existence=True): if existence: return True base_seqs = base_sequences_smallcases(n, p, check=False) @@ -684,7 +687,6 @@ def is_base_sequences_tuple(base_sequences, verbose=False): print(f'Base sequences should only contiain -1, +1, found {el}') return False - for j in range(1, n+p): autocorr = _nonperiodic_autocorrelation(A, j) + _nonperiodic_autocorrelation(B, j) + _nonperiodic_autocorrelation(C, j) + _nonperiodic_autocorrelation(D, j) if autocorr != 0: @@ -694,6 +696,7 @@ def is_base_sequences_tuple(base_sequences, verbose=False): return True + def turyn_type_sequences_smallcases(n, existence=False): r""" Construction of Turyn type sequences for small values of `n`. @@ -750,10 +753,10 @@ def convertLists(hexstring): seqs[i].append(-1) last = bin(int(hexstring[-1], 16))[2:].zfill(3) for i in range(3): - if last[i] == '0': - seqs[i].append(1) - else: - seqs[i].append(-1) + if last[i] == '0': + seqs[i].append(1) + else: + seqs[i].append(-1) return seqs db = { @@ -784,6 +787,7 @@ def convertLists(hexstring): return convertLists(db[n]) + def base_sequences_smallcases(n, p, existence=False, check=True): r"""Construct base sequences of length `n+p, n+p, n, n` from available data. @@ -849,9 +853,9 @@ def base_sequences_smallcases(n, p, existence=False, check=True): return True turyn_type_seqs = turyn_type_sequences_smallcases(n) return base_sequences_construction(turyn_type_seqs, check=check) - if p == 1 and turyn_sequences_smallcases(n+p, existence=True): + if p == 1 and turyn_sequences_smallcases(n + p, existence=True): if existence: return True - return turyn_sequences_smallcases(n+p) + return turyn_sequences_smallcases(n + p) raise ValueError(f'Base sequences of order {n+p}, {n+p}, {n}, {n} not yet implemented.') diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 1105a3ea177..cd3c902e1c9 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -85,35 +85,35 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from itertools import repeat -from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets -from sage.sets.family import Family -from sage.sets.non_negative_integers import NonNegativeIntegers -from sage.structure.global_options import GlobalOptions -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.list_clone import ClonableList -from sage.structure.parent import Parent -from sage.structure.richcmp import richcmp, richcmp_method -from sage.misc.persist import register_unpickle_override -from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from sage.rings.infinity import PlusInfinity -from sage.arith.all import factorial, binomial -from sage.arith.misc import multinomial -from sage.rings.integer import Integer -from sage.combinat.composition import Composition, Compositions -from sage.combinat.integer_vector import IntegerVectors, integer_vectors_nk_fast_iter + import sage.libs.symmetrica.all as symmetrica import sage.misc.prandom as random -from sage.combinat import permutation -from sage.groups.perm_gps.permgroup import PermutationGroup -from sage.misc.misc_c import prod -from sage.misc.misc import powerset + +from sage.arith.misc import binomial, factorial, multinomial from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.sets_cat import Sets - +from sage.combinat import permutation from sage.combinat.combinatorial_map import combinatorial_map +from sage.combinat.composition import Composition, Compositions +from sage.combinat.integer_vector import IntegerVectors, integer_vectors_nk_fast_iter from sage.combinat.posets.posets import Poset +from sage.groups.perm_gps.permgroup import PermutationGroup +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.combinat.subset import powerset +from sage.misc.misc_c import prod +from sage.misc.persist import register_unpickle_override +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.infinity import PlusInfinity +from sage.rings.integer import Integer +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets +from sage.sets.family import Family +from sage.sets.non_negative_integers import NonNegativeIntegers +from sage.structure.global_options import GlobalOptions +from sage.structure.list_clone import ClonableList +from sage.structure.parent import Parent +from sage.structure.richcmp import richcmp, richcmp_method +from sage.structure.unique_representation import UniqueRepresentation @richcmp_method @@ -233,7 +233,7 @@ def __init__(self, parent, t, check=True): A tableau is shallowly immutable. See :trac:`15862`. The entries themselves may be mutable objects, though in that case the - resulting Tableau should be unhashable. + resulting Tableau should be unhashable. :: sage: T = Tableau([[1,2],[2]]) sage: t0 = T[0] @@ -359,7 +359,7 @@ def _repr_(self): 1,2,3/4,5 sage: Tableaux.options._reset() """ - return self.parent().options._dispatch(self,'_repr_','display') + return self.parent().options._dispatch(self, '_repr_', 'display') def _repr_list(self): """ @@ -392,6 +392,11 @@ def _repr_diagram(self): sage: print(t._repr_diagram()) 4 5 1 2 3 + sage: Tableaux.options.convention='russian' + sage: print(t._repr_diagram()) + 5 3 + 4 2 + 1 sage: Tableaux.options._reset() TESTS: @@ -410,15 +415,34 @@ def _repr_diagram(self): str_tab = [[str(data) for data in row] for row in self] col_widths = [2]*len(str_tab[0]) for row in str_tab: - for i,e in enumerate(row): + for i, e in enumerate(row): col_widths[i] = max(col_widths[i], len(e)) + if self.parent().options('convention') == "Russian": + col_width = max(col_widths) + 1 + max_height = max(a + len(val) for a, val in enumerate(str_tab)) + str_list = [] + for i in range(max_height): + st = ' ' * ((max_height - i - 1) * col_width) + for a in range(i + 1): + b = i - a + if len(str_tab[b:]) > 0 and len(str_tab[b][a:]) > 0: + st += str_tab[b][a].rjust(col_width, ' ').ljust(col_width * 2 - 1, ' ') + else: + st += ' ' * (col_width * 2 - 1) + str_list.append(st) + import re + mm = min(len(re.search('^ +', sline)[0]) for sline in str_list) - 1 + str_list = [sline[mm:] for sline in str_list] + str_list.reverse() + return '\n'.join(str_list) + if self.parent().options('convention') == "French": str_tab = reversed(str_tab) return "\n".join(" " - + " ".join("{:>{width}}".format(e,width=col_widths[i]) - for i,e in enumerate(row)) + + " ".join("{:>{width}}".format(e, width=col_widths[i]) + for i, e in enumerate(row)) for row in str_tab) def _repr_compact(self): @@ -437,7 +461,7 @@ def _repr_compact(self): return '/'.join(','.join('%s' % r for r in row) for row in self) def _ascii_art_(self): - """ + r""" TESTS:: sage: ascii_art(list(StandardTableaux(3))) @@ -463,9 +487,23 @@ def _ascii_art_(self): [ 3 ] [ 2 3 2 ] [ 1 2 3, 1 3, 1 2, 1 ] + sage: Tableaux.options(convention="russian", ascii_art="table") + sage: ascii_art(list(StandardTableaux(3))) + [ / \ / \ ] + [ / 3 / \ 3 \ ] + [ / \ / / \ / \ / \ / \ \ / \ ] + [ / 2 / \ 2 X 3 / \ 3 X 2 / \ 2 \ ] + [ / \ / \ / \ / \ / \ / \ / \ ] + [ \ 1 / \ 1 / \ 1 / \ 1 / ] + [ \ / , \ / , \ / , \ / ] + sage: Tableaux.options(ascii_art="repr") + sage: ascii_art(list(StandardTableaux(3))) + [ 3 3 ] + [ 2 2 3 3 2 2 ] + [ 1 , 1 , 1 , 1 ] sage: Tableaux.options._reset() """ - ascii = self.parent().options._dispatch(self,'_ascii_art_','ascii_art') + ascii = self.parent().options._dispatch(self, '_ascii_art_', 'ascii_art') from sage.typeset.ascii_art import AsciiArt return AsciiArt(ascii.splitlines()) @@ -482,8 +520,7 @@ def _unicode_art_(self): โ”‚ 5 โ”‚ โ””โ”€โ”€โ”€โ”˜ sage: unicode_art(Tableau([])) - โ”Œโ” - โ””โ”˜ + <BLANKLINE> """ from sage.typeset.unicode_art import UnicodeArt return UnicodeArt(self._ascii_art_table(use_unicode=True).splitlines()) @@ -491,7 +528,7 @@ def _unicode_art_(self): _ascii_art_repr = _repr_diagram def _ascii_art_table(self, use_unicode=False): - """ + r""" TESTS: We check that :trac:`16487` is fixed:: @@ -510,9 +547,21 @@ def _ascii_art_table(self, use_unicode=False): +---+---+---+ | 1 | 2 | 3 | +---+---+---+ + sage: Tableaux.options.convention="russian" + sage: print(t._ascii_art_table()) + / \ / \ + / 5 X 3 / + / \ / \ / + \ 4 X 2 / + \ / \ / + \ 1 / + \ / sage: t = Tableau([]); print(t._ascii_art_table()) - ++ - ++ + <BLANKLINE> + + sage: Tableaux.options.convention="french" + sage: print(t._ascii_art_table()) + <BLANKLINE> sage: Tableaux.options._reset() sage: t = Tableau([[1,2,3,10,15],[12,15,17]]) @@ -546,6 +595,22 @@ def _ascii_art_table(self, use_unicode=False): +----+----+----+---+ | 1 | 2 | 15 | 7 | +----+----+----+---+ + sage: Tableaux.options.convention="russian" + sage: ascii_art(t) + / \ / \ / \ / \ + / \ / \ / \ / \ + \ 9 X 10 X 6 X 7 / + \ / \ / \ / \ / + \ / \ / \ / \ / + \ 8 X 5 X 15 / + \ / \ / \ / + \ / \ / \ / + \ 12 X 2 / + \ / \ / + \ / \ / + \ 1 / + \ / + \ / sage: Tableaux.options._reset() Unicode version:: @@ -573,14 +638,31 @@ def _ascii_art_table(self, use_unicode=False): โ”œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ” โ”‚ 1 โ”‚ 2 โ”‚ 15 โ”‚ 7 โ”‚ โ””โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜ + sage: Tableaux.options.convention="russian" + sage: print(t._ascii_art_table(use_unicode=True)) + โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ + โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ + โ•ฒ 9 โ•ณ 10 โ•ฒ โ•ฑ 7 โ•ฑ + โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ + โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ + โ•ฒ 8 โ•ณ 5 โ•ณ 15 โ•ฑ + โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ + โ•ฒ โ•ฑ โ•ฒ โ•ฑ โ•ฒ โ•ฑ + โ•ฒ 12 โ•ณ 2 โ•ฑ + โ•ฒ โ•ฑ โ•ฒ โ•ฑ + โ•ฒ โ•ฑ โ•ฒ โ•ฑ + โ•ฒ 1 โ•ฑ + โ•ฒ โ•ฑ + โ•ฒ โ•ฑ sage: Tableaux.options._reset() """ from sage.combinat.output import ascii_art_table + self.parent().options('convention') return ascii_art_table(self, use_unicode=use_unicode, convention=self.parent().options('convention')) def _ascii_art_compact(self): - """ + r""" TESTS: We check that :trac:`16487` is fixed:: @@ -593,6 +675,11 @@ def _ascii_art_compact(self): sage: print(t._ascii_art_compact()) |4|5| |1|2|3| + sage: Tableaux.options.convention="russian" + sage: print(t._ascii_art_compact()) + /5X3/ + \4X2/ + \1/ sage: Tableaux.options._reset() sage: t = Tableau([[1,2,3,10,15],[12,15,17]]) @@ -607,6 +694,9 @@ def _ascii_art_compact(self): if not self: return "." + if self.parent().options('convention') == "Russian": + from sage.combinat.output import ascii_art_table_russian + return ascii_art_table_russian(self, compact=True) if self.parent().options('convention') == "English": T = self else: @@ -616,12 +706,12 @@ def _ascii_art_compact(self): str_tab = [[str(_) for _ in row] for row in T] col_widths = [1]*len(self[0]) for row in str_tab: - for i,e in enumerate(row): + for i, e in enumerate(row): col_widths[i] = max(col_widths[i], len(e)) return "\n".join("|" + "|".join("{:^{width}}".format(e, width=col_widths[i]) - for i,e in enumerate(row)) + for i, e in enumerate(row)) + "|" for row in str_tab) def _latex_(self): @@ -648,11 +738,21 @@ def _latex_(self): \lr{1}&\lr{1}&\lr{2}\\\cline{1-3} \end{array}$} } + sage: Tableaux.options.convention="russian" + sage: latex(t) # indirect doctest + {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{\rotatebox{45}{$\begin{array}[t]{*{3}c}\cline{1-1} + \lr{\rotatebox{-45}{3}}\\\cline{1-2} + \lr{\rotatebox{-45}{2}}&\lr{\rotatebox{-45}{3}}\\\cline{1-3} + \lr{\rotatebox{-45}{1}}&\lr{\rotatebox{-45}{1}}&\lr{\rotatebox{-45}{2}}\\\cline{1-3} + \end{array}$}} + } + sage: Tableaux.options._reset() """ - return self.parent().options._dispatch(self,'_latex_', 'latex') + return self.parent().options._dispatch(self, '_latex_', 'latex') - _latex_list=_repr_list + _latex_list = _repr_list def _latex_diagram(self): r""" @@ -693,11 +793,11 @@ def __truediv__(self, t): ValueError: the shape of the tableau must contain the partition """ from sage.combinat.partition import _Partitions - #if t is a list, convert it to a partition first + # if t is a list, convert it to a partition first if isinstance(t, list): t = _Partitions(t) - #Check to make sure that tableau shape contains t + # Check to make sure that tableau shape contains t if not self.shape().contains(t): raise ValueError("the shape of the tableau must contain the partition") @@ -736,9 +836,9 @@ def __call__(self, *cell): IndexError: the cell (3,3) is not contained in [[1, 2, 3], [4, 5]] """ try: - i,j = cell + i, j = cell except ValueError: - i,j = cell[0] + i, j = cell[0] try: return self[i][j] @@ -749,7 +849,8 @@ def level(self): """ Return the level of ``self``, which is always 1. - This function exists mainly for compatibility with :class:`TableauTuple`. + This function exists mainly for compatibility with + :class:`TableauTuple`. EXAMPLES:: @@ -761,8 +862,8 @@ def level(self): def components(self): """ This function returns a list containing itself. It exists mainly for - compatibility with :class:`TableauTuple` as it allows constructions like the - example below. + compatibility with :class:`TableauTuple` as it allows constructions + like the example below. EXAMPLES:: @@ -811,7 +912,7 @@ def corners(self): """ return self.shape().corners() - @combinatorial_map(order=2,name='conjugate') + @combinatorial_map(order=2, name='conjugate') def conjugate(self): """ Return the conjugate of ``self``. @@ -852,6 +953,11 @@ def pp(self): 5 3 4 1 2 3 + sage: Tableaux.options.convention="russian" + sage: T.pp() + 5 4 3 + 3 2 + 1 sage: Tableaux.options._reset() """ print(self._repr_diagram()) @@ -860,6 +966,37 @@ def plot(self, descents=False): r""" Return a plot ``self``. + If English notation is set then the first row of the tableau is on the + top: + + .. PLOT:: + :width: 200 px + + t = Tableau([[1,2,3,4],[2,3],[5]]) + Tableaux.options.convention="english" + sphinx_plot(t.plot()) + + If French notation is set, the first row of the tableau is on + the bottom: + + .. PLOT:: + :width: 200 px + + t = Tableau([[1,2,3,4],[2,3],[5]]) + Tableaux.options.convention="french" + sphinx_plot(t.plot()) + Tableaux.options.convention="english" + + If Russian notation is set, we tilt the French notation by 45 degrees: + + .. PLOT:: + :width: 200 px + + t = Tableau([[1,2,3,4],[2,3],[5]]) + Tableaux.options.convention="russian" + sphinx_plot(t.plot()) + Tableaux.options.convention="english" + INPUT: - ``descents`` -- boolean (default: ``False``); if ``True``, @@ -869,15 +1006,15 @@ def plot(self, descents=False): EXAMPLES:: sage: t = Tableau([[1,2,4],[3]]) - sage: t.plot() + sage: t.plot() # optional - sage.plot Graphics object consisting of 11 graphics primitives - sage: t.plot(descents=True) + sage: t.plot(descents=True) # optional - sage.plot Graphics object consisting of 12 graphics primitives sage: t = Tableau([[2,2,4],[3]]) - sage: t.plot() + sage: t.plot() # optional - sage.plot Graphics object consisting of 11 graphics primitives - sage: t.plot(descents=True) + sage: t.plot(descents=True) # optional - sage.plot Traceback (most recent call last): ... ValueError: the tableau must be standard for 'descents=True' @@ -889,25 +1026,62 @@ def plot(self, descents=False): if descents and not self.is_standard(): raise ValueError("the tableau must be standard for 'descents=True'") + # For English we build up to down for French, down to up + if self.parent().options('convention') == "English": + m = 1 + else: + m = -1 + p = self.shape() + r = p.conjugate() - G = line([(0,0),(p[0],0)], axes=False, figsize=1.5) + # Increases the height + if self.parent().options('convention') == "Russian": + pp = p # h + rr = r + h = [-i-1 for i in range(len(p))] + v = [i+1 for i in range(len(r))] + + else: + pp = [0] * len(p) + rr = [0] * len(r) + h = [0] * len(p) + v = [0] * len(r) + + G = line([(0, 0), (p[0], pp[0])], axes=False, figsize=1.5) for i in range(len(p)): - G += line([(0,-i-1), (p[i],-i-1)]) + G += line([(h[i], m*(-i-1)), (h[i]+p[i], pp[i]+m*(-i-1))]) - r = p.conjugate() - G += line([(0,0),(0,-r[0])]) + G += line([(0, 0), (-rr[0], m*-r[0])]) for i in range(len(r)): - G += line([(i+1,0),(i+1,-r[i])]) + G += line([(i+1, v[i]), (i+1-rr[i], v[i]+m*-r[i])]) if descents: t = StandardTableau(self) for i in t.standard_descents(): c = t.cells_containing(i)[0] - G += polygon([(c[1],-c[0]), (c[1]+1,-c[0]), (c[1]+1,-c[0]-1), (c[1],-c[0]-1)], rgbcolor=(1,0,1)) - - for c in self.cells(): - G += text(str(self.entry(c)), (c[1]+0.5,-c[0]-0.5)) + if self.parent().options('convention') == "Russian": + G += polygon([(c[1]+1-v[c[0]], m*(-c[1]-c[0])), + (c[1]+2-v[c[0]], m*(-c[1]-c[0]-1)), + (c[1]+1-v[c[0]], m*(-c[1]-c[0]-2)), + (c[1]-v[c[0]], m*(-c[1]-c[0]-1)) + ], + rgbcolor=(1, 0, 1) + ) + else: + G += polygon([(c[1], m*-c[0]), + (c[1]+1, m*-c[0]), + (c[1]+1, m*(-c[0]-1)), + (c[1], m*(-c[0]-1)) + ], + rgbcolor=(1, 0, 1)) + + if self.parent().options('convention') == "Russian": + for c in self.cells(): + G += text(str(self.entry(c)), (c[1]+1-v[c[0]], m*(-c[1]-c[0]-1))) + else: + for c in self.cells(): + G += text(str(self.entry(c)), (c[1]+0.5, m*(-c[0]-0.5))) return G @@ -981,10 +1155,10 @@ def descents(self): [(1, 0), (1, 1)] """ descents = [] - for i in range(1,len(self)): + for i in range(1, len(self)): for j in range(len(self[i])): if self[i][j] > self[i-1][j]: - descents.append((i,j)) + descents.append((i, j)) return descents def major_index(self): @@ -1015,7 +1189,7 @@ def major_index(self): """ descents = self.descents() p = self.shape() - return len(descents) + sum([ p.leg_length(*d) for d in descents ]) + return len(descents) + sum([p.leg_length(*d) for d in descents]) def inversions(self): """ @@ -1048,13 +1222,13 @@ def inversions(self): # find the d that satisfy condition 1 for k in range(j+1, len(row)): if entry > row[k]: - inversions.append( ((i,j),(i,k)) ) + inversions.append(((i, j), (i, k))) # find the d that satisfy condition 2 if i == 0: continue for k in range(j): if entry > previous_row[k]: - inversions.append( ((i,j),(i-1,k)) ) + inversions.append(((i, j), (i-1, k))) previous_row = row return inversions @@ -1102,19 +1276,19 @@ def to_sign_matrix(self, max_entry=None): EXAMPLES:: sage: t = SemistandardTableau([[1,1,1,2,4],[3,3,4],[4,5],[6,6]]) - sage: t.to_sign_matrix(6) + sage: t.to_sign_matrix(6) # optional - sage.modules [ 0 0 0 1 0 0] [ 0 1 0 -1 0 0] [ 1 -1 0 1 0 0] [ 0 0 1 -1 1 1] [ 0 0 0 1 -1 0] sage: t = Tableau([[1,2,4],[3,5]]) - sage: t.to_sign_matrix(7) + sage: t.to_sign_matrix(7) # optional - sage.modules [ 0 0 0 1 0 0 0] [ 0 1 0 -1 1 0 0] [ 1 -1 1 0 -1 0 0] sage: t = Tableau([(4,5,4,3),(2,1,3)]) - sage: t.to_sign_matrix(5) + sage: t.to_sign_matrix(5) # optional - sage.modules [ 0 0 1 0 0] [ 0 0 0 1 0] [ 1 0 -1 -1 1] @@ -1133,19 +1307,19 @@ def to_sign_matrix(self, max_entry=None): raise ValueError("the entries must be non-negative integers") from sage.matrix.matrix_space import MatrixSpace if max_entry is None: - max_entry=max([max(c) for c in self]) + max_entry = max([max(c) for c in self]) MS = MatrixSpace(ZZ, len(self[0]), max_entry) Tconj = self.conjugate() - l = len(Tconj) - d = {(l-i-1,elem-1): 1 for i, row in enumerate(Tconj) for elem in row} + conj_len = len(Tconj) + d = {(conj_len-i-1, elem-1): 1 for i, row in enumerate(Tconj) for elem in row} partial_sum_matrix = MS(d) from copy import copy sign_matrix = copy(MS.zero()) for j in range(max_entry): - sign_matrix[0,j] = partial_sum_matrix[0,j] - for i in range(1,l): + sign_matrix[0, j] = partial_sum_matrix[0, j] + for i in range(1, conj_len): for j in range(max_entry): - sign_matrix[i,j] = partial_sum_matrix[i,j] - partial_sum_matrix[i-1,j] + sign_matrix[i, j] = partial_sum_matrix[i, j] - partial_sum_matrix[i-1, j] return sign_matrix def schuetzenberger_involution(self, n=None, check=True): @@ -1212,7 +1386,7 @@ def schuetzenberger_involution(self, n=None, check=True): return SemistandardTableau(list(t)) return t - @combinatorial_map(order=2,name='evacuation') + @combinatorial_map(order=2, name='evacuation') def evacuation(self, n=None, check=True): r""" Return the evacuation of the tableau ``self``. @@ -1259,7 +1433,7 @@ def evacuation(self, n=None, check=True): sage: s.parent() Standard tableaux """ - return self.schuetzenberger_involution(n,check) + return self.schuetzenberger_involution(n, check) @combinatorial_map(name="standardization") def standardization(self, check=True): @@ -1475,7 +1649,7 @@ def entry(self, cell): sage: t.entry( (1,1) ) 4 """ - i,j = cell + i, j = cell return self[i][j] def weight(self): @@ -1547,7 +1721,7 @@ def is_row_strict(self): sage: Tableau([[5, 3], [2, 4]]).is_row_strict() False """ - return all(row[i]<row[i+1] for row in self for i in range(len(row)-1)) + return all(row[i] < row[i+1] for row in self for i in range(len(row)-1)) def is_row_increasing(self, weak=False): r""" @@ -1719,7 +1893,8 @@ def is_rectangular(self): def vertical_flip(self): """ - Return the tableau obtained by vertically flipping the tableau ``self``. + Return the tableau obtained by vertically flipping the tableau + ``self``. This only works for rectangular tableaux. @@ -1747,7 +1922,7 @@ def rotate_180(self): if not self.is_rectangular(): raise TypeError("the tableau must be rectangular to use rotate_180()") - return Tableau([ [l for l in reversed(row)] for row in reversed(self) ]) + return Tableau([[rline for rline in reversed(row)] for row in reversed(self)]) def cells(self): """ @@ -1763,7 +1938,7 @@ def cells(self): """ s = [] for i, row in enumerate(self): - s += [ (i,j) for j in range(len(row)) ] + s += [(i, j) for j in range(len(row))] return s def cells_containing(self, i): @@ -1800,9 +1975,9 @@ def cells_containing(self, i): cell_list = [] for r in range(len(self)-1, -1, -1): rth_row = self[r] - for c,val in enumerate(rth_row): + for c, val in enumerate(rth_row): if val == i: - cell_list.append((r,c)) + cell_list.append((r, c)) return cell_list def leq(self, secondtab): @@ -1888,10 +2063,10 @@ def k_weight(self, k): w = self.weight() s = self.cells() - for l in range(1,len(w)+1): - new_s = [(i,j) for i,j in s if self[i][j] == l] + for l in range(1, len(w)+1): + new_s = [(i, j) for i, j in s if self[i][j] == l] - #If there are no elements that meet the condition + # If there are no elements that meet the condition if new_s == []: res.append(0) continue @@ -1914,8 +2089,8 @@ def is_k_tableau(self, k): False """ shapes = self.to_chain() - kshapes = [ la.k_conjugate(k) for la in shapes ] - return all( kshapes[i+1].contains(kshapes[i]) for i in range(len(shapes)-1) ) + kshapes = [la.k_conjugate(k) for la in shapes] + return all(kshapes[i+1].contains(kshapes[i]) for i in range(len(shapes)-1)) def restrict(self, n): """ @@ -1970,14 +2145,14 @@ def restrict(self, n): sage: _.category() Category of elements of Semistandard tableaux """ - res = [ [y for y in row if y <= n] for row in self ] + res = [[y for y in row if y <= n] for row in self] res = [row for row in res if row] # attempt to return a tableau of the same type try: - return self.parent()( res ) + return self.parent()(res) except Exception: try: - return self.parent().Element( res ) + return self.parent().Element(res) except Exception: return Tableau(res) @@ -2141,7 +2316,7 @@ def bump(self, x): new_t = self.to_list() for row in new_t: i = 0 - #try to insert to_insert into row + # try to insert to_insert into row while i < len(row): if to_insert < row[i]: t = to_insert @@ -2150,15 +2325,15 @@ def bump(self, x): break i += 1 - #if we haven't already inserted to_insert - #append it to the end of row + # if we haven't already inserted to_insert + # append it to the end of row if i == len(row): row.append(to_insert) if isinstance(self, SemistandardTableau): return SemistandardTableau(new_t) return Tableau(new_t) - #if we got here, we are at the end of the tableau - #add to_insert as the last row + # if we got here, we are at the end of the tableau + # add to_insert as the last row new_t.append([to_insert]) if isinstance(self, SemistandardTableau): return SemistandardTableau(new_t) @@ -2271,7 +2446,7 @@ def insert_word(self, w, left=False): w = [i for i in reversed(w)] res = self for i in w: - res = res.schensted_insert(i,left=left) + res = res.schensted_insert(i, left=left) return res def reverse_bump(self, loc): @@ -2469,33 +2644,33 @@ def _slide_up(self, c): """ new_st = self.to_list() spotl, spotc = c - while [spotl, spotc] != [0,0]: - #once moving box is in first column, just move letters up - #(French notation!) + while [spotl, spotc] != [0, 0]: + # once moving box is in first column, just move letters up + # (French notation!) if spotc == 0: new_st[spotl][spotc] = new_st[spotl-1][spotc] spotl -= 1 continue - #once moving box is in first row, just move letters up + # once moving box is in first row, just move letters up elif spotl == 0: new_st[spotl][spotc] = new_st[spotl][spotc-1] spotc -= 1 continue else: - #If we get to this stage, we need to compare + # If we get to this stage, we need to compare below = new_st[spotl-1][spotc] left = new_st[spotl][spotc-1] if below >= left: - #Swap with the cell below + # Swap with the cell below new_st[spotl][spotc] = new_st[spotl-1][spotc] spotl -= 1 continue else: - #Swap with the cell to the left + # Swap with the cell to the left new_st[spotl][spotc] = new_st[spotl][spotc-1] spotc -= 1 continue - #set box in position (0,0) to 0 + # set box in position (0,0) to 0 new_st[0][0] = 0 return Tableau(new_st) @@ -2522,14 +2697,14 @@ def _slide_down(self, c, n): [[1, 2, 2, 2, 2, 3], [2, 4, 4, 6, 6], [4, 5, 7, 11], [5, 8]] """ new_st = self.to_list() - #new_st is a deep copy of self, so as not to mess around with self. + # new_st is a deep copy of self, so as not to mess around with self. new_st_shape = [len(x) for x in self] spotl, spotc = c - #spotl and spotc are the coordinates of the wandering hole. - #All comments and variable names below refer to French notation. + # spotl and spotc are the coordinates of the wandering hole. + # All comments and variable names below refer to French notation. while True: - #"right_neighbor" and "upper_neighbor" refer to neighbors of the - #hole. + # "right_neighbor" and "upper_neighbor" refer to neighbors of the + # hole. go_right = None if len(new_st_shape) > spotl + 1 and new_st_shape[spotl + 1] >= spotc + 1: upper_neighbor = new_st[spotl + 1][spotc] @@ -2636,7 +2811,7 @@ def promotion_inverse(self, n): return self s = self.shape()[0] l = self.weight()[0] - word = [i-1 for row in reversed(self) for i in row if i>1] + word = [i-1 for row in reversed(self) for i in row if i > 1] t = Tableau([]) t = t.insert_word(word) t = t.to_list() @@ -2768,26 +2943,26 @@ def row_stabilizer(self): EXAMPLES:: - sage: rs = Tableau([[1,2,3],[4,5]]).row_stabilizer() - sage: rs.order() == factorial(3)*factorial(2) + sage: rs = Tableau([[1,2,3],[4,5]]).row_stabilizer() # optional - sage.groups + sage: rs.order() == factorial(3)*factorial(2) # optional - sage.groups True - sage: PermutationGroupElement([(1,3,2),(4,5)]) in rs + sage: PermutationGroupElement([(1,3,2),(4,5)]) in rs # optional - sage.groups True - sage: PermutationGroupElement([(1,4)]) in rs + sage: PermutationGroupElement([(1,4)]) in rs # optional - sage.groups False - sage: rs = Tableau([[1, 2],[3]]).row_stabilizer() - sage: PermutationGroupElement([(1,2),(3,)]) in rs + sage: rs = Tableau([[1, 2],[3]]).row_stabilizer() # optional - sage.groups + sage: PermutationGroupElement([(1,2),(3,)]) in rs # optional - sage.groups True - sage: rs.one().domain() + sage: rs.one().domain() # optional - sage.groups [1, 2, 3] - sage: rs = Tableau([[1],[2],[3]]).row_stabilizer() - sage: rs.order() + sage: rs = Tableau([[1],[2],[3]]).row_stabilizer() # optional - sage.groups + sage: rs.order() # optional - sage.groups 1 - sage: rs = Tableau([[2,4,5],[1,3]]).row_stabilizer() - sage: rs.order() + sage: rs = Tableau([[2,4,5],[1,3]]).row_stabilizer() # optional - sage.groups + sage: rs.order() # optional - sage.groups 12 - sage: rs = Tableau([]).row_stabilizer() - sage: rs.order() + sage: rs = Tableau([]).row_stabilizer() # optional - sage.groups + sage: rs.order() # optional - sage.groups 1 """ # Ensure that the permutations involve all elements of the @@ -2796,8 +2971,8 @@ def row_stabilizer(self): gens = [list(range(1, k + 1))] for row in self: for j in range(len(row) - 1): - gens.append( (row[j], row[j + 1]) ) - return PermutationGroup( gens ) + gens.append((row[j], row[j + 1])) + return PermutationGroup(gens) def column_stabilizer(self): """ @@ -2809,12 +2984,12 @@ def column_stabilizer(self): EXAMPLES:: - sage: cs = Tableau([[1,2,3],[4,5]]).column_stabilizer() - sage: cs.order() == factorial(2)*factorial(2) + sage: cs = Tableau([[1,2,3],[4,5]]).column_stabilizer() # optional - sage.groups + sage: cs.order() == factorial(2)*factorial(2) # optional - sage.groups True - sage: PermutationGroupElement([(1,3,2),(4,5)]) in cs + sage: PermutationGroupElement([(1,3,2),(4,5)]) in cs # optional - sage.groups False - sage: PermutationGroupElement([(1,4)]) in cs + sage: PermutationGroupElement([(1,4)]) in cs # optional - sage.groups True """ return self.conjugate().row_stabilizer() @@ -2858,7 +3033,7 @@ def _heights(self): heights = [1]*(cor[0][1]) for i in range(1, ncor): - heights += [ cor[i][0] ]*(cor[i][1]-cor[i-1][1]) + heights += [cor[i][0]]*(cor[i][1]-cor[i-1][1]) return heights @@ -2871,7 +3046,7 @@ def last_letter_lequal(self, tab2): sage: st = StandardTableaux([3,2]) sage: f = lambda b: 1 if b else 0 - sage: matrix( [ [ f(t1.last_letter_lequal(t2)) for t2 in st] for t1 in st] ) + sage: matrix([[f(t1.last_letter_lequal(t2)) for t2 in st] for t1 in st]) # optional - sage.modules [1 1 1 1 1] [0 1 1 1 1] [0 0 1 1 1] @@ -3018,13 +3193,13 @@ def add_entry(self, cell, m): if r == len(tab) and c == 0: tab.append([m]) else: - raise IndexError('%s is not an addable cell of the tableau' % ((r,c),)) + raise IndexError('%s is not an addable cell of the tableau' % ((r, c),)) else: tab_r = tab[r] if c == len(tab_r): tab_r.append(m) else: - raise IndexError('%s is not an addable cell of the tableau' % ((r,c),)) + raise IndexError('%s is not an addable cell of the tableau' % ((r, c),)) # attempt to return a tableau of the same type as self if tab in self.parent(): @@ -3059,8 +3234,8 @@ def catabolism(self): if h == 0: return self else: - #Remove the top row and insert it back in - return Tableau(self[1:]).insert_word(self[0],left=True) + # Remove the top row and insert it back in + return Tableau(self[1:]).insert_word(self[0], left=True) def catabolism_sequence(self): """ @@ -3138,7 +3313,7 @@ def lambda_catabolism(self, part): w1 = list(sum((row for row in reversed(self[m:])), ())) w2 = [] - for i,row in enumerate(reversed(self[:m])): + for i, row in enumerate(reversed(self[:m])): w2 += row[part[-1 - i]:] return Tableau([]).insert_word(w2 + w1) @@ -3178,8 +3353,8 @@ def reduced_lambda_catabolism(self, part): a = self[0][0] - part = [ min(part1[i], len(self[i])) for i in range(min(len(part1),len(self)))] - tt_part = Tableau([ [a+i]*part[i] for i in range(len(part)) ]) + part = [min(part1[i], len(self[i])) for i in range(min(len(part1), len(self)))] + tt_part = Tableau([[a+i]*part[i] for i in range(len(part))]) t_part = Tableau([[self[i][j] for j in range(part[i])] for i in range(len(part))]) if t_part == tt_part: @@ -3272,8 +3447,8 @@ def promotion_operator(self, i): weight = self.weight() perm = permutation.from_reduced_word(range(1, len(weight)+1)) l = part.add_horizontal_border_strip(i) - ltab = [ from_chain( chain + [next] ) for next in l ] - return [ x.symmetric_group_action_on_values(perm) for x in ltab ] + ltab = [from_chain(chain + [next]) for next in l] + return [x.symmetric_group_action_on_values(perm) for x in ltab] ################################## # actions on tableaux from words # @@ -3403,9 +3578,9 @@ def atom(self): sage: Tableau([[1,2,3],[4,5],[6]]).atom() [3, 2, 1] """ - ll = [ t.socle() for t in self.catabolism_sequence() ] + ll = [t.socle() for t in self.catabolism_sequence()] lres = ll[:] - for i in range(1,len(ll)): + for i in range(1, len(ll)): lres[i] = ll[i] - ll[i-1] return lres @@ -3539,7 +3714,7 @@ def right_key_tableau(self): update.append(col_b[:-1]) else: update.append(col_b) - key[i].insert(0,key_val) + key[i].insert(0, key_val) right_cols = update return Tableau(key).conjugate() @@ -3599,7 +3774,7 @@ def left_key_tableau(self): key[0] = list(cols_list[0]) from bisect import bisect_right - for i, col_a in enumerate(cols_list[1:],1): + for i, col_a in enumerate(cols_list[1:], 1): left_cols = cols_list[:i] for elem in reversed(col_a): key_val = elem @@ -3609,7 +3784,7 @@ def left_key_tableau(self): key_val = col_b[j] update.insert(0, col_b[:j]) left_cols = update - key[i].insert(0,key_val) + key[i].insert(0, key_val) return Tableau(key).conjugate() ################# @@ -3632,9 +3807,9 @@ def _segments(self): sage: sorted(t._segments().items()) [((0, 2), 2), ((0, 3), 3), ((0, 5), 4), ((1, 3), 1), ((1, 5), 2), ((2, 4), 1)] - sage: B = crystals.Tableaux("A4", shape=[4,3,2,1]) - sage: t = B[31].to_tableau() - sage: sorted(t._segments().items()) + sage: B = crystals.Tableaux("A4", shape=[4,3,2,1]) # optional - sage.modules + sage: t = B[31].to_tableau() # optional - sage.modules + sage: sorted(t._segments().items()) # optional - sage.modules [((0, 5), 3), ((1, 4), 2), ((2, 4), 1)] """ segments = {} @@ -3664,9 +3839,9 @@ def seg(self): sage: t.seg() 6 - sage: B = crystals.Tableaux("A4",shape=[4,3,2,1]) - sage: t = B[31].to_tableau() - sage: t.seg() + sage: B = crystals.Tableaux("A4", shape=[4,3,2,1]) # optional - sage.modules + sage: t = B[31].to_tableau() # optional - sage.modules + sage: t.seg() # optional - sage.modules 3 """ return len(self._segments()) @@ -3692,9 +3867,9 @@ def flush(self): sage: t.flush() 3 - sage: B = crystals.Tableaux("A4",shape=[4,3,2,1]) - sage: t = B[32].to_tableau() - sage: t.flush() + sage: B = crystals.Tableaux("A4", shape=[4,3,2,1]) # optional - sage.modules + sage: t = B[32].to_tableau() # optional - sage.modules + sage: t.flush() # optional - sage.modules 4 """ for i in range(len(self)-1): @@ -3711,7 +3886,7 @@ def flush(self): for t in S: if s[0][0]+1 == t[0][0] and s[1] == t[1] and ( (s[1] >= 1 and self[s[0][0]+1][s[1]-1] <= self[s[0][0]][s[1]]) - or (s[1] < 1 and self[s[0][0]+1][s[1]] != s[0][0]+2) ): + or (s[1] < 1 and self[s[0][0]+1][s[1]] != s[0][0]+2)): f += 1 return f @@ -3740,7 +3915,7 @@ def content(self, k, multicharge=[0]): ... ValueError: 6 does not appear in tableau """ - for r,row in enumerate(self): + for r, row in enumerate(self): try: return row.index(k) - r + multicharge[0] except ValueError: @@ -3817,16 +3992,16 @@ def residue_sequence(self, e, multicharge=(0,)): EXAMPLES:: - sage: StandardTableauTuple([[1,2],[3,4]]).residue_sequence(2) + sage: StandardTableauTuple([[1,2],[3,4]]).residue_sequence(2) # optional - sage.groups 2-residue sequence (0,1,1,0) with multicharge (0) - sage: StandardTableauTuple([[1,2],[3,4]]).residue_sequence(3) + sage: StandardTableauTuple([[1,2],[3,4]]).residue_sequence(3) # optional - sage.groups 3-residue sequence (0,1,2,0) with multicharge (0) - sage: StandardTableauTuple([[1,2],[3,4]]).residue_sequence(4) + sage: StandardTableauTuple([[1,2],[3,4]]).residue_sequence(4) # optional - sage.groups 4-residue sequence (0,1,3,0) with multicharge (0) """ res = [0] * self.size() - for r,row in enumerate(self): - for c,entry in enumerate(row): + for r, row in enumerate(self): + for c, entry in enumerate(row): res[entry-1] = multicharge[0] - r + c from sage.combinat.tableau_residues import ResidueSequence return ResidueSequence(e, multicharge, res, check=False) @@ -3855,16 +4030,16 @@ def degree(self, e, multicharge=(0,)): EXAMPLES:: - sage: StandardTableau([[1,2,5],[3,4]]).degree(3) + sage: StandardTableau([[1,2,5],[3,4]]).degree(3) # optional - sage.groups 0 - sage: StandardTableau([[1,2,5],[3,4]]).degree(4) + sage: StandardTableau([[1,2,5],[3,4]]).degree(4) # optional - sage.groups 1 """ n = self.size() if n == 0: return 0 - deg = self.shape()._initial_degree(e,multicharge) + deg = self.shape()._initial_degree(e, multicharge) res = self.shape().initial_tableau().residue_sequence(e, multicharge) for r in self.reduced_row_word(): if res[r] == res[r+1]: @@ -3900,11 +4075,11 @@ def codegree(self, e, multicharge=(0,)): EXAMPLES:: - sage: StandardTableau([[1,3,5],[2,4]]).codegree(3) + sage: StandardTableau([[1,3,5],[2,4]]).codegree(3) # optional - sage.groups 0 - sage: StandardTableau([[1,2,5],[3,4]]).codegree(3) + sage: StandardTableau([[1,2,5],[3,4]]).codegree(3) # optional - sage.groups 1 - sage: StandardTableau([[1,2,5],[3,4]]).codegree(4) + sage: StandardTableau([[1,2,5],[3,4]]).codegree(4) # optional - sage.groups 0 """ if not self: # the trivial case @@ -4652,15 +4827,15 @@ def up(self): sage: [x for x in t.up()] [[[1, 2, 3]], [[1, 2], [3]]] """ - #Get a list of all places where we can add a cell - #to the shape of self + # Get a list of all places where we can add a cell + # to the shape of self outside_corners = self.shape().outside_corners() n = self.size() - #Go through and add n+1 to the end of each - #of the rows + # Go through and add n+1 to the end of each + # of the rows for row, _ in outside_corners: new_t = [list(_) for _ in self] if row != len(self): @@ -4736,12 +4911,12 @@ def standard_descents(self): [] """ descents = [] - #whatpart gives the number for which self is a partition - whatpart = sum(i for i in self.shape()) - #now find the descents + # whatpart gives the number for which self is a partition + whatpart = sum(self.shape()) + # now find the descents for i in range(1, whatpart): - #find out what row i and i+1 are in (we're using the - #standardness of self here) + # find out what row i and i+1 are in (we're using the + # standardness of self here) for row in self: if row.count(i + 1): break @@ -4883,7 +5058,7 @@ def from_chain(chain): for i in reversed(range(2, len(chain) + 1)): for j in range(len(chain[i - 1])): for k in range(chain[i - 1][j]): - res[j][k] = i -1 + res[j][k] = i - 1 T = Tableaux_all() return T.element_class(T, res) @@ -4928,7 +5103,7 @@ def from_shape_and_word(shape, w, convention="French"): if convention == "French": shape = reversed(shape) for l in shape: - res.append( tuple(w[j:j+l]) ) + res.append(tuple(w[j:j+l])) j += l if convention == "French": res.reverse() @@ -5194,7 +5369,7 @@ def K_promotion_inverse(self, ceiling=None): ans = ans.K_bender_knuth(i) return ans - @combinatorial_map(order=2,name='K-evacuation') + @combinatorial_map(order=2, name='K-evacuation') def K_evacuation(self, ceiling=None): """ Return the K-evacuation involution from [TY2009]_ to ``self``. @@ -5472,7 +5647,11 @@ class options(GlobalOptions): case_sensitive=False) convention = dict(default="English", description='Sets the convention used for displaying tableaux and partitions', - values=dict(English='use the English convention',French='use the French convention'), + values=dict( + English='use the English convention', + French='use the French convention', + Russian='use the Russian convention', + ), case_sensitive=False) notation = dict(alt_name="convention") @@ -5603,7 +5782,7 @@ def __init__(self, n): super().__init__(category=Sets()) self.size = n - def __contains__(self,x): + def __contains__(self, x): """ TESTS:: @@ -5643,13 +5822,13 @@ def an_element(self): sage: T.an_element() [] """ - if self.size==0: + if self.size == 0: return self.element_class(self, []) - if self.size==1: + if self.size == 1: return self.element_class(self, [[1]]) - return self.element_class(self, [[1]*(self.size-1),[1]]) + return self.element_class(self, [[1]*(self.size-1), [1]]) ########################## @@ -5852,27 +6031,27 @@ def __classcall_private__(cls, *args, **kwargs): # The first arg could be either a size or a shape if isinstance(args[0], (int, Integer)): if size is not None: - raise ValueError( "size was specified more than once" ) + raise ValueError("size was specified more than once") else: size = args[0] else: if shape is not None: - raise ValueError( "the shape was specified more than once" ) + raise ValueError("the shape was specified more than once") shape = args[0] # we check it's a partition later if len(args) == 2: # The second non-keyword argument is the weight if mu is not None: - raise ValueError( "the weight was specified more than once" ) + raise ValueError("the weight was specified more than once") else: mu = args[1] # Consistency checks if size is not None: if not isinstance(size, (int, Integer)): - raise ValueError( "size must be an integer" ) + raise ValueError("size must be an integer") elif size < 0: - raise ValueError( "size must be non-negative" ) + raise ValueError("size must be non-negative") if shape is not None: from sage.combinat.skew_partition import SkewPartitions @@ -5884,40 +6063,40 @@ def __classcall_private__(cls, *args, **kwargs): from sage.combinat.skew_tableau import SemistandardSkewTableaux return SemistandardSkewTableaux(shape, mu) else: - raise ValueError( "shape must be a (skew) partition" ) + raise ValueError("shape must be a (skew) partition") if mu is not None: if mu not in Compositions() and mu not in _Partitions: - raise ValueError( "mu must be a composition" ) + raise ValueError("mu must be a composition") mu = Composition(mu) is_inf = max_entry is PlusInfinity() if max_entry is not None: if not is_inf and not isinstance(max_entry, (int, Integer)): - raise ValueError( "max_entry must be an integer or PlusInfinity" ) + raise ValueError("max_entry must be an integer or PlusInfinity") elif max_entry <= 0: - raise ValueError( "max_entry must be positive" ) + raise ValueError("max_entry must be positive") if (mu is not None) and (max_entry is not None): if max_entry != len(mu): - raise ValueError( "the maximum entry must match the weight" ) + raise ValueError("the maximum entry must match the weight") if (size is not None) and (shape is not None): if sum(shape) != size: # This could return an empty class instead of an error - raise ValueError( "size and shape are different sizes" ) + raise ValueError("size and shape are different sizes") if (size is not None) and (mu is not None): if sum(mu) != size: # This could return an empty class instead of an error - raise ValueError( "size and eval are different sizes" ) + raise ValueError("size and eval are different sizes") # Dispatch appropriately if (shape is not None) and (mu is not None): if sum(shape) != sum(mu): # This could return an empty class instead of an error - raise ValueError( "shape and eval are different sizes" ) + raise ValueError("shape and eval are different sizes") else: return SemistandardTableaux_shape_weight(shape, mu) @@ -6022,26 +6201,26 @@ def __getitem__(self, r): ... ValueError: infinite set """ - if isinstance(r,(int,Integer)): + if isinstance(r, (int, Integer)): return self.unrank(r) - elif isinstance(r,slice): - start=0 if r.start is None else r.start - stop=r.stop + elif isinstance(r, slice): + start = 0 if r.start is None else r.start + stop = r.stop if stop is None and not self.is_finite(): - raise ValueError( 'infinite set' ) + raise ValueError('infinite set') else: - raise ValueError( 'r must be an integer or a slice' ) - count=0 - tabs=[] + raise ValueError('r must be an integer or a slice') + count = 0 + tabs = [] for t in self: - if count==stop: + if count == stop: break - if count>=start: + if count >= start: tabs.append(t) - count+=1 + count += 1 # this is to cope with empty slices endpoints like [:6] or [:} - if count==stop or stop is None: + if count == stop or stop is None: return tabs raise IndexError('value out of range') @@ -6296,7 +6475,7 @@ def __contains__(self, x): sage: 1 in SST False """ - return SemistandardTableaux.__contains__(self, x) and [len(_) for _ in x]==self.shape + return SemistandardTableaux.__contains__(self, x) and [len(_) for _ in x] == self.shape def _repr_(self): """ @@ -6408,7 +6587,7 @@ def __contains__(self, x): sage: 1 in SST False """ - if self.size==0: + if self.size == 0: return x == [] return (SemistandardTableaux.__contains__(self, x) @@ -6437,9 +6616,9 @@ def random_element(self): EXAMPLES:: - sage: SemistandardTableaux(6).random_element() # random + sage: SemistandardTableaux(6).random_element() # random # optional - sage.modules [[1, 1, 2], [3, 5, 5]] - sage: SemistandardTableaux(6, max_entry=7).random_element() # random + sage: SemistandardTableaux(6, max_entry=7).random_element() # random # optional - sage.modules [[2, 4, 4, 6, 6, 6]] """ from sage.rings.integer_ring import ZZ @@ -6456,14 +6635,14 @@ def random_element(self): pos += 1 tot += weights[pos] # we now have pos elements over the diagonal and n - 2 * pos on it - m = diagonal_matrix( list(IntegerVectors(self.size - 2 * pos, - self.max_entry).random_element()) ) + m = diagonal_matrix(list(IntegerVectors(self.size - 2 * pos, + self.max_entry).random_element())) above_diagonal = list(IntegerVectors(pos, kchoose2m1 + 1).random_element()) index = 0 for i in range(self.max_entry - 1): for j in range(i + 1, self.max_entry): - m[i,j] = above_diagonal[index] - m[j,i] = above_diagonal[index] + m[i, j] = above_diagonal[index] + m[j, i] = above_diagonal[index] index += 1 return RSK(m)[0] @@ -6669,9 +6848,9 @@ def random_element(self): """ from sage.misc.prandom import randint - with_sentinels = [max(i,j) for i,j in zip([0]+list(self.shape), [k+1 for k in self.shape]+[0])] + with_sentinels = [max(i, j) for i, j in zip([0]+list(self.shape), [k+1 for k in self.shape]+[0])] t = [[self.max_entry+1]*i for i in with_sentinels] - for i,l in enumerate(self.shape): + for i, l in enumerate(self.shape): for j in range(l): content = j - i t[i][j] = randint(1 - content, self.max_entry) @@ -6694,7 +6873,7 @@ def random_element(self): row += 1 x = t[row][col + 1] y = t[row + 1][col] - return SemistandardTableau([l[:c] for l,c in zip(t, self.shape)]) + return SemistandardTableau([l[:c] for l, c in zip(t, self.shape)]) def cardinality(self, algorithm='hook'): r""" @@ -6745,7 +6924,7 @@ def cardinality(self, algorithm='hook'): conj = self.shape.conjugate() num = Integer(1) den = Integer(1) - for i,l in enumerate(self.shape): + for i, l in enumerate(self.shape): for j in range(l): num *= self.max_entry + j - i den *= l + conj[j] - i - j - 1 @@ -6988,13 +7167,13 @@ class RowStandardTableaux(Tableaux): sage: ST = RowStandardTableaux(3); ST Row standard tableaux of size 3 - sage: ST.first() + sage: ST.first() # optional - sage.graphs [[1, 2, 3]] - sage: ST.last() + sage: ST.last() # optional - sage.graphs [[3], [1], [2]] - sage: ST.cardinality() + sage: ST.cardinality() # optional - sage.graphs 10 - sage: ST.list() + sage: ST.list() # optional - sage.graphs [[[1, 2, 3]], [[2, 3], [1]], [[1, 2], [3]], @@ -7021,13 +7200,13 @@ class RowStandardTableaux(Tableaux): [] sage: ST = RowStandardTableaux([2,2]); ST Row standard tableaux of shape [2, 2] - sage: ST.first() + sage: ST.first() # optional - sage.graphs [[2, 4], [1, 3]] - sage: ST.last() + sage: ST.last() # optional - sage.graphs [[2, 3], [1, 4]] - sage: ST.cardinality() + sage: ST.cardinality() # optional - sage.graphs 6 - sage: ST.list() + sage: ST.list() # optional - sage.graphs [[[2, 4], [1, 3]], [[3, 4], [1, 2]], [[1, 4], [2, 3]], @@ -7081,8 +7260,8 @@ def __classcall_private__(cls, *args, **kwargs): return RowStandardTableaux_shape(_Partitions(n)) elif n in SkewPartitions(): - #from sage.combinat.skew_tableau import RowStandardSkewTableaux - #return RowStandardSkewTableaux(n) + # from sage.combinat.skew_tableau import RowStandardSkewTableaux + # return RowStandardSkewTableaux(n) raise NotImplementedError("row standard skew tableaux not yet implemented") if not isinstance(n, (int, Integer)) or n < 0: @@ -7116,9 +7295,9 @@ def __contains__(self, x): if isinstance(x, RowStandardTableau): return True elif Tableaux.__contains__(self, x): - flatx = sorted(sum((list(row) for row in x),[])) - return ( flatx == list(range(1,len(flatx)+1)) - and all(row[i] < row[i+1] for row in x for i in range(len(row)-1)) ) + flatx = sorted(sum((list(row) for row in x), [])) + return (flatx == list(range(1, len(flatx)+1)) + and all(row[i] < row[i+1] for row in x for i in range(len(row)-1))) return False @@ -7162,11 +7341,11 @@ class RowStandardTableaux_size(RowStandardTableaux, DisjointUnionEnumeratedSets) EXAMPLES:: - sage: [ t for t in RowStandardTableaux(1) ] + sage: [t for t in RowStandardTableaux(1)] # optional - sage.graphs [[[1]]] - sage: [ t for t in RowStandardTableaux(2) ] + sage: [t for t in RowStandardTableaux(2)] # optional - sage.graphs [[[1, 2]], [[2], [1]], [[1], [2]]] - sage: list(RowStandardTableaux(3)) + sage: list(RowStandardTableaux(3)) # optional - sage.graphs [[[1, 2, 3]], [[2, 3], [1]], [[1, 2], [3]], @@ -7186,7 +7365,7 @@ class RowStandardTableaux_size(RowStandardTableaux, DisjointUnionEnumeratedSets) 10 sage: ns = [1,2,3,4,5,6] sage: sts = [RowStandardTableaux(n) for n in ns] - sage: all(st.cardinality() == len(st.list()) for st in sts) + sage: all(st.cardinality() == len(st.list()) for st in sts) # optional - sage.graphs True sage: RowStandardTableaux(40).cardinality() # not tested, too long 2063837185739279909309355007659204891024472174278 @@ -7203,8 +7382,8 @@ def __init__(self, n): TESTS:: - sage: TestSuite( RowStandardTableaux(0) ).run() - sage: TestSuite( RowStandardTableaux(3) ).run() + sage: TestSuite(RowStandardTableaux(0)).run() # optional - sage.graphs + sage: TestSuite(RowStandardTableaux(3)).run() # optional - sage.graphs """ RowStandardTableaux.__init__(self) from sage.combinat.partition import Partitions_n @@ -7227,10 +7406,10 @@ def __contains__(self, x): TESTS:: sage: ST3 = RowStandardTableaux(3) - sage: all(st in ST3 for st in ST3) + sage: all(st in ST3 for st in ST3) # optional - sage.graphs True sage: ST4 = RowStandardTableaux(4) - sage: [x for x in ST4 if x in ST3] + sage: [x for x in ST4 if x in ST3] # optional - sage.graphs [] Check that :trac:`14145` is fixed:: @@ -7254,7 +7433,7 @@ def an_element(self): elif self._size == 1: return self.element_class(self, [[1]]) else: - return self.element_class(self, [range(1,self._size + 1)]) + return self.element_class(self, [range(1, self._size + 1)]) class RowStandardTableaux_shape(RowStandardTableaux): @@ -7273,7 +7452,7 @@ def __init__(self, p): TESTS:: - sage: TestSuite( RowStandardTableaux([2,1,1]) ).run() + sage: TestSuite( RowStandardTableaux([2,1,1]) ).run() # optional - sage.graphs """ super().__init__(category=FiniteEnumeratedSets()) self.shape = p @@ -7283,9 +7462,9 @@ def __contains__(self, x): EXAMPLES:: sage: ST = RowStandardTableaux([2,1,1]) - sage: all(st in ST for st in ST) + sage: all(st in ST for st in ST) # optional - sage.graphs True - sage: len([x for x in RowStandardTableaux(4) if x in ST]) + sage: len([x for x in RowStandardTableaux(4) if x in ST]) # optional - sage.graphs 12 sage: ST.cardinality() 12 @@ -7308,14 +7487,14 @@ def __iter__(self): EXAMPLES:: - sage: [t for t in RowStandardTableaux([2,2])] + sage: [t for t in RowStandardTableaux([2,2])] # optional - sage.graphs [[[2, 4], [1, 3]], [[3, 4], [1, 2]], [[1, 4], [2, 3]], [[1, 3], [2, 4]], [[1, 2], [3, 4]], [[2, 3], [1, 4]]] - sage: [t for t in RowStandardTableaux([3,2])] + sage: [t for t in RowStandardTableaux([3,2])] # optional - sage.graphs [[[2, 4, 5], [1, 3]], [[3, 4, 5], [1, 2]], [[1, 4, 5], [2, 3]], @@ -7327,7 +7506,7 @@ def __iter__(self): [[2, 3, 4], [1, 5]], [[2, 3, 5], [1, 4]]] sage: st = RowStandardTableaux([2,1]) - sage: st[0].parent() is st + sage: st[0].parent() is st # optional - sage.graphs True """ partial_sums = [sum(self.shape[:i]) for i in range(len(self.shape)+1)] @@ -7336,9 +7515,9 @@ def __iter__(self): relations = [] m = 1 for row in self.shape: - relations += [(m+i,m+i+1) for i in range(row-1)] + relations += [(m+i, m+i+1) for i in range(row-1)] m += row - P = Poset((range(1,self.shape.size()+1), relations)) + P = Poset((range(1, self.shape.size()+1), relations)) L = P.linear_extensions() # now run through the linear extensions and return the corresponding tableau for lin in L: @@ -7434,7 +7613,7 @@ class StandardTableaux(SemistandardTableaux): 2 sage: ST.list() [[[1, 3], [2, 4]], [[1, 2], [3, 4]]] - sage: StandardTableau([[1,2,3],[4,5]]).residue_sequence(3).standard_tableaux() + sage: StandardTableau([[1,2,3],[4,5]]).residue_sequence(3).standard_tableaux() # optional - sage.groups Standard tableaux with 3-residue sequence (0,1,2,2,0) and multicharge (0) """ @staticmethod @@ -7517,10 +7696,10 @@ def __contains__(self, x): return True elif Tableaux.__contains__(self, x): flatx = sorted(sum((list(row) for row in x), [])) - return flatx == list(range(1,len(flatx)+1)) and (len(x)==0 or - (all(row[i]<row[i+1] for row in x for i in range(len(row)-1)) and - all(x[r][c]<x[r+1][c] for r in range(len(x)-1) - for c in range(len(x[r+1])) ) + return flatx == list(range(1, len(flatx)+1)) and (len(x) == 0 or + (all(row[i] < row[i+1] for row in x for i in range(len(row)-1)) and + all(x[r][c] < x[r+1][c] for r in range(len(x)-1) + for c in range(len(x[r+1]))) )) return False @@ -7760,7 +7939,7 @@ def random_element(self): matching = PerfectMatchings(set(range(1, self.size + 1)) - set(fixed_point_positions)).random_element() permutation_cycle_rep = ([(fixed_point,) for fixed_point in fixed_point_positions] - + [(a,b) for a,b in matching]) + + [(a, b) for a, b in matching]) return from_cycles(self.size, permutation_cycle_rep).robinson_schensted()[0] @@ -7892,7 +8071,7 @@ def __iter__(self): """ pi = self.shape - #Set the initial tableau by filling it in going down the columns + # Set the initial tableau by filling it in going down the columns tableau = [[None]*n for n in pi] size = sum(pi) row = 0 @@ -7900,9 +8079,9 @@ def __iter__(self): for i in range(size): tableau[row][col] = i+1 - #If we can move down, then do it; - #otherwise, move to the next column over - if ( row + 1 < len(pi) and col < pi[row+1]): + # If we can move down, then do it; + # otherwise, move to the next column over + if (row + 1 < len(pi) and col < pi[row+1]): row += 1 else: row = 0 @@ -7912,59 +8091,59 @@ def __iter__(self): # iterate until we reach the last tableau which is # filled with the row indices. - last_tableau = sum([[row]*l for (row,l) in enumerate(pi)], []) + last_tableau = sum([[row]*l for (row, l) in enumerate(pi)], []) - #Convert the tableau to "vector format" - #tableau_vector[i] is the row that number i - #is in + # Convert the tableau to "vector format" + # tableau_vector[i] is the row that number i + # is in tableau_vector = [None]*size for row in range(len(pi)): for col in range(pi[row]): tableau_vector[tableau[row][col]-1] = row - while tableau_vector!=last_tableau: - #Locate the smallest integer j such that j is not - #in the lowest corner of the subtableau T_j formed by - #1,...,j. This happens to be first j such that - #tableau_vector[j]<tableau_vector[j-1]. - #l will correspond to the shape of T_j + while tableau_vector != last_tableau: + # Locate the smallest integer j such that j is not + # in the lowest corner of the subtableau T_j formed by + # 1,...,j. This happens to be first j such that + # ntableau_vector[j]<tableau_vector[j-1]. + # l will correspond to the shape of T_j l = [0]*size l[0] = 1 j = 0 - for i in range(1,size): + for i in range(1, size): l[tableau_vector[i]] += 1 - if ( tableau_vector[i] < tableau_vector[i-1] ): + if (tableau_vector[i] < tableau_vector[i-1]): j = i break - #Find the last nonzero row of l and store it in k + # Find the last nonzero row of l and store it in k i = size - 1 - while ( l[i] == 0 ): + while l[i] == 0: i -= 1 k = i - #Find a new row for the letter j (next lowest corner) - t = l[ 1 + tableau_vector[j] ] + # Find a new row for the letter j (next lowest corner) + t = l[1 + tableau_vector[j]] i = k - while ( l[i] != t ): + while l[i] != t: i -= 1 - #Move the letter j to row i + # Move the letter j to row i tableau_vector[j] = i l[i] -= 1 - #Fill in the columns of T_j using 1,...,j-1 in increasing order + # Fill in the columns of T_j using 1,...,j-1 in increasing order m = 0 - while ( m < j ): + while m < j: r = 0 - while ( l[r] != 0 ): + while l[r] != 0: tableau_vector[m] = r l[r] -= 1 m += 1 r += 1 - #Convert the tableau vector back to the regular tableau - #format + # Convert the tableau vector back to the regular tableau + # format row_count = [0] * len(pi) tableau = [[None] * n for n in pi] @@ -8026,7 +8205,7 @@ def random_element(self): cells = [] for i in range(len(p)): for j in range(p[i]): - cells.append((i,j)) + cells.append((i, j)) m = sum(p) while m > 0: @@ -8143,7 +8322,7 @@ def symmetric_group_action_on_values(word, perm): l = r + 1 places_r, places_l = unmatched_places(w, l, r) - #Now change the number of l's and r's in the new word + # Now change the number of l's and r's in the new word nbl = len(places_l) nbr = len(places_r) ma = max(nbl, nbr) @@ -8413,8 +8592,8 @@ def __classcall_private__(cls, *args, **kwargs): elif shape in SkewPartitions(): raise NotImplementedError("skew increasing tableaux are not" " currently implemented") - #from sage.combinat.skew_tableau import IncreasingSkewTableaux - #return IncreasingSkewTableaux(shape, wt) + # from sage.combinat.skew_tableau import IncreasingSkewTableaux + # return IncreasingSkewTableaux(shape, wt) else: raise ValueError("shape must be a (skew) partition") @@ -8558,9 +8737,9 @@ def __getitem__(self, r): ... ValueError: infinite set """ - if isinstance(r, (int,Integer)): + if isinstance(r, (int, Integer)): return self.unrank(r) - elif isinstance(r,slice): + elif isinstance(r, slice): start = 0 if r.start is None else r.start stop = r.stop if stop is None and not self.is_finite(): @@ -9244,10 +9423,10 @@ def __iter__(self): list_of_inc_tabs.append(self.element_class(self, active_tab)) continue growth_spots = [] - for (r,c) in unfilled_spots: - if (r-1,c) not in active_tab.cells() or active_tab[r-1][c] != 0: - if (r,c-1) not in active_tab.cells() or active_tab[r][c-1] != 0: - growth_spots.append((r,c)) + for (r, c) in unfilled_spots: + if (r-1, c) not in active_tab.cells() or active_tab[r-1][c] != 0: + if (r, c-1) not in active_tab.cells() or active_tab[r][c-1] != 0: + growth_spots.append((r, c)) growth_choices = list(powerset(growth_spots)) top_value = max(active_tab.entries()) try: @@ -9256,9 +9435,9 @@ def __iter__(self): continue for growth_choice in growth_choices[1:]: new_tab = [[0] * k for k in self.shape] - for (r,c) in active_tab.cells(): + for (r, c) in active_tab.cells(): new_tab[r][c] = active_tab[r][c] - for (r,c) in growth_choice: + for (r, c) in growth_choice: new_tab[r][c] = growth_num list_of_partial_inc_tabs.append(Tableau(new_tab)) for inctab in list_of_inc_tabs: diff --git a/src/sage/combinat/tableau_tuple.py b/src/sage/combinat/tableau_tuple.py index 8b9af538b00..889f5ee9bc4 100644 --- a/src/sage/combinat/tableau_tuple.py +++ b/src/sage/combinat/tableau_tuple.py @@ -228,7 +228,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod from sage.misc.prandom import randint -from sage.arith.all import factorial +from sage.arith.misc import factorial from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer import Integer from sage.rings.semirings.non_negative_integer_semiring import NN @@ -635,7 +635,7 @@ def __call__(self, *cell): sage: t(3,3,3) Traceback (most recent call last): ... - IndexError: The cell (3, 3, 3) is not contained in the tableau + IndexError: the cell (3, 3, 3) is not contained in the tableau """ if isinstance(cell[0], (int, Integer)): k, r, c = cell[0], cell[1], cell[2] @@ -644,7 +644,7 @@ def __call__(self, *cell): try: return self[k][r][c] except IndexError: - raise IndexError("The cell (%s, %s, %s) is not contained in the tableau" % (k, r, c)) + raise IndexError("the cell (%s, %s, %s) is not contained in the tableau" % (k, r, c)) def level(self): """ @@ -2661,11 +2661,11 @@ def an_element(self): """ if self.size() == 0: return self.element_class(self, [[] for _ in range(self.level())]) - else: - tab = [[[m for m in range(1, self.size() + 1)]]] - for s in range(self.level() - 1): - tab.append([]) - return self.element_class(self, tab) + + tab = [[[m for m in range(1, self.size() + 1)]]] + for _ in range(self.level() - 1): + tab.append([]) + return self.element_class(self, tab) # ------------------------------------------------- @@ -4126,12 +4126,12 @@ def __classcall_private__(cls, *args, **kwargs): raise ValueError('the shape must be a partition tuple') if level is None: - level=shape.level() - elif level!=shape.level(): + level = shape.level() + elif level != shape.level(): raise ValueError('the shape and level must agree') if size is None: - size=shape.size() - elif size!=shape.size(): + size = shape.size() + elif size != shape.size(): raise ValueError('the shape and size must agree') # now that the inputs appear to make sense, return the appropriate class @@ -4235,8 +4235,8 @@ def __contains__(self, t): if all(s in Tableaux() for s in t): flatt = sorted(sum((list(row) for s in t for row in s), [])) return flatt == list(range(1, len(flatt)+1)) and all(len(x) == 0 or - (all(row[i]<row[i+1] for row in x for i in range(len(row)-1)) - and all(x[r][c]<x[r+1][c] for c in range(len(x[0])) + (all(row[i] < row[i+1] for row in x for i in range(len(row)-1)) + and all(x[r][c] < x[r+1][c] for c in range(len(x[0])) for r in range(len(x)-1) if len(x[r+1]) > c)) for x in t) else: return t in StandardTableaux() diff --git a/src/sage/combinat/tamari_lattices.py b/src/sage/combinat/tamari_lattices.py index c08b1348e44..6ef7dd06cdc 100644 --- a/src/sage/combinat/tamari_lattices.py +++ b/src/sage/combinat/tamari_lattices.py @@ -48,7 +48,7 @@ # **************************************************************************** from __future__ import annotations from sage.combinat.posets.lattices import LatticePoset, MeetSemilattice -from sage.arith.all import gcd +from sage.arith.misc import gcd def paths_in_triangle(i, j, a, b) -> list[tuple[int, ...]]: diff --git a/src/sage/combinat/tiling.py b/src/sage/combinat/tiling.py index 640f1c6d096..676a4846b23 100644 --- a/src/sage/combinat/tiling.py +++ b/src/sage/combinat/tiling.py @@ -109,8 +109,8 @@ Showing one solution:: sage: solution = next(T.solve()) # long time - sage: G = sum([piece.show2d() for piece in solution], Graphics()) # long time - sage: G.show(aspect_ratio=1, axes=False) # long time + sage: G = sum([piece.show2d() for piece in solution], Graphics()) # long time # optional - sage.plot + sage: G.show(aspect_ratio=1, axes=False) # long time # optional - sage.plot 1d Easy Example --------------- @@ -162,8 +162,8 @@ sage: T = TilingSolver(L, box=(8,8), reflection=True) sage: solution = next(T.solve()) # long time (7s) - sage: G = sum([piece.show2d() for piece in solution], Graphics()) # long time (<1s) - sage: G.show(aspect_ratio=1, axes=False) # long time (2s) + sage: G = sum([piece.show2d() for piece in solution], Graphics()) # long time (<1s) # optional - sage.plot + sage: G.show(aspect_ratio=1, axes=False) # long time (2s) # optional - sage.plot Compute the number of solutions:: @@ -218,8 +218,8 @@ sage: T.number_of_solutions() 10 sage: solution = next(T.solve()) - sage: G = sum([p.show2d() for p in solution], Graphics()) - sage: G.show(aspect_ratio=1) # long time (2s) + sage: G = sum([p.show2d() for p in solution], Graphics()) # optional - sage.plot + sage: G.show(aspect_ratio=1) # long time (2s) # optional - sage.plot :: @@ -240,16 +240,15 @@ sage: from sage.combinat.tiling import Polyomino, TilingSolver sage: Y = Polyomino([(0,0),(1,0),(2,0),(3,0),(2,1)], color='yellow') sage: T = TilingSolver([Y], box=(15,15), reusable=True, reflection=True) - sage: a = T.animate(stop=40) # long time # optional -- ImageMagick - sage: a # long time # optional -- ImageMagick + sage: a = T.animate(stop=40); a # long time # optional -- ImageMagick sage.plot Animation with 40 frames Incremental animation of the solutions (one piece is removed/added at a time):: - sage: a = T.animate('incremental', stop=40) # long time # optional -- ImageMagick - sage: a # long time # optional -- ImageMagick + sage: a = T.animate('incremental', stop=40) # long time # optional -- ImageMagick sage.plot + sage: a # long time # optional -- ImageMagick sage.plot Animation with 40 frames - sage: a.show(delay=50, iterations=1) # long time # optional -- ImageMagick + sage: a.show(delay=50, iterations=1) # long time # optional -- ImageMagick sage.plot 5d Easy Example --------------- @@ -931,11 +930,11 @@ def canonical(self): sage: (p + (3,4,5)).canonical() Polyomino: [(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 1, 1), (1, 2, 0)], Color: deeppink """ - minxyz, maxxyz = self.bounding_box() + minxyz, _ = self.bounding_box() return self - minxyz def canonical_isometric_copies(self, orientation_preserving=True, - mod_box_isometries=False): + mod_box_isometries=False): r""" Return the list of image of ``self`` under isometries of the `n`-cube where the coordinates are all nonnegative and minimal. @@ -1220,8 +1219,7 @@ def isometric_copies(self, box, orientation_preserving=True, all_distinct_cano = self.canonical_isometric_copies(orientation_preserving, mod_box_isometries) for cano in all_distinct_cano: - for t in cano.translated_copies(box=box): - yield t + yield from cano.translated_copies(box=box) def isometric_copies_intersection(self, box, orientation_preserving=True): r""" @@ -1389,7 +1387,7 @@ def show3d(self, size=1): sage: from sage.combinat.tiling import Polyomino sage: p = Polyomino([(0,0,0), (0,1,0), (1,1,0), (1,1,1)], color='blue') - sage: p.show3d() # long time (2s) + sage: p.show3d() # long time (2s) # optional -- sage.plot Graphics3d Object """ assert self._dimension == 3, "Dimension of the polyomino must be 3." @@ -1422,7 +1420,7 @@ def show2d(self, size=0.7, color='black', thickness=1): sage: from sage.combinat.tiling import Polyomino sage: p = Polyomino([(0,0),(1,0),(1,1),(1,2)], color='deeppink') - sage: p.show2d() # long time (0.5s) + sage: p.show2d() # long time (0.5s) # optional -- sage.plot Graphics object consisting of 17 graphics primitives """ assert self._dimension == 2, "Dimension of the polyomino must be 2." @@ -1473,12 +1471,12 @@ def self_surrounding(self, radius, remove_incomplete_copies=True, ....: (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (2, 0), (2, 2), ....: (2, 3), (2, 5), (2, 6), (2, 8)]) sage: solution = H.self_surrounding(8) - sage: G = sum([p.show2d() for p in solution], Graphics()) + sage: G = sum([p.show2d() for p in solution], Graphics()) # optional - sage.plot :: sage: solution = H.self_surrounding(8, remove_incomplete_copies=False) - sage: G = sum([p.show2d() for p in solution], Graphics()) + sage: G = sum([p.show2d() for p in solution], Graphics()) # optional - sage.plot """ # Define the box to tile @@ -2425,38 +2423,38 @@ def animate(self, partial=None, stop=None, size=0.75, axes=False): sage: from sage.combinat.tiling import Polyomino, TilingSolver sage: y = Polyomino([(0,0),(1,0),(2,0),(3,0),(2,1)], color='cyan') sage: T = TilingSolver([y], box=(5,10), reusable=True, reflection=True) - sage: a = T.animate() - sage: a # optional -- ImageMagick # long time + sage: a = T.animate() # optional - sage.plot + sage: a # optional -- ImageMagick # long time # optional - sage.plot Animation with 10 frames Include partial solutions (common prefix between two consecutive solutions):: - sage: a = T.animate('common_prefix') - sage: a # optional -- ImageMagick # long time + sage: a = T.animate('common_prefix') # optional - sage.plot + sage: a # optional -- ImageMagick # long time # optional - sage.plot Animation with 19 frames Incremental solutions (one piece removed or added at a time):: - sage: a = T.animate('incremental') # long time (2s) - sage: a # long time (2s) # optional -- ImageMagick + sage: a = T.animate('incremental') # long time (2s) # optional - sage.plot + sage: a # long time (2s) # optional -- ImageMagick sage.plot Animation with 123 frames :: - sage: a.show() # optional -- ImageMagick # long time + sage: a.show() # optional -- ImageMagick # long time # optional - sage.plot The ``show`` function takes arguments to specify the delay between frames (measured in hundredths of a second, default value 20) and the number of iterations (default value 0, which means to iterate forever). To iterate 4 times with half a second between each frame:: - sage: a.show(delay=50, iterations=4) # optional -- ImageMagick # long time + sage: a.show(delay=50, iterations=4) # optional -- ImageMagick # long time # optional - sage.plot Limit the number of frames:: - sage: a = T.animate('incremental', stop=13) # not tested - sage: a # not tested + sage: a = T.animate('incremental', stop=13) # not tested # optional - sage.plot + sage: a # not tested # optional - sage.plot Animation with 13 frames """ dimension = self._box._dimension diff --git a/src/sage/combinat/triangles_FHM.py b/src/sage/combinat/triangles_FHM.py index 7fca1bd0252..43f2947a51b 100644 --- a/src/sage/combinat/triangles_FHM.py +++ b/src/sage/combinat/triangles_FHM.py @@ -12,11 +12,11 @@ The M-triangle class is motivated by the generating series of Mรถbius numbers for graded posets. A typical example is:: - sage: W = SymmetricGroup(4) - sage: posets.NoncrossingPartitions(W).M_triangle() + sage: W = SymmetricGroup(4) # optional - sage.groups + sage: posets.NoncrossingPartitions(W).M_triangle() # optional - sage.graphs sage.groups M: x^3*y^3 - 6*x^2*y^3 + 6*x^2*y^2 + 10*x*y^3 - 16*x*y^2 - 5*y^3 + 6*x*y + 10*y^2 - 6*y + 1 - sage: unicode_art(_) + sage: unicode_art(_) # optional - sage.graphs sage.modules sage.groups โŽ› -5 10 -6 1โŽž โŽœ 10 -16 6 0โŽŸ โŽœ -6 6 0 0โŽŸ @@ -31,7 +31,7 @@ sage: f = C.greedy_facet() sage: C.F_triangle(f) F: 5*x^3 + 5*x^2*y + 3*x*y^2 + y^3 + 10*x^2 + 8*x*y + 3*y^2 + 6*x + 3*y + 1 - sage: unicode_art(_) + sage: unicode_art(_) # optional - sage.modules โŽ› 1 0 0 0โŽž โŽœ 3 3 0 0โŽŸ โŽœ 3 8 5 0โŽŸ @@ -67,7 +67,7 @@ def _matrix_display(self, variables=None): sage: from sage.combinat.triangles_FHM import _matrix_display sage: x, y = PolynomialRing(QQ,['x', 'y']).gens() - sage: _matrix_display(x**2+x*y+y**3) + sage: _matrix_display(x**2+x*y+y**3) # optional - sage.modules [1 0 0] [0 0 0] [0 1 0] @@ -76,10 +76,10 @@ def _matrix_display(self, variables=None): With a specific choice of variables:: sage: x, y, z = PolynomialRing(QQ,['x','y','z']).gens() - sage: _matrix_display(x**2+z*x*y+z*y**3+z*x,[y,z]) + sage: _matrix_display(x**2+z*x*y+z*y**3+z*x,[y,z]) # optional - sage.modules [ x x 0 1] [x^2 0 0 0] - sage: _matrix_display(x**2+z*x*y+z*y**3+z*x,[x,z]) + sage: _matrix_display(x**2+z*x*y+z*y**3+z*x,[x,z]) # optional - sage.modules [ y^3 y + 1 0] [ 0 0 1] """ @@ -124,7 +124,7 @@ class Triangle(SageObject): sage: from sage.combinat.triangles_FHM import Triangle sage: x, y = polygens(ZZ, 'x,y') sage: ht = Triangle(1+4*x+2*x*y) - sage: unicode_art(ht) + sage: unicode_art(ht) # optional - sage.modules โŽ›0 2โŽž โŽ1 4โŽ  """ @@ -136,7 +136,7 @@ def __init__(self, poly, variables=None): sage: from sage.combinat.triangles_FHM import Triangle sage: x, y = polygens(ZZ, 'x,y') sage: ht = Triangle(1+2*x*y) - sage: unicode_art(ht) + sage: unicode_art(ht) # optional - sage.modules โŽ›0 2โŽž โŽ1 0โŽ  """ @@ -156,7 +156,7 @@ def _ascii_art_(self): sage: from sage.combinat.triangles_FHM import H_triangle sage: x, y = polygens(ZZ, 'x,y') sage: ht = H_triangle(1+2*x*y) - sage: ascii_art(ht) + sage: ascii_art(ht) # optional - sage.modules [0 2] [1 0] """ @@ -171,7 +171,7 @@ def _unicode_art_(self): sage: from sage.combinat.triangles_FHM import H_triangle sage: x, y = polygens(ZZ, 'x,y') sage: ht = H_triangle(1+2*x*y) - sage: unicode_art(ht) + sage: unicode_art(ht) # optional - sage.modules โŽ›0 2โŽž โŽ1 0โŽ  """ @@ -200,7 +200,7 @@ def _latex_(self): sage: from sage.combinat.triangles_FHM import H_triangle sage: x, y = polygens(ZZ, 'x,y') sage: ht = H_triangle(1+2*x*y) - sage: latex(ht) + sage: latex(ht) # optional - sage.modules \left(\begin{array}{rr} 0 & 2 \\ 1 & 0 @@ -296,7 +296,7 @@ def matrix(self): sage: from sage.combinat.triangles_FHM import H_triangle sage: x, y = polygens(ZZ, 'x,y') sage: h = H_triangle(1+2*x*y) - sage: h.matrix() + sage: h.matrix() # optional - sage.modules [0 2] [1 0] """ @@ -557,9 +557,9 @@ def gamma(self): sage: H_triangle(ht).gamma() ฮ“: y^2 + x - sage: W = SymmetricGroup(5) - sage: P = posets.NoncrossingPartitions(W) - sage: P.M_triangle().h().gamma() + sage: W = SymmetricGroup(5) # optional - sage.groups + sage: P = posets.NoncrossingPartitions(W) # optional - sage.graphs + sage: P.M_triangle().h().gamma() # optional - sage.graphs sage.groups ฮ“: y^4 + 3*x*y^2 + 2*x^2 + 2*x*y + x """ x, y = self._vars diff --git a/src/sage/combinat/tuple.py b/src/sage/combinat/tuple.py index 7e7f85c61ef..95ae68b040c 100644 --- a/src/sage/combinat/tuple.py +++ b/src/sage/combinat/tuple.py @@ -16,12 +16,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.libs.gap.libgap import libgap +from sage.arith.misc import binomial from sage.rings.integer_ring import ZZ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets - +from itertools import product, combinations_with_replacement class Tuples(Parent, UniqueRepresentation): """ @@ -35,23 +35,23 @@ class Tuples(Parent, UniqueRepresentation): sage: S = [1,2] sage: Tuples(S,3).list() - [[1, 1, 1], [2, 1, 1], [1, 2, 1], [2, 2, 1], [1, 1, 2], - [2, 1, 2], [1, 2, 2], [2, 2, 2]] + [(1, 1, 1), (2, 1, 1), (1, 2, 1), (2, 2, 1), (1, 1, 2), + (2, 1, 2), (1, 2, 2), (2, 2, 2)] sage: mset = ["s","t","e","i","n"] sage: Tuples(mset,2).list() - [['s', 's'], ['t', 's'], ['e', 's'], ['i', 's'], ['n', 's'], - ['s', 't'], ['t', 't'], ['e', 't'], ['i', 't'], ['n', 't'], - ['s', 'e'], ['t', 'e'], ['e', 'e'], ['i', 'e'], ['n', 'e'], - ['s', 'i'], ['t', 'i'], ['e', 'i'], ['i', 'i'], ['n', 'i'], - ['s', 'n'], ['t', 'n'], ['e', 'n'], ['i', 'n'], ['n', 'n']] + [('s', 's'), ('t', 's'), ('e', 's'), ('i', 's'), ('n', 's'), + ('s', 't'), ('t', 't'), ('e', 't'), ('i', 't'), ('n', 't'), + ('s', 'e'), ('t', 'e'), ('e', 'e'), ('i', 'e'), ('n', 'e'), + ('s', 'i'), ('t', 'i'), ('e', 'i'), ('i', 'i'), ('n', 'i'), + ('s', 'n'), ('t', 'n'), ('e', 'n'), ('i', 'n'), ('n', 'n')] :: - sage: K.<a> = GF(4, 'a') - sage: mset = [x for x in K if x != 0] - sage: Tuples(mset,2).list() - [[a, a], [a + 1, a], [1, a], [a, a + 1], [a + 1, a + 1], [1, a + 1], - [a, 1], [a + 1, 1], [1, 1]] + sage: K.<a> = GF(4, 'a') # optional - sage.rings.finite_rings + sage: mset = [x for x in K if x != 0] # optional - sage.rings.finite_rings + sage: Tuples(mset,2).list() # optional - sage.rings.finite_rings + [(a, a), (a + 1, a), (1, a), (a, a + 1), (a + 1, a + 1), (1, a + 1), + (a, 1), (a + 1, 1), (1, 1)] """ @staticmethod def __classcall_private__(cls, S, k): @@ -75,7 +75,7 @@ def __init__(self, S, k): """ self.S = S self.k = k - self._index_list = [S.index(s) for s in S] + self._index_list = list(set(S.index(s) for s in S)) category = FiniteEnumeratedSets() Parent.__init__(self, category=category) @@ -94,46 +94,34 @@ def __iter__(self): sage: S = [1,2] sage: Tuples(S,3).list() - [[1, 1, 1], [2, 1, 1], [1, 2, 1], [2, 2, 1], [1, 1, 2], - [2, 1, 2], [1, 2, 2], [2, 2, 2]] + [(1, 1, 1), (2, 1, 1), (1, 2, 1), (2, 2, 1), (1, 1, 2), + (2, 1, 2), (1, 2, 2), (2, 2, 2)] sage: mset = ["s","t","e","i","n"] sage: Tuples(mset,2).list() - [['s', 's'], ['t', 's'], ['e', 's'], ['i', 's'], ['n', 's'], - ['s', 't'], ['t', 't'], ['e', 't'], ['i', 't'], - ['n', 't'], ['s', 'e'], ['t', 'e'], ['e', 'e'], ['i', 'e'], - ['n', 'e'], ['s', 'i'], ['t', 'i'], ['e', 'i'], - ['i', 'i'], ['n', 'i'], ['s', 'n'], ['t', 'n'], ['e', 'n'], - ['i', 'n'], ['n', 'n']] - """ - S = self.S - k = self.k - import copy - if k <= 0: - yield [] - return - if k == 1: - for x in S: - yield [x] - return - - for s in S: - for x in Tuples(S, k - 1): - y = copy.copy(x) - y.append(s) - yield y + [('s', 's'), ('t', 's'), ('e', 's'), ('i', 's'), ('n', 's'), + ('s', 't'), ('t', 't'), ('e', 't'), ('i', 't'), ('n', 't'), + ('s', 'e'), ('t', 'e'), ('e', 'e'), ('i', 'e'), ('n', 'e'), + ('s', 'i'), ('t', 'i'), ('e', 'i'), ('i', 'i'), ('n', 'i'), + ('s', 'n'), ('t', 'n'), ('e', 'n'), ('i', 'n'), ('n', 'n')] + sage: Tuples((1,1,2),3).list() + [(1, 1, 1), (2, 1, 1), (1, 2, 1), (2, 2, 1), (1, 1, 2), + (2, 1, 2), (1, 2, 2), (2, 2, 2)] + """ + for p in product(self._index_list, repeat=self.k): + yield tuple(self.S[i] for i in reversed(p)) def cardinality(self): """ EXAMPLES:: sage: S = [1,2,3,4,5] - sage: Tuples(S,2).cardinality() + sage: Tuples(S,2).cardinality() # optional - sage.libs.gap 25 sage: S = [1,1,2,3,4,5] - sage: Tuples(S,2).cardinality() + sage: Tuples(S,2).cardinality() # optional - sage.libs.gap 25 """ - return ZZ(libgap.NrTuples(self._index_list, ZZ(self.k))) + return ZZ(len(self._index_list)).__pow__(self.k) Tuples_sk = Tuples @@ -151,10 +139,10 @@ class UnorderedTuples(Parent, UniqueRepresentation): sage: S = [1,2] sage: UnorderedTuples(S,3).list() - [[1, 1, 1], [1, 1, 2], [1, 2, 2], [2, 2, 2]] + [(1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)] sage: UnorderedTuples(["a","b","c"],2).list() - [['a', 'a'], ['a', 'b'], ['a', 'c'], ['b', 'b'], ['b', 'c'], - ['c', 'c']] + [('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'b'), ('b', 'c'), + ('c', 'c')] """ @staticmethod def __classcall_private__(cls, S, k): @@ -178,7 +166,7 @@ def __init__(self, S, k): """ self.S = S self.k = k - self._index_list = [S.index(s) for s in S] + self._index_list = list(set(S.index(s) for s in S)) category = FiniteEnumeratedSets() Parent.__init__(self, category=category) @@ -191,29 +179,31 @@ def __repr__(self): """ return "Unordered tuples of %s of length %s" % (self.S, self.k) - def list(self): + def __iter__(self): """ EXAMPLES:: sage: S = [1,2] sage: UnorderedTuples(S,3).list() - [[1, 1, 1], [1, 1, 2], [1, 2, 2], [2, 2, 2]] + [(1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)] sage: UnorderedTuples(["a","b","c"],2).list() - [['a', 'a'], ['a', 'b'], ['a', 'c'], ['b', 'b'], ['b', 'c'], - ['c', 'c']] + [('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'b'), ('b', 'c'), + ('c', 'c')] + sage: UnorderedTuples([1,1,2],3).list() + [(1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)] """ - ans = libgap.UnorderedTuples(self._index_list, ZZ(self.k)) - return [[self.S[i] for i in l] for l in ans] + for ans in combinations_with_replacement(self._index_list, self.k): + yield tuple(self.S[i] for i in ans) def cardinality(self): """ EXAMPLES:: sage: S = [1,2,3,4,5] - sage: UnorderedTuples(S,2).cardinality() + sage: UnorderedTuples(S,2).cardinality() # optional - sage.libs.gap 15 """ - return ZZ(libgap.NrUnorderedTuples(self._index_list, ZZ(self.k))) + return binomial(len(self._index_list) + self.k - 1, self.k) UnorderedTuples_sk = UnorderedTuples diff --git a/src/sage/combinat/tutorial.py b/src/sage/combinat/tutorial.py index 6422d920378..a5edc7146ea 100644 --- a/src/sage/combinat/tutorial.py +++ b/src/sage/combinat/tutorial.py @@ -275,37 +275,37 @@ introduce two variables, `C` and `z`, and we define the equation:: - sage: C, z = var('C,z') - sage: sys = [ C == z + C*C ] + sage: C, z = var('C,z') # needs sage.symbolic + sage: sys = [ C == z + C*C ] # needs sage.symbolic There are two solutions, which happen to have closed forms:: - sage: sol = solve(sys, C, solution_dict=True); sol + sage: sol = solve(sys, C, solution_dict=True); sol # needs sage.symbolic [{C: -1/2*sqrt(-4*z + 1) + 1/2}, {C: 1/2*sqrt(-4*z + 1) + 1/2}] - sage: s0 = sol[0][C]; s1 = sol[1][C] + sage: s0 = sol[0][C]; s1 = sol[1][C] # needs sage.symbolic and whose Taylor series begin as follows:: - sage: s0.series(z, 6) + sage: s0.series(z, 6) # needs sage.symbolic 1*z + 1*z^2 + 2*z^3 + 5*z^4 + 14*z^5 + Order(z^6) - sage: s1.series(z, 6) + sage: s1.series(z, 6) # needs sage.symbolic 1 + (-1)*z + (-1)*z^2 + (-2)*z^3 + (-5)*z^4 + (-14)*z^5 + Order(z^6) The second solution is clearly aberrant, while the first one gives the expected coefficients. Therefore, we set:: - sage: C = s0 + sage: C = s0 # needs sage.symbolic We can now calculate the next terms:: - sage: C.series(z, 11) + sage: C.series(z, 11) # needs sage.symbolic 1*z + 1*z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + 429*z^8 + 1430*z^9 + 4862*z^10 + Order(z^11) or calculate, more or less instantaneously, the 100-th coefficient:: - sage: C.series(z, 101).coefficient(z,100) + sage: C.series(z, 101).coefficient(z,100) # needs sage.symbolic 227508830794229349661819540395688853956041682601541047340 It is unfortunate to have to recalculate everything if at some point we @@ -321,7 +321,7 @@ define by a recursive equation:: sage: C = L.undefined(valuation=1) - sage: C.define( z + C * C ) + sage: C.define(z + C * C) :: @@ -338,19 +338,19 @@ We now return to the closed form of `C(z)`:: - sage: z = var('z') - sage: C = s0; C + sage: z = var('z') # needs sage.symbolic + sage: C = s0; C # needs sage.symbolic -1/2*sqrt(-4*z + 1) + 1/2 The `n`-th coefficient in the Taylor series for `C(z)` being given by `\frac{1}{n!} C(z)^{(n)}(0)`, we look at the successive derivatives `C(z)^{(n)}(z)`:: - sage: derivative(C, z, 1) + sage: derivative(C, z, 1) # needs sage.symbolic 1/sqrt(-4*z + 1) - sage: derivative(C, z, 2) + sage: derivative(C, z, 2) # needs sage.symbolic 2/(-4*z + 1)^(3/2) - sage: derivative(C, z, 3) + sage: derivative(C, z, 3) # needs sage.symbolic 12/(-4*z + 1)^(5/2) This suggests the existence of a simple explicit formula, which we will @@ -360,7 +360,7 @@ Taking successive quotients:: - sage: [ (d(n+1) / d(n)) for n in range(1,17) ] + sage: [ (d(n+1) / d(n)) for n in range(1,17) ] # needs sage.symbolic [2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62] we observe that `d_n` satisfies the recurrence relation @@ -373,9 +373,9 @@ We check this:: - sage: n = var('n') - sage: c = 1/n*binomial(2*(n-1),n-1) - sage: [c.subs(n=k) for k in range(1, 11)] + sage: n = var('n') # needs sage.symbolic + sage: c = 1/n*binomial(2*(n-1),n-1) # needs sage.symbolic + sage: [c.subs(n=k) for k in range(1, 11)] # needs sage.symbolic [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862] sage: [catalan_number(k-1) for k in range(1, 11)] [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862] @@ -383,14 +383,14 @@ We can now calculate coefficients much further; here we calculate `c_{100000}` which has more than `60000` digits:: - sage: cc = c(n = 100000) + sage: cc = c(n=100000) # needs sage.symbolic This takes a couple of seconds:: - sage: %time cc = c(100000) # not tested + sage: %time cc = c(100000) # not tested # needs sage.symbolic CPU times: user 2.34 s, sys: 0.00 s, total: 2.34 s Wall time: 2.34 s - sage: ZZ(cc).ndigits() + sage: ZZ(cc).ndigits() # needs sage.symbolic 60198 The methods which we have used generalize to all recursively defined @@ -417,6 +417,7 @@ In the present case, `P=y^2-y+x`. We formally differentiate this equation with respect to `z`:: + sage: # needs sage.symbolic sage: x, y, z = var('x, y, z') sage: P = function('P')(x, y) sage: C = function('C')(z) @@ -434,9 +435,9 @@ In the case of complete binary trees, this gives:: - sage: P = y^2 - y + x - sage: Px = diff(P, x); Py = diff(P, y) - sage: - Px / Py + sage: P = y^2 - y + x # needs sage.symbolic + sage: Px = diff(P, x); Py = diff(P, y) # needs sage.symbolic + sage: - Px / Py # needs sage.symbolic -1/(2*y - 1) Recall that `P(z, C(z))=0`. Thus, we can calculate this fraction @@ -447,7 +448,7 @@ sage: Qx = QQ['x'].fraction_field() sage: Qxy = Qx['y'] - sage: R = Qxy.quo(P); R + sage: R = Qxy.quo(P); R # needs sage.symbolic Univariate Quotient Polynomial Ring in ybar over Fraction Field of Univariate Polynomial Ring in x over Rational Field with modulus y^2 - y + x @@ -458,7 +459,7 @@ We continue the calculation of this fraction in `R`:: - sage: fraction = - R(Px) / R(Py); fraction + sage: fraction = - R(Px) / R(Py); fraction # needs sage.symbolic (1/2/(x - 1/4))*ybar - 1/4/(x - 1/4) .. note:: @@ -474,9 +475,9 @@ `z` and `C(z)` to obtain an expression for `\frac{d}{dz}C(z)`:: - sage: fraction = fraction.lift(); fraction + sage: fraction = fraction.lift(); fraction # needs sage.symbolic (1/2/(x - 1/4))*y - 1/4/(x - 1/4) - sage: fraction(x=z, y=C) + sage: fraction(x=z, y=C) # needs sage.symbolic 2*C(z)/(4*z - 1) - 1/(4*z - 1) or, more legibly, @@ -486,6 +487,7 @@ In this simple case, we can directly deduce from this expression a linear differential equation with coefficients in `\QQ[z]`:: + sage: # needs sage.symbolic sage: equadiff = diff(C,z) == fraction(x=z, y=C) sage: equadiff diff(C(z), z) == 2*C(z)/(4*z - 1) - 1/(4*z - 1) @@ -501,10 +503,10 @@ It is trivial to verify this equation on the closed form:: - sage: Cf = sage.symbolic.function_factory.function('C') - sage: equadiff.substitute_function(Cf, s0.function(z)) + sage: Cf = sage.symbolic.function_factory.function('C') # needs sage.symbolic + sage: equadiff.substitute_function(Cf, s0.function(z)) # needs sage.symbolic (4*z - 1)/sqrt(-4*z + 1) + sqrt(-4*z + 1) == 0 - sage: bool(equadiff.substitute_function(Cf, s0.function(z))) + sage: bool(equadiff.substitute_function(Cf, s0.function(z))) # needs sage.symbolic True .. On veut non seulement remplacer les occurrences de C(z), mais @@ -774,14 +776,14 @@ formula. We look at the number of compositions of `n` ranging from `0` to `9`:: - sage: [ Compositions(n).cardinality() for n in range(10) ] + sage: [Compositions(n).cardinality() for n in range(10)] [1, 1, 2, 4, 8, 16, 32, 64, 128, 256] Similarly, if we consider the number of compositions of `5` by length, we find a line of Pascalโ€™s triangle:: - sage: x = var('x') - sage: sum( x^len(c) for c in C5 ) + sage: x = var('x') # needs sage.symbolic + sage: sum(x^len(c) for c in C5) # needs sage.symbolic x^5 + 4*x^4 + 6*x^3 + 4*x^2 + x The above example uses a functionality which we have not seen yet: @@ -872,12 +874,13 @@ ``Sage``; as a result, the following commands are not yet implemented:: - sage: C = Graphs(5) # todo: not implemented - sage: C.cardinality() # todo: not implemented + sage: # not implemented + sage: C = Graphs(5) + sage: C.cardinality() 34 - sage: Graphs(19).cardinality() # todo: not implemented + sage: Graphs(19).cardinality() 24637809253125004524383007491432768 - sage: Graphs(19).random_element() # todo: not implemented + sage: Graphs(19).random_element() Graph on 19 vertices What we have seen so far also applies, in principle, to finite algebraic @@ -893,8 +896,8 @@ or the algebra of `2\times 2` matrices over the finite field `\ZZ/2\ZZ`:: - sage: C = MatrixSpace(GF(2), 2) - sage: C.list() + sage: C = MatrixSpace(GF(2), 2) # needs sage.modules sage.rings.finite_rings + sage: C.list() # needs sage.modules sage.rings.finite_rings [ [0 0] [1 0] [0 1] [0 0] [0 0] [1 1] [1 0] [1 0] [0 1] [0 1] [0 0], [0 0], [0 0], [1 0], [0 1], [0 0], [1 0], [0 1], [1 0], [0 1], @@ -902,7 +905,7 @@ [0 0] [1 1] [1 1] [1 0] [0 1] [1 1] [1 1], [1 0], [0 1], [1 1], [1 1], [1 1] ] - sage: C.cardinality() + sage: C.cardinality() # needs sage.modules sage.rings.finite_rings 16 .. topic:: Exercise @@ -1048,7 +1051,7 @@ the function ``sum`` receives the iterator directly, and can short-circuit the construction of the intermediate list. If there are a large number of elements, this avoids allocating a large quantity of -memory to fill a list which will be immediately destroyed [2]_. +memory to fill a list which will be immediately destroyed. Most functions that take a list of elements as input will also accept an iterator (or an iterable) instead. To begin with, one can obtain the @@ -1146,24 +1149,24 @@ :: - sage: x = var('x') - sage: sum( x^len(s) for s in Subsets(8) ) + sage: x = var('x') # needs sage.symbolic + sage: sum(x^len(s) for s in Subsets(8)) # needs sage.symbolic x^8 + 8*x^7 + 28*x^6 + 56*x^5 + 70*x^4 + 56*x^3 + 28*x^2 + 8*x + 1 :: - sage: sum( x^p.length() for p in Permutations(3) ) + sage: sum(x^p.length() for p in Permutations(3)) # needs sage.symbolic x^3 + 2*x^2 + 2*x + 1 :: - sage: factor(sum( x^p.length() for p in Permutations(3) )) + sage: factor(sum(x^p.length() for p in Permutations(3))) # needs sage.symbolic (x^2 + x + 1)*(x + 1) :: sage: P = Permutations(5) - sage: all( p in P for p in P ) + sage: all(p in P for p in P) True :: @@ -1238,7 +1241,7 @@ ^^^^^^^^^^^^^^^^^^^^^^^ ``Python`` provides numerous tools for manipulating iterators; most of them -are in the ``itertools`` library, which can be imported by:: +are in the :mod:`itertools` library, which can be imported by:: sage: import itertools @@ -1375,15 +1378,15 @@ to define a formal variable ``Leaf`` for the leaves and a formal 2-ary function ``Node``:: - sage: var('Leaf') + sage: var('Leaf') # needs sage.symbolic Leaf - sage: function('Node', nargs=2) + sage: function('Node', nargs=2) # needs sage.symbolic Node The second tree in :ref:`figure-examples-catalan-trees` can be represented by the expression:: - sage: tr = Node(Node(Leaf, Node(Leaf, Leaf)), Leaf) + sage: tr = Node(Node(Leaf, Node(Leaf, Leaf)), Leaf) # needs sage.symbolic .. _section-constructions: @@ -1666,7 +1669,7 @@ combinatorial species:: sage: from sage.combinat.species.library import * - sage: o = var('o') + sage: o = var('o') # needs sage.symbolic We begin by redefining the complete binary trees; to do so, we stipulate the recurrence relation directly on the sets:: @@ -1678,10 +1681,10 @@ Now we can construct the set of trees with five nodes, list them, count them...:: - sage: BT5 = BT.isotypes([o]*5) - sage: BT5.cardinality() + sage: BT5 = BT.isotypes([o]*5) # needs sage.symbolic + sage: BT5.cardinality() # needs sage.symbolic 14 - sage: BT5.list() + sage: BT5.list() # needs sage.symbolic [o*(o*(o*(o*o))), o*(o*((o*o)*o)), o*((o*o)*(o*o)), o*((o*(o*o))*o), o*(((o*o)*o)*o), (o*o)*(o*(o*o)), (o*o)*((o*o)*o), (o*(o*o))*(o*o), ((o*o)*o)*(o*o), @@ -1730,8 +1733,8 @@ :: - sage: FW3 = FW.isotypes([o]*3) - sage: FW3.list() + sage: FW3 = FW.isotypes([o]*3) # needs sage.symbolic + sage: FW3.list() # needs sage.symbolic [o*(o*(o*{})), o*(o*(({}*o)*{})), o*((({}*o)*o)*{}), (({}*o)*o)*(o*{}), (({}*o)*o)*(({}*o)*{})] @@ -1805,7 +1808,7 @@ then the graphs with two edges, and so on. The set of children of a graph `G` can be constructed by *augmentation*, adding an edge in all the possible ways to `G`, and then selecting, from among those graphs, -the ones that are still canonical [3]_. Recursively, one obtains all +the ones that are still canonical [2]_. Recursively, one obtains all the canonical graphs. .. figure:: ../../media/prefix-tree-graphs-4.png @@ -1819,7 +1822,7 @@ them, exactly the same algorithm can be used, selecting only the children which are planar:: - sage: [len(list(graphs(n, property = lambda G: G.is_planar()))) + sage: [len(list(graphs(n, property=lambda G: G.is_planar()))) ....: for n in range(7)] [1, 1, 2, 4, 11, 33, 142] @@ -1848,12 +1851,6 @@ clean up. .. [2] - Technical detail: ``range`` returns an iterator on - `\{0,\dots,8\}` while ``range`` returns the corresponding - list. Starting in ``Python`` 3.0, ``range`` will behave like ``range``, and - ``range`` will no longer be needed. - -.. [3] In practice, an efficient implementation would exploit the symmetries of `G`, i.e., its automorphism group, to reduce the number of children to explore, and to reduce the cost of each test of diff --git a/src/sage/combinat/vector_partition.py b/src/sage/combinat/vector_partition.py index ba1a51c29d4..2bd89dbb244 100644 --- a/src/sage/combinat/vector_partition.py +++ b/src/sage/combinat/vector_partition.py @@ -52,15 +52,15 @@ def find_min(vect): [0, 1, 0] """ i = len(vect) - while vect[i-1]==0 and i>0: - i=i-1 + while vect[i-1] == 0 and i > 0: + i = i-1 min = [0]*len(vect) - if i>0: - min[i-1]=1 + if i > 0: + min[i-1] = 1 return min -def IntegerVectorsIterator(vect, min = None): +def IntegerVectorsIterator(vect, min=None): """ Return an iterator over the list of integer vectors which are componentwise less than or equal to ``vect``, and lexicographically greater than or equal @@ -102,7 +102,6 @@ def IntegerVectorsIterator(vect, min = None): yield [j] + vec - class VectorPartition(CombinatorialElement): r""" A vector partition is a multiset of integer vectors. @@ -162,7 +161,7 @@ def partition_at_vertex(self, i): sage: V.partition_at_vertex(1) [4, 2] """ - return Partition(sorted([vec[i] for vec in self._list], reverse = True)) + return Partition(sorted([vec[i] for vec in self._list], reverse=True)) class VectorPartitions(UniqueRepresentation, Parent): @@ -316,7 +315,7 @@ def __iter__(self): for part in self._parts: # choose the first part if tuple(part) == self._vec: yield self.element_class(self, [list(part)]) - elif any(part[i]>self._vec[i] for i in range(len(self._vec))): + elif any(part[i] > self._vec[i] for i in range(len(self._vec))): pass else:# recursively find all possibilities for the rest of the vector partition new_vec = tuple(self._vec[i]-part[i] for i in range(len(self._vec))) diff --git a/src/sage/combinat/words/__init__.py b/src/sage/combinat/words/__init__.py deleted file mode 100644 index 4dc6dd45dba..00000000000 --- a/src/sage/combinat/words/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -r""" -Combinatorics on words - -**Main modules and their methods:** - -- :ref:`sage.combinat.words.abstract_word` -- :ref:`sage.combinat.words.finite_word` -- :ref:`sage.combinat.words.infinite_word` -- :ref:`sage.combinat.words.alphabet` -- :ref:`sage.combinat.words.words` -- :ref:`sage.combinat.words.paths` -- :ref:`sage.combinat.words.morphism` -- :ref:`sage.combinat.words.shuffle_product` -- :ref:`sage.combinat.words.suffix_trees` - -Main classes and functions meant to be used by the user: - - :func:`~sage.combinat.words.word.Word`, - :class:`~sage.combinat.words.words.FiniteWords`, - :class:`~sage.combinat.words.words.InfiniteWords`, - :func:`~sage.combinat.words.words.Words`, - :func:`~sage.combinat.words.alphabet.Alphabet`, - :class:`~sage.combinat.words.morphism.WordMorphism`, - :class:`~sage.combinat.words.paths.WordPaths`. - -A list of common words can be accessed through ``words.<tab>`` and are listed in -the :ref:`words catalog <sage.combinat.words.word_generators>`. - -**Internal representation of words:** - -- :ref:`sage.combinat.words.word` -- :ref:`sage.combinat.words.word_char` -- :ref:`sage.combinat.words.word_datatypes` -- :ref:`sage.combinat.words.word_infinite_datatypes` - -**Options:** - -- :ref:`sage.combinat.words.word_options` - -See :func:`~sage.combinat.words.word_options.WordOptions`. -""" diff --git a/src/sage/combinat/words/abstract_word.py b/src/sage/combinat/words/abstract_word.py index ff3be9930ad..1488d8e7271 100644 --- a/src/sage/combinat/words/abstract_word.py +++ b/src/sage/combinat/words/abstract_word.py @@ -251,7 +251,7 @@ def __len__(self): """ L = self.length() if L is None or L is Infinity: - msg = "Python len method cannot return a non integer value (=%s): "%L + msg = "Python len method cannot return a non integer value (=%s): " % L msg += "use length method instead." raise TypeError(msg) return int(L) @@ -1478,24 +1478,24 @@ def sum_digits(self, base=2, mod=None): Sum of digits modulo 2 of the prime numbers written in base 2:: - sage: Word(primes(1000)).sum_digits() + sage: Word(primes(1000)).sum_digits() # optional - sage.libs.pari word: 1001110100111010111011001011101110011011... Sum of digits modulo 3 of the prime numbers written in base 3:: - sage: Word(primes(1000)).sum_digits(base=3) + sage: Word(primes(1000)).sum_digits(base=3) # optional - sage.libs.pari word: 2100002020002221222121022221022122111022... - sage: Word(primes(1000)).sum_digits(base=3, mod=3) + sage: Word(primes(1000)).sum_digits(base=3, mod=3) # optional - sage.libs.pari word: 2100002020002221222121022221022122111022... Sum of digits modulo 2 of the prime numbers written in base 3:: - sage: Word(primes(1000)).sum_digits(base=3, mod=2) + sage: Word(primes(1000)).sum_digits(base=3, mod=2) # optional - sage.libs.pari word: 0111111111111111111111111111111111111111... Sum of digits modulo 7 of the prime numbers written in base 10:: - sage: Word(primes(1000)).sum_digits(base=10, mod=7) + sage: Word(primes(1000)).sum_digits(base=10, mod=7) # optional - sage.libs.pari word: 2350241354435041006132432241353546006304... Negative entries:: diff --git a/src/sage/combinat/words/all.py b/src/sage/combinat/words/all.py index 078ca4e48ab..687b572c8e5 100644 --- a/src/sage/combinat/words/all.py +++ b/src/sage/combinat/words/all.py @@ -1,3 +1,48 @@ +r""" +Combinatorics on words + +**Main modules and their methods:** + +- :ref:`sage.combinat.words.abstract_word` +- :ref:`sage.combinat.words.finite_word` +- :ref:`sage.combinat.words.infinite_word` +- :ref:`sage.combinat.words.alphabet` +- :ref:`sage.combinat.words.words` +- :ref:`sage.combinat.words.paths` +- :ref:`sage.combinat.words.morphism` +- :ref:`sage.combinat.words.shuffle_product` +- :ref:`sage.combinat.words.suffix_trees` + +Main classes and functions meant to be used by the user: + + :func:`~sage.combinat.words.word.Word`, + :class:`~sage.combinat.words.words.FiniteWords`, + :class:`~sage.combinat.words.words.InfiniteWords`, + :func:`~sage.combinat.words.words.Words`, + :func:`~sage.combinat.words.alphabet.Alphabet`, + :class:`~sage.combinat.words.morphism.WordMorphism`, + :class:`~sage.combinat.words.paths.WordPaths`. + +A list of common words can be accessed through ``words.<tab>`` and are listed in +the :ref:`words catalog <sage.combinat.words.word_generators>`. + +**Internal representation of words:** + +- :ref:`sage.combinat.words.word` +- :ref:`sage.combinat.words.word_char` +- :ref:`sage.combinat.words.word_datatypes` +- :ref:`sage.combinat.words.word_infinite_datatypes` + +**Options:** + +- :ref:`sage.combinat.words.word_options` + +See :func:`~sage.combinat.words.word_options.WordOptions`. +""" +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) + from .alphabet import Alphabet, build_alphabet from .morphism import WordMorphism from .paths import WordPaths diff --git a/src/sage/combinat/words/alphabet.py b/src/sage/combinat/words/alphabet.py index 3286eb8b3b4..5d1b0d5468a 100644 --- a/src/sage/combinat/words/alphabet.py +++ b/src/sage/combinat/words/alphabet.py @@ -193,15 +193,15 @@ def build_alphabet(data=None, names=None, name=None): Traceback (most recent call last): ... ValueError: invalid value for names - sage: Alphabet(8, x) + sage: Alphabet(8, x) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: invalid value for names - sage: Alphabet(name=x, names="punctuation") + sage: Alphabet(name=x, names="punctuation") # optional - sage.symbolic Traceback (most recent call last): ... ValueError: name cannot be specified with any other argument - sage: Alphabet(x) + sage: Alphabet(x) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: unable to construct an alphabet from the given parameters diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 148e2eb9836..e476b756183 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -136,7 +136,7 @@ sage: st = w.suffix_tree() sage: st Implicit Suffix Tree of the word: abaabbba - sage: st.show(word_labels=True) + sage: st.show(word_labels=True) # optional - sage.plot :: @@ -190,9 +190,9 @@ Rauzy graphs:: sage: f = words.FibonacciWord()[:30] - sage: f.rauzy_graph(4) + sage: f.rauzy_graph(4) # optional - sage.graphs Looped digraph on 5 vertices - sage: f.reduced_rauzy_graph(4) + sage: f.reduced_rauzy_graph(4) # optional - sage.graphs Looped multi-digraph on 2 vertices Left-special and bispecial factors:: @@ -305,8 +305,8 @@ def coerce(self, other): Otherwise it will attempt to convert ``other`` to the domain of ``self``. If that fails, it will attempt to convert ``self`` to the domain of - ``other``. If both attempts fail, it raises a ``TypeError`` to signal - failure. + ``other``. If both attempts fail, it raises a :class:`TypeError` + to signal failure. EXAMPLES:: @@ -501,18 +501,20 @@ def __pow__(self, exp): return self # infinite power of a non-empty word - fcn = lambda n: self[n % self.length()] + def fcn(n): + return self[n % self.length()] + if exp is Infinity: return self._parent.shift()(fcn) - #If exp*|self| is not an integer - length = exp* self.length() + # If exp*|self| is not an integer + length = exp * self.length() if length in ZZ and length >= 0: return self._parent(fcn, length=length) else: raise ValueError("Power of the word is not defined on the exponent {}:" " the length of the word ({}) times the exponent ({}) must" - " be a positive integer".format(exp,self.length(),exp)) + " be a positive integer".format(exp, self.length(), exp)) def length(self): r""" @@ -574,7 +576,7 @@ def content(self, n=None): from collections import Counter c = Counter(self) if n is not None: - alphabet = range(1,n+1) + alphabet = range(1, n + 1) elif not self.parent().alphabet().cardinality() == +Infinity: alphabet = self.parent().alphabet() else: @@ -616,13 +618,13 @@ def is_yamanouchi(self, n=None): """ from sage.combinat.words.word import Word if n is not None: - w = Word(self, alphabet=list(range(1,n+1))) + w = Word(self, alphabet=list(range(1, n + 1))) elif not self.parent().alphabet().cardinality() == +Infinity: w = self else: w = Word(self, alphabet=sorted(self.letters())) l = w.length() - for a in range(l-1,-1,-1): + for a in range(l - 1, -1, -1): mu = w.parent()(self[a:]).content() if not all(mu[i] >= mu[i+1] for i in range(len(mu)-1)): return False @@ -686,7 +688,7 @@ def schuetzenberger_involution(self, n=None): alphsize = parent.alphabet().cardinality() if not alphsize == +Infinity: n = max(parent.alphabet()) - elif r.length()>0: + elif r.length() > 0: n = max(w) for k in range(r.length()): w[k] = n+1 - w[k] @@ -869,7 +871,7 @@ def to_integer_list(self): """ cmp_key = self._parent.sortkey_letters ordered_alphabet = sorted(self.letters(), key=cmp_key) - index = dict((b,a) for (a,b) in enumerate(ordered_alphabet)) + index = {b: a for a, b in enumerate(ordered_alphabet)} return [index[a] for a in self] def to_ordered_set_partition(self): @@ -1459,16 +1461,16 @@ def topological_entropy(self, n): sage: W = Words([0, 1]) sage: w = W([0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1]) - sage: t = w.topological_entropy(3); t + sage: t = w.topological_entropy(3); t # optional - sage.symbolic 1/3*log(7)/log(2) - sage: n(t) + sage: n(t) # optional - sage.symbolic 0.935784974019201 :: sage: w = words.ThueMorseWord()[:100] sage: topo = w.topological_entropy - sage: for i in range(0, 41, 5): + sage: for i in range(0, 41, 5): # optional - sage.symbolic ....: print("{} {}".format(i, n(topo(i), digits=5))) 0 1.0000 5 0.71699 @@ -1492,7 +1494,7 @@ def topological_entropy(self, n): sage: W = Words(range(20)) sage: w = W(range(20)) - sage: w.topological_entropy(3) + sage: w.topological_entropy(3) # optional - sage.symbolic 1/3*log(18)/log(20) """ d = self.parent().alphabet().cardinality() @@ -1520,12 +1522,12 @@ def rauzy_graph(self, n): sage: w = Word(range(10)); w word: 0123456789 - sage: g = w.rauzy_graph(3); g + sage: g = w.rauzy_graph(3); g # optional - sage.graphs Looped digraph on 8 vertices sage: WordOptions(identifier='') - sage: g.vertices(sort=True) + sage: g.vertices(sort=True) # optional - sage.graphs [012, 123, 234, 345, 456, 567, 678, 789] - sage: g.edges(sort=True) + sage: g.edges(sort=True) # optional - sage.graphs [(012, 123, 3), (123, 234, 4), (234, 345, 5), @@ -1538,20 +1540,20 @@ def rauzy_graph(self, n): :: sage: f = words.FibonacciWord()[:100] - sage: f.rauzy_graph(8) + sage: f.rauzy_graph(8) # optional - sage.graphs Looped digraph on 9 vertices :: sage: w = Word('1111111') - sage: g = w.rauzy_graph(3) - sage: g.edges(sort=True) + sage: g = w.rauzy_graph(3) # optional - sage.graphs + sage: g.edges(sort=True) # optional - sage.graphs [(word: 111, word: 111, word: 1)] :: sage: w = Word('111') - sage: for i in range(5) : w.rauzy_graph(i) + sage: for i in range(5): w.rauzy_graph(i) # optional - sage.graphs Looped multi-digraph on 1 vertex Looped digraph on 1 vertex Looped digraph on 1 vertex @@ -1562,9 +1564,9 @@ def rauzy_graph(self, n): sage: W = Words('abcde') sage: w = W('abc') - sage: w.rauzy_graph(0) + sage: w.rauzy_graph(0) # optional - sage.graphs Looped multi-digraph on 1 vertex - sage: _.edges(sort=True) + sage: _.edges(sort=True) # optional - sage.graphs [(word: , word: , word: a), (word: , word: , word: b), (word: , word: , word: c)] @@ -1579,7 +1581,7 @@ def rauzy_graph(self, n): u = w[:-1] v = w[1:] a = w[-1:] - g.add_edge(u,v,a) + g.add_edge(u, v, a) return g def reduced_rauzy_graph(self, n): @@ -1631,35 +1633,37 @@ def reduced_rauzy_graph(self, n): sage: w = Word(range(10)); w word: 0123456789 - sage: g = w.reduced_rauzy_graph(3); g + sage: g = w.reduced_rauzy_graph(3); g # optional - sage.graphs Looped multi-digraph on 2 vertices - sage: g.vertices(sort=True) + sage: g.vertices(sort=True) # optional - sage.graphs [word: 012, word: 789] - sage: g.edges(sort=True) + sage: g.edges(sort=True) # optional - sage.graphs [(word: 012, word: 789, word: 3456789)] For the Fibonacci word:: sage: f = words.FibonacciWord()[:100] - sage: g = f.reduced_rauzy_graph(8);g + sage: g = f.reduced_rauzy_graph(8);g # optional - sage.graphs Looped multi-digraph on 2 vertices - sage: g.vertices(sort=True) + sage: g.vertices(sort=True) # optional - sage.graphs [word: 01001010, word: 01010010] - sage: g.edges(sort=True) - [(word: 01001010, word: 01010010, word: 010), (word: 01010010, word: 01001010, word: 01010), (word: 01010010, word: 01001010, word: 10)] + sage: g.edges(sort=True) # optional - sage.graphs + [(word: 01001010, word: 01010010, word: 010), + (word: 01010010, word: 01001010, word: 01010), + (word: 01010010, word: 01001010, word: 10)] For periodic words:: sage: from itertools import cycle sage: w = Word(cycle('abcd'))[:100] - sage: g = w.reduced_rauzy_graph(3) - sage: g.edges(sort=True) + sage: g = w.reduced_rauzy_graph(3) # optional - sage.graphs + sage: g.edges(sort=True) # optional - sage.graphs [(word: abc, word: abc, word: dabc)] :: sage: w = Word('111') - sage: for i in range(5) : w.reduced_rauzy_graph(i) + sage: for i in range(5): w.reduced_rauzy_graph(i) # optional - sage.graphs Looped digraph on 1 vertex Looped digraph on 1 vertex Looped digraph on 1 vertex @@ -1671,10 +1675,10 @@ def reduced_rauzy_graph(self, n): sage: sigma = WordMorphism('a->abcd,b->cd,c->cd,d->cd') sage: w = sigma.fixed_point('a')[:100]; w word: abcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd... - sage: g = w.reduced_rauzy_graph(5) - sage: g.vertices(sort=True) + sage: g = w.reduced_rauzy_graph(5) # optional - sage.graphs + sage: g.vertices(sort=True) # optional - sage.graphs [word: abcdc, word: cdcdc] - sage: g.edges(sort=True) + sage: g.edges(sort=True) # optional - sage.graphs [(word: abcdc, word: cdcdc, word: dc), (word: cdcdc, word: cdcdc, word: dc)] AUTHOR: @@ -1686,20 +1690,20 @@ def reduced_rauzy_graph(self, n): from copy import copy g = copy(self.rauzy_graph(n)) # Otherwise it changes the rauzy_graph function. - l = [v for v in g if g.in_degree(v)==1 and g.out_degree(v)==1] + l = [v for v in g if g.in_degree(v) == 1 == g.out_degree(v)] if g.num_verts() != 0 and len(l) == g.num_verts(): # In this case, the Rauzy graph is simply a cycle. g = DiGraph() g.allow_loops(True) g.add_vertex(self[:n]) - g.add_edge(self[:n],self[:n],self[n:n+len(l)]) + g.add_edge(self[:n], self[:n], self[n:n + len(l)]) else: g.allow_loops(True) g.allow_multiple_edges(True) for v in l: [i] = g.neighbors_in(v) [o] = g.neighbors_out(v) - g.add_edge(i,o,g.edge_label(i,v)[0]*g.edge_label(v,o)[0]) + g.add_edge(i, o, g.edge_label(i, v)[0]*g.edge_label(v, o)[0]) g.delete_vertex(v) return g @@ -1729,8 +1733,7 @@ def left_special_factors_iterator(self, n=None): """ if n is None: for i in range(self.length()): - for w in self.left_special_factors_iterator(i): - yield w + yield from self.left_special_factors_iterator(i) else: left_extensions = defaultdict(set) for w in self.factor_iterator(n+1): @@ -1797,8 +1800,7 @@ def right_special_factors_iterator(self, n=None): """ if n is None: for i in range(self.length()): - for w in self.right_special_factors_iterator(i): - yield w + yield from self.right_special_factors_iterator(i) else: right_extensions = defaultdict(set) for w in self.factor_iterator(n+1): @@ -1888,18 +1890,17 @@ def bispecial_factors_iterator(self, n=None): """ if n is None: for i in range(self.length()): - for w in self.bispecial_factors_iterator(i): - yield w + yield from self.bispecial_factors_iterator(i) else: left_extensions = defaultdict(set) right_extensions = defaultdict(set) - for w in self.factor_iterator(n+2): + for w in self.factor_iterator(n + 2): v = w[1:-1] left_extensions[v].add(w[0]) right_extensions[v].add(w[-1]) for v in left_extensions: if (len(left_extensions[v]) > 1 and - len(right_extensions[v]) > 1): + len(right_extensions[v]) > 1): yield v def bispecial_factors(self, n=None): @@ -2064,7 +2065,7 @@ def _conjugates_list(self): [word: a] """ S = [self] - for i in range(1,self.length()): + for i in range(1, self.length()): S.append(self.conjugate(i)) return S @@ -2389,12 +2390,12 @@ def longest_common_suffix(self, other): return other iter = enumerate(zip(reversed(self), reversed(other))) - i,(b,c) = next(iter) + i, (b, c) = next(iter) if b != c: - #In this case, return the empty word + # In this case, return the empty word return self[:0] - for i,(b,c) in iter: + for i, (b, c) in iter: if b != c: return self[-i:] else: @@ -2504,14 +2505,14 @@ def is_palindrome(self, f=None): """ l = self.length() if f is None: - return self[:l//2] == self[l//2 + l%2:].reversal() + return self[:l//2] == self[l//2 + l % 2:].reversal() else: from sage.combinat.words.morphism import WordMorphism if not isinstance(f, WordMorphism): f = WordMorphism(f) if not f.is_involution(): raise ValueError("f must be an involution") - return self[:l//2 + l%2] == f(self[l//2:].reversal()) + return self[:l//2 + l % 2] == f(self[l//2:].reversal()) def lps(self, f=None, l=None): r""" @@ -2587,26 +2588,26 @@ def lps(self, f=None, l=None): word: bbabaa word: abbabaab """ - #If the length of the lps of self[:-1] is not known: + # If the length of the lps of self[:-1] is not known: if l is None: l = self.lps_lengths(f)[-1] return self[len(self)-l:] - #If l == w[:-1].length(), there is no shortcut + # If l == w[:-1].length(), there is no shortcut if self.length() == l + 1: return self.lps(f=f) - #Obtain the letter to the left (g) and to the right (d) of the - #precedent lps of self + # Obtain the letter to the left (g) and to the right (d) of the + # precedent lps of self g = self[-l-2] d = self[-1] - #If the word g*d is a `f`-palindrome, the result follows + # If the word g*d is a `f`-palindrome, the result follows if f is None: if g == d: return self[-l-2:] else: - #Otherwise, the length of the lps of self is smallest than l+2 + # Otherwise, the length of the lps of self is smallest than l+2 return self[-l-1:].lps() else: from sage.combinat.words.morphism import WordMorphism @@ -2666,20 +2667,20 @@ def palindromic_lacunas_study(self, f=None): sage: c == set([Word(), Word('ba'), Word('baba'), Word('ab'), Word('bbabaa'), Word('abbabaab')]) True """ - #Initialize the results of computations + # Initialize the results of computations palindromes = set() lengths_lps = [None] * self.length() lacunas = [] - #Initialize the first lps + # Initialize the first lps pal = self[:0] palindromes.add(pal) - #For all the non-empty prefixes of self, + # For all the non-empty prefixes of self, for i in range(self.length()): - #Compute its longest `f`-palindromic suffix using the preceding lps (pal) - pal = self[:i+1].lps(l=pal.length(),f=f) + # Compute its longest `f`-palindromic suffix using the preceding lps (pal) + pal = self[:i+1].lps(l=pal.length(), f=f) lengths_lps[i] = pal.length() @@ -2864,8 +2865,7 @@ def length_maximal_palindrome(self, j, m=None, f=None): i -= 1 if jj == 2 * i: return 0 - else: - return jj - 2*i - 1 + return jj - 2 * i - 1 def lengths_maximal_palindromes(self, f=None): r""" @@ -2911,7 +2911,7 @@ def lengths_maximal_palindromes(self, f=None): for j in range(1, 2 * len(self) + 1): if j >= k + LPC[k]: - p = self.length_maximal_palindrome((j - 1)*0.5, -(j%2), f) + p = self.length_maximal_palindrome((j - 1)*0.5, -(j % 2), f) LPC.append(p) if j + p > k + LPC[k]: k = j @@ -3004,7 +3004,7 @@ def palindromes(self, f=None): [word: , word: ab, word: abbabaab, word: ba, word: baba, word: bbabaa] """ LPS = self.lps_lengths(f) - return set(self[i-LPS[i] : i] for i in range(len(self)+1)) + return set(self[i - LPS[i]: i] for i in range(len(self) + 1)) def palindromic_complexity(self, n): r""" @@ -3026,7 +3026,7 @@ def palindromic_complexity(self, n): sage: [w.palindromic_complexity(i) for i in range(20)] [1, 2, 2, 2, 2, 0, 4, 0, 4, 0, 4, 0, 4, 0, 2, 0, 2, 0, 4, 0] """ - return len([x for x in self.palindromes() if len(x)==n]) + return len([1 for x in self.palindromes() if len(x) == n]) def palindrome_prefixes(self): r""" @@ -3096,9 +3096,9 @@ def defect(self, f=None): sage: sa = WordMorphism('a->ab,b->b') sage: sb = WordMorphism('a->a,b->ba') sage: w = (sa*sb*sb*sa*sa*sa*sb).fixed_point('a') - sage: w[:30].defect() + sage: w[:30].defect() # optional - sage.modules 0 - sage: w[110:140].defect() + sage: w[110:140].defect() # optional - sage.modules 0 It is even conjectured that the defect of an aperiodic word which is @@ -3106,11 +3106,11 @@ def defect(self, f=None): (see [BBGL2008]_):: sage: w = words.ThueMorseWord() - sage: w[:50].defect() + sage: w[:50].defect() # optional - sage.modules 12 - sage: w[:100].defect() + sage: w[:100].defect() # optional - sage.modules 16 - sage: w[:300].defect() + sage: w[:300].defect() # optional - sage.modules 52 For generalized defect with an involution different from the identity, @@ -3159,10 +3159,10 @@ def defect(self, f=None): A = set(map(D, self.letters())) while A: x = A.pop() - if f(x) != x: # count only non f-palindromic letters + if f(x) != x: # count only non f-palindromic letters if f(x) in A: A.remove(f(x)) - g_w +=1 + g_w += 1 return self.length()+1-g_w-len(self.palindromes(f=f)) @@ -3287,8 +3287,8 @@ def palindromic_closure(self, side='right', f=None): if f is None: if side == 'right': l = self.lps().length() - #return self * self[-(l+1)::-1] - return self * self[:self.length()-l].reversal() + # return self * self[-(l+1)::-1] + return self * self[:self.length() - l].reversal() elif side == 'left': l = self.reversal().lps().length() return self[:l-1:-1] * self @@ -3411,7 +3411,7 @@ def minimal_period(self): """ if self.is_empty(): return 1 - return self.length()-self.length_border() + return self.length() - self.length_border() def order(self): r""" @@ -3438,7 +3438,7 @@ def order(self): 0 """ from sage.rings.rational import Rational - return Rational((self.length(),self.minimal_period())) + return Rational((self.length(), self.minimal_period())) def critical_exponent(self): r""" @@ -3489,8 +3489,8 @@ def critical_exponent(self): queue = [(0, 0, -1, 0)] # suffix tree vertices to visit for Depth First Search best_exp = 1 # best exponent so far while queue: - (v,i,j,l) = queue.pop() - for k in range(i,j+1): + v, i, j, l = queue.pop() + for k in range(i, j+1): if l-j+k-1 != 0: m = pft[l-j+k-2] while m > 0 and self[j-l+m] != self[k-1]: @@ -3504,7 +3504,7 @@ def critical_exponent(self): current_exp = QQ((current_pos+1, current_pos+1-m)) if current_exp > best_exp: best_exp = current_exp - for ((i,j),u) in st._transition_function[v].items(): + for ((i, j), u) in st._transition_function[v].items(): if j is None: j = self.length() queue.append((u, i, j, l+j-i+1)) @@ -3672,7 +3672,7 @@ def periods(self, divide_length=False): """ n = len(self) if divide_length: - possible = (i for i in range(1,n) if n % i == 0) + possible = (i for i in range(1, n) if not n % i) else: possible = range(1, n) return [x for x in possible if self.has_period(x)] @@ -3739,10 +3739,10 @@ def longest_common_subword(self, other): # the empty word. lcs = [[[] for _ in repeat(None, len(w2) + 1)] for j in range(2)] - for i,l1 in enumerate(self): - for j,l2 in enumerate(other): + for i, l1 in enumerate(self): + for j, l2 in enumerate(other): lcs[0][j] = max(lcs[0][j-1], lcs[1][j], - lcs[1][j-1] + ([l1] if l1==l2 else []),key=len) + lcs[1][j-1] + ([l1] if l1 == l2 else []), key=len) # Maintaining the meaning of lcs for the next loop lcs.pop(1) @@ -4029,9 +4029,9 @@ def inversions(self): """ inversion_list = [] cmp_key = self._parent.sortkey_letters - for (i1, letter1) in enumerate(self): + for i1, letter1 in enumerate(self): k1 = cmp_key(letter1) - for (i2, letter2) in enumerate(self[i1 + 1:]): + for i2, letter2 in enumerate(self[i1 + 1:]): k2 = cmp_key(letter2) if k1 > k2: inversion_list.append([i1, i1 + i2 + 1]) @@ -4087,8 +4087,8 @@ def degree(self, weights=None): for a in self: if a not in rank: rank[a] = rank_fcn(a) - deg += rank[a]+1 - elif isinstance(weights, (list,tuple)): + deg += rank[a] + 1 + elif isinstance(weights, (list, tuple)): rank = {} for a in self: if a not in rank: @@ -4212,7 +4212,7 @@ def last_position_dict(self): {'1': 3, '2': 6, '3': 5} """ d = {} - for (i, letter) in enumerate(self): + for i, letter in enumerate(self): d[letter] = i return d @@ -4357,7 +4357,7 @@ def find(self, sub, start=0, end=None): if not isinstance(sub, FiniteWord_class): try: sub = self.parent()(sub) - except (ValueError,TypeError): + except (ValueError, TypeError): return -1 p = self[start:end].first_occurrence(sub) return -1 if p is None else p+start @@ -5180,7 +5180,7 @@ def overlap_partition(self, other, delay=0, p=None, involution=None): {{-4, -2, 0, 2, 4}, {-5, -3, -1, 1, 3, 5}} """ if not isinstance(delay, (int, Integer)): - raise TypeError("delay (=%s) must be an integer"%delay) + raise TypeError("delay (=%s) must be an integer" % delay) elif delay < 0: return other.overlap_partition(self, -delay, p) @@ -5193,23 +5193,23 @@ def overlap_partition(self, other, delay=0, p=None, involution=None): elif not isinstance(p, DisjointSet_class): raise TypeError("p(=%s) is not a DisjointSet" % p) - #Join the classes of each pair of letters that are one above the other + # Join the classes of each pair of letters that are one above the other from sage.combinat.words.morphism import WordMorphism S = zip(islice(self, int(delay), None), other) if involution is None: - for (a,b) in S: + for a, b in S: p.union(a, b) elif isinstance(involution, WordMorphism): - for (a,b) in S: + for a, b in S: p.union(a, b) # take the first letter of the word p.union(involution(a)[0], involution(b)[0]) elif callable(involution): - for (a,b) in S: + for a, b in S: p.union(a, b) p.union(involution(a), involution(b)) else: - raise TypeError("involution (=%s) must be callable"%involution) + raise TypeError("involution (=%s) must be callable" % involution) return p # TODO: requires a parent with a sortkey_letters method @@ -5311,11 +5311,11 @@ def _s(self, i): # replace the unpaired subword i^a (i+1)^b # with i^b (i+1)^a - for j,p in enumerate(unpaired): + for j, p in enumerate(unpaired): if j < len(unpaired_ip): out[p] = i else: - out[p] = i+1 + out[p] = i + 1 return self.parent()(out, check=False) def _to_partition_content(self): @@ -5336,7 +5336,7 @@ def _to_partition_content(self): from sage.combinat.words.word import Word n = max(self) - ev = Word( Words(n)(self).evaluation() ) + ev = Word(Words(n)(self).evaluation()) sig = ev.reversal().standard_permutation().reduced_word() # sig is now the reverse complement of a reduced word for a minimal @@ -5610,7 +5610,7 @@ def balance(self): for i in range(1, self.length()): start = iter(self) end = iter(self) - abelian = dict(zip(alphabet, [0]*len(alphabet))) + abelian = dict(zip(alphabet, [0] * len(alphabet))) for _ in range(i): abelian[next(end)] += 1 abel_max = abelian.copy() @@ -5766,7 +5766,7 @@ def abelian_vectors(self, n): S = set() if n > self.length(): return S - rank = dict((letter,i) for i,letter in enumerate(alphabet)) + rank = {letter: i for i, letter in enumerate(alphabet)} start = iter(self) end = iter(self) abelian = [0] * size @@ -5885,7 +5885,7 @@ def sturmian_desubstitute_as_possible(self): if self.is_empty(): return self W = self.parent() - if W.alphabet().cardinality()== 2: + if W.alphabet().cardinality() == 2: alphabet = W.alphabet() else: alphabet = self.letters() @@ -5893,15 +5893,15 @@ def sturmian_desubstitute_as_possible(self): raise TypeError('your word must be defined on a binary alphabet or use at most two different letters') elif len(alphabet) < 2: return W() - word_from_letter = {l:W([l],datatype="list",check=False) for l in alphabet} + word_from_letter = {l: W([l], datatype="list", check=False) for l in alphabet} is_prefix = True current_run_length = 0 prefix_length = 0 prefix_letter = self[0] - is_isolated = {alphabet[0]:True,alphabet[1]:True} - minimal_run = {alphabet[0]:Infinity,alphabet[1]:Infinity} - maximal_run = {alphabet[0]:0,alphabet[1]:0} - runs = {alphabet[0]:[],alphabet[1]:[]} + is_isolated = {alphabet[0]: True, alphabet[1]: True} + minimal_run = {alphabet[0]: Infinity, alphabet[1]: Infinity} + maximal_run = {alphabet[0]: 0, alphabet[1]: 0} + runs = {alphabet[0]: [], alphabet[1]: []} for i in self: if is_prefix: if i == prefix_letter: @@ -5919,8 +5919,8 @@ def sturmian_desubstitute_as_possible(self): is_isolated[i] = False else: runs[previous_letter].append(current_run_length) - minimal_run[previous_letter] = min(minimal_run[previous_letter],current_run_length) - maximal_run[previous_letter] = max(maximal_run[previous_letter],current_run_length) + minimal_run[previous_letter] = min(minimal_run[previous_letter], current_run_length) + maximal_run[previous_letter] = max(maximal_run[previous_letter], current_run_length) current_run_length = 1 previous_letter = i # at this point, previous_letter is the suffix letter and current_run_length is the suffix length @@ -5930,13 +5930,13 @@ def sturmian_desubstitute_as_possible(self): return W() else: if is_isolated[alphabet[0]]: - l_isolated = alphabet[0] #the isolated letter - l_running = alphabet[1] #the running letter (non-isolated) + l_isolated = alphabet[0] # the isolated letter + l_running = alphabet[1] # the running letter (non-isolated) else: l_isolated = alphabet[1] l_running = alphabet[0] - w_isolated = word_from_letter[l_isolated] #the word associated to the isolated letter - w_running = word_from_letter[l_running] #the word associated to the running letter + w_isolated = word_from_letter[l_isolated] # the word associated to the isolated letter + w_running = word_from_letter[l_running] # the word associated to the running letter min_run = minimal_run[l_running] if (prefix_letter == l_isolated) or (prefix_length <= min_run): desubstitued_word = W() @@ -6066,17 +6066,17 @@ def is_tangent(self): """ if (self.parent().alphabet().cardinality() != 2): raise TypeError('your word must be defined on a binary alphabet') - [a,b] = self.parent().alphabet() + a, b = self.parent().alphabet() mini = 0 maxi = 0 height = 0 for i in self.sturmian_desubstitute_as_possible(): if i == a: height = height + 1 - maxi = max(maxi , height) + maxi = max(maxi, height) if i == b: height = height - 1 - mini = min(mini , height) + mini = min(mini, height) return (maxi - mini <= 2) # TODO. @@ -6291,16 +6291,15 @@ def shuffle(self, other, overlap=0): if overlap == 0: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 return ShuffleProduct_w1w2(self, other) - else: - if any(a not in ZZ for a in self) or any(a not in ZZ for a in other): - raise ValueError("for a nonzero overlap, words must contain integers as letters") - if overlap is True: - from sage.combinat.shuffle import ShuffleProduct_overlapping - return ShuffleProduct_overlapping(self, other, self.parent()) - elif isinstance(overlap, (int,Integer)): - from sage.combinat.shuffle import ShuffleProduct_overlapping_r - return ShuffleProduct_overlapping_r(self, other, overlap, self.parent()) - raise ValueError('overlapping must be True or an integer') + if any(a not in ZZ for a in self) or any(a not in ZZ for a in other): + raise ValueError("for a nonzero overlap, words must contain integers as letters") + if overlap is True: + from sage.combinat.shuffle import ShuffleProduct_overlapping + return ShuffleProduct_overlapping(self, other, self.parent()) + elif isinstance(overlap, (int, Integer)): + from sage.combinat.shuffle import ShuffleProduct_overlapping_r + return ShuffleProduct_overlapping_r(self, other, overlap, self.parent()) + raise ValueError('overlapping must be True or an integer') def shifted_shuffle(self, other, shift=None): r""" @@ -6824,18 +6823,18 @@ def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickn EXAMPLES:: - sage: Word(range(20)).colored_vector() + sage: Word(range(20)).colored_vector() # optional - sage.plot Graphics object consisting of 21 graphics primitives - sage: Word(range(100)).colored_vector(0,0,10,1) + sage: Word(range(100)).colored_vector(0,0,10,1) # optional - sage.plot Graphics object consisting of 101 graphics primitives - sage: Words(range(100))(range(10)).colored_vector() + sage: Words(range(100))(range(10)).colored_vector() # optional - sage.plot Graphics object consisting of 11 graphics primitives sage: w = Word('abbabaab') - sage: w.colored_vector() + sage: w.colored_vector() # optional - sage.plot Graphics object consisting of 9 graphics primitives - sage: w.colored_vector(cmap='autumn') + sage: w.colored_vector(cmap='autumn') # optional - sage.plot Graphics object consisting of 9 graphics primitives - sage: Word(range(20)).colored_vector(label='Rainbow') + sage: Word(range(20)).colored_vector(label='Rainbow') # optional - sage.plot Graphics object consisting of 23 graphics primitives When two words are defined under the same parent, same letters are @@ -6844,30 +6843,30 @@ def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickn sage: W = Words(range(20)) sage: w = W(range(20)) sage: y = W(range(10,20)) - sage: y.colored_vector(y=1, x=10) + w.colored_vector() + sage: y.colored_vector(y=1, x=10) + w.colored_vector() # optional - sage.plot Graphics object consisting of 32 graphics primitives TESTS: The empty word:: - sage: Word().colored_vector() + sage: Word().colored_vector() # optional - sage.plot Graphics object consisting of 1 graphics primitive - sage: Word().colored_vector(label='empty') + sage: Word().colored_vector(label='empty') # optional - sage.plot Graphics object consisting of 3 graphics primitives Unknown cmap:: - sage: Word(range(100)).colored_vector(cmap='jolies') + sage: Word(range(100)).colored_vector(cmap='jolies') # optional - sage.plot Traceback (most recent call last): ... RuntimeError: Color map jolies not known - sage: Word(range(100)).colored_vector(cmap='__doc__') + sage: Word(range(100)).colored_vector(cmap='__doc__') # optional - sage.plot Traceback (most recent call last): ... RuntimeError: Color map __doc__ not known """ - #Recognize the color map + # Recognize the color map import matplotlib.cm as cm from matplotlib.colors import LinearSegmentedColormap as C key_error = False @@ -6883,32 +6882,32 @@ def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickn sage.misc.verbose.verbose("The possible color maps include: %s" % possibilities, level=0) raise RuntimeError("Color map %s not known" % cmap) - #Drawing the colored vector... + # Drawing the colored vector... from sage.plot.line import line from sage.plot.polygon import polygon from sage.plot.text import text - #The default width of the vector + # The default width of the vector if width == 'default': width = self.length() - #The black frame of the vector + # The black frame of the vector ymax = y + height - L = [(x,y), (x+width,y), (x+width,ymax), (x,ymax), (x,y)] - rep = line(L, rgbcolor=(0,0,0), thickness=thickness) + L = [(x, y), (x+width, y), (x+width, ymax), (x, ymax), (x, y)] + rep = line(L, rgbcolor=(0, 0, 0), thickness=thickness) - #The label + # The label if label is not None: hl = height/2.0 # height of the label rectangle ymax2 = ymax + hl - rep += text(str(label), (x+width/2.0, ymax + hl/2.0), rgbcolor=(1,0,0)) - L = [(x,ymax), (x+width,ymax), (x+width,ymax2), (x,ymax2), (x,ymax)] - rep += line(L, rgbcolor=(0,0,0), thickness=thickness) + rep += text(str(label), (x+width/2.0, ymax + hl/2.0), rgbcolor=(1, 0, 0)) + L = [(x, ymax), (x+width, ymax), (x+width, ymax2), (x, ymax2), (x, ymax)] + rep += line(L, rgbcolor=(0, 0, 0), thickness=thickness) - #base : the width of each rectangle + # base : the width of each rectangle base = width / float(self.length()) if not self.is_empty() else None - #A colored rectangle for each letter + # A colored rectangle for each letter dim = self.parent().alphabet().cardinality() if dim is Infinity: ordered_alphabet = sorted(self.letters(), @@ -6917,8 +6916,8 @@ def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickn else: ordered_alphabet = self.parent().alphabet() dim = float(self.parent().alphabet().cardinality()) - letter_to_integer_dict = dict((a, i) for (i, a) in - enumerate(ordered_alphabet)) + letter_to_integer_dict = {a: i for i, a in + enumerate(ordered_alphabet)} xp = x for a in self: i = letter_to_integer_dict[a] diff --git a/src/sage/combinat/words/lyndon_word.py b/src/sage/combinat/words/lyndon_word.py index ca271c5a114..6adb96421e5 100644 --- a/src/sage/combinat/words/lyndon_word.py +++ b/src/sage/combinat/words/lyndon_word.py @@ -12,17 +12,15 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent - +from sage.arith.misc import divisors, gcd, moebius, multinomial +from sage.combinat.combinat_cython import lyndon_word_iterator from sage.combinat.composition import Composition, Compositions -from sage.rings.integer import Integer -from sage.arith.all import divisors, gcd, moebius, multinomial - from sage.combinat.necklace import _sfc -from sage.combinat.words.words import FiniteWords from sage.combinat.words.finite_word import FiniteWord_class -from sage.combinat.combinat_cython import lyndon_word_iterator +from sage.combinat.words.words import FiniteWords +from sage.rings.integer import Integer +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation def LyndonWords(e=None, k=None): diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 6cca2834ee5..389c37a9b65 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -24,7 +24,7 @@ abstract numeration system associated to the morphism and the starting letter, see chapter 3 of the book [BR2010b]_:: - sage: w[10000000] + sage: w[10000000] # optional - sage.modules 'b' """ @@ -57,7 +57,7 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: w = m.fixed_point('a') sage: w word: abaababaabaababaababaabaababaabaababaaba... - sage: w[555:1000] + sage: w[555:1000] # optional - sage.modules word: abaababaabaababaababaabaababaabaababaaba... sage: w.length() +Infinity @@ -68,11 +68,11 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: m.fixed_point('a') word: abcbabacababaabcbabaabccaabcbabaabcbabaa... sage: w = m.fixed_point('a') - sage: w[7] + sage: w[7] # optional - sage.modules 'c' - sage: w[2:7] + sage: w[2:7] # optional - sage.modules word: cbaba - sage: w[500:503] + sage: w[500:503] # optional - sage.modules word: caa When the morphic word is finite:: @@ -81,7 +81,7 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: w = m.fixed_point("a") sage: w word: ab - sage: w[0] + sage: w[0] # optional - sage.modules 'a' sage: w.length() 2 @@ -93,7 +93,7 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: from sage.combinat.words.morphic import WordDatatype_morphic sage: coding = {'a':'x', 'b':'y'} sage: w = WordDatatype_morphic(W, m, 'a', coding=coding) - sage: [w[i] for i in range(10)] + sage: [w[i] for i in range(10)] # optional - sage.modules ['x', 'y', 'x', 'x', 'y', 'x', 'y', 'x', 'x', 'y'] TESTS:: @@ -104,9 +104,9 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: for _ in range(10000): _ = next(it) sage: L = [next(it) for _ in range(10)]; L ['d', 'd', 'd', 'c', 'd', 'd', 'd', 'c', 'b', 'a'] - sage: w[10000:10010] + sage: w[10000:10010] # optional - sage.modules word: dddcdddcba - sage: list(w[10000:10010]) == L + sage: list(w[10000:10010]) == L # optional - sage.modules True """ @@ -177,18 +177,18 @@ def representation(self, n): sage: m = WordMorphism('a->ab,b->a') sage: w = m.fixed_point('a') - sage: w.representation(5) + sage: w.representation(5) # optional - sage.modules [1, 0, 0, 0] When the morphic word is finite:: sage: m = WordMorphism("a->ab,b->,c->cdab,d->dcab") sage: w = m.fixed_point("a") - sage: w.representation(0) + sage: w.representation(0) # optional - sage.modules [] - sage: w.representation(1) + sage: w.representation(1) # optional - sage.modules [1] - sage: w.representation(2) + sage: w.representation(2) # optional - sage.modules Traceback (most recent call last): ... IndexError: index (=2) out of range, the fixed point is finite and has length 2 @@ -204,10 +204,10 @@ def representation(self, n): sage: w = WordDatatype_morphic(W, m, 'a') sage: type(w) <class 'sage.combinat.words.morphic.WordDatatype_morphic'> - sage: w.representation(5) + sage: w.representation(5) # optional - sage.modules [1, 0, 0, 0] """ - letters_to_int = {a:i for (i,a) in enumerate(self._alphabet)} + letters_to_int = {a:i for (i,a) in enumerate(self._alphabet)} position = letters_to_int[self._letter] M = self._morphism.incidence_matrix() vMk = vector([1]*len(self._alphabet)) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 5b302a34742..b06acd3839e 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -66,7 +66,7 @@ Incidence matrix:: - sage: matrix(m) + sage: matrix(m) # optional - sage.modules [2 3 1] [1 3 0] [1 1 1] @@ -568,7 +568,7 @@ def __ne__(self, other): """ return not self == other - def __repr__(self): + def __repr__(self) -> str: r""" Return the string representation of the morphism. @@ -587,7 +587,7 @@ def __repr__(self): """ return "WordMorphism: %s" % str(self) - def __str__(self): + def __str__(self) -> str: r""" Return the morphism in str. @@ -612,7 +612,7 @@ def __str__(self): :: sage: s = WordMorphism({1:[1,2],2:[1]}) - sage: s.dual_map() + sage: s.dual_map() # optional - sage.modules E_1^*(1->12, 2->1) TESTS:: @@ -625,7 +625,7 @@ def __str__(self): for lettre, image in self._morph.items()] return ', '.join(sorted(L)) - def __call__(self, w, order=1, datatype=None): + def __call__(self, w, order=1): r""" Return the image of ``w`` under self to the given order. @@ -635,8 +635,6 @@ def __call__(self, w, order=1, datatype=None): - ``order`` - integer or plus ``Infinity`` (default: 1) - - ``datatype`` - deprecated - OUTPUT: - ``word`` - order-th iterated image under self of ``w`` @@ -752,7 +750,7 @@ def __call__(self, w, order=1, datatype=None): sage: m('') word: - The default datatype when the input is a finite word is another + When the input is a finite word, the output is another finite word:: sage: w = m('aabb') @@ -764,49 +762,7 @@ def __call__(self, w, order=1, datatype=None): sage: import tempfile sage: with tempfile.NamedTemporaryFile(suffix=".sobj") as f: ....: save(w, filename=f.name) - - The ``datatype`` argument is deprecated:: - - sage: m = WordMorphism('a->ab,b->ba') - sage: w = m('aaab',datatype='list') - doctest:warning - ... - DeprecationWarning: the "datatype" argument is deprecated - See https://github.com/sagemath/sage/issues/26307 for details. - - sage: type(w) - <class 'sage.combinat.words.word.FiniteWord_list'> - sage: w = m('aaab',datatype='str') - sage: type(w) - <class 'sage.combinat.words.word.FiniteWord_str'> - sage: w = m('aaab',datatype='tuple') - sage: type(w) - <class 'sage.combinat.words.word.FiniteWord_tuple'> - - To use str datatype for the output word, the domain and codomain - alphabet must consist of str objects:: - - sage: m = WordMorphism({0:[0,1],1:[1,0]}) - sage: w = m([0],4); type(w) - <class 'sage.combinat.words.word.FiniteWord_char'> - sage: w = m([0],4,datatype='list') - doctest:warning - ... - DeprecationWarning: the "datatype" argument is deprecated - See https://github.com/sagemath/sage/issues/26307 for details. - sage: type(w) - <class 'sage.combinat.words.word.FiniteWord_list'> - sage: w = m([0],4,datatype='str') - Traceback (most recent call last): - ... - ValueError: 0 not in alphabet - sage: w = m([0],4,datatype='tuple'); type(w) - <class 'sage.combinat.words.word.FiniteWord_tuple'> """ - if datatype is not None: - from sage.misc.superseded import deprecation - deprecation(26307, 'the "datatype" argument is deprecated') - if order == 1: D = self.domain() C = self.codomain() @@ -817,10 +773,7 @@ def __call__(self, w, order=1, datatype=None): im = C() for a in w: im += self._morph[a] - if datatype is not None: - return C(im, datatype=datatype) - else: - return im + return im if isinstance(w, Iterable): pass @@ -853,7 +806,7 @@ def __call__(self, w, order=1, datatype=None): return self.fixed_point(letter=letter) elif isinstance(order, (int, Integer)) and order > 1: - return self(self(w, order - 1), datatype=datatype) + return self(self(w, order - 1)) elif order == 0: return self._domain(w) @@ -1146,21 +1099,21 @@ def _matrix_(self, R=None): sage: fibo = WordMorphism('a->ab,b->a') sage: tm = WordMorphism('a->ab,b->ba') - sage: Mfibo = matrix(fibo); Mfibo # indirect doctest + sage: Mfibo = matrix(fibo); Mfibo # indirect doctest # optional - sage.modules [1 1] [1 0] - sage: Mtm = matrix(tm); Mtm + sage: Mtm = matrix(tm); Mtm # optional - sage.modules [1 1] [1 1] - sage: Mtm * Mfibo == matrix(tm*fibo) # indirect doctest + sage: Mtm * Mfibo == matrix(tm*fibo) # indirect doctest # optional - sage.modules True - sage: Mfibo * Mtm == matrix(fibo*tm) # indirect doctest + sage: Mfibo * Mtm == matrix(fibo*tm) # indirect doctest # optional - sage.modules True - sage: Mfibo.parent() + sage: Mfibo.parent() # optional - sage.modules Full MatrixSpace of 2 by 2 dense matrices over Integer Ring - sage: p = Mfibo.charpoly(); p + sage: p = Mfibo.charpoly(); p # optional - sage.modules x^2 - x - 1 - sage: p.roots(ring=RR, multiplicities=False) + sage: p.roots(ring=RR, multiplicities=False) # optional - sage.modules [-0.618033988749895, 1.61803398874989] """ if R is None: @@ -1181,12 +1134,12 @@ def incidence_matrix(self): EXAMPLES:: sage: m = WordMorphism('a->abc,b->a,c->c') - sage: m.incidence_matrix() + sage: m.incidence_matrix() # optional - sage.modules [1 1 0] [1 0 0] [1 0 1] sage: m = WordMorphism('a->abc,b->a,c->c,d->abbccccabca,e->abc') - sage: m.incidence_matrix() + sage: m.incidence_matrix() # optional - sage.modules [1 1 0 3 1] [1 0 0 3 1] [1 0 1 5 1] @@ -1249,9 +1202,10 @@ def is_endomorphism(self): We check that :trac:`8674` is fixed:: - sage: P = WordPaths('abcd') - sage: m = WordMorphism('a->adab,b->ab,c->cbcd,d->cd', domain=P, codomain=P) - sage: m.is_endomorphism() + sage: P = WordPaths('abcd') # optional - sage.modules + sage: m = WordMorphism('a->adab,b->ab,c->cbcd,d->cd', # optional - sage.modules + ....: domain=P, codomain=P) + sage: m.is_endomorphism() # optional - sage.modules True """ return self.codomain() == self.domain() @@ -1540,11 +1494,11 @@ def pisot_eigenvector_right(self): EXAMPLES:: sage: m = WordMorphism('a->aaaabbc,b->aaabbc,c->aabc') - sage: matrix(m) + sage: matrix(m) # optional - sage.modules [4 3 2] [2 2 1] [1 1 1] - sage: m.pisot_eigenvector_right() + sage: m.pisot_eigenvector_right() # optional - sage.modules sage.rings.number_field (1, 0.5436890126920763?, 0.2955977425220848?) """ eig = self.incidence_matrix().eigenvectors_right() @@ -1570,11 +1524,11 @@ def pisot_eigenvector_left(self): EXAMPLES:: sage: m = WordMorphism('a->aaaabbc,b->aaabbc,c->aabc') - sage: matrix(m) + sage: matrix(m) # optional - sage.modules [4 3 2] [2 2 1] [1 1 1] - sage: m.pisot_eigenvector_left() + sage: m.pisot_eigenvector_left() # optional - sage.modules sage.rings.number_field (1, 0.8392867552141611?, 0.5436890126920763?) """ eig = self.incidence_matrix().eigenvectors_left() @@ -2119,12 +2073,12 @@ def language(self, n, u=None): The fibonacci morphism:: - sage: s = WordMorphism({0: [0,1], 1:[0]}) - sage: sorted(s.language(3)) + sage: s = WordMorphism({0: [0,1], 1: [0]}) + sage: sorted(s.language(3)) # optional - sage.modules [word: 001, word: 010, word: 100, word: 101] - sage: len(s.language(1000)) + sage: len(s.language(1000)) # optional - sage.modules 1001 - sage: all(len(s.language(n)) == n+1 for n in range(100)) + sage: all(len(s.language(n)) == n+1 for n in range(100)) # optional - sage.modules True A growing but non-primitive example. The DOL-languages generated @@ -2134,14 +2088,14 @@ def language(self, n, u=None): sage: u = s.fixed_point(0) sage: A0 = u[:200].factor_set(5) - sage: B0 = s.language(5, [0]) - sage: set(A0) == B0 + sage: B0 = s.language(5, [0]) # optional - sage.modules + sage: set(A0) == B0 # optional - sage.modules True sage: v = s.fixed_point(2) sage: A2 = v[:200].factor_set(5) - sage: B2 = s.language(5, [2]) - sage: set(A2) == B2 + sage: B2 = s.language(5, [2]) # optional - sage.modules + sage: set(A2) == B2 # optional - sage.modules True sage: len(A0), len(A2) @@ -2150,7 +2104,7 @@ def language(self, n, u=None): The Chacon transformation (non-primitive):: sage: s = WordMorphism({0: [0,0,1,0], 1:[1]}) - sage: sorted(s.language(10)) + sage: sorted(s.language(10)) # optional - sage.modules [word: 0001000101, word: 0001010010, ... @@ -2504,8 +2458,8 @@ def dual_map(self, k=1): EXAMPLES:: - sage: sigma = WordMorphism({1:[2],2:[3],3:[1,2]}) - sage: sigma.dual_map() + sage: sigma = WordMorphism({1: [2], 2: [3], 3: [1,2]}) + sage: sigma.dual_map() # optional - sage.modules E_1^*(1->2, 2->3, 3->12) :: @@ -2559,7 +2513,7 @@ def rauzy_fractal_projection(self, eig=None, prec=53): is:: sage: s = WordMorphism('1->12,2->13,3->1') - sage: s.rauzy_fractal_projection() + sage: s.rauzy_fractal_projection() # optional - sage.modules {'1': (1.00000000000000, 0.000000000000000), '2': (-1.41964337760708, -0.606290729207199), '3': (-0.771844506346038, 1.11514250803994)} @@ -2567,9 +2521,9 @@ def rauzy_fractal_projection(self, eig=None, prec=53): TESTS:: sage: t = WordMorphism('1->12,2->3,3->45,4->5,5->6,6->7,7->8,8->1') - sage: E = t.incidence_matrix().eigenvalues() - sage: x = [x for x in E if -0.8 < x < -0.7][0] - sage: t.rauzy_fractal_projection(prec=10) + sage: E = t.incidence_matrix().eigenvalues() # optional - sage.modules + sage: x = [x for x in E if -0.8 < x < -0.7][0] # optional - sage.modules + sage: t.rauzy_fractal_projection(prec=10) # optional - sage.modules {'1': (1.0, 0.00), '2': (-1.7, -0.56), '3': (0.79, 1.3), @@ -2578,7 +2532,7 @@ def rauzy_fractal_projection(self, eig=None, prec=53): '6': (0.79, 1.3), '7': (0.21, -1.3), '8': (-0.88, 0.74)} - sage: t.rauzy_fractal_projection(eig=x, prec=10) + sage: t.rauzy_fractal_projection(eig=x, prec=10) # optional - sage.modules {'1': (1.0, 0.00), '2': (-0.12, -0.74), '3': (-0.66, -0.56), @@ -2663,19 +2617,20 @@ def rauzy_fractal_points(self, n=None, exchange=False, eig=None, translate=None, and ``'3'`` are respectively:: sage: s = WordMorphism('1->12,2->13,3->1') - sage: D = s.rauzy_fractal_points(n=100) - sage: len(D['1']) + sage: D = s.rauzy_fractal_points(n=100) # optional - sage.modules + sage: len(D['1']) # optional - sage.modules 54 - sage: len(D['2']) + sage: len(D['2']) # optional - sage.modules 30 - sage: len(D['3']) + sage: len(D['3']) # optional - sage.modules 16 TESTS:: sage: s = WordMorphism('1->12,2->13,3->1') - sage: D = s.rauzy_fractal_points(n=100, exchange=True, translate=[(3,1,-2), (5,-33,8)], prec=40) - sage: len(D['1']) + sage: D = s.rauzy_fractal_points(n=100, exchange=True, # optional - sage.modules + ....: translate=[(3,1,-2), (5,-33,8)], prec=40) + sage: len(D['1']) # optional - sage.modules 108 AUTHOR: @@ -2837,113 +2792,127 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, #. The Rauzy fractal of the Tribonacci substitution:: sage: s = WordMorphism('1->12,2->13,3->1') - sage: s.rauzy_fractal_plot() # long time + sage: s.rauzy_fractal_plot() # long time # optional - sage.plot Graphics object consisting of 3 graphics primitives #. The "Hokkaido" fractal. We tweak the plot using the plotting options to get a nice reusable picture, in which we mark the origin by a black dot:: sage: s = WordMorphism('a->ab,b->c,c->d,d->e,e->a') - sage: G = s.rauzy_fractal_plot(n=100000, point_size=3, plot_origin=(50,"black")) # not tested + sage: G = s.rauzy_fractal_plot(n=100000, point_size=3, # not tested + ....: plot_origin=(50,"black")) sage: G.show(figsize=10, axes=false) # not tested #. Another "Hokkaido" fractal and its domain exchange:: sage: s = WordMorphism({1:[2], 2:[4,3], 3:[4], 4:[5,3], 5:[6], 6:[1]}) - sage: s.rauzy_fractal_plot() # not tested takes > 1 second - sage: s.rauzy_fractal_plot(exchange=True) # not tested takes > 1 second + sage: s.rauzy_fractal_plot() # not tested (> 1 second) + sage: s.rauzy_fractal_plot(exchange=True) # not tested (> 1 second) #. A three-dimensional Rauzy fractal:: sage: s = WordMorphism('1->12,2->13,3->14,4->1') - sage: s.rauzy_fractal_plot() # not tested takes > 1 second + sage: s.rauzy_fractal_plot() # not tested (> 1 second) #. A one-dimensional Rauzy fractal (very scattered):: sage: s = WordMorphism('1->2122,2->1') - sage: s.rauzy_fractal_plot().show(figsize=20) # not tested takes > 1 second + sage: s.rauzy_fractal_plot().show(figsize=20) # not tested (> 1 second) #. A high resolution plot of a complicated fractal:: sage: s = WordMorphism('1->23,2->123,3->1122233') - sage: G = s.rauzy_fractal_plot(n=300000) # not tested takes > 1 second - sage: G.show(axes=false, figsize=20) # not tested takes > 1 second + sage: G = s.rauzy_fractal_plot(n=300000) # not tested (> 1 second) + sage: G.show(axes=false, figsize=20) # not tested (> 1 second) #. A nice colorful animation of a domain exchange:: sage: s = WordMorphism('1->21,2->3,3->4,4->25,5->6,6->7,7->1') - sage: L = [s.rauzy_fractal_plot(), s.rauzy_fractal_plot(exchange=True)] # not tested takes > 1 second - sage: animate(L, axes=false).show(delay=100) # not tested takes > 1 second + sage: L = [s.rauzy_fractal_plot(), # not tested (> 1 second) + ....: s.rauzy_fractal_plot(exchange=True)] + sage: animate(L, axes=false).show(delay=100) # not tested (> 1 second) #. Plotting with only one color:: sage: s = WordMorphism('1->12,2->31,3->1') - sage: s.rauzy_fractal_plot(colormap={'1':'black', '2':'black', '3':'black'}) # not tested takes > 1 second + sage: cm = {'1':'black', '2':'black', '3':'black'} + sage: s.rauzy_fractal_plot(colormap=cm) # not tested (> 1 second) #. Different fractals can be obtained by choosing another (non-Pisot) eigenvalue:: sage: s = WordMorphism('1->12,2->3,3->45,4->5,5->6,6->7,7->8,8->1') - sage: E = s.incidence_matrix().eigenvalues() - sage: x = [x for x in E if -0.8 < x < -0.7][0] - sage: s.rauzy_fractal_plot() # not tested takes > 1 second - sage: s.rauzy_fractal_plot(eig=x) # not tested takes > 1 second + sage: E = s.incidence_matrix().eigenvalues() # optional - sage.modules + sage: x = [x for x in E if -0.8 < x < -0.7][0] # optional - sage.modules + sage: s.rauzy_fractal_plot() # not tested (> 1 second) + sage: s.rauzy_fractal_plot(eig=x) # not tested (> 1 second) #. A Pisot reducible substitution with seemingly overlapping tiles:: - sage: s = WordMorphism({1:[1,2], 2:[2,3], 3:[4], 4:[5], 5:[6], 6:[7], 7:[8], 8:[9], 9:[10], 10:[1]}) - sage: s.rauzy_fractal_plot() # not tested takes > 1 second + sage: s = WordMorphism({1:[1,2], 2:[2,3], 3:[4], 4:[5], 5:[6], + ....: 6:[7], 7:[8], 8:[9], 9:[10], 10:[1]}) + sage: s.rauzy_fractal_plot() # not tested (> 1 second) #. A non-Pisot reducible substitution with a strange Rauzy fractal:: sage: s = WordMorphism({1:[3,2], 2:[3,3], 3:[4], 4:[1]}) - sage: s.rauzy_fractal_plot() # not tested takes > 1 second + sage: s.rauzy_fractal_plot() # not tested (> 1 second) #. A substitution with overlapping tiles. We use the options ``colormap`` and ``opacity`` to study how the tiles overlap:: sage: s = WordMorphism('1->213,2->4,3->5,4->1,5->21') - sage: s.rauzy_fractal_plot() # not tested takes > 1 second - sage: s.rauzy_fractal_plot(colormap={'1':'red', '4':'purple'}) # not tested takes > 1 second - sage: s.rauzy_fractal_plot(opacity={'1':0.1,'2':1,'3':0.1,'4':0.1,'5':0.1}, n=150000) # not tested takes > 1 second + sage: s.rauzy_fractal_plot() # not tested (> 1 second) + sage: s.rauzy_fractal_plot(colormap={'1':'red', '4':'purple'}) # not tested (> 1 second) + sage: s.rauzy_fractal_plot(n=150000, # not tested (> 1 second) + ....: opacity={'1':0.1,'2':1,'3':0.1,'4':0.1,'5':0.1}) #. Funny experiments by playing with the precision of the float numbers used to plot the fractal:: sage: s = WordMorphism('1->12,2->13,3->1') - sage: s.rauzy_fractal_plot(prec=6) # not tested - sage: s.rauzy_fractal_plot(prec=9) # not tested - sage: s.rauzy_fractal_plot(prec=15) # not tested - sage: s.rauzy_fractal_plot(prec=19) # not tested - sage: s.rauzy_fractal_plot(prec=25) # not tested + sage: s.rauzy_fractal_plot(prec=6) # not tested + sage: s.rauzy_fractal_plot(prec=9) # not tested + sage: s.rauzy_fractal_plot(prec=15) # not tested + sage: s.rauzy_fractal_plot(prec=19) # not tested + sage: s.rauzy_fractal_plot(prec=25) # not tested #. Using the ``translate`` option to plot periodic tilings:: sage: s = WordMorphism('1->12,2->13,3->1') - sage: s.rauzy_fractal_plot(n=10000, translate=[(0,0,0),(-1,0,1),(0,-1,1),(1,-1,0),(1,0,-1),(0,1,-1),(-1,1,0)]) # not tested takes > 1 second + sage: s.rauzy_fractal_plot(n=10000, # not tested (> 1 second) + ....: translate=[(0,0,0),(-1,0,1),(0,-1,1),(1,-1,0), + ....: (1,0,-1),(0,1,-1),(-1,1,0)]) :: sage: t = WordMorphism("a->aC,b->d,C->de,d->a,e->ab") # substitution found by Julien Bernat - sage: V = [vector((0,0,1,0,-1)), vector((0,0,1,-1,0))] - sage: S = set(map(tuple, [i*V[0] + j*V[1] for i in [-1,0,1] for j in [-1,0,1]])) - sage: t.rauzy_fractal_plot(n=10000, translate=S, exchange=true) # not tested takes > 1 second + sage: V = [vector((0,0,1,0,-1)), vector((0,0,1,-1,0))] # optional - sage.modules + sage: S = set(map(tuple, [i*V[0] + j*V[1] + ....: for i in [-1,0,1] for j in [-1,0,1]])) + sage: t.rauzy_fractal_plot(n=10000, # not tested (> 1 second) + ....: translate=S, exchange=true) #. Using the ``translate`` option to plot arbitrary tilings with the fractal pieces. This can be used for example to plot the self-replicating tiling of the Rauzy fractal:: sage: s = WordMorphism({1:[1,2], 2:[3], 3:[4,3], 4:[5], 5:[6], 6:[1]}) - sage: s.rauzy_fractal_plot() # not tested takes > 1 second - sage: D = {1:[(0,0,0,0,0,0), (0,1,0,0,0,0)], 3:[(0,0,0,0,0,0), (0,1,0,0,0,0)], 6:[(0,1,0,0,0,0)]} - sage: s.rauzy_fractal_plot(n=30000, translate=D) # not tested takes > 1 second + sage: s.rauzy_fractal_plot() # not tested (> 1 second) + sage: D = {1: [(0,0,0,0,0,0), (0,1,0,0,0,0)], + ....: 3: [(0,0,0,0,0,0), (0,1,0,0,0,0)], 6: [(0,1,0,0,0,0)]} + sage: s.rauzy_fractal_plot(n=30000, translate=D) # not tested (> 1 second) #. Plot the projection of the canonical basis with the fractal:: - sage: s = WordMorphism({1:[2,1], 2:[3], 3:[6,4], 4:[5,1], 5:[6], 6:[7], 7:[8], 8:[9], 9:[1]}) - sage: s.rauzy_fractal_plot(plot_basis=True) # not tested takes > 1 second + sage: s = WordMorphism({1:[2,1], 2:[3], 3:[6,4], 4:[5,1], + ....: 5:[6], 6:[7], 7:[8], 8:[9], 9:[1]}) + sage: s.rauzy_fractal_plot(plot_basis=True) # not tested (> 1 second) TESTS:: sage: s = WordMorphism('a->ab,b->c,c->d,d->e,e->a') - sage: s.rauzy_fractal_plot(n=1000, colormap='Set1', opacity={'a':0.5,'b':1,'c':0.7,'d':0,'e':0.2}, plot_origin=(100,"black"), plot_basis=True, point_size=2.5) + sage: s.rauzy_fractal_plot(n=1000, colormap='Set1', # optional - sage.modules sage.plot + ....: opacity={'a':0.5,'b':1,'c':0.7,'d':0,'e':0.2}, + ....: plot_origin=(100,"black"), plot_basis=True, + ....: point_size=2.5) Graphics object consisting of 10 graphics primitives REFERENCES: @@ -3003,7 +2972,7 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, # 1D plots if dim_fractal == 1: - from sage.all import plot + from sage.plot.plot import plot for a in col_dict: # We plot only the points with a color in col_dict and with positive opacity if (a in col_dict) and (opacity[a] > 0): @@ -3360,24 +3329,24 @@ def abelian_rotation_subspace(self): EXAMPLES:: - sage: WordMorphism('0->1,1->0').abelian_rotation_subspace() + sage: WordMorphism('0->1,1->0').abelian_rotation_subspace() # optional - sage.modules Vector space of degree 2 and dimension 2 over Rational Field Basis matrix: [1 0] [0 1] - sage: WordMorphism('0->01,1->10').abelian_rotation_subspace() + sage: WordMorphism('0->01,1->10').abelian_rotation_subspace() # optional - sage.modules Vector space of degree 2 and dimension 0 over Rational Field Basis matrix: [] - sage: WordMorphism('0->01,1->1').abelian_rotation_subspace() + sage: WordMorphism('0->01,1->1').abelian_rotation_subspace() # optional - sage.modules Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [0 1] - sage: WordMorphism('1->122,2->211').abelian_rotation_subspace() + sage: WordMorphism('1->122,2->211').abelian_rotation_subspace() # optional - sage.modules Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [ 1 -1] - sage: WordMorphism('0->1,1->102,2->3,3->4,4->2').abelian_rotation_subspace() + sage: WordMorphism('0->1,1->102,2->3,3->4,4->2').abelian_rotation_subspace() # optional - sage.modules Vector space of degree 5 and dimension 3 over Rational Field Basis matrix: [0 0 1 0 0] @@ -3386,7 +3355,7 @@ def abelian_rotation_subspace(self): The domain needs to be equal to the codomain:: - sage: WordMorphism('0->1,1->',codomain=Words('01')).abelian_rotation_subspace() + sage: WordMorphism('0->1,1->',codomain=Words('01')).abelian_rotation_subspace() # optional - sage.modules Vector space of degree 2 and dimension 0 over Rational Field Basis matrix: [] @@ -3718,7 +3687,7 @@ def simplify_alphabet_size(self, Z=None): r""" If this morphism is simplifiable, return morphisms `h` and `k` such that this morphism is simplifiable with respect to `h` and `k`, otherwise - raise ``ValueError``. + raise :class:`ValueError`. This method is quite fast if this morphism is non-injective, but very slow if it is injective. diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index 3d0ee41a4c4..326f7f7090c 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -45,7 +45,7 @@ [(0, 0), (1, 2), (-2, 6), (-1, 8), (-1, 5), (-1, 2), (-4, 6), (-3, 8)] sage: p.is_closed() False - sage: p.plot() + sage: p.plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives To obtain a list of all the available word path specific functions, @@ -104,14 +104,14 @@ Finite Dyck paths sage: d = D('()()()(())'); d Path: ()()()(()) - sage: d.plot() + sage: d.plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives :: sage: P = WordPaths('abcdef', steps='triangle_grid') sage: p = P('babaddefadabcadefaadfafabacdefa') - sage: p.plot() + sage: p.plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives Vector steps may be in more than 2 dimensions:: @@ -120,7 +120,7 @@ sage: P = WordPaths(alphabet='abc', steps=d); P Word Paths over 3 steps sage: p = P('abcabcabcabcaabacabcababcacbabacacabcaccbcac') - sage: p.plot() + sage: p.plot() # optional - sage.plot Graphics3d Object :: @@ -137,7 +137,7 @@ sage: CubePaths = WordPaths('abcABC', steps='cube_grid'); CubePaths Word Paths on the cube grid - sage: CubePaths('abcabaabcabAAAAA').plot() + sage: CubePaths('abcabaabcabAAAAA').plot() # optional - sage.plot Graphics3d Object The input data may be a str, a list, a tuple, @@ -332,7 +332,7 @@ def WordPaths(alphabet, steps=None): elif alphabet.cardinality() == 6: steps = 'hexagonal_grid' else: - raise TypeError("Unable to make a class WordPaths from %s"%alphabet) + raise TypeError("Unable to make a class WordPaths from %s" % alphabet) #Returns the class of WordPaths according to the given type of paths if isinstance(steps, str): @@ -384,7 +384,7 @@ def __init__(self, alphabet, steps): True If size of alphabet is twice the number of steps, then opposite - vectors are used for the second part of the alphabet. + vectors are used for the second part of the alphabet:: sage: WordPaths('abcd',[(2,1),(2,4)]) Word Paths over 4 steps @@ -455,10 +455,10 @@ def __eq__(self, other): sage: W1 == W3 False """ - return self is other or (type(self) == type(other) and \ - self.alphabet() == other.alphabet() and \ - self.vector_space() == other.vector_space() and \ - self.letters_to_steps() == other.letters_to_steps()) + return self is other or (type(self) is type(other) and + self.alphabet() == other.alphabet() and + self.vector_space() == other.vector_space() and + self.letters_to_steps() == other.letters_to_steps()) def __ne__(self, other): r""" @@ -1226,7 +1226,7 @@ def tikz_trajectory(self): '(0.000, 0.000) -- (1.00, 0.000) -- (1.50, 0.866) -- (1.00, 1.73) -- (0.000, 1.73) -- (-0.500, 0.866)' """ - from sage.all import n + from sage.misc.functional import N as n f = lambda x: n(x,digits=3) l = [str(tuple(map(f, pt))) for pt in self.points()] return ' -- '.join(l) @@ -1365,15 +1365,15 @@ def plot_projection(self, v=None, letters=None, color=None, ring=None, To remove the axis, do like this:: - sage: r = w.plot_projection(v) - sage: r.axes(False) - sage: r # long time (2s) + sage: r = w.plot_projection(v) # optional - sage.plot + sage: r.axes(False) # optional - sage.plot + sage: r # long time (2s) # optional - sage.plot Graphics object consisting of 200 graphics primitives You can assign different colors to each letter:: - sage: color = {'1':'purple', '2':(.2,.3,.4), '3': 'magenta'} - sage: w.plot_projection(v, color=color) # long time (2s) + sage: color = {'1': 'purple', '2': (.2,.3,.4), '3': 'magenta'} + sage: w.plot_projection(v, color=color) # long time (2s) # optional - sage.plot Graphics object consisting of 200 graphics primitives The 3d-Rauzy fractal:: @@ -1383,14 +1383,14 @@ def plot_projection(self, v=None, letters=None, color=None, ring=None, sage: v = s.pisot_eigenvector_right() sage: P = WordPaths('1234',[(1,0,0,0), (0,1,0,0), (0,0,1,0), (0,0,0,1)]) sage: w = P(D[:200]) - sage: w.plot_projection(v) + sage: w.plot_projection(v) # optional - sage.plot Graphics3d Object The dimension of vector space of the parent must be 3 or 4:: sage: P = WordPaths('ab', [(1, 0), (0, 1)]) sage: p = P('aabbabbab') - sage: p.plot_projection() + sage: p.plot_projection() # optional - sage.plot Traceback (most recent call last): ... TypeError: The dimension of the vector space (=2) must be 3 or 4 @@ -1444,7 +1444,7 @@ def projected_path(self, v=None, ring=None): sage: p = w.projected_path(v) sage: p Path: 1213121121312121312112131213121121312121... - sage: p[:20].plot() + sage: p[:20].plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives The ``ring`` argument allows to change the precision of the @@ -1530,42 +1530,42 @@ def plot(self, pathoptions=dict(rgbcolor='red',thickness=3), A non closed path on the square grid:: sage: P = WordPaths('abAB') - sage: P('abababAABAB').plot() + sage: P('abababAABAB').plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives A closed path on the square grid:: - sage: P('abababAABABB').plot() + sage: P('abababAABABB').plot() # optional - sage.plot Graphics object consisting of 4 graphics primitives A Dyck path:: sage: P = WordPaths('()', steps='dyck') - sage: P('()()()((()))').plot() + sage: P('()()()((()))').plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives A path in the triangle grid:: sage: P = WordPaths('abcdef', steps='triangle_grid') - sage: P('abcdedededefab').plot() + sage: P('abcdedededefab').plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives A polygon of length 220 that tiles the plane in two ways:: sage: P = WordPaths('abAB') - sage: P('aBababAbabaBaBABaBabaBaBABAbABABaBabaBaBABaBababAbabaBaBABaBabaBaBABAbABABaBABAbAbabAbABABaBABAbABABaBabaBaBABAbABABaBABAbAbabAbABAbAbabaBababAbABAbAbabAbABABaBABAbAbabAbABAbAbabaBababAbabaBaBABaBababAbabaBababAbABAbAbab').plot() + sage: P('aBababAbabaBaBABaBabaBaBABAbABABaBabaBaBABaBababAbabaBaBABaBabaBaBABAbABABaBABAbAbabAbABABaBABAbABABaBabaBaBABAbABABaBABAbAbabAbABAbAbabaBababAbABAbAbabAbABABaBABAbAbabAbABAbAbabaBababAbabaBaBABaBababAbabaBababAbABAbAbab').plot() # optional - sage.plot Graphics object consisting of 4 graphics primitives With gridlines:: - sage: P('ababababab').plot(gridlines=True) + sage: P('ababababab').plot(gridlines=True) # optional - sage.plot TESTS:: sage: P = WordPaths('abAB') - sage: P().plot() + sage: P().plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives - sage: sum(map(plot,map(P,['a','A','b','B']))) + sage: sum(map(plot,map(P,['a','A','b','B']))) # optional - sage.plot Graphics object consisting of 12 graphics primitives """ G = Graphics() @@ -1614,38 +1614,44 @@ def animate(self): sage: P = WordPaths('abAB') sage: p = P('aaababbb') - sage: a = p.animate(); a # optional -- ImageMagick + sage: a = p.animate(); print(a) # optional - sage.plot Animation with 9 frames - sage: show(a) # optional -- ImageMagick - sage: a.gif(delay=35, iterations=3) # optional -- ImageMagick + sage: show(a) # long time # optional -- ImageMagick sage.plot + sage: show(a, delay=35, iterations=3) # long time # optional -- ImageMagick sage.plot :: sage: P = WordPaths('abcdef',steps='triangle') sage: p = P('abcdef') - sage: p.animate() # optional -- ImageMagick + sage: a = p.animate(); print(a) # optional - sage.plot Animation with 8 frames + sage: show(a) # long time # optional -- ImageMagick sage.plot If the path is closed, the plain polygon is added at the end of the animation:: sage: P = WordPaths('abAB') sage: p = P('ababAbABABaB') - sage: a = p.animate(); a # optional -- ImageMagick + sage: a = p.animate(); print(a) # optional - sage.plot Animation with 14 frames + sage: show(a) # long time # optional -- ImageMagick sage.plot Another example illustrating a Fibonacci tile:: sage: w = words.fibonacci_tile(2) - sage: show(w.animate()) # optional -- ImageMagick + sage: a = w.animate(); print(a) # optional - sage.plot + Animation with 54 frames + sage: show(a) # long time # optional -- ImageMagick sage.plot The first 4 Fibonacci tiles in an animation:: - sage: a = words.fibonacci_tile(0).animate() - sage: b = words.fibonacci_tile(1).animate() - sage: c = words.fibonacci_tile(2).animate() - sage: d = words.fibonacci_tile(3).animate() - sage: (a*b*c*d).show() # optional -- ImageMagick # long time + sage: a = words.fibonacci_tile(0).animate() # optional - sage.plot + sage: b = words.fibonacci_tile(1).animate() # optional - sage.plot + sage: c = words.fibonacci_tile(2).animate() # optional - sage.plot + sage: d = words.fibonacci_tile(3).animate() # optional - sage.plot + sage: print(a*b*c*d) # optional - sage.plot + Animation with 296 frames + sage: show(a*b*c*d) # long time # optional -- ImageMagick sage.plot .. note:: @@ -1707,17 +1713,17 @@ def plot_directive_vector(self, options=dict(rgbcolor='blue')): Word Paths on the square grid sage: p = P('aaaccaccacacacaccccccbbdd'); p Path: aaaccaccacacacaccccccbbdd - sage: R = p.plot() + p.plot_directive_vector() - sage: R.axes(False) - sage: R.set_aspect_ratio(1) - sage: R.plot() + sage: R = p.plot() + p.plot_directive_vector() # optional - sage.plot + sage: R.axes(False) # optional - sage.plot + sage: R.set_aspect_ratio(1) # optional - sage.plot + sage: R.plot() # optional - sage.plot Graphics object consisting of 4 graphics primitives TESTS: A closed path:: - sage: P('acbd').plot_directive_vector() + sage: P('acbd').plot_directive_vector() # optional - sage.plot Graphics object consisting of 1 graphics primitive """ start = self.start_point() @@ -2014,12 +2020,12 @@ def plot(self, pathoptions=dict(rgbcolor='red',arrow_head=True,thickness=3), Word Paths over 2 steps sage: p = P('ababab'); p Path: ababab - sage: p.plot() + sage: p.plot() # optional - sage.plot Graphics3d Object sage: P = WordPaths('abcABC', steps='cube_grid') sage: p = P('abcabcAABBC') - sage: p.plot() + sage: p.plot() # optional - sage.plot Graphics3d Object """ diff --git a/src/sage/combinat/words/shuffle_product.py b/src/sage/combinat/words/shuffle_product.py index 101e7ca695c..7363d642126 100644 --- a/src/sage/combinat/words/shuffle_product.py +++ b/src/sage/combinat/words/shuffle_product.py @@ -22,7 +22,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from sage.combinat.words.word import Word_class, Word -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.integer_vector import IntegerVectors from sage.combinat.composition import Composition diff --git a/src/sage/combinat/words/suffix_trees.py b/src/sage/combinat/words/suffix_trees.py index a0e4727a1c0..c3646a36907 100644 --- a/src/sage/combinat/words/suffix_trees.py +++ b/src/sage/combinat/words/suffix_trees.py @@ -286,14 +286,13 @@ def transition_function(self, node, word): if word.is_empty(): return 0 if word.length() == 1: - return self._transition_function[(node,word)] - else: - return self.transition_function( \ - self._transition_function[(node,word[0:1])], word[1:]) + return self._transition_function[(node, word)] + return self.transition_function( + self._transition_function[(node, word[0:1])], word[1:]) def states(self): r""" - Returns the states of the automaton defined by the suffix trie. + Return the states of the automaton defined by the suffix trie. EXAMPLES:: @@ -438,9 +437,9 @@ def to_digraph(self): sage: from sage.combinat.words.suffix_trees import SuffixTrie sage: w = Words("cao")("cac") sage: t = SuffixTrie(w) - sage: d = t.to_digraph(); d + sage: d = t.to_digraph(); d # optional - sage.graphs Digraph on 6 vertices - sage: d.adjacency_matrix() + sage: d.adjacency_matrix() # optional - sage.graphs sage.modules [0 1 0 1 0 0] [0 0 1 0 0 0] [0 0 0 0 1 0] @@ -462,13 +461,13 @@ def plot(self, layout='tree', tree_root=0, tree_orientation='up', EXAMPLES:: sage: from sage.combinat.words.suffix_trees import SuffixTrie - sage: SuffixTrie(Word("cacao")).plot() + sage: SuffixTrie(Word("cacao")).plot() # optional - sage.plot Graphics object consisting of 38 graphics primitives TESTS:: sage: from sage.combinat.words.suffix_trees import SuffixTrie - sage: type(SuffixTrie(Word("cacao")).plot()) + sage: type(SuffixTrie(Word("cacao")).plot()) # optional - sage.plot <class 'sage.plot.graphics.Graphics'> """ tree = self.to_digraph() @@ -492,7 +491,7 @@ def show(self, *args, **kwds): sage: from sage.combinat.words.suffix_trees import SuffixTrie sage: w = Words("cao")("cac") sage: t = SuffixTrie(w) - sage: t.show() + sage: t.show() # optional - sage.plot """ self.plot(*args, **kwds).show() return @@ -830,7 +829,7 @@ def to_digraph(self, word_labels=False): sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree sage: W = Words([0,1,2]) sage: t = ImplicitSuffixTree(W([0,1,0,1,2])) - sage: t.to_digraph() + sage: t.to_digraph() # optional - sage.graphs Digraph on 8 vertices """ if not self._letters: @@ -866,17 +865,17 @@ def plot(self, word_labels=False, layout='tree', tree_root=0, EXAMPLES:: sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree - sage: ImplicitSuffixTree(Word('cacao')).plot(word_labels=True) + sage: ImplicitSuffixTree(Word('cacao')).plot(word_labels=True) # optional - sage.graphs sage.plot Graphics object consisting of 23 graphics primitives - sage: ImplicitSuffixTree(Word('cacao')).plot(word_labels=False) + sage: ImplicitSuffixTree(Word('cacao')).plot(word_labels=False) # optional - sage.graphs sage.plot Graphics object consisting of 23 graphics primitives TESTS:: sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree - sage: type(ImplicitSuffixTree(Word('cacao')).plot(word_labels=True)) + sage: type(ImplicitSuffixTree(Word('cacao')).plot(word_labels=True)) # optional - sage.graphs sage.plot <class 'sage.plot.graphics.Graphics'> - sage: type(ImplicitSuffixTree(Word('cacao')).plot(word_labels=False)) + sage: type(ImplicitSuffixTree(Word('cacao')).plot(word_labels=False)) # optional - sage.graphs sage.plot <class 'sage.plot.graphics.Graphics'> """ tree = self.to_digraph(word_labels=word_labels) @@ -905,8 +904,8 @@ def show(self, word_labels=None, *args, **kwds): sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree sage: w = Words("cao")("cacao") sage: t = ImplicitSuffixTree(w) - sage: t.show(word_labels=True) - sage: t.show(word_labels=False) + sage: t.show(word_labels=True) # optional - sage.plot + sage: t.show(word_labels=False) # optional - sage.plot """ self.plot(word_labels=word_labels, *args, **kwds).show() return @@ -1507,7 +1506,7 @@ def uncompactify(self): sage: abbab = Words("ab")("abbab") sage: s = SuffixTrie(abbab) sage: t = ImplicitSuffixTree(abbab) - sage: t.uncompactify().is_isomorphic(s.to_digraph()) + sage: t.uncompactify().is_isomorphic(s.to_digraph()) # optional - sage.graphs True """ tree = self.to_digraph(word_labels=True) diff --git a/src/sage/combinat/words/word.py b/src/sage/combinat/words/word.py index 051d0a1a702..4555c2df762 100644 --- a/src/sage/combinat/words/word.py +++ b/src/sage/combinat/words/word.py @@ -263,7 +263,7 @@ class FiniteWord_char(WordDatatype_char, FiniteWord_class): sage: len(w.factor_set()) 127 - sage: w.rauzy_graph(5) + sage: w.rauzy_graph(5) # optional - sage.graphs Looped digraph on 9 vertices sage: u = W([1,2,3]) diff --git a/src/sage/combinat/words/word_char.pyx b/src/sage/combinat/words/word_char.pyx index 494976a9f92..433aae3f4db 100644 --- a/src/sage/combinat/words/word_char.pyx +++ b/src/sage/combinat/words/word_char.pyx @@ -17,7 +17,7 @@ from sage.data_structures.bitset_base cimport * cimport cython from cpython.object cimport Py_EQ, Py_NE -from sage.rings.integer cimport Integer, smallInteger +from sage.rings.integer cimport smallInteger from sage.rings.rational cimport Rational from libc.string cimport memcpy, memcmp from sage.combinat.words.word_datatypes cimport WordDatatype @@ -32,6 +32,7 @@ import itertools # the maximum value of a size_t cdef size_t SIZE_T_MAX = -(<size_t> 1) + def reversed_word_iterator(WordDatatype_char w): r""" This function exists only because it is not possible to use yield in the @@ -48,6 +49,7 @@ def reversed_word_iterator(WordDatatype_char w): for i in range(w._length-1, -1, -1): yield w._data[i] + cdef class WordDatatype_char(WordDatatype): r""" A Fast class for words represented by an array ``unsigned char *``. @@ -361,7 +363,7 @@ cdef class WordDatatype_char(WordDatatype): """ cdef Py_ssize_t i, start, stop, step, slicelength cdef unsigned char * data - cdef size_t j,k + cdef size_t j, k if isinstance(key, slice): # here the key is a slice PySlice_GetIndicesEx(key, @@ -374,7 +376,7 @@ cdef class WordDatatype_char(WordDatatype): return self._new_c(self._data+start, stop-start, self) data = <unsigned char *>check_allocarray(slicelength, sizeof(unsigned char)) j = 0 - for k in range(start,stop,step): + for k in range(start, stop, step): data[j] = self._data[k] j += 1 return self._new_c(data, slicelength, None) @@ -392,7 +394,7 @@ cdef class WordDatatype_char(WordDatatype): def __iter__(self): r""" - Iterator over the letter of self + Iterator over the letters of ``self``. EXAMPLES:: @@ -406,7 +408,7 @@ cdef class WordDatatype_char(WordDatatype): def __reversed__(self): r""" - Reversed iterator over the letter of self + Reversed iterator over the letters of ``self``. EXAMPLES:: @@ -533,7 +535,6 @@ cdef class WordDatatype_char(WordDatatype): raise ValueError("a word cannot be taken modulo") if exp == float('inf'): - from sage.rings.infinity import Infinity def fcn(n): return self[n % self.length()] diff --git a/src/sage/combinat/words/word_datatypes.pxd b/src/sage/combinat/words/word_datatypes.pxd index d7e4d74cca0..c3329bd5a78 100644 --- a/src/sage/combinat/words/word_datatypes.pxd +++ b/src/sage/combinat/words/word_datatypes.pxd @@ -1,4 +1,3 @@ cdef class WordDatatype(): cdef public _parent cdef _hash - diff --git a/src/sage/combinat/words/word_datatypes.pyx b/src/sage/combinat/words/word_datatypes.pyx index b39c1b2e925..57c8079aad6 100644 --- a/src/sage/combinat/words/word_datatypes.pyx +++ b/src/sage/combinat/words/word_datatypes.pyx @@ -64,7 +64,7 @@ cdef class WordDatatype(): cdef int res if self._hash is None: res = 5381 - for s in islice(self,1024): + for s in islice(self, 1024): res = ((res << 5) + res) + hash(s) self._hash = res return self._hash @@ -94,10 +94,9 @@ cdef class WordDatatype_list(WordDatatype): sage: w = Word([0,1,1,0]) sage: isinstance(w, sage.combinat.words.word_datatypes.WordDatatype_list) True - """ self._parent = parent - if isinstance(data,list): + if isinstance(data, list): self._data = data else: self._data = list(data) @@ -697,7 +696,7 @@ cdef class WordDatatype_str(WordDatatype): sage: w.split("32") [word: , word: 30301030, word: , word: 12, word: 30, word: , word: 1] - If the separator is not a string a ValueError is raised:: + If the separator is not a string a :class:`ValueError` is raised:: sage: w = Word("le papa du papa du papa etait un petit pioupiou") sage: w.split(Word(['p','a','p','a'])) @@ -867,14 +866,12 @@ cdef class WordDatatype_str(WordDatatype): True sage: abba.is_prefix(ab) False - """ if isinstance(other, WordDatatype_str): return other._data.startswith(self._data) - if isinstance(other ,str): + if isinstance(other, str): return other.startswith(self._data) - else: - return super().is_prefix(other) + return super().is_prefix(other) def has_prefix(self, other): r""" @@ -940,10 +937,9 @@ cdef class WordDatatype_tuple(WordDatatype): sage: u = Word([0,1,1,0], datatype='tuple') sage: isinstance(u, sage.combinat.words.word_datatypes.WordDatatype_tuple) True - """ self._parent = parent - if isinstance(data,tuple): + if isinstance(data, tuple): self._data = data else: self._data = tuple(data) diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index b485205878f..06141373c85 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -66,7 +66,7 @@ from sage.combinat.words.finite_word import FiniteWord_class, Factorization from sage.combinat.words.words import FiniteWords, InfiniteWords from sage.combinat.words.morphism import WordMorphism -from sage.arith.all import gcd +from sage.arith.misc import gcd from sage.misc.decorators import rename_keyword @@ -139,7 +139,7 @@ class LowerChristoffelWord(FiniteWord_list): word: 01 """ - def __init__(self, p, q, alphabet=(0,1), algorithm='cf'): + def __init__(self, p, q, alphabet=(0, 1), algorithm='cf'): r""" INPUT: @@ -184,7 +184,7 @@ def __init__(self, p, q, alphabet=(0,1), algorithm='cf'): if len(set(alphabet)) != 2: raise ValueError("alphabet must contain exactly two distinct elements") # Compute gcd of p, q; raise TypeError if not 1. - if gcd(p,q) != 1: + if gcd(p, q) != 1: raise ValueError("%s and %s are not relatively prime" % (p, q)) # Compute the Christoffel word if algorithm == 'linear': @@ -194,7 +194,7 @@ def __init__(self, p, q, alphabet=(0,1), algorithm='cf'): w = [alphabet[0]] else: for i in range(p + q): - v = (u+p) % (p+q) + v = (u + p) % (p + q) new_letter = alphabet[0] if u < v else alphabet[1] w.append(new_letter) u = v @@ -208,7 +208,7 @@ def __init__(self, p, q, alphabet=(0,1), algorithm='cf'): cf = QQ((p, q)).continued_fraction_list() u = [alphabet[0]] v = [alphabet[1]] - #do not consider the first zero if p < q + # do not consider the first zero if p < q start = 1 if p < q else 0 for i in range(start, len(cf)-1): if i % 2 == 0: @@ -241,10 +241,10 @@ def markoff_number(self): sage: w0 = words.LowerChristoffelWord(4,7) sage: w1, w2 = w0.standard_factorization() - sage: (m0,m1,m2) = (w.markoff_number() for w in (w0,w1,w2)) - sage: (m0,m1,m2) + sage: (m0,m1,m2) = (w.markoff_number() for w in (w0,w1,w2)) # optional - sage.modules + sage: (m0,m1,m2) # optional - sage.modules (294685, 13, 7561) - sage: m0**2 + m1**2 + m2**2 == 3*m0*m1*m2 + sage: m0**2 + m1**2 + m2**2 == 3*m0*m1*m2 # optional - sage.modules True """ from sage.matrix.constructor import matrix @@ -540,9 +540,9 @@ def FibonacciWord(self, alphabet=(0, 1), construction_method="recursive"): :: - sage: words.FibonacciWord([0,1], 'function') + sage: words.FibonacciWord([0,1], 'function') # optional - sage.symbolic word: 0100101001001010010100100101001001010010... - sage: words.FibonacciWord('ab', 'function') + sage: words.FibonacciWord('ab', 'function') # optional - sage.symbolic word: abaababaabaababaababaabaababaabaababaaba... TESTS:: @@ -555,7 +555,7 @@ def FibonacciWord(self, alphabet=(0, 1), construction_method="recursive"): word: 0100101001001010010100100101001001010010... sage: f[:10000] == w[:10000] True - sage: f[:10000] == u[:10000] #long time + sage: f[:10000] == u[:10000] #long time True sage: words.FibonacciWord("abc") Traceback (most recent call last): @@ -640,7 +640,7 @@ def FixedPointOfMorphism(self, morphism, first_letter): sage: tm = words.FixedPointOfMorphism(mu,0); tm word: 0110100110010110100101100110100110010110... sage: TM = words.ThueMorseWord() - sage: tm[:1000] == TM[:1000] + sage: tm[:1000] == TM[:1000] # optional - sage.modules True :: @@ -650,7 +650,7 @@ def FixedPointOfMorphism(self, morphism, first_letter): word: 0100101001001010010100100101001001010010... sage: F = words.FibonacciWord(); F word: 0100101001001010010100100101001001010010... - sage: f[:1000] == F[:1000] + sage: f[:1000] == F[:1000] # optional - sage.modules True :: @@ -745,17 +745,17 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): INPUT: - - ``slope`` - the slope of the word. It can be one of the following: + - ``slope`` -- the slope of the word. It can be one of the following: - real number in `]0, 1[` - iterable over the continued fraction expansion of a real number in `]0, 1[` - - ``alphabet`` - any container of length two that is suitable to + - ``alphabet`` -- any container of length two that is suitable to build an instance of OrderedAlphabet (list, tuple, str, ...) - - ``bits`` - integer (optional and considered only if ``slope`` is + - ``bits`` -- integer (optional and considered only if ``slope`` is a real number) the number of bits to consider when computing the continued fraction. @@ -774,13 +774,13 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): From real slope:: - sage: words.CharacteristicSturmianWord(1/golden_ratio^2) + sage: words.CharacteristicSturmianWord(1/golden_ratio^2) # optional - sage.symbolic word: 0100101001001010010100100101001001010010... sage: words.CharacteristicSturmianWord(4/5) word: 11110 sage: words.CharacteristicSturmianWord(5/14) word: 01001001001001 - sage: words.CharacteristicSturmianWord(pi-3) + sage: words.CharacteristicSturmianWord(pi - 3) # optional - sage.symbolic word: 0000001000000100000010000001000000100000... From an iterator of the continued fraction expansion of a real:: @@ -803,7 +803,7 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): The characteristic sturmian word of slope `(\sqrt{3}-1)/2`:: - sage: words.CharacteristicSturmianWord((sqrt(3)-1)/2) + sage: words.CharacteristicSturmianWord((sqrt(3)-1)/2) # optional - sage.symbolic word: 0100100101001001001010010010010100100101... The same word defined from the continued fraction expansion of @@ -846,17 +846,17 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): :: - sage: words.CharacteristicSturmianWord(1/golden_ratio^2) + sage: words.CharacteristicSturmianWord(1/golden_ratio^2) # optional - sage.symbolic word: 0100101001001010010100100101001001010010... - sage: _.length() + sage: _.length() # optional - sage.symbolic +Infinity :: - sage: a = words.LowerMechanicalWord(1/pi)[1:] - sage: b = words.UpperMechanicalWord(1/pi)[1:] - sage: c = words.CharacteristicSturmianWord(1/pi) - sage: n = 500; a[:n] == b[:n] == c[:n] + sage: a = words.LowerMechanicalWord(1/pi)[1:] # optional - sage.symbolic + sage: b = words.UpperMechanicalWord(1/pi)[1:] # optional - sage.symbolic + sage: c = words.CharacteristicSturmianWord(1/pi) # optional - sage.symbolic + sage: n = 500; a[:n] == b[:n] == c[:n] # optional - sage.symbolic True :: @@ -927,19 +927,19 @@ def _CharacteristicSturmianWord_LetterIterator(self, cf, alphabet=(0,1)): EXAMPLES:: - sage: continued_fraction(1/golden_ratio^2)[:8] + sage: continued_fraction(1/golden_ratio^2)[:8] # optional - sage.symbolic [0; 2, 1, 1, 1, 1, 2] - sage: cf = iter(_) - sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf)) + sage: cf = iter(_) # optional - sage.symbolic + sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf)) # optional - sage.symbolic word: 0100101001001010010100100101001010 :: - sage: alpha = (sqrt(3)-1)/2 - sage: continued_fraction(alpha)[:10] + sage: alpha = (sqrt(3)-1)/2 # optional - sage.symbolic + sage: continued_fraction(alpha)[:10] # optional - sage.symbolic [0; 2, 1, 2, 1, 2, 1, 2, 1, 2] - sage: cf = iter(_) - sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf)) + sage: cf = iter(_) # optional - sage.symbolic + sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf)) # optional - sage.symbolic word: 0100100101001001001010010010010100100101... """ try: @@ -1048,7 +1048,7 @@ def KolakoskiWord(self, alphabet=(1,2)): if a not in ZZ or a <= 0 or b not in ZZ or b <= 0 or a == b: msg = 'the alphabet (=%s) must consist of two distinct positive integers' % (alphabet,) raise ValueError(msg) - return InfiniteWords(alphabet)(self._KolakoskiWord_iterator(a, b), datatype = 'iter') + return InfiniteWords(alphabet)(self._KolakoskiWord_iterator(a, b), datatype='iter') def _KolakoskiWord_iterator(self, a=1, b=2): r""" @@ -1133,23 +1133,23 @@ def LowerMechanicalWord(self, alpha, rho=0, alphabet=None): EXAMPLES:: - sage: words.LowerMechanicalWord(1/golden_ratio^2) + sage: words.LowerMechanicalWord(1/golden_ratio^2) # optional - sage.symbolic word: 0010010100100101001010010010100100101001... - sage: words.LowerMechanicalWord(1/5) + sage: words.LowerMechanicalWord(1/5) # optional - sage.symbolic word: 0000100001000010000100001000010000100001... - sage: words.LowerMechanicalWord(1/pi) + sage: words.LowerMechanicalWord(1/pi) # optional - sage.symbolic word: 0001001001001001001001000100100100100100... TESTS:: - sage: m = words.LowerMechanicalWord(1/golden_ratio^2)[1:] - sage: s = words.CharacteristicSturmianWord(1/golden_ratio^2) - sage: m[:500] == s[:500] + sage: m = words.LowerMechanicalWord(1/golden_ratio^2)[1:] # optional - sage.symbolic + sage: s = words.CharacteristicSturmianWord(1/golden_ratio^2) # optional - sage.symbolic + sage: m[:500] == s[:500] # optional - sage.symbolic True Check that this returns a word in an alphabet (:trac:`10054`):: - sage: words.UpperMechanicalWord(1/golden_ratio^2).parent() + sage: words.UpperMechanicalWord(1/golden_ratio^2).parent() # optional - sage.symbolic Infinite words over {0, 1} """ if not 0 <= alpha <= 1: @@ -1193,23 +1193,23 @@ def UpperMechanicalWord(self, alpha, rho=0, alphabet=None): EXAMPLES:: - sage: words.UpperMechanicalWord(1/golden_ratio^2) + sage: words.UpperMechanicalWord(1/golden_ratio^2) # optional - sage.symbolic word: 1010010100100101001010010010100100101001... - sage: words.UpperMechanicalWord(1/5) + sage: words.UpperMechanicalWord(1/5) # optional - sage.symbolic word: 1000010000100001000010000100001000010000... - sage: words.UpperMechanicalWord(1/pi) + sage: words.UpperMechanicalWord(1/pi) # optional - sage.symbolic word: 1001001001001001001001000100100100100100... TESTS:: - sage: m = words.UpperMechanicalWord(1/golden_ratio^2)[1:] - sage: s = words.CharacteristicSturmianWord(1/golden_ratio^2) - sage: m[:500] == s[:500] + sage: m = words.UpperMechanicalWord(1/golden_ratio^2)[1:] # optional - sage.symbolic + sage: s = words.CharacteristicSturmianWord(1/golden_ratio^2) # optional - sage.symbolic + sage: m[:500] == s[:500] # optional - sage.symbolic True Check that this returns a word in an alphabet (:trac:`10054`):: - sage: words.UpperMechanicalWord(1/golden_ratio^2).parent() + sage: words.UpperMechanicalWord(1/golden_ratio^2).parent() # optional - sage.symbolic Infinite words over {0, 1} """ if not 0 <= alpha <= 1: @@ -1276,9 +1276,9 @@ def StandardEpisturmianWord(self, directive_word): """ if not isinstance(directive_word, Word_class): raise TypeError("directive_word is not a word, so it cannot be used to build an episturmian word") - epistandard = directive_word.parent()(\ - self._StandardEpisturmianWord_LetterIterator(directive_word), - datatype='iter') + epistandard = directive_word.parent()( + self._StandardEpisturmianWord_LetterIterator(directive_word), + datatype='iter') return epistandard def _StandardEpisturmianWord_LetterIterator(self, directive_word): @@ -1496,16 +1496,16 @@ def _fibonacci_tile(self, n, q_0=None, q_1=3): [BmBGL09]_ """ - from sage.combinat.words.all import WordMorphism + from sage.combinat.words.morphism import WordMorphism W = FiniteWords([0,1,2,3]) bar = WordMorphism({0:0,1:3,3:1,2:2},codomain=W) - if n==0: + if n == 0: a = [] if q_0 is None else [q_0] return W(a) - elif n==1: + elif n == 1: b = [] if q_1 is None else [q_1] return W(b) - elif n%3 == 2: + elif n % 3 == 2: u = self._fibonacci_tile(n-1,q_0,q_1) v = self._fibonacci_tile(n-2,q_0,q_1) return u * v @@ -1520,7 +1520,7 @@ def fibonacci_tile(self, n): EXAMPLES:: - sage: for i in range(3): words.fibonacci_tile(i) + sage: for i in range(3): words.fibonacci_tile(i) # optional - sage.modules Path: 3210 Path: 323030101212 Path: 3230301030323212323032321210121232121010... @@ -1538,7 +1538,7 @@ def dual_fibonacci_tile(self, n): EXAMPLES:: - sage: for i in range(4): words.dual_fibonacci_tile(i) + sage: for i in range(4): words.dual_fibonacci_tile(i) # optional - sage.modules Path: 3210 Path: 32123032301030121012 Path: 3212303230103230321232101232123032123210... @@ -1649,7 +1649,7 @@ def _s_adic_iterator(self, sequence, letters): yield precedent_letter for (i,(m,a)) in enumerate(zip(sequence, letters)): if not precedent_letter == m(a)[0]: - raise ValueError("the hypothesis of the algorithm used is not satisfied; the image of the %s-th letter (=%s) under the %s-th morphism (=%s) should start with the %s-th letter (=%s)"%(i+1,a,i+1,m,i,precedent_letter)) + raise ValueError("the hypothesis of the algorithm used is not satisfied; the image of the %s-th letter (=%s) under the %s-th morphism (=%s) should start with the %s-th letter (=%s)" % (i+1,a,i+1,m,i,precedent_letter)) w = p(m(a)[1:]) for b in w: yield b diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index c0a4457df85..900ab9c8508 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -705,9 +705,9 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr Construction of a word path from a finite word:: sage: W = FiniteWords('abcd') - sage: P = WordPaths('abcd') + sage: P = WordPaths('abcd') # optional - sage.modules sage: w = W('aaab') - sage: P(w) + sage: P(w) # optional - sage.modules Path: aaab Construction of a word path from a Christoffel word:: @@ -715,8 +715,8 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr sage: w = words.ChristoffelWord(5,8) sage: w word: 0010010100101 - sage: P = WordPaths([0,1,2,3]) - sage: P(w) + sage: P = WordPaths([0,1,2,3]) # optional - sage.modules + sage: P(w) # optional - sage.modules Path: 0010010100101 Construction of a word represented by a list from a word @@ -744,19 +744,19 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr sage: w = words.FibonacciWord() sage: f = w[:100] - sage: P = WordPaths([0,1,2,3]) - sage: p = P(f); p + sage: P = WordPaths([0,1,2,3]) # optional - sage.modules + sage: p = P(f); p # optional - sage.modules Path: 0100101001001010010100100101001001010010... - sage: p.length() + sage: p.length() # optional - sage.modules 100 Creation of a word path from a FiniteWord_callable:: sage: g = W(lambda n:n%2, length = 100) - sage: P = WordPaths([0,1,2,3]) - sage: p = P(g); p + sage: P = WordPaths([0,1,2,3]) # optional - sage.modules + sage: p = P(g); p # optional - sage.modules Path: 0101010101010101010101010101010101010101... - sage: p.length() + sage: p.length() # optional - sage.modules 100 Creation of a word from a pickled function:: @@ -1018,7 +1018,7 @@ def random_element(self, length=None, *args, **kwds): TESTS:: - sage: _ = FiniteWords(GF(5)).random_element() + sage: _ = FiniteWords(GF(5)).random_element() # optional - sage.rings.finite_rings """ if length is None: length = ZZ.random_element(0, 10) @@ -1635,11 +1635,12 @@ def __setstate__(self, state): r""" TESTS:: - sage: import os + sage: import os, tempfile sage: W = Words('ab') - sage: filename = os.path.join(tmp_dir(), 'test.sobj') - sage: W.save(filename) - sage: load(filename) + sage: with tempfile.TemporaryDirectory() as d: + ....: filename = os.path.join(d, 'test.sobj') + ....: W.save(filename) + ....: load(filename) Finite and infinite words over {'a', 'b'} """ # add a default to support old pickles from #19619 @@ -1928,9 +1929,9 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr Construction of a word path from a finite word:: sage: W = Words('abcd') - sage: P = WordPaths('abcd') + sage: P = WordPaths('abcd') # optional - sage.modules sage: w = W('aaab') - sage: P(w) + sage: P(w) # optional - sage.modules Path: aaab Construction of a word path from a Christoffel word:: @@ -1938,8 +1939,8 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr sage: w = words.ChristoffelWord(5,8) sage: w word: 0010010100101 - sage: P = WordPaths([0,1,2,3]) - sage: P(w) + sage: P = WordPaths([0,1,2,3]) # optional - sage.modules + sage: P(w) # optional - sage.modules Path: 0010010100101 Construction of a word represented by a list from a word @@ -1967,19 +1968,19 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr sage: w = words.FibonacciWord() sage: f = w[:100] - sage: P = WordPaths([0,1,2,3]) - sage: p = P(f); p + sage: P = WordPaths([0,1,2,3]) # optional - sage.modules + sage: p = P(f); p # optional - sage.modules Path: 0100101001001010010100100101001001010010... - sage: p.length() + sage: p.length() # optional - sage.modules 100 Creation of a word path from a FiniteWord_callable:: - sage: g = Word(lambda n:n%2, length = 100) - sage: P = WordPaths([0,1,2,3]) - sage: p = P(g); p + sage: g = Word(lambda n: n%2, length=100) + sage: P = WordPaths([0,1,2,3]) # optional - sage.modules + sage: p = P(g); p # optional - sage.modules Path: 0101010101010101010101010101010101010101... - sage: p.length() + sage: p.length() # optional - sage.modules 100 Creation of a word from a pickled function:: @@ -2100,11 +2101,12 @@ def __setstate__(self, state): r""" TESTS:: - sage: import os + sage: import os, tempfile sage: W = Words('ab', 10) - sage: filename = os.path.join(tmp_dir(), 'test.sobj') - sage: W.save(filename) - sage: load(filename) + sage: with tempfile.TemporaryDirectory() as d: + ....: filename = os.path.join(d, 'test.sobj') + ....: W.save(filename) + ....: load(filename) Words of length 10 over {'a', 'b'} """ # add a default to support old pickles from #19619 @@ -2215,7 +2217,7 @@ def random_element(self, *args, **kwds): TESTS:: - sage: _ = Words(GF(5),4).random_element() + sage: _ = Words(GF(5),4).random_element() # optional - sage.rings.finite_rings Check that :trac:`18283` is fixed:: diff --git a/src/sage/combinat/yang_baxter_graph.py b/src/sage/combinat/yang_baxter_graph.py index 426095f6332..306e8063f63 100644 --- a/src/sage/combinat/yang_baxter_graph.py +++ b/src/sage/combinat/yang_baxter_graph.py @@ -68,7 +68,7 @@ def YangBaxterGraph(partition=None, root=None, operators=None): The ``partition`` keyword is a shorthand for the above construction:: - sage: Y = YangBaxterGraph(partition=[3,1]); Y + sage: Y = YangBaxterGraph(partition=[3,1]); Y # optional - sage.combinat Yang-Baxter graph of [3, 1], with top vertex (0, 2, 1, 0) sage: Y.vertices(sort=True) [(0, 2, 1, 0), (2, 0, 1, 0), (2, 1, 0, 0)] @@ -79,25 +79,25 @@ def YangBaxterGraph(partition=None, root=None, operators=None): sage: swappers = [SwapIncreasingOperator(i) for i in range(3)] sage: Y = YangBaxterGraph(root=(1,2,3,4), operators=swappers); Y Yang-Baxter graph with root vertex (1, 2, 3, 4) - sage: Y.plot() + sage: Y.plot() # optional - sage.plot Graphics object consisting of 97 graphics primitives The Cayley graph of a finite group can be realized as a Yang-Baxter graph:: sage: def left_multiplication_by(g): - ....: return lambda h : h*g - sage: G = CyclicPermutationGroup(4) - sage: operators = [ left_multiplication_by(gen) for gen in G.gens() ] - sage: Y = YangBaxterGraph(root=G.identity(), operators=operators); Y + ....: return lambda h: h*g + sage: G = CyclicPermutationGroup(4) # optional - sage.groups + sage: operators = [ left_multiplication_by(gen) for gen in G.gens() ] # optional - sage.groups + sage: Y = YangBaxterGraph(root=G.identity(), operators=operators); Y # optional - sage.groups Yang-Baxter graph with root vertex () - sage: Y.plot(edge_labels=False) + sage: Y.plot(edge_labels=False) # optional - sage.groups sage.plot Graphics object consisting of 9 graphics primitives - sage: G = SymmetricGroup(4) - sage: operators = [left_multiplication_by(gen) for gen in G.gens()] - sage: Y = YangBaxterGraph(root=G.identity(), operators=operators); Y + sage: G = SymmetricGroup(4) # optional - sage.groups + sage: operators = [left_multiplication_by(gen) for gen in G.gens()] # optional - sage.groups + sage: Y = YangBaxterGraph(root=G.identity(), operators=operators); Y # optional - sage.groups Yang-Baxter graph with root vertex () - sage: Y.plot(edge_labels=False) + sage: Y.plot(edge_labels=False) # optional - sage.groups sage.plot Graphics object consisting of 96 graphics primitives AUTHORS: @@ -361,7 +361,7 @@ def root(self): sage: Y = YangBaxterGraph(root=(1,0,3,2,1,0), operators=ops) sage: Y.root() (1, 0, 3, 2, 1, 0) - sage: Y = YangBaxterGraph(partition=[3,2]) + sage: Y = YangBaxterGraph(partition=[3,2]) # optional - sage.combinat sage: Y.root() (1, 0, 2, 1, 0) """ @@ -392,9 +392,9 @@ def plot(self, *args, **kwds): sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator sage: ops = [SwapIncreasingOperator(i) for i in range(4)] sage: Y = YangBaxterGraph(root=(1,0,2,1,0), operators=ops) - sage: Y.plot() + sage: Y.plot() # optional - sage.plot Graphics object consisting of 16 graphics primitives - sage: Y.plot(edge_labels=False) + sage: Y.plot(edge_labels=False) # optional - sage.plot Graphics object consisting of 11 graphics primitives """ if "edge_labels" not in kwds: @@ -546,7 +546,7 @@ def relabel_edges(self, edge_dict, inplace=True): from copy import copy Y = copy(self) digraph = Y._digraph - for u, v, i in digraph.edges(sort=True): + for u, v in digraph.edges(sort=False, labels=False): digraph.set_edge_label(u, v, edge_dict[u, v]) if not inplace: return Y @@ -572,9 +572,9 @@ def __init__(self, partition): EXAMPLES:: - sage: Y = YangBaxterGraph(partition=[3,2,1]); Y + sage: Y = YangBaxterGraph(partition=[3,2,1]); Y # optional - sage.combinat Yang-Baxter graph of [3, 2, 1], with top vertex (0, 1, 0, 2, 1, 0) - sage: loads(dumps(Y)) == Y + sage: loads(dumps(Y)) == Y # optional - sage.combinat True AUTHORS: @@ -592,8 +592,8 @@ def __repr__(self): r""" EXAMPLES:: - sage: Y = YangBaxterGraph(partition=[3,2]) - sage: Y.__repr__() + sage: Y = YangBaxterGraph(partition=[3,2]) # optional - sage.combinat + sage: Y.__repr__() # optional - sage.combinat 'Yang-Baxter graph of [3, 2], with top vertex (1, 0, 2, 1, 0)' """ return "Yang-Baxter graph of %s, with top vertex %s" % (self._partition, self._root) @@ -604,13 +604,13 @@ def __copy__(self): EXAMPLES:: - sage: Y = YangBaxterGraph(partition=[3,2]); Y + sage: Y = YangBaxterGraph(partition=[3,2]); Y # optional - sage.combinat Yang-Baxter graph of [3, 2], with top vertex (1, 0, 2, 1, 0) - sage: B = copy(Y); B + sage: B = copy(Y); B # optional - sage.combinat Yang-Baxter graph of [3, 2], with top vertex (1, 0, 2, 1, 0) - sage: Y is B + sage: Y is B # optional - sage.combinat False - sage: Y == B + sage: Y == B # optional - sage.combinat True """ from copy import copy @@ -626,10 +626,10 @@ def _digraph(self): EXAMPLES:: - sage: Y = YangBaxterGraph(partition=[2,1]) - sage: Y._digraph + sage: Y = YangBaxterGraph(partition=[2,1]) # optional - sage.combinat + sage: Y._digraph # optional - sage.combinat Digraph on 2 vertices - sage: Y.edges() + sage: Y.edges() # optional - sage.combinat [((0, 1, 0), (1, 0, 0), Swap positions 0 and 1)] """ digraph = super()._digraph @@ -645,8 +645,8 @@ def _vertex_ordering(self): EXAMPLES:: - sage: Y = YangBaxterGraph(partition=[3,2]) - sage: Y._vertex_ordering + sage: Y = YangBaxterGraph(partition=[3,2]) # optional - sage.combinat + sage: Y._vertex_ordering # optional - sage.combinat [(1, 0, 2, 1, 0), (1, 2, 0, 1, 0), (1, 2, 1, 0, 0), (2, 1, 0, 1, 0), (2, 1, 1, 0, 0)] """ return self._digraph.vertices(sort=True) @@ -661,12 +661,11 @@ def __iter__(self): EXAMPLES:: - sage: Y = YangBaxterGraph(partition=[3,2]) - sage: list(Y.__iter__()) + sage: Y = YangBaxterGraph(partition=[3,2]) # optional - sage.combinat + sage: list(Y.__iter__()) # optional - sage.combinat [(1, 0, 2, 1, 0), (1, 2, 0, 1, 0), (1, 2, 1, 0, 0), (2, 1, 0, 1, 0), (2, 1, 1, 0, 0)] """ - for v in self._vertex_ordering: - yield v + yield from self._vertex_ordering def _swap_operator(self, operator, u): r""" @@ -680,14 +679,14 @@ def _swap_operator(self, operator, u): EXAMPLES:: - sage: Y = YangBaxterGraph(partition=[3,1]) - sage: from sage.combinat.yang_baxter_graph import SwapOperator - sage: ops = [SwapOperator(i) for i in range(3)] - sage: [Y._swap_operator(op, (1,2,3,4)) for op in ops] + sage: Y = YangBaxterGraph(partition=[3,1]) # optional - sage.combinat + sage: from sage.combinat.yang_baxter_graph import SwapOperator # optional - sage.combinat + sage: ops = [SwapOperator(i) for i in range(3)] # optional - sage.combinat + sage: [Y._swap_operator(op, (1,2,3,4)) for op in ops] # optional - sage.combinat [(2, 1, 3, 4), (1, 3, 2, 4), (1, 2, 4, 3)] - sage: [Y._swap_operator(op, [4,3,2,1]) for op in ops] + sage: [Y._swap_operator(op, [4,3,2,1]) for op in ops] # optional - sage.combinat [[3, 4, 2, 1], [4, 2, 3, 1], [4, 3, 1, 2]] - sage: [Y._swap_operator(op, Permutation([1,2,3,4])) for op in ops] + sage: [Y._swap_operator(op, Permutation([1,2,3,4])) for op in ops] # optional - sage.combinat [[2, 1, 3, 4], [1, 3, 2, 4], [1, 2, 4, 3]] """ return operator(u) @@ -710,12 +709,12 @@ def vertex_relabelling_dict(self, v): EXAMPLES:: - sage: Y = YangBaxterGraph(partition=[3,1]) - sage: Y.vertex_relabelling_dict((1,2,3,4)) + sage: Y = YangBaxterGraph(partition=[3,1]) # optional - sage.combinat + sage: Y.vertex_relabelling_dict((1,2,3,4)) # optional - sage.combinat {(0, 2, 1, 0): (1, 2, 3, 4), (2, 0, 1, 0): (2, 1, 3, 4), (2, 1, 0, 0): (2, 3, 1, 4)} - sage: Y.vertex_relabelling_dict((4,3,2,1)) + sage: Y.vertex_relabelling_dict((4,3,2,1)) # optional - sage.combinat {(0, 2, 1, 0): (4, 3, 2, 1), (2, 0, 1, 0): (3, 4, 2, 1), (2, 1, 0, 0): (3, 2, 4, 1)} @@ -737,14 +736,14 @@ def relabel_vertices(self, v, inplace=True): EXAMPLES:: - sage: Y = YangBaxterGraph(partition=[3,1]); Y + sage: Y = YangBaxterGraph(partition=[3,1]); Y # optional - sage.combinat Yang-Baxter graph of [3, 1], with top vertex (0, 2, 1, 0) - sage: d = Y.relabel_vertices((1,2,3,4), inplace=False); d + sage: d = Y.relabel_vertices((1,2,3,4), inplace=False); d # optional - sage.combinat Digraph on 3 vertices - sage: Y.vertices(sort=True) + sage: Y.vertices(sort=True) # optional - sage.combinat [(0, 2, 1, 0), (2, 0, 1, 0), (2, 1, 0, 0)] - sage: e = Y.relabel_vertices((1,2,3,4)); e - sage: Y.vertices(sort=True) + sage: e = Y.relabel_vertices((1,2,3,4)); e # optional - sage.combinat + sage: Y.vertices(sort=True) # optional - sage.combinat [(1, 2, 3, 4), (2, 1, 3, 4), (2, 3, 1, 4)] """ relabelling = self.vertex_relabelling_dict(v) @@ -911,7 +910,7 @@ def __call__(self, u): EXAMPLES:: - sage: Y = YangBaxterGraph(partition=[2,2]) + sage: Y = YangBaxterGraph(partition=[2,2]) # optional - sage.combinat sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator sage: operators = [SwapIncreasingOperator(i) for i in range(3)] sage: [op((1,2,3,4)) for op in operators] diff --git a/src/sage/cpython/__init__.py b/src/sage/cpython/__init__.py index 51974f1e438..5deff221609 100644 --- a/src/sage/cpython/__init__.py +++ b/src/sage/cpython/__init__.py @@ -40,7 +40,7 @@ def connect(*args, **kwargs): if fix_for_ticket_30157(): raise RuntimeError( 'patch for Github issue #30157 failed; please report this ' - 'bug to https://trac.sagemath.org') + 'bug to https://github.com/sagemath/sage/issues') # Undo the monkey-patch try: diff --git a/src/sage/cpython/_py2_random.py b/src/sage/cpython/_py2_random.py index 795820c6cc7..1cd9532fee4 100644 --- a/src/sage/cpython/_py2_random.py +++ b/src/sage/cpython/_py2_random.py @@ -281,9 +281,9 @@ def sample(self, population, k): population contains repeats, then each occurrence is a possible selection in the sample. - To choose a sample in a range of integers, use xrange as an argument. + To choose a sample in a range of integers, use range as an argument. This is especially fast and space efficient for sampling from a - large population: sample(xrange(10000000), 60) + large population: sample(range(10000000), 60) """ # Sampling without replacement entails tracking either potential diff --git a/src/sage/cpython/atexit.pyx b/src/sage/cpython/atexit.pyx index baa3d7a2c0e..961aa348d0a 100644 --- a/src/sage/cpython/atexit.pyx +++ b/src/sage/cpython/atexit.pyx @@ -2,15 +2,15 @@ """Utilities for interfacing with the standard library's atexit module.""" -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Erik M. Bray <erik.bray@lri.fr> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import atexit @@ -51,7 +51,8 @@ cdef class restore_atexit: sage: import atexit sage: from sage.cpython.atexit import restore_atexit sage: def handler(*args, **kwargs): - ....: import sys # see https://github.com/sagemath/sage/issues/25270#comment:56 + ....: import sys + ....: # see https://github.com/sagemath/sage/issues/25270#comment:56 ....: sys.stdout.write(str((args, kwargs))) ....: sys.stdout.write('\n') sage: atexit.register(handler, 1, 2, c=3) @@ -188,6 +189,7 @@ cdef extern from *: PyObject* kwargs atexit_callback** _atexit_callbacks(object module) + def _get_exithandlers(): """Return list of exit handlers registered with the atexit module.""" cdef atexit_callback ** callbacks @@ -206,10 +208,11 @@ def _get_exithandlers(): else: kwargs = {} exithandlers.append((<object>callback.func, - <object>callback.args, - kwargs)) + <object>callback.args, + kwargs)) return exithandlers + def _set_exithandlers(exithandlers): """ Replace the list of exit handlers registered with the atexit module diff --git a/src/sage/cpython/cython_metaclass.h b/src/sage/cpython/cython_metaclass.h index da06ab75a6b..ecf7f973c3e 100644 --- a/src/sage/cpython/cython_metaclass.h +++ b/src/sage/cpython/cython_metaclass.h @@ -52,6 +52,16 @@ static CYTHON_INLINE int Sage_PyType_Ready(PyTypeObject* t) if (r < 0) return r; +#if PY_VERSION_HEX >= 0x03050000 + // Cython 3 sets Py_TPFLAGS_HEAPTYPE before calling PyType_Ready, + // and resets just after the call. We need to reset it earlier, + // since otherwise the call to metaclass.__init__ below may have + // illegal memory accesses. + // See also: + // https://github.com/cython/cython/issues/3603 + t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE; +#endif + /* Set or get metaclass (the type of t) */ PyTypeObject* metaclass; diff --git a/src/sage/cpython/cython_metaclass.pyx b/src/sage/cpython/cython_metaclass.pyx index a846884093e..a8fa92fc1a8 100644 --- a/src/sage/cpython/cython_metaclass.pyx +++ b/src/sage/cpython/cython_metaclass.pyx @@ -19,13 +19,16 @@ file if you are using one). In the extension type (a.k.a. ``cdef class``) for which you want to define a metaclass, define a method ``__getmetaclass__`` with a single -unused argument. This method should return a type to be used as +unused argument, and turn off the Cython directive +``always_allow_keywords``. This method should return a type to be used as metaclass: .. code-block:: cython + cimport cython cimport sage.cpython.cython_metaclass cdef class MyCustomType(): + @cython.always_allow_keywords(False) def __getmetaclass__(_): from foo import MyMetaclass return MyMetaclass @@ -61,9 +64,12 @@ In Python, this would be ``meta.__init__(cls, name, bases, dict)``. EXAMPLES:: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' + ....: cimport cython ....: cimport sage.cpython.cython_metaclass ....: cdef class MyCustomType(): + ....: @cython.always_allow_keywords(False) ....: def __getmetaclass__(_): ....: class MyMetaclass(type): ....: def __init__(*args): @@ -75,9 +81,9 @@ EXAMPLES:: ....: ''') Calling MyMetaclass.__init__(<class '...MyCustomType'>, None, None, None) Calling MyMetaclass.__init__(<class '...MyDerivedType'>, None, None, None) - sage: MyCustomType.__class__ + sage: MyCustomType.__class__ # needs sage.misc.cython <class '...MyMetaclass'> - sage: class MyPythonType(MyDerivedType): + sage: class MyPythonType(MyDerivedType): # needs sage.misc.cython ....: pass Calling MyMetaclass.__init__(<class '...MyPythonType'>, 'MyPythonType', (<class '...MyDerivedType'>,), {...}) @@ -98,9 +104,12 @@ TESTS: Check that a proper exception is raised if ``__getmetaclass__`` returns a non-type:: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' + ....: cimport cython ....: cimport sage.cpython.cython_metaclass ....: cdef class MyCustomType(): + ....: @cython.always_allow_keywords(False) ....: def __getmetaclass__(_): ....: return 2 ....: ''') diff --git a/src/sage/cpython/debug.pyx b/src/sage/cpython/debug.pyx index e00f31ac94e..986abff2a99 100644 --- a/src/sage/cpython/debug.pyx +++ b/src/sage/cpython/debug.pyx @@ -1,19 +1,18 @@ """ Various functions to debug Python internals """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Jeroen Demeyer <jdemeyer@cage.ugent.be> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cpython.object cimport (PyObject, PyTypeObject, Py_TYPE, - descrgetfunc, descrsetfunc) + descrgetfunc, descrsetfunc) cdef extern from "Python.h": # Helper to get a pointer to an object's __dict__ slot, if any @@ -58,6 +57,7 @@ def shortrepr(obj, max=50): cdef object _no_default = object() # Unique object + def getattr_debug(obj, name, default=_no_default): r""" A re-implementation of ``getattr()`` with lots of debugging info. @@ -101,7 +101,7 @@ def getattr_debug(obj, name, default=_no_default): found '__doc__' in dict of <class 'list'> got ... 'str'>) returning ... 'str'>) - sage: _ = getattr_debug(gp(1), "log") + sage: _ = getattr_debug(gp(1), "log") # needs sage.libs.pari getattr_debug(obj=1, name='log'): type(obj) = <class 'sage.interfaces.gp.GpElement'> object has __dict__ slot (<class 'dict'>) @@ -153,9 +153,9 @@ def getattr_debug(obj, name, default=_no_default): dct = <object>(dictptr[0]) print(f" object has __dict__ slot ({type(dct)})") else: - print(f" object has uninitialized __dict__ slot") + print(" object has uninitialized __dict__ slot") else: - print(f" object does not have __dict__ slot") + print(" object does not have __dict__ slot") cdef descrgetfunc get = NULL cdef descrsetfunc set = NULL @@ -172,15 +172,15 @@ def getattr_debug(obj, name, default=_no_default): set = Py_TYPE(attr).tp_descr_set if get is not NULL: if set is not NULL: - print(f" attribute is data descriptor (has __get__ and __set__)") + print(" attribute is data descriptor (has __get__ and __set__)") if dct is not None: - print(f" ignoring __dict__ because we have a data descriptor") - print(f" calling __get__()") + print(" ignoring __dict__ because we have a data descriptor") + print(" calling __get__()") attr = get(attr, obj, type(obj)) print(f" returning {shortrepr(attr)} ({type(attr)})") return attr else: - print(f" attribute is ordinary descriptor (has __get__)") + print(" attribute is ordinary descriptor (has __get__)") attr_in_class = True break @@ -198,7 +198,7 @@ def getattr_debug(obj, name, default=_no_default): if attr_in_class: if get is not NULL: - print(f" calling __get__()") + print(" calling __get__()") attr = get(attr, obj, type(obj)) print(f" returning {shortrepr(attr)} ({type(attr)})") return attr @@ -206,14 +206,14 @@ def getattr_debug(obj, name, default=_no_default): try: tpgetattr = type(obj).__getattr__ except AttributeError: - print(f" class does not have __getattr__") + print(" class does not have __getattr__") else: - print(f" calling __getattr__()") + print(" calling __getattr__()") attr = tpgetattr(obj, name) print(f" returning {shortrepr(attr)} ({type(attr)})") return attr - print(f" attribute not found") + print(" attribute not found") raise AttributeError(AttributeErrorMessage(obj, name)) diff --git a/src/sage/cpython/dict_del_by_value.pyx b/src/sage/cpython/dict_del_by_value.pyx index 3894554c13d..19dd2bb2731 100644 --- a/src/sage/cpython/dict_del_by_value.pyx +++ b/src/sage/cpython/dict_del_by_value.pyx @@ -160,12 +160,13 @@ cdef int del_dictitem_by_exact_value(PyDictObject *mp, PyObject *value, Py_hash_ ep.me_value = NULL mp.ma_used -= 1 dictkeys_set_index(keys, i, DKIX_DUMMY) - #We have transferred the to-be-deleted references to the list T - #we now delete the list so that the actual decref happens through a - #deallocation routine that uses the Python Trashcan macros to - #avoid stack overflow in deleting deep structures. + # We have transferred the to-be-deleted references to the list T + # we now delete the list so that the actual decref happens through a + # deallocation routine that uses the Python Trashcan macros to + # avoid stack overflow in deleting deep structures. del T + def test_del_dictitem_by_exact_value(D, value, h): """ This function helps testing some cdef function used to delete dictionary items. diff --git a/src/sage/cpython/getattr.pyx b/src/sage/cpython/getattr.pyx index 0eabdfd36ab..52afed49d64 100644 --- a/src/sage/cpython/getattr.pyx +++ b/src/sage/cpython/getattr.pyx @@ -37,7 +37,7 @@ cdef extern from "Python.h": cdef class AttributeErrorMessage: """ - Tries to emulate the standard Python ``AttributeError`` message. + Tries to emulate the standard Python :class:`AttributeError` message. .. NOTE:: @@ -54,7 +54,8 @@ cdef class AttributeErrorMessage: Traceback (most recent call last): ... AttributeError: 'sage.rings.integer.Integer' object has no attribute 'bla' - sage: QQ[x].gen().bla + sage: x = polygen(ZZ, 'x') + sage: QQ[x].gen().bla # needs sage.libs.flint Traceback (most recent call last): ... AttributeError: 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint' object has no attribute 'bla' @@ -67,7 +68,7 @@ cdef class AttributeErrorMessage: TESTS: - The error message used for the ``AttributeError`` is a unique object + The error message used for the :class:`AttributeError` is a unique object and is changed inplace. This is for reasons of efficiency. Hence, if one really needs the error message as a string, then one should make a copy of its string representation before it changes. :: @@ -83,7 +84,7 @@ cdef class AttributeErrorMessage: ....: except AttributeError as exc: ....: ElementError2 = exc sage: ElementError - AttributeError('sage.symbolic.expression.Expression' object has no attribute '__bla'...) + AttributeError('sage.rings.polynomial...' object has no attribute '__bla'...) sage: ElementError2.args[0] is ElementError.args[0] True sage: isinstance(ElementError.args[0], sage.cpython.getattr.AttributeErrorMessage) @@ -239,7 +240,7 @@ cpdef getattr_from_other_class(self, cls, name): - ``name`` -- a string - If self is an instance of cls, raises an ``AttributeError``, to + If self is an instance of cls, raises an :class:`AttributeError`, to avoid a double lookup. This function is intended to be called from __getattr__, and so should not be called if name is an attribute of self. @@ -270,7 +271,7 @@ cpdef getattr_from_other_class(self, cls, name): Caveat: lazy attributes work with extension types only if they allow attribute assignment or have a public attribute - ``__cached_methods`` of type ``<dict>``. This condition + ``_cached_methods`` of type ``<dict>``. This condition is satisfied, e.g., by any class that is derived from :class:`Parent`:: @@ -299,7 +300,7 @@ cpdef getattr_from_other_class(self, cls, name): TypeError: descriptor '__weakref__' for 'A' objects doesn't apply to ...'sage.rings.integer.Integer' object - When this occurs, an ``AttributeError`` is raised:: + When this occurs, an :class:`AttributeError` is raised:: sage: getattr_from_other_class(1, A, "__weakref__") Traceback (most recent call last): @@ -366,7 +367,7 @@ cpdef getattr_from_other_class(self, cls, name): # Not a descriptor return attribute # Conditionally defined lazy_attributes don't work well with fake subclasses - # (a TypeError is raised if the lazy attribute is not defined). + # (a :class:`TypeError` is raised if the lazy attribute is not defined). # For the moment, we ignore that when this occurs. # Other descriptors (including __weakref__) also break. try: @@ -406,20 +407,21 @@ def dir_with_other_class(self, *cls): Check that objects without dicts are well handled:: - sage: cython("cdef class A:\n cdef public int a") # optional - sage.misc.cython - sage: cython("cdef class B:\n cdef public int b") # optional - sage.misc.cython - sage: x = A() # optional - sage.misc.cython - sage: x.a = 1 # optional - sage.misc.cython - sage: hasattr(x,'__dict__') # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython("cdef class A:\n cdef public int a") + sage: cython("cdef class B:\n cdef public int b") + sage: x = A() + sage: x.a = 1 + sage: hasattr(x,'__dict__') False - sage: dir_with_other_class(x, B) # optional - sage.misc.cython + sage: dir_with_other_class(x, B) [..., 'a', 'b'] TESTS: Check that :trac:`13043` is fixed:: - sage: len(dir(RIF))==len(set(dir(RIF))) + sage: len(dir(RIF))==len(set(dir(RIF))) # needs sage.rings.real_interval_field True """ ret = set() diff --git a/src/sage/cpython/string.pxd b/src/sage/cpython/string.pxd index 9607d7d52c1..1fde0aec0de 100644 --- a/src/sage/cpython/string.pxd +++ b/src/sage/cpython/string.pxd @@ -1,14 +1,12 @@ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Erik M. Bray <erik.bray@lri.fr> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** - - +# https://www.gnu.org/licenses/ +# **************************************************************************** cdef extern from "string_impl.h": str _cstr_to_str(const char* c, encoding, errors) diff --git a/src/sage/cpython/string.pyx b/src/sage/cpython/string.pyx index 2bd86dbfcf6..554a8a128be 100644 --- a/src/sage/cpython/string.pyx +++ b/src/sage/cpython/string.pyx @@ -6,22 +6,23 @@ TESTS: Check that this can be used outside of Sage (see :trac:`25549`):: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' ....: from sage.cpython.string cimport char_to_str ....: print(char_to_str("hello world!")) ....: ''') hello world! """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Erik M. Bray <erik.bray@lri.fr> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import sys diff --git a/src/sage/cpython/wrapperdescr.pxd b/src/sage/cpython/wrapperdescr.pxd index fe0a0618a17..b6775860710 100644 --- a/src/sage/cpython/wrapperdescr.pxd +++ b/src/sage/cpython/wrapperdescr.pxd @@ -39,7 +39,9 @@ cdef inline wrapperbase* get_slotdef(wrapper_descriptor slotwrapper) except NULL TESTS:: - sage: cython(''' # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython( + ....: ''' ....: from sage.cpython.wrapperdescr cimport get_slotdef ....: from cpython.long cimport PyLong_FromVoidPtr ....: def py_get_slotdef(slotwrapper): diff --git a/src/sage/cpython/wrapperdescr.pyx b/src/sage/cpython/wrapperdescr.pyx index 529d4dae2e3..66c79ca38e2 100644 --- a/src/sage/cpython/wrapperdescr.pyx +++ b/src/sage/cpython/wrapperdescr.pyx @@ -68,8 +68,9 @@ def wrapperdescr_call(slotwrapper, self, *args, **kwds): 54 sage: wrapperdescr_call(Element.__mul__, 7/5, 9) 63/5 - sage: from sage.numerical.mip import MixedIntegerLinearProgram - sage: wrapperdescr_call(type.__call__, MixedIntegerLinearProgram, maximization=False) + sage: from sage.numerical.mip import MixedIntegerLinearProgram # needs sage.numerical.mip + sage: wrapperdescr_call(type.__call__, # needs sage.numerical.mip + ....: MixedIntegerLinearProgram, maximization=False) Mixed Integer Program (no objective, 0 variables, 0 constraints) TESTS:: @@ -97,6 +98,6 @@ cdef wrapperdescr_fastcall(wrapper_descriptor slotwrapper, self, args, kwds): if <PyObject*>kwds is not NULL and kwds: raise TypeError(f"wrapper {bytes_to_str(slotdef.name)} slotdef " - "doesn't take keyword arguments") + "doesn't take keyword arguments") return slotdef.wrapper(self, args, slotwrapper.d_wrapped) diff --git a/src/sage/crypto/block_cipher/des.py b/src/sage/crypto/block_cipher/des.py index 4eddfba1425..08afe715710 100644 --- a/src/sage/crypto/block_cipher/des.py +++ b/src/sage/crypto/block_cipher/des.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" DES @@ -77,7 +78,7 @@ from sage.rings.integer_ring import ZZ from sage.modules.free_module_element import vector from sage.rings.finite_rings.finite_field_constructor import GF -from sage.modules.vector_mod2_dense import Vector_mod2_dense +from sage.structure.element import Vector from sage.rings.integer import Integer from sage.crypto.sboxes import DES_S1_1, DES_S1_2, DES_S1_3, DES_S1_4 from sage.crypto.sboxes import DES_S2_1, DES_S2_2, DES_S2_3, DES_S2_4 @@ -472,8 +473,8 @@ def __repr__(self): DES block cipher with 16 rounds and the following key schedule: Original DES key schedule with 16 rounds """ - return('DES block cipher with %s rounds and the following key ' - 'schedule:\n%s' % (self._rounds, self.keySchedule.__repr__())) + return ('DES block cipher with %s rounds and the following key ' + 'schedule:\n%s' % (self._rounds, self.keySchedule.__repr__())) def encrypt(self, plaintext, key): r""" @@ -511,7 +512,7 @@ def encrypt(self, plaintext, key): sage: des.encrypt(P, K56) == C True """ - if isinstance(plaintext, (list, tuple, Vector_mod2_dense)): + if isinstance(plaintext, (list, tuple, Vector)): inputType = 'vector' elif isinstance(plaintext, (Integer, int)): inputType = 'integer' @@ -568,7 +569,7 @@ def decrypt(self, ciphertext, key): sage: des.decrypt(C, K56).hex() == P True """ - if isinstance(ciphertext, (list, tuple, Vector_mod2_dense)): + if isinstance(ciphertext, (list, tuple, Vector)): inputType = 'vector' elif isinstance(ciphertext, (Integer, int)): inputType = 'integer' @@ -868,7 +869,7 @@ def __call__(self, key): pass a ``masterKey`` value on initialisation. Otherwise you can omit ``masterKey`` and pass a key when you call the object. """ - if isinstance(key, (list, tuple, Vector_mod2_dense)): + if isinstance(key, (list, tuple, Vector)): inputType = 'vector' elif isinstance(key, (Integer, int)): inputType = 'integer' diff --git a/src/sage/crypto/block_cipher/miniaes.py b/src/sage/crypto/block_cipher/miniaes.py index 49cb0564d2c..6eb9568b9fc 100644 --- a/src/sage/crypto/block_cipher/miniaes.py +++ b/src/sage/crypto/block_cipher/miniaes.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.modules sage.rings.finite_rings r""" Mini-AES @@ -1510,7 +1511,6 @@ def shift_row(self, block): [block[1][1], block[1][0]] ] ) return mat - ### conversion functions to convert between different data formats def GF_to_binary(self, G): diff --git a/src/sage/crypto/block_cipher/present.py b/src/sage/crypto/block_cipher/present.py index 1774e6d5977..6e5605692a1 100644 --- a/src/sage/crypto/block_cipher/present.py +++ b/src/sage/crypto/block_cipher/present.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" PRESENT @@ -63,8 +64,8 @@ from sage.rings.integer import Integer from sage.modules.free_module_element import vector from sage.rings.finite_rings.finite_field_constructor import GF +from sage.structure.element import Vector from sage.crypto.sboxes import PRESENT as PRESENTSBOX -from sage.modules.vector_mod2_dense import Vector_mod2_dense def _smallscale_present_linearlayer(nsboxes=16): @@ -417,7 +418,7 @@ def encrypt(self, plaintext, key): \leq 32` and current STATE `b_{63} \dots b_0`, addRoundkey consists of the operation for `0 \leq j \leq 63`, `b_j = b_j \oplus \kappa^i_j`. """ - if isinstance(plaintext, (list, tuple, Vector_mod2_dense)): + if isinstance(plaintext, (list, tuple, Vector)): inputType = 'vector' elif isinstance(plaintext, (Integer, int)): inputType = 'integer' @@ -473,7 +474,7 @@ def decrypt(self, ciphertext, key): sage: present.decrypt(c4, k4) == p4 True """ - if isinstance(ciphertext, (list, tuple, Vector_mod2_dense)): + if isinstance(ciphertext, (list, tuple, Vector)): inputType = 'vector' elif isinstance(ciphertext, (Integer, int)): inputType = 'integer' @@ -773,7 +774,7 @@ def __call__(self, K): pass a ``master_key`` value on initialisation. Otherwise you can omit ``master_key`` and pass a key when you call the object. """ - if isinstance(K, (list, tuple, Vector_mod2_dense)): + if isinstance(K, (list, tuple, Vector)): inputType = 'vector' elif isinstance(K, (Integer, int)): inputType = 'integer' diff --git a/src/sage/crypto/block_cipher/sdes.py b/src/sage/crypto/block_cipher/sdes.py index 02a7a14772c..30b8cf2516c 100644 --- a/src/sage/crypto/block_cipher/sdes.py +++ b/src/sage/crypto/block_cipher/sdes.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.rings.finite_rings r""" Simplified DES diff --git a/src/sage/crypto/boolean_function.pxd b/src/sage/crypto/boolean_function.pxd index 2821fb0d1b0..8a97eb875aa 100644 --- a/src/sage/crypto/boolean_function.pxd +++ b/src/sage/crypto/boolean_function.pxd @@ -1,8 +1,8 @@ cdef inline unsigned int hamming_weight(unsigned int x): # valid for 32bits - x -= (x>>1) & 0x55555555UL # 0-2 in 2 bits - x = ((x>>2) & 0x33333333UL) + (x & 0x33333333UL) # 0-4 in 4 bits - x = ((x>>4) + x) & 0x0f0f0f0fUL # 0-8 in 8 bits + x -= (x>>1) & 0x55555555UL # 0-2 in 2 bits + x = ((x>>2) & 0x33333333UL) + (x & 0x33333333UL) # 0-4 in 4 bits + x = ((x>>4) + x) & 0x0f0f0f0fUL # 0-8 in 8 bits x *= 0x01010101UL return x>>24 diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index d10c0c11546..fa99fab5ea3 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -10,14 +10,14 @@ and also algebraic immunity. EXAMPLES:: - sage: R.<x>=GF(2^8,'a')[] + sage: # needs sage.rings.finite_rings + sage: R.<x> = GF(2^8,'a')[] sage: from sage.crypto.boolean_function import BooleanFunction - sage: B = BooleanFunction( x^254 ) # the Boolean function Tr(x^254) - sage: B + sage: B = BooleanFunction(x^254); B # the Boolean function Tr(x^254) Boolean function with 8 variables sage: B.nonlinearity() 112 - sage: B.algebraic_immunity() + sage: B.algebraic_immunity() # needs sage.rings.polynomial.pbori 4 AUTHOR: @@ -32,19 +32,20 @@ AUTHOR: from cysignals.signals cimport sig_check from libc.string cimport memcpy -from sage.structure.sage_object cimport SageObject -from sage.structure.richcmp cimport rich_to_bool -from sage.rings.integer_ring import ZZ -from sage.rings.integer cimport Integer -from sage.rings.finite_rings.finite_field_constructor import GF -from sage.rings.polynomial.pbori.pbori import BooleanPolynomial -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField -from sage.rings.finite_rings.finite_field_givaro import FiniteField_givaro -from sage.rings.polynomial.polynomial_element import is_Polynomial - +from sage.data_structures.bitset_base cimport * from sage.misc.superseded import deprecated_function_alias +from sage.rings.finite_rings.finite_field_base import FiniteField +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.integer cimport Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_element import Polynomial +from sage.structure.richcmp cimport rich_to_bool +from sage.structure.sage_object cimport SageObject -from sage.data_structures.bitset_base cimport * +try: + from sage.rings.polynomial.pbori.pbori import BooleanPolynomial +except ImportError: + BooleanPolynomial = () # for details about the implementation of hamming_weight (in .pxd), # walsh_hadamard transform, reed_muller transform, and a lot @@ -62,13 +63,13 @@ cdef walsh_hadamard(long *f, int ldn): sage: from sage.crypto.boolean_function import BooleanFunction sage: B = BooleanFunction([1,0,0,1]) - sage: B.walsh_hadamard_transform() # indirect doctest + sage: B.walsh_hadamard_transform() # indirect doctest (0, 0, 0, -4) """ cdef long n, ldm, m, mh, t1, t2, r, j, u, v n = 1 << ldn for ldm in range(1, ldn+1): - m = (1 << ldm) + m = (1 << ldm) mh = m // 2 # If this is ``for r in range(0, n, m):``, then Cython generates horrible C code for 0 <= r < n by m: @@ -90,11 +91,12 @@ cdef long yellow_code(unsigned long a): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction sage: R.<x,y,z> = BooleanPolynomialRing(3) sage: P = x*y - sage: B = BooleanFunction( P ) - sage: B.truth_table() # indirect doctest + sage: B = BooleanFunction(P) + sage: B.truth_table() # indirect doctest (False, False, False, True, False, False, False, True) """ cdef unsigned long s = (8*sizeof(unsigned long)) >> 1 @@ -102,7 +104,7 @@ cdef long yellow_code(unsigned long a): cdef unsigned long r = a while(s): sig_check() - r ^= ( (r&m) << s ) + r ^= (r&m) << s s >>= 1 m ^= (m<<s) return r @@ -123,11 +125,12 @@ cdef reed_muller(mp_limb_t* f, int ldn): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction sage: R.<x,y,z> = BooleanPolynomialRing(3) sage: P = x*y - sage: B = BooleanFunction( P ) - sage: B.truth_table() # indirect doctest + sage: B = BooleanFunction(P) + sage: B.truth_table() # indirect doctest (False, False, False, True, False, False, False, True) """ cdef long n, ldm, m, mh, t1, t2, r, j @@ -137,7 +140,7 @@ cdef reed_muller(mp_limb_t* f, int ldn): f[r] = yellow_code(f[r]) # inter word transform for ldm in range(1, ldn+1): - m = 1 << ldm + m = 1 << ldm mh = m // 2 # If this is ``for r in range(0, n, m):``, then Cython generates horrible C code for 0 <= r < n by m: @@ -155,15 +158,15 @@ cdef class BooleanFunction(SageObject): We can construct a Boolean Function from either: - - an integer - the result is the zero function with ``x`` variables; - - a list - it is expected to be the truth table of the + - an integer -- the result is the zero function with ``x`` variables; + - a list -- it is expected to be the truth table of the result. Therefore it must be of length a power of 2, and its elements are interpreted as Booleans; - - a string - representing the truth table in hexadecimal; - - a Boolean polynomial - the result is the corresponding Boolean function; - - a polynomial P over an extension of GF(2) - the result is - the Boolean function with truth table ``( Tr(P(x)) for x in - GF(2^k) )`` + - a string -- representing the truth table in hexadecimal; + - a Boolean polynomial -- the result is the corresponding Boolean function; + - a polynomial `P` over an extension of `\GF{2}` -- the result is + the Boolean function with truth table ``(Tr(P(x)) for x in + GF(2^k))`` EXAMPLES: @@ -180,10 +183,9 @@ cdef class BooleanFunction(SageObject): note that elements can be of different types:: - sage: B = BooleanFunction([False, sqrt(2)]) - sage: B + sage: B = BooleanFunction([False, sqrt(2)]); B # needs sage.symbolic Boolean function with 1 variable - sage: [b for b in B] + sage: [b for b in B] # needs sage.symbolic [False, True] from a string:: @@ -193,21 +195,20 @@ cdef class BooleanFunction(SageObject): from a :class:`sage.rings.polynomial.pbori.BooleanPolynomial`:: - sage: R.<x,y,z> = BooleanPolynomialRing(3) - sage: P = x*y - sage: BooleanFunction( P ) + sage: R.<x,y,z> = BooleanPolynomialRing(3) # needs sage.rings.polynomial.pbori + sage: P = x*y # needs sage.rings.polynomial.pbori + sage: BooleanFunction(P) # needs sage.rings.polynomial.pbori Boolean function with 3 variables from a polynomial over a binary field:: - sage: R.<x> = GF(2^8,'a')[] - sage: B = BooleanFunction( x^7 ) - sage: B + sage: R.<x> = GF(2^8,'a')[] # needs sage.rings.finite_rings + sage: B = BooleanFunction(x^7); B # needs sage.rings.finite_rings Boolean function with 8 variables two failure cases:: - sage: BooleanFunction(sqrt(2)) + sage: BooleanFunction(sqrt(2)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to init the Boolean function @@ -256,29 +257,27 @@ cdef class BooleanFunction(SageObject): note that elements can be of different types:: - sage: B = BooleanFunction([False, sqrt(2)]) - sage: B + sage: B = BooleanFunction([False, sqrt(2)]); B # needs sage.symbolic Boolean function with 1 variable - sage: [b for b in B] + sage: [b for b in B] # needs sage.symbolic [False, True] from a :class:`sage.rings.polynomial.pbori.BooleanPolynomial`:: - sage: R.<x,y,z> = BooleanPolynomialRing(3) - sage: P = x*y - sage: BooleanFunction( P ) + sage: R.<x,y,z> = BooleanPolynomialRing(3) # needs sage.rings.polynomial.pbori + sage: P = x*y # needs sage.rings.polynomial.pbori + sage: BooleanFunction(P) # needs sage.rings.polynomial.pbori Boolean function with 3 variables from a polynomial over a binary field:: - sage: R.<x> = GF(2^8,'a')[] - sage: B = BooleanFunction( x^7 ) - sage: B + sage: R.<x> = GF(2^8,'a')[] # needs sage.rings.finite_rings + sage: B = BooleanFunction(x^7); B # needs sage.rings.finite_rings Boolean function with 8 variables two failure cases:: - sage: BooleanFunction(sqrt(2)) + sage: BooleanFunction(sqrt(2)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to init the Boolean function @@ -297,7 +296,7 @@ cdef class BooleanFunction(SageObject): raise ValueError("the length of the truth table must be a power of 2") from types import GeneratorType if isinstance(x, (list,tuple,GeneratorType)): - # initialisation from a truth table + # initialisation from a truth table # first, check the length L = ZZ(len(x)) @@ -309,36 +308,41 @@ cdef class BooleanFunction(SageObject): # then, initialize our bitset bitset_init(self._truth_table, <mp_bitcnt_t> L) for i in range(L): - bitset_set_to(self._truth_table, i, x[i])#int(x[i])&1) + bitset_set_to(self._truth_table, i, x[i]) # int(x[i])&1) elif isinstance(x, BooleanPolynomial): - # initialisation from a Boolean polynomial + # initialisation from a Boolean polynomial self._nvariables = ZZ(x.parent().ngens()) bitset_init(self._truth_table, <mp_bitcnt_t> (1<<self._nvariables)) bitset_zero(self._truth_table) for m in x: - i = sum( [1<<k for k in m.iterindex()] ) + i = sum([1<<k for k in m.iterindex()]) bitset_set(self._truth_table, i) - reed_muller(self._truth_table.bits, ZZ(self._truth_table.limbs).exact_log(2) ) + reed_muller(self._truth_table.bits, + ZZ(self._truth_table.limbs).exact_log(2)) elif isinstance(x, (int, Integer)): - # initialisation to the zero function + # initialisation to the zero function self._nvariables = ZZ(x) bitset_init(self._truth_table, <mp_bitcnt_t> (1<<self._nvariables)) bitset_zero(self._truth_table) - elif is_Polynomial(x): + elif isinstance(x, Polynomial): K = x.base_ring() - if is_FiniteField(K) and K.characteristic() == 2: + if isinstance(K, FiniteField) and K.characteristic() == 2: self._nvariables = K.degree() bitset_init(self._truth_table, <mp_bitcnt_t> (1<<self._nvariables)) bitset_zero(self._truth_table) - if isinstance(K,FiniteField_givaro): #the ordering is not the same in this case + try: + from sage.rings.finite_rings.finite_field_givaro import FiniteField_givaro + except ImportError: + FiniteField_givaro = () + if isinstance(K, FiniteField_givaro): # the ordering is not the same in this case for u in K: - bitset_set_to(self._truth_table, ZZ(u._vector_().list(),2) , (x(u)).trace()) + bitset_set_to(self._truth_table, ZZ(u._vector_().list(),2), (x(u)).trace()) else: for i,u in enumerate(K): - bitset_set_to(self._truth_table, i , (x(u)).trace()) + bitset_set_to(self._truth_table, i, (x(u)).trace()) elif isinstance(x, BooleanFunction): self._nvariables = x.nvariables() bitset_init(self._truth_table, <mp_bitcnt_t> (1<<self._nvariables)) @@ -369,7 +373,7 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: B=BooleanFunction([0, 1, 1, 0, 1, 0, 0, 0]) + sage: B = BooleanFunction([0, 1, 1, 0, 1, 0, 0, 0]) sage: (~B).truth_table(format='int') (1, 0, 0, 1, 0, 1, 1, 1) """ @@ -385,15 +389,15 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: A=BooleanFunction([0, 1, 0, 1, 1, 0, 0, 1]) - sage: B=BooleanFunction([0, 1, 1, 0, 1, 0, 0, 0]) + sage: A = BooleanFunction([0, 1, 0, 1, 1, 0, 0, 1]) + sage: B = BooleanFunction([0, 1, 1, 0, 1, 0, 0, 0]) sage: (A+B).truth_table(format='int') (0, 0, 1, 1, 0, 0, 0, 1) it also corresponds to the addition of algebraic normal forms:: - sage: S = A.algebraic_normal_form() + B.algebraic_normal_form() - sage: (A+B).algebraic_normal_form() == S + sage: S = A.algebraic_normal_form() + B.algebraic_normal_form() # needs sage.rings.polynomial.pbori + sage: (A+B).algebraic_normal_form() == S # needs sage.rings.polynomial.pbori True TESTS:: @@ -403,7 +407,7 @@ cdef class BooleanFunction(SageObject): ... ValueError: the two Boolean functions must have the same number of variables """ - if (self.nvariables() != other.nvariables() ): + if self.nvariables() != other.nvariables(): raise ValueError("the two Boolean functions must have the same number of variables") cdef BooleanFunction res = BooleanFunction(self) bitset_xor(res._truth_table, res._truth_table, other._truth_table) @@ -417,15 +421,15 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: A=BooleanFunction([0, 1, 0, 1, 1, 0, 0, 1]) - sage: B=BooleanFunction([0, 1, 1, 0, 1, 0, 0, 0]) + sage: A = BooleanFunction([0, 1, 0, 1, 1, 0, 0, 1]) + sage: B = BooleanFunction([0, 1, 1, 0, 1, 0, 0, 0]) sage: (A*B).truth_table(format='int') (0, 1, 0, 0, 1, 0, 0, 0) it also corresponds to the multiplication of algebraic normal forms:: - sage: P = A.algebraic_normal_form() * B.algebraic_normal_form() - sage: (A*B).algebraic_normal_form() == P + sage: P = A.algebraic_normal_form() * B.algebraic_normal_form() # needs sage.rings.polynomial.pbori + sage: (A*B).algebraic_normal_form() == P # needs sage.rings.polynomial.pbori True TESTS:: @@ -435,7 +439,7 @@ cdef class BooleanFunction(SageObject): ... ValueError: the two Boolean functions must have the same number of variables """ - if (self.nvariables() != other.nvariables() ): + if self.nvariables() != other.nvariables(): raise ValueError("the two Boolean functions must have the same number of variables") cdef BooleanFunction res = BooleanFunction(self) bitset_and(res._truth_table, res._truth_table, other._truth_table) @@ -449,8 +453,8 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: A=BooleanFunction([0, 1, 0, 1]) - sage: B=BooleanFunction([0, 1, 1, 0]) + sage: A = BooleanFunction([0, 1, 0, 1]) + sage: B = BooleanFunction([0, 1, 1, 0]) sage: (A|B).truth_table(format='int') (0, 1, 0, 1, 0, 1, 1, 0) @@ -479,12 +483,13 @@ cdef class BooleanFunction(SageObject): res[i+L]=other[i] return res - memcpy(res._truth_table.bits , self._truth_table.bits, nb_limbs * sizeof(unsigned long)) - memcpy(&(res._truth_table.bits[nb_limbs]), other._truth_table.bits, nb_limbs * sizeof(unsigned long)) + memcpy(res._truth_table.bits, + self._truth_table.bits, nb_limbs * sizeof(unsigned long)) + memcpy(&(res._truth_table.bits[nb_limbs]), + other._truth_table.bits, nb_limbs * sizeof(unsigned long)) return res - def algebraic_normal_form(self): """ Return the :class:`sage.rings.polynomial.pbori.BooleanPolynomial` @@ -494,10 +499,9 @@ cdef class BooleanFunction(SageObject): sage: from sage.crypto.boolean_function import BooleanFunction sage: B = BooleanFunction([0,1,1,0,1,0,1,1]) - sage: P = B.algebraic_normal_form() - sage: P + sage: P = B.algebraic_normal_form(); P # needs sage.rings.polynomial.pbori x0*x1*x2 + x0 + x1*x2 + x1 + x2 - sage: [ P(*ZZ(i).digits(base=2,padto=3)) for i in range(8) ] + sage: [P(*ZZ(i).digits(base=2, padto=3)) for i in range(8)] # needs sage.rings.polynomial.pbori [0, 1, 1, 0, 1, 0, 1, 1] """ cdef bitset_t anf @@ -514,14 +518,14 @@ cdef class BooleanFunction(SageObject): for i in range(anf.limbs): if anf.bits[i]: inf = i*sizeof(long)*8 - sup = min( (i+1)*sizeof(long)*8 , (1<<self._nvariables) ) + sup = min((i+1)*sizeof(long)*8, (1<<self._nvariables)) for j in range(inf, sup): if bitset_in(anf,j): m = R(1) for k in range(self._nvariables): if (j>>k)&1: m *= G[k] - P+=m + P += m bitset_free(anf) return P @@ -543,15 +547,16 @@ cdef class BooleanFunction(SageObject): INPUT: a string representing the desired format, can be either - - 'bin' (default) : we return a tuple of Boolean values - - 'int' : we return a tuple of 0 or 1 values - - 'hex' : we return a string representing the truth_table in hexadecimal + - ``'bin'`` (default): we return a tuple of Boolean values + - ``'int'``: we return a tuple of 0 or 1 values + - ``'hex'``: we return a string representing the truth table in hexadecimal EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction sage: R.<x,y,z> = BooleanPolynomialRing(3) - sage: B = BooleanFunction( x*y*z + z + y + 1 ) + sage: B = BooleanFunction(x*y*z + z + y + 1) sage: B.truth_table() (True, True, False, False, False, False, True, False) sage: B.truth_table(format='int') @@ -559,9 +564,10 @@ cdef class BooleanFunction(SageObject): sage: B.truth_table(format='hex') '43' - sage: BooleanFunction('00ab').truth_table(format='hex') + sage: BooleanFunction('00ab').truth_table(format='hex') # needs sage.rings.polynomial.pbori '00ab' + sage: # needs sage.rings.polynomial.pbori sage: H = '0abbacadabbacad0' sage: len(H) 16 @@ -698,16 +704,16 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: R.<x> = GF(2^3,'a')[] - sage: B = BooleanFunction( x^3 ) - sage: B.walsh_hadamard_transform() + sage: R.<x> = GF(2^3,'a')[] # needs sage.rings.finite_rings + sage: B = BooleanFunction(x^3) # needs sage.rings.finite_rings + sage: B.walsh_hadamard_transform() # needs sage.rings.finite_rings (0, -4, 0, 4, 0, 4, 0, 4) """ cdef long *temp cdef mp_bitcnt_t i,n if self._walsh_hadamard_transform is None: - n = self._truth_table.size + n = self._truth_table.size temp = <long *>sig_malloc(sizeof(long)*n) for i in range(n): @@ -745,7 +751,7 @@ cdef class BooleanFunction(SageObject): def is_balanced(self): """ - Return True if the function takes the value True half of the time. + Return ``True`` if the function takes the value ``True`` half of the time. EXAMPLES:: @@ -761,8 +767,10 @@ cdef class BooleanFunction(SageObject): def is_symmetric(self): """ - Return True if the function is symmetric, i.e. invariant under - permutation of its input bits. Another way to see it is that the + Return ``True`` if the function is symmetric, i.e. invariant under + permutation of its input bits. + + Another way to see it is that the output depends only on the Hamming weight of the input. EXAMPLES:: @@ -778,18 +786,19 @@ cdef class BooleanFunction(SageObject): True """ cdef mp_bitcnt_t i - cdef list T = [ self(2**i-1) for i in range(self._nvariables+1) ] + cdef list T = [self(2**i-1) for i in range(self._nvariables+1)] for i in range(1 << self._nvariables): sig_check() - if T[ hamming_weight(i) ] != bitset_in(self._truth_table, i): + if T[hamming_weight(i)] != bitset_in(self._truth_table, i): return False return True def nonlinearity(self): """ - Return the nonlinearity of the function. This is the distance - to the linear functions, or the number of output ones need to - change to obtain a linear function. + Return the nonlinearity of the function. + + This is the distance to the linear functions, or the number of + output ones need to change to obtain a linear function. EXAMPLES:: @@ -805,12 +814,12 @@ cdef class BooleanFunction(SageObject): cdef long w if self._nonlinearity is None: self._nonlinearity = \ - ( (1<<self._nvariables) - max( [abs(w) for w in self.walsh_hadamard_transform()] ) ) >> 1 + ((1<<self._nvariables) - max(abs(w) for w in self.walsh_hadamard_transform())) >> 1 return self._nonlinearity def is_bent(self): """ - Return True if the function is bent. + Return ``True`` if the function is bent. EXAMPLES:: @@ -829,8 +838,8 @@ cdef class BooleanFunction(SageObject): correlation immune of order `m`. A Boolean function is said to be correlation immune of order - `m` , if the output of the function is statistically - independent of the combination of any m of its inputs. + `m` if the output of the function is statistically + independent of the combination of any `m` of its inputs. EXAMPLES:: @@ -846,7 +855,7 @@ cdef class BooleanFunction(SageObject): for i in range(len(W)): sig_check() if W[i]: - c = min( c , hamming_weight(i) ) + c = min(c, hamming_weight(i)) self._correlation_immunity = ZZ(c-1) return self._correlation_immunity @@ -858,7 +867,7 @@ cdef class BooleanFunction(SageObject): A Boolean function is said to be resilient of order `m` if it is balanced and correlation immune of order `m`. - If the function is not balanced, we return -1. + If the function is not balanced, we return `-1`. EXAMPLES:: @@ -888,7 +897,7 @@ cdef class BooleanFunction(SageObject): cdef long i if self._autocorrelation is None: - n = self._truth_table.size + n = self._truth_table.size temp = <long *>sig_malloc(sizeof(long)*n) W = self.walsh_hadamard_transform() @@ -897,7 +906,8 @@ cdef class BooleanFunction(SageObject): temp[i] = W[i]*W[i] walsh_hadamard(temp, self._nvariables) - self._autocorrelation = tuple([temp[i] >> self._nvariables for i in xrange(n)]) + self._autocorrelation = tuple([temp[i] >> self._nvariables + for i in range(n)]) sig_free(temp) return self._autocorrelation @@ -948,7 +958,7 @@ cdef class BooleanFunction(SageObject): cdef long a if self._absolute_indicator is None: D = self.autocorrelation() - self._absolute_indicator = max([ abs(a) for a in D[1:] ]) + self._absolute_indicator = max([abs(a) for a in D[1:]]) return self._absolute_indicator absolut_indicator = deprecated_function_alias(28001, absolute_indicator) @@ -982,17 +992,17 @@ cdef class BooleanFunction(SageObject): INPUT: - ``d`` -- an integer; - - ``dim`` -- a Boolean (default: False), if True, return also + - ``dim`` -- a Boolean (default: ``False``), if ``True``, return also the dimension of the annihilator vector space. EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction sage: f = BooleanFunction("7969817CC5893BA6AC326E47619F5AD0") - sage: f.annihilator(1) is None + sage: f.annihilator(1) is None # needs sage.rings.polynomial.pbori True - sage: g = BooleanFunction( f.annihilator(3) ) - sage: set([ fi*g(i) for i,fi in enumerate(f) ]) + sage: g = BooleanFunction(f.annihilator(3)) # needs sage.rings.polynomial.pbori + sage: set(fi*g(i) for i,fi in enumerate(f)) # needs sage.rings.polynomial.pbori {0} """ # NOTE: this is a toy implementation @@ -1008,7 +1018,7 @@ cdef class BooleanFunction(SageObject): from sage.misc.misc_c import prod from sage.matrix.constructor import Matrix - from sage.arith.all import binomial + from sage.arith.misc import binomial M = Matrix(GF(2), sum(binomial(self._nvariables,i) for i in range(d+1)), len(s)) cdef long i @@ -1045,8 +1055,8 @@ cdef class BooleanFunction(SageObject): """ Return the algebraic immunity of the Boolean function. - This is the smallest integer `i` such that there exists a non - trivial annihilator for `self` or `~self`. + This is the smallest integer `i` such that there exists a + nontrivial annihilator for ``self`` or ``~self``. INPUT: @@ -1055,15 +1065,17 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction sage: R.<x0,x1,x2,x3,x4,x5> = BooleanPolynomialRing(6) sage: B = BooleanFunction(x0*x1 + x1*x2 + x2*x3 + x3*x4 + x4*x5) sage: B.algebraic_immunity(annihilator=True) (2, x0*x1 + x1*x2 + x2*x3 + x3*x4 + x4*x5 + 1) - sage: B[0] +=1 + sage: B[0] += 1 sage: B.algebraic_immunity() 2 + sage: # needs sage.rings.finite_rings sage.rings.polynomial.pbori sage: R.<x> = GF(2^8,'a')[] sage: B = BooleanFunction(x^31) sage: B.algebraic_immunity() @@ -1088,10 +1100,11 @@ cdef class BooleanFunction(SageObject): The algebraic degree of a Boolean function is defined as the degree of its algebraic normal form. Note that the degree of the constant - zero function is defined to be equal to -1. + zero function is defined to be equal to `-1`. EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction sage: B.<x0, x1, x2, x3> = BooleanPolynomialRing() sage: f = BooleanFunction(x1*x2 + x1*x2*x3 + x1) @@ -1111,6 +1124,7 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction sage: R.<x0, x1, x2, x3> = BooleanPolynomialRing() sage: f = BooleanFunction(x0*x1 + x2 + x3) @@ -1151,7 +1165,7 @@ cdef class BooleanFunction(SageObject): True sage: f.is_linear_structure(7) False - sage: f.is_linear_structure(20) #parameter is out of range + sage: f.is_linear_structure(20) # parameter is out of range Traceback (most recent call last): ... IndexError: index out of range @@ -1165,7 +1179,7 @@ cdef class BooleanFunction(SageObject): Traceback (most recent call last): ... TypeError: input vector must be an element of a vector space with dimension 4 - sage: f.is_linear_structure('X') #failure case + sage: f.is_linear_structure('X') # failure case Traceback (most recent call last): ... TypeError: cannot compute is_linear_structure() using parameter X @@ -1237,6 +1251,7 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: + sage: # needs sage.modules sage: from sage.crypto.boolean_function import BooleanFunction sage: f = BooleanFunction([0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0]) sage: LS = f.linear_structures() @@ -1272,6 +1287,7 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction sage: f = BooleanFunction([0,1,0,1,0,1,0,1]) sage: f.derivative(1).algebraic_normal_form() @@ -1279,8 +1295,8 @@ cdef class BooleanFunction(SageObject): sage: u = [1,0,0] sage: f.derivative(u).algebraic_normal_form() 1 - sage: v = vector(GF(2), u) - sage: f.derivative(u).algebraic_normal_form() + sage: v = vector(GF(2), u) # needs sage.modules + sage: f.derivative(v).algebraic_normal_form() # needs sage.modules 1 sage: f.derivative(8).algebraic_normal_form() Traceback (most recent call last): @@ -1311,9 +1327,9 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: B=BooleanFunction([0,0,1,1]) - sage: B[0]=1 - sage: B[2]=(3**17 == 9) + sage: B = BooleanFunction([0,0,1,1]) + sage: B[0] = 1 + sage: B[2] = (3**17 == 9) sage: [b for b in B] [True, False, False, True] @@ -1334,7 +1350,7 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: B=BooleanFunction([0,1,1,1]) + sage: B = BooleanFunction([0,1,1,1]) sage: [ int(B[i]) for i in range(len(B)) ] [0, 1, 1, 1] """ @@ -1373,6 +1389,7 @@ cdef class BooleanFunction(SageObject): """ return unpickle_BooleanFunction, (self.truth_table(format='hex'),) + def unpickle_BooleanFunction(bool_list): """ Specific function to unpickle Boolean functions. @@ -1381,11 +1398,12 @@ def unpickle_BooleanFunction(bool_list): sage: from sage.crypto.boolean_function import BooleanFunction sage: B = BooleanFunction([0,1,1,0]) - sage: loads(dumps(B)) == B # indirect doctest + sage: loads(dumps(B)) == B # indirect doctest True """ return BooleanFunction(bool_list) + cdef class BooleanFunctionIterator: cdef long index, last cdef BooleanFunction f @@ -1413,7 +1431,7 @@ cdef class BooleanFunctionIterator: sage: from sage.crypto.boolean_function import BooleanFunction sage: B = BooleanFunction(1) - sage: [b for b in B] # indirect doctest + sage: [b for b in B] # indirect doctest [False, False] """ return self diff --git a/src/sage/crypto/cipher.py b/src/sage/crypto/cipher.py index 32c06571483..14e9df6a504 100644 --- a/src/sage/crypto/cipher.py +++ b/src/sage/crypto/cipher.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat """ Ciphers """ @@ -73,7 +74,7 @@ class PublicKeyCipher(Cipher): """ Public key cipher class """ - def __init__(self, parent, key, public = True): + def __init__(self, parent, key, public=True): """ Create a public key cipher diff --git a/src/sage/crypto/classical.py b/src/sage/crypto/classical.py index 39cab2a6f90..616dc861652 100644 --- a/src/sage/crypto/classical.py +++ b/src/sage/crypto/classical.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Classical Cryptosystems @@ -45,19 +46,22 @@ # - methods to cryptanalyze the Hill, substitution, transposition, and # Vigenere ciphers +from random import randint + +from sage.arith.misc import inverse_mod, xgcd +from sage.misc.lazy_import import lazy_import from sage.monoids.string_monoid import ( StringMonoid_class, AlphabeticStringMonoid) from sage.monoids.string_monoid_element import StringMonoidElement from sage.monoids.string_ops import strip_encoding -from sage.groups.perm_gps.permgroup_named import SymmetricGroup -from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from sage.arith.all import xgcd, inverse_mod -from random import randint -from sage.matrix.matrix_space import MatrixSpace + +lazy_import('sage.groups.perm_gps.permgroup_named', 'SymmetricGroup') +lazy_import('sage.groups.perm_gps.permgroup_element', 'PermutationGroupElement') +lazy_import('sage.matrix.matrix_space', 'MatrixSpace') from .cryptosystem import SymmetricKeyCryptosystem from .classical_cipher import ( @@ -1201,7 +1205,7 @@ def inverse_key(self, a, b): capital letters of the English alphabet, there are 12 such integers relatively prime to `n`:: - sage: euler_phi(A.alphabet_size()) + sage: euler_phi(A.alphabet_size()) # needs sage.libs.pari 12 And here is a list of those integers:: @@ -1285,7 +1289,7 @@ def random_key(self): class HillCryptosystem(SymmetricKeyCryptosystem): r""" - Create a Hill cryptosystem defined by the `m` x `m` matrix space + Create a Hill cryptosystem defined by the `m \times m` matrix space over `\ZZ / N \ZZ`, where `N` is the alphabet size of the string monoid ``S``. @@ -1302,19 +1306,17 @@ class HillCryptosystem(SymmetricKeyCryptosystem): EXAMPLES:: + sage: # needs sage.modules sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E + sage: E = HillCryptosystem(S, 3); E Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 sage: R = IntegerModRing(26) sage: M = MatrixSpace(R,3,3) - sage: A = M([[1,0,1],[0,1,1],[2,2,3]]) - sage: A + sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A [1 0 1] [0 1 1] [2 2 3] - sage: e = E(A) - sage: e + sage: e = E(A); e Hill cipher on Free alphabetic string monoid on A-Z of block length 3 sage: e(S("LAMAISONBLANCHE")) JYVKSKQPELAYKPV @@ -1322,8 +1324,8 @@ class HillCryptosystem(SymmetricKeyCryptosystem): TESTS:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E == loads(dumps(E)) + sage: E = HillCryptosystem(S, 3) # needs sage.modules + sage: E == loads(dumps(E)) # needs sage.modules True """ @@ -1331,7 +1333,7 @@ def __init__(self, S, m): r""" See ``HillCryptosystem`` for full documentation. - Create a Hill cryptosystem defined by the `m` x `m` matrix space + Create a Hill cryptosystem defined by the `m \times m` matrix space over `\ZZ / N \ZZ`, where `N` is the alphabet size of the string monoid ``S``. @@ -1349,8 +1351,7 @@ def __init__(self, S, m): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E + sage: E = HillCryptosystem(S, 3); E # needs sage.modules Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 """ if not isinstance(S, StringMonoid_class): @@ -1369,18 +1370,16 @@ def __call__(self, A): EXAMPLES:: + sage: # needs sage.modules sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E + sage: E = HillCryptosystem(S,3); E Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 sage: M = E.key_space() - sage: A = M([[1,0,1],[0,1,1],[2,2,3]]) - sage: A + sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A [1 0 1] [0 1 1] [2 2 3] - sage: e = E(A) - sage: e + sage: e = E(A); e Hill cipher on Free alphabetic string monoid on A-Z of block length 3 sage: m = S("LAMAISONBLANCHE") sage: e(m) @@ -1405,10 +1404,9 @@ def _repr_(self): EXAMPLES:: sage: A = AlphabeticStrings() - sage: H = HillCryptosystem(A, 3) - sage: H + sage: H = HillCryptosystem(A, 3); H # needs sage.modules Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 - sage: H._repr_() + sage: H._repr_() # needs sage.modules 'Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3' """ return "Hill cryptosystem on %s of block length %s" % ( @@ -1430,20 +1428,20 @@ def block_length(self): sage: A = AlphabeticStrings() sage: n = randint(1, A.ngens() - 1) - sage: H = HillCryptosystem(A, n) - sage: H.block_length() == n + sage: H = HillCryptosystem(A, n) # needs sage.modules + sage: H.block_length() == n # needs sage.modules True """ return self.key_space().nrows() def random_key(self): - """ + r""" A random key within the key space of this Hill cipher. That is, - generate a random `m` x `m` matrix to be used as a block + generate a random `m \times m` matrix to be used as a block permutation, where `m` is the block length of this Hill cipher. If `n` is the size of the cryptosystem alphabet, then there are `n^{m^2}` possible keys. However the number of valid keys, - i.e. invertible `m` x `m` square matrices, is smaller than + i.e. invertible `m \times m` square matrices, is smaller than `n^{m^2}`. OUTPUT: @@ -1452,6 +1450,7 @@ def random_key(self): EXAMPLES:: + sage: # needs sage.modules sage: A = AlphabeticStrings() sage: n = 3 sage: H = HillCryptosystem(A, n) @@ -1478,7 +1477,7 @@ def inverse_key(self, A): INPUT: - - ``A`` - an invertible matrix of the key space of this Hill cipher + - ``A`` -- an invertible matrix of the key space of this Hill cipher OUTPUT: @@ -1486,8 +1485,9 @@ def inverse_key(self, A): EXAMPLES:: + sage: # needs sage.modules sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) + sage: E = HillCryptosystem(S, 3) sage: A = E.random_key() sage: B = E.inverse_key(A) sage: M = S("LAMAISONBLANCHE") @@ -1519,7 +1519,7 @@ def encoding(self, M): INPUT: - - ``M`` - a string, possibly empty + - ``M`` -- a string, possibly empty OUTPUT: @@ -1529,8 +1529,8 @@ def encoding(self, M): sage: M = "The matrix cipher by Lester S. Hill." sage: A = AlphabeticStrings() - sage: H = HillCryptosystem(A, 7) - sage: H.encoding(M) == A.encoding(M) + sage: H = HillCryptosystem(A, 7) # needs sage.modules + sage: H.encoding(M) == A.encoding(M) # needs sage.modules True """ S = self.cipher_domain() @@ -1547,9 +1547,9 @@ def deciphering(self, A, C): INPUT: - - ``A`` - a key within the key space of this Hill cipher + - ``A`` -- a key within the key space of this Hill cipher - - ``C`` - a string (possibly empty) over the string monoid of this + - ``C`` -- a string (possibly empty) over the string monoid of this Hill cipher OUTPUT: @@ -1558,6 +1558,7 @@ def deciphering(self, A, C): EXAMPLES:: + sage: # needs sage.modules sage: H = HillCryptosystem(AlphabeticStrings(), 3) sage: K = H.random_key() sage: M = H.encoding("Good day, mate! How ya going?") @@ -1585,6 +1586,7 @@ def enciphering(self, A, M): EXAMPLES:: + sage: # needs sage.modules sage: H = HillCryptosystem(AlphabeticStrings(), 3) sage: K = H.random_key() sage: M = H.encoding("Good day, mate! How ya going?") @@ -1595,6 +1597,7 @@ def enciphering(self, A, M): e = self(A) return e(M) + class ShiftCryptosystem(SymmetricKeyCryptosystem): r""" Create a shift cryptosystem. @@ -3258,21 +3261,20 @@ class TranspositionCryptosystem(SymmetricKeyCryptosystem): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) - sage: E - Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 - sage: K = [ 14-i for i in range(14) ] - sage: K + sage: E = TranspositionCryptosystem(S,14); E # needs sage.groups + Transposition cryptosystem on + Free alphabetic string monoid on A-Z of block length 14 + sage: K = [14 - i for i in range(14)]; K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - sage: e = E(K) - sage: e(S("THECATINTHEHAT")) + sage: e = E(K) # needs sage.groups + sage: e(S("THECATINTHEHAT")) # needs sage.groups TAHEHTNITACEHT TESTS:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) - sage: E == loads(dumps(E)) + sage: E = TranspositionCryptosystem(S,14) # needs sage.groups + sage: E == loads(dumps(E)) # needs sage.groups True """ @@ -3283,8 +3285,7 @@ def __init__(self, S, n): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) - sage: E + sage: E = TranspositionCryptosystem(S,14); E # needs sage.groups Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 """ if not isinstance(S, StringMonoid_class): @@ -3303,15 +3304,13 @@ def __call__(self, K): EXAMPLES:: sage: M = AlphabeticStrings() - sage: E = TranspositionCryptosystem(M,14) - sage: E + sage: E = TranspositionCryptosystem(M,14); E # needs sage.groups Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 - sage: K = [ 14-i for i in range(14) ] - sage: K + sage: K = [14 - i for i in range(14)]; K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - sage: e = E(K) + sage: e = E(K) # needs sage.groups sage: m = M("THECATINTHEHAT") - sage: e(m) + sage: e(m) # needs sage.groups TAHEHTNITACEHT """ G = self.key_space() @@ -3331,10 +3330,9 @@ def _repr_(self): EXAMPLES:: sage: A = AlphabeticStrings() - sage: T = TranspositionCryptosystem(A, 14) - sage: T + sage: T = TranspositionCryptosystem(A, 14); T # needs sage.groups Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 - sage: T._repr_() + sage: T._repr_() # needs sage.groups 'Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14' """ return "Transposition cryptosystem on %s of block length %s" % ( @@ -3352,6 +3350,7 @@ def random_key(self): EXAMPLES:: + sage: # needs sage.groups sage: S = AlphabeticStrings() sage: E = TranspositionCryptosystem(S, 14) sage: K = E.random_key() @@ -3372,10 +3371,10 @@ def inverse_key(self, K, check=True): INPUT: - - ``K`` - a key belonging to the key space of this transposition + - ``K`` -- a key belonging to the key space of this transposition cipher - - ``check`` - bool (default: ``True``); check that ``K`` belongs to + - ``check`` -- bool (default: ``True``); check that ``K`` belongs to the key space of this cryptosystem. OUTPUT: @@ -3384,6 +3383,7 @@ def inverse_key(self, K, check=True): EXAMPLES:: + sage: # needs sage.groups sage: S = AlphabeticStrings() sage: E = TranspositionCryptosystem(S, 14) sage: K = E.random_key() @@ -3410,7 +3410,7 @@ def encoding(self, M): INPUT: - - ``M`` - a string, possibly empty + - ``M`` -- a string, possibly empty OUTPUT: @@ -3420,8 +3420,8 @@ def encoding(self, M): sage: M = "Transposition cipher is not about matrix transpose." sage: A = AlphabeticStrings() - sage: T = TranspositionCryptosystem(A, 11) - sage: T.encoding(M) == A.encoding(M) + sage: T = TranspositionCryptosystem(A, 11) # needs sage.groups + sage: T.encoding(M) == A.encoding(M) # needs sage.groups True """ S = self.cipher_domain() @@ -3438,10 +3438,10 @@ def deciphering(self, K, C): INPUT: - - ``K`` - a key belonging to the key space of this transposition + - ``K`` -- a key belonging to the key space of this transposition cipher - - ``C`` - a string (possibly empty) over the string monoid of this + - ``C`` -- a string (possibly empty) over the string monoid of this cryptosystem. OUTPUT: @@ -3450,6 +3450,7 @@ def deciphering(self, K, C): EXAMPLES:: + sage: # needs sage.groups sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) sage: K = T.random_key() sage: M = T.encoding("The cat in the hat.") @@ -3465,10 +3466,10 @@ def enciphering(self, K, M): INPUT: - - ``K`` - a key belonging to the key space of this transposition + - ``K`` -- a key belonging to the key space of this transposition cipher - - ``M`` - a string (possibly empty) over the string monoid of this + - ``M`` -- a string (possibly empty) over the string monoid of this cryptosystem OUTPUT: @@ -3477,6 +3478,7 @@ def enciphering(self, K, M): EXAMPLES:: + sage: # needs sage.groups sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) sage: K = T.random_key() sage: M = T.encoding("The cat in the hat.") @@ -3486,6 +3488,7 @@ def enciphering(self, K, M): e = self(K) return e(M) + class VigenereCryptosystem(SymmetricKeyCryptosystem): """ Create a Vigenere cryptosystem of block length ``n``. @@ -3494,7 +3497,7 @@ class VigenereCryptosystem(SymmetricKeyCryptosystem): - ``S``-- a string monoid over some alphabet - - ``n`` - integer `> 0`; block length of an encryption/decryption key + - ``n`` -- integer `> 0`; block length of an encryption/decryption key OUTPUT: @@ -3621,7 +3624,7 @@ def inverse_key(self, K): INPUT: - - ``K`` - a key within the key space of this Vigenere cryptosystem + - ``K`` -- a key within the key space of this Vigenere cryptosystem OUTPUT: @@ -3653,7 +3656,7 @@ def encoding(self, M): INPUT: - - ``M`` - a string, possibly empty + - ``M`` -- a string, possibly empty OUTPUT: @@ -3681,9 +3684,9 @@ def deciphering(self, K, C): INPUT: - - ``K`` - a key belonging to the key space of this Vigenere cipher + - ``K`` -- a key belonging to the key space of this Vigenere cipher - - ``C`` - a string (possibly empty) over the string monoid of this + - ``C`` -- a string (possibly empty) over the string monoid of this cryptosystem OUTPUT: @@ -3707,9 +3710,9 @@ def enciphering(self, K, M): INPUT: - - ``K`` - a key belonging to the key space of this Vigenere cipher + - ``K`` -- a key belonging to the key space of this Vigenere cipher - - ``M`` - a string (possibly empty) over the string monoid of this + - ``M`` -- a string (possibly empty) over the string monoid of this cryptosystem OUTPUT: diff --git a/src/sage/crypto/classical_cipher.py b/src/sage/crypto/classical_cipher.py index 72ea18a3117..fd2c2464293 100644 --- a/src/sage/crypto/classical_cipher.py +++ b/src/sage/crypto/classical_cipher.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat """ Classical Ciphers """ @@ -8,9 +9,12 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from .cipher import SymmetricKeyCipher +from sage.misc.lazy_import import lazy_import from sage.monoids.string_monoid_element import StringMonoidElement -from sage.modules.free_module import FreeModule + +lazy_import('sage.modules.free_module', 'FreeModule') + +from .cipher import SymmetricKeyCipher class AffineCipher(SymmetricKeyCipher): @@ -152,6 +156,7 @@ def _repr_(self): # as the alphabet used for the plaintext and ciphertext spaces. return "Affine cipher on %s" % self.parent().cipher_domain() + class HillCipher(SymmetricKeyCipher): """ Hill cipher class @@ -164,13 +169,12 @@ def __init__(self, parent, key): EXAMPLES:: + sage: # needs sage.modules sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E + sage: E = HillCryptosystem(S,3); E Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 sage: M = E.key_space() - sage: A = M([[1,0,1],[0,1,1],[2,2,3]]) - sage: A + sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A [1 0 1] [0 1 1] [2 2 3] @@ -182,8 +186,8 @@ def __init__(self, parent, key): TESTS:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E == loads(dumps(E)) + sage: E = HillCryptosystem(S,3) # needs sage.modules + sage: E == loads(dumps(E)) # needs sage.modules True """ # TODO: some type checking that the key is an invertible matrix? @@ -216,6 +220,7 @@ def _repr_(self): EXAMPLES:: + sage: # needs sage.modules sage: H = HillCryptosystem(AlphabeticStrings(), 3) sage: M = MatrixSpace(IntegerModRing(26), 3, 3) sage: A = M([[1,0,1], [0,1,1], [2,2,3]]) @@ -466,12 +471,12 @@ def __init__(self, parent, key): EXAMPLES:: + sage: # needs sage.groups sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) - sage: E - Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 - sage: K = [ 14-i for i in range(14) ] - sage: K + sage: E = TranspositionCryptosystem(S,14); E + Transposition cryptosystem on + Free alphabetic string monoid on A-Z of block length 14 + sage: K = [ 14-i for i in range(14) ]; K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] sage: e = E(K) sage: m = S("THECATINTHEHAT") @@ -480,11 +485,11 @@ def __init__(self, parent, key): EXAMPLES:: + sage: # needs sage.groups sage: S = AlphabeticStrings() sage: E = TranspositionCryptosystem(S,15) sage: m = S("THECATANDTHEHAT") - sage: G = E.key_space() - sage: G + sage: G = E.key_space(); G Symmetric group of order 15! as a permutation group sage: g = G([ 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13 ]) sage: e = E(g) @@ -494,8 +499,8 @@ def __init__(self, parent, key): TESTS:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) - sage: E == loads(dumps(E)) + sage: E = TranspositionCryptosystem(S,14) # needs sage.groups + sage: E == loads(dumps(E)) # needs sage.groups True """ n = parent.block_length() @@ -503,7 +508,7 @@ def __init__(self, parent, key): raise ValueError("key (= %s) must have block length %s" % (key, n)) SymmetricKeyCipher.__init__(self, parent, key) - def __call__(self, M, mode = "ECB"): + def __call__(self, M, mode="ECB"): S = self.domain() # = plaintext_space = ciphertext_space if not isinstance(M, StringMonoidElement) and M.parent() == S: raise TypeError("Argument M (= %s) must be a string in the plaintext space." % M) @@ -555,7 +560,7 @@ def __init__(self, parent, key): """ SymmetricKeyCipher.__init__(self, parent, key) - def __call__(self, M, mode = "ECB"): + def __call__(self, M, mode="ECB"): S = self.domain() # = plaintext_space = ciphertext_space if not isinstance(M, StringMonoidElement) and M.parent() == S: raise TypeError("Argument M (= %s) must be a string in the plaintext space." % M) diff --git a/src/sage/crypto/cryptosystem.py b/src/sage/crypto/cryptosystem.py index b4a1e7c98ea..33cc87cf08e 100644 --- a/src/sage/crypto/cryptosystem.py +++ b/src/sage/crypto/cryptosystem.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Cryptosystems @@ -96,7 +97,7 @@ class Cryptosystem(parent_old.Parent, Set_generic): Substitution cryptosystem on Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3) Hill cryptosystem on Free binary string monoid of block length 3 - sage: TranspositionCryptosystem(OctalStrings(), 5) + sage: TranspositionCryptosystem(OctalStrings(), 5) # needs sage.groups Transposition cryptosystem on Free octal string monoid of block length 5 sage: VigenereCryptosystem(Radix64Strings(), 7) Vigenere cryptosystem on Free radix 64 string monoid of period 7 @@ -129,7 +130,7 @@ def __init__(self, plaintext_space, ciphertext_space, key_space, Substitution cryptosystem on Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3) Hill cryptosystem on Free binary string monoid of block length 3 - sage: TranspositionCryptosystem(OctalStrings(), 5) + sage: TranspositionCryptosystem(OctalStrings(), 5) # needs sage.groups Transposition cryptosystem on Free octal string monoid of block length 5 sage: VigenereCryptosystem(Radix64Strings(), 7) Vigenere cryptosystem on Free radix 64 string monoid of period 7 @@ -172,9 +173,9 @@ def __eq__(self, right): sage: hill2 = HillCryptosystem(AlphabeticStrings(), 4) sage: hill1 == hill2 True - sage: tran1 = TranspositionCryptosystem(HexadecimalStrings(), 5) - sage: tran2 = TranspositionCryptosystem(HexadecimalStrings(), 5) - sage: tran1 == tran2 + sage: tran1 = TranspositionCryptosystem(HexadecimalStrings(), 5) # needs sage.groups + sage: tran2 = TranspositionCryptosystem(HexadecimalStrings(), 5) # needs sage.groups + sage: tran1 == tran2 # needs sage.groups True sage: vig1 = VigenereCryptosystem(AlphabeticStrings(), 7) sage: vig2 = VigenereCryptosystem(AlphabeticStrings(), 7) @@ -195,9 +196,9 @@ def __eq__(self, right): sage: hill2 = HillCryptosystem(Radix64Strings(), 5) sage: hill1 == hill2 False - sage: tran1 = TranspositionCryptosystem(Radix64Strings(), 3) - sage: tran2 = TranspositionCryptosystem(HexadecimalStrings(), 3) - sage: tran1 == tran2 + sage: tran1 = TranspositionCryptosystem(Radix64Strings(), 3) # needs sage.groups + sage: tran2 = TranspositionCryptosystem(HexadecimalStrings(), 3) # needs sage.groups + sage: tran1 == tran2 # needs sage.groups False sage: vig1 = VigenereCryptosystem(AlphabeticStrings(), 7) sage: vig2 = VigenereCryptosystem(Radix64Strings(), 7) @@ -207,7 +208,7 @@ def __eq__(self, right): return (type(self) is type(right) and self._cipher_domain == right._cipher_domain and self._cipher_codomain == right._cipher_codomain and - self._key_space == right._key_space and + self._key_space == right._key_space and self._block_length == right._block_length and self._period == right._period) @@ -225,7 +226,7 @@ def plaintext_space(self): Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3).plaintext_space() Free binary string monoid - sage: TranspositionCryptosystem(OctalStrings(), 5).plaintext_space() + sage: TranspositionCryptosystem(OctalStrings(), 5).plaintext_space() # needs sage.groups Free octal string monoid sage: VigenereCryptosystem(Radix64Strings(), 7).plaintext_space() Free radix 64 string monoid @@ -248,7 +249,7 @@ def cipher_domain(self): Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3).cipher_domain() Free binary string monoid - sage: TranspositionCryptosystem(OctalStrings(), 5).cipher_domain() + sage: TranspositionCryptosystem(OctalStrings(), 5).cipher_domain() # needs sage.groups Free octal string monoid sage: VigenereCryptosystem(Radix64Strings(), 7).cipher_domain() Free radix 64 string monoid @@ -269,7 +270,7 @@ def ciphertext_space(self): Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3).ciphertext_space() Free binary string monoid - sage: TranspositionCryptosystem(OctalStrings(), 5).ciphertext_space() + sage: TranspositionCryptosystem(OctalStrings(), 5).ciphertext_space() # needs sage.groups Free octal string monoid sage: VigenereCryptosystem(Radix64Strings(), 7).ciphertext_space() Free radix 64 string monoid @@ -292,7 +293,7 @@ def cipher_codomain(self): Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3).cipher_codomain() Free binary string monoid - sage: TranspositionCryptosystem(OctalStrings(), 5).cipher_codomain() + sage: TranspositionCryptosystem(OctalStrings(), 5).cipher_codomain() # needs sage.groups Free octal string monoid sage: VigenereCryptosystem(Radix64Strings(), 7).cipher_codomain() Free radix 64 string monoid @@ -313,7 +314,7 @@ def key_space(self): Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3).key_space() Full MatrixSpace of 3 by 3 dense matrices over Ring of integers modulo 2 - sage: TranspositionCryptosystem(OctalStrings(), 5).key_space() + sage: TranspositionCryptosystem(OctalStrings(), 5).key_space() # needs sage.groups Symmetric group of order 5! as a permutation group sage: VigenereCryptosystem(Radix64Strings(), 7).key_space() Free radix 64 string monoid @@ -335,7 +336,7 @@ def block_length(self): 1 sage: HillCryptosystem(BinaryStrings(), 3).block_length() 3 - sage: TranspositionCryptosystem(OctalStrings(), 5).block_length() + sage: TranspositionCryptosystem(OctalStrings(), 5).block_length() # needs sage.groups 5 sage: VigenereCryptosystem(Radix64Strings(), 7).block_length() 1 diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index cf72c2660c4..d24b87fe5d4 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules """ Hard Lattice Generator @@ -35,27 +36,36 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, INPUT: - ``type`` -- one of the following strings - - ``'modular'`` (default) -- A class of lattices for which - asymptotic worst-case to average-case connections hold. For - more refer to [Aj1996]_. - - ``'random'`` -- Special case of modular (n=1). A dense class - of lattice used for testing basis reduction algorithms - proposed by Goldstein and Mayer [GM2002]_. - - ``'ideal'`` -- Special case of modular. Allows for a more - compact representation proposed by [LM2006]_. - - ``'cyclotomic'`` -- Special case of ideal. Allows for - efficient processing proposed by [LM2006]_. - - ``n`` -- Determinant size, primal:`det(L) = q^n`, dual:`det(L) = q^{m-n}`. + + - ``'modular'`` (default) -- A class of lattices for which + asymptotic worst-case to average-case connections hold. For + more refer to [Aj1996]_. + - ``'random'`` -- Special case of modular (n=1). A dense class + of lattice used for testing basis reduction algorithms + proposed by Goldstein and Mayer [GM2002]_. + - ``'ideal'`` -- Special case of modular. Allows for a more + compact representation proposed by [LM2006]_. + - ``'cyclotomic'`` -- Special case of ideal. Allows for + efficient processing proposed by [LM2006]_. + + - ``n`` -- Determinant size, primal: `det(L) = q^n`, dual: `det(L) = q^{m-n}`. For ideal lattices this is also the degree of the quotient polynomial. + - ``m`` -- Lattice dimension, `L \subseteq Z^m`. + - ``q`` -- Coefficient size, `q-Z^m \subseteq L`. + - ``seed`` -- Randomness seed. - - ``quotient`` -- For the type ideal, this determines the quotient + + - ``quotient`` -- For the type ``'ideal'``, this determines the quotient polynomial. Ignored for all other types. + - ``dual`` -- Set this flag if you want a basis for `q-dual(L)`, for example for Regev's LWE bases [Reg2005]_. + - ``ntl`` -- Set this flag if you want the lattice basis in NTL readable format. + - ``lattice`` -- Set this flag if you want a :class:`FreeModule_submodule_with_basis_integer` object instead of an integer matrix representing the basis. @@ -95,9 +105,9 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, [ 3082 0 0 0 0 0 0 0 1 0] [-4580 0 0 0 0 0 0 0 0 1] - Ideal bases with quotient x^n-1, m=2*n are NTRU bases:: + Ideal bases with quotient `x^n-1`, `m=2*n` are NTRU bases:: - sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4-1) + sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4 - 1) # needs sage.symbolic [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] @@ -110,7 +120,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, Ideal bases also work with polynomials:: sage: R.<t> = PolynomialRing(ZZ) - sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=t^4-1) + sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=t^4 - 1) # needs sage.libs.pari [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] @@ -122,7 +132,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, Cyclotomic bases with n=2^k are SWIFFT bases:: - sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42) + sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42) # needs sage.libs.pari [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] @@ -149,9 +159,9 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, Relation of primal and dual bases:: - sage: B_primal=sage.crypto.gen_lattice(m=10, q=11, seed=42) - sage: B_dual=sage.crypto.gen_lattice(m=10, q=11, seed=42, dual=True) - sage: B_dual_alt=transpose(11*B_primal.inverse()).change_ring(ZZ) + sage: B_primal = sage.crypto.gen_lattice(m=10, q=11, seed=42) + sage: B_dual = sage.crypto.gen_lattice(m=10, q=11, seed=42, dual=True) + sage: B_dual_alt = transpose(11*B_primal.inverse()).change_ring(ZZ) sage: B_dual_alt.hermite_form() == B_dual.hermite_form() True @@ -159,11 +169,11 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, Test some bad quotient polynomials:: - sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=cos(x)) + sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=cos(x)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: self must be a numeric expression - sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=x^23-1) + sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=x^23-1) # needs sage.symbolic Traceback (most recent call last): ... ValueError: ideal basis requires n = quotient.degree() @@ -218,7 +228,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.matrix.constructor import identity_matrix, block_matrix from sage.matrix.matrix_space import MatrixSpace - from sage.rings.integer_ring import IntegerRing + from sage.rings.integer_ring import ZZ if seed is not None: from sage.misc.randstate import set_random_seed set_random_seed(seed) @@ -227,7 +237,6 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, if n != 1: raise ValueError('random bases require n = 1') - ZZ = IntegerRing() ZZ_q = IntegerModRing(q) A = identity_matrix(ZZ_q, n) @@ -256,7 +265,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, A = A.stack(R.random_element().matrix()) elif type == 'cyclotomic': - from sage.arith.all import euler_phi + from sage.arith.misc import euler_phi from sage.misc.functional import cyclotomic_polynomial # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n diff --git a/src/sage/crypto/lfsr.py b/src/sage/crypto/lfsr.py index 40b469652ec..869bdcf5990 100644 --- a/src/sage/crypto/lfsr.py +++ b/src/sage/crypto/lfsr.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Linear feedback shift register (LFSR) sequence commands @@ -128,8 +129,9 @@ import copy from sage.structure.all import Sequence -from sage.rings.all import Integer, PolynomialRing -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField +from sage.rings.integer import Integer +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing def lfsr_sequence(key, fill, n): @@ -179,7 +181,7 @@ def lfsr_sequence(key, fill, n): raise TypeError("key must be a list") key = Sequence(key) F = key.universe() - if not is_FiniteField(F): + if not isinstance(F, FiniteField): raise TypeError("universe of sequence must be a finite field") s = fill diff --git a/src/sage/crypto/lwe.py b/src/sage/crypto/lwe.py index bc027e97362..0be1b92d77e 100644 --- a/src/sage/crypto/lwe.py +++ b/src/sage/crypto/lwe.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs scipy sage.symbolic """ (Ring-)LWE oracle generators @@ -52,6 +52,7 @@ Note that Ring-LWE samples are returned as vectors:: + sage: # needs sage.libs.pari sage: from sage.crypto.lwe import RingLWE sage: from sage.stats.distributions.discrete_gaussian_polynomial import DiscreteGaussianDistributionPolynomialSampler sage: D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], euler_phi(16), 5) @@ -91,23 +92,25 @@ - [CGW2013]_ """ +from sage.arith.misc import euler_phi, next_prime from sage.functions.log import log from sage.functions.other import floor, ceil -from sage.misc.functional import sqrt from sage.misc.functional import cyclotomic_polynomial, round -from sage.misc.randstate import set_random_seed +from sage.misc.functional import sqrt from sage.misc.prandom import randint +from sage.misc.randstate import set_random_seed from sage.modules.free_module import FreeModule from sage.modules.free_module_element import random_vector, vector from sage.numerical.optimize import find_root -from sage.rings.all import ZZ, IntegerModRing, RR -from sage.arith.all import next_prime, euler_phi +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.integer_ring import ZZ +from sage.rings.real_mpfr import RR +from sage.stats.distributions.discrete_gaussian_integer import DiscreteGaussianDistributionIntegerSampler +from sage.stats.distributions.discrete_gaussian_polynomial import DiscreteGaussianDistributionPolynomialSampler from sage.structure.element import parent from sage.structure.sage_object import SageObject from sage.symbolic.constants import pi from sage.symbolic.ring import SR -from sage.stats.distributions.discrete_gaussian_integer import DiscreteGaussianDistributionIntegerSampler -from sage.stats.distributions.discrete_gaussian_polynomial import DiscreteGaussianDistributionPolynomialSampler class UniformSampler(SageObject): @@ -281,7 +284,7 @@ def __init__(self, n, q, D, secret_dist='uniform', m=None): sage: L = [] sage: def add_samples(): ....: global L - ....: L += [lwe() for _ in range(1000)] + ....: L += [lwe() for _ in range(100)] sage: add_samples() To test the oracle, we use the internal secret to evaluate the samples @@ -294,8 +297,9 @@ def __init__(self, n, q, D, secret_dist='uniform', m=None): fix the representation and recover the correct standard deviation of the noise:: - sage: from numpy import std - sage: while abs(std([e if e <= 200 else e-401 for e in S()]) - 3.0) > 0.01: + sage: from numpy import std # needs numpy + sage: while abs(std([e if e <= 200 else e-401 for e in S()]) - 3.0) > 0.01: # needs numpy + ....: L = [] # reset L to avoid quadratic behaviour ....: add_samples() If ``m`` is not ``None`` the number of available samples is restricted:: @@ -303,13 +307,13 @@ def __init__(self, n, q, D, secret_dist='uniform', m=None): sage: from sage.crypto.lwe import LWE sage: lwe = LWE(n=20, q=next_prime(400), D=D, m=30) sage: _ = [lwe() for _ in range(30)] - sage: lwe() # 31 + sage: lwe() # 31 Traceback (most recent call last): ... IndexError: Number of available samples exhausted. """ self.n = ZZ(n) - self.m = m + self.m = m self.__i = 0 self.K = IntegerModRing(q) self.FM = FreeModule(self.K, n) @@ -345,7 +349,6 @@ def _repr_(self): else: return "LWE(%d, %d, %s, %s, %s)"%(self.n,self.K.order(),self.D,self.secret_dist, self.m) - def __call__(self): """ EXAMPLES:: @@ -537,13 +540,13 @@ def __init__(self, N, q, D, poly=None, secret_dist='uniform', m=None): sage: from sage.crypto.lwe import RingLWE sage: from sage.stats.distributions.discrete_gaussian_polynomial import DiscreteGaussianDistributionPolynomialSampler - sage: D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n=euler_phi(20), sigma=3.0) - sage: RingLWE(N=20, q=next_prime(800), D=D) + sage: D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n=euler_phi(20), sigma=3.0) # needs sage.libs.pari + sage: RingLWE(N=20, q=next_prime(800), D=D) # needs sage.libs.pari RingLWE(20, 809, Discrete Gaussian sampler for polynomials of degree < 8 with ฯƒ=3.000000 in each component, x^8 - x^6 + x^4 - x^2 + 1, 'uniform', None) """ self.N = ZZ(N) self.n = euler_phi(N) - self.m = m + self.m = m self.__i = 0 self.K = IntegerModRing(q) @@ -581,11 +584,11 @@ def _repr_(self): else: return "RingLWE(%d, %d, %s, %s, %s, %s)"%(self.N, self.K.order(), self.D, self.poly, self.secret_dist, self.m) - def __call__(self): """ EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.crypto.lwe import DiscreteGaussianDistributionPolynomialSampler, RingLWE sage: N = 16 sage: n = euler_phi(N) diff --git a/src/sage/crypto/mq/mpolynomialsystemgenerator.py b/src/sage/crypto/mq/mpolynomialsystemgenerator.py index 3c0bb6b349c..9028dab1d98 100644 --- a/src/sage/crypto/mq/mpolynomialsystemgenerator.py +++ b/src/sage/crypto/mq/mpolynomialsystemgenerator.py @@ -68,7 +68,7 @@ def varstrs(self, name, round): sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator sage: msg = MPolynomialSystemGenerator() - sage: msg.varstrs('K', i) + sage: msg.varstrs('K', i) # needs sage.all Traceback (most recent call last): ... NotImplementedError diff --git a/src/sage/crypto/mq/rijndael_gf.py b/src/sage/crypto/mq/rijndael_gf.py index 154c84d146c..ba24ed0627e 100644 --- a/src/sage/crypto/mq/rijndael_gf.py +++ b/src/sage/crypto/mq/rijndael_gf.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" Rijndael-GF @@ -80,7 +81,7 @@ '3902dc1925dc116a8409850b1dfb9732'. We can use this example to demonstrate the correctness of this implementation:: - sage: rgf = RijndaelGF(4, 4) # change dimensions for this example + sage: rgf = RijndaelGF(4, 4) # change dimensions for this example sage: plain = '3243f6a8885a308d313198a2e0370734' sage: key = '2b7e151628aed2a6abf7158809cf4f3c' sage: expected_ciphertext = '3925841d02dc09fbdc118597196a0b32' @@ -160,8 +161,7 @@ finally perform the inversion step after the affine transformation polynomial has been evaluated. :: - sage: inv_affine = sb_pc(1, 2, algorithm='decrypt', - ....: no_inversion=True) + sage: inv_affine = sb_pc(1, 2, algorithm='decrypt', no_inversion=True) sage: state = rgf._hex_to_GF('ff87968431d86a51645151fa773ad009') sage: evaluated = inv_affine(state.list()) sage: result = evaluated * -1 @@ -252,7 +252,7 @@ ``apply_poly`` a dictionary mapping keywords to their values. :: sage: rgf.apply_poly(rgf.state_vrs, rgf.add_round_key_poly_constr(), - ....: poly_constr_attr={'round' : 5}) + ....: poly_constr_attr={'round': 5}) [a00 + k500 a01 + k501 a02 + k502 a03 + k503] [a10 + k510 a11 + k511 a12 + k512 a13 + k513] [a20 + k520 a21 + k521 a22 + k522 a23 + k523] @@ -269,10 +269,11 @@ when passed an index ``i,j`` will return `g(f(A))_{i,j}` in terms of the entries of `A`. :: + sage: # needs sage.libs.gap sage: rcpc = rgf.compose(rgf.shift_rows_poly_constr(), - ....: rgf.mix_columns_poly_constr()) - sage: rcpc - A polynomial constructor of a round component of Rijndael-GF block cipher with block length 4, key length 6, and 12 rounds. + ....: rgf.mix_columns_poly_constr()); rcpc + A polynomial constructor of a round component of Rijndael-GF block cipher + with block length 4, key length 6, and 12 rounds. sage: rcpc(2, 1) a01 + a12 + x*a23 + (x + 1)*a30 <BLANKLINE> @@ -284,7 +285,7 @@ True <BLANKLINE> sage: rcpc = rgf.compose(rgf.mix_columns_poly_constr(), - ....: rgf.shift_rows_poly_constr()) + ....: rgf.shift_rows_poly_constr()) sage: result = rgf.apply_poly(state, rcpc, algorithm='decrypt') sage: new_state = rgf.mix_columns(state, algorithm='decrypt') sage: new_state = rgf.shift_rows(new_state, algorithm='decrypt') @@ -301,8 +302,7 @@ ``compose`` will return a polynomial representing `g(f(A))_{i,j}` in terms of the entries of `A`. :: - sage: poly = rgf.mix_columns_poly_constr()(0, 3) - sage: poly + sage: poly = rgf.mix_columns_poly_constr()(0, 3); poly x*a03 + (x + 1)*a13 + a23 + a33 sage: rgf.compose(rgf.sub_bytes_poly_constr(), poly) (x^3 + x)*a03^254 + @@ -347,16 +347,18 @@ returned ``Round_Component_Poly_Constr`` object's ``__call__`` method must have its own ``algorithm`` keyword defaulted to 'encrypt'. :: + sage: # needs sage.libs.gap sage: poly = rgf.shift_rows_poly_constr()(2, 1) sage: rgf.compose(rgf.mix_columns_poly_constr(), poly, algorithm='decrypt') (x^3 + x^2 + 1)*a03 + (x^3 + 1)*a13 + (x^3 + x^2 + x)*a23 + (x^3 + x + 1)*a33 <BLANKLINE> sage: state = rgf._hex_to_GF('80121e0776fd1d8a8d8c31bc965d1fee') sage: with_decrypt = rgf.compose(rgf.sub_bytes_poly_constr(), - ....: rgf.shift_rows_poly_constr(), algorithm='decrypt') + ....: rgf.shift_rows_poly_constr(), + ....: algorithm='decrypt') sage: result_wd = rgf.apply_poly(state, with_decrypt) sage: no_decrypt = rgf.compose(rgf.sub_bytes_poly_constr(), - ....: rgf.shift_rows_poly_constr()) + ....: rgf.shift_rows_poly_constr()) sage: result_nd = rgf.apply_poly(state, no_decrypt) sage: result_wd == result_nd True @@ -365,10 +367,10 @@ ``compose`` to make ``f`` and ``g`` use those keywords during polynomial creation. :: - sage: rcpc = rgf.compose(rgf.add_round_key_poly_constr(), - ....: rgf.add_round_key_poly_constr(), - ....: f_attr={'round' : 4}, g_attr={'round' : 7}) - sage: rcpc(1, 2) + sage: rcpc = rgf.compose(rgf.add_round_key_poly_constr(), # needs sage.libs.gap + ....: rgf.add_round_key_poly_constr(), + ....: f_attr={'round': 4}, g_attr={'round': 7}) + sage: rcpc(1, 2) # needs sage.libs.gap a12 + k412 + k712 In addition to building polynomial representations of state matrices, we can @@ -424,7 +426,8 @@ from sage.matrix.constructor import matrix from sage.matrix.constructor import column_matrix -from sage.structure.element import Matrix +from sage.structure.element import Element, Matrix +from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_base from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.structure.sage_object import SageObject from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -515,7 +518,7 @@ def __init__(self, Nb, Nk, state_chr='a', key_chr='k'): self._all_PR = PolynomialRing(self._F, len(state_names + subkey_names), state_names + subkey_names) self.state_vrs = matrix(4, self._Nb, self._state_PR.gens()) - fNb = 4 * self._Nb + fNb = 4 * self._Nb self.subkey_vrs_list = list(self._all_PR.gens()[fNb:]) self.subkey_vrs = [matrix(4, self._Nb, self.subkey_vrs_list[fNb * i: fNb * (i + 1)]) @@ -757,10 +760,9 @@ def _GF_to_hex(self, GF): sage: rgf._GF_to_hex(output) 'e142cd5fcd9d6d94a3340793034391b5' """ - from sage.rings.finite_rings.element_base import is_FiniteFieldElement if not isinstance(GF, Matrix) and \ not isinstance(GF, list) and \ - not is_FiniteFieldElement(GF): + not (isinstance(GF, Element) and isinstance(GF.parent(), FiniteField_base)): msg = ("keyword 'GF' must be a matrix over {0}, a list of " "elements from {0}, or a single element from {0}") raise TypeError(msg.format(self._F)) @@ -883,10 +885,9 @@ def _GF_to_bin(self, GF): sage: rgf._GF_to_bin(output) '11011000000111111111100000011011110110000001111111111000000110111101100000011111111110000001101111011000000111111111100000011011' """ - from sage.rings.finite_rings.element_base import is_FiniteFieldElement if not isinstance(GF, Matrix) and \ not isinstance(GF, list) and \ - not is_FiniteFieldElement(GF): + not (isinstance(GF, Element) and isinstance(GF.parent(), FiniteField_base)): msg = ("keyword 'GF' must be a matrix over {0}, a list of " "elements from {0}, or a single element from {0}") raise TypeError(msg.format(self)) @@ -1119,14 +1120,16 @@ def _check_valid_PRmatrix(self, PRm, keyword): sage: rgf._check_valid_PRmatrix(5, 'state') Traceback (most recent call last): ... - TypeError: keyword 'state' must be a 4 x 4 matrix with entries from a multivariate PolynomialRing over Finite Field in x of size 2^8 + TypeError: keyword 'state' must be a 4 x 4 matrix with entries from + a multivariate PolynomialRing over Finite Field in x of size 2^8 <BLANKLINE> sage: entries = [rgf._F.random_element() for i in range(24)] sage: wrong_dimensions = matrix(4, 6, entries) sage: rgf._check_valid_PRmatrix(wrong_dimensions, 'state') Traceback (most recent call last): ... - TypeError: keyword 'state' must be a 4 x 4 matrix with entries from a multivariate PolynomialRing over Finite Field in x of size 2^8 + TypeError: keyword 'state' must be a 4 x 4 matrix with entries from + a multivariate PolynomialRing over Finite Field in x of size 2^8 <BLANKLINE> sage: F.<a> = GF(3^4) sage: entries = [F.random_element() for i in range(16)] @@ -1134,23 +1137,24 @@ def _check_valid_PRmatrix(self, PRm, keyword): sage: rgf._check_valid_PRmatrix(wrong_base, 'state') Traceback (most recent call last): ... - TypeError: keyword 'state' must be a 4 x 4 matrix with entries from a multivariate PolynomialRing over Finite Field in x of size 2^8 + TypeError: keyword 'state' must be a 4 x 4 matrix with entries from + a multivariate PolynomialRing over Finite Field in x of size 2^8 """ from sage.rings.polynomial.multi_polynomial_ring_base import \ MPolynomialRing_base msg = ("keyword '{0}' must be a {1} x {2} matrix with entries from a " "multivariate PolynomialRing over {3}") msg = msg.format(keyword, 4, self._Nb, self._F) - if (not isinstance(PRm, Matrix) or \ - not (PRm.base_ring().is_field() and \ - PRm.base_ring().is_finite() and \ - PRm.base_ring().order() == 256 and \ - PRm.dimensions() == (4, self._Nb))) and \ - (not isinstance(PRm, Matrix) or \ - not isinstance(PRm.base_ring(), MPolynomialRing_base) or \ - not (PRm.base_ring().base_ring().is_field() and \ - PRm.base_ring().base_ring().is_finite() and \ - PRm.base_ring().base_ring().order() == 256) or \ + if (not isinstance(PRm, Matrix) or + not (PRm.base_ring().is_field() and + PRm.base_ring().is_finite() and + PRm.base_ring().order() == 256 and + PRm.dimensions() == (4, self._Nb))) and \ + (not isinstance(PRm, Matrix) or + not isinstance(PRm.base_ring(), MPolynomialRing_base) or + not (PRm.base_ring().base_ring().is_field() and + PRm.base_ring().base_ring().is_finite() and + PRm.base_ring().base_ring().order() == 256) or not PRm.dimensions() == (4, self._Nb)): raise TypeError(msg) @@ -1184,8 +1188,8 @@ def expand_key(self, key): msg = "keyword '{0}' must be a {1} x {2} matrix over GF({3})" msg = msg.format(key, 4, self._Nk, self._F.order()) if not isinstance(key, Matrix) or \ - not (key.base_ring().is_field() and \ - key.base_ring().is_finite() and \ + not (key.base_ring().is_field() and + key.base_ring().is_finite() and key.base_ring().order() == self._F.order()) or \ not key.dimensions() == (4, self._Nk): raise TypeError(msg) @@ -1266,7 +1270,8 @@ def expand_key_poly(self, row, col, round): sage: rgf.compose(rgf.sub_bytes_poly_constr(), rgf.expand_key_poly) Traceback (most recent call last): ... - TypeError: keyword 'g' must be a Round_Component_Poly_Constr or a polynomial over Finite Field in x of size 2^8 + TypeError: keyword 'g' must be a Round_Component_Poly_Constr or + a polynomial over Finite Field in x of size 2^8 <BLANKLINE> sage: state = rgf._hex_to_GF('00000000000000000000000000000000') sage: rgf.apply_poly(state, rgf.expand_key_poly) @@ -1359,7 +1364,7 @@ def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, sage: state = rgf._hex_to_GF('4915598f55e5d7a0daca94fa1f0a63f7') sage: apply_poly_result = rgf.apply_poly(state, - ....: rgf.sub_bytes_poly_constr()) + ....: rgf.sub_bytes_poly_constr()) sage: direct_result = rgf.sub_bytes(state) sage: direct_result == apply_poly_result True @@ -1374,7 +1379,8 @@ def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, sage: key = rgf._hex_to_GF('54d990a16ba09ab596bbf40ea111702f') sage: keys = rgf.expand_key(key) sage: result = rgf.apply_poly(state, - ....: rgf.add_round_key_poly_constr(), keys=keys) + ....: rgf.add_round_key_poly_constr(), + ....: keys=keys) sage: result == rgf.add_round_key(state, key) True <BLANKLINE> @@ -1386,8 +1392,8 @@ def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, dictionary ``poly_constr_attr`` mapping keywords to their values. :: sage: rgf.apply_poly(rgf.state_vrs, - ....: rgf.add_round_key_poly_constr(), - ....: poly_constr_attr={'round' : 5}) + ....: rgf.add_round_key_poly_constr(), + ....: poly_constr_attr={'round': 5}) [a00 + k500 a01 + k501 a02 + k502 a03 + k503] [a10 + k510 a11 + k511 a12 + k512 a13 + k513] [a20 + k520 a21 + k521 a22 + k522 a23 + k523] @@ -1397,12 +1403,12 @@ def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, if not isinstance(poly_constr, RijndaelGF.Round_Component_Poly_Constr): msg = "keyword 'poly_constr' must be a Round_Component_Poly_Constr" raise TypeError(msg) - if keys is not None and (not isinstance(keys, list) or \ - len(keys) != self._Nr + 1 or \ - not all(isinstance(k, Matrix) for k in keys) or \ - not all(k.dimensions() == (4, self._Nb) for k in keys) or \ + if keys is not None and (not isinstance(keys, list) or + len(keys) != self._Nr + 1 or + not all(isinstance(k, Matrix) for k in keys) or + not all(k.dimensions() == (4, self._Nb) for k in keys) or not all(k.base_ring().is_finite() and k.base_ring().is_field() - and k.base_ring().order() == 256 for k in keys) ): + and k.base_ring().order() == 256 for k in keys)): msg = ("keys must be a length {0} array of 4 by {1} matrices" " over {2}") raise TypeError(msg.format(self._Nr, self._Nb, self._F)) @@ -1500,9 +1506,9 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): ``Round_Component_Poly_Constr`` object corresponding to the composition of multiple round functions as such:: - sage: fn = rgf.compose(rgf.shift_rows_poly_constr(), - ....: rgf.mix_columns_poly_constr()) - sage: fn(1, 3) + sage: fn = rgf.compose(rgf.shift_rows_poly_constr(), # needs sage.libs.gap + ....: rgf.mix_columns_poly_constr()) + sage: fn(1, 3) # needs sage.libs.gap a03 + x*a10 + (x + 1)*a21 + a32 If we use ``compose`` to make a new ``Round_Component_Poly_Constr`` @@ -1510,7 +1516,7 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): ``compose``:: sage: state = rgf._hex_to_GF('36400926f9336d2d9fb59d23c42c3950') - sage: result = rgf.apply_poly(state, fn) + sage: result = rgf.apply_poly(state, fn) # needs sage.libs.gap sage: rgf._GF_to_hex(result) 'f4bcd45432e554d075f1d6c51dd03b3c' <BLANKLINE> @@ -1521,7 +1527,7 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): :: - sage: fn2 = rgf.compose(rgf.sub_bytes_poly_constr(), fn) + sage: fn2 = rgf.compose(rgf.sub_bytes_poly_constr(), fn) # needs sage.libs.gap If the second argument is a polynomial, then the value of ``algorithm`` is passed directly to the first argument `f` during evaluation. @@ -1529,29 +1535,30 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): object, changing ``algorithm`` does nothing since the returned object has its own ``algorithm='encrypt'`` keyword. :: - sage: f = rgf.compose(rgf.sub_bytes_poly_constr(), - ....: rgf.mix_columns_poly_constr(), algorithm='decrypt') - sage: g = rgf.compose(rgf.sub_bytes_poly_constr(), - ....: rgf.mix_columns_poly_constr()) - sage: all(f(i,j) == g(i,j) for i in range(4) for j in range(4)) + sage: f = rgf.compose(rgf.sub_bytes_poly_constr(), # needs sage.libs.gap + ....: rgf.mix_columns_poly_constr(), + ....: algorithm='decrypt') + sage: g = rgf.compose(rgf.sub_bytes_poly_constr(), # needs sage.libs.gap + ....: rgf.mix_columns_poly_constr()) + sage: all(f(i,j) == g(i,j) for i in range(4) for j in range(4)) # needs sage.libs.gap True We can change the keyword attributes of the ``__call__`` methods of ``f`` and ``g`` by passing dictionaries ``f_attr`` and ``g_attr`` to ``compose``. :: - sage: fn = rgf.compose(rgf.add_round_key_poly_constr(), - ....: rgf.add_round_key_poly_constr(), - ....: f_attr={'round' : 4}, g_attr={'round' : 7}) - sage: fn(1, 2) + sage: fn = rgf.compose(rgf.add_round_key_poly_constr(), # needs sage.libs.gap + ....: rgf.add_round_key_poly_constr(), + ....: f_attr={'round': 4}, g_attr={'round': 7}) + sage: fn(1, 2) # needs sage.libs.gap a12 + k412 + k712 """ if not isinstance(f, RijndaelGF.Round_Component_Poly_Constr): msg = "keyword 'f' must be a Round_Component_Poly_Constr" raise TypeError(msg) - from sage.rings.polynomial.multi_polynomial import is_MPolynomial + from sage.rings.polynomial.multi_polynomial import MPolynomial if not isinstance(g, RijndaelGF.Round_Component_Poly_Constr) and \ - not is_MPolynomial(g): + not isinstance(g, MPolynomial): msg = ("keyword 'g' must be a Round_Component_Poly_Constr or a " "polynomial over {0}") raise TypeError(msg.format(self._F)) @@ -1573,10 +1580,10 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): return g(f_vals + self.subkey_vrs_list) else: if isinstance(g_attr, dict): - lm = lambda i, j, alg='encrypt' : \ + lm = lambda i, j, alg='encrypt': \ self.compose(f, g(i, j, alg, **g_attr), alg, f_attr, g_attr) else: - lm = lambda i, j, alg='encrypt' : \ + lm = lambda i, j, alg='encrypt': \ self.compose(f, g(i, j, alg), alg, f_attr, g_attr) return RijndaelGF.Round_Component_Poly_Constr(lm, self) @@ -1591,7 +1598,8 @@ def add_round_key_poly_constr(self): sage: rgf = RijndaelGF(4, 4) sage: ark_pc = rgf.add_round_key_poly_constr() sage: ark_pc - A polynomial constructor for the function 'Add Round Key' of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + A polynomial constructor for the function 'Add Round Key' of Rijndael-GF + block cipher with block length 4, key length 4, and 10 rounds. sage: ark_pc(0, 1) a01 + k001 @@ -1617,7 +1625,7 @@ def add_round_key_poly_constr(self): value. :: sage: rgf.apply_poly(rgf.state_vrs, ark_pc, - ....: poly_constr_attr={'round' : 6}) + ....: poly_constr_attr={'round': 6}) [a00 + k600 a01 + k601 a02 + k602 a03 + k603] [a10 + k610 a11 + k611 a12 + k612 a13 + k613] [a20 + k620 a21 + k621 a22 + k622 a23 + k623] @@ -1625,9 +1633,9 @@ def add_round_key_poly_constr(self): :: - sage: rcpc = rgf.compose(ark_pc, ark_pc, - ....: f_attr={'round' : 3}, g_attr={'round' : 5}) - sage: rcpc(3, 1) + sage: rcpc = rgf.compose(ark_pc, ark_pc, # needs sage.libs.gap + ....: f_attr={'round': 3}, g_attr={'round': 5}) + sage: rcpc(3, 1) # needs sage.libs.gap a31 + k331 + k531 """ return self._add_round_key_rcpc @@ -1667,10 +1675,8 @@ def _add_round_key_pc(self, row, col, algorithm='encrypt', round=0): As expected, since the encryption and decryption transformations are identical, changing ``algorithm`` has no effect. - sage: with_encrypt = rgf._add_round_key_pc(3, 2, - ....: 'encrypt') - sage: with_decrypt = rgf._add_round_key_pc(3, 2, - ....: 'decrypt') + sage: with_encrypt = rgf._add_round_key_pc(3, 2, 'encrypt') + sage: with_decrypt = rgf._add_round_key_pc(3, 2, 'decrypt') sage: with_encrypt == with_decrypt True """ @@ -1723,9 +1729,9 @@ def sub_bytes_poly_constr(self): sage: from sage.crypto.mq.rijndael_gf import RijndaelGF sage: rgf = RijndaelGF(4, 4) - sage: sb_pc = rgf.sub_bytes_poly_constr() - sage: sb_pc - A polynomial constructor for the function 'SubBytes' of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + sage: sb_pc = rgf.sub_bytes_poly_constr(); sb_pc + A polynomial constructor for the function 'SubBytes' of Rijndael-GF + block cipher with block length 4, key length 4, and 10 rounds. sage: sb_pc(2, 3) (x^2 + 1)*a23^254 + (x^3 + 1)*a23^253 + @@ -1773,17 +1779,17 @@ def sub_bytes_poly_constr(self): When passing the returned object to ``apply_poly`` and ``compose``, we can make those methods change the keyword ``no_inversion`` of this object's ``__call__`` method by passing the dictionary - ``{'no_inversion' : True}`` to them. :: + ``{'no_inversion': True}`` to them. :: sage: result = rgf.apply_poly(state, sb_pc, - ....: poly_constr_attr={'no_inversion' : True}) + ....: poly_constr_attr={'no_inversion': True}) sage: rgf._GF_to_hex(result) '961c72894526f746aa85fc920adcc719' :: - sage: rcpc = rgf.compose(sb_pc, rgf.shift_rows_poly_constr(), - ....: f_attr={'no_inversion' : True}) + sage: rcpc = rgf.compose(sb_pc, rgf.shift_rows_poly_constr(), # needs sage.libs.gap + ....: f_attr={'no_inversion': True}) Note that if we set ``algorithm='decrypt'`` for ``apply_poly``, it will perform the necessary performance enhancement described above @@ -1848,7 +1854,7 @@ def _sub_bytes_pc(self, row, col, algorithm='encrypt', no_inversion=False): calculated. :: sage: poly = rgf._sub_bytes_pc(0, 0, - ....: algorithm='decrypt', no_inversion=True) + ....: algorithm='decrypt', no_inversion=True) sage: state = rgf._hex_to_GF('b415f8016858552e4bb6124c5f998a4c') sage: poly(state.list()) ^ -1 x^7 + x^6 + x^2 + x @@ -1865,8 +1871,8 @@ def _sub_bytes_pc(self, row, col, algorithm='encrypt', no_inversion=False): elif algorithm == 'decrypt': var = self.state_vrs[row, col] coeffs = self._sb_D_coeffs - result = (sum([coeffs[i] * var**(2**i) for i in range(8)]) + \ - self._F("x^2 + 1")) + result = (sum([coeffs[i] * var**(2**i) for i in range(8)]) + + self._F("x^2 + 1")) if no_inversion: return result else: @@ -1956,7 +1962,8 @@ def mix_columns_poly_constr(self): sage: rgf = RijndaelGF(4, 4) sage: mc_pc = rgf.mix_columns_poly_constr() sage: mc_pc - A polynomial constructor for the function 'Mix Columns' of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + A polynomial constructor for the function 'Mix Columns' of Rijndael-GF + block cipher with block length 4, key length 4, and 10 rounds. sage: mc_pc(1, 2) a02 + x*a12 + (x + 1)*a22 + a32 sage: mc_pc(1, 0, algorithm='decrypt') @@ -2181,13 +2188,14 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): EXAMPLES:: - sage: from sage.crypto.mq.rijndael_gf import \ - ....: RijndaelGF + sage: from sage.crypto.mq.rijndael_gf import RijndaelGF sage: rgf = RijndaelGF(4, 4) sage: rcpc = RijndaelGF.Round_Component_Poly_Constr( - ....: rgf._shift_rows_pc, rgf, "Shift Rows") + ....: rgf._shift_rows_pc, rgf, "Shift Rows") sage: rcpc - A polynomial constructor for the function 'Shift Rows' of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + A polynomial constructor for the function 'Shift Rows' of + Rijndael-GF block cipher with block length 4, key length 4, + and 10 rounds. If `\phi` is the round component function to which this object corresponds to, then ``__call__(i,j)`` `= \phi(A)_{i,j}`, where @@ -2195,7 +2203,7 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): by ``__call__(i,j)`` will be in terms of the entries of `A`. :: sage: rcpc = RijndaelGF.Round_Component_Poly_Constr( - ....: rgf._mix_columns_pc, rgf, "Mix Columns") + ....: rgf._mix_columns_pc, rgf, "Mix Columns") sage: poly = rcpc(1, 2); poly a02 + x*a12 + (x + 1)*a22 + a32 sage: state = rgf._hex_to_GF('d1876c0f79c4300ab45594add66ff41f') @@ -2210,7 +2218,7 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): ``Round_Component_Poly_Constr`` object will act similarly. :: sage: all(rgf._mix_columns_pc(i, j) == rcpc(i, j) - ....: for i in range(4) for j in range(4)) + ....: for i in range(4) for j in range(4)) True Since all keyword arguments of ``polynomial_constr`` must have a @@ -2225,8 +2233,8 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): ``compose``. :: sage: rgf.apply_poly(rgf.state_vrs, - ....: rgf.add_round_key_poly_constr(), - ....: poly_constr_attr={'round' : 9}) + ....: rgf.add_round_key_poly_constr(), + ....: poly_constr_attr={'round': 9}) [a00 + k900 a01 + k901 a02 + k902 a03 + k903] [a10 + k910 a11 + k911 a12 + k912 a13 + k913] [a20 + k920 a21 + k921 a22 + k922 a23 + k923] @@ -2234,10 +2242,10 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): :: - sage: fn = rgf.compose(rgf.add_round_key_poly_constr(), - ....: rgf.add_round_key_poly_constr(), - ....: f_attr={'round' : 3}, g_attr={'round' : 7}) - sage: fn(2, 3) + sage: fn = rgf.compose(rgf.add_round_key_poly_constr(), # needs sage.libs.gap + ....: rgf.add_round_key_poly_constr(), + ....: f_attr={'round': 3}, g_attr={'round': 7}) + sage: fn(2, 3) # needs sage.libs.gap a23 + k323 + k723 Because all ``Round_Component_Poly_Constr`` objects are callable @@ -2246,9 +2254,9 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): keywords, however, must be checked in ``polynomial_constr``. :: sage: def my_poly_constr(row, col, algorithm='encrypt'): - ....: return x * rgf._F.one() # example body with no checks + ....: return x * rgf._F.one() # example body with no checks sage: rcpc = RijndaelGF.Round_Component_Poly_Constr( - ....: my_poly_constr, rgf, "My Poly Constr") + ....: my_poly_constr, rgf, "My Poly Constr") sage: rcpc(-1, 2) Traceback (most recent call last): ... @@ -2304,22 +2312,21 @@ def __call__(self, row, col, algorithm='encrypt', **kwargs): EXAMPLES:: - sage: from sage.crypto.mq.rijndael_gf import \ - ....: RijndaelGF + sage: from sage.crypto.mq.rijndael_gf import RijndaelGF sage: rgf = RijndaelGF(4, 4) sage: rcpc = RijndaelGF.Round_Component_Poly_Constr( - ....: rgf._shift_rows_pc, rgf, "Shift Rows") + ....: rgf._shift_rows_pc, rgf, "Shift Rows") sage: rcpc(1, 2) a13 sage: all(rcpc(i, j) == rgf._shift_rows_pc(i, j) - ....: for i in range(4) for j in range(4)) + ....: for i in range(4) for j in range(4)) True """ if row not in range(4): raise ValueError("keyword 'row' must be in range 0 - 3") if col not in range(self._Nb): msg = "keyword 'col' must be in range 0 - {0}" - raise ValueError(msg.format(self._Nb-1)) + raise ValueError(msg.format(self._Nb - 1)) if algorithm not in ['encrypt', 'decrypt']: msg = ("keyword 'algorithm' must be either 'encrypt' or " "'decrypt'") @@ -2333,15 +2340,17 @@ def __repr__(self): EXAMPLES:: - sage: from sage.crypto.mq.rijndael_gf import \ - ....: RijndaelGF + sage: from sage.crypto.mq.rijndael_gf import RijndaelGF sage: rgf = RijndaelGF(4, 4) sage: RijndaelGF.Round_Component_Poly_Constr( - ....: rgf._shift_rows_pc, rgf, "Shift Rows") - A polynomial constructor for the function 'Shift Rows' of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + ....: rgf._shift_rows_pc, rgf, "Shift Rows") + A polynomial constructor for the function 'Shift Rows' of + Rijndael-GF block cipher with block length 4, key length 4, + and 10 rounds. sage: RijndaelGF.Round_Component_Poly_Constr( - ....: rgf._shift_rows_pc, rgf) - A polynomial constructor of a round component of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + ....: rgf._shift_rows_pc, rgf) + A polynomial constructor of a round component of Rijndael-GF + block cipher with block length 4, key length 4, and 10 rounds. """ if self._rc_name is None: msg = "A polynomial constructor of a round component of {0}" diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index 81ae146e204..091ff4a96fa 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" Small Scale Variants of the AES (SR) Polynomial System Generator @@ -103,8 +104,8 @@ sage: a = K.gen() sage: K = [a] sage: P = [1] - sage: F,s = sr.polynomial_system(P=P, K=K) - sage: F.groebner_basis() + sage: F,s = sr.polynomial_system(P=P, K=K) # needs sage.rings.polynomial.pbori + sage: F.groebner_basis() # needs sage.rings.polynomial.pbori [k100, k101 + 1, k102, k103 + k003, x100 + 1, x101 + k003 + 1, x102 + k003 + 1, x103 + k003, w100, w101, w102 + 1, w103 + k003 + 1, @@ -123,8 +124,8 @@ All solutions can easily be recovered using the variety function for ideals.:: - sage: I = F.ideal() - sage: for V in I.variety(): + sage: I = F.ideal() # needs sage.rings.polynomial.pbori + sage: for V in I.variety(): # needs sage.rings.polynomial.pbori sage.symbolic ....: for k,v in sorted(V.items()): ....: print("{} {}".format(k, v)) ....: print("\n") @@ -173,7 +174,7 @@ We can also verify the correctness of the variety by evaluating all ideal generators on all points.:: - sage: for V in I.variety(): + sage: for V in I.variety(): # needs sage.rings.polynomial.pbori sage.symbolic ....: for f in I.gens(): ....: if f.subs(V) != 0: ....: print("epic fail") @@ -206,7 +207,7 @@ or use ``S`` to find alternative polynomial representations for the S-Box.:: - sage: S.polynomials(degree=3) + sage: S.polynomials(degree=3) # needs sage.libs.singular [x0*x1 + x1*x2 + x0*x3 + x0*y2 + x1 + y0 + y1 + 1, x0*x1 + x0*x2 + x0*y0 + x0*y1 + x0*y2 + x1 + x2 + y0 + y1 + y2, x0*x1 + x0*x2 + x0*x3 + x1*x3 + x0*y0 + x1*y0 + x0*y1 + x0*y3, @@ -665,7 +666,7 @@ def __ne__(self, other): sage: sr1 != sr2 True """ - return not(self == other) + return not (self == other) def sub_bytes(self, d): r""" @@ -876,11 +877,11 @@ def sbox(self, inversion_only=False): if not inversion_only: with AllowZeroInversionsContext(self): S = [self.sub_byte(elem) for elem in sorted(k)] - return SBox(S) + return SBox(S) else: e = self.e S = [elem ** (2**e - 2) for elem in sorted(k)] - return SBox(S) + return SBox(S) def shift_rows(self, d): r""" @@ -963,7 +964,6 @@ def mix_columns(self, d): # AES uses the column major ordering return Matrix(k, d.ncols(), d.nrows(), ret).transpose() - def add_round_key(self, d, key): r""" Perform the ``AddRoundKey`` operation on @@ -1092,7 +1092,7 @@ def random_vector(self, *args, **kwds): """ return self.vector(self.random_state_array(*args, **kwds)) - def random_element(self, elem_type = "vector", *args, **kwds): + def random_element(self, elem_type="vector", *args, **kwds): """ Return a random element for self. Other arguments and keywords are passed to random_* methods. @@ -1509,7 +1509,6 @@ def _insert_matrix_into_matrix(self, dst, src, row, col): dst[row+i, col+j] = src[i, j] return dst - def varformatstr(self, name, n=None, rc=None, e=None): r""" Return a format string which is understood by print et al. @@ -1571,7 +1570,7 @@ def varstr(self, name, nr, rc, e): format_string = self.varformatstr(name, self.n, self.r*self.c, self.e) return format_string % (nr, rc, e) - def varstrs(self, name, nr, rc = None, e = None): + def varstrs(self, name, nr, rc=None, e=None): """ Return a list of strings representing variables in ``self``. @@ -1653,7 +1652,7 @@ def variable_dict(self): 'x103': x103} sage: sr = mq.SR(1,1,1,4,gf2=True) - sage: sr.variable_dict() + sage: sr.variable_dict() # needs sage.rings.polynomial.pbori {'k000': k000, 'k001': k001, 'k002': k002, @@ -1799,7 +1798,6 @@ def ring(self, order=None, reverse_variables=None): else: names = self.varstrs("k", 0, r*c, e) - for _n in process(list(range(n))): names += self.varstrs("k", _n+1, r*c, e) names += self.varstrs("x", _n+1, r*c, e) @@ -1807,7 +1805,7 @@ def ring(self, order=None, reverse_variables=None): names += self.varstrs("s", _n, r, e) if reverse_variables: - names += self.varstrs("k", 0, r*c, e) + names += self.varstrs("k", 0, r*c, e) #from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing @@ -1880,7 +1878,6 @@ def round_polynomials(self, i, plaintext=None, ciphertext=None): lin = (wj + ki + M * xj + rcon).list() - wi = Matrix(R, r*c*e, 1, _vars("w", i, r*c, e)) xi = Matrix(R, r*c*e, 1, _vars("x", i, r*c, e)) sbox = [] @@ -1974,7 +1971,7 @@ def key_schedule_polynomials(self, i): sbox += self.inversion_polynomials( kj[(4*c-3)*e : (4*c-3)*e + e] , si[2*e : 3*e] , e ) sbox += self.inversion_polynomials( kj[(4*c-4)*e : (4*c-4)*e + e] , si[3*e : 4*e] , e ) - si = L * si + d + rc + si = L * si + d + rc Sum = Matrix(R, r*e, 1) lin = [] if c > 1: @@ -2007,16 +2004,16 @@ def polynomial_system(self, P=None, K=None, C=None): sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) sage: P = sr.vector([0, 0, 1, 0]) sage: K = sr.vector([1, 0, 0, 1]) - sage: F, s = sr.polynomial_system(P, K) + sage: F, s = sr.polynomial_system(P, K) # needs sage.rings.polynomial.pbori This returns a polynomial system:: - sage: F + sage: F # needs sage.rings.polynomial.pbori Polynomial Sequence with 36 Polynomials in 20 Variables and a solution:: - sage: s # random -- maybe we need a better doctest here? + sage: s # random -- maybe we need a better doctest here? # needs sage.rings.polynomial.pbori {k000: 1, k001: 0, k003: 1, k002: 0} This solution is not the only solution that we can learn from the @@ -2024,24 +2021,25 @@ def polynomial_system(self, P=None, K=None, C=None): :: - sage: F.groebner_basis()[-3:] + sage: F.groebner_basis()[-3:] # needs sage.rings.polynomial.pbori [k000 + 1, k001, k003 + 1] In particular we have two solutions:: - sage: len(F.ideal().variety()) + sage: len(F.ideal().variety()) # needs sage.rings.polynomial.pbori 2 In the following example we provide ``C`` explicitly:: sage: C = sr(P,K) - sage: F,s = sr.polynomial_system(P=P, C=C) - sage: F + sage: F,s = sr.polynomial_system(P=P, C=C) # needs sage.rings.polynomial.pbori + sage: F # needs sage.rings.polynomial.pbori Polynomial Sequence with 36 Polynomials in 20 Variables Alternatively, we can use symbols for the ``P`` and ``C``. First, we have to create a polynomial ring:: + sage: # needs sage.rings.polynomial.pbori sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) sage: R = sr.R sage: vn = sr.varstrs("P",0,1,4) + R.variable_names() + sr.varstrs("C",0,1,4) @@ -2051,6 +2049,7 @@ def polynomial_system(self, P=None, K=None, C=None): Now, we can construct the purely symbolic equation system:: + sage: # needs sage.rings.polynomial.pbori sage: C = sr.vars("C",0); C (C000, C001, C002, C003) sage: P = sr.vars("P",0) @@ -2065,13 +2064,13 @@ def polynomial_system(self, P=None, K=None, C=None): We show that the (returned) key is a solution to the returned system:: sage: sr = mq.SR(3,4,4,8, star=True, gf2=True, polybori=True) - sage: while True: # workaround (see :trac:`31891`) + sage: while True: # workaround (see :trac:`31891`) # needs sage.rings.polynomial.pbori ....: try: ....: F, s = sr.polynomial_system() ....: break ....: except ZeroDivisionError: ....: pass - sage: F.subs(s).groebner_basis() # long time + sage: F.subs(s).groebner_basis() # long time # needs sage.rings.polynomial.pbori Polynomial Sequence with 1248 Polynomials in 1248 Variables """ plaintext = P @@ -2288,7 +2287,7 @@ def shift_rows_matrix(self): return shift_rows - def lin_matrix(self, length = None): + def lin_matrix(self, length=None): """ Return the ``Lin`` matrix. @@ -2592,7 +2591,7 @@ def phi(self, l, diffusion_matrix=False): sage: sr = mq.SR(2, 1, 2, 4, gf2=True) sage: k = sr.base_ring() sage: A = matrix(k, 1, 2, [k.gen(), 0] ) - sage: sr.phi(A) + sage: sr.phi(A) # needs sage.libs.gap [0 0] [0 0] [1 0] @@ -2646,7 +2645,7 @@ def antiphi(self, l): sage: sr = mq.SR(gf2=True) sage: A = sr.random_state_array() - sage: sr.antiphi(sr.phi(A)) == A + sage: sr.antiphi(sr.phi(A)) == A # needs sage.libs.gap True """ e = self.e @@ -2713,8 +2712,6 @@ def mix_columns_matrix(self): k = self.k a = k.gen() - - if r == 1: M = Matrix(k, r, r, 1) @@ -2722,9 +2719,9 @@ def mix_columns_matrix(self): M = Matrix(k, r, r, [a+1, a, a, a+1]) elif r == 4: - M = Matrix(k, r, [a, a+1, 1, 1, \ - 1, a, a+1, 1, \ - 1, 1, a, a+1, \ + M = Matrix(k, r, [a, a+1, 1, 1, + 1, a, a+1, 1, + 1, 1, a, a+1, a+1, 1, 1, a]) mix_columns = Matrix(k, r*c, r*c) @@ -2763,21 +2760,20 @@ def lin_matrix(self, length=None): length = r*c if e == 8: - Z = Matrix(GF(2), 8, 8, [1, 0, 0, 0, 1, 1, 1, 1, \ - 1, 1, 0, 0, 0, 1, 1, 1, \ - 1, 1, 1, 0, 0, 0, 1, 1, \ - 1, 1, 1, 1, 0, 0, 0, 1, \ - 1, 1, 1, 1, 1, 0, 0, 0, \ - 0, 1, 1, 1, 1, 1, 0, 0, \ - 0, 0, 1, 1, 1, 1, 1, 0, \ + Z = Matrix(GF(2), 8, 8, [1, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1]) else: - Z = Matrix(GF(2), 4, 4, [1, 1, 1, 0, \ - 0, 1, 1, 1, \ - 1, 0, 1, 1, \ + Z = Matrix(GF(2), 4, 4, [1, 1, 1, 0, + 0, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 0, 1]) - Z = Z.transpose() # account for endianess mismatch lin = Matrix(GF(2), length*e, length*e) @@ -2970,36 +2966,36 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, w7*x6 + w7*x4 + w7*x3 + w6*x7 + w6*x5 + w6*x4 + w6*x0 + w5*x6 + w5*x5 + w5*x1 + w4*x7 + w4*x6 + w4*x2 + w3*x7 + w3*x3 + w2*x4 + w1*x5 + w0*x6, w7*x5 + w7*x3 + w7*x2 + w6*x6 + w6*x4 + w6*x3 + w5*x7 + w5*x5 + w5*x4 + w5*x0 + w4*x6 + w4*x5 + w4*x1 + w3*x7 + w3*x6 + w3*x2 + w2*x7 + w2*x3 + w1*x4 + w0*x5, w7*x7 + w7*x4 + w7*x2 + w7*x1 + w6*x5 + w6*x3 + w6*x2 + w5*x6 + w5*x4 + w5*x3 + w4*x7 + w4*x5 + w4*x4 + w4*x0 + w3*x6 + w3*x5 + w3*x1 + w2*x7 + w2*x6 + w2*x2 + w1*x7 + w1*x3 + w0*x4, - w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w4*x7 + w4*x6 + w4*x4 + w3*x7 + w3*x5 + w3*x0 + w2*x6 + w2*x1 \ + w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w4*x7 + w4*x6 + w4*x4 + w3*x7 + w3*x5 + w3*x0 + w2*x6 + w2*x1 + w1*x7 + w1*x2 + w0*x3, w7*x6 + w7*x3 + w7*x2 + w6*x7 + w6*x4 + w6*x3 + w5*x5 + w5*x4 + w4*x6 + w4*x5 + w3*x7 + w3*x6 + w2*x7 + w2*x0 + w1*x1 + w0*x2, w7*x7 + w7*x5 + w7*x2 + w7*x1 + w6*x6 + w6*x3 + w6*x2 + w5*x7 + w5*x4 + w5*x3 + w4*x5 + w4*x4 + w3*x6 + w3*x5 + w2*x7 + w2*x6 + w1*x7 + w1*x0 + w0*x1, w7*x6 + w7*x5 + w7*x2 + w7*x0 + w6*x7 + w6*x4 + w6*x3 + w5*x7 + w5*x6 + w5*x3 + w5*x1 + w4*x5 + w4*x4 + w3*x7 + w3*x4 + w3*x2 + w2*x6 + w2*x5 + w1*x5 + w1*x3 + w0*x7 + w0*x6 + x7, - w7*x6 + w7*x3 + w7*x2 + w6*x6 + w6*x5 + w6*x2 + w6*x0 + w5*x7 + w5*x4 + w5*x3 + w4*x7 + w4*x6 + w4*x3 + w4*x1 + w3*x5 + w3*x4 + w2*x7 + w2*x4 + w2*x2 + w1*x6 + w1*x5 + w0*x5 + w0*x3 \ + w7*x6 + w7*x3 + w7*x2 + w6*x6 + w6*x5 + w6*x2 + w6*x0 + w5*x7 + w5*x4 + w5*x3 + w4*x7 + w4*x6 + w4*x3 + w4*x1 + w3*x5 + w3*x4 + w2*x7 + w2*x4 + w2*x2 + w1*x6 + w1*x5 + w0*x5 + w0*x3 + x6, - w7*x7 + w7*x5 + w7*x4 + w7*x1 + w6*x6 + w6*x3 + w6*x2 + w5*x6 + w5*x5 + w5*x2 + w5*x0 + w4*x7 + w4*x4 + w4*x3 + w3*x7 + w3*x6 + w3*x3 + w3*x1 + w2*x5 + w2*x4 + w1*x7 + w1*x4 + w1*x2 \ + w7*x7 + w7*x5 + w7*x4 + w7*x1 + w6*x6 + w6*x3 + w6*x2 + w5*x6 + w5*x5 + w5*x2 + w5*x0 + w4*x7 + w4*x4 + w4*x3 + w3*x7 + w3*x6 + w3*x3 + w3*x1 + w2*x5 + w2*x4 + w1*x7 + w1*x4 + w1*x2 + w0*x6 + w0*x5 + x5, - w7*x7 + w7*x5 + w7*x2 + w7*x1 + w6*x7 + w6*x5 + w6*x4 + w6*x1 + w5*x6 + w5*x3 + w5*x2 + w4*x6 + w4*x5 + w4*x2 + w4*x0 + w3*x7 + w3*x4 + w3*x3 + w2*x7 + w2*x6 + w2*x3 + w2*x1 + w1*x5 \ + w7*x7 + w7*x5 + w7*x2 + w7*x1 + w6*x7 + w6*x5 + w6*x4 + w6*x1 + w5*x6 + w5*x3 + w5*x2 + w4*x6 + w4*x5 + w4*x2 + w4*x0 + w3*x7 + w3*x4 + w3*x3 + w2*x7 + w2*x6 + w2*x3 + w2*x1 + w1*x5 + w1*x4 + w0*x7 + w0*x4 + w0*x2 + x4, - w7*x5 + w7*x4 + w7*x3 + w7*x2 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w4*x6 + w4*x5 + w4*x4 + w4*x3 + w4*x2 + w3*x7 + w3*x6 + w3*x5 + w3*x4 + w3*x0 \ + w7*x5 + w7*x4 + w7*x3 + w7*x2 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w4*x6 + w4*x5 + w4*x4 + w4*x3 + w4*x2 + w3*x7 + w3*x6 + w3*x5 + w3*x4 + w3*x0 + w2*x7 + w2*x6 + w2*x5 + w2*x4 + w2*x3 + w1*x7 + w1*x6 + w1*x5 + w1*x1 + w0*x7 + w0*x6 + w0*x5 + w0*x4 + x3, - w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x7 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x6 + w4*x3 + w3*x7 + w3*x6 + w3*x5 + w3*x3 + w2*x7 + w2*x4 + w2*x0 \ + w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x7 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x6 + w4*x3 + w3*x7 + w3*x6 + w3*x5 + w3*x3 + w2*x7 + w2*x4 + w2*x0 + w1*x7 + w1*x6 + w1*x4 + w0*x5 + w0*x1 + x2, - w7*x6 + w7*x4 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x7 + w5*x5 + w5*x2 + w4*x7 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w3*x6 + w3*x3 + w2*x7 + w2*x6 + w2*x5 + w2*x3 \ + w7*x6 + w7*x4 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x7 + w5*x5 + w5*x2 + w4*x7 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w3*x6 + w3*x3 + w2*x7 + w2*x6 + w2*x5 + w2*x3 + w1*x7 + w1*x4 + w1*x0 + w0*x7 + w0*x6 + w0*x4 + x1, w7*x7 + w7*x4 + w7*x3 + w6*x7 + w6*x6 + w6*x3 + w6*x1 + w5*x5 + w5*x4 + w4*x7 + w4*x4 + w4*x2 + w3*x6 + w3*x5 + w2*x5 + w2*x3 + w1*x7 + w1*x6 + w0*x6 + w0*x4 + w0*x0 + x0, w7*x6 + w7*x5 + w7*x3 + w7*x0 + w7 + w6*x7 + w6*x5 + w6*x2 + w6*x0 + w5*x7 + w5*x4 + w5*x2 + w5*x1 + w4*x6 + w4*x4 + w4*x3 + w3*x6 + w3*x5 + w3*x1 + w2*x7 + w2*x3 + w1*x5 + w0*x7, - w7*x5 + w7*x4 + w7*x2 + w6*x7 + w6*x6 + w6*x4 + w6*x1 + w6 + w5*x6 + w5*x3 + w5*x1 + w5*x0 + w4*x5 + w4*x3 + w4*x2 + w3*x7 + w3*x5 + w3*x4 + w3*x0 + w2*x7 + w2*x6 + w2*x2 + w1*x4 \ + w7*x5 + w7*x4 + w7*x2 + w6*x7 + w6*x6 + w6*x4 + w6*x1 + w6 + w5*x6 + w5*x3 + w5*x1 + w5*x0 + w4*x5 + w4*x3 + w4*x2 + w3*x7 + w3*x5 + w3*x4 + w3*x0 + w2*x7 + w2*x6 + w2*x2 + w1*x4 + w0*x6, - w7*x7 + w7*x4 + w7*x3 + w7*x1 + w6*x6 + w6*x5 + w6*x3 + w6*x0 + w5*x7 + w5*x5 + w5*x2 + w5*x0 + w5 + w4*x7 + w4*x4 + w4*x2 + w4*x1 + w3*x6 + w3*x4 + w3*x3 + w2*x6 + w2*x5 + w2*x1 \ + w7*x7 + w7*x4 + w7*x3 + w7*x1 + w6*x6 + w6*x5 + w6*x3 + w6*x0 + w5*x7 + w5*x5 + w5*x2 + w5*x0 + w5 + w4*x7 + w4*x4 + w4*x2 + w4*x1 + w3*x6 + w3*x4 + w3*x3 + w2*x6 + w2*x5 + w2*x1 + w1*x7 + w1*x3 + w0*x5, - w7*x7 + w7*x6 + w7*x3 + w7*x2 + w7*x0 + w6*x5 + w6*x4 + w6*x2 + w5*x7 + w5*x6 + w5*x4 + w5*x1 + w4*x6 + w4*x3 + w4*x1 + w4*x0 + w4 + w3*x5 + w3*x3 + w3*x2 + w2*x7 + w2*x5 + w2*x4 \ + w7*x7 + w7*x6 + w7*x3 + w7*x2 + w7*x0 + w6*x5 + w6*x4 + w6*x2 + w5*x7 + w5*x6 + w5*x4 + w5*x1 + w4*x6 + w4*x3 + w4*x1 + w4*x0 + w4 + w3*x5 + w3*x3 + w3*x2 + w2*x7 + w2*x5 + w2*x4 + w2*x0 + w1*x7 + w1*x6 + w1*x2 + w0*x4, - w7*x3 + w7*x2 + w7*x1 + w7*x0 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w6*x0 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x2 + w5*x1 + w5*x0 + w4*x7 + w4*x6 + w4*x5 + w4*x4 \ + w7*x3 + w7*x2 + w7*x1 + w7*x0 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w6*x0 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x2 + w5*x1 + w5*x0 + w4*x7 + w4*x6 + w4*x5 + w4*x4 + w4*x3 + w4*x2 + w4*x0 + w3*x7 + w3*x6 + w3*x5 + w3*x4 + w3*x2 + w3 + w2*x7 + w2*x6 + w2*x4 + w1*x6 + w1*x1 + w0*x3, - w7*x7 + w7*x6 + w7*x5 + w7*x3 + w7*x2 + w7*x1 + w6*x7 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w5*x0 + w4*x7 + w4*x5 + w4*x2 + w4*x1 + w3*x7 + w3*x4 \ + w7*x7 + w7*x6 + w7*x5 + w7*x3 + w7*x2 + w7*x1 + w6*x7 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w5*x0 + w4*x7 + w4*x5 + w4*x2 + w4*x1 + w3*x7 + w3*x4 + w3*x3 + w2*x6 + w2*x5 + w2 + w1*x7 + w1*x0 + w0*x2, - w7*x6 + w7*x5 + w7*x4 + w7*x2 + w7*x1 + w7*x0 + w6*x7 + w6*x6 + w6*x4 + w6*x3 + w6*x2 + w6*x0 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x7 + w4*x6 + w4*x4 + w4*x1 + w4*x0 + w3*x6 \ + w7*x6 + w7*x5 + w7*x4 + w7*x2 + w7*x1 + w7*x0 + w6*x7 + w6*x6 + w6*x4 + w6*x3 + w6*x2 + w6*x0 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x7 + w4*x6 + w4*x4 + w4*x1 + w4*x0 + w3*x6 + w3*x3 + w3*x2 + w2*x5 + w2*x4 + w1*x7 + w1*x6 + w1 + w0*x1, w7*x7 + w7*x6 + w7*x4 + w7*x1 + w6*x6 + w6*x3 + w6*x1 + w6*x0 + w5*x5 + w5*x3 + w5*x2 + w4*x7 + w4*x5 + w4*x4 + w4*x0 + w3*x7 + w3*x6 + w3*x2 + w2*x4 + w1*x6 + w0*x0 + w0] @@ -3007,58 +3003,58 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, l.append(w7*x6 + w7*x5 + w7*x1 + w6*x7 + w6*x6 + w6*x2 + w5*x7 + w5*x3 + w4*x4 + w3*x5 + w2*x6 + w1*x7 + w0*x0 + 1) if not biaffine_only: - l.extend([w7**2 + w7*w6 + w7*w3 + w7*w1 + w7*x7 + w7*x6 + w7*x5 + w7*x2 + w7*x1 + w7*x0 + w6**2 + w6*w0 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w6*x0 + w5**2 + w5*w4 + w5*w3 \ - + w5*w2 + w5*x7 + w5*x5 + w5*x4 + w5*x1 + w5*x0 + w4**2 + w4*w2 + w4*w0 + w4*x5 + w4*x4 + w4*x2 + w3*w2 + w3*x6 + w3*x3 + w3*x1 + w3*x0 + w2*x7 + w2*x5 + w2*x4 \ + l.extend([w7**2 + w7*w6 + w7*w3 + w7*w1 + w7*x7 + w7*x6 + w7*x5 + w7*x2 + w7*x1 + w7*x0 + w6**2 + w6*w0 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w6*x0 + w5**2 + w5*w4 + w5*w3 + + w5*w2 + w5*x7 + w5*x5 + w5*x4 + w5*x1 + w5*x0 + w4**2 + w4*w2 + w4*w0 + w4*x5 + w4*x4 + w4*x2 + w3*w2 + w3*x6 + w3*x3 + w3*x1 + w3*x0 + w2*x7 + w2*x5 + w2*x4 + w2*x0 + w1*x4 + w0**2 + w0*x0, - w7*x6 + w7*x4 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w4*x5 + w4*x4 + w4*x3 + w4*x1 + w4*x0 + w3*x7 + w3*x5 + w3*x2 \ - + w2*x7 + w2*x6 + w2*x3 + w1*x7 + w1*x6 + w1*x5 + w1*x4 + w1*x2 + w0*x6 + w0*x5 + w0*x4 + w0*x2 + w0*x1 + x7**2 + x7*x6 + x7*x5 + x7*x3 + x7*x1 + x7*x0 + x6*x2 \ + w7*x6 + w7*x4 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w4*x5 + w4*x4 + w4*x3 + w4*x1 + w4*x0 + w3*x7 + w3*x5 + w3*x2 + + w2*x7 + w2*x6 + w2*x3 + w1*x7 + w1*x6 + w1*x5 + w1*x4 + w1*x2 + w0*x6 + w0*x5 + w0*x4 + w0*x2 + w0*x1 + x7**2 + x7*x6 + x7*x5 + x7*x3 + x7*x1 + x7*x0 + x6*x2 + x6*x1 + x5*x4 + x5*x3 + x5*x2 + x5*x1 + x4*x3 + x4*x2 + x4*x1 + x3**2 + x3*x2 + x2*x1 + x2*x0, - w7*x5 + w7*x4 + w7*x3 + w7*x1 + w7*x0 + w6*x7 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x3 + w4*x7 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w3*x6 + w3*x5 + w3*x4 + w3*x2 + w3*x1 \ - + w2*x6 + w2*x3 + w1*x7 + w1*x4 + w0*x7 + w0*x6 + w0*x5 + w0*x3 + x7*x3 + x7*x2 + x6*x5 + x6*x4 + x6*x3 + x6*x2 + x6*x0 + x5*x4 + x5*x3 + x5*x2 + x4**2 + x4*x3 \ + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w7*x0 + w6*x7 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x3 + w4*x7 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w3*x6 + w3*x5 + w3*x4 + w3*x2 + w3*x1 + + w2*x6 + w2*x3 + w1*x7 + w1*x4 + w0*x7 + w0*x6 + w0*x5 + w0*x3 + x7*x3 + x7*x2 + x6*x5 + x6*x4 + x6*x3 + x6*x2 + x6*x0 + x5*x4 + x5*x3 + x5*x2 + x4**2 + x4*x3 + x3*x2 + x3*x1, - w7*w3 + w7*w2 + w7*x6 + w7*x5 + w7*x4 + w7*x1 + w7*x0 + w6*w5 + w6*w4 + w6*w3 + w6*w2 + w6*w0 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x0 + w5*w4 + w5*w3 + w5*w2 + w5*x7 \ - + w5*x6 + w5*x4 + w5*x3 + w5*x0 + w4**2 + w4*w3 + w4*x7 + w4*x4 + w4*x3 + w4*x1 + w3*w2 + w3*w1 + w3*x7 + w3*x5 + w3*x2 + w3*x0 + w2*x6 + w2*x4 + w2*x3 + w1*x7 \ + w7*w3 + w7*w2 + w7*x6 + w7*x5 + w7*x4 + w7*x1 + w7*x0 + w6*w5 + w6*w4 + w6*w3 + w6*w2 + w6*w0 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x0 + w5*w4 + w5*w3 + w5*w2 + w5*x7 + + w5*x6 + w5*x4 + w5*x3 + w5*x0 + w4**2 + w4*w3 + w4*x7 + w4*x4 + w4*x3 + w4*x1 + w3*w2 + w3*w1 + w3*x7 + w3*x5 + w3*x2 + w3*x0 + w2*x6 + w2*x4 + w2*x3 + w1*x7 + w1*x3 + w0*x7, - w7*x5 + w7*x2 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x2 + w6*x1 + w5*x5 + w5*x3 + w5*x2 + w4*x3 + w4*x2 + w4*x1 + w3*x6 + w3*x3 + w3*x2 + w3*x0 + w2*x7 + w2*x6 \ - + w2*x5 + w2*x3 + w2*x2 + w1*x6 + w1*x4 + w1*x3 + w0*x4 + w0*x3 + w0*x2 + x7*x5 + x7*x4 + x7*x1 + x7*x0 + x6*x0 + x5**2 + x5*x2 + x5*x1 + x5*x0 + x4**2 + x4*x0 \ + w7*x5 + w7*x2 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x2 + w6*x1 + w5*x5 + w5*x3 + w5*x2 + w4*x3 + w4*x2 + w4*x1 + w3*x6 + w3*x3 + w3*x2 + w3*x0 + w2*x7 + w2*x6 + + w2*x5 + w2*x3 + w2*x2 + w1*x6 + w1*x4 + w1*x3 + w0*x4 + w0*x3 + w0*x2 + x7*x5 + x7*x4 + x7*x1 + x7*x0 + x6*x0 + x5**2 + x5*x2 + x5*x1 + x5*x0 + x4**2 + x4*x0 + x3*x2 + x3*x0 + x1**2, - w7*w6 + w7*w5 + w7*w4 + w7*w3 + w7*x7 + w7*x5 + w7*x4 + w7*x3 + w7*x0 + w6**2 + w6*w5 + w6*w4 + w6*w2 + w6*w1 + w6*w0 + w6*x7 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w5*w4 \ - + w5*w1 + w5*w0 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w5*x2 + w4*w2 + w4*w1 + w4*x7 + w4*x6 + w4*x3 + w4*x2 + w4*x0 + w3*w0 + w3*x7 + w3*x6 + w3*x4 + w3*x1 + w2**2 \ + w7*w6 + w7*w5 + w7*w4 + w7*w3 + w7*x7 + w7*x5 + w7*x4 + w7*x3 + w7*x0 + w6**2 + w6*w5 + w6*w4 + w6*w2 + w6*w1 + w6*w0 + w6*x7 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w5*w4 + + w5*w1 + w5*w0 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w5*x2 + w4*w2 + w4*w1 + w4*x7 + w4*x6 + w4*x3 + w4*x2 + w4*x0 + w3*w0 + w3*x7 + w3*x6 + w3*x4 + w3*x1 + w2**2 + w2*x5 + w2*x3 + w2*x2 + w1*x7 + w1*x6 + w1*x2 + w0*x6, - w7*w5 + w7*w4 + w7*w1 + w7*w0 + w7*x6 + w7*x2 + w6*w0 + w6*x6 + w6*x3 + w6*x2 + w6*x1 + w5**2 + w5*w2 + w5*w1 + w5*w0 + w5*x7 + w5*x6 + w5*x5 + w5*x2 + w4**2 + w4*w0 \ - + w4*x6 + w4*x1 + w4*x0 + w3*w2 + w3*w0 + w3*x5 + w3*x4 + w3*x3 + w3*x2 + w3*x1 + w3*x0 + w2*x7 + w2*x6 + w2*x5 + w2*x4 + w2*x3 + w2*x2 + w2*x0 + w1**2 + w1*x7 \ + w7*w5 + w7*w4 + w7*w1 + w7*w0 + w7*x6 + w7*x2 + w6*w0 + w6*x6 + w6*x3 + w6*x2 + w6*x1 + w5**2 + w5*w2 + w5*w1 + w5*w0 + w5*x7 + w5*x6 + w5*x5 + w5*x2 + w4**2 + w4*w0 + + w4*x6 + w4*x1 + w4*x0 + w3*w2 + w3*w0 + w3*x5 + w3*x4 + w3*x3 + w3*x2 + w3*x1 + w3*x0 + w2*x7 + w2*x6 + w2*x5 + w2*x4 + w2*x3 + w2*x2 + w2*x0 + w1**2 + w1*x7 + w1*x6 + w1*x4 + w0*x3, - w7*x7 + w7*x6 + w7*x5 + w7*x2 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w5*x0 + w4*x7 + w4*x5 + w4*x2 + w3*x7 + w3*x6 + w3*x3 \ - + w2*x7 + w2*x6 + w2*x5 + w2*x4 + w2*x2 + w1*x6 + w1*x5 + w1*x4 + w1*x2 + w1*x1 + w0*x6 + w0*x3 + x7**2 + x7*x5 + x7*x3 + x6**2 + x6*x5 + x6*x2 + x6*x0 + x5**2 \ + w7*x7 + w7*x6 + w7*x5 + w7*x2 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w5*x0 + w4*x7 + w4*x5 + w4*x2 + w3*x7 + w3*x6 + w3*x3 + + w2*x7 + w2*x6 + w2*x5 + w2*x4 + w2*x2 + w1*x6 + w1*x5 + w1*x4 + w1*x2 + w1*x1 + w0*x6 + w0*x3 + x7**2 + x7*x5 + x7*x3 + x6**2 + x6*x5 + x6*x2 + x6*x0 + x5**2 + x4**2 + x4*x3 + x4*x2 + x4*x1 + x3**2 + x3*x1 + x2*x1, - w7**2 + w7*w6 + w7*w5 + w7*w3 + w7*w1 + w7*w0 + w7*x6 + w7*x5 + w7*x3 + w7*x2 + w7*x1 + w6*w2 + w6*w1 + w6*x7 + w6*x6 + w6*x5 + w6*x2 + w6*x1 + w6*x0 + w5*w4 + w5*w3 \ - + w5*w2 + w5*w1 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w5*x0 + w4*w3 + w4*w2 + w4*w1 + w4*x7 + w4*x5 + w4*x4 + w4*x1 + w4*x0 + w3**2 + w3*w2 + w3*x5 + w3*x4 \ + w7**2 + w7*w6 + w7*w5 + w7*w3 + w7*w1 + w7*w0 + w7*x6 + w7*x5 + w7*x3 + w7*x2 + w7*x1 + w6*w2 + w6*w1 + w6*x7 + w6*x6 + w6*x5 + w6*x2 + w6*x1 + w6*x0 + w5*w4 + w5*w3 + + w5*w2 + w5*w1 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w5*x0 + w4*w3 + w4*w2 + w4*w1 + w4*x7 + w4*x5 + w4*x4 + w4*x1 + w4*x0 + w3**2 + w3*w2 + w3*x5 + w3*x4 + w3*x2 + w2*w1 + w2*w0 + w2*x6 + w2*x3 + w2*x1 + w2*x0 + w1*x7 + w1*x5 + w1*x4 + w1*x0 + w0*x4, - w7*x7 + w7*x5 + w7*x2 + w6*x7 + w6*x6 + w6*x3 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w4*x1 + w3*x6 + w3*x3 + w2*x7 + w2*x4 + w1*x7 \ - + w1*x6 + w1*x5 + w1*x3 + w0*x7 + w0*x6 + w0*x5 + w0*x3 + w0*x2 + w0*x0 + x7**2 + x7*x6 + x7*x3 + x7*x1 + x6**2 + x6*x0 + x5**2 + x5*x4 + x5*x3 + x5*x2 + x4**2 \ + w7*x7 + w7*x5 + w7*x2 + w6*x7 + w6*x6 + w6*x3 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w4*x1 + w3*x6 + w3*x3 + w2*x7 + w2*x4 + w1*x7 + + w1*x6 + w1*x5 + w1*x3 + w0*x7 + w0*x6 + w0*x5 + w0*x3 + w0*x2 + w0*x0 + x7**2 + x7*x6 + x7*x3 + x7*x1 + x6**2 + x6*x0 + x5**2 + x5*x4 + x5*x3 + x5*x2 + x4**2 + x4*x2 + x4*x0 + x3*x2 + x0**2, - w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w6*x0 + w5*x7 + w5*x5 + w5*x2 + w4*x7 + w4*x6 + w4*x3 + w3*x7 + w3*x6 + w3*x5 + w3*x4 \ - + w3*x2 + w2*x6 + w2*x5 + w2*x4 + w2*x2 + w2*x1 + w1*x6 + w1*x3 + w0*x7 + w0*x4 + x7*x6 + x7*x5 + x7*x4 + x7*x3 + x6**2 + x6*x5 + x6*x4 + x6*x2 + x6*x1 + x6*x0 \ + w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w6*x0 + w5*x7 + w5*x5 + w5*x2 + w4*x7 + w4*x6 + w4*x3 + w3*x7 + w3*x6 + w3*x5 + w3*x4 + + w3*x2 + w2*x6 + w2*x5 + w2*x4 + w2*x2 + w2*x1 + w1*x6 + w1*x3 + w0*x7 + w0*x4 + x7*x6 + x7*x5 + x7*x4 + x7*x3 + x6**2 + x6*x5 + x6*x4 + x6*x2 + x6*x1 + x6*x0 + x5*x4 + x5*x1 + x5*x0 + x4*x2 + x4*x1 + x3*x0 + x2**2, - w7*x5 + w7*x4 + w7*x3 + w7*x2 + w6*x7 + w6*x1 + w5*x5 + w5*x4 + w5*x3 + w5*x2 + w5*x1 + w4*x7 + w4*x6 + w4*x4 + w4*x3 + w3*x6 + w3*x5 + w3*x4 + w3*x3 + w2*x2 + w2*x0 \ - + w1*x6 + w1*x5 + w1*x4 + w1*x3 + w1*x2 + w0*x7 + w0*x5 + w0*x4 + x7**2 + x7*x4 + x7*x2 + x6*x4 + x6*x3 + x6*x2 + x6*x1 + x5**2 + x5*x4 + x5*x3 + x5*x2 + x5*x0 \ + w7*x5 + w7*x4 + w7*x3 + w7*x2 + w6*x7 + w6*x1 + w5*x5 + w5*x4 + w5*x3 + w5*x2 + w5*x1 + w4*x7 + w4*x6 + w4*x4 + w4*x3 + w3*x6 + w3*x5 + w3*x4 + w3*x3 + w2*x2 + w2*x0 + + w1*x6 + w1*x5 + w1*x4 + w1*x3 + w1*x2 + w0*x7 + w0*x5 + w0*x4 + x7**2 + x7*x4 + x7*x2 + x6*x4 + x6*x3 + x6*x2 + x6*x1 + x5**2 + x5*x4 + x5*x3 + x5*x2 + x5*x0 + x4*x3 + x4*x2 + x4*x1 + x3**2 + x2*x0 + x1*x0, - w7*x6 + w7*x5 + w7*x3 + w7*x2 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w5*x7 + w5*x1 + w4*x5 + w4*x4 + w4*x3 + w4*x2 + w4*x1 + w3*x7 + w3*x6 + w3*x4 + w3*x3 + w2*x6 + w2*x5 \ - + w2*x4 + w2*x3 + w1*x2 + w1*x0 + w0*x6 + w0*x5 + w0*x4 + w0*x3 + w0*x2 + x7*x5 + x7*x2 + x7*x0 + x6**2 + x6*x5 + x6*x2 + x6*x1 + x6*x0 + x5**2 + x5*x4 + x4**2 \ + w7*x6 + w7*x5 + w7*x3 + w7*x2 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w5*x7 + w5*x1 + w4*x5 + w4*x4 + w4*x3 + w4*x2 + w4*x1 + w3*x7 + w3*x6 + w3*x4 + w3*x3 + w2*x6 + w2*x5 + + w2*x4 + w2*x3 + w1*x2 + w1*x0 + w0*x6 + w0*x5 + w0*x4 + w0*x3 + w0*x2 + x7*x5 + x7*x2 + x7*x0 + x6**2 + x6*x5 + x6*x2 + x6*x1 + x6*x0 + x5**2 + x5*x4 + x4**2 + x4*x2 + x4*x1 + x4*x0 + x3**2 + x3*x2 + x1*x0, - w7**2 + w7*w5 + w7*w3 + w7*x7 + w7*x6 + w7*x4 + w7*x3 + w7*x2 + w6**2 + w6*w5 + w6*w2 + w6*w0 + w6*x7 + w6*x6 + w6*x3 + w6*x2 + w6*x1 + w6*x0 + w5**2 + w5*x7 + w5*x6 \ - + w5*x5 + w5*x4 + w5*x2 + w5*x1 + w4**2 + w4*w3 + w4*w2 + w4*w1 + w4*x6 + w4*x5 + w4*x2 + w4*x1 + w3**2 + w3*w1 + w3*x6 + w3*x5 + w3*x3 + w3*x0 + w2*w1 + w2*x7 \ + w7**2 + w7*w5 + w7*w3 + w7*x7 + w7*x6 + w7*x4 + w7*x3 + w7*x2 + w6**2 + w6*w5 + w6*w2 + w6*w0 + w6*x7 + w6*x6 + w6*x3 + w6*x2 + w6*x1 + w6*x0 + w5**2 + w5*x7 + w5*x6 + + w5*x5 + w5*x4 + w5*x2 + w5*x1 + w4**2 + w4*w3 + w4*w2 + w4*w1 + w4*x6 + w4*x5 + w4*x2 + w4*x1 + w3**2 + w3*w1 + w3*x6 + w3*x5 + w3*x3 + w3*x0 + w2*w1 + w2*x7 + w2*x4 + w2*x2 + w2*x1 + w1*x6 + w1*x5 + w1*x1 + w0*x5, - w7*w5 + w7*w2 + w7*w0 + w7*x5 + w7*x3 + w6**2 + w6*w5 + w6*w2 + w6*w1 + w6*w0 + w6*x7 + w6*x3 + w6*x2 + w6*x0 + w5**2 + w5*w4 + w5*x7 + w5*x6 + w5*x4 + w5*x2 + w5*x0 \ - + w4**2 + w4*w2 + w4*w1 + w4*w0 + w4*x6 + w4*x4 + w4*x3 + w4*x2 + w4*x0 + w3**2 + w3*w2 + w3*x7 + w3*x6 + w3*x4 + w3*x3 + w3*x2 + w3*x0 + w2*x7 + w2*x6 + w2*x4 \ + w7*w5 + w7*w2 + w7*w0 + w7*x5 + w7*x3 + w6**2 + w6*w5 + w6*w2 + w6*w1 + w6*w0 + w6*x7 + w6*x3 + w6*x2 + w6*x0 + w5**2 + w5*w4 + w5*x7 + w5*x6 + w5*x4 + w5*x2 + w5*x0 + + w4**2 + w4*w2 + w4*w1 + w4*w0 + w4*x6 + w4*x4 + w4*x3 + w4*x2 + w4*x0 + w3**2 + w3*w2 + w3*x7 + w3*x6 + w3*x4 + w3*x3 + w3*x2 + w3*x0 + w2*x7 + w2*x6 + w2*x4 + w2*x1 + w2*x0 + w1*w0 + w1*x5 + w1*x4 + w0*x1, - w7**2 + w7*w4 + w7*w2 + w7*x6 + w7*x4 + w7*x0 + w6*w4 + w6*w3 + w6*w2 + w6*w1 + w6*x4 + w6*x3 + w6*x1 + w5**2 + w5*w4 + w5*w3 + w5*w2 + w5*w0 + w5*x7 + w5*x5 + w5*x3 \ - + w5*x1 + w5*x0 + w4*w3 + w4*w2 + w4*w1 + w4*x7 + w4*x5 + w4*x4 + w4*x3 + w4*x1 + w4*x0 + w3**2 + w3*x7 + w3*x5 + w3*x4 + w3*x3 + w3*x1 + w2*w0 + w2*x7 + w2*x5 \ + w7**2 + w7*w4 + w7*w2 + w7*x6 + w7*x4 + w7*x0 + w6*w4 + w6*w3 + w6*w2 + w6*w1 + w6*x4 + w6*x3 + w6*x1 + w5**2 + w5*w4 + w5*w3 + w5*w2 + w5*w0 + w5*x7 + w5*x5 + w5*x3 + + w5*x1 + w5*x0 + w4*w3 + w4*w2 + w4*w1 + w4*x7 + w4*x5 + w4*x4 + w4*x3 + w4*x1 + w4*x0 + w3**2 + w3*x7 + w3*x5 + w3*x4 + w3*x3 + w3*x1 + w2*w0 + w2*x7 + w2*x5 + w2*x2 + w2*x1 + w1*w0 + w1*x6 + w1*x5 + w0*x2]) return l - def _inversion_polynomials_single_sbox(self, x= None, w=None, biaffine_only=None, correct_only=None): + def _inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, correct_only=None): """ Generate inversion polynomials of a single S-box. @@ -3152,9 +3148,9 @@ def inversion_polynomials(self, xi, wi, length): EXAMPLES:: sage: sr = mq.SR(1, 1, 1, 8, gf2=True) - sage: xi = sr.vars('x', 1) - sage: wi = sr.vars('w', 1) - sage: sr.inversion_polynomials(xi, wi, len(xi))[:3] + sage: xi = sr.vars('x', 1) # needs sage.rings.polynomial.pbori + sage: wi = sr.vars('w', 1) # needs sage.rings.polynomial.pbori + sage: sr.inversion_polynomials(xi, wi, len(xi))[:3] # needs sage.rings.polynomial.pbori [x100*w100 + x100*w102 + x100*w103 + x100*w107 + x101*w101 + x101*w102 + x101*w106 + x102*w100 + x102*w101 + x102*w105 + x103*w100 + x103*w104 + x104*w103 + x105*w102 + x106*w101 + x107*w100, x100*w101 + x100*w103 + x100*w104 + x101*w100 + x101*w102 + x101*w103 + x101*w107 + x102*w101 + x102*w102 + x102*w106 + x103*w100 + x103*w101 + x103*w105 + x104*w100 + x104*w104 + x105*w103 + x106*w102 + x107*w101, x100*w102 + x100*w104 + x100*w105 + x101*w101 + x101*w103 + x101*w104 + x102*w100 + x102*w102 + x102*w103 + x102*w107 + x103*w101 + x103*w102 + x103*w106 + x104*w100 + x104*w101 + x104*w105 + x105*w100 + x105*w104 + x106*w103 + x107*w102] @@ -3234,7 +3230,7 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, sage: sr = SR_gf2_2(1, 1, 1, e) sage: P = PolynomialRing(GF(2),['x%d'%i for i in range(e)] + ['w%d'%i for i in range(e)],order='lex') sage: X,W = P.gens()[:e],P.gens()[e:] - sage: sr.inversion_polynomials_single_sbox(X, W, groebner=True) + sage: sr.inversion_polynomials_single_sbox(X, W, groebner=True) # needs sage.libs.singular [x0 + w0*w1*w2 + w0*w1 + w0*w2 + w0*w3 + w0 + w1 + w2, x1 + w0*w1*w3 + w0*w3 + w0 + w1*w3 + w1 + w2*w3, x2 + w0*w2*w3 + w0*w2 + w0 + w1*w2 + w1*w3 + w2*w3, @@ -3243,7 +3239,7 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, sage: from sage.crypto.mq.sr import SR_gf2_2 sage: e = 4 sage: sr = SR_gf2_2(1, 1, 1, e) - sage: sr.inversion_polynomials_single_sbox() + sage: sr.inversion_polynomials_single_sbox() # needs sage.libs.singular [w3*w1 + w3*w0 + w3*x2 + w3*x1 + w3 + w2*w1 + w1 + x3 + x2 + x1, w3*w2 + w3*w1 + w3*x3 + w2 + w1 + x3, w3*w2 + w3*w1 + w3*x2 + w3 + w2*x3 + x2 + x1, @@ -3276,8 +3272,8 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, sage: from sage.crypto.mq.sr import SR_gf2_2 sage: e = 4 sage: sr = SR_gf2_2(1, 1, 1, e) - sage: l = sr.inversion_polynomials_single_sbox() - sage: l == sr.inversion_polynomials_single_sbox(biaffine_only=True, correct_only=False) + sage: l = sr.inversion_polynomials_single_sbox() # needs sage.libs.singular + sage: l == sr.inversion_polynomials_single_sbox(biaffine_only=True, correct_only=False) # needs sage.libs.singular True """ @@ -3290,7 +3286,7 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, w = P.gens()[:e] S = self.sbox(inversion_only=True) - F = S.polynomials(w, x, degree=e-2, groebner=groebner) + F = S.polynomials(w, x, degree=e-2, groebner=groebner) return F class AllowZeroInversionsContext: @@ -3308,6 +3304,7 @@ def __init__(self, sr): a^2 + a """ self.sr = sr + def __enter__(self): """ EXAMPLES:: @@ -3325,6 +3322,7 @@ def __enter__(self): """ self.allow_zero_inversions = self.sr._allow_zero_inversions self.sr._allow_zero_inversions = True + def __exit__(self, typ, value, tb): """ EXAMPLES:: diff --git a/src/sage/crypto/public_key/blum_goldwasser.py b/src/sage/crypto/public_key/blum_goldwasser.py index d841e69699a..1d090673400 100644 --- a/src/sage/crypto/public_key/blum_goldwasser.py +++ b/src/sage/crypto/public_key/blum_goldwasser.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Blum-Goldwasser Probabilistic Encryption @@ -30,17 +31,16 @@ from operator import xor +from sage.arith.misc import gcd, power_mod, xgcd from sage.crypto.cryptosystem import PublicKeyCryptosystem -from sage.crypto.util import is_blum_prime -from sage.crypto.util import least_significant_bits -from sage.crypto.util import random_blum_prime +from sage.crypto.util import is_blum_prime, least_significant_bits, random_blum_prime from sage.functions.log import log from sage.functions.other import Function_floor from sage.monoids.string_monoid import BinaryStrings -from sage.arith.all import gcd, power_mod, xgcd from sage.rings.finite_rings.integer_mod import Mod as mod from sage.rings.finite_rings.integer_mod_ring import IntegerModFactory + floor = Function_floor() IntegerModRing = IntegerModFactory("IntegerModRing") @@ -89,6 +89,7 @@ class BlumGoldwasser(PublicKeyCryptosystem): The following encryption/decryption example is taken from Example 8.57, pages 309--310 of [MvOV1996]_:: + sage: # needs sage.symbolic sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: bg = BlumGoldwasser(); bg The Blum-Goldwasser public-key encryption scheme. @@ -112,6 +113,7 @@ class BlumGoldwasser(PublicKeyCryptosystem): private key. Finally, compare the decrypted message with the original plaintext. :: + sage: # needs sage.libs.pari sage.symbolic sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import bin_to_ascii sage: bg = BlumGoldwasser() @@ -125,10 +127,10 @@ class BlumGoldwasser(PublicKeyCryptosystem): If `(p, q, a, b)` is a private key, then `n = pq` is the corresponding public key. Furthermore, we have `\gcd(p, q) = ap + bq = 1`. :: - sage: p, q, a, b = prikey - sage: pubkey == p * q + sage: p, q, a, b = prikey # needs sage.symbolic + sage: pubkey == p * q # needs sage.symbolic True - sage: gcd(p, q) == a*p + b*q == 1 + sage: gcd(p, q) == a*p + b*q == 1 # needs sage.symbolic True """ @@ -265,24 +267,25 @@ def decrypt(self, C, K): Decrypt a longer ciphertext and convert the resulting plaintext into an ASCII string:: + sage: # needs sage.libs.pari sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import bin_to_ascii sage: bg = BlumGoldwasser() sage: p = 78307; q = 412487 sage: K = bg.private_key(p, q) - sage: C = ([[1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0], \ - ....: [1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1], \ - ....: [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], \ - ....: [0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1], \ - ....: [1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0], \ - ....: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], \ - ....: [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0], \ - ....: [1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1], \ - ....: [0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], \ - ....: [1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1], \ - ....: [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1], \ - ....: [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0], \ - ....: [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]], 3479653279) + sage: C = ([[1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0], + ....: [1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1], + ....: [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1], + ....: [1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0], + ....: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], + ....: [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0], + ....: [1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1], + ....: [0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], + ....: [1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1], + ....: [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1], + ....: [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0], + ....: [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]], 3479653279) sage: P = bg.decrypt(C, K) sage: bin_to_ascii(flatten(P)) 'Blum-Goldwasser encryption' @@ -416,13 +419,13 @@ def encrypt(self, P, K, seed=None): sage: bg = BlumGoldwasser() sage: p = 499; q = 547; n = p * q sage: P = "10011100000100001100" - sage: C = bg.encrypt(P, n, seed=159201); C + sage: C = bg.encrypt(P, n, seed=159201); C # needs sage.symbolic ([[0, 0, 1, 0], [0, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]], 139680) Convert the ciphertext sub-blocks into a binary string:: sage: bin = BinaryStrings() - sage: bin(flatten(C[0])) + sage: bin(flatten(C[0])) # needs sage.symbolic 00100000110011100100 Now encrypt an ASCII string. The result is random; no seed is @@ -433,7 +436,7 @@ def encrypt(self, P, K, seed=None): sage: bg = BlumGoldwasser() sage: K = 32300619509 sage: P = "Blum-Goldwasser encryption" - sage: bg.encrypt(P, K) # random + sage: bg.encrypt(P, K) # random # needs sage.symbolic ([[1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0], \ [1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1], \ [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], \ @@ -555,9 +558,9 @@ def private_key(self, p, q): sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import is_blum_prime sage: bg = BlumGoldwasser() - sage: P = primes_first_n(10); P + sage: P = primes_first_n(10); P # needs sage.libs.pari [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - sage: [is_blum_prime(_) for _ in P] + sage: [is_blum_prime(_) for _ in P] # needs sage.libs.pari [False, True, False, True, True, False, False, True, True, False] sage: bg.private_key(19, 23) (19, 23, -6, 5) @@ -567,6 +570,7 @@ def private_key(self, p, q): resulting private key `(p, q, a, b)` satisfies `\gcd(p, q) = ap + bq = 1`:: + sage: # needs sage.libs.pari sage: from sage.crypto.util import random_blum_prime sage: p = random_blum_prime(10**4, 10**5) sage: q = random_blum_prime(10**4, 10**5) @@ -629,9 +633,9 @@ def public_key(self, p, q): sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import is_blum_prime sage: bg = BlumGoldwasser() - sage: P = primes_first_n(10); P + sage: P = primes_first_n(10); P # needs sage.libs.pari [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - sage: [is_blum_prime(_) for _ in P] + sage: [is_blum_prime(_) for _ in P] # needs sage.libs.pari [False, True, False, True, True, False, False, True, True, False] sage: bg.public_key(3, 7) 21 @@ -640,6 +644,7 @@ def public_key(self, p, q): public key corresponding to those two primes, and test that the public key factorizes into Blum primes:: + sage: # needs sage.libs.pari sage: from sage.crypto.util import random_blum_prime sage: p = random_blum_prime(10**4, 10**5) sage: q = random_blum_prime(10**4, 10**5) @@ -731,6 +736,7 @@ def random_key(self, lbound, ubound, ntries=100): Choosing a random pair of public and private keys. We then test to see if they satisfy the requirements of the Blum-Goldwasser scheme:: + sage: # needs sage.libs.pari sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import is_blum_prime sage: bg = BlumGoldwasser() @@ -755,7 +761,7 @@ def random_key(self, lbound, ubound, ntries=100): sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: bg = BlumGoldwasser() - sage: pubkey, privkey = bg.random_key(24, 30) + sage: pubkey, privkey = bg.random_key(24, 30) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: No Blum primes within the specified closed interval. diff --git a/src/sage/crypto/sbox.pyx b/src/sage/crypto/sbox.pyx index 77b7a904cc2..b72f13e30a8 100644 --- a/src/sage/crypto/sbox.pyx +++ b/src/sage/crypto/sbox.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" S-Boxes and Their Algebraic Representations """ @@ -15,9 +16,8 @@ from sage.matrix.matrix0 cimport Matrix from sage.misc.cachefunc import cached_method from sage.misc.functional import is_even from sage.misc.misc_c import prod as mul -from sage.misc.superseded import deprecated_function_alias from sage.modules.free_module_element import vector -from sage.rings.finite_rings.element_base import is_FiniteFieldElement +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.rings.ideal import FieldIdeal, Ideal from sage.rings.integer_ring import ZZ @@ -40,7 +40,7 @@ cdef Py_ssize_t _nterms(Py_ssize_t nvars, Py_ssize_t deg): sage: from sage.crypto.sbox import SBox sage: S = SBox(7,6,0,4,2,5,1,3) - sage: F = S.polynomials(degree=3) # indirect doctest + sage: F = S.polynomials(degree=3) # indirect doctest # needs sage.libs.singular """ cdef Py_ssize_t total = 1 cdef Py_ssize_t divisor = 1 @@ -59,9 +59,9 @@ cdef Py_ssize_t _nterms(Py_ssize_t nvars, Py_ssize_t deg): cdef class SBox(SageObject): r""" A substitution box or S-box is one of the basic components of - symmetric key cryptography. In general, an S-box takes ``m`` input - bits and transforms them into ``n`` output bits. This is called an - ``mxn`` S-box and is often implemented as a lookup table. These + symmetric key cryptography. In general, an S-box takes `m` input + bits and transforms them into `n` output bits. This is called an + `m \times n` S-box and is often implemented as a lookup table. These S-boxes are carefully chosen to resist linear and differential cryptanalysis [He2002]_. @@ -173,12 +173,12 @@ cdef class SBox(SageObject): sage: S.output_size() 3 """ - from sage.rings.polynomial.polynomial_element import is_Polynomial + from sage.rings.polynomial.polynomial_element import Polynomial if "S" in kwargs: args = kwargs["S"] - if len(args) == 1 and is_Polynomial(args[0]): + if len(args) == 1 and isinstance(args[0], Polynomial): # SBox defined via Univariate Polynomial, compute lookup table # by evaluating the polynomial on every base_ring element poly = args[0] @@ -195,7 +195,7 @@ cdef class SBox(SageObject): _S_list = [] for e in S: - if is_FiniteFieldElement(e): + if isinstance(e, Element) and isinstance(e.parent(), FiniteField): e = e.polynomial().change_ring(ZZ).subs(e.parent().characteristic()) _S_list.append(e) S = _S_list @@ -436,7 +436,7 @@ cdef class SBox(SageObject): return self._S_list[<Integer> X] # Handle non-integer inputs: vectors, finite field elements to-integer-coercible elements - #cdef int i + # cdef int i if isinstance(X, Element): K = X.parent() if K.base_ring().characteristic() != 2: @@ -591,7 +591,7 @@ cdef class SBox(SageObject): ... IndexError: list index out of range sage: from sage.crypto.sboxes import PRESENT - sage: PRESENT.derivative(1).max_degree() < PRESENT.max_degree() + sage: PRESENT.derivative(1).max_degree() < PRESENT.max_degree() # needs sage.rings.polynomial.pbori True """ from sage.structure.element import is_Vector @@ -639,6 +639,54 @@ cdef class SBox(SageObject): [0 0 2 2 2 2 0 0] [0 2 2 0 0 2 2 0] [0 0 0 0 2 2 2 2] + sage: S = SBox(7,4,8,6) + sage: S.difference_distribution_table() + [4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [0 0 0 2 0 0 0 0 0 0 0 0 0 0 2 0] + [0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 2] + [0 2 0 0 0 0 0 0 0 0 0 0 2 0 0 0] + + TESTS:: + + Testing square SBoxes:: + + sage: from sage.crypto.sbox import SBox + sage: S = SBox(7,6,0,4,2,5,1,3) + sage: S.difference_distribution_table() + [8 0 0 0 0 0 0 0] + [0 2 2 0 2 0 0 2] + [0 0 2 2 0 0 2 2] + [0 2 0 2 2 0 2 0] + [0 2 0 2 0 2 0 2] + [0 0 2 2 2 2 0 0] + [0 2 2 0 0 2 2 0] + [0 0 0 0 2 2 2 2] + + Testing non-square SBoxes:: + + sage: from sage.crypto.sbox import SBox + sage: S = SBox(8,8,8,8) + sage: S.difference_distribution_table() + [4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + sage: S = SBox(7,4,8,6) + sage: S.difference_distribution_table() + [4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [0 0 0 2 0 0 0 0 0 0 0 0 0 0 2 0] + [0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 2] + [0 2 0 0 0 0 0 0 0 0 0 0 2 0 0 0] + sage: S = SBox(0,0,0,1,0,0,1,3) + sage: S.difference_distribution_table() + [8 0 0 0] + [4 2 2 0] + [2 4 0 2] + [2 4 0 2] + [4 2 2 0] + [6 0 0 2] + [2 4 0 2] + [2 4 0 2] """ cdef Py_ssize_t nrows = 1 << self.m cdef Py_ssize_t ncols = 1 << self.n @@ -649,7 +697,7 @@ cdef class SBox(SageObject): for i in range(nrows): si = self._S_list[i] for di in range(nrows): - L[di*nrows + si ^ self._S_list[i ^ di]] += 1 + L[di*ncols + si ^ self._S_list[i ^ di]] += 1 A = matrix(ZZ, nrows, ncols, L) A.set_immutable() @@ -840,7 +888,8 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox(7,6,0,4,2,5,1,3) sage: S.ring() - Multivariate Polynomial Ring in x0, x1, x2, y0, y1, y2 over Finite Field of size 2 + Multivariate Polynomial Ring in x0, x1, x2, y0, y1, y2 over + Finite Field of size 2 """ return self._ring @@ -858,9 +907,9 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox([7,6,0,4,2,5,1,3]) - sage: F = S.polynomials() + sage: F = S.polynomials() # needs sage.libs.singular sage: s = S.solutions() - sage: any(f.subs(_s) for f in F for _s in s) + sage: any(f.subs(_s) for f in F for _s in s) # needs sage.libs.singular False """ if X is None and Y is None: @@ -908,7 +957,7 @@ cdef class SBox(SageObject): By default, this method returns an indirect representation:: - sage: S.polynomials() + sage: S.polynomials() # needs sage.libs.singular [x0*x2 + x1 + y1 + 1, x0*x1 + x1 + x2 + y0 + y1 + y2 + 1, x0*y1 + x0 + x2 + y0 + y2, @@ -930,7 +979,7 @@ cdef class SBox(SageObject): bits are greater than the input bits:: sage: P.<y0,y1,y2,x0,x1,x2> = PolynomialRing(GF(2),6,order='lex') - sage: S.polynomials([x0,x1,x2],[y0,y1,y2], groebner=True) + sage: S.polynomials([x0,x1,x2],[y0,y1,y2], groebner=True) # needs sage.libs.singular [y0 + x0*x1 + x0*x2 + x0 + x1*x2 + x1 + 1, y1 + x0*x2 + x1 + 1, y2 + x0 + x1*x2 + x1 + x2 + 1] @@ -940,19 +989,15 @@ cdef class SBox(SageObject): Check that :trac:`22453` is fixed:: sage: from sage.crypto.sboxes import AES - sage: aes_polys = AES.polynomials() - sage: p = aes_polys[0].parent("x3*y0 + x5*y0 + x7*y0 + x6*y1 + x2*y2" - ....: " + x3*y2 + x4*y2 + x2*y3 + x3*y3 +" - ....: " x5*y4 + x6*y4 + x3*y5 + x4*y5 + x4*y7" - ....: " + x2 + x3 + y2 + y3 + y4 + 1") - sage: p in aes_polys - True + sage: aes_polys = AES.polynomials() # long time + sage: aes_polys[3] # long time + x3*y0 + x5*y0 + x7*y0 + x6*y1 + x2*y2 + x3*y2 + x4*y2 + + x2*y3 + x3*y3 + x5*y4 + x6*y4 + x3*y5 + x4*y5 + + x4*y7 + x2 + x3 + y2 + y3 + y4 + 1 """ cdef Py_ssize_t m = self.m cdef Py_ssize_t n = self.n - F = GF(2) - if X is None and Y is None: P = self.ring() X = P.gens()[:m] @@ -1059,7 +1104,7 @@ cdef class SBox(SageObject): cdef int i for i in range(2**m): x = k(vector(self.to_bits(i, m))) - l.append( (x, self(x)) ) + l.append((x, self(x))) P = PolynomialRing(k, 'x') return P.lagrange_polynomial(l) @@ -1275,11 +1320,11 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox([7,6,0,4,2,5,1,3]) sage: f3 = S.component_function(3) - sage: f3.algebraic_normal_form() + sage: f3.algebraic_normal_form() # needs sage.rings.polynomial.pbori x0*x1 + x0*x2 + x0 + x2 sage: f5 = S.component_function([1, 0, 1]) - sage: f5.algebraic_normal_form() + sage: f5.algebraic_normal_form() # needs sage.rings.polynomial.pbori x0*x2 + x0 + x1*x2 """ cdef Py_ssize_t m = self.m @@ -1412,6 +1457,12 @@ cdef class SBox(SageObject): sage: S = SBox([12,5,6,11,9,0,10,13,3,14,15,8,4,7,1,2]) sage: S.linear_branch_number() 2 + + TESTS:: + + sage: f = SBox([0, 2, 0, 6, 2, 2, 3, 7]) + sage: f.linear_branch_number() + 1 """ cdef Py_ssize_t m = self.m cdef Py_ssize_t n = self.n @@ -1419,8 +1470,8 @@ cdef class SBox(SageObject): cdef Py_ssize_t ret = (1 << m) + (1 << n) cdef Py_ssize_t a, b, w - for a in range(1, 1 << m): - for b in range(1 << n): + for a in range(1 << m): + for b in range(1, 1 << n): if lat.get_unsafe(a, b) != 0: w = hamming_weight(a) + hamming_weight(b) if w < ret: @@ -1448,7 +1499,7 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox(7,6,0,4,2,5,1,3) - sage: S.autocorrelation_table() + sage: S.autocorrelation_table() # needs sage.combinat [ 8 8 8 8 8 8 8 8] [ 8 0 0 0 0 0 0 -8] [ 8 0 -8 0 0 0 0 0] @@ -1572,7 +1623,7 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox([0,1,3,6,7,4,5,2]) - sage: S.linear_structures() + sage: S.linear_structures() # needs sage.combinat [(1, 1, 1), (2, 2, 1), (3, 3, 1), (4, 4, 1), (5, 5, 1), (6, 6, 1), (7, 7, 1)] """ @@ -1650,7 +1701,7 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox([12,5,6,11,9,0,10,13,3,14,15,8,4,7,1,2]) - sage: S.max_degree() + sage: S.max_degree() # needs sage.rings.polynomial.pbori 3 """ ret = ZZ.zero() @@ -1670,7 +1721,7 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox([12,5,6,11,9,0,10,13,3,14,15,8,4,7,1,2]) - sage: S.min_degree() + sage: S.min_degree() # needs sage.rings.polynomial.pbori 2 """ ret = ZZ(self.m) diff --git a/src/sage/crypto/sboxes.py b/src/sage/crypto/sboxes.py index 056ce082b50..27ca13fbcc3 100644 --- a/src/sage/crypto/sboxes.py +++ b/src/sage/crypto/sboxes.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" S-Boxes used in cryptographic schemes @@ -396,6 +397,7 @@ def monomial_function(n, e): X = R.gen() return SBox(X**e) + # Bijective S-Boxes mapping 9 bits to 9 # ===================================== diff --git a/src/sage/crypto/stream.py b/src/sage/crypto/stream.py index 728e73ca59b..636f588ad97 100644 --- a/src/sage/crypto/stream.py +++ b/src/sage/crypto/stream.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.rings.finite_rings """ Stream Cryptosystems """ @@ -12,15 +13,14 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from .cryptosystem import SymmetricKeyCryptosystem -from .stream_cipher import LFSRCipher, ShrinkingGeneratorCipher - +from sage.arith.misc import gcd, power_mod +from sage.crypto.cryptosystem import SymmetricKeyCryptosystem +from sage.crypto.stream_cipher import LFSRCipher, ShrinkingGeneratorCipher from sage.crypto.util import random_blum_prime from sage.monoids.string_monoid import BinaryStrings -from sage.arith.all import gcd, power_mod from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.rings.finite_rings.integer_mod_ring import IntegerModFactory -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_element import Polynomial IntegerModRing = IntegerModFactory("IntegerModRing") @@ -29,7 +29,7 @@ class LFSRCryptosystem(SymmetricKeyCryptosystem): """ Linear feedback shift register cryptosystem class """ - def __init__(self, field = None): + def __init__(self, field=None): """ Create a linear feedback shift cryptosystem. @@ -73,7 +73,7 @@ def __call__(self, key): if not isinstance(key, (list, tuple)) and len(key) == 2: raise TypeError("Argument key (= %s) must be a list of tuple of length 2" % key) poly, IS = key - if not is_Polynomial(poly): + if not isinstance(poly, Polynomial): raise TypeError("poly (= %s) must be a polynomial." % poly) if not isinstance(IS, (list, tuple)): raise TypeError("IS (= %s) must be an initial in the key space." % IS) diff --git a/src/sage/crypto/stream_cipher.py b/src/sage/crypto/stream_cipher.py index 07a9bf08251..c6f46c8cef0 100644 --- a/src/sage/crypto/stream_cipher.py +++ b/src/sage/crypto/stream_cipher.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.rings.finite_rings """ Stream Ciphers """ @@ -61,9 +62,9 @@ def __init__(self, parent, poly, IS): sage: E == loads(dumps(E)) True """ - SymmetricKeyCipher.__init__(self, parent, key = (poly, IS)) + SymmetricKeyCipher.__init__(self, parent, key=(poly, IS)) - def __call__(self, M, mode = "ECB"): + def __call__(self, M, mode="ECB"): r""" Generate key stream from the binary string ``M``. @@ -179,7 +180,7 @@ def __init__(self, parent, e1, e2): raise TypeError("Argument e1 (= %s) must be a LFSR cipher." % e1) if not isinstance(e2, LFSRCipher): raise TypeError("Argument e2 (= %s) must be a LFSR cipher." % e2) - SymmetricKeyCipher.__init__(self, parent, key = (e1, e2)) + SymmetricKeyCipher.__init__(self, parent, key=(e1, e2)) def keystream_cipher(self): """ @@ -221,7 +222,7 @@ def decimating_cipher(self): """ return self.key()[1] - def __call__(self, M, mode = "ECB"): + def __call__(self, M, mode="ECB"): r""" INPUT: diff --git a/src/sage/crypto/util.py b/src/sage/crypto/util.py index aa013f9aca4..8590c83db5c 100644 --- a/src/sage/crypto/util.py +++ b/src/sage/crypto/util.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat """ Utility Functions for Cryptography @@ -20,13 +21,15 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.monoids.string_monoid import BinaryStrings -from sage.arith.all import is_prime, lcm, primes, random_prime -from sage.rings.integer import Integer +from sage.arith.functions import lcm +from sage.arith.misc import is_prime, primes, random_prime +from sage.misc.lazy_import import lazy_import from sage.rings.finite_rings.integer_mod import Mod as mod +from sage.rings.integer import Integer -from sage.misc.lazy_import import lazy_import lazy_import('sage.arith.misc', ('carmichael_lambda'), deprecation=34719) +lazy_import('sage.monoids.string_monoid', 'BinaryStrings') + def ascii_integer(B): r""" @@ -295,14 +298,14 @@ def has_blum_prime(lbound, ubound): sage: from sage.crypto.util import has_blum_prime sage: from sage.crypto.util import is_blum_prime - sage: has_blum_prime(4, 100) + sage: has_blum_prime(4, 100) # needs sage.libs.pari True sage: for n in range(4, 100): ....: if is_blum_prime(n): ....: print(n) ....: break 7 - sage: has_blum_prime(24, 28) + sage: has_blum_prime(24, 28) # needs sage.libs.pari False TESTS: @@ -375,8 +378,8 @@ def is_blum_prime(n): False sage: is_blum_prime(7) True - sage: p = random_blum_prime(10**3, 10**5) - sage: is_blum_prime(p) + sage: p = random_blum_prime(10**3, 10**5) # needs sage.libs.pari + sage: is_blum_prime(p) # needs sage.libs.pari True """ if n < 0: @@ -484,10 +487,10 @@ def random_blum_prime(lbound, ubound, ntries=100): Choose a random prime and check that it is a Blum prime:: sage: from sage.crypto.util import random_blum_prime - sage: p = random_blum_prime(10**4, 10**5) - sage: is_prime(p) + sage: p = random_blum_prime(10**4, 10**5) # needs sage.libs.pari + sage: is_prime(p) # needs sage.libs.pari True - sage: mod(p, 4) == 3 + sage: mod(p, 4) == 3 # needs sage.libs.pari True TESTS: @@ -498,11 +501,11 @@ def random_blum_prime(lbound, ubound, ntries=100): is not a Blum prime. :: sage: from sage.crypto.util import random_blum_prime - sage: random_blum_prime(24, 30, ntries=10) + sage: random_blum_prime(24, 30, ntries=10) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: No Blum primes within the specified closed interval. - sage: random_blum_prime(24, 28) + sage: random_blum_prime(24, 28) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: No Blum primes within the specified closed interval. diff --git a/src/sage/data_structures/bitset.pyx b/src/sage/data_structures/bitset.pyx index 29bbeeb0d1c..446062554c1 100644 --- a/src/sage/data_structures/bitset.pyx +++ b/src/sage/data_structures/bitset.pyx @@ -204,27 +204,28 @@ cdef class FrozenBitset: the number of elements currently in the bitset, while the capacity is the number of elements that the bitset can hold. :: - sage: p = primes_first_n(10); p + sage: p = primes_first_n(10); p # needs sage.libs.pari [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - sage: tuple(p) + sage: tuple(p) # needs sage.libs.pari (2, 3, 5, 7, 11, 13, 17, 19, 23, 29) - sage: F = FrozenBitset(p); F; FrozenBitset(tuple(p)) + sage: F = FrozenBitset(p); F; FrozenBitset(tuple(p)) # needs sage.libs.pari 001101010001010001010001000001 001101010001010001010001000001 Recover the primes from the bitset:: - sage: for b in F: + sage: for b in F: # needs sage.libs.pari ....: print(b) 2 3 ... 29 - sage: list(F) + sage: list(F) # needs sage.libs.pari [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] Query the bitset:: + sage: # needs sage.libs.pari sage: len(F) 10 sage: len(list(F)) @@ -2067,7 +2068,7 @@ def test_bitset(py_a, py_b, long n): Large enough to span multiple limbs. We don't explicitly check the number of limbs below because it will be different in the 32 bit versus 64 bit cases:: - sage: test_bitset('111001'*25, RealField(151)(pi).str(2)[2:], 69) + sage: test_bitset('111001'*25, RealField(151)(pi).str(2)[2:], 69) # needs sage.symbolic a 111001111001111001111001111001111001111001111001111001111001111001111001111001111001111001111001111001111001111001111001111001111001111001111001111001 list a [0, 1, 2, 5, 6, 7, 8, 11, 12, 13, 14, 17, 18, 19, 20, 23, 24, 25, 26, 29, 30, 31, 32, 35, 36, 37, 38, 41, 42, 43, 44, 47, 48, 49, 50, 53, 54, 55, 56, 59, 60, 61, 62, 65, 66, 67, 68, 71, 72, 73, 74, 77, 78, 79, 80, 83, 84, 85, 86, 89, 90, 91, 92, 95, 96, 97, 98, 101, 102, 103, 104, 107, 108, 109, 110, 113, 114, 115, 116, 119, 120, 121, 122, 125, 126, 127, 128, 131, 132, 133, 134, 137, 138, 139, 140, 143, 144, 145, 146, 149] a.size 150 @@ -2193,9 +2194,7 @@ def test_bitset(py_a, py_b, long n): print("a.hamming_weight() ", bitset_hamming_weight(a)) - morphism = {} - for i in xrange(a.size): - morphism[i] = a.size - i - 1 + morphism = {i: a.size - i - 1 for i in range(a.size)} bitset_map(r, a, morphism) print("a.map(m) ", bitset_string(r)) diff --git a/src/sage/data_structures/bitset_base.pxd b/src/sage/data_structures/bitset_base.pxd index f932e894efe..6c1d69364c9 100644 --- a/src/sage/data_structures/bitset_base.pxd +++ b/src/sage/data_structures/bitset_base.pxd @@ -174,15 +174,15 @@ cdef inline bint bitset_init(fused_bitset_t bits, mp_bitcnt_t size) except -1: bits.size = size if fused_bitset_t is bitset_t: - bits.limbs = (size - 1) / (8 * LIMB_SIZE) + 1 + bits.limbs = (size - 1) // (8 * LIMB_SIZE) + 1 bits.bits = <mp_limb_t*>check_calloc(bits.limbs, LIMB_SIZE) else: - bits.limbs = ((size - 1) / (8*ALIGNMENT) + 1) * (ALIGNMENT/LIMB_SIZE) + bits.limbs = ((size - 1) // (8*ALIGNMENT) + 1) * (ALIGNMENT//LIMB_SIZE) extra = (ALIGNMENT + LIMB_SIZE - 2) // LIMB_SIZE bits.mem = check_calloc(bits.limbs + extra, LIMB_SIZE) bits.bits = <mp_limb_t*> align(bits.mem, ALIGNMENT) bits.non_zero_chunks_are_initialized = False - bits.non_zero_chunks = <mp_bitcnt_t*> check_allocarray((bits.limbs*LIMB_SIZE) / ALIGNMENT, sizeof(mp_bitcnt_t)) + bits.non_zero_chunks = <mp_bitcnt_t*> check_allocarray((bits.limbs*LIMB_SIZE) // ALIGNMENT, sizeof(mp_bitcnt_t)) cdef inline bint bitset_check_alignment(fused_bitset_t bits): """ @@ -203,7 +203,7 @@ cdef inline int bitset_realloc(bitset_t bits, mp_bitcnt_t size) except -1: if size <= 0: raise ValueError("bitset capacity must be greater than 0") - cdef mp_size_t limbs_new = (size - 1) / (8 * LIMB_SIZE) + 1 + cdef mp_size_t limbs_new = (size - 1) // (8 * LIMB_SIZE) + 1 bits.bits = <mp_limb_t*>check_reallocarray(bits.bits, limbs_new, LIMB_SIZE) bits.size = size bits.limbs = limbs_new diff --git a/src/sage/data_structures/blas_dict.pyx b/src/sage/data_structures/blas_dict.pyx index df6bf29641e..c13cab2aab9 100644 --- a/src/sage/data_structures/blas_dict.pyx +++ b/src/sage/data_structures/blas_dict.pyx @@ -398,7 +398,8 @@ cpdef dict sum_of_terms(index_coeff_pairs): {'a': 1, 'b': 3} sage: blas.sum_of_terms([('a', 5), ('b', 3), ('a', -5)]) {'b': 3} - sage: blas.sum_of_terms([('a', 5), ('b', GF(2).one()), ('a', -5), ('b', GF(2).one())]) + sage: blas.sum_of_terms([('a', 5), ('b', GF(2).one()), + ....: ('a', -5), ('b', GF(2).one())]) {} """ cdef dict result = {} diff --git a/src/sage/data_structures/bounded_integer_sequences.pyx b/src/sage/data_structures/bounded_integer_sequences.pyx index 724f296eae2..907f9b4298a 100644 --- a/src/sage/data_structures/bounded_integer_sequences.pyx +++ b/src/sage/data_structures/bounded_integer_sequences.pyx @@ -110,9 +110,8 @@ AUTHORS: from cysignals.signals cimport sig_check, sig_on, sig_off from sage.data_structures.bitset_base cimport * -from cpython.int cimport PyInt_FromSize_t +from cpython.long cimport PyLong_FromSize_t from cpython.slice cimport PySlice_GetIndicesEx -from sage.libs.gmp.mpn cimport mpn_rshift, mpn_lshift, mpn_copyi, mpn_ior_n, mpn_zero, mpn_copyd, mpn_cmp from sage.libs.flint.flint cimport FLINT_BIT_COUNT as BIT_COUNT from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool @@ -296,7 +295,7 @@ cdef biseq_getitem_py(biseq_t S, mp_size_t index): """ cdef size_t out = biseq_getitem(S, index) - return PyInt_FromSize_t(out) + return PyLong_FromSize_t(out) cdef inline void biseq_inititem(biseq_t S, mp_size_t index, size_t item): """ @@ -1212,7 +1211,7 @@ cdef class BoundedIntegerSequence: sage: T+None Traceback (most recent call last): ... - TypeError: Cannot concatenate bounded integer sequence and None + TypeError: cannot concatenate bounded integer sequence and None TESTS: @@ -1228,7 +1227,7 @@ cdef class BoundedIntegerSequence: """ cdef BoundedIntegerSequence myself, right, out if other is None or self is None: - raise TypeError('Cannot concatenate bounded integer sequence and None') + raise TypeError('cannot concatenate bounded integer sequence and None') myself = self # may result in a type error right = other # --"-- if right.data.itembitsize != myself.data.itembitsize: diff --git a/src/sage/data_structures/list_of_pairs.pxd b/src/sage/data_structures/list_of_pairs.pxd new file mode 100644 index 00000000000..4dbb57c201c --- /dev/null +++ b/src/sage/data_structures/list_of_pairs.pxd @@ -0,0 +1,14 @@ +cimport cython + +cdef struct pair_s: + size_t first + size_t second + +@cython.final +cdef class ListOfPairs: + cdef pair_s** _lists + cdef size_t length + + cdef inline int enlarge(self) except -1 + cdef inline int add(self, size_t first, size_t second) except -1 + cdef inline pair_s* get(self, size_t index) except NULL diff --git a/src/sage/data_structures/list_of_pairs.pyx b/src/sage/data_structures/list_of_pairs.pyx new file mode 100644 index 00000000000..258320353a0 --- /dev/null +++ b/src/sage/data_structures/list_of_pairs.pyx @@ -0,0 +1,121 @@ +r""" +A data structure to store lists of integer pairs of large size. +""" + +# **************************************************************************** +# Copyright (C) 2022 Jonathan Kliem <jonathan.kliem@gmail.com> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from cysignals.memory cimport check_reallocarray, check_allocarray, sig_free +from sage.rings.integer cimport smallInteger + +# Should be a power of two. +# Should be neither exposed nor modified. +cdef size_t length_per_list = 16348 + +cdef class ListOfPairs: + def __dealloc__(self): + cdef size_t n_lists = self.length // length_per_list + cdef size_t i + for i in range(n_lists): + sig_free(self._lists[i]) + sig_free(self._lists) + + cdef inline int enlarge(self) except -1: + """ + Increase size of list by one. + """ + if self.length % length_per_list: + self.length += 1 + return 0 + + cdef size_t n_lists = self.length // length_per_list + self._lists = <pair_s**> check_reallocarray(self._lists, n_lists + 1, sizeof(pair_s*)) + self._lists[n_lists] = <pair_s*> check_allocarray(length_per_list, sizeof(pair_s)) + self.length += 1 + + cdef inline pair_s* get(self, size_t index) except NULL: + """ + Return a pointer to a pair of the list corresponding to the ``index``. + """ + if not (0 <= index < self.length): + raise IndexError + + cdef size_t list_index = index // length_per_list + cdef size_t index_in_list = index - list_index * length_per_list + + return &self._lists[list_index][index_in_list] + + def __getitem__(self, size_t index): + r""" + Get item of specified index. + + EXAMPLES:: + + sage: from sage.data_structures.list_of_pairs import ListOfPairs + sage: l = ListOfPairs() + sage: l[0] = [1, 5] + sage: l[0] + (1, 5) + sage: l[1] + Traceback (most recent call last): + ... + IndexError + sage: l[-1] + Traceback (most recent call last): + ... + OverflowError: can't convert negative value to size_t + """ + cdef pair_s* pair = self.get(index) + return (smallInteger(pair.first), smallInteger(pair.second)) + + def __setitem__(self, size_t index, value): + r""" + Set item of specified index. + + Allows increasing the size of the list by at most 1. + + EXAMPLES:: + + sage: from sage.data_structures.list_of_pairs import ListOfPairs + sage: l = ListOfPairs() + sage: l[0] = (2, 1) + sage: l[1] = (1, 2) + sage: l[0] + (2, 1) + sage: l[1] + (1, 2) + sage: l[10] = (5, 3) + Traceback (most recent call last): + ... + IndexError + sage: l[2] = 2 + Traceback (most recent call last): + ... + TypeError: 'sage.rings.integer.Integer' object is not iterable + """ + cdef size_t first, second + (first, second) = value + + if index == self.length: + self.add(first, second) + return + + cdef pair_s* pair_pt = self.get(index) + pair_pt.first = first + pair_pt.second = second + + cdef inline int add(self, size_t first, size_t second) except -1: + """ + Add a pair to the list. + """ + self.enlarge() + cdef pair_s* last = self.get(self.length - 1) + last.first = first + last.second = second diff --git a/src/sage/data_structures/sparse_bitset.pxd b/src/sage/data_structures/sparse_bitset.pxd index 742ac26c6a5..9b95c55675b 100644 --- a/src/sage/data_structures/sparse_bitset.pxd +++ b/src/sage/data_structures/sparse_bitset.pxd @@ -6,7 +6,7 @@ This is a regular bitset to which we will add additional structure. In particular some representation of which limbs even contain data. """ # **************************************************************************** -# Copyright (C) 2020 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2020 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index f8f6dc6a186..8838a4f1754 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -99,9 +99,12 @@ from sage.arith.misc import divisors from sage.misc.misc_c import prod from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.lazy_import import lazy_import from sage.combinat.integer_vector_weighted import iterator_fast as wt_int_vec_iter -from sage.combinat.sf.sfa import _variables_recursive, _raise_variables from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis +from sage.misc.cachefunc import cached_method + +lazy_import('sage.combinat.sf.sfa', ['_variables_recursive', '_raise_variables']) class Stream(): @@ -122,13 +125,13 @@ class Stream(): If an approximate order or even the true order is known, it must be set after calling ``super().__init__``. - Otherwise, a lazy attribute `_approximate_order` has to be + Otherwise, a lazy attribute ``_approximate_order`` has to be defined. Any initialization code depending on the approximate orders of input streams can be put into this definition. However, keep in mind that (trivially) this initialization - code is not executed if `_approximate_order` is set to a + code is not executed if ``_approximate_order`` is set to a value before it is accessed. """ @@ -159,11 +162,15 @@ def _approximate_order(self): def __ne__(self, other): """ - Check inequality of ``self`` and ``other``. + Return whether ``self`` and ``other`` are known to be different. The default is to always return ``False`` as it usually cannot be decided whether they are equal. + INPUT: + + - ``other`` -- a stream + EXAMPLES:: sage: from sage.data_structures.stream import Stream @@ -178,7 +185,7 @@ def __ne__(self, other): def is_nonzero(self): r""" Return ``True`` if and only if this stream is known - to be nonzero. + to be non-zero. The default implementation is ``False``. @@ -191,6 +198,21 @@ def is_nonzero(self): """ return False + def is_uninitialized(self): + r""" + Return ``True`` if ``self`` is an uninitialized stream. + + The default implementation is ``False``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_zero + sage: zero = Stream_zero() + sage: zero.is_uninitialized() + False + """ + return False + class Stream_inexact(Stream): """ @@ -204,14 +226,7 @@ class Stream_inexact(Stream): - ``is_sparse`` -- boolean; whether the implementation of the stream is sparse - ``true_order`` -- boolean; if the approximate order is the actual order - .. TODO:: - - The ``approximate_order`` is currently only updated when - invoking :meth:`order`. It might make sense to update it - whenever the coefficient one larger than the current - ``approximate_order`` is computed, since in some methods this - will allow shortcuts. - + If the cache is dense, it begins with the first non-zero term. """ def __init__(self, is_sparse, true_order): """ @@ -225,7 +240,6 @@ def __init__(self, is_sparse, true_order): sage: g = Stream_function(lambda n: n, False, 0) sage: isinstance(g, Stream_inexact) True - """ super().__init__(true_order) self._is_sparse = is_sparse @@ -235,30 +249,9 @@ def __init__(self, is_sparse, true_order): self._cache = list() self._iter = self.iterate_coefficients() - @lazy_attribute - def _offset(self): - """ - Return the offset of a stream with a dense cache. - - EXAMPLES:: - - sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n, False, -3) - sage: f._offset - -3 - sage: [f[i] for i in range(-3, 5)] - [-3, -2, -1, 0, 1, 2, 3, 4] - sage: f._cache - [-3, -2, -1, 0, 1, 2, 3, 4] - """ - # self[n] = self._cache[n-self._offset] - if self._is_sparse: - raise ValueError("_offset is only for dense streams") - return self._approximate_order - def is_nonzero(self): r""" - Return ``True`` if and only if the cache contains a nonzero element. + Return ``True`` if and only if the cache contains a non-zero element. EXAMPLES:: @@ -347,7 +340,7 @@ def __setstate__(self, d): def __getitem__(self, n): """ - Return the `n`-th coefficient of ``self``. + Return the ``n``-th coefficient of ``self``. INPUT: @@ -364,38 +357,67 @@ def __getitem__(self, n): sage: [f[i] for i in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] sage: f._cache - {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81} + {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81} sage: f = Stream_function(lambda n: n^2, False, 0) sage: f[3] 9 sage: f._cache - [0, 1, 4, 9] + [1, 4, 9] sage: [f[i] for i in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] sage: f._cache - [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] + [1, 4, 9, 16, 25, 36, 49, 64, 81] """ if n < self._approximate_order: return ZZ.zero() if self._is_sparse: try: - c = self._cache[n] + return self._cache[n] except KeyError: - c = self.get_coefficient(n) + pass + + c = self.get_coefficient(n) + if self._true_order or n > self._approximate_order: self._cache[n] = c - else: - i = n - self._offset - if i >= len(self._cache): - a = len(self._cache) + self._offset - # It is important to extend by generator: - # self._iter might recurse, and thereby extend the - # cache itself, too. - self._cache.extend(next(self._iter) for _ in range(a, n+1)) - c = self._cache[i] + return c - return c + if c: + self._true_order = True + self._cache[n] = c + return c + + # self._approximate_order is not in self._cache if + # self._true_order is False + ao = self._approximate_order + 1 + while ao in self._cache: + if self._cache[ao]: + self._true_order = True + break + ao += 1 + self._approximate_order = ao + return c + + # Dense implementation + while not self._true_order and n >= self._approximate_order: + c = next(self._iter) + if c: + self._true_order = True + self._cache.append(c) + else: + self._approximate_order += 1 + + if self._true_order: + # It is important to extend by generator: + # self._iter might recurse, and thereby extend the + # cache itself, too. + i = n - self._approximate_order + self._cache.extend(next(self._iter) + for _ in range(i - len(self._cache) + 1)) + return self._cache[i] + + return ZZ.zero() def iterate_coefficients(self): """ @@ -419,7 +441,7 @@ def iterate_coefficients(self): def order(self): r""" Return the order of ``self``, which is the minimum index ``n`` such - that ``self[n]`` is nonzero. + that ``self[n]`` is non-zero. EXAMPLES:: @@ -427,48 +449,37 @@ def order(self): sage: f = Stream_function(lambda n: n, True, 0) sage: f.order() 1 + + TESTS:: + + sage: f = Stream_function(lambda n: n*(n+1), False, -1) + sage: f.order() + 1 + sage: f._true_order + True + + sage: f = Stream_function(lambda n: n*(n+1), True, -1) + sage: f.order() + 1 + sage: f._true_order + True """ if self._true_order: return self._approximate_order - if self._is_sparse: - n = self._approximate_order - cache = self._cache - while True: - if n in cache: - if cache[n]: - self._approximate_order = n - self._true_order = True - return n - n += 1 - else: - if self[n]: - self._approximate_order = n - self._true_order = True - return n - n += 1 - else: - n = self._approximate_order - cache = self._cache - while True: - if n - self._offset < len(cache): - if cache[n - self._offset]: - self._approximate_order = n - self._true_order = True - return n - n += 1 - else: - if self[n]: - self._approximate_order = n - self._true_order = True - return n - n += 1 + n = self._approximate_order + while not self[n]: + n += 1 + return n def __ne__(self, other): """ - Check inequality of ``self`` and ``other``. + Return whether ``self`` and ``other`` are known to be different. + + Only the elements in the caches are considered. - Check if there are any differences in the caches to see if they - are known to be not equal. + INPUT: + + - ``other`` -- a stream EXAMPLES:: @@ -534,31 +545,33 @@ def __ne__(self, other): True sage: g != f True + """ + # TODO: more cases, in particular mixed implementations, + # could be detected if not isinstance(other, Stream_inexact): - return False + return (other != self) - if self._is_sparse: + if self.is_uninitialized() != other.is_uninitialized(): + return True + + if self._is_sparse and other._is_sparse: for i in self._cache: if i in other._cache and other._cache[i] != self._cache[i]: return True - else: # they are dense - # Make ``self`` have the smaller approximate order. - if self._approximate_order > other._approximate_order: - self, other = other, self - saorder = self._approximate_order - soffset = self._offset - oaorder = other._approximate_order - ooffset = other._offset - end = min(oaorder, soffset + len(self._cache)) - for i in range(saorder, end): - if self._cache[i-soffset]: - return True - # now check all known values - end = min(soffset + len(self._cache), ooffset + len(other._cache)) - for i in range(oaorder, end): - if self._cache[i-soffset] != other._cache[i-ooffset]: - return True + + elif not self._is_sparse and not other._is_sparse: + if ((self._true_order + and other._approximate_order > self._approximate_order) + or (other._true_order + and self._approximate_order > other._approximate_order)): + return True + + if not self._true_order or not other._true_order: + return False + + if any(i != j for i, j in zip(self._cache, other._cache)): + return True return False @@ -657,13 +670,13 @@ def __init__(self, initial_coefficients, constant=None, degree=None, order=None) # complicated otherwise for i, v in enumerate(initial_coefficients): if v: - # We have found the first nonzero coefficient + # We have found the first non-zero coefficient order += i initial_coefficients = initial_coefficients[i:] if order + len(initial_coefficients) == self._degree: # Strip off the constant values at the end for w in reversed(initial_coefficients): - if w != self._constant: + if not (w == self._constant): break initial_coefficients.pop() self._degree -= 1 @@ -736,7 +749,7 @@ def __getitem__(self, n): def order(self): r""" Return the order of ``self``, which is the minimum index - ``n`` such that ``self[n]`` is nonzero. + ``n`` such that ``self[n]`` is non-zero. EXAMPLES:: @@ -744,7 +757,6 @@ def order(self): sage: s = Stream_exact([1]) sage: s.order() 0 - """ return self._approximate_order @@ -763,7 +775,9 @@ def __hash__(self): def __eq__(self, other): """ - Test the equality between ``self`` and ``other``. + Return whether ``self`` and ``other`` are known to be equal. + + If ``other`` is also exact, equality is computable. INPUT: @@ -795,6 +809,7 @@ def __eq__(self, other): sage: t = Stream_exact([2], order=-1, degree=5, constant=1) sage: s == t False + """ return (isinstance(other, type(self)) and self._degree == other._degree @@ -804,8 +819,10 @@ def __eq__(self, other): def __ne__(self, other): """ - Test inequality between ``self`` and ``other``, where - other is exact or inexact, but not zero. + Return whether ``self`` and ``other`` are known to be different. + + The argument ``other`` may be exact or inexact, but is + assumed to be non-zero. INPUT: @@ -836,13 +853,17 @@ def __ne__(self, other): [0, 0, 0, 2, 1, 1, 1, 1] sage: [f[i] for i in range(-3, 5)] [0, 0, 0, 2, 1, 1, 1, 1] - """ if isinstance(other, type(self)): return (self._degree != other._degree or self._approximate_order != other._approximate_order or self._initial_coefficients != other._initial_coefficients or self._constant != other._constant) + if other.is_uninitialized(): + return True + if isinstance(other, Stream_zero): + # We are assumed to be nonzero + return True # if other is not exact, we can at least compare with the # elements in its cache if other._is_sparse: @@ -850,18 +871,21 @@ def __ne__(self, other): if self[i] != other._cache[i]: return True else: - if other._offset > self._approximate_order: - return False - return any(self[i] != c for i, c in enumerate(other._cache, other._offset)) + if other._true_order: + return any(self[i] != c + for i, c in enumerate(other._cache, + other._approximate_order)) + if other._approximate_order > self._approximate_order: + return True return False def is_nonzero(self): r""" Return ``True`` if and only if this stream is known - to be nonzero. + to be non-zero. - An assumption of this class is that it is nonzero. + An assumption of this class is that it is non-zero. EXAMPLES:: @@ -911,7 +935,6 @@ class Stream_iterator(Stream_inexact): sage: f = Stream_iterator(iter(NonNegativeIntegers()), 1) sage: [f[i] for i in range(10)] [0, 0, 1, 2, 3, 4, 5, 6, 7, 8] - """ def __init__(self, iter, approximate_order, true_order=False): """ @@ -940,6 +963,11 @@ class Stream_function(Stream_inexact): - ``approximate_order`` -- integer; a lower bound for the order of the stream + .. NOTE:: + + We assume for equality that ``function`` is a function in the + mathematical sense. + EXAMPLES:: sage: from sage.data_structures.stream import Stream_function @@ -972,6 +1000,43 @@ def __init__(self, function, is_sparse, approximate_order, true_order=False): super().__init__(is_sparse, true_order) self._approximate_order = approximate_order + def __hash__(self): + """ + Return the hash of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: 1, False, 1) + sage: hash(f) == hash(g) + True + """ + # We don't hash the function as it might not be hashable. + return hash(type(self)) + + def __eq__(self, other): + r""" + Return whether ``self`` and ``other`` are known to be equal. + + INPUT: + + - ``other`` -- a stream + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function + sage: fun = lambda n: n + sage: f = Stream_function(fun, True, 0) + sage: g = Stream_function(fun, False, 0) + sage: h = Stream_function(lambda n: n, False, 0) + sage: f == g + True + sage: f == h + False + """ + return isinstance(other, type(self)) and self.get_coefficient == other.get_coefficient + class Stream_uninitialized(Stream_inexact): r""" @@ -999,7 +1064,6 @@ class Stream_uninitialized(Stream_inexact): sage: C._target = one sage: C[4] 0 - """ def __init__(self, approximate_order, true_order=False): """ @@ -1016,6 +1080,7 @@ def __init__(self, approximate_order, true_order=False): raise ValueError("the valuation must be specified for undefined series") super().__init__(False, true_order) self._approximate_order = approximate_order + self._initializing = False def iterate_coefficients(self): """ @@ -1038,6 +1103,36 @@ def iterate_coefficients(self): yield self._target[n] n += 1 + def is_uninitialized(self): + """ + Return ``True`` if ``self`` is an uninitialized stream. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_uninitialized + sage: C = Stream_uninitialized(0) + sage: C.is_uninitialized() + True + + A more subtle uninitialized series:: + + sage: L.<z> = LazyPowerSeriesRing(QQ) + sage: T = L.undefined(1) + sage: D = L.undefined(0) + sage: T.define(z * exp(T) * D) + sage: T._coeff_stream.is_uninitialized() + True + """ + if self._target is None: + return True + if self._initializing: + return False + # We implement semaphore-like behavior for coupled (undefined) series + self._initializing = True + result = self._target.is_uninitialized() + self._initializing = False + return result + class Stream_unary(Stream_inexact): r""" @@ -1046,6 +1141,9 @@ class Stream_unary(Stream_inexact): INPUT: - ``series`` -- :class:`Stream` the operator acts on + - ``is_sparse`` -- boolean + - ``true_order`` -- boolean (default: ``False``) if the approximate order + is the actual order EXAMPLES:: @@ -1058,8 +1156,7 @@ class Stream_unary(Stream_inexact): sage: [g[i] for i in range(10)] [0, 4, 8, 12, 16, 20, 24, 28, 32, 36] """ - - def __init__(self, series, is_sparse): + def __init__(self, series, is_sparse, true_order=False): """ Initialize ``self``. @@ -1074,7 +1171,7 @@ def __init__(self, series, is_sparse): sage: TestSuite(g).run() """ self._series = series - super().__init__(is_sparse, False) + super().__init__(is_sparse, true_order) def __hash__(self): """ @@ -1092,11 +1189,11 @@ def __hash__(self): def __eq__(self, other): """ - Test equality. + Return whether ``self`` and ``other`` are known to be equal. INPUT: - - ``other`` -- a stream of coefficients + - ``other`` -- a stream EXAMPLES:: @@ -1114,6 +1211,20 @@ def __eq__(self, other): """ return isinstance(other, type(self)) and self._series == other._series + def is_uninitialized(self): + """ + Return ``True`` if ``self`` is an uninitialized stream. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_uninitialized, Stream_unary + sage: C = Stream_uninitialized(0) + sage: M = Stream_unary(C, True) + sage: M.is_uninitialized() + True + """ + return self._series.is_uninitialized() + class Stream_binary(Stream_inexact): """ @@ -1176,11 +1287,11 @@ def __hash__(self): def __eq__(self, other): """ - Test equality. + Return whether ``self`` and ``other`` are known to be equal. INPUT: - - ``other`` -- a :class:`Stream` of coefficients + - ``other`` -- a stream EXAMPLES:: @@ -1202,6 +1313,24 @@ def __eq__(self, other): return False return self._left == other._left and self._right == other._right + def is_uninitialized(self): + """ + Return ``True`` if ``self`` is an uninitialized stream. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_uninitialized, Stream_sub, Stream_function + sage: C = Stream_uninitialized(0) + sage: F = Stream_function(lambda n: n, True, 0) + sage: B = Stream_sub(F, C, True) + sage: B.is_uninitialized() + True + sage: Bp = Stream_sub(F, F, True) + sage: Bp.is_uninitialized() + False + """ + return self._left.is_uninitialized() or self._right.is_uninitialized() + class Stream_binaryCommutative(Stream_binary): r""" @@ -1239,11 +1368,11 @@ def __hash__(self): def __eq__(self, other): """ - Test the equality between ``self`` and ``other``. + Return whether ``self`` and ``other`` are known to be equal. INPUT: - - ``other`` -- a :class:`Stream` of coefficients + - ``other`` -- a stream EXAMPLES:: @@ -1279,7 +1408,6 @@ class Stream_zero(Stream): sage: s[5] 0 """ - def __init__(self): """ Initialize ``self``. @@ -1289,7 +1417,6 @@ def __init__(self): sage: from sage.data_structures.stream import Stream_zero sage: s = Stream_zero() sage: TestSuite(s).run() - """ super().__init__(True) self._approximate_order = infinity @@ -1328,7 +1455,11 @@ def order(self): def __eq__(self, other): """ - Check equality of ``self`` and ``other``. + Return whether ``self`` and ``other`` are known to be equal. + + INPUT: + + - ``other`` -- a stream EXAMPLES:: @@ -1338,6 +1469,33 @@ def __eq__(self, other): """ return self is other or isinstance(other, Stream_zero) + def __ne__(self, other): + """ + Return whether ``self`` and ``other`` are known to be different. + + INPUT: + + - ``other`` -- a stream + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_zero, Stream_function + sage: Stream_zero() != Stream_zero() + False + sage: f = Stream_function(lambda n: 2*n, True, 0) + sage: Stream_zero() != f + False + sage: f[0] + 0 + sage: Stream_zero() != f + False + sage: f[1] + 2 + sage: Stream_zero() != f + True + """ + return self is not other and not isinstance(other, Stream_zero) and other.is_nonzero() + def __hash__(self): """ Return the hash of ``self``. @@ -1538,18 +1696,15 @@ def get_coefficient(self, n): sage: [h.get_coefficient(i) for i in range(10)] [0, 0, 1, 6, 20, 50, 105, 196, 336, 540] """ - c = ZZ.zero() - for k in range(self._left._approximate_order, - n - self._right._approximate_order + 1): - val = self._left[k] - if val: - c += val * self._right[n-k] - return c + return sum(l * self._right[n - k] + for k in range(self._left._approximate_order, + n - self._right._approximate_order + 1) + if (l := self._left[k])) def is_nonzero(self): r""" Return ``True`` if and only if this stream is known - to be nonzero. + to be non-zero. EXAMPLES:: @@ -1567,6 +1722,14 @@ def is_nonzero(self): return self._left.is_nonzero() and self._right.is_nonzero() +class Stream_cauchy_mul_commutative(Stream_cauchy_mul, Stream_binaryCommutative): + """ + Operator for multiplication of two coefficient streams using the + Cauchy product for commutative multiplication of coefficients. + """ + pass + + class Stream_dirichlet_convolve(Stream_binary): r""" Operator for the Dirichlet convolution of two streams. @@ -1615,7 +1778,7 @@ def _approximate_order(self): or self._right._approximate_order <= 0): raise ValueError("Dirichlet convolution is only defined for " "coefficient streams with minimal index of " - "nonzero coefficient at least 1") + "non-zero coefficient at least 1") return self._left._approximate_order * self._right._approximate_order def get_coefficient(self, n): @@ -1637,50 +1800,49 @@ def get_coefficient(self, n): sage: [h[i] for i in range(1, 10)] [1, 3, 4, 7, 6, 12, 8, 15, 13] """ - c = ZZ.zero() - for k in divisors(n): - if k < self._left._approximate_order or n // k < self._right._approximate_order: - continue - val = self._left[k] - if val: - c += val * self._right[n//k] - return c + return sum(l * self._right[n//k] for k in divisors(n) + if (k >= self._left._approximate_order + and n // k >= self._right._approximate_order + and (l := self._left[k]))) -class Stream_dirichlet_invert(Stream_unary): +class Stream_cauchy_compose(Stream_binary): r""" - Operator for inverse with respect to Dirichlet convolution of the stream. + Return ``f`` composed by ``g``. + + This is the composition `(f \circ g)(z) = f(g(z))`. INPUT: - - ``series`` -- a :class:`Stream` + - ``f`` -- a :class:`Stream` + - ``g`` -- a :class:`Stream` with positive order EXAMPLES:: - sage: from sage.data_structures.stream import (Stream_dirichlet_invert, Stream_function) - sage: f = Stream_function(lambda n: 1, True, 1) - sage: g = Stream_dirichlet_invert(f, True) - sage: [g[i] for i in range(10)] - [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] - sage: [moebius(i) for i in range(10)] - [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] + sage: from sage.data_structures.stream import Stream_cauchy_compose, Stream_function + sage: f = Stream_function(lambda n: n, True, 1) + sage: g = Stream_function(lambda n: 1, True, 1) + sage: h = Stream_cauchy_compose(f, g, True) + sage: [h[i] for i in range(10)] + [0, 1, 3, 8, 20, 48, 112, 256, 576, 1280] + sage: u = Stream_cauchy_compose(g, f, True) + sage: [u[i] for i in range(10)] + [0, 1, 3, 8, 21, 55, 144, 377, 987, 2584] """ - def __init__(self, series, is_sparse): + def __init__(self, f, g, is_sparse): """ - Initialize. + Initialize ``self``. TESTS:: - sage: from sage.data_structures.stream import (Stream_exact, Stream_dirichlet_invert) - sage: f = Stream_exact([0, 0], constant=1) - sage: g = Stream_dirichlet_invert(f, True) - sage: g[1] - Traceback (most recent call last): - ... - ZeroDivisionError: the Dirichlet inverse only exists if the coefficient with index 1 is non-zero + sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_compose + sage: f = Stream_function(lambda n: 1, True, 1) + sage: g = Stream_function(lambda n: n^2, True, 1) + sage: h = Stream_cauchy_compose(f, g, True) """ - super().__init__(series, is_sparse) - self._zero = ZZ.zero() + if g._true_order and g._approximate_order <= 0: + raise ValueError("can only compose with a series of positive valuation") + super().__init__(f, g, is_sparse) @lazy_attribute def _approximate_order(self): @@ -1689,122 +1851,10 @@ def _approximate_order(self): EXAMPLES:: - sage: from sage.data_structures.stream import Stream_function, Stream_dirichlet_invert + sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_compose sage: f = Stream_function(lambda n: n, True, 1) - sage: h = Stream_dirichlet_invert(f, True) - sage: h._approximate_order - 1 - sage: [h[i] for i in range(5)] - [0, -2, -8, -12, -48] - """ - # this is the true order, but we want to check first - if self._series._approximate_order > 1: - raise ZeroDivisionError("the Dirichlet inverse only exists if the " - "coefficient with index 1 is non-zero") - self._true_order = True - return 1 - - @lazy_attribute - def _ainv(self): - """ - The inverse of the leading coefficient. - - EXAMPLES:: - - sage: from sage.data_structures.stream import (Stream_exact, Stream_dirichlet_invert) - sage: f = Stream_exact([0, 3], constant=2) - sage: g = Stream_dirichlet_invert(f, True) - sage: g._ainv - 1/3 - - sage: f = Stream_exact([Zmod(6)(5)], constant=2, order=1) - sage: g = Stream_dirichlet_invert(f, True) - sage: g._ainv - 5 - """ - try: - return ~self._series[1] - except TypeError: - return self._series[1].inverse_of_unit() - - def get_coefficient(self, n): - """ - Return the ``n``-th coefficient of ``self``. - - INPUT: - - - ``n`` -- integer; the degree for the coefficient - - EXAMPLES:: - - sage: from sage.data_structures.stream import (Stream_exact, Stream_dirichlet_invert) - sage: f = Stream_exact([0, 3], constant=2) - sage: g = Stream_dirichlet_invert(f, True) - sage: g.get_coefficient(6) - 2/27 - sage: [g[i] for i in range(8)] - [0, 1/3, -2/9, -2/9, -2/27, -2/9, 2/27, -2/9] - """ - if n == 1: - return self._ainv - c = self._zero - for k in divisors(n): - if k < n: - val = self._series[n//k] - if val: - c += self[k] * val - return -c * self._ainv - - -class Stream_cauchy_compose(Stream_binary): - r""" - Return ``f`` composed by ``g``. - - This is the composition `(f \circ g)(z) = f(g(z))`. - - INPUT: - - - ``f`` -- a :class:`Stream` - - ``g`` -- a :class:`Stream` with positive order - - EXAMPLES:: - - sage: from sage.data_structures.stream import Stream_cauchy_compose, Stream_function - sage: f = Stream_function(lambda n: n, True, 1) - sage: g = Stream_function(lambda n: 1, True, 1) - sage: h = Stream_cauchy_compose(f, g, True) - sage: [h[i] for i in range(10)] - [0, 1, 3, 8, 20, 48, 112, 256, 576, 1280] - sage: u = Stream_cauchy_compose(g, f, True) - sage: [u[i] for i in range(10)] - [0, 1, 3, 8, 21, 55, 144, 377, 987, 2584] - """ - def __init__(self, f, g, is_sparse): - """ - Initialize ``self``. - - TESTS:: - - sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_compose - sage: f = Stream_function(lambda n: 1, True, 1) - sage: g = Stream_function(lambda n: n^2, True, 1) - sage: h = Stream_cauchy_compose(f, g, True) - """ - if g._true_order and g._approximate_order <= 0: - raise ValueError("can only compose with a series of positive valuation") - super().__init__(f, g, is_sparse) - - @lazy_attribute - def _approximate_order(self): - """ - Compute and return the approximate order of ``self``. - - EXAMPLES:: - - sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_compose - sage: f = Stream_function(lambda n: n, True, 1) - sage: g = Stream_function(lambda n: n^2, True, 1) - sage: h = Stream_cauchy_compose(f, g, True) + sage: g = Stream_function(lambda n: n^2, True, 1) + sage: h = Stream_cauchy_compose(f, g, True) sage: h._approximate_order 1 sage: [h[i] for i in range(5)] @@ -1853,16 +1903,23 @@ def get_coefficient(self, n): fv = self._left._approximate_order gv = self._right._approximate_order if n < 0: - return sum(self._left[i] * self._neg_powers[-i][n] - for i in range(fv, n // gv + 1)) + return sum(l * self._neg_powers[-k][n] + for k in range(fv, n // gv + 1) + if (l := self._left[k])) # n > 0 while len(self._pos_powers) <= n // gv: # TODO: possibly we always want a dense cache here? - self._pos_powers.append(Stream_cauchy_mul(self._pos_powers[-1], self._right, self._is_sparse)) - ret = sum(self._left[i] * self._neg_powers[-i][n] for i in range(fv, 0)) - if n == 0: + self._pos_powers.append(Stream_cauchy_mul(self._pos_powers[-1], + self._right, + self._is_sparse)) + ret = sum(l * self._neg_powers[-k][n] for k in range(fv, 0) + if (l := self._left[k])) + + if not n: ret += self._left[0] - return ret + sum(self._left[i] * self._pos_powers[i][n] for i in range(1, n // gv+1)) + + return ret + sum(l * self._pos_powers[k][n] for k in range(1, n // gv + 1) + if (l := self._left[k])) class Stream_plethysm(Stream_binary): @@ -1887,6 +1944,7 @@ class Stream_plethysm(Stream_binary): EXAMPLES:: + sage: # needs sage.modules sage: from sage.data_structures.stream import Stream_function, Stream_plethysm sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() @@ -1910,6 +1968,7 @@ class Stream_plethysm(Stream_binary): This class also handles the plethysm of an exact stream with a stream of order `0`:: + sage: # needs sage.modules sage: from sage.data_structures.stream import Stream_exact sage: f = Stream_exact([s[1]], order=1) sage: g = Stream_function(lambda n: s[n], True, 0) @@ -1921,6 +1980,7 @@ class Stream_plethysm(Stream_binary): Check corner cases:: + sage: # needs sage.modules sage: f0 = Stream_exact([p([])]) sage: f1 = Stream_exact([p[1]], order=1) sage: f2 = Stream_exact([p[2]], order=2 ) @@ -1934,21 +1994,24 @@ class Stream_plethysm(Stream_binary): Check that degree one elements are treated in the correct way:: + sage: # needs sage.modules sage: R.<a1,a2,a11,b1,b21,b111> = QQ[]; p = SymmetricFunctions(R).p() sage: f_s = a1*p[1] + a2*p[2] + a11*p[1,1] sage: g_s = b1*p[1] + b21*p[2,1] + b111*p[1,1,1] sage: r_s = f_s(g_s) - sage: f = Stream_exact([f_s.restrict_degree(k) for k in range(f_s.degree()+1)]) - sage: g = Stream_exact([g_s.restrict_degree(k) for k in range(g_s.degree()+1)]) + sage: f = Stream_exact([f_s.restrict_degree(k) + ....: for k in range(f_s.degree()+1)]) + sage: g = Stream_exact([g_s.restrict_degree(k) + ....: for k in range(g_s.degree()+1)]) sage: r = Stream_plethysm(f, g, True, p) sage: r_s == sum(r[n] for n in range(2*(r_s.degree()+1))) True - sage: r_s - f_s(g_s, include=[]) + sage: r_s - f_s(g_s, include=[]) # needs sage.modules (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] - sage: r2 = Stream_plethysm(f, g, True, p, include=[]) - sage: r_s - sum(r2[n] for n in range(2*(r_s.degree()+1))) + sage: r2 = Stream_plethysm(f, g, True, p, include=[]) # needs sage.modules + sage: r_s - sum(r2[n] for n in range(2*(r_s.degree()+1))) # needs sage.modules (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] """ @@ -1958,6 +2021,7 @@ def __init__(self, f, g, is_sparse, p, ring=None, include=None, exclude=None): TESTS:: + sage: # needs sage.modules sage: from sage.data_structures.stream import Stream_function, Stream_plethysm sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() @@ -1979,7 +2043,7 @@ def __init__(self, f, g, is_sparse, p, ring=None, include=None, exclude=None): self._basis = ring self._p = p g = Stream_map_coefficients(g, lambda x: p(x), is_sparse) - self._powers = [g] # a cache for the powers of g + self._powers = [g] # a cache for the powers of g in the powersum basis R = self._basis.base_ring() self._degree_one = _variables_recursive(R, include=include, exclude=exclude) @@ -1999,6 +2063,7 @@ def _approximate_order(self): EXAMPLES:: + sage: # needs sage.modules sage: from sage.data_structures.stream import Stream_function, Stream_plethysm sage: p = SymmetricFunctions(QQ).p() sage: f = Stream_function(lambda n: p[n], True, 1) @@ -2015,7 +2080,6 @@ def _approximate_order(self): # " support") return self._left._approximate_order * self._right._approximate_order - def get_coefficient(self, n): r""" Return the ``n``-th coefficient of ``self``. @@ -2026,6 +2090,7 @@ def get_coefficient(self, n): EXAMPLES:: + sage: # needs sage.modules sage: from sage.data_structures.stream import Stream_function, Stream_plethysm sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() @@ -2045,26 +2110,25 @@ def get_coefficient(self, n): if not n: # special case of 0 if self._right[0]: assert self._degree_f is not None, "the plethysm with a lazy symmetric function of valuation 0 is defined only for symmetric functions of finite support" + K = self._degree_f + else: + K = 1 + else: + K = n + 1 - return sum((c * self.compute_product(n, la) - for k in range(self._left._approximate_order, self._degree_f) - if self._left[k] - for la, c in self._left[k]), - self._basis.zero()) - - res = sum((c * self.compute_product(n, la) - for k in range(self._left._approximate_order, n+1) - if self._left[k] - for la, c in self._left[k]), - self._basis.zero()) - return res + return sum((c * self.compute_product(n, la) + for k in range(self._left._approximate_order, K) + if self._left[k] # necessary, because it might be int(0) + for la, c in self._left[k]), + self._basis.zero()) def compute_product(self, n, la): r""" - Compute the product ``c * p[la](self._right)`` in degree ``n``. + Compute the product ``p[la](self._right)`` in degree ``n``. EXAMPLES:: + sage: # needs sage.modules sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function, Stream_zero sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() @@ -2077,21 +2141,26 @@ def compute_product(self, n, la): sage: A == p[2, 1](s[2] + s[3]).homogeneous_component(7) True + sage: # needs sage.modules sage: p2 = tensor([p, p]) sage: f = Stream_exact([1]) # irrelevant for this test - sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), True, 1) + sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) + ....: for k in range(n+1)), True, 1) sage: h = Stream_plethysm(f, g, True, p2) sage: A = h.compute_product(7, Partition([2, 1])) sage: B = p[2, 1](sum(g[n] for n in range(7))) - sage: B = p2.element_class(p2, {m: c for m, c in B if sum(mu.size() for mu in m) == 7}) + sage: B = p2.element_class(p2, {m: c for m, c in B + ....: if sum(mu.size() for mu in m) == 7}) sage: A == B True + sage: # needs sage.modules sage: f = Stream_exact([1]) # irrelevant for this test sage: g = Stream_function(lambda n: s[n], True, 0) sage: h = Stream_plethysm(f, g, True, p) - sage: B = p[2, 2, 1](sum(s[i] for i in range(7))) - sage: all(h.compute_product(k, Partition([2, 2, 1])) == B.restrict_degree(k) for k in range(7)) + sage: B = p[2, 2, 1](sum(p(s[i]) for i in range(7))) + sage: all(h.compute_product(k, Partition([2, 2, 1])) + ....: == B.restrict_degree(k) for k in range(7)) True """ # This is the approximate order of the result @@ -2109,22 +2178,35 @@ def compute_product(self, n, la): wgt.reverse() exp.reverse() for k in wt_int_vec_iter(n - ret_approx_order, wgt): - # TODO: it may make a big difference here if the - # approximate order would be updated. - # The test below is based on not removing the fixed block - #if any(d < self._right._approximate_order * m - # for m, d in zip(exp, k)): - # continue - ret += prod(self.stretched_power_restrict_degree(i, m, rao * m + d) - for i, m, d in zip(wgt, exp, k)) + # prod does not short-cut zero, therefore + # ret += prod(self.stretched_power_restrict_degree(i, m, rao * m + d) + # for i, m, d in zip(wgt, exp, k)) + # is expensive + lf = [] + for i, m, d in zip(wgt, exp, k): + f = self.stretched_power_restrict_degree(i, m, rao * m + d) + if not f: + break + lf.append(f) + else: + ret += prod(lf) + return ret + @cached_method def stretched_power_restrict_degree(self, i, m, d): r""" - Return the degree ``d*i`` part of ``p([i]*m)(g)``. + Return the degree ``d*i`` part of ``p([i]*m)(g)`` in + terms of ``self._basis``. + + INPUT: + + - ``i``, ``m`` -- positive integers + - ``d`` -- integer EXAMPLES:: + sage: # needs sage.modules sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function, Stream_zero sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() @@ -2135,50 +2217,58 @@ def stretched_power_restrict_degree(self, i, m, d): sage: A == p[2,2,2](s[2] + s[3]).homogeneous_component(12) True + sage: # needs sage.modules sage: p2 = tensor([p, p]) sage: f = Stream_exact([1]) # irrelevant for this test - sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), True, 1) + sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) + ....: for k in range(n+1)), True, 1) sage: h = Stream_plethysm(f, g, True, p2) sage: A = h.stretched_power_restrict_degree(2, 3, 6) - sage: B = p[2,2,2](sum(g[n] for n in range(7))) # long time - sage: B = p2.element_class(p2, {m: c for m, c in B if sum(mu.size() for mu in m) == 12}) # long time - sage: A == B # long time + sage: B = p[2,2,2](sum(g[n] for n in range(7))) # long time + sage: B = p2.element_class(p2, {m: c for m, c in B # long time + ....: if sum(mu.size() for mu in m) == 12}) + sage: A == B # long time True + """ + # TODO: we should do lazy binary powering here while len(self._powers) < m: # TODO: possibly we always want a dense cache here? - self._powers.append(Stream_cauchy_mul(self._powers[-1], self._powers[0], self._is_sparse)) + self._powers.append(Stream_cauchy_mul(self._powers[-1], + self._powers[0], + self._is_sparse)) power_d = self._powers[m-1][d] # we have to check power_d for zero because it might be an # integer and not a symmetric function if power_d: + # _raise_variables(c, i, self._degree_one) cannot vanish + # because i is positive and c is non-zero if self._tensor_power is None: - terms = {mon.stretch(i): raised_c for mon, c in power_d - if (raised_c := _raise_variables(c, i, self._degree_one))} + terms = {mon.stretch(i): + _raise_variables(c, i, self._degree_one) + for mon, c in power_d} else: - terms = {tuple((mu.stretch(i) for mu in mon)): raised_c - for mon, c in power_d - if (raised_c := _raise_variables(c, i, self._degree_one))} - return self._p.element_class(self._p, terms) + terms = {tuple((mu.stretch(i) for mu in mon)): + _raise_variables(c, i, self._degree_one) + for mon, c in power_d} + return self._basis(self._p.element_class(self._p, terms)) - return self._p.zero() + return self._basis.zero() ##################################################################### # Unary operations -class Stream_scalar(Stream_inexact): +class Stream_scalar(Stream_unary): """ Base class for operators multiplying a coefficient stream by a scalar. - .. TODO:: - - This does not inherit from :class:`Stream_unary`, because of - the extra argument ``scalar``. However, we could also - override :meth:`Stream_unary.hash`, - :meth:`Stream_unary.__eq__`. Would this be any better? + INPUT: + - ``series`` -- a :class:`Stream` + - ``scalar`` -- a non-zero, non-one scalar + - ``is_sparse`` -- boolean """ def __init__(self, series, scalar, is_sparse): """ @@ -2190,10 +2280,10 @@ def __init__(self, series, scalar, is_sparse): sage: f = Stream_function(lambda n: -1, True, 0) sage: g = Stream_rmul(f, 3, True) """ - self._series = series self._scalar = scalar assert scalar, "the scalar must not be equal to 0" - super().__init__(is_sparse, series._true_order) + assert scalar != 1, "the scalar must not be equal to 1" + super().__init__(series, is_sparse, series._true_order) @lazy_attribute def _approximate_order(self): @@ -2230,11 +2320,11 @@ def __hash__(self): def __eq__(self, other): """ - Test equality. + Return whether ``self`` and ``other`` are known to be equal. INPUT: - - ``other`` -- a stream of coefficients + - ``other`` -- a stream EXAMPLES:: @@ -2258,7 +2348,7 @@ def __eq__(self, other): def is_nonzero(self): r""" Return ``True`` if and only if this stream is known - to be nonzero. + to be non-zero. EXAMPLES:: @@ -2285,10 +2375,11 @@ class Stream_rmul(Stream_scalar): INPUT: - ``series`` -- a :class:`Stream` - - ``scalar`` -- a scalar + - ``scalar`` -- a non-zero, non-one scalar EXAMPLES:: + sage: # needs sage.modules sage: from sage.data_structures.stream import (Stream_rmul, Stream_function) sage: W = algebras.DifferentialWeyl(QQ, names=('x',)) sage: x, dx = W.gens() @@ -2326,10 +2417,11 @@ class Stream_lmul(Stream_scalar): INPUT: - ``series`` -- a :class:`Stream` - - ``scalar`` -- a scalar + - ``scalar`` -- a non-zero, non-one scalar EXAMPLES:: + sage: # needs sage.modules sage: from sage.data_structures.stream import (Stream_lmul, Stream_function) sage: W = algebras.DifferentialWeyl(QQ, names=('x',)) sage: x, dx = W.gens() @@ -2432,7 +2524,7 @@ def get_coefficient(self, n): def is_nonzero(self): r""" Return ``True`` if and only if this stream is known - to be nonzero. + to be non-zero. EXAMPLES:: @@ -2461,7 +2553,8 @@ class Stream_cauchy_invert(Stream_unary): - ``approximate_order`` -- ``None``, or a lower bound on the order of the resulting stream - Instances of this class are always dense. + Instances of this class are always dense, because of mathematical + necessities. EXAMPLES:: @@ -2570,9 +2663,9 @@ def iterate_coefficients(self): def is_nonzero(self): r""" Return ``True`` if and only if this stream is known - to be nonzero. + to be non-zero. - An assumption of this class is that it is nonzero. + An assumption of this class is that it is non-zero. EXAMPLES:: @@ -2585,9 +2678,116 @@ def is_nonzero(self): return True -class Stream_map_coefficients(Stream_inexact): +class Stream_dirichlet_invert(Stream_unary): + r""" + Operator for inverse with respect to Dirichlet convolution of the stream. + + INPUT: + + - ``series`` -- a :class:`Stream` + + EXAMPLES:: + + sage: from sage.data_structures.stream import (Stream_dirichlet_invert, Stream_function) + sage: f = Stream_function(lambda n: 1, True, 1) + sage: g = Stream_dirichlet_invert(f, True) + sage: [g[i] for i in range(10)] + [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] + sage: [moebius(i) for i in range(10)] # needs sage.libs.pari + [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] + """ + def __init__(self, series, is_sparse): + """ + Initialize. + + TESTS:: + + sage: from sage.data_structures.stream import (Stream_exact, Stream_dirichlet_invert) + sage: f = Stream_exact([0, 0], constant=1) + sage: g = Stream_dirichlet_invert(f, True) + sage: g[1] + Traceback (most recent call last): + ... + ZeroDivisionError: the Dirichlet inverse only exists if the coefficient with index 1 is non-zero + """ + super().__init__(series, is_sparse) + self._zero = ZZ.zero() + + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_dirichlet_invert + sage: f = Stream_function(lambda n: n, True, 1) + sage: h = Stream_dirichlet_invert(f, True) + sage: h._approximate_order + 1 + sage: [h[i] for i in range(5)] + [0, -2, -8, -12, -48] + """ + # this is the true order, but we want to check first + if self._series._approximate_order > 1: + raise ZeroDivisionError("the Dirichlet inverse only exists if the " + "coefficient with index 1 is non-zero") + self._true_order = True + return 1 + + @lazy_attribute + def _ainv(self): + """ + The inverse of the leading coefficient. + + EXAMPLES:: + + sage: from sage.data_structures.stream import (Stream_exact, Stream_dirichlet_invert) + sage: f = Stream_exact([0, 3], constant=2) + sage: g = Stream_dirichlet_invert(f, True) + sage: g._ainv + 1/3 + + sage: f = Stream_exact([Zmod(6)(5)], constant=2, order=1) + sage: g = Stream_dirichlet_invert(f, True) + sage: g._ainv + 5 + """ + try: + return ~self._series[1] + except TypeError: + return self._series[1].inverse_of_unit() + + def get_coefficient(self, n): + """ + Return the ``n``-th coefficient of ``self``. + + INPUT: + + - ``n`` -- integer; the degree for the coefficient + + EXAMPLES:: + + sage: from sage.data_structures.stream import (Stream_exact, Stream_dirichlet_invert) + sage: f = Stream_exact([0, 3], constant=2) + sage: g = Stream_dirichlet_invert(f, True) + sage: g.get_coefficient(6) + 2/27 + sage: [g[i] for i in range(8)] + [0, 1/3, -2/9, -2/9, -2/27, -2/9, 2/27, -2/9] + """ + if n == 1: + return self._ainv + # TODO: isn't self[k] * l and l * self[k] the same here? + c = sum(self[k] * l for k in divisors(n) + if (k < n + and (l := self._series[n // k]))) + return -c * self._ainv + + +class Stream_map_coefficients(Stream_unary): r""" - The stream with ``function`` applied to each nonzero coefficient + The stream with ``function`` applied to each non-zero coefficient of ``series``. INPUT: @@ -2595,6 +2795,11 @@ class Stream_map_coefficients(Stream_inexact): - ``series`` -- a :class:`Stream` - ``function`` -- a function that modifies the elements of the stream + .. NOTE:: + + We assume for equality that ``function`` is a function in the + mathematical sense. + EXAMPLES:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) @@ -2616,8 +2821,7 @@ def __init__(self, series, function, is_sparse, approximate_order=None, true_ord sage: TestSuite(g).run(skip="_test_pickling") """ self._function = function - self._series = series - super().__init__(is_sparse, true_order) + super().__init__(series, is_sparse, true_order) if approximate_order is not None: self._approximate_order = approximate_order @@ -2685,11 +2889,11 @@ def __hash__(self): def __eq__(self, other): """ - Test equality. + Return whether ``self`` and ``other`` are known to be equal. INPUT: - - ``other`` -- a stream of coefficients + - ``other`` -- a stream EXAMPLES:: @@ -2708,7 +2912,7 @@ def __eq__(self, other): class Stream_shift(Stream): """ - Operator for shifting a nonzero, nonexact stream. + Operator for shifting a non-zero, non-exact stream. Instances of this class share the cache with its input stream. @@ -2754,7 +2958,7 @@ def _approximate_order(self): def order(self): r""" Return the order of ``self``, which is the minimum index - ``n`` such that ``self[n]`` is nonzero. + ``n`` such that ``self[n]`` is non-zero. EXAMPLES:: @@ -2765,7 +2969,6 @@ def order(self): """ return self._series.order() + self._shift - def __getitem__(self, n): """ Return the ``n``-th coefficient of ``self``. @@ -2781,7 +2984,7 @@ def __getitem__(self, n): sage: [M[i] for i in range(6)] [0, 0, 0, 1, 2, 3] """ - return self._series[n-self._shift] + return self._series[n - self._shift] def __hash__(self): """ @@ -2800,11 +3003,11 @@ def __hash__(self): def __eq__(self, other): """ - Test equality. + Return whether ``self`` and ``other`` are known to be equal. INPUT: - - ``other`` -- a stream of coefficients + - ``other`` -- a stream EXAMPLES:: @@ -2818,15 +3021,16 @@ def __eq__(self, other): sage: M2 == Stream_shift(F, 2) True """ - return (isinstance(other, type(self)) and self._shift == other._shift + return (isinstance(other, type(self)) + and self._shift == other._shift and self._series == other._series) def is_nonzero(self): r""" Return ``True`` if and only if this stream is known - to be nonzero. + to be non-zero. - An assumption of this class is that it is nonzero. + An assumption of this class is that it is non-zero. EXAMPLES:: @@ -2838,15 +3042,278 @@ def is_nonzero(self): """ return self._series.is_nonzero() + def is_uninitialized(self): + """ + Return ``True`` if ``self`` is an uninitialized stream. -class Stream_derivative(Stream_inexact): - """ - Operator for taking derivatives of a stream. + EXAMPLES:: - INPUT: + sage: from sage.data_structures.stream import Stream_uninitialized, Stream_shift + sage: C = Stream_uninitialized(0) + sage: S = Stream_shift(C, 5) + sage: S.is_uninitialized() + True + """ + return self._series.is_uninitialized() - - ``series`` -- a :class:`Stream` + +class Stream_truncated(Stream_unary): + """ + Operator for shifting a non-zero, non-exact stream that has + been shifted below its minimal valuation. + + Instances of this class share the cache with its input stream. + + INPUT: + + - ``series`` -- a :class:`Stream_inexact` + - ``shift`` -- an integer + - ``minimal_valuation`` -- an integer; this is also the approximate order + """ + def __init__(self, series, shift, minimal_valuation): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_truncated + sage: def fun(n): return 1 if ZZ(n).is_power_of(2) else 0 + sage: s = Stream_truncated(Stream_function(fun, True, 0), -5, 0) + sage: TestSuite(s).run(skip="_test_pickling") + sage: s = Stream_truncated(Stream_function(fun, False, 0), -5, 0) + sage: TestSuite(s).run(skip="_test_pickling") + + Verify that we have used the cache to see if we can get the + true order at initialization:: + + sage: f = Stream_function(fun, True, 0) + sage: [f[i] for i in range(0, 10)] + [0, 1, 1, 0, 1, 0, 0, 0, 1, 0] + sage: f._cache + {1: 1, 2: 1, 3: 0, 4: 1, 5: 0, 6: 0, 7: 0, 8: 1, 9: 0} + sage: s = Stream_truncated(f, -5, 0) + sage: s._true_order + True + sage: s._approximate_order + 3 + sage: f = Stream_function(fun, False, 0) + sage: [f[i] for i in range(0, 10)] + [0, 1, 1, 0, 1, 0, 0, 0, 1, 0] + sage: f._cache + [1, 1, 0, 1, 0, 0, 0, 1, 0] + sage: s = Stream_truncated(f, -5, 0) + sage: s._true_order + True + sage: s._approximate_order + 3 + """ + super().__init__(series, series._is_sparse, False) + assert isinstance(series, Stream_inexact) + # We share self._series._cache but not self._series._approximate order + # self._approximate_order cannot be updated by self._series.__getitem__ + self._cache = series._cache + self._shift = shift + ao = minimal_valuation + # Try to find the true order based on the values already computed + if self._is_sparse: + ao -= shift + while ao in self._cache: + if self._cache[ao]: + self._true_order = True + break + ao += 1 + ao += shift + else: + start = ao - (series._approximate_order + shift) + for val in self._cache[start:]: + if val: + self._true_order = True + break + ao += 1 + self._approximate_order = ao + + def __getitem__(self, n): + """ + Return the ``n``-th coefficient of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_truncated + sage: def fun(n): return 1 if ZZ(n).is_power_of(2) else 0 + sage: s = Stream_truncated(Stream_function(fun, True, 0), -5, 0) + sage: [s[i] for i in range(10)] + [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] + sage: s._approximate_order + 3 + sage: s._true_order + True + sage: s = Stream_truncated(Stream_function(fun, False, 0), -5, 0) + sage: s[10] + 0 + sage: s._approximate_order + 3 + sage: s._true_order + True + """ + if n < self._approximate_order: + return ZZ.zero() + ret = self._series[n-self._shift] + if not self._true_order: + if self._is_sparse: + ao = self._approximate_order - self._shift + while ao in self._cache: + if self._cache[ao]: + self._true_order = True + break + ao += 1 + self._approximate_order = ao + self._shift + else: # dense case + offset = self._series._approximate_order + self._shift + start = self._approximate_order - offset + for val in self._cache[start:]: + if val: + self._true_order = True + break + self._approximate_order += 1 + return ret + + def __hash__(self): + """ + Return the hash of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_truncated + sage: def fun(n): return 1 if ZZ(n).is_power_of(2) else 0 + sage: s = Stream_truncated(Stream_function(fun, True, 0), -5, 0) + sage: hash(s) == hash(s) + True + """ + return hash((type(self), self._series)) + + def __eq__(self, other): + """ + Test equality. + + INPUT: + + - ``other`` -- a stream of coefficients + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_truncated + sage: def fun(n): return 1 if ZZ(n).is_power_of(2) else 0 + sage: f = Stream_function(fun, True, 0) + sage: sm5 = Stream_truncated(f, -5, 0) + sage: sm2 = Stream_truncated(f, -2, 0) + sage: sm2 == sm5 + False + sage: sm5 == Stream_truncated(f, -5, 0) + True + """ + # We assume that comparisons of this class are done only by elements in + # a common ring; in particular, the minimum order will be the same. + return (isinstance(other, type(self)) and self._shift == other._shift + and self._series == other._series) + + def order(self): + """ + Return the order of ``self``, which is the minimum index ``n`` such + that ``self[n]`` is non-zero. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_truncated + sage: def fun(n): return 1 if ZZ(n).is_power_of(2) else 0 + sage: s = Stream_truncated(Stream_function(fun, True, 0), -5, 0) + sage: s.order() + 3 + sage: s = Stream_truncated(Stream_function(fun, False, 0), -5, 0) + sage: s.order() + 3 + + Check that it also worked properly with the cache partially filled:: + + sage: f = Stream_function(fun, True, 0) + sage: dummy = [f[i] for i in range(10)] + sage: s = Stream_truncated(f, -5, 0) + sage: s.order() + 3 + sage: f = Stream_function(fun, False, 0) + sage: dummy = [f[i] for i in range(10)] + sage: s = Stream_truncated(f, -5, 0) + sage: s.order() + 3 + """ + if self._true_order: + return self._approximate_order + if self._is_sparse: + n = self._approximate_order + cache = self._series._cache + while True: + if n - self._shift in cache: + if cache[n-self._shift]: + self._approximate_order = n + self._true_order = True + return n + elif self[n]: + return n + n += 1 + # dense case + return super().order() + + def is_nonzero(self): + r""" + Return ``True`` if and only if this stream is known + to be non-zero. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_truncated + sage: def fun(n): return 1 if ZZ(n).is_power_of(2) else 0 + sage: f = Stream_function(fun, False, 0) + sage: [f[i] for i in range(0, 4)] + [0, 1, 1, 0] + sage: f._cache + [1, 1, 0] + sage: s = Stream_truncated(f, -5, 0) + sage: s.is_nonzero() + False + sage: [f[i] for i in range(7,10)] # updates the cache of s + [0, 1, 0] + sage: s.is_nonzero() + True + + sage: f = Stream_function(fun, True, 0) + sage: [f[i] for i in range(0, 4)] + [0, 1, 1, 0] + sage: f._cache + {1: 1, 2: 1, 3: 0} + sage: s = Stream_truncated(f, -5, 0) + sage: s.is_nonzero() + False + sage: [f[i] for i in range(7,10)] # updates the cache of s + [0, 1, 0] + sage: s.is_nonzero() + True + """ + if self._is_sparse: + return any(c for n, c in self._series._cache.items() + if n + self._shift >= self._approximate_order) + offset = self._series._approximate_order + self._shift + start = self._approximate_order - offset + return any(self._cache[start:]) + + +class Stream_derivative(Stream_unary): + """ + Operator for taking derivatives of a non-exact stream. + + INPUT: + + - ``series`` -- a :class:`Stream` - ``shift`` -- a positive integer + - ``is_sparse`` -- boolean """ def __init__(self, series, shift, is_sparse): """ @@ -2859,9 +3326,8 @@ def __init__(self, series, shift, is_sparse): sage: f2 = Stream_derivative(f, 2, True) sage: TestSuite(f2).run() """ - self._series = series self._shift = shift - super().__init__(is_sparse, False) + super().__init__(series, is_sparse, False) @lazy_attribute def _approximate_order(self): @@ -2905,7 +3371,7 @@ def __getitem__(self, n): sage: [f2[i] for i in range(-1, 4)] [0, 2, 6, 12, 20] """ - return (prod(n+k for k in range(1, self._shift + 1)) + return (prod(n + k for k in range(1, self._shift + 1)) * self._series[n + self._shift]) def __hash__(self): @@ -2923,17 +3389,16 @@ def __hash__(self): True sage: hash(f) == hash(g) False - """ return hash((type(self), self._series, self._shift)) def __eq__(self, other): """ - Test equality. + Return whether ``self`` and ``other`` are known to be equal. INPUT: - - ``other`` -- a stream of coefficients + - ``other`` -- a stream EXAMPLES:: @@ -2947,13 +3412,14 @@ def __eq__(self, other): sage: f == Stream_derivative(a, 1, True) True """ - return (isinstance(other, type(self)) and self._shift == other._shift + return (isinstance(other, type(self)) + and self._shift == other._shift and self._series == other._series) def is_nonzero(self): r""" Return ``True`` if and only if this stream is known - to be nonzero. + to be non-zero. EXAMPLES:: @@ -2965,3 +3431,323 @@ def is_nonzero(self): True """ return self._series.is_nonzero() + + +class Stream_infinite_operator(Stream): + r""" + Stream defined by applying an operator an infinite number of times. + + The ``iterator`` returns elements `s_i` to compute an infinite operator. + The valuation of `s_i` is weakly increasing as we iterate over `I` and + there are only finitely many terms with any fixed valuation. + In particular, this *assumes* the result is nonzero. + + .. WARNING:: + + This does not check that the input is valid. + + INPUT: + + - ``iterator`` -- the iterator for the factors + """ + def __init__(self, iterator): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_sum + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: it = (t^n / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_sum(it) + """ + self._op_iter = iterator + self._cur = None + self._cur_order = -infinity + super().__init__(False) + + @lazy_attribute + def _approximate_order(self): + r""" + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_sum, Stream_infinite_product + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: it = (t^n / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_sum(it) + sage: f._approximate_order + 1 + sage: it = (t^n for n in PositiveIntegers()) + sage: f = Stream_infinite_product(it) + sage: f._approximate_order + 0 + sage: it = (t^(n-10) for n in PositiveIntegers()) + sage: f = Stream_infinite_product(it) + sage: f._approximate_order + -45 + """ + if self._cur is None: + self._advance() + while self._cur_order <= 0: + self._advance() + return self._cur._coeff_stream._approximate_order + + def _advance(self): + r""" + Advance the iterator so that the approximate order increases + by at least one. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_sum + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: it = (n * t^n for n in range(10)) + sage: f = Stream_infinite_sum(it) + sage: f._cur is None + True + sage: f._advance() + sage: f._cur + t + 2*t^2 + sage: f._cur_order + 2 + sage: for _ in range(20): + ....: f._advance() + sage: f._cur + t + 2*t^2 + 3*t^3 + 4*t^4 + 5*t^5 + 6*t^6 + 7*t^7 + 8*t^8 + 9*t^9 + sage: f._cur_order + +Infinity + + sage: it = (t^(n//3) / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_sum(it) + sage: f._advance() + sage: f._cur + 2 + 3*t + 3*t^2 + 3*t^3 + O(t^4) + sage: f._advance() + sage: f._cur + 2 + 5*t + 6*t^2 + 6*t^3 + 6*t^4 + O(t^5) + """ + if self._cur is None: + temp = next(self._op_iter) + if isinstance(temp._coeff_stream, Stream_zero): + self._advance() + return + self.initial(temp) + self._cur_order = temp._coeff_stream._approximate_order + + order = self._cur_order + while order == self._cur_order: + try: + next_factor = next(self._op_iter) + except StopIteration: + self._cur_order = infinity + return + if isinstance(next_factor._coeff_stream, Stream_zero): + continue + coeff_stream = next_factor._coeff_stream + while coeff_stream._approximate_order < order: + # This check also updates the next_factor._approximate_order + if coeff_stream[coeff_stream._approximate_order]: + order = coeff_stream._approximate_order + raise ValueError(f"invalid product computation with invalid order {order} < {self._cur_order}") + self.apply_operator(next_factor) + order = coeff_stream._approximate_order + # We check to see if we need to increment the order + if order == self._cur_order and not coeff_stream[order]: + order += 1 + self._cur_order = order + + def __getitem__(self, n): + r""" + Return the ``n``-th coefficient of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_sum + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: it = (t^n / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_sum(it) + sage: f[2] + 2 + sage: f[5] + 5 + """ + while n >= self._cur_order: + self._advance() + return self._cur[n] + + def order(self): + r""" + Return the order of ``self``, which is the minimum index ``n`` such + that ``self[n]`` is nonzero. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_sum + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: it = (t^(5+n) / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_sum(it) + sage: f.order() + 6 + """ + return self._approximate_order + + def __hash__(self): + r""" + Return the hash of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_sum + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: it = (t^n / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_sum(it) + sage: hash(f) == hash((type(f), f._op_iter)) + True + """ + return hash((type(self), self._op_iter)) + + def __ne__(self, other): + r""" + Return whether ``self`` and ``other`` are known to be equal. + + INPUT: + + - ``other`` -- a stream + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_sum + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: itf = (t^n / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_sum(itf) + sage: itg = (t^(2*n-1) / (1 - t) for n in PositiveIntegers()) + sage: g = Stream_infinite_sum(itg) + sage: f != g + False + sage: f[10] + 10 + sage: g[10] + 5 + sage: f != g + True + """ + if not isinstance(other, type(self)): + return True + ao = min(self._approximate_order, other._approximate_order) + if any(self[i] != other[i] for i in range(ao, min(self._cur_order, other._cur_order))): + return True + return False + + def is_nonzero(self): + r""" + Return ``True`` if and only if this stream is known + to be nonzero. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_sum + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: it = (t^n / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_sum(it) + sage: f.is_nonzero() + True + """ + return True + + +class Stream_infinite_sum(Stream_infinite_operator): + r""" + Stream defined by an infinite sum. + + The ``iterator`` returns elements `s_i` to compute the product + `\sum_{i \in I} s_i`. See :class:`Stream_infinite_operator` + for restrictions on the `s_i`. + + INPUT: + + - ``iterator`` -- the iterator for the factors + """ + def initial(self, obj): + r""" + Set the initial data. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_sum + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: it = (t^n / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_sum(it) + sage: f._cur is None + True + sage: f._advance() # indirect doctest + sage: f._cur + t + 2*t^2 + 2*t^3 + 2*t^4 + O(t^5) + """ + self._cur = obj + + def apply_operator(self, next_obj): + r""" + Apply the operator to ``next_obj``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_sum + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: it = (t^(n//2) / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_sum(it) + sage: f._advance() + sage: f._advance() # indirect doctest + sage: f._cur + 1 + 3*t + 4*t^2 + 4*t^3 + 4*t^4 + O(t^5) + """ + self._cur += next_obj + + +class Stream_infinite_product(Stream_infinite_operator): + r""" + Stream defined by an infinite product. + + The ``iterator`` returns elements `p_i` to compute the product + `\prod_{i \in I} (1 + p_i)`. See :class:`Stream_infinite_operator` + for restrictions on the `p_i`. + + INPUT: + + - ``iterator`` -- the iterator for the factors + """ + def initial(self, obj): + r""" + Set the initial data. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_product + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: it = (t^n / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_product(it) + sage: f._cur is None + True + sage: f._advance() # indirect doctest + sage: f._cur + 1 + t + 2*t^2 + 3*t^3 + 4*t^4 + 5*t^5 + 6*t^6 + O(t^7) + """ + self._cur = obj + 1 + + def apply_operator(self, next_obj): + r""" + Apply the operator to ``next_obj``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_infinite_product + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: it = (t^n / (1 - t) for n in PositiveIntegers()) + sage: f = Stream_infinite_product(it) + sage: f._advance() + sage: f._advance() # indirect doctest + sage: f._cur + 1 + t + 2*t^2 + 4*t^3 + 6*t^4 + 9*t^5 + 13*t^6 + O(t^7) + """ + self._cur = self._cur + self._cur * next_obj diff --git a/src/sage/databases/conway.py b/src/sage/databases/conway.py index d5d83431ea3..600c5a7c1ff 100644 --- a/src/sage/databases/conway.py +++ b/src/sage/databases/conway.py @@ -179,7 +179,7 @@ def __iter__(self): def polynomial(self, p, n): """ Return the Conway polynomial of degree ``n`` over ``GF(p)``, - or raise a RuntimeError if this polynomial is not in the + or raise a :class:`RuntimeError` if this polynomial is not in the database. .. NOTE:: diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index f6364976dc7..54e83d639ad 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -51,7 +51,7 @@ import sage.schemes.elliptic_curves.constructor as elliptic from .sql_db import SQLDatabase, verify_column from sage.features.databases import DatabaseCremona -from sage.misc.misc import walltime +from sage.misc.timing import walltime import re import string @@ -217,7 +217,7 @@ def cremona_letter_code(n): Traceback (most recent call last): ... ValueError: Cremona letter codes are only defined for non-negative integers - sage: cremona_letter_code(x) + sage: cremona_letter_code(x) # needs sage.symbolic Traceback (most recent call last): ... ValueError: Cremona letter codes are only defined for non-negative integers @@ -1377,7 +1377,7 @@ def _init_from_ftpdata(self, ftpdata, largest_conductor=0): if largest_conductor: print("largest conductor =", largest_conductor) - self.__largest_conductor__ = largest_conductor + self.__largest_conductor__ = largest_conductor # Since July 2014 the data files have been arranged in # subdirectories (see trac #16903). diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 99e96a9b816..b78e582d91e 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -1493,6 +1493,7 @@ def read_markov(bas_ele, variables, num_strands=4): EXAMPLES:: + sage: # needs sympy sage: from sage.databases.cubic_hecke_db import read_markov sage: from sympy import var sage: u, v, w, s = var('u, v, w, s') diff --git a/src/sage/databases/db_modular_polynomials.py b/src/sage/databases/db_modular_polynomials.py index d9f4b0752c2..4e0422539fc 100644 --- a/src/sage/databases/db_modular_polynomials.py +++ b/src/sage/databases/db_modular_polynomials.py @@ -20,16 +20,17 @@ def _dbz_to_string(name): r""" TESTS:: + sage: # optional - database_kohel sage: from sage.databases.db_modular_polynomials import _dbz_to_string - sage: _dbz_to_string('PolMod/Atk/pol.002.dbz') # optional - database_kohel + sage: _dbz_to_string('PolMod/Atk/pol.002.dbz') '3 0 1 \n2 1 -1 \n2 0 744 \n1 1 -1 \n1 0 184512 \n0 2 1 \n0 1 7256 \n0 0 15252992 \n' - sage: _dbz_to_string('PolMod/Cls/pol.001.dbz') # optional - database_kohel + sage: _dbz_to_string('PolMod/Cls/pol.001.dbz') '1 0 1 \n' - sage: _dbz_to_string('PolMod/Eta/pol.002.dbz') # optional - database_kohel + sage: _dbz_to_string('PolMod/Eta/pol.002.dbz') '3 0 1 \n2 0 48 \n1 1 -1 \n1 0 768 \n0 0 4096 \n' - sage: _dbz_to_string('PolMod/EtaCrr/crr.02.002.dbz') # optional - database_kohel + sage: _dbz_to_string('PolMod/EtaCrr/crr.02.002.dbz') '2 1 1 \n2 0 -48 \n1 1 2304 \n0 2 -4096 \n0 1 196608 \n' - sage: _dbz_to_string('PolHeeg/Cls/0000001-0005000/pol.0000003.dbz') # optional - database_kohel + sage: _dbz_to_string('PolHeeg/Cls/0000001-0005000/pol.0000003.dbz') '0\n1\n' """ from sage.env import SAGE_SHARE diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index 452abbcce8e..86ab944744a 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -259,6 +259,7 @@ def mapping(sigma): from sage.combinat.colored_permutations import SignedPermutation, SignedPermutations from sage.combinat.plane_partition import PlanePartition from sage.combinat.decorated_permutation import DecoratedPermutation, DecoratedPermutations +from sage.combinat.set_partition_ordered import OrderedSetPartition, OrderedSetPartitions ###################################################################### # the FindStat URLs @@ -1499,7 +1500,8 @@ def __call__(self, elt): from sage.repl.preparse import preparse try: l = {} - code = "from sage.all import *\n" + preparse(self.sage_code()) + environment = 'sage.all' + code = f"from {environment} import *\n" + preparse(self.sage_code()) exec(code, l) except SyntaxError: raise ValueError("could not execute verified code for %s" % self) @@ -1555,11 +1557,12 @@ def reset(self): Check that new statistics and maps cannot be reset:: - sage: q = findstat([(d, randint(1, 1000)) for d in DyckWords(4)]) # optional -- internet - sage: q.set_description("Random values on Dyck paths.") # optional -- internet - sage: print(q.description()) # optional -- internet + sage: # optional - internet + sage: q = findstat([(d, randint(1, 1000)) for d in DyckWords(4)]) + sage: q.set_description("Random values on Dyck paths.") + sage: print(q.description()) Random values on Dyck paths. - sage: q.reset() # optional -- internet + sage: q.reset() Traceback (most recent call last): ... ValueError: cannot reset values of St000000: a new statistic on Dyck paths @@ -2094,7 +2097,7 @@ def oeis_search(self, search_size=32, verbose=True): if counter >= 4: if verbose: print('Searching the OEIS for "%s"' % OEIS_string) - return oeis(str(OEIS_string)) # in python 2.7, oeis does not like unicode + return oeis(OEIS_string) if verbose: print("Too little information to search the OEIS for this statistic (only %s values given)." % counter) @@ -2370,7 +2373,7 @@ def submit(self, max_values=FINDSTAT_MAX_SUBMISSION_VALUES): sage: s.set_description(u"Mรถbius") # optional -- internet sage: s.submit() # optional -- webbrowser """ - args = dict() + args = {} args["OriginalStatistic"] = self.id_str() args["Domain"] = self.domain().id_str() args["Values"] = self.first_terms_str(max_values=max_values) @@ -2918,7 +2921,6 @@ def browse(self): """ webbrowser.open(FINDSTAT_URL_STATISTICS + self.id_str()) - def info(self): """ Print a detailed description of the compound statistic. @@ -3280,14 +3282,15 @@ def set_properties_raw(self, value): EXAMPLES:: - sage: from sage.databases.findstat import FindStatMap # optional -- internet - sage: FindStatMap(61).set_properties_raw('surjective') # optional -- internet - sage: FindStatMap(61).properties_raw() # optional -- internet + sage: # optional - internet + sage: from sage.databases.findstat import FindStatMap + sage: FindStatMap(61).set_properties_raw('surjective') + sage: FindStatMap(61).properties_raw() 'surjective' - sage: FindStatMap(61) # optional -- internet + sage: FindStatMap(61) Mp00061(modified): to increasing tree - sage: FindStatMap(61).reset() # optional -- internet - sage: FindStatMap(61) # optional -- internet + sage: FindStatMap(61).reset() + sage: FindStatMap(61) Mp00061: to increasing tree """ if value != self.properties_raw(): @@ -4187,7 +4190,7 @@ def __hash__(self): EXAMPLES:: sage: from sage.databases.findstat import FindStatCollections - sage: set(c for c in FindStatCollections()) # optional -- internet + sage: set(FindStatCollections()) # optional -- internet {Cc0001: Permutations, Cc0002: Integer partitions, ... @@ -4283,13 +4286,14 @@ def in_range(self, element): EXAMPLES:: + sage: # optional - internet sage: from sage.databases.findstat import FindStatCollection - sage: c = FindStatCollection("GelfandTsetlinPatterns") # optional -- internet - sage: c.in_range(GelfandTsetlinPattern([[2, 1], [1]])) # optional -- internet + sage: c = FindStatCollection("GelfandTsetlinPatterns") + sage: c.in_range(GelfandTsetlinPattern([[2, 1], [1]])) True - sage: c.in_range(GelfandTsetlinPattern([[3, 1], [1]])) # optional -- internet + sage: c.in_range(GelfandTsetlinPattern([[3, 1], [1]])) True - sage: c.in_range(GelfandTsetlinPattern([[7, 1], [1]])) # optional -- internet + sage: c.in_range(GelfandTsetlinPattern([[7, 1], [1]])) False TESTS:: @@ -4512,6 +4516,7 @@ def name(self, style="singular"): return self._data["NamePlural"] raise ValueError("argument 'style' (=%s) must be 'singular' or 'plural'" % style) + from collections import namedtuple _SupportedFindStatCollection = namedtuple("SupportedFindStatCollection", ["string_to_element", @@ -4670,7 +4675,13 @@ def name(self, style="singular"): for i, v in enumerate(x, 1))) + "]", DecoratedPermutations, lambda x: x.size(), - lambda x: isinstance(x, DecoratedPermutation))} + lambda x: isinstance(x, DecoratedPermutation)), + "OrderedSetPartitions": + _SupportedFindStatCollection(lambda x: OrderedSetPartition(literal_eval(x.replace('{','[').replace('}',']'))), + str, + OrderedSetPartitions, + lambda x: x.size(), + lambda x: isinstance(x, OrderedSetPartition))} class FindStatCollections(UniqueRepresentation, Parent): @@ -4738,6 +4749,7 @@ def __init__(self): # fields = "SageCodeElementToString,SageCodeElementsOnLevel,SageCodeStringToElement" # url = FINDSTAT_API_COLLECTIONS + id + "?fields=" + fields # print(json.load(urlopen(url))["included"]["Collections"][id]) + def position(item): try: return tuple(_SupportedFindStatCollections).index(item[1]["NameWiki"]) diff --git a/src/sage/databases/jones.py b/src/sage/databases/jones.py index 97741e98be5..26d4dbaa373 100644 --- a/src/sage/databases/jones.py +++ b/src/sage/databases/jones.py @@ -68,8 +68,10 @@ import os -from sage.rings.all import NumberField, RationalField, PolynomialRing -from sage.misc.misc import powerset +from sage.rings.number_field.number_field import NumberField +from sage.rings.rational_field import RationalField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.combinat.subset import powerset from sage.env import SAGE_SHARE from sage.misc.persist import load, save @@ -254,20 +256,21 @@ def ramified_at(self, S, d=None, var='a'): EXAMPLES:: - sage: J = JonesDatabase() # optional - database_jones_numfield - sage: J.ramified_at([101,109]) # optional - database_jones_numfield + sage: # optional - database_jones_numfield + sage: J = JonesDatabase() + sage: J.ramified_at([101,109]) [] - sage: J.ramified_at([109]) # optional - database_jones_numfield + sage: J.ramified_at([109]) [Number Field in a with defining polynomial x^2 - 109, Number Field in a with defining polynomial x^3 - x^2 - 36*x + 4, Number Field in a with defining polynomial x^4 - x^3 + 14*x^2 + 34*x + 393] - sage: J.ramified_at(101) # optional - database_jones_numfield + sage: J.ramified_at(101) [Number Field in a with defining polynomial x^2 - 101, Number Field in a with defining polynomial x^4 - x^3 + 13*x^2 - 19*x + 361, Number Field in a with defining polynomial x^5 + x^4 - 6*x^3 - x^2 + 18*x + 4, Number Field in a with defining polynomial x^5 + 2*x^4 + 7*x^3 + 4*x^2 + 11*x - 6, Number Field in a with defining polynomial x^5 - x^4 - 40*x^3 - 93*x^2 - 21*x + 17] - sage: J.ramified_at((2, 5, 29), 3, 'c') # optional - database_jones_numfield + sage: J.ramified_at((2, 5, 29), 3, 'c') [Number Field in c with defining polynomial x^3 - x^2 - 8*x - 28, Number Field in c with defining polynomial x^3 - x^2 + 10*x + 102, Number Field in c with defining polynomial x^3 - x^2 - 48*x - 188, diff --git a/src/sage/databases/knotinfo_db.py b/src/sage/databases/knotinfo_db.py index d70e6be6bac..2dba694604d 100644 --- a/src/sage/databases/knotinfo_db.py +++ b/src/sage/databases/knotinfo_db.py @@ -45,8 +45,8 @@ class KnotInfoColumnTypes(Enum): <KnotInfoColumnTypes.OnlyLinks: 'L'>, <KnotInfoColumnTypes.KnotsAndLinks: 'B'>] """ - OnlyKnots = 'K' # column that is only used in the KnotInfo table - OnlyLinks = 'L' # column that is only used in the LinkInfo table + OnlyKnots = 'K' # column that is only used in the KnotInfo table + OnlyLinks = 'L' # column that is only used in the LinkInfo table KnotsAndLinks = 'B' # column that is only used in both tables @@ -262,7 +262,6 @@ def sobj_column(self): """ return 'column_dict.sobj' - def sobj_data(self, column): r""" Return the file name under which the data of the given @@ -311,13 +310,10 @@ def diagram_url(self, fname, single=False): else: return '%sdiagram_display.php?%s' %(self.url(), fname) - knots = ['https://knotinfo.math.indiana.edu/', 'knotinfo_data_complete'] links = ['https://linkinfo.sitehost.iu.edu/', 'linkinfo_data_complete'] - - #---------------------------------------------------------------------------------------------------------------------------- # Class to provide data for knots and links from the KnotInfo web-page #---------------------------------------------------------------------------------------------------------------------------- @@ -406,7 +402,6 @@ def create_filecache(self, force=False): self._create_data_sobj(sobj_path=sobj_path) return - def version(self): r""" Return the version of the database currently installed on the device. @@ -439,7 +434,6 @@ def version(self): from database_knotinfo import version return version() - def demo_version(self): r""" Return whether the KnotInfo databases are installed completely or @@ -457,7 +451,7 @@ def demo_version(self): num_knots_file = os.path.join(self._sobj_path, self.filename.knots.num_knots(self.version())) from builtins import FileNotFoundError try: - self._num_knots = load(num_knots_file) + self._num_knots = load(num_knots_file) except FileNotFoundError: self.create_filecache() self._demo = False @@ -483,7 +477,6 @@ def knot_list(self): self._knot_list = link_list() return self._knot_list - def link_list(self): r""" Return the LinkInfo table rows as Python list. @@ -557,8 +550,6 @@ def _create_col_dict_sobj(self, sobj_path=None): save(column_dict, '%s/%s' %(sobj_path, self.filename.knots.sobj_column())) - - def _create_data_sobj(self, sobj_path=None): r""" Create ``sobj`` files containing the contents of the whole table. @@ -591,15 +582,15 @@ def _create_data_sobj(self, sobj_path=None): # ---------------------------------------------------------------- # Columns that exist for knots and links # ---------------------------------------------------------------- - column_dict = load('%s/%s' %(sobj_path, self.filename.knots.sobj_column())) + column_dict = load('%s/%s' %(sobj_path, self.filename.knots.sobj_column())) cols = KnotInfoColumns('ColsTemp', column_dict) for col in cols: val_list = [] - if col.column_type() != col.types.OnlyLinks: - for i in range(1 , len_knots): + if col.column_type() != col.types.OnlyLinks: + for i in range(1, len_knots): if col.name == self._names_column: - row_dict[self._knot_prefix + knot_list[i][col.name]] = [i - 1 , 1] + row_dict[self._knot_prefix + knot_list[i][col.name]] = [i - 1, 1] val_list.append(knot_list[i][col.name]) @@ -621,7 +612,6 @@ def _create_data_sobj(self, sobj_path=None): save(row_dict, '%s/%s' %(sobj_path, self.filename.knots.sobj_row())) - @cached_method def columns(self): r""" @@ -639,7 +629,6 @@ def columns(self): column_dict = self.read_column_dict() return KnotInfoColumns('Columns', column_dict) - # ------------------------------------------------------------------------------------------------------------- # read the dictionary for the column names from sobj-file # ------------------------------------------------------------------------------------------------------------- @@ -717,7 +706,6 @@ def row_names(self): names = self.read(self.columns().name) return {k:names[v[0]] for k, v in row_dict.items()} - # ------------------------------------------------------------------------------------------------------------- # read the number of knots contained in the database (without proper links) from the according sobj-file. # ------------------------------------------------------------------------------------------------------------- @@ -741,7 +729,6 @@ def read_num_knots(self): self.demo_version() return self._num_knots - # ------------------------------------------------------------------------------------------------------------- # read an sobj-file obtained from KnotInfo database # ------------------------------------------------------------------------------------------------------------- @@ -803,7 +790,6 @@ def _test_database(self, **options): tester.assertTrue(all(L.is_recoverable(unique=False) for L, in sample)) - column_demo_sample = { 'name': ['Name', KnotInfoColumnTypes.KnotsAndLinks], 'name_unoriented': ['Name - Unoriented', KnotInfoColumnTypes.OnlyLinks], @@ -825,6 +811,13 @@ def _test_database(self, **options): 'kauffman_polynomial': ['Kauffman', KnotInfoColumnTypes.KnotsAndLinks], 'khovanov_polynomial': ['Khovanov', KnotInfoColumnTypes.KnotsAndLinks], 'khovanov_torsion_polynomial': ['Khovanov Torsion', KnotInfoColumnTypes.OnlyKnots], + 'khovanov_unreduced_integral_polynomial': ['KH Unred Z Poly', KnotInfoColumnTypes.OnlyKnots], + 'khovanov_reduced_integral_polynomial': ['KH Red Z Poly', KnotInfoColumnTypes.OnlyKnots], + 'khovanov_reduced_rational_polynomial': ['KH Red Q Poly', KnotInfoColumnTypes.OnlyKnots], + 'khovanov_reduced_mod2_polynomial': ['KH Red Mod2 Poly', KnotInfoColumnTypes.OnlyKnots], + 'khovanov_odd_integral_polynomial': ['KH Odd Red Z Poly', KnotInfoColumnTypes.OnlyKnots], + 'khovanov_odd_rational_polynomial': ['KH Odd Red Q Poly', KnotInfoColumnTypes.OnlyKnots], + 'khovanov_odd_mod2_polynomial': ['KH Red Odd Mod2 Poly', KnotInfoColumnTypes.OnlyKnots], 'determinant': ['Determinant', KnotInfoColumnTypes.KnotsAndLinks], 'positive': ['Positive', KnotInfoColumnTypes.OnlyKnots], 'fibered': ['Fibered', KnotInfoColumnTypes.OnlyKnots], @@ -1147,5 +1140,82 @@ def _test_database(self, **options): 'Q^(-9)t^(-3)+Q^(-7)t^(-2)+Q^(-5)t^(-1)+Q^(-3)+Qt^2', 'Q^(-5)t^(-2)+Q^(-3)t^(-1)+Q^(-1)+Qt+Q^3t^2+Q^5t^3', 'Q^(-19)t^(-6)+Q^(-15)t^(-4)+Q^(-11)t^(-2)', - 'Q^(-15)t^(-6)+Q^(-11)t^(-4)+Q^(-9)t^(-3)+Q^(-7)t^(-2)+Q^(-5)t^(-1)'] + 'Q^(-15)t^(-6)+Q^(-11)t^(-4)+Q^(-9)t^(-3)+Q^(-7)t^(-2)+Q^(-5)t^(-1)'], + dc.khovanov_unreduced_integral_polynomial: [ + '', + 'q + q^(3) + t^(2) q^(5) + t^(3) q^(9) + t^(3) q^(7) T^(2)', + 't^(-2) q^(-5) + t^(-1) q^(-1) + q^(-1) + q + t q + t^(2) q^(5) + t^(-1) q^(-3) T^(2) + t^(2) q^(3) T^(2)', + 'q^(3) + q^(5) + t^(2) q^(7) + t^(3) q^(11) + t^(4) q^(11) + t^(5) q^(15) + t^(3) q^(9) T^(2) + t^(5) q^(13) T^(2)', + 'q + q^(3) + t q^(3) + t^(2) q^(5) + t^(2) q^(7) + t^(3) q^(9) + t^(4) q^(9) + t^(5) q^(13) + t^(2) q^(5) T^(2) + t^(3) q^(7) T^(2) + t^(5) q^(11) T^(2)', + 't^(-2) q^(-5) + t^(-1) q^(-1) + 2 q^(-1) + q + t q + t q^(3) + t^(2) q^(5) + t^(3) q^(5) + t^(4) q^(9) + t^(-1) q^(-3) T^(2) + t q T^(2) + t^(2) q^(3) T^(2) + t^(4) q^(7) T^(2)', + 't^(-2) q^(-3) + t^(-1) q + 2 q + q^(3) + t q^(3) + t q^(5) + t^(2) q^(5) + t^(2) q^(7) + t^(3) q^(7) + t^(3) q^(9) + t^(4) q^(11) + t^(-1) q^(-1) T^(2) + t q^(3) T^(2) + t^(2) q^(5) T^(2) + t^(3) q^(7) T^(2) + t^(4) q^(9) T^(2)', + 't^(-3) q^(-7) + t^(-2) q^(-5) + t^(-2) q^(-3) + t^(-1) q^(-3) + t^(-1) q^(-1) + 2 q^(-1) + 2 q + t q + t q^(3) + t^(2) q^(3) + t^(2) q^(5) + t^(3) q^(7) + t^(-2) q^(-5) T^(2) + t^(-1) q^(-3) T^(2) + q^(-1) T^(2) + t q T^(2) + t^(2) q^(3) T^(2) + t^(3) q^(5) T^(2)', + 'q^(5) + q^(7) + t^(2) q^(9) + t^(3) q^(13) + t^(4) q^(13) + t^(5) q^(17) + t^(6) q^(17) + t^(7) q^(21) + t^(3) q^(11) T^(2) + t^(5) q^(15) T^(2) + t^(7) q^(19) T^(2)', + 'q + q^(3) + t q^(3) + t^(2) q^(5) + t^(2) q^(7) + t^(3) q^(7) + t^(3) q^(9) + t^(4) q^(9) + t^(4) q^(11) + t^(5) q^(13) + t^(6) q^(13) + t^(7) q^(17) + t^(2) q^(5) T^(2) + t^(3) q^(7) T^(2) + t^(4) q^(9) T^(2) + t^(5) q^(11) T^(2) + t^(7) q^(15) T^(2)'], + dc.khovanov_reduced_integral_polynomial: [ + '', + 'q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + 'q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + 'q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + 'q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + 'q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], + dc.khovanov_reduced_rational_polynomial: [ + '', + ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], + dc.khovanov_reduced_mod2_polynomial: [ + '', + ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], + dc.khovanov_odd_integral_polynomial: [ + '', + 'q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + 'q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + 'q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + 'q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + 'q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], + dc.khovanov_odd_rational_polynomial: [ + '', + ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], + dc.khovanov_odd_mod2_polynomial: [ + '', + ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'] } diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 509f0c10d46..b6eeac3499c 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -5,8 +5,8 @@ You can query the OEIS (Online Database of Integer Sequences) through Sage in order to: - - identify a sequence from its first terms. - - obtain more terms, formulae, references, etc. for a given sequence. +- identify a sequence from its first terms. +- obtain more terms, formulae, references, etc. for a given sequence. AUTHORS: @@ -21,35 +21,36 @@ EXAMPLES:: - sage: oeis - The On-Line Encyclopedia of Integer Sequences (https://oeis.org/) + sage: oeis + The On-Line Encyclopedia of Integer Sequences (https://oeis.org/) What about a sequence starting with `3, 7, 15, 1` ? :: - sage: search = oeis([3, 7, 15, 1], max_results=4) ; search # optional -- internet # random + sage: # optional - internet + sage: search = oeis([3, 7, 15, 1], max_results=4); search # random 0: A001203: Simple continued fraction expansion of Pi. 1: A240698: Partial sums of divisors of n, cf. A027750. 2: A082495: a(n) = (2^n - 1) mod n. - 3: A165416: Irregular array read by rows: The n-th row contains those distinct positive integers that each, when written in binary, occurs as a substring in binary n. - - sage: [u.id() for u in search] # optional -- internet # random + 3: A165416: Irregular array read by rows: The n-th row contains those + distinct positive integers that each, when written in binary, + occurs as a substring in binary n. + sage: [u.id() for u in search] # random ['A001203', 'A240698', 'A082495', 'A165416'] - sage: c = search[0] ; c # optional -- internet + sage: c = search[0]; c A001203: Simple continued fraction expansion of Pi. :: - sage: c.first_terms(15) # optional -- internet + sage: # optional - internet + sage: c.first_terms(15) (3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1) - - sage: c.examples() # optional -- internet + sage: c.examples() 0: Pi = 3.1415926535897932384... 1: = 3 + 1/(7 + 1/(15 + 1/(1 + 1/(292 + ...)))) 2: = [a_0; a_1, a_2, a_3, ...] = [3; 7, 15, 1, 292, ...]. - - sage: c.comments() # optional -- internet + sage: c.comments() 0: The first 5821569425 terms were computed by _Eric W. Weisstein_ on Sep 18 2011. 1: The first 10672905501 terms were computed by _Eric W. Weisstein_ on Jul 17 2013. 2: The first 15000000000 terms were computed by _Eric W. Weisstein_ on Jul 27 2013. @@ -57,51 +58,49 @@ :: - sage: x = c.natural_object() ; type(x) # optional -- internet + sage: # optional - internet + sage: x = c.natural_object(); type(x) <class 'sage.rings.continued_fraction.ContinuedFraction_periodic'> - - sage: x.convergents()[:7] # optional -- internet + sage: x.convergents()[:7] [3, 22/7, 333/106, 355/113, 103993/33102, 104348/33215, 208341/66317] - - sage: RR(x.value()) # optional -- internet + sage: RR(x.value()) 3.14159265358979 - sage: RR(x.value()) == RR(pi) # optional -- internet + sage: RR(x.value()) == RR(pi) True -What about posets ? Are they hard to count ? To which other structures are they -related ? +What about posets? Are they hard to count? To which other structures are they +related? :: + sage: # optional - internet sage: [Posets(i).cardinality() for i in range(10)] [1, 1, 2, 5, 16, 63, 318, 2045, 16999, 183231] - sage: oeis(_) # optional -- internet + sage: oeis(_) 0: A000112: Number of partially ordered sets ("posets") with n unlabeled elements. - sage: p = _[0] # optional -- internet - -:: - - sage: 'hard' in p.keywords() # optional -- internet + sage: p = _[0] + sage: 'hard' in p.keywords() True - sage: len(p.formulas()) # optional -- internet + sage: len(p.formulas()) 0 - sage: len(p.first_terms()) # optional -- internet + sage: len(p.first_terms()) 17 - -:: - - sage: p.cross_references(fetch=True) # optional -- internet # random - 0: A000798: Number of different quasi-orders (or topologies, or transitive digraphs) with n labeled elements. - 1: A001035: Number of partially ordered sets ("posets") with n labeled elements (or labeled acyclic transitive digraphs). + sage: p.cross_references(fetch=True) # random + 0: A000798: Number of different quasi-orders (or topologies, or transitive digraphs) + with n labeled elements. + 1: A001035: Number of partially ordered sets ("posets") with n labeled elements + (or labeled acyclic transitive digraphs). 2: A001930: Number of topologies, or transitive digraphs with n unlabeled nodes. 3: A006057: Number of topologies on n labeled points satisfying axioms T_0-T_4. 4: A079263: Number of constrained mixed models with n factors. 5: A079265: Number of antisymmetric transitive binary relations on n unlabeled points. - 6: A263859: Triangle read by rows: T(n,k) (n>=1, k>=0) is the number of posets with n elements and rank k (or depth k+1). + 6: A263859: Triangle read by rows: T(n,k) (n>=1, k>=0) is the number of posets + with n elements and rank k (or depth k+1). 7: A316978: Number of factorizations of n into factors > 1 with no equivalent primes. 8: A319559: Number of non-isomorphic T_0 set systems of weight n. 9: A326939: Number of T_0 sets of subsets of {1..n} that cover all n vertices. - 10: A326943: Number of T_0 sets of subsets of {1..n} that cover all n vertices and are closed under intersection. + 10: A326943: Number of T_0 sets of subsets of {1..n} that cover all n vertices and + are closed under intersection. ... What does the Taylor expansion of the `e^{e^x-1}` function have to do with @@ -109,25 +108,22 @@ :: + sage: # optional - internet, needs sage.symbolic sage: x = var('x') ; f(x) = e^(e^x - 1) - sage: L = [a*factorial(b) for a,b in taylor(f(x), x, 0, 20).coefficients()] ; L + sage: L = [a*factorial(b) for a,b in taylor(f(x), x, 0, 20).coefficients()]; L [1, 1, 2, 5, 15, 52, 203, 877, 4140, 21147, 115975, 678570, 4213597, - 27644437, 190899322, 1382958545, 10480142147, 82864869804, 682076806159, - 5832742205057, 51724158235372] - - sage: oeis(L) # optional -- internet - 0: A000110: Bell or exponential numbers: number of ways to partition a set of n labeled elements. + 27644437, 190899322, 1382958545, 10480142147, 82864869804, 682076806159, + 5832742205057, 51724158235372] + sage: oeis(L) + 0: A000110: Bell or exponential numbers: number of ways to partition + a set of n labeled elements. 1: A292935: E.g.f.: exp(exp(-x) - 1). - - sage: b = _[0] # optional -- internet - - sage: b.formulas()[0] # optional -- internet + sage: b = _[0] + sage: b.formulas()[0] 'E.g.f.: exp(exp(x) - 1).' - - sage: [i for i in b.comments() if 'prime' in i][-1] # optional -- internet + sage: [i for i in b.comments() if 'prime' in i][-1] 'Number n is prime if ...' - - sage: [n for n in range(2, 20) if (b(n)-2) % n == 0] # optional -- internet + sage: [n for n in range(2, 20) if (b(n)-2) % n == 0] [2, 3, 5, 7, 11, 13, 17, 19] .. SEEALSO:: @@ -261,18 +257,18 @@ class OEIS: Sequences. You can query it using its methods, but ``OEIS`` can also be called directly with three arguments: - - ``query`` - it can be: + - ``query`` -- it can be: - a string representing an OEIS ID (e.g. 'A000045'). - an integer representing an OEIS ID (e.g. 45). - a list representing a sequence of integers. - a string, representing a text search. - - ``max_results`` - (integer, default: 30) the maximum number of + - ``max_results`` -- (integer, default: 30) the maximum number of results to return, they are sorted according to their relevance. In any cases, the OEIS website will never provide more than 100 results. - - ``first_result`` - (integer, default: 0) allow to skip the + - ``first_result`` -- (integer, default: 0) allow to skip the ``first_result`` first results in the search, to go further. This is useful if you are looking for a sequence that may appear after the 100 first found sequences. @@ -299,16 +295,17 @@ class OEIS: sage: oeis('A000040') # optional -- internet A000040: The prime numbers. - sage: oeis(45) # optional -- internet A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. The database can be searched by subsequence:: - sage: search = oeis([1,2,3,5,8,13]) ; search # optional -- internet + sage: search = oeis([1,2,3,5,8,13]); search # optional -- internet 0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. 1: A290689: Number of transitive rooted trees with n nodes. - 2: A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) for k = 2..2n-1, n >= 2. + 2: A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; + T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) + for k = 2..2n-1, n >= 2. sage: fibo = search[0] # optional -- internet @@ -349,9 +346,10 @@ class OEIS: The database can be searched by description:: - sage: oeis('prime gap factorization', max_results=4) # optional --internet # random + sage: oeis('prime gap factorization', max_results=4) # random # optional -- internet 0: A073491: Numbers having no prime gaps in their factorization. - 1: A073485: Product of any number of consecutive primes; squarefree numbers with no gaps in their prime factorization. + 1: A073485: Product of any number of consecutive primes; squarefree numbers + with no gaps in their prime factorization. 2: A073490: Number of prime gaps in factorization of n. 3: A073492: Numbers having at least one prime gap in their factorization. @@ -362,7 +360,9 @@ class OEIS: sage: oeis([1,2,3,5,8,13]) # optional -- internet 0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. 1: A290689: Number of transitive rooted trees with n nodes. - 2: A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) for k = 2..2n-1, n >= 2. + 2: A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; + T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) + for k = 2..2n-1, n >= 2. sage: oeis('A000045') # optional -- internet A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. @@ -659,20 +659,19 @@ class OEISSequence(SageObject, UniqueRepresentation): between calling and getting item, see :meth:`__call__` for more details :: + sage: # optional - internet sage: sfibo = oeis('A039834') - sage: sfibo.first_terms()[:10] # optional -- internet + sage: sfibo.first_terms()[:10] (1, 1, 0, 1, -1, 2, -3, 5, -8, 13) - - sage: sfibo(-2) # optional -- internet + sage: sfibo(-2) 1 - sage: sfibo(3) # optional -- internet + sage: sfibo(3) 2 - sage: sfibo.offsets() # optional -- internet + sage: sfibo.offsets() (-2, 6) - - sage: sfibo[0] # optional -- internet + sage: sfibo[0] 1 - sage: sfibo[6] # optional -- internet + sage: sfibo[6] -3 .. automethod:: __call__ @@ -981,7 +980,7 @@ def keywords(self): EXAMPLES:: sage: f = oeis(53) ; f # optional -- internet - A000053: Local stops on New York City Broadway line (IRT #1) subway. + A000053: Local stops on New York City... sage: f.keywords() # optional -- internet ('nonn', 'fini', ...) @@ -1005,11 +1004,11 @@ def natural_object(self): OUTPUT: - If the sequence ``self`` corresponds to the digits of a real - number, returns the associated real number (as an element of - RealLazyField()). + number, returns the associated real number (as an element of + RealLazyField()). - If the sequence ``self`` corresponds to the convergents of a - continued fraction, returns the associated continued fraction. + continued fraction, returns the associated continued fraction. .. WARNING:: @@ -1024,25 +1023,25 @@ def natural_object(self): EXAMPLES:: - sage: g = oeis("A002852") ; g # optional -- internet + sage: g = oeis("A002852"); g # optional -- internet A002852: Continued fraction for Euler's constant (or Euler-Mascheroni constant) gamma. - sage: x = g.natural_object() ; type(x) # optional -- internet + sage: x = g.natural_object(); type(x) # optional -- internet <class 'sage.rings.continued_fraction.ContinuedFraction_periodic'> sage: RDF(x) == RDF(euler_gamma) # optional -- internet True - sage: cfg = continued_fraction(euler_gamma) - sage: x[:90] == cfg[:90] # optional -- internet + sage: cfg = continued_fraction(euler_gamma) # needs sage.symbolic + sage: x[:90] == cfg[:90] # optional - internet # needs sage.symbolic True :: - sage: ee = oeis('A001113') ; ee # optional -- internet + sage: ee = oeis('A001113'); ee # optional -- internet A001113: Decimal expansion of e. - sage: x = ee.natural_object() ; x # optional -- internet + sage: x = ee.natural_object(); x # optional -- internet 2.718281828459046? sage: x.parent() # optional -- internet @@ -1053,7 +1052,7 @@ def natural_object(self): :: - sage: av = oeis('A087778') ; av # optional -- internet + sage: av = oeis('A087778'); av # optional -- internet A087778: Decimal expansion ... Avogadro... sage: av.natural_object() # optional -- internet @@ -1061,18 +1060,20 @@ def natural_object(self): :: - sage: fib = oeis('A000045') ; fib # optional -- internet + sage: fib = oeis('A000045'); fib # optional -- internet A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. - sage: x = fib.natural_object() ; x.universe() # optional -- internet + sage: x = fib.natural_object(); x.universe() # optional -- internet Non negative integer semiring :: - sage: sfib = oeis('A039834') ; sfib # optional -- internet - A039834: a(n+2) = -a(n+1) + a(n) (signed Fibonacci numbers) with a(-2) = a(-1) = 1; or Fibonacci numbers (A000045) extended to negative indices. + sage: sfib = oeis('A039834'); sfib # optional -- internet + A039834: a(n+2) = -a(n+1) + a(n) (signed Fibonacci numbers) with + a(-2) = a(-1) = 1; or Fibonacci numbers (A000045) + extended to negative indices. - sage: x = sfib.natural_object() ; x.universe() # optional -- internet + sage: x = sfib.natural_object(); x.universe() # optional -- internet Integer Ring TESTS:: @@ -1263,7 +1264,7 @@ def first_terms(self, number=None): EXAMPLES:: - sage: f = oeis(45) ; f # optional -- internet + sage: f = oeis(45); f # optional -- internet A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. sage: f.first_terms()[:10] # optional -- internet @@ -1271,7 +1272,7 @@ def first_terms(self, number=None): Handle dead sequences, see :trac:`17330` :: - sage: oeis(5000).first_terms(12) # optional -- internet + sage: oeis(5000).first_terms(12) # optional -- internet doctest:warning ... RuntimeWarning: This sequence is dead: "A005000: Erroneous version of A006505." @@ -1440,14 +1441,15 @@ def __iter__(self): sage: w = oeis(7540) ; w # optional -- internet A007540: Wilson primes: primes p such that (p-1)! == -1 (mod p^2). - sage: i = w.__iter__() # optional -- internet - sage: next(i) # optional -- internet + sage: # optional - internet + sage: i = w.__iter__() + sage: next(i) 5 - sage: next(i) # optional -- internet + sage: next(i) 13 - sage: next(i) # optional -- internet + sage: next(i) 563 - sage: next(i) # optional -- internet + sage: next(i) Traceback (most recent call last): ... LookupError: future values not provided by OEIS @@ -1481,9 +1483,8 @@ def __iter__(self): sage: s = oeis._imaginary_sequence(ident='A999991', keywords='sign,full') sage: for i in s: pass """ - for x in self.first_terms(): - yield x - if not self.is_full() is True: + yield from self.first_terms() + if self.is_full() is not True: raise LookupError("future values not provided by OEIS") def references(self): @@ -1518,17 +1519,16 @@ def links(self, browse=None, format='guess'): INPUT: - ``browse`` -- an integer, a list of integers, or the word 'all' - (default: ``None``) : which links to open in a web browser. + (default: ``None``): which links to open in a web browser. - - ``format`` -- string (default: 'guess') : how to display the links. + - ``format`` -- string (default: 'guess'): how to display the links. - OUTPUT: + OUTPUT: Tuple of strings (with fancy formatting): - - tuple of strings (with fancy formatting): - - if ``format`` is ``url``, returns a tuple of absolute links without description. - - if ``format`` is ``html``, returns nothing but prints a tuple of clickable absolute links in their context. - - if ``format`` is ``guess``, adapts the output to the context (command line or notebook). - - if ``format`` is ``raw``, the links as they appear in the database, relative links are not made absolute. + - if ``format`` is ``url``, returns a tuple of absolute links without description. + - if ``format`` is ``html``, returns nothing but prints a tuple of clickable absolute links in their context. + - if ``format`` is ``guess``, adapts the output to the context (command line or notebook). + - if ``format`` is ``raw``, the links as they appear in the database, relative links are not made absolute. EXAMPLES:: @@ -1630,13 +1630,17 @@ def cross_references(self, fetch=False): A005598: a(n) = 1 + Sum_{i=1..n} (n-i+1)*phi(i). sage: nbalanced.cross_references() # optional -- internet - ('A049703', 'A049695', 'A103116', 'A000010') + ('A000010', 'A002088', 'A011755', 'A049695', 'A049703', 'A103116') sage: nbalanced.cross_references(fetch=True) # optional -- internet - 0: A049703: a(0) = 0; for n>0, a(n) = A005598(n)/2. - 1: A049695: Array T read by diagonals; ... - 2: A103116: a(n) = Sum_{i=1..n} (n-i+1)*phi(i). - 3: A000010: Euler totient function phi(n): count numbers <= n and prime to n. + 0: A000010: Euler totient function phi(n): count numbers <= n and prime to n. + 1: A002088: Sum of totient function: a(n) = Sum_{k=1..n} phi(k), cf. A000010. + 2: A011755: a(n) = Sum_{k=1..n} k*phi(k). + 3: A049695: Array T read by diagonals; T(i,j) is the number of nonnegative + slopes of lines determined by 2 lattice points in + [ 0,i ] X [ 0,j ] if i > 0; T(0,j)=1 if j > 0; T(0,0)=0. + 4: A049703: a(0) = 0; for n>0, a(n) = A005598(n)/2. + 5: A103116: a(n) = Sum_{i=1..n} (n-i+1)*phi(i). sage: phi = _[3] # optional -- internet @@ -1663,8 +1667,10 @@ def extensions_or_errors(self): EXAMPLES:: - sage: sfibo = oeis('A039834') ; sfibo # optional -- internet - A039834: a(n+2) = -a(n+1) + a(n) (signed Fibonacci numbers) with a(-2) = a(-1) = 1; or Fibonacci numbers (A000045) extended to negative indices. + sage: sfibo = oeis('A039834'); sfibo # optional -- internet + A039834: a(n+2) = -a(n+1) + a(n) (signed Fibonacci numbers) with + a(-2) = a(-1) = 1; or Fibonacci numbers (A000045) extended + to negative indices. sage: sfibo.extensions_or_errors()[0] # optional -- internet 'Signs corrected by _Len Smiley_ and _N. J. A. Sloane_' @@ -1688,7 +1694,7 @@ def examples(self): EXAMPLES:: - sage: c = oeis(1203) ; c # optional -- internet + sage: c = oeis(1203); c # optional -- internet A001203: Simple continued fraction expansion of Pi. sage: c.examples() # optional -- internet @@ -1714,7 +1720,7 @@ def comments(self): EXAMPLES:: - sage: f = oeis(45) ; f # optional -- internet + sage: f = oeis(45); f # optional -- internet A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. sage: f.comments()[:8] # optional -- internet @@ -1746,7 +1752,7 @@ def url(self): EXAMPLES:: - sage: f = oeis(45) ; f # optional -- internet + sage: f = oeis(45); f # optional -- internet A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. sage: f.url() # optional -- internet @@ -1766,7 +1772,7 @@ def browse(self): EXAMPLES:: - sage: f = oeis(45) ; f # optional -- internet webbrowser + sage: f = oeis(45); f # optional -- internet webbrowser A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. sage: f.browse() # optional -- internet webbrowser @@ -1781,7 +1787,7 @@ def browse(self): def show(self): r""" - Display most available informations about the sequence ``self``. + Display most available information about the sequence ``self``. EXAMPLES:: @@ -2000,14 +2006,14 @@ def test_compile_sage_code(self): One correct sequence:: - sage: s = oeis.find_by_id('A027642') # optional -- internet - sage: s.test_compile_sage_code() # optional -- internet + sage: s = oeis.find_by_id('A027642') # optional -- internet + sage: s.test_compile_sage_code() # optional -- internet True One dead sequence:: - sage: s = oeis.find_by_id('A000154') # optional -- internet - sage: s.test_compile_sage_code() # optional -- internet + sage: s = oeis.find_by_id('A000154') # optional -- internet + sage: s.test_compile_sage_code() # optional -- internet doctest:warning ... RuntimeWarning: This sequence is dead: ... @@ -2031,7 +2037,7 @@ class FancyTuple(tuple): EXAMPLES:: sage: from sage.databases.oeis import FancyTuple - sage: t = FancyTuple(['zero', 'one', 'two', 'three', 4]) ; t + sage: t = FancyTuple(['zero', 'one', 'two', 'three', 4]); t 0: zero 1: one 2: two @@ -2049,14 +2055,14 @@ def __repr__(self): EXAMPLES:: sage: from sage.databases.oeis import FancyTuple - sage: t = FancyTuple(['zero', 'one', 'two', 'three', 4]) ; t + sage: t = FancyTuple(['zero', 'one', 'two', 'three', 4]); t 0: zero 1: one 2: two 3: three 4: 4 - sage: t = FancyTuple(['Franรงais', 'Espaรฑol', 'ไธญๆ–‡']) ; t + sage: t = FancyTuple(['Franรงais', 'Espaรฑol', 'ไธญๆ–‡']); t 0: Franรงais 1: Espaรฑol 2: ไธญๆ–‡ diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index 087c494ef39..299d917aed6 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -259,7 +259,7 @@ def construct_skeleton(database): typ = u'NOTYPE' else: typ = col[2] - skeleton[table[0]][col[1]] = {'sql':typ, \ + skeleton[table[0]][col[1]] = {'sql':typ, 'primary_key':(col[5]!=0), 'index':(col[5]!=0), 'unique': False} exe2 = cur.execute("PRAGMA index_list(%s)"%table[0]) for col in exe2.fetchall(): @@ -389,10 +389,10 @@ def row_str(row, html): ret = '<html><!--notruncate-->\n' ret += ' <table bgcolor=lightgrey cellpadding=0>\n' ret += ' <tr>\n <td bgcolor=white align=center> ' - ret += (' </td>\n <td bgcolor=white ' \ + ret += (' </td>\n <td bgcolor=white ' + 'align=center> ').join(col_titles) ret += ' </td>\n </tr>\n' - ret += '\n'.join([' <tr>\n ' + row_str(row, True) + ' </tr>' \ + ret += '\n'.join([' <tr>\n ' + row_str(row, True) + ' </tr>' for row in cur]) ret += '\n </table>\n</html>' else: @@ -472,10 +472,10 @@ def __init__(self, database, *args, **kwds): elif isinstance(x, tuple): if 'param_tuple' not in kwds: kwds['param_tuple'] = x - if total_args > 2 or not ('query_dict' in kwds or \ - 'query_string' in kwds) or ('query_dict' in kwds and\ + if total_args > 2 or not ('query_dict' in kwds or + 'query_string' in kwds) or ('query_dict' in kwds and ('param_tuple' in kwds or 'query_string' in kwds)): - raise ValueError('Query must be constructed with either a ' \ + raise ValueError('Query must be constructed with either a ' + 'dictionary or a string and tuple') if 'query_dict' in kwds: @@ -509,7 +509,7 @@ def __init__(self, database, *args, **kwds): + '%s.%s '%(table_name, query_dict['expression'][0]) \ + '%s ?'%query_dict['expression'][1] else: - query_dict['display_cols'] = ['%s.%s'%(table_name, x) \ + query_dict['display_cols'] = ['%s.%s'%(table_name, x) for x in query_dict['display_cols']] self.__query_string__ = 'SELECT ' \ + ', '.join(query_dict['display_cols']) + ' FROM ' \ @@ -545,7 +545,7 @@ def __repr__(self): return 'Empty query on %s.'%self.__database__.__dblocation__ return "Query for sql database: %s"%self.__database__.__dblocation__ \ + "\nQuery string: %s"%self.__query_string__ \ - + ("\nParameter tuple: %s"%str(self.__param_tuple__) if \ + + ("\nParameter tuple: %s"%str(self.__param_tuple__) if self.__param_tuple__ else "") def get_query_string(self): @@ -682,7 +682,7 @@ def show(self, **kwds): except Exception: raise RuntimeError('Failure to fetch query.') - print(_create_print_table(cur, [des[0] for des in cur.description], \ + print(_create_print_table(cur, [des[0] for des in cur.description], **kwds)) def __copy__(self): @@ -704,7 +704,7 @@ def __copy__(self): d.__param_tuple__ = self.__param_tuple__ return d - def intersect(self, other, join_table=None, join_dict=None, \ + def intersect(self, other, join_table=None, join_dict=None, in_place=False): """ Return a new ``SQLQuery`` that is the intersection of ``self`` and @@ -753,10 +753,10 @@ def intersect(self, other, join_table=None, join_dict=None, \ True """ if self.__query_dict__ is None or other.__query_dict__ is None: - raise RuntimeError('Queries must be constructed using a ' \ + raise RuntimeError('Queries must be constructed using a ' + 'dictionary in order to be intersected.') if self.__database__ != other.__database__: - raise TypeError('Queries %s and %s must be '%(self, other) \ + raise TypeError('Queries %s and %s must be '%(self, other) + 'attached to the same database.') if in_place: @@ -773,7 +773,7 @@ def intersect(self, other, join_table=None, join_dict=None, \ return copy(other) if not other.__query_string__: return copy(self) - return self._merge_queries(other, copy(self), join_table, \ + return self._merge_queries(other, copy(self), join_table, join_dict, 'AND') def _merge_queries(self, other, ret, join_table, join_dict, operator): @@ -802,14 +802,14 @@ def _merge_queries(self, other, ret, join_table, join_dict, operator): pattern = ' JOIN ' if re.search(pattern, self.__query_string__) \ or re.search(pattern, other.__query_string__): - raise TypeError('Input queries have joins but join ' \ + raise TypeError('Input queries have joins but join ' + 'parameters are NoneType') s = ((self.__query_string__).upper()).split('FROM ') o = ((other.__query_string__).upper()).split('FROM ') s = s[1].split(' WHERE ') o = o[1].split(' WHERE ') if s[0] != o[0]: - raise ValueError('Input queries query different tables but ' \ + raise ValueError('Input queries query different tables but ' + 'join parameters are NoneType') # inner join clause @@ -819,7 +819,7 @@ def _merge_queries(self, other, ret, join_table, join_dict, operator): joins += ' INNER JOIN %s ON %s.'%(table, join_table) \ + '%s=%s.'%(join_dict[table][0], table) \ + '%s '%join_dict[table][1] - ret.__query_string__ = re.sub(' FROM .* WHERE ', ' FROM ' + joins \ + ret.__query_string__ = re.sub(' FROM .* WHERE ', ' FROM ' + joins + 'WHERE ', self.__query_string__) # concatenate display cols @@ -829,9 +829,10 @@ def _merge_queries(self, other, ret, join_table, join_dict, operator): new_query = ''.join(disp1) # concatenate where clause - new_query = re.sub(' WHERE ',' WHERE ( ', new_query) - new_query += re.sub('^.* WHERE ',' ) %s ( '%operator, \ - other.__query_string__) + new_query = re.sub(' WHERE ', ' WHERE ( ', + new_query) + new_query += re.sub('^.* WHERE ', f' ) {operator} ( ', + other.__query_string__) ret.__query_string__ = new_query + ' )' ret.__param_tuple__ = self.__param_tuple__ + other.__param_tuple__ @@ -876,10 +877,10 @@ def union(self, other, join_table=None, join_dict=None, in_place=False): [(1, 1), (4, 1)] """ if self.__query_dict__ is None or other.__query_dict__ is None: - raise RuntimeError('Queries must be constructed using a ' \ + raise RuntimeError('Queries must be constructed using a ' + 'dictionary in order to be unioned.') if self.__database__ != other.__database__: - raise TypeError('Queries %s and %s must be '%(self, other) \ + raise TypeError('Queries %s and %s must be '%(self, other) + 'attached to the same database.') if in_place: @@ -891,9 +892,10 @@ def union(self, other, join_table=None, join_dict=None, in_place=False): return copy(self) if not other.__query_string__: return copy(other) - return self._merge_queries(other, copy(self), join_table, \ + return self._merge_queries(other, copy(self), join_table, join_dict, 'OR') + class SQLDatabase(SageObject): def __init__(self, filename=None, read_only=None, skeleton=None): r""" @@ -1066,15 +1068,15 @@ def __init__(self, filename=None, read_only=None, skeleton=None): read_only = False filename = tmp_filename() + '.db' elif (filename[-3:] != '.db'): - raise ValueError('Please enter a valid database path (file name ' \ - + '%s does not end in .db).'%filename) + raise ValueError('Please enter a valid database path (file name ' + + '%s does not end in .db).' % filename) if read_only is None: read_only = True self.__read_only__ = read_only self.ignore_warnings = False self.__dblocation__ = filename - self.__connection__ = sqlite.connect(self.__dblocation__, \ + self.__connection__ = sqlite.connect(self.__dblocation__, check_same_thread=False) # this is to avoid the multiple thread problem with dsage: # pysqlite does not trust multiple threads for the same connection @@ -1092,14 +1094,14 @@ def __init__(self, filename=None, read_only=None, skeleton=None): else: for column in skeleton[table]: if column not in self.__skeleton__[table]: - self.add_column(table, column, \ - skeleton[table][column]) + self.add_column(table, column, + skeleton[table][column]) else: - print('Column attributes were ignored for ' \ - 'table {}, column {} -- column is ' \ + print('Column attributes were ignored for ' + 'table {}, column {} -- column is ' 'already in table.'.format(table, column)) elif skeleton is not None: - raise RuntimeError('Cannot update skeleton of a read only ' \ + raise RuntimeError('Cannot update skeleton of a read only ' + 'database.') def __repr__(self): @@ -1304,8 +1306,8 @@ def show(self, table_name, **kwds): cur.execute('SELECT * FROM ' + table_name) except Exception: raise RuntimeError('Failure to fetch data.') - print(_create_print_table(cur, [des[0] for des in cur.description], \ - **kwds)) + print(_create_print_table(cur, [des[0] for des in cur.description], + **kwds)) def get_cursor(self, ignore_warning=None): """ @@ -1332,8 +1334,8 @@ def get_cursor(self, ignore_warning=None): ignore_warning = self.ignore_warnings if not ignore_warning: import warnings - warnings.warn('Database is read only, using the cursor can ' \ - + 'alter the stored data. Set self.ignore_warnings to ' \ + warnings.warn('Database is read only, using the cursor can ' + + 'alter the stored data. Set self.ignore_warnings to ' + 'True in order to mute future warnings.', RuntimeWarning) return self.__connection__.cursor() @@ -1376,9 +1378,9 @@ def get_connection(self, ignore_warning=None): ignore_warning = self.ignore_warnings if not ignore_warning: import warnings - warnings.warn('Database is read only, using the connection ' \ - + 'can alter the stored data. Set self.ignore_warnings ' \ - + 'to True in order to mute future warnings.', \ + warnings.warn('Database is read only, using the connection ' + 'can alter the stored data. Set self.ignore_warnings ' + 'to True in order to mute future warnings.', RuntimeWarning) return self.__connection__ @@ -1457,7 +1459,7 @@ def create_table(self, table_name, table_skeleton): else: statement.append(col + ' ' + typ) if table_skeleton[col]['index']: - index_statement += 'CREATE INDEX i_%s_%s'%(table_name,\ + index_statement += 'CREATE INDEX i_%s_%s'%(table_name, col) + ' ON %s(%s);\n'%(table_name, col) create_statement += ', '.join(statement) + ') ' @@ -1638,13 +1640,14 @@ def _rebuild_table(self, table_name, col_name=None, default=''): INSERT INTO spam SELECT %s FROM %s; DROP TABLE %s; CREATE TABLE %s (%s); - """%(cols_attr, original, table_name, table_name, table_name, cols_attr)) + """ % (cols_attr, original, table_name, table_name, table_name, cols_attr)) # Update indices in new table - index_statement = ''.join(['CREATE INDEX i_%s_%s ON '%(table_name, \ - col) + '%s(%s);\n'%(table_name, col) for col in \ - self.__skeleton__[table_name] if \ - self.__skeleton__[table_name][col]['index'] and not \ - self.__skeleton__[table_name][col]['primary_key']]) + skeleton = self.__skeleton__[table_name] + index_statement = ''.join(f'CREATE INDEX i_{table_name}_{col} ON ' + + f'{table_name}({col});\n' + for col in skeleton + if skeleton[col]['index'] + and not skeleton[col]['primary_key']) if index_statement: self.__connection__.executescript(index_statement) @@ -1652,7 +1655,7 @@ def _rebuild_table(self, table_name, col_name=None, default=''): self.__connection__.executescript(""" INSERT INTO %s SELECT %s FROM spam; DROP TABLE spam; - """%(table_name, cols)) + """ % (table_name, cols)) self.vacuum() @@ -1733,7 +1736,7 @@ def rename_table(self, table_name, new_name): if new_name in self.__skeleton__: raise ValueError('Database already has table %s.'%new_name) - self.__connection__.execute('ALTER TABLE %s RENAME TO '%table_name \ + self.__connection__.execute('ALTER TABLE %s RENAME TO '%table_name + new_name) # Update skeleton: @@ -1759,7 +1762,7 @@ def drop_table(self, table_name): {} """ if self.__read_only__: - raise RuntimeError('Cannot drop tables from a read only ' \ + raise RuntimeError('Cannot drop tables from a read only ' + 'database.') if table_name not in self.__skeleton__: raise ValueError("Database has no table %s."%table_name) @@ -2115,15 +2118,15 @@ def delete_rows(self, query): raise RuntimeError('Cannot delete rows from a read only database.') # Check query is associated with this database if not isinstance(query, SQLQuery): - raise TypeError('%s is not a valid SQLQuery'%query) + raise TypeError('%s is not a valid SQLQuery' % query) if query.__database__ is not self: - raise ValueError('%s is not associated to this database.'%query) + raise ValueError('%s is not associated to this database.' % query) if (query.__query_string__).find(' JOIN ') != -1: - raise ValueError('%s is not a valid query. Can only '%query \ - + 'delete from one table at a time.') + raise ValueError(f'{query} is not a valid query. Can only ' + 'delete from one table at a time.') - delete_statement = re.sub('SELECT .* FROM', 'DELETE FROM', \ - query.__query_string__) + delete_statement = re.sub('SELECT .* FROM', 'DELETE FROM', + query.__query_string__) try: cur = self.get_cursor() @@ -2156,10 +2159,10 @@ def add_rows(self, table_name, rows, entry_order=None): strows = [tuple((str(entry) for entry in row)) for row in rows] if entry_order is not None: - self.__connection__.executemany('INSERT INTO ' + table_name \ + self.__connection__.executemany('INSERT INTO ' + table_name + str(tuple(entry_order)) + ' VALUES ' + quest, strows) else: - self.__connection__.executemany('INSERT INTO ' + table_name \ + self.__connection__.executemany('INSERT INTO ' + table_name + ' VALUES ' + quest, strows) add_data = add_rows diff --git a/src/sage/databases/stein_watkins.py b/src/sage/databases/stein_watkins.py index 2936fd6da1d..167fa3a195b 100644 --- a/src/sage/databases/stein_watkins.py +++ b/src/sage/databases/stein_watkins.py @@ -44,12 +44,13 @@ We type ``next(d)`` to get each isogeny class of curves from ``d``:: - sage: C = next(d) # optional - database_stein_watkins - sage: C # optional - database_stein_watkins + sage: # optional - database_stein_watkins + sage: C = next(d) + sage: C Stein-Watkins isogeny class of conductor 11 - sage: next(d) # optional - database_stein_watkins + sage: next(d) Stein-Watkins isogeny class of conductor 14 - sage: next(d) # optional - database_stein_watkins + sage: next(d) Stein-Watkins isogeny class of conductor 15 An isogeny class has a number of attributes that give data about @@ -58,21 +59,22 @@ :: - sage: C.data # optional - database_stein_watkins + sage: # optional - database_stein_watkins + sage: C.data ['11', '[11]', '0', '0.253842', '25', '+*1'] - sage: C.curves # optional - database_stein_watkins + sage: C.curves [[[0, -1, 1, 0, 0], '(1)', '1', '5'], [[0, -1, 1, -10, -20], '(5)', '1', '5'], [[0, -1, 1, -7820, -263580], '(1)', '1', '1']] - sage: C.conductor # optional - database_stein_watkins + sage: C.conductor 11 - sage: C.leading_coefficient # optional - database_stein_watkins + sage: C.leading_coefficient '0.253842' - sage: C.modular_degree # optional - database_stein_watkins + sage: C.modular_degree '+*1' - sage: C.rank # optional - database_stein_watkins + sage: C.rank 0 - sage: C.isogeny_number # optional - database_stein_watkins + sage: C.isogeny_number '25' If we were to continue typing ``next(d)`` we would @@ -101,16 +103,17 @@ Each call ``next(d)`` gives another elliptic curve of prime conductor:: - sage: C = next(d) # optional - database_stein_watkins - sage: C # optional - database_stein_watkins + sage: # optional - database_stein_watkins + sage: C = next(d) + sage: C Stein-Watkins isogeny class of conductor 17 - sage: C.curves # optional - database_stein_watkins + sage: C.curves [[[1, -1, 1, -1, 0], '[1]', '1', '4'], [[1, -1, 1, -6, -4], '[2]', '1', '2x'], [[1, -1, 1, -1, -14], '(4)', '1', '4'], [[1, -1, 1, -91, -310], '[1]', '1', '2']] - sage: C = next(d) # optional - database_stein_watkins - sage: C # optional - database_stein_watkins + sage: C = next(d) + sage: C Stein-Watkins isogeny class of conductor 19 REFERENCE: diff --git a/src/sage/docs/conf.py b/src/sage/docs/conf.py deleted file mode 100644 index 8dbc27d90e0..00000000000 --- a/src/sage/docs/conf.py +++ /dev/null @@ -1,4 +0,0 @@ -from sage.misc.superseded import deprecation -deprecation(33763, "This module is deprecated. Use sage_docbuild.conf instead.") - -from sage_docbuild.conf import * diff --git a/src/sage/docs/instancedoc.py b/src/sage/docs/instancedoc.py deleted file mode 100644 index e24368e4943..00000000000 --- a/src/sage/docs/instancedoc.py +++ /dev/null @@ -1,122 +0,0 @@ -r""" -Dynamic documentation for instances of classes - -The functionality in this module allows to define specific docstrings -of *instances* of a class, which are different from the class docstring. -A typical use case is given by cached methods: the documentation of a -cached method should not be the documentation of the class -:class:`CachedMethod`; it should be the documentation of the underlying -method. - -In order to use this, define a class docstring as usual. Also define a -method ``def _instancedoc_(self)`` which should return the docstring of -the instance ``self``. Finally, add the decorator ``@instancedoc`` to -the class. - -.. WARNING:: - - Since the ``__doc__`` attribute is never inherited, the decorator - ``@instancedoc`` must be added to all subclasses of the class - defining ``_instancedoc_``. Doing it on the base class is not - sufficient. - -EXAMPLES:: - - sage: from sage.misc.instancedoc import instancedoc - sage: @instancedoc - ....: class X(): - ....: "Class docstring" - ....: def _instancedoc_(self): - ....: return "Instance docstring" - sage: X.__doc__ - 'Class docstring' - sage: X().__doc__ - 'Instance docstring' - -For a Cython ``cdef class``, a decorator cannot be used. Instead, call -:func:`instancedoc` as a function after defining the class:: - - sage: cython(''' # optional - sage.misc.cython - ....: from sage.misc.instancedoc import instancedoc - ....: cdef class Y: - ....: "Class docstring" - ....: def _instancedoc_(self): - ....: return "Instance docstring" - ....: instancedoc(Y) - ....: ''') - sage: Y.__doc__ - 'File:...\nClass docstring' - sage: Y().__doc__ - 'Instance docstring' - -One can still add a custom ``__doc__`` attribute on a particular -instance:: - - sage: obj = X() - sage: obj.__doc__ = "Very special doc" - sage: print(obj.__doc__) - Very special doc - -This normally does not work on extension types:: - - sage: Y().__doc__ = "Very special doc" - Traceback (most recent call last): - ... - AttributeError: attribute '__doc__' of 'Y' objects is not writable - -This is an example involving a metaclass, where the instances are -classes. In this case, the ``_instancedoc_`` from the metaclass is only -used if the instance of the metaclass (the class) does not have a -docstring:: - - sage: @instancedoc - ....: class Meta(type): - ....: "Metaclass doc" - ....: def _instancedoc_(self): - ....: return "Docstring for {}".format(self) - sage: class T(metaclass=Meta): - ....: pass - sage: print(T.__doc__) - Docstring for <class '__main__.T'> - sage: class U(metaclass=Meta): - ....: "Special doc for U" - sage: print(U.__doc__) - Special doc for U - -TESTS: - -Check that inheritance works (after passing the subclass to -:func:`instancedoc`):: - - sage: @instancedoc - ....: class A(): - ....: "Class A docstring" - ....: def _instancedoc_(self): - ....: return "Instance docstring" - sage: class B(A): - ....: "Class B docstring" - sage: B.__doc__ - 'Class B docstring' - sage: B().__doc__ # Ideally, this would return the instance docstring - 'Class B docstring' - sage: B = instancedoc(B) - sage: B.__doc__ - 'Class B docstring' - sage: B().__doc__ - 'Instance docstring' -""" - -#***************************************************************************** -# Copyright (C) 2017 Jeroen Demeyer <J.Demeyer@UGent.be> -# -# 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. -# https://www.gnu.org/licenses/ -#***************************************************************************** - -from sage.misc.superseded import deprecation -deprecation(33763, 'This module is deprecated. Use "sage.misc.instancedoc" instead.') - -from sage.misc.instancedoc import instancedoc diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index aa1268a6a27..11bf91a3aef 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -8,10 +8,20 @@ - David Roe (2012-03-27) -- initial version, based on Robert Bradshaw's code. """ # **************************************************************************** -# Copyright (C) 2012 David Roe <roed.math@gmail.com> -# Robert Bradshaw <robertwb@gmail.com> -# William Stein <wstein@gmail.com> -# Copyright (C) 2016 Jeroen Demeyer <jdemeyer@cage.ugent.be> +# Copyright (C) 2012-2013 David Roe <roed.math@gmail.com> +# 2012-2013 Robert Bradshaw <robertwb@gmail.com> +# 2012 William Stein <wstein@gmail.com> +# 2013 R. Andrew Ohana +# 2013-2014 Volker Braun +# 2013-2018 Jeroen Demeyer <jdemeyer@cage.ugent.be> +# 2013-2021 John H. Palmieri +# 2017 Erik M. Bray +# 2017-2021 Frรฉdรฉric Chapoton +# 2018 Sรฉbastien Labbรฉ +# 2019 Franรงois Bissey +# 2020-2023 Matthias Koeppe +# 2022 Michael Orlitzky +# 2022 Sebastian Oehms # # 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 @@ -20,6 +30,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import importlib import random import os import sys @@ -35,16 +46,14 @@ from sage.misc.temporary_file import tmp_dir from cysignals.signals import AlarmInterrupt, init_cysignals -from .sources import FileDocTestSource, DictAsObject +from .sources import FileDocTestSource, DictAsObject, get_basename from .forker import DocTestDispatcher from .reporting import DocTestReporter from .util import Timer, count_noun, dict_difference from .external import available_software -from .parsing import parse_optional_tags +from .parsing import parse_optional_tags, parse_file_optional_tags, unparse_optional_tags, \ + nodoctest_regex, optionaltag_regex, optionalfiledirective_regex -nodoctest_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*nodoctest') -optionaltag_regex = re.compile(r'^(\w|[.])+$') -optionalfiledirective_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*sage\.doctest: (.*)') # Optional tags which are always automatically added @@ -57,7 +66,6 @@ except ImportError: pass - class DocTestDefaults(SageObject): """ This class is used for doctesting the Sage doctest module. @@ -115,6 +123,7 @@ def __init__(self, **kwds): self.initial = False self.exitfirst = False self.force_lib = False + self.if_installed = False self.abspath = True # sage-runtests default is False self.verbose = False self.debug = False @@ -137,6 +146,8 @@ def __init__(self, **kwds): # displaying user-defined optional tags and we don't want to see # the auto_optional_tags there. self.optional = set(['sage']) | auto_optional_tags + self.hide = '' + self.probe = '' # > 0: always run GC before every test # < 0: disable GC @@ -213,18 +224,23 @@ def skipdir(dirname): return True return False -def skipfile(filename, tested_optional_tags=False): +def skipfile(filename, tested_optional_tags=False, *, + if_installed=False, log=None): """ - Return True if and only if the file ``filename`` should not be - doctested. + Return ``True`` if and only if the file ``filename`` should not be doctested. INPUT: - - ``filename`` - name of a file + - ``filename`` -- name of a file - - ``tested_optional_tags`` - a list or tuple or set of optional tags to test, + - ``tested_optional_tags`` -- a list or tuple or set of optional tags to test, or ``False`` (no optional test) or ``True`` (all optional tests) + - ``if_installed`` -- (boolean, default ``False``) whether to skip Python/Cython files + that are not installed as modules + + - ``log`` -- function to call with log messages, or ``None`` + If ``filename`` contains a line of the form ``"# sage.doctest: optional - xyz")``, then this will return ``False`` if "xyz" is in ``tested_optional_tags``. Otherwise, it returns the matching tag @@ -243,7 +259,8 @@ def skipfile(filename, tested_optional_tags=False): sage: skipfile(filename) True sage: with open(filename, "w") as f: - ....: _ = f.write("# sage.doctest: optional - xyz") + ....: _ = f.write("# sage.doctest: " # broken in two source lines to avoid the pattern + ....: "optional - xyz") # of relint (multiline_doctest_comment) sage: skipfile(filename, False) 'optional - xyz' sage: bool(skipfile(filename, False)) @@ -261,28 +278,53 @@ def skipfile(filename, tested_optional_tags=False): base, ext = os.path.splitext(filename) # .rst.txt appear in the installed documentation in subdirectories named "_sources" if ext not in ('.py', '.pyx', '.pxd', '.pxi', '.sage', '.spyx', '.rst', '.tex', '.rst.txt'): + if log: + log(f"Skipping '{filename}' because it does not have one of the recognized file name extensions") + return True + if if_installed and ext not in ('.py', '.pyx'): + if log: + log(f"Skipping '{filename}' because it is not the source file of a Python module") return True - # These files are created by the jupyter-sphinx extension for internal use and should not be tested if "jupyter_execute" in filename: + if log: + log(f"Skipping '{filename}' because it is created by the jupyter-sphinx extension for internal use and should not be tested") return True - with open(filename) as F: - line_count = 0 - for line in F: - if nodoctest_regex.match(line): + if if_installed: + module_name = get_basename(filename) + try: + if not importlib.util.find_spec(module_name): # tries to import the containing package + if log: + log(f"Skipping '{filename}' because module {module_name} is not present in the venv") return True - if tested_optional_tags is not True: - # Adapted from code in SageDocTestParser.parse - m = optionalfiledirective_regex.match(line) - if m: - if tested_optional_tags is False: - return m.group(2) - optional_tags = parse_optional_tags('#' + m.group(2)) - extra = optional_tags - set(tested_optional_tags) - if extra: - return m.group(2) - line_count += 1 - if line_count >= 10: - break + except ModuleNotFoundError as e: + if log: + log(f"Skipping '{filename}' because module {e.name} cannot be imported") + return True + + with open(filename) as F: + file_optional_tags = parse_file_optional_tags(enumerate(F)) + + if 'not tested' in file_optional_tags: + if log: + log(f"Skipping '{filename}' because it is marked 'nodoctest'") + return True + + if tested_optional_tags is False: + if file_optional_tags: + file_tag_string = unparse_optional_tags(file_optional_tags, prefix='') + if log: + log(f"Skipping '{filename}' because it is marked '# {file_tag_string}'") + return file_tag_string + + elif tested_optional_tags is not True: + extra = set(tag for tag in file_optional_tags + if tag not in tested_optional_tags) + if extra: + file_tag_string = unparse_optional_tags(file_optional_tags, prefix='') + if log: + log(f"Skipping '{filename}' because it is marked '{file_tag_string}'") + return file_tag_string + return False @@ -400,6 +442,27 @@ def __init__(self, options, args): if options.verbose: options.show_skipped = True + options.hidden_features = set() + if isinstance(options.hide, str): + if not len(options.hide): + options.hide = set([]) + else: + s = options.hide.lower() + options.hide = set(s.split(',')) + for h in options.hide: + if not optionaltag_regex.search(h): + raise ValueError('invalid optional tag {!r}'.format(h)) + if 'all' in options.hide: + options.hide.discard('all') + from sage.features.all import all_features + feature_names = set([f.name for f in all_features() if not f.is_standard()]) + options.hide = options.hide.union(feature_names) + if 'optional' in options.hide: + options.hide.discard('optional') + from sage.features.all import all_features + feature_names = set([f.name for f in all_features() if f.is_optional()]) + options.hide = options.hide.union(feature_names) + options.disabled_optional = set() if isinstance(options.optional, str): s = options.optional.lower() @@ -416,6 +479,8 @@ def __init__(self, options, args): options.optional.discard('optional') from sage.misc.package import list_packages for pkg in list_packages('optional', local=True).values(): + if pkg.name in options.hide: + continue if pkg.is_installed() and pkg.installed_version == pkg.remote_version: options.optional.add(pkg.name) @@ -434,6 +499,23 @@ def __init__(self, options, args): options.optional |= auto_optional_tags options.optional -= options.disabled_optional + if isinstance(options.probe, str): + if options.probe == 'none': + options.probe = '' + s = options.probe.lower() + if not s: + options.probe = set() + else: + options.probe = set(s.split(',')) + if "all" in options.probe: + # Special case to probe all features that are not present + options.probe = True + else: + # Check that all tags are valid + for o in options.probe: + if not optionaltag_regex.search(o): + raise ValueError('invalid optional tag {!r}'.format(o)) + self.options = options self.files = args @@ -626,8 +708,8 @@ def load_baseline_stats(self, filename): try: with open(filename) as stats_file: self.baseline_stats.update(json.load(stats_file)) - except Exception: - self.log("Error loading baseline stats from %s"%filename) + except Exception as e: + self.log("Error loading baseline stats from %s: %s" % (filename, e)) def load_stats(self, filename): """ @@ -690,7 +772,7 @@ def save_stats(self, filename): """ from sage.misc.temporary_file import atomic_write with atomic_write(filename) as stats_file: - json.dump(self.stats, stats_file) + json.dump(self.stats, stats_file, sort_keys=True, indent=4) def log(self, s, end="\n"): """ @@ -790,7 +872,7 @@ def add_files(self): # SAGE_ROOT_GIT can be None on distributions which typically # only have the SAGE_LOCAL install tree but not SAGE_ROOT if SAGE_ROOT_GIT is not None: - have_git = os.path.isdir(SAGE_ROOT_GIT) + have_git = os.path.exists(SAGE_ROOT_GIT) else: have_git = False @@ -865,11 +947,14 @@ def all_doc_sources(): data = line.strip().split(' ') status, filename = data[0], data[-1] if (set(status).issubset("MARCU") - and filename.startswith("src/sage") - and (filename.endswith(".py") or - filename.endswith(".pyx") or - filename.endswith(".rst"))): - self.files.append(os.path.relpath(opj(SAGE_ROOT,filename))) + and filename.startswith("src/sage") + and (filename.endswith(".py") or + filename.endswith(".pyx") or + filename.endswith(".rst")) + and not skipfile(opj(SAGE_ROOT, filename), + True if self.options.optional else False, + if_installed=self.options.if_installed)): + self.files.append(os.path.relpath(opj(SAGE_ROOT, filename))) def expand_files_into_sources(self): r""" @@ -928,11 +1013,14 @@ def expand(): if dir[0] == "." or skipdir(os.path.join(root,dir)): dirs.remove(dir) for file in files: - if not skipfile(os.path.join(root, file), self.options.optional): + if not skipfile(os.path.join(root, file), + True if self.options.optional else False, + if_installed=self.options.if_installed): yield os.path.join(root, file) else: - # the user input this file explicitly, so we don't skip it - yield path + if not skipfile(path, True if self.options.optional else False, + if_installed=self.options.if_installed, log=self.log): # log when directly specified filenames are skipped + yield path self.sources = [FileDocTestSource(path, self.options) for path in expand()] def filter_sources(self): @@ -1001,7 +1089,7 @@ def sort_sources(self): def sort_key(source): basename = source.basename - return -self.stats.get(basename, default).get('walltime'), basename + return -self.stats.get(basename, default).get('walltime', 0), basename self.sources = sorted(self.sources, key=sort_key) def run_doctests(self): @@ -1082,7 +1170,7 @@ def cleanup(self, final=True): sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: from sage.env import SAGE_SRC sage: import os - sage: dirname = os.path.join(SAGE_SRC, 'sage', 'rings', 'infinity.py') + sage: dirname = os.path.join(SAGE_SRC, 'sage', 'rings', 'all.py') sage: DD = DocTestDefaults() sage: DC = DocTestController(DD, [dirname]) @@ -1096,7 +1184,7 @@ def cleanup(self, final=True): sage: DC.run() Running doctests with ID ... Doctesting 1 file. - sage -t .../rings/infinity.py + sage -t .../rings/all.py [... tests, ... s] ---------------------------------------------------------------------- All tests passed! @@ -1328,6 +1416,49 @@ def run(self): Features detected... 0 + We test the ``--hide`` option (:trac:`34185`):: + + sage: from sage.doctest.control import test_hide + sage: filename = tmp_filename(ext='.py') + sage: with open(filename, 'w') as f: + ....: f.write(test_hide) + ....: f.close() + 729 + sage: DF = DocTestDefaults(hide='buckygen,all') + sage: DC = DocTestController(DF, [filename]) + sage: DC.run() + Running doctests with ID ... + Using --optional=sage... + Features to be detected: ... + Doctesting 1 file. + sage -t ....py + [4 tests, ... s] + ---------------------------------------------------------------------- + All tests passed! + ---------------------------------------------------------------------- + Total time for all tests: ... seconds + cpu time: ... seconds + cumulative wall time: ... seconds + Features detected... + 0 + + sage: DF = DocTestDefaults(hide='benzene,optional') + sage: DC = DocTestController(DF, [filename]) + sage: DC.run() + Running doctests with ID ... + Using --optional=sage + Features to be detected: ... + Doctesting 1 file. + sage -t ....py + [4 tests, ... s] + ---------------------------------------------------------------------- + All tests passed! + ---------------------------------------------------------------------- + Total time for all tests: ... seconds + cpu time: ... seconds + cumulative wall time: ... seconds + Features detected... + 0 """ opt = self.options L = (opt.gdb, opt.lldb, opt.valgrind, opt.massif, opt.cachegrind, opt.omega) @@ -1368,6 +1499,21 @@ def run(self): self.log("Using --optional=" + self._optional_tags_string()) available_software._allow_external = self.options.optional is True or 'external' in self.options.optional + + for h in self.options.hide: + try: + i = available_software._indices[h] + except KeyError: + pass + else: + f = available_software._features[i] + if f.is_present(): + f.hide() + self.options.hidden_features.add(f) + for g in f.joined_features(): + if g.name in self.options.optional: + self.options.optional.discard(g.name) + for o in self.options.disabled_optional: try: i = available_software._indices[o] @@ -1377,12 +1523,20 @@ def run(self): available_software._seen[i] = -1 self.log("Features to be detected: " + ','.join(available_software.detectable())) + if self.options.hidden_features: + self.log("Hidden features: " + ','.join([f.name for f in self.options.hidden_features])) + if self.options.probe: + self.log("Features to be probed: " + ('all' if self.options.probe is True + else ','.join(self.options.probe))) self.add_files() self.expand_files_into_sources() self.filter_sources() self.sort_sources() self.run_doctests() + for f in self.options.hidden_features: + f.unhide() + self.log("Features detected for doctesting: " + ','.join(available_software.seen())) self.cleanup() @@ -1401,10 +1555,10 @@ def run_doctests(module, options=None): EXAMPLES:: - sage: run_doctests(sage.rings.infinity) + sage: run_doctests(sage.rings.all) Running doctests with ID ... Doctesting 1 file. - sage -t .../sage/rings/infinity.py + sage -t .../sage/rings/all.py [... tests, ... s] ---------------------------------------------------------------------- All tests passed! @@ -1463,3 +1617,34 @@ def stringify(x): if not save_dtmode and IP is not None: IP.run_line_magic('colors', old_color) IP.config.TerminalInteractiveShell.colors = old_config_color + + +############################################################################### +# Declaration of doctest strings +############################################################################### + +test_hide=r"""r{quotmark} +{prompt}: next(graphs.fullerenes(20)) +Traceback (most recent call last): + ... +FeatureNotPresentError: buckygen is not available. +... +{prompt}: next(graphs.fullerenes(20)) # optional buckygen +Graph on 20 vertices + +{prompt}: len(list(graphs.fusenes(2))) +Traceback (most recent call last): + ... +FeatureNotPresentError: benzene is not available. +... +{prompt}: len(list(graphs.fusenes(2))) # optional benzene +1 +{prompt}: from sage.matrix.matrix_space import get_matrix_class +{prompt}: get_matrix_class(GF(25,'x'), 4, 4, False, 'meataxe') +Failed lazy import: +sage.matrix.matrix_gfpn_dense is not available. +... +{prompt}: get_matrix_class(GF(25,'x'), 4, 4, False, 'meataxe') # optional meataxe +<class 'sage.matrix.matrix_gfpn_dense.Matrix_gfpn_dense'> +{quotmark} +""".format(quotmark='"""', prompt='sage') # using prompt to hide these lines from _test_enough_doctests diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index f8374b13473..9768202e76f 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -16,7 +16,12 @@ """ #***************************************************************************** -# Copyright (C) 2016 KWANKYU LEE <ekwankyu@gmail.com> +# Copyright (C) 2016 Kwankyu Lee <ekwankyu@gmail.com> +# 2018 Thierry Monteil +# 2018-2021 Sรฉbastien Labbรฉ +# 2019 Markus Wageringel +# 2020 John H. Palmieri +# 2021 Matthias Koeppe # # 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 @@ -367,6 +372,7 @@ def external_software(): """ return sorted(f.name for f in external_features()) + external_software = external_software() @@ -380,6 +386,7 @@ class AvailableSoftware(): sage: from sage.doctest.external import external_software, available_software sage: external_software ['cplex', + 'dvips', 'ffmpeg', 'gurobi', 'internet', diff --git a/src/sage/doctest/fixtures.py b/src/sage/doctest/fixtures.py index e6f8fc45f8e..a3b5e9edda7 100644 --- a/src/sage/doctest/fixtures.py +++ b/src/sage/doctest/fixtures.py @@ -33,7 +33,7 @@ """ #***************************************************************************** -# Copyright (C) 2014 Martin von Gagern <Martin.vGagern@gmx.net> +# Copyright (C) 2014-2015 Martin von Gagern <Martin.vGagern@gmx.net> # # 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 diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index fe58e2bde3e..b5521868dd5 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -22,10 +22,22 @@ """ # **************************************************************************** -# Copyright (C) 2012 David Roe <roed.math@gmail.com> -# Robert Bradshaw <robertwb@gmail.com> -# William Stein <wstein@gmail.com> -# Copyright (C) 2013-2015 Jeroen Demeyer <jdemeyer@cage.ugent.be> +# Copyright (C) 2012-2013 David Roe <roed.math@gmail.com> +# 2012 Robert Bradshaw <robertwb@gmail.com> +# 2012 William Stein <wstein@gmail.com> +# 2013 R. Andrew Ohana +# 2013-2018 Jeroen Demeyer <jdemeyer@cage.ugent.be> +# 2013-2020 John H. Palmieri +# 2013-2017 Volker Braun +# 2014 Andrรฉ Apitzsch +# 2014 Darij Grinberg +# 2016-2021 Frรฉdรฉric Chapoton +# 2017-2019 Erik M. Bray +# 2018 Julian Rรผth +# 2020 Jonathan Kliem +# 2020-2023 Matthias Koeppe +# 2022 Markus Wageringel +# 2022 Michael Orlitzky # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -47,18 +59,19 @@ import doctest import traceback import tempfile +from collections import defaultdict from dis import findlinestarts from queue import Empty import gc import IPython.lib.pretty import sage.misc.randstate as randstate -from sage.misc.misc import walltime +from sage.misc.timing import walltime from .util import Timer, RecordingDict, count_noun from .sources import DictAsObject from .parsing import OriginalSource, reduce_hex from sage.structure.sage_object import SageObject -from .parsing import SageOutputChecker, pre_hash, get_source +from .parsing import SageOutputChecker, pre_hash, get_source, unparse_optional_tags from sage.repl.user_globals import set_globals from sage.cpython.atexit import restore_atexit from sage.cpython.string import bytes_to_str, str_to_bytes @@ -131,10 +144,11 @@ def init_sage(controller=None): Check that SymPy equation pretty printer is limited in doctest mode to default width (80 chars):: - sage: from sympy import sympify # optional - sage.symbolic - sage: from sympy.printing.pretty.pretty import PrettyPrinter # optional - sage.symbolic - sage: s = sympify('+x^'.join(str(i) for i in range(30))) # optional - sage.symbolic - sage: print(PrettyPrinter(settings={'wrap_line': True}).doprint(s)) # optional - sage.symbolic + sage: # needs sympy + sage: from sympy import sympify + sage: from sympy.printing.pretty.pretty import PrettyPrinter + sage: s = sympify('+x^'.join(str(i) for i in range(30))) + sage: print(PrettyPrinter(settings={'wrap_line': True}).doprint(s)) 29 28 27 26 25 24 23 22 21 20 19 18 17 x + x + x + x + x + x + x + x + x + x + x + x + x + <BLANKLINE> @@ -527,7 +541,7 @@ def __init__(self, *args, **kwds): self.msgfile = self._fakeout.real_stdout self.history = [] self.references = [] - self.setters = {} + self.setters = defaultdict(dict) self.running_global_digest = hashlib.md5() self.total_walltime_skips = 0 self.total_performed_tests = 0 @@ -715,10 +729,18 @@ def compiler(example): outcome = FAILURE # guilty until proved innocent or insane + probed_tags = getattr(example, 'probed_tags', False) + # If the example executed without raising any exceptions, # verify its output. if exception is None: if check(example.want, got, self.optionflags): + if probed_tags and probed_tags is not True: + example.warnings.append( + f"The tag '{unparse_optional_tags(probed_tags)}' " + f"may no longer be needed; these features are not present, " + f"but we ran the doctest anyway as requested by --probe, " + f"and it succeeded.") outcome = SUCCESS # The example raised an exception: check if it was expected. @@ -754,6 +776,12 @@ def compiler(example): # We expected an exception: see whether it matches. elif check(example.exc_msg, exc_msg, self.optionflags): + if probed_tags and probed_tags is not True: + example.warnings.append( + f"The tag '{unparse_optional_tags(example.probed_tags)}' " + f"may no longer be needed; these features are not present, " + f"but we ran the doctest anyway as requested by --probe, " + f"and it succeeded (raised the expected exception).") outcome = SUCCESS # Another chance if they didn't care about the detail. @@ -762,19 +790,32 @@ def compiler(example): m2 = re.match(r'(?:[^:]*\.)?([^:]*:)', exc_msg) if m1 and m2 and check(m1.group(1), m2.group(1), self.optionflags): + if probed_tags and probed_tags is not True: + example.warnings.append( + f"The tag '{unparse_optional_tags(example.probed_tags)}' " + f"may no longer be needed; these features are not present, " + f"but we ran the doctest anyway as requested by --probe, " + f"and it succeeded (raised an exception as expected).") outcome = SUCCESS check_duration = walltime(check_starttime) self.total_walltime += example.walltime + check_duration # Report the outcome. + if example.warnings: + for warning in example.warnings: + out(self._failure_header(test, example, f'Warning: {warning}')) if outcome is SUCCESS: if self.options.warn_long > 0 and example.walltime + check_duration > self.options.warn_long: self.report_overtime(out, test, example, got, check_duration=check_duration) + elif example.warnings: + pass elif not quiet: self.report_success(out, test, example, got, check_duration=check_duration) + elif probed_tags: + pass elif outcome is FAILURE: if not quiet: self.report_failure(out, test, example, got, test.globs) @@ -831,14 +872,15 @@ def run(self, test, compileflags=0, out=None, clear_globs=True): sage: from sage.doctest.control import DocTestDefaults; DD = DocTestDefaults() sage: from sage.env import SAGE_SRC sage: import doctest, sys, os - sage: DTR = SageDocTestRunner(SageOutputChecker(), verbose=False, sage_options=DD, optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) + sage: DTR = SageDocTestRunner(SageOutputChecker(), verbose=False, sage_options=DD, + ....: optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) sage: filename = os.path.join(SAGE_SRC,'sage','doctest','forker.py') sage: FDS = FileDocTestSource(filename,DD) sage: doctests, extras = FDS.create_doctests(globals()) sage: DTR.run(doctests[0], clear_globs=False) TestResults(failed=0, attempted=4) """ - self.setters = {} + self.setters = defaultdict(dict) randstate.set_random_seed(self.options.random_seed) warnings.showwarning = showwarning_with_traceback self.running_doctest_digest = hashlib.md5() @@ -1037,17 +1079,20 @@ def compile_and_execute(self, example, compiler, globs): sage: from sage.doctest.control import DocTestDefaults; DD = DocTestDefaults() sage: from sage.env import SAGE_SRC sage: import doctest, sys, os, hashlib - sage: DTR = SageDocTestRunner(SageOutputChecker(), verbose=False, sage_options=DD, optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) + sage: DTR = SageDocTestRunner(SageOutputChecker(), verbose=False, sage_options=DD, + ....: optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) sage: DTR.running_doctest_digest = hashlib.md5() - sage: filename = os.path.join(SAGE_SRC,'sage','doctest','forker.py') - sage: FDS = FileDocTestSource(filename,DD) + sage: filename = os.path.join(SAGE_SRC, 'sage', 'doctest', 'forker.py') + sage: FDS = FileDocTestSource(filename, DD) sage: globs = RecordingDict(globals()) sage: 'doctest_var' in globs False sage: doctests, extras = FDS.create_doctests(globs) sage: ex0 = doctests[0].examples[0] sage: flags = 32768 if sys.version_info.minor < 8 else 524288 - sage: compiler = lambda ex: compile(ex.source, '<doctest sage.doctest.forker[0]>', 'single', flags, 1) + sage: def compiler(ex): + ....: return compile(ex.source, '<doctest sage.doctest.forker[0]>', + ....: 'single', flags, 1) sage: DTR.compile_and_execute(ex0, compiler, globs) 1764 sage: globs['doctest_var'] @@ -1060,7 +1105,9 @@ def compile_and_execute(self, example, compiler, globs): Now we can execute some more doctests to see the dependencies. :: sage: ex1 = doctests[0].examples[1] - sage: compiler = lambda ex:compile(ex.source, '<doctest sage.doctest.forker[1]>', 'single', flags, 1) + sage: def compiler(ex): + ....: return compile(ex.source, '<doctest sage.doctest.forker[1]>', + ....: 'single', flags, 1) sage: DTR.compile_and_execute(ex1, compiler, globs) sage: sorted(list(globs.set)) ['R', 'a'] @@ -1072,7 +1119,9 @@ def compile_and_execute(self, example, compiler, globs): :: sage: ex2 = doctests[0].examples[2] - sage: compiler = lambda ex:compile(ex.source, '<doctest sage.doctest.forker[2]>', 'single', flags, 1) + sage: def compiler(ex): + ....: return compile(ex.source, '<doctest sage.doctest.forker[2]>', + ....: 'single', flags, 1) sage: DTR.compile_and_execute(ex2, compiler, globs) a + 42 sage: list(globs.set) @@ -1085,6 +1134,8 @@ def compile_and_execute(self, example, compiler, globs): if isinstance(globs, RecordingDict): globs.start() example.sequence_number = len(self.history) + if not hasattr(example, 'warnings'): + example.warnings = [] self.history.append(example) timer = Timer().start() try: @@ -1096,11 +1147,28 @@ def compile_and_execute(self, example, compiler, globs): if isinstance(globs, RecordingDict): example.predecessors = [] for name in globs.got: - ref = self.setters.get(name) - if ref is not None: - example.predecessors.append(ref) + setters_dict = self.setters.get(name) # setter_optional_tags -> setter + if setters_dict: + was_set = False + for setter_optional_tags, setter in setters_dict.items(): + if setter_optional_tags.issubset(example.optional_tags): # was set in a less constrained doctest + was_set = True + example.predecessors.append(setter) + if not was_set: + if example.probed_tags: + # Probing confusion. + # Do not issue the "was set only in doctest marked" warning; + # and also do not issue the "may no longer be needed" notice + example.probed_tags = True + else: + f_setter_optional_tags = "; ".join("'" + + unparse_optional_tags(setter_optional_tags) + + "'" + for setter_optional_tags in setters_dict) + example.warnings.append(f"Variable '{name}' referenced here " + f"was set only in doctest marked {f_setter_optional_tags}") for name in globs.set: - self.setters[name] = example + self.setters[name][example.optional_tags] = example else: example.predecessors = None self.update_digests(example) @@ -1253,7 +1321,7 @@ def report_success(self, out, test, example, got, *, check_duration=0): sage: from sage.doctest.forker import SageDocTestRunner sage: from sage.doctest.sources import FileDocTestSource sage: from sage.doctest.control import DocTestDefaults; DD = DocTestDefaults() - sage: from sage.misc.misc import walltime + sage: from sage.misc.timing import walltime sage: from sage.env import SAGE_SRC sage: import doctest, sys, os sage: DTR = SageDocTestRunner(SageOutputChecker(), verbose=True, sage_options=DD, optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) @@ -1427,7 +1495,7 @@ def report_overtime(self, out, test, example, got, *, check_duration=0): sage: from sage.doctest.forker import SageDocTestRunner sage: from sage.doctest.sources import FileDocTestSource sage: from sage.doctest.control import DocTestDefaults; DD = DocTestDefaults() - sage: from sage.misc.misc import walltime + sage: from sage.misc.timing import walltime sage: from sage.env import SAGE_SRC sage: import doctest, sys, os sage: DTR = SageDocTestRunner(SageOutputChecker(), verbose=True, sage_options=DD, optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) @@ -2112,7 +2180,7 @@ def run(self): TESTS:: - sage: run_doctests(sage.symbolic.units) # indirect doctest # optional - sage.symbolic + sage: run_doctests(sage.symbolic.units) # indirect doctest # needs sage.symbolic Running doctests with ID ... Doctesting 1 file. sage -t .../sage/symbolic/units.py diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 26d793b96bf..3a2ac1b98d4 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -13,9 +13,19 @@ """ # **************************************************************************** -# Copyright (C) 2012 David Roe <roed.math@gmail.com> -# Robert Bradshaw <robertwb@gmail.com> -# William Stein <wstein@gmail.com> +# Copyright (C) 2012-2018 David Roe <roed.math@gmail.com> +# 2012 Robert Bradshaw <robertwb@gmail.com> +# 2012 William Stein <wstein@gmail.com> +# 2013 R. Andrew Ohana +# 2013 Volker Braun +# 2013-2018 Jeroen Demeyer <jdemeyer@cage.ugent.be> +# 2016-2021 Frรฉdรฉric Chapoton +# 2017-2018 Erik M. Bray +# 2020 Marc Mezzarobba +# 2020-2023 Matthias Koeppe +# 2022 John H. Palmieri +# 2022 Sรฉbastien Labbรฉ +# 2023 Kwankyu Lee # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -23,13 +33,17 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -import re +import collections.abc import doctest +import re + from collections import defaultdict -from sage.repl.preparse import preparse, strip_string_literals from functools import reduce -from .external import available_software +from sage.misc.cachefunc import cached_function +from sage.repl.preparse import preparse, strip_string_literals + +from .external import available_software, external_software _RIFtol = None @@ -63,7 +77,7 @@ def RIFtol(*args): if _RIFtol is None: try: # We need to import from sage.all to avoid circular imports. - from sage.all import RealIntervalField + from sage.rings.real_mpfi import RealIntervalField except ImportError: from warnings import warn warn("RealIntervalField not available, ignoring all tolerance specifications in doctests") @@ -79,80 +93,461 @@ def fake_RIFtol(*args): # This is the correct pattern to match ISO/IEC 6429 ANSI escape sequences: ansi_escape_sequence = re.compile(r'(\x1b[@-Z\\-~]|\x1b\[.*?[@-~]|\x9b.*?[@-~])') +special_optional_regex = 'arb216|arb218|py2|long time|not implemented|not tested|known bug' +tag_with_explanation_regex = fr'((?:\w|[.])+)\s*(?:\((.*?)\))?' +optional_regex = re.compile(fr'(?P<cmd>{special_optional_regex})\s*(?:\((?P<cmd_explanation>.*?)\))?|' + fr'[^ a-z]\s*(optional|needs)(?:\s|[:-])*(?P<tags>(?:(?:{tag_with_explanation_regex})\s*)*)', + re.IGNORECASE) +special_optional_regex = re.compile(special_optional_regex, re.IGNORECASE) +tag_with_explanation_regex = re.compile(tag_with_explanation_regex, re.IGNORECASE) -def parse_optional_tags(string): - """ - Return a set consisting of the optional tags from the following +nodoctest_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*nodoctest') +optionaltag_regex = re.compile(r'^(\w|[.])+$') +optionalfiledirective_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*sage\.doctest: (.*)') + + +def parse_optional_tags(string, *, return_string_sans_tags=False): + r""" + Return a dictionary whose keys are optional tags from the following set that occur in a comment on the first line of the input string. - - 'long time' - - 'not implemented' - - 'not tested' - - 'known bug' - - 'py2' - - 'arb216' - - 'arb218' - - 'optional: PKG_NAME' -- the set will just contain 'PKG_NAME' + - ``'long time'`` + - ``'not implemented'`` + - ``'not tested'`` + - ``'known bug'`` + - ``'py2'`` + - ``'arb216'`` + - ``'arb218'`` + - ``'optional - FEATURE...'`` or ``'needs FEATURE...'`` -- + the dictionary will just have the key ``'FEATURE'`` + + The values, if non-``None``, are strings with optional explanations + for a tag, which may appear in parentheses after the tag in ``string``. + + INPUT: + + - ``string`` -- a string + + - ``return_string_sans_tags`` -- (boolean, default ``False``); whether to + additionally return ``string`` with the optional tags removed but other + comments kept and a boolean ``is_persistent`` EXAMPLES:: sage: from sage.doctest.parsing import parse_optional_tags sage: parse_optional_tags("sage: magma('2 + 2')# optional: magma") - {'magma'} + {'magma': None} sage: parse_optional_tags("sage: #optional -- mypkg") - {'mypkg'} + {'mypkg': None} sage: parse_optional_tags("sage: print(1) # parentheses are optional here") - set() + {} sage: parse_optional_tags("sage: print(1) # optional") - {''} + {} sage: sorted(list(parse_optional_tags("sage: #optional -- foo bar, baz"))) ['bar', 'foo'] sage: parse_optional_tags("sage: #optional -- foo.bar, baz") - {'foo.bar'} + {'foo.bar': None} + sage: parse_optional_tags("sage: #needs foo.bar, baz") + {'foo.bar': None} sage: sorted(list(parse_optional_tags(" sage: factor(10^(10^10) + 1) # LoNg TiME, NoT TeSTED; OptioNAL -- P4cka9e"))) ['long time', 'not tested', 'p4cka9e'] sage: parse_optional_tags(" sage: raise RuntimeError # known bug") - {'bug'} + {'bug': None} sage: sorted(list(parse_optional_tags(" sage: determine_meaning_of_life() # long time, not implemented"))) ['long time', 'not implemented'] We don't parse inside strings:: sage: parse_optional_tags(" sage: print(' # long time')") - set() + {} sage: parse_optional_tags(" sage: print(' # long time') # not tested") - {'not tested'} + {'not tested': None} UTF-8 works:: - sage: parse_optional_tags("'ฤ›ลกฤล™ลพรฝรกรญรฉฤฤŽ'") - set() + sage: parse_optional_tags("'ฤ›ลกฤล™ลพรฝรกรญรฉฤฤŽ'") + {} + + Tags with parenthesized explanations:: + + sage: parse_optional_tags(" sage: 1 + 1 # long time (1 year, 2 months??), optional - bliss (because)") + {'bliss': 'because', 'long time': '1 year, 2 months??'} + + With ``return_string_sans_tags=True``:: + + sage: parse_optional_tags("sage: print(1) # very important 1 # optional - foo", + ....: return_string_sans_tags=True) + ({'foo': None}, 'sage: print(1) # very important 1 ', False) + sage: parse_optional_tags("sage: print( # very important too # optional - foo\n....: 2)", + ....: return_string_sans_tags=True) + ({'foo': None}, 'sage: print( # very important too \n....: 2)', False) + sage: parse_optional_tags("sage: #this is persistent #needs scipy", + ....: return_string_sans_tags=True) + ({'scipy': None}, 'sage: #this is persistent ', True) + sage: parse_optional_tags("sage: #this is not #needs scipy\n....: import scipy", + ....: return_string_sans_tags=True) + ({'scipy': None}, 'sage: #this is not \n....: import scipy', False) + """ safe, literals, state = strip_string_literals(string) - first_line = safe.split('\n', 1)[0] - if '#' not in first_line: - return set() - comment = first_line[first_line.find('#') + 1:] - comment = comment[comment.index('(') + 1: comment.rindex(')')] - # strip_string_literals replaces comments - comment = "#" + (literals[comment]).lower() + split = safe.split('\n', 1) + if len(split) > 1: + first_line, rest = split + else: + first_line, rest = split[0], None - optional_regex = re.compile(r'(arb216|arb218|py2|long time|not implemented|not tested|known bug)|([^ a-z]\s*optional\s*[:-]*((\s|\w|[.])*))') + sharp_index = first_line.find('#') + if sharp_index < 0: # no comment + if return_string_sans_tags: + return {}, string, False + else: + return {} + + first_line_sans_comments, comment = first_line[:sharp_index] % literals, first_line[sharp_index:] % literals + if not first_line_sans_comments.endswith(" ") and not first_line_sans_comments.rstrip().endswith("sage:"): + # Enforce two spaces before comment + first_line_sans_comments = first_line_sans_comments.rstrip() + " " + + if return_string_sans_tags: + # skip non-tag comments that precede the first tag comment + if m := optional_regex.search(comment): + sharp_index = comment[:m.start(0) + 1].rfind('#') + if sharp_index >= 0: + first_line = first_line_sans_comments + comment[:sharp_index] + comment = comment[sharp_index:] + else: + # no tag comment + return {}, string, False - tags = [] + tags = {} for m in optional_regex.finditer(comment): - cmd = m.group(1) - if cmd == 'known bug': - tags.append('bug') # so that such tests will be run by sage -t ... -only-optional=bug + cmd = m.group('cmd') + if cmd and cmd.lower() == 'known bug': + tags['bug'] = None # so that such tests will be run by sage -t ... -only-optional=bug elif cmd: - tags.append(cmd) + tags[cmd.lower()] = m.group('cmd_explanation') or None else: - tags.extend(m.group(3).split() or [""]) - return set(tags) + # optional/needs + tags.update({m.group(1).lower(): m.group(2) or None + for m in tag_with_explanation_regex.finditer(m.group('tags'))}) + + if return_string_sans_tags: + is_persistent = tags and first_line_sans_comments.strip() == 'sage:' and not rest # persistent (block-scoped) tag + return tags, (first_line + '\n' + rest%literals if rest is not None + else first_line), is_persistent + else: + return tags -def parse_tolerance(source, want): +def parse_file_optional_tags(lines): + r""" + Scan the first few lines for file-level doctest directives. + + INPUT: + + - ``lines`` -- iterable of pairs ``(lineno, line)``. + + OUTPUT: + + a dictionary whose keys are strings (tags); see :func:`parse_optional_tags` + + EXAMPLES:: + + sage: from sage.doctest.parsing import parse_file_optional_tags + sage: filename = tmp_filename(ext=".pyx") + sage: with open(filename, "r") as f: + ....: parse_file_optional_tags(enumerate(f)) + {} + sage: with open(filename, "w") as f: + ....: _ = f.write("# nodoctest") + sage: with open(filename, "r") as f: + ....: parse_file_optional_tags(enumerate(f)) + {'not tested': None} + sage: with open(filename, "w") as f: + ....: _ = f.write("# sage.doctest: " # broken in two source lines to avoid the pattern + ....: "optional - xyz") # of relint (multiline_doctest_comment) + sage: with open(filename, "r") as f: + ....: parse_file_optional_tags(enumerate(f)) + {'xyz': None} + """ + tags = {} + for line_count, line in lines: + if nodoctest_regex.match(line): + tags['not tested'] = None + if m := optionalfiledirective_regex.match(line): + file_tag_string = m.group(2) + tags.update(parse_optional_tags('#' + file_tag_string)) + if line_count >= 10: + break + return tags + + +@cached_function +def _standard_tags(): + r""" + Return the set of the names of all standard features. + + EXAMPLES:: + + sage: from sage.doctest.parsing import _standard_tags + sage: sorted(_standard_tags()) + [..., 'numpy', ..., 'sage.rings.finite_rings', ...] + """ + from sage.features.all import all_features + return frozenset(feature.name for feature in all_features() + if feature._spkg_type() == 'standard') + + +def _tag_group(tag): + r""" + Classify a doctest tag as belonging to one of 4 groups. + + INPUT: + + - ``tag`` -- string + + OUTPUT: + + a string; one of ``'special'``, ``'optional'``, ``'standard'``, ``'sage'`` + + EXAMPLES:: + + sage: from sage.doctest.parsing import _tag_group + sage: _tag_group('scipy') + 'standard' + sage: _tag_group('sage.numerical.mip') + 'sage' + sage: _tag_group('bliss') + 'optional' + sage: _tag_group('not tested') + 'special' + """ + if tag.startswith('sage.'): + return 'sage' + elif tag in _standard_tags(): + return 'standard' + elif not special_optional_regex.fullmatch(tag): + return 'optional' + else: + return 'special' + + +def unparse_optional_tags(tags, prefix='# '): + r""" + Return a comment string that sets ``tags``. + + INPUT: + + - ``tags`` -- dict or iterable of tags, as output by :func:`parse_optional_tags` + + - ``prefix`` -- to be put before a nonempty string + + EXAMPLES:: + + sage: from sage.doctest.parsing import unparse_optional_tags + sage: unparse_optional_tags({}) + '' + sage: unparse_optional_tags({'magma': None}) + '# optional - magma' + sage: unparse_optional_tags({'fictional_optional': None, + ....: 'sage.rings.number_field': None, + ....: 'scipy': 'just because', + ....: 'bliss': None}) + '# optional - bliss fictional_optional, needs scipy (just because) sage.rings.number_field' + sage: unparse_optional_tags(['long time', 'not tested', 'p4cka9e'], prefix='') + 'long time, not tested, optional - p4cka9e' """ + group = defaultdict(set) + if isinstance(tags, collections.abc.Mapping): + for tag, explanation in tags.items(): + if tag == 'bug': + tag = 'known bug' + group[_tag_group(tag)].add(f'{tag} ({explanation})' if explanation else tag) + else: + for tag in tags: + if tag == 'bug': + tag = 'known bug' + group[_tag_group(tag)].add(tag) + + tags = sorted(group.pop('special', [])) + if 'optional' in group: + tags.append('optional - ' + " ".join(sorted(group.pop('optional')))) + if 'standard' in group or 'sage' in group: + tags.append('needs ' + " ".join(sorted(group.pop('standard', [])) + + sorted(group.pop('sage', [])))) + assert not group + if tags: + return prefix + ', '.join(tags) + return '' + + +optional_tag_columns = [48, 56, 64, 72, 80, 84] +standard_tag_columns = [88, 100, 120, 160] + + +def update_optional_tags(line, tags=None, *, add_tags=None, remove_tags=None, force_rewrite=False): + r""" + Return the doctest ``line`` with tags changed. + + EXAMPLES:: + + sage: from sage.doctest.parsing import update_optional_tags, optional_tag_columns, standard_tag_columns + sage: ruler = '' + sage: for column in optional_tag_columns: + ....: ruler += ' ' * (column - len(ruler)) + 'V' + sage: for column in standard_tag_columns: + ....: ruler += ' ' * (column - len(ruler)) + 'v' + sage: def print_with_ruler(lines): + ....: print('|' + ruler) + ....: for line in lines: + ....: print('|' + line) + sage: print_with_ruler([ # the tags are obscured in the source file to avoid relint warnings + ....: update_optional_tags(' sage: something() # opt' 'ional - latte_int', + ....: remove_tags=['latte_int', 'wasnt_even_there']), + ....: update_optional_tags(' sage: nothing_to_be_seen_here()', + ....: tags=['scipy', 'long time']), + ....: update_optional_tags(' sage: nothing_to_be_seen_here(honestly=True)', + ....: add_tags=['scipy', 'long time']), + ....: update_optional_tags(' sage: nothing_to_be_seen_here(honestly=True, very=True)', + ....: add_tags=['scipy', 'long time']), + ....: update_optional_tags(' sage: no_there_is_absolutely_nothing_to_be_seen_here_i_am_serious()#opt' 'ional:bliss', + ....: add_tags=['scipy', 'long time']), + ....: update_optional_tags(' sage: ntbsh() # abbrv for above#opt' 'ional:bliss', + ....: add_tags={'scipy': None, 'long time': '30s on the highest setting'}), + ....: update_optional_tags(' sage: no_there_is_absolutely_nothing_to_be_seen_here_i_am_serious() # really, you can trust me here', + ....: add_tags=['scipy']), + ....: ]) + | V V V V V V v v v v + | sage: something() + | sage: nothing_to_be_seen_here() # long time # needs scipy + | sage: nothing_to_be_seen_here(honestly=True) # long time # needs scipy + | sage: nothing_to_be_seen_here(honestly=True, very=True) # long time # needs scipy + | sage: no_there_is_absolutely_nothing_to_be_seen_here_i_am_serious() # long time, optional - bliss, needs scipy + | sage: ntbsh() # abbrv for above # long time (30s on the highest setting), optional - bliss, needs scipy + | sage: no_there_is_absolutely_nothing_to_be_seen_here_i_am_serious() # really, you can trust me here # needs scipy + + When no tags are changed, by default, the unchanged input is returned. + We can force a rewrite; unconditionally or whenever standard tags are involved. + But even when forced, if comments are already aligned at one of the standard alignment columns, + this alignment is kept even if we would normally realign farther to the left:: + + sage: print_with_ruler([ + ....: update_optional_tags(' sage: unforced() # opt' 'ional - latte_int'), + ....: update_optional_tags(' sage: unforced() # opt' 'ional - latte_int', + ....: add_tags=['latte_int']), + ....: update_optional_tags(' sage: forced()#opt' 'ional- latte_int', + ....: force_rewrite=True), + ....: update_optional_tags(' sage: forced() # opt' 'ional - scipy', + ....: force_rewrite='standard'), + ....: update_optional_tags(' sage: aligned_with_below() # opt' 'ional - 4ti2', + ....: force_rewrite=True), + ....: update_optional_tags(' sage: aligned_with_above() # opt' 'ional - 4ti2', + ....: force_rewrite=True), + ....: update_optional_tags(' sage: also_already_aligned() # ne' 'eds scipy', + ....: force_rewrite='standard'), + ....: update_optional_tags(' sage: two_columns_first_preserved() # lo' 'ng time # ne' 'eds scipy', + ....: force_rewrite='standard'), + ....: update_optional_tags(' sage: two_columns_first_preserved() # lo' 'ng time # ne' 'eds scipy', + ....: force_rewrite='standard'), + ....: ]) + | V V V V V V v v v v + | sage: unforced() # optional - latte_int + | sage: unforced() # optional - latte_int + | sage: forced() # optional - latte_int + | sage: forced() # needs scipy + | sage: aligned_with_below() # optional - 4ti2 + | sage: aligned_with_above() # optional - 4ti2 + | sage: also_already_aligned() # needs scipy + | sage: two_columns_first_preserved() # long time # needs scipy + | sage: two_columns_first_preserved() # long time # needs scipy + + Rewriting a persistent (block-scoped) tag:: + + sage: print_with_ruler([ + ....: update_optional_tags(' sage: #opt' 'ional:magma sage.symbolic', + ....: force_rewrite=True), + ....: ]) + | V V V V V V v v v v + | sage: # optional - magma, needs sage.symbolic + """ + if not (m := re.match('( *sage: *)(.*)', line)): + raise ValueError(f'line must start with a sage: prompt, got: {line}') + + current_tags, line_sans_tags, is_persistent = parse_optional_tags(line.rstrip(), return_string_sans_tags=True) + + if isinstance(tags, collections.abc.Mapping): + new_tags = dict(tags) + elif tags is not None: + new_tags = {tag: None for tag in tags} + else: + new_tags = dict(current_tags) + + if add_tags is not None: + if isinstance(add_tags, collections.abc.Mapping): + new_tags.update(add_tags) + else: + new_tags.update({tag: None for tag in add_tags}) + + if remove_tags is not None: + for tag in remove_tags: + new_tags.pop(tag, None) + + if not force_rewrite and new_tags == current_tags: + return line + + if not new_tags: + return line_sans_tags.rstrip() + + if (force_rewrite == 'standard' + and new_tags == current_tags + and not any(_tag_group(tag) in ['standard', 'sage'] + for tag in new_tags)): + return line + + if is_persistent: + line = line_sans_tags.rstrip() + ' ' + else: + group = defaultdict(set) + for tag in new_tags: + group[_tag_group(tag)].add(tag) + tag_columns = (optional_tag_columns if group['optional'] or group['special'] + else standard_tag_columns) + + if len(line_sans_tags) in tag_columns and line_sans_tags[-2:] == ' ': + # keep alignment + line = line_sans_tags + pass + else: + # realign + line = line_sans_tags.rstrip() + for column in tag_columns: + if len(line) <= column - 2: + line += ' ' * (column - 2 - len(line)) + break + line += ' ' + + if (group['optional'] or group['special']) and (group['standard'] or group['sage']): + # Try if two-column mode works better + first_part = unparse_optional_tags({tag: explanation + for tag, explanation in new_tags.items() + if (tag in group['optional'] + or tag in group['special'])}) + column = standard_tag_columns[0] + if len(line + first_part) + 8 <= column: + line += first_part + line += ' ' * (column - len(line)) + line += unparse_optional_tags({tag: explanation + for tag, explanation in new_tags.items() + if not (tag in group['optional'] + or tag in group['special'])}) + return line.rstrip() + + line += unparse_optional_tags(new_tags) + return line + + +def parse_tolerance(source, want): + r""" Return a version of ``want`` marked up with the tolerance tags specified in ``source``. @@ -163,8 +558,8 @@ def parse_tolerance(source, want): OUTPUT: - - ``want`` if there are no tolerance tags specified; a - :class:`MarkedOutput` version otherwise. + ``want`` if there are no tolerance tags specified; a + :class:`MarkedOutput` version otherwise. EXAMPLES:: @@ -442,13 +837,15 @@ class SageDocTestParser(doctest.DocTestParser): A version of the standard doctest parser which handles Sage's custom options and tolerances in floating point arithmetic. """ - def __init__(self, optional_tags=(), long=False): + def __init__(self, optional_tags=(), long=False, *, probed_tags=(), file_optional_tags=()): r""" INPUT: - ``optional_tags`` -- a list or tuple of strings. - ``long`` -- boolean, whether to run doctests marked as taking a long time. + - ``probed_tags`` -- a list or tuple of strings. + - ``file_optional_tags`` -- an iterable of strings. EXAMPLES:: @@ -477,6 +874,8 @@ def __init__(self, optional_tags=(), long=False): self.optional_tags.remove('sage') else: self.optional_only = True + self.probed_tags = probed_tags + self.file_optional_tags = set(file_optional_tags) def __eq__(self, other): """ @@ -522,7 +921,7 @@ def parse(self, string, *args): - A list consisting of strings and :class:`doctest.Example` instances. There will be at least one string between - successive examples (exactly one unless or long or optional + successive examples (exactly one unless long or optional tests are removed), and it will begin and end with a string. EXAMPLES:: @@ -571,7 +970,7 @@ def parse(self, string, *args): of the current line should be joined to the next line. This feature allows for breaking large integers over multiple lines but is not standard for Python doctesting. It's not - guaranteed to persist, but works in Sage 5.5:: + guaranteed to persist:: sage: n = 1234\ ....: 5678 @@ -587,6 +986,23 @@ def parse(self, string, *args): sage: print(m) 87654321 + Optional tags at the start of an example block persist to the end of + the block (delimited by a blank line):: + + sage: # long time, needs sage.rings.number_field + sage: QQbar(I)^10000 + 1 + sage: QQbar(I)^10000 # not tested + I + + sage: # needs sage.rings.finite_rings + sage: GF(7) + Finite Field of size 7 + sage: GF(10) + Traceback (most recent call last): + ... + ValueError: the order of a finite field must be a prime power + Test that :trac:`26575` is resolved:: sage: example3 = 'sage: Zp(5,4,print_mode="digits")(5)\n...00010' @@ -596,6 +1012,90 @@ def parse(self, string, *args): 'Zp(5,4,print_mode="digits")(5)\n' sage: dte.want '...00010\n' + + Style warnings:: + + sage: def parse(test_string): + ....: return [x if isinstance(x, str) + ....: else (getattr(x, 'warnings', None), x.sage_source, x.source) + ....: for x in DTP.parse(test_string)] + + sage: parse('sage: 1 # optional guava mango\nsage: 2 # optional guava\nsage: 3 # optional guava\nsage: 4 # optional guava\nsage: 5 # optional guava\n\nsage: 11 # optional guava') + ['', + (["Consider using a block-scoped tag by inserting the line 'sage: # optional - guava' just before this line to avoid repeating the tag 5 times"], + '1 # optional guava mango\n', + 'None # virtual doctest'), + '', + (None, '2 # optional guava\n', 'Integer(2) # optional guava\n'), + '', + (None, '3 # optional guava\n', 'Integer(3) # optional guava\n'), + '', + (None, '4 # optional guava\n', 'Integer(4) # optional guava\n'), + '', + (None, '5 # optional guava\n', 'Integer(5) # optional guava\n'), + '\n', + (None, '11 # optional guava\n', 'Integer(11) # optional guava\n'), + ''] + + sage: parse('sage: 1 # optional guava\nsage: 2 # optional guava mango\nsage: 3 # optional guava\nsage: 4 # optional guava\nsage: 5 # optional guava\n') + ['', + (["Consider using a block-scoped tag by inserting the line 'sage: # optional - guava' just before this line to avoid repeating the tag 5 times"], + '1 # optional guava\n', + 'Integer(1) # optional guava\n'), + '', + '', + (None, '3 # optional guava\n', 'Integer(3) # optional guava\n'), + '', + (None, '4 # optional guava\n', 'Integer(4) # optional guava\n'), + '', + (None, '5 # optional guava\n', 'Integer(5) # optional guava\n'), + ''] + + sage: parse('sage: # optional mango\nsage: 1 # optional guava\nsage: 2 # optional guava mango\nsage: 3 # optional guava\nsage: 4 # optional guava\n sage: 5 # optional guava\n') # optional - guava mango + ['', + (["Consider updating this block-scoped tag to 'sage: # optional - guava mango' to avoid repeating the tag 5 times"], + '# optional mango\n', + 'None # virtual doctest'), + '', + '', + '', + '', + '', + ''] + + sage: parse('::\n\n sage: 1 # optional guava\n sage: 2 # optional guava mango\n sage: 3 # optional guava\n\n::\n\n sage: 4 # optional guava\n sage: 5 # optional guava\n') + ['::\n\n', + (None, '1 # optional guava\n', 'Integer(1) # optional guava\n'), + '', + '', + (None, '3 # optional guava\n', 'Integer(3) # optional guava\n'), + '\n::\n\n', + (None, '4 # optional guava\n', 'Integer(4) # optional guava\n'), + '', + (None, '5 # optional guava\n', 'Integer(5) # optional guava\n'), + ''] + + TESTS:: + + sage: parse("::\n\n sage: # needs sage.combinat\n sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \\\n ....: import incidence_matrix_to_bit_rep_of_Vrep\n sage: P = polytopes.associahedron(['A',3])\n\n") + ['::\n\n', + '', + (None, + 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions import incidence_matrix_to_bit_rep_of_Vrep\n', + 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions import incidence_matrix_to_bit_rep_of_Vrep\n'), + '', + (None, + "P = polytopes.associahedron(['A',3])\n", + "P = polytopes.associahedron(['A',Integer(3)])\n"), + '\n'] + + sage: example4 = '::\n\n sage: C.minimum_distance(algorithm="guava") # optional - guava\n ...\n 24\n\n' + sage: parsed4 = DTP.parse(example4) + sage: dte = parsed4[1] + sage: dte.sage_source + 'C.minimum_distance(algorithm="guava") # optional - guava\n' + sage: dte.want + '...\n24\n' """ # Regular expressions find_sage_prompt = re.compile(r"^(\s*)sage: ", re.M) @@ -603,7 +1103,7 @@ def parse(self, string, *args): find_python_continuation = re.compile(r"^(\s*)\.\.\.([^\.])", re.M) python_prompt = re.compile(r"^(\s*)>>>", re.M) backslash_replacer = re.compile(r"""(\s*)sage:(.*)\\\ * -\ *(((\.){4}:)|((\.){3}))?\ *""") +\ *((\.){4}:)?\ *""") # The following are used to allow ... at the beginning of output ellipsis_tag = "<TEMP_ELLIPSIS_TAG>" @@ -612,13 +1112,8 @@ def parse(self, string, *args): # doctest system. m = backslash_replacer.search(string) while m is not None: - next_prompt = find_sage_prompt.search(string, m.end()) g = m.groups() - if next_prompt: - future = string[m.end():next_prompt.start()] + '\n' + string[next_prompt.start():] - else: - future = string[m.end():] - string = string[:m.start()] + g[0] + "sage:" + g[1] + future + string = string[:m.start()] + g[0] + "sage:" + g[1] + string[m.end():] m = backslash_replacer.search(string, m.start()) replace_ellipsis = not python_prompt.search(string) @@ -630,9 +1125,77 @@ def parse(self, string, *args): string = find_sage_continuation.sub(r"\1...", string) res = doctest.DocTestParser.parse(self, string, *args) filtered = [] + persistent_optional_tags = self.file_optional_tags + persistent_optional_tag_setter = None + persistent_optional_tag_setter_index = None + first_example_in_block = None + first_example_in_block_index = None + tag_count_within_block = defaultdict(lambda: 0) + + def update_tag_counts(optional_tags): + for tag in optional_tags: + if tag not in persistent_optional_tags: + tag_count_within_block[tag] += 1 + tag_count_within_block[''] += 1 + + def check_and_clear_tag_counts(): + if (num_examples := tag_count_within_block['']) >= 4: + if overused_tags := set(tag for tag, count in tag_count_within_block.items() + if tag and count >= num_examples): + overused_tags.update(persistent_optional_tags) + overused_tags.difference_update(self.file_optional_tags) + suggested = unparse_optional_tags(overused_tags, prefix='sage: # ') + + if persistent_optional_tag_setter: + warning_example = persistent_optional_tag_setter + index = persistent_optional_tag_setter_index + warning = (f"Consider updating this block-scoped tag to '{suggested}' " + f"to avoid repeating the tag {num_examples} times") + else: + warning_example = first_example_in_block + index = first_example_in_block_index + warning = (f"Consider using a block-scoped tag by " + f"inserting the line '{suggested}' just before this line " + f"to avoid repeating the tag {num_examples} times") + + if not (index < len(filtered) and filtered[index] == warning_example): + # The example to which we want to attach our warning is + # not in ``filtered``. It is either the persistent tag line, + # or the first example of the block and not run because of unmet tags, + # or just a comment. Either way, we transform this example + # to a virtual example and attach the warning to it. + warning_example.sage_source = warning_example.source + if warning_example.sage_source.startswith("sage: "): + warning_example.sage_source = warning_example.source[6:] + warning_example.source = 'None # virtual doctest' + warning_example.want = '' + filtered.insert(index, warning_example) + + if not hasattr(warning_example, 'warnings'): + warning_example.warnings = [] + warning_example.warnings.append(warning) + tag_count_within_block.clear() + for item in res: if isinstance(item, doctest.Example): - optional_tags = parse_optional_tags(item.source) + optional_tags, source_sans_tags, is_persistent = parse_optional_tags(item.source, return_string_sans_tags=True) + optional_tags = set(optional_tags) + if is_persistent: + check_and_clear_tag_counts() + persistent_optional_tags = optional_tags + persistent_optional_tags.update(self.file_optional_tags) + persistent_optional_tag_setter = first_example_in_block = item + persistent_optional_tag_setter_index = len(filtered) + first_example_in_block_index = None + continue + + if not first_example_in_block: + first_example_in_block = item + first_example_in_block_index = len(filtered) + update_tag_counts(optional_tags) + optional_tags.update(persistent_optional_tags) + item.optional_tags = frozenset(optional_tags) + item.probed_tags = set() if optional_tags: for tag in optional_tags: self.optionals[tag] += 1 @@ -647,13 +1210,34 @@ def parse(self, string, *args): continue if self.optional_tags is not True: - extra = optional_tags - self.optional_tags # set difference + extra = set(tag + for tag in optional_tags + if (tag not in self.optional_tags + and tag not in available_software)) if extra: - if not available_software.issuperset(extra): + if any(tag in external_software for tag in extra): + # never probe "external" software + continue + if any(tag in ['webbrowser'] for tag in extra): + # never probe + continue + if any(tag in ['got', 'expected', 'nameerror'] for tag in extra): + # never probe special tags added by sage-fixdoctests + continue + if all(tag in persistent_optional_tags for tag in extra): + # don't probe if test is only conditional + # on file-level or block-level tags + continue + if self.probed_tags is True: + item.probed_tags = extra + elif all(tag in self.probed_tags for tag in extra): + item.probed_tags = extra + else: continue elif self.optional_only: self.optionals['sage'] += 1 continue + if replace_ellipsis: item.want = item.want.replace(ellipsis_tag, "...") if item.exc_msg is not None: @@ -664,7 +1248,16 @@ def parse(self, string, *args): if item.sage_source.lstrip().startswith('#'): continue item.source = preparse(item.sage_source) + else: + if '\n' in item: + check_and_clear_tag_counts() + persistent_optional_tags = self.file_optional_tags + persistent_optional_tag_setter = first_example_in_block = None + persistent_optional_tag_setter_index = first_example_in_block_index = None filtered.append(item) + + check_and_clear_tag_counts() + return filtered @@ -748,11 +1341,11 @@ def add_tolerance(self, wantval, want): sage: want_tol = MarkedOutput().update(tol=0.0001) sage: want_abs = MarkedOutput().update(abs_tol=0.0001) sage: want_rel = MarkedOutput().update(rel_tol=0.0001) - sage: OC.add_tolerance(RIF(pi.n(64)), want_tol).endpoints() + sage: OC.add_tolerance(RIF(pi.n(64)), want_tol).endpoints() # needs sage.symbolic (3.14127849432443, 3.14190681285516) - sage: OC.add_tolerance(RIF(pi.n(64)), want_abs).endpoints() + sage: OC.add_tolerance(RIF(pi.n(64)), want_abs).endpoints() # needs sage.symbolic (3.14149265358979, 3.14169265358980) - sage: OC.add_tolerance(RIF(pi.n(64)), want_rel).endpoints() + sage: OC.add_tolerance(RIF(pi.n(64)), want_rel).endpoints() # needs sage.symbolic (3.14127849432443, 3.14190681285516) sage: OC.add_tolerance(RIF(1e1000), want_tol) 1.000?e1000 @@ -862,7 +1455,7 @@ def check_output(self, want, got, optionflags): More explicit tolerance checks:: - sage: _ = x # rel tol 1e10 + sage: _ = x # rel tol 1e10 # needs sage.symbolic sage: raise RuntimeError # rel tol 1e10 Traceback (most recent call last): ... @@ -1047,6 +1640,17 @@ def do_fixup(self, want, got): got = ld_pie_warning_regex.sub('', got) did_fixup = True + if "Overriding pythran description" in got: + # Some signatures changed in numpy-1.25.x that may yet be + # reverted, but which pythran would otherwise warn about. + # Pythran has a special case for numpy.random that hides + # the warning -- I guess until we know if the changes will + # be reverted -- but only in v0.14.0 of pythran. Ignoring + # This warning allows us to support older pythran with e.g. + # numpy-1.25.2. + pythran_numpy_warning_regex = re.compile(r'WARNING: Overriding pythran description with argspec information for: numpy\.random\.[a-z_]+') + got = pythran_numpy_warning_regex.sub('', got) + did_fixup = True return did_fixup, want, got def output_difference(self, example, got, optionflags): diff --git a/src/sage/doctest/reporting.py b/src/sage/doctest/reporting.py index 51c6ea55626..361fea344c2 100644 --- a/src/sage/doctest/reporting.py +++ b/src/sage/doctest/reporting.py @@ -23,10 +23,16 @@ """ # **************************************************************************** -# Copyright (C) 2012 David Roe <roed.math@gmail.com> -# Robert Bradshaw <robertwb@gmail.com> -# William Stein <wstein@gmail.com> -# Copyright (C) 2013 Jeroen Demeyer <jdemeyer@cage.ugent.be> +# Copyright (C) 2012-2013 David Roe <roed.math@gmail.com> +# 2012 Robert Bradshaw <robertwb@gmail.com> +# 2012 William Stein <wstein@gmail.com> +# 2013 R. Andrew Ohana +# 2013 Jeroen Demeyer <jdemeyer@cage.ugent.be> +# 2013-2017 Volker Braun +# 2018 Julian Rรผth +# 2018-2021 Sรฉbastien Labbรฉ +# 2020 Samuel Leliรจvre +# 2022 Matthias Koeppe # # 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 @@ -258,7 +264,9 @@ def report(self, source, timeout, return_code, results, output, pid=None): Output so far... ********************************************************************** sage: DTR.stats - {'sage.doctest.reporting': {'failed': True, 'walltime': 1000000.0}} + {'sage.doctest.reporting': {'failed': True, + 'ntests': 0, + 'walltime': 1000000.0}} Or a process that returned a bad exit code:: @@ -269,7 +277,9 @@ def report(self, source, timeout, return_code, results, output, pid=None): Output before trouble ********************************************************************** sage: DTR.stats - {'sage.doctest.reporting': {'failed': True, 'walltime': 1000000.0}} + {'sage.doctest.reporting': {'failed': True, + 'ntests': 0, + 'walltime': 1000000.0}} Or a process that segfaulted:: @@ -281,7 +291,9 @@ def report(self, source, timeout, return_code, results, output, pid=None): Output before trouble ********************************************************************** sage: DTR.stats - {'sage.doctest.reporting': {'failed': True, 'walltime': 1000000.0}} + {'sage.doctest.reporting': {'failed': True, + 'ntests': 0, + 'walltime': 1000000.0}} Report a timeout with results and a ``SIGKILL``:: @@ -293,7 +305,9 @@ def report(self, source, timeout, return_code, results, output, pid=None): Output before trouble ********************************************************************** sage: DTR.stats - {'sage.doctest.reporting': {'failed': True, 'walltime': 1000000.0}} + {'sage.doctest.reporting': {'failed': True, + 'ntests': 1, + 'walltime': 1000000.0}} This is an internal error since results is None:: @@ -304,12 +318,15 @@ def report(self, source, timeout, return_code, results, output, pid=None): All output ********************************************************************** sage: DTR.stats - {'sage.doctest.reporting': {'failed': True, 'walltime': 1000000.0}} + {'sage.doctest.reporting': {'failed': True, + 'ntests': 1, + 'walltime': 1000000.0}} Or tell the user that everything succeeded:: sage: doctests, extras = FDS.create_doctests(globals()) - sage: runner = SageDocTestRunner(SageOutputChecker(), verbose=False, sage_options=DD, optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) + sage: runner = SageDocTestRunner(SageOutputChecker(), verbose=False, sage_options=DD, + ....: optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) sage: Timer().start().stop().annotate(runner) sage: D = DictAsObject({'err':None}) sage: runner.update_results(D) @@ -317,7 +334,7 @@ def report(self, source, timeout, return_code, results, output, pid=None): sage: DTR.report(FDS, False, 0, (sum([len(t.examples) for t in doctests]), D), "Good tests") [... tests, ... s] sage: DTR.stats - {'sage.doctest.reporting': {'walltime': ...}} + {'sage.doctest.reporting': {'ntests': ..., 'walltime': ...}} Or inform the user that some doctests failed:: @@ -360,7 +377,8 @@ def report(self, source, timeout, return_code, results, output, pid=None): sage: DC = DocTestController(DD, [filename]) sage: DTR = DocTestReporter(DC) sage: doctests, extras = FDS.create_doctests(globals()) - sage: runner = SageDocTestRunner(SageOutputChecker(), verbose=False, sage_options=DD, optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) + sage: runner = SageDocTestRunner(SageOutputChecker(), verbose=False, sage_options=DD, + ....: optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) sage: Timer().start().stop().annotate(runner) sage: D = DictAsObject({'err':None}) sage: runner.update_results(D) @@ -411,7 +429,7 @@ def report(self, source, timeout, return_code, results, output, pid=None): log(output) log("*"*70) postscript['lines'].append(cmd + " # %s"%fail_msg) - stats[basename] = dict(failed=True, walltime=1e6) + stats[basename] = dict(failed=True, walltime=1e6, ntests=ntests) if not the_baseline_stats.get('failed', False): self.error_status |= 4 elif return_code: @@ -427,7 +445,7 @@ def report(self, source, timeout, return_code, results, output, pid=None): log(output) log("*"*70) postscript['lines'].append(cmd + " # %s" % fail_msg) - stats[basename] = dict(failed=True, walltime=1e6) + stats[basename] = dict(failed=True, walltime=1e6, ntests=ntests) if not the_baseline_stats.get('failed', False): self.error_status |= (8 if return_code > 0 else 16) else: @@ -483,9 +501,9 @@ def report(self, source, timeout, return_code, results, output, pid=None): if hasattr(result_dict, 'tb'): log(result_dict.tb) if hasattr(result_dict, 'walltime'): - stats[basename] = dict(failed=True, walltime=wall) + stats[basename] = dict(failed=True, walltime=wall, ntests=ntests) else: - stats[basename] = dict(failed=True, walltime=1e6) + stats[basename] = dict(failed=True, walltime=1e6, ntests=ntests) self.error_status |= 64 if result_dict.err is None or result_dict.err == 'tab': f = result_dict.failures @@ -497,9 +515,9 @@ def report(self, source, timeout, return_code, results, output, pid=None): if not the_baseline_stats.get('failed', False): self.error_status |= 1 if f or result_dict.err == 'tab': - stats[basename] = dict(failed=True, walltime=wall) + stats[basename] = dict(failed=True, walltime=wall, ntests=ntests) else: - stats[basename] = dict(walltime=wall) + stats[basename] = dict(walltime=wall, ntests=ntests) postscript['cputime'] += cpu postscript['walltime'] += wall @@ -556,7 +574,6 @@ def report(self, source, timeout, return_code, results, output, pid=None): import traceback log(traceback.format_exc(), end="") - def finalize(self): """ Print out the postscript that summarizes the doctests that were run. diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index 6321e73a5e8..5064496052b 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -10,9 +10,17 @@ """ # **************************************************************************** -# Copyright (C) 2012 David Roe <roed.math@gmail.com> -# Robert Bradshaw <robertwb@gmail.com> -# William Stein <wstein@gmail.com> +# Copyright (C) 2012-2013 David Roe <roed.math@gmail.com> +# 2012 Robert Bradshaw <robertwb@gmail.com> +# 2012 William Stein <wstein@gmail.com> +# 2013 R. Andrew Ohana +# 2013-2017 Jeroen Demeyer <jdemeyer@cage.ugent.be> +# 2013-2019 John H. Palmieri +# 2014 Volker Braun +# 2014-2022 Frรฉdรฉric Chapoton +# 2017 Erik M. Bray +# 2021 Sรฉbastien Labbรฉ +# 2021-2023 Matthias Koeppe # # Distributed under the terms of the GNU General Public License (GPL) # @@ -76,8 +84,10 @@ def get_basename(path): sage: from sage.doctest.sources import get_basename sage: from sage.env import SAGE_SRC sage: import os - sage: get_basename(os.path.join(SAGE_SRC,'sage','doctest','sources.py')) + sage: get_basename(os.path.join(SAGE_SRC, 'sage', 'doctest', 'sources.py')) 'sage.doctest.sources' + sage: get_basename(os.path.join(SAGE_SRC, 'sage', 'structure', 'element.pxd')) + 'sage.structure.element.pxd' """ if path is None: return None @@ -103,10 +113,14 @@ def get_basename(path): # it goes. while is_package_or_sage_namespace_package_dir(root): root = os.path.dirname(root) - fully_qualified_path = os.path.splitext(path[len(root) + 1:])[0] + fully_qualified_path, ext = os.path.splitext(path[len(root) + 1:]) if os.path.split(path)[1] == '__init__.py': fully_qualified_path = fully_qualified_path[:-9] - return fully_qualified_path.replace(os.path.sep, '.') + basename = fully_qualified_path.replace(os.path.sep, '.') + if ext in ['.pxd', '.pxi']: + # disambiguate from .pyx with the same basename + basename += ext + return basename class DocTestSource(): @@ -151,7 +165,7 @@ def __eq__(self, other): sage: FDS == FDS2 True """ - if type(self) != type(other): + if type(self) is not type(other): return False return self.__dict__ == other.__dict__ @@ -224,9 +238,31 @@ def _process_doc(self, doctests, doc, namespace, start): # Line number refers to the end of the docstring sigon = doctest.Example(sig_on_count_doc_doctest, "0\n", lineno=docstring.count("\n")) sigon.sage_source = sig_on_count_doc_doctest + sigon.optional_tags = frozenset() + sigon.probed_tags = frozenset() dt.examples.append(sigon) doctests.append(dt) + @lazy_attribute + def file_optional_tags(self): + r""" + Return the set of tags that should apply to all doctests in this source. + + This default implementation just returns the empty set. + + EXAMPLES:: + + sage: from sage.doctest.control import DocTestDefaults + sage: from sage.doctest.sources import StringDocTestSource, PythonSource + sage: from sage.structure.dynamic_class import dynamic_class + sage: s = "'''\n sage: 2 + 2\n 4\n'''" + sage: PythonStringSource = dynamic_class('PythonStringSource', (StringDocTestSource, PythonSource)) + sage: PSS = PythonStringSource('<runtime>', s, DocTestDefaults(), 'runtime') + sage: PSS.file_optional_tags + set() + """ + return set() + def _create_doctests(self, namespace, tab_okay=None): """ Creates a list of doctests defined in this source. @@ -262,7 +298,7 @@ def _create_doctests(self, namespace, tab_okay=None): sage: FDS.qualified_name = NestedName('sage.doctest.sources') sage: doctests, extras = FDS._create_doctests({}) sage: len(doctests) - 41 + 43 sage: extras['tab'] False sage: extras['line_number'] @@ -273,7 +309,9 @@ def _create_doctests(self, namespace, tab_okay=None): self._init() self.line_shift = 0 self.parser = SageDocTestParser(self.options.optional, - self.options.long) + self.options.long, + probed_tags=self.options.probe, + file_optional_tags=self.file_optional_tags) self.linking = False doctests = [] in_docstring = False @@ -685,6 +723,25 @@ def in_lib(self): return (self.options.force_lib or is_package_or_sage_namespace_package_dir(os.path.dirname(self.path))) + @lazy_attribute + def file_optional_tags(self): + """ + Return the set of tags that should apply to all doctests in this source. + + EXAMPLES:: + + sage: from sage.doctest.control import DocTestDefaults + sage: from sage.doctest.sources import FileDocTestSource + sage: from sage.env import SAGE_SRC + sage: import os + sage: filename = os.path.join(SAGE_SRC, 'sage', 'repl', 'user_globals.py') + sage: FDS = FileDocTestSource(filename, DocTestDefaults()) + sage: FDS.file_optional_tags + {'sage.modules': None} + """ + from .parsing import parse_file_optional_tags + return parse_file_optional_tags(self) + def create_doctests(self, namespace): r""" Return a list of doctests for this file. @@ -709,16 +766,16 @@ def create_doctests(self, namespace): sage: FDS = FileDocTestSource(filename,DocTestDefaults()) sage: doctests, extras = FDS.create_doctests(globals()) sage: len(doctests) - 41 + 43 sage: extras['tab'] False We give a self referential example:: - sage: doctests[18].name + sage: doctests[20].name 'sage.doctest.sources.FileDocTestSource.create_doctests' - sage: doctests[18].examples[10].source - 'doctests[Integer(18)].examples[Integer(10)].source\n' + sage: doctests[20].examples[10].source + 'doctests[Integer(20)].examples[Integer(10)].source\n' TESTS: @@ -727,11 +784,12 @@ def create_doctests(self, namespace): sage: import sys sage: bitness = '64' if sys.maxsize > (1 << 32) else '32' - sage: gp.get_precision() == 38 + sage: gp.get_precision() == 38 # needs sage.libs.pari False # 32-bit True # 64-bit - sage: ex = doctests[18].examples[13] - sage: (bitness == '64' and ex.want == 'True \n') or (bitness == '32' and ex.want == 'False \n') + sage: ex = doctests[20].examples[13] + sage: ((bitness == '64' and ex.want == 'True \n') # needs sage.libs.pari + ....: or (bitness == '32' and ex.want == 'False \n')) True We check that lines starting with a # aren't doctested:: @@ -757,9 +815,11 @@ def create_doctests(self, namespace): def _test_enough_doctests(self, check_extras=True, verbose=True): r""" This function checks to see that the doctests are not getting - unexpectedly skipped. It uses a different (and simpler) code - path than the doctest creation functions, so there are a few - files in Sage that it counts incorrectly. + unexpectedly skipped. + + It uses a different (and simpler) code path than the doctest + creation functions. In particular, it does not understand + file-level and block-level # optional / needs tags. INPUT: @@ -772,13 +832,14 @@ def _test_enough_doctests(self, check_extras=True, verbose=True): TESTS:: + sage: # not tested (because the output will change when source files are changed) sage: from sage.doctest.control import DocTestDefaults sage: from sage.doctest.sources import FileDocTestSource sage: from sage.env import SAGE_SRC sage: cwd = os.getcwd() sage: os.chdir(SAGE_SRC) sage: import itertools - sage: for path, dirs, files in itertools.chain(os.walk('sage'), os.walk('doc')): # long time + sage: for path, dirs, files in itertools.chain(os.walk('sage'), os.walk('doc')): ....: path = os.path.relpath(path) ....: dirs.sort(); files.sort() ....: for F in files: @@ -787,7 +848,7 @@ def _test_enough_doctests(self, check_extras=True, verbose=True): ....: filename = os.path.join(path, F) ....: FDS = FileDocTestSource(filename, DocTestDefaults(long=True, optional=True, force_lib=True)) ....: FDS._test_enough_doctests(verbose=False) - There are 3 unexpected tests being run in sage/doctest/parsing.py + There are 4 unexpected tests being run in sage/doctest/parsing.py There are 1 unexpected tests being run in sage/doctest/reporting.py sage: os.chdir(cwd) """ diff --git a/src/sage/doctest/test.py b/src/sage/doctest/test.py index a36b3caf64f..aa64974fd72 100644 --- a/src/sage/doctest/test.py +++ b/src/sage/doctest/test.py @@ -251,17 +251,25 @@ Even though the doctester master process has exited, the child process is still alive, but it should be killed automatically -after the `die_timeout` given above (10 seconds):: - - sage: pid = int(open(F).read()) # long time - sage: time.sleep(2) # long time - sage: os.kill(pid, signal.SIGQUIT) # long time; 2 seconds passed => still alive - sage: time.sleep(8) # long time - sage: os.kill(pid, signal.SIGQUIT) # long time; 10 seconds passed => dead +after the ``die_timeout`` given above (10 seconds):: + + sage: # long time + sage: pid = int(open(F).read()) + sage: time.sleep(2) + sage: os.kill(pid, signal.SIGQUIT) # 2 seconds passed => still alive + sage: time.sleep(8) + sage: os.kill(pid, signal.SIGQUIT) # 10 seconds passed => dead # random Traceback (most recent call last): ... ProcessLookupError: ... +If the child process is dead and removed, the last output should be as above. +However, the child process interrupted its parent process (see +``"interrupt_diehard.rst"``), and became an orphan process. Depending on the +system, an orphan process may eventually become a zombie process instead of +being removed, and then the last output would just be a blank. Hence the ``# +random`` tag. + Test a doctest failing with ``abort()``:: sage: subprocess.call(["sage", "-t", "--warn-long", "0", # long time @@ -457,13 +465,12 @@ Running doctests ... Doctesting 1 file. sage -t --warn-long 0.0 --random-seed=0 show_skipped.rst - 1 unlabeled test not run 2 tests not run due to known bugs 1 gap test not run 1 long test not run 1 not tested test not run 0 tests not run because we ran out of time - [1 test, ... s] + [2 tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- @@ -477,11 +484,10 @@ Running doctests ... Doctesting 1 file. sage -t --long --warn-long 0.0 --random-seed=0 show_skipped.rst - 1 unlabeled test not run 2 tests not run due to known bugs 1 not tested test not run 0 tests not run because we ran out of time - [3 tests, ... s] + [4 tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- @@ -493,10 +499,9 @@ Running doctests ... Doctesting 1 file. sage -t --long --warn-long 0.0 --random-seed=0 show_skipped.rst - 1 unlabeled test not run 2 tests not run due to known bugs 1 not tested test not run - 1 sage test not run + 2 sage tests not run 0 tests not run because we ran out of time [2 tests, ... s] ---------------------------------------------------------------------- diff --git a/src/sage/doctest/util.py b/src/sage/doctest/util.py index f056ceb21b0..7446373eae0 100644 --- a/src/sage/doctest/util.py +++ b/src/sage/doctest/util.py @@ -10,8 +10,11 @@ # **************************************************************************** # Copyright (C) 2012 David Roe <roed.math@gmail.com> -# Robert Bradshaw <robertwb@gmail.com> -# William Stein <wstein@gmail.com> +# 2012 Robert Bradshaw <robertwb@gmail.com> +# 2012 William Stein <wstein@gmail.com> +# 2013 Jeroen Demeyer <jdemeyer@cage.ugent.be> +# 2014 Volker Braun +# 2017 Frรฉdรฉric Chapoton # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -19,7 +22,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.misc.misc import walltime, cputime +from sage.misc.timing import walltime, cputime def count_noun(number, noun, plural=None, pad_number=False, pad_noun=False): diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py index ccf1de6115d..e672314a9c0 100644 --- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py @@ -43,8 +43,7 @@ class initialization directly. from sage.misc.cachefunc import cached_method from sage.misc.classcall_metaclass import typecall from sage.rings.integer import Integer -from sage.rings.finite_rings.finite_field_constructor import is_PrimeFiniteField -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.fraction_field import FractionField from sage.rings.fraction_field import is_FractionField from sage.rings.quotient_ring import is_QuotientRing @@ -251,7 +250,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None): raise ValueError('domain and codomain do not agree') if R not in Fields(): return typecall(cls, polys, domain) - if is_FiniteField(R): + if isinstance(R, FiniteField): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain) elif isinstance(morphism_or_polys,(list, tuple)): @@ -299,7 +298,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None): if R not in Fields(): return typecall(cls, polys, domain) - if is_FiniteField(R): + if isinstance(R, FiniteField): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain) @@ -319,7 +318,8 @@ def __init__(self, polys_or_rat_fncts, domain): """ L = polys_or_rat_fncts # Next attribute needed for _fast_eval and _fastpolys - self._is_prime_finite_field = is_PrimeFiniteField(L[0].base_ring()) + R = L[0].base_ring() + self._is_prime_finite_field = isinstance(R, FiniteField) and R.is_prime_field() DynamicalSystem.__init__(self, L, domain) def __copy__(self): diff --git a/src/sage/dynamics/arithmetic_dynamics/all.py b/src/sage/dynamics/arithmetic_dynamics/all.py index d37ef38b437..f536734b5d9 100644 --- a/src/sage/dynamics/arithmetic_dynamics/all.py +++ b/src/sage/dynamics/arithmetic_dynamics/all.py @@ -5,5 +5,8 @@ from .projective_ds import DynamicalSystem_projective from .product_projective_ds import DynamicalSystem_product_projective from .berkovich_ds import DynamicalSystem_Berkovich +from .dynamical_semigroup import DynamicalSemigroup +from .dynamical_semigroup import DynamicalSemigroup_affine +from .dynamical_semigroup import DynamicalSemigroup_projective lazy_import('sage.dynamics.arithmetic_dynamics.wehlerK3', 'WehlerK3Surface') lazy_import('sage.dynamics.arithmetic_dynamics.wehlerK3', 'random_WehlerK3Surface') diff --git a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py index 96cc0d12d39..de956719603 100644 --- a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py @@ -926,7 +926,7 @@ def __call__(self, x, type_3_pole_check=True): variable = nth_derivative.parent().gens()[0] a = x.center()[0] Taylor_expansion = [] - from sage.functions.other import factorial + from sage.arith.misc import factorial for i in range(f.degree() + 1): Taylor_expansion.append(nth_derivative(a) * 1/factorial(i)) nth_derivative = nth_derivative.derivative(variable) diff --git a/src/sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py b/src/sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py new file mode 100644 index 00000000000..5b324ddbd9a --- /dev/null +++ b/src/sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py @@ -0,0 +1,1541 @@ +r""" +Dynamical semigroups + +A dynamical semigroup is a finitely generated subsemigroup of +the endomorphism ring of a subscheme of projective or affine space. + +AUTHORS: + + - Dang Phan (August 6th, 2023): initial implementation +""" + +# **************************************************************************** +# Dang Phan <dang8phan@gmail.com> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from collections.abc import Collection +from sage.categories.fields import Fields +from sage.categories.number_fields import NumberFields +from sage.categories.semigroups import Semigroups +from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine +from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem +from sage.dynamics.arithmetic_dynamics.projective_ds import DynamicalSystem_projective +from sage.misc.classcall_metaclass import typecall +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.rings.finite_rings.finite_field_base import FiniteField +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.structure.parent import Parent + + +class DynamicalSemigroup(Parent, metaclass=InheritComparisonClasscallMetaclass): + r""" + A dynamical semigroup defined by a multiple dynamical systems on projective or affine space. + + INPUT: + + - ``ds_data`` -- list or tuple of dynamical systems or objects that define dynamical systems + + OUTPUT: + + :class:`DynamicalSemigroup_affine` if ``ds_data`` only contains dynamical systems + over affine space; and :class:`DynamicalSemigroup_projective` otherwise. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: DynamicalSemigroup(([x, y], [x^2, y^2])) + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([x, y], P) + sage: g = DynamicalSystem([x^2, y^2], P) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f = DynamicalSystem_affine(x, A) + sage: DynamicalSemigroup(f) + Dynamical semigroup over Affine Space of dimension 1 over Rational Field defined by 1 dynamical system: + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (x) + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f = DynamicalSystem(x, A) + sage: g = DynamicalSystem(x^2, A) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Affine Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (x) + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (x^2) + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: X = P.subscheme(x - y) + sage: f = DynamicalSystem_projective([x, y], X) + sage: g = DynamicalSystem_projective([x^2, y^2], X) + sage: DynamicalSemigroup_projective([f, g]) + Dynamical semigroup over Closed subscheme of Projective Space of dimension 1 over Rational Field defined by: + x - y defined by 2 dynamical systems: + Dynamical System of Closed subscheme of Projective Space of dimension 1 over Rational Field defined by: + x - y + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Closed subscheme of Projective Space of dimension 1 over Rational Field defined by: + x - y + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + + If a dynamical semigroup is built from dynamical systems with different base rings, all systems will be coerced + to the largest base ring:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: Q.<z,w> = ProjectiveSpace(RR, 1) + sage: f = DynamicalSystem([x, y], P) + sage: g = DynamicalSystem([z^2, w^2], Q) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Projective Space of dimension 1 over Real Field with 53 bits of precision defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Real Field with 53 bits of precision + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Projective Space of dimension 1 over Real Field with 53 bits of precision + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: B.<y> = AffineSpace(RR, 1) + sage: f = DynamicalSystem(x, A) + sage: g = DynamicalSystem(y^2, B) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Affine Space of dimension 1 over Real Field with 53 bits of precision defined by 2 dynamical systems: + Dynamical System of Affine Space of dimension 1 over Real Field with 53 bits of precision + Defn: Defined on coordinates by sending (x) to + (x) + Dynamical System of Affine Space of dimension 1 over Real Field with 53 bits of precision + Defn: Defined on coordinates by sending (x) to + (x^2) + + If a dynamical semigroup is built from dynamical systems over number fields, a composite number field is created + and all systems will be coerced to it. This composite number field contains all of the initial number fields:: + + sage: R.<r> = QQ[] + sage: K.<k> = NumberField(r^2 - 2) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: Q.<x,y> = ProjectiveSpace(K, 1) + sage: f = DynamicalSystem([x, y], P) + sage: g = DynamicalSystem([z^2, w^2], Q) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Projective Space of dimension 1 over Number Field in k with defining polynomial r^2 - 2 defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Number Field in k with defining polynomial r^2 - 2 + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Projective Space of dimension 1 over Number Field in k with defining polynomial r^2 - 2 + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + + :: + + sage: R.<r> = QQ[] + sage: K.<k> = NumberField(r^2 - 2) + sage: L.<l> = NumberField(r^2 - 3) + sage: P.<x,y> = ProjectiveSpace(K, 1) + sage: Q.<z,w> = ProjectiveSpace(L, 1) + sage: f = DynamicalSystem([x, y], P) + sage: g = DynamicalSystem([z^2, w^2], Q) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Projective Space of dimension 1 over Number Field in kl with defining polynomial r^4 - 10*r^2 + 1 defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Number Field in kl with defining polynomial r^4 - 10*r^2 + 1 + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Projective Space of dimension 1 over Number Field in kl with defining polynomial r^4 - 10*r^2 + 1 + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + + :: + + sage: R.<r> = QQ[] + sage: K.<k> = NumberField(r^2 - 2) + sage: L.<l> = NumberField(r^2 - 3) + sage: P.<x> = AffineSpace(K, 1) + sage: Q.<y> = AffineSpace(L, 1) + sage: f = DynamicalSystem(x, P) + sage: g = DynamicalSystem(y^2, Q) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Affine Space of dimension 1 over Number Field in kl with defining polynomial r^4 - 10*r^2 + 1 defined by 2 dynamical systems: + Dynamical System of Affine Space of dimension 1 over Number Field in kl with defining polynomial r^4 - 10*r^2 + 1 + Defn: Defined on coordinates by sending (x) to + (x) + Dynamical System of Affine Space of dimension 1 over Number Field in kl with defining polynomial r^4 - 10*r^2 + 1 + Defn: Defined on coordinates by sending (x) to + (x^2) + + A dynamical semigroup may contain dynamical systems over function fields:: + + sage: R.<r> = QQ[] + sage: P.<x,y> = ProjectiveSpace(R, 1) + sage: f = DynamicalSystem([r * x, y], P) + sage: g = DynamicalSystem([x, r * y], P) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Projective Space of dimension 1 over Univariate Polynomial Ring in r over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Univariate Polynomial Ring in r over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (r*x : y) + Dynamical System of Projective Space of dimension 1 over Univariate Polynomial Ring in r over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x : r*y) + + :: + + sage: R.<r> = QQ[] + sage: P.<x,y> = ProjectiveSpace(R, 1) + sage: f = DynamicalSystem([r * x, y], P) + sage: g = DynamicalSystem([x, y], P) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Projective Space of dimension 1 over Univariate Polynomial Ring in r over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Univariate Polynomial Ring in r over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (r*x : y) + Dynamical System of Projective Space of dimension 1 over Univariate Polynomial Ring in r over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x : y) + + :: + + sage: R.<r,s> = QQ[] + sage: P.<x,y> = ProjectiveSpace(R, 1) + sage: f = DynamicalSystem([r * x, y], P) + sage: g = DynamicalSystem([s * x, y], P) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Projective Space of dimension 1 over Multivariate Polynomial Ring in r, s over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Multivariate Polynomial Ring in r, s over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (r*x : y) + Dynamical System of Projective Space of dimension 1 over Multivariate Polynomial Ring in r, s over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (s*x : y) + + :: + + sage: R.<r,s> = QQ[] + sage: P.<x,y> = ProjectiveSpace(R, 1) + sage: f = DynamicalSystem([r * x, s * y], P) + sage: g = DynamicalSystem([s * x, r * y], P) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Projective Space of dimension 1 over Multivariate Polynomial Ring in r, s over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Multivariate Polynomial Ring in r, s over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (r*x : s*y) + Dynamical System of Projective Space of dimension 1 over Multivariate Polynomial Ring in r, s over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (s*x : r*y) + + A dynamical semigroup may contain dynamical systems over finite fields:: + + sage: F = FiniteField(5) + sage: P.<x,y> = ProjectiveSpace(F, 1) + sage: DynamicalSemigroup(([x, y], [x^2, y^2])) + Dynamical semigroup over Projective Space of dimension 1 over Finite Field of size 5 defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Finite Field of size 5 + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Projective Space of dimension 1 over Finite Field of size 5 + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + + If a dynamical semigroup is built from dynamical systems over both projective and affine spaces, all systems + will be homogenized to dynamical systems over projective space:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: A.<z> = AffineSpace(QQ, 1) + sage: f = DynamicalSystem([x, y], P) + sage: g = DynamicalSystem(z^2, A) + sage: DynamicalSemigroup((f, g)) + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + + TESTS:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: DynamicalSemigroup(1) + Traceback (most recent call last): + ... + TypeError: 1 does not define a 'DynamicalSemigroup' object + + :: + + sage: R.<r> = QQ[] + sage: K.<k> = NumberField(r^2 - 2) + sage: P.<x,y> = ProjectiveSpace(RR, 1) + sage: Q.<z,w> = ProjectiveSpace(K, 1) + sage: f = DynamicalSystem([x, y], P) + sage: g = DynamicalSystem([z^2, w^2], Q) + sage: DynamicalSemigroup((f, g)) + Traceback (most recent call last): + ... + ValueError: given dynamical systems are not automorphic under global composition + + :: + + sage: F = FiniteField(5) + sage: P.<x,y> = ProjectiveSpace(F, 1) + sage: Q.<z,w> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([x, y], P) + sage: g = DynamicalSystem([z^2, w^2], Q) + sage: DynamicalSemigroup((f, g)) + Traceback (most recent call last): + ... + ValueError: given dynamical systems are not automorphic under global composition + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: Q.<u,v,w> = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem([x, y]) + sage: g = DynamicalSystem([u^2, v^2, w^2]) + sage: DynamicalSemigroup((f, g)) + Traceback (most recent call last): + ... + ValueError: domains of 'DynamicalSystem' objects must be of the same dimension + """ + + @staticmethod + def __classcall_private__(cls, ds_data): + if isinstance(ds_data, Collection): + all_affine_systems = all(isinstance(ds_datum, DynamicalSystem_affine) for ds_datum in ds_data) + if all_affine_systems: + return DynamicalSemigroup_affine(ds_data) + elif isinstance(ds_data, DynamicalSystem_affine): + return DynamicalSemigroup_affine(ds_data) + elif not isinstance(ds_data, DynamicalSystem): + raise TypeError(str(ds_data) + " does not define a 'DynamicalSemigroup' object") + return DynamicalSemigroup_projective(ds_data) + + def __init__(self, systems): + r""" + The Python constructor. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: DynamicalSemigroup(([x, y], [x^2, y^2])) + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + """ + + self._dynamical_systems = [] + for ds in systems: + if ds not in self._dynamical_systems: + self._dynamical_systems.append(ds) + Parent.__init__(self, category=Semigroups().FinitelyGeneratedAsMagma()) + + def __call__(self, input): + r""" + The result after evaluating this dynamical semigroup on a value. + + INPUT: + + - ``input`` -- one value that can be evaluated + with the generators of this dynamical semigroup. + + OUTPUT: A set of the resulting values after applying all of this dynamical semigroup's generators to ``input``. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: f(2) + {(2 : 1), (4 : 1)} + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: f([2, 1]) + {(2 : 1), (4 : 1)} + + TESTS:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: f(f(2)) + Traceback (most recent call last): + ... + TypeError: unable to convert {(4 : 1), (2 : 1)} to an element of Rational Field + """ + result = set() + for ds in self.defining_systems(): + result.add(ds(self.domain()(input))) + return result + + def base_ring(self): + r""" + The base ring of this dynamical semigroup. This is identical + to the base ring of all of its defining dynamical system. + + OUTPUT: A ring. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: f.base_ring() + Rational Field + """ + return self.defining_systems()[0].base_ring() + + def change_ring(self, new_ring): + r""" + Return a new :class:`DynamicalSemigroup` whose generators + are the initial dynamical systems coerced to ``new_ring``. + + INPUT: + + - ``new_ring`` -- a ring. + + OUTPUT: + + A :class:`DynamicalSemigroup` defined by this dynamical + semigroup's generators, but coerced to ``new_ring``. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: f.change_ring(RR) + Dynamical semigroup over Projective Space of dimension 1 over Real Field with 53 bits of precision defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Real Field with 53 bits of precision + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Projective Space of dimension 1 over Real Field with 53 bits of precision + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + """ + new_systems = [] + for ds in self.defining_systems(): + new_systems.append(ds.change_ring(new_ring)) + return DynamicalSemigroup_projective(new_systems) + + def domain(self): + r""" + Return the domain of the generators of this dynamical semigroup. + + OUTPUT: A subscheme of a projective space or affine space. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: f.domain() + Projective Space of dimension 1 over Rational Field + """ + return self.defining_systems()[0].domain() + + def codomain(self): + r""" + Return the codomain of the generators of this dynamical semigroup. + + OUTPUT: A subscheme of a projective space or affine space. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: f.codomain() + Projective Space of dimension 1 over Rational Field + """ + return self.defining_systems()[0].codomain() + + def defining_polynomials(self): + r""" + Return the set of polynomials that define the generators of this dynamical semigroup. + + OUTPUT: A set of polynomials. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: f.defining_polynomials() + {(x, y), (x^2, y^2)} + """ + result = set() + for ds in self.defining_systems(): + result.add(ds.defining_polynomials()) + return result + + def defining_systems(self): + r""" + Return the generators of this dynamical semigroup. + + OUTPUT: A tuple of dynamical systems. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: f.defining_systems() + (Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x : y), + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2)) + """ + return tuple(self._dynamical_systems) + + def nth_iterate(self, p, n): + r""" + Return a set of values that results from evaluating this dynamical semigroup + on the value ``p`` a total of ``n`` times. + + INPUT: + + - ``p`` -- a value on which dynamical systems can evaluate + - ``n`` -- a nonnegative integer + + OUTPUT: a set of values + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x^2, y^2],)) + sage: f.nth_iterate(2, 0) + {(2 : 1)} + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x^2, y^2],)) + sage: f.nth_iterate(2, 1) + {(4 : 1)} + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x^2, y^2],)) + sage: f.nth_iterate(2, 2) + {(16 : 1)} + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x + y, x - y], [x^2, y^2])) + sage: f.nth_iterate(2, 0) + {(2 : 1)} + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x + y, x - y], [x^2, y^2])) + sage: f.nth_iterate(2, 1) + {(3 : 1), (4 : 1)} + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x + y, x - y], [x^2, y^2])) + sage: f.nth_iterate(2, 2) + {(5/3 : 1), (2 : 1), (9 : 1), (16 : 1)} + + TESTS:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x + y, x - y], [x^2, y^2])) + sage: f.nth_iterate(2, 3.5) + Traceback (most recent call last): + ... + TypeError: Attempt to coerce non-integral RealNumber to Integer + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x + y, x - y], [x^2, y^2])) + sage: f.nth_iterate(2, -3) + Traceback (most recent call last): + ... + ValueError: -3 must be a nonnegative integer + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x + y, x - y], [x^2, y^2])) + sage: f.nth_iterate(3, 2) == (f * f)(3) + True + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x + y, x - y], [x^2, y^2])) + sage: one = QQ(1) + sage: f.nth_iterate(2, one) + {(3 : 1), (4 : 1)} + + """ + n = ZZ(n) + if n < 0: + raise ValueError(str(n) + " must be a nonnegative integer") + result = {self.domain()(p)} + for i in range(1, n + 1): + next_iteration = set() + for point in result: + next_iteration.update(self(point)) + result = next_iteration + return result + + def orbit(self, p, n): + r""" + If ``n`` is an integer, return `(p, f(p), f^2(p), \dots, f^n(p))`. If ``n`` is a list or tuple in interval + notation `[a, b]`, return `(f^a(p), \dots, f^b(p))`. + + INPUT: + + - `p` -- value on which this dynamical semigroup can be evaluated + - `n` -- a nonnegative integer or a list or tuple of length 2 describing an + interval of the number line containing entirely nonnegative integers + + OUTPUT: a tuple of sets of values on the domain of this dynamical semigroup. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: d = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: d.orbit(2, 0) + ({(2 : 1)},) + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: d = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: d.orbit(2, 1) + ({(2 : 1)}, {(2 : 1), (4 : 1)}) + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: d = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: d.orbit(2, 2) + ({(2 : 1)}, {(2 : 1), (4 : 1)}, {(2 : 1), (4 : 1), (16 : 1)}) + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: d = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: d.orbit(2, [1, 2]) + ({(2 : 1), (4 : 1)}, {(2 : 1), (4 : 1), (16 : 1)}) + + TESTS:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: d = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: one = QQ(1) + sage: d.orbit(2, one) + ({(2 : 1)}, {(2 : 1), (4 : 1)}) + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: d = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: d.orbit(2, -2) + Traceback (most recent call last): + ... + ValueError: -2 must be a nonnegative integer + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: d = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: d.orbit(2, x) + Traceback (most recent call last): + ... + TypeError: not a constant polynomial + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: d = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: d.orbit(2, [1, 2, 3]) + Traceback (most recent call last): + ... + ValueError: [1, 2, 3] must be an integer or list or tuple of two integers + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: d = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: d.orbit(2, [-2, 1]) + Traceback (most recent call last): + ... + ValueError: [-2, 1] must contain exactly two nonnegative integers + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: d = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: d.orbit(2, [2, 1]) + Traceback (most recent call last): + ... + ValueError: [2, 1] cannot be in descending order + """ + + if not isinstance(n, Collection): + n = ZZ(n) + if n < 0: + raise ValueError(str(n) + " must be a nonnegative integer") + return self.orbit(p, [0, n]) + + if not len(n) == 2: + raise ValueError(str(n) + " must be an integer or list or tuple of two integers") + if ZZ(n[0]) < 0 or ZZ(n[1]) < 0: + raise ValueError(str(n) + " must contain exactly two nonnegative integers") + if ZZ(n[0]) > ZZ(n[1]): + raise ValueError(str(n) + " cannot be in descending order") + + result = [] + current_iterate = self.nth_iterate(p, n[0]) + result.append(current_iterate) + for i in range(n[0] + 1, n[1] + 1): + next_iterate = set() + for value in current_iterate: + next_iterate.update(self(value)) + result.append(next_iterate) + current_iterate = next_iterate + return tuple(result) + + def specialization(self, assignments): + r""" + Returns the specialization of the generators of this dynamical semigroup. + + INPUT: + + - `assignments` -- argument for specialization of the generators of this dynamical semigroup. + + OUTPUT: a dynamical semigroup with the specialization of the generators of this dynamical semigroup. + + EXAMPLES:: + + sage: R.<r> = QQ[] + sage: P.<x,y> = ProjectiveSpace(R, 1) + sage: f = DynamicalSystem([r * x, y], P) + sage: g = DynamicalSystem([x, r * y], P) + sage: d = DynamicalSemigroup((f, g)) + sage: d.specialization({r:2}) + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (2*x : y) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x : 2*y) + + :: + + sage: R.<r> = QQ[] + sage: P.<x,y> = ProjectiveSpace(R, 1) + sage: f = DynamicalSystem([r * x, y], P) + sage: g = DynamicalSystem([x, y], P) + sage: d = DynamicalSemigroup((f, g)) + sage: d.specialization({r:2}) + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (2*x : y) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x : y) + + :: + + sage: R.<r,s> = QQ[] + sage: P.<x,y> = ProjectiveSpace(R, 1) + sage: f = DynamicalSystem([r * x, y], P) + sage: g = DynamicalSystem([s * x, y], P) + sage: d = DynamicalSemigroup((f, g)) + sage: d.specialization({r:2, s:3}) + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (2*x : y) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (3*x : y) + + :: + + sage: R.<r,s> = QQ[] + sage: P.<x,y> = ProjectiveSpace(R, 1) + sage: f = DynamicalSystem([r * x, s * y], P) + sage: g = DynamicalSystem([s * x, r * y], P) + sage: d = DynamicalSemigroup((f, g)) + sage: d.specialization({s:3}) + Dynamical semigroup over Projective Space of dimension 1 over Univariate Polynomial Ring in r over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Univariate Polynomial Ring in r over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (r*x : 3*y) + Dynamical System of Projective Space of dimension 1 over Univariate Polynomial Ring in r over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (3*x : r*y) + """ + specialized_systems = [] + for ds in self.defining_systems(): + specialized_systems.append(ds.specialization(assignments)) + return DynamicalSemigroup(specialized_systems) + + def __mul__(self, other_dynamical_semigroup): + r""" + Return a new :class:`DynamicalSemigroup` that is the result of multiplying + this dynamical semigroup with another dynamical semigroup of the same type + using the * operator. + + Let `f` be a dynamical semigroup with generators `\{ f_1, f_2, \dots, f_m \}` + and `g` be a dynamical semigroup with generators `\{ g_1, g_2, \dots, g_n \}`. + The product `f * g` has generators + `\{ f_i(g_j) : 1 \leq i \leq m, 1 \leq j \leq n \}`. + + INPUT: + + - ``other_dynamical_semigroup`` -- a dynamical semigroup + + OUTPUT: :class:`DynamicalSemigroup` + + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f1 = DynamicalSystem([x^10, y^10], P) + sage: f = DynamicalSemigroup(f1) + sage: f*f + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 1 dynamical system: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^100 : y^100) + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f1 = DynamicalSystem_affine(x^10, A) + sage: f = DynamicalSemigroup(f1) + sage: f*f + Dynamical semigroup over Affine Space of dimension 1 over Rational Field defined by 1 dynamical system: + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (x^100) + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f1 = DynamicalSystem([x^2 + x * y, y^2 + x * y], P) + sage: g1 = DynamicalSystem([x^3 + x^2 * y, y^3 + x * y^2], P) + sage: f = DynamicalSemigroup(f1) + sage: g = DynamicalSemigroup(g1) + sage: f*g + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 1 dynamical system: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^6 + 2*x^5*y + 2*x^4*y^2 + 2*x^3*y^3 + x^2*y^4 : x^4*y^2 + 2*x^3*y^3 + 2*x^2*y^4 + 2*x*y^5 + y^6) + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f1 = DynamicalSystem([x^2 + x * y, y^2 + x * y], P) + sage: f2 = DynamicalSystem([x^2 - x * y, y^2 - x * y], P) + sage: g1 = DynamicalSystem([x^3 + x^2 * y, y^3 + x * y^2], P) + sage: g2 = DynamicalSystem([x^3 - x^2 * y, y^3 - x * y^2], P) + sage: f = DynamicalSemigroup((f1, f2)) + sage: g = DynamicalSemigroup((g1, g2)) + sage: f*g + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^6 + 2*x^5*y + 2*x^4*y^2 + 2*x^3*y^3 + x^2*y^4 : x^4*y^2 + 2*x^3*y^3 + 2*x^2*y^4 + 2*x*y^5 + y^6) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^6 - 2*x^5*y + 2*x^3*y^3 - x^2*y^4 : -x^4*y^2 + 2*x^3*y^3 - 2*x*y^5 + y^6) + + TESTS:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f1 = DynamicalSystem([x^2 + x * y, y^2 - x * y], P) + sage: g1 = DynamicalSystem([x^3 - x^2 * y, y^3 + x * y^2], P) + sage: f = DynamicalSemigroup(f1) + sage: g = DynamicalSemigroup(g1) + sage: f*g == g*f + False + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f1 = DynamicalSystem([x^2 + x * y, y^2 + x * y], P) + sage: g1 = DynamicalSystem([x^3 + x^2 * y, y^3 + x * y^2], P) + sage: h1 = DynamicalSystem([x^4 + x^3 * y, y^4 + x * y^3], P) + sage: f = DynamicalSemigroup(f1) + sage: g = DynamicalSemigroup(g1) + sage: h = DynamicalSemigroup(h1) + sage: (f*g)*h == f*(g*h) + True + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f1 = DynamicalSystem([x, y], P) + sage: f = DynamicalSemigroup(f1) + sage: f*1 + Traceback (most recent call last): + ... + TypeError: can only multiply dynamical semigroups with other dynamical semigroups of the same type + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: A.<z> = AffineSpace(QQ, 1) + sage: f1 = DynamicalSystem_projective([x, y], P) + sage: g1 = DynamicalSystem_affine(z, A) + sage: f = DynamicalSemigroup_projective(f1) + sage: g = DynamicalSemigroup_affine(g1) + sage: f*g + Traceback (most recent call last): + ... + TypeError: can only multiply dynamical semigroups with other dynamical semigroups of the same type + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: Q.<z,w> = ProjectiveSpace(RR, 1) + sage: f1 = DynamicalSystem([x, y], P) + sage: g1 = DynamicalSystem([z, w], Q) + sage: f = DynamicalSemigroup(f1) + sage: g = DynamicalSemigroup(g1) + sage: f*g + Traceback (most recent call last): + ... + ValueError: left dynamical semigroup's domain must equal right dynamical semigroup's codomain + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: Q.<z,w> = ProjectiveSpace(QQ, 1) + sage: f1 = DynamicalSystem([x, y], P) + sage: g1 = DynamicalSystem([z, w], Q) + sage: f = DynamicalSemigroup(f1) + sage: g = DynamicalSemigroup(g1) + sage: f*g + Traceback (most recent call last): + ... + ValueError: left dynamical semigroup's domain must equal right dynamical semigroup's codomain + """ + if type(self) is not type(other_dynamical_semigroup): + raise TypeError("can only multiply dynamical semigroups with other dynamical semigroups of the same type") + if self.domain() != other_dynamical_semigroup.codomain(): + raise ValueError("left dynamical semigroup's domain must equal right dynamical semigroup's codomain") + composite_systems = [] + for f in self.defining_systems(): + for g in other_dynamical_semigroup.defining_systems(): + composite_systems.append(DynamicalSystem(f * g)) + return DynamicalSemigroup(composite_systems) + + def __pow__(self, n): + r""" + Return a new dynamical semigroup that is this dynamical semigroup with itself ``n`` times. + If ``n`` is zero, return a dynamical semigroup with the identity map. + + INPUT: + + - ``n`` -- a nonnegative integer + + OUTPUT: :class:`DynamicalSemigroup` + + EXAMPLES:: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f = DynamicalSystem(x^2, A) + sage: d = DynamicalSemigroup(f) + sage: d^2 + Dynamical semigroup over Affine Space of dimension 1 over Rational Field defined by 1 dynamical system: + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (x^4) + + :: + + sage: A.<x, y, z, w, t, u ,v> = AffineSpace(QQ, 7) + sage: f = DynamicalSystem([t + u, v - w, x + y, z^2, u * t, v^2 - w^2, x * y * z], A) + sage: d = DynamicalSemigroup(f) + sage: d^0 + Dynamical semigroup over Affine Space of dimension 7 over Rational Field defined by 1 dynamical system: + Dynamical System of Affine Space of dimension 7 over Rational Field + Defn: Defined on coordinates by sending (x, y, z, w, t, u, v) to + (x, y, z, w, t, u, v) + + TESTS:: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f1 = DynamicalSystem(x^2 + 1, A) + sage: f2 = DynamicalSystem(x^3 - 1, A) + sage: d = DynamicalSemigroup(f) + sage: d*d == d^2 + True + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f1 = DynamicalSystem(x^2 + 1, A) + sage: f2 = DynamicalSystem(x^3 - 1, A) + sage: d = DynamicalSemigroup(f) + sage: d^3 * d^2 == d^(3 + 2) + True + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f1 = DynamicalSystem(x^2 + 1, A) + sage: f2 = DynamicalSystem(x^3 - 1, A) + sage: d = DynamicalSemigroup(f) + sage: (d^3)^2 == d^(3 * 2) + True + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f1 = DynamicalSystem(x^2 + 1, A) + sage: f2 = DynamicalSystem(x^3 - 1, A) + sage: g1 = DynamicalSystem(x^3 + x - 1, A) + sage: g2 = DynamicalSystem(x^2 - x + 1, A) + sage: f = DynamicalSemigroup((f1, f2)) + sage: g = DynamicalSemigroup((g1, g2)) + sage: (f * g) ^ 2 == f^2 * g^2 + False + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f1 = DynamicalSystem(x^2 + 1, A) + sage: f2 = DynamicalSystem(x^3 - 1, A) + sage: g1 = DynamicalSystem(x^3 + x - 1, A) + sage: g2 = DynamicalSystem(x^2 - x + 1, A) + sage: f = DynamicalSemigroup((f1, f2)) + sage: g = DynamicalSemigroup((g1, g2)) + sage: f * g^0 == f + True + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f1 = DynamicalSystem(x^2 + 1, A) + sage: f2 = DynamicalSystem(x^3 - 1, A) + sage: g1 = DynamicalSystem(x^3 + x - 1, A) + sage: g2 = DynamicalSystem(x^2 - x + 1, A) + sage: f = DynamicalSemigroup((f1, f2)) + sage: g = DynamicalSemigroup((g1, g2)) + sage: g * f^0 == g + True + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f1 = DynamicalSystem(x^2 + 1, A) + sage: f2 = DynamicalSystem(x^3 - 1, A) + sage: d = DynamicalSemigroup((f1, f2)) + sage: d^1.5 + Traceback (most recent call last): + ... + TypeError: Attempt to coerce non-integral RealNumber to Integer + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f1 = DynamicalSystem(x^2 + 1, A) + sage: f2 = DynamicalSystem(x^3 - 1, A) + sage: d = DynamicalSemigroup((f1, f2)) + sage: d^(-1) + Traceback (most recent call last): + ... + ValueError: -1 must be a nonnegative integer + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f = DynamicalSystem(x^2, A) + sage: d = DynamicalSemigroup(f) + sage: two = RR(2) + sage: d^two + Dynamical semigroup over Affine Space of dimension 1 over Rational Field defined by 1 dynamical system: + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (x^4) + """ + n = ZZ(n) + if n < 0: + raise ValueError(str(n) + " must be a nonnegative integer") + if n == 0: + return DynamicalSemigroup(DynamicalSystem(self.defining_systems()[0] ** 0)) + result = self + for i in range(n - 1): + result = result * self + return result + + def _repr_(self): + r""" + Return the :class:`String` representation of this dynamical semigroup. + + OUTPUT: A :class:`String` displaying information about this dynamical semigroup. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: DynamicalSemigroup(([x, y], [x^2, y^2])) + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + """ + header = "Dynamical semigroup over %s defined by %d dynamical system" + if (len(self.defining_systems()) > 1): + header += "s" + header += ":" + header = header % (str(self.domain()), len(self.defining_systems())) + systems = [] + for ds in self.defining_systems(): + systems.append(str(ds)) + systems = '\n'.join(systems) + return header + "\n" + systems + + def __eq__(self, other): + r""" + Return whether two dynamical semigroups are equal. + + OUTPUT: + + A boolean that is True if and only if the generators of the two + dynamical semigroups are equal as sets and no generator is of degree 1. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x^2, y^2], [x^3, y^3])) + sage: g = DynamicalSemigroup(([x^2, y^2], [x^3, y^3])) + sage: f == g + True + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x^2, y^2], [x^2, y^2])) + sage: g = DynamicalSemigroup(([x^2, y^2], [x^2, y^2], [x^2, y^2])) + sage: f == g + True + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x^3, y^3], [x^2, y^2])) + sage: g = DynamicalSemigroup(([x^2, y^2], [x^3, y^3])) + sage: f == g + True + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x^3, y^3], [x^2, y^2])) + sage: g = DynamicalSemigroup(([x^2, y^2], [y^3, x^3])) + sage: f == g + False + + TESTS:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: f == 1 + False + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSemigroup(([x, y], [x^2, y^2])) + sage: g = DynamicalSemigroup(([x^2, y^2], [x^3, y^3])) + sage: f == g + Traceback (most recent call last): + ... + NotImplementedError: cannot compare dynamical semigroups with at least one generator of degree 1 + """ + if isinstance(other, DynamicalSemigroup): + if any(ds.degree() == 1 for ds in self.defining_systems()) or \ + any(ds.degree() == 1 for ds in other.defining_systems()): + raise NotImplementedError("cannot compare dynamical semigroups with at least one generator of degree 1") + return all(ds in other.defining_systems() for ds in self.defining_systems()) and \ + all(ds in self.defining_systems() for ds in other.defining_systems()) + return False + + +class DynamicalSemigroup_projective(DynamicalSemigroup): + r""" + A dynamical semigroup defined by a multiple dynamical systems on projective space. + + INPUT: + + - ``ds_data`` -- list or tuple of dynamical systems or objects that define dynamical systems + over projective space. + + OUTPUT: :class:`DynamicalSemigroup_projective` + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: DynamicalSemigroup_projective(([x, y], [x^2, y^2])) + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x : y) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^2 : y^2) + """ + + @staticmethod + def __classcall_private__(cls, ds_data): + systems = [] + + if isinstance(ds_data, Collection): + for ds_datum in ds_data: + if isinstance(ds_datum, DynamicalSystem_projective): + systems.append(ds_datum) + elif isinstance(ds_datum, DynamicalSystem_affine): + dimension = ds_datum.domain().dimension() + systems.append(ds_datum.homogenize(dimension)) + else: + try: + systems.append(DynamicalSystem_projective(ds_datum)) + except ValueError: + raise ValueError(str(ds_datum) + " does not define a 'DynamicalSystem_projective' object") + else: + if isinstance(ds_data, DynamicalSystem_projective): + systems.append(ds_data) + else: + try: + systems.append(DynamicalSystem_projective(ds_data)) + except ValueError: + raise ValueError(str(ds_data) + " does not define a 'DynamicalSystem_projective' object") + + systems = _standardize_domains_of_(systems) + if systems[0].base_ring() not in Fields(): + return typecall(cls, systems) + if isinstance(systems[0].base_ring(), FiniteField): + return DynamicalSemigroup_projective_finite_field(systems) + return DynamicalSemigroup_projective_field(systems) + + def dehomogenize(self, n): + r""" + Return a new :class:`DynamicalSemigroup_projective` with the dehomogenization at ``n`` of + the generators of this dynamical semigroup. + + INPUT: + + - ``n`` -- a tuple of nonnegative integers. If ``n`` is an integer, + then the two values of the tuple are assumed to be the same + + OUTPUT: :class:`DynamicalSemigroup_affine` + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([x, y], P) + sage: g = DynamicalSystem([x^2, y^2], P) + sage: d = DynamicalSemigroup((f, g)) + sage: d.dehomogenize(0) + Dynamical semigroup over Affine Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (y) to + (y) + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (y) to + (y^2) + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([x, y], P) + sage: g = DynamicalSystem([x^2, y^2], P) + sage: d = DynamicalSemigroup((f, g)) + sage: d.dehomogenize(1) + Dynamical semigroup over Affine Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (x) + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (x^2) + + TESTS:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([x, y], P) + sage: g = DynamicalSystem([x^2, y^2], P) + sage: d = DynamicalSemigroup((f, g)) + sage: d.dehomogenize((1, 0)) + Traceback (most recent call last): + ... + ValueError: Scheme morphism: + From: Affine Space of dimension 1 over Rational Field + To: Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (1/x) is not a `DynamicalSystem_affine` object + """ + new_systems = [] + for ds in self.defining_systems(): + new_system = ds.dehomogenize(n) + if not isinstance(new_system, DynamicalSystem_affine): + raise ValueError(str(new_system) + " is not a `DynamicalSystem_affine` object") + new_systems.append(new_system) + return DynamicalSemigroup_affine(new_systems) + + +class DynamicalSemigroup_projective_field(DynamicalSemigroup_projective): + pass + + +class DynamicalSemigroup_projective_finite_field(DynamicalSemigroup_projective_field): + pass + + +class DynamicalSemigroup_affine(DynamicalSemigroup): + r""" + A dynamical semigroup defined by multiple dynamical systems on affine space. + + INPUT: + + - ``ds_data`` -- list or tuple of dynamical systems or objects that define dynamical systems + over affine space. + + OUTPUT: :class:`DynamicalSemigroup_affine` + + EXAMPLES:: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f = DynamicalSystem(x, A) + sage: g = DynamicalSystem(x^2, A) + sage: DynamicalSemigroup_affine((f, g)) + Dynamical semigroup over Affine Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (x) + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (x^2) + """ + + @staticmethod + def __classcall_private__(cls, ds_data): + systems = [] + + if isinstance(ds_data, Collection): + for ds_datum in ds_data: + if isinstance(ds_datum, DynamicalSystem_affine): + systems.append(ds_datum) + else: + try: + systems.append(DynamicalSystem_affine(ds_datum)) + except ValueError: + raise ValueError(str(ds_datum) + " does not define a 'DynamicalSystem_affine' object") + else: + if isinstance(ds_data, DynamicalSystem_affine): + systems.append(ds_data) + else: + try: + systems.append(DynamicalSystem_affine(ds_data)) + except ValueError: + raise ValueError(str(ds_data) + " does not define a 'DynamicalSystem_affine' object") + + systems = _standardize_domains_of_(systems) + if systems[0].base_ring() not in Fields(): + return typecall(cls, systems) + if isinstance(systems[0].base_ring(), FiniteField): + return DynamicalSemigroup_affine_finite_field(systems) + return DynamicalSemigroup_affine_field(systems) + + def homogenize(self, n): + r""" + Return a new :class:`DynamicalSemigroup_projective` with the homogenization at ``n`` of + the generators of this dynamical semigroup. + + INPUT: + + - ``n`` -- a tuple of nonnegative integers. If ``n`` is an integer, + then the two values of the tuple are assumed to be the same + + OUTPUT: :class:`DynamicalSemigroup_projective` + + EXAMPLES:: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f = DynamicalSystem(x + 1, A) + sage: g = DynamicalSystem(x^2, A) + sage: d = DynamicalSemigroup((f, g)) + sage: d.homogenize(1) + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x0 : x1) to + (x0 + x1 : x1) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x0 : x1) to + (x0^2 : x1^2) + + :: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: f = DynamicalSystem(x + 1, A) + sage: g = DynamicalSystem(x^2, A) + sage: d = DynamicalSemigroup((f, g)) + sage: d.homogenize((1, 0)) + Dynamical semigroup over Projective Space of dimension 1 over Rational Field defined by 2 dynamical systems: + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x0 : x1) to + (x1 : x0 + x1) + Dynamical System of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x0 : x1) to + (x1^2 : x0^2) + """ + new_systems = [] + for ds in self.defining_systems(): + new_systems.append(ds.homogenize(n)) + return DynamicalSemigroup_projective(new_systems) + + +class DynamicalSemigroup_affine_field(DynamicalSemigroup_affine): + pass + + +class DynamicalSemigroup_affine_finite_field(DynamicalSemigroup_affine_field): + pass + + +def _standardize_domains_of_(systems): + r""" + Coerces dynamical systems to the same domain and have the same generators. + + INPUT: + + - ``systems`` -- list of dynamical systems + + OUTPUT: list of dynamical systems from ``systems`` coerced to the same domain with the same generators + + EXAMPLES:: + + sage: A.<x> = AffineSpace(QQ, 1) + sage: B.<y> = AffineSpace(RR, 1) + sage: f = DynamicalSystem(x, A) + sage: g = DynamicalSystem(x^2, B) + sage: sage.dynamics.arithmetic_dynamics.dynamical_semigroup._standardize_domains_of_([f, g]) + [Dynamical System of Affine Space of dimension 1 over Real Field with 53 bits of precision + Defn: Defined on coordinates by sending (x) to + (x), + Dynamical System of Affine Space of dimension 1 over Real Field with 53 bits of precision + Defn: Defined on coordinates by sending (x) to + (x^2)] + """ + identical_domains = True + for ds in systems: + if ds.domain() != systems[0].domain(): + identical_domains = False + break + + over_number_fields = True + all_over_QQ = True + for ds in systems: + if ds.base_ring() not in NumberFields(): + over_number_fields = False + if ds.base_ring() is not QQ: + all_over_QQ = False + + biggest_ring = None + + if over_number_fields and not all_over_QQ: + number_fields = [] + for ds in systems: + number_fields.append(ds.base_ring()) + + minimal_composite_field = None + for field in number_fields: + if field is not QQ: + if minimal_composite_field is None: + minimal_composite_field = field + else: + minimal_composite_field = minimal_composite_field.composite_fields(field)[0] + + biggest_ring = minimal_composite_field + else: + for ds in systems: + if biggest_ring is None: + biggest_ring = ds.base_ring() + elif ds.base_ring().has_coerce_map_from(biggest_ring): + biggest_ring = ds.base_ring() + elif biggest_ring.has_coerce_map_from(ds.base_ring()): + pass + else: + raise ValueError("given dynamical systems are not automorphic \ + under global composition") + + for i in range(len(systems)): + if systems[i].base_ring() != biggest_ring: + systems[i] = systems[i].change_ring(biggest_ring) + + domain = systems[0].domain() + + identical_domains = all(ds.domain() == systems[0].domain() for ds in systems) + if not identical_domains: + for ds in systems: + if ds.domain().dimension() != systems[0].domain().dimension(): + raise ValueError("domains of 'DynamicalSystem' objects must be of the same dimension") + + gens = systems[0].domain().ambient_space().gens() + for i in range(len(systems)): + if systems[i].domain().coordinate_ring() != systems[0].domain().coordinate_ring(): + sub_dict = {} + old_gens = systems[i].domain().ambient_space().gens() + for j in range(len(old_gens)): + sub_dict[old_gens[j]] = gens[j] + new_polys = [] + for poly in systems[i].defining_polynomials(): + new_polys.append(poly.subs(sub_dict)) + systems[i] = DynamicalSystem(new_polys, domain) + + return systems diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index b1e5240e90f..e8e5ddba1c4 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -22,22 +22,23 @@ from copy import copy, deepcopy from itertools import permutations, combinations, product +from sage.arith.functions import lcm +from sage.arith.misc import CRT, divisors, gcd, is_square +from sage.combinat.permutation import Arrangements from sage.combinat.subset import Subsets -from sage.misc.functional import sqrt from sage.matrix.constructor import matrix -from sage.structure.element import is_Matrix +from sage.misc.functional import sqrt from sage.misc.misc_c import prod +from sage.parallel.use_fork import p_iter_fork from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.integer_ring import ZZ from sage.rings.number_field.number_field import NumberField -from sage.arith.all import gcd, lcm, CRT, is_square, divisors from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ from sage.sets.primes import Primes from sage.sets.set import Set -from sage.combinat.permutation import Arrangements -from sage.parallel.use_fork import p_iter_fork +from sage.structure.element import is_Matrix def automorphism_group_QQ_fixedpoints(rational_function, return_functions=False, iso_type=False): @@ -125,7 +126,7 @@ def automorphism_group_QQ_fixedpoints(rational_function, return_functions=False, else: elements = [matrix(F, 2, [1,0,0,1])] - rational_roots = h.roots(multiplicities = False) + rational_roots = h.roots(multiplicities=False) min_poly = 1 @@ -742,7 +743,7 @@ def automorphism_group_QQ_CRT(rational_function, prime_lower_bound=4, return_fun # compute automorphisms mod p phi_p = f.change_ring(GF(p))/g.change_ring(GF(p)) sorted_automorphisms = automorphism_group_FF(phi_p) - sorted_automorphisms.sort(key = PGL_order) + sorted_automorphisms.sort(key=PGL_order) orders = [PGL_order(A) for A in sorted_automorphisms] automorphisms.append(sorted_automorphisms) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py index 65c6671ce59..735e0800a6f 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py @@ -34,7 +34,7 @@ from sage.rings.rational_field import QQ from sage.schemes.affine.affine_space import AffineSpace from sage.symbolic.constants import e -from sage.arith.all import gcd +from sage.arith.misc import gcd from copy import copy def bCheck(c, v, p, b): diff --git a/src/sage/dynamics/arithmetic_dynamics/generic_ds.py b/src/sage/dynamics/arithmetic_dynamics/generic_ds.py index 3e227942256..25d8645ae86 100644 --- a/src/sage/dynamics/arithmetic_dynamics/generic_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/generic_ds.py @@ -33,7 +33,7 @@ class initialization directly. from sage.schemes.affine.affine_space import is_AffineSpace from sage.schemes.affine.affine_subscheme import AlgebraicScheme_subscheme_affine from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.qqbar import AlgebraicField_common from sage.schemes.berkovich.berkovich_space import is_Berkovich_Cp from sage.rings.rational_field import QQ @@ -416,7 +416,7 @@ def field_of_definition_critical(self, return_embedding=False, simplify_all=Fals CR = CR.ring() x = CR.gen(0) poly = (g*CR(f).derivative(x) - f*CR(g).derivative(x)).univariate_polynomial() - if is_FiniteField(ds.base_ring()): + if isinstance(ds.base_ring(), FiniteField): return poly.splitting_field(names, map=return_embedding) else: K = poly.splitting_field(names, map=return_embedding, simplify_all=simplify_all) @@ -536,7 +536,7 @@ def field_of_definition_periodic(self, n, formal=False, return_embedding=False, fn = ds.nth_iterate_map(n) f,g = fn[0].numerator(), fn[0].denominator() poly = (f - g*x).univariate_polynomial() - if is_FiniteField(ds.base_ring()): + if isinstance(ds.base_ring(), FiniteField): return poly.splitting_field(names, map=return_embedding) else: K = poly.splitting_field(names, map=return_embedding, simplify_all=simplify_all) @@ -630,7 +630,7 @@ def field_of_definition_preimage(self, point, n, return_embedding=False, simplif #want the polynomial ring not the fraction field CR = CR.ring() poly = (f*point[1] - g*CR(point[0])).univariate_polynomial() - if is_FiniteField(ds.base_ring()): + if isinstance(ds.base_ring(), FiniteField): return poly.splitting_field(names, map=return_embedding) else: K = poly.splitting_field(names, map=return_embedding, simplify_all=simplify_all) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 385ccad1a91..6520177f4a7 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -52,68 +52,71 @@ class initialization directly. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.misc import is_prime +from copy import copy +from itertools import count, product + +import sage.rings.abc + +from sage.arith.functions import lcm +from sage.arith.misc import binomial, gcd, is_prime, moebius, next_prime, primes from sage.calculus.functions import jacobian from sage.categories.fields import Fields +from sage.categories.finite_fields import FiniteFields from sage.categories.function_fields import FunctionFields -from sage.categories.number_fields import NumberFields from sage.categories.homset import End +from sage.categories.number_fields import NumberFields +from sage.dynamics.arithmetic_dynamics.endPN_automorphism_group import ( + automorphism_group_QQ_CRT, + automorphism_group_QQ_fixedpoints, + conjugating_set_helper, + conjugating_set_initializer, + is_conjugate_helper) +from sage.dynamics.arithmetic_dynamics.endPN_automorphism_group import automorphism_group_FF from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem -from sage.misc.functional import sqrt +from sage.dynamics.arithmetic_dynamics.projective_ds_helper import ( + _fast_possible_periods, + _all_periodic_points) from sage.functions.other import ceil from sage.libs.pari.all import PariError from sage.matrix.constructor import matrix, identity_matrix from sage.misc.cachefunc import cached_method from sage.misc.classcall_metaclass import typecall +from sage.misc.functional import sqrt from sage.misc.mrange import xmrange from sage.modules.free_module_element import vector -from sage.rings.integer import Integer -from sage.arith.all import gcd, lcm, next_prime, binomial, primes, moebius -from sage.categories.finite_fields import FiniteFields +from sage.parallel.ncpus import ncpus +from sage.parallel.use_fork import p_iter_fork from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic from sage.rings.complex_mpfr import ComplexField -from sage.rings.finite_rings.finite_field_constructor import (is_FiniteField, GF, - is_PrimeFiniteField) +from sage.rings.finite_rings.finite_field_base import FiniteField +from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.rings.fraction_field import (FractionField, is_FractionField, FractionField_1poly_field) from sage.rings.fraction_field_element import is_FractionFieldElement, FractionFieldElement from sage.rings.function_field.function_field import is_FunctionField +from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.polynomial.flatten import FlatteningMorphism, UnflatteningMorphism from sage.rings.morphism import RingHomomorphism_im_gens from sage.rings.number_field.number_field_ideal import NumberFieldFractionalIdeal -from sage.rings.padics.all import Qp +from sage.rings.padics.factory import Qp from sage.rings.polynomial.multi_polynomial_ring_base import is_MPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.qqbar import QQbar, number_field_elements_from_algebraics from sage.rings.quotient_ring import QuotientRing_generic from sage.rings.rational_field import QQ -import sage.rings.abc from sage.rings.real_mpfr import RealField from sage.schemes.generic.morphism import SchemeMorphism_polynomial -from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective +from sage.schemes.product_projective.space import is_ProductProjectiveSpaces from sage.schemes.projective.projective_morphism import ( SchemeMorphism_polynomial_projective_space, SchemeMorphism_polynomial_projective_space_field, SchemeMorphism_polynomial_projective_space_finite_field) -from sage.schemes.projective.projective_space import (ProjectiveSpace, - is_ProjectiveSpace) -from sage.schemes.product_projective.space import is_ProductProjectiveSpaces +from sage.schemes.projective.projective_space import ProjectiveSpace, is_ProjectiveSpace +from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective from sage.structure.element import get_coercion_model from sage.symbolic.constants import e -from copy import copy -from sage.parallel.ncpus import ncpus -from sage.parallel.use_fork import p_iter_fork -from sage.dynamics.arithmetic_dynamics.projective_ds_helper import (_fast_possible_periods,_all_periodic_points) -from itertools import count, product -from .endPN_automorphism_group import ( - automorphism_group_QQ_CRT, - automorphism_group_QQ_fixedpoints, - conjugating_set_helper, - conjugating_set_initializer, - is_conjugate_helper) -from .endPN_automorphism_group import automorphism_group_FF class DynamicalSystem_projective(SchemeMorphism_polynomial_projective_space, @@ -193,7 +196,7 @@ class DynamicalSystem_projective(SchemeMorphism_polynomial_projective_space, Symbolic Ring elements are not allowed:: sage: x,y = var('x,y') - sage: DynamicalSystem_projective([x^2,y^2]) + sage: DynamicalSystem_projective([x^2, y^2]) Traceback (most recent call last): ... ValueError: [x^2, y^2] must be elements of a polynomial ring @@ -221,7 +224,7 @@ class DynamicalSystem_projective(SchemeMorphism_polynomial_projective_space, When elements of the quotient ring are used, they are reduced:: sage: P.<x,y,z> = ProjectiveSpace(CC, 2) - sage: X = P.subscheme([x-y]) + sage: X = P.subscheme([x - y]) sage: u,v,w = X.coordinate_ring().gens() sage: DynamicalSystem_projective([u^2, v^2, w*u], domain=X) Dynamical System of Closed subscheme of Projective Space of dimension @@ -238,7 +241,7 @@ class DynamicalSystem_projective(SchemeMorphism_polynomial_projective_space, sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([(x-2*y)^2, (x-2*z)^2, x^2]) - sage: X = P.subscheme(y-z) + sage: X = P.subscheme(y - z) sage: f(f(f(X))) Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: @@ -248,7 +251,7 @@ class DynamicalSystem_projective(SchemeMorphism_polynomial_projective_space, sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: f = DynamicalSystem_projective([(x-2*y)^2, (x-2*z)^2, (x-2*w)^2, x^2]) - sage: f(P.subscheme([x,y,z])) + sage: f(P.subscheme([x, y, z])) Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: w, @@ -282,18 +285,18 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): sage: R.<x,y> = QQ[] sage: P1 = ProjectiveSpace(R) - sage: f = DynamicalSystem_projective([x-y, x*y]) + sage: f = DynamicalSystem_projective([x - y, x*y]) Traceback (most recent call last): ... ValueError: polys (=[x - y, x*y]) must be of the same degree - sage: DynamicalSystem_projective([x-1, x*y+x]) + sage: DynamicalSystem_projective([x - 1, x*y + x]) Traceback (most recent call last): ... ValueError: polys (=[x - 1, x*y + x]) must be homogeneous :: - sage: DynamicalSystem_projective([exp(x),exp(y)]) + sage: DynamicalSystem_projective([exp(x), exp(y)]) Traceback (most recent call last): ... ValueError: [e^x, e^y] must be elements of a polynomial ring @@ -310,7 +313,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): :: sage: A.<x,y> = AffineSpace(ZZ, 2) - sage: DynamicalSystem_projective([x^2,y^2], A) + sage: DynamicalSystem_projective([x^2, y^2], A) Traceback (most recent call last): ... ValueError: "domain" must be a projective scheme @@ -373,7 +376,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): raise ValueError('"domain" must be a projective scheme') if R not in Fields(): return typecall(cls, polys, domain) - if is_FiniteField(R): + if isinstance(R, FiniteField): return DynamicalSystem_projective_finite_field(polys, domain) return DynamicalSystem_projective_field(polys, domain) @@ -432,7 +435,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): if not all(split_d == domain._degree(f) for f in split_poly): msg = 'polys (={}) must be multi-homogeneous of the same degrees (by component)' raise TypeError(msg.format(polys)) - if is_FiniteField(R): + if isinstance(R, FiniteField): from sage.dynamics.arithmetic_dynamics.product_projective_ds import DynamicalSystem_product_projective_finite_field return DynamicalSystem_product_projective_finite_field(polys, domain) return DynamicalSystem_product_projective(polys, domain) @@ -450,7 +453,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): raise ValueError('"domain" must be a projective scheme') if R not in Fields(): return typecall(cls, polys, domain) - if is_FiniteField(R): + if isinstance(R, FiniteField): return DynamicalSystem_projective_finite_field(polys, domain) return DynamicalSystem_projective_field(polys, domain) @@ -469,8 +472,9 @@ def __init__(self, polys, domain): (3/5*x^2 : y^2) """ # Next attribute needed for _fast_eval and _fastpolys - self._is_prime_finite_field = is_PrimeFiniteField(polys[0].base_ring()) - DynamicalSystem.__init__(self,polys,domain) + R = polys[0].base_ring() + self._is_prime_finite_field = isinstance(R, FiniteField) and R.is_prime_field() + DynamicalSystem.__init__(self, polys, domain) def __copy__(self): r""" @@ -501,7 +505,8 @@ def _number_field_from_algebraics(self): sage: P.<x,y> = ProjectiveSpace(QQbar,1) sage: f = DynamicalSystem_projective([x^2 + QQbar(sqrt(2)) * y^2, y^2]) sage: f._number_field_from_algebraics() - Dynamical System of Projective Space of dimension 1 over Number Field in a with defining polynomial y^2 - 2 with a = 1.414213562373095? + Dynamical System of Projective Space of dimension 1 over Number Field in a + with defining polynomial y^2 - 2 with a = 1.414213562373095? Defn: Defined on coordinates by sending (x : y) to (x^2 + a*y^2 : y^2) """ @@ -524,7 +529,7 @@ def dehomogenize(self, n): If the dehomogenizing indices are the same for the domain and codomain, then a :class:`DynamicalSystem_affine` given by - dehomogenizing the source and target of `self` with respect to + dehomogenizing the source and target of ``self`` with respect to the given indices is returned. If the dehomogenizing indices for the domain and codomain are different then the resulting affine patches are different and a scheme morphism is returned. @@ -532,7 +537,7 @@ def dehomogenize(self, n): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(ZZ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2]) sage: f.dehomogenize(0) Dynamical System of Affine Space of dimension 1 over Integer Ring Defn: Defined on coordinates by sending (y) to @@ -565,7 +570,7 @@ def dynatomic_polynomial(self, period): ALGORITHM: - For a positive integer `n`, let `[F_n,G_n]` be the coordinates of the `nth` + For a positive integer `n`, let `[F_n,G_n]` be the coordinates of the `n`-th iterate of `f`. Then construct .. MATH:: @@ -672,8 +677,7 @@ def dynatomic_polynomial(self, period): sage: P.<x,y> = ProjectiveSpace(Qp(5),1) sage: f = DynamicalSystem_projective([x^2 + y^2, y^2]) sage: f.dynatomic_polynomial(2) - (x^4*y + (2 + O(5^20))*x^2*y^3 - x*y^4 + (2 + O(5^20))*y^5)/(x^2*y - - x*y^2 + y^3) + (x^4*y + (2 + O(5^20))*x^2*y^3 - x*y^4 + (2 + O(5^20))*y^5)/(x^2*y - x*y^2 + y^3) :: @@ -724,20 +728,22 @@ def dynatomic_polynomial(self, period): sage: P.<x,y> = ProjectiveSpace(CC, 1) sage: f = DynamicalSystem_projective([x^2 - CC.0/3*y^2, y^2]) sage: f.dynatomic_polynomial(2) - (x^4*y + (-0.666666666666667*I)*x^2*y^3 - x*y^4 + (-0.111111111111111 - 0.333333333333333*I)*y^5)/(x^2*y - x*y^2 + (-0.333333333333333*I)*y^3) + (x^4*y + (-0.666666666666667*I)*x^2*y^3 - x*y^4 + + (-0.111111111111111 - 0.333333333333333*I)*y^5)/(x^2*y - x*y^2 + + (-0.333333333333333*I)*y^3) :: sage: P.<x,y> = ProjectiveSpace(CC, 1) - sage: f = DynamicalSystem_projective([x^2-CC.0/5*y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - CC.0/5*y^2, y^2]) sage: f.dynatomic_polynomial(2) x^2 + x*y + (1.00000000000000 - 0.200000000000000*I)*y^2 :: sage: L.<t> = PolynomialRing(QuadraticField(2).maximal_order()) - sage: P.<x, y> = ProjectiveSpace(L.fraction_field() , 1) - sage: f = DynamicalSystem_projective([x^2 + (t^2 + 1)*y^2 , y^2]) + sage: P.<x, y> = ProjectiveSpace(L.fraction_field(), 1) + sage: f = DynamicalSystem_projective([x^2 + (t^2 + 1)*y^2, y^2]) sage: f.dynatomic_polynomial(2) x^2 + x*y + (t^2 + 2)*y^2 @@ -809,7 +815,7 @@ def dynatomic_polynomial(self, period): sage: R.<c> = QQ[] sage: P.<x,y> = ProjectiveSpace(R,1) - sage: f = DynamicalSystem_projective([x^2 + c*y^2,y^2]) + sage: f = DynamicalSystem_projective([x^2 + c*y^2, y^2]) sage: f.dynatomic_polynomial([1,2]).parent() Multivariate Polynomial Ring in x, y over Univariate Polynomial Ring in c over Rational Field @@ -909,24 +915,23 @@ def nth_iterate_map(self, n, normalize=False): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2]) sage: f.nth_iterate_map(2) - Dynamical System of Projective Space of dimension 1 over Rational - Field + Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (x^4 + 2*x^2*y^2 + 2*y^4 : y^4) :: sage: P.<x,y> = ProjectiveSpace(CC,1) - sage: f = DynamicalSystem_projective([x^2-y^2, x*y]) + sage: f = DynamicalSystem_projective([x^2 - y^2, x*y]) sage: f.nth_iterate_map(3) - Dynamical System of Projective Space of dimension 1 over Complex - Field with 53 bits of precision + Dynamical System of Projective Space of dimension 1 + over Complex Field with 53 bits of precision Defn: Defined on coordinates by sending (x : y) to - (x^8 + (-7.00000000000000)*x^6*y^2 + 13.0000000000000*x^4*y^4 + - (-7.00000000000000)*x^2*y^6 + y^8 : x^7*y + (-4.00000000000000)*x^5*y^3 - + 4.00000000000000*x^3*y^5 - x*y^7) + (x^8 + (-7.00000000000000)*x^6*y^2 + 13.0000000000000*x^4*y^4 + + (-7.00000000000000)*x^2*y^6 + y^8 + : x^7*y + (-4.00000000000000)*x^5*y^3 + 4.00000000000000*x^3*y^5 - x*y^7) :: @@ -935,8 +940,8 @@ def nth_iterate_map(self, n, normalize=False): sage: f.nth_iterate_map(2) Dynamical System of Projective Space of dimension 2 over Integer Ring Defn: Defined on coordinates by sending (x : y : z) to - (x^4 - 3*x^2*y^2 + y^4 : x^3*y - x*y^3 : 2*x^4 - 2*x^2*y^2 + y^4 - + 2*x^2*z^2 + z^4) + (x^4 - 3*x^2*y^2 + y^4 : x^3*y - x*y^3 + : 2*x^4 - 2*x^2*y^2 + y^4 + 2*x^2*z^2 + z^4) :: @@ -955,8 +960,7 @@ def nth_iterate_map(self, n, normalize=False): sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([y^2 * z^3, y^3 * z^2, x^5]) sage: f.nth_iterate_map( 5, normalize=True) - Dynamical System of Projective Space of dimension 2 over Rational - Field + Dynamical System of Projective Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x : y : z) to (y^202*z^443 : x^140*y^163*z^342 : x^645) """ @@ -1010,7 +1014,7 @@ def nth_iterate(self, P, n, **kwds): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(ZZ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, 2*y^2]) + sage: f = DynamicalSystem_projective([x^2 + y^2, 2*y^2]) sage: Q = P(1,1) sage: f.nth_iterate(Q,4) (32768 : 32768) @@ -1018,7 +1022,7 @@ def nth_iterate(self, P, n, **kwds): :: sage: P.<x,y> = ProjectiveSpace(ZZ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, 2*y^2]) + sage: f = DynamicalSystem_projective([x^2 + y^2, 2*y^2]) sage: Q = P(1,1) sage: f.nth_iterate(Q, 4, normalize=True) (1 : 1) @@ -1026,7 +1030,7 @@ def nth_iterate(self, P, n, **kwds): :: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: f = DynamicalSystem_projective([x^2, 2*y^2, z^2-x^2]) + sage: f = DynamicalSystem_projective([x^2, 2*y^2, z^2 - x^2]) sage: Q = P(2,7,1) sage: f.nth_iterate(Q,2) (-16/7 : -2744 : 1) @@ -1035,11 +1039,11 @@ def nth_iterate(self, P, n, **kwds): sage: R.<t> = PolynomialRing(QQ) sage: P.<x,y,z> = ProjectiveSpace(R,2) - sage: f = DynamicalSystem_projective([x^2+t*y^2, (2-t)*y^2, z^2]) - sage: Q = P(2+t,7,t) + sage: f = DynamicalSystem_projective([x^2 + t*y^2, (2-t)*y^2, z^2]) + sage: Q = P(2 + t, 7, t) sage: f.nth_iterate(Q,2) - (t^4 + 2507*t^3 - 6787*t^2 + 10028*t + 16 : -2401*t^3 + 14406*t^2 - - 28812*t + 19208 : t^4) + (t^4 + 2507*t^3 - 6787*t^2 + 10028*t + 16 + : -2401*t^3 + 14406*t^2 - 28812*t + 19208 : t^4) :: @@ -1058,7 +1062,7 @@ def nth_iterate(self, P, n, **kwds): ((c^6 - 9*c^4 + 25*c^2 - c - 21)/(c^2 - 3) : 1) sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: f = DynamicalSystem_projective([x^2+3*y^2, 2*y^2,z^2]) + sage: f = DynamicalSystem_projective([x^2 + 3*y^2, 2*y^2, z^2]) sage: f.nth_iterate(P(2, 7, 1), -2) Traceback (most recent call last): ... @@ -1073,7 +1077,8 @@ def nth_iterate(self, P, n, **kwds): sage: f.nth_iterate(P(0, 1), 3) Traceback (most recent call last): ... - ValueError: [0, 0] does not define a point in Projective Space of dimension 1 over Rational Field since all entries are zero + ValueError: [0, 0] does not define a point in Projective Space of + dimension 1 over Rational Field since all entries are zero :: @@ -1087,7 +1092,7 @@ def nth_iterate(self, P, n, **kwds): :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem([x+y,y]) + sage: f = DynamicalSystem([x + y, y]) sage: Q = (3,1) sage: f.nth_iterate(Q,0) (3 : 1) @@ -1095,7 +1100,7 @@ def nth_iterate(self, P, n, **kwds): TESTS:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem([x^2+y^2,y^2]) + sage: f = DynamicalSystem([x^2 + y^2, y^2]) sage: f.nth_iterate(0,0) (0 : 1) """ @@ -1215,9 +1220,9 @@ def arakelov_zhang_pairing(self, g, **kwds): sage: f.arakelov_zhang_pairing(g) 0.326954667248466 sage: # Correct value should be = 0.323067... - sage: f.arakelov_zhang_pairing(g, n=9) + sage: f.arakelov_zhang_pairing(g, n=9) # long time 0.323091061918965 - sage: _ - 0.323067 + sage: _ - 0.323067 # long time 0.0000240619189654789 Also from Prop. 18 of Petsche, Szpiro and Tucker, includes places of bad reduction:: @@ -1228,11 +1233,13 @@ def arakelov_zhang_pairing(self, g, **kwds): sage: a = 7/(b - 1) sage: f = DynamicalSystem_projective([a*y^2 - (a*y - x)^2, y^2]) sage: g = DynamicalSystem_projective([x^2, y^2]) - sage: # If all archimedean absolute values of a have modulus > 2, - sage: # then the pairing should be h(a). - sage: f.arakelov_zhang_pairing(g, n=6) + + If all archimedean absolute values of a have modulus > 2, + then the pairing should be h(a).:: + + sage: f.arakelov_zhang_pairing(g, n=6) # long time 1.93846423207664 - sage: _ - a.global_height() + sage: _ - a.global_height() # long time -0.00744591697867292 """ n = kwds.pop('n', 5) @@ -1474,14 +1481,14 @@ def dynamical_degree(self, N=3, prec=53): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem_projective([x^2 + (x*y), y^2]) + sage: f = DynamicalSystem_projective([x^2 + x*y, y^2]) sage: f.dynamical_degree() 2.00000000000000 :: sage: P2.<X,Y,Z> = ProjectiveSpace(ZZ, 2) - sage: f = DynamicalSystem_projective([X*Y, Y*Z+Z^2, Z^2]) + sage: f = DynamicalSystem_projective([X*Y, Y*Z + Z^2, Z^2]) sage: f.dynamical_degree(N=5, prec=100) 1.4309690811052555010452244131 """ @@ -1523,21 +1530,21 @@ def orbit(self, P, N, **kwds): EXAMPLES:: sage: P.<x,y,z> = ProjectiveSpace(ZZ,2) - sage: f = DynamicalSystem_projective([x^2+y^2, y^2-z^2, 2*z^2]) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2 - z^2, 2*z^2]) sage: f.orbit(P(1,2,1), 3) [(1 : 2 : 1), (5 : 3 : 2), (34 : 5 : 8), (1181 : -39 : 128)] :: sage: P.<x,y,z> = ProjectiveSpace(ZZ,2) - sage: f = DynamicalSystem_projective([x^2+y^2, y^2-z^2, 2*z^2]) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2 - z^2, 2*z^2]) sage: f.orbit(P(1,2,1), [2,4]) [(34 : 5 : 8), (1181 : -39 : 128), (1396282 : -14863 : 32768)] :: sage: P.<x,y,z> = ProjectiveSpace(ZZ,2) - sage: X = P.subscheme(x^2-y^2) + sage: X = P.subscheme(x^2 - y^2) sage: f = DynamicalSystem_projective([x^2, y^2, x*z], domain=X) sage: f.orbit(X(2,2,3), 3, normalize=True) [(2 : 2 : 3), (2 : 2 : 3), (2 : 2 : 3), (2 : 2 : 3)] @@ -1545,22 +1552,22 @@ def orbit(self, P, N, **kwds): :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, y^2]) - sage: f.orbit(P.point([1,2],False), 4, check=False) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2]) + sage: f.orbit(P.point([1,2], False), 4, check=False) [(1 : 2), (5 : 4), (41 : 16), (1937 : 256), (3817505 : 65536)] :: sage: K.<c> = FunctionField(QQ) sage: P.<x,y> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([x^2+c*y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 + c*y^2, y^2]) sage: f.orbit(P(0,1), 3) [(0 : 1), (c : 1), (c^2 + c : 1), (c^4 + 2*c^3 + c^2 + c : 1)] :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2+y^2,y^2], domain=P) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2], domain=P) sage: f.orbit(P.point([1, 2], False), 4, check=False) [(1 : 2), (5 : 4), (41 : 16), (1937 : 256), (3817505 : 65536)] @@ -1584,7 +1591,8 @@ def orbit(self, P, N, **kwds): sage: f.orbit(P(0, 1), 3) Traceback (most recent call last): ... - ValueError: [0, 0] does not define a point in Projective Space of dimension 1 over Rational Field since all entries are zero + ValueError: [0, 0] does not define a point in Projective Space of + dimension 1 over Rational Field since all entries are zero sage: f.orbit(P(0, 1), 3, check=False) [(0 : 1), (0 : 0), (0 : 0), (0 : 0)] @@ -1601,20 +1609,20 @@ def orbit(self, P, N, **kwds): sage: P.<x,y,z> = ProjectiveSpace(QQ,2) sage: f = DynamicalSystem_projective([x^2, y^2, x*z]) - sage: f.orbit((2/3,1/3), 3) + sage: f.orbit((2/3, 1/3), 3) [(2/3 : 1/3 : 1), (2/3 : 1/6 : 1), (2/3 : 1/24 : 1), (2/3 : 1/384 : 1)] TESTS:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem([x^2+y^2,y^2]) + sage: f = DynamicalSystem([x^2 + y^2, y^2]) sage: f.orbit(0, 0) [(0 : 1)] :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem([x^2-y^2,y^2]) + sage: f = DynamicalSystem([x^2 - y^2, y^2]) sage: f.orbit(0,2) [(0 : 1), (-1 : 1), (0 : 1)] """ @@ -1650,7 +1658,7 @@ def orbit(self, P, N, **kwds): def resultant(self, normalize=False): r""" - Computes the resultant of the defining polynomials of + Compute the resultant of the defining polynomials of this dynamical system. If ``normalize`` is ``True``, then first normalize the coordinate @@ -1665,7 +1673,7 @@ def resultant(self, normalize=False): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, 6*y^2]) + sage: f = DynamicalSystem_projective([x^2 + y^2, 6*y^2]) sage: f.resultant() 36 @@ -1673,7 +1681,7 @@ def resultant(self, normalize=False): sage: R.<t> = PolynomialRing(GF(17)) sage: P.<x,y> = ProjectiveSpace(R,1) - sage: f = DynamicalSystem_projective([t*x^2+t*y^2, 6*y^2]) + sage: f = DynamicalSystem_projective([t*x^2 + t*y^2, 6*y^2]) sage: f.resultant() 2*t^2 @@ -1681,23 +1689,23 @@ def resultant(self, normalize=False): sage: R.<t> = PolynomialRing(GF(17)) sage: P.<x,y,z> = ProjectiveSpace(R,2) - sage: f = DynamicalSystem_projective([t*x^2+t*y^2, 6*y^2, 2*t*z^2]) + sage: f = DynamicalSystem_projective([t*x^2 + t*y^2, 6*y^2, 2*t*z^2]) sage: f.resultant() 13*t^8 :: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: F = DynamicalSystem_projective([x^2+y^2,6*y^2,10*x*z+z^2+y^2]) + sage: F = DynamicalSystem_projective([x^2 + y^2, 6*y^2, 10*x*z + z^2 + y^2]) sage: F.resultant() 1296 :: - sage: R.<t>=PolynomialRing(QQ) - sage: s = (t^3+t+1).roots(QQbar)[0][0] - sage: P.<x,y>=ProjectiveSpace(QQbar,1) - sage: f = DynamicalSystem_projective([s*x^3-13*y^3, y^3-15*y^3]) + sage: R.<t> = PolynomialRing(QQ) + sage: s = (t^3 + t + 1).roots(QQbar)[0][0] + sage: P.<x,y> = ProjectiveSpace(QQbar, 1) + sage: f = DynamicalSystem_projective([s*x^3 - 13*y^3, y^3 - 15*y^3]) sage: f.resultant() 871.6925062959149? """ @@ -1758,14 +1766,15 @@ def primes_of_bad_reduction(self, check=True): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([1/3*x^2+1/2*y^2, y^2]) + sage: f = DynamicalSystem_projective([1/3*x^2 + 1/2*y^2, y^2]) sage: f.primes_of_bad_reduction() [2, 3] :: sage: P.<x,y,z,w> = ProjectiveSpace(QQ,3) - sage: f = DynamicalSystem_projective([12*x*z-7*y^2, 31*x^2-y^2, 26*z^2, 3*w^2-z*w]) + sage: f = DynamicalSystem_projective([12*x*z - 7*y^2, 31*x^2 - y^2, + ....: 26*z^2, 3*w^2 - z*w]) sage: f.primes_of_bad_reduction() [2, 3, 7, 13, 31] @@ -1778,7 +1787,7 @@ def primes_of_bad_reduction(self, check=True): sage: f.primes_of_bad_reduction() [Fractional ideal (a), Fractional ideal (3)] - This is an example where check = False returns extra primes:: + This is an example where ``check=False`` returns extra primes:: sage: P.<x,y,z> = ProjectiveSpace(ZZ,2) sage: f = DynamicalSystem_projective([3*x*y^2 + 7*y^3 - 4*y^2*z + 5*z^3, @@ -1860,16 +1869,20 @@ def conjugate(self, M, adjugate=False, normalize=False): - ``M`` -- a square invertible matrix - - ``adjugate`` -- (default: ``False``) boolean, also classically called adjoint, takes a square matrix ``M`` and finds the transpose of its cofactor matrix. Used for conjugation in place of inverse when specified ``'True'``. Functionality is the same in projective space. + - ``adjugate`` -- (default: ``False``) boolean, also classically called + adjoint, takes a square matrix ``M`` and finds the transpose of its + cofactor matrix. Used for conjugation in place of inverse when + specified ``True``. Functionality is the same in projective space. - - ``normalize`` -- (default: ``False``) boolean, if normalize is ``'True'``, then the function ``normalize_coordinates`` is called. + - ``normalize`` -- (default: ``False``) boolean, if ``normalize`` is + ``True``, then the method ``normalize_coordinates`` is called. OUTPUT: a dynamical system EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(ZZ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2]) sage: f.conjugate(matrix([[1,2], [0,1]])) Dynamical System of Projective Space of dimension 1 over Integer Ring Defn: Defined on coordinates by sending (x : y) to @@ -1878,9 +1891,9 @@ def conjugate(self, M, adjugate=False, normalize=False): :: sage: R.<x> = PolynomialRing(QQ) - sage: K.<i> = NumberField(x^2+1) + sage: K.<i> = NumberField(x^2 + 1) sage: P.<x,y> = ProjectiveSpace(ZZ,1) - sage: f = DynamicalSystem_projective([x^3+y^3, y^3]) + sage: f = DynamicalSystem_projective([x^3 + y^3, y^3]) sage: f.conjugate(matrix([[i,0], [0,-i]])) Dynamical System of Projective Space of dimension 1 over Integer Ring Defn: Defined on coordinates by sending (x : y) to @@ -1889,7 +1902,7 @@ def conjugate(self, M, adjugate=False, normalize=False): :: sage: P.<x,y,z> = ProjectiveSpace(ZZ,2) - sage: f = DynamicalSystem_projective([x^2+y^2 ,y^2, y*z]) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2, y*z]) sage: f.conjugate(matrix([[1,2,3], [0,1,2], [0,0,1]])) Dynamical System of Projective Space of dimension 2 over Integer Ring Defn: Defined on coordinates by sending (x : y : z) to @@ -1907,25 +1920,26 @@ def conjugate(self, M, adjugate=False, normalize=False): :: sage: R.<x> = PolynomialRing(QQ) - sage: K.<i> = NumberField(x^2+1) + sage: K.<i> = NumberField(x^2 + 1) sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([1/3*x^2+1/2*y^2, y^2]) + sage: f = DynamicalSystem_projective([1/3*x^2 + 1/2*y^2, y^2]) sage: f.conjugate(matrix([[i,0], [0,-i]])) - Dynamical System of Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 + Dynamical System of Projective Space of dimension 1 + over Number Field in i with defining polynomial x^2 + 1 Defn: Defined on coordinates by sending (x : y) to ((1/3*i)*x^2 + (1/2*i)*y^2 : (-i)*y^2) TESTS:: sage: R = ZZ - sage: P.<x,y>=ProjectiveSpace(R,1) - sage: f=DynamicalSystem_projective([x^2 + y^2,y^2]) - sage: m=matrix(R,2,[4, 3, 2, 1]) - sage: f.conjugate(m,normalize=False) + sage: P.<x,y> = ProjectiveSpace(R,1) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2]) + sage: m = matrix(R, 2, [4, 3, 2, 1]) + sage: f.conjugate(m, normalize=False) Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (-4*x^2 - 8*x*y - 7/2*y^2 : 12*x^2 + 20*x*y + 8*y^2) - sage: f.conjugate(m,adjugate=True) + sage: f.conjugate(m, adjugate=True) Dynamical System of Projective Space of dimension 1 over Integer Ring Defn: Defined on coordinates by sending (x : y) to (8*x^2 + 16*x*y + 7*y^2 : -24*x^2 - 40*x*y - 16*y^2) @@ -1999,7 +2013,7 @@ def green_function(self, P, v, **kwds): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, x*y]); + sage: f = DynamicalSystem_projective([x^2 + y^2, x*y]); sage: Q = P(5, 1) sage: f.green_function(Q, 0, N=30) 1.6460930159932946233759277576 @@ -2007,7 +2021,7 @@ def green_function(self, P, v, **kwds): :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, x*y]); + sage: f = DynamicalSystem_projective([x^2 + y^2, x*y]); sage: Q = P(5, 1) sage: f.green_function(Q, 0, N=200, prec=200) 1.6460930160038721802875250367738355497198064992657997569827 @@ -2016,7 +2030,7 @@ def green_function(self, P, v, **kwds): sage: K.<w> = QuadraticField(3) sage: P.<x,y> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([17*x^2+1/7*y^2, 17*w*x*y]) + sage: f = DynamicalSystem_projective([17*x^2 + 1/7*y^2, 17*w*x*y]) sage: f.green_function(P.point([w, 2], False), K.places()[1]) 1.7236334013785676107373093775 sage: f.green_function(P([2, 1]), K.ideal(7), N=7) @@ -2027,7 +2041,7 @@ def green_function(self, P, v, **kwds): :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, x*y]) + sage: f = DynamicalSystem_projective([x^2 + y^2, x*y]) sage: f.green_function(P.point([5,2], False), 0, N=30) 1.7315451844777407992085512000 sage: f.green_function(P.point([2,1], False), 0, N=30) @@ -2190,7 +2204,7 @@ def canonical_height(self, P, **kwds): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(ZZ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, 2*x*y]); + sage: f = DynamicalSystem_projective([x^2 + y^2, 2*x*y]); sage: f.canonical_height(P.point([5,4]), error_bound=0.001) 2.1970553519503404898926835324 sage: f.canonical_height(P.point([2,1]), error_bound=0.001) @@ -2201,18 +2215,18 @@ def canonical_height(self, P, **kwds): sage: R.<X> = PolynomialRing(QQ) sage: K.<a> = NumberField(X^2 + X - 1) sage: P.<x,y> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([x^2-2*y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - 2*y^2, y^2]) sage: Q = P.point([a,1]) - sage: f.canonical_height(Q, error_bound=0.000001) # Answer only within error_bound of 0 + sage: f.canonical_height(Q, error_bound=0.000001) # Answer only within error_bound of 0 5.7364919788790160119266380480e-8 - sage: f.nth_iterate(Q,2) == Q # but it is indeed preperiodic + sage: f.nth_iterate(Q, 2) == Q # but it is indeed preperiodic True :: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: X = P.subscheme(x^2-y^2); - sage: f = DynamicalSystem_projective([x^2,y^2, 4*z^2], domain=X); + sage: X = P.subscheme(x^2 - y^2); + sage: f = DynamicalSystem_projective([x^2, y^2, 4*z^2], domain=X); sage: Q = X([4,4,1]) sage: f.canonical_height(Q, badprimes=[2]) 0.0013538030870311431824555314882 @@ -2220,8 +2234,8 @@ def canonical_height(self, P, **kwds): :: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: X = P.subscheme(x^2-y^2); - sage: f = DynamicalSystem_projective([x^2,y^2, 30*z^2], domain=X) + sage: X = P.subscheme(x^2 - y^2); + sage: f = DynamicalSystem_projective([x^2, y^2, 30*z^2], domain=X) sage: Q = X([4, 4, 1]) sage: f.canonical_height(Q, badprimes=[2,3,5], prec=200) 2.7054056208276961889784303469356774912979228770208655455481 @@ -2229,7 +2243,7 @@ def canonical_height(self, P, **kwds): :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem_projective([1000*x^2-29*y^2, 1000*y^2]) + sage: f = DynamicalSystem_projective([1000*x^2 - 29*y^2, 1000*y^2]) sage: Q = P(-1/4, 1) sage: f.canonical_height(Q, error_bound=0.01) 3.7996079979254623065837411853 @@ -2249,7 +2263,7 @@ def canonical_height(self, P, **kwds): :: sage: P.<x,y>=ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem([2*( -2*x^3 + 3*(x^2*y)) + 3*y^3,3*y^3]) + sage: f = DynamicalSystem([2*(-2*x^3 + 3*(x^2*y)) + 3*y^3, 3*y^3]) sage: f.canonical_height(P(1,0)) 0.00000000000000000000000000000 """ @@ -2332,7 +2346,7 @@ def canonical_height(self, P, **kwds): # is always nonnegative, so if this value is within -err of 0, return 0. if h < 0: assert h > -err, "A negative height less than -error_bound was computed. " + \ - "This should be impossible, please report bug on trac.sagemath.org." + "This should be impossible, please report bug on https://github.com/sagemath/sage/issues" # This should be impossible. The error bound for Wells' is rigorous # and the actual height is always >= 0. If we see something less than -err, # something has g one very wrong. @@ -2424,7 +2438,8 @@ def height_difference_bound(self, prec=None): :: sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) - sage: f = DynamicalSystem_projective([x^2, QQbar(sqrt(-1))*y^2, QQbar(sqrt(3))*z^2]) + sage: f = DynamicalSystem_projective([x^2, QQbar(sqrt(-1))*y^2, + ....: QQbar(sqrt(3))*z^2]) sage: f.height_difference_bound() 2.89037175789616 @@ -2488,8 +2503,8 @@ def multiplier(self, P, n, check=True): EXAMPLES:: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: f = DynamicalSystem_projective([x^2,y^2, 4*z^2]); - sage: Q = P.point([4,4,1], False); + sage: f = DynamicalSystem_projective([x^2, y^2, 4*z^2]) + sage: Q = P.point([4,4,1], False) sage: f.multiplier(Q,1) [2 0] [0 2] @@ -2511,23 +2526,23 @@ def multiplier(self, P, n, check=True): :: sage: P.<x,y> = ProjectiveSpace(RR,1) - sage: f = DynamicalSystem_projective([x^2-2*y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - 2*y^2, y^2]) sage: f.multiplier(P(2,1), 1) [4.00000000000000] :: sage: P.<x,y> = ProjectiveSpace(Qp(13),1) - sage: f = DynamicalSystem_projective([x^2-29/16*y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - 29/16*y^2, y^2]) sage: f.multiplier(P(5,4), 3) [6 + 8*13 + 13^2 + 8*13^3 + 13^4 + 8*13^5 + 13^6 + 8*13^7 + 13^8 + - 8*13^9 + 13^10 + 8*13^11 + 13^12 + 8*13^13 + 13^14 + 8*13^15 + 13^16 + - 8*13^17 + 13^18 + 8*13^19 + O(13^20)] + 8*13^9 + 13^10 + 8*13^11 + 13^12 + 8*13^13 + 13^14 + 8*13^15 + 13^16 + + 8*13^17 + 13^18 + 8*13^19 + O(13^20)] :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2-y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - y^2, y^2]) sage: f.multiplier(P(0,1), 1) Traceback (most recent call last): ... @@ -2590,14 +2605,14 @@ def _multipliermod(self, P, n, p, k): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2-29/16*y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - 29/16*y^2, y^2]) sage: f._multipliermod(P(5,4), 3, 11, 1) [3] :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2-29/16*y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - 29/16*y^2, y^2]) sage: f._multipliermod(P(5,4), 3, 11, 2) [80] """ @@ -2709,34 +2724,41 @@ def nth_preimage_tree(self, Q, n, **kwds): kwds: - - ``return_points`` -- (default: ``False``) boolean; if ``True``, return a list of lists - where the index ``i`` is the level of the tree and the elements of the list at that - index are the ``i``-th preimage points as an algebraic element of the splitting field - of the polynomial ``f^n - Q = 0`` + - ``return_points`` -- (default: ``False``) boolean; if ``True``, + return a list of lists where the index `i` is the level of the tree + and the elements of the list at that index are the `i`-th preimage + points as an algebraic element of the splitting field of the + polynomial `f^n - Q = 0` - - ``numerical`` -- (default: ``False``) boolean; calculate pre-images numerically. Note if this - is set to ``True``, preimage points are displayed as complex numbers + - ``numerical`` -- (default: ``False``) boolean; calculate pre-images + numerically. Note if this is set to ``True``, preimage points are + displayed as complex numbers - - ``prec`` -- (default: 100) positive integer; the precision of the ``ComplexField`` if - we compute the preimage points numerically + - ``prec`` -- (default: 100) positive integer; the precision of the + ``ComplexField`` if we compute the preimage points numerically - - ``display_labels`` -- (default: ``True``) boolean; whether to display vertex labels. Since labels - can be very cluttered, can set ``display_labels`` to ``False`` and use ``return_points`` to get a + - ``display_labels`` -- (default: ``True``) boolean; whether to display + vertex labels. Since labels can be very cluttered, can set + ``display_labels`` to ``False`` and use ``return_points`` to get a hold of the points themselves, either as algebraic or complex numbers - - ``display_complex`` -- (default: ``False``) boolean; display vertex labels as - complex numbers. Note if this option is chosen that we must choose an embedding - from the splitting field ``field_def`` of the nth-preimage equation into C. We make - the choice of the first embedding returned by ``field_def.embeddings(ComplexField())`` + - ``display_complex`` -- (default: ``False``) boolean; display vertex + labels as complex numbers. Note if this option is chosen that we must + choose an embedding from the splitting field ``field_def`` of the + `n`-th-preimage equation into `\CC`. We make the choice of the first + embedding returned by ``field_def.embeddings(ComplexField())`` - - ``digits`` -- a positive integer, the number of decimal digits to display for complex - numbers. This only applies if ``display_complex`` is set to ``True`` + - ``digits`` -- a positive integer, the number of decimal digits to + display for complex numbers. This only applies if ``display_complex`` + is set to ``True`` OUTPUT: - If ``return_points`` is ``False``, a ``GraphPlot`` object representing the ``n``-th pre-image tree. - If ``return_points`` is ``True``, a tuple ``(GP, points)``, where ``GP`` is a ``GraphPlot`` object, - and ``points`` is a list of lists as described above under ``return_points``. + If ``return_points`` is ``False``, a :class:`GraphPlot` object representing + the `n`-th pre-image tree. If ``return_points`` is ``True``, a tuple + ``(GP, points)``, where ``GP`` is a :class:`GraphPlot` object, and + ``points`` is a list of lists as described above under + ``return_points``. EXAMPLES:: @@ -2748,7 +2770,7 @@ def nth_preimage_tree(self, Q, n, **kwds): :: - sage: P.<x,y> = ProjectiveSpace(GF(3),1) + sage: P.<x,y> = ProjectiveSpace(GF(3), 1) sage: f = DynamicalSystem_projective([x^2 + x*y + y^2, y^2]) sage: Q = P(0,1) sage: f.nth_preimage_tree(Q, 2, return_points=True) @@ -2851,7 +2873,7 @@ def possible_periods(self, **kwds): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2-29/16*y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - 29/16*y^2, y^2]) sage: f.possible_periods(ncpus=1) [1, 3] @@ -2950,7 +2972,7 @@ def _preperiodic_points_to_cyclegraph(self, preper): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2-2*y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - 2*y^2, y^2]) sage: preper = [P(-2, 1), P(1, 0), P(0, 1), P(1, 1), P(2, 1), P(-1, 1)] sage: f._preperiodic_points_to_cyclegraph(preper) Looped digraph on 6 vertices @@ -2995,21 +3017,21 @@ def is_PGL_minimal(self, prime_list=None): EXAMPLES:: sage: PS.<X,Y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([X^2+3*Y^2, X*Y]) + sage: f = DynamicalSystem_projective([X^2 + 3*Y^2, X*Y]) sage: f.is_PGL_minimal() True :: sage: PS.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([6*x^2+12*x*y+7*y^2, 12*x*y]) + sage: f = DynamicalSystem_projective([6*x^2 + 12*x*y + 7*y^2, 12*x*y]) sage: f.is_PGL_minimal() False :: sage: PS.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([6*x^2+12*x*y+7*y^2, y^2]) + sage: f = DynamicalSystem_projective([6*x^2 + 12*x*y + 7*y^2, y^2]) sage: f.is_PGL_minimal() False """ @@ -3055,7 +3077,7 @@ def minimal_model(self, return_transformation=False, prime_list=None, algorithm= - ``algorithm`` -- (optional) string; can be one of the following: - ``check_primes`` -- (optional) boolean: this signals whether to - check whether each element in prime_list is a prime + check whether each element in ``prime_list`` is a prime * ``'BM'`` - the Bruin-Molnar algorithm [BM2012]_ * ``'HS'`` - the Hutz-Stoll algorithm [HS2018]_ @@ -3070,7 +3092,7 @@ def minimal_model(self, return_transformation=False, prime_list=None, algorithm= EXAMPLES:: sage: PS.<X,Y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([X^2+3*Y^2, X*Y]) + sage: f = DynamicalSystem_projective([X^2 + 3*Y^2, X*Y]) sage: f.minimal_model(return_transformation=True) ( Dynamical System of Projective Space of dimension 1 over Rational @@ -3085,8 +3107,10 @@ def minimal_model(self, return_transformation=False, prime_list=None, algorithm= :: sage: PS.<X,Y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([7365/2*X^4 + 6282*X^3*Y + 4023*X^2*Y^2 + 1146*X*Y^3 + 245/2*Y^4, - ....: -12329/2*X^4 - 10506*X^3*Y - 6723*X^2*Y^2 - 1914*X*Y^3 - 409/2*Y^4]) + sage: f = DynamicalSystem_projective([7365/2*X^4 + 6282*X^3*Y + 4023*X^2*Y^2 + ....: + 1146*X*Y^3 + 245/2*Y^4, + ....: -12329/2*X^4 - 10506*X^3*Y - 6723*X^2*Y^2 + ....: - 1914*X*Y^3 - 409/2*Y^4]) sage: f.minimal_model(return_transformation=True) ( Dynamical System of Projective Space of dimension 1 over Rational Field @@ -3101,17 +3125,16 @@ def minimal_model(self, return_transformation=False, prime_list=None, algorithm= :: sage: PS.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([6*x^2+12*x*y+7*y^2, 12*x*y]) + sage: f = DynamicalSystem_projective([6*x^2 + 12*x*y + 7*y^2, 12*x*y]) sage: f.minimal_model() - Dynamical System of Projective Space of dimension 1 over Rational - Field + Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (x^2 + 12*x*y + 42*y^2 : 2*x*y) :: sage: PS.<x,y> = ProjectiveSpace(ZZ,1) - sage: f = DynamicalSystem_projective([6*x^2+12*x*y+7*y^2, 12*x*y + 42*y^2]) + sage: f = DynamicalSystem_projective([6*x^2 + 12*x*y + 7*y^2, 12*x*y + 42*y^2]) sage: g,M = f.minimal_model(return_transformation=True, algorithm='BM') sage: f.conjugate(M) == g True @@ -3136,7 +3159,7 @@ def minimal_model(self, return_transformation=False, prime_list=None, algorithm= TESTS:: sage: PS.<X,Y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([X+Y, X-3*Y]) + sage: f = DynamicalSystem_projective([X + Y, X - 3*Y]) sage: f.minimal_model() Traceback (most recent call last): ... @@ -3145,7 +3168,7 @@ def minimal_model(self, return_transformation=False, prime_list=None, algorithm= :: sage: PS.<X,Y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([X^2-Y^2, X^2+X*Y]) + sage: f = DynamicalSystem_projective([X^2 - Y^2, X^2 + X*Y]) sage: f.minimal_model() Traceback (most recent call last): ... @@ -3155,10 +3178,11 @@ def minimal_model(self, return_transformation=False, prime_list=None, algorithm= sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem([2*x^2, y^2]) - sage: f.minimal_model(algorithm = 'BM') + sage: f.minimal_model(algorithm='BM') Traceback (most recent call last): ... - TypeError: affine minimality is only considered for maps not of the form f or 1/f for a polynomial f + TypeError: affine minimality is only considered for + maps not of the form f or 1/f for a polynomial f :: @@ -3348,8 +3372,9 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): r""" Return a dynamical system conjugate to this one with affine (n, m) preperiodic points. - If the base ring of this dynamical system is finite, there may not be a model - with affine preperiodic points, in which case a ValueError is thrown. + If the base ring of this dynamical system is finite, there may + not be a model with affine preperiodic points, in which case a + :class:`ValueError` is raised. INPUT: @@ -3376,34 +3401,35 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): sage: g.periodic_points(1) [(-1 : -1 : 1), - (-1/2 : -1 : 1), - (-1/2 : -1/2 : 1), - (-1/3 : -2/3 : 1), - (0 : -1 : 1), - (0 : -1/2 : 1), - (0 : 0 : 1)] + (-1/2 : -1 : 1), + (-1/2 : -1/2 : 1), + (-1/3 : -2/3 : 1), + (0 : -1 : 1), + (0 : -1/2 : 1), + (0 : 0 : 1)] :: sage: P.<x,y,z> = ProjectiveSpace(GF(9), 2) sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) sage: f.affine_preperiodic_model(0, 1) - Dynamical System of Projective Space of dimension 2 over Finite Field in z2 of size 3^2 - Defn: Defined on coordinates by sending (x : y : z) to - ((-z2)*x^2 : z2*x^2 + (-z2)*x*y + (-z2)*y^2 : - (-z2)*x^2 + z2*x*y + (z2 + 1)*y^2 - y*z + z^2) + Dynamical System of Projective Space of dimension 2 + over Finite Field in z2 of size 3^2 + Defn: Defined on coordinates by sending (x : y : z) to + ((-z2)*x^2 : z2*x^2 + (-z2)*x*y + (-z2)*y^2 : + (-z2)*x^2 + z2*x*y + (z2 + 1)*y^2 - y*z + z^2) :: sage: R.<c> = GF(3)[] sage: P.<x,y,z> = ProjectiveSpace(R, 2) sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) - sage: f.affine_preperiodic_model(0, 1) # long time + sage: f.affine_preperiodic_model(0, 1) # long time Dynamical System of Projective Space of dimension 2 over - Univariate Polynomial Ring in c over Finite Field of size 3 + Univariate Polynomial Ring in c over Finite Field of size 3 Defn: Defined on coordinates by sending (x : y : z) to (2*c^3*x^2 : c^3*x^2 + 2*c^3*x*y + 2*c^3*y^2 : - 2*c^3*x^2 + c^3*x*y + (c^3 + c^2)*y^2 + 2*c^2*y*z + c^2*z^2) + 2*c^3*x^2 + c^3*x*y + (c^3 + c^2)*y^2 + 2*c^2*y*z + c^2*z^2) :: @@ -3412,7 +3438,7 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): sage: f = DynamicalSystem_projective([x^2 + k*x*y + y^2, z^2, y^2]) sage: f.affine_preperiodic_model(1, 1) Dynamical System of Projective Space of dimension 2 - over Cyclotomic Field of order 3 and degree 2 + over Cyclotomic Field of order 3 and degree 2 Defn: Defined on coordinates by sending (x : y : z) to (-y^2 : x^2 : x^2 + (-k)*x*z + z^2) @@ -3430,8 +3456,8 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): sage: X = P.subscheme(2*y - z) sage: f = DynamicalSystem_projective([x^2 + y^2, z^2 + y^2, z^2], domain=X) sage: f.affine_preperiodic_model(0, 1) - Dynamical System of Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - 2*y - z + Dynamical System of Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: 2*y - z Defn: Defined on coordinates by sending (x : y : z) to (-x^2 - y^2 : y^2 : x^2 + z^2) @@ -3577,7 +3603,7 @@ def automorphism_group(self, **kwds): EXAMPLES:: sage: R.<x,y> = ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem_projective([x^2-y^2, x*y]) + sage: f = DynamicalSystem_projective([x^2 - y^2, x*y]) sage: f.automorphism_group(return_functions=True) [x, -x] @@ -3601,7 +3627,7 @@ def automorphism_group(self, **kwds): :: sage: R.<x,y> = ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem_projective([x^2-2*x*y-2*y^2, -2*x^2-2*x*y+y^2]) + sage: f = DynamicalSystem_projective([x^2 - 2*x*y - 2*y^2, -2*x^2 - 2*x*y + y^2]) sage: f.automorphism_group(return_functions=True) [x, 1/x, -x - 1, -x/(x + 1), (-x - 1)/x, -1/(x + 1)] @@ -3609,10 +3635,12 @@ def automorphism_group(self, **kwds): sage: R.<x,y> = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([3*x^2*y - y^3, x^3 - 3*x*y^2]) - sage: lst, label = f.automorphism_group(algorithm='CRT', return_functions=True, iso_type=True) + sage: lst, label = f.automorphism_group(algorithm='CRT', return_functions=True, + ....: iso_type=True) sage: sorted(lst), label ([-1/x, 1/x, (-x - 1)/(x - 1), (-x + 1)/(x + 1), (x - 1)/(x + 1), - (x + 1)/(x - 1), -x, x], 'Dihedral of order 8') + (x + 1)/(x - 1), -x, x], + 'Dihedral of order 8') :: @@ -3640,7 +3668,7 @@ def automorphism_group(self, **kwds): sage: K.<w> = CyclotomicField(3) sage: P.<x,y> = ProjectiveSpace(K, 1) - sage: D6 = DynamicalSystem_projective([y^2,x^2]) + sage: D6 = DynamicalSystem_projective([y^2, x^2]) sage: sorted(D6.automorphism_group()) [ [-w - 1 0] [ 0 -w - 1] [w 0] [0 w] [0 1] [1 0] @@ -3683,35 +3711,35 @@ def critical_subscheme(self): sage: set_verbose(None) sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^3-2*x*y^2 + 2*y^3, y^3]) + sage: f = DynamicalSystem_projective([x^3 - 2*x*y^2 + 2*y^3, y^3]) sage: f.critical_subscheme() Closed subscheme of Projective Space of dimension 1 over Rational Field defined by: - 9*x^2*y^2 - 6*y^4 + 9*x^2*y^2 - 6*y^4 :: sage: set_verbose(None) sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([2*x^2-y^2, x*y]) + sage: f = DynamicalSystem_projective([2*x^2 - y^2, x*y]) sage: f.critical_subscheme() Closed subscheme of Projective Space of dimension 1 over Rational Field defined by: - 4*x^2 + 2*y^2 + 4*x^2 + 2*y^2 :: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: f = DynamicalSystem_projective([2*x^2-y^2, x*y, z^2]) + sage: f = DynamicalSystem_projective([2*x^2 - y^2, x*y, z^2]) sage: f.critical_subscheme() Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - 8*x^2*z + 4*y^2*z + 8*x^2*z + 4*y^2*z :: - sage: P.<x,y,z,w> = ProjectiveSpace(GF(81),3) - sage: g = DynamicalSystem_projective([x^3+y^3, y^3+z^3, z^3+x^3, w^3]) + sage: P.<x,y,z,w> = ProjectiveSpace(GF(81), 3) + sage: g = DynamicalSystem_projective([x^3 + y^3, y^3 + z^3, z^3 + x^3, w^3]) sage: g.critical_subscheme() Closed subscheme of Projective Space of dimension 3 over Finite Field in z4 of size 3^4 defined by: @@ -3720,7 +3748,7 @@ def critical_subscheme(self): :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2,x*y]) + sage: f = DynamicalSystem_projective([x^2, x*y]) sage: f.critical_subscheme() Traceback (most recent call last): ... @@ -3752,7 +3780,7 @@ def critical_points(self, R=None): sage: set_verbose(None) sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^3-2*x*y^2 + 2*y^3, y^3]) + sage: f = DynamicalSystem_projective([x^3 - 2*x*y^2 + 2*y^3, y^3]) sage: f.critical_points() [(1 : 0)] sage: K.<w> = QuadraticField(6) @@ -3763,7 +3791,7 @@ def critical_points(self, R=None): sage: set_verbose(None) sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([2*x^2-y^2, x*y]) + sage: f = DynamicalSystem_projective([2*x^2 - y^2, x*y]) sage: f.critical_points(QQbar) [(-0.7071067811865475?*I : 1), (0.7071067811865475?*I : 1)] """ @@ -3828,7 +3856,7 @@ def ramification_type(self, R=None, stable=True): sage: F.ramification_type() [[3], [3], [3]] - sage: F = DynamicalSystem_projective([x^3-2*x*y^2 + 2*y^3, y^3]) + sage: F = DynamicalSystem_projective([x^3 - 2*x*y^2 + 2*y^3, y^3]) sage: F.ramification_type() [[2], [2], [3]] sage: F.ramification_type(R=F.base_ring()) @@ -3862,7 +3890,7 @@ def is_postcritically_finite(self, err=0.01, use_algebraic_closure=True): Only for endomorphisms of `\mathbb{P}^1`. It checks if each critical point is preperiodic. The optional parameter ``err`` is passed into - ``is_preperiodic()`` as part of the preperiodic check. + :meth:`is_preperiodic` as part of the preperiodic check. The computations can be done either over the algebraic closure of the base field or over the minimal extension of the base field that @@ -3872,8 +3900,8 @@ def is_postcritically_finite(self, err=0.01, use_algebraic_closure=True): - ``err`` -- (default: 0.01) positive real number - - ``use_algebraic_closure`` -- boolean (default: True) -- If True uses the - algebraic closure. If False, uses the smallest extension of the base field + - ``use_algebraic_closure`` -- boolean (default: ``True``) -- If ``True``, uses the + algebraic closure. If ``False``, uses the smallest extension of the base field containing all the critical points. OUTPUT: boolean @@ -3897,14 +3925,15 @@ def is_postcritically_finite(self, err=0.01, use_algebraic_closure=True): sage: R.<z> = QQ[] sage: K.<v> = NumberField(z^8 + 3*z^6 + 3*z^4 + z^2 + 1) sage: PS.<x,y> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([x^3+v*y^3, y^3]) + sage: f = DynamicalSystem_projective([x^3 + v*y^3, y^3]) sage: f.is_postcritically_finite() # long time True :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([6*x^2+16*x*y+16*y^2, -3*x^2-4*x*y-4*y^2]) + sage: f = DynamicalSystem_projective([6*x^2 + 16*x*y + 16*y^2, + ....: -3*x^2 - 4*x*y - 4*y^2]) sage: f.is_postcritically_finite() True @@ -3920,7 +3949,7 @@ def is_postcritically_finite(self, err=0.01, use_algebraic_closure=True): sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem_projective([8*x^4 - 8*x^2*y^2 + y^4, y^4]) - sage: f.is_postcritically_finite(use_algebraic_closure=False) #long time + sage: f.is_postcritically_finite(use_algebraic_closure=False) # long time True :: @@ -3979,7 +4008,7 @@ def is_dynamical_belyi_map(self): EXAMPLES:: sage: P.<x,y>=ProjectiveSpace(QQ, 1) - sage: f=DynamicalSystem_projective([-2*x^3 - 9*x^2*y - 12*x*y^2 - 6*y^3, y^3]) + sage: f = DynamicalSystem_projective([-2*x^3 - 9*x^2*y - 12*x*y^2 - 6*y^3, y^3]) sage: f.is_dynamical_belyi_map() True @@ -3993,7 +4022,7 @@ def is_dynamical_belyi_map(self): :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem_projective([x^2 + y^2,y^2]) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2]) sage: f.is_dynamical_belyi_map() False @@ -4024,7 +4053,7 @@ def is_dynamical_belyi_map(self): :: sage: P.<x,y> = ProjectiveSpace(GF(7), 1) - sage: f = DynamicalSystem_projective([x^3 + 6*y^3, y^3]) + sage: f = DynamicalSystem_projective([x^3 + 6*y^3, y^3]) sage: f.is_dynamical_belyi_map() False """ @@ -4060,8 +4089,8 @@ def critical_point_portrait(self, check=True, use_algebraic_closure=True): - ``check`` -- boolean (default: True) - - ``use_algebraic_closure`` -- boolean (default: True) -- If True uses the - algebraic closure. If False, uses the smallest extension of the base field + - ``use_algebraic_closure`` -- boolean (default: ``True``) -- If ``True``, uses the + algebraic closure. If ``False``, uses the smallest extension of the base field containing all the critical points. OUTPUT: a digraph @@ -4071,8 +4100,8 @@ def critical_point_portrait(self, check=True, use_algebraic_closure=True): sage: R.<z> = QQ[] sage: K.<v> = NumberField(z^6 + 2*z^5 + 2*z^4 + 2*z^3 + z^2 + 1) sage: PS.<x,y> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([x^2+v*y^2, y^2]) - sage: f.critical_point_portrait(check=False) # long time + sage: f = DynamicalSystem_projective([x^2 + v*y^2, y^2]) + sage: f.critical_point_portrait(check=False) # long time Looped digraph on 6 vertices :: @@ -4105,7 +4134,7 @@ def critical_point_portrait(self, check=True, use_algebraic_closure=True): sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem_projective([8*x^4 - 8*x^2*y^2 + y^4, y^4]) - sage: f.critical_point_portrait(use_algebraic_closure=False) #long time + sage: f.critical_point_portrait(use_algebraic_closure=False) # long time Looped digraph on 6 vertices :: @@ -4183,8 +4212,8 @@ def critical_height(self, **kwds): - ``error_bound`` -- (optional) a positive real number - - ``use_algebraic_closure`` -- boolean (default: True) -- If True uses the - algebraic closure. If False, uses the smallest extension of the base field + - ``use_algebraic_closure`` -- boolean (default: ``True``) -- If ``True``, uses the + algebraic closure. If ``False``, uses the smallest extension of the base field containing all the critical points. OUTPUT: real number @@ -4192,7 +4221,7 @@ def critical_height(self, **kwds): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^3+7*y^3, 11*y^3]) + sage: f = DynamicalSystem_projective([x^3 + 7*y^3, 11*y^3]) sage: f.critical_height() 1.1989273321156851418802151128 @@ -4200,21 +4229,21 @@ def critical_height(self, **kwds): sage: K.<w> = QuadraticField(2) sage: P.<x,y> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([x^2+w*y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 + w*y^2, y^2]) sage: f.critical_height() 0.16090842452312941163719755472 Postcritically finite maps have critical height 0:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^3-3/4*x*y^2 + 3/4*y^3, y^3]) + sage: f = DynamicalSystem_projective([x^3 - 3/4*x*y^2 + 3/4*y^3, y^3]) sage: f.critical_height(error_bound=0.0001) 0.00000000000000000000000000000 :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^3+3*x*y^2, y^3]) + sage: f = DynamicalSystem_projective([x^3 + 3*x*y^2, y^3]) sage: f.critical_height(use_algebraic_closure=False) 0.000023477016733897112886491967991 sage: f.critical_height() @@ -4369,7 +4398,8 @@ def preperiodic_points(self, m, n, **kwds): sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: X = P.subscheme(2*x - y) - sage: f = DynamicalSystem_projective([x^2 - y^2, 2*(x^2 - y^2), y^2 - z^2], domain=X) + sage: f = DynamicalSystem_projective([x^2 - y^2, 2*(x^2 - y^2), y^2 - z^2], + ....: domain=X) sage: f.preperiodic_points(1, 1) [(-1/4 : -1/2 : 1), (1 : 2 : 1)] @@ -4395,7 +4425,8 @@ def preperiodic_points(self, m, n, **kwds): sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2) sage: f = DynamicalSystem_projective([x^2, x*y, z^2]) sage: f.preperiodic_points(2, 1, return_scheme=True, minimal=False) - Closed subscheme of Projective Space of dimension 2 over Finite Field of size 5 defined by: + Closed subscheme of + Projective Space of dimension 2 over Finite Field of size 5 defined by: 0, x^8*z^4 - x^4*z^8, x^7*y*z^4 - x^3*y*z^8 @@ -4426,7 +4457,7 @@ def preperiodic_points(self, m, n, **kwds): sage: f = DynamicalSystem_projective([x^2 + c*y^2, y^2]) sage: f.preperiodic_points(1, 2, return_scheme=True) Closed subscheme of Projective Space of dimension 1 over Univariate - Polynomial Ring in c over Rational Field defined by: + Polynomial Ring in c over Rational Field defined by: x^2 - x*y + (c + 1)*y^2 TESTS:: @@ -4454,7 +4485,7 @@ def preperiodic_points(self, m, n, **kwds): :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: f=DynamicalSystem([x^2 - z^2, y^2 - 21/16*z^2, z^2]) + sage: f = DynamicalSystem([x^2 - z^2, y^2 - 21/16*z^2, z^2]) sage: len(f.preperiodic_points(1, 2, minimal=True, formal=False)) == 16 True @@ -4465,7 +4496,8 @@ def preperiodic_points(self, m, n, **kwds): sage: f.preperiodic_points(2, 2) Traceback (most recent call last): ... - ValueError: dynamical system is not a morphism, cannot calculate minimal or formal preperiodic points + ValueError: dynamical system is not a morphism, + cannot calculate minimal or formal preperiodic points """ n = ZZ(n) m = ZZ(m) @@ -4513,7 +4545,7 @@ def preperiodic_points(self, m, n, **kwds): # we now deform by a parameter t T = R['t'] t = T.gens()[0] - Pt = ProjectiveSpace(N-1, R=T, names = [str(i) for i in CR.gens()]) + Pt = ProjectiveSpace(N-1, R=T, names=[str(i) for i in CR.gens()]) deformed_polys = [poly + t*Pt.gens()[-1]**d for poly in new_f.defining_polynomials()[:-1]] deformed_polys += [new_f.defining_polynomials()[-1]] f_deformed = DynamicalSystem(deformed_polys) @@ -4751,7 +4783,8 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari sage: K.<u> = NumberField(x^2 - x + 3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: X = P.subscheme(2*x - y) - sage: f = DynamicalSystem_projective([x^2 - y^2, 2*(x^2 - y^2), y^2 - z^2], domain=X) + sage: f = DynamicalSystem_projective([x^2 - y^2, 2*(x^2 - y^2), y^2 - z^2], + ....: domain=X) sage: f.periodic_points(2) [(-1/5*u - 1/5 : -2/5*u - 2/5 : 1), (1/5*u - 2/5 : 2/5*u - 4/5 : 1)] @@ -4790,8 +4823,8 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: f = DynamicalSystem([x^2 - 2*y^2, y^2, z^2]) - sage: X = f.periodic_points(2, minimal=False, formal=True, return_scheme=True) - sage: len(X.defining_polynomials()) + sage: X = f.periodic_points(2, minimal=False, formal=True, return_scheme=True) # long time + sage: len(X.defining_polynomials()) # long time 19 TESTS:: @@ -4863,7 +4896,7 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari # we now deform by a parameter t T = R['t'] t = T.gens()[0] - Pt = ProjectiveSpace(N-1, R=T, names = [str(i) for i in CR.gens()]) + Pt = ProjectiveSpace(N-1, R=T, names=[str(i) for i in CR.gens()]) deformed_polys = [poly + t*Pt.gens()[-1]**d for poly in new_f.defining_polynomials()[:-1]] deformed_polys += [new_f.defining_polynomials()[-1]] f_deformed = DynamicalSystem(deformed_polys) @@ -5002,7 +5035,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([x^2, z^2, y^2]) - sage: f.multiplier_spectra(2, formal=True) + sage: f.multiplier_spectra(2, formal=True) # long time [ [4 0] [4 0] [4 0] [4 0] [4 0] [4 0] [4 0] [4 0] [0 0] [0 0] [0 4], [0 0], [0 0], [0 4], [0 4], [0 0], [0 0], [0 4], [0 0], [0 0], @@ -5026,21 +5059,23 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem_projective([4608*x^10 - 2910096*x^9*y + 325988068*x^8*y^2 + 31825198932*x^7*y^3 - 4139806626613*x^6*y^4\ - - 44439736715486*x^5*y^5 + 2317935971590902*x^4*y^6 - 15344764859590852*x^3*y^7 + 2561851642765275*x^2*y^8\ - + 113578270285012470*x*y^9 - 150049940203963800*y^10, 4608*y^10]) + sage: f = DynamicalSystem_projective([4608*x^10 - 2910096*x^9*y + 325988068*x^8*y^2 + ....: + 31825198932*x^7*y^3 - 4139806626613*x^6*y^4 - 44439736715486*x^5*y^5 + ....: + 2317935971590902*x^4*y^6 - 15344764859590852*x^3*y^7 + ....: + 2561851642765275*x^2*y^8 + 113578270285012470*x*y^9 + ....: - 150049940203963800*y^10, 4608*y^10]) sage: sorted(f.multiplier_spectra(1)) [-119820502365680843999, - -7198147681176255644585/256, - -3086380435599991/9, - -3323781962860268721722583135/35184372088832, - -4290991994944936653/2097152, - 0, - 529278480109921/256, - 1061953534167447403/19683, - 848446157556848459363/19683, - 82911372672808161930567/8192, - 3553497751559301575157261317/8192] + -7198147681176255644585/256, + -3086380435599991/9, + -3323781962860268721722583135/35184372088832, + -4290991994944936653/2097152, + 0, + 529278480109921/256, + 1061953534167447403/19683, + 848446157556848459363/19683, + 82911372672808161930567/8192, + 3553497751559301575157261317/8192] :: @@ -5128,7 +5163,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([x^2, z^2, y^2]) sage: g = f.change_ring(QQbar) - sage: f.multiplier_spectra(1) == g.multiplier_spectra(1) + sage: f.multiplier_spectra(1) == g.multiplier_spectra(1) # long time True :: @@ -5136,7 +5171,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur sage: K.<w> = QuadraticField(5) sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: f = DynamicalSystem_projective([x^2 + w*x*y + y^2, y^2, z^2]) - sage: f.multiplier_spectra(1) + sage: f.multiplier_spectra(1) # long time [ [1.000000000000000? - 1.572302755514847?*I 0] [1.000000000000000? - 1.572302755514847?*I 0.618033988749895? - 1.757887921270715?*I] @@ -5488,9 +5523,10 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([x^2, z^2, y^2]) sage: f.sigma_invariants(1, chow=True) - [1, 7, -6, -12, 21, -36, -60, 72, 48, 35, -90, -120, 352, 96, -288, -64, 35, -120, -120, 688, -96, - -1056, 320, 384, 0, 21, -90, -60, 672, -384, -1440, 1344, 768, -768, 0, 0, 7, -36, -12, 328, -336, - -864, 1472, 384, -1536, 512, 0, 0, 0, 1, -6, 0, 64, -96, -192, 512, 0, -768, 512, 0, 0, 0, 0, 0] + [1, 7, -6, -12, 21, -36, -60, 72, 48, 35, -90, -120, 352, 96, -288, -64, 35, + -120, -120, 688, -96, -1056, 320, 384, 0, 21, -90, -60, 672, -384, -1440, 1344, + 768, -768, 0, 0, 7, -36, -12, 328, -336, -864, 1472, 384, -1536, 512, 0, 0, 0, + 1, -6, 0, 64, -96, -192, 512, 0, -768, 512, 0, 0, 0, 0, 0] When calculating the sigma invariants for `\mathbb{P}^N`, with `N > 1`, the default algorithm loses information about multiplicities. Note that @@ -5554,13 +5590,13 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem_projective([512*x^5 - 378128*x^4*y + 76594292*x^3*y^2 - 4570550136*x^2*y^3 - 2630045017*x*y^4\ - + 28193217129*y^5, 512*y^5]) + sage: f = DynamicalSystem_projective([512*x^5 - 378128*x^4*y + 76594292*x^3*y^2 + ....: - 4570550136*x^2*y^3 - 2630045017*x*y^4 + 28193217129*y^5, 512*y^5]) sage: f.sigma_invariants(1) [19575526074450617/1048576, -9078122048145044298567432325/2147483648, - -2622661114909099878224381377917540931367/1099511627776, - -2622661107937102104196133701280271632423/549755813888, - 338523204830161116503153209450763500631714178825448006778305/72057594037927936, 0] + -2622661114909099878224381377917540931367/1099511627776, + -2622661107937102104196133701280271632423/549755813888, + 338523204830161116503153209450763500631714178825448006778305/72057594037927936, 0] :: @@ -5688,7 +5724,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', # we now deform by a parameter t T = base_ring['k'] k = T.gens()[0] - Pt = ProjectiveSpace(N, R=T, names = [str(i) for i in CR.gens()]) + Pt = ProjectiveSpace(N, R=T, names=[str(i) for i in CR.gens()]) deformed_polys = [poly + k*Pt.gens()[-1]**d for poly in new_f.defining_polynomials()[:-1]] deformed_polys += [new_f.defining_polynomials()[-1]] f_deformed = DynamicalSystem(deformed_polys) @@ -5973,15 +6009,15 @@ def reduced_form(self, **kwds): sage: f = DynamicalSystem_projective([x^3 + x*y^2, y^3]) sage: m = matrix(QQ, 2, 2, [-201221, -1, 1, 0]) sage: f = f.conjugate(m) - sage: f.reduced_form(prec=50, smallest_coeffs=False) #needs 2 periodic + sage: f.reduced_form(prec=50, smallest_coeffs=False) # this needs 2 periodic Traceback (most recent call last): ... - ValueError: accuracy of Newton's root not within tolerance(0.000066... > 1e-06), increase precision + ValueError: accuracy of Newton's root not within tolerance(0.000066... > 1e-06), + increase precision sage: f.reduced_form(smallest_coeffs=False) ( Dynamical System of Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (x^3 + x*y^2 : y^3) + Defn: Defined on coordinates by sending (x : y) to (x^3 + x*y^2 : y^3) , <BLANKLINE> [ 0 -1] @@ -5991,14 +6027,13 @@ def reduced_form(self, **kwds): :: sage: PS.<x,y> = ProjectiveSpace(ZZ, 1) - sage: f = DynamicalSystem_projective([x^2+ x*y, y^2]) #needs 3 periodic + sage: f = DynamicalSystem_projective([x^2 + x*y, y^2]) # this needs 3 periodic sage: m = matrix(QQ, 2, 2, [-221, -1, 1, 0]) sage: f = f.conjugate(m) sage: f.reduced_form(prec=200, smallest_coeffs=False) ( Dynamical System of Projective Space of dimension 1 over Integer Ring - Defn: Defined on coordinates by sending (x : y) to - (-x^2 + x*y - y^2 : -y^2) + Defn: Defined on coordinates by sending (x : y) to (-x^2 + x*y - y^2 : -y^2) , [ 0 -1] [ 1 220] @@ -6011,8 +6046,7 @@ def reduced_form(self, **kwds): sage: f.reduced_form(smallest_coeffs=False) ( Dynamical System of Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (x^3 : y^3) + Defn: Defined on coordinates by sending (x : y) to (x^3 : y^3) , <BLANKLINE> [1 0] @@ -6022,8 +6056,10 @@ def reduced_form(self, **kwds): :: sage: PS.<X,Y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([7365*X^4 + 12564*X^3*Y + 8046*X^2*Y^2 + 2292*X*Y^3 + 245*Y^4,\ - -12329*X^4 - 21012*X^3*Y - 13446*X^2*Y^2 - 3828*X*Y^3 - 409*Y^4]) + sage: f = DynamicalSystem_projective([7365*X^4 + 12564*X^3*Y + 8046*X^2*Y^2 + ....: + 2292*X*Y^3 + 245*Y^4, + ....: -12329*X^4 - 21012*X^3*Y - 13446*X^2*Y^2 + ....: - 3828*X*Y^3 - 409*Y^4]) sage: f.reduced_form(prec=30, smallest_coeffs=False) Traceback (most recent call last): ... @@ -6032,7 +6068,8 @@ def reduced_form(self, **kwds): ( Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (X : Y) to - (-7*X^4 - 12*X^3*Y - 42*X^2*Y^2 - 12*X*Y^3 - 7*Y^4 : -X^4 - 4*X^3*Y - 6*X^2*Y^2 - 4*X*Y^3 - Y^4), + (-7*X^4 - 12*X^3*Y - 42*X^2*Y^2 - 12*X*Y^3 - 7*Y^4 + : -X^4 - 4*X^3*Y - 6*X^2*Y^2 - 4*X*Y^3 - Y^4), <BLANKLINE> [-1 2] [ 2 -5] @@ -6067,9 +6104,9 @@ def reduced_form(self, **kwds): sage: f = f.conjugate(m) sage: f.reduced_form(smallest_coeffs=False) ( - Dynamical System of Projective Space of dimension 1 over Number Field in w with defining polynomial x^2 - 2 with w = 1.414213562373095? - Defn: Defined on coordinates by sending (x : y) to - (x^3 : w*y^3) , + Dynamical System of Projective Space of dimension 1 over Number Field in w + with defining polynomial x^2 - 2 with w = 1.414213562373095? + Defn: Defined on coordinates by sending (x : y) to (x^3 : w*y^3) , <BLANKLINE> [ 1 -12] [ 0 1] @@ -6078,16 +6115,18 @@ def reduced_form(self, **kwds): :: sage: R.<x> = QQ[] - sage: K.<w> = NumberField(x^5+x-3, embedding=(x^5+x-3).roots(ring=CC)[0][0]) + sage: K.<w> = NumberField(x^5 + x - 3, + ....: embedding=(x^5 + x - 3).roots(ring=CC)[0][0]) sage: P.<x,y> = ProjectiveSpace(K, 1) sage: f = DynamicalSystem_projective([12*x^3, 2334*w*y^3]) sage: m = matrix(K, 2, 2, [-12,1,1,0]) sage: f = f.conjugate(m) sage: f.reduced_form(smallest_coeffs=False) ( - Dynamical System of Projective Space of dimension 1 over Number Field in w with defining polynomial x^5 + x - 3 with w = 1.132997565885066? + Dynamical System of Projective Space of dimension 1 over Number Field in w + with defining polynomial x^5 + x - 3 with w = 1.132997565885066? Defn: Defined on coordinates by sending (x : y) to - (12*x^3 : (2334*w)*y^3) , + (12*x^3 : (2334*w)*y^3) , <BLANKLINE> [ 0 -1] [ 1 -12] @@ -6142,7 +6181,7 @@ def reduced_form(self, **kwds): sage: P.<x,y> = QQ[] sage: f = DynamicalSystem([4*x^2 + y^2, 4*y^2]) - sage: f.reduced_form() #long time + sage: f.reduced_form() # long time ( Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to @@ -6222,10 +6261,6 @@ def _is_preperiodic(self, P, err=0.1, return_period=False): Determine if the point is preperiodic with respect to this dynamical system. - .. NOTE:: - - This is only implemented for projective space (not subschemes). - ALGORITHM: We know that a point is preperiodic if and only if it has @@ -6266,7 +6301,7 @@ def _is_preperiodic(self, P, err=0.1, return_period=False): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^3-3*x*y^2, y^3], domain=P) + sage: f = DynamicalSystem_projective([x^3 - 3*x*y^2, y^3], domain=P) sage: Q = P(-1, 1) sage: f._is_preperiodic(Q) True @@ -6276,19 +6311,60 @@ def _is_preperiodic(self, P, err=0.1, return_period=False): sage: R.<X> = PolynomialRing(QQ) sage: K.<a> = NumberField(X^2 + X - 1) sage: P.<x,y> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([x^2-2*y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - 2*y^2, y^2]) sage: Q = P.point([a,1]) sage: Q.is_preperiodic(f) True + + :: + + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: X = P.subscheme(z) + sage: f = DynamicalSystem([x^2 - y^2, y^2, z^2], domain=X) + sage: p = X((-1, 1, 0)) + sage: f._is_preperiodic(p, return_period=True) + (0, 2) + + :: + + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: X = P.subscheme(x) + sage: f = DynamicalSystem([x^2 - y^2, y^2, z^2], domain=X) + sage: p = X((0, 1, 0)) + sage: f._is_preperiodic(p, return_period=True) + Traceback (most recent call last): + ... + ValueError: orbit of point leaves domain + + :: + + sage: R.<t> = QQ[] + sage: K.<a> = NumberField(t^2 - t - 1) + sage: P.<x,y,z> = ProjectiveSpace(K, 2) + sage: X = P.subscheme(z) + sage: f = DynamicalSystem([x^2 - y^2, y^2, z^2], domain=X) + sage: p = X((-a + 1, 1, 0)) + sage: f._is_preperiodic(p) + True """ - if not is_ProjectiveSpace(self.codomain()): - raise NotImplementedError("must be over projective space") - if not self.is_morphism(): - raise TypeError("must be a morphism") + codomain = self.codomain() + if not is_ProjectiveSpace(codomain): + # in order to calculate the canonical height, we need + # this map to be a morphism of projective space + ambient_space = codomain.ambient_space() + f = DynamicalSystem(self.defining_polynomials(), domain=ambient_space) + if not f.is_morphism(): + raise ValueError('must be a morphism of projective space') + else: + f = self + if not f.is_morphism(): + raise TypeError("must be a morphism") if not P.codomain() == self.domain(): raise TypeError("point must be in domain of map") - h = self.canonical_height(P, error_bound = err) + # we calculate the canonical height without considering + # if the domain is a subscheme + h = f.canonical_height(P, error_bound=err) # we know canonical height 0 if and only if preperiodic # however precision issues can occur so we can only tell *not* preperiodic # if the value is larger than the error @@ -6298,14 +6374,20 @@ def _is_preperiodic(self, P, err=0.1, return_period=False): # either we can find the cycle or the height is # larger than the difference between the canonical height # and the height, so the canonical height cannot be 0 - B = self.height_difference_bound() + B = f.height_difference_bound() orbit = [P] n = 1 # to compute period - Q = self(P) + try: + Q = self(P) + except TypeError: + raise ValueError('orbit of point leaves domain') H = Q.global_height() while Q not in orbit and H <= B: orbit.append(Q) - Q = self(Q) + try: + Q = self(Q) + except TypeError: + raise ValueError('orbit of point leaves domain') H = Q.global_height() n += 1 if H <= B: #it must have been in the cycle @@ -6401,6 +6483,309 @@ def postcritical_set(self, check=True): next_point = f(next_point) return post_critical_list + def is_chebyshev(self): + r""" + Check if ``self`` is a Chebyshev polynomial. + + OUTPUT: True if ``self`` is Chebyshev, False otherwise. + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: F = DynamicalSystem_projective([x^4, y^4]) + sage: F.is_chebyshev() + False + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: F = DynamicalSystem_projective([x^2 + y^2, y^2]) + sage: F.is_chebyshev() + False + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: F = DynamicalSystem_projective([2*x^2 - y^2, y^2]) + sage: F.is_chebyshev() + True + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: F = DynamicalSystem_projective([x^3, 4*y^3 - 3*x^2*y]) + sage: F.is_chebyshev() + True + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: F = DynamicalSystem_projective([2*x^2 - y^2, y^2]) + sage: L.<i> = CyclotomicField(4) + sage: M = Matrix([[0,i],[-i,0]]) + sage: F.conjugate(M) + Dynamical System of Projective Space of dimension 1 over Cyclotomic Field of order 4 and degree 2 + Defn: Defined on coordinates by sending (x : y) to + ((-i)*x^2 : (-i)*x^2 + (2*i)*y^2) + sage: F.is_chebyshev() + True + + REFERENCES: + + - [Mil2006]_ + """ + # We need `F` to be defined over a number field for + # the function `is_postcrtically_finite` to work + if self.base_ring() not in NumberFields(): + raise NotImplementedError("Base ring must be a number field") + + if self.domain().dimension() != 1: + return False + + # All Chebyshev polynomials are postcritically finite + if not self.is_postcritically_finite(): + return False + + # Get field of definition for critical points and change base field + critical_field, phi = self.field_of_definition_critical(return_embedding=True) + F_crit = self.change_ring(phi) + + # Get the critical points and post-critical set + crit_set = set(F_crit.critical_points()) + post_crit_set = set() + images_needed = copy(crit_set) + while len(images_needed) != 0: + Q = images_needed.pop() + Q2 = F_crit(Q) + if Q2 not in post_crit_set: + post_crit_set.add(Q2) + images_needed.add(Q2) + + crit_fixed_pts = set() + for crit in crit_set: + if F_crit.nth_iterate(crit, 1) == crit: + crit_fixed_pts.add(crit) + + # All Chebyshev maps have 3 post-critical values + if (len(post_crit_set) != 3) or (len(crit_fixed_pts) != 1): + return False + + f = F_crit.dehomogenize(1)[0] + x = f.parent().gen() + ram_points = {} + for crit in crit_set: + g = f + new_crit = crit + + # Check if critical point is infinity + if crit[1] == 0: + g = g.subs(x=1/x) + new_crit = F_crit.domain()([0, 1]) + + # Check if output is infinity + if F_crit.nth_iterate(crit, 1)[1] == 0: + g = 1/g + + new_crit = new_crit.dehomogenize(1)[0] + e = 1 + g = g.derivative(x) + + while g(new_crit) == 0: + e += 1 + g = g.derivative(x) + + ram_points[crit] = e + + r = {} + + # Set r value to 0 to represent infinity + r[crit_fixed_pts.pop()] = 0 + + # Get non-fixed tail points in the post-critical portrait + crit_tails = crit_set.difference(post_crit_set) + for crit in crit_tails: + # Each critical tail point has r value 1 + r[crit] = 1 + point = crit + + # Assign r values to every point in the orbit of crit. + # If we find a point in the orbit which already has an r value assigned, + # check that we get a consistent r value. + while F_crit.nth_iterate(point, 1) not in r.keys(): + if point not in ram_points.keys(): + r[F_crit.nth_iterate(point,1)] = r[point] + else: + r[F_crit.nth_iterate(point,1)] = r[point] * ram_points[point] + + point = F_crit.nth_iterate(point,1) + + # Once we get here, the image of point has an assigned r value + # We check that this value is consistent + if point not in ram_points.keys(): + if r[F_crit.nth_iterate(point,1)] != r[point]: + return False + elif r[F_crit.nth_iterate(point,1)] != r[point] * ram_points[point]: + return False + + # The non-one r values must be one of the following in order for F to be Chebyshev + r_vals = sorted([val for val in r.values() if val != 1]) + return r_vals == [0, 2, 2] + + def is_Lattes(self): + r""" + Check if ``self`` is a Lattes map + + OUTPUT: True if ``self`` is Lattes, False otherwise + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: F = DynamicalSystem_projective([x^3, y^3]) + sage: F.is_Lattes() + False + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: F = DynamicalSystem_projective([x^2 - 2*y^2, y^2]) + sage: F.is_Lattes() + False + + :: + + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: F = DynamicalSystem_projective([x^2 + y^2 + z^2, y^2, z^2]) + sage: F.is_Lattes() + False + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: F = DynamicalSystem_projective([(x + y)*(x - y)^3, y*(2*x + y)^3]) + sage: F.is_Lattes() + True + + :: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: F = DynamicalSystem_projective([(x + y)^4, 16*x*y*(x - y)^2]) + sage: F.is_Lattes() + True + + :: + + sage: f = P.Lattes_map(EllipticCurve([0, 0, 0, 0, 2]),2) + sage: f.is_Lattes() + True + + :: + + sage: f = P.Lattes_map(EllipticCurve([0, 0, 0, 0, 2]), 2) + sage: L.<i> = CyclotomicField(4) + sage: M = Matrix([[i, 0], [0, -i]]) + sage: f.conjugate(M) + Dynamical System of Projective Space of dimension 1 over Cyclotomic Field of order 4 and degree 2 + Defn: Defined on coordinates by sending (x : y) to + ((-1/4*i)*x^4 + (-4*i)*x*y^3 : (-i)*x^3*y + (2*i)*y^4) + sage: f.is_Lattes() + True + + REFERENCES: + + - [Mil2006]_ + """ + # We need `f` to be defined over a number field for + # the function `is_postcrtically_finite` to work + if self.base_ring() not in NumberFields(): + raise NotImplementedError("Base ring must be a number field") + + if self.domain().dimension() != 1: + return False + + # All Lattes maps are postcritically finite + if not self.is_postcritically_finite(): + return False + + # Get field of definition for critical points and change basefield + critical_field, phi = self.field_of_definition_critical(return_embedding=True) + F_crit = self.change_ring(phi) + + # Get the critical points and post-critical set + crit = F_crit.critical_points() + post_crit = set() + images_needed = copy(crit) + while len(images_needed) != 0: + Q = images_needed.pop() + Q2 = F_crit(Q) + if Q2 not in post_crit: + post_crit.add(Q2) + images_needed.append(Q2) + + (crit_set, post_crit_set) = crit, list(post_crit) + + # All Lattes maps have 3 or 4 post critical values + if not len(post_crit_set) in [3, 4]: + return False + + f = F_crit.dehomogenize(1)[0] + x = f.parent().gen() + ram_points = {} + for crit in crit_set: + g = f + new_crit = crit + + # Check if critical point is infinity + if crit[1] == 0: + g = g.subs(x=1/x) + new_crit = F_crit.domain()([0, 1]) + + # Check if output is infinity + if F_crit.nth_iterate(crit, 1)[1] == 0: + g = 1/g + + new_crit = new_crit.dehomogenize(1)[0] + + e = 1 + g = g.derivative(x) + while g(new_crit) == 0: + e += 1 + g = g.derivative(x) + ram_points[crit] = e + + r = {} + + # Get tail points in the post-critical portrait + crit_tails = set(crit_set).difference(set(post_crit_set)) + for crit in crit_tails: + # Each critical tail point has r value 1 + r[crit] = 1 + point = crit + + # Assign r values to every point in the orbit of crit + # If we find a point in the orbit which already has an r value assigned, + # check that we get a consistent r value + while F_crit.nth_iterate(point, 1) not in r.keys(): + if point not in ram_points.keys(): + r[F_crit.nth_iterate(point, 1)] = r[point] + else: + r[F_crit.nth_iterate(point, 1)] = r[point] * ram_points[point] + + point = F_crit.nth_iterate(point,1) + + # Once we get here the image of point has an assigned r value + # We check that this value is consistent. + if point not in ram_points.keys(): + if r[F_crit.nth_iterate(point, 1)] != r[point]: + return False + else: + if r[F_crit.nth_iterate(point, 1)] != r[point] * ram_points[point]: + return False + + # The non-one r values must be one of the following in order for F to be Lattes + r_lattes_cases = [[2, 2, 2, 2], [3, 3, 3], [2, 4, 4], [2, 3, 6]] + r_vals = sorted([val for val in r.values() if val != 1]) + return r_vals in r_lattes_cases + class DynamicalSystem_projective_field(DynamicalSystem_projective, SchemeMorphism_polynomial_projective_space_field): @@ -6445,7 +6830,7 @@ def lift_to_rational_periodic(self, points_modp, B=None): There may be multiple points in the lift. sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem_projective([-5*x^2 + 4*y^2, 4*x*y]) - sage: f.lift_to_rational_periodic([[P(1,0).change_ring(GF(3)), 1]]) # long time + sage: f.lift_to_rational_periodic([[P(1,0).change_ring(GF(3)), 1]]) # long time [[(1 : 0), 1], [(2/3 : 1), 1], [(-2/3 : 1), 1]] :: @@ -6458,8 +6843,11 @@ def lift_to_rational_periodic(self, points_modp, B=None): :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: f = DynamicalSystem_projective([76*x^2 - 180*x*y + 45*y^2 + 14*x*z + 45*y*z - 90*z^2, 67*x^2 - 180*x*y - 157*x*z + 90*y*z, -90*z^2]) - sage: f.lift_to_rational_periodic([[P(14,19,1).change_ring(GF(23)), 9]]) # long time + sage: f = DynamicalSystem_projective([76*x^2 - 180*x*y + 45*y^2 + ....: + 14*x*z + 45*y*z - 90*z^2, + ....: 67*x^2 - 180*x*y - 157*x*z + 90*y*z, + ....: -90*z^2]) + sage: f.lift_to_rational_periodic([[P(14,19,1).change_ring(GF(23)), 9]]) # long time [[(-9 : -4 : 1), 9]] """ if not points_modp: @@ -6672,8 +7060,8 @@ def all_periodic_points(self, **kwds): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2-3/4*y^2, y^2]) - sage: sorted(f.all_periodic_points(prime_bound=20, lifting_prime=7)) # long time + sage: f = DynamicalSystem_projective([x^2 - 3/4*y^2, y^2]) + sage: sorted(f.all_periodic_points(prime_bound=20, lifting_prime=7)) # long time [(-1/2 : 1), (1 : 0), (3/2 : 1)] :: @@ -6692,28 +7080,29 @@ def all_periodic_points(self, **kwds): sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem_projective([-5*x^2 + 4*y^2, 4*x*y]) - sage: sorted(f.all_periodic_points()) # long time + sage: sorted(f.all_periodic_points()) # long time [(-2 : 1), (-2/3 : 1), (2/3 : 1), (1 : 0), (2 : 1)] :: sage: R.<x> = QQ[] - sage: K.<w> = NumberField(x^2-x+1) + sage: K.<w> = NumberField(x^2 - x + 1) sage: P.<u,v> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([u^2 + v^2,v^2]) + sage: f = DynamicalSystem_projective([u^2 + v^2, v^2]) sage: sorted(f.all_periodic_points()) [(-w + 1 : 1), (w : 1), (1 : 0)] :: sage: R.<x> = QQ[] - sage: K.<w> = NumberField(x^2-x+1) + sage: K.<w> = NumberField(x^2 - x + 1) sage: P.<u,v> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([u^2+v^2,u*v]) + sage: f = DynamicalSystem_projective([u^2 + v^2, u*v]) sage: f.all_periodic_points() Traceback (most recent call last): ... - NotImplementedError: rational periodic points for number fields only implemented for polynomials + NotImplementedError: rational periodic points for number fields + only implemented for polynomials :: @@ -6727,7 +7116,8 @@ def all_periodic_points(self, **kwds): :: sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) - sage: f = DynamicalSystem_projective([x^2 - (3/4)*w^2, y^2 - 3/4*w^2, z^2 - 3/4*w^2, w^2]) + sage: f = DynamicalSystem_projective([x^2 - (3/4)*w^2, y^2 - 3/4*w^2, + ....: z^2 - 3/4*w^2, w^2]) sage: sorted(f.all_periodic_points(algorithm="dynatomic")) [(-1/2 : -1/2 : -1/2 : 1), (-1/2 : -1/2 : 3/2 : 1), @@ -6755,7 +7145,7 @@ def all_periodic_points(self, **kwds): TESTS:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem([x^2+ y^2, x*y]) + sage: f = DynamicalSystem([x^2 + y^2, x*y]) sage: f.all_periodic_points(algorithm="banana") Traceback (most recent call last): ... @@ -6885,7 +7275,7 @@ def all_rational_preimages(self, points): In others words, all the rational points which have some iterate in the set points. This function repeatedly calls - ``rational_preimages``. If the degree is at least two, + :meth:`rational_preimages`. If the degree is at least two, by Northocott, this is always a finite set. The map must be defined over number fields and be an endomorphism. @@ -6901,12 +7291,15 @@ def all_rational_preimages(self, points): sage: f = DynamicalSystem_projective([16*x^2 - 29*y^2, 16*y^2]) sage: sorted(f.all_rational_preimages([P(-1,4)])) [(-7/4 : 1), (-5/4 : 1), (-3/4 : 1), (-1/4 : 1), (1/4 : 1), (3/4 : 1), - (5/4 : 1), (7/4 : 1)] + (5/4 : 1), (7/4 : 1)] :: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: f = DynamicalSystem_projective([76*x^2 - 180*x*y + 45*y^2 + 14*x*z + 45*y*z - 90*z^2, 67*x^2 - 180*x*y - 157*x*z + 90*y*z, -90*z^2]) + sage: f = DynamicalSystem_projective([76*x^2 - 180*x*y + 45*y^2 + 14*x*z + ....: + 45*y*z - 90*z^2, + ....: 67*x^2 - 180*x*y - 157*x*z + 90*y*z, + ....: -90*z^2]) sage: sorted(f.all_rational_preimages([P(-9,-4,1)])) [(-9 : -4 : 1), (0 : -1 : 1), (0 : 0 : 1), (0 : 1 : 1), (0 : 4 : 1), (1 : 0 : 1), (1 : 1 : 1), (1 : 2 : 1), (1 : 3 : 1)] @@ -6921,10 +7314,10 @@ def all_rational_preimages(self, points): A number field example:: sage: z = QQ['z'].0 - sage: K.<w> = NumberField(z^3 + (z^2)/4 - (41/16)*z + 23/64); + sage: K.<w> = NumberField(z^3 + (z^2)/4 - (41/16)*z + 23/64) sage: P.<x,y> = ProjectiveSpace(K,1) sage: f = DynamicalSystem_projective([16*x^2 - 29*y^2, 16*y^2]) - sage: sorted(f.all_rational_preimages([P(16*w^2 - 29,16)]), key=str) + sage: sorted(f.all_rational_preimages([P(16*w^2 - 29, 16)]), key=str) [(-w - 1/2 : 1), (-w : 1), (-w^2 + 21/16 : 1), @@ -6942,7 +7335,7 @@ def all_rational_preimages(self, points): sage: K.<w> = QuadraticField(3) sage: P.<u,v> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([u^2+v^2, v^2]) + sage: f = DynamicalSystem_projective([u^2 + v^2, v^2]) sage: f.all_rational_preimages(P(4)) [(-w : 1), (w : 1)] """ @@ -7021,10 +7414,9 @@ def all_preperiodic_points(self, **kwds): EXAMPLES:: sage: PS.<x,y> = ProjectiveSpace(1,QQ) - sage: f = DynamicalSystem_projective([x^2 -y^2, 3*x*y]) + sage: f = DynamicalSystem_projective([x^2 - y^2, 3*x*y]) sage: sorted(f.all_preperiodic_points()) - [(-2 : 1), (-1 : 1), (-1/2 : 1), (0 : 1), (1/2 : 1), (1 : 0), (1 : 1), - (2 : 1)] + [(-2 : 1), (-1 : 1), (-1/2 : 1), (0 : 1), (1/2 : 1), (1 : 0), (1 : 1), (2 : 1)] :: @@ -7036,20 +7428,20 @@ def all_preperiodic_points(self, **kwds): :: sage: PS.<x,y,z> = ProjectiveSpace(2,QQ) - sage: f = DynamicalSystem_projective([x^2 - 21/16*z^2, y^2-2*z^2, z^2]) - sage: sorted(f.all_preperiodic_points(prime_bound=[1,8], lifting_prime=7, periods=[2])) # long time - [(-5/4 : -2 : 1), (-5/4 : -1 : 1), (-5/4 : 0 : 1), (-5/4 : 1 : 1), (-5/4 - : 2 : 1), (-1/4 : -2 : 1), (-1/4 : -1 : 1), (-1/4 : 0 : 1), (-1/4 : 1 : - 1), (-1/4 : 2 : 1), (1/4 : -2 : 1), (1/4 : -1 : 1), (1/4 : 0 : 1), (1/4 - : 1 : 1), (1/4 : 2 : 1), (5/4 : -2 : 1), (5/4 : -1 : 1), (5/4 : 0 : 1), - (5/4 : 1 : 1), (5/4 : 2 : 1)] + sage: f = DynamicalSystem_projective([x^2 - 21/16*z^2, y^2 - 2*z^2, z^2]) + sage: sorted(f.all_preperiodic_points(prime_bound=[1,8], # long time + ....: lifting_prime=7, periods=[2])) + [(-5/4 : -2 : 1), (-5/4 : -1 : 1), (-5/4 : 0 : 1), (-5/4 : 1 : 1), (-5/4 : 2 : 1), + (-1/4 : -2 : 1), (-1/4 : -1 : 1), (-1/4 : 0 : 1), (-1/4 : 1 : 1), (-1/4 : 2 : 1), + (1/4 : -2 : 1), (1/4 : -1 : 1), (1/4 : 0 : 1), (1/4 : 1 : 1), (1/4 : 2 : 1), + (5/4 : -2 : 1), (5/4 : -1 : 1), (5/4 : 0 : 1), (5/4 : 1 : 1), (5/4 : 2 : 1)] :: sage: K.<w> = QuadraticField(33) sage: PS.<x,y> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([x^2-71/48*y^2, y^2]) - sage: sorted(f.all_preperiodic_points()) # long time + sage: f = DynamicalSystem_projective([x^2 - 71/48*y^2, y^2]) + sage: sorted(f.all_preperiodic_points()) # long time [(-1/12*w - 1 : 1), (-1/6*w - 1/4 : 1), (-1/12*w - 1/2 : 1), @@ -7190,7 +7582,7 @@ def rational_preperiodic_graph(self, **kwds): :: sage: PS.<x,y> = ProjectiveSpace(1,QQ) - sage: f = DynamicalSystem_projective([-3/2*x^3 +19/6*x*y^2, y^3]) + sage: f = DynamicalSystem_projective([-3/2*x^3 + 19/6*x*y^2, y^3]) sage: f.rational_preperiodic_graph(prime_bound=[1,8]) Looped digraph on 12 vertices @@ -7199,15 +7591,16 @@ def rational_preperiodic_graph(self, **kwds): sage: PS.<x,y,z> = ProjectiveSpace(2,QQ) sage: f = DynamicalSystem_projective([2*x^3 - 50*x*z^2 + 24*z^3, ....: 5*y^3 - 53*y*z^2 + 24*z^3, 24*z^3]) - sage: f.rational_preperiodic_graph(prime_bound=[1,11], lifting_prime=13) # long time + sage: f.rational_preperiodic_graph(prime_bound=[1,11], # long time + ....: lifting_prime=13) Looped digraph on 30 vertices :: sage: K.<w> = QuadraticField(-3) sage: P.<x,y> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([x^2+y^2, y^2]) - sage: f.rational_preperiodic_graph() # long time + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2]) + sage: f.rational_preperiodic_graph() # long time Looped digraph on 5 vertices """ #input checking done in .rational_preperiodic_points() @@ -7237,7 +7630,7 @@ def connected_rational_component(self, P, n=0): EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: K.<w> = NumberField(x^3+1/4*x^2-41/16*x+23/64) + sage: K.<w> = NumberField(x^3 + 1/4*x^2 - 41/16*x + 23/64) sage: PS.<x,y> = ProjectiveSpace(1,K) sage: f = DynamicalSystem_projective([x^2 - 29/16*y^2, y^2]) sage: P = PS([w,1]) @@ -7258,9 +7651,9 @@ def connected_rational_component(self, P, n=0): :: sage: PS.<x,y,z> = ProjectiveSpace(2,QQ) - sage: f = DynamicalSystem_projective([x^2 - 21/16*z^2, y^2-2*z^2, z^2]) - sage: P = PS([17/16,7/4,1]) - sage: f.connected_rational_component(P,3) + sage: f = DynamicalSystem_projective([x^2 - 21/16*z^2, y^2 - 2*z^2, z^2]) + sage: P = PS([17/16, 7/4, 1]) + sage: f.connected_rational_component(P, 3) [(17/16 : 7/4 : 1), (-47/256 : 17/16 : 1), (-83807/65536 : -223/256 : 1), @@ -7414,7 +7807,8 @@ def conjugating_set(self, other, R=None, num_cpus=2): sage: D8.conjugating_set(D8) Traceback (most recent call last): ... - ValueError: no more rational preimages; try extending the base field and trying again + ValueError: no more rational preimages; + try extending the base field and trying again :: @@ -7459,7 +7853,7 @@ def conjugating_set(self, other, R=None, num_cpus=2): note that only one possible conjugation is returned:: sage: P.<x,y,z> = ProjectiveSpace(GF(11), 2) - sage: f = DynamicalSystem_projective([2*x + 12*y, 11*y+2*z, x+z]) + sage: f = DynamicalSystem_projective([2*x + 12*y, 11*y + 2*z, x + z]) sage: m1 = matrix(GF(11), 3, 3, [1,4,1,0,2,1,1,1,1]) sage: g = f.conjugate(m1) sage: f.conjugating_set(g) @@ -7473,11 +7867,11 @@ def conjugating_set(self, other, R=None, num_cpus=2): sage: L.<v> = CyclotomicField(8) sage: P.<x,y,z> = ProjectiveSpace(L, 2) - sage: f = DynamicalSystem_projective([2*x + 12*y, 11*y+2*z, x+z]) + sage: f = DynamicalSystem_projective([2*x + 12*y, 11*y + 2*z, x + z]) sage: m1 = matrix(L, 3, 3, [1,4,v^2,0,2,1,1,1,1]) sage: g = f.conjugate(m1) - sage: m = f.conjugating_set(g)[0] - sage: f.conjugate(m) == g + sage: m = f.conjugating_set(g)[0] # long time + sage: f.conjugate(m) == g # long time True TESTS: @@ -7668,7 +8062,7 @@ def is_conjugate(self, other, R=None, num_cpus=2): sage: f.is_conjugate(g) True - conjugation is only checked over the base field by default:: + Conjugation is only checked over the base field by default:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([-3*y^2, 3*x^2]) @@ -7679,7 +8073,7 @@ def is_conjugate(self, other, R=None, num_cpus=2): :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: f = DynamicalSystem_projective([7*x + 12*y, 8*y+2*z, x+z]) + sage: f = DynamicalSystem_projective([7*x + 12*y, 8*y + 2*z, x + z]) sage: m1 = matrix(QQ, 3, 3, [1,4,1,0,2,1,1,1,1]) sage: g = f.conjugate(m1) sage: f.is_conjugate(g) @@ -7688,7 +8082,7 @@ def is_conjugate(self, other, R=None, num_cpus=2): :: sage: P.<x,y,z> = ProjectiveSpace(GF(7), 2) - sage: f = DynamicalSystem_projective([2*x + 12*y, 11*y+2*z, x+z]) + sage: f = DynamicalSystem_projective([2*x + 12*y, 11*y + 2*z, x + z]) sage: m1 = matrix(GF(7), 3, 3, [1,4,1,0,2,1,1,1,1]) sage: g = f.conjugate(m1) sage: f.is_conjugate(g) @@ -7697,7 +8091,7 @@ def is_conjugate(self, other, R=None, num_cpus=2): :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: f = DynamicalSystem_projective([2*x^2 + 12*y*x, 11*y*x+2*y^2, x^2+z^2]) + sage: f = DynamicalSystem_projective([2*x^2 + 12*y*x, 11*y*x + 2*y^2, x^2 + z^2]) sage: m1 = matrix(QQ, 3, 3, [1,4,1,0,2,1,1,1,1]) sage: g = f.conjugate(m1) sage: f.is_conjugate(g) @@ -7799,7 +8193,7 @@ def is_polynomial(self): sage: K.<w> = QuadraticField(4/27) sage: P.<x,y> = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([x**3 + w*y^3,x*y**2]) + sage: f = DynamicalSystem_projective([x**3 + w*y^3, x*y**2]) sage: f.is_polynomial() False @@ -7814,7 +8208,7 @@ def is_polynomial(self): :: sage: PS.<x,y> = ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem_projective([6*x^2+12*x*y+7*y^2, 12*x*y + 42*y^2]) + sage: f = DynamicalSystem_projective([6*x^2 + 12*x*y + 7*y^2, 12*x*y + 42*y^2]) sage: f.is_polynomial() False @@ -7823,7 +8217,7 @@ def is_polynomial(self): See :trac:`25242`:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: F = DynamicalSystem([x^2+ y^2, x*y]) + sage: F = DynamicalSystem([x^2 + y^2, x*y]) sage: F2 = F.conjugate(matrix(QQ,2,2, [1,2,3,5])) sage: F2.is_polynomial() False @@ -7947,13 +8341,14 @@ def normal_form(self, return_conjugation=False): :: - sage: K = GF(3^3, prefix = 'w') + sage: K = GF(3^3, prefix='w') sage: P.<x,y> = ProjectiveSpace(K,1) sage: f = DynamicalSystem_projective([x^3 + 2*x^2*y + 2*x*y^2 + K.gen()*y^3, y^3]) sage: f.normal_form() - Dynamical System of Projective Space of dimension 1 over Finite Field in w3 of size 3^3 - Defn: Defined on coordinates by sending (x : y) to - (x^3 + x^2*y + x*y^2 + (-w3)*y^3 : y^3) + Dynamical System of Projective Space of dimension 1 + over Finite Field in w3 of size 3^3 + Defn: Defined on coordinates by sending (x : y) to + (x^3 + x^2*y + x*y^2 + (-w3)*y^3 : y^3) :: @@ -8116,24 +8511,26 @@ def potential_good_reduction(self, prime, return_conjugation=False): A tuple: - The first element is: - - ``False`` if this dynamical system does not have potential good reduction. - - ``True`` if this dynamical system does have potential good reduction. + - ``False`` if this dynamical system does not have potential good reduction. + - ``True`` if this dynamical system does have potential good reduction. + - The second element is: - - ``None`` if this dynamical system does not have potential good reduction. - - A dynamical system with good reduction at ``prime`` otherwise. + - ``None`` if this dynamical system does not have potential good reduction. + - A dynamical system with good reduction at ``prime`` otherwise. + - If ``return_conjugation`` is ``True``, then the tuple will have a third element, which is: - - ``None`` if this dynamical system does not have potential good reduction. - - The `PGL_2` map used to achieve good reduction otherwise. + - ``None`` if this dynamical system does not have potential good reduction. + - The `PGL_2` map used to achieve good reduction otherwise. EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: system = DynamicalSystem_projective([x^2-y^2, 2*x*y]) + sage: system = DynamicalSystem_projective([x^2 - y^2, 2*x*y]) sage: prime = system.field_of_definition_periodic(1).prime_above(2) sage: new_system = system.potential_good_reduction(prime)[1] sage: new_system Dynamical System of Projective Space of dimension 1 over Number Field - in a with defining polynomial x^2 + 1 + in a with defining polynomial x^2 + 1 Defn: Defined on coordinates by sending (x : y) to ((-1/2*a)*x^2 + (-5/2*a)*y^2 : (-a)*x*y + y^2) @@ -8156,7 +8553,7 @@ def potential_good_reduction(self, prime, return_conjugation=False): :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: system = DynamicalSystem_projective([3^4*x^3+3*x*y^2+y^3, 3^6*y^3]) + sage: system = DynamicalSystem_projective([3^4*x^3 + 3*x*y^2 + y^3, 3^6*y^3]) sage: prime = system.field_of_definition_periodic(1).prime_above(3) sage: system.potential_good_reduction(prime) (False, None) @@ -8164,7 +8561,7 @@ def potential_good_reduction(self, prime, return_conjugation=False): :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: system = DynamicalSystem_projective([x^5-x*y^4, 5*y^5]) + sage: system = DynamicalSystem_projective([x^5 - x*y^4, 5*y^5]) sage: prime = system.field_of_definition_periodic(1).prime_above(5) sage: system.potential_good_reduction(prime) (False, None) @@ -8178,16 +8575,17 @@ def potential_good_reduction(self, prime, return_conjugation=False): sage: system = DynamicalSystem_projective([x^2 - y^2, 2*x*y]) sage: system.potential_good_reduction(prime) (True, - Dynamical System of Projective Space of dimension 1 over - Number Field in a with defining polynomial x^2 + 1 - Defn: Defined on coordinates by sending (x : y) to - ((-1/2*a)*x^2 + (-5/2*a)*y^2 : (-a)*x*y + y^2)) + Dynamical System of Projective Space of dimension 1 over + Number Field in a with defining polynomial x^2 + 1 + Defn: Defined on coordinates by sending (x : y) to + ((-1/2*a)*x^2 + (-5/2*a)*y^2 : (-a)*x*y + y^2)) :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: system = DynamicalSystem_projective([3^5*x^3 + x^2*y - 3^5*x*y^2, -3^5*x^2*y + x*y^2 + 3^5*y^3]) - sage: system.potential_good_reduction(3, return_conjugation=True) + sage: system = DynamicalSystem_projective([3^5*x^3 + x^2*y - 3^5*x*y^2, + ....: -3^5*x^2*y + x*y^2 + 3^5*y^3]) + sage: system.potential_good_reduction(3, return_conjugation=True) # long time (False, None, None) :: @@ -8203,7 +8601,7 @@ def potential_good_reduction(self, prime, return_conjugation=False): :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: system = DynamicalSystem_projective([3*x^2 + x*y+y^2, 9*y^2]) + sage: system = DynamicalSystem_projective([3*x^2 + x*y + y^2, 9*y^2]) sage: prime = system.field_of_definition_periodic(1).prime_above(3) sage: system.potential_good_reduction(prime) (False, None) @@ -8310,20 +8708,22 @@ def reduce_base_field(self): :: sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) - sage: f = DynamicalSystem_projective([x^2 + QQbar(sqrt(3))*y^2, y^2, QQbar(sqrt(2))*z^2]) + sage: f = DynamicalSystem_projective([x^2 + QQbar(sqrt(3))*y^2, + ....: y^2, QQbar(sqrt(2))*z^2]) sage: f.reduce_base_field() Dynamical System of Projective Space of dimension 2 over Number Field in a with - defining polynomial y^4 - 4*y^2 + 1 with a = -0.5176380902050415? + defining polynomial y^4 - 4*y^2 + 1 with a = -0.5176380902050415? Defn: Defined on coordinates by sending (x : y : z) to (x^2 + (-a^2 + 2)*y^2 : y^2 : (a^3 - 3*a)*z^2) :: sage: R.<x> = QQ[] - sage: K.<v> = NumberField(x^3-2, embedding=(x^3-2).roots(ring=CC)[0][0]) + sage: K.<v> = NumberField(x^3 - 2, embedding=(x^3 - 2).roots(ring=CC)[0][0]) sage: R.<x> = QQ[] - sage: L.<w> = NumberField(x^6 + 9*x^4 - 4*x^3 + 27*x^2 + 36*x + 31, \ - ....: embedding=(x^6 + 9*x^4 - 4*x^3 + 27*x^2 + 36*x + 31).roots(ring=CC)[0][0]) + sage: L.<w> = NumberField(x^6 + 9*x^4 - 4*x^3 + 27*x^2 + 36*x + 31, + ....: embedding=(x^6 + 9*x^4 - 4*x^3 + ....: + 27*x^2 + 36*x + 31).roots(ring=CC)[0][0]) sage: P.<x,y> = ProjectiveSpace(L,1) sage: f = DynamicalSystem([L(v)*x^2 + y^2, x*y]) sage: f.reduce_base_field().base_ring().is_isomorphic(K) @@ -8371,7 +8771,7 @@ def is_newton(self, return_conjugation=False): sage: F = f.homogenize(1) sage: F.is_newton(return_conjugation=True) ( - [1 0] + [1 0] True, [0 1] ) @@ -8461,7 +8861,7 @@ def is_postcritically_finite(self, **kwds): EXAMPLES:: sage: P.<x,y,z> = ProjectiveSpace(GF(5),2) - sage: f = DynamicalSystem_projective([x^2 + y^2,y^2, z^2 + y*z], domain=P) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2, z^2 + y*z], domain=P) sage: f.is_postcritically_finite() True @@ -8492,14 +8892,14 @@ def _is_preperiodic(self, P, **kwds): EXAMPLES:: sage: P.<x,y,z> = ProjectiveSpace(GF(5),2) - sage: f = DynamicalSystem_projective([x^2 + y^2,y^2, z^2 + y*z], domain=P) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2, z^2 + y*z], domain=P) sage: f._is_preperiodic(P(2,1,2)) True :: sage: P.<x,y,z> = ProjectiveSpace(GF(5),2) - sage: f = DynamicalSystem_projective([x^2 + y^2,y^2, z^2 + y*z], domain=P) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2, z^2 + y*z], domain=P) sage: f._is_preperiodic(P(2,1,2), return_period=True) (0, 6) """ @@ -8526,14 +8926,14 @@ def orbit_structure(self, P): EXAMPLES:: sage: P.<x,y,z> = ProjectiveSpace(GF(5),2) - sage: f = DynamicalSystem_projective([x^2 + y^2,y^2, z^2 + y*z], domain=P) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2, z^2 + y*z], domain=P) sage: f.orbit_structure(P(2,1,2)) (0, 6) :: sage: P.<x,y,z> = ProjectiveSpace(GF(7),2) - sage: X = P.subscheme(x^2-y^2) + sage: X = P.subscheme(x^2 - y^2) sage: f = DynamicalSystem_projective([x^2, y^2, z^2], domain=X) sage: f.orbit_structure(X(1,1,2)) (0, 2) @@ -8579,21 +8979,21 @@ def cyclegraph(self): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(GF(13),1) - sage: f = DynamicalSystem_projective([x^2-y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - y^2, y^2]) sage: f.cyclegraph() Looped digraph on 14 vertices :: sage: P.<x,y,z> = ProjectiveSpace(GF(3^2,'t'),2) - sage: f = DynamicalSystem_projective([x^2+y^2, y^2, z^2+y*z]) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2, z^2 + y*z]) sage: f.cyclegraph() Looped digraph on 91 vertices :: sage: P.<x,y,z> = ProjectiveSpace(GF(7),2) - sage: X = P.subscheme(x^2-y^2) + sage: X = P.subscheme(x^2 - y^2) sage: f = DynamicalSystem_projective([x^2, y^2, z^2], domain=X) sage: f.cyclegraph() Looped digraph on 15 vertices @@ -8601,15 +9001,15 @@ def cyclegraph(self): :: sage: P.<x,y,z> = ProjectiveSpace(GF(3),2) - sage: f = DynamicalSystem_projective([x*z-y^2, x^2-y^2, y^2-z^2]) + sage: f = DynamicalSystem_projective([x*z - y^2, x^2 - y^2, y^2 - z^2]) sage: f.cyclegraph() Looped digraph on 13 vertices :: sage: P.<x,y,z> = ProjectiveSpace(GF(3),2) - sage: X = P.subscheme([x-y]) - sage: f = DynamicalSystem_projective([x^2-y^2, x^2-y^2, y^2-z^2], domain=X) + sage: X = P.subscheme([x - y]) + sage: f = DynamicalSystem_projective([x^2 - y^2, x^2 - y^2, y^2 - z^2], domain=X) sage: f.cyclegraph() Looped digraph on 4 vertices """ @@ -8671,7 +9071,7 @@ def possible_periods(self, return_points=False): :: sage: P.<x,y> = ProjectiveSpace(GF(13),1) - sage: f = DynamicalSystem_projective([x^2-y^2, y^2]) + sage: f = DynamicalSystem_projective([x^2 - y^2, y^2]) sage: sorted(f.possible_periods(True)) [[(0 : 1), 2], [(1 : 0), 1], [(3 : 1), 3], [(3 : 1), 36]] @@ -8735,7 +9135,7 @@ def automorphism_group(self, **kwds): EXAMPLES:: sage: R.<x,y> = ProjectiveSpace(GF(7^3,'t'),1) - sage: f = DynamicalSystem_projective([x^2-y^2, x*y]) + sage: f = DynamicalSystem_projective([x^2 - y^2, x*y]) sage: f.automorphism_group() [ [1 0] [6 0] @@ -8745,9 +9145,10 @@ def automorphism_group(self, **kwds): :: sage: R.<x,y> = ProjectiveSpace(GF(3^2,'t'),1) - sage: f = DynamicalSystem_projective([x^3,y^3]) - sage: lst, label = f.automorphism_group(return_functions=True, iso_type=True) # long time - sage: sorted(lst, key=str), label # long time + sage: f = DynamicalSystem_projective([x^3, y^3]) + sage: lst, label = f.automorphism_group(return_functions=True, # long time + ....: iso_type=True) + sage: sorted(lst, key=str), label # long time ([(2*x + 1)/(x + 1), (2*x + 1)/x, (2*x + 2)/(x + 2), @@ -8777,14 +9178,14 @@ def automorphism_group(self, **kwds): :: sage: R.<x,y> = ProjectiveSpace(GF(2^5,'t'),1) - sage: f = DynamicalSystem_projective([x^5,y^5]) + sage: f = DynamicalSystem_projective([x^5, y^5]) sage: f.automorphism_group(return_functions=True, iso_type=True) ([x, 1/x], 'Cyclic of order 2') :: sage: R.<x,y> = ProjectiveSpace(GF(3^4,'t'),1) - sage: f = DynamicalSystem_projective([x^2+25*x*y+y^2, x*y+3*y^2]) + sage: f = DynamicalSystem_projective([x^2 + 25*x*y + y^2, x*y + 3*y^2]) sage: f.automorphism_group(absolute=True) [Univariate Polynomial Ring in w over Finite Field in b of size 3^4, [ @@ -8833,14 +9234,14 @@ def all_periodic_points(self, **kwds): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(GF(5^2),1) - sage: f = DynamicalSystem_projective([x^2+y^2, x*y]) + sage: f = DynamicalSystem_projective([x^2 + y^2, x*y]) sage: f.all_periodic_points() [(1 : 0), (z2 + 2 : 1), (4*z2 + 3 : 1)] :: sage: P.<x,y,z> = ProjectiveSpace(GF(5),2) - sage: f = DynamicalSystem_projective([x^2+y^2+z^2, x*y+x*z, z^2]) + sage: f = DynamicalSystem_projective([x^2 + y^2 + z^2, x*y + x*z, z^2]) sage: f.all_periodic_points() [(1 : 0 : 0), (0 : 0 : 1), diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx b/src/sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx index 0228711e7f3..f8fb37d5cf4 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx @@ -9,20 +9,20 @@ AUTHORS: """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 William Stein <wstein@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.arith.functions cimport LCM_list from sage.rings.finite_rings.finite_field_constructor import GF -from sage.sets.all import Set -from sage.misc.misc import subsets +from sage.combinat.subset import subsets + cpdef _fast_possible_periods(self, return_points=False): r""" @@ -89,7 +89,7 @@ cpdef _fast_possible_periods(self, return_points=False): p = PS.base_ring().order() N = int(PS.dimension_relative()) - point_table = [[0,0] for i in xrange(p**(N + 1))] + point_table = [[0,0] for i in range(p**(N + 1))] index = 1 periods = set() points_periods = [] @@ -173,7 +173,7 @@ def _enum_points(int prime, int dimension): highest_range = prime**dimension while current_range <= highest_range: - for value in xrange(current_range, 2*current_range): + for value in range(current_range, 2*current_range): yield _get_point_from_hash(value, prime, dimension) current_range = current_range * prime @@ -211,7 +211,7 @@ cpdef list _get_point_from_hash(int value, int prime, int dimension): cdef list P = [] cdef int i - for i in xrange(dimension + 1): + for i in range(dimension + 1): P.append(value % prime) value /= prime @@ -258,7 +258,7 @@ cpdef _normalize_coordinates(list point, int prime, int len_points): """ cdef int last_coefficient, coefficient, mod_inverse, val - for coefficient in xrange(len_points): + for coefficient in range(len_points): val = ((<int> point[coefficient]) + prime) % prime point[coefficient] = val if val != 0: @@ -266,7 +266,7 @@ cpdef _normalize_coordinates(list point, int prime, int len_points): mod_inverse = _mod_inv(last_coefficient, prime) - for coefficient in xrange(len_points): + for coefficient in range(len_points): point[coefficient] = (point[coefficient] * mod_inverse) % prime cpdef _all_periodic_points(self): diff --git a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py index 442bb514561..cc4078c017a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py +++ b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py @@ -474,7 +474,7 @@ def Qxa(self, a): sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 \ - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 \ + 5*x0*x2*y0*y2 \ - - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 \ + - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP(1, 1, 0, 1, 0, 0) @@ -815,7 +815,7 @@ def degenerate_fibers(self): for n in range(3): affvars = list(R0.gens()) del affvars[n] - R1 = PolynomialRing(K, 2, affvars, order = 'lex') + R1 = PolynomialRing(K, 2, affvars, order='lex') mapvars = list(R1.gens()) mapvars.insert(n,1) phi1 = R0.hom(mapvars, R1) @@ -846,7 +846,7 @@ def degenerate_fibers(self): for n in range(3): affvars = list(R0.gens()) del affvars[n] - R1 = PolynomialRing(K, 2, affvars, order = 'lex') + R1 = PolynomialRing(K, 2, affvars, order='lex') mapvars = list(R1.gens()) mapvars.insert(n, 1) phi1 = R0.hom(mapvars,R1) @@ -867,7 +867,7 @@ def degenerate_fibers(self): return [xFibers,yFibers] @cached_method - def degenerate_primes(self,check = True): + def degenerate_primes(self,check=True): r""" Determine which primes `p` self has degenerate fibers over `GF(p)`. @@ -1179,7 +1179,7 @@ def sigmaX(self, P, **kwds): #Defines the ideal whose solution gives `(s0, s1)` and the two points #on the fiber - RR = PolynomialRing(BR, 5,'s0, s1, z0, z1, z2',order = 'lex') + RR = PolynomialRing(BR, 5,'s0, s1, z0, z1, z2',order='lex') s0, s1, z0, z1, z2 = RR.gens() I = RR.ideal([RR(T[0]), RR(T[1]), @@ -1189,7 +1189,7 @@ def sigmaX(self, P, **kwds): RR(T[7]) - (P[1][1]*z2 + P[1][2]*z1)]) #Find the points - SS = PolynomialRing(BR, 4,'s, z0, z1, z2', order = 'lex') + SS = PolynomialRing(BR, 4,'s, z0, z1, z2', order='lex') s, z0, z1, z2 = SS.gens() phi = RR.hom([s, 1, z0, z1, z2], SS) J = phi(I) @@ -1234,7 +1234,7 @@ def sigmaX(self, P, **kwds): SS(newT[7]) - (P[1][1]*z2 + P[1][2]*z1)]) #Find the points - SSS = PolynomialRing(BR, 3, 'z0, z1, z2', order = 'lex') + SSS = PolynomialRing(BR, 3, 'z0, z1, z2', order='lex') z0,z1,z2 = SSS.gens() phi = SS.hom([0, z0, z1, z2], SSS) J2 = phi(II) @@ -1248,7 +1248,7 @@ def sigmaX(self, P, **kwds): [a, b, c] = [V[0][z0], V[0][z1], V[0][z2]] if len(V) == 0 or [a,b,c] == [0, 0, 0]: - SS = PolynomialRing(BR, 3, 'z0, z1, z2', order = 'lex') + SS = PolynomialRing(BR, 3, 'z0, z1, z2', order='lex') z0,z1,z2 = SS.gens() phi = RR.hom([1, 0, z0, z1, z2], SS) J = phi(I) @@ -1430,7 +1430,7 @@ def sigmaY(self,P, **kwds): RR(T[6]) - (P[0][0]*z2 + P[0][2]*z0), RR(T[7]) - (P[0][1]*z2 + P[0][2]*z1)]) #Find the points - SS = PolynomialRing(BR, 4, 's, z0, z1, z2', order = 'lex') + SS = PolynomialRing(BR, 4, 's, z0, z1, z2', order='lex') s, z0, z1, z2 = SS.gens() phi = RR.hom([s, 1, z0, z1, z2], SS) J = phi(I) @@ -1486,7 +1486,7 @@ def sigmaY(self,P, **kwds): if len(V) == 1: [a, b, c] = [V[0][z0], V[0][z1], V[0][z2]] if len(V) == 0 or [a,b,c] == [0, 0, 0]: - SS = PolynomialRing(BR, 3, 'z0, z1, z2', order = 'lex') + SS = PolynomialRing(BR, 3, 'z0, z1, z2', order='lex') z0,z1,z2 = SS.gens() phi = RR.hom([1, 0, z0, z1, z2], SS) J = phi(I) @@ -1584,7 +1584,7 @@ def psi(self,a, **kwds): kwds.update({"check":False}) return self.sigmaX(A, **kwds) - def lambda_plus(self, P, v, N, m, n, prec = 100): + def lambda_plus(self, P, v, N, m, n, prec=100): r""" Evaluates the local canonical height plus function of Call-Silverman at the place ``v`` for ``P`` with ``N`` terms of the series. @@ -1744,7 +1744,7 @@ def lambda_minus(self, P, v, N, m, n, prec=100): local_height = beta*R((PK[1][i]/PK[1][n]).abs()).log() - R((PK[0][j]/PK[0][m]).abs()).log() for e in range(N): #Take the next iterate - Q = W.psi(PK, check = False) + Q = W.psi(PK, check=False) L = [x.abs() for x in list(Q[0])] l = L.index(max(L)) L = [y.abs() for y in list(Q[1])] diff --git a/src/sage/dynamics/cellular_automata/__init__.py b/src/sage/dynamics/cellular_automata/__init__.py deleted file mode 100644 index bd469e79134..00000000000 --- a/src/sage/dynamics/cellular_automata/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -r""" -Cellular Automata -""" diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 765cb9559d6..f387c84ccec 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -167,7 +167,7 @@ def mandelbrot_plot(f=None, **kwds): sage: B.<c> = CC[] sage: R.<z> = B[] sage: f = z^5 + c - sage: mandelbrot_plot(f) + sage: mandelbrot_plot(f) # long time 500x500px 24-bit RGB image When the polynomial is defined over a multivariate polynomial ring it is @@ -175,7 +175,7 @@ def mandelbrot_plot(f=None, **kwds): sage: R.<a,b> = CC[] sage: f = a^2 + b^3 - sage: mandelbrot_plot(f, parameter=b) + sage: mandelbrot_plot(f, parameter=b) # long time 500x500px 24-bit RGB image Interact functionality is not implemented for general polynomial maps:: @@ -206,21 +206,21 @@ def mandelbrot_plot(f=None, **kwds): from ipywidgets.widgets import FloatSlider, IntSlider, ColorPicker, interact widgets = dict( - x_center = FloatSlider(min=-1.0, max=1.0, step=EPS, + x_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=x_center, description="Real center"), - y_center = FloatSlider(min=-1.0, max=1.0, step=EPS, + y_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=y_center, description="Imag center"), - image_width = FloatSlider(min=EPS, max=4.0, step=EPS, + image_width=FloatSlider(min=EPS, max=4.0, step=EPS, value=image_width, description="Width"), - max_iteration = IntSlider(min=0, max=1000, + max_iteration=IntSlider(min=0, max=1000, value=max_iteration, description="Iterations"), - pixel_count = IntSlider(min=10, max=1000, + pixel_count=IntSlider(min=10, max=1000, value=pixel_count, description="Pixels"), - level_sep = IntSlider(min=1, max=20, + level_sep=IntSlider(min=1, max=20, value=level_sep, description="Color sep"), - color_num = IntSlider(min=1, max=100, + color_num=IntSlider(min=1, max=100, value=number_of_colors, description="# Colors"), - base_color = ColorPicker(value=Color(base_color).html_color(), + base_color=ColorPicker(value=Color(base_color).html_color(), description="Base color"), ) @@ -396,7 +396,7 @@ def external_ray(theta, **kwds): pixel[i, j] = old_pixel[i, j] # Make sure that theta is a list so loop below works - if type(theta) != list: + if not isinstance(theta, list): theta = [theta] # Check if theta is in the interval [0,1] @@ -593,7 +593,7 @@ def julia_plot(f=None, **kwds): sage: R.<z> = CC[] sage: f = z^3 - z + 1 - sage: julia_plot(f) + sage: julia_plot(f) # long time 500x500px 24-bit RGB image To display an interactive plot of the Julia set in the Notebook, @@ -729,25 +729,25 @@ def julia_plot(f=None, **kwds): from ipywidgets.widgets import FloatSlider, IntSlider, \ ColorPicker, interact widgets = dict( - c_real = FloatSlider(min=-2.0, max=2.0, step=EPS, + c_real=FloatSlider(min=-2.0, max=2.0, step=EPS, value=c_real, description="Real c"), - c_imag = FloatSlider(min=-2.0, max=2.0, step=EPS, + c_imag=FloatSlider(min=-2.0, max=2.0, step=EPS, value=c_imag, description="Imag c"), - x_center = FloatSlider(min=-1.0, max=1.0, step=EPS, + x_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=x_center, description="Real center"), - y_center = FloatSlider(min=-1.0, max=1.0, step=EPS, + y_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=y_center, description="Imag center"), - image_width = FloatSlider(min=EPS, max=4.0, step=EPS, + image_width=FloatSlider(min=EPS, max=4.0, step=EPS, value=image_width, description="Width"), - max_iteration = IntSlider(min=0, max=1000, + max_iteration=IntSlider(min=0, max=1000, value=max_iteration, description="Iterations"), - pixel_count = IntSlider(min=10, max=1000, + pixel_count=IntSlider(min=10, max=1000, value=pixel_count, description="Pixels"), - level_sep = IntSlider(min=1, max=20, + level_sep=IntSlider(min=1, max=20, value=level_sep, description="Color sep"), - color_num = IntSlider(min=1, max=100, + color_num=IntSlider(min=1, max=100, value=number_of_colors, description="# Colors"), - base_color = ColorPicker(value=base_color.html_color(), + base_color=ColorPicker(value=base_color.html_color(), description="Base color"), ) if mandelbrot: diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 1189b55fec9..9ee71e4f4bf 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -9,24 +9,22 @@ AUTHORS: - Ben Barros """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 BEN BARROS <bbarros@slu.edu> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.plot.colors import Color from sage.repl.image import Image from copy import copy from cysignals.signals cimport sig_check from sage.rings.complex_mpfr import ComplexField -from sage.functions.log import exp, log -from sage.symbolic.constants import pi +from sage.functions.log import exp from sage.symbolic.relation import solve from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.cc import CC @@ -38,7 +36,7 @@ from sage.symbolic.ring import SR from sage.calculus.var import var from sage.rings.fraction_field import is_FractionField from sage.categories.function_fields import FunctionFields -from sage.libs.all import PariError +from cypari2.handle_error import PariError from math import sqrt @@ -682,6 +680,15 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, sage: f = z^4 - z + c sage: polynomial_mandelbrot(f, pixel_count=100) 100x100px 24-bit RGB image + + :: + + sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import polynomial_mandelbrot + sage: B.<c> = CC[] + sage: R.<z> = B[] + sage: f = z^2*(z-c) + c + sage: polynomial_mandelbrot(f, pixel_count=100) + 100x100px 24-bit RGB image """ cdef: @@ -732,7 +739,7 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, # Take the given base color and create a list of evenly spaced # colors between the given base color and white. The number of # colors in the list depends on the variable color_num. - if type(base_color) == Color: + if isinstance(base_color, Color): # Convert Color to RGB list base_color = [int(k*255) for k in base_color] color_list = [] @@ -765,7 +772,7 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, df = f.derivative(z).univariate_polynomial() critical_pts = df.roots(multiplicities=False) constant_c = True - except PariError: + except (PariError, TypeError): constant_c = False # If c is in the constant term of the polynomial, then the critical points @@ -944,7 +951,7 @@ cpdef general_julia(f, double x_center=0, double y_center=0, image_width=4, sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import general_julia sage: from sage.plot.colors import Color sage: R.<z> = CC[] - sage: f = z^5 - 1 + sage: f = z^5 - 1 sage: general_julia(f) 500x500px 24-bit RGB image """ @@ -966,7 +973,7 @@ cpdef general_julia(f, double x_center=0, double y_center=0, image_width=4, # Take the given base color and create a list of evenly spaced # colors between the given base color and white. The number of # colors in the list depends on the variable color_num. - if type(base_color) == Color: + if isinstance(base_color, Color): # Convert Color to RGB list base_color = [int(k*255) for k in base_color] color_list = [] diff --git a/src/sage/env.py b/src/sage/env.py index ac279ed5da3..f4899639a6d 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -198,7 +198,8 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st GRAPHS_DATA_DIR = var("GRAPHS_DATA_DIR", join(SAGE_SHARE, "graphs")) ELLCURVE_DATA_DIR = var("ELLCURVE_DATA_DIR", join(SAGE_SHARE, "ellcurves")) POLYTOPE_DATA_DIR = var("POLYTOPE_DATA_DIR", join(SAGE_SHARE, "reflexive_polytopes")) -GAP_ROOT_DIR = var("GAP_ROOT_DIR", join(SAGE_SHARE, "gap")) +GAP_LIB_DIR = var("GAP_LIB_DIR", join(SAGE_LOCAL, "lib", "gap")) +GAP_SHARE_DIR = var("GAP_SHARE_DIR", join(SAGE_SHARE, "gap")) THEBE_DIR = var("THEBE_DIR", join(SAGE_SHARE, "thebe")) COMBINATORIAL_DESIGN_DATA_DIR = var("COMBINATORIAL_DESIGN_DATA_DIR", join(SAGE_SHARE, "combinatorial_designs")) CREMONA_MINI_DATA_DIR = var("CREMONA_MINI_DATA_DIR", join(SAGE_SHARE, "cremona")) @@ -230,12 +231,6 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st LIE_INFO_DIR = var("LIE_INFO_DIR", join(SAGE_LOCAL, "lib", "LiE")) SINGULAR_BIN = var("SINGULAR_BIN") or "Singular" -# The path to libSingular, to be passed to dlopen(). This will -# typically be set to an absolute path in sage_conf, but the relative -# fallback path here works on systems where dlopen() searches the -# system's library locations. -LIBSINGULAR_PATH = var("LIBSINGULAR_PATH", "libSingular.so") - # OpenMP OPENMP_CFLAGS = var("OPENMP_CFLAGS", "") OPENMP_CXXFLAGS = var("OPENMP_CXXFLAGS", "") @@ -256,81 +251,6 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st SAGE_GAP_COMMAND = var('SAGE_GAP_COMMAND', _gap_cmd) -def _get_shared_lib_path(*libnames: str) -> Optional[str]: - """ - Return the full path to a shared library file installed in - ``$SAGE_LOCAL/lib`` or the directories associated with the - Python sysconfig. - - This can also be passed more than one library name (e.g. for cases where - some library may have multiple names depending on the platform) in which - case the first one found is returned. - - This supports most *NIX variants (in which ``lib<libname>.so`` is found - under ``$SAGE_LOCAL/lib``), macOS (same, but with the ``.dylib`` - extension), and Cygwin (under ``$SAGE_LOCAL/bin/cyg<libname>.dll``, - or ``$SAGE_LOCAL/bin/cyg<libname>-*.dll`` for versioned DLLs). - - For distributions like Debian that use a multiarch layout, we also try the - multiarch lib paths (i.e. ``/usr/lib/<arch>/``). - - This returns ``None`` if no matching library file could be found. - - EXAMPLES:: - - sage: from sage.env import _get_shared_lib_path - sage: "gap" in _get_shared_lib_path("gap") - True - sage: _get_shared_lib_path("an_absurd_lib") is None - True - - """ - - for libname in libnames: - search_directories: List[Path] = [] - patterns: List[str] = [] - if sys.platform == 'cygwin': - # Later down we take the first matching DLL found, so search - # SAGE_LOCAL first so that it takes precedence - if SAGE_LOCAL: - search_directories.append(Path(SAGE_LOCAL) / 'bin') - search_directories.append(Path(sysconfig.get_config_var('BINDIR'))) - # Note: The following is not very robust, since if there are multible - # versions for the same library this just selects one more or less - # at arbitrary. However, practically speaking, on Cygwin, there - # will only ever be one version - patterns = [f'cyg{libname}.dll', f'cyg{libname}-*.dll'] - else: - if sys.platform == 'darwin': - ext = 'dylib' - else: - ext = 'so' - - if SAGE_LOCAL: - search_directories.append(Path(SAGE_LOCAL) / 'lib') - libdir = sysconfig.get_config_var('LIBDIR') - if libdir is not None: - libdir = Path(libdir) - search_directories.append(libdir) - - multiarchlib = sysconfig.get_config_var('MULTIARCH') - if multiarchlib is not None: - search_directories.append(libdir / multiarchlib), - - patterns = [f'lib{libname}.{ext}'] - - for directory in search_directories: - for pattern in patterns: - path = next(directory.glob(pattern), None) - if path is not None: - return str(path.resolve()) - - # Just return None if no files were found - return None - -# locate libgap shared object -GAP_SO = var("GAP_SO", _get_shared_lib_path("gap", "")) - # post process if DOT_SAGE is not None and ' ' in DOT_SAGE: if UNAME[:6] == 'CYGWIN': @@ -384,17 +304,20 @@ def sage_include_directories(use_sources=False): sage: any(os.path.isfile(os.path.join(d, file)) for d in dirs) True """ - import distutils.sysconfig - - TOP = SAGE_SRC if use_sources else SAGE_LIB - - dirs = [TOP, - distutils.sysconfig.get_python_inc()] + if use_sources: + dirs = [SAGE_SRC] + else: + import sage + dirs = [os.path.dirname(directory) + for directory in sage.__path__] try: import numpy - dirs.insert(1, numpy.get_include()) + dirs.append(numpy.get_include()) except ModuleNotFoundError: pass + + dirs.append(sysconfig.get_config_var('INCLUDEPY')) + return dirs def get_cblas_pc_module_name() -> str: @@ -449,7 +372,8 @@ def cython_aliases(required_modules=None, We can use ``cython.parallel`` regardless of whether OpenMP is supported. This will run in parallel, if OpenMP is supported:: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # optional - sage.misc.cython + ....: ''' ....: #distutils: extra_compile_args = OPENMP_CFLAGS ....: #distutils: extra_link_args = OPENMP_CFLAGS ....: from cython.parallel import prange diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index d21bddd5deb..236822c7a32 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -15,6 +15,7 @@ This module provides a function, :func:`fast_callable`, to transform such expressions into a form where they can be evaluated quickly:: + sage: # needs sage.symbolic sage: f = sin(x) + 3*x^2 sage: ff = fast_callable(f, vars=[x]) sage: ff(3.5) @@ -29,18 +30,19 @@ huge win over sage.calculus, which evidently has a lot of overhead. Compare the cost of evaluating Wilkinson's polynomial (in unexpanded form) at x=30:: + sage: # needs sage.symbolic sage: wilk = prod((x-i) for i in [1 .. 20]); wilk (x - 1)*(x - 2)*(x - 3)*(x - 4)*(x - 5)*(x - 6)*(x - 7)*(x - 8)*(x - 9)*(x - 10)*(x - 11)*(x - 12)*(x - 13)*(x - 14)*(x - 15)*(x - 16)*(x - 17)*(x - 18)*(x - 19)*(x - 20) - sage: timeit('wilk.subs(x=30)') # random, long time + sage: timeit('wilk.subs(x=30)') # random # long time 625 loops, best of 3: 1.43 ms per loop sage: fc_wilk = fast_callable(wilk, vars=[x]) - sage: timeit('fc_wilk(30)') # random, long time + sage: timeit('fc_wilk(30)') # random # long time 625 loops, best of 3: 9.72 us per loop You can specify a particular domain for the evaluation using ``domain=``:: - sage: fc_wilk_zz = fast_callable(wilk, vars=[x], domain=ZZ) + sage: fc_wilk_zz = fast_callable(wilk, vars=[x], domain=ZZ) # needs sage.symbolic The meaning of domain=D is that each intermediate and final result is converted to type D. For instance, the previous example of @@ -58,7 +60,7 @@ the correct parent before we call D. We don't yet have a special interpreter with domain ZZ, so we can see how that compares to the generic fc_wilk example above:: - sage: timeit('fc_wilk_zz(30)') # random, long time + sage: timeit('fc_wilk_zz(30)') # random # long time # needs sage.symbolic 625 loops, best of 3: 15.4 us per loop However, for other types, using domain=D will get a large speedup, @@ -68,8 +70,8 @@ operation will be floating-point, we can just execute the floating-point operations directly and skip all the Python object creations that you would get from actually using RDF objects:: - sage: fc_wilk_rdf = fast_callable(wilk, vars=[x], domain=RDF) - sage: timeit('fc_wilk_rdf(30.0)') # random, long time + sage: fc_wilk_rdf = fast_callable(wilk, vars=[x], domain=RDF) # needs sage.symbolic + sage: timeit('fc_wilk_rdf(30.0)') # random # long time # needs sage.symbolic 625 loops, best of 3: 7 us per loop The domain does not need to be a Sage type; for instance, domain=float @@ -78,27 +80,27 @@ and domain=RDF; the only difference is that when domain=RDF is used, the return value is an RDF element, and when domain=float is used, the return value is a Python float.) :: - sage: fc_wilk_float = fast_callable(wilk, vars=[x], domain=float) - sage: timeit('fc_wilk_float(30.0)') # random, long time + sage: fc_wilk_float = fast_callable(wilk, vars=[x], domain=float) # needs sage.symbolic + sage: timeit('fc_wilk_float(30.0)') # random # long time # needs sage.symbolic 625 loops, best of 3: 5.04 us per loop We also have support for ``RR``:: - sage: fc_wilk_rr = fast_callable(wilk, vars=[x], domain=RR) - sage: timeit('fc_wilk_rr(30.0)') # random, long time + sage: fc_wilk_rr = fast_callable(wilk, vars=[x], domain=RR) # needs sage.symbolic + sage: timeit('fc_wilk_rr(30.0)') # random # long time # needs sage.symbolic 625 loops, best of 3: 13 us per loop For ``CC``:: - sage: fc_wilk_cc = fast_callable(wilk, vars=[x], domain=CC) - sage: timeit('fc_wilk_cc(30.0)') # random, long time + sage: fc_wilk_cc = fast_callable(wilk, vars=[x], domain=CC) # needs sage.symbolic + sage: timeit('fc_wilk_cc(30.0)') # random # long time # needs sage.symbolic 625 loops, best of 3: 23 us per loop And support for ``CDF``:: - sage: fc_wilk_cdf = fast_callable(wilk, vars=[x], domain=CDF) - sage: timeit('fc_wilk_cdf(30.0)') # random, long time + sage: fc_wilk_cdf = fast_callable(wilk, vars=[x], domain=CDF) # needs sage.symbolic + sage: timeit('fc_wilk_cdf(30.0)') # random # long time # needs sage.symbolic 625 loops, best of 3: 10.2 us per loop Currently, :func:`fast_callable` can accept two kinds of objects: @@ -122,6 +124,7 @@ ordering (you can include extra variable names here, too). :: For symbolic expressions, you need to specify the variable names, so that :func:`fast_callable` knows what order to use. :: + sage: # needs sage.symbolic sage: var('y,z,x') (y, z, x) sage: f = 10*y + 100*z + x @@ -131,8 +134,8 @@ that :func:`fast_callable` knows what order to use. :: You can also specify extra variable names:: - sage: ff = fast_callable(f, vars=('x','w','z','y')) - sage: ff(1,2,3,4) + sage: ff = fast_callable(f, vars=('x','w','z','y')) # needs sage.symbolic + sage: ff(1,2,3,4) # needs sage.symbolic 341 This should be enough for normal use of :func:`fast_callable`; let's @@ -178,8 +181,9 @@ expression trees, and returns an expression tree representing the function call. :: sage: v3 = etb.call(sin, v1+v2) - sage: v3 - sin(add(add(mul(add(v_0, v_1), add(v_1, v_1)), floordiv(v_1, v_1)), add(mul(3.14159000000000, v_0), mul(1729, v_1)))) + sage: v3 # needs sage.symbolic + sin(add(add(mul(add(v_0, v_1), add(v_1, v_1)), floordiv(v_1, v_1)), + add(mul(3.14159000000000, v_0), mul(1729, v_1)))) Many sage/Python built-in functions are specially handled; for instance, when evaluating an expression involving :func:`sin` over ``RDF``, @@ -201,15 +205,15 @@ expression tree built up using the methods described above. EXAMPLES:: - sage: var('x') + sage: var('x') # needs sage.symbolic x - sage: f = fast_callable(sqrt(x^7+1), vars=[x], domain=float) + sage: f = fast_callable(sqrt(x^7+1), vars=[x], domain=float) # needs sage.symbolic :: - sage: f(1) + sage: f(1) # needs sage.symbolic 1.4142135623730951 - sage: f.op_list() + sage: f.op_list() # needs sage.symbolic [('load_arg', 0), ('ipow', 7), ('load_const', 1.0), 'add', 'sqrt', 'return'] To interpret that last line, we load argument 0 ('x' in this case) onto @@ -225,7 +229,9 @@ Here we take sin of the first argument and add it to f:: sage: f = etb.call(sqrt, x^7 + 1) sage: g = etb.call(sin, x) sage: fast_callable(f+g).op_list() - [('load_arg', 0), ('ipow', 7), ('load_const', 1), 'add', ('py_call', <function sqrt at ...>, 1), ('load_arg', 0), ('py_call', sin, 1), 'add', 'return'] + [('load_arg', 0), ('ipow', 7), ('load_const', 1), 'add', + ('py_call', <function sqrt at ...>, 1), ('load_arg', 0), ('py_call', sin, 1), + 'add', 'return'] AUTHOR: @@ -261,7 +267,7 @@ AUTHOR: sage: c = etb.var('c') sage: for i in range(16): ....: z = z*z + c - sage: mand = fast_callable(z, domain=CDF) + sage: mand = fast_callable(z, domain=CDF) # needs sage.rings.complex_double Now ``ff`` does 32 complex arithmetic operations on each call (16 additions and 16 multiplications). However, if ``z*z`` produced @@ -335,6 +341,7 @@ def fast_callable(x, domain=None, vars=None, EXAMPLES:: + sage: # needs sage.symbolic sage: var('x') x sage: expr = sin(x) + 3*x^2 @@ -350,6 +357,7 @@ def fast_callable(x, domain=None, vars=None, the RDF interpreter; elements of RDF just don't display all their digits. We have special fast interpreter for domain=CDF:: + sage: # needs sage.symbolic sage: f_float = fast_callable(expr, vars=[x], domain=float) sage: f_float(2) 12.909297426825681 @@ -364,23 +372,34 @@ def fast_callable(x, domain=None, vars=None, sage: f = fast_callable(expr, vars=('z','x','y')) sage: f(1, 2, 3) sin(2) + 12 + sage: K.<x> = QQ[] sage: p = -1/4*x^6 + 1/2*x^5 - x^4 - 12*x^3 + 1/2*x^2 - 1/95*x - 1/2 sage: fp = fast_callable(p, domain=RDF) sage: fp.op_list() - [('load_arg', 0), ('load_const', -0.25), 'mul', ('load_const', 0.5), 'add', ('load_arg', 0), 'mul', ('load_const', -1.0), 'add', ('load_arg', 0), 'mul', ('load_const', -12.0), 'add', ('load_arg', 0), 'mul', ('load_const', 0.5), 'add', ('load_arg', 0), 'mul', ('load_const', -0.010526315789473684), 'add', ('load_arg', 0), 'mul', ('load_const', -0.5), 'add', 'return'] + [('load_arg', 0), ('load_const', -0.25), 'mul', ('load_const', 0.5), 'add', + ('load_arg', 0), 'mul', ('load_const', -1.0), 'add', ('load_arg', 0), 'mul', + ('load_const', -12.0), 'add', ('load_arg', 0), 'mul', ('load_const', 0.5), + 'add', ('load_arg', 0), 'mul', ('load_const', -0.010526315789473684), + 'add', ('load_arg', 0), 'mul', ('load_const', -0.5), 'add', 'return'] sage: fp(3.14159) -552.4182988917153 + sage: K.<x,y,z> = QQ[] sage: p = x*y^2 + 1/3*y^2 - x*z - y*z sage: fp = fast_callable(p, domain=RDF) sage: fp.op_list() - [('load_const', 0.0), ('load_const', 1.0), ('load_arg', 0), ('ipow', 1), ('load_arg', 1), ('ipow', 2), 'mul', 'mul', 'add', ('load_const', 0.3333333333333333), ('load_arg', 1), ('ipow', 2), 'mul', 'add', ('load_const', -1.0), ('load_arg', 0), ('ipow', 1), ('load_arg', 2), ('ipow', 1), 'mul', 'mul', 'add', ('load_const', -1.0), ('load_arg', 1), ('ipow', 1), ('load_arg', 2), ('ipow', 1), 'mul', 'mul', 'add', 'return'] - sage: fp(e, pi, sqrt(2)) # abs tol 3e-14 + [('load_const', 0.0), ('load_const', 1.0), ('load_arg', 0), ('ipow', 1), + ('load_arg', 1), ('ipow', 2), 'mul', 'mul', 'add', + ('load_const', 0.3333333333333333), ('load_arg', 1), ('ipow', 2), 'mul', 'add', + ('load_const', -1.0), ('load_arg', 0), ('ipow', 1), ('load_arg', 2), + ('ipow', 1), 'mul', 'mul', 'add', ('load_const', -1.0), ('load_arg', 1), + ('ipow', 1), ('load_arg', 2), ('ipow', 1), 'mul', 'mul', 'add', 'return'] + sage: fp(e, pi, sqrt(2)) # abs tol 3e-14 # needs sage.symbolic 21.831120464939584 - sage: symbolic_result = p(e, pi, sqrt(2)); symbolic_result + sage: symbolic_result = p(e, pi, sqrt(2)); symbolic_result # needs sage.symbolic pi^2*e + 1/3*pi^2 - sqrt(2)*pi - sqrt(2)*e - sage: n(symbolic_result) + sage: n(symbolic_result) # needs sage.symbolic 21.8311204649396 :: @@ -398,7 +417,9 @@ def fast_callable(x, domain=None, vars=None, Check that fast_callable also works for symbolic functions with evaluation functions:: - sage: def evalf_func(self, x, y, parent): return parent(x*y) if parent is not None else x*y + sage: # needs sage.symbolic + sage: def evalf_func(self, x, y, parent): + ....: return parent(x*y) if parent is not None else x*y sage: x,y = var('x,y') sage: f = function('f', evalf_func=evalf_func) sage: fc = fast_callable(f(x, y), vars=[x, y]) @@ -407,7 +428,9 @@ def fast_callable(x, domain=None, vars=None, And also when there are complex values involved:: - sage: def evalf_func(self, x, y, parent): return parent(I*x*y) if parent is not None else I*x*y + sage: # needs sage.symbolic + sage: def evalf_func(self, x, y, parent): + ....: return parent(I*x*y) if parent is not None else I*x*y sage: g = function('g', evalf_func=evalf_func) sage: fc = fast_callable(g(x, y), vars=[x, y]) sage: fc(3, 4) @@ -465,41 +488,89 @@ def fast_callable(x, domain=None, vars=None, etb = ExpressionTreeBuilder(vars=vars, domain=domain) et = x._fast_callable_(etb) - if isinstance(domain, sage.rings.abc.RealField): - from sage.ext.interpreters.wrapper_rr import Wrapper_rr as builder - str = InstructionStream(sage.ext.interpreters.wrapper_rr.metadata, - len(vars), - domain) - - elif isinstance(domain, sage.rings.abc.ComplexField): - from sage.ext.interpreters.wrapper_cc import Wrapper_cc as builder - str = InstructionStream(sage.ext.interpreters.wrapper_cc.metadata, - len(vars), - domain) - - elif isinstance(domain, sage.rings.abc.RealDoubleField) or domain is float: - from sage.ext.interpreters.wrapper_rdf import Wrapper_rdf as builder - str = InstructionStream(sage.ext.interpreters.wrapper_rdf.metadata, - len(vars), - domain) - elif isinstance(domain, sage.rings.abc.ComplexDoubleField): - from sage.ext.interpreters.wrapper_cdf import Wrapper_cdf as builder - str = InstructionStream(sage.ext.interpreters.wrapper_cdf.metadata, - len(vars), - domain) - elif domain is None: - from sage.ext.interpreters.wrapper_py import Wrapper_py as builder - str = InstructionStream(sage.ext.interpreters.wrapper_py.metadata, - len(vars)) - else: - from sage.ext.interpreters.wrapper_el import Wrapper_el as builder - str = InstructionStream(sage.ext.interpreters.wrapper_el.metadata, - len(vars), - domain) + builder, str = _builder_and_stream(vars=vars, domain=domain) + generate_code(et, str) str.instr('return') return builder(str.get_current()) + +def _builder_and_stream(vars, domain): + r""" + Return a builder and a stream. + + This is an internal function used only once, by :func:`fast_callable`. + + INPUT: + + - ``vars`` -- a sequence of variable names + + - ``domain`` -- a Sage parent or Python type or ``None``; if non-``None``, + all arithmetic is done in that domain + + OUTPUT: A :class:`Wrapper`, an class:`InstructionStream` + + EXAMPLES:: + + sage: from sage.ext.fast_callable import _builder_and_stream + sage: _builder_and_stream(["x", "y"], ZZ) + (<class 'sage.ext.interpreters.wrapper_el.Wrapper_el'>, + <sage.ext.fast_callable.InstructionStream object at 0x...>) + sage: _builder_and_stream(["x", "y"], RR) # needs sage.rings.real_mpfr + (<class 'sage.ext.interpreters.wrapper_rr.Wrapper_rr'>, + <sage.ext.fast_callable.InstructionStream object at 0x...>) + + Modularized test with sagemath-categories after :issue:`35095`, which has + (a basic version of) ``RDF`` but not the specialized interpreter for it. + In this case, the function falls back to using the :class:`Element` + interpreter:: + + sage: domain = RDF + sage: from sage.structure.element import Element as domain + sage: _builder_and_stream(["x", "y"], domain) + (<class 'sage.ext.interpreters.wrapper_el.Wrapper_el'>, + <sage.ext.fast_callable.InstructionStream object at 0x...>) + """ + if isinstance(domain, sage.rings.abc.RealField): + try: + from sage.ext.interpreters.wrapper_rr import metadata, Wrapper_rr as builder + except ImportError: + pass + else: + return builder, InstructionStream(metadata, len(vars), domain) + + if isinstance(domain, sage.rings.abc.ComplexField): + try: + from sage.ext.interpreters.wrapper_cc import metadata, Wrapper_cc as builder + except ImportError: + pass + else: + return builder, InstructionStream(metadata, len(vars), domain) + + if isinstance(domain, sage.rings.abc.RealDoubleField) or domain is float: + try: + from sage.ext.interpreters.wrapper_rdf import metadata, Wrapper_rdf as builder + except ImportError: + pass + else: + return builder, InstructionStream(metadata, len(vars), domain) + + if isinstance(domain, sage.rings.abc.ComplexDoubleField): + try: + from sage.ext.interpreters.wrapper_cdf import metadata, Wrapper_cdf as builder + except ImportError: + pass + else: + return builder, InstructionStream(metadata, len(vars), domain) + + if domain is None: + from sage.ext.interpreters.wrapper_py import metadata, Wrapper_py as builder + return builder, InstructionStream(metadata, len(vars)) + + from sage.ext.interpreters.wrapper_el import metadata, Wrapper_el as builder + return builder, InstructionStream(metadata, len(vars), domain) + + def function_name(fn): r""" Given a function, return a string giving a name for the function. @@ -520,7 +591,7 @@ def function_name(fn): sage: from sage.ext.fast_callable import function_name sage: function_name(operator.pow) 'pow' - sage: function_name(cos) + sage: function_name(cos) # needs sage.symbolic 'cos' sage: function_name(factorial) '{factorial}' @@ -627,9 +698,9 @@ cdef class ExpressionTreeBuilder: sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder('x') - sage: var('x') + sage: var('x') # needs sage.symbolic x - sage: etb._clean_var(x) + sage: etb._clean_var(x) # needs sage.symbolic 'x' sage: x = polygen(RR); x x @@ -652,10 +723,10 @@ cdef class ExpressionTreeBuilder: sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder('x') - sage: etb.constant(pi) + sage: etb.constant(pi) # needs sage.symbolic pi - sage: etb = ExpressionTreeBuilder('x', domain=RealField(200)) - sage: etb.constant(pi) + sage: etb = ExpressionTreeBuilder('x', domain=RealField(200)) # needs sage.rings.real_mpfr + sage: etb.constant(pi) # needs sage.rings.real_mpfr sage.symbolic 3.1415926535897932384626433832795028841971693993751058209749 """ if self._domain is not None: @@ -669,6 +740,7 @@ cdef class ExpressionTreeBuilder: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: var('a,b,some_really_long_name') (a, b, some_really_long_name) @@ -726,6 +798,7 @@ cdef class ExpressionTreeBuilder: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: etb.call(cos, x) @@ -755,8 +828,8 @@ cdef class ExpressionTreeBuilder: EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: etb.choice(etb.call(operator.eq, x, 0), 0, 1/x) + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: etb.choice(etb.call(operator.eq, x, 0), 0, 1/x) # needs sage.symbolic (0 if {eq}(v_0, 0) else div(1, v_0)) """ return ExpressionChoice(self, @@ -792,6 +865,7 @@ cdef class Expression: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb.var(x) @@ -818,10 +892,10 @@ cdef class Expression: EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: v = etb(3); v # indirect doctest + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: v = etb(3); v # indirect doctest # needs sage.symbolic 3 - sage: v._get_etb() is etb + sage: v._get_etb() is etb # needs sage.symbolic True """ self._etb = etb @@ -833,10 +907,10 @@ cdef class Expression: EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: v = etb(3); v + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: v = etb(3); v # needs sage.symbolic 3 - sage: v._get_etb() is etb + sage: v._get_etb() is etb # needs sage.symbolic True """ return self._etb @@ -847,6 +921,7 @@ cdef class Expression: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -869,6 +944,7 @@ cdef class Expression: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -891,6 +967,7 @@ cdef class Expression: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -913,6 +990,7 @@ cdef class Expression: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -935,6 +1013,7 @@ cdef class Expression: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -960,6 +1039,7 @@ cdef class Expression: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -1000,6 +1080,7 @@ cdef class Expression: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -1016,6 +1097,7 @@ cdef class Expression: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -1034,6 +1116,7 @@ cdef class Expression: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -1052,6 +1135,7 @@ cdef class Expression: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -1070,8 +1154,8 @@ cdef class ExpressionConstant(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: type(etb(3)) + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: type(etb(3)) # needs sage.symbolic <class 'sage.ext.fast_callable.ExpressionConstant'> """ @@ -1083,6 +1167,7 @@ cdef class ExpressionConstant(Expression): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder, ExpressionConstant sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: etb(3) @@ -1106,8 +1191,8 @@ cdef class ExpressionConstant(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: etb(3).value() + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: etb(3).value() # needs sage.symbolic 3 """ return self._value @@ -1119,6 +1204,7 @@ cdef class ExpressionConstant(Expression): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: v = etb.constant(pi) @@ -1138,8 +1224,8 @@ cdef class ExpressionVariable(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: type(etb.var(x)) + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: type(etb.var(x)) # needs sage.symbolic <class 'sage.ext.fast_callable.ExpressionVariable'> """ cdef int _variable_index @@ -1150,6 +1236,7 @@ cdef class ExpressionVariable(Expression): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder, ExpressionVariable sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: etb(x) @@ -1171,8 +1258,8 @@ cdef class ExpressionVariable(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: etb(x).variable_index() + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: etb(x).variable_index() # needs sage.symbolic 0 """ return self._variable_index @@ -1183,6 +1270,7 @@ cdef class ExpressionVariable(Expression): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: v = etb._var_number(0) @@ -1205,8 +1293,8 @@ cdef class ExpressionCall(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: type(etb.call(sin, x)) + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: type(etb.call(sin, x)) # needs sage.symbolic <class 'sage.ext.fast_callable.ExpressionCall'> """ cdef object _function @@ -1218,6 +1306,7 @@ cdef class ExpressionCall(Expression): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder, ExpressionCall sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -1243,8 +1332,8 @@ cdef class ExpressionCall(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: etb.call(sin, x).function() + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: etb.call(sin, x).function() # needs sage.symbolic sin """ return self._function @@ -1256,8 +1345,8 @@ cdef class ExpressionCall(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: etb.call(sin, x).arguments() + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: etb.call(sin, x).arguments() # needs sage.symbolic [v_0] """ return copy(self._arguments) @@ -1268,6 +1357,7 @@ cdef class ExpressionCall(Expression): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb.var(x) @@ -1294,8 +1384,8 @@ cdef class ExpressionIPow(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: type(etb.var('x')^17) + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: type(etb.var('x')^17) # needs sage.symbolic <class 'sage.ext.fast_callable.ExpressionIPow'> """ cdef object _base @@ -1307,6 +1397,7 @@ cdef class ExpressionIPow(Expression): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder, ExpressionIPow sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -1332,8 +1423,8 @@ cdef class ExpressionIPow(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: (etb(33)^42).base() + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: (etb(33)^42).base() # needs sage.symbolic 33 """ return self._base @@ -1345,8 +1436,8 @@ cdef class ExpressionIPow(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: (etb(x)^(-1)).exponent() + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: (etb(x)^(-1)).exponent() # needs sage.symbolic -1 """ return self._exponent @@ -1357,6 +1448,7 @@ cdef class ExpressionIPow(Expression): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb.var(x) @@ -1383,8 +1475,8 @@ cdef class ExpressionChoice(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: etb.choice(etb.call(operator.eq, x, 0), 0, 1/x) + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: etb.choice(etb.call(operator.eq, x, 0), 0, 1/x) # needs sage.symbolic (0 if {eq}(v_0, 0) else div(1, v_0)) """ @@ -1398,6 +1490,7 @@ cdef class ExpressionChoice(Expression): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder, ExpressionChoice sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -1426,9 +1519,9 @@ cdef class ExpressionChoice(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: x = etb(x) - sage: etb.choice(x, ~x, 0).condition() + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: x = etb(x) # needs sage.symbolic + sage: etb.choice(x, ~x, 0).condition() # needs sage.symbolic v_0 """ return self._cond @@ -1440,9 +1533,9 @@ cdef class ExpressionChoice(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: x = etb(x) - sage: etb.choice(x, ~x, 0).if_true() + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: x = etb(x) # needs sage.symbolic + sage: etb.choice(x, ~x, 0).if_true() # needs sage.symbolic inv(v_0) """ return self._iftrue @@ -1454,9 +1547,9 @@ cdef class ExpressionChoice(Expression): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder - sage: etb = ExpressionTreeBuilder(vars=(x,)) - sage: x = etb(x) - sage: etb.choice(x, ~x, 0).if_false() + sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic + sage: x = etb(x) # needs sage.symbolic + sage: etb.choice(x, ~x, 0).if_false() # needs sage.symbolic 0 """ return self._iffalse @@ -1468,6 +1561,7 @@ cdef class ExpressionChoice(Expression): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: x = etb(x) @@ -1491,19 +1585,19 @@ cpdef _expression_binop_helper(s, o, op): EXAMPLES:: sage: from sage.ext.fast_callable import _expression_binop_helper, ExpressionTreeBuilder - sage: var('x,y') + sage: var('x,y') # needs sage.symbolic (x, y) - sage: etb = ExpressionTreeBuilder(vars=(x,y)) - sage: x = etb(x) + sage: etb = ExpressionTreeBuilder(vars=(x,y)) # needs sage.symbolic + sage: x = etb(x) # needs sage.symbolic Now x is an Expression, but y is not. Still, all the following cases work:: - sage: _expression_binop_helper(x, x, operator.add) + sage: _expression_binop_helper(x, x, operator.add) # needs sage.symbolic add(v_0, v_0) - sage: _expression_binop_helper(x, y, operator.add) + sage: _expression_binop_helper(x, y, operator.add) # needs sage.symbolic add(v_0, v_1) - sage: _expression_binop_helper(y, x, operator.add) + sage: _expression_binop_helper(y, x, operator.add) # needs sage.symbolic add(v_1, v_0) """ @@ -1547,9 +1641,9 @@ class IntegerPowerFunction(): sage: square = IntegerPowerFunction(2) sage: square (^2) - sage: square(pi) + sage: square(pi) # needs sage.symbolic pi^2 - sage: square(I) + sage: square(I) # needs sage.symbolic -1 sage: square(RIF(-1, 1)).str(style='brackets') '[0.0000000000000000 .. 1.0000000000000000]' @@ -1574,7 +1668,7 @@ class IntegerPowerFunction(): sage: cube = IntegerPowerFunction(3) sage: cube (^3) - sage: cube(AA(7)^(1/3)) + sage: cube(AA(7)^(1/3)) # needs sage.rings.number_field 7.000000000000000? sage: cube.exponent 3 @@ -1633,9 +1727,11 @@ cpdef dict get_builtin_functions(): sage: from sage.ext.fast_callable import get_builtin_functions sage: builtins = get_builtin_functions() - sage: sorted(set(builtins.values())) - ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atanh', 'ceil', 'cos', 'cosh', 'cot', 'csc', 'div', 'exp', 'floor', 'floordiv', 'inv', 'log', 'mul', 'neg', 'pow', 'sec', 'sin', 'sinh', 'sqrt', 'sub', 'tan', 'tanh'] - sage: builtins[sin] + sage: sorted(set(builtins.values())) # needs sage.symbolic + ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atanh', 'ceil', + 'cos', 'cosh', 'cot', 'csc', 'div', 'exp', 'floor', 'floordiv', 'inv', 'log', + 'mul', 'neg', 'pow', 'sec', 'sin', 'sinh', 'sqrt', 'sub', 'tan', 'tanh'] + sage: builtins[sin] # needs sage.symbolic 'sin' sage: builtins[ln] 'log' @@ -1688,9 +1784,11 @@ cpdef generate_code(Expression expr, InstructionStream stream): EXAMPLES:: sage: from sage.ext.fast_callable import ExpressionTreeBuilder, generate_code, InstructionStream + + sage: # needs sage.symbolic sage: etb = ExpressionTreeBuilder('x') sage: x = etb.var('x') - sage: expr = ((x+pi)*(x+1)) + sage: expr = (x+pi) * (x+1) sage: from sage.ext.interpreters.wrapper_py import metadata, Wrapper_py sage: instr_stream = InstructionStream(metadata, 1) sage: generate_code(expr, instr_stream) @@ -1708,6 +1806,8 @@ cpdef generate_code(Expression expr, InstructionStream stream): sage: def my_sqrt(x): ....: if x < 0: raise ValueError("sqrt of negative number") ....: return sqrt(x, extend=False) + + sage: # needs sage.symbolic sage: fc = fast_callable(expr, domain=RealField(130)) sage: fc(0) 3.1415926535897932384626433832795028842 @@ -1733,11 +1833,15 @@ cpdef generate_code(Expression expr, InstructionStream stream): sage: fc = fast_callable(etb.call(my_sin, x), domain=RDF) sage: fc(3) 0.1411200080598672 + + sage: # needs sage.rings.real_mpfr sage.symbolic sage: fc = fast_callable(etb.call(my_sin, x), domain=RealField(100)) sage: fc(3) 0.14112000805986722210074480281 sage: fc.op_list() [('load_arg', 0), ('py_call', <function my_sin at 0x...>, 1), 'return'] + + sage: # needs sage.symbolic sage: fc = fast_callable(etb.call(my_sqrt, x), domain=RDF) sage: fc(3) 1.7320508075688772 @@ -1754,6 +1858,7 @@ cpdef generate_code(Expression expr, InstructionStream stream): Traceback (most recent call last): ... ValueError: sqrt of negative number + sage: etb2 = ExpressionTreeBuilder(('y','z')) sage: y = etb2.var('y') sage: z = etb2.var('z') @@ -1764,14 +1869,16 @@ cpdef generate_code(Expression expr, InstructionStream stream): [('load_arg', 0), ('load_arg', 1), ('py_call', <function my_norm at 0x...>, 2), 'sqrt', 'return'] sage: fc.python_calls() [<function my_norm at 0x...>] - sage: fc = fast_callable(etb2.call(sqrt, etb2.call(my_norm, y, z)), domain=RR) - sage: fc(3, 4) + sage: fc = fast_callable(etb2.call(sqrt, etb2.call(my_norm, y, z)), domain=RR) # needs sage.rings.real_mpfr + sage: fc(3, 4) # needs sage.rings.real_mpfr 5.00000000000000 sage: fc = fast_callable(etb2.call(my_norm, y, z), domain=ZZ) sage: fc(3, 4) 25 sage: fc.op_list() [('load_arg', 0), ('load_arg', 1), ('py_call', <function my_norm at 0x...>, 2), 'return'] + + sage: # needs sage.symbolic sage: fc = fast_callable(expr) sage: fc(3.0r) 4.0*pi + 12.0 @@ -1795,6 +1902,7 @@ cpdef generate_code(Expression expr, InstructionStream stream): :: + sage: # needs sage.symbolic sage: fc = fast_callable(etb(x)^100) sage: fc(pi) pi^100 @@ -1809,18 +1917,18 @@ cpdef generate_code(Expression expr, InstructionStream stream): [('load_arg', 0), ('ipow', 100), 'return'] sage: fc(1.1) 13780.61233982... - sage: fc = fast_callable(etb(x)^100, domain=RR) - sage: fc.op_list() + sage: fc = fast_callable(etb(x)^100, domain=RR) # needs sage.rings.real_mpfr + sage: fc.op_list() # needs sage.rings.real_mpfr [('load_arg', 0), ('ipow', 100), 'return'] - sage: fc(1.1) + sage: fc(1.1) # needs sage.rings.real_mpfr 13780.6123398224 sage: fc = fast_callable(etb(x)^(-100), domain=RDF) sage: fc.op_list() [('load_arg', 0), ('ipow', -100), 'return'] sage: fc(1.1) 7.25657159014...e-05 - sage: fc = fast_callable(etb(x)^(-100), domain=RR) - sage: fc(1.1) + sage: fc = fast_callable(etb(x)^(-100), domain=RR) # needs sage.rings.real_mpfr + sage: fc(1.1) # needs sage.rings.real_mpfr 0.0000725657159014814 sage: expo = 2^32 sage: base = (1.0).nextabove() @@ -1831,10 +1939,10 @@ cpdef generate_code(Expression expr, InstructionStream stream): 1.0000009536747712 sage: RDF(base)^expo 1.0000009536747712 - sage: fc = fast_callable(etb(x)^expo, domain=RR) - sage: fc.op_list() + sage: fc = fast_callable(etb(x)^expo, domain=RR) # needs sage.rings.real_mpfr + sage: fc.op_list() # needs sage.rings.real_mpfr [('load_arg', 0), ('py_call', (^4294967296), 1), 'return'] - sage: fc(base) + sage: fc(base) # needs sage.rings.real_mpfr 1.00000095367477 sage: base^expo 1.00000095367477 @@ -1842,6 +1950,7 @@ cpdef generate_code(Expression expr, InstructionStream stream): Make sure we do not overflow the stack with highly nested expressions (:trac:`11766`):: + sage: # needs sage.rings.real_mpfr sage: R.<x> = CC[] sage: f = R(list(range(100000))) sage: ff = fast_callable(f) @@ -1957,7 +2066,8 @@ cdef class InstructionStream: EXAMPLES:: - sage: from sage.ext.interpreters.wrapper_rdf import metadata + sage: from sage.ext.interpreters.wrapper_el import metadata + sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules sage: from sage.ext.fast_callable import InstructionStream sage: instr_stream = InstructionStream(metadata, 1) sage: instr_stream.get_current() @@ -1993,7 +2103,8 @@ cdef class InstructionStream: EXAMPLES:: - sage: from sage.ext.interpreters.wrapper_rdf import metadata + sage: from sage.ext.interpreters.wrapper_el import metadata + sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules sage: from sage.ext.fast_callable import InstructionStream, op_list sage: instr_stream = InstructionStream(metadata, 1) sage: instr_stream.load_const(5) @@ -2018,7 +2129,8 @@ cdef class InstructionStream: EXAMPLES:: - sage: from sage.ext.interpreters.wrapper_rdf import metadata + sage: from sage.ext.interpreters.wrapper_el import metadata + sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules sage: from sage.ext.fast_callable import InstructionStream sage: instr_stream = InstructionStream(metadata, 12) sage: instr_stream.load_arg(5) @@ -2037,7 +2149,8 @@ cdef class InstructionStream: EXAMPLES:: - sage: from sage.ext.interpreters.wrapper_rdf import metadata + sage: from sage.ext.interpreters.wrapper_el import metadata + sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules sage: from sage.ext.fast_callable import InstructionStream sage: instr_stream = InstructionStream(metadata, 1) sage: instr_stream.has_instr('return') @@ -2060,11 +2173,12 @@ cdef class InstructionStream: EXAMPLES:: - sage: from sage.ext.interpreters.wrapper_rdf import metadata + sage: from sage.ext.interpreters.wrapper_el import metadata + sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules sage: from sage.ext.fast_callable import InstructionStream sage: instr_stream = InstructionStream(metadata, 1) sage: instr_stream.instr('load_arg', 0) - sage: instr_stream.instr('sin') + sage: instr_stream.instr('sin') # needs sage.symbolic sage: instr_stream.instr('py_call', math.sin, 1) sage: instr_stream.instr('abs') sage: instr_stream.instr('factorial') @@ -2072,7 +2186,7 @@ cdef class InstructionStream: ... KeyError: 'factorial' sage: instr_stream.instr('return') - sage: instr_stream.current_op_list() + sage: instr_stream.current_op_list() # needs sage.symbolic [('load_arg', 0), 'sin', ('py_call', <built-in function sin>, 1), 'abs', 'return'] """ self.instr0(opname, args) @@ -2138,7 +2252,8 @@ cdef class InstructionStream: EXAMPLES:: - sage: from sage.ext.interpreters.wrapper_rdf import metadata + sage: from sage.ext.interpreters.wrapper_el import metadata + sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules sage: from sage.ext.fast_callable import InstructionStream sage: instr_stream = InstructionStream(metadata, 1) sage: md = instr_stream.get_metadata() @@ -2156,7 +2271,8 @@ cdef class InstructionStream: EXAMPLES:: - sage: from sage.ext.interpreters.wrapper_rdf import metadata + sage: from sage.ext.interpreters.wrapper_el import metadata + sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules sage: from sage.ext.fast_callable import InstructionStream sage: instr_stream = InstructionStream(metadata, 1) sage: instr_stream.instr('load_arg', 0) @@ -2178,7 +2294,8 @@ cdef class InstructionStream: EXAMPLES:: - sage: from sage.ext.interpreters.wrapper_rdf import metadata + sage: from sage.ext.interpreters.wrapper_el import metadata + sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules sage: from sage.ext.fast_callable import InstructionStream sage: instr_stream = InstructionStream(metadata, 1) sage: instr_stream.get_current() @@ -2326,7 +2443,8 @@ def op_list(args, metadata): EXAMPLES:: - sage: from sage.ext.interpreters.wrapper_rdf import metadata + sage: from sage.ext.interpreters.wrapper_el import metadata + sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules sage: from sage.ext.fast_callable import InstructionStream, op_list sage: instr_stream = InstructionStream(metadata, 1) sage: instr_stream.instr('load_arg', 0) @@ -2370,10 +2488,11 @@ cdef class Wrapper: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import ExpressionTreeBuilder, generate_code, InstructionStream sage: etb = ExpressionTreeBuilder('x') sage: x = etb.var('x') - sage: expr = ((x+pi)*(x+1)) + sage: expr = (x+pi) * (x+1) sage: from sage.ext.interpreters.wrapper_py import metadata, Wrapper_py sage: instr_stream = InstructionStream(metadata, 1) sage: generate_code(expr, instr_stream) @@ -2406,7 +2525,7 @@ cdef class Wrapper: EXAMPLES:: - sage: fast_callable(sin(x)/x, vars=[x], domain=RDF).get_orig_args() + sage: fast_callable(sin(x)/x, vars=[x], domain=RDF).get_orig_args() # needs sage.symbolic {'args': 1, 'code': [0, 0, 16, 0, 0, 8, 2], 'constants': [], @@ -2422,7 +2541,7 @@ cdef class Wrapper: EXAMPLES:: - sage: fast_callable(cos(x)*x, vars=[x], domain=RDF).op_list() + sage: fast_callable(cos(x) * x, vars=[x], domain=RDF).op_list() # needs sage.symbolic [('load_arg', 0), ('load_arg', 0), 'cos', 'mul', 'return'] """ return op_list(self._orig_args, self._metadata) @@ -2438,9 +2557,9 @@ cdef class Wrapper: EXAMPLES:: - sage: fast_callable(abs(sin(x)), vars=[x], domain=RDF).python_calls() + sage: fast_callable(abs(sin(x)), vars=[x], domain=RDF).python_calls() # needs sage.symbolic [] - sage: fast_callable(abs(sin(factorial(x))), vars=[x]).python_calls() + sage: fast_callable(abs(sin(factorial(x))), vars=[x]).python_calls() # needs sage.symbolic [factorial, sin] """ ops = self.op_list() @@ -2509,6 +2628,7 @@ class FastCallableFloatWrapper: An error is thrown if the answer is complex:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import FastCallableFloatWrapper sage: f = sqrt(x) sage: ff = fast_callable(f, vars=[x], domain=CDF) @@ -2547,6 +2667,7 @@ class FastCallableFloatWrapper: The wrapper will ignore an imaginary part smaller in magnitude than ``imag_tol``, but not one larger:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import FastCallableFloatWrapper sage: f = x sage: ff = fast_callable(f, vars=[x], domain=CDF) @@ -2574,6 +2695,7 @@ class FastCallableFloatWrapper: Evaluation either returns a ``float``, or raises a ``ValueError``:: + sage: # needs sage.symbolic sage: from sage.ext.fast_callable import FastCallableFloatWrapper sage: f = x sage: ff = fast_callable(f, vars=[x], domain=CDF) diff --git a/src/sage/ext/fast_eval.pyx b/src/sage/ext/fast_eval.pyx index 7b45ea1c5a0..52fbc8f7406 100644 --- a/src/sage/ext/fast_eval.pyx +++ b/src/sage/ext/fast_eval.pyx @@ -51,14 +51,15 @@ def fast_float(f, *vars, old=None, expect_one_var=False): EXAMPLES:: sage: from sage.ext.fast_eval import fast_float - sage: x,y = var('x,y') - sage: f = fast_float(sqrt(x^2+y^2), 'x', 'y') - sage: f(3,4) + sage: x,y = var('x,y') # needs sage.symbolic + sage: f = fast_float(sqrt(x^2+y^2), 'x', 'y') # needs sage.symbolic + sage: f(3,4) # needs sage.symbolic 5.0 Specifying the argument names is essential, as fast_float objects only distinguish between arguments by order. :: + sage: # needs sage.symbolic sage: f = fast_float(x-y, 'x','y') sage: f(1,2) -1.0 diff --git a/src/sage/ext/memory.pyx b/src/sage/ext/memory.pyx index 1de6dedab82..b95130b19dd 100644 --- a/src/sage/ext/memory.pyx +++ b/src/sage/ext/memory.pyx @@ -3,14 +3,14 @@ Low-level memory allocation functions TESTS: -Check that a ``MemoryError`` is raised if we try to allocate a +Check that an error is raised if we try to allocate a ridiculously large integer, see :trac:`15363`:: - sage: 2^(2^63-3) - Traceback (most recent call last): - ... - OverflowError: exponent must be at most 2147483647 # 32-bit - RuntimeError: Aborted # 64-bit + sage: try: + ....: 2^(2^63-3) + ....: except (OverflowError, RuntimeError, FloatingPointError): + ....: print ('Overflow error') + ...Overflow error AUTHORS: diff --git a/src/sage/ext/memory_allocator.pxd b/src/sage/ext/memory_allocator.pxd index 5ada54f9535..f96253345f6 100644 --- a/src/sage/ext/memory_allocator.pxd +++ b/src/sage/ext/memory_allocator.pxd @@ -56,7 +56,8 @@ cdef class MemoryAllocator: TESTS:: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' ....: from sage.ext.memory_allocator cimport MemoryAllocator ....: cdef MemoryAllocator mem = MemoryAllocator() ....: cdef void* ptr @@ -64,7 +65,8 @@ cdef class MemoryAllocator: ....: ptr = mem.aligned_malloc(2**i, 4048) ....: assert <size_t> ptr == (<size_t> ptr) & ~(2**i-1) ....: ''') - doctest:...: DeprecationWarning: this class is deprecated; use the class from the python package `memory_allocator` + doctest:...: DeprecationWarning: this class is deprecated; + use the class from the python package `memory_allocator` See https://github.com/sagemath/sage/issues/31591 for details. """ cdef size_t extra = alignment - 1 @@ -85,7 +87,8 @@ cdef class MemoryAllocator: TESTS:: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' ....: from sage.ext.memory_allocator cimport MemoryAllocator ....: def foo(): ....: cdef MemoryAllocator mem = MemoryAllocator() @@ -94,8 +97,9 @@ cdef class MemoryAllocator: ....: ptr = mem.aligned_calloc(2**i, i, 2**i) ....: assert <size_t> ptr == (<size_t> ptr) & ~(2**i-1) ....: ''') - sage: foo() - doctest:...: DeprecationWarning: this class is deprecated; use the class from the python package `memory_allocator` + sage: foo() # needs sage.misc.cython + doctest:...: DeprecationWarning: this class is deprecated; + use the class from the python package `memory_allocator` See https://github.com/sagemath/sage/issues/31591 for details. """ # Find extra such that (nmemb + extra) * size >= nmemb * size + alignment - 1 @@ -120,7 +124,8 @@ cdef class MemoryAllocator: TESTS:: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' ....: from sage.ext.memory_allocator cimport MemoryAllocator ....: def foo(): ....: cdef MemoryAllocator mem = MemoryAllocator() @@ -129,8 +134,8 @@ cdef class MemoryAllocator: ....: ptr = mem.aligned_allocarray(2**i, i, 2**i) ....: assert <size_t> ptr == (<size_t> ptr) & ~(2**i-1) ....: ''') - sage: foo() # random # might raise deprecation warning - sage: foo() + sage: foo() # random # might raise deprecation warning # needs sage.misc.cython + sage: foo() # needs sage.misc.cython """ # Find extra such that (nmemb + extra) * size >= nmemb * size + alignment - 1 # โ‡” extra * size >= alignment - 1 diff --git a/src/sage/ext/memory_allocator.pyx b/src/sage/ext/memory_allocator.pyx index 1f271a3e82e..0c2814658e9 100644 --- a/src/sage/ext/memory_allocator.pyx +++ b/src/sage/ext/memory_allocator.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.misc.cython +# sage.doctest: needs sage.misc.cython from cysignals.memory cimport * from sage.misc.superseded import deprecation diff --git a/src/sage/ext/stdsage.pxd b/src/sage/ext/stdsage.pxd index 15abe13b7cd..e2bf7434f35 100644 --- a/src/sage/ext/stdsage.pxd +++ b/src/sage/ext/stdsage.pxd @@ -10,7 +10,7 @@ Standard C helper code for Cython modules # http://www.gnu.org/licenses/ #***************************************************************************** -from cpython.object cimport Py_TYPE, PyTypeObject +from cpython.object cimport Py_TYPE, PyTypeObject, PyObject cdef inline PY_NEW(type t): @@ -19,7 +19,7 @@ cdef inline PY_NEW(type t): :class:`Integer` where we change ``tp_new`` at runtime (Cython optimizations assume that ``tp_new`` doesn't change). """ - return (<PyTypeObject*>t).tp_new(t, <object>NULL, <object>NULL) + return (<PyTypeObject*>t).tp_new(t, <PyObject*>NULL, <PyObject*>NULL) cdef inline void PY_SET_TP_NEW(type dst, type src): diff --git a/src/sage/ext_data/valgrind/valgrind-python.supp b/src/sage/ext_data/valgrind/valgrind-python.supp new file mode 100644 index 00000000000..16aa2858484 --- /dev/null +++ b/src/sage/ext_data/valgrind/valgrind-python.supp @@ -0,0 +1,480 @@ +# From the CPython repository with the suppressions for _PyObject_Free +# and _PyObject_Realloc enabled. See the upstream suppression file for +# details: +# +# https://github.com/python/cpython/blob/main/Misc/valgrind-python.supp + +# all tool names: Addrcheck,Memcheck,cachegrind,helgrind,massif +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Addr4 + fun:address_in_range +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Value4 + fun:address_in_range +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 8 (x86_64 aka amd64) + Memcheck:Value8 + fun:address_in_range +} + +{ + ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value + Memcheck:Cond + fun:address_in_range +} + +# +# Leaks (including possible leaks) +# Hmmm, I wonder if this masks some real leaks. I think it does. +# Will need to fix that. +# + +{ + Suppress leaking the GIL after a fork. + Memcheck:Leak + fun:malloc + fun:PyThread_allocate_lock + fun:PyEval_ReInitThreads +} + +{ + Suppress leaking the autoTLSkey. This looks like it shouldn't leak though. + Memcheck:Leak + fun:malloc + fun:PyThread_create_key + fun:_PyGILState_Init + fun:Py_InitializeEx + fun:Py_Main +} + +{ + Hmmm, is this a real leak or like the GIL? + Memcheck:Leak + fun:malloc + fun:PyThread_ReInitTLS +} + +{ + Handle PyMalloc confusing valgrind (possibly leaked) + Memcheck:Leak + fun:realloc + fun:_PyObject_GC_Resize + fun:COMMENT_THIS_LINE_TO_DISABLE_LEAK_WARNING +} + +{ + Handle PyMalloc confusing valgrind (possibly leaked) + Memcheck:Leak + fun:malloc + fun:_PyObject_GC_New + fun:COMMENT_THIS_LINE_TO_DISABLE_LEAK_WARNING +} + +{ + Handle PyMalloc confusing valgrind (possibly leaked) + Memcheck:Leak + fun:malloc + fun:_PyObject_GC_NewVar + fun:COMMENT_THIS_LINE_TO_DISABLE_LEAK_WARNING +} + +# +# Non-python specific leaks +# + +{ + Handle pthread issue (possibly leaked) + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate_tls_storage + fun:_dl_allocate_tls +} + +{ + Handle pthread issue (possibly leaked) + Memcheck:Leak + fun:memalign + fun:_dl_allocate_tls_storage + fun:_dl_allocate_tls +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Addr4 + fun:_PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Value4 + fun:_PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Use of uninitialised value of size 8 + Memcheck:Addr8 + fun:_PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Use of uninitialised value of size 8 + Memcheck:Value8 + fun:_PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value + Memcheck:Cond + fun:_PyObject_Free +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Addr4 + fun:_PyObject_Realloc +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Value4 + fun:_PyObject_Realloc +} + +{ + ADDRESS_IN_RANGE/Use of uninitialised value of size 8 + Memcheck:Addr8 + fun:_PyObject_Realloc +} + +{ + ADDRESS_IN_RANGE/Use of uninitialised value of size 8 + Memcheck:Value8 + fun:_PyObject_Realloc +} + +{ + ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value + Memcheck:Cond + fun:_PyObject_Realloc +} + +### +### All the suppressions below are for errors that occur within libraries +### that Python uses. The problems to not appear to be related to Python's +### use of the libraries. +### + +{ + Generic ubuntu ld problems + Memcheck:Addr8 + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so +} + +{ + Generic gentoo ld problems + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so +} + +{ + DBM problems, see test_dbm + Memcheck:Param + write(buf) + fun:write + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + fun:dbm_close +} + +{ + DBM problems, see test_dbm + Memcheck:Value8 + fun:memmove + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + fun:dbm_store + fun:dbm_ass_sub +} + +{ + DBM problems, see test_dbm + Memcheck:Cond + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + fun:dbm_store + fun:dbm_ass_sub +} + +{ + DBM problems, see test_dbm + Memcheck:Cond + fun:memmove + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + fun:dbm_store + fun:dbm_ass_sub +} + +{ + GDBM problems, see test_gdbm + Memcheck:Param + write(buf) + fun:write + fun:gdbm_open + +} + +{ + Uninitialised byte(s) false alarm, see bpo-35561 + Memcheck:Param + epoll_ctl(event) + fun:epoll_ctl + fun:pyepoll_internal_ctl +} + +{ + ZLIB problems, see test_gzip + Memcheck:Cond + obj:/lib/libz.so.1.2.3 + obj:/lib/libz.so.1.2.3 + fun:deflate +} + +{ + Avoid problems w/readline doing a putenv and leaking on exit + Memcheck:Leak + fun:malloc + fun:xmalloc + fun:sh_set_lines_and_columns + fun:_rl_get_screen_size + fun:_rl_init_terminal_io + obj:/lib/libreadline.so.4.3 + fun:rl_initialize +} + +# Valgrind emits "Conditional jump or move depends on uninitialised value(s)" +# false alarms on GCC builtin strcmp() function. The GCC code is correct. +# +# Valgrind bug: https://bugs.kde.org/show_bug.cgi?id=264936 +{ + bpo-38118: Valgrind emits false alarm on GCC builtin strcmp() + Memcheck:Cond + fun:PyUnicode_Decode +} + + +### +### These occur from somewhere within the SSL, when running +### test_socket_sll. They are too general to leave on by default. +### +###{ +### somewhere in SSL stuff +### Memcheck:Cond +### fun:memset +###} +###{ +### somewhere in SSL stuff +### Memcheck:Value4 +### fun:memset +###} +### +###{ +### somewhere in SSL stuff +### Memcheck:Cond +### fun:MD5_Update +###} +### +###{ +### somewhere in SSL stuff +### Memcheck:Value4 +### fun:MD5_Update +###} + +# Fedora's package "openssl-1.0.1-0.1.beta2.fc17.x86_64" on x86_64 +# See http://bugs.python.org/issue14171 +{ + openssl 1.0.1 prng 1 + Memcheck:Cond + fun:bcmp + fun:fips_get_entropy + fun:FIPS_drbg_instantiate + fun:RAND_init_fips + fun:OPENSSL_init_library + fun:SSL_library_init + fun:init_hashlib +} + +{ + openssl 1.0.1 prng 2 + Memcheck:Cond + fun:fips_get_entropy + fun:FIPS_drbg_instantiate + fun:RAND_init_fips + fun:OPENSSL_init_library + fun:SSL_library_init + fun:init_hashlib +} + +{ + openssl 1.0.1 prng 3 + Memcheck:Value8 + fun:_x86_64_AES_encrypt_compact + fun:AES_encrypt +} + +# +# All of these problems come from using test_socket_ssl +# +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_bin2bn +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_num_bits_word +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:BN_num_bits_word +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_mod_exp_mont_word +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_mod_exp_mont +} + +{ + from test_socket_ssl + Memcheck:Param + write(buf) + fun:write + obj:/usr/lib/libcrypto.so.0.9.7 +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:RSA_verify +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:RSA_verify +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:DES_set_key_unchecked +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:DES_encrypt2 +} + +{ + from test_socket_ssl + Memcheck:Cond + obj:/usr/lib/libssl.so.0.9.7 +} + +{ + from test_socket_ssl + Memcheck:Value4 + obj:/usr/lib/libssl.so.0.9.7 +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BUF_MEM_grow_clean +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:memcpy + fun:ssl3_read_bytes +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:SHA1_Update +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:SHA1_Update +} + +{ + test_buffer_non_debug + Memcheck:Addr4 + fun:PyUnicodeUCS2_FSConverter +} + +{ + test_buffer_non_debug + Memcheck:Addr4 + fun:PyUnicode_FSConverter +} + +{ + wcscmp_false_positive + Memcheck:Addr8 + fun:wcscmp + fun:_PyOS_GetOpt + fun:Py_Main + fun:main +} + +# Additional suppressions for the unified decimal tests: +{ + test_decimal + Memcheck:Addr4 + fun:PyUnicodeUCS2_FSConverter +} + +{ + test_decimal2 + Memcheck:Addr4 + fun:PyUnicode_FSConverter +} + diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index cb2e2a085c3..89a7b184a4c 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -52,6 +52,19 @@ As can be seen above, features try to produce helpful error messages. """ +# ***************************************************************************** +# Copyright (C) 2016 Julian Rรผth +# 2018 Jeroen Demeyer +# 2018 Timo Kaufmann +# 2019-2022 Matthias Koeppe +# 2021 Kwankyu Lee +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from __future__ import annotations import os @@ -74,8 +87,10 @@ def __call__(cls, *args, **kwds): else: return type.__call__(cls, *args, **kwds) + _trivial_unique_representation_cache = dict() + class TrivialUniqueRepresentation(metaclass=TrivialClasscallMetaClass): r""" A trivial version of :class:`UniqueRepresentation` without Cython dependencies. @@ -92,6 +107,7 @@ def __classcall__(cls, *args, **options): cached = _trivial_unique_representation_cache[key] = type.__call__(cls, *args, **options) return cached + class Feature(TrivialUniqueRepresentation): r""" A feature of the runtime environment @@ -108,6 +124,8 @@ class Feature(TrivialUniqueRepresentation): - ``url`` -- a URL for the upstream package providing the feature + - ``type`` -- (string) one of ``'standard'``, ``'optional'`` (default), ``'experimental'`` + Overwrite :meth:`_is_present` to add feature checks. EXAMPLES:: @@ -121,7 +139,7 @@ class Feature(TrivialUniqueRepresentation): sage: GapPackage("grape") is GapPackage("grape") True """ - def __init__(self, name, spkg=None, url=None, description=None): + def __init__(self, name, spkg=None, url=None, description=None, type='optional'): r""" TESTS:: @@ -137,6 +155,20 @@ def __init__(self, name, spkg=None, url=None, description=None): self._cache_is_present = None self._cache_resolution = None + self._hidden = False + self._type = type + + try: + from sage.misc.package import spkg_type + except ImportError: # may have been surgically removed in a downstream distribution + pass + else: + if spkg and (t := spkg_type(spkg)) not in (type, None): + from warnings import warn + warn(f'Feature {name} is declared {type}, ' + f'but it is provided by {spkg}, ' + f'which is declared {t} in SAGE_ROOT/build/pkgs', + stacklevel=3) def is_present(self): r""" @@ -173,6 +205,8 @@ def is_present(self): sage: TestFeature("other").is_present() FeatureTestResult('other', True) """ + if self._hidden: + return FeatureTestResult(self, False, reason="Feature `{name}` is hidden.".format(name=self.name)) # We do not use @cached_method here because we wish to use # Feature early in the build system of sagelib. if self._cache_is_present is None: @@ -198,7 +232,7 @@ def require(self): EXAMPLES:: sage: from sage.features.gap import GapPackage - sage: GapPackage("ve1EeThu").require() + sage: GapPackage("ve1EeThu").require() # needs sage.libs.gap Traceback (most recent call last): ... FeatureNotPresentError: gap_package_ve1EeThu is not available. @@ -225,6 +259,25 @@ def __repr__(self): description = f'{self.name!r}: {self.description}' if self.description else f'{self.name!r}' return f'Feature({description})' + def _spkg_type(self): + r""" + Return the type of this feature. + + For features provided by an SPKG in the Sage distribution, + this should match the SPKG type, or a warning will be issued. + + EXAMPLES:: + + sage: from sage.features.databases import DatabaseCremona + sage: DatabaseCremona()._spkg_type() + 'optional' + + OUTPUT: + + The type as a string in ``('base', 'standard', 'optional', 'experimental')``. + """ + return self._type + def resolution(self): r""" Return a suggestion on how to make :meth:`is_present` pass if it did not @@ -240,6 +293,8 @@ def resolution(self): sage: Executable(name="CSDP", spkg="csdp", executable="theta", url="https://github.com/dimpase/csdp").resolution() # optional - sage_spkg '...To install CSDP...you can try to run...sage -i csdp...Further installation instructions might be available at https://github.com/dimpase/csdp.' """ + if self._hidden: + return "Use method `unhide` to make it available again." if self._cache_resolution is not None: return self._cache_resolution lines = [] @@ -251,7 +306,117 @@ def resolution(self): self._cache_resolution = "\n".join(lines) return self._cache_resolution + def joined_features(self): + r""" + Return a list of features that ``self`` is the join of. + + OUTPUT: + + A (possibly empty) list of instances of :class:`Feature`. + + EXAMPLES:: + + sage: from sage.features.graphviz import Graphviz + sage: Graphviz().joined_features() + [Feature('dot'), Feature('neato'), Feature('twopi')] + sage: from sage.features.sagemath import sage__rings__function_field + sage: sage__rings__function_field().joined_features() + [Feature('sage.rings.function_field.function_field_polymod'), + Feature('sage.libs.singular'), + Feature('sage.libs.singular.singular'), + Feature('sage.interfaces.singular')] + sage: from sage.features.interfaces import Mathematica + sage: Mathematica().joined_features() + [] + """ + from sage.features.join_feature import JoinFeature + res = [] + if isinstance(self, JoinFeature): + for f in self._features: + res += [f] + f.joined_features() + return res + + def is_standard(self): + r""" + Return whether this feature corresponds to a standard SPKG. + + EXAMPLES:: + sage: from sage.features.databases import DatabaseCremona, DatabaseConwayPolynomials + sage: DatabaseCremona().is_standard() + False + sage: DatabaseConwayPolynomials().is_standard() + True + """ + if self.name.startswith('sage.'): + return True + return self._spkg_type() == 'standard' + + def is_optional(self): + r""" + Return whether this feature corresponds to an optional SPKG. + + EXAMPLES:: + + sage: from sage.features.databases import DatabaseCremona, DatabaseConwayPolynomials + sage: DatabaseCremona().is_optional() + True + sage: DatabaseConwayPolynomials().is_optional() + False + """ + return self._spkg_type() == 'optional' + + def hide(self): + r""" + Hide this feature. For example this is used when the doctest option + ``--hide`` is set. Setting an installed feature as hidden pretends + that it is not available. To revert this use :meth:`unhide`. + + EXAMPLES: + + Benzene is an optional SPKG. The following test fails if it is hidden or + not installed. Thus, in the second invocation the optional tag is needed:: + + sage: from sage.features.graph_generators import Benzene + sage: Benzene().hide() + sage: len(list(graphs.fusenes(2))) # needs sage.graphs + Traceback (most recent call last): + ... + FeatureNotPresentError: benzene is not available. + Feature `benzene` is hidden. + Use method `unhide` to make it available again. + + sage: Benzene().unhide() + sage: len(list(graphs.fusenes(2))) # optional - benzene, needs sage.graphs + 1 + """ + self._hidden = True + + def unhide(self): + r""" + Revert what :meth:`hide` does. + + EXAMPLES: + + Polycyclic is a standard GAP package since 4.10 (see :trac:`26856`). The + following test just fails if it is hidden. Thus, in the second + invocation no optional tag is needed:: + + sage: from sage.features.gap import GapPackage + sage: Polycyclic = GapPackage("polycyclic", spkg="gap_packages") + sage: Polycyclic.hide() + sage: libgap(AbelianGroup(3, [0,3,4], names="abc")) # needs sage.libs.gap + Traceback (most recent call last): + ... + FeatureNotPresentError: gap_package_polycyclic is not available. + Feature `gap_package_polycyclic` is hidden. + Use method `unhide` to make it available again. + + sage: Polycyclic.unhide() + sage: libgap(AbelianGroup(3, [0,3,4], names="abc")) # needs sage.libs.gap + Pcp-group with orders [ 0, 3, 4 ] + """ + self._hidden = False class FeatureNotPresentError(RuntimeError): r""" @@ -287,7 +452,7 @@ def __str__(self): EXAMPLES:: sage: from sage.features.gap import GapPackage - sage: GapPackage("gapZuHoh8Uu").require() # indirect doctest + sage: GapPackage("gapZuHoh8Uu").require() # indirect doctest # needs sage.libs.gap Traceback (most recent call last): ... FeatureNotPresentError: gap_package_gapZuHoh8Uu is not available. @@ -320,7 +485,7 @@ class FeatureTestResult(): Explanatory messages might be available as ``reason`` and ``resolution``:: - sage: presence.reason + sage: presence.reason # needs sage.libs.gap '`TestPackageAvailability("NOT_A_PACKAGE")` evaluated to `fail` in GAP.' sage: bool(presence.resolution) False @@ -670,7 +835,9 @@ def absolute_filename(self) -> str: A :class:`FeatureNotPresentError` is raised if the file cannot be found:: sage: from sage.features import StaticFile - sage: StaticFile(name="no_such_file", filename="KaT1aihu", search_path=(), spkg="some_spkg", url="http://rand.om").absolute_filename() # optional - sage_spkg + sage: StaticFile(name="no_such_file", filename="KaT1aihu",\ + search_path=(), spkg="some_spkg",\ + url="http://rand.om").absolute_filename() # optional - sage_spkg Traceback (most recent call last): ... FeatureNotPresentError: no_such_file is not available. @@ -682,9 +849,8 @@ def absolute_filename(self) -> str: path = os.path.join(directory, self.filename) if os.path.isfile(path) or os.path.isdir(path): return os.path.abspath(path) - raise FeatureNotPresentError(self, - reason="{filename!r} not found in any of {search_path}".format(filename=self.filename, search_path=self.search_path), - resolution=self.resolution()) + reason = "{filename!r} not found in any of {search_path}".format(filename=self.filename, search_path=self.search_path) + raise FeatureNotPresentError(self, reason=reason, resolution=self.resolution()) class CythonFeature(Feature): @@ -704,8 +870,10 @@ class CythonFeature(Feature): ....: ....: assert fabs(-1) == 1 ....: ''' - sage: fabs = CythonFeature("fabs", test_code=fabs_test_code, spkg="gcc", url="https://gnu.org") - sage: fabs.is_present() + sage: fabs = CythonFeature("fabs", test_code=fabs_test_code, # needs sage.misc.cython + ....: spkg="gcc", url="https://gnu.org", + ....: type="standard") + sage: fabs.is_present() # needs sage.misc.cython FeatureTestResult('fabs', True) Test various failures:: @@ -756,7 +924,7 @@ def _is_present(self): sage: from sage.features import CythonFeature sage: empty = CythonFeature("empty", test_code="") - sage: empty.is_present() + sage: empty.is_present() # needs sage.misc.cython FeatureTestResult('empty', True) """ from sage.misc.temporary_file import tmp_filename @@ -769,6 +937,9 @@ def _is_present(self): pyx.write(self.test_code) try: from sage.misc.cython import cython_import + except ImportError: + return FeatureTestResult(self, False, reason="sage.misc.cython is not available") + try: cython_import(pyx.name, verbose=-1) except CCompilerError: return FeatureTestResult(self, False, reason="Failed to compile test code.") diff --git a/src/sage/features/all.py b/src/sage/features/all.py index 2ec0c267b83..599bc575dd7 100644 --- a/src/sage/features/all.py +++ b/src/sage/features/all.py @@ -2,6 +2,18 @@ Enumeration of all defined features """ +# ***************************************************************************** +# Copyright (C) 2021-2023 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + +import itertools + + def all_features(): r""" Return an iterable of all features. @@ -25,3 +37,89 @@ def all_features(): else: if af != all_features: yield from af() + + +def module_feature(module_name): + r""" + Find a top-level :class:`Feature` that provides the Python module of the given ``module_name``. + + Only features known to :func:`all_features` are considered. + + INPUT: + + - ``module_name`` -- string + + OUTPUT: a :class:`Feature` or ``None``. + + EXAMPLES:: + + sage: from sage.features.all import module_feature + sage: module_feature('sage.combinat.tableau') # needs sage.combinat + Feature('sage.combinat') + sage: module_feature('sage.combinat.posets.poset') # needs sage.graphs + Feature('sage.graphs') + sage: module_feature('sage.schemes.toric.variety') # needs sage.geometry.polyhedron + Feature('sage.geometry.polyhedron') + sage: module_feature('scipy') # needs scipy + Feature('scipy') + sage: print(module_feature('sage.structure.element')) + None + sage: print(module_feature('sage.does_not_exist')) + None + """ + longest_prefix = '' + longest_prefix_feature = None + for feature in all_features(): + for joined in itertools.chain([feature], feature.joined_features()): + if joined.name == module_name: + return feature + if (joined.name + '.').startswith(longest_prefix): + if (module_name + '.').startswith(joined.name + '.'): + longest_prefix = feature.name + '.' + longest_prefix_feature = feature + return longest_prefix_feature + + +def name_feature(name, toplevel=None): + r""" + Find a top-level :class:`Feature` that provides the top-level ``name``. + + Only features known to :func:`all_features` are considered. + + INPUT: + + - ``name`` -- string + + - ``toplevel`` -- a module or other namespace + + OUTPUT: a :class:`Feature` or ``None``. + + EXAMPLES:: + + sage: from sage.features.all import name_feature + sage: name_feature('QuadraticField') # needs sage.rings.number_field + Feature('sage.rings.number_field') + sage: name_feature('line') # needs sage.plot + Feature('sage.plot') + sage: print(name_feature('ZZ')) + None + sage: print(name_feature('does_not_exist')) + None + """ + if toplevel is None: + try: + import sage.all as toplevel + except ImportError: + return None + try: + obj = getattr(toplevel, name) + except AttributeError: + return None + + from sage.misc.dev_tools import find_object_modules + + for module, names in find_object_modules(obj).items(): + if name in names and (feature := module_feature(module)): + return feature + + return None diff --git a/src/sage/features/bliss.py b/src/sage/features/bliss.py index e8efd3e8f97..37fc4d7f8c3 100644 --- a/src/sage/features/bliss.py +++ b/src/sage/features/bliss.py @@ -1,7 +1,18 @@ -# -*- coding: utf-8 -*- r""" Features for testing the presence of ``bliss`` """ + +# ***************************************************************************** +# Copyright (C) 2016 Julian Rรผth +# 2018 Jeroen Demeyer +# 2021 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import CythonFeature, PythonModule from .join_feature import JoinFeature @@ -24,7 +35,7 @@ class BlissLibrary(CythonFeature): r""" - A :class:`~sage.features.Feature` which describes whether the Bliss library is + A :class:`~sage.features.Feature` which describes whether the :ref:`Bliss library <spkg_bliss>` is present and functional. EXAMPLES:: diff --git a/src/sage/features/cddlib.py b/src/sage/features/cddlib.py index 59a72a2120f..b8fdb6fed8e 100644 --- a/src/sage/features/cddlib.py +++ b/src/sage/features/cddlib.py @@ -1,13 +1,23 @@ r""" Feature for testing the presence of ``cddlib`` """ + +# ***************************************************************************** +# Copyright (C) 2022 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import Executable class CddExecutable(Executable): r""" A :class:`~sage.features.Feature` describing the presence of an executable - which comes as a part of ``cddlib``. + which comes as a part of :ref:`cddlib <spkg_cddlib>`. EXAMPLES:: @@ -24,4 +34,4 @@ def __init__(self, name='cddexec_gmp'): True """ Executable.__init__(self, name=name, executable=name, spkg="cddlib", - url="https://github.com/cddlib/cddlib") + url="https://github.com/cddlib/cddlib", type="standard") diff --git a/src/sage/features/csdp.py b/src/sage/features/csdp.py index e86ec415d09..e8aa55e50ea 100644 --- a/src/sage/features/csdp.py +++ b/src/sage/features/csdp.py @@ -3,6 +3,18 @@ Feature for testing the presence of ``csdp`` """ +# ***************************************************************************** +# Copyright (C) 2016 Julian Rรผth +# 2018 Jeroen Demeyer +# 2019 David Coudert +# 2021 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + import os import re import subprocess @@ -13,7 +25,7 @@ class CSDP(Executable): r""" A :class:`~sage.features.Feature` which checks for the ``theta`` binary - of CSDP. + of :ref:`CSDP <spkg_csdp>`. EXAMPLES:: diff --git a/src/sage/features/cython.py b/src/sage/features/cython.py index f537843f4f4..8f03155ac2f 100644 --- a/src/sage/features/cython.py +++ b/src/sage/features/cython.py @@ -1,8 +1,16 @@ -# -*- coding: utf-8 -*- r""" Features for testing the presence of ``cython`` """ +# ***************************************************************************** +# Copyright (C) 2021 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import CythonFeature diff --git a/src/sage/features/databases.py b/src/sage/features/databases.py index d1e77a8ff32..f9b297b1e30 100644 --- a/src/sage/features/databases.py +++ b/src/sage/features/databases.py @@ -1,8 +1,21 @@ -# -*- coding: utf-8 -*- r""" Features for testing the presence of various databases """ +# ***************************************************************************** +# Copyright (C) 2016 Julian Rรผth +# 2018-2019 Jeroen Demeyer +# 2018 Timo Kaufmann +# 2020-2022 Matthias Koeppe +# 2020-2022 Sebastian Oehms +# 2021 Kwankyu Lee +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import StaticFile, PythonModule from sage.env import ( @@ -13,8 +26,8 @@ class DatabaseConwayPolynomials(StaticFile): r""" - A :class:`~sage.features.Feature` which describes the presence of Frank Luebeck's - database of Conway polynomials. + A :class:`~sage.features.Feature` which describes the presence of :ref:`Frank Luebeck's + database of Conway polynomials <spkg_conway_polynomials>`. EXAMPLES:: @@ -39,7 +52,8 @@ def __init__(self): filename='conway_polynomials.p', search_path=search_path, spkg='conway_polynomials', - description="Frank Luebeck's database of Conway polynomials") + description="Frank Luebeck's database of Conway polynomials", + type='standard') CREMONA_DATA_DIRS = set([CREMONA_MINI_DATA_DIR, CREMONA_LARGE_DATA_DIR]) @@ -47,8 +61,8 @@ def __init__(self): class DatabaseCremona(StaticFile): r""" - A :class:`~sage.features.Feature` which describes the presence of John Cremona's - database of elliptic curves. + A :class:`~sage.features.Feature` which describes the presence of :ref:`John Cremona's + database of elliptic curves <spkg_database_cremona_ellcurve>`. INPUT: @@ -60,7 +74,7 @@ class DatabaseCremona(StaticFile): sage: from sage.features.databases import DatabaseCremona sage: DatabaseCremona('cremona_mini').is_present() FeatureTestResult('database_cremona_mini_ellcurve', True) - sage: DatabaseCremona().is_present() # optional - database_cremona_ellcurve + sage: DatabaseCremona().is_present() # optional - database_cremona_ellcurve FeatureTestResult('database_cremona_ellcurve', True) """ def __init__(self, name="cremona", spkg="database_cremona_ellcurve"): @@ -81,7 +95,8 @@ def __init__(self, name="cremona", spkg="database_cremona_ellcurve"): class DatabaseJones(StaticFile): r""" - A :class:`~sage.features.Feature` which describes the presence of John Jones's tables of number fields. + A :class:`~sage.features.Feature` which describes the presence of + :ref:`John Jones's tables of number fields <spkg_database_jones_numfield>`. EXAMPLES:: @@ -105,12 +120,13 @@ def __init__(self): class DatabaseKnotInfo(PythonModule): r""" - A :class:`~sage.features.Feature` which describes the presence of the databases at the + A :class:`~sage.features.Feature` which describes the presence of the + :ref:`package providing the KnotInfo and LinkInfo databases <spkg_database_knotinfo>`. + + The homes of these databases are the web-pages `KnotInfo <https://knotinfo.math.indiana.edu/>`__ and `LinkInfo <https://linkinfo.sitehost.iu.edu>`__. - - EXAMPLES:: sage: from sage.features.databases import DatabaseKnotInfo @@ -127,9 +143,13 @@ def __init__(self): """ PythonModule.__init__(self, 'database_knotinfo', spkg='database_knotinfo') + class DatabaseCubicHecke(PythonModule): r""" - A :class:`~sage.features.Feature` which describes the presence of the databases at the + A :class:`~sage.features.Feature` which describes the presence of the + :ref:`Cubic Hecke algebra database package <spkg_database_cubic_hecke>`. + + The home of this database is the web-page `Cubic Hecke algebra on 4 strands <http://www.lamfa.u-picardie.fr/marin/representationH4-en.html>`__ of Ivan Marin. @@ -149,10 +169,12 @@ def __init__(self): """ PythonModule.__init__(self, 'database_cubic_hecke', spkg='database_cubic_hecke') + class DatabaseReflexivePolytopes(StaticFile): r""" - A :class:`~sage.features.Feature` which describes the presence of the PALP database - of reflexive lattice polytopes. + A :class:`~sage.features.Feature` which describes the presence of the + :ref:`PALP databases of reflexive three-dimensional <spkg_polytopes_db>` + and :ref:`four-dimensional lattice polytopes <spkg_polytopes_db_4d>`. EXAMPLES:: diff --git a/src/sage/features/dvipng.py b/src/sage/features/dvipng.py index 44ef6c7074a..281084a6e72 100644 --- a/src/sage/features/dvipng.py +++ b/src/sage/features/dvipng.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Feature for testing the presence of ``dvipng`` """ diff --git a/src/sage/features/ffmpeg.py b/src/sage/features/ffmpeg.py index bb708478251..36a23594162 100644 --- a/src/sage/features/ffmpeg.py +++ b/src/sage/features/ffmpeg.py @@ -1,9 +1,8 @@ -# -*- coding: utf-8 -*- r""" Feature for testing the presence of ``ffmpeg`` """ # **************************************************************************** -# Copyright (C) 2018 Sebastien Labbe <slabqc@gmail.com> +# Copyright (C) 2018-2022 Sebastien Labbe <slabqc@gmail.com> # # 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 @@ -16,7 +15,7 @@ class FFmpeg(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``ffmpeg`` + A :class:`~sage.features.Feature` describing the presence of :ref:`ffmpeg <spkg_ffmpeg>`. EXAMPLES:: diff --git a/src/sage/features/four_ti_2.py b/src/sage/features/four_ti_2.py index e898f601599..2af1c1e25d2 100644 --- a/src/sage/features/four_ti_2.py +++ b/src/sage/features/four_ti_2.py @@ -8,7 +8,7 @@ class FourTi2Executable(Executable): r""" - A :class:`~sage.features.Feature` for the 4ti2 executables. + A :class:`~sage.features.Feature` for the :ref:`4ti2 <spkg_4ti2>` executables. """ def __init__(self, name): r""" @@ -27,7 +27,7 @@ def __init__(self, name): class FourTi2(JoinFeature): r""" - A :class:`~sage.features.Feature` describing the presence of the ``4ti2`` executables. + A :class:`~sage.features.Feature` describing the presence of all :ref:`4ti2 <spkg_4ti2>` executables. EXAMPLES:: diff --git a/src/sage/features/gap.py b/src/sage/features/gap.py index 20add30c114..a989dcfc1fb 100644 --- a/src/sage/features/gap.py +++ b/src/sage/features/gap.py @@ -1,15 +1,28 @@ -# -*- coding: utf-8 -*- r""" -Features for testing the presence of GAP packages +Features for testing the presence of the SageMath interfaces to ``gap`` and of GAP packages """ +# ***************************************************************************** +# Copyright (C) 2016 Julian Rรผth +# 2018 Jeroen Demeyer +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** -from . import Feature, FeatureTestResult - +from . import Feature, FeatureTestResult, PythonModule +from .join_feature import JoinFeature +from .sagemath import sage__libs__gap class GapPackage(Feature): r""" A :class:`~sage.features.Feature` describing the presence of a GAP package. + .. SEEALSO:: + + :class:`Feature sage.libs.gap <~sage.features.sagemath.sage__libs__gap>` + EXAMPLES:: sage: from sage.features.gap import GapPackage @@ -39,7 +52,11 @@ def _is_present(self): sage: GapPackage("grape", spkg="gap_packages")._is_present() # optional - gap_packages FeatureTestResult('gap_package_grape', True) """ - from sage.libs.gap.libgap import libgap + try: + from sage.libs.gap.libgap import libgap + except ImportError: + return FeatureTestResult(self, False, + reason="sage.libs.gap is not available") command = 'TestPackageAvailability("{package}")'.format(package=self.package) presence = libgap.eval(command) if presence: @@ -48,3 +65,14 @@ def _is_present(self): else: return FeatureTestResult(self, False, reason="`{command}` evaluated to `{presence}` in GAP.".format(command=command, presence=presence)) + + +def all_features(): + return [GapPackage("atlasrep", spkg="gap_packages"), + GapPackage("design", spkg="gap_packages"), + GapPackage("grape", spkg="gap_packages"), + GapPackage("guava", spkg="gap_packages"), + GapPackage("hap", spkg="gap_packages"), + GapPackage("polycyclic", spkg="gap_packages"), + GapPackage("qpa", spkg="gap_packages"), + GapPackage("quagroup", spkg="gap_packages")] diff --git a/src/sage/features/gfan.py b/src/sage/features/gfan.py index 6551ca5340c..a58090b4c91 100644 --- a/src/sage/features/gfan.py +++ b/src/sage/features/gfan.py @@ -2,12 +2,21 @@ Features for testing the presence of ``gfan`` """ +# ***************************************************************************** +# Copyright (C) 2022 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import Executable class GfanExecutable(Executable): r""" - A :class:`~sage.features.Feature` for the gfan executables. + A :class:`~sage.features.Feature` for the :ref:`gfan <spkg_gfan>` executables. """ def __init__(self, cmd=None): r""" @@ -21,7 +30,7 @@ def __init__(self, cmd=None): name = "gfan" else: name = f"gfan_{cmd}" - Executable.__init__(self, name, executable=name, spkg="gfan") + Executable.__init__(self, name, executable=name, spkg="gfan", type='standard') def all_features(): diff --git a/src/sage/features/graph_generators.py b/src/sage/features/graph_generators.py index 0ecd63bad76..47c4557241c 100644 --- a/src/sage/features/graph_generators.py +++ b/src/sage/features/graph_generators.py @@ -1,8 +1,20 @@ -# -*- coding: utf-8 -*- r""" -Features for testing the presence of various graph generator programs +Features for testing the presence of graph generator programs ``benzene``, ``buckygen``, ``plantri`` """ +# ***************************************************************************** +# Copyright (C) 2016 Julian Rรผth +# 2018 Jeroen Demeyer +# 2019 Frรฉdรฉric Chapoton +# 2021 Matthias Koeppe +# 2021 Kwankyu Lee +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + import os import subprocess @@ -11,7 +23,7 @@ class Plantri(Executable): r""" - A :class:`~sage.features.Feature` which checks for the ``plantri`` binary. + A :class:`~sage.features.Feature` which checks for the :ref:`plantri <spkg_plantri>` binary. EXAMPLES:: @@ -58,7 +70,7 @@ def is_functional(self): class Buckygen(Executable): r""" - A :class:`~sage.features.Feature` which checks for the ``buckygen`` binary. + A :class:`~sage.features.Feature` which checks for the :ref:`buckygen <spkg_buckygen>` binary. EXAMPLES:: @@ -105,7 +117,7 @@ def is_functional(self): class Benzene(Executable): r""" - A :class:`~sage.features.Feature` which checks for the ``benzene`` + A :class:`~sage.features.Feature` which checks for the :ref:`benzene <spkg_benzene>` binary. EXAMPLES:: diff --git a/src/sage/features/graphviz.py b/src/sage/features/graphviz.py index 0a0c8ba88e9..abf9b7615fa 100644 --- a/src/sage/features/graphviz.py +++ b/src/sage/features/graphviz.py @@ -1,9 +1,10 @@ -# -*- coding: utf-8 -*- r""" Features for testing the presence of ``graphviz`` """ + # **************************************************************************** # Copyright (C) 2018 Sebastien Labbe <slabqc@gmail.com> +# 2021 Matthias Koeppe # # 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 @@ -11,15 +12,16 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** + from . import Executable from .join_feature import JoinFeature class dot(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``dot`` + A :class:`~sage.features.Feature` describing the presence of ``dot``. - EXAMPLES:: + TESTS:: sage: from sage.features.graphviz import dot sage: dot().is_present() # optional - graphviz @@ -40,9 +42,9 @@ def __init__(self): class neato(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``neato`` + A :class:`~sage.features.Feature` describing the presence of ``neato``. - EXAMPLES:: + TESTS: sage: from sage.features.graphviz import neato sage: neato().is_present() # optional - graphviz @@ -63,9 +65,9 @@ def __init__(self): class twopi(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``twopi`` + A :class:`~sage.features.Feature` describing the presence of ``twopi``. - EXAMPLES:: + TESTS:: sage: from sage.features.graphviz import twopi sage: twopi().is_present() # optional - graphviz @@ -87,8 +89,8 @@ def __init__(self): class Graphviz(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of - the ``dot``, ``neato``, and ``twopi`` executables from the - ``graphviz`` package. + the :class:`dot`, :class:`neato`, and :class:`twopi` executables from the + :ref:`graphviz <spkg_graphviz>` package. EXAMPLES:: diff --git a/src/sage/features/igraph.py b/src/sage/features/igraph.py index 04ac4efbb54..bcf81f9cec7 100644 --- a/src/sage/features/igraph.py +++ b/src/sage/features/igraph.py @@ -1,6 +1,17 @@ r""" Check for igraph """ + +# **************************************************************************** +# Copyright (C) 2021 Matthias Koeppe +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from . import PythonModule from .join_feature import JoinFeature @@ -8,7 +19,7 @@ class python_igraph(JoinFeature): r""" A :class:`sage.features.Feature` describing the presence of the - Python package ``igraph``. + Python package :ref:`igraph <spkg_python_igraph>`. EXAMPLES:: diff --git a/src/sage/features/imagemagick.py b/src/sage/features/imagemagick.py index 59e35cb5a7a..fceeed8b727 100644 --- a/src/sage/features/imagemagick.py +++ b/src/sage/features/imagemagick.py @@ -1,14 +1,14 @@ -# -*- coding: utf-8 -*- r""" Feature for testing the presence of ``imagemagick`` -Currently we only check for the presence of ``convert``. When needed other +Currently we only check for the presence of ``convert``. When needed, other commands like ``magick``, ``magick-script``, ``convert``, ``mogrify``, ``identify``, ``composite``, ``montage``, ``compare``, etc. could be also checked in this module. """ + # **************************************************************************** -# Copyright (C) 2018 Sebastien Labbe <slabqc@gmail.com> +# Copyright (C) 2018-2022 Sebastien Labbe <slabqc@gmail.com> # # 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 @@ -22,7 +22,7 @@ class Convert(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``convert`` + A :class:`~sage.features.Feature` describing the presence of ``convert``. EXAMPLES:: @@ -103,12 +103,13 @@ def is_functional(self): # The command seems functional return FeatureTestResult(self, True) + class ImageMagick(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of - ``ImageMagick`` + :ref:`ImageMagick <spkg_imagemagick>` - Currently, only the availability of ``convert`` is checked. + Currently, only the availability of the :class:`convert` program is checked. EXAMPLES:: diff --git a/src/sage/features/interfaces.py b/src/sage/features/interfaces.py index b77c2cc4f88..ddfc3b9b7ee 100644 --- a/src/sage/features/interfaces.py +++ b/src/sage/features/interfaces.py @@ -1,6 +1,17 @@ r""" -Features for testing whether interpreter interfaces are functional +Features for testing whether interpreter interfaces to ``magma``, ``maple``, ``mathematica`` etc. are functional """ + +# **************************************************************************** +# Copyright (C) 2021 Matthias Koeppe +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + import importlib from . import Feature, FeatureTestResult, PythonModule diff --git a/src/sage/features/internet.py b/src/sage/features/internet.py index 6e800120828..f1eb000fe92 100644 --- a/src/sage/features/internet.py +++ b/src/sage/features/internet.py @@ -2,6 +2,16 @@ Feature for testing if the Internet is available """ +# **************************************************************************** +# Copyright (C) 2021 Matthias Koeppe +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from . import Feature, FeatureTestResult diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py index 94830eead1e..802cb433ba3 100644 --- a/src/sage/features/join_feature.py +++ b/src/sage/features/join_feature.py @@ -2,6 +2,17 @@ Join features """ +# **************************************************************************** +# Copyright (C) 2021-2022 Matthias Koeppe +# 2021-2022 Kwankyu Lee +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from . import Feature, FeatureTestResult @@ -35,7 +46,9 @@ class JoinFeature(Feature): sage: F.is_present() FeatureTestResult('xxyyyy', False) """ - def __init__(self, name, features, spkg=None, url=None, description=None): + + def __init__(self, name, features, spkg=None, url=None, description=None, type=None, + **kwds): """ TESTS: @@ -57,7 +70,15 @@ def __init__(self, name, features, spkg=None, url=None, description=None): raise ValueError('given features have more than one url; provide url argument') elif len(urls) == 1: url = next(iter(urls)) - super().__init__(name, spkg=spkg, url=url, description=description) + if type is None: + if any(f._spkg_type() == 'experimental' for f in features): + type = 'experimental' + elif any(f._spkg_type() == 'optional' for f in features): + type = 'optional' + else: + type = 'standard' + + super().__init__(name, spkg=spkg, url=url, description=description, type=type, **kwds) self._features = features def _is_present(self): @@ -105,3 +126,50 @@ def is_functional(self): if not test: return test return FeatureTestResult(self, True) + + def hide(self): + r""" + Hide this feature and all its joined features. + + EXAMPLES:: + + sage: from sage.features.sagemath import sage__groups + sage: f = sage__groups() + sage: f.hide() + sage: f._features[0].is_present() + FeatureTestResult('sage.groups.perm_gps.permgroup', False) + + sage: f.require() + Traceback (most recent call last): + ... + FeatureNotPresentError: sage.groups is not available. + Feature `sage.groups` is hidden. + Use method `unhide` to make it available again. + """ + for f in self._features: + f.hide() + super(JoinFeature, self).hide() + + def unhide(self): + r""" + Revert what :meth:`hide` does. + + EXAMPLES:: + + sage: from sage.features.sagemath import sage__groups + sage: f = sage__groups() + sage: f.hide() + sage: f.is_present() + FeatureTestResult('sage.groups', False) + sage: f._features[0].is_present() + FeatureTestResult('sage.groups.perm_gps.permgroup', False) + + sage: f.unhide() + sage: f.is_present() # optional sage.groups + FeatureTestResult('sage.groups', True) + sage: f._features[0].is_present() # optional sage.groups + FeatureTestResult('sage.groups.perm_gps.permgroup', True) + """ + for f in self._features: + f.unhide() + super(JoinFeature, self).unhide() diff --git a/src/sage/features/kenzo.py b/src/sage/features/kenzo.py index df2e658e975..72f703da15f 100644 --- a/src/sage/features/kenzo.py +++ b/src/sage/features/kenzo.py @@ -1,13 +1,25 @@ -# -*- coding: utf-8 -*- r""" Feature for testing the presence of ``kenzo`` """ +# **************************************************************************** +# Copyright (C) 2020 Travis Scrimshaw +# 2021 Matthias Koeppe +# 2021 Michael Orlitzky +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + + from . import Feature, FeatureTestResult class Kenzo(Feature): r""" - A :class:`~sage.features.Feature` describing the presence of ``Kenzo``. + A :class:`~sage.features.Feature` describing the presence of :ref:`Kenzo <spkg_kenzo>`. EXAMPLES:: @@ -36,7 +48,10 @@ def _is_present(self): sage: Kenzo()._is_present() # optional - kenzo FeatureTestResult('kenzo', True) """ - from sage.libs.ecl import ecl_eval + try: + from sage.libs.ecl import ecl_eval + except ImportError: + return FeatureTestResult(self, False, reason="sage.libs.ecl is not available") # Redirection of ECL and Maxima stdout to /dev/null # This is also done in the Maxima library, but we # also do it here for redundancy. diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index 02bcb57a0ca..48b4576961c 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -1,9 +1,12 @@ -# -*- coding: utf-8 -*- r""" Features for testing the presence of ``latex`` and equivalent programs """ + # **************************************************************************** # Copyright (C) 2021 Sebastien Labbe <slabqc@gmail.com> +# 2021 Matthias Koeppe +# 2022 Kwankyu Lee +# 2022 Sebastian Oehms # # 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 @@ -47,6 +50,23 @@ def is_functional(self): sage: from sage.features.latex import latex sage: latex().is_functional() # optional - latex FeatureTestResult('latex', True) + + When the feature is not functional, more information on the reason + can be obtained as follows:: + + sage: result = latex().is_functional() # not tested + sage: print(result.reason) # not tested + Running latex on a sample file + (with command='latex -interaction=nonstopmode tmp_wmpos8ak.tex') + returned non-zero exit status='1' with stderr='' + and stdout='This is pdfTeX, + ... + Runaway argument? + {document + ! File ended while scanning use of \end. + ... + No pages of output. + Transcript written on tmp_wmpos8ak.log.' """ lines = [] lines.append(r"\documentclass{article}") @@ -74,8 +94,12 @@ def is_functional(self): return FeatureTestResult(self, True) else: return FeatureTestResult(self, False, reason="Running latex on " - "a sample file returned non-zero " - "exit status {}".format(result.returncode)) + "a sample file (with command='{}') returned non-zero " + "exit status='{}' with stderr='{}' " + "and stdout='{}'".format(result.args, + result.returncode, + result.stderr.strip(), + result.stdout.strip())) class latex(LaTeX): @@ -162,6 +186,27 @@ def __init__(self): super().__init__("lualatex") +class dvips(Executable): + r""" + A :class:`~sage.features.Feature` describing the presence of ``dvips`` + + EXAMPLES:: + + sage: from sage.features.latex import dvips + sage: dvips().is_present() # optional - dvips + FeatureTestResult('dvips', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.latex import dvips + sage: isinstance(dvips(), dvips) + True + """ + Executable.__init__(self, "dvips", executable="dvips", + url="https://tug.org/texinfohtml/dvips.html") + class TeXFile(StaticFile): r""" A :class:`sage.features.Feature` describing the presence of a TeX file @@ -251,4 +296,5 @@ def all_features(): pdflatex(), xelatex(), lualatex(), + dvips(), LaTeXPackage("tkz-graph")] diff --git a/src/sage/features/latte.py b/src/sage/features/latte.py index 6202152501f..4df8b1cd586 100644 --- a/src/sage/features/latte.py +++ b/src/sage/features/latte.py @@ -1,7 +1,20 @@ -# -*- coding: utf-8 -*- r""" Features for testing the presence of ``latte_int`` """ + +# **************************************************************************** +# Copyright (C) 2018 Vincent Delecroix +# 2019 Frรฉdรฉric Chapoton +# 2021 Matthias Koeppe +# 2021 Kwankyu Lee +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from . import Executable from .join_feature import JoinFeature @@ -11,7 +24,7 @@ class Latte_count(Executable): r""" - Feature for the executable ``count`` from the LattE suite. + Feature for the executable ``count`` from :ref:`LattE integrale <spkg_latte_int>`. """ def __init__(self): r""" @@ -28,7 +41,7 @@ def __init__(self): class Latte_integrate(Executable): r""" - Feature for the executable ``integrate`` from the LattE suite. + Feature for the executable ``integrate`` from :ref:`LattE integrale <spkg_latte_int>`. """ def __init__(self): r""" @@ -45,8 +58,8 @@ def __init__(self): class Latte(JoinFeature): r""" - A :class:`~sage.features.Feature` describing the presence of the ``LattE`` - binaries which comes as a part of ``latte_int``. + A :class:`~sage.features.Feature` describing the presence of excecutables + from :ref:`LattE integrale <spkg_latte_int>`. EXAMPLES:: diff --git a/src/sage/features/lrs.py b/src/sage/features/lrs.py index d7b15fbcdd6..6eb0a11b642 100644 --- a/src/sage/features/lrs.py +++ b/src/sage/features/lrs.py @@ -3,6 +3,19 @@ Feature for testing the presence of ``lrslib`` """ +# ***************************************************************************** +# Copyright (C) 2016 Julian Rรผth +# 2018 Jeroen Demeyer +# 2021-2022 Matthias Koeppe +# 2021 Kwankyu Lee +# 2022 Sรฉbastien Labbรฉ +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + import subprocess from . import Executable, FeatureTestResult @@ -127,7 +140,7 @@ def is_functional(self): class Lrslib(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of the executables - which comes as a part of ``lrslib``. + :class:`lrs <Lrs>` and :class:`lrsnash <LrsNash>` provided by the :ref:`lrslib <spkg_lrslib>` package. EXAMPLES:: diff --git a/src/sage/features/mcqd.py b/src/sage/features/mcqd.py index 131b175aabc..036e8fc727b 100644 --- a/src/sage/features/mcqd.py +++ b/src/sage/features/mcqd.py @@ -2,13 +2,23 @@ Features for testing the presence of ``mcqd`` """ +# ***************************************************************************** +# Copyright (C) 2021 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import PythonModule from .join_feature import JoinFeature class Mcqd(JoinFeature): r""" - A :class:`~sage.features.Feature` describing the presence of :mod:`~sage.graphs.mcqd` + A :class:`~sage.features.Feature` describing the presence of the :mod:`~sage.graphs.mcqd` module, + which is the SageMath interface to the :ref:`mcqd <spkg_mcqd>` library EXAMPLES:: diff --git a/src/sage/features/meataxe.py b/src/sage/features/meataxe.py index d3f7fce200e..cc2a69cfeff 100644 --- a/src/sage/features/meataxe.py +++ b/src/sage/features/meataxe.py @@ -2,13 +2,25 @@ Feature for testing the presence of ``meataxe`` """ +# ***************************************************************************** +# Copyright (C) 2021 Matthias Koeppe +# 2021 Kwankyu Lee +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + + from . import PythonModule from .join_feature import JoinFeature class Meataxe(JoinFeature): r""" - A :class:`~sage.features.Feature` describing the presence of ``meataxe``. + A :class:`~sage.features.Feature` describing the presence of the Sage modules + that depend on the :ref:`meataxe <spkg_meataxe>` library. EXAMPLES:: diff --git a/src/sage/features/mip_backends.py b/src/sage/features/mip_backends.py index 477d88efabf..98b4766c1f5 100644 --- a/src/sage/features/mip_backends.py +++ b/src/sage/features/mip_backends.py @@ -2,6 +2,16 @@ Features for testing the presence of :class:`MixedIntegerLinearProgram` backends """ +# ***************************************************************************** +# Copyright (C) 2021-2022 Matthias Koeppe +# 2021 Kwankyu Lee +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import Feature, PythonModule, FeatureTestResult from .join_feature import JoinFeature @@ -92,7 +102,8 @@ def __init__(self): JoinFeature.__init__(self, 'cvxopt', [MIPBackend('CVXOPT'), PythonModule('cvxopt')], - spkg='cvxopt') + spkg='cvxopt', + type='standard') def all_features(): diff --git a/src/sage/features/msolve.py b/src/sage/features/msolve.py index a7c7d5441b7..31cc42e6176 100644 --- a/src/sage/features/msolve.py +++ b/src/sage/features/msolve.py @@ -9,18 +9,27 @@ - :mod:`sage.rings.polynomial.msolve` """ +# ***************************************************************************** +# Copyright (C) 2022 Marc Mezzarobba +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + import subprocess from . import Executable from . import FeatureTestResult class msolve(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of msolve + A :class:`~sage.features.Feature` describing the presence of :ref:`msolve <spkg_msolve>`. EXAMPLES:: sage: from sage.features.msolve import msolve - sage: msolve().is_present() # optional - msolve + sage: msolve().is_present() # optional - msolve FeatureTestResult('msolve', True) """ def __init__(self): @@ -36,12 +45,12 @@ def __init__(self): def is_functional(self): r""" - Test if our installation of msolve is working + Test if our installation of msolve is working. - EXAMPLES:: + TESTS:: sage: from sage.features.msolve import msolve - sage: msolve().is_functional() # optional - msolve + sage: msolve().is_functional() # optional - msolve FeatureTestResult('msolve', True) """ msolve_out = subprocess.run(["msolve", "-h"], capture_output=True) diff --git a/src/sage/features/nauty.py b/src/sage/features/nauty.py index 86683eb29df..ebd2daeb311 100644 --- a/src/sage/features/nauty.py +++ b/src/sage/features/nauty.py @@ -2,6 +2,15 @@ Features for testing the presence of nauty executables """ +# ***************************************************************************** +# Copyright (C) 2022 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from sage.env import SAGE_NAUTY_BINS_PREFIX from . import Executable @@ -10,7 +19,7 @@ class NautyExecutable(Executable): r""" - A :class:`~sage.features.Feature` which checks for nauty executables. + A :class:`~sage.features.Feature` which checks for executables from the :ref:`nauty <spkg_nauty>` package. EXAMPLES:: @@ -28,13 +37,14 @@ def __init__(self, name): """ Executable.__init__(self, name=f"nauty_{name}", executable=f"{SAGE_NAUTY_BINS_PREFIX}{name}", - spkg="nauty") + spkg="nauty", + type="standard") class Nauty(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of the executables - which comes as a part of ``nauty``. + which comes as a part of :ref:`nauty <spkg_nauty>`. EXAMPLES:: diff --git a/src/sage/features/normaliz.py b/src/sage/features/normaliz.py index 5c3ab4255f3..80b3891daf3 100644 --- a/src/sage/features/normaliz.py +++ b/src/sage/features/normaliz.py @@ -1,6 +1,16 @@ r""" Feature for testing the presence of ``pynormaliz`` """ + +# ***************************************************************************** +# Copyright (C) 2021 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import PythonModule from .join_feature import JoinFeature @@ -8,7 +18,7 @@ class PyNormaliz(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of the - Python package ``PyNormaliz``. + Python package :ref:`PyNormaliz <spkg_pynormaliz>`. EXAMPLES:: diff --git a/src/sage/features/palp.py b/src/sage/features/palp.py index e9936f705ce..b58a8fc2e54 100644 --- a/src/sage/features/palp.py +++ b/src/sage/features/palp.py @@ -17,11 +17,11 @@ class PalpExecutable(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of a PALP executable. + A :class:`~sage.features.Feature` describing the presence of a :ref:`PALP <spkg_palp>` executable. INPUT: - - ``palpprog`` -- string, one of "poly", "class", "nef", "cws". + - ``palpprog`` -- string, one of ``"poly"``, ``"class"``, ``"nef"``, ``"cws"``. - ``suff`` -- string or ``None``. """ @@ -36,15 +36,15 @@ def __init__(self, palpprog, suff=None): if suff: Executable.__init__(self, f"palp_{palpprog}_{suff}d", executable=f"{palpprog}-{suff}d.x", - spkg="palp") + spkg="palp", type="standard") else: Executable.__init__(self, f"palp_{palpprog}", executable=f"{palpprog}.x", - spkg="palp") + spkg="palp", type="standard") class Palp(JoinFeature): r""" - A :class:`~sage.features.Feature` describing the presence of ``PALP``. + A :class:`~sage.features.Feature` describing the presence of :ref:`PALP <spkg_palp>`. """ def __init__(self): r""" diff --git a/src/sage/features/pandoc.py b/src/sage/features/pandoc.py index 0a2bbcdacdb..00ee6055024 100644 --- a/src/sage/features/pandoc.py +++ b/src/sage/features/pandoc.py @@ -4,6 +4,7 @@ """ # **************************************************************************** # Copyright (C) 2018 Thierry Monteil <sage!lma.metelu.net> +# 2021 Matthias Koeppe # # 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 @@ -17,7 +18,7 @@ class Pandoc(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``pandoc`` + A :class:`~sage.features.Feature` describing the presence of :ref:`pandoc <spkg_pandoc>`. EXAMPLES:: diff --git a/src/sage/features/pdf2svg.py b/src/sage/features/pdf2svg.py index 9de3fb3cfd6..98578ecb6a1 100644 --- a/src/sage/features/pdf2svg.py +++ b/src/sage/features/pdf2svg.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Feature for testing the presence of ``pdf2svg`` """ @@ -16,7 +15,7 @@ class pdf2svg(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``pdf2svg`` + A :class:`~sage.features.Feature` describing the presence of :ref:`pdf2svg <spkg_pdf2svg>`. EXAMPLES:: diff --git a/src/sage/features/phitigra.py b/src/sage/features/phitigra.py index f792d7b47cd..6c1896bd8df 100644 --- a/src/sage/features/phitigra.py +++ b/src/sage/features/phitigra.py @@ -1,12 +1,22 @@ r""" -Check for phitigra +Check for ``phitigra`` """ + +# ***************************************************************************** +# Copyright (C) 2022 Jean-Florent Raymond +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import PythonModule class Phitigra(PythonModule): r""" - A :class:`sage.features.Feature` describing the presence of phitigra. + A :class:`sage.features.Feature` describing the presence of :ref:`phitigra <spkg_phitigra>`. Phitigra is provided by an optional package in the Sage distribution. diff --git a/src/sage/features/pkg_systems.py b/src/sage/features/pkg_systems.py index 5e31ec9f66d..8485fab0c7d 100644 --- a/src/sage/features/pkg_systems.py +++ b/src/sage/features/pkg_systems.py @@ -1,6 +1,16 @@ r""" -Features for testing the presence of package systems +Features for testing the presence of package systems ``sage_spkg``, ``conda``, ``pip``, ``debian``, ``fedora`` etc. """ + +# ***************************************************************************** +# Copyright (C) 2021-2022 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import Feature diff --git a/src/sage/features/polymake.py b/src/sage/features/polymake.py index 579951c047f..d2b433b1c7f 100644 --- a/src/sage/features/polymake.py +++ b/src/sage/features/polymake.py @@ -1,14 +1,24 @@ r""" -Feature for testing the presence of the Python interface to polymake +Feature for testing the presence of ``jupymake``, the Python interface to polymake """ + +# ***************************************************************************** +# Copyright (C) 2021 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import PythonModule from .join_feature import JoinFeature class JuPyMake(JoinFeature): r""" - A :class:`~sage.features.Feature` describing the presence of the :mod:`JuPyMake` - module, a Python interface to the polymake library. + A :class:`~sage.features.Feature` describing the presence of the :ref:`JuPyMake <spkg_jupymake>` + module, a Python interface to the :ref:`polymake <spkg_polymake>` library. EXAMPLES:: diff --git a/src/sage/features/poppler.py b/src/sage/features/poppler.py index 1b0379bc0d2..b8f8586e7f5 100644 --- a/src/sage/features/poppler.py +++ b/src/sage/features/poppler.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Check for poppler features diff --git a/src/sage/features/rubiks.py b/src/sage/features/rubiks.py index b418c1571cb..07250532cb6 100644 --- a/src/sage/features/rubiks.py +++ b/src/sage/features/rubiks.py @@ -1,14 +1,17 @@ -# -*- coding: utf-8 -*- r""" Features for testing the presence of ``rubiks`` """ # **************************************************************************** +# Copyright (C) 2020 John H. Palmieri +# 2021-2022 Matthias Koeppe +# # 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. # https://www.gnu.org/licenses/ # **************************************************************************** + from sage.env import RUBIKS_BINS_PREFIX from . import Executable @@ -17,7 +20,7 @@ class cu2(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``cu2`` + A :class:`~sage.features.Feature` describing the presence of ``cu2``. EXAMPLES:: @@ -39,7 +42,7 @@ def __init__(self): class size222(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``size222`` + A :class:`~sage.features.Feature` describing the presence of ``size222``. EXAMPLES:: @@ -61,7 +64,7 @@ def __init__(self): class optimal(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``optimal`` + A :class:`~sage.features.Feature` describing the presence of ``optimal``. EXAMPLES:: @@ -83,7 +86,7 @@ def __init__(self): class mcube(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``mcube`` + A :class:`~sage.features.Feature` describing the presence of ``mcube``. EXAMPLES:: @@ -105,7 +108,7 @@ def __init__(self): class dikcube(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``dikcube`` + A :class:`~sage.features.Feature` describing the presence of ``dikcube``. EXAMPLES:: @@ -127,7 +130,7 @@ def __init__(self): class cubex(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of ``cubex`` + A :class:`~sage.features.Feature` describing the presence of ``cubex``. EXAMPLES:: @@ -149,9 +152,9 @@ def __init__(self): class Rubiks(JoinFeature): r""" - A :class:`~sage.features.Feature` describing the presence of - ``cu2``, ``cubex``, ``dikcube``, ``mcube``, ``optimal``, and - ``size222``. + A :class:`~sage.features.Feature` describing the presence of the + :class:`cu2`, :class:`cubex`, :class:`dikcube`, :class:`mcube`, :class:`optimal`, and + :class:`size222` programs from the :ref:`rubiks <spkg_rubiks>` package. EXAMPLES:: diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index 58552614425..ac3922552e4 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -1,19 +1,66 @@ r""" Features for testing the presence of Python modules in the Sage library + +All of these features are present in a monolithic installation of the Sage library, +such as the one made by the SageMath distribution. + +The features are defined for the purpose of separately testing modularized +distributions such as :ref:`sagemath-categories <spkg_sagemath_categories>` +and :ref:`sagemath-repl <spkg_sagemath_repl>`. + +Often, doctests in a module of the Sage library illustrate the +interplay with a range of different objects; this is a form of integration testing. +These objects may come from modules shipped in +other distributions. For example, :mod:`sage.structure.element` +(shipped by :ref:`sagemath-objects <spkg_sagemath_objects>`, +one of the most fundamental distributions) contains the +doctest:: + + sage: G = SymmetricGroup(4) # needs sage.groups + sage: g = G([2, 3, 4, 1]) # needs sage.groups + sage: g.powers(4) # needs sage.groups + [(), (1,2,3,4), (1,3)(2,4), (1,4,3,2)] + +This test cannot pass when the distribution :ref:`sagemath-objects <spkg_sagemath_objects>` +is tested separately (in a virtual environment): In this situation, +:class:`SymmetricGroup` is not defined anywhere (and thus not present +in the top-level namespace). +Hence, we conditionalize this doctest on the presence of the feature +:class:`sage.groups <sage__groups>`. """ + +# ***************************************************************************** +# Copyright (C) 2021-2023 Matthias Koeppe +# 2021 Kwankyu Lee +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import PythonModule, StaticFile from .join_feature import JoinFeature class sagemath_doc_html(StaticFile): r""" - A :class:`Feature` which describes the presence of the documentation + A :class:`~sage.features.Feature` which describes the presence of the documentation of the Sage library in HTML format. - EXAMPLES:: + Developers often use ``make build`` instead of ``make`` to avoid the + long time it takes to compile the documentation. Although commands + such as ``make ptest`` build the documentation before testing, other + test commands such as ``make ptestlong-nodoc`` or ``./sage -t --all`` + do not. + + All doctests that refer to the built documentation need to be marked + ``# needs sagemath_doc_html``. + + TESTS:: sage: from sage.features.sagemath import sagemath_doc_html - sage: sagemath_doc_html().is_present() # optional - sagemath_doc_html + sage: sagemath_doc_html().is_present() # needs sagemath_doc_html FeatureTestResult('sagemath_doc_html', True) """ def __init__(self): @@ -28,17 +75,62 @@ def __init__(self): StaticFile.__init__(self, 'sagemath_doc_html', filename='html', search_path=(SAGE_DOC,), - spkg='sagemath_doc_html') + spkg='sagemath_doc_html', + type='standard') class sage__combinat(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of :mod:`sage.combinat`. - EXAMPLES:: + EXAMPLES: + + Python modules that provide elementary combinatorial objects such as :mod:`sage.combinat.subset`, + :mod:`sage.combinat.composition`, :mod:`sage.combinat.permutation` are always available; + there is no need for an ``# optional/needs`` tag:: + + sage: Permutation([1,2,3]).is_even() + True + sage: Permutation([6,1,4,5,2,3]).bruhat_inversions() + [[0, 1], [0, 2], [0, 3], [2, 4], [2, 5], [3, 4], [3, 5]] + + Use ``# needs sage.combinat`` for doctests that use any other Python modules + from :mod:`sage.combinat`, for example :mod:`sage.combinat.tableau_tuple`:: + + sage: TableauTuple([[[7,8,9]],[],[[1,2,3],[4,5],[6]]]).shape() # needs sage.combinat + ([3], [], [3, 2, 1]) + + Doctests that use Python modules from :mod:`sage.combinat` that involve trees, + graphs, hypergraphs, posets, quivers, combinatorial designs, + finite state machines etc. should be marked ``# needs sage.combinat sage.graphs``:: + + sage: L = Poset({0: [1], 1: [2], 2:[3], 3:[4]}) # needs sage.combinat sage.graphs + sage: L.is_chain() # needs sage.combinat sage.graphs + True + + Doctests that use combinatorial modules/algebras, or root systems should use the tag + ``# needs sage.combinat sage.modules``:: + + sage: # needs sage.combinat sage.modules + sage: A = SchurAlgebra(QQ, 2, 3) + sage: a = A.an_element(); a + 2*S((1, 1, 1), (1, 1, 1)) + 2*S((1, 1, 1), (1, 1, 2)) + + 3*S((1, 1, 1), (1, 2, 2)) + sage: L = RootSystem(['A',3,1]).root_lattice() + sage: PIR = L.positive_imaginary_roots(); PIR + Positive imaginary roots of type ['A', 3, 1] + + Doctests that use lattices, semilattices, or Dynkin diagrams should use the tag + ``# needs sage.combinat sage.graphs sage.modules``:: + + sage: L = LatticePoset({0: [1,2], 1: [3], 2: [3,4], 3: [5], 4: [5]}) # needs sage.combinat sage.graphs sage.modules + sage: L.meet_irreducibles() # needs sage.combinat sage.graphs sage.modules + [1, 3, 4] + + TESTS:: sage: from sage.features.sagemath import sage__combinat - sage: sage__combinat().is_present() # optional - sage.combinat + sage: sage__combinat().is_present() # needs sage.combinat FeatureTestResult('sage.combinat', True) """ def __init__(self): @@ -51,19 +143,39 @@ def __init__(self): """ # sage.combinat will be a namespace package. # Testing whether sage.combinat itself can be imported is meaningless. + # Some modules providing basic combinatorics are already included in sagemath-categories. # Hence, we test a Python module within the package. JoinFeature.__init__(self, 'sage.combinat', - [PythonModule('sage.combinat.combination')]) + [PythonModule('sage.combinat'), # namespace package + PythonModule('sage.combinat.tableau'), # representative + ], + spkg='sagemath_combinat', type="standard") -class sage__geometry__polyhedron(PythonModule): +class sage__geometry__polyhedron(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of :mod:`sage.geometry.polyhedron`. - EXAMPLES:: + EXAMPLES: + + Doctests that use polyhedra, cones, geometric complexes, triangulations, etc. should use + the tag ``# needs sage.geometry.polyhedron``:: + + sage: co = polytopes.truncated_tetrahedron() # needs sage.geometry.polyhedron + sage: co.volume() # needs sage.geometry.polyhedron + 184/3 + + Some constructions of polyhedra require additional tags:: + + sage: # needs sage.combinat sage.geometry.polyhedron sage.rings.number_field + sage: perm_a3_reg_nf = polytopes.generalized_permutahedron( + ....: ['A',3], regular=True, backend='number_field'); perm_a3_reg_nf + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices + + TESTS:: sage: from sage.features.sagemath import sage__geometry__polyhedron - sage: sage__geometry__polyhedron().is_present() # optional - sage.geometry.polyhedron + sage: sage__geometry__polyhedron().is_present() # needs sage.geometry.polyhedron FeatureTestResult('sage.geometry.polyhedron', True) """ @@ -75,17 +187,69 @@ def __init__(self): sage: isinstance(sage__geometry__polyhedron(), sage__geometry__polyhedron) True """ - PythonModule.__init__(self, 'sage.geometry.polyhedron') + JoinFeature.__init__(self, 'sage.geometry.polyhedron', + [PythonModule('sage.geometry'), # namespace package + PythonModule('sage.geometry.polyhedron'), # representative + PythonModule('sage.schemes.toric'), # namespace package + PythonModule('sage.schemes.toric.variety'), # representative + ], + spkg='sagemath_polyhedra', type="standard") class sage__graphs(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of :mod:`sage.graphs`. - EXAMPLES:: + EXAMPLES: + + Doctests that use anything from :mod:`sage.graphs` (:class:`Graph`, :class:`DiGraph`, ...) + should be marked ``# needs sage.graphs``. The same applies to any doctest that + uses a :class:`~sage.combinat.posets.posets.Poset`, cluster algebra quiver, finite + state machines, abelian sandpiles, or Dynkin diagrams:: + + sage: g = graphs.PetersenGraph() # needs sage.graphs + sage: r, s = g.is_weakly_chordal(certificate=True); r # needs sage.graphs + False + + Also any use of tree classes defined in :mod:`sage.combinat` (:class:`BinaryTree`, + :class:`RootedTree`, ...) in doctests should be marked the same. + + By way of generalization, any use of :class:`SimplicialComplex` or other abstract complexes from + :mod:`sage.topology`, hypergraphs, and combinatorial designs, should be marked + ``# needs sage.graphs`` as well:: + + sage: X = SimplicialComplex([[0,1,2], [1,2,3]]) # needs sage.graphs + sage: X.link(Simplex([0])) # needs sage.graphs + Simplicial complex with vertex set (1, 2) and facets {(1, 2)} + + sage: IncidenceStructure([[1,2,3],[1,4]]).degrees(2) # needs sage.graphs + {(1, 2): 1, (1, 3): 1, (1, 4): 1, (2, 3): 1, (2, 4): 0, (3, 4): 0} + + On the other hand, matroids are not implemented as posets in Sage but are instead + closely tied to linear algebra over fields; hence use ``# needs sage.modules`` instead:: + + sage: # needs sage.modules + sage: M = Matroid(Matrix(QQ, [[1, 0, 0, 0, 1, 1, 1], + ....: [0, 1, 0, 1, 0, 1, 1], + ....: [0, 0, 1, 1, 1, 0, 1]])) + sage: N = M / [2] \ [3, 4] + sage: sorted(N.groundset()) + [0, 1, 5, 6] + + However, many constructions (and some methods) of matroids do involve graphs:: + + sage: # needs sage.modules + sage: W = matroids.Wheel(3) # despite the name, not created via graphs + sage: W.is_isomorphic(N) # goes through a graph isomorphism test # needs sage.graphs + False + sage: K4 = matroids.CompleteGraphic(4) # this one is created via graphs # needs sage.graphs + sage: K4.is_isomorphic(W) # needs sage.graphs + True + + TESTS:: sage: from sage.features.sagemath import sage__graphs - sage: sage__graphs().is_present() # optional - sage.graphs + sage: sage__graphs().is_present() # needs sage.graphs FeatureTestResult('sage.graphs', True) """ def __init__(self): @@ -97,17 +261,41 @@ def __init__(self): True """ JoinFeature.__init__(self, 'sage.graphs', - [PythonModule('sage.graphs.graph')]) + # These lists of modules are an (incomplete) duplication + # of information in the distribution's MANIFEST. + # But at least as long as the monolithic Sage library is + # around, we need this information here for use by + # sage-fixdoctests. + [PythonModule('sage.graphs'), # namespace package + PythonModule('sage.graphs.graph'), # representative + PythonModule('sage.combinat.designs'), # namespace package + PythonModule('sage.combinat.designs.block_design'), # representative + PythonModule('sage.combinat.posets'), # namespace package + PythonModule('sage.combinat.posets.posets'), # representative + PythonModule('sage.topology'), # namespace package + PythonModule('sage.topology.simplicial_complex'), # representative + ], + spkg='sagemath_graphs', type="standard") class sage__groups(JoinFeature): r""" - A :class:`sage.features.Feature` describing the presence of ``sage.groups``. + A :class:`~sage.features.Feature` describing the presence of ``sage.groups``. - EXAMPLES:: + EXAMPLES: + + Permutations and sets of permutations are always available, but permutation groups are + implemented in Sage using the :ref:`GAP <spkg_gap>` system and require the tag + ``# needs sage.groups``:: + + sage: p = Permutation([2,1,4,3]) + sage: p.to_permutation_group_element() # needs sage.groups + (1,2)(3,4) + + TESTS:: sage: from sage.features.sagemath import sage__groups - sage: sage__groups().is_present() # optional - sage.groups + sage: sage__groups().is_present() # needs sage.groups FeatureTestResult('sage.groups', True) """ def __init__(self): @@ -119,17 +307,349 @@ def __init__(self): True """ JoinFeature.__init__(self, 'sage.groups', - [PythonModule('sage.groups.perm_gps.permgroup')]) + [PythonModule('sage.groups.perm_gps.permgroup')], + spkg='sagemath_groups', type='standard') + + +class sage__libs__ecl(PythonModule): + r""" + A :class:`~sage.features.Feature` describing the presence of :mod:`sage.libs.ecl`. + + EXAMPLES:: + + sage: from sage.features.sagemath import sage__libs__ecl + sage: sage__libs__ecl().is_present() # optional - sage.libs.ecl + FeatureTestResult('sage.libs.ecl', True) + """ + + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__libs__ecl + sage: isinstance(sage__libs__ecl(), sage__libs__ecl) + True + """ + PythonModule.__init__(self, 'sage.libs.ecl') + + +class sage__libs__flint(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of :mod:`sage.libs.flint` + and other modules depending on FLINT and arb. + + In addition to the modularization purposes that this tag serves, it also provides attribution + to the upstream project. + + TESTS:: + + sage: from sage.features.sagemath import sage__libs__flint + sage: sage__libs__flint().is_present() # needs sage.libs.flint + FeatureTestResult('sage.libs.flint', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__libs__flint + sage: isinstance(sage__libs__flint(), sage__libs__flint) + True + """ + JoinFeature.__init__(self, 'sage.libs.flint', + [PythonModule('sage.libs.flint.flint'), + PythonModule('sage.libs.arb.arith')], + spkg='sagemath_flint', type='standard') + + +class sage__libs__gap(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of :mod:`sage.libs.gap` + (the library interface to :ref:`GAP <spkg_gap>`) and :mod:`sage.interfaces.gap` (the pexpect + interface to GAP). By design, we do not distinguish between these two, in order + to facilitate the conversion of code from the pexpect interface to the library + interface. + + .. SEEALSO:: + + :class:`Features for GAP packages <~sage.features.gap.GapPackage>` + + TESTS:: + + sage: from sage.features.gap import sage__libs__gap + sage: sage__libs__gap().is_present() # needs sage.libs.gap + FeatureTestResult('sage.libs.gap', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.gap import sage__libs__gap + sage: isinstance(sage__libs__gap(), sage__libs__gap) + True + """ + JoinFeature.__init__(self, 'sage.libs.gap', + [PythonModule('sage.libs.gap.libgap'), + PythonModule('sage.interfaces.gap')]) + + +class sage__libs__linbox(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of :mod:`sage.libs.linbox` + and other modules depending on Givaro, FFLAS-FFPACK, LinBox. + + In addition to the modularization purposes that this tag serves, + it also provides attribution to the upstream project. + + TESTS:: + + sage: from sage.features.sagemath import sage__libs__linbox + sage: sage__libs__linbox().is_present() # needs sage.libs.linbox + FeatureTestResult('sage.libs.linbox', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__libs__linbox + sage: isinstance(sage__libs__linbox(), sage__libs__linbox) + True + """ + JoinFeature.__init__(self, 'sage.libs.linbox', + [PythonModule('sage.rings.finite_rings.element_givaro')], + spkg='sagemath_linbox', type='standard') + + +class sage__libs__m4ri(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of Cython modules + depending on the M4RI and/or M4RIe libraries. + + In addition to the modularization purposes that this tag serves, + it also provides attribution to the upstream project. + + TESTS:: + + sage: from sage.features.sagemath import sage__libs__m4ri + sage: sage__libs__m4ri().is_present() # needs sage.libs.m4ri + FeatureTestResult('sage.libs.m4ri', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__libs__m4ri + sage: isinstance(sage__libs__m4ri(), sage__libs__m4ri) + True + """ + JoinFeature.__init__(self, 'sage.libs.m4ri', + [PythonModule('sage.matrix.matrix_gf2e_dense')], + spkg='sagemath_m4ri', type='standard') + + +class sage__libs__ntl(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of :mod:`sage.libs.ntl` + and other modules depending on NTL. + + In addition to the modularization purposes that this tag serves, + it also provides attribution to the upstream project. + + TESTS:: + + sage: from sage.features.sagemath import sage__libs__ntl + sage: sage__libs__ntl().is_present() # needs sage.libs.ntl + FeatureTestResult('sage.libs.ntl', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__libs__ntl + sage: isinstance(sage__libs__ntl(), sage__libs__ntl) + True + """ + JoinFeature.__init__(self, 'sage.libs.ntl', + [PythonModule('sage.libs.ntl.convert')], + spkg='sagemath_ntl', type='standard') + + +class sage__libs__pari(JoinFeature): + r""" + A :class:`~sage.features.Feature` describing the presence of :mod:`sage.libs.pari`. + + SageMath uses the :ref:`PARI <spkg_pari>` library (via :ref:`cypari2 + <spkg_cypari>`) for numerous purposes. Doctests that involves such features + should be marked ``# needs sage.libs.pari``. + + In addition to the modularization purposes that this tag serves, it also + provides attribution to the upstream project. + + EXAMPLES:: + + sage: R.<a> = QQ[] + sage: S.<x> = R[] + sage: f = x^2 + a; g = x^3 + a + sage: r = f.resultant(g); r # needs sage.libs.pari + a^3 + a^2 + + TESTS:: + + sage: from sage.features.sagemath import sage__libs__pari + sage: sage__libs__pari().is_present() # needs sage.libs.pari + FeatureTestResult('sage.libs.pari', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__libs__pari + sage: isinstance(sage__libs__pari(), sage__libs__pari) + True + """ + JoinFeature.__init__(self, 'sage.libs.pari', + [PythonModule('sage.libs.pari.convert_sage')], + spkg='sagemath_pari', type='standard') + + +class sage__libs__singular(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of :mod:`sage.libs.singular` + (the library interface to Singular) and :mod:`sage.interfaces.singular` (the pexpect + interface to Singular). By design, we do not distinguish between these two, in order + to facilitate the conversion of code from the pexpect interface to the library + interface. + + .. SEEALSO:: + + :class:`Feature singular <~sage.features.singular.Singular>` + + TESTS:: + + sage: from sage.features.singular import sage__libs__singular + sage: sage__libs__singular().is_present() # needs sage.libs.singular + FeatureTestResult('sage.libs.singular', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.singular import sage__libs__singular + sage: isinstance(sage__libs__singular(), sage__libs__singular) + True + """ + JoinFeature.__init__(self, 'sage.libs.singular', + [PythonModule('sage.libs.singular.singular'), + PythonModule('sage.interfaces.singular')]) + + +class sage__modular(JoinFeature): + r""" + A :class:`~sage.features.Feature` describing the presence of :mod:`sage.modular`. + + TESTS:: + + sage: from sage.features.sagemath import sage__modular + sage: sage__modular().is_present() # needs sage.modular + FeatureTestResult('sage.modular', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__modular + sage: isinstance(sage__modular(), sage__modular) + True + """ + JoinFeature.__init__(self, 'sage.modular', + [PythonModule('sage.modular.modform.eisenstein_submodule')], + spkg='sagemath_schemes', type='standard') + + +class sage__modules(JoinFeature): + r""" + A :class:`~sage.features.Feature` describing the presence of :mod:`sage.modules`. + + EXAMPLES: + + All uses of implementations of vector spaces / free modules in SageMath, whether + :class:`sage.modules.free_module.FreeModule`, + :class:`sage.combinat.free_module.CombinatorialFreeModule`, + :class:`sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule`, or + additive abelian groups, should be marked ``# needs sage.modules``. + + The same holds for matrices, tensors, algebras, quadratic forms, + point lattices, root systems, matrix/affine/Weyl/Coxeter groups, matroids, + and ring derivations. + + Likewise, all uses of :mod:`sage.coding`, :mod:`sage.crypto`, and :mod:`sage.homology` + in doctests should be marked ``# needs sage.modules``. + + TESTS:: + + sage: from sage.features.sagemath import sage__modules + sage: sage__modules().is_present() # needs sage.modules + FeatureTestResult('sage.modules', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__modules + sage: isinstance(sage__modules(), sage__modules) + True + """ + JoinFeature.__init__(self, 'sage.modules', + [PythonModule('sage.modules'), # namespace package + PythonModule('sage.modules.free_module'), # representative + PythonModule('sage.matrix'), # namespace package + PythonModule('sage.matrix.matrix2'), # representative + PythonModule('sage.combinat.free_module'), + PythonModule('sage.quadratic_forms'), # namespace package + PythonModule('sage.quadratic_forms.quadratic_form'), # representative + PythonModule('sage.groups.additive_abelian'), # namespace package + PythonModule('sage.groups.additive_abelian.qmodnz'), # representative + PythonModule('sage.groups.affine_gps'), # namespace package + PythonModule('sage.groups.affine_gps.affine_group'), # representative + PythonModule('sage.groups.matrix_gps'), # namespace package + PythonModule('sage.groups.matrix_gps.named_group'), # representative + PythonModule('sage.homology'), # namespace package + PythonModule('sage.homology.chain_complex'), # representative + PythonModule('sage.matroids'), # namespace package + PythonModule('sage.matroids.matroid'), # representative + ], + spkg='sagemath_modules', type='standard') + + +class sage__numerical__mip(PythonModule): + r""" + A :class:`~sage.features.Feature` describing the presence of :mod:`sage.numerical.mip`. + + TESTS:: + + sage: from sage.features.sagemath import sage__numerical__mip + sage: sage__numerical__mip().is_present() # needs sage.numerical.mip + FeatureTestResult('sage.numerical.mip', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__numerical__mip + sage: isinstance(sage__numerical__mip(), sage__numerical__mip) + True + """ + PythonModule.__init__(self, 'sage.numerical.mip', + spkg='sagemath_polyhedra') class sage__plot(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of :mod:`sage.plot`. - EXAMPLES:: + TESTS:: sage: from sage.features.sagemath import sage__plot - sage: sage__plot().is_present() # optional - sage.plot + sage: sage__plot().is_present() # needs sage.plot FeatureTestResult('sage.plot', True) """ def __init__(self): @@ -141,17 +661,151 @@ def __init__(self): True """ JoinFeature.__init__(self, 'sage.plot', - [PythonModule('sage.plot.plot')]) + [PythonModule('sage.plot.plot')], + spkg='sagemath_plot', type='standard') + + +class sage__rings__complex_double(PythonModule): + r""" + A :class:`~sage.features.Feature` describing the presence of :mod:`sage.rings.complex_double`. + + TESTS:: + + sage: from sage.features.sagemath import sage__rings__complex_double + sage: sage__rings__complex_double().is_present() # needs sage.rings.complex_double + FeatureTestResult('sage.rings.complex_double', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__rings__complex_double + sage: isinstance(sage__rings__complex_double(), sage__rings__complex_double) + True + """ + PythonModule.__init__(self, 'sage.rings.complex_double', + spkg='sagemath_modules', type='standard') + + +class sage__rings__finite_rings(JoinFeature): + r""" + A :class:`~sage.features.Feature` describing the presence of :mod:`sage.rings.finite_rings`; + specifically, the element implementations using the :ref:`PARI <spkg_pari>` library. + + TESTS:: + + sage: from sage.features.sagemath import sage__rings__finite_rings + sage: sage__rings__finite_rings().is_present() # needs sage.rings.finite_rings + FeatureTestResult('sage.rings.finite_rings', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__rings__finite_rings + sage: isinstance(sage__rings__finite_rings(), sage__rings__finite_rings) + True + """ + JoinFeature.__init__(self, 'sage.rings.finite_rings', + [PythonModule('sage.rings.finite_rings.element_pari_ffelt'), + PythonModule('sage.rings.algebraic_closure_finite_field')], + type='standard') + + +class sage__rings__function_field(JoinFeature): + r""" + A :class:`~sage.features.Feature` describing the presence of :mod:`sage.rings.function_field`. + + EXAMPLES: + + Rational function fields are always available:: + + sage: K.<x> = FunctionField(QQ) + sage: K.maximal_order() + Maximal order of Rational function field in x over Rational Field + + Use the tag ``# needs sage.rings.function_field`` whenever extensions + of function fields (by adjoining a root of a univariate polynomial) come into play:: + + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L # needs sage.rings.function_field + Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x + + Such extensions of function fields are implemented using Grรถbner bases of polynomial rings; + Sage makes essential use of the :ref:`Singular <spkg_singular>` system for this. + (It is not necessary to use the tag ``# needs sage.libs.singular``; it is + implied by ``# needs sage.rings.function_field``.) + + TESTS:: + + sage: from sage.features.sagemath import sage__rings__function_field + sage: sage__rings__function_field().is_present() # needs sage.rings.function_field + FeatureTestResult('sage.rings.function_field', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__rings__function_field + sage: isinstance(sage__rings__function_field(), sage__rings__function_field) + True + """ + JoinFeature.__init__(self, 'sage.rings.function_field', + [PythonModule('sage.rings.function_field.function_field_polymod'), + sage__libs__singular()], + type='standard') class sage__rings__number_field(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of :mod:`sage.rings.number_field`. - EXAMPLES:: + Number fields are implemented in Sage using a complicated mixture of various libraries, + including :ref:`arb <spkg_arb>`, :ref:`FLINT <spkg_flint>`, :ref:`GAP <spkg_gap>`, + :ref:`MPFI <spkg_mpfi>`, :ref:`NTL <spkg_ntl>`, and :ref:`PARI <spkg_pari>`. + + EXAMPLES: + + Rational numbers are, of course, always available:: + + sage: QQ in NumberFields() + True + + Doctests that construct algebraic number fields should be marked ``# needs sage.rings.number_field``:: + + sage: # needs sage.rings.number_field + sage: K.<cuberoot2> = NumberField(x^3 - 2) + sage: L.<cuberoot3> = K.extension(x^3 - 3) + sage: S.<sqrt2> = L.extension(x^2 - 2); S + Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field + + sage: # needs sage.rings.number_field + sage: K.<zeta> = CyclotomicField(15) + sage: CC(zeta) + 0.913545457642601 + 0.406736643075800*I + + Doctests that make use of the algebraic field ``QQbar``, the algebraic real field ``AA``, + or the universal cyclotomic field should be marked likewise:: + + sage: # needs sage.rings.number_field + sage: AA(-1)^(1/3) + -1 + sage: QQbar(-1)^(1/3) + 0.500000000000000? + 0.866025403784439?*I + + sage: # needs sage.rings.number_field + sage: UCF = UniversalCyclotomicField(); UCF + Universal Cyclotomic Field + sage: E = UCF.gen + sage: f = E(2) + E(3); f + 2*E(3) + E(3)^2 + sage: f.galois_conjugates() + [2*E(3) + E(3)^2, E(3) + 2*E(3)^2] + + TESTS:: sage: from sage.features.sagemath import sage__rings__number_field - sage: sage__rings__number_field().is_present() # optional - sage.rings.number_field + sage: sage__rings__number_field().is_present() # needs sage.rings.number_field FeatureTestResult('sage.rings.number_field', True) """ def __init__(self): @@ -163,17 +817,20 @@ def __init__(self): True """ JoinFeature.__init__(self, 'sage.rings.number_field', - [PythonModule('sage.rings.number_field.number_field_element')]) + [PythonModule('sage.rings.number_field.number_field_element'), + PythonModule('sage.rings.universal_cyclotomic_field'), + PythonModule('sage.rings.qqbar')], + type='standard') class sage__rings__padics(JoinFeature): r""" - A :class:`sage.features.Feature` describing the presence of ``sage.rings.padics``. + A :class:`~sage.features.Feature` describing the presence of ``sage.rings.padics``. - EXAMPLES:: + TESTS:: sage: from sage.features.sagemath import sage__rings__padics - sage: sage__rings__padics().is_present() # optional - sage.rings.padics + sage: sage__rings__padics().is_present() # needs sage.rings.padics FeatureTestResult('sage.rings.padics', True) """ def __init__(self): @@ -185,17 +842,51 @@ def __init__(self): True """ JoinFeature.__init__(self, 'sage.rings.padics', - [PythonModule('sage.rings.padics.factory')]) + [PythonModule('sage.rings.padics.factory')], + type='standard') + + +class sage__rings__polynomial__pbori(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of :mod:`sage.rings.polynomial.pbori`. + + TESTS:: + + sage: from sage.features.sagemath import sage__rings__polynomial__pbori + sage: sage__rings__polynomial__pbori().is_present() # needs sage.rings.polynomial.pbori + FeatureTestResult('sage.rings.polynomial.pbori', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__rings__polynomial__pbori + sage: isinstance(sage__rings__polynomial__pbori(), sage__rings__polynomial__pbori) + True + """ + JoinFeature.__init__(self, 'sage.rings.polynomial.pbori', + [PythonModule('sage.rings.polynomial.pbori.pbori')], + spkg='sagemath_brial', type='standard') class sage__rings__real_double(PythonModule): r""" A :class:`~sage.features.Feature` describing the presence of :mod:`sage.rings.real_double`. - EXAMPLES:: + EXAMPLES: + + The Real Double Field is basically always available, and no ``# optional/needs`` tag is needed:: + + sage: RDF.characteristic() + 0 + + The feature exists for use in doctests of Python modules that are shipped by the + most fundamental distributions. + + TESTS:: sage: from sage.features.sagemath import sage__rings__real_double - sage: sage__rings__real_double().is_present() # optional - sage.rings.real_double + sage: sage__rings__real_double().is_present() # needs sage.rings.real_double FeatureTestResult('sage.rings.real_double', True) """ def __init__(self): @@ -206,17 +897,100 @@ def __init__(self): sage: isinstance(sage__rings__real_double(), sage__rings__real_double) True """ - PythonModule.__init__(self, 'sage.rings.real_double') + PythonModule.__init__(self, 'sage.rings.real_double', type='standard') + + +class sage__rings__real_mpfr(JoinFeature): + r""" + A :class:`~sage.features.Feature` describing the presence of :mod:`sage.rings.real_mpfr`. + + TESTS:: + + sage: from sage.features.sagemath import sage__rings__real_mpfr + sage: sage__rings__real_mpfr().is_present() # needs sage.rings.real_mpfr + FeatureTestResult('sage.rings.real_mpfr', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__rings__real_mpfr + sage: isinstance(sage__rings__real_mpfr(), sage__rings__real_mpfr) + True + """ + JoinFeature.__init__(self, 'sage.rings.real_mpfr', + [PythonModule('sage.rings.real_mpfr'), + PythonModule('sage.rings.complex_mpfr'), + ], + spkg='sagemath_modules', type='standard') + + +class sage__sat(JoinFeature): + r""" + A :class:`~sage.features.Feature` describing the presence of :mod:`sage.sat`. + + TESTS:: + + sage: from sage.features.sagemath import sage__sat + sage: sage__sat().is_present() # needs sage.sat + FeatureTestResult('sage.sat', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__sat + sage: isinstance(sage__sat(), sage__sat) + True + """ + JoinFeature.__init__(self, 'sage.sat', + [PythonModule('sage.sat.expression')], + spkg='sagemath_combinat', type='standard') + + +class sage__schemes(JoinFeature): + r""" + A :class:`~sage.features.Feature` describing the presence of :mod:`sage.schemes`. + + TESTS:: + + sage: from sage.features.sagemath import sage__schemes + sage: sage__schemes().is_present() # needs sage.schemes + FeatureTestResult('sage.schemes', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__schemes + sage: isinstance(sage__schemes(), sage__schemes) + True + """ + JoinFeature.__init__(self, 'sage.schemes', + [PythonModule('sage.schemes.elliptic_curves.ell_generic')], + spkg="sagemath_schemes", type='standard') class sage__symbolic(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of :mod:`sage.symbolic`. - EXAMPLES:: + EXAMPLES: + + The symbolics subsystem of Sage will be provided by the distribution + sagemath-symbolics, in preparation at :issue:`35095`. If it is not installed, + Sage will be able to provide installation advice:: + + sage: from sage.features.sagemath import sage__symbolic + sage: print(sage__symbolic().resolution()) # optional - sage_spkg, not tested + ...To install sagemath_symbolics...you can try to run... + pip install sagemath-symbolics + ... + + TESTS:: sage: from sage.features.sagemath import sage__symbolic - sage: sage__symbolic().is_present() # optional - sage.symbolic + sage: sage__symbolic().is_present() # needs sage.symbolic FeatureTestResult('sage.symbolic', True) """ def __init__(self): @@ -228,8 +1002,32 @@ def __init__(self): True """ JoinFeature.__init__(self, 'sage.symbolic', - [PythonModule('sage.symbolic.expression')], - spkg="sagemath_symbolics") + [PythonModule('sage.symbolic.expression'), + PythonModule('sage.manifolds'), + PythonModule('sage.calculus.calculus'), + PythonModule('sage.calculus.desolvers'), + PythonModule('sage.calculus.predefined'), + PythonModule('sage.calculus.tests'), + PythonModule('sage.calculus.var'), + PythonModule('sage.geometry.riemannian_manifolds'), + PythonModule('sage.geometry.hyperbolic_space'), + PythonModule('sage.dynamics.complex_dynamics'), + PythonModule('sage.libs.pynac'), + PythonModule('sage.libs.ecl'), + PythonModule('sage.interfaces.fricas'), + PythonModule('sage.interfaces.giac'), + PythonModule('sage.interfaces.magma'), + PythonModule('sage.interfaces.magma_free'), + PythonModule('sage.interfaces.maple'), + PythonModule('sage.interfaces.mathematica'), + PythonModule('sage.interfaces.mathics'), + PythonModule('sage.interfaces.maxima'), + PythonModule('sage.interfaces.maxima_abstract'), + PythonModule('sage.interfaces.maxima_lib'), + PythonModule('sage.interfaces.qepcad'), + PythonModule('sage.interfaces.sympy'), + PythonModule('sage.interfaces.sympy_wrapper'), + ], spkg='sagemath_symbolics', type='standard') def all_features(): @@ -259,8 +1057,26 @@ def all_features(): sage__geometry__polyhedron(), sage__graphs(), sage__groups(), + sage__libs__ecl(), + sage__libs__flint(), + sage__libs__gap(), + sage__libs__linbox(), + sage__libs__m4ri(), + sage__libs__ntl(), + sage__libs__pari(), + sage__libs__singular(), + sage__modular(), + sage__modules(), + sage__numerical__mip(), sage__plot(), + sage__rings__complex_double(), + sage__rings__finite_rings(), + sage__rings__function_field(), sage__rings__number_field(), sage__rings__padics(), + sage__rings__polynomial__pbori(), sage__rings__real_double(), + sage__rings__real_mpfr(), + sage__sat(), + sage__schemes(), sage__symbolic()] diff --git a/src/sage/features/singular.py b/src/sage/features/singular.py index 610e195c641..fce89a8e91c 100644 --- a/src/sage/features/singular.py +++ b/src/sage/features/singular.py @@ -1,18 +1,34 @@ r""" -Features for testing the presence of Singular +Features for testing the presence of ``singular`` and the SageMath interfaces to it """ -from . import Executable + +# ***************************************************************************** +# Copyright (C) 2022-2023 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + +from . import Executable, PythonModule +from .join_feature import JoinFeature +from .sagemath import sage__libs__singular from sage.env import SINGULAR_BIN class Singular(Executable): r""" - A :class:`~sage.features.Feature` describing the presence of the Singular executable. + A :class:`~sage.features.Feature` describing the presence of the :ref:`singular <spkg_singular>` executable. + + .. SEEALSO:: + + :class:`Feature sage.libs.singular <~sage.features.sagemath.sage__libs__singular>` EXAMPLES:: sage: from sage.features.singular import Singular - sage: Singular().is_present() + sage: Singular().is_present() # needs singular FeatureTestResult('singular', True) """ def __init__(self): @@ -24,4 +40,8 @@ def __init__(self): True """ Executable.__init__(self, "singular", SINGULAR_BIN, - spkg='singular') + spkg='singular', type='standard') + + +def all_features(): + return [Singular()] diff --git a/src/sage/features/sphinx.py b/src/sage/features/sphinx.py index d29de3f34f4..a70e8a11eee 100644 --- a/src/sage/features/sphinx.py +++ b/src/sage/features/sphinx.py @@ -1,12 +1,22 @@ r""" -Check for Sphinx +Features for testing the presence of ``sphinx`` """ + +# ***************************************************************************** +# Copyright (C) 2021 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import PythonModule class Sphinx(PythonModule): r""" - A :class:`sage.features.Feature` describing the presence of Sphinx. + A :class:`sage.features.Feature` describing the presence of :ref:`Sphinx <spkg_sphinx>`. Sphinx is provided by a standard package in the Sage distribution, but it can be disabled by ``configure --disable-doc``. @@ -25,7 +35,7 @@ def __init__(self): sage: isinstance(Sphinx(), Sphinx) True """ - PythonModule.__init__(self, 'sphinx', spkg='sphinx') + PythonModule.__init__(self, 'sphinx', spkg='sphinx', type='standard') def all_features(): diff --git a/src/sage/features/standard.py b/src/sage/features/standard.py new file mode 100644 index 00000000000..c2090fc53a4 --- /dev/null +++ b/src/sage/features/standard.py @@ -0,0 +1,36 @@ +r""" +Check for various standard packages (for modularized distributions) + +These features are provided by standard packages in the Sage distribution. +""" + +# ***************************************************************************** +# Copyright (C) 2023 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + +from . import PythonModule +from .join_feature import JoinFeature + + +def all_features(): + return [PythonModule('cvxopt', spkg='cvxopt', type='standard'), + PythonModule('fpylll', spkg='fpylll', type='standard'), + JoinFeature('ipython', (PythonModule('IPython'),), spkg='ipython', type='standard'), + JoinFeature('lrcalc_python', (PythonModule('lrcalc'),), spkg='lrcalc_python', type='standard'), + PythonModule('mpmath', spkg='mpmath', type='standard'), + PythonModule('networkx', spkg='networkx', type='standard'), + PythonModule('numpy', spkg='numpy', type='standard'), + PythonModule('pexpect', spkg='pexpect', type='standard'), + JoinFeature('pillow', (PythonModule('PIL'),), spkg='pillow', type='standard'), + JoinFeature('pplpy', (PythonModule('ppl'),), spkg='pplpy', type='standard'), + PythonModule('primecountpy', spkg='primecountpy', type='standard'), + PythonModule('ptyprocess', spkg='ptyprocess', type='standard'), + PythonModule('pyparsing', spkg='pyparsing', type='standard'), + PythonModule('requests', spkg='requests', type='standard'), + PythonModule('scipy', spkg='scipy', type='standard'), + PythonModule('sympy', spkg='sympy', type='standard')] diff --git a/src/sage/features/tdlib.py b/src/sage/features/tdlib.py index ff38f6e23a5..128c056a49c 100644 --- a/src/sage/features/tdlib.py +++ b/src/sage/features/tdlib.py @@ -2,13 +2,23 @@ Features for testing the presence of ``tdlib`` """ +# ***************************************************************************** +# Copyright (C) 2021 Matthias Koeppe +# 2021 Kwankyu Lee +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + from . import PythonModule from .join_feature import JoinFeature class Tdlib(JoinFeature): r""" - A :class:`~sage.features.Feature` describing the presence of the ``tdlib``. + A :class:`~sage.features.Feature` describing the presence of the SageMath interface to the :ref:`tdlib <spkg_tdlib>` library. """ def __init__(self): r""" diff --git a/src/sage/finance/__init__.py b/src/sage/finance/__init__.py deleted file mode 100644 index cd972774cd6..00000000000 --- a/src/sage/finance/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from sage.misc.superseded import deprecation -deprecation(32427, "the package sage.finance is deprecated") diff --git a/src/sage/finance/all.py b/src/sage/finance/all.py deleted file mode 100644 index 8dd0e2b60b7..00000000000 --- a/src/sage/finance/all.py +++ /dev/null @@ -1,15 +0,0 @@ -from sage.misc.lazy_import import lazy_import - -lazy_import('sage.finance.stock', 'Stock') -lazy_import('sage.finance.markov_multifractal', 'MarkovSwitchingMultifractal') - -# We lazy_import the following modules since they import numpy which -# slows downsage startup -lazy_import('sage.finance.time_series', 'TimeSeries') -lazy_import('sage.finance.time_series', 'autoregressive_fit') -lazy_import('sage.finance.fractal', - ['stationary_gaussian_simulation', - 'fractional_gaussian_noise_simulation', - 'fractional_brownian_motion_simulation', - 'multifractal_cascade_random_walk_simulation']) -lazy_import('sage.finance.option', 'black_scholes') diff --git a/src/sage/finance/easter.py b/src/sage/finance/easter.py deleted file mode 100644 index 6c69f1d34ec..00000000000 --- a/src/sage/finance/easter.py +++ /dev/null @@ -1,117 +0,0 @@ -""" -Copyright (c) 2003-2005 Gustavo Niemeyer <gustavo@niemeyer.net> - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>" -__license__ = "PSF License" - -import datetime - -__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"] - -EASTER_JULIAN = 1 -EASTER_ORTHODOX = 2 -EASTER_WESTERN = 3 - - -def easter(year, algorithm=EASTER_WESTERN): - """ - This function was ported from the work done by GM Arts, - on top of the algorithm by Claus Tondering, which was - based in part on the algorithm of Ouding (1940), as - quoted in "Explanatory Supplement to the Astronomical - Almanac", P. Kenneth Seidelmann, editor. - - This function implements three different easter - calculation algorithms: - - 1 - Original calculation in Julian calendar, valid in - dates after 326 AD - 2 - Original algorithm, with date converted to Gregorian - calendar, valid in years 1583 to 4099 - 3 - Revised algorithm, in Gregorian calendar, valid in - years 1583 to 4099 as well - - These algorithms are represented by the constants: - - EASTER_JULIAN = 1 - EASTER_ORTHODOX = 2 - EASTER_WESTERN = 3 - - The default algorithm is algorithm 3. - - More about the algorithm may be found at: - - http://users.chariot.net.au/~gmarts/eastalg.htm - - and - - https://www.tondering.dk/claus/calendar.html - - EXAMPLES:: - - sage: import sage.finance.easter - doctest:warning... - DeprecationWarning: the package sage.finance is deprecated... - - sage: sage.finance.easter.easter(2009, 1) - datetime.date(2009, 4, 6) - sage: sage.finance.easter.easter(2009, 2) - datetime.date(2009, 4, 19) - sage: sage.finance.easter.easter(2009, 3) - datetime.date(2009, 4, 12) - sage: sage.finance.easter.easter(2010, 1) - datetime.date(2010, 3, 22) - sage: sage.finance.easter.easter(2010, 2) - datetime.date(2010, 4, 4) - sage: sage.finance.easter.easter(2010, 3) - datetime.date(2010, 4, 4) - - AUTHORS: - - - Gustavo Niemeyer (author of function) - - Phaedon Sinis (adapted code for sage) - """ - year = int(year) - algorithm = int(algorithm) - - if not (1 <= algorithm <= 3): - raise ValueError("invalid algorithm") - - # g - Golden year - 1 - # c - Century - # h - (23 - Epact) mod 30 - # i - Number of days from March 21 to Paschal Full Moon - # j - Weekday for PFM (0=Sunday, etc) - # p - Number of days from March 21 to Sunday on or before PFM - # (-6 to 28 algorithms 1 & 3, to 56 for algorithm 2) - # e - Extra days to add for algorithm 2 (converting Julian - # date to Gregorian date) - - y = year - g = y % 19 - e = 0 - if algorithm < 3: - # Old algorithm - i = (19*g+15)%30 - j = (y+y//4+i)%7 - if algorithm == 2: - # Extra dates to convert Julian to Gregorian date - e = 10 - if y > 1600: - e = e+y//100-16-(y//100-16)//4 - else: - # New algorithm - c = y//100 - h = (c-c//4-(8*c+13)//25+19*g+15)%30 - i = h-(h//28)*(1-(h//28)*(29//(h+1))*((21-g)//11)) - j = (y+y//4+i+2-c+c//4)%7 - - # p can be from -6 to 56 corresponding to dates 22 March to 23 May - # (later dates apply to algorithm 2, although 23 May never actually occurs) - p = i-j+e - d = 1+(p+27+(p+6)//40)%31 - m = 3+(p+26)//30 - return datetime.date(y, m, d) diff --git a/src/sage/finance/fractal.pyx b/src/sage/finance/fractal.pyx deleted file mode 100644 index a3323bc6c3c..00000000000 --- a/src/sage/finance/fractal.pyx +++ /dev/null @@ -1,344 +0,0 @@ -r""" -Multifractal Random Walk - -This module implements the fractal approach to understanding financial -markets that was pioneered by Mandelbrot. In particular, it implements -the multifractal random walk model of asset returns as developed by -Bacry, Kozhemyak, and Muzy, 2006, *Continuous cascade models for asset -returns* and many other papers by Bacry et al. See -http://www.cmap.polytechnique.fr/~bacry/ftpPapers.html - -See also Mandelbrot's *The Misbehavior of Markets* for a motivated -introduction to the general idea of using a self-similar approach to -modeling asset returns. - -One of the main goals of this implementation is that everything is -highly optimized and ready for real world high performance simulation -work. - -AUTHOR: - -- William Stein (2008) -""" - -from sage.rings.all import RDF, CDF, Integer -from sage.modules.free_module_element import vector -I = CDF.gen() - -from sage.stats.time_series cimport TimeSeries - -cdef extern from "math.h": - double exp(double) - double log(double) - double pow(double, double) - double sqrt(double) - -################################################################## -# Simulation -################################################################## - -def stationary_gaussian_simulation(s, N, n=1): - r""" - Implementation of the Davies-Harte algorithm which given an - autocovariance sequence (ACVS) ``s`` and an integer ``N``, simulates ``N`` - steps of the corresponding stationary Gaussian process with mean - 0. We assume that a certain Fourier transform associated to ``s`` is - nonnegative; if it isn't, this algorithm fails with a - ``NotImplementedError``. - - INPUT: - - - ``s`` -- a list of real numbers that defines the ACVS. - Optimally ``s`` should have length ``N+1``; if not - we pad it with extra 0's until it has length ``N+1``. - - - ``N`` -- a positive integer. - - OUTPUT: - - A list of ``n`` time series. - - EXAMPLES: - - We define an autocovariance sequence:: - - sage: N = 2^15 - sage: s = [1/math.sqrt(k+1) for k in [0..N]] - sage: s[:5] - [1.0, 0.7071067811865475, 0.5773502691896258, 0.5, 0.4472135954999579] - - We run the simulation:: - - sage: set_random_seed(0) - sage: sim = finance.stationary_gaussian_simulation(s, N)[0] - doctest:warning... - DeprecationWarning: the package sage.finance is deprecated... - - Note that indeed the autocovariance sequence approximates ``s`` well:: - - sage: [sim.autocovariance(i) for i in [0..4]] - [0.98665816086255..., 0.69201577095377..., 0.56234006792017..., 0.48647965409871..., 0.43667043322102...] - - .. WARNING:: - - If you were to do the above computation with a small - value of ``N``, then the autocovariance sequence would not approximate - ``s`` very well. - - REFERENCES: - - This is a standard algorithm that is described in several papers. - It is summarized nicely with many applications at the beginning of - *Simulating a Class of Stationary Gaussian Processes Using the - Davies-Harte Algorithm, with Application to Long Memory - Processes*, 2000, Peter F. Craigmile, which is easily found as a - free PDF via a Google search. This paper also generalizes the - algorithm to the case when all elements of ``s`` are nonpositive. - - The book *Wavelet Methods for Time Series Analysis* by Percival - and Walden also describes this algorithm, but has a typo in that - they put a `2\pi` instead of `\pi` a certain sum. That book describes - exactly how to use Fourier transform. The description is in - Section 7.8. Note that these pages are missing from the Google - Books version of the book, but are in the Amazon.com preview of - the book. - """ - N = Integer(N) - if N < 1: - raise ValueError("N must be positive") - - if not isinstance(s, TimeSeries): - s = TimeSeries(s) - - # Make sure s has length N+1. - if len(s) > N + 1: - s = s[:N+1] - elif len(s) < N + 1: - s += TimeSeries(N+1-len(s)) - - # Make symmetrized vector. - v = s + s[1:-1].reversed() - - # Compute its fast Fourier transform. - cdef TimeSeries a - a = v.fft() - - # Take the real entries in the result. - a = TimeSeries([a[0]]) + a[1:].scale_time(2) - - # Verify the nonnegativity condition. - if a.min() < 0: - raise NotImplementedError("Stationary Gaussian simulation only implemented when Fourier transform is nonnegative") - - sims = [] - cdef Py_ssize_t i, k, iN = N - cdef TimeSeries y, Z - cdef double temp, nn = N - for i from 0 <= i < n: - Z = TimeSeries(2*iN).randomize('normal') - y = TimeSeries(2*iN) - y._values[0] = sqrt(2*nn*a._values[0]) * Z._values[0] - y._values[2*iN-1] = sqrt(2*nn*a._values[iN]) * Z._values[2*iN-1] - for k from 1 <= k < iN: - temp = sqrt(nn*a._values[k]) - y._values[2*k-1] = temp*Z._values[2*k-1] - y._values[2*k] = temp*Z._values[2*k] - y.ifft(overwrite=True) - sims.append(y[:iN]) - - return sims - -def fractional_gaussian_noise_simulation(double H, double sigma2, N, n=1): - r""" - Return ``n`` simulations with ``N`` steps each of fractional Gaussian - noise with Hurst parameter ``H`` and innovations variance ``sigma2``. - - INPUT: - - - ``H`` -- float; ``0 < H < 1``; the Hurst parameter. - - - ``sigma2`` - positive float; innovation variance. - - - ``N`` -- positive integer; number of steps in simulation. - - - ``n`` -- positive integer (default: 1); number of simulations. - - OUTPUT: - - List of ``n`` time series. - - EXAMPLES: - - We simulate a fractional Gaussian noise:: - - sage: set_random_seed(0) - sage: finance.fractional_gaussian_noise_simulation(0.8,1,10,2) - [[-0.1157, 0.7025, 0.4949, 0.3324, 0.7110, 0.7248, -0.4048, 0.3103, -0.3465, 0.2964], - [-0.5981, -0.6932, 0.5947, -0.9995, -0.7726, -0.9070, -1.3538, -1.2221, -0.0290, 1.0077]] - - The sums define a fractional Brownian motion process:: - - sage: set_random_seed(0) - sage: finance.fractional_gaussian_noise_simulation(0.8,1,10,1)[0].sums() - [-0.1157, 0.5868, 1.0818, 1.4142, 2.1252, 2.8500, 2.4452, 2.7555, 2.4090, 2.7054] - - ALGORITHM: - - See *Simulating a Class of Stationary Gaussian - Processes using the Davies-Harte Algorithm, with Application to - Long Meoryy Processes*, 2000, Peter F. Craigmile for a discussion - and references for why the algorithm we give -- which uses - the ``stationary_gaussian_simulation()`` function. - """ - if H <= 0 or H >= 1: - raise ValueError("H must satisfy 0 < H < 1") - if sigma2 <= 0: - raise ValueError("sigma2 must be positive") - N = Integer(N) - if N < 1: - raise ValueError("N must be positive") - cdef TimeSeries s = TimeSeries(N+1) - s._values[0] = sigma2 - cdef Py_ssize_t k - cdef double H2 = 2*H - for k from 1 <= k <= N: - s._values[k] = sigma2/2 * (pow(k+1,H2) - 2*pow(k,H2) + pow(k-1,H2)) - return stationary_gaussian_simulation(s, N, n) - - -def fractional_brownian_motion_simulation(double H, double sigma2, N, n=1): - """ - Return the partial sums of a fractional Gaussian noise simulation - with the same input parameters. - - INPUT: - - - ``H`` -- float; ``0 < H < 1``; the Hurst parameter. - - - ``sigma2`` - float; innovation variance (should be close to 0). - - - ``N`` -- positive integer. - - - ``n`` -- positive integer (default: 1). - - OUTPUT: - - List of ``n`` time series. - - EXAMPLES:: - - sage: set_random_seed(0) - sage: finance.fractional_brownian_motion_simulation(0.8,0.1,8,1) - [[-0.0754, 0.1874, 0.2735, 0.5059, 0.6824, 0.6267, 0.6465, 0.6289]] - sage: set_random_seed(0) - sage: finance.fractional_brownian_motion_simulation(0.8,0.01,8,1) - [[-0.0239, 0.0593, 0.0865, 0.1600, 0.2158, 0.1982, 0.2044, 0.1989]] - sage: finance.fractional_brownian_motion_simulation(0.8,0.01,8,2) - [[-0.0167, 0.0342, 0.0261, 0.0856, 0.1735, 0.2541, 0.1409, 0.1692], - [0.0244, -0.0153, 0.0125, -0.0363, 0.0764, 0.1009, 0.1598, 0.2133]] - """ - return [a.sums() for a in fractional_gaussian_noise_simulation(H,sigma2,N,n)] - -def multifractal_cascade_random_walk_simulation(double T, - double lambda2, - double ell, - double sigma2, - N, - n=1): - r""" - Return a list of ``n`` simulations of a multifractal random walk using - the log-normal cascade model of Bacry-Kozhemyak-Muzy 2008. This - walk can be interpreted as the sequence of logarithms of a price - series. - - INPUT: - - - ``T`` -- positive real; the integral scale. - - - ``lambda2`` -- positive real; the intermittency coefficient. - - - ``ell`` -- a small number -- time step size. - - - ``sigma2`` -- variance of the Gaussian white noise ``eps[n]``. - - - ``N`` -- number of steps in each simulation. - - - ``n`` -- the number of separate simulations to run. - - OUTPUT: - - List of time series. - - EXAMPLES:: - - sage: set_random_seed(0) - sage: a = finance.multifractal_cascade_random_walk_simulation(3770,0.02,0.01,0.01,10,3) - sage: a - [[-0.0096, 0.0025, 0.0066, 0.0016, 0.0078, 0.0051, 0.0047, -0.0013, 0.0003, -0.0043], - [0.0003, 0.0035, 0.0257, 0.0358, 0.0377, 0.0563, 0.0661, 0.0746, 0.0749, 0.0689], - [-0.0120, -0.0116, 0.0043, 0.0078, 0.0115, 0.0018, 0.0085, 0.0005, 0.0012, 0.0060]] - - The corresponding price series:: - - sage: a[0].exp() - [0.9905, 1.0025, 1.0067, 1.0016, 1.0078, 1.0051, 1.0047, 0.9987, 1.0003, 0.9957] - - MORE DETAILS: - - The random walk has n-th step `\text{eps}_n e^{\omega_n}`, where - `\text{eps}_n` is gaussian white noise of variance `\sigma^2` and - `\omega_n` is renormalized gaussian magnitude, which is given by a - stationary gaussian simulation associated to a certain autocovariance - sequence. See Bacry, Kozhemyak, Muzy, 2006, - *Continuous cascade models for asset returns* for details. - """ - if ell <= 0: - raise ValueError("ell must be positive") - if T <= ell: - raise ValueError("T must be > ell") - if lambda2 <= 0: - raise ValueError("lambda2 must be positive") - N = Integer(N) - if N < 1: - raise ValueError("N must be positive") - - # Compute the mean of the Gaussian stationary process omega. - # See page 3 of Bacry, Kozhemyak, Muzy, 2008 -- "Log-Normal - # Continuous Cascades..." - cdef double mean = -lambda2 * (log(T/ell) + 1) - - # Compute the autocovariance sequence of the Gaussian - # stationary process omega. [Loc. cit.] We have - # tau = ell*i in that formula (6). - cdef TimeSeries s = TimeSeries(N+1) - s._values[0] = lambda2*(log(T/ell) + 1) - cdef Py_ssize_t i - for i from 1 <= i < N+1: - if ell*i >= T: - s._values[i] = lambda2 * log(T/(ell*i)) - else: - break # all covariance numbers after this point are 0 - - # Compute n simulations of omega, but with mean 0. - omega = stationary_gaussian_simulation(s, N+1, n) - - # Increase each by the given mean. - omega = [t.add_scalar(mean) for t in omega] - - # For each simulation, create corresponding multifractal - # random walk, as explained on page 6 of [loc. cit.] - sims = [] - cdef Py_ssize_t k - cdef TimeSeries eps, steps, om - for om in omega: - # First compute N Gaussian white noise steps - eps = TimeSeries(N).randomize('normal', 0, sigma2) - - # Compute the steps of the multifractal random walk. - steps = TimeSeries(N) - for k from 0 <= k < N: - steps._values[k] = eps._values[k] * exp(om._values[k]) - - sims.append(steps.sums()) - - return sims diff --git a/src/sage/finance/markov_multifractal.py b/src/sage/finance/markov_multifractal.py deleted file mode 100644 index 6206f56b304..00000000000 --- a/src/sage/finance/markov_multifractal.py +++ /dev/null @@ -1,278 +0,0 @@ -""" -Markov Switching Multifractal model - -REFERENCE: - -*How to Forecast Long-Run Volatility: Regime Switching and -the Estimation of Multifractal Processes*, Calvet and Fisher, 2004. - -AUTHOR: - -- William Stein, 2008 - -TESTS:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1.0,0.95,3) - doctest:warning... - DeprecationWarning: the package sage.finance is deprecated... - sage: loads(dumps(msm)) == msm - True -""" -import math - -class MarkovSwitchingMultifractal: - def __init__(self, kbar, m0, sigma, gamma_kbar, b): - """ - INPUT: - - - ``kbar`` -- positive integer - - - ``m0`` -- float with ``0 <= m0 <= 2`` - - - ``sigma`` -- positive float - - - ``gamma_kbar`` -- float with ``0 <= gamma_kbar < 1`` - - - ``b`` -- float > 1 - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,0.5,0.95,3); msm - Markov switching multifractal model with m0 = 1.4, sigma = 0.5, b = 3.0, and gamma_8 = 0.95 - sage: yen_usd = finance.MarkovSwitchingMultifractal(10,1.448,0.461,0.998,3.76) - sage: cad_usd = finance.MarkovSwitchingMultifractal(10,1.278,0.262,0.644,2.11) - sage: dm = finance.MarkovSwitchingMultifractal(10,1.326,0.643,0.959,2.7) - """ - self.__m0 = float(m0) - assert self.__m0 >= 0 and self.__m0 <= 2, "m0 must be between 0 and 2" - self.__sigma = float(sigma) - assert self.__sigma > 0, "sigma must be positive" - self.__b = float(b) - assert self.__b > 1, "b must be bigger than 1" - self.__gamma_kbar = float(gamma_kbar) - assert self.__gamma_kbar >= 0 and self.__gamma_kbar < 1, \ - "gamma_kbar must be between 0 and 1" - self.__kbar = int(kbar) - assert self.__kbar > 0, "kbar must be positive" - - def __eq__(self, other): - """ - Test equality of ``self`` and ``other``. - - Comparison is done on the tuple ``(m0, sigma, b, gamma_kbar, kbar)``. - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1.0,0.95,3) - - sage: msm == msm - True - sage: cad_usd = finance.MarkovSwitchingMultifractal(10,1.278,0.262,0.644,2.11); cad_usd - Markov switching multifractal model with m0 = 1.278, sigma = 0.262, b = 2.11, and gamma_10 = 0.644 - sage: msm == cad_usd - False - """ - if not isinstance(other, MarkovSwitchingMultifractal): - return False - return (self.__m0 == other.__m0 and - self.__sigma == other.__sigma and - self.__b == other.__b and - self.__gamma_kbar == other.__gamma_kbar and - self.__kbar == other.__kbar) - - def __hash__(self): - """ - Return the hash of ``self``. - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1.0,0.95,3) - sage: H = hash(msm) - """ - return hash((self.__m0, self.__sigma, self.__b, self.__gamma_kbar, - self.__kbar)) - - def __ne__(self, other): - """ - Test inequality of ``self`` and ``other``. - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1.0,0.95,3) - - sage: msm != msm - False - sage: cad_usd = finance.MarkovSwitchingMultifractal(10,1.278,0.262,0.644,2.11); cad_usd - Markov switching multifractal model with m0 = 1.278, sigma = 0.262, b = 2.11, and gamma_10 = 0.644 - sage: msm != cad_usd - True - """ - return not (self == other) - - def __repr__(self): - """ - Return string representation of Markov switching multifractal model. - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1,0.95,3) - sage: msm.__repr__() - 'Markov switching multifractal model with m0 = 1.4, sigma = 1.0, b = 3.0, and gamma_8 = 0.95' - """ - return "Markov switching multifractal model with m0 = %s, sigma = %s, b = %s, and gamma_%s = %s"%(self.m0(), self.sigma(), self.b(), self.kbar(), self.gamma_kbar()) - - def m0(self): - """ - Return parameter m0 of Markov switching multifractal model. - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1,0.95,3) - sage: msm.m0() - 1.4 - """ - return self.__m0 - - def sigma(self): - """ - Return parameter sigma of Markov switching multifractal model. - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1,0.95,3) - sage: msm.sigma() - 1.0 - """ - return self.__sigma - - def b(self): - """ - Return parameter b of Markov switching multifractal model. - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1,0.95,3) - sage: msm.b() - 3.0 - """ - return self.__b - - def gamma_kbar(self): - """ - Return parameter ``gamma_kbar`` of Markov switching multifractal model. - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,0.01,0.95,3) - sage: msm.gamma_kbar() - 0.95 - """ - return self.__gamma_kbar - - def kbar(self): - """ - Return parameter ``kbar`` of Markov switching multifractal model. - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,0.01,0.95,3) - sage: msm.kbar() - 8 - """ - return self.__kbar - - def gamma(self): - """ - Return the vector of the kbar transitional probabilities. - - OUTPUT: - - - gamma -- a tuple of ``self.kbar()`` floats. - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1.0,0.95,3) - sage: msm.gamma() - (0.001368852970712986, 0.004100940201672509, 0.012252436441829..., 0.03630878209190..., 0.10501923017634..., 0.28312883556311..., 0.6315968501359..., 0.95000000000000...) - """ - try: - return self.__gamma - except AttributeError: - pass - - b = self.__b - gamma_kbar = self.__gamma_kbar - kbar = self.__kbar - - # We compute gamma1 from gamma_kbar by inverting the relation - # that defines the gamma_k given on page 54 of Calvet-Fisher: - gamma1 = 1 - math.exp(math.log(1-gamma_kbar)/(b**(kbar-1))) - - gamma = tuple([1 - (1 - gamma1)**(b**k) for k in range(kbar)]) - self.__gamma = gamma - return gamma - - def simulation(self, n): - """ - Same as ``self.simulations``, but run only 1 time, and returns a time - series instead of a list of time series. - - INPUT: - - - ``n`` -- a positive integer. - - EXAMPLES:: - - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1.0,0.95,3) - sage: m = msm.simulation(5); m # random - [0.0059, -0.0097, -0.0101, -0.0110, -0.0067] - sage: len(m) - 5 - sage: m = msm.simulation(3); m # random - [0.0055, -0.0084, 0.0141] - sage: len(m) - 3 - """ - return self.simulations(n, 1)[0] - - def simulations(self, n, k=1): - """ - Return ``k`` simulations of length ``n`` using this Markov switching - multifractal model for ``n`` time steps. - - INPUT: - - - ``n`` -- positive integer; number of steps. - - - ``k`` -- positive integer (default: 1); number of simulations. - - OUTPUT: - - list -- a list of TimeSeries objects. - - EXAMPLES:: - - sage: cad_usd = finance.MarkovSwitchingMultifractal(10,1.278,0.262,0.644,2.11); cad_usd - Markov switching multifractal model with m0 = 1.278, sigma = 0.262, b = 2.11, and gamma_10 = 0.644 - """ - from . import markov_multifractal_cython - return markov_multifractal_cython.simulations(n, k, - self.__m0, self.__sigma, - self.__kbar, self.gamma()) - - - -## def ml_estimation(v, kbar, M): -## """ -## Compute parameters that model the time series v, - -## INPUT: -## v -- series of returns; e.g., sequence of -## differences of logs of price -## kbar -- positive integer; model parameter -## m -- finite list of the values that the multiplier -## M takes on. - -## OUTPUT: -## m0, sigma, gamma_kbar, b -## """ diff --git a/src/sage/finance/markov_multifractal_cython.pyx b/src/sage/finance/markov_multifractal_cython.pyx deleted file mode 100644 index 9b53511b45f..00000000000 --- a/src/sage/finance/markov_multifractal_cython.pyx +++ /dev/null @@ -1,75 +0,0 @@ -""" -Markov Switching Multifractal model - -Cython code -""" - -from sage.misc.randstate cimport randstate, current_randstate - -cdef extern from "math.h": - double sqrt(double) - -from sage.stats.time_series cimport TimeSeries - -def simulations(Py_ssize_t n, Py_ssize_t k, - double m0, double sigma, - int kbar, gamma): - """ - Return k simulations of length n using the Markov switching - multifractal model. - - INPUT: - n, k -- positive integers - m0, sigma -- floats - kbar -- integer - gamma -- list of floats - - OUTPUT: - list of lists - - EXAMPLES:: - - sage: set_random_seed(0) - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1.0,0.95,3) - doctest:warning... - DeprecationWarning: the package sage.finance is deprecated... - sage: import sage.finance.markov_multifractal_cython - sage: sage.finance.markov_multifractal_cython.simulations(5,2,1.278,0.262,8,msm.gamma()) - [[0.0014, -0.0023, -0.0028, -0.0030, -0.0019], [0.0020, -0.0020, 0.0034, -0.0010, -0.0004]] - """ - cdef double m1 = 2 - m0 - cdef Py_ssize_t i, j, a, c - cdef TimeSeries t, eps - cdef TimeSeries markov_state_vector = TimeSeries(kbar) - cdef TimeSeries gamma_vals = TimeSeries(gamma) - cdef randstate rstate = current_randstate() - - sigma = sigma / 100 # model's sigma is a percent - - # output list of simulations - S = [] - - for i from 0 <= i < k: - # Initialize the model - for j from 0 <= j < kbar: - # n & 1 means "is odd" - markov_state_vector._values[j] = m0 if (rstate.c_random() & 1) else m1 - t = TimeSeries(n) - - # Generate n normally distributed random numbers with mean 0 - # and variance 1. - eps = TimeSeries(n) - eps.randomize('normal') - - for a from 0 <= a < n: - # Compute next step in the simulation - t._values[a] = sigma * eps._values[a] * sqrt(markov_state_vector.prod()) - - # Now update the volatility state vector - for c from 0 <= c < kbar: - if rstate.c_rand_double() <= gamma_vals._values[c]: - markov_state_vector._values[c] = m0 if (rstate.c_random() & 1) else m1 - - S.append(t) - - return S diff --git a/src/sage/finance/option.pyx b/src/sage/finance/option.pyx deleted file mode 100644 index 31b290e0ce9..00000000000 --- a/src/sage/finance/option.pyx +++ /dev/null @@ -1,102 +0,0 @@ -""" - Tools for working with financial options - - AUTHORS: - - Brian Manion, 2013: initial version -""" - -cdef extern from "math.h": - double erf(double) - double exp(double) - double log(double) - double sqrt(double) - -def black_scholes(double spot_price, double strike_price, double time_to_maturity, double risk_free_rate, double vol, opt_type): - r""" - Calculates call/put price of European style options - using Black-Scholes formula. See [Shr2004]_ for one of many - standard references for this formula. - - INPUT: - - - ``spot_price`` -- The current underlying asset price - - ``strike_price`` -- The strike of the option - - ``time_to_maturity`` -- The # of years until expiration - - ``risk_free_rate`` -- The risk-free interest-rate - - ``vol`` -- The volatility - - ``opt_type`` -- string; The type of option, either ``'put'`` - for put option or ``'call'`` for call option - - OUTPUT: - - The price of an option with the given parameters. - - EXAMPLES:: - - sage: finance.black_scholes - doctest:warning... - DeprecationWarning: the package sage.finance is deprecated... - <built-in function black_scholes> - - sage: finance.black_scholes(42, 40, 0.5, 0.1, 0.2, 'call') # abs tol 1e-10 - 4.759422392871532 - sage: finance.black_scholes(42, 40, 0.5, 0.1, 0.2, 'put') # abs tol 1e-10 - 0.8085993729000958 - sage: finance.black_scholes(100, 95, 0.25, 0.1, 0.5, 'call') # abs tol 1e-10 - 13.695272738608132 - sage: finance.black_scholes(100, 95, 0.25, 0.1, 0.5, 'put') # abs tol 1e-10 - 6.349714381299734 - sage: finance.black_scholes(527.07, 520, 0.424563772, 0.0236734,0.15297,'whichever makes me more money') - Traceback (most recent call last): - ... - ValueError: 'whichever makes me more money' is not a valid string - """ - #First we calculate d1, d1=d11*d12, d12=d121+d122*d123 - cdef double d11 = 1/(vol*sqrt(time_to_maturity)) - - cdef double d121 = log(spot_price/strike_price) - cdef double d122 = risk_free_rate + pow(vol,2)/2 - cdef double d123 = time_to_maturity - cdef double d12 = d121+d122*d123 - - cdef double d1 = d11*d12 - cdef double d2 = d1 - vol*sqrt(time_to_maturity) - - cdef double call_value = _std_norm_cdf(d1)*spot_price - _std_norm_cdf(d2)*strike_price*exp(-1*risk_free_rate*time_to_maturity) - cdef double put_value = _std_norm_cdf(-1*d2)*strike_price*exp(-1*risk_free_rate*time_to_maturity) - _std_norm_cdf(-1*d1)*spot_price - - if opt_type == 'call': - return call_value - elif opt_type == 'put': - return put_value - else: - raise ValueError("'%s' is not a valid string" % opt_type) - -def _std_norm_cdf(double x): - r""" - Standard normal cumulative distribution function; Used internally. - - INPUT: - - - `x` -- The upper limit of integration for the standard normal cdf - - OUTPUT: - - The probability that a random variable X, which is standard normally - distributed, takes on a value less than or equal to x. - - EXAMPLES:: - - sage: from sage.finance.option import _std_norm_cdf - sage: _std_norm_cdf(0) # abs tol 1e-10 - 0.5 - sage: x = _std_norm_cdf(1.96); x # abs tol 1e-10 - 0.9750021048517795 - sage: y = _std_norm_cdf(-1.96); y # abs tol 1e-10 - 0.02499789514822044 - sage: x + y # abs tol 1e-10 - 1.0 - """ - cdef double e1 = x/sqrt(2) - cdef double prob = 0.5*(1+erf(e1)) - return prob diff --git a/src/sage/finance/stock.py b/src/sage/finance/stock.py deleted file mode 100644 index 0ffa2854853..00000000000 --- a/src/sage/finance/stock.py +++ /dev/null @@ -1,643 +0,0 @@ -r""" -Stock Market Price Series - -This module's main class is :class:`Stock`. It defines the following methods: - -.. csv-table:: - :class: contentstable - :widths: 20,80 - :delim: | - - :meth:`~sage.finance.stock.Stock.market_value` | Return the current market value of this stock. - :meth:`~sage.finance.stock.Stock.current_price_data` | Get Yahoo current price data for this stock. - :meth:`~sage.finance.stock.Stock.history` | Return an immutable sequence of historical price data for this stock - :meth:`~sage.finance.stock.Stock.open` | Return a time series containing historical opening prices for this stock. - :meth:`~sage.finance.stock.Stock.close` | Return the time series of all historical closing prices for this stock. - :meth:`~sage.finance.stock.Stock.load_from_file` | Load historical data from a local csv formatted data file. - -.. WARNING:: - - The `Stock` class is currently broken due to the change in the Yahoo - interface. See :trac:`25473`. - -AUTHORS: - -- William Stein, 2008 - -- Brett Nakayama, 2008 - -- Chris Swierczewski, 2008 - -TESTS:: - - sage: from sage.finance.stock import OHLC - doctest:warning... - DeprecationWarning: the package sage.finance is deprecated... - sage: ohlc = OHLC('18-Aug-04', 100.01, 104.06, 95.96, 100.34, 22353092) - sage: loads(dumps(ohlc)) == ohlc - True - -Classes and methods -------------------- -""" - -from sage.structure.all import Sequence -from datetime import date - -from urllib.request import urlopen - - -class OHLC: - def __init__(self, timestamp, open, high, low, close, volume): - """ - Open, high, low, and close information for a stock. Also stores - a timestamp for that data along with the volume. - - INPUT: - - - ``timestamp`` -- string - - - ``open``, ``high``, ``low``, ``close`` -- float - - - ``volume`` -- int - - EXAMPLES:: - - sage: from sage.finance.stock import OHLC - sage: OHLC('18-Aug-04', 100.01, 104.06, 95.96, 100.34, 22353092) - 18-Aug-04 100.01 104.06 95.96 100.34 22353092 - """ - self.timestamp = timestamp - self.open = float(open) - self.high = float(high) - self.low = float(low) - self.close = float(close) - self.volume = int(volume) - - def __repr__(self): - """ - Return string representation of stock OHLC data. - - EXAMPLES:: - - sage: from sage.finance.stock import OHLC - sage: OHLC('18-Aug-04', 100.01, 104.06, 95.96, 100.34, 22353092).__repr__() - ' 18-Aug-04 100.01 104.06 95.96 100.34 22353092' - """ - return '%10s %4.2f %4.2f %4.2f %4.2f %10d' % (self.timestamp, self.open, self.high, - self.low, self.close, self.volume) - - def __eq__(self, other): - """ - Compare ``self`` and ``other``. - - EXAMPLES:: - - sage: from sage.finance.stock import OHLC - sage: ohlc = OHLC('18-Aug-04', 100.01, 104.06, 95.96, 100.34, 22353092) - sage: ohlc2 = OHLC('18-Aug-04', 101.01, 104.06, 95.96, 100.34, 22353092) - sage: ohlc == ohlc2 - False - """ - if not isinstance(other, OHLC): - return False - return (self.timestamp == other.timestamp and - self.open == other.open and - self.high == other.high and - self.low == other.low and - self.close == other.close and - self.volume == other.volume) - - def __hash__(self): - """ - Return the hash of ``self``. - - EXAMPLES:: - - sage: from sage.finance.stock import OHLC - sage: ohlc = OHLC('18-Aug-04', 100.01, 104.06, 95.96, 100.34, 22353092) - sage: H = hash(ohlc) - """ - return hash((self.timestamp, - self.open, - self.high, - self.low, - self.close , - self.volume)) - - def __ne__(self, other): - """ - Compare ``self`` and ``other``. - - EXAMPLES:: - - sage: from sage.finance.stock import OHLC - sage: ohlc = OHLC('18-Aug-04', 100.01, 104.06, 95.96, 100.34, 22353092) - sage: ohlc2 = OHLC('18-Aug-04', 101.01, 104.06, 95.96, 100.34, 22353092) - sage: ohlc != ohlc2 - True - """ - return not (self == other) - - -class Stock: - """ - Class for retrieval of stock market information. - """ - def __init__(self, symbol, cid=''): - """ - Create a ``Stock`` object. Optional initialization by ``cid``: an - identifier for each equity used by Google Finance. - - INPUT: - - - ``symbol`` -- string, a ticker symbol (with or without market). - Format: ``"MARKET:SYMBOL"`` or ``"SYMBOL"``. If you don't - supply the market, it is assumed to be NYSE or NASDAQ. - e.g. "goog" or "OTC:NTDOY" - - - ``cid`` -- Integer, a Google contract ID (optional). - - - .. NOTE:: - - Currently, the symbol and cid do not have to match. When using - :meth:`history`, the cid will take precedence. - - EXAMPLES:: - - sage: S = finance.Stock('ibm') # optional -- internet - doctest:warning... - DeprecationWarning: Importing finance from here is deprecated... - sage: S # optional -- internet # known bug - IBM (...) - """ - self.symbol = symbol.upper() - self.cid = cid - - def __repr__(self): - """ - Return string representation of this stock. - - EXAMPLES:: - - sage: finance.Stock('ibm').__repr__() # optional -- internet # known bug - 'IBM (...)' - """ - return "%s (%s)" % (self.symbol, self.market_value()) - - def market_value(self): - """ - Return the current market value of this stock. - - OUTPUT: - - A Python float. - - EXAMPLES:: - - sage: finance.Stock('goog').market_value() # random; optional - internet # known bug - 575.83000000000004 - """ - return float(self.current_price_data()['price']) - - def current_price_data(self): - r""" - Get Yahoo current price data for this stock. - - This method returns a dictionary with the following keys: - - - .. csv-table:: - :class: contentstable - :widths: 25,25,25,25 - :delim: | - - ``'price'`` | ``'change'`` | ``'volume'`` | ``'avg_daily_volume'`` - ``'stock_exchange'`` | ``'market_cap'`` | ``'book_value'`` | ``'ebitda'`` - ``'dividend_per_share'`` | ``'dividend_yield'`` | ``'earnings_per_share'`` | ``'52_week_high'`` - ``'52_week_low'`` | ``'50day_moving_avg'`` | ``'200day_moving_avg'`` | ``'price_earnings_ratio'`` - ``'price_earnings_growth_ratio'`` | ``'price_sales_ratio'`` | ``'price_book_ratio'`` | ``'short_ratio'``. - - EXAMPLES:: - - sage: finance.Stock('GOOG').current_price_data() # random; optional - internet # known bug - {'200day_moving_avg': '536.57', - '50day_moving_avg': '546.01', - '52_week_high': '599.65', - '52_week_low': '487.56', - 'avg_daily_volume': '1826450', - 'book_value': '153.64', - 'change': '+0.56', - 'dividend_per_share': 'N/A', - 'dividend_yield': 'N/A', - 'earnings_per_share': '20.99', - 'ebitda': '21.48B', - 'market_cap': '366.11B', - 'price': '537.90', - 'price_book_ratio': '3.50', - 'price_earnings_growth_ratio': '0.00', - 'price_earnings_ratio': '25.62', - 'price_sales_ratio': '5.54', - 'short_ratio': '1.50', - 'stock_exchange': '"NMS"', - 'volume': '1768181'} - - TESTS:: - - sage: finance.Stock('GOOG').current_price_data() # optional -- internet # known bug - {'200day_moving_avg': ..., - '50day_moving_avg': ..., - '52_week_high': ..., - '52_week_low': ..., - 'avg_daily_volume': ..., - 'book_value': ..., - 'change': ..., - 'dividend_per_share': ..., - 'dividend_yield': ..., - 'earnings_per_share': ..., - 'ebitda': ..., - 'market_cap': ..., - 'price': ..., - 'price_book_ratio': ..., - 'price_earnings_growth_ratio': ..., - 'price_earnings_ratio': ..., - 'price_sales_ratio': ..., - 'short_ratio': ..., - 'stock_exchange': ..., - 'volume': ...} - """ - url = 'http://finance.yahoo.com/d/quotes.csv?s=%s&f=%s' % (self.symbol, 'l1c1va2xj1b4j4dyekjm3m4rr5p5p6s7') - values = urlopen(url).read().strip().strip('"').split(',') - data = {} - data['price'] = values[0] - data['change'] = values[1] - data['volume'] = values[2] - data['avg_daily_volume'] = values[3] - data['stock_exchange'] = values[4] - data['market_cap'] = values[5] - data['book_value'] = values[6] - data['ebitda'] = values[7] - data['dividend_per_share'] = values[8] - data['dividend_yield'] = values[9] - data['earnings_per_share'] = values[10] - data['52_week_high'] = values[11] - data['52_week_low'] = values[12] - data['50day_moving_avg'] = values[13] - data['200day_moving_avg'] = values[14] - data['price_earnings_ratio'] = values[15] - data['price_earnings_growth_ratio'] = values[16] - data['price_sales_ratio'] = values[17] - data['price_book_ratio'] = values[18] - data['short_ratio'] = values[19] - return data - - def history(self, startdate='Jan+1,+1900', enddate=None, histperiod='daily'): - """ - Return an immutable sequence of historical price data - for this stock, obtained from Google. OHLC data is stored - internally as well. By default, returns the past year's daily - OHLC data. - - Dates ``startdate`` and ``enddate`` should be formatted - ``'Mon+d,+yyyy'``, where ``'Mon'`` is a three character abbreviation - of the month's name. - - .. NOTE:: - - Google Finance returns the past year's financial data by default - when ``startdate`` is set too low from the equity's date of going - public. By default, this function only looks at the NASDAQ and - NYSE markets. However, if you specified the market during - initialization of the stock (i.e. ``finance.Stock("OTC:NTDOY")``), - this method will give correct results. - - INPUT: - - - ``startdate`` -- string, (default: ``'Jan+1,+1900'``) - - - ``enddate`` -- string, (default: current date) - - - ``histperiod`` -- string, (``'daily'`` or ``'weekly'``) - - OUTPUT: - - A sequence. - - EXAMPLES: - - We get the first five days of VMware's stock history:: - - sage: finance.Stock('vmw').history('Aug+13,+2007')[:5] # optional -- internet # known bug - [ - 14-Aug-07 50.00 55.50 48.00 51.00 38262850, - 15-Aug-07 52.11 59.87 51.50 57.71 10689100, - 16-Aug-07 60.99 61.49 52.71 56.99 6919500, - 17-Aug-07 59.00 59.00 54.45 55.55 3087000, - 20-Aug-07 56.05 57.50 55.61 57.33 2141900 - ] - sage: finance.Stock('F').history('Aug+20,+1992', 'Jul+7,+2008')[:5] # optional -- internet # known bug - [ - 20-Aug-92 0.00 7.90 7.73 7.83 5492698, - 21-Aug-92 0.00 7.92 7.66 7.68 5345999, - 24-Aug-92 0.00 7.59 7.33 7.35 11056299, - 25-Aug-92 0.00 7.66 7.38 7.61 8875299, - 26-Aug-92 0.00 7.73 7.64 7.68 6447201 - ] - - Note that when ``startdate`` is too far prior to a stock's actual start - date, Google Finance defaults to a year's worth of stock history - leading up to the specified end date. For example, Apple's (AAPL) - stock history only dates back to September 7, 1984:: - - sage: finance.Stock('AAPL').history('Sep+1,+1900', 'Jan+1,+2000')[0:5] # optional -- internet # known bug - [ - 4-Jan-99 0.00 1.51 1.43 1.47 238221200, - 5-Jan-99 0.00 1.57 1.48 1.55 352522800, - 6-Jan-99 0.00 1.58 1.46 1.49 337125600, - 7-Jan-99 0.00 1.61 1.50 1.61 357254800, - 8-Jan-99 0.00 1.67 1.57 1.61 169680000 - ] - - Here is an example where we create and get the history of a stock - that is not in NASDAQ or NYSE:: - - sage: finance.Stock("OTC:NTDOY").history(startdate="Jan+1,+2007", enddate="Jan+1,+2008")[:5] # optional -- internet # known bug - [ - 3-Jan-07 32.44 32.75 32.30 32.44 156283, - 4-Jan-07 31.70 32.40 31.20 31.70 222643, - 5-Jan-07 30.15 30.50 30.15 30.15 65670, - 8-Jan-07 30.10 30.50 30.00 30.10 130765, - 9-Jan-07 29.90 30.05 29.60 29.90 103338 - ] - - Here, we create a stock by cid, and get historical data. - Note that when using historical, if a cid is specified, - it will take precedence over the stock's symbol. So, if - the symbol and cid do not match, the history based on the - contract id will be returned. :: - - sage: sage.finance.stock.Stock("AAPL", 22144).history(startdate='Jan+1,+1990')[:5] #optional -- internet # known bug - [ - 8-Jun-99 0.00 1.74 1.70 1.70 78414000, - 9-Jun-99 0.00 1.73 1.69 1.73 88446400, - 10-Jun-99 0.00 1.72 1.69 1.72 79262400, - 11-Jun-99 0.00 1.73 1.65 1.66 46261600, - 14-Jun-99 0.00 1.67 1.61 1.62 39270000 - ] - """ - if enddate is None: - enddate = date.today().strftime("%b+%d,+%Y") - - symbol = self.symbol - - if self.cid == '': - if ':' in symbol: - R = self._get_data('', startdate, enddate, histperiod) - else: - try: - R = self._get_data('NASDAQ:', startdate, enddate, histperiod) - except RuntimeError: - R = self._get_data("NYSE:", startdate, enddate, histperiod) - else: - R = self._get_data('', startdate, enddate, histperiod) - self.__historical = [] - self.__historical = self._load_from_csv(R) - return self.__historical - - def open(self, *args, **kwds): - r""" - Return a time series containing historical opening prices for this - stock. If no arguments are given, will return last acquired historical - data. Otherwise, data will be gotten from Google Finance. - - INPUT: - - - ``startdate`` -- string, (default: ``'Jan+1,+1900'``) - - - ``enddate`` -- string, (default: current date) - - - ``histperiod`` -- string, (``'daily'`` or ``'weekly'``) - - OUTPUT: - - A time series -- close price data. - - EXAMPLES: - - You can directly obtain Open data as so:: - - sage: finance.Stock('vmw').open(startdate='Jan+1,+2008', enddate='Feb+1,+2008') # optional -- internet # known bug - [85.4900, 84.9000, 82.0000, 81.2500, ... 82.0000, 58.2700, 54.4900, 55.6000, 56.9800] - - Or, you can initialize stock data first and then extract the Open - data:: - - sage: c = finance.Stock('vmw') # optional -- internet # known bug - sage: c.history(startdate='Feb+1,+2008', enddate='Mar+1,+2008')[:5] # optional -- internet # known bug - [ - 1-Feb-08 56.98 58.14 55.06 57.85 2490481, - 4-Feb-08 58.00 60.47 56.91 58.05 1840709, - 5-Feb-08 57.60 59.30 57.17 59.30 1712179, - 6-Feb-08 60.32 62.00 59.50 61.52 2211775, - 7-Feb-08 60.50 62.75 59.56 60.80 1521651 - ] - sage: c.open() # optional -- internet # known bug - [56.9800, 58.0000, 57.6000, 60.3200, ... 56.5500, 59.3000, 60.0000, 59.7900, 59.2600] - - Otherwise, :meth:`history` will be called with the default - arguments returning a year's worth of data:: - - sage: finance.Stock('vmw').open() # random; optional -- internet # known bug - [52.1100, 60.9900, 59.0000, 56.0500, 57.2500, ... 83.0500, 85.4900, 84.9000, 82.0000, 81.2500] - """ - - from .time_series import TimeSeries - - if len(args) != 0: - return TimeSeries([x.open for x in self.history(*args, **kwds)]) - - try: - return TimeSeries([x.open for x in self.__historical]) - except AttributeError: - pass - - return TimeSeries([x.open for x in self.history(*args, **kwds)]) - - def close(self, *args, **kwds): - r""" - Return the time series of all historical closing prices for this stock. - If no arguments are given, will return last acquired historical data. - Otherwise, data will be gotten from Google Finance. - - INPUT: - - - ``startdate`` -- string, (default: ``'Jan+1,+1900'``) - - - ``enddate`` -- string, (default: current date) - - - ``histperiod`` -- string, (``'daily'`` or ``'weekly'``) - - OUTPUT: - - A time series -- close price data. - - EXAMPLES: - - You can directly obtain close data as so:: - - sage: finance.Stock('vmw').close(startdate='Jan+1,+2008', enddate='Feb+1,+2008') # optional -- internet # known bug - [84.6000, 83.9500, 80.4900, 72.9900, ... 83.0000, 54.8700, 56.4200, 56.6700, 57.8500] - - Or, you can initialize stock data first and then extract the Close - data:: - - sage: c = finance.Stock('vmw') # optional -- internet # known bug - sage: c.history(startdate='Feb+1,+2008', enddate='Mar+1,+2008')[:5] # optional -- internet # known bug - [ - 1-Feb-08 56.98 58.14 55.06 57.85 2490481, - 4-Feb-08 58.00 60.47 56.91 58.05 1840709, - 5-Feb-08 57.60 59.30 57.17 59.30 1712179, - 6-Feb-08 60.32 62.00 59.50 61.52 2211775, - 7-Feb-08 60.50 62.75 59.56 60.80 1521651 - ] - sage: c.close() # optional -- internet # known bug - [57.8500, 58.0500, 59.3000, 61.5200, ... 58.2900, 60.1800, 59.8600, 59.9500, 58.6700] - - Otherwise, :meth:`history` will be called with the default - arguments returning a year's worth of data:: - - sage: finance.Stock('vmw').close() # random; optional -- internet # known bug - [57.7100, 56.9900, 55.5500, 57.3300, 65.9900 ... 84.9900, 84.6000, 83.9500, 80.4900, 72.9900] - """ - - from .time_series import TimeSeries - - if args: - return TimeSeries([x.close for x in self.history(*args, **kwds)]) - - try: - return TimeSeries([x.close for x in self.__historical]) - except AttributeError: - pass - - return TimeSeries([x.close for x in self.history(*args, **kwds)]) - - def load_from_file(self, file): - r""" - Load historical data from a local csv formatted data file. Note - that no symbol data is included in Google Finance's csv data. - The csv file must be formatted in the following way, just as - on Google Finance:: - - Timestamp,Open,High,Low,Close,Volume - - INPUT: - - - ``file`` -- local file with Google Finance formatted OHLC data. - - OUTPUT: - - A sequence -- OHLC data. - - EXAMPLES: - - Suppose you have a file in your home directory containing Apple stock - OHLC data, such as that from Google Finance, called - ``AAPL-minutely.csv``. One can load this information into a Stock - object like so. Note that the path must be explicit:: - - sage: filename = tmp_filename(ext='.csv') - sage: with open(filename, 'w') as fobj: - ....: _ = fobj.write("Date,Open,High,Low,Close,Volume\n1212405780,187.80,187.80,187.80,187.80,100\n1212407640,187.75,188.00,187.75,188.00,2000\n1212407700,188.00,188.00,188.00,188.00,1000\n1212408000,188.00,188.11,188.00,188.00,2877\n1212408060,188.00,188.00,188.00,188.00,687") - sage: finance.Stock('aapl').load_from_file(filename)[:5] - ... - 1212408060 188.00 188.00 188.00 188.00 687, - 1212408000 188.00 188.11 188.00 188.00 2877, - 1212407700 188.00 188.00 188.00 188.00 1000, - 1212407640 187.75 188.00 187.75 188.00 2000, - 1212405780 187.80 187.80 187.80 187.80 100 - ] - - - Note that since the source file doesn't contain information on which - equity the information comes from, the symbol designated at - initialization of Stock need not match the source of the data. For - example, we can initialize a Stock object with the symbol ``'goog'``, - but load data from ``'aapl'`` stock prices:: - - sage: finance.Stock('goog').load_from_file(filename)[:5] - [ - 1212408060 188.00 188.00 188.00 188.00 687, - 1212408000 188.00 188.11 188.00 188.00 2877, - 1212407700 188.00 188.00 188.00 188.00 1000, - 1212407640 187.75 188.00 187.75 188.00 2000, - 1212405780 187.80 187.80 187.80 187.80 100 - ] - """ - with open(file) as file_obj: - R = file_obj.read() - self.__historical = self._load_from_csv(R) - return self.__historical - - def _load_from_csv(self, R): - r""" - EXAMPLES: - - This indirectly tests ``_load_from_csv()``:: - - sage: filename = tmp_filename(ext='.csv') - sage: with open(filename,'w') as fobj: - ....: _ = fobj.write("Date,Open,High,Low,Close,Volume\n1212405780,187.80,187.80,187.80,187.80,100\n1212407640,187.75,188.00,187.75,188.00,2000\n1212407700,188.00,188.00,188.00,188.00,1000\n1212408000,188.00,188.11,188.00,188.00,2877\n1212408060,188.00,188.00,188.00,188.00,687") - sage: finance.Stock('aapl').load_from_file(filename) - [ - 1212408060 188.00 188.00 188.00 188.00 687, - 1212408000 188.00 188.11 188.00 188.00 2877, - 1212407700 188.00 188.00 188.00 188.00 1000, - 1212407640 187.75 188.00 187.75 188.00 2000, - 1212405780 187.80 187.80 187.80 187.80 100 - ] - """ - R = R.splitlines() - hist_data = [] - for x in reversed(R[1:]): - try: - timestamp, opn, high, low, close, volume = x.split(',') - ohlc = OHLC(timestamp, opn, high, low, close, volume) - hist_data.append(ohlc) - except ValueError: - pass - hist_data = Sequence(hist_data,cr=True,universe=lambda x:x, immutable=True) - return hist_data - - def _get_data(self, exchange, startdate, enddate, histperiod='daily'): - """ - This function is used internally. - - EXAMPLES: - - This indirectly tests the use of ``_get_data()``:: - - sage: finance.Stock('aapl').history(startdate='Jan+1,+1990',enddate='Jan+1,+1991')[:2] # optional -- internet # known bug - [ - 2-Jan-90 0.00 1.34 1.25 1.33 45799600, - 3-Jan-90 0.00 1.36 1.34 1.34 51998800 - ] - - TESTS:: - - sage: finance.Stock('whatever').history() # optional -- internet # known bug - Traceback (most recent call last): - ... - RuntimeError: Google reported a wrong request (did you specify a cid?) - """ - symbol = self.symbol - cid = self.cid - if cid == '': - url = 'http://finance.google.com/finance/historical?q=%s%s&startdate=%s&enddate=%s&histperiod=%s&output=csv' % (exchange, symbol.upper(), startdate, enddate, histperiod) - else: - url = 'http://finance.google.com/finance/historical?cid=%s&startdate=%s&enddate=%s&histperiod=%s&output=csv' % (cid, startdate, enddate, histperiod) - data = urlopen(url).read() - if "Bad Request" in data or "The requested URL was not found on this server." in data: - raise RuntimeError("Google reported a wrong request (did you specify a cid?)") - return data diff --git a/src/sage/finance/time_series.py b/src/sage/finance/time_series.py deleted file mode 100644 index ab2d836d1fa..00000000000 --- a/src/sage/finance/time_series.py +++ /dev/null @@ -1,10 +0,0 @@ -r""" -Time Series (deprecated module) - -This module consists only of deprecated lazy imports from -:mod:`sage.stats.time_series`. -""" - - -from sage.misc.lazy_import import lazy_import -lazy_import('sage.stats.time_series', ('TimeSeries', 'autoregressive_fit'), deprecation=32427) diff --git a/src/sage/functions/airy.py b/src/sage/functions/airy.py index eceb9e6eafc..11f4c56be8c 100644 --- a/src/sage/functions/airy.py +++ b/src/sage/functions/airy.py @@ -30,9 +30,9 @@ Verify that the Airy functions are solutions to the differential equation:: - sage: diff(airy_ai(x), x, 2) - x * airy_ai(x) + sage: diff(airy_ai(x), x, 2) - x * airy_ai(x) # needs sage.symbolic 0 - sage: diff(airy_bi(x), x, 2) - x * airy_bi(x) + sage: diff(airy_bi(x), x, 2) - x * airy_bi(x) # needs sage.symbolic 0 """ @@ -46,11 +46,17 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.symbolic.function import BuiltinFunction -from sage.symbolic.expression import Expression -from sage.symbolic.ring import SR -from sage.rings.integer_ring import ZZ from sage.calculus.functional import derivative +from sage.misc.lazy_import import lazy_import +from sage.rings.integer_ring import ZZ +from sage.structure.element import Expression +from sage.symbolic.function import BuiltinFunction + +lazy_import('sage.symbolic.ring', 'SR') + +lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') +lazy_import('mpmath', ['airyai', 'airybi'], + as_=['_mpmath_airyai', '_mpmath_airybi']) class FunctionAiryAiGeneral(BuiltinFunction): @@ -76,6 +82,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.functions.airy import airy_ai_general sage: x, n = var('x n') sage: airy_ai_general(-2, x) @@ -95,10 +102,10 @@ def _derivative_(self, alpha, x, diff_param=None): EXAMPLES:: sage: from sage.functions.airy import airy_ai_general - sage: x, n = var('x n') - sage: derivative(airy_ai_general(n, x), x) + sage: x, n = var('x n') # needs sage.symbolic + sage: derivative(airy_ai_general(n, x), x) # needs sage.symbolic airy_ai(n + 1, x) - sage: derivative(airy_ai_general(n, x), n) + sage: derivative(airy_ai_general(n, x), n) # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: cannot differentiate airy_ai @@ -114,10 +121,10 @@ def _eval_(self, alpha, x): EXAMPLES:: sage: from sage.functions.airy import airy_ai_general - sage: x, n = var('x n') - sage: airy_ai_general(-2, 1.0) + sage: x, n = var('x n') # needs sage.symbolic + sage: airy_ai_general(-2, 1.0) # needs mpmath 0.136645379421096 - sage: airy_ai_general(n, 1.0) + sage: airy_ai_general(n, 1.0) # needs sage.symbolic airy_ai(n, 1.00000000000000) """ if not isinstance(x, Expression) and \ @@ -138,13 +145,11 @@ def _evalf_(self, alpha, x, parent=None, algorithm=None): EXAMPLES:: sage: from sage.functions.airy import airy_ai_general - sage: airy_ai_general(-2, 1.0) + sage: airy_ai_general(-2, 1.0) # needs mpmath 0.136645379421096 """ - import mpmath - from sage.libs.mpmath import utils as mpmath_utils - return mpmath_utils.call(mpmath.airyai, x, derivative=alpha, - parent=parent) + return _mpmath_utils_call(_mpmath_airyai, x, derivative=alpha, + parent=parent) class FunctionAiryAiSimple(BuiltinFunction): @@ -155,9 +160,9 @@ def __init__(self): EXAMPLES:: sage: from sage.functions.airy import airy_ai_simple - sage: f = airy_ai_simple(x); f + sage: f = airy_ai_simple(x); f # needs sage.symbolic airy_ai(x) - sage: airy_ai_simple(x)._sympy_() + sage: airy_ai_simple(x)._sympy_() # needs sage.symbolic airyai(x) """ BuiltinFunction.__init__(self, 'airy_ai', @@ -173,7 +178,7 @@ def _derivative_(self, x, diff_param=None): EXAMPLES:: sage: from sage.functions.airy import airy_ai_simple - sage: derivative(airy_ai_simple(x), x) + sage: derivative(airy_ai_simple(x), x) # needs sage.symbolic airy_ai_prime(x) """ return airy_ai_prime(x) @@ -183,13 +188,13 @@ def _eval_(self, x): EXAMPLES:: sage: from sage.functions.airy import airy_ai_simple - sage: airy_ai_simple(0) + sage: airy_ai_simple(0) # needs sage.symbolic 1/3*3^(1/3)/gamma(2/3) - sage: airy_ai_simple(0.0) + sage: airy_ai_simple(0.0) # needs mpmath 0.355028053887817 - sage: airy_ai_simple(I) + sage: airy_ai_simple(I) # needs sage.symbolic airy_ai(I) - sage: airy_ai_simple(1.0 * I) + sage: airy_ai_simple(1.0 * I) # needs sage.symbolic 0.331493305432141 - 0.317449858968444*I """ from .gamma import gamma @@ -202,27 +207,28 @@ def _evalf_(self, x, **kwargs): EXAMPLES:: sage: from sage.functions.airy import airy_ai_simple - sage: airy_ai_simple(0.0) + sage: airy_ai_simple(0.0) # needs mpmath 0.355028053887817 - sage: airy_ai_simple(1.0 * I) + sage: airy_ai_simple(1.0 * I) # needs sage.symbolic 0.331493305432141 - 0.317449858968444*I We can use several methods for numerical evaluation:: + sage: # needs sage.symbolic sage: airy_ai_simple(3).n(algorithm='mpmath') 0.00659113935746072 sage: airy_ai_simple(3).n(algorithm='mpmath', prec=100) 0.0065911393574607191442574484080 - sage: airy_ai_simple(3).n(algorithm='scipy') # rel tol 1e-10 + sage: airy_ai_simple(3).n(algorithm='scipy') # rel tol 1e-10 # needs scipy 0.006591139357460719 sage: airy_ai_simple(I).n(algorithm='scipy') # rel tol 1e-10 0.33149330543214117 - 0.3174498589684438*I TESTS:: - sage: parent(airy_ai_simple(3).n(algorithm='scipy')) + sage: parent(airy_ai_simple(3).n(algorithm='scipy')) # needs scipy sage.rings.real_mpfr sage.symbolic Real Field with 53 bits of precision - sage: airy_ai_simple(3).n(algorithm='scipy', prec=200) + sage: airy_ai_simple(3).n(algorithm='scipy', prec=200) # needs scipy sage.symbolic Traceback (most recent call last): ... NotImplementedError: airy_ai not implemented for precision > 53 @@ -246,9 +252,7 @@ def _evalf_(self, x, **kwargs): return CC(y) return parent(y) elif algorithm == 'mpmath': - import mpmath - from sage.libs.mpmath import utils as mpmath_utils - return mpmath_utils.call(mpmath.airyai, x, parent=parent) + return _mpmath_utils_call(_mpmath_airyai, x, parent=parent) else: raise ValueError("unknown algorithm '%s'" % algorithm) @@ -261,12 +265,13 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: x, n = var('x n') sage: airy_ai_prime(x) airy_ai_prime(x) sage: airy_ai_prime(0) -1/3*3^(2/3)/gamma(1/3) - sage: airy_ai_prime(x)._sympy_() + sage: airy_ai_prime(x)._sympy_() # needs sympy airyaiprime(x) """ BuiltinFunction.__init__(self, 'airy_ai_prime', @@ -280,7 +285,7 @@ def _derivative_(self, x, diff_param=None): """ EXAMPLES:: - sage: derivative(airy_ai_prime(x), x) + sage: derivative(airy_ai_prime(x), x) # needs sage.symbolic x*airy_ai(x) """ return x * airy_ai_simple(x) @@ -289,9 +294,9 @@ def _eval_(self, x): """ EXAMPLES:: - sage: airy_ai_prime(0) + sage: airy_ai_prime(0) # needs sage.symbolic -1/3*3^(2/3)/gamma(1/3) - sage: airy_ai_prime(0.0) + sage: airy_ai_prime(0.0) # needs mpmath -0.258819403792807 """ from .gamma import gamma @@ -303,25 +308,26 @@ def _evalf_(self, x, **kwargs): """ EXAMPLES:: - sage: airy_ai_prime(0.0) + sage: airy_ai_prime(0.0) # needs mpmath -0.258819403792807 We can use several methods for numerical evaluation:: + sage: # needs sage.symbolic sage: airy_ai_prime(4).n(algorithm='mpmath') -0.00195864095020418 sage: airy_ai_prime(4).n(algorithm='mpmath', prec=100) -0.0019586409502041789001381409184 - sage: airy_ai_prime(4).n(algorithm='scipy') # rel tol 1e-10 + sage: airy_ai_prime(4).n(algorithm='scipy') # rel tol 1e-10 # needs scipy -0.00195864095020418 - sage: airy_ai_prime(I).n(algorithm='scipy') # rel tol 1e-10 + sage: airy_ai_prime(I).n(algorithm='scipy') # rel tol 1e-10 # needs scipy -0.43249265984180707 + 0.09804785622924324*I TESTS:: - sage: parent(airy_ai_prime(3).n(algorithm='scipy')) + sage: parent(airy_ai_prime(3).n(algorithm='scipy')) # needs scipy sage.rings.real_mpfr sage.symbolic Real Field with 53 bits of precision - sage: airy_ai_prime(3).n(algorithm='scipy', prec=200) + sage: airy_ai_prime(3).n(algorithm='scipy', prec=200) # needs scipy sage.symbolic Traceback (most recent call last): ... NotImplementedError: airy_ai_prime not implemented @@ -346,9 +352,7 @@ def _evalf_(self, x, **kwargs): return CC(y) return parent(y) elif algorithm == 'mpmath': - import mpmath - from sage.libs.mpmath import utils as mpmath_utils - return mpmath_utils.call(mpmath.airyai, x, derivative=1, + return _mpmath_utils_call(_mpmath_airyai, x, derivative=1, parent=parent) else: raise ValueError("unknown algorithm '%s'" % algorithm) @@ -405,12 +409,13 @@ def airy_ai(alpha, x=None, hold_derivative=True, **kwds): EXAMPLES:: - sage: n, x = var('n x') - sage: airy_ai(x) + sage: n, x = var('n x') # needs sage.symbolic + sage: airy_ai(x) # needs sage.symbolic airy_ai(x) It can return derivatives or integrals:: + sage: # needs sage.symbolic sage: airy_ai(2, x) airy_ai(2, x) sage: airy_ai(1, x, hold_derivative=False) @@ -425,35 +430,35 @@ def airy_ai(alpha, x=None, hold_derivative=True, **kwds): It can be evaluated symbolically or numerically for real or complex values:: - sage: airy_ai(0) + sage: airy_ai(0) # needs sage.symbolic 1/3*3^(1/3)/gamma(2/3) - sage: airy_ai(0.0) + sage: airy_ai(0.0) # needs mpmath 0.355028053887817 - sage: airy_ai(I) + sage: airy_ai(I) # needs sage.symbolic airy_ai(I) - sage: airy_ai(1.0*I) + sage: airy_ai(1.0*I) # needs sage.symbolic 0.331493305432141 - 0.317449858968444*I The functions can be evaluated numerically either using mpmath. which can compute the values to arbitrary precision, and scipy:: - sage: airy_ai(2).n(prec=100) + sage: airy_ai(2).n(prec=100) # needs sage.symbolic 0.034924130423274379135322080792 - sage: airy_ai(2).n(algorithm='mpmath', prec=100) + sage: airy_ai(2).n(algorithm='mpmath', prec=100) # needs sage.symbolic 0.034924130423274379135322080792 - sage: airy_ai(2).n(algorithm='scipy') # rel tol 1e-10 + sage: airy_ai(2).n(algorithm='scipy') # rel tol 1e-10 # needs scipy sage.symbolic 0.03492413042327323 And the derivatives can be evaluated:: - sage: airy_ai(1, 0) + sage: airy_ai(1, 0) # needs sage.symbolic -1/3*3^(2/3)/gamma(1/3) - sage: airy_ai(1, 0.0) + sage: airy_ai(1, 0.0) # needs mpmath -0.258819403792807 Plots:: - sage: plot(airy_ai(x), (x, -10, 5)) + plot(airy_ai_prime(x), + sage: plot(airy_ai(x), (x, -10, 5)) + plot(airy_ai_prime(x), # needs sage.plot sage.symbolic ....: (x, -10, 5), color='red') Graphics object consisting of 2 graphics primitives @@ -515,6 +520,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.functions.airy import airy_bi_general sage: x, n = var('x n') sage: airy_bi_general(-2, x) @@ -534,10 +540,10 @@ def _derivative_(self, alpha, x, diff_param=None): EXAMPLES:: sage: from sage.functions.airy import airy_bi_general - sage: x, n = var('x n') - sage: derivative(airy_bi_general(n, x), x) + sage: x, n = var('x n') # needs sage.symbolic + sage: derivative(airy_bi_general(n, x), x) # needs sage.symbolic airy_bi(n + 1, x) - sage: derivative(airy_bi_general(n, x), n) + sage: derivative(airy_bi_general(n, x), n) # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: cannot differentiate airy_bi @@ -553,10 +559,10 @@ def _eval_(self, alpha, x): EXAMPLES:: sage: from sage.functions.airy import airy_bi_general - sage: x, n = var('x n') - sage: airy_bi_general(-2, 1.0) + sage: x, n = var('x n') # needs sage.symbolic + sage: airy_bi_general(-2, 1.0) # needs mpmath 0.388621540699059 - sage: airy_bi_general(n, 1.0) + sage: airy_bi_general(n, 1.0) # needs sage.symbolic airy_bi(n, 1.00000000000000) """ if not isinstance(x, Expression) and \ @@ -573,14 +579,14 @@ def _evalf_(self, alpha, x, **kwargs): EXAMPLES:: sage: from sage.functions.airy import airy_bi_general - sage: airy_bi_general(-2, 1.0) + sage: airy_bi_general(-2, 1.0) # needs mpmath 0.388621540699059 """ parent = kwargs.get('parent') import mpmath from sage.libs.mpmath import utils as mpmath_utils - return mpmath_utils.call(mpmath.airybi, x, derivative=alpha, + return _mpmath_utils_call(_mpmath_airybi, x, derivative=alpha, parent=parent) @@ -592,9 +598,9 @@ def __init__(self): EXAMPLES:: sage: from sage.functions.airy import airy_bi_simple - sage: f = airy_bi_simple(x); f + sage: f = airy_bi_simple(x); f # needs sage.symbolic airy_bi(x) - sage: f._sympy_() + sage: f._sympy_() # needs sympy sage.symbolic airybi(x) """ BuiltinFunction.__init__(self, 'airy_bi', @@ -610,7 +616,7 @@ def _derivative_(self, x, diff_param=None): EXAMPLES:: sage: from sage.functions.airy import airy_bi_simple - sage: derivative(airy_bi_simple(x), x) + sage: derivative(airy_bi_simple(x), x) # needs sage.symbolic airy_bi_prime(x) """ return airy_bi_prime(x) @@ -620,15 +626,15 @@ def _eval_(self, x): EXAMPLES:: sage: from sage.functions.airy import airy_bi_simple - sage: airy_bi_simple(0) + sage: airy_bi_simple(0) # needs sage.symbolic 1/3*3^(5/6)/gamma(2/3) - sage: airy_bi_simple(0.0) + sage: airy_bi_simple(0.0) # needs mpmath 0.614926627446001 - sage: airy_bi_simple(0).n() == airy_bi(0.0) + sage: airy_bi_simple(0).n() == airy_bi(0.0) # needs mpmath sage.symbolic True - sage: airy_bi_simple(I) + sage: airy_bi_simple(I) # needs sage.symbolic airy_bi(I) - sage: airy_bi_simple(1.0 * I) + sage: airy_bi_simple(1.0 * I) # needs sage.symbolic 0.648858208330395 + 0.344958634768048*I """ from .gamma import gamma @@ -641,27 +647,28 @@ def _evalf_(self, x, **kwargs): EXAMPLES:: sage: from sage.functions.airy import airy_bi_simple - sage: airy_bi_simple(0.0) + sage: airy_bi_simple(0.0) # needs mpmath 0.614926627446001 - sage: airy_bi_simple(1.0 * I) + sage: airy_bi_simple(1.0 * I) # needs sage.symbolic 0.648858208330395 + 0.344958634768048*I We can use several methods for numerical evaluation:: - sage: airy_bi_simple(3).n(algorithm='mpmath') + sage: # needs sage.symbolic + sage: airy_bi_simple(3).n(algorithm='mpmath') # needs mpmath 14.0373289637302 - sage: airy_bi_simple(3).n(algorithm='mpmath', prec=100) + sage: airy_bi_simple(3).n(algorithm='mpmath', prec=100) # needs mpmath 14.037328963730232031740267314 - sage: airy_bi_simple(3).n(algorithm='scipy') # rel tol 1e-10 + sage: airy_bi_simple(3).n(algorithm='scipy') # rel tol 1e-10 # needs scipy 14.037328963730136 - sage: airy_bi_simple(I).n(algorithm='scipy') # rel tol 1e-10 + sage: airy_bi_simple(I).n(algorithm='scipy') # rel tol 1e-10 # needs scipy 0.648858208330395 + 0.34495863476804844*I TESTS:: - sage: parent(airy_bi_simple(3).n(algorithm='scipy')) + sage: parent(airy_bi_simple(3).n(algorithm='scipy')) # needs scipy sage.rings.real_mpfr sage.symbolic Real Field with 53 bits of precision - sage: airy_bi_simple(3).n(algorithm='scipy', prec=200) + sage: airy_bi_simple(3).n(algorithm='scipy', prec=200) # needs scipy sage.symbolic Traceback (most recent call last): ... NotImplementedError: airy_bi not implemented for precision > 53 @@ -687,7 +694,7 @@ def _evalf_(self, x, **kwargs): elif algorithm == 'mpmath': import mpmath from sage.libs.mpmath import utils as mpmath_utils - return mpmath_utils.call(mpmath.airybi, x, parent=parent) + return _mpmath_utils_call(_mpmath_airybi, x, parent=parent) else: raise ValueError("unknown algorithm '%s'" % algorithm) @@ -700,12 +707,13 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: x, n = var('x n') sage: airy_bi_prime(x) airy_bi_prime(x) sage: airy_bi_prime(0) 3^(1/6)/gamma(1/3) - sage: airy_bi_prime(x)._sympy_() + sage: airy_bi_prime(x)._sympy_() # needs sympy airybiprime(x) """ BuiltinFunction.__init__(self, 'airy_bi_prime', @@ -719,7 +727,7 @@ def _derivative_(self, x, diff_param=None): """ EXAMPLES:: - sage: derivative(airy_bi_prime(x), x) + sage: derivative(airy_bi_prime(x), x) # needs sage.symbolic x*airy_bi(x) """ return x * airy_bi_simple(x) @@ -728,9 +736,9 @@ def _eval_(self, x): """ EXAMPLES:: - sage: airy_bi_prime(0) + sage: airy_bi_prime(0) # needs sage.symbolic 3^(1/6)/gamma(1/3) - sage: airy_bi_prime(0.0) + sage: airy_bi_prime(0.0) # needs mpmath 0.448288357353826 """ from .gamma import gamma @@ -742,25 +750,26 @@ def _evalf_(self, x, **kwargs): """ EXAMPLES:: - sage: airy_bi_prime(0.0) + sage: airy_bi_prime(0.0) # needs mpmath 0.448288357353826 We can use several methods for numerical evaluation:: + sage: # needs sage.symbolic sage: airy_bi_prime(4).n(algorithm='mpmath') 161.926683504613 sage: airy_bi_prime(4).n(algorithm='mpmath', prec=100) 161.92668350461340184309492429 - sage: airy_bi_prime(4).n(algorithm='scipy') # rel tol 1e-10 + sage: airy_bi_prime(4).n(algorithm='scipy') # rel tol 1e-10 # needs scipy 161.92668350461398 sage: airy_bi_prime(I).n(algorithm='scipy') # rel tol 1e-10 0.135026646710819 - 0.1288373867812549*I TESTS:: - sage: parent(airy_bi_prime(3).n(algorithm='scipy')) + sage: parent(airy_bi_prime(3).n(algorithm='scipy')) # needs scipy sage.rings.real_mpfr sage.symbolic Real Field with 53 bits of precision - sage: airy_bi_prime(3).n(algorithm='scipy', prec=200) + sage: airy_bi_prime(3).n(algorithm='scipy', prec=200) # needs scipy sage.symbolic Traceback (most recent call last): ... NotImplementedError: airy_bi_prime not implemented @@ -785,9 +794,7 @@ def _evalf_(self, x, **kwargs): return CC(y) return parent(y) elif algorithm == 'mpmath': - import mpmath - from sage.libs.mpmath import utils as mpmath_utils - return mpmath_utils.call(mpmath.airybi, x, derivative=1, + return _mpmath_utils_call(_mpmath_airybi, x, derivative=1, parent=parent) else: raise ValueError("unknown algorithm '%s'" % algorithm) @@ -845,12 +852,13 @@ def airy_bi(alpha, x=None, hold_derivative=True, **kwds): EXAMPLES:: - sage: n, x = var('n x') - sage: airy_bi(x) + sage: n, x = var('n x') # needs sage.symbolic + sage: airy_bi(x) # needs sage.symbolic airy_bi(x) It can return derivatives or integrals:: + sage: # needs sage.symbolic sage: airy_bi(2, x) airy_bi(2, x) sage: airy_bi(1, x, hold_derivative=False) @@ -865,35 +873,35 @@ def airy_bi(alpha, x=None, hold_derivative=True, **kwds): It can be evaluated symbolically or numerically for real or complex values:: - sage: airy_bi(0) + sage: airy_bi(0) # needs sage.symbolic 1/3*3^(5/6)/gamma(2/3) - sage: airy_bi(0.0) + sage: airy_bi(0.0) # needs mpmath 0.614926627446001 - sage: airy_bi(I) + sage: airy_bi(I) # needs sage.symbolic airy_bi(I) - sage: airy_bi(1.0*I) + sage: airy_bi(1.0*I) # needs sage.symbolic 0.648858208330395 + 0.344958634768048*I The functions can be evaluated numerically using mpmath, which can compute the values to arbitrary precision, and scipy:: - sage: airy_bi(2).n(prec=100) + sage: airy_bi(2).n(prec=100) # needs sage.symbolic 3.2980949999782147102806044252 - sage: airy_bi(2).n(algorithm='mpmath', prec=100) + sage: airy_bi(2).n(algorithm='mpmath', prec=100) # needs sage.symbolic 3.2980949999782147102806044252 - sage: airy_bi(2).n(algorithm='scipy') # rel tol 1e-10 + sage: airy_bi(2).n(algorithm='scipy') # rel tol 1e-10 # needs scipy sage.symbolic 3.2980949999782134 And the derivatives can be evaluated:: - sage: airy_bi(1, 0) + sage: airy_bi(1, 0) # needs sage.symbolic 3^(1/6)/gamma(1/3) - sage: airy_bi(1, 0.0) + sage: airy_bi(1, 0.0) # needs mpmath 0.448288357353826 Plots:: - sage: plot(airy_bi(x), (x, -10, 5)) + plot(airy_bi_prime(x), + sage: plot(airy_bi(x), (x, -10, 5)) + plot(airy_bi_prime(x), # needs sage.plot sage.symbolic ....: (x, -10, 5), color='red') Graphics object consisting of 2 graphics primitives diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index 95405c3d72f..24ee74b561c 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -122,33 +122,34 @@ Evaluate the Bessel J function symbolically and numerically:: + sage: # needs sage.symbolic sage: bessel_J(0, x) bessel_J(0, x) sage: bessel_J(0, 0) 1 sage: bessel_J(0, x).diff(x) -1/2*bessel_J(1, x) + 1/2*bessel_J(-1, x) - - sage: N(bessel_J(0, 0), digits = 20) + sage: N(bessel_J(0, 0), digits=20) 1.0000000000000000000 - sage: find_root(bessel_J(0,x), 0, 5) + sage: find_root(bessel_J(0,x), 0, 5) # needs scipy 2.404825557695773 Plot the Bessel J function:: - sage: f(x) = Bessel(0)(x); f + sage: f(x) = Bessel(0)(x); f # needs sage.symbolic x |--> bessel_J(0, x) - sage: plot(f, (x, 1, 10)) + sage: plot(f, (x, 1, 10)) # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive Visualize the Bessel Y function on the complex plane (set plot_points to a higher value to get more detail):: - sage: complex_plot(bessel_Y(0, x), (-5, 5), (-5, 5), plot_points=20) + sage: complex_plot(bessel_Y(0, x), (-5, 5), (-5, 5), plot_points=20) # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive Evaluate a combination of Bessel functions:: + sage: # needs sage.symbolic sage: f(x) = bessel_J(1, x) - bessel_Y(0, x) sage: f(pi) bessel_J(1, pi) - bessel_Y(0, pi) @@ -160,6 +161,7 @@ Symbolically solve a second order differential equation with initial conditions `y(1) = a` and `y'(1) = b` in terms of Bessel functions:: + sage: # needs sage.symbolic sage: y = function('y')(x) sage: a, b = var('a, b') sage: diffeq = x^2*diff(y,x,x) + x*diff(y,x) + x^2*y == 0 @@ -212,18 +214,30 @@ from sage.misc.functional import sqrt from sage.functions.log import exp +from sage.functions.gamma import gamma from sage.functions.hyperbolic import sinh, cosh from sage.functions.trig import sin, cos -from sage.libs.mpmath import utils as mpmath_utils -from sage.misc.latex import latex +from sage.misc.lazy_import import lazy_import +from sage.rings.infinity import infinity, unsigned_infinity from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.structure.element import get_coercion_model -from sage.symbolic.constants import pi -from sage.symbolic.ring import SR +from sage.structure.element import Expression, get_coercion_model from sage.symbolic.function import BuiltinFunction -from sage.symbolic.expression import Expression + +lazy_import('sage.misc.latex', 'latex') + +lazy_import('sage.symbolic.constants', 'pi') +lazy_import('sage.symbolic.ring', 'SR') + +lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') +lazy_import('mpmath', + ['besseli', 'besselj', 'besselk', + 'bessely', 'hankel1', 'hankel2', + 'struveh', 'struvel'], + as_=['_mpmath_besseli', '_mpmath_besselj', '_mpmath_besselk', + '_mpmath_bessely', '_mpmath_hankel1', '_mpmath_hankel2', + '_mpmath_struveh', '_mpmath_struvel']) class Function_Bessel_J(BuiltinFunction): @@ -258,11 +272,12 @@ class Function_Bessel_J(BuiltinFunction): EXAMPLES:: - sage: bessel_J(1.0, 1.0) + sage: bessel_J(1.0, 1.0) # needs mpmath 0.440050585744933 + + sage: # needs sage.symbolic sage: bessel_J(2, I).n(digits=30) -0.135747669767038281182852569995 - sage: bessel_J(1, x) bessel_J(1, x) sage: n = var('n') @@ -271,37 +286,34 @@ class Function_Bessel_J(BuiltinFunction): Examples of symbolic manipulation:: + sage: # needs sage.symbolic sage: a = bessel_J(pi, bessel_J(1, I)); a bessel_J(pi, bessel_J(1, I)) sage: N(a, digits=20) 0.00059023706363796717363 - 0.0026098820470081958110*I - sage: f = bessel_J(2, x) sage: f.diff(x) -1/2*bessel_J(3, x) + 1/2*bessel_J(1, x) Comparison to a well-known integral representation of `J_1(1)`:: - sage: A = numerical_integral(1/pi*cos(x - sin(x)), 0, pi) - sage: A[0] # abs tol 1e-14 + sage: A = numerical_integral(1/pi*cos(x - sin(x)), 0, pi) # needs sage.symbolic + sage: A[0] # abs tol 1e-14 # needs sage.symbolic 0.44005058574493355 - sage: bessel_J(1.0, 1.0) - A[0] < 1e-15 + sage: bessel_J(1.0, 1.0) - A[0] < 1e-15 # needs sage.symbolic True Integration is supported directly and through Maxima:: - sage: f = bessel_J(2, x) - sage: f.integrate(x) + sage: f = bessel_J(2, x) # needs sage.symbolic + sage: f.integrate(x) # needs sage.symbolic 1/24*x^3*hypergeometric((3/2,), (5/2, 3), -1/4*x^2) - sage: m = maxima(bessel_J(2, x)) - sage: m.integrate(x) - (hypergeometric([3/2],[5/2,3],-_SAGE_VAR_x^2/4)*_SAGE_VAR_x^3)/24 Visualization (set plot_points to a higher value to get more detail):: - sage: plot(bessel_J(1,x), (x,0,5), color='blue') + sage: plot(bessel_J(1,x), (x,0,5), color='blue') # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive - sage: complex_plot(bessel_J(1, x), (-5, 5), (-5, 5), plot_points=20) + sage: complex_plot(bessel_J(1, x), (-5, 5), (-5, 5), plot_points=20) # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive ALGORITHM: @@ -311,7 +323,7 @@ class Function_Bessel_J(BuiltinFunction): Check whether the return value is real whenever the argument is real (:trac:`10251`):: - sage: bessel_J(5, 1.5) in RR + sage: bessel_J(5, 1.5) in RR # needs mpmath True REFERENCES: @@ -330,7 +342,7 @@ def __init__(self): sage: sage.functions.bessel.Function_Bessel_J() bessel_J - sage: bessel_J(x, x)._sympy_() + sage: bessel_J(x, x)._sympy_() # needs sympy sage.symbolic besselj(x, x) """ BuiltinFunction.__init__(self, 'bessel_J', nargs=2, @@ -345,6 +357,7 @@ def _eval_(self, n, x): """ EXAMPLES:: + sage: # needs sage.symbolic sage: n = var('n') sage: bessel_J(0, 0) 1 @@ -361,7 +374,6 @@ def _eval_(self, n, x): sage: bessel_J(n, 0) bessel_J(n, 0) """ - from sage.rings.infinity import unsigned_infinity if not isinstance(x, Expression) and x == 0: if n == 0: return ZZ.one() @@ -378,15 +390,16 @@ def _evalf_(self, n, x, parent=None, algorithm=None): """ EXAMPLES:: - sage: bessel_J(0.0, 1.0) + sage: bessel_J(0.0, 1.0) # needs mpmath 0.765197686557967 - sage: bessel_J(0, 1).n(digits=20) + sage: bessel_J(0, 1).n(digits=20) # needs sage.symbolic 0.76519768655796655145 - sage: bessel_J(0.5, 1.5) + sage: bessel_J(0.5, 1.5) # needs mpmath 0.649838074753747 Check for correct rounding (:trac:`17122`):: + sage: # needs sage.rings.real_mpfr sage: R = RealField(113) sage: a = R("8.935761195587725798762818805462843676e-01") sage: aa = RealField(200)(a) @@ -405,8 +418,7 @@ def _evalf_(self, n, x, parent=None, algorithm=None): pass n, x = get_coercion_model().canonical_coercion(n, x) - import mpmath - return mpmath_utils.call(mpmath.besselj, n, x, parent=parent) + return _mpmath_utils_call(_mpmath_besselj, n, x, parent=parent) def _derivative_(self, n, x, diff_param): """ @@ -414,6 +426,7 @@ def _derivative_(self, n, x, diff_param): EXAMPLES:: + sage: # needs sage.symbolic sage: f(z) = bessel_J(10, z) sage: derivative(f, z) z |--> -1/2*bessel_J(11, z) + 1/2*bessel_J(9, z) @@ -435,7 +448,7 @@ def _print_latex_(self, n, z): EXAMPLES:: - sage: latex(bessel_J(1, x)) + sage: latex(bessel_J(1, x)) # needs sage.symbolic J_{1}(x) """ return r"J_{%s}(%s)" % (latex(n), latex(z)) @@ -469,10 +482,12 @@ class Function_Bessel_Y(BuiltinFunction): EXAMPLES:: - sage: bessel_Y(1, x) + sage: bessel_Y(1, x) # needs sage.symbolic bessel_Y(1, x) - sage: bessel_Y(1.0, 1.0) + sage: bessel_Y(1.0, 1.0) # needs mpmath -0.781212821300289 + + sage: # needs sage.symbolic sage: n = var('n') sage: bessel_Y(n, x) bessel_Y(n, x) @@ -485,29 +500,30 @@ class Function_Bessel_Y(BuiltinFunction): Examples of symbolic manipulation:: + sage: # needs sage.symbolic sage: a = bessel_Y(pi, bessel_Y(1, I)); a bessel_Y(pi, bessel_Y(1, I)) sage: N(a, digits=20) 4.2059146571791095708 + 21.307914215321993526*I - sage: f = bessel_Y(2, x) sage: f.diff(x) -1/2*bessel_Y(3, x) + 1/2*bessel_Y(1, x) High precision and complex valued inputs (see :trac:`4230`):: - sage: bessel_Y(0, 1).n(128) + sage: bessel_Y(0, 1).n(128) # needs sage.symbolic 0.088256964215676957982926766023515162828 - sage: bessel_Y(0, RealField(200)(1)) + sage: bessel_Y(0, RealField(200)(1)) # needs sage.rings.real_mpfr 0.088256964215676957982926766023515162827817523090675546711044 - sage: bessel_Y(0, ComplexField(200)(0.5+I)) - 0.077763160184438051408593468823822434235010300228009867784073 + 1.0142336049916069152644677682828326441579314239591288411739*I + sage: bessel_Y(0, ComplexField(200)(0.5+I)) # needs sage.symbolic + 0.077763160184438051408593468823822434235010300228009867784073 + + 1.0142336049916069152644677682828326441579314239591288411739*I Visualization (set plot_points to a higher value to get more detail):: - sage: plot(bessel_Y(1,x), (x,0,5), color='blue') + sage: plot(bessel_Y(1, x), (x, 0, 5), color='blue') # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive - sage: complex_plot(bessel_Y(1, x), (-5, 5), (-5, 5), plot_points=20) + sage: complex_plot(bessel_Y(1, x), (-5, 5), (-5, 5), plot_points=20) # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive ALGORITHM: @@ -519,11 +535,12 @@ class Function_Bessel_Y(BuiltinFunction): Check whether the return value is real whenever the argument is real (:trac:`10251`):: - sage: bessel_Y(5, 1.5) in RR + sage: bessel_Y(5, 1.5) in RR # needs mpmath True Coercion works correctly (see :trac:`17130`):: + sage: # needs sage.rings.real_mpfr sage: r = bessel_Y(RealField(200)(1), 1.0); r -0.781212821300289 sage: parent(r) @@ -547,9 +564,9 @@ def __init__(self): EXAMPLES:: - sage: sage.functions.bessel.Function_Bessel_Y()(0, x) + sage: sage.functions.bessel.Function_Bessel_Y()(0, x) # needs sage.symbolic bessel_Y(0, x) - sage: bessel_Y(x, x)._sympy_() + sage: bessel_Y(x, x)._sympy_() # needs sympy sage.symbolic bessely(x, x) """ BuiltinFunction.__init__(self, 'bessel_Y', nargs=2, @@ -564,6 +581,7 @@ def _eval_(self, n, x): """ EXAMPLES:: + sage: # needs sage.symbolic sage: bessel_Y(1, 0) Infinity sage: bessel_Y(I,0) @@ -575,10 +593,9 @@ def _eval_(self, n, x): TESTS:: - sage: bessel_Y(0, 0) + sage: bessel_Y(0, 0) # needs sage.symbolic -Infinity """ - from sage.rings.infinity import infinity, unsigned_infinity if not isinstance(x, Expression) and x == 0: if n == 0: return -infinity @@ -593,15 +610,16 @@ def _evalf_(self, n, x, parent=None, algorithm=None): """ EXAMPLES:: - sage: bessel_Y(0.5, 1.5) + sage: bessel_Y(0.5, 1.5) # needs mpmath -0.0460831658930974 - sage: bessel_Y(1.0+2*I, 3.0+4*I) + sage: bessel_Y(1.0+2*I, 3.0+4*I) # needs mpmath sage.symbolic 0.699410324467538 + 0.228917940896421*I - sage: bessel_Y(0, 1).n(256) + sage: bessel_Y(0, 1).n(256) # needs mpmath sage.symbolic 0.08825696421567695798292676602351516282781752309067554671104384761199978932351 Check for correct rounding (:trac:`17122`):: + sage: # needs mpmath sage.rings.real_mpfr sage: R = RealField(113) sage: a = R("8.935761195587725798762818805462843676e-01") sage: aa = RealField(200)(a) @@ -620,8 +638,7 @@ def _evalf_(self, n, x, parent=None, algorithm=None): pass n, x = get_coercion_model().canonical_coercion(n, x) - import mpmath - return mpmath_utils.call(mpmath.bessely, n, x, parent=parent) + return _mpmath_utils_call(_mpmath_bessely, n, x, parent=parent) def _derivative_(self, n, x, diff_param): """ @@ -629,6 +646,7 @@ def _derivative_(self, n, x, diff_param): EXAMPLES:: + sage: # needs sage.symbolic sage: f(x) = bessel_Y(10, x) sage: derivative(f, x) x |--> -1/2*bessel_Y(11, x) + 1/2*bessel_Y(9, x) @@ -649,7 +667,7 @@ def _print_latex_(self, n, z): EXAMPLES:: - sage: latex(bessel_Y(1, x)) + sage: latex(bessel_Y(1, x)) # needs sage.symbolic Y_{1}(x) """ return r"Y_{%s}(%s)" % (latex(n), latex(z)) @@ -670,10 +688,12 @@ class Function_Bessel_I(BuiltinFunction): EXAMPLES:: + sage: bessel_I(1.0, 1.0) # needs mpmath + 0.565159103992485 + + sage: # needs sage.symbolic sage: bessel_I(1, x) bessel_I(1, x) - sage: bessel_I(1.0, 1.0) - 0.565159103992485 sage: n = var('n') sage: bessel_I(n, x) bessel_I(n, x) @@ -682,16 +702,17 @@ class Function_Bessel_I(BuiltinFunction): Examples of symbolic manipulation:: + sage: # needs sage.symbolic sage: a = bessel_I(pi, bessel_I(1, I)) sage: N(a, digits=20) 0.00026073272117205890524 - 0.0011528954889080572268*I - sage: f = bessel_I(2, x) sage: f.diff(x) 1/2*bessel_I(3, x) + 1/2*bessel_I(1, x) Special identities that bessel_I satisfies:: + sage: # needs sage.symbolic sage: bessel_I(1/2, x) sqrt(2)*sqrt(1/(pi*x))*sinh(x) sage: eq = bessel_I(1/2, x) == bessel_I(0.5, x) @@ -705,25 +726,26 @@ class Function_Bessel_I(BuiltinFunction): Examples of asymptotic behavior:: - sage: limit(bessel_I(0, x), x=oo) + sage: limit(bessel_I(0, x), x=oo) # needs sage.symbolic +Infinity - sage: limit(bessel_I(0, x), x=0) + sage: limit(bessel_I(0, x), x=0) # needs sage.symbolic 1 High precision and complex valued inputs:: - sage: bessel_I(0, 1).n(128) + sage: bessel_I(0, 1).n(128) # needs sage.symbolic 1.2660658777520083355982446252147175376 - sage: bessel_I(0, RealField(200)(1)) + sage: bessel_I(0, RealField(200)(1)) # needs sage.rings.real_mpfr 1.2660658777520083355982446252147175376076703113549622068081 - sage: bessel_I(0, ComplexField(200)(0.5+I)) - 0.80644357583493619472428518415019222845373366024179916785502 + 0.22686958987911161141397453401487525043310874687430711021434*I + sage: bessel_I(0, ComplexField(200)(0.5+I)) # needs sage.symbolic + 0.80644357583493619472428518415019222845373366024179916785502 + + 0.22686958987911161141397453401487525043310874687430711021434*I Visualization (set plot_points to a higher value to get more detail):: - sage: plot(bessel_I(1,x), (x,0,5), color='blue') + sage: plot(bessel_I(1, x), (x, 0, 5), color='blue') # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive - sage: complex_plot(bessel_I(1, x), (-5, 5), (-5, 5), plot_points=20) + sage: complex_plot(bessel_I(1, x), (-5, 5), (-5, 5), plot_points=20) # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive ALGORITHM: @@ -733,12 +755,12 @@ class Function_Bessel_I(BuiltinFunction): TESTS:: - sage: N(bessel_I(1,1),500) + sage: N(bessel_I(1,1),500) # needs sage.symbolic 0.565159103992485027207696027609863307328899621621092009480294489479255640964371134092664997766814410064677886055526302676857637684917179812041131208121 Check whether the return value is real whenever the argument is real (:trac:`10251`):: - sage: bessel_I(5, 1.5) in RR + sage: bessel_I(5, 1.5) in RR # needs mpmath True REFERENCES: @@ -755,9 +777,9 @@ def __init__(self): EXAMPLES:: - sage: bessel_I(1,x) + sage: bessel_I(1, x) # needs sage.symbolic bessel_I(1, x) - sage: bessel_I(x, x)._sympy_() + sage: bessel_I(x, x)._sympy_() # needs sympy sage.symbolic besseli(x, x) """ BuiltinFunction.__init__(self, 'bessel_I', nargs=2, @@ -771,6 +793,7 @@ def _eval_(self, n, x): """ EXAMPLES:: + sage: # needs sage.symbolic sage: n,y = var('n,y') sage: bessel_I(y, x) bessel_I(y, x) @@ -787,7 +810,6 @@ def _eval_(self, n, x): sage: bessel_I(n, 0) bessel_I(n, 0) """ - from sage.rings.infinity import unsigned_infinity if not isinstance(x, Expression) and x == 0: if n == 0: return ZZ.one() @@ -804,13 +826,12 @@ def _evalf_(self, n, x, parent=None, algorithm=None): """ EXAMPLES:: - sage: bessel_I(0.0, 1.0) + sage: bessel_I(0.0, 1.0) # needs mpmath 1.26606587775201 - sage: bessel_I(1,3).n(digits=20) + sage: bessel_I(1,3).n(digits=20) # needs sage.symbolic 3.9533702174026093965 """ - import mpmath - return mpmath_utils.call(mpmath.besseli, n, x, parent=parent) + return _mpmath_utils_call(_mpmath_besseli, n, x, parent=parent) def _derivative_(self, n, x, diff_param): """ @@ -819,6 +840,7 @@ def _derivative_(self, n, x, diff_param): EXAMPLES:: + sage: # needs sage.symbolic sage: f(z) = bessel_I(10, x) sage: derivative(f, x) z |--> 1/2*bessel_I(11, x) + 1/2*bessel_I(9, x) @@ -839,7 +861,7 @@ def _print_latex_(self, n, z): EXAMPLES:: - sage: latex(bessel_I(1, x)) + sage: latex(bessel_I(1, x)) # needs sage.symbolic I_{1}(x) """ return r"I_{%s}(%s)" % (latex(n), latex(z)) @@ -860,10 +882,12 @@ class Function_Bessel_K(BuiltinFunction): EXAMPLES:: + sage: bessel_K(1.0, 1.0) # needs mpmath + 0.601907230197235 + + sage: # needs sage.symbolic sage: bessel_K(1, x) bessel_K(1, x) - sage: bessel_K(1.0, 1.0) - 0.601907230197235 sage: n = var('n') sage: bessel_K(n, x) bessel_K(n, x) @@ -872,15 +896,14 @@ class Function_Bessel_K(BuiltinFunction): Examples of symbolic manipulation:: + sage: # needs sage.symbolic sage: a = bessel_K(pi, bessel_K(1, I)); a bessel_K(pi, bessel_K(1, I)) sage: N(a, digits=20) 3.8507583115005220156 + 0.068528298579883425456*I - sage: f = bessel_K(2, x) sage: f.diff(x) -1/2*bessel_K(3, x) - 1/2*bessel_K(1, x) - sage: bessel_K(1/2, x) sqrt(1/2)*sqrt(pi)*e^(-x)/sqrt(x) sage: bessel_K(1/2, -1) @@ -890,27 +913,28 @@ class Function_Bessel_K(BuiltinFunction): Examples of asymptotic behavior:: - sage: bessel_K(0, 0.0) + sage: bessel_K(0, 0.0) # needs mpmath +infinity - sage: limit(bessel_K(0, x), x=0) + sage: limit(bessel_K(0, x), x=0) # needs sage.symbolic +Infinity - sage: limit(bessel_K(0, x), x=oo) + sage: limit(bessel_K(0, x), x=oo) # needs sage.symbolic 0 High precision and complex valued inputs:: - sage: bessel_K(0, 1).n(128) + sage: bessel_K(0, 1).n(128) # needs sage.symbolic 0.42102443824070833333562737921260903614 - sage: bessel_K(0, RealField(200)(1)) + sage: bessel_K(0, RealField(200)(1)) # needs sage.rings.real_mpfr 0.42102443824070833333562737921260903613621974822666047229897 - sage: bessel_K(0, ComplexField(200)(0.5+I)) - 0.058365979093103864080375311643360048144715516692187818271179 - 0.67645499731334483535184142196073004335768129348518210260256*I + sage: bessel_K(0, ComplexField(200)(0.5+I)) # needs sage.rings.real_mpfr sage.symbolic + 0.058365979093103864080375311643360048144715516692187818271179 + - 0.67645499731334483535184142196073004335768129348518210260256*I Visualization (set plot_points to a higher value to get more detail):: - sage: plot(bessel_K(1,x), (x,0,5), color='blue') + sage: plot(bessel_K(1,x), (x,0,5), color='blue') # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive - sage: complex_plot(bessel_K(1, x), (-5, 5), (-5, 5), plot_points=20) + sage: complex_plot(bessel_K(1, x), (-5, 5), (-5, 5), plot_points=20) # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive ALGORITHM: @@ -924,13 +948,13 @@ class Function_Bessel_K(BuiltinFunction): The Bessel K function can be evaluated numerically at complex orders:: - sage: bessel_K(10 * I, 10).n() + sage: bessel_K(10 * I, 10).n() # needs sage.symbolic 9.82415743819925e-8 For a fixed imaginary order and increasing, real, second component the value of Bessel K is exponentially decaying:: - sage: for x in [10, 20, 50, 100, 200]: print(bessel_K(5*I, x).n()) + sage: for x in [10, 20, 50, 100, 200]: print(bessel_K(5*I, x).n()) # needs sage.symbolic 5.27812176514912e-6 3.11005908421801e-10 2.66182488515423e-23 - 8.59622057747552e-58*I @@ -939,7 +963,7 @@ class Function_Bessel_K(BuiltinFunction): Check whether the return value is real whenever the argument is real (:trac:`10251`):: - sage: bessel_K(5, 1.5) in RR + sage: bessel_K(5, 1.5) in RR # needs mpmath True REFERENCES: @@ -958,7 +982,7 @@ def __init__(self): sage: sage.functions.bessel.Function_Bessel_K() bessel_K - sage: bessel_K(x, x)._sympy_() + sage: bessel_K(x, x)._sympy_() # needs sympy sage.symbolic besselk(x, x) """ BuiltinFunction.__init__(self, 'bessel_K', nargs=2, @@ -972,6 +996,7 @@ def _eval_(self, n, x): """ EXAMPLES:: + sage: # needs sage.symbolic sage: n = var('n') sage: bessel_K(1, 0) Infinity @@ -982,10 +1007,9 @@ def _eval_(self, n, x): TESTS:: - sage: bessel_K(0, 0) + sage: bessel_K(0, 0) # needs sage.symbolic +Infinity """ - from sage.rings.infinity import infinity, unsigned_infinity if not isinstance(x, Expression) and x == 0: if n == 0: return infinity @@ -998,15 +1022,14 @@ def _evalf_(self, n, x, parent=None, algorithm=None): """ EXAMPLES:: - sage: bessel_K(0.0, 1.0) + sage: bessel_K(0.0, 1.0) # needs mpmath 0.421024438240708 - sage: bessel_K(-1, 1).n(128) + sage: bessel_K(-1, 1).n(128) # needs sage.symbolic 0.60190723019723457473754000153561733926 - sage: bessel_K(0, RealField(128)(1)) + sage: bessel_K(0, RealField(128)(1)) # needs sage.rings.real_mpfr 0.42102443824070833333562737921260903614 """ - import mpmath - return mpmath_utils.call(mpmath.besselk, n, x, parent=parent) + return _mpmath_utils_call(_mpmath_besselk, n, x, parent=parent) def _derivative_(self, n, x, diff_param): """ @@ -1014,6 +1037,7 @@ def _derivative_(self, n, x, diff_param): EXAMPLES:: + sage: # needs sage.symbolic sage: f(x) = bessel_K(10, x) sage: derivative(f, x) x |--> -1/2*bessel_K(11, x) - 1/2*bessel_K(9, x) @@ -1034,7 +1058,7 @@ def _print_latex_(self, n, z): EXAMPLES:: - sage: latex(bessel_K(1, x)) + sage: latex(bessel_K(1, x)) # needs sage.symbolic K_{1}(x) """ return r"K_{%s}(%s)" % (latex(n), latex(z)) @@ -1052,15 +1076,15 @@ def Bessel(*args, **kwds): A function factory that produces symbolic I, J, K, and Y Bessel functions. There are several ways to call this function: - - ``Bessel(order, type)`` - - ``Bessel(order)`` -- type defaults to 'J' - - ``Bessel(order, typ=T)`` - - ``Bessel(typ=T)`` -- order is unspecified, this is a 2-parameter - function - - ``Bessel()`` -- order is unspecified, type is 'J' + - ``Bessel(order, type)`` + - ``Bessel(order)`` -- type defaults to ``'J'`` + - ``Bessel(order, typ=T)`` + - ``Bessel(typ=T)`` -- order is unspecified, this is a 2-parameter + function + - ``Bessel()`` -- order is unspecified, type is ``'J'`` - where ``order`` can be any integer and T must be one of the strings 'I', - 'J', 'K', or 'Y'. + where ``order`` can be any integer and ``T`` must be one of the strings ``'I'``, + ``'J'``, ``'K'``, or ``'Y'``. See the EXAMPLES below. @@ -1070,64 +1094,70 @@ def Bessel(*args, **kwds): sage: Bessel() bessel_J + sage: Bessel(typ='K') + bessel_K + + sage: # needs sage.symbolic sage: Bessel(1)(x) bessel_J(1, x) sage: Bessel(1, 'Y')(x) bessel_Y(1, x) sage: Bessel(-2, 'Y')(x) bessel_Y(-2, x) - sage: Bessel(typ='K') - bessel_K sage: Bessel(0, typ='I')(x) bessel_I(0, x) Evaluation:: sage: f = Bessel(1) - sage: f(3.0) + sage: f(3.0) # needs mpmath 0.339058958525936 + + sage: # needs sage.symbolic sage: f(3) bessel_J(1, 3) sage: f(3).n(digits=50) 0.33905895852593645892551459720647889697308041819801 - sage: g = Bessel(typ='J') sage: g(1,3) bessel_J(1, 3) sage: g(2, 3+I).n() 0.634160370148554 + 0.0253384000032695*I - sage: abs(numerical_integral(1/pi*cos(3*sin(x)), 0.0, pi)[0] - Bessel(0, 'J')(3.0)) < 1e-15 + sage: abs(numerical_integral(1/pi*cos(3*sin(x)), 0.0, pi)[0] + ....: - Bessel(0, 'J')(3.0)) < 1e-15 True Symbolic calculus:: - sage: f(x) = Bessel(0, 'J')(x) - sage: derivative(f, x) + sage: f(x) = Bessel(0, 'J')(x) # needs sage.symbolic + sage: derivative(f, x) # needs sage.symbolic x |--> -1/2*bessel_J(1, x) + 1/2*bessel_J(-1, x) - sage: derivative(f, x, x) + sage: derivative(f, x, x) # needs sage.symbolic x |--> 1/4*bessel_J(2, x) - 1/2*bessel_J(0, x) + 1/4*bessel_J(-2, x) Verify that `J_0` satisfies Bessel's differential equation numerically using the ``test_relation()`` method:: - sage: y = bessel_J(0, x) - sage: diffeq = x^2*derivative(y,x,x) + x*derivative(y,x) + x^2*y == 0 - sage: diffeq.test_relation(proof=False) + sage: y = bessel_J(0, x) # needs sage.symbolic + sage: diffeq = x^2*derivative(y,x,x) + x*derivative(y,x) + x^2*y == 0 # needs sage.symbolic + sage: diffeq.test_relation(proof=False) # needs sage.symbolic True Conversion to other systems:: + sage: # needs sage.symbolic sage: x,y = var('x,y') - sage: f = maxima(Bessel(typ='K')(x,y)) - sage: f.derivative('_SAGE_VAR_x') - (%pi*csc(%pi*_SAGE_VAR_x) *('diff(bessel_i(-_SAGE_VAR_x,_SAGE_VAR_y),_SAGE_VAR_x,1) -'diff(bessel_i(_SAGE_VAR_x,_SAGE_VAR_y),_SAGE_VAR_x,1))) /2 -%pi*bessel_k(_SAGE_VAR_x,_SAGE_VAR_y)*cot(%pi*_SAGE_VAR_x) - sage: f.derivative('_SAGE_VAR_y') - -(bessel_k(_SAGE_VAR_x+1,_SAGE_VAR_y)+bessel_k(_SAGE_VAR_x-1, _SAGE_VAR_y))/2 + sage: f = Bessel(typ='K')(x,y) + sage: expected = f.derivative(y) + sage: actual = maxima(f).derivative('_SAGE_VAR_y').sage() + sage: bool(actual == expected) + True Compute the particular solution to Bessel's Differential Equation that satisfies `y(1) = 1` and `y'(1) = 1`, then verify the initial conditions and plot it:: + sage: # needs sage.symbolic sage: y = function('y')(x) sage: diffeq = x^2*diff(y,x,x) + x*diff(y,x) + x^2*y == 0 sage: f = desolve(diffeq, y, [1, 1, 1]); f @@ -1135,37 +1165,39 @@ def Bessel(*args, **kwds): 1)*bessel_Y(1, 1) - bessel_J(1, 1)*bessel_Y(0, 1)) - (bessel_J(1, 1) + bessel_J(0, 1))*bessel_Y(0, x)/(bessel_J(0, 1)*bessel_Y(1, 1) - bessel_J(1, 1)*bessel_Y(0, 1)) - sage: f.subs(x=1).n() # numerical verification + sage: f.subs(x=1).n() # numerical verification 1.00000000000000 sage: fp = f.diff(x) sage: fp.subs(x=1).n() 1.00000000000000 - sage: f.subs(x=1).simplify_full() # symbolic verification + sage: f.subs(x=1).simplify_full() # symbolic verification # needs sage.symbolic 1 - sage: fp = f.diff(x) - sage: fp.subs(x=1).simplify_full() + sage: fp = f.diff(x) # needs sage.symbolic + sage: fp.subs(x=1).simplify_full() # needs sage.symbolic 1 - sage: plot(f, (x,0,5)) + sage: plot(f, (x,0,5)) # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive Plotting:: - sage: f(x) = Bessel(0)(x); f + sage: f(x) = Bessel(0)(x); f # needs sage.symbolic x |--> bessel_J(0, x) - sage: plot(f, (x, 1, 10)) + sage: plot(f, (x, 1, 10)) # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive - sage: plot([ Bessel(i, 'J') for i in range(5) ], 2, 10) + sage: plot([Bessel(i, 'J') for i in range(5)], 2, 10) # needs sage.plot Graphics object consisting of 5 graphics primitives - sage: G = Graphics() - sage: G += sum([ plot(Bessel(i), 0, 4*pi, rgbcolor=hue(sin(pi*i/10))) for i in range(5) ]) - sage: show(G) + sage: G = Graphics() # needs sage.plot + sage: G += sum(plot(Bessel(i), 0, 4*pi, rgbcolor=hue(sin(pi*i/10))) # needs sage.plot sage.symbolic + ....: for i in range(5)) + sage: show(G) # needs sage.plot A recreation of Abramowitz and Stegun Figure 9.1:: + sage: # needs sage.plot sage.symbolic sage: G = plot(Bessel(0, 'J'), 0, 15, color='black') sage: G += plot(Bessel(0, 'Y'), 0, 15, color='black') sage: G += plot(Bessel(1, 'J'), 0, 15, color='black', linestyle='dotted') @@ -1223,11 +1255,11 @@ class Function_Struve_H(BuiltinFunction): EXAMPLES:: - sage: struve_H(-1/2,x) + sage: struve_H(-1/2, x) # needs sage.symbolic sqrt(2)*sqrt(1/(pi*x))*sin(x) - sage: struve_H(2,x) + sage: struve_H(2, x) # needs sage.symbolic struve_H(2, x) - sage: struve_H(1/2,pi).n() + sage: struve_H(1/2, pi).n() # needs sage.symbolic 0.900316316157106 REFERENCES: @@ -1242,10 +1274,11 @@ def __init__(self): r""" EXAMPLES:: + sage: # needs sage.symbolic sage: n = var('n') sage: maxima("struve_h(n,x);").sage() struve_H(n, x) - sage: struve_H(7/5,1)._maxima_() + sage: struve_H(7/5, 1)._maxima_() struve_h(7/5,1) sage: loads(dumps(struve_H(n,x))) struve_H(n, x) @@ -1261,19 +1294,20 @@ def _eval_(self, a, z): """ EXAMPLES:: - sage: struve_H(0,0) + sage: # needs sage.symbolic + sage: struve_H(0, 0) 0 - sage: struve_H(pi,0) + sage: struve_H(pi, 0) 0 - sage: struve_H(-1/2,x) + sage: struve_H(-1/2, x) sqrt(2)*sqrt(1/(pi*x))*sin(x) - sage: struve_H(1/2,-1) + sage: struve_H(1/2, -1) -sqrt(2)*sqrt(-1/pi)*(cos(1) - 1) - sage: struve_H(1/2,pi) + sage: struve_H(1/2, pi) 2*sqrt(2)/pi - sage: struve_H(2,x) + sage: struve_H(2, x) struve_H(2, x) - sage: struve_H(-3/2,x) + sage: struve_H(-3/2, x) -bessel_J(3/2, x) """ if z.is_zero() \ @@ -1281,10 +1315,8 @@ def _eval_(self, a, z): and a.real() >= -1: return ZZ.zero() if a == QQ((-1, 2)): - from sage.functions.trig import sin return sqrt(2 / (pi * z)) * sin(z) if a == QQ((1, 2)): - from sage.functions.trig import cos return sqrt(2 / (pi * z)) * (1 - cos(z)) if a < 0 and not SR(a).is_integer() and SR(2 * a).is_integer(): n = (a * (-2) - 1) / 2 @@ -1294,25 +1326,24 @@ def _evalf_(self, a, z, parent=None, algorithm=None): """ EXAMPLES:: - sage: struve_H(1/2,pi).n() + sage: struve_H(1/2, pi).n() # needs sage.symbolic 0.900316316157106 - sage: struve_H(1/2,pi).n(200) + sage: struve_H(1/2, pi).n(200) # needs sage.symbolic 0.9003163161571060695551991910... """ - import mpmath - return mpmath_utils.call(mpmath.struveh, a, z, parent=parent) + return _mpmath_utils_call(_mpmath_struveh, a, z, parent=parent) def _derivative_(self, a, z, diff_param=None): """ EXAMPLES:: - sage: diff(struve_H(3/2,x),x) - -1/2*sqrt(2)*sqrt(1/(pi*x))*(cos(x) - 1) + 1/16*sqrt(2)*x^(3/2)/sqrt(pi) - 1/2*struve_H(5/2, x) + sage: diff(struve_H(3/2,x), x) # needs sage.symbolic + -1/2*sqrt(2)*sqrt(1/(pi*x))*(cos(x) - 1) + 1/16*sqrt(2)*x^(3/2)/sqrt(pi) + - 1/2*struve_H(5/2, x) """ if diff_param == 0: raise ValueError("cannot differentiate struve_H in the first parameter") - from .gamma import gamma from .other import sqrt return (z**a / (sqrt(pi) * 2**a * gamma(a + Integer(3) / Integer(2))) - struve_H(a + 1, z) + struve_H(a - 1, z)) / 2 @@ -1320,7 +1351,7 @@ def _print_latex_(self, a, z): """ EXAMPLES:: - sage: latex(struve_H(2,x)) + sage: latex(struve_H(2,x)) # needs sage.symbolic H_{{2}}({x}) """ return r"H_{{%s}}({%s})" % (a, z) @@ -1339,11 +1370,11 @@ class Function_Struve_L(BuiltinFunction): EXAMPLES:: - sage: struve_L(2,x) + sage: struve_L(2, x) # needs sage.symbolic struve_L(2, x) - sage: struve_L(1/2,pi).n() + sage: struve_L(1/2, pi).n() # needs sage.symbolic 4.76805417696286 - sage: diff(struve_L(1,x),x) + sage: diff(struve_L(1,x), x) # needs sage.symbolic 1/3*x/pi - 1/2*struve_L(2, x) + 1/2*struve_L(0, x) REFERENCES: @@ -1358,12 +1389,13 @@ def __init__(self): r""" EXAMPLES:: + sage: # needs sage.symbolic sage: n = var('n') sage: maxima("struve_l(n,x);").sage() struve_L(n, x) - sage: struve_L(7/5,1)._maxima_() + sage: struve_L(7/5, 1)._maxima_() struve_l(7/5,1) - sage: loads(dumps(struve_L(n,x))) + sage: loads(dumps(struve_L(n, x))) struve_L(n, x) """ BuiltinFunction.__init__(self, 'struve_L', nargs=2, @@ -1377,19 +1409,20 @@ def _eval_(self, a, z): """ EXAMPLES:: - sage: struve_L(-2,0) + sage: # needs sage.symbolic + sage: struve_L(-2, 0) struve_L(-2, 0) - sage: struve_L(-1,0) + sage: struve_L(-1, 0) 0 - sage: struve_L(pi,0) + sage: struve_L(pi, 0) 0 - sage: struve_L(-1/2,x) + sage: struve_L(-1/2, x) sqrt(2)*sqrt(1/(pi*x))*sinh(x) - sage: struve_L(1/2,1) + sage: struve_L(1/2, 1) sqrt(2)*(cosh(1) - 1)/sqrt(pi) - sage: struve_L(2,x) + sage: struve_L(2, x) struve_L(2, x) - sage: struve_L(-3/2,x) + sage: struve_L(-3/2, x) -bessel_I(3/2, x) """ if z.is_zero() \ @@ -1397,10 +1430,8 @@ def _eval_(self, a, z): and a.real() >= -1: return ZZ.zero() if a == -Integer(1) / 2: - from sage.functions.hyperbolic import sinh return sqrt(2 / (pi * z)) * sinh(z) if a == Integer(1) / 2: - from sage.functions.hyperbolic import cosh return sqrt(2 / (pi * z)) * (cosh(z) - 1) if a < 0 and not SR(a).is_integer() and SR(2 * a).is_integer(): n = (a * (-2) - 1) / 2 @@ -1410,25 +1441,23 @@ def _evalf_(self, a, z, parent=None, algorithm=None): """ EXAMPLES:: - sage: struve_L(1/2,pi).n() + sage: struve_L(1/2, pi).n() # needs sage.symbolic 4.76805417696286 - sage: struve_L(1/2,pi).n(200) + sage: struve_L(1/2, pi).n(200) # needs sage.symbolic 4.768054176962864289162484345... """ - import mpmath - return mpmath_utils.call(mpmath.struvel, a, z, parent=parent) + return _mpmath_utils_call(_mpmath_struvel, a, z, parent=parent) def _derivative_(self, a, z, diff_param=None): """ EXAMPLES:: - sage: diff(struve_L(1,x),x) + sage: diff(struve_L(1,x), x) # needs sage.symbolic 1/3*x/pi - 1/2*struve_L(2, x) + 1/2*struve_L(0, x) """ if diff_param == 0: raise ValueError("cannot differentiate struve_L in the first parameter") - from .gamma import gamma from .other import sqrt return (z**a / (sqrt(pi) * 2**a * gamma(a + Integer(3) / Integer(2))) - struve_L(a + 1, z) + struve_L(a - 1, z)) / 2 @@ -1436,7 +1465,7 @@ def _print_latex_(self, a, z): """ EXAMPLES:: - sage: latex(struve_L(2,x)) + sage: latex(struve_L(2,x)) # needs sage.symbolic L_{{2}}({x}) """ return r"L_{{%s}}({%s})" % (a, z) @@ -1457,15 +1486,15 @@ class Function_Hankel1(BuiltinFunction): EXAMPLES:: - sage: hankel1(3, x) + sage: hankel1(3, x) # needs sage.symbolic hankel1(3, x) - sage: hankel1(3, 4.) + sage: hankel1(3, 4.) # needs mpmath 0.430171473875622 - 0.182022115953485*I - sage: latex(hankel1(3, x)) + sage: latex(hankel1(3, x)) # needs sage.symbolic H_{3}^{(1)}\left(x\right) - sage: hankel1(3., x).series(x == 2, 10).subs(x=3).n() # abs tol 1e-12 + sage: hankel1(3., x).series(x == 2, 10).subs(x=3).n() # abs tol 1e-12 # needs sage.symbolic 0.309062682819597 - 0.512591541605233*I - sage: hankel1(3, 3.) + sage: hankel1(3, 3.) # needs mpmath 0.309062722255252 - 0.538541616105032*I REFERENCES: @@ -1476,7 +1505,7 @@ def __init__(self): r""" TESTS:: - sage: hankel1(3, x)._sympy_() + sage: hankel1(3, x)._sympy_() # needs sympy sage.symbolic hankel1(3, x) """ BuiltinFunction.__init__(self, 'hankel1', nargs=2, @@ -1490,13 +1519,12 @@ def _evalf_(self, nu, z, parent, algorithm=None): r""" TESTS:: - sage: hankel1(3, 3).n(100) + sage: hankel1(3, 3).n(100) # needs sage.symbolic 0.30906272225525164361826019495 - 0.53854161610503161800470390534*I - sage: hankel1(I, I).n() + sage: hankel1(I, I).n() # needs sage.symbolic -0.886357449263715*I """ - from mpmath import hankel1 - return mpmath_utils.call(hankel1, nu, z, parent=parent) + return _mpmath_utils_call(_mpmath_hankel1, nu, z, parent=parent) def _latex_(self): r""" @@ -1511,7 +1539,7 @@ def _print_latex_(self, nu, z): r""" TESTS:: - sage: latex(hankel1(3, x)) + sage: latex(hankel1(3, x)) # needs sage.symbolic H_{3}^{(1)}\left(x\right) """ return r"H_{{{}}}^{{(1)}}\left({}\right)".format(latex(nu), latex(z)) @@ -1520,8 +1548,8 @@ def _derivative_(self, nu, z, diff_param): r""" TESTS:: - sage: y = var('y') - sage: hankel1(x, y).diff(y) + sage: y = var('y') # needs sage.symbolic + sage: hankel1(x, y).diff(y) # needs sage.symbolic x*hankel1(x, y)/y - hankel1(x + 1, y) """ if diff_param == 1: @@ -1545,15 +1573,15 @@ class Function_Hankel2(BuiltinFunction): EXAMPLES:: - sage: hankel2(3, x) + sage: hankel2(3, x) # needs sage.symbolic hankel2(3, x) - sage: hankel2(3, 4.) + sage: hankel2(3, 4.) # needs mpmath 0.430171473875622 + 0.182022115953485*I - sage: latex(hankel2(3, x)) + sage: latex(hankel2(3, x)) # needs sage.symbolic H_{3}^{(2)}\left(x\right) - sage: hankel2(3., x).series(x == 2, 10).subs(x=3).n() # abs tol 1e-12 + sage: hankel2(3., x).series(x == 2, 10).subs(x=3).n() # abs tol 1e-12 # needs sage.symbolic 0.309062682819597 + 0.512591541605234*I - sage: hankel2(3, 3.) + sage: hankel2(3, 3.) # needs mpmath 0.309062722255252 + 0.538541616105032*I REFERENCES: @@ -1564,7 +1592,7 @@ def __init__(self): r""" TESTS:: - sage: hankel2(3, x)._sympy_() + sage: hankel2(3, x)._sympy_() # needs sympy sage.symbolic hankel2(3, x) """ BuiltinFunction.__init__(self, 'hankel2', nargs=2, @@ -1578,13 +1606,12 @@ def _evalf_(self, nu, z, parent, algorithm=None): r""" TESTS:: - sage: hankel2(3, 3).n(100) + sage: hankel2(3, 3).n(100) # needs sage.symbolic 0.30906272225525164361826019495 + 0.53854161610503161800470390534*I - sage: hankel2(I, I).n() + sage: hankel2(I, I).n() # needs sage.symbolic 0.790274862674015 + 0.444006335520019*I """ - from mpmath import hankel2 - return mpmath_utils.call(hankel2, nu, z, parent=parent) + return _mpmath_utils_call(_mpmath_hankel2, nu, z, parent=parent) def _latex_(self): r""" @@ -1599,7 +1626,7 @@ def _print_latex_(self, nu, z): r""" TESTS:: - sage: latex(hankel2(3, x)) + sage: latex(hankel2(3, x)) # needs sage.symbolic H_{3}^{(2)}\left(x\right) """ return r"H_{{{}}}^{{(2)}}\left({}\right)".format(latex(nu), latex(z)) @@ -1608,8 +1635,8 @@ def _derivative_(self, nu, z, diff_param): r""" TESTS:: - sage: y = var('y') - sage: hankel2(x, y).diff(y) + sage: y = var('y') # needs sage.symbolic + sage: hankel2(x, y).diff(y) # needs sage.symbolic -1/2*hankel2(x + 1, y) + 1/2*hankel2(x - 1, y) """ if diff_param == 1: @@ -1633,16 +1660,18 @@ class SphericalBesselJ(BuiltinFunction): EXAMPLES:: + sage: spherical_bessel_J(3, 3.) # needs mpmath + 0.152051662030533 + sage: spherical_bessel_J(2.,3.) # rel tol 1e-10 # needs mpmath + 0.2986374970757335 + + sage: # needs sage.symbolic sage: spherical_bessel_J(3, x) spherical_bessel_J(3, x) sage: spherical_bessel_J(3 + 0.2 * I, 3) 0.150770999183897 - 0.0260662466510632*I sage: spherical_bessel_J(3, x).series(x == 2, 10).subs(x=3).n() 0.152051648665037 - sage: spherical_bessel_J(3, 3.) - 0.152051662030533 - sage: spherical_bessel_J(2.,3.) # rel tol 1e-10 - 0.2986374970757335 sage: spherical_bessel_J(4, x).simplify() -((45/x^2 - 105/x^4 - 1)*sin(x) + 5*(21/x^2 - 2)*cos(x)/x)/x sage: integrate(spherical_bessel_J(1,x)^2,(x,0,oo)) @@ -1662,7 +1691,7 @@ def __init__(self): r""" TESTS:: - sage: spherical_bessel_J(3, x)._sympy_() + sage: spherical_bessel_J(3, x)._sympy_() # needs sympy sage.symbolic jn(3, x) """ conversions = dict(mathematica='SphericalBesselJ', @@ -1675,12 +1704,12 @@ def _evalf_(self, n, z, parent, algorithm=None): r""" TESTS:: - sage: spherical_bessel_J(3, 3).n(100) + sage: spherical_bessel_J(3, 3).n(100) # needs sage.symbolic 0.15205166203053329097480571600 - sage: spherical_bessel_J(I, I).n() + sage: spherical_bessel_J(I, I).n() # needs sage.symbolic 0.215520585196889 - 0.282308805801851*I """ - return mpmath_utils.call(spherical_bessel_f, 'besselj', n, z, + return _mpmath_utils_call(spherical_bessel_f, 'besselj', n, z, parent=parent) def _latex_(self): @@ -1696,7 +1725,7 @@ def _print_latex_(self, n, z): r""" TESTS:: - sage: latex(spherical_bessel_J(4, x)) + sage: latex(spherical_bessel_J(4, x)) # needs sage.symbolic j_{4}\left(x\right) """ return r"j_{{{}}}\left({}\right)".format(latex(n), latex(z)) @@ -1705,8 +1734,8 @@ def _derivative_(self, n, z, diff_param): r""" TESTS:: - sage: y = var('y') - sage: spherical_bessel_J(x, y).diff(y) + sage: y = var('y') # needs sage.symbolic + sage: spherical_bessel_J(x, y).diff(y) # needs sage.symbolic -(x + 1)*spherical_bessel_J(x, y)/y + spherical_bessel_J(x - 1, y) """ if SR(n).is_numeric() and not SR(n).is_integer(): @@ -1733,6 +1762,7 @@ class SphericalBesselY(BuiltinFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: spherical_bessel_Y(3, x) spherical_bessel_Y(3, x) sage: spherical_bessel_Y(3 + 0.2 * I, 3) @@ -1760,7 +1790,7 @@ def __init__(self): r""" TESTS:: - sage: spherical_bessel_Y(3, x)._sympy_() + sage: spherical_bessel_Y(3, x)._sympy_() # needs sympy sage.symbolic yn(3, x) """ conversions = dict(mathematica='SphericalBesselY', @@ -1773,12 +1803,12 @@ def _evalf_(self, n, z, parent, algorithm=None): r""" TESTS:: - sage: spherical_bessel_Y(3, 3).n(100) + sage: spherical_bessel_Y(3, 3).n(100) # needs sage.symbolic -0.50802305570981460285684870920 - sage: spherical_bessel_Y(I, I).n() + sage: spherical_bessel_Y(I, I).n() # needs sage.symbolic -0.174225389805399 + 1.36247234140312*I """ - return mpmath_utils.call(spherical_bessel_f, 'bessely', n, z, + return _mpmath_utils_call(spherical_bessel_f, 'bessely', n, z, parent=parent) def _latex_(self): @@ -1794,7 +1824,7 @@ def _print_latex_(self, n, z): r""" TESTS:: - sage: latex(spherical_bessel_Y(4, x)) + sage: latex(spherical_bessel_Y(4, x)) # needs sage.symbolic y_{4}\left(x\right) """ return r"y_{{{}}}\left({}\right)".format(latex(n), latex(z)) @@ -1803,8 +1833,8 @@ def _derivative_(self, n, z, diff_param): r""" TESTS:: - sage: y = var('y') - sage: spherical_bessel_Y(x, y).diff(y) + sage: y = var('y') # needs sage.symbolic + sage: spherical_bessel_Y(x, y).diff(y) # needs sage.symbolic -1/2*spherical_bessel_Y(x, y)/y -... 1/2*spherical_bessel_Y(x + 1, y) + 1/2*spherical_bessel_Y(x - 1, y) """ @@ -1833,6 +1863,7 @@ class SphericalHankel1(BuiltinFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: spherical_hankel1(3, x) spherical_hankel1(3, x) sage: spherical_hankel1(3 + 0.2 * I, 3) @@ -1870,12 +1901,12 @@ def _evalf_(self, n, z, parent, algorithm=None): r""" TESTS:: - sage: spherical_hankel1(3, 3).n(100) + sage: spherical_hankel1(3, 3).n(100) # needs sage.symbolic 0.15205166203053329097480571600 - 0.50802305570981460285684870920*I - sage: spherical_hankel1(I, I).n() + sage: spherical_hankel1(I, I).n() # needs sage.symbolic -1.14695175620623 - 0.456534195607250*I """ - return mpmath_utils.call(spherical_bessel_f, 'hankel1', n, z, + return _mpmath_utils_call(spherical_bessel_f, 'hankel1', n, z, parent=parent) def _latex_(self): @@ -1891,7 +1922,7 @@ def _print_latex_(self, n, z): r""" TESTS:: - sage: latex(spherical_hankel1(4, x)) + sage: latex(spherical_hankel1(4, x)) # needs sage.symbolic h_{4}^{(1)}\left(x\right) """ return r"h_{{{}}}^{{(1)}}\left({}\right)".format(latex(n), latex(z)) @@ -1900,8 +1931,8 @@ def _derivative_(self, n, z, diff_param): r""" TESTS:: - sage: y = var('y') - sage: spherical_hankel1(x, y).diff(y) + sage: y = var('y') # needs sage.symbolic + sage: spherical_hankel1(x, y).diff(y) # needs sage.symbolic -1/2*spherical_hankel1(x, y)/y -... 1/2*spherical_hankel1(x + 1, y) + 1/2*spherical_hankel1(x - 1, y) """ @@ -1930,6 +1961,7 @@ class SphericalHankel2(BuiltinFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: spherical_hankel2(3, x) spherical_hankel2(3, x) sage: spherical_hankel2(3 + 0.2 * I, 3) @@ -1970,13 +2002,13 @@ def _evalf_(self, n, z, parent, algorithm=None): r""" TESTS:: - sage: spherical_hankel2(3, 3).n(100) + sage: spherical_hankel2(3, 3).n(100) # needs sage.symbolic 0.15205166203053329097480571600 + 0.50802305570981460285684870920*I - sage: spherical_hankel2(I, I).n() + sage: spherical_hankel2(I, I).n() # needs sage.symbolic 1.57799292660001 - 0.108083415996452*I """ - return mpmath_utils.call(spherical_bessel_f, 'hankel2', n, z, - parent=parent) + return _mpmath_utils_call(spherical_bessel_f, 'hankel2', n, z, + parent=parent) def _latex_(self): r""" @@ -1991,7 +2023,7 @@ def _print_latex_(self, n, z): r""" TESTS:: - sage: latex(spherical_hankel2(4, x)) + sage: latex(spherical_hankel2(4, x)) # needs sage.symbolic h_{4}^{(2)}\left(x\right) """ return r"h_{{{}}}^{{(2)}}\left({}\right)".format(latex(n), latex(z)) @@ -2000,6 +2032,7 @@ def _derivative_(self, n, z, diff_param): r""" TESTS:: + sage: # needs sage.symbolic sage: y = var('y') sage: spherical_hankel2(x, y).diff(y) -1/2*spherical_hankel2(x, y)/y -... @@ -2036,9 +2069,9 @@ def spherical_bessel_f(F, n, z): EXAMPLES:: sage: from sage.functions.bessel import spherical_bessel_f - sage: spherical_bessel_f('besselj', 3, 4) + sage: spherical_bessel_f('besselj', 3, 4) # needs mpmath mpf('0.22924385795503024') - sage: spherical_bessel_f('hankel1', 3, 4) + sage: spherical_bessel_f('hankel1', 3, 4) # needs mpmath mpc(real='0.22924385795503024', imag='-0.21864196590306359') TESTS: @@ -2046,13 +2079,12 @@ def spherical_bessel_f(F, n, z): Check that :trac:`28474` is fixed:: sage: from sage.functions.bessel import spherical_bessel_f - sage: spherical_bessel_f('besselj', 3, -4) + sage: spherical_bessel_f('besselj', 3, -4) # needs mpmath mpc(real='-0.22924385795503024', imag='0.0') - sage: spherical_bessel_f('bessely', 3, -4) + sage: spherical_bessel_f('bessely', 3, -4) # needs mpmath mpc(real='-0.21864196590306359', imag='0.0') """ - from mpmath import mp - ctx = mp + from mpmath import mp as ctx prec = ctx.prec try: n = ctx.convert(n) diff --git a/src/sage/functions/error.py b/src/sage/functions/error.py index ca665622f20..1e4b74d5afe 100644 --- a/src/sage/functions/error.py +++ b/src/sage/functions/error.py @@ -40,16 +40,27 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.all import parent as s_parent -from sage.symbolic.function import BuiltinFunction -from sage.libs.mpmath import utils as mpmath_utils -from sage.symbolic.expression import Expression -from sage.functions.all import exp from sage.misc.functional import sqrt -from sage.symbolic.constants import pi -from sage.rings.rational import Rational +from sage.misc.lazy_import import lazy_import +from sage.misc.persist import register_unpickle_override from sage.rings.infinity import unsigned_infinity -from sage.symbolic.expression import I +from sage.rings.rational import Rational +from sage.structure.element import Expression, parent as s_parent +from sage.symbolic.function import BuiltinFunction + +lazy_import('sage.functions.log', ['exp']) +lazy_import('sage.functions.trig', ['sin', 'cos']) + +lazy_import('sage.symbolic.constants', ['I', 'pi']) + +lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') +lazy_import('sage.libs.mpmath.all', 'erf', as_='_mpmath_erf') +lazy_import('sage.libs.mpmath.all', 'erfc', as_='_mpmath_erfc') +lazy_import('sage.libs.mpmath.all', 'erfi', as_='_mpmath_erfi') +lazy_import('sage.libs.mpmath.all', 'erfinv', as_='_mpmath_erfinv') +lazy_import('sage.libs.mpmath.all', 'fresnelc', as_='_mpmath_fresnelc') +lazy_import('sage.libs.mpmath.all', 'fresnels', as_='_mpmath_fresnels') + class Function_erf(BuiltinFunction): r""" @@ -68,21 +79,21 @@ class Function_erf(BuiltinFunction): We can evaluate numerically:: - sage: erf(2) + sage: erf(2) # needs sage.symbolic erf(2) - sage: erf(2).n() + sage: erf(2).n() # needs sage.symbolic 0.995322265018953 - sage: erf(2).n(100) + sage: erf(2).n(100) # needs sage.symbolic 0.99532226501895273416206925637 - sage: erf(ComplexField(100)(2+3j)) + sage: erf(ComplexField(100)(2+3j)) # needs sage.rings.real_mpfr -20.829461427614568389103088452 + 8.6873182714701631444280787545*I Basic symbolic properties are handled by Sage and Maxima:: - sage: x = var("x") - sage: diff(erf(x),x) + sage: x = var("x") # needs sage.symbolic + sage: diff(erf(x),x) # needs sage.symbolic 2*e^(-x^2)/sqrt(pi) - sage: integrate(erf(x),x) + sage: integrate(erf(x),x) # needs sage.symbolic x*erf(x) + e^(-x^2)/sqrt(pi) ALGORITHM: @@ -99,78 +110,78 @@ class Function_erf(BuiltinFunction): Check limits:: - sage: limit(erf(x),x=0) + sage: limit(erf(x), x=0) # needs sage.symbolic 0 - sage: limit(erf(x),x=infinity) + sage: limit(erf(x), x=infinity) # needs sage.symbolic 1 Check that it's odd:: - sage: erf(1.0) + sage: erf(1.0) # needs mpmath 0.842700792949715 - sage: erf(-1.0) + sage: erf(-1.0) # needs mpmath -0.842700792949715 Check against other implementations and against the definition:: - sage: erf(3).n() + sage: erf(3).n() # needs sage.symbolic 0.999977909503001 - sage: maxima.erf(3).n() + sage: maxima.erf(3).n() # needs sage.symbolic 0.999977909503001 - sage: (1-pari(3).erfc()) + sage: 1 - pari(3).erfc() # needs sage.libs.pari 0.999977909503001 - sage: RR(3).erf() + sage: RR(3).erf() # needs sage.rings.real_mpfr 0.999977909503001 - sage: (integrate(exp(-x**2),(x,0,3))*2/sqrt(pi)).n() + sage: (integrate(exp(-x**2), (x,0,3))*2/sqrt(pi)).n() # needs sage.symbolic 0.999977909503001 :trac:`9044`:: - sage: N(erf(sqrt(2)),200) + sage: N(erf(sqrt(2)),200) # needs sage.symbolic 0.95449973610364158559943472566693312505644755259664313203267 :trac:`11626`:: - sage: n(erf(2),100) + sage: n(erf(2),100) # needs sage.symbolic 0.99532226501895273416206925637 - sage: erf(2).n(100) + sage: erf(2).n(100) # needs sage.symbolic 0.99532226501895273416206925637 Test (indirectly) :trac:`11885`:: sage: erf(float(0.5)) 0.5204998778130465 - sage: erf(complex(0.5)) + sage: erf(complex(0.5)) # needs sage.rings.complex_double (0.5204998778130465+0j) Ensure conversion from maxima elements works:: - sage: merf = maxima(erf(x)).sage().operator() - sage: merf.parent() == erf.parent() + sage: merf = maxima(erf(x)).sage().operator() # needs sage.symbolic + sage: merf.parent() == erf.parent() # needs sage.symbolic True Make sure we can dump and load it:: - sage: loads(dumps(erf(2))) + sage: loads(dumps(erf(2))) # needs sage.symbolic erf(2) Special-case 0 for immediate evaluation:: - sage: erf(0) + sage: erf(0) # needs mpmath 0 - sage: solve(erf(x)==0,x) + sage: solve(erf(x)==0, x) # needs sage.symbolic [x == 0] Make sure that we can hold:: - sage: erf(0,hold=True) + sage: erf(0, hold=True) # needs sage.symbolic erf(0) - sage: simplify(erf(0,hold=True)) + sage: simplify(erf(0, hold=True)) # needs sage.symbolic 0 Check that high-precision ComplexField inputs work:: - sage: CC(erf(ComplexField(1000)(2+3j))) + sage: CC(erf(ComplexField(1000)(2+3j))) # needs sage.rings.real_mpfr -20.8294614276146 + 8.68731827147016*I """ @@ -180,9 +191,9 @@ def __init__(self): EXAMPLES:: - sage: maxima(erf(2)) + sage: maxima(erf(2)) # needs sage.symbolic erf(2) - sage: erf(2)._sympy_() + sage: erf(2)._sympy_() # needs sympy sage.symbolic erf(2) """ BuiltinFunction.__init__(self, "erf", latex_name=r"\operatorname{erf}", @@ -197,6 +208,7 @@ def _eval_(self, x): Input is not an expression but is exact:: + sage: # needs sage.symbolic sage: erf(0) 0 sage: erf(1) @@ -210,17 +222,17 @@ def _eval_(self, x): Input is not an expression and is not exact:: - sage: erf(0.0) + sage: erf(0.0) # needs mpmath 0.000000000000000 Input is an expression but not a trivial zero:: - sage: erf(x) + sage: erf(x) # needs sage.symbolic erf(x) Input is an expression which is trivially zero:: - sage: erf(SR(0)) + sage: erf(SR(0)) # needs sage.symbolic 0 """ if isinstance(x, Expression): @@ -240,39 +252,38 @@ def _evalf_(self, x, parent=None, algorithm=None): """ EXAMPLES:: - sage: erf(2).n() + sage: erf(2).n() # needs sage.symbolic 0.995322265018953 - sage: erf(2).n(200) + sage: erf(2).n(200) # needs sage.symbolic 0.99532226501895273416206925636725292861089179704006007673835 - sage: erf(pi - 1/2*I).n(100) + sage: erf(pi - 1/2*I).n(100) # needs sage.symbolic 1.0000111669099367825726058952 + 1.6332655417638522934072124547e-6*I TESTS: Check that PARI/GP through the GP interface gives the same answer:: - sage: gp.set_real_precision(59) # random + sage: gp.set_real_precision(59) # random # needs sage.libs.pari 38 - sage: print(gp.eval("1 - erfc(1)")); print(erf(1).n(200)) + sage: print(gp.eval("1 - erfc(1)")); print(erf(1).n(200)) # needs sage.libs.pari 0.84270079294971486934122063508260925929606699796630290845994 0.84270079294971486934122063508260925929606699796630290845994 Check that for an imaginary input, the output is also imaginary, see :trac:`13193`:: - sage: erf(3.0*I) + sage: erf(3.0*I) # needs sage.symbolic 1629.99462260157*I - sage: erf(33.0*I) + sage: erf(33.0*I) # needs sage.symbolic 1.51286977510409e471*I Check that real ball evaluation is fixed :trac:`28061`:: - sage: RealBallField(128)(erf(5)) # abs tol 1e-38 + sage: RealBallField(128)(erf(5)) # abs tol 1e-38 # needs sage.symbolic [0.99999999999846254020557196514981165651 +/- 7.33e-39] """ R = parent or s_parent(x) - import mpmath - y = mpmath_utils.call(mpmath.erf, x, parent=R) + y = _mpmath_utils_call(_mpmath_erf, x, parent=R) return y def _derivative_(self, x, diff_param=None): @@ -281,22 +292,23 @@ def _derivative_(self, x, diff_param=None): EXAMPLES:: - sage: erf(x).diff(x) + sage: erf(x).diff(x) # needs sage.symbolic 2*e^(-x^2)/sqrt(pi) TESTS: Check if :trac:`8568` is fixed:: - sage: var('c,x') + sage: var('c,x') # needs sage.symbolic (c, x) - sage: derivative(erf(c*x),x) + sage: derivative(erf(c*x),x) # needs sage.symbolic 2*c*e^(-c^2*x^2)/sqrt(pi) - sage: erf(c*x).diff(x)._maxima_init_() + sage: erf(c*x).diff(x)._maxima_init_() # needs sage.symbolic '((%pi)^(-1/2))*(_SAGE_VAR_c)*(exp(((_SAGE_VAR_c)^(2))*((_SAGE_VAR_x)^(2))*(-1)))*(2)' """ return 2*exp(-x**2)/sqrt(pi) + erf = Function_erf() @@ -316,9 +328,9 @@ def __init__(self): EXAMPLES:: - sage: maxima(erfi(2)) + sage: maxima(erfi(2)) # needs sage.symbolic erfi(2) - sage: erfi(2)._sympy_() + sage: erfi(2)._sympy_() # needs sympy sage.symbolic erfi(2) """ BuiltinFunction.__init__(self, "erfi", @@ -331,6 +343,7 @@ def _eval_(self, x): """ EXAMPLES:: + sage: # needs sage.symbolic sage: erfi(0) 0 sage: erfi(SR(0)) @@ -352,16 +365,15 @@ def _evalf_(self, x, parent=None, algorithm=None): """ EXAMPLES:: - sage: erfi(2.) + sage: erfi(2.) # needs mpmath 18.5648024145756 - sage: erfi(2).n(100) + sage: erfi(2).n(100) # needs sage.symbolic 18.564802414575552598704291913 - sage: erfi(-2*I).n(100) + sage: erfi(-2*I).n(100) # needs sage.symbolic -0.99532226501895273416206925637*I """ R = parent or s_parent(x) - import mpmath - return mpmath_utils.call(mpmath.erfi, x, parent=R) + return _mpmath_utils_call(_mpmath_erfi, x, parent=R) def _derivative_(self, x, diff_param=None): """ @@ -369,14 +381,16 @@ def _derivative_(self, x, diff_param=None): EXAMPLES:: - sage: erfi(x).diff(x) + sage: erfi(x).diff(x) # needs sage.symbolic 2*e^(x^2)/sqrt(pi) """ return 2*exp(x**2)/sqrt(pi) + erfi = Function_erfi() + class Function_erfc(BuiltinFunction): r""" The complementary error function. @@ -389,23 +403,23 @@ class Function_erfc(BuiltinFunction): EXAMPLES:: - sage: erfc(6) + sage: erfc(6) # needs sage.symbolic erfc(6) - sage: erfc(6).n() + sage: erfc(6).n() # needs sage.symbolic 2.15197367124989e-17 - sage: erfc(RealField(100)(1/2)) + sage: erfc(RealField(100)(1/2)) # needs sage.rings.real_mpfr 0.47950012218695346231725334611 - sage: 1 - erfc(0.5) + sage: 1 - erfc(0.5) # needs mpmath 0.520499877813047 - sage: erf(0.5) + sage: erf(0.5) # needs mpmath 0.520499877813047 TESTS: Check that :trac:`25991` is fixed:: - sage: erfc(x)._fricas_() # optional - fricas + sage: erfc(x)._fricas_() # optional - fricas, needs sage.symbolic - erf(x) + 1 """ @@ -413,9 +427,9 @@ def __init__(self): r""" EXAMPLES:: - sage: maxima(erfc(2)) + sage: maxima(erfc(2)) # needs sage.symbolic erfc(2) - sage: erfc(2)._sympy_() + sage: erfc(2)._sympy_() # needs sympy sage.symbolic erfc(2) """ BuiltinFunction.__init__(self, "erfc", @@ -429,6 +443,7 @@ def _eval_(self, x): """ EXAMPLES:: + sage: # needs sage.symbolic sage: erfc(0) 1 sage: erfc(SR(0)) @@ -455,16 +470,15 @@ def _evalf_(self, x, parent=None, algorithm=None): """ EXAMPLES:: - sage: erfc(4).n() + sage: erfc(4).n() # needs sage.symbolic 1.54172579002800e-8 - sage: erfc(4).n(100) + sage: erfc(4).n(100) # needs sage.symbolic 1.5417257900280018852159673487e-8 - sage: erfc(4*I).n(100) + sage: erfc(4*I).n(100) # needs sage.symbolic 1.0000000000000000000000000000 - 1.2969597307176392315279409506e6*I """ R = parent or s_parent(x) - import mpmath - return mpmath_utils.call(mpmath.erfc, x, parent=R) + return _mpmath_utils_call(_mpmath_erfc, x, parent=R) def _derivative_(self, x, diff_param=None): """ @@ -472,11 +486,12 @@ def _derivative_(self, x, diff_param=None): EXAMPLES:: - sage: erfc(x).diff(x) + sage: erfc(x).diff(x) # needs sage.symbolic -2*e^(-x^2)/sqrt(pi) """ return -2*exp(-x**2)/sqrt(pi) + erfc = Function_erfc() @@ -496,15 +511,16 @@ def __init__(self): EXAMPLES:: - sage: erfinv(2)._sympy_() + sage: erfinv(2)._sympy_() # needs sympy sage.symbolic erfinv(2) - sage: maxima(erfinv(2)) + sage: maxima(erfinv(2)) # needs sage.symbolic inverse_erf(2) TESTS: Check that :trac:`11349` is fixed:: + sage: # needs sage.symbolic sage: _ = var('z,t') sage: PDF = exp(-x^2 /2)/sqrt(2*pi) sage: integralExpr = integrate(PDF,x,z,oo).subs(z==log(t)) @@ -523,11 +539,11 @@ def _eval_(self, x): """ EXAMPLES:: - sage: erfinv(0) + sage: erfinv(0) # needs mpmath 0 - sage: erfinv(SR(0)) + sage: erfinv(SR(0)) # needs sage.symbolic 0 - sage: erfinv(1) + sage: erfinv(1) # needs sage.symbolic Infinity """ if isinstance(x, Expression): @@ -544,14 +560,13 @@ def _evalf_(self, x, parent=None, algorithm=None): """ EXAMPLES:: - sage: erfinv(0.2) + sage: erfinv(0.2) # needs mpmath 0.179143454621292 - sage: erfinv(1/5).n(100) + sage: erfinv(1/5).n(100) # needs sage.symbolic 0.17914345462129167649274901663 """ R = parent or s_parent(x) - import mpmath - return mpmath_utils.call(mpmath.erfinv, x, parent=R) + return _mpmath_utils_call(_mpmath_erfinv, x, parent=R) def _derivative_(self, x, diff_param=None): """ @@ -559,16 +574,18 @@ def _derivative_(self, x, diff_param=None): EXAMPLES:: - sage: erfinv(x).diff(x) + sage: erfinv(x).diff(x) # needs sage.symbolic 1/2*sqrt(pi)*e^(erfinv(x)^2) """ return sqrt(pi)*exp(erfinv(x)**2)/2 + erfinv = Function_erfinv() -from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.functions.other', 'Function_erf', Function_erf) + ############################ # Fresnel integrals # ############################ @@ -592,6 +609,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: fresnel_sin(0) 0 sage: fresnel_sin(x).subs(x==0) @@ -599,7 +617,7 @@ def __init__(self): sage: x = var('x') sage: fresnel_sin(1).n(100) 0.43825914739035476607675669662 - sage: fresnel_sin(x)._sympy_() + sage: fresnel_sin(x)._sympy_() # needs sympy fresnels(x) """ BuiltinFunction.__init__(self, "fresnel_sin", nargs=1, @@ -614,15 +632,15 @@ def _eval_(self, x): r""" EXAMPLES:: - sage: fresnel_sin(pi) + sage: fresnel_sin(pi) # needs sage.symbolic fresnel_sin(pi) - sage: fresnel_sin(oo) + sage: fresnel_sin(oo) # needs mpmath 1/2 - sage: fresnel_sin(-oo) + sage: fresnel_sin(-oo) # needs mpmath -1/2 - sage: fresnel_sin(I*oo) + sage: fresnel_sin(I*oo) # needs sage.symbolic -1/2*I - sage: fresnel_sin(-I*oo) + sage: fresnel_sin(-I*oo) # needs sage.symbolic 1/2*I """ if isinstance(x, Expression): @@ -632,11 +650,11 @@ def _eval_(self, x): return x if x.is_infinity(): if x.is_positive_infinity(): - return Rational((1,2)) + return Rational((1, 2)) elif x.imag_part().is_positive_infinity(): - return -I*Rational((1,2)) + return -I*Rational((1, 2)) elif x.imag_part().is_negative_infinity(): - return I*Rational((1,2)) + return I*Rational((1, 2)) elif x < 0: return -fresnel_sin(-x) elif not x: @@ -646,30 +664,29 @@ def _evalf_(self, x, parent=None, algorithm=None): r""" EXAMPLES:: - sage: fresnel_sin(pi) + sage: fresnel_sin(pi) # needs sage.symbolic fresnel_sin(pi) - sage: fresnel_sin(pi).n(100) + sage: fresnel_sin(pi).n(100) # needs sage.symbolic 0.59824907809026766482843860921 - sage: fresnel_sin(1.0+2*I) + sage: fresnel_sin(1.0+2*I) # needs sage.symbolic 36.7254648839914 + 15.5877511044046*I """ - import mpmath - from sage.libs.mpmath import utils as mpmath_utils - return mpmath_utils.call(mpmath.fresnels, x, parent=parent) + return _mpmath_utils_call(_mpmath_fresnels, x, parent=parent) def _derivative_(self, x, diff_param=None): """ EXAMPLES:: - sage: x = var('x') - sage: fresnel_sin(x).diff(x) + sage: x = var('x') # needs sage.symbolic + sage: fresnel_sin(x).diff(x) # needs sage.symbolic sin(1/2*pi*x^2) """ - from sage.functions.trig import sin return sin(pi*x**2/2) + fresnel_sin = Function_Fresnel_sin() + class Function_Fresnel_cos(BuiltinFunction): def __init__(self): r""" @@ -690,6 +707,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: fresnel_cos(0) 0 sage: fresnel_cos(x).subs(x==0) @@ -697,7 +715,7 @@ def __init__(self): sage: x = var('x') sage: fresnel_cos(1).n(100) 0.77989340037682282947420641365 - sage: fresnel_cos(x)._sympy_() + sage: fresnel_cos(x)._sympy_() # needs sympy fresnelc(x) """ BuiltinFunction.__init__(self, "fresnel_cos", nargs=1, @@ -712,15 +730,15 @@ def _eval_(self, x): r""" EXAMPLES:: - sage: fresnel_cos(pi) + sage: fresnel_cos(pi) # needs sage.symbolic fresnel_cos(pi) - sage: fresnel_cos(oo) + sage: fresnel_cos(oo) # needs mpmath 1/2 - sage: fresnel_cos(-oo) + sage: fresnel_cos(-oo) # needs mpmath -1/2 - sage: fresnel_cos(I*oo) + sage: fresnel_cos(I*oo) # needs sage.symbolic 1/2*I - sage: fresnel_cos(-I*oo) + sage: fresnel_cos(-I*oo) # needs sage.symbolic -1/2*I """ if isinstance(x, Expression): @@ -730,11 +748,11 @@ def _eval_(self, x): return x if x.is_infinity(): if x.is_positive_infinity(): - return Rational((1,2)) + return Rational((1, 2)) elif x.imag_part().is_positive_infinity(): - return I*Rational((1,2)) + return I*Rational((1, 2)) elif x.imag_part().is_negative_infinity(): - return -I*Rational((1,2)) + return -I*Rational((1, 2)) elif x < 0: return -fresnel_cos(-x) elif not x: @@ -744,26 +762,24 @@ def _evalf_(self, x, parent=None, algorithm=None): r""" EXAMPLES:: - sage: fresnel_cos(pi) + sage: fresnel_cos(pi) # needs sage.symbolic fresnel_cos(pi) - sage: fresnel_cos(pi).n(100) + sage: fresnel_cos(pi).n(100) # needs sage.symbolic 0.52369854372622864215767570284 - sage: fresnel_cos(1.0+2*I) + sage: fresnel_cos(1.0+2*I) # needs sage.symbolic 16.0878713741255 - 36.2256879928817*I """ - import mpmath - from sage.libs.mpmath import utils as mpmath_utils - return mpmath_utils.call(mpmath.fresnelc, x, parent=parent) + return _mpmath_utils_call(_mpmath_fresnelc, x, parent=parent) def _derivative_(self, x, diff_param=None): """ EXAMPLES:: - sage: x = var('x') - sage: fresnel_cos(x).diff(x) + sage: x = var('x') # needs sage.symbolic + sage: fresnel_cos(x).diff(x) # needs sage.symbolic cos(1/2*pi*x^2) """ - from sage.functions.trig import cos return cos(pi*x**2/2) + fresnel_cos = Function_Fresnel_cos() diff --git a/src/sage/functions/exp_integral.py b/src/sage/functions/exp_integral.py index 1cf90029844..5fb024c877c 100644 --- a/src/sage/functions/exp_integral.py +++ b/src/sage/functions/exp_integral.py @@ -36,30 +36,38 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Benjamin Jones <benjaminfjones@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** +import math +from sage.misc.lazy_import import lazy_import +from sage.rings.infinity import Infinity +from sage.rings.integer_ring import ZZ +from sage.structure.element import Expression, parent from sage.symbolic.function import BuiltinFunction -from sage.symbolic.expression import Expression -from sage.structure.all import parent -from sage.misc.latex import latex -from sage.libs.mpmath import utils as mpmath_utils -mpmath_utils_call = mpmath_utils.call # eliminate some overhead in _evalf_ -from sage.rings.real_mpfr import RealField -from sage.rings.integer_ring import ZZ -from sage.functions.log import exp, log -from sage.functions.trig import sin, cos -from sage.functions.hyperbolic import sinh, cosh -import math +lazy_import('sage.functions.log', ['exp', 'log']) +lazy_import('sage.functions.trig', ['sin', 'cos']) +lazy_import('sage.functions.hyperbolic', ['sinh', 'cosh']) + +lazy_import('sage.misc.latex', 'latex') +lazy_import('sage.rings.real_mpfr', 'RealField') + +lazy_import('sage.symbolic.ring', 'SR') + +lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') +lazy_import('mpmath', + ['chi', 'ci', 'e1', 'ei', 'expint', 'ei', 'li', 'shi', 'si'], + as_=['_mpmath_chi', '_mpmath_ci', '_mpmath_e1', '_mpmath_ei', '_mpmath_expint', + '_mpmath_ei', '_mpmath_li', '_mpmath_shi', '_mpmath_si']) class Function_exp_integral_e(BuiltinFunction): @@ -79,61 +87,60 @@ class Function_exp_integral_e(BuiltinFunction): Numerical evaluation is handled using mpmath:: - sage: N(exp_integral_e(1,1)) + sage: N(exp_integral_e(1, 1)) # needs sage.symbolic 0.219383934395520 - sage: exp_integral_e(1, RealField(100)(1)) + sage: exp_integral_e(1, RealField(100)(1)) # needs sage.symbolic 0.21938393439552027367716377546 We can compare this to PARI's evaluation of :meth:`exponential_integral_1`:: - sage: N(exponential_integral_1(1)) + sage: N(exponential_integral_1(1)) # needs sage.symbolic 0.219383934395520 We can verify one case of [AS1964]_ 5.1.45, i.e. `E_n(z) = z^{n-1}\Gamma(1-n,z)`:: - sage: N(exp_integral_e(2, 3+I)) + sage: N(exp_integral_e(2, 3+I)) # needs sage.symbolic 0.00354575823814662 - 0.00973200528288687*I - sage: N((3+I)*gamma(-1, 3+I)) + sage: N((3+I)*gamma(-1, 3+I)) # needs sage.symbolic 0.00354575823814662 - 0.00973200528288687*I Maxima returns the following improper integral as a multiple of ``exp_integral_e(1,1)``:: - sage: uu = integral(e^(-x)*log(x+1),x,0,oo) - sage: uu + sage: uu = integral(e^(-x)*log(x+1), x, 0, oo); uu # needs sage.symbolic e*exp_integral_e(1, 1) - sage: uu.n(digits=30) + sage: uu.n(digits=30) # needs sage.symbolic 0.596347362323194074341078499369 Symbolic derivatives and integrals are handled by Sage and Maxima:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = exp_integral_e(2,x) sage: f.diff(x) -exp_integral_e(1, x) - sage: f.integrate(x) -exp_integral_e(3, x) - - sage: f = exp_integral_e(-1,x) + sage: f = exp_integral_e(-1, x) sage: f.integrate(x) Ei(-x) - gamma(-1, x) Some special values of ``exp_integral_e`` can be simplified. [AS1964]_ 5.1.23:: - sage: exp_integral_e(0,x) + sage: exp_integral_e(0, x) # needs sage.symbolic e^(-x)/x [AS1964]_ 5.1.24:: - sage: exp_integral_e(6,0) + sage: # needs sage.symbolic + sage: exp_integral_e(6, 0) 1/5 sage: nn = var('nn') sage: assume(nn > 1) - sage: f = exp_integral_e(nn,0) + sage: f = exp_integral_e(nn, 0) sage: f.simplify() 1/(nn - 1) @@ -150,9 +157,9 @@ def __init__(self): EXAMPLES:: - sage: exp_integral_e(1, 0) + sage: exp_integral_e(1, 0) # needs sage.symbolic exp_integral_e(1, 0) - sage: exp_integral_e(1, x)._sympy_() + sage: exp_integral_e(1, x)._sympy_() # needs sage.symbolic expint(1, x) """ @@ -164,25 +171,25 @@ def _eval_(self, n, z): """ EXAMPLES:: - sage: exp_integral_e(1.0, x) + sage: exp_integral_e(1.0, x) # needs sage.symbolic exp_integral_e(1.00000000000000, x) - sage: exp_integral_e(x, 1.0) + sage: exp_integral_e(x, 1.0) # needs sage.symbolic exp_integral_e(x, 1.00000000000000) - sage: exp_integral_e(3, 0) + sage: exp_integral_e(3, 0) # needs mpmath 1/2 TESTS: Check that Python ints work (:trac:`14766`):: - sage: exp_integral_e(int(3), 0) + sage: exp_integral_e(int(3), 0) # needs mpmath 1/2 """ z_zero = False # special case: z == 0 and n > 1 if isinstance(z, Expression): if z.is_trivial_zero(): - z_zero = True # for later + z_zero = True # for later if n > 1: return 1/(n-1) else: @@ -205,22 +212,20 @@ def _eval_(self, n, z): else: return exp(-z)/z - return None # leaves the expression unevaluated + return None # leaves the expression unevaluated def _evalf_(self, n, z, parent=None, algorithm=None): """ EXAMPLES:: - sage: exp_integral_e(1.0, 1.0) + sage: exp_integral_e(1.0, 1.0) # needs mpmath 0.219383934395520 - sage: N(exp_integral_e(1, 1+I)) + sage: N(exp_integral_e(1, 1+I)) # needs sage.symbolic 0.000281624451981418 - 0.179324535039359*I - sage: exp_integral_e(1, RealField(100)(1)) + sage: exp_integral_e(1, RealField(100)(1)) # needs sage.rings.real_mpfr 0.21938393439552027367716377546 - """ - import mpmath - return mpmath_utils.call(mpmath.expint, n, z, parent=parent) + return _mpmath_utils_call(_mpmath_expint, n, z, parent=parent) def _print_latex_(self, n, z): r""" @@ -228,7 +233,7 @@ def _print_latex_(self, n, z): EXAMPLES:: - sage: latex(exp_integral_e(1, -x - 1)) + sage: latex(exp_integral_e(1, -x - 1)) # needs sage.symbolic E_{1}\left(-x - 1\right) """ return r"E_{{{}}}\left({}\right)".format(latex(n), latex(z)) @@ -241,20 +246,19 @@ def _derivative_(self, n, z, diff_param=None): EXAMPLES:: + sage: # needs sage.symbolic sage: x = var('x') - sage: f = exp_integral_e(2,x) + sage: f = exp_integral_e(2, x) sage: f.diff(x) -exp_integral_e(1, x) - - sage: f = exp_integral_e(2,sqrt(x)) + sage: f = exp_integral_e(2, sqrt(x)) sage: f.diff(x) -1/2*exp_integral_e(1, sqrt(x))/sqrt(x) - """ if n in ZZ and n > 0: - return -1*exp_integral_e(n-1,z) - else: - raise NotImplementedError("The derivative of this function is only implemented for n = 1, 2, 3, ...") + return -1*exp_integral_e(n-1, z) + raise NotImplementedError("The derivative of this function is only implemented for n = 1, 2, 3, ...") + exp_integral_e = Function_exp_integral_e() @@ -271,33 +275,33 @@ class Function_exp_integral_e1(BuiltinFunction): EXAMPLES:: - sage: exp_integral_e1(x) + sage: exp_integral_e1(x) # needs sage.symbolic exp_integral_e1(x) - sage: exp_integral_e1(1.0) + sage: exp_integral_e1(1.0) # needs mpmath 0.219383934395520 Numerical evaluation is handled using mpmath:: - sage: N(exp_integral_e1(1)) + sage: N(exp_integral_e1(1)) # needs sage.symbolic 0.219383934395520 - sage: exp_integral_e1(RealField(100)(1)) + sage: exp_integral_e1(RealField(100)(1)) # needs sage.rings.real_mpfr 0.21938393439552027367716377546 We can compare this to PARI's evaluation of :meth:`exponential_integral_1`:: - sage: N(exp_integral_e1(2.0)) + sage: N(exp_integral_e1(2.0)) # needs mpmath 0.0489005107080611 - sage: N(exponential_integral_1(2.0)) + sage: N(exponential_integral_1(2.0)) # needs sage.rings.real_mpfr 0.0489005107080611 Symbolic derivatives and integrals are handled by Sage and Maxima:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = exp_integral_e1(x) sage: f.diff(x) -e^(-x)/x - sage: f.integrate(x) -exp_integral_e(2, x) @@ -313,9 +317,9 @@ def __init__(self): EXAMPLES:: - sage: exp_integral_e1(1) + sage: exp_integral_e1(1) # needs sage.symbolic exp_integral_e1(1) - sage: exp_integral_e1(x)._sympy_() + sage: exp_integral_e1(x)._sympy_() # needs sympy sage.symbolic expint(1, x) """ @@ -327,15 +331,13 @@ def _evalf_(self, z, parent=None, algorithm=None): """ EXAMPLES:: - sage: N(exp_integral_e1(1+I)) + sage: N(exp_integral_e1(1+I)) # needs sage.symbolic 0.000281624451981418 - 0.179324535039359*I - sage: exp_integral_e1(RealField(200)(0.5)) + sage: exp_integral_e1(RealField(200)(0.5)) # needs sage.rings.real_mpfr 0.55977359477616081174679593931508523522684689031635351524829 """ - import mpmath - return mpmath_utils_call(mpmath.e1, z, parent=parent) - + return _mpmath_utils_call(_mpmath_e1, z, parent=parent) def _print_latex_(self, z): r""" @@ -343,7 +345,7 @@ def _print_latex_(self, z): EXAMPLES:: - sage: latex(exp_integral_e1(2)) + sage: latex(exp_integral_e1(2)) # needs sage.symbolic E_{1}\left(2\right) """ return r"E_{{1}}\left({}\right)".format(latex(z)) @@ -356,11 +358,11 @@ def _derivative_(self, z, diff_param=None): EXAMPLES:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = exp_integral_e1(x) sage: f.diff(x) -e^(-x)/x - sage: f = exp_integral_e1(x^2) sage: f.diff(x) -2*e^(-x^2)/x @@ -368,6 +370,7 @@ def _derivative_(self, z, diff_param=None): """ return -exp(-z)/z + exp_integral_e1 = Function_exp_integral_e1() @@ -385,22 +388,22 @@ class Function_log_integral(BuiltinFunction): Numerical evaluation for real and complex arguments is handled using mpmath:: - sage: N(log_integral(3)) + sage: N(log_integral(3)) # needs sage.symbolic 2.16358859466719 - sage: N(log_integral(3), digits=30) + sage: N(log_integral(3), digits=30) # needs sage.symbolic 2.16358859466719197287692236735 - sage: log_integral(ComplexField(100)(3+I)) + sage: log_integral(ComplexField(100)(3+I)) # needs sage.symbolic 2.2879892769816826157078450911 + 0.87232935488528370139883806779*I - sage: log_integral(0) + sage: log_integral(0) # needs mpmath 0 Symbolic derivatives and integrals are handled by Sage and Maxima:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = log_integral(x) sage: f.diff(x) 1/log(x) - sage: f.integrate(x) x*log_integral(x) - Ei(2*log(x)) @@ -408,7 +411,7 @@ class Function_log_integral(BuiltinFunction): 1,925,320,391,606,803,968,923 many prime numbers less than 1e23. The value of ``log_integral(1e23)`` is very close to this:: - sage: log_integral(1e23) + sage: log_integral(1e23) # needs mpmath 1.92532039161405e21 ALGORITHM: @@ -431,18 +434,18 @@ def __init__(self): EXAMPLES:: - sage: log_integral(3) + sage: log_integral(3) # needs sage.symbolic log_integral(3) - sage: log_integral(x)._sympy_() + sage: log_integral(x)._sympy_() # needs sympy sage.symbolic li(x) - sage: log_integral(x)._fricas_init_() + sage: log_integral(x)._fricas_init_() # needs sage.symbolic 'li(x)' TESTS: Verify that :trac:`28917` is fixed:: - sage: latex(log_integral(x)) + sage: latex(log_integral(x)) # needs sage.symbolic \operatorname{log\_integral}\left(x\right) """ BuiltinFunction.__init__(self, "log_integral", nargs=1, @@ -455,12 +458,12 @@ def _eval_(self, z): """ EXAMPLES:: - sage: z = var('z') - sage: log_integral(z) + sage: z = var('z') # needs sage.symbolic + sage: log_integral(z) # needs sage.symbolic log_integral(z) - sage: log_integral(3.0) + sage: log_integral(3.0) # needs mpmath 2.16358859466719 - sage: log_integral(0) + sage: log_integral(0) # needs mpmath 0 """ @@ -475,14 +478,13 @@ def _evalf_(self, z, parent=None, algorithm=None): """ EXAMPLES:: - sage: N(log_integral(1e6)) + sage: N(log_integral(1e6)) # needs mpmath 78627.5491594622 - sage: log_integral(RealField(200)(1e6)) + sage: log_integral(RealField(200)(1e6)) # needs sage.rings.real_mpfr 78627.549159462181919862910747947261161321874382421767074759 """ - import mpmath - return mpmath_utils_call(mpmath.li, z, parent=parent) + return _mpmath_utils_call(_mpmath_li, z, parent=parent) def _derivative_(self, z, diff_param=None): r""" @@ -490,11 +492,11 @@ def _derivative_(self, z, diff_param=None): EXAMPLES:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = log_integral(x) sage: f.diff(x) 1/log(x) - sage: f = log_integral(x^2) sage: f.diff(x) 2*x/log(x^2) @@ -502,8 +504,10 @@ def _derivative_(self, z, diff_param=None): """ return 1/log(z) + li = log_integral = Function_log_integral() + class Function_log_integral_offset(BuiltinFunction): r""" The offset logarithmic integral, or Eulerian logarithmic integral, @@ -537,13 +541,13 @@ class Function_log_integral_offset(BuiltinFunction): So we have:: - sage: li(4.5)-li(2.0)-Li(4.5) + sage: li(4.5) - li(2.0) - Li(4.5) # needs mpmath 0.000000000000000 `\operatorname{Li}(x)` is extended to complex arguments `z` by analytic continuation (see [AS1964]_ 5.1.3):: - sage: Li(6.6+5.4*I) + sage: Li(6.6 + 5.4*I) # needs sage.symbolic 3.97032201503632 + 2.62311237593572*I The function `\operatorname{Li}` is an approximation for the number of @@ -570,6 +574,7 @@ class Function_log_integral_offset(BuiltinFunction): Numerical evaluation for real and complex arguments is handled using mpmath:: + sage: # needs sage.symbolic sage: N(log_integral_offset(3)) 1.11842481454970 sage: N(log_integral_offset(3), digits=30) @@ -578,7 +583,7 @@ class Function_log_integral_offset(BuiltinFunction): 1.2428254968641898308632562019 + 0.87232935488528370139883806779*I sage: log_integral_offset(2) 0 - sage: for n in range(1,7): + sage: for n in range(1,7): # needs primecountpy ....: print('%-10s%-10s%-20s'%(10^n, prime_pi(10^n), N(Li(10^n)))) 10 4 5.12043572466980 100 25 29.0809778039621 @@ -591,20 +596,21 @@ class Function_log_integral_offset(BuiltinFunction): There are 1,925,320,391,606,803,968,923 prime numbers less than 1e23. The value of ``log_integral_offset(1e23)`` is very close to this:: - sage: log_integral_offset(1e23) + sage: log_integral_offset(1e23) # needs mpmath 1.92532039161405e21 Symbolic derivatives are handled by Sage and integration by Maxima:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = log_integral_offset(x) sage: f.diff(x) 1/log(x) sage: f.integrate(x) -x*log_integral(2) + x*log_integral(x) - Ei(2*log(x)) - sage: Li(x).integrate(x,2.0,4.5) - -2.5*log_integral(2) + 5.799321147411334 - sage: N(f.integrate(x,2.0,3.0)) # abs tol 1e-15 + sage: Li(x).integrate(x, 2.0, 4.5).n(digits=10) + 3.186411697 + sage: N(f.integrate(x, 2.0, 3.0)) # abs tol 1e-15 0.601621785860587 ALGORITHM: @@ -626,9 +632,9 @@ def __init__(self): EXAMPLES:: - sage: log_integral_offset(3) + sage: log_integral_offset(3) # needs sage.symbolic log_integral(3) - log_integral(2) - sage: log_integral_offset(x, hold=True)._sympy_() + sage: log_integral_offset(x, hold=True)._sympy_() # needs sympy sage.symbolic Li(x) TESTS: @@ -643,22 +649,21 @@ def __init__(self): latex_name=r'\operatorname{log\_integral\_offset}', conversions=dict(sympy='Li')) - def _eval_(self,z): + def _eval_(self, z): """ EXAMPLES:: - sage: z = var('z') - sage: log_integral_offset(z) + sage: z = var('z') # needs sage.symbolic + sage: log_integral_offset(z) # needs sage.symbolic -log_integral(2) + log_integral(z) - sage: log_integral_offset(3.0) + sage: log_integral_offset(3.0) # needs mpmath 1.11842481454970 - sage: log_integral_offset(2) + sage: log_integral_offset(2) # needs mpmath 0 """ if z == 2: - import sage.symbolic.ring - return sage.symbolic.ring.SR(0) + return SR(0) return li(z)-li(2) # If we return:(li(z)-li(2)) we get correct symbolic integration. # But on definite integration it returns x.xxxx-li(2). @@ -667,16 +672,15 @@ def _evalf_(self, z, parent=None, algorithm=None): """ EXAMPLES:: - sage: N(log_integral_offset(1e6)) + sage: N(log_integral_offset(1e6)) # needs mpmath 78626.5039956821 - sage: log_integral_offset(RealField(200)(1e6)) + sage: log_integral_offset(RealField(200)(1e6)) # needs sage.rings.real_mpfr 78626.503995682064427078066159058066548185351766843615873183 - sage: li(4.5)-li(2.0)-Li(4.5) + sage: li(4.5) - li(2.0) - Li(4.5) # needs mpmath 0.000000000000000 """ - import mpmath - return mpmath_utils_call(mpmath.li, z, offset=True, parent=parent) + return _mpmath_utils_call(_mpmath_li, z, offset=True, parent=parent) def _derivative_(self, z, diff_param=None): r""" @@ -684,19 +688,21 @@ def _derivative_(self, z, diff_param=None): EXAMPLES:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = log_integral_offset(x) sage: f.diff(x) 1/log(x) - sage: f = log_integral_offset(x^2) sage: f.diff(x) 2*x/log(x^2) """ return 1/log(z) + Li = log_integral_offset = Function_log_integral_offset() + class Function_sin_integral(BuiltinFunction): r""" The trigonometric integral `\operatorname{Si}(z)` defined by @@ -711,56 +717,55 @@ class Function_sin_integral(BuiltinFunction): Numerical evaluation for real and complex arguments is handled using mpmath:: - sage: sin_integral(0) + sage: sin_integral(0) # needs mpmath 0 - sage: sin_integral(0.0) + sage: sin_integral(0.0) # needs mpmath 0.000000000000000 - sage: sin_integral(3.0) + sage: sin_integral(3.0) # needs mpmath 1.84865252799947 - sage: N(sin_integral(3), digits=30) + sage: N(sin_integral(3), digits=30) # needs sage.symbolic 1.84865252799946825639773025111 - sage: sin_integral(ComplexField(100)(3+I)) + sage: sin_integral(ComplexField(100)(3+I)) # needs sage.symbolic 2.0277151656451253616038525998 + 0.015210926166954211913653130271*I The alias ``Si`` can be used instead of ``sin_integral``:: - sage: Si(3.0) + sage: Si(3.0) # needs mpmath 1.84865252799947 The limit of `\operatorname{Si}(z)` as `z \to \infty` is `\pi/2`:: - sage: N(sin_integral(1e23)) + sage: N(sin_integral(1e23)) # needs mpmath 1.57079632679490 - sage: N(pi/2) + sage: N(pi/2) # needs sage.symbolic 1.57079632679490 At 200 bits of precision `\operatorname{Si}(10^{23})` agrees with `\pi/2` up to `10^{-24}`:: - sage: sin_integral(RealField(200)(1e23)) + sage: sin_integral(RealField(200)(1e23)) # needs sage.rings.real_mpfr 1.5707963267948966192313288218697837425815368604836679189519 - sage: N(pi/2, prec=200) + sage: N(pi/2, prec=200) # needs sage.symbolic 1.5707963267948966192313216916397514420985846996875529104875 The exponential sine integral is analytic everywhere:: - sage: sin_integral(-1.0) + sage: sin_integral(-1.0) # needs mpmath -0.946083070367183 - sage: sin_integral(-2.0) + sage: sin_integral(-2.0) # needs mpmath -1.60541297680269 - sage: sin_integral(-1e23) + sage: sin_integral(-1e23) # needs mpmath -1.57079632679490 Symbolic derivatives and integrals are handled by Sage and Maxima:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = sin_integral(x) sage: f.diff(x) sin(x)/x - sage: f.integrate(x) x*sin_integral(x) + cos(x) - sage: integrate(sin(x)/x, x) -1/2*I*Ei(I*x) + 1/2*I*Ei(-I*x) @@ -770,19 +775,20 @@ class Function_sin_integral(BuiltinFunction): \operatorname{Ei}(ix) - \pi/2`, which are both anti-derivatives of `\sin(x)/x`, at some random positive real numbers:: - sage: f(x) = 1/2*I*Ei(-I*x) - 1/2*I*Ei(I*x) - pi/2 - sage: g(x) = sin_integral(x) - sage: R = [ abs(RDF.random_element()) for i in range(100) ] - sage: all(abs(f(x) - g(x)) < 1e-10 for x in R) + sage: f(x) = 1/2*I*Ei(-I*x) - 1/2*I*Ei(I*x) - pi/2 # needs sage.symbolic + sage: g(x) = sin_integral(x) # needs sage.symbolic + sage: R = [abs(RDF.random_element()) for i in range(100)] + sage: all(abs(f(x) - g(x)) < 1e-10 for x in R) # needs sage.symbolic True The Nielsen spiral is the parametric plot of (Si(t), Ci(t)):: - sage: x=var('x') + sage: # needs sage.symbolic + sage: x = var('x') sage: f(x) = sin_integral(x) sage: g(x) = cos_integral(x) - sage: P = parametric_plot([f, g], (x, 0.5 ,20)) - sage: show(P, frame=True, axes=False) + sage: P = parametric_plot([f, g], (x, 0.5 ,20)) # needs sage.plot + sage: show(P, frame=True, axes=False) # needs sage.plot ALGORITHM: @@ -803,13 +809,14 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: sin_integral(1) sin_integral(1) - sage: sin_integral(x)._sympy_() + sage: sin_integral(x)._sympy_() # needs sympy Si(x) sage: sin_integral(x)._fricas_init_() 'Si(x)' - sage: sin_integral(x)._giac_() + sage: sin_integral(x)._giac_() # needs sage.libs.giac Si(sageVARx) """ BuiltinFunction.__init__(self, "sin_integral", nargs=1, @@ -822,12 +829,12 @@ def _eval_(self, z): """ EXAMPLES:: - sage: z = var('z') - sage: sin_integral(z) + sage: z = var('z') # needs sage.symbolic + sage: sin_integral(z) # needs sage.symbolic sin_integral(z) - sage: sin_integral(3.0) + sage: sin_integral(3.0) # needs mpmath 1.84865252799947 - sage: sin_integral(0) + sage: sin_integral(0) # needs mpmath 0 """ @@ -843,29 +850,28 @@ def _evalf_(self, z, parent=None, algorithm=None): The limit `\operatorname{Si}(z)` as `z \to \infty` is `\pi/2`:: - sage: N(sin_integral(1e23) - pi/2) + sage: N(sin_integral(1e23) - pi/2) # needs sage.symbolic 0.000000000000000 At 200 bits of precision `\operatorname{Si}(10^{23})` agrees with `\pi/2` up to `10^{-24}`:: - sage: sin_integral(RealField(200)(1e23)) + sage: sin_integral(RealField(200)(1e23)) # needs sage.rings.real_mpfr 1.5707963267948966192313288218697837425815368604836679189519 - sage: N(pi/2, prec=200) + sage: N(pi/2, prec=200) # needs sage.symbolic 1.5707963267948966192313216916397514420985846996875529104875 The exponential sine integral is analytic everywhere, even on the negative real axis:: - sage: sin_integral(-1.0) + sage: sin_integral(-1.0) # needs mpmath -0.946083070367183 - sage: sin_integral(-2.0) + sage: sin_integral(-2.0) # needs mpmath -1.60541297680269 - sage: sin_integral(-1e23) + sage: sin_integral(-1e23) # needs mpmath -1.57079632679490 """ - import mpmath - return mpmath_utils_call(mpmath.si, z, parent=parent) + return _mpmath_utils_call(_mpmath_si, z, parent=parent) def _derivative_(self, z, diff_param=None): r""" @@ -875,11 +881,11 @@ def _derivative_(self, z, diff_param=None): EXAMPLES:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = sin_integral(x) sage: f.diff(x) sin(x)/x - sage: f = sin_integral(x^2) sage: f.diff(x) 2*sin(x^2)/x @@ -887,6 +893,7 @@ def _derivative_(self, z, diff_param=None): """ return sin(z)/z + Si = sin_integral = Function_sin_integral() @@ -903,62 +910,63 @@ class Function_cos_integral(BuiltinFunction): EXAMPLES:: - sage: z = var('z') - sage: cos_integral(z) + sage: z = var('z') # needs sage.symbolic + sage: cos_integral(z) # needs sage.symbolic cos_integral(z) - sage: cos_integral(3.0) + sage: cos_integral(3.0) # needs mpmath 0.119629786008000 - sage: cos_integral(0) + sage: cos_integral(0) # needs sage.symbolic cos_integral(0) - sage: N(cos_integral(0)) + sage: N(cos_integral(0)) # needs mpmath -infinity Numerical evaluation for real and complex arguments is handled using mpmath:: - sage: cos_integral(3.0) + sage: cos_integral(3.0) # needs mpmath 0.119629786008000 The alias ``Ci`` can be used instead of ``cos_integral``:: - sage: Ci(3.0) + sage: Ci(3.0) # needs mpmath 0.119629786008000 Compare ``cos_integral(3.0)`` to the definition of the value using numerical integration:: - sage: a = numerical_integral((cos(x)-1)/x, 0, 3)[0] - sage: abs(N(euler_gamma + log(3)) + a - N(cos_integral(3.0))) < 1e-14 + sage: a = numerical_integral((cos(x)-1)/x, 0, 3)[0] # needs sage.symbolic + sage: abs(N(euler_gamma + log(3)) + a - N(cos_integral(3.0))) < 1e-14 # needs sage.symbolic True Arbitrary precision and complex arguments are handled:: - sage: N(cos_integral(3), digits=30) + sage: N(cos_integral(3), digits=30) # needs sage.symbolic 0.119629786008000327626472281177 - sage: cos_integral(ComplexField(100)(3+I)) + sage: cos_integral(ComplexField(100)(3+I)) # needs sage.symbolic 0.078134230477495714401983633057 - 0.37814733904787920181190368789*I The limit `\operatorname{Ci}(z)` as `z \to \infty` is zero:: - sage: N(cos_integral(1e23)) + sage: N(cos_integral(1e23)) # needs mpmath -3.24053937643003e-24 Symbolic derivatives and integrals are handled by Sage and Maxima:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = cos_integral(x) sage: f.diff(x) cos(x)/x - sage: f.integrate(x) x*cos_integral(x) - sin(x) The Nielsen spiral is the parametric plot of (Si(t), Ci(t)):: - sage: t=var('t') + sage: # needs sage.symbolic + sage: t = var('t') sage: f(t) = sin_integral(t) sage: g(t) = cos_integral(t) - sage: P = parametric_plot([f, g], (t, 0.5 ,20)) - sage: show(P, frame=True, axes=False) + sage: P = parametric_plot([f, g], (t, 0.5 ,20)) # needs sage.plot + sage: show(P, frame=True, axes=False) # needs sage.plot ALGORITHM: @@ -979,13 +987,14 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: cos_integral(1) cos_integral(1) - sage: cos_integral(x)._sympy_() + sage: cos_integral(x)._sympy_() # needs sympy Ci(x) sage: cos_integral(x)._fricas_init_() 'Ci(x)' - sage: cos_integral(x)._giac_() + sage: cos_integral(x)._giac_() # needs sage.libs.giac Ci(sageVARx) """ BuiltinFunction.__init__(self, "cos_integral", nargs=1, @@ -998,16 +1007,15 @@ def _evalf_(self, z, parent=None, algorithm=None): """ EXAMPLES:: - sage: N(cos_integral(1e23)) < 1e-20 + sage: N(cos_integral(1e23)) < 1e-20 # needs mpmath True - sage: N(cos_integral(10^-10), digits=30) + sage: N(cos_integral(10^-10), digits=30) # needs sage.symbolic -22.4486352650389239795759024568 - sage: cos_integral(ComplexField(100)(I)) + sage: cos_integral(ComplexField(100)(I)) # needs sage.symbolic 0.83786694098020824089467857943 + 1.5707963267948966192313216916*I """ - import mpmath - return mpmath_utils_call(mpmath.ci, z, parent=parent) + return _mpmath_utils_call(_mpmath_ci, z, parent=parent) def _derivative_(self, z, diff_param=None): r""" @@ -1015,11 +1023,11 @@ def _derivative_(self, z, diff_param=None): EXAMPLES:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = cos_integral(x) sage: f.diff(x) cos(x)/x - sage: f = cos_integral(x^2) sage: f.diff(x) 2*cos(x^2)/x @@ -1027,6 +1035,7 @@ def _derivative_(self, z, diff_param=None): """ return cos(z)/z + Ci = cos_integral = Function_cos_integral() @@ -1044,45 +1053,45 @@ class Function_sinh_integral(BuiltinFunction): Numerical evaluation for real and complex arguments is handled using mpmath:: - sage: sinh_integral(3.0) + sage: sinh_integral(3.0) # needs mpmath 4.97344047585981 - sage: sinh_integral(1.0) + sage: sinh_integral(1.0) # needs mpmath 1.05725087537573 - sage: sinh_integral(-1.0) + sage: sinh_integral(-1.0) # needs mpmath -1.05725087537573 The alias ``Shi`` can be used instead of ``sinh_integral``:: - sage: Shi(3.0) + sage: Shi(3.0) # needs mpmath 4.97344047585981 Compare ``sinh_integral(3.0)`` to the definition of the value using numerical integration:: - sage: a = numerical_integral(sinh(x)/x, 0, 3)[0] - sage: abs(a - N(sinh_integral(3))) < 1e-14 + sage: a = numerical_integral(sinh(x)/x, 0, 3)[0] # needs sage.symbolic + sage: abs(a - N(sinh_integral(3))) < 1e-14 # needs sage.symbolic True Arbitrary precision and complex arguments are handled:: - sage: N(sinh_integral(3), digits=30) + sage: N(sinh_integral(3), digits=30) # needs sage.symbolic 4.97344047585980679771041838252 - sage: sinh_integral(ComplexField(100)(3+I)) + sage: sinh_integral(ComplexField(100)(3+I)) # needs sage.symbolic 3.9134623660329374406788354078 + 3.0427678212908839256360163759*I The limit `\operatorname{Shi}(z)` as `z \to \infty` is `\infty`:: - sage: N(sinh_integral(Infinity)) + sage: N(sinh_integral(Infinity)) # needs mpmath +infinity Symbolic derivatives and integrals are handled by Sage and Maxima:: - sage: x = var('x') - sage: f = sinh_integral(x) - sage: f.diff(x) + sage: x = var('x') # needs sage.symbolic + sage: f = sinh_integral(x) # needs sage.symbolic + sage: f.diff(x) # needs sage.symbolic sinh(x)/x - sage: f.integrate(x) + sage: f.integrate(x) # needs sage.symbolic x*sinh_integral(x) - cosh(x) Note that due to some problems with the way Maxima handles these @@ -1090,11 +1099,11 @@ class Function_sinh_integral(BuiltinFunction): results (typically when using inexact endpoints) due to inconsistent branching:: - sage: integrate(sinh_integral(x), x, 0, 1/2) + sage: integrate(sinh_integral(x), x, 0, 1/2) # needs sage.symbolic -cosh(1/2) + 1/2*sinh_integral(1/2) + 1 - sage: integrate(sinh_integral(x), x, 0, 1/2).n() # correct + sage: integrate(sinh_integral(x), x, 0, 1/2).n() # correct # needs sage.symbolic 0.125872409703453 - sage: integrate(sinh_integral(x), x, 0, 0.5).n() # fixed in maxima 5.29.1 + sage: integrate(sinh_integral(x), x, 0, 0.5).n() # fixed in maxima 5.29.1 # needs sage.symbolic 0.125872409703453 ALGORITHM: @@ -1116,9 +1125,9 @@ def __init__(self): EXAMPLES:: - sage: sinh_integral(1) + sage: sinh_integral(1) # needs sage.symbolic sinh_integral(1) - sage: sinh_integral(x)._sympy_() + sage: sinh_integral(x)._sympy_() # needs sympy sage.symbolic Shi(x) """ @@ -1132,12 +1141,12 @@ def _eval_(self, z): """ EXAMPLES:: - sage: z = var('z') - sage: sinh_integral(z) + sage: z = var('z') # needs sage.symbolic + sage: sinh_integral(z) # needs sage.symbolic sinh_integral(z) - sage: sinh_integral(3.0) + sage: sinh_integral(3.0) # needs mpmath 4.97344047585981 - sage: sinh_integral(0) + sage: sinh_integral(0) # needs mpmath 0 """ @@ -1152,14 +1161,13 @@ def _evalf_(self, z, parent=None, algorithm=None): """ EXAMPLES:: - sage: N(sinh_integral(10^-10), digits=30) + sage: N(sinh_integral(10^-10), digits=30) # needs sage.symbolic 1.00000000000000000000055555556e-10 - sage: sinh_integral(ComplexField(100)(I)) + sage: sinh_integral(ComplexField(100)(I)) # needs sage.symbolic 0.94608307036718301494135331382*I """ - import mpmath - return mpmath_utils_call(mpmath.shi, z, parent=parent) + return _mpmath_utils_call(_mpmath_shi, z, parent=parent) def _derivative_(self, z, diff_param=None): r""" @@ -1167,11 +1175,11 @@ def _derivative_(self, z, diff_param=None): EXAMPLES:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = sinh_integral(x) sage: f.diff(x) sinh(x)/x - sage: f = sinh_integral(ln(x)) sage: f.diff(x) 1/2*(x^2 - 1)/(x^2*log(x)) @@ -1179,6 +1187,7 @@ def _derivative_(self, z, diff_param=None): """ return sinh(z)/z + Shi = sinh_integral = Function_sinh_integral() @@ -1194,54 +1203,54 @@ class Function_cosh_integral(BuiltinFunction): EXAMPLES:: - sage: z = var('z') - sage: cosh_integral(z) + sage: z = var('z') # needs sage.symbolic + sage: cosh_integral(z) # needs sage.symbolic cosh_integral(z) - sage: cosh_integral(3.0) + sage: cosh_integral(3.0) # needs mpmath 4.96039209476561 Numerical evaluation for real and complex arguments is handled using mpmath:: - sage: cosh_integral(1.0) + sage: cosh_integral(1.0) # needs mpmath 0.837866940980208 The alias ``Chi`` can be used instead of ``cosh_integral``:: - sage: Chi(1.0) + sage: Chi(1.0) # needs mpmath 0.837866940980208 Here is an example from the mpmath documentation:: - sage: f(x) = cosh_integral(x) - sage: find_root(f, 0.1, 1.0) + sage: f(x) = cosh_integral(x) # needs sage.symbolic + sage: find_root(f, 0.1, 1.0) # needs scipy sage.symbolic 0.523822571389... Compare ``cosh_integral(3.0)`` to the definition of the value using numerical integration:: - sage: a = numerical_integral((cosh(x)-1)/x, 0, 3)[0] - sage: abs(N(euler_gamma + log(3)) + a - N(cosh_integral(3.0))) < 1e-14 + sage: a = numerical_integral((cosh(x)-1)/x, 0, 3)[0] # needs sage.symbolic + sage: abs(N(euler_gamma + log(3)) + a - N(cosh_integral(3.0))) < 1e-14 # needs sage.symbolic True Arbitrary precision and complex arguments are handled:: - sage: N(cosh_integral(3), digits=30) + sage: N(cosh_integral(3), digits=30) # needs sage.symbolic 4.96039209476560976029791763669 - sage: cosh_integral(ComplexField(100)(3+I)) + sage: cosh_integral(ComplexField(100)(3+I)) # needs sage.symbolic 3.9096723099686417127843516794 + 3.0547519627014217273323873274*I The limit of `\operatorname{Chi}(z)` as `z \to \infty` is `\infty`:: - sage: N(cosh_integral(Infinity)) + sage: N(cosh_integral(Infinity)) # needs mpmath +infinity Symbolic derivatives and integrals are handled by Sage and Maxima:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = cosh_integral(x) sage: f.diff(x) cosh(x)/x - sage: f.integrate(x) x*cosh_integral(x) - sinh(x) @@ -1264,9 +1273,9 @@ def __init__(self): EXAMPLES:: - sage: cosh_integral(1) + sage: cosh_integral(1) # needs sage.symbolic cosh_integral(1) - sage: cosh_integral(x)._sympy_() + sage: cosh_integral(x)._sympy_() # needs sage.symbolic Chi(x) """ @@ -1280,14 +1289,13 @@ def _evalf_(self, z, parent=None, algorithm=None): """ EXAMPLES:: - sage: N(cosh_integral(10^-10), digits=30) + sage: N(cosh_integral(10^-10), digits=30) # needs sage.symbolic -22.4486352650389239795709024568 - sage: cosh_integral(ComplexField(100)(I)) + sage: cosh_integral(ComplexField(100)(I)) # needs sage.symbolic 0.33740392290096813466264620389 + 1.5707963267948966192313216916*I """ - import mpmath - return mpmath_utils_call(mpmath.chi, z, parent=parent) + return _mpmath_utils_call(_mpmath_chi, z, parent=parent) def _derivative_(self, z, diff_param=None): r""" @@ -1295,11 +1303,11 @@ def _derivative_(self, z, diff_param=None): EXAMPLES:: + sage: # needs sage.symbolic sage: x = var('x') sage: f = cosh_integral(x) sage: f.diff(x) cosh(x)/x - sage: f = cosh_integral(ln(x)) sage: f.diff(x) 1/2*(x^2 + 1)/(x^2*log(x)) @@ -1307,6 +1315,7 @@ def _derivative_(self, z, diff_param=None): """ return cosh(z)/z + Chi = cosh_integral = Function_cosh_integral() @@ -1333,31 +1342,33 @@ class Function_exp_integral(BuiltinFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: Ei(10) Ei(10) sage: Ei(I) Ei(I) sage: Ei(3+I) Ei(I + 3) - sage: Ei(1.3) - 2.72139888023202 sage: Ei(10r) Ei(10) - sage: Ei(1.3r) + + sage: Ei(1.3) # needs mpmath + 2.72139888023202 + sage: Ei(1.3r) # needs mpmath 2.7213988802320235 The branch cut for this function is along the negative real axis:: - sage: Ei(-3 + 0.1*I) + sage: Ei(-3 + 0.1*I) # needs sage.symbolic -0.0129379427181693 + 3.13993830250942*I - sage: Ei(-3 - 0.1*I) + sage: Ei(-3 - 0.1*I) # needs sage.symbolic -0.0129379427181693 - 3.13993830250942*I The precision for the result is deduced from the precision of the input. Convert the input to a higher precision explicitly if a result with higher precision is desired:: - sage: Ei(RealField(300)(1.1)) + sage: Ei(RealField(300)(1.1)) # needs sage.rings.real_mpfr 2.16737827956340282358378734233807621497112737591639704719499002090327541763352339357795426 ALGORITHM: Uses mpmath. @@ -1366,6 +1377,7 @@ class Function_exp_integral(BuiltinFunction): Show that the evaluation and limit issue in :trac:`13271` is fixed:: + sage: # needs sage.symbolic sage: var('Z') Z sage: (Ei(-Z)).limit(Z=oo) @@ -1379,9 +1391,9 @@ def __init__(self): """ TESTS:: - sage: Ei(10) + sage: Ei(10) # needs sage.symbolic Ei(10) - sage: Ei(x)._sympy_() + sage: Ei(x)._sympy_() # needs sympy sage.symbolic Ei(x) """ BuiltinFunction.__init__(self, "Ei", @@ -1393,6 +1405,7 @@ def _evalf_(self, x, parent=None, algorithm=None): """ EXAMPLES:: + sage: # needs sage.symbolic sage: Ei(10).n() 2492.22897624188 sage: Ei(20).n() @@ -1402,13 +1415,13 @@ def _evalf_(self, x, parent=None, algorithm=None): sage: Ei(3+I).n() 7.82313467600158 + 6.09751978399231*I """ - import mpmath - return mpmath_utils_call(mpmath.ei, x, parent=parent) + return _mpmath_utils_call(_mpmath_ei, x, parent=parent) def _derivative_(self, x, diff_param=None): """ EXAMPLES:: + sage: # needs sage.symbolic sage: Ei(x).diff(x) e^x/x sage: Ei(x).diff(x).subs(x=1) @@ -1421,6 +1434,7 @@ def _derivative_(self, x, diff_param=None): """ return exp(x)/x + Ei = exp_integral_ei = Function_exp_integral() @@ -1456,27 +1470,29 @@ def exponential_integral_1(x, n=0): EXAMPLES:: + sage: # needs sage.libs.pari sage: exponential_integral_1(2) 0.0489005107080611 sage: exponential_integral_1(2, 4) # abs tol 1e-18 [0.0489005107080611, 0.00377935240984891, 0.000360082452162659, 0.0000376656228439245] sage: exponential_integral_1(40, 5) - [0.000000000000000, 2.22854325868847e-37, 6.33732515501151e-55, 2.02336191509997e-72, 6.88522610630764e-90] - sage: exponential_integral_1(0) - +Infinity - sage: r = exponential_integral_1(RealField(150)(1)) - sage: r + [0.000000000000000, 2.22854325868847e-37, 6.33732515501151e-55, + 2.02336191509997e-72, 6.88522610630764e-90] + sage: r = exponential_integral_1(RealField(150)(1)); r 0.21938393439552027367716377546012164903104729 sage: parent(r) Real Field with 150 bits of precision sage: exponential_integral_1(RealField(150)(100)) 3.6835977616820321802351926205081189876552201e-46 + sage: exponential_integral_1(0) + +Infinity + TESTS: The relative error for a single value should be less than 1 ulp:: - sage: for prec in [20..1000]: # long time (22s on sage.math, 2013) + sage: for prec in [20..1000]: # long time (22s on sage.math, 2013), needs sage.libs.pari ....: R = RealField(prec) ....: S = RealField(prec+64) ....: for t in range(8): # Try 8 values for each precision @@ -1490,7 +1506,7 @@ def exponential_integral_1(x, n=0): The absolute error for a vector should be less than `2^{-p} c`, where `p` is the precision in bits of `x` and `c = 2` ``max(1, exponential_integral_1(x))``:: - sage: for prec in [20..128]: # long time (15s on sage.math, 2013) + sage: for prec in [20..128]: # long time (15s on sage.math, 2013), needs sage.libs.pari ....: R = RealField(prec) ....: S = RealField(prec+64) ....: a = R.random_element(-15,10).exp() @@ -1512,7 +1528,6 @@ def exponential_integral_1(x, n=0): """ if isinstance(x, Expression): if x.is_trivial_zero(): - from sage.rings.infinity import Infinity return Infinity else: raise NotImplementedError("Use the symbolic exponential integral " + @@ -1520,7 +1535,6 @@ def exponential_integral_1(x, n=0): # x == 0 => return Infinity if not x: - from sage.rings.infinity import Infinity return Infinity # Figure out output precision diff --git a/src/sage/functions/gamma.py b/src/sage/functions/gamma.py index e93e518b0b9..8ecf834a8a8 100644 --- a/src/sage/functions/gamma.py +++ b/src/sage/functions/gamma.py @@ -1,16 +1,24 @@ """ Gamma and related functions """ -from sage.symbolic.function import GinacFunction, BuiltinFunction -from sage.symbolic.expression import register_symbol, symbol_table -from sage.structure.all import parent as s_parent -from sage.rings.complex_mpfr import ComplexField +from sage.misc.lazy_import import lazy_import +from sage.rings.infinity import Infinity from sage.rings.rational import Rational -from sage.functions.exp_integral import Ei -from sage.libs.mpmath import utils as mpmath_utils -from .log import exp -from .other import sqrt -from sage.symbolic.constants import pi +from sage.structure.element import parent as s_parent +from sage.symbolic.function import GinacFunction, BuiltinFunction +from sage.symbolic.symbols import register_symbol, symbol_table + +lazy_import('sage.rings.complex_mpfr', 'ComplexField') + +lazy_import('sage.functions.error', 'erf') +lazy_import('sage.functions.exp_integral', 'Ei') +lazy_import('sage.functions.log', 'exp') +lazy_import('sage.functions.other', 'sqrt') + +lazy_import('sage.symbolic.constants', 'pi') + +lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') +lazy_import('mpmath', 'gammainc', as_='_mpmath_gammainc') class Function_gamma(GinacFunction): @@ -32,9 +40,9 @@ def __init__(self): EXAMPLES:: sage: from sage.functions.gamma import gamma1 - sage: gamma1(CDF(0.5,14)) + sage: gamma1(CDF(0.5, 14)) # needs sage.libs.pari -4.0537030780372815e-10 - 5.773299834553605e-10*I - sage: gamma1(CDF(I)) + sage: gamma1(CDF(I)) # needs sage.libs.pari sage.symbolic -0.15494982830181067 - 0.49801566811835607*I Recall that `\Gamma(n)` is `n-1` factorial:: @@ -43,124 +51,124 @@ def __init__(self): True sage: gamma1(6) 120 - sage: gamma1(1/2) + sage: gamma1(1/2) # needs sage.symbolic sqrt(pi) sage: gamma1(-1) Infinity - sage: gamma1(I) + sage: gamma1(I) # needs sage.symbolic gamma(I) - sage: gamma1(x/2)(x=5) + sage: gamma1(x/2)(x=5) # needs sage.symbolic 3/4*sqrt(pi) sage: gamma1(float(6)) # For ARM: rel tol 3e-16 120.0 - sage: gamma(6.) + sage: gamma(6.) # needs sage.symbolic 120.000000000000 - sage: gamma1(x) + sage: gamma1(x) # needs sage.symbolic gamma(x) :: - sage: gamma1(pi) + sage: gamma1(pi) # needs sage.symbolic gamma(pi) - sage: gamma1(i) + sage: gamma1(i) # needs sage.symbolic gamma(I) - sage: gamma1(i).n() + sage: gamma1(i).n() # needs sage.symbolic -0.154949828301811 - 0.498015668118356*I sage: gamma1(int(5)) 24 :: - sage: conjugate(gamma(x)) + sage: conjugate(gamma(x)) # needs sage.symbolic gamma(conjugate(x)) :: - sage: plot(gamma1(x),(x,1,5)) + sage: plot(gamma1(x), (x,1,5)) # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive We are also able to compute the Laurent expansion of the Gamma function (as well as of functions containing the Gamma function):: - sage: gamma(x).series(x==0, 2) + sage: gamma(x).series(x==0, 2) # needs sage.symbolic 1*x^(-1) + (-euler_gamma) + (1/2*euler_gamma^2 + 1/12*pi^2)*x + Order(x^2) - sage: (gamma(x)^2).series(x==0, 1) + sage: (gamma(x)^2).series(x==0, 1) # needs sage.symbolic 1*x^(-2) + (-2*euler_gamma)*x^(-1) + (2*euler_gamma^2 + 1/6*pi^2) + Order(x) To prevent automatic evaluation use the ``hold`` argument:: - sage: gamma1(1/2,hold=True) + sage: gamma1(1/2, hold=True) # needs sage.symbolic gamma(1/2) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: gamma1(1/2,hold=True).simplify() + sage: gamma1(1/2, hold=True).simplify() # needs sage.symbolic sqrt(pi) TESTS: - sage: gamma(x)._sympy_() + sage: gamma(x)._sympy_() # needs sympy sage.symbolic gamma(x) We verify that we can convert this function to Maxima and convert back to Sage:: - sage: z = var('z') - sage: maxima(gamma1(z)).sage() + sage: z = var('z') # needs sage.symbolic + sage: maxima(gamma1(z)).sage() # needs sage.symbolic gamma(z) - sage: latex(gamma1(z)) + sage: latex(gamma1(z)) # needs sage.symbolic \Gamma\left(z\right) Test that :trac:`5556` is fixed:: - sage: gamma1(3/4) + sage: gamma1(3/4) # needs sage.symbolic gamma(3/4) - sage: gamma1(3/4).n(100) + sage: gamma1(3/4).n(100) # needs sage.symbolic 1.2254167024651776451290983034 Check that negative integer input works:: sage: (-1).gamma() Infinity - sage: (-1.).gamma() + sage: (-1.).gamma() # needs sage.rings.real_mpfr NaN - sage: CC(-1).gamma() + sage: CC(-1).gamma() # needs sage.libs.pari Infinity sage: RDF(-1).gamma() NaN - sage: CDF(-1).gamma() + sage: CDF(-1).gamma() # needs sage.libs.pari sage.rings.complex_double Infinity Check if :trac:`8297` is fixed:: - sage: latex(gamma(1/4)) + sage: latex(gamma(1/4)) # needs sage.symbolic \Gamma\left(\frac{1}{4}\right) Test pickling:: - sage: loads(dumps(gamma(x))) + sage: loads(dumps(gamma(x))) # needs sage.symbolic gamma(x) Check that the implementations roughly agrees (note there might be difference of several ulp on more complicated entries):: - sage: import mpmath - sage: float(gamma(10.)) == gamma(10.r) == float(gamma(mpmath.mpf(10))) + sage: import mpmath # needs mpmath + sage: float(gamma(10.)) == gamma(10.r) == float(gamma(mpmath.mpf(10))) # needs mpmath True - sage: float(gamma(8.5)) == gamma(8.5r) == float(gamma(mpmath.mpf(8.5))) + sage: float(gamma(8.5)) == gamma(8.5r) == float(gamma(mpmath.mpf(8.5))) # needs mpmath True Check that ``QQbar`` half integers work with the ``pi`` formula:: - sage: gamma(QQbar(1/2)) + sage: gamma(QQbar(1/2)) # needs sage.rings.number_field sage.symbolic sqrt(pi) - sage: gamma(QQbar(-9/2)) + sage: gamma(QQbar(-9/2)) # needs sage.rings.number_field sage.symbolic -32/945*sqrt(pi) .. SEEALSO:: @@ -175,6 +183,7 @@ def __init__(self): 'fricas':'Gamma', 'giac':'Gamma'}) + gamma1 = Function_gamma() @@ -197,14 +206,13 @@ def __init__(self): Numerical evaluation happens when appropriate, to the appropriate accuracy (see :trac:`10072`):: + sage: # needs sage.symbolic sage: log_gamma(6) log(120) sage: log_gamma(6.) 4.78749174278205 sage: log_gamma(6).n() 4.78749174278205 - sage: log_gamma(RealField(100)(6)) - 4.7874917427820459942477009345 sage: log_gamma(2.4 + I) -0.0308566579348816 + 0.693427705955790*I sage: log_gamma(-3.1) @@ -212,17 +220,21 @@ def __init__(self): sage: log_gamma(-1.1) == log(gamma(-1.1)) False + sage: log_gamma(RealField(100)(6)) # needs sage.rings.real_mpfr + 4.7874917427820459942477009345 + Symbolic input works (see :trac:`10075`):: - sage: log_gamma(3*x) + sage: log_gamma(3*x) # needs sage.symbolic log_gamma(3*x) - sage: log_gamma(3 + I) + sage: log_gamma(3 + I) # needs sage.symbolic log_gamma(I + 3) - sage: log_gamma(3 + I + x) + sage: log_gamma(3 + I + x) # needs sage.symbolic log_gamma(x + I + 3) Check that :trac:`12521` is fixed:: + sage: # needs sage.symbolic sage: log_gamma(-2.1) 1.53171380819509 - 9.42477796076938*I sage: log_gamma(CC(-2.1)) @@ -237,35 +249,38 @@ def __init__(self): to evaluate a held expression, use the ``n()`` numerical evaluation method:: - sage: log_gamma(SR(5), hold=True) + sage: log_gamma(SR(5), hold=True) # needs sage.symbolic log_gamma(5) - sage: log_gamma(SR(5), hold=True).n() + sage: log_gamma(SR(5), hold=True).n() # needs sage.symbolic 3.17805383034795 TESTS:: + sage: log_gamma(pari(6)) # needs sage.libs.pari + 4.78749174278205 + + sage: # needs sage.symbolic sage: log_gamma(-2.1 + I) -1.90373724496982 - 7.18482377077183*I - sage: log_gamma(pari(6)) - 4.78749174278205 - sage: log_gamma(x)._sympy_() + sage: log_gamma(x)._sympy_() # needs sympy loggamma(x) - sage: log_gamma(CC(6)) + sage: log_gamma(CC(6)) # needs sage.rings.real_mpfr 4.78749174278205 - sage: log_gamma(CC(-2.5)) + sage: log_gamma(CC(-2.5)) # needs sage.rings.real_mpfr -0.0562437164976741 - 9.42477796076938*I sage: log_gamma(RDF(-2.5)) -0.056243716497674054 - 9.42477796076938*I - sage: log_gamma(CDF(-2.5)) + sage: log_gamma(CDF(-2.5)) # needs sage.rings.complex_double -0.056243716497674054 - 9.42477796076938*I sage: log_gamma(float(-2.5)) (-0.056243716497674054-9.42477796076938j) - sage: log_gamma(complex(-2.5)) + sage: log_gamma(complex(-2.5)) # needs sage.rings.complex_double (-0.056243716497674054-9.42477796076938j) ``conjugate(log_gamma(x)) == log_gamma(conjugate(x))`` unless on the branch cut, which runs along the negative real axis.:: + sage: # needs sage.symbolic sage: conjugate(log_gamma(x)) conjugate(log_gamma(x)) sage: var('y', domain='positive') @@ -302,45 +317,49 @@ def __init__(self): EXAMPLES:: - sage: gamma_inc(CDF(0,1), 3) + sage: gamma_inc(CDF(0,1), 3) # needs sage.libs.pari sage.rings.complex_double 0.0032085749933691158 + 0.012406185811871568*I - sage: gamma_inc(RDF(1), 3) + sage: gamma_inc(RDF(1), 3) # needs sage.rings.complex_double 0.049787068367863944 - sage: gamma_inc(3,2) + + sage: # needs sage.symbolic + sage: gamma_inc(3, 2) gamma(3, 2) - sage: gamma_inc(x,0) + sage: gamma_inc(x, 0) gamma(x) - sage: latex(gamma_inc(3,2)) + sage: latex(gamma_inc(3, 2)) \Gamma\left(3, 2\right) - sage: loads(dumps((gamma_inc(3,2)))) + sage: loads(dumps((gamma_inc(3, 2)))) gamma(3, 2) - sage: i = ComplexField(30).0; gamma_inc(2, 1 + i) + + sage: i = ComplexField(30).0; gamma_inc(2, 1 + i) # needs sage.rings.real_mpfr 0.70709210 - 0.42035364*I - sage: gamma_inc(2., 5) + sage: gamma_inc(2., 5) # needs sage.rings.complex_double 0.0404276819945128 - sage: x,y=var('x,y') - sage: gamma_inc(x,y).diff(x) + + sage: x, y = var('x,y') # needs sage.symbolic + sage: gamma_inc(x,y).diff(x) # needs sage.symbolic diff(gamma(x, y), x) - sage: (gamma_inc(x,x+1).diff(x)).simplify() + sage: (gamma_inc(x, x + 1).diff(x)).simplify() # needs sage.symbolic -(x + 1)^(x - 1)*e^(-x - 1) + D[0](gamma)(x, x + 1) TESTS: Check that :trac:`21407` is fixed:: - sage: gamma(-1,5)._sympy_() + sage: gamma(-1, 5)._sympy_() # needs sympy sage.symbolic expint(2, 5)/5 - sage: gamma(-3/2,5)._sympy_() + sage: gamma(-3/2, 5)._sympy_() # needs sympy sage.symbolic -6*sqrt(5)*exp(-5)/25 + 4*sqrt(pi)*erfc(sqrt(5))/3 Check that :trac:`25597` is fixed:: - sage: gamma(-1,5)._fricas_() # optional - fricas + sage: gamma(-1, 5)._fricas_() # optional - fricas, needs sage.symbolic Gamma(- 1,5) - sage: var('t') # optional - fricas + sage: var('t') # needs sage.symbolic t - sage: integrate(-exp(-x)*x^(t-1), x, algorithm="fricas") # optional - fricas + sage: integrate(-exp(-x)*x^(t-1), x, algorithm="fricas") # optional - fricas, needs sage.symbolic gamma(t, x) .. SEEALSO:: @@ -356,6 +375,7 @@ def _method_arguments(self, x, y): r""" TESTS:: + sage: # needs sage.libs.flint sage: b = RBF(1, 1e-10) sage: gamma(b) # abs tol 1e-9 [1.0000000000 +/- 5.78e-11] @@ -372,21 +392,23 @@ def _eval_(self, x, y): """ EXAMPLES:: - sage: gamma_inc(2.,0) + sage: gamma_inc(2., 0) # needs sage.rings.complex_double 1.00000000000000 - sage: gamma_inc(2,0) + sage: gamma_inc(2, 0) # needs sage.rings.real_mpfr 1 - sage: gamma_inc(1/2,2) + + sage: # needs sage.symbolic + sage: gamma_inc(1/2, 2) -sqrt(pi)*(erf(sqrt(2)) - 1) - sage: gamma_inc(1/2,1) + sage: gamma_inc(1/2, 1) -sqrt(pi)*(erf(1) - 1) - sage: gamma_inc(1/2,0) + sage: gamma_inc(1/2, 0) sqrt(pi) - sage: gamma_inc(x,0) + sage: gamma_inc(x, 0) gamma(x) - sage: gamma_inc(1,2) + sage: gamma_inc(1, 2) e^(-2) - sage: gamma_inc(0,2) + sage: gamma_inc(0, 2) -Ei(-2) """ if y == 0: @@ -396,7 +418,6 @@ def _eval_(self, x, y): if x == 0: return -Ei(-y) if x == Rational((1, 2)): # only for x>0 - from sage.functions.error import erf return sqrt(pi) * (1 - erf(sqrt(y))) return None @@ -404,41 +425,41 @@ def _evalf_(self, x, y, parent=None, algorithm='pari'): """ EXAMPLES:: - sage: gamma_inc(0,2) + sage: gamma_inc(0, 2) # needs sage.symbolic -Ei(-2) - sage: gamma_inc(0,2.) + sage: gamma_inc(0, 2.) # needs sage.rings.real_mpfr 0.0489005107080611 - sage: gamma_inc(0,2).n(algorithm='pari') + sage: gamma_inc(0, 2).n(algorithm='pari') # needs sage.libs.pari sage.symbolic 0.0489005107080611 - sage: gamma_inc(0,2).n(200) + sage: gamma_inc(0, 2).n(200) # needs sage.symbolic 0.048900510708061119567239835228... - sage: gamma_inc(3,2).n() + sage: gamma_inc(3, 2).n() # needs sage.symbolic 1.35335283236613 TESTS: Check that :trac:`7099` is fixed:: - sage: R = RealField(1024) - sage: gamma(R(9), R(10^-3)) # rel tol 1e-308 + sage: R = RealField(1024) # needs sage.rings.real_mpfr + sage: gamma(R(9), R(10^-3)) # rel tol 1e-308 # needs sage.rings.real_mpfr 40319.99999999999999999999999999988898884344822911869926361916294165058203634104838326009191542490601781777105678829520585311300510347676330951251563007679436243294653538925717144381702105700908686088851362675381239820118402497959018315224423868693918493033078310647199219674433536605771315869983788442389633 - sage: numerical_approx(gamma(9, 10^(-3)) - gamma(9), digits=40) # abs tol 1e-36 + sage: numerical_approx(gamma(9, 10^(-3)) - gamma(9), digits=40) # abs tol 1e-36 # needs sage.symbolic -1.110111598370794007949063502542063148294e-28 Check that :trac:`17328` is fixed:: - sage: gamma_inc(float(-1), float(-1)) + sage: gamma_inc(float(-1), float(-1)) # needs sage.rings.real_mpfr (-0.8231640121031085+3.141592653589793j) - sage: gamma_inc(RR(-1), RR(-1)) + sage: gamma_inc(RR(-1), RR(-1)) # needs sage.rings.complex_double -0.823164012103109 + 3.14159265358979*I - sage: gamma_inc(-1, float(-log(3))) - gamma_inc(-1, float(-log(2))) # abs tol 1e-15 + sage: gamma_inc(-1, float(-log(3))) - gamma_inc(-1, float(-log(2))) # abs tol 1e-15 # needs sage.symbolic (1.2730972164471142+0j) Check that :trac:`17130` is fixed:: - sage: r = gamma_inc(float(0), float(1)); r + sage: r = gamma_inc(float(0), float(1)); r # needs sage.rings.real_mpfr 0.21938393439552029 - sage: type(r) + sage: type(r) # needs sage.rings.real_mpfr <... 'float'> """ R = parent or s_parent(x) @@ -460,14 +481,14 @@ def _evalf_(self, x, y, parent=None, algorithm='pari'): if algorithm == 'pari': v = ComplexField(prec)(x).gamma_inc(y) else: - import mpmath - v = ComplexField(prec)(mpmath_utils.call(mpmath.gammainc, x, y, parent=R)) + v = ComplexField(prec)(_mpmath_utils_call(_mpmath_gammainc, x, y, parent=R)) if v.is_real(): return R(v) else: return C(v) -# synonym. + +# shorter alias gamma_inc = Function_gamma_inc() @@ -484,10 +505,12 @@ def __init__(self): EXAMPLES:: - sage: gamma_inc_lower(CDF(0,1), 3) + sage: gamma_inc_lower(CDF(0,1), 3) # needs sage.rings.complex_double -0.1581584032951798 - 0.5104218539302277*I - sage: gamma_inc_lower(RDF(1), 3) + sage: gamma_inc_lower(RDF(1), 3) # needs sage.rings.complex_double 0.950212931632136 + + sage: # needs sage.symbolic sage: gamma_inc_lower(3, 2, hold=True) gamma_inc_lower(3, 2) sage: gamma_inc_lower(3, 2) @@ -498,16 +521,17 @@ def __init__(self): \gamma\left(x, x\right) sage: loads(dumps((gamma_inc_lower(x, x)))) gamma_inc_lower(x, x) - sage: i = ComplexField(30).0; gamma_inc_lower(2, 1 + i) + + sage: i = ComplexField(30).0; gamma_inc_lower(2, 1 + i) # needs sage.rings.real_mpfr 0.29290790 + 0.42035364*I - sage: gamma_inc_lower(2., 5) + sage: gamma_inc_lower(2., 5) # needs sage.rings.complex_double 0.959572318005487 Interfaces to other software:: - sage: gamma_inc_lower(x,x)._sympy_() + sage: gamma_inc_lower(x, x)._sympy_() # needs sympy sage.symbolic lowergamma(x, x) - sage: maxima(gamma_inc_lower(x,x)) + sage: maxima(gamma_inc_lower(x, x)) # needs sage.symbolic gamma_incomplete_lower(_SAGE_VAR_x,_SAGE_VAR_x) .. SEEALSO:: @@ -522,33 +546,34 @@ def _eval_(self, x, y): """ EXAMPLES:: - sage: gamma_inc_lower(2.,0) + sage: gamma_inc_lower(2., 0) # needs sage.rings.complex_double 0.000000000000000 - sage: gamma_inc_lower(2,0) + + sage: # needs sage.symbolic + sage: gamma_inc_lower(2, 0) 0 - sage: gamma_inc_lower(1/2,2) + sage: gamma_inc_lower(1/2, 2) sqrt(pi)*erf(sqrt(2)) - sage: gamma_inc_lower(1/2,1) + sage: gamma_inc_lower(1/2, 1) sqrt(pi)*erf(1) - sage: gamma_inc_lower(1/2,0) + sage: gamma_inc_lower(1/2, 0) 0 - sage: gamma_inc_lower(x,0) + sage: gamma_inc_lower(x, 0) 0 - sage: gamma_inc_lower(1,2) + sage: gamma_inc_lower(1, 2) -e^(-2) + 1 - sage: gamma_inc_lower(0,2) + sage: gamma_inc_lower(0, 2) +Infinity - sage: gamma_inc_lower(2,377/79) + sage: gamma_inc_lower(2, 377/79) -456/79*e^(-377/79) + 1 - sage: gamma_inc_lower(3,x) + sage: gamma_inc_lower(3, x) -(x^2 + 2*x + 2)*e^(-x) + 2 - sage: gamma_inc_lower(9/2,37/7) + sage: gamma_inc_lower(9/2, 37/7) -1/38416*sqrt(pi)*(1672946*sqrt(259)*e^(-37/7)/sqrt(pi) - 252105*erf(1/7*sqrt(259))) """ if y == 0: return 0 if x == 0: - from sage.rings.infinity import Infinity return Infinity elif x == 1: return 1 - exp(-y) @@ -561,11 +586,11 @@ def _evalf_(self, x, y, parent=None, algorithm='mpmath'): """ EXAMPLES:: - sage: gamma_inc_lower(3,2.) + sage: gamma_inc_lower(3, 2.) # needs sage.rings.real_mpfr 0.646647167633873 - sage: gamma_inc_lower(3,2).n(200) + sage: gamma_inc_lower(3, 2).n(200) # needs sage.symbolic 0.646647167633873081060005050275155... - sage: gamma_inc_lower(0,2.) + sage: gamma_inc_lower(0, 2.) # needs sage.rings.real_mpfr +infinity """ R = parent or s_parent(x) @@ -587,18 +612,17 @@ def _evalf_(self, x, y, parent=None, algorithm='mpmath'): Cx = ComplexField(prec)(x) v = Cx.gamma() - Cx.gamma_inc(y) else: - import mpmath - v = ComplexField(prec)(mpmath_utils.call(mpmath.gammainc, x, 0, y, parent=R)) + v = ComplexField(prec)(_mpmath_utils_call(_mpmath_gammainc, x, 0, y, parent=R)) return R(v) if v.is_real() else C(v) def _derivative_(self, x, y, diff_param=None): """ EXAMPLES:: - sage: x,y = var('x,y') - sage: gamma_inc_lower(x,y).diff(y) + sage: x, y = var('x,y') # needs sage.symbolic + sage: gamma_inc_lower(x, y).diff(y) # needs sage.symbolic y^(x - 1)*e^(-y) - sage: gamma_inc_lower(x,y).diff(x) + sage: gamma_inc_lower(x, y).diff(x) # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: cannot differentiate gamma_inc_lower in the first parameter @@ -613,7 +637,7 @@ def _mathematica_init_evaled_(self, *args): r""" EXAMPLES:: - sage: gamma_inc_lower(4/3, 1)._mathematica_() # indirect doctest, optional - mathematica + sage: gamma_inc_lower(4/3, 1)._mathematica_() # indirect doctest # optional - mathematica, needs sage.symbolic Gamma[4/3, 0, 1] """ args_mathematica = [] @@ -627,7 +651,8 @@ def _mathematica_init_evaled_(self, *args): x, z = args_mathematica return "Gamma[%s,0,%s]" % (x, z) -# synonym. + +# shorter alias gamma_inc_lower = Function_gamma_inc_lower() @@ -641,9 +666,9 @@ def gamma(a, *args, **kwds): True sage: gamma(6) 120 - sage: gamma(1/2) + sage: gamma(1/2) # needs sage.symbolic sqrt(pi) - sage: gamma(-4/3) + sage: gamma(-4/3) # needs sage.symbolic gamma(-4/3) sage: gamma(-1) Infinity @@ -652,47 +677,48 @@ def gamma(a, *args, **kwds): :: - sage: gamma_inc(3,2) + sage: gamma_inc(3, 2) # needs sage.symbolic gamma(3, 2) - sage: gamma_inc(x,0) + sage: gamma_inc(x,0) # needs sage.symbolic gamma(x) :: - sage: gamma(5, hold=True) + sage: gamma(5, hold=True) # needs sage.symbolic gamma(5) - sage: gamma(x, 0, hold=True) + sage: gamma(x, 0, hold=True) # needs sage.symbolic gamma(x, 0) :: - sage: gamma(CDF(I)) + sage: gamma(CDF(I)) # needs sage.libs.pari sage.symbolic -0.15494982830181067 - 0.49801566811835607*I - sage: gamma(CDF(0.5,14)) + sage: gamma(CDF(0.5, 14)) # needs sage.libs.pari -4.0537030780372815e-10 - 5.773299834553605e-10*I Use ``numerical_approx`` to get higher precision from symbolic expressions:: - sage: gamma(pi).n(100) + sage: gamma(pi).n(100) # needs sage.symbolic 2.2880377953400324179595889091 - sage: gamma(3/4).n(100) + sage: gamma(3/4).n(100) # needs sage.symbolic 1.2254167024651776451290983034 The precision for the result is also deduced from the precision of the input. Convert the input to a higher precision explicitly if a result with higher precision is desired.:: - sage: t = gamma(RealField(100)(2.5)); t + sage: t = gamma(RealField(100)(2.5)); t # needs sage.rings.real_mpfr 1.3293403881791370204736256125 - sage: t.prec() + sage: t.prec() # needs sage.rings.real_mpfr 100 The gamma function only works with input that can be coerced to the Symbolic Ring:: - sage: Q.<i> = NumberField(x^2+1) - sage: gamma(i) + sage: x = polygen(ZZ, 'x') + sage: Q.<i> = NumberField(x^2 + 1) # needs sage.rings.number_field + sage: gamma(i) # needs sage.rings.number_field sage.symbolic Traceback (most recent call last): ... TypeError: cannot coerce arguments: no canonical coercion from Number Field in i with defining polynomial x^2 + 1 to Symbolic Ring @@ -727,6 +753,7 @@ def _mathematica_gamma3(*args): assert len(args) == 3 return gamma_inc(args[0], args[1]) - gamma_inc(args[0], args[2]) + register_symbol(_mathematica_gamma3, dict(mathematica='Gamma'), 3) @@ -743,37 +770,38 @@ def __init__(self): EXAMPLES:: sage: from sage.functions.gamma import psi1 - sage: psi1(x) + sage: psi1(x) # needs sage.symbolic psi(x) - sage: psi1(x).derivative(x) + sage: psi1(x).derivative(x) # needs sage.symbolic psi(1, x) :: - sage: psi1(3) + sage: psi1(3) # needs sage.symbolic -euler_gamma + 3/2 :: - sage: psi(.5) + sage: psi(.5) # needs sage.symbolic -1.96351002602142 - sage: psi(RealField(100)(.5)) + sage: psi(RealField(100)(.5)) # needs sage.rings.real_mpfr sage.symbolic -1.9635100260214234794409763330 TESTS:: - sage: latex(psi1(x)) + sage: latex(psi1(x)) # needs sage.symbolic \psi\left(x\right) - sage: loads(dumps(psi1(x)+1)) + sage: loads(dumps(psi1(x) + 1)) # needs sage.symbolic psi(x) + 1 + sage: # needs sage.symbolic sage: t = psi1(x); t psi(x) sage: t.subs(x=.2) -5.28903989659219 - sage: psi(x)._sympy_() + sage: psi(x)._sympy_() # needs sympy polygamma(0, x) - sage: psi(x)._fricas_() # optional - fricas + sage: psi(x)._fricas_() # optional - fricas digamma(x) """ GinacFunction.__init__(self, "psi", nargs=1, latex_name=r'\psi', @@ -791,6 +819,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.functions.gamma import psi2 sage: psi2(2, x) psi(2, x) @@ -802,39 +831,40 @@ def __init__(self): :: - sage: psi2(0, x) + sage: psi2(0, x) # needs sage.symbolic psi(x) - sage: psi2(-1, x) + sage: psi2(-1, x) # needs sage.symbolic log(gamma(x)) - sage: psi2(3, 1) + sage: psi2(3, 1) # needs sage.symbolic 1/15*pi^4 :: - sage: psi2(2, .5).n() + sage: psi2(2, .5).n() # needs sage.symbolic -16.8287966442343 - sage: psi2(2, .5).n(100) + sage: psi2(2, .5).n(100) # needs sage.symbolic -16.828796644234319995596334261 TESTS:: - sage: psi2(n, x).derivative(n) + sage: psi2(n, x).derivative(n) # needs sage.symbolic Traceback (most recent call last): ... RuntimeError: cannot diff psi(n,x) with respect to n + sage: # needs sage.symbolic sage: latex(psi2(2,x)) \psi\left(2, x\right) - sage: loads(dumps(psi2(2,x)+1)) + sage: loads(dumps(psi2(2,x) + 1)) psi(2, x) + 1 - sage: psi(2, x)._sympy_() + sage: psi(2, x)._sympy_() # needs sympy polygamma(2, x) - sage: psi(2, x)._fricas_() # optional - fricas + sage: psi(2, x)._fricas_() # optional - fricas polygamma(2,x) Fixed conversion:: - sage: psi(2,x)._maple_init_() + sage: psi(2, x)._maple_init_() # needs sage.symbolic 'Psi(2,x)' """ GinacFunction.__init__(self, "psi", nargs=2, latex_name=r'\psi', @@ -851,9 +881,9 @@ def _maxima_init_evaled_(self, *args): These are indirect doctests for this function.:: sage: from sage.functions.gamma import psi2 - sage: psi2(2, x)._maxima_() + sage: psi2(2, x)._maxima_() # needs sage.symbolic psi[2](_SAGE_VAR_x) - sage: psi2(4, x)._maxima_() + sage: psi2(4, x)._maxima_() # needs sage.symbolic psi[4](_SAGE_VAR_x) """ args_maxima = [] @@ -867,6 +897,7 @@ def _maxima_init_evaled_(self, *args): n, x = args_maxima return "psi[%s](%s)" % (n, x) + psi1 = Function_psi1() psi2 = Function_psi2() @@ -885,6 +916,7 @@ def psi(x, *args, **kwds): EXAMPLES:: + sage: # needs sage.symbolic sage: psi(x) psi(x) sage: psi(.5) @@ -900,14 +932,14 @@ def psi(x, *args, **kwds): :: - sage: psi(3, hold=True) + sage: psi(3, hold=True) # needs sage.symbolic psi(3) - sage: psi(1, 5, hold=True) + sage: psi(1, 5, hold=True) # needs sage.symbolic psi(1, 5) TESTS:: - sage: psi(2, x, 3) + sage: psi(2, x, 3) # needs sage.symbolic Traceback (most recent call last): ... TypeError: Symbolic function psi takes at most 2 arguments (3 given) @@ -918,6 +950,7 @@ def psi(x, *args, **kwds): raise TypeError("Symbolic function psi takes at most 2 arguments (%s given)" % (len(args) + 1)) return psi2(x, args[0], **kwds) + # We have to add the wrapper function manually to the symbol_table when we have # two functions with different number of arguments and the same name symbol_table['functions']['psi'] = psi @@ -926,6 +959,7 @@ def psi(x, *args, **kwds): def _swap_psi(a, b): return psi(b, a) + register_symbol(_swap_psi, {'giac': 'Psi'}, 2) @@ -979,30 +1013,32 @@ def __init__(self): EXAMPLES:: - sage: beta(3,2) + sage: # needs sage.symbolic + sage: beta(3, 2) 1/12 sage: beta(3,1) 1/3 - sage: beta(1/2,1/2) + sage: beta(1/2, 1/2) beta(1/2, 1/2) sage: beta(-1,1) -1 sage: beta(-1/2,-1/2) 0 - sage: ex = beta(x/2,3) + sage: ex = beta(x/2, 3) sage: set(ex.operands()) == set([1/2*x, 3]) True sage: beta(.5,.5) 3.14159265358979 - sage: beta(1,2.0+I) + sage: beta(1, 2.0+I) 0.400000000000000 - 0.200000000000000*I - sage: ex = beta(3,x+I) + sage: ex = beta(3, x+I) sage: set(ex.operands()) == set([x+I, 3]) True The result is symbolic if exact input is given:: - sage: ex = beta(2,1+5*I); ex + sage: # needs sage.symbolic + sage: ex = beta(2, 1+5*I); ex beta(... sage: set(ex.operands()) == set([1+5*I, 2]) True @@ -1015,7 +1051,7 @@ def __init__(self): sage: beta(2., I) -0.500000000000000 - 0.500000000000000*I - sage: beta(x, x)._sympy_() + sage: beta(x, x)._sympy_() # needs sympy sage.symbolic beta(x, x) Test pickling:: @@ -1025,7 +1061,7 @@ def __init__(self): Check that :trac:`15196` is fixed:: - sage: beta(-1.3,-0.4) + sage: beta(-1.3, -0.4) # needs sage.symbolic -4.92909641669610 """ GinacFunction.__init__(self, 'beta', nargs=2, @@ -1041,9 +1077,10 @@ def _method_arguments(self, x, y): r""" TESTS:: - sage: RBF(beta(sin(3),sqrt(RBF(2).add_error(1e-8)/3))) # abs tol 6e-7 + sage: RBF(beta(sin(3), sqrt(RBF(2).add_error(1e-8)/3))) # abs tol 6e-7 # needs sage.libs.flint sage.symbolic [7.407662 +/- 6.17e-7] """ return [x, y] + beta = Function_beta() diff --git a/src/sage/functions/generalized.py b/src/sage/functions/generalized.py index d912ea23719..3d58d4d9d0a 100644 --- a/src/sage/functions/generalized.py +++ b/src/sage/functions/generalized.py @@ -16,28 +16,28 @@ Dirac delta function:: - sage: dirac_delta(x) + sage: dirac_delta(x) # needs sage.symbolic dirac_delta(x) Heaviside step function:: - sage: heaviside(x) + sage: heaviside(x) # needs sage.symbolic heaviside(x) Unit step function:: - sage: unit_step(x) + sage: unit_step(x) # needs sage.symbolic unit_step(x) Signum (sgn) function:: - sage: sgn(x) + sage: sgn(x) # needs sage.symbolic sgn(x) Kronecker delta function:: - sage: m,n=var('m,n') - sage: kronecker_delta(m,n) + sage: m, n = var('m,n') # needs sage.symbolic + sage: kronecker_delta(m, n) # needs sage.symbolic kronecker_delta(m, n) """ @@ -51,9 +51,12 @@ # ############################################################################## -from sage.symbolic.function import (BuiltinFunction, GinacFunction) -from sage.rings.complex_interval_field import ComplexIntervalField +from sage.misc.lazy_import import lazy_import from sage.rings.integer_ring import ZZ +from sage.symbolic.function import BuiltinFunction, GinacFunction + +lazy_import('sage.misc.latex', 'latex') +lazy_import('sage.rings.complex_interval_field', 'ComplexIntervalField') class FunctionDiracDelta(BuiltinFunction): @@ -78,13 +81,14 @@ class FunctionDiracDelta(BuiltinFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: dirac_delta(1) 0 sage: dirac_delta(0) dirac_delta(0) sage: dirac_delta(x) dirac_delta(x) - sage: integrate(dirac_delta(x), x, -1, 1, algorithm='sympy') + sage: integrate(dirac_delta(x), x, -1, 1, algorithm='sympy') # needs sympy 1 REFERENCES: @@ -102,6 +106,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: dirac_delta(1) 0 sage: dirac_delta(0) @@ -111,9 +116,9 @@ def __init__(self): sage: latex(dirac_delta(x)) \delta\left(x\right) - sage: loads(dumps(dirac_delta(x))) + sage: loads(dumps(dirac_delta(x))) # needs sage.symbolic dirac_delta(x) - sage: dirac_delta(x)._sympy_() + sage: dirac_delta(x)._sympy_() # needs sympy sage.symbolic DiracDelta(x) """ BuiltinFunction.__init__(self, "dirac_delta", latex_name=r"\delta", @@ -130,6 +135,7 @@ def _eval_(self, x): EXAMPLES:: + sage: # needs sage.symbolic sage: dirac_delta(1) 0 sage: dirac_delta(0) @@ -141,7 +147,7 @@ def _eval_(self, x): Evaluation test:: - sage: dirac_delta(x).subs(x=1) + sage: dirac_delta(x).subs(x=1) # needs sage.symbolic 0 """ try: @@ -154,8 +160,8 @@ def _evalf_(self, x, **kwds): """ TESTS:: - sage: h(x) = dirac_delta(x) - sage: h(pi).numerical_approx() + sage: h(x) = dirac_delta(x) # needs sage.symbolic + sage: h(pi).numerical_approx() # needs sage.symbolic 0.000000000000000 """ approx_x = ComplexIntervalField()(x) @@ -188,6 +194,7 @@ class FunctionHeaviside(GinacFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: heaviside(-1) 0 sage: heaviside(1) @@ -197,23 +204,24 @@ class FunctionHeaviside(GinacFunction): sage: heaviside(x) heaviside(x) - sage: heaviside(-1/2) + sage: heaviside(-1/2) # needs sage.symbolic 0 - sage: heaviside(exp(-1000000000000000000000)) + sage: heaviside(exp(-1000000000000000000000)) # needs sage.symbolic 1 TESTS:: - sage: heaviside(x)._sympy_() + sage: heaviside(x)._sympy_() # needs sympy sage.symbolic Heaviside(x) - sage: heaviside(x).subs(x=1) + sage: heaviside(x).subs(x=1) # needs sage.symbolic 1 - sage: heaviside(x).subs(x=-1) + sage: heaviside(x).subs(x=-1) # needs sage.symbolic 0 :: - sage: ex = heaviside(x)+1 + sage: # needs sage.symbolic + sage: ex = heaviside(x) + 1 sage: t = loads(dumps(ex)); t heaviside(x) + 1 sage: bool(t == ex) @@ -236,6 +244,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: heaviside(-1) 0 sage: heaviside(1) @@ -246,9 +255,9 @@ def __init__(self): heaviside(x) sage: latex(heaviside(x)) H\left(x\right) - sage: heaviside(x)._sympy_() + sage: heaviside(x)._sympy_() # needs sympy Heaviside(x) - sage: heaviside(x)._giac_() + sage: heaviside(x)._giac_() # needs sage.libs.giac Heaviside(sageVARx) sage: h(x) = heaviside(x) sage: h(pi).numerical_approx() @@ -266,7 +275,7 @@ def _derivative_(self, x, diff_param=None): EXAMPLES:: - sage: heaviside(x).diff(x) + sage: heaviside(x).diff(x) # needs sage.symbolic dirac_delta(x) """ return dirac_delta(x) @@ -293,6 +302,7 @@ class FunctionUnitStep(GinacFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: unit_step(-1) 0 sage: unit_step(1) @@ -306,6 +316,7 @@ class FunctionUnitStep(GinacFunction): TESTS:: + sage: # needs sage.symbolic sage: unit_step(x).subs(x=1) 1 sage: unit_step(x).subs(x=0) @@ -324,6 +335,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: unit_step(-1) 0 sage: unit_step(1) @@ -337,9 +349,9 @@ def __init__(self): TESTS:: - sage: t = loads(dumps(unit_step(x)+1)); t + sage: t = loads(dumps(unit_step(x) + 1)); t # needs sage.symbolic unit_step(x) + 1 - sage: t.subs(x=0) + sage: t.subs(x=0) # needs sage.symbolic 2 """ GinacFunction.__init__(self, "unit_step", latex_name=r"\mathrm{u}", @@ -351,7 +363,7 @@ def _derivative_(self, x, diff_param=None): EXAMPLES:: - sage: unit_step(x).diff(x) + sage: unit_step(x).diff(x) # needs sage.symbolic dirac_delta(x) """ return dirac_delta(x) @@ -384,7 +396,7 @@ class FunctionSignum(BuiltinFunction): 1 sage: sgn(0) 0 - sage: sgn(x) + sage: sgn(x) # needs sage.symbolic sgn(x) We can also use ``sign``:: @@ -393,24 +405,24 @@ class FunctionSignum(BuiltinFunction): 1 sage: sign(0) 0 - sage: a = AA(-5).nth_root(7) - sage: sign(a) + sage: a = AA(-5).nth_root(7) # needs sage.rings.number_field + sage: sign(a) # needs sage.rings.number_field -1 TESTS: Check if conversions to sympy and others work (:trac:`11921`):: - sage: sgn(x)._sympy_() + sage: sgn(x)._sympy_() # needs sympy sage.symbolic sign(x) - sage: sgn(x)._fricas_init_() + sage: sgn(x)._fricas_init_() # needs sage.symbolic '(x+->abs(x)/x)(x)' - sage: sgn(x)._giac_() + sage: sgn(x)._giac_() # needs sage.libs.giac sage.symbolic sign(sageVARx) Test for :trac:`31085`:: - sage: fricas(sign(x)).eval(x=-3) # optional - fricas + sage: fricas(sign(x)).eval(x=-3) # optional - fricas # needs sage.symbolic - 1 REFERENCES: @@ -430,9 +442,9 @@ def __init__(self): 1 sage: sgn(0) 0 - sage: sgn(x) + sage: sgn(x) # needs sage.symbolic sgn(x) - sage: sgn(x)._sympy_() + sage: sgn(x)._sympy_() # needs sympy sage.symbolic sign(x) """ BuiltinFunction.__init__(self, "sgn", latex_name=r"\mathrm{sgn}", @@ -452,18 +464,18 @@ def _eval_(self, x): 1 sage: sgn(0) 0 - sage: sgn(x) + sage: sgn(x) # needs sage.symbolic sgn(x) - sage: sgn(-exp(-10000000000000000000)) + sage: sgn(-exp(-10000000000000000000)) # needs sage.symbolic -1 Evaluation test:: - sage: sgn(x).subs(x=1) + sage: sgn(x).subs(x=1) # needs sage.symbolic 1 - sage: sgn(x).subs(x=0) + sage: sgn(x).subs(x=0) # needs sage.symbolic 0 - sage: sgn(x).subs(x=-1) + sage: sgn(x).subs(x=-1) # needs sage.symbolic -1 More tests:: @@ -472,9 +484,9 @@ def _eval_(self, x): 1 sage: sign(RDF(2)) 1 - sage: sign(AA(-2)) + sage: sign(AA(-2)) # needs sage.rings.number_field -1 - sage: sign(AA(0)) + sage: sign(AA(0)) # needs sage.rings.number_field 0 """ try: @@ -489,6 +501,7 @@ def _evalf_(self, x, **kwds): Check that :trac:`16587` is fixed:: + sage: # needs sage.symbolic sage: M = sgn(3/2, hold=True); M sgn(3/2) sage: M.n() @@ -518,7 +531,7 @@ def _derivative_(self, x, diff_param=None): EXAMPLES:: - sage: sgn(x).diff(x) + sage: sgn(x).diff(x) # needs sage.symbolic 2*dirac_delta(x) """ assert diff_param == 0 @@ -547,12 +560,12 @@ class FunctionKroneckerDelta(BuiltinFunction): EXAMPLES:: - sage: kronecker_delta(1,2) + sage: kronecker_delta(1,2) # needs sage.rings.complex_interval_field 0 - sage: kronecker_delta(1,1) + sage: kronecker_delta(1,1) # needs sage.rings.complex_interval_field 1 - sage: m,n=var('m,n') - sage: kronecker_delta(m,n) + sage: m, n = var('m,n') # needs sage.symbolic + sage: kronecker_delta(m, n) # needs sage.symbolic kronecker_delta(m, n) REFERENCES: @@ -566,12 +579,12 @@ def __init__(self): EXAMPLES:: - sage: kronecker_delta(1,2) + sage: kronecker_delta(1,2) # needs sage.rings.complex_interval_field 0 - sage: kronecker_delta(1,1) + sage: kronecker_delta(1,1) # needs sage.rings.complex_interval_field 1 - sage: y = var('y') - sage: kronecker_delta(x, y)._sympy_() + sage: y = var('y') # needs sage.symbolic + sage: kronecker_delta(x, y)._sympy_() # needs sympy sage.symbolic KroneckerDelta(x, y) """ BuiltinFunction.__init__(self, "kronecker_delta", nargs=2, @@ -585,25 +598,26 @@ def _eval_(self, m, n): EXAMPLES:: - sage: kronecker_delta(1,2) + sage: kronecker_delta(1,2) # needs sage.rings.complex_interval_field 0 - sage: kronecker_delta(1,1) + sage: kronecker_delta(1,1) # needs sage.rings.complex_interval_field 1 Kronecker delta is a symmetric function. We keep arguments sorted to ensure that k_d(m, n) - k_d(n, m) cancels automatically:: - sage: x,y = var('x,y') + sage: # needs sage.symbolic + sage: x, y = var('x,y') sage: kronecker_delta(x, y) kronecker_delta(x, y) sage: kronecker_delta(y, x) kronecker_delta(x, y) - sage: kronecker_delta(x,2*x) + sage: kronecker_delta(x, 2*x) kronecker_delta(2*x, x) Evaluation test:: - sage: kronecker_delta(1,x).subs(x=1) + sage: kronecker_delta(1, x).subs(x=1) # needs sage.symbolic 1 """ try: @@ -616,8 +630,8 @@ def _evalf_(self, m, n, **kwds): """ TESTS:: - sage: h(x) = kronecker_delta(3,x) - sage: h(pi).numerical_approx() + sage: h(x) = kronecker_delta(3, x) # needs sage.symbolic + sage: h(pi).numerical_approx() # needs sage.symbolic 0.000000000000000 """ if bool(repr(m) > repr(n)): @@ -637,7 +651,7 @@ def _derivative_(self, *args, **kwds): EXAMPLES:: - sage: kronecker_delta(x,1).diff(x) + sage: kronecker_delta(x, 1).diff(x) # needs sage.symbolic 0 """ # Kronecker delta is non-zero (but finite) only in the set of @@ -653,11 +667,10 @@ def _print_latex_(self, m, n, **kwds): EXAMPLES:: sage: from sage.misc.latex import latex - sage: m,n=var('m,n') - sage: latex(kronecker_delta(m,n)) + sage: m, n = var('m,n') # needs sage.symbolic + sage: latex(kronecker_delta(m, n)) # needs sage.symbolic \delta_{m,n} """ - from sage.misc.latex import latex return r"\delta_{%s,%s}" % (latex(m), latex(n)) diff --git a/src/sage/functions/hyperbolic.py b/src/sage/functions/hyperbolic.py index 9a362b8882f..6c70caef310 100644 --- a/src/sage/functions/hyperbolic.py +++ b/src/sage/functions/hyperbolic.py @@ -28,16 +28,15 @@ Inverse hyperbolic functions have logarithmic expressions, so expressions of the form ``exp(c*f(x))`` simplify:: + sage: # needs sage.symbolic sage: exp(2*atanh(x)) -(x + 1)/(x - 1) sage: exp(2*acoth(x)) (x + 1)/(x - 1) - sage: exp(2*asinh(x)) (x + sqrt(x^2 + 1))^2 sage: exp(2*acosh(x)) (x + sqrt(x^2 - 1))^2 - sage: exp(2*asech(x)) (sqrt(-x^2 + 1)/x + 1/x)^2 sage: exp(2*acsch(x)) @@ -54,28 +53,29 @@ def __init__(self): EXAMPLES:: - sage: sinh(pi) - sinh(pi) sage: sinh(3.1415) 11.5476653707437 + + sage: # needs sage.symbolic + sage: sinh(pi) + sinh(pi) sage: float(sinh(pi)) 11.54873935725774... sage: RR(sinh(pi)) 11.5487393572577 - sage: latex(sinh(x)) \sinh\left(x\right) - sage: sinh(x)._sympy_() + sage: sinh(x)._sympy_() # needs sympy sinh(x) To prevent automatic evaluation, use the ``hold`` parameter:: - sage: sinh(arccosh(x),hold=True) + sage: sinh(arccosh(x), hold=True) # needs sage.symbolic sinh(arccosh(x)) To then evaluate again, use the ``unhold`` method:: - sage: sinh(arccosh(x),hold=True).unhold() + sage: sinh(arccosh(x), hold=True).unhold() # needs sage.symbolic sqrt(x + 1)*sqrt(x - 1) """ GinacFunction.__init__(self, "sinh", latex_name=r"\sinh") @@ -91,28 +91,29 @@ def __init__(self): EXAMPLES:: - sage: cosh(pi) - cosh(pi) sage: cosh(3.1415) 11.5908832931176 + + sage: # needs sage.symbolic + sage: cosh(pi) + cosh(pi) sage: float(cosh(pi)) 11.591953275521519 sage: RR(cosh(1/2)) 1.12762596520638 - sage: latex(cosh(x)) \cosh\left(x\right) - sage: cosh(x)._sympy_() + sage: cosh(x)._sympy_() # needs sympy cosh(x) To prevent automatic evaluation, use the ``hold`` parameter:: - sage: cosh(arcsinh(x),hold=True) + sage: cosh(arcsinh(x), hold=True) # needs sage.symbolic cosh(arcsinh(x)) To then evaluate again, use the ``unhold`` method:: - sage: cosh(arcsinh(x),hold=True).unhold() + sage: cosh(arcsinh(x), hold=True).unhold() # needs sage.symbolic sqrt(x^2 + 1) """ GinacFunction.__init__(self, "cosh", latex_name=r"\cosh") @@ -128,14 +129,16 @@ def __init__(self): EXAMPLES:: - sage: tanh(pi) - tanh(pi) sage: tanh(3.1415) 0.996271386633702 - sage: float(tanh(pi)) - 0.99627207622075 sage: tan(3.1415/4) 0.999953674278156 + + sage: # needs sage.symbolic + sage: tanh(pi) + tanh(pi) + sage: float(tanh(pi)) + 0.99627207622075 sage: tanh(pi/4) tanh(1/4*pi) sage: RR(tanh(1/2)) @@ -143,32 +146,33 @@ def __init__(self): :: - sage: CC(tanh(pi + I*e)) + sage: CC(tanh(pi + I*e)) # needs sage.rings.real_mpfr sage.symbolic 0.997524731976164 - 0.00279068768100315*I - sage: ComplexField(100)(tanh(pi + I*e)) + sage: ComplexField(100)(tanh(pi + I*e)) # needs sage.rings.real_mpfr sage.symbolic 0.99752473197616361034204366446 - 0.0027906876810031453884245163923*I - sage: CDF(tanh(pi + I*e)) # rel tol 2e-15 + sage: CDF(tanh(pi + I*e)) # rel tol 2e-15 # needs sage.rings.complex_double sage.symbolic 0.9975247319761636 - 0.002790687681003147*I To prevent automatic evaluation, use the ``hold`` parameter:: - sage: tanh(arcsinh(x),hold=True) + sage: tanh(arcsinh(x), hold=True) # needs sage.symbolic tanh(arcsinh(x)) To then evaluate again, use the ``unhold`` method:: - sage: tanh(arcsinh(x),hold=True).unhold() + sage: tanh(arcsinh(x), hold=True).unhold() # needs sage.symbolic x/sqrt(x^2 + 1) TESTS:: - sage: latex(tanh(x)) + sage: latex(tanh(x)) # needs sage.symbolic \tanh\left(x\right) - sage: tanh(x)._sympy_() + sage: tanh(x)._sympy_() # needs sympy sage.symbolic tanh(x) Check that real/imaginary parts are correct (:trac:`20098`):: + sage: # needs sage.symbolic sage: tanh(1+2*I).n() 1.16673625724092 - 0.243458201185725*I sage: tanh(1+2*I).real().n() @@ -193,6 +197,12 @@ def __init__(self): EXAMPLES:: + sage: coth(3.1415) + 1.00374256795520 + sage: coth(complex(1, 2)) # abs tol 1e-15 # needs sage.rings.complex_double + (0.8213297974938518+0.17138361290918508j) + + sage: # needs sage.symbolic sage: coth(pi) coth(pi) sage: coth(0) @@ -207,22 +217,19 @@ def __init__(self): Infinity sage: coth(7.*pi*I/2) -I*cot(3.50000000000000*pi) - sage: coth(3.1415) - 1.00374256795520 sage: float(coth(pi)) 1.0037418731973213 sage: RR(coth(pi)) 1.00374187319732 - sage: coth(complex(1, 2)) # abs tol 1e-15 - (0.8213297974938518+0.17138361290918508j) + sage: # needs sage.symbolic sage: bool(diff(coth(x), x) == diff(1/tanh(x), x)) True sage: diff(coth(x), x) -1/sinh(x)^2 sage: latex(coth(x)) \coth\left(x\right) - sage: coth(x)._sympy_() + sage: coth(x)._sympy_() # needs sympy coth(x) """ GinacFunction.__init__(self, "coth", latex_name=r"\coth") @@ -231,9 +238,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.arange(2, 5) - sage: coth(a) + sage: import numpy # needs numpy + sage: a = numpy.arange(2, 5) # needs numpy + sage: coth(a) # needs numpy array([1.03731472, 1.00496982, 1.00067115]) """ return 1.0 / tanh(x) @@ -249,10 +256,12 @@ def __init__(self): EXAMPLES:: - sage: sech(pi) - sech(pi) sage: sech(3.1415) 0.0862747018248192 + + sage: # needs sage.symbolic + sage: sech(pi) + sech(pi) sage: float(sech(pi)) 0.0862667383340544... sage: RR(sech(pi)) @@ -270,13 +279,14 @@ def __init__(self): sage: sech(8.*pi*I/2) sec(4.00000000000000*pi) + sage: # needs sage.symbolic sage: bool(diff(sech(x), x) == diff(1/cosh(x), x)) True sage: diff(sech(x), x) -sech(x)*tanh(x) sage: latex(sech(x)) \operatorname{sech}\left(x\right) - sage: sech(x)._sympy_() + sage: sech(x)._sympy_() # needs sympy sech(x) """ GinacFunction.__init__(self, "sech", latex_name=r"\operatorname{sech}",) @@ -285,9 +295,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.arange(2, 5) - sage: sech(a) + sage: import numpy # needs numpy + sage: a = numpy.arange(2, 5) # needs numpy + sage: sech(a) # needs numpy array([0.26580223, 0.09932793, 0.03661899]) """ return 1.0 / cosh(x) @@ -303,10 +313,12 @@ def __init__(self): EXAMPLES:: - sage: csch(pi) - csch(pi) sage: csch(3.1415) 0.0865975907592133 + + sage: # needs sage.symbolic + sage: csch(pi) + csch(pi) sage: float(csch(pi)) 0.0865895375300469... sage: RR(csch(pi)) @@ -322,13 +334,14 @@ def __init__(self): sage: csch(7.*pi*I/2) -I*csc(3.50000000000000*pi) + sage: # needs sage.symbolic sage: bool(diff(csch(x), x) == diff(1/sinh(x), x)) True sage: diff(csch(x), x) -coth(x)*csch(x) sage: latex(csch(x)) \operatorname{csch}\left(x\right) - sage: csch(x)._sympy_() + sage: csch(x)._sympy_() # needs sympy csch(x) """ GinacFunction.__init__(self, "csch", latex_name=r"\operatorname{csch}") @@ -337,9 +350,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.arange(2, 5) - sage: csch(a) + sage: import numpy # needs numpy + sage: a = numpy.arange(2, 5) # needs numpy + sage: csch(a) # needs numpy array([0.27572056, 0.09982157, 0.03664357]) """ return 1.0 / sinh(x) @@ -364,24 +377,25 @@ def __init__(self): arcsinh sage: asinh(0.5) 0.481211825059603 - sage: asinh(1/2) + sage: asinh(1/2) # needs sage.symbolic arcsinh(1/2) - sage: asinh(1 + I*1.0) + sage: asinh(1 + I*1.0) # needs sage.symbolic 1.06127506190504 + 0.666239432492515*I To prevent automatic evaluation use the ``hold`` argument:: - sage: asinh(-2,hold=True) + sage: asinh(-2, hold=True) # needs sage.symbolic arcsinh(-2) To then evaluate again, use the ``unhold`` method:: - sage: asinh(-2,hold=True).unhold() + sage: asinh(-2, hold=True).unhold() # needs sage.symbolic -arcsinh(2) ``conjugate(asinh(x))==asinh(conjugate(x))`` unless on the branch cuts which run along the imaginary axis outside the interval [-I, +I].:: + sage: # needs sage.symbolic sage: conjugate(asinh(x)) conjugate(arcsinh(x)) sage: var('y', domain='positive') @@ -399,11 +413,11 @@ def __init__(self): TESTS:: - sage: asinh(x).operator() + sage: asinh(x).operator() # needs sage.symbolic arcsinh - sage: latex(asinh(x)) + sage: latex(asinh(x)) # needs sage.symbolic \operatorname{arsinh}\left(x\right) - sage: asinh(x)._sympy_() + sage: asinh(x)._sympy_() # needs sympy sage.symbolic asinh(x) """ GinacFunction.__init__(self, "arcsinh", @@ -422,6 +436,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: acosh(1/2) arccosh(1/2) sage: acosh(1 + I*1.0) @@ -430,7 +445,8 @@ def __init__(self): 1.3169578969248168 sage: cosh(float(acosh(2))) 2.0 - sage: acosh(complex(1, 2)) # abs tol 1e-15 + + sage: acosh(complex(1, 2)) # abs tol 1e-15 # needs sage.rings.complex_double (1.5285709194809982+1.1437177404024204j) .. warning:: @@ -442,14 +458,16 @@ def __init__(self): :: + sage: acosh(CC(0.5)) # needs sage.rings.real_mpfr + 1.04719755119660*I + + sage: # needs sage.symbolic sage: acosh(0.5) NaN sage: acosh(1/2) arccosh(1/2) sage: acosh(1/2).n() NaN - sage: acosh(CC(0.5)) - 1.04719755119660*I sage: acosh(0) 1/2*I*pi sage: acosh(-1) @@ -457,17 +475,18 @@ def __init__(self): To prevent automatic evaluation use the ``hold`` argument:: - sage: acosh(-1,hold=True) + sage: acosh(-1, hold=True) # needs sage.symbolic arccosh(-1) To then evaluate again, use the ``unhold`` method:: - sage: acosh(-1,hold=True).unhold() + sage: acosh(-1, hold=True).unhold() # needs sage.symbolic I*pi ``conjugate(arccosh(x))==arccosh(conjugate(x))`` unless on the branch cut which runs along the real axis from +1 to -inf.:: + sage: # needs sage.symbolic sage: conjugate(acosh(x)) conjugate(arccosh(x)) sage: var('y', domain='positive') @@ -485,11 +504,11 @@ def __init__(self): TESTS:: - sage: acosh(x).operator() + sage: acosh(x).operator() # needs sage.symbolic arccosh - sage: latex(acosh(x)) + sage: latex(acosh(x)) # needs sage.symbolic \operatorname{arcosh}\left(x\right) - sage: acosh(x)._sympy_() + sage: acosh(x)._sympy_() # needs sympy sage.symbolic acosh(x) """ GinacFunction.__init__(self, "arccosh", @@ -510,31 +529,32 @@ def __init__(self): sage: atanh(0.5) 0.549306144334055 - sage: atanh(1/2) + sage: atanh(1/2) # needs sage.symbolic 1/2*log(3) - sage: atanh(1 + I*1.0) + sage: atanh(1 + I*1.0) # needs sage.symbolic 0.402359478108525 + 1.01722196789785*I To prevent automatic evaluation use the ``hold`` argument:: - sage: atanh(-1/2,hold=True) + sage: atanh(-1/2, hold=True) # needs sage.symbolic arctanh(-1/2) To then evaluate again, use the ``unhold`` method:: - sage: atanh(-1/2,hold=True).unhold() + sage: atanh(-1/2, hold=True).unhold() # needs sage.symbolic -1/2*log(3) ``conjugate(arctanh(x)) == arctanh(conjugate(x))`` unless on the branch cuts which run along the real axis outside the interval [-1, +1]. :: + sage: # needs sage.symbolic sage: conjugate(atanh(x)) conjugate(arctanh(x)) sage: var('y', domain='positive') y sage: conjugate(atanh(y)) conjugate(arctanh(y)) - sage: conjugate(atanh(y+I)) + sage: conjugate(atanh(y + I)) conjugate(arctanh(y + I)) sage: conjugate(atanh(1/16)) 1/2*log(17/15) @@ -545,11 +565,11 @@ def __init__(self): TESTS:: - sage: atanh(x).operator() + sage: atanh(x).operator() # needs sage.symbolic arctanh - sage: latex(atanh(x)) + sage: latex(atanh(x)) # needs sage.symbolic \operatorname{artanh}\left(x\right) - sage: atanh(x)._sympy_() + sage: atanh(x)._sympy_() # needs sympy sage.symbolic atanh(x) """ GinacFunction.__init__(self, "arctanh", @@ -568,6 +588,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: acoth(2.0) 0.549306144334055 sage: acoth(2) @@ -577,28 +598,28 @@ def __init__(self): sage: acoth(2).n(200) 0.54930614433405484569762261846126285232374527891137472586735 - sage: bool(diff(acoth(x), x) == diff(atanh(x), x)) + sage: bool(diff(acoth(x), x) == diff(atanh(x), x)) # needs sage.symbolic True - sage: diff(acoth(x), x) + sage: diff(acoth(x), x) # needs sage.symbolic -1/(x^2 - 1) - sage: float(acoth(2)) + sage: float(acoth(2)) # needs sage.symbolic 0.5493061443340549 - sage: float(acoth(2).n(53)) # Correct result to 53 bits + sage: float(acoth(2).n(53)) # Correct result to 53 bits # needs sage.rings.real_mpfr sage.symbolic 0.5493061443340549 - sage: float(acoth(2).n(100)) # Compute 100 bits and then round to 53 + sage: float(acoth(2).n(100)) # Compute 100 bits and then round to 53 # needs sage.rings.real_mpfr sage.symbolic 0.5493061443340549 TESTS:: - sage: latex(acoth(x)) + sage: latex(acoth(x)) # needs sage.symbolic \operatorname{arcoth}\left(x\right) - sage: acoth(x)._sympy_() + sage: acoth(x)._sympy_() # needs sympy sage.symbolic acoth(x) Check that :trac:`23636` is fixed:: - sage: acoth(float(1.1)) + sage: acoth(float(1.1)) # needs sage.symbolic 1.5222612188617113 """ GinacFunction.__init__(self, "arccoth", @@ -611,9 +632,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.arange(2,5) - sage: acoth(a) + sage: import numpy # needs numpy + sage: a = numpy.arange(2,5) # needs numpy + sage: acoth(a) # needs numpy array([0.54930614, 0.34657359, 0.25541281]) """ return arctanh(1.0 / x) @@ -629,6 +650,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: asech(0.5) 1.31695789692482 sage: asech(1/2) @@ -640,11 +662,11 @@ def __init__(self): sage: float(asech(1/2)) 1.3169578969248168 - sage: diff(asech(x), x) + sage: diff(asech(x), x) # needs sage.symbolic -1/(sqrt(-x^2 + 1)*x) - sage: latex(asech(x)) + sage: latex(asech(x)) # needs sage.symbolic \operatorname{arsech}\left(x\right) - sage: asech(x)._sympy_() + sage: asech(x)._sympy_() # needs sympy sage.symbolic asech(x) """ GinacFunction.__init__(self, "arcsech", @@ -657,9 +679,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.linspace(0,1,3) - sage: asech(a) + sage: import numpy # needs numpy + sage: a = numpy.linspace(0,1,3) # needs numpy + sage: asech(a) # needs numpy doctest:...: RuntimeWarning: divide by zero encountered in ...divide array([ inf, 1.3169579, 0. ]) """ @@ -676,6 +698,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: acsch(2.0) 0.481211825059603 sage: acsch(2) @@ -687,18 +710,18 @@ def __init__(self): sage: float(acsch(1)) 0.881373587019543 - sage: diff(acsch(x), x) + sage: diff(acsch(x), x) # needs sage.symbolic -1/(sqrt(x^2 + 1)*x) - sage: latex(acsch(x)) + sage: latex(acsch(x)) # needs sage.symbolic \operatorname{arcsch}\left(x\right) TESTS: Check that :trac:`20818` is fixed:: - sage: acsch(float(0.1)) + sage: acsch(float(0.1)) # needs sage.symbolic 2.99822295029797 - sage: acsch(x)._sympy_() + sage: acsch(x)._sympy_() # needs sympy sage.symbolic acsch(x) """ GinacFunction.__init__(self, "arccsch", @@ -711,9 +734,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.linspace(0,1,3) - sage: acsch(a) + sage: import numpy # needs numpy + sage: a = numpy.linspace(0,1,3) # needs numpy + sage: acsch(a) # needs numpy doctest:...: RuntimeWarning: divide by zero encountered in ...divide array([ inf, 1.44363548, 0.88137359]) """ diff --git a/src/sage/functions/hypergeometric.py b/src/sage/functions/hypergeometric.py index 50c60b25638..1c2712382f3 100644 --- a/src/sage/functions/hypergeometric.py +++ b/src/sage/functions/hypergeometric.py @@ -19,8 +19,11 @@ sage: sum(((2*I)^x/(x^3 + 1)*(1/4)^x), x, 0, oo) hypergeometric((1, 1, -1/2*I*sqrt(3) - 1/2, 1/2*I*sqrt(3) - 1/2),... (2, -1/2*I*sqrt(3) + 1/2, 1/2*I*sqrt(3) + 1/2), 1/2*I) - sage: sum((-1)^x/((2*x + 1)*factorial(2*x + 1)), x, 0, oo) + sage: res = sum((-1)^x/((2*x + 1)*factorial(2*x + 1)), x, 0, oo) + sage: res # not tested - depends on maxima version hypergeometric((1/2,), (3/2, 3/2), -1/4) + sage: res in [hypergeometric((1/2,), (3/2, 3/2), -1/4), sin_integral(1)] + True Simplification (note that ``simplify_full`` does not yet call ``simplify_hypergeometric``):: @@ -46,6 +49,7 @@ Computing terms and series:: + sage: # needs sage.symbolic sage: var('z') z sage: hypergeometric([], [], z).series(z, 0) @@ -57,6 +61,7 @@ sage: hypergeometric([], [], z).series(z, 3) 1 + 1*z + 1/2*z^2 + Order(z^3) + sage: # needs sage.symbolic sage: hypergeometric([-2], [], z).series(z, 3) 1 + (-2)*z + 1*z^2 sage: hypergeometric([-2], [], z).series(z, 6) @@ -68,26 +73,27 @@ sage: hypergeometric([-2], [], z).series(z, 2).is_terminating_series() False - sage: hypergeometric([1], [], z).series(z, 6) + sage: hypergeometric([1], [], z).series(z, 6) # needs sage.symbolic 1 + 1*z + 1*z^2 + 1*z^3 + 1*z^4 + 1*z^5 + Order(z^6) - sage: hypergeometric([], [1/2], -z^2/4).series(z, 11) + sage: hypergeometric([], [1/2], -z^2/4).series(z, 11) # needs sage.symbolic 1 + (-1/2)*z^2 + 1/24*z^4 + (-1/720)*z^6 + 1/40320*z^8 +... (-1/3628800)*z^10 + Order(z^11) sage: hypergeometric([1], [5], x).series(x, 5) 1 + 1/5*x + 1/30*x^2 + 1/210*x^3 + 1/1680*x^4 + Order(x^5) - sage: sum(hypergeometric([1, 2], [3], 1/3).terms(6)).n() + sage: sum(hypergeometric([1, 2], [3], 1/3).terms(6)).n() # needs sage.symbolic 1.29788359788360 - sage: hypergeometric([1, 2], [3], 1/3).n() + sage: hypergeometric([1, 2], [3], 1/3).n() # needs sage.symbolic 1.29837194594696 sage: hypergeometric([], [], x).series(x, 20)(x=1).n() == e.n() True Plotting:: + sage: # needs sage.symbolic sage: f(x) = hypergeometric([1, 1], [3, 3, 3], x) - sage: plot(f, x, -30, 30) + sage: plot(f, x, -30, 30) # needs sage.plot Graphics object consisting of 1 graphics primitive sage: g(x) = hypergeometric([x], [], 2) sage: complex_plot(g, (-1, 1), (-1, 1)) @@ -95,6 +101,7 @@ Numeric evaluation:: + sage: # needs sage.symbolic sage: hypergeometric([1], [], 1/10).n() # geometric series 1.11111111111111 sage: hypergeometric([], [], 1).n() # e @@ -112,42 +119,42 @@ Conversions:: - sage: maxima(hypergeometric([1, 1, 1], [3, 3, 3], x)) + sage: maxima(hypergeometric([1, 1, 1], [3, 3, 3], x)) # needs sage.symbolic hypergeometric([1,1,1],[3,3,3],_SAGE_VAR_x) - sage: hypergeometric((5, 4), (4, 4), 3)._sympy_() + sage: hypergeometric((5, 4), (4, 4), 3)._sympy_() # needs sage.symbolic hyper((5, 4), (4, 4), 3) - sage: hypergeometric((5, 4), (4, 4), 3)._mathematica_init_() + sage: hypergeometric((5, 4), (4, 4), 3)._mathematica_init_() # needs sage.symbolic 'HypergeometricPFQ[{5,4},{4,4},3]' Arbitrary level of nesting for conversions:: - sage: maxima(nest(lambda y: hypergeometric([y], [], x), 3, 1)) + sage: maxima(nest(lambda y: hypergeometric([y], [], x), 3, 1)) # needs sage.symbolic 1/(1-_SAGE_VAR_x)^(1/(1-_SAGE_VAR_x)^(1/(1-_SAGE_VAR_x))) - sage: maxima(nest(lambda y: hypergeometric([y], [3], x), 3, 1))._sage_() + sage: maxima(nest(lambda y: hypergeometric([y], [3], x), 3, 1))._sage_() # needs sage.symbolic hypergeometric((hypergeometric((hypergeometric((1,), (3,), x),), (3,),... x),), (3,), x) - sage: nest(lambda y: hypergeometric([y], [], x), 3, 1)._mathematica_init_() + sage: nest(lambda y: hypergeometric([y], [], x), 3, 1)._mathematica_init_() # needs sage.symbolic 'HypergeometricPFQ[{HypergeometricPFQ[{HypergeometricPFQ[{1},{},x]},... The confluent hypergeometric functions can arise as solutions to second-order differential equations (example from `here <http://ask.sagemath.org/question/ 1168/how-can-one-use-maxima-kummer-confluent-functions>`_):: - sage: var('m') + sage: var('m') # needs sage.symbolic m - sage: y = function('y')(x) - sage: desolve(diff(y, x, 2) + 2*x*diff(y, x) - 4*m*y, y, + sage: y = function('y')(x) # needs sage.symbolic + sage: desolve(diff(y, x, 2) + 2*x*diff(y, x) - 4*m*y, y, # needs sage.symbolic ....: contrib_ode=true, ivar=x) [y(x) == _K1*hypergeometric_M(-m, 1/2, -x^2) +... _K2*hypergeometric_U(-m, 1/2, -x^2)] Series expansions of confluent hypergeometric functions:: - sage: hypergeometric_M(2, 2, x).series(x, 3) + sage: hypergeometric_M(2, 2, x).series(x, 3) # needs sage.symbolic 1 + 1*x + 1/2*x^2 + Order(x^3) - sage: hypergeometric_U(2, 2, x).series(x == 3, 100).subs(x=1).n() + sage: hypergeometric_U(2, 2, x).series(x == 3, 100).subs(x=1).n() # needs sage.symbolic 0.403652637676806 - sage: hypergeometric_U(2, 2, 1).n() + sage: hypergeometric_U(2, 2, 1).n() # needs mpmath 0.403652637676806 """ @@ -162,27 +169,33 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from functools import reduce + +from sage.arith.misc import binomial, factorial, rising_factorial +from sage.calculus.functional import derivative +from sage.functions.error import erf +from sage.functions.gamma import gamma +from sage.functions.hyperbolic import cosh, sinh +from sage.functions.log import exp, log +from sage.functions.other import sqrt, real_part +from sage.misc.lazy_import import lazy_import +from sage.misc.misc_c import prod +from sage.rings.infinity import Infinity from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.infinity import Infinity -from sage.arith.all import binomial, rising_factorial, factorial -from sage.symbolic.constants import pi +from sage.structure.element import Expression, get_coercion_model from sage.symbolic.function import BuiltinFunction -from sage.symbolic.ring import SR -from sage.structure.element import get_coercion_model -from sage.misc.latex import latex -from sage.misc.misc_c import prod -from sage.libs.mpmath import utils as mpmath_utils -from sage.symbolic.expression import Expression -from sage.calculus.functional import derivative -from functools import reduce -from .gamma import gamma -from .other import sqrt, real_part -from .log import exp, log -from .hyperbolic import cosh, sinh -from .error import erf +lazy_import('sage.misc.latex', 'latex') + +lazy_import('sage.symbolic.constants', 'pi') +lazy_import('sage.symbolic.ring', 'SR') + +lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') +lazy_import('mpmath', 'hyp1f1', as_='_mpmath_hyp1f1') +lazy_import('mpmath', 'hyper', as_='_mpmath_hyper') +lazy_import('mpmath', 'hyperu', as_='_mpmath_hyperu') def rational_param_as_tuple(x): @@ -197,7 +210,7 @@ def rational_param_as_tuple(x): (1, 2) sage: rational_param_as_tuple(3) 3 - sage: rational_param_as_tuple(pi) + sage: rational_param_as_tuple(pi) # needs sage.symbolic pi """ try: @@ -234,7 +247,7 @@ def __init__(self): EXAMPLES:: - sage: maxima(hypergeometric) + sage: maxima(hypergeometric) # needs sage.symbolic hypergeometric TESTS:: @@ -265,6 +278,7 @@ def __call__(self, a, b, z, **kwargs): EXAMPLES:: + sage: # needs sage.symbolic sage: hypergeometric([], [], 1) hypergeometric((), (), 1) sage: hypergeometric([], [1], 1) @@ -289,7 +303,7 @@ def _print_latex_(self, a, b, z): r""" TESTS:: - sage: latex(hypergeometric([1, 1], [2], -1)) + sage: latex(hypergeometric([1, 1], [2], -1)) # needs sage.symbolic \,_2F_1\left(\begin{matrix} 1,1 \\ 2 \end{matrix} ; -1 \right) """ @@ -303,7 +317,7 @@ def _eval_(self, a, b, z, **kwargs): """ EXAMPLES:: - sage: hypergeometric([], [], 0) + sage: hypergeometric([], [], 0) # needs sage.symbolic 1 """ if not isinstance(a, tuple) or not isinstance(b, tuple): @@ -326,12 +340,12 @@ def _evalf_try_(self, a, b, z): EXAMPLES:: - sage: hypergeometric._evalf_try_((1.0,), (2.0,), 3.0) + sage: hypergeometric._evalf_try_((1.0,), (2.0,), 3.0) # needs mpmath 6.36184564106256 - sage: hypergeometric._evalf_try_((1.0, 1), (), 3.0) + sage: hypergeometric._evalf_try_((1.0, 1), (), 3.0) # needs mpmath -0.0377593153441588 + 0.750349833788561*I sage: hypergeometric._evalf_try_((1, 1), (), 3) # exact input - sage: hypergeometric._evalf_try_((x,), (), 1.0) # symbolic + sage: hypergeometric._evalf_try_((x,), (), 1.0) # symbolic # needs sage.symbolic sage: hypergeometric._evalf_try_(1.0, 2.0, 3.0) # not tuples """ # We need to override this for hypergeometric functions since @@ -350,32 +364,31 @@ def _evalf_(self, a, b, z, parent, algorithm=None): """ TESTS:: - sage: hypergeometric([1, 1], [2], -1).n() + sage: hypergeometric([1, 1], [2], -1).n() # needs sage.symbolic 0.693147180559945 - sage: hypergeometric([], [], RealField(100)(1)) + sage: hypergeometric([], [], RealField(100)(1)) # needs sage.rings.real_mpfr sage.symbolic 2.7182818284590452353602874714 """ if not isinstance(a, tuple) or not isinstance(b, tuple): raise TypeError("The first two parameters must be of type list") - from mpmath import hyper aa = [rational_param_as_tuple(c) for c in a] bb = [rational_param_as_tuple(c) for c in b] - return mpmath_utils.call(hyper, aa, bb, z, parent=parent) + return _mpmath_utils_call(_mpmath_hyper, aa, bb, z, parent=parent) def _tderivative_(self, a, b, z, *args, **kwargs): """ EXAMPLES:: - sage: hypergeometric([1/3, 2/3], [5], x^2).diff(x) + sage: hypergeometric([1/3, 2/3], [5], x^2).diff(x) # needs sage.symbolic 4/45*x*hypergeometric((4/3, 5/3), (6,), x^2) - sage: hypergeometric([1, 2], [x], 2).diff(x) + sage: hypergeometric([1, 2], [x], 2).diff(x) # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: derivative of hypergeometric function with... respect to parameters. Try calling .simplify_hypergeometric()... first. - sage: hypergeometric([1/3, 2/3], [5], 2).diff(x) + sage: hypergeometric([1/3, 2/3], [5], 2).diff(x) # needs sage.symbolic 0 """ diff_param = kwargs['diff_param'] @@ -401,16 +414,17 @@ def _fast_callable_(self, a, b, z, etb): EXAMPLES:: + sage: # needs sage.symbolic sage: h = hypergeometric([], [], x) sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=['x']) sage: h._fast_callable_(etb) {hypergeometric((), (), x)}(v_0) - sage: var('x, y') + sage: var('x, y') # needs sage.symbolic (x, y) - sage: f = fast_callable(hypergeometric([y], [], x), vars=[x, y]) - sage: f(3, 4) + sage: f = fast_callable(hypergeometric([y], [], x), vars=[x, y]) # needs sage.symbolic + sage: f(3, 4) # needs sage.symbolic hypergeometric((4,), (), 3) """ return etb.call(self, *map(etb.var, etb._vars)) @@ -421,7 +435,7 @@ def sorted_parameters(self, a, b, z): EXAMPLES:: - sage: hypergeometric([2, 1, 3], [5, 4], + sage: hypergeometric([2, 1, 3], [5, 4], # needs sage.symbolic ....: 1/2).sorted_parameters() hypergeometric((1, 2, 3), (4, 5), 1/2) """ @@ -434,12 +448,12 @@ def eliminate_parameters(self, a, b, z): EXAMPLES:: - sage: hypergeometric([1, 1, 2, 5], [5, 1, 4], + sage: hypergeometric([1, 1, 2, 5], [5, 1, 4], # needs sage.symbolic ....: 1/2).eliminate_parameters() hypergeometric((1, 2), (4,), 1/2) sage: hypergeometric([x], [x], x).eliminate_parameters() hypergeometric((), (), x) - sage: hypergeometric((5, 4), (4, 4), 3).eliminate_parameters() + sage: hypergeometric((5, 4), (4, 4), 3).eliminate_parameters() # needs sage.symbolic hypergeometric((5,), (4,), 3) """ aa = list(a) # tuples are immutable @@ -472,6 +486,7 @@ def is_termwise_finite(self, a, b, z): EXAMPLES:: + sage: # needs sage.symbolic sage: hypergeometric([2], [3, 4], 5).is_termwise_finite() True sage: hypergeometric([2], [-3, 4], 5).is_termwise_finite() @@ -482,6 +497,7 @@ def is_termwise_finite(self, a, b, z): ....: 5).is_termwise_finite() # ambiguous False + sage: # needs sage.symbolic sage: hypergeometric([0], [-1], 5).is_termwise_finite() True sage: hypergeometric([0], [0], @@ -545,18 +561,19 @@ def is_absolutely_convergent(self, a, b, z): Degree giving infinite radius of convergence:: - sage: hypergeometric([2, 3], [4, 5], + sage: hypergeometric([2, 3], [4, 5], # needs sage.symbolic ....: 6).is_absolutely_convergent() True - sage: hypergeometric([2, 3], [-4, 5], + sage: hypergeometric([2, 3], [-4, 5], # needs sage.symbolic ....: 6).is_absolutely_convergent() # undefined False - sage: (hypergeometric([2, 3], [-4, 5], Infinity) + sage: (hypergeometric([2, 3], [-4, 5], Infinity) # needs sage.symbolic ....: .is_absolutely_convergent()) # undefined False Ordinary geometric series (unit radius of convergence):: + sage: # needs sage.symbolic sage: hypergeometric([1], [], 1/2).is_absolutely_convergent() True sage: hypergeometric([1], [], 2).is_absolutely_convergent() @@ -570,6 +587,7 @@ def is_absolutely_convergent(self, a, b, z): Degree `p = q+1` (unit radius of convergence):: + sage: # needs sage.symbolic sage: hypergeometric([2, 3], [4], 6).is_absolutely_convergent() False sage: hypergeometric([2, 3], [4], 1).is_absolutely_convergent() @@ -593,13 +611,13 @@ def is_absolutely_convergent(self, a, b, z): Degree giving zero radius of convergence:: - sage: hypergeometric([1, 2, 3], [4], + sage: hypergeometric([1, 2, 3], [4], # needs sage.symbolic ....: 2).is_absolutely_convergent() False - sage: hypergeometric([1, 2, 3], [4], + sage: hypergeometric([1, 2, 3], [4], # needs sage.symbolic ....: 1/2).is_absolutely_convergent() False - sage: (hypergeometric([1, 2, -3], [4], 1/2) + sage: (hypergeometric([1, 2, -3], [4], 1/2) # needs sage.symbolic ....: .is_absolutely_convergent()) # polynomial True """ @@ -655,6 +673,7 @@ def deflated(self, a, b, z): EXAMPLES:: + sage: # needs sage.symbolic sage: x = hypergeometric([6, 1], [3, 4, 5], 10) sage: y = x.deflated() sage: y @@ -666,6 +685,7 @@ def deflated(self, a, b, z): 2.87893612686782 2.87893612686782 + sage: # needs sage.symbolic sage: x = hypergeometric([6, 7], [3, 4, 5], 10) sage: y = x.deflated() sage: y @@ -688,6 +708,7 @@ def _deflated(self, a, b, z): EXAMPLES:: + sage: # needs sage.symbolic sage: x = hypergeometric([5], [4], 3) sage: y = x.deflated() sage: y @@ -745,6 +766,7 @@ def closed_form(hyp): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.functions.hypergeometric import closed_form sage: var('a b c z') (a, b, c, z) @@ -936,6 +958,7 @@ class Hypergeometric_M(BuiltinFunction): EXAMPLES:: + sage: # needs mpmath sage: hypergeometric_M(1, 1, 1) hypergeometric_M(1, 1, 1) sage: hypergeometric_M(1, 1, 1.) @@ -944,16 +967,18 @@ class Hypergeometric_M(BuiltinFunction): 2.7182818284590452354 sage: hypergeometric_M(1, 1, 1).simplify_hypergeometric() e - sage: hypergeometric_M(1, 1/2, x).simplify_hypergeometric() - (-I*sqrt(pi)*x*erf(I*sqrt(-x))*e^x + sqrt(-x))/sqrt(-x) sage: hypergeometric_M(1, 3/2, 1).simplify_hypergeometric() 1/2*sqrt(pi)*erf(1)*e + + sage: hypergeometric_M(1, 1/2, x).simplify_hypergeometric() # needs sage.symbolic + (-I*sqrt(pi)*x*erf(I*sqrt(-x))*e^x + sqrt(-x))/sqrt(-x) + """ def __init__(self): r""" TESTS:: - sage: maxima(hypergeometric_M(1,1,x)) + sage: maxima(hypergeometric_M(1,1,x)) # needs sage.symbolic kummer_m(1,1,_SAGE_VAR_x) sage: latex(hypergeometric_M(1,1,x)) M\left(1, 1, x\right) @@ -970,8 +995,8 @@ def _eval_(self, a, b, z, **kwargs): """ TESTS:: - sage: (a,b)=var('a,b') - sage: hypergeometric_M(a,b,0) + sage: (a,b)=var('a,b') # needs sage.symbolic + sage: hypergeometric_M(a,b,0) # needs sage.symbolic 1 """ if not isinstance(z, Expression) and z == 0: @@ -982,11 +1007,10 @@ def _evalf_(self, a, b, z, parent, algorithm=None): """ TESTS:: - sage: hypergeometric_M(1,1,1).n() + sage: hypergeometric_M(1,1,1).n() # needs mpmath 2.71828182845905 """ - from mpmath import hyp1f1 - return mpmath_utils.call(hyp1f1, a, b, z, parent=parent) + return _mpmath_utils_call(_mpmath_hyp1f1, a, b, z, parent=parent) def _derivative_(self, a, b, z, diff_param): """ @@ -1011,9 +1035,9 @@ def generalized(self, a, b, z): EXAMPLES:: - sage: var('a b z') + sage: var('a b z') # needs sage.symbolic (a, b, z) - sage: hypergeometric_M(a, b, z).generalized() + sage: hypergeometric_M(a, b, z).generalized() # needs sage.symbolic hypergeometric((a,), (b,), z) """ @@ -1047,27 +1071,28 @@ class Hypergeometric_U(BuiltinFunction): EXAMPLES:: + sage: # needs mpmath sage: hypergeometric_U(1, 1, 1) hypergeometric_U(1, 1, 1) sage: hypergeometric_U(1, 1, 1.) 0.596347362323194 sage: hypergeometric_U(1, 1, 1).n(70) 0.59634736232319407434 - sage: hypergeometric_U(10^4, 1/3, 1).n() + sage: hypergeometric_U(10^4, 1/3, 1).n() # needs sage.libs.pari 6.60377008885811e-35745 - sage: hypergeometric_U(2 + I, 2, 1).n() - 0.183481989942099 - 0.458685959185190*I - sage: hypergeometric_U(1, 3, x).simplify_hypergeometric() - (x + 1)/x^2 sage: hypergeometric_U(1, 2, 2).simplify_hypergeometric() 1/2 + sage: hypergeometric_U(2 + I, 2, 1).n() # needs sage.symbolic + 0.183481989942099 - 0.458685959185190*I + sage: hypergeometric_U(1, 3, x).simplify_hypergeometric() # needs sage.symbolic + (x + 1)/x^2 """ def __init__(self): r""" TESTS:: - sage: maxima(hypergeometric_U(1,1,x)) + sage: maxima(hypergeometric_U(1,1,x)) # needs sage.symbolic kummer_u(1,1,_SAGE_VAR_x) sage: latex(hypergeometric_U(1,1,x)) U\left(1, 1, x\right) @@ -1087,11 +1112,10 @@ def _evalf_(self, a, b, z, parent, algorithm=None): """ TESTS:: - sage: hypergeometric_U(1,1,1).n() + sage: hypergeometric_U(1,1,1).n() # needs mpmath 0.596347362323194 """ - from mpmath import hyperu - return mpmath_utils.call(hyperu, a, b, z, parent=parent) + return _mpmath_utils_call(_mpmath_hyperu, a, b, z, parent=parent) def _derivative_(self, a, b, z, diff_param): """ @@ -1116,13 +1140,13 @@ def generalized(self, a, b, z): EXAMPLES:: - sage: var('a b z') + sage: var('a b z') # needs sage.symbolic (a, b, z) - sage: hypergeometric_U(a, b, z).generalized() + sage: hypergeometric_U(a, b, z).generalized() # needs sage.symbolic hypergeometric((a, a - b + 1), (), -1/z)/z^a - sage: hypergeometric_U(1, 3, 1/2).generalized() + sage: hypergeometric_U(1, 3, 1/2).generalized() # needs mpmath 2*hypergeometric((1, -1), (), -2) - sage: hypergeometric_U(3, I, 2).generalized() + sage: hypergeometric_U(3, I, 2).generalized() # needs sage.symbolic 1/8*hypergeometric((3, -I + 4), (), -1/2) """ diff --git a/src/sage/functions/jacobi.py b/src/sage/functions/jacobi.py index 6fe3b2ade89..629b24ce930 100644 --- a/src/sage/functions/jacobi.py +++ b/src/sage/functions/jacobi.py @@ -145,17 +145,21 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.symbolic.function import BuiltinFunction -from sage.functions.trig import (arctan, arcsin, arccos, arccot, arcsec, - arccsc, csc, sec, sin, cos, tan, cot) from sage.functions.hyperbolic import (arctanh, arccosh, arcsinh, arcsech, arccsch, arccoth, cosh, coth, sech, csch, tanh, sinh) -from sage.rings.rational_field import QQ -from sage.rings.integer import Integer from sage.functions.special import elliptic_e, elliptic_kc -from sage.libs.mpmath import utils -from sage.misc.latex import latex +from sage.functions.trig import (arctan, arcsin, arccos, arccot, arcsec, + arccsc, csc, sec, sin, cos, tan, cot) +from sage.misc.lazy_import import lazy_import +from sage.rings.integer import Integer +from sage.rings.rational_field import QQ +from sage.symbolic.function import BuiltinFunction + +lazy_import('sage.misc.latex', 'latex') + +lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') +lazy_import('mpmath', 'ellipfun', as_='_mpmath_ellipfun') HALF = QQ((1, 2)) @@ -176,18 +180,19 @@ def __init__(self, kind): TESTS:: - sage: N(jacobi("sn", I, 1/2)) # abs tol 1e-12 + sage: N(jacobi("sn", I, 1/2)) # abs tol 1e-12 # needs sage.symbolic -8.59454886300046e-73 + 1.34737147138542*I - sage: CN = fricas(jacobi('cn',x, 2)); CN # optional - fricas + sage: # optional - fricas, needs sage.symbolic + sage: CN = fricas(jacobi('cn',x, 2)); CN jacobiCn(x,2) - sage: fricas.series(CN, x=0) # optional - fricas + sage: fricas.series(CN, x=0) 1 2 3 4 17 6 79 8 1381 10 11 1 - - x + - x - -- x + --- x - ----- x + O(x ) 2 8 80 640 19200 - sage: fricas(jacobi('sn',x, 2)) # optional - fricas + sage: fricas(jacobi('sn',x, 2)) jacobiSn(x,2) - sage: fricas(jacobi('dn',x, 2)) # optional - fricas + sage: fricas(jacobi('dn',x, 2)) jacobiDn(x,2) """ if kind not in ['nd', 'ns', 'nc', 'dn', 'ds', 'dc', 'sn', 'sd', @@ -208,7 +213,8 @@ def _eval_(self, x, m): Check that the simplifications are correct:: - sage: from mpmath import almosteq + sage: # needs mpmath sage.symbolic + sage: from sage.libs.mpmath.all import almosteq sage: almosteq(n(jacobi_nd(8, 0, hold=True)), n(jacobi_nd(8, 0))) True sage: almosteq(n(jacobi_nd(1, 1, hold=True)), n(jacobi_nd(1, 1))) @@ -356,13 +362,12 @@ def _evalf_(self, x, m, parent, algorithm=None): r""" TESTS:: - sage: jacobi_sn(3, 4).n(100) + sage: jacobi_sn(3, 4).n(100) # needs mpmath sage.symbolic -0.33260000892770027112809652714 + 1.7077912301715219199143891076e-33*I - sage: jacobi_dn(I, I).n() + sage: jacobi_dn(I, I).n() # needs mpmath sage.symbolic 0.874189950651018 + 0.667346865048825*I """ - from mpmath import ellipfun - return utils.call(ellipfun, self.kind, x, m, parent=parent) + return _mpmath_utils_call(_mpmath_ellipfun, self.kind, x, m, parent=parent) def _derivative_(self, x, m, diff_param): r""" @@ -371,6 +376,7 @@ def _derivative_(self, x, m, diff_param): sn, cn, and dn are analytic for all real ``x``, so we can check that the derivatives are correct by computing the series:: + sage: # needs mpmath sage.symbolic sage: from mpmath import almosteq sage: a = 0.9327542442482303 sage: b = 0.7402326293643771 @@ -508,13 +514,14 @@ def _print_latex_(self, x, m): r""" TESTS:: - sage: latex(jacobi_sn(x, 3)) + sage: latex(jacobi_sn(x, 3)) # needs sage.symbolic \operatorname{sn}\left(x\middle|3\right) """ return r"\operatorname{{{}}}\left({}\middle|{}\right)".format(self.kind, latex(x), latex(m)) + jacobi_nd = Jacobi('nd') jacobi_ns = Jacobi('ns') jacobi_nc = Jacobi('nc') @@ -560,6 +567,7 @@ def _eval_(self, x, m): Check that the simplifications are correct:: + sage: # needs mpmath sage.symbolic sage: from mpmath import almosteq sage: almosteq(n(inverse_jacobi_cd(1, -8, hold=True)), ....: n(inverse_jacobi_cd(1, -8))) @@ -712,12 +720,12 @@ def _evalf_(self, x, m, parent, algorithm=None): r""" TESTS:: - sage: inverse_jacobi_cn(2, 3).n() + sage: inverse_jacobi_cn(2, 3).n() # needs mpmath 0.859663746362987*I - sage: inverse_jacobi_cd(3, 4).n(100) + sage: inverse_jacobi_cd(3, 4).n(100) # needs mpmath -0.67214752201235862490069823239 + 2.1565156474996432354386749988*I """ - return utils.call(inverse_jacobi_f, self.kind, x, m, parent=parent) + return _mpmath_utils_call(inverse_jacobi_f, self.kind, x, m, parent=parent) def _derivative_(self, x, m, diff_param): r""" @@ -726,6 +734,7 @@ def _derivative_(self, x, m, diff_param): Check that ``dy/dx * dx/dy == 1``, where ``y = jacobi_pq(x, m)`` and ``x = inverse_jacobi_pq(y, m)``:: + sage: # needs mpmath sage.symbolic sage: from mpmath import almosteq sage: a = 0.130103220857094 sage: b = 0.437176765041986 @@ -898,13 +907,14 @@ def _print_latex_(self, x, m): r""" TESTS:: - sage: latex(inverse_jacobi_dn(x, 3)) + sage: latex(inverse_jacobi_dn(x, 3)) # needs sage.symbolic \operatorname{arcdn}\left(x\middle|3\right) """ return r"\operatorname{{arc{}}}\left({}\middle|{}\right)".format(self.kind, latex(x), latex(m)) + inverse_jacobi_nd = InverseJacobi('nd') inverse_jacobi_ns = InverseJacobi('ns') inverse_jacobi_nc = InverseJacobi('nc') @@ -933,6 +943,7 @@ def jacobi(kind, z, m, **kwargs): EXAMPLES:: + sage: # needs mpmath sage: jacobi('sn', 1, 1) tanh(1) sage: jacobi('cd', 1, 1/2) @@ -942,8 +953,9 @@ def jacobi(kind, z, m, **kwargs): sage: (RDF(jacobi('cn', 1, 1/2)), RDF(jacobi('dn', 1, 1/2)), ....: RDF(jacobi('cn', 1, 1/2) / jacobi('dn', 1, 1/2))) (0.5959765676721407, 0.8231610016315962, 0.7240097216593705) - sage: jsn = jacobi('sn', x, 1) - sage: P = plot(jsn, 0, 1) + + sage: jsn = jacobi('sn', x, 1) # needs sage.symbolic + sage: P = plot(jsn, 0, 1) # needs sage.plot sage.symbolic """ if kind == 'nd': return jacobi_nd(z, m, **kwargs) @@ -994,20 +1006,24 @@ def inverse_jacobi(kind, x, m, **kwargs): EXAMPLES:: - sage: jacobi('dn', inverse_jacobi('dn', 3, 0.4), 0.4) + sage: jacobi('dn', inverse_jacobi('dn', 3, 0.4), 0.4) # needs mpmath 3.00000000000000 - sage: inverse_jacobi('dn', 10, 1/10).n(digits=50) + sage: inverse_jacobi('dn', 10, 1/10).n(digits=50) # needs mpmath 2.4777736267904273296523691232988240759001423661683*I - sage: inverse_jacobi_dn(x, 1) + sage: inverse_jacobi_dn(x, 1) # needs sage.symbolic arcsech(x) - sage: inverse_jacobi_dn(1, 3) + sage: inverse_jacobi_dn(1, 3) # needs mpmath 0 + + sage: # needs sage.symbolic sage: m = var('m') sage: z = inverse_jacobi_dn(x, m).series(x, 4).subs(x=0.1, m=0.7) sage: jacobi_dn(z, 0.7) 0.0999892750039819... sage: inverse_jacobi_nd(x, 1) arccosh(x) + + sage: # needs mpmath sage: inverse_jacobi_nd(1, 2) 0 sage: inverse_jacobi_ns(10^-5, 3).n() @@ -1020,7 +1036,7 @@ def inverse_jacobi(kind, x, m, **kwargs): 0.499098231322220 sage: inverse_jacobi('sn', 0.4707504, 0.5) 0.499999911466555 - sage: P = plot(inverse_jacobi('sn', x, 0.5), 0, 1) + sage: P = plot(inverse_jacobi('sn', x, 0.5), 0, 1) # needs sage.plot """ if kind == 'nd': return inverse_jacobi_nd(x, m, **kwargs) @@ -1050,6 +1066,7 @@ def inverse_jacobi(kind, x, m, **kwargs): raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") + class JacobiAmplitude(BuiltinFunction): r""" The Jacobi amplitude function @@ -1073,11 +1090,11 @@ def _eval_(self, x, m): r""" TESTS:: - sage: jacobi_am(x, 0) + sage: jacobi_am(x, 0) # needs sage.symbolic x - sage: jacobi_am(0, x) + sage: jacobi_am(0, x) # needs sage.symbolic 0 - sage: jacobi_am(3, 4.) + sage: jacobi_am(3, 4.) # needs mpmath -0.339059208303591 """ if m == 0: @@ -1090,18 +1107,18 @@ def _evalf_(self, x, m, parent, algorithm=None): r""" TESTS:: - sage: jacobi_am(1, 2).n(100) + sage: jacobi_am(1, 2).n(100) # needs mpmath 0.73704379494724574105101929735 """ - return utils.call(jacobi_am_f, x, m, parent=parent) + return _mpmath_utils_call(jacobi_am_f, x, m, parent=parent) def _derivative_(self, x, m, diff_param): r""" TESTS:: - sage: diff(jacobi_am(x, 3), x) + sage: diff(jacobi_am(x, 3), x) # needs sage.symbolic jacobi_dn(x, 3) - sage: diff(jacobi_am(3, x), x) + sage: diff(jacobi_am(3, x), x) # needs sage.symbolic -1/2*(x*jacobi_cn(3, x)*jacobi_sn(3, x) -... (3*x + elliptic_e(jacobi_am(3, x), x) - 3)*jacobi_dn(3, x))/((x - 1)*x) """ @@ -1125,7 +1142,7 @@ def _print_latex_(self, x, m): r""" TESTS:: - sage: latex(jacobi_am(3,x)) + sage: latex(jacobi_am(3,x)) # needs sage.symbolic \operatorname{am}\left(3\middle|x\right) """ return r"\operatorname{{am}}\left({}\middle|{}\right)".format(latex(x), @@ -1143,9 +1160,10 @@ def inverse_jacobi_f(kind, x, m): TESTS:: - sage: from mpmath import ellipfun, chop + sage: from mpmath import ellipfun, chop # needs mpmath sage: from sage.functions.jacobi import inverse_jacobi_f + sage: # needs mpmath sage: chop(ellipfun('sn', inverse_jacobi_f('sn', 0.6, 0), 0)) mpf('0.59999999999999998') sage: chop(ellipfun('sn', inverse_jacobi_f('sn', 0.6, 1), 1)) @@ -1159,6 +1177,7 @@ def inverse_jacobi_f(kind, x, m): sage: chop(ellipfun('sn', inverse_jacobi_f('sn', 0.8, 4), 4)) mpf('0.80000000000000004') + sage: # needs mpmath sage: chop(ellipfun('ns', inverse_jacobi_f('ns', 0.8, 0), 0)) mpf('0.80000000000000004') sage: chop(ellipfun('ns', inverse_jacobi_f('ns', -0.7, 1), 1)) @@ -1170,6 +1189,7 @@ def inverse_jacobi_f(kind, x, m): sage: chop(ellipfun('ns', inverse_jacobi_f('ns', -10, 6), 6)) mpf('-10.0') + sage: # needs mpmath sage: chop(ellipfun('cn', inverse_jacobi_f('cn', -10, 0), 0)) mpf('-9.9999999999999982') sage: chop(ellipfun('cn', inverse_jacobi_f('cn', 50, 1), 1)) @@ -1185,6 +1205,7 @@ def inverse_jacobi_f(kind, x, m): sage: chop(ellipfun('cn', inverse_jacobi_f('cn', -2, 0.9), 0.9)) mpf('-2.0') + sage: # needs mpmath sage: chop(ellipfun('nc', inverse_jacobi_f('nc', -4, 0), 0)) mpf('-3.9999999999999987') sage: chop(ellipfun('nc', inverse_jacobi_f('nc', 7, 1), 1)) @@ -1196,6 +1217,7 @@ def inverse_jacobi_f(kind, x, m): sage: chop(ellipfun('nc', inverse_jacobi_f('nc', -18, -4), -4)) mpf('-17.999999999999925') + sage: # needs mpmath sage: chop(ellipfun('dn', inverse_jacobi_f('dn', -0.3, 1), 1)) mpf('-0.29999999999999999') sage: chop(ellipfun('dn', inverse_jacobi_f('dn', 1, -1), -1)) @@ -1213,6 +1235,7 @@ def inverse_jacobi_f(kind, x, m): sage: chop(ellipfun('dn', inverse_jacobi_f('dn', -1.9, 0.2), 0.2)) mpf('-1.8999999999999999') + sage: # needs mpmath sage: chop(ellipfun('nd', inverse_jacobi_f('nd', -1.9, 1), 1)) mpf('-1.8999999999999999') sage: chop(ellipfun('nd', inverse_jacobi_f('nd', 1, -1), -1)) @@ -1224,6 +1247,7 @@ def inverse_jacobi_f(kind, x, m): sage: chop(ellipfun('nd', inverse_jacobi_f('nd', -3, 0.8), 0.8)) mpf('-2.9999999999999996') + sage: # needs mpmath sage: chop(ellipfun('sc', inverse_jacobi_f('sc', -3, 0), 0)) mpf('-3.0') sage: chop(ellipfun('sc', inverse_jacobi_f('sc', 2, 1), 1)) @@ -1233,6 +1257,7 @@ def inverse_jacobi_f(kind, x, m): sage: chop(ellipfun('sc', inverse_jacobi_f('sc', -7, 3), 3)) mpf('-7.0') + sage: # needs mpmath sage: chop(ellipfun('cs', inverse_jacobi_f('cs', -7, 0), 0)) mpf('-6.9999999999999991') sage: chop(ellipfun('cs', inverse_jacobi_f('cs', 8, 1), 1)) @@ -1244,18 +1269,19 @@ def inverse_jacobi_f(kind, x, m): sage: chop(ellipfun('cs', inverse_jacobi_f('cs', -6, 8), 8)) mpf('-6.0000000000000018') - sage: chop(ellipfun('cd', inverse_jacobi_f('cd', -6, 0), 0)) + sage: chop(ellipfun('cd', inverse_jacobi_f('cd', -6, 0), 0)) # needs mpmath mpf('-6.0000000000000009') - sage: chop(ellipfun('cd', inverse_jacobi_f('cd', 1, 3), 3)) + sage: chop(ellipfun('cd', inverse_jacobi_f('cd', 1, 3), 3)) # needs mpmath mpf('1.0') - sage: chop(ellipfun('cd', inverse_jacobi_f('cd', 6, 8), 8)) + sage: chop(ellipfun('cd', inverse_jacobi_f('cd', 6, 8), 8)) # needs mpmath mpf('6.0000000000000027') - sage: chop(ellipfun('dc', inverse_jacobi_f('dc', 5, 0), 0)) + sage: chop(ellipfun('dc', inverse_jacobi_f('dc', 5, 0), 0)) # needs mpmath mpf('5.0000000000000018') - sage: chop(ellipfun('dc', inverse_jacobi_f('dc', -4, 2), 2)) + sage: chop(ellipfun('dc', inverse_jacobi_f('dc', -4, 2), 2)) # needs mpmath mpf('-4.0000000000000018') + sage: # needs mpmath sage: chop(ellipfun('sd', inverse_jacobi_f('sd', -4, 0), 0)) mpf('-3.9999999999999991') sage: chop(ellipfun('sd', inverse_jacobi_f('sd', 7, 1), 1)) @@ -1265,12 +1291,10 @@ def inverse_jacobi_f(kind, x, m): sage: chop(ellipfun('sd', inverse_jacobi_f('sd', 8, 0.8), 0.8)) mpf('7.9999999999999991') - sage: chop(ellipfun('ds', inverse_jacobi_f('ds', 4, 0.25), 0.25)) + sage: chop(ellipfun('ds', inverse_jacobi_f('ds', 4, 0.25), 0.25)) # needs mpmath mpf('4.0') """ - from mpmath import mp - - ctx = mp + from mpmath import mp as ctx prec = ctx.prec try: x = ctx.convert(x) @@ -1611,6 +1635,7 @@ def jacobi_am_f(x, m): TESTS:: + sage: # needs mpmath sage: from mpmath import ellipf sage: from sage.functions.jacobi import jacobi_am_f sage: ellipf(jacobi_am_f(0.5, 1), 1) @@ -1626,9 +1651,7 @@ def jacobi_am_f(x, m): sage: jacobi_am_f(-3, 2) mpf('0.36067407399586108') """ - from mpmath import mp - - ctx = mp + from mpmath import mp as ctx prec = ctx.prec try: x = ctx.convert(x) diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index 6f9133841a3..38c6ca08bbe 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -8,20 +8,35 @@ - Tomas Kalvoda (2015-04-01): Add :meth:`exp_polar()` (:trac:`18085`) """ -from sage.symbolic.function import GinacFunction, BuiltinFunction -from sage.symbolic.constants import e as const_e -from sage.symbolic.constants import pi as const_pi -from sage.libs.mpmath import utils as mpmath_utils -from sage.structure.all import parent as s_parent -from sage.symbolic.expression import Expression, register_symbol -from sage.rings.real_double import RDF -from sage.rings.complex_double import CDF +from sage.misc.functional import log as log +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ +from sage.rings.real_double import RDF +from sage.structure.element import Expression, parent as s_parent +from sage.symbolic.function import GinacFunction, BuiltinFunction +from sage.symbolic.symbols import register_symbol -from sage.misc.functional import log as log +lazy_import('sage.functions.gamma', 'psi1') +lazy_import('sage.functions.other', 'imag') +lazy_import('sage.functions.transcendental', ['hurwitz_zeta', 'zeta']) + +lazy_import('sage.symbolic.constants', 'e', as_='const_e') +lazy_import('sage.symbolic.constants', 'pi', as_='const_pi') +lazy_import('sage.rings.complex_double', 'CDF') + +lazy_import('sage.libs.flint.arith', 'harmonic_number', as_='_flint_harmonic_number') + +lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') +lazy_import('mpmath', 'harmonic', as_='_mpmath_harmonic') +lazy_import('mpmath', 'lambertw', as_='_mpmath_lambertw') + +lazy_import('sympy', 'polylog', as_='_sympy_polylog') +lazy_import('sympy', 'sympify', as_='_sympify') + +lazy_import('scipy.special', 'lambertw', as_='_scipy_lambertw') class Function_exp(GinacFunction): @@ -30,6 +45,7 @@ class Function_exp(GinacFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: exp(-1) e^(-1) sage: exp(2) @@ -42,28 +58,30 @@ class Function_exp(GinacFunction): x*e^(x^2) sage: exp(2.5) 12.1824939607035 + sage: exp(I*pi/12) + (1/4*I + 1/4)*sqrt(6) - (1/4*I - 1/4)*sqrt(2) + sage: exp(float(2.5)) 12.182493960703473 sage: exp(RDF('2.5')) 12.182493960703473 - sage: exp(I*pi/12) - (1/4*I + 1/4)*sqrt(6) - (1/4*I - 1/4)*sqrt(2) To prevent automatic evaluation, use the ``hold`` parameter:: - sage: exp(I*pi,hold=True) + sage: exp(I*pi, hold=True) # needs sage.symbolic e^(I*pi) - sage: exp(0,hold=True) + sage: exp(0, hold=True) # needs sage.symbolic e^0 To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: exp(0,hold=True).simplify() + sage: exp(0, hold=True).simplify() # needs sage.symbolic 1 :: + sage: # needs sage.symbolic sage: exp(pi*I/2) I sage: exp(pi*I) @@ -76,25 +94,26 @@ class Function_exp(GinacFunction): For the sake of simplification, the argument is reduced modulo the period of the complex exponential function, `2\pi i`:: - sage: k = var('k', domain='integer') - sage: exp(2*k*pi*I) + sage: k = var('k', domain='integer') # needs sage.symbolic + sage: exp(2*k*pi*I) # needs sage.symbolic 1 - sage: exp(log(2) + 2*k*pi*I) + sage: exp(log(2) + 2*k*pi*I) # needs sage.symbolic 2 The precision for the result is deduced from the precision of the input. Convert the input to a higher precision explicitly if a result with higher precision is desired:: - sage: t = exp(RealField(100)(2)); t + sage: t = exp(RealField(100)(2)); t # needs sage.rings.real_mpfr 7.3890560989306502272304274606 - sage: t.prec() + sage: t.prec() # needs sage.rings.real_mpfr 100 - sage: exp(2).n(100) + sage: exp(2).n(100) # needs sage.symbolic 7.3890560989306502272304274606 TESTS:: + sage: # needs sage.symbolic sage: latex(exp(x)) e^{x} sage: latex(exp(sqrt(x))) @@ -105,25 +124,27 @@ class Function_exp(GinacFunction): \left(e^{\sqrt{x}}\right)^{x} sage: latex(exp(sqrt(x)^x)) e^{\left(\sqrt{x}^{x}\right)} - sage: exp(x)._sympy_() + sage: exp(x)._sympy_() # needs sympy exp(x) Test conjugates:: - sage: conjugate(exp(x)) + sage: conjugate(exp(x)) # needs sage.symbolic e^conjugate(x) Test simplifications when taking powers of exp (:trac:`7264`):: + sage: # needs sage.symbolic sage: var('a,b,c,II') (a, b, c, II) sage: model_exp = exp(II)**a*(b) - sage: sol1_l={b: 5.0, a: 1.1} + sage: sol1_l = {b: 5.0, a: 1.1} sage: model_exp.subs(sol1_l) 5.00000000000000*e^(1.10000000000000*II) :: + sage: # needs sage.symbolic sage: exp(3)^II*exp(x) e^(3*II + x) sage: exp(x)*exp(x) @@ -135,14 +156,14 @@ class Function_exp(GinacFunction): Another instance of the same problem (:trac:`7394`):: - sage: 2*sqrt(e) + sage: 2*sqrt(e) # needs sage.symbolic 2*e^(1/2) Check that :trac:`19918` is fixed:: - sage: exp(-x^2).subs(x=oo) + sage: exp(-x^2).subs(x=oo) # needs sage.symbolic 0 - sage: exp(-x).subs(x=-oo) + sage: exp(-x).subs(x=-oo) # needs sage.symbolic +Infinity """ def __init__(self): @@ -151,7 +172,7 @@ def __init__(self): sage: loads(dumps(exp)) exp - sage: maxima(exp(x))._sage_() + sage: maxima(exp(x))._sage_() # needs sage.symbolic e^x """ GinacFunction.__init__(self, "exp", latex_name=r"\exp", @@ -169,20 +190,21 @@ class Function_log1(GinacFunction): EXAMPLES:: - sage: ln(e^2) + sage: ln(e^2) # needs sage.symbolic 2 - sage: ln(2) + sage: ln(2) # needs sage.symbolic log(2) - sage: ln(10) + sage: ln(10) # needs sage.symbolic log(10) TESTS:: + sage: # needs sage.symbolic sage: latex(x.log()) \log\left(x\right) sage: latex(log(1/4)) \log\left(\frac{1}{4}\right) - sage: log(x)._sympy_() + sage: log(x)._sympy_() # needs sympy log(x) sage: loads(dumps(ln(x)+1)) log(x) + 1 @@ -190,13 +212,14 @@ class Function_log1(GinacFunction): ``conjugate(log(x))==log(conjugate(x))`` unless on the branch cut which runs along the negative real axis.:: + sage: # needs sage.symbolic sage: conjugate(log(x)) conjugate(log(x)) sage: var('y', domain='positive') y sage: conjugate(log(y)) log(y) - sage: conjugate(log(y+I)) + sage: conjugate(log(y + I)) conjugate(log(y + I)) sage: conjugate(log(-1)) -I*pi @@ -208,20 +231,20 @@ class Function_log1(GinacFunction): sage: from sage.functions.log import function_log as log sage: log(float(5)) 1.6094379124341003 - sage: log(float(0)) + sage: log(float(0)) # needs sage.symbolic -inf - sage: log(float(-1)) + sage: log(float(-1)) # needs sage.symbolic 3.141592653589793j - sage: log(x).subs(x=float(-1)) + sage: log(x).subs(x=float(-1)) # needs sage.symbolic 3.141592653589793j :trac:`22142`:: - sage: log(QQbar(sqrt(2))) + sage: log(QQbar(sqrt(2))) # needs sage.rings.number_field sage.symbolic log(1.414213562373095?) - sage: log(QQbar(sqrt(2))*1.) + sage: log(QQbar(sqrt(2))*1.) # needs sage.rings.number_field sage.symbolic 0.346573590279973 - sage: polylog(QQbar(sqrt(2)),3) + sage: polylog(QQbar(sqrt(2)),3) # needs sage.rings.number_field sage.symbolic polylog(1.414213562373095?, 3) """ def __init__(self): @@ -230,7 +253,7 @@ def __init__(self): sage: loads(dumps(ln)) log - sage: maxima(ln(x))._sage_() + sage: maxima(ln(x))._sage_() # needs sage.symbolic log(x) """ GinacFunction.__init__(self, 'log', latex_name=r'\log', @@ -250,14 +273,14 @@ class Function_log2(GinacFunction): EXAMPLES:: sage: from sage.functions.log import logb - sage: logb(1000,10) + sage: logb(1000, 10) # needs sage.symbolic 3 TESTS:: - sage: logb(7, 2) + sage: logb(7, 2) # needs sage.symbolic log(7)/log(2) - sage: logb(int(7), 2) + sage: logb(int(7), 2) # needs sage.symbolic log(7)/log(2) """ def __init__(self): @@ -283,16 +306,17 @@ def __init__(self): `\text{Li}_s(z) = \sum_{k=1}^{\infty} z^k / k^s`. The first argument is `s` (usually an integer called the weight) - and the second argument is `z` : ``polylog(s, z)``. + and the second argument is `z`: ``polylog(s, z)``. This definition is valid for arbitrary complex numbers `s` and `z` with `|z| < 1`. It can be extended to `|z| \ge 1` by the process of analytic continuation, with a branch cut along the positive real axis - from `1` to `+\infty`. A `NaN` value may be returned for floating + from `1` to `+\infty`. A ``NaN`` value may be returned for floating point arguments that are on the branch cut. EXAMPLES:: + sage: # needs sage.symbolic sage: polylog(2.7, 0) 0.000000000000000 sage: polylog(2, 1) @@ -308,55 +332,54 @@ def __init__(self): sage: polylog(4, 0.5) 0.517479061673899 + sage: # needs sage.symbolic sage: polylog(1, x) -log(-x + 1) - sage: polylog(2,x^2+1) + sage: polylog(2, x^2 + 1) dilog(x^2 + 1) - sage: f = polylog(4, 1); f 1/90*pi^4 sage: f.n() 1.08232323371114 - sage: polylog(4, 2).n() 2.42786280675470 - 0.174371300025453*I - sage: complex(polylog(4,2)) + sage: complex(polylog(4, 2)) (2.4278628067547032-0.17437130002545306j) - sage: float(polylog(4,0.5)) + sage: float(polylog(4, 0.5)) 0.5174790616738993 - sage: z = var('z') - sage: polylog(2,z).series(z==0, 5) + sage: polylog(2, z).series(z==0, 5) 1*z + 1/4*z^2 + 1/9*z^3 + 1/16*z^4 + Order(z^5) sage: loads(dumps(polylog)) polylog - sage: latex(polylog(5, x)) + sage: latex(polylog(5, x)) # needs sage.symbolic {\rm Li}_{5}(x) - sage: polylog(x, x)._sympy_() + sage: polylog(x, x)._sympy_() # needs sympy sage.symbolic polylog(x, x) TESTS: Check if :trac:`8459` is fixed:: - sage: t = maxima(polylog(5,x)).sage(); t + sage: t = maxima(polylog(5,x)).sage(); t # needs sage.symbolic polylog(5, x) - sage: t.operator() == polylog + sage: t.operator() == polylog # needs sage.symbolic True - sage: t.subs(x=.5).n() + sage: t.subs(x=.5).n() # needs sage.symbolic 0.50840057924226... Check if :trac:`18386` is fixed:: - sage: polylog(2.0, 1) + sage: polylog(2.0, 1) # needs sage.symbolic 1.64493406684823 - sage: polylog(2, 1.0) + sage: polylog(2, 1.0) # needs sage.symbolic 1.64493406684823 - sage: polylog(2.0, 1.0) + sage: polylog(2.0, 1.0) # needs sage.symbolic 1.64493406684823 + sage: # needs sage.libs.flint sage: polylog(2, RealBallField(100)(1/3)) [0.36621322997706348761674629766... +/- ...] sage: polylog(2, ComplexBallField(100)(4/3)) @@ -370,12 +393,12 @@ def __init__(self): sage: parent(_) Complex ball field with 53 bits of precision - sage: polylog(1,-1) # known bug + sage: polylog(1, -1) # known bug # needs sage.symbolic -log(2) Check for :trac:`21907`:: - sage: bool(x*polylog(x,x)==0) + sage: bool(x*polylog(x,x)==0) # needs sage.symbolic False """ GinacFunction.__init__(self, "polylog", nargs=2, @@ -390,9 +413,9 @@ def _maxima_init_evaled_(self, *args): These are indirect doctests for this function:: - sage: polylog(2, x)._maxima_() + sage: polylog(2, x)._maxima_() # needs sage.symbolic li[2](_SAGE_VAR_x) - sage: polylog(4, x)._maxima_() + sage: polylog(4, x)._maxima_() # needs sage.symbolic polylog(4,_SAGE_VAR_x) """ args_maxima = [] @@ -414,8 +437,8 @@ def _method_arguments(self, k, z): r""" TESTS:: - sage: b = RBF(1/2, .0001) - sage: polylog(2, b) + sage: b = RBF(1/2, .0001) # needs sage.libs.flint + sage: polylog(2, b) # needs sage.libs.flint [0.582 +/- ...] """ return [z, k] @@ -430,10 +453,11 @@ def __init__(self): The dilogarithm function `\text{Li}_2(z) = \sum_{k=1}^{\infty} z^k / k^2`. - This is simply an alias for polylog(2, z). + This is simply an alias for ``polylog(2, z)``. EXAMPLES:: + sage: # needs sage.symbolic sage: dilog(1) 1/6*pi^2 sage: dilog(1/2) @@ -457,14 +481,16 @@ def __init__(self): sage: dilog(z).diff(z, 2) log(-z + 1)/z^2 - 1/((z - 1)*z) sage: dilog(z).series(z==1/2, 3) - (1/12*pi^2 - 1/2*log(2)^2) + (-2*log(1/2))*(z - 1/2) + (2*log(1/2) + 2)*(z - 1/2)^2 + Order(1/8*(2*z - 1)^3) + (1/12*pi^2 - 1/2*log(2)^2) + (-2*log(1/2))*(z - 1/2) + + (2*log(1/2) + 2)*(z - 1/2)^2 + Order(1/8*(2*z - 1)^3) - sage: latex(dilog(z)) + sage: latex(dilog(z)) # needs sage.symbolic {\rm Li}_2\left(z\right) Dilog has a branch point at `1`. Sage's floating point libraries may handle this differently from the symbolic package:: + sage: # needs sage.symbolic sage: dilog(1) 1/6*pi^2 sage: dilog(1.) @@ -479,9 +505,10 @@ def __init__(self): ``conjugate(dilog(x))==dilog(conjugate(x))`` unless on the branch cuts which run along the positive real axis beginning at 1.:: + sage: # needs sage.symbolic sage: conjugate(dilog(x)) conjugate(dilog(x)) - sage: var('y',domain='positive') + sage: var('y', domain='positive') y sage: conjugate(dilog(y)) conjugate(dilog(y)) @@ -497,10 +524,12 @@ def __init__(self): Check that return type matches argument type where possible (:trac:`18386`):: - sage: dilog(0.5) + sage: dilog(0.5) # needs sage.symbolic 0.582240526465012 - sage: dilog(-1.0) + sage: dilog(-1.0) # needs sage.symbolic -0.822467033424113 + + sage: # needs sage.rings.real_mpfr sage.symbolic sage: y = dilog(RealField(13)(0.5)) sage: parent(y) Real Field with 13 bits of precision @@ -520,16 +549,14 @@ def _sympy_(self, z): EXAMPLES:: - sage: w = dilog(x)._sympy_(); w + sage: w = dilog(x)._sympy_(); w # needs sympy sage.symbolic polylog(2, x) - sage: w.diff() + sage: w.diff() # needs sympy sage.symbolic polylog(1, x)/x - sage: w._sage_() + sage: w._sage_() # needs sympy sage.symbolic dilog(x) """ - import sympy - from sympy import polylog as sympy_polylog - return sympy_polylog(2, sympy.sympify(z, evaluate=False)) + return _sympy_polylog(2, _sympify(z, evaluate=False)) dilog = Function_dilog() @@ -566,55 +593,55 @@ class Function_lambert_w(BuiltinFunction): Evaluation of the principal branch:: - sage: lambert_w(1.0) + sage: lambert_w(1.0) # needs scipy 0.567143290409784 - sage: lambert_w(-1).n() + sage: lambert_w(-1).n() # needs mpmath -0.318131505204764 + 1.33723570143069*I - sage: lambert_w(-1.5 + 5*I) + sage: lambert_w(-1.5 + 5*I) # needs mpmath sage.symbolic 1.17418016254171 + 1.10651494102011*I Evaluation of other branches:: - sage: lambert_w(2, 1.0) + sage: lambert_w(2, 1.0) # needs scipy -2.40158510486800 + 10.7762995161151*I Solutions to certain exponential equations are returned in terms of lambert_w:: - sage: S = solve(e^(5*x)+x==0, x, to_poly_solve=True) - sage: z = S[0].rhs(); z + sage: S = solve(e^(5*x)+x==0, x, to_poly_solve=True) # needs sage.symbolic + sage: z = S[0].rhs(); z # needs sage.symbolic -1/5*lambert_w(5) - sage: N(z) + sage: N(z) # needs sage.symbolic -0.265344933048440 Check the defining equation numerically at `z=5`:: - sage: N(lambert_w(5)*exp(lambert_w(5)) - 5) + sage: N(lambert_w(5)*exp(lambert_w(5)) - 5) # needs mpmath 0.000000000000000 There are several special values of the principal branch which are automatically simplified:: - sage: lambert_w(0) + sage: lambert_w(0) # needs mpmath 0 - sage: lambert_w(e) + sage: lambert_w(e) # needs sage.symbolic 1 - sage: lambert_w(-1/e) + sage: lambert_w(-1/e) # needs sage.symbolic -1 Integration (of the principal branch) is evaluated using Maxima:: - sage: integrate(lambert_w(x), x) + sage: integrate(lambert_w(x), x) # needs sage.symbolic (lambert_w(x)^2 - lambert_w(x) + 1)*x/lambert_w(x) - sage: integrate(lambert_w(x), x, 0, 1) + sage: integrate(lambert_w(x), x, 0, 1) # needs sage.symbolic (lambert_w(1)^2 - lambert_w(1) + 1)/lambert_w(1) - 1 - sage: integrate(lambert_w(x), x, 0, 1.0) + sage: integrate(lambert_w(x), x, 0, 1.0) # needs sage.symbolic 0.3303661247616807 Warning: The integral of a non-principal branch is not implemented, neither is numerical integration using GSL. The :meth:`numerical_integral` function does work if you pass a lambda function:: - sage: numerical_integral(lambda x: lambert_w(x), 0, 1) + sage: numerical_integral(lambda x: lambert_w(x), 0, 1) # needs sage.modules (0.33036612476168054, 3.667800782666048e-15) """ @@ -624,27 +651,27 @@ def __init__(self): EXAMPLES:: - sage: lambert_w(0, 1.0) + sage: lambert_w(0, 1.0) # needs scipy 0.567143290409784 - sage: lambert_w(x, x)._sympy_() + sage: lambert_w(x, x)._sympy_() # needs sympy sage.symbolic LambertW(x, x) TESTS: Check that :trac:`25987` is fixed:: - sage: lambert_w(x)._fricas_() # optional - fricas + sage: lambert_w(x)._fricas_() # optional - fricas, needs sage.symbolic lambertW(x) - sage: fricas(lambert_w(x)).eval(x = -1/e) # optional - fricas + sage: fricas(lambert_w(x)).eval(x=-1/e) # optional - fricas, needs sage.symbolic - 1 The two-argument form of Lambert's function is not supported by FriCAS, so we return a generic operator:: - sage: var("n") + sage: var("n") # needs sage.symbolic n - sage: lambert_w(n, x)._fricas_() # optional - fricas + sage: lambert_w(n, x)._fricas_() # optional - fricas, needs sage.symbolic generalizedLambertW(n,x) """ BuiltinFunction.__init__(self, "lambert_w", nargs=2, @@ -662,9 +689,9 @@ def __call__(self, *args, **kwds): EXAMPLES:: - sage: lambert_w(1) + sage: lambert_w(1) # needs sage.symbolic lambert_w(1) - sage: lambert_w(1, 2) + sage: lambert_w(1, 2) # needs sage.symbolic lambert_w(1, 2) """ if len(args) == 2: @@ -678,6 +705,7 @@ def _method_arguments(self, n, z): r""" TESTS:: + sage: # needs sage.libs.flint sage: b = RBF(1, 0.001) sage: lambert_w(b) [0.567 +/- 6.44e-4] @@ -697,29 +725,29 @@ def _eval_(self, n, z): """ EXAMPLES:: - sage: lambert_w(6.0) + sage: lambert_w(6.0) # needs scipy 1.43240477589830 - sage: lambert_w(1) + sage: lambert_w(1) # needs sage.symbolic lambert_w(1) - sage: lambert_w(x+1) + sage: lambert_w(x + 1) # needs sage.symbolic lambert_w(x + 1) There are three special values which are automatically simplified:: - sage: lambert_w(0) + sage: lambert_w(0) # needs mpmath 0 - sage: lambert_w(e) + sage: lambert_w(e) # needs sage.symbolic 1 - sage: lambert_w(-1/e) + sage: lambert_w(-1/e) # needs sage.symbolic -1 - sage: lambert_w(SR(0)) + sage: lambert_w(SR(0)) # needs sage.symbolic 0 The special values only hold on the principal branch:: - sage: lambert_w(1,e) + sage: lambert_w(1, e) # needs sage.symbolic lambert_w(1, e) - sage: lambert_w(1, e.n()) + sage: lambert_w(1, e.n()) # needs sage.symbolic -0.532092121986380 + 4.59715801330257*I TESTS: @@ -728,11 +756,11 @@ def _eval_(self, n, z): value should be either the same as the parent of the input, or a Sage type:: - sage: parent(lambert_w(int(0))) + sage: parent(lambert_w(int(0))) # needs mpmath <... 'int'> - sage: parent(lambert_w(Integer(0))) + sage: parent(lambert_w(Integer(0))) # needs mpmath Integer Ring - sage: parent(lambert_w(e)) + sage: parent(lambert_w(e)) # needs sage.symbolic Symbolic Ring """ if not isinstance(z, Expression): @@ -750,13 +778,14 @@ def _evalf_(self, n, z, parent=None, algorithm=None): """ EXAMPLES:: - sage: N(lambert_w(1)) + sage: N(lambert_w(1)) # needs sage.symbolic 0.567143290409784 - sage: lambert_w(RealField(100)(1)) + sage: lambert_w(RealField(100)(1)) # needs sage.rings.real_mpfr 0.56714329040978387299996866221 SciPy is used to evaluate for float, RDF, and CDF inputs:: + sage: # needs scipy sage: lambert_w(RDF(1)) 0.5671432904097838 sage: lambert_w(float(1)) @@ -772,8 +801,7 @@ def _evalf_(self, n, z, parent=None, algorithm=None): """ R = parent or s_parent(z) if R is float or R is RDF: - from scipy.special import lambertw - res = lambertw(z, n) + res = _scipy_lambertw(z, n) # SciPy always returns a complex value, make it real if possible if not res.imag: return R(res.real) @@ -782,11 +810,9 @@ def _evalf_(self, n, z, parent=None, algorithm=None): else: return CDF(res) elif R is complex or R is CDF: - from scipy.special import lambertw - return R(lambertw(z, n)) + return R(_scipy_lambertw(z, n)) else: - import mpmath - return mpmath_utils.call(mpmath.lambertw, z, n, parent=R) + return _mpmath_utils_call(_mpmath_lambertw, z, n, parent=R) def _derivative_(self, n, z, diff_param=None): r""" @@ -794,19 +820,19 @@ def _derivative_(self, n, z, diff_param=None): EXAMPLES:: - sage: x = var('x') - sage: derivative(lambert_w(x), x) + sage: x = var('x') # needs sage.symbolic + sage: derivative(lambert_w(x), x) # needs sage.symbolic lambert_w(x)/(x*lambert_w(x) + x) - sage: derivative(lambert_w(2, exp(x)), x) + sage: derivative(lambert_w(2, exp(x)), x) # needs sage.symbolic e^x*lambert_w(2, e^x)/(e^x*lambert_w(2, e^x) + e^x) TESTS: Differentiation in the first parameter raises an error :trac:`14788`:: - sage: n = var('n') - sage: lambert_w(n, x).diff(n) + sage: n = var('n') # needs sage.symbolic + sage: lambert_w(n, x).diff(n) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate lambert_w in the first parameter @@ -822,16 +848,16 @@ def _maxima_init_evaled_(self, n, z): These are indirect doctests for this function.:: - sage: lambert_w(0, x)._maxima_() + sage: lambert_w(0, x)._maxima_() # needs sage.symbolic lambert_w(_SAGE_VAR_x) - sage: lambert_w(1, x)._maxima_() + sage: lambert_w(1, x)._maxima_() # needs sage.symbolic generalized_lambert_w(1,_SAGE_VAR_x) TESTS:: - sage: lambert_w(x)._maxima_()._sage_() + sage: lambert_w(x)._maxima_()._sage_() # needs sage.symbolic lambert_w(x) - sage: lambert_w(2, x)._maxima_()._sage_() + sage: lambert_w(2, x)._maxima_()._sage_() # needs sage.symbolic lambert_w(2, x) """ if isinstance(z, str): @@ -852,9 +878,9 @@ def _print_(self, n, z): EXAMPLES:: - sage: lambert_w(1) + sage: lambert_w(1) # needs sage.symbolic lambert_w(1) - sage: lambert_w(0,x) + sage: lambert_w(0, x) # needs sage.symbolic lambert_w(x) """ if n == 0: @@ -869,13 +895,14 @@ def _print_latex_(self, n, z): EXAMPLES:: + sage: # needs sage.symbolic sage: latex(lambert_w(1)) \operatorname{W}({1}) - sage: latex(lambert_w(0,x)) + sage: latex(lambert_w(0, x)) \operatorname{W}({x}) - sage: latex(lambert_w(1,x)) + sage: latex(lambert_w(1, x)) \operatorname{W_{1}}({x}) - sage: latex(lambert_w(1,x+exp(x))) + sage: latex(lambert_w(1, x + exp(x))) \operatorname{W_{1}}({x + e^{x}}) """ if n == 0: @@ -908,23 +935,23 @@ def __init__(self): The following expressions are evaluated using the exponential function:: - sage: exp_polar(pi*I/2) + sage: exp_polar(pi*I/2) # needs sage.symbolic I - sage: x = var('x', domain='real') - sage: exp_polar(-1/2*I*pi + x) + sage: x = var('x', domain='real') # needs sage.symbolic + sage: exp_polar(-1/2*I*pi + x) # needs sage.symbolic e^(-1/2*I*pi + x) The function is left unevaluated when the imaginary part of the input `z` does not satisfy `-\pi < \Im(z) \leq \pi`:: - sage: exp_polar(2*pi*I) + sage: exp_polar(2*pi*I) # needs sage.symbolic exp_polar(2*I*pi) - sage: exp_polar(-4*pi*I) + sage: exp_polar(-4*pi*I) # needs sage.symbolic exp_polar(-4*I*pi) This fixes :trac:`18085`:: - sage: integrate(1/sqrt(1+x^3),x,algorithm='sympy') + sage: integrate(1/sqrt(1+x^3), x, algorithm='sympy') # needs sage.symbolic 1/3*x*gamma(1/3)*hypergeometric((1/3, 1/2), (4/3,), -x^3)/gamma(4/3) @@ -948,25 +975,23 @@ def _evalf_(self, z, parent=None, algorithm=None): If the imaginary part of `z` obeys `-\pi < z \leq \pi`, then `\operatorname{exp\_polar}(z)` is evaluated as `\exp(z)`:: - sage: exp_polar(1.0 + 2.0*I) + sage: exp_polar(1.0 + 2.0*I) # needs sage.symbolic -1.13120438375681 + 2.47172667200482*I If the imaginary part of `z` is outside of that interval the expression is left unevaluated:: - sage: exp_polar(-5.0 + 8.0*I) + sage: exp_polar(-5.0 + 8.0*I) # needs sage.symbolic exp_polar(-5.00000000000000 + 8.00000000000000*I) An attempt to numerically evaluate such an expression raises an error:: - sage: exp_polar(-5.0 + 8.0*I).n() + sage: exp_polar(-5.0 + 8.0*I).n() # needs sage.symbolic Traceback (most recent call last): ... ValueError: invalid attempt to numerically evaluate exp_polar() """ - from sage.functions.other import imag - if (not isinstance(z, Expression) and bool(-const_pi < imag(z) <= const_pi)): return exp(z) @@ -977,17 +1002,17 @@ def _eval_(self, z): """ EXAMPLES:: - sage: exp_polar(3*I*pi) + sage: exp_polar(3*I*pi) # needs sage.symbolic exp_polar(3*I*pi) - sage: x = var('x', domain='real') - sage: exp_polar(4*I*pi + x) + sage: x = var('x', domain='real') # needs sage.symbolic + sage: exp_polar(4*I*pi + x) # needs sage.symbolic exp_polar(4*I*pi + x) TESTS: Check that :trac:`24441` is fixed:: - sage: exp_polar(arcsec(jacobi_sn(1.1*I*x, x))) # should be fast + sage: exp_polar(arcsec(jacobi_sn(1.1*I*x, x))) # should be fast # needs sage.symbolic exp_polar(arcsec(jacobi_sn(1.10000000000000*I*x, x))) """ try: @@ -1021,7 +1046,7 @@ class Function_harmonic_number_generalized(BuiltinFunction): H_{s,m}=\zeta(m)-\zeta(m,s-1) If called with a single argument, that argument is ``s`` and ``m`` is - assumed to be 1 (the normal harmonic numbers ``H_s``). + assumed to be 1 (the normal harmonic numbers `H_s`). ALGORITHM: @@ -1035,42 +1060,44 @@ class Function_harmonic_number_generalized(BuiltinFunction): Evaluation of integer, rational, or complex argument:: - sage: harmonic_number(5) + sage: harmonic_number(5) # needs mpmath 137/60 - sage: harmonic_number(3,3) + + sage: # needs sage.symbolic + sage: harmonic_number(3, 3) 251/216 sage: harmonic_number(5/2) -2*log(2) + 46/15 - sage: harmonic_number(3.,3) + sage: harmonic_number(3., 3) zeta(3) - 0.0400198661225573 - sage: harmonic_number(3.,3.) + sage: harmonic_number(3., 3.) 1.16203703703704 - sage: harmonic_number(3,3).n(200) + sage: harmonic_number(3, 3).n(200) 1.16203703703703703703703... - sage: harmonic_number(1+I,5) + sage: harmonic_number(1 + I, 5) harmonic_number(I + 1, 5) - sage: harmonic_number(5,1.+I) + sage: harmonic_number(5, 1. + I) 1.57436810798989 - 1.06194728851357*I Solutions to certain sums are returned in terms of harmonic numbers:: - sage: k=var('k') - sage: sum(1/k^7,k,1,x) + sage: k = var('k') # needs sage.symbolic + sage: sum(1/k^7,k,1,x) # needs sage.symbolic harmonic_number(x, 7) Check the defining integral at a random integer:: - sage: n=randint(10,100) - sage: bool(SR(integrate((1-x^n)/(1-x),x,0,1)) == harmonic_number(n)) + sage: n = randint(10,100) + sage: bool(SR(integrate((1-x^n)/(1-x),x,0,1)) == harmonic_number(n)) # needs sage.symbolic True There are several special values which are automatically simplified:: - sage: harmonic_number(0) + sage: harmonic_number(0) # needs mpmath 0 - sage: harmonic_number(1) + sage: harmonic_number(1) # needs mpmath 1 - sage: harmonic_number(x,1) + sage: harmonic_number(x, 1) # needs sage.symbolic harmonic_number(x) """ @@ -1078,9 +1105,9 @@ def __init__(self): r""" EXAMPLES:: - sage: loads(dumps(harmonic_number(x,5))) + sage: loads(dumps(harmonic_number(x, 5))) # needs sage.symbolic harmonic_number(x, 5) - sage: harmonic_number(x, x)._sympy_() + sage: harmonic_number(x, x)._sympy_() # needs sympy sage.symbolic harmonic(x, x) """ BuiltinFunction.__init__(self, "harmonic_number", nargs=2, @@ -1089,15 +1116,15 @@ def __init__(self): def __call__(self, z, m=1, **kwds): r""" Custom call method allows the user to pass one argument or two. If - one argument is passed, we assume it is ``z`` and that ``m=1``. + one argument is passed, we assume it is ``z`` and that `m=1`. EXAMPLES:: - sage: harmonic_number(x) + sage: harmonic_number(x) # needs sage.symbolic harmonic_number(x) - sage: harmonic_number(x,1) + sage: harmonic_number(x, 1) # needs sage.symbolic harmonic_number(x) - sage: harmonic_number(x,2) + sage: harmonic_number(x, 2) # needs sage.symbolic harmonic_number(x, 2) """ return BuiltinFunction.__call__(self, z, m, **kwds) @@ -1106,30 +1133,32 @@ def _eval_(self, z, m): """ EXAMPLES:: - sage: harmonic_number(x,0) + sage: harmonic_number(5) # needs mpmath + 137/60 + + sage: # needs sage.symbolic + sage: harmonic_number(x, 0) x - sage: harmonic_number(x,1) + sage: harmonic_number(x, 1) harmonic_number(x) - sage: harmonic_number(5) - 137/60 - sage: harmonic_number(3,3) + sage: harmonic_number(3, 3) 251/216 - sage: harmonic_number(3,3).n() # this goes from rational to float + sage: harmonic_number(3, 3).n() # this goes from rational to float 1.16203703703704 - sage: harmonic_number(3,3.) # the following uses zeta functions + sage: harmonic_number(3, 3.) # the following uses zeta functions 1.16203703703704 - sage: harmonic_number(3.,3) + sage: harmonic_number(3., 3) zeta(3) - 0.0400198661225573 - sage: harmonic_number(0.1,5) + sage: harmonic_number(0.1, 5) zeta(5) - 0.650300133161038 - sage: harmonic_number(0.1,5).n() + sage: harmonic_number(0.1, 5).n() 0.386627621982332 - sage: harmonic_number(3,5/2) + sage: harmonic_number(3, 5/2) 1/27*sqrt(3) + 1/8*sqrt(2) + 1 TESTS:: - sage: harmonic_number(int(3), int(3)) + sage: harmonic_number(int(3), int(3)) # needs sage.symbolic 1.162037037037037 """ if m == 0: @@ -1144,13 +1173,14 @@ def _evalf_(self, z, m, parent=None, algorithm=None): """ EXAMPLES:: - sage: harmonic_number(3.,3) + sage: # needs sage.symbolic + sage: harmonic_number(3., 3) zeta(3) - 0.0400198661225573 - sage: harmonic_number(3.,3.) + sage: harmonic_number(3., 3.) 1.16203703703704 - sage: harmonic_number(3,3).n(200) + sage: harmonic_number(3, 3).n(200) 1.16203703703703703703703... - sage: harmonic_number(5,I).n() + sage: harmonic_number(5, I).n() 2.36889632899995 - 3.51181956521611*I """ if m == 0: @@ -1160,16 +1190,15 @@ def _evalf_(self, z, m, parent=None, algorithm=None): elif m == 1: return harmonic_m1._evalf_(z, parent, algorithm) - from sage.functions.transcendental import zeta, hurwitz_zeta return zeta(m) - hurwitz_zeta(m, z + 1) def _maxima_init_evaled_(self, n, z): """ EXAMPLES:: - sage: maxima_calculus(harmonic_number(x,2)) + sage: maxima_calculus(harmonic_number(x, 2)) # needs sage.symbolic gen_harmonic_number(2,_SAGE_VAR_x) - sage: maxima_calculus(harmonic_number(3,harmonic_number(x,3),hold=True)) + sage: maxima_calculus(harmonic_number(3, harmonic_number(x,3), hold=True)) # needs sage.symbolic 1/3^gen_harmonic_number(3,_SAGE_VAR_x)+1/2^gen_harmonic_number(3,_SAGE_VAR_x)+1 """ if isinstance(n, str): @@ -1192,6 +1221,7 @@ def _derivative_(self, n, m, diff_param=None): EXAMPLES:: + sage: # needs sage.symbolic sage: k,m,n = var('k,m,n') sage: sum(1/k, k, 1, x).diff(x) 1/6*pi^2 - harmonic_number(x, 2) @@ -1204,7 +1234,6 @@ def _derivative_(self, n, m, diff_param=None): ... ValueError: cannot differentiate harmonic_number in the second parameter """ - from sage.functions.transcendental import zeta if diff_param == 1: raise ValueError("cannot differentiate harmonic_number in the second parameter") if m == 1: @@ -1216,9 +1245,9 @@ def _print_(self, z, m): """ EXAMPLES:: - sage: harmonic_number(x) + sage: harmonic_number(x) # needs sage.symbolic harmonic_number(x) - sage: harmonic_number(x,2) + sage: harmonic_number(x, 2) # needs sage.symbolic harmonic_number(x, 2) """ if m == 1: @@ -1230,9 +1259,9 @@ def _print_latex_(self, z, m): """ EXAMPLES:: - sage: latex(harmonic_number(x)) + sage: latex(harmonic_number(x)) # needs sage.symbolic H_{x} - sage: latex(harmonic_number(x,2)) + sage: latex(harmonic_number(x, 2)) # needs sage.symbolic H_{{x},{2}} """ if m == 1: @@ -1250,13 +1279,14 @@ class _Function_swap_harmonic(BuiltinFunction): EXAMPLES:: - sage: maxima(harmonic_number(x,2)) # maxima expect interface + sage: # needs sage.symbolic + sage: maxima(harmonic_number(x, 2)) # maxima expect interface gen_harmonic_number(2,_SAGE_VAR_x) sage: from sage.calculus.calculus import symbolic_expression_from_maxima_string as sefms sage: sefms('gen_harmonic_number(3,x)') harmonic_number(x, 3) sage: from sage.interfaces.maxima_lib import maxima_lib, max_to_sr - sage: c=maxima_lib(harmonic_number(x,2)); c + sage: c = maxima_lib(harmonic_number(x,2)); c gen_harmonic_number(2,_SAGE_VAR_x) sage: max_to_sr(c.ecl()) harmonic_number(x, 2) @@ -1294,10 +1324,10 @@ def __init__(self): r""" EXAMPLES:: - sage: k=var('k') - sage: loads(dumps(sum(1/k,k,1,x))) + sage: k = var('k') # needs sage.symbolic + sage: loads(dumps(sum(1/k, k, 1, x))) # needs sage.symbolic harmonic_number(x) - sage: harmonic_number(x)._sympy_() + sage: harmonic_number(x)._sympy_() # needs sympy sage.symbolic harmonic(x) """ BuiltinFunction.__init__(self, "harmonic_number", nargs=1, @@ -1310,15 +1340,15 @@ def _eval_(self, z, **kwds): """ EXAMPLES:: - sage: harmonic_number(0) + sage: harmonic_number(0) # needs mpmath 0 - sage: harmonic_number(1) + sage: harmonic_number(1) # needs mpmath 1 - sage: harmonic_number(20) + sage: harmonic_number(20) # needs mpmath 55835135/15519504 - sage: harmonic_number(5/2) + sage: harmonic_number(5/2) # needs sage.symbolic -2*log(2) + 46/15 - sage: harmonic_number(2*x) + sage: harmonic_number(2*x) # needs sage.symbolic harmonic_number(2*x) """ if z in ZZ: @@ -1327,28 +1357,25 @@ def _eval_(self, z, **kwds): elif z == 1: return Integer(1) elif z > 1: - import sage.libs.flint.arith as flint_arith - return flint_arith.harmonic_number(z) + return _flint_harmonic_number(z) elif z in QQ: - from .gamma import psi1 return psi1(z + 1) - psi1(1) def _evalf_(self, z, parent=None, algorithm='mpmath'): """ EXAMPLES:: - sage: harmonic_number(20).n() # this goes from rational to float + sage: # needs mpmath + sage: harmonic_number(20).n() # this goes from rational to float 3.59773965714368 sage: harmonic_number(20).n(200) 3.59773965714368191148376906... - sage: harmonic_number(20.) # this computes the integral with mpmath + sage: harmonic_number(20.) # this computes the integral with mpmath 3.59773965714368 - sage: harmonic_number(1.0*I) + sage: harmonic_number(1.0*I) # needs sage.symbolic 0.671865985524010 + 1.07667404746858*I """ - from sage.libs.mpmath import utils as mpmath_utils - import mpmath - return mpmath_utils.call(mpmath.harmonic, z, parent=parent) + return _mpmath_utils_call(_mpmath_harmonic, z, parent=parent) def _derivative_(self, z, diff_param=None): """ @@ -1356,19 +1383,18 @@ def _derivative_(self, z, diff_param=None): EXAMPLES:: - sage: k=var('k') - sage: sum(1/k,k,1,x).diff(x) + sage: k = var('k') # needs sage.symbolic + sage: sum(1/k, k, 1, x).diff(x) # needs sage.symbolic 1/6*pi^2 - harmonic_number(x, 2) """ - from sage.functions.transcendental import zeta return zeta(2) - harmonic_number(z, 2) def _print_latex_(self, z): """ EXAMPLES:: - sage: k=var('k') - sage: latex(sum(1/k,k,1,x)) + sage: k = var('k') # needs sage.symbolic + sage: latex(sum(1/k, k, 1, x)) # needs sage.symbolic H_{x} """ return r"H_{%s}" % z diff --git a/src/sage/functions/min_max.py b/src/sage/functions/min_max.py index 28419136e52..caaed6f1193 100644 --- a/src/sage/functions/min_max.py +++ b/src/sage/functions/min_max.py @@ -7,15 +7,16 @@ Here you can see some differences:: - sage: max(x, x^2) + sage: max(x, x^2) # needs sage.symbolic x - sage: max_symbolic(x, x^2) + sage: max_symbolic(x, x^2) # needs sage.symbolic max(x, x^2) - sage: f(x) = max_symbolic(x, x^2); f(1/2) + sage: f(x) = max_symbolic(x, x^2); f(1/2) # needs sage.symbolic 1/2 This works as expected for more than two entries:: + sage: # needs sage.symbolic sage: max(3, 5, x) 5 sage: min(3, 5, x) @@ -33,11 +34,13 @@ # https://www.gnu.org/licenses/ ############################################################################### +from builtins import max as builtin_max, min as builtin_min + +from sage.misc.lazy_import import lazy_import +from sage.structure.element import Expression from sage.symbolic.function import BuiltinFunction -from sage.symbolic.expression import Expression -from sage.symbolic.ring import SR -from builtins import max as builtin_max, min as builtin_min +lazy_import('sage.symbolic.ring', 'SR') class MinMax_base(BuiltinFunction): @@ -45,6 +48,7 @@ def eval_helper(self, this_f, builtin_f, initial_val, args): """ EXAMPLES:: + sage: # needs sage.symbolic sage: max_symbolic(3, 5, x) # indirect doctest max(x, 5) sage: max_symbolic([5.0r]) # indirect doctest @@ -89,20 +93,20 @@ def __call__(self, *args, **kwds): """ EXAMPLES:: - sage: max_symbolic(3, 5, x) + sage: max_symbolic(3, 5, x) # needs sage.symbolic max(x, 5) - sage: max_symbolic(3, 5, x, hold=True) + sage: max_symbolic(3, 5, x, hold=True) # needs sage.symbolic max(3, 5, x) - sage: max_symbolic([3, 5, x]) + sage: max_symbolic([3, 5, x]) # needs sage.symbolic max(x, 5) :: - sage: min_symbolic(3, 5, x) + sage: min_symbolic(3, 5, x) # needs sage.symbolic min(x, 3) - sage: min_symbolic(3, 5, x, hold=True) + sage: min_symbolic(3, 5, x, hold=True) # needs sage.symbolic min(3, 5, x) - sage: min_symbolic([3, 5, x]) + sage: min_symbolic([3, 5, x]) # needs sage.symbolic min(x, 3) TESTS: @@ -116,6 +120,7 @@ def __call__(self, *args, **kwds): Check if a single argument which is not iterable works:: + sage: # needs sage.symbolic sage: max_symbolic(None) Traceback (most recent call last): ... @@ -162,6 +167,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: max_symbolic(3, x) max(3, x) sage: max_symbolic(3, x).subs(x=5) @@ -173,11 +179,11 @@ def __init__(self): TESTS:: - sage: loads(dumps(max_symbolic(x, 5))) + sage: loads(dumps(max_symbolic(x, 5))) # needs sage.symbolic max(x, 5) - sage: latex(max_symbolic(x, 5)) + sage: latex(max_symbolic(x, 5)) # needs sage.symbolic \max\left(x, 5\right) - sage: max_symbolic(x, 5)._sympy_() + sage: max_symbolic(x, 5)._sympy_() # needs sympy sage.symbolic Max(5, x) """ BuiltinFunction.__init__(self, 'max', nargs=0, latex_name=r"\max", @@ -187,6 +193,7 @@ def _eval_(self, *args): """ EXAMPLES:: + sage: # needs sage.symbolic sage: t = max_symbolic(x, 5); t max(x, 5) sage: t.subs(x=3) # indirect doctest @@ -215,6 +222,7 @@ def _evalf_(self, *args, **kwds): """ EXAMPLES:: + sage: # needs sage.symbolic sage: t = max_symbolic(sin(x), cos(x)) sage: t.subs(x=1).n(200) 0.84147098480789650665250232163029899962256306079837106567275 @@ -231,10 +239,10 @@ def _evalf_(self, *args, **kwds): We can usually integrate these expressions, but can't guarantee a symbolic answer in closed form:: - sage: f = max_symbolic(sin(x), cos(x)) - sage: r = integral(f, x, 0, 1) + sage: f = max_symbolic(sin(x), cos(x)) # needs sage.symbolic + sage: r = integral(f, x, 0, 1) # needs sage.symbolic ... - sage: r.n() # abs tol 1e-8 + sage: r.n() # abs tol 1e-8 # needs sage.symbolic 0.873911256504955 """ return max_symbolic(args) @@ -254,6 +262,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: min_symbolic(3, x) min(3, x) sage: min_symbolic(3, x).subs(x=5) @@ -265,11 +274,11 @@ def __init__(self): TESTS:: - sage: loads(dumps(min_symbolic(x, 5))) + sage: loads(dumps(min_symbolic(x, 5))) # needs sage.symbolic min(x, 5) - sage: latex(min_symbolic(x, 5)) + sage: latex(min_symbolic(x, 5)) # needs sage.symbolic \min\left(x, 5\right) - sage: min_symbolic(x, 5)._sympy_() + sage: min_symbolic(x, 5)._sympy_() # needs sympy sage.symbolic Min(5, x) """ BuiltinFunction.__init__(self, 'min', nargs=0, latex_name=r"\min", @@ -279,6 +288,7 @@ def _eval_(self, *args): """ EXAMPLES:: + sage: # needs sage.symbolic sage: t = min_symbolic(x, 5); t min(x, 5) sage: t.subs(x=3) # indirect doctest @@ -307,6 +317,7 @@ def _evalf_(self, *args, **kwds): """ EXAMPLES:: + sage: # needs sage.symbolic sage: t = min_symbolic(sin(x), cos(x)) sage: t.subs(x=1).n(200) 0.54030230586813971740093660744297660373231042061792222767010 diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 7398c763971..7a9322973ad 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -395,20 +395,33 @@ import warnings -from sage.misc.latex import latex -from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ -from sage.rings.real_mpfr import RR -from sage.rings.cc import CC -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing import sage.rings.abc -from sage.symbolic.function import BuiltinFunction, GinacFunction -from sage.symbolic.expression import Expression -from sage.symbolic.ring import SR -from sage.functions.other import factorial, binomial -from sage.structure.element import parent from sage.arith.misc import rising_factorial +from sage.misc.lazy_import import lazy_import +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.symbolic.function import BuiltinFunction, GinacFunction +from sage.structure.element import Expression, parent + +lazy_import('sage.functions.other', ['factorial', 'binomial']) + +lazy_import('sage.misc.latex', 'latex') +lazy_import('sage.rings.cc', 'CC') +lazy_import('sage.rings.polynomial.polynomial_ring_constructor', 'PolynomialRing') +lazy_import('sage.rings.real_mpfr', 'RR') + +lazy_import('sage.symbolic.ring', 'SR') +lazy_import('sage.calculus.calculus', 'maxima', as_='_maxima') + +lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') +lazy_import('sage.libs.mpmath.all', 'chebyt', as_='_mpmath_chebyt') +lazy_import('sage.libs.mpmath.all', 'chebyu', as_='_mpmath_chebyu') +lazy_import('sage.libs.mpmath.all', 'laguerre', as_='_mpmath_laguerre') +lazy_import('sage.libs.mpmath.all', 'legenp', as_='_mpmath_legenp') +lazy_import('sage.libs.mpmath.all', 'legenq', as_='_mpmath_legenq') + +lazy_import('scipy.special', 'eval_chebyu', as_='_scipy_chebyu') class OrthogonalFunction(BuiltinFunction): @@ -466,9 +479,9 @@ def _eval_special_values_(self, *args): EXAMPLES:: - sage: var('n') + sage: var('n') # needs sage.symbolic n - sage: chebyshev_T(n,-1) + sage: chebyshev_T(n, -1) # needs sage.symbolic (-1)^n """ raise ValueError("no special values known") @@ -480,9 +493,9 @@ def _eval_(self, n, *args): EXAMPLES:: - sage: var('n,x') + sage: var('n,x') # needs sage.symbolic (n, x) - sage: chebyshev_T(5,x) + sage: chebyshev_T(5, x) # needs sage.symbolic 16*x^5 - 20*x^3 + 5*x """ return None @@ -497,9 +510,10 @@ def __call__(self, *args, **kwds): EXAMPLES:: + sage: # needs sage.symbolic sage: chebyshev_T(5, x) 16*x^5 - 20*x^3 + 5*x - sage: chebyshev_T(5, x, algorithm='pari') + sage: chebyshev_T(5, x, algorithm='pari') # needs sage.libs.pari 16*x^5 - 20*x^3 + 5*x sage: chebyshev_T(5, x, algorithm='maxima') 16*x^5 - 20*x^3 + 5*x @@ -512,9 +526,8 @@ def __call__(self, *args, **kwds): elif algorithm == 'recursive': return self.eval_recursive(*args, **kwds) elif algorithm == 'maxima': - from sage.calculus.calculus import maxima kwds['hold'] = True - return maxima(self._eval_(*args, **kwds))._sage_() + return _maxima(self._eval_(*args, **kwds))._sage_() return super(OrthogonalFunction, self).__call__(*args, **kwds) @@ -525,7 +538,7 @@ class ChebyshevFunction(OrthogonalFunction): EXAMPLES:: - sage: chebyshev_T(3,x) + sage: chebyshev_T(3, x) # needs sage.symbolic 4*x^3 - 3*x """ def __call__(self, n, *args, **kwds): @@ -538,16 +551,17 @@ def __call__(self, n, *args, **kwds): EXAMPLES:: - sage: K.<a> = NumberField(x^3-x-1) - sage: chebyshev_T(5, a) + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField(x^3 - x - 1) # needs sage.rings.number_field + sage: chebyshev_T(5, a) # needs sage.rings.number_field 16*a^2 + a - 4 - sage: chebyshev_T(5,MatrixSpace(ZZ, 2)([1, 2, -4, 7])) + sage: chebyshev_T(5, MatrixSpace(ZZ, 2)([1, 2, -4, 7])) # needs sage.modules [-40799 44162] [-88324 91687] sage: R.<x> = QQ[] sage: parent(chebyshev_T(5, x)) Univariate Polynomial Ring in x over Rational Field - sage: chebyshev_T(5, 2, hold=True) + sage: chebyshev_T(5, 2, hold=True) # needs sage.symbolic chebyshev_T(5, 2) sage: chebyshev_T(1,2,3) Traceback (most recent call last): @@ -570,18 +584,20 @@ def _eval_(self, n, x): EXAMPLES:: + sage: # needs sage.symbolic sage: var('n,x') (n, x) - sage: chebyshev_T(5,x) + sage: chebyshev_T(5, x) 16*x^5 - 20*x^3 + 5*x sage: chebyshev_T(64, x) 2*(2*(2*(2*(2*(2*x^2 - 1)^2 - 1)^2 - 1)^2 - 1)^2 - 1)^2 - 1 - sage: chebyshev_T(n,-1) + sage: chebyshev_T(n, -1) (-1)^n - sage: chebyshev_T(-7,x) + sage: chebyshev_T(-7, x) 64*x^7 - 112*x^5 + 56*x^3 - 7*x - sage: chebyshev_T(3/2,x) + sage: chebyshev_T(3/2, x) chebyshev_T(3/2, x) + sage: R.<t> = QQ[] sage: chebyshev_T(2,t) 2*t^2 - 1 @@ -589,14 +605,14 @@ def _eval_(self, n, x): 4*t^2 - 1 sage: parent(chebyshev_T(4, RIF(5))) Real Interval Field with 53 bits of precision - sage: RR2 = RealField(5) - sage: chebyshev_T(100000,RR2(2)) + sage: RR2 = RealField(5) # needs sage.rings.real_mpfr + sage: chebyshev_T(100000, RR2(2)) # needs sage.rings.real_mpfr 8.9e57180 - sage: chebyshev_T(5,Qp(3)(2)) + sage: chebyshev_T(5, Qp(3)(2)) # needs sage.rings.padics 2 + 3^2 + 3^3 + 3^4 + 3^5 + O(3^20) - sage: chebyshev_T(100001/2, 2) + sage: chebyshev_T(100001/2, 2) # needs sage.symbolic ...chebyshev_T(100001/2, 2) - sage: chebyshev_U._eval_(1.5, Mod(8,9)) is None + sage: chebyshev_U._eval_(1.5, Mod(8,9)) is None # needs mpmath True """ # n is an integer => evaluate algebraically (as polynomial) @@ -639,12 +655,11 @@ class Func_chebyshev_T(ChebyshevFunction): EXAMPLES:: - sage: chebyshev_T(5,x) + sage: chebyshev_T(5, x) # needs sage.symbolic 16*x^5 - 20*x^3 + 5*x - sage: var('k') + sage: var('k') # needs sage.symbolic k - sage: test = chebyshev_T(k,x) - sage: test + sage: test = chebyshev_T(k, x); test # needs sage.symbolic chebyshev_T(k, x) """ def __init__(self): @@ -653,15 +668,16 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: var('n, x') (n, x) sage: from sage.functions.orthogonal_polys import Func_chebyshev_T sage: chebyshev_T2 = Func_chebyshev_T() - sage: chebyshev_T2(1,x) + sage: chebyshev_T2(1, x) x - sage: chebyshev_T(x, x)._sympy_() + sage: chebyshev_T(x, x)._sympy_() # needs sympy chebyshevt(x, x) - sage: maxima(chebyshev_T(1,x, hold=True)) + sage: maxima(chebyshev_T(1, x, hold=True)) _SAGE_VAR_x sage: maxima(chebyshev_T(n, chebyshev_T(n, x))) chebyshev_t(_SAGE_VAR_n,chebyshev_t(_SAGE_VAR_n,_SAGE_VAR_x)) @@ -685,7 +701,7 @@ def _print_latex_(self, n, z): r""" TESTS:: - sage: latex(chebyshev_T(3, x, hold=True)) + sage: latex(chebyshev_T(3, x, hold=True)) # needs sage.symbolic T_{3}\left(x\right) """ return r"T_{{{}}}\left({}\right)".format(latex(n), latex(z)) @@ -697,15 +713,16 @@ def _eval_special_values_(self, n, x): EXAMPLES:: + sage: # needs sage.symbolic sage: var('n') n - sage: chebyshev_T(n,1) + sage: chebyshev_T(n, 1) 1 - sage: chebyshev_T(n,0) + sage: chebyshev_T(n, 0) 1/2*(-1)^(1/2*n)*((-1)^n + 1) - sage: chebyshev_T(n,-1) + sage: chebyshev_T(n, -1) (-1)^n - sage: chebyshev_T._eval_special_values_(3/2,x) + sage: chebyshev_T._eval_special_values_(3/2, x) Traceback (most recent call last): ... ValueError: no special value found @@ -731,13 +748,14 @@ def _evalf_(self, n, x, **kwds): EXAMPLES:: - sage: chebyshev_T._evalf_(10,3) + sage: # needs sage.rings.real_mpfr + sage: chebyshev_T._evalf_(10, 3) 2.26195370000000e7 - sage: chebyshev_T._evalf_(10,3,parent=RealField(75)) + sage: chebyshev_T._evalf_(10, 3, parent=RealField(75)) 2.261953700000000000000e7 - sage: chebyshev_T._evalf_(10,I) + sage: chebyshev_T._evalf_(10, I) # needs sage.symbolic -3363.00000000000 - sage: chebyshev_T._evalf_(5,0.3) + sage: chebyshev_T._evalf_(5, 0.3) 0.998880000000000 sage: chebyshev_T(1/2, 0) 0.707106781186548 @@ -750,15 +768,15 @@ def _evalf_(self, n, x, **kwds): This simply evaluates using :class:`RealField` or :class:`ComplexField`:: - sage: chebyshev_T(1234.5, RDF(2.1)) + sage: chebyshev_T(1234.5, RDF(2.1)) # needs sage.rings.real_mpfr 5.48174256255782e735 - sage: chebyshev_T(1234.5, I) + sage: chebyshev_T(1234.5, I) # needs sage.rings.real_mpfr sage.symbolic -1.21629397684152e472 - 1.21629397684152e472*I For large values of ``n``, mpmath fails (but the algebraic formula still works):: - sage: chebyshev_T._evalf_(10^6, 0.1) + sage: chebyshev_T._evalf_(10^6, 0.1) # needs sage.rings.real_mpfr Traceback (most recent call last): ... NoConvergence: Hypergeometric series converges too slowly. Try increasing maxterms. @@ -782,10 +800,7 @@ def _evalf_(self, n, x, **kwds): if not isinstance(real_parent, (sage.rings.abc.RealField, sage.rings.abc.ComplexField)): raise TypeError("cannot evaluate chebyshev_T with parent {}".format(real_parent)) - from sage.libs.mpmath.all import call as mpcall - from sage.libs.mpmath.all import chebyt as mpchebyt - - return mpcall(mpchebyt, n, x, parent=real_parent) + return _mpmath_utils_call(_mpmath_chebyt, n, x, parent=real_parent) def eval_formula(self, n, x): """ @@ -802,18 +817,20 @@ def eval_formula(self, n, x): EXAMPLES:: - sage: chebyshev_T.eval_formula(-1,x) + sage: # needs sage.symbolic + sage: chebyshev_T.eval_formula(-1, x) x - sage: chebyshev_T.eval_formula(0,x) + sage: chebyshev_T.eval_formula(0, x) 1 - sage: chebyshev_T.eval_formula(1,x) + sage: chebyshev_T.eval_formula(1, x) x - sage: chebyshev_T.eval_formula(2,0.1) == chebyshev_T._evalf_(2,0.1) - True - sage: chebyshev_T.eval_formula(10,x) + sage: chebyshev_T.eval_formula(10, x) 512*x^10 - 1280*x^8 + 1120*x^6 - 400*x^4 + 50*x^2 - 1 - sage: chebyshev_T.eval_algebraic(10,x).expand() + sage: chebyshev_T.eval_algebraic(10, x).expand() 512*x^10 - 1280*x^8 + 1120*x^6 - 400*x^4 + 50*x^2 - 1 + + sage: chebyshev_T.eval_formula(2, 0.1) == chebyshev_T._evalf_(2, 0.1) # needs sage.rings.complex_double + True """ if n < 0: return self.eval_formula(-n, x) @@ -841,9 +858,9 @@ def eval_algebraic(self, n, x): EXAMPLES:: - sage: chebyshev_T.eval_algebraic(5, x) + sage: chebyshev_T.eval_algebraic(5, x) # needs sage.symbolic 2*(2*(2*x^2 - 1)*x - x)*(2*x^2 - 1) - x - sage: chebyshev_T(-7, x) - chebyshev_T(7,x) + sage: chebyshev_T(-7, x) - chebyshev_T(7, x) # needs sage.symbolic 0 sage: R.<t> = ZZ[] sage: chebyshev_T.eval_algebraic(-1, t) @@ -856,12 +873,15 @@ def eval_algebraic(self, n, x): 1/2 sage: chebyshev_T(7^100, Mod(2,3)) 2 - sage: n = 97; x = RIF(pi/2/n) - sage: chebyshev_T(n, cos(x)).contains_zero() + sage: n = 97; x = RIF(pi/2/n) # needs sage.symbolic + sage: chebyshev_T(n, cos(x)).contains_zero() # needs sage.symbolic True + + sage: # needs sage.rings.padics sage: R.<t> = Zp(2, 8, 'capped-abs')[] - sage: chebyshev_T(10^6+1, t) - (2^7 + O(2^8))*t^5 + O(2^8)*t^4 + (2^6 + O(2^8))*t^3 + O(2^8)*t^2 + (1 + 2^6 + O(2^8))*t + O(2^8) + sage: chebyshev_T(10^6 + 1, t) + (2^7 + O(2^8))*t^5 + O(2^8)*t^4 + (2^6 + O(2^8))*t^3 + O(2^8)*t^2 + + (1 + 2^6 + O(2^8))*t + O(2^8) """ if n == 0: return parent(x).one() @@ -877,9 +897,9 @@ def _eval_recursive_(self, n, x, both=False): EXAMPLES:: - sage: chebyshev_T._eval_recursive_(5, x) + sage: chebyshev_T._eval_recursive_(5, x) # needs sage.symbolic (2*(2*(2*x^2 - 1)*x - x)*(2*x^2 - 1) - x, False) - sage: chebyshev_T._eval_recursive_(5, x, True) + sage: chebyshev_T._eval_recursive_(5, x, True) # needs sage.symbolic (2*(2*(2*x^2 - 1)*x - x)*(2*x^2 - 1) - x, 2*(2*x^2 - 1)^2 - 1) """ if n == 1: @@ -898,6 +918,7 @@ def _eval_numpy_(self, n, x): EXAMPLES:: + sage: # needs numpy scipy sage: import numpy sage: z = numpy.array([1,2]) sage: z2 = numpy.array([[1,2],[1,2]]) @@ -922,13 +943,14 @@ def _derivative_(self, n, x, diff_param): EXAMPLES:: + sage: # needs sage.symbolic sage: var('k') k - sage: derivative(chebyshev_T(k,x),x) + sage: derivative(chebyshev_T(k, x), x) k*chebyshev_U(k - 1, x) - sage: derivative(chebyshev_T(3,x),x) + sage: derivative(chebyshev_T(3, x), x) 12*x^2 - 3 - sage: derivative(chebyshev_T(k,x),k) + sage: derivative(chebyshev_T(k, x), k) Traceback (most recent call last): ... NotImplementedError: derivative w.r.t. to the index is not supported yet @@ -965,16 +987,17 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: var('n, x') (n, x) sage: from sage.functions.orthogonal_polys import Func_chebyshev_U sage: chebyshev_U2 = Func_chebyshev_U() - sage: chebyshev_U2(1,x) + sage: chebyshev_U2(1, x) 2*x - sage: chebyshev_U(x, x)._sympy_() + sage: chebyshev_U(x, x)._sympy_() # needs sympy chebyshevu(x, x) sage: maxima(chebyshev_U(2,x, hold=True)) - 3*((-(8*(1-_SAGE_VAR_x))/3)+(4*(1-_SAGE_VAR_x)^2)/3+1) + 3*(...-...(8*(1-_SAGE_VAR_x))/3)+(4*(1-_SAGE_VAR_x)^2)/3+1) sage: maxima(chebyshev_U(n,x, hold=True)) chebyshev_u(_SAGE_VAR_n,_SAGE_VAR_x) """ @@ -997,7 +1020,7 @@ def _print_latex_(self, n, z): r""" TESTS:: - sage: latex(chebyshev_U(3, x, hold=True)) + sage: latex(chebyshev_U(3, x, hold=True)) # needs sage.symbolic U_{3}\left(x\right) """ return r"U_{{{}}}\left({}\right)".format(latex(n), latex(z)) @@ -1018,6 +1041,7 @@ def eval_formula(self, n, x): EXAMPLES:: + sage: # needs sage.symbolic sage: chebyshev_U.eval_formula(10, x) 1024*x^10 - 2304*x^8 + 1792*x^6 - 560*x^4 + 60*x^2 - 1 sage: chebyshev_U.eval_formula(-2, x) @@ -1054,13 +1078,13 @@ def eval_algebraic(self, n, x): EXAMPLES:: - sage: chebyshev_U.eval_algebraic(5,x) + sage: chebyshev_U.eval_algebraic(5, x) # needs sage.symbolic -2*((2*x + 1)*(2*x - 1)*x - 4*(2*x^2 - 1)*x)*(2*x + 1)*(2*x - 1) sage: parent(chebyshev_U(3, Mod(8,9))) Ring of integers modulo 9 sage: parent(chebyshev_U(3, Mod(1,9))) Ring of integers modulo 9 - sage: chebyshev_U(-3,x) + chebyshev_U(1,x) + sage: chebyshev_U(-3, x) + chebyshev_U(1, x) # needs sage.symbolic 0 sage: chebyshev_U(-1,Mod(5,8)) 0 @@ -1075,11 +1099,11 @@ def eval_algebraic(self, n, x): 1 sage: chebyshev_U.eval_algebraic(1, t) 2*t - sage: n = 97; x = RIF(pi/n) - sage: chebyshev_U(n-1, cos(x)).contains_zero() + sage: n = 97; x = RIF(pi/n) # needs sage.symbolic + sage: chebyshev_U(n - 1, cos(x)).contains_zero() # needs sage.symbolic True - sage: R.<t> = Zp(2, 6, 'capped-abs')[] - sage: chebyshev_U(10^6+1, t) + sage: R.<t> = Zp(2, 6, 'capped-abs')[] # needs sage.rings.padics + sage: chebyshev_U(10^6 + 1, t) # needs sage.rings.padics (2 + O(2^6))*t + O(2^6) """ if n == -1: @@ -1096,10 +1120,11 @@ def _eval_recursive_(self, n, x, both=False): EXAMPLES:: - sage: chebyshev_U._eval_recursive_(3, x) + sage: chebyshev_U._eval_recursive_(3, x) # needs sage.symbolic (4*((2*x + 1)*(2*x - 1) - 2*x^2)*x, False) - sage: chebyshev_U._eval_recursive_(3, x, True) - (4*((2*x + 1)*(2*x - 1) - 2*x^2)*x, ((2*x + 1)*(2*x - 1) + 2*x)*((2*x + 1)*(2*x - 1) - 2*x)) + sage: chebyshev_U._eval_recursive_(3, x, True) # needs sage.symbolic + (4*((2*x + 1)*(2*x - 1) - 2*x^2)*x, + ((2*x + 1)*(2*x - 1) + 2*x)*((2*x + 1)*(2*x - 1) - 2*x)) """ if n == 0: return parent(x).one(), 2*x @@ -1117,11 +1142,11 @@ def _evalf_(self, n, x, **kwds): EXAMPLES:: - sage: chebyshev_U(5,-4+3.*I) + sage: chebyshev_U(5,-4+3.*I) # needs sage.symbolic 98280.0000000000 - 11310.0000000000*I - sage: chebyshev_U(10,3).n(75) + sage: chebyshev_U(10, 3).n(75) # needs sage.symbolic 4.661117900000000000000e7 - sage: chebyshev_U._evalf_(1.5, Mod(8,9)) + sage: chebyshev_U._evalf_(1.5, Mod(8,9)) # needs sage.rings.real_mpfr Traceback (most recent call last): ... TypeError: cannot evaluate chebyshev_U with parent Ring of integers modulo 9 @@ -1143,10 +1168,7 @@ def _evalf_(self, n, x, **kwds): if not isinstance(real_parent, (sage.rings.abc.RealField, sage.rings.abc.ComplexField)): raise TypeError("cannot evaluate chebyshev_U with parent {}".format(real_parent)) - from sage.libs.mpmath.all import call as mpcall - from sage.libs.mpmath.all import chebyu as mpchebyu - - return mpcall(mpchebyu, n, x, parent=real_parent) + return _mpmath_utils_call(_mpmath_chebyu, n, x, parent=real_parent) def _eval_special_values_(self, n, x): """ @@ -1155,13 +1177,14 @@ def _eval_special_values_(self, n, x): EXAMPLES:: + sage: # needs sage.symbolic sage: var('n') n - sage: chebyshev_U(n,1) + sage: chebyshev_U(n, 1) n + 1 - sage: chebyshev_U(n,0) + sage: chebyshev_U(n, 0) 1/2*(-1)^(1/2*n)*((-1)^n + 1) - sage: chebyshev_U(n,-1) + sage: chebyshev_U(n, -1) (-1)^n*(n + 1) sage: chebyshev_U._eval_special_values_(n, 2) Traceback (most recent call last): @@ -1185,6 +1208,7 @@ def _eval_numpy_(self, n, x): EXAMPLES:: + sage: # needs numpy scipy sage: import numpy sage: z = numpy.array([1,2]) sage: z2 = numpy.array([[1,2],[1,2]]) @@ -1199,8 +1223,7 @@ def _eval_numpy_(self, n, x): sage: chebyshev_U(z,0.1) array([ 0.2 , -0.96]) """ - from scipy.special import eval_chebyu - return eval_chebyu(n, x) + return _scipy_chebyu(n, x) def _derivative_(self, n, x, diff_param): """ @@ -1209,13 +1232,14 @@ def _derivative_(self, n, x, diff_param): EXAMPLES:: + sage: # needs sage.symbolic sage: var('k') k - sage: derivative(chebyshev_U(k,x),x) + sage: derivative(chebyshev_U(k,x), x) ((k + 1)*chebyshev_T(k + 1, x) - x*chebyshev_U(k, x))/(x^2 - 1) - sage: derivative(chebyshev_U(3,x),x) + sage: derivative(chebyshev_U(3,x), x) 24*x^2 - 4 - sage: derivative(chebyshev_U(k,x),k) + sage: derivative(chebyshev_U(k,x), k) Traceback (most recent call last): ... NotImplementedError: derivative w.r.t. to the index is not supported yet @@ -1223,9 +1247,10 @@ def _derivative_(self, n, x, diff_param): if diff_param == 0: raise NotImplementedError("derivative w.r.t. to the index is not supported yet") elif diff_param == 1: - return ((n+1)*chebyshev_T(n+1, x) - x*chebyshev_U(n,x)) / (x*x-1) + return ((n+1)*chebyshev_T(n+1, x) - x*chebyshev_U(n, x)) / (x*x-1) raise ValueError("illegal differentiation parameter {}".format(diff_param)) + chebyshev_U = Func_chebyshev_U() @@ -1233,29 +1258,31 @@ class Func_legendre_P(GinacFunction): r""" EXAMPLES:: + sage: # needs sage.symbolic sage: legendre_P(4, 2.0) 55.3750000000000 sage: legendre_P(1, x) x - sage: legendre_P(4, x+1) + sage: legendre_P(4, x + 1) 35/8*(x + 1)^4 - 15/4*(x + 1)^2 + 3/8 sage: legendre_P(1/2, I+1.) 1.05338240025858 + 0.359890322109665*I sage: legendre_P(0, SR(1)).parent() Symbolic Ring - sage: legendre_P(0, 0) + sage: legendre_P(0, 0) # needs sage.symbolic 1 - sage: legendre_P(1, x) + sage: legendre_P(1, x) # needs sage.symbolic x + sage: # needs sage.symbolic sage: legendre_P(4, 2.) 55.3750000000000 - sage: legendre_P(5.5,1.00001) + sage: legendre_P(5.5, 1.00001) 1.00017875754114 - sage: legendre_P(1/2, I+1).n() + sage: legendre_P(1/2, I + 1).n() 1.05338240025858 + 0.359890322109665*I - sage: legendre_P(1/2, I+1).n(59) + sage: legendre_P(1/2, I + 1).n(59) 1.0533824002585801 + 0.35989032210966539*I sage: legendre_P(42, RR(12345678)) 2.66314881466753e309 @@ -1266,22 +1293,24 @@ class Func_legendre_P(GinacFunction): sage: legendre_P(201/2, 0).n(100) 0.056138617863017877699963095883 + sage: # needs sage.symbolic sage: R.<x> = QQ[] - sage: legendre_P(4,x) + sage: legendre_P(4, x) 35/8*x^4 - 15/4*x^2 + 3/8 - sage: legendre_P(10000,x).coefficient(x,1) + sage: legendre_P(10000, x).coefficient(x, 1) 0 sage: var('t,x') (t, x) - sage: legendre_P(-5,t) + sage: legendre_P(-5, t) 35/8*t^4 - 15/4*t^2 + 3/8 - sage: legendre_P(4, x+1) + sage: legendre_P(4, x + 1) 35/8*(x + 1)^4 - 15/4*(x + 1)^2 + 3/8 sage: legendre_P(4, sqrt(2)) 83/8 sage: legendre_P(4, I*e) 35/8*e^4 + 15/4*e^2 + 3/8 + sage: # needs sage.symbolic sage: n = var('n') sage: derivative(legendre_P(n,x), x) (n*x*legendre_P(n, x) - n*legendre_P(n - 1, x))/(x^2 - 1) @@ -1296,12 +1325,13 @@ class Func_legendre_P(GinacFunction): Verify that :trac:`33962` is fixed:: - sage: [legendre_P(n, 0) for n in range(-10, 10)] + sage: [legendre_P(n, 0) for n in range(-10, 10)] # needs sage.symbolic [0, 35/128, 0, -5/16, 0, 3/8, 0, -1/2, 0, 1, 1, 0, -1/2, 0, 3/8, 0, -5/16, 0, 35/128, 0] Verify that :trac:`33963` is fixed:: + sage: # needs sage.symbolic sage: n = var("n") sage: assume(n, "integer") sage: assume(n, "even") @@ -1335,7 +1365,7 @@ def __init__(self): sage: loads(dumps(legendre_Q)) legendre_Q - sage: maxima(legendre_Q(20,x, hold=True))._sage_().coefficient(x,10) + sage: maxima(legendre_Q(20, x, hold=True))._sage_().coefficient(x, 10) # needs sage.symbolic -29113619535/131072*log(-(x + 1)/(x - 1)) """ BuiltinFunction.__init__(self, "legendre_Q", nargs=2, latex_name=r"Q", @@ -1349,15 +1379,16 @@ def _eval_(self, n, x, *args, **kwds): EXAMPLES:: + sage: # needs sage.symbolic sage: legendre_Q(2,x) 1/4*(3*x^2 - 1)*(log(x + 1) - log(-x + 1)) - 3/2*x - sage: legendre_Q(5,0) + sage: legendre_Q(5, 0) -8/15 - sage: legendre_Q(2,2*x) + sage: legendre_Q(2, 2*x) 1/4*(12*x^2 - 1)*(log(2*x + 1) - log(-2*x + 1)) - 3*x sage: legendre_Q(1/2, I+1.) -0.511424110789061 + 1.34356195297194*I - sage: legendre_Q(-1,x) + sage: legendre_Q(-1, x) Infinity """ ret = self._eval_special_values_(n, x) @@ -1375,6 +1406,7 @@ def _eval_special_values_(self, n, x): EXAMPLES:: + sage: # needs sage.symbolic sage: var('n') n sage: legendre_Q(n, 0) @@ -1414,20 +1446,18 @@ def _evalf_(self, n, x, parent=None, **kwds): EXAMPLES:: - sage: legendre_Q(4, 2.) + sage: legendre_Q(4, 2.) # needs mpmath 0.00116107583162041 - 86.9828465962674*I - sage: legendre_Q(1/2, I+1.) + sage: legendre_Q(1/2, I+1.) # needs sage.symbolic -0.511424110789061 + 1.34356195297194*I - sage: legendre_Q(1/2, I+1).n(59) + sage: legendre_Q(1/2, I+1).n(59) # needs sage.symbolic -0.51142411078906080 + 1.3435619529719394*I """ ret = self._eval_special_values_(n, x) if ret is not None: return ret - import mpmath - from sage.libs.mpmath.all import call as mpcall - return mpcall(mpmath.legenq, n, 0, x, parent=parent) + return _mpmath_utils_call(_mpmath_legenq, n, 0, x, parent=parent) def eval_recursive(self, n, arg, **kwds): """ @@ -1435,9 +1465,9 @@ def eval_recursive(self, n, arg, **kwds): EXAMPLES:: - sage: legendre_Q.eval_recursive(2,x) + sage: legendre_Q.eval_recursive(2, x) # needs sage.symbolic 3/4*x^2*(log(x + 1) - log(-x + 1)) - 3/2*x - 1/4*log(x + 1) + 1/4*log(-x + 1) - sage: legendre_Q.eval_recursive(20,x).expand().coefficient(x,10) + sage: legendre_Q.eval_recursive(20, x).expand().coefficient(x, 10) # needs sage.symbolic -29113619535/131072*log(x + 1) + 29113619535/131072*log(-x + 1) """ from sage.functions.log import ln @@ -1471,15 +1501,17 @@ def eval_formula(self, n, arg, **kwds): EXAMPLES:: + sage: # needs sage.symbolic sage: legendre_Q.eval_formula(1, x) 1/2*x*(log(x + 1) - log(-x + 1)) - 1 - sage: legendre_Q.eval_formula(2,x).expand().collect(log(1+x)).collect(log(1-x)) + sage: legendre_Q.eval_formula(2, x).expand().collect(log(1+x)).collect(log(1-x)) 1/4*(3*x^2 - 1)*log(x + 1) - 1/4*(3*x^2 - 1)*log(-x + 1) - 3/2*x - sage: legendre_Q.eval_formula(20,x).coefficient(x,10) + sage: legendre_Q.eval_formula(20, x).coefficient(x, 10) -29113619535/131072*log(x + 1) + 29113619535/131072*log(-x + 1) sage: legendre_Q(0, 2) -1/2*I*pi + 1/2*log(3) - sage: legendre_Q(0, 2.) + + sage: legendre_Q(0, 2.) # needs mpmath 0.549306144334055 - 1.57079632679490*I """ from sage.functions.log import ln @@ -1497,9 +1529,9 @@ def _Wfunc(self, n, arg): EXAMPLES:: - sage: legendre_Q._Wfunc(2, x) + sage: legendre_Q._Wfunc(2, x) # needs sage.symbolic 3/2*x - sage: legendre_Q._Wfunc(7, x) + sage: legendre_Q._Wfunc(7, x) # needs sage.symbolic 429/16*x^6 - 275/8*x^4 + 849/80*x^2 - 16/35 """ if n == 0: @@ -1517,20 +1549,21 @@ def _Wfunc(self, n, arg): return sum(b * arg**a for a, b in enumerate(help3)) - def _derivative_(self, n, x, *args,**kwds): + def _derivative_(self, n, x, *args, **kwds): """ Return the derivative of legendre_Q. EXAMPLES:: + sage: # needs sage.symbolic sage: n = var('n') sage: derivative(legendre_Q(n,x), x) (n*x*legendre_Q(n, x) - n*legendre_Q(n - 1, x))/(x^2 - 1) - sage: ex1 = legendre_Q(5,x,hold=True).diff(x).expand().simplify_full() - sage: ex2 = legendre_Q(5,x).diff(x).expand().simplify_full() + sage: ex1 = legendre_Q(5, x, hold=True).diff(x).expand().simplify_full() + sage: ex2 = legendre_Q(5, x).diff(x).expand().simplify_full() sage: ex1.subs(x=7).n() == ex2.subs(x=7).n() True - sage: derivative(legendre_Q(n,x), n) + sage: derivative(legendre_Q(n, x), n) Traceback (most recent call last): ... NotImplementedError: Derivative w.r.t. to the index is not supported. @@ -1579,7 +1612,7 @@ class Func_assoc_legendre_P(BuiltinFunction): We give the first Ferrers functions for non-negative integers `n` and `m` in the interval `-1<x<1`:: - sage: for n in range(4): + sage: for n in range(4): # needs sage.symbolic ....: for m in range(n+1): ....: print(f"P_{n}^{m}({x}) = {gen_legendre_P(n, m, x)}") P_0^0(x) = 1 @@ -1612,6 +1645,7 @@ class Func_assoc_legendre_P(BuiltinFunction): Here are some specific values with negative integers:: + sage: # needs sage.symbolic sage: gen_legendre_P(-2, -1, x) 1/2*sqrt(-x^2 + 1) sage: gen_legendre_P(2, -2, x) @@ -1623,6 +1657,7 @@ class Func_assoc_legendre_P(BuiltinFunction): Here are some other random values with floating numbers:: + sage: # needs sage.symbolic sage: m = var('m'); assume(m, 'integer') sage: gen_legendre_P(m, m, .2) 0.960000000000000^(1/2*m)*(-1)^m*factorial(2*m)/(2^m*factorial(m)) @@ -1635,19 +1670,19 @@ class Func_assoc_legendre_P(BuiltinFunction): Some consistency checks:: - sage: gen_legendre_P(1, 1, x) + sage: gen_legendre_P(1, 1, x) # needs sage.symbolic -sqrt(-x^2 + 1) - sage: gen_legendre_P.eval_gen_poly(1, 1, x) + sage: gen_legendre_P.eval_gen_poly(1, 1, x) # needs sage.symbolic -sqrt(-x^2 + 1) - sage: gen_legendre_P(1, 1, 0.5) # abs tol 1e-14 + sage: gen_legendre_P(1, 1, 0.5) # abs tol 1e-14 # needs mpmath -0.866025403784439 sage: gen_legendre_P.eval_gen_poly(1, 1, 0.5) # abs tol 1e-14 -0.866025403784439 - sage: gen_legendre_P._evalf_(1, 1, 0.5) # abs tol 1e-14 + sage: gen_legendre_P._evalf_(1, 1, 0.5) # abs tol 1e-14 # needs mpmath -0.866025403784439 - sage: gen_legendre_P(2/3,1,0.) # abs tol 1e-14 + sage: gen_legendre_P(2/3, 1, 0.) # abs tol 1e-14 # needs mpmath -0.773063511309286 - sage: gen_legendre_P._eval_special_values_(2/3,1,0.).n() # abs tol 1e-14 + sage: gen_legendre_P._eval_special_values_(2/3, 1, 0.).n() # abs tol 1e-14 # needs sage.symbolic -0.773063511309286 REFERENCES: @@ -1661,19 +1696,19 @@ def __init__(self): sage: loads(dumps(gen_legendre_P)) gen_legendre_P - sage: maxima(gen_legendre_P(20,6,x, hold=True))._sage_().expand().coefficient(x,10) + sage: maxima(gen_legendre_P(20, 6, x, hold=True))._sage_().expand().coefficient(x,10) # needs sage.symbolic 2508866163428625/128 TESTS:: - sage: fricas(gen_legendre_P(2,1/2,x)) # optional - fricas + sage: fricas(gen_legendre_P(2, 1/2, x)) # optional - fricas, needs sage.symbolic 1 legendreP(2,-,x) 2 - sage: gen_legendre_P(3,0,x) + sage: gen_legendre_P(3, 0, x) # needs sage.symbolic 5/2*x^3 - 3/2*x - sage: fricas.legendreP(3,x) # optional - fricas + sage: fricas.legendreP(3, x) # optional - fricas, needs sage.symbolic 5 3 3 - x - - x 2 2 @@ -1691,9 +1726,9 @@ def _eval_(self, n, m, x, *args, **kwds): EXAMPLES:: - sage: gen_legendre_P(13/2,2,0) + sage: gen_legendre_P(13/2, 2, 0) # needs sage.symbolic 4*sqrt(pi)/(gamma(13/4)*gamma(-15/4)) - sage: gen_legendre_P(3,2,x) + sage: gen_legendre_P(3, 2, x) # needs sage.symbolic -15*(x^2 - 1)*x """ ret = self._eval_special_values_(n, m, x) @@ -1710,23 +1745,25 @@ def _eval_special_values_(self, n, m, x): Case `|m| > |n|` for integers:: - sage: gen_legendre_P(2,3,4) + sage: gen_legendre_P(2, 3, 4) # needs mpmath 0 Case `x = 0`:: - sage: gen_legendre_P(13/2,2,0) + sage: # needs sage.symbolic + sage: gen_legendre_P(13/2, 2, 0) 4*sqrt(pi)/(gamma(13/4)*gamma(-15/4)) - sage: (m,n) = var('m,n') - sage: gen_legendre_P(n,m,0) + sage: m, n = var('m,n') + sage: gen_legendre_P(n, m, 0) sqrt(pi)*2^m/(gamma(-1/2*m + 1/2*n + 1)*gamma(-1/2*m - 1/2*n + 1/2)) - sage: gen_legendre_P(n,3,0) + sage: gen_legendre_P(n, 3, 0) 8*sqrt(pi)/(gamma(1/2*n - 1/2)*gamma(-1/2*n - 1)) - sage: gen_legendre_P(3,m,0) + sage: gen_legendre_P(3, m, 0) sqrt(pi)*2^m/(gamma(-1/2*m + 5/2)*gamma(-1/2*m - 1)) Case `m = n` for integers:: + sage: # needs sage.symbolic sage: m = var('m') sage: assume(m, 'integer') sage: gen_legendre_P(m, m, x) @@ -1738,9 +1775,9 @@ def _eval_special_values_(self, n, m, x): Case `n = 0`:: - sage: gen_legendre_P(m, 0, x) + sage: gen_legendre_P(m, 0, x) # needs sage.symbolic legendre_P(m, x) - sage: gen_legendre_P(2,0,4) == legendre_P(2,4) + sage: gen_legendre_P(2, 0, 4) == legendre_P(2, 4) # needs sage.symbolic True """ @@ -1768,11 +1805,11 @@ def _eval_int_ord_deg_(self, n, m, x): TESTS:: - sage: gen_legendre_P._eval_int_ord_deg_(-2, 1, x) + sage: gen_legendre_P._eval_int_ord_deg_(-2, 1, x) # needs sage.symbolic -sqrt(-x^2 + 1) - sage: gen_legendre_P._eval_int_ord_deg_(2, -1, x) + sage: gen_legendre_P._eval_int_ord_deg_(2, -1, x) # needs sage.symbolic 1/2*sqrt(-x^2 + 1)*x - sage: gen_legendre_P._eval_int_ord_deg_(-2, -1, x) + sage: gen_legendre_P._eval_int_ord_deg_(-2, -1, x) # needs sage.symbolic 1/2*sqrt(-x^2 + 1) """ @@ -1792,19 +1829,17 @@ def _evalf_(self, n, m, x, parent=None, **kwds): EXAMPLES:: - sage: gen_legendre_P(10,2,3).n() # abs tol 1e-14 + sage: gen_legendre_P(10, 2, 3).n() # abs tol 1e-14 # needs sage.symbolic -7.19496360000000e8 - sage: gen_legendre_P(5/2,2,1.+I) + sage: gen_legendre_P(5/2,2,1.+I) # needs sage.symbolic 14.3165258449040 - 12.7850496155152*I - sage: gen_legendre_P(5/2,2,ComplexField(70)(1+I)) + sage: gen_legendre_P(5/2, 2, ComplexField(70)(1+I)) # needs sage.rings.real_mpfr sage.symbolic 14.316525844904028532 - 12.785049615515157033*I - sage: gen_legendre_P(2/3,1,0.) + sage: gen_legendre_P(2/3, 1, 0.) # needs mpmath -0.773063511309286 """ - import mpmath - from sage.libs.mpmath.all import call as mpcall - return mpcall(mpmath.legenp, n, m, x, parent=parent) + return _mpmath_utils_call(_mpmath_legenp, n, m, x, parent=parent) def eval_gen_poly(self, n, m, arg, **kwds): r""" @@ -1825,9 +1860,9 @@ def eval_gen_poly(self, n, m, arg, **kwds): EXAMPLES:: - sage: gen_legendre_P(7,4,x) + sage: gen_legendre_P(7, 4, x) # needs sage.symbolic 3465/2*(13*x^3 - 3*x)*(x^2 - 1)^2 - sage: gen_legendre_P(3,1,sqrt(x)) + sage: gen_legendre_P(3, 1, sqrt(x)) # needs sage.symbolic -3/2*(5*x - 1)*sqrt(-x + 1) REFERENCE: @@ -1854,10 +1889,12 @@ def _derivative_(self, n, m, x, *args, **kwds): EXAMPLES:: - sage: (m,n) = var('m,n') + sage: # needs sage.symbolic + sage: m, n = var('m,n') sage: derivative(gen_legendre_P(n,m,x), x) - -((n + 1)*x*gen_legendre_P(n, m, x) + (m - n - 1)*gen_legendre_P(n + 1, m, x))/(x^2 - 1) - sage: gen_legendre_P(3,2,x,hold=True).diff(x).expand().simplify_full() + -((n + 1)*x*gen_legendre_P(n, m, x) + + (m - n - 1)*gen_legendre_P(n + 1, m, x))/(x^2 - 1) + sage: gen_legendre_P(3, 2, x, hold=True).diff(x).expand().simplify_full() -45*x^2 + 15 sage: derivative(gen_legendre_P(n,m,x), n) Traceback (most recent call last): @@ -1872,8 +1909,10 @@ def _derivative_(self, n, m, x, *args, **kwds): # https://dlmf.nist.gov/14.10#E4 return ((m-n-1)*gen_legendre_P(n+1, m, x) + (n+1)*x*gen_legendre_P(n, m, x))/(1 - x**2) + gen_legendre_P = Func_assoc_legendre_P() + class Func_assoc_legendre_Q(BuiltinFunction): def __init__(self): r""" @@ -1881,12 +1920,13 @@ def __init__(self): sage: loads(dumps(gen_legendre_Q)) gen_legendre_Q - sage: maxima(gen_legendre_Q(2,1,3, hold=True))._sage_().simplify_full() + sage: maxima(gen_legendre_Q(2, 1, 3, hold=True))._sage_().simplify_full() # needs sage.symbolic 1/4*sqrt(2)*(36*pi - 36*I*log(2) + 25*I) """ BuiltinFunction.__init__(self, "gen_legendre_Q", nargs=3, latex_name=r"Q", - conversions={'maxima':'assoc_legendre_q', 'mathematica':'LegendreQ', - 'maple':'LegendreQ'}) + conversions={'maxima': 'assoc_legendre_q', + 'mathematica': 'LegendreQ', + 'maple': 'LegendreQ'}) def _eval_(self, n, m, x, *args, **kwds): r""" @@ -1894,15 +1934,15 @@ def _eval_(self, n, m, x, *args, **kwds): EXAMPLES:: - sage: gen_legendre_Q(2,1,3) + sage: gen_legendre_Q(2, 1, 3) # needs sage.symbolic -1/4*sqrt(-2)*(-36*I*pi + 36*log(2) - 25) """ ret = self._eval_special_values_(n, m, x) if ret is not None: return ret if (n in ZZ and m in ZZ - and n >= 0 and m >= 0 - and (x in ZZ or not SR(x).is_numeric())): + and n >= 0 and m >= 0 + and (x in ZZ or not SR(x).is_numeric())): return self.eval_recursive(n, m, x) def _eval_special_values_(self, n, m, x): @@ -1911,8 +1951,8 @@ def _eval_special_values_(self, n, m, x): EXAMPLES:: - sage: n, m = var('n m') - sage: gen_legendre_Q(n,m,0) + sage: n, m = var('n m') # needs sage.symbolic + sage: gen_legendre_Q(n, m, 0) # needs sage.symbolic -sqrt(pi)*2^(m - 1)*gamma(1/2*m + 1/2*n + 1/2)*sin(1/2*pi*m + 1/2*pi*n)/gamma(-1/2*m + 1/2*n + 1) """ if m == 0: @@ -1932,18 +1972,16 @@ def _evalf_(self, n, m, x, parent=None, **kwds): EXAMPLES:: - sage: gen_legendre_Q(2,1,3.) + sage: gen_legendre_Q(2, 1, 3.) # needs mpmath -39.9859464434253 + 0.0165114736149193*I - sage: gen_legendre_Q(2,1,ComplexField(70)(3)) + sage: gen_legendre_Q(2, 1, ComplexField(70)(3)) # needs sage.rings.real_mpfr -39.985946443425296223 + 0.016511473614919329585*I """ ret = self._eval_special_values_(n, m, x) if ret is not None: return ret - import mpmath - from sage.libs.mpmath.all import call as mpcall - return mpcall(mpmath.legenq, n, m, x, parent=parent) + return _mpmath_utils_call(_mpmath_legenq, n, m, x, parent=parent) def eval_recursive(self, n, m, x, **kwds): """ @@ -1951,15 +1989,16 @@ def eval_recursive(self, n, m, x, **kwds): EXAMPLES:: - sage: gen_legendre_Q(3,4,x) + sage: # needs sage.symbolic + sage: gen_legendre_Q(3, 4, x) 48/(x^2 - 1)^2 - sage: gen_legendre_Q(4,5,x) + sage: gen_legendre_Q(4, 5, x) -384/((x^2 - 1)^2*sqrt(-x^2 + 1)) - sage: gen_legendre_Q(0,1,x) + sage: gen_legendre_Q(0, 1, x) -1/sqrt(-x^2 + 1) - sage: gen_legendre_Q(0,2,x) + sage: gen_legendre_Q(0, 2, x) -1/2*((x + 1)^2 - (x - 1)^2)/(x^2 - 1) - sage: gen_legendre_Q(2,2,x).subs(x=2).expand() + sage: gen_legendre_Q(2, 2, x).subs(x=2).expand() 9/2*I*pi - 9/2*log(3) + 14/3 """ from sage.misc.functional import sqrt @@ -1973,19 +2012,21 @@ def eval_recursive(self, n, m, x, **kwds): else: return (-1)**m*(m-1).factorial()*((x+1)**m - (x-1)**m)/(2*denom) else: - return ((n-m+1)*x*gen_legendre_Q(n,m-1,x)-(n+m-1)*gen_legendre_Q(n-1,m-1,x))/sqrt(1-x**2) + return ((n-m+1)*x*gen_legendre_Q(n, m-1, x)-(n+m-1)*gen_legendre_Q(n-1, m-1, x))/sqrt(1-x**2) - def _derivative_(self, n, m, x, *args,**kwds): + def _derivative_(self, n, m, x, *args, **kwds): """ Return the derivative of ``gen_legendre_Q(n,m,x)``. EXAMPLES:: - sage: (m,n) = var('m,n') + sage: # needs sage.symbolic + sage: m, n = var('m,n') sage: derivative(gen_legendre_Q(n,m,x), x) - -((n + 1)*x*gen_legendre_Q(n, m, x) + (m - n - 1)*gen_legendre_Q(n + 1, m, x))/(x^2 - 1) - sage: ex1=gen_legendre_Q(3,2,x,hold=True).diff(x).expand().simplify_full() - sage: ex2=gen_legendre_Q(3,2,x).diff(x).expand().simplify_full() + -((n + 1)*x*gen_legendre_Q(n, m, x) + + (m - n - 1)*gen_legendre_Q(n + 1, m, x))/(x^2 - 1) + sage: ex1 = gen_legendre_Q(3, 2, x, hold=True).diff(x).expand().simplify_full() + sage: ex2 = gen_legendre_Q(3, 2, x).diff(x).expand().simplify_full() sage: ex1.subs(x=5).n() == ex2.subs(x=5).n() True sage: derivative(gen_legendre_Q(n,m,x), n) @@ -2013,44 +2054,43 @@ class Func_hermite(GinacFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: x = PolynomialRing(QQ, 'x').gen() - sage: hermite(2,x) + sage: hermite(2, x) 4*x^2 - 2 - sage: hermite(3,x) + sage: hermite(3, x) 8*x^3 - 12*x - sage: hermite(3,2) + sage: hermite(3, 2) 40 sage: S.<y> = PolynomialRing(RR) - sage: hermite(3,y) + sage: hermite(3, y) 8.00000000000000*y^3 - 12.0000000000000*y sage: R.<x,y> = QQ[] - sage: hermite(3,y^2) + sage: hermite(3, y^2) 8*y^6 - 12*y^2 sage: w = var('w') - sage: hermite(3,2*w) + sage: hermite(3, 2*w) 64*w^3 - 24*w - sage: hermite(5,3.1416) + sage: hermite(5, 3.1416) 5208.69733891963 - sage: hermite(5,RealField(100)(pi)) + sage: hermite(5, RealField(100)(pi)) 5208.6167627118104649470287166 Check that :trac:`17192` is fixed:: + sage: # needs sage.symbolic sage: x = PolynomialRing(QQ, 'x').gen() - sage: hermite(0,x) + sage: hermite(0, x) 1 - - sage: hermite(-1,x) + sage: hermite(-1, x) Traceback (most recent call last): ... RuntimeError: hermite_eval: The index n must be a nonnegative integer - - sage: hermite(-7,x) + sage: hermite(-7, x) Traceback (most recent call last): ... RuntimeError: hermite_eval: The index n must be a nonnegative integer - - sage: m,x = SR.var('m,x') + sage: m, x = SR.var('m,x') sage: hermite(m, x).diff(m) Traceback (most recent call last): ... @@ -2064,17 +2104,17 @@ def __init__(self): sage: loads(dumps(hermite)) hermite - sage: hermite(x, x)._sympy_() + sage: hermite(x, x)._sympy_() # needs sympy sage.symbolic hermite(x, x) TESTS:: - sage: fricas(hermite(x, 5)) # optional - fricas + sage: fricas(hermite(x, 5)) # optional - fricas # needs sage.symbolic hermiteH(x,5) - sage: hermite(5,x) + sage: hermite(5, x) # needs sage.symbolic 32*x^5 - 160*x^3 + 120*x - sage: fricas.hermiteH(5,x) # optional - fricas + sage: fricas.hermiteH(5, x) # optional - fricas # needs sage.symbolic 5 3 32 x - 160 x + 120 x """ @@ -2107,7 +2147,7 @@ class Func_jacobi_P(OrthogonalFunction): sage: x = PolynomialRing(QQ, 'x').gen() sage: jacobi_P(2,0,0,x) 3/2*x^2 - 1/2 - sage: jacobi_P(2,1,2,1.2) + sage: jacobi_P(2,1,2,1.2) # needs sage.symbolic 5.01000000000000 """ def __init__(self): @@ -2116,22 +2156,22 @@ def __init__(self): EXAMPLES:: - sage: n,a,b,x = SR.var('n,a,b,x') + sage: n, a, b, x = SR.var('n,a,b,x') # needs sage.symbolic sage: loads(dumps(jacobi_P)) jacobi_P - sage: jacobi_P(n, a, b, x, hold=True)._sympy_() + sage: jacobi_P(n, a, b, x, hold=True)._sympy_() # needs sympy sage.symbolic jacobi(n, a, b, x) TESTS:: - sage: fricas(jacobi_P(1/2,4,1/3,x)) # optional - fricas + sage: fricas(jacobi_P(1/2, 4, 1/3, x)) # optional - fricas, needs sage.symbolic 1 1 jacobiP(-,4,-,x) 2 3 - sage: jacobi_P(1,2,3,x) + sage: jacobi_P(1, 2, 3, x) # needs sage.symbolic 7/2*x - 1/2 - sage: fricas.jacobiP(1,2,3,x) # optional - fricas + sage: fricas.jacobiP(1, 2, 3, x) # optional - fricas, needs sage.symbolic 7 x - 1 ------- 2 @@ -2147,16 +2187,17 @@ def _eval_(self, n, a, b, x): """ EXAMPLES:: - sage: n,a,b,x = SR.var('n,a,b,x') - sage: jacobi_P(1,n,n,n) + sage: # needs sage.symbolic + sage: n, a, b, x = SR.var('n,a,b,x') + sage: jacobi_P(1, n, n, n) (n + 1)*n - sage: jacobi_P(2,n,n,n) + sage: jacobi_P(2, n, n, n) 1/4*(2*n - 1)*(n + 2)*(n + 1)^2 - sage: jacobi_P(1,n,n,x) + sage: jacobi_P(1, n, n, x) (n + 1)*x - sage: jacobi_P(3,2,1,x) + sage: jacobi_P(3, 2, 1, x) 21/2*x^3 + 7/2*x^2 - 7/2*x - 1/2 - sage: jacobi_P(1,a,b,x) + sage: jacobi_P(1, a, b, x) 1/2*a*x + 1/2*b*x + 1/2*a - 1/2*b + x TESTS: @@ -2187,7 +2228,7 @@ def _eval_(self, n, a, b, x): if n not in ZZ: return from .gamma import gamma - s = sum(binomial(n,m) * gamma(a+b+n+m+1) / gamma(a+m+1) * ((x-1)/2)**m for m in range(n+1)) + s = sum(binomial(n, m) * gamma(a+b+n+m+1) / gamma(a+m+1) * ((x-1)/2)**m for m in range(n+1)) r = gamma(a+n+1) / factorial(n) / gamma(n+a+b+1) * s return r.to_gamma().gamma_normalize().normalize() @@ -2195,11 +2236,11 @@ def _evalf_(self, n, a, b, x, **kwds): """ EXAMPLES:: - sage: jacobi_P(2, 1, 2, 1.2) + sage: jacobi_P(2, 1, 2, 1.2) # needs sage.symbolic 5.01000000000000 - sage: jacobi_P(2, 1, 2, 1.2, hold=True).n(20) + sage: jacobi_P(2, 1, 2, 1.2, hold=True).n(20) # needs sage.symbolic 5.0100 - sage: jacobi_P(2, 1, 2, pi+I, hold=True).n(100) + sage: jacobi_P(2, 1, 2, pi + I, hold=True).n(100) # needs sage.symbolic 41.103034125334442891187112674 + 31.486722862692829003857755524*I """ from sage.rings.complex_arb import ComplexBallField as CBF @@ -2211,6 +2252,7 @@ def _evalf_(self, n, a, b, x, **kwds): ret = BF(x).jacobi_P(BF(n), BF(a), BF(b)) return SR(ret)._eval_self(the_parent) + jacobi_P = Func_jacobi_P() @@ -2241,62 +2283,66 @@ class Func_ultraspherical(GinacFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: ultraspherical(8, 101/11, x) 795972057547264/214358881*x^8 - 62604543852032/19487171*x^6... sage: x = PolynomialRing(QQ, 'x').gen() - sage: ultraspherical(2,3/2,x) + sage: ultraspherical(2, 3/2, x) 15/2*x^2 - 3/2 - sage: ultraspherical(1,1,x) + sage: ultraspherical(1, 1, x) 2*x - sage: t = PolynomialRing(RationalField(),"t").gen() - sage: gegenbauer(3,2,t) + sage: t = PolynomialRing(RationalField(), "t").gen() + sage: gegenbauer(3, 2, t) 32*t^3 - 12*t sage: x = SR.var('x') sage: n = ZZ.random_element(5, 5001) sage: a = QQ.random_element().abs() + 5 - sage: s = ( (n+1)*ultraspherical(n+1,a,x) - ....: - 2*x*(n+a)*ultraspherical(n,a,x) - ....: + (n+2*a-1)*ultraspherical(n-1,a,x) ) + sage: s = ( (n + 1)*ultraspherical(n + 1, a, x) + ....: - 2*x*(n + a)*ultraspherical(n, a, x) + ....: + (n + 2*a - 1)*ultraspherical(n - 1, a, x) ) sage: s.expand().is_zero() True - sage: ultraspherical(5,9/10,3.1416) + sage: ultraspherical(5, 9/10, 3.1416) 6949.55439044240 - sage: ultraspherical(5,9/10,RealField(100)(pi)) + sage: ultraspherical(5, 9/10, RealField(100)(pi)) # needs sage.rings.real_mpfr 6949.4695419382702451843080687 - sage: a,n = SR.var('a,n') - sage: gegenbauer(2,a,x) + sage: # needs sage.symbolic + sage: a, n = SR.var('a,n') + sage: gegenbauer(2, a, x) 2*(a + 1)*a*x^2 - a - sage: gegenbauer(3,a,x) + sage: gegenbauer(3, a, x) 4/3*(a + 2)*(a + 1)*a*x^3 - 2*(a + 1)*a*x - sage: gegenbauer(3,a,x).expand() + sage: gegenbauer(3, a, x).expand() 4/3*a^3*x^3 + 4*a^2*x^3 + 8/3*a*x^3 - 2*a^2*x - 2*a*x - sage: gegenbauer(10,a,x).expand().coefficient(x,2) + sage: gegenbauer(10, a, x).expand().coefficient(x, 2) 1/12*a^6 + 5/4*a^5 + 85/12*a^4 + 75/4*a^3 + 137/6*a^2 + 10*a - sage: ex = gegenbauer(100,a,x) - sage: (ex.subs(a==55/98) - gegenbauer(100,55/98,x)).is_trivial_zero() + sage: ex = gegenbauer(100, a, x) + sage: (ex.subs(a==55/98) - gegenbauer(100, 55/98, x)).is_trivial_zero() True - sage: gegenbauer(2,-3,x) + sage: # needs sage.symbolic + sage: gegenbauer(2, -3, x) 12*x^2 + 3 sage: gegenbauer(120,-99/2,3) 1654502372608570682112687530178328494861923493372493824 - sage: gegenbauer(5,9/2,x) + sage: gegenbauer(5, 9/2, x) 21879/8*x^5 - 6435/4*x^3 + 1287/8*x sage: gegenbauer(15,3/2,5) 3903412392243800 - sage: derivative(gegenbauer(n,a,x),x) + sage: derivative(gegenbauer(n, a, x), x) # needs sage.symbolic 2*a*gegenbauer(n - 1, a + 1, x) - sage: derivative(gegenbauer(3,a,x),x) + sage: derivative(gegenbauer(3, a, x), x) # needs sage.symbolic 4*(a + 2)*(a + 1)*a*x^2 - 2*(a + 1)*a - sage: derivative(gegenbauer(n,a,x),a) + sage: derivative(gegenbauer(n, a, x), a) # needs sage.symbolic Traceback (most recent call last): ... RuntimeError: derivative w.r.t. to the second index is not supported yet Numerical evaluation with the mpmath library:: + sage: # needs mpmath sage: from mpmath import gegenbauer as gegenbauer_mp sage: from mpmath import mp sage: mp.pretty = True; mp.dps=25 @@ -2310,15 +2356,15 @@ class Func_ultraspherical(GinacFunction): Check that :trac:`17192` is fixed:: sage: x = PolynomialRing(QQ, 'x').gen() - sage: ultraspherical(0,1,x) + sage: ultraspherical(0, 1, x) # needs sage.symbolic 1 - sage: ultraspherical(-1,1,x) + sage: ultraspherical(-1, 1, x) # needs sage.symbolic Traceback (most recent call last): ... RuntimeError: gegenb_eval: The index n must be a nonnegative integer - sage: ultraspherical(-7,1,x) + sage: ultraspherical(-7, 1, x) # needs sage.symbolic Traceback (most recent call last): ... RuntimeError: gegenb_eval: The index n must be a nonnegative integer @@ -2331,12 +2377,15 @@ def __init__(self): sage: loads(dumps(ultraspherical)) gegenbauer - sage: ultraspherical(x, x, x)._sympy_() + sage: ultraspherical(x, x, x)._sympy_() # needs sympy sage.symbolic gegenbauer(x, x, x) """ GinacFunction.__init__(self, "gegenbauer", nargs=3, latex_name=r"C", - conversions={'maxima':'ultraspherical', 'mathematica':'GegenbauerC', - 'maple':'GegenbauerC', 'sympy':'gegenbauer'}) + conversions={'maxima': 'ultraspherical', + 'mathematica': 'GegenbauerC', + 'maple': 'GegenbauerC', + 'sympy': 'gegenbauer'}) + ultraspherical = Func_ultraspherical() gegenbauer = Func_ultraspherical() @@ -2354,15 +2403,19 @@ def __init__(self): EXAMPLES:: - sage: n,x = var('n,x') - sage: loads(dumps(laguerre)) - laguerre - sage: laguerre(x, x)._sympy_() + sage: # needs sage.symbolic + sage: n, x = var('n,x') + sage: laguerre(x, x)._sympy_() # needs sympy laguerre(x, x) sage: maxima(laguerre(1, x, hold=True)) 1-_SAGE_VAR_x sage: maxima(laguerre(n, laguerre(n, x))) laguerre(_SAGE_VAR_n,laguerre(_SAGE_VAR_n,_SAGE_VAR_x)) + + TESTS:: + + sage: loads(dumps(laguerre)) + laguerre """ OrthogonalFunction.__init__(self, "laguerre", nargs=2, latex_name=r"L", conversions={'maxima': 'laguerre', @@ -2378,17 +2431,17 @@ def _eval_(self, n, x, *args, **kwds): EXAMPLES:: sage: x = PolynomialRing(QQ, 'x').gen() - sage: laguerre(2,x) + sage: laguerre(2, x) # needs mpmath 1/2*x^2 - 2*x + 1 - sage: laguerre(3,x) + sage: laguerre(3, x) # needs mpmath -1/6*x^3 + 3/2*x^2 - 3*x + 1 - sage: laguerre(2,2) + sage: laguerre(2, 2) # needs mpmath -1 - sage: laguerre(-1, x) + sage: laguerre(-1, x) # needs sage.symbolic e^x - sage: laguerre(-6, x) + sage: laguerre(-6, x) # needs sage.symbolic 1/120*(x^5 + 25*x^4 + 200*x^3 + 600*x^2 + 600*x + 120)*e^x - sage: laguerre(-9,2) + sage: laguerre(-9,2) # needs sage.symbolic 66769/315*e^2 """ from sage.rings.integer import Integer @@ -2408,9 +2461,9 @@ def _eval_special_values_(self, n, x): EXAMPLES:: - sage: laguerre(0, 0) + sage: laguerre(0, 0) # needs mpmath 1 - sage: laguerre(1, x) + sage: laguerre(1, x) # needs sage.symbolic -x + 1 """ if n == 0 or x == 0: @@ -2424,14 +2477,14 @@ def _pol_laguerre(self, n, x): EXAMPLES:: - sage: laguerre(3,sin(x)) + sage: laguerre(3, sin(x)) # needs sage.symbolic -1/6*sin(x)^3 + 3/2*sin(x)^2 - 3*sin(x) + 1 sage: R.<x> = PolynomialRing(QQ, 'x') - sage: laguerre(4,x) + sage: laguerre(4, x) # needs mpmath 1/24*x^4 - 2/3*x^3 + 3*x^2 - 4*x + 1 - sage: laguerre(4,x+1) + sage: laguerre(4, x + 1) # needs mpmath 1/24*(x + 1)^4 - 2/3*(x + 1)^3 + 3*(x + 1)^2 - 4*x - 3 - sage: laguerre(10,1+I) + sage: laguerre(10,1+I) # needs sage.symbolic 142511/113400*I + 95867/22680 """ if hasattr(x, 'pyobject'): @@ -2448,38 +2501,36 @@ def _evalf_(self, n, x, **kwds): EXAMPLES:: - sage: laguerre(100,RealField(300)(pi)) + sage: laguerre(100, RealField(300)(pi)) # needs sage.symbolic -0.638322077840648311606324... - sage: laguerre(10,1.+I) + sage: laguerre(10,1.+I) # needs sage.symbolic 4.22694003527337 + 1.25671075837743*I - sage: laguerre(-9, 2.) + sage: laguerre(-9, 2.) # needs sage.symbolic 1566.22186244286 """ the_parent = kwds.get('parent', None) if the_parent is None: the_parent = parent(x) - import mpmath - from sage.libs.mpmath.all import call as mpcall - if n<0: + if n < 0: # work around mpmath issue 307 from sage.functions.log import exp - return exp(x) * mpcall(mpmath.laguerre, -n-1, 0, -x, parent=the_parent) + return exp(x) * _mpmath_utils_call(_mpmath_laguerre, -n-1, 0, -x, parent=the_parent) else: - return mpcall(mpmath.laguerre, n, 0, x, parent=the_parent) + return _mpmath_utils_call(_mpmath_laguerre, n, 0, x, parent=the_parent) - def _derivative_(self, n, x, *args,**kwds): + def _derivative_(self, n, x, *args, **kwds): """ Return the derivative of `laguerre(n,x)`. EXAMPLES:: - sage: n=var('n') - sage: diff(laguerre(n,x), x) + sage: n = var('n') # needs sage.symbolic + sage: diff(laguerre(n, x), x) # needs sage.symbolic -gen_laguerre(n - 1, 1, x) TESTS:: - sage: diff(laguerre(x,x)) + sage: diff(laguerre(x, x)) # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: Derivative w.r.t. to the index is not supported. @@ -2488,12 +2539,13 @@ def _derivative_(self, n, x, *args,**kwds): if diff_param == 0: raise NotImplementedError("Derivative w.r.t. to the index is not supported.") if diff_param == 1: - return -gen_laguerre(n-1,1,x) - else: - raise ValueError("illegal differentiation parameter {}".format(diff_param)) + return -gen_laguerre(n-1, 1, x) + raise ValueError(f"illegal differentiation parameter {diff_param}") + laguerre = Func_laguerre() + class Func_gen_laguerre(OrthogonalFunction): """ REFERENCE: @@ -2506,19 +2558,25 @@ def __init__(self): EXAMPLES:: - sage: a,n,x = var('a, n, x') - sage: loads(dumps(gen_laguerre)) - gen_laguerre - sage: gen_laguerre(x, x, x)._sympy_() + sage: # needs sage.symbolic + sage: a, n, x = var('a, n, x') + sage: gen_laguerre(x, x, x)._sympy_() # needs sympy assoc_laguerre(x, x, x) - sage: maxima(gen_laguerre(1,2,x, hold=True)) + sage: maxima(gen_laguerre(1, 2, x, hold=True)) 3*(1-_SAGE_VAR_x/3) sage: maxima(gen_laguerre(n, a, gen_laguerre(n, a, x))) gen_laguerre(_SAGE_VAR_n,_SAGE_VAR_a, gen_laguerre(_SAGE_VAR_n,_SAGE_VAR_a,_SAGE_VAR_x)) + + TESTS:: + + sage: loads(dumps(gen_laguerre)) + gen_laguerre """ OrthogonalFunction.__init__(self, "gen_laguerre", nargs=3, latex_name=r"L", - conversions={'maxima':'gen_laguerre', 'mathematica':'LaguerreL', - 'maple':'LaguerreL', 'sympy':'assoc_laguerre'}) + conversions={'maxima': 'gen_laguerre', + 'mathematica': 'LaguerreL', + 'maple': 'LaguerreL', + 'sympy': 'assoc_laguerre'}) def _eval_(self, n, a, x, *args, **kwds): r""" @@ -2526,6 +2584,7 @@ def _eval_(self, n, a, x, *args, **kwds): EXAMPLES:: + sage: # needs sage.symbolic sage: gen_laguerre(2, 1, x) 1/2*x^2 - 3*x + 3 sage: gen_laguerre(2, 1/2, x) @@ -2551,11 +2610,11 @@ def _eval_special_values_(self, n, a, x): EXAMPLES:: - sage: gen_laguerre(0, 1, pi) + sage: gen_laguerre(0, 1, pi) # needs sage.symbolic 1 - sage: gen_laguerre(1, 2, x) + sage: gen_laguerre(1, 2, x) # needs sage.symbolic -x + 3 - sage: gen_laguerre(3, 4, 0) + sage: gen_laguerre(3, 4, 0) # needs mpmath 35 """ if n == 0: @@ -2572,14 +2631,14 @@ def _pol_gen_laguerre(self, n, a, x): """ EXAMPLES:: - sage: gen_laguerre(3, 1/2, sin(x)) + sage: gen_laguerre(3, 1/2, sin(x)) # needs sage.symbolic -1/6*sin(x)^3 + 7/4*sin(x)^2 - 35/8*sin(x) + 35/16 sage: R.<x> = PolynomialRing(QQ, 'x') - sage: gen_laguerre(4, -1/2, x) + sage: gen_laguerre(4, -1/2, x) # needs mpmath 1/24*x^4 - 7/12*x^3 + 35/16*x^2 - 35/16*x + 35/128 - sage: gen_laguerre(4, -1/2, x+1) + sage: gen_laguerre(4, -1/2, x + 1) # needs mpmath 1/24*(x + 1)^4 - 7/12*(x + 1)^3 + 35/16*(x + 1)^2 - 35/16*x - 245/128 - sage: gen_laguerre(10, 1, 1+I) + sage: gen_laguerre(10, 1, 1+I) # needs sage.symbolic 25189/2100*I + 11792/2835 """ return sum(binomial(n + a, n - k) * (-1)**k / factorial(k) * x**k @@ -2589,17 +2648,15 @@ def _evalf_(self, n, a, x, **kwds): """ EXAMPLES:: - sage: gen_laguerre(100,1,RealField(300)(pi)) + sage: gen_laguerre(100, 1, RealField(300)(pi)) # needs sage.symbolic -0.89430788373354541911... - sage: gen_laguerre(10,1/2,1.+I) + sage: gen_laguerre(10,1/2,1.+I) # needs sage.symbolic 5.34469635574906 + 5.23754057922902*I """ the_parent = kwds.get('parent', None) if the_parent is None: the_parent = parent(x) - import mpmath - from sage.libs.mpmath.all import call as mpcall - return mpcall(mpmath.laguerre, n, a, x, parent=the_parent) + return _mpmath_utils_call(_mpmath_laguerre, n, a, x, parent=the_parent) def _derivative_(self, n, a, x, diff_param): """ @@ -2607,17 +2664,17 @@ def _derivative_(self, n, a, x, diff_param): EXAMPLES:: - sage: (a,n)=var('a,n') - sage: diff(gen_laguerre(n,a,x), x) + sage: a, n = var('a,n') # needs sage.symbolic + sage: diff(gen_laguerre(n,a,x), x) # needs sage.symbolic -gen_laguerre(n - 1, a + 1, x) - sage: gen_laguerre(n,a,x).diff(a) + sage: gen_laguerre(n,a,x).diff(a) # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: Derivative w.r.t. to the second index is not supported. TESTS:: - sage: diff(gen_laguerre(n,a,x), n) + sage: diff(gen_laguerre(n,a,x), n) # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: Derivative w.r.t. to the index is not supported. @@ -2631,6 +2688,7 @@ def _derivative_(self, n, a, x, diff_param): else: raise ValueError("illegal differentiation parameter {}".format(diff_param)) + gen_laguerre = Func_gen_laguerre() @@ -2659,8 +2717,8 @@ class Func_krawtchouk(OrthogonalFunction): We verify the orthogonality for `n = 4`:: sage: n = 4 - sage: p = SR.var('p') - sage: matrix([[sum(binomial(n,m) * p**m * (1-p)**(n-m) + sage: p = SR.var('p') # needs sage.symbolic + sage: matrix([[sum(binomial(n,m) * p**m * (1-p)**(n-m) # needs sage.symbolic ....: * krawtchouk(i,m,n,p) * krawtchouk(j,m,n,p) ....: for m in range(n+1)).expand().factor() ....: for i in range(n+1)] for j in range(n+1)]) @@ -2672,8 +2730,8 @@ class Func_krawtchouk(OrthogonalFunction): We verify the relationship between the Krawtchouk implementations:: - sage: q = SR.var('q') - sage: all(codes.bounds.krawtchouk(n, 1/q, j, x)*(-q)^j + sage: q = SR.var('q') # needs sage.symbolic + sage: all(codes.bounds.krawtchouk(n, 1/q, j, x)*(-q)^j # needs sage.symbolic ....: == krawtchouk(j, x, n, 1-q) for j in range(n+1)) True """ @@ -2683,10 +2741,10 @@ def __init__(self): EXAMPLES:: - sage: k,x,n,p = var('k,x,n,p') + sage: k, x, n, p = var('k,x,n,p') # needs sage.symbolic sage: TestSuite(krawtchouk).run() - sage: TestSuite(krawtchouk(k, x, n, p)).run() - sage: TestSuite(krawtchouk(3, x, n, p)).run() + sage: TestSuite(krawtchouk(k, x, n, p)).run() # needs sage.symbolic + sage: TestSuite(krawtchouk(3, x, n, p)).run() # needs sage.symbolic """ super().__init__(name="krawtchouk", nargs=4, latex_name="K") @@ -2696,8 +2754,8 @@ def eval_formula(self, k, x, n, p): EXAMPLES:: - sage: x,n,p = var('x,n,p') - sage: krawtchouk.eval_formula(3, x, n, p).expand().collect(x) + sage: x, n, p = var('x,n,p') # needs sage.symbolic + sage: krawtchouk.eval_formula(3, x, n, p).expand().collect(x) # needs sage.symbolic -1/6*n^3*p^3 + 1/2*n^2*p^3 - 1/3*n*p^3 - 1/2*(n*p - 2*p + 1)*x^2 + 1/6*x^3 + 1/6*(3*n^2*p^2 - 9*n*p^2 + 3*n*p + 6*p^2 - 6*p + 2)*x """ @@ -2711,7 +2769,8 @@ def _eval_(self, j, x, n, p, *args, **kwds): EXAMPLES:: - sage: k,x,n,p = var('k,x,n,p') + sage: # needs sage.symbolic + sage: k, x, n, p = var('k,x,n,p') sage: krawtchouk(3, x, 5, p).expand() -10*p^3 + 6*p^2*x - 3/2*p*x^2 + 1/6*x^3 + 3/2*p*x - 1/2*x^2 + 1/3*x sage: krawtchouk(k, x, 5, p) @@ -2721,11 +2780,11 @@ def _eval_(self, j, x, n, p, *args, **kwds): sage: krawtchouk(k, x, n, p) (-1)^k*p^k*binomial(n, k)*hypergeometric((-k, -x), (-n,), 1/p) - sage: k3_hypergeo = krawtchouk(k,x,n,p)(k=3).simplify_hypergeometric() - sage: bool(k3_hypergeo == krawtchouk(3,x,n,p)) + sage: k3_hypergeo = krawtchouk(k,x,n,p)(k=3).simplify_hypergeometric() # needs sage.symbolic + sage: bool(k3_hypergeo == krawtchouk(3,x,n,p)) # needs sage.symbolic True - sage: krawtchouk(2,x,n,p,hold=True) + sage: krawtchouk(2, x, n, p, hold=True) # needs sage.symbolic krawtchouk(2, x, n, p) """ if kwds.get('hold', False): @@ -2745,21 +2804,24 @@ def eval_recursive(self, j, x, n, p, *args, **kwds): EXAMPLES:: - sage: x,n,p = var('x,n,p') - sage: krawtchouk.eval_recursive(0,x,n,p) + sage: # needs sage.symbolic + sage: x, n, p = var('x,n,p') + sage: krawtchouk.eval_recursive(0, x, n, p) 1 - sage: krawtchouk.eval_recursive(1,x,n,p) + sage: krawtchouk.eval_recursive(1, x, n, p) -n*p + x - sage: krawtchouk.eval_recursive(2,x,n,p).collect(x) - 1/2*n^2*p^2 + 1/2*n*(p - 1)*p - n*p^2 + 1/2*n*p - 1/2*(2*n*p - 2*p + 1)*x + 1/2*x^2 - sage: bool(krawtchouk.eval_recursive(2,x,n,p) == krawtchouk(2,x,n,p)) + sage: krawtchouk.eval_recursive(2, x, n, p).collect(x) + 1/2*n^2*p^2 + 1/2*n*(p - 1)*p - n*p^2 + 1/2*n*p + - 1/2*(2*n*p - 2*p + 1)*x + 1/2*x^2 + sage: bool(krawtchouk.eval_recursive(2, x, n, p) == krawtchouk(2, x, n, p)) True - sage: bool(krawtchouk.eval_recursive(3,x,n,p) == krawtchouk(3,x,n,p)) + sage: bool(krawtchouk.eval_recursive(3, x, n, p) == krawtchouk(3, x, n, p)) True - sage: bool(krawtchouk.eval_recursive(4,x,n,p) == krawtchouk(4,x,n,p)) + sage: bool(krawtchouk.eval_recursive(4, x, n, p) == krawtchouk(4, x, n, p)) True - sage: M = matrix([[-1/2,-1],[1,0]]) - sage: krawtchouk.eval_recursive(2, M, 3, 1/2) + + sage: M = matrix([[-1/2, -1], [1, 0]]) # needs sage.modules + sage: krawtchouk.eval_recursive(2, M, 3, 1/2) # needs sage.modules [ 9/8 7/4] [-7/4 1/4] """ @@ -2772,6 +2834,7 @@ def eval_recursive(self, j, x, n, p, *args, **kwds): tm1 = (x - p*(n-(j-1)) - (j-1)*q) * krawtchouk.eval_recursive(j-1, x, n, p) return (tm1 - tm2) / j + krawtchouk = Func_krawtchouk() @@ -2791,10 +2854,10 @@ def __init__(self): EXAMPLES:: - sage: n,x,b,c = var('n,x,b,c') + sage: n, x, b, c = var('n,x,b,c') # needs sage.symbolic sage: TestSuite(meixner).run() - sage: TestSuite(meixner(3, x, b, c)).run() - sage: TestSuite(meixner(n, x, b, c)).run() + sage: TestSuite(meixner(3, x, b, c)).run() # needs sage.symbolic + sage: TestSuite(meixner(n, x, b, c)).run() # needs sage.symbolic """ super().__init__(name="meixner", nargs=4, latex_name="M") @@ -2804,8 +2867,8 @@ def eval_formula(self, n, x, b, c): EXAMPLES:: - sage: x,b,c = var('x,b,c') - sage: meixner.eval_formula(3, x, b, c).expand().collect(x) + sage: x, b, c = var('x,b,c') # needs sage.symbolic + sage: meixner.eval_formula(3, x, b, c).expand().collect(x) # needs sage.symbolic -x^3*(3/c - 3/c^2 + 1/c^3 - 1) + b^3 + 3*(b - 2*b/c + b/c^2 - 1/c - 1/c^2 + 1/c^3 + 1)*x^2 + 3*b^2 + (3*b^2 + 6*b - 3*b^2/c - 3*b/c - 3*b/c^2 - 2/c^3 + 2)*x + 2*b @@ -2824,7 +2887,8 @@ def _eval_(self, n, x, b, c, *args, **kwds): EXAMPLES:: - sage: n,x,b,c = var('n,x,b,c') + sage: # needs sage.symbolic + sage: n, x, b, c = var('n,x,b,c') sage: meixner(2, x, b, c).collect(x) -x^2*(2/c - 1/c^2 - 1) + b^2 + (2*b - 2*b/c - 1/c^2 + 1)*x + b sage: meixner(3, x, b, c).factor().collect(x) @@ -2834,16 +2898,17 @@ def _eval_(self, n, x, b, c, *args, **kwds): sage: meixner(n, x, b, c) gamma(b + n)*hypergeometric((-n, -x), (b,), -1/c + 1)/gamma(b) - sage: n3_hypergeo = meixner(n,x,b,c)(n=3).simplify_hypergeometric() + sage: # needs sage.symbolic + sage: n3_hypergeo = meixner(n, x, b, c)(n=3).simplify_hypergeometric() sage: n3_hypergeo = n3_hypergeo.simplify_full() - sage: bool(n3_hypergeo == meixner(3,x,b,c)) + sage: bool(n3_hypergeo == meixner(3, x, b, c)) True - sage: n4_hypergeo = meixner(n,x,b,c)(n=4).simplify_hypergeometric() + sage: n4_hypergeo = meixner(n, x, b, c)(n=4).simplify_hypergeometric() sage: n4_hypergeo = n4_hypergeo.simplify_full() - sage: bool(n4_hypergeo == meixner(4,x,b,c)) + sage: bool(n4_hypergeo == meixner(4, x, b, c)) True - sage: meixner(2,x,b,c,hold=True) + sage: meixner(2, x, b, c, hold=True) # needs sage.symbolic meixner(2, x, b, c) """ if kwds.get('hold', False): @@ -2864,24 +2929,25 @@ def eval_recursive(self, n, x, b, c, *args, **kwds): EXAMPLES:: - sage: x,b,c = var('x,b,c') - sage: meixner.eval_recursive(0,x,b,c) + sage: # needs sage.symbolic + sage: x, b, c = var('x,b,c') + sage: meixner.eval_recursive(0, x, b, c) 1 - sage: meixner.eval_recursive(1,x,b,c) + sage: meixner.eval_recursive(1, x, b, c) -x*(1/c - 1) + b - sage: meixner.eval_recursive(2,x,b,c).simplify_full().collect(x) + sage: meixner.eval_recursive(2, x, b, c).simplify_full().collect(x) -x^2*(2/c - 1/c^2 - 1) + b^2 + (2*b - 2*b/c - 1/c^2 + 1)*x + b - sage: bool(meixner(2,x,b,c) == meixner.eval_recursive(2,x,b,c)) + sage: bool(meixner(2, x, b, c) == meixner.eval_recursive(2, x, b, c)) True - sage: bool(meixner(3,x,b,c) == meixner.eval_recursive(3,x,b,c)) + sage: bool(meixner(3, x, b, c) == meixner.eval_recursive(3, x, b, c)) True - sage: bool(meixner(4,x,b,c) == meixner.eval_recursive(4,x,b,c)) + sage: bool(meixner(4, x, b, c) == meixner.eval_recursive(4, x, b, c)) True - sage: M = matrix([[-1/2,-1],[1,0]]) + sage: M = matrix([[-1/2, -1], [1, 0]]) sage: ret = meixner.eval_recursive(2, M, b, c).simplify_full().factor() sage: for i in range(2): # make the output polynomials in 1/c ....: for j in range(2): - ....: ret[i,j] = ret[i,j].collect(c) + ....: ret[i, j] = ret[i, j].collect(c) sage: ret [b^2 + 1/2*(2*b + 3)/c - 1/4/c^2 - 5/4 -2*b + (2*b - 1)/c + 3/2/c^2 - 1/2] [ 2*b - (2*b - 1)/c - 3/2/c^2 + 1/2 b^2 + b + 2/c - 1/c^2 - 1] @@ -2894,6 +2960,7 @@ def eval_recursive(self, n, x, b, c, *args, **kwds): tm1 = (b+n-1) * ((c-1) * x + n-1 + (n-1+b) * c) * meixner.eval_recursive(n-1, x, b, c) return (tm1 - tm2) / (c * (n - 1 + b)) + meixner = Func_meixner() @@ -2912,20 +2979,21 @@ class Func_hahn(OrthogonalFunction): We verify the orthogonality for `n = 3`:: + sage: # needs sage.symbolic sage: n = 2 - sage: a,b = SR.var('a,b') - sage: def rho(k,a,b,n): - ....: return binomial(a+k,k) * binomial(b+n-k,n-k) - sage: M = matrix([[sum(rho(k,a,b,n) - ....: * hahn(i,k,a,b,n) * hahn(j,k,a,b,n) - ....: for k in range(n+1)).expand().factor() + sage: a, b = SR.var('a,b') + sage: def rho(k, a, b, n): + ....: return binomial(a + k, k) * binomial(b + n - k, n - k) + sage: M = matrix([[sum(rho(k, a, b, n) + ....: * hahn(i, k, a, b, n) * hahn(j, k, a, b, n) + ....: for k in range(n + 1)).expand().factor() ....: for i in range(n+1)] for j in range(n+1)]) sage: M = M.factor() sage: P = rising_factorial - sage: def diag(i,a,b,n): - ....: return ((-1)^i * factorial(i) * P(b+1,i) * P(i+a+b+1,n+1) - ....: / (factorial(n) * (2*i+a+b+1) * P(-n,i) * P(a+1,i))) - sage: all(M[i,i] == diag(i,a,b,n) for i in range(3)) + sage: def diag(i, a, b, n): + ....: return ((-1)^i * factorial(i) * P(b + 1, i) * P(i + a + b + 1, n + 1) + ....: / (factorial(n) * (2*i + a + b + 1) * P(-n, i) * P(a + 1, i))) + sage: all(M[i,i] == diag(i, a, b, n) for i in range(3)) True sage: all(M[i,j] == 0 for i in range(3) for j in range(3) if i != j) True @@ -2936,10 +3004,10 @@ def __init__(self): EXAMPLES:: - sage: k,x,a,b,n = var('k,x,a,b,n') + sage: k, x, a, b, n = var('k,x,a,b,n') # needs sage.symbolic sage: TestSuite(hahn).run() - sage: TestSuite(hahn(3, x, a, b, n)).run() - sage: TestSuite(hahn(k, x, a, b, n)).run(skip="_test_category") + sage: TestSuite(hahn(3, x, a, b, n)).run() # needs sage.symbolic + sage: TestSuite(hahn(k, x, a, b, n)).run(skip="_test_category") # needs sage.symbolic """ super().__init__(name="hahn", nargs=5, latex_name="Q") @@ -2949,7 +3017,8 @@ def eval_formula(self, k, x, a, b, n): EXAMPLES:: - sage: k,x,a,b,n = var('k,x,a,b,n') + sage: # needs sage.symbolic + sage: k, x, a, b, n = var('k,x,a,b,n') sage: Q2 = hahn.eval_formula(2, x, a, b, n).simplify_full() sage: Q2.coefficient(x^2).factor() (a + b + 4)*(a + b + 3)/((a + 2)*(a + 1)*(n - 1)*n) @@ -2959,7 +3028,7 @@ def eval_formula(self, k, x, a, b, n): 1 """ P = rising_factorial - return sum(P(-k,i) * P(k+a+b+1,i) * P(-x,i) / (P(a+1,i) * P(-n,i) * factorial(i)) + return sum(P(-k, i) * P(k+a+b+1, i) * P(-x, i) / (P(a+1, i) * P(-n, i) * factorial(i)) for i in range(k+1)) def _eval_(self, k, x, a, b, n, *args, **kwds): @@ -2968,27 +3037,28 @@ def _eval_(self, k, x, a, b, n, *args, **kwds): EXAMPLES:: - sage: k,x,a,b,n = var('k,x,a,b,n') - sage: hahn(1, x, a, b, n).collect(x) + sage: k, x, a, b, n = var('k,x,a,b,n') # needs sage.symbolic + sage: hahn(1, x, a, b, n).collect(x) # needs sage.symbolic -(a + b + 2)*x/((a + 1)*n) + 1 - sage: hahn(k, x, a, b, n) + sage: hahn(k, x, a, b, n) # needs sage.symbolic hypergeometric((-k, a + b + k + 1, -x), (a + 1, -n), 1) - sage: k2_hypergeo = hahn(k,x,a,b,n)(k=2).simplify_hypergeometric() - sage: bool(k2_hypergeo == hahn(2,x,a,b,n)) + sage: # needs sage.symbolic + sage: k2_hypergeo = hahn(k, x, a, b, n)(k=2).simplify_hypergeometric() + sage: bool(k2_hypergeo == hahn(2, x, a, b, n)) True - sage: k3_hypergeo = hahn(k,x,a,b,n)(k=3).simplify_hypergeometric() - sage: bool(k3_hypergeo == hahn(3,x,a,b,n)) + sage: k3_hypergeo = hahn(k, x, a, b, n)(k=3).simplify_hypergeometric() + sage: bool(k3_hypergeo == hahn(3, x, a, b, n)) True - sage: hahn(2,x,a,b,n,hold=True) + sage: hahn(2, x, a, b, n, hold=True) # needs sage.symbolic hahn(2, x, a, b, n) """ if kwds.get('hold', False): return None if k not in ZZ or k < 0: from sage.functions.hypergeometric import hypergeometric - return hypergeometric([-k, k+a+b+1, -x], [a+1,-n], 1) + return hypergeometric([-k, k+a+b+1, -x], [a+1, -n], 1) try: return self.eval_formula(k, x, a, b, n) except (TypeError, ValueError): @@ -3001,20 +3071,21 @@ def eval_recursive(self, k, x, a, b, n, *args, **kwds): EXAMPLES:: - sage: x,a,b,n = var('x,a,b,n') - sage: hahn.eval_recursive(0,x,a,b,n) + sage: # needs sage.symbolic + sage: x, a, b, n = var('x,a,b,n') + sage: hahn.eval_recursive(0, x, a, b, n) 1 - sage: hahn.eval_recursive(1,x,a,b,n) + sage: hahn.eval_recursive(1, x, a, b, n) -(a + b + 2)*x/((a + 1)*n) + 1 - sage: bool(hahn(2,x,a,b,n) == hahn.eval_recursive(2,x,a,b,n)) + sage: bool(hahn(2, x, a, b, n) == hahn.eval_recursive(2, x, a, b, n)) True - sage: bool(hahn(3,x,a,b,n) == hahn.eval_recursive(3,x,a,b,n)) + sage: bool(hahn(3, x, a, b, n) == hahn.eval_recursive(3, x, a, b, n)) True - sage: bool(hahn(4,x,a,b,n) == hahn.eval_recursive(4,x,a,b,n)) + sage: bool(hahn(4, x, a, b, n) == hahn.eval_recursive(4, x, a, b, n)) True - sage: M = matrix([[-1/2,-1],[1,0]]) - sage: ret = hahn.eval_recursive(2, M, 1, 2, n).simplify_full().factor() - sage: ret + sage: M = matrix([[-1/2, -1], [1, 0]]) # needs sage.modules + sage: ret = hahn.eval_recursive(2, M, 1, 2, n).simplify_full().factor() # needs sage.modules + sage: ret # needs sage.modules [1/4*(4*n^2 + 8*n - 19)/((n - 1)*n) 3/2*(4*n + 3)/((n - 1)*n)] [ -3/2*(4*n + 3)/((n - 1)*n) (n^2 - n - 7)/((n - 1)*n)] """ diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 83f310e8b98..9dbe9787545 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -6,39 +6,37 @@ Check that gamma function imports are deprecated (:trac:`24411`):: sage: from sage.functions.other import beta - sage: beta(x, x) + sage: beta(x, x) # needs sage.symbolic doctest:warning...: DeprecationWarning: Importing beta from here is deprecated; please use "from sage.functions.gamma import beta" instead. See https://github.com/sagemath/sage/issues/24411 for details. beta(x, x) """ -from sage.misc.lazy_import import lazy_import -lazy_import('sage.functions.gamma', - ('gamma', 'log_gamma', 'gamma_inc', - 'gamma_inc_lower', 'psi', 'beta'), deprecation=24411) +import math -from sage.symbolic.function import GinacFunction, BuiltinFunction -from sage.symbolic.expression import Expression, register_symbol, symbol_table -from sage.symbolic.ring import SR, SymbolicRing +from sage.arith.misc import binomial as arith_binomial +from sage.functions.trig import arctan2 +from sage.misc.functional import sqrt +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.rational import Rational -from sage.rings.complex_mpfr import ComplexField -from sage.misc.latex import latex -from sage.structure.element import Element -import math - -from sage.structure.element import coercion_model - +from sage.structure.element import coercion_model, Element, Expression # avoid name conflicts with `parent` as a function parameter -from sage.structure.all import parent as s_parent +from sage.structure.element import parent as s_parent +from sage.symbolic.function import GinacFunction, BuiltinFunction +from sage.symbolic.symbols import register_symbol, symbol_table -from sage.functions.trig import arctan2 +lazy_import('sage.misc.latex', 'latex') +lazy_import('sage.rings.complex_mpfr', 'ComplexField') -from sage.arith.misc import binomial as arith_binomial +lazy_import('sage.symbolic.ring', 'SR') -from sage.misc.functional import sqrt + +lazy_import('sage.functions.gamma', + ('gamma', 'log_gamma', 'gamma_inc', + 'gamma_inc_lower', 'psi', 'beta'), deprecation=24411) class Function_abs(GinacFunction): @@ -48,14 +46,16 @@ def __init__(self): EXAMPLES:: + sage: abs(-2) + 2 + + sage: # needs sage.symbolic sage: var('x y') (x, y) sage: abs(x) abs(x) sage: abs(x^2 + y^2) abs(x^2 + y^2) - sage: abs(-2) - 2 sage: sqrt(x^2) sqrt(x^2) sage: abs(sqrt(x)) @@ -66,20 +66,21 @@ def __init__(self): sage: f = sage.functions.other.Function_abs() sage: latex(f) \mathrm{abs} - sage: latex(abs(x)) + sage: latex(abs(x)) # needs sage.symbolic {\left| x \right|} - sage: abs(x)._sympy_() + sage: abs(x)._sympy_() # needs sympy sage.symbolic Abs(x) Test pickling:: - sage: loads(dumps(abs(x))) + sage: loads(dumps(abs(x))) # needs sage.symbolic abs(x) TESTS: Check that :trac:`12588` is fixed:: + sage: # needs sage.symbolic sage: abs(pi*I) pi sage: abs(pi*I*catalan) @@ -117,7 +118,7 @@ def __init__(self): sage: abs((pi+e)*x) (pi + e)*abs(x) - sage: fricas(abs(x)).sage().derivative() # optional - fricas + sage: fricas(abs(x)).sage().derivative() # optional - fricas # needs sage.symbolic 1/2*(x + conjugate(x))/abs(x) """ GinacFunction.__init__(self, "abs", latex_name=r"\mathrm{abs}", @@ -126,6 +127,7 @@ def __init__(self): giac='abs', fricas='abs')) + abs = abs_symbolic = Function_abs() @@ -146,9 +148,9 @@ def _eval_floor_ceil(self, x, method, bits=0, **kwds): TESTS:: - sage: numbers = [SR(10^100 + exp(-100)), SR(10^100 - exp(-100)), SR(10^100)] - sage: numbers += [-n for n in numbers] - sage: for n in numbers: + sage: numbers = [SR(10^100 + exp(-100)), SR(10^100 - exp(-100)), SR(10^100)] # needs sage.symbolic + sage: numbers += [-n for n in numbers] # needs sage.symbolic + sage: for n in numbers: # needs sage.symbolic ....: f = floor(n) ....: c = ceil(n) ....: if f == c: @@ -158,6 +160,7 @@ def _eval_floor_ceil(self, x, method, bits=0, **kwds): A test from :trac:`12121`:: + sage: # needs sage.symbolic sage: e1 = pi - continued_fraction(pi).convergent(2785) sage: e2 = e - continued_fraction(e).convergent(1500) sage: f = e1/e2 @@ -174,7 +177,7 @@ def _eval_floor_ceil(self, x, method, bits=0, **kwds): Traceback (most recent call last): ... ValueError: Calling ceil() on infinity or NaN - sage: ceil(NaN) + sage: ceil(NaN) # needs sage.symbolic Traceback (most recent call last): ... ValueError: Calling ceil() on infinity or NaN @@ -182,10 +185,10 @@ def _eval_floor_ceil(self, x, method, bits=0, **kwds): Test that elements of symbolic subrings work in the same way as elements of ``SR``, :trac:`32724`:: - sage: SCR = SR.subring(no_variables=True) - sage: floor(log(2^(3/2)) / log(2) + 1/2) + sage: SCR = SR.subring(no_variables=True) # needs sage.symbolic + sage: floor(log(2^(3/2)) / log(2) + 1/2) # needs sage.symbolic 2 - sage: floor(SCR(log(2^(-3/2)) / log(2) + 1/2)) + sage: floor(SCR(log(2^(-3/2)) / log(2) + 1/2)) # needs sage.symbolic -1 """ # First, some obvious things... @@ -224,7 +227,7 @@ def _eval_floor_ceil(self, x, method, bits=0, **kwds): # Might it be needed to simplify x? This only applies for # elements of SR (or its subrings) - need_to_simplify = isinstance(s_parent(x), SymbolicRing) + need_to_simplify = isinstance(x, Expression) # An integer which is close to x. We use this to increase precision # by subtracting this guess before converting to an interval field. @@ -320,8 +323,8 @@ def __init__(self): EXAMPLES:: - sage: a = ceil(2/5 + x) - sage: a + sage: # needs sage.symbolic + sage: a = ceil(2/5 + x); a ceil(x + 2/5) sage: a(x=4) 5 @@ -338,7 +341,7 @@ def __init__(self): :: - sage: ceil(sin(8)/sin(2)) + sage: ceil(sin(8)/sin(2)) # needs sage.symbolic 2 :: @@ -350,45 +353,45 @@ def __init__(self): :: - sage: ceil(factorial(50)/exp(1)) + sage: ceil(factorial(50)/exp(1)) # needs sage.symbolic 11188719610782480504630258070757734324011354208865721592720336801 - sage: ceil(SR(10^50 + 10^(-50))) + sage: ceil(SR(10^50 + 10^(-50))) # needs sage.symbolic 100000000000000000000000000000000000000000000000001 - sage: ceil(SR(10^50 - 10^(-50))) + sage: ceil(SR(10^50 - 10^(-50))) # needs sage.symbolic 100000000000000000000000000000000000000000000000000 Small numbers which are extremely close to an integer are hard to deal with:: - sage: ceil((33^100 + 1)^(1/100)) + sage: ceil((33^100 + 1)^(1/100)) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot compute ceil(...) using 256 bits of precision This can be fixed by giving a sufficiently large ``bits`` argument:: - sage: ceil((33^100 + 1)^(1/100), bits=500) + sage: ceil((33^100 + 1)^(1/100), bits=500) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot compute ceil(...) using 512 bits of precision - sage: ceil((33^100 + 1)^(1/100), bits=1000) + sage: ceil((33^100 + 1)^(1/100), bits=1000) # needs sage.symbolic 34 :: - sage: ceil(sec(e)) + sage: ceil(sec(e)) # needs sage.symbolic -1 - sage: latex(ceil(x)) + sage: latex(ceil(x)) # needs sage.symbolic \left \lceil x \right \rceil - sage: ceil(x)._sympy_() + sage: ceil(x)._sympy_() # needs sympy sage.symbolic ceiling(x) :: - sage: import numpy - sage: a = numpy.linspace(0,2,6) - sage: ceil(a) + sage: import numpy # needs numpy + sage: a = numpy.linspace(0,2,6) # needs numpy + sage: ceil(a) # needs numpy array([0., 1., 1., 2., 2., 2.]) Test pickling:: @@ -405,7 +408,7 @@ def _print_latex_(self, x): r""" EXAMPLES:: - sage: latex(ceil(x)) # indirect doctest + sage: latex(ceil(x)) # indirect doctest # needs sage.symbolic \left \lceil x \right \rceil """ return r"\left \lceil %s \right \rceil"%latex(x) @@ -419,13 +422,13 @@ def __call__(self, x, **kwds): TESTS:: - sage: ceil(SR(10^50 + 10^(-50))) + sage: ceil(SR(10^50 + 10^(-50))) # needs sage.symbolic 100000000000000000000000000000000000000000000000001 - sage: ceil(SR(10^50 - 10^(-50))) + sage: ceil(SR(10^50 - 10^(-50))) # needs sage.symbolic 100000000000000000000000000000000000000000000000000 sage: ceil(int(10^50)) 100000000000000000000000000000000000000000000000000 - sage: ceil((1725033*pi - 5419351)/(25510582*pi - 80143857)) + sage: ceil((1725033*pi - 5419351)/(25510582*pi - 80143857)) # needs sage.symbolic -2 """ return _eval_floor_ceil(self, x, "ceil", **kwds) @@ -434,12 +437,13 @@ def _eval_(self, x): """ EXAMPLES:: - sage: ceil(x).subs(x==7.5) + sage: ceil(x).subs(x==7.5) # needs sage.symbolic 8 - sage: ceil(x) + sage: ceil(x) # needs sage.symbolic ceil(x) - sage: var('x',domain='integer') + sage: # needs sage.symbolic + sage: var('x', domain='integer') x sage: ceil(x) x @@ -463,6 +467,7 @@ def _eval_(self, x): return Integer(math.ceil(x)) return None + ceil = Function_ceil() @@ -496,17 +501,20 @@ def __init__(self): 5 sage: type(floor(5.4)) <class 'sage.rings.integer.Integer'> + + sage: # needs sage.symbolic sage: var('x') x - sage: a = floor(5.4 + x); a - floor(x + 5.40000000000000) + sage: a = floor(5.25 + x); a + floor(x + 5.25000000000000) sage: a.simplify() - floor(x + 0.4000000000000004) + 5 + floor(x + 0.25) + 5 sage: a(x=2) 7 :: + sage: # needs sage.symbolic sage: floor(cos(8) / cos(2)) 0 sage: floor(log(4) / log(2)) @@ -522,11 +530,11 @@ def __init__(self): :: - sage: floor(factorial(50)/exp(1)) + sage: floor(factorial(50)/exp(1)) # needs sage.symbolic 11188719610782480504630258070757734324011354208865721592720336800 - sage: floor(SR(10^50 + 10^(-50))) + sage: floor(SR(10^50 + 10^(-50))) # needs sage.symbolic 100000000000000000000000000000000000000000000000000 - sage: floor(SR(10^50 - 10^(-50))) + sage: floor(SR(10^50 - 10^(-50))) # needs sage.symbolic 99999999999999999999999999999999999999999999999999 sage: floor(int(10^50)) 100000000000000000000000000000000000000000000000000 @@ -534,27 +542,27 @@ def __init__(self): Small numbers which are extremely close to an integer are hard to deal with:: - sage: floor((33^100 + 1)^(1/100)) + sage: floor((33^100 + 1)^(1/100)) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot compute floor(...) using 256 bits of precision This can be fixed by giving a sufficiently large ``bits`` argument:: - sage: floor((33^100 + 1)^(1/100), bits=500) + sage: floor((33^100 + 1)^(1/100), bits=500) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot compute floor(...) using 512 bits of precision - sage: floor((33^100 + 1)^(1/100), bits=1000) + sage: floor((33^100 + 1)^(1/100), bits=1000) # needs sage.symbolic 33 :: - sage: import numpy - sage: a = numpy.linspace(0,2,6) - sage: floor(a) + sage: import numpy # needs numpy + sage: a = numpy.linspace(0,2,6) # needs numpy + sage: floor(a) # needs numpy array([0., 0., 0., 1., 1., 2.]) - sage: floor(x)._sympy_() + sage: floor(x)._sympy_() # needs sympy sage.symbolic floor(x) Test pickling:: @@ -569,7 +577,7 @@ def _print_latex_(self, x): r""" EXAMPLES:: - sage: latex(floor(x)) + sage: latex(floor(x)) # needs sage.symbolic \left \lfloor x \right \rfloor """ return r"\left \lfloor %s \right \rfloor"%latex(x) @@ -583,13 +591,13 @@ def __call__(self, x, **kwds): TESTS:: - sage: floor(SR(10^50 + 10^(-50))) + sage: floor(SR(10^50 + 10^(-50))) # needs sage.symbolic 100000000000000000000000000000000000000000000000000 - sage: floor(SR(10^50 - 10^(-50))) + sage: floor(SR(10^50 - 10^(-50))) # needs sage.symbolic 99999999999999999999999999999999999999999999999999 sage: floor(int(10^50)) 100000000000000000000000000000000000000000000000000 - sage: floor((1725033*pi - 5419351)/(25510582*pi - 80143857)) + sage: floor((1725033*pi - 5419351)/(25510582*pi - 80143857)) # needs sage.symbolic -3 """ return _eval_floor_ceil(self, x, "floor", **kwds) @@ -598,12 +606,13 @@ def _eval_(self, x): """ EXAMPLES:: - sage: floor(x).subs(x==7.5) + sage: floor(x).subs(x==7.5) # needs sage.symbolic 7 - sage: floor(x) + sage: floor(x) # needs sage.symbolic floor(x) - sage: var('x',domain='integer') + sage: # needs sage.symbolic + sage: var('x', domain='integer') x sage: floor(x) x @@ -627,6 +636,7 @@ def _eval_(self, x): return Integer(math.floor(x)) return None + floor = Function_floor() @@ -645,17 +655,17 @@ def __init__(self): EXAMPLES:: - sage: x = SR('x') - sage: x.Order() + sage: x = SR('x') # needs sage.symbolic + sage: x.Order() # needs sage.symbolic Order(x) - sage: (x^2 + x).Order() + sage: (x^2 + x).Order() # needs sage.symbolic Order(x^2 + x) TESTS: Check that :trac:`19425` is resolved:: - sage: x.Order().operator() + sage: x.Order().operator() # needs sage.symbolic Order """ GinacFunction.__init__(self, "Order", @@ -666,6 +676,7 @@ def _sympy_(self, arg): """ EXAMPLES:: + sage: # needs sympy sage.symbolic sage: x.Order()._sympy_() O(x) sage: SR(1).Order()._sympy_() @@ -675,9 +686,9 @@ def _sympy_(self, arg): sage: exp(x).series(x==1, 3)._sympy_() E + E*(x - 1) + E*(x - 1)**2/2 + O((x - 1)**3, (x, 1)) - sage: (-(pi-x)^3).Order()._sympy_() + sage: (-(pi-x)^3).Order()._sympy_() # needs sympy sage.symbolic O((x - pi)**3, (x, pi)) - sage: cos(x).series(x==pi, 3)._sympy_() + sage: cos(x).series(x==pi, 3)._sympy_() # needs sympy sage.symbolic -1 + (pi - x)**2/2 + O((x - pi)**3, (x, pi)) """ roots = arg.solve(arg.default_variable(), algorithm='sympy', @@ -690,6 +701,7 @@ def _sympy_(self, arg): import sympy return sympy.O(*sympy.sympify(arg, evaluate=False)) + Order = Function_Order() @@ -708,6 +720,8 @@ def __init__(self): <class 'sage.rings.real_mpfr.RealNumber'> sage: frac(456/123) 29/41 + + sage: # needs sage.symbolic sage: var('x') x sage: a = frac(5.4 + x); a @@ -716,7 +730,7 @@ def __init__(self): cos(8)/cos(2) sage: latex(frac(x)) \operatorname{frac}\left(x\right) - sage: frac(x)._sympy_() + sage: frac(x)._sympy_() # needs sympy frac(x) Test pickling:: @@ -732,9 +746,9 @@ def _evalf_(self, x, **kwds): """ EXAMPLES:: - sage: frac(pi).n() + sage: frac(pi).n() # needs sage.symbolic 0.141592653589793 - sage: frac(pi).n(200) + sage: frac(pi).n(200) # needs sage.symbolic 0.14159265358979323846264338327950288419716939937510582097494 """ return x - floor(x) @@ -743,9 +757,9 @@ def _eval_(self, x): """ EXAMPLES:: - sage: frac(x).subs(x==7.5) + sage: frac(x).subs(x==7.5) # needs sage.symbolic 0.500000000000000 - sage: frac(x) + sage: frac(x) # needs sage.symbolic frac(x) """ try: @@ -761,6 +775,7 @@ def _eval_(self, x): return x - ret return None + frac = Function_frac() @@ -781,9 +796,9 @@ class Function_real_nth_root(BuiltinFunction): EXAMPLES:: - sage: real_nth_root(2, 3) + sage: real_nth_root(2, 3) # needs sage.symbolic 2^(1/3) - sage: real_nth_root(-2, 3) + sage: real_nth_root(-2, 3) # needs sage.symbolic -2^(1/3) sage: real_nth_root(8, 3) 2 @@ -804,8 +819,8 @@ class Function_real_nth_root(BuiltinFunction): Some symbolic calculus:: - sage: f = real_nth_root(x, 5)^3 - sage: f + sage: # needs sage.symbolic + sage: f = real_nth_root(x, 5)^3; f real_nth_root(x^3, 5) sage: f.diff() 3/5*x^2*real_nth_root(x^(-12), 5) @@ -822,14 +837,14 @@ def __init__(self): TESTS:: - sage: cube_root = real_nth_root(x, 3) - sage: loads(dumps(cube_root)) + sage: cube_root = real_nth_root(x, 3) # needs sage.symbolic + sage: loads(dumps(cube_root)) # needs sage.symbolic real_nth_root(x, 3) :: - sage: f = real_nth_root(x, 3) - sage: f._sympy_() + sage: f = real_nth_root(x, 3) # needs sage.symbolic + sage: f._sympy_() # needs sympy sage.symbolic Piecewise((Abs(x)**(1/3)*sign(x), Eq(im(x), 0)), (x**(1/3), True)) """ @@ -842,9 +857,9 @@ def _print_latex_(self, base, exp): r""" TESTS:: - sage: latex(real_nth_root(x, 3)) + sage: latex(real_nth_root(x, 3)) # needs sage.symbolic x^{\frac{1}{3}} - sage: latex(real_nth_root(x^2 + x, 3)) + sage: latex(real_nth_root(x^2 + x, 3)) # needs sage.symbolic {\left(x^{2} + x\right)}^{\frac{1}{3}} """ return latex(base**(1/exp)) @@ -855,7 +870,7 @@ def _evalf_(self, base, exp, parent=None): sage: real_nth_root(RDF(-2), 3) -1.25992104989487... - sage: real_nth_root(Reals(100)(2), 2) + sage: real_nth_root(Reals(100)(2), 2) # needs sage.rings.real_mpfr 1.4142135623730950488016887242 """ if hasattr(exp, 'real_part'): @@ -894,9 +909,9 @@ def _eval_(self, base, exp): """ TESTS:: - sage: real_nth_root(x, 1) + sage: real_nth_root(x, 1) # needs sage.symbolic x - sage: real_nth_root(x, 3) + sage: real_nth_root(x, 3) # needs sage.symbolic real_nth_root(x, 3) sage: real_nth_root(RIF(2), 3) @@ -919,8 +934,8 @@ def _power_(self, base, exp, power_param=None): """ TESTS:: - sage: f = real_nth_root(x, 3) - sage: f^5 + sage: f = real_nth_root(x, 3) # needs sage.symbolic + sage: f^5 # needs sage.symbolic real_nth_root(x^5, 3) """ return self(base**power_param, exp) @@ -929,6 +944,7 @@ def _derivative_(self, base, exp, diff_param=None): """ TESTS:: + sage: # needs sage.symbolic sage: f = real_nth_root(x, 3) sage: f.diff() 1/3*real_nth_root(x^(-2), 3) @@ -944,6 +960,7 @@ def _derivative_(self, base, exp, diff_param=None): """ return 1/exp * self(base, exp)**(1-exp) + real_nth_root = Function_real_nth_root() @@ -954,6 +971,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: arg(3+i) arctan(1/3) sage: arg(-1+i) @@ -971,6 +989,7 @@ def __init__(self): sage: arg(0) 0 + sage: # needs sage.symbolic sage: latex(arg(x)) {\rm arg}\left(x\right) sage: maxima(arg(x)) @@ -979,25 +998,25 @@ def __init__(self): atan(1/2) sage: maxima(arg(sqrt(2)+i)) atan(1/sqrt(2)) - sage: arg(x)._sympy_() + sage: arg(x)._sympy_() # needs sympy arg(x) - sage: arg(2+i) + sage: arg(2+i) # needs sage.symbolic arctan(1/2) - sage: arg(sqrt(2)+i) + sage: arg(sqrt(2)+i) # needs sage.symbolic arg(sqrt(2) + I) - sage: arg(sqrt(2)+i).simplify() + sage: arg(sqrt(2)+i).simplify() # needs sage.symbolic arctan(1/2*sqrt(2)) TESTS:: - sage: arg(0.0) + sage: arg(0.0) # needs sage.rings.complex_double 0.000000000000000 - sage: arg(3.0) + sage: arg(3.0) # needs sage.rings.complex_double 0.000000000000000 - sage: arg(-2.5) + sage: arg(-2.5) # needs sage.rings.complex_double 3.14159265358979 - sage: arg(2.0+3*i) + sage: arg(2.0+3*i) # needs sage.symbolic 0.982793723247329 """ BuiltinFunction.__init__(self, "arg", @@ -1010,6 +1029,7 @@ def _eval_(self, x): """ EXAMPLES:: + sage: # needs sage.symbolic sage: arg(3+i) arctan(1/3) sage: arg(-1+i) @@ -1043,6 +1063,7 @@ def _evalf_(self, x, parent=None, algorithm=None): """ EXAMPLES:: + sage: # needs sage.rings.complex_double sage: arg(0.0) 0.000000000000000 sage: arg(3.0) @@ -1051,19 +1072,20 @@ def _evalf_(self, x, parent=None, algorithm=None): 0.00000000000000000000000000 sage: arg(3.00000000000000000000000000).prec() 90 - sage: arg(ComplexIntervalField(90)(3)).prec() - 90 - sage: arg(ComplexIntervalField(90)(3)).parent() - Real Interval Field with 90 bits of precision - sage: arg(3.0r) - 0.0 sage: arg(RDF(3)) 0.0 sage: arg(RDF(3)).parent() Real Double Field sage: arg(-2.5) 3.14159265358979 - sage: arg(2.0+3*i) + + sage: arg(ComplexIntervalField(90)(3)).prec() # needs sage.rings.complex_interval_field + 90 + sage: arg(ComplexIntervalField(90)(3)).parent() # needs sage.rings.complex_interval_field + Real Interval Field with 90 bits of precision + sage: arg(3.0r) # needs sage.rings.real_mpfr + 0.0 + sage: arg(2.0+3*i) # needs sage.symbolic 0.982793723247329 TESTS: @@ -1071,7 +1093,7 @@ def _evalf_(self, x, parent=None, algorithm=None): Make sure that the ``_evalf_`` method works when it receives a keyword argument ``parent`` :trac:`12289`:: - sage: arg(5+I, hold=True).n() + sage: arg(5+I, hold=True).n() # needs sage.symbolic 0.197395559849881 """ try: @@ -1091,6 +1113,7 @@ def _evalf_(self, x, parent=None, algorithm=None): return parent(x).arg() + arg=Function_arg() @@ -1105,19 +1128,19 @@ def __init__(self): It is possible to prevent automatic evaluation using the ``hold`` parameter:: - sage: real_part(I,hold=True) + sage: real_part(I, hold=True) # needs sage.symbolic real_part(I) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: real_part(I,hold=True).simplify() + sage: real_part(I, hold=True).simplify() # needs sage.symbolic 0 EXAMPLES:: - sage: z = 1+2*I - sage: real(z) + sage: z = 1+2*I # needs sage.symbolic + sage: real(z) # needs sage.symbolic 1 sage: real(5/3) 5/3 @@ -1134,6 +1157,7 @@ def __init__(self): Sage can recognize some expressions as real and accordingly return the identical argument:: + sage: # needs sage.symbolic sage: SR.var('x', domain='integer').real_part() x sage: SR.var('x', domain='integer').imag_part() @@ -1152,22 +1176,22 @@ def __init__(self): sage: loads(dumps(real_part)) real_part - sage: real_part(x)._sympy_() + sage: real_part(x)._sympy_() # needs sympy sage.symbolic re(x) Check if :trac:`6401` is fixed:: - sage: latex(x.real()) + sage: latex(x.real()) # needs sage.symbolic \Re \left( x \right) - sage: f(x) = function('f')(x) - sage: latex( f(x).real()) + sage: f(x) = function('f')(x) # needs sage.symbolic + sage: latex( f(x).real()) # needs sage.symbolic \Re \left( f\left(x\right) \right) Check that some real part expansions evaluate correctly (:trac:`21614`):: - sage: real(sqrt(sin(x))).subs(x==0) + sage: real(sqrt(sin(x))).subs(x==0) # needs sage.symbolic 0 """ GinacFunction.__init__(self, "real_part", @@ -1189,6 +1213,7 @@ def __call__(self, x, **kwargs): else: return GinacFunction.__call__(self, x, **kwargs) + real = real_part = Function_real_part() @@ -1200,36 +1225,36 @@ def __init__(self): It is possible to prevent automatic evaluation using the ``hold`` parameter:: - sage: imag_part(I,hold=True) + sage: imag_part(I, hold=True) # needs sage.symbolic imag_part(I) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: imag_part(I,hold=True).simplify() + sage: imag_part(I, hold=True).simplify() # needs sage.symbolic 1 TESTS:: - sage: z = 1+2*I - sage: imaginary(z) + sage: z = 1+2*I # needs sage.symbolic + sage: imaginary(z) # needs sage.symbolic 2 - sage: imag(z) + sage: imag(z) # needs sage.symbolic 2 sage: imag(complex(3, 4)) 4.0 sage: loads(dumps(imag_part)) imag_part - sage: imag_part(x)._sympy_() + sage: imag_part(x)._sympy_() # needs sympy sage.symbolic im(x) Check if :trac:`6401` is fixed:: - sage: latex(x.imag()) + sage: latex(x.imag()) # needs sage.symbolic \Im \left( x \right) - sage: f(x) = function('f')(x) - sage: latex( f(x).imag()) + sage: f(x) = function('f')(x) # needs sage.symbolic + sage: latex(f(x).imag()) # needs sage.symbolic \Im \left( f\left(x\right) \right) """ GinacFunction.__init__(self, "imag_part", @@ -1267,21 +1292,22 @@ def __init__(self): It is possible to prevent automatic evaluation using the ``hold`` parameter:: - sage: conjugate(I,hold=True) + sage: conjugate(I, hold=True) # needs sage.symbolic conjugate(I) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: conjugate(I,hold=True).simplify() + sage: conjugate(I, hold=True).simplify() # needs sage.symbolic -I TESTS:: + sage: # needs sage.symbolic sage: x,y = var('x,y') sage: x.conjugate() conjugate(x) - sage: _._sympy_() + sage: _._sympy_() # needs sympy conjugate(x) sage: latex(conjugate(x)) \overline{x} @@ -1300,6 +1326,7 @@ def __init__(self): Check if :trac:`8755` is fixed:: + sage: # needs sage.symbolic sage: conjugate(sqrt(-3)) conjugate(sqrt(-3)) sage: conjugate(sqrt(3)) @@ -1308,14 +1335,15 @@ def __init__(self): conjugate(sqrt(x)) sage: conjugate(x^2) conjugate(x)^2 - sage: var('y',domain='positive') + sage: var('y', domain='positive') y sage: conjugate(sqrt(y)) sqrt(y) Check if :trac:`10964` is fixed:: - sage: z= I*sqrt(-3); z + sage: # needs sage.symbolic + sage: z = I*sqrt(-3); z I*sqrt(-3) sage: conjugate(z) -I*conjugate(sqrt(-3)) @@ -1326,8 +1354,8 @@ def __init__(self): Check that sums are handled correctly:: - sage: y = var('y', domain='real') - sage: conjugate(y + I) + sage: y = var('y', domain='real') # needs sage.symbolic + sage: conjugate(y + I) # needs sage.symbolic y - I Test pickling:: @@ -1352,7 +1380,7 @@ def __init__(self): INPUT: - - ``n`` - a non-negative integer, a complex number (except negative + - ``n`` -- a non-negative integer, a complex number (except negative integers) or any symbolic expression @@ -1369,6 +1397,7 @@ def __init__(self): sage: factorial(6) == 6*5*4*3*2 True + sage: # needs sage.symbolic sage: x = SR.var('x') sage: f = factorial(x + factorial(x)); f factorial(x + factorial(x)) @@ -1379,24 +1408,24 @@ def __init__(self): To prevent automatic evaluation use the ``hold`` argument:: - sage: factorial(5, hold=True) + sage: factorial(5, hold=True) # needs sage.symbolic factorial(5) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: factorial(5, hold=True).simplify() + sage: factorial(5, hold=True).simplify() # needs sage.symbolic 120 We can also give input other than nonnegative integers. For other nonnegative numbers, the :func:`sage.functions.gamma.gamma` function is used:: - sage: factorial(1/2) + sage: factorial(1/2) # needs sage.symbolic 1/2*sqrt(pi) - sage: factorial(3/4) + sage: factorial(3/4) # needs sage.symbolic gamma(7/4) - sage: factorial(2.3) + sage: factorial(2.3) # needs sage.symbolic 2.68343738195577 But negative input always fails:: @@ -1408,9 +1437,9 @@ def __init__(self): And very large integers remain unevaluated:: - sage: factorial(2**64) + sage: factorial(2**64) # needs sage.symbolic factorial(18446744073709551616) - sage: SR(2**64).factorial() + sage: SR(2**64).factorial() # needs sage.symbolic factorial(18446744073709551616) TESTS: @@ -1418,6 +1447,7 @@ def __init__(self): We verify that we can convert this function to Maxima and bring it back into Sage.:: + sage: # needs sage.symbolic sage: z = var('z') sage: factorial._maxima_init_() 'factorial' @@ -1425,17 +1455,18 @@ def __init__(self): factorial(_SAGE_VAR_z) sage: _.sage() factorial(z) - sage: _._sympy_() + sage: _._sympy_() # needs sympy factorial(z) sage: k = var('k') sage: factorial(k) factorial(k) - sage: factorial(3.14) + sage: factorial(3.14) # needs sage.symbolic 7.173269190187... Test latex typesetting:: + sage: # needs sage.symbolic sage: latex(factorial(x)) x! sage: latex(factorial(2*x)) @@ -1454,6 +1485,7 @@ def __init__(self): Check that :trac:`11539` is fixed:: + sage: # needs sage.symbolic sage: (factorial(x) == 0).simplify() factorial(x) == 0 sage: maxima(factorial(x) == 0).sage() @@ -1464,8 +1496,8 @@ def __init__(self): Check that :trac:`16166` is fixed:: - sage: RBF = RealBallField(53) - sage: factorial(RBF(4.2)) # abs tol 1e-13 + sage: RBF = RealBallField(53) # needs sage.libs.flint + sage: factorial(RBF(4.2)) # abs tol 1e-13 # needs sage.libs.flint [32.5780960503314 +/- 6.06e-14] Test pickling:: @@ -1490,6 +1522,7 @@ def _eval_(self, x): EXAMPLES:: + sage: # needs sage.symbolic sage: k = var('k') sage: k.factorial() factorial(k) @@ -1508,14 +1541,14 @@ def _eval_(self, x): Check that :trac:`25421` is fixed:: - sage: factorial(RBF(2)**64) + sage: factorial(RBF(2)**64) # needs sage.libs.flint [+/- 2.30e+347382171326740403407] Check that :trac:`26749` is fixed:: - sage: factorial(float(3.2)) # abs tol 1e-14 + sage: factorial(float(3.2)) # abs tol 1e-14 # needs sage.symbolic 7.7566895357931776 - sage: type(factorial(float(3.2))) + sage: type(factorial(float(3.2))) # needs sage.symbolic <class 'float'> """ if isinstance(x, (int, Integer)): @@ -1532,6 +1565,7 @@ def _eval_(self, x): from sage.functions.gamma import gamma return gamma(x + 1) + factorial = Function_factorial() @@ -1564,40 +1598,42 @@ def __init__(self): EXAMPLES:: - sage: binomial(5,2) + sage: # needs sage.symbolic + sage: binomial(5, 2) 10 - sage: binomial(2,0) + sage: binomial(2, 0) 1 - sage: binomial(1/2, 0) + sage: binomial(1/2, 0) # needs sage.libs.pari 1 - sage: binomial(3,-1) + sage: binomial(3, -1) 0 - sage: binomial(20,10) + sage: binomial(20, 10) 184756 sage: binomial(-2, 5) -6 - sage: binomial(RealField()('2.5'), 2) - 1.87500000000000 - sage: n=var('n'); binomial(n,2) + sage: n = var('n'); binomial(n, 2) 1/2*(n - 1)*n - sage: n=var('n'); binomial(n,n) + sage: n = var('n'); binomial(n, n) 1 - sage: n=var('n'); binomial(n,n-1) + sage: n = var('n'); binomial(n, n - 1) n sage: binomial(2^100, 2^100) 1 + sage: binomial(RealField()('2.5'), 2) # needs sage.rings.real_mpfr + 1.87500000000000 + :: - sage: k, i = var('k,i') - sage: binomial(k,i) + sage: k, i = var('k,i') # needs sage.symbolic + sage: binomial(k,i) # needs sage.symbolic binomial(k, i) We can use a ``hold`` parameter to prevent automatic evaluation:: - sage: SR(5).binomial(3, hold=True) + sage: SR(5).binomial(3, hold=True) # needs sage.symbolic binomial(5, 3) - sage: SR(5).binomial(3, hold=True).simplify() + sage: SR(5).binomial(3, hold=True).simplify() # needs sage.symbolic 10 TESTS: @@ -1607,12 +1643,13 @@ def __init__(self): :: - sage: n,k = var('n,k') + sage: # needs sage.symbolic + sage: n, k = var('n,k') sage: maxima(binomial(n,k)) binomial(_SAGE_VAR_n,_SAGE_VAR_k) sage: _.sage() binomial(n, k) - sage: _._sympy_() + sage: _._sympy_() # needs sympy binomial(n, k) sage: binomial._maxima_init_() 'binomial' @@ -1620,19 +1657,19 @@ def __init__(self): For polynomials:: sage: y = polygen(QQ, 'y') - sage: binomial(y, 2).parent() + sage: binomial(y, 2).parent() # needs sage.symbolic Univariate Polynomial Ring in y over Rational Field :trac:`16726`:: - sage: binomial(CIF(1), 2) + sage: binomial(CIF(1), 2) # needs sage.symbolic 0 - sage: binomial(CIF(3), 2) + sage: binomial(CIF(3), 2) # needs sage.symbolic 3 Test pickling:: - sage: loads(dumps(binomial(n,k))) + sage: loads(dumps(binomial(n, k))) # needs sage.symbolic binomial(n, k) """ GinacFunction.__init__(self, "binomial", nargs=2, preserved_arg=1, @@ -1649,6 +1686,7 @@ def _binomial_sym(self, n, k): EXAMPLES:: + sage: # needs sage.symbolic sage: binomial._binomial_sym(x, 3) 1/6*(x - 1)*(x - 2)*x sage: binomial._binomial_sym(x, x) @@ -1657,7 +1695,6 @@ def _binomial_sym(self, n, k): ValueError: second argument must be an integer sage: binomial._binomial_sym(x, SR(3)) 1/6*(x - 1)*(x - 2)*x - sage: binomial._binomial_sym(x, 0r) 1 sage: binomial._binomial_sym(x, -1) @@ -1691,8 +1728,10 @@ def _eval_(self, n, k): 10 sage: type(binomial._eval_(5, 3)) <class 'sage.rings.integer.Integer'> - sage: type(binomial._eval_(5., 3)) + sage: type(binomial._eval_(5., 3)) # needs sage.rings.real_mpfr <class 'sage.rings.real_mpfr.RealNumber'> + + sage: # needs sage.symbolic sage: binomial._eval_(x, 3) 1/6*(x - 1)*(x - 2)*x sage: binomial._eval_(x, x-2) @@ -1726,17 +1765,18 @@ def _evalf_(self, n, k, parent=None, algorithm=None): 10.0 sage: type(binomial._evalf_(5.r, 3)) <... 'float'> - sage: binomial._evalf_(1/2,1/1) + sage: binomial._evalf_(1/2, 1/1) # needs sage.libs.pari 1/2 - sage: binomial._evalf_(10^20+1/1,10^20) + sage: binomial._evalf_(10^20 + 1/1, 10^20) 100000000000000000001 - sage: binomial._evalf_(SR(10**7),10**7) + sage: binomial._evalf_(SR(10**7), 10**7) # needs sage.symbolic 1 - sage: binomial._evalf_(3/2,SR(1/1)) + sage: binomial._evalf_(3/2, SR(1/1)) # needs sage.symbolic 3/2 """ return arith_binomial(n, k) + binomial = Function_binomial() @@ -1747,9 +1787,9 @@ class Function_sum(BuiltinFunction): EXAMPLES:: sage: from sage.functions.other import symbolic_sum as ssum - sage: r = ssum(x, x, 1, 10); r + sage: r = ssum(x, x, 1, 10); r # needs sage.symbolic sum(x, x, 1, 10) - sage: r.unhold() + sage: r.unhold() # needs sage.symbolic 55 """ def __init__(self): @@ -1757,7 +1797,7 @@ def __init__(self): EXAMPLES:: sage: from sage.functions.other import symbolic_sum as ssum - sage: maxima(ssum(x, x, 1, 10)) + sage: maxima(ssum(x, x, 1, 10)) # needs sage.symbolic 55 """ BuiltinFunction.__init__(self, "sum", nargs=4, @@ -1768,7 +1808,7 @@ def _print_latex_(self, x, var, a, b): EXAMPLES:: sage: from sage.functions.other import symbolic_sum as ssum - sage: latex(ssum(x^2, x, 1, 10)) + sage: latex(ssum(x^2, x, 1, 10)) # needs sage.symbolic {\sum_{x=1}^{10} x^{2}} """ return r"{{\sum_{{{}={}}}^{{{}}} {}}}".format(latex(var), latex(a), @@ -1780,20 +1820,21 @@ def _sympy_(self, term, k, a, n): EXAMPLES:: + sage: # needs sage.symbolic sage: var('k, n') (k, n) - sage: s = sum(k, k, 1, n, hold=True) - sage: s + sage: s = sum(k, k, 1, n, hold=True); s sum(k, k, 1, n) - sage: s._sympy_() # indirect test + sage: s._sympy_() # indirect test # needs sympy Sum(k, (k, 1, n)) - sage: s._sympy_().doit() + sage: s._sympy_().doit() # needs sympy n**2/2 + n/2 """ import sympy return sympy.Sum(term, (k, a, n)) + symbolic_sum = Function_sum() @@ -1804,25 +1845,26 @@ class Function_prod(BuiltinFunction): EXAMPLES:: sage: from sage.functions.other import symbolic_product as sprod - sage: r = sprod(x, x, 1, 10); r + sage: r = sprod(x, x, 1, 10); r # needs sage.symbolic product(x, x, 1, 10) - sage: r.unhold() + sage: r.unhold() # needs sage.symbolic 3628800 """ def __init__(self): """ EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.functions.other import symbolic_product as sprod sage: _ = var('m n', domain='integer') sage: r = maxima(sprod(sin(m), m, 1, n)).sage(); r product(sin(m), m, 1, n) sage: isinstance(r.operator(), sage.functions.other.Function_prod) True - sage: r = sympy(sprod(sin(m), m, 1, n)).sage(); r # known bug + sage: r = sympy(sprod(sin(m), m, 1, n)).sage(); r # known bug # needs sympy product(sin(m), m, 1, n) - sage: isinstance(r.operator(), - ....: sage.functions.other.Function_prod) # known bug + sage: isinstance(r.operator(), # known bug # needs sympy + ....: sage.functions.other.Function_prod) True sage: giac(sprod(m, m, 1, n)).sage() factorial(n) @@ -1836,7 +1878,7 @@ def _print_latex_(self, x, var, a, b): EXAMPLES:: sage: from sage.functions.other import symbolic_product as sprod - sage: latex(sprod(x^2, x, 1, 10)) + sage: latex(sprod(x^2, x, 1, 10)) # needs sage.symbolic {\prod_{x=1}^{10} x^{2}} """ return r"{{\prod_{{{}={}}}^{{{}}} {}}}".format(latex(var), latex(a), @@ -1848,15 +1890,16 @@ def _sympy_(self, term, k, a, n): EXAMPLES:: - sage: var('k, n') + sage: var('k, n') # needs sage.symbolic (k, n) - sage: p = product(k^2+k+1,k,1,n, hold=True) - sage: p._sympy_() # indirect test + sage: p = product(k^2 + k + 1, k, 1, n, hold=True) # needs sympy sage.symbolic + sage: p._sympy_() # indirect test # needs sympy sage.symbolic Product(k**2 + k + 1, (k, 1, n)) """ import sympy return sympy.Product(term, (k, a, n)) + symbolic_product = Function_prod() @@ -1867,11 +1910,12 @@ class Function_limit(BuiltinFunction): This function is called to create formal wrappers of limits that Maxima can't compute:: - sage: a = lim(exp(x^2)*(1-erf(x)), x=infinity); a + sage: a = lim(exp(x^2)*(1-erf(x)), x=infinity); a # needs sage.symbolic -limit((erf(x) - 1)*e^(x^2), x, +Infinity) EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.functions.other import symbolic_limit as slimit sage: slimit(1/x, x, +oo) limit(1/x, x, +Infinity) @@ -1889,7 +1933,7 @@ def __init__(self): EXAMPLES:: sage: from sage.functions.other import symbolic_limit as slimit - sage: maxima(slimit(1/x, x, +oo)) + sage: maxima(slimit(1/x, x, +oo)) # needs sage.symbolic 0 """ BuiltinFunction.__init__(self, "limit", nargs=0, @@ -1909,6 +1953,7 @@ def _print_latex_(self, ex, var, to, direction=''): r""" EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.functions.other import symbolic_limit as slimit sage: var('x,a') (x, a) @@ -1923,6 +1968,7 @@ def _print_latex_(self, ex, var, to, direction=''): When one-sided limits are converted back from maxima, the direction argument becomes a symbolic variable. We check if typesetting these works:: + sage: # needs sage.symbolic sage: from sage.functions.other import symbolic_limit as slimit sage: var('minus,plus') (minus, plus) @@ -1941,12 +1987,13 @@ def _print_latex_(self, ex, var, to, direction=''): Check if :trac:`13181` is fixed:: + sage: # needs sage.symbolic sage: t = var('t') - sage: latex(limit(exp_integral_e(1/2, I*t - I*x)*sqrt(-t + x),t=x,dir='-')) + sage: latex(limit(exp_integral_e(1/2, I*t - I*x)*sqrt(-t + x), t=x, dir='-')) \lim_{t \to x^-}\, \sqrt{-t + x} E_{\frac{1}{2}}\left(i \, t - i \, x\right) - sage: latex(limit(exp_integral_e(1/2, I*t - I*x)*sqrt(-t + x),t=x,dir='+')) + sage: latex(limit(exp_integral_e(1/2, I*t - I*x)*sqrt(-t + x), t=x, dir='+')) \lim_{t \to x^+}\, \sqrt{-t + x} E_{\frac{1}{2}}\left(i \, t - i \, x\right) - sage: latex(limit(exp_integral_e(1/2, I*t - I*x)*sqrt(-t + x),t=x)) + sage: latex(limit(exp_integral_e(1/2, I*t - I*x)*sqrt(-t + x), t=x)) \lim_{t \to x}\, \sqrt{-t + x} E_{\frac{1}{2}}\left(i \, t - i \, x\right) """ if repr(direction) == 'minus': @@ -1958,6 +2005,7 @@ def _print_latex_(self, ex, var, to, direction=''): return r"\lim_{{{} \to {}{}}}\, {}".format(latex(var), latex(to), dir_str, latex(ex)) + symbolic_limit = Function_limit() @@ -1972,6 +2020,7 @@ class Function_cases(GinacFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: ex = cases([(x==0, pi), (True, 0)]); ex cases(((x == 0, pi), (1, 0))) sage: ex.subs(x==0) @@ -1986,9 +2035,10 @@ class Function_cases(GinacFunction): The first encountered default is used, as well as the first relation that can be trivially decided:: - sage: cases(((True, pi), (True, 0))) + sage: cases(((True, pi), (True, 0))) # needs sage.symbolic pi + sage: # needs sage.symbolic sage: _ = var('y') sage: ex = cases(((x==0, pi), (y==1, 0))); ex cases(((x == 0, pi), (y == 1, 0))) @@ -2010,7 +2060,7 @@ def __call__(self, l, **kwargs): """ EXAMPLES:: - sage: ex = cases([(x==0, pi), (True, 0)]); ex + sage: ex = cases([(x==0, pi), (True, 0)]); ex # needs sage.symbolic cases(((x == 0, pi), (1, 0))) TESTS:: @@ -2020,7 +2070,7 @@ def __call__(self, l, **kwargs): ... TypeError: ...__call__() missing 1 required positional argument: 'l' - sage: cases(x) + sage: cases(x) # needs sage.symbolic Traceback (most recent call last): ... RuntimeError: cases argument not a sequence @@ -2032,17 +2082,16 @@ def _print_latex_(self, l, **kwargs): r""" EXAMPLES:: - sage: ex = cases([(x==0, pi), (True, 0)]); ex + sage: ex = cases([(x==0, pi), (True, 0)]); ex # needs sage.symbolic cases(((x == 0, pi), (1, 0))) - sage: latex(ex) + sage: latex(ex) # needs sage.symbolic \begin{cases}{\pi} & {x = 0}\\{0} & {1}\end{cases} TESTS: Verify that :trac:`25624` is fixed:: - sage: L = latex(cases([(x == 0, 0), (1, 1)])) - sage: L + sage: L = latex(cases([(x == 0, 0), (1, 1)])); L # needs sage.symbolic \begin{cases}{0} & {x = 0}\\{1} & {1}\end{cases} """ if not isinstance(l, (list, tuple)): @@ -2063,10 +2112,9 @@ def _sympy_(self, l): EXAMPLES:: - sage: ex = cases(((x<0, pi), (x==1, 1), (True, 0))) - sage: assert ex == ex._sympy_()._sage_() + sage: ex = cases(((x<0, pi), (x==1, 1), (True, 0))) # needs sage.symbolic + sage: assert ex == ex._sympy_()._sage_() # needs sympy sage.symbolic """ - from sage.symbolic.ring import SR from sympy import Piecewise as pw args = [] for tup in l.operands(): @@ -2094,6 +2142,7 @@ class Function_crootof(BuiltinFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: c = complex_root_of(x^6 + x + 1, 1); c complex_root_of(x^6 + x + 1, 1) sage: c.n() @@ -2118,6 +2167,7 @@ def _eval_(self, poly, index): """ TESTS:: + sage: # needs sage.symbolic sage: _ = var('y') sage: complex_root_of(1, 1) Traceback (most recent call last): @@ -2143,9 +2193,9 @@ def _evalf_(self, poly, index, parent=None, algorithm=None): """ EXAMPLES:: - sage: complex_root_of(x^2-2, 1).n() + sage: complex_root_of(x^2 - 2, 1).n() # needs sage.symbolic 1.41421356237309 - sage: complex_root_of(x^2-2, 3).n() + sage: complex_root_of(x^2 - 2, 3).n() # needs sage.symbolic Traceback (most recent call last): ... IndexError: root index out of [-2, 1] range, got 3 @@ -2154,9 +2204,9 @@ def _evalf_(self, poly, index, parent=None, algorithm=None): Check that low precision is handled (:trac:`24378`):: - sage: complex_root_of(x^8-1, 7).n(2) + sage: complex_root_of(x^8 - 1, 7).n(2) # needs sage.symbolic 0.75 + 0.75*I - sage: complex_root_of(x^8-1, 7).n(20) + sage: complex_root_of(x^8 - 1, 7).n(20) # needs sage.symbolic 0.70711 + 0.70711*I """ from sympy.core.evalf import prec_to_dps @@ -2168,6 +2218,7 @@ def _evalf_(self, poly, index, parent=None, algorithm=None): sobj = CRootOf(Poly(poly._sympy_()), int(index)) return parent(sobj.n(1 + prec_to_dps(prec))._sage_()) + complex_root_of = Function_crootof() @@ -2176,12 +2227,13 @@ class Function_elementof(BuiltinFunction): Formal set membership function that is only accessible internally. This function is called to express a set membership statement, - usually as part of a solution set returned by ``solve()``. + usually as part of a solution set returned by :func:`solve`. See :class:`sage.sets.set.Set` and :class:`sage.sets.real_set.RealSet` for possible set arguments. EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.functions.other import element_of sage: element_of(x, SR(ZZ)) element_of(x, Integer Ring) @@ -2208,9 +2260,9 @@ def _eval_(self, x, s): EXAMPLES:: sage: from sage.functions.other import element_of - sage: element_of(x, SR(RealSet(-oo, oo))) + sage: element_of(x, SR(RealSet(-oo, oo))) # needs sage.symbolic element_of(x, (-oo, +oo)) - sage: element_of(x, 0) + sage: element_of(x, 0) # needs sage.symbolic Traceback (most recent call last): ... ValueError: not a set: 0 @@ -2234,11 +2286,12 @@ def _print_latex_(self, ex, s): EXAMPLES:: sage: from sage.functions.other import element_of - sage: latex(element_of(x, SR(ZZ))) + sage: latex(element_of(x, SR(ZZ))) # needs sage.symbolic x \in \Bold{Z} - sage: latex(element_of(x, SR(Set([4,6,8])))) + sage: latex(element_of(x, SR(Set([4,6,8])))) # needs sage.symbolic x \in \left\{8, 4, 6\right\} """ return r"{} \in {}".format(latex(ex), latex(s)) + element_of = Function_elementof() diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index 10d82e3709a..ff3851a1776 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic r""" Piecewise functions @@ -71,11 +71,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - -from sage.symbolic.function import BuiltinFunction -from sage.sets.real_set import RealSet -from sage.symbolic.ring import SR +from sage.misc.lazy_import import lazy_import from sage.rings.infinity import minus_infinity, infinity +from sage.sets.real_set import RealSet +from sage.symbolic.function import BuiltinFunction + +lazy_import('sage.symbolic.ring', 'SR') class PiecewiseFunction(BuiltinFunction): @@ -756,17 +757,22 @@ def integral(self, parameters, variable, x=None, a=None, b=None, definite=False, sage: f2(x) = 3 - x sage: f = piecewise([[(-2, 0), f1], [(0, 3), f2]]) sage: f.integral() - piecewise(x|-->2*x + 4 on (-2, 0), x|-->-1/2*x^2 + 3*x + 4 on (0, 3); x) + piecewise(x|-->2*x + 4 on (-2, 0), + x|-->-1/2*x^2 + 3*x + 4 on (0, 3); x) sage: f1(y) = -1 sage: f2(y) = y + 3 sage: f3(y) = -y - 1 sage: f4(y) = y^2 - 1 sage: f5(y) = 3 - sage: f = piecewise([[[-4,-3],f1],[(-3,-2),f2],[[-2,0],f3],[(0,2),f4],[[2,3],f5]]) - sage: F = f.integral(y) - sage: F - piecewise(y|-->-y - 4 on [-4, -3], y|-->1/2*y^2 + 3*y + 7/2 on (-3, -2), y|-->-1/2*y^2 - y - 1/2 on [-2, 0], y|-->1/3*y^3 - y - 1/2 on (0, 2), y|-->3*y - 35/6 on [2, 3]; y) + sage: f = piecewise([[[-4,-3],f1], [(-3,-2),f2], [[-2,0],f3], + ....: [(0,2),f4], [[2,3],f5]]) + sage: F = f.integral(y); F + piecewise(y|-->-y - 4 on [-4, -3], + y|-->1/2*y^2 + 3*y + 7/2 on (-3, -2), + y|-->-1/2*y^2 - y - 1/2 on [-2, 0], + y|-->1/3*y^3 - y - 1/2 on (0, 2), + y|-->3*y - 35/6 on [2, 3]; y) Ensure results are consistent with FTC:: @@ -792,7 +798,9 @@ def integral(self, parameters, variable, x=None, a=None, b=None, definite=False, sage: f3(y) = 3 sage: f = piecewise([[(-infinity, -3), f1], [(-3, 0), f2], [(0, infinity), f3]]) sage: f.integral() - piecewise(y|-->1/3*y^3 + 3*y^2 + 9*y + 9 on (-oo, -3), y|-->1/2*y^2 + 3*y + 9/2 on (-3, 0), y|-->3*y + 9/2 on (0, +oo); y) + piecewise(y|-->1/3*y^3 + 3*y^2 + 9*y + 9 on (-oo, -3), + y|-->1/2*y^2 + 3*y + 9/2 on (-3, 0), + y|-->3*y + 9/2 on (0, +oo); y) :: @@ -934,33 +942,51 @@ def convolution(self, parameters, variable, other): EXAMPLES:: sage: x = PolynomialRing(QQ,'x').gen() - sage: f = piecewise([[[0,1],1]]) ## example 0 + sage: f = piecewise([[[0,1],1]]) ## example 0 sage: g = f.convolution(f); g piecewise(x|-->x on (0, 1], x|-->-x + 2 on (1, 2]; x) sage: h = f.convolution(g); h - piecewise(x|-->1/2*x^2 on (0, 1], x|-->-x^2 + 3*x - 3/2 on (1, 2], x|-->1/2*x^2 - 3*x + 9/2 on (2, 3]; x) - sage: f = piecewise([[(0,1),1],[(1,2),2],[(2,3),1]]) ## example 1 + piecewise(x|-->1/2*x^2 on (0, 1], + x|-->-x^2 + 3*x - 3/2 on (1, 2], + x|-->1/2*x^2 - 3*x + 9/2 on (2, 3]; x) + sage: f = piecewise([[(0,1),1], [(1,2),2], [(2,3),1]]) ## example 1 sage: g = f.convolution(f) sage: h = f.convolution(g); h - piecewise(x|-->1/2*x^2 on (0, 1], x|-->2*x^2 - 3*x + 3/2 on (1, 3], x|-->-2*x^2 + 21*x - 69/2 on (3, 4], x|-->-5*x^2 + 45*x - 165/2 on (4, 5], x|-->-2*x^2 + 15*x - 15/2 on (5, 6], x|-->2*x^2 - 33*x + 273/2 on (6, 8], x|-->1/2*x^2 - 9*x + 81/2 on (8, 9]; x) - sage: f = piecewise([[(-1,1),1]]) ## example 2 + piecewise(x|-->1/2*x^2 on (0, 1], + x|-->2*x^2 - 3*x + 3/2 on (1, 3], + x|-->-2*x^2 + 21*x - 69/2 on (3, 4], + x|-->-5*x^2 + 45*x - 165/2 on (4, 5], + x|-->-2*x^2 + 15*x - 15/2 on (5, 6], + x|-->2*x^2 - 33*x + 273/2 on (6, 8], + x|-->1/2*x^2 - 9*x + 81/2 on (8, 9]; x) + sage: f = piecewise([[(-1,1),1]]) ## example 2 sage: g = piecewise([[(0,3),x]]) sage: f.convolution(g) - piecewise(x|-->1/2*x^2 + x + 1/2 on (-1, 1], x|-->2*x on (1, 2], x|-->-1/2*x^2 + x + 4 on (2, 4]; x) - sage: g = piecewise([[(0,3),1],[(3,4),2]]) + piecewise(x|-->1/2*x^2 + x + 1/2 on (-1, 1], + x|-->2*x on (1, 2], + x|-->-1/2*x^2 + x + 4 on (2, 4]; x) + sage: g = piecewise([[(0,3),1], [(3,4),2]]) sage: f.convolution(g) - piecewise(x|-->x + 1 on (-1, 1], x|-->2 on (1, 2], x|-->x on (2, 3], x|-->-x + 6 on (3, 4], x|-->-2*x + 10 on (4, 5]; x) + piecewise(x|-->x + 1 on (-1, 1], + x|-->2 on (1, 2], + x|-->x on (2, 3], + x|-->-x + 6 on (3, 4], + x|-->-2*x + 10 on (4, 5]; x) Check that the bugs raised in :trac:`12123` are fixed:: sage: f = piecewise([[(-2, 2), 2]]) sage: g = piecewise([[(0, 2), 3/4]]) sage: f.convolution(g) - piecewise(x|-->3/2*x + 3 on (-2, 0], x|-->3 on (0, 2], x|-->-3/2*x + 6 on (2, 4]; x) + piecewise(x|-->3/2*x + 3 on (-2, 0], + x|-->3 on (0, 2], + x|-->-3/2*x + 6 on (2, 4]; x) sage: f = piecewise([[(-1, 1), 1]]) sage: g = piecewise([[(0, 1), x], [(1, 2), -x + 2]]) sage: f.convolution(g) - piecewise(x|-->1/2*x^2 + x + 1/2 on (-1, 0], x|-->-1/2*x^2 + x + 1/2 on (0, 2], x|-->1/2*x^2 - 3*x + 9/2 on (2, 3]; x) + piecewise(x|-->1/2*x^2 + x + 1/2 on (-1, 0], + x|-->-1/2*x^2 + x + 1/2 on (0, 2], + x|-->1/2*x^2 - 3*x + 9/2 on (2, 3]; x) """ from sage.symbolic.integration.integral import definite_integral f = self @@ -1014,11 +1040,14 @@ def trapezoid(self, parameters, variable, N): sage: f = piecewise([[[0,1], x^2], [RealSet.open_closed(1,2), 5-x^2]]) sage: f.trapezoid(2) - piecewise(x|-->1/2*x on (0, 1/2), x|-->3/2*x - 1/2 on (1/2, 1), x|-->7/2*x - 5/2 on (1, 3/2), x|-->-7/2*x + 8 on (3/2, 2); x) - sage: f = piecewise([[[-1,1], 1-x^2]]) + piecewise(x|-->1/2*x on (0, 1/2), + x|-->3/2*x - 1/2 on (1/2, 1), + x|-->7/2*x - 5/2 on (1, 3/2), + x|-->-7/2*x + 8 on (3/2, 2); x) + sage: f = piecewise([[[-1,1], 1 - x^2]]) sage: f.trapezoid(4).integral(definite=True) 5/4 - sage: f = piecewise([[[-1,1], 1/2+x-x^3]]) ## example 3 + sage: f = piecewise([[[-1,1], 1/2 + x - x^3]]) ## example 3 sage: f.trapezoid(6).integral(definite=True) 1 @@ -1031,7 +1060,10 @@ def trapezoid(self, parameters, variable, N): sage: f2 = 5-y^2 sage: f = piecewise([[[0,1],f1], [RealSet.open_closed(1,2),f2]]) sage: f.trapezoid(2) - piecewise(y|-->1/2*y on (0, 1/2), y|-->3/2*y - 1/2 on (1/2, 1), y|-->7/2*y - 5/2 on (1, 3/2), y|-->-7/2*y + 8 on (3/2, 2); y) + piecewise(y|-->1/2*y on (0, 1/2), + y|-->3/2*y - 1/2 on (1/2, 1), + y|-->7/2*y - 5/2 on (1, 3/2), + y|-->-7/2*y + 8 on (3/2, 2); y) """ def func(x0, x1): f0, f1 = self(x0), self(x1) @@ -1066,7 +1098,7 @@ def laplace(self, parameters, variable, x='x', s='t'): EXAMPLES:: sage: x, s, w = var('x, s, w') - sage: f = piecewise([[(0,1),1],[[1,2], 1-x]]) + sage: f = piecewise([[(0,1),1], [[1,2], 1 - x]]) sage: f.laplace(x, s) -e^(-s)/s + (s + 1)*e^(-2*s)/s^2 + 1/s - e^(-s)/s^2 sage: f.laplace(x, w) @@ -1075,7 +1107,7 @@ def laplace(self, parameters, variable, x='x', s='t'): :: sage: y, t = var('y, t') - sage: f = piecewise([[[1,2], 1-y]]) + sage: f = piecewise([[[1,2], 1 - y]]) sage: f.laplace(y, t) (t + 1)*e^(-2*t)/t^2 - e^(-t)/t^2 @@ -1085,11 +1117,13 @@ def laplace(self, parameters, variable, x='x', s='t'): sage: t = var('t') sage: f1(t) = -t sage: f2(t) = 2 - sage: f = piecewise([[[0,1],f1],[(1,infinity),f2]]) + sage: f = piecewise([[[0,1],f1], [(1,infinity),f2]]) sage: f.laplace(t,s) (s + 1)*e^(-s)/s^2 + 2*e^(-s)/s - 1/s^2 """ - from sage.all import assume, exp, forget + from sage.symbolic.assumptions import assume, forget + from sage.functions.log import exp + x = SR.var(x) s = SR.var(s) assume(s>0) @@ -1149,8 +1183,8 @@ def fourier_series_cosine_coefficient(self, parameters, more than one period, the half-period must be passed as the second argument; for instance:: - sage: f2 = piecewise([((0,1), x), ((1,2), 2-x), - ....: ((2,3), x-2), ((3,4), 2-(x-2))]) + sage: f2 = piecewise([((0,1), x), ((1,2), 2 - x), + ....: ((2,3), x - 2), ((3,4), 2 - (x-2))]) sage: bool(f2.restriction((0,2)) == f) # f2 extends f on (0,4) True sage: f2.fourier_series_cosine_coefficient(3, 1) # half-period = 1 @@ -1158,7 +1192,7 @@ def fourier_series_cosine_coefficient(self, parameters, The default half-period is 2 and one has:: - sage: f2.fourier_series_cosine_coefficient(3) # half-period = 2 + sage: f2.fourier_series_cosine_coefficient(3) # half-period = 2 0 The Fourier coefficient `-4/(9\pi^2)` obtained above is actually @@ -1180,7 +1214,8 @@ def fourier_series_cosine_coefficient(self, parameters, -3/5/pi """ - from sage.all import cos, pi + from sage.functions.trig import cos + from sage.symbolic.constants import pi L0 = (self.domain().sup() - self.domain().inf()) / 2 if not L: L = L0 @@ -1270,7 +1305,8 @@ def fourier_series_sine_coefficient(self, parameters, variable, 4/3/pi """ - from sage.all import sin, pi + from sage.functions.trig import sin + from sage.symbolic.constants import pi L0 = (self.domain().sup() - self.domain().inf()) / 2 if not L: L = L0 @@ -1358,7 +1394,10 @@ def fourier_series_partial_sum(self, parameters, variable, N, - 4/9*sin(3*pi*x)/pi^2 + 4*sin(pi*x)/pi^2 + 1/4 """ - from sage.all import pi, sin, cos, srange + from sage.symbolic.constants import pi + from sage.functions.trig import cos, sin + from sage.arith.srange import srange + if not L: L = (self.domain().sup() - self.domain().inf()) / 2 x = self.default_variable() @@ -1375,15 +1414,15 @@ def _sympy_(self, parameters, variable): EXAMPLES:: sage: ex = piecewise([((0, 1), pi), ([1, 2], x)]) - sage: f = ex._sympy_(); f + sage: f = ex._sympy_(); f # needs sympy Piecewise((pi, (x > 0) & (x < 1)), (x, (x >= 1) & (x <= 2))) - sage: f.diff() + sage: f.diff() # needs sympy Piecewise((0, (x > 0) & (x < 1)), (1, (x >= 1) & (x <= 2))) sage: ex = piecewise([((-100, -2), 1/x), ((1, +oo), cos(x))]) - sage: g = ex._sympy_(); g + sage: g = ex._sympy_(); g # needs sympy Piecewise((1/x, (x > -100) & (x < -2)), (cos(x), x > 1)) - sage: g.diff() + sage: g.diff() # needs sympy Piecewise((-1/x**2, (x > -100) & (x < -2)), (-sin(x), x > 1)) """ from sympy import Piecewise as pw @@ -1401,29 +1440,29 @@ def _giac_init_(self, parameters, variable): EXAMPLES:: sage: ex = piecewise([((0, 1), pi), ([1, 2], x)]) - sage: f = ex._giac_(); f + sage: f = ex._giac_(); f # needs sage.libs.giac piecewise(((sageVARx>0) and (1>sageVARx)),pi,((sageVARx>=1) and (2>=sageVARx)),sageVARx) - sage: f.diff(x) + sage: f.diff(x) # needs sage.libs.giac piecewise(((sageVARx>0) and (1>sageVARx)),0,((sageVARx>=1) and (2>=sageVARx)),1) - sage: ex = piecewise([((-100, -2), 1/x), ((1, +oo), cos(x))]) - sage: g = ex._giac_(); g + sage: ex = piecewise([((-100, -2), 1/x), ((1, +oo), cos(x))]) # needs sage.libs.giac + sage: g = ex._giac_(); g # needs sage.libs.giac piecewise(((sageVARx>-100) and ((-2)>sageVARx)),1/sageVARx,sageVARx>1,cos(sageVARx)) - sage: g.diff(x) + sage: g.diff(x) # needs sage.libs.giac piecewise(((sageVARx>-100) and ((-2)>sageVARx)),-1/sageVARx^2,sageVARx>1,-sin(sageVARx)) TESTS:: - sage: f = piecewise([([0,1],x),((1,2),3*x)]) - sage: a = libgiac(f) # random because verbose - sage: a + sage: f = piecewise([([0,1], x), ((1,2), 3*x)]) + sage: a = libgiac(f) # random because verbose # needs sage.libs.giac + sage: a # needs sage.libs.giac piecewise(((sageVARx>=0) and (1>=sageVARx)),sageVARx,((sageVARx>1) and (2>sageVARx)),sageVARx*3) """ from sage.misc.flatten import flatten args = [(domain._giac_condition_(variable), func._giac_init_()) for domain, func in parameters] - args = ",".join(a for a in flatten(args)) + args = ",".join(flatten(args)) return f"piecewise({args})" diff --git a/src/sage/functions/prime_pi.pyx b/src/sage/functions/prime_pi.pyx index 38c68a2d4b4..141e538cf74 100644 --- a/src/sage/functions/prime_pi.pyx +++ b/src/sage/functions/prime_pi.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs primecountpy r""" Counting primes @@ -32,10 +33,13 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.misc.lazy_import import LazyImport from sage.rings.integer cimport Integer from sage.symbolic.function cimport BuiltinFunction -from primecountpy.primecount import prime_pi as _prime_pi -from primecountpy.primecount import phi as _phi + +_prime_pi = LazyImport('primecountpy.primecount', 'prime_pi', as_name='prime_pi') +_phi = LazyImport('primecountpy.primecount', 'phi', as_name='_phi') + cdef class PrimePi(BuiltinFunction): def __init__(self): @@ -45,8 +49,8 @@ cdef class PrimePi(BuiltinFunction): INPUT: - - ``x`` - a real number - - ``prime_bound`` - (default 0) a real number < 2^32, ``prime_pi`` will + - ``x`` -- a real number + - ``prime_bound`` -- (default 0) a real number < 2^32; :func:`prime_pi` will make sure to use all the primes up to ``prime_bound`` (although, possibly more) in computing ``prime_pi``, this can potentially speedup the time of computation, at a cost to memory usage. @@ -59,6 +63,7 @@ cdef class PrimePi(BuiltinFunction): These examples test common inputs:: + sage: # needs sage.symbolic sage: prime_pi(7) 4 sage: prime_pi(100) @@ -73,23 +78,25 @@ cdef class PrimePi(BuiltinFunction): The following test is to verify that :trac:`4670` has been essentially resolved:: - sage: prime_pi(10^10) + sage: prime_pi(10^10) # needs sage.symbolic 455052511 - The ``prime_pi`` function also has a special plotting method, so it + The :func:`prime_pi` function also has a special plotting method, so it plots quickly and perfectly as a step function:: - sage: P = plot(prime_pi, 50, 100) + sage: P = plot(prime_pi, 50, 100) # needs sage.plot sage.symbolic """ super(PrimePi, self).__init__('prime_pi', latex_name=r"\pi", - conversions={'mathematica':'PrimePi', 'pari':'primepi', - 'sympy':'primepi'}) + conversions={'mathematica': 'PrimePi', + 'pari': 'primepi', + 'sympy': 'primepi'}) def __call__(self, *args, coerce=True, hold=False): r""" EXAMPLES:: + sage: # needs sage.symbolic sage: prime_pi.__call__(756) 133 sage: prime_pi.__call__(6574, 577) @@ -104,8 +111,8 @@ cdef class PrimePi(BuiltinFunction): TypeError: Symbolic function prime_pi takes 1 or 2 arguments (3 given) """ if len(args) > 2: - raise TypeError("Symbolic function %s takes 1 or 2"%self._name - + " arguments (%s given)"%len(args)) + raise TypeError(f"Symbolic function {self._name} takes 1 or 2" + f" arguments ({len(args)} given)") return super(PrimePi, self).__call__(args[0], coerce=coerce, hold=hold) def _eval_(self, x): @@ -127,7 +134,7 @@ cdef class PrimePi(BuiltinFunction): Make sure we actually compute correct results for 64-bit entries:: - sage: for i in (32..42): prime_pi(2^i) # long time (13s on sage.math, 2011) + sage: for i in (32..42): prime_pi(2^i) # long time (13s on sage.math, 2011) 203280221 393615806 762939111 @@ -180,28 +187,29 @@ cdef class PrimePi(BuiltinFunction): EXAMPLES:: - sage: plot(prime_pi, 1, 100) + sage: plot(prime_pi, 1, 100) # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive - sage: prime_pi.plot(1, 51, thickness=2, vertical_lines=False) + sage: prime_pi.plot(1, 51, thickness=2, vertical_lines=False) # needs sage.plot sage.symbolic Graphics object consisting of 16 graphics primitives """ from sage.plot.step import plot_step_function if xmax < xmin: return plot_step_function([], **kwds) if xmax < 2: - return plot_step_function([(xmin,0),(xmax,0)], **kwds) + return plot_step_function([(xmin, 0), (xmax, 0)], **kwds) y = self(xmin) v = [(xmin, y)] from sage.rings.fast_arith import prime_range for p in prime_range(xmin+1, xmax+1, py_ints=True): y += 1 - v.append((p,y)) - v.append((xmax,y)) + v.append((p, y)) + v.append((xmax, y)) return plot_step_function(v, vertical_lines=vertical_lines, **kwds) -######## + prime_pi = PrimePi() + cpdef Integer legendre_phi(x, a): r""" Legendre's formula, also known as the partial sieve function, is a useful @@ -235,22 +243,26 @@ cpdef Integer legendre_phi(x, a): if not isinstance(a, Integer): a = Integer(a) if a < Integer(0): - raise ValueError("a (=%s) must be non-negative"%a) + raise ValueError("a (=%s) must be non-negative" % a) y = Integer(x) # legendre_phi(x, a) = 0 when x <= 0 - if not y: return Integer(0) + if not y: + return Integer(0) # legendre_phi(x, 0) = x - if a == Integer(0): return Integer(y) + if a == Integer(0): + return Integer(y) # If a > prime_pi(2^32), we compute phi(x,a) = max(pi(x)-a+1,1) if a > Integer(203280221): ret = prime_pi(x)-a+Integer(1) - if ret < Integer(1): return Integer(1) + if ret < Integer(1): + return Integer(1) return ret # Deal with the general case return Integer(_phi(y, a)) + partial_sieve_function = legendre_phi diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 56f96f2ef53..93e032d0677 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -141,15 +141,27 @@ # **************************************************************************** import sage.rings.abc + +from sage.misc.functional import sqrt +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer -from sage.misc.latex import latex from sage.rings.integer_ring import ZZ -from sage.symbolic.constants import pi +from sage.structure.element import parent as s_parent from sage.symbolic.function import BuiltinFunction -from sage.libs.mpmath import utils as mpmath_utils -from sage.functions.all import sin, cot, exp -from sage.misc.functional import sqrt -from sage.symbolic.constants import I + +lazy_import('sage.functions.jacobi', 'jacobi_am_f') +lazy_import('sage.functions.log', ['exp']) +lazy_import('sage.functions.trig', ['sin', 'cot']) + +lazy_import('sage.misc.latex', 'latex') + +lazy_import('sage.symbolic.constants', ['I', 'pi']) + +lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') +lazy_import('mpmath', + ['spherharm', 'ellipe', 'ellipf', 'ellipk', 'ellippi'], + as_=['_mpmath_spherharm', '_mpmath_ellipe', '_mpmath_ellipf', + '_mpmath_ellipk', '_mpmath_ellippi']) class SphericalHarmonic(BuiltinFunction): @@ -161,6 +173,7 @@ class SphericalHarmonic(BuiltinFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: x, y = var('x, y') sage: spherical_harmonic(3, 2, x, y) 1/8*sqrt(30)*sqrt(7)*cos(x)*e^(2*I*y)*sin(x)^2/sqrt(pi) @@ -175,6 +188,7 @@ class SphericalHarmonic(BuiltinFunction): The degree `n` and the order `m` can be symbolic:: + sage: # needs sage.symbolic sage: n, m = var('n m') sage: spherical_harmonic(n, m, x, y) spherical_harmonic(n, m, x, y) @@ -189,26 +203,27 @@ class SphericalHarmonic(BuiltinFunction): The convention regarding the Condon-Shortley phase `(-1)^m` is the same as for SymPy's spherical harmonics and :wikipedia:`Spherical_harmonics`:: + sage: # needs sage.symbolic sage: spherical_harmonic(1, 1, x, y) -1/4*sqrt(3)*sqrt(2)*e^(I*y)*sin(x)/sqrt(pi) - sage: from sympy import Ynm - sage: Ynm(1, 1, x, y).expand(func=True) + sage: from sympy import Ynm # needs sympy + sage: Ynm(1, 1, x, y).expand(func=True) # needs sympy -sqrt(6)*exp(I*y)*sin(x)/(4*sqrt(pi)) - sage: spherical_harmonic(1, 1, x, y) - Ynm(1, 1, x, y) + sage: spherical_harmonic(1, 1, x, y) - Ynm(1, 1, x, y) # needs sympy 0 It also agrees with SciPy's spherical harmonics:: - sage: spherical_harmonic(1, 1, pi/2, pi).n() # abs tol 1e-14 + sage: spherical_harmonic(1, 1, pi/2, pi).n() # abs tol 1e-14 # needs sage.symbolic 0.345494149471335 - sage: from scipy.special import sph_harm # NB: arguments x and y are swapped - sage: sph_harm(1, 1, pi.n(), (pi/2).n()) # abs tol 1e-14 + sage: from scipy.special import sph_harm # NB: arguments x and y are swapped # needs scipy + sage: sph_harm(1, 1, pi.n(), (pi/2).n()) # abs tol 1e-14 # needs scipy sage.symbolic (0.3454941494713355-4.231083042742082e-17j) Note that this convention differs from the one in Maxima, as revealed by the sign difference for odd values of `m`:: - sage: maxima.spherical_harmonic(1, 1, x, y).sage() + sage: maxima.spherical_harmonic(1, 1, x, y).sage() # needs sage.symbolic 1/2*sqrt(3/2)*e^(I*y)*sin(x)/sqrt(pi) It follows that, contrary to Maxima, SageMath uses the same sign convention @@ -224,21 +239,22 @@ def __init__(self): r""" TESTS:: - sage: n, m, theta, phi = var('n m theta phi') - sage: spherical_harmonic(n, m, theta, phi)._sympy_() + sage: n, m, theta, phi = var('n m theta phi') # needs sage.symbolic + sage: spherical_harmonic(n, m, theta, phi)._sympy_() # needs sympy sage.symbolic Ynm(n, m, theta, phi) """ BuiltinFunction.__init__(self, 'spherical_harmonic', nargs=4, conversions=dict( - maple='SphericalY', - mathematica='SphericalHarmonicY', - maxima='spherical_harmonic', - sympy='Ynm')) + maple='SphericalY', + mathematica='SphericalHarmonicY', + maxima='spherical_harmonic', + sympy='Ynm')) def _eval_(self, n, m, theta, phi, **kwargs): r""" TESTS:: + sage: # needs sage.symbolic sage: x, y = var('x y') sage: spherical_harmonic(1, 2, x, y) 0 @@ -255,28 +271,29 @@ def _eval_(self, n, m, theta, phi, **kwargs): Check that :trac:`20939` is fixed:: - sage: ex = spherical_harmonic(3, 2, 1, 2*pi/3) - sage: QQbar(ex * sqrt(pi)/cos(1)/sin(1)^2).minpoly() + sage: ex = spherical_harmonic(3, 2, 1, 2*pi/3) # needs sage.symbolic + sage: QQbar(ex * sqrt(pi)/cos(1)/sin(1)^2).minpoly() # needs sage.rings.number_field sage.symbolic x^4 + 105/32*x^2 + 11025/1024 Check whether Sage yields correct results compared to Maxima, up to the Condon-Shortley phase factor `(-1)^m` (see :trac:`25034` and :trac:`33117`):: - sage: spherical_harmonic(1, 1, pi/3, pi/6).n() # abs tol 1e-14 + sage: # needs sage.symbolic + sage: spherical_harmonic(1, 1, pi/3, pi/6).n() # abs tol 1e-14 -0.259120612103502 - 0.149603355150537*I - sage: maxima.spherical_harmonic(1, 1, pi/3, pi/6).n() # abs tol 1e-14 + sage: maxima.spherical_harmonic(1, 1, pi/3, pi/6).n() # abs tol 1e-14 0.259120612103502 + 0.149603355150537*I - sage: spherical_harmonic(1, -1, pi/3, pi/6).n() # abs tol 1e-14 + sage: spherical_harmonic(1, -1, pi/3, pi/6).n() # abs tol 1e-14 0.259120612103502 - 0.149603355150537*I - sage: maxima.spherical_harmonic(1, -1, pi/3, pi/6).n() # abs tol 1e-14 + sage: maxima.spherical_harmonic(1, -1, pi/3, pi/6).n() # abs tol 1e-14 -0.259120612103502 + 0.149603355150537*I Check that :trac:`33501` is fixed:: - sage: spherical_harmonic(2, 1, x, y) + sage: spherical_harmonic(2, 1, x, y) # needs sage.symbolic -1/4*sqrt(6)*sqrt(5)*cos(x)*e^(I*y)*sin(x)/sqrt(pi) - sage: spherical_harmonic(5, -3, x, y) + sage: spherical_harmonic(5, -3, x, y) # needs sage.symbolic -1/32*(9*sqrt(385)*sin(x)^4 - 8*sqrt(385)*sin(x)^2)*e^(-3*I*y)*sin(x)/sqrt(pi) """ @@ -289,8 +306,8 @@ def _eval_(self, n, m, theta, phi, **kwargs): from sage.functions.trig import cos from sage.functions.orthogonal_polys import gen_legendre_P res = (sqrt(factorial(n-m) * (2*n+1) / (4*pi * factorial(n+m))) - * gen_legendre_P(n, m, cos(theta)) - * exp(I*m*phi)).simplify_trig() + * gen_legendre_P(n, m, cos(theta)) + * exp(I*m*phi)).simplify_trig() res = res.substitute({sqrt(sin(theta)**2): sin(theta)}) return res @@ -298,9 +315,9 @@ def _evalf_(self, n, m, theta, phi, parent, **kwds): r""" TESTS:: - sage: spherical_harmonic(3 + I, 2, 1, 2).n(100) + sage: spherical_harmonic(3 + I, 2, 1, 2).n(100) # needs sage.symbolic -0.35115433730748836508201061672 - 0.41556223397536866209990358597*I - sage: spherical_harmonic(I, I, I, I).n() + sage: spherical_harmonic(I, I, I, I).n() # needs sage.symbolic 7.66678546069894 - 0.265754432549751*I Consistency with ``_eval_``:: @@ -308,21 +325,20 @@ def _evalf_(self, n, m, theta, phi, parent, **kwds): sage: d = lambda a, b: abs(spherical_harmonic(a, b, 1., 2.) ....: - spherical_harmonic(a, b, 1, 2).n()) sage: ab = [(0, 0), (1, -1), (1, 0), (1, 1), (3, 2), (3, 3)] - sage: all(d(a, b) < 1e-14 for a, b in ab) + sage: all(d(a, b) < 1e-14 for a, b in ab) # needs sage.symbolic True """ - from mpmath import spherharm - return mpmath_utils.call(spherharm, n, m, theta, phi, parent=parent) + return _mpmath_utils_call(_mpmath_spherharm, n, m, theta, phi, parent=parent) def _derivative_(self, n, m, theta, phi, diff_param): r""" TESTS:: + sage: # needs sage.symbolic sage: n, m, theta, phi = var('n m theta phi') sage: Ynm = spherical_harmonic(n, m, theta, phi) - sage: DY_theta = Ynm.diff(theta) - sage: DY_theta + sage: DY_theta = Ynm.diff(theta); DY_theta m*cot(theta)*spherical_harmonic(n, m, theta, phi) + sqrt(-(m + n + 1)*(m - n))*e^(-I*phi)*spherical_harmonic(n, m + 1, theta, phi) sage: Ynm.diff(phi) @@ -330,6 +346,7 @@ def _derivative_(self, n, m, theta, phi, diff_param): Check that :trac:`33117` is fixed:: + sage: # needs sage.symbolic sage: DY_theta.subs({n: 1, m: 0}) -1/2*sqrt(3)*sin(theta)/sqrt(pi) sage: Ynm.subs({n: 1, m: 0}).diff(theta) @@ -365,16 +382,18 @@ def _print_latex_(self, n, m, theta, phi): r""" TESTS:: - sage: y = var('y') - sage: latex(spherical_harmonic(3, 2, x, y, hold=True)) + sage: y = var('y') # needs sage.symbolic + sage: latex(spherical_harmonic(3, 2, x, y, hold=True)) # needs sage.symbolic Y_{3}^{2}\left(x, y\right) """ return r"Y_{{{}}}^{{{}}}\left({}, {}\right)".format( - latex(n), latex(m), latex(theta), latex(phi)) + latex(n), latex(m), latex(theta), latex(phi)) + spherical_harmonic = SphericalHarmonic() -####### elliptic functions and integrals + +# elliptic functions and integrals def elliptic_j(z, prec=53): r""" @@ -400,30 +419,31 @@ def elliptic_j(z, prec=53): EXAMPLES:: - sage: elliptic_j(CC(i)) + sage: elliptic_j(CC(i)) # needs sage.rings.real_mpfr 1728.00000000000 - sage: elliptic_j(sqrt(-2.0)) + sage: elliptic_j(sqrt(-2.0)) # needs sage.rings.complex_double 8000.00000000000 - sage: z = ComplexField(100)(1,sqrt(11))/2 - sage: elliptic_j(z) + sage: z = ComplexField(100)(1, sqrt(11))/2 # needs sage.rings.real_mpfr sage.symbolic + sage: elliptic_j(z) # needs sage.rings.real_mpfr sage.symbolic -32768.000... - sage: elliptic_j(z).real().round() + sage: elliptic_j(z).real().round() # needs sage.rings.real_mpfr sage.symbolic -32768 :: - sage: tau = (1 + sqrt(-163))/2 - sage: (-elliptic_j(tau.n(100)).real().round())^(1/3) + sage: tau = (1 + sqrt(-163))/2 # needs sage.symbolic + sage: (-elliptic_j(tau.n(100)).real().round())^(1/3) # needs sage.symbolic 640320 This example shows the need for higher precision than the default one of the `ComplexField`, see :trac:`28355`:: - sage: -elliptic_j(tau) # rel tol 1e-2 + sage: # needs sage.symbolic + sage: -elliptic_j(tau) # rel tol 1e-2 2.62537412640767e17 - 732.558854258998*I - sage: -elliptic_j(tau,75) # rel tol 1e-2 + sage: -elliptic_j(tau, 75) # rel tol 1e-2 2.625374126407680000000e17 - 0.0001309913593909879441262*I - sage: -elliptic_j(tau,100) # rel tol 1e-2 + sage: -elliptic_j(tau, 100) # rel tol 1e-2 2.6253741264076799999999999999e17 - 1.3012822400356887122945119790e-12*I sage: (-elliptic_j(tau, 100).real().round())^(1/3) 640320 @@ -439,7 +459,8 @@ def elliptic_j(z, prec=53): from sage.libs.pari.all import pari return CC(pari(z).ellj()) -#### elliptic integrals + +# elliptic integrals class EllipticE(BuiltinFunction): r""" @@ -452,17 +473,16 @@ class EllipticE(BuiltinFunction): EXAMPLES:: - sage: z = var("z") - sage: elliptic_e(z, 1) + sage: z = var("z") # needs sage.symbolic + sage: elliptic_e(z, 1) # needs sage.symbolic elliptic_e(z, 1) - sage: # this is still wrong: must be abs(sin(z)) + 2*round(z/pi) - sage: elliptic_e(z, 1).simplify() - 2*round(z/pi) + sin(z) - sage: elliptic_e(z, 0) + sage: elliptic_e(z, 1).simplify() # not tested # needs sage.symbolic + 2*round(z/pi) - sin(pi*round(z/pi) - z) + sage: elliptic_e(z, 0) # needs sage.symbolic z - sage: elliptic_e(0.5, 0.1) # abs tol 2e-15 + sage: elliptic_e(0.5, 0.1) # abs tol 2e-15 # needs mpmath 0.498011394498832 - sage: elliptic_e(1/2, 1/10).n(200) + sage: elliptic_e(1/2, 1/10).n(200) # needs sage.symbolic 0.4980113944988315331154610406... .. SEEALSO:: @@ -485,27 +505,28 @@ def __init__(self): sage: loads(dumps(elliptic_e)) elliptic_e - sage: elliptic_e(x, x)._sympy_() + sage: elliptic_e(x, x)._sympy_() # needs sympy sage.symbolic elliptic_e(x, x) Check that :trac:`34085` is fixed:: - sage: _ = var("x y") - sage: fricas(elliptic_e(x, y)) # optional - fricas + sage: _ = var("x y") # needs sage.symbolic + sage: fricas(elliptic_e(x, y)) # optional - fricas, needs sage.symbolic ellipticE(sin(x),y) However, the conversion is only correct in the interval `[-\pi/2, \pi/2]`:: - sage: fricas(elliptic_e(x, y)).D(x).sage()/elliptic_e(x, y).diff(x) # optional - fricas + sage: fricas(elliptic_e(x, y)).D(x).sage()/elliptic_e(x, y).diff(x) # optional - fricas, needs sage.symbolic cos(x)/sqrt(-sin(x)^2 + 1) Numerically:: - sage: f = lambda x, y: elliptic_e(arcsin(x), y).subs(x=x, y=y) # optional - fricas - sage: g = lambda x, y: fricas.ellipticE(x, y).sage() # optional - fricas - sage: d = lambda x, y: f(x, y) - g(x, y) # optional - fricas - sage: [d(N(-pi/2+x), y) for x in range(1, 3) for y in range(-2,2)] # optional - fricas tol 1e-8 + sage: f = lambda x, y: elliptic_e(arcsin(x), y).subs(x=x, y=y) + sage: g = lambda x, y: fricas.ellipticE(x, y).sage() + sage: d = lambda x, y: f(x, y) - g(x, y) + sage: [d(N(-pi/2 + x), y) # tol 1e-8 # optional - fricas, needs sage.symbolic + ....: for x in range(1, 3) for y in range(-2, 2)] [0.000000000000000, 0.000000000000000, 0.000000000000000, @@ -528,6 +549,7 @@ def _eval_(self, z, m): """ EXAMPLES:: + sage: # needs sage.symbolic sage: z = var("z") sage: elliptic_e(0, x) 0 @@ -538,9 +560,9 @@ def _eval_(self, z, m): sage: elliptic_e(z, 1) elliptic_e(z, 1) - Here arccoth doesn't have 1 in its domain, so we just hold the expression: + Here arccoth doesn't have 1 in its domain, so we just hold the expression:: - sage: elliptic_e(arccoth(1), x^2*e) + sage: elliptic_e(arccoth(1), x^2*e) # needs sage.symbolic elliptic_e(+Infinity, x^2*e) """ if z == 0: @@ -554,32 +576,31 @@ def _evalf_(self, z, m, parent=None, algorithm=None): """ EXAMPLES:: - sage: elliptic_e(0.5, 0.1) + sage: elliptic_e(0.5, 0.1) # needs mpmath 0.498011394498832 - sage: elliptic_e(1/2, 1/10).n(200) + sage: elliptic_e(1/2, 1/10).n(200) # needs sage.symbolic 0.4980113944988315331154610406... - sage: elliptic_e(I, I).n() + sage: elliptic_e(I, I).n() # needs sage.symbolic -0.189847437084712 + 1.03209769372160*I TESTS: This gave an error in Maxima (:trac:`15046`):: - sage: elliptic_e(2.5, 2.5) + sage: elliptic_e(2.5, 2.5) # needs mpmath 0.535647771608740 + 1.63996015168665*I """ - R = parent or parent(z) - from mpmath import ellipe - return mpmath_utils.call(ellipe, z, m, parent=R) + R = parent or s_parent(z) + return _mpmath_utils_call(_mpmath_ellipe, z, m, parent=R) def _derivative_(self, z, m, diff_param): """ EXAMPLES:: - sage: x,z = var('x,z') - sage: elliptic_e(z, x).diff(z, 1) + sage: x, z = var('x,z') # needs sage.symbolic + sage: elliptic_e(z, x).diff(z, 1) # needs sage.symbolic sqrt(-x*sin(z)^2 + 1) - sage: elliptic_e(z, x).diff(x, 1) + sage: elliptic_e(z, x).diff(x, 1) # needs sage.symbolic 1/2*(elliptic_e(z, x) - elliptic_f(z, x))/x """ if diff_param == 0: @@ -591,11 +612,12 @@ def _print_latex_(self, z, m): r""" EXAMPLES:: - sage: latex(elliptic_e(pi, x)) + sage: latex(elliptic_e(pi, x)) # needs sage.symbolic E(\pi\,|\,x) """ return r"E(%s\,|\,%s)" % (latex(z), latex(m)) + elliptic_e = EllipticE() @@ -609,9 +631,9 @@ class EllipticEC(BuiltinFunction): EXAMPLES:: - sage: elliptic_ec(0.1) + sage: elliptic_ec(0.1) # needs mpmath 1.53075763689776 - sage: elliptic_ec(x).diff() + sage: elliptic_ec(x).diff() # needs sage.symbolic 1/2*(elliptic_ec(x) - elliptic_kc(x))/x .. SEEALSO:: @@ -628,17 +650,17 @@ def __init__(self): sage: loads(dumps(elliptic_ec)) elliptic_ec - sage: elliptic_ec(x)._sympy_() + sage: elliptic_ec(x)._sympy_() # needs sage.symbolic elliptic_e(x) TESTS:: - sage: fricas(elliptic_ec(x)) # optional - fricas + sage: fricas(elliptic_ec(x)) # optional - fricas, needs sage.symbolic ellipticE(x) - sage: elliptic_ec(0.5) # abs tol 1e-8 + sage: elliptic_ec(0.5) # abs tol 1e-8 # needs sage.symbolic 1.35064388104768 - sage: fricas.ellipticE(0.5).sage() # abs tol 1e-8 # optional - fricas + sage: fricas.ellipticE(0.5).sage() # abs tol 1e-8 # optional - fricas, needs sage.symbolic 1.3506438810476755025201749 """ BuiltinFunction.__init__(self, 'elliptic_ec', nargs=1, latex_name='E', @@ -651,11 +673,11 @@ def _eval_(self, x): """ EXAMPLES:: - sage: elliptic_ec(0) + sage: elliptic_ec(0) # needs sage.symbolic 1/2*pi - sage: elliptic_ec(1) + sage: elliptic_ec(1) # needs sage.symbolic 1 - sage: elliptic_ec(x) + sage: elliptic_ec(x) # needs sage.symbolic elliptic_ec(x) """ if x == 0: @@ -667,28 +689,29 @@ def _evalf_(self, x, parent=None, algorithm=None): """ EXAMPLES:: - sage: elliptic_ec(sqrt(2)/2).n() + sage: elliptic_ec(sqrt(2)/2).n() # needs sage.symbolic 1.23742252487318 - sage: elliptic_ec(sqrt(2)/2).n(200) + sage: elliptic_ec(sqrt(2)/2).n(200) # needs sage.symbolic 1.237422524873181672854746084083... - sage: elliptic_ec(I).n() + sage: elliptic_ec(I).n() # needs sage.symbolic 1.63241178144043 - 0.369219492375499*I """ - R = parent or parent(x) - from mpmath import ellipe - return mpmath_utils.call(ellipe, x, parent=R) + R = parent or s_parent(x) + return _mpmath_utils_call(_mpmath_ellipe, x, parent=R) def _derivative_(self, x, diff_param): """ EXAMPLES:: - sage: elliptic_ec(x).diff() + sage: elliptic_ec(x).diff() # needs sage.symbolic 1/2*(elliptic_ec(x) - elliptic_kc(x))/x """ return (elliptic_ec(x) - elliptic_kc(x)) / (Integer(2) * x) + elliptic_ec = EllipticEC() + class EllipticEU(BuiltinFunction): r""" Return Jacobi's form of the incomplete elliptic integral of the second kind: @@ -705,7 +728,7 @@ class EllipticEU(BuiltinFunction): EXAMPLES:: - sage: elliptic_eu (0.5, 0.1) + sage: elliptic_eu(0.5, 0.1) # needs mpmath 0.496054551286597 .. SEEALSO:: @@ -732,7 +755,7 @@ def _eval_(self, u, m): """ EXAMPLES:: - sage: elliptic_eu(1,1) + sage: elliptic_eu(1, 1) # needs sage.symbolic elliptic_eu(1, 1) """ pass @@ -741,22 +764,22 @@ def _evalf_(self, u, m, parent=None, algorithm=None): """ EXAMPLES:: - sage: elliptic_eu(1,1).n() + sage: elliptic_eu(1, 1).n() # needs sage.symbolic 0.761594155955765 - sage: elliptic_eu(1,1).n(200) + sage: elliptic_eu(1, 1).n(200) # needs sage.symbolic 0.7615941559557648881194582... """ - R = parent or parent(u) - return mpmath_utils.call(elliptic_eu_f, u, m, parent=R) + R = parent or s_parent(u) + return _mpmath_utils_call(elliptic_eu_f, u, m, parent=R) def _derivative_(self, u, m, diff_param): """ EXAMPLES:: - sage: x,m = var('x,m') - sage: elliptic_eu(x,m).diff(x) + sage: x, m = var('x,m') # needs sage.symbolic + sage: elliptic_eu(x, m).diff(x) # needs sage.symbolic sqrt(-m*jacobi_sn(x, m)^2 + 1)*jacobi_dn(x, m) - sage: elliptic_eu(x,m).diff(m) + sage: elliptic_eu(x, m).diff(m) # needs sage.symbolic 1/2*(elliptic_eu(x, m) - elliptic_f(jacobi_am(x, m), m))/m - 1/2*(m*jacobi_cn(x, m)*jacobi_sn(x, m) @@ -780,11 +803,12 @@ def _print_latex_(self, u, m): """ EXAMPLES:: - sage: latex(elliptic_eu(1,x)) + sage: latex(elliptic_eu(1, x)) # needs sage.symbolic E(1;x) """ return r"E(%s;%s)" % (latex(u), latex(m)) + def elliptic_eu_f(u, m): r""" Internal function for numeric evaluation of ``elliptic_eu``, defined as @@ -795,13 +819,10 @@ def elliptic_eu_f(u, m): EXAMPLES:: sage: from sage.functions.special import elliptic_eu_f - sage: elliptic_eu_f(0.5, 0.1) + sage: elliptic_eu_f(0.5, 0.1) # needs mpmath mpf('0.49605455128659691') """ - from mpmath import mp - from sage.functions.jacobi import jacobi_am_f - - ctx = mp + from mpmath import mp as ctx prec = ctx.prec try: u = ctx.convert(u) @@ -811,8 +832,10 @@ def elliptic_eu_f(u, m): finally: ctx.prec = prec + elliptic_eu = EllipticEU() + class EllipticF(BuiltinFunction): r""" Return the incomplete elliptic integral of the first kind. @@ -826,12 +849,12 @@ class EllipticF(BuiltinFunction): EXAMPLES:: - sage: z = var("z") - sage: elliptic_f (z, 0) + sage: z = var("z") # needs sage.symbolic + sage: elliptic_f(z, 0) # needs sage.symbolic z - sage: elliptic_f (z, 1).simplify() + sage: elliptic_f(z, 1).simplify() # needs sage.symbolic log(tan(1/4*pi + 1/2*z)) - sage: elliptic_f (0.2, 0.1) + sage: elliptic_f(0.2, 0.1) # needs mpmath 0.200132506747543 .. SEEALSO:: @@ -848,27 +871,28 @@ def __init__(self): sage: loads(dumps(elliptic_f)) elliptic_f - sage: elliptic_f(x, 2)._sympy_() + sage: elliptic_f(x, 2)._sympy_() # needs sympy sage.symbolic elliptic_f(x, 2) Check that :trac:`34186` is fixed:: - sage: _ = var("x y") - sage: fricas(elliptic_f(x, y)) # optional - fricas + sage: _ = var("x y") # needs sage.symbolic + sage: fricas(elliptic_f(x, y)) # optional - fricas, needs sage.symbolic ellipticF(sin(x),y) However, the conversion is only correct in the interval `[-\pi/2, \pi/2]`:: - sage: fricas(elliptic_f(x, y)).D(x).sage()/elliptic_f(x, y).diff(x) # optional - fricas + sage: fricas(elliptic_f(x, y)).D(x).sage()/elliptic_f(x, y).diff(x) # optional - fricas, needs sage.symbolic cos(x)/sqrt(-sin(x)^2 + 1) Numerically:: - sage: f = lambda x, y: elliptic_f(arcsin(x), y).subs(x=x, y=y) # optional - fricas - sage: g = lambda x, y: fricas.ellipticF(x, y).sage() # optional - fricas - sage: d = lambda x, y: f(x, y) - g(x, y) # optional - fricas - sage: [d(N(-pi/2+x), y) for x in range(1, 3) for y in range(-2,2)] # optional - fricas tol 1e-8 + sage: f = lambda x, y: elliptic_f(arcsin(x), y).subs(x=x, y=y) + sage: g = lambda x, y: fricas.ellipticF(x, y).sage() + sage: d = lambda x, y: f(x, y) - g(x, y) + sage: [d(N(-pi/2 + x), y) # tol 1e-8 # optional - fricas, needs sage.symbolic + ....: for x in range(1, 3) for y in range(-2,2)] [0.000000000000000, 0.000000000000000, 0.000000000000000, @@ -889,13 +913,14 @@ def _eval_(self, z, m): """ EXAMPLES:: - sage: elliptic_f(x,1) + sage: # needs sage.symbolic + sage: elliptic_f(x, 1) elliptic_f(x, 1) - sage: elliptic_f(x,0) + sage: elliptic_f(x, 0) x - sage: elliptic_f(0,1) + sage: elliptic_f(0, 1) 0 - sage: elliptic_f(pi/2,x) + sage: elliptic_f(pi/2, x) elliptic_kc(x) """ if m == 0: @@ -909,25 +934,24 @@ def _evalf_(self, z, m, parent=None, algorithm=None): """ EXAMPLES:: - sage: elliptic_f(1,1).n() + sage: elliptic_f(1, 1).n() # needs sage.symbolic 1.22619117088352 - sage: elliptic_f(1,1).n(200) + sage: elliptic_f(1, 1).n(200) # needs sage.symbolic 1.22619117088351707081306096... - sage: elliptic_f(I,I).n() + sage: elliptic_f(I, I).n() # needs sage.symbolic 0.149965060031782 + 0.925097284105771*I """ - R = parent or parent(z) - from mpmath import ellipf - return mpmath_utils.call(ellipf, z, m, parent=R) + R = parent or s_parent(z) + return _mpmath_utils_call(_mpmath_ellipf, z, m, parent=R) def _derivative_(self, z, m, diff_param): """ EXAMPLES:: - sage: x,m = var('x,m') - sage: elliptic_f(x,m).diff(x) + sage: x, m = var('x,m') # needs sage.symbolic + sage: elliptic_f(x, m).diff(x) # needs sage.symbolic 1/sqrt(-m*sin(x)^2 + 1) - sage: elliptic_f(x,m).diff(m) + sage: elliptic_f(x, m).diff(m) # needs sage.symbolic -1/2*elliptic_f(x, m)/m + 1/4*sin(2*x)/(sqrt(-m*sin(x)^2 + 1)*(m - 1)) - 1/2*elliptic_e(x, m)/((m - 1)*m) @@ -945,11 +969,12 @@ def _print_latex_(self, z, m): r""" EXAMPLES:: - sage: latex(elliptic_f(x,pi)) + sage: latex(elliptic_f(x, pi)) # needs sage.symbolic F(x\,|\,\pi) """ return r"F(%s\,|\,%s)" % (latex(z), latex(m)) + elliptic_f = EllipticF() @@ -963,7 +988,7 @@ class EllipticKC(BuiltinFunction): EXAMPLES:: - sage: elliptic_kc(0.5) + sage: elliptic_kc(0.5) # needs mpmath 1.85407467730137 .. SEEALSO:: @@ -984,17 +1009,17 @@ def __init__(self): sage: loads(dumps(elliptic_kc)) elliptic_kc - sage: elliptic_kc(x)._sympy_() + sage: elliptic_kc(x)._sympy_() # needs sage.symbolic elliptic_k(x) TESTS:: - sage: fricas(elliptic_kc(x)) # optional - fricas + sage: fricas(elliptic_kc(x)) # optional - fricas, needs sage.symbolic ellipticK(x) - sage: elliptic_kc(0.3) # abs tol 1e-8 + sage: elliptic_kc(0.3) # abs tol 1e-8 # needs mpmath 1.71388944817879 - sage: fricas.ellipticK(0.3).sage() # abs tol 1e-3 # optional - fricas + sage: fricas.ellipticK(0.3).sage() # abs tol 1e-3 # optional - fricas, needs sage.symbolic 1.7138894481787910555457043 """ BuiltinFunction.__init__(self, 'elliptic_kc', nargs=1, latex_name='K', @@ -1007,9 +1032,9 @@ def _eval_(self, z): """ EXAMPLES:: - sage: elliptic_kc(0) + sage: elliptic_kc(0) # needs sage.symbolic 1/2*pi - sage: elliptic_kc(1/2) + sage: elliptic_kc(1/2) # needs sage.symbolic elliptic_kc(1/2) TESTS: @@ -1017,10 +1042,10 @@ def _eval_(self, z): Check if complex numbers in the arguments are converted to maxima correctly (see :trac:`7557`):: - sage: t = jacobi_sn(1.2+2*I*elliptic_kc(1-.5),.5) - sage: maxima(t) # abs tol 1e-13 + sage: t = jacobi_sn(1.2 + 2*I*elliptic_kc(1 - .5), .5) # needs sage.symbolic + sage: maxima(t) # abs tol 1e-13 # needs sage.symbolic 0.88771548861928029 - 1.7301614091485560e-15*%i - sage: t.n() # abs tol 1e-13 + sage: t.n() # abs tol 1e-13 # needs sage.symbolic 0.887715488619280 - 1.73016140914856e-15*I """ if z == 0: @@ -1032,30 +1057,31 @@ def _evalf_(self, z, parent=None, algorithm=None): """ EXAMPLES:: - sage: elliptic_kc(1/2).n() + sage: elliptic_kc(1/2).n() # needs sage.symbolic 1.85407467730137 - sage: elliptic_kc(1/2).n(200) + sage: elliptic_kc(1/2).n(200) # needs sage.symbolic 1.85407467730137191843385034... - sage: elliptic_kc(I).n() + sage: elliptic_kc(I).n() # needs sage.symbolic 1.42127228104504 + 0.295380284214777*I """ - R = parent or parent(z) - from mpmath import ellipk - return mpmath_utils.call(ellipk, z, parent=R) + R = parent or s_parent(z) + return _mpmath_utils_call(_mpmath_ellipk, z, parent=R) def _derivative_(self, z, diff_param): """ EXAMPLES:: - sage: elliptic_kc(x).diff(x) + sage: elliptic_kc(x).diff(x) # needs sage.symbolic -1/2*((x - 1)*elliptic_kc(x) + elliptic_ec(x))/((x - 1)*x) """ return ((elliptic_ec(z) - (Integer(1) - z) * elliptic_kc(z)) / (Integer(2) * (Integer(1) - z) * z)) + elliptic_kc = EllipticKC() + class EllipticPi(BuiltinFunction): r""" Return the incomplete elliptic integral of the third kind: @@ -1074,15 +1100,15 @@ class EllipticPi(BuiltinFunction): EXAMPLES:: - sage: N(elliptic_pi(1, pi/4, 1)) + sage: N(elliptic_pi(1, pi/4, 1)) # needs sage.symbolic 1.14779357469632 Compare the value computed by Maxima to the definition as a definite integral (using GSL):: - sage: elliptic_pi(0.1, 0.2, 0.3) + sage: elliptic_pi(0.1, 0.2, 0.3) # needs mpmath 0.200665068220979 - sage: numerical_integral(1/(1-0.1*sin(x)^2)/sqrt(1-0.3*sin(x)^2), 0.0, 0.2) + sage: numerical_integral(1/(1-0.1*sin(x)^2)/sqrt(1-0.3*sin(x)^2), 0.0, 0.2) # needs sage.symbolic (0.2006650682209791, 2.227829789769088e-15) REFERENCES: @@ -1095,7 +1121,7 @@ def __init__(self): sage: loads(dumps(elliptic_pi)) elliptic_pi - sage: elliptic_pi(x, pi/4, 1)._sympy_() + sage: elliptic_pi(x, pi/4, 1)._sympy_() # needs sympy sage.symbolic elliptic_pi(x, pi/4, 1) """ BuiltinFunction.__init__(self, 'elliptic_pi', nargs=3, @@ -1108,9 +1134,9 @@ def _eval_(self, n, z, m): """ EXAMPLES:: - sage: elliptic_pi(x,x,pi) + sage: elliptic_pi(x, x, pi) # needs sympy sage.symbolic elliptic_pi(x, x, pi) - sage: elliptic_pi(0,x,pi) + sage: elliptic_pi(0, x, pi) # needs sympy sage.symbolic elliptic_f(x, pi) """ if n == 0: @@ -1120,32 +1146,33 @@ def _evalf_(self, n, z, m, parent=None, algorithm=None): """ EXAMPLES:: - sage: elliptic_pi(pi,1/2,1).n() + sage: # needs sage.symbolic + sage: elliptic_pi(pi, 1/2, 1).n() 0.795062820631931 - sage: elliptic_pi(pi,1/2,1).n(200) + sage: elliptic_pi(pi, 1/2, 1).n(200) 0.79506282063193125292514098445... - sage: elliptic_pi(pi,1,1).n() + sage: elliptic_pi(pi, 1, 1).n() 0.0991592574231369 - 1.30004368185937*I - sage: elliptic_pi(pi,I,I).n() + sage: elliptic_pi(pi, I, I).n() 0.0542471560940594 + 0.552096453413081*I """ - R = parent or parent(z) - from mpmath import ellippi - return mpmath_utils.call(ellippi, n, z, m, parent=R) + R = parent or s_parent(z) + return _mpmath_utils_call(_mpmath_ellippi, n, z, m, parent=R) def _derivative_(self, n, z, m, diff_param): """ EXAMPLES:: - sage: n,z,m = var('n,z,m') - sage: elliptic_pi(n,z,m).diff(n) + sage: # needs sage.symbolic + sage: n, z, m = var('n,z,m') + sage: elliptic_pi(n, z, m).diff(n) 1/4*(sqrt(-m*sin(z)^2 + 1)*n*sin(2*z)/(n*sin(z)^2 - 1) + 2*(m - n)*elliptic_f(z, m)/n + 2*(n^2 - m)*elliptic_pi(n, z, m)/n + 2*elliptic_e(z, m))/((m - n)*(n - 1)) - sage: elliptic_pi(n,z,m).diff(z) + sage: elliptic_pi(n, z, m).diff(z) -1/(sqrt(-m*sin(z)^2 + 1)*(n*sin(z)^2 - 1)) - sage: elliptic_pi(n,z,m).diff(m) + sage: elliptic_pi(n, z, m).diff(m) 1/4*(m*sin(2*z)/(sqrt(-m*sin(z)^2 + 1)*(m - 1)) - 2*elliptic_e(z, m)/(m - 1) - 2*elliptic_pi(n, z, m))/(m - n) @@ -1172,9 +1199,10 @@ def _print_latex_(self, n, z, m): r""" EXAMPLES:: - sage: latex(elliptic_pi(x,pi,0)) + sage: latex(elliptic_pi(x, pi, 0)) # needs sage.symbolic \Pi(x,\pi,0) """ return r"\Pi(%s,%s,%s)" % (latex(n), latex(z), latex(m)) + elliptic_pi = EllipticPi() diff --git a/src/sage/functions/spike_function.py b/src/sage/functions/spike_function.py index 83fde81b0ca..4739ca7ffb4 100644 --- a/src/sage/functions/spike_function.py +++ b/src/sage/functions/spike_function.py @@ -20,10 +20,11 @@ import math from sage.misc.lazy_import import lazy_import -lazy_import("sage.plot.all", "line") -from sage.modules.free_module_element import vector from sage.rings.real_double import RDF +lazy_import('sage.modules.free_module_element', 'vector') +lazy_import('sage.plot.all', 'line') + class SpikeFunction: """ @@ -31,9 +32,9 @@ class SpikeFunction: INPUT: - - ``v`` - list of pairs (x, height) + - ``v`` -- list of pairs (x, height) - - ``eps`` - parameter that determines approximation to a true spike + - ``eps`` -- parameter that determines approximation to a true spike OUTPUT: @@ -41,12 +42,12 @@ class SpikeFunction: EXAMPLES:: - sage: spike_function([(-3,4),(-1,1),(2,3)],0.001) + sage: spike_function([(-3,4), (-1,1), (2,3)], 0.001) A spike function with spikes at [-3.0, -1.0, 2.0] Putting the spikes too close together may delete some:: - sage: spike_function([(1,1),(1.01,4)],0.1) + sage: spike_function([(1,1), (1.01,4)], 0.1) Some overlapping spikes have been deleted. You might want to use a smaller value for eps. A spike function with spikes at [1.0] @@ -55,10 +56,9 @@ class SpikeFunction: ``spike_function``, but one can use it directly:: sage: from sage.functions.spike_function import SpikeFunction - sage: S = SpikeFunction([(0,1),(1,2),(pi,-5)]) - sage: S + sage: S = SpikeFunction([(0,1), (1,2), (pi,-5)]); S # needs sage.symbolic A spike function with spikes at [0.0, 1.0, 3.141592653589793] - sage: S.support + sage: S.support # needs sage.symbolic [0.0, 1.0, 3.141592653589793] """ def __init__(self, v, eps=0.0000001): @@ -67,7 +67,7 @@ def __init__(self, v, eps=0.0000001): EXAMPLES:: - sage: S = spike_function([(-3,4),(-1,1),(2,3)],0.001); S + sage: S = spike_function([(-3,4), (-1,1), (2,3)], 0.001); S A spike function with spikes at [-3.0, -1.0, 2.0] sage: S.height [4.0, 1.0, 3.0] @@ -99,7 +99,7 @@ def __repr__(self): EXAMPLES:: - sage: spike_function([(-3,4),(-1,1),(2,3)],0.001) + sage: spike_function([(-3,4), (-1,1), (2,3)], 0.001) A spike function with spikes at [-3.0, -1.0, 2.0] """ return "A spike function with spikes at %s" % self.support @@ -113,7 +113,7 @@ def _eval(self, x): EXAMPLES:: - sage: S = spike_function([(0,5)],eps=.001) + sage: S = spike_function([(0,5)], eps=.001) sage: S(0) 5.0 sage: S(.1) @@ -156,10 +156,10 @@ def plot_fft_abs(self, samples=2**12, xmin=None, xmax=None, **kwds): EXAMPLES:: - sage: S = spike_function([(-3,4),(-1,1),(2,3)]); S + sage: S = spike_function([(-3,4), (-1,1), (2,3)]); S A spike function with spikes at [-3.0, -1.0, 2.0] - sage: P = S.plot_fft_abs(8) - sage: p = P[0]; p.ydata # abs tol 1e-8 + sage: P = S.plot_fft_abs(8) # needs sage.plot + sage: p = P[0]; p.ydata # abs tol 1e-8 # needs sage.plot [5.0, 5.0, 3.367958691924177, 3.367958691924177, 4.123105625617661, 4.123105625617661, 4.759921664218055, 4.759921664218055] """ @@ -175,10 +175,10 @@ def plot_fft_arg(self, samples=2**12, xmin=None, xmax=None, **kwds): EXAMPLES:: - sage: S = spike_function([(-3,4),(-1,1),(2,3)]); S + sage: S = spike_function([(-3,4), (-1,1), (2,3)]); S A spike function with spikes at [-3.0, -1.0, 2.0] - sage: P = S.plot_fft_arg(8) - sage: p = P[0]; p.ydata # abs tol 1e-8 + sage: P = S.plot_fft_arg(8) # needs sage.plot + sage: p = P[0]; p.ydata # abs tol 1e-8 # needs sage.plot [0.0, 0.0, -0.211524990023434, -0.211524990023434, 0.244978663126864, 0.244978663126864, -0.149106180027477, -0.149106180027477] @@ -194,9 +194,9 @@ def vector(self, samples=2**16, xmin=None, xmax=None): EXAMPLES:: - sage: S = spike_function([(-3,4),(-1,1),(2,3)],0.001); S + sage: S = spike_function([(-3,4), (-1,1), (2,3)],0.001); S A spike function with spikes at [-3.0, -1.0, 2.0] - sage: S.vector(16) + sage: S.vector(16) # needs sage.modules (4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) """ @@ -220,8 +220,8 @@ def _ranges(self, xmin, xmax): EXAMPLES:: - sage: S = spike_function([(-1,1),(1,40)]) - sage: S._ranges(None,None) + sage: S = spike_function([(-1,1), (1,40)]) + sage: S._ranges(None, None) (-1.0, 1.0) """ width = (self.support[-1] + self.support[0])/float(2) @@ -239,9 +239,9 @@ def plot(self, xmin=None, xmax=None, **kwds): EXAMPLES:: - sage: S = spike_function([(-1,1),(1,40)]) - sage: P = plot(S) - sage: P[0] + sage: S = spike_function([(-1,1), (1,40)]) + sage: P = plot(S) # needs sage.plot + sage: P[0] # needs sage.plot Line defined by 8 points """ v = [] diff --git a/src/sage/functions/transcendental.py b/src/sage/functions/transcendental.py index b76e3a1bbbe..d0a30362fdf 100644 --- a/src/sage/functions/transcendental.py +++ b/src/sage/functions/transcendental.py @@ -15,24 +15,26 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +import math import sys +from sage.misc.lazy_import import lazy_import +from sage.misc.misc import increase_recursion_limit from sage.rings.integer_ring import ZZ -from sage.rings.real_mpfr import RR -from sage.rings.real_double import RDF -from sage.rings.complex_mpfr import ComplexField, is_ComplexNumber -from sage.rings.cc import CC -from sage.rings.real_mpfr import (RealField, is_RealNumber) - from sage.symbolic.function import GinacFunction, BuiltinFunction -import sage.libs.mpmath.utils as mpmath_utils -from sage.combinat.combinat import bernoulli_polynomial +lazy_import('sage.functions.gamma', 'psi') +lazy_import('sage.functions.other', 'factorial') -from .gamma import psi -from .other import factorial +lazy_import('sage.combinat.combinat', 'bernoulli_polynomial') +lazy_import('sage.rings.cc', 'CC') +lazy_import('sage.rings.complex_mpfr', ['ComplexField', 'is_ComplexNumber']) +lazy_import('sage.rings.polynomial.polynomial_real_mpfr_dense', 'PolynomialRealDense') +lazy_import('sage.rings.real_double', 'RDF') +lazy_import('sage.rings.real_mpfr', ['RR', 'RealField', 'is_RealNumber']) -I = CC.gen(0) +lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') +lazy_import('mpmath', 'zeta', as_='_mpmath_zeta') class Function_zeta(GinacFunction): @@ -44,21 +46,23 @@ def __init__(self): - ``s`` - real or complex number - If s is a real number the computation is done using the MPFR + If s is a real number, the computation is done using the MPFR library. When the input is not real, the computation is done using the PARI C library. EXAMPLES:: + sage: RR = RealField(200) # needs sage.rings.real_mpfr + sage: zeta(RR(2)) # needs sage.rings.real_mpfr + 1.6449340668482264364724151666460251892189499012067984377356 + + sage: # needs sage.symbolic sage: zeta(x) zeta(x) sage: zeta(2) 1/6*pi^2 sage: zeta(2.) 1.64493406684823 - sage: RR = RealField(200) - sage: zeta(RR(2)) - 1.6449340668482264364724151666460251892189499012067984377356 sage: zeta(I) zeta(I) sage: zeta(I).n() @@ -71,80 +75,81 @@ def __init__(self): It is possible to use the ``hold`` argument to prevent automatic evaluation:: - sage: zeta(2,hold=True) + sage: zeta(2, hold=True) # needs sage.symbolic zeta(2) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = zeta(2,hold=True); a.simplify() + sage: a = zeta(2, hold=True); a.simplify() # needs sage.symbolic 1/6*pi^2 The Laurent expansion of `\zeta(s)` at `s=1` is implemented by means of the :wikipedia:`Stieltjes constants <Stieltjes_constants>`:: - sage: s = SR('s') - sage: zeta(s).series(s==1, 2) + sage: s = SR('s') # needs sage.symbolic + sage: zeta(s).series(s==1, 2) # needs sage.symbolic 1*(s - 1)^(-1) + euler_gamma + (-stieltjes(1))*(s - 1) + Order((s - 1)^2) Generally, the Stieltjes constants occur in the Laurent expansion of `\zeta`-type singularities:: - sage: zeta(2*s/(s+1)).series(s==1, 2) + sage: zeta(2*s/(s+1)).series(s==1, 2) # needs sage.symbolic 2*(s - 1)^(-1) + (euler_gamma + 1) + (-1/2*stieltjes(1))*(s - 1) + Order((s - 1)^2) TESTS:: + sage: # needs sage.symbolic sage: latex(zeta(x)) \zeta(x) sage: a = loads(dumps(zeta(x))) sage: a.operator() == zeta True - sage: zeta(x)._sympy_() + sage: zeta(x)._sympy_() # needs sympy zeta(x) - sage: zeta(1) + sage: zeta(1) # needs sage.symbolic Infinity - sage: zeta(x).subs(x=1) + sage: zeta(x).subs(x=1) # needs sage.symbolic Infinity Check that :trac:`19799` is resolved:: - sage: zeta(pi) + sage: zeta(pi) # needs sage.symbolic zeta(pi) - sage: zeta(pi).n() # rel tol 1e-10 + sage: zeta(pi).n() # rel tol 1e-10 # needs sage.symbolic 1.17624173838258 Check that :trac:`20082` is fixed:: - sage: zeta(x).series(x==pi, 2) + sage: zeta(x).series(x==pi, 2) # needs sage.symbolic (zeta(pi)) + (zetaderiv(1, pi))*(-pi + x) + Order((pi - x)^2) - sage: (zeta(x) * 1/(1 - exp(-x))).residue(x==2*pi*I) + sage: (zeta(x) * 1/(1 - exp(-x))).residue(x==2*pi*I) # needs sage.symbolic zeta(2*I*pi) Check that :trac:`20102` is fixed:: - sage: (zeta(x)^2).series(x==1, 1) + sage: (zeta(x)^2).series(x==1, 1) # needs sage.symbolic 1*(x - 1)^(-2) + (2*euler_gamma)*(x - 1)^(-1) + (euler_gamma^2 - 2*stieltjes(1)) + Order(x - 1) - sage: (zeta(x)^4).residue(x==1) + sage: (zeta(x)^4).residue(x==1) # needs sage.symbolic 4/3*euler_gamma*(3*euler_gamma^2 - 2*stieltjes(1)) - 28/3*euler_gamma*stieltjes(1) + 2*stieltjes(2) Check that the right infinities are returned (:trac:`19439`):: - sage: zeta(1.0) + sage: zeta(1.0) # needs sage.symbolic +infinity - sage: zeta(SR(1.0)) + sage: zeta(SR(1.0)) # needs sage.symbolic Infinity Fixed conversion:: - sage: zeta(3)._maple_init_() + sage: zeta(3)._maple_init_() # needs sage.symbolic 'Zeta(3)' - sage: zeta(3)._maple_().sage() # optional - maple + sage: zeta(3)._maple_().sage() # optional - maple # needs sage.symbolic zeta(3) """ GinacFunction.__init__(self, 'zeta', @@ -172,6 +177,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: _ = var('n') sage: stieltjes(n) stieltjes(n) @@ -183,25 +189,26 @@ def __init__(self): stieltjes(2) sage: stieltjes(2).n(100) -0.0096903631928723184845303860352 - sage: RR = RealField(200) - sage: stieltjes(RR(2)) + sage: RR = RealField(200) # needs sage.rings.real_mpfr + sage: stieltjes(RR(2)) # needs sage.rings.real_mpfr -0.0096903631928723184845303860352125293590658061013407498807014 It is possible to use the ``hold`` argument to prevent automatic evaluation:: - sage: stieltjes(0,hold=True) + sage: stieltjes(0, hold=True) # needs sage.symbolic stieltjes(0) + sage: # needs sage.symbolic sage: latex(stieltjes(n)) \gamma_{n} sage: a = loads(dumps(stieltjes(n))) sage: a.operator() == stieltjes True - sage: stieltjes(x)._sympy_() + sage: stieltjes(x)._sympy_() # needs sympy stieltjes(x) - sage: stieltjes(x).subs(x==0) + sage: stieltjes(x).subs(x==0) # needs sage.symbolic euler_gamma """ GinacFunction.__init__(self, "stieltjes", nargs=1, @@ -209,6 +216,7 @@ def __init__(self): sympy='stieltjes'), latex_name=r'\gamma') + stieltjes = Function_stieltjes() @@ -217,9 +225,9 @@ def __init__(self): r""" TESTS:: - sage: latex(hurwitz_zeta(x, 2)) + sage: latex(hurwitz_zeta(x, 2)) # needs sage.symbolic \zeta\left(x, 2\right) - sage: hurwitz_zeta(x, 2)._sympy_() + sage: hurwitz_zeta(x, 2)._sympy_() # needs sympy sage.symbolic zeta(x, 2) """ BuiltinFunction.__init__(self, 'hurwitz_zeta', nargs=2, @@ -231,16 +239,18 @@ def _eval_(self, s, x): r""" TESTS:: + sage: # needs sage.symbolic sage: hurwitz_zeta(x, 1) zeta(x) sage: hurwitz_zeta(4, 3) 1/90*pi^4 - 17/16 sage: hurwitz_zeta(-4, x) -1/5*x^5 + 1/2*x^4 - 1/3*x^3 + 1/30*x - sage: hurwitz_zeta(3, 0.5) - 8.41439832211716 sage: hurwitz_zeta(0, x) -x + 1/2 + + sage: hurwitz_zeta(3, 0.5) # needs mpmath + 8.41439832211716 """ if x == 1: return zeta(s) @@ -255,22 +265,21 @@ def _evalf_(self, s, x, parent=None, algorithm=None): r""" TESTS:: - sage: hurwitz_zeta(11/10, 1/2).n() + sage: hurwitz_zeta(11/10, 1/2).n() # needs sage.symbolic 12.1038134956837 - sage: hurwitz_zeta(11/10, 1/2).n(100) + sage: hurwitz_zeta(11/10, 1/2).n(100) # needs sage.symbolic 12.103813495683755105709077413 sage: hurwitz_zeta(11/10, 1 + 1j).n() 9.85014164287853 - 1.06139499403981*I """ - from mpmath import zeta - return mpmath_utils.call(zeta, s, x, parent=parent) + return _mpmath_utils_call(_mpmath_zeta, s, x, parent=parent) def _derivative_(self, s, x, diff_param): r""" TESTS:: - sage: y = var('y') - sage: diff(hurwitz_zeta(x, y), y) + sage: y = var('y') # needs sage.symbolic + sage: diff(hurwitz_zeta(x, y), y) # needs sage.symbolic -x*hurwitz_zeta(x + 1, y) """ if diff_param == 1: @@ -279,6 +288,7 @@ def _derivative_(self, s, x, diff_param): raise NotImplementedError('derivative with respect to first ' 'argument') + hurwitz_zeta_func = Function_HurwitzZeta() @@ -302,6 +312,7 @@ def hurwitz_zeta(s, x, **kwargs): Symbolic evaluations:: + sage: # needs sage.symbolic sage: hurwitz_zeta(x, 1) zeta(x) sage: hurwitz_zeta(4, 3) @@ -315,13 +326,13 @@ def hurwitz_zeta(s, x, **kwargs): Numerical evaluations:: - sage: hurwitz_zeta(3, 1/2).n() + sage: hurwitz_zeta(3, 1/2).n() # needs mpmath 8.41439832211716 - sage: hurwitz_zeta(11/10, 1/2).n() + sage: hurwitz_zeta(11/10, 1/2).n() # needs sage.symbolic 12.1038134956837 - sage: hurwitz_zeta(3, x).series(x, 60).subs(x=0.5).n() + sage: hurwitz_zeta(3, x).series(x, 60).subs(x=0.5).n() # needs sage.symbolic 8.41439832211716 - sage: hurwitz_zeta(3, 0.5) + sage: hurwitz_zeta(3, 0.5) # needs mpmath 8.41439832211716 REFERENCES: @@ -338,31 +349,32 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: zetaderiv(1, x) zetaderiv(1, x) sage: zetaderiv(1, x).diff(x) zetaderiv(2, x) sage: var('n') n - sage: zetaderiv(n,x) + sage: zetaderiv(n, x) zetaderiv(n, x) sage: zetaderiv(1, 4).n() -0.0689112658961254 - sage: import mpmath; mpmath.diff(lambda x: mpmath.zeta(x), 4) + sage: import mpmath; mpmath.diff(lambda x: mpmath.zeta(x), 4) # needs mpmath mpf('-0.068911265896125382') TESTS:: - sage: latex(zetaderiv(2,x)) + sage: latex(zetaderiv(2, x)) # needs sage.symbolic \zeta^\prime\left(2, x\right) - sage: a = loads(dumps(zetaderiv(2,x))) - sage: a.operator() == zetaderiv + sage: a = loads(dumps(zetaderiv(2, x))) # needs sage.symbolic + sage: a.operator() == zetaderiv # needs sage.symbolic True - sage: b = RBF(3/2, 1e-10) - sage: zetaderiv(1, b, hold=True) + sage: b = RBF(3/2, 1e-10) # needs sage.libs.flint + sage: zetaderiv(1, b, hold=True) # needs sage.libs.flint sage.symbolic zetaderiv(1, [1.500000000 +/- 1.01e-10]) - sage: zetaderiv(b, 1) + sage: zetaderiv(b, 1) # needs sage.libs.flint sage.symbolic zetaderiv([1.500000000 +/- 1.01e-10], 1) """ GinacFunction.__init__(self, "zetaderiv", nargs=2, @@ -372,25 +384,26 @@ def _evalf_(self, n, x, parent=None, algorithm=None): r""" TESTS:: - sage: zetaderiv(0, 3, hold=True).n() == zeta(3).n() + sage: zetaderiv(0, 3, hold=True).n() == zeta(3).n() # needs sage.symbolic True - sage: zetaderiv(2, 3 + I).n() + sage: zetaderiv(2, 3 + I).n() # needs sage.symbolic 0.0213814086193841 - 0.174938812330834*I """ - from mpmath import zeta - return mpmath_utils.call(zeta, x, 1, n, parent=parent) + return _mpmath_utils_call(_mpmath_zeta, x, 1, n, parent=parent) def _method_arguments(self, k, x, **args): r""" TESTS:: - sage: zetaderiv(1, RBF(3/2, 0.0001)) + sage: zetaderiv(1, RBF(3/2, 0.0001)) # needs sage.libs.flint [-3.93 +/- ...e-3] """ return [x, k] + zetaderiv = Function_zetaderiv() + def zeta_symmetric(s): r""" Completed function `\xi(s)` that satisfies @@ -417,13 +430,16 @@ def zeta_symmetric(s): EXAMPLES:: - sage: zeta_symmetric(0.7) - 0.497580414651127 - sage: zeta_symmetric(1-0.7) - 0.497580414651127 + sage: # needs sage.rings.real_mpfr sage: RR = RealField(200) sage: zeta_symmetric(RR(0.7)) 0.49758041465112690357779107525638385212657443284080589766062 + + sage: # needs sage.libs.pari sage.rings.real_mpfr + sage: zeta_symmetric(0.7) + 0.497580414651127 + sage: zeta_symmetric(1 - 0.7) + 0.497580414651127 sage: C.<i> = ComplexField() sage: zeta_symmetric(0.5 + i*14.0) 0.000201294444235258 + 1.49077798716757e-19*I @@ -444,10 +460,8 @@ def zeta_symmetric(s): if s == 1: # deal with poles, hopefully return R(0.5) - return (s/2 + 1).gamma() * (s-1) * (R.pi()**(-s/2)) * s.zeta() + return (s/2 + 1).gamma() * (s-1) * (R.pi()**(-s/2)) * s.zeta() -import math -from sage.rings.polynomial.polynomial_real_mpfr_dense import PolynomialRealDense class DickmanRho(BuiltinFunction): r""" @@ -483,13 +497,14 @@ class DickmanRho(BuiltinFunction): EXAMPLES:: + sage: # needs sage.symbolic sage: dickman_rho(2) 0.306852819440055 sage: dickman_rho(10) 2.77017183772596e-11 sage: dickman_rho(10.00000000000000000000000000000000000000) 2.77017183772595898875812120063434232634e-11 - sage: plot(log(dickman_rho(x)), (x, 0, 15)) + sage: plot(log(dickman_rho(x)), (x, 0, 15)) # needs sage.plot Graphics object consisting of 1 graphics primitive AUTHORS: @@ -508,11 +523,11 @@ def __init__(self): TESTS:: - sage: dickman_rho(x) + sage: dickman_rho(x) # needs sage.symbolic dickman_rho(x) - sage: dickman_rho(3) + sage: dickman_rho(3) # needs sage.symbolic 0.0486083882911316 - sage: dickman_rho(pi) + sage: dickman_rho(pi) # needs sage.symbolic 0.0359690758968463 """ self._cur_prec = 0 @@ -522,9 +537,12 @@ def _eval_(self, x): """ EXAMPLES:: - sage: [dickman_rho(n) for n in [1..10]] - [1.00000000000000, 0.306852819440055, 0.0486083882911316, 0.00491092564776083, 0.000354724700456040, 0.0000196496963539553, 8.74566995329392e-7, 3.23206930422610e-8, 1.01624828273784e-9, 2.77017183772596e-11] - sage: dickman_rho(0) + sage: [dickman_rho(n) for n in [1..10]] # needs sage.symbolic + [1.00000000000000, 0.306852819440055, 0.0486083882911316, + 0.00491092564776083, 0.000354724700456040, 0.0000196496963539553, + 8.74566995329392e-7, 3.23206930422610e-8, 1.01624828273784e-9, + 2.77017183772596e-11] + sage: dickman_rho(0) # needs sage.symbolic 1.00000000000000 """ if not is_RealNumber(x): @@ -545,9 +563,8 @@ def _eval_(self, x): max = x.parent()(1.1)*x + 10 abs_prec = (-self.approximate(max).log2() + rel_prec + 2*max.log2()).ceil() self._f = {} - if sys.getrecursionlimit() < max + 10: - sys.setrecursionlimit(int(max) + 10) - self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent()) + with increase_recursion_limit(int(max)): + self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent()) return self._f[n](2*(x-n-x.parent()(0.5))) def power_series(self, n, abs_prec): @@ -570,7 +587,7 @@ def power_series(self, n, abs_prec): -9.9376e-8*x^11 + 3.7722e-7*x^10 - 1.4684e-6*x^9 + 5.8783e-6*x^8 - 0.000024259*x^7 + 0.00010341*x^6 - 0.00045583*x^5 + 0.0020773*x^4 - 0.0097336*x^3 + 0.045224*x^2 - 0.11891*x + 0.13032 sage: f(-1), f(0), f(1) (0.30685, 0.13032, 0.048608) - sage: dickman_rho(2), dickman_rho(2.5), dickman_rho(3) + sage: dickman_rho(2), dickman_rho(2.5), dickman_rho(3) # needs sage.symbolic (0.306852819440055, 0.130319561832251, 0.0486083882911316) """ return self._compute_power_series(n, abs_prec, cache_ring=None) @@ -648,11 +665,11 @@ def approximate(self, x, parent=None): EXAMPLES:: - sage: dickman_rho.approximate(10) + sage: dickman_rho.approximate(10) # needs sage.rings.real_mpfr 2.41739196365564e-11 - sage: dickman_rho(10) + sage: dickman_rho(10) # needs sage.symbolic 2.77017183772596e-11 - sage: dickman_rho.approximate(1000) + sage: dickman_rho.approximate(1000) # needs sage.rings.real_mpfr 4.32938809066403e-3464 """ log, exp, sqrt, pi = math.log, math.exp, math.sqrt, math.pi @@ -665,4 +682,5 @@ def approximate(self, x, parent=None): y = (exp(xi)-1.0)/xi - x return (-x*xi + RR(xi).eint()).exp() / (sqrt(2*pi*x)*xi) + dickman_rho = DickmanRho() diff --git a/src/sage/functions/trig.py b/src/sage/functions/trig.py index 16aeeae43ab..62e5bd35b2e 100644 --- a/src/sage/functions/trig.py +++ b/src/sage/functions/trig.py @@ -1,9 +1,10 @@ r""" Trigonometric functions """ -from sage.symbolic.function import GinacFunction import math +from sage.symbolic.function import GinacFunction + class Function_sin(GinacFunction): def __init__(self): @@ -12,45 +13,48 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: sin(0) 0 sage: sin(x).subs(x==0) 0 sage: sin(2).n(100) 0.90929742682568169539601986591 - sage: loads(dumps(sin)) - sin - sage: sin(x)._sympy_() + sage: sin(x)._sympy_() # needs sympy sin(x) We can prevent evaluation using the ``hold`` parameter:: - sage: sin(0,hold=True) + sage: sin(0, hold=True) # needs sage.symbolic sin(0) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = sin(0,hold=True); a.simplify() + sage: a = sin(0, hold=True); a.simplify() # needs sage.symbolic 0 If possible, the argument is also reduced modulo the period length `2\pi`, and well-known identities are directly evaluated:: - sage: k = var('k', domain='integer') - sage: sin(1 + 2*k*pi) + sage: k = var('k', domain='integer') # needs sage.symbolic + sage: sin(1 + 2*k*pi) # needs sage.symbolic sin(1) - sage: sin(k*pi) + sage: sin(k*pi) # needs sage.symbolic 0 TESTS:: - sage: conjugate(sin(x)) + sage: loads(dumps(sin)) + sin + + sage: conjugate(sin(x)) # needs sage.symbolic sin(conjugate(x)) sage: sin(complex(1,1)) # rel tol 1e-15 (1.2984575814159773+0.6349639147847361j) + sage: # needs sage.symbolic sage: sin(pi/5) 1/4*sqrt(-2*sqrt(5) + 10) sage: sin(pi/8) @@ -94,27 +98,33 @@ def __init__(self): sage: csc(104*pi/105) csc(1/105*pi) - sage: all(sin(rat*pi).n(200)-sin(rat*pi,hold=True).n(200) < 1e-30 for rat in [1/5,2/5,1/30,7/30,11/30,13/30,1/8,3/8,1/24,5/24,7/24,11/24]) + sage: all(sin(rat*pi).n(200) - sin(rat*pi, hold=True).n(200) < 1e-30 # needs sage.symbolic + ....: for rat in [1/5, 2/5, 1/30, 7/30, 11/30, 13/30, + ....: 1/8, 3/8, 1/24, 5/24, 7/24, 11/24]) True - sage: all(cos(rat*pi).n(200)-cos(rat*pi,hold=True).n(200) < 1e-30 for rat in [1/10,3/10,1/12,5/12,1/15,2/15,4/15,7/15,1/8,3/8,1/24,5/24,11/24]) + sage: all(cos(rat*pi).n(200)-cos(rat*pi, hold=True).n(200) < 1e-30 # needs sage.symbolic + ....: for rat in [1/10, 3/10, 1/12, 5/12, 1/15, 2/15, 4/15, 7/15, + ....: 1/8, 3/8, 1/24, 5/24, 11/24]) True - sage: all(tan(rat*pi).n(200)-tan(rat*pi,hold=True).n(200) < 1e-30 for rat in [1/5,2/5,1/10,3/10,1/20,3/20,7/20,9/20,1/8,3/8,1/16,3/16,5/16,7/16,1/24,5/24,7/24,11/24]) + sage: all(tan(rat*pi).n(200)-tan(rat*pi, hold=True).n(200) < 1e-30 # needs sage.symbolic + ....: for rat in [1/5, 2/5, 1/10, 3/10, 1/20, 3/20, 7/20, 9/20, + ....: 1/8, 3/8, 1/16, 3/16, 5/16, 7/16, 1/24, 5/24, 7/24, 11/24]) True Check that :trac:`20456` is fixed:: - sage: assume(x>0) - sage: sin(pi*x) + sage: assume(x > 0) # needs sage.symbolic + sage: sin(pi*x) # needs sage.symbolic sin(pi*x) - sage: forget() + sage: forget() # needs sage.symbolic Check that :trac:`20752` is fixed:: - sage: sin(3*pi+41/42*pi) + sage: sin(3*pi + 41/42*pi) # needs sage.symbolic -sin(1/42*pi) - sage: sin(-5*pi+1/42*pi) + sage: sin(-5*pi + 1/42*pi) # needs sage.symbolic -sin(1/42*pi) - sage: sin(pi-1/42*pi) + sage: sin(pi - 1/42*pi) # needs sage.symbolic sin(1/42*pi) """ GinacFunction.__init__(self, 'sin', latex_name=r"\sin", @@ -132,32 +142,32 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: cos(pi) -1 sage: cos(x).subs(x==pi) -1 sage: cos(2).n(100) -0.41614683654714238699756822950 - sage: loads(dumps(cos)) - cos - sage: cos(x)._sympy_() + sage: cos(x)._sympy_() # needs sympy cos(x) We can prevent evaluation using the ``hold`` parameter:: - sage: cos(0,hold=True) + sage: cos(0, hold=True) # needs sage.symbolic cos(0) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = cos(0,hold=True); a.simplify() + sage: a = cos(0, hold=True); a.simplify() # needs sage.symbolic 1 If possible, the argument is also reduced modulo the period length `2\pi`, and well-known identities are directly evaluated:: + sage: # needs sage.symbolic sage: k = var('k', domain='integer') sage: cos(1 + 2*k*pi) cos(1) @@ -168,18 +178,21 @@ def __init__(self): TESTS:: - sage: conjugate(cos(x)) + sage: loads(dumps(cos)) + cos + + sage: conjugate(cos(x)) # needs sage.symbolic cos(conjugate(x)) sage: cos(complex(1,1)) # rel tol 1e-15 (0.8337300251311491-0.9888977057628651j) Check that :trac:`20752` is fixed:: - sage: cos(3*pi+41/42*pi) + sage: cos(3*pi + 41/42*pi) # needs sage.symbolic cos(1/42*pi) - sage: cos(-5*pi+1/42*pi) + sage: cos(-5*pi + 1/42*pi) # needs sage.symbolic -cos(1/42*pi) - sage: cos(pi-1/42*pi) + sage: cos(pi - 1/42*pi) # needs sage.symbolic -cos(1/42*pi) """ GinacFunction.__init__(self, 'cos', latex_name=r"\cos", @@ -197,12 +210,14 @@ def __init__(self): EXAMPLES:: - sage: tan(pi) - 0 sage: tan(3.1415) -0.0000926535900581913 sage: tan(3.1415/4) 0.999953674278156 + + sage: # needs sage.symbolic + sage: tan(pi) + 0 sage: tan(pi/4) 1 sage: tan(1/2) @@ -212,37 +227,37 @@ def __init__(self): We can prevent evaluation using the ``hold`` parameter:: - sage: tan(pi/4,hold=True) + sage: tan(pi/4, hold=True) # needs sage.symbolic tan(1/4*pi) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = tan(pi/4,hold=True); a.simplify() + sage: a = tan(pi/4, hold=True); a.simplify() # needs sage.symbolic 1 If possible, the argument is also reduced modulo the period length `\pi`, and well-known identities are directly evaluated:: - sage: k = var('k', domain='integer') - sage: tan(1 + 2*k*pi) + sage: k = var('k', domain='integer') # needs sage.symbolic + sage: tan(1 + 2*k*pi) # needs sage.symbolic tan(1) - sage: tan(k*pi) + sage: tan(k*pi) # needs sage.symbolic 0 TESTS:: - sage: tan(x)._sympy_() + sage: tan(x)._sympy_() # needs sympy sage.symbolic tan(x) - sage: conjugate(tan(x)) + sage: conjugate(tan(x)) # needs sage.symbolic tan(conjugate(x)) sage: tan(complex(1,1)) # rel tol 1e-15 (0.2717525853195118+1.0839233273386946j) Check that :trac:`19791` is fixed:: - sage: tan(2+I).imag().n() + sage: tan(2+I).imag().n() # needs sage.symbolic 1.16673625724092 """ GinacFunction.__init__(self, 'tan', latex_name=r"\tan") @@ -258,6 +273,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: cot(pi/4) 1 sage: RR(cot(pi/4)) @@ -267,24 +283,25 @@ def __init__(self): sage: cot(0.5) 1.83048772171245 - sage: latex(cot(x)) + sage: latex(cot(x)) # needs sage.symbolic \cot\left(x\right) - sage: cot(x)._sympy_() + sage: cot(x)._sympy_() # needs sympy sage.symbolic cot(x) We can prevent evaluation using the ``hold`` parameter:: - sage: cot(pi/4,hold=True) + sage: cot(pi/4, hold=True) # needs sage.symbolic cot(1/4*pi) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = cot(pi/4,hold=True); a.simplify() + sage: a = cot(pi/4, hold=True); a.simplify() # needs sage.symbolic 1 EXAMPLES:: + sage: # needs sage.symbolic sage: cot(pi/4) 1 sage: cot(x).subs(x==pi/4) @@ -294,7 +311,8 @@ def __init__(self): sage: cot(x) cot(x) - sage: n(cot(pi/4),100) + sage: # needs sage.symbolic + sage: n(cot(pi/4), 100) 1.0000000000000000000000000000 sage: float(cot(1)) 0.64209261593433... @@ -305,29 +323,29 @@ def __init__(self): TESTS:: - sage: cot(float(0)) + sage: cot(float(0)) # needs sage.symbolic Infinity - sage: cot(SR(0)) + sage: cot(SR(0)) # needs sage.symbolic Infinity - sage: cot(float(0.1)) + sage: cot(float(0.1)) # needs sage.symbolic 9.966644423259238 sage: type(_) <... 'float'> - sage: cot(float(0)) + sage: cot(float(0)) # needs sage.symbolic Infinity - sage: cot(SR(0)) + sage: cot(SR(0)) # needs sage.symbolic Infinity - sage: cot(float(0.1)) + sage: cot(float(0.1)) # needs sage.symbolic 9.966644423259238 sage: type(_) <... 'float'> Test complex input:: - sage: cot(complex(1,1)) # rel tol 1e-15 + sage: cot(complex(1,1)) # rel tol 1e-15 # needs sage.rings.complex_double (0.21762156185440273-0.8680141428959249j) - sage: cot(1.+I) + sage: cot(1.+I) # needs sage.symbolic 0.217621561854403 - 0.868014142895925*I """ GinacFunction.__init__(self, 'cot', latex_name=r"\cot") @@ -336,9 +354,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.arange(2, 5) - sage: cot(a) + sage: import numpy # needs numpy + sage: a = numpy.arange(2, 5) # needs numpy + sage: cot(a) # needs numpy array([-0.45765755, -7.01525255, 0.86369115]) """ return 1.0 / tan(x) @@ -354,6 +372,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: sec(pi/4) sqrt(2) sage: sec(x).subs(x==pi/4) @@ -373,31 +392,32 @@ def __init__(self): sage: sec(0.5) 1.13949392732455 + sage: # needs sage.symbolic sage: bool(diff(sec(x), x) == diff(1/cos(x), x)) True sage: diff(sec(x), x) sec(x)*tan(x) sage: latex(sec(x)) \sec\left(x\right) - sage: sec(x)._sympy_() + sage: sec(x)._sympy_() # needs sympy sec(x) We can prevent evaluation using the ``hold`` parameter:: - sage: sec(pi/4,hold=True) + sage: sec(pi/4, hold=True) # needs sage.symbolic sec(1/4*pi) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = sec(pi/4,hold=True); a.simplify() + sage: a = sec(pi/4, hold=True); a.simplify() # needs sage.symbolic sqrt(2) TESTS: Test complex input:: - sage: sec(complex(1,1)) # rel tol 1e-15 + sage: sec(complex(1,1)) # rel tol 1e-15 # needs sage.rings.complex_double (0.49833703055518686+0.5910838417210451j) """ GinacFunction.__init__(self, 'sec', latex_name=r"\sec") @@ -406,9 +426,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.arange(2, 5) - sage: sec(a) + sage: import numpy # needs numpy + sage: a = numpy.arange(2, 5) # needs numpy + sage: sec(a) # needs numpy array([-2.40299796, -1.01010867, -1.52988566]) """ return 1 / cos(x) @@ -424,6 +444,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: csc(pi/4) sqrt(2) sage: csc(x).subs(x==pi/4) @@ -434,7 +455,7 @@ def __init__(self): csc(x) sage: RR(csc(pi/4)) 1.41421356237310 - sage: n(csc(pi/4),100) + sage: n(csc(pi/4), 100) 1.4142135623730950488016887242 sage: float(csc(pi/4)) 1.4142135623730951 @@ -443,31 +464,32 @@ def __init__(self): sage: csc(0.5) 2.08582964293349 + sage: # needs sage.symbolic sage: bool(diff(csc(x), x) == diff(1/sin(x), x)) True sage: diff(csc(x), x) -cot(x)*csc(x) sage: latex(csc(x)) \csc\left(x\right) - sage: csc(x)._sympy_() + sage: csc(x)._sympy_() # needs sympy csc(x) We can prevent evaluation using the ``hold`` parameter:: - sage: csc(pi/4,hold=True) + sage: csc(pi/4, hold=True) # needs sage.symbolic csc(1/4*pi) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = csc(pi/4,hold=True); a.simplify() + sage: a = csc(pi/4,hold=True); a.simplify() # needs sage.symbolic sqrt(2) TESTS: Test complex input:: - sage: csc(complex(1,1)) # rel tol 1e-15 + sage: csc(complex(1,1)) # rel tol 1e-15 # needs sage.rings.complex_double (0.6215180171704284-0.30393100162842646j) """ GinacFunction.__init__(self, 'csc', latex_name=r"\csc") @@ -476,9 +498,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.arange(2, 5) - sage: csc(a) + sage: import numpy # needs numpy + sage: a = numpy.arange(2, 5) # needs numpy + sage: csc(a) # needs numpy array([ 1.09975017, 7.0861674 , -1.32134871]) """ return 1 / sin(x) @@ -500,25 +522,26 @@ def __init__(self): sage: arcsin(0.5) 0.523598775598299 - sage: arcsin(1/2) + sage: arcsin(1/2) # needs sage.symbolic 1/6*pi - sage: arcsin(1 + 1.0*I) + sage: arcsin(1 + 1.0*I) # needs sage.symbolic 0.666239432492515 + 1.06127506190504*I We can delay evaluation using the ``hold`` parameter:: - sage: arcsin(0,hold=True) + sage: arcsin(0, hold=True) # needs sage.symbolic arcsin(0) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = arcsin(0,hold=True); a.simplify() + sage: a = arcsin(0, hold=True); a.simplify() # needs sage.symbolic 0 ``conjugate(arcsin(x))==arcsin(conjugate(x))``, unless on the branch cuts which run along the real axis outside the interval [-1, +1].:: + sage: # needs sage.symbolic sage: conjugate(arcsin(x)) conjugate(arcsin(x)) sage: var('y', domain='positive') @@ -536,13 +559,13 @@ def __init__(self): TESTS:: - sage: arcsin(x)._sympy_() + sage: arcsin(x)._sympy_() # needs sympy sage.symbolic asin(x) - sage: arcsin(x).operator() + sage: arcsin(x).operator() # needs sage.symbolic arcsin - sage: asin(complex(1,1)) + sage: asin(complex(1,1)) # needs sage.rings.complex_double (0.6662394324925152+1.0612750619050357j) - sage: asin(SR(2.1)) + sage: asin(SR(2.1)) # needs sage.symbolic 1.57079632679490 - 1.37285914424258*I """ GinacFunction.__init__(self, 'arcsin', latex_name=r"\arcsin", @@ -563,27 +586,28 @@ def __init__(self): sage: arccos(0.5) 1.04719755119660 - sage: arccos(1/2) + sage: arccos(1/2) # needs sage.symbolic 1/3*pi - sage: arccos(1 + 1.0*I) + sage: arccos(1 + 1.0*I) # needs sage.symbolic 0.904556894302381 - 1.06127506190504*I - sage: arccos(3/4).n(100) + sage: arccos(3/4).n(100) # needs sage.symbolic 0.72273424781341561117837735264 We can delay evaluation using the ``hold`` parameter:: - sage: arccos(0,hold=True) + sage: arccos(0, hold=True) # needs sage.symbolic arccos(0) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = arccos(0,hold=True); a.simplify() + sage: a = arccos(0, hold=True); a.simplify() # needs sage.symbolic 1/2*pi ``conjugate(arccos(x))==arccos(conjugate(x))``, unless on the branch cuts, which run along the real axis outside the interval [-1, +1].:: + sage: # needs sage.symbolic sage: conjugate(arccos(x)) conjugate(arccos(x)) sage: var('y', domain='positive') @@ -601,13 +625,13 @@ def __init__(self): TESTS:: - sage: arccos(x)._sympy_() + sage: arccos(x)._sympy_() # needs sympy sage.symbolic acos(x) - sage: arccos(x).operator() + sage: arccos(x).operator() # needs sage.symbolic arccos - sage: acos(complex(1,1)) + sage: acos(complex(1,1)) # needs sage.rings.complex_double (0.9045568943023814-1.0612750619050357j) - sage: acos(SR(2.1)) + sage: acos(SR(2.1)) # needs sage.symbolic 1.37285914424258*I """ GinacFunction.__init__(self, 'arccos', latex_name=r"\arccos", @@ -626,6 +650,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: arctan(1/2) arctan(1/2) sage: RDF(arctan(1/2)) # rel tol 1e-15 @@ -637,18 +662,19 @@ def __init__(self): We can delay evaluation using the ``hold`` parameter:: - sage: arctan(0,hold=True) + sage: arctan(0, hold=True) # needs sage.symbolic arctan(0) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = arctan(0,hold=True); a.simplify() + sage: a = arctan(0, hold=True); a.simplify() # needs sage.symbolic 0 ``conjugate(arctan(x))==arctan(conjugate(x))``, unless on the branch cuts which run along the imaginary axis outside the interval [-I, +I].:: + sage: # needs sage.symbolic sage: conjugate(arctan(x)) conjugate(arctan(x)) sage: var('y', domain='positive') @@ -668,18 +694,18 @@ def __init__(self): TESTS:: - sage: arctan(x)._sympy_() + sage: arctan(x)._sympy_() # needs sympy sage.symbolic atan(x) - sage: arctan(x).operator() + sage: arctan(x).operator() # needs sage.symbolic arctan - sage: atan(complex(1,1)) + sage: atan(complex(1,1)) # needs sage.rings.complex_double (1.0172219678978514+0.4023594781085251j) Check that :trac:`19918` is fixed:: - sage: arctan(-x).subs(x=oo) + sage: arctan(-x).subs(x=oo) # needs sage.symbolic -1/2*pi - sage: arctan(-x).subs(x=-oo) + sage: arctan(-x).subs(x=-oo) # needs sage.symbolic 1/2*pi """ GinacFunction.__init__(self, 'arctan', latex_name=r"\arctan", @@ -698,6 +724,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: arccot(1/2) arccot(1/2) sage: RDF(arccot(1/2)) # abs tol 2e-16 @@ -715,24 +742,24 @@ def __init__(self): We can delay evaluation using the ``hold`` parameter:: - sage: arccot(1,hold=True) + sage: arccot(1, hold=True) # needs sage.symbolic arccot(1) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = arccot(1,hold=True); a.simplify() + sage: a = arccot(1, hold=True); a.simplify() # needs sage.symbolic 1/4*pi TESTS: Test complex input:: - sage: arccot(x)._sympy_() + sage: arccot(x)._sympy_() # needs sympy sage.symbolic acot(x) - sage: arccot(complex(1,1)) # rel tol 1e-15 + sage: arccot(complex(1,1)) # rel tol 1e-15 # needs sage.rings.complex_double (0.5535743588970452-0.4023594781085251j) - sage: arccot(1.+I) + sage: arccot(1.+I) # needs sage.symbolic 0.553574358897045 - 0.402359478108525*I """ @@ -745,9 +772,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.arange(2, 5) - sage: arccot(a) + sage: import numpy # needs numpy + sage: a = numpy.arange(2, 5) # needs numpy + sage: arccot(a) # needs numpy array([0.46364761, 0.32175055, 0.24497866]) """ return math.pi / 2 - arctan(x) @@ -763,6 +790,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: arccsc(2) arccsc(2) sage: RDF(arccsc(2)) # rel tol 1e-15 @@ -775,25 +803,25 @@ def __init__(self): arccsc(I + 1) sage: diff(acsc(x), x) -1/(sqrt(x^2 - 1)*x) - sage: arccsc(x)._sympy_() + sage: arccsc(x)._sympy_() # needs sympy acsc(x) We can delay evaluation using the ``hold`` parameter:: - sage: arccsc(1,hold=True) + sage: arccsc(1, hold=True) # needs sage.symbolic arccsc(1) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = arccsc(1,hold=True); a.simplify() + sage: a = arccsc(1, hold=True); a.simplify() # needs sage.symbolic 1/2*pi TESTS: Test complex input:: - sage: arccsc(complex(1,1)) # rel tol 1e-15 + sage: arccsc(complex(1,1)) # rel tol 1e-15 # needs sage.rings.complex_double (0.45227844715119064-0.5306375309525178j) """ GinacFunction.__init__(self, 'arccsc', latex_name=r"\operatorname{arccsc}", @@ -805,9 +833,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.arange(2, 5) - sage: arccsc(a) + sage: import numpy # needs numpy + sage: a = numpy.arange(2, 5) # needs numpy + sage: arccsc(a) # needs numpy array([0.52359878, 0.33983691, 0.25268026]) """ return arcsin(1.0 / x) @@ -823,6 +851,7 @@ def __init__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: arcsec(2) arcsec(2) sage: arcsec(2.0) @@ -837,25 +866,25 @@ def __init__(self): arcsec(I + 1) sage: diff(asec(x), x) 1/(sqrt(x^2 - 1)*x) - sage: arcsec(x)._sympy_() + sage: arcsec(x)._sympy_() # needs sympy asec(x) We can delay evaluation using the ``hold`` parameter:: - sage: arcsec(1,hold=True) + sage: arcsec(1, hold=True) # needs sage.symbolic arcsec(1) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: a = arcsec(1,hold=True); a.simplify() + sage: a = arcsec(1, hold=True); a.simplify() # needs sage.symbolic 0 TESTS: Test complex input:: - sage: arcsec(complex(1,1)) # rel tol 1e-15 + sage: arcsec(complex(1,1)) # rel tol 1e-15 # needs sage.rings.complex_double (1.118517879643706+0.5306375309525178j) """ GinacFunction.__init__(self, 'arcsec', latex_name=r"\operatorname{arcsec}", @@ -867,9 +896,9 @@ def _eval_numpy_(self, x): """ EXAMPLES:: - sage: import numpy - sage: a = numpy.arange(2, 5) - sage: arcsec(a) + sage: import numpy # needs numpy + sage: a = numpy.arange(2, 5) # needs numpy + sage: arcsec(a) # needs numpy array([1.04719755, 1.23095942, 1.31811607]) """ return arccos(1.0 / x) @@ -902,89 +931,91 @@ def __init__(self): Note the difference between the two functions:: - sage: arctan2(1,-1) + sage: arctan2(1, -1) # needs sage.symbolic 3/4*pi - sage: arctan(1/-1) + sage: arctan(1/-1) # needs sage.symbolic -1/4*pi This is consistent with Python and Maxima:: - sage: maxima.atan2(1,-1) + sage: maxima.atan2(1, -1) # needs sage.symbolic (3*%pi)/4 sage: math.atan2(1,-1) 2.356194490192345 More examples:: - sage: arctan2(1,0) + sage: arctan2(1, 0) # needs sage.symbolic 1/2*pi - sage: arctan2(2,3) + sage: arctan2(2, 3) # needs sage.symbolic arctan(2/3) - sage: arctan2(-1,-1) + sage: arctan2(-1, -1) # needs sage.symbolic -3/4*pi Of course we can approximate as well:: - sage: arctan2(-1/2,1).n(100) + sage: arctan2(-1/2, 1).n(100) # needs sage.symbolic -0.46364760900080611621425623146 - sage: arctan2(2,3).n(100) + sage: arctan2(2, 3).n(100) # needs sage.symbolic 0.58800260354756755124561108063 We can delay evaluation using the ``hold`` parameter:: - sage: arctan2(-1/2,1,hold=True) + sage: arctan2(-1/2, 1, hold=True) # needs sage.symbolic arctan2(-1/2, 1) To then evaluate again, we currently must use Maxima via :meth:`sage.symbolic.expression.Expression.simplify`:: - sage: arctan2(-1/2,1,hold=True).simplify() + sage: arctan2(-1/2, 1, hold=True).simplify() # needs sage.symbolic -arctan(1/2) The function also works with numpy arrays as input:: + sage: # needs numpy sage: import numpy sage: a = numpy.linspace(1, 3, 3) sage: b = numpy.linspace(3, 6, 3) sage: atan2(a, b) array([0.32175055, 0.41822433, 0.46364761]) - sage: atan2(1,a) + sage: atan2(1,a) # needs numpy array([0.78539816, 0.46364761, 0.32175055]) - sage: atan2(a, 1) + sage: atan2(a, 1) # needs numpy array([0.78539816, 1.10714872, 1.24904577]) TESTS:: - sage: x,y = var('x,y') - sage: arctan2(y,x).operator() + sage: x,y = var('x,y') # needs sage.symbolic + sage: arctan2(y, x).operator() # needs sage.symbolic arctan2 Check if :trac:`8565` is fixed:: - sage: atan2(-pi,0) + sage: atan2(-pi, 0) # needs sage.symbolic -1/2*pi Check if :trac:`8564` is fixed:: - sage: arctan2(x,x)._sympy_() + sage: arctan2(x,x)._sympy_() # needs sympy sage.symbolic atan2(x, x) Check if numerical evaluation works :trac:`9913`:: - sage: arctan2(0, -log(2)).n() + sage: arctan2(0, -log(2)).n() # needs sage.symbolic 3.14159265358979 Check that atan2(0,0) returns NaN :trac:`21614`:: - sage: atan2(0,0) + sage: # needs sage.symbolic + sage: atan2(0, 0) NaN - sage: atan2(0,0).n() + sage: atan2(0, 0).n() NaN - sage: atan2(0,0,hold=True) + sage: atan2(0, 0, hold=True) arctan2(0, 0) - sage: atan2(0,0,hold=True).n() + sage: atan2(0, 0, hold=True).n() Traceback (most recent call last): ... RuntimeError: atan2(): division by zero @@ -992,7 +1023,7 @@ def __init__(self): Check if :trac:`10062` is fixed, this was caused by ``(I*I).is_positive()`` returning ``True``:: - sage: arctan2(0, I*I) + sage: arctan2(0, I*I) # needs sage.symbolic pi """ GinacFunction.__init__(self, 'arctan2', nargs=2, latex_name=r"\arctan", diff --git a/src/sage/functions/wigner.py b/src/sage/functions/wigner.py index cb5a5c0e107..af987c20084 100644 --- a/src/sage/functions/wigner.py +++ b/src/sage/functions/wigner.py @@ -23,10 +23,14 @@ # https://www.gnu.org/licenses/ # ********************************************************************** -from sage.rings.complex_mpfr import ComplexNumber +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.finite_rings.integer_mod import Mod -from sage.symbolic.constants import pi + +lazy_import('sage.rings.complex_mpfr', 'ComplexNumber') + +lazy_import('sage.symbolic.constants', 'pi') + # This list of precomputed factorials is needed to massively # accelerate future calculations of the various coefficients @@ -78,15 +82,15 @@ def wigner_3j(j_1, j_2, j_3, m_1, m_2, m_3, prec=None): EXAMPLES:: - sage: wigner_3j(2, 6, 4, 0, 0, 0) + sage: wigner_3j(2, 6, 4, 0, 0, 0) # needs sage.symbolic sqrt(5/143) sage: wigner_3j(2, 6, 4, 0, 0, 1) 0 - sage: wigner_3j(0.5, 0.5, 1, 0.5, -0.5, 0) + sage: wigner_3j(0.5, 0.5, 1, 0.5, -0.5, 0) # needs sage.symbolic sqrt(1/6) - sage: wigner_3j(40, 100, 60, -10, 60, -50) + sage: wigner_3j(40, 100, 60, -10, 60, -50) # needs sage.symbolic 95608/18702538494885*sqrt(21082735836735314343364163310/220491455010479533763) - sage: wigner_3j(2500, 2500, 5000, 2488, 2400, -4888, prec=64) + sage: wigner_3j(2500, 2500, 5000, 2488, 2400, -4888, prec=64) # needs sage.rings.real_mpfr 7.60424456883448589e-12 It is an error to have arguments that are not integer or half @@ -223,11 +227,11 @@ def clebsch_gordan(j_1, j_2, j_3, m_1, m_2, m_3, prec=None): EXAMPLES:: - sage: simplify(clebsch_gordan(3/2,1/2,2, 3/2,1/2,2)) + sage: simplify(clebsch_gordan(3/2,1/2,2, 3/2,1/2,2)) # needs sage.symbolic 1 - sage: clebsch_gordan(1.5,0.5,1, 1.5,-0.5,1) + sage: clebsch_gordan(1.5,0.5,1, 1.5,-0.5,1) # needs sage.symbolic 1/2*sqrt(3) - sage: clebsch_gordan(3/2,1/2,1, -1/2,1/2,0) + sage: clebsch_gordan(3/2,1/2,1, -1/2,1/2,0) # needs sage.symbolic -sqrt(3)*sqrt(1/6) .. NOTE:: @@ -275,7 +279,7 @@ def _big_delta_coeff(aa, bb, cc, prec=None): EXAMPLES:: sage: from sage.functions.wigner import _big_delta_coeff - sage: _big_delta_coeff(1,1,1) + sage: _big_delta_coeff(1,1,1) # needs sage.symbolic 1/2*sqrt(1/6) """ if int(aa + bb - cc) != (aa + bb - cc): @@ -294,10 +298,10 @@ def _big_delta_coeff(aa, bb, cc, prec=None): maxfact = max(aa + bb - cc, aa + cc - bb, bb + cc - aa, aa + bb + cc + 1) _calc_factlist(maxfact) - argsqrt = Integer(_Factlist[int(aa + bb - cc)] * \ - _Factlist[int(aa + cc - bb)] * \ - _Factlist[int(bb + cc - aa)]) / \ - Integer(_Factlist[int(aa + bb + cc + 1)]) + argsqrt = Integer(_Factlist[int(aa + bb - cc)] * + _Factlist[int(aa + cc - bb)] * + _Factlist[int(bb + cc - aa)]) /\ + Integer(_Factlist[int(aa + bb + cc + 1)]) ressqrt = argsqrt.sqrt(prec) if isinstance(ressqrt, ComplexNumber): @@ -325,7 +329,7 @@ def racah(aa, bb, cc, dd, ee, ff, prec=None): EXAMPLES:: - sage: racah(3,3,3,3,3,3) + sage: racah(3,3,3,3,3,3) # needs sage.symbolic -1/14 .. NOTE:: @@ -398,6 +402,7 @@ def wigner_6j(j_1, j_2, j_3, j_4, j_5, j_6, prec=None): EXAMPLES:: + sage: # needs sage.symbolic sage: wigner_6j(3,3,3,3,3,3) -1/14 sage: wigner_6j(5,5,5,5,5,5) @@ -497,23 +502,24 @@ def wigner_9j(j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9, prec=None): A couple of examples and test cases, note that for speed reasons a precision is given:: - sage: wigner_9j(1,1,1, 1,1,1, 1,1,0 ,prec=64) # ==1/18 + sage: # needs sage.symbolic + sage: wigner_9j(1,1,1, 1,1,1, 1,1,0, prec=64) # ==1/18 0.0555555555555555555 sage: wigner_9j(1,1,1, 1,1,1, 1,1,1) 0 - sage: wigner_9j(1,1,1, 1,1,1, 1,1,2 ,prec=64) # ==1/18 + sage: wigner_9j(1,1,1, 1,1,1, 1,1,2, prec=64) # ==1/18 0.0555555555555555556 - sage: wigner_9j(1,2,1, 2,2,2, 1,2,1 ,prec=64) # ==-1/150 + sage: wigner_9j(1,2,1, 2,2,2, 1,2,1, prec=64) # ==-1/150 -0.00666666666666666667 - sage: wigner_9j(3,3,2, 2,2,2, 3,3,2 ,prec=64) # ==157/14700 + sage: wigner_9j(3,3,2, 2,2,2, 3,3,2, prec=64) # ==157/14700 0.0106802721088435374 - sage: wigner_9j(3,3,2, 3,3,2, 3,3,2 ,prec=64) # ==3221*sqrt(70)/(246960*sqrt(105)) - 365/(3528*sqrt(70)*sqrt(105)) + sage: wigner_9j(3,3,2, 3,3,2, 3,3,2, prec=64) # ==3221*sqrt(70)/(246960*sqrt(105)) - 365/(3528*sqrt(70)*sqrt(105)) 0.00944247746651111739 - sage: wigner_9j(3,3,1, 3.5,3.5,2, 3.5,3.5,1 ,prec=64) # ==3221*sqrt(70)/(246960*sqrt(105)) - 365/(3528*sqrt(70)*sqrt(105)) + sage: wigner_9j(3,3,1, 3.5,3.5,2, 3.5,3.5,1, prec=64) # ==3221*sqrt(70)/(246960*sqrt(105)) - 365/(3528*sqrt(70)*sqrt(105)) 0.0110216678544351364 - sage: wigner_9j(100,80,50, 50,100,70, 60,50,100 ,prec=1000)*1.0 + sage: wigner_9j(100,80,50, 50,100,70, 60,50,100, prec=1000)*1.0 1.05597798065761e-7 - sage: wigner_9j(30,30,10, 30.5,30.5,20, 30.5,30.5,10 ,prec=1000)*1.0 # ==(80944680186359968990/95103769817469)*sqrt(1/682288158959699477295) + sage: wigner_9j(30,30,10, 30.5,30.5,20, 30.5,30.5,10, prec=1000)*1.0 # ==(80944680186359968990/95103769817469)*sqrt(1/682288158959699477295) 0.0000325841699408828 sage: wigner_9j(64,62.5,114.5, 61.5,61,112.5, 113.5,110.5,60, prec=1000)*1.0 -3.41407910055520e-39 @@ -529,7 +535,7 @@ def wigner_9j(j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9, prec=None): Traceback (most recent call last): ... ValueError: j values must be integer or half integer and fulfill the triangle relation - sage: wigner_9j(1,1,1, 0.5,1,1.5, 0.5,1,2.5,prec=64) + sage: wigner_9j(1,1,1, 0.5,1,1.5, 0.5,1,2.5,prec=64) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: j values must be integer or half integer and fulfill the triangle relation @@ -584,6 +590,7 @@ def gaunt(l_1, l_2, l_3, m_1, m_2, m_3, prec=None): EXAMPLES:: + sage: # needs sage.symbolic sage: gaunt(1,0,1,1,0,-1) -1/2/sqrt(pi) sage: gaunt(1,0,1,1,0,0) @@ -704,8 +711,8 @@ def gaunt(l_1, l_2, l_3, m_1, m_2, m_3, prec=None): (4*pi) ressqrt = argsqrt.sqrt() - prefac = Integer(_Factlist[bigL] * _Factlist[l_2 - l_1 + l_3] * \ - _Factlist[l_1 - l_2 + l_3] * _Factlist[l_1 + l_2 - l_3])/ \ + prefac = Integer(_Factlist[bigL] * _Factlist[l_2 - l_1 + l_3] * + _Factlist[l_1 - l_2 + l_3] * _Factlist[l_1 + l_2 - l_3]) / \ _Factlist[2 * bigL + 1] / \ (_Factlist[bigL - l_1] * _Factlist[bigL - l_2] * _Factlist[bigL - l_3]) diff --git a/src/sage/game_theory/cooperative_game.py b/src/sage/game_theory/cooperative_game.py index 0cb18189191..b95ba0f655a 100644 --- a/src/sage/game_theory/cooperative_game.py +++ b/src/sage/game_theory/cooperative_game.py @@ -21,7 +21,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from itertools import permutations, combinations -from sage.misc.misc import powerset +from sage.combinat.subset import powerset from sage.rings.integer import Integer from sage.structure.sage_object import SageObject diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index a669cb153af..cd6e371eeb2 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -635,7 +635,7 @@ from itertools import product from .parser import Parser from sage.misc.latex import latex -from sage.misc.misc import powerset +from sage.combinat.subset import powerset from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject from sage.matrix.constructor import matrix @@ -2743,8 +2743,8 @@ def _is_degenerate_pure(self, certificate=False): sage: g._is_degenerate_pure() True - Whilst this game is not degenerate in pure strategies, it is - actually degenerate, but only in mixed strategies. + Whilst this game is not degenerate in pure strategies, it is + actually degenerate, but only in mixed strategies:: sage: A = matrix([[3, 0], [0, 3], [1.5, 1.5]]) sage: B = matrix([[4, 3], [2, 6], [3, 1]]) diff --git a/src/sage/games/hexad.py b/src/sage/games/hexad.py index 710513207a7..7b3af6f49d7 100644 --- a/src/sage/games/hexad.py +++ b/src/sage/games/hexad.py @@ -107,7 +107,6 @@ def view_list(L): return matrix(GF(2), 3, 3, lambda x, y: 1 if (x,y) in L else 0) - def picture_set(A, L): """ This is needed in the :meth:`Minimog.find_hexad` function below. diff --git a/src/sage/games/quantumino.py b/src/sage/games/quantumino.py index dd52254bef7..9f8da835585 100644 --- a/src/sage/games/quantumino.py +++ b/src/sage/games/quantumino.py @@ -413,7 +413,7 @@ class QuantuminoSolver(SageObject): Quantumino solver for the box (5, 4, 4) Aside pentamino number: 12 """ - def __init__(self, aside, box=(5,8,2)): + def __init__(self, aside, box=(5, 8, 2)): r""" Constructor. @@ -424,8 +424,8 @@ def __init__(self, aside, box=(5,8,2)): Quantumino solver for the box (5, 8, 2) Aside pentamino number: 9 """ - if not 0 <= aside < 17: - raise ValueError("aside (=%s) must be between 0 and 16" % aside) + if not (0 <= aside < 17): + raise ValueError(f"aside (={aside}) must be between 0 and 16") self._aside = aside self._box = box diff --git a/src/sage/games/sudoku.py b/src/sage/games/sudoku.py index 4731b9bc517..abcadd08ca3 100644 --- a/src/sage/games/sudoku.py +++ b/src/sage/games/sudoku.py @@ -410,7 +410,6 @@ def to_matrix(self): from sage.matrix.constructor import matrix return matrix(ZZ, self.n*self.n, self.puzzle) - def to_ascii(self): r""" Construct an ASCII-art version of a Sudoku puzzle. @@ -465,7 +464,7 @@ def to_latex(self): nsquare = n*n array = [] array.append('\\begin{array}{|*{%s}{*{%s}{r}|}}\\hline\n' % (n, n)) - gen = (x for x in self.puzzle) + gen = iter(self.puzzle) for row in range(nsquare): for col in range(nsquare): entry = next(gen) @@ -720,8 +719,7 @@ def backtrack(self): """ from .sudoku_backtrack import backtrack_all solutions = backtrack_all(self.n, self.puzzle) - for soln in solutions: - yield soln + yield from solutions def dlx(self, count_only=False): r""" @@ -829,16 +827,16 @@ def dlx(self, count_only=False): # Boxes of the grid are numbered in row-major order # ``rcbox`` simply maps a row-column index pair to the box number it lives in - rcbox = [ [i//n + n*(j//n) for i in range(nsquare)] for j in range(nsquare)] + rcbox = [ [i//n + n*(j//n) for i in range(nsquare)] for j in range(nsquare)] # Every entry in a Sudoku puzzle satisfies four constraints # Every location has a single entry, and each row, column and box has each symbol once # These arrays can be thought of as assigning ID numbers to these constraints, # and correspond to column numbers of the `0-1` matrix describing the exact cover - rows = [[i+j for i in range(nsquare)] for j in range(0, nfour, nsquare)] - cols = [[i+j for i in range(nsquare)] for j in range(nfour, 2*nfour, nsquare)] - boxes = [[i+j for i in range(nsquare)] for j in range(2*nfour, 3*nfour, nsquare)] - rowcol = [[i+j for i in range(nsquare)] for j in range(3*nfour, 4*nfour, nsquare)] + rows = [[i+j for i in range(nsquare)] for j in range(0, nfour, nsquare)] + cols = [[i+j for i in range(nsquare)] for j in range(nfour, 2*nfour, nsquare)] + boxes = [[i+j for i in range(nsquare)] for j in range(2*nfour, 3*nfour, nsquare)] + rowcol = [[i+j for i in range(nsquare)] for j in range(3*nfour, 4*nfour, nsquare)] def make_row(row, col, entry): r""" diff --git a/src/sage/geometry/abc.pyx b/src/sage/geometry/abc.pyx index 4db85b7ace8..f3aee46d324 100644 --- a/src/sage/geometry/abc.pyx +++ b/src/sage/geometry/abc.pyx @@ -13,13 +13,13 @@ class LatticePolytope: EXAMPLES:: sage: import sage.geometry.abc - sage: P = LatticePolytope([(1,2,3), (4,5,6)]) # optional - sage.geometry.polyhedron - sage: isinstance(P, sage.geometry.abc.LatticePolytope) # optional - sage.geometry.polyhedron + sage: P = LatticePolytope([(1,2,3), (4,5,6)]) # needs sage.geometry.polyhedron + sage: isinstance(P, sage.geometry.abc.LatticePolytope) # needs sage.geometry.polyhedron True By design, there is a unique direct subclass:: - sage: sage.geometry.abc.LatticePolytope.__subclasses__() # optional - sage.geometry.polyhedron + sage: sage.geometry.abc.LatticePolytope.__subclasses__() # needs sage.geometry.polyhedron [<class 'sage.geometry.lattice_polytope.LatticePolytopeClass'>] sage: len(sage.geometry.abc.Polyhedron.__subclasses__()) <= 1 @@ -39,13 +39,13 @@ class ConvexRationalPolyhedralCone: EXAMPLES:: sage: import sage.geometry.abc - sage: C = cones.nonnegative_orthant(2) # optional - sage.geometry.polyhedron - sage: isinstance(C, sage.geometry.abc.ConvexRationalPolyhedralCone) # optional - sage.geometry.polyhedron + sage: C = cones.nonnegative_orthant(2) # needs sage.geometry.polyhedron + sage: isinstance(C, sage.geometry.abc.ConvexRationalPolyhedralCone) # needs sage.geometry.polyhedron True By design, there is a unique direct subclass:: - sage: sage.geometry.abc.ConvexRationalPolyhedralCone.__subclasses__() # optional - sage.geometry.polyhedron + sage: sage.geometry.abc.ConvexRationalPolyhedralCone.__subclasses__() # needs sage.geometry.polyhedron [<class 'sage.geometry.cone.ConvexRationalPolyhedralCone'>] sage: len(sage.geometry.abc.Polyhedron.__subclasses__()) <= 1 @@ -65,13 +65,13 @@ class Polyhedron: EXAMPLES:: sage: import sage.geometry.abc - sage: P = polytopes.cube() # optional - sage.geometry.polyhedron - sage: isinstance(P, sage.geometry.abc.Polyhedron) # optional - sage.geometry.polyhedron + sage: P = polytopes.cube() # needs sage.geometry.polyhedron + sage: isinstance(P, sage.geometry.abc.Polyhedron) # needs sage.geometry.polyhedron True By design, there is a unique direct subclass:: - sage: sage.geometry.abc.Polyhedron.__subclasses__() # optional - sage.geometry.polyhedron + sage: sage.geometry.abc.Polyhedron.__subclasses__() # needs sage.geometry.polyhedron [<class 'sage.geometry.polyhedron.base0.Polyhedron_base0'>] sage: len(sage.geometry.abc.Polyhedron.__subclasses__()) <= 1 diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 865fa9299f2..f0a8620011a 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -129,6 +129,7 @@ You can work with subcones that form faces of other cones:: + sage: # needs sage.graphs sage: face = four_rays.faces(dim=2)[0] sage: face 2-d face of 3-d cone in 3-d lattice N @@ -145,6 +146,7 @@ If you need to know inclusion relations between faces, you can use :: + sage: # needs sage.graphs sage: L = four_rays.face_lattice() sage: [len(s) for s in L.level_sets()] [1, 4, 4, 1] @@ -237,9 +239,9 @@ from sage.features import PythonModule lazy_import('ppl', ['C_Polyhedron', 'Generator_System', 'Constraint_System', 'Linear_Expression', 'Poly_Con_Relation'], - feature=PythonModule("ppl", spkg="pplpy")) + feature=PythonModule("ppl", spkg="pplpy", type="standard")) lazy_import('ppl', ['ray', 'point'], as_=['PPL_ray', 'PPL_point'], - feature=PythonModule("ppl", spkg="pplpy")) + feature=PythonModule("ppl", spkg="pplpy", type="standard")) def is_Cone(x): @@ -572,9 +574,9 @@ def _ambient_space_point(body, data): (1, 1/3) sage: _ambient_space_point(c, vector(QQ,[1,1/3])) (1, 1/3) - sage: _ambient_space_point(c, [1/2,1/sqrt(3)]) + sage: _ambient_space_point(c, [1/2, 1/sqrt(3)]) # needs sage.rings.number_field sage.symbolic (1/2, 0.5773502691896258?) - sage: _ambient_space_point(c, vector(AA,[1/2,1/sqrt(3)])) + sage: _ambient_space_point(c, vector(AA, [1/2, 1/sqrt(3)])) # needs sage.rings.number_field sage.symbolic (1/2, 0.5773502691896258?) sage: _ambient_space_point(c, [1,1,3]) Traceback (most recent call last): @@ -592,9 +594,9 @@ def _ambient_space_point(body, data): sage: from sage.geometry.cone import _ambient_space_point sage: c = Cone([(1,0), (0,1)]) - sage: _ambient_space_point(c, [1, pi]) + sage: _ambient_space_point(c, [1, pi]) # needs sage.rings.number_field sage.symbolic (1.00000000000000, 3.14159265358979) - sage: _ambient_space_point(c, vector(SR,[1, pi])) + sage: _ambient_space_point(c, vector(SR,[1, pi])) # needs sage.rings.number_field sage.symbolic (1.00000000000000, 3.14159265358979) """ @@ -844,7 +846,7 @@ def __richcmp__(self, right, op): sage: c2 is c3 False """ - if type(self) != type(right): + if type(self) is not type(right): return NotImplemented # We probably do need to have explicit comparison of lattices here @@ -1005,7 +1007,7 @@ def ambient_vector_space(self, base_field=None): sage: c = Cone([(1,0)]) sage: c.ambient_vector_space() Vector space of dimension 2 over Rational Field - sage: c.ambient_vector_space(AA) + sage: c.ambient_vector_space(AA) # needs sage.rings.number_field Vector space of dimension 2 over Algebraic Real Field """ return self.lattice().vector_space(base_field=base_field) @@ -1098,7 +1100,7 @@ def plot(self, **options): EXAMPLES:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: quadrant.plot() # optional - sage.plot + sage: quadrant.plot() # needs sage.plot Graphics object consisting of 9 graphics primitives """ tp = ToricPlotter(options, self.lattice().degree(), self.rays()) @@ -1601,7 +1603,7 @@ def __getstate__(self): TESTS:: sage: C = Cone([(1,0)]) - sage: C.face_lattice() + sage: C.face_lattice() # needs sage.combinat sage.graphs Finite lattice containing 2 elements with distinguished linear extension sage: C._test_pickling() sage: C2 = loads(dumps(C)); C2 @@ -1674,17 +1676,17 @@ def _contains(self, point, region='whole cone'): We can test vectors with irrational components:: sage: c = Cone([(1,0), (0,1)]) - sage: c._contains((1,sqrt(2))) + sage: c._contains((1, sqrt(2))) # needs sage.symbolic True - sage: c._contains(vector(SR, [1,pi])) + sage: c._contains(vector(SR, [1, pi])) # needs sage.symbolic True Ensure that complex vectors are not contained in a real cone:: sage: c = Cone([(1,0), (0,1)]) - sage: c._contains((1,I)) + sage: c._contains((1,I)) # needs sage.symbolic False - sage: c._contains(vector(QQbar,[1,I])) + sage: c._contains(vector(QQbar, [1,I])) # needs sage.rings.number_field sage.symbolic False And we refuse to coerce elements of another lattice into ours:: @@ -1971,7 +1973,7 @@ def _latex_(self): sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant._latex_() '\\sigma^{2}' - sage: quadrant.facets()[0]._latex_() + sage: quadrant.facets()[0]._latex_() # needs sage.graphs '\\sigma^{1} \\subset \\sigma^{2}' """ if self.ambient() is self: @@ -1995,7 +1997,7 @@ def _repr_(self): '2-d cone in 2-d lattice N' sage: quadrant 2-d cone in 2-d lattice N - sage: quadrant.facets()[0] + sage: quadrant.facets()[0] # needs sage.graphs 1-d face of 2-d cone in 2-d lattice N """ result = "%d-d" % self.dim() @@ -2051,7 +2053,7 @@ def _sort_faces(self, faces): sage: octant = Cone(identity_matrix(3).columns()) sage: # indirect doctest - sage: for i, face in enumerate(octant.faces(1)): + sage: for i, face in enumerate(octant.faces(1)): # needs sage.graphs ....: if face.ray(0) != octant.ray(i): ....: print("Wrong order!") """ @@ -2095,6 +2097,7 @@ def adjacent(self): EXAMPLES:: + sage: # needs sage.graphs sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)]) sage: octant.adjacent() () @@ -2111,7 +2114,7 @@ def adjacent(self): sage: fan = Fan(cones=[(0,1), (1,2)], ....: rays=[(1,0), (0,1), (-1,0)]) sage: cone = fan.generating_cone(0) - sage: len(cone.adjacent()) + sage: len(cone.adjacent()) # needs sage.graphs 1 The second generating cone is adjacent to this one. Now we create the @@ -2120,7 +2123,7 @@ def adjacent(self): sage: fan = Fan(cones=[(0,1), (1,2)], ....: rays=[(1,0,0), (0,1,0), (-1,0,0)]) sage: cone = fan.generating_cone(0) - sage: len(cone.adjacent()) + sage: len(cone.adjacent()) # needs sage.graphs 1 The result is as before, since we still have:: @@ -2133,7 +2136,7 @@ def adjacent(self): sage: fan = Fan(cones=[(0,1), (1,2), (3,)], ....: rays=[(1,0,0), (0,1,0), (-1,0,0), (0,0,1)]) sage: cone = fan.generating_cone(0) - sage: len(cone.adjacent()) + sage: len(cone.adjacent()) # needs sage.graphs 0 Since now ``cone`` has smaller dimension than ``fan``, it and its @@ -2176,6 +2179,8 @@ def ambient(self): 3-d cone in 3-d lattice N sage: cone.ambient() is cone True + + sage: # needs sage.graphs sage: face = cone.faces(1)[0] sage: face 1-d face of 3-d cone in 3-d lattice N @@ -2199,7 +2204,7 @@ def ambient_ray_indices(self): sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.ambient_ray_indices() (0, 1) - sage: quadrant.facets()[1].ambient_ray_indices() + sage: quadrant.facets()[1].ambient_ray_indices() # needs sage.graphs (1,) """ return self._ambient_ray_indices @@ -2232,15 +2237,15 @@ def contains(self, *args): True sage: c.contains((-1,0)) False - sage: c.contains(c.dual_lattice()(1,0)) #random output (warning) + sage: c.contains(c.dual_lattice()(1,0)) # random output (warning) False sage: c.contains(c.dual_lattice()(1,0)) False sage: c.contains(1) False - sage: c.contains(1/2, sqrt(3)) + sage: c.contains(1/2, sqrt(3)) # needs sage.symbolic True - sage: c.contains(-1/2, sqrt(3)) + sage: c.contains(-1/2, sqrt(3)) # needs sage.symbolic False """ point = flatten(args) @@ -2369,7 +2374,7 @@ def embed(self, cone): 1-d cone in 3-d lattice N sage: ray.ambient_ray_indices() (0,) - sage: ray.adjacent() + sage: ray.adjacent() # needs sage.graphs () sage: ray.ambient() 1-d cone in 3-d lattice N @@ -2377,6 +2382,7 @@ def embed(self, cone): If we want to operate with this ray as a face of the cone, we need to embed it first:: + sage: # needs sage.graphs sage: e_ray = c.embed(ray) sage: e_ray 1-d face of 3-d cone in 3-d lattice N @@ -2402,7 +2408,7 @@ def embed(self, cone): ... ValueError: 1-d cone in 3-d lattice N is not a face of 3-d cone in 3-d lattice N! - sage: c.embed(Cone([(1,0,1), (-1,0,1)])) + sage: c.embed(Cone([(1,0,1), (-1,0,1)])) # needs sage.graphs Traceback (most recent call last): ... ValueError: 2-d cone in 3-d lattice N is not a face @@ -2447,13 +2453,13 @@ def face_lattice(self): Let's take a look at the face lattice of the first quadrant:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: L = quadrant.face_lattice() - sage: L + sage: L = quadrant.face_lattice() # needs sage.combinat sage.graphs + sage: L # needs sage.combinat sage.graphs Finite lattice containing 4 elements with distinguished linear extension To see all faces arranged by dimension, you can do this:: - sage: for level in L.level_sets(): print(level) + sage: for level in L.level_sets(): print(level) # needs sage.combinat sage.graphs [0-d face of 2-d cone in 2-d lattice N] [1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N] @@ -2461,15 +2467,15 @@ def face_lattice(self): For a particular face you can look at its actual rays... :: - sage: face = L.level_sets()[1][0] - sage: face.rays() + sage: face = L.level_sets()[1][0] # needs sage.combinat sage.graphs + sage: face.rays() # needs sage.combinat sage.graphs N(1, 0) in 2-d lattice N ... or you can see the index of the ray of the original cone that corresponds to the above one:: - sage: face.ambient_ray_indices() + sage: face.ambient_ray_indices() # needs sage.combinat sage.graphs (0,) sage: quadrant.ray(0) N(1, 0) @@ -2477,21 +2483,22 @@ def face_lattice(self): An alternative to extracting faces from the face lattice is to use :meth:`faces` method:: - sage: face is quadrant.faces(dim=1)[0] + sage: face is quadrant.faces(dim=1)[0] # needs sage.combinat sage.graphs True The advantage of working with the face lattice directly is that you can (relatively easily) get faces that are related to the given one:: - sage: face = L.level_sets()[1][0] - sage: D = L.hasse_diagram() - sage: sorted(D.neighbors(face)) + sage: face = L.level_sets()[1][0] # needs sage.combinat sage.graphs + sage: D = L.hasse_diagram() # needs sage.combinat sage.graphs + sage: sorted(D.neighbors(face)) # needs sage.combinat sage.graphs [0-d face of 2-d cone in 2-d lattice N, 2-d cone in 2-d lattice N] However, you can achieve some of this functionality using :meth:`facets`, :meth:`facet_of`, and :meth:`adjacent` methods:: + sage: # needs sage.graphs sage: face = quadrant.faces(1)[0] sage: face 1-d face of 2-d cone in 2-d lattice N @@ -2511,6 +2518,7 @@ def face_lattice(self): Note that if ``cone`` is a face of ``supercone``, then the face lattice of ``cone`` consists of (appropriate) faces of ``supercone``:: + sage: # needs sage.combinat sage.graphs sage: supercone = Cone([(1,2,3,4), (5,6,7,8), ....: (1,2,4,8), (1,3,9,7)]) sage: supercone.face_lattice() @@ -2542,19 +2550,19 @@ def face_lattice(self): to have non identical face lattices, even if the faces themselves are equal (see :trac:`10998`):: - sage: C1.face_lattice() is C2.face_lattice() + sage: C1.face_lattice() is C2.face_lattice() # needs sage.combinat sage.graphs False - sage: C1.facets()[0] + sage: C1.facets()[0] # needs sage.graphs 0-d face of 1-d cone in 2-d lattice N - sage: C2.facets()[0] + sage: C2.facets()[0] # needs sage.graphs 0-d face of 1-d cone in 2-d lattice N - sage: C1.facets()[0].ambient() is C1 + sage: C1.facets()[0].ambient() is C1 # needs sage.graphs True - sage: C2.facets()[0].ambient() is C1 + sage: C2.facets()[0].ambient() is C1 # needs sage.graphs False - sage: C2.facets()[0].ambient() is C2 + sage: C2.facets()[0].ambient() is C2 # needs sage.graphs True """ if "_face_lattice" not in self.__dict__: @@ -2680,40 +2688,41 @@ def faces(self, dim=None, codim=None): Let's take a look at the faces of the first quadrant:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: quadrant.faces() + sage: quadrant.faces() # needs sage.graphs ((0-d face of 2-d cone in 2-d lattice N,), (1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N), (2-d cone in 2-d lattice N,)) - sage: quadrant.faces(dim=1) + sage: quadrant.faces(dim=1) # needs sage.graphs (1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N) - sage: face = quadrant.faces(dim=1)[0] + sage: face = quadrant.faces(dim=1)[0] # needs sage.graphs Now you can look at the actual rays of this face... :: - sage: face.rays() + sage: face.rays() # needs sage.graphs N(1, 0) in 2-d lattice N ... or you can see indices of the rays of the original cone that correspond to the above ray:: - sage: face.ambient_ray_indices() + sage: face.ambient_ray_indices() # needs sage.graphs (0,) sage: quadrant.ray(0) N(1, 0) Note that it is OK to ask for faces of too small or high dimension:: - sage: quadrant.faces(-1) + sage: quadrant.faces(-1) # needs sage.graphs () - sage: quadrant.faces(3) + sage: quadrant.faces(3) # needs sage.graphs () In the case of non-strictly convex cones even faces of small non-negative dimension may be missing:: + sage: # needs sage.graphs sage: halfplane = Cone([(1,0), (0,1), (-1,0)]) sage: halfplane.faces(0) () @@ -2732,7 +2741,7 @@ def faces(self, dim=None, codim=None): dimension of the ambient space work as expected (see :trac:`9188`):: sage: c = Cone([(1,1,1,3),(1,-1,1,3),(-1,-1,1,3)]) - sage: c.faces() + sage: c.faces() # needs sage.graphs ((0-d face of 3-d cone in 4-d lattice N,), (1-d face of 3-d cone in 4-d lattice N, 1-d face of 3-d cone in 4-d lattice N, @@ -2745,16 +2754,17 @@ def faces(self, dim=None, codim=None): We also ensure that a call to this function does not break :meth:`facets` method (see :trac:`9780`):: - sage: cone = toric_varieties.dP8().fan().generating_cone(0); cone # optional - palp + sage: # needs palp sage.graphs + sage: cone = toric_varieties.dP8().fan().generating_cone(0); cone 2-d cone of Rational polyhedral fan in 2-d lattice N - sage: for f in cone.facets(): print(f.rays()) # optional - palp + sage: for f in cone.facets(): print(f.rays()) N(1, 1) in 2-d lattice N N(0, 1) in 2-d lattice N - sage: len(cone.faces()) # optional - palp + sage: len(cone.faces()) 3 - sage: for f in cone.facets(): print(f.rays()) # optional - palp + sage: for f in cone.facets(): print(f.rays()) N(1, 1) in 2-d lattice N N(0, 1) @@ -2900,6 +2910,7 @@ def facet_of(self): EXAMPLES:: + sage: # needs sage.graphs sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)]) sage: octant.facet_of() () @@ -2912,14 +2923,14 @@ def facet_of(self): While fan is the top element of its own cone lattice, which is a variant of a face lattice, we do not refer to cones as its facets:: - sage: fan = Fan([octant]) - sage: fan.generating_cone(0).facet_of() + sage: fan = Fan([octant]) # needs sage.graphs + sage: fan.generating_cone(0).facet_of() # needs sage.graphs () Subcones of generating cones work as before:: - sage: one_cone = fan(1)[0] - sage: len(one_cone.facet_of()) + sage: one_cone = fan(1)[0] # needs sage.graphs + sage: len(one_cone.facet_of()) # needs sage.graphs 2 """ L = self._ambient._face_lattice_function() @@ -2938,7 +2949,7 @@ def facets(self): EXAMPLES:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: quadrant.facets() + sage: quadrant.facets() # needs sage.graphs (1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N) """ @@ -3257,10 +3268,10 @@ def is_isomorphic(self, other): We check that :trac:`18613` is fixed:: sage: K = cones.trivial(0) - sage: K.is_isomorphic(K) + sage: K.is_isomorphic(K) # needs sage.graphs True sage: K = cones.trivial(1) - sage: K.is_isomorphic(K) + sage: K.is_isomorphic(K) # needs sage.graphs True sage: K = cones.trivial(2) sage: K.is_isomorphic(K) @@ -3269,7 +3280,7 @@ def is_isomorphic(self, other): A random (strictly convex) cone is isomorphic to itself:: sage: K = random_cone(max_ambient_dim=6, strictly_convex=True) - sage: K.is_isomorphic(K) + sage: K.is_isomorphic(K) # needs sage.graphs True """ if self.is_strictly_convex() and other.is_strictly_convex(): @@ -3484,7 +3495,7 @@ def plot(self, **options): EXAMPLES:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: quadrant.plot() # optional - sage.plot + sage: quadrant.plot() # needs sage.plot Graphics object consisting of 9 graphics primitives """ # What to do with 3-d cones in 5-d? Use some projection method? @@ -3754,7 +3765,7 @@ def solid_restriction(self): the original:: sage: K = random_cone(max_ambient_dim=6) - sage: len(K.solid_restriction().facets()) == len(K.facets()) + sage: len(K.solid_restriction().facets()) == len(K.facets()) # needs sage.graphs True """ if self.is_solid(): @@ -3915,7 +3926,8 @@ def sublattice_quotient(self, *args, **kwds): EXAMPLES:: - sage: C2_Z2 = Cone([(1,0),(1,2)]) # C^2/Z_2 + sage: # needs sage.graphs + sage: C2_Z2 = Cone([(1,0), (1,2)]) # C^2/Z_2 sage: c1, c2 = C2_Z2.facets() sage: c2.sublattice_quotient() 1-d lattice, quotient of 2-d lattice N by Sublattice <N(1, 2)> @@ -3967,11 +3979,11 @@ def sublattice_complement(self, *args, **kwds): EXAMPLES:: - sage: C2_Z2 = Cone([(1,0),(1,2)]) # C^2/Z_2 - sage: c1, c2 = C2_Z2.facets() - sage: c2.sublattice() + sage: C2_Z2 = Cone([(1,0), (1,2)]) # C^2/Z_2 + sage: c1, c2 = C2_Z2.facets() # needs sage.graphs + sage: c2.sublattice() # needs sage.graphs Sublattice <N(1, 2)> - sage: c2.sublattice_complement() + sage: c2.sublattice_complement() # needs sage.graphs Sublattice <N(0, 1)> A more complicated example:: @@ -4197,7 +4209,8 @@ def relative_orthogonal_quotient(self, supercone): EXAMPLES:: - sage: rho = Cone([(1,1,1,3),(1,-1,1,3),(-1,-1,1,3),(-1,1,1,3)]) + sage: # needs sage.graphs + sage: rho = Cone([(1,1,1,3), (1,-1,1,3), (-1,-1,1,3), (-1,1,1,3)]) sage: rho.orthogonal_sublattice() Sublattice <M(0, 0, 3, -1)> sage: sigma = rho.facets()[1] @@ -4214,6 +4227,7 @@ def relative_orthogonal_quotient(self, supercone): Different codimension:: + sage: # needs sage.graphs sage: rho = Cone([[1,-1,1,3],[-1,-1,1,3]]) sage: sigma = rho.facets()[0] sage: sigma.orthogonal_sublattice() @@ -4280,7 +4294,7 @@ def semigroup_generators(self): We start with a simple case of a non-smooth 2-dimensional cone:: - sage: Cone([ (1,0), (1,2) ]).semigroup_generators() + sage: Cone([(1,0), (1,2)]).semigroup_generators() N(1, 1), N(1, 0), N(1, 2) @@ -4294,19 +4308,19 @@ def semigroup_generators(self): GAP's toric package thinks this is challenging:: - sage: cone = Cone([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]]).dual() - sage: len( cone.semigroup_generators() ) + sage: cone = Cone([[1,2,3,4], [0,1,0,7], [3,1,0,2], [0,0,1,0]]).dual() + sage: len(cone.semigroup_generators()) 2806 The cone need not be strictly convex:: - sage: halfplane = Cone([(1,0),(2,1),(-1,0)]) + sage: halfplane = Cone([(1,0), (2,1), (-1,0)]) sage: sorted(halfplane.semigroup_generators()) [N(-1, 0), N(0, 1), N(1, 0)] - sage: line = Cone([(1,1,1),(-1,-1,-1)]) + sage: line = Cone([(1,1,1), (-1,-1,-1)]) sage: sorted(line.semigroup_generators()) [N(-1, -1, -1), N(1, 1, 1)] - sage: wedge = Cone([ (1,0,0), (1,2,0), (0,0,1), (0,0,-1) ]) + sage: wedge = Cone([(1,0,0), (1,2,0), (0,0,1), (0,0,-1)]) sage: sorted(wedge.semigroup_generators()) [N(0, 0, -1), N(0, 0, 1), N(1, 0, 0), N(1, 1, 0), N(1, 2, 0)] @@ -4324,14 +4338,14 @@ def semigroup_generators(self): sage: A.elementary_divisors() [1, 1, 1, 0] sage: cone3d = Cone([(3,0,-1), (1,-1,0), (0,1,0), (0,0,1)]) - sage: rays = ( A*vector(v) for v in cone3d.rays() ) + sage: rays = (A*vector(v) for v in cone3d.rays()) sage: gens = Cone(rays).semigroup_generators(); sorted(gens) [N(-2, -1, 0, 17), N(0, 1, -2, 0), N(1, -1, 1, 15), N(3, -4, 5, 45), N(3, 0, 1, -2)] - sage: set(map(tuple,gens)) == set( tuple(A*r) for r in cone3d.semigroup_generators() ) + sage: set(map(tuple,gens)) == set(tuple(A*r) for r in cone3d.semigroup_generators()) True TESTS:: @@ -4425,7 +4439,7 @@ def Hilbert_basis(self): We start with a simple case of a non-smooth 2-dimensional cone:: - sage: Cone([ (1,0), (1,2) ]).Hilbert_basis() + sage: Cone([(1,0), (1,2)]).Hilbert_basis() N(1, 0), N(1, 2), N(1, 1) @@ -4433,14 +4447,14 @@ def Hilbert_basis(self): Two more complicated example from GAP/toric:: - sage: Cone([[1,0],[3,4]]).dual().Hilbert_basis() + sage: Cone([[1,0], [3,4]]).dual().Hilbert_basis() M(0, 1), M(4, -3), M(1, 0), M(2, -1), M(3, -2) in 2-d lattice M - sage: cone = Cone([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]]).dual() + sage: cone = Cone([[1,2,3,4], [0,1,0,7], [3,1,0,2], [0,0,1,0]]).dual() sage: cone.Hilbert_basis() # long time M(10, -7, 0, 1), M(-5, 21, 0, -3), @@ -4475,7 +4489,7 @@ def Hilbert_basis(self): Not a strictly convex cone:: - sage: wedge = Cone([ (1,0,0), (1,2,0), (0,0,1), (0,0,-1) ]) + sage: wedge = Cone([(1,0,0), (1,2,0), (0,0,1), (0,0,-1)]) sage: sorted(wedge.semigroup_generators()) [N(0, 0, -1), N(0, 0, 1), N(1, 0, 0), N(1, 1, 0), N(1, 2, 0)] sage: wedge.Hilbert_basis() @@ -4573,7 +4587,7 @@ def Hilbert_coefficients(self, point, solver=None, verbose=0, EXAMPLES:: - sage: cone = Cone([(1,0),(0,1)]) + sage: cone = Cone([(1,0), (0,1)]) sage: cone.rays() N(1, 0), N(0, 1) @@ -4584,19 +4598,19 @@ def Hilbert_coefficients(self, point, solver=None, verbose=0, A more complicated example:: sage: N = ToricLattice(2) - sage: cone = Cone([N(1,0),N(1,2)]) + sage: cone = Cone([N(1,0), N(1,2)]) sage: cone.Hilbert_basis() N(1, 0), N(1, 2), N(1, 1) in 2-d lattice N - sage: cone.Hilbert_coefficients( N(1,1) ) + sage: cone.Hilbert_coefficients(N(1,1)) (0, 0, 1) The cone need not be strictly convex:: sage: N = ToricLattice(3) - sage: cone = Cone([N(1,0,0),N(1,2,0),N(0,0,1),N(0,0,-1)]) + sage: cone = Cone([N(1,0,0), N(1,2,0), N(0,0,1), N(0,0,-1)]) sage: cone.Hilbert_basis() N(1, 2, 0), N(1, 0, 0), @@ -4604,7 +4618,7 @@ def Hilbert_coefficients(self, point, solver=None, verbose=0, N(0, 0, -1), N(1, 1, 0) in 3-d lattice N - sage: cone.Hilbert_coefficients( N(1,1,3) ) + sage: cone.Hilbert_coefficients(N(1,1,3)) (0, 0, 3, 0, 1) """ point = self.lattice()(point) @@ -4663,7 +4677,7 @@ def is_solid(self): A closed convex cone is solid if and only if its dual is strictly convex:: - sage: K = random_cone(max_ambient_dim = 8) + sage: K = random_cone(max_ambient_dim=8) sage: K.is_solid() == K.dual().is_strictly_convex() True """ @@ -4710,7 +4724,7 @@ def is_proper(self): Likewise, a half-space contains at least one line, so it is not proper:: - sage: halfspace = Cone([(1,0),(0,1),(-1,0)]) + sage: halfspace = Cone([(1,0), (0,1), (-1,0)]) sage: halfspace.is_proper() False @@ -4746,14 +4760,14 @@ def is_full_space(self): The right half-space contains a vector subspace, but it is still not equal to the entire space:: - sage: K = Cone([(1,0),(-1,0),(0,1)]) + sage: K = Cone([(1,0), (-1,0), (0,1)]) sage: K.is_full_space() False However, if we allow conic combinations of both axes, then the resulting cone is the entire two-dimensional space:: - sage: K = Cone([(1,0),(-1,0),(0,1),(0,-1)]) + sage: K = Cone([(1,0), (-1,0), (0,1), (0,-1)]) sage: K.is_full_space() True @@ -4817,7 +4831,7 @@ def lineality(self): The lineality of a cone should be an integer between zero and the dimension of the ambient space, inclusive:: - sage: K = random_cone(max_ambient_dim = 8) + sage: K = random_cone(max_ambient_dim=8) sage: l = K.lineality() sage: l in ZZ True @@ -4826,7 +4840,7 @@ def lineality(self): A strictly convex cone should have lineality zero:: - sage: K = random_cone(max_ambient_dim = 8, strictly_convex = True) + sage: K = random_cone(max_ambient_dim=8, strictly_convex=True) sage: K.lineality() 0 """ @@ -4904,7 +4918,7 @@ def discrete_complementarity_set(self): When a cone is the entire space, its dual is the trivial cone, so the only discrete complementarity set for it is empty:: - sage: K = Cone([(1,0),(-1,0),(0,1),(0,-1)]) + sage: K = Cone([(1,0), (-1,0), (0,1), (0,-1)]) sage: K.is_full_space() True sage: K.discrete_complementarity_set() @@ -4923,7 +4937,7 @@ def discrete_complementarity_set(self): sage: K = random_cone(max_ambient_dim=6) sage: dcs_dual = K.dual().discrete_complementarity_set() - sage: expected = tuple( (x,s) for (s,x) in dcs_dual ) + sage: expected = tuple((x,s) for (s,x) in dcs_dual) sage: actual = K.discrete_complementarity_set() sage: sorted(actual) == sorted(expected) True @@ -4933,7 +4947,7 @@ def discrete_complementarity_set(self): sage: K = random_cone(max_ambient_dim=6) sage: dcs = K.discrete_complementarity_set() - sage: sum( (s*x).abs() for (x,s) in dcs ) + sage: sum((s*x).abs() for (x,s) in dcs) 0 """ # Return an immutable tuple instead of a mutable list because @@ -5042,7 +5056,7 @@ def lyapunov_like_basis(self): sage: K = random_cone(max_ambient_dim=8) sage: LL = K.lyapunov_like_basis() - sage: all( L.is_lyapunov_like_on(K) for L in LL ) + sage: all(L.is_lyapunov_like_on(K) for L in LL) True The Lyapunov-like transformations on a cone and its dual are @@ -5053,8 +5067,8 @@ def lyapunov_like_basis(self): sage: LL1 = K.lyapunov_like_basis() sage: LL2 = (L.transpose() for L in K.dual().lyapunov_like_basis()) sage: V = VectorSpace(K.lattice().base_field(), K.lattice_dim()^2) - sage: LL1_vecs = ( V(m.list()) for m in LL1 ) - sage: LL2_vecs = ( V(m.list()) for m in LL2 ) + sage: LL1_vecs = (V(m.list()) for m in LL1) + sage: LL2_vecs = (V(m.list()) for m in LL2) sage: V.span(LL1_vecs) == V.span(LL2_vecs) True @@ -5065,9 +5079,9 @@ def lyapunov_like_basis(self): sage: LL = K.lyapunov_like_basis() sage: W = VectorSpace(K.lattice().base_field(), K.lattice_dim()**2) sage: LL_W = W.span( W(m.list()) for m in LL ) - sage: brackets = ( W((L1*L2 - L2*L1).list()) for L1 in LL - ....: for L2 in LL ) - sage: all( b in LL_W for b in brackets ) + sage: brackets = (W((L1*L2 - L2*L1).list()) for L1 in LL + ....: for L2 in LL) + sage: all(b in LL_W for b in brackets) True """ # Matrices are not vectors in Sage, so we have to convert them @@ -5149,7 +5163,7 @@ def lyapunov_rank(self): [Or2017]_:: sage: Q5 = VectorSpace(QQ, 5) - sage: gs = Q5.basis() + [ -r for r in Q5.basis() ] + sage: gs = Q5.basis() + [-r for r in Q5.basis()] sage: K = Cone(gs) sage: K.lyapunov_rank() 25 @@ -5229,7 +5243,7 @@ def lyapunov_rank(self): sage: K1 = random_cone(max_ambient_dim=8) sage: n = K1.lattice_dim() sage: A = random_matrix(QQ, n, algorithm='unimodular') - sage: K2 = Cone( ( A*r for r in K1 ), lattice=K1.lattice()) + sage: K2 = Cone((A*r for r in K1), lattice=K1.lattice()) sage: K1.lyapunov_rank() == K2.lyapunov_rank() True @@ -5286,7 +5300,7 @@ def lyapunov_rank(self): sage: K = random_cone(max_ambient_dim=8) sage: L = ToricLattice(K.lattice_dim() + 1) - sage: K = Cone([ r.list() + [0] for r in K ], lattice=L) + sage: K = Cone([r.list() + [0] for r in K], lattice=L) sage: K.lyapunov_rank() >= K.lattice_dim() True """ @@ -5360,14 +5374,14 @@ def random_element(self, ring=ZZ): components nonnegative:: sage: K = cones.nonnegative_orthant(3) - sage: all( x >= 0 for x in K.random_element() ) + sage: all(x >= 0 for x in K.random_element()) True - sage: all( x >= 0 for x in K.random_element(ring=QQ) ) + sage: all(x >= 0 for x in K.random_element(ring=QQ)) True If ``ring`` is not ``ZZ`` or ``QQ``, an error is raised:: - sage: K = Cone([(1,0),(0,1)]) + sage: K = Cone([(1,0), (0,1)]) sage: K.random_element(ring=RR) Traceback (most recent call last): ... @@ -5516,7 +5530,7 @@ def positive_operators_gens(self, K2=None): sage: K.positive_operators_gens() [[1]] - sage: K = Cone([(1,0),(0,1)]) + sage: K = Cone([(1,0), (0,1)]) sage: K.positive_operators_gens() [ [1 0] [0 1] [0 0] [0 0] @@ -5546,13 +5560,13 @@ def positive_operators_gens(self, K2=None): Every operator is positive on the ambient vector space:: - sage: K = Cone([(1,),(-1,)]) + sage: K = Cone([(1,), (-1,)]) sage: K.is_full_space() True sage: K.positive_operators_gens() [[1], [-1]] - sage: K = Cone([(1,0),(-1,0),(0,1),(0,-1)]) + sage: K = Cone([(1,0), (-1,0), (0,1), (0,-1)]) sage: K.is_full_space() True sage: K.positive_operators_gens() @@ -5564,7 +5578,7 @@ def positive_operators_gens(self, K2=None): A non-obvious application is to find the positive operators on the right half-plane [Or2018b]_:: - sage: K = Cone([(1,0),(0,1),(0,-1)]) + sage: K = Cone([(1,0), (0,1), (0,-1)]) sage: K.positive_operators_gens() [ [1 0] [0 0] [ 0 0] [0 0] [ 0 0] @@ -5580,7 +5594,7 @@ def positive_operators_gens(self, K2=None): sage: K2 = random_cone(max_ambient_dim=3) sage: pi_gens = K1.positive_operators_gens(K2) sage: L = ToricLattice(K1.lattice_dim() * K2.lattice_dim()) - sage: pi_cone = Cone(( g.list() for g in pi_gens ), + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: P = matrix(K2.lattice_dim(), @@ -5596,16 +5610,16 @@ def positive_operators_gens(self, K2=None): sage: K = random_cone(max_ambient_dim=3) sage: pi_gens = K.positive_operators_gens() sage: L = ToricLattice(K.lattice_dim()**2) - sage: pi_cone = Cone(( g.list() for g in pi_gens ), + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: actual = pi_cone.dual().linear_subspace() - sage: U1 = [ vector((s.tensor_product(x)).list()) - ....: for x in K.lines() - ....: for s in K.dual() ] - sage: U2 = [ vector((s.tensor_product(x)).list()) - ....: for x in K - ....: for s in K.dual().lines() ] + sage: U1 = [vector((s.tensor_product(x)).list()) + ....: for x in K.lines() + ....: for s in K.dual()] + sage: U2 = [vector((s.tensor_product(x)).list()) + ....: for x in K + ....: for s in K.dual().lines()] sage: expected = pi_cone.lattice().vector_space().span(U1+U2) sage: actual == expected True @@ -5667,7 +5681,7 @@ def positive_operators_gens(self, K2=None): sage: pi_cone.dim() == n^2 True - sage: K = Cone([(1,0),(0,1),(0,-1)]) + sage: K = Cone([(1,0), (0,1), (0,-1)]) sage: pi_gens = K.positive_operators_gens() sage: pi_cone = Cone((g.list() for g in pi_gens), ....: check=False) @@ -5712,7 +5726,7 @@ def positive_operators_gens(self, K2=None): sage: pi_cone.lineality() == n^2 True - sage: K = Cone([(1,0),(0,1),(0,-1)]) + sage: K = Cone([(1,0), (0,1), (0,-1)]) sage: pi_gens = K.positive_operators_gens() sage: pi_cone = Cone((g.list() for g in pi_gens), check=False) sage: pi_cone.lineality() == 2 @@ -5733,10 +5747,11 @@ def positive_operators_gens(self, K2=None): The positive operators on a permuted cone can be obtained by conjugation:: + sage: # needs sage.groups sage: K = random_cone(max_ambient_dim=3) sage: L = ToricLattice(K.lattice_dim()**2) sage: p = SymmetricGroup(K.lattice_dim()).random_element().matrix() - sage: pK = Cone(( p*k for k in K ), K.lattice(), check=False) + sage: pK = Cone((p*k for k in K), K.lattice(), check=False) sage: pi_gens = pK.positive_operators_gens() sage: actual = Cone((g.list() for g in pi_gens), ....: lattice=L, @@ -5813,16 +5828,16 @@ def positive_operators_gens(self, K2=None): sage: L = ToricLattice(m*n) sage: M1 = MatrixSpace(F, m, m) sage: M2 = MatrixSpace(F, n, n) - sage: tps = ( M2(s.list()).tensor_product(M1(x.list())) - ....: for x in K1.dual().lyapunov_like_basis() - ....: for s in K2.lyapunov_like_basis() ) + sage: tps = (M2(s.list()).tensor_product(M1(x.list())) + ....: for x in K1.dual().lyapunov_like_basis() + ....: for s in K2.lyapunov_like_basis()) sage: W = VectorSpace(F, (m**2)*(n**2)) - sage: expected = span(F, ( W(x.list()) for x in tps )) + sage: expected = span(F, (W(x.list()) for x in tps)) sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: LL_pi = pi_cone.lyapunov_like_basis() - sage: actual = span(F, ( W(x.list()) for x in LL_pi )) + sage: actual = span(F, (W(x.list()) for x in LL_pi)) sage: actual == expected True """ @@ -5922,11 +5937,11 @@ def cross_positive_operators_gens(self): [0 1] [0 0] [1 0] [-1 0] [0 0] [ 0 0] [0 0], [1 0], [0 0], [ 0 0], [0 1], [ 0 -1] ] - sage: K = Cone([(1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1)]) - sage: all( c[i][j] >= 0 for c in K.cross_positive_operators_gens() - ....: for i in range(c.nrows()) - ....: for j in range(c.ncols()) - ....: if i != j ) + sage: K = Cone([(1,0,0,0), (0,1,0,0), (0,0,1,0), (0,0,0,1)]) + sage: all(c[i][j] >= 0 for c in K.cross_positive_operators_gens() + ....: for i in range(c.nrows()) + ....: for j in range(c.ncols()) + ....: if i != j) True The trivial cone in a trivial space has no cross-positive @@ -5939,13 +5954,13 @@ def cross_positive_operators_gens(self): Every operator is a cross-positive operator on the ambient vector space:: - sage: K = Cone([(1,),(-1,)]) + sage: K = Cone([(1,), (-1,)]) sage: K.is_full_space() True sage: K.cross_positive_operators_gens() [[1], [-1]] - sage: K = Cone([(1,0),(-1,0),(0,1),(0,-1)]) + sage: K = Cone([(1,0), (-1,0), (0,1), (0,-1)]) sage: K.is_full_space() True sage: K.cross_positive_operators_gens() @@ -5957,7 +5972,7 @@ def cross_positive_operators_gens(self): A non-obvious application is to find the cross-positive operators on the right half-plane [Or2018b]_:: - sage: K = Cone([(1,0),(0,1),(0,-1)]) + sage: K = Cone([(1,0), (0,1), (0,-1)]) sage: K.cross_positive_operators_gens() [ [1 0] [-1 0] [0 0] [ 0 0] [0 0] [ 0 0] @@ -5967,13 +5982,13 @@ def cross_positive_operators_gens(self): Cross-positive operators on a subspace are Lyapunov-like and vice-versa:: - sage: K = Cone([(1,0),(-1,0),(0,1),(0,-1)]) + sage: K = Cone([(1,0), (-1,0), (0,1), (0,-1)]) sage: K.is_full_space() True - sage: lls = span( vector(l.list()) - ....: for l in K.lyapunov_like_basis() ) - sage: cs = span( vector(c.list()) - ....: for c in K.cross_positive_operators_gens() ) + sage: lls = span(vector(l.list()) + ....: for l in K.lyapunov_like_basis()) + sage: cs = span(vector(c.list()) + ....: for c in K.cross_positive_operators_gens()) sage: cs == lls True @@ -5984,7 +5999,7 @@ def cross_positive_operators_gens(self): sage: K = random_cone(max_ambient_dim=3) sage: cp_gens = K.cross_positive_operators_gens() - sage: all( L.is_cross_positive_on(K) for L in cp_gens ) + sage: all(L.is_cross_positive_on(K) for L in cp_gens) True The lineality space of the cone of cross-positive operators is @@ -5994,10 +6009,10 @@ def cross_positive_operators_gens(self): sage: L = ToricLattice(K.lattice_dim()**2) sage: cp_gens = K.cross_positive_operators_gens() sage: cp_cone = Cone((g.list() for g in cp_gens), - ....: lattice=L, - ....: check=False) - sage: ll_basis = ( vector(l.list()) - ....: for l in K.lyapunov_like_basis() ) + ....: lattice=L, + ....: check=False) + sage: ll_basis = (vector(l.list()) + ....: for l in K.lyapunov_like_basis()) sage: lls = L.vector_space().span(ll_basis) sage: cp_cone.linear_subspace() == lls True @@ -6056,10 +6071,11 @@ def cross_positive_operators_gens(self): The cross-positive operators of a permuted cone can be obtained by conjugation:: + sage: # needs sage.groups sage: K = random_cone(max_ambient_dim=3) sage: L = ToricLattice(K.lattice_dim()**2) sage: p = SymmetricGroup(K.lattice_dim()).random_element().matrix() - sage: pK = Cone(( p*k for k in K ), K.lattice(), check=False) + sage: pK = Cone((p*k for k in K), K.lattice(), check=False) sage: cp_gens = pK.cross_positive_operators_gens() sage: actual = Cone((g.list() for g in cp_gens), ....: lattice=L, @@ -6173,7 +6189,7 @@ def Z_operators_gens(self): sage: K = random_cone(max_ambient_dim=3) sage: Z_gens = K.Z_operators_gens() - sage: all( L.is_Z_operator_on(K) for L in Z_gens ) + sage: all(L.is_Z_operator_on(K) for L in Z_gens) True """ return [ -cp for cp in self.cross_positive_operators_gens() ] @@ -6370,7 +6386,7 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, TESTS: It's hard to test the output of a random process, but we can at - least make sure that we get a cone back. + least make sure that we get a cone back:: sage: from sage.geometry.cone import is_Cone sage: K = random_cone(max_ambient_dim=6, max_rays=10) @@ -6458,9 +6474,9 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, we will loop with an absurd, unattainable, number of rays:: sage: K = random_cone(min_ambient_dim=3, # long time - ....: max_ambient_dim=3, # long time - ....: min_rays=7, # long time - ....: max_rays=9) # long time + ....: max_ambient_dim=3, + ....: min_rays=7, + ....: max_rays=9) sage: K.nrays() >= 7 # long time True sage: K.lattice_dim() # long time @@ -6477,7 +6493,7 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, It is an error to request a non-strictly-convex trivial cone:: - sage: L = ToricLattice(0,"L") + sage: L = ToricLattice(0, "L") sage: random_cone(lattice=L, strictly_convex=False) Traceback (most recent call last): ... @@ -6493,7 +6509,7 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, But fine to ask for a strictly convex trivial cone:: - sage: L = ToricLattice(0,"L") + sage: L = ToricLattice(0, "L") sage: random_cone(lattice=L, strictly_convex=True) 0-d cone in 0-d lattice L @@ -6566,19 +6582,19 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, # The next three checks prevent an infinite loop (a futile # search for more rays) in zero, one, or two dimensions. if min_rays > 4 and max_ambient_dim < 3: - msg = 'all cones in zero/one/two dimensions have four or fewer ' + msg = 'all cones in zero/one/two dimensions have four or fewer ' msg += 'generators. Please increase max_ambient_dim to at least ' msg += '3, or decrease min_rays.' raise ValueError(msg) if min_rays > 2 and max_ambient_dim < 2: - msg = 'all cones in zero/one dimensions have two or fewer ' + msg = 'all cones in zero/one dimensions have two or fewer ' msg += 'generators. Please increase max_ambient_dim to at least ' msg += '2, or decrease min_rays.' raise ValueError(msg) if min_rays > 0 and max_ambient_dim == 0: - msg = 'all cones in zero dimensions have no generators. ' + msg = 'all cones in zero dimensions have no generators. ' msg += 'Please increase max_ambient_dim to at least 1, or ' msg += 'decrease min_rays.' raise ValueError(msg) @@ -6593,17 +6609,17 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, # using its dimension rather than max_ambient_dim as the indicator. if lattice is not None: if min_rays > 4 and lattice.dimension() < 3: - msg = 'all cones in the given lattice have four or fewer ' + msg = 'all cones in the given lattice have four or fewer ' msg += 'generators. Please decrease min_rays.' raise ValueError(msg) if min_rays > 2 and lattice.dimension() < 2: - msg = 'all cones in the given lattice have two or fewer ' + msg = 'all cones in the given lattice have two or fewer ' msg += 'generators. Please decrease min_rays.' raise ValueError(msg) if min_rays > 0 and lattice.dimension() == 0: - msg = 'all cones in the given lattice have no generators. ' + msg = 'all cones in the given lattice have no generators. ' msg += 'Please decrease min_rays.' raise ValueError(msg) @@ -6613,7 +6629,7 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, msg = 'all cones in this lattice are strictly convex (trivial).' raise ValueError(msg) if max_rays is not None and max_rays < 2: - msg = 'all cones are strictly convex when ``max_rays`` is ' + msg = 'all cones are strictly convex when ``max_rays`` is ' msg += 'less than two.' raise ValueError(msg) @@ -6640,7 +6656,7 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, msg = 'all cones are solid when max_ambient_dim is zero.' raise ValueError(msg) if (max_ambient_dim is not None and - min_rays > 2*(max_ambient_dim - 1)): + min_rays > 2 * (max_ambient_dim - 1)): msg = 'every cone is solid when ' msg += 'min_rays > 2*(max_ambient_dim - 1).' raise ValueError(msg) @@ -6648,12 +6664,11 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, if lattice.dimension() == 0: msg = 'all cones in the given lattice are solid.' raise ValueError(msg) - if min_rays > 2*(lattice.dimension() - 1): + if min_rays > 2 * (lattice.dimension() - 1): msg = 'every cone is solid when min_rays > 2*(d - 1) ' msg += 'where d is the dimension of the given lattice.' raise ValueError(msg) - # Now that we've sanity-checked our parameters, we can massage the # min/maxes for (non-)solid cones. It doesn't violate the user's # expectation to increase a minimum, decrease a maximum, or fix an @@ -6780,7 +6795,6 @@ def is_valid(K): K = Cone(rays, lattice=L) rays = list(K.rays()) # Avoid re-normalizing next time around - if strictly_convex is not None: if strictly_convex: if not K.is_strictly_convex(): diff --git a/src/sage/geometry/cone_catalog.py b/src/sage/geometry/cone_catalog.py index a3d1ffa670f..d6898d40087 100644 --- a/src/sage/geometry/cone_catalog.py +++ b/src/sage/geometry/cone_catalog.py @@ -374,8 +374,8 @@ def rearrangement(p, ambient_dim=None, lattice=None): sage: ambient_dim = ZZ.random_element(2,10).abs() sage: p = ZZ.random_element(1, ambient_dim) sage: K = cones.rearrangement(p, ambient_dim) - sage: P = SymmetricGroup(ambient_dim).random_element().matrix() - sage: all( K.contains(P*r) for r in K ) + sage: P = SymmetricGroup(ambient_dim).random_element().matrix() # needs sage.groups + sage: all(K.contains(P*r) for r in K) # needs sage.groups True The smallest ``p`` components of every element of the rearrangement @@ -527,6 +527,7 @@ def schur(ambient_dim=None, lattice=None): generators of the Schur cone and the nonnegative orthant in dimension five is `\left(3/4\right)\pi`:: + sage: # needs sage.rings.number_fields sage: P = cones.schur(5) sage: Q = cones.nonnegative_orthant(5) sage: G = ( g.change_ring(QQbar).normalized() for g in P ) diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index 26d814fb437..258544012fe 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.graphs sage.combinat r""" Rational polyhedral fans @@ -196,11 +196,12 @@ We can also make ``fan3`` smooth, but it will take a bit more work:: + sage: # needs palp sage: cube = lattice_polytope.cross_polytope(3).polar() - sage: sk = cube.skeleton_points(2) # optional - palp - sage: rays = [cube.point(p) for p in sk] # optional - palp - sage: fan4 = fan3.subdivide(new_rays=rays) # optional - palp - sage: fan4.is_smooth() # optional - palp + sage: sk = cube.skeleton_points(2) + sage: rays = [cube.point(p) for p in sk] + sage: fan4 = fan3.subdivide(new_rays=rays) + sage: fan4.is_smooth() True Let's see how "different" are ``fan2`` and ``fan4``:: @@ -209,9 +210,9 @@ 6 sage: fan2.nrays() 8 - sage: fan4.ngenerating_cones() # optional - palp + sage: fan4.ngenerating_cones() # needs palp 48 - sage: fan4.nrays() # optional - palp + sage: fan4.nrays() # needs palp 26 Smoothness does not come for free! @@ -253,7 +254,7 @@ from sage.graphs.digraph import DiGraph from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method -from sage.misc.misc import walltime +from sage.misc.timing import walltime from sage.misc.misc_c import prod from sage.modules.free_module import span from sage.modules.free_module_element import vector @@ -261,7 +262,7 @@ from sage.rings.rational_field import QQ -def is_Fan(x): +def is_Fan(x) -> bool: r""" Check if ``x`` is a Fan. @@ -271,16 +272,16 @@ def is_Fan(x): OUTPUT: - - ``True`` if ``x`` is a fan and ``False`` otherwise. + ``True`` if ``x`` is a fan and ``False`` otherwise EXAMPLES:: sage: from sage.geometry.fan import is_Fan sage: is_Fan(1) False - sage: fan = toric_varieties.P2().fan(); fan # optional - palp + sage: fan = toric_varieties.P2().fan(); fan # needs palp Rational polyhedral fan in 2-d lattice N - sage: is_Fan(fan) # optional - palp + sage: is_Fan(fan) # needs palp True """ return isinstance(x, RationalPolyhedralFan) @@ -369,7 +370,7 @@ def Fan(cones, rays=None, lattice=None, check=True, normalize=True, OUTPUT: - - a :class:`fan <RationalPolyhedralFan>`. + a :class:`fan <RationalPolyhedralFan>` .. SEEALSO:: @@ -503,12 +504,12 @@ def Fan(cones, rays=None, lattice=None, check=True, normalize=True, sage: fan = Fan([c1, c2], allow_arrangement=True) sage: fan.ngenerating_cones() 7 - sage: fan.plot() # optional - sage.plot + sage: fan.plot() # needs sage.plot Graphics3d Object Cones of different dimension:: - sage: c1 = Cone([(1,0),(0,1)]) + sage: c1 = Cone([(1,0), (0,1)]) sage: c2 = Cone([(2,1)]) sage: c3 = Cone([(-1,-2)]) sage: fan = Fan([c1, c2, c3], allow_arrangement=True) @@ -523,7 +524,7 @@ def Fan(cones, rays=None, lattice=None, check=True, normalize=True, sage: c3 = Cone([[0, 1, 1], [1, 0, 1], [0, -1, 1], [-1, 0, 1]]) sage: c1 = Cone([[0, 0, 1]]) sage: fan1 = Fan([c1, c3], allow_arrangement=True) - sage: fan1.plot() # optional - sage.plot + sage: fan1.plot() # needs sage.plot Graphics3d Object A 3-d cone and two 2-d cones:: @@ -687,7 +688,7 @@ def FaceFan(polytope, lattice=None): OUTPUT: - - :class:`rational polyhedral fan <RationalPolyhedralFan>`. + :class:`rational polyhedral fan <RationalPolyhedralFan>` See also :func:`NormalFan`. @@ -737,7 +738,7 @@ def FaceFan(polytope, lattice=None): ValueError: face fans are defined only for polytopes containing the origin as an interior point! - sage: interval_in_QQ2 = Polyhedron([ (0,-1), (0,+1) ]) + sage: interval_in_QQ2 = Polyhedron([(0,-1), (0,+1)]) sage: FaceFan(interval_in_QQ2).generating_cones() (1-d cone of Rational polyhedral fan in 2-d lattice M, 1-d cone of Rational polyhedral fan in 2-d lattice M) @@ -753,7 +754,7 @@ def FaceFan(polytope, lattice=None): "face fans are defined only for polytopes containing " "the origin as an interior point!") if is_LatticePolytope(polytope): - if any(d <= 0 for d in polytope.distances([0]*polytope.dim())): + if any(d <= 0 for d in polytope.distances([0] * polytope.dim())): raise interior_point_error cones = (f.ambient_vertex_indices() for f in polytope.facets()) rays = polytope.vertices() @@ -763,8 +764,8 @@ def FaceFan(polytope, lattice=None): if not (polytope.is_compact() and polytope.relative_interior_contains(origin)): raise interior_point_error - cones = [ [ v.index() for v in facet.incident() ] - for facet in polytope.inequalities() ] + cones = [[v.index() for v in facet.incident()] + for facet in polytope.inequalities()] rays = [vector(_) for _ in polytope.vertices()] is_complete = polytope.dim() == polytope.ambient_dim() if lattice is None: @@ -796,7 +797,7 @@ def NormalFan(polytope, lattice=None): OUTPUT: - - :class:`rational polyhedral fan <RationalPolyhedralFan>`. + :class:`rational polyhedral fan <RationalPolyhedralFan>` See also :func:`FaceFan`. @@ -904,7 +905,7 @@ def Fan2d(rays, lattice=None): (False, True) sage: fan = Fan2d([(1,1), (-1,-1), (1,-1), (-1,1)]) - sage: [ cone.ambient_ray_indices() for cone in fan ] + sage: [cone.ambient_ray_indices() for cone in fan] [(2, 1), (1, 3), (3, 0), (0, 2)] sage: fan.is_complete() True @@ -961,13 +962,14 @@ def Fan2d(rays, lattice=None): # remove multiple rays without changing order rays = normalize_rays(rays, lattice) - rays = sorted( (r, i) for i, r in enumerate(rays) ) - distinct_rays = [ rays[i] for i in range(len(rays)) if rays[i][0] != rays[i-1][0] ] + rays = sorted((r, i) for i, r in enumerate(rays)) + distinct_rays = [rays[i] for i in range(len(rays)) + if rays[i][0] != rays[i-1][0]] if distinct_rays: - rays = sorted( (i, r) for r, i in distinct_rays ) - rays = [ r[1] for r in rays ] + rays = sorted((i, r) for r, i in distinct_rays) + rays = [r[1] for r in rays] else: # all given rays were the same - rays = [ rays[0][0] ] + rays = [rays[0][0]] lattice = rays[0].parent() if lattice.dimension() != 2: raise ValueError('the lattice must be 2-dimensional.') @@ -978,7 +980,8 @@ def Fan2d(rays, lattice=None): import math # each sorted_rays entry = (angle, ray, original_ray_index) - sorted_rays = sorted( (math.atan2(r[0],r[1]), r, i) for i,r in enumerate(rays) ) + sorted_rays = sorted((math.atan2(r[0], r[1]), r, i) + for i, r in enumerate(rays)) cones = [] is_complete = True for i in range(n): @@ -987,7 +990,7 @@ def Fan2d(rays, lattice=None): if r1.is_zero(): raise ValueError('only non-zero vectors define rays') assert r0 != r1 - cross_prod = r0[0]*r1[1]-r0[1]*r1[0] + cross_prod = r0[0] * r1[1] - r0[1] * r1[0] if cross_prod < 0: r0_index = (i-1) % len(sorted_rays) r1_index = i @@ -1019,18 +1022,19 @@ class Cone_of_fan(ConvexRationalPolyhedralCone): OUTPUT: - - cone of ``ambient``. + cone of ``ambient`` EXAMPLES: The intended way to get objects of this class is the following:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: cone = fan.generating_cone(0); cone # optional - palp + sage: # needs palp + sage: fan = toric_varieties.P1xP1().fan() + sage: cone = fan.generating_cone(0); cone 2-d cone of Rational polyhedral fan in 2-d lattice N - sage: cone.ambient_ray_indices() # optional - palp + sage: cone.ambient_ray_indices() (0, 2) - sage: cone.star_generator_indices() # optional - palp + sage: cone.star_generator_indices() (0,) """ @@ -1043,31 +1047,32 @@ def __init__(self, ambient, ambient_ray_indices): The following code is likely to construct an invalid object, we just test that creation of cones of fans is working:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: cone = sage.geometry.fan.Cone_of_fan(fan, (0,)); cone # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: cone = sage.geometry.fan.Cone_of_fan(fan, (0,)); cone # needs palp 1-d cone of Rational polyhedral fan in 2-d lattice N - sage: TestSuite(cone).run() # optional - palp + sage: TestSuite(cone).run() # needs palp """ super().__init__(ambient=ambient, ambient_ray_indices=ambient_ray_indices) self._is_strictly_convex = True # Because if not, this cone should not have been constructed - def _repr_(self): + def _repr_(self) -> str: r""" Return a string representation of ``self``. OUTPUT: - - string. + string TESTS:: - sage: P1xP1 = toric_varieties.P1xP1() # optional - palp - sage: cone = P1xP1.fan().generating_cone(0) # optional - palp - sage: cone._repr_() # optional - palp + sage: # needs palp + sage: P1xP1 = toric_varieties.P1xP1() + sage: cone = P1xP1.fan().generating_cone(0) + sage: cone._repr_() '2-d cone of Rational polyhedral fan in 2-d lattice N' - sage: cone.facets()[0]._repr_() # optional - palp + sage: cone.facets()[0]._repr_() '1-d cone of Rational polyhedral fan in 2-d lattice N' """ # The base class would print "face of" instead of "cone of" @@ -1080,13 +1085,13 @@ def star_generator_indices(self): OUTPUT: - - increasing :class:`tuple` of integers. + increasing :class:`tuple` of integers EXAMPLES:: - sage: P1xP1 = toric_varieties.P1xP1() # optional - palp - sage: cone = P1xP1.fan().generating_cone(0) # optional - palp - sage: cone.star_generator_indices() # optional - palp + sage: P1xP1 = toric_varieties.P1xP1() # needs palp + sage: cone = P1xP1.fan().generating_cone(0) # needs palp + sage: cone.star_generator_indices() # needs palp (0,) TESTS: @@ -1132,13 +1137,13 @@ def star_generators(self): OUTPUT: - - increasing :class:`tuple` of integers. + increasing :class:`tuple` of integers EXAMPLES:: - sage: P1xP1 = toric_varieties.P1xP1() # optional - palp - sage: cone = P1xP1.fan().generating_cone(0) # optional - palp - sage: cone.star_generators() # optional - palp + sage: P1xP1 = toric_varieties.P1xP1() # needs palp + sage: cone = P1xP1.fan().generating_cone(0) # needs palp + sage: cone.star_generators() # needs palp (2-d cone of Rational polyhedral fan in 2-d lattice N,) """ if "_star_generators" not in self.__dict__: @@ -1186,7 +1191,7 @@ class RationalPolyhedralFan(IntegralRayCollection, Callable, Container): OUTPUT: - - rational polyhedral fan. + rational polyhedral fan """ def __init__(self, cones, rays, lattice, @@ -1256,8 +1261,8 @@ def __call__(self, dim=None, codim=None): OUTPUT: - - cones of ``self`` of the specified (co)dimension if it was given, - otherwise ``self``. + cones of ``self`` of the specified (co)dimension if it was given, + otherwise ``self`` TESTS:: @@ -1363,7 +1368,7 @@ def __iter__(self): OUTPUT: - - iterator. + iterator TESTS:: @@ -1390,10 +1395,10 @@ def _compute_cone_lattice(self): We use different algorithms depending on available information. One of the common cases is a fan which is KNOWN to be complete, i.e. we do - not even need to check if it is complete. + not even need to check if it is complete:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.cone_lattice() # indirect doctest # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.cone_lattice() # indirect doctest # needs palp Finite lattice containing 10 elements with distinguished linear extension These 10 elements are: 1 origin, 4 rays, 4 generating cones, 1 fan. @@ -1464,8 +1469,8 @@ def FanFace(rays, cones): # For general fans we will "merge" face lattices of generating # cones. L = DiGraph() - face_to_rays = dict() # face |---> (indices of fan rays) - rays_to_index = dict() # (indices of fan rays) |---> face index + face_to_rays = {} # face |---> (indices of fan rays) + rays_to_index = {} # (indices of fan rays) |---> face index # face index |---> (indices of containing generating cones) index_to_cones = [] # During construction index 0 will correspond to the fan @@ -1492,7 +1497,7 @@ def FanFace(rays, cones): rays_to_index[f_rays] = f_index index_to_cones.append([i]) # Add all relations between faces of cone to L - for f,g in L_cone.cover_relations_iterator(): + for f, g in L_cone.cover_relations_iterator(): L.add_edge(rays_to_index[face_to_rays[f]], rays_to_index[face_to_rays[g]]) # Add the inclusion of cone into the fan itself @@ -1511,7 +1516,7 @@ def FanFace(rays, cones): head.extend(rays_to_index[(n,)] for n in range(self.nrays())) new_order = head + [n for n in new_order if n not in head] # "Invert" this list to a dictionary - labels = dict() + labels = {} for new, old in enumerate(new_order): labels[old] = new L.relabel(labels) @@ -1528,7 +1533,7 @@ def FanFace(rays, cones): L.relabel(D) self._cone_lattice = FinitePoset(L, elements, key=id(self)) - def _contains(self, cone): + def _contains(self, cone) -> bool: r""" Check if ``cone`` is equivalent to a cone of the fan. @@ -1541,8 +1546,8 @@ def _contains(self, cone): OUTPUT: - - ``False`` if ``cone`` is not a cone or if ``cone`` is not - equivalent to a cone of the fan. ``True`` otherwise. + ``False`` if ``cone`` is not a cone or if ``cone`` is not + equivalent to a cone of the fan, ``True`` otherwise TESTS:: @@ -1594,8 +1599,8 @@ def support_contains(self, *args): OUTPUT: - - ``True`` if ``point`` is contained in the support of the - fan, ``False`` otherwise. + ``True`` if ``point`` is contained in the support of the + fan, ``False`` otherwise TESTS:: @@ -1615,7 +1620,7 @@ def support_contains(self, *args): True sage: f.support_contains((-1,0)) False - sage: f.support_contains(f.lattice().dual()(1,0)) #random output (warning) + sage: f.support_contains(f.lattice().dual()(1,0)) # random output (warning) False sage: f.support_contains(f.lattice().dual()(1,0)) False @@ -1623,9 +1628,9 @@ def support_contains(self, *args): False sage: f.support_contains(0) # 0 converts to the origin in the lattice True - sage: f.support_contains(1/2, sqrt(3)) + sage: f.support_contains(1/2, sqrt(3)) # needs sage.symbolic True - sage: f.support_contains(-1/2, sqrt(3)) + sage: f.support_contains(-1/2, sqrt(3)) # needs sage.symbolic False """ if len(args) == 1: @@ -1660,16 +1665,16 @@ def cartesian_product(self, other, lattice=None): OUTPUT: - - a :class:`fan <RationalPolyhedralFan>` whose cones are all pairwise - Cartesian products of the cones of ``self`` and ``other``. + a :class:`fan <RationalPolyhedralFan>` whose cones are all pairwise + Cartesian products of the cones of ``self`` and ``other`` EXAMPLES:: sage: K = ToricLattice(1, 'K') - sage: fan1 = Fan([[0],[1]],[(1,),(-1,)], lattice=K) + sage: fan1 = Fan([[0],[1]], [(1,),(-1,)], lattice=K) sage: L = ToricLattice(2, 'L') - sage: fan2 = Fan(rays=[(1,0),(0,1),(-1,-1)], - ....: cones=[[0,1],[1,2],[2,0]], lattice=L) + sage: fan2 = Fan(rays=[(1,0), (0,1), (-1,-1)], + ....: cones=[[0,1], [1,2], [2,0]], lattice=L) sage: fan1.cartesian_product(fan2) Rational polyhedral fan in 3-d lattice K+L sage: _.ngenerating_cones() @@ -1725,20 +1730,20 @@ def common_refinement(self, other): OUTPUT: - - a :class:`fan <RationalPolyhedralFan>` + a :class:`fan <RationalPolyhedralFan>` EXAMPLES: Refining a fan with itself gives itself:: - sage: F0 = Fan2d([(1,0),(0,1),(-1,0),(0,-1)]) + sage: F0 = Fan2d([(1,0), (0,1), (-1,0), (0,-1)]) sage: F0.common_refinement(F0) == F0 True A more complex example with complete fans:: - sage: F1 = Fan([[0],[1]],[(1,),(-1,)]) - sage: F2 = Fan2d([(1,0),(1,1),(0,1),(-1,0),(0,-1)]) + sage: F1 = Fan([[0],[1]], [(1,),(-1,)]) + sage: F2 = Fan2d([(1,0), (1,1), (0,1), (-1,0), (0,-1)]) sage: F3 = F2.cartesian_product(F1) sage: F4 = F1.cartesian_product(F2) sage: FF = F3.common_refinement(F4) @@ -1751,8 +1756,8 @@ def common_refinement(self, other): An example with two non-complete fans with the same support:: - sage: F5 = Fan2d([(1,0),(1,2),(0,1)]) - sage: F6 = Fan2d([(1,0),(2,1),(0,1)]) + sage: F5 = Fan2d([(1,0), (1,2), (0,1)]) + sage: F6 = Fan2d([(1,0), (2,1), (0,1)]) sage: F5.common_refinement(F6).ngenerating_cones() 3 @@ -1775,13 +1780,13 @@ def common_refinement(self, other): FanMorphism(id, other, self, subdivide=True) return subdivision - def _latex_(self): + def _latex_(self) -> str: r""" Return a LaTeX representation of ``self``. OUTPUT: - - string. + string TESTS:: @@ -1803,16 +1808,16 @@ def _ray_to_cones(self, i=None): OUTPUT: - - :class:`frozenset` of indices of generating cones of ``self`` - containing the ``i``-th ray if ``i`` was given, :class:`tuple` of - these sets for all rays otherwise. + :class:`frozenset` of indices of generating cones of ``self`` + containing the ``i``-th ray if ``i`` was given, :class:`tuple` of + these sets for all rays otherwise. EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan._ray_to_cones(0) # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan._ray_to_cones(0) # needs palp frozenset({0, 3}) - sage: fan._ray_to_cones() # optional - palp + sage: fan._ray_to_cones() # needs palp (frozenset({0, 3}), frozenset({1, 2}), frozenset({0, 1}), frozenset({2, 3})) """ # This function is close to self(1)[i].star_generator_indices(), but @@ -1832,13 +1837,13 @@ def _ray_to_cones(self, i=None): else: return self._ray_to_cones_tuple[i] - def _repr_(self): + def _repr_(self) -> str: r""" Return a string representation of ``self``. OUTPUT: - - string. + string TESTS:: @@ -1874,7 +1879,7 @@ def _subdivide_stellar(self, new_rays, verbose): OUTPUT: - - rational polyhedral fan. + rational polyhedral fan TESTS:: @@ -1944,8 +1949,8 @@ def cone_containing(self, *points): OUTPUT: - - A :class:`cone of fan <Cone_of_fan>` whose ambient fan is - ``self``. + A :class:`cone of fan <Cone_of_fan>` whose ambient fan is + ``self`` .. NOTE:: @@ -1995,7 +2000,7 @@ def cone_containing(self, *points): TESTS:: sage: fan = Fan(cones=[(0,1,2,3), (0,1,4)], - ....: rays=[(1,1,1), (1,-1,1), (1,-1,-1), (1,1,-1), (0,0,1)]) + ....: rays=[(1,1,1), (1,-1,1), (1,-1,-1), (1,1,-1), (0,0,1)]) sage: fan.cone_containing(0).rays() N(1, 1, 1) in 3-d lattice N @@ -2068,12 +2073,12 @@ def cone_lattice(self): OUTPUT: - - :class:`finite poset <sage.combinat.posets.posets.FinitePoset` of - :class:`cones of fan<Cone_of_fan>`, behaving like "regular" cones, - but also containing the information about their relation to this - fan, namely, the contained rays and containing generating cones. The - top of the lattice will be this fan itself (*which is not a* - :class:`cone of fan<Cone_of_fan>`). + :class:`finite poset <sage.combinat.posets.posets.FinitePoset` of + :class:`cones of fan<Cone_of_fan>`, behaving like "regular" cones, + but also containing the information about their relation to this + fan, namely, the contained rays and containing generating cones. The + top of the lattice will be this fan itself (*which is not a* + :class:`cone of fan<Cone_of_fan>`). See also :meth:`cones`. @@ -2121,9 +2126,9 @@ def cone_lattice(self): can (and will!) be computed in a much more efficient way, but the interface is exactly the same:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: L = fan.cone_lattice() # optional - palp - sage: for l in L.level_sets()[:-1]: # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: L = fan.cone_lattice() # needs palp + sage: for l in L.level_sets()[:-1]: # needs palp ....: print([f.ambient_ray_indices() for f in l]) [()] [(0,), (1,), (2,), (3,)] @@ -2146,6 +2151,21 @@ def cone_lattice(self): self._compute_cone_lattice() return self._cone_lattice + def f_vector(self) -> tuple: + r""" + Return the f-vector of the fan. + + This is the tuple `(f_0, f_1, \ldots, f_d)` + where `f_i` is the number of cones of dimension `i`. + + EXAMPLES:: + + sage: F = ClusterAlgebra(['A',2]).cluster_fan() + sage: F.f_vector() + (1, 5, 5) + """ + return tuple(len(d) for d in self.cones()) + # Internally we use this name for a uniform behaviour of cones and fans. _face_lattice_function = cone_lattice @@ -2155,7 +2175,7 @@ def __getstate__(self): OUTPUT: - - :class:`dict`. + :class:`dict` TESTS:: @@ -2189,9 +2209,9 @@ def cones(self, dim=None, codim=None): OUTPUT: - - :class:`tuple` of cones of ``self`` of the specified (co)dimension, - if either ``dim`` or ``codim`` is given. Otherwise :class:`tuple` of - such tuples for all existing dimensions. + :class:`tuple` of cones of ``self`` of the specified (co)dimension, + if either ``dim`` or ``codim`` is given. Otherwise :class:`tuple` of + such tuples for all existing dimensions. EXAMPLES:: @@ -2257,7 +2277,7 @@ def cones(self, dim=None, codim=None): "dimension and codimension cannot be specified together!") return self._cones[dim] if 0 <= dim < len(self._cones) else () - def contains(self, cone): + def contains(self, cone) -> bool: r""" Check if a given ``cone`` is equivalent to a cone of the fan. @@ -2267,8 +2287,8 @@ def contains(self, cone): OUTPUT: - - ``False`` if ``cone`` is not a cone or if ``cone`` is not - equivalent to a cone of the fan. ``True`` otherwise. + ``False`` if ``cone`` is not a cone or if ``cone`` is not + equivalent to a cone of the fan, ``True`` otherwise .. NOTE:: @@ -2349,8 +2369,8 @@ def embed(self, cone): OUTPUT: - - a :class:`cone of fan <Cone_of_fan>`, equivalent to ``cone`` but - sitting inside ``self``. + a :class:`cone of fan <Cone_of_fan>`, equivalent to ``cone`` but + sitting inside ``self`` EXAMPLES: @@ -2431,19 +2451,19 @@ def Gale_transform(self): OUTPUT: - A matrix over `ZZ`. + A matrix over `ZZ` EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.Gale_transform() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.Gale_transform() # needs palp [ 1 1 0 0 -2] [ 0 0 1 1 -2] - sage: _.base_ring() # optional - palp + sage: _.base_ring() # needs palp Integer Ring """ m = self.rays().matrix().stack(matrix(ZZ, 1, self.lattice_dim())) - m = m.augment(matrix(ZZ, m.nrows(), 1, [1]*m.nrows())) + m = m.augment(matrix(ZZ, m.nrows(), 1, [1] * m.nrows())) return matrix(ZZ, m.integer_kernel().matrix()) def generating_cone(self, n): @@ -2456,12 +2476,12 @@ def generating_cone(self, n): OUTPUT: - - :class:`cone of fan<Cone_of_fan>`. + :class:`cone of fan<Cone_of_fan>` EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.generating_cone(0) # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.generating_cone(0) # needs palp 2-d cone of Rational polyhedral fan in 2-d lattice N """ return self._generating_cones[n] @@ -2472,12 +2492,12 @@ def generating_cones(self): OUTPUT: - - :class:`tuple` of :class:`cones of fan<Cone_of_fan>`. + :class:`tuple` of :class:`cones of fan<Cone_of_fan>` EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.generating_cones() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.generating_cones() # needs palp (2-d cone of Rational polyhedral fan in 2-d lattice N, 2-d cone of Rational polyhedral fan in 2-d lattice N, 2-d cone of Rational polyhedral fan in 2-d lattice N, @@ -2508,18 +2528,19 @@ def vertex_graph(self): EXAMPLES:: - sage: dP8 = toric_varieties.dP8() # optional - palp sage.graphs - sage: g = dP8.fan().vertex_graph(); g # optional - palp sage.graphs + sage: # needs palp + sage: dP8 = toric_varieties.dP8() + sage: g = dP8.fan().vertex_graph(); g Graph on 4 vertices - sage: set(dP8.fan(1)) == set(g.vertices(sort=False)) # optional - palp sage.graphs + sage: set(dP8.fan(1)) == set(g.vertices(sort=False)) True - sage: g.edge_labels() # all edge labels the same since every cone is smooth # optional - palp sage.graphs + sage: g.edge_labels() # all edge labels the same since every cone is smooth [(1, 0), (1, 0), (1, 0), (1, 0)] - sage: g = toric_varieties.Cube_deformation(10).fan().vertex_graph() # optional - sage.graphs - sage: g.automorphism_group().order() # optional - sage.graphs sage.groups + sage: g = toric_varieties.Cube_deformation(10).fan().vertex_graph() + sage: g.automorphism_group().order() # needs sage.groups 48 - sage: g.automorphism_group(edge_labels=True).order() # optional - sage.graphs sage.groups + sage: g.automorphism_group(edge_labels=True).order() # needs sage.groups 4 """ from sage.geometry.cone import classify_cone_2d @@ -2537,7 +2558,7 @@ def vertex_graph(self): from sage.graphs.graph import Graph return Graph(graph) - def is_complete(self): + def is_complete(self) -> bool: r""" Check if ``self`` is complete. @@ -2546,12 +2567,12 @@ def is_complete(self): OUTPUT: - - ``True`` if ``self`` is complete and ``False`` otherwise. + ``True`` if ``self`` is complete and ``False`` otherwise EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.is_complete() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.is_complete() # needs palp True sage: cone1 = Cone([(1,0), (0,1)]) sage: cone2 = Cone([(-1,0)]) @@ -2578,7 +2599,7 @@ def is_complete(self): self._is_complete = True return True - def is_equivalent(self, other): + def is_equivalent(self, other) -> bool: r""" Check if ``self`` is "mathematically" the same as ``other``. @@ -2588,9 +2609,9 @@ def is_equivalent(self, other): OUTPUT: - - ``True`` if ``self`` and ``other`` define the same fans as - collections of equivalent cones in the same lattice, ``False`` - otherwise. + ``True`` if ``self`` and ``other`` define the same fans as + collections of equivalent cones in the same lattice, ``False`` + otherwise. There are three different equivalences between fans `F_1` and `F_2` in the same lattice: @@ -2638,7 +2659,7 @@ def is_equivalent(self, other): return sorted(sorted(cone.rays()) for cone in self) \ == sorted(sorted(cone.rays()) for cone in other) - def is_isomorphic(self, other): + def is_isomorphic(self, other) -> bool: r""" Check if ``self`` is in the same `GL(n, \ZZ)`-orbit as ``other``. @@ -2664,8 +2685,8 @@ def is_isomorphic(self, other): OUTPUT: - - ``True`` if ``self`` and ``other`` are in the same - `GL(n, \ZZ)`-orbit, ``False`` otherwise. + ``True`` if ``self`` and ``other`` are in the same + `GL(n, \ZZ)`-orbit, ``False`` otherwise .. SEEALSO:: @@ -2680,7 +2701,7 @@ def is_isomorphic(self, other): sage: rays = ((1, 1), (0, 1), (-1, -1), (1, 0)) sage: cones = [(0,1), (1,2), (2,3), (3,0)] sage: fan1 = Fan(cones, rays) - sage: m = matrix([[-2,3],[1,-1]]) + sage: m = matrix([[-2,3], [1,-1]]) sage: fan2 = Fan(cones, [vector(r)*m for r in rays]) sage: fan1.is_isomorphic(fan2) True @@ -2729,12 +2750,12 @@ def _2d_echelon_forms(self): OUTPUT: - A set of integer matrices. + A set of integer matrices EXAMPLES:: - sage: fan = toric_varieties.dP8().fan() # optional - palp - sage: fan._2d_echelon_forms() # optional - palp + sage: fan = toric_varieties.dP8().fan() # needs palp + sage: fan._2d_echelon_forms() # needs palp frozenset({[ 1 0 -1 -1] [ 0 1 0 -1], [ 1 0 -1 0] [ 0 1 -1 -1], [ 1 0 -1 0] @@ -2751,12 +2772,12 @@ def _2d_echelon_form(self): OUTPUT: - An integer matrix whose columns are the rays in the echelon form. + An integer matrix whose columns are the rays in the echelon form EXAMPLES:: - sage: fan = toric_varieties.dP8().fan() # optional - palp - sage: fan._2d_echelon_form() # optional - palp + sage: fan = toric_varieties.dP8().fan() # needs palp + sage: fan._2d_echelon_form() # needs palp [ 1 0 -1 -1] [ 0 1 0 -1] """ @@ -2782,7 +2803,7 @@ def isomorphism(self, other): sage: rays = ((1, 1), (0, 1), (-1, -1), (3, 1)) sage: cones = [(0,1), (1,2), (2,3), (3,0)] sage: fan1 = Fan(cones, rays) - sage: m = matrix([[-2,3],[1,-1]]) + sage: m = matrix([[-2,3], [1,-1]]) sage: fan2 = Fan(cones, [vector(r)*m for r in rays]) sage: fan1.isomorphism(fan2) @@ -2799,7 +2820,7 @@ def isomorphism(self, other): Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in 2-d lattice N - sage: fan1.isomorphism(toric_varieties.P2().fan()) # optional - palp + sage: fan1.isomorphism(toric_varieties.P2().fan()) # needs palp Traceback (most recent call last): ... FanNotIsomorphicError @@ -2807,7 +2828,7 @@ def isomorphism(self, other): from sage.geometry.fan_isomorphism import find_isomorphism return find_isomorphism(self, other, check=False) - def is_simplicial(self): + def is_simplicial(self) -> bool: r""" Check if ``self`` is simplicial. @@ -2817,12 +2838,12 @@ def is_simplicial(self): OUTPUT: - - ``True`` if ``self`` is simplicial and ``False`` otherwise. + ``True`` if ``self`` is simplicial and ``False`` otherwise EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.is_simplicial() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.is_simplicial() # needs palp True sage: cone1 = Cone([(1,0), (0,1)]) sage: cone2 = Cone([(-1,0)]) @@ -2844,7 +2865,7 @@ def is_simplicial(self): return self._is_simplicial @cached_method - def is_smooth(self, codim=None): + def is_smooth(self, codim=None) -> bool: r""" Check if ``self`` is smooth. @@ -2866,13 +2887,13 @@ def is_smooth(self, codim=None): OUTPUT: - - ``True`` if ``self`` is smooth (in codimension ``codim``, if it was - given) and ``False`` otherwise. + ``True`` if ``self`` is smooth (in codimension ``codim``, if it was + given) and ``False`` otherwise. EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.is_smooth() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.is_smooth() # needs palp True sage: cone1 = Cone([(1,0), (0,1)]) sage: cone2 = Cone([(-1,0)]) @@ -2912,8 +2933,8 @@ def make_simplicial(self, **kwds): OUTPUT: - - :class:`rational polyhedral fan - <sage.geometry.fan.RationalPolyhedralFan>`. + :class:`rational polyhedral fan + <sage.geometry.fan.RationalPolyhedralFan>` EXAMPLES:: @@ -2936,12 +2957,12 @@ def ngenerating_cones(self): OUTPUT: - - integer. + integer EXAMPLES:: - sage: fan = toric_varieties.P1xP1().fan() # optional - palp - sage: fan.ngenerating_cones() # optional - palp + sage: fan = toric_varieties.P1xP1().fan() # needs palp + sage: fan.ngenerating_cones() # needs palp 4 sage: cone1 = Cone([(1,0), (0,1)]) sage: cone2 = Cone([(-1,0)]) @@ -2962,12 +2983,12 @@ def plot(self, **options): OUTPUT: - - a plot. + a plot EXAMPLES:: - sage: fan = toric_varieties.dP6().fan() # optional - palp - sage: fan.plot() # optional - palp sage.plot + sage: fan = toric_varieties.dP6().fan() # needs palp + sage: fan.plot() # needs palp sage.plot Graphics object consisting of 31 graphics primitives """ tp = ToricPlotter(options, self.lattice().degree(), self.rays()) @@ -2998,8 +3019,8 @@ def subdivide(self, new_rays=None, make_simplicial=False, OUTPUT: - - :class:`rational polyhedral fan - <sage.geometry.fan.RationalPolyhedralFan>`. + :class:`rational polyhedral fan + <sage.geometry.fan.RationalPolyhedralFan>` Currently the "default" algorithm corresponds to iterative stellar subdivision for each ray in ``new_rays``. @@ -3025,8 +3046,8 @@ def subdivide(self, new_rays=None, make_simplicial=False, We check that :trac:`11902` is fixed:: - sage: fan = toric_varieties.P2().fan() # optional - palp - sage: fan.subdivide(new_rays=[(0,0)]) # optional - palp + sage: fan = toric_varieties.P2().fan() # needs palp + sage: fan.subdivide(new_rays=[(0,0)]) # needs palp Traceback (most recent call last): ... ValueError: the origin cannot be used for fan subdivision! @@ -3080,9 +3101,9 @@ def virtual_rays(self, *args): OUTPUT: - - a :class:`~sage.geometry.point_collection.PointCollection` of - primitive integral ray generators. Usually (if the fan is - full-dimensional) this will be empty. + a :class:`~sage.geometry.point_collection.PointCollection` of + primitive integral ray generators. Usually (if the fan is + full-dimensional) this will be empty. EXAMPLES:: @@ -3173,7 +3194,8 @@ def primitive_collections(self): EXAMPLES:: - sage: fan = Fan([[0,1,3],[3,4],[2,0],[1,2,4]], [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)]) + sage: fan = Fan([[0,1,3], [3,4], [2,0], [1,2,4]], + ....: [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)]) sage: fan.primitive_collections() [frozenset({0, 4}), frozenset({2, 3}), @@ -3201,12 +3223,12 @@ def is_in_SR(I): d_max = max(map(len, facets)) + 1 SR = [] for d in range(1, d_max): - checked = set([]) + checked = set() for facet in facets: for I_minus_j_list in Combinations(facet, d): I_minus_j = frozenset(I_minus_j_list) for j in all_points - I_minus_j: - I = I_minus_j.union( frozenset([j]) ) + I = I_minus_j.union(frozenset([j])) if I in checked: continue @@ -3229,17 +3251,19 @@ def Stanley_Reisner_ideal(self, ring): OUTPUT: - - The Stanley-Reisner ideal in the given polynomial ring. + The Stanley-Reisner ideal in the given polynomial ring EXAMPLES:: - sage: fan = Fan([[0,1,3],[3,4],[2,0],[1,2,4]], [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)]) - sage: fan.Stanley_Reisner_ideal( PolynomialRing(QQ,5,'A, B, C, D, E') ) - Ideal (A*E, C*D, A*B*C, B*D*E) of Multivariate Polynomial Ring in A, B, C, D, E over Rational Field + sage: fan = Fan([[0,1,3], [3,4], [2,0], [1,2,4]], + ....: [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)]) + sage: fan.Stanley_Reisner_ideal(PolynomialRing(QQ, 5, 'A, B, C, D, E')) + Ideal (A*E, C*D, A*B*C, B*D*E) of + Multivariate Polynomial Ring in A, B, C, D, E over Rational Field """ generators_indices = self.primitive_collections() - SR = ring.ideal([ prod([ ring.gen(i) for i in sr]) for sr in generators_indices ]) - return SR + return ring.ideal([prod([ring.gen(i) for i in sr]) + for sr in generators_indices]) def linear_equivalence_ideal(self, ring): """ @@ -3257,14 +3281,16 @@ def linear_equivalence_ideal(self, ring): EXAMPLES:: - sage: fan = Fan([[0,1,3],[3,4],[2,0],[1,2,4]], [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)]) - sage: fan.linear_equivalence_ideal( PolynomialRing(QQ,5,'A, B, C, D, E') ) - Ideal (-3*A + 3*C - D + E, -2*A - 2*C - D - E, A + B + C + D + E) of Multivariate Polynomial Ring in A, B, C, D, E over Rational Field + sage: fan = Fan([[0,1,3],[3,4],[2,0],[1,2,4]], + ....: [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)]) + sage: fan.linear_equivalence_ideal(PolynomialRing(QQ, 5, 'A, B, C, D, E')) + Ideal (-3*A + 3*C - D + E, -2*A - 2*C - D - E, A + B + C + D + E) of + Multivariate Polynomial Ring in A, B, C, D, E over Rational Field """ gens = [] - for d in range(0,self.dim()): - gens.append( sum([ self.ray(i)[d] * ring.gen(i) - for i in range(0, self.nrays()) ]) ) + for d in range(self.dim()): + gens.append(sum([self.ray(i)[d] * ring.gen(i) + for i in range(self.nrays())])) return ring.ideal(gens) def oriented_boundary(self, cone): @@ -3297,17 +3323,19 @@ def oriented_boundary(self, cone): EXAMPLES:: - sage: fan = toric_varieties.P(3).fan() # optional - palp - sage: cone = fan(2)[0] # optional - palp - sage: bdry = fan.oriented_boundary(cone); bdry # optional - palp - -1-d cone of Rational polyhedral fan in 3-d lattice N + 1-d cone of Rational polyhedral fan in 3-d lattice N - sage: bdry[0] # optional - palp + sage: # needs palp + sage: fan = toric_varieties.P(3).fan() + sage: cone = fan(2)[0] + sage: bdry = fan.oriented_boundary(cone); bdry + -1-d cone of Rational polyhedral fan in 3-d lattice N + + 1-d cone of Rational polyhedral fan in 3-d lattice N + sage: bdry[0] (-1, 1-d cone of Rational polyhedral fan in 3-d lattice N) - sage: bdry[1] # optional - palp + sage: bdry[1] (1, 1-d cone of Rational polyhedral fan in 3-d lattice N) - sage: fan.oriented_boundary(bdry[0][1]) # optional - palp + sage: fan.oriented_boundary(bdry[0][1]) -0-d cone of Rational polyhedral fan in 3-d lattice N - sage: fan.oriented_boundary(bdry[1][1]) # optional - palp + sage: fan.oriented_boundary(bdry[1][1]) -0-d cone of Rational polyhedral fan in 3-d lattice N If you pass the fan itself, this method returns the @@ -3315,12 +3343,12 @@ def oriented_boundary(self, cone): order of the rays in :meth:`cone.ray_basis() <sage.geometry.cone.IntegralRayCollection.ray_basis>` :: - sage: fan.oriented_boundary(fan) # optional - palp + sage: fan.oriented_boundary(fan) # needs palp -3-d cone of Rational polyhedral fan in 3-d lattice N + 3-d cone of Rational polyhedral fan in 3-d lattice N - 3-d cone of Rational polyhedral fan in 3-d lattice N + 3-d cone of Rational polyhedral fan in 3-d lattice N - sage: [cone.rays().basis().matrix().det() # optional - palp + sage: [cone.rays().basis().matrix().det() # needs palp ....: for cone in fan.generating_cones()] [-1, 1, -1, 1] @@ -3335,9 +3363,9 @@ def oriented_boundary(self, cone): TESTS:: - sage: fan = toric_varieties.P2().fan() # optional - palp - sage: trivial_cone = fan(0)[0] # optional - palp - sage: fan.oriented_boundary(trivial_cone) # optional - palp + sage: fan = toric_varieties.P2().fan() # needs palp + sage: trivial_cone = fan(0)[0] # needs palp + sage: fan.oriented_boundary(trivial_cone) # needs palp 0 """ if cone is not self: @@ -3352,24 +3380,24 @@ def oriented_boundary(self, cone): def sign(x): assert x != 0 if x > 0: - return +1 + return 1 else: return -1 N_QQ = self.lattice().base_extend(QQ) dim = self.lattice_dim() - outward_vectors = dict() + outward_vectors = {} generating_cones = [] for c in self.generating_cones(): if c.dim() == dim: outward_v = [] else: Q = N_QQ.quotient(c.rays()) - outward_v = [ Q.lift(q) for q in Q.gens() ] + outward_v = [Q.lift(q) for q in Q.gens()] outward_vectors[c] = outward_v orientation = sign(matrix(outward_v + list(c.rays().basis())).det()) generating_cones.append(tuple([orientation, c])) - boundaries = {self:FormalSum(generating_cones)} + boundaries = {self: FormalSum(generating_cones)} # The orientation of each facet is arbitrary, but the # partition of the boundary in positively and negatively @@ -3482,22 +3510,24 @@ def complex(self, base_ring=ZZ, extended=False): EXAMPLES:: - sage: fan = toric_varieties.P(3).fan() # optional - palp - sage: K_normal = fan.complex(); K_normal # optional - palp + sage: # needs palp + sage: fan = toric_varieties.P(3).fan() + sage: K_normal = fan.complex(); K_normal Chain complex with at most 4 nonzero terms over Integer Ring - sage: K_normal.homology() # optional - palp + sage: K_normal.homology() {0: Z, 1: 0, 2: 0, 3: 0} - sage: K_extended = fan.complex(extended=True); K_extended # optional - palp + sage: K_extended = fan.complex(extended=True); K_extended Chain complex with at most 5 nonzero terms over Integer Ring - sage: K_extended.homology() # optional - palp + sage: K_extended.homology() {-1: 0, 0: 0, 1: 0, 2: 0, 3: 0} Homology computations are much faster over `\QQ` if you do not care about the torsion coefficients:: - sage: toric_varieties.P2_123().fan().complex(extended=True, base_ring=QQ) # optional - palp + sage: toric_varieties.P2_123().fan().complex(extended=True, # needs palp + ....: base_ring=QQ) Chain complex with at most 4 nonzero terms over Rational Field - sage: _.homology() # optional - palp + sage: _.homology() # needs palp {-1: Vector space of dimension 0 over Rational Field, 0: Vector space of dimension 0 over Rational Field, 1: Vector space of dimension 0 over Rational Field, @@ -3505,7 +3535,7 @@ def complex(self, base_ring=ZZ, extended=False): The extended complex is only defined for complete fans:: - sage: fan = Fan([ Cone([(1,0)]) ]) + sage: fan = Fan([Cone([(1,0)])]) sage: fan.is_complete() False sage: fan.complex(extended=True) @@ -3525,27 +3555,28 @@ def complex(self, base_ring=ZZ, extended=False): Things get more complicated for non-complete fans:: sage: fan = Fan([Cone([(1,1,1)]), - ....: Cone([(1,0,0),(0,1,0)]), - ....: Cone([(-1,0,0),(0,-1,0),(0,0,-1)])]) + ....: Cone([(1,0,0), (0,1,0)]), + ....: Cone([(-1,0,0), (0,-1,0), (0,0,-1)])]) sage: fan.complex().homology() {0: 0, 1: 0, 2: Z x Z, 3: 0} - sage: fan = Fan([Cone([(1,0,0),(0,1,0)]), - ....: Cone([(-1,0,0),(0,-1,0),(0,0,-1)])]) + sage: fan = Fan([Cone([(1,0,0), (0,1,0)]), + ....: Cone([(-1,0,0), (0,-1,0), (0,0,-1)])]) sage: fan.complex().homology() {0: 0, 1: 0, 2: Z, 3: 0} - sage: fan = Fan([Cone([(-1,0,0),(0,-1,0),(0,0,-1)])]) + sage: fan = Fan([Cone([(-1,0,0), (0,-1,0), (0,0,-1)])]) sage: fan.complex().homology() {0: 0, 1: 0, 2: 0, 3: 0} """ dim = self.dim() - delta = dict() - for degree in range(1, dim+1): - m = matrix(base_ring, len(self(degree-1)), len(self(degree)), base_ring.zero()) + delta = {} + for degree in range(1, dim + 1): + m = matrix(base_ring, len(self(degree - 1)), len(self(degree)), + base_ring.zero()) for i, cone in enumerate(self(degree)): boundary = self.oriented_boundary(cone) for orientation, d_cone in boundary: - m[self(degree-1).index(d_cone), i] = orientation - delta[dim-degree] = m + m[self(degree - 1).index(d_cone), i] = orientation + delta[dim - degree] = m from sage.homology.chain_complex import ChainComplex if not extended: @@ -3573,25 +3604,25 @@ def discard_faces(cones): OUTPUT: - - a list of - :class:`cones <sage.geometry.cone.ConvexRationalPolyhedralCone>`, - sorted by dimension in decreasing order. + a list of + :class:`cones <sage.geometry.cone.ConvexRationalPolyhedralCone>`, + sorted by dimension in decreasing order EXAMPLES: Consider all cones of a fan:: - sage: Sigma = toric_varieties.P2().fan() # optional - palp - sage: cones = flatten(Sigma.cones()) # optional - palp - sage: len(cones) # optional - palp + sage: Sigma = toric_varieties.P2().fan() # needs palp + sage: cones = flatten(Sigma.cones()) # needs palp + sage: len(cones) # needs palp 7 Most of them are not necessary to generate this fan:: sage: from sage.geometry.fan import discard_faces - sage: len(discard_faces(cones)) # optional - palp + sage: len(discard_faces(cones)) # needs palp 3 - sage: Sigma.ngenerating_cones() # optional - palp + sage: Sigma.ngenerating_cones() # needs palp 3 """ # Convert to a list or make a copy, so that the input is unchanged. @@ -3617,7 +3648,7 @@ def _refine_arrangement_to_fan(cones): OUTPUT: - - a list of refined cones. + a list of refined cones EXAMPLES:: diff --git a/src/sage/geometry/fan_isomorphism.py b/src/sage/geometry/fan_isomorphism.py index d700d24f682..2c69f06a71f 100644 --- a/src/sage/geometry/fan_isomorphism.py +++ b/src/sage/geometry/fan_isomorphism.py @@ -16,7 +16,6 @@ from sage.geometry.cone import Cone - class FanNotIsomorphicError(Exception): """ Exception to return if there is no fan isomorphism @@ -39,10 +38,10 @@ def fan_isomorphic_necessary_conditions(fan1, fan2): EXAMPLES:: - sage: fan1 = toric_varieties.P2().fan() # optional - palp - sage: fan2 = toric_varieties.dP8().fan() # optional - palp + sage: fan1 = toric_varieties.P2().fan() # needs palp sage.graphs + sage: fan2 = toric_varieties.dP8().fan() # needs palp sage.graphs sage: from sage.geometry.fan_isomorphism import fan_isomorphic_necessary_conditions - sage: fan_isomorphic_necessary_conditions(fan1, fan2) # optional - palp + sage: fan_isomorphic_necessary_conditions(fan1, fan2) # needs palp sage.graphs False """ if fan1.lattice_dim() != fan2.lattice_dim(): @@ -79,9 +78,9 @@ def fan_isomorphism_generator(fan1, fan2): EXAMPLES:: - sage: fan = toric_varieties.P2().fan() # optional - palp + sage: fan = toric_varieties.P2().fan() # needs palp sage.graphs sage: from sage.geometry.fan_isomorphism import fan_isomorphism_generator - sage: sorted(fan_isomorphism_generator(fan, fan)) # optional - palp + sage: sorted(fan_isomorphism_generator(fan, fan)) # needs palp sage.graphs [ [-1 -1] [-1 -1] [ 0 1] [0 1] [ 1 0] [1 0] [ 0 1], [ 1 0], [-1 -1], [1 0], [-1 -1], [0 1] @@ -94,7 +93,7 @@ def fan_isomorphism_generator(fan1, fan2): ....: Cone([m1*vector([-1,-14]), m1*vector([-100, -5])])]) sage: fan2 = Fan([Cone([m2*vector([23, 14]), m2*vector([ 3,100])]), ....: Cone([m2*vector([-1,-14]), m2*vector([-100, -5])])]) - sage: sorted(fan_isomorphism_generator(fan1, fan2)) + sage: sorted(fan_isomorphism_generator(fan1, fan2)) # needs sage.graphs [ [-12 1 -5] [ -4 0 -1] @@ -112,24 +111,24 @@ def fan_isomorphism_generator(fan1, fan2): ....: Cone([m1*vector([1,1]), m1*vector([0,1])])]) sage: fan2 = Fan([Cone([m2*vector([1,0]), m2*vector([1,1])]), ....: Cone([m2*vector([1,1]), m2*vector([0,1])])]) - sage: sorted(fan_isomorphism_generator(fan0, fan0)) + sage: sorted(fan_isomorphism_generator(fan0, fan0)) # needs sage.graphs [ [0 1] [1 0] [1 0], [0 1] ] - sage: sorted(fan_isomorphism_generator(fan1, fan1)) + sage: sorted(fan_isomorphism_generator(fan1, fan1)) # needs sage.graphs [ [ -3 -20 28] [1 0 0] [ -1 -4 7] [0 1 0] [ -1 -5 8], [0 0 1] ] - sage: sorted(fan_isomorphism_generator(fan1, fan2)) + sage: sorted(fan_isomorphism_generator(fan1, fan2)) # needs sage.graphs [ [-24 -3 7] [-12 1 -5] [ -7 -1 2] [ -4 0 -1] [ -8 -1 2], [ -5 0 -1] ] - sage: sorted(fan_isomorphism_generator(fan2, fan1)) + sage: sorted(fan_isomorphism_generator(fan2, fan1)) # needs sage.graphs [ [ 0 1 -1] [ 0 1 -1] [ 1 -13 8] [ 2 -8 1] @@ -217,14 +216,14 @@ def find_isomorphism(fan1, fan2, check=False): sage: fan2 = Fan(cones, [vector(r)*m for r in rays]) sage: from sage.geometry.fan_isomorphism import find_isomorphism - sage: find_isomorphism(fan1, fan2, check=True) + sage: find_isomorphism(fan1, fan2, check=True) # needs sage.graphs Fan morphism defined by the matrix [-2 3] [ 1 -1] Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in 2-d lattice N - sage: find_isomorphism(fan1, toric_varieties.P2().fan()) # optional - palp + sage: find_isomorphism(fan1, toric_varieties.P2().fan()) # needs palp sage.graphs Traceback (most recent call last): ... FanNotIsomorphicError @@ -233,7 +232,7 @@ def find_isomorphism(fan1, fan2, check=False): ....: rays=[(-1,-1,0),(-1,-1,3),(-1,1,-1),(-1,3,-1),(0,2,-1),(1,-1,1)]) sage: fan2 = Fan(cones=[[0,2,3,5],[0,1,4,5],[0,1,2],[3,4,5]], ....: rays=[(-1,-1,-1),(-1,-1,0),(-1,1,-1),(0,2,-1),(1,-1,1),(3,-1,-1)]) - sage: fan1.is_isomorphic(fan2) + sage: fan1.is_isomorphic(fan2) # needs sage.graphs True """ generator = fan_isomorphism_generator(fan1, fan2) @@ -312,14 +311,14 @@ def fan_2d_echelon_forms(fan): EXAMPLES:: - sage: fan = toric_varieties.P2().fan() # optional - palp + sage: fan = toric_varieties.P2().fan() # needs palp sage.graphs sage: from sage.geometry.fan_isomorphism import fan_2d_echelon_forms - sage: fan_2d_echelon_forms(fan) # optional - palp + sage: fan_2d_echelon_forms(fan) # needs palp sage.graphs frozenset({[ 1 0 -1] [ 0 1 -1]}) - sage: fan = toric_varieties.dP7().fan() # optional - palp - sage: sorted(fan_2d_echelon_forms(fan)) # optional - palp + sage: fan = toric_varieties.dP7().fan() # needs palp sage.graphs + sage: sorted(fan_2d_echelon_forms(fan)) # needs palp sage.graphs [ [ 1 0 -1 -1 0] [ 1 0 -1 -1 0] [ 1 0 -1 -1 1] [ 1 0 -1 0 1] [ 0 1 0 -1 -1], [ 0 1 1 0 -1], [ 0 1 1 0 -1], [ 0 1 0 -1 -1], @@ -335,10 +334,10 @@ def fan_2d_echelon_forms(fan): sage: fan1 = Fan(cones, rays) sage: from sage.geometry.fan_isomorphism import fan_2d_echelon_form, fan_2d_echelon_forms sage: echelon_forms = fan_2d_echelon_forms(fan1) - sage: S4 = CyclicPermutationGroup(4) + sage: S4 = CyclicPermutationGroup(4) # needs sage.groups sage: rays.reverse() sage: cones = [(3,1), (1,2), (2,0), (0,3)] - sage: for i in range(100): + sage: for i in range(100): # needs sage.groups ....: m = random_matrix(ZZ,2,2) ....: if abs(det(m)) != 1: continue ....: perm = S4.random_element() @@ -383,9 +382,9 @@ def fan_2d_echelon_form(fan): EXAMPLES:: - sage: fan = toric_varieties.P2().fan() # optional - palp + sage: fan = toric_varieties.P2().fan() # needs palp sage.graphs sage: from sage.geometry.fan_isomorphism import fan_2d_echelon_form - sage: fan_2d_echelon_form(fan) # optional - palp + sage: fan_2d_echelon_form(fan) # needs palp sage.graphs [ 1 0 -1] [ 0 1 -1] """ diff --git a/src/sage/geometry/fan_morphism.py b/src/sage/geometry/fan_morphism.py index e94e2cce8c0..1d3cd1db886 100644 --- a/src/sage/geometry/fan_morphism.py +++ b/src/sage/geometry/fan_morphism.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.graphs, sage.combinat r""" Morphisms between toric lattices compatible with fans @@ -318,15 +319,15 @@ def __mul__(self, right): EXAMPLES:: sage: A2 = toric_varieties.A2() - sage: P3 = toric_varieties.P(3) # optional - palp + sage: P3 = toric_varieties.P(3) # needs palp sage: m = matrix([(2,0,0), (1,1,0)]) - sage: phi = A2.hom(m, P3).fan_morphism(); phi # optional - palp + sage: phi = A2.hom(m, P3).fan_morphism(); phi # needs palp Fan morphism defined by the matrix [2 0 0] [1 1 0] Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in 3-d lattice N - sage: prod(phi.factor()) # indirect test # optional - palp + sage: prod(phi.factor()) # indirect test # needs palp Fan morphism defined by the matrix [2 0 0] [1 1 0] @@ -360,7 +361,7 @@ def _RISGIS(self): sage: normal = NormalFan(diamond) sage: N = face.lattice() sage: fm = FanMorphism(identity_matrix(2), - ....: normal, face, subdivide=True) + ....: normal, face, subdivide=True) sage: fm._RISGIS() (frozenset({2}), frozenset({3}), @@ -528,13 +529,14 @@ def _ray_index_map(self): TESTS:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp - sage: phi._ray_index_map() # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) + sage: phi._ray_index_map() (-1, 1, -1, 0) - sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) # optional - palp - sage: xi._ray_index_map() # optional - palp + sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) + sage: xi._ray_index_map() Traceback (most recent call last): ... ValueError: ray #1 is mapped into a 2-d cone! @@ -676,6 +678,7 @@ def _subdivide_domain_fan(self, check, verbose): domain_fan = self._domain_fan lattice_dim = self.domain().dimension() if verbose: + from sage.misc.timing import walltime start = walltime() print("Placing ray images", end=" ") # Figure out where 1-dimensional cones (i.e. rays) are mapped. @@ -774,7 +777,7 @@ def _support_error(self): sage: quadrant = Fan([quadrant]) sage: quadrant_bl = quadrant.subdivide([(1,1)]) sage: fm = FanMorphism(identity_matrix(2), - ....: quadrant, quadrant_bl, check=False) + ....: quadrant, quadrant_bl, check=False) Now we report that the morphism is invalid:: @@ -861,8 +864,8 @@ def _validate(self): TESTS:: - sage: trivialfan2 = Fan([],[],lattice=ToricLattice(2)) - sage: trivialfan3 = Fan([],[],lattice=ToricLattice(3)) + sage: trivialfan2 = Fan([], [], lattice=ToricLattice(2)) + sage: trivialfan3 = Fan([], [], lattice=ToricLattice(3)) sage: FanMorphism(zero_matrix(2,3), trivialfan2, trivialfan3) Fan morphism defined by the matrix [0 0 0] @@ -983,7 +986,7 @@ def image_cone(self, cone): sage: normal = NormalFan(diamond) sage: N = face.lattice() sage: fm = FanMorphism(identity_matrix(2), - ....: normal, face, subdivide=True) + ....: normal, face, subdivide=True) sage: fm.image_cone(Cone([(1,0)])) 1-d cone of Rational polyhedral fan in 2-d lattice N sage: fm.image_cone(Cone([(1,1)])) @@ -1038,32 +1041,33 @@ def index(self, cone=None): EXAMPLES:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp - sage: phi.index() # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) + sage: phi.index() 1 - sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) # optional - palp - sage: psi.index() # optional - palp + sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) + sage: psi.index() 2 - sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) # optional - palp - sage: xi.index() # optional - palp + sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) + sage: xi.index() +Infinity Infinite index in the last example indicates that the image has positive codimension in the codomain. Let's look at the rays of our fans:: - sage: Sigma_p.rays() + sage: Sigma_p.rays() # needs palp N( 1), N(-1) in 1-d lattice N - sage: Sigma.rays() # optional - palp + sage: Sigma.rays() # needs palp N( 1, 1), N( 0, 1), N(-1, -1), N( 1, 0) in 2-d lattice N - sage: xi.factor()[0].domain_fan().rays() # optional - palp + sage: xi.factor()[0].domain_fan().rays() # needs palp N(-1, 0), N( 1, 0) in Sublattice <N(1, 0)> @@ -1079,25 +1083,26 @@ def index(self, cone=None): 1-d cones are ``None``, except for one which is infinite, and all indices over 2-d cones are ``None``, except for one which is 1:: - sage: [xi.index(cone) for cone in Sigma(1)] # optional - palp + sage: [xi.index(cone) for cone in Sigma(1)] # needs palp [None, None, None, +Infinity] - sage: [xi.index(cone) for cone in Sigma(2)] # optional - palp + sage: [xi.index(cone) for cone in Sigma(2)] # needs palp [None, 1, None, None] TESTS:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.Cube_nonpolyhedral().fan() sage: m = matrix([[2,6,10], [7,11,13]]) - sage: zeta = FanMorphism(m, Sigma, Sigma_p, subdivide=True) # optional - palp - sage: [zeta.index(cone) for cone in flatten(Sigma_p.cones())] # optional - palp + sage: zeta = FanMorphism(m, Sigma, Sigma_p, subdivide=True) + sage: [zeta.index(cone) for cone in flatten(Sigma_p.cones())] [+Infinity, None, None, None, None, None, None, None, None, None, 4, 4, None, 4, None, None, 2, None, 4, None, 4, 1, 1, 1, 1, 1, 1] - sage: zeta = prod(zeta.factor()[1:]) # optional - palp - sage: Sigma_p = zeta.codomain_fan() # optional - palp - sage: [zeta.index(cone) for cone in flatten(Sigma_p.cones())] # optional - palp + sage: zeta = prod(zeta.factor()[1:]) + sage: Sigma_p = zeta.codomain_fan() + sage: [zeta.index(cone) for cone in flatten(Sigma_p.cones())] [4, 4, 4, 1, 4, 4, 4, 1, 1, 1, 1, 1, 1] - sage: zeta.index() == zeta.index(Sigma_p(0)[0]) # optional - palp + sage: zeta.index() == zeta.index(Sigma_p(0)[0]) True """ if cone is None: @@ -1128,14 +1133,15 @@ def is_birational(self): EXAMPLES:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp - sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) # optional - palp - sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) # optional - palp - sage: phi.index(), psi.index(), xi.index() # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) + sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) + sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) + sage: phi.index(), psi.index(), xi.index() (1, 2, +Infinity) - sage: phi.is_birational(), psi.is_birational(), xi.is_birational() # optional - palp + sage: phi.is_birational(), psi.is_birational(), xi.is_birational() (True, False, False) """ return self.index() == 1 @@ -1176,26 +1182,27 @@ def is_bundle(self): We consider several maps between fans of a del Pezzo surface and the projective line:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp - sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) # optional - palp - sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) # optional - palp - sage: phi.is_bundle() # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) + sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) + sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) + sage: phi.is_bundle() True - sage: phi.is_fibration() # optional - palp + sage: phi.is_fibration() True - sage: phi.index() # optional - palp + sage: phi.index() 1 - sage: psi.is_bundle() # optional - palp + sage: psi.is_bundle() False - sage: psi.is_fibration() # optional - palp + sage: psi.is_fibration() True - sage: psi.index() # optional - palp + sage: psi.index() 2 - sage: xi.is_fibration() # optional - palp + sage: xi.is_fibration() False - sage: xi.index() # optional - palp + sage: xi.index() +Infinity The first of these maps induces not only a fibration, but a fiber @@ -1268,26 +1275,27 @@ def is_fibration(self): We consider several maps between fans of a del Pezzo surface and the projective line:: - sage: Sigma = toric_varieties.dP8().fan() # optional - palp + sage: # needs palp + sage: Sigma = toric_varieties.dP8().fan() sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp - sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) # optional - palp - sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) # optional - palp - sage: phi.is_bundle() # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) + sage: psi = FanMorphism(matrix([[2], [-2]]), Sigma, Sigma_p) + sage: xi = FanMorphism(matrix([[1, 0]]), Sigma_p, Sigma) + sage: phi.is_bundle() True - sage: phi.is_fibration() # optional - palp + sage: phi.is_fibration() True - sage: phi.index() # optional - palp + sage: phi.index() 1 - sage: psi.is_bundle() # optional - palp + sage: psi.is_bundle() False - sage: psi.is_fibration() # optional - palp + sage: psi.is_fibration() True - sage: psi.index() # optional - palp + sage: psi.index() 2 - sage: xi.is_fibration() # optional - palp + sage: xi.is_fibration() False - sage: xi.index() # optional - palp + sage: xi.index() +Infinity The first of these maps induces not only a fibration, but a fiber @@ -1382,9 +1390,9 @@ def is_injective(self): We also embed the affine plane into the projective one:: - sage: P2 = toric_varieties.P(2).fan() # optional - palp + sage: P2 = toric_varieties.P(2).fan() # needs palp sage: m = identity_matrix(2) - sage: FanMorphism(m, A2, P2).is_injective() # optional - palp + sage: FanMorphism(m, A2, P2).is_injective() # needs palp True """ if self.matrix().index_in_saturation() != 1: @@ -1393,8 +1401,8 @@ def is_injective(self): return prod(self.factor()[1:]).is_injective() # Now we know that underlying lattice morphism is bijective. Sigma = self.domain_fan() - return all(all(self.image_cone(sigma).dim() == d for sigma in Sigma(d)) - for d in range(1, Sigma.dim() + 1)) + return all(self.image_cone(sigma).dim() == d + for d in range(1, Sigma.dim() + 1) for sigma in Sigma(d)) @cached_method def is_surjective(self): @@ -1562,15 +1570,16 @@ def preimage_cones(self, cone): We check that reviewer's example from :trac:`9972` is handled correctly:: + sage: # needs palp sage: N1 = ToricLattice(1) sage: N2 = ToricLattice(2) sage: Hom21 = Hom(N2, N1) sage: pr = Hom21([N1.0,0]) - sage: P1xP1 = toric_varieties.P1xP1() # optional - palp - sage: f = FanMorphism(pr, P1xP1.fan()) # optional - palp - sage: c = f.image_cone(Cone([(1,0), (0,1)])); c # optional - palp + sage: P1xP1 = toric_varieties.P1xP1() + sage: f = FanMorphism(pr, P1xP1.fan()) + sage: c = f.image_cone(Cone([(1,0), (0,1)])); c 1-d cone of Rational polyhedral fan in 1-d lattice N - sage: f.preimage_cones(c) # optional - palp + sage: f.preimage_cones(c) (1-d cone of Rational polyhedral fan in 2-d lattice N, 2-d cone of Rational polyhedral fan in 2-d lattice N, 2-d cone of Rational polyhedral fan in 2-d lattice N) @@ -1676,8 +1685,8 @@ def primitive_preimage_cones(self, cone): Consider a projection of a del Pezzo surface onto the projective line:: - sage: Sigma = toric_varieties.dP6().fan() # optional - palp - sage: Sigma.rays() # optional - palp + sage: Sigma = toric_varieties.dP6().fan() # needs palp + sage: Sigma.rays() # needs palp N( 0, 1), N(-1, 0), N(-1, -1), @@ -1686,7 +1695,7 @@ def primitive_preimage_cones(self, cone): N( 1, 1) in 2-d lattice N sage: Sigma_p = toric_varieties.P1().fan() - sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # optional - palp + sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) # needs palp Under this map, one pair of rays is mapped to the origin, one in the positive direction, and one in the negative one. Also three @@ -1694,28 +1703,28 @@ def primitive_preimage_cones(self, cone): the negative one, so there are 5 preimage cones corresponding to either of the rays of the codomain fan ``Sigma_p``:: - sage: len(phi.preimage_cones(Cone([(1,)]))) # optional - palp + sage: len(phi.preimage_cones(Cone([(1,)]))) # needs palp 5 Yet only rays are primitive:: - sage: phi.primitive_preimage_cones(Cone([(1,)])) # optional - palp + sage: phi.primitive_preimage_cones(Cone([(1,)])) # needs palp (1-d cone of Rational polyhedral fan in 2-d lattice N, 1-d cone of Rational polyhedral fan in 2-d lattice N) Since all primitive cones are mapped onto their images bijectively, we get a fibration:: - sage: phi.is_fibration() # optional - palp + sage: phi.is_fibration() # needs palp True But since there are several primitive cones corresponding to the same cone of the codomain fan, this map is not a bundle, even though its index is 1:: - sage: phi.is_bundle() # optional - palp + sage: phi.is_bundle() # needs palp False - sage: phi.index() # optional - palp + sage: phi.index() # needs palp 1 """ sigma_p = self._codomain_fan.embed(cone) # Necessary if used as a key @@ -1769,10 +1778,10 @@ def factor(self): coordinate planes":: sage: A2 = toric_varieties.A2() - sage: P3 = toric_varieties.P(3) # optional - palp + sage: P3 = toric_varieties.P(3) # needs palp sage: m = matrix([(2,0,0), (1,1,0)]) - sage: phi = A2.hom(m, P3) # optional - palp - sage: phi.as_polynomial_map() # optional - palp + sage: phi = A2.hom(m, P3) # needs palp + sage: phi.as_polynomial_map() # needs palp Scheme morphism: From: 2-d affine toric variety To: 3-d CPR-Fano toric variety covered by 4 affine patches @@ -1781,18 +1790,19 @@ def factor(self): Now we will work with the underlying fan morphism:: - sage: phi = phi.fan_morphism(); phi # optional - palp + sage: # needs palp + sage: phi = phi.fan_morphism(); phi Fan morphism defined by the matrix [2 0 0] [1 1 0] Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in 3-d lattice N - sage: phi.is_surjective(), phi.is_birational(), phi.is_injective() # optional - palp + sage: phi.is_surjective(), phi.is_birational(), phi.is_injective() (False, False, False) - sage: phi_i, phi_b, phi_s = phi.factor() # optional - palp - sage: phi_s.is_surjective(), phi_b.is_birational(), phi_i.is_injective() # optional - palp + sage: phi_i, phi_b, phi_s = phi.factor() + sage: phi_s.is_surjective(), phi_b.is_birational(), phi_i.is_injective() (True, True, True) - sage: prod(phi.factor()) == phi # optional - palp + sage: prod(phi.factor()) == phi True Double cover (surjective):: @@ -1801,26 +1811,26 @@ def factor(self): N(1, 0), N(0, 1) in 2-d lattice N - sage: phi_s # optional - palp + sage: phi_s # needs palp Fan morphism defined by the matrix [2 0] [1 1] Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in Sublattice <N(1, 0, 0), N(0, 1, 0)> - sage: phi_s.codomain_fan().rays() # optional - palp + sage: phi_s.codomain_fan().rays() # needs palp N(1, 0, 0), N(1, 1, 0) in Sublattice <N(1, 0, 0), N(0, 1, 0)> Blowup chart (birational):: - sage: phi_b # optional - palp + sage: phi_b # needs palp Fan morphism defined by the matrix [1 0] [0 1] Domain fan: Rational polyhedral fan in Sublattice <N(1, 0, 0), N(0, 1, 0)> Codomain fan: Rational polyhedral fan in Sublattice <N(1, 0, 0), N(0, 1, 0)> - sage: phi_b.codomain_fan().rays() # optional - palp + sage: phi_b.codomain_fan().rays() # needs palp N(-1, -1, 0), N( 0, 1, 0), N( 1, 0, 0) @@ -1828,13 +1838,13 @@ def factor(self): Coordinate plane inclusion (injective):: - sage: phi_i # optional - palp + sage: phi_i # needs palp Fan morphism defined by the matrix [1 0 0] [0 1 0] Domain fan: Rational polyhedral fan in Sublattice <N(1, 0, 0), N(0, 1, 0)> Codomain fan: Rational polyhedral fan in 3-d lattice N - sage: phi.codomain_fan().rays() # optional - palp + sage: phi.codomain_fan().rays() # needs palp N( 1, 0, 0), N( 0, 1, 0), N( 0, 0, 1), @@ -1843,20 +1853,21 @@ def factor(self): TESTS:: - sage: phi_s.matrix() * phi_b.matrix() * phi_i.matrix() == m # optional - palp + sage: phi_s.matrix() * phi_b.matrix() * phi_i.matrix() == m # needs palp True - sage: phi.domain_fan() is phi_s.domain_fan() # optional - palp + sage: # needs palp + sage: phi.domain_fan() is phi_s.domain_fan() True - sage: phi_s.codomain_fan() is phi_b.domain_fan() # optional - palp + sage: phi_s.codomain_fan() is phi_b.domain_fan() True - sage: phi_b.codomain_fan() is phi_i.domain_fan() # optional - palp + sage: phi_b.codomain_fan() is phi_i.domain_fan() True - sage: phi_i.codomain_fan() is phi.codomain_fan() # optional - palp + sage: phi_i.codomain_fan() is phi.codomain_fan() True - sage: trivialfan2 = Fan([],[],lattice=ToricLattice(2)) - sage: trivialfan3 = Fan([],[],lattice=ToricLattice(3)) + sage: trivialfan2 = Fan([], [], lattice=ToricLattice(2)) + sage: trivialfan3 = Fan([], [], lattice=ToricLattice(3)) sage: f = FanMorphism(zero_matrix(2,3), trivialfan2, trivialfan3) sage: [phi.matrix().dimensions() for phi in f.factor()] [(0, 3), (0, 0), (2, 0)] diff --git a/src/sage/geometry/hasse_diagram.py b/src/sage/geometry/hasse_diagram.py index eeed5f560d9..d30f08ac8d5 100644 --- a/src/sage/geometry/hasse_diagram.py +++ b/src/sage/geometry/hasse_diagram.py @@ -104,11 +104,9 @@ def lattice_from_incidences(atom_to_coatoms, coatom_to_atoms, and we can compute the lattice as :: sage: from sage.geometry.cone import lattice_from_incidences - sage: L = lattice_from_incidences( - ....: atom_to_coatoms, coatom_to_atoms) - sage: L + sage: L = lattice_from_incidences(atom_to_coatoms, coatom_to_atoms); L # needs sage.graphs Finite lattice containing 8 elements with distinguished linear extension - sage: for level in L.level_sets(): print(level) + sage: for level in L.level_sets(): print(level) # needs sage.graphs [((), (0, 1, 2))] [((0,), (0, 1)), ((1,), (0, 2)), ((2,), (1, 2))] [((0, 1), (0,)), ((0, 2), (1,)), ((1, 2), (2,))] diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py index 45c8efb11ed..9f6d5725f68 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py @@ -24,7 +24,7 @@ :: - sage: g.plot(axes=True) # optional - sage.plot + sage: g.plot(axes=True) # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -37,7 +37,7 @@ sage: g = HyperbolicPlane().UHP().get_geodesic(I, 3 + I) sage: g.length() arccosh(11/2) - sage: g.plot(axes=True) # optional - sage.plot + sage: g.plot(axes=True) # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -49,7 +49,7 @@ sage: g = HyperbolicPlane().UHP().get_geodesic(I, 3*I) sage: g Geodesic in UHP from I to 3*I - sage: g.plot() # optional - sage.plot + sage: g.plot() # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1126,7 +1126,7 @@ def plot(self, boundary=True, **options): EXAMPLES:: sage: UHP = HyperbolicPlane().UHP() - sage: UHP.get_geodesic(0, 1).plot() # optional - sage.plot + sage: UHP.get_geodesic(0, 1).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1137,7 +1137,7 @@ def plot(self, boundary=True, **options): :: - sage: UHP.get_geodesic(I, 3+4*I).plot(linestyle="dashed", color="brown") # optional - sage.plot + sage: UHP.get_geodesic(I, 3+4*I).plot(linestyle="dashed", color="brown") # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1148,7 +1148,7 @@ def plot(self, boundary=True, **options): :: - sage: UHP.get_geodesic(1, infinity).plot(color='orange') # optional - sage.plot + sage: UHP.get_geodesic(1, infinity).plot(color='orange') # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1162,25 +1162,25 @@ def plot(self, boundary=True, **options): Plotting a line with ``boundary=True``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(0, I) - sage: g.plot() # optional - sage.plot + sage: g.plot() # needs sage.plot Graphics object consisting of 2 graphics primitives Plotting a line with ``boundary=False``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(0, I) - sage: g.plot(boundary=False) # optional - sage.plot + sage: g.plot(boundary=False) # needs sage.plot Graphics object consisting of 1 graphics primitive Plotting a circle with ``boundary=True``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(-3, 19) - sage: g.plot() # optional - sage.plot + sage: g.plot() # needs sage.plot Graphics object consisting of 2 graphics primitives Plotting a circle with ``boundary=False``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(3, 4) - sage: g.plot(boundary=False) # optional - sage.plot + sage: g.plot(boundary=False) # needs sage.plot Graphics object consisting of 1 graphics primitive """ @@ -2202,7 +2202,7 @@ def plot(self, boundary=True, **options): First some lines:: sage: PD = HyperbolicPlane().PD() - sage: PD.get_geodesic(0, 1).plot() # optional - sage.plot + sage: PD.get_geodesic(0, 1).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -2211,7 +2211,7 @@ def plot(self, boundary=True, **options): :: - sage: PD.get_geodesic(0, 0.3+0.8*I).plot() # optional - sage.plot + sage: PD.get_geodesic(0, 0.3+0.8*I).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -2221,15 +2221,15 @@ def plot(self, boundary=True, **options): Then some generic geodesics:: - sage: PD.get_geodesic(-0.5, 0.3+0.4*I).plot() # optional - sage.plot + sage: PD.get_geodesic(-0.5, 0.3+0.4*I).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives sage: g = PD.get_geodesic(-1, exp(3*I*pi/7)) - sage: G = g.plot(linestyle="dashed",color="red"); G # optional - sage.plot + sage: G = g.plot(linestyle="dashed",color="red"); G # needs sage.plot Graphics object consisting of 2 graphics primitives sage: h = PD.get_geodesic(exp(2*I*pi/11), exp(1*I*pi/11)) - sage: H = h.plot(thickness=6, color="orange"); H # optional - sage.plot + sage: H = h.plot(thickness=6, color="orange"); H # needs sage.plot Graphics object consisting of 2 graphics primitives - sage: show(G+H) # optional - sage.plot + sage: show(G+H) # needs sage.plot .. PLOT:: @@ -2293,7 +2293,7 @@ class HyperbolicGeodesicKM(HyperbolicGeodesic): sage: KM = HyperbolicPlane().KM() sage: g = KM.get_geodesic((0.1,0.9),(-0.1,-0.9)) sage: h = KM.get_geodesic((-0.707106781,-0.707106781),(0.707106781,-0.707106781)) - sage: P = g.plot(color='orange')+h.plot(); P # optional - sage.plot + sage: P = g.plot(color='orange')+h.plot(); P # needs sage.plot Graphics object consisting of 4 graphics primitives .. PLOT:: @@ -2313,7 +2313,7 @@ def plot(self, boundary=True, **options): EXAMPLES:: - sage: HyperbolicPlane().KM().get_geodesic(0, 1).plot() # optional - sage.plot + sage: HyperbolicPlane().KM().get_geodesic(0, 1).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -2424,7 +2424,7 @@ def plot(self, show_hyperboloid=True, **graphics_options): sage: from sage.geometry.hyperbolic_space.hyperbolic_geodesic \ ....: import * sage: g = HyperbolicPlane().HM().random_geodesic() - sage: g.plot() # optional - sage.plot + sage: g.plot() # needs sage.plot Graphics3d Object .. PLOT:: diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py index 9e3e8d3fc88..2de12812ddc 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py @@ -218,7 +218,7 @@ def __hash__(self): if self.domain().is_isometry_group_projective(): # Special care must be taken for projective groups m = matrix(self._matrix.nrows(), - [abs(x) for x in self._matrix.list()]) + [abs(x) for x in self._matrix.list()]) m.set_immutable() else: m = self._matrix diff --git a/src/sage/calculus/__init__.py b/src/sage/geometry/hyperplane_arrangement/all.py similarity index 100% rename from src/sage/calculus/__init__.py rename to src/sage/geometry/hyperplane_arrangement/all.py diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index 4b18982f72e..7174a80ece5 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -66,8 +66,9 @@ Number fields are also possible:: - sage: x = var('x') - sage: NF.<a> = NumberField(x**4 - 5*x**2 + 5,embedding=1.90) + sage: # needs sage.rings.number_field + sage: x = polygen(QQ, 'x') + sage: NF.<a> = NumberField(x**4 - 5*x**2 + 5, embedding=1.90) sage: H.<y,z> = HyperplaneArrangements(NF) sage: A = H([[(-a**3 + 3*a, -a**2 + 4), 1], [(a**3 - 4*a, -1), 1], ....: [(0, 2*a**2 - 6), 1], [(-a**3 + 4*a, -1), 1], @@ -75,7 +76,8 @@ sage: A Arrangement of 5 hyperplanes of dimension 2 and rank 2 sage: A.base_ring() - Number Field in a with defining polynomial x^4 - 5*x^2 + 5 with a = 1.902113032590308? + Number Field in a with defining polynomial x^4 - 5*x^2 + 5 + with a = 1.902113032590308? Notation (iii): a list or tuple of hyperplanes:: @@ -88,11 +90,11 @@ Notation (iv): using the library of arrangements:: - sage: hyperplane_arrangements.braid(4) + sage: hyperplane_arrangements.braid(4) # needs sage.graphs Arrangement of 6 hyperplanes of dimension 4 and rank 3 sage: hyperplane_arrangements.semiorder(3) Arrangement of 6 hyperplanes of dimension 3 and rank 2 - sage: hyperplane_arrangements.graphical(graphs.PetersenGraph()) + sage: hyperplane_arrangements.graphical(graphs.PetersenGraph()) # needs sage.graphs Arrangement of 15 hyperplanes of dimension 10 and rank 9 sage: hyperplane_arrangements.Ish(5) Arrangement of 20 hyperplanes of dimension 5 and rank 4 @@ -106,6 +108,7 @@ New arrangements from old:: + sage: # needs sage.graphs sage: a = hyperplane_arrangements.braid(3) sage: b = a.add_hyperplane([4, 1, 2, 3]) sage: b @@ -114,15 +117,16 @@ sage: a == c True + sage: # needs sage.combinat sage.graphs sage: a = hyperplane_arrangements.braid(3) sage: b = a.union(hyperplane_arrangements.semiorder(3)) sage: b == a | hyperplane_arrangements.semiorder(3) # alternate syntax True sage: b == hyperplane_arrangements.Catalan(3) True - sage: a Arrangement <t1 - t2 | t0 - t1 | t0 - t2> + sage: a = hyperplane_arrangements.coordinate(4) sage: h = a.hyperplanes()[0] sage: b = a.restriction(h) @@ -138,6 +142,7 @@ normal space (actually, it is a bit more complicated over finite fields):: + sage: # needs sage.graphs sage: a = hyperplane_arrangements.braid(4); a Arrangement of 6 hyperplanes of dimension 4 and rank 3 sage: a.is_essential() @@ -202,6 +207,7 @@ The distance between regions is defined as the number of hyperplanes separating them. For example:: + sage: # needs sage.combinat sage: r1 = b.regions()[0] sage: r2 = b.regions()[1] sage: b.distance_between_regions(r1, r2) @@ -222,6 +228,7 @@ ordered by reverse inclusion. It includes the ambient space of the arrangement (as the intersection over the empty set):: + sage: # needs sage.graphs sage: a = hyperplane_arrangements.braid(3) sage: p = a.intersection_poset() sage: p.is_ranked() @@ -240,19 +247,20 @@ :meth:`~HyperplaneArrangementElement.intersection_poset` of the arrangement and `\mu` is the Mรถbius function of `P`:: + sage: # long time sage: a = hyperplane_arrangements.semiorder(5) - sage: a.characteristic_polynomial() # long time (about a second on Core i7) + sage: a.characteristic_polynomial() # about a second on Core i7 x^5 - 20*x^4 + 180*x^3 - 790*x^2 + 1380*x - sage: a.poincare_polynomial() # long time + sage: a.poincare_polynomial() 1380*x^4 + 790*x^3 + 180*x^2 + 20*x + 1 - sage: a.n_regions() # long time + sage: a.n_regions() 2371 - sage: charpoly = a.characteristic_polynomial() # long time - sage: charpoly(-1) # long time + sage: charpoly = a.characteristic_polynomial() + sage: charpoly(-1) -2371 - sage: a.n_bounded_regions() # long time + sage: a.n_bounded_regions() 751 - sage: charpoly(1) # long time + sage: charpoly(1) 751 For finer invariants derived from the intersection poset, see @@ -262,16 +270,16 @@ Miscellaneous methods (see documentation for an explanation):: sage: a = hyperplane_arrangements.semiorder(3) - sage: a.has_good_reduction(5) + sage: a.has_good_reduction(5) # needs sage.rings.finite_rings True sage: b = a.change_ring(GF(5)) - sage: pa = a.intersection_poset() - sage: pb = b.intersection_poset() - sage: pa.is_isomorphic(pb) + sage: pa = a.intersection_poset() # needs sage.graphs + sage: pb = b.intersection_poset() # needs sage.rings.finite_rings + sage: pa.is_isomorphic(pb) # needs sage.graphs sage.rings.finite_rings True - sage: a.face_vector() + sage: a.face_vector() # needs sage.graphs (0, 12, 30, 19) - sage: a.face_vector() + sage: a.face_vector() # needs sage.graphs (0, 12, 30, 19) sage: a.is_central() False @@ -356,7 +364,6 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.geometry.hyperplane_arrangement.hyperplane import AmbientVectorSpace, Hyperplane -from sage.combinat.posets.posets import Poset class HyperplaneArrangementElement(Element): @@ -394,13 +401,14 @@ def __init__(self, parent, hyperplanes, check=True, backend=None): It is possible to specify a backend for polyhedral computations:: - sage: R.<sqrt5> = QuadraticField(5) # optional - sage.rings.number_field - sage: H = HyperplaneArrangements(R, names='xyz') # optional - sage.rings.number_field - sage: x, y, z = H.gens() # optional - sage.rings.number_field - sage: A = H(sqrt5*x + 2*y + 3*z, backend='normaliz') # optional - sage.rings.number_field - sage: A.backend() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R.<sqrt5> = QuadraticField(5) + sage: H = HyperplaneArrangements(R, names='xyz') + sage: x, y, z = H.gens() + sage: A = H(sqrt5*x + 2*y + 3*z, backend='normaliz') + sage: A.backend() 'normaliz' - sage: A.regions()[0].backend() # optional - pynormaliz # optional - sage.rings.number_field + sage: A.regions()[0].backend() # optional - pynormaliz 'normaliz' """ super().__init__(parent) @@ -424,8 +432,8 @@ def _first_ngens(self, n): EXAMPLES:: - sage: a.<x,y,z> = hyperplane_arrangements.braid(3) # indirect doctest - sage: (x, y) == a._first_ngens(2) + sage: a.<x,y,z> = hyperplane_arrangements.braid(3) # indirect doctest # needs sage.graphs + sage: (x, y) == a._first_ngens(2) # needs sage.graphs True """ return self.parent()._first_ngens(n) @@ -570,6 +578,7 @@ def rank(self): sage: A.rank() 2 + sage: # needs sage.graphs sage: B = hyperplane_arrangements.braid(3) sage: B.hyperplanes() (Hyperplane 0*t0 + t1 - t2 + 0, @@ -689,7 +698,7 @@ def plot(self, **kwds): EXAMPLES:: sage: L.<x, y> = HyperplaneArrangements(QQ) - sage: L(x, y, x+y-2).plot() # optional - sage.plot + sage: L(x, y, x+y-2).plot() # needs sage.plot Graphics object consisting of 3 graphics primitives """ from sage.geometry.hyperplane_arrangement.plot import plot @@ -720,6 +729,7 @@ def cone(self, variable='t'): EXAMPLES:: + sage: # needs sage.combinat sage: a.<x,y,z> = hyperplane_arrangements.semiorder(3) sage: b = a.cone() sage: a.characteristic_polynomial().factor() @@ -781,15 +791,16 @@ def intersection_poset(self, element_label="int"): of hyperplanes of the arrangement. :: sage: A = hyperplane_arrangements.coordinate(2) - sage: L = A.intersection_poset(); L + sage: L = A.intersection_poset(); L # needs sage.combinat Finite poset containing 4 elements - sage: sorted(L) + sage: sorted(L) # needs sage.combinat [0, 1, 2, 3] - sage: L.level_sets() + sage: L.level_sets() # needs sage.combinat [[0], [1, 2], [3]] :: + sage: # needs sage.combinat sage: A = hyperplane_arrangements.semiorder(3) sage: L = A.intersection_poset(); L Finite poset containing 19 elements @@ -804,8 +815,8 @@ def intersection_poset(self, element_label="int"): index in ``self.hyperplanes()``. :: sage: A = hyperplane_arrangements.semiorder(3) - sage: L = A.intersection_poset(element_label='subset') - sage: [sorted(level, key=sorted) for level in L.level_sets()] + sage: L = A.intersection_poset(element_label='subset') # needs sage.combinat + sage: [sorted(level, key=sorted) for level in L.level_sets()] # needs sage.combinat [[{}], [{0}, {1}, {2}, {3}, {4}, {5}], [{0, 2}, {0, 3}, {0, 4}, {0, 5}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 4}, {2, 5}, {3, 4}, {3, 5}]] @@ -813,31 +824,32 @@ def intersection_poset(self, element_label="int"): :: sage: H.<x,y> = HyperplaneArrangements(QQ) - sage: A = H((y , (y-1) , (y+1) , (x - y) , (x + y))) - sage: L = A.intersection_poset(element_label='subset') - sage: sorted(L, key=sorted) + sage: A = H((y, y-1, y+1, x-y, x+y)) + sage: L = A.intersection_poset(element_label='subset') # needs sage.combinat + sage: sorted(L, key=sorted) # needs sage.combinat [{}, {0}, {0, 3}, {0, 4}, {1}, {1, 3, 4}, {2}, {2, 3}, {2, 4}, {3}, {4}] One can instead use affine subspaces as elements, which is what is used to compute the poset in the first place:: sage: A = hyperplane_arrangements.coordinate(2) - sage: L = A.intersection_poset(element_label='subspace'); L + sage: L = A.intersection_poset(element_label='subspace'); L # needs sage.combinat Finite poset containing 4 elements - sage: sorted(L, key=lambda S: (S.dimension(), S.linear_part().basis_matrix())) + sage: sorted(L, key=lambda S: (S.dimension(), # needs sage.combinat + ....: S.linear_part().basis_matrix())) [Affine space p + W where: p = (0, 0) W = Vector space of degree 2 and dimension 0 over Rational Field - Basis matrix: - [], Affine space p + W where: + Basis matrix: [], + Affine space p + W where: p = (0, 0) W = Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [0 1], Affine space p + W where: + Basis matrix: [0 1], + Affine space p + W where: p = (0, 0) W = Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 0], Affine space p + W where: + Basis matrix: [1 0], + Affine space p + W where: p = (0, 0) W = Vector space of dimension 2 over Rational Field] """ @@ -904,7 +916,7 @@ def _slow_characteristic_polynomial(self): EXAMPLES:: sage: a = hyperplane_arrangements.coordinate(2) - sage: a._slow_characteristic_polynomial() + sage: a._slow_characteristic_polynomial() # needs sage.combinat x^2 - 2*x + 1 """ from sage.rings.polynomial.polynomial_ring import polygen @@ -974,6 +986,177 @@ def poincare_polynomial(self): poincare = (-x)**self.dimension() * charpoly(-QQ(1)/x) return R(poincare) + @cached_method + def cocharacteristic_polynomial(self): + r""" + Return the cocharacteristic polynomial of ``self``. + + The cocharacteristic polynomial of a hyperplane arrangement `A` + is defined by + + .. MATH:: + + \Psi_A(z) := \sum_{X \in L} |\mu(B,X)| z^{\dim X}, + + where `L` is the intersection poset of `A`, `B` is the minimal + element of `L` (here, the `0` dimensional subspace), and + `\mu` is the Mรถbius function of `L`. + + OUTPUT: + + The cocharacteristic polynomial in `\ZZ[z]`. + + EXAMPLES:: + + sage: A = hyperplane_arrangements.coordinate(2) + sage: A.cocharacteristic_polynomial() + z^2 + 2*z + 1 + sage: B = hyperplane_arrangements.braid(3) + sage: B.cocharacteristic_polynomial() + 2*z^3 + 3*z^2 + z + + TESTS:: + + sage: I = hyperplane_arrangements.Ish(2) + sage: I.is_central() + False + sage: I.cocharacteristic_polynomial() + Traceback (most recent call last): + ... + ValueError: only defined for central hyperplane arrangements + """ + if not self.is_central(): + raise ValueError("only defined for central hyperplane arrangements") + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(ZZ, 'z') + z = R.gen() + L = self.intersection_poset(element_label="subspace").dual() + B = L.minimal_elements()[0] + return R.sum(abs(L.moebius_function(B, X)) * z**X.dimension() + for X in L) + + @cached_method + def primitive_eulerian_polynomial(self): + r""" + Return the primitive Eulerian polynomial of ``self``. + + The primitive Eulerian polynomial of a hyperplane arrangement `A` + is defined [BHS2023]_ by + + .. MATH:: + + P_A(z) := \sum_{X \in L} |\mu(B,X)| (z - 1)^{\mathrm{codim} X}, + + where `L` is the intersection poset of `A`, `B` is the minimal + element of `L` (here, the `0` dimensional subspace), and + `\mu` is the Mรถbius function of `L`. + + OUTPUT: + + The primitive Eulerian polynomial in `\ZZ[z]`. + + EXAMPLES:: + + sage: A = hyperplane_arrangements.coordinate(2) + sage: A.primitive_eulerian_polynomial() + z^2 + sage: B = hyperplane_arrangements.braid(3) + sage: B.primitive_eulerian_polynomial() + z^2 + z + + sage: H = hyperplane_arrangements.Shi(['B',2]).cone() + sage: H.is_simplicial() + False + sage: H.primitive_eulerian_polynomial() + z^3 + 11*z^2 + 4*z + + sage: H = hyperplane_arrangements.graphical(graphs.CycleGraph(4)) + sage: H.primitive_eulerian_polynomial() + z^3 + 3*z^2 - z + + We verify Example 2.4 in [BHS2023]_ for `k = 2,3,4,5`:: + + sage: R.<x,y> = HyperplaneArrangements(QQ) + sage: for k in range(2,6): + ....: H = R([x+j*y for j in range(k)]) + ....: H.primitive_eulerian_polynomial() + z^2 + z^2 + z + z^2 + 2*z + z^2 + 3*z + + We verify Equation (4) in [BHS2023]_ on some examples:: + + sage: R.<x> = ZZ[] + sage: Arr = [hyperplane_arrangements.braid(n) for n in range(2,6)] + sage: all(R(A.cocharacteristic_polynomial()(1/(x-1)) * (x-1)^A.dimension()) + ....: == R(A.primitive_eulerian_polynomial()) for A in Arr) + True + + We compute types `H_3` and `F_4` in Table 1 of [BHS2023]_:: + + sage: W = CoxeterGroup(['H',3], implementation="matrix") + sage: A = HyperplaneArrangements(W.base_ring(), tuple(f'x{s}' for s in range(W.rank()))) + sage: H = A([[0] + list(r) for r in W.positive_roots()]) + sage: H.is_simplicial() + True + sage: H.primitive_eulerian_polynomial() + z^3 + 28*z^2 + 16*z + + sage: W = CoxeterGroup(['F',4], implementation="permutation") + sage: A = HyperplaneArrangements(QQ, tuple(f'x{s}' for s in range(W.rank()))) + sage: H = A([[0] + list(r) for r in W.positive_roots()]) + sage: H.primitive_eulerian_polynomial() # long time + z^4 + 116*z^3 + 220*z^2 + 48*z + + We verify Proposition 2.5 in [BHS2023]_ on the braid arrangement + `B_k` for `k = 2,3,4,5`:: + + sage: B = [hyperplane_arrangements.braid(k) for k in range(2,6)] + sage: all(H.is_simplicial() for H in B) + True + sage: all(c > 0 for H in B for c in H.primitive_eulerian_polynomial().coefficients()) + True + + We verify Example 9.4 in [BHS2023]_ showing a hyperplane arrangement + whose primitive Eulerian polynomial does not have real roots (in + general, the graphical arrangement of a cycle graph corresponds + to the arrangements in Example 9.4):: + + sage: H = hyperplane_arrangements.graphical(graphs.CycleGraph(5)) + sage: pep = H.primitive_eulerian_polynomial(); pep + z^4 + 6*z^3 - 4*z^2 + z + sage: pep.roots(QQbar) + [(-6.626418492719221?, 1), + (0, 1), + (0.3132092463596102? - 0.2298065541510677?*I, 1), + (0.3132092463596102? + 0.2298065541510677?*I, 1)] + sage: pep.roots(AA) + [(-6.626418492719221?, 1), (0, 1)] + + TESTS:: + + sage: I = hyperplane_arrangements.Ish(2) + sage: I.is_central() + False + sage: I.primitive_eulerian_polynomial() + Traceback (most recent call last): + ... + ValueError: only defined for central hyperplane arrangements + """ + if not self.is_central(): + raise ValueError("only defined for central hyperplane arrangements") + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(ZZ, 'z') + z = R.gen() + L = self.intersection_poset(element_label="subspace").dual() + B = L.minimal_elements()[0] + n = self.dimension() + return R.sum(abs(L.moebius_function(B, X)) * (z - 1)**(n-X.dimension()) + for X in L) + def deletion(self, hyperplanes): r""" Return the hyperplane arrangement obtained by removing ``h``. @@ -1017,9 +1200,9 @@ def deletion(self, hyperplanes): Checks that deletion preserves the backend:: - sage: H = HyperplaneArrangements(QQ,names='xyz') + sage: H = HyperplaneArrangements(QQ, names='xyz') sage: x,y,z = H.gens() - sage: h1,h2 = [1*x+2*y+3*z,3*x+2*y+1*z] + sage: h1,h2 = [1*x+2*y+3*z, 3*x+2*y+1*z] sage: A = H(h1,h2,backend='normaliz') sage: A.deletion(h2).backend() 'normaliz' @@ -1049,6 +1232,7 @@ def restriction(self, hyperplane): EXAMPLES:: + sage: # needs sage.graphs sage: A.<u,x,y,z> = hyperplane_arrangements.braid(4); A Arrangement of 6 hyperplanes of dimension 4 and rank 3 sage: H = A[0]; H @@ -1073,9 +1257,9 @@ def restriction(self, hyperplane): Checks that restriction preserves the backend:: - sage: H = HyperplaneArrangements(QQ,names='xyz') + sage: H = HyperplaneArrangements(QQ, names='xyz') sage: x,y,z = H.gens() - sage: h1,h2 = [1*x+2*y+3*z,3*x+2*y+1*z] + sage: h1,h2 = [1*x+2*y+3*z, 3*x+2*y+1*z] sage: A = H(h1, h2, backend='normaliz') sage: A.restriction(h2).backend() 'normaliz' @@ -1136,9 +1320,9 @@ def change_ring(self, base_ring): Checks that changing the ring preserves the backend:: - sage: H = HyperplaneArrangements(QQ,names='xyz') + sage: H = HyperplaneArrangements(QQ, names='xyz') sage: x,y,z = H.gens() - sage: h1,h2 = [1*x+2*y+3*z,3*x+2*y+1*z] + sage: h1, h2 = [1*x+2*y+3*z, 3*x+2*y+1*z] sage: A = H(h1, h2, backend='normaliz') sage: A.change_ring(RDF).backend() 'normaliz' @@ -1173,17 +1357,23 @@ def n_regions(self): Check that :trac:`30749` is fixed:: + sage: # needs sage.rings.number_field sage: R.<y> = QQ[] - sage: v1 = AA.polynomial_root(AA.common_polynomial(y^2 - 3), RIF(RR(1.7320508075688772), RR(1.7320508075688774))) - sage: v2 = QQbar.polynomial_root(AA.common_polynomial(y^4 - y^2 + 1), CIF(RIF(RR(0.8660254037844386), RR(0.86602540378443871)), RIF(-RR(0.50000000000000011), -RR(0.49999999999999994)))) - sage: my_vectors = (vector(AA, [-v1, -1, 1]), vector(AA, [0, 2, 1]), vector(AA,[v1, -1, 1]), vector(AA, [1, 0, 0]), vector(AA, [1/2, AA(-1/2*v2^3 + v2),0]), vector(AA, [-1/2, AA(-1/2*v2^3 + v2), 0])) + sage: v1 = AA.polynomial_root(AA.common_polynomial(y^2 - 3), + ....: RIF(RR(1.7320508075688772), RR(1.7320508075688774))) + sage: v2 = QQbar.polynomial_root(AA.common_polynomial(y^4 - y^2 + 1), + ....: CIF(RIF(RR(0.8660254037844386), RR(0.86602540378443871)), + ....: RIF(-RR(0.50000000000000011), -RR(0.49999999999999994)))) + sage: my_vectors = (vector(AA, [-v1, -1, 1]), vector(AA, [0, 2, 1]), vector(AA, [v1, -1, 1]), + ....: vector(AA, [1, 0, 0]), vector(AA, [1/2, AA(-1/2*v2^3 + v2),0]), + ....: vector(AA, [-1/2, AA(-1/2*v2^3 + v2), 0])) sage: H = HyperplaneArrangements(AA, names='xyz') sage: x,y,z = H.gens() - sage: A = H(backend="normaliz") # optional - pynormaliz - sage: for v in my_vectors: # optional - pynormaliz + sage: A = H(backend="normaliz") # optional - pynormaliz + sage: for v in my_vectors: # optional - pynormaliz ....: a, b, c = v ....: A = A.add_hyperplane(a*x + b*y + c*z) - sage: A.n_regions() # optional - pynormaliz + sage: A.n_regions() # optional - pynormaliz 24 """ if self.base_ring().characteristic() != 0: @@ -1242,6 +1432,7 @@ def has_good_reduction(self, p): EXAMPLES:: + sage: # needs sage.combinat sage: a = hyperplane_arrangements.semiorder(3) sage: a.has_good_reduction(5) True @@ -1276,8 +1467,8 @@ def is_linear(self): sage: a = hyperplane_arrangements.semiorder(3) sage: a.is_linear() False - sage: b = hyperplane_arrangements.braid(3) - sage: b.is_linear() + sage: b = hyperplane_arrangements.braid(3) # needs sage.graphs + sage: b.is_linear() # needs sage.graphs True sage: H.<x,y> = HyperplaneArrangements(QQ) @@ -1339,8 +1530,8 @@ def is_central(self, certificate=False): EXAMPLES:: - sage: a = hyperplane_arrangements.braid(2) - sage: a.is_central() + sage: a = hyperplane_arrangements.braid(2) # needs sage.graphs + sage: a.is_central() # needs sage.graphs True The Catalan arrangement in dimension 3 is not central:: @@ -1351,11 +1542,11 @@ def is_central(self, certificate=False): The empty arrangement in dimension 5 is central:: - sage: H = HyperplaneArrangements(QQ,names=tuple(['x'+str(i) for i in range(7)])) + sage: H = HyperplaneArrangements(QQ, names=tuple(['x'+str(i) for i in range(7)])) sage: c = H() sage: c.is_central(certificate=True) - (True, A 7-dimensional polyhedron in QQ^7 defined as the convex - hull of 1 vertex and 7 lines) + (True, A 7-dimensional polyhedron in QQ^7 defined + as the convex hull of 1 vertex and 7 lines) """ R = self.base_ring() # If there are no hyperplanes in the arrangement, @@ -1422,8 +1613,8 @@ def center(self): The Braid arrangement in dimension 3 has a center that is neither empty nor full-dimensional:: - sage: A = hyperplane_arrangements.braid(3) - sage: A.center() + sage: A = hyperplane_arrangements.braid(3) # needs sage.combinat + sage: A.center() # needs sage.combinat A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line """ return self.is_central(certificate=True)[1] @@ -1444,16 +1635,16 @@ def is_simplicial(self): EXAMPLES:: sage: H.<x,y,z> = HyperplaneArrangements(QQ) - sage: A = H([[0,1,1,1],[0,1,2,3]]) + sage: A = H([[0,1,1,1], [0,1,2,3]]) sage: A.is_simplicial() True - sage: A = H([[0,1,1,1],[0,1,2,3],[0,1,3,2]]) + sage: A = H([[0,1,1,1], [0,1,2,3], [0,1,3,2]]) sage: A.is_simplicial() True - sage: A = H([[0,1,1,1],[0,1,2,3],[0,1,3,2],[0,2,1,3]]) + sage: A = H([[0,1,1,1], [0,1,2,3], [0,1,3,2], [0,2,1,3]]) sage: A.is_simplicial() False - sage: hyperplane_arrangements.braid(3).is_simplicial() + sage: hyperplane_arrangements.braid(3).is_simplicial() # needs sage.graphs True """ # if the arr is not essential, grab the essential version and check there. @@ -1479,10 +1670,10 @@ def essentialization(self): EXAMPLES:: - sage: a = hyperplane_arrangements.braid(3) - sage: a.is_essential() + sage: a = hyperplane_arrangements.braid(3) # needs sage.graphs + sage: a.is_essential() # needs sage.graphs False - sage: a.essentialization() + sage: a.essentialization() # needs sage.graphs Arrangement <t1 - t2 | t1 + 2*t2 | 2*t1 + t2> sage: H.<x,y> = HyperplaneArrangements(QQ) @@ -1617,7 +1808,7 @@ def face_vector(self): EXAMPLES:: sage: A = hyperplane_arrangements.Shi(3) - sage: A.face_vector() + sage: A.face_vector() # needs sage.combinat (0, 6, 21, 16) """ m = self.whitney_data()[0] @@ -1699,6 +1890,7 @@ def vertices(self, exclude_sandwiched=False): EXAMPLES:: + sage: # needs sage.combinat sage: A = hyperplane_arrangements.Shi(3).essentialization() sage: A.dimension() 2 @@ -1706,14 +1898,14 @@ def vertices(self, exclude_sandwiched=False): (6, 21, 16) sage: A.vertices() ((-2/3, 1/3), (-1/3, -1/3), (0, -1), (0, 0), (1/3, -2/3), (2/3, -1/3)) - sage: point2d(A.vertices(), size=20) + A.plot() # optional - sage.plot + sage: point2d(A.vertices(), size=20) + A.plot() # needs sage.plot Graphics object consisting of 7 graphics primitives sage: H.<x,y> = HyperplaneArrangements(QQ) sage: chessboard = [] sage: N = 8 - sage: for x0 in range(N+1): - ....: for y0 in range(N+1): + sage: for x0 in range(N + 1): + ....: for y0 in range(N + 1): ....: chessboard.extend([x-x0, y-y0]) sage: chessboard = H(chessboard) sage: len(chessboard.vertices()) @@ -1722,7 +1914,7 @@ def vertices(self, exclude_sandwiched=False): ((0, 0), (0, 8), (8, 0), (8, 8)) """ import itertools - from sage.matroids.all import Matroid + from sage.matroids.constructor import Matroid R = self.parent().base_ring() parallels = self._parallel_hyperplanes() A_list = [parallel[0][1] for parallel in parallels] @@ -1776,8 +1968,8 @@ def _make_region(self, hyperplanes): Checks that it creates the regions with the appropriate backend:: - sage: h = H(x,backend='normaliz') # optional - pynormaliz - sage: h._make_region([x, 1-x, y, 1-y]).backend() # optional - pynormaliz + sage: h = H(x,backend='normaliz') + sage: h._make_region([x, 1-x, y, 1-y]).backend() # optional - pynormaliz 'normaliz' """ ieqs = [h.dense_coefficient_list() for h in hyperplanes] @@ -1802,23 +1994,29 @@ def regions(self): EXAMPLES:: - sage: a = hyperplane_arrangements.braid(2) - sage: a.regions() - (A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line) + sage: a = hyperplane_arrangements.braid(2) # needs sage.graphs + sage: a.regions() # needs sage.graphs + (A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex, 1 ray, 1 line, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex, 1 ray, 1 line) sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H(x, y+1) sage: A.regions() - (A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays) + (A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays) sage: chessboard = [] sage: N = 8 - sage: for x0 in range(N+1): - ....: for y0 in range(N+1): + sage: for x0 in range(N + 1): + ....: for y0 in range(N + 1): ....: chessboard.extend([x-x0, y-y0]) sage: chessboard = H(chessboard) sage: len(chessboard.bounded_regions()) # long time, 359 ms on a Core i7 @@ -1829,9 +2027,9 @@ def regions(self): sage: from itertools import product sage: def zero_one(d): ....: for x in product([0,1], repeat=d): - ....: if any(y for y in x): + ....: if any(x): ....: yield [0] + list(x) - ....: + sage: K.<x,y> = HyperplaneArrangements(QQ) sage: A = K(*zero_one(2)) sage: len(A.regions()) @@ -1851,20 +2049,22 @@ def regions(self): It is possible to specify the backend:: + sage: # needs sage.rings.number_field sage: K.<q> = CyclotomicField(9) - sage: L.<r9> = NumberField((q+q**(-1)).minpoly(),embedding = AA(q+q**-1)) - sage: norms = [[1,1/3*(-2*r9**2-r9+1),0], - ....: [1,-r9**2-r9,0], - ....: [1,-r9**2+1,0], - ....: [1,-r9**2,0], - ....: [1,r9**2-4,-r9**2+3]] + sage: L.<r9> = NumberField((q + q**(-1)).minpoly(), + ....: embedding=AA(q + q**-1)) + sage: norms = [[1, 1/3*(-2*r9**2-r9+1), 0], + ....: [1, -r9**2 - r9, 0], + ....: [1, -r9**2 + 1, 0], + ....: [1, -r9**2, 0], + ....: [1, r9**2 - 4, -r9**2+3]] sage: H.<x,y,z> = HyperplaneArrangements(L) sage: A = H(backend='normaliz') sage: for v in norms: ....: a,b,c = v ....: A = A.add_hyperplane(a*x + b*y + c*z) - sage: R = A.regions() # optional - pynormaliz - sage: R[0].backend() # optional - pynormaliz + sage: R = A.regions() # optional - pynormaliz + sage: R[0].backend() # optional - pynormaliz 'normaliz' TESTS:: @@ -1872,7 +2072,8 @@ def regions(self): sage: K.<x,y,z,w,r> = HyperplaneArrangements(QQ) sage: A = K() sage: A.regions() - (A 5-dimensional polyhedron in QQ^5 defined as the convex hull of 1 vertex and 5 lines,) + (A 5-dimensional polyhedron in QQ^5 + defined as the convex hull of 1 vertex and 5 lines,) """ if self.base_ring().characteristic() != 0: raise ValueError('base field must have characteristic zero') @@ -1930,7 +2131,7 @@ def regions(self): # In this case, at least one of the vertices is not on the hyperplane. # So we check if any ray or line pokes the hyperplane. if ( any(ieq[1:]*r[:]*direction < 0 for r in region.rays()) or - any(ieq[1:]*l[:] != 0 for l in region_lines)): + any(ieq[1:]*l[:] != 0 for l in region_lines)): splits = True if splits: @@ -1972,10 +2173,11 @@ def poset_of_regions(self, B=None, numbered_labels=True): EXAMPLES:: sage: H.<x,y,z> = HyperplaneArrangements(QQ) - sage: A = H([[0,1,1,1],[0,1,2,3]]) - sage: A.poset_of_regions() + sage: A = H([[0,1,1,1], [0,1,2,3]]) + sage: A.poset_of_regions() # needs sage.combinat Finite poset containing 4 elements + sage: # needs sage.combinat sage.graphs sage: A = hyperplane_arrangements.braid(3) sage: A.poset_of_regions() Finite poset containing 6 elements @@ -1986,12 +2188,14 @@ def poset_of_regions(self, B=None, numbered_labels=True): Finite poset containing 24 elements sage: H.<x,y,z> = HyperplaneArrangements(QQ) - sage: A = H([[0,1,1,1],[0,1,2,3],[0,1,3,2],[0,2,1,3]]) + sage: A = H([[0,1,1,1], [0,1,2,3], [0,1,3,2], [0,2,1,3]]) sage: R = A.regions() sage: base_region = R[3] - sage: A.poset_of_regions(B=base_region) + sage: A.poset_of_regions(B=base_region) # needs sage.combinat Finite poset containing 14 elements """ + from sage.combinat.posets.posets import Poset + # We use RX to keep track of indexes and R to keep track of which regions # we've already hit. This poset is graded, so we can go one set at a time RX = self.regions() @@ -2092,109 +2296,88 @@ def closed_faces(self, labelled=True): EXAMPLES:: + sage: # needs sage.graphs sage: a = hyperplane_arrangements.braid(2) sage: a.hyperplanes() (Hyperplane t0 - t1 + 0,) sage: a.closed_faces() - (((0,), - A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line), - ((1,), - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line), - ((-1,), - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line)) + (((0,), A 1-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 1 line), + ((1,), A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex, 1 ray, 1 line), + ((-1,), A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex, 1 ray, 1 line)) sage: a.closed_faces(labelled=False) - (A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line) + (A 1-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 1 line, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex, 1 ray, 1 line, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex, 1 ray, 1 line) sage: [(v, F, F.representative_point()) for v, F in a.closed_faces()] - [((0,), - A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line, - (0, 0)), - ((1,), - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line, - (0, -1)), - ((-1,), - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line, - (-1, 0))] + [((0,), A 1-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 1 line, (0, 0)), + ((1,), A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex, 1 ray, 1 line, (0, -1)), + ((-1,), A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex, 1 ray, 1 line, (-1, 0))] sage: H.<x,y> = HyperplaneArrangements(QQ) sage: a = H(x, y+1) sage: a.hyperplanes() (Hyperplane 0*x + y + 1, Hyperplane x + 0*y + 0) sage: [(v, F, F.representative_point()) for v, F in a.closed_faces()] - [((0, 0), - A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, - (0, -1)), - ((0, 1), - A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray, - (1, -1)), - ((0, -1), - A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray, - (-1, -1)), - ((1, 0), - A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray, - (0, 0)), - ((1, 1), - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - (1, 0)), - ((1, -1), - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - (-1, 0)), - ((-1, 0), - A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray, - (0, -2)), - ((-1, 1), - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - (1, -2)), - ((-1, -1), - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - (-1, -2))] - - sage: a = hyperplane_arrangements.braid(3) - sage: a.hyperplanes() + [((0, 0), A 0-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex, (0, -1)), + ((0, 1), A 1-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 1 ray, (1, -1)), + ((0, -1), A 1-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 1 ray, (-1, -1)), + ((1, 0), A 1-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 1 ray, (0, 0)), + ((1, 1), A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, (1, 0)), + ((1, -1), A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, (-1, 0)), + ((-1, 0), A 1-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 1 ray, (0, -2)), + ((-1, 1), A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, (1, -2)), + ((-1, -1), A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, (-1, -2))] + + sage: a = hyperplane_arrangements.braid(3) # needs sage.graphs + sage: a.hyperplanes() # needs sage.graphs (Hyperplane 0*t0 + t1 - t2 + 0, Hyperplane t0 - t1 + 0*t2 + 0, Hyperplane t0 + 0*t1 - t2 + 0) - sage: [(v, F, F.representative_point()) for v, F in a.closed_faces()] - [((0, 0, 0), - A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line, - (0, 0, 0)), - ((0, 1, 1), - A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, - (0, -1, -1)), - ((0, -1, -1), - A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, - (-1, 0, 0)), - ((1, 0, 1), - A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, - (1, 1, 0)), - ((1, 1, 1), - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, - (0, -1, -2)), - ((1, -1, 0), - A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, - (-1, 0, -1)), - ((1, -1, 1), - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, - (1, 2, 0)), - ((1, -1, -1), - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, - (-2, 0, -1)), - ((-1, 0, -1), - A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, - (0, 0, 1)), - ((-1, 1, 0), - A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, - (1, 0, 1)), - ((-1, 1, 1), - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, - (0, -2, -1)), - ((-1, 1, -1), - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, - (1, 0, 2)), - ((-1, -1, -1), - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, - (-1, 0, 1))] + sage: [(v, F, F.representative_point()) for v, F in a.closed_faces()] # needs sage.graphs + [((0, 0, 0), A 1-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex and 1 line, (0, 0, 0)), + ((0, 1, 1), A 2-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 1 ray, 1 line, (0, -1, -1)), + ((0, -1, -1), A 2-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 1 ray, 1 line, (-1, 0, 0)), + ((1, 0, 1), A 2-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 1 ray, 1 line, (1, 1, 0)), + ((1, 1, 1), A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 2 rays, 1 line, (0, -1, -2)), + ((1, -1, 0), A 2-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 1 ray, 1 line, (-1, 0, -1)), + ((1, -1, 1), A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 2 rays, 1 line, (1, 2, 0)), + ((1, -1, -1), A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 2 rays, 1 line, (-2, 0, -1)), + ((-1, 0, -1), A 2-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 1 ray, 1 line, (0, 0, 1)), + ((-1, 1, 0), A 2-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 1 ray, 1 line, (1, 0, 1)), + ((-1, 1, 1), A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 2 rays, 1 line, (0, -2, -1)), + ((-1, 1, -1), A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 2 rays, 1 line, (1, 0, 2)), + ((-1, -1, -1), A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 1 vertex, 2 rays, 1 line, (-1, 0, 1))] Let us check that the number of closed faces with a given dimension computed using ``self.closed_faces()`` equals the one @@ -2206,10 +2389,10 @@ def closed_faces(self, labelled=True): ....: LHS = Qx.sum(x ** F[1].dim() for F in a.closed_faces()) ....: return LHS == RHS sage: a = hyperplane_arrangements.Catalan(2) - sage: test_number(a) + sage: test_number(a) # needs sage.combinat True sage: a = hyperplane_arrangements.Shi(3) - sage: test_number(a) # long time + sage: test_number(a) # long time # needs sage.combinat True TESTS: @@ -2344,26 +2527,27 @@ def face_product(self, F, G, normalize=True): EXAMPLES:: + sage: # needs sage.graphs sage: a = hyperplane_arrangements.braid(3) sage: a.hyperplanes() (Hyperplane 0*t0 + t1 - t2 + 0, Hyperplane t0 - t1 + 0*t2 + 0, Hyperplane t0 + 0*t1 - t2 + 0) sage: faces = {F0: F1 for F0, F1 in a.closed_faces()} - sage: xGyEz = faces[(0, 1, 1)] # closed face x >= y = z + sage: xGyEz = faces[(0, 1, 1)] # closed face x >= y = z sage: xGyEz.representative_point() (0, -1, -1) - sage: xGyEz = faces[(0, 1, 1)] # closed face x >= y = z + sage: xGyEz = faces[(0, 1, 1)] # closed face x >= y = z sage: xGyEz.representative_point() (0, -1, -1) - sage: yGxGz = faces[(1, -1, 1)] # closed face y >= x >= z - sage: xGyGz = faces[(1, 1, 1)] # closed face x >= y >= z + sage: yGxGz = faces[(1, -1, 1)] # closed face y >= x >= z + sage: xGyGz = faces[(1, 1, 1)] # closed face x >= y >= z sage: a.face_product(xGyEz, yGxGz) == xGyGz True sage: a.face_product(yGxGz, xGyEz) == yGxGz True - sage: xEzGy = faces[(-1, 1, 0)] # closed face x = z >= y - sage: xGzGy = faces[(-1, 1, 1)] # closed face x >= z >= y + sage: xEzGy = faces[(-1, 1, 0)] # closed face x = z >= y + sage: xGzGy = faces[(-1, 1, 1)] # closed face x >= z >= y sage: a.face_product(xEzGy, yGxGz) == xGzGy True """ @@ -2439,6 +2623,7 @@ def face_semigroup_algebra(self, field=None, names='e'): EXAMPLES:: + sage: # needs sage.graphs sage: a = hyperplane_arrangements.braid(3) sage: [(i, F[0]) for i, F in enumerate(a.closed_faces())] [(0, (0, 0, 0)), @@ -2480,13 +2665,14 @@ def face_semigroup_algebra(self, field=None, names='e'): sage: (e3 + 2*e4) * (e1 - e7) e4 - e6 - sage: U3 = a.face_semigroup_algebra(field=GF(3)); U3 + sage: U3 = a.face_semigroup_algebra(field=GF(3)); U3 # needs sage.graphs sage.rings.finite_rings Finite-dimensional algebra of degree 13 over Finite Field of size 3 TESTS: The ``names`` keyword works:: + sage: # needs sage.graphs sage: a = hyperplane_arrangements.braid(3) sage: U = a.face_semigroup_algebra(names='x'); U Finite-dimensional algebra of degree 13 over Rational Field @@ -2545,7 +2731,8 @@ def region_containing_point(self, p): sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H([(1,0), 0], [(0,1), 1], [(0,1), -1], [(1,-1), 0], [(1,1), 0]) sage: A.region_containing_point([1,2]) - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 2 vertices and 2 rays TESTS:: @@ -2625,15 +2812,23 @@ def bounded_regions(self): EXAMPLES:: + sage: # needs sage.combinat sage: A = hyperplane_arrangements.semiorder(3) sage: A.bounded_regions() - (A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line, - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line, - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line, - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 6 vertices and 1 line, - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line, - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line, - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line) + (A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 3 vertices and 1 line, + A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 3 vertices and 1 line, + A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 3 vertices and 1 line, + A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 6 vertices and 1 line, + A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 3 vertices and 1 line, + A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 3 vertices and 1 line, + A 3-dimensional polyhedron in QQ^3 defined + as the convex hull of 3 vertices and 1 line) sage: A.bounded_regions()[0].is_compact() # the regions are only *relatively* bounded False sage: A.is_essential() @@ -2657,23 +2852,36 @@ def unbounded_regions(self): EXAMPLES:: + sage: # needs sage.combinat sage: A = hyperplane_arrangements.semiorder(3) sage: B = A.essentialization() sage: B.n_regions() - B.n_bounded_regions() 12 sage: B.unbounded_regions() - (A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays) + (A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 3 vertices and 1 ray, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 3 vertices and 1 ray, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 3 vertices and 1 ray, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 3 vertices and 1 ray, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 3 vertices and 1 ray, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 3 vertices and 1 ray, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays, + A 2-dimensional polyhedron in QQ^2 defined + as the convex hull of 1 vertex and 2 rays) """ s = set(range(self.n_regions())).difference(set(self._bounded_region_indices())) return tuple(self.regions()[i] for i in s) @@ -2698,7 +2906,7 @@ def whitney_data(self): EXAMPLES:: sage: A = hyperplane_arrangements.Shi(3) - sage: A.whitney_data() + sage: A.whitney_data() # needs sage.combinat ( [ 1 -6 9] [ 1 6 6] [ 0 6 -15] [ 0 6 15] @@ -2747,6 +2955,7 @@ def doubly_indexed_whitney_number(self, i, j, kind=1): EXAMPLES:: + sage: # needs sage.combinat sage: A = hyperplane_arrangements.Shi(3) sage: A.doubly_indexed_whitney_number(0, 2) 9 @@ -2797,6 +3006,7 @@ def whitney_number(self, k, kind=1): EXAMPLES:: + sage: # needs sage.combinat sage: A = hyperplane_arrangements.Shi(3) sage: A.whitney_number(0) 1 @@ -2806,7 +3016,7 @@ def whitney_number(self, k, kind=1): 9 sage: A.characteristic_polynomial() x^3 - 6*x^2 + 9*x - sage: A.whitney_number(1,kind=2) + sage: A.whitney_number(1, kind=2) 6 sage: p = A.intersection_poset() sage: r = p.rank_function() @@ -2990,9 +3200,9 @@ def matroid(self): We check the lattice of flats is isomorphic to the intersection lattice:: - sage: f = sum([list(M.flats(i)) for i in range(M.rank()+1)], []) - sage: PF = Poset([f, lambda x,y: x < y]) - sage: PF.is_isomorphic(A.intersection_poset()) + sage: f = sum([list(M.flats(i)) for i in range(M.rank() + 1)], []) + sage: PF = Poset([f, lambda x, y: x < y]) # needs sage.combinat + sage: PF.is_isomorphic(A.intersection_poset()) # needs sage.combinat True """ if not self.is_central(): @@ -3082,7 +3292,8 @@ def minimal_generated_number(self): Check that :trac:`26705` is fixed:: - sage: w = WeylGroup(['A',4]).from_reduced_word([3,4,2,1]) + sage: # needs sage.combinat sage.groups + sage: w = WeylGroup(['A', 4]).from_reduced_word([3, 4, 2, 1]) sage: I = w.inversion_arrangement() sage: I Arrangement <a4 | a1 | a1 + a2 | a1 + a2 + a3 + a4> @@ -3170,9 +3381,9 @@ def derivation_module_free_chain(self): EXAMPLES:: - sage: W = WeylGroup(['A',3], prefix='s') - sage: A = W.long_element().inversion_arrangement() - sage: for M in A.derivation_module_free_chain(): print("%s\n"%M) + sage: W = WeylGroup(['A',3], prefix='s') # needs sage.combinat sage.groups + sage: A = W.long_element().inversion_arrangement() # needs sage.combinat sage.groups + sage: for M in A.derivation_module_free_chain(): print("%s\n"%M) # needs sage.combinat sage.groups [ 1 0 0] [ 0 1 0] [ 0 0 a3] @@ -3246,8 +3457,8 @@ def is_free(self, algorithm="singular"): For type `A` arrangements, chordality is equivalent to freeness. We verify that in type `A_3`:: - sage: W = WeylGroup(['A',3], prefix='s') - sage: for x in W: + sage: W = WeylGroup(['A', 3], prefix='s') # needs sage.combinat sage.groups + sage: for x in W: # needs sage.combinat sage.groups ....: A = x.inversion_arrangement() ....: assert A.matroid().is_chordal() == A.is_free() @@ -3255,8 +3466,8 @@ def is_free(self, algorithm="singular"): We check that the algorithms agree:: - sage: W = WeylGroup(['B',3], prefix='s') - sage: for x in W: # long time + sage: W = WeylGroup(['B', 3], prefix='s') # needs sage.combinat sage.groups + sage: for x in W: # long time # needs sage.combinat sage.groups ....: A = x.inversion_arrangement() ....: assert (A.is_free(algorithm="BC") ....: == A.is_free(algorithm="singular")) @@ -3315,19 +3526,19 @@ def derivation_module_basis(self, algorithm="singular"): EXAMPLES:: - sage: W = WeylGroup(['A',2], prefix='s') - sage: A = W.long_element().inversion_arrangement() - sage: A.derivation_module_basis() + sage: W = WeylGroup(['A', 2], prefix='s') # needs sage.combinat sage.groups + sage: A = W.long_element().inversion_arrangement() # needs sage.combinat sage.groups + sage: A.derivation_module_basis() # needs sage.combinat sage.groups [(a1, a2), (0, a1*a2 + a2^2)] TESTS: We check the algorithms produce a basis with the same exponents:: - sage: W = WeylGroup(['A',2], prefix='s') - sage: exponents = lambda B: sorted([max(x.degree() for x in b) - ....: for b in B]) - sage: for x in W: # long time + sage: W = WeylGroup(['A', 2], prefix='s') # needs sage.combinat sage.groups + sage: def exponents(B): + ....: return sorted([max(x.degree() for x in b) for b in B]) + sage: for x in W: # long time # needs sage.combinat sage.groups ....: A = x.inversion_arrangement() ....: B = A.derivation_module_basis(algorithm="singular") ....: Bp = A.derivation_module_basis(algorithm="BC") @@ -3619,7 +3830,8 @@ def ngens(self): EXAMPLES:: sage: L.<x, y, z> = HyperplaneArrangements(QQ); L - Hyperplane arrangements in 3-dimensional linear space over Rational Field with coordinates x, y, z + Hyperplane arrangements in 3-dimensional linear space + over Rational Field with coordinates x, y, z sage: L.ngens() 3 """ @@ -3659,7 +3871,8 @@ def gen(self, i): EXAMPLES:: sage: L.<x, y, z> = HyperplaneArrangements(QQ); L - Hyperplane arrangements in 3-dimensional linear space over Rational Field with coordinates x, y, z + Hyperplane arrangements in + 3-dimensional linear space over Rational Field with coordinates x, y, z sage: L.gen(0) Hyperplane x + 0*y + 0*z + 0 """ diff --git a/src/sage/geometry/hyperplane_arrangement/check_freeness.py b/src/sage/geometry/hyperplane_arrangement/check_freeness.py index 30f963612ec..e99c8ee9b39 100644 --- a/src/sage/geometry/hyperplane_arrangement/check_freeness.py +++ b/src/sage/geometry/hyperplane_arrangement/check_freeness.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.libs.singular r""" Helper Functions For Freeness Of Hyperplane Arrangements diff --git a/src/sage/geometry/hyperplane_arrangement/hyperplane.py b/src/sage/geometry/hyperplane_arrangement/hyperplane.py index c431291a3a6..8d4b301f8d8 100644 --- a/src/sage/geometry/hyperplane_arrangement/hyperplane.py +++ b/src/sage/geometry/hyperplane_arrangement/hyperplane.py @@ -397,6 +397,7 @@ def point(self): sage: h.point() in h True + sage: # needs sage.rings.finite_rings sage: H.<x,y,z> = HyperplaneArrangements(GF(3)) sage: h = 2*x + y + z + 1 sage: h.point() @@ -552,6 +553,7 @@ def primitive(self, signed=True): Check that :trac:`30078` is fixed:: + sage: # needs sage.rings.number_field sage: R.<sqrt2> = QuadraticField(2) sage: H.<x,y> = HyperplaneArrangements(base_ring=R) sage: B = H([1,1,0], [2,2,0], [sqrt2,sqrt2,0]) @@ -560,6 +562,7 @@ def primitive(self, signed=True): Check that :trac:`30749` is fixed:: + sage: # needs sage.rings.number_field sage: tau = (1+AA(5).sqrt()) / 2 sage: ncn = [[2*tau+1,2*tau,tau],[2*tau+2,2*tau+1,tau+1]] sage: ncn += [[tau+1,tau+1,tau],[2*tau,2*tau,tau],[tau+1,tau+1,1]] @@ -638,7 +641,7 @@ def plot(self, **kwds): EXAMPLES:: sage: L.<x, y> = HyperplaneArrangements(QQ) - sage: (x+y-2).plot() # optional - sage.plot + sage: (x + y - 2).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives """ from sage.geometry.hyperplane_arrangement.plot import plot_hyperplane diff --git a/src/sage/geometry/hyperplane_arrangement/library.py b/src/sage/geometry/hyperplane_arrangement/library.py index 0334593a889..4ec9f9fdbdf 100644 --- a/src/sage/geometry/hyperplane_arrangement/library.py +++ b/src/sage/geometry/hyperplane_arrangement/library.py @@ -5,12 +5,12 @@ :mod:`sage.geometry.hyperplane_arrangement.arrangement` for details about how to construct your own hyperplane arrangements. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 David Perkinson <davidp@reed.edu> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.graphs.graph_generators import graphs from sage.matrix.constructor import matrix, random_matrix @@ -65,7 +65,6 @@ def make_parent(base_ring, dimension, names=None): return HyperplaneArrangements(base_ring, names=names) - class HyperplaneArrangementLibrary(): """ The library of hyperplane arrangements. @@ -91,7 +90,7 @@ def braid(self, n, K=QQ, names=None): EXAMPLES:: - sage: hyperplane_arrangements.braid(4) + sage: hyperplane_arrangements.braid(4) # needs sage.graphs Arrangement of 6 hyperplanes of dimension 4 and rank 3 """ x = polygen(QQ, 'x') @@ -125,6 +124,7 @@ def bigraphical(self, G, A=None, K=QQ, names=None): EXAMPLES:: + sage: # needs sage.graphs sage: G = graphs.CycleGraph(4) sage: G.edges(sort=True) [(0, 1, None), (0, 3, None), (1, 2, None), (2, 3, None)] @@ -233,6 +233,86 @@ def coordinate(self, n, K=QQ, names=None): x = H.gens() return H(x) + def Coxeter(self, data, K=QQ, names=None): + r""" + Return the Coxeter arrangement. + + This generalizes the braid arrangements to crystallographic + root systems. + + INPUT: + + - ``data`` -- either an integer or a Cartan type (or coercible + into; see "CartanType") + + - ``K`` -- field (default:``QQ``) + + - ``names`` -- tuple of strings or ``None`` (default); the + variable names for the ambient space + + OUTPUT: + + - If ``data`` is an integer `n`, return the braid arrangement in + dimension `n`, i.e. the set of `n(n-1)` hyperplanes: + `\{ x_i - x_j = 0,1 : 1 \leq i \leq j \leq n \}`. This corresponds + to the Coxeter arrangement of Cartan type `A_{n-1}`. + + - If ``data`` is a Cartan type, return the Coxeter arrangement of given + type. + + The Coxeter arrangement of a given crystallographic + Cartan type is defined by the inner products + `\langle a,x \rangle = 0` where + `a \in \Phi^+` runs over positive roots of the root system `\Phi`. + + EXAMPLES:: + + sage: # needs sage.combinat + sage: hyperplane_arrangements.Coxeter(4) + Arrangement of 6 hyperplanes of dimension 4 and rank 3 + sage: hyperplane_arrangements.Coxeter("B4") + Arrangement of 16 hyperplanes of dimension 4 and rank 4 + sage: hyperplane_arrangements.Coxeter("A3") + Arrangement of 6 hyperplanes of dimension 4 and rank 3 + + If the Cartan type is not crystallographic, the Coxeter arrangement + is not implemented yet:: + + sage: hyperplane_arrangements.Coxeter("H3") + Traceback (most recent call last): + ... + NotImplementedError: Coxeter arrangements are not implemented for non crystallographic Cartan types + + The characteristic polynomial is pre-computed using the results + of Terao, see [Ath2000]_:: + + sage: # needs sage.combinat + sage: hyperplane_arrangements.Coxeter("A3").characteristic_polynomial() + x^3 - 6*x^2 + 11*x - 6 + """ + from sage.combinat.root_system.weyl_group import WeylGroup + if data in NN: + cartan_type = CartanType(["A", data - 1]) + else: + cartan_type = CartanType(data) + if not cartan_type.is_crystallographic(): + raise NotImplementedError("Coxeter arrangements are not implemented for non crystallographic Cartan types") + W = WeylGroup(cartan_type) + Ra = RootSystem(cartan_type).ambient_space() + PR = Ra.positive_roots() + d = Ra.dimension() + H = make_parent(K, d, names) + x = H.gens() + hyperplanes = [] + + for a in PR: + hyperplanes.append(sum(a[j] * x[j] for j in range(d))) + A = H(*hyperplanes) + x = polygen(QQ, 'x') + charpoly = prod(x - d + 1 for d in W.degrees()) + A.characteristic_polynomial.set_cache(charpoly) + return A + def G_semiorder(self, G, K=QQ, names=None): r""" Return the semiorder hyperplane arrangement of a graph. @@ -254,6 +334,7 @@ def G_semiorder(self, G, K=QQ, names=None): EXAMPLES:: + sage: # needs sage.graphs sage: G = graphs.CompleteGraph(5) sage: hyperplane_arrangements.G_semiorder(G) Arrangement of 20 hyperplanes of dimension 5 and rank 4 @@ -292,13 +373,14 @@ def G_Shi(self, G, K=QQ, names=None): EXAMPLES:: + sage: # needs sage.graphs sage: G = graphs.CompleteGraph(5) sage: hyperplane_arrangements.G_Shi(G) Arrangement of 20 hyperplanes of dimension 5 and rank 4 sage: g = graphs.HouseGraph() sage: hyperplane_arrangements.G_Shi(g) Arrangement of 12 hyperplanes of dimension 5 and rank 4 - sage: a = hyperplane_arrangements.G_Shi(graphs.WheelGraph(4)); a + sage: a = hyperplane_arrangements.G_Shi(graphs.WheelGraph(4)); a Arrangement of 12 hyperplanes of dimension 4 and rank 3 """ n = G.num_verts() @@ -334,6 +416,7 @@ def graphical(self, G, K=QQ, names=None): EXAMPLES:: + sage: # needs sage.graphs sage: G = graphs.CompleteGraph(5) sage: hyperplane_arrangements.graphical(G) Arrangement of 10 hyperplanes of dimension 5 and rank 4 @@ -343,11 +426,12 @@ def graphical(self, G, K=QQ, names=None): TESTS:: + sage: # needs sage.graphs sage: h = hyperplane_arrangements.graphical(g) sage: h.characteristic_polynomial() x^5 - 6*x^4 + 14*x^3 - 15*x^2 + 6*x - sage: h.characteristic_polynomial.clear_cache() # long time - sage: h.characteristic_polynomial() # long time + sage: h.characteristic_polynomial.clear_cache() # long time + sage: h.characteristic_polynomial() # long time x^5 - 6*x^4 + 14*x^3 - 15*x^2 + 6*x """ n = G.num_verts() @@ -389,7 +473,8 @@ def Ish(self, n, K=QQ, names=None): EXAMPLES:: - sage: a = hyperplane_arrangements.Ish(3); a + sage: # needs sage.combinat + sage: a = hyperplane_arrangements.Ish(3); a Arrangement of 6 hyperplanes of dimension 3 and rank 2 sage: a.characteristic_polynomial() x^3 - 6*x^2 + 9*x @@ -399,8 +484,8 @@ def Ish(self, n, K=QQ, names=None): TESTS:: - sage: a.characteristic_polynomial.clear_cache() # long time - sage: a.characteristic_polynomial() # long time + sage: a.characteristic_polynomial.clear_cache() # long time # needs sage.combinat + sage: a.characteristic_polynomial() # long time # needs sage.combinat x^3 - 6*x^2 + 9*x REFERENCES: @@ -421,6 +506,85 @@ def Ish(self, n, K=QQ, names=None): A.characteristic_polynomial.set_cache(charpoly) return A + def IshB(self, n, K=QQ, names=None): + r""" + Return the type B Ish arrangement. + + INPUT: + + - ``n`` -- integer + - ``K`` -- field (default:``QQ``) + - ``names`` -- tuple of strings or ``None`` (default); the + variable names for the ambient space + + OUTPUT: + + The type `B` Ish arrangement, which is the set of `2n^2` hyperplanes + + .. MATH:: + + \{ x_i \pm x_j = 0 : 1 \leq i < j \leq n \} + \cup + \{ x_i = a : 1 \leq i\leq n, \quad i - n \leq a \leq n - i + 1 \}. + + EXAMPLES:: + + sage: a = hyperplane_arrangements.IshB(2) + sage: a + Arrangement of 8 hyperplanes of dimension 2 and rank 2 + sage: a.hyperplanes() + (Hyperplane 0*t0 + t1 - 1, + Hyperplane 0*t0 + t1 + 0, + Hyperplane t0 - t1 + 0, + Hyperplane t0 + 0*t1 - 2, + Hyperplane t0 + 0*t1 - 1, + Hyperplane t0 + 0*t1 + 0, + Hyperplane t0 + 0*t1 + 1, + Hyperplane t0 + t1 + 0) + sage: a.cone().is_free() + True + + .. PLOT:: + :width: 500 px + + a = hyperplane_arrangements.IshB(2) + sphinx_plot(a.plot()) + + :: + + sage: a = hyperplane_arrangements.IshB(3); a + Arrangement of 18 hyperplanes of dimension 3 and rank 3 + sage: a.characteristic_polynomial() + x^3 - 18*x^2 + 108*x - 216 + sage: b = hyperplane_arrangements.Shi(['B', 3]) + sage: b.characteristic_polynomial() + x^3 - 18*x^2 + 108*x - 216 + + TESTS:: + + sage: a.characteristic_polynomial.clear_cache() + sage: a.characteristic_polynomial() + x^3 - 18*x^2 + 108*x - 216 + + REFERENCES: + + - [TT2023]_ + """ + H = make_parent(K, n, names) + x = H.gens() + hyperplanes = [] + for i in range(n): + for j in range(i+1, n): + hyperplanes.append(x[i] - x[j]) + hyperplanes.append(x[i] + x[j]) + for a in range(i+1-n, n-i+1): + hyperplanes.append(x[i] - a) + A = H(*hyperplanes) + x = polygen(QQ, 'x') + charpoly = (x - 2*n) ** n + A.characteristic_polynomial.set_cache(charpoly) + return A + def linial(self, n, K=QQ, names=None): r""" Return the linial hyperplane arrangement. @@ -492,11 +656,12 @@ def semiorder(self, n, K=QQ, names=None): TESTS:: + sage: # needs sage.combinat sage: h = hyperplane_arrangements.semiorder(5) sage: h.characteristic_polynomial() x^5 - 20*x^4 + 180*x^3 - 790*x^2 + 1380*x - sage: h.characteristic_polynomial.clear_cache() # long time - sage: h.characteristic_polynomial() # long time + sage: h.characteristic_polynomial.clear_cache() # long time + sage: h.characteristic_polynomial() # long time x^5 - 20*x^4 + 180*x^3 - 790*x^2 + 1380*x """ H = make_parent(K, n, names) @@ -548,23 +713,24 @@ def Shi(self, data, K=QQ, names=None, m=1): EXAMPLES:: + sage: # needs sage.combinat sage: hyperplane_arrangements.Shi(4) Arrangement of 12 hyperplanes of dimension 4 and rank 3 sage: hyperplane_arrangements.Shi("A3") Arrangement of 12 hyperplanes of dimension 4 and rank 3 - sage: hyperplane_arrangements.Shi("A3",m=2) + sage: hyperplane_arrangements.Shi("A3", m=2) Arrangement of 24 hyperplanes of dimension 4 and rank 3 sage: hyperplane_arrangements.Shi("B4") Arrangement of 32 hyperplanes of dimension 4 and rank 4 - sage: hyperplane_arrangements.Shi("B4",m=3) + sage: hyperplane_arrangements.Shi("B4", m=3) Arrangement of 96 hyperplanes of dimension 4 and rank 4 sage: hyperplane_arrangements.Shi("C3") Arrangement of 18 hyperplanes of dimension 3 and rank 3 - sage: hyperplane_arrangements.Shi("D4",m=3) + sage: hyperplane_arrangements.Shi("D4", m=3) Arrangement of 72 hyperplanes of dimension 4 and rank 4 sage: hyperplane_arrangements.Shi("E6") Arrangement of 72 hyperplanes of dimension 8 and rank 6 - sage: hyperplane_arrangements.Shi("E6",m=2) + sage: hyperplane_arrangements.Shi("E6", m=2) Arrangement of 144 hyperplanes of dimension 8 and rank 6 If the Cartan type is not crystallographic, the Shi arrangement @@ -578,32 +744,34 @@ def Shi(self, data, K=QQ, names=None, m=1): The characteristic polynomial is pre-computed using the results of [Ath1996]_:: + sage: # needs sage.combinat sage: hyperplane_arrangements.Shi("A3").characteristic_polynomial() x^4 - 12*x^3 + 48*x^2 - 64*x - sage: hyperplane_arrangements.Shi("A3",m=2).characteristic_polynomial() + sage: hyperplane_arrangements.Shi("A3", m=2).characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x sage: hyperplane_arrangements.Shi("C3").characteristic_polynomial() x^3 - 18*x^2 + 108*x - 216 sage: hyperplane_arrangements.Shi("E6").characteristic_polynomial() x^8 - 72*x^7 + 2160*x^6 - 34560*x^5 + 311040*x^4 - 1492992*x^3 + 2985984*x^2 - sage: hyperplane_arrangements.Shi("B4",m=3).characteristic_polynomial() + sage: hyperplane_arrangements.Shi("B4", m=3).characteristic_polynomial() x^4 - 96*x^3 + 3456*x^2 - 55296*x + 331776 TESTS:: + sage: # needs sage.combinat sage: h = hyperplane_arrangements.Shi(4) sage: h.characteristic_polynomial() x^4 - 12*x^3 + 48*x^2 - 64*x - sage: h.characteristic_polynomial.clear_cache() # long time - sage: h.characteristic_polynomial() # long time + sage: h.characteristic_polynomial.clear_cache() # long time + sage: h.characteristic_polynomial() # long time x^4 - 12*x^3 + 48*x^2 - 64*x - sage: h = hyperplane_arrangements.Shi("A3",m=2) + sage: h = hyperplane_arrangements.Shi("A3", m=2) sage: h.characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x sage: h.characteristic_polynomial.clear_cache() sage: h.characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x - sage: h = hyperplane_arrangements.Shi("B3",m=3) + sage: h = hyperplane_arrangements.Shi("B3", m=3) sage: h.characteristic_polynomial() x^3 - 54*x^2 + 972*x - 5832 sage: h.characteristic_polynomial.clear_cache() @@ -611,7 +779,7 @@ def Shi(self, data, K=QQ, names=None, m=1): x^3 - 54*x^2 + 972*x - 5832 """ if data in NN: - cartan_type = CartanType(["A",data-1]) + cartan_type = CartanType(["A", data - 1]) else: cartan_type = CartanType(data) if not cartan_type.is_crystallographic(): @@ -634,4 +802,5 @@ def Shi(self, data, K=QQ, names=None, m=1): A.characteristic_polynomial.set_cache(charpoly) return A + hyperplane_arrangements = HyperplaneArrangementLibrary() diff --git a/src/sage/geometry/hyperplane_arrangement/plot.py b/src/sage/geometry/hyperplane_arrangement/plot.py index dc407a40ad3..be468c111bc 100644 --- a/src/sage/geometry/hyperplane_arrangement/plot.py +++ b/src/sage/geometry/hyperplane_arrangement/plot.py @@ -56,25 +56,26 @@ sage: H3.<x,y,z> = HyperplaneArrangements(QQ) sage: A = H3([(1,0,0), 0], [(0,0,1), 5]) - sage: A.plot(hyperplane_opacities=0.5, hyperplane_labels=True, hyperplane_legend=False) # optional - sage.plot + sage: A.plot(hyperplane_opacities=0.5, hyperplane_labels=True, # needs sage.plot + ....: hyperplane_legend=False) Graphics3d Object sage: c = H3([(1,0,0),0], [(0,0,1),5]) - sage: c.plot(ranges=10) # optional - sage.plot + sage: c.plot(ranges=10) # needs sage.plot Graphics3d Object - sage: c.plot(ranges=[[9.5,10], [-3,3]]) # optional - sage.plot + sage: c.plot(ranges=[[9.5,10], [-3,3]]) # needs sage.plot Graphics3d Object - sage: c.plot(ranges=[[[9.5,10], [-3,3]], [[-6,6], [-5,5]]]) # optional - sage.plot + sage: c.plot(ranges=[[[9.5,10], [-3,3]], [[-6,6], [-5,5]]]) # needs sage.plot Graphics3d Object sage: H2.<s,t> = HyperplaneArrangements(QQ) sage: h = H2([(1,1),0], [(1,-1),0], [(0,1),2]) - sage: h.plot(ranges=20) # optional - sage.plot + sage: h.plot(ranges=20) # needs sage.plot Graphics object consisting of 3 graphics primitives - sage: h.plot(ranges=[-1, 10]) # optional - sage.plot + sage: h.plot(ranges=[-1, 10]) # needs sage.plot Graphics object consisting of 3 graphics primitives - sage: h.plot(ranges=[[-1, 1], [-5, 5], [-1, 10]]) # optional - sage.plot + sage: h.plot(ranges=[[-1, 1], [-5, 5], [-1, 10]]) # needs sage.plot Graphics object consisting of 3 graphics primitives sage: a = hyperplane_arrangements.coordinate(3) @@ -83,24 +84,24 @@ sage: opts['label_offsets'] = [(0,2,2), (2,0,2), (2,2,0)] sage: opts['hyperplane_legend'] = False sage: opts['hyperplane_opacities'] = 0.7 - sage: a.plot(**opts) # optional - sage.plot + sage: a.plot(**opts) # needs sage.plot Graphics3d Object sage: opts['hyperplane_labels'] = 'short' - sage: a.plot(**opts) # optional - sage.plot + sage: a.plot(**opts) # needs sage.plot Graphics3d Object sage: H.<u> = HyperplaneArrangements(QQ) sage: pts = H(3*u+4, 2*u+5, 7*u+1) - sage: pts.plot(hyperplane_colors=['yellow','black','blue']) # optional - sage.plot + sage: pts.plot(hyperplane_colors=['yellow','black','blue']) # needs sage.plot Graphics object consisting of 3 graphics primitives - sage: pts.plot(point_sizes=[50,100,200], hyperplane_colors='blue') # optional - sage.plot + sage: pts.plot(point_sizes=[50,100,200], hyperplane_colors='blue') # needs sage.plot Graphics object consisting of 3 graphics primitives sage: H.<x,y,z> = HyperplaneArrangements(QQ) sage: a = H(x, y+1, y+2) - sage: a.plot(hyperplane_labels=True,label_colors='blue',label_fontsize=18) # optional - sage.plot + sage: a.plot(hyperplane_labels=True, label_colors='blue', label_fontsize=18) # needs sage.plot Graphics3d Object - sage: a.plot(hyperplane_labels=True,label_colors=['red','green','black']) # optional - sage.plot + sage: a.plot(hyperplane_labels=True, label_colors=['red','green','black']) # needs sage.plot Graphics3d Object """ from copy import copy @@ -145,7 +146,7 @@ def plot(hyperplane_arrangement, **kwds): EXAMPLES:: sage: B = hyperplane_arrangements.semiorder(4) - sage: B.plot() # optional - sage.plot + sage: B.plot() # needs sage.combinat sage.plot Displaying the essentialization. Graphics3d Object """ @@ -284,9 +285,6 @@ def plot(hyperplane_arrangement, **kwds): return p - - - def plot_hyperplane(hyperplane, **kwds): r""" Return the plot of a single hyperplane. @@ -333,33 +331,35 @@ def plot_hyperplane(hyperplane, **kwds): sage: H1.<x> = HyperplaneArrangements(QQ) sage: a = 3*x + 4 - sage: a.plot() # indirect doctest # optional - sage.plot + sage: a.plot() # indirect doctest # needs sage.plot Graphics object consisting of 3 graphics primitives - sage: a.plot(point_size=100,hyperplane_label='hello') # optional - sage.plot + sage: a.plot(point_size=100, hyperplane_label='hello') # needs sage.plot Graphics object consisting of 3 graphics primitives sage: H2.<x,y> = HyperplaneArrangements(QQ) sage: b = 3*x + 4*y + 5 - sage: b.plot() # optional - sage.plot + sage: b.plot() # needs sage.plot Graphics object consisting of 2 graphics primitives - sage: b.plot(ranges=(1,5),label_offset=(2,-1)) # optional - sage.plot + sage: b.plot(ranges=(1,5), label_offset=(2,-1)) # needs sage.plot Graphics object consisting of 2 graphics primitives - sage: opts = {'hyperplane_label':True, 'label_color':'green', - ....: 'label_fontsize':24, 'label_offset':(0,1.5)} - sage: b.plot(**opts) # optional - sage.plot + sage: opts = {'hyperplane_label': True, 'label_color': 'green', + ....: 'label_fontsize': 24, 'label_offset': (0,1.5)} + sage: b.plot(**opts) # needs sage.plot Graphics object consisting of 2 graphics primitives + sage: # needs sage.plot sage: H3.<x,y,z> = HyperplaneArrangements(QQ) sage: c = 2*x + 3*y + 4*z + 5 - sage: c.plot() # optional - sage.plot + sage: c.plot() Graphics3d Object - sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', frame=False) # optional - sage.plot + sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', + ....: frame=False) Graphics3d Object sage: d = -3*x + 2*y + 2*z + 3 - sage: d.plot(opacity=0.8) # optional - sage.plot + sage: d.plot(opacity=0.8) Graphics3d Object sage: e = 4*x + 2*z + 3 - sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) # optional - sage.plot + sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) Graphics3d Object """ if hyperplane.base_ring().characteristic(): @@ -489,20 +489,20 @@ def legend_3d(hyperplane_arrangement, hyperplane_colors, length): sage: a = hyperplane_arrangements.semiorder(3) sage: from sage.geometry.hyperplane_arrangement.plot import legend_3d - sage: legend_3d(a, list(colors.values())[:6],length='long') + sage: legend_3d(a, list(colors.values())[:6], length='long') # needs sage.combinat sage.plot Graphics object consisting of 6 graphics primitives sage: b = hyperplane_arrangements.semiorder(4) sage: c = b.essentialization() - sage: legend_3d(c, list(colors.values())[:12], length='long') + sage: legend_3d(c, list(colors.values())[:12], length='long') # needs sage.combinat sage.plot Graphics object consisting of 12 graphics primitives - sage: legend_3d(c, list(colors.values())[:12], length='short') + sage: legend_3d(c, list(colors.values())[:12], length='short') # needs sage.combinat sage.plot Graphics object consisting of 12 graphics primitives - sage: p = legend_3d(c, list(colors.values())[:12], length='short') - sage: p.set_legend_options(ncol=4) - sage: type(p) + sage: p = legend_3d(c, list(colors.values())[:12], length='short') # needs sage.combinat sage.plot + sage: p.set_legend_options(ncol=4) # needs sage.combinat sage.plot + sage: type(p) # needs sage.combinat sage.plot <class 'sage.plot.graphics.Graphics'> """ if hyperplane_arrangement.dimension() != 3: diff --git a/src/sage/geometry/integral_points.pxi b/src/sage/geometry/integral_points.pxi new file mode 100644 index 00000000000..037efb41da8 --- /dev/null +++ b/src/sage/geometry/integral_points.pxi @@ -0,0 +1,1449 @@ +r""" +Cython helper methods to compute integral points in polyhedra. +""" + +#***************************************************************************** +# Copyright (C) 2010 Volker Braun <vbraun.name@gmail.com> +# +# 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. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from cysignals.signals cimport sig_check +import copy +import itertools + +from sage.matrix.constructor import matrix, column_matrix, vector, diagonal_matrix +from sage.rings.integer_ring import ZZ +from sage.rings.integer cimport Integer +from sage.arith.misc import gcd +from sage.arith.functions import lcm +from sage.misc.misc_c import prod +from sage.modules.free_module import FreeModule + +############################################################################## +# The basic idea to enumerate the lattice points in the parallelotope +# is to use the Smith normal form of the ray coordinate matrix to +# bring the lattice into a "nice" basis. Here is the straightforward +# implementation. Note that you do not need to reduce to the +# full-dimensional case, the Smith normal form takes care of that for +# you. +# +## def parallelotope_points(spanning_points, lattice): +## # compute points in the open parallelotope, see [BK2001] +## R = matrix(spanning_points).transpose() +## D,U,V = R.smith_form() +## e = D.diagonal() # the elementary divisors +## d = prod(e) # the determinant +## u = U.inverse().columns() # generators for gp(semigroup) +## +## # "inverse" of the ray matrix as far as possible over ZZ +## # R*Rinv == diagonal_matrix([d]*D.ncols() + [0]*(D.nrows()-D.ncols())) +## # If R is full rank, this is Rinv = matrix(ZZ, R.inverse() * d) +## Dinv = D.transpose() +## for i in range(D.ncols()): +## Dinv[i,i] = d/D[i,i] +## Rinv = V * Dinv * U +## +## gens = [] +## for b in CartesianProduct(*[ range(i) for i in e ]): +## # this is our generator modulo the lattice spanned by the rays +## gen_mod_rays = sum( b_i*u_i for b_i, u_i in zip(b,u) ) +## q_times_d = Rinv * gen_mod_rays +## q_times_d = vector(ZZ,[ q_i % d for q_i in q_times_d ]) +## gen = lattice(R*q_times_d / d) +## gen.set_immutable() +## gens.append(gen) +## assert(len(gens) == d) +## return tuple(gens) +# +# The problem with the naive implementation is that it is slow: +# +# 1. You can simplify some of the matrix multiplications +# +# 2. The inner loop keeps creating new matrices and vectors, which +# is slow. It needs to recycle objects. Instead of creating a new +# lattice point again and again, change the entries of an +# existing lattice point and then copy it! + + +cpdef tuple parallelotope_points(spanning_points, lattice): + r""" + Return integral points in the parallelotope starting at the origin + and spanned by the ``spanning_points``. + + See :meth:`~ConvexRationalPolyhedralCone.semigroup_generators` for a description of the + algorithm. + + INPUT: + + - ``spanning_points`` -- a non-empty list of linearly independent + rays (`\ZZ`-vectors or :class:`toric lattice + <sage.geometry.toric_lattice.ToricLatticeFactory>` elements), + not necessarily primitive lattice points. + + OUTPUT: + + The tuple of all lattice points in the half-open parallelotope + spanned by the rays `r_i`, + + .. MATH:: + + \mathop{par}(\{r_i\}) = + \sum_{0\leq a_i < 1} a_i r_i + + By half-open parallelotope, we mean that the + points in the facets not meeting the origin are omitted. + + EXAMPLES: + + Note how the points on the outward-facing factes are omitted:: + + sage: from sage.geometry.integral_points import parallelotope_points + sage: rays = list(map(vector, [(2,0), (0,2)])) + sage: parallelotope_points(rays, ZZ^2) + ((0, 0), (0, 1), (1, 0), (1, 1)) + + The rays can also be toric lattice points:: + + sage: rays = list(map(ToricLattice(2), [(2,0), (0,2)])) + sage: parallelotope_points(rays, ToricLattice(2)) + (N(0, 0), N(0, 1), N(1, 0), N(1, 1)) + + A non-smooth cone:: + + sage: c = Cone([ (1,0), (1,2) ]) + sage: parallelotope_points(c.rays(), c.lattice()) + (N(0, 0), N(1, 1)) + + A ``ValueError`` is raised if the ``spanning_points`` are not + linearly independent:: + + sage: rays = list(map(ToricLattice(2), [(1,1)]*2)) + sage: parallelotope_points(rays, ToricLattice(2)) + Traceback (most recent call last): + ... + ValueError: The spanning points are not linearly independent! + + TESTS:: + + sage: rays = list(map(vector,[(-3, -2, -3, -2), (-2, -1, -8, 5), (1, 9, -7, -4), (-3, -1, -2, 2)])) + sage: len(parallelotope_points(rays, ZZ^4)) + 967 + """ + cdef MatrixClass VDinv + cdef MatrixClass R = matrix(spanning_points).transpose() + e, d, VDinv = ray_matrix_normal_form(R) + cdef tuple points = loop_over_parallelotope_points(e, d, VDinv, R, lattice) + for p in points: + p.set_immutable() + return points + + +cpdef tuple ray_matrix_normal_form(R): + r""" + Compute the Smith normal form of the ray matrix for + :func:`parallelotope_points`. + + INPUT: + + - ``R`` -- `\ZZ`-matrix whose columns are the rays spanning the + parallelotope. + + OUTPUT: + + A tuple containing ``e``, ``d``, and ``VDinv``. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import ray_matrix_normal_form + sage: R = column_matrix(ZZ,[3,3,3]) + sage: ray_matrix_normal_form(R) + ([3], 3, [1]) + """ + D,U,V = R.smith_form() + e = D.diagonal() # the elementary divisors + cdef Integer d = prod(e) # the determinant + if d == ZZ.zero(): + raise ValueError('The spanning points are not linearly independent!') + cdef int i + Dinv = diagonal_matrix(ZZ, [ d // e[i] for i in range(D.ncols()) ]) + VDinv = V * Dinv + return (e, d, VDinv) + + + +# The optimized version avoids constructing new matrices, vectors, and lattice points +cpdef tuple loop_over_parallelotope_points(e, d, MatrixClass VDinv, + MatrixClass R, lattice, + A=None, b=None): + r""" + The inner loop of :func:`parallelotope_points`. + + INPUT: + + See :meth:`parallelotope_points` for ``e``, ``d``, ``VDinv``, ``R``, ``lattice``. + + - ``A``, ``b``: Either both ``None`` or a vector and number. If + present, only the parallelotope points satisfying `A x \leq b` + are returned. + + OUTPUT: + + The points of the half-open parallelotope as a tuple of lattice + points. + + EXAMPLES:: + + sage: e = [3] + sage: d = prod(e) + sage: VDinv = matrix(ZZ, [[1]]) + sage: R = column_matrix(ZZ,[3,3,3]) + sage: lattice = ZZ^3 + sage: from sage.geometry.integral_points import loop_over_parallelotope_points + sage: loop_over_parallelotope_points(e, d, VDinv, R, lattice) + ((0, 0, 0), (1, 1, 1), (2, 2, 2)) + + sage: A = vector(ZZ, [1,0,0]) + sage: b = 1 + sage: loop_over_parallelotope_points(e, d, VDinv, R, lattice, A, b) + ((0, 0, 0), (1, 1, 1)) + """ + cdef int i, j + cdef int dim = VDinv.nrows() + cdef int ambient_dim = R.nrows() + s = ZZ.zero() # summation variable + cdef list gens = [] + gen = lattice(ZZ.zero()) + cdef VectorClass q_times_d = vector(ZZ, dim) + for base in itertools.product(*[ range(i) for i in e ]): + for i in range(dim): + s = ZZ.zero() + for j in range(dim): + s += VDinv.get_unsafe(i,j) * base[j] + q_times_d.set_unsafe(i, s % d) + for i in range(ambient_dim): + s = ZZ.zero() + for j in range(dim): + s += R.get_unsafe(i,j) * q_times_d.get_unsafe(j) + gen[i] = s / d + if A is not None: + s = ZZ.zero() + for i in range(ambient_dim): + s += A[i] * gen[i] + if s > b: + continue + gens.append(copy.copy(gen)) + if A is None: + assert(len(gens) == d) + return tuple(gens) + + + +############################################################################## +cpdef tuple simplex_points(vertices): + r""" + Return the integral points in a lattice simplex. + + INPUT: + + - ``vertices`` -- an iterable of integer coordinate vectors. The + indices of vertices that span the simplex under + consideration. + + OUTPUT: + + A tuple containing the integral point coordinates as `\ZZ`-vectors. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import simplex_points + sage: simplex_points([(1,2,3), (2,3,7), (-2,-3,-11)]) + ((-2, -3, -11), (0, 0, -2), (1, 2, 3), (2, 3, 7)) + + The simplex need not be full-dimensional:: + + sage: simplex = Polyhedron([(1,2,3,5), (2,3,7,5), (-2,-3,-11,5)]) + sage: simplex_points(simplex.Vrepresentation()) + ((2, 3, 7, 5), (0, 0, -2, 5), (-2, -3, -11, 5), (1, 2, 3, 5)) + + sage: simplex_points([(2,3,7)]) + ((2, 3, 7),) + + TESTS:: + + sage: v = [(1,0,7,-1), (-2,-2,4,-3), (-1,-1,-1,4), (2,9,0,-5), (-2,-1,5,1)] + sage: simplex = Polyhedron(v); simplex + A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices + sage: pts = simplex_points(simplex.Vrepresentation()) + sage: len(pts) + 49 + sage: for p in pts: p.set_immutable() + sage: len(set(pts)) + 49 + + sage: all(simplex.contains(p) for p in pts) + True + + sage: v = [(4,-1,-1,-1), (-1,4,-1,-1), (-1,-1,4,-1), (-1,-1,-1,4), (-1,-1,-1,-1)] + sage: P4mirror = Polyhedron(v); P4mirror + A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices + sage: len(simplex_points(P4mirror.Vrepresentation())) + 126 + + sage: vertices = list(map(vector, [(1,2,3), (2,3,7), (-2,-3,-11)])) + sage: for v in vertices: v.set_immutable() + sage: simplex_points(vertices) + ((-2, -3, -11), (0, 0, -2), (1, 2, 3), (2, 3, 7)) + """ + cdef list rays = [vector(ZZ, list(v)) for v in vertices] + if not rays: + return () + cdef VectorClass origin = rays.pop() + origin.set_immutable() + if not rays: + return (origin,) + translate_points(rays, origin) + + # Find equation Ax<=b that cuts out simplex from parallelotope + cdef MatrixClass Rt = matrix(ZZ, rays) + cdef MatrixClass R = Rt.transpose() + cdef int nrays = len(rays) + cdef Integer b + M = FreeModule(ZZ, nrays) + if R.is_square(): + b = abs(R.det()) + A = R.solve_left(M([b]*nrays)) + else: + RtR = Rt * R + b = abs(RtR.det()) + A = RtR.solve_left(M([b]*nrays)) * Rt + + e, d, VDinv = ray_matrix_normal_form(R) + lattice = origin.parent() + points = loop_over_parallelotope_points(e, d, VDinv, R, lattice, A, b) + tuple(rays) + translate_points(points, -origin) + return points + + +cdef translate_points(v_list, VectorClass delta): + r""" + Add ``delta`` to each vector in ``v_list``. + """ + cdef int dim = delta.degree() + cdef int i + for v in v_list: + for i in range(dim): + v[i] -= delta.get_unsafe(i) + + + +############################################################################## +# For points with "small" coordinates (that is, fitting into a small +# rectangular bounding box) it is faster to naively enumerate the +# points. This saves the overhead of triangulating the polytope etc. + +cpdef rectangular_box_points(list box_min, list box_max, + polyhedron=None, count_only=False, + return_saturated=False): + r""" + Return the integral points in the lattice bounding box that are + also contained in the given polyhedron. + + INPUT: + + - ``box_min`` -- A list of integers. The minimal value for each + coordinate of the rectangular bounding box. + + - ``box_max`` -- A list of integers. The maximal value for each + coordinate of the rectangular bounding box. + + - ``polyhedron`` -- A + :class:`~sage.geometry.polyhedron.base.Polyhedron_base`, a PPL + :class:`~ppl.polyhedron.C_Polyhedron`, or ``None`` (default). + + - ``count_only`` -- Boolean (default: ``False``). Whether to + return only the total number of vertices, and not their + coordinates. Enabling this option speeds up the + enumeration. Cannot be combined with the ``return_saturated`` + option. + + - ``return_saturated`` -- Boolean (default: ``False``. Whether to + also return which inequalities are saturated for each point of + the polyhedron. Enabling this slows down the enumeration. Cannot + be combined with the ``count_only`` option. + + OUTPUT: + + By default, this function returns a tuple containing the integral + points of the rectangular box spanned by ``box_min`` and ``box_max`` + and that lie inside the ``polyhedron``. For sufficiently large + bounding boxes, this are all integral points of the polyhedron. + + If no polyhedron is specified, all integral points of the + rectangular box are returned. + + If ``count_only`` is specified, only the total number (an integer) + of found lattice points is returned. + + If ``return_saturated`` is enabled, then for each integral point a + pair ``(point, Hrep)`` is returned where ``point`` is the point + and ``Hrep`` is the set of indices of the H-representation objects + that are saturated at the point. + + ALGORITHM: + + This function implements the naive algorithm towards counting + integral points. Given min and max of vertex coordinates, it + iterates over all points in the bounding box and checks whether + they lie in the polyhedron. The following optimizations are + implemented: + + * Cython: Use machine integers and optimizing C/C++ compiler + where possible, arbitrary precision integers where necessary. + Bounds checking, no compile time limits. + + * Unwind inner loop (and next-to-inner loop): + + .. MATH:: + + Ax \leq b + \quad \Leftrightarrow \quad + a_1 x_1 ~\leq~ b - \sum_{i=2}^d a_i x_i + + so we only have to evaluate `a_1 * x_1` in the inner loop. + + * Coordinates are permuted to make the longest box edge the + inner loop. The inner loop is optimized to run very fast, so + its best to do as much work as possible there. + + * Continuously reorder inequalities and test the most + restrictive inequalities first. + + * Use convexity and only find first and last allowed point in + the inner loop. The points in-between must be points of the + polyhedron, too. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import rectangular_box_points + sage: rectangular_box_points([0,0,0],[1,2,3]) + ((0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), + (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), + (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 2, 3), + (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 0, 3), + (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), + (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 2, 3)) + + sage: from sage.geometry.integral_points import rectangular_box_points + sage: rectangular_box_points([0,0,0],[1,2,3], count_only=True) + 24 + + sage: cell24 = polytopes.twenty_four_cell() + sage: rectangular_box_points([-1]*4, [1]*4, cell24) + ((-1, 0, 0, 0), (0, -1, 0, 0), (0, 0, -1, 0), (0, 0, 0, -1), + (0, 0, 0, 0), + (0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, 0), (1, 0, 0, 0)) + sage: d = 3 + sage: dilated_cell24 = d*cell24 + sage: len( rectangular_box_points([-d]*4, [d]*4, dilated_cell24) ) + 305 + + sage: d = 6 + sage: dilated_cell24 = d*cell24 + sage: len( rectangular_box_points([-d]*4, [d]*4, dilated_cell24) ) + 3625 + + sage: rectangular_box_points([-d]*4, [d]*4, dilated_cell24, count_only=True) + 3625 + + sage: polytope = Polyhedron([(-4,-3,-2,-1),(3,1,1,1),(1,2,1,1),(1,1,3,0),(1,3,2,4)]) + sage: pts = rectangular_box_points([-4]*4, [4]*4, polytope); pts + ((-4, -3, -2, -1), (-1, 0, 0, 1), (0, 1, 1, 1), (1, 1, 1, 1), (1, 1, 3, 0), + (1, 2, 1, 1), (1, 2, 2, 2), (1, 3, 2, 4), (2, 1, 1, 1), (3, 1, 1, 1)) + sage: all(polytope.contains(p) for p in pts) + True + + sage: set(map(tuple,pts)) == \ + ....: set([(-4,-3,-2,-1),(3,1,1,1),(1,2,1,1),(1,1,3,0),(1,3,2,4), + ....: (0,1,1,1),(1,2,2,2),(-1,0,0,1),(1,1,1,1),(2,1,1,1)]) # computed with PALP + True + + Long ints and non-integral polyhedra are explicitly allowed:: + + sage: polytope = Polyhedron([[1], [10*pi.n()]], base_ring=RDF) # needs sage.symbolic + sage: len(rectangular_box_points([-100], [100], polytope)) # needs sage.symbolic + 31 + + sage: halfplane = Polyhedron(ieqs=[(-1,1,0)]) + sage: rectangular_box_points([0,-1+10^50], [0,1+10^50]) + ((0, 99999999999999999999999999999999999999999999999999), + (0, 100000000000000000000000000000000000000000000000000), + (0, 100000000000000000000000000000000000000000000000001)) + sage: len( rectangular_box_points([0,-100+10^50], [1,100+10^50], halfplane) ) + 201 + + Using a PPL polyhedron:: + + sage: # needs pplpy + sage: from ppl import Variable, Generator_System, C_Polyhedron, point + sage: gs = Generator_System() + sage: x = Variable(0); y = Variable(1); z = Variable(2) + sage: gs.insert(point(0*x + 1*y + 0*z)) + sage: gs.insert(point(0*x + 1*y + 3*z)) + sage: gs.insert(point(3*x + 1*y + 0*z)) + sage: gs.insert(point(3*x + 1*y + 3*z)) + sage: poly = C_Polyhedron(gs) + sage: rectangular_box_points([0]*3, [3]*3, poly) + ((0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), + (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 1, 3), (3, 1, 0), (3, 1, 1), (3, 1, 2), (3, 1, 3)) + + Optionally, return the information about the saturated inequalities as well:: + + sage: cube = polytopes.cube() + sage: cube.Hrepresentation(0) + An inequality (-1, 0, 0) x + 1 >= 0 + sage: cube.Hrepresentation(1) + An inequality (0, -1, 0) x + 1 >= 0 + sage: cube.Hrepresentation(2) + An inequality (0, 0, -1) x + 1 >= 0 + sage: rectangular_box_points([0]*3, [1]*3, cube, return_saturated=True) + (((0, 0, 0), frozenset()), + ((0, 0, 1), frozenset({2})), + ((0, 1, 0), frozenset({1})), + ((0, 1, 1), frozenset({1, 2})), + ((1, 0, 0), frozenset({0})), + ((1, 0, 1), frozenset({0, 2})), + ((1, 1, 0), frozenset({0, 1})), + ((1, 1, 1), frozenset({0, 1, 2}))) + + TESTS: + + Check that this can be interrupted, see :trac:`20781`:: + + sage: ieqs = [(-1, -1, -1, -1, -1, -1, -1, -1, -1), + ....: (0, -1, 0, 0, 0, 0, 0, 0, 0), + ....: (0, -1, 0, 2, -1, 0, 0, 0, 0), + ....: (0, 0, -1, -1, 2, -1, 0, 0, 0), + ....: (0, 2, 0, -1, 0, 0, 0, 0, 0), + ....: (0, 0, 0, 0, 0, 0, 0, -1, 2), + ....: (1, 0, 2, 0, -1, 0, 0, 0, 0), + ....: (0, 0, 0, 0, -1, 2, -1, 0, 0), + ....: (0, 0, 0, 0, 0, 0, 0, 0, -1), + ....: (0, 0, 0, 0, 0, -1, 2, -1, 0), + ....: (0, 0, 0, 0, 0, 0, -1, 2, -1)] + sage: P = Polyhedron(ieqs=ieqs) + sage: alarm(0.5); P.integral_points() + Traceback (most recent call last): + ... + AlarmInterrupt + """ + assert len(box_min) == len(box_max) + assert not (count_only and return_saturated) + cdef int d = len(box_min) + cdef int i, j + cdef list diameter = sorted([(box_max[i]-box_min[i], i) for i in range(d)], + reverse=True) + cdef list diameter_value = [x[0] for x in diameter] + cdef list diameter_index = [x[1] for x in diameter] + + # Construct the inverse permutation + cdef list orig_perm = list(range(len(diameter_index))) + for i, j in enumerate(diameter_index): + orig_perm[j] = i + + box_min = perm_action(diameter_index, box_min) + box_max = perm_action(diameter_index, box_max) + cdef InequalityCollection inequalities = InequalityCollection(polyhedron, diameter_index, box_min, box_max) + + if count_only: + return loop_over_rectangular_box_points(box_min, box_max, inequalities, d, count_only) + + cdef list points = [] + cdef VectorClass v = vector(ZZ, d) + if not return_saturated: + for p in loop_over_rectangular_box_points(box_min, box_max, inequalities, d, count_only): + # v = vector(ZZ, perm_action(orig_perm, p)) # too slow + for i in range(d): + v.set_unsafe(i, Integer(p[orig_perm[i]])) + v_copy = copy.copy(v) + v_copy.set_immutable() + points.append(v_copy) + else: + for p, saturated in loop_over_rectangular_box_points_saturated(box_min, box_max, + inequalities, d): + for i in range(d): + v.set_unsafe(i, Integer(p[orig_perm[i]])) + v_copy = copy.copy(v) + v_copy.set_immutable() + points.append( (v_copy, saturated) ) + + return tuple(points) + +cdef list perm_action(list p, list lst): + """ + Return the action of a permutation ``p`` of `(0, ..., n-1)` + on a list of length `n`. + """ + return [lst[i] for i in p] + +cdef loop_over_rectangular_box_points(list box_min, list box_max, + InequalityCollection inequalities, + int d, bint count_only): + """ + The inner loop of :func:`rectangular_box_points`. + + INPUT: + + - ``box_min``, ``box_max`` -- the bounding box. + + - ``inequalities`` -- a :class:`InequalityCollection` containing + the inequalities defining the polyhedron. + + - ``d`` -- the ambient space dimension. + + - ``count_only`` -- whether to only return the total number of + lattice points. + + OUTPUT: + + The integral points in the bounding box satisfying all + inequalities. + """ + cdef int inc + cdef Integer i_min, i_max + if count_only: + points = 0 + else: + points = [] + cdef list p = list(box_min) + inequalities.prepare_next_to_inner_loop(p) + while True: + sig_check() + inequalities.prepare_inner_loop(p) + i_min = box_min[0] + i_max = box_max[0] + # Find the lower bound for the allowed region + while i_min <= i_max: + if inequalities.are_satisfied(i_min): + break + i_min += 1 + # Find the upper bound for the allowed region + while i_min <= i_max: + if inequalities.are_satisfied(i_max): + break + i_max -= 1 + # The points i_min .. i_max are contained in the polyhedron + if count_only: + if i_max >= i_min: + points += i_max - i_min + 1 + else: + i = i_min + while i <= i_max: + p[0] = i + points.append(tuple(p)) + i += 1 + # finally increment the other entries in p to move on to next inner loop + inc = 1 + if d == 1: + return points + while True: + if p[inc] == box_max[inc]: + p[inc] = box_min[inc] + inc += 1 + if inc == d: + return points + else: + p[inc] += 1 + break + if inc > 1: + inequalities.prepare_next_to_inner_loop(p) + + + +cdef loop_over_rectangular_box_points_saturated(list box_min, list box_max, + InequalityCollection inequalities, + int d): + """ + The analog of :func:`rectangular_box_points` except that it keeps + track of which inequalities are saturated. + + INPUT: + + See :func:`rectangular_box_points`. + + OUTPUT: + + The integral points in the bounding box satisfying all + inequalities, each point being returned by a coordinate vector and + a set of H-representation object indices. + """ + cdef int inc + cdef list points = [] + cdef list p = list(box_min) + inequalities.prepare_next_to_inner_loop(p) + while True: + inequalities.prepare_inner_loop(p) + i_min = box_min[0] + i_max = box_max[0] + # Find the lower bound for the allowed region + while i_min <= i_max: + if inequalities.are_satisfied(i_min): + break + i_min += 1 + # Find the upper bound for the allowed region + while i_min <= i_max: + if inequalities.are_satisfied(i_max): + break + i_max -= 1 + # The points i_min .. i_max are contained in the polyhedron + i = i_min + while i <= i_max: + p[0] = i + saturated = inequalities.satisfied_as_equalities(i) + points.append( (tuple(p), saturated) ) + i += 1 + # finally increment the other entries in p to move on to next inner loop + inc = 1 + if d == 1: + return points + while True: + if p[inc] == box_max[inc]: + p[inc] = box_min[inc] + inc += 1 + if inc == d: + return points + else: + p[inc] += 1 + break + if inc > 1: + inequalities.prepare_next_to_inner_loop(p) + + +cdef class Inequality_generic: + r""" + An inequality whose coefficients are arbitrary Python/Sage objects + + INPUT: + + - ``A`` -- list of coefficients + + - ``b`` -- element + + OUTPUT: + + Inequality `A x + b \geq 0`. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import Inequality_generic + sage: Inequality_generic([2 * pi, sqrt(3), 7/2], -5.5) # needs sage.symbolic + generic: (2*pi, sqrt(3), 7/2) x + -5.50000000000000 >= 0 + """ + + cdef list A + cdef object b + cdef object coeff + cdef object cache + # The index of the inequality in the polyhedron H-representation + cdef int index + + def __cinit__(self, list A, b, int index=-1): + """ + The Cython constructor + + INPUT: + + See :class:`Inequality_generic`. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import Inequality_generic + sage: Inequality_generic([2 * pi, sqrt(3), 7/2], -5.5) # needs sage.symbolic + generic: (2*pi, sqrt(3), 7/2) x + -5.50000000000000 >= 0 + """ + self.A = A + self.b = b + self.coeff = 0 + self.cache = 0 + self.index = int(index) + + def __repr__(self): + """ + Return a string representation. + + OUTPUT: + + String. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import Inequality_generic + sage: Inequality_generic([2,3,7], -5).__repr__() + 'generic: (2, 3, 7) x + -5 >= 0' + """ + s = 'generic: (' + s += ', '.join(str(self.A[i]) for i in range(len(self.A))) + s += ') x + ' + str(self.b) + ' >= 0' + return s + + cdef prepare_next_to_inner_loop(self, p): + """ + In :class:`Inequality_int` this method is used to peel of the + next-to-inner loop. + + See :meth:`InequalityCollection.prepare_inner_loop` for more details. + """ + pass + + cdef prepare_inner_loop(self, p): + """ + Peel off the inner loop. + + See :meth:`InequalityCollection.prepare_inner_loop` for more details. + """ + cdef int j + self.coeff = self.A[0] + self.cache = self.b + for j in range(1, len(self.A)): + self.cache += self.A[j] * p[j] + + cdef bint is_not_satisfied(self, inner_loop_variable) except -1: + r""" + Test the inequality, using the cached value from :meth:`prepare_inner_loop` + + OUTPUT: + + Boolean. Whether the inequality is not satisfied. + """ + return inner_loop_variable * self.coeff + self.cache < 0 + + cdef bint is_equality(Inequality_generic self, int inner_loop_variable) except -1: + r""" + Test the inequality, using the cached value from :meth:`prepare_inner_loop` + + OUTPUT: + + Boolean. Given the inequality `Ax + b \geq 0`, this method + returns whether the equality `Ax + b = 0` is satisfied. + """ + return inner_loop_variable * self.coeff + self.cache == 0 + + +# if dim>20 then we always use the generic inequalities (Inequality_generic) +DEF INEQ_INT_MAX_DIM = 20 + +cdef class Inequality_int: + r""" + Fast version of inequality in the case that all coefficients fit + into machine ints. + + INPUT: + + - ``A`` -- list of integers + + - ``b`` -- integer + + - ``max_abs_coordinates`` -- the maximum of the coordinates that + one wants to evaluate the coordinates on; used for overflow + checking + + OUTPUT: + + Inequality `A x + b \geq 0`. A ``OverflowError`` is raised if a + machine integer is not long enough to hold the results. A + ``ValueError`` is raised if some of the input is not integral. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import Inequality_int + sage: Inequality_int([2,3,7], -5, [10]*3) + integer: (2, 3, 7) x + -5 >= 0 + + sage: Inequality_int([1]*21, -5, [10]*21) + Traceback (most recent call last): + ... + OverflowError: Dimension limit exceeded. + + sage: Inequality_int([2,3/2,7], -5, [10]*3) + Traceback (most recent call last): + ... + ValueError: Not integral. + + sage: Inequality_int([2,3,7], -5.2, [10]*3) + Traceback (most recent call last): + ... + ValueError: Not integral. + + sage: Inequality_int([2,3,7], -5*10^50, [10]*3) # actual error message can differ between 32 and 64 bit + Traceback (most recent call last): + ... + OverflowError: ... + + TESTS: + + Check that :trac:`21993` is fixed:: + + sage: Inequality_int([18560500, -89466500], 108027, [178933, 37121]) + Traceback (most recent call last): + ... + OverflowError: ... + + """ + cdef int A[INEQ_INT_MAX_DIM] + cdef int b + cdef int dim + # the innermost coefficient + cdef int coeff + cdef int cache + # the next-to-innermost coefficient + cdef int coeff_next + cdef int cache_next + # The index of the inequality in the polyhedron H-representation + cdef int index + + cdef int _to_int(self, x) except? -999: + if x not in ZZ: + raise ValueError('Not integral.') + return int(x) # raises OverflowError in Cython if necessary + + def __cinit__(self, list A, b, list max_abs_coordinates, int index=-1): + """ + The Cython constructor + + See :class:`Inequality_int` for input. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import Inequality_int + sage: Inequality_int([2,3,7], -5, [10]*3) + integer: (2, 3, 7) x + -5 >= 0 + """ + cdef int i + self.dim = self._to_int(len(A)) + self.index = int(index) + if self.dim < 1 or self.dim > INEQ_INT_MAX_DIM: + raise OverflowError('Dimension limit exceeded.') + for i in range(self.dim): + self.A[i] = self._to_int(A[i]) + self.b = self._to_int(b) + self.coeff = self.A[0] + if self.dim > 0: + self.coeff_next = self.A[1] + # finally, make sure that there cannot be any overflow during the enumeration + self._to_int(abs(ZZ(b)) + sum( abs(ZZ(A[i])) * ZZ(max_abs_coordinates[i]) + for i in range(self.dim) )) + + def __repr__(self): + """ + Return a string representation. + + OUTPUT: + + String. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import Inequality_int + sage: Inequality_int([2,3,7], -5, [10]*3).__repr__() + 'integer: (2, 3, 7) x + -5 >= 0' + """ + s = 'integer: (' + s += ', '.join([str(self.A[i]) for i in range(self.dim)]) + s += ') x + ' + str(self.b) + ' >= 0' + return s + + cdef prepare_next_to_inner_loop(Inequality_int self, p): + """ + Peel off the next-to-inner loop. + + See :meth:`InequalityCollection.prepare_inner_loop` for more details. + """ + cdef int j + self.cache_next = self.b + for j in range(2, self.dim): + self.cache_next += self.A[j] * p[j] + + cdef prepare_inner_loop(Inequality_int self, p): + """ + Peel off the inner loop. + + See :meth:`InequalityCollection.prepare_inner_loop` for more details. + """ + cdef int j + if self.dim > 1: + self.cache = self.cache_next + self.coeff_next * p[1] + else: + self.cache = self.cache_next + + cdef bint is_not_satisfied(Inequality_int self, int inner_loop_variable): + return inner_loop_variable * self.coeff + self.cache < 0 + + cdef bint is_equality(Inequality_int self, int inner_loop_variable): + return inner_loop_variable * self.coeff + self.cache == 0 + + + +cdef class InequalityCollection: + """ + A collection of inequalities. + + INPUT: + + - ``polyhedron`` -- a polyhedron defining the inequalities. + + - ``permutation`` -- list; a 0-based permutation of the coordinates. + Will be used to permute the coordinates of the inequality. + + - ``box_min``, ``box_max`` -- the (not permuted) minimal and maximal + coordinates of the bounding box. Used for bounds checking. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import InequalityCollection + sage: P_QQ = Polyhedron(identity_matrix(3).columns() + [(-2, -1,-1)], base_ring=QQ) + sage: ieq = InequalityCollection(P_QQ, [0,1,2], [0]*3,[1]*3); ieq + The collection of inequalities + integer: (3, -2, -2) x + 2 >= 0 + integer: (-1, 4, -1) x + 1 >= 0 + integer: (-1, -1, 4) x + 1 >= 0 + integer: (-1, -1, -1) x + 1 >= 0 + + sage: P_RR = Polyhedron(identity_matrix(2).columns() + [(-2.7, -1)], base_ring=RDF) + sage: InequalityCollection(P_RR, [0,1], [0]*2, [1]*2) + The collection of inequalities + integer: (-1, -1) x + 1 >= 0 + generic: (-1.0, 3.7) x + 1.0 >= 0 + generic: (1.0, -1.35) x + 1.35 >= 0 + + sage: line = Polyhedron(eqns=[(2,3,7)]) + sage: InequalityCollection(line, [0,1], [0]*2, [1]*2 ) + The collection of inequalities + integer: (3, 7) x + 2 >= 0 + integer: (-3, -7) x + -2 >= 0 + + TESTS:: + + sage: TestSuite(ieq).run(skip='_test_pickling') + """ + cdef list ineqs_int + cdef list ineqs_generic + + def __repr__(self): + r""" + Return a string representation. + + OUTPUT: + + String. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import InequalityCollection + sage: line = Polyhedron(eqns=[(2,3,7)]) + sage: InequalityCollection(line, [0,1], [0]*2, [1]*2 ).__repr__() + 'The collection of inequalities\ninteger: (3, 7) x + 2 >= 0\ninteger: (-3, -7) x + -2 >= 0' + """ + s = 'The collection of inequalities\n' + for ineq in self.ineqs_int: + s += str(<Inequality_int>ineq) + '\n' + for ineq in self.ineqs_generic: + s += str(<Inequality_generic>ineq) + '\n' + return s.strip() + + cpdef tuple _make_A_b(self, Hrep_obj, list permutation): + r""" + Return the coefficients and constant of the H-representation + object. + + INPUT: + + - ``Hrep_obj`` -- a H-representation object of the polyhedron + - ``permutation`` -- the permutation of the coordinates to + apply to ``A`` + + OUTPUT: + + A pair ``(A,b)``. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import InequalityCollection + sage: line = Polyhedron(eqns=[(2,3,7)]) + sage: ieq = InequalityCollection(line, [0,1], [0]*2, [1]*2 ) + sage: ieq._make_A_b(line.Hrepresentation(0), [0,1]) + ([3, 7], 2) + sage: ieq._make_A_b(line.Hrepresentation(0), [1,0]) + ([7, 3], 2) + """ + cdef list v = list(Hrep_obj) + cdef list A = perm_action(permutation, v[1:]) + b = v[0] + try: + x = lcm([a.denominator() for a in A] + [b.denominator()]) + A = [a * x for a in A] + b = b * x + except AttributeError: + pass + return (A, b) + + def __cinit__(self, polyhedron, list permutation, box_min, box_max): + """ + The Cython constructor + + See the class documentation for the description of the arguments. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import InequalityCollection + sage: line = Polyhedron(eqns=[(2,3,7)]) + sage: InequalityCollection(line, [0,1], [0]*2, [1]*2 ) + The collection of inequalities + integer: (3, 7) x + 2 >= 0 + integer: (-3, -7) x + -2 >= 0 + """ + cdef list max_abs_coordinates = [max(abs(c_min), abs(c_max)) + for c_min, c_max in zip(box_min, box_max)] + max_abs_coordinates = perm_action(permutation, max_abs_coordinates) + self.ineqs_int = [] + self.ineqs_generic = [] + if polyhedron is None: + return + + try: + # polyhedron is a PPL C_Polyhedron class? + self._cinit_from_PPL(max_abs_coordinates, permutation, polyhedron) + except AttributeError: + try: + # polyhedron is a Polyhedron class? + self._cinit_from_Polyhedron(max_abs_coordinates, permutation, polyhedron) + except AttributeError: + raise TypeError('Cannot extract Hrepresentation data from polyhedron.') + + cdef _cinit_from_PPL(self, list max_abs_coordinates, list permutation, + polyhedron): + """ + Initialize the inequalities from a PPL C_Polyhedron + + See __cinit__ for a description of the arguments. + + EXAMPLES:: + + sage: # needs pplpy + sage: from ppl import Variable, Generator_System, C_Polyhedron, point + sage: gs = Generator_System() + sage: x = Variable(0); y = Variable(1); z = Variable(2) + sage: gs.insert(point(0*x + 0*y + 1*z)) + sage: gs.insert(point(0*x + 3*y + 1*z)) + sage: gs.insert(point(3*x + 0*y + 1*z)) + sage: gs.insert(point(3*x + 3*y + 1*z)) + sage: poly = C_Polyhedron(gs) + sage: from sage.geometry.integral_points import InequalityCollection + sage: InequalityCollection(poly, [0,2,1], [0]*3, [3]*3 ) + The collection of inequalities + integer: (0, 1, 0) x + -1 >= 0 + integer: (0, -1, 0) x + 1 >= 0 + integer: (1, 0, 0) x + 0 >= 0 + integer: (0, 0, 1) x + 0 >= 0 + integer: (-1, 0, 0) x + 3 >= 0 + integer: (0, 0, -1) x + 3 >= 0 + """ + cdef list A + cdef int index + for index,c in enumerate(polyhedron.minimized_constraints()): + A = perm_action(permutation, [Integer(mpz) for mpz in c.coefficients()]) + b = Integer(c.inhomogeneous_term()) + try: + H = Inequality_int(A, b, max_abs_coordinates, index) + self.ineqs_int.append(H) + except (OverflowError, ValueError): + H = Inequality_generic(A, b, index) + self.ineqs_generic.append(H) + if c.is_equality(): + A = [ -a for a in A ] + b = -b + try: + H = Inequality_int(A, b, max_abs_coordinates, index) + self.ineqs_int.append(H) + except (OverflowError, ValueError): + H = Inequality_generic(A, b, index) + self.ineqs_generic.append(H) + + cdef _cinit_from_Polyhedron(self, list max_abs_coordinates, + list permutation, polyhedron): + """ + Initialize the inequalities from a Sage Polyhedron + + See __cinit__ for a description of the arguments. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import InequalityCollection + sage: line = Polyhedron(eqns=[(2,3,7)]) + sage: InequalityCollection(line, [0,1], [0]*2, [1]*2 ) + The collection of inequalities + integer: (3, 7) x + 2 >= 0 + integer: (-3, -7) x + -2 >= 0 + + TESTS: + + Check that :trac:`21037` is fixed:: + + sage: P = Polyhedron(vertices=((0, 0), (17,3))) + sage: P += 1/1000*polytopes.regular_polygon(5) # needs sage.rings.number_field + sage: P.integral_points() # needs sage.rings.number_field + ((0, 0), (17, 3)) + """ + cdef list A + for Hrep_obj in polyhedron.inequality_generator(): + A, b = self._make_A_b(Hrep_obj, permutation) + try: + H = Inequality_int(A, b, max_abs_coordinates, Hrep_obj.index()) + self.ineqs_int.append(H) + except (OverflowError, ValueError, TypeError): + H = Inequality_generic(A, b, Hrep_obj.index()) + self.ineqs_generic.append(H) + for Hrep_obj in polyhedron.equation_generator(): + A, b = self._make_A_b(Hrep_obj, permutation) + # add inequality + try: + H = Inequality_int(A, b, max_abs_coordinates, Hrep_obj.index()) + self.ineqs_int.append(H) + except (OverflowError, ValueError, TypeError): + H = Inequality_generic(A, b, Hrep_obj.index()) + self.ineqs_generic.append(H) + # add sign-reversed inequality + A = [ -a for a in A ] + b = -b + try: + H = Inequality_int(A, b, max_abs_coordinates, Hrep_obj.index()) + self.ineqs_int.append(H) + except (OverflowError, ValueError, TypeError): + H = Inequality_generic(A, b, Hrep_obj.index()) + self.ineqs_generic.append(H) + + cpdef prepare_next_to_inner_loop(self, p): + r""" + Peel off the next-to-inner loop. + + In the next-to-inner loop of :func:`rectangular_box_points`, + we have to repeatedly evaluate `A x-A_0 x_0+b`. To speed up + computation, we pre-evaluate + + .. MATH:: + + c = b + \sum_{i=2} A_i x_i + + and only compute `A x-A_0 x_0+b = A_1 x_1 +c \geq 0` in the + next-to-inner loop. + + INPUT: + + - ``p`` -- the point coordinates. Only ``p[2:]`` coordinates + are potentially used by this method. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import InequalityCollection, print_cache + sage: P = Polyhedron(ieqs=[(2,3,7,11)]) + sage: ieq = InequalityCollection(P, [0,1,2], [0]*3,[1]*3); ieq + The collection of inequalities + integer: (3, 7, 11) x + 2 >= 0 + sage: ieq.prepare_next_to_inner_loop([2,1,3]) + sage: ieq.prepare_inner_loop([2,1,3]) + sage: print_cache(ieq) + Cached inner loop: 3 * x_0 + 42 >= 0 + Cached next-to-inner loop: 3 * x_0 + 7 * x_1 + 35 >= 0 + """ + for ineq in self.ineqs_int: + (<Inequality_int>ineq).prepare_next_to_inner_loop(p) + for ineq in self.ineqs_generic: + (<Inequality_generic>ineq).prepare_next_to_inner_loop(p) + + cpdef prepare_inner_loop(self, p): + r""" + Peel off the inner loop. + + In the inner loop of :func:`rectangular_box_points`, we have + to repeatedly evaluate `A x+b\geq 0`. To speed up computation, we pre-evaluate + + .. MATH:: + + c = A x - A_0 x_0 +b = b + \sum_{i=1} A_i x_i + + and only test `A_0 x_0 +c \geq 0` in the inner loop. + + You must call :meth:`prepare_next_to_inner_loop` before + calling this method. + + INPUT: + + - ``p`` -- the coordinates of the point to loop over. Only the + ``p[1:]`` entries are used. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import InequalityCollection, print_cache + sage: P = Polyhedron(ieqs=[(2,3,7,11)]) + sage: ieq = InequalityCollection(P, [0,1,2], [0]*3,[1]*3); ieq + The collection of inequalities + integer: (3, 7, 11) x + 2 >= 0 + sage: ieq.prepare_next_to_inner_loop([2,1,3]) + sage: ieq.prepare_inner_loop([2,1,3]) + sage: print_cache(ieq) + Cached inner loop: 3 * x_0 + 42 >= 0 + Cached next-to-inner loop: 3 * x_0 + 7 * x_1 + 35 >= 0 + """ + for ineq in self.ineqs_int: + (<Inequality_int>ineq).prepare_inner_loop(p) + for ineq in self.ineqs_generic: + (<Inequality_generic>ineq).prepare_inner_loop(p) + + cpdef swap_ineq_to_front(self, int i): + r""" + Swap the ``i``-th entry of the list to the front of the list of inequalities. + + INPUT: + + - ``i`` -- Integer. The :class:`Inequality_int` to swap to the + beginning of the list of integral inequalities. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import InequalityCollection + sage: P_QQ = Polyhedron(identity_matrix(3).columns() + [(-2, -1,-1)], base_ring=QQ) + sage: iec = InequalityCollection(P_QQ, [0,1,2], [0]*3,[1]*3) + sage: iec + The collection of inequalities + integer: (3, -2, -2) x + 2 >= 0 + integer: (-1, 4, -1) x + 1 >= 0 + integer: (-1, -1, 4) x + 1 >= 0 + integer: (-1, -1, -1) x + 1 >= 0 + sage: iec.swap_ineq_to_front(3) + sage: iec + The collection of inequalities + integer: (-1, -1, -1) x + 1 >= 0 + integer: (3, -2, -2) x + 2 >= 0 + integer: (-1, 4, -1) x + 1 >= 0 + integer: (-1, -1, 4) x + 1 >= 0 + """ + i_th_entry = self.ineqs_int[i] + cdef int j + for j in range(i-1,-1,-1): + self.ineqs_int[j+1] = self.ineqs_int[j] + self.ineqs_int[0] = i_th_entry + + cpdef bint are_satisfied(self, inner_loop_variable) except -1: + r""" + Return whether all inequalities are satisfied. + + You must call :meth:`prepare_inner_loop` before calling this + method. + + INPUT: + + - ``inner_loop_variable`` -- Integer. the 0-th coordinate of + the lattice point. + + OUTPUT: + + Boolean. Whether the lattice point is in the polyhedron. + + EXAMPLES:: + + sage: from sage.geometry.integral_points import InequalityCollection + sage: line = Polyhedron(eqns=[(2,3,7)]) + sage: ieq = InequalityCollection(line, [0,1], [0]*2, [1]*2 ) + sage: ieq.prepare_next_to_inner_loop([3,4]) + sage: ieq.prepare_inner_loop([3,4]) + sage: ieq.are_satisfied(3) + False + """ + cdef int i + for i in range(len(self.ineqs_int)): + sig_check() + ineq = self.ineqs_int[i] + if (<Inequality_int>ineq).is_not_satisfied(inner_loop_variable): + if i > 0: + self.swap_ineq_to_front(i) + return False + for i in range(len(self.ineqs_generic)): + sig_check() + ineq = self.ineqs_generic[i] + if (<Inequality_generic>ineq).is_not_satisfied(inner_loop_variable): + return False + return True + + cpdef frozenset satisfied_as_equalities(self, inner_loop_variable): + """ + Return the inequalities (by their index) that are satisfied as + equalities. + + INPUT: + + - ``inner_loop_variable`` -- Integer. the 0-th coordinate of + the lattice point. + + OUTPUT: + + A set of integers in ascending order. Each integer is the + index of a H-representation object of the polyhedron (either a + inequality or an equation). + + EXAMPLES:: + + sage: from sage.geometry.integral_points import InequalityCollection + sage: quadrant = Polyhedron(rays=[(1,0), (0,1)]) + sage: ieqs = InequalityCollection(quadrant, [0,1], [-1]*2, [1]*2 ) + sage: ieqs.prepare_next_to_inner_loop([-1,0]) + sage: ieqs.prepare_inner_loop([-1,0]) + sage: ieqs.satisfied_as_equalities(-1) + frozenset({1}) + sage: ieqs.satisfied_as_equalities(0) + frozenset({0, 1}) + sage: ieqs.satisfied_as_equalities(1) + frozenset({1}) + """ + cdef int i + cdef list result = [] + for i in range(len(self.ineqs_int)): + sig_check() + ineq = self.ineqs_int[i] + if (<Inequality_int>ineq).is_equality(inner_loop_variable): + result.append( (<Inequality_int>ineq).index ) + for i in range(len(self.ineqs_generic)): + sig_check() + ineq = self.ineqs_generic[i] + if (<Inequality_generic>ineq).is_equality(inner_loop_variable): + result.append( (<Inequality_generic>ineq).index ) + return frozenset(result) + + + +cpdef print_cache(InequalityCollection inequality_collection): + r""" + Print the cached values in :class:`Inequality_int` (for + debugging/doctesting only). + + EXAMPLES:: + + sage: from sage.geometry.integral_points import InequalityCollection, print_cache + sage: P = Polyhedron(ieqs=[(2,3,7)]) + sage: ieq = InequalityCollection(P, [0,1], [0]*2,[1]*2); ieq + The collection of inequalities + integer: (3, 7) x + 2 >= 0 + sage: ieq.prepare_next_to_inner_loop([3,5]) + sage: ieq.prepare_inner_loop([3,5]) + sage: print_cache(ieq) + Cached inner loop: 3 * x_0 + 37 >= 0 + Cached next-to-inner loop: 3 * x_0 + 7 * x_1 + 2 >= 0 + """ + cdef Inequality_int ieq = <Inequality_int>(inequality_collection.ineqs_int[0]) + print('Cached inner loop: ' + + str(ieq.coeff) + ' * x_0 + ' + str(ieq.cache) + ' >= 0') + print('Cached next-to-inner loop: ' + + str(ieq.coeff) + ' * x_0 + ' + + str(ieq.coeff_next) + ' * x_1 + ' + str(ieq.cache_next) + ' >= 0') diff --git a/src/sage/geometry/integral_points.py b/src/sage/geometry/integral_points.py new file mode 100644 index 00000000000..48153591bcf --- /dev/null +++ b/src/sage/geometry/integral_points.py @@ -0,0 +1,24 @@ +try: + from .integral_points_integer_dense import ( + parallelotope_points, + ray_matrix_normal_form, + loop_over_parallelotope_points, + simplex_points, + rectangular_box_points, + print_cache, + Inequality_generic, + Inequality_int, + InequalityCollection, + ) +except ImportError: + from .integral_points_generic_dense import ( + parallelotope_points, + ray_matrix_normal_form, + loop_over_parallelotope_points, + simplex_points, + rectangular_box_points, + print_cache, + Inequality_generic, + Inequality_int, + InequalityCollection, + ) diff --git a/src/sage/geometry/integral_points.pyx b/src/sage/geometry/integral_points.pyx deleted file mode 100644 index 8b2e54b2d5d..00000000000 --- a/src/sage/geometry/integral_points.pyx +++ /dev/null @@ -1,1453 +0,0 @@ -#cython: wraparound=False, boundscheck=False -r""" -Cython helper methods to compute integral points in polyhedra. -""" - -#***************************************************************************** -# Copyright (C) 2010 Volker Braun <vbraun.name@gmail.com> -# -# 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** - -from cysignals.signals cimport sig_check -import copy -import itertools - -from sage.matrix.constructor import matrix, column_matrix, vector, diagonal_matrix -from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ -from sage.rings.real_mpfr import RR -from sage.rings.integer cimport Integer -from sage.arith.misc import GCD as gcd -from sage.arith.functions import lcm -from sage.combinat.permutation import Permutation -from sage.misc.misc_c import prod -from sage.modules.free_module import FreeModule -from sage.modules.vector_integer_dense cimport Vector_integer_dense -from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense - -############################################################################## -# The basic idea to enumerate the lattice points in the parallelotope -# is to use the Smith normal form of the ray coordinate matrix to -# bring the lattice into a "nice" basis. Here is the straightforward -# implementation. Note that you do not need to reduce to the -# full-dimensional case, the Smith normal form takes care of that for -# you. -# -## def parallelotope_points(spanning_points, lattice): -## # compute points in the open parallelotope, see [BK2001] -## R = matrix(spanning_points).transpose() -## D,U,V = R.smith_form() -## e = D.diagonal() # the elementary divisors -## d = prod(e) # the determinant -## u = U.inverse().columns() # generators for gp(semigroup) -## -## # "inverse" of the ray matrix as far as possible over ZZ -## # R*Rinv == diagonal_matrix([d]*D.ncols() + [0]*(D.nrows()-D.ncols())) -## # If R is full rank, this is Rinv = matrix(ZZ, R.inverse() * d) -## Dinv = D.transpose() -## for i in range(D.ncols()): -## Dinv[i,i] = d/D[i,i] -## Rinv = V * Dinv * U -## -## gens = [] -## for b in CartesianProduct(*[ range(i) for i in e ]): -## # this is our generator modulo the lattice spanned by the rays -## gen_mod_rays = sum( b_i*u_i for b_i, u_i in zip(b,u) ) -## q_times_d = Rinv * gen_mod_rays -## q_times_d = vector(ZZ,[ q_i % d for q_i in q_times_d ]) -## gen = lattice(R*q_times_d / d) -## gen.set_immutable() -## gens.append(gen) -## assert(len(gens) == d) -## return tuple(gens) -# -# The problem with the naive implementation is that it is slow: -# -# 1. You can simplify some of the matrix multiplications -# -# 2. The inner loop keeps creating new matrices and vectors, which -# is slow. It needs to recycle objects. Instead of creating a new -# lattice point again and again, change the entries of an -# existing lattice point and then copy it! - - -cpdef tuple parallelotope_points(spanning_points, lattice): - r""" - Return integral points in the parallelotope starting at the origin - and spanned by the ``spanning_points``. - - See :meth:`~ConvexRationalPolyhedralCone.semigroup_generators` for a description of the - algorithm. - - INPUT: - - - ``spanning_points`` -- a non-empty list of linearly independent - rays (`\ZZ`-vectors or :class:`toric lattice - <sage.geometry.toric_lattice.ToricLatticeFactory>` elements), - not necessarily primitive lattice points. - - OUTPUT: - - The tuple of all lattice points in the half-open parallelotope - spanned by the rays `r_i`, - - .. MATH:: - - \mathop{par}(\{r_i\}) = - \sum_{0\leq a_i < 1} a_i r_i - - By half-open parallelotope, we mean that the - points in the facets not meeting the origin are omitted. - - EXAMPLES: - - Note how the points on the outward-facing factes are omitted:: - - sage: from sage.geometry.integral_points import parallelotope_points - sage: rays = list(map(vector, [(2,0), (0,2)])) - sage: parallelotope_points(rays, ZZ^2) - ((0, 0), (0, 1), (1, 0), (1, 1)) - - The rays can also be toric lattice points:: - - sage: rays = list(map(ToricLattice(2), [(2,0), (0,2)])) - sage: parallelotope_points(rays, ToricLattice(2)) - (N(0, 0), N(0, 1), N(1, 0), N(1, 1)) - - A non-smooth cone:: - - sage: c = Cone([ (1,0), (1,2) ]) - sage: parallelotope_points(c.rays(), c.lattice()) - (N(0, 0), N(1, 1)) - - A ``ValueError`` is raised if the ``spanning_points`` are not - linearly independent:: - - sage: rays = list(map(ToricLattice(2), [(1,1)]*2)) - sage: parallelotope_points(rays, ToricLattice(2)) - Traceback (most recent call last): - ... - ValueError: The spanning points are not linearly independent! - - TESTS:: - - sage: rays = list(map(vector,[(-3, -2, -3, -2), (-2, -1, -8, 5), (1, 9, -7, -4), (-3, -1, -2, 2)])) - sage: len(parallelotope_points(rays, ZZ^4)) - 967 - """ - cdef Matrix_integer_dense VDinv - cdef Matrix_integer_dense R = matrix(spanning_points).transpose() - e, d, VDinv = ray_matrix_normal_form(R) - cdef tuple points = loop_over_parallelotope_points(e, d, VDinv, R, lattice) - for p in points: - p.set_immutable() - return points - - -cpdef tuple ray_matrix_normal_form(R): - r""" - Compute the Smith normal form of the ray matrix for - :func:`parallelotope_points`. - - INPUT: - - - ``R`` -- `\ZZ`-matrix whose columns are the rays spanning the - parallelotope. - - OUTPUT: - - A tuple containing ``e``, ``d``, and ``VDinv``. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import ray_matrix_normal_form - sage: R = column_matrix(ZZ,[3,3,3]) - sage: ray_matrix_normal_form(R) - ([3], 3, [1]) - """ - D,U,V = R.smith_form() - e = D.diagonal() # the elementary divisors - cdef Integer d = prod(e) # the determinant - if d == ZZ.zero(): - raise ValueError('The spanning points are not linearly independent!') - cdef int i - Dinv = diagonal_matrix(ZZ, [ d // e[i] for i in range(D.ncols()) ]) - VDinv = V * Dinv - return (e, d, VDinv) - - - -# The optimized version avoids constructing new matrices, vectors, and lattice points -cpdef tuple loop_over_parallelotope_points(e, d, Matrix_integer_dense VDinv, - Matrix_integer_dense R, lattice, - A=None, b=None): - r""" - The inner loop of :func:`parallelotope_points`. - - INPUT: - - See :meth:`parallelotope_points` for ``e``, ``d``, ``VDinv``, ``R``, ``lattice``. - - - ``A``, ``b``: Either both ``None`` or a vector and number. If - present, only the parallelotope points satisfying `A x \leq b` - are returned. - - OUTPUT: - - The points of the half-open parallelotope as a tuple of lattice - points. - - EXAMPLES:: - - sage: e = [3] - sage: d = prod(e) - sage: VDinv = matrix(ZZ, [[1]]) - sage: R = column_matrix(ZZ,[3,3,3]) - sage: lattice = ZZ^3 - sage: from sage.geometry.integral_points import loop_over_parallelotope_points - sage: loop_over_parallelotope_points(e, d, VDinv, R, lattice) - ((0, 0, 0), (1, 1, 1), (2, 2, 2)) - - sage: A = vector(ZZ, [1,0,0]) - sage: b = 1 - sage: loop_over_parallelotope_points(e, d, VDinv, R, lattice, A, b) - ((0, 0, 0), (1, 1, 1)) - """ - cdef int i, j - cdef int dim = VDinv.nrows() - cdef int ambient_dim = R.nrows() - s = ZZ.zero() # summation variable - cdef list gens = [] - gen = lattice(ZZ.zero()) - cdef Vector_integer_dense q_times_d = vector(ZZ, dim) - for base in itertools.product(*[ range(i) for i in e ]): - for i in range(dim): - s = ZZ.zero() - for j in range(dim): - s += VDinv.get_unsafe(i,j) * base[j] - q_times_d.set_unsafe(i, s % d) - for i in range(ambient_dim): - s = ZZ.zero() - for j in range(dim): - s += R.get_unsafe(i,j) * q_times_d.get_unsafe(j) - gen[i] = s / d - if A is not None: - s = ZZ.zero() - for i in range(ambient_dim): - s += A[i] * gen[i] - if s > b: - continue - gens.append(copy.copy(gen)) - if A is None: - assert(len(gens) == d) - return tuple(gens) - - - -############################################################################## -cpdef tuple simplex_points(vertices): - r""" - Return the integral points in a lattice simplex. - - INPUT: - - - ``vertices`` -- an iterable of integer coordinate vectors. The - indices of vertices that span the simplex under - consideration. - - OUTPUT: - - A tuple containing the integral point coordinates as `\ZZ`-vectors. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import simplex_points - sage: simplex_points([(1,2,3), (2,3,7), (-2,-3,-11)]) - ((-2, -3, -11), (0, 0, -2), (1, 2, 3), (2, 3, 7)) - - The simplex need not be full-dimensional:: - - sage: simplex = Polyhedron([(1,2,3,5), (2,3,7,5), (-2,-3,-11,5)]) - sage: simplex_points(simplex.Vrepresentation()) - ((2, 3, 7, 5), (0, 0, -2, 5), (-2, -3, -11, 5), (1, 2, 3, 5)) - - sage: simplex_points([(2,3,7)]) - ((2, 3, 7),) - - TESTS:: - - sage: v = [(1,0,7,-1), (-2,-2,4,-3), (-1,-1,-1,4), (2,9,0,-5), (-2,-1,5,1)] - sage: simplex = Polyhedron(v); simplex - A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices - sage: pts = simplex_points(simplex.Vrepresentation()) - sage: len(pts) - 49 - sage: for p in pts: p.set_immutable() - sage: len(set(pts)) - 49 - - sage: all(simplex.contains(p) for p in pts) - True - - sage: v = [(4,-1,-1,-1), (-1,4,-1,-1), (-1,-1,4,-1), (-1,-1,-1,4), (-1,-1,-1,-1)] - sage: P4mirror = Polyhedron(v); P4mirror - A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices - sage: len(simplex_points(P4mirror.Vrepresentation())) - 126 - - sage: vertices = list(map(vector, [(1,2,3), (2,3,7), (-2,-3,-11)])) - sage: for v in vertices: v.set_immutable() - sage: simplex_points(vertices) - ((-2, -3, -11), (0, 0, -2), (1, 2, 3), (2, 3, 7)) - """ - cdef list rays = [vector(ZZ, list(v)) for v in vertices] - if not rays: - return () - cdef Vector_integer_dense origin = rays.pop() - origin.set_immutable() - if not rays: - return (origin,) - translate_points(rays, origin) - - # Find equation Ax<=b that cuts out simplex from parallelotope - cdef Matrix_integer_dense Rt = matrix(ZZ, rays) - cdef Matrix_integer_dense R = Rt.transpose() - cdef int nrays = len(rays) - cdef Integer b - M = FreeModule(ZZ, nrays) - if R.is_square(): - b = abs(R.det()) - A = R.solve_left(M([b]*nrays)) - else: - RtR = Rt * R - b = abs(RtR.det()) - A = RtR.solve_left(M([b]*nrays)) * Rt - - e, d, VDinv = ray_matrix_normal_form(R) - lattice = origin.parent() - points = loop_over_parallelotope_points(e, d, VDinv, R, lattice, A, b) + tuple(rays) - translate_points(points, -origin) - return points - - -cdef translate_points(v_list, Vector_integer_dense delta): - r""" - Add ``delta`` to each vector in ``v_list``. - """ - cdef int dim = delta.degree() - cdef int i - for v in v_list: - for i in range(dim): - v[i] -= delta.get_unsafe(i) - - - -############################################################################## -# For points with "small" coordinates (that is, fitting into a small -# rectangular bounding box) it is faster to naively enumerate the -# points. This saves the overhead of triangulating the polytope etc. - -cpdef rectangular_box_points(list box_min, list box_max, - polyhedron=None, count_only=False, - return_saturated=False): - r""" - Return the integral points in the lattice bounding box that are - also contained in the given polyhedron. - - INPUT: - - - ``box_min`` -- A list of integers. The minimal value for each - coordinate of the rectangular bounding box. - - - ``box_max`` -- A list of integers. The maximal value for each - coordinate of the rectangular bounding box. - - - ``polyhedron`` -- A - :class:`~sage.geometry.polyhedron.base.Polyhedron_base`, a PPL - :class:`~ppl.polyhedron.C_Polyhedron`, or ``None`` (default). - - - ``count_only`` -- Boolean (default: ``False``). Whether to - return only the total number of vertices, and not their - coordinates. Enabling this option speeds up the - enumeration. Cannot be combined with the ``return_saturated`` - option. - - - ``return_saturated`` -- Boolean (default: ``False``. Whether to - also return which inequalities are saturated for each point of - the polyhedron. Enabling this slows down the enumeration. Cannot - be combined with the ``count_only`` option. - - OUTPUT: - - By default, this function returns a tuple containing the integral - points of the rectangular box spanned by ``box_min`` and ``box_max`` - and that lie inside the ``polyhedron``. For sufficiently large - bounding boxes, this are all integral points of the polyhedron. - - If no polyhedron is specified, all integral points of the - rectangular box are returned. - - If ``count_only`` is specified, only the total number (an integer) - of found lattice points is returned. - - If ``return_saturated`` is enabled, then for each integral point a - pair ``(point, Hrep)`` is returned where ``point`` is the point - and ``Hrep`` is the set of indices of the H-representation objects - that are saturated at the point. - - ALGORITHM: - - This function implements the naive algorithm towards counting - integral points. Given min and max of vertex coordinates, it - iterates over all points in the bounding box and checks whether - they lie in the polyhedron. The following optimizations are - implemented: - - * Cython: Use machine integers and optimizing C/C++ compiler - where possible, arbitrary precision integers where necessary. - Bounds checking, no compile time limits. - - * Unwind inner loop (and next-to-inner loop): - - .. MATH:: - - Ax \leq b - \quad \Leftrightarrow \quad - a_1 x_1 ~\leq~ b - \sum_{i=2}^d a_i x_i - - so we only have to evaluate `a_1 * x_1` in the inner loop. - - * Coordinates are permuted to make the longest box edge the - inner loop. The inner loop is optimized to run very fast, so - its best to do as much work as possible there. - - * Continuously reorder inequalities and test the most - restrictive inequalities first. - - * Use convexity and only find first and last allowed point in - the inner loop. The points in-between must be points of the - polyhedron, too. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import rectangular_box_points - sage: rectangular_box_points([0,0,0],[1,2,3]) - ((0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), - (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), - (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 2, 3), - (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 0, 3), - (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), - (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 2, 3)) - - sage: from sage.geometry.integral_points import rectangular_box_points - sage: rectangular_box_points([0,0,0],[1,2,3], count_only=True) - 24 - - sage: cell24 = polytopes.twenty_four_cell() - sage: rectangular_box_points([-1]*4, [1]*4, cell24) - ((-1, 0, 0, 0), (0, -1, 0, 0), (0, 0, -1, 0), (0, 0, 0, -1), - (0, 0, 0, 0), - (0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, 0), (1, 0, 0, 0)) - sage: d = 3 - sage: dilated_cell24 = d*cell24 - sage: len( rectangular_box_points([-d]*4, [d]*4, dilated_cell24) ) - 305 - - sage: d = 6 - sage: dilated_cell24 = d*cell24 - sage: len( rectangular_box_points([-d]*4, [d]*4, dilated_cell24) ) - 3625 - - sage: rectangular_box_points([-d]*4, [d]*4, dilated_cell24, count_only=True) - 3625 - - sage: polytope = Polyhedron([(-4,-3,-2,-1),(3,1,1,1),(1,2,1,1),(1,1,3,0),(1,3,2,4)]) - sage: pts = rectangular_box_points([-4]*4, [4]*4, polytope); pts - ((-4, -3, -2, -1), (-1, 0, 0, 1), (0, 1, 1, 1), (1, 1, 1, 1), (1, 1, 3, 0), - (1, 2, 1, 1), (1, 2, 2, 2), (1, 3, 2, 4), (2, 1, 1, 1), (3, 1, 1, 1)) - sage: all(polytope.contains(p) for p in pts) - True - - sage: set(map(tuple,pts)) == \ - ....: set([(-4,-3,-2,-1),(3,1,1,1),(1,2,1,1),(1,1,3,0),(1,3,2,4), - ....: (0,1,1,1),(1,2,2,2),(-1,0,0,1),(1,1,1,1),(2,1,1,1)]) # computed with PALP - True - - Long ints and non-integral polyhedra are explicitly allowed:: - - sage: polytope = Polyhedron([[1], [10*pi.n()]], base_ring=RDF) - sage: len( rectangular_box_points([-100], [100], polytope) ) - 31 - - sage: halfplane = Polyhedron(ieqs=[(-1,1,0)]) - sage: rectangular_box_points([0,-1+10^50], [0,1+10^50]) - ((0, 99999999999999999999999999999999999999999999999999), - (0, 100000000000000000000000000000000000000000000000000), - (0, 100000000000000000000000000000000000000000000000001)) - sage: len( rectangular_box_points([0,-100+10^50], [1,100+10^50], halfplane) ) - 201 - - Using a PPL polyhedron:: - - sage: from ppl import Variable, Generator_System, C_Polyhedron, point - sage: gs = Generator_System() - sage: x = Variable(0); y = Variable(1); z = Variable(2) - sage: gs.insert(point(0*x + 1*y + 0*z)) - sage: gs.insert(point(0*x + 1*y + 3*z)) - sage: gs.insert(point(3*x + 1*y + 0*z)) - sage: gs.insert(point(3*x + 1*y + 3*z)) - sage: poly = C_Polyhedron(gs) - sage: rectangular_box_points([0]*3, [3]*3, poly) - ((0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), - (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 1, 3), (3, 1, 0), (3, 1, 1), (3, 1, 2), (3, 1, 3)) - - Optionally, return the information about the saturated inequalities as well:: - - sage: cube = polytopes.cube() - sage: cube.Hrepresentation(0) - An inequality (-1, 0, 0) x + 1 >= 0 - sage: cube.Hrepresentation(1) - An inequality (0, -1, 0) x + 1 >= 0 - sage: cube.Hrepresentation(2) - An inequality (0, 0, -1) x + 1 >= 0 - sage: rectangular_box_points([0]*3, [1]*3, cube, return_saturated=True) - (((0, 0, 0), frozenset()), - ((0, 0, 1), frozenset({2})), - ((0, 1, 0), frozenset({1})), - ((0, 1, 1), frozenset({1, 2})), - ((1, 0, 0), frozenset({0})), - ((1, 0, 1), frozenset({0, 2})), - ((1, 1, 0), frozenset({0, 1})), - ((1, 1, 1), frozenset({0, 1, 2}))) - - TESTS: - - Check that this can be interrupted, see :trac:`20781`:: - - sage: ieqs = [(-1, -1, -1, -1, -1, -1, -1, -1, -1), - ....: (0, -1, 0, 0, 0, 0, 0, 0, 0), - ....: (0, -1, 0, 2, -1, 0, 0, 0, 0), - ....: (0, 0, -1, -1, 2, -1, 0, 0, 0), - ....: (0, 2, 0, -1, 0, 0, 0, 0, 0), - ....: (0, 0, 0, 0, 0, 0, 0, -1, 2), - ....: (1, 0, 2, 0, -1, 0, 0, 0, 0), - ....: (0, 0, 0, 0, -1, 2, -1, 0, 0), - ....: (0, 0, 0, 0, 0, 0, 0, 0, -1), - ....: (0, 0, 0, 0, 0, -1, 2, -1, 0), - ....: (0, 0, 0, 0, 0, 0, -1, 2, -1)] - sage: P = Polyhedron(ieqs=ieqs) - sage: alarm(0.5); P.integral_points() - Traceback (most recent call last): - ... - AlarmInterrupt - """ - assert len(box_min) == len(box_max) - assert not (count_only and return_saturated) - cdef int d = len(box_min) - cdef int i, j - cdef list diameter = sorted([ (box_max[i]-box_min[i], i) for i in range(d) ], - reverse=True) - cdef list diameter_value = [x[0] for x in diameter] - cdef list diameter_index = [x[1] for x in diameter] - - # Construct the inverse permutation - cdef list orig_perm = list(xrange(len(diameter_index))) - for i, j in enumerate(diameter_index): - orig_perm[j] = i - - box_min = perm_action(diameter_index, box_min) - box_max = perm_action(diameter_index, box_max) - cdef InequalityCollection inequalities = InequalityCollection(polyhedron, diameter_index, box_min, box_max) - - if count_only: - return loop_over_rectangular_box_points(box_min, box_max, inequalities, d, count_only) - - cdef list points = [] - cdef Vector_integer_dense v = vector(ZZ, d) - if not return_saturated: - for p in loop_over_rectangular_box_points(box_min, box_max, inequalities, d, count_only): - # v = vector(ZZ, perm_action(orig_perm, p)) # too slow - for i in range(d): - v.set_unsafe(i, Integer(p[orig_perm[i]])) - v_copy = copy.copy(v) - v_copy.set_immutable() - points.append(v_copy) - else: - for p, saturated in loop_over_rectangular_box_points_saturated(box_min, box_max, - inequalities, d): - for i in range(d): - v.set_unsafe(i, Integer(p[orig_perm[i]])) - v_copy = copy.copy(v) - v_copy.set_immutable() - points.append( (v_copy, saturated) ) - - return tuple(points) - -cdef list perm_action(list p, list lst): - """ - Return the action of a permutation ``p`` of `(0, ..., n-1)` - on a list of length `n`. - """ - return [lst[i] for i in p] - -cdef loop_over_rectangular_box_points(list box_min, list box_max, - InequalityCollection inequalities, - int d, bint count_only): - """ - The inner loop of :func:`rectangular_box_points`. - - INPUT: - - - ``box_min``, ``box_max`` -- the bounding box. - - - ``inequalities`` -- a :class:`InequalityCollection` containing - the inequalities defining the polyhedron. - - - ``d`` -- the ambient space dimension. - - - ``count_only`` -- whether to only return the total number of - lattice points. - - OUTPUT: - - The integral points in the bounding box satisfying all - inequalities. - """ - cdef int inc - cdef Integer i_min, i_max - if count_only: - points = 0 - else: - points = [] - cdef list p = list(box_min) - inequalities.prepare_next_to_inner_loop(p) - while True: - sig_check() - inequalities.prepare_inner_loop(p) - i_min = box_min[0] - i_max = box_max[0] - # Find the lower bound for the allowed region - while i_min <= i_max: - if inequalities.are_satisfied(i_min): - break - i_min += 1 - # Find the upper bound for the allowed region - while i_min <= i_max: - if inequalities.are_satisfied(i_max): - break - i_max -= 1 - # The points i_min .. i_max are contained in the polyhedron - if count_only: - if i_max >= i_min: - points += i_max - i_min + 1 - else: - i = i_min - while i <= i_max: - p[0] = i - points.append(tuple(p)) - i += 1 - # finally increment the other entries in p to move on to next inner loop - inc = 1 - if d == 1: - return points - while True: - if p[inc] == box_max[inc]: - p[inc] = box_min[inc] - inc += 1 - if inc == d: - return points - else: - p[inc] += 1 - break - if inc > 1: - inequalities.prepare_next_to_inner_loop(p) - - - -cdef loop_over_rectangular_box_points_saturated(list box_min, list box_max, - InequalityCollection inequalities, - int d): - """ - The analog of :func:`rectangular_box_points` except that it keeps - track of which inequalities are saturated. - - INPUT: - - See :func:`rectangular_box_points`. - - OUTPUT: - - The integral points in the bounding box satisfying all - inequalities, each point being returned by a coordinate vector and - a set of H-representation object indices. - """ - cdef int inc - cdef list points = [] - cdef list p = list(box_min) - inequalities.prepare_next_to_inner_loop(p) - while True: - inequalities.prepare_inner_loop(p) - i_min = box_min[0] - i_max = box_max[0] - # Find the lower bound for the allowed region - while i_min <= i_max: - if inequalities.are_satisfied(i_min): - break - i_min += 1 - # Find the upper bound for the allowed region - while i_min <= i_max: - if inequalities.are_satisfied(i_max): - break - i_max -= 1 - # The points i_min .. i_max are contained in the polyhedron - i = i_min - while i <= i_max: - p[0] = i - saturated = inequalities.satisfied_as_equalities(i) - points.append( (tuple(p), saturated) ) - i += 1 - # finally increment the other entries in p to move on to next inner loop - inc = 1 - if d == 1: - return points - while True: - if p[inc] == box_max[inc]: - p[inc] = box_min[inc] - inc += 1 - if inc == d: - return points - else: - p[inc] += 1 - break - if inc > 1: - inequalities.prepare_next_to_inner_loop(p) - - -cdef class Inequality_generic: - r""" - An inequality whose coefficients are arbitrary Python/Sage objects - - INPUT: - - - ``A`` -- list of coefficients - - - ``b`` -- element - - OUTPUT: - - Inequality `A x + b \geq 0`. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import Inequality_generic - sage: Inequality_generic([2*pi,sqrt(3),7/2], -5.5) - generic: (2*pi, sqrt(3), 7/2) x + -5.50000000000000 >= 0 - """ - - cdef list A - cdef object b - cdef object coeff - cdef object cache - # The index of the inequality in the polyhedron H-representation - cdef int index - - def __cinit__(self, list A, b, int index=-1): - """ - The Cython constructor - - INPUT: - - See :class:`Inequality_generic`. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import Inequality_generic - sage: Inequality_generic([2*pi,sqrt(3),7/2], -5.5) - generic: (2*pi, sqrt(3), 7/2) x + -5.50000000000000 >= 0 - """ - self.A = A - self.b = b - self.coeff = 0 - self.cache = 0 - self.index = int(index) - - def __repr__(self): - """ - Return a string representation. - - OUTPUT: - - String. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import Inequality_generic - sage: Inequality_generic([2,3,7], -5).__repr__() - 'generic: (2, 3, 7) x + -5 >= 0' - """ - s = 'generic: (' - s += ', '.join(str(self.A[i]) for i in range(len(self.A))) - s += ') x + ' + str(self.b) + ' >= 0' - return s - - cdef prepare_next_to_inner_loop(self, p): - """ - In :class:`Inequality_int` this method is used to peel of the - next-to-inner loop. - - See :meth:`InequalityCollection.prepare_inner_loop` for more details. - """ - pass - - cdef prepare_inner_loop(self, p): - """ - Peel off the inner loop. - - See :meth:`InequalityCollection.prepare_inner_loop` for more details. - """ - cdef int j - self.coeff = self.A[0] - self.cache = self.b - for j in range(1, len(self.A)): - self.cache += self.A[j] * p[j] - - cdef bint is_not_satisfied(self, inner_loop_variable) except -1: - r""" - Test the inequality, using the cached value from :meth:`prepare_inner_loop` - - OUTPUT: - - Boolean. Whether the inequality is not satisfied. - """ - return inner_loop_variable * self.coeff + self.cache < 0 - - cdef bint is_equality(Inequality_generic self, int inner_loop_variable) except -1: - r""" - Test the inequality, using the cached value from :meth:`prepare_inner_loop` - - OUTPUT: - - Boolean. Given the inequality `Ax + b \geq 0`, this method - returns whether the equality `Ax + b = 0` is satisfied. - """ - return inner_loop_variable * self.coeff + self.cache == 0 - - -# if dim>20 then we always use the generic inequalities (Inequality_generic) -DEF INEQ_INT_MAX_DIM = 20 - -cdef class Inequality_int: - r""" - Fast version of inequality in the case that all coefficients fit - into machine ints. - - INPUT: - - - ``A`` -- list of integers - - - ``b`` -- integer - - - ``max_abs_coordinates`` -- the maximum of the coordinates that - one wants to evaluate the coordinates on; used for overflow - checking - - OUTPUT: - - Inequality `A x + b \geq 0`. A ``OverflowError`` is raised if a - machine integer is not long enough to hold the results. A - ``ValueError`` is raised if some of the input is not integral. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import Inequality_int - sage: Inequality_int([2,3,7], -5, [10]*3) - integer: (2, 3, 7) x + -5 >= 0 - - sage: Inequality_int([1]*21, -5, [10]*21) - Traceback (most recent call last): - ... - OverflowError: Dimension limit exceeded. - - sage: Inequality_int([2,3/2,7], -5, [10]*3) - Traceback (most recent call last): - ... - ValueError: Not integral. - - sage: Inequality_int([2,3,7], -5.2, [10]*3) - Traceback (most recent call last): - ... - ValueError: Not integral. - - sage: Inequality_int([2,3,7], -5*10^50, [10]*3) # actual error message can differ between 32 and 64 bit - Traceback (most recent call last): - ... - OverflowError: ... - - TESTS: - - Check that :trac:`21993` is fixed:: - - sage: Inequality_int([18560500, -89466500], 108027, [178933, 37121]) - Traceback (most recent call last): - ... - OverflowError: ... - - """ - cdef int A[INEQ_INT_MAX_DIM] - cdef int b - cdef int dim - # the innermost coefficient - cdef int coeff - cdef int cache - # the next-to-innermost coefficient - cdef int coeff_next - cdef int cache_next - # The index of the inequality in the polyhedron H-representation - cdef int index - - cdef int _to_int(self, x) except? -999: - if x not in ZZ: - raise ValueError('Not integral.') - return int(x) # raises OverflowError in Cython if necessary - - def __cinit__(self, list A, b, list max_abs_coordinates, int index=-1): - """ - The Cython constructor - - See :class:`Inequality_int` for input. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import Inequality_int - sage: Inequality_int([2,3,7], -5, [10]*3) - integer: (2, 3, 7) x + -5 >= 0 - """ - cdef int i - self.dim = self._to_int(len(A)) - self.index = int(index) - if self.dim < 1 or self.dim > INEQ_INT_MAX_DIM: - raise OverflowError('Dimension limit exceeded.') - for i in range(self.dim): - self.A[i] = self._to_int(A[i]) - self.b = self._to_int(b) - self.coeff = self.A[0] - if self.dim > 0: - self.coeff_next = self.A[1] - # finally, make sure that there cannot be any overflow during the enumeration - self._to_int(abs(ZZ(b)) + sum( abs(ZZ(A[i])) * ZZ(max_abs_coordinates[i]) - for i in range(self.dim) )) - - def __repr__(self): - """ - Return a string representation. - - OUTPUT: - - String. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import Inequality_int - sage: Inequality_int([2,3,7], -5, [10]*3).__repr__() - 'integer: (2, 3, 7) x + -5 >= 0' - """ - s = 'integer: (' - s += ', '.join([str(self.A[i]) for i in range(self.dim)]) - s += ') x + ' + str(self.b) + ' >= 0' - return s - - cdef prepare_next_to_inner_loop(Inequality_int self, p): - """ - Peel off the next-to-inner loop. - - See :meth:`InequalityCollection.prepare_inner_loop` for more details. - """ - cdef int j - self.cache_next = self.b - for j in range(2, self.dim): - self.cache_next += self.A[j] * p[j] - - cdef prepare_inner_loop(Inequality_int self, p): - """ - Peel off the inner loop. - - See :meth:`InequalityCollection.prepare_inner_loop` for more details. - """ - cdef int j - if self.dim > 1: - self.cache = self.cache_next + self.coeff_next * p[1] - else: - self.cache = self.cache_next - - cdef bint is_not_satisfied(Inequality_int self, int inner_loop_variable): - return inner_loop_variable * self.coeff + self.cache < 0 - - cdef bint is_equality(Inequality_int self, int inner_loop_variable): - return inner_loop_variable * self.coeff + self.cache == 0 - - - -cdef class InequalityCollection: - """ - A collection of inequalities. - - INPUT: - - - ``polyhedron`` -- a polyhedron defining the inequalities. - - - ``permutation`` -- list; a 0-based permutation of the coordinates. - Will be used to permute the coordinates of the inequality. - - - ``box_min``, ``box_max`` -- the (not permuted) minimal and maximal - coordinates of the bounding box. Used for bounds checking. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import InequalityCollection - sage: P_QQ = Polyhedron(identity_matrix(3).columns() + [(-2, -1,-1)], base_ring=QQ) - sage: ieq = InequalityCollection(P_QQ, [0,1,2], [0]*3,[1]*3); ieq - The collection of inequalities - integer: (3, -2, -2) x + 2 >= 0 - integer: (-1, 4, -1) x + 1 >= 0 - integer: (-1, -1, 4) x + 1 >= 0 - integer: (-1, -1, -1) x + 1 >= 0 - - sage: P_RR = Polyhedron(identity_matrix(2).columns() + [(-2.7, -1)], base_ring=RDF) - sage: InequalityCollection(P_RR, [0,1], [0]*2, [1]*2) - The collection of inequalities - integer: (-1, -1) x + 1 >= 0 - generic: (-1.0, 3.7) x + 1.0 >= 0 - generic: (1.0, -1.35) x + 1.35 >= 0 - - sage: line = Polyhedron(eqns=[(2,3,7)]) - sage: InequalityCollection(line, [0,1], [0]*2, [1]*2 ) - The collection of inequalities - integer: (3, 7) x + 2 >= 0 - integer: (-3, -7) x + -2 >= 0 - - TESTS:: - - sage: TestSuite(ieq).run(skip='_test_pickling') - """ - cdef list ineqs_int - cdef list ineqs_generic - - def __repr__(self): - r""" - Return a string representation. - - OUTPUT: - - String. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import InequalityCollection - sage: line = Polyhedron(eqns=[(2,3,7)]) - sage: InequalityCollection(line, [0,1], [0]*2, [1]*2 ).__repr__() - 'The collection of inequalities\ninteger: (3, 7) x + 2 >= 0\ninteger: (-3, -7) x + -2 >= 0' - """ - s = 'The collection of inequalities\n' - for ineq in self.ineqs_int: - s += str(<Inequality_int>ineq) + '\n' - for ineq in self.ineqs_generic: - s += str(<Inequality_generic>ineq) + '\n' - return s.strip() - - cpdef tuple _make_A_b(self, Hrep_obj, list permutation): - r""" - Return the coefficients and constant of the H-representation - object. - - INPUT: - - - ``Hrep_obj`` -- a H-representation object of the polyhedron - - ``permutation`` -- the permutation of the coordinates to - apply to ``A`` - - OUTPUT: - - A pair ``(A,b)``. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import InequalityCollection - sage: line = Polyhedron(eqns=[(2,3,7)]) - sage: ieq = InequalityCollection(line, [0,1], [0]*2, [1]*2 ) - sage: ieq._make_A_b(line.Hrepresentation(0), [0,1]) - ([3, 7], 2) - sage: ieq._make_A_b(line.Hrepresentation(0), [1,0]) - ([7, 3], 2) - """ - cdef list v = list(Hrep_obj) - cdef list A = perm_action(permutation, v[1:]) - b = v[0] - try: - x = lcm([a.denominator() for a in A] + [b.denominator()]) - A = [a * x for a in A] - b = b * x - except AttributeError: - pass - return (A, b) - - def __cinit__(self, polyhedron, list permutation, box_min, box_max): - """ - The Cython constructor - - See the class documentation for the description of the arguments. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import InequalityCollection - sage: line = Polyhedron(eqns=[(2,3,7)]) - sage: InequalityCollection(line, [0,1], [0]*2, [1]*2 ) - The collection of inequalities - integer: (3, 7) x + 2 >= 0 - integer: (-3, -7) x + -2 >= 0 - """ - cdef list max_abs_coordinates = [max(abs(c_min), abs(c_max)) - for c_min, c_max in zip(box_min, box_max)] - max_abs_coordinates = perm_action(permutation, max_abs_coordinates) - self.ineqs_int = [] - self.ineqs_generic = [] - if polyhedron is None: - return - - try: - # polyhedron is a PPL C_Polyhedron class? - self._cinit_from_PPL(max_abs_coordinates, permutation, polyhedron) - except AttributeError: - try: - # polyhedron is a Polyhedron class? - self._cinit_from_Polyhedron(max_abs_coordinates, permutation, polyhedron) - except AttributeError: - raise TypeError('Cannot extract Hrepresentation data from polyhedron.') - - cdef _cinit_from_PPL(self, list max_abs_coordinates, list permutation, - polyhedron): - """ - Initialize the inequalities from a PPL C_Polyhedron - - See __cinit__ for a description of the arguments. - - EXAMPLES:: - - sage: from ppl import Variable, Generator_System, C_Polyhedron, point - sage: gs = Generator_System() - sage: x = Variable(0); y = Variable(1); z = Variable(2) - sage: gs.insert(point(0*x + 0*y + 1*z)) - sage: gs.insert(point(0*x + 3*y + 1*z)) - sage: gs.insert(point(3*x + 0*y + 1*z)) - sage: gs.insert(point(3*x + 3*y + 1*z)) - sage: poly = C_Polyhedron(gs) - sage: from sage.geometry.integral_points import InequalityCollection - sage: InequalityCollection(poly, [0,2,1], [0]*3, [3]*3 ) - The collection of inequalities - integer: (0, 1, 0) x + -1 >= 0 - integer: (0, -1, 0) x + 1 >= 0 - integer: (1, 0, 0) x + 0 >= 0 - integer: (0, 0, 1) x + 0 >= 0 - integer: (-1, 0, 0) x + 3 >= 0 - integer: (0, 0, -1) x + 3 >= 0 - """ - cdef list A - cdef int index - for index,c in enumerate(polyhedron.minimized_constraints()): - A = perm_action(permutation, [Integer(mpz) for mpz in c.coefficients()]) - b = Integer(c.inhomogeneous_term()) - try: - H = Inequality_int(A, b, max_abs_coordinates, index) - self.ineqs_int.append(H) - except (OverflowError, ValueError): - H = Inequality_generic(A, b, index) - self.ineqs_generic.append(H) - if c.is_equality(): - A = [ -a for a in A ] - b = -b - try: - H = Inequality_int(A, b, max_abs_coordinates, index) - self.ineqs_int.append(H) - except (OverflowError, ValueError): - H = Inequality_generic(A, b, index) - self.ineqs_generic.append(H) - - cdef _cinit_from_Polyhedron(self, list max_abs_coordinates, - list permutation, polyhedron): - """ - Initialize the inequalities from a Sage Polyhedron - - See __cinit__ for a description of the arguments. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import InequalityCollection - sage: line = Polyhedron(eqns=[(2,3,7)]) - sage: InequalityCollection(line, [0,1], [0]*2, [1]*2 ) - The collection of inequalities - integer: (3, 7) x + 2 >= 0 - integer: (-3, -7) x + -2 >= 0 - - TESTS: - - Check that :trac:`21037` is fixed:: - - sage: P = Polyhedron(vertices=((0, 0), (17,3))) - sage: P += 1/1000*polytopes.regular_polygon(5) # optional - sage.rings.number_field - sage: P.integral_points() # optional - sage.rings.number_field - ((0, 0), (17, 3)) - """ - cdef list A - for Hrep_obj in polyhedron.inequality_generator(): - A, b = self._make_A_b(Hrep_obj, permutation) - try: - H = Inequality_int(A, b, max_abs_coordinates, Hrep_obj.index()) - self.ineqs_int.append(H) - except (OverflowError, ValueError, TypeError): - H = Inequality_generic(A, b, Hrep_obj.index()) - self.ineqs_generic.append(H) - for Hrep_obj in polyhedron.equation_generator(): - A, b = self._make_A_b(Hrep_obj, permutation) - # add inequality - try: - H = Inequality_int(A, b, max_abs_coordinates, Hrep_obj.index()) - self.ineqs_int.append(H) - except (OverflowError, ValueError, TypeError): - H = Inequality_generic(A, b, Hrep_obj.index()) - self.ineqs_generic.append(H) - # add sign-reversed inequality - A = [ -a for a in A ] - b = -b - try: - H = Inequality_int(A, b, max_abs_coordinates, Hrep_obj.index()) - self.ineqs_int.append(H) - except (OverflowError, ValueError, TypeError): - H = Inequality_generic(A, b, Hrep_obj.index()) - self.ineqs_generic.append(H) - - cpdef prepare_next_to_inner_loop(self, p): - r""" - Peel off the next-to-inner loop. - - In the next-to-inner loop of :func:`rectangular_box_points`, - we have to repeatedly evaluate `A x-A_0 x_0+b`. To speed up - computation, we pre-evaluate - - .. MATH:: - - c = b + \sum_{i=2} A_i x_i - - and only compute `A x-A_0 x_0+b = A_1 x_1 +c \geq 0` in the - next-to-inner loop. - - INPUT: - - - ``p`` -- the point coordinates. Only ``p[2:]`` coordinates - are potentially used by this method. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import InequalityCollection, print_cache - sage: P = Polyhedron(ieqs=[(2,3,7,11)]) - sage: ieq = InequalityCollection(P, [0,1,2], [0]*3,[1]*3); ieq - The collection of inequalities - integer: (3, 7, 11) x + 2 >= 0 - sage: ieq.prepare_next_to_inner_loop([2,1,3]) - sage: ieq.prepare_inner_loop([2,1,3]) - sage: print_cache(ieq) - Cached inner loop: 3 * x_0 + 42 >= 0 - Cached next-to-inner loop: 3 * x_0 + 7 * x_1 + 35 >= 0 - """ - for ineq in self.ineqs_int: - (<Inequality_int>ineq).prepare_next_to_inner_loop(p) - for ineq in self.ineqs_generic: - (<Inequality_generic>ineq).prepare_next_to_inner_loop(p) - - cpdef prepare_inner_loop(self, p): - r""" - Peel off the inner loop. - - In the inner loop of :func:`rectangular_box_points`, we have - to repeatedly evaluate `A x+b\geq 0`. To speed up computation, we pre-evaluate - - .. MATH:: - - c = A x - A_0 x_0 +b = b + \sum_{i=1} A_i x_i - - and only test `A_0 x_0 +c \geq 0` in the inner loop. - - You must call :meth:`prepare_next_to_inner_loop` before - calling this method. - - INPUT: - - - ``p`` -- the coordinates of the point to loop over. Only the - ``p[1:]`` entries are used. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import InequalityCollection, print_cache - sage: P = Polyhedron(ieqs=[(2,3,7,11)]) - sage: ieq = InequalityCollection(P, [0,1,2], [0]*3,[1]*3); ieq - The collection of inequalities - integer: (3, 7, 11) x + 2 >= 0 - sage: ieq.prepare_next_to_inner_loop([2,1,3]) - sage: ieq.prepare_inner_loop([2,1,3]) - sage: print_cache(ieq) - Cached inner loop: 3 * x_0 + 42 >= 0 - Cached next-to-inner loop: 3 * x_0 + 7 * x_1 + 35 >= 0 - """ - for ineq in self.ineqs_int: - (<Inequality_int>ineq).prepare_inner_loop(p) - for ineq in self.ineqs_generic: - (<Inequality_generic>ineq).prepare_inner_loop(p) - - cpdef swap_ineq_to_front(self, int i): - r""" - Swap the ``i``-th entry of the list to the front of the list of inequalities. - - INPUT: - - - ``i`` -- Integer. The :class:`Inequality_int` to swap to the - beginning of the list of integral inequalities. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import InequalityCollection - sage: P_QQ = Polyhedron(identity_matrix(3).columns() + [(-2, -1,-1)], base_ring=QQ) - sage: iec = InequalityCollection(P_QQ, [0,1,2], [0]*3,[1]*3) - sage: iec - The collection of inequalities - integer: (3, -2, -2) x + 2 >= 0 - integer: (-1, 4, -1) x + 1 >= 0 - integer: (-1, -1, 4) x + 1 >= 0 - integer: (-1, -1, -1) x + 1 >= 0 - sage: iec.swap_ineq_to_front(3) - sage: iec - The collection of inequalities - integer: (-1, -1, -1) x + 1 >= 0 - integer: (3, -2, -2) x + 2 >= 0 - integer: (-1, 4, -1) x + 1 >= 0 - integer: (-1, -1, 4) x + 1 >= 0 - """ - i_th_entry = self.ineqs_int[i] - cdef int j - for j in range(i-1,-1,-1): - self.ineqs_int[j+1] = self.ineqs_int[j] - self.ineqs_int[0] = i_th_entry - - cpdef bint are_satisfied(self, inner_loop_variable) except -1: - r""" - Return whether all inequalities are satisfied. - - You must call :meth:`prepare_inner_loop` before calling this - method. - - INPUT: - - - ``inner_loop_variable`` -- Integer. the 0-th coordinate of - the lattice point. - - OUTPUT: - - Boolean. Whether the lattice point is in the polyhedron. - - EXAMPLES:: - - sage: from sage.geometry.integral_points import InequalityCollection - sage: line = Polyhedron(eqns=[(2,3,7)]) - sage: ieq = InequalityCollection(line, [0,1], [0]*2, [1]*2 ) - sage: ieq.prepare_next_to_inner_loop([3,4]) - sage: ieq.prepare_inner_loop([3,4]) - sage: ieq.are_satisfied(3) - False - """ - cdef int i - for i in range(len(self.ineqs_int)): - sig_check() - ineq = self.ineqs_int[i] - if (<Inequality_int>ineq).is_not_satisfied(inner_loop_variable): - if i > 0: - self.swap_ineq_to_front(i) - return False - for i in range(len(self.ineqs_generic)): - sig_check() - ineq = self.ineqs_generic[i] - if (<Inequality_generic>ineq).is_not_satisfied(inner_loop_variable): - return False - return True - - cpdef frozenset satisfied_as_equalities(self, inner_loop_variable): - """ - Return the inequalities (by their index) that are satisfied as - equalities. - - INPUT: - - - ``inner_loop_variable`` -- Integer. the 0-th coordinate of - the lattice point. - - OUTPUT: - - A set of integers in ascending order. Each integer is the - index of a H-representation object of the polyhedron (either a - inequality or an equation). - - EXAMPLES:: - - sage: from sage.geometry.integral_points import InequalityCollection - sage: quadrant = Polyhedron(rays=[(1,0), (0,1)]) - sage: ieqs = InequalityCollection(quadrant, [0,1], [-1]*2, [1]*2 ) - sage: ieqs.prepare_next_to_inner_loop([-1,0]) - sage: ieqs.prepare_inner_loop([-1,0]) - sage: ieqs.satisfied_as_equalities(-1) - frozenset({1}) - sage: ieqs.satisfied_as_equalities(0) - frozenset({0, 1}) - sage: ieqs.satisfied_as_equalities(1) - frozenset({1}) - """ - cdef int i - cdef list result = [] - for i in range(len(self.ineqs_int)): - sig_check() - ineq = self.ineqs_int[i] - if (<Inequality_int>ineq).is_equality(inner_loop_variable): - result.append( (<Inequality_int>ineq).index ) - for i in range(len(self.ineqs_generic)): - sig_check() - ineq = self.ineqs_generic[i] - if (<Inequality_generic>ineq).is_equality(inner_loop_variable): - result.append( (<Inequality_generic>ineq).index ) - return frozenset(result) - - - -cpdef print_cache(InequalityCollection inequality_collection): - r""" - Print the cached values in :class:`Inequality_int` (for - debugging/doctesting only). - - EXAMPLES:: - - sage: from sage.geometry.integral_points import InequalityCollection, print_cache - sage: P = Polyhedron(ieqs=[(2,3,7)]) - sage: ieq = InequalityCollection(P, [0,1], [0]*2,[1]*2); ieq - The collection of inequalities - integer: (3, 7) x + 2 >= 0 - sage: ieq.prepare_next_to_inner_loop([3,5]) - sage: ieq.prepare_inner_loop([3,5]) - sage: print_cache(ieq) - Cached inner loop: 3 * x_0 + 37 >= 0 - Cached next-to-inner loop: 3 * x_0 + 7 * x_1 + 2 >= 0 - """ - cdef Inequality_int ieq = <Inequality_int>(inequality_collection.ineqs_int[0]) - print('Cached inner loop: ' + - str(ieq.coeff) + ' * x_0 + ' + str(ieq.cache) + ' >= 0') - print('Cached next-to-inner loop: ' + - str(ieq.coeff) + ' * x_0 + ' + - str(ieq.coeff_next) + ' * x_1 + ' + str(ieq.cache_next) + ' >= 0') diff --git a/src/sage/geometry/integral_points_generic_dense.pyx b/src/sage/geometry/integral_points_generic_dense.pyx new file mode 100644 index 00000000000..5ff619f44d4 --- /dev/null +++ b/src/sage/geometry/integral_points_generic_dense.pyx @@ -0,0 +1,6 @@ +#cython: wraparound=False, boundscheck=False + +from sage.modules.vector_integer_dense cimport Vector_integer_dense as VectorClass +from sage.matrix.matrix_dense cimport Matrix_dense as MatrixClass + +include "integral_points.pxi" diff --git a/src/sage/geometry/integral_points_integer_dense.pyx b/src/sage/geometry/integral_points_integer_dense.pyx new file mode 100644 index 00000000000..0151ffed5c0 --- /dev/null +++ b/src/sage/geometry/integral_points_integer_dense.pyx @@ -0,0 +1,6 @@ +#cython: wraparound=False, boundscheck=False + +from sage.modules.vector_integer_dense cimport Vector_integer_dense as VectorClass +from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense as MatrixClass + +include "integral_points.pxi" diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 939564dd73f..26c7d9a3819 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -119,9 +119,9 @@ from sage.features import PythonModule from sage.features.palp import PalpExecutable lazy_import('ppl', ['C_Polyhedron', 'Generator_System', 'Linear_Expression'], - feature=PythonModule("ppl", spkg="pplpy")) + feature=PythonModule("ppl", spkg="pplpy", type="standard")) lazy_import('ppl', 'point', as_='PPL_point', - feature=PythonModule("ppl", spkg="pplpy")) + feature=PythonModule("ppl", spkg="pplpy", type="standard")) from sage.matrix.constructor import matrix from sage.structure.element import is_Matrix @@ -239,7 +239,7 @@ def LatticePolytope(data, compute_vertices=True, n=0, lattice=None): We draw a pretty picture of the polytope in 3-dimensional space:: - sage: p.plot3d().show() # optional - palp sage.plot + sage: p.plot3d().show() # needs palp sage.plot Now we add an extra point, which is in the interior of the polytope... @@ -295,7 +295,7 @@ def LatticePolytope(data, compute_vertices=True, n=0, lattice=None): sage: p.points() Empty collection in 3-d lattice M - sage: p.faces() + sage: p.faces() # needs sage.graphs ((-1-d lattice polytope in 3-d lattice M,),) """ if isinstance(data, LatticePolytopeClass): @@ -398,6 +398,7 @@ def ReflexivePolytope(dim, n): else: raise NotImplementedError("only 2- and 3-dimensional reflexive polytopes are available!") + # Sequences of reflexive polytopes _rp = [None] * 4 @@ -464,7 +465,7 @@ def is_LatticePolytope(x): sage: is_LatticePolytope(1) False sage: p = LatticePolytope([(1,0), (0,1), (-1,-1)]) - sage: p # optional - palp + sage: p # needs palp 2-d reflexive polytope #0 in 2-d lattice M sage: is_LatticePolytope(p) True @@ -763,6 +764,7 @@ def _compute_facets(self): Check that :trac:`28741` is fixed:: + sage: # needs sage.graphs sage: p = LatticePolytope([], lattice=ToricLattice(3).dual()); p -1-d lattice polytope in 3-d lattice M sage: a = p.faces()[0][0] @@ -966,9 +968,9 @@ def _palp(self, command, reduce_dimension=False): TESTS:: sage: o = lattice_polytope.cross_polytope(3) - sage: o._palp("poly.x -f") # optional - palp + sage: o._palp("poly.x -f") # needs palp 'M:7 6 N:27 8 Pic:17 Cor:0\n' - sage: print(o._palp("nef.x -f -N -p")) # random time information # optional - palp + sage: print(o._palp("nef.x -f -N -p")) # random time information # needs palp M:27 8 N:7 6 codim=2 #part=5 H:[0] P:0 V:2 4 5 0sec 0cpu H:[0] P:2 V:3 4 5 0sec 0cpu @@ -976,18 +978,18 @@ def _palp(self, command, reduce_dimension=False): np=3 d:1 p:1 0sec 0cpu sage: p = LatticePolytope([[1]]) - sage: p._palp("poly.x -f") # optional - palp + sage: p._palp("poly.x -f") # needs palp Traceback (most recent call last): ... ValueError: Cannot run "poly.x -f" for the zero-dimensional polytope! Polytope: 0-d lattice polytope in 1-d lattice M sage: p = LatticePolytope([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)]) - sage: p._palp("poly.x -f") # optional - palp + sage: p._palp("poly.x -f") # needs palp Traceback (most recent call last): ... ValueError: Cannot run PALP for a 2-dimensional polytope in a 3-dimensional space! - sage: p._palp("poly.x -f", reduce_dimension=True) # optional - palp + sage: p._palp("poly.x -f", reduce_dimension=True) # needs palp 'M:5 4 F:4\n' """ if self.dim() <= 0: @@ -1098,22 +1100,23 @@ def _read_equations(self, data): For a reflexive polytope construct the polar polytope:: + sage: # needs palp sage: p = LatticePolytope([(1,0), (0,1), (-1,-1)]) sage: p.vertices() M( 1, 0), M( 0, 1), M(-1, -1) in 2-d lattice M - sage: s = p.poly_x("e") # optional - palp - sage: print(s) # optional - palp + sage: s = p.poly_x("e") + sage: print(s) 3 2 Vertices of P-dual <-> Equations of P 2 -1 -1 2 -1 -1 - sage: "_polar" in p.__dict__ # optional - palp + sage: "_polar" in p.__dict__ False - sage: p._read_equations(s) # optional - palp - sage: p._polar._vertices # optional - palp + sage: p._read_equations(s) + sage: p._polar._vertices N( 2, -1), N(-1, 2), N(-1, -1) @@ -1121,6 +1124,7 @@ def _read_equations(self, data): For a non-reflexive polytope cache facet equations:: + sage: # needs palp sage: p = LatticePolytope([(1,0), (0,2), (-1,-3 )]) sage: p.vertices() M( 1, 0), @@ -1131,19 +1135,19 @@ def _read_equations(self, data): False sage: "_facet_constants" in p.__dict__ False - sage: s = p.poly_x("e") # optional - palp - sage: print(s) # optional - palp + sage: s = p.poly_x("e") + sage: print(s) 3 2 Equations of P 5 -1 2 -2 -1 2 -3 2 3 - sage: p._read_equations(s) # optional - palp - sage: p._facet_normals # optional - palp + sage: p._read_equations(s) + sage: p._facet_normals N( 5, -1), N(-2, -1), N(-3, 2) in 2-d lattice N - sage: p._facet_constants # optional - palp + sage: p._facet_constants (2, 2, 3) """ if isinstance(data, str): @@ -1210,8 +1214,8 @@ def _read_nef_partitions(self, data): TESTS:: sage: o = lattice_polytope.cross_polytope(3) - sage: s = o.nef_x("-p -N -Lv") # optional - palp - sage: print(s) # random time values # optional - palp + sage: s = o.nef_x("-p -N -Lv") # needs palp + sage: print(s) # random time values # needs palp M:27 8 N:7 6 codim=2 #part=5 3 6 Vertices in N-lattice: 1 0 0 -1 0 0 @@ -1232,8 +1236,8 @@ def _read_nef_partitions(self, data): sage: o_copy = LatticePolytope(o.vertices()) sage: "_nef_partitions" in o_copy.__dict__ False - sage: o_copy._read_nef_partitions(s) # optional - palp - sage: o_copy._nef_partitions # optional - palp + sage: o_copy._read_nef_partitions(s) # needs palp + sage: o_copy._nef_partitions # needs palp [ Nef-partition {0, 1, 3} โŠ” {2, 4, 5}, Nef-partition {0, 1, 2} โŠ” {3, 4, 5}, @@ -1335,7 +1339,7 @@ def _sort_faces(self, faces): sage: o = lattice_polytope.cross_polytope(3) sage: # indirect doctest - sage: for i, face in enumerate(o.faces(0)): + sage: for i, face in enumerate(o.faces(0)): # needs sage.graphs ....: if face.vertex(0) != o.vertex(i): ....: print("Wrong order!") """ @@ -1380,10 +1384,10 @@ def adjacent(self): EXAMPLES:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.adjacent() + sage: o.adjacent() # needs sage.graphs () - sage: face = o.faces(1)[0] - sage: face.adjacent() + sage: face = o.faces(1)[0] # needs sage.graphs + sage: face.adjacent() # needs sage.graphs (1-d face of 3-d reflexive polytope in 3-d lattice M, 1-d face of 3-d reflexive polytope in 3-d lattice M, 1-d face of 3-d reflexive polytope in 3-d lattice M, @@ -1505,6 +1509,8 @@ def ambient(self): 3-d reflexive polytope in 3-d lattice M sage: o.ambient() is o True + + sage: # needs sage.graphs sage: face = o.faces(1)[0] sage: face 1-d face of 3-d reflexive polytope in 3-d lattice M @@ -1533,6 +1539,7 @@ def ambient_facet_indices(self): But each of its other faces is contained in one or more facets:: + sage: # needs sage.graphs sage: face = o.faces(1)[0] sage: face.ambient_facet_indices() (4, 5) @@ -1561,10 +1568,10 @@ def ambient_point_indices(self): EXAMPLES:: sage: cube = lattice_polytope.cross_polytope(3).polar() - sage: face = cube.facets()[0] - sage: face.ambient_point_indices() # optional - palp + sage: face = cube.facets()[0] # needs sage.graphs + sage: face.ambient_point_indices() # needs palp sage.graphs (4, 5, 6, 7, 8, 9, 10, 11, 12) - sage: cube.points(face.ambient_point_indices()) == face.points() # optional - palp + sage: cube.points(face.ambient_point_indices()) == face.points() # needs palp sage.graphs True """ if self._ambient is self: @@ -1587,10 +1594,10 @@ def ambient_ordered_point_indices(self): EXAMPLES:: sage: cube = lattice_polytope.cross_polytope(3).polar() - sage: face = cube.facets()[0] - sage: face.ambient_ordered_point_indices() # optional - palp + sage: face = cube.facets()[0] # needs sage.graphs + sage: face.ambient_ordered_point_indices() # needs palp sage.graphs (5, 8, 4, 9, 10, 11, 6, 12, 7) - sage: cube.points(face.ambient_ordered_point_indices()) # optional - palp + sage: cube.points(face.ambient_ordered_point_indices()) # needs palp sage.graphs N(-1, -1, -1), N(-1, -1, 0), N(-1, -1, 1), @@ -1621,8 +1628,8 @@ def ambient_vertex_indices(self): sage: o = lattice_polytope.cross_polytope(3) sage: o.ambient_vertex_indices() (0, 1, 2, 3, 4, 5) - sage: face = o.faces(1)[0] - sage: face.ambient_vertex_indices() + sage: face = o.faces(1)[0] # needs sage.graphs + sage: face.ambient_vertex_indices() # needs sage.graphs (0, 1) """ return self._ambient_vertex_indices @@ -1641,7 +1648,7 @@ def boundary_point_indices(self): All points but the origin are on the boundary of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() - sage: square.points() # optional - palp + sage: square.points() # needs palp N( 1, 1), N( 1, -1), N(-1, -1), @@ -1652,18 +1659,18 @@ def boundary_point_indices(self): N( 0, 1), N( 1, 0) in 2-d lattice N - sage: square.boundary_point_indices() # optional - palp + sage: square.boundary_point_indices() # needs palp (0, 1, 2, 3, 4, 5, 7, 8) For an edge the boundary is formed by the end points:: - sage: face = square.edges()[0] - sage: face.points() + sage: face = square.edges()[0] # needs sage.graphs + sage: face.points() # needs sage.graphs N(-1, -1), N(-1, 1), N(-1, 0) in 2-d lattice N - sage: face.boundary_point_indices() + sage: face.boundary_point_indices() # needs sage.graphs (0, 1) """ return tuple(i @@ -1683,7 +1690,7 @@ def boundary_points(self): All points but the origin are on the boundary of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() - sage: square.boundary_points() # optional - palp + sage: square.boundary_points() # needs palp N( 1, 1), N( 1, -1), N(-1, -1), @@ -1696,8 +1703,8 @@ def boundary_points(self): For an edge the boundary is formed by the end points:: - sage: face = square.edges()[0] - sage: face.boundary_points() + sage: face = square.edges()[0] # needs sage.graphs + sage: face.boundary_points() # needs sage.graphs N(-1, -1), N(-1, 1) in 2-d lattice N @@ -1775,7 +1782,7 @@ def distances(self, point=None): EXAMPLES: The matrix of distances for a 3-dimensional octahedron:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.distances() # optional - palp + sage: o.distances() # needs palp [2 0 0 0 2 2 1] [2 2 0 0 0 2 1] [2 2 2 0 0 0 1] @@ -1794,7 +1801,7 @@ def distances(self, point=None): sage: o.distances([1,2,3/2]) (-3/2, 5/2, 11/2, 3/2, -1/2, -7/2, 1/2, 7/2) - sage: o.distances([1,2,sqrt(2)]) + sage: o.distances([1,2,sqrt(2)]) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert sqrt(2) to an element of Rational Field @@ -1802,17 +1809,17 @@ def distances(self, point=None): Now we create a non-spanning polytope:: sage: p = LatticePolytope([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)]) - sage: p.distances() # optional - palp + sage: p.distances() # needs palp [2 2 0 0 1] [2 0 0 2 1] [0 0 2 2 1] [0 2 2 0 1] - sage: p.distances((1/2, 3, 0)) # optional - palp + sage: p.distances((1/2, 3, 0)) # needs palp (9/2, -3/2, -5/2, 7/2) This point is not even in the affine subspace of the polytope:: - sage: p.distances((1, 1, 1)) # optional - palp + sage: p.distances((1, 1, 1)) # needs palp (3, 1, -1, 1) """ if point is not None: @@ -1841,6 +1848,7 @@ def dual(self): EXAMPLES:: + sage: # needs sage.graphs sage: o = lattice_polytope.cross_polytope(4) sage: e = o.edges()[0]; e 1-d face of 4-d reflexive polytope in 4-d lattice M @@ -1893,11 +1901,11 @@ def edges(self): EXAMPLES:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.edges() + sage: o.edges() # needs sage.graphs (1-d face of 3-d reflexive polytope in 3-d lattice M, ... 1-d face of 3-d reflexive polytope in 3-d lattice M) - sage: len(o.edges()) + sage: len(o.edges()) # needs sage.graphs 12 """ return self.faces(dim=1) @@ -1920,13 +1928,12 @@ def face_lattice(self): Let's take a look at the face lattice of a square:: sage: square = LatticePolytope([(0,0), (1,0), (1,1), (0,1)]) - sage: L = square.face_lattice() - sage: L + sage: L = square.face_lattice(); L # needs sage.graphs Finite lattice containing 10 elements with distinguished linear extension To see all faces arranged by dimension, you can do this:: - sage: for level in L.level_sets(): print(level) + sage: for level in L.level_sets(): print(level) # needs sage.graphs [-1-d face of 2-d lattice polytope in 2-d lattice M] [0-d face of 2-d lattice polytope in 2-d lattice M, 0-d face of 2-d lattice polytope in 2-d lattice M, @@ -1940,15 +1947,15 @@ def face_lattice(self): For a particular face you can look at its actual vertices... :: - sage: face = L.level_sets()[1][0] - sage: face.vertices() + sage: face = L.level_sets()[1][0] # needs sage.graphs + sage: face.vertices() # needs sage.graphs M(0, 0) in 2-d lattice M ... or you can see the index of the vertex of the original polytope that corresponds to the above one:: - sage: face.ambient_vertex_indices() + sage: face.ambient_vertex_indices() # needs sage.graphs (0,) sage: square.vertex(0) M(0, 0) @@ -1956,15 +1963,15 @@ def face_lattice(self): An alternative to extracting faces from the face lattice is to use :meth:`faces` method:: - sage: face is square.faces(dim=0)[0] + sage: face is square.faces(dim=0)[0] # needs sage.graphs True The advantage of working with the face lattice directly is that you can (relatively easily) get faces that are related to the given one:: - sage: face = L.level_sets()[1][0] - sage: D = L.hasse_diagram() - sage: sorted(D.neighbors(face)) + sage: face = L.level_sets()[1][0] # needs sage.graphs + sage: D = L.hasse_diagram() # needs sage.graphs + sage: sorted(D.neighbors(face)) # needs sage.graphs [-1-d face of 2-d lattice polytope in 2-d lattice M, 1-d face of 2-d lattice polytope in 2-d lattice M, 1-d face of 2-d lattice polytope in 2-d lattice M] @@ -1972,6 +1979,7 @@ def face_lattice(self): However, you can achieve some of this functionality using :meth:`facets`, :meth:`facet_of`, and :meth:`adjacent` methods:: + sage: # needs sage.graphs sage: face = square.faces(0)[0] sage: face 0-d face of 2-d lattice polytope in 2-d lattice M @@ -1993,6 +2001,7 @@ def face_lattice(self): Note that if ``p`` is a face of ``superp``, then the face lattice of ``p`` consists of (appropriate) faces of ``superp``:: + sage: # needs sage.graphs sage: superp = LatticePolytope([(1,2,3,4), (5,6,7,8), ....: (1,2,4,8), (1,3,9,7)]) sage: superp.face_lattice() @@ -2098,7 +2107,7 @@ def faces(self, dim=None, codim=None): Let's take a look at the faces of a square:: sage: square = LatticePolytope([(0,0), (1,0), (1,1), (0,1)]) - sage: square.faces() + sage: square.faces() # needs sage.graphs ((-1-d face of 2-d lattice polytope in 2-d lattice M,), (0-d face of 2-d lattice polytope in 2-d lattice M, 0-d face of 2-d lattice polytope in 2-d lattice M, @@ -2112,7 +2121,7 @@ def faces(self, dim=None, codim=None): Its faces of dimension one (i.e., edges):: - sage: square.faces(dim=1) + sage: square.faces(dim=1) # needs sage.graphs (1-d face of 2-d lattice polytope in 2-d lattice M, 1-d face of 2-d lattice polytope in 2-d lattice M, 1-d face of 2-d lattice polytope in 2-d lattice M, @@ -2120,16 +2129,16 @@ def faces(self, dim=None, codim=None): Its faces of codimension one are the same (also edges):: - sage: square.faces(codim=1) is square.faces(dim=1) + sage: square.faces(codim=1) is square.faces(dim=1) # needs sage.graphs True Let's pick a particular face:: - sage: face = square.faces(dim=1)[0] + sage: face = square.faces(dim=1)[0] # needs sage.graphs Now you can look at the actual vertices of this face... :: - sage: face.vertices() + sage: face.vertices() # needs sage.graphs M(0, 0), M(0, 1) in 2-d lattice M @@ -2137,9 +2146,9 @@ def faces(self, dim=None, codim=None): ... or you can see indices of the vertices of the original polytope that correspond to the above ones:: - sage: face.ambient_vertex_indices() + sage: face.ambient_vertex_indices() # needs sage.graphs (0, 3) - sage: square.vertices(face.ambient_vertex_indices()) + sage: square.vertices(face.ambient_vertex_indices()) # needs sage.graphs M(0, 0), M(0, 1) in 2-d lattice M @@ -2364,6 +2373,7 @@ def facet_of(self): EXAMPLES:: + sage: # needs sage.graphs sage: square = LatticePolytope([(0,0), (1,0), (1,1), (0,1)]) sage: square.facet_of() () @@ -2388,11 +2398,11 @@ def facets(self): EXAMPLES:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.facets() + sage: o.facets() # needs sage.graphs (2-d face of 3-d reflexive polytope in 3-d lattice M, ... 2-d face of 3-d reflexive polytope in 3-d lattice M) - sage: len(o.facets()) + sage: len(o.facets()) # needs sage.graphs 8 """ return self.faces(codim=1) @@ -2420,14 +2430,14 @@ def incidence_matrix(self): [0 1 1 0] [1 1 0 0] [1 0 0 1] - sage: o.faces(1)[0].incidence_matrix() + sage: o.faces(1)[0].incidence_matrix() # needs sage.graphs [1 0] [0 1] sage: o = lattice_polytope.cross_polytope(4) sage: o.incidence_matrix().column(3).nonzero_positions() [3, 4, 5, 6] - sage: o.facets()[3].ambient_vertex_indices() + sage: o.facets()[3].ambient_vertex_indices() # needs sage.graphs (3, 4, 5, 6) TESTS:: @@ -2471,7 +2481,7 @@ def index(self): database:: sage: d = lattice_polytope.cross_polytope(2) - sage: d.index() # optional - palp + sage: d.index() # needs palp 3 Note that polytopes with the same index are not necessarily the @@ -2493,7 +2503,7 @@ def index(self): But they are in the same `GL(Z^n)` orbit and have the same normal form:: - sage: d.normal_form() # optional - palp + sage: d.normal_form() # needs palp M( 1, 0), M( 0, 1), M( 0, -1), @@ -2532,7 +2542,7 @@ def interior_point_indices(self): The origin is the only interior point of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() - sage: square.points() # optional - palp + sage: square.points() # needs palp N( 1, 1), N( 1, -1), N(-1, -1), @@ -2543,18 +2553,18 @@ def interior_point_indices(self): N( 0, 1), N( 1, 0) in 2-d lattice N - sage: square.interior_point_indices() # optional - palp + sage: square.interior_point_indices() # needs palp (6,) Its edges also have a single interior point each:: - sage: face = square.edges()[0] - sage: face.points() + sage: face = square.edges()[0] # needs sage.graphs + sage: face.points() # needs sage.graphs N(-1, -1), N(-1, 1), N(-1, 0) in 2-d lattice N - sage: face.interior_point_indices() + sage: face.interior_point_indices() # needs sage.graphs (2,) """ return tuple(i @@ -2574,14 +2584,14 @@ def interior_points(self): The origin is the only interior point of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() - sage: square.interior_points() # optional - palp + sage: square.interior_points() # needs palp N(0, 0) in 2-d lattice N Its edges also have a single interior point each:: - sage: face = square.edges()[0] - sage: face.interior_points() + sage: face = square.edges()[0] # needs sage.graphs + sage: face.interior_points() # needs sage.graphs N(-1, 0) in 2-d lattice N """ @@ -2667,7 +2677,7 @@ def ambient_vector_space(self, base_field=None): sage: p = LatticePolytope([(1,0)]) sage: p.ambient_vector_space() Vector space of dimension 2 over Rational Field - sage: p.ambient_vector_space(AA) + sage: p.ambient_vector_space(AA) # needs sage.rings.number_field Vector space of dimension 2 over Algebraic Real Field """ return self.lattice().vector_space(base_field=base_field) @@ -2728,7 +2738,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, Nef-partitions of the 4-dimensional cross-polytope:: sage: p = lattice_polytope.cross_polytope(4) - sage: p.nef_partitions() # optional - palp + sage: p.nef_partitions() # needs palp [ Nef-partition {0, 1, 4, 5} โŠ” {2, 3, 6, 7} (direct product), Nef-partition {0, 1, 2, 4} โŠ” {3, 5, 6, 7}, @@ -2742,7 +2752,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, Now we omit projections:: - sage: p.nef_partitions(keep_projections=False) # optional - palp + sage: p.nef_partitions(keep_projections=False) # needs palp [ Nef-partition {0, 1, 4, 5} โŠ” {2, 3, 6, 7} (direct product), Nef-partition {0, 1, 2, 4} โŠ” {3, 5, 6, 7}, @@ -2755,7 +2765,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, Currently Hodge numbers cannot be computed for a given nef-partition:: - sage: p.nef_partitions()[1].hodge_numbers() # optional - palp + sage: p.nef_partitions()[1].hodge_numbers() # needs palp Traceback (most recent call last): ... NotImplementedError: use nef_partitions(hodge_numbers=True)! @@ -2763,7 +2773,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, But they can be obtained from ``nef.x`` for all nef-partitions at once. Partitions will be exactly the same:: - sage: p.nef_partitions(hodge_numbers=True) # long time (2s on sage.math, 2011) # optional - palp + sage: p.nef_partitions(hodge_numbers=True) # long time (2s on sage.math, 2011), needs palp [ Nef-partition {0, 1, 4, 5} โŠ” {2, 3, 6, 7} (direct product), Nef-partition {0, 1, 2, 4} โŠ” {3, 5, 6, 7}, @@ -2777,26 +2787,26 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, Now it is possible to get Hodge numbers:: - sage: p.nef_partitions(hodge_numbers=True)[1].hodge_numbers() # optional - palp + sage: p.nef_partitions(hodge_numbers=True)[1].hodge_numbers() # needs palp (20,) Since nef-partitions are cached, their Hodge numbers are accessible after the first request, even if you do not specify ``hodge_numbers=True`` anymore:: - sage: p.nef_partitions()[1].hodge_numbers() # optional - palp + sage: p.nef_partitions()[1].hodge_numbers() # needs palp (20,) We illustrate removal of symmetric partitions on a diamond:: sage: p = lattice_polytope.cross_polytope(2) - sage: p.nef_partitions() # optional - palp + sage: p.nef_partitions() # needs palp [ Nef-partition {0, 2} โŠ” {1, 3} (direct product), Nef-partition {0, 1} โŠ” {2, 3}, Nef-partition {0, 1, 2} โŠ” {3} (projection) ] - sage: p.nef_partitions(keep_symmetric=True) # optional - palp + sage: p.nef_partitions(keep_symmetric=True) # needs palp [ Nef-partition {0, 1, 3} โŠ” {2} (projection), Nef-partition {0, 2, 3} โŠ” {1} (projection), @@ -2811,7 +2821,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, sage: p = LatticePolytope([(1,0,0), (0,1,0), (0,0,2), ....: (-1,0,0), (0,-1,0), (0,0,-1)]) - sage: p.nef_partitions() # optional - palp + sage: p.nef_partitions() # needs palp Traceback (most recent call last): ... ValueError: The given polytope is not reflexive! @@ -2865,8 +2875,8 @@ def nef_x(self, keys): nef-partitions:: sage: o = lattice_polytope.cross_polytope(3) - sage: s = o.nef_x("-N -V -p") # optional - palp - sage: s # output contains random time # optional - palp + sage: s = o.nef_x("-N -V -p") # needs palp + sage: s # output contains random time # needs palp M:27 8 N:7 6 codim=2 #part=5 3 6 Vertices of P: 1 0 0 -1 0 0 @@ -2953,7 +2963,7 @@ def normal_form(self, algorithm="palp", permutation=False): M(-1, 0), M( 0, -1) in 2-d lattice M - sage: d.normal_form() # optional - palp + sage: d.normal_form() # needs palp M( 1, 0), M( 0, 1), M( 0, -1), @@ -2962,9 +2972,9 @@ def normal_form(self, algorithm="palp", permutation=False): The diamond is the 3rd polytope in the internal database:: - sage: d.index() # optional - palp + sage: d.index() # needs palp 3 - sage: d # optional - palp + sage: d # needs palp 2-d reflexive polytope #3 in 2-d lattice M You can get it in its normal form (in the default lattice) as :: @@ -2989,7 +2999,7 @@ def normal_form(self, algorithm="palp", permutation=False): We can perform the same examples using other algorithms:: sage: o = lattice_polytope.cross_polytope(2) - sage: o.normal_form(algorithm="palp_native") + sage: o.normal_form(algorithm="palp_native") # needs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), @@ -2997,7 +3007,7 @@ def normal_form(self, algorithm="palp", permutation=False): in 2-d lattice M sage: o = lattice_polytope.cross_polytope(2) - sage: o.normal_form(algorithm="palp_modified") + sage: o.normal_form(algorithm="palp_modified") # needs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), @@ -3055,13 +3065,13 @@ def _palp_modified_normal_form(self, permutation=False): M(-1, 0), M( 0, -1) in 2-d lattice M - sage: o._palp_modified_normal_form() + sage: o._palp_modified_normal_form() # needs sage.graphs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), M(-1, 0) in 2-d lattice M - sage: o._palp_modified_normal_form(permutation=True) + sage: o._palp_modified_normal_form(permutation=True) # needs sage.graphs sage.groups (M( 1, 0), M( 0, 1), M( 0, -1), @@ -3108,13 +3118,13 @@ def _palp_native_normal_form(self, permutation=False): M(-1, 0), M( 0, -1) in 2-d lattice M - sage: o._palp_native_normal_form() + sage: o._palp_native_normal_form() # needs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), M(-1, 0) in 2-d lattice M - sage: o._palp_native_normal_form(permutation=True) + sage: o._palp_native_normal_form(permutation=True) # needs sage.groups (M( 1, 0), M( 0, 1), M( 0, -1), @@ -3159,40 +3169,36 @@ def _palp_PM_max(self, check=False): sage: o = lattice_polytope.cross_polytope(2) sage: PM = o.vertex_facet_pairing_matrix() - sage: PM_max = PM.permutation_normal_form() - sage: PM_max == o._palp_PM_max() + sage: PM_max = PM.permutation_normal_form() # needs sage.graphs + sage: PM_max == o._palp_PM_max() # needs sage.graphs sage.groups True sage: P2 = ReflexivePolytope(2, 0) - sage: PM_max, permutations = P2._palp_PM_max(check=True) - sage: PM_max + sage: PM_max, permutations = P2._palp_PM_max(check=True) # needs sage.groups + sage: PM_max # needs sage.graphs [3 0 0] [0 3 0] [0 0 3] - sage: list(permutations.values()) + sage: list(permutations.values()) # needs sage.groups [[(1,2,3), (1,2,3)], [(1,3,2), (1,3,2)], [(1,3), (1,3)], [(1,2), (1,2)], [(), ()], [(2,3), (2,3)]] - sage: PM_max.automorphisms_of_rows_and_columns() + sage: PM_max.automorphisms_of_rows_and_columns() # needs sage.graphs [((), ()), ((1,2,3), (1,2,3)), ((1,3,2), (1,3,2)), ((2,3), (2,3)), ((1,2), (1,2)), ((1,3), (1,3))] - sage: PMs = [i._palp_PM_max(check=True) - ....: for i in ReflexivePolytopes(2)] # long time - sage: all(len(i) == len(j.automorphisms_of_rows_and_columns()) - ....: for j, i in PMs) # long time + sage: PMs = ( i._palp_PM_max(check=True) + ....: for i in ReflexivePolytopes(2) ) + sage: results = ( len(i) == len(j.automorphisms_of_rows_and_columns()) + ....: for j, i in PMs ) + sage: all(results) # long time True """ - def PGE(S, u, v): - if u == v: - return S.one() - return S((u, v), check=False) - PM = self.vertex_facet_pairing_matrix() n_v = PM.ncols() n_f = PM.nrows() @@ -3202,30 +3208,24 @@ def PGE(S, u, v): # and find all the ways of making the first row of PM_max def index_of_max(iterable): # returns the index of max of any iterable - m, x = 0, iterable[0] - for k, l in enumerate(iterable): - if l > x: - m, x = k, l - return m + return max(enumerate(iterable), key=lambda x: x[1])[0] n_s = 1 - permutations = {0 : [S_f.one(), S_v.one()]} + permutations = {0: [S_f.one(), S_v.one()]} for j in range(n_v): - m = index_of_max( - [(PM.with_permuted_columns(permutations[0][1]))[0][i] - for i in range(j, n_v)]) + m = index_of_max(PM[0, i] for i in range(j, n_v)) if m > 0: - permutations[0][1] = PGE(S_v, j + 1, m + j + 1) * permutations[0][1] + permutations[0][1] = S_v((j + 1, m + j + 1), check=False) * permutations[0][1] first_row = list(PM[0]) # Arrange other rows one by one and compare with first row for k in range(1, n_f): # Error for k == 1 already! permutations[n_s] = [S_f.one(), S_v.one()] - m = index_of_max(PM.with_permuted_columns(permutations[n_s][1])[k]) + m = index_of_max(PM[k, permutations[n_s][1](j+1) - 1] for j in range(n_v)) if m > 0: - permutations[n_s][1] = PGE(S_v, 1, m+1) * permutations[n_s][1] - d = ((PM.with_permuted_columns(permutations[n_s][1]))[k][0] + permutations[n_s][1] = S_v((1, m + 1), check=False) * permutations[n_s][1] + d = (PM[k, permutations[n_s][1](1) - 1] - permutations[0][1](first_row)[0]) if d < 0: # The largest elt of this row is smaller than largest elt @@ -3233,14 +3233,12 @@ def index_of_max(iterable): continue # otherwise: for i in range(1, n_v): - m = index_of_max( - [PM.with_permuted_columns(permutations[n_s][1])[k][j] - for j in range(i, n_v)]) + m = index_of_max(PM[k, permutations[n_s][1](j+1) - 1] for j in range(i,n_v)) if m > 0: - permutations[n_s][1] = PGE(S_v, i + 1, m + i + 1) \ + permutations[n_s][1] = S_v((i + 1, m + i + 1), check=False) \ * permutations[n_s][1] if d == 0: - d = (PM.with_permuted_columns(permutations[n_s][1])[k][i] + d = (PM[k, permutations[n_s][1](i+1) - 1] -permutations[0][1](first_row)[i]) if d < 0: break @@ -3248,7 +3246,7 @@ def index_of_max(iterable): # This row is smaller than 1st row, so nothing to do del permutations[n_s] continue - permutations[n_s][0] = PGE(S_f, 1, k + 1) * permutations[n_s][0] + permutations[n_s][0] = S_f((1, k + 1), check=False) * permutations[n_s][0] if d == 0: # This row is the same, so we have a symmetry! n_s += 1 @@ -3258,9 +3256,9 @@ def index_of_max(iterable): first_row = list(PM[k]) permutations = {0: permutations[n_s]} n_s = 1 - permutations = {k:permutations[k] for k in permutations if k < n_s} + permutations = {k: permutations[k] for k in permutations if k < n_s} - b = PM.with_permuted_rows_and_columns(*permutations[0])[0] + b = tuple(PM[permutations[0][0](1) - 1, permutations[0][1](j+1) - 1] for j in range(n_v)) # Work out the restrictions the current permutations # place on other permutations as a automorphisms # of the first row @@ -3294,34 +3292,35 @@ def index_of_max(iterable): # between 0 and S(0) for s in range(l, n_f): for j in range(1, S[0]): - v = PM.with_permuted_rows_and_columns( - *permutations_bar[n_p])[s] - if v[0] < v[j]: - permutations_bar[n_p][1] = PGE(S_v, 1, j + 1) * permutations_bar[n_p][1] + v0 = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] + vj = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](j+1) - 1] + if v0 < vj: + permutations_bar[n_p][1] = S_v((1, j + 1), check=False) * permutations_bar[n_p][1] if ccf == 0: - l_r[0] = PM.with_permuted_rows_and_columns( - *permutations_bar[n_p])[s][0] - permutations_bar[n_p][0] = PGE(S_f, l + 1, s + 1) * permutations_bar[n_p][0] + l_r[0] = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] + if s != l: + permutations_bar[n_p][0] = S_f((l + 1, s + 1), check=False) * permutations_bar[n_p][0] n_p += 1 ccf = 1 permutations_bar[n_p] = copy(permutations[k]) else: - d1 = PM.with_permuted_rows_and_columns( - *permutations_bar[n_p])[s][0] + d1 = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] d = d1 - l_r[0] if d < 0: # We move to the next line continue elif d==0: # Maximal values agree, so possible symmetry - permutations_bar[n_p][0] = PGE(S_f, l + 1, s + 1) * permutations_bar[n_p][0] + if s != l: + permutations_bar[n_p][0] = S_f((l + 1, s + 1), check=False) * permutations_bar[n_p][0] n_p += 1 permutations_bar[n_p] = copy(permutations[k]) else: # We found a greater maximal value for first entry. # It becomes our new reference: l_r[0] = d1 - permutations_bar[n_p][0] = PGE(S_f, l + 1, s + 1) * permutations_bar[n_p][0] + if s != l: + permutations_bar[n_p][0] = S_f((l + 1, s + 1), check=False) * permutations_bar[n_p][0] # Forget previous work done cf = 0 permutations_bar = {0:copy(permutations_bar[n_p])} @@ -3335,26 +3334,24 @@ def index_of_max(iterable): ccf = cf # Now let us find out where the end of the # next symmetry block is: - if h < c+1: - h = S[h-1] + if h < c + 1: + h = S[h - 1] s = n_p # Check through this block for each possible permutation while s > 0: s -= 1 # Find the largest value in this symmetry block for j in range(c + 1, h): - v = PM.with_permuted_rows_and_columns( - *permutations_bar[s])[l] - if (v[c] < v[j]): - permutations_bar[s][1] = PGE(S_v, c + 1, j + 1) * permutations_bar[s][1] + vc = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] + vj = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(j+1) - 1] + if (vc < vj): + permutations_bar[s][1] = S_v((c + 1, j + 1), check=False) * permutations_bar[s][1] if ccf == 0: # Set reference and carry on to next permutation - l_r[c] = PM.with_permuted_rows_and_columns( - *permutations_bar[s])[l][c] + l_r[c] = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] ccf = 1 else: - d1 = PM.with_permuted_rows_and_columns( - *permutations_bar[s])[l][c] + d1 = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] d = d1 - l_r[c] if d < 0: n_p -= 1 @@ -3383,7 +3380,7 @@ def index_of_max(iterable): # the restrictions the last worked out # row imposes. c = 0 - M = (PM.with_permuted_rows_and_columns(*permutations[0]))[l] + M = tuple(PM[permutations[0][0](l+1) - 1, permutations[0][1](j+1) - 1] for j in range(n_v)) while c < n_v: s = S[c] + 1 S[c] = c + 1 @@ -3410,10 +3407,10 @@ def npoints(self): octahedron and its polar cube:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.npoints() # optional - palp + sage: o.npoints() # needs palp 7 sage: cube = o.polar() - sage: cube.npoints() # optional - palp + sage: cube.npoints() # needs palp 27 """ try: @@ -3449,9 +3446,9 @@ def origin(self): EXAMPLES:: sage: p = lattice_polytope.cross_polytope(2) - sage: p.origin() # optional - palp + sage: p.origin() # needs palp 4 - sage: p.point(p.origin()) # optional - palp + sage: p.point(p.origin()) # needs palp M(0, 0) sage: p = LatticePolytope(([1],[2])) @@ -3564,28 +3561,30 @@ def plot3d(self, EXAMPLES: The default plot of a cube:: sage: c = lattice_polytope.cross_polytope(3).polar() - sage: c.plot3d() # optional - palp sage.plot + sage: c.plot3d() # needs palp sage.plot Graphics3d Object Plot without facets and points, shown without the frame:: - sage: c.plot3d(show_facets=false, show_points=false).show(frame=False) # optional - palp sage.plot + sage: c.plot3d(show_facets=false, # needs palp sage.plot + ....: show_points=false).show(frame=False) Plot with facets of different colors:: - sage: c.plot3d(facet_colors=rainbow(c.nfacets(), 'rgbtuple')) # optional - palp sage.plot + sage: c.plot3d(facet_colors=rainbow(c.nfacets(), 'rgbtuple')) # needs palp sage.plot Graphics3d Object It is also possible to plot lower dimensional polytops in 3D (let's also change labels of vertices):: - sage: lattice_polytope.cross_polytope(2).plot3d(vlabels=["A", "B", "C", "D"]) # optional - palp sage.plot + sage: c2 = lattice_polytope.cross_polytope(2) + sage: c2.plot3d(vlabels=["A", "B", "C", "D"]) # needs palp sage.plot Graphics3d Object TESTS:: sage: p = LatticePolytope([[0,0,0],[0,1,1],[1,0,1],[1,1,0]]) - sage: p.plot3d() # optional - palp sage.plot + sage: p.plot3d() # needs palp sage.plot Graphics3d Object """ dim = self.dim() @@ -3676,7 +3675,7 @@ def show3d(self): EXAMPLES:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.show3d() # optional - palp sage.plot + sage: o.show3d() # needs palp sage.plot """ self.plot3d().show(axis=False, frame=False) @@ -3696,14 +3695,14 @@ def point(self, i): M( 0, -1, 0), M( 0, 0, -1) in 3-d lattice M - sage: o.point(1) # optional - palp + sage: o.point(1) # needs palp M(0, 1, 0) The only other point in the octahedron is the origin:: - sage: o.point(6) # optional - palp + sage: o.point(6) # needs palp M(0, 0, 0) - sage: o.points() # optional - palp + sage: o.points() # needs palp M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), @@ -3732,7 +3731,7 @@ def points(self, *args, **kwds): Lattice points of the octahedron and its polar cube:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.points() # optional - palp + sage: o.points() # needs palp M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), @@ -3742,7 +3741,7 @@ def points(self, *args, **kwds): M( 0, 0, 0) in 3-d lattice M sage: cube = o.polar() - sage: cube.points() # optional - palp + sage: cube.points() # needs palp N( 1, -1, -1), N( 1, 1, -1), N( 1, 1, 1), @@ -3775,7 +3774,7 @@ def points(self, *args, **kwds): Lattice points of a 2-dimensional diamond in a 3-dimensional space:: sage: p = LatticePolytope([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)]) - sage: p.points() # optional - palp + sage: p.points() # needs palp M( 1, 0, 0), M( 0, 1, 0), M(-1, 0, 0), @@ -3783,9 +3782,9 @@ def points(self, *args, **kwds): M( 0, 0, 0) in 3-d lattice M - Only two of the above points: + Only two of the above points:: - sage: p.points(1, 3) # optional - palp + sage: p.points(1, 3) # needs palp M(0, 1, 0), M(0, -1, 0) in 3-d lattice M @@ -3916,7 +3915,7 @@ def poly_x(self, keys, reduce_dimension=False): reflexive or not:: sage: o = lattice_polytope.cross_polytope(3) - sage: print(o.poly_x("e")) # optional - palp + sage: print(o.poly_x("e")) # needs palp 8 3 Vertices of P-dual <-> Equations of P -1 -1 1 1 -1 1 @@ -3934,7 +3933,7 @@ def poly_x(self, keys, reduce_dimension=False): sage: BIG = lattice_polytope.cross_polytope(7) sage: BIG 7-d reflexive polytope in 7-d lattice M - sage: BIG.poly_x("e") # optional - palp + sage: BIG.poly_x("e") # needs palp Traceback (most recent call last): ... ValueError: Error executing 'poly.x -fe' for the given polytope! @@ -3945,7 +3944,7 @@ def poly_x(self, keys, reduce_dimension=False): could, it would crush anyway):: sage: p = LatticePolytope([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)]) - sage: p.poly_x("e") # optional - palp + sage: p.poly_x("e") # needs palp Traceback (most recent call last): ... ValueError: Cannot run PALP for a 2-dimensional polytope in a 3-dimensional space! @@ -3953,7 +3952,7 @@ def poly_x(self, keys, reduce_dimension=False): But if you know what you are doing, you can call it for the polytope in some basis of the spanned space:: - sage: print(p.poly_x("e", reduce_dimension=True)) # optional - palp + sage: print(p.poly_x("e", reduce_dimension=True)) # needs palp 4 2 Equations of P -1 1 0 1 1 2 @@ -3970,9 +3969,9 @@ def skeleton(self): EXAMPLES:: sage: d = lattice_polytope.cross_polytope(2) - sage: g = d.skeleton(); g # optional - palp + sage: g = d.skeleton(); g # needs palp sage.graphs Graph on 4 vertices - sage: g.edges(sort=True) # optional - palp + sage: g.edges(sort=True) # needs palp sage.graphs [(0, 1, None), (0, 3, None), (1, 2, None), (2, 3, None)] """ skeleton = Graph() @@ -3992,34 +3991,37 @@ def skeleton_points(self, k=1): sage: o = lattice_polytope.cross_polytope(3) sage: c = o.polar() - sage: c.skeleton_points() # optional - palp + sage: c.skeleton_points() # needs palp sage.graphs [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 19, 21, 22, 23, 25, 26] The default was 1-skeleton:: - sage: c.skeleton_points(k=1) # optional - palp + sage: c.skeleton_points(k=1) # needs palp sage.graphs [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 19, 21, 22, 23, 25, 26] 0-skeleton just lists all vertices:: - sage: c.skeleton_points(k=0) # optional - palp + sage: c.skeleton_points(k=0) # needs palp sage.graphs [0, 1, 2, 3, 4, 5, 6, 7] 2-skeleton lists all points except for the origin (point #17):: - sage: c.skeleton_points(k=2) # optional - palp - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26] + sage: c.skeleton_points(k=2) # needs palp sage.graphs + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 18, 19, 20, 21, 22, 23, 24, 25, 26] 3-skeleton includes all points:: - sage: c.skeleton_points(k=3) # optional - palp - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] + sage: c.skeleton_points(k=3) # needs palp + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26] It is OK to compute higher dimensional skeletons - you will get the list of all points:: - sage: c.skeleton_points(k=100) # optional - palp - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] + sage: c.skeleton_points(k=100) # needs palp + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26] """ if k >= self.dim(): return list(range(self.npoints())) @@ -4045,7 +4047,7 @@ def skeleton_show(self, normal=None): EXAMPLES: Show a pretty picture of the octahedron:: sage: o = lattice_polytope.cross_polytope(3) - sage: o.skeleton_show([1,2,4]) # optional - palp sage.plot + sage: o.skeleton_show([1,2,4]) # needs palp sage.plot Does not work for a diamond at the moment:: @@ -4073,7 +4075,7 @@ def traverse_boundary(self): EXAMPLES:: sage: p = lattice_polytope.cross_polytope(2).polar() - sage: p.traverse_boundary() + sage: p.traverse_boundary() # needs sage.graphs [3, 0, 1, 2] """ if self.dim() != 2: @@ -4202,9 +4204,9 @@ def is_NefPartition(x): sage: is_NefPartition(1) False sage: o = lattice_polytope.cross_polytope(3) - sage: np = o.nef_partitions()[0]; np # optional - palp + sage: np = o.nef_partitions()[0]; np # needs palp Nef-partition {0, 1, 3} โŠ” {2, 4, 5} - sage: is_NefPartition(np) # optional - palp + sage: is_NefPartition(np) # needs palp True """ return isinstance(x, NefPartition) @@ -4342,7 +4344,7 @@ class NefPartition(SageObject, Hashable): nef-partitions of a given reflexive polytope (they will be computed using ``nef.x`` program from PALP):: - sage: o.nef_partitions() # optional - palp + sage: o.nef_partitions() # needs palp [ Nef-partition {0, 1, 3} โŠ” {2, 4, 5}, Nef-partition {0, 1, 3, 4} โŠ” {2, 5} (direct product), @@ -4359,8 +4361,8 @@ def __init__(self, data, Delta_polar, check=True): TESTS:: sage: o = lattice_polytope.cross_polytope(3) - sage: np = o.nef_partitions()[0] # optional - palp - sage: TestSuite(np).run() # optional - palp + sage: np = o.nef_partitions()[0] # needs palp + sage: TestSuite(np).run() # needs palp """ if check and not Delta_polar.is_reflexive(): raise ValueError("nef-partitions can be constructed for reflexive " @@ -4395,9 +4397,9 @@ def __eq__(self, other): sage: np = NefPartition([0, 0, 1, 0, 1, 1], o) sage: np == np True - sage: np == o.nef_partitions()[0] # optional - palp + sage: np == o.nef_partitions()[0] # needs palp True - sage: np == o.nef_partitions()[1] # optional - palp + sage: np == o.nef_partitions()[1] # needs palp False sage: np2 = NefPartition(np._vertex_to_part, o) sage: np2 is np @@ -4456,9 +4458,9 @@ def __ne__(self, other): sage: np = NefPartition([0, 0, 1, 0, 1, 1], o) sage: np != np False - sage: np != o.nef_partitions()[0] # optional - palp + sage: np != o.nef_partitions()[0] # needs palp False - sage: np != o.nef_partitions()[1] # optional - palp + sage: np != o.nef_partitions()[1] # needs palp True sage: np2 = NefPartition(np._vertex_to_part, o) sage: np2 is np @@ -4738,14 +4740,15 @@ def hodge_numbers(self): Currently, you need to request Hodge numbers when you compute nef-partitions:: + sage: # long time, needs palp sage: p = lattice_polytope.cross_polytope(5) - sage: np = p.nef_partitions()[0] # long time (4s on sage.math, 2011) # optional - palp - sage: np.hodge_numbers() # long time # optional - palp + sage: np = p.nef_partitions()[0] # 4s on sage.math, 2011 + sage: np.hodge_numbers() Traceback (most recent call last): ... NotImplementedError: use nef_partitions(hodge_numbers=True)! - sage: np = p.nef_partitions(hodge_numbers=True)[0] # long time (13s on sage.math, 2011) # optional - palp - sage: np.hodge_numbers() # long time # optional - palp + sage: np = p.nef_partitions(hodge_numbers=True)[0] # 13s on sage.math, 2011 + sage: np.hodge_numbers() (19, 19) """ try: @@ -4923,11 +4926,11 @@ def part(self, i, all_points=False): Nef-partition {0, 1, 3} โŠ” {2, 4, 5} sage: np.part(0) (0, 1, 3) - sage: np.part(0, all_points=True) # optional - palp + sage: np.part(0, all_points=True) # needs palp (0, 1, 3) sage: np.dual().part(0) (0, 1, 2, 3) - sage: np.dual().part(0, all_points=True) # optional - palp + sage: np.dual().part(0, all_points=True) # needs palp (0, 1, 2, 3, 8) """ return self.parts(all_points)[i] @@ -4957,11 +4960,11 @@ def parts(self, all_points=False): Nef-partition {0, 1, 3} โŠ” {2, 4, 5} sage: np.parts() ((0, 1, 3), (2, 4, 5)) - sage: np.parts(all_points=True) # optional - palp + sage: np.parts(all_points=True) # needs palp ((0, 1, 3), (2, 4, 5)) sage: np.dual().parts() ((0, 1, 2, 3), (4, 5, 6, 7)) - sage: np.dual().parts(all_points=True) # optional - palp + sage: np.dual().parts(all_points=True) # needs palp ((0, 1, 2, 3, 8), (4, 5, 6, 7, 10)) """ parts = [[] for _ in range(self._nparts)] @@ -5035,29 +5038,29 @@ def part_of_point(self, i): sage: p = LatticePolytope([(1,0,0), (0,1,0), (0,0,1), (0,1,-1), ....: (0,-1,1), (-1,1,0), (0,-1,-1), (-1,-1,0), (-1,-1,2)]) - sage: np = p.nef_partitions()[0]; np # optional - palp + sage: np = p.nef_partitions()[0]; np # needs palp Nef-partition {1, 2, 5, 7, 8} โŠ” {0, 3, 4, 6} sage: p.nvertices() 9 - sage: p.npoints() # optional - palp + sage: p.npoints() # needs palp 15 We see that the polytope has 6 more points in addition to vertices. One of them is the origin:: - sage: p.origin() # optional - palp + sage: p.origin() # needs palp 14 - sage: np.part_of_point(14) # optional - palp + sage: np.part_of_point(14) # needs palp Traceback (most recent call last): ... ValueError: the origin belongs to all parts! But the remaining 5 are partitioned by ``np``:: - sage: [n for n in range(p.npoints()) # optional - palp + sage: [n for n in range(p.npoints()) # needs palp ....: if p.origin() != n and np.part_of_point(n) == 0] [1, 2, 5, 7, 8, 9, 11, 13] - sage: [n for n in range(p.npoints()) # optional - palp + sage: [n for n in range(p.npoints()) # needs palp ....: if p.origin() != n and np.part_of_point(n) == 1] [0, 3, 4, 6, 10, 12] """ @@ -5090,26 +5093,29 @@ def _palp(command, polytopes, reduce_dimension=False): TESTS:: + sage: # needs palp sage: o = lattice_polytope.cross_polytope(3) - sage: result_name = lattice_polytope._palp("poly.x -f", [o]) # optional - palp - sage: f = open(result_name) # optional - palp - sage: f.readlines() # optional - palp + sage: result_name = lattice_polytope._palp("poly.x -f", [o]) + sage: f = open(result_name) + sage: f.readlines() ['M:7 6 N:27 8 Pic:17 Cor:0\n'] - sage: f.close() # optional - palp - sage: os.remove(result_name) # optional - palp + sage: f.close() + sage: os.remove(result_name) sage: p = LatticePolytope([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)]) - sage: lattice_polytope._palp("poly.x -f", [p]) # optional - palp + sage: lattice_polytope._palp("poly.x -f", [p]) # needs palp Traceback (most recent call last): ... ValueError: Cannot run PALP for a 2-dimensional polytope in a 3-dimensional space! - sage: result_name = lattice_polytope._palp("poly.x -f", [p], reduce_dimension=True) # optional - palp - sage: f = open(result_name) # optional - palp - sage: f.readlines() # optional - palp + sage: # needs palp + sage: result_name = lattice_polytope._palp("poly.x -f", [p], + ....: reduce_dimension=True) + sage: f = open(result_name) + sage: f.readlines() ['M:5 4 F:4\n'] - sage: f.close() # optional - palp - sage: os.remove(result_name) # optional - palp + sage: f.close() + sage: os.remove(result_name) """ if _palp_dimension is not None: dot = command.find(".") @@ -5180,9 +5186,9 @@ def _palp_canonical_order(V, PM_max, permutations): sage: L = lattice_polytope.cross_polytope(2) sage: V = L.vertices() - sage: PM_max, permutations = L._palp_PM_max(check=True) # optional - sage.groups + sage: PM_max, permutations = L._palp_PM_max(check=True) # needs sage.groups sage: from sage.geometry.lattice_polytope import _palp_canonical_order - sage: _palp_canonical_order(V, PM_max, permutations) # optional - sage.groups + sage: _palp_canonical_order(V, PM_max, permutations) # needs sage.groups (M( 1, 0), M( 0, 1), M( 0, -1), @@ -5190,11 +5196,10 @@ def _palp_canonical_order(V, PM_max, permutations): in 2-d lattice M, (1,3,2,4)) """ n_v = PM_max.ncols() - n_f = PM_max.nrows() S_v = SymmetricGroup(n_v) p_c = S_v.one() - M_max = [max([PM_max[i][j] for i in range(n_f)]) for j in range(n_v)] - S_max = [sum([PM_max[i][j] for i in range(n_f)]) for j in range(n_v)] + M_max = [max(row[j] for row in PM_max.rows()) for j in range(n_v)] + S_max = sum(PM_max) for i in range(n_v): k = i for j in range(i + 1, n_v): @@ -5207,13 +5212,15 @@ def _palp_canonical_order(V, PM_max, permutations): p_c = S_v((1 + i, 1 + k), check=False) * p_c # Create array of possible NFs. permutations = [p_c * l[1] for l in permutations.values()] - Vs = [(V.column_matrix().with_permuted_columns(sig).hermite_form(), sig) + Vmatrix = V.column_matrix() + Vs = [(Vmatrix.with_permuted_columns(sig).hermite_form(), sig) for sig in permutations] Vmin = min(Vs, key=lambda x:x[0]) - vertices = [V.module()(_) for _ in Vmin[0].columns()] + Vmodule = V.module() + vertices = [Vmodule(_) for _ in Vmin[0].columns()] for v in vertices: v.set_immutable() - return (PointCollection(vertices, V.module()), Vmin[1]) + return (PointCollection(vertices, Vmodule), Vmin[1]) def _palp_convert_permutation(permutation): @@ -5235,9 +5242,9 @@ def _palp_convert_permutation(permutation): EXAMPLES:: sage: from sage.geometry.lattice_polytope import _palp_convert_permutation - sage: _palp_convert_permutation('1023') # optional - sage.groups + sage: _palp_convert_permutation('1023') # needs sage.groups (1,2) - sage: _palp_convert_permutation('0123456789bac') # optional - sage.groups + sage: _palp_convert_permutation('0123456789bac') # needs sage.groups (11,12) """ def from_palp_index(i): @@ -5251,8 +5258,8 @@ def from_palp_index(i): elif o in range(65, 91): i = o - 28 else: - raise ValueError('Cannot convert PALP index ' - + i + ' to number.') + raise ValueError('cannot convert PALP index ' + + i + ' to number') return i n = len(permutation) domain = [from_palp_index(i) for i in permutation] @@ -5261,6 +5268,7 @@ def from_palp_index(i): S = SymmetricGroup(n) return make_permgroup_element(S, domain) + def _read_nef_x_partitions(data): r""" Read all nef-partitions for one polytope from a string or an open @@ -5277,14 +5285,14 @@ def _read_nef_x_partitions(data): TESTS:: sage: o = lattice_polytope.cross_polytope(3) - sage: s = o.nef_x("-N -p") # optional - palp - sage: print(s) # random # optional - palp + sage: s = o.nef_x("-N -p") # needs palp + sage: print(s) # random # needs palp M:27 8 N:7 6 codim=2 #part=5 P:0 V:2 4 5 0sec 0cpu P:2 V:3 4 5 0sec 0cpu P:3 V:4 5 0sec 0cpu np=3 d:1 p:1 0sec 0cpu - sage: lattice_polytope._read_nef_x_partitions(s) # optional - palp + sage: lattice_polytope._read_nef_x_partitions(s) # needs palp [[2, 4, 5], [3, 4, 5], [4, 5]] """ if isinstance(data, str): @@ -5339,9 +5347,10 @@ def _read_poly_x_incidences(data, dim): TESTS:: + sage: # needs palp sage: p = lattice_polytope.cross_polytope(2) - sage: result_name = lattice_polytope._palp("poly.x -fi", [p]) # optional - palp - sage: with open(result_name) as f: # optional - palp + sage: result_name = lattice_polytope._palp("poly.x -fi", [p]) + sage: with open(result_name) as f: ....: print(f.read()) Incidences as binary numbers [F-vector=(4 4)]: v[d][i]: sum_j Incidence(i'th dim-d-face, j-th vertex) x 2^j @@ -5350,12 +5359,12 @@ def _read_poly_x_incidences(data, dim): f[d][i]: sum_j Incidence(i'th dim-d-face, j-th facet) x 2^j f[0]: 0011 0101 1010 1100 f[1]: 0001 0010 0100 1000 - sage: f = open(result_name) # optional - palp - sage: l = f.readline() # optional - palp - sage: lattice_polytope._read_poly_x_incidences(f, 2) # optional - palp + sage: f = open(result_name) + sage: l = f.readline() + sage: lattice_polytope._read_poly_x_incidences(f, 2) [[[3], [0], [2], [1]], [[0, 3], [2, 3], [0, 1], [1, 2]]] - sage: f.close() # optional - palp - sage: os.remove(result_name) # optional - palp + sage: f.close() + sage: os.remove(result_name) """ data.readline() lines = [data.readline().split() for i in range(dim)] @@ -5393,7 +5402,7 @@ def all_cached_data(polytopes): sequences as well:: sage: o = lattice_polytope.cross_polytope(3) - sage: lattice_polytope.all_cached_data([o]) # optional - palp + sage: lattice_polytope.all_cached_data([o]) # needs palp """ all_polars(polytopes) all_points(polytopes) @@ -5424,8 +5433,8 @@ def all_nef_partitions(polytopes, keep_symmetric=False): sequences as well:: sage: o = lattice_polytope.cross_polytope(3) - sage: lattice_polytope.all_nef_partitions([o]) # optional - palp - sage: o.nef_partitions() # optional - palp + sage: lattice_polytope.all_nef_partitions([o]) # needs palp + sage: o.nef_partitions() # needs palp [ Nef-partition {0, 1, 3} โŠ” {2, 4, 5}, Nef-partition {0, 1, 3, 4} โŠ” {2, 5} (direct product), @@ -5438,7 +5447,7 @@ def all_nef_partitions(polytopes, keep_symmetric=False): sage: p = LatticePolytope([(1,0,0), (0,1,0), (0,0,2), ....: (-1,0,0), (0,-1,0), (0,0,-1)]) - sage: lattice_polytope.all_nef_partitions([o, p]) # optional - palp + sage: lattice_polytope.all_nef_partitions([o, p]) # needs palp Traceback (most recent call last): ... ValueError: nef-partitions can be computed for reflexive polytopes only @@ -5473,8 +5482,8 @@ def all_points(polytopes): sequences as well:: sage: o = lattice_polytope.cross_polytope(3) - sage: lattice_polytope.all_points([o]) # optional - palp - sage: o.points() # optional - palp + sage: lattice_polytope.all_points([o]) # needs palp + sage: o.points() # needs palp M( 1, 0, 0), M( 0, 1, 0), M( 0, 0, 1), @@ -5526,8 +5535,8 @@ def all_polars(polytopes): sequences as well:: sage: o = lattice_polytope.cross_polytope(3) - sage: lattice_polytope.all_polars([o]) # optional - palp - sage: o.polar() # optional - palp + sage: lattice_polytope.all_polars([o]) # needs palp + sage: o.polar() # needs palp 3-d reflexive polytope in 3-d lattice N """ result_name = _palp("poly.x -fe", polytopes) @@ -5537,6 +5546,7 @@ def all_polars(polytopes): result.close() os.remove(result_name) + # Synonym for the above function all_facet_equations = all_polars @@ -5668,8 +5678,8 @@ def positive_integer_relations(points): EXAMPLES: This is a 3-dimensional reflexive polytope:: sage: p = LatticePolytope([(1,0,0), (0,1,0), - ....: (-1,-1,0), (0,0,1), (-1,0,-1)]) - sage: p.points() # optional - palp + ....: (-1,-1,0), (0,0,1), (-1,0,-1)]) + sage: p.points() # needs palp M( 1, 0, 0), M( 0, 1, 0), M(-1, -1, 0), @@ -5681,7 +5691,7 @@ def positive_integer_relations(points): We can compute linear relations between its points in the following way:: - sage: p.points().matrix().kernel().echelonized_basis_matrix() # optional - palp + sage: p.points().matrix().kernel().echelonized_basis_matrix() # needs palp [ 1 0 0 1 1 0] [ 0 1 1 -1 -1 0] [ 0 0 0 0 0 1] @@ -5690,7 +5700,8 @@ def positive_integer_relations(points): numbers. This function transforms them in such a way, that all coefficients are non-negative integers:: - sage: lattice_polytope.positive_integer_relations(p.points().column_matrix()) # optional - palp + sage: points = p.points().column_matrix() + sage: lattice_polytope.positive_integer_relations(points) # needs palp [1 0 0 1 1 0] [1 1 1 0 0 0] [0 0 0 0 0 1] @@ -5756,10 +5767,11 @@ def read_all_polytopes(file_name): We use poly.x to compute two polar polytopes and read them:: + sage: # needs palp sage: d = lattice_polytope.cross_polytope(2) sage: o = lattice_polytope.cross_polytope(3) - sage: result_name = lattice_polytope._palp("poly.x -fe", [d, o]) # optional - palp - sage: with open(result_name) as f: # optional - palp + sage: result_name = lattice_polytope._palp("poly.x -fe", [d, o]) + sage: with open(result_name) as f: ....: print(f.read()) 4 2 Vertices of P-dual <-> Equations of P -1 1 @@ -5775,10 +5787,10 @@ def read_all_polytopes(file_name): 1 -1 -1 -1 1 -1 1 1 -1 - sage: lattice_polytope.read_all_polytopes(result_name) # optional - palp + sage: lattice_polytope.read_all_polytopes(result_name) [2-d reflexive polytope #14 in 2-d lattice M, 3-d reflexive polytope in 3-d lattice M] - sage: os.remove(result_name) # optional - palp + sage: os.remove(result_name) """ polytopes = [] with open(file_name) as f: @@ -5878,7 +5890,7 @@ def set_palp_dimension(d): Let's try to work with a 7-dimensional polytope:: sage: p = lattice_polytope.cross_polytope(7) - sage: p._palp("poly.x -fv") # optional - palp + sage: p._palp("poly.x -fv") # needs palp Traceback (most recent call last): ... ValueError: Error executing 'poly.x -fv' for the given polytope! @@ -5888,7 +5900,7 @@ def set_palp_dimension(d): However, we can work with this polytope by changing PALP dimension to 11:: sage: lattice_polytope.set_palp_dimension(11) - sage: p._palp("poly.x -fv") # optional - palp + sage: p._palp("poly.x -fv") # needs palp '7 14 Vertices of P...' Let's go back to default settings:: @@ -5919,10 +5931,11 @@ def skip_palp_matrix(data, n=1): EXAMPLES: We create a file with vertices of the square and the cube, but read only the second set:: + sage: # needs palp sage: d = lattice_polytope.cross_polytope(2) sage: o = lattice_polytope.cross_polytope(3) - sage: result_name = lattice_polytope._palp("poly.x -fe", [d, o]) # optional - palp - sage: with open(result_name) as f: # optional - palp + sage: result_name = lattice_polytope._palp("poly.x -fe", [d, o]) + sage: with open(result_name) as f: ....: print(f.read()) 4 2 Vertices of P-dual <-> Equations of P -1 1 @@ -5938,14 +5951,14 @@ def skip_palp_matrix(data, n=1): 1 -1 -1 -1 1 -1 1 1 -1 - sage: f = open(result_name) # optional - palp - sage: lattice_polytope.skip_palp_matrix(f) # optional - palp - sage: lattice_polytope.read_palp_matrix(f) # optional - palp + sage: f = open(result_name) + sage: lattice_polytope.skip_palp_matrix(f) + sage: lattice_polytope.read_palp_matrix(f) [-1 1 -1 1 -1 1 -1 1] [-1 -1 1 1 -1 -1 1 1] [ 1 1 1 1 -1 -1 -1 -1] - sage: f.close() # optional - palp - sage: os.remove(result_name) # optional - palp + sage: f.close() + sage: os.remove(result_name) """ for i in range(n): line = data.readline() diff --git a/src/sage/geometry/linear_expression.py b/src/sage/geometry/linear_expression.py index 7f4a91b3194..0bc15952746 100644 --- a/src/sage/geometry/linear_expression.py +++ b/src/sage/geometry/linear_expression.py @@ -440,7 +440,7 @@ def evaluate(self, point): 9 sage: ex([1,1]) # syntactic sugar 9 - sage: ex([pi, e]) + sage: ex([pi, e]) # needs sage.symbolic 2*pi + 3*e + 4 """ try: diff --git a/src/sage/geometry/newton_polygon.py b/src/sage/geometry/newton_polygon.py index 4f253741ab7..28101e70646 100644 --- a/src/sage/geometry/newton_polygon.py +++ b/src/sage/geometry/newton_polygon.py @@ -464,7 +464,7 @@ def plot(self, **kwargs): sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (2,6) ]) - sage: polygon = NP.plot() # optional - sage.plot + sage: polygon = NP.plot() # needs sage.plot """ vertices = self.vertices() if len(vertices) == 0: @@ -523,8 +523,6 @@ def reverse(self, degree=None): return parent(polyhedron) - - class ParentNewtonPolygon(Parent, UniqueRepresentation): r""" Construct a Newton polygon. @@ -630,13 +628,15 @@ def __init__(self): """ Parent class for all Newton polygons. + EXAMPLES:: + sage: from sage.geometry.newton_polygon import ParentNewtonPolygon sage: ParentNewtonPolygon() Parent for Newton polygons TESTS: - This class is a singleton. + This class is a singleton:: sage: ParentNewtonPolygon() is ParentNewtonPolygon() True diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 913a788b5df..2e20e508057 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.graphs r""" Finite polyhedral complexes @@ -117,7 +117,7 @@ from sage.rings.integer_ring import ZZ from sage.graphs.graph import Graph from sage.combinat.posets.posets import Poset -from sage.misc.misc import powerset +from sage.combinat.subset import powerset class PolyhedralComplex(GenericCellComplex): @@ -203,7 +203,7 @@ class PolyhedralComplex(GenericCellComplex): (A vertex at (0, 1/4),), (A vertex at (1/7, 2/7),), (A vertex at (1/3, 1/3),)] - sage: pc.plot() # optional - sage.plot + sage: pc.plot() # needs sage.plot Graphics object consisting of 10 graphics primitives sage: pc.is_pure() True @@ -752,17 +752,17 @@ def plot(self, **kwds): sage: p3 = Polyhedron(vertices=[(0, 0), (0, 2), (-1, 1)]) sage: pc1 = PolyhedralComplex([p1, p2, p3, -p1, -p2, -p3]) sage: bb = dict(xmin=-2, xmax=2, ymin=-3, ymax=3, axes=False) - sage: g0 = pc1.plot(color='rainbow', **bb) # optional - sage.plot - sage: g1 = pc1.plot(explosion_factor=0.5, **bb) # optional - sage.plot - sage: g2 = pc1.plot(explosion_factor=1, color='rainbow', alpha=0.5, **bb) # optional - sage.plot + sage: g0 = pc1.plot(color='rainbow', **bb) # needs sage.plot + sage: g1 = pc1.plot(explosion_factor=0.5, **bb) # needs sage.plot + sage: g2 = pc1.plot(explosion_factor=1, color='rainbow', alpha=0.5, **bb) # needs sage.plot sage: graphics_array([g0, g1, g2]).show(axes=False) # not tested sage: pc2 = PolyhedralComplex([polytopes.hypercube(3)]) sage: pc3 = pc2.subdivide(new_vertices=[(0, 0, 0)]) - sage: g3 = pc3.plot(explosion_factor=1, color='rainbow', # optional - sage.plot + sage: g3 = pc3.plot(explosion_factor=1, color='rainbow', # needs sage.plot ....: alpha=0.5, axes=False, online=True) sage: pc4 = pc2.subdivide(make_simplicial=True) - sage: g4 = pc4.plot(explosion_factor=1, center=(1, -1, 1), fill='blue', # optional - sage.plot + sage: g4 = pc4.plot(explosion_factor=1, center=(1, -1, 1), fill='blue', # needs sage.plot ....: wireframe='white', point={'color':'red', 'size':10}, ....: alpha=0.6, online=True) sage: pc5 = PolyhedralComplex([ @@ -773,7 +773,7 @@ def plot(self, **kwds): ....: Polyhedron(rays=[[-1,0,0], [0,-1,0], [0,0,1]]), ....: Polyhedron(rays=[[-1,0,0], [0,1,0], [0,0,-1]]), ....: Polyhedron(rays=[[-1,0,0], [0,1,0], [0,0,1]])]) - sage: g5 = pc5.plot(explosion_factor=0.3, color='rainbow', alpha=0.8, # optional - sage.plot + sage: g5 = pc5.plot(explosion_factor=0.3, color='rainbow', alpha=0.8, # needs sage.plot ....: point={'size': 20}, axes=False, online=True) """ @@ -1001,7 +1001,7 @@ def face_poset(self): sage: poset Finite poset containing 11 elements sage: d = {i: i.vertices_matrix() for i in poset} - sage: poset.plot(element_labels=d) # optional - sage.plot + sage: poset.plot(element_labels=d) # needs sage.plot Graphics object consisting of 28 graphics primitives For a nonbounded polyhedral complex:: @@ -1234,7 +1234,7 @@ def connected_component(self, cell=None): if v not in g: raise ValueError( "the polyhedral complex does not contain the given cell") - vertices = g.connected_component_containing_vertex(v) + vertices = g.connected_component_containing_vertex(v, sort=False) facets = [f for f in self.maximal_cell_iterator() if any(vf in f.vertices_matrix().columns() for vf in vertices)] @@ -1243,7 +1243,7 @@ def connected_component(self, cell=None): if cell not in g: raise ValueError( "the polyhedral complex does not contain the given cell") - faces = g.connected_component_containing_vertex(cell) + faces = g.connected_component_containing_vertex(cell, sort=False) facets = [f for f in self.maximal_cell_iterator() if f in faces] return PolyhedralComplex(facets, maximality_check=False, @@ -2532,11 +2532,11 @@ def exploded_plot(polyhedra, *, sage: p1 = Polyhedron(vertices=[(1, 1), (0, 0), (1, 2)]) sage: p2 = Polyhedron(vertices=[(1, 2), (0, 0), (0, 2)]) sage: p3 = Polyhedron(vertices=[(0, 0), (1, 1), (2, 0)]) - sage: exploded_plot([p1, p2, p3]) # optional - sage.plot + sage: exploded_plot([p1, p2, p3]) # needs sage.plot Graphics object consisting of 20 graphics primitives - sage: exploded_plot([p1, p2, p3], center=(1, 1)) # optional - sage.plot + sage: exploded_plot([p1, p2, p3], center=(1, 1)) # needs sage.plot Graphics object consisting of 19 graphics primitives - sage: exploded_plot([p1, p2, p3], center=(1, 1), sticky_vertices=True) # optional - sage.plot + sage: exploded_plot([p1, p2, p3], center=(1, 1), sticky_vertices=True) # needs sage.plot Graphics object consisting of 23 graphics primitives """ from sage.plot.colors import rainbow diff --git a/src/sage/geometry/polyhedron/backend_cdd.py b/src/sage/geometry/polyhedron/backend_cdd.py index 442aabbd328..f0e7e3ada8b 100644 --- a/src/sage/geometry/polyhedron/backend_cdd.py +++ b/src/sage/geometry/polyhedron/backend_cdd.py @@ -54,8 +54,8 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, verbose=False): EXAMPLES:: - sage: Polyhedron(vertices=[(0,0)], rays=[(1,1)], - ....: lines=[(1,-1)], backend='cdd', base_ring=QQ) # indirect doctest + sage: Polyhedron(vertices=[(0,0)], rays=[(1,1)], # indirect doctest + ....: lines=[(1,-1)], backend='cdd', base_ring=QQ) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line """ @@ -106,8 +106,8 @@ def _init_from_Hrepresentation(self, ieqs, eqns, verbose=False): EXAMPLES:: - sage: Polyhedron(ieqs=[(0,1,1)], eqns=[(0,1,-1)], - ....: backend='cdd', base_ring=QQ) # indirect doctest + sage: Polyhedron(ieqs=[(0,1,1)], eqns=[(0,1,-1)], # indirect doctest + ....: backend='cdd', base_ring=QQ) A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray @@ -217,7 +217,7 @@ def _init_from_cdd_output(self, cddout): TESTS:: - sage: p = Polyhedron(vertices = [[0,0],[1,0],[0,1],[1,1]], backend='cdd', base_ring=QQ) # indirect doctest + sage: p = Polyhedron(vertices = [[0,0],[1,0],[0,1],[1,1]], backend='cdd', base_ring=QQ) # indirect doctest sage: p.vertices() (A vertex at (0, 0), A vertex at (1, 0), A vertex at (0, 1), A vertex at (1, 1)) diff --git a/src/sage/geometry/polyhedron/backend_cdd_rdf.py b/src/sage/geometry/polyhedron/backend_cdd_rdf.py index 2f3795a4b0f..a39ad446a80 100644 --- a/src/sage/geometry/polyhedron/backend_cdd_rdf.py +++ b/src/sage/geometry/polyhedron/backend_cdd_rdf.py @@ -1,3 +1,5 @@ +# sage.doctest: optional - sage.rings.real_double + r""" The cdd backend for polyhedral computations, floating point version """ @@ -123,8 +125,8 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep, verbose=Fal sage: parent = Polyhedra_RDF_cdd(RDF, 1, 'cdd') sage: Vrep = [[[0.0], [1.0]], [], []] sage: Hrep = [[[0.0, 1.0], [1.0, -1.0]], []] - sage: p = Polyhedron_RDF_cdd(parent, Vrep, Hrep, - ....: Vrep_minimal=True, Hrep_minimal=True) # indirect doctest + sage: p = Polyhedron_RDF_cdd(parent, Vrep, Hrep, # indirect doctest + ....: Vrep_minimal=True, Hrep_minimal=True) sage: p A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 2 vertices @@ -132,6 +134,7 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep, verbose=Fal Test that :trac:`29568` is fixed:: + sage: # needs sage.groups sage: P = polytopes.buckyball(exact=False) sage: Q = P + P.center() sage: P.is_combinatorially_isomorphic(Q) @@ -144,8 +147,8 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep, verbose=Fal sage: Vrep = [[], [], [[1.0]]] sage: Hrep = [[], []] - sage: p = Polyhedron_RDF_cdd(parent, Vrep, Hrep, - ....: Vrep_minimal=True, Hrep_minimal=True) # indirect doctest + sage: p = Polyhedron_RDF_cdd(parent, Vrep, Hrep, # indirect doctest + ....: Vrep_minimal=True, Hrep_minimal=True) sage: p A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 1 vertex and 1 line @@ -204,7 +207,7 @@ def try_init(rep): from warnings import catch_warnings, simplefilter vertices, rays, lines = (tuple(x) for x in Vrep) - ieqs, eqns = (tuple(x) for x in Hrep) + ieqs, eqns = (tuple(x) for x in Hrep) if not (vertices or rays or lines): # cdd refuses to handle empty polyhedra. @@ -214,7 +217,7 @@ def try_init(rep): # We prefer the shorter representation. # Note that for the empty polyhedron we prefer Hrepresentation. prim = "Hrep" if len(ieqs) <= len(vertices) + len(rays) else "Vrep" - sec = "Vrep" if len(ieqs) <= len(vertices) + len(rays) else "Hrep" + sec = "Vrep" if len(ieqs) <= len(vertices) + len(rays) else "Hrep" with catch_warnings(): # Raise an error and try the other representation in case of diff --git a/src/sage/geometry/polyhedron/backend_field.py b/src/sage/geometry/polyhedron/backend_field.py index 996d6c1a7ac..77d83c4a381 100644 --- a/src/sage/geometry/polyhedron/backend_field.py +++ b/src/sage/geometry/polyhedron/backend_field.py @@ -7,15 +7,16 @@ EXAMPLES:: + sage: # needs sage.rings.number_field sage: p0 = (0, 0) sage: p1 = (1, 0) - sage: p2 = (1/2, AA(3).sqrt()/2) # optional - sage.rings.number_field - sage: equilateral_triangle = Polyhedron([p0, p1, p2]) # optional - sage.rings.number_field - sage: equilateral_triangle.vertices() # optional - sage.rings.number_field + sage: p2 = (1/2, AA(3).sqrt()/2) + sage: equilateral_triangle = Polyhedron([p0, p1, p2]) + sage: equilateral_triangle.vertices() (A vertex at (0, 0), A vertex at (1, 0), A vertex at (0.500000000000000?, 0.866025403784439?)) - sage: equilateral_triangle.inequalities() # optional - sage.rings.number_field + sage: equilateral_triangle.inequalities() (An inequality (-1, -0.5773502691896258?) x + 1 >= 0, An inequality (1, -0.5773502691896258?) x + 0 >= 0, An inequality (0, 1.154700538379252?) x + 0 >= 0) @@ -46,23 +47,26 @@ class Polyhedron_field(Polyhedron_base): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # needs sage.rings.number_field ....: rays=[(1,1)], lines=[], backend='field', base_ring=AA) - sage: TestSuite(p).run() # optional - sage.rings.number_field + sage: TestSuite(p).run() # needs sage.rings.number_field TESTS:: - sage: K.<sqrt3> = QuadraticField(3) # optional - sage.rings.number_field - sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) # optional - sage.rings.number_field - sage: TestSuite(p).run() # optional - sage.rings.number_field + sage: K.<sqrt3> = QuadraticField(3) # needs sage.rings.number_field + sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) # needs sage.rings.number_field + sage: TestSuite(p).run() # needs sage.rings.number_field Check that :trac:`19013` is fixed:: - sage: K.<phi> = NumberField(x^2-x-1, embedding=1.618) # optional - sage.rings.number_field - sage: P1 = Polyhedron([[0,1],[1,1],[1,-phi+1]]) # optional - sage.rings.number_field - sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]]) # optional - sage.rings.number_field - sage: P1.intersection(P2) # optional - sage.rings.number_field - The empty polyhedron in (Number Field in phi with defining polynomial x^2 - x - 1 with phi = 1.618033988749895?)^2 + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<phi> = NumberField(x^2 - x - 1, embedding=1.618) + sage: P1 = Polyhedron([[0,1], [1,1], [1,-phi+1]]) + sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]]) + sage: P1.intersection(P2) + The empty polyhedron + in (Number Field in phi with defining polynomial x^2 - x - 1 with phi = 1.618033988749895?)^2 Check that :trac:`28654` is fixed:: @@ -83,10 +87,10 @@ def _is_zero(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field - sage: p._is_zero(0) # optional - sage.rings.number_field + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_zero(0) # needs sage.rings.number_field sage.symbolic True - sage: p._is_zero(1/100000) # optional - sage.rings.number_field + sage: p._is_zero(1/100000) # needs sage.rings.number_fiedl False """ return x == 0 @@ -105,10 +109,10 @@ def _is_nonneg(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field - sage: p._is_nonneg(1) # optional - sage.rings.number_field + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_nonneg(1) # needs sage.rings.number_field sage.symbolic True - sage: p._is_nonneg(-1/100000) # optional - sage.rings.number_field + sage: p._is_nonneg(-1/100000) # needs sage.rings.number_field sage.symbolic False """ return x >= 0 @@ -127,10 +131,10 @@ def _is_positive(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field - sage: p._is_positive(1) # optional - sage.rings.number_field + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_positive(1) # needs sage.rings.number_field sage.symbolic True - sage: p._is_positive(0) # optional - sage.rings.number_field + sage: p._is_positive(0) # needs sage.rings.number_field sage.symbolic False """ return x > 0 @@ -150,12 +154,12 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep): sage: from sage.geometry.polyhedron.parent import Polyhedra_field sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field - sage: parent = Polyhedra_field(AA, 1, 'field') # optional - sage.rings.number_field + sage: parent = Polyhedra_field(AA, 1, 'field') # needs sage.rings.number_field sage: Vrep = [[[0], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # optional - sage.rings.number_field + sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # needs sage.rings.number_field ....: Vrep_minimal=True, Hrep_minimal=True) - sage: p # optional - sage.rings.number_field + sage: p # needs sage.rings.number_field A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices """ self._init_Vrepresentation(*Vrep) @@ -244,12 +248,13 @@ def _init_Vrepresentation(self, vertices, rays, lines): sage: from sage.geometry.polyhedron.parent import Polyhedra_field sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field - sage: parent = Polyhedra_field(AA, 1, 'field') # optional - sage.rings.number_field + sage: parent = Polyhedra_field(AA, 1, 'field') # needs sage.rings.number_field sage: Vrep = [[[0], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # optional - sage.rings.number_field - ....: Vrep_minimal=True, Hrep_minimal=True) - sage: p.vertices_list() # optional - sage.rings.number_field + sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # needs sage.rings.number_field + ....: Vrep_minimal=True, + ....: Hrep_minimal=True) + sage: p.vertices_list() # needs sage.rings.number_field [[0], [1]] """ self._Vrepresentation = [] @@ -268,13 +273,15 @@ def _init_Vrepresentation_backend(self, Vrep): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/sqrt(2)),(sqrt(2),0),(4,sqrt(5)/6)], # optional - sage.rings.number_field - ....: base_ring=AA, backend='field') # indirect doctest - sage: p.Hrepresentation() # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(0, 1/sqrt(2)), # indirect doctest # needs sage.rings.number_field sage.symbolic + ....: (sqrt(2), 0), + ....: (4, sqrt(5)/6)], + ....: base_ring=AA, backend='field') + sage: p.Hrepresentation() # needs sage.rings.number_field sage.symbolic (An inequality (-0.1582178750233332?, 1.097777812326429?) x + 0.2237538646678492? >= 0, An inequality (-0.1419794359520263?, -1.698172434277148?) x + 1.200789243901438? >= 0, An inequality (0.3001973109753594?, 0.600394621950719?) x - 0.4245431085692869? >= 0) - sage: p.Vrepresentation() # optional - sage.rings.number_field + sage: p.Vrepresentation() # needs sage.rings.number_field sage.symbolic (A vertex at (0.?e-16, 0.7071067811865475?), A vertex at (1.414213562373095?, 0), A vertex at (4.000000000000000?, 0.372677996249965?)) @@ -289,12 +296,12 @@ def _init_Hrepresentation(self, inequalities, equations): sage: from sage.geometry.polyhedron.parent import Polyhedra_field sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field - sage: parent = Polyhedra_field(AA, 1, 'field') # optional - sage.rings.number_field + sage: parent = Polyhedra_field(AA, 1, 'field') # needs sage.rings.number_field sage: Vrep = [[[0], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # optional - sage.rings.number_field + sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # needs sage.rings.number_field ....: Vrep_minimal=True, Hrep_minimal=True) - sage: p.inequalities_list() # optional - sage.rings.number_field + sage: p.inequalities_list() # needs sage.rings.number_field [[0, 1], [1, -1]] """ self._Hrepresentation = [] @@ -311,13 +318,15 @@ def _init_Hrepresentation_backend(self, Hrep): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/sqrt(2)),(sqrt(2),0),(4,sqrt(5)/6)], # optional - sage.rings.number_field - ....: base_ring=AA, backend='field') # indirect doctest - sage: p.Hrepresentation() # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(0, 1/sqrt(2)), # indirect doctest # needs sage.rings.number_field sage.symbolic + ....: (sqrt(2), 0), + ....: (4, sqrt(5)/6)], + ....: base_ring=AA, backend='field') + sage: p.Hrepresentation() # needs sage.rings.number_field sage.symbolic (An inequality (-0.1582178750233332?, 1.097777812326429?) x + 0.2237538646678492? >= 0, An inequality (-0.1419794359520263?, -1.698172434277148?) x + 1.200789243901438? >= 0, An inequality (0.3001973109753594?, 0.600394621950719?) x - 0.4245431085692869? >= 0) - sage: p.Vrepresentation() # optional - sage.rings.number_field + sage: p.Vrepresentation() # needs sage.rings.number_field sage.symbolic (A vertex at (0.?e-16, 0.7071067811865475?), A vertex at (1.414213562373095?, 0), A vertex at (4.000000000000000?, 0.372677996249965?)) @@ -330,11 +339,11 @@ def _init_empty_polyhedron(self): TESTS:: - sage: empty = Polyhedron(backend='field', base_ring=AA); empty # optional - sage.rings.number_field + sage: empty = Polyhedron(backend='field', base_ring=AA); empty # needs sage.rings.number_field The empty polyhedron in AA^0 - sage: empty.Vrepresentation() # optional - sage.rings.number_field + sage: empty.Vrepresentation() # needs sage.rings.number_field () - sage: empty.Hrepresentation() # optional - sage.rings.number_field + sage: empty.Hrepresentation() # needs sage.rings.number_field (An equation -1 == 0,) sage: Polyhedron(vertices=[], backend='field') The empty polyhedron in QQ^0 diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index af0c2c459a7..19da8cce5e5 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - pynormaliz """ The Normaliz backend for polyhedral computations @@ -89,72 +90,74 @@ class Polyhedron_normaliz(Polyhedron_base_number_field): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], rays=[(1,1)], # optional - pynormaliz - ....: lines=[], backend='normaliz') - sage: TestSuite(p).run() # optional - pynormaliz + sage: p = Polyhedron(vertices=[(0,0), (1,0), (0,1)], + ....: rays=[(1,1)], lines=[], + ....: backend='normaliz') + sage: TestSuite(p).run() Two ways to get the full space:: - sage: Polyhedron(eqns=[[0, 0, 0]], backend='normaliz') # optional - pynormaliz + sage: Polyhedron(eqns=[[0, 0, 0]], backend='normaliz') A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 lines - sage: Polyhedron(ieqs=[[0, 0, 0]], backend='normaliz') # optional - pynormaliz + sage: Polyhedron(ieqs=[[0, 0, 0]], backend='normaliz') A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 lines A lower-dimensional affine cone; we test that there are no mysterious inequalities coming in from the homogenization:: - sage: P = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], # optional - pynormaliz + sage: P = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], ....: backend='normaliz') - sage: P.n_inequalities() # optional - pynormaliz + sage: P.n_inequalities() 1 - sage: P.equations() # optional - pynormaliz + sage: P.equations() (An equation (1, 0) x - 1 == 0,) The empty polyhedron:: - sage: P=Polyhedron(ieqs=[[-2, 1, 1], [-3, -1, -1], [-4, 1, -2]], # optional - pynormaliz - ....: backend='normaliz') - sage: P # optional - pynormaliz + sage: P = Polyhedron(ieqs=[[-2, 1, 1], [-3, -1, -1], [-4, 1, -2]], + ....: backend='normaliz') + sage: P The empty polyhedron in QQ^2 - sage: P.Vrepresentation() # optional - pynormaliz + sage: P.Vrepresentation() () - sage: P.Hrepresentation() # optional - pynormaliz + sage: P.Hrepresentation() (An equation -1 == 0,) TESTS: Tests copied from various methods in :mod:`sage.geometry.polyhedron.base`:: - sage: p = Polyhedron(vertices = [[1,0,0], [0,1,0], [0,0,1]], # optional - pynormaliz + sage: p = Polyhedron(vertices=[[1,0,0], [0,1,0], [0,0,1]], ....: backend='normaliz') - sage: p.n_equations() # optional - pynormaliz + sage: p.n_equations() 1 - sage: p.n_inequalities() # optional - pynormaliz + sage: p.n_inequalities() 3 - sage: p = Polyhedron(vertices = [[t,t^2,t^3] for t in range(6)], # optional - pynormaliz + sage: p = Polyhedron(vertices=[[t,t^2,t^3] for t in range(6)], ....: backend='normaliz') - sage: p.n_facets() # optional - pynormaliz + sage: p.n_facets() 8 - sage: p = Polyhedron(vertices = [[1,0],[0,1],[1,1]], rays=[[1,1]], # optional - pynormaliz + sage: p = Polyhedron(vertices=[[1,0], [0,1], [1,1]], rays=[[1,1]], ....: backend='normaliz') - sage: p.n_vertices() # optional - pynormaliz + sage: p.n_vertices() 2 - sage: p = Polyhedron(vertices = [[1,0],[0,1]], rays=[[1,1]], # optional - pynormaliz + sage: p = Polyhedron(vertices=[[1,0], [0,1]], rays=[[1,1]], ....: backend='normaliz') - sage: p.n_rays() # optional - pynormaliz + sage: p.n_rays() 1 - sage: p = Polyhedron(vertices = [[0,0]], rays=[[0,1],[0,-1]], # optional - pynormaliz + sage: p = Polyhedron(vertices=[[0,0]], rays=[[0,1], [0,-1]], ....: backend='normaliz') - sage: p.n_lines() # optional - pynormaliz + sage: p.n_lines() 1 Algebraic polyhedra:: - sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], backend='normaliz', verbose=True) # optional - pynormaliz # optional - sage.rings.number_field + sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], # needs sage.rings.number_field sage.symbolic + ....: backend='normaliz', verbose=True) # ----8<---- Equivalent Normaliz input file ----8<---- amb_space 1 number_field min_poly (a^2 - 2) embedding [1.414213562373095 +/- 2.99e-16] @@ -165,16 +168,23 @@ class Polyhedron_normaliz(Polyhedron_base_number_field): (a) 1 # ----8<-------------------8<-------------------8<---- # Calling PyNormaliz.NmzCone(cone=[], number_field=['a^2 - 2', 'a', '[1.414213562373095 +/- 2.99e-16]'], subspace=[], vertices=[[1, 1], [[[0, 1], [1, 1]], 1]]) - sage: P # optional - pynormaliz # optional - sage.rings.number_field - A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - pynormaliz # optional - sage.rings.number_field + sage: P # needs sage.rings.number_field sage.symbolic + A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as + the convex hull of 2 vertices + sage: P.vertices() # needs sage.rings.number_field sage.symbolic (A vertex at (1), A vertex at (sqrt(2))) - sage: P = polytopes.icosahedron(exact=True, backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: P # optional - pynormaliz # optional - sage.rings.number_field - A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 defined as the convex hull of 12 vertices - - sage: x = polygen(ZZ); P = Polyhedron(vertices=[[sqrt(2)], [AA.polynomial_root(x^3-2, RIF(0,3))]], backend='normaliz', verbose=True) # optional - pynormaliz # optional - sage.rings.number_field + sage: P = polytopes.icosahedron(exact=True, # needs sage.rings.number_field + ....: backend='normaliz'); P + A 3-dimensional polyhedron in + (Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790?)^3 + defined as the convex hull of 12 vertices + + sage: x = polygen(ZZ) + sage: P = Polyhedron(vertices=[[sqrt(2)], # needs sage.rings.number_field sage.symbolic + ....: [AA.polynomial_root(x^3 - 2, RIF(0,3))]], + ....: backend='normaliz', verbose=True) # ----8<---- Equivalent Normaliz input file ----8<---- amb_space 1 number_field min_poly (a^6 - 2) embedding [1.122462048309373 +/- 5.38e-16] @@ -185,9 +195,10 @@ class Polyhedron_normaliz(Polyhedron_base_number_field): (a^2) 1 # ----8<-------------------8<-------------------8<---- # Calling PyNormaliz.NmzCone(cone=[], number_field=['a^6 - 2', 'a', '[1.122462048309373 +/- 5.38e-16]'], subspace=[], vertices=[[[[0, 1], [0, 1], [0, 1], [1, 1], [0, 1], [0, 1]], 1], [[[0, 1], [0, 1], [1, 1], [0, 1], [0, 1], [0, 1]], 1]]) - sage: P # optional - pynormaliz # optional - sage.rings.number_field - A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - pynormaliz # optional - sage.rings.number_field + sage: P # needs sage.rings.number_field sage.symbolic + A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as + the convex hull of 2 vertices + sage: P.vertices() # needs sage.rings.number_field sage.symbolic (A vertex at (2^(1/3)), A vertex at (sqrt(2))) """ @@ -200,14 +211,14 @@ def __init__(self, parent, Vrep, Hrep, normaliz_cone=None, normaliz_data=None, i TESTS:: - sage: p = Polyhedron(backend='normaliz') # optional - pynormaliz - sage: TestSuite(p).run() # optional - pynormaliz - sage: p = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], # optional - pynormaliz + sage: p = Polyhedron(backend='normaliz') + sage: TestSuite(p).run() + sage: p = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], ....: backend='normaliz') - sage: TestSuite(p).run() # optional - pynormaliz - sage: p = Polyhedron(vertices=[(-1,-1), (1,0), (1,1), (0,1)], # optional - pynormaliz + sage: TestSuite(p).run() + sage: p = Polyhedron(vertices=[(-1,-1), (1,0), (1,1), (0,1)], ....: backend='normaliz') - sage: TestSuite(p).run() # optional - pynormaliz + sage: TestSuite(p).run() """ if normaliz_cone: if Hrep is not None or Vrep is not None or normaliz_data is not None: @@ -230,29 +241,31 @@ def _nmz_result(self, normaliz_cone, property): TESTS:: - sage: p = Polyhedron(vertices=[(0, 0), (1, 0), (0, 1)], rays=[(1,1)], # optional - pynormaliz + sage: p = Polyhedron(vertices=[(0, 0), (1, 0), (0, 1)], rays=[(1,1)], ....: lines=[], backend='normaliz') - sage: p._nmz_result(p._normaliz_cone, 'EquivariantXyzzyModuleSeries') # optional - pynormaliz + sage: p._nmz_result(p._normaliz_cone, 'EquivariantXyzzyModuleSeries') Traceback (most recent call last): ... NormalizError: Some error in the normaliz input data detected: Unknown ConeProperty... - sage: x = polygen(QQ, 'x') # optional - sage.rings.number_field - sage: K.<a> = NumberField(x^3 - 3, embedding=AA(3)**(1/3)) # optional - sage.rings.number_field - sage: p = Polyhedron(vertices=[(0, 0), (1, 1), (a, 3), (-1, a**2)], # optional - pynormaliz # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField(x^3 - 3, embedding=AA(3)**(1/3)) + sage: p = Polyhedron(vertices=[(0, 0), (1, 1), (a, 3), (-1, a**2)], ....: rays=[(-1,-a)], backend='normaliz') - sage: sorted(p._nmz_result(p._normaliz_cone, 'VerticesOfPolyhedron')) # optional - pynormaliz # optional - sage.rings.number_field + sage: sorted(p._nmz_result(p._normaliz_cone, 'VerticesOfPolyhedron')) [[-1, a^2, 1], [1, 1, 1], [a, 3, 1]] - sage: triangulation_generators = p._nmz_result(p._normaliz_cone, 'Triangulation')[1] # optional - pynormaliz # optional - sage.rings.number_field - sage: sorted(triangulation_generators) # optional - pynormaliz # optional - sage.rings.number_field + sage: triangulation_generators = p._nmz_result(p._normaliz_cone, + ....: 'Triangulation')[1] + sage: sorted(triangulation_generators) [[-a^2, -3, 0], [-1, a^2, 1], [0, 0, 1], [1, 1, 1], [a, 3, 1]] - sage: p._nmz_result(p._normaliz_cone, 'AffineDim') == 2 # optional - pynormaliz # optional - sage.rings.number_field + sage: p._nmz_result(p._normaliz_cone, 'AffineDim') == 2 True - sage: p._nmz_result(p._normaliz_cone, 'EmbeddingDim') == 3 # optional - pynormaliz # optional - sage.rings.number_field + sage: p._nmz_result(p._normaliz_cone, 'EmbeddingDim') == 3 True - sage: p._nmz_result(p._normaliz_cone, 'ExtremeRays') # optional - pynormaliz # optional - sage.rings.number_field + sage: p._nmz_result(p._normaliz_cone, 'ExtremeRays') [[-1/3*a^2, -1, 0]] - sage: p._nmz_result(p._normaliz_cone, 'MaximalSubspace') # optional - pynormaliz # optional - sage.rings.number_field + sage: p._nmz_result(p._normaliz_cone, 'MaximalSubspace') [] """ def rational_handler(list): @@ -272,9 +285,9 @@ def _init_from_normaliz_cone(self, normaliz_cone, internal_base_ring): TESTS:: - sage: p = Polyhedron(backend='normaliz') # optional - pynormaliz - sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz # optional - pynormaliz - sage: Polyhedron_normaliz._init_from_Hrepresentation(p, [], []) # indirect doctest # optional - pynormaliz + sage: p = Polyhedron(backend='normaliz') + sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz + sage: Polyhedron_normaliz._init_from_Hrepresentation(p, [], []) # indirect doctest """ if internal_base_ring is None: internal_base_ring = QQ @@ -297,7 +310,7 @@ def _convert_to_pynormaliz(x): TESTS:: - sage: K.<sqrt2> = QuadraticField(2) # optional - sage.rings.number_field + sage: K.<sqrt2> = QuadraticField(2) # needs sage.rings.number_field sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz as Pn sage: Pn._convert_to_pynormaliz(17) 17 @@ -309,19 +322,21 @@ def _convert_to_pynormaliz(x): [[28, 5]] sage: Pn._convert_to_pynormaliz(28901824309821093821093812093810928309183091832091/5234573685674784567853456543456456786543456765) [[28901824309821093821093812093810928309183091832091, 5234573685674784567853456543456456786543456765]] - sage: Pn._convert_to_pynormaliz(7 + sqrt2) # optional - sage.rings.number_field + sage: Pn._convert_to_pynormaliz(7 + sqrt2) # needs sage.rings.number_field [[7, 1], [1, 1]] - sage: Pn._convert_to_pynormaliz(7/2 + sqrt2) # optional - sage.rings.number_field + sage: Pn._convert_to_pynormaliz(7/2 + sqrt2) # needs sage.rings.number_field [[7, 2], [1, 1]] sage: Pn._convert_to_pynormaliz([[1, 2], (3, 4)]) [[1, 2], [3, 4]] Check that :trac:`29836` is fixed:: - sage: P = polytopes.simplex(backend='normaliz') # optional - pynormaliz - sage: K.<sqrt2> = QuadraticField(2) # optional - pynormaliz # optional - sage.rings.number_field - sage: P.dilation(sqrt2) # optional - pynormaliz # optional - sage.rings.number_field - A 3-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.41...)^4 defined as the convex hull of 4 vertices + sage: P = polytopes.simplex(backend='normaliz') + sage: K.<sqrt2> = QuadraticField(2) # needs sage.rings.number_field + sage: P.dilation(sqrt2) # needs sage.rings.number_field + A 3-dimensional polyhedron in + (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.41...)^4 + defined as the convex hull of 4 vertices """ def _QQ_pair(x): x = QQ(x) @@ -345,24 +360,25 @@ def _init_from_normaliz_data(self, data, internal_base_ring=None, verbose=False) TESTS:: - sage: p = Polyhedron(backend='normaliz', ambient_dim=2) # optional - pynormaliz - sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_QQ_normaliz # optional - pynormaliz - sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} # optional - pynormaliz - sage: Polyhedron_QQ_normaliz._init_from_normaliz_data(p, data) # optional - pynormaliz - sage: p.inequalities_list() # optional - pynormaliz + sage: p = Polyhedron(backend='normaliz', ambient_dim=2) + sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_QQ_normaliz + sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} + sage: Polyhedron_QQ_normaliz._init_from_normaliz_data(p, data) + sage: p.inequalities_list() [[0, -1, 2], [0, 2, -1]] - sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz # optional - pynormaliz - sage: from sage.rings.qqbar import AA # optional - pynormaliz # optional - sage.rings.number_field - sage: from sage.rings.number_field.number_field import QuadraticField # optional - pynormaliz # optional - sage.rings.number_field - sage: data = {'number_field': ['a^2 - 2', 'a', '[1.4 +/- 0.1]'], # optional - pynormaliz + sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz + sage: from sage.rings.qqbar import AA # needs sage.rings.number_field + sage: from sage.rings.number_field.number_field import QuadraticField # needs sage.rings.number_field + sage: data = {'number_field': ['a^2 - 2', 'a', '[1.4 +/- 0.1]'], ....: 'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} - sage: from sage.geometry.polyhedron.parent import Polyhedra_normaliz # optional - pynormaliz - sage: parent = Polyhedra_normaliz(AA, 2, 'normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: Polyhedron_normaliz(parent, None, None, normaliz_data=data, # indirect doctest, optional - pynormaliz # optional - sage.rings.number_field + sage: from sage.geometry.polyhedron.parent import Polyhedra_normaliz + sage: parent = Polyhedra_normaliz(AA, 2, 'normaliz') # needs sage.rings.number_field + sage: Polyhedron_normaliz(parent, None, None, # needs sage.rings.number_field + ....: normaliz_data=data, ....: internal_base_ring=QuadraticField(2)) A 2-dimensional polyhedron in AA^2 defined as the convex hull of 1 vertex and 2 rays - sage: _.inequalities_list() # optional - pynormaliz # optional - sage.rings.number_field + sage: _.inequalities_list() # needs sage.rings.number_field [[0, -1/2, 1], [0, 2, -1]] """ if internal_base_ring is None: @@ -376,11 +392,11 @@ def _cone_from_normaliz_data(self, data, verbose=False): EXAMPLES:: - sage: p = Polyhedron(backend='normaliz', ambient_dim=2) # optional - pynormaliz - sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_QQ_normaliz # optional - pynormaliz - sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} # optional - pynormaliz - sage: cone = Polyhedron_QQ_normaliz._cone_from_normaliz_data(p, data) # optional - pynormaliz - sage: p._nmz_result(cone,'SupportHyperplanes') # optional - pynormaliz + sage: p = Polyhedron(backend='normaliz', ambient_dim=2) + sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_QQ_normaliz + sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} + sage: cone = Polyhedron_QQ_normaliz._cone_from_normaliz_data(p, data) + sage: p._nmz_result(cone,'SupportHyperplanes') [[-1, 2, 0], [0, 0, 1], [2, -1, 0]] """ if verbose: @@ -417,10 +433,10 @@ def _is_zero(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field - sage: p._is_zero(0) # optional - sage.rings.number_field + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_zero(0) # needs sage.rings.number_field sage.symbolic True - sage: p._is_zero(1/100000) # optional - sage.rings.number_field + sage: p._is_zero(1/100000) # needs sage.rings.number_field sage.symbolic False """ return x == 0 @@ -439,10 +455,10 @@ def _is_nonneg(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field - sage: p._is_nonneg(1) # optional - sage.rings.number_field + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_nonneg(1) # needs sage.rings.number_field sage.symbolic True - sage: p._is_nonneg(-1/100000) # optional - sage.rings.number_field + sage: p._is_nonneg(-1/100000) # needs sage.rings.number_field sage.symbolic False """ return x >= 0 @@ -461,10 +477,10 @@ def _is_positive(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field - sage: p._is_positive(1) # optional - sage.rings.number_field + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: p._is_positive(1) # needs sage.rings.number_field sage.symbolic True - sage: p._is_positive(0) # optional - sage.rings.number_field + sage: p._is_positive(0) # needs sage.rings.number_field sage.symbolic False """ return x > 0 @@ -492,9 +508,9 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbo EXAMPLES:: - sage: p = Polyhedron(backend='normaliz') # optional - pynormaliz - sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz # optional - pynormaliz - sage: Polyhedron_normaliz._init_from_Vrepresentation(p, [], [], []) # optional - pynormaliz + sage: p = Polyhedron(backend='normaliz') + sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz + sage: Polyhedron_normaliz._init_from_Vrepresentation(p, [], [], []) """ def vert_ray_line_QQ(vertices, rays, lines): @@ -565,27 +581,31 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): EXAMPLES:: - sage: p = Polyhedron(backend='normaliz') # optional - pynormaliz - sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz # optional - pynormaliz - sage: Polyhedron_normaliz._init_from_Hrepresentation(p, [], []) # optional - pynormaliz + sage: p = Polyhedron(backend='normaliz') + sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz + sage: Polyhedron_normaliz._init_from_Hrepresentation(p, [], []) TESTS:: - sage: K.<a> = QuadraticField(2) # optional - sage.rings.number_field - sage: p = Polyhedron(ieqs=[(1, a, 0)], backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: p & p == p # optional - pynormaliz # optional - sage.rings.number_field + sage: K.<a> = QuadraticField(2) # needs sage.rings.number_field + sage: p = Polyhedron(ieqs=[(1, a, 0)], backend='normaliz') # needs sage.rings.number_field + sage: p & p == p # needs sage.rings.number_field True Check that :trac:`30248` is fixed, that maps as input works:: - sage: q = Polyhedron(backend='normaliz', base_ring=AA, # optional - pynormaliz # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: q = Polyhedron(backend='normaliz', base_ring=AA, ....: rays=[(0, 0, 1), (0, 1, -1), (1, 0, -1)]) - sage: make_new_Hrep = lambda h: tuple(x if i == 0 else -1*x for i, x in enumerate(h._vector)) - sage: new_inequalities = map(make_new_Hrep, q.inequality_generator()) # optional - pynormaliz # optional - sage.rings.number_field - sage: new_equations = map(make_new_Hrep, q.equation_generator()) # optional - pynormaliz # optional - sage.rings.number_field - sage: parent = q.parent() # optional - pynormaliz # optional - sage.rings.number_field - sage: new_q = parent.element_class(parent,None,[new_inequalities,new_equations]) # optional - pynormaliz # optional - sage.rings.number_field - sage: new_q # optional - pynormaliz # optional - sage.rings.number_field + sage: def make_new_Hrep(h): + ....: return tuple(x if i == 0 else -1*x + ....: for i, x in enumerate(h._vector)) + sage: new_inequalities = map(make_new_Hrep, q.inequality_generator()) + sage: new_equations = map(make_new_Hrep, q.equation_generator()) + sage: parent = q.parent() + sage: new_q = parent.element_class(parent, None, + ....: [new_inequalities, new_equations]) + sage: new_q A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays """ @@ -669,28 +689,29 @@ def _cone_from_Vrepresentation_and_Hrepresentation(self, vertices, rays, lines, EXAMPLES:: - sage: P = polytopes.hypercube(4,backend='normaliz') * Polyhedron(rays=[[0,1]]) * Polyhedron(lines=[[1,0]]) # optional - pynormaliz - sage: P # optional - pynormaliz + sage: P = (polytopes.hypercube(4, backend='normaliz') + ....: * Polyhedron(rays=[[0,1]]) + ....: * Polyhedron(lines=[[1,0]])); P A 6-dimensional polyhedron in ZZ^8 defined as the convex hull of 16 vertices, 1 ray, 1 line - sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation( # optional - pynormaliz + sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation( ....: P.vertices(), P.rays(), P.lines(), ....: P.inequalities(), P.equations()) - sage: import PyNormaliz # optional - pynormaliz - sage: PyNormaliz.NmzIsComputed(cone, "VerticesOfPolyhedron") # optional - pynormaliz + sage: import PyNormaliz + sage: PyNormaliz.NmzIsComputed(cone, "VerticesOfPolyhedron") True - sage: PyNormaliz.NmzIsComputed(cone, "ExtremeRays") # optional - pynormaliz + sage: PyNormaliz.NmzIsComputed(cone, "ExtremeRays") True - sage: PyNormaliz.NmzIsComputed(cone, "MaximalSubspace") # optional - pynormaliz + sage: PyNormaliz.NmzIsComputed(cone, "MaximalSubspace") True - sage: PyNormaliz.NmzIsComputed(cone, "SupportHyperplanes") # optional - pynormaliz + sage: PyNormaliz.NmzIsComputed(cone, "SupportHyperplanes") True - sage: PyNormaliz.NmzIsComputed(cone, "Equations") # optional - pynormaliz + sage: PyNormaliz.NmzIsComputed(cone, "Equations") False All values must be specified:: - sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation( # optional - pynormaliz + sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation( ....: P.vertices(), None, P.lines(), ....: P.inequalities(), P.equations()) Traceback (most recent call last): @@ -699,8 +720,8 @@ def _cone_from_Vrepresentation_and_Hrepresentation(self, vertices, rays, lines, This method cannot be used for the empty cone:: - sage: P = Polyhedron(backend='normaliz') # optional - pynormaliz - sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation( # optional - pynormaliz + sage: P = Polyhedron(backend='normaliz') + sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation( ....: P.vertices(), P.rays(), P.lines(), ....: P.inequalities(), P.equations()) Traceback (most recent call last): @@ -713,32 +734,39 @@ def _cone_from_Vrepresentation_and_Hrepresentation(self, vertices, rays, lines, ....: cone = P._cone_from_Vrepresentation_and_Hrepresentation(P.vertices(),P.rays(),P.lines(),P.inequalities(),P.equations()) ....: cone2 = P._normaliz_cone ....: args = ['Equations','VerticesOfPolyhedron','ExtremeRays','SupportHyperplanes','MaximalSubspace'] - ....: return all(P._nmz_result(cone,arg) == P._nmz_result(cone2,arg) for arg in args) - sage: test_poly(polytopes.simplex(backend='normaliz')) # optional - pynormaliz + ....: return all(P._nmz_result(cone,arg) == P._nmz_result(cone2, arg) + ....: for arg in args) + sage: test_poly(polytopes.simplex(backend='normaliz')) True - sage: test_poly(polytopes.dodecahedron(backend='normaliz')) # optional - pynormaliz # optional - sage.rings.number_field + sage: test_poly(polytopes.dodecahedron(backend='normaliz')) # needs sage.rings.number_field True - sage: test_poly(Polyhedron(vertices=[[1,0],[0,1]],rays=[[1,1]], backend='normaliz')) # optional - pynormaliz + sage: test_poly(Polyhedron(vertices=[[1,0], [0,1]], rays=[[1,1]], + ....: backend='normaliz')) True - sage: test_poly(Polyhedron(vertices=[[-1,0],[1,0]],lines=[[0,1]], backend='normaliz')) # optional - pynormaliz + sage: test_poly(Polyhedron(vertices=[[-1,0], [1,0]], lines=[[0,1]], + ....: backend='normaliz')) True - sage: test_poly(Polyhedron(rays=[[1,0,0],[0,1,0]], backend='normaliz')) # optional - pynormaliz + sage: test_poly(Polyhedron(rays=[[1,0,0],[0,1,0]], + ....: backend='normaliz')) True - sage: test_poly(Polyhedron(vertices=[[1,0,0],[0,1,0]], rays=[[1,0,0],[0,1,0]], backend='normaliz')) # optional - pynormaliz + sage: test_poly(Polyhedron(vertices=[[1,0,0], [0,1,0]], rays=[[1,0,0], [0,1,0]], + ....: backend='normaliz')) True - sage: test_poly(Polyhedron(vertices=[[0,0,0],[0,1,1],[1,0,1],[-1,-1,1]],rays=[[0,0,1]], backend='normaliz')) # optional - pynormaliz + sage: test_poly(Polyhedron(vertices=[[0,0,0], [0,1,1], [1,0,1], [-1,-1,1]], + ....: rays=[[0,0,1]], + ....: backend='normaliz')) True Old input format will give a meaningful error message:: - sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation( # optional - pynormaliz + sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation( ....: P.vertices(), P.rays(), ....: P.inequalities(), P.equations()) Traceback (most recent call last): ... ValueError: the specification of this method has changed; please specify the lines as well - sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation( # optional - pynormaliz + sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation( ....: P.vertices(), P.rays(), ....: P.inequalities(), P.equations(), True) Traceback (most recent call last): @@ -747,11 +775,12 @@ def _cone_from_Vrepresentation_and_Hrepresentation(self, vertices, rays, lines, Check that :trac:`30891` is fixed:: - sage: p = Polyhedron(vertices=[(-3,-3), (3,0), (3,3), (0,3)], backend='normaliz') # optional - pynormaliz - sage: q = loads(p.dumps()) # optional - pynormaliz - sage: q.volume() # optional - pynormaliz + sage: p = Polyhedron(vertices=[(-3,-3), (3,0), (3,3), (0,3)], + ....: backend='normaliz') + sage: q = loads(p.dumps()) + sage: q.volume() 18 - sage: q.ehrhart_series() # optional - pynormaliz + sage: q.ehrhart_series() (13*t^2 + 22*t + 1)/(-t^3 + 3*t^2 - 3*t + 1) """ if eqns in (True, False, None): @@ -856,21 +885,21 @@ def _test_far_facet_condition(self, tester=None, **options): TESTS:: - sage: P = Polyhedron(rays=[[1,1]], backend='normaliz') # optional - pynormaliz - sage: P._test_far_facet_condition() # optional - pynormaliz + sage: P = Polyhedron(rays=[[1,1]], backend='normaliz') + sage: P._test_far_facet_condition() - sage: P = Polyhedron(vertices=[[1,0], [0,1]], # optional - pynormaliz + sage: P = Polyhedron(vertices=[[1,0], [0,1]], ....: rays=[[1,1]], backend='normaliz') - sage: P._test_far_facet_condition() # optional - pynormaliz + sage: P._test_far_facet_condition() - sage: P = Polyhedron(rays=[[1,1,0]], # optional - pynormaliz + sage: P = Polyhedron(rays=[[1,1,0]], ....: lines=[[0,0,1]], backend='normaliz') - sage: P._test_far_facet_condition() # optional - pynormaliz + sage: P._test_far_facet_condition() - sage: P = Polyhedron(vertices=[[1,0,0], [0,1,0]], # optional - pynormaliz + sage: P = Polyhedron(vertices=[[1,0,0], [0,1,0]], ....: rays=[[1,1,0]], ....: lines=[[0,0,1]], backend='normaliz') - sage: P._test_far_facet_condition() # optional - pynormaliz + sage: P._test_far_facet_condition() """ if tester is None: tester = self._tester(**options) @@ -897,13 +926,13 @@ def _init_Vrepresentation_from_normaliz(self): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], # indirect doctest # optional - pynormaliz + sage: p = Polyhedron(vertices=[(0,1/2), (2,0), (4,5/6)], # indirect doctest ....: backend='normaliz') - sage: p.Hrepresentation() # optional - pynormaliz + sage: p.Hrepresentation() (An inequality (-5, 12) x + 10 >= 0, An inequality (1, -12) x + 6 >= 0, An inequality (1, 4) x - 2 >= 0) - sage: p.Vrepresentation() # optional - pynormaliz + sage: p.Vrepresentation() (A vertex at (0, 1/2), A vertex at (2, 0), A vertex at (4, 5/6)) """ self._Vrepresentation = [] @@ -928,13 +957,13 @@ def _init_Hrepresentation_from_normaliz(self): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/2), (2,0), (4,5/6)], # indirect doctest # optional - pynormaliz + sage: p = Polyhedron(vertices=[(0,1/2), (2,0), (4,5/6)], # indirect doctest ....: backend='normaliz') - sage: p.Hrepresentation() # optional - pynormaliz + sage: p.Hrepresentation() (An inequality (-5, 12) x + 10 >= 0, An inequality (1, -12) x + 6 >= 0, An inequality (1, 4) x - 2 >= 0) - sage: p.Vrepresentation() # optional - pynormaliz + sage: p.Vrepresentation() (A vertex at (0, 1/2), A vertex at (2, 0), A vertex at (4, 5/6)) """ self._Hrepresentation = [] @@ -956,15 +985,15 @@ def _init_empty_polyhedron(self): TESTS:: - sage: empty = Polyhedron(backend='normaliz'); empty # optional - pynormaliz + sage: empty = Polyhedron(backend='normaliz'); empty The empty polyhedron in ZZ^0 - sage: empty.Vrepresentation() # optional - pynormaliz + sage: empty.Vrepresentation() () - sage: empty.Hrepresentation() # optional - pynormaliz + sage: empty.Hrepresentation() (An equation -1 == 0,) - sage: Polyhedron(vertices = [], backend='normaliz') # optional - pynormaliz + sage: Polyhedron(vertices=[], backend='normaliz') The empty polyhedron in ZZ^0 - sage: Polyhedron(backend='normaliz')._init_empty_polyhedron() # optional - pynormaliz + sage: Polyhedron(backend='normaliz')._init_empty_polyhedron() """ super()._init_empty_polyhedron() # Can't seem to set up an empty _normaliz_cone. @@ -979,9 +1008,9 @@ def _from_normaliz_cone(cls, parent, normaliz_cone, internal_base_ring=None): TESTS:: - sage: P=Polyhedron(ieqs=[[1, 0, 2], [3, 0, -2], [3, 2, -2]], # optional - pynormaliz + sage: P=Polyhedron(ieqs=[[1, 0, 2], [3, 0, -2], [3, 2, -2]], ....: backend='normaliz') - sage: PI = P.integral_hull() # indirect doctest; optional - pynormaliz + sage: PI = P.integral_hull() # indirect doctest """ return cls(parent, None, None, normaliz_cone=normaliz_cone, internal_base_ring=internal_base_ring) @@ -995,7 +1024,7 @@ def _number_field_triple(internal_base_ring): sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz as Pn sage: Pn._number_field_triple(QQ) is None True - sage: Pn._number_field_triple(QuadraticField(5)) # optional - sage.rings.number_field + sage: Pn._number_field_triple(QuadraticField(5)) # needs sage.rings.number_field ['a^2 - 5', 'a', '[2.236067977499789 +/- 8.06e-16]'] """ R = internal_base_ring @@ -1022,11 +1051,11 @@ def _make_normaliz_cone(data, verbose=False): TESTS:: - sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz # optional - pynormaliz - sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} # optional - pynormaliz - sage: nmz_cone = Polyhedron_normaliz._make_normaliz_cone(data,verbose=False) # optional - pynormaliz - sage: from PyNormaliz import NmzResult # optional - pynormaliz - sage: NmzResult(nmz_cone, "ExtremeRays") # optional - pynormaliz + sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz + sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} + sage: nmz_cone = Polyhedron_normaliz._make_normaliz_cone(data,verbose=False) + sage: from PyNormaliz import NmzResult + sage: NmzResult(nmz_cone, "ExtremeRays") [[1, 2, 0], [2, 1, 0]] """ if verbose: @@ -1047,14 +1076,14 @@ def _get_nmzcone_data(self): The empty polyhedron:: - sage: P = Polyhedron(backend='normaliz') # optional - pynormaliz - sage: P._get_nmzcone_data() # optional - pynormaliz + sage: P = Polyhedron(backend='normaliz') + sage: P._get_nmzcone_data() {} Another simple example:: - sage: C = Polyhedron(backend='normaliz', rays=[[1, 2], [2, 1]]) # optional - pynormaliz - sage: C._get_nmzcone_data() # optional - pynormaliz + sage: C = Polyhedron(backend='normaliz', rays=[[1, 2], [2, 1]]) + sage: C._get_nmzcone_data() {'cone': [[1, 2], [2, 1]], 'inhom_equations': [], 'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]], @@ -1093,7 +1122,7 @@ def _normaliz_format(self, data, file_output=None): EXAMPLES:: - sage: P = Polyhedron(vertices=[[0, 0], [0, 1], [1, 0]], # indirect doctest; optional - pynormaliz + sage: P = Polyhedron(vertices=[[0, 0], [0, 1], [1, 0]], # indirect doctest ....: backend='normaliz', verbose=True) # ----8<---- Equivalent Normaliz input file ----8<---- amb_space 2 @@ -1148,9 +1177,9 @@ def __copy__(self): TESTS:: - sage: P = polytopes.cube(backend='normaliz') # optional - pynormaliz - sage: Q = copy(P) # optional - pynormaliz - sage: P._normaliz_cone is Q._normaliz_cone # optional - pynormaliz + sage: P = polytopes.cube(backend='normaliz') + sage: Q = copy(P) + sage: P._normaliz_cone is Q._normaliz_cone False """ other = super().__copy__() @@ -1167,8 +1196,8 @@ def __getstate__(self): TESTS:: - sage: P = polytopes.simplex(backend='normaliz') # optional - pynormaliz - sage: P.__getstate__() # optional - pynormaliz + sage: P = polytopes.simplex(backend='normaliz') + sage: P.__getstate__() (Polyhedra in ZZ^4, {'_Hrepresentation': (An inequality (0, 0, 0, 1) x + 0 >= 0, An inequality (0, 0, 1, 0) x + 0 >= 0, @@ -1209,52 +1238,54 @@ def __setstate__(self, state): TESTS:: - sage: P = polytopes.permutahedron(4, backend='normaliz') # optional - pynormaliz - sage: P.volume(measure='induced_lattice', engine='normaliz') # optional - pynormaliz + sage: P = polytopes.permutahedron(4, backend='normaliz') + sage: P.volume(measure='induced_lattice', engine='normaliz') 96 - sage: P.volume.clear_cache() # optional - pynormaliz - sage: P1 = loads(dumps(P)) # indirect doctest # optional - pynormaliz - sage: P1.volume(measure='induced_lattice', engine='normaliz') # optional - pynormaliz + sage: P.volume.clear_cache() + sage: P1 = loads(dumps(P)) # indirect doctest + sage: P1.volume(measure='induced_lattice', engine='normaliz') 96 Test that the obtained cone is valid:: - sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz # optional - pynormaliz - sage: P = polytopes.permutahedron(4, backend='normaliz') # optional - pynormaliz - sage: P1 = loads(dumps(P)) # optional - pynormaliz - sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone) # optional - pynormaliz - sage: P2 == P # optional - pynormaliz + sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz + sage: P = polytopes.permutahedron(4, backend='normaliz') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone) + sage: P2 == P True - sage: P = Polyhedron(lines=[[1,0], [0,1]], backend='normaliz') # optional - pynormaliz - sage: P1 = loads(dumps(P)) # optional - pynormaliz - sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone) # optional - pynormaliz - sage: P2 == P # optional - pynormaliz + sage: P = Polyhedron(lines=[[1,0], [0,1]], backend='normaliz') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone) + sage: P2 == P True - sage: P = Polyhedron(backend='normaliz') # optional - pynormaliz - sage: P1 = loads(dumps(P)) # optional - pynormaliz - sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone) # optional - pynormaliz - sage: P2 == P # optional - pynormaliz + sage: P = Polyhedron(backend='normaliz') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone) + sage: P2 == P True - sage: P = polytopes.permutahedron(4, backend='normaliz') * Polyhedron(lines=[[1]], backend='normaliz') # optional - pynormaliz - sage: P1 = loads(dumps(P)) # optional - pynormaliz - sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone) # optional - pynormaliz - sage: P2 == P # optional - pynormaliz + sage: P = polytopes.permutahedron(4, backend='normaliz') * Polyhedron(lines=[[1]], backend='normaliz') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone) + sage: P2 == P True - sage: P = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: P1 = loads(dumps(P)) # optional - pynormaliz # optional - sage.rings.number_field - sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone, internal_base_ring=P1._internal_base_ring) # optional - pynormaliz # optional - sage.rings.number_field - sage: P == P2 # optional - pynormaliz # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron(backend='normaliz') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone, + ....: internal_base_ring=P1._internal_base_ring) + sage: P == P2 True Test that :trac:`31820` is fixed:: - sage: P = polytopes.cube(backend='normaliz') # optional - pynormaliz - sage: v = P.Vrepresentation()[0] # optional - pynormaliz - sage: v1 = loads(v.dumps()) # optional - pynormaliz + sage: P = polytopes.cube(backend='normaliz') + sage: v = P.Vrepresentation()[0] + sage: v1 = loads(v.dumps()) """ if "_pickle_vertices" in state[1]: vertices = state[1].pop("_pickle_vertices") @@ -1294,29 +1325,31 @@ def integral_hull(self): Unbounded example from Normaliz manual, "a dull polyhedron":: - sage: P = Polyhedron(ieqs=[[1, 0, 2], [3, 0, -2], [3, 2, -2]], # optional - pynormaliz - ....: backend='normaliz') - sage: PI = P.integral_hull() # optional - pynormaliz - sage: P.plot(color='yellow') + PI.plot(color='green') # optional - pynormaliz # optional - sage.plot + sage: P = Polyhedron(ieqs=[[1, 0, 2], [3, 0, -2], [3, 2, -2]], + ....: backend='normaliz') + sage: PI = P.integral_hull() + sage: P.plot(color='yellow') + PI.plot(color='green') # needs sage.plot Graphics object consisting of 10 graphics primitives - sage: PI.Vrepresentation() # optional - pynormaliz - (A vertex at (-1, 0), A vertex at (0, 1), A ray in the direction (1, 0)) + sage: PI.Vrepresentation() + (A vertex at (-1, 0), + A vertex at (0, 1), + A ray in the direction (1, 0)) Nonpointed case:: - sage: P = Polyhedron(vertices=[[1/2, 1/3]], rays=[[1, 1]], # optional - pynormaliz - ....: lines=[[-1, 1]], backend='normaliz') - sage: PI = P.integral_hull() # optional - pynormaliz - sage: PI.Vrepresentation() # optional - pynormaliz + sage: P = Polyhedron(vertices=[[1/2, 1/3]], rays=[[1, 1]], + ....: lines=[[-1, 1]], backend='normaliz') + sage: PI = P.integral_hull() + sage: PI.Vrepresentation() (A vertex at (1, 0), A ray in the direction (1, 0), A line in the direction (1, -1)) Empty polyhedron:: - sage: P = Polyhedron(backend='normaliz') # optional - pynormaliz - sage: PI = P.integral_hull() # optional - pynormaliz - sage: PI.Vrepresentation() # optional - pynormaliz + sage: P = Polyhedron(backend='normaliz') + sage: PI = P.integral_hull() + sage: PI.Vrepresentation() () """ if self.is_empty(): @@ -1341,14 +1374,14 @@ def _h_star_vector_normaliz(self): The `h^*`-vector of a unimodular simplex is 1:: - sage: s3 = polytopes.simplex(3,backend='normaliz') # optional - pynormaliz - sage: s3._h_star_vector_normaliz() # optional - pynormaliz + sage: s3 = polytopes.simplex(3, backend='normaliz') + sage: s3._h_star_vector_normaliz() [1] The `h^*`-vector of the `0/1`-cube is [1,4,1]:: - sage: cube = polytopes.cube(intervals='zero_one', backend='normaliz') # optional - pynormaliz - sage: cube.h_star_vector() # optional - pynormaliz + sage: cube = polytopes.cube(intervals='zero_one', backend='normaliz') + sage: cube.h_star_vector() [1, 4, 1] TESTS: @@ -1356,9 +1389,9 @@ def _h_star_vector_normaliz(self): Check that :trac:`33847` is fixed:: sage: L = [[1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0], [1, 0, 1, 0, 0, 0], - ....: [1, 0, 0, 1, 0, 0], [1, 0, 0, 0, 1, 0], [1, 0, 0, 1, 2, 3]] - sage: P = Polyhedron(vertices=L,backend='normaliz') # optional - pynormaliz - sage: P.h_star_vector() # optional - pynormaliz + ....: [1, 0, 0, 1, 0, 0], [1, 0, 0, 0, 1, 0], [1, 0, 0, 1, 2, 3]] + sage: P = Polyhedron(vertices=L, backend='normaliz') + sage: P.h_star_vector() [1, 0, 2] """ return self.ehrhart_series().numerator().list() @@ -1395,57 +1428,57 @@ def _volume_normaliz(self, measure='euclidean'): For normaliz, the default is the euclidean volume in the ambient space and the result is a float:: - sage: s = polytopes.simplex(3,backend='normaliz') # optional - pynormaliz - sage: s._volume_normaliz() # optional - pynormaliz + sage: s = polytopes.simplex(3, backend='normaliz') + sage: s._volume_normaliz() 0.3333333333333333 One other possibility is to compute the scaled volume where a unimodular simplex has volume 1:: - sage: s._volume_normaliz(measure='induced_lattice') # optional - pynormaliz + sage: s._volume_normaliz(measure='induced_lattice') 1 sage: v = [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]] - sage: cube = Polyhedron(vertices=v,backend='normaliz') # optional - pynormaliz - sage: cube._volume_normaliz() # optional - pynormaliz + sage: cube = Polyhedron(vertices=v, backend='normaliz') + sage: cube._volume_normaliz() 1.0 - sage: cube._volume_normaliz(measure='induced_lattice') # optional - pynormaliz + sage: cube._volume_normaliz(measure='induced_lattice') 6 Or one can calculate the ambient volume, which is the above multiplied by the volume of the unimodular simplex (or zero if not full-dimensional):: - sage: cube._volume_normaliz(measure='ambient') # optional - pynormaliz + sage: cube._volume_normaliz(measure='ambient') 1 - sage: s._volume_normaliz(measure='ambient') # optional - pynormaliz + sage: s._volume_normaliz(measure='ambient') 0 TESTS: Check that :trac:`28872` is fixed:: - sage: P = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: P.volume(measure='induced_lattice') # optional - pynormaliz # optional - sage.rings.number_field + sage: P = polytopes.dodecahedron(backend='normaliz') # needs sage.rings.number_field + sage: P.volume(measure='induced_lattice') # needs sage.rings.number_field -1056*sqrt5 + 2400 Some sanity checks that the ambient volume works correctly:: - sage: (2*cube)._volume_normaliz(measure='ambient') # optional - pynormaliz + sage: (2*cube)._volume_normaliz(measure='ambient') 8 - sage: (1/2*cube)._volume_normaliz(measure='ambient') # optional - pynormaliz + sage: (1/2*cube)._volume_normaliz(measure='ambient') 1/8 - sage: s._volume_normaliz(measure='ambient') # optional - pynormaliz + sage: s._volume_normaliz(measure='ambient') 0 - sage: P = polytopes.regular_polygon(3, backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: P._volume_normaliz('ambient') == P.volume(engine='internal') # optional - pynormaliz # optional - sage.rings.number_field + sage: P = polytopes.regular_polygon(3, backend='normaliz') # needs sage.rings.number_field + sage: P._volume_normaliz('ambient') == P.volume(engine='internal') # needs sage.rings.number_field True - sage: P = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: P._volume_normaliz('ambient') == P.volume(engine='internal') # optional - pynormaliz # optional - sage.rings.number_field + sage: P = polytopes.dodecahedron(backend='normaliz') # needs sage.rings.number_field + sage: P._volume_normaliz('ambient') == P.volume(engine='internal') # needs sage.rings.number_field True - sage: P = Polyhedron(rays=[[1]], backend='normaliz') # optional - pynormaliz - sage: P.volume() # optional - pynormaliz + sage: P = Polyhedron(rays=[[1]], backend='normaliz') + sage: P.volume() +Infinity """ cone = self._normaliz_cone @@ -1489,26 +1522,26 @@ def _triangulate_normaliz(self): EXAMPLES:: - sage: P = Polyhedron(vertices=[[0,0,1],[1,0,1],[0,1,1],[1,1,1]],backend='normaliz') # optional - pynormaliz - sage: P._triangulate_normaliz() # optional - pynormaliz + sage: P = Polyhedron(vertices=[[0,0,1], [1,0,1], [0,1,1], [1,1,1]], backend='normaliz') + sage: P._triangulate_normaliz() [(0, 1, 2), (1, 2, 3)] - sage: C1 = Polyhedron(rays=[[0,0,1],[1,0,1],[0,1,1],[1,1,1]],backend='normaliz') # optional - pynormaliz - sage: C1._triangulate_normaliz() # optional - pynormaliz + sage: C1 = Polyhedron(rays=[[0,0,1], [1,0,1], [0,1,1], [1,1,1]], backend='normaliz') + sage: C1._triangulate_normaliz() [(0, 1, 2), (1, 2, 3)] - sage: C2 = Polyhedron(rays=[[1,0,1],[0,0,1],[0,1,1],[1,1,10/9]],backend='normaliz') # optional - pynormaliz - sage: C2._triangulate_normaliz() # optional - pynormaliz + sage: C2 = Polyhedron(rays=[[1,0,1], [0,0,1], [0,1,1], [1,1,10/9]], backend='normaliz') + sage: C2._triangulate_normaliz() [(0, 1, 2), (1, 2, 3)] Works only for cones and compact polyhedra:: - sage: P = polytopes.cube(backend='normaliz') # optional - pynormaliz - sage: Q = Polyhedron(rays=[[0,1]], backend='normaliz') # optional - pynormaliz - sage: R = Polyhedron(lines=[[0,1]], backend='normaliz') # optional - pynormaliz - sage: (P*Q)._triangulate_normaliz() # optional - pynormaliz + sage: P = polytopes.cube(backend='normaliz') + sage: Q = Polyhedron(rays=[[0,1]], backend='normaliz') + sage: R = Polyhedron(lines=[[0,1]], backend='normaliz') + sage: (P*Q)._triangulate_normaliz() Traceback (most recent call last): ... NotImplementedError: triangulation of non-compact polyhedra that are not cones is not supported - sage: (P*R)._triangulate_normaliz() # optional - pynormaliz + sage: (P*R)._triangulate_normaliz() Traceback (most recent call last): ... NotImplementedError: triangulation of non-compact not pointed polyhedron is not supported @@ -1517,8 +1550,8 @@ def _triangulate_normaliz(self): Check that :trac:`30531` is fixed:: - sage: P = polytopes.cube(backend='normaliz')*AA(2).sqrt() # optional - pynormaliz - sage: P._triangulate_normaliz() # optional - pynormaliz + sage: P = polytopes.cube(backend='normaliz')*AA(2).sqrt() + sage: P._triangulate_normaliz() [(0, 1, 2, 4), (1, 2, 4, 3), (1, 3, 4, 5), @@ -1528,8 +1561,9 @@ def _triangulate_normaliz(self): :: - sage: C1 = Polyhedron(rays=[[0,0,1],[1,0,AA(2).sqrt()],[0,1,1],[1,1,1]], backend='normaliz') # optional - pynormaliz - sage: C1._triangulate_normaliz() # optional - pynormaliz + sage: C1 = Polyhedron(rays=[[0,0,1], [1,0,AA(2).sqrt()], [0,1,1], [1,1,1]], + ....: backend='normaliz') + sage: C1._triangulate_normaliz() [(0, 1, 3), (0, 3, 2)] """ if self.lines(): @@ -1605,10 +1639,10 @@ class Polyhedron_QQ_normaliz(Polyhedron_normaliz, Polyhedron_QQ): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], # optional - pynormaliz + sage: p = Polyhedron(vertices=[(0,0), (1,0), (0,1)], ....: rays=[(1,1)], lines=[], ....: backend='normaliz', base_ring=QQ) - sage: TestSuite(p).run() # optional - pynormaliz + sage: TestSuite(p).run() """ @cached_method(do_pickle=True) @@ -1630,34 +1664,37 @@ def ehrhart_series(self, variable='t'): EXAMPLES:: - sage: S = Polyhedron(vertices=[[0,1],[1,0]], backend='normaliz') # optional - pynormaliz - sage: ES = S.ehrhart_series() # optional - pynormaliz - sage: ES.numerator() # optional - pynormaliz + sage: S = Polyhedron(vertices=[[0,1], [1,0]], backend='normaliz') + sage: ES = S.ehrhart_series() + sage: ES.numerator() 1 - sage: ES.denominator().factor() # optional - pynormaliz + sage: ES.denominator().factor() (t - 1)^2 - sage: C = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]],backend='normaliz') # optional - pynormaliz - sage: ES = C.ehrhart_series() # optional - pynormaliz - sage: ES.numerator() # optional - pynormaliz + sage: C = Polyhedron(vertices=[[0,0,0], [0,0,1], [0,1,0], [0,1,1], + ....: [1,0,0], [1,0,1], [1,1,0], [1,1,1]], + ....: backend='normaliz') + sage: ES = C.ehrhart_series() + sage: ES.numerator() t^2 + 4*t + 1 - sage: ES.denominator().factor() # optional - pynormaliz + sage: ES.denominator().factor() (t - 1)^4 The following example is from the Normaliz manual contained in the file ``rational.in``:: - sage: rat_poly = Polyhedron(vertices=[[1/2,1/2],[-1/3,-1/3],[1/4,-1/2]],backend='normaliz') # optional - pynormaliz - sage: ES = rat_poly.ehrhart_series() # optional - pynormaliz - sage: ES.numerator() # optional - pynormaliz + sage: rat_poly = Polyhedron(vertices=[[1/2,1/2], [-1/3,-1/3], [1/4,-1/2]], + ....: backend='normaliz') + sage: ES = rat_poly.ehrhart_series() + sage: ES.numerator() 2*t^6 + 3*t^5 + 4*t^4 + 3*t^3 + t^2 + t + 1 - sage: ES.denominator().factor() # optional - pynormaliz + sage: ES.denominator().factor() (-1) * (t + 1)^2 * (t - 1)^3 * (t^2 + 1) * (t^2 + t + 1) The polyhedron should be compact:: - sage: C = Polyhedron(backend='normaliz',rays=[[1,2],[2,1]]) # optional - pynormaliz - sage: C.ehrhart_series() # optional - pynormaliz + sage: C = Polyhedron(rays=[[1,2], [2,1]], backend='normaliz') + sage: C.ehrhart_series() Traceback (most recent call last): ... NotImplementedError: Ehrhart series can only be computed for compact polyhedron @@ -1670,8 +1707,8 @@ def ehrhart_series(self, variable='t'): Check that the Ehrhart series is pickled:: - sage: new_poly = loads(dumps(rat_poly)) # optional - pynormaliz - sage: new_poly.ehrhart_series.is_in_cache() # optional - pynormaliz + sage: new_poly = loads(dumps(rat_poly)) + sage: new_poly.ehrhart_series.is_in_cache() True """ if self.is_empty(): @@ -1720,29 +1757,31 @@ def _ehrhart_quasipolynomial_normaliz(self, variable='t'): EXAMPLES:: - sage: C = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]],backend='normaliz') # optional - pynormaliz - sage: C._ehrhart_quasipolynomial_normaliz() # optional - pynormaliz + sage: C = Polyhedron(vertices=[[0,0,0], [0,0,1], [0,1,0], [0,1,1], + ....: [1,0,0], [1,0,1], [1,1,0], [1,1,1]], + ....: backend='normaliz') + sage: C._ehrhart_quasipolynomial_normaliz() t^3 + 3*t^2 + 3*t + 1 - sage: P = Polyhedron(vertices=[[0,0],[3/2,0],[0,3/2],[1,1]],backend='normaliz') # optional - pynormaliz - sage: P._ehrhart_quasipolynomial_normaliz() # optional - pynormaliz + sage: P = Polyhedron(vertices=[[0,0], [3/2,0], [0,3/2], [1,1]], backend='normaliz') + sage: P._ehrhart_quasipolynomial_normaliz() (3/2*t^2 + 2*t + 1, 3/2*t^2 + 2*t + 1/2) - sage: P._ehrhart_quasipolynomial_normaliz('x') # optional - pynormaliz + sage: P._ehrhart_quasipolynomial_normaliz('x') (3/2*x^2 + 2*x + 1, 3/2*x^2 + 2*x + 1/2) The quasipolynomial evaluated at ``i`` counts the integral points in the ``i``-th dilate:: - sage: Q = Polyhedron(vertices = [[-1/3],[2/3]],backend='normaliz') # optional - pynormaliz - sage: p0,p1,p2 = Q._ehrhart_quasipolynomial_normaliz() # optional - pynormaliz - sage: r0 = [p0(i) for i in range(15)] # optional - pynormaliz - sage: r1 = [p1(i) for i in range(15)] # optional - pynormaliz - sage: r2 = [p2(i) for i in range(15)] # optional - pynormaliz - sage: result = [None]*15 # optional - pynormaliz - sage: result[::3] = r0[::3] # optional - pynormaliz - sage: result[1::3] = r1[1::3] # optional - pynormaliz - sage: result[2::3] = r2[2::3] # optional - pynormaliz - sage: result == [(i*Q).integral_points_count() for i in range(15)] # optional - pynormaliz + sage: Q = Polyhedron(vertices=[[-1/3], [2/3]], backend='normaliz') + sage: p0,p1,p2 = Q._ehrhart_quasipolynomial_normaliz() + sage: r0 = [p0(i) for i in range(15)] + sage: r1 = [p1(i) for i in range(15)] + sage: r2 = [p2(i) for i in range(15)] + sage: result = [None]*15 + sage: result[::3] = r0[::3] + sage: result[1::3] = r1[1::3] + sage: result[2::3] = r2[2::3] + sage: result == [(i*Q).integral_points_count() for i in range(15)] True @@ -1791,32 +1830,33 @@ def hilbert_series(self, grading, variable='t'): EXAMPLES:: - sage: C = Polyhedron(backend='normaliz',rays=[[0,0,1],[0,1,1],[1,0,1],[1,1,1]]) # optional - pynormaliz - sage: HS = C.hilbert_series([1,1,1]) # optional - pynormaliz - sage: HS.numerator() # optional - pynormaliz + sage: C = Polyhedron(backend='normaliz', + ....: rays=[[0,0,1], [0,1,1], [1,0,1], [1,1,1]]) + sage: HS = C.hilbert_series([1,1,1]) + sage: HS.numerator() t^2 + 1 - sage: HS.denominator().factor() # optional - pynormaliz + sage: HS.denominator().factor() (-1) * (t + 1) * (t - 1)^3 * (t^2 + t + 1) By changing the grading, you can get the Ehrhart series of the square lifted at height 1:: - sage: C.hilbert_series([0,0,1]) # optional - pynormaliz + sage: C.hilbert_series([0,0,1]) (t + 1)/(-t^3 + 3*t^2 - 3*t + 1) Here is an example ``2cone.in`` from the Normaliz manual:: - sage: C = Polyhedron(backend='normaliz',rays=[[1,3],[2,1]]) # optional - pynormaliz - sage: HS = C.hilbert_series([1,1]) # optional - pynormaliz - sage: HS.numerator() # optional - pynormaliz + sage: C = Polyhedron(backend='normaliz', rays=[[1,3], [2,1]]) + sage: HS = C.hilbert_series([1,1]) + sage: HS.numerator() t^5 + t^4 + t^3 + t^2 + 1 - sage: HS.denominator().factor() # optional - pynormaliz + sage: HS.denominator().factor() (t + 1) * (t - 1)^2 * (t^2 + 1) * (t^2 + t + 1) - sage: HS = C.hilbert_series([1,2]) # optional - pynormaliz - sage: HS.numerator() # optional - pynormaliz + sage: HS = C.hilbert_series([1,2]) + sage: HS.numerator() t^8 + t^6 + t^5 + t^3 + 1 - sage: HS.denominator().factor() # optional - pynormaliz + sage: HS.denominator().factor() (t + 1) * (t - 1)^2 * (t^2 + 1) * (t^6 + t^5 + t^4 + t^3 + t^2 + t + 1) Here is the magic square example form the Normaliz manual:: @@ -1828,9 +1868,10 @@ def hilbert_series(self, grading, variable='t'): ....: [0,1,1,0, 0, 0,-1, 0, 0,-1], ....: [0,0,1,1, 0,-1, 0, 0, 0,-1], ....: [0,1,1,0, 0,-1, 0,-1, 0, 0]] - sage: magic_square = Polyhedron(eqns=eq,backend='normaliz') & Polyhedron(rays=identity_matrix(9).rows()) # optional - pynormaliz + sage: magic_square = (Polyhedron(eqns=eq, backend='normaliz') + ....: & Polyhedron(rays=identity_matrix(9).rows())) sage: grading = [1,1,1,0,0,0,0,0,0] - sage: magic_square.hilbert_series(grading) # optional - pynormaliz + sage: magic_square.hilbert_series(grading) (t^6 + 2*t^3 + 1)/(-t^9 + 3*t^6 - 3*t^3 + 1) .. SEEALSO:: @@ -1841,8 +1882,8 @@ def hilbert_series(self, grading, variable='t'): Check that the Hilbert series is pickled:: - sage: new_magic = loads(dumps(magic_square)) # optional - pynormaliz - sage: new_magic.hilbert_series.is_in_cache(grading) # optional - pynormaliz + sage: new_magic = loads(dumps(magic_square)) + sage: new_magic.hilbert_series.is_in_cache(grading) True """ if self.is_empty(): @@ -1885,29 +1926,29 @@ def integral_points(self, threshold=10000): EXAMPLES:: - sage: Polyhedron(vertices=[(-1,-1), (1,0), (1,1), (0,1)], # optional - pynormaliz + sage: Polyhedron(vertices=[(-1,-1), (1,0), (1,1), (0,1)], ....: backend='normaliz').integral_points() ((-1, -1), (0, 0), (0, 1), (1, 0), (1, 1)) - sage: simplex = Polyhedron([(1,2,3), (2,3,7), (-2,-3,-11)], # optional - pynormaliz + sage: simplex = Polyhedron([(1,2,3), (2,3,7), (-2,-3,-11)], ....: backend='normaliz') - sage: simplex.integral_points() # optional - pynormaliz + sage: simplex.integral_points() ((-2, -3, -11), (0, 0, -2), (1, 2, 3), (2, 3, 7)) The polyhedron need not be full-dimensional:: - sage: simplex = Polyhedron([(1,2,3,5), (2,3,7,5), (-2,-3,-11,5)], # optional - pynormaliz + sage: simplex = Polyhedron([(1,2,3,5), (2,3,7,5), (-2,-3,-11,5)], ....: backend='normaliz') - sage: simplex.integral_points() # optional - pynormaliz + sage: simplex.integral_points() ((-2, -3, -11, 5), (0, 0, -2, 5), (1, 2, 3, 5), (2, 3, 7, 5)) - sage: point = Polyhedron([(2,3,7)], # optional - pynormaliz + sage: point = Polyhedron([(2,3,7)], ....: backend='normaliz') - sage: point.integral_points() # optional - pynormaliz + sage: point.integral_points() ((2, 3, 7),) - sage: empty = Polyhedron(backend='normaliz') # optional - pynormaliz - sage: empty.integral_points() # optional - pynormaliz + sage: empty = Polyhedron(backend='normaliz') + sage: empty.integral_points() () Here is a simplex where the naive algorithm of running over @@ -1915,9 +1956,9 @@ def integral_points(self, threshold=10000): enough:: sage: v = [(1,0,7,-1), (-2,-2,4,-3), (-1,-1,-1,4), (2,9,0,-5), (-2,-1,5,1)] - sage: simplex = Polyhedron(v, backend='normaliz'); simplex # optional - pynormaliz + sage: simplex = Polyhedron(v, backend='normaliz'); simplex A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices - sage: len(simplex.integral_points()) # optional - pynormaliz + sage: len(simplex.integral_points()) 49 A rather thin polytope for which the bounding box method would @@ -1925,27 +1966,27 @@ def integral_points(self, threshold=10000): polytope, so the other backends use the bounding box method):: sage: P = Polyhedron(vertices=((0, 0), (178933,37121))) + 1/1000*polytopes.hypercube(2) - sage: P = Polyhedron(vertices=P.vertices_list(), # optional - pynormaliz + sage: P = Polyhedron(vertices=P.vertices_list(), ....: backend='normaliz') - sage: len(P.integral_points()) # optional - pynormaliz + sage: len(P.integral_points()) 434 Finally, the 3-d reflexive polytope number 4078:: sage: v = [(1,0,0), (0,1,0), (0,0,1), (0,0,-1), (0,-2,1), ....: (-1,2,-1), (-1,2,-2), (-1,1,-2), (-1,-1,2), (-1,-3,2)] - sage: P = Polyhedron(v, backend='normaliz') # optional - pynormaliz - sage: pts1 = P.integral_points() # optional - pynormaliz - sage: all(P.contains(p) for p in pts1) # optional - pynormaliz + sage: P = Polyhedron(v, backend='normaliz') + sage: pts1 = P.integral_points() + sage: all(P.contains(p) for p in pts1) True - sage: pts2 = LatticePolytope(v).points() # optional - palp - sage: for p in pts1: p.set_immutable() # optional - pynormaliz - sage: set(pts1) == set(pts2) # optional - palp # optional - pynormaliz + sage: pts2 = LatticePolytope(v).points() # needs palp + sage: for p in pts1: p.set_immutable() + sage: set(pts1) == set(pts2) # needs palp True - sage: timeit('Polyhedron(v, backend='normaliz').integral_points()') # not tested - random + sage: timeit('Polyhedron(v, backend='normaliz').integral_points()') # not tested - random 625 loops, best of 3: 1.41 ms per loop - sage: timeit('LatticePolytope(v).points()') # not tested - random + sage: timeit('LatticePolytope(v).points()') # not tested - random 25 loops, best of 3: 17.2 ms per loop TESTS: @@ -1954,32 +1995,32 @@ def integral_points(self, threshold=10000): Empty polyhedron in 1 dimension:: - sage: P = Polyhedron(ambient_dim=1, backend='normaliz') # optional - pynormaliz - sage: P.integral_points() # optional - pynormaliz + sage: P = Polyhedron(ambient_dim=1, backend='normaliz') + sage: P.integral_points() () Empty polyhedron in 0 dimensions:: - sage: P = Polyhedron(ambient_dim=0, backend='normaliz') # optional - pynormaliz - sage: P.integral_points() # optional - pynormaliz + sage: P = Polyhedron(ambient_dim=0, backend='normaliz') + sage: P.integral_points() () Single point in 1 dimension:: - sage: P = Polyhedron([[3]], backend='normaliz') # optional - pynormaliz - sage: P.integral_points() # optional - pynormaliz + sage: P = Polyhedron([[3]], backend='normaliz') + sage: P.integral_points() ((3),) Single non-integral point in 1 dimension:: - sage: P = Polyhedron([[1/2]], backend='normaliz') # optional - pynormaliz - sage: P.integral_points() # optional - pynormaliz + sage: P = Polyhedron([[1/2]], backend='normaliz') + sage: P.integral_points() () Single point in 0 dimensions:: - sage: P = Polyhedron([[]], backend='normaliz') # optional - pynormaliz - sage: P.integral_points() # optional - pynormaliz + sage: P = Polyhedron([[]], backend='normaliz') + sage: P.integral_points() ((),) A polytope with no integral points (:trac:`22938`):: @@ -1988,12 +2029,12 @@ def integral_points(self, threshold=10000): ....: [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, -1], ....: [-1, -1, -1, -1], [1, 1, 0, 0], [1, 0, 1, 0], ....: [1, 0, 0, 1]] - sage: P = Polyhedron(ieqs=ieqs, backend='normaliz') # optional - pynormaliz - sage: P.bounding_box() # optional - pynormaliz + sage: P = Polyhedron(ieqs=ieqs, backend='normaliz') + sage: P.bounding_box() ((-3/4, -1/2, -1/4), (-1/2, -1/4, 0)) - sage: P.bounding_box(integral_hull=True) # optional - pynormaliz + sage: P.bounding_box(integral_hull=True) (None, None) - sage: P.integral_points() # optional - pynormaliz + sage: P.integral_points() () Check the polytopes from :trac:`22984`:: @@ -2025,8 +2066,8 @@ def integral_points(self, threshold=10000): ....: [4, 0, 0, 0, 0, 0, 1, 0, 0], ....: [2, 0, 0, 0, 0, 0, 0, 1, 0], ....: [1, 0, 0, 0, 0, 0, 0, 0, 1]] - sage: P = Polyhedron(ieqs=ieqs, backend='normaliz') # optional - pynormaliz - sage: P.integral_points() # optional - pynormaliz + sage: P = Polyhedron(ieqs=ieqs, backend='normaliz') + sage: P.integral_points() ((-2, -2, -4, -5, -4, -3, -2, -1), (-2, -2, -4, -5, -4, -3, -2, 0), (-1, -2, -3, -4, -3, -2, -2, -1), @@ -2047,8 +2088,8 @@ def integral_points(self, threshold=10000): ....: [4, 0, 0, 0, 0, 0, 1, 0, 0], ....: [2, 0, 0, 0, 0, 0, 0, 1, 0], ....: [1, 0, 0, 0, 0, 0, 0, 0, 1]] - sage: P = Polyhedron(ieqs=ieqs, backend='normaliz') # optional - pynormaliz - sage: P.integral_points() # optional - pynormaliz + sage: P = Polyhedron(ieqs=ieqs, backend='normaliz') + sage: P.integral_points() ((-3, -4, -6, -8, -6, -4, -2, -1), (-3, -4, -6, -8, -6, -4, -2, 0), (-2, -2, -4, -5, -4, -3, -2, -1), @@ -2110,20 +2151,20 @@ def integral_points_generators(self): Normaliz gives a nonnegative integer basis of the lineality space:: - sage: P = Polyhedron(backend='normaliz',lines=[[2,2]]) # optional - pynormaliz - sage: P.integral_points_generators() # optional - pynormaliz + sage: P = Polyhedron(backend='normaliz', lines=[[2,2]]) + sage: P.integral_points_generators() (((0, 0),), (), ((1, 1),)) A recession cone generated by two rays:: - sage: C = Polyhedron(backend='normaliz',rays=[[1,2],[2,1]]) # optional - pynormaliz - sage: C.integral_points_generators() # optional - pynormaliz + sage: C = Polyhedron(backend='normaliz', rays=[[1,2], [2,1]]) + sage: C.integral_points_generators() (((0, 0),), ((1, 1), (1, 2), (2, 1)), ()) Empty polyhedron:: - sage: P = Polyhedron(backend='normaliz') # optional - pynormaliz - sage: P.integral_points_generators() # optional - pynormaliz + sage: P = Polyhedron(backend='normaliz') + sage: P.integral_points_generators() ((), (), ()) """ # Trivial cases: polyhedron with 0 vertices @@ -2200,16 +2241,17 @@ class functions. is equal to 1 = `\chi_{trivial}` (Prop 6.1 [Stap2011]_). Here is the computation for the 3-dimensional standard simplex:: - sage: S = polytopes.simplex(3, backend = 'normaliz'); S # optional - pynormaliz + sage: # needs sage.groups + sage: S = polytopes.simplex(3, backend='normaliz'); S A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices - sage: G = S.restricted_automorphism_group(output = 'permutation'); # optional - pynormaliz - sage: G.is_isomorphic(SymmetricGroup(4)) # optional - pynormaliz + sage: G = S.restricted_automorphism_group(output='permutation') + sage: G.is_isomorphic(SymmetricGroup(4)) True - sage: len(G) # optional - pynormaliz + sage: len(G) 24 - sage: Hstar = S._Hstar_function_normaliz(G); Hstar # optional - pynormaliz + sage: Hstar = S._Hstar_function_normaliz(G); Hstar chi_4 - sage: G.character_table() # optional - pynormaliz + sage: G.character_table() [ 1 -1 1 1 -1] [ 3 -1 0 -1 1] [ 2 0 -1 2 0] @@ -2221,35 +2263,38 @@ class functions. `\pm(0,0,1),\pm(1,0,1), \pm(0,1,1), \pm(1,1,1)` and let G = `\Zmod{2}` act on P as follows:: - sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz - ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz - sage: K = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: G = K.subgroup(gens = [K([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz - sage: conj_reps = G.conjugacy_classes_representatives() # optional - pynormaliz - sage: Dict = P.permutations_to_matrices(conj_reps, acting_group = G) # optional - pynormaliz - sage: list(Dict.keys())[0] # optional - pynormaliz + sage: # needs sage.groups + sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], [-1,0,-1], + ....: [0,1,1], [0,-1,-1], [1,1,1], [-1,-1,-1]], + ....: backend='normaliz') + sage: K = P.restricted_automorphism_group(output='permutation') + sage: G = K.subgroup(gens=[K([(0,2),(1,3),(4,6),(5,7)])]) + sage: conj_reps = G.conjugacy_classes_representatives() + sage: Dict = P.permutations_to_matrices(conj_reps, acting_group=G) + sage: list(Dict.keys())[0] (0,2)(1,3)(4,6)(5,7) - sage: list(Dict.values())[0] # optional - pynormaliz + sage: list(Dict.values())[0] [-1 0 1 0] [ 0 1 0 0] [ 0 0 1 0] [ 0 0 0 1] - sage: len(G) # optional - pynormaliz + sage: len(G) 2 - sage: G.character_table() # optional - pynormaliz + sage: G.character_table() [ 1 1] [ 1 -1] Then we calculate the rational function `H^*(t)`:: - sage: Hst = P._Hstar_function_normaliz(G); Hst # optional - pynormaliz - (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) + sage: Hst = P._Hstar_function_normaliz(G); Hst # needs sage.groups + (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) To see the exact as written in [Stap2011]_, we can format it as ``'Hstar_as_lin_comb'``. The first coordinate is the coefficient of the trivial character; the second is the coefficient of the sign character:: - sage: lin = P._Hstar_function_normaliz(G,output = 'Hstar_as_lin_comb'); lin # optional - pynormaliz + sage: lin = P._Hstar_function_normaliz(G, output='Hstar_as_lin_comb'); lin # needs sage.groups ((t^4 + 3*t^3 + 8*t^2 + 3*t + 1)/(t + 1), (3*t^3 + 2*t^2 + 3*t)/(t + 1)) """ from sage.groups.conjugacy_classes import ConjugacyClassGAP @@ -2358,15 +2403,16 @@ def _Hstar_as_rat_fct(self, initial_Hstar): The expression of `H^*` as a polynomial in `t` for a 3-dimensional simplex is computed as follows:: - sage: simplex = Polyhedron(vertices=[[0,0,0],[1,0,0],[0,1,0],[0,0,1]],backend='normaliz') # optional - pynormaliz - sage: Hstar = simplex.Hstar_function(); Hstar # optional - pynormaliz # indirect doctest + sage: simplex = Polyhedron(vertices=[[0,0,0], [1,0,0], + ....: [0,1,0], [0,0,1]], backend='normaliz') + sage: Hstar = simplex.Hstar_function(); Hstar # indirect doctest # needs sage.rings.number_field chi_4 The polynomial is `\chi_4 \cdot t^0`. We can see which irreducible representation `\chi_4` corresponds to by looking at the character table:: - sage: G = simplex.restricted_automorphism_group(output='permutation') # optional - pynormaliz - sage: char = G.character_table();char # optional - pynormaliz + sage: G = simplex.restricted_automorphism_group(output='permutation') # needs sage.groups + sage: char = G.character_table(); char # needs sage.groups [ 1 -1 1 1 -1] [ 3 -1 0 -1 1] [ 2 0 -1 2 0] @@ -2378,15 +2424,16 @@ def _Hstar_as_rat_fct(self, initial_Hstar): As another example, we can look at `H^*(t)` for the `\pm 1` square:: - sage: square = Polyhedron(vertices = [[1,1],[-1,1],[-1,-1],[1,-1]], backend ='normaliz') # optional - pynormaliz - sage: Hstar = square.Hstar_function() ; Hstar # optional - pynormaliz + sage: square = Polyhedron(vertices=[[1,1], [-1,1], [-1,-1], [1,-1]], + ....: backend='normaliz') + sage: Hstar = square.Hstar_function(); Hstar # needs sage.rings.number_field chi_0*t^2 + (2*chi_0 + chi_2 + chi_3 + chi_4)*t + chi_0 Plugging in the values from the first column of the character table below yields the `h^*`-polynomial of the square, `t^2+6t+1`:: - sage: G = square.restricted_automorphism_group(output='permutation') # optional - pynormaliz - sage: G.character_table() # optional - pynormaliz + sage: G = square.restricted_automorphism_group(output='permutation') # needs sage.groups + sage: G.character_table() # needs sage.groups [ 1 1 1 1 1] [ 1 -1 -1 1 1] [ 1 -1 1 -1 1] @@ -2433,27 +2480,32 @@ class functions of the acting group. A character `\rho` is effective if The `H^*` series of the two-dimensional permutahedron under the action of the symmetric group is effective:: - sage: p3 = polytopes.permutahedron(3, backend = 'normaliz') # optional - pynormaliz - sage: G = p3.restricted_automorphism_group(output='permutation') # optional - pynormaliz - sage: reflection12 = G([(0,2),(1,4),(3,5)]) # optional - pynormaliz - sage: reflection23 = G([(0,1),(2,3),(4,5)]) # optional - pynormaliz - sage: S3 = G.subgroup(gens=[reflection12, reflection23]) # optional - pynormaliz - sage: S3.is_isomorphic(SymmetricGroup(3)) # optional - pynormaliz + sage: # needs sage.groups + sage: p3 = polytopes.permutahedron(3, backend='normaliz') + sage: G = p3.restricted_automorphism_group(output='permutation') + sage: reflection12 = G([(0,2),(1,4),(3,5)]) + sage: reflection23 = G([(0,1),(2,3),(4,5)]) + sage: S3 = G.subgroup(gens=[reflection12, reflection23]) + sage: S3.is_isomorphic(SymmetricGroup(3)) True - sage: [Hstar, Hlin] = [p3.Hstar_function(S3), p3.Hstar_function(S3, output = 'Hstar_as_lin_comb')] # optional - pynormaliz - sage: p3._is_effective_normaliz(Hstar,Hlin) # optional - pynormaliz + sage: Hstar = p3.Hstar_function(S3) # needs sage.rings.number_field + sage: Hlin = p3.Hstar_function(S3, output='Hstar_as_lin_comb') # needs sage.rings.number_field + sage: p3._is_effective_normaliz(Hstar, Hlin) # needs sage.rings.number_field True If the `H^*`-series is not polynomial, then it is not effective:: - sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz - ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz - sage: G = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: H = G.subgroup(gens = [G([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz - sage: Hstar = P.Hstar_function(H); Hstar # optional - pynormaliz - (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) - sage: Hstar_lin = P.Hstar_function(H, output = 'Hstar_as_lin_comb') # optional - pynormaliz - sage: P._is_effective_normaliz(Hstar, Hstar_lin) # optional - pynormaliz + sage: # needs sage.groups + sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], [-1,0,-1], + ....: [0,1,1], [0,-1,-1], [1,1,1], [-1,-1,-1]], + ....: backend='normaliz') + sage: G = P.restricted_automorphism_group(output='permutation') + sage: H = G.subgroup(gens = [G([(0,2),(1,3),(4,6),(5,7)])]) + sage: Hstar = P.Hstar_function(H); Hstar # needs sage.rings.number_field + (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) + sage: Hstar_lin = P.Hstar_function(H, output='Hstar_as_lin_comb') # needs sage.rings.number_field + sage: P._is_effective_normaliz(Hstar, Hstar_lin) # needs sage.rings.number_field False """ if not Hstar.denominator().is_unit(): @@ -2478,9 +2530,9 @@ class Polyhedron_ZZ_normaliz(Polyhedron_QQ_normaliz, Polyhedron_ZZ): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], # optional - pynormaliz + sage: p = Polyhedron(vertices=[(0,0), (1,0), (0,1)], ....: rays=[(1,1)], lines=[], ....: backend='normaliz', base_ring=ZZ) - sage: TestSuite(p).run() # optional - pynormaliz + sage: TestSuite(p).run() """ pass diff --git a/src/sage/geometry/polyhedron/backend_number_field.py b/src/sage/geometry/polyhedron/backend_number_field.py index 437550de3aa..e79688bea5f 100644 --- a/src/sage/geometry/polyhedron/backend_number_field.py +++ b/src/sage/geometry/polyhedron/backend_number_field.py @@ -39,27 +39,26 @@ class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): EXAMPLES:: - sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], backend='number_field') # optional - sage.rings.number_field - sage: P # optional - sage.rings.number_field + sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], backend='number_field'); P # needs sage.rings.number_field sage.symbolic A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.rings.number_field + sage: P.vertices() # needs sage.rings.number_field sage.symbolic (A vertex at (1), A vertex at (sqrt(2))) - sage: P = polytopes.icosahedron(exact=True, backend='number_field') # optional - sage.rings.number_field - sage: P # optional - sage.rings.number_field + sage: P = polytopes.icosahedron(exact=True, backend='number_field') # needs sage.rings.number_field + sage: P # needs sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 defined as the convex hull of 12 vertices - sage: x = polygen(ZZ); P = Polyhedron( # optional - sage.rings.number_field + sage: x = polygen(ZZ); P = Polyhedron( # needs sage.rings.number_field sage.symbolic ....: vertices=[[sqrt(2)], [AA.polynomial_root(x^3-2, RIF(0,3))]], ....: backend='number_field') - sage: P # optional - sage.rings.number_field + sage: P # needs sage.rings.number_field sage.symbolic A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.rings.number_field + sage: P.vertices() # needs sage.rings.number_field sage.symbolic (A vertex at (sqrt(2)), A vertex at (2^(1/3))) TESTS: @@ -67,18 +66,21 @@ class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): Tests from :class:`~sage.geometry.polyhedron.backend_field.Polyhedron_field` -- here the data are already either in a number field or in ``AA``:: - sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # optional - sage.rings.number_field - ....: rays=[(1,1)], lines=[], backend='number_field', base_ring=AA) - sage: TestSuite(p).run() # optional - sage.rings.number_field - - sage: K.<sqrt3> = QuadraticField(3) # optional - sage.rings.number_field - sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)], backend='number_field') # optional - sage.rings.number_field - sage: TestSuite(p).run() # optional - sage.rings.number_field - - sage: K.<phi> = NumberField(x^2-x-1, embedding=1.618) # optional - sage.rings.number_field - sage: P1 = Polyhedron([[0,1], [1,1], [1,-phi+1]], backend='number_field') # optional - sage.rings.number_field - sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]], backend='number_field') # optional - sage.rings.number_field - sage: P1.intersection(P2) # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # needs sage.rings.number_field + ....: rays=[(1,1)], lines=[], backend='number_field', + ....: base_ring=AA) + sage: TestSuite(p).run() # needs sage.rings.number_field + + sage: K.<sqrt3> = QuadraticField(3) # needs sage.rings.number_field + sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)], backend='number_field') # needs sage.rings.number_field + sage: TestSuite(p).run() # needs sage.rings.number_field + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<phi> = NumberField(x^2 - x - 1, embedding=1.618) + sage: P1 = Polyhedron([[0,1], [1,1], [1,-phi+1]], backend='number_field') + sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]], backend='number_field') + sage: P1.intersection(P2) The empty polyhedron in (Number Field in phi with defining polynomial x^2 - x - 1 with phi = 1.618033988749895?)^2 @@ -119,9 +121,9 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, Check that the coordinates of a vertex get simplified in the Symbolic Ring:: - sage: p = Polyhedron(ambient_dim=2, base_ring=SR, backend='number_field') + sage: p = Polyhedron(ambient_dim=2, base_ring=SR, backend='number_field') # needs sage.symbolic sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field - sage: Polyhedron_number_field._init_from_Vrepresentation(p, [(0,1/2),(sqrt(2),0),(4,5/6)], [], []); p + sage: Polyhedron_number_field._init_from_Vrepresentation(p, [(0,1/2),(sqrt(2),0),(4,5/6)], [], []); p # needs sage.symbolic A 2-dimensional polyhedron in (Symbolic Ring)^2 defined as the convex hull of 3 vertices sage: p.vertices()[0][0] 0 diff --git a/src/sage/geometry/polyhedron/backend_polymake.py b/src/sage/geometry/polyhedron/backend_polymake.py index 36ccc33c39f..624ae2f6340 100644 --- a/src/sage/geometry/polyhedron/backend_polymake.py +++ b/src/sage/geometry/polyhedron/backend_polymake.py @@ -77,13 +77,14 @@ class Polyhedron_polymake(Polyhedron_base): It can also be obtained differently:: - sage: P=Polyhedron(ieqs=[[-2, 1, 1], [-3, -1, -1], [-4, 1, -2]], # optional - jupymake + sage: # optional - jupymake + sage: P=Polyhedron(ieqs=[[-2, 1, 1], [-3, -1, -1], [-4, 1, -2]], ....: backend='polymake') - sage: P # optional - jupymake + sage: P The empty polyhedron in QQ^2 - sage: P.Vrepresentation() # optional - jupymake + sage: P.Vrepresentation() () - sage: P.Hrepresentation() # optional - jupymake + sage: P.Hrepresentation() (An equation -1 == 0,) The full polyhedron:: @@ -96,8 +97,8 @@ class Polyhedron_polymake(Polyhedron_base): Quadratic fields work:: - sage: V = polytopes.dodecahedron().vertices_list() # optional - sage.rings.number_field - sage: Polyhedron(vertices=V, backend='polymake') # optional - jupymake # optional - sage.rings.number_field + sage: V = polytopes.dodecahedron().vertices_list() # needs sage.rings.number_field + sage: Polyhedron(vertices=V, backend='polymake') # optional - jupymake, needs sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 @@ -211,11 +212,12 @@ def __init__(self, parent, Vrep, Hrep, polymake_polytope=None, **kwds): TESTS: - sage: p = Polyhedron(backend='polymake') # optional - jupymake - sage: TestSuite(p).run() # optional - jupymake - sage: p = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], # optional - jupymake + sage: # optional - jupymake + sage: p = Polyhedron(backend='polymake') + sage: TestSuite(p).run() + sage: p = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], ....: backend='polymake') - sage: TestSuite(p).run() # optional - jupymake + sage: TestSuite(p).run() We skip the Lawrence test because it involves numerically unstable floating point arithmetic:: @@ -226,14 +228,15 @@ def __init__(self, parent, Vrep, Hrep, polymake_polytope=None, **kwds): :: - sage: p = Polyhedron(rays=[[1,1]], backend='polymake') # optional - jupymake - sage: TestSuite(p).run() # optional - jupymake - sage: p = Polyhedron(rays=[[1]], backend='polymake') # optional - jupymake - sage: TestSuite(p).run() # optional - jupymake - sage: p = Polyhedron(rays=[[1,1,1]], lines=[[1,0,0]], backend='polymake') # optional - jupymake - sage: TestSuite(p).run() # optional - jupymake - sage: p = Polyhedron(vertices=[[]], backend='polymake') # optional - jupymake - sage: TestSuite(p).run() # optional - jupymake + sage: # optional - jupymake + sage: p = Polyhedron(rays=[[1,1]], backend='polymake') + sage: TestSuite(p).run() + sage: p = Polyhedron(rays=[[1]], backend='polymake') + sage: TestSuite(p).run() + sage: p = Polyhedron(rays=[[1,1,1]], lines=[[1,0,0]], backend='polymake') + sage: TestSuite(p).run() + sage: p = Polyhedron(vertices=[[]], backend='polymake') + sage: TestSuite(p).run() """ if polymake_polytope is not None: if Hrep is not None or Vrep is not None: @@ -250,7 +253,7 @@ def _init_from_polymake_polytope(self, polymake_polytope): TESTS:: sage: p = Polyhedron(backend='polymake') # optional - jupymake - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake sage: Polyhedron_polymake._init_from_Hrepresentation(p, [], []) # indirect doctest # optional - jupymake """ self._polymake_polytope = polymake_polytope @@ -281,7 +284,7 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbo EXAMPLES:: sage: p = Polyhedron(backend='polymake') # optional - jupymake - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake sage: Polyhedron_polymake._init_from_Vrepresentation(p, [], [], []) # optional - jupymake """ from sage.interfaces.polymake import polymake @@ -348,7 +351,7 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): EXAMPLES:: sage: p = Polyhedron(backend='polymake') # optional - jupymake - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake sage: Polyhedron_polymake._init_from_Hrepresentation(p, [], []) # optional - jupymake """ from sage.interfaces.polymake import polymake @@ -644,31 +647,35 @@ def __setstate__(self, state): Test that the obtained cone is valid:: - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake - sage: P = polytopes.permutahedron(4, backend='polymake') # optional - jupymake - sage: P1 = loads(dumps(P)) # optional - jupymake - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake - sage: P._test_polymake_pickling(other=P2) # optional - jupymake + sage: # optional - jupymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake + sage: P = polytopes.permutahedron(4, backend='polymake') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) + sage: P._test_polymake_pickling(other=P2) - sage: P = Polyhedron(lines=[[1,0], [0,1]], backend='polymake') # optional - jupymake - sage: P1 = loads(dumps(P)) # optional - jupymake - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake - sage: P._test_polymake_pickling(other=P2) # optional - jupymake + sage: # optional - jupymake + sage: P = Polyhedron(lines=[[1,0], [0,1]], backend='polymake') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) + sage: P._test_polymake_pickling(other=P2) sage: P = Polyhedron(backend='polymake') # optional - jupymake sage: P1 = loads(dumps(P)) # optional - jupymake sage: P._test_polymake_pickling(other=P1) # optional - jupymake - sage: P = polytopes.permutahedron(4, backend='polymake') * Polyhedron(lines=[[1]], backend='polymake') # optional - jupymake - sage: P1 = loads(dumps(P)) # optional - jupymake - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake - sage: P._test_polymake_pickling(other=P2) # optional - jupymake + sage: # optional - jupymake + sage: P = polytopes.permutahedron(4, backend='polymake') * Polyhedron(lines=[[1]], backend='polymake') + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) + sage: P._test_polymake_pickling(other=P2) - sage: print("Possible output"); P = polytopes.dodecahedron(backend='polymake') # optional - jupymake # optional - sage.rings.number_field + sage: # optional - jupymake, needs sage.rings.number_field + sage: print("Possible output"); P = polytopes.dodecahedron(backend='polymake') Possible output... - sage: P1 = loads(dumps(P)) # optional - jupymake # optional - sage.rings.number_field - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake # optional - sage.rings.number_field - sage: P._test_polymake_pickling(other=P2) # optional - jupymake # optional - sage.rings.number_field + sage: P1 = loads(dumps(P)) + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) + sage: P._test_polymake_pickling(other=P2) """ if "_pickle_vertices" in state[1]: vertices = state[1].pop("_pickle_vertices") @@ -688,7 +695,6 @@ def __setstate__(self, state): inequalities = self.inequalities() equations = self.equations() - p = self._polymake_polytope_from_Vrepresentation_and_Hrepresentation([vertices, rays, lines], [inequalities, equations]) if p is not None: self._polymake_polytope = p diff --git a/src/sage/geometry/polyhedron/backend_ppl.py b/src/sage/geometry/polyhedron/backend_ppl.py index 1caafb52a93..a4012616deb 100644 --- a/src/sage/geometry/polyhedron/backend_ppl.py +++ b/src/sage/geometry/polyhedron/backend_ppl.py @@ -16,7 +16,7 @@ from sage.features import PythonModule lazy_import('ppl', ['C_Polyhedron', 'Generator_System', 'Constraint_System', 'Linear_Expression', 'line', 'ray', 'point'], - feature=PythonModule("ppl", spkg="pplpy")) + feature=PythonModule("ppl", spkg="pplpy", type="standard")) ######################################################################### @@ -281,8 +281,8 @@ def _init_Vrepresentation_from_ppl(self, minimize): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], - ....: backend='ppl') # indirect doctest + sage: p = Polyhedron(vertices=[(0,1/2), (2,0), (4,5/6)], # indirect doctest + ....: backend='ppl') sage: p.Hrepresentation() (An inequality (1, 4) x - 2 >= 0, An inequality (1, -12) x + 6 >= 0, @@ -321,8 +321,8 @@ def _init_Hrepresentation_from_ppl(self, minimize): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], - ....: backend='ppl') # indirect doctest + sage: p = Polyhedron(vertices=[(0,1/2), (2,0), (4,5/6)], # indirect doctest + ....: backend='ppl') sage: p.Hrepresentation() (An inequality (1, 4) x - 2 >= 0, An inequality (1, -12) x + 6 >= 0, @@ -539,7 +539,6 @@ def _convert_constraints_to_ppl(ieqs, eqns): return cs - ######################################################################### class Polyhedron_QQ_ppl(Polyhedron_ppl, Polyhedron_QQ): r""" diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 77a11c53d21..ec26e49075c 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -21,7 +21,7 @@ # Copyright (C) 2019 Julian Ritter # Copyright (C) 2019-2020 Laith Rastanawi # Copyright (C) 2019-2020 Sophia Elia -# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -124,8 +124,8 @@ class Polyhedron_base(Polyhedron_base7): :: - sage: p=polytopes.flow_polytope(digraphs.DeBruijn(3,2)) # optional - sage.graphs - sage: TestSuite(p).run() # optional - sage.graphs + sage: p = polytopes.flow_polytope(digraphs.DeBruijn(3,2)) # needs sage.combinat sage.graphs + sage: TestSuite(p).run() :: @@ -135,13 +135,14 @@ class Polyhedron_base(Polyhedron_base7): :: - sage: P = polytopes.permutahedron(3) * Polyhedron(rays=[[0,0,1],[0,1,1],[1,2,3]]) # optional - sage.combinat - sage: TestSuite(P).run() # optional - sage.combinat + sage: P3 = polytopes.permutahedron(3) + sage: P = P3 * Polyhedron(rays=[[0,0,1], [0,1,1], [1,2,3]]) + sage: TestSuite(P).run() :: - sage: P = polytopes.permutahedron(3)*Polyhedron(rays=[[0,0,1],[0,1,1]], lines=[[1,0,0]]) # optional - sage.combinat - sage: TestSuite(P).run() # optional - sage.combinat + sage: P = P3 * Polyhedron(rays=[[0,0,1], [0,1,1]], lines=[[1,0,0]]) + sage: TestSuite(P).run() :: @@ -233,44 +234,46 @@ def to_linear_program(self, solver=None, return_variable=False, base_ring=None): Irrational algebraic linear program over an embedded number field:: - sage: p = polytopes.icosahedron() # optional - sage.rings.number_field - sage: lp, x = p.to_linear_program(return_variable=True) # optional - sage.rings.number_field - sage: lp.set_objective(x[0] + x[1] + x[2]) # optional - sage.rings.number_field - sage: lp.solve() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: p = polytopes.icosahedron() + sage: lp, x = p.to_linear_program(return_variable=True) + sage: lp.set_objective(x[0] + x[1] + x[2]) + sage: lp.solve() 1/4*sqrt5 + 3/4 Same example with floating point:: - sage: lp, x = p.to_linear_program(return_variable=True, base_ring=RDF) # optional - sage.rings.number_field - sage: lp.set_objective(x[0] + x[1] + x[2]) # optional - sage.rings.number_field - sage: lp.solve() # tol 1e-5 # optional - sage.rings.number_field + sage: lp, x = p.to_linear_program(return_variable=True, base_ring=RDF) + sage: lp.set_objective(x[0] + x[1] + x[2]) + sage: lp.solve() # tol 1e-5 # needs sage.rings.number_field 1.3090169943749475 Same example with a specific floating point solver:: - sage: lp, x = p.to_linear_program(return_variable=True, solver='GLPK') # optional - sage.rings.number_field - sage: lp.set_objective(x[0] + x[1] + x[2]) # optional - sage.rings.number_field - sage: lp.solve() # tol 1e-8 # optional - sage.rings.number_field + sage: lp, x = p.to_linear_program(return_variable=True, solver='GLPK') + sage: lp.set_objective(x[0] + x[1] + x[2]) + sage: lp.solve() # tol 1e-8 # needs sage.rings.number_field 1.3090169943749475 Irrational algebraic linear program over `AA`:: - sage: p = polytopes.icosahedron(base_ring=AA) # optional - sage.rings.number_field - sage: lp, x = p.to_linear_program(return_variable=True) # optional - sage.rings.number_field - sage: lp.set_objective(x[0] + x[1] + x[2]) # optional - sage.rings.number_field - sage: lp.solve() # long time # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: p = polytopes.icosahedron(base_ring=AA) + sage: lp, x = p.to_linear_program(return_variable=True) + sage: lp.set_objective(x[0] + x[1] + x[2]) + sage: lp.solve() # long time 1.309016994374948? TESTS:: - sage: p = polytopes.flow_polytope(digraphs.DeBruijn(3,2)); p # optional - sage.graphs + sage: p = polytopes.flow_polytope(digraphs.DeBruijn(3,2)); p # needs sage.combinat sage.graphs A 19-dimensional polyhedron in QQ^27 defined as the convex hull of 1 vertex and 148 rays - sage: p.to_linear_program().polyhedron() == p # optional - sage.graphs + sage: p.to_linear_program().polyhedron() == p True - sage: p = polytopes.icosahedron() # optional - sage.rings.number_field - sage: p.to_linear_program(solver='PPL') # optional - sage.rings.number_field + sage: p = polytopes.icosahedron() # needs sage.rings.number_field + sage: p.to_linear_program(solver='PPL') # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: The PPL backend only supports rational data. @@ -316,13 +319,14 @@ def boundary_complex(self): The boundary complex of the octahedron:: + sage: # needs sage.graphs sage: oc = polytopes.octahedron() sage: sc_oc = oc.boundary_complex() - sage: fl_oc = oc.face_lattice() - sage: fl_sc = sc_oc.face_poset() - sage: [len(x) for x in fl_oc.level_sets()] + sage: fl_oc = oc.face_lattice() # needs sage.combinat + sage: fl_sc = sc_oc.face_poset() # needs sage.combinat + sage: [len(x) for x in fl_oc.level_sets()] # needs sage.combinat [1, 6, 12, 8, 1] - sage: [len(x) for x in fl_sc.level_sets()] + sage: [len(x) for x in fl_sc.level_sets()] # needs sage.combinat [6, 12, 8] sage: sc_oc.euler_characteristic() 2 @@ -463,7 +467,7 @@ def is_inscribed(self, certificate=False): EXAMPLES:: - sage: q = Polyhedron(vertices = [[1,1,1,1],[-1,-1,1,1],[1,-1,-1,1], + sage: q = Polyhedron(vertices=[[1,1,1,1],[-1,-1,1,1],[1,-1,-1,1], ....: [-1,1,-1,1],[1,1,1,-1],[-1,-1,1,-1], ....: [1,-1,-1,-1],[-1,1,-1,-1],[0,0,10/13,-24/13], ....: [0,0,-10/13,-24/13]]) @@ -555,7 +559,7 @@ def is_inscribed(self, certificate=False): sage: V = P.Vrepresentation() sage: H = P.Hrepresentation() sage: parent = P.parent() - sage: for V1 in Permutations(V): # optional - sage.combinat + sage: for V1 in Permutations(V): ....: P1 = parent._element_constructor_( ....: [V1, [], []], [H, []], Vrep_minimal=True, Hrep_minimal=True) ....: assert P1.is_inscribed() @@ -657,7 +661,7 @@ def normal_fan(self, direction='inner'): EXAMPLES:: - sage: S = Polyhedron(vertices = [[0, 0], [1, 0], [0, 1]]) + sage: S = Polyhedron(vertices=[[0, 0], [1, 0], [0, 1]]) sage: S.normal_fan() Rational polyhedral fan in 2-d lattice N @@ -667,25 +671,27 @@ def normal_fan(self, direction='inner'): Currently, it is only possible to get the normal fan of a bounded rational polytope:: - sage: P = Polyhedron(rays = [[1, 0], [0, 1]]) + sage: P = Polyhedron(rays=[[1, 0], [0, 1]]) sage: P.normal_fan() Traceback (most recent call last): ... NotImplementedError: the normal fan is only supported for polytopes (compact polyhedra). - sage: Q = Polyhedron(vertices = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + sage: Q = Polyhedron(vertices=[[1, 0, 0], [0, 1, 0], [0, 0, 1]]) sage: Q.normal_fan() Traceback (most recent call last): ... ValueError: the normal fan is only defined for full-dimensional polytopes - sage: R = Polyhedron(vertices=[[0, 0], [AA(sqrt(2)), 0], [0, AA(sqrt(2))]]) # optional - sage.rings.number_field - sage: R.normal_fan() # optional - sage.rings.number_field + sage: R = Polyhedron(vertices=[[0, 0], # needs sage.rings.number_field sage.symbolic + ....: [AA(sqrt(2)), 0], + ....: [0, AA(sqrt(2))]]) + sage: R.normal_fan() # needs sage.rings.number_field sage.symbolic Traceback (most recent call last): ... NotImplementedError: normal fan handles only polytopes over the rationals - sage: P = Polyhedron(vertices=[[0,0],[2,0],[0,2],[2,1],[1,2]]) + sage: P = Polyhedron(vertices=[[0,0], [2,0], [0,2], [2,1], [1,2]]) sage: P.normal_fan(direction=None) Traceback (most recent call last): ... @@ -746,13 +752,14 @@ def face_fan(self): The polytope should contain the origin in the interior:: - sage: P = Polyhedron(vertices = [[1/2, 1], [1, 1/2]]) + sage: P = Polyhedron(vertices=[[1/2, 1], [1, 1/2]]) sage: P.face_fan() Traceback (most recent call last): ... - ValueError: face fans are defined only for polytopes containing the origin as an interior point! + ValueError: face fans are defined only for polytopes + containing the origin as an interior point! - sage: Q = Polyhedron(vertices = [[-1, 1/2], [1, -1/2]]) + sage: Q = Polyhedron(vertices=[[-1, 1/2], [1, -1/2]]) sage: Q.contains([0,0]) True sage: FF = Q.face_fan(); FF @@ -760,8 +767,8 @@ def face_fan(self): The polytope has to have rational coordinates:: - sage: S = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: S.face_fan() # optional - sage.rings.number_field + sage: S = polytopes.dodecahedron() # needs sage.rings.number_field + sage: S.face_fan() # needs sage.rings.number_field Traceback (most recent call last): ... NotImplementedError: face fan handles only polytopes over the rationals @@ -852,8 +859,8 @@ def barycentric_subdivision(self, subdivision_frac=None): sage: P.barycentric_subdivision() A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 6 vertices - sage: P = polytopes.regular_polygon(4, base_ring=QQ) # optional - sage.rings.number_field - sage: P.barycentric_subdivision() # optional - sage.rings.number_field + sage: P = polytopes.regular_polygon(4, base_ring=QQ) # needs sage.rings.number_field + sage: P.barycentric_subdivision() # needs sage.rings.number_field A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 8 vertices @@ -965,17 +972,20 @@ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additiona `\pm 1` 2-dimensional square. The permutations are written in terms of the vertices of the square:: - sage: square = Polyhedron(vertices=[[1,1],[-1,1],[-1,-1],[1,-1]], backend='normaliz') # optional - pynormaliz - sage: square.vertices() # optional - pynormaliz + sage: # optional - pynormaliz, needs sage.groups + sage: square = Polyhedron(vertices=[[1,1], [-1,1], + ....: [-1,-1], [1,-1]], + ....: backend='normaliz') + sage: square.vertices() (A vertex at (-1, -1), - A vertex at (-1, 1), - A vertex at (1, -1), - A vertex at (1, 1)) - sage: aut_square = square.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: conj_reps = aut_square.conjugacy_classes_representatives() # optional - pynormaliz - sage: gens_dict = square.permutations_to_matrices(conj_reps); # optional - pynormaliz - sage: rotation_180 = aut_square([(0,3),(1,2)]) # optional - pynormaliz - sage: rotation_180,gens_dict[rotation_180] # optional - pynormaliz + A vertex at (-1, 1), + A vertex at (1, -1), + A vertex at (1, 1)) + sage: aut_square = square.restricted_automorphism_group(output='permutation') + sage: conj_reps = aut_square.conjugacy_classes_representatives() + sage: gens_dict = square.permutations_to_matrices(conj_reps) + sage: rotation_180 = aut_square([(0,3),(1,2)]) + sage: rotation_180, gens_dict[rotation_180] ( [-1 0 0] [ 0 -1 0] @@ -984,11 +994,13 @@ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additiona This example tests the functionality for additional elements:: + sage: # needs sage.groups sage.rings.real_mpfr sage: C = polytopes.cross_polytope(2) - sage: G = C.restricted_automorphism_group(output = 'permutation') + sage: G = C.restricted_automorphism_group(output='permutation') sage: conj_reps = G.conjugacy_classes_representatives() - sage: add_elt = G([(0,2,3,1)]) - sage: dict = C.permutations_to_matrices(conj_reps,additional_elts = [add_elt]) + sage: add_elt = G([(0, 2, 3, 1)]) + sage: dict = C.permutations_to_matrices(conj_reps, + ....: additional_elts=[add_elt]) sage: dict[add_elt] [ 0 1 0] [-1 0 0] @@ -1048,16 +1060,17 @@ def bounding_box(self, integral=False, integral_hull=False): EXAMPLES:: - sage: Polyhedron([ (1/3,2/3), (2/3, 1/3) ]).bounding_box() + sage: Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box() ((1/3, 1/3), (2/3, 2/3)) - sage: Polyhedron([ (1/3,2/3), (2/3, 1/3) ]).bounding_box(integral=True) + sage: Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box(integral=True) ((0, 0), (1, 1)) - sage: Polyhedron([ (1/3,2/3), (2/3, 1/3) ]).bounding_box(integral_hull=True) + sage: Polyhedron([(1/3,2/3), (2/3, 1/3)]).bounding_box(integral_hull=True) (None, None) - sage: Polyhedron([ (1/3,2/3), (3/3, 4/3) ]).bounding_box(integral_hull=True) + sage: Polyhedron([(1/3,2/3), (3/3, 4/3)]).bounding_box(integral_hull=True) ((1, 1), (1, 1)) - sage: polytopes.buckyball(exact=False).bounding_box() - ((-0.8090169944, -0.8090169944, -0.8090169944), (0.8090169944, 0.8090169944, 0.8090169944)) + sage: polytopes.buckyball(exact=False).bounding_box() # needs sage.groups + ((-0.8090169944, -0.8090169944, -0.8090169944), + (0.8090169944, 0.8090169944, 0.8090169944)) TESTS:: @@ -1135,38 +1148,39 @@ def _polymake_init_(self): Non-pointed polyhedron:: + sage: # optional - jupymake sage: P = Polyhedron(vertices=[[1, 0], [0, 1]], lines=[[1, 0]]) - sage: PP = polymake(P) # optional - jupymake - sage: PP.VERTICES # optional - jupymake + sage: PP = polymake(P) + sage: PP.VERTICES 1 0 1 1 0 0 - sage: PP.FACETS # optional - jupymake + sage: PP.FACETS 1 0 -1 0 0 1 - sage: PP.LINEALITY_SPACE # optional - jupymake + sage: PP.LINEALITY_SPACE 0 1 0 Algebraic polyhedron:: - sage: P = polytopes.dodecahedron(); P # optional - sage.rings.number_field + sage: P = polytopes.dodecahedron(); P # needs sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 defined as the convex hull of 20 vertices - sage: print("There may be a recompilation warning"); PP = polymake(P); PP # optional - jupymake # optional - sage.rings.number_field - There may be a recompilation warning... + sage: print("Maybe recompile warning"); PP = polymake(P); PP # optional - jupymake, needs sage.rings.number_field + Maybe recompile warning... Polytope<QuadraticExtension<Rational>>[...] - sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - jupymake # optional - sage.rings.number_field + sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - jupymake, needs sage.rings.number_field 1 -1+1r5 -4+2r5 0 Floating-point polyhedron:: - sage: P = polytopes.dodecahedron(exact=False); P + sage: P = polytopes.dodecahedron(exact=False); P # needs sage.groups A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 20 vertices - sage: print("There may be a recompilation warning"); PP = polymake(P); PP # optional - jupymake + sage: print("Maybe recompile warning"); PP = polymake(P); PP # optional - jupymake, needs sage.groups There may be a recompilation warning... Polytope<Float>[...] - sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - jupymake + sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - jupymake, needs sage.groups 1 -0.472135955 0 -1.236067978 """ diff --git a/src/sage/geometry/polyhedron/base0.py b/src/sage/geometry/polyhedron/base0.py index 7ed7e777374..556eefc5148 100644 --- a/src/sage/geometry/polyhedron/base0.py +++ b/src/sage/geometry/polyhedron/base0.py @@ -21,7 +21,7 @@ # Copyright (C) 2019 Julian Ritter # Copyright (C) 2019-2020 Laith Rastanawi # Copyright (C) 2019-2020 Sophia Elia -# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -83,10 +83,10 @@ def __init__(self, parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pre sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field sage: from sage.geometry.polyhedron.parent import Polyhedra_field - sage: parent = Polyhedra_field(AA, 1, 'field') # optional - sage.rings.number_field + sage: parent = Polyhedra_field(AA, 1, 'field') # needs sage.rings.number_field sage: Vrep = [[[0], [1/2], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, # optional - sage.rings.number_field + sage: p = Polyhedron_field(parent, Vrep, Hrep, # needs sage.rings.number_field ....: Vrep_minimal=False, Hrep_minimal=True) Traceback (most recent call last): ... @@ -406,13 +406,13 @@ def change_ring(self, base_ring, backend=None): ... TypeError: cannot change the base ring to the Integer Ring - sage: P = polytopes.regular_polygon(3); P # optional - sage.rings.number_field + sage: P = polytopes.regular_polygon(3); P # needs sage.rings.number_field A 2-dimensional polyhedron in AA^2 defined as the convex hull of 3 vertices - sage: P.vertices() # optional - sage.rings.number_field + sage: P.vertices() # needs sage.rings.number_field (A vertex at (0.?e-16, 1.000000000000000?), A vertex at (0.866025403784439?, -0.500000000000000?), A vertex at (-0.866025403784439?, -0.500000000000000?)) - sage: P.change_ring(QQ) # optional - sage.rings.number_field + sage: P.change_ring(QQ) # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: cannot change the base ring to the Rational Field @@ -425,11 +425,11 @@ def change_ring(self, base_ring, backend=None): base ring from an exact ring into ``RDF`` may cause a loss of data:: - sage: P = Polyhedron([[2/3,0],[6666666666666667/10^16,0]], base_ring=AA); P # optional - sage.rings.number_field + sage: P = Polyhedron([[2/3,0],[6666666666666667/10^16,0]], base_ring=AA); P # needs sage.rings.number_field A 1-dimensional polyhedron in AA^2 defined as the convex hull of 2 vertices - sage: Q = P.change_ring(RDF); Q # optional - sage.rings.number_field + sage: Q = P.change_ring(RDF); Q # needs sage.rings.number_field A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex - sage: P.n_vertices() == Q.n_vertices() # optional - sage.rings.number_field + sage: P.n_vertices() == Q.n_vertices() # needs sage.rings.number_field False """ from sage.categories.rings import Rings @@ -577,8 +577,8 @@ def is_compact(self): EXAMPLES:: - sage: p = polytopes.icosahedron() # optional - sage.rings.number_field - sage: p.is_compact() # optional - sage.rings.number_field + sage: p = polytopes.icosahedron() # needs sage.rings.number_field + sage: p.is_compact() # needs sage.rings.number_field True sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0],[0,0,0,1],[1,-1,0,0]]) sage: p.is_compact() @@ -890,11 +890,12 @@ def inequalities(self): An inequality (0, 1, 0) x + 0 >= 0, An inequality (0, 0, 1) x + 0 >= 0) - sage: p3 = Polyhedron(vertices=Permutations([1, 2, 3, 4])) # optional - sage.combinat - sage: ieqs = p3.inequalities() # optional - sage.combinat - sage: ieqs[0] # optional - sage.combinat + sage: # needs sage.combinat + sage: p3 = Polyhedron(vertices=Permutations([1, 2, 3, 4])) + sage: ieqs = p3.inequalities() + sage: ieqs[0] An inequality (0, 1, 1, 1) x - 6 >= 0 - sage: list(_) # optional - sage.combinat + sage: list(_) [-6, 0, 1, 1, 1] """ return tuple(self.inequality_generator()) @@ -915,13 +916,14 @@ def inequalities_list(self): sage: p.inequalities_list()[0:3] [[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] - sage: p3 = Polyhedron(vertices=Permutations([1, 2, 3, 4])) # optional - sage.combinat - sage: ieqs = p3.inequalities_list() # optional - sage.combinat - sage: ieqs[0] # optional - sage.combinat + sage: # needs sage.combinat + sage: p3 = Polyhedron(vertices=Permutations([1, 2, 3, 4])) + sage: ieqs = p3.inequalities_list() + sage: ieqs[0] [-6, 0, 1, 1, 1] - sage: ieqs[-1] # optional - sage.combinat + sage: ieqs[-1] [-3, 0, 1, 0, 1] - sage: ieqs == [list(x) for x in p3.inequality_generator()] # optional - sage.combinat + sage: ieqs == [list(x) for x in p3.inequality_generator()] True """ return [list(x) for x in self.inequality_generator()] @@ -1317,8 +1319,8 @@ def backend(self): sage: triangle = Polyhedron(vertices = [[1, 0], [0, 1], [1, 1]]) sage: triangle.backend() 'ppl' - sage: D = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: D.backend() # optional - sage.rings.number_field + sage: D = polytopes.dodecahedron() # needs sage.rings.number_field + sage: D.backend() # needs sage.rings.number_field 'field' sage: P = Polyhedron([[1.23]]) sage: P.backend() @@ -1352,10 +1354,10 @@ def cdd_Hrepresentation(self): end <BLANKLINE> - sage: triangle = Polyhedron(vertices=[[1,0], [0,1], [1,1]], base_ring=AA) # optional - sage.rings.number_field - sage: triangle.base_ring() # optional - sage.rings.number_field + sage: triangle = Polyhedron(vertices=[[1,0], [0,1], [1,1]], base_ring=AA) # needs sage.rings.number_field + sage: triangle.base_ring() # needs sage.rings.number_field Algebraic Real Field - sage: triangle.cdd_Hrepresentation() # optional - sage.rings.number_field + sage: triangle.cdd_Hrepresentation() # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: the base ring must be ZZ, QQ, or RDF diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py index daac9aa6c05..77b7bf4427e 100644 --- a/src/sage/geometry/polyhedron/base1.py +++ b/src/sage/geometry/polyhedron/base1.py @@ -24,7 +24,7 @@ # Copyright (C) 2019 Julian Ritter # Copyright (C) 2019-2020 Laith Rastanawi # Copyright (C) 2019-2020 Sophia Elia -# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -95,14 +95,15 @@ def __hash__(self): r""" TESTS:: - sage: K.<a> = QuadraticField(2) # optional - sage.rings.number_field - sage: p = Polyhedron(vertices=[(0, 1, a), (3, a, 5)], # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K.<a> = QuadraticField(2) + sage: p = Polyhedron(vertices=[(0, 1, a), (3, a, 5)], ....: rays=[(a, 2, 3), (0, 0, 1)], ....: base_ring=K) - sage: q = Polyhedron(vertices=[(3, a, 5), (0, 1, a)], # optional - sage.rings.number_field + sage: q = Polyhedron(vertices=[(3, a, 5), (0, 1, a)], ....: rays=[(0, 0, 1), (a, 2, 3)], ....: base_ring=K) - sage: hash(p) == hash(q) # optional - sage.rings.number_field + sage: hash(p) == hash(q) True """ # TODO: find something better *but* fast @@ -401,11 +402,11 @@ def ambient_vector_space(self, base_field=None): sage: poly_test.ambient_vector_space() is poly_test.ambient() True - sage: poly_test.ambient_vector_space(AA) # optional - sage.rings.number_field + sage: poly_test.ambient_vector_space(AA) # needs sage.rings.number_field Vector space of dimension 4 over Algebraic Real Field sage: poly_test.ambient_vector_space(RDF) Vector space of dimension 4 over Real Double Field - sage: poly_test.ambient_vector_space(SR) # optional - sage.symbolic + sage: poly_test.ambient_vector_space(SR) # needs sage.symbolic Vector space of dimension 4 over Symbolic Ring """ return self.Vrepresentation_space().vector_space(base_field=base_field) @@ -620,14 +621,15 @@ def contains(self, point): The point need not have coordinates in the same field as the polyhedron:: + sage: # needs sage.symbolic sage: ray = Polyhedron(vertices=[(0,0)], rays=[(1,0)], base_ring=QQ) - sage: ray.contains([sqrt(2)/3,0]) # irrational coordinates are ok # optional - sage.symbolic + sage: ray.contains([sqrt(2)/3,0]) # irrational coordinates are ok True - sage: a = var('a') # optional - sage.symbolic - sage: ray.contains([a,0]) # a might be negative! # optional - sage.symbolic + sage: a = var('a') + sage: ray.contains([a,0]) # a might be negative! False - sage: assume(a>0) # optional - sage.symbolic - sage: ray.contains([a,0]) # optional - sage.symbolic + sage: assume(a>0) + sage: ray.contains([a,0]) True sage: ray.contains(['hello', 'kitty']) # no common ring for coordinates False diff --git a/src/sage/geometry/polyhedron/base2.py b/src/sage/geometry/polyhedron/base2.py index 9afeeaaef1f..0594d0c6708 100644 --- a/src/sage/geometry/polyhedron/base2.py +++ b/src/sage/geometry/polyhedron/base2.py @@ -21,7 +21,7 @@ # Copyright (C) 2019 Julian Ritter # Copyright (C) 2019-2020 Laith Rastanawi # Copyright (C) 2019-2020 Sophia Elia -# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -95,7 +95,7 @@ def is_lattice_polytope(self): sage: polytopes.cross_polytope(3).is_lattice_polytope() True - sage: polytopes.regular_polygon(5).is_lattice_polytope() # optional - sage.rings.number_field + sage: polytopes.regular_polygon(5).is_lattice_polytope() # needs sage.rings.number_field False """ if not self.is_compact(): @@ -143,8 +143,9 @@ def lattice_polytope(self, envelope=False): First, a polyhedron with integral vertices:: sage: P = Polyhedron(vertices=[(1, 0), (0, 1), (-1, 0), (0, -1)]) - sage: lp = P.lattice_polytope() - sage: lp # optional - palp + sage: lp = P.lattice_polytope(); lp + 2-d reflexive polytope... in 2-d lattice M + sage: lp # optional - polytopes_db, needs palp 2-d reflexive polytope #3 in 2-d lattice M sage: lp.vertices() M(-1, 0), @@ -163,7 +164,7 @@ def lattice_polytope(self, envelope=False): to add the argument "envelope=True" to compute an enveloping lattice polytope. sage: lp = P.lattice_polytope(True) - sage: lp # optional - palp + sage: lp # optional - polytopes_db, needs palp 2-d reflexive polytope #5 in 2-d lattice M sage: lp.vertices() M(-1, 0), @@ -207,9 +208,9 @@ def _integral_points_PALP(self): EXAMPLES:: - sage: Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)])._integral_points_PALP() # optional - palp + sage: Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)])._integral_points_PALP() # needs palp [M(-1, -1), M(0, 1), M(1, 0), M(1, 1), M(0, 0)] - sage: Polyhedron(vertices=[(-1/2,-1/2),(1,0),(1,1),(0,1)]).lattice_polytope(True).points() # optional - palp + sage: Polyhedron(vertices=[(-1/2,-1/2),(1,0),(1,1),(0,1)]).lattice_polytope(True).points() # needs palp M(-1, -1), M(-1, 0), M( 0, -1), @@ -218,7 +219,7 @@ def _integral_points_PALP(self): M( 1, 0), M( 0, 0) in 2-d lattice M - sage: Polyhedron(vertices=[(-1/2,-1/2),(1,0),(1,1),(0,1)])._integral_points_PALP() # optional - palp + sage: Polyhedron(vertices=[(-1/2,-1/2),(1,0),(1,1),(0,1)])._integral_points_PALP() # needs palp [M(1, 1), M(0, 1), M(1, 0), M(0, 0)] """ if not self.is_compact(): @@ -262,18 +263,19 @@ def h_star_vector(self): volume = `\frac{1}{dim(S)!}`) is always 1. Here we test this on simplices up to dimension 3:: - sage: s1 = polytopes.simplex(1,backend='normaliz') # optional - pynormaliz - sage: s2 = polytopes.simplex(2,backend='normaliz') # optional - pynormaliz - sage: s3 = polytopes.simplex(3,backend='normaliz') # optional - pynormaliz - sage: [s1.h_star_vector(),s2.h_star_vector(),s3.h_star_vector()] # optional - pynormaliz + sage: # optional - pynormaliz + sage: s1 = polytopes.simplex(1,backend='normaliz') + sage: s2 = polytopes.simplex(2,backend='normaliz') + sage: s3 = polytopes.simplex(3,backend='normaliz') + sage: [s1.h_star_vector(), s2.h_star_vector(), s3.h_star_vector()] [[1], [1], [1]] For a less trivial example, we compute the `h^*`-vector of the `0/1`-cube, which has the Eulerian numbers `(3,i)` for `i \in [0,2]` as an `h^*`-vector:: - sage: cube = polytopes.cube(intervals='zero_one', backend='normaliz') # optional - pynormaliz - sage: cube.h_star_vector() # optional - pynormaliz + sage: cube = polytopes.cube(intervals='zero_one', backend='normaliz') # optional - pynormaliz + sage: cube.h_star_vector() # optional - pynormaliz [1, 4, 1] sage: from sage.combinat.combinat import eulerian_number sage: [eulerian_number(3,i) for i in range(3)] @@ -293,8 +295,8 @@ def h_star_vector(self): ... TypeError: The h_star vector is only defined for lattice polytopes - sage: t2 = Polyhedron(vertices=[[AA(sqrt(2))],[1/2]]) - sage: t2.h_star_vector() + sage: t2 = Polyhedron(vertices=[[AA(sqrt(2))], [1/2]]) # needs sage.rings.number_field sage.symbolic + sage: t2.h_star_vector() # needs sage.rings.number_field sage.symbolic Traceback (most recent call last): ... TypeError: The h_star vector is only defined for lattice polytopes @@ -445,9 +447,9 @@ def integral_points(self, threshold=100000): sage: pts1 = P.integral_points() # Sage's own code sage: all(P.contains(p) for p in pts1) True - sage: pts2 = LatticePolytope(v).points() # optional - palp + sage: pts2 = LatticePolytope(v).points() # needs palp sage: for p in pts1: p.set_immutable() - sage: set(pts1) == set(pts2) # optional - palp + sage: set(pts1) == set(pts2) # needs palp True sage: timeit('Polyhedron(v).integral_points()') # not tested - random @@ -641,13 +643,15 @@ def random_integral_point(self, **kwds): EXAMPLES:: sage: P = Polyhedron(vertices=[(-1,-1),(1,0),(1,1),(0,1)]) - sage: P.random_integral_point() # random + sage: P.random_integral_point() # random (0, 0) sage: P.random_integral_point() in P.integral_points() True - sage: P.random_integral_point(explicit_enumeration_threshold=0, triangulation='cddlib') # random, optional - latte_int + sage: P.random_integral_point(explicit_enumeration_threshold=0, # random, optional - latte_int + ....: triangulation='cddlib') (1, 1) - sage: P.random_integral_point(explicit_enumeration_threshold=0, triangulation='cddlib', foo=7) # optional - latte_int + sage: P.random_integral_point(explicit_enumeration_threshold=0, # optional - latte_int + ....: triangulation='cddlib', foo=7) Traceback (most recent call last): ... RuntimeError: ... @@ -764,9 +768,9 @@ def generating_function_of_integral_points(self, **kwds): EXAMPLES:: - sage: P2 = ( - ....: Polyhedron(ieqs=[(0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, -1)]), - ....: Polyhedron(ieqs=[(0, -1, 0, 1), (0, 1, 0, 0), (0, 0, 1, 0)])) + sage: # needs sage.combinat + sage: P2 = (Polyhedron(ieqs=[(0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, -1)]), + ....: Polyhedron(ieqs=[(0, -1, 0, 1), (0, 1, 0, 0), (0, 0, 1, 0)])) sage: P2[0].generating_function_of_integral_points(sort_factors=True) 1 * (-y0 + 1)^-1 * (-y1 + 1)^-1 * (-y0*y2 + 1)^-1 sage: P2[1].generating_function_of_integral_points(sort_factors=True) @@ -781,6 +785,7 @@ def generating_function_of_integral_points(self, **kwds): The number of integer partitions `1 \leq r_0 \leq r_1 \leq r_2 \leq r_3 \leq r_4`:: + sage: # needs sage.combinat sage: P = Polyhedron(ieqs=[(-1, 1, 0, 0, 0, 0), (0, -1, 1, 0, 0, 0), ....: (0, 0, -1, 1, 0, 0), (0, 0, 0, -1, 1, 0), ....: (0, 0, 0, 0, -1, 1)]) @@ -793,8 +798,8 @@ def generating_function_of_integral_points(self, **kwds): z^5 + z^6 + 2*z^7 + 3*z^8 + 5*z^9 + 7*z^10 + 10*z^11 + 13*z^12 + 18*z^13 + 23*z^14 + 30*z^15 + 37*z^16 + 47*z^17 + 57*z^18 + 70*z^19 + 84*z^20 + 101*z^21 + 119*z^22 + 141*z^23 + 164*z^24 + O(z^25) - sage: [Partitions(k, length=5).cardinality() for k in range(5,20)] == \ - ....: c.truncate().coefficients(sparse=False)[5:20] + sage: ([Partitions(k, length=5).cardinality() for k in range(5,20)] == + ....: c.truncate().coefficients(sparse=False)[5:20]) True .. SEEALSO:: diff --git a/src/sage/geometry/polyhedron/base3.py b/src/sage/geometry/polyhedron/base3.py index 55bd007f234..8904d9fac82 100644 --- a/src/sage/geometry/polyhedron/base3.py +++ b/src/sage/geometry/polyhedron/base3.py @@ -23,7 +23,7 @@ # Copyright (C) 2019 Julian Ritter # Copyright (C) 2019-2020 Laith Rastanawi # Copyright (C) 2019-2020 Sophia Elia -# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -135,8 +135,9 @@ def slack_matrix(self): [1 0 1 0 0 1] [1 0 0 0 1 1] - sage: P = polytopes.dodecahedron().faces(2)[0].as_polyhedron() # optional - sage.rings.number_field - sage: P.slack_matrix() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron().faces(2)[0].as_polyhedron() + sage: P.slack_matrix() [1/2*sqrt5 - 1/2 0 0 1 1/2*sqrt5 - 1/2 0] [ 0 0 1/2*sqrt5 - 1/2 1/2*sqrt5 - 1/2 1 0] [ 0 1/2*sqrt5 - 1/2 1 0 1/2*sqrt5 - 1/2 0] @@ -153,7 +154,7 @@ def slack_matrix(self): sage: Polyhedron().slack_matrix() [] - sage: Polyhedron(base_ring=QuadraticField(2)).slack_matrix().base_ring() # optional - sage.rings.number_field + sage: Polyhedron(base_ring=QuadraticField(2)).slack_matrix().base_ring() # needs sage.rings.number_field Number Field in a with defining polynomial x^2 - 2 with a = 1.41... """ if not self.n_Vrepresentation() or not self.n_Hrepresentation(): @@ -274,7 +275,7 @@ def incidence_matrix(self): sage: P = polytopes.twenty_four_cell() sage: M = P.incidence_matrix() - sage: sum(sum(x) for x in M) == P.flag_f_vector(0, 3) # optional - sage.combinat + sage: sum(sum(x) for x in M) == P.flag_f_vector(0, 3) # needs sage.combinat True TESTS: @@ -287,10 +288,11 @@ def incidence_matrix(self): Test that this method works for inexact base ring (``cdd`` sets the cache already):: - sage: P = polytopes.dodecahedron(exact=False) # optional - sage.groups - sage: M = P.incidence_matrix.cache # optional - sage.groups - sage: P.incidence_matrix.clear_cache() # optional - sage.groups - sage: M == P.incidence_matrix() # optional - sage.groups + sage: # needs sage.groups + sage: P = polytopes.dodecahedron(exact=False) + sage: M = P.incidence_matrix.cache + sage: P.incidence_matrix.clear_cache() + sage: M == P.incidence_matrix() True """ if self.base_ring() in (ZZ, QQ): @@ -604,7 +606,7 @@ def face_generator(self, face_dimension=None, algorithm=None, **kwds): A 1-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 2 vertices, A 1-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 2 vertices] - Check that we catch incorrect algorithms: + Check that we catch incorrect algorithms:: sage: list(P.face_generator(2, algorithm='integrate'))[:4] Traceback (most recent call last): @@ -629,7 +631,6 @@ def face_generator(self, face_dimension=None, algorithm=None, **kwds): if 'dual' in kwds and dual is None: dual = kwds['dual'] - from sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator import FaceIterator_geom return FaceIterator_geom(self, output_dimension=face_dimension, dual=dual) @@ -1009,8 +1010,8 @@ def vertex_adjacency_matrix(self, algorithm=None): sage: M = Q.vertex_adjacency_matrix() sage: sum(M) (4, 4, 3, 3, 4, 4, 4, 3, 3) - sage: G = Q.vertex_graph() # optional - sage.graphs - sage: G.degree() # optional - sage.graphs + sage: G = Q.vertex_graph() # needs sage.graphs + sage: G.degree() # needs sage.graphs [4, 4, 3, 3, 4, 4, 4, 3, 3] TESTS: @@ -1155,11 +1156,11 @@ def simplicity(self): EXAMPLES:: - sage: polytopes.hypersimplex(4,2).simplicity() # optional - sage.combinat + sage: polytopes.hypersimplex(4,2).simplicity() 1 - sage: polytopes.hypersimplex(5,2).simplicity() # optional - sage.combinat + sage: polytopes.hypersimplex(5,2).simplicity() 2 - sage: polytopes.hypersimplex(6,2).simplicity() # optional - sage.combinat + sage: polytopes.hypersimplex(6,2).simplicity() 3 sage: polytopes.simplex(3).simplicity() 3 @@ -1208,7 +1209,7 @@ def simpliciality(self): sage: polytopes.cyclic_polytope(10,4).simpliciality() 3 - sage: polytopes.hypersimplex(5,2).simpliciality() # optional - sage.combinat + sage: polytopes.hypersimplex(5,2).simpliciality() 2 sage: polytopes.cross_polytope(4).simpliciality() 3 @@ -1294,8 +1295,8 @@ def is_pyramid(self, certificate=False): True sage: P.is_pyramid(certificate=True) (True, A vertex at (1, 0, 0, 0)) - sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() # optional - sage.rings.number_field - sage: egyptian_pyramid.is_pyramid() # optional - sage.rings.number_field + sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() # needs sage.rings.number_field + sage: egyptian_pyramid.is_pyramid() # needs sage.rings.number_field True sage: Q = polytopes.octahedron() sage: Q.is_pyramid() @@ -1464,13 +1465,13 @@ def is_lawrence_polytope(self): EXAMPLES:: - sage: P = polytopes.hypersimplex(5,2) # optional - sage.combinat - sage: L = P.lawrence_polytope() # optional - sage.combinat - sage: L.is_lattice_polytope() # optional - sage.combinat + sage: P = polytopes.hypersimplex(5,2) + sage: L = P.lawrence_polytope() + sage: L.is_lattice_polytope() True - sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() # optional - sage.number_field - sage: egyptian_pyramid.is_lawrence_polytope() # optional - sage.number_field + sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() # needs sage.number_field + sage: egyptian_pyramid.is_lawrence_polytope() # needs sage.number_field True sage: polytopes.octahedron().is_lawrence_polytope() diff --git a/src/sage/geometry/polyhedron/base4.py b/src/sage/geometry/polyhedron/base4.py index 7e8aeb32890..5313d64b357 100644 --- a/src/sage/geometry/polyhedron/base4.py +++ b/src/sage/geometry/polyhedron/base4.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.graphs +# sage.doctest: needs sage.graphs r""" Base class for polyhedra: Graph-theoretic methods @@ -24,7 +24,7 @@ # Copyright (C) 2019 Julian Ritter # Copyright (C) 2019-2020 Laith Rastanawi # Copyright (C) 2019-2020 Sophia Elia -# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -95,7 +95,7 @@ def vertex_facet_graph(self, labels=True): sage: P = polytopes.cube() sage: G = P.vertex_facet_graph(); G Digraph on 14 vertices - sage: G.vertices(key = lambda v: str(v)) + sage: G.vertices(sort=True, key=lambda v: str(v)) [A vertex at (-1, -1, -1), A vertex at (-1, -1, 1), A vertex at (-1, 1, -1), @@ -353,7 +353,7 @@ def face_lattice(self): sage: c5_20_fl = c5_20.face_lattice() # long time sage: [len(x) for x in c5_20_fl.level_sets()] # long time [1, 20, 190, 580, 680, 272, 1] - sage: polytopes.hypercube(2).face_lattice().plot() # optional - sage.plot + sage: polytopes.hypercube(2).face_lattice().plot() # needs sage.plot Graphics object consisting of 27 graphics primitives sage: level_sets = polytopes.cross_polytope(2).face_lattice().level_sets() sage: level_sets[0][0].ambient_V_indices(), level_sets[-1][0].ambient_V_indices() @@ -399,31 +399,33 @@ def hasse_diagram(self): EXAMPLES:: - sage: P = polytopes.regular_polygon(4).pyramid() # optional - sage.rings.number_field - sage: D = P.hasse_diagram(); D # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.regular_polygon(4).pyramid() + sage: D = P.hasse_diagram(); D Digraph on 20 vertices - sage: D.degree_polynomial() # optional - sage.rings.number_field + sage: D.degree_polynomial() x^5 + x^4*y + x*y^4 + y^5 + 4*x^3*y + 8*x^2*y^2 + 4*x*y^3 Faces of an mutable polyhedron are not hashable. Hence those are not suitable as vertices of the hasse diagram. Use the combinatorial polyhedron instead:: - sage: P = polytopes.regular_polygon(4).pyramid() # optional - sage.rings.number_field - sage: parent = P.parent() # optional - sage.rings.number_field - sage: parent = parent.change_ring(QQ, backend='ppl') # optional - sage.rings.number_field - sage: Q = parent._element_constructor_(P, mutable=True) # optional - sage.rings.number_field - sage: Q.hasse_diagram() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.regular_polygon(4).pyramid() + sage: parent = P.parent() + sage: parent = parent.change_ring(QQ, backend='ppl') + sage: Q = parent._element_constructor_(P, mutable=True) + sage: Q.hasse_diagram() Traceback (most recent call last): ... TypeError: mutable polyhedra are unhashable - sage: C = Q.combinatorial_polyhedron() # optional - sage.rings.number_field - sage: D = C.hasse_diagram() # optional - sage.rings.number_field - sage: set(D.vertices()) == set(range(20)) # optional - sage.rings.number_field + sage: C = Q.combinatorial_polyhedron() + sage: D = C.hasse_diagram() + sage: set(D.vertices(sort=False)) == set(range(20)) True sage: def index_to_combinatorial_face(n): ....: return C.face_by_face_lattice_index(n) - sage: D.relabel(index_to_combinatorial_face, inplace=True) # optional - sage.rings.number_field - sage: D.vertices() # optional - sage.rings.number_field + sage: D.relabel(index_to_combinatorial_face, inplace=True) + sage: D.vertices(sort=True) [A -1-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, @@ -444,7 +446,7 @@ def hasse_diagram(self): A 2-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron, A 3-dimensional face of a 3-dimensional combinatorial polyhedron] - sage: D.degree_polynomial() # optional - sage.rings.number_field + sage: D.degree_polynomial() x^5 + x^4*y + x*y^4 + y^5 + 4*x^3*y + 8*x^2*y^2 + 4*x*y^3 """ @@ -643,7 +645,8 @@ def combinatorial_automorphism_group(self, vertex_graph_only=False): EXAMPLES:: sage: quadrangle = Polyhedron(vertices=[(0,0),(1,0),(0,1),(2,3)]) - sage: quadrangle.combinatorial_automorphism_group().is_isomorphic(groups.permutation.Dihedral(4)) + sage: quadrangle.combinatorial_automorphism_group().is_isomorphic( + ....: groups.permutation.Dihedral(4)) True sage: quadrangle.restricted_automorphism_group() Permutation Group with generators [()] @@ -655,19 +658,24 @@ def combinatorial_automorphism_group(self, vertex_graph_only=False): Permutation Group with generators [(A vertex at (1,0),A vertex at (1,1))] This shows an example of two polytopes whose vertex-edge graphs are isomorphic, - but their face_lattices are not isomorphic:: - - sage: Q=Polyhedron([[-123984206864/2768850730773, -101701330976/922950243591, -64154618668/2768850730773, -2748446474675/2768850730773], - ....: [-11083969050/98314591817, -4717557075/98314591817, -32618537490/98314591817, -91960210208/98314591817], - ....: [-9690950/554883199, -73651220/554883199, 1823050/554883199, -549885101/554883199], [-5174928/72012097, 5436288/72012097, -37977984/72012097, 60721345/72012097], - ....: [-19184/902877, 26136/300959, -21472/902877, 899005/902877], [53511524/1167061933, 88410344/1167061933, 621795064/1167061933, 982203941/1167061933], - ....: [4674489456/83665171433, -4026061312/83665171433, 28596876672/83665171433, -78383796375/83665171433], [857794884940/98972360190089, -10910202223200/98972360190089, 2974263671400/98972360190089, -98320463346111/98972360190089]]) + but their face lattices are not isomorphic:: + + sage: Q = Polyhedron([[-123984206864/2768850730773, -101701330976/922950243591, -64154618668/2768850730773, -2748446474675/2768850730773], + ....: [-11083969050/98314591817, -4717557075/98314591817, -32618537490/98314591817, -91960210208/98314591817], + ....: [-9690950/554883199, -73651220/554883199, 1823050/554883199, -549885101/554883199], + ....: [-5174928/72012097, 5436288/72012097, -37977984/72012097, 60721345/72012097], + ....: [-19184/902877, 26136/300959, -21472/902877, 899005/902877], + ....: [53511524/1167061933, 88410344/1167061933, 621795064/1167061933, 982203941/1167061933], + ....: [4674489456/83665171433, -4026061312/83665171433, 28596876672/83665171433, -78383796375/83665171433], + ....: [857794884940/98972360190089, -10910202223200/98972360190089, 2974263671400/98972360190089, -98320463346111/98972360190089]]) sage: C = polytopes.cyclic_polytope(4,8) sage: C.is_combinatorially_isomorphic(Q) False - sage: C.combinatorial_automorphism_group(vertex_graph_only=True).is_isomorphic(Q.combinatorial_automorphism_group(vertex_graph_only=True)) + sage: C.combinatorial_automorphism_group(vertex_graph_only=True).is_isomorphic( + ....: Q.combinatorial_automorphism_group(vertex_graph_only=True)) True - sage: C.combinatorial_automorphism_group(vertex_graph_only=False).is_isomorphic(Q.combinatorial_automorphism_group(vertex_graph_only=False)) + sage: C.combinatorial_automorphism_group(vertex_graph_only=False).is_isomorphic( + ....: Q.combinatorial_automorphism_group(vertex_graph_only=False)) False The automorphism group of the face lattice is isomorphic to the combinatorial automorphism group:: @@ -1080,10 +1088,10 @@ def is_combinatorially_isomorphic(self, other, algorithm='bipartite_graph'): All the faces of the 3-dimensional permutahedron are either combinatorially isomorphic to a square or a hexagon:: - sage: H = polytopes.regular_polygon(6) # optional - sage.rings.number_field + sage: H = polytopes.regular_polygon(6) # needs sage.rings.number_field sage: S = polytopes.hypercube(2) sage: P = polytopes.permutahedron(4) - sage: all(F.as_polyhedron().is_combinatorially_isomorphic(S) # optional - sage.rings.number_field + sage: all(F.as_polyhedron().is_combinatorially_isomorphic(S) # needs sage.rings.number_field ....: or F.as_polyhedron().is_combinatorially_isomorphic(H) ....: for F in P.faces(2)) True @@ -1102,7 +1110,7 @@ def is_combinatorially_isomorphic(self, other, algorithm='bipartite_graph'): ....: return C.intersection(H) sage: [simplex_intersection(k).is_combinatorially_isomorphic(cube_intersection(k)) for k in range(2,5)] [True, True, True] - sage: simplex_intersection(2).is_combinatorially_isomorphic(polytopes.regular_polygon(6)) # optional - sage.rings.number_field + sage: simplex_intersection(2).is_combinatorially_isomorphic(polytopes.regular_polygon(6)) # needs sage.rings.number_field True sage: simplex_intersection(3).is_combinatorially_isomorphic(polytopes.octahedron()) True @@ -1225,7 +1233,7 @@ def is_self_dual(self): True sage: polytopes.cube().is_self_dual() False - sage: polytopes.hypersimplex(5,2).is_self_dual() + sage: polytopes.hypersimplex(5,2).is_self_dual() # needs sage.combinat False sage: P = Polyhedron(vertices=[[1/2, 1/3]], rays=[[1, 1]]).is_self_dual() Traceback (most recent call last): diff --git a/src/sage/geometry/polyhedron/base5.py b/src/sage/geometry/polyhedron/base5.py index 04d1fa0314b..89feb2d7b0f 100644 --- a/src/sage/geometry/polyhedron/base5.py +++ b/src/sage/geometry/polyhedron/base5.py @@ -23,7 +23,7 @@ # Copyright (C) 2019 Julian Ritter # Copyright (C) 2019-2020 Laith Rastanawi # Copyright (C) 2019-2020 Sophia Elia -# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -164,8 +164,8 @@ def polar(self, in_affine_span=False): EXAMPLES:: - sage: p = Polyhedron(vertices = [[0,0,1],[0,1,0],[1,0,0],[0,0,0],[1,1,1]], base_ring=QQ) - sage: p + sage: p = Polyhedron(vertices=[[0,0,1], [0,1,0], [1,0,0], [0,0,0], [1,1,1]], + ....: base_ring=QQ); p A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 5 vertices sage: p.polar() A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 6 vertices @@ -324,7 +324,7 @@ def _test_pyramid(self, tester=None, **options): TESTS: - sage: polytopes.regular_polygon(4)._test_pyramid() # optional - sage.rings.number_field + sage: polytopes.regular_polygon(4)._test_pyramid() # needs sage.rings.number_field """ if tester is None: tester = self._tester(**options) @@ -393,8 +393,7 @@ def bipyramid(self): sage: cross_poly_4d = octahedron.bipyramid() sage: cross_poly_4d.n_vertices() 8 - sage: q = [list(v) for v in cross_poly_4d.vertex_generator()] - sage: q + sage: q = [list(v) for v in cross_poly_4d.vertex_generator()]; q [[-1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], @@ -419,7 +418,7 @@ def bipyramid(self): from itertools import chain new_verts = chain(([0] + list(x) for x in self.vertex_generator()), [[1] + list(c), [-1] + list(c)]) - new_rays = ([0] + r for r in self.rays()) + new_rays = ([0] + r for r in self.rays()) new_lines = ([0] + l for l in self.lines()) new_ieqs = chain(([i.b()] + [ c*i.A() + i.b()] + list(i.A()) for i in self.inequalities()), ([i.b()] + [-c*i.A() - i.b()] + list(i.A()) for i in self.inequalities())) @@ -509,7 +508,7 @@ def prism(self): from itertools import chain new_verts = chain(([0] + v for v in self.vertices()), ([1] + v for v in self.vertices())) - new_rays = ([0] + r for r in self.rays()) + new_rays = ([0] + r for r in self.rays()) new_lines = ([0] + l for l in self.lines()) new_eqns = ([e.b()] + [0] + list(e[1:]) for e in self.equations()) new_ieqs = chain(([i.b()] + [0] + list(i[1:]) for i in self.inequalities()), @@ -639,11 +638,9 @@ def lawrence_polytope(self): sage: L = P.lawrence_polytope(); L A 9-dimensional polyhedron in ZZ^9 defined as the convex hull of 12 vertices sage: V = P.vertices_list() - sage: i = 0 - sage: for v in V: + sage: for i, v in enumerate(V): ....: v = v + i*[0] ....: P = P.lawrence_extension(v) - ....: i = i + 1 sage: P == L True @@ -699,14 +696,17 @@ def minkowski_sum(self, other): A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 13 vertices sage: four_cube = polytopes.hypercube(4) - sage: four_simplex = Polyhedron(vertices = [[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]]) + sage: four_simplex = Polyhedron(vertices=[[0, 0, 0, 1], [0, 0, 1, 0], + ....: [0, 1, 0, 0], [1, 0, 0, 0]]) sage: four_cube + four_simplex A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 36 vertices sage: four_cube.minkowski_sum(four_simplex) == four_cube + four_simplex True - sage: poly_spam = Polyhedron([[3,4,5,2],[1,0,0,1],[0,0,0,0],[0,4,3,2],[-3,-3,-3,-3]], base_ring=ZZ) - sage: poly_eggs = Polyhedron([[5,4,5,4],[-4,5,-4,5],[4,-5,4,-5],[0,0,0,0]], base_ring=QQ) + sage: poly_spam = Polyhedron([[3,4,5,2], [1,0,0,1], [0,0,0,0], + ....: [0,4,3,2], [-3,-3,-3,-3]], base_ring=ZZ) + sage: poly_eggs = Polyhedron([[5,4,5,4], [-4,5,-4,5], + ....: [4,-5,4,-5], [0,0,0,0]], base_ring=QQ) sage: poly_spam + poly_spam + poly_eggs A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 12 vertices """ @@ -771,7 +771,7 @@ def minkowski_difference(self, other): The polyhedra need not be full-dimensional:: - sage: X2 = Polyhedron(vertices=[(-1,-1,0),(1,-1,0),(-1,1,0),(1,1,0)]) + sage: X2 = Polyhedron(vertices=[(-1,-1,0), (1,-1,0), (-1,1,0), (1,1,0)]) sage: Y2 = Polyhedron(vertices=[(0,0,0), (0,1,0), (1,0,0)]) / 2 sage: (X2+Y2)-Y2 == X2 True @@ -782,7 +782,8 @@ def minkowski_difference(self, other): :: sage: four_cube = polytopes.hypercube(4) - sage: four_simplex = Polyhedron(vertices = [[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]]) + sage: four_simplex = Polyhedron(vertices=[[0, 0, 0, 1], [0, 0, 1, 0], + ....: [0, 1, 0, 0], [1, 0, 0, 0]]) sage: four_cube - four_simplex A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 16 vertices sage: four_cube.minkowski_difference(four_simplex) == four_cube - four_simplex @@ -790,8 +791,10 @@ def minkowski_difference(self, other): Coercion of the base ring works:: - sage: poly_spam = Polyhedron([[3,4,5,2],[1,0,0,1],[0,0,0,0],[0,4,3,2],[-3,-3,-3,-3]], base_ring=ZZ) - sage: poly_eggs = Polyhedron([[5,4,5,4],[-4,5,-4,5],[4,-5,4,-5],[0,0,0,0]], base_ring=QQ) / 100 + sage: poly_spam = Polyhedron([[3,4,5,2], [1,0,0,1], [0,0,0,0], + ....: [0,4,3,2], [-3,-3,-3,-3]], base_ring=ZZ) + sage: poly_eggs = Polyhedron([[5,4,5,4], [-4,5,-4,5], + ....: [4,-5,4,-5], [0,0,0,0]], base_ring=QQ) / 100 sage: poly_spam - poly_eggs A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 5 vertices @@ -867,7 +870,7 @@ def __sub__(self, other): sage: (X-v)+v == X True - sage: Y = Polyhedron(vertices=[(1/2,0),(0,1/2)]) + sage: Y = Polyhedron(vertices=[(1/2,0), (0,1/2)]) sage: (X-Y).Vrepresentation() (A vertex at (1/2, -1), A vertex at (1/2, 1/2), A vertex at (-1, 1/2), A vertex at (-1, -1)) @@ -893,8 +896,8 @@ def product(self, other): EXAMPLES:: - sage: P1 = Polyhedron([[0],[1]], base_ring=ZZ) - sage: P2 = Polyhedron([[0],[1]], base_ring=QQ) + sage: P1 = Polyhedron([[0], [1]], base_ring=ZZ) + sage: P2 = Polyhedron([[0], [1]], base_ring=QQ) sage: P1.product(P2) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices @@ -934,14 +937,14 @@ def product(self, other): new_vertices = (tuple(x) + tuple(y) for x in self.vertex_generator() for y in other.vertex_generator()) - self_zero = tuple(0 for _ in range( self.ambient_dim())) + self_zero = tuple(0 for _ in range( self.ambient_dim())) other_zero = tuple(0 for _ in range(other.ambient_dim())) - rays = chain((tuple(r) + other_zero for r in self.ray_generator()), - (self_zero + tuple(r) for r in other.ray_generator())) + rays = chain((tuple(r) + other_zero for r in self.ray_generator()), + (self_zero + tuple(r) for r in other.ray_generator())) - lines = chain((tuple(l) + other_zero for l in self.line_generator()), - (self_zero + tuple(l) for l in other.line_generator())) + lines = chain((tuple(l) + other_zero for l in self.line_generator()), + (self_zero + tuple(l) for l in other.line_generator())) if self.n_vertices() == 0 or other.n_vertices() == 0: # In this case we obtain the empty polyhedron. @@ -950,11 +953,15 @@ def product(self, other): rays = () lines = () - ieqs = chain((tuple(i) + other_zero for i in self.inequality_generator()), - ((i.b(),) + self_zero + tuple(i.A()) for i in other.inequality_generator())) + ieqs = chain((tuple(i) + other_zero + for i in self.inequality_generator()), + ((i.b(),) + self_zero + tuple(i.A()) + for i in other.inequality_generator())) - eqns = chain((tuple(e) + other_zero for e in self.equation_generator()), - ((e.b(),) + self_zero + tuple(e.A()) for e in other.equation_generator())) + eqns = chain((tuple(e) + other_zero + for e in self.equation_generator()), + ((e.b(),) + self_zero + tuple(e.A()) + for e in other.equation_generator())) pref_rep = 'Vrep' if self.n_vertices() + self.n_rays() + other.n_vertices() + other.n_rays() \ <= self.n_inequalities() + other.n_inequalities() else 'Hrep' @@ -1050,7 +1057,7 @@ def join(self, other): sage: C = polytopes.hypercube(5) sage: S = Polyhedron([[1]]) - sage: C.join(S).is_combinatorially_isomorphic(C.pyramid()) # optional - sage.graphs + sage: C.join(S).is_combinatorially_isomorphic(C.pyramid()) # needs sage.graphs True sage: P = polytopes.simplex(backend='cdd') @@ -1151,11 +1158,11 @@ def subdirect_sum(self, other): EXAMPLES:: - sage: P1 = Polyhedron([[1],[2]], base_ring=ZZ) - sage: P2 = Polyhedron([[3],[4]], base_ring=QQ) - sage: sds = P1.subdirect_sum(P2);sds - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 - vertices + sage: P1 = Polyhedron([[1], [2]], base_ring=ZZ) + sage: P2 = Polyhedron([[3], [4]], base_ring=QQ) + sage: sds = P1.subdirect_sum(P2); sds + A 2-dimensional polyhedron in QQ^2 + defined as the convex hull of 4 vertices sage: sds.vertices() (A vertex at (0, 3), A vertex at (0, 4), @@ -1216,8 +1223,8 @@ def direct_sum(self, other): EXAMPLES:: - sage: P1 = Polyhedron([[1],[2]], base_ring=ZZ) - sage: P2 = Polyhedron([[3],[4]], base_ring=QQ) + sage: P1 = Polyhedron([[1], [2]], base_ring=ZZ) + sage: P2 = Polyhedron([[3], [4]], base_ring=QQ) sage: ds = P1.direct_sum(P2);ds A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices sage: ds.vertices() @@ -1293,8 +1300,8 @@ def convex_hull(self, other): sage: a_simplex = polytopes.simplex(3, project=True) sage: verts = a_simplex.vertices() - sage: verts = [[x[0]*3/5+x[1]*4/5, -x[0]*4/5+x[1]*3/5, x[2]] for x in verts] - sage: another_simplex = Polyhedron(vertices = verts) + sage: verts = [[x[0]*3/5 + x[1]*4/5, -x[0]*4/5 + x[1]*3/5, x[2]] for x in verts] + sage: another_simplex = Polyhedron(vertices=verts) sage: simplex_union = a_simplex.convex_hull(another_simplex) sage: simplex_union.n_vertices() 7 @@ -1348,11 +1355,14 @@ def intersection(self, other): Check that :trac:`19012` is fixed:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(5) - sage: P = Polyhedron([[0,0],[0,a],[1,1]]) - sage: Q = Polyhedron(ieqs=[[-1,a,1]]) + sage: P = Polyhedron([[0, 0], [0, a], [1, 1]]) + sage: Q = Polyhedron(ieqs=[[-1, a, 1]]) sage: P.intersection(Q) - A 2-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?)^2 defined as the convex hull of 4 vertices + A 2-dimensional polyhedron in + (Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?)^2 + defined as the convex hull of 4 vertices """ new_ieqs = self.inequalities() + other.inequalities() new_eqns = self.equations() + other.equations() @@ -1456,15 +1466,15 @@ def translation(self, displacement): EXAMPLES:: - sage: P = Polyhedron([[0,0],[1,0],[0,1]], base_ring=ZZ) + sage: P = Polyhedron([[0,0], [1,0], [0,1]], base_ring=ZZ) sage: P.translation([2,1]) A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices - sage: P.translation( vector(QQ,[2,1]) ) + sage: P.translation(vector(QQ, [2,1])) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices TESTS:: - sage: P = Polyhedron([[0,0],[1,0],[0,1]], base_ring=ZZ, backend='field') + sage: P = Polyhedron([[0,0], [1,0], [0,1]], base_ring=ZZ, backend='field') sage: P.translation([2,1]).backend() 'field' @@ -1501,7 +1511,7 @@ def _translation_double_description(self, displacement): EXAMPLES:: - sage: P = Polyhedron([[0,0],[1,0],[0,1]], base_ring=ZZ) + sage: P = Polyhedron([[0,0], [1,0], [0,1]], base_ring=ZZ) sage: Vrep, Hrep, parent = P._translation_double_description([2,1]) sage: [tuple(x) for x in Vrep], [tuple(x) for x in Hrep], parent ([((2, 1), (2, 2), (3, 1)), (), ()], @@ -1541,7 +1551,7 @@ def dilation(self, scalar): EXAMPLES:: - sage: p = Polyhedron(vertices = [[t,t^2,t^3] for t in srange(2,6)]) + sage: p = Polyhedron(vertices=[[t,t^2,t^3] for t in srange(2,6)]) sage: next(p.vertex_generator()) A vertex at (2, 4, 8) sage: p2 = p.dilation(2) @@ -1698,35 +1708,45 @@ def linear_transformation(self, linear_transf, new_base_ring=None): EXAMPLES:: sage: b3 = polytopes.Birkhoff_polytope(3) - sage: proj_mat=matrix([[0,1,0,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0],[0,0,0,0,0,1,0,0,0],[0,0,0,0,0,0,0,1,0]]) + sage: proj_mat = matrix([[0,1,0,0,0,0,0,0,0], [0,0,0,1,0,0,0,0,0], + ....: [0,0,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,1,0]]) sage: b3_proj = proj_mat * b3; b3_proj A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices - sage: square = polytopes.regular_polygon(4) # optional - sage.rings.number_field - sage: square.vertices_list() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: square = polytopes.regular_polygon(4) + sage: square.vertices_list() [[0, -1], [1, 0], [-1, 0], [0, 1]] - sage: transf = matrix([[1,1],[0,1]]) # optional - sage.rings.number_field - sage: sheared = transf * square # optional - sage.rings.number_field - sage: sheared.vertices_list() # optional - sage.rings.number_field + sage: transf = matrix([[1,1], [0,1]]) + sage: sheared = transf * square + sage: sheared.vertices_list() [[-1, -1], [1, 0], [-1, 0], [1, 1]] - sage: sheared == square.linear_transformation(transf) # optional - sage.rings.number_field + sage: sheared == square.linear_transformation(transf) True Specifying the new base ring may avoid coercion failure:: - sage: K.<sqrt2> = QuadraticField(2) # optional - sage.rings.number_field - sage: L.<sqrt3> = QuadraticField(3) # optional - sage.rings.number_field - sage: P = polytopes.cube()*sqrt2 # optional - sage.rings.number_field - sage: M = matrix([[sqrt3, 0, 0], [0, sqrt3, 0], [0, 0, 1]]) # optional - sage.rings.number_field - sage: P.linear_transformation(M, new_base_ring=K.composite_fields(L)[0]) # optional - sage.rings.number_field - A 3-dimensional polyhedron in (Number Field in sqrt2sqrt3 with defining polynomial x^4 - 10*x^2 + 1 with sqrt2sqrt3 = 0.3178372451957823?)^3 defined as the convex hull of 8 vertices + sage: # needs sage.rings.number_field + sage: K.<sqrt2> = QuadraticField(2) + sage: L.<sqrt3> = QuadraticField(3) + sage: P = polytopes.cube()*sqrt2 + sage: M = matrix([[sqrt3, 0, 0], [0, sqrt3, 0], [0, 0, 1]]) + sage: P.linear_transformation(M, new_base_ring=K.composite_fields(L)[0]) + A 3-dimensional polyhedron in + (Number Field in sqrt2sqrt3 with defining polynomial x^4 - 10*x^2 + 1 + with sqrt2sqrt3 = 0.3178372451957823?)^3 + defined as the convex hull of 8 vertices Linear transformation without specified new base ring fails in this case:: - sage: M*P # optional - sage.rings.number_field + sage: M*P # needs sage.rings.number_field Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 3 by 3 dense matrices over Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?' and 'Full MatrixSpace of 3 by 8 dense matrices over Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?' + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 3 by 3 dense matrices over Number Field in sqrt3 + with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?' and + 'Full MatrixSpace of 3 by 8 dense matrices over Number Field in sqrt2 + with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?' TESTS: @@ -1743,7 +1763,7 @@ def linear_transformation(self, linear_transf, new_base_ring=None): A 3-dimensional polyhedron in RDF^4 defined as the convex hull of 5 vertices sage: (1/1 * proj_mat) * b3 A 3-dimensional polyhedron in QQ^4 defined as the convex hull of 5 vertices - sage: (AA(2).sqrt() * proj_mat) * b3 # optional - sage.rings.number_field + sage: (AA(2).sqrt() * proj_mat) * b3 # needs sage.rings.number_field A 3-dimensional polyhedron in AA^4 defined as the convex hull of 5 vertices Check that zero-matrices act correctly:: @@ -1757,13 +1777,17 @@ def linear_transformation(self, linear_transf, new_base_ring=None): sage: Matrix([[0 for _ in range(8)]]) * b3 Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 1 by 8 dense matrices over Integer Ring' and 'Full MatrixSpace of 9 by 6 dense matrices over Integer Ring' + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 1 by 8 dense matrices over Integer Ring' and + 'Full MatrixSpace of 9 by 6 dense matrices over Integer Ring' sage: Matrix(ZZ, []) * b3 A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex sage: Matrix(ZZ, [[],[]]) * b3 Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 0 dense matrices over Integer Ring' and 'Full MatrixSpace of 9 by 6 dense matrices over Integer Ring' + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 0 dense matrices over Integer Ring' and + 'Full MatrixSpace of 9 by 6 dense matrices over Integer Ring' Check that the precomputed double description is correct:: @@ -1938,7 +1962,7 @@ def face_truncation(self, face, linear_coefficients=None, cut_frac=None): A vertex at (-1, -1/3, -1), A vertex at (-1/3, -1, -1), A vertex at (-1, -1, -1/3)) - sage: vertex_trunc2 = Cube.face_truncation(Cube.faces(0)[0],cut_frac=1/2) + sage: vertex_trunc2 = Cube.face_truncation(Cube.faces(0)[0], cut_frac=1/2) sage: vertex_trunc2.f_vector() (1, 10, 15, 7, 1) sage: tuple(f.ambient_V_indices() for f in vertex_trunc2.faces(2)) @@ -1960,7 +1984,7 @@ def face_truncation(self, face, linear_coefficients=None, cut_frac=None): A vertex at (-1, 0, -1), A vertex at (0, -1, -1), A vertex at (-1, -1, 0)) - sage: vertex_trunc3 = Cube.face_truncation(Cube.faces(0)[0],cut_frac=0.3) + sage: vertex_trunc3 = Cube.face_truncation(Cube.faces(0)[0], cut_frac=0.3) sage: vertex_trunc3.vertices() (A vertex at (-1.0, -1.0, 1.0), A vertex at (-1.0, 1.0, -1.0), @@ -1993,7 +2017,7 @@ def face_truncation(self, face, linear_coefficients=None, cut_frac=None): A vertex at (-1/3, 1, 1), A vertex at (-1/3, 1, -1), A vertex at (-1/3, -1, -1)) - sage: face_trunc.face_lattice().is_isomorphic(Cube.face_lattice()) + sage: face_trunc.face_lattice().is_isomorphic(Cube.face_lattice()) # needs sage.combinat sage.graphs True TESTS: @@ -2087,20 +2111,21 @@ def stack(self, face, position=None): ... ValueError: cannot stack onto a vertex - sage: stacked_square_half = cube.stack(square_face,position=1/2) + sage: stacked_square_half = cube.stack(square_face, position=1/2) sage: stacked_square_half.f_vector() (1, 9, 16, 9, 1) - sage: stacked_square_large = cube.stack(square_face,position=10) + sage: stacked_square_large = cube.stack(square_face, position=10) - sage: hexaprism = polytopes.regular_polygon(6).prism() # optional - sage.rings.number_field - sage: hexaprism.f_vector() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: hexaprism = polytopes.regular_polygon(6).prism() + sage: hexaprism.f_vector() (1, 12, 18, 8, 1) - sage: square_face = hexaprism.faces(2)[2] # optional - sage.rings.number_field - sage: stacked_hexaprism = hexaprism.stack(square_face) # optional - sage.rings.number_field - sage: stacked_hexaprism.f_vector() # optional - sage.rings.number_field + sage: square_face = hexaprism.faces(2)[2] + sage: stacked_hexaprism = hexaprism.stack(square_face) + sage: stacked_hexaprism.f_vector() (1, 13, 22, 11, 1) - sage: hexaprism.stack(square_face,position=4) # optional - sage.rings.number_field + sage: hexaprism.stack(square_face, position=4) # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: the chosen position is too large @@ -2122,7 +2147,7 @@ def stack(self, face, position=None): It is possible to stack on unbounded faces:: - sage: Q = Polyhedron(vertices=[[0,1],[1,0]],rays=[[1,1]]) + sage: Q = Polyhedron(vertices=[[0,1], [1,0]], rays=[[1,1]]) sage: E = Q.faces(1) sage: Q.stack(E[0],1/2).Vrepresentation() (A vertex at (0, 1), @@ -2220,11 +2245,12 @@ def wedge(self, face, width=1): EXAMPLES:: - sage: P_4 = polytopes.regular_polygon(4) # optional - sage.rings.number_field - sage: W1 = P_4.wedge(P_4.faces(1)[0]); W1 # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P_4 = polytopes.regular_polygon(4) + sage: W1 = P_4.wedge(P_4.faces(1)[0]); W1 A 3-dimensional polyhedron in AA^3 defined as the convex hull of 6 vertices - sage: triangular_prism = polytopes.regular_polygon(3).prism() # optional - sage.rings.number_field - sage: W1.is_combinatorially_isomorphic(triangular_prism) # optional - sage.graphs # optional - sage.rings.number_field + sage: triangular_prism = polytopes.regular_polygon(3).prism() + sage: W1.is_combinatorially_isomorphic(triangular_prism) # needs sage.graphs True sage: Q = polytopes.hypersimplex(4,2) @@ -2256,9 +2282,9 @@ def wedge(self, face, width=1): A vertex at (0, 1, 1, 0, -1)) sage: C_3_7 = polytopes.cyclic_polytope(3,7) - sage: P_6 = polytopes.regular_polygon(6) # optional - sage.rings.number_field - sage: W4 = P_6.wedge(P_6.faces(1)[0]) # optional - sage.rings.number_field - sage: W4.is_combinatorially_isomorphic(C_3_7.polar()) # optional - sage.graphs # optional - sage.rings.number_field + sage: P_6 = polytopes.regular_polygon(6) # needs sage.rings.number_field + sage: W4 = P_6.wedge(P_6.faces(1)[0]) # needs sage.rings.number_field + sage: W4.is_combinatorially_isomorphic(C_3_7.polar()) # needs sage.graphs sage.rings.number_field True REFERENCES: @@ -2342,10 +2368,11 @@ def face_split(self, face): EXAMPLES:: - sage: pentagon = polytopes.regular_polygon(5) # optional - sage.rings.number_field - sage: f = pentagon.faces(1)[0] # optional - sage.rings.number_field - sage: fsplit_pentagon = pentagon.face_split(f) # optional - sage.rings.number_field - sage: fsplit_pentagon.f_vector() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: pentagon = polytopes.regular_polygon(5) + sage: f = pentagon.faces(1)[0] + sage: fsplit_pentagon = pentagon.face_split(f) + sage: fsplit_pentagon.f_vector() (1, 7, 14, 9, 1) TESTS: @@ -2429,7 +2456,7 @@ def _test_lawrence(self, tester=None, **options): Check that :trac:`28725` is fixed:: - sage: polytopes.regular_polygon(3)._test_lawrence() # optional - sage.rings.number_field + sage: polytopes.regular_polygon(3)._test_lawrence() # needs sage.rings.number_field Check that :trac:`30293` is fixed:: @@ -2538,10 +2565,11 @@ def one_point_suspension(self, vertex): sage: ops_cube.f_vector() (1, 9, 24, 24, 9, 1) - sage: pentagon = polytopes.regular_polygon(5) # optional - sage.rings.number_field - sage: v = pentagon.vertices()[0] # optional - sage.rings.number_field - sage: ops_pentagon = pentagon.one_point_suspension(v) # optional - sage.rings.number_field - sage: ops_pentagon.f_vector() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: pentagon = polytopes.regular_polygon(5) + sage: v = pentagon.vertices()[0] + sage: ops_pentagon = pentagon.one_point_suspension(v) + sage: ops_pentagon.f_vector() (1, 6, 12, 8, 1) It works with a polyhedral face as well:: @@ -2561,7 +2589,9 @@ def one_point_suspension(self, vertex): sage: cube.one_point_suspension(e) Traceback (most recent call last): ... - TypeError: the vertex A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices should be a Vertex or PolyhedronFace of dimension 0 + TypeError: the vertex + A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices + should be a Vertex or PolyhedronFace of dimension 0 """ from sage.geometry.polyhedron.representation import Vertex from sage.geometry.polyhedron.face import PolyhedronFace diff --git a/src/sage/geometry/polyhedron/base6.py b/src/sage/geometry/polyhedron/base6.py index 2dd1117ad79..b9d23daefa1 100644 --- a/src/sage/geometry/polyhedron/base6.py +++ b/src/sage/geometry/polyhedron/base6.py @@ -21,7 +21,7 @@ # Copyright (C) 2019 Julian Ritter # Copyright (C) 2019-2020 Laith Rastanawi # Copyright (C) 2019-2020 Sophia Elia -# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -45,9 +45,9 @@ class Polyhedron_base6(Polyhedron_base5): sage: from sage.geometry.polyhedron.base6 import Polyhedron_base6 sage: P = polytopes.cube() - sage: Polyhedron_base6.plot(P) + sage: Polyhedron_base6.plot(P) # needs sage.plot Graphics3d Object - sage: print(Polyhedron_base6.tikz(P, output_type='TikzPicture')) + sage: print(Polyhedron_base6.tikz(P, output_type='TikzPicture')) # needs sage.plot \RequirePackage{luatex85} \documentclass[tikz]{standalone} \begin{document} @@ -130,7 +130,7 @@ class Polyhedron_base6(Polyhedron_base5): \end{document} sage: Q = polytopes.hypercube(4) - sage: Polyhedron_base6.show(Q) + sage: Polyhedron_base6.show(Q) # needs sage.plot sage: Polyhedron_base6.schlegel_projection(Q) The projection of a polyhedron into 3 dimensions @@ -194,87 +194,93 @@ def plot(self, By default, the wireframe is rendered in blue and the fill in green:: - sage: square.plot() # optional - sage.plot + sage: # needs sage.plot + sage: square.plot() Graphics object consisting of 6 graphics primitives - sage: point.plot() # optional - sage.plot + sage: point.plot() Graphics object consisting of 1 graphics primitive - sage: line.plot() # optional - sage.plot + sage: line.plot() Graphics object consisting of 2 graphics primitives - sage: cube.plot() # optional - sage.plot + sage: cube.plot() Graphics3d Object - sage: hypercube.plot() # optional - sage.plot + sage: hypercube.plot() Graphics3d Object Draw the lines in red and nothing else:: - sage: square.plot(point=False, line='red', polygon=False) # optional - sage.plot + sage: # needs sage.plot + sage: square.plot(point=False, line='red', polygon=False) Graphics object consisting of 4 graphics primitives - sage: point.plot(point=False, line='red', polygon=False) # optional - sage.plot + sage: point.plot(point=False, line='red', polygon=False) Graphics object consisting of 0 graphics primitives - sage: line.plot(point=False, line='red', polygon=False) # optional - sage.plot + sage: line.plot(point=False, line='red', polygon=False) Graphics object consisting of 1 graphics primitive - sage: cube.plot(point=False, line='red', polygon=False) # optional - sage.plot + sage: cube.plot(point=False, line='red', polygon=False) Graphics3d Object - sage: hypercube.plot(point=False, line='red', polygon=False) # optional - sage.plot + sage: hypercube.plot(point=False, line='red', polygon=False) Graphics3d Object Draw points in red, no lines, and a blue polygon:: - sage: square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot + sage: # needs sage.plot + sage: square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) Graphics object consisting of 2 graphics primitives - sage: point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot + sage: point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) Graphics object consisting of 1 graphics primitive - sage: line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot + sage: line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) Graphics object consisting of 1 graphics primitive - sage: cube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot + sage: cube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) Graphics3d Object - sage: hypercube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot + sage: hypercube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) Graphics3d Object If we instead use the ``fill`` and ``wireframe`` options, the coloring depends on the dimension of the object:: - sage: square.plot(fill='green', wireframe='red') # optional - sage.plot + sage: # needs sage.plot + sage: square.plot(fill='green', wireframe='red') Graphics object consisting of 6 graphics primitives - sage: point.plot(fill='green', wireframe='red') # optional - sage.plot + sage: point.plot(fill='green', wireframe='red') Graphics object consisting of 1 graphics primitive - sage: line.plot(fill='green', wireframe='red') # optional - sage.plot + sage: line.plot(fill='green', wireframe='red') Graphics object consisting of 2 graphics primitives - sage: cube.plot(fill='green', wireframe='red') # optional - sage.plot + sage: cube.plot(fill='green', wireframe='red') Graphics3d Object - sage: hypercube.plot(fill='green', wireframe='red') # optional - sage.plot + sage: hypercube.plot(fill='green', wireframe='red') Graphics3d Object It is possible to draw polyhedra up to dimension 4, no matter what the ambient dimension is:: sage: hcube = polytopes.hypercube(5) - sage: facet = hcube.facets()[0].as_polyhedron();facet + sage: facet = hcube.facets()[0].as_polyhedron(); facet A 4-dimensional polyhedron in ZZ^5 defined as the convex hull of 16 vertices - sage: facet.plot() # optional - sage.plot + sage: facet.plot() # needs sage.plot Graphics3d Object For a 3d plot, we may draw the polygons with rainbow colors, using any of the following ways:: - sage: cube.plot(polygon='rainbow') # optional - sage.plot + sage: cube.plot(polygon='rainbow') # needs sage.plot Graphics3d Object - sage: cube.plot(polygon={'color':'rainbow'}) # optional - sage.plot + sage: cube.plot(polygon={'color':'rainbow'}) # needs sage.plot Graphics3d Object - sage: cube.plot(fill='rainbow') # optional - sage.plot + sage: cube.plot(fill='rainbow') # needs sage.plot Graphics3d Object For a 3d plot, the size of a point, the thickness of a line and the width of an arrow are controlled by the respective parameters:: sage: prism = Polyhedron(vertices=[[0,0,0],[1,0,0],[0,1,0]], rays=[[0,0,1]]) - sage: prism.plot(size=20, thickness=30, width=1) # optional - sage.plot + sage: prism.plot(size=20, thickness=30, width=1) # needs sage.plot Graphics3d Object - sage: prism.plot(point={'size':20, 'color':'black'}, line={'thickness':30, 'width':1, 'color':'black'}, polygon='rainbow') # optional - sage.plot + sage: prism.plot(point={'size':20, 'color':'black'}, # needs sage.plot + ....: line={'thickness':30, 'width':1, 'color':'black'}, + ....: polygon='rainbow') Graphics3d Object TESTS:: - sage: for p in square.plot(): # optional - sage.plot + sage: for p in square.plot(): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) blue Point set defined by 4 point(s) blue Line defined by 2 points @@ -283,18 +289,18 @@ def plot(self, blue Line defined by 2 points green Polygon defined by 4 points - sage: for p in line.plot(): # optional - sage.plot + sage: for p in line.plot(): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) blue Point set defined by 2 point(s) green Line defined by 2 points - sage: for p in point.plot(): # optional - sage.plot + sage: for p in point.plot(): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) green Point set defined by 1 point(s) Draw the lines in red and nothing else:: - sage: for p in square.plot(point=False, line='red', polygon=False): # optional - sage.plot + sage: for p in square.plot(point=False, line='red', polygon=False): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Line defined by 2 points red Line defined by 2 points @@ -303,66 +309,68 @@ def plot(self, Draw vertices in red, no lines, and a blue polygon:: - sage: for p in square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # optional - sage.plot + sage: for p in square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 4 point(s) (0, 0, 1) Polygon defined by 4 points - sage: for p in line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # optional - sage.plot + sage: for p in line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 2 point(s) - sage: for p in point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # optional - sage.plot + sage: for p in point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 1 point(s) Draw in red without wireframe:: - sage: for p in square.plot(wireframe=False, fill="red"): # optional - sage.plot + sage: for p in square.plot(wireframe=False, fill="red"): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Polygon defined by 4 points - sage: for p in line.plot(wireframe=False, fill="red"): # optional - sage.plot + sage: for p in line.plot(wireframe=False, fill="red"): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Line defined by 2 points - sage: for p in point.plot(wireframe=False, fill="red"): # optional - sage.plot + sage: for p in point.plot(wireframe=False, fill="red"): # needs sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 1 point(s) We try to draw the polytope in 2 or 3 dimensions:: - sage: type(Polyhedron(ieqs=[(1,)]).plot()) # optional - sage.plot + sage: # needs sage.plot + sage: type(Polyhedron(ieqs=[(1,)]).plot()) <class 'sage.plot.graphics.Graphics'> - sage: type(polytopes.hypercube(1).plot()) # optional - sage.plot + sage: type(polytopes.hypercube(1).plot()) <class 'sage.plot.graphics.Graphics'> - sage: type(polytopes.hypercube(2).plot()) # optional - sage.plot + sage: type(polytopes.hypercube(2).plot()) <class 'sage.plot.graphics.Graphics'> - sage: type(polytopes.hypercube(3).plot()) # optional - sage.plot + sage: type(polytopes.hypercube(3).plot()) <class 'sage.plot.plot3d.base.Graphics3dGroup'> In 4d a projection to 3d is used:: - sage: type(polytopes.hypercube(4).plot()) # optional - sage.plot + sage: type(polytopes.hypercube(4).plot()) # needs sage.plot <class 'sage.plot.plot3d.base.Graphics3dGroup'> - sage: type(polytopes.hypercube(5).plot()) # optional - sage.plot + sage: type(polytopes.hypercube(5).plot()) Traceback (most recent call last): ... NotImplementedError: plotting of 5-dimensional polyhedra not implemented If the polyhedron is not full-dimensional, the :meth:`affine_hull_projection` is used if necessary:: - sage: type(Polyhedron([(0,), (1,)]).plot()) # optional - sage.plot + sage: # needs sage.plot + sage: type(Polyhedron([(0,), (1,)]).plot()) <class 'sage.plot.graphics.Graphics'> - sage: type(Polyhedron([(0,0), (1,1)]).plot()) # optional - sage.plot + sage: type(Polyhedron([(0,0), (1,1)]).plot()) <class 'sage.plot.graphics.Graphics'> - sage: type(Polyhedron([(0,0,0), (1,1,1)]).plot()) # optional - sage.plot + sage: type(Polyhedron([(0,0,0), (1,1,1)]).plot()) <class 'sage.plot.plot3d.base.Graphics3dGroup'> - sage: type(Polyhedron([(0,0,0,0), (1,1,1,1)]).plot()) # optional - sage.plot + sage: type(Polyhedron([(0,0,0,0), (1,1,1,1)]).plot()) <class 'sage.plot.graphics.Graphics'> - sage: type(Polyhedron([(0,0,0,0,0), (1,1,1,1,1)]).plot()) # optional - sage.plot + sage: type(Polyhedron([(0,0,0,0,0), (1,1,1,1,1)]).plot()) <class 'sage.plot.graphics.Graphics'> - sage: type(Polyhedron([(0,0,0,0), (1,1,1,1), (1,0,0,0)]).plot()) # optional - sage.plot + sage: type(Polyhedron([(0,0,0,0), (1,1,1,1), (1,0,0,0)]).plot()) <class 'sage.plot.graphics.Graphics'> TESTS: @@ -380,28 +388,29 @@ def plot(self, Check that :trac:`31802` is fixed:: + sage: # needs sage.plot sage: halfspace = Polyhedron(rays=[(0, 0, 1)], lines=[(1, 0, 0), (0, 1, 0)]) sage: len(halfspace.projection().arrows) 5 - sage: halfspace.plot(fill=(0,1,0)) + sage: halfspace.plot(fill=(0, 1, 0)) Graphics3d Object sage: fullspace = Polyhedron(lines=[(1, 0, 0), (0, 1, 0), (0, 0, 1)]) sage: len(fullspace.projection().arrows) 6 - sage: fullspace.plot(color=(1,0,0), alpha=0.5) + sage: fullspace.plot(color=(1, 0, 0), alpha=0.5) Graphics3d Object sage: cone = Polyhedron(rays=[(1, 0, 0), (0, 1, 0), (0, 0, 1)]) sage: cone.plot(fill='rainbow', alpha=0.6) Graphics3d Object - sage: p = Polyhedron(vertices=[(0,0,0),(1,0,0)],rays=[(-1,1,0),(1,1,0),(0,0,1)]) + sage: p = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0)], rays=[(-1, 1, 0), (1, 1, 0), (0, 0, 1)]) sage: p.plot(fill='mediumspringgreen', point='red', size=30, width=2) Graphics3d Object - sage: cylinder = Polyhedron(vertices = [(0, 0, 0), (1, 0, 0), (0, 1, 0)], lines=[(0, 0, 1)]) - sage: cylinder.plot(fill='red') # check it is not all black + sage: cylinder = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0)], lines=[(0, 0, 1)]) + sage: cylinder.plot(fill='red') # check it is not all black # needs sage.plot Graphics3d Object - sage: quarter = Polyhedron(rays = [(-1, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]) - sage: quarter.plot(fill='rainbow') # check it is not all black nor with too many colors + sage: quarter = Polyhedron(rays=[(-1, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]) + sage: quarter.plot(fill='rainbow') # check it is not all black nor with too many colors # needs sage.plot Graphics3d Object """ def merge_options(*opts): @@ -470,7 +479,7 @@ def show(self, **kwds): EXAMPLES:: sage: square = polytopes.hypercube(2) - sage: square.show(point='red') # optional - sage.plot + sage: square.show(point='red') # needs sage.plot """ self.plot(**kwds).show() @@ -544,8 +553,9 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, EXAMPLES:: + sage: # needs sage.plot sage: co = polytopes.cuboctahedron() - sage: Img = co.tikz([0,0,1], 0, output_type='TikzPicture') + sage: Img = co.tikz([0, 0, 1], 0, output_type='TikzPicture') sage: Img \documentclass[tikz]{standalone} \begin{document} @@ -581,9 +591,9 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, When output type is a :class:`sage.misc.latex_standalone.TikzPicture`:: + sage: # needs sage.plot sage: co = polytopes.cuboctahedron() - sage: t = co.tikz([674,108,-731], 112, output_type='TikzPicture') - sage: t + sage: t = co.tikz([674, 108, -731], 112, output_type='TikzPicture'); t \documentclass[tikz]{standalone} \begin{document} \begin{tikzpicture}% @@ -600,7 +610,7 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, %% \end{tikzpicture} \end{document} - sage: path_to_file = t.pdf() # not tested + sage: path_to_file = t.pdf() # not tested """ return self.projection().tikz(view, angle, scale, @@ -692,8 +702,8 @@ def gale_transform(self): Check that :trac:`29073` is fixed:: - sage: P = polytopes.icosahedron(exact=False) - sage: sum(P.gale_transform()).norm() < 1e-15 + sage: P = polytopes.icosahedron(exact=False) # needs sage.groups + sage: sum(P.gale_transform()).norm() < 1e-15 # needs sage.groups True """ if not self.is_compact(): @@ -784,8 +794,8 @@ def render_solid(self, **kwds): EXAMPLES:: sage: p = polytopes.hypercube(3) - sage: p_solid = p.render_solid(opacity = .7) - sage: type(p_solid) + sage: p_solid = p.render_solid(opacity=.7) # needs sage.plot + sage: type(p_solid) # needs sage.plot <class 'sage.plot.plot3d.index_face_set.IndexFaceSet'> """ proj = self.projection() @@ -803,8 +813,8 @@ def render_wireframe(self, **kwds): EXAMPLES:: sage: p = Polyhedron([[1,2,],[1,1],[0,0]]) - sage: p_wireframe = p.render_wireframe() - sage: p_wireframe._objects + sage: p_wireframe = p.render_wireframe() # needs sage.plot + sage: p_wireframe._objects # needs sage.plot [Line defined by 2 points, Line defined by 2 points, Line defined by 2 points] """ proj = self.projection() @@ -853,30 +863,31 @@ def schlegel_projection(self, facet=None, position=None): sage: tfcube.facets()[-1] A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 8 vertices sage: sp = tfcube.schlegel_projection(tfcube.facets()[-1]) - sage: sp.plot() # optional - sage.plot + sage: sp.plot() # needs sage.plot Graphics3d Object The same truncated cube but see inside the tetrahedral facet:: sage: tfcube.facets()[4] A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 4 vertices - sage: sp = tfcube.schlegel_projection(tfcube.facets()[4]) - sage: sp.plot() # optional - sage.plot + sage: sp = tfcube.schlegel_projection(tfcube.facets()[4]) # needs sage.symbolic + sage: sp.plot() # needs sage.plot sage.symbolic Graphics3d Object A different values of ``position`` changes the projection:: - sage: sp = tfcube.schlegel_projection(tfcube.facets()[4],1/2) - sage: sp.plot() # optional - sage.plot + sage: # needs sage.symbolic + sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 1/2) + sage: sp.plot() # needs sage.plot Graphics3d Object - sage: sp = tfcube.schlegel_projection(tfcube.facets()[4],4) - sage: sp.plot() # optional - sage.plot + sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 4) + sage: sp.plot() # needs sage.plot Graphics3d Object A value which is too large give a projection point that sees more than one facet resulting in a error:: - sage: sp = tfcube.schlegel_projection(tfcube.facets()[4],5) + sage: sp = tfcube.schlegel_projection(tfcube.facets()[4], 5) Traceback (most recent call last): ... ValueError: the chosen position is too large @@ -936,10 +947,11 @@ def _affine_hull_projection(self, *, Check that :trac:`24047` is fixed:: - sage: P1 = Polyhedron(vertices=([[-1, 1], [0, -1], [0, 0], [-1, -1]])) + sage: P1 = Polyhedron(vertices=[[-1, 1], [0, -1], [0, 0], [-1, -1]]) sage: P2 = Polyhedron(vertices=[[1, 1], [1, -1], [0, -1], [0, 0]]) sage: P = P1.intersection(P2) - sage: A, b = P.affine_hull_projection(as_affine_map=True, orthonormal=True, extend=True) # optional - sage.rings.number_field + sage: A, b = P.affine_hull_projection(as_affine_map=True, + ....: orthonormal=True, extend=True) sage: Polyhedron([(2,3,4)]).affine_hull_projection() A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex @@ -950,27 +962,26 @@ def _affine_hull_projection(self, *, 'field' sage: P = Polyhedron(vertices=[[0,0], [1,0]], backend='field') - sage: P.affine_hull_projection(orthogonal=True, orthonormal=True, extend=True).backend() # optional - sage.rings.number_field + sage: P.affine_hull_projection(orthogonal=True, orthonormal=True, + ....: extend=True).backend() 'field' Check that :trac:`29116` is fixed:: - sage: V =[ - ....: [1, 0, -1, 0, 0], - ....: [1, 0, 0, -1, 0], - ....: [1, 0, 0, 0, -1], - ....: [1, 0, 0, +1, 0], - ....: [1, 0, 0, 0, +1], - ....: [1, +1, 0, 0, 0] - ....: ] + sage: V = [[1, 0, -1, 0, 0], + ....: [1, 0, 0, -1, 0], + ....: [1, 0, 0, 0, -1], + ....: [1, 0, 0, +1, 0], + ....: [1, 0, 0, 0, +1], + ....: [1, +1, 0, 0, 0]] sage: P = Polyhedron(V) sage: P.affine_hull_projection() A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 6 vertices - sage: P.affine_hull_projection(orthonormal=True) + sage: P.affine_hull_projection(orthonormal=True) # needs sage.symbolic Traceback (most recent call last): ... ValueError: the base ring needs to be extended; try with "extend=True" - sage: P.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field + sage: P.affine_hull_projection(orthonormal=True, extend=True) # needs sage.rings.number_field A 4-dimensional polyhedron in AA^4 defined as the convex hull of 6 vertices """ result = AffineHullProjectionData() @@ -1176,7 +1187,7 @@ def affine_hull_projection(self, The resulting affine hulls depend on the parameter ``orthogonal`` and ``orthonormal``:: - sage: L = Polyhedron([[1,0],[0,1]]); L + sage: L = Polyhedron([[1,0], [0,1]]); L A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices sage: A = L.affine_hull_projection(); A A 1-dimensional polyhedron in ZZ^1 defined as the convex hull of 2 vertices @@ -1186,13 +1197,13 @@ def affine_hull_projection(self, A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 2 vertices sage: A.vertices() (A vertex at (0), A vertex at (2)) - sage: A = L.affine_hull_projection(orthonormal=True) # optional - sage.rings.number_field + sage: A = L.affine_hull_projection(orthonormal=True) # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: the base ring needs to be extended; try with "extend=True" - sage: A = L.affine_hull_projection(orthonormal=True, extend=True); A # optional - sage.rings.number_field + sage: A = L.affine_hull_projection(orthonormal=True, extend=True); A # needs sage.rings.number_field A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices - sage: A.vertices() # optional - sage.rings.number_field + sage: A.vertices() # needs sage.rings.number_field (A vertex at (1.414213562373095?), A vertex at (0.?e-18)) More generally:: @@ -1218,9 +1229,9 @@ def affine_hull_projection(self, A vertex at (2, 0, 0), A vertex at (1, 3/2, 0), A vertex at (1, 1/2, 4/3)) - sage: A = S.affine_hull_projection(orthonormal=True, extend=True); A # optional - sage.rings.number_field + sage: A = S.affine_hull_projection(orthonormal=True, extend=True); A # needs sage.rings.number_field A 3-dimensional polyhedron in AA^3 defined as the convex hull of 4 vertices - sage: A.vertices() # optional - sage.rings.number_field + sage: A.vertices() # needs sage.rings.number_field (A vertex at (0.7071067811865475?, 0.4082482904638630?, 1.154700538379252?), A vertex at (0.7071067811865475?, 1.224744871391589?, 0.?e-18), A vertex at (1.414213562373095?, 0.?e-18, 0.?e-18), @@ -1228,82 +1239,108 @@ def affine_hull_projection(self, With the parameter ``minimal`` one can get a minimal base ring:: + sage: # needs sage.rings.number_field sage: s = polytopes.simplex(3) - sage: s_AA = s.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field - sage: s_AA.base_ring() # optional - sage.rings.number_field + sage: s_AA = s.affine_hull_projection(orthonormal=True, extend=True) + sage: s_AA.base_ring() Algebraic Real Field - sage: s_full = s.affine_hull_projection(orthonormal=True, extend=True, minimal=True) # optional - sage.rings.number_field - sage: s_full.base_ring() # optional - sage.rings.number_field - Number Field in a with defining polynomial y^4 - 4*y^2 + 1 with a = 0.5176380902050415? + sage: s_full = s.affine_hull_projection(orthonormal=True, extend=True, + ....: minimal=True) + sage: s_full.base_ring() + Number Field in a with defining polynomial y^4 - 4*y^2 + 1 + with a = 0.5176380902050415? More examples with the ``orthonormal`` parameter:: - sage: P = polytopes.permutahedron(3); P # optional - sage.combinat # optional - sage.rings.number_field + sage: P = polytopes.permutahedron(3); P A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices - sage: set([F.as_polyhedron().affine_hull_projection(orthonormal=True, extend=True).volume() for F in P.affine_hull_projection().faces(1)]) == {1, sqrt(AA(2))} # optional - sage.combinat # optional - sage.rings.number_field + sage: set([F.as_polyhedron().affine_hull_projection( # needs sage.combinat sage.rings.number_field + ....: orthonormal=True, extend=True).volume() + ....: for F in P.affine_hull_projection().faces(1)]) == {1, sqrt(AA(2))} True - sage: set([F.as_polyhedron().affine_hull_projection(orthonormal=True, extend=True).volume() for F in P.affine_hull_projection(orthonormal=True, extend=True).faces(1)]) == {sqrt(AA(2))} # optional - sage.combinat # optional - sage.rings.number_field + sage: set([F.as_polyhedron().affine_hull_projection( # needs sage.combinat sage.rings.number_field + ....: orthonormal=True, extend=True).volume() + ....: for F in P.affine_hull_projection( + ....: orthonormal=True, extend=True).faces(1)]) == {sqrt(AA(2))} True - sage: D = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: F = D.faces(2)[0].as_polyhedron() # optional - sage.rings.number_field - sage: F.affine_hull_projection(orthogonal=True) # optional - sage.rings.number_field - A 2-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^2 defined as the convex hull of 5 vertices - sage: F.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: D = polytopes.dodecahedron() + sage: F = D.faces(2)[0].as_polyhedron() + sage: F.affine_hull_projection(orthogonal=True) + A 2-dimensional polyhedron in + (Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790?)^2 + defined as the convex hull of 5 vertices + sage: F.affine_hull_projection(orthonormal=True, extend=True) A 2-dimensional polyhedron in AA^2 defined as the convex hull of 5 vertices - sage: K.<sqrt2> = QuadraticField(2) # optional - sage.rings.number_field - sage: P = Polyhedron([2*[K.zero()],2*[sqrt2]]); P # optional - sage.rings.number_field - A 1-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?)^2 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K.<sqrt2> = QuadraticField(2) + sage: P = Polyhedron([2*[K.zero()],2*[sqrt2]]); P + A 1-dimensional polyhedron in + (Number Field in sqrt2 with defining polynomial x^2 - 2 + with sqrt2 = 1.414213562373095?)^2 + defined as the convex hull of 2 vertices + sage: P.vertices() (A vertex at (0, 0), A vertex at (sqrt2, sqrt2)) - sage: A = P.affine_hull_projection(orthonormal=True); A # optional - sage.rings.number_field - A 1-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?)^1 defined as the convex hull of 2 vertices - sage: A.vertices() # optional - sage.rings.number_field + sage: A = P.affine_hull_projection(orthonormal=True); A + A 1-dimensional polyhedron in + (Number Field in sqrt2 with defining polynomial x^2 - 2 + with sqrt2 = 1.414213562373095?)^1 + defined as the convex hull of 2 vertices + sage: A.vertices() (A vertex at (0), A vertex at (2)) - sage: K.<sqrt3> = QuadraticField(3) # optional - sage.rings.number_field - sage: P = Polyhedron([2*[K.zero()],2*[sqrt3]]); P # optional - sage.rings.number_field - A 1-dimensional polyhedron in (Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^2 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K.<sqrt3> = QuadraticField(3) + sage: P = Polyhedron([2*[K.zero()], 2*[sqrt3]]); P + A 1-dimensional polyhedron in + (Number Field in sqrt3 with defining polynomial x^2 - 3 + with sqrt3 = 1.732050807568878?)^2 + defined as the convex hull of 2 vertices + sage: P.vertices() (A vertex at (0, 0), A vertex at (sqrt3, sqrt3)) - sage: A = P.affine_hull_projection(orthonormal=True) # optional - sage.rings.number_field + sage: A = P.affine_hull_projection(orthonormal=True) Traceback (most recent call last): ... ValueError: the base ring needs to be extended; try with "extend=True" - sage: A = P.affine_hull_projection(orthonormal=True, extend=True); A # optional - sage.rings.number_field + sage: A = P.affine_hull_projection(orthonormal=True, extend=True); A A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices - sage: A.vertices() # optional - sage.rings.number_field + sage: A.vertices() (A vertex at (0), A vertex at (2.449489742783178?)) - sage: sqrt(6).n() # optional - sage.rings.number_field + sage: sqrt(6).n() 2.44948974278318 The affine hull is combinatorially equivalent to the input:: - sage: P.is_combinatorially_isomorphic(P.affine_hull_projection()) # optional - sage.rings.number_field + sage: P.is_combinatorially_isomorphic(P.affine_hull_projection()) # needs sage.rings.number_field True - sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(orthogonal=True)) # optional - sage.rings.number_field + sage: P.is_combinatorially_isomorphic(P.affine_hull_projection( # needs sage.rings.number_field + ....: orthogonal=True)) True - sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(orthonormal=True, extend=True)) # optional - sage.rings.number_field + sage: P.is_combinatorially_isomorphic(P.affine_hull_projection( # needs sage.rings.number_field + ....: orthonormal=True, extend=True)) True The ``orthonormal=True`` parameter preserves volumes; it provides an isometric copy of the polyhedron:: - sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() # optional - sage.rings.number_field - sage: P = Pentagon.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field - sage: _, c= P.is_inscribed(certificate=True) # optional - sage.rings.number_field - sage: c # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() + sage: P = Pentagon.affine_hull_projection(orthonormal=True, extend=True) + sage: _, c= P.is_inscribed(certificate=True) + sage: c (0.4721359549995794?, 0.6498393924658126?) - sage: circumradius = (c-vector(P.vertices()[0])).norm() # optional - sage.rings.number_field - sage: p = polytopes.regular_polygon(5) # optional - sage.rings.number_field - sage: p.volume() # optional - sage.rings.number_field + sage: circumradius = (c - vector(P.vertices()[0])).norm() + sage: p = polytopes.regular_polygon(5) + sage: p.volume() 2.377641290737884? - sage: P.volume() # optional - sage.rings.number_field + sage: P.volume() 1.53406271079097? - sage: p.volume()*circumradius^2 # optional - sage.rings.number_field + sage: p.volume()*circumradius^2 1.534062710790965? - sage: P.volume() == p.volume()*circumradius^2 # optional - sage.rings.number_field + sage: P.volume() == p.volume()*circumradius^2 True One can also use ``orthogonal`` parameter to calculate volumes; @@ -1311,28 +1348,33 @@ def affine_hull_projection(self, by the square root of the determinant of the linear part of the affine transformation times its transpose:: - sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() # optional - sage.rings.number_field - sage: Pnormal = Pentagon.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field - sage: Pgonal = Pentagon.affine_hull_projection(orthogonal=True) # optional - sage.rings.number_field - sage: A, b = Pentagon.affine_hull_projection(orthogonal=True, as_affine_map=True) # optional - sage.rings.number_field - sage: Adet = (A.matrix().transpose()*A.matrix()).det() # optional - sage.rings.number_field - sage: Pnormal.volume() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() + sage: Pnormal = Pentagon.affine_hull_projection(orthonormal=True, + ....: extend=True) + sage: Pgonal = Pentagon.affine_hull_projection(orthogonal=True) + sage: A, b = Pentagon.affine_hull_projection(orthogonal=True, + ....: as_affine_map=True) + sage: Adet = (A.matrix().transpose()*A.matrix()).det() + sage: Pnormal.volume() 1.53406271079097? - sage: Pgonal.volume()/Adet.sqrt(extend=True) # optional - sage.rings.number_field + sage: Pgonal.volume()/Adet.sqrt(extend=True) -80*(55*sqrt(5) - 123)/sqrt(-6368*sqrt(5) + 14240) - sage: Pgonal.volume()/AA(Adet).sqrt().n(digits=20) # optional - sage.rings.number_field + sage: Pgonal.volume()/AA(Adet).sqrt().n(digits=20) 1.5340627107909646813 - sage: AA(Pgonal.volume()^2) == (Pnormal.volume()^2)*AA(Adet) # optional - sage.rings.number_field + sage: AA(Pgonal.volume()^2) == (Pnormal.volume()^2)*AA(Adet) True Another example with ``as_affine_map=True``:: - sage: P = polytopes.permutahedron(4) # optional - sage.combinat # optional - sage.rings.number_field - sage: A, b = P.affine_hull_projection(orthonormal=True, as_affine_map=True, extend=True) # optional - sage.combinat # optional - sage.rings.number_field - sage: Q = P.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.combinat # optional - sage.rings.number_field - sage: Q.center() # optional - sage.combinat # optional - sage.rings.number_field + sage: # needs sage.combinat sage.rings.number_field + sage: P = polytopes.permutahedron(4) + sage: Q = P.affine_hull_projection(orthonormal=True, extend=True) + sage: A, b = P.affine_hull_projection(orthonormal=True, extend=True, + ....: as_affine_map=True) + sage: Q.center() (0.7071067811865475?, 1.224744871391589?, 1.732050807568878?) - sage: A(P.center()) + b == Q.center() # optional - sage.combinat # optional - sage.rings.number_field + sage: A(P.center()) + b == Q.center() True For unbounded, non full-dimensional polyhedra, the ``orthogonal=True`` and ``orthonormal=True`` @@ -1347,11 +1389,13 @@ def affine_hull_projection(self, sage: P.affine_hull_projection(orthogonal=True) Traceback (most recent call last): ... - NotImplementedError: "orthogonal=True" and "orthonormal=True" work only for compact polyhedra + NotImplementedError: "orthogonal=True" and "orthonormal=True" + work only for compact polyhedra sage: P.affine_hull_projection(orthonormal=True) Traceback (most recent call last): ... - NotImplementedError: "orthogonal=True" and "orthonormal=True" work only for compact polyhedra + NotImplementedError: "orthogonal=True" and "orthonormal=True" + work only for compact polyhedra Setting ``as_affine_map`` to ``True`` without ``orthogonal`` or ``orthonormal`` set to ``True``:: @@ -1387,12 +1431,12 @@ def affine_hull_projection(self, ....: as_polyhedron=True, ....: as_affine_map=True); data AffineHullProjectionData(image=A 2-dimensional polyhedron in QQ^2 - defined as the convex hull of 3 vertices, + defined as the convex hull of 3 vertices, projection_linear_map=Vector space morphism represented by the matrix: [ -1 -1/2] [ 1 -1/2] [ 0 1] - Domain: Vector space of dimension 3 over Rational Field + Domain: Vector space of dimension 3 over Rational Field Codomain: Vector space of dimension 2 over Rational Field, projection_translation=(1, 1/2), section_linear_map=None, @@ -1402,42 +1446,47 @@ def affine_hull_projection(self, sage: data = S.affine_hull_projection(orthogonal=True, return_all_data=True); data AffineHullProjectionData(image=A 2-dimensional polyhedron in QQ^2 - defined as the convex hull of 3 vertices, + defined as the convex hull of 3 vertices, projection_linear_map=Vector space morphism represented by the matrix: [ -1 -1/2] [ 1 -1/2] [ 0 1] - Domain: Vector space of dimension 3 over Rational Field + Domain: Vector space of dimension 3 over Rational Field Codomain: Vector space of dimension 2 over Rational Field, projection_translation=(1, 1/2), section_linear_map=Vector space morphism represented by the matrix: [-1/2 1/2 0] [-1/3 -1/3 2/3] - Domain: Vector space of dimension 2 over Rational Field - Codomain: Vector space of dimension 3 over Rational Field, section_translation=(1, 0, 0)) + Domain: Vector space of dimension 2 over Rational Field + Codomain: Vector space of dimension 3 over Rational Field, + section_translation=(1, 0, 0)) The section map is a right inverse of the projection map:: - sage: data.image.linear_transformation(data.section_linear_map.matrix().transpose()) + data.section_translation == S + sage: mat = data.section_linear_map.matrix().transpose() + sage: data.image.linear_transformation(mat) + data.section_translation == S True Same without ``orthogonal=True``:: sage: data = S.affine_hull_projection(return_all_data=True); data AffineHullProjectionData(image=A 2-dimensional polyhedron in ZZ^2 - defined as the convex hull of 3 vertices, + defined as the convex hull of 3 vertices, projection_linear_map=Vector space morphism represented by the matrix: [1 0] [0 1] [0 0] - Domain: Vector space of dimension 3 over Rational Field - Codomain: Vector space of dimension 2 over Rational Field, projection_translation=(0, 0), + Domain: Vector space of dimension 3 over Rational Field + Codomain: Vector space of dimension 2 over Rational Field, + projection_translation=(0, 0), section_linear_map=Vector space morphism represented by the matrix: [ 1 0 -1] [ 0 1 -1] - Domain: Vector space of dimension 2 over Rational Field - Codomain: Vector space of dimension 3 over Rational Field, section_translation=(0, 0, 1)) - sage: data.image.linear_transformation(data.section_linear_map.matrix().transpose()) + data.section_translation == S + Domain: Vector space of dimension 2 over Rational Field + Codomain: Vector space of dimension 3 over Rational Field, + section_translation=(0, 0, 1)) + sage: mat = data.section_linear_map.matrix().transpose() + sage: data.image.linear_transformation(mat) + data.section_translation == S True :: @@ -1473,8 +1522,8 @@ def _test_affine_hull_projection(self, tester=None, verbose=False, **options): TESTS:: - sage: D = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: D.facets()[0].as_polyhedron()._test_affine_hull_projection() # optional - sage.rings.number_field + sage: D = polytopes.dodecahedron() # needs sage.rings.number_field + sage: D.facets()[0].as_polyhedron()._test_affine_hull_projection() # needs sage.rings.number_field """ if tester is None: tester = self._tester(**options) @@ -1562,7 +1611,8 @@ def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambien EXAMPLES:: - sage: triangle = Polyhedron([(1,0,0), (0,1,0), (0,0,1)]); triangle + sage: # needs sage.symbolic + sage: triangle = Polyhedron([(1, 0, 0), (0, 1, 0), (0, 0, 1)]); triangle A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices sage: A = triangle.affine_hull_manifold(name='A'); A 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3 @@ -1577,29 +1627,36 @@ def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambien sage: A.normal().display() n = 1/3*sqrt(3) e_x + 1/3*sqrt(3) e_y + 1/3*sqrt(3) e_z sage: A.induced_metric() # Need to call this before volume_form - Riemannian metric gamma on the 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3 + Riemannian metric gamma on the + 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3 sage: A.volume_form() - 2-form eps_gamma on the 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3 + 2-form eps_gamma on the + 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3 Orthogonal version:: - sage: A = triangle.affine_hull_manifold(name='A', orthogonal=True); A + sage: A = triangle.affine_hull_manifold(name='A', orthogonal=True); A # needs sage.symbolic 2-dimensional Riemannian submanifold A embedded in the Euclidean space E^3 - sage: A.embedding().display() + sage: A.embedding().display() # needs sage.symbolic A โ†’ E^3 - (x0, x1) โ†ฆ (x, y, z) = (t0 - 1/2*x0 - 1/3*x1 + 1, t0 + 1/2*x0 - 1/3*x1, t0 + 2/3*x1) - sage: A.embedding().inverse().display() + (x0, x1) โ†ฆ (x, y, z) = (t0 - 1/2*x0 - 1/3*x1 + 1, + t0 + 1/2*x0 - 1/3*x1, t0 + 2/3*x1) + sage: A.embedding().inverse().display() # needs sage.symbolic E^3 โ†’ A (x, y, z) โ†ฆ (x0, x1) = (-x + y + 1, -1/2*x - 1/2*y + z + 1/2) Arrangement of affine hull of facets:: - sage: D = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: E3 = EuclideanSpace(3) # optional - sage.rings.number_field - sage: submanifolds = [ # optional - sage.rings.number_field - ....: F.as_polyhedron().affine_hull_manifold(name=f'F{i}', orthogonal=True, ambient_space=E3) + sage: # needs sage.rings.number_field sage.symbolic + sage: D = polytopes.dodecahedron() + sage: E3 = EuclideanSpace(3) + sage: submanifolds = [ # long time + ....: F.as_polyhedron().affine_hull_manifold(name=f'F{i}', + ....: orthogonal=True, ambient_space=E3) ....: for i, F in enumerate(D.facets())] - sage: sum(FM.plot({}, srange(-2, 2, 0.1), srange(-2, 2, 0.1), opacity=0.2) # not tested # optional - sage.plot # optional - sage.rings.number_field + sage: sum(FM.plot({}, # long time, not tested # needs sage.plot + ....: srange(-2, 2, 0.1), srange(-2, 2, 0.1), + ....: opacity=0.2) ....: for FM in submanifolds) + D.plot() Graphics3d Object @@ -1607,7 +1664,7 @@ def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambien sage: cube = polytopes.cube(); cube A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices - sage: cube.affine_hull_manifold() + sage: cube.affine_hull_manifold() # needs sage.symbolic Euclidean space E^3 """ diff --git a/src/sage/geometry/polyhedron/base7.py b/src/sage/geometry/polyhedron/base7.py index db828e2eb0a..c1c06b90a28 100644 --- a/src/sage/geometry/polyhedron/base7.py +++ b/src/sage/geometry/polyhedron/base7.py @@ -21,7 +21,7 @@ # Copyright (C) 2019 Julian Ritter # Copyright (C) 2019-2020 Laith Rastanawi # Copyright (C) 2019-2020 Sophia Elia -# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019-2021 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -43,12 +43,16 @@ class Polyhedron_base7(Polyhedron_base6): TESTS:: + sage: # needs sage.combinat sage: from sage.geometry.polyhedron.base7 import Polyhedron_base7 sage: P = polytopes.associahedron(['A', 3]) sage: Polyhedron_base7.centroid(P) (81/632, 36/79, 81/632) sage: Polyhedron_base7.triangulate(P) - (<0,1,2,13>, <0,1,7,13>, <0,2,5,13>, <0,6,7,12>, <0,6,8,13>, <0,6,12,13>, <0,7,12,13>, <1,2,7,12>, <1,2,12,13>, <1,7,12,13>, <2,3,7,12>, <2,3,12,13>, <3,4,7,12>, <3,11,12,13>, <6,8,9,12>, <6,8,12,13>, <6,9,10,12>, <8,9,12,13>) + (<0,1,2,13>, <0,1,7,13>, <0,2,5,13>, <0,6,7,12>, <0,6,8,13>, + <0,6,12,13>, <0,7,12,13>, <1,2,7,12>, <1,2,12,13>, <1,7,12,13>, + <2,3,7,12>, <2,3,12,13>, <3,4,7,12>, <3,11,12,13>, <6,8,9,12>, + <6,8,12,13>, <6,9,10,12>, <8,9,12,13>) sage: Polyhedron_base7.volume(P, measure='induced') 79/3 """ @@ -88,17 +92,17 @@ def centroid(self, engine='auto', **kwds): sage: P.centroid() (1/4, 0, 0) - sage: P = polytopes.associahedron(['A',2]) - sage: P.centroid() + sage: P = polytopes.associahedron(['A', 2]) # needs sage.combinat + sage: P.centroid() # needs sage.combinat (2/21, 2/21) - sage: P = polytopes.permutahedron(4, backend='normaliz') # optional - pynormaliz - sage: P.centroid() # optional - pynormaliz + sage: P = polytopes.permutahedron(4, backend='normaliz') # optional - pynormaliz + sage: P.centroid() # optional - pynormaliz (5/2, 5/2, 5/2, 5/2) The method is not implemented for unbounded polyhedra:: - sage: P = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)]) + sage: P = Polyhedron(vertices=[(0, 0)], rays=[(1, 0), (0, 1)]) sage: P.centroid() Traceback (most recent call last): ... @@ -223,12 +227,12 @@ def triangulate(self, engine='auto', connected=True, fine=False, regular=None, s sage: cube = polytopes.hypercube(3) sage: triangulation = cube.triangulate( - ....: engine='internal') # to make doctest independent of TOPCOM + ....: engine='internal') # to make doctest independent of TOPCOM sage: triangulation (<0,1,2,7>, <0,1,5,7>, <0,2,3,7>, <0,3,4,7>, <0,4,5,7>, <1,5,6,7>) sage: simplex_indices = triangulation[0]; simplex_indices (0, 1, 2, 7) - sage: simplex_vertices = [ cube.Vrepresentation(i) for i in simplex_indices ] + sage: simplex_vertices = [cube.Vrepresentation(i) for i in simplex_indices] sage: simplex_vertices [A vertex at (1, -1, -1), A vertex at (1, 1, -1), @@ -240,11 +244,14 @@ def triangulate(self, engine='auto', connected=True, fine=False, regular=None, s It is possible to use ``'normaliz'`` as an engine. For this, the polyhedron should have the backend set to normaliz:: - sage: P = Polyhedron(vertices=[[0,0,1],[1,0,1],[0,1,1],[1,1,1]],backend='normaliz') # optional - pynormaliz - sage: P.triangulate(engine='normaliz') # optional - pynormaliz + sage: P = Polyhedron(vertices=[[0,0,1], [1,0,1], # optional - pynormaliz + ....: [0,1,1], [1,1,1]], + ....: backend='normaliz') + sage: P.triangulate(engine='normaliz') # optional - pynormaliz (<0,1,2>, <1,2,3>) - sage: P = Polyhedron(vertices=[[0,0,1],[1,0,1],[0,1,1],[1,1,1]]) + sage: P = Polyhedron(vertices=[[0,0,1], [1,0,1], + ....: [0,1,1], [1,1,1]]) sage: P.triangulate(engine='normaliz') Traceback (most recent call last): ... @@ -252,17 +259,24 @@ def triangulate(self, engine='auto', connected=True, fine=False, regular=None, s The normaliz engine can triangulate pointed cones:: - sage: C1 = Polyhedron(rays=[[0,0,1],[1,0,1],[0,1,1],[1,1,1]],backend='normaliz') # optional - pynormaliz - sage: C1.triangulate(engine='normaliz') # optional - pynormaliz + sage: # optional - pynormaliz + sage: C1 = Polyhedron(rays=[[0,0,1], [1,0,1], + ....: [0,1,1], [1,1,1]], + ....: backend='normaliz') + sage: C1.triangulate(engine='normaliz') (<0,1,2>, <1,2,3>) - sage: C2 = Polyhedron(rays=[[1,0,1],[0,0,1],[0,1,1],[1,1,10/9]],backend='normaliz') # optional - pynormaliz - sage: C2.triangulate(engine='normaliz') # optional - pynormaliz + sage: C2 = Polyhedron(rays=[[1,0,1], [0,0,1], + ....: [0,1,1], [1,1,10/9]], + ....: backend='normaliz') + sage: C2.triangulate(engine='normaliz') (<0,1,2>, <1,2,3>) They can also be affine cones:: - sage: K = Polyhedron(vertices=[[1,1,1]],rays=[[1,0,0],[0,1,0],[1,1,-1],[1,1,1]], backend='normaliz') # optional - pynormaliz - sage: K.triangulate(engine='normaliz') # optional - pynormaliz + sage: K = Polyhedron(vertices=[[1,1,1]], # optional - pynormaliz + ....: rays=[[1,0,0], [0,1,0], [1,1,-1], [1,1,1]], + ....: backend='normaliz') + sage: K.triangulate(engine='normaliz') # optional - pynormaliz (<0,1,2>, <0,1,3>) """ if self.lines(): @@ -306,11 +320,11 @@ def _volume_lrs(self, verbose=False): EXAMPLES:: - sage: polytopes.hypercube(3)._volume_lrs() # optional - lrslib + sage: polytopes.hypercube(3)._volume_lrs() # optional - lrslib 8 - sage: (polytopes.hypercube(3)*2)._volume_lrs() # optional - lrslib + sage: (polytopes.hypercube(3)*2)._volume_lrs() # optional - lrslib 64 - sage: polytopes.twenty_four_cell()._volume_lrs() # optional - lrslib + sage: polytopes.twenty_four_cell()._volume_lrs() # optional - lrslib 2 REFERENCES: @@ -377,35 +391,36 @@ def _volume_latte(self, verbose=False, algorithm='triangulate', **kwargs): EXAMPLES:: - sage: polytopes.hypercube(3)._volume_latte() # optional - latte_int + sage: # optional - latte_int + sage: polytopes.hypercube(3)._volume_latte() 8 - sage: (polytopes.hypercube(3)*2)._volume_latte() # optional - latte_int + sage: (polytopes.hypercube(3)*2)._volume_latte() 64 - sage: polytopes.twenty_four_cell()._volume_latte() # optional - latte_int + sage: polytopes.twenty_four_cell()._volume_latte() 2 - sage: polytopes.cuboctahedron()._volume_latte() # optional - latte_int + sage: polytopes.cuboctahedron()._volume_latte() 20/3 TESTS: Testing triangulate algorithm:: - sage: polytopes.cuboctahedron()._volume_latte(algorithm='triangulate') # optional - latte_int + sage: polytopes.cuboctahedron()._volume_latte(algorithm='triangulate') # optional - latte_int 20/3 Testing cone decomposition algorithm:: - sage: polytopes.cuboctahedron()._volume_latte(algorithm='cone-decompose') # optional - latte_int + sage: polytopes.cuboctahedron()._volume_latte(algorithm='cone-decompose') # optional - latte_int 20/3 Testing raw output:: - sage: polytopes.cuboctahedron()._volume_latte(raw_output=True) # optional - latte_int + sage: polytopes.cuboctahedron()._volume_latte(raw_output=True) # optional - latte_int '20/3' Testing inexact rings:: - sage: P = Polyhedron(vertices=[[0,0],[1,0],[0,1]],base_ring=RDF) + sage: P = Polyhedron(vertices=[[0,0], [1,0], [0,1]],base_ring=RDF) sage: P.volume(engine='latte') Traceback (most recent call last): ... @@ -441,7 +456,7 @@ def _volume_normaliz(self, measure='induced'): TESTS:: - sage: P = Polyhedron(vertices=[[0,0],[1,0],[0,1],[1,1]]) + sage: P = Polyhedron(vertices=[[0,0], [1,0], [0,1], [1,1]]) sage: P._volume_normaliz() Traceback (most recent call last): ... @@ -494,21 +509,21 @@ def volume(self, measure='ambient', engine='auto', **kwds): (which requires a rational polytope):: sage: I3 = polytopes.hypercube(3) - sage: I3.volume(engine='lrs') # optional - lrslib + sage: I3.volume(engine='lrs') # optional - lrslib 8 sage: C24 = polytopes.twenty_four_cell() - sage: C24.volume(engine='lrs') # optional - lrslib + sage: C24.volume(engine='lrs') # optional - lrslib 2 If the base ring is exact, the answer is exact:: - sage: P5 = polytopes.regular_polygon(5) # optional - sage.rings.number_field - sage: P5.volume() # optional - sage.rings.number_field + sage: P5 = polytopes.regular_polygon(5) # needs sage.rings.number_field + sage: P5.volume() # needs sage.rings.number_field 2.377641290737884? - sage: polytopes.icosahedron().volume() # optional - sage.rings.number_field + sage: polytopes.icosahedron().volume() # needs sage.rings.number_field 5/12*sqrt5 + 5/4 - sage: numerical_approx(_) # abs tol 1e9 # optional - sage.rings.number_field + sage: numerical_approx(_) # abs tol 1e9 # needs sage.rings.number_field 2.18169499062491 When considering lower-dimensional polytopes, we can ask for the @@ -521,83 +536,96 @@ def volume(self, measure='ambient', engine='auto', **kwds): sage: P = Polyhedron([[0, 0], [1, 1]]) sage: P.volume() 0 - sage: P.volume(measure='induced') + sage: P.volume(measure='induced') # needs sage.rings.number_field 1.414213562373095? - sage: P.volume(measure='induced_rational') # optional -- latte_int + sage: P.volume(measure='induced_rational') # optional - latte_int 1 - sage: S = polytopes.regular_polygon(6); S # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: S = polytopes.regular_polygon(6); S A 2-dimensional polyhedron in AA^2 defined as the convex hull of 6 vertices - sage: edge = S.faces(1)[4].as_polyhedron() # optional - sage.rings.number_field - sage: edge.vertices() # optional - sage.rings.number_field + sage: edge = S.faces(1)[4].as_polyhedron() + sage: edge.vertices() (A vertex at (0.866025403784439?, 1/2), A vertex at (0, 1)) - sage: edge.volume() # optional - sage.rings.number_field + sage: edge.volume() 0 - sage: edge.volume(measure='induced') # optional - sage.rings.number_field + sage: edge.volume(measure='induced') 1 - sage: P = Polyhedron(backend='normaliz',vertices=[[1,0,0],[0,0,1],[-1,1,1],[-1,2,0]]) # optional - pynormaliz - sage: P.volume() # optional - pynormaliz + sage: # optional - pynormaliz + sage: P = Polyhedron(backend='normaliz', + ....: vertices=[[1,0,0], [0,0,1], + ....: [-1,1,1], [-1,2,0]]) + sage: P.volume() 0 - sage: P.volume(measure='induced') # optional - pynormaliz # optional - sage.rings.number_field + sage: P.volume(measure='induced') # needs sage.rings.number_field 2.598076211353316? - sage: P.volume(measure='induced',engine='normaliz') # optional - pynormaliz + sage: P.volume(measure='induced', engine='normaliz') 2.598076211353316 - sage: P.volume(measure='induced_rational') # optional - pynormaliz, latte_int + sage: P.volume(measure='induced_rational') # optional - latte_int 3/2 - sage: P.volume(measure='induced_rational',engine='normaliz') # optional - pynormaliz + sage: P.volume(measure='induced_rational', + ....: engine='normaliz') 3/2 - sage: P.volume(measure='induced_lattice') # optional - pynormaliz + sage: P.volume(measure='induced_lattice') 3 The same polytope without normaliz backend:: - sage: P = Polyhedron(vertices=[[1,0,0],[0,0,1],[-1,1,1],[-1,2,0]]) - sage: P.volume(measure='induced_lattice',engine='latte') # optional - latte_int + sage: P = Polyhedron(vertices=[[1,0,0], [0,0,1], [-1,1,1], [-1,2,0]]) + sage: P.volume(measure='induced_lattice', engine='latte') # optional - latte_int 3 - sage: Dexact = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: v = Dexact.faces(2)[0].as_polyhedron().volume(measure='induced', engine='internal'); v # optional - sage.rings.number_field + sage: # needs sage.groups sage.rings.number_field + sage: Dexact = polytopes.dodecahedron() + sage: F0 = Dexact.faces(2)[0].as_polyhedron() + sage: v = F0.volume(measure='induced', engine='internal'); v 1.53406271079097? - sage: v = Dexact.faces(2)[4].as_polyhedron().volume(measure='induced', engine='internal'); v # optional - sage.rings.number_field + sage: F4 = Dexact.faces(2)[4].as_polyhedron() + sage: v = F4.volume(measure='induced', engine='internal'); v 1.53406271079097? - sage: RDF(v) # abs tol 1e-9 # optional - sage.rings.number_field + sage: RDF(v) # abs tol 1e-9 1.53406271079044 + sage: # needs sage.groups sage: Dinexact = polytopes.dodecahedron(exact=False) - sage: w = Dinexact.faces(2)[2].as_polyhedron().volume(measure='induced', engine='internal'); RDF(w) # abs tol 1e-9 + sage: F2 = Dinexact.faces(2)[2].as_polyhedron() + sage: w = F2.volume(measure='induced', engine='internal') + sage: RDF(w) # abs tol 1e-9 1.5340627082974878 - sage: [polytopes.simplex(d).volume(measure='induced') for d in range(1,5)] == [sqrt(d+1)/factorial(d) for d in range(1,5)] + sage: all(polytopes.simplex(d).volume(measure='induced') # needs sage.rings.number_field sage.symbolic + ....: == sqrt(d+1)/factorial(d) + ....: for d in range(1,5)) True sage: I = Polyhedron([[-3, 0], [0, 9]]) - sage: I.volume(measure='induced') # optional - sage.rings.number_field + sage: I.volume(measure='induced') # needs sage.rings.number_field 9.48683298050514? - sage: I.volume(measure='induced_rational') # optional -- latte_int + sage: I.volume(measure='induced_rational') # optional - latte_int 3 sage: T = Polyhedron([[3, 0, 0], [0, 4, 0], [0, 0, 5]]) - sage: T.volume(measure='induced') # optional - sage.rings.number_field + sage: T.volume(measure='induced') # needs sage.rings.number_field 13.86542462386205? - sage: T.volume(measure='induced_rational') # optional -- latte_int + sage: T.volume(measure='induced_rational') # optional - latte_int 1/2 sage: Q = Polyhedron(vertices=[(0, 0, 1, 1), (0, 1, 1, 0), (1, 1, 0, 0)]) sage: Q.volume(measure='induced') 1 - sage: Q.volume(measure='induced_rational') # optional -- latte_int + sage: Q.volume(measure='induced_rational') # optional - latte_int 1/2 The volume of a full-dimensional unbounded polyhedron is infinity:: - sage: P = Polyhedron(vertices = [[1, 0], [0, 1]], rays = [[1, 1]]) + sage: P = Polyhedron(vertices=[[1, 0], [0, 1]], rays=[[1, 1]]) sage: P.volume() +Infinity The volume of a non full-dimensional unbounded polyhedron depends on the measure used:: - sage: P = Polyhedron(ieqs = [[1,1,1],[-1,-1,-1],[3,1,0]]); P + sage: P = Polyhedron(ieqs = [[1,1,1], [-1,-1,-1], [3,1,0]]); P A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray sage: P.volume() 0 @@ -605,9 +633,9 @@ def volume(self, measure='ambient', engine='auto', **kwds): +Infinity sage: P.volume(measure='ambient') 0 - sage: P.volume(measure='induced_rational') # optional - pynormaliz + sage: P.volume(measure='induced_rational') # optional - pynormaliz +Infinity - sage: P.volume(measure='induced_rational',engine='latte') # optional - latte_int + sage: P.volume(measure='induced_rational',engine='latte') +Infinity The volume in `0`-dimensional space is taken by counting measure:: @@ -635,7 +663,7 @@ def volume(self, measure='ambient', engine='auto', **kwds): Induced volumes work with lrs (:trac:`33410`):: sage: P = Polyhedron([[0, 0], [1, 1]]) - sage: P.volume(measure='induced', engine='lrs') # optional - lrslib + sage: P.volume(measure='induced', engine='lrs') # optional - lrslib 1.414213562373095? """ from sage.features import FeatureNotPresentError @@ -773,7 +801,7 @@ def integrate(self, function, measure='ambient', **kwds): sage: P = polytopes.cube() sage: x, y, z = polygens(QQ, 'x, y, z') - sage: P.integrate(x^2*y^2*z^2) # optional - latte_int + sage: P.integrate(x^2*y^2*z^2) # optional - latte_int 8/27 If the polyhedron has floating point coordinates, an inexact result can @@ -781,41 +809,45 @@ def integrate(self, function, measure='ambient', **kwds): sage: P = 1.4142*polytopes.cube() sage: P_QQ = Polyhedron(vertices=[[QQ(vi) for vi in v] for v in P.vertex_generator()]) - sage: RDF(P_QQ.integrate(x^2*y^2*z^2)) # optional - latte_int + sage: RDF(P_QQ.integrate(x^2*y^2*z^2)) # optional - latte_int 6.703841212195228 Integral over a non full-dimensional polytope:: sage: x, y = polygens(QQ, 'x, y') - sage: P = Polyhedron(vertices=[[0,0],[1,1]]) - sage: P.integrate(x*y) # optional - latte_int + sage: P = Polyhedron(vertices=[[0,0], [1,1]]) + sage: P.integrate(x*y) 0 - sage: ixy = P.integrate(x*y, measure='induced'); ixy # optional - latte_int + sage: ixy = P.integrate(x*y, measure='induced'); ixy # optional - latte_int 0.4714045207910317? - sage: ixy.parent() # optional - latte_int + sage: ixy.parent() # optional - latte_int Algebraic Real Field Convert to a symbolic expression:: - sage: ixy.radical_expression() # optional - latte_int + sage: ixy.radical_expression() # optional - latte_int 1/3*sqrt(2) Another non full-dimensional polytope integration:: sage: R.<x, y, z> = QQ[] sage: P = polytopes.simplex(2) - sage: V = AA(P.volume(measure='induced')); V.radical_expression() + sage: V = AA(P.volume(measure='induced')) # needs sage.rings.number_field + sage: V.radical_expression() # needs sage.rings.number_field sage.symbolic 1/2*sqrt(3) - sage: P.integrate(R(1), measure='induced') == V # optional - latte_int + sage: P.integrate(R(1), measure='induced') == V # optional - latte_int, needs sage.rings.number_field sage.symbolic True Computing the mass center:: - sage: (P.integrate(x, measure='induced') / V).radical_expression() # optional - latte_int + sage: (P.integrate(x, measure='induced') # optional - latte_int, needs sage.rings.number_field sage.symbolic + ....: / V).radical_expression() 1/3 - sage: (P.integrate(y, measure='induced') / V).radical_expression() # optional - latte_int + sage: (P.integrate(y, measure='induced') # optional - latte_int, needs sage.rings.number_field sage.symbolic + ....: / V).radical_expression() 1/3 - sage: (P.integrate(z, measure='induced') / V).radical_expression() # optional - latte_int + sage: (P.integrate(z, measure='induced') # optional - latte_int, needs sage.rings.number_field sage.symbolic + ....: / V).radical_expression() 1/3 TESTS: @@ -824,28 +856,28 @@ def integrate(self, function, measure='ambient', **kwds): sage: P = polytopes.octahedron() sage: x, y, z = polygens(QQ, 'x, y, z') - sage: P.integrate(2*x^2*y^4*z^6+z^2) # optional - latte_int + sage: P.integrate(2*x^2*y^4*z^6 + z^2) # optional - latte_int 630632/4729725 Testing a polytope with non-rational vertices:: - sage: P = polytopes.icosahedron() # optional - sage.rings.number_field - sage: P.integrate(x^2*y^2*z^2) # optional - latte_int # optional - sage.rings.number_field + sage: P = polytopes.icosahedron() # needs sage.rings.number_field + sage: P.integrate(x^2*y^2*z^2) # optional - latte_int, needs sage.rings.number_field Traceback (most recent call last): ... TypeError: the base ring must be ZZ, QQ, or RDF Testing a univariate polynomial:: - sage: P = Polyhedron(vertices=[[0],[1]]) + sage: P = Polyhedron(vertices=[[0], [1]]) sage: x = polygen(QQ, 'x') - sage: P.integrate(x) # optional - latte_int + sage: P.integrate(x) # optional - latte_int 1/2 Testing a polytope with floating point coordinates:: - sage: P = Polyhedron(vertices = [[0, 0], [1, 0], [1.1, 1.1], [0, 1]]) - sage: P.integrate('[[1,[2,2]]]') # optional - latte_int + sage: P = Polyhedron(vertices=[[0, 0], [1, 0], [1.1, 1.1], [0, 1]]) + sage: P.integrate('[[1,[2,2]]]') Traceback (most recent call last): ... TypeError: LattE integrale cannot be applied over inexact rings @@ -942,7 +974,7 @@ def _integrate_latte_(self, polynomial, **kwds): sage: P = polytopes.cube() sage: x, y, z = polygens(QQ, 'x, y, z') - sage: P._integrate_latte_(x^2 + y^2*z^2) # optional - latte_int + sage: P._integrate_latte_(x^2 + y^2*z^2) # optional - latte_int 32/9 :: @@ -951,7 +983,6 @@ def _integrate_latte_(self, polynomial, **kwds): sage: Polyhedron(vertices=[()]).integrate(R(42)) 42 """ - from sage.interfaces.latte import integrate from sage.rings.real_double import RDF if self.base_ring() == RDF: @@ -961,6 +992,8 @@ def _integrate_latte_(self, polynomial, **kwds): assert len(self.vertices()) == 1 vertex = tuple(vertices[0]) return polynomial(vertex) + + from sage.interfaces.latte import integrate return integrate(self.cdd_Hrepresentation(), polynomial, cdd=True, **kwds) diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index 0efcb15f1a2..007f000eb56 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -97,13 +97,13 @@ def integral_points_count(self, verbose=False, use_Hrepresentation=False, INPUT: - - ``verbose`` (boolean; ``False`` by default) -- whether to display + - ``verbose`` -- (boolean; ``False`` by default) whether to display verbose output. - - ``use_Hrepresentation`` - (boolean; ``False`` by default) -- whether + - ``use_Hrepresentation`` -- (boolean; ``False`` by default) -- whether to send the H or V representation to LattE - - ``preprocess`` - (boolean; ``True`` by default) -- whether, if the integral hull + - ``preprocess`` -- (boolean; ``True`` by default) whether, if the integral hull is known to lie in a coordinate hyperplane, to tighten bounds to reduce dimension .. SEEALSO:: @@ -115,13 +115,13 @@ def integral_points_count(self, verbose=False, use_Hrepresentation=False, sage: P = polytopes.cube() sage: P.integral_points_count() 27 - sage: P.integral_points_count(explicit_enumeration_threshold=0) # optional - latte_int + sage: P.integral_points_count(explicit_enumeration_threshold=0) # optional - latte_int 27 We enlarge the polyhedron to force the use of the generating function methods - implemented in LattE integrale, rather than explicit enumeration. + implemented in LattE integrale, rather than explicit enumeration:: - sage: (1000000000*P).integral_points_count(verbose=True) # optional - latte_int + sage: (1000000000*P).integral_points_count(verbose=True) # optional - latte_int This is LattE integrale... ... Total time:... @@ -132,7 +132,7 @@ def integral_points_count(self, verbose=False, use_Hrepresentation=False, sage: Q = P*(8/9) sage: Q.integral_points_count() 1 - sage: Q.integral_points_count(explicit_enumeration_threshold=0) # optional - latte_int + sage: Q.integral_points_count(explicit_enumeration_threshold=0) 1 Unbounded polyhedra (with or without lattice points) are not supported:: @@ -155,7 +155,7 @@ def integral_points_count(self, verbose=False, use_Hrepresentation=False, ....: x = lp.new_variable(nonnegative=True) ....: lp.add_constraint(lp.sum(fibonacci(i+3)*x[i] for i in range(d)) <= b) ....: return lp.polyhedron(backend=backend) - sage: fibonacci_knapsack(20, 12).integral_points_count() # does not finish with preprocess=False + sage: fibonacci_knapsack(20, 12).integral_points_count() # does not finish with preprocess=False # needs sage.combinat 33 TESTS: @@ -163,10 +163,10 @@ def integral_points_count(self, verbose=False, use_Hrepresentation=False, We check that :trac:`21491` is fixed:: sage: P = Polyhedron(ieqs=[], eqns=[[-10,0,1],[-10,1,0]]) - sage: P.integral_points_count() # optional - latte_int + sage: P.integral_points_count() 1 sage: P = Polyhedron(ieqs=[], eqns=[[-11,0,2],[-10,1,0]]) - sage: P.integral_points_count() # optional - latte_int + sage: P.integral_points_count() 0 """ if self.is_empty(): @@ -243,12 +243,12 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, is computed using LattE Integrale (optional) * ``'latte'``; use LattE integrale program (optional) * ``'normaliz'``; use Normaliz program (optional package pynormaliz). - The backend of ``self`` must be set to 'normaliz'. + The backend of ``self`` must be set to ``'normaliz'``. - - ``variable`` -- string (default: 't'); The variable in which the - Ehrhart polynomial should be expressed. + - ``variable`` -- string (default: ``'t'``); The variable in which the + Ehrhart polynomial should be expressed. - - When the ``engine`` is 'latte', the additional input values are: + - When the ``engine`` is ``'latte'``, the additional input values are: * ``verbose`` - boolean (default: ``False``); If ``True``, print the whole output of the LattE command. @@ -259,9 +259,9 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, * ``dual`` - boolean; triangulate and signed-decompose in the dual space - * ``irrational_primal`` - boolean; triangulate in the dual space, + * ``irrational_primal`` -- boolean; triangulate in the dual space, signed-decompose in the primal space using irrationalization. - * ``irrational_all_primal`` - boolean; triangulate and signed-decompose + * ``irrational_all_primal`` -- boolean; triangulate and signed-decompose in the primal space using irrationalization. * ``maxdet`` -- integer; decompose down to an index (determinant) of ``maxdet`` instead of index 1 (unimodular cones). @@ -270,8 +270,8 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, * ``compute_vertex_cones`` -- string; either 'cdd' or 'lrs' or '4ti2' * ``smith_form`` -- string; either 'ilio' or 'lidia' * ``dualization`` -- string; either 'cdd' or '4ti2' - * ``triangulation`` - string; 'cddlib', '4ti2' or 'topcom' - * ``triangulation_max_height`` - integer; use a uniform distribution + * ``triangulation`` -- string; 'cddlib', '4ti2' or 'topcom' + * ``triangulation_max_height`` -- integer; use a uniform distribution of height from 1 to this number OUTPUT: @@ -287,54 +287,59 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, To start, we find the Ehrhart polynomial of a three-dimensional ``simplex``, first using ``engine='latte'``. Leaving the engine - unspecified sets the ``engine`` to 'latte' by default:: + unspecified sets the ``engine`` to ``'latte'`` by default:: sage: simplex = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)]) sage: simplex = simplex.change_ring(QQ) - sage: poly = simplex.ehrhart_polynomial(engine='latte') # optional - latte_int - sage: poly # optional - latte_int + sage: poly = simplex.ehrhart_polynomial(engine='latte') # optional - latte_int + sage: poly # optional - latte_int 7/2*t^3 + 2*t^2 - 1/2*t + 1 - sage: poly(1) # optional - latte_int + sage: poly(1) # optional - latte_int 6 - sage: len(simplex.integral_points()) # optional - latte_int + sage: len(simplex.integral_points()) 6 - sage: poly(2) # optional - latte_int + sage: poly(2) # optional - latte_int 36 - sage: len((2*simplex).integral_points()) # optional - latte_int + sage: len((2*simplex).integral_points()) 36 Now we find the same Ehrhart polynomial, this time using ``engine='normaliz'``. To use the Normaliz engine, the ``simplex`` must be defined with ``backend='normaliz'``:: - sage: simplex = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)], backend='normaliz') # optional - pynormaliz - sage: simplex = simplex.change_ring(QQ) # optional - pynormaliz - sage: poly = simplex.ehrhart_polynomial(engine = 'normaliz') # optional - pynormaliz - sage: poly # optional - pynormaliz + sage: # optional - pynormaliz + sage: simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), + ....: (-3,2,1), (1,-1,-2)], + ....: backend='normaliz') + sage: simplex = simplex.change_ring(QQ) + sage: poly = simplex.ehrhart_polynomial(engine='normaliz') + sage: poly 7/2*t^3 + 2*t^2 - 1/2*t + 1 If the ``engine='normaliz'``, the backend should be ``'normaliz'``, otherwise it returns an error:: - sage: simplex = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)]) + sage: simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), + ....: (-3,2,1), (1,-1,-2)]) sage: simplex = simplex.change_ring(QQ) - sage: simplex.ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + sage: simplex.ehrhart_polynomial(engine='normaliz') Traceback (most recent call last): ... TypeError: The backend of the polyhedron should be 'normaliz' The polyhedron should be compact:: - sage: C = Polyhedron(backend='normaliz',rays=[[1,2],[2,1]]) # optional - pynormaliz - sage: C = C.change_ring(QQ) # optional - pynormaliz - sage: C.ehrhart_polynomial() # optional - pynormaliz + sage: C = Polyhedron(rays=[[1,2], [2,1]], # optional - pynormaliz + ....: backend='normaliz') + sage: C = C.change_ring(QQ) # optional - pynormaliz + sage: C.ehrhart_polynomial() # optional - pynormaliz Traceback (most recent call last): ... ValueError: Ehrhart polynomial only defined for compact polyhedra The polyhedron should have integral vertices:: - sage: L = Polyhedron(vertices = [[0],[1/2]]) + sage: L = Polyhedron(vertices=[[0], [1/2]]) sage: L.ehrhart_polynomial() Traceback (most recent call last): ... @@ -344,11 +349,12 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, The cache of the Ehrhart polynomial is being pickled:: - sage: P = polytopes.cube().change_ring(QQ) # optional - latte_int - sage: P.ehrhart_polynomial() # optional - latte_int + sage: # optional - latte_int + sage: P = polytopes.cube().change_ring(QQ) + sage: P.ehrhart_polynomial() 8*t^3 + 12*t^2 + 6*t + 1 - sage: Q = loads(dumps(P)) # optional - latte_int - sage: Q.ehrhart_polynomial.is_in_cache() # optional - latte_int + sage: Q = loads(dumps(P)) + sage: Q.ehrhart_polynomial.is_in_cache() True """ # check if ``self`` is compact and has vertices in ZZ @@ -404,7 +410,7 @@ def ehrhart_quasipolynomial(self, variable='t', engine=None, verbose=False, INPUT: - - ``variable`` -- string (default: 't'); The variable in which the + - ``variable`` -- string (default: ``'t'``); The variable in which the Ehrhart polynomial should be expressed. - ``engine`` -- string; The backend to use. Allowed values are: @@ -425,21 +431,21 @@ def ehrhart_quasipolynomial(self, variable='t', engine=None, verbose=False, consult `the LattE documentation <https://www.math.ucdavis.edu/~latte/software/packages/latte_current/>`__: - * ``dual`` - boolean; triangulate and signed-decompose in the dual + * ``dual`` -- boolean; triangulate and signed-decompose in the dual space - * ``irrational_primal`` - boolean; triangulate in the dual space, + * ``irrational_primal`` -- boolean; triangulate in the dual space, signed-decompose in the primal space using irrationalization. - * ``irrational_all_primal`` - boolean; triangulate and signed-decompose + * ``irrational_all_primal`` -- boolean; triangulate and signed-decompose in the primal space using irrationalization. * ``maxdet`` -- integer; decompose down to an index (determinant) of ``maxdet`` instead of index 1 (unimodular cones). * ``no_decomposition`` -- boolean; do not signed-decompose simplicial cones. - * ``compute_vertex_cones`` -- string; either 'cdd' or 'lrs' or '4ti2' - * ``smith_form`` -- string; either 'ilio' or 'lidia' - * ``dualization`` -- string; either 'cdd' or '4ti2' - * ``triangulation`` - string; 'cddlib', '4ti2' or 'topcom' - * ``triangulation_max_height`` - integer; use a uniform distribution of + * ``compute_vertex_cones`` -- string; either ``'cdd'`` or ``'lrs'`` or ``'4ti2'`` + * ``smith_form`` -- string; either ``'ilio'`` or ``'lidia'`` + * ``dualization`` -- string; either ``'cdd'`` or ``'4ti2'`` + * ``triangulation`` - string; ``'cddlib'``, ``'4ti2'`` or ``'topcom'`` + * ``triangulation_max_height`` -- integer; use a uniform distribution of height from 1 to this number OUTPUT: @@ -466,10 +472,10 @@ def ehrhart_quasipolynomial(self, variable='t', engine=None, verbose=False, the dilated line segment. Note that it is necessary to set the backend of the polytope to 'normaliz':: - sage: line_seg = Polyhedron(vertices=[[0],[1/2]],backend='normaliz') # optional - pynormaliz - sage: line_seg # optional - pynormaliz + sage: line_seg = Polyhedron(vertices=[[0], [1/2]], # optional - pynormaliz + ....: backend='normaliz'); line_seg A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 2 vertices - sage: line_seg.ehrhart_quasipolynomial() # optional - pynormaliz + sage: line_seg.ehrhart_quasipolynomial() # optional - pynormaliz (1/2*t + 1, 1/2*t + 1/2) For a more exciting example, let us look at the subpolytope of the @@ -477,34 +483,33 @@ def ehrhart_quasipolynomial(self, variable='t', engine=None, verbose=False, across the hyperplane `x_1 = x_4`:: sage: verts = [[3/2, 3, 4, 3/2], - ....: [3/2, 4, 3, 3/2], - ....: [5/2, 1, 4, 5/2], - ....: [5/2, 4, 1, 5/2], - ....: [7/2, 1, 2, 7/2], - ....: [7/2, 2, 1, 7/2]] - sage: subpoly = Polyhedron(vertices=verts, backend='normaliz') # optional - pynormaliz - sage: eq = subpoly.ehrhart_quasipolynomial() # optional - pynormaliz - sage: eq # optional - pynormaliz + ....: [3/2, 4, 3, 3/2], + ....: [5/2, 1, 4, 5/2], + ....: [5/2, 4, 1, 5/2], + ....: [7/2, 1, 2, 7/2], + ....: [7/2, 2, 1, 7/2]] + sage: subpoly = Polyhedron(vertices=verts, # optional - pynormaliz + ....: backend='normaliz') + sage: eq = subpoly.ehrhart_quasipolynomial(); eq # optional - pynormaliz (4*t^2 + 3*t + 1, 4*t^2 + 2*t) - sage: eq = subpoly.ehrhart_quasipolynomial() # optional - pynormaliz - sage: eq # optional - pynormaliz + sage: eq = subpoly.ehrhart_quasipolynomial(); eq # optional - pynormaliz (4*t^2 + 3*t + 1, 4*t^2 + 2*t) - sage: even_ep = eq[0] # optional - pynormaliz - sage: odd_ep = eq[1] # optional - pynormaliz - sage: even_ep(2) # optional - pynormaliz + sage: even_ep = eq[0] # optional - pynormaliz + sage: odd_ep = eq[1] # optional - pynormaliz + sage: even_ep(2) # optional - pynormaliz 23 - sage: ts = 2*subpoly # optional - pynormaliz - sage: ts.integral_points_count() # optional - pynormaliz latte_int + sage: ts = 2*subpoly # optional - pynormaliz + sage: ts.integral_points_count() # optional - pynormaliz latte_int 23 - sage: odd_ep(1) # optional - pynormaliz + sage: odd_ep(1) # optional - pynormaliz 6 - sage: subpoly.integral_points_count() # optional - pynormaliz latte_int + sage: subpoly.integral_points_count() # optional - pynormaliz latte_int 6 A polytope with rational nonintegral vertices must have ``backend='normaliz'``:: - sage: line_seg = Polyhedron(vertices=[[0],[1/2]]) + sage: line_seg = Polyhedron(vertices=[[0], [1/2]]) sage: line_seg.ehrhart_quasipolynomial() Traceback (most recent call last): ... @@ -512,8 +517,9 @@ def ehrhart_quasipolynomial(self, variable='t', engine=None, verbose=False, The polyhedron should be compact:: - sage: C = Polyhedron(backend='normaliz',rays=[[1/2,2],[2,1]]) # optional - pynormaliz - sage: C.ehrhart_quasipolynomial() # optional - pynormaliz + sage: C = Polyhedron(rays=[[1/2,2], [2,1]], # optional - pynormaliz + ....: backend='normaliz') + sage: C.ehrhart_quasipolynomial() # optional - pynormaliz Traceback (most recent call last): ... ValueError: Ehrhart quasipolynomial only defined for compact polyhedra @@ -521,30 +527,35 @@ def ehrhart_quasipolynomial(self, variable='t', engine=None, verbose=False, If the polytope happens to be a lattice polytope, the Ehrhart polynomial is returned:: - sage: simplex = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)], backend='normaliz') # optional - pynormaliz - sage: simplex = simplex.change_ring(QQ) # optional - pynormaliz - sage: poly = simplex.ehrhart_quasipolynomial(engine='normaliz') # optional - pynormaliz - sage: poly # optional - pynormaliz + sage: # optional - pynormaliz + sage: simplex = Polyhedron(vertices=[(0,0,0), (3,3,3), + ....: (-3,2,1), (1,-1,-2)], + ....: backend='normaliz') + sage: simplex = simplex.change_ring(QQ) + sage: poly = simplex.ehrhart_quasipolynomial( + ....: engine='normaliz'); poly 7/2*t^3 + 2*t^2 - 1/2*t + 1 - sage: simplex.ehrhart_polynomial() # optional - pynormaliz latte_int + sage: simplex.ehrhart_polynomial() # optional - latte_int 7/2*t^3 + 2*t^2 - 1/2*t + 1 TESTS: The cache of the Ehrhart quasipolynomial is being pickled:: - sage: P = polytopes.cuboctahedron(backend='normaliz')/2 # optional - pynormaliz - sage: P.ehrhart_quasipolynomial() # optional - pynormaliz + sage: # optional - pynormaliz + sage: P = polytopes.cuboctahedron(backend='normaliz')/2 + sage: P.ehrhart_quasipolynomial() (5/6*t^3 + 2*t^2 + 5/3*t + 1, 5/6*t^3 + 1/2*t^2 + 1/6*t - 1/2) - sage: Q = loads(dumps(P)) # optional - pynormaliz - sage: Q.ehrhart_quasipolynomial.is_in_cache() # optional - pynormaliz + sage: Q = loads(dumps(P)) + sage: Q.ehrhart_quasipolynomial.is_in_cache() True - sage: P = polytopes.cuboctahedron().change_ring(QQ) # optional - latte_int - sage: P.ehrhart_quasipolynomial(engine='latte') # optional - latte_int + sage: # optional - latte_int + sage: P = polytopes.cuboctahedron().change_ring(QQ) + sage: P.ehrhart_quasipolynomial(engine='latte') 20/3*t^3 + 8*t^2 + 10/3*t + 1 - sage: Q = loads(dumps(P)) # optional - latte_int - sage: Q.ehrhart_quasipolynomial.is_in_cache(engine='latte') # optional - latte_int + sage: Q = loads(dumps(P)) + sage: Q.ehrhart_quasipolynomial.is_in_cache(engine='latte') True """ if self.is_empty(): @@ -582,7 +593,7 @@ def _ehrhart_quasipolynomial_normaliz(self, variable='t'): INPUT: - - ``variable`` -- string (default: 't'); The variable in which the + - ``variable`` -- string (default: ``'t'``); The variable in which the Ehrhart polynomial is expressed. OUTPUT: @@ -596,31 +607,31 @@ def _ehrhart_quasipolynomial_normaliz(self, variable='t'): reflection across the hyperplane `x_1 = x_4`:: sage: verts = [[3/2, 3, 4, 3/2], - ....: [3/2, 4, 3, 3/2], - ....: [5/2, 1, 4, 5/2], - ....: [5/2, 4, 1, 5/2], - ....: [7/2, 1, 2, 7/2], - ....: [7/2, 2, 1, 7/2]] - sage: subpoly = Polyhedron(vertices=verts, backend='normaliz') # optional - pynormaliz - sage: eq = subpoly._ehrhart_quasipolynomial_normaliz() # optional - pynormaliz - sage: eq # optional - pynormaliz + ....: [3/2, 4, 3, 3/2], + ....: [5/2, 1, 4, 5/2], + ....: [5/2, 4, 1, 5/2], + ....: [7/2, 1, 2, 7/2], + ....: [7/2, 2, 1, 7/2]] + sage: subpoly = Polyhedron(vertices=verts, # optional - pynormaliz + ....: backend='normaliz') + sage: eq = subpoly._ehrhart_quasipolynomial_normaliz(); eq # optional - pynormaliz (4*t^2 + 3*t + 1, 4*t^2 + 2*t) - sage: even_ep = eq[0] # optional - pynormaliz - sage: odd_ep = eq[1] # optional - pynormaliz - sage: even_ep(2) # optional - pynormaliz + sage: even_ep = eq[0] # optional - pynormaliz + sage: odd_ep = eq[1] # optional - pynormaliz + sage: even_ep(2) # optional - pynormaliz 23 - sage: ts = 2*subpoly # optional - pynormaliz - sage: ts.integral_points_count() # optional - pynormaliz latte_int + sage: ts = 2*subpoly # optional - pynormaliz + sage: ts.integral_points_count() # optional - pynormaliz latte_int 23 - sage: odd_ep(1) # optional - pynormaliz + sage: odd_ep(1) # optional - pynormaliz 6 - sage: subpoly.integral_points_count() # optional - pynormaliz latte_int + sage: subpoly.integral_points_count() # optional - pynormaliz latte_int 6 TESTS:: sage: line_seg = Polyhedron(vertices=[[0],[1/2]]) - sage: line_seg._ehrhart_quasipolynomial_normaliz() # optional - pynormaliz + sage: line_seg._ehrhart_quasipolynomial_normaliz() Traceback (most recent call last): ... TypeError: The backend of the polyhedron should be 'normaliz' @@ -645,20 +656,20 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, INPUT: - - ``verbose`` - boolean (default: ``False``); if ``True``, print the + - ``verbose`` -- boolean (default: ``False``); if ``True``, print the whole output of the LattE command. The following options are passed to the LattE command, for details you should consult `the LattE documentation <https://www.math.ucdavis.edu/~latte/software/packages/latte_current/>`__: - - ``dual`` - boolean; triangulate and signed-decompose in the dual + - ``dual`` -- boolean; triangulate and signed-decompose in the dual space - - ``irrational_primal`` - boolean; triangulate in the dual space, + - ``irrational_primal`` -- boolean; triangulate in the dual space, signed-decompose in the primal space using irrationalization. - - ``irrational_all_primal`` - boolean; triangulate and signed-decompose + - ``irrational_all_primal`` -- boolean; triangulate and signed-decompose in the primal space using irrationalization. - ``maxdet`` -- integer; decompose down to an index (determinant) of @@ -666,15 +677,15 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, - ``no_decomposition`` -- boolean; do not signed-decompose simplicial cones. - - ``compute_vertex_cones`` -- string; either 'cdd' or 'lrs' or '4ti2' + - ``compute_vertex_cones`` -- string; either ``'cdd'`` or ``'lrs'`` or ``'4ti2'`` - - ``smith_form`` -- string; either 'ilio' or 'lidia' + - ``smith_form`` -- string; either ``'ilio'`` or ``'lidia'`` - - ``dualization`` -- string; either 'cdd' or '4ti2' + - ``dualization`` -- string; either ``'cdd'`` or ``'4ti2'`` - - ``triangulation`` - string; 'cddlib', '4ti2' or 'topcom' + - ``triangulation`` -- string; ``'cddlib'``, ``'4ti2'`` or ``'topcom'`` - - ``triangulation_max_height`` - integer; use a uniform distribution of + - ``triangulation_max_height`` -- integer; use a uniform distribution of height from 1 to this number .. NOTE:: @@ -698,31 +709,31 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, EXAMPLES:: - sage: P = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)]) - sage: p = P._ehrhart_polynomial_latte() # optional - latte_int - sage: p # optional - latte_int + sage: P = Polyhedron(vertices=[(0,0,0), (3,3,3), (-3,2,1), (1,-1,-2)]) + sage: p = P._ehrhart_polynomial_latte(); p # optional - latte_int 7/2*t^3 + 2*t^2 - 1/2*t + 1 - sage: p(1) # optional - latte_int + sage: p(1) # optional - latte_int 6 - sage: len(P.integral_points()) # optional - latte_int + sage: len(P.integral_points()) 6 - sage: p(2) # optional - latte_int + sage: p(2) # optional - latte_int 36 - sage: len((2*P).integral_points()) # optional - latte_int + sage: len((2*P).integral_points()) 36 The unit hypercubes:: + sage: # optional - latte_int sage: from itertools import product sage: def hypercube(d): - ....: return Polyhedron(vertices=list(product([0,1],repeat=d))) - sage: hypercube(3)._ehrhart_polynomial_latte() # optional - latte_int + ....: return Polyhedron(vertices=list(product([0,1], repeat=d))) + sage: hypercube(3)._ehrhart_polynomial_latte() t^3 + 3*t^2 + 3*t + 1 - sage: hypercube(4)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(4)._ehrhart_polynomial_latte() t^4 + 4*t^3 + 6*t^2 + 4*t + 1 - sage: hypercube(5)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(5)._ehrhart_polynomial_latte() t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 - sage: hypercube(6)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(6)._ehrhart_polynomial_latte() t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 TESTS: @@ -822,50 +833,56 @@ def fixed_subpolytope(self, vertex_permutation): The fixed subpolytopes of the cube can be obtained as follows:: - sage: Cube = polytopes.cube(backend = 'normaliz') # optional - pynormaliz - sage: AG = Cube.restricted_automorphism_group(output='permutation') # optional - pynormaliz - sage: reprs = AG.conjugacy_classes_representatives() # optional - pynormaliz + sage: Cube = polytopes.cube(backend = 'normaliz') # optional - pynormaliz + sage: AG = Cube.restricted_automorphism_group( # optional - pynormaliz + ....: output='permutation') + sage: reprs = AG.conjugacy_classes_representatives() # optional - pynormaliz The fixed subpolytope of the identity element of the group is the entire cube:: - sage: reprs[0] # optional - pynormaliz + sage: reprs[0] # optional - pynormaliz () - sage: Cube.fixed_subpolytope(vertex_permutation = reprs[0]) # optional - pynormaliz + sage: Cube.fixed_subpolytope(vertex_permutation=reprs[0]) # optional - pynormaliz A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 8 vertices - sage: _.vertices() # optional - pynormaliz + sage: _.vertices() # optional - pynormaliz (A vertex at (-1, -1, -1), - A vertex at (-1, -1, 1), - A vertex at (-1, 1, -1), - A vertex at (-1, 1, 1), - A vertex at (1, -1, -1), - A vertex at (1, -1, 1), - A vertex at (1, 1, -1), - A vertex at (1, 1, 1)) + A vertex at (-1, -1, 1), + A vertex at (-1, 1, -1), + A vertex at (-1, 1, 1), + A vertex at (1, -1, -1), + A vertex at (1, -1, 1), + A vertex at (1, 1, -1), + A vertex at (1, 1, 1)) You can obtain non-trivial examples:: - sage: fsp = Cube.fixed_subpolytope(AG([(0,1),(2,3),(4,5),(6,7)]));fsp # optional - pynormaliz + sage: G = AG([(0,1),(2,3),(4,5),(6,7)]) # optional - pynormaliz + sage: fsp = Cube.fixed_subpolytope(G); fsp # optional - pynormaliz A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices - sage: fsp.vertices() # optional - pynormaliz + sage: fsp.vertices() # optional - pynormaliz (A vertex at (-1, -1, 0), - A vertex at (-1, 1, 0), - A vertex at (1, -1, 0), - A vertex at (1, 1, 0)) + A vertex at (-1, 1, 0), + A vertex at (1, -1, 0), + A vertex at (1, 1, 0)) - The next example shows that fixed_subpolytope works for rational polytopes:: + The next example shows that :meth:`fixed_subpolytope` works for rational polytopes:: - sage: P = Polyhedron(vertices=[[0],[1/2]], backend='normaliz') # optional - pynormaliz - sage: P.vertices() # optional - pynormaliz + sage: # optional - pynormaliz + sage: P = Polyhedron(vertices=[[0], [1/2]], + ....: backend='normaliz') + sage: P.vertices() (A vertex at (0), A vertex at (1/2)) - sage: G = P.restricted_automorphism_group(output='permutation');G # optional - pynormaliz + sage: G = P.restricted_automorphism_group( + ....: output='permutation'); G Permutation Group with generators [(0,1)] - sage: len(G) # optional - pynormaliz + sage: len(G) 2 - sage: fixed_set = P.fixed_subpolytope(G.gens()[0]); fixed_set # optional - pynormaliz + sage: fixed_set = P.fixed_subpolytope(G.gens()[0]) + sage: fixed_set A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex - sage: fixed_set.vertices_list() # optional - pynormaliz + sage: fixed_set.vertices_list() [[1/4]] """ if self.is_empty(): @@ -911,7 +928,7 @@ def fixed_subpolytopes(self, conj_class_reps): INPUT: - ``conj_class_reps`` -- a list of representatives of the conjugacy - classes of the subgroup of the ``restricted_automorphism_group`` of + classes of the subgroup of the :meth:`restricted_automorphism_group` of the polytope. Each element is written as a permutation of the vertices of the polytope. @@ -929,22 +946,24 @@ def fixed_subpolytopes(self, conj_class_reps): Here is an example for the square:: - sage: p = polytopes.hypercube(2, backend = 'normaliz'); p # optional - pynormaliz + sage: # optional - pynormaliz, needs sage.groups + sage: p = polytopes.hypercube(2, backend='normaliz'); p A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices - sage: aut_p = p.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: aut_p.order() # optional - pynormaliz + sage: aut_p = p.restricted_automorphism_group( + ....: output='permutation') + sage: aut_p.order() 8 - sage: conj_list = aut_p.conjugacy_classes_representatives(); # optional - pynormaliz - sage: fixedpolytopes_dictionary = p.fixed_subpolytopes(conj_list) # optional - pynormaliz - sage: fixedpolytopes_dictionary[aut_p([(0,3),(1,2)])] # optional - pynormaliz + sage: conj_list = aut_p.conjugacy_classes_representatives() + sage: fixedpolytopes_dict = p.fixed_subpolytopes(conj_list) + sage: fixedpolytopes_dict[aut_p([(0,3),(1,2)])] A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex TESTS:: sage: P = Polyhedron(vertices=[[1, 1]], rays=[[1, 1]]) - sage: aut_P = P.restricted_automorphism_group(output = 'permutation') - sage: conj_list = aut_P.conjugacy_classes_representatives() - sage: P.fixed_subpolytopes(conj_list) + sage: aut_P = P.restricted_automorphism_group(output='permutation') # needs sage.groups + sage: conj_list = aut_P.conjugacy_classes_representatives() # needs sage.groups + sage: P.fixed_subpolytopes(conj_list) # needs sage.groups Traceback (most recent call last): ... NotImplementedError: unbounded polyhedra are not supported @@ -976,24 +995,24 @@ def Hstar_function(self, acting_group=None, output=None): - ``acting_group`` -- (default=None) a permgroup object. A subgroup of the polytope's ``restricted_automorphism_group``. If ``None``, it is set to the full ``restricted_automorphism_group`` of the - polytope. The acting group should always use output='permutation'. + polytope. The acting group should always use ``output='permutation'``. - ``output`` -- string. an output option. The allowed values are: - * ``None`` (default): returns the rational function `H^*(t)`. `H^*` - is a rational function in `t` with coefficients in the ring of - class functions. - * ``'e_series_list'``: Returns a list of the ehrhart_series for the - fixed_subpolytopes of each conjugacy class representative. - * ``'determinant_vec'``: Returns a list of the determinants - of `Id-\rho*t` for each conjugacy class representative. - * ``'Hstar_as_lin_comb'``: Returns a vector of the coefficients - of the irreducible representations in the expression of `H^*`. - * ``'prod_det_es'``: Returns a vector of the product of - determinants and the Ehrhart series. - * ``'complete'``: Returns a list with Hstar, - Hstar_as_lin_comb, character table of the acting group, and - whether Hstar is effective. + * ``None`` (default): returns the rational function `H^*(t)`. `H^*` + is a rational function in `t` with coefficients in the ring of + class functions. + * ``'e_series_list'``: Returns a list of the ehrhart_series for the + fixed_subpolytopes of each conjugacy class representative. + * ``'determinant_vec'``: Returns a list of the determinants + of `Id-\rho*t` for each conjugacy class representative. + * ``'Hstar_as_lin_comb'``: Returns a vector of the coefficients + of the irreducible representations in the expression of `H^*`. + * ``'prod_det_es'``: Returns a vector of the product of + determinants and the Ehrhart series. + * ``'complete'``: Returns a list with ``Hstar``, + ``Hstar_as_lin_comb``, character table of the acting group, and + whether ``Hstar`` is effective. OUTPUT: @@ -1006,18 +1025,20 @@ class functions. EXAMPLES: The `H^*`-polynomial of the standard (`d-1`)-dimensional simplex - `S = conv(e_1, \dots, e_d)` under its ``restricted_automorphism_group`` + `S = conv(e_1, \dots, e_d)` under its :meth:`restricted_automorphism_group` is equal to 1 = `\chi_{trivial}` (Prop 6.1 [Stap2011]_). Here is the computation for the 3-dimensional standard simplex:: - sage: S = polytopes.simplex(3, backend = 'normaliz'); S # optional - pynormaliz + sage: # optional - pynormaliz + sage: S = polytopes.simplex(3, backend='normaliz'); S A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices - sage: G = S.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: G.is_isomorphic(SymmetricGroup(4)) # optional - pynormaliz + sage: G = S.restricted_automorphism_group( + ....: output='permutation') + sage: G.is_isomorphic(SymmetricGroup(4)) True - sage: Hstar = S._Hstar_function_normaliz(G); Hstar # optional - pynormaliz + sage: Hstar = S._Hstar_function_normaliz(G); Hstar chi_4 - sage: G.character_table() # optional - pynormaliz + sage: G.character_table() [ 1 -1 1 1 -1] [ 3 -1 0 -1 1] [ 2 0 -1 2 0] @@ -1029,36 +1050,44 @@ class functions. `\pm(0,0,1),\pm(1,0,1), \pm(0,1,1), \pm(1,1,1)` and let G = `\Zmod{2}` act on P as follows:: - sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz - ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz - sage: K = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: G = K.subgroup(gens = [K([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz - sage: conj_reps = G.conjugacy_classes_representatives() # optional - pynormaliz - sage: Dict = P.permutations_to_matrices(conj_reps, acting_group = G) # optional - pynormaliz - sage: list(Dict.keys())[0] # optional - pynormaliz + sage: # optional - pynormaliz + sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], + ....: [-1,0,-1], [0,1,1], + ....: [0,-1,-1], [1,1,1], [-1,-1,-1]], + ....: backend='normaliz') + sage: K = P.restricted_automorphism_group( + ....: output='permutation') + sage: G = K.subgroup(gens=[K([(0,2),(1,3),(4,6),(5,7)])]) + sage: conj_reps = G.conjugacy_classes_representatives() + sage: Dict = P.permutations_to_matrices(conj_reps, + ....: acting_group=G) + sage: list(Dict.keys())[0] (0,2)(1,3)(4,6)(5,7) - sage: list(Dict.values())[0] # optional - pynormaliz + sage: list(Dict.values())[0] [-1 0 1 0] [ 0 1 0 0] [ 0 0 1 0] [ 0 0 0 1] - sage: len(G) # optional - pynormaliz + sage: len(G) 2 - sage: G.character_table() # optional - pynormaliz + sage: G.character_table() [ 1 1] [ 1 -1] Then we calculate the rational function `H^*(t)`:: - sage: Hst = P._Hstar_function_normaliz(G); Hst # optional - pynormaliz - (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) + sage: Hst = P._Hstar_function_normaliz(G); Hst # optional - pynormaliz + (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) To see the exact as written in [Stap2011]_, we can format it as ``'Hstar_as_lin_comb'``. The first coordinate is the coefficient of the trivial character; the second is the coefficient of the sign character:: - sage: lin = P._Hstar_function_normaliz(G,output = 'Hstar_as_lin_comb'); lin # optional - pynormaliz - ((t^4 + 3*t^3 + 8*t^2 + 3*t + 1)/(t + 1), (3*t^3 + 2*t^2 + 3*t)/(t + 1)) + sage: lin = P._Hstar_function_normaliz( # optional - pynormaliz + ....: G, output='Hstar_as_lin_comb'); lin + ((t^4 + 3*t^3 + 8*t^2 + 3*t + 1)/(t + 1), + (3*t^3 + 2*t^2 + 3*t)/(t + 1)) """ if self.is_empty(): raise NotImplementedError('empty polyhedra are not supported') @@ -1078,26 +1107,26 @@ def _Hstar_function_normaliz(self, acting_group=None, output=None): INPUT: - ``acting_group`` -- (default=None) a permgroup object. A subgroup of - `self`'s ``restricted_automorphism_group`` output as a permutation. + ``self``'s ``restricted_automorphism_group`` output as a permutation. If ``None``, it is set to the full ``restricted_automorphism_group`` - of `self`. The acting group should always use output='permutation'. + of ``self``. The acting group should always use ``output='permutation'``. - ``output`` -- string. an output option. The allowed values are: - * ``None`` (default): returns the rational function `H^*(t)`. `H^*` - is a rational function in `t` with coefficients in the ring of - class functions. - * ``'e_series_list'``: Returns a list of the ehrhart_series - for the fixed_subpolytopes of each conjugacy class representative. - * ``'determinant_vec'``: Returns a list of the determinants - of `Id-\rho*t` for each conjugacy class representative. - * ``'Hstar_as_lin_comb'``: Returns a vector of the coefficients - of the irreducible representations in the expression of `H^*`. - * ``'prod_det_es'``: Returns a vector of the product of - determinants and the Ehrhart series. - * ``'complete'``: Returns a list with Hstar, - Hstar_as_lin_comb, character table of the acting group, and - whether Hstar is effective. + * ``None`` (default): Returns the rational function `H^*(t)`. `H^*` + is a rational function in `t` with coefficients in the ring of + class functions. + * ``'e_series_list'``: Returns a list of the ehrhart_series + for the fixed_subpolytopes of each conjugacy class representative. + * ``'determinant_vec'``: Returns a list of the determinants + of `Id-\rho*t` for each conjugacy class representative. + * ``'Hstar_as_lin_comb'``: Returns a vector of the coefficients + of the irreducible representations in the expression of `H^*`. + * ``'prod_det_es'``: Returns a vector of the product of + determinants and the Ehrhart series. + * ``'complete'``: Returns a list with ``Hstar``, + ``Hstar_as_lin_comb``, character table of the acting group, and + whether ``Hstar`` is effective. OUTPUT: @@ -1121,7 +1150,7 @@ def is_effective(self, Hstar, Hstar_as_lin_comb): Test for the effectiveness of the ``Hstar`` series of this polytope. The ``Hstar`` series of the polytope is determined by the action of a - subgroup of the polytope's ``restricted_automorphism_group``. The + subgroup of the polytope's :meth:`restricted_automorphism_group`. The ``Hstar`` series is effective if it is a polynomial in `t` and the coefficient of each `t^i` is an effective character in the ring of class functions of the acting group. A character `\rho` is effective if @@ -1151,27 +1180,37 @@ class functions of the acting group. A character `\rho` is effective if The `H^*` series of the two-dimensional permutahedron under the action of the symmetric group is effective:: - sage: p3 = polytopes.permutahedron(3, backend = 'normaliz') # optional - pynormaliz - sage: G = p3.restricted_automorphism_group(output='permutation') # optional - pynormaliz - sage: reflection12 = G([(0,2),(1,4),(3,5)]) # optional - pynormaliz - sage: reflection23 = G([(0,1),(2,3),(4,5)]) # optional - pynormaliz - sage: S3 = G.subgroup(gens=[reflection12, reflection23]) # optional - pynormaliz - sage: S3.is_isomorphic(SymmetricGroup(3)) # optional - pynormaliz + sage: # optional - pynormaliz + sage: p3 = polytopes.permutahedron(3, backend='normaliz') + sage: G = p3.restricted_automorphism_group( + ....: output='permutation') + sage: reflection12 = G([(0,2),(1,4),(3,5)]) + sage: reflection23 = G([(0,1),(2,3),(4,5)]) + sage: S3 = G.subgroup(gens=[reflection12, reflection23]) + sage: S3.is_isomorphic(SymmetricGroup(3)) True - sage: [Hstar, Hlin] = [p3.Hstar_function(S3), p3.Hstar_function(S3, output = 'Hstar_as_lin_comb')] # optional - pynormaliz - sage: p3.is_effective(Hstar,Hlin) # optional - pynormaliz + sage: Hstar = p3.Hstar_function(S3) + sage: Hlin = p3.Hstar_function(S3, + ....: output='Hstar_as_lin_comb') + sage: p3.is_effective(Hstar, Hlin) True If the `H^*`-series is not polynomial, then it is not effective:: - sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz - ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz - sage: G = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: H = G.subgroup(gens = [G([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz - sage: Hstar = P.Hstar_function(H); Hstar # optional - pynormaliz - (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) - sage: Hstar_lin = P.Hstar_function(H, output = 'Hstar_as_lin_comb') # optional - pynormaliz - sage: P.is_effective(Hstar, Hstar_lin) # optional - pynormaliz + sage: # optional - pynormaliz + sage: P = Polyhedron(vertices=[[0,0,1], [0,0,-1], [1,0,1], + ....: [-1,0,-1], [0,1,1], + ....: [0,-1,-1], [1,1,1], [-1,-1,-1]], + ....: backend='normaliz') + sage: G = P.restricted_automorphism_group( + ....: output='permutation') + sage: H = G.subgroup(gens=[G([(0,2),(1,3),(4,6),(5,7)])]) + sage: Hstar = P.Hstar_function(H); Hstar + (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) + sage: Hstar_lin = P.Hstar_function(H, + ....: output='Hstar_as_lin_comb') + sage: P.is_effective(Hstar, Hstar_lin) False """ if self.is_empty(): @@ -1188,7 +1227,7 @@ def _is_effective_normaliz(self, Hstar, Hstar_as_lin_comb): Test for the effectiveness of the ``Hstar`` series of this polytope. The ``Hstar`` series of the polytope is determined by the action of a - subgroup of the polytope's ``restricted_automorphism_group``. The + subgroup of the polytope's :meth:`restricted_automorphism_group`. The ``Hstar`` series is effective if it is a polynomial in `t` and the coefficient of each `t^i` is an effective character in the ring of class functions of the acting group. A character `\rho` is effective if @@ -1211,10 +1250,12 @@ class functions of the acting group. A character `\rho` is effective if TESTS:: - sage: p1 = Polyhedron(vertices = [[0],[1/2]]); - sage: p2 = Polyhedron(vertices = [[0],[1/2]], backend='normaliz') # optional - pynormaliz - sage: [Hstar,Hstarlin] = [p2.Hstar_function(),p2.Hstar_function(output='Hstar_as_lin_comb')] # optional - pynormaliz - sage: p1._is_effective_normaliz(Hstar,Hstarlin) # optional - pynormaliz + sage: p1 = Polyhedron(vertices=[[0], [1/2]]) + sage: p2 = Polyhedron(vertices=[[0], [1/2]], # optional - pynormaliz + ....: backend='normaliz') + sage: Hstar = p2.Hstar_function() # optional - pynormaliz + sage: Hstarlin = p2.Hstar_function(output='Hstar_as_lin_comb') # optional - pynormaliz + sage: p1._is_effective_normaliz(Hstar, Hstarlin) # optional - pynormaliz Traceback (most recent call last): ... TypeError: the backend of the polyhedron should be 'normaliz' diff --git a/src/sage/geometry/polyhedron/base_RDF.py b/src/sage/geometry/polyhedron/base_RDF.py index bf375c130ab..fe75503edf2 100644 --- a/src/sage/geometry/polyhedron/base_RDF.py +++ b/src/sage/geometry/polyhedron/base_RDF.py @@ -1,3 +1,5 @@ +# sage.doctest: optional - sage.rings.real_double + """ Base class for polyhedra over ``RDF`` """ @@ -6,7 +8,6 @@ from .base import Polyhedron_base - class Polyhedron_RDF(Polyhedron_base): """ Base class for polyhedra over ``RDF``. diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 4255f0232df..561ed76d70c 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -79,7 +79,7 @@ def is_lattice_polytope(self): sage: polytopes.cross_polytope(3).is_lattice_polytope() True - sage: polytopes.regular_polygon(5).is_lattice_polytope() # optional - sage.rings.number_field + sage: polytopes.regular_polygon(5).is_lattice_polytope() # needs sage.rings.number_field False TESTS: @@ -163,25 +163,26 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, 7/2*t^3 + 2*t^2 - 1/2*t + 1 sage: p(1) # optional - latte_int 6 - sage: len(P.integral_points()) # optional - latte_int + sage: len(P.integral_points()) 6 sage: p(2) # optional - latte_int 36 - sage: len((2*P).integral_points()) # optional - latte_int + sage: len((2*P).integral_points()) 36 The unit hypercubes:: + sage: # optional - latte_int sage: from itertools import product sage: def hypercube(d): ....: return Polyhedron(vertices=list(product([0,1],repeat=d))) - sage: hypercube(3)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(3)._ehrhart_polynomial_latte() t^3 + 3*t^2 + 3*t + 1 - sage: hypercube(4)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(4)._ehrhart_polynomial_latte() t^4 + 4*t^3 + 6*t^2 + 4*t + 1 - sage: hypercube(5)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(5)._ehrhart_polynomial_latte() t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 - sage: hypercube(6)._ehrhart_polynomial_latte() # optional - latte_int + sage: hypercube(6)._ehrhart_polynomial_latte() t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 TESTS: @@ -281,7 +282,7 @@ def _ehrhart_polynomial_normaliz(self, variable='t'): Receive a type error if the backend is not normaliz:: sage: c = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]) - sage: c._ehrhart_polynomial_normaliz() # optional - pynormaliz + sage: c._ehrhart_polynomial_normaliz() Traceback (most recent call last): ... TypeError: The polyhedron's backend should be 'normaliz' @@ -367,11 +368,11 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, dual=None 7/2*t^3 + 2*t^2 - 1/2*t + 1 sage: poly(1) # optional - latte_int 6 - sage: len(simplex.integral_points()) # optional - latte_int + sage: len(simplex.integral_points()) 6 sage: poly(2) # optional - latte_int 36 - sage: len((2*simplex).integral_points()) # optional - latte_int + sage: len((2*simplex).integral_points()) 36 Now we find the same Ehrhart polynomial, this time using @@ -387,7 +388,7 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, dual=None it returns an error:: sage: simplex = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)]) - sage: simplex.ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + sage: simplex.ehrhart_polynomial(engine='normaliz') Traceback (most recent call last): ... TypeError: The polyhedron's backend should be 'normaliz' @@ -399,27 +400,30 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, dual=None hypercube, and the coefficient of the leading monomial equals the volume of the unit hypercube:: + sage: # optional - latte_int sage: from itertools import product sage: def hypercube(d): ....: return Polyhedron(vertices=list(product([0,1],repeat=d))) - sage: hypercube(3).ehrhart_polynomial() # optional - latte_int + sage: hypercube(3).ehrhart_polynomial() t^3 + 3*t^2 + 3*t + 1 - sage: hypercube(4).ehrhart_polynomial() # optional - latte_int + sage: hypercube(4).ehrhart_polynomial() t^4 + 4*t^3 + 6*t^2 + 4*t + 1 - sage: hypercube(5).ehrhart_polynomial() # optional - latte_int + sage: hypercube(5).ehrhart_polynomial() t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 - sage: hypercube(6).ehrhart_polynomial() # optional - latte_int + sage: hypercube(6).ehrhart_polynomial() t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 + sage: # optional - pynormaliz + sage: from itertools import product sage: def hypercube(d): - ....: return Polyhedron(vertices=list(product([0,1],repeat=d)),backend='normaliz') # optional - pynormaliz - sage: hypercube(3).ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + ....: return Polyhedron(vertices=list(product([0,1],repeat=d)),backend='normaliz') + sage: hypercube(3).ehrhart_polynomial(engine='normaliz') t^3 + 3*t^2 + 3*t + 1 - sage: hypercube(4).ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + sage: hypercube(4).ehrhart_polynomial(engine='normaliz') t^4 + 4*t^3 + 6*t^2 + 4*t + 1 - sage: hypercube(5).ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + sage: hypercube(5).ehrhart_polynomial(engine='normaliz') t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 - sage: hypercube(6).ehrhart_polynomial(engine='normaliz') # optional - pynormaliz + sage: hypercube(6).ehrhart_polynomial(engine='normaliz') t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 An empty polyhedron:: @@ -511,14 +515,14 @@ def polar(self): if not self.has_IP_property(): raise ValueError('The polytope must have the IP property.') - vertices = tuple( ieq.A()/ieq.b() for - ieq in self.inequality_generator() ) + vertices = tuple(ieq.A() / ieq.b() for + ieq in self.inequality_generator()) ieqs = ((1,) + tuple(v[:]) for v in self.vertices()) pref_rep = 'Hrep' if self.n_vertices() <= self.n_inequalities() else 'Vrep' - if all( all(v_i in ZZ for v_i in v) for v in vertices): + if all(v_i in ZZ for v in vertices for v_i in v): parent = self.parent() vertices = (v.change_ring(ZZ) for v in vertices) else: @@ -626,8 +630,8 @@ def fibration_generator(self, dim): EXAMPLES:: - sage: P = Polyhedron(toric_varieties.P4_11169().fan().rays(), base_ring=ZZ) # optional - palp - sage: list(P.fibration_generator(2)) # optional - palp + sage: P = Polyhedron(toric_varieties.P4_11169().fan().rays(), base_ring=ZZ) # needs palp sage.graphs + sage: list(P.fibration_generator(2)) # needs palp sage.graphs [A 2-dimensional polyhedron in ZZ^4 defined as the convex hull of 3 vertices] """ from sage.combinat.combination import Combinations diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py index c802207303f..9491fce4e75 100644 --- a/src/sage/geometry/polyhedron/base_number_field.py +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -32,12 +32,12 @@ def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds EXAMPLES:: - sage: rt2 = AA(sqrt(2)); rt2 # optional - sage.rings.number_field + sage: rt2 = AA(sqrt(2)); rt2 # needs sage.rings.number_field sage.symbolic 1.414213562373095? - sage: rt3 = AA(sqrt(3)); rt3 # optional - sage.rings.number_field + sage: rt3 = AA(sqrt(3)); rt3 # needs sage.rings.number_field sage.symbolic 1.732050807568878? sage: from sage.geometry.polyhedron.base_number_field import _number_field_elements_from_algebraics_list_of_lists_of_lists - sage: K, results, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists([[[rt2], [1]], [[rt3]], [[1], []]]); results # optional - sage.rings.number_field + sage: K, results, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists([[[rt2], [1]], [[rt3]], [[1], []]]); results # needs sage.rings.number_field sage.symbolic [[[-a^3 + 3*a], [1]], [[a^2 - 2]], [[1], []]] """ from sage.rings.qqbar import number_field_elements_from_algebraics @@ -58,39 +58,42 @@ def _compute_data_lists_and_internal_base_ring(self, data_lists, convert_QQ, con EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], # optional - pynormaliz + sage: # optional - pynormaliz, needs sage.rings.number_field + sage: p = Polyhedron(vertices=[(0,1/2), (2,0), (4,5/6)], ....: base_ring=AA, backend='normaliz') - sage: def convert_QQ(ieqs, eqs): # optional - pynormaliz - ....: return [ [ 1000*x for x in ieq ] for ieq in ieqs], \ - ....: [ [ 1000*x for x in eq ] for eq in eqs] - sage: def convert_NF(ieqs, eqs): # optional - pynormaliz + sage: def convert_QQ(ieqs, eqs): + ....: return [[1000*x for x in ieq] for ieq in ieqs], \ + ....: [[1000*x for x in eq] for eq in eqs] + sage: def convert_NF(ieqs, eqs): ....: return ieqs, eqs - sage: p._compute_data_lists_and_internal_base_ring([[[1]], [[1/2]]], # optional - pynormaliz - ....: convert_QQ, convert_NF) + sage: p._compute_data_lists_and_internal_base_ring( + ....: [[[1]], [[1/2]]], convert_QQ, convert_NF) (([[1000]], [[500]]), Rational Field) - sage: p._compute_data_lists_and_internal_base_ring([[[AA(1)]], [[1/2]]], # optional - pynormaliz - ....: convert_QQ, convert_NF) + sage: p._compute_data_lists_and_internal_base_ring( + ....: [[[AA(1)]], [[1/2]]], convert_QQ, convert_NF) (([[1000]], [[500]]), Rational Field) - sage: p._compute_data_lists_and_internal_base_ring([[[AA(sqrt(2))]], [[1/2]]], # optional - pynormaliz # optional - sage.rings.number_field - ....: convert_QQ, convert_NF) + sage: p._compute_data_lists_and_internal_base_ring( + ....: [[[AA(sqrt(2))]], [[1/2]]], convert_QQ, convert_NF) ([[[a]], [[1/2]]], Number Field in a with defining polynomial y^2 - 2 with a = 1.414213562373095?) TESTS:: - sage: K.<a> = QuadraticField(-5) # optional - sage.rings.number_field - sage: p = Polyhedron(vertices=[(a,1/2),(2,0),(4,5/6)], # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field - ....: base_ring=K, backend='normaliz') + sage: K.<a> = QuadraticField(-5) # needs sage.rings.number_field + sage: p = Polyhedron(base_ring=K, # indirect doctest # optional - pynormaliz, needs sage.rings.number_field + ....: backend='normaliz', + ....: vertices=[(a,1/2), (2,0), (4,5/6)]) Traceback (most recent call last): ... ValueError: invalid base ring: Number Field in a ... is not real embedded Checks that :trac:`30248` is fixed:: - sage: q = Polyhedron(backend='normaliz', base_ring=AA, # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field + sage: q = Polyhedron(base_ring=AA, # indirect doctest # optional - pynormaliz, needs sage.rings.number_field + ....: backend='normaliz', ....: rays=[(0, 0, 1), (0, 1, -1), (1, 0, -1)]); q A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays - sage: -q # optional - pynormaliz # optional - sage.rings.number_field + sage: -q # optional - pynormaliz, needs sage.rings.number_field A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays """ from sage.categories.number_fields import NumberFields diff --git a/src/sage/geometry/polyhedron/cdd_file_format.py b/src/sage/geometry/polyhedron/cdd_file_format.py index 78fd01787b7..4388f2ecb0b 100644 --- a/src/sage/geometry/polyhedron/cdd_file_format.py +++ b/src/sage/geometry/polyhedron/cdd_file_format.py @@ -50,8 +50,8 @@ def cdd_Vrepresentation(cdd_type, vertices, rays, lines, file_output=None): sage: cdd_Vrepresentation('rational', [[0,0]], [[1,0]], [[0,1]], file_output=filename) """ vertices = _set_to_None_if_empty(vertices) - rays = _set_to_None_if_empty(rays) - lines = _set_to_None_if_empty(lines) + rays = _set_to_None_if_empty(rays) + lines = _set_to_None_if_empty(lines) num, ambient_dim = _common_length_of(vertices, rays, lines) @@ -115,7 +115,7 @@ def cdd_Hrepresentation(cdd_type, ieqs, eqns, file_output=None): sage: cdd_Hrepresentation('rational', None, [[0,1]], file_output=filename) """ ieqs = _set_to_None_if_empty(ieqs) - eqns = _set_to_None_if_empty(eqns) + eqns = _set_to_None_if_empty(eqns) num, ambient_dim = _common_length_of(ieqs, eqns) ambient_dim -= 1 diff --git a/src/sage/calculus/transforms/__init__.py b/src/sage/geometry/polyhedron/combinatorial_polyhedron/all.py similarity index 100% rename from src/sage/calculus/transforms/__init__.py rename to src/sage/geometry/polyhedron/combinatorial_polyhedron/all.py diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd index 7c2a14192da..030c9defa45 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd @@ -1,13 +1,14 @@ cimport cython -from sage.structure.sage_object cimport SageObject -from .face_iterator cimport FaceIterator, CombinatorialFace -from .list_of_faces cimport ListOfFaces -from .face_data_structure cimport face_t -from .polyhedron_face_lattice cimport PolyhedronFaceLattice +from sage.data_structures.list_of_pairs cimport ListOfPairs +from sage.structure.sage_object cimport SageObject +from .face_iterator cimport FaceIterator, CombinatorialFace +from .list_of_faces cimport ListOfFaces +from .face_data_structure cimport face_t +from .polyhedron_face_lattice cimport PolyhedronFaceLattice @cython.final cdef class CombinatorialPolyhedron(SageObject): - cdef public dict __cached_methods + cdef public dict _cached_methods # Do not assume any of those attributes to be initialized, use the corresponding methods instead. cdef tuple _Vrep # the names of VRep, if they exist @@ -24,22 +25,10 @@ cdef class CombinatorialPolyhedron(SageObject): cdef tuple _far_face_tuple cdef tuple _f_vector - # Edges, ridges and incidences are stored in a pointer of pointers. - # The first edge has vertices ``edges[0][0]`` and ``edges[0][1]``, - # the second edge has vertices ``edges[0][2]`` and ``edges[0][3]``, etc. - # There are ``_length_edges_list`` edges in ``edges[i]``, so the edge - # ``_length_edges_list + 1`` has vertices ``edges[1][0]`` and ``edges[1][1]``. - # Likewise for ridges and incidences. - cdef size_t _length_edges_list - - - cdef size_t **_edges # stores edges labeled by vertex indices - cdef size_t _n_edges - cdef size_t **_ridges # stores ridges labeled by facet indices - cdef size_t _n_ridges - cdef size_t **_face_lattice_incidences # stores incidences in Hasse diagram labeled indices of the faces - cdef size_t _n_face_lattice_incidences - cdef PolyhedronFaceLattice _all_faces # class to generate Hasse diagram incidences + cdef ListOfPairs _edges # stores edges labeled by vertex indices + cdef ListOfPairs _ridges # stores ridges labeled by facet indices + cdef ListOfPairs _face_lattice_incidences # stores incidences in Hasse diagram labeled indices of the faces + cdef PolyhedronFaceLattice _all_faces # class to generate Hasse diagram incidences cdef tuple Vrep(self) cdef tuple facet_names(self) @@ -53,12 +42,24 @@ cdef class CombinatorialPolyhedron(SageObject): cdef tuple far_face_tuple(self) cdef int _algorithm_to_dual(self, algorithm) except -2 + # Methods to initialize the combinatorial polyhedron. + cdef _init_from_polyhedron(self, data) + cdef _init_from_lattice_polytope(self, data) + cdef _init_from_cone(self, data) + cdef _init_facet_names(self, facets) + cdef _init_from_incidence_matrix(self, data) + cdef _init_from_list_of_facets(self, data) + cdef _init_from_ListOfFaces(self, ListOfFaces facets, ListOfFaces Vrep) + cdef _initialize_far_face(self) + cdef _init_as_trivial_polyhedron(self, int dimension) + # Methods to obtain a different combinatorial polyhedron. cpdef CombinatorialPolyhedron dual(self) cpdef CombinatorialPolyhedron pyramid(self, new_vertex=*, new_facet=*) cdef FaceIterator _face_iter(self, bint dual, int dimension) cdef int _compute_f_vector(self, size_t num_threads, size_t parallelization_depth, int dual) except -1 + cdef int _persist_f_vector(self, size_t* input_f_vector, bint input_is_reversed) except -1 cdef inline int _compute_edges(self, dual) except -1: return self._compute_edges_or_ridges(dual, True) @@ -68,11 +69,7 @@ cdef class CombinatorialPolyhedron(SageObject): cdef int _compute_edges_or_ridges(self, int dual, bint do_edges) except -1 cdef size_t _compute_edges_or_ridges_with_iterator( - self, FaceIterator face_iter, const bint do_atom_rep, const bint do_f_vector, - size_t ***edges_pt, size_t *counter_pt, size_t *current_length_pt, - size_t* f_vector) except -1 - cdef int _compute_face_lattice_incidences(self) except -1 + self, FaceIterator face_iter, const bint do_atom_rep, + ListOfPairs edges, size_t* f_vector) except -1 - cdef inline int _set_edge(self, size_t a, size_t b, size_t ***edges_pt, size_t *counter_pt, size_t *current_length_pt) except -1 - cdef inline void _free_edges(self, size_t ***edges_pt, size_t counter) - cdef inline size_t _get_edge(self, size_t **edges, size_t edge_number, size_t vertex) except -1 + cdef int _compute_face_lattice_incidences(self) except -1 diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index de5f26d951f..5a07abb2408 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -49,14 +49,14 @@ Obtaining edges and ridges:: Vertex-graph and facet-graph:: - sage: C.vertex_graph() # optional - sage.graphs + sage: C.vertex_graph() # needs sage.graphs Graph on 16 vertices - sage: C.facet_graph() # optional - sage.graphs + sage: C.facet_graph() # needs sage.graphs Graph on 8 vertices Face lattice:: - sage: C.face_lattice() # optional - sage.combinat + sage: C.face_lattice() # needs sage.combinat Finite lattice containing 82 elements Face iterator:: @@ -73,7 +73,7 @@ AUTHOR: """ # **************************************************************************** -# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -84,9 +84,8 @@ AUTHOR: import numbers from memory_allocator cimport MemoryAllocator -from cysignals.memory cimport check_malloc, check_allocarray, check_reallocarray, check_calloc, sig_free +from cysignals.memory cimport check_calloc, sig_free -from sage.rings.integer import Integer from sage.graphs.graph import Graph from sage.geometry.polyhedron.base import Polyhedron_base from sage.geometry.lattice_polytope import LatticePolytopeClass @@ -103,7 +102,7 @@ from .conversions cimport Vrep_list_to_bit_rep from sage.misc.cachefunc import cached_method from sage.rings.integer cimport smallInteger -from cysignals.signals cimport sig_check, sig_block, sig_unblock +from cysignals.signals cimport sig_check from .face_data_structure cimport face_len_atoms, face_init, face_free from .face_iterator cimport iter_t, parallel_f_vector @@ -329,7 +328,7 @@ cdef class CombinatorialPolyhedron(SageObject): Traceback (most recent call last): ... ValueError: the combinatorial polyhedron was not initialized - sage: C.face_lattice() # optional - sage.combinat + sage: C.face_lattice() # needs sage.combinat Traceback (most recent call last): ... ValueError: the combinatorial polyhedron was not initialized @@ -347,15 +346,6 @@ cdef class CombinatorialPolyhedron(SageObject): self._all_faces = None self._n_facets = -1 - # ``_length_edges_list`` should not be touched in an instance - # of :class:`CombinatorialPolyhedron`. This number can be altered, - # but should probably be a power of `2` (for memory usage). - # ``_length_edges_list`` shouldn't be too small for speed and - # shouldn't be too large, as ``ridges``, ``edges`` and ``incidences`` - # each have a memory overhead of - # ``self._length_edges_list*2*sizeof(size_t *)``. - self._length_edges_list = 16348 - def __init__(self, data, Vrep=None, facets=None, unbounded=False, far_face=None): r""" Initialize :class:`CombinatorialPolyhedron`. @@ -364,71 +354,97 @@ cdef class CombinatorialPolyhedron(SageObject): TESTS:: - sage: C = CombinatorialPolyhedron([[0,1,2],[0,1,3], - ....: [0,2,3],[1,2,3]]) # indirect doctest + sage: C = CombinatorialPolyhedron([[0,1,2], [0,1,3], # indirect doctest + ....: [0,2,3], [1,2,3]]) sage: TestSuite(sage.geometry.polyhedron.combinatorial_polyhedron.base.CombinatorialPolyhedron).run() """ - data_modified = None + self._equations = () + self._far_face_tuple = () if isinstance(data, Polyhedron_base): - # input is ``Polyhedron`` - Vrep = data.Vrepresentation() - facets = tuple(inequality for inequality in data.Hrepresentation()) - self._dimension = data.dimension() - - if not data.is_compact(): - self._bounded = False - far_face = tuple(i for i in range(data.n_Vrepresentation()) if not data.Vrepresentation()[i].is_vertex()) - else: - self._bounded = True - - P = data - data = data.incidence_matrix() + self._init_from_polyhedron(data) + return + if isinstance(data, LatticePolytopeClass): + self._init_from_lattice_polytope(data) + return + if isinstance(data, ConvexRationalPolyhedralCone): + self._init_from_cone(data) + return - # Delete equations - if P.n_equations(): - data_modified = data.delete_columns([e.index() for e in P.equations()]) - else: - data_modified = data - elif isinstance(data, LatticePolytopeClass): - # input is ``LatticePolytope`` - self._bounded = True - Vrep = data.vertices() - self._n_Vrepresentation = len(Vrep) - facets = tuple(data.facet_normals()) - self._n_Hrepresentation = len(facets) - data = data.incidence_matrix() - elif isinstance(data, ConvexRationalPolyhedralCone): - # input is ``Cone`` - self._bounded = False - Vrep = tuple(data.rays()) + (data.lattice().zero(),) - self._n_Vrepresentation = len(Vrep) - facets = tuple(data.facet_normals()) - self._n_Hrepresentation = len(facets) - far_face = tuple(i for i in range(len(Vrep) - 1)) - self._dimension = data.dim() - from sage.matrix.constructor import matrix - from sage.rings.integer_ring import ZZ - data = matrix(ZZ, data.incidence_matrix().rows() - + [[ZZ.one() for _ in range(len(facets))]]) - else: - # Input is different from ``Polyhedron`` and ``LatticePolytope``. - if unbounded and not far_face: + self._bounded = not unbounded + if unbounded: + if not far_face: raise ValueError("must specify far face for unbounded polyhedron") - - self._bounded = not unbounded + self._far_face_tuple = tuple(far_face) if Vrep: - # store vertices names self._Vrep = tuple(Vrep) - Vinv = {v: i for i,v in enumerate(self._Vrep)} + + self._init_facet_names(facets) + + if data == [] or data == (): + self._init_as_trivial_polyhedron(-1) + elif isinstance(data, Matrix): + self._init_from_incidence_matrix(data) + elif isinstance(data, numbers.Integral): + self._init_as_trivial_polyhedron(data) + elif (isinstance(data, (tuple, list)) and + len(data) == 2 and + isinstance(data[0], ListOfFaces) and + isinstance(data[1], ListOfFaces)): + self._init_from_ListOfFaces(data[0], data[1]) + else: - self._Vrep = None - Vinv = None + self._init_from_list_of_facets(data) + + cdef _init_from_polyhedron(self, data): + r''' + Initialize from :class:`~sage.geometry.polyhedron.parent.Polyhedron_base`. + ''' + self._Vrep = data.Vrepresentation() + self._facet_names = data.inequalities() + self._equations = data.equations() + self._dimension = data.dimension() + + if not data.is_compact(): + self._bounded = False + self._far_face_tuple = tuple(i for i in range(data.n_Vrepresentation()) if not data.Vrepresentation()[i].is_vertex()) + else: + self._bounded = True - if facets: - # store facets names and compute equations + return self._init_from_incidence_matrix(data.incidence_matrix()) + + cdef _init_from_lattice_polytope(self, data): + r''' + Initialize from :class:`~sage.geometry.lattice_polytope.LatticePolytopeClass`. + ''' + self._bounded = True + self._Vrep = tuple(data.vertices()) + self._facet_names = tuple(data.facet_normals()) + self._dimension = data.dimension() + return self._init_from_incidence_matrix(data.incidence_matrix()) + + cdef _init_from_cone(self, data): + r''' + Initialize from :class:`~sage.geometry.cone.ConvexRationalPolyhedralCone`. + ''' + self._bounded = False + self._Vrep = tuple(data.rays()) + (data.lattice().zero(),) + self._facet_names = tuple(data.facet_normals()) + self._far_face_tuple = tuple(i for i in range(len(self._Vrep) - 1)) + self._dimension = data.dim() + from sage.matrix.constructor import matrix + from sage.rings.integer_ring import ZZ + incidence_matrix = matrix(ZZ, data.incidence_matrix().rows() + + [[ZZ.one() for _ in range(len(data.facet_normals()))]]) + return self._init_from_incidence_matrix(incidence_matrix) + + cdef _init_facet_names(self, facets): + ''' + Store facet names and compute equations. + ''' + if facets is not None: facets = tuple(facets) test = [1] * len(facets) # 0 if that facet is an equation @@ -445,127 +461,129 @@ cdef class CombinatorialPolyhedron(SageObject): else: self._facet_names = None - if data == [] or data == (): - # Handling the empty polyhedron. - data = -1 - - if isinstance(data, Matrix): - # Input is incidence-matrix or was converted to it. - self._n_Hrepresentation = data.ncols() - self._n_Vrepresentation = data.nrows() - - if not isinstance(data, Matrix_dense): - from sage.rings.integer_ring import ZZ - from sage.matrix.constructor import matrix - data = matrix(ZZ, data, sparse=False) - assert isinstance(data, Matrix_dense), "conversion to ``Matrix_dense`` didn't work" + cdef _init_from_incidence_matrix(self, data): + """ + Initialize from an incidence matrix. + """ + # Input is incidence-matrix or was converted to it. + self._n_Hrepresentation = data.ncols() + self._n_Vrepresentation = data.nrows() - # Store the incidence matrix. - if not data.is_immutable(): - data = data.__copy__() - data.set_immutable() - self.incidence_matrix.set_cache(data) + if not isinstance(data, Matrix_dense): + from sage.rings.integer_ring import ZZ + from sage.matrix.constructor import matrix + data = matrix(ZZ, data, sparse=False) + assert isinstance(data, Matrix_dense), "conversion to ``Matrix_dense`` didn't work" + # Store the incidence matrix. + if not data.is_immutable(): + data = data.__copy__() + data.set_immutable() + self.incidence_matrix.set_cache(data) - if data_modified is None: - # Delete equations. - data_modified = data.delete_columns([i for i in range(data.ncols()) if all(data[j,i] for j in range(data.nrows()))], check=False) - # Initializing the facets in their Bit-representation. - self._bitrep_facets = incidence_matrix_to_bit_rep_of_facets(data_modified) + # Delete equations. + data = data.delete_columns( + [i for i in range(data.ncols()) + if all(data[j,i] for j in range(data.nrows()))], + check=False) - # Initializing the Vrep as their Bit-representation. - self._bitrep_Vrep = incidence_matrix_to_bit_rep_of_Vrep(data_modified) + # Initializing the facets in their Bit-representation. + self._bitrep_facets = incidence_matrix_to_bit_rep_of_facets(data) - self._n_facets = self.bitrep_facets().n_faces() + # Initializing the Vrep as their Bit-representation. + self._bitrep_Vrep = incidence_matrix_to_bit_rep_of_Vrep(data) - # Initialize far_face if unbounded. - if not self._bounded: - face_init(self._far_face, self.bitrep_facets().n_atoms(), self._n_facets) - Vrep_list_to_bit_rep(tuple(far_face), self._far_face) + self._n_facets = self.bitrep_facets().n_faces() - elif isinstance(data, numbers.Integral): - # To construct a trivial polyhedron, equal to its affine hull, - # one can give an Integer as Input. - if data < -1: - raise ValueError("any polyhedron must have dimension at least -1") - self._dimension = data - - if self._dimension == 0: - self._n_facets = 1 - self._n_Vrepresentation = 1 - else: - self._n_facets = 0 - self._n_Vrepresentation = 0 + self._initialize_far_face() - # Initializing the facets in their Bit-representation. - self._bitrep_facets = facets_tuple_to_bit_rep_of_facets((), 0) + cdef _init_from_list_of_facets(self, data): + """ + Initialize from a list of facets. - # Initializing the Vrep as their Bit-representation. - self._bitrep_Vrep = facets_tuple_to_bit_rep_of_Vrep((), 0) + Tuple and iterator work as well. - elif isinstance(data, (tuple, list)) and len(data) == 2 and isinstance(data[0], ListOfFaces) and isinstance(data[1], ListOfFaces): - # Initialize self from two ``ListOfFaces``. - self._bitrep_facets = data[0] - self._bitrep_Vrep = data[1] + The facets are given by its ``[vertices, rays, lines]``. + """ + if is_iterator(data): + data = tuple(data) - self._n_Hrepresentation = self._bitrep_facets.n_faces() - self._n_Vrepresentation = self._bitrep_Vrep.n_faces() - self._n_facets = self._n_Hrepresentation + if self._Vrep is None: + # Get the names of the Vrep. + Vrep = sorted(set.union(*map(set, data))) + n_Vrepresentation = len(Vrep) + if Vrep != range(len(Vrep)): + self._Vrep = tuple(Vrep) + Vinv = {v: i for i,v in enumerate(self._Vrep)} + else: + # Assuming the user gave as correct names for the vertices + # and labeled them instead by `0,...,n`. + n_Vrepresentation = len(self._Vrep) - # Initialize far_face if unbounded. - if not self._bounded: - face_init(self._far_face, self.bitrep_facets().n_atoms(), self._n_facets) - Vrep_list_to_bit_rep(tuple(far_face), self._far_face) + self._n_Vrepresentation = n_Vrepresentation + # Relabel the Vrep to be `0,...,n`. + if self._Vrep is not None: + def f(v): + return Vinv[v] else: - # Input is a "list" of facets. - # The facets given by its ``[vertices, rays, lines]``. - # Actually at least tuple, list, iterator will work. - if is_iterator(data): - data = tuple(data) - - if self._Vrep is None: - # Get the names of the Vrep. - Vrep = sorted(set.union(*map(set, data))) - n_Vrepresentation = len(Vrep) - if Vrep != range(len(Vrep)): - self._Vrep = tuple(Vrep) - Vinv = {v: i for i,v in enumerate(self._Vrep)} - else: - # Assuming the user gave as correct names for the vertices - # and labeled them instead by `0,...,n`. - n_Vrepresentation = len(self._Vrep) + def f(v): + return int(v) + facets = tuple(tuple(f(i) for i in j) for j in data) - self._n_Vrepresentation = n_Vrepresentation + self._n_facets = len(facets) + self._n_Hrepresentation = len(facets) - # Relabel the Vrep to be `0,...,n`. - if self._Vrep is not None: - def f(v): - return Vinv[v] - else: - def f(v): - return int(v) - facets = tuple(tuple(f(i) for i in j) for j in data) + # Initializing the facets in their Bit-representation. + self._bitrep_facets = facets_tuple_to_bit_rep_of_facets(facets, n_Vrepresentation) + + # Initializing the Vrep as their Bit-representation. + self._bitrep_Vrep = facets_tuple_to_bit_rep_of_Vrep(facets, n_Vrepresentation) - self._n_facets = len(facets) - self._n_Hrepresentation = len(facets) + self._initialize_far_face() - # Initializing the facets in their Bit-representation. - self._bitrep_facets = facets_tuple_to_bit_rep_of_facets(facets, n_Vrepresentation) + cdef _init_from_ListOfFaces(self, ListOfFaces facets, ListOfFaces Vrep): + """ + Initialize self from two ``ListOfFaces``. + """ + self._bitrep_facets = facets + self._bitrep_Vrep = Vrep - # Initializing the Vrep as their Bit-representation. - self._bitrep_Vrep = facets_tuple_to_bit_rep_of_Vrep(facets, n_Vrepresentation) + self._n_Hrepresentation = self._bitrep_facets.n_faces() + self._n_Vrepresentation = self._bitrep_Vrep.n_faces() + self._n_facets = self._n_Hrepresentation - # Initialize far_face if unbounded. - if not self._bounded: - face_init(self._far_face, self.bitrep_facets().n_atoms(), self._n_facets) - Vrep_list_to_bit_rep(tuple(far_face), self._far_face) + self._initialize_far_face() + cdef _initialize_far_face(self): + """ + Initialize far_face if unbounded. + """ if not self._bounded: - self._far_face_tuple = tuple(far_face) + face_init(self._far_face, self.bitrep_facets().n_atoms(), self._n_facets) + Vrep_list_to_bit_rep(tuple(self._far_face_tuple), self._far_face) + + cdef _init_as_trivial_polyhedron(self, int dimension): + """ + Initialize polyhedron equal to its affine hull. + """ + if dimension < -1: + raise ValueError("any polyhedron must have dimension at least -1") + self._dimension = dimension + + if self._dimension == 0: + self._n_facets = 1 + self._n_Vrepresentation = 1 else: - self._far_face_tuple = () + self._n_facets = 0 + self._n_Vrepresentation = 0 + + # Initializing the facets in their Bit-representation. + self._bitrep_facets = facets_tuple_to_bit_rep_of_facets((), 0) + + # Initializing the Vrep as their Bit-representation. + self._bitrep_Vrep = facets_tuple_to_bit_rep_of_Vrep((), 0) def __dealloc__(self): """ @@ -578,9 +596,6 @@ cdef class CombinatorialPolyhedron(SageObject): """ if not self._bounded: face_free(self._far_face) - self._free_edges(&self._edges, self._n_edges) - self._free_edges(&self._ridges, self._n_ridges) - self._free_edges(&self._face_lattice_incidences, self._n_face_lattice_incidences) def _repr_(self): r""" @@ -625,16 +640,17 @@ cdef class CombinatorialPolyhedron(SageObject): TESTS:: - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C1 = loads(C.dumps()) # optional - sage.combinat - sage: it = C.face_generator() # optional - sage.combinat - sage: it1 = C1.face_generator() # optional - sage.combinat - sage: tup = tuple((face.ambient_Vrepresentation(), # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = CombinatorialPolyhedron(P) + sage: C1 = loads(C.dumps()) + sage: it = C.face_generator() + sage: it1 = C1.face_generator() + sage: tup = tuple((face.ambient_Vrepresentation(), ....: face.ambient_Hrepresentation()) for face in it) - sage: tup1 = tuple((face.ambient_Vrepresentation(), # optional - sage.combinat + sage: tup1 = tuple((face.ambient_Vrepresentation(), ....: face.ambient_Hrepresentation()) for face in it1) - sage: tup == tup1 # optional - sage.combinat + sage: tup == tup1 True sage: P = polytopes.cyclic_polytope(4,10) @@ -732,9 +748,9 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(3) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.Hrepresentation() # optional - sage.combinat + sage: P = polytopes.permutahedron(3) + sage: C = CombinatorialPolyhedron(P) + sage: C.Hrepresentation() (An inequality (1, 1, 0) x - 3 >= 0, An inequality (-1, -1, 0) x + 5 >= 0, An inequality (0, 1, 0) x - 1 >= 0, @@ -1089,10 +1105,11 @@ cdef class CombinatorialPolyhedron(SageObject): :: - sage: P = polytopes.permutahedron(5, backend='field') # optional - sage.combinat - sage: C = P.combinatorial_polyhedron() # optional - sage.combinat - sage: C.incidence_matrix.clear_cache() # optional - sage.combinat - sage: C.incidence_matrix() == P.incidence_matrix() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5, backend='field') + sage: C = P.combinatorial_polyhedron() + sage: C.incidence_matrix.clear_cache() + sage: C.incidence_matrix() == P.incidence_matrix() True The incidence matrix is consistent with @@ -1243,15 +1260,10 @@ cdef class CombinatorialPolyhedron(SageObject): def f(size_t i): return smallInteger(i) - # Getting the indices of the `i`-th edge. - def vertex_one(size_t i): - return f(self._get_edge(self._edges, i, 0)) - - def vertex_two(size_t i): - return f(self._get_edge(self._edges, i, 1)) - cdef size_t j - return tuple((vertex_one(j), vertex_two(j)) for j in range(self._n_edges)) + return tuple((f(self._edges.get(j).first), + f(self._edges.get(j).second)) + for j in range(self._edges.length)) def vertex_graph(self, names=True, algorithm=None): r""" @@ -1274,15 +1286,14 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = polytopes.cyclic_polytope(3,5) sage: C = CombinatorialPolyhedron(P) - sage: C.vertex_graph() + sage: G = C.vertex_graph(); G # needs sage.graphs Graph on 5 vertices - sage: G = C.vertex_graph() - sage: sorted(G.degree()) + sage: sorted(G.degree()) # needs sage.graphs [3, 3, 4, 4, 4] sage: P = Polyhedron(rays=[[1]]) sage: C = CombinatorialPolyhedron(P) - sage: C.graph() + sage: C.graph() # needs sage.graphs Graph on 1 vertex """ vertices = self.vertices(names=names) @@ -1339,14 +1350,14 @@ cdef class CombinatorialPolyhedron(SageObject): from sage.matrix.constructor import matrix cdef Matrix_dense adjacency_matrix = matrix( ZZ, self.n_Vrepresentation(), self.n_Vrepresentation(), 0) - cdef size_t i, a, b + cdef size_t i, first, second self._compute_edges(self._algorithm_to_dual(algorithm)) - for i in range(self._n_edges): - a = self._get_edge(self._edges, i, 0) - b = self._get_edge(self._edges, i, 1) - adjacency_matrix.set_unsafe_int(a, b, 1) - adjacency_matrix.set_unsafe_int(b, a, 1) + for i in range(self._edges.length): + first = self._edges.get(i).first + second = self._edges.get(i).second + adjacency_matrix.set_unsafe_int(first, second, 1) + adjacency_matrix.set_unsafe_int(second, first, 1) adjacency_matrix.set_immutable() return adjacency_matrix @@ -1383,11 +1394,12 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(2) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.ridges() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(2) + sage: C = CombinatorialPolyhedron(P) + sage: C.ridges() ((An inequality (1, 0) x - 1 >= 0, An inequality (-1, 0) x + 2 >= 0),) - sage: C.ridges(add_equations=True) # optional - sage.combinat + sage: C.ridges(add_equations=True) (((An inequality (1, 0) x - 1 >= 0, An equation (1, 1) x - 3 == 0), (An inequality (-1, 0) x + 2 >= 0, An equation (1, 1) x - 3 == 0)),) @@ -1459,7 +1471,7 @@ cdef class CombinatorialPolyhedron(SageObject): deprecation(31834, "the keyword ``add_equalities`` is deprecated; use ``add_equations``", 3) add_equations = True self._compute_ridges(self._algorithm_to_dual(algorithm)) - n_ridges = self._n_ridges + cdef size_t n_ridges = self._ridges.length # Mapping the indices of the Vepr to the names, if requested. if self.facet_names() is not None and names is True: @@ -1469,23 +1481,16 @@ cdef class CombinatorialPolyhedron(SageObject): def f(size_t i): return smallInteger(i) - # Getting the indices of the `i`-th ridge. - def facet_one(size_t i): - return f(self._get_edge(self._ridges, i, 0)) - - def facet_two(size_t i): - return f(self._get_edge(self._ridges, i, 1)) - - cdef size_t j if add_equations and names: - # Also getting the equations for each facet. return tuple( - (((facet_one(i),) + self.equations()), - ((facet_two(i),) + self.equations())) - for i in range(n_ridges)) + ((f(self._ridges.get(i).first),) + self.equations(), + (f(self._ridges.get(i).second),) + self.equations()) + for i in range (n_ridges)) else: - return tuple((facet_one(i), facet_two(i)) - for i in range(n_ridges)) + return tuple( + (f(self._ridges.get(i).first), + f(self._ridges.get(i).second)) + for i in range (n_ridges)) @cached_method def facet_adjacency_matrix(self, algorithm=None): @@ -1529,14 +1534,14 @@ cdef class CombinatorialPolyhedron(SageObject): from sage.matrix.constructor import matrix cdef Matrix_dense adjacency_matrix = matrix( ZZ, self.n_facets(), self.n_facets(), 0) - cdef size_t i, a, b + cdef size_t i self._compute_ridges(self._algorithm_to_dual(algorithm)) - for i in range(self._n_ridges): - a = self._get_edge(self._ridges, i, 0) - b = self._get_edge(self._ridges, i, 1) - adjacency_matrix.set_unsafe_int(a, b, 1) - adjacency_matrix.set_unsafe_int(b, a, 1) + for i in range(self._ridges.length): + first = self._ridges.get(i).first + second = self._ridges.get(i).second + adjacency_matrix.set_unsafe_int(first, second, 1) + adjacency_matrix.set_unsafe_int(second, first, 1) adjacency_matrix.set_immutable() return adjacency_matrix @@ -1563,25 +1568,25 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = polytopes.cyclic_polytope(4,6) sage: C = CombinatorialPolyhedron(P) - sage: C.facet_graph() + sage: C.facet_graph() # needs sage.graphs Graph on 9 vertices TESTS:: sage: P = Polyhedron(ieqs=[[1,-1,0],[1,1,0]]) - sage: CombinatorialPolyhedron(P).facet_graph() + sage: CombinatorialPolyhedron(P).facet_graph() # needs sage.graphs Graph on 2 vertices Checking that :trac:`28604` is fixed:: sage: C = CombinatorialPolyhedron(polytopes.cube()); C A 3-dimensional combinatorial polyhedron with 6 facets - sage: C.facet_graph(names=False) + sage: C.facet_graph(names=False) # needs sage.graphs Graph on 6 vertices sage: C = CombinatorialPolyhedron(polytopes.hypersimplex(5,2)); C A 4-dimensional combinatorial polyhedron with 10 facets - sage: C.facet_graph() + sage: C.facet_graph() # needs sage.combinat sage.graphs Graph on 10 vertices """ face_iter = self.face_iter(self.dimension() - 1, algorithm='primal') @@ -1619,7 +1624,7 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = polytopes.hypercube(2).pyramid() sage: C = CombinatorialPolyhedron(P) - sage: G = C.vertex_facet_graph(); G + sage: G = C.vertex_facet_graph(); G # needs sage.graphs Digraph on 10 vertices sage: C.Vrepresentation() (A vertex at (0, -1, -1), @@ -1627,7 +1632,7 @@ cdef class CombinatorialPolyhedron(SageObject): A vertex at (0, 1, -1), A vertex at (0, 1, 1), A vertex at (1, 0, 0)) - sage: sorted(G.neighbors_out(C.Vrepresentation()[4])) + sage: sorted(G.neighbors_out(C.Vrepresentation()[4])) # needs sage.graphs [An inequality (-1, -1, 0) x + 1 >= 0, An inequality (-1, 0, -1) x + 1 >= 0, An inequality (-1, 0, 1) x + 1 >= 0, @@ -1640,7 +1645,7 @@ cdef class CombinatorialPolyhedron(SageObject): with a string 'H' or 'V':: sage: C = CombinatorialPolyhedron(P.incidence_matrix()) - sage: C.vertex_facet_graph().vertices(sort=True) + sage: C.vertex_facet_graph().vertices(sort=True) # needs sage.graphs [('H', 0), ('H', 1), ('H', 2), @@ -1654,18 +1659,18 @@ cdef class CombinatorialPolyhedron(SageObject): If ``names`` is ``False`` then the vertices of the graph are given by integers:: - sage: C.vertex_facet_graph(names=False).vertices(sort=True) + sage: C.vertex_facet_graph(names=False).vertices(sort=True) # needs sage.graphs [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] TESTS: Test that :trac:`29898` is fixed:: - sage: Polyhedron().vertex_facet_graph() + sage: Polyhedron().vertex_facet_graph() # needs sage.graphs Digraph on 0 vertices - sage: Polyhedron([[0]]).vertex_facet_graph() + sage: Polyhedron([[0]]).vertex_facet_graph() # needs sage.graphs Digraph on 1 vertex - sage: Polyhedron([[0]]).vertex_facet_graph(False) + sage: Polyhedron([[0]]).vertex_facet_graph(False) # needs sage.graphs Digraph on 1 vertex """ from sage.graphs.digraph import DiGraph @@ -1734,9 +1739,9 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.f_vector() # optional - sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: C.f_vector() (1, 120, 240, 150, 30, 1) sage: P = polytopes.cyclic_polytope(6,10) @@ -1746,9 +1751,9 @@ cdef class CombinatorialPolyhedron(SageObject): Using two threads:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.f_vector(num_threads=2) # optional - sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: C.f_vector(num_threads=2) (1, 120, 240, 150, 30, 1) TESTS:: @@ -1806,7 +1811,7 @@ cdef class CombinatorialPolyhedron(SageObject): Obtain the entire flag-f-vector:: sage: C = polytopes.hypercube(4).combinatorial_polyhedron() - sage: C.flag_f_vector() # optional - sage.combinat + sage: C.flag_f_vector() # needs sage.combinat {(-1,): 1, (0,): 16, (0, 1): 64, @@ -1827,38 +1832,38 @@ cdef class CombinatorialPolyhedron(SageObject): Specify an entry:: - sage: C.flag_f_vector(0,3) # optional - sage.combinat + sage: C.flag_f_vector(0,3) # needs sage.combinat 64 - sage: C.flag_f_vector(2) # optional - sage.combinat + sage: C.flag_f_vector(2) # needs sage.combinat 24 Leading ``-1`` and trailing entry of dimension are allowed:: - sage: C.flag_f_vector(-1,0,3) # optional - sage.combinat + sage: C.flag_f_vector(-1,0,3) # needs sage.combinat 64 - sage: C.flag_f_vector(-1,0,3,4) # optional - sage.combinat + sage: C.flag_f_vector(-1,0,3,4) # needs sage.combinat 64 One can get the number of trivial faces:: - sage: C.flag_f_vector(-1) # optional - sage.combinat + sage: C.flag_f_vector(-1) # needs sage.combinat 1 - sage: C.flag_f_vector(4) # optional - sage.combinat + sage: C.flag_f_vector(4) # needs sage.combinat 1 Polyhedra with lines, have ``0`` entries accordingly:: sage: C = (Polyhedron(lines=[[1]]) * polytopes.hypercube(2)).combinatorial_polyhedron() - sage: C.flag_f_vector() # optional - sage.combinat + sage: C.flag_f_vector() # needs sage.combinat {(-1,): 1, (0, 1): 0, (0, 2): 0, (0,): 0, (1, 2): 8, (1,): 4, (2,): 4, 3: 1} If the arguments are not stricly increasing or out of range, a key error is raised:: - sage: C.flag_f_vector(-1,0,3,5) # optional - sage.combinat + sage: C.flag_f_vector(-1,0,3,5) # needs sage.combinat Traceback (most recent call last): ... KeyError: (0, 3, 5) - sage: C.flag_f_vector(-1,3,0) # optional - sage.combinat + sage: C.flag_f_vector(-1,3,0) # needs sage.combinat Traceback (most recent call last): ... KeyError: (3, 0) @@ -1886,7 +1891,7 @@ cdef class CombinatorialPolyhedron(SageObject): TESTS:: sage: C = CombinatorialPolyhedron(3) - sage: C._flag_f_vector() # optional - sage.combinat + sage: C._flag_f_vector() # needs sage.combinat {(-1,): 1, (0, 1): 0, (0, 2): 0, (0,): 0, (1, 2): 0, (1,): 0, (2,): 0, 3: 1} """ poly = self.face_lattice().flag_f_polynomial() @@ -2123,7 +2128,7 @@ cdef class CombinatorialPolyhedron(SageObject): # For each face in the iterator, check if its a simplex. face_iter.structure.lowest_dimension = 2 # every 1-face is a simplex d = face_iter.next_dimension() - while (d < dim): + while d < dim: sig_check() if face_iter.n_atom_rep() == d + 1: # The current face is a simplex. @@ -2234,7 +2239,7 @@ cdef class CombinatorialPolyhedron(SageObject): # For each coface in the iterator, check if its a simplex. coface_iter.structure.lowest_dimension = 2 # every coface of dimension 1 is a simplex d = coface_iter.next_dimension() - while (d < dim): + while d < dim: sig_check() if coface_iter.n_atom_rep() == d + 1: # The current coface is a simplex. @@ -2629,15 +2634,16 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.join_of_Vrep(0,1) # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = CombinatorialPolyhedron(P) + sage: C.join_of_Vrep(0,1) A 1-dimensional face of a 3-dimensional combinatorial polyhedron - sage: C.join_of_Vrep(0,11).ambient_V_indices() # optional - sage.combinat + sage: C.join_of_Vrep(0,11).ambient_V_indices() (0, 1, 10, 11, 12, 13) - sage: C.join_of_Vrep(8).ambient_V_indices() # optional - sage.combinat + sage: C.join_of_Vrep(8).ambient_V_indices() (8,) - sage: C.join_of_Vrep().ambient_V_indices() # optional - sage.combinat + sage: C.join_of_Vrep().ambient_V_indices() () """ return self.face_generator().join_of_Vrep(*indices) @@ -2652,19 +2658,20 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: C = CombinatorialPolyhedron(P) # optional - sage.rings.number_field - sage: C.meet_of_Hrep(0) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: C = CombinatorialPolyhedron(P) + sage: C.meet_of_Hrep(0) A 2-dimensional face of a 3-dimensional combinatorial polyhedron - sage: C.meet_of_Hrep(0).ambient_H_indices() # optional - sage.rings.number_field + sage: C.meet_of_Hrep(0).ambient_H_indices() (0,) - sage: C.meet_of_Hrep(0,1).ambient_H_indices() # optional - sage.rings.number_field + sage: C.meet_of_Hrep(0,1).ambient_H_indices() (0, 1) - sage: C.meet_of_Hrep(0,2).ambient_H_indices() # optional - sage.rings.number_field + sage: C.meet_of_Hrep(0,2).ambient_H_indices() (0, 2) - sage: C.meet_of_Hrep(0,2,3).ambient_H_indices() # optional - sage.rings.number_field + sage: C.meet_of_Hrep(0,2,3).ambient_H_indices() (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) - sage: C.meet_of_Hrep().ambient_H_indices() # optional - sage.rings.number_field + sage: C.meet_of_Hrep().ambient_H_indices() () """ return self.face_generator().meet_of_Hrep(*indices) @@ -2695,38 +2702,39 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(dimension=2) # optional - sage.combinat - sage: face = next(it); face # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(dimension=2) + sage: face = next(it); face A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_Vrepresentation() # optional - sage.combinat + sage: face.ambient_Vrepresentation() (A vertex at (1, 3, 2, 5, 4), A vertex at (2, 3, 1, 5, 4), A vertex at (3, 1, 2, 5, 4), A vertex at (3, 2, 1, 5, 4), A vertex at (2, 1, 3, 5, 4), A vertex at (1, 2, 3, 5, 4)) - sage: face = next(it); face # optional - sage.combinat + sage: face = next(it); face A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_Vrepresentation() # optional - sage.combinat + sage: face.ambient_Vrepresentation() (A vertex at (2, 1, 4, 5, 3), A vertex at (3, 2, 4, 5, 1), A vertex at (3, 1, 4, 5, 2), A vertex at (1, 3, 4, 5, 2), A vertex at (1, 2, 4, 5, 3), A vertex at (2, 3, 4, 5, 1)) - sage: face.ambient_Hrepresentation() # optional - sage.combinat + sage: face.ambient_Hrepresentation() (An inequality (0, 0, -1, -1, 0) x + 9 >= 0, An inequality (0, 0, 0, -1, 0) x + 5 >= 0, An equation (1, 1, 1, 1, 1) x - 15 == 0) - sage: face.ambient_H_indices() # optional - sage.combinat + sage: face.ambient_H_indices() (25, 29, 30) - sage: face = next(it); face # optional - sage.combinat + sage: face = next(it); face A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_H_indices() # optional - sage.combinat + sage: face.ambient_H_indices() (24, 29, 30) - sage: face.ambient_V_indices() # optional - sage.combinat + sage: face.ambient_V_indices() (32, 89, 90, 94) sage: C = CombinatorialPolyhedron([[0,1,2],[0,1,3],[0,2,3],[1,2,3]]) @@ -2838,31 +2846,31 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = Polyhedron(rays=[[1,0],[0,1]]) sage: C = CombinatorialPolyhedron(P) - sage: C.face_lattice() + sage: C.face_lattice() # needs sage.combinat Finite lattice containing 5 elements sage: P = Polyhedron(rays=[[1,0,0], [-1,0,0], [0,-1,0], [0,1,0]]) sage: C = CombinatorialPolyhedron(P) sage: P1 = Polyhedron(rays=[[1,0], [-1,0]]) sage: C1 = CombinatorialPolyhedron(P1) - sage: C.face_lattice().is_isomorphic(C1.face_lattice()) + sage: C.face_lattice().is_isomorphic(C1.face_lattice()) # needs sage.combinat True - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.face_lattice() # optional - sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: C.face_lattice() # needs sage.combinat Finite lattice containing 542 elements TESTS:: sage: P = polytopes.cyclic_polytope(4,10) sage: C = CombinatorialPolyhedron(P) - sage: C.face_lattice().is_isomorphic(P.face_lattice()) + sage: C.face_lattice().is_isomorphic(P.face_lattice()) # needs sage.combinat True - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.face_lattice().is_isomorphic(P.face_lattice()) # optional - sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = CombinatorialPolyhedron(P) + sage: C.face_lattice().is_isomorphic(P.face_lattice()) # needs sage.combinat True """ from sage.combinat.posets.lattices import FiniteLatticePoset @@ -2892,42 +2900,33 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.regular_polygon(4).pyramid() # optional - sage.rings.number_field - sage: C = CombinatorialPolyhedron(P) # optional - sage.rings.number_field - sage: D = C.hasse_diagram(); D # optional - sage.graphs # optional - sage.rings.number_field + sage: # needs sage.graphs sage.rings.number_field + sage: P = polytopes.regular_polygon(4).pyramid() + sage: C = CombinatorialPolyhedron(P) + sage: D = C.hasse_diagram(); D Digraph on 20 vertices - sage: D.average_degree() # optional - sage.graphs # optional - sage.rings.number_field + sage: D.average_degree() 21/5 - sage: D.relabel(C.face_by_face_lattice_index) # optional - sage.graphs # optional - sage.rings.number_field - sage: dim_0_vert = D.vertices(sort=True)[1:6]; dim_0_vert # optional - sage.graphs # optional - sage.rings.number_field + sage: D.relabel(C.face_by_face_lattice_index) + sage: dim_0_vert = D.vertices(sort=True)[1:6]; dim_0_vert [A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron] - sage: sorted(D.out_degree(vertices=dim_0_vert)) # optional - sage.graphs # optional - sage.rings.number_field + sage: sorted(D.out_degree(vertices=dim_0_vert)) [3, 3, 3, 3, 4] """ if not self._face_lattice_incidences: # compute all incidences. self._compute_face_lattice_incidences() - if self._face_lattice_incidences is NULL: + if self._face_lattice_incidences is None: raise TypeError("could not determine face lattice") - cdef size_t **incidences = self._face_lattice_incidences - cdef size_t n_incidences = self._n_face_lattice_incidences - - # Getting the indices of the `i`-th incidence. - def face_one(size_t i): - return smallInteger(self._get_edge(incidences, i, 0)) - - def face_two(size_t i): - return smallInteger(self._get_edge(incidences, i, 1)) - # Edges of the face-lattice/Hasse diagram. cdef size_t j - edges = tuple((face_one(j), face_two(j)) - for j in range(n_incidences)) + cdef size_t n_incidences = self._face_lattice_incidences.length + edges = tuple(self._face_lattice_incidences[j] for j in range(n_incidences)) V = tuple(smallInteger(i) for i in range(sum(self._f_vector))) @@ -2944,12 +2943,12 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = polytopes.cube() sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() # optional - sage.combinat + sage: F = C.face_lattice() # needs sage.combinat sage: def f(i): ....: return (i, C._face_lattice_dimension(i)) ....: - sage: G = F.relabel(f) # optional - sage.combinat - sage: set(G._elements) # optional - sage.combinat + sage: G = F.relabel(f) # needs sage.combinat + sage: set(G._elements) # needs sage.combinat {(0, -1), (1, 0), (2, 0), @@ -2998,15 +2997,16 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: + sage: # needs sage.combinat sage: P = polytopes.cube() sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() # optional - sage.combinat - sage: F # optional - sage.combinat + sage: F = C.face_lattice() + sage: F Finite lattice containing 28 elements - sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat - sage: G.level_sets()[0] # optional - sage.combinat + sage: G = F.relabel(C.face_by_face_lattice_index) + sage: G.level_sets()[0] [A -1-dimensional face of a 3-dimensional combinatorial polyhedron] - sage: G.level_sets()[3] # optional - sage.combinat + sage: G.level_sets()[3] [A 2-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron, @@ -3016,9 +3016,9 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = Polyhedron(rays=[[0,1], [1,0]]) sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() # optional - sage.combinat - sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat - sage: G._elements # optional - sage.combinat + sage: F = C.face_lattice() # needs sage.combinat + sage: G = F.relabel(C.face_by_face_lattice_index) # needs sage.combinat + sage: G._elements # needs sage.combinat (A -1-dimensional face of a 2-dimensional combinatorial polyhedron, A 0-dimensional face of a 2-dimensional combinatorial polyhedron, A 1-dimensional face of a 2-dimensional combinatorial polyhedron, @@ -3026,8 +3026,8 @@ cdef class CombinatorialPolyhedron(SageObject): A 2-dimensional face of a 2-dimensional combinatorial polyhedron) sage: def f(i): return C.face_by_face_lattice_index(i).ambient_V_indices() - sage: G = F.relabel(f) # optional - sage.combinat - sage: G._elements # optional - sage.combinat + sage: G = F.relabel(f) # needs sage.combinat + sage: G._elements # needs sage.combinat ((), (0,), (0, 1), (0, 2), (0, 1, 2)) """ self._record_all_faces() # Initialize ``_all_faces``, if not done yet. @@ -3072,13 +3072,14 @@ cdef class CombinatorialPolyhedron(SageObject): sage: [face.ambient_V_indices() for face in chain] [(15,), (6, 15), (5, 6, 14, 15), (0, 5, 6, 7, 8, 9, 14, 15)] - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = P.combinatorial_polyhedron() # optional - sage.combinat - sage: chain = C.a_maximal_chain(); chain # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = P.combinatorial_polyhedron() + sage: chain = C.a_maximal_chain(); chain [A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 1-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron] - sage: [face.ambient_V_indices() for face in chain] # optional - sage.combinat + sage: [face.ambient_V_indices() for face in chain] [(16,), (15, 16), (8, 9, 14, 15, 16, 17)] sage: P = Polyhedron(rays=[[1,0]], lines=[[0,1]]) @@ -3374,7 +3375,7 @@ cdef class CombinatorialPolyhedron(SageObject): sage: D.f_vector() (1, 6, 12, 8, 1) sage: D1 = P.polar().combinatorial_polyhedron() - sage: D1.face_lattice().is_isomorphic(D.face_lattice()) # optional - sage.combinat + sage: D1.face_lattice().is_isomorphic(D.face_lattice()) # needs sage.combinat True Polar is an alias to be consistent with :class:`~sage.geometry.polyhedron.base.Polyhedron_base`:: @@ -3424,7 +3425,7 @@ cdef class CombinatorialPolyhedron(SageObject): sage: C1 = C.pyramid() sage: P1 = P.pyramid() sage: C2 = P1.combinatorial_polyhedron() - sage: C2.vertex_facet_graph().is_isomorphic(C1.vertex_facet_graph()) # optional - sage.combinat + sage: C2.vertex_facet_graph().is_isomorphic(C1.vertex_facet_graph()) # needs sage.combinat True One can specify a name for the new vertex:: @@ -3443,10 +3444,11 @@ cdef class CombinatorialPolyhedron(SageObject): One can specify a name for the new facets:: - sage: P = polytopes.regular_polygon(4) # optional - sage.rings.number_field - sage: C = P.combinatorial_polyhedron() # optional - sage.rings.number_field - sage: C1 = C.pyramid(new_facet='base') # optional - sage.rings.number_field - sage: C1.Hrepresentation() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.regular_polygon(4) + sage: C = P.combinatorial_polyhedron() + sage: C1 = C.pyramid(new_facet='base') + sage: C1.Hrepresentation() (An inequality (-1/2, 1/2) x + 1/2 >= 0, An inequality (-1/2, -1/2) x + 1/2 >= 0, An inequality (1/2, 0.50000000000000000?) x + 1/2 >= 0, @@ -3529,24 +3531,26 @@ cdef class CombinatorialPolyhedron(SageObject): parallel_f_vector(structs, num_threads, parallelization_depth, f_vector) - # Copy ``f_vector``. - if dual: - if dim > 1 and f_vector[1] < self.n_facets(): - # The input seemed to be wrong. - raise ValueError("not all facets are joins of vertices") + self._persist_f_vector(f_vector, dual) - # We have computed the ``f_vector`` of the dual. - # Reverse it: - self._f_vector = \ - tuple(smallInteger(f_vector[dim+1-i]) for i in range(dim+2)) + cdef int _persist_f_vector(self, size_t* input_f_vector, bint input_is_reversed) except -1: + cdef int dim = self.dimension() + if input_is_reversed: + f_vector = \ + tuple(smallInteger(input_f_vector[dim + 1 - i]) for i in range(dim + 2)) else: - if self.is_bounded() and dim > 1 \ - and f_vector[1] < self.n_Vrepresentation() - len(self.far_face_tuple()): - # The input seemed to be wrong. + f_vector = \ + tuple(smallInteger(input_f_vector[i]) for i in range(dim + 2)) + + # Sanity checks. + if dim > 1: + if f_vector[-2] < self.n_facets(): + raise ValueError("not all facets are joins of vertices") + if self.is_bounded() and f_vector[1] < self.n_Vrepresentation(): raise ValueError("not all vertices are intersections of facets") - self._f_vector = tuple(smallInteger(f_vector[i]) for i in range(dim+2)) + self._f_vector = f_vector cdef int _compute_edges_or_ridges(self, int dual, bint do_edges) except -1: r""" @@ -3560,57 +3564,29 @@ cdef class CombinatorialPolyhedron(SageObject): See :meth:`CombinatorialPolyhedron.edges` and :meth:`CombinatorialPolyhedron.ridges`. """ - if (self._edges is not NULL and do_edges) or (self._ridges is not NULL and not do_edges): + if (self._edges is not None and do_edges) or (self._ridges is not None and not do_edges): return 0 # There is no need to recompute. if dual == -1: # Determine whether to use dual mode or not. if not self.is_bounded(): dual = 0 - else: - if self.is_simple(): - per_face_primal = self.n_Vrepresentation() * self.n_facets() - else: - per_face_primal = self.n_Vrepresentation() * self.n_facets() ** 2 - - if self.is_simplicial(): - per_face_dual = self.n_Vrepresentation() * self.n_facets() - else: - per_face_dual = self.n_Vrepresentation() ** 2 * self.n_facets() - - from sage.arith.misc import binomial - estimate_n_faces = self.dimension() * binomial(min(self.n_facets(), self.n_Vrepresentation()), - self.dimension() // 2) - - # Note that the runtime per face already computes the coatoms of the next level, i.e. - # the runtime for each facet suffices to compute all ridges in primal, - # the runtime for each vertex suffices to compute all edges in dual. - if do_edges: - estimate_primal = estimate_n_faces * per_face_primal - estimate_dual = self.n_Vrepresentation() * per_face_dual - else: - estimate_primal = self.n_facets() * per_face_primal - estimate_dual = estimate_n_faces * per_face_dual - - dual = int(estimate_dual < estimate_primal) + algorithm = self.choose_algorithm_to_compute_edges_or_ridges("edges" if do_edges else "ridges") + dual = self._algorithm_to_dual(algorithm) cdef FaceIterator face_iter cdef int dim = self.dimension() - cdef size_t **edges = NULL - cdef size_t counter = 0 # the number of edges so far - cdef size_t current_length = 1 # dynamically enlarge **edges + cdef ListOfPairs edges = ListOfPairs() cdef int output_dim_init = 1 if do_edges else dim - 2 - cdef bint do_f_vector = False cdef size_t* f_vector = NULL try: - edges = <size_t**> check_malloc(sizeof(size_t*)) if dim == 1 and (do_edges or self.n_facets() > 1): # In this case there is an edge/ridge, but its not a proper face. - self._set_edge(0, 1, &edges, &counter, ¤t_length) + edges.add(0, 1) elif dim <= 1 or self.n_facets() == 0: # There is no edge/ridge. @@ -3621,73 +3597,120 @@ cdef class CombinatorialPolyhedron(SageObject): if not self._f_vector and ((dual ^ do_edges)): # While doing edges in non-dual mode or ridges in dual-mode # one might as well do the f-vector. - do_f_vector = True - # Initialize ``f_vector``. f_vector = <size_t *> check_calloc((dim + 2), sizeof(size_t)) f_vector[0] = 1 f_vector[dim + 1] = 1 face_iter = self._face_iter(dual, -2) else: - do_f_vector = False face_iter = self._face_iter(dual, output_dim_init) - self._compute_edges_or_ridges_with_iterator(face_iter, (dual ^ do_edges), do_f_vector, - &edges, &counter, ¤t_length, f_vector) - - # Success, copy the data to ``CombinatorialPolyhedron``. + self._compute_edges_or_ridges_with_iterator(face_iter, (dual ^ do_edges), + edges, f_vector) - # Copy ``f_vector``. - if do_f_vector: - if dual: - if dim > 1 and f_vector[1] < self.n_facets(): - # The input seemed to be wrong. - raise ValueError("not all facets are joins of vertices") - - # We have computed the ``f_vector`` of the dual. - # Reverse it: - self._f_vector = \ - tuple(smallInteger(f_vector[dim+1-i]) for i in range(dim+2)) - - else: - if self.is_bounded() and dim > 1 \ - and f_vector[1] < self.n_Vrepresentation() - len(self.far_face_tuple()): - # The input seemed to be wrong. - raise ValueError("not all vertices are intersections of facets") - - self._f_vector = tuple(smallInteger(f_vector[i]) for i in range(dim+2)) + # Success, persist the data. + if f_vector is not NULL: + self._persist_f_vector(f_vector, dual) - # Copy the edge or ridges. if do_edges: - sig_block() - self._n_edges = counter self._edges = edges - edges = NULL - counter = 0 - sig_unblock() else: - sig_block() - self._n_ridges = counter self._ridges = edges - edges = NULL - counter = 0 - sig_unblock() finally: - self._free_edges(&edges, counter) sig_free(f_vector) - if do_edges and self._edges is NULL: + if do_edges and self._edges is None: raise ValueError('could not determine edges') - elif not do_edges and self._ridges is NULL: + elif not do_edges and self._ridges is None: raise ValueError('could not determine ridges') + def choose_algorithm_to_compute_edges_or_ridges(self, edges_or_ridges): + """ + Use some heuristics to pick primal or dual algorithm for + computation of edges resp. ridges. + + We estimate how long it takes to compute a face using the primal + and the dual algorithm. This may differ significantly, so that e.g. + visiting all faces with the primal algorithm is faster than using + the dual algorithm to just visit vertices and edges. + + We guess the number of edges and ridges and do a wild estimate on + the total number of faces. + + INPUT: + + - ``edges_or_ridges`` -- string; one of: + * ``'edges'`` + * ``'ridges'`` + + OUTPUT: + + Either ``'primal'`` or ``'dual'``. + + EXAMPLES:: + + sage: C = polytopes.permutahedron(5).combinatorial_polyhedron() + sage: C.choose_algorithm_to_compute_edges_or_ridges("edges") + 'primal' + sage: C.choose_algorithm_to_compute_edges_or_ridges("ridges") + 'primal' + + :: + + sage: C = polytopes.cross_polytope(5).combinatorial_polyhedron() + sage: C.choose_algorithm_to_compute_edges_or_ridges("edges") + 'dual' + sage: C.choose_algorithm_to_compute_edges_or_ridges("ridges") + 'dual' + + + :: + + sage: C = polytopes.Birkhoff_polytope(5).combinatorial_polyhedron() + sage: C.choose_algorithm_to_compute_edges_or_ridges("edges") + 'dual' + sage: C.choose_algorithm_to_compute_edges_or_ridges("ridges") + 'primal' + sage: C.choose_algorithm_to_compute_edges_or_ridges("something_else") + Traceback (most recent call last): + ... + ValueError: unknown computation goal something_else + """ + if self.is_simple(): + per_face_primal = self.n_Vrepresentation() * self.n_facets() + else: + per_face_primal = self.n_Vrepresentation() * self.n_facets() ** 2 + + if self.is_simplicial(): + per_face_dual = self.n_Vrepresentation() * self.n_facets() + else: + per_face_dual = self.n_Vrepresentation() ** 2 * self.n_facets() + + from sage.arith.misc import binomial + estimate_n_faces = self.dimension() * binomial(min(self.n_facets(), self.n_Vrepresentation()), + self.dimension() // 2) + + # Note that the runtime per face already computes the coatoms of the next level, i.e. + # the runtime for each facet suffices to compute all ridges in primal, + # the runtime for each vertex suffices to compute all edges in dual. + if edges_or_ridges == "edges": + estimate_primal = estimate_n_faces * per_face_primal + estimate_dual = self.n_Vrepresentation() * per_face_dual + elif edges_or_ridges == "ridges": + estimate_primal = self.n_facets() * per_face_primal + estimate_dual = estimate_n_faces * per_face_dual + else: + raise ValueError(f"unknown computation goal {edges_or_ridges}") + + return 'dual' if (estimate_dual < estimate_primal) else 'primal' + cdef size_t _compute_edges_or_ridges_with_iterator( - self, FaceIterator face_iter, const bint do_atom_rep, const bint do_f_vector, - size_t ***edges_pt, size_t *counter_pt, size_t *current_length_pt, - size_t* f_vector) except -1: + self, FaceIterator face_iter, const bint do_atom_rep, + ListOfPairs edges, size_t* f_vector) except -1: r""" See :meth:`CombinatorialPolyhedron._compute_edges`. """ - cdef size_t a,b # facets of an edge + cdef size_t a, b # facets of an edge cdef int dim = self.dimension() + cdef bint do_f_vector = f_vector is not NULL # The dimension in which to record the edges or ridges. cdef output_dimension = 1 if do_atom_rep else dim - 2 @@ -3717,7 +3740,7 @@ cdef class CombinatorialPolyhedron(SageObject): # Copy the information. a = face_iter.structure.coatom_rep[0] b = face_iter.structure.coatom_rep[1] - self._set_edge(a, b, edges_pt, counter_pt, current_length_pt) + edges.add(a, b) d = face_iter.next_dimension() cdef int _compute_face_lattice_incidences(self) except -1: @@ -3729,7 +3752,6 @@ cdef class CombinatorialPolyhedron(SageObject): if self._face_lattice_incidences: return 1 # There is no need to recompute the incidences. - cdef size_t len_incidence_list = self._length_edges_list cdef int dim = self.dimension() f_vector = self.f_vector() self._record_all_faces() # set up ``self._all_faces`` @@ -3753,135 +3775,49 @@ cdef class CombinatorialPolyhedron(SageObject): # For ``dimension_one`` we add: cdef size_t already_seen_next # = sum(f_vector[j] for j in range(dimension_two + 2)) - # For each incidence we determine its location in ``incidences`` - # by ``incidences[one][two]``. - cdef size_t **incidences = NULL - - cdef size_t counter = 0 # the number of incidences so far - cdef size_t current_length = 1 # dynamically enlarge **incidences + cdef ListOfPairs incidences = ListOfPairs() if all_faces is None: raise ValueError("could not determine a list of all faces") dimension_one = 0 if dim > -1: - while (f_vector[dimension_one + 1] == 0): + while f_vector[dimension_one + 1] == 0: # Taking care of cases, where there might be no faces # of dimension 0, 1, etc (``n_lines > 0``). dimension_one += 1 dimension_two = -1 - try: - incidences = <size_t**> check_malloc(sizeof(size_t*)) - while (dimension_one < dim + 1): - already_seen = sum(f_vector[j] for j in range(dimension_two + 1)) - already_seen_next = already_seen + f_vector[dimension_two + 1] + while dimension_one < dim + 1: + already_seen = sum(f_vector[j] for j in range(dimension_two + 1)) + already_seen_next = already_seen + f_vector[dimension_two + 1] + + if all_faces.dual: + # If ``dual``, then ``all_faces`` has the dimensions reversed. + all_faces.incidence_init(dim - 1 - dimension_two, dim - 1 - dimension_one) + else: + all_faces.incidence_init(dimension_one, dimension_two) + # Get all incidences for fixed ``[dimension_one, dimension_two]``. + while all_faces.next_incidence(&second, &first): if all_faces.dual: - # If ``dual``, then ``all_faces`` has the dimensions reversed. - all_faces.incidence_init(dim - 1 - dimension_two, dim - 1 - dimension_one) + # If ``dual``, then ``second`` and ``first are flipped. + second += already_seen + first += already_seen_next + incidences.add(second, first) else: - all_faces.incidence_init(dimension_one, dimension_two) - - # Get all incidences for fixed ``[dimension_one, dimension_two]``. - while all_faces.next_incidence(&second, &first): - if all_faces.dual: - # If ``dual``, then ``second`` and ``first are flipped. - second += already_seen - first += already_seen_next - self._set_edge(second, first, &incidences, &counter, ¤t_length) - else: - second += already_seen_next - first += already_seen - self._set_edge(first, second, &incidences, &counter, ¤t_length) - - sig_check() - - # Increase dimensions. - dimension_one += 1 - dimension_two = dimension_one - 1 - - # Success, copy the data to ``CombinatorialPolyhedron``. - sig_block() - self._face_lattice_incidences = incidences - self._n_face_lattice_incidences = counter - incidences = NULL - counter = 0 - sig_unblock() - finally: - self._free_edges(&incidences, counter) - - cdef inline int _set_edge(self, size_t a, size_t b, size_t ***edges_pt, size_t *counter_pt, size_t *current_length_pt) except -1: - r""" - Set an edge in an edge list. - - Sets the values of all pointers accordingly. - - INPUT: - - - ``a``,``b`` -- the vertices of the edge - - ``edges_pt`` -- pointer to the list of lists; might point to ``NULL`` - when ``current_length_pt[0] == 0`` - - ``counter_pt`` -- pointer to the number of edges - - ``current_length_pt`` -- pointer to the length of ``edges_pt[0]`` - """ - cdef size_t len_edge_list = self._length_edges_list - # Determine the position in ``edges``. - cdef size_t one = counter_pt[0] // len_edge_list - cdef size_t two = counter_pt[0] % len_edge_list - - if unlikely(current_length_pt[0] == 0): - edges_pt[0] = <size_t**> check_malloc(sizeof(size_t*)) - current_length_pt[0] = 1 + second += already_seen_next + first += already_seen + incidences.add(first, second) - # Enlarge ``edges`` if needed. - if unlikely(two == 0): - if unlikely(one + 1 > current_length_pt[0]): - # enlarge **edges - current_length_pt[0] = 2*current_length_pt[0] - edges_pt[0] = <size_t **> check_reallocarray(edges_pt[0], current_length_pt[0], sizeof(size_t*)) + sig_check() - edges_pt[0][one] = <size_t *> check_allocarray(2 * len_edge_list, sizeof(size_t)) + # Increase dimensions. + dimension_one += 1 + dimension_two = dimension_one - 1 - edges_pt[0][one][2*two] = a - edges_pt[0][one][2*two + 1] = b - counter_pt[0] = counter_pt[0] + 1 - - cdef inline void _free_edges(self, size_t ***edges_pt, size_t counter): - r""" - Free the memory allocated for the edges. - """ - if edges_pt[0] is NULL: - return - - cdef size_t len_edge_list = self._length_edges_list - # Determine the position in ``edges``. - cdef size_t one = counter // len_edge_list - cdef size_t i - - for i in range(one): - sig_free(edges_pt[0][i]) - - sig_free(edges_pt[0]) - - cdef inline size_t _get_edge(self, size_t **edges, size_t edge_number, size_t vertex) except -1: - r""" - Get a vertex of an edge in an edge list. - - INPUT: - - - ``edges`` -- the edges list - - ``edge_number`` -- the number of the edge to obtain - - ``vertex`` -- one of ``0``, ``1``; the vertex to obtain - - OUTPUT: The specified vertex of the specified edge. - """ - cdef size_t len_edge_list = self._length_edges_list - # Determine the position in ``edges``. - cdef size_t one = edge_number // len_edge_list - cdef size_t two = edge_number % len_edge_list - - return edges[one][2*two + vertex] + # Success, persist the data. + self._face_lattice_incidences = incidences def _record_all_faces(self): r""" @@ -3897,15 +3833,18 @@ cdef class CombinatorialPolyhedron(SageObject): TESTS:: - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator() # optional - sage.combinat - sage: tup = tuple((face.ambient_Vrepresentation(), # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator() + sage: tup = tuple((face.ambient_Vrepresentation(), ....: face.ambient_Hrepresentation()) for face in it) - sage: rg = range(1,sum(C.f_vector()) - 1) # optional - sage.combinat - sage: tup2 = tuple((C.face_by_face_lattice_index(i).ambient_Vrepresentation(), # optional - sage.combinat - ....: C.face_by_face_lattice_index(i).ambient_Hrepresentation()) for i in rg) - sage: sorted(tup) == sorted(tup2) # optional - sage.combinat + sage: rg = range(1,sum(C.f_vector()) - 1) + sage: tup2 = tuple( + ....: (C.face_by_face_lattice_index(i).ambient_Vrepresentation(), + ....: C.face_by_face_lattice_index(i).ambient_Hrepresentation()) + ....: for i in rg) + sage: sorted(tup) == sorted(tup2) True sage: P = polytopes.cyclic_polytope(4,10) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index c1a0b996a8a..bf01025707f 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -22,9 +22,9 @@ Obtain a face from a face lattice index:: sage: P = polytopes.simplex(2) sage: C = CombinatorialPolyhedron(P) - sage: sorted(C.face_lattice()._elements) # optional - sage.combinat + sage: sorted(C.face_lattice()._elements) # needs sage.combinat [0, 1, 2, 3, 4, 5, 6, 7] - sage: face = C.face_by_face_lattice_index(0); face # optional - sage.combinat + sage: face = C.face_by_face_lattice_index(0); face A -1-dimensional face of a 2-dimensional combinatorial polyhedron Obtain further information regarding a face:: @@ -55,7 +55,7 @@ AUTHOR: """ # **************************************************************************** -# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -70,7 +70,7 @@ import numbers from sage.rings.integer cimport smallInteger from .conversions cimport bit_rep_to_Vrep_list from .base cimport CombinatorialPolyhedron -from .face_iterator cimport FaceIterator_base +from .face_iterator cimport FaceIterator_base, FaceStatus from .polyhedron_face_lattice cimport PolyhedronFaceLattice from .face_data_structure cimport face_len_atoms, face_init, face_free, face_copy, face_issubset from .face_list_data_structure cimport bit_rep_to_coatom_rep @@ -97,8 +97,8 @@ cdef class CombinatorialFace(SageObject): Obtain a combinatorial face from an index of the face lattice:: - sage: F = C.face_lattice() # optional - sage.combinat - sage: F._elements[3] # optional - sage.combinat + sage: F = C.face_lattice() # needs sage.combinat + sage: F._elements[3] # needs sage.combinat 34 sage: C.face_by_face_lattice_index(29) A 1-dimensional face of a 5-dimensional combinatorial polyhedron @@ -177,7 +177,7 @@ cdef class CombinatorialFace(SageObject): self.atoms = it.atoms self.coatoms = it.coatoms - if it.structure.face_status == 0: + if it.structure.face_status == FaceStatus.NOT_INITIALIZED: raise LookupError("face iterator not set to a face") face_init(self.face, self.coatoms.n_atoms(), self.coatoms.n_coatoms()) @@ -260,15 +260,16 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(6) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(dimension=3, algorithm='primal') # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: face.__repr__() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(6) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(dimension=3, algorithm='primal') + sage: face = next(it) + sage: face.__repr__() 'A 3-dimensional face of a 5-dimensional combinatorial polyhedron' - sage: it = C.face_generator(dimension=3, algorithm='dual') # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: face.__repr__() # optional - sage.combinat + sage: it = C.face_generator(dimension=3, algorithm='dual') + sage: face = next(it) + sage: face.__repr__() 'A 3-dimensional face of a 5-dimensional combinatorial polyhedron' """ return "A {}-dimensional face of a {}-dimensional combinatorial polyhedron"\ @@ -318,15 +319,16 @@ cdef class CombinatorialFace(SageObject): TESTS:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: F = C.face_lattice() # optional - sage.combinat - sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: F = C.face_lattice() + sage: G = F.relabel(C.face_by_face_lattice_index) sage: P = polytopes.cyclic_polytope(4,10) sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() # optional - sage.combinat - sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat + sage: F = C.face_lattice() # needs sage.combinat + sage: G = F.relabel(C.face_by_face_lattice_index) # needs sage.combinat """ return self._hash_index @@ -349,7 +351,7 @@ cdef class CombinatorialFace(SageObject): sage: F2 = C.face_by_face_lattice_index(1) sage: F1 < F2 True - sage: for i,j in Combinations(range(28), 2): # optional - sage.combinat + sage: for i,j in Combinations(range(28), 2): ....: F1 = C.face_by_face_lattice_index(i) ....: F2 = C.face_by_face_lattice_index(j) ....: if F1.dim() != F2.dim(): @@ -361,7 +363,7 @@ cdef class CombinatorialFace(SageObject): sage: F2 = C.face_by_face_lattice_index(1) sage: F1 < F2 True - sage: for i,j in Combinations(range(28), 2): # optional - sage.combinat + sage: for i,j in Combinations(range(28), 2): ....: F1 = C.face_by_face_lattice_index(i) ....: F2 = C.face_by_face_lattice_index(j) ....: if F1.dim() != F2.dim(): @@ -501,16 +503,17 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.associahedron(['A', 3]) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator() # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: face.dimension() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.associahedron(['A', 3]) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator() + sage: face = next(it) + sage: face.dimension() 2 ``dim`` is an alias:: - sage: face.dim() # optional - sage.combinat + sage: face.dim() # needs sage.combinat 2 """ if self._dual: @@ -545,19 +548,20 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(dimension=2) # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: face.ambient_Vrepresentation() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(dimension=2) + sage: face = next(it) + sage: face.ambient_Vrepresentation() (A vertex at (1, 3, 2, 5, 4), A vertex at (2, 3, 1, 5, 4), A vertex at (3, 1, 2, 5, 4), A vertex at (3, 2, 1, 5, 4), A vertex at (2, 1, 3, 5, 4), A vertex at (1, 2, 3, 5, 4)) - sage: face = next(it) # optional - sage.combinat - sage: face.ambient_Vrepresentation() # optional - sage.combinat + sage: face = next(it) + sage: face.ambient_Vrepresentation() (A vertex at (2, 1, 4, 5, 3), A vertex at (3, 2, 4, 5, 1), A vertex at (3, 1, 4, 5, 2), @@ -609,13 +613,14 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(dimension=2) # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: next(it).ambient_V_indices() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(dimension=2) + sage: face = next(it) + sage: next(it).ambient_V_indices() (32, 91, 92, 93, 94, 95) - sage: next(it).ambient_V_indices() # optional - sage.combinat + sage: next(it).ambient_V_indices() (32, 89, 90, 94) sage: C = CombinatorialPolyhedron([[0,1,2],[0,1,3],[0,2,3],[1,2,3]]) @@ -688,14 +693,15 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(2) # optional - sage.combinat - sage: next(it).ambient_Hrepresentation() # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(2) + sage: next(it).ambient_Hrepresentation() (An inequality (1, 1, 1, 0, 0) x - 6 >= 0, An inequality (0, 0, 0, -1, 0) x + 5 >= 0, An equation (1, 1, 1, 1, 1) x - 15 == 0) - sage: next(it).ambient_Hrepresentation() # optional - sage.combinat + sage: next(it).ambient_Hrepresentation() (An inequality (0, 0, -1, -1, 0) x + 9 >= 0, An inequality (0, 0, 0, -1, 0) x + 5 >= 0, An equation (1, 1, 1, 1, 1) x - 15 == 0) @@ -748,21 +754,22 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(2) # optional - sage.combinat - sage: face = next(it) # optional - sage.combinat - sage: face.ambient_H_indices(add_equations=False) # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(2) + sage: face = next(it) + sage: face.ambient_H_indices(add_equations=False) (28, 29) - sage: face2 = next(it) # optional - sage.combinat - sage: face2.ambient_H_indices(add_equations=False) # optional - sage.combinat + sage: face2 = next(it) + sage: face2.ambient_H_indices(add_equations=False) (25, 29) Add the indices of the equation:: - sage: face.ambient_H_indices(add_equations=True) # optional - sage.combinat + sage: face.ambient_H_indices(add_equations=True) # needs sage.combinat (28, 29, 30) - sage: face2.ambient_H_indices(add_equations=True) # optional - sage.combinat + sage: face2.ambient_H_indices(add_equations=True) # needs sage.combinat (25, 29, 30) Another example:: @@ -828,13 +835,14 @@ cdef class CombinatorialFace(SageObject): Specifying whether to count the equations or not:: - sage: P = polytopes.permutahedron(5) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator(2) # optional - sage.combinat - sage: f = next(it) # optional - sage.combinat - sage: f.n_ambient_Hrepresentation(add_equations=True) # optional - sage.combinat + sage: # needs sage.combinat + sage: P = polytopes.permutahedron(5) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator(2) + sage: f = next(it) + sage: f.n_ambient_Hrepresentation(add_equations=True) 3 - sage: f.n_ambient_Hrepresentation(add_equations=False) # optional - sage.combinat + sage: f.n_ambient_Hrepresentation(add_equations=False) 2 TESTS:: @@ -877,7 +885,7 @@ cdef class CombinatorialFace(SageObject): sage: F.f_vector() (1, 5, 10, 10, 5, 1) sage: F_alt = polytopes.cyclic_polytope(4,5).combinatorial_polyhedron() - sage: F_alt.vertex_facet_graph().is_isomorphic(F.vertex_facet_graph()) # optional - sage.graphs + sage: F_alt.vertex_facet_graph().is_isomorphic(F.vertex_facet_graph()) # needs sage.graphs True Obtaining the quotient:: diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx index b4af45206e5..baeb8fc4855 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx @@ -31,11 +31,12 @@ Obtain the facets of a polyhedron as :class:`~sage.geometry.polyhedron.combinato Obtain the Vrepresentation of a polyhedron as facet-incidences stored in :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces.ListOfFaces`:: + sage: # needs sage.combinat sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \ ....: import incidence_matrix_to_bit_rep_of_Vrep - sage: P = polytopes.associahedron(['A',4]) # optional - sage.combinat - sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) # optional - sage.combinat - sage: face_list.compute_dimension() # optional - sage.combinat + sage: P = polytopes.associahedron(['A',4]) + sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) + sage: face_list.compute_dimension() 4 Obtain the facets of a polyhedron as :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces.ListOfFaces` from a facet list:: @@ -58,7 +59,7 @@ AUTHOR: """ #***************************************************************************** -# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -69,13 +70,10 @@ AUTHOR: from memory_allocator cimport MemoryAllocator -from sage.structure.element import is_Matrix from sage.matrix.matrix_dense cimport Matrix_dense from .list_of_faces cimport ListOfFaces from .face_data_structure cimport face_next_atom, face_add_atom_safe, facet_set_coatom, face_clear -from .face_list_data_structure cimport face_list_t - cdef extern from "Python.h": int unlikely(int) nogil # Defined by Cython diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd index eea0e3b4da8..f37bcd36085 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd @@ -2,7 +2,7 @@ Cython data structure for combinatorial faces. """ # **************************************************************************** -# Copyright (C) 2020 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2020 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd index 452b2c9cdc9..1dd74505306 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd @@ -5,10 +5,16 @@ from .face_data_structure cimport face_t from .face_list_data_structure cimport face_list_t from .combinatorial_face cimport CombinatorialFace +cdef enum FaceStatus: + NOT_INITIALIZED + INITIALIZED + IGNORE_SUBSETS + ONLY_VISIT_SUBSETS + cdef struct iter_s: bint dual # if 1, then iterate over dual Polyhedron face_t face # the current face of the iterator - int face_status # 0 not initialized, 1 initialized, 2 added to visited_all, 3 only visit subsets + FaceStatus face_status size_t *atom_rep # a place where atom-representaion of face will be stored size_t *coatom_rep # a place where coatom-representaion of face will be stored int current_dimension # dimension of current face, dual dimension if ``dual`` diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index b8f9f0a27b0..f0ac1e774a7 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -165,7 +165,7 @@ AUTHOR: """ #***************************************************************************** -# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -178,10 +178,8 @@ from cython.parallel cimport prange, threadid from cysignals.memory cimport check_allocarray, sig_free from memory_allocator cimport MemoryAllocator -from sage.rings.integer cimport smallInteger from cysignals.signals cimport sig_check -from .conversions cimport bit_rep_to_Vrep_list, Vrep_list_to_bit_rep -from .conversions import facets_tuple_to_bit_rep_of_facets +from .conversions cimport bit_rep_to_Vrep_list from .base cimport CombinatorialPolyhedron from sage.geometry.polyhedron.face import combinatorial_face_to_polyhedral_face, PolyhedronFace @@ -209,13 +207,13 @@ cdef class FaceIterator_base(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(4) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: it = C.face_generator() # indirect doctest # optional - sage.combinat + sage: P = polytopes.permutahedron(4) + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_generator() # indirect doctest sage: f_vector = [1, 0, 0, 0, 1] - sage: for face in it: f_vector[face.dimension()+1] += 1 # optional - sage.combinat - sage: print ('f_vector of permutahedron(4): ', f_vector) # optional - sage.combinat + sage: for face in it: f_vector[face.dimension()+1] += 1 + sage: print ('f_vector of permutahedron(4): ', f_vector) f_vector of permutahedron(4): [1, 24, 36, 14, 1] sage: TestSuite(sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator.FaceIterator).run() @@ -414,7 +412,7 @@ cdef class FaceIterator_base(SageObject): self.structure.visited_all[self.structure.dimension -1].n_faces = 0 else: self.structure.visited_all[self.structure.dimension -1].n_faces = 1 - self.structure.face_status = 0 + self.structure.face_status = FaceStatus.NOT_INITIALIZED self.structure.new_faces[self.structure.dimension - 1].n_faces = self.coatoms.n_faces() self.structure.current_dimension = self.structure.dimension - 1 self.structure.highest_dimension = self.structure.dimension - 1 @@ -460,7 +458,7 @@ cdef class FaceIterator_base(SageObject): sage: next(it).ambient_V_indices() == it.current().ambient_V_indices() True """ - if unlikely(self.structure.face_status == 0): + if unlikely(self.structure.face_status == FaceStatus.NOT_INITIALIZED): raise ValueError("iterator not set to a face yet") return CombinatorialFace(self) @@ -639,17 +637,18 @@ cdef class FaceIterator_base(SageObject): If the iterator has already been used, it must be reset before:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: it = P.face_generator() # optional - sage.rings.number_field - sage: _ = next(it), next(it) # optional - sage.rings.number_field - sage: next(it).ambient_V_indices() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: it = P.face_generator() + sage: _ = next(it), next(it) + sage: next(it).ambient_V_indices() (15, 16, 17, 18, 19) - sage: it.meet_of_Hrep(9,11) # optional - sage.rings.number_field + sage: it.meet_of_Hrep(9,11) Traceback (most recent call last): ... ValueError: please reset the face iterator - sage: it.reset() # optional - sage.rings.number_field - sage: it.meet_of_Hrep(9,11).ambient_H_indices() # optional - sage.rings.number_field + sage: it.reset() + sage: it.meet_of_Hrep(9,11).ambient_H_indices() (9, 11) TESTS: @@ -724,17 +723,18 @@ cdef class FaceIterator_base(SageObject): If the iterator has already been used, it must be reset before:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: it = P.face_generator() # optional - sage.rings.number_field - sage: _ = next(it), next(it) # optional - sage.rings.number_field - sage: next(it).ambient_V_indices() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: it = P.face_generator() + sage: _ = next(it), next(it) + sage: next(it).ambient_V_indices() (15, 16, 17, 18, 19) - sage: it.join_of_Vrep(1,10) # optional - sage.rings.number_field + sage: it.join_of_Vrep(1,10) Traceback (most recent call last): ... ValueError: please reset the face iterator - sage: it.reset() # optional - sage.rings.number_field - sage: it.join_of_Vrep(1,10).ambient_V_indices() # optional - sage.rings.number_field + sage: it.reset() + sage: it.join_of_Vrep(1,10).ambient_V_indices() (1, 10) In the case of an unbounded polyhedron, we try to make sense of the input:: @@ -848,9 +848,10 @@ cdef class FaceIterator_base(SageObject): The face iterator must not have the output dimension specified:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: it = P.face_generator(2) # optional - sage.rings.number_field - sage: it._meet_of_coatoms(1,2) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: it = P.face_generator(2) + sage: it._meet_of_coatoms(1,2) Traceback (most recent call last): ... ValueError: face iterator must not have the output dimension specified @@ -888,7 +889,7 @@ cdef class FaceIterator_base(SageObject): sage: it._meet_of_coatoms(1, 2) A -1-dimensional face of a Polyhedron in QQ^2 """ - if unlikely(self.structure.face_status != 0): + if unlikely(self.structure.face_status != FaceStatus.NOT_INITIALIZED): raise ValueError("please reset the face iterator") if unlikely(self.structure.output_dimension != -2): raise ValueError("face iterator must not have the output dimension specified") @@ -957,24 +958,26 @@ cdef class FaceIterator_base(SageObject): If the iterator has already been used, it must be reset before:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: it = P.face_generator() # optional - sage.rings.number_field - sage: _ = next(it), next(it) # optional - sage.rings.number_field - sage: next(it).ambient_V_indices() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: it = P.face_generator() + sage: _ = next(it), next(it) + sage: next(it).ambient_V_indices() (15, 16, 17, 18, 19) - sage: it._join_of_atoms(1,10) # optional - sage.rings.number_field + sage: it._join_of_atoms(1,10) Traceback (most recent call last): ... ValueError: please reset the face iterator - sage: it.reset() # optional - sage.rings.number_field - sage: it._join_of_atoms(1,10).ambient_V_indices() # optional - sage.rings.number_field + sage: it.reset() + sage: it._join_of_atoms(1,10).ambient_V_indices() (1, 10) The face iterator must not have the output dimension specified:: - sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: it = P.face_generator(2) # optional - sage.rings.number_field - sage: it._join_of_atoms(1,2) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = polytopes.dodecahedron() + sage: it = P.face_generator(2) + sage: it._join_of_atoms(1,2) Traceback (most recent call last): ... ValueError: face iterator must not have the output dimension specified @@ -994,7 +997,7 @@ cdef class FaceIterator_base(SageObject): ... IndexError: atoms out of range """ - if unlikely(self.structure.face_status != 0): + if unlikely(self.structure.face_status != FaceStatus.NOT_INITIALIZED): raise ValueError("please reset the face iterator") if unlikely(self.structure.output_dimension != -2): raise ValueError("face iterator must not have the output dimension specified") @@ -1049,14 +1052,14 @@ cdef class FaceIterator_base(SageObject): See :meth:`FaceIterator_base.ignore_subfaces` and :meth:`FaceIterator_base.ignore_supfaces`. """ - if unlikely(self.structure.face_status == 0): + if unlikely(self.structure.face_status == FaceStatus.NOT_INITIALIZED): raise ValueError("iterator not set to a face yet") - if unlikely(self.structure.face_status == 3): + if unlikely(self.structure.face_status == FaceStatus.ONLY_VISIT_SUBSETS): # The iterator is consumed, if it was just set to visit only subsets # next thing to ignore subsets. self.structure.current_dimension = self.structure.dimension return 0 - if unlikely(self.structure.face_status == 2): + if unlikely(self.structure.face_status == FaceStatus.IGNORE_SUBSETS): # Nothing to do. return 0 # The current face is added to ``visited_all``. @@ -1065,7 +1068,7 @@ cdef class FaceIterator_base(SageObject): # as there are no new faces. add_face_shallow(self.structure.visited_all[self.structure.current_dimension], self.structure.face) - self.structure.face_status = 2 + self.structure.face_status = FaceStatus.IGNORE_SUBSETS def only_subfaces(self): r""" @@ -1177,9 +1180,9 @@ cdef class FaceIterator_base(SageObject): See :meth:`FaceIterator_base.only_subfaces` and :meth:`FaceIterator_base.only_supfaces`. """ - if unlikely(self.structure.face_status == 0): + if unlikely(self.structure.face_status == FaceStatus.NOT_INITIALIZED): raise ValueError("iterator not set to a face yet") - if unlikely(self.structure.face_status == 2): + if unlikely(self.structure.face_status == FaceStatus.IGNORE_SUBSETS): raise ValueError("cannot only visit subsets after ignoring a face") cdef face_list_t* faces = &self.structure.new_faces[self.structure.current_dimension] @@ -1191,7 +1194,7 @@ cdef class FaceIterator_base(SageObject): swap_faces(faces[0].faces[yet_to_visit], faces[0].faces[faces[0].n_faces - 1]) - self.structure.face_status = 3 + self.structure.face_status = FaceStatus.ONLY_VISIT_SUBSETS self.structure.yet_to_visit = 0 # This will work: # ``next_dimension`` will first call ``next_face_loop`` and then check @@ -1281,13 +1284,13 @@ cdef class FaceIterator_base(SageObject): if n_atoms == self.coatoms.n_atoms(): # The face is the universe. self.structure.face[0] = face[0] - self.structure.face_status = 1 + self.structure.face_status = FaceStatus.INITIALIZED self.structure.current_dimension = self.structure.dimension return 0 elif n_atoms == 0: # The face is the empty face. self.structure.face[0] = face[0] - self.structure.face_status = 1 + self.structure.face_status = FaceStatus.INITIALIZED self.structure.current_dimension = -1 return 0 @@ -1576,12 +1579,12 @@ cdef class FaceIterator(FaceIterator_base): r""" EXAMPLES:: - sage: P = polytopes.associahedron(['A',3]) # optional - sage.combinat - sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat - sage: C.face_generator() # optional - sage.combinat + sage: P = polytopes.associahedron(['A',3]) # needs sage.combinat + sage: C = CombinatorialPolyhedron(P) # needs sage.combinat + sage: C.face_generator() # needs sage.combinat Iterator over the proper faces of a 3-dimensional combinatorial polyhedron - sage: C.face_generator(1) # optional - sage.combinat + sage: C.face_generator(1) # needs sage.combinat Iterator over the 1-faces of a 3-dimensional combinatorial polyhedron """ if self.structure.output_dimension != -2: @@ -1847,11 +1850,11 @@ cdef class FaceIterator_geom(FaceIterator_base): r""" EXAMPLES:: - sage: P = polytopes.associahedron(['A',3]) # optional - sage.combinat - sage: P.face_generator() # optional - sage.combinat + sage: P = polytopes.associahedron(['A',3]) # needs sage.combinat + sage: P.face_generator() # needs sage.combinat Iterator over the faces of a 3-dimensional polyhedron in QQ^3 - sage: P.face_generator(1) # optional - sage.combinat + sage: P.face_generator(1) # needs sage.combinat Iterator over the 1-faces of a 3-dimensional polyhedron in QQ^3 """ if self._requested_dim is not None: @@ -1928,7 +1931,7 @@ cdef inline int next_dimension(iter_t structure, size_t parallelization_depth=0) e.g. if it is ``1`` it will stop after having yield all faces of a facet """ cdef int max_dim = structure.highest_dimension - parallelization_depth - structure.face_status = 0 + structure.face_status = FaceStatus.NOT_INITIALIZED while (not next_face_loop(structure)) and (structure.current_dimension <= max_dim): sig_check() structure._index += 1 @@ -1959,7 +1962,7 @@ cdef inline int next_face_loop(iter_t structure) nogil except -1: # Set ``face`` to the next face. structure.yet_to_visit -= 1 structure.face[0] = faces[0].faces[structure.yet_to_visit][0] - structure.face_status = 1 + structure.face_status = FaceStatus.INITIALIZED return 1 if structure.current_dimension <= structure.lowest_dimension: diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd index b43e50a6aae..79b319e1982 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd @@ -2,7 +2,7 @@ Inline cython methods for lists of faces. """ # **************************************************************************** -# Copyright (C) 2020 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2020 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx index e6c9aa2b134..ec9c23d090d 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx @@ -2,7 +2,7 @@ Sorting of a list of faces. """ # **************************************************************************** -# Copyright (C) 2020 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2020 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx index 9639f10b6b7..dffa76036fa 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx @@ -39,11 +39,12 @@ Obtain the facets of a polyhedron:: Obtain the Vrepresentation of a polyhedron as facet-incidences:: + sage: # needs sage.combinat sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \ ....: import incidence_matrix_to_bit_rep_of_Vrep - sage: P = polytopes.associahedron(['A',3]) # optional - sage.combinat - sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) # optional - sage.combinat - sage: face_list.compute_dimension() # optional - sage.combinat + sage: P = polytopes.associahedron(['A',3]) + sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) + sage: face_list.compute_dimension() 3 Obtain the facets of a polyhedron as :class:`ListOfFaces` from a facet list:: @@ -79,9 +80,8 @@ AUTHOR: - Jonathan Kliem (2019-04) """ - # **************************************************************************** -# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -90,7 +90,6 @@ AUTHOR: # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.element import is_Matrix from sage.matrix.matrix_dense cimport Matrix_dense from .face_list_data_structure cimport * @@ -98,6 +97,7 @@ from .face_list_data_structure cimport * cdef extern from "Python.h": int unlikely(int) nogil # Defined by Cython + cdef class ListOfFaces: r""" A class to store the Bit-representation of faces in. diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx index 4e9ba7e0e99..be6ffbda794 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx @@ -51,13 +51,13 @@ AUTHOR: """ #***************************************************************************** -# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# Copyright (C) 2019 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from .conversions \ @@ -66,7 +66,6 @@ from .conversions \ from .conversions cimport bit_rep_to_Vrep_list -from sage.rings.integer cimport smallInteger from .base cimport CombinatorialPolyhedron from .face_iterator cimport FaceIterator from .face_list_data_structure cimport * @@ -100,7 +99,8 @@ cdef class PolyhedronFaceLattice: sage: P = polytopes.Birkhoff_polytope(3) sage: C = CombinatorialPolyhedron(P) - sage: C.face_lattice() # indirect doctests + sage: C._record_all_faces() # indirect doctests + sage: C.face_lattice() # needs sage.combinat Finite lattice containing 50 elements ALGORITHM: @@ -215,7 +215,7 @@ cdef class PolyhedronFaceLattice: sage: P = polytopes.cube() sage: C = CombinatorialPolyhedron(P) sage: C._record_all_faces() # indirect doctests - sage: C.face_lattice() + sage: C.face_lattice() # needs sage.combinat Finite lattice containing 28 elements sage: TestSuite(sage.geometry.polyhedron.combinatorial_polyhedron.polyhedron_face_lattice.PolyhedronFaceLattice).run() diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index 7f11ac13593..f18492f584f 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -176,8 +176,8 @@ exact way to work with roots in Sage is the :mod:`Algebraic Real Field <sage.rings.qqbar>` :: - sage: triangle = Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)], base_ring=AA) # optional - sage.rings.number_field # optional - sage.symbolic - sage: triangle.Hrepresentation() # optional - sage.rings.number_field # optional - sage.symbolic + sage: triangle = Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)], base_ring=AA) # needs sage.rings.number_field sage.symbolic + sage: triangle.Hrepresentation() # needs sage.rings.number_field sage.symbolic (An inequality (-1, -0.5773502691896258?) x + 1 >= 0, An inequality (1, -0.5773502691896258?) x + 0 >= 0, An inequality (0, 1.154700538379252?) x + 0 >= 0) @@ -186,21 +186,24 @@ symbolic ring element and, therefore, the polyhedron defined over the symbolic ring. This is currently not supported as SR is not exact:: - sage: Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)]) # optional - sage.symbolic + sage: Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)]) # needs sage.symbolic Traceback (most recent call last): ... ValueError: no default backend for computations with Symbolic Ring - sage: SR.is_exact() # optional - sage.symbolic + sage: SR.is_exact() # needs sage.symbolic False Even faster than all algebraic real numbers (the field ``AA``) is to take the smallest extension field. For the equilateral triangle, that would be:: - sage: K.<sqrt3> = NumberField(x^2 - 3, embedding=AA(3)**(1/2)) # optional - sage.rings.number_field - sage: Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) # optional - sage.rings.number_field - A 2-dimensional polyhedron in (Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^2 defined as the convex hull of 3 vertices + sage: x = polygen(ZZ, 'x') + sage: K.<sqrt3> = NumberField(x^2 - 3, embedding=AA(3)**(1/2)) # needs sage.rings.number_field + sage: Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) # needs sage.rings.number_field + A 2-dimensional polyhedron in + (Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^2 + defined as the convex hull of 3 vertices .. WARNING:: @@ -217,7 +220,7 @@ A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex sage: Polyhedron(vertices = [[1.12345678901234, 2.123456789012345]]) A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex - sage: Polyhedron(vertices = [[1.123456789012345, 2.123456789012345]]) + sage: Polyhedron(vertices = [[1.123456789012345, 2.123456789012345]]) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: the only allowed inexact ring is 'RDF' with backend 'cdd' @@ -449,25 +452,28 @@ def Polyhedron(vertices=None, rays=None, lines=None, by the cyclic shifts of `(0, \pm 1, \pm (1+\sqrt(5))/2)`, cf. :wikipedia:`Regular_icosahedron`. It needs a number field:: - sage: R0.<r0> = QQ[] # optional - sage.rings.number_field - sage: R1.<r1> = NumberField(r0^2-5, embedding=AA(5)**(1/2)) # optional - sage.rings.number_field - sage: gold = (1+r1)/2 # optional - sage.rings.number_field - sage: v = [[0, 1, gold], [0, 1, -gold], [0, -1, gold], [0, -1, -gold]] # optional - sage.rings.number_field - sage: pp = Permutation((1, 2, 3)) # optional - sage.combinat # optional - sage.rings.number_field - sage: icosah = Polyhedron( # optional - sage.combinat # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: R0.<r0> = QQ[] + sage: R1.<r1> = NumberField(r0^2-5, embedding=AA(5)**(1/2)) + sage: gold = (1+r1)/2 + sage: v = [[0, 1, gold], [0, 1, -gold], [0, -1, gold], [0, -1, -gold]] + sage: pp = Permutation((1, 2, 3)) + sage: icosah = Polyhedron( # needs sage.combinat ....: [(pp^2).action(w) for w in v] + [pp.action(w) for w in v] + v, ....: base_ring=R1) - sage: len(icosah.faces(2)) # optional - sage.combinat # optional - sage.rings.number_field + sage: len(icosah.faces(2)) # needs sage.combinat 20 When the input contains elements of a Number Field, they require an embedding:: - sage: K = NumberField(x^2-2,'s') # optional - sage.rings.number_field - sage: s = K.0 # optional - sage.rings.number_field - sage: L = NumberField(x^3-2,'t') # optional - sage.rings.number_field - sage: t = L.0 # optional - sage.rings.number_field - sage: P = Polyhedron(vertices = [[0,s],[t,0]]) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K = NumberField(x^2 - 2,'s') + sage: s = K.0 + sage: L = NumberField(x^3 - 2,'t') + sage: t = L.0 + sage: P = Polyhedron(vertices=[[0,s], [t,0]]) Traceback (most recent call last): ... ValueError: invalid base ring @@ -504,6 +510,7 @@ def Polyhedron(vertices=None, rays=None, lines=None, sage: Polyhedron(o, base_ring=QQ) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices + sage: # needs sage.combinat sage: H.<x,y> = HyperplaneArrangements(QQ) sage: h = x + y - 1; h Hyperplane x + y - 1 @@ -563,18 +570,19 @@ def Polyhedron(vertices=None, rays=None, lines=None, Check that input with too many bits of precision returns an error (see :trac:`22552`):: - sage: Polyhedron(vertices=[(8.3319544851638732, 7.0567045956967727), (6.4876921900819049, 4.8435898415984129)]) + sage: Polyhedron(vertices=[(8.3319544851638732, 7.0567045956967727), # needs sage.rings.real_mpfr + ....: (6.4876921900819049, 4.8435898415984129)]) Traceback (most recent call last): ... ValueError: the only allowed inexact ring is 'RDF' with backend 'cdd' Check that setting ``base_ring`` to a ``RealField`` returns an error (see :trac:`22552`):: - sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(40)) + sage: Polyhedron(vertices=[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(40)) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: no default backend for computations with Real Field with 40 bits of precision - sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(53)) + sage: Polyhedron(vertices=[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(53)) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: no default backend for computations with Real Field with 53 bits of precision @@ -721,7 +729,8 @@ def Polyhedron(vertices=None, rays=None, lines=None, if base_ring not in Fields(): got_compact_Vrep = got_Vrep and not rays and not lines - got_cone_Vrep = got_Vrep and all(all(x == 0 for x in v) for v in vertices) + got_cone_Vrep = got_Vrep and all(x == 0 + for v in vertices for x in v) if not got_compact_Vrep and not got_cone_Vrep: base_ring = base_ring.fraction_field() convert = True @@ -742,7 +751,7 @@ def Polyhedron(vertices=None, rays=None, lines=None, raise ValueError("the only allowed inexact ring is 'RDF' with backend 'cdd'") # Add the origin if necessary - if got_Vrep and len(vertices) == 0 and len(rays + lines) > 0: + if got_Vrep and len(vertices) == 0 and bool(rays + lines): vertices = [[0] * ambient_dim] # Specific backends can override the base_ring diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index c1c94a9b8f9..089580e3146 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -28,10 +28,10 @@ `\RR`, for example:: sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm - sage: A = matrix(AA, [(1,0,1), (0,1,1), (-AA(2).sqrt(),-AA(3).sqrt(),1), # optional - sage.rings.number_field + sage: A = matrix(AA, [(1,0,1), (0,1,1), (-AA(2).sqrt(),-AA(3).sqrt(),1), # needs sage.rings.number_field ....: (-AA(3).sqrt(),-AA(2).sqrt(),1)]) - sage: alg = StandardAlgorithm(A) # optional - sage.rings.number_field - sage: alg.run().R # optional - sage.rings.number_field + sage: alg = StandardAlgorithm(A) + sage: alg.run().R # needs sage.rings.number_field [(-0.4177376677004119?, 0.5822623322995881?, 0.4177376677004119?), (-0.2411809548974793?, -0.2411809548974793?, 0.2411809548974793?), (0.07665629029830300?, 0.07665629029830300?, 0.2411809548974793?), @@ -147,7 +147,7 @@ def __init__(self, problem, A_rows, R_cols): self.problem = problem self.A = list(A_rows) self.R = list(R_cols) - self.one = problem._field.one() + self.one = problem._field.one() self.zero = problem._field.zero() # a cache for scalar products (see the method zero_set) @@ -411,10 +411,11 @@ def matrix_space(self, nrows, ncols): sage: DD.matrix_space(3,2) Full MatrixSpace of 3 by 2 dense matrices over Rational Field - sage: K.<sqrt2> = QuadraticField(2) # optional - sage.rings.number_field - sage: A = matrix([[1,sqrt2],[2,0]]) # optional - sage.rings.number_field - sage: DD, _ = Problem(A).initial_pair() # optional - sage.rings.number_field - sage: DD.matrix_space(1,2) # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: K.<sqrt2> = QuadraticField(2) + sage: A = matrix([[1,sqrt2],[2,0]]) + sage: DD, _ = Problem(A).initial_pair() + sage: DD.matrix_space(1,2) Full MatrixSpace of 1 by 2 dense matrices over Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? """ @@ -597,9 +598,9 @@ def base_ring(self): EXAMPLES:: - sage: A = matrix(AA, [(1, 1), (-1, 1)]) # optional - sage.rings.number_field + sage: A = matrix(AA, [(1, 1), (-1, 1)]) # needs sage.rings.number_field sage: from sage.geometry.polyhedron.double_description import Problem - sage: Problem(A).base_ring() # optional - sage.rings.number_field + sage: Problem(A).base_ring() # needs sage.rings.number_field Algebraic Real Field """ return self._field diff --git a/src/sage/geometry/polyhedron/face.py b/src/sage/geometry/polyhedron/face.py index 2166f016ba8..8a1e2dc2969 100644 --- a/src/sage/geometry/polyhedron/face.py +++ b/src/sage/geometry/polyhedron/face.py @@ -35,7 +35,7 @@ or :meth:`~sage.geometry.polyhedron.base.face_lattice` to get the whole face lattice as a poset:: - sage: P.face_lattice() # optional - sage.combinat + sage: P.face_lattice() # needs sage.combinat Finite lattice containing 28 elements The faces are printed in shorthand notation where each integer is the @@ -404,7 +404,7 @@ def ambient_Hrepresentation(self, index=None): EXAMPLES:: sage: square = polytopes.hypercube(2) - sage: for face in square.face_lattice(): # optional - sage.combinat + sage: for face in square.face_lattice(): # needs sage.combinat ....: print(face.ambient_Hrepresentation()) (An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0, An inequality (1, 0) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0) @@ -445,7 +445,7 @@ def ambient_Vrepresentation(self, index=None): EXAMPLES:: sage: square = polytopes.hypercube(2) - sage: for fl in square.face_lattice(): # optional - sage.combinat + sage: for fl in square.face_lattice(): # needs sage.combinat ....: print(fl.ambient_Vrepresentation()) () (A vertex at (1, -1),) @@ -478,15 +478,14 @@ def n_ambient_Hrepresentation(self): EXAMPLES:: sage: p = polytopes.cross_polytope(4) - sage: face = p.face_lattice()[5] # optional - sage.combinat - sage: face # optional - sage.combinat + sage: face = p.face_lattice()[5]; face # needs sage.combinat A 1-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 2 vertices - sage: face.ambient_Hrepresentation() # optional - sage.combinat + sage: face.ambient_Hrepresentation() # needs sage.combinat (An inequality (1, -1, 1, -1) x + 1 >= 0, An inequality (1, 1, 1, 1) x + 1 >= 0, An inequality (1, 1, 1, -1) x + 1 >= 0, An inequality (1, -1, 1, 1) x + 1 >= 0) - sage: face.n_ambient_Hrepresentation() # optional - sage.combinat + sage: face.n_ambient_Hrepresentation() # needs sage.combinat 4 """ return len(self.ambient_Hrepresentation()) @@ -505,12 +504,11 @@ def n_ambient_Vrepresentation(self): EXAMPLES:: sage: p = polytopes.cross_polytope(4) - sage: face = p.face_lattice()[5] # optional - sage.combinat - sage: face # optional - sage.combinat + sage: face = p.face_lattice()[5]; face # needs sage.combinat A 1-dimensional face of a Polyhedron in ZZ^4 defined as the convex hull of 2 vertices - sage: face.ambient_Vrepresentation() # optional - sage.combinat + sage: face.ambient_Vrepresentation() # needs sage.combinat (A vertex at (-1, 0, 0, 0), A vertex at (0, 0, -1, 0)) - sage: face.n_ambient_Vrepresentation() # optional - sage.combinat + sage: face.n_ambient_Vrepresentation() # needs sage.combinat 2 """ return len(self.ambient_Vrepresentation()) @@ -595,8 +593,8 @@ def dim(self): EXAMPLES:: - sage: fl = polytopes.dodecahedron().face_lattice() # optional - sage.combinat # optional - sage.rings.number_field - sage: sorted([ x.dim() for x in fl ]) # optional - sage.combinat # optional - sage.rings.number_field + sage: fl = polytopes.dodecahedron().face_lattice() # needs sage.combinat sage.rings.number_field + sage: sorted(x.dim() for x in fl) # needs sage.combinat sage.rings.number_field [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3] @@ -605,7 +603,7 @@ def dim(self): Check that :trac:`28650` is fixed:: - sage: P = Polyhedron(vertices=[[1,0]], rays=[[1,0],[0,1]]) + sage: P = Polyhedron(vertices=[[1,0]], rays=[[1,0], [0,1]]) sage: P.faces(2) (A 2-dimensional face of a Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,) """ @@ -630,8 +628,8 @@ def _repr_(self): EXAMPLES:: sage: square = polytopes.hypercube(2) - sage: a_face = list( square.face_lattice() )[8] # optional - sage.combinat - sage: a_face.__repr__() # optional - sage.combinat + sage: a_face = list( square.face_lattice() )[8] # needs sage.combinat + sage: a_face.__repr__() # needs sage.combinat 'A 1-dimensional face of a Polyhedron in ZZ^2 defined as the convex hull of 2 vertices' """ desc = '' @@ -679,8 +677,7 @@ def polyhedron(self): sage: P = polytopes.cross_polytope(3); P A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices - sage: face = P.facets()[3] - sage: face + sage: face = P.facets()[3]; face A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices sage: face.polyhedron() A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices @@ -704,10 +701,11 @@ def ambient_vector_space(self, base_field=None): sage: half_plane = Polyhedron(ieqs=[(0,1,0)]) sage: line = half_plane.faces(1)[0]; line - A 1-dimensional face of a Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line + A 1-dimensional face of a + Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line sage: line.ambient_vector_space() Vector space of dimension 2 over Rational Field - sage: line.ambient_vector_space(AA) # optional - sage.rings.number_field + sage: line.ambient_vector_space(AA) # needs sage.rings.number_field Vector space of dimension 2 over Algebraic Real Field """ return self.polyhedron().ambient_vector_space(base_field=base_field) @@ -716,15 +714,14 @@ def is_relatively_open(self): r""" Return whether ``self`` is relatively open. - OUTPUT: - - Boolean. + OUTPUT: Boolean. EXAMPLES:: sage: half_plane = Polyhedron(ieqs=[(0,1,0)]) sage: line = half_plane.faces(1)[0]; line - A 1-dimensional face of a Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line + A 1-dimensional face of a + Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line sage: line.is_relatively_open() True """ @@ -734,15 +731,14 @@ def is_compact(self): r""" Return whether ``self`` is compact. - OUTPUT: - - Boolean. + OUTPUT: Boolean. EXAMPLES:: sage: half_plane = Polyhedron(ieqs=[(0,1,0)]) sage: line = half_plane.faces(1)[0]; line - A 1-dimensional face of a Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line + A 1-dimensional face of a + Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line sage: line.is_compact() False """ @@ -762,9 +758,9 @@ def as_polyhedron(self, **kwds): sage: P = polytopes.cross_polytope(3); P A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices - sage: face = P.faces(2)[3] - sage: face - A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices + sage: face = P.faces(2)[3]; face + A 2-dimensional face of a + Polyhedron in ZZ^3 defined as the convex hull of 3 vertices sage: face.as_polyhedron() A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices @@ -791,9 +787,9 @@ def _some_elements_(self): sage: P = polytopes.cross_polytope(3); P A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices - sage: face = P.faces(2)[3] - sage: face - A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 3 vertices + sage: face = P.faces(2)[3]; face + A 2-dimensional face of a + Polyhedron in ZZ^3 defined as the convex hull of 3 vertices sage: face.as_polyhedron().vertices() (A vertex at (0, -1, 0), A vertex at (0, 0, -1), A vertex at (1, 0, 0)) sage: face.an_element() # indirect doctest @@ -815,7 +811,8 @@ def contains(self, point): sage: half_plane = Polyhedron(ieqs=[(0,1,0)]) sage: line = half_plane.faces(1)[0]; line - A 1-dimensional face of a Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line + A 1-dimensional face of a + Polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line sage: line.contains([0, 1]) True @@ -864,7 +861,7 @@ def normal_cone(self, direction='outer'): EXAMPLES:: - sage: p = Polyhedron(vertices = [[1,2],[2,1],[-2,2],[-2,-2],[2,-2]]) + sage: p = Polyhedron(vertices=[[1,2], [2,1], [-2,2], [-2,-2], [2,-2]]) sage: for v in p.face_generator(0): ....: vect = v.vertices()[0].vector() ....: nc = v.normal_cone().rays_list() @@ -894,11 +891,14 @@ def normal_cone(self, direction='outer'): sage: f2 = p.faces(1)[0] sage: f3 = p.faces(2)[0] sage: f1.normal_cone() - A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line + A 3-dimensional polyhedron in ZZ^3 defined as + the convex hull of 1 vertex, 2 rays, 1 line sage: f2.normal_cone() - A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line + A 2-dimensional polyhedron in ZZ^3 defined as + the convex hull of 1 vertex, 1 ray, 1 line sage: f3.normal_cone() - A 1-dimensional polyhedron in ZZ^3 defined as the convex hull of 1 vertex and 1 line + A 1-dimensional polyhedron in ZZ^3 defined as + the convex hull of 1 vertex and 1 line Normal cones are only defined for non-empty faces:: @@ -941,8 +941,8 @@ def affine_tangent_cone(self): sage: half_plane_in_space = Polyhedron(ieqs=[(0,1,0,0)], eqns=[(0,0,0,1)]) sage: line = half_plane_in_space.faces(1)[0]; line - A 1-dimensional face - of a Polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line + A 1-dimensional face of a + Polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line sage: T_line = line.affine_tangent_cone() sage: T_line == half_plane_in_space True @@ -954,9 +954,9 @@ def affine_tangent_cone(self): sage: T_edge = edge.affine_tangent_cone() sage: T_edge.Vrepresentation() (A line in the direction (0, 1, 0), - A ray in the direction (0, 0, 1), - A vertex at (1, 0, -1), - A ray in the direction (-1, 0, 0)) + A ray in the direction (0, 0, 1), + A vertex at (1, 0, -1), + A ray in the direction (-1, 0, 0)) TESTS: @@ -1034,9 +1034,9 @@ def combinatorial_face_to_polyhedral_face(polyhedron, combinatorial_face): INPUT: - ``polyhedron`` -- a polyhedron containing ``combinatorial_face`` - - ``combinatorial_face`` -- a ``CombinatorialFace`` + - ``combinatorial_face`` -- a :class:`CombinatorialFace` - OUTPUT: a ``PolyhedronFace``. + OUTPUT: a :class:`PolyhedronFace`. EXAMPLES:: @@ -1059,9 +1059,9 @@ def combinatorial_face_to_polyhedral_face(polyhedron, combinatorial_face): 0 sage: polytopes.simplex(backend='cdd').equations()[0].index() 4 - sage: polytopes.simplex(backend='normaliz').equations()[0].index() # optional - pynormaliz + sage: polytopes.simplex(backend='normaliz').equations()[0].index() # optional - pynormaliz 4 - sage: polytopes.simplex(backend='polymake').equations()[0].index() # optional - jupymake + sage: polytopes.simplex(backend='polymake').equations()[0].index() # optional - jupymake 4 """ V_indices = combinatorial_face.ambient_V_indices() @@ -1074,7 +1074,7 @@ def combinatorial_face_to_polyhedral_face(polyhedron, combinatorial_face): elif polyhedron.backend() in ('normaliz', 'cdd', 'field', 'number_field', 'polymake'): # Equations after the inequalities in Hrep. n_ieqs = polyhedron.n_inequalities() - H_indices = tuple(x for x in combinatorial_face.ambient_H_indices(add_equations=False)) + H_indices = tuple(combinatorial_face.ambient_H_indices(add_equations=False)) H_indices += tuple(range(n_ieqs, n_ieqs + n_equations)) else: raise NotImplementedError("unknown backend") diff --git a/src/sage/geometry/polyhedron/generating_function.py b/src/sage/geometry/polyhedron/generating_function.py index 9fadd8f3e13..2c6cfccf200 100644 --- a/src/sage/geometry/polyhedron/generating_function.py +++ b/src/sage/geometry/polyhedron/generating_function.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat r""" Generating Function of Polyhedron's Integral Points diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index e54d8a7efd1..a1a59cdfe65 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -117,7 +117,7 @@ def zero_sum_projection(d, base_ring=None): Exact computation in :class:`AA <sage.rings.qqbar.AlgebraicRealField>`:: - sage: zero_sum_projection(3, base_ring=AA) # optional - sage.rings.number_field + sage: zero_sum_projection(3, base_ring=AA) # needs sage.rings.number_field [ 0.7071067811865475? -0.7071067811865475? 0] [ 0.4082482904638630? 0.4082482904638630? -0.8164965809277260?] @@ -171,17 +171,17 @@ def project_points(*points, **kwds): Check that it is (almost) an isometry:: - sage: V = list(map(vector, IntegerVectors(n=5, length=3))) # optional - sage.combinat - sage: P = project_points(*V) # optional - sage.combinat - sage: for i in range(21): # optional - sage.combinat + sage: V = list(map(vector, IntegerVectors(n=5, length=3))) + sage: P = project_points(*V) + sage: for i in range(21): # needs sage.combinat ....: for j in range(21): ....: assert abs((V[i]-V[j]).norm() - (P[i]-P[j]).norm()) < 0.00001 Example with exact computation:: - sage: V = [ vector(v) for v in IntegerVectors(n=4, length=2) ] # optional - sage.combinat - sage: P = project_points(*V, base_ring=AA) # optional - sage.combinat sage.rings.number_field - sage: for i in range(len(V)): # optional - sage.combinat sage.rings.number_field + sage: V = [ vector(v) for v in IntegerVectors(n=4, length=2) ] + sage: P = project_points(*V, base_ring=AA) # needs sage.combinat sage.rings.number_field + sage: for i in range(len(V)): # needs sage.combinat sage.rings.number_field ....: for j in range(len(V)): ....: assert (V[i]-V[j]).norm() == (P[i]-P[j]).norm() @@ -412,7 +412,7 @@ def gale_transform_to_primal(vectors, base_ring=None, backend=None): (-55, 0, 0), (0, -55, 0), (0, 0, -55)] - sage: gale_transform_to_primal(p, backend='normaliz') # optional - pynormaliz + sage: gale_transform_to_primal(p, backend='normaliz') # optional - pynormaliz [(16, -35, 54), (24, 10, 31), (-15, 50, -60), @@ -458,7 +458,7 @@ def gale_transform_to_primal(vectors, base_ring=None, backend=None): ker = Matrix(base_ring, vectors).left_kernel() else: ker = Matrix(vectors).left_kernel() - solutions = Polyhedron(lines=tuple(y for y in ker.basis_matrix()), base_ring=base_ring, backend=backend) + solutions = Polyhedron(lines=tuple(ker.basis_matrix()), base_ring=base_ring, backend=backend) from sage.matrix.special import identity_matrix pos_orthant = Polyhedron(rays=identity_matrix(len(vectors)), base_ring=base_ring, backend=backend) @@ -515,15 +515,16 @@ def regular_polygon(self, n, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: octagon = polytopes.regular_polygon(8) # optional - sage.rings.number_field - sage: octagon # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: octagon = polytopes.regular_polygon(8) + sage: octagon A 2-dimensional polyhedron in AA^2 defined as the convex hull of 8 vertices - sage: octagon.n_vertices() # optional - sage.rings.number_field + sage: octagon.n_vertices() 8 - sage: v = octagon.volume() # optional - sage.rings.number_field - sage: v # optional - sage.rings.number_field + sage: v = octagon.volume() + sage: v 2.828427124746190? - sage: v == 2*QQbar(2).sqrt() # optional - sage.rings.number_field + sage: v == 2*QQbar(2).sqrt() True Its non exact version:: @@ -537,14 +538,16 @@ def regular_polygon(self, n, exact=True, base_ring=None, backend=None): TESTS:: - sage: octagon = polytopes.regular_polygon(8, backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: octagon # optional - pynormaliz # optional - sage.rings.number_field + sage: # optional - pynormaliz, needs sage.rings.number_field + sage: octagon = polytopes.regular_polygon(8, backend='normaliz') + sage: octagon A 2-dimensional polyhedron in AA^2 defined as the convex hull of 8 vertices - sage: octagon.n_vertices() # optional - pynormaliz # optional - sage.rings.number_field + sage: octagon.n_vertices() 8 - sage: octagon.volume() # optional - pynormaliz # optional - sage.rings.number_field + sage: octagon.volume() 2*a - sage: TestSuite(octagon).run() # long time # optional - sage.rings.number_field + sage: TestSuite(octagon).run() # long time + sage: TestSuite(polytopes.regular_polygon(5, exact=False)).run() """ n = ZZ(n) @@ -609,8 +612,8 @@ def Birkhoff_polytope(self, n, backend=None): TESTS:: - sage: b4norm = polytopes.Birkhoff_polytope(4,backend='normaliz') # optional - pynormaliz - sage: TestSuite(b4norm).run() # optional - pynormaliz + sage: b4norm = polytopes.Birkhoff_polytope(4,backend='normaliz') # optional - pynormaliz + sage: TestSuite(b4norm).run() # optional - pynormaliz sage: TestSuite(polytopes.Birkhoff_polytope(3)).run() """ from itertools import permutations @@ -678,14 +681,14 @@ def simplex(self, dim=3, project=False, base_ring=None, backend=None): Computation in algebraic reals:: - sage: s3 = polytopes.simplex(3, project=True, base_ring=AA) # optional - sage.rings.number_field - sage: s3.volume() == sqrt(3+1) / factorial(3) # optional - sage.rings.number_field + sage: s3 = polytopes.simplex(3, project=True, base_ring=AA) # needs sage.rings.number_field + sage: s3.volume() == sqrt(3+1) / factorial(3) # needs sage.rings.number_field True TESTS:: - sage: s6norm = polytopes.simplex(6,backend='normaliz') # optional - pynormaliz - sage: TestSuite(s6norm).run() # optional - pynormaliz + sage: s6norm = polytopes.simplex(6,backend='normaliz') # optional - pynormaliz + sage: TestSuite(s6norm).run() # optional - pynormaliz sage: TestSuite(polytopes.simplex(5)).run() """ verts = list((ZZ**(dim + 1)).basis()) @@ -716,47 +719,48 @@ def icosahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: ico = polytopes.icosahedron() # optional - sage.rings.number_field - sage: ico.f_vector() # optional - sage.rings.number_field + sage: ico = polytopes.icosahedron() # needs sage.rings.number_field + sage: ico.f_vector() # needs sage.rings.number_field (1, 12, 30, 20, 1) - sage: ico.volume() # optional - sage.rings.number_field + sage: ico.volume() # needs sage.rings.number_field 5/12*sqrt5 + 5/4 Its non exact version:: - sage: ico = polytopes.icosahedron(exact=False) - sage: ico.base_ring() + sage: ico = polytopes.icosahedron(exact=False) # needs sage.groups + sage: ico.base_ring() # needs sage.groups Real Double Field - sage: ico.volume() # known bug (trac 18214) + sage: ico.volume() # known bug # needs sage.groups 2.181694990... A version using `AA <sage.rings.qqbar.AlgebraicRealField>`:: - sage: ico = polytopes.icosahedron(base_ring=AA) # long time # optional - sage.rings.number_field - sage: ico.base_ring() # long time # optional - sage.rings.number_field + sage: ico = polytopes.icosahedron(base_ring=AA) # long time # needs sage.groups sage.rings.number_field + sage: ico.base_ring() # long time # needs sage.groups sage.rings.number_field Algebraic Real Field - sage: ico.volume() # long time # optional - sage.rings.number_field + sage: ico.volume() # long time # needs sage.groups sage.rings.number_field 2.181694990624913? Note that if base ring is provided it must contain the square root of `5`. Otherwise you will get an error:: - sage: polytopes.icosahedron(base_ring=QQ) # optional - sage.symbolic + sage: polytopes.icosahedron(base_ring=QQ) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert 1/4*sqrt(5) + 1/4 to a rational TESTS:: - sage: ico = polytopes.icosahedron(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: ico.f_vector() # optional - pynormaliz # optional - sage.rings.number_field + sage: # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: ico = polytopes.icosahedron(backend='normaliz') + sage: ico.f_vector() (1, 12, 30, 20, 1) - sage: ico.volume() # optional - pynormaliz # optional - sage.rings.number_field + sage: ico.volume() 5/12*sqrt5 + 5/4 - sage: TestSuite(ico).run() # optional - pynormaliz # optional - sage.rings.number_field + sage: TestSuite(ico).run() - sage: ico = polytopes.icosahedron(exact=False) - sage: TestSuite(ico).run(skip="_test_lawrence") + sage: ico = polytopes.icosahedron(exact=False) # needs sage.groups + sage: TestSuite(ico).run(skip="_test_lawrence") # needs sage.groups """ if base_ring is None and exact: @@ -798,31 +802,32 @@ def dodecahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: d12 = polytopes.dodecahedron() # optional - sage.rings.number_field - sage: d12.f_vector() # optional - sage.rings.number_field + sage: # needs sage.groups sage.rings.number_field + sage: d12 = polytopes.dodecahedron() + sage: d12.f_vector() (1, 20, 30, 12, 1) - sage: d12.volume() # optional - sage.rings.number_field + sage: d12.volume() -176*sqrt5 + 400 - sage: numerical_approx(_) # optional - sage.rings.number_field + sage: numerical_approx(_) 6.45203596003699 - sage: d12 = polytopes.dodecahedron(exact=False) - sage: d12.base_ring() + sage: d12 = polytopes.dodecahedron(exact=False) # needs sage.groups + sage: d12.base_ring() # needs sage.groups Real Double Field Here is an error with a field that does not contain `\sqrt(5)`:: - sage: polytopes.dodecahedron(base_ring=QQ) # optional - sage.symbolic + sage: polytopes.dodecahedron(base_ring=QQ) # needs sage.groups sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert 1/4*sqrt(5) + 1/4 to a rational TESTS:: - sage: d12 = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: d12.f_vector() # optional - pynormaliz # optional - sage.rings.number_field + sage: d12 = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: d12.f_vector() # optional - pynormaliz, needs sage.groups sage.rings.number_field (1, 20, 30, 12, 1) - sage: TestSuite(d12).run() # optional - pynormaliz # optional - sage.rings.number_field + sage: TestSuite(d12).run() # optional - pynormaliz, needs sage.groups sage.rings.number_field """ return self.icosahedron(exact=exact, base_ring=base_ring, backend=backend).polar() @@ -847,17 +852,17 @@ def small_rhombicuboctahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: sr = polytopes.small_rhombicuboctahedron() # optional - sage.rings.number_field - sage: sr.f_vector() # optional - sage.rings.number_field + sage: sr = polytopes.small_rhombicuboctahedron() # needs sage.rings.number_field + sage: sr.f_vector() # needs sage.rings.number_field (1, 24, 48, 26, 1) - sage: sr.volume() # optional - sage.rings.number_field + sage: sr.volume() # needs sage.rings.number_field 80/3*sqrt2 + 32 The faces are `8` equilateral triangles and `18` squares:: - sage: sum(1 for f in sr.facets() if len(f.vertices()) == 3) # optional - sage.rings.number_field + sage: sum(1 for f in sr.facets() if len(f.vertices()) == 3) # needs sage.rings.number_field 8 - sage: sum(1 for f in sr.facets() if len(f.vertices()) == 4) # optional - sage.rings.number_field + sage: sum(1 for f in sr.facets() if len(f.vertices()) == 4) # needs sage.rings.number_field 18 Its non exact version:: @@ -871,12 +876,13 @@ def small_rhombicuboctahedron(self, exact=True, base_ring=None, backend=None): TESTS:: - sage: sr = polytopes.small_rhombicuboctahedron(backend='normaliz') # optional - sage.rings.number_field pynormaliz - sage: sr.f_vector() # optional - sage.rings.number_field pynormaliz + sage: # optional - pynormaliz, needs sage.rings.number_field + sage: sr = polytopes.small_rhombicuboctahedron(backend='normaliz') + sage: sr.f_vector() (1, 24, 48, 26, 1) - sage: sr.volume() # optional - sage.rings.number_field pynormaliz + sage: sr.volume() 80/3*sqrt2 + 32 - sage: TestSuite(sr).run() # long time # optional - sage.rings.number_field pynormaliz + sage: TestSuite(sr).run() # long time """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField @@ -918,8 +924,8 @@ def great_rhombicuboctahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: gr = polytopes.great_rhombicuboctahedron() # long time ~ 3sec # optional - sage.rings.number_field - sage: gr.f_vector() # long time # optional - sage.rings.number_field + sage: gr = polytopes.great_rhombicuboctahedron() # long time # needs sage.rings.number_field + sage: gr.f_vector() # long time # needs sage.rings.number_field (1, 48, 72, 26, 1) A faster implementation is obtained by setting ``exact=False``:: @@ -1040,8 +1046,8 @@ def cuboctahedron(self, backend=None): TESTS:: - sage: co_norm = polytopes.cuboctahedron(backend='normaliz') # optional - pynormaliz - sage: TestSuite(co_norm).run() # optional - pynormaliz + sage: co_norm = polytopes.cuboctahedron(backend='normaliz') # optional - pynormaliz + sage: TestSuite(co_norm).run() # optional - pynormaliz """ v = [[0, -1, -1], [0, 1, -1], [0, -1, 1], [0, 1, 1], [-1, -1, 0], [1, -1, 0], [-1, 1, 0], [1, 1, 0], @@ -1072,28 +1078,28 @@ def truncated_cube(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: co = polytopes.truncated_cube() # optional - sage.rings.number_field - sage: co.f_vector() # optional - sage.rings.number_field + sage: co = polytopes.truncated_cube() # needs sage.rings.number_field + sage: co.f_vector() # needs sage.rings.number_field (1, 24, 36, 14, 1) Its facets are 8 triangles and 6 octogons:: - sage: sum(1 for f in co.facets() if len(f.vertices()) == 3) # optional - sage.rings.number_field + sage: sum(1 for f in co.facets() if len(f.vertices()) == 3) # needs sage.rings.number_field 8 - sage: sum(1 for f in co.facets() if len(f.vertices()) == 8) # optional - sage.rings.number_field + sage: sum(1 for f in co.facets() if len(f.vertices()) == 8) # needs sage.rings.number_field 6 Some more computation:: - sage: co.volume() # optional - sage.rings.number_field + sage: co.volume() # needs sage.rings.number_field 56/3*sqrt2 - 56/3 TESTS:: - sage: co = polytopes.truncated_cube(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: co.f_vector() # optional - pynormaliz # optional - sage.rings.number_field + sage: co = polytopes.truncated_cube(backend='normaliz') # optional - pynormaliz, needs sage.rings.number_field + sage: co.f_vector() # optional - pynormaliz # needs sage.rings.number_field (1, 24, 36, 14, 1) - sage: TestSuite(co).run() # optional - pynormaliz # optional - sage.rings.number_field + sage: TestSuite(co).run() # optional - pynormaliz # needs sage.rings.number_field """ if base_ring is None and exact: @@ -1150,8 +1156,8 @@ def tetrahedron(self, backend=None): TESTS:: - sage: t_norm = polytopes.tetrahedron(backend='normaliz') # optional - pynormaliz - sage: TestSuite(t_norm).run() # optional - pynormaliz + sage: t_norm = polytopes.tetrahedron(backend='normaliz') # optional - pynormaliz + sage: TestSuite(t_norm).run() # optional - pynormaliz """ v = [[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]] return Polyhedron(vertices=v, base_ring=ZZ, backend=backend) @@ -1192,8 +1198,8 @@ def truncated_tetrahedron(self, backend=None): TESTS:: - sage: tt_norm = polytopes.truncated_tetrahedron(backend='normaliz') # optional - pynormaliz - sage: TestSuite(tt_norm).run() # optional - pynormaliz + sage: tt_norm = polytopes.truncated_tetrahedron(backend='normaliz') # optional - pynormaliz + sage: TestSuite(tt_norm).run() # optional - pynormaliz """ v = [(3,1,1), (1,3,1), (1,1,3), (-3,-1,1), (-1,-3,1), (-1,-1,3), @@ -1233,13 +1239,13 @@ def truncated_octahedron(self, backend=None): sage: co.volume() 32 - sage: co.ehrhart_polynomial() # optional - latte_int + sage: co.ehrhart_polynomial() # optional - latte_int # needs sage.combinat 32*t^3 + 18*t^2 + 6*t + 1 TESTS:: - sage: to_norm = polytopes.truncated_octahedron(backend='normaliz') # optional - pynormaliz - sage: TestSuite(to_norm).run() # optional - pynormaliz + sage: to_norm = polytopes.truncated_octahedron(backend='normaliz') # optional - pynormaliz, needs sage.combinat + sage: TestSuite(to_norm).run() # optional - pynormaliz, needs sage.combinat """ v = [(0, e, f) for e in [-1, 1] for f in [-2, 2]] v = [(xyz[sigma(1) - 1], xyz[sigma(2) - 1], xyz[sigma(3) - 1]) @@ -1280,8 +1286,8 @@ def octahedron(self, backend=None): TESTS:: - sage: o_norm = polytopes.octahedron(backend='normaliz') # optional - pynormaliz - sage: TestSuite(o_norm).run() # optional - pynormaliz + sage: o_norm = polytopes.octahedron(backend='normaliz') # optional - pynormaliz + sage: TestSuite(o_norm).run() # optional - pynormaliz """ v = [[0, 0, -1], [0, 0, 1], [1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0]] @@ -1313,14 +1319,17 @@ def snub_cube(self, exact=False, base_ring=None, backend=None, verbose=False): EXAMPLES:: - sage: sc_inexact = polytopes.snub_cube(exact=False); sc_inexact # optional - sage.groups + sage: # needs sage.groups + sage: sc_inexact = polytopes.snub_cube(exact=False); sc_inexact A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 24 vertices - sage: sc_inexact.f_vector() # optional - sage.groups + sage: sc_inexact.f_vector() (1, 24, 60, 38, 1) - sage: sc_exact = polytopes.snub_cube(exact=True) # long time # optional - sage.groups sage.rings.number_field - sage: sc_exact.f_vector() # long time # optional - sage.groups sage.rings.number_field + + sage: # long time, needs sage.groups sage.rings.number_field + sage: sc_exact = polytopes.snub_cube(exact=True) + sage: sc_exact.f_vector() (1, 24, 60, 38, 1) - sage: sorted(sc_exact.vertices()) # long time # optional - sage.groups sage.rings.number_field + sage: sorted(sc_exact.vertices()) [A vertex at (-1, -z, -z^2), A vertex at (-1, -z^2, z), A vertex at (-1, z^2, -z), @@ -1345,13 +1354,13 @@ def snub_cube(self, exact=False, base_ring=None, backend=None, verbose=False): A vertex at (1, -z^2, -z), A vertex at (1, z^2, z), A vertex at (1, z, -z^2)] - sage: sc_exact.is_combinatorially_isomorphic(sc_inexact) # long time # optional - sage.groups sage.rings.number_field + sage: sc_exact.is_combinatorially_isomorphic(sc_inexact) True TESTS:: - sage: sc = polytopes.snub_cube(exact=True, backend='normaliz') # optional - pynormaliz sage.groups sage.rings.number_field - sage: sc.f_vector() # optional - pynormaliz sage.groups sage.rings.number_field + sage: sc = polytopes.snub_cube(exact=True, backend='normaliz') # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: sc.f_vector() # optional - pynormaliz, needs sage.groups sage.rings.number_field (1, 24, 60, 38, 1) """ @@ -1416,34 +1425,37 @@ def buckyball(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: bb = polytopes.buckyball() # long time - 6secs # optional - sage.rings.number_field - sage: bb.f_vector() # long time # optional - sage.rings.number_field + sage: bb = polytopes.buckyball() # long time # needs sage.groups sage.rings.number_field + sage: bb.f_vector() # long time # needs sage.groups sage.rings.number_field (1, 60, 90, 32, 1) - sage: bb.base_ring() # long time # optional - sage.rings.number_field - Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? + sage: bb.base_ring() # long time # needs sage.groups sage.rings.number_field + Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790? A much faster implementation using floating point approximations:: - sage: bb = polytopes.buckyball(exact=False) - sage: bb.f_vector() + sage: bb = polytopes.buckyball(exact=False) # needs sage.groups + sage: bb.f_vector() # needs sage.groups (1, 60, 90, 32, 1) - sage: bb.base_ring() + sage: bb.base_ring() # needs sage.groups Real Double Field Its facets are 5 regular pentagons and 6 regular hexagons:: - sage: sum(1 for f in bb.facets() if len(f.vertices()) == 5) + sage: sum(1 for f in bb.facets() if len(f.vertices()) == 5) # needs sage.groups 12 - sage: sum(1 for f in bb.facets() if len(f.vertices()) == 6) + sage: sum(1 for f in bb.facets() if len(f.vertices()) == 6) # needs sage.groups 20 TESTS:: - sage: bb = polytopes.buckyball(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: bb.f_vector() # optional - pynormaliz # optional - sage.rings.number_field + sage: # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: bb = polytopes.buckyball(backend='normaliz') + sage: bb.f_vector() (1, 60, 90, 32, 1) - sage: bb.base_ring() # optional - pynormaliz # optional - sage.rings.number_field - Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? + sage: bb.base_ring() + Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790? """ return self.icosahedron(exact=exact, base_ring=base_ring, backend=backend).truncation() @@ -1465,25 +1477,27 @@ def icosidodecahedron(self, exact=True, backend=None): EXAMPLES:: - sage: id = polytopes.icosidodecahedron() # optional - sage.rings.number_field - sage: id.f_vector() # optional - sage.rings.number_field + sage: id = polytopes.icosidodecahedron() # needs sage.groups sage.rings.number_field + sage: id.f_vector() # needs sage.groups sage.rings.number_field (1, 30, 60, 32, 1) TESTS:: - sage: id = polytopes.icosidodecahedron(exact=False); id + sage: id = polytopes.icosidodecahedron(exact=False); id # needs sage.groups sage.rings.number_field A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 30 vertices - sage: TestSuite(id).run(skip=["_test_is_combinatorially_isomorphic", + sage: TestSuite(id).run(skip=["_test_is_combinatorially_isomorphic", # needs sage.groups sage.rings.number_field ....: "_test_product", ....: "_test_pyramid", ....: "_test_lawrence"]) - sage: id = polytopes.icosidodecahedron(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field - sage: id.f_vector() # optional - pynormaliz # optional - sage.rings.number_field + sage: # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: id = polytopes.icosidodecahedron(backend='normaliz') + sage: id.f_vector() (1, 30, 60, 32, 1) - sage: id.base_ring() # optional - pynormaliz # optional - sage.rings.number_field - Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? - sage: TestSuite(id).run() # long time # optional - pynormaliz # optional - sage.rings.number_field + sage: id.base_ring() + Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790? + sage: TestSuite(id).run() # long time """ from sage.rings.number_field.number_field import QuadraticField from itertools import product @@ -1530,10 +1544,11 @@ def icosidodecahedron_V2(self, exact=True, base_ring=None, backend=None): EXAMPLES:: sage: id = polytopes.icosidodecahedron_V2() # long time - 6secs - sage: id.f_vector() # long time + sage: id.f_vector() # long time (1, 30, 60, 32, 1) - sage: id.base_ring() # long time - Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? + sage: id.base_ring() # long time + Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790? A much faster implementation using floating point approximations:: @@ -1552,12 +1567,14 @@ def icosidodecahedron_V2(self, exact=True, base_ring=None, backend=None): TESTS:: - sage: id = polytopes.icosidodecahedron_V2(backend='normaliz') # optional - pynormaliz - sage: id.f_vector() # optional - pynormaliz + sage: # optional - pynormaliz + sage: id = polytopes.icosidodecahedron_V2(backend='normaliz') + sage: id.f_vector() (1, 30, 60, 32, 1) - sage: id.base_ring() # optional - pynormaliz - Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? - sage: TestSuite(id).run() # optional - pynormaliz, long time + sage: id.base_ring() + Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790? + sage: TestSuite(id).run() # long time """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField @@ -1600,24 +1617,25 @@ def truncated_dodecahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: td = polytopes.truncated_dodecahedron() - sage: td.f_vector() + sage: td = polytopes.truncated_dodecahedron() # needs sage.rings.number_field + sage: td.f_vector() # needs sage.rings.number_field (1, 60, 90, 32, 1) - sage: td.base_ring() - Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? + sage: td.base_ring() # needs sage.rings.number_field + Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790? Its facets are 20 triangles and 12 regular decagons:: - sage: sum(1 for f in td.facets() if len(f.vertices()) == 3) + sage: sum(1 for f in td.facets() if len(f.vertices()) == 3) # needs sage.rings.number_field 20 - sage: sum(1 for f in td.facets() if len(f.vertices()) == 10) + sage: sum(1 for f in td.facets() if len(f.vertices()) == 10) # needs sage.rings.number_field 12 The faster implementation using floating point approximations does not fully work unfortunately, see https://github.com/cddlib/cddlib/pull/7 for a detailed discussion of this case:: - sage: td = polytopes.truncated_dodecahedron(exact=False) # random + sage: td = polytopes.truncated_dodecahedron(exact=False) # random doctest:warning ... UserWarning: This polyhedron data is numerically complicated; cdd @@ -1633,11 +1651,13 @@ def truncated_dodecahedron(self, exact=True, base_ring=None, backend=None): TESTS:: - sage: td = polytopes.truncated_dodecahedron(backend='normaliz') # optional - pynormaliz - sage: td.f_vector() # optional - pynormaliz + sage: # optional - pynormaliz, needs sage.rings.number_field + sage: td = polytopes.truncated_dodecahedron(backend='normaliz') + sage: td.f_vector() (1, 60, 90, 32, 1) - sage: td.base_ring() # optional - pynormaliz - Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? + sage: td.base_ring() + Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790? """ if base_ring is None and exact: @@ -1694,15 +1714,15 @@ def pentakis_dodecahedron(self, exact=True, base_ring=None, backend=None): A much faster implementation is obtained when setting ``exact=False``:: - sage: pd = polytopes.pentakis_dodecahedron(exact=False) - sage: pd.n_vertices() + sage: pd = polytopes.pentakis_dodecahedron(exact=False) # needs sage.groups + sage: pd.n_vertices() # needs sage.groups 32 - sage: pd.n_inequalities() + sage: pd.n_inequalities() # needs sage.groups 60 The 60 are triangles:: - sage: all(len(f.vertices()) == 3 for f in pd.facets()) + sage: all(len(f.vertices()) == 3 for f in pd.facets()) # needs sage.groups True """ return self.buckyball(exact=exact, base_ring=base_ring, backend=backend).polar() @@ -1736,8 +1756,8 @@ def Kirkman_icosahedron(self, backend=None): TESTS:: - sage: ki_norm = polytopes.Kirkman_icosahedron(backend='normaliz') # optional - pynormaliz - sage: TestSuite(ki_norm).run() # optional - pynormaliz + sage: ki_norm = polytopes.Kirkman_icosahedron(backend='normaliz') # optional - pynormaliz + sage: TestSuite(ki_norm).run() # optional - pynormaliz """ vertices = [[9, 6, 6], [-9, 6, 6], [9, -6, 6], [9, 6, -6], [-9, -6, 6], [-9, 6, -6], [9, -6, -6], [-9, -6, -6], @@ -1768,11 +1788,12 @@ def rhombicosidodecahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: rid = polytopes.rhombicosidodecahedron() # long time - 6secs - sage: rid.f_vector() # long time + sage: rid = polytopes.rhombicosidodecahedron() # long time (6secs) + sage: rid.f_vector() # long time (1, 60, 120, 62, 1) - sage: rid.base_ring() # long time - Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? + sage: rid.base_ring() # long time + Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790? A much faster implementation using floating point approximations:: @@ -1793,11 +1814,13 @@ def rhombicosidodecahedron(self, exact=True, base_ring=None, backend=None): TESTS:: - sage: rid = polytopes.rhombicosidodecahedron(backend='normaliz') # optional - pynormaliz - sage: rid.f_vector() # optional - pynormaliz + sage: # optional - pynormaliz + sage: rid = polytopes.rhombicosidodecahedron(backend='normaliz') + sage: rid.f_vector() (1, 60, 120, 62, 1) - sage: rid.base_ring() # optional - pynormaliz - Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? + sage: rid.base_ring() + Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790? """ if base_ring is None and exact: @@ -1845,11 +1868,12 @@ def truncated_icosidodecahedron(self, exact=True, base_ring=None, backend=None): EXAMPLES:: - sage: ti = polytopes.truncated_icosidodecahedron() # long time - sage: ti.f_vector() # long time + sage: ti = polytopes.truncated_icosidodecahedron() # long time + sage: ti.f_vector() # long time (1, 120, 180, 62, 1) - sage: ti.base_ring() # long time - Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? + sage: ti.base_ring() # long time + Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790? The implementation using floating point approximations is much faster:: @@ -1871,7 +1895,7 @@ def truncated_icosidodecahedron(self, exact=True, base_ring=None, backend=None): TESTS:: sage: ti = polytopes.truncated_icosidodecahedron(backend='normaliz') # optional - pynormaliz - sage: ti.f_vector() # optional - pynormaliz + sage: ti.f_vector() (1, 120, 180, 62, 1) sage: ti.base_ring() # optional - pynormaliz Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? @@ -1924,17 +1948,20 @@ def snub_dodecahedron(self, base_ring=None, backend=None, verbose=False): Only the backend using the optional normaliz package can construct the snub dodecahedron in reasonable time:: - sage: sd = polytopes.snub_dodecahedron(base_ring=AA, backend='normaliz') # optional - pynormaliz, long time - sage: sd.f_vector() # optional - pynormaliz, long time + sage: sd = polytopes.snub_dodecahedron(base_ring=AA, # optional - pynormaliz, long time + ....: backend='normaliz') + sage: sd.f_vector() # optional - pynormaliz, long time (1, 60, 150, 92, 1) - sage: sd.base_ring() # optional - pynormaliz, long time + sage: sd.base_ring() # optional - pynormaliz, long time Algebraic Real Field Its facets are 80 triangles and 12 pentagons:: - sage: sum(1 for f in sd.facets() if len(f.vertices()) == 3) # optional - pynormaliz, long time + sage: sum(1 for f in sd.facets() # optional - pynormaliz, long time + ....: if len(f.vertices()) == 3) 80 - sage: sum(1 for f in sd.facets() if len(f.vertices()) == 5) # optional - pynormaliz, long time + sage: sum(1 for f in sd.facets() # optional - pynormaliz, long time + ....: if len(f.vertices()) == 5) 12 TESTS: @@ -2009,13 +2036,13 @@ def twenty_four_cell(self, backend=None): TESTS:: - sage: tfcell = polytopes.twenty_four_cell(backend='normaliz') # optional - pynormaliz - sage: TestSuite(tfcell).run() # optional - pynormaliz + sage: tfcell = polytopes.twenty_four_cell(backend='normaliz') # optional - pynormaliz + sage: TestSuite(tfcell).run() # optional - pynormaliz """ q12 = QQ((1, 2)) verts = list(itertools.product([q12, -q12], repeat=4)) B4 = (ZZ**4).basis() - verts.extend(v for v in B4) + verts.extend(B4) verts.extend(-v for v in B4) return Polyhedron(vertices=verts, backend=backend) @@ -2042,7 +2069,7 @@ def runcitruncated_six_hundred_cell(self, exact=True, backend=None): EXAMPLES:: - sage: polytopes.runcitruncated_six_hundred_cell(backend='normaliz') # not tested - very long time + sage: polytopes.runcitruncated_six_hundred_cell(backend='normaliz') # not tested - very long time A 4-dimensional polyhedron in AA^4 defined as the convex hull of 7200 vertices """ @@ -2071,7 +2098,8 @@ def cantitruncated_six_hundred_cell(self, exact=True, backend=None): EXAMPLES:: - sage: polytopes.cantitruncated_six_hundred_cell(exact=True,backend='normaliz') # not tested - very long time + sage: polytopes.cantitruncated_six_hundred_cell(exact=True, # not tested - very long time + ....: backend='normaliz') A 4-dimensional polyhedron in AA^4 defined as the convex hull of 7200 vertices """ return self.generalized_permutahedron(['H', 4], point=[1, 1, 1, 0], exact=exact, backend=backend, regular=True) @@ -2099,7 +2127,8 @@ def bitruncated_six_hundred_cell(self, exact=True, backend=None): EXAMPLES:: - sage: polytopes.runcinated_six_hundred_cell(exact=True,backend='normaliz') # not tested - very long time + sage: polytopes.runcinated_six_hundred_cell(exact=True, # not tested - very long time + ....: backend='normaliz') A 4-dimensional polyhedron in AA^4 defined as the convex hull of 3600 vertices """ return self.generalized_permutahedron(['H', 4], point=[0, 1, 1, 0], exact=exact, backend=backend, regular=True) @@ -2127,7 +2156,7 @@ def cantellated_six_hundred_cell(self, exact=False, backend=None): EXAMPLES:: - sage: polytopes.cantellated_six_hundred_cell() # not tested - very long time + sage: polytopes.cantellated_six_hundred_cell() # not tested - very long time doctest:warning ... UserWarning: This polyhedron data is numerically complicated; cdd @@ -2139,7 +2168,8 @@ def cantellated_six_hundred_cell(self, exact=False, backend=None): It is possible to use the backend ``'normaliz'`` to get an exact representation:: - sage: polytopes.cantellated_six_hundred_cell(exact=True,backend='normaliz') # not tested - long time + sage: polytopes.cantellated_six_hundred_cell(exact=True, # not tested - long time + ....: backend='normaliz') A 4-dimensional polyhedron in AA^4 defined as the convex hull of 3600 vertices """ return self.generalized_permutahedron(['H', 4], point=[1, 0, 1, 0], exact=exact, backend=backend, regular=True) @@ -2166,7 +2196,7 @@ def truncated_six_hundred_cell(self, exact=False, backend=None): EXAMPLES:: - sage: polytopes.truncated_six_hundred_cell() # not tested - long time + sage: polytopes.truncated_six_hundred_cell() # not tested - long time A 4-dimensional polyhedron in RDF^4 defined as the convex hull of 1440 vertices It is possible to use the backend ``'normaliz'`` to get an exact @@ -2200,7 +2230,7 @@ def rectified_six_hundred_cell(self, exact=True, backend=None): EXAMPLES:: - sage: polytopes.rectified_six_hundred_cell(backend='normaliz') # not tested - long time ~14sec + sage: polytopes.rectified_six_hundred_cell(backend='normaliz') # not tested - long time ~14sec A 4-dimensional polyhedron in AA^4 defined as the convex hull of 720 vertices """ return self.generalized_permutahedron(['H', 4], point=[0, 1, 0, 0], exact=exact, backend=backend, regular=True) @@ -2226,22 +2256,23 @@ def six_hundred_cell(self, exact=False, backend=None): EXAMPLES:: - sage: p600 = polytopes.six_hundred_cell() - sage: p600 + sage: p600 = polytopes.six_hundred_cell(); p600 # needs sage.groups A 4-dimensional polyhedron in RDF^4 defined as the convex hull of 120 vertices - sage: p600.f_vector() # long time ~2sec + sage: p600.f_vector() # long time (~2sec) # needs sage.groups (1, 120, 720, 1200, 600, 1) Computation with exact coordinates is currently too long to be useful:: - sage: p600 = polytopes.six_hundred_cell(exact=True) # not tested - very long time - sage: len(list(p600.bounded_edges())) # not tested - very long time + sage: p600 = polytopes.six_hundred_cell(exact=True) # long time, not tested, needs sage.groups + sage: len(list(p600.bounded_edges())) # long time, not tested, needs sage.groups 720 TESTS:: - sage: p600 = polytopes.six_hundred_cell(exact=True, backend='normaliz') # optional - pynormaliz - sage: len(list(p600.bounded_edges())) # optional - pynormaliz, long time + sage: # optional - pynormaliz, needs sage.groups sage.rings.number_field + sage: p600 = polytopes.six_hundred_cell(exact=True, + ....: backend='normaliz') + sage: len(list(p600.bounded_edges())) # long time 720 """ if exact: @@ -2297,8 +2328,8 @@ def grand_antiprism(self, exact=True, backend=None, verbose=False): Computation with the backend ``'normaliz'`` is instantaneous:: - sage: gap_norm = polytopes.grand_antiprism(backend='normaliz') # optional - pynormaliz - sage: gap_norm # optional - pynormaliz + sage: gap_norm = polytopes.grand_antiprism(backend='normaliz') # optional - pynormaliz, needs sage.rings.number_field + sage: gap_norm # optional - pynormaliz, needs sage.rings.number_field A 4-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^4 defined as the convex hull of 100 vertices @@ -2454,15 +2485,17 @@ def hypersimplex(self, dim, k, project=False, backend=None): EXAMPLES:: + sage: # needs sage.combinat sage: h_4_2 = polytopes.hypersimplex(4, 2) sage: h_4_2 A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 6 vertices sage: h_4_2.f_vector() (1, 6, 12, 8, 1) - sage: h_4_2.ehrhart_polynomial() # optional - latte_int + sage: h_4_2.ehrhart_polynomial() # optional - latte_int 2/3*t^3 + 2*t^2 + 7/3*t + 1 sage: TestSuite(h_4_2).run() + sage: # needs sage.combinat sage: h_7_3 = polytopes.hypersimplex(7, 3, project=True) sage: h_7_3 A 6-dimensional polyhedron in RDF^6 defined as the convex hull of 35 vertices @@ -2514,9 +2547,9 @@ def permutahedron(self, n, project=False, backend=None): sage: perm4 = polytopes.permutahedron(4, project=True) sage: perm4 A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 24 vertices - sage: perm4.plot() # optional - sage.plot + sage: perm4.plot() # needs sage.plot Graphics3d Object - sage: perm4.graph().is_isomorphic(graphs.BubbleSortGraph(4)) + sage: perm4.graph().is_isomorphic(graphs.BubbleSortGraph(4)) # needs sage.graphs True As both Hrepresentation an Vrepresentation are known, the permutahedron can be set @@ -2594,19 +2627,23 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula EXAMPLES:: - sage: perm_a3 = polytopes.generalized_permutahedron(['A',3]); perm_a3 + sage: perm_a3 = polytopes.generalized_permutahedron(['A',3]); perm_a3 # needs sage.combinat A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 24 vertices You can put the starting point along the hyperplane of the first generator:: - sage: perm_a3_011 = polytopes.generalized_permutahedron(['A',3],[0,1,1]); perm_a3_011 + sage: # needs sage.combinat + sage: perm_a3_011 = polytopes.generalized_permutahedron(['A',3], [0,1,1]) + sage: perm_a3_011 A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 12 vertices - sage: perm_a3_110 = polytopes.generalized_permutahedron(['A',3],[1,1,0]); perm_a3_110 + sage: perm_a3_110 = polytopes.generalized_permutahedron(['A',3], [1,1,0]) + sage: perm_a3_110 A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 12 vertices sage: perm_a3_110.is_combinatorially_isomorphic(perm_a3_011) True - sage: perm_a3_101 = polytopes.generalized_permutahedron(['A',3],[1,0,1]); perm_a3_101 + sage: perm_a3_101 = polytopes.generalized_permutahedron(['A',3], [1,0,1]) + sage: perm_a3_101 A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 12 vertices sage: perm_a3_110.is_combinatorially_isomorphic(perm_a3_101) False @@ -2618,8 +2655,8 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula The usual output does not necessarily give a polyhedron with isometric vertex figures:: - sage: perm_a2 = polytopes.generalized_permutahedron(['A',2]) - sage: perm_a2.vertices() + sage: perm_a2 = polytopes.generalized_permutahedron(['A',2]) # needs sage.combinat + sage: perm_a2.vertices() # needs sage.combinat (A vertex at (-1, -1), A vertex at (-1, 0), A vertex at (0, -1), @@ -2629,18 +2666,20 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula It works also with Coxeter types that lead to non-rational coordinates:: - sage: perm_b3 = polytopes.generalized_permutahedron(['B',3]); perm_b3 # long time # optional - sage.rings.number_field - A 3-dimensional polyhedron - in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^3 - defined as the convex hull of 48 vertices + sage: perm_b3 = polytopes.generalized_permutahedron(['B',3]) # long time, needs sage.combinat sage.rings.number_field + sage: perm_b3 # long time, needs sage.combinat sage.rings.number_field + A 3-dimensional polyhedron in + (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^3 + defined as the convex hull of 48 vertices Setting ``regular=True`` applies a linear transformation to get isometric vertex figures and the result is inscribed. This cannot be done using rational coordinates. We first do the computations using floating point approximations (``RDF``):: - sage: perm_a2_inexact = polytopes.generalized_permutahedron(['A',2], exact=False) - sage: sorted(perm_a2_inexact.vertices()) + sage: perm_a2_inexact = polytopes.generalized_permutahedron( # needs sage.combinat + ....: ['A',2], exact=False) + sage: sorted(perm_a2_inexact.vertices()) # needs sage.combinat [A vertex at (-1.0, -1.0), A vertex at (-1.0, 0.0), A vertex at (0.0, -1.0), @@ -2648,8 +2687,9 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula A vertex at (1.0, 0.0), A vertex at (1.0, 1.0)] - sage: perm_a2_inexact_reg = polytopes.generalized_permutahedron(['A',2], exact=False, regular=True) - sage: sorted(perm_a2_inexact_reg.vertices()) + sage: perm_a2_inexact_reg = polytopes.generalized_permutahedron( # needs sage.combinat + ....: ['A',2], exact=False, regular=True) + sage: sorted(perm_a2_inexact_reg.vertices()) # needs sage.combinat [A vertex at (-1.0, 0.0), A vertex at (-0.5, -0.8660254038), A vertex at (-0.5, 0.8660254038), @@ -2659,8 +2699,9 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula We can do the same computation using exact arithmetic with the field ``AA``:: - sage: perm_a2_reg = polytopes.generalized_permutahedron(['A',2], regular=True) # optional - sage.rings.number_field - sage: V = sorted(perm_a2_reg.vertices()); V # random # optional - sage.rings.number_field + sage: perm_a2_reg = polytopes.generalized_permutahedron( # needs sage.combinat sage.rings.number_field + ....: ['A',2], regular=True) + sage: V = sorted(perm_a2_reg.vertices()); V # random # needs sage.combinat sage.rings.number_field [A vertex at (-1, 0), A vertex at (-1/2, -0.866025403784439?), A vertex at (-1/2, 0.866025403784439?), @@ -2671,60 +2712,66 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula Even though the numbers look like floating point approximations, the computation is actually exact. We can clean up the display a bit using ``exactify``:: - sage: for v in V: # optional - sage.rings.number_field + sage: for v in V: # needs sage.combinat sage.rings.number_field ....: for x in v: ....: x.exactify() - sage: V # optional - sage.rings.number_field + sage: V # needs sage.combinat sage.rings.number_field [A vertex at (-1, 0), A vertex at (-1/2, -0.866025403784439?), A vertex at (-1/2, 0.866025403784439?), A vertex at (1/2, -0.866025403784439?), A vertex at (1/2, 0.866025403784439?), A vertex at (1, 0)] - sage: perm_a2_reg.is_inscribed() # optional - sage.rings.number_field + sage: perm_a2_reg.is_inscribed() # needs sage.combinat sage.rings.number_field True Larger examples take longer:: - sage: perm_a3_reg = polytopes.generalized_permutahedron(['A',3], regular=True); perm_a3_reg # long time # optional - sage.rings.number_field + sage: # needs sage.combinat sage.rings.number_field + sage: perm_a3_reg = polytopes.generalized_permutahedron( # long time + ....: ['A',3], regular=True); perm_a3_reg A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices - sage: perm_a3_reg.is_inscribed() # long time # optional - sage.rings.number_field + sage: perm_a3_reg.is_inscribed() # long time True - sage: perm_b3_reg = polytopes.generalized_permutahedron(['B',3], regular=True); perm_b3_reg # not tested - long time (12sec on 64 bits). + sage: perm_b3_reg = polytopes.generalized_permutahedron( # long time (12sec on 64 bits), not tested + ....: ['B',3], regular=True); perm_b3_reg A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices It is faster with the backend ``'number_field'``, which internally uses an embedded number field instead of doing the computations directly with the base ring (``AA``):: - sage: perm_a3_reg_nf = polytopes.generalized_permutahedron( # optional - sage.rings.number_field + sage: # needs sage.combinat sage.rings.number_field + sage: perm_a3_reg_nf = polytopes.generalized_permutahedron( ....: ['A',3], regular=True, backend='number_field'); perm_a3_reg_nf A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices - sage: perm_a3_reg_nf.is_inscribed() # optional - sage.rings.number_field + sage: perm_a3_reg_nf.is_inscribed() True - sage: perm_b3_reg_nf = polytopes.generalized_permutahedron( # long time # optional - sage.rings.number_field + sage: perm_b3_reg_nf = polytopes.generalized_permutahedron( # long time ....: ['B',3], regular=True, backend='number_field'); perm_b3_reg_nf A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices It is even faster with the backend ``'normaliz'``:: - sage: perm_a3_reg_norm = polytopes.generalized_permutahedron( # optional - pynormaliz + sage: # optional - pynormaliz, needs sage.combinat sage.rings.number_field + sage: perm_a3_reg_norm = polytopes.generalized_permutahedron( ....: ['A',3], regular=True, backend='normaliz'); perm_a3_reg_norm A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices - sage: perm_a3_reg_norm.is_inscribed() # optional - pynormaliz + sage: perm_a3_reg_norm.is_inscribed() True - sage: perm_b3_reg_norm = polytopes.generalized_permutahedron( # optional - pynormaliz + sage: perm_b3_reg_norm = polytopes.generalized_permutahedron( ....: ['B',3], regular=True, backend='normaliz'); perm_b3_reg_norm A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices The speedups from using backend ``'normaliz'`` allow us to go even further:: - sage: perm_h3 = polytopes.generalized_permutahedron(['H',3], backend='normaliz') # optional - pynormaliz - sage: perm_h3 # optional - pynormaliz - A 3-dimensional polyhedron - in (Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?)^3 + sage: # optional - pynormaliz, needs sage.combinat sage.rings.number_field + sage: perm_h3 = polytopes.generalized_permutahedron( + ....: ['H',3], backend='normaliz'); perm_h3 + A 3-dimensional polyhedron in + (Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?)^3 defined as the convex hull of 120 vertices - sage: perm_f4 = polytopes.generalized_permutahedron(['F',4], backend='normaliz') # long time # optional - pynormaliz - sage: perm_f4 # long time # optional - pynormaliz + sage: perm_f4 = polytopes.generalized_permutahedron( # long time + ....: ['F',4], backend='normaliz'); perm_f4 A 4-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^4 defined as the convex hull of 1152 vertices @@ -2736,7 +2783,7 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula TESTS:: - sage: TestSuite(perm_h3).run() # optional - pynormaliz + sage: TestSuite(perm_h3).run() # optional - pynormaliz # needs sage.combinat sage.rings.number_field """ from sage.combinat.root_system.coxeter_group import CoxeterGroup try: @@ -2816,7 +2863,7 @@ def omnitruncated_one_hundred_twenty_cell(self, exact=True, backend=None): EXAMPLES:: - sage: polytopes.omnitruncated_one_hundred_twenty_cell(backend='normaliz') # not tested - very long time ~10min + sage: polytopes.omnitruncated_one_hundred_twenty_cell(backend='normaliz') # not tested - very long time ~10min A 4-dimensional polyhedron in AA^4 defined as the convex hull of 14400 vertices """ if not exact: @@ -2849,7 +2896,7 @@ def runcitruncated_one_hundred_twenty_cell(self, exact=False, backend=None): EXAMPLES:: - sage: polytopes.runcitruncated_one_hundred_twenty_cell(exact=False) # not tested - very long time + sage: polytopes.runcitruncated_one_hundred_twenty_cell(exact=False) # not tested - very long time doctest:warning ... UserWarning: This polyhedron data is numerically complicated; cdd @@ -2860,7 +2907,8 @@ def runcitruncated_one_hundred_twenty_cell(self, exact=False, backend=None): It is possible to use the backend ``'normaliz'`` to get an exact representation:: - sage: polytopes.runcitruncated_one_hundred_twenty_cell(exact=True,backend='normaliz') # not tested - very long time + sage: polytopes.runcitruncated_one_hundred_twenty_cell(exact=True, # not tested - very long time + ....: backend='normaliz') A 4-dimensional polyhedron in AA^4 defined as the convex hull of 7200 vertices """ return self.generalized_permutahedron(['H', 4], point=[1, 0, 1, 1], exact=exact, backend=backend, regular=True) @@ -2888,7 +2936,7 @@ def cantitruncated_one_hundred_twenty_cell(self, exact=True, backend=None): EXAMPLES:: - sage: polytopes.cantitruncated_one_hundred_twenty_cell(exact=True,backend='normaliz') # not tested - very long time + sage: polytopes.cantitruncated_one_hundred_twenty_cell(exact=True, backend='normaliz') # not tested - very long time A 4-dimensional polyhedron in AA^4 defined as the convex hull of 7200 vertices """ return self.generalized_permutahedron(['H', 4], point=[0, 1, 1, 1], exact=exact, backend=backend, regular=True) @@ -2916,7 +2964,7 @@ def runcinated_one_hundred_twenty_cell(self, exact=False, backend=None): EXAMPLES:: - sage: polytopes.runcinated_one_hundred_twenty_cell(exact=False) # not tested - very long time + sage: polytopes.runcinated_one_hundred_twenty_cell(exact=False) # not tested - very long time doctest:warning ... UserWarning: This polyhedron data is numerically complicated; cdd could not convert between the inexact V and H representation without loss of data. The resulting object @@ -2926,7 +2974,8 @@ def runcinated_one_hundred_twenty_cell(self, exact=False, backend=None): It is possible to use the backend ``'normaliz'`` to get an exact representation:: - sage: polytopes.runcinated_one_hundred_twenty_cell(exact=True,backend='normaliz') # not tested - very long time + sage: polytopes.runcinated_one_hundred_twenty_cell(exact=True, # not tested - very long time + ....: backend='normaliz') A 4-dimensional polyhedron in AA^4 defined as the convex hull of 2400 vertices """ return self.generalized_permutahedron(['H', 4], point=[1, 0, 0, 1], exact=exact, backend=backend, regular=True) @@ -2954,7 +3003,7 @@ def cantellated_one_hundred_twenty_cell(self, exact=True, backend=None): EXAMPLES:: - sage: polytopes.cantellated_one_hundred_twenty_cell(backend='normaliz') # not tested - long time + sage: polytopes.cantellated_one_hundred_twenty_cell(backend='normaliz') # not tested - long time A 4-dimensional polyhedron in AA^4 defined as the convex hull of 3600 vertices """ return self.generalized_permutahedron(['H', 4], point=[0, 1, 0, 1], exact=exact, backend=backend, regular=True) @@ -2982,7 +3031,7 @@ def truncated_one_hundred_twenty_cell(self, exact=True, backend=None): EXAMPLES:: - sage: polytopes.truncated_one_hundred_twenty_cell(backend='normaliz') # not tested - long time + sage: polytopes.truncated_one_hundred_twenty_cell(backend='normaliz') # not tested - long time A 4-dimensional polyhedron in AA^4 defined as the convex hull of 2400 vertices """ return self.generalized_permutahedron(['H', 4], point=[0, 0, 1, 1], exact=exact, backend=backend, regular=True) @@ -3010,7 +3059,7 @@ def rectified_one_hundred_twenty_cell(self, exact=True, backend=None): EXAMPLES:: - sage: polytopes.rectified_one_hundred_twenty_cell(backend='normaliz') # not tested - long time + sage: polytopes.rectified_one_hundred_twenty_cell(backend='normaliz') # not tested - long time A 4-dimensional polyhedron in AA^4 defined as the convex hull of 1200 vertices """ return self.generalized_permutahedron(['H', 4], point=[0, 0, 1, 0], exact=exact, backend=backend, regular=True) @@ -3045,24 +3094,26 @@ def one_hundred_twenty_cell(self, exact=True, backend=None, construction='coxete sage: polytopes.one_hundred_twenty_cell() # not tested - long time ~15 sec. A 4-dimensional polyhedron in (Number Field in sqrt5 with defining - polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^4 defined as - the convex hull of 600 vertices + polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^4 defined as + the convex hull of 600 vertices The ``'normaliz'`` is faster:: sage: P = polytopes.one_hundred_twenty_cell(backend='normaliz'); P # optional - pynormaliz A 4-dimensional polyhedron in (Number Field in sqrt5 with defining - polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^4 defined as the convex hull of 600 vertices + polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^4 defined as + the convex hull of 600 vertices It is also possible to realize it using the generalized permutahedron of type `H_4`:: - sage: polytopes.one_hundred_twenty_cell(backend='normaliz',construction='as_permutahedron') # not tested - long time + sage: polytopes.one_hundred_twenty_cell(backend='normaliz', # not tested - long time + ....: construction='as_permutahedron') A 4-dimensional polyhedron in AA^4 defined as the convex hull of 600 vertices TESTS:: - sage: TestSuite(P).run() # optional - pynormaliz, long time + sage: TestSuite(P).run() # long time, optional - pynormaliz """ if construction == 'coxeter': if not exact: @@ -3150,7 +3201,7 @@ def hypercube(self, dim, intervals=None, backend=None): Return the `0/1`-hypercube of dimension 4:: - sage: z_cube = polytopes.hypercube(4,intervals = 'zero_one') + sage: z_cube = polytopes.hypercube(4, intervals='zero_one') sage: z_cube.vertices()[0] A vertex at (1, 0, 1, 1) sage: z_cube.is_simple() @@ -3159,13 +3210,13 @@ def hypercube(self, dim, intervals=None, backend=None): Integer Ring sage: z_cube.volume() 1 - sage: z_cube.ehrhart_polynomial() # optional - latte_int + sage: z_cube.ehrhart_polynomial() # optional - latte_int t^4 + 4*t^3 + 6*t^2 + 4*t + 1 Return the 4-dimensional combinatorial cube that is the product of [0,3]^4:: - sage: t_cube = polytopes.hypercube(4, intervals = [[0,3]]*4) + sage: t_cube = polytopes.hypercube(4, intervals=[[0,3]]*4) Checking that t_cube is three times the previous `0/1`-cube:: @@ -3193,14 +3244,14 @@ def hypercube(self, dim, intervals=None, backend=None): If the dimension ``dim`` is not equal to the length of intervals, an error is raised:: - sage: u_cube = polytopes.hypercube(2,intervals = [[0,1],[0,2],[0,3]]) + sage: u_cube = polytopes.hypercube(2, intervals=[[0,1],[0,2],[0,3]]) Traceback (most recent call last): ... ValueError: the dimension of the hypercube must match the number of intervals The intervals must be pairs `(a, b)` with `a < b`:: - sage: w_cube = polytopes.hypercube(3, intervals = [[0,1],[3,2],[0,3]]) + sage: w_cube = polytopes.hypercube(3, intervals=[[0,1],[3,2],[0,3]]) Traceback (most recent call last): ... ValueError: each interval must be a pair `(a, b)` with `a < b` @@ -3208,7 +3259,7 @@ def hypercube(self, dim, intervals=None, backend=None): If a string besides 'zero_one' is passed to ``intervals``, return an error:: - sage: v_cube = polytopes.hypercube(3,intervals = 'a_string') + sage: v_cube = polytopes.hypercube(3, intervals='a_string') Traceback (most recent call last): ... ValueError: the only allowed string is 'zero_one' @@ -3218,15 +3269,15 @@ def hypercube(self, dim, intervals=None, backend=None): sage: ls = [randint(-100,100) for _ in range(4)] sage: intervals = [[x, x+randint(1,50)] for x in ls] sage: P = polytopes.hypercube(4, intervals, backend='field') - sage: P1 = polytopes.hypercube(4, intervals, backend='ppl') - sage: assert P == P1 + sage: P1 = polytopes.hypercube(4, intervals, backend='ppl') # needs pplpy + sage: assert P == P1 # needs pplpy Check that coercion for input invervals is handled correctly:: sage: P = polytopes.hypercube(2, [[1/2, 2], [0, 1]]) sage: P = polytopes.hypercube(2, [[1/2, 2], [0, 1.0]]) - sage: P = polytopes.hypercube(2, [[1/2, 2], [0, AA(2).sqrt()]]) - sage: P = polytopes.hypercube(2, [[1/2, 2], [0, 1.0]], backend='ppl') + sage: P = polytopes.hypercube(2, [[1/2, 2], [0, AA(2).sqrt()]]) # needs sage.rings.number_field + sage: P = polytopes.hypercube(2, [[1/2, 2], [0, 1.0]], backend='ppl') # needs pplpy Traceback (most recent call last): ... ValueError: specified backend ppl cannot handle the intervals @@ -3303,13 +3354,13 @@ def cube(self, intervals=None, backend=None): - ``intervals`` -- list (default=None). It takes the following possible inputs: - - If the input is ``None`` (the default), returns the convex hull of - the eight `\pm 1` vectors of length three. + - If the input is ``None`` (the default), returns the convex hull of + the eight `\pm 1` vectors of length three. - - ``'zero_one'`` -- (string). Return the `0/1`-cube. + - ``'zero_one'`` -- (string). Return the `0/1`-cube. - - a list of 3 lists of length 2. The cube will be a product of - these three intervals. + - a list of 3 lists of length 2. The cube will be a product of + these three intervals. - ``backend`` -- the backend to use to create the polytope. @@ -3328,7 +3379,7 @@ def cube(self, intervals=None, backend=None): (1, 8, 12, 6, 1) sage: c.volume() 8 - sage: c.plot() # optional - sage.plot + sage: c.plot() # needs sage.plot Graphics3d Object Return the `0/1`-cube:: @@ -3371,7 +3422,7 @@ def cross_polytope(self, dim, backend=None): TESTS:: - sage: cp = polytopes.cross_polytope(4,backend='normaliz') # optional - pynormaliz + sage: cp = polytopes.cross_polytope(4, backend='normaliz') # optional - pynormaliz sage: TestSuite(cp).run() # optional - pynormaliz :: @@ -3409,19 +3460,19 @@ def parallelotope(self, generators, backend=None): sage: polytopes.parallelotope([ (1,0), (0,1) ]) A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices - sage: polytopes.parallelotope([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]]) + sage: polytopes.parallelotope([[1,2,3,4], [0,1,0,7], [3,1,0,2], [0,0,1,0]]) A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 16 vertices - sage: K = QuadraticField(2, 'sqrt2') - sage: sqrt2 = K.gen() - sage: P = polytopes.parallelotope([ (1,sqrt2), (1,-1) ]); P + sage: K = QuadraticField(2, 'sqrt2') # needs sage.rings.number_field + sage: sqrt2 = K.gen() # needs sage.rings.number_field + sage: P = polytopes.parallelotope([(1, sqrt2), (1, -1)]); P # needs sage.rings.number_field A 2-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?)^2 defined as the convex hull of 4 vertices TESTS:: - sage: TestSuite(P).run() + sage: TestSuite(P).run() # needs sage.rings.number_field """ from sage.modules.free_module_element import vector generators = [vector(v) for v in generators] diff --git a/src/sage/geometry/polyhedron/misc.py b/src/sage/geometry/polyhedron/misc.py index 1e0345c054f..b47e51f79b8 100644 --- a/src/sage/geometry/polyhedron/misc.py +++ b/src/sage/geometry/polyhedron/misc.py @@ -30,7 +30,7 @@ def _to_space_separated_string(l, base_ring=None): sage: import sage.geometry.polyhedron.misc as P sage: P._to_space_separated_string([2,3]) '2 3' - sage: P._to_space_separated_string([2, 1/5], RDF) + sage: P._to_space_separated_string([2, 1/5], RDF) # needs sage.rings.real_double '2.0 0.2' """ if base_ring: diff --git a/src/sage/geometry/polyhedron/modules/__init__.py b/src/sage/geometry/polyhedron/modules/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/categories/examples/__init__.py b/src/sage/geometry/polyhedron/modules/all.py similarity index 100% rename from src/sage/categories/examples/__init__.py rename to src/sage/geometry/polyhedron/modules/all.py diff --git a/src/sage/geometry/polyhedron/palp_database.py b/src/sage/geometry/polyhedron/palp_database.py index 70864270966..29b729cec18 100644 --- a/src/sage/geometry/polyhedron/palp_database.py +++ b/src/sage/geometry/polyhedron/palp_database.py @@ -5,7 +5,7 @@ EXAMPLES:: sage: from sage.geometry.polyhedron.palp_database import PALPreader - sage: for lp in PALPreader(2): + sage: for lp in PALPreader(2): # needs sage.graphs ....: cone = Cone([(1,r[0],r[1]) for r in lp.vertices()]) ....: fan = Fan([cone]) ....: X = ToricVariety(fan) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 8c4905b4b91..92691fab081 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -2,12 +2,12 @@ Parents for Polyhedra """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Volker Braun <vbraun.name@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.structure.parent import Parent from sage.structure.element import get_coercion_model @@ -64,7 +64,7 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * EXAMPLES:: sage: from sage.geometry.polyhedron.parent import Polyhedra - sage: Polyhedra(AA, 3) # optional - sage.rings.number_field + sage: Polyhedra(AA, 3) # needs sage.rings.number_field Polyhedra in AA^3 sage: Polyhedra(ZZ, 3) Polyhedra in ZZ^3 @@ -96,32 +96,34 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * TESTS:: - sage: Polyhedra(RR, 3, backend='field') + sage: Polyhedra(RR, 3, backend='field') # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: the 'field' backend for polyhedron cannot be used with non-exact fields - sage: Polyhedra(RR, 3) + sage: Polyhedra(RR, 3) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: no default backend for computations with Real Field with 53 bits of precision - sage: Polyhedra(QQ[I], 2) # optional - sage.rings.number_field + sage: Polyhedra(QQ[I], 2) # needs sage.rings.number_field Traceback (most recent call last): ... - ValueError: invalid base ring: Number Field in I with defining polynomial x^2 + 1 with I = 1*I cannot be coerced to a real field - sage: Polyhedra(AA, 3, backend='polymake') # optional - jupymake # optional - sage.rings.number_field + ValueError: invalid base ring: Number Field in I + with defining polynomial x^2 + 1 with I = 1*I + cannot be coerced to a real field + sage: Polyhedra(AA, 3, backend='polymake') # optional - jupymake # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: the 'polymake' backend for polyhedron cannot be used with Algebraic Real Field - sage: Polyhedra(QQ, 2, backend='normaliz') # optional - pynormaliz + sage: Polyhedra(QQ, 2, backend='normaliz') Polyhedra in QQ^2 - sage: Polyhedra(SR, 2, backend='normaliz') # optional - pynormaliz # optional - sage.symbolic + sage: Polyhedra(SR, 2, backend='normaliz') # optional - pynormaliz # needs sage.symbolic Polyhedra in (Symbolic Ring)^2 - sage: SCR = SR.subring(no_variables=True) # optional - sage.symbolic - sage: Polyhedra(SCR, 2, backend='normaliz') # optional - pynormaliz # optional - sage.symbolic + sage: SCR = SR.subring(no_variables=True) # needs sage.symbolic + sage: Polyhedra(SCR, 2, backend='normaliz') # optional - pynormaliz # needs sage.symbolic Polyhedra in (Symbolic Constants Subring)^2 - sage: Polyhedra(SCR, 2, backend='number_field') # optional - sage.symbolic + sage: Polyhedra(SCR, 2, backend='number_field') # needs sage.symbolic Polyhedra in (Symbolic Constants Subring)^2 """ @@ -191,7 +193,7 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * return Polyhedra_field(base_ring.fraction_field(), ambient_dim, backend) else: raise ValueError('No such backend (=' + str(backend) + - ') implemented for given basering (=' + str(base_ring)+').') + ') implemented for given basering (=' + str(base_ring) + ').') class Polyhedra_base(UniqueRepresentation, Parent): @@ -208,15 +210,15 @@ class Polyhedra_base(UniqueRepresentation, Parent): - ``backend`` -- string. The name of the backend for computations. There are several backends implemented: - * ``backend="ppl"`` uses the Parma Polyhedra Library + * ``backend="ppl"`` uses the Parma Polyhedra Library - * ``backend="cdd"`` uses CDD + * ``backend="cdd"`` uses CDD - * ``backend="normaliz"`` uses normaliz + * ``backend="normaliz"`` uses normaliz - * ``backend="polymake"`` uses polymake + * ``backend="polymake"`` uses polymake - * ``backend="field"`` a generic Sage implementation + * ``backend="field"`` a generic Sage implementation EXAMPLES:: @@ -270,13 +272,14 @@ def list(self): sage: P.cardinality() +Infinity - sage: P = Polyhedra(AA, 0) # optional - sage.rings.number_field - sage: P.category() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: P = Polyhedra(AA, 0) + sage: P.category() Category of finite enumerated polyhedral sets over Algebraic Real Field - sage: P.list() # optional - sage.rings.number_field + sage: P.list() [The empty polyhedron in AA^0, A 0-dimensional polyhedron in AA^0 defined as the convex hull of 1 vertex] - sage: P.cardinality() # optional - sage.rings.number_field + sage: P.cardinality() 2 """ if self.ambient_dim(): @@ -380,11 +383,14 @@ def some_elements(self): sage: from sage.geometry.polyhedron.parent import Polyhedra sage: Polyhedra(QQ, 4).some_elements() - [A 3-dimensional polyhedron in QQ^4 defined as the convex hull of 4 vertices, - A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 1 vertex and 4 rays, - A 2-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices and 1 ray, + [A 3-dimensional polyhedron in QQ^4 + defined as the convex hull of 4 vertices, + A 4-dimensional polyhedron in QQ^4 + defined as the convex hull of 1 vertex and 4 rays, + A 2-dimensional polyhedron in QQ^4 + defined as the convex hull of 2 vertices and 1 ray, The empty polyhedron in QQ^4] - sage: Polyhedra(ZZ,0).some_elements() + sage: Polyhedra(ZZ, 0).some_elements() [The empty polyhedron in ZZ^0, A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex] """ @@ -395,10 +401,10 @@ def some_elements(self): points = [] R = self.base_ring() for i in range(self.ambient_dim() + 5): - points.append([R(i*j^2) for j in range(self.ambient_dim())]) + points.append([R(i*j ^ 2) for j in range(self.ambient_dim())]) return [ - self.element_class(self, [points[0:self.ambient_dim()+1], [], []], None), - self.element_class(self, [points[0:1], points[1:self.ambient_dim()+1], []], None), + self.element_class(self, [points[0:self.ambient_dim() + 1], [], []], None), + self.element_class(self, [points[0:1], points[1:self.ambient_dim() + 1], []], None), self.element_class(self, [points[0:3], points[4:5], []], None), self.element_class(self, None, None)] @@ -413,10 +419,10 @@ def zero(self): sage: from sage.geometry.polyhedron.parent import Polyhedra sage: p = Polyhedra(QQ, 4).zero(); p A 0-dimensional polyhedron in QQ^4 defined as the convex hull of 1 vertex - sage: p+p == p + sage: p + p == p True """ - Vrep = [[[self.base_ring().zero()]*self.ambient_dim()], [], []] + Vrep = [[[self.base_ring().zero()] * self.ambient_dim()], [], []] return self.element_class(self, Vrep, None) def empty(self): @@ -443,12 +449,13 @@ def universe(self): sage: from sage.geometry.polyhedron.parent import Polyhedra sage: P = Polyhedra(QQ, 4) sage: P.universe() - A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 1 vertex and 4 lines + A 4-dimensional polyhedron in QQ^4 defined as + the convex hull of 1 vertex and 4 lines sage: P.universe().is_universe() True """ R = self.base_ring() - return self(None, [[[R.one()]+[R.zero()]*self.ambient_dim()], []], convert=True) + return self(None, [[[R.one()] + [R.zero()] * self.ambient_dim()], []], convert=True) @cached_method def Vrepresentation_space(self): @@ -496,10 +503,9 @@ def Hrepresentation_space(self): """ if self.base_ring() in Fields(): from sage.modules.free_module import VectorSpace - return VectorSpace(self.base_ring(), self.ambient_dim()+1) - else: - from sage.modules.free_module import FreeModule - return FreeModule(self.base_ring(), self.ambient_dim()+1) + return VectorSpace(self.base_ring(), self.ambient_dim() + 1) + from sage.modules.free_module import FreeModule + return FreeModule(self.base_ring(), self.ambient_dim() + 1) def _repr_base_ring(self): """ @@ -510,8 +516,9 @@ def _repr_base_ring(self): sage: from sage.geometry.polyhedron.parent import Polyhedra sage: Polyhedra(QQ, 3)._repr_base_ring() 'QQ' - sage: K.<sqrt3> = NumberField(x^2 - 3, embedding=AA(3).sqrt()) # optional - sage.rings.number_field - sage: Polyhedra(K, 4)._repr_base_ring() # optional - sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<sqrt3> = NumberField(x^2 - 3, embedding=AA(3).sqrt()) # needs sage.rings.number_field + sage: Polyhedra(K, 4)._repr_base_ring() # needs sage.rings.number_field '(Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)' """ @@ -544,8 +551,9 @@ def _repr_ambient_module(self): sage: from sage.geometry.polyhedron.parent import Polyhedra sage: Polyhedra(QQ, 3)._repr_ambient_module() 'QQ^3' - sage: K.<sqrt3> = NumberField(x^2 - 3, embedding=AA(3).sqrt()) # optional - sage.rings.number_field - sage: Polyhedra(K, 4)._repr_ambient_module() # optional - sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<sqrt3> = NumberField(x^2 - 3, embedding=AA(3).sqrt()) # needs sage.rings.number_field + sage: Polyhedra(K, 4)._repr_ambient_module() # needs sage.rings.number_field '(Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^4' """ s = self._repr_base_ring() @@ -568,7 +576,7 @@ def _repr_(self): sage: Polyhedra(QQ, 3)._repr_() 'Polyhedra in QQ^3' """ - return 'Polyhedra in '+self._repr_ambient_module() + return 'Polyhedra in ' + self._repr_ambient_module() def _element_constructor_(self, *args, **kwds): """ @@ -600,12 +608,14 @@ def _element_constructor_(self, *args, **kwds): Check that :trac:`21270` is fixed:: - sage: poly = polytopes.regular_polygon(7) # optional - sage.rings.number_field - sage: lp, x = poly.to_linear_program(solver='InteractiveLP', return_variable=True) # optional - sage.rings.number_field - sage: lp.set_objective(x[0] + x[1]) # optional - sage.rings.number_field - sage: b = lp.get_backend() # optional - sage.rings.number_field - sage: P = b.interactive_lp_problem() # optional - sage.rings.number_field - sage: p = P.plot() # optional - sage.plot # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: poly = polytopes.regular_polygon(7) + sage: lp, x = poly.to_linear_program(solver='InteractiveLP', + ....: return_variable=True) + sage: lp.set_objective(x[0] + x[1]) + sage: b = lp.get_backend() + sage: P = b.interactive_lp_problem() + sage: p = P.plot() # needs sage.plot sage: Q = Polyhedron(ieqs=[[-499999, 1000000], [1499999, -1000000]]) sage: P = Polyhedron(ieqs=[[0, 1.0], [1.0, -1.0]], base_ring=RDF) @@ -627,11 +637,12 @@ def _element_constructor_(self, *args, **kwds): When the parent of the object is not ``self``, the default is not to copy:: - sage: Q = P.base_extend(AA) # optional - sage.rings.number_field - sage: q = Q._element_constructor_(p) # optional - sage.rings.number_field - sage: q is p # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: Q = P.base_extend(AA) + sage: q = Q._element_constructor_(p) + sage: q is p False - sage: q = Q._element_constructor_(p, copy=False) # optional - sage.rings.number_field + sage: q = Q._element_constructor_(p, copy=False) Traceback (most recent call last): ... ValueError: you need to make a copy when changing the parent @@ -668,7 +679,7 @@ def convert_base_ring_Hrep(lstlst): if m == 0: newlstlst.append(lst) else: - newlstlst.append([q/m for q in lst]) + newlstlst.append([q / m for q in lst]) else: newlstlst.append(lst) return convert_base_ring(newlstlst) @@ -697,7 +708,7 @@ def convert_base_ring_Hrep(lstlst): return self._element_constructor_polyhedron(polyhedron, mutable=mutable, **kwds) if nargs == 1 and args[0] == 0: return self.zero() - raise ValueError('Cannot convert to polyhedron object.') + raise ValueError('cannot convert to polyhedron object') def _element_constructor_polyhedron(self, polyhedron, **kwds): """ @@ -718,10 +729,10 @@ def _element_constructor_polyhedron(self, polyhedron, **kwds): sage: P(p) A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices - sage: P = Polyhedra(AA, 3, backend='field') # optional - sage.rings.number_field + sage: P = Polyhedra(AA, 3, backend='field') # needs sage.rings.number_field sage: vertices = [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)] - sage: p = Polyhedron(vertices=vertices) # optional - sage.rings.number_field - sage: P(p) # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=vertices) + sage: P(p) # needs sage.rings.number_field A 3-dimensional polyhedron in AA^3 defined as the convex hull of 4 vertices """ Vrep = None @@ -745,9 +756,9 @@ def base_extend(self, base_ring, backend=None, ambient_dim=None): EXAMPLES:: sage: from sage.geometry.polyhedron.parent import Polyhedra - sage: Polyhedra(ZZ,3).base_extend(QQ) + sage: Polyhedra(ZZ, 3).base_extend(QQ) Polyhedra in QQ^3 - sage: Polyhedra(ZZ,3).an_element().base_extend(QQ) + sage: Polyhedra(ZZ, 3).an_element().base_extend(QQ) A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices sage: Polyhedra(QQ, 2).base_extend(ZZ) Polyhedra in QQ^2 @@ -781,9 +792,9 @@ def change_ring(self, base_ring, backend=None, ambient_dim=None): EXAMPLES:: sage: from sage.geometry.polyhedron.parent import Polyhedra - sage: Polyhedra(ZZ,3).change_ring(QQ) + sage: Polyhedra(ZZ, 3).change_ring(QQ) Polyhedra in QQ^3 - sage: Polyhedra(ZZ,3).an_element().change_ring(QQ) + sage: Polyhedra(ZZ, 3).an_element().change_ring(QQ) A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices sage: Polyhedra(RDF, 3).change_ring(QQ).backend() @@ -818,26 +829,26 @@ def _coerce_base_ring(self, other): - ``other`` -- must be either: - * another ``Polyhedron`` object + * another ``Polyhedron`` object - * `\ZZ`, `\QQ`, `RDF`, or a ring that can be coerced into them. + * `\ZZ`, `\QQ`, `RDF`, or a ring that can be coerced into them. - * a constant that can be coerced to `\ZZ`, `\QQ`, or `RDF`. + * a constant that can be coerced to `\ZZ`, `\QQ`, or `RDF`. OUTPUT: - Either `\ZZ`, `\QQ`, or `RDF`. Raises ``TypeError`` if + Either `\ZZ`, `\QQ`, or `RDF`. Raises :class:`TypeError` if ``other`` is not a suitable input. .. NOTE:: "Real" numbers in sage are not necessarily elements of - `RDF`. For example, the literal `1.0` is not. + ``RDF``. For example, the literal `1.0` is not. EXAMPLES:: - sage: triangle_QQ = Polyhedron(vertices = [[1,0],[0,1],[1,1]], base_ring=QQ).parent() - sage: triangle_RDF = Polyhedron(vertices = [[1,0],[0,1],[1,1]], base_ring=RDF).parent() + sage: triangle_QQ = Polyhedron(vertices=[[1,0],[0,1],[1,1]], base_ring=QQ).parent() + sage: triangle_RDF = Polyhedron(vertices=[[1,0],[0,1],[1,1]], base_ring=RDF).parent() sage: triangle_QQ._coerce_base_ring(QQ) Rational Field sage: triangle_QQ._coerce_base_ring(triangle_RDF) @@ -858,16 +869,18 @@ def _coerce_base_ring(self, other): Test that :trac:`28770` is fixed:: sage: z = QQ['z'].0 - sage: K = NumberField(z^2 - 2,'s') - sage: triangle_QQ._coerce_base_ring(K) + sage: K = NumberField(z^2 - 2, 's') # needs sage.rings.number_field + sage: triangle_QQ._coerce_base_ring(K) # needs sage.rings.number_field Number Field in s with defining polynomial z^2 - 2 - sage: triangle_QQ._coerce_base_ring(K.gen()) + sage: triangle_QQ._coerce_base_ring(K.gen()) # needs sage.rings.number_field Number Field in s with defining polynomial z^2 - 2 sage: z = QQ['z'].0 - sage: K = NumberField(z^2 - 2,'s') - sage: K.gen()*polytopes.simplex(backend='field') - A 3-dimensional polyhedron in (Number Field in s with defining polynomial z^2 - 2)^4 defined as the convex hull of 4 vertices + sage: K = NumberField(z^2 - 2, 's') # needs sage.rings.number_field + sage: K.gen() * polytopes.simplex(backend='field') # needs sage.rings.number_field + A 3-dimensional polyhedron in + (Number Field in s with defining polynomial z^2 - 2)^4 + defined as the convex hull of 4 vertices """ from sage.structure.element import Element if isinstance(other, Element): @@ -891,19 +904,19 @@ def _coerce_base_ring(self, other): except TypeError: pass if other_ring is None: - raise TypeError('Could not coerce '+str(other)+' into ZZ, QQ, or RDF.') + raise TypeError(f'Could not coerce {other} into ZZ, QQ, or RDF.') if not other_ring.is_exact(): other_ring = RDF # the only supported floating-point numbers for now cm_map, cm_ring = get_coercion_model().analyse(self.base_ring(), other_ring) if cm_ring is None: - raise TypeError('Could not coerce type '+str(other)+' into ZZ, QQ, or RDF.') + raise TypeError(f'Could not coerce type {other} into ZZ, QQ, or RDF.') return cm_ring def _coerce_map_from_(self, X): r""" - Return whether there is a coercion from ``X`` + Return whether there is a coercion from ``X``. INPUT: @@ -916,9 +929,9 @@ def _coerce_map_from_(self, X): EXAMPLES:: sage: from sage.geometry.polyhedron.parent import Polyhedra - sage: Polyhedra(QQ,3).has_coerce_map_from( Polyhedra(ZZ,3) ) # indirect doctest + sage: Polyhedra(QQ, 3).has_coerce_map_from(Polyhedra(ZZ, 3)) # indirect doctest True - sage: Polyhedra(ZZ,3).has_coerce_map_from( Polyhedra(QQ,3) ) + sage: Polyhedra(ZZ, 3).has_coerce_map_from(Polyhedra(QQ, 3)) False """ if not isinstance(X, Polyhedra_base): @@ -988,8 +1001,10 @@ def _get_action_(self, other, op, self_is_left): sage: from sage.geometry.polyhedron.parent import Polyhedra sage: PZZ2.get_action(ZZ^2, op=operator.add) Right action by Ambient free module of rank 2 over the principal ideal domain Integer Ring on Polyhedra in ZZ^2 - with precomposition on left by Identity endomorphism of Polyhedra in ZZ^2 - with precomposition on right by Generic endomorphism of Ambient free module of rank 2 over the principal ideal domain Integer Ring + with precomposition on left by + Identity endomorphism of Polyhedra in ZZ^2 + with precomposition on right by + Generic endomorphism of Ambient free module of rank 2 over the principal ideal domain Integer Ring """ import operator @@ -1043,7 +1058,7 @@ def _make_Inequality(self, polyhedron, data): EXAMPLES:: - sage: p = Polyhedron([(1,2,3),(2/3,3/4,4/5)]) # indirect doctest + sage: p = Polyhedron([(1,2,3), (2/3,3/4,4/5)]) # indirect doctest sage: next(p.inequality_generator()) An inequality (0, 0, -1) x + 3 >= 0 """ @@ -1070,7 +1085,7 @@ def _make_Equation(self, polyhedron, data): EXAMPLES:: - sage: p = Polyhedron([(1,2,3),(2/3,3/4,4/5)]) # indirect doctest + sage: p = Polyhedron([(1,2,3), (2/3,3/4,4/5)]) # indirect doctest sage: next(p.equation_generator()) An equation (0, 44, -25) x - 13 == 0 """ @@ -1097,7 +1112,7 @@ def _make_Vertex(self, polyhedron, data): EXAMPLES:: - sage: p = Polyhedron([(1,2,3),(2/3,3/4,4/5)], rays=[(5/6,6/7,7/8)]) # indirect doctest + sage: p = Polyhedron([(1,2,3), (2/3,3/4,4/5)], rays=[(5/6,6/7,7/8)]) # indirect doctest sage: next(p.vertex_generator()) A vertex at (1, 2, 3) """ @@ -1124,7 +1139,7 @@ def _make_Ray(self, polyhedron, data): EXAMPLES:: - sage: p = Polyhedron([(1,2,3),(2/3,3/4,4/5)], rays=[(5/6,6/7,7/8)]) # indirect doctest + sage: p = Polyhedron([(1,2,3), (2/3,3/4,4/5)], rays=[(5/6,6/7,7/8)]) # indirect doctest sage: next(p.ray_generator()) A ray in the direction (140, 144, 147) """ @@ -1151,7 +1166,7 @@ def _make_Line(self, polyhedron, data): EXAMPLES:: - sage: p = Polyhedron([(1,2,3),(2/3,3/4,4/5)], lines=[(5/6,6/7,7/8)]) # indirect doctest + sage: p = Polyhedron([(1,2,3), (2/3,3/4,4/5)], lines=[(5/6,6/7,7/8)]) # indirect doctest sage: next(p.line_generator()) A line in the direction (140, 144, 147) """ @@ -1201,9 +1216,11 @@ def _element_constructor_polyhedron(self, polyhedron, **kwds): else: return Polyhedra_base._element_constructor_polyhedron(self, polyhedron, **kwds) + class Polyhedra_ZZ_normaliz(Polyhedra_base): Element = Polyhedron_ZZ_normaliz + class Polyhedra_QQ_ppl(Polyhedra_base): Element = Polyhedron_QQ_ppl @@ -1233,27 +1250,35 @@ def _element_constructor_polyhedron(self, polyhedron, **kwds): else: return Polyhedra_base._element_constructor_polyhedron(self, polyhedron, **kwds) + class Polyhedra_QQ_normaliz(Polyhedra_base): Element = Polyhedron_QQ_normaliz + class Polyhedra_QQ_cdd(Polyhedra_base): Element = Polyhedron_QQ_cdd + class Polyhedra_RDF_cdd(Polyhedra_base): Element = Polyhedron_RDF_cdd + class Polyhedra_normaliz(Polyhedra_base): Element = Polyhedron_normaliz + class Polyhedra_polymake(Polyhedra_base): Element = Polyhedron_polymake + class Polyhedra_field(Polyhedra_base): Element = Polyhedron_field + class Polyhedra_number_field(Polyhedra_base): Element = Polyhedron_number_field + @cached_function def does_backend_handle_base_ring(base_ring, backend): r""" @@ -1264,9 +1289,9 @@ def does_backend_handle_base_ring(base_ring, backend): sage: from sage.geometry.polyhedron.parent import does_backend_handle_base_ring sage: does_backend_handle_base_ring(QQ, 'ppl') True - sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'ppl') # optional - sage.rings.number_field + sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'ppl') # needs sage.rings.number_field sage.symbolic False - sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'field') # optional - sage.rings.number_field + sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'field') # needs sage.rings.number_field sage.symbolic True """ try: diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index a4c30cadd0c..b6bb235b711 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -13,7 +13,7 @@ from math import pi -from sage.rings.real_double import RDF +from sage.misc.lazy_import import lazy_import from sage.structure.sage_object import SageObject from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix, identity_matrix @@ -22,7 +22,6 @@ from sage.misc.latex import LatexExpr from sage.structure.sequence import Sequence -from sage.misc.lazy_import import lazy_import lazy_import("sage.plot.all", ["Graphics", "point2d", "line2d", "arrow", "polygon2d", "rainbow"]) lazy_import("sage.plot.plot3d.all", ["point3d", "line3d", "arrow3d", "polygons3d"]) lazy_import("sage.plot.plot3d.transform", "rotate_arbitrary") @@ -178,6 +177,8 @@ def __init__(self, projection_point): [ 0.7071067811... 0.7071067811...] sage: TestSuite(proj).run(skip='_test_pickling') """ + from sage.rings.real_double import RDF + self.projection_point = vector(projection_point) self.dim = self.projection_point.degree() @@ -227,6 +228,8 @@ def __call__(self, x): sage: proj.__call__(vector([1,0,0])) (0.5, 0.0) """ + from sage.rings.real_double import RDF + img = self.house * x denom = self.psize - img[self.dim - 1] if denom.is_zero(): @@ -279,6 +282,8 @@ def __init__(self, facet, projection_point): (2.0, 2.0, 0.0) sage: TestSuite(proj).run(skip='_test_pickling') """ + from sage.rings.real_double import RDF + self.facet = facet ineq = [h for h in facet.ambient_Hrepresentation() if h.is_inequality()][0] self.full_A = ineq.A() @@ -341,6 +346,7 @@ def __init__(self, polyhedron, proj=projection_func_identity): EXAMPLES:: + sage: # needs sage.groups sage: p = polytopes.icosahedron(exact=False) sage: from sage.geometry.polyhedron.plot import Projection sage: Projection(p) @@ -350,12 +356,12 @@ def __init__(self, polyhedron, proj=projection_func_identity): The projection of a polyhedron into 2 dimensions sage: Projection(p, lambda x: [x[1],x[2]] ) # another way of doing the same projection The projection of a polyhedron into 2 dimensions - sage: _.plot() # plot of the projected icosahedron in 2d # optional - sage.plot + sage: _.plot() # plot of the projected icosahedron in 2d # needs sage.plot Graphics object consisting of 51 graphics primitives sage: proj = Projection(p) sage: proj.stereographic([1,2,3]) The projection of a polyhedron into 2 dimensions - sage: proj.plot() # optional - sage.plot + sage: proj.plot() # needs sage.plot Graphics object consisting of 51 graphics primitives sage: TestSuite(proj).run(skip='_test_pickling') """ @@ -406,11 +412,12 @@ def __call__(self, proj=projection_func_identity): EXAMPLES:: + sage: # needs sage.groups sage: p = polytopes.icosahedron(exact=False) sage: from sage.geometry.polyhedron.plot import Projection sage: pproj = Projection(p) sage: from sage.geometry.polyhedron.plot import ProjectionFuncStereographic - sage: pproj_stereo = pproj.__call__(proj = ProjectionFuncStereographic([1,2,3])) + sage: pproj_stereo = pproj.__call__(proj=ProjectionFuncStereographic([1, 2, 3])) sage: sorted(pproj_stereo.polygons) [[2, 0, 9], [3, 1, 10], @@ -430,6 +437,7 @@ def identity(self): EXAMPLES:: + sage: # needs sage.groups sage: p = polytopes.icosahedron(exact=False) sage: from sage.geometry.polyhedron.plot import Projection sage: pproj = Projection(p) @@ -451,12 +459,11 @@ def stereographic(self, projection_point=None): EXAMPLES:: sage: from sage.geometry.polyhedron.plot import Projection - sage: proj = Projection(polytopes.buckyball()) #long time - sage: proj #long time + sage: proj = Projection(polytopes.buckyball()); proj # long time The projection of a polyhedron into 3 dimensions - sage: proj.stereographic([5,2,3]).plot() #long time # optional - sage.plot + sage: proj.stereographic([5,2,3]).plot() # long time # needs sage.plot Graphics object consisting of 123 graphics primitives - sage: Projection( polytopes.twenty_four_cell() ).stereographic([2,0,0,0]) + sage: Projection(polytopes.twenty_four_cell()).stereographic([2,0,0,0]) The projection of a polyhedron into 3 dimensions """ if projection_point is None: @@ -491,7 +498,7 @@ def schlegel(self, facet=None, position=None): sage: from sage.geometry.polyhedron.plot import Projection sage: Projection(cube4).schlegel() The projection of a polyhedron into 3 dimensions - sage: _.plot() # optional - sage.plot + sage: _.plot() # needs sage.plot Graphics3d Object The 4-cube with a truncated vertex seen into the resulting tetrahedron @@ -500,24 +507,24 @@ def schlegel(self, facet=None, position=None): sage: tcube4 = cube4.face_truncation(cube4.faces(0)[0]) sage: tcube4.facets()[4] A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 4 vertices - sage: into_tetra = Projection(tcube4).schlegel(tcube4.facets()[4]) - sage: into_tetra.plot() # optional - sage.plot + sage: into_tetra = Projection(tcube4).schlegel(tcube4.facets()[4]) # needs sage.symbolic + sage: into_tetra.plot() # needs sage.plot sage.symbolic Graphics3d Object Taking a larger value for the position changes the image:: - sage: into_tetra_far = Projection(tcube4).schlegel(tcube4.facets()[4],4) - sage: into_tetra_far.plot() # optional - sage.plot + sage: into_tetra_far = Projection(tcube4).schlegel(tcube4.facets()[4], 4) # needs sage.symbolic + sage: into_tetra_far.plot() # needs sage.plot sage.symbolic Graphics3d Object A value which is too large or negative give a projection point that sees more than one facet resulting in a error:: - sage: Projection(tcube4).schlegel(tcube4.facets()[4],5) + sage: Projection(tcube4).schlegel(tcube4.facets()[4], 5) Traceback (most recent call last): ... ValueError: the chosen position is too large - sage: Projection(tcube4).schlegel(tcube4.facets()[4],-1) + sage: Projection(tcube4).schlegel(tcube4.facets()[4], -1) Traceback (most recent call last): ... ValueError: 'position' should be a positive number @@ -577,7 +584,7 @@ def coord_indices_of(self, v_list): sage: p = polytopes.hypercube(3) sage: proj = p.projection() - sage: proj.coord_indices_of([vector((1,1,1)),vector((1,-1,1))]) + sage: proj.coord_indices_of([vector((1,1,1)), vector((1,-1,1))]) [2, 3] """ return [self.coord_index_of(v) for v in v_list] @@ -633,7 +640,7 @@ def _init_from_2d(self, polyhedron): TESTS:: - sage: p = Polyhedron(vertices = [[0,0],[0,1],[1,0],[1,1]]) + sage: p = Polyhedron(vertices=[[0,0],[0,1],[1,0],[1,1]]) sage: proj = p.projection() sage: [proj.coordinates_of([i]) for i in proj.points] [[[0, 0]], [[0, 1]], [[1, 0]], [[1, 1]]] @@ -655,7 +662,7 @@ def _init_from_3d(self, polyhedron): TESTS:: - sage: p = Polyhedron(vertices = [[0,0,1],[0,1,2],[1,0,3],[1,1,5]]) + sage: p = Polyhedron(vertices=[[0,0,1],[0,1,2],[1,0,3],[1,1,5]]) sage: proj = p.projection() sage: [proj.coordinates_of([i]) for i in proj.points] [[[0, 0, 1]], [[0, 1, 2]], [[1, 0, 3]], [[1, 1, 5]]] @@ -694,7 +701,7 @@ def _init_lines_arrows(self, polyhedron): TESTS:: - sage: p = Polyhedron(ieqs = [[1, 0, 0, 1],[1,1,0,0]]) + sage: p = Polyhedron(ieqs=[[1, 0, 0, 1], [1, 1, 0, 0]]) sage: pp = p.projection() sage: pp.arrows [[0, 1], [0, 2], [0, 3], [0, 4]] @@ -706,7 +713,7 @@ def _init_lines_arrows(self, polyhedron): We check that :trac:`31802` is fixed:: - sage: x = Polyhedron(lines=[(1, 0, 0),(0, 1, 0)], rays=[(0, 0, 1)]) + sage: x = Polyhedron(lines=[(1, 0, 0), (0, 1, 0)], rays=[(0, 0, 1)]) sage: y = x.projection() sage: del y.arrows sage: y.arrows = Sequence([]) @@ -818,12 +825,12 @@ def _init_solid_3d(self, polyhedron): sage: proj.polygons [[1, 0, 2], [3, 0, 1], [2, 0, 3], [3, 1, 2]] - sage: x = Polyhedron(rays = [(-1, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]) + sage: x = Polyhedron(rays=[(-1, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]) sage: y = x.projection() sage: y.polygons [[5, 2, 1, 6], [2, 7, 8, 1]] - sage: cylinder = Polyhedron(vertices = [(0, 0, 0), (1, 0, 0), (0, 1, 0)], lines=[(0, 0, 1)]) + sage: cylinder = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0)], lines=[(0, 0, 1)]) sage: len(cylinder.projection().polygons) 3 """ @@ -913,8 +920,8 @@ def render_points_1d(self, **kwds): sage: cube1 = polytopes.hypercube(1) sage: proj = cube1.projection() - sage: points = proj.render_points_1d() # optional - sage.plot - sage: points._objects # optional - sage.plot + sage: points = proj.render_points_1d() # needs sage.plot + sage: points._objects # needs sage.plot [Point set defined by 2 point(s)] """ return point2d([c + [0] for c in self.coordinates_of(self.points)], **kwds) @@ -934,8 +941,8 @@ def render_line_1d(self, **kwds): EXAMPLES:: - sage: outline = polytopes.hypercube(1).projection().render_line_1d() # optional - sage.plot - sage: outline._objects[0] # optional - sage.plot + sage: outline = polytopes.hypercube(1).projection().render_line_1d() # needs sage.plot + sage: outline._objects[0] # needs sage.plot Line defined by 2 points """ if len(self.lines) == 0: @@ -952,10 +959,11 @@ def render_points_2d(self, **kwds): EXAMPLES:: + sage: # needs sage.rings.number_field sage: hex = polytopes.regular_polygon(6) sage: proj = hex.projection() - sage: hex_points = proj.render_points_2d() # optional - sage.plot - sage: hex_points._objects # optional - sage.plot + sage: hex_points = proj.render_points_2d() # needs sage.plot + sage: hex_points._objects # needs sage.plot [Point set defined by 6 point(s)] """ return point2d(self.coordinates_of(self.points), **kwds) @@ -966,9 +974,9 @@ def render_outline_2d(self, **kwds): EXAMPLES:: - sage: penta = polytopes.regular_polygon(5) - sage: outline = penta.projection().render_outline_2d() # optional - sage.plot - sage: outline._objects[0] # optional - sage.plot + sage: penta = polytopes.regular_polygon(5) # needs sage.rings.number_field + sage: outline = penta.projection().render_outline_2d() # needs sage.plot sage.rings.number_field + sage: outline._objects[0] # needs sage.plot sage.rings.number_field Line defined by 2 points """ wireframe = [] @@ -986,11 +994,11 @@ def render_fill_2d(self, **kwds): EXAMPLES:: - sage: cps = [i^3 for i in srange(-2,2,1/5)] - sage: p = Polyhedron(vertices = [[(t^2-1)/(t^2+1),2*t/(t^2+1)] for t in cps]) + sage: cps = [i^3 for i in srange(-2, 2, 1/5)] + sage: p = Polyhedron(vertices=[[(t^2-1)/(t^2+1), 2*t/(t^2+1)] for t in cps]) sage: proj = p.projection() - sage: filled_poly = proj.render_fill_2d() # optional - sage.plot - sage: filled_poly.axes_width() # optional - sage.plot + sage: filled_poly = proj.render_fill_2d() # needs sage.plot + sage: filled_poly.axes_width() # needs sage.plot 0.8 """ poly = [polygon2d(self.coordinates_of(p), **kwds) @@ -1005,8 +1013,8 @@ def render_vertices_3d(self, **kwds): sage: p = polytopes.cross_polytope(3) sage: proj = p.projection() - sage: verts = proj.render_vertices_3d() # optional - sage.plot - sage: verts.bounding_box() # optional - sage.plot + sage: verts = proj.render_vertices_3d() # needs sage.plot + sage: verts.bounding_box() # needs sage.plot ((-1.0, -1.0, -1.0), (1.0, 1.0, 1.0)) """ return point3d(self.coordinates_of(self.points), **kwds) @@ -1019,8 +1027,8 @@ def render_wireframe_3d(self, **kwds): sage: cube = polytopes.hypercube(3) sage: cube_proj = cube.projection() - sage: wire = cube_proj.render_wireframe_3d() # optional - sage.plot - sage: print(wire.tachyon().split('\n')[77]) # for testing # optional - sage.plot + sage: wire = cube_proj.render_wireframe_3d() # needs sage.plot + sage: print(wire.tachyon().split('\n')[77]) # for testing # needs sage.plot FCylinder base 1.0 1.0 -1.0 apex -1.0 1.0 -1.0 rad 0.005 texture... """ wireframe = [] @@ -1039,8 +1047,8 @@ def render_solid_3d(self, **kwds): EXAMPLES:: sage: p = polytopes.hypercube(3).projection() - sage: p_solid = p.render_solid_3d(opacity=.7) # optional - sage.plot - sage: type(p_solid) # optional - sage.plot + sage: p_solid = p.render_solid_3d(opacity=.7) # needs sage.plot + sage: type(p_solid) # needs sage.plot <class 'sage.plot.plot3d.index_face_set.IndexFaceSet'> """ polys = self.polygons @@ -1070,9 +1078,10 @@ def render_0d(self, point_opts=None, line_opts=None, polygon_opts=None): EXAMPLES:: - sage: print(Polyhedron([]).projection().render_0d().description()) # optional - sage.plot + sage: print(Polyhedron([]).projection().render_0d().description()) # needs sage.plot <BLANKLINE> - sage: print(Polyhedron(ieqs=[(1,)]).projection().render_0d().description()) # optional - sage.plot + sage: P = Polyhedron(ieqs=[(1,)]) + sage: print(P.projection().render_0d().description()) # needs sage.plot Point set defined by 1 point(s): [(0.0, 0.0)] """ if point_opts is None: @@ -1101,7 +1110,7 @@ def render_1d(self, point_opts=None, line_opts=None, polygon_opts=None): EXAMPLES:: - sage: Polyhedron([(0,), (1,)]).projection().render_1d() # optional - sage.plot + sage: Polyhedron([(0,), (1,)]).projection().render_1d() # needs sage.plot Graphics object consisting of 2 graphics primitives """ plt = Graphics() @@ -1133,7 +1142,7 @@ def render_2d(self, point_opts=None, line_opts=None, polygon_opts=None): sage: q3 = p3.projection() sage: p4 = Polyhedron(vertices=[[2,0]], rays=[[1,-1]], lines=[[1,1]]) sage: q4 = p4.projection() - sage: q1.plot() + q2.plot() + q3.plot() + q4.plot() # optional - sage.plot + sage: q1.plot() + q2.plot() + q3.plot() + q4.plot() # needs sage.plot Graphics object consisting of 18 graphics primitives """ plt = Graphics() @@ -1164,29 +1173,34 @@ def render_3d(self, point_opts=None, line_opts=None, polygon_opts=None): sage: p1 = Polyhedron(vertices=[[1,1,1]], rays=[[1,1,1]]) sage: p2 = Polyhedron(vertices=[[2,0,0], [0,2,0], [0,0,2]]) - sage: p3 = Polyhedron(vertices=[[1,0,0], [0,1,0], [0,0,1]], rays=[[-1,-1,-1]]) - sage: p1.projection().plot() + p2.projection().plot() + p3.projection().plot() # optional - sage.plot + sage: p3 = Polyhedron(vertices=[[1,0,0], [0,1,0], [0,0,1]], + ....: rays=[[-1,-1,-1]]) + sage: (p1.projection().plot() + p2.projection().plot() # needs sage.plot + ....: + p3.projection().plot()) Graphics3d Object It correctly handles various degenerate cases:: - sage: Polyhedron(lines=[[1,0,0],[0,1,0],[0,0,1]]).plot() # whole space # optional - sage.plot + sage: # needs sage.plot + sage: Polyhedron(lines=[[1,0,0], [0,1,0], [0,0,1]]).plot() # whole space Graphics3d Object - sage: Polyhedron(vertices=[[1,1,1]], rays=[[1,0,0]], # optional - sage.plot - ....: lines=[[0,1,0],[0,0,1]]).plot() # half space + sage: Polyhedron(vertices=[[1,1,1]], rays=[[1,0,0]], + ....: lines=[[0,1,0], [0,0,1]]).plot() # half space Graphics3d Object - sage: Polyhedron(vertices=[[1,1,1]], # optional - sage.plot - ....: lines=[[0,1,0],[0,0,1]]).plot() # R^2 in R^3 + sage: Polyhedron(lines=[[0,1,0], [0,0,1]], + ....: vertices=[[1,1,1]]).plot() # R^2 in R^3 Graphics3d Object - sage: Polyhedron(rays=[[0,1,0],[0,0,1]], lines=[[1,0,0]]).plot() # quadrant wedge in R^2 # optional - sage.plot + sage: Polyhedron(rays=[[0,1,0], [0,0,1]], # quadrant wedge in R^2 + ....: lines=[[1,0,0]]).plot() Graphics3d Object - sage: Polyhedron(rays=[[0,1,0]], lines=[[1,0,0]]).plot() # upper half plane in R^3 # optional - sage.plot + sage: Polyhedron(rays=[[0,1,0]], # upper half plane in R^3 + ....: lines=[[1,0,0]]).plot() Graphics3d Object - sage: Polyhedron(lines=[[1,0,0]]).plot() # R^1 in R^2 # optional - sage.plot + sage: Polyhedron(lines=[[1,0,0]]).plot() # R^1 in R^2 Graphics3d Object - sage: Polyhedron(rays=[[0,1,0]]).plot() # Half-line in R^3 # optional - sage.plot + sage: Polyhedron(rays=[[0,1,0]]).plot() # Half-line in R^3 Graphics3d Object - sage: Polyhedron(vertices=[[1,1,1]]).plot() # point in R^3 # optional - sage.plot + sage: Polyhedron(vertices=[[1,1,1]]).plot() # point in R^3 Graphics3d Object The origin is not included, if it is not in the polyhedron (:trac:`23555`):: @@ -1194,13 +1208,13 @@ def render_3d(self, point_opts=None, line_opts=None, polygon_opts=None): sage: Q = Polyhedron([[100],[101]]) sage: P = Q*Q*Q; P A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices - sage: p = P.plot() # optional - sage.plot - sage: p.bounding_box() # optional - sage.plot + sage: p = P.plot() # needs sage.plot + sage: p.bounding_box() # needs sage.plot ((100.0, 100.0, 100.0), (101.0, 101.0, 101.0)) Plot 3d polytope with rainbow colors:: - sage: polytopes.hypercube(3).plot(polygon='rainbow', alpha=0.4) # optional - sage.plot + sage: polytopes.hypercube(3).plot(polygon='rainbow', alpha=0.4) # needs sage.plot Graphics3d Object """ pplt = None @@ -1238,28 +1252,28 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, INPUT: - - ``view`` - list (default: [0,0,1]) representing the rotation axis (see note below). - - ``angle`` - integer (default: 0) angle of rotation in degree from 0 to 360 (see note + - ``view`` -- list (default: [0,0,1]) representing the rotation axis (see note below). + - ``angle`` -- integer (default: 0) angle of rotation in degree from 0 to 360 (see note below). - - ``scale`` - integer (default: 1) specifying the scaling of the tikz picture. - - ``edge_color`` - string (default: 'blue!95!black') representing colors which tikz + - ``scale`` -- integer (default: 1) specifying the scaling of the tikz picture. + - ``edge_color`` -- string (default: 'blue!95!black') representing colors which tikz recognize. - - ``facet_color`` - string (default: 'blue!95!black') representing colors which tikz + - ``facet_color`` -- string (default: 'blue!95!black') representing colors which tikz recognize. - - ``vertex_color`` - string (default: 'green') representing colors which tikz + - ``vertex_color`` -- string (default: 'green') representing colors which tikz recognize. - - ``opacity`` - real number (default: 0.8) between 0 and 1 giving the opacity of + - ``opacity`` -- real number (default: 0.8) between 0 and 1 giving the opacity of the front facets. - - ``axis`` - Boolean (default: False) draw the axes at the origin or not. - - ``output_type`` - string (default: ``None``), valid values + - ``axis`` -- Boolean (default: False) draw the axes at the origin or not. + - ``output_type`` -- string (default: ``None``), valid values are ``None`` (deprecated), ``'LatexExpr'`` and ``'TikzPicture'``, - whether to return a LatexExpr object (which inherits from Python - str) or a ``TikzPicture`` object from module + whether to return a :class:`LatexExpr` object (which inherits from Python + :class:`str`) or a :class:`TikzPicture` object from module :mod:`sage.misc.latex_standalone` OUTPUT: - - LatexExpr object or TikzPicture object + :class:`LatexExpr` object or :class:`TikzPicture` object .. NOTE:: @@ -1291,8 +1305,10 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, EXAMPLES:: + sage: # needs sage.plot sage.rings.number_field sage: P1 = polytopes.small_rhombicuboctahedron() - sage: Image1 = P1.projection().tikz([1,3,5], 175, scale=4, output_type='TikzPicture') + sage: Image1 = P1.projection().tikz([1,3,5], 175, scale=4, + ....: output_type='TikzPicture') sage: type(Image1) <class 'sage.misc.latex_standalone.TikzPicture'> sage: Image1 @@ -1319,8 +1335,11 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, A second example:: - sage: P2 = Polyhedron(vertices=[[1, 1],[1, 2],[2, 1]]) - sage: Image2 = P2.projection().tikz(scale=3, edge_color='blue!95!black', facet_color='orange!95!black', opacity=0.4, vertex_color='yellow', axis=True, output_type='TikzPicture') + sage: P2 = Polyhedron(vertices=[[1, 1], [1, 2], [2, 1]]) + sage: Image2 = P2.projection().tikz(scale=3, edge_color='blue!95!black', + ....: facet_color='orange!95!black', opacity=0.4, + ....: vertex_color='yellow', axis=True, + ....: output_type='TikzPicture') sage: Image2 \documentclass[tikz]{standalone} \begin{document} @@ -1341,7 +1360,11 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, The second example using a LatexExpr as output type:: - sage: Image2 = P2.projection().tikz(scale=3, edge_color='blue!95!black', facet_color='orange!95!black', opacity=0.4, vertex_color='yellow', axis=True, output_type='LatexExpr') + sage: # needs sage.plot + sage: Image2 = P2.projection().tikz(scale=3, edge_color='blue!95!black', + ....: facet_color='orange!95!black', opacity=0.4, + ....: vertex_color='yellow', axis=True, + ....: output_type='LatexExpr') sage: type(Image2) <class 'sage.misc.latex.LatexExpr'> sage: print('\n'.join(Image2.splitlines()[:4])) @@ -1349,15 +1372,19 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, [scale=3.000000, back/.style={loosely dotted, thin}, edge/.style={color=blue!95!black, thick}, - sage: with open('polytope-tikz2.tex', 'w') as f: # not tested + sage: with open('polytope-tikz2.tex', 'w') as f: # not tested ....: _ = f.write(Image2) A third example:: - sage: P3 = Polyhedron(vertices=[[-1, -1, 2],[-1, 2, -1],[2, -1, -1]]) - sage: P3 + sage: # needs sage.plot + sage: P3 = Polyhedron(vertices=[[-1, -1, 2], [-1, 2, -1], [2, -1, -1]]); P3 A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices - sage: Image3 = P3.projection().tikz([0.5,-1,-0.1], 55, scale=3, edge_color='blue!95!black',facet_color='orange!95!black', opacity=0.7, vertex_color='yellow', axis=True, output_type='TikzPicture') + sage: Image3 = P3.projection().tikz([0.5, -1, -0.1], 55, scale=3, + ....: edge_color='blue!95!black', + ....: facet_color='orange!95!black', opacity=0.7, + ....: vertex_color='yellow', axis=True, + ....: output_type='TikzPicture') sage: Image3 \documentclass[tikz]{standalone} \begin{document} @@ -1382,8 +1409,8 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, A fourth example:: - sage: P = Polyhedron(vertices=[[1,1,0,0],[1,2,0,0],[2,1,0,0],[0,0,1,0],[0,0,0,1]]) - sage: P + sage: P = Polyhedron(vertices=[[1,1,0,0], [1,2,0,0], + ....: [2,1,0,0], [0,0,1,0], [0,0,0,1]]); P A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices sage: P.projection().tikz(output_type='TikzPicture') Traceback (most recent call last): @@ -1394,8 +1421,8 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, Make it possible to draw Schlegel diagram for 4-polytopes. :: - sage: P=Polyhedron(vertices=[[1,1,0,0],[1,2,0,0],[2,1,0,0],[0,0,1,0],[0,0,0,1]]) - sage: P + sage: P = Polyhedron(vertices=[[1,1,0,0], [1,2,0,0], + ....: [2,1,0,0], [0,0,1,0], [0,0,0,1]]); P A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices sage: P.projection().tikz(output_type='TikzPicture') Traceback (most recent call last): @@ -1450,25 +1477,27 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): INPUT: - - ``scale`` - integer specifying the scaling of the tikz picture. - - ``edge_color`` - string representing colors which tikz + - ``scale`` -- integer specifying the scaling of the tikz picture. + - ``edge_color`` -- string representing colors which tikz recognize. - - ``facet_color`` - string representing colors which tikz + - ``facet_color`` -- string representing colors which tikz recognize. - - ``vertex_color`` - string representing colors which tikz + - ``vertex_color`` -- string representing colors which tikz recognize. - - ``opacity`` - real number between 0 and 1 giving the opacity of + - ``opacity`` -- real number between 0 and 1 giving the opacity of the front facets. - - ``axis`` - Boolean (default: False) draw the axes at the origin or not. + - ``axis`` -- Boolean (default: ``False``) draw the axes at the origin or not. OUTPUT: - - LatexExpr -- containing the TikZ picture. + :class:`LatexExpr` -- containing the TikZ picture. EXAMPLES:: - sage: P = Polyhedron(vertices=[[1, 1],[1, 2],[2, 1]]) - sage: Image = P.projection()._tikz_2d(scale=3, edge_color='black', facet_color='orange', opacity=0.75, vertex_color='yellow', axis=True) + sage: P = Polyhedron(vertices=[[1, 1], [1, 2], [2, 1]]) + sage: Image = P.projection()._tikz_2d(scale=3, edge_color='black', + ....: facet_color='orange', opacity=0.75, + ....: vertex_color='yellow', axis=True) sage: type(Image) <class 'sage.misc.latex.LatexExpr'> sage: print('\n'.join(Image.splitlines()[:4])) @@ -1481,7 +1510,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): Scientific notation is not used in the output (:trac:`16519`):: - sage: P = Polyhedron([[2*10^-10,0],[0,1],[1,0]],base_ring=QQ) + sage: P = Polyhedron([[2*10^-10,0], [0,1], [1,0]], base_ring=QQ) sage: tikz = P.projection().tikz(output_type='TikzPicture') sage: 'e-10' in tikz.content() False @@ -1578,43 +1607,45 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, INPUT: - - ``view`` - list (default: [0,0,1]) representing the rotation axis. - - ``angle`` - integer angle of rotation in degree from 0 to 360. - - ``scale`` - integer specifying the scaling of the tikz picture. - - ``edge_color`` - string representing colors which tikz + - ``view`` -- list (default: [0,0,1]) representing the rotation axis. + - ``angle`` -- integer angle of rotation in degree from 0 to 360. + - ``scale`` -- integer specifying the scaling of the tikz picture. + - ``edge_color`` -- string representing colors which tikz recognize. - - ``facet_color`` - string representing colors which tikz + - ``facet_color`` -- string representing colors which tikz recognize. - - ``vertex_color`` - string representing colors which tikz + - ``vertex_color`` -- string representing colors which tikz recognize. - - ``opacity`` - real number between 0 and 1 giving the opacity of + - ``opacity`` -- real number between 0 and 1 giving the opacity of the front facets. - - ``axis`` - Boolean draw the axes at the origin or not. + - ``axis`` -- Boolean draw the axes at the origin or not. OUTPUT: - - LatexExpr -- containing the TikZ picture. + :class:`LatexExpr` -- containing the TikZ picture. EXAMPLES:: - sage: P = Polyhedron(vertices=[[-1, -1, 2],[-1, 2, -1],[2, -1, -1]]) - sage: P + sage: # needs sage.plot + sage: P = Polyhedron(vertices=[[-1, -1, 2], [-1, 2, -1], [2, -1, -1]]); P A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices - sage: Image = P.projection()._tikz_2d_in_3d(view=[0.5,-1,-0.5], angle=55, scale=3, edge_color='blue!95!black', facet_color='orange', opacity=0.5, vertex_color='yellow', axis=True) + sage: Image = P.projection()._tikz_2d_in_3d(view=[0.5, -1, -0.5], angle=55, scale=3, + ....: edge_color='blue!95!black', facet_color='orange', + ....: opacity=0.5, vertex_color='yellow', axis=True) sage: print('\n'.join(Image.splitlines()[:4])) \begin{tikzpicture}% [x={(0.644647cm, -0.476559cm)}, y={(0.192276cm, 0.857859cm)}, z={(-0.739905cm, -0.192276cm)}, - sage: with open('polytope-tikz3.tex', 'w') as f: # not tested + sage: with open('polytope-tikz3.tex', 'w') as f: # not tested ....: _ = f.write(Image) :: - sage: p = Polyhedron(vertices=[[1,0,0],[0,1,0],[0,0,1]]) + sage: p = Polyhedron(vertices=[[1, 0, 0], [0, 1, 0], [0, 0, 1]]) sage: proj = p.projection() - sage: Img = proj.tikz([1,1,1],130,axis=True, output_type='LatexExpr') - sage: print('\n'.join(Img.splitlines()[12:21])) + sage: Img = proj.tikz([1, 1, 1], 130, axis=True, output_type='LatexExpr') # needs sage.plot + sage: print('\n'.join(Img.splitlines()[12:21])) # needs sage.plot %% with the command: ._tikz_2d_in_3d and parameters: %% view = [1, 1, 1] %% angle = 130 @@ -1629,6 +1660,8 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, The ``facet_color`` is the filing color of the polytope (polygon). """ + from sage.rings.real_double import RDF + view_vector = vector(RDF, view) rot = rotate_arbitrary(view_vector, -(angle/360)*2*pi) rotation_matrix = rot[:2].transpose() @@ -1728,27 +1761,30 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, INPUT: - - ``view`` - list (default: [0,0,1]) representing the rotation axis. - - ``angle`` - integer angle of rotation in degree from 0 to 360. - - ``scale`` - integer specifying the scaling of the tikz picture. - - ``edge_color`` - string representing colors which tikz + - ``view`` -- list (default: [0,0,1]) representing the rotation axis. + - ``angle`` -- integer angle of rotation in degree from 0 to 360. + - ``scale`` -- integer specifying the scaling of the tikz picture. + - ``edge_color`` -- string representing colors which tikz recognize. - - ``facet_color`` - string representing colors which tikz + - ``facet_color`` -- string representing colors which tikz recognize. - - ``vertex_color`` - string representing colors which tikz + - ``vertex_color`` -- string representing colors which tikz recognize. - - ``opacity`` - real number between 0 and 1 giving the opacity of + - ``opacity`` -- real number between 0 and 1 giving the opacity of the front facets. - - ``axis`` - Boolean draw the axes at the origin or not. + - ``axis`` -- Boolean draw the axes at the origin or not. OUTPUT: - - LatexExpr -- containing the TikZ picture. + :class:`LatexExpr` -- containing the TikZ picture. EXAMPLES:: + sage: # needs sage.plot sage.rings.number_field sage: P = polytopes.small_rhombicuboctahedron() - sage: Image = P.projection()._tikz_3d_in_3d([3,7,5], 100, scale=3, edge_color='blue', facet_color='orange', opacity=0.5, vertex_color='green', axis=True) + sage: Image = P.projection()._tikz_3d_in_3d([3, 7, 5], 100, scale=3, + ....: edge_color='blue', facet_color='orange', + ....: opacity=0.5, vertex_color='green', axis=True) sage: type(Image) <class 'sage.misc.latex.LatexExpr'> sage: print('\n'.join(Image.splitlines()[:4])) @@ -1756,13 +1792,17 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, [x={(-0.046385cm, 0.837431cm)}, y={(-0.243536cm, 0.519228cm)}, z={(0.968782cm, 0.170622cm)}, - sage: with open('polytope-tikz1.tex', 'w') as f: # not tested + sage: with open('polytope-tikz1.tex', 'w') as f: # not tested ....: _ = f.write(Image) :: - sage: Associahedron = Polyhedron(vertices=[[1,0,1],[1,0,0],[1,1,0],[0,0,-1],[0,1,0],[-1,0,0],[0,1,1],[0,0,1],[0,-1,0]]).polar() - sage: ImageAsso = Associahedron.projection().tikz([-15,-755,-655], 116, scale=1, output_type='LatexExpr') + sage: # needs sage.plot + sage: Associahedron = Polyhedron(vertices=[[1, 0, 1], [1, 0, 0], [1, 1, 0], + ....: [0, 0, -1], [0, 1, 0], [-1, 0, 0], + ....: [0, 1, 1], [0, 0, 1], [0, -1, 0]]).polar() + sage: ImageAsso = Associahedron.projection().tikz([-15, -755, -655], 116, scale=1, + ....: output_type='LatexExpr') sage: print('\n'.join(ImageAsso.splitlines()[12:30])) %% with the command: ._tikz_3d_in_3d and parameters: %% view = [-15, -755, -655] @@ -1783,6 +1823,8 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, \coordinate (1.00000, -1.00000, 0.00000) at (1.00000, -1.00000, 0.00000); \coordinate (1.00000, 0.00000, -1.00000) at (1.00000, 0.00000, -1.00000); """ + from sage.rings.real_double import RDF + view_vector = vector(RDF, view) rot = rotate_arbitrary(view_vector, -(angle/360)*2*pi) rotation_matrix = rot[:2].transpose() diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py index c7eac168fad..933275357d8 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py @@ -407,11 +407,11 @@ def plot(self): sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: P = LatticePolytope_PPL((1,0), (0,1), (0,0), (2,2)) - sage: P.plot() # optional - sage.plot + sage: P.plot() # needs sage.plot Graphics object consisting of 6 graphics primitives - sage: LatticePolytope_PPL([0], [1]).plot() # optional - sage.plot + sage: LatticePolytope_PPL([0], [1]).plot() # needs sage.plot Graphics object consisting of 3 graphics primitives - sage: LatticePolytope_PPL([0]).plot() # optional - sage.plot + sage: LatticePolytope_PPL([0]).plot() # needs sage.plot Graphics object consisting of 2 graphics primitives """ from sage.plot.point import point2d diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py index 7b8d712c33b..91e4d4de82f 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py @@ -45,10 +45,10 @@ Finally, we can compute automorphisms and identify fibrations that only differ by a lattice automorphism:: - sage: square = LatticePolytope_PPL((-1,-1),(-1,1),(1,-1),(1,1)) + sage: square = LatticePolytope_PPL((-1,-1), (-1,1), (1,-1), (1,1)) sage: fibers = [ f.vertices() for f in square.fibration_generator(1) ]; fibers [((1, 0), (-1, 0)), ((0, 1), (0, -1)), ((-1, -1), (1, 1)), ((-1, 1), (1, -1))] - sage: square.pointsets_mod_automorphism(fibers) + sage: square.pointsets_mod_automorphism(fibers) # needs sage.groups (frozenset({(-1, -1), (1, 1)}), frozenset({(-1, 0), (1, 0)})) AUTHORS: @@ -115,39 +115,39 @@ def LatticePolytope_PPL(*args): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: LatticePolytope_PPL((0,0),(1,0),(0,1)) + sage: LatticePolytope_PPL((0,0), (1,0), (0,1)) A 2-dimensional lattice polytope in ZZ^2 with 3 vertices - sage: from ppl import point, Generator_System, C_Polyhedron, Linear_Expression, Variable - sage: p = point(Linear_Expression([2,3],0)); p + sage: from ppl import point, Generator_System, C_Polyhedron, Linear_Expression # needs pplpy + sage: p = point(Linear_Expression([2,3],0)); p # needs pplpy point(2/1, 3/1) - sage: LatticePolytope_PPL(p) + sage: LatticePolytope_PPL(p) # needs pplpy A 0-dimensional lattice polytope in ZZ^2 with 1 vertex - sage: P = C_Polyhedron(Generator_System(p)); P + sage: P = C_Polyhedron(Generator_System(p)); P # needs pplpy A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point - sage: LatticePolytope_PPL(P) + sage: LatticePolytope_PPL(P) # needs pplpy A 0-dimensional lattice polytope in ZZ^2 with 1 vertex A ``TypeError`` is raised if the arguments do not specify a lattice polytope:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: LatticePolytope_PPL((0,0),(1/2,1)) + sage: LatticePolytope_PPL((0,0), (1/2,1)) # needs pplpy Traceback (most recent call last): ... TypeError: unable to convert rational 1/2 to an integer - sage: from ppl import point, Generator_System, C_Polyhedron, Linear_Expression, Variable - sage: p = point(Linear_Expression([2,3],0), 5); p + sage: from ppl import point, Generator_System, C_Polyhedron, Linear_Expression # needs pplpy + sage: p = point(Linear_Expression([2,3],0), 5); p # needs pplpy point(2/5, 3/5) - sage: LatticePolytope_PPL(p) + sage: LatticePolytope_PPL(p) # needs pplpy Traceback (most recent call last): ... TypeError: generator is not a lattice polytope generator - sage: P = C_Polyhedron(Generator_System(p)); P + sage: P = C_Polyhedron(Generator_System(p)); P # needs pplpy A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point - sage: LatticePolytope_PPL(P) + sage: LatticePolytope_PPL(P) # needs pplpy Traceback (most recent call last): ... TypeError: polyhedron has non-integral generators @@ -179,7 +179,6 @@ def LatticePolytope_PPL(*args): return polytope_class(gs) - ######################################################################## class LatticePolytope_PPL_class(C_Polyhedron): """ @@ -190,7 +189,7 @@ class LatticePolytope_PPL_class(C_Polyhedron): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: LatticePolytope_PPL((0,0),(1,0),(0,1)) + sage: LatticePolytope_PPL((0,0), (1,0), (0,1)) A 2-dimensional lattice polytope in ZZ^2 with 3 vertices """ @@ -205,7 +204,7 @@ def __repr__(self): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: P = LatticePolytope_PPL((0,0),(1,0),(0,1)) + sage: P = LatticePolytope_PPL((0,0), (1,0), (0,1)) sage: P A 2-dimensional lattice polytope in ZZ^2 with 3 vertices sage: P.__repr__() @@ -241,7 +240,7 @@ def is_bounded(self): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: LatticePolytope_PPL((0,0),(1,0),(0,1)).is_bounded() + sage: LatticePolytope_PPL((0,0), (1,0), (0,1)).is_bounded() True """ return True @@ -296,7 +295,7 @@ def bounding_box(self): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: LatticePolytope_PPL((0,0),(1,0),(0,1)).bounding_box() + sage: LatticePolytope_PPL((0,0), (1,0), (0,1)).bounding_box() ((0, 0), (1, 1)) """ box_min = [] @@ -325,7 +324,7 @@ def n_integral_points(self): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: LatticePolytope_PPL((0,0),(1,0),(0,1)).n_integral_points() + sage: LatticePolytope_PPL((0,0), (1,0), (0,1)).n_integral_points() 3 """ if self.is_empty(): @@ -350,7 +349,7 @@ def integral_points(self): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: LatticePolytope_PPL((-1,-1),(1,0),(1,1),(0,1)).integral_points() + sage: LatticePolytope_PPL((-1,-1), (1,0), (1,1), (0,1)).integral_points() ((-1, -1), (0, 0), (0, 1), (1, 0), (1, 1)) sage: simplex = LatticePolytope_PPL((1,2,3), (2,3,7), (-2,-3,-11)) @@ -386,15 +385,15 @@ def integral_points(self): sage: v = [(1,0,0), (0,1,0), (0,0,1), (0,0,-1), (0,-2,1), ....: (-1,2,-1), (-1,2,-2), (-1,1,-2), (-1,-1,2), (-1,-3,2)] sage: P = LatticePolytope_PPL(*v) - sage: pts1 = P.integral_points() # Sage's own code - sage: pts2 = LatticePolytope(v).points() # optional - palp + sage: pts1 = P.integral_points() # Sage's own code + sage: pts2 = LatticePolytope(v).points() # needs palp sage: for p in pts1: p.set_immutable() - sage: set(pts1) == set(pts2) # optional - palp + sage: set(pts1) == set(pts2) # needs palp True sage: len(Polyhedron(v).integral_points()) # takes about 1 ms 23 - sage: len(LatticePolytope(v).points()) # takes about 13 ms # optional - palp + sage: len(LatticePolytope(v).points()) # takes about 13 ms # needs palp 23 sage: len(LatticePolytope_PPL(*v).integral_points()) # takes about 0.5 ms 23 @@ -427,7 +426,7 @@ def _integral_points_saturating(self): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: quad = LatticePolytope_PPL((-1,-1),(0,1),(1,0),(1,1)) + sage: quad = LatticePolytope_PPL((-1,-1), (0,1), (1,0), (1,1)) sage: quad._integral_points_saturating() (((-1, -1), frozenset({0, 1})), ((0, 0), frozenset()), @@ -450,7 +449,7 @@ def _integral_points_saturating(self): @cached_method def integral_points_not_interior_to_facets(self): """ - Return the integral points not interior to facets + Return the integral points not interior to facets. OUTPUT: @@ -461,7 +460,7 @@ def integral_points_not_interior_to_facets(self): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: square = LatticePolytope_PPL((-1,-1),(-1,1),(1,-1),(1,1)) + sage: square = LatticePolytope_PPL((-1,-1), (-1,1), (1,-1), (1,1)) sage: square.n_integral_points() 9 sage: square.integral_points_not_interior_to_facets() @@ -483,7 +482,8 @@ def vertices(self): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: p = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) + sage: p = LatticePolytope_PPL((-9,-6,-1,-1), + ....: (0,0,0,1), (0,0,1,0), (0,1,0,0), (1,0,0,0)) sage: p.vertices() ((-9, -6, -1, -1), (0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, 0), (1, 0, 0, 0)) sage: p.minimized_generators() @@ -503,7 +503,7 @@ def vertices(self): def vertices_saturating(self, constraint): r""" - Return the vertices saturating the constraint + Return the vertices saturating the constraint. INPUT: @@ -518,7 +518,7 @@ def vertices_saturating(self, constraint): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: p = LatticePolytope_PPL((0,0),(0,1),(1,0)) + sage: p = LatticePolytope_PPL((0,0), (0,1), (1,0)) sage: ieq = next(iter(p.constraints())); ieq x0>=0 sage: p.vertices_saturating(ieq) @@ -545,10 +545,10 @@ def is_full_dimensional(self): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: p = LatticePolytope_PPL((0,0),(0,1)) + sage: p = LatticePolytope_PPL((0,0), (0,1)) sage: p.is_full_dimensional() False - sage: q = LatticePolytope_PPL((0,0),(0,1),(1,0)) + sage: q = LatticePolytope_PPL((0,0), (0,1), (1,0)) sage: q.is_full_dimensional() True """ @@ -577,8 +577,9 @@ def fibration_generator(self, dim): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: p = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) - sage: list( p.fibration_generator(2) ) + sage: p = LatticePolytope_PPL((-9,-6,-1,-1), + ....: (0,0,0,1), (0,0,1,0), (0,1,0,0), (1,0,0,0)) + sage: list(p.fibration_generator(2)) [A 2-dimensional lattice polytope in ZZ^4 with 3 vertices] """ assert self.is_full_dimensional() @@ -634,7 +635,7 @@ def pointsets_mod_automorphism(self, pointsets): INPUT: - - ``polytopes`` a tuple/list/iterable of subsets of the + - ``polytopes`` -- a tuple/list/iterable of subsets of the integral points of ``self``. OUTPUT: @@ -645,18 +646,18 @@ def pointsets_mod_automorphism(self, pointsets): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: square = LatticePolytope_PPL((-1,-1),(-1,1),(1,-1),(1,1)) - sage: fibers = [ f.vertices() for f in square.fibration_generator(1) ] - sage: square.pointsets_mod_automorphism(fibers) # optional - sage.groups # optional - sage.graphs + sage: square = LatticePolytope_PPL((-1,-1), (-1,1), (1,-1), (1,1)) + sage: fibers = [f.vertices() for f in square.fibration_generator(1)] + sage: square.pointsets_mod_automorphism(fibers) # needs sage.graphs sage.groups (frozenset({(-1, -1), (1, 1)}), frozenset({(-1, 0), (1, 0)})) sage: cell24 = LatticePolytope_PPL( - ....: (1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1),(1,-1,-1,1),(0,0,-1,1), - ....: (0,-1,0,1),(-1,0,0,1),(1,0,0,-1),(0,1,0,-1),(0,0,1,-1),(-1,1,1,-1), - ....: (1,-1,-1,0),(0,0,-1,0),(0,-1,0,0),(-1,0,0,0),(1,-1,0,0),(1,0,-1,0), - ....: (0,1,1,-1),(-1,1,1,0),(-1,1,0,0),(-1,0,1,0),(0,-1,-1,1),(0,0,0,-1)) + ....: (1,0,0,0), (0,1,0,0), (0,0,1,0), (0,0,0,1), (1,-1,-1,1), (0,0,-1,1), + ....: (0,-1,0,1), (-1,0,0,1), (1,0,0,-1), (0,1,0,-1), (0,0,1,-1), (-1,1,1,-1), + ....: (1,-1,-1,0), (0,0,-1,0), (0,-1,0,0), (-1,0,0,0), (1,-1,0,0), (1,0,-1,0), + ....: (0,1,1,-1), (-1,1,1,0), (-1,1,0,0), (-1,0,1,0), (0,-1,-1,1), (0,0,0,-1)) sage: fibers = [f.vertices() for f in cell24.fibration_generator(2)] - sage: cell24.pointsets_mod_automorphism(fibers) # long time # optional - sage.groups # optional - sage.graphs + sage: cell24.pointsets_mod_automorphism(fibers) # long time # needs sage.graphs sage.groups (frozenset({(-1, 0, 0, 0), (-1, 0, 0, 1), (0, 0, 0, -1), @@ -715,9 +716,7 @@ def contains(self, point_coordinates): - ``point_coordinates`` -- a list/tuple/iterable of rational numbers. The coordinates of the point. - OUTPUT: - - Boolean. + OUTPUT: Boolean. EXAMPLES:: @@ -740,9 +739,7 @@ def contains_origin(self): """ Test whether the polytope contains the origin - OUTPUT: - - Boolean. + OUTPUT: Boolean. EXAMPLES:: @@ -796,7 +793,7 @@ def affine_lattice_polytope(self): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: poly_4d = LatticePolytope_PPL((-9,-6,0,0),(0,1,0,0),(1,0,0,0)); poly_4d + sage: poly_4d = LatticePolytope_PPL((-9,-6,0,0), (0,1,0,0), (1,0,0,0)); poly_4d A 2-dimensional lattice polytope in ZZ^4 with 3 vertices sage: poly_4d.space_dimension() 4 @@ -826,7 +823,8 @@ def base_projection(self, fiber): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: poly = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) + sage: poly = LatticePolytope_PPL((-9,-6,-1,-1), + ....: (0,0,0,1), (0,0,1,0), (0,1,0,0), (1,0,0,0)) sage: fiber = next(poly.fibration_generator(2)) sage: poly.base_projection(fiber) Finitely generated module V/W over Integer Ring with invariants (0, 0) @@ -852,7 +850,8 @@ def base_projection_matrix(self, fiber): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: poly = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) + sage: poly = LatticePolytope_PPL((-9,-6,-1,-1), + ....: (0,0,0,1), (0,0,1,0), (0,1,0,0), (1,0,0,0)) sage: fiber = next(poly.fibration_generator(2)) sage: poly.base_projection_matrix(fiber) [ 0 0 -1 0] @@ -863,9 +862,9 @@ def base_projection_matrix(self, fiber): sage: proj = poly.base_projection(fiber) sage: proj_matrix = poly.base_projection_matrix(fiber) - sage: [ proj(p) for p in poly.integral_points() ] + sage: [proj(p) for p in poly.integral_points()] [(-1, -1), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 1), (1, 0)] - sage: [ proj_matrix*p for p in poly.integral_points() ] + sage: [proj_matrix*p for p in poly.integral_points()] [(1, 1), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, -1), (-1, 0)] """ return matrix(ZZ, fiber.vertices()).right_kernel_matrix() @@ -889,13 +888,14 @@ def base_rays(self, fiber, points): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: poly = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) + sage: poly = LatticePolytope_PPL((-9,-6,-1,-1), + ....: (0,0,0,1), (0,0,1,0), (0,1,0,0), (1,0,0,0)) sage: fiber = next(poly.fibration_generator(2)) sage: poly.base_rays(fiber, poly.integral_points_not_interior_to_facets()) ((-1, -1), (0, 1), (1, 0)) - sage: p = LatticePolytope_PPL((1,0),(1,2),(-1,0)) - sage: f = LatticePolytope_PPL((1,0),(-1,0)) + sage: p = LatticePolytope_PPL((1,0), (1,2), (-1,0)) + sage: f = LatticePolytope_PPL((1,0), (-1,0)) sage: p.base_rays(f, p.integral_points()) ((1),) """ @@ -922,16 +922,14 @@ def has_IP_property(self): That is, the polytope is full-dimensional and the origin is a interior point not on the boundary. - OUTPUT: - - Boolean. + OUTPUT: Boolean. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: LatticePolytope_PPL((-1,-1),(0,1),(1,0)).has_IP_property() + sage: LatticePolytope_PPL((-1,-1), (0,1), (1,0)).has_IP_property() True - sage: LatticePolytope_PPL((-1,-1),(1,1)).has_IP_property() + sage: LatticePolytope_PPL((-1,-1), (1,1)).has_IP_property() False """ origin = C_Polyhedron(point(0*Variable(self.space_dimension()))) @@ -977,24 +975,28 @@ def restricted_automorphism_group(self, vertex_labels=None): EXAMPLES:: + sage: # needs sage.graphs sage.groups sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: Z3square = LatticePolytope_PPL((0,0), (1,2), (2,1), (3,3)) - sage: G1234 = Z3square.restricted_automorphism_group(vertex_labels=(1,2,3,4)) # optional - sage.groups # optional - sage.graphs - sage: G1234 == PermutationGroup([[(2,3)],[(1,2),(3,4)]]) # optional - sage.groups # optional - sage.graphs + sage: G1234 = Z3square.restricted_automorphism_group( + ....: vertex_labels=(1,2,3,4)) + sage: G1234 == PermutationGroup([[(2,3)], [(1,2),(3,4)]]) True - sage: G = Z3square.restricted_automorphism_group() # optional - sage.groups # optional - sage.graphs - sage: G == PermutationGroup([[((1,2),(2,1))],[((0,0),(1,2)),((2,1),(3,3))],[((0,0),(3,3))]]) # optional - sage.groups # optional - sage.graphs + sage: G = Z3square.restricted_automorphism_group() + sage: G == PermutationGroup([[((1,2),(2,1))], [((0,0),(1,2)), + ....: ((2,1),(3,3))], [((0,0),(3,3))]]) True - sage: set(G.domain()) == set(Z3square.vertices()) # optional - sage.groups # optional - sage.graphs + sage: set(G.domain()) == set(Z3square.vertices()) True - sage: set(map(tuple,G.orbit(Z3square.vertices()[0]))) == set([(0, 0), (1, 2), (3, 3), (2, 1)]) # optional - sage.groups # optional - sage.graphs + sage: (set(tuple(x) for x in G.orbit(Z3square.vertices()[0])) + ....: == set([(0, 0), (1, 2), (3, 3), (2, 1)])) True sage: cell24 = LatticePolytope_PPL( - ....: (1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1),(1,-1,-1,1),(0,0,-1,1), - ....: (0,-1,0,1),(-1,0,0,1),(1,0,0,-1),(0,1,0,-1),(0,0,1,-1),(-1,1,1,-1), - ....: (1,-1,-1,0),(0,0,-1,0),(0,-1,0,0),(-1,0,0,0),(1,-1,0,0),(1,0,-1,0), - ....: (0,1,1,-1),(-1,1,1,0),(-1,1,0,0),(-1,0,1,0),(0,-1,-1,1),(0,0,0,-1)) - sage: cell24.restricted_automorphism_group().cardinality() # optional - sage.groups # optional - sage.graphs + ....: (1,0,0,0), (0,1,0,0), (0,0,1,0), (0,0,0,1), (1,-1,-1,1), (0,0,-1,1), + ....: (0,-1,0,1), (-1,0,0,1), (1,0,0,-1), (0,1,0,-1), (0,0,1,-1), (-1,1,1,-1), + ....: (1,-1,-1,0), (0,0,-1,0), (0,-1,0,0), (-1,0,0,0), (1,-1,0,0), (1,0,-1,0), + ....: (0,1,1,-1), (-1,1,1,0), (-1,1,0,0), (-1,0,1,0), (0,-1,-1,1), (0,0,0,-1)) + sage: cell24.restricted_automorphism_group().cardinality() 1152 """ if not self.is_full_dimensional(): @@ -1034,7 +1036,7 @@ def lattice_automorphism_group(self, points=None, point_labels=None): - ``point_labels`` -- A tuple of labels for the ``points`` or ``None`` (default). These will be used as labels for the do - permutation group. If ``None`` the ``points`` will be used + permutation group. If ``None``, the ``points`` will be used themselves. OUTPUT: @@ -1047,32 +1049,34 @@ def lattice_automorphism_group(self, points=None, point_labels=None): sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: Z3square = LatticePolytope_PPL((0,0), (1,2), (2,1), (3,3)) - sage: Z3square.lattice_automorphism_group() # optional - sage.groups # optional - sage.graphs + sage: Z3square.lattice_automorphism_group() # needs sage.graphs sage.groups Permutation Group with generators [(), ((1,2),(2,1)), ((0,0),(3,3)), ((0,0),(3,3))((1,2),(2,1))] - sage: G1 = Z3square.lattice_automorphism_group(point_labels=(1,2,3,4)); G1 # optional - sage.groups # optional - sage.graphs + sage: G1 = Z3square.lattice_automorphism_group(point_labels=(1,2,3,4)) # needs sage.graphs sage.groups + sage: G1 # needs sage.graphs sage.groups Permutation Group with generators [(), (2,3), (1,4), (1,4)(2,3)] - sage: G1.cardinality() # optional - sage.groups # optional - sage.graphs + sage: G1.cardinality() # needs sage.graphs sage.groups 4 - sage: G2 = Z3square.restricted_automorphism_group(vertex_labels=(1,2,3,4)) # optional - sage.groups # optional - sage.graphs - sage: G2 == PermutationGroup([[(2,3)], [(1,2),(3,4)], [(1,4)]]) # optional - sage.groups # optional - sage.graphs + sage: G2 = Z3square.restricted_automorphism_group(vertex_labels=(1,2,3,4)) # needs sage.graphs sage.groups + sage: G2 == PermutationGroup([[(2,3)], [(1,2),(3,4)], [(1,4)]]) # needs sage.graphs sage.groups True - sage: G2.cardinality() # optional - sage.groups # optional - sage.graphs + sage: G2.cardinality() # needs sage.graphs sage.groups 8 - sage: points = Z3square.integral_points(); points + sage: points = Z3square.integral_points(); points ((0, 0), (1, 1), (1, 2), (2, 1), (2, 2), (3, 3)) - sage: Z3square.lattice_automorphism_group(points, point_labels=(1,2,3,4,5,6)) # optional - sage.groups # optional - sage.graphs + sage: Z3square.lattice_automorphism_group(points, # needs sage.graphs sage.groups + ....: point_labels=(1,2,3,4,5,6)) Permutation Group with generators [(), (3,4), (1,6)(2,5), (1,6)(2,5)(3,4)] Point labels also work for lattice polytopes that are not full-dimensional, see :trac:`16669`:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: lp = LatticePolytope_PPL((1,0,0),(0,1,0),(-1,-1,0)) - sage: lp.lattice_automorphism_group(point_labels=(0,1,2)) # optional - sage.groups # optional - sage.graphs + sage: lp = LatticePolytope_PPL((1,0,0), (0,1,0), (-1,-1,0)) + sage: lp.lattice_automorphism_group(point_labels=(0,1,2)) # needs sage.graphs sage.groups Permutation Group with generators [(), (1,2), (0,1), (0,1,2), (0,2,1), (0,2)] """ if not self.is_full_dimensional(): @@ -1149,17 +1153,17 @@ def _find_isomorphism_to_subreflexive_polytope(self): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: polygon = LatticePolytope_PPL((0,0,2,1),(0,1,2,0),(2,3,0,0),(2,0,0,3)) + sage: polygon = LatticePolytope_PPL((0,0,2,1), (0,1,2,0), (2,3,0,0), (2,0,0,3)) sage: polygon._find_isomorphism_to_subreflexive_polytope() (A 2-dimensional lattice polytope in ZZ^2 with 3 vertices, A 2-dimensional lattice polytope in ZZ^2 with 4 vertices, - The map A*x+b with A= - [ 1 1] - [ 0 1] - [-1 -1] - [ 1 0] - b = - (-1, 0, 3, 0)) + The map A*x+b with + A= + [ 1 1] + [ 0 1] + [-1 -1] + [ 1 0] + b = (-1, 0, 3, 0)) sage: ambient, sub, embedding = _ sage: ambient.vertices() ((0, 0), (0, 3), (3, 0)) @@ -1220,15 +1224,15 @@ def embed_in_reflexive_polytope(self, output='hom'): EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL - sage: polygon = LatticePolytope_PPL((0,0,2,1),(0,1,2,0),(2,3,0,0),(2,0,0,3)) + sage: polygon = LatticePolytope_PPL((0,0,2,1), (0,1,2,0), (2,3,0,0), (2,0,0,3)) sage: polygon.embed_in_reflexive_polytope() - The map A*x+b with A= - [ 1 1] - [ 0 1] - [-1 -1] - [ 1 0] - b = - (-1, 0, 3, 0) + The map A*x+b with + A= + [ 1 1] + [ 0 1] + [-1 -1] + [ 1 0] + b = (-1, 0, 3, 0) sage: polygon.embed_in_reflexive_polytope('polytope') A 2-dimensional lattice polytope in ZZ^2 with 3 vertices sage: polygon.embed_in_reflexive_polytope('points') diff --git a/src/sage/geometry/polyhedron/representation.py b/src/sage/geometry/polyhedron/representation.py index 6ce59ff5a8a..554e36ec239 100644 --- a/src/sage/geometry/polyhedron/representation.py +++ b/src/sage/geometry/polyhedron/representation.py @@ -799,8 +799,8 @@ def is_facet_defining_inequality(self, other): sage: Q = Polyhedron(ieqs=[[0,2,0,3]]) sage: Q.inequalities()[0].is_facet_defining_inequality(P) True - sage: Q = Polyhedron(ieqs=[[0,AA(2).sqrt(),0,3]]) # optional - sage.rings.number_field - sage: Q.inequalities()[0].is_facet_defining_inequality(P) # optional - sage.rings.number_field + sage: Q = Polyhedron(ieqs=[[0,AA(2).sqrt(),0,3]]) # needs sage.rings.number_field + sage: Q.inequalities()[0].is_facet_defining_inequality(P) True sage: Q = Polyhedron(ieqs=[[1,1,0,0]]) sage: Q.inequalities()[0].is_facet_defining_inequality(P) @@ -901,9 +901,10 @@ def _repr_(self): Test that :trac:`21105` has been fixed:: - sage: K.<cbrt2> = NumberField(x^3 - 2, 'a', embedding=1.26) # optional - sage.rings.number_field - sage: P = Polyhedron(vertices=[(1,1,cbrt2),(cbrt2,1,1)]) # optional - sage.rings.number_field - sage: P.inequalities() # optional - sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<cbrt2> = NumberField(x^3 - 2, 'a', embedding=1.26) # needs sage.rings.number_field + sage: P = Polyhedron(vertices=[(1,1,cbrt2),(cbrt2,1,1)]) # needs sage.rings.number_field + sage: P.inequalities() # needs sage.rings.number_field (An inequality (-cbrt2^2 - cbrt2 - 1, 0, 0) x + cbrt2^2 + cbrt2 + 2 >= 0, An inequality (cbrt2^2 + cbrt2 + 1, 0, 0) x - cbrt2^2 + cbrt2 + 1 >= 0) """ @@ -993,7 +994,7 @@ def outer_normal(self): EXAMPLES:: - sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]]) + sage: p = Polyhedron(vertices=[[0,0,0],[1,1,0],[1,2,0]]) sage: a = next(p.inequality_generator()) sage: a.outer_normal() (1, -1, 0) @@ -1037,7 +1038,6 @@ def type(self): """ return self.EQUATION - def is_equation(self): """ Tests if this object is an equation. By construction, it must be. diff --git a/src/sage/geometry/pseudolines.py b/src/sage/geometry/pseudolines.py index 37b9ee324ca..8ce4496c65a 100644 --- a/src/sage/geometry/pseudolines.py +++ b/src/sage/geometry/pseudolines.py @@ -49,7 +49,7 @@ sage: p = PseudolineArrangement(permutations) sage: p Arrangement of pseudolines of size 4 - sage: p.show() + sage: p.show() # needs sage.plot **Sequence of transpositions** @@ -67,7 +67,7 @@ sage: p = PseudolineArrangement(transpositions) sage: p Arrangement of pseudolines of size 4 - sage: p.show() + sage: p.show() # needs sage.plot Note that this ordering is not necessarily unique. @@ -75,7 +75,7 @@ **Felsner's Matrix** Felser gave an encoding of an arrangement of pseudolines that takes `n^2` bits -instead of the `n^2log(n)` bits required by the two previous encodings. +instead of the `n^2\log(n)` bits required by the two previous encodings. Instead of storing the permutation ``[3, 2, 1]`` to remember that line `l_0` crosses `l_3` then `l_2` then `l_1`, it is sufficient to remember the positions @@ -129,17 +129,19 @@ avoid a common crossing of three lines by adding a random noise to `b`:: sage: n = 20 - sage: l = sorted(zip(Subsets(20*n,n).random_element(), [randint(0,20*n)+random() for i in range(n)])) - sage: print(l[:5]) # not tested - [(96, 278.0130613051349), (74, 332.92512282478714), (13, 155.65820951249867), (209, 34.753946221755307), (147, 193.51376457741441)] + sage: l = sorted(zip(Subsets(20*n, n).random_element(), + ....: [randint(0, 20*n) + random() for i in range(n)])) + sage: print(l[:5]) # not tested # needs sage.combinat + [(96, 278.0130613051349), (74, 332.92512282478714), (13, 155.65820951249867), + (209, 34.753946221755307), (147, 193.51376457741441)] We can now compute for each `i` the order in which line `i` meets the other lines:: - sage: permutations = [[0..i-1]+[i+1..n-1] for i in range(n)] - sage: a = lambda x : l[x][0] - sage: b = lambda x : l[x][1] + sage: permutations = [[0..i-1] + [i+1..n-1] for i in range(n)] + sage: def a(x): return l[x][0] + sage: def b(x): return l[x][1] sage: for i, perm in enumerate(permutations): - ....: perm.sort(key = lambda j : (b(j)-b(i))/(a(i)-a(j))) + ....: perm.sort(key=lambda j: (b(j)-b(i))/(a(i)-a(j))) And finally build the line arrangement:: @@ -147,7 +149,7 @@ sage: p = PseudolineArrangement(permutations) sage: print(p) Arrangement of pseudolines of size 20 - sage: p.show(figsize=[20,8]) + sage: p.show(figsize=[20,8]) # needs sage.combinat sage.plot Author ^^^^^^ @@ -174,12 +176,12 @@ def __init__(self, seq, encoding="auto"): INPUT: - - ``seq`` (a sequence describing the line arrangement). It can be : + - ``seq`` (a sequence describing the line arrangement). It can be: - - A list of `n` permutations of size `n-1`. - - A list of `\binom n 2` transpositions - - A Felsner matrix, given as a sequence of `n` binary vectors of - length `n-1`. + - A list of `n` permutations of size `n-1`. + - A list of `\binom n 2` transpositions + - A Felsner matrix, given as a sequence of `n` binary vectors of + length `n-1`. - ``encoding`` (information on how the data should be interpreted), and can assume any value among 'transpositions', 'permutations', 'Felsner' @@ -188,7 +190,7 @@ def __init__(self, seq, encoding="auto"): .. NOTE:: - * The pseudolines are assumed to be integers `0..(n-1)`. + * The pseudolines are assumed to be integers `0,\dots,n-1`. * For more information on the different encodings, see the :mod:`pseudolines module <sage.geometry.pseudolines>`'s @@ -417,14 +419,14 @@ def show(self, **args): sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p = PseudolineArrangement(permutations) - sage: p.show(figsize=[7,5]) + sage: p.show(figsize=[7,5]) # needs sage.plot TESTS:: sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 0, 1], [2, 0, 1]] sage: p = PseudolineArrangement(permutations) - sage: p.show() + sage: p.show() # needs sage.plot Traceback (most recent call last): ... ValueError: There has been a problem while plotting the figure... diff --git a/src/sage/geometry/relative_interior.py b/src/sage/geometry/relative_interior.py index 262c927a08a..8f4a63a8a14 100644 --- a/src/sage/geometry/relative_interior.py +++ b/src/sage/geometry/relative_interior.py @@ -324,11 +324,11 @@ def __eq__(self, other): sage: ri_segment = segment.relative_interior(); ri_segment Relative interior of a 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices - sage: segment2 = Polyhedron([[1, 2], [3, 4]], base_ring=AA) - sage: ri_segment2 = segment2.relative_interior(); ri_segment2 + sage: segment2 = Polyhedron([[1, 2], [3, 4]], base_ring=AA) # needs sage.rings.number_field + sage: ri_segment2 = segment2.relative_interior(); ri_segment2 # needs sage.rings.number_field Relative interior of a 1-dimensional polyhedron in AA^2 defined as the convex hull of 2 vertices - sage: ri_segment == ri_segment2 + sage: ri_segment == ri_segment2 # needs sage.rings.number_field True TESTS:: @@ -337,7 +337,7 @@ def __eq__(self, other): sage: ri_segment == empty False """ - if type(self) != type(other): + if type(self) is not type(other): return False return self._polyhedron == other._polyhedron @@ -355,11 +355,11 @@ def __ne__(self, other): sage: ri_segment = segment.relative_interior(); ri_segment Relative interior of a 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices - sage: segment2 = Polyhedron([[1, 2], [3, 4]], base_ring=AA) - sage: ri_segment2 = segment2.relative_interior(); ri_segment2 + sage: segment2 = Polyhedron([[1, 2], [3, 4]], base_ring=AA) # needs sage.rings.number_field + sage: ri_segment2 = segment2.relative_interior(); ri_segment2 # needs sage.rings.number_field Relative interior of a 1-dimensional polyhedron in AA^2 defined as the convex hull of 2 vertices - sage: ri_segment != ri_segment2 + sage: ri_segment != ri_segment2 # needs sage.rings.number_field False """ return not (self == other) diff --git a/src/sage/geometry/ribbon_graph.py b/src/sage/geometry/ribbon_graph.py index 6cc269c6b99..809d6edba9a 100644 --- a/src/sage/geometry/ribbon_graph.py +++ b/src/sage/geometry/ribbon_graph.py @@ -956,19 +956,19 @@ def homology_basis(self): [[25, 26]], [[27, 28]]] """ - aux_sigma = [list(x) for x in self._sigma.cycle_tuples(singletons=True)] + aux_sigma = [list(x) for x in self._sigma.cycle_tuples(singletons=True)] basis = [[list(x)] for x in self.reduced()._rho.cycle_tuples()] - #Now we define center as the set of edges that were contracted - #in reduced() this set is contractible and can be define as the - #complement of reduced_rho in rho + # Now we define center as the set of edges that were contracted + # in reduced() this set is contractible and can be define as the + # complement of reduced_rho in rho center = [list(x) for x in self._rho.cycle_tuples() if (x not in self.reduced()._rho.cycle_tuples())] - #We define an auxiliary list 'vertices' that will contain the - #vertices (cycles of sigma) corresponding to each half edge. + # We define an auxiliary list 'vertices' that will contain the + # vertices (cycles of sigma) corresponding to each half edge. vertices = [] @@ -1221,7 +1221,7 @@ def bipartite_ribbon_graph(p, q): elif (i+1) % q != 0: k = (i+1) % q t = 0 - if (i+1) % q != 0: + if (i+1) % q != 0: t = 1 aux_edge = [i+1, p*q + k*p - ((i+1 + t*q)/q).floor() +1] rho += [aux_edge] diff --git a/src/sage/geometry/riemannian_manifolds/__init__.py b/src/sage/geometry/riemannian_manifolds/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py index e1021f66a97..c0161ab0c4f 100644 --- a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py +++ b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py @@ -85,7 +85,8 @@ class ParametrizedSurface3D(SageObject): explicitly specifying its parametric equation:: sage: u, v = var('u,v', domain='real') - sage: eparaboloid = ParametrizedSurface3D((u, v, u^2 + v^2), (u, v),'elliptic paraboloid'); eparaboloid + sage: eparaboloid = ParametrizedSurface3D((u, v, u^2 + v^2), (u, v), + ....: 'elliptic paraboloid'); eparaboloid Parametrized surface ('elliptic paraboloid') with equation (u, v, u^2 + v^2) When the ranges for the intrinsic coordinates are known, they can be @@ -96,19 +97,24 @@ class ParametrizedSurface3D(SageObject): sage: coords = ((u1, -pi/2, pi/2), (u2, 0, pi)) sage: ellipsoid_eq = (cos(u1)*cos(u2), 2*sin(u1)*cos(u2), 3*sin(u2)) sage: ellipsoid = ParametrizedSurface3D(ellipsoid_eq, coords, 'ellipsoid'); ellipsoid - Parametrized surface ('ellipsoid') with equation (cos(u1)*cos(u2), 2*cos(u2)*sin(u1), 3*sin(u2)) - sage: ellipsoid.plot() # optional - sage.plot + Parametrized surface ('ellipsoid') with equation + (cos(u1)*cos(u2), 2*cos(u2)*sin(u1), 3*sin(u2)) + sage: ellipsoid.plot() # needs sage.plot Graphics3d Object Standard surfaces can be constructed using the ``surfaces`` generator:: sage: klein = surfaces.Klein(); klein - Parametrized surface ('Klein bottle') with equation (-(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*cos(u), -(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*sin(u), cos(1/2*u)*sin(2*v) + sin(1/2*u)*sin(v)) + Parametrized surface ('Klein bottle') with equation + (-(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*cos(u), + -(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*sin(u), + cos(1/2*u)*sin(2*v) + sin(1/2*u)*sin(v)) Latex representation of the surfaces:: sage: u, v = var('u, v', domain='real') - sage: sphere = ParametrizedSurface3D((cos(u)*cos(v), sin(u)*cos(v), sin(v)), (u, v), 'sphere') + sage: sphere = ParametrizedSurface3D((cos(u)*cos(v), sin(u)*cos(v), sin(v)), (u, v), + ....: 'sphere') sage: print(latex(sphere)) \left(\cos\left(u\right) \cos\left(v\right), \cos\left(v\right) \sin\left(u\right), \sin\left(v\right)\right) sage: print(sphere._latex_()) @@ -119,8 +125,9 @@ class ParametrizedSurface3D(SageObject): To plot a parametric surface, use the :meth:`plot` member function:: sage: enneper = surfaces.Enneper(); enneper - Parametrized surface ('Enneper's surface') with equation (-1/9*(u^2 - 3*v^2 - 3)*u, -1/9*(3*u^2 - v^2 + 3)*v, 1/3*u^2 - 1/3*v^2) - sage: enneper.plot(aspect_ratio='automatic') # optional - sage.plot + Parametrized surface ('Enneper's surface') with equation + (-1/9*(u^2 - 3*v^2 - 3)*u, -1/9*(3*u^2 - v^2 + 3)*v, 1/3*u^2 - 1/3*v^2) + sage: enneper.plot(aspect_ratio='automatic') # needs sage.plot Graphics3d Object We construct an ellipsoid whose axes are given by symbolic variables `a`, @@ -131,11 +138,14 @@ class ParametrizedSurface3D(SageObject): sage: a, b, c = var('a, b, c', domain='real') sage: u1, u2 = var('u1, u2', domain='real') sage: ellipsoid_eq = (a*cos(u1)*cos(u2), b*sin(u1)*cos(u2), c*sin(u2)) - sage: ellipsoid = ParametrizedSurface3D(ellipsoid_eq, (u1, u2), 'Symbolic ellipsoid'); ellipsoid - Parametrized surface ('Symbolic ellipsoid') with equation (a*cos(u1)*cos(u2), b*cos(u2)*sin(u1), c*sin(u2)) + sage: ellipsoid = ParametrizedSurface3D(ellipsoid_eq, (u1, u2), + ....: 'Symbolic ellipsoid'); ellipsoid + Parametrized surface ('Symbolic ellipsoid') with equation + (a*cos(u1)*cos(u2), b*cos(u2)*sin(u1), c*sin(u2)) sage: ellipsoid.natural_frame() - {1: (-a*cos(u2)*sin(u1), b*cos(u1)*cos(u2), 0), 2: (-a*cos(u1)*sin(u2), -b*sin(u1)*sin(u2), c*cos(u2))} + {1: (-a*cos(u2)*sin(u1), b*cos(u1)*cos(u2), 0), + 2: (-a*cos(u1)*sin(u2), -b*sin(u1)*sin(u2), c*cos(u2))} We find the normal vector field to the surface. The normal vector field is the vector product of the vectors of the natural frame, @@ -148,7 +158,8 @@ class ParametrizedSurface3D(SageObject): the unit normal vector field of the elliptic paraboloid, we put:: sage: u, v = var('u,v', domain='real') - sage: eparaboloid = ParametrizedSurface3D([u,v,u^2+v^2],[u,v],'elliptic paraboloid') + sage: eparaboloid = ParametrizedSurface3D([u, v, u^2 + v^2], [u,v], + ....: 'elliptic paraboloid') sage: eparaboloid.normal_vector(normalized=True) (-2*u/sqrt(4*u^2 + 4*v^2 + 1), -2*v/sqrt(4*u^2 + 4*v^2 + 1), 1/sqrt(4*u^2 + 4*v^2 + 1)) @@ -156,7 +167,9 @@ class ParametrizedSurface3D(SageObject): sage: u, v = var('u, v', domain='real') sage: a, b = var('a, b', domain='real') - sage: torus = ParametrizedSurface3D(((a + b*cos(u))*cos(v),(a + b*cos(u))*sin(v), b*sin(u)),[u,v],'torus') + sage: torus = ParametrizedSurface3D(((a + b*cos(u))*cos(v), + ....: (a + b*cos(u))*sin(v), + ....: b*sin(u)), [u,v], 'torus') sage: torus.first_fundamental_form_coefficients() {(1, 1): b^2, (1, 2): 0, (2, 1): 0, (2, 2): b^2*cos(u)^2 + 2*a*b*cos(u) + a^2} @@ -179,7 +192,7 @@ class ParametrizedSurface3D(SageObject): Once we specify numerical values for the axes of the ellipsoid, we can determine the numerical value of the length integral:: - sage: L = sqrt(ellipsoid.first_fundamental_form(du, du).substitute(u1=u1,u2=u2)) + sage: L = sqrt(ellipsoid.first_fundamental_form(du, du).substitute(u1=u1, u2=u2)) sage: numerical_integral(L.substitute(a=2, b=1.5, c=1),0,1)[0] # rel tol 1e-11 2.00127905972 @@ -189,8 +202,9 @@ class ParametrizedSurface3D(SageObject): sage: u, v = var('u,v', domain='real') sage: assume(R>0) sage: assume(cos(v)>0) - sage: sphere = ParametrizedSurface3D([R*cos(u)*cos(v),R*sin(u)*cos(v),R*sin(v)],[u,v],'sphere') - sage: integral(integral(sphere.area_form(),u,0,2*pi),v,-pi/2,pi/2) + sage: sphere = ParametrizedSurface3D([R*cos(u)*cos(v), R*sin(u)*cos(v), R*sin(v)], + ....: [u,v], 'sphere') + sage: integral(integral(sphere.area_form(), u, 0, 2*pi), v, -pi/2, pi/2) 4*pi*R^2 We can find an orthonormal frame field `\{e_1, e_2\}` of a surface @@ -198,9 +212,13 @@ class ParametrizedSurface3D(SageObject): orthonormal frame field for the elliptic paraboloid:: sage: u, v = var('u,v', domain='real') - sage: eparaboloid = ParametrizedSurface3D([u,v,u^2+v^2],[u,v],'elliptic paraboloid') + sage: eparaboloid = ParametrizedSurface3D([u, v, u^2 + v^2], [u,v], + ....: 'elliptic paraboloid') sage: eparaboloid.orthonormal_frame() - {1: (1/sqrt(4*u^2 + 1), 0, 2*u/sqrt(4*u^2 + 1)), 2: (-4*u*v/(sqrt(4*u^2 + 4*v^2 + 1)*sqrt(4*u^2 + 1)), sqrt(4*u^2 + 1)/sqrt(4*u^2 + 4*v^2 + 1), 2*v/(sqrt(4*u^2 + 4*v^2 + 1)*sqrt(4*u^2 + 1)))} + {1: (1/sqrt(4*u^2 + 1), 0, 2*u/sqrt(4*u^2 + 1)), + 2: (-4*u*v/(sqrt(4*u^2 + 4*v^2 + 1)*sqrt(4*u^2 + 1)), + sqrt(4*u^2 + 1)/sqrt(4*u^2 + 4*v^2 + 1), + 2*v/(sqrt(4*u^2 + 4*v^2 + 1)*sqrt(4*u^2 + 1)))} We can express the orthogonal frame field both in exterior coordinates (i.e. expressed as vector field fields in the ambient @@ -209,7 +227,9 @@ class ParametrizedSurface3D(SageObject): coordinates:: sage: eparaboloid.orthonormal_frame(coordinates='int') - {1: (1/sqrt(4*u^2 + 1), 0), 2: (-4*u*v/(sqrt(4*u^2 + 4*v^2 + 1)*sqrt(4*u^2 + 1)), sqrt(4*u^2 + 1)/sqrt(4*u^2 + 4*v^2 + 1))} + {1: (1/sqrt(4*u^2 + 1), 0), + 2: (-4*u*v/(sqrt(4*u^2 + 4*v^2 + 1)*sqrt(4*u^2 + 1)), + sqrt(4*u^2 + 1)/sqrt(4*u^2 + 4*v^2 + 1))} Using the orthonormal frame in interior coordinates, we can calculate the structure functions `c^k_{ij}` of the surface, defined by @@ -227,18 +247,19 @@ class ParametrizedSurface3D(SageObject): sage: sphere = surfaces.Sphere(); sphere Parametrized surface ('Sphere') with equation (cos(u)*cos(v), cos(v)*sin(u), sin(v)) - sage: K = sphere.gauss_curvature(); K # Not tested -- see trac 12737 + sage: K = sphere.gauss_curvature(); K # Not tested -- see trac 12737 1 - sage: H = sphere.mean_curvature(); H # Not tested -- see trac 12737 + sage: H = sphere.mean_curvature(); H # Not tested -- see trac 12737 -1 We can easily generate a color plot of the Gaussian curvature of a surface. Here we deal with the ellipsoid:: + sage: # needs numpy sage: u1, u2 = var('u1,u2', domain='real') sage: u = [u1,u2] sage: ellipsoid_equation(u1,u2) = [2*cos(u1)*cos(u2),1.5*cos(u1)*sin(u2),sin(u1)] - sage: ellipsoid = ParametrizedSurface3D(ellipsoid_equation(u1,u2), [u1, u2],'ellipsoid') + sage: ellipsoid = ParametrizedSurface3D(ellipsoid_equation(u1,u2), [u1, u2], 'ellipsoid') sage: # set intervals for variables and the number of division points sage: u1min, u1max = -1.5, 1.5 sage: u2min, u2max = 0, 6.28 @@ -247,7 +268,7 @@ class ParametrizedSurface3D(SageObject): sage: from numpy import linspace sage: u1_array = linspace(u1min, u1max, u1num) sage: u2_array = linspace(u2min, u2max, u2num) - sage: u_array = [ (uu1,uu2) for uu1 in u1_array for uu2 in u2_array] + sage: u_array = [(uu1,uu2) for uu1 in u1_array for uu2 in u2_array] sage: # Find the gaussian curvature sage: K(u1,u2) = ellipsoid.gauss_curvature() sage: # Make array of K values @@ -256,36 +277,39 @@ class ParametrizedSurface3D(SageObject): sage: K_max = max(K_array) sage: K_min = min(K_array) sage: # Make the array of color coefficients - sage: cc_array = [ (ccc - K_min)/(K_max - K_min) for ccc in K_array ] - sage: points_array = [ellipsoid_equation(u_array[counter][0],u_array[counter][1]) for counter in range(0,len(u_array)) ] - sage: curvature_ellipsoid_plot = sum( point([xx for xx in points_array[counter]],color=hue(cc_array[counter]/2)) for counter in range(0,len(u_array)) ) - sage: curvature_ellipsoid_plot.show(aspect_ratio=1) + sage: cc_array = [(ccc - K_min)/(K_max - K_min) for ccc in K_array] + sage: points_array = [ellipsoid_equation(u_array[counter][0], + ....: u_array[counter][1]) + ....: for counter in range(0,len(u_array))] + sage: curvature_ellipsoid_plot = sum(point([xx # needs sage.plot + ....: for xx in points_array[counter]], + ....: color=hue(cc_array[counter]/2)) + ....: for counter in range(0,len(u_array))) + sage: curvature_ellipsoid_plot.show(aspect_ratio=1) # needs sage.plot We can find the principal curvatures and principal directions of the elliptic paraboloid:: sage: u, v = var('u, v', domain='real') - sage: eparaboloid = ParametrizedSurface3D([u, v, u^2+v^2], [u, v], 'elliptic paraboloid') + sage: eparaboloid = ParametrizedSurface3D([u, v, u^2+v^2], [u, v], + ....: 'elliptic paraboloid') sage: pd = eparaboloid.principal_directions(); pd - [(2*sqrt(4*u^2 + 4*v^2 + 1)/(16*u^4 + 16*v^4 + 8*(4*u^2 + 1)*v^2 + 8*u^2 + 1), [(1, v/u)], 1), (2/sqrt(4*u^2 + 4*v^2 + 1), [(1, -u/v)], 1)] + [(2*sqrt(4*u^2 + 4*v^2 + 1)/(16*u^4 + 16*v^4 + 8*(4*u^2 + 1)*v^2 + 8*u^2 + 1), [(1, v/u)], 1), + (2/sqrt(4*u^2 + 4*v^2 + 1), [(1, -u/v)], 1)] We extract the principal curvatures:: - sage: k1 = pd[0][0].simplify_full() - sage: k1 + sage: k1 = pd[0][0].simplify_full(); k1 2*sqrt(4*u^2 + 4*v^2 + 1)/(16*u^4 + 16*v^4 + 8*(4*u^2 + 1)*v^2 + 8*u^2 + 1) - sage: k2 = pd[1][0].simplify_full() - sage: k2 + sage: k2 = pd[1][0].simplify_full(); k2 2/sqrt(4*u^2 + 4*v^2 + 1) and check them by comparison with the Gaussian and mean curvature expressed in terms of the principal curvatures:: - sage: K = eparaboloid.gauss_curvature().simplify_full() - sage: K + sage: K = eparaboloid.gauss_curvature().simplify_full(); K 4/(16*u^4 + 16*v^4 + 8*(4*u^2 + 1)*v^2 + 8*u^2 + 1) - sage: H = eparaboloid.mean_curvature().simplify_full() - sage: H + sage: H = eparaboloid.mean_curvature().simplify_full(); H 2*(2*u^2 + 2*v^2 + 1)/(4*u^2 + 4*v^2 + 1)^(3/2) sage: (K - k1*k2).simplify_full() 0 @@ -311,14 +335,18 @@ class ParametrizedSurface3D(SageObject): that these points are conjugate:: sage: S = surfaces.Sphere() - sage: g1 = [c[-1] for c in S.geodesics_numerical((0,0),(1,0),(0,2*pi,100))] - sage: g2 = [c[-1] for c in S.geodesics_numerical((0,0),(cos(pi/3),sin(pi/3)),(0,2*pi,100))] - sage: g3 = [c[-1] for c in S.geodesics_numerical((0,0),(cos(2*pi/3),sin(2*pi/3)),(0,2*pi,100))] - sage: (S.plot(opacity=0.3) + line3d(g1,color='red') + line3d(g2,color='red') + line3d(g3,color='red')).show() # optional - sage.plot + sage: g1 = [c[-1] for c in S.geodesics_numerical((0,0), (1,0), (0,2*pi,100))] + sage: g2 = [c[-1] for c in S.geodesics_numerical((0,0), + ....: (cos(pi/3),sin(pi/3)), + ....: (0,2*pi,100))] + sage: g3 = [c[-1] for c in S.geodesics_numerical((0,0), + ....: (cos(2*pi/3),sin(2*pi/3)), + ....: (0,2*pi,100))] + sage: (S.plot(opacity=0.3) + line3d(g1, color='red') # needs sage.plot + ....: + line3d(g2, color='red') + line3d(g3, color='red')).show() """ - def __init__(self, equation, variables, name=None): r""" See ``ParametrizedSurface3D`` for full documentation. @@ -336,7 +364,8 @@ def __init__(self, equation, variables, name=None): sage: u, v = var('u,v', domain='real') sage: eq = (3*u + 3*u*v^2 - u^3, 3*v + 3*u^2*v - v^3, 3*(u^2-v^2)) sage: enneper = ParametrizedSurface3D(eq, (u, v),'Enneper Surface'); enneper - Parametrized surface ('Enneper Surface') with equation (-u^3 + 3*u*v^2 + 3*u, 3*u^2*v - v^3 + 3*v, 3*u^2 - 3*v^2) + Parametrized surface ('Enneper Surface') with equation + (-u^3 + 3*u*v^2 + 3*u, 3*u^2*v - v^3 + 3*v, 3*u^2 - 3*v^2) """ self.equation = tuple(equation) @@ -368,7 +397,6 @@ def _latex_(self): from sage.misc.latex import latex return latex(self.equation) - def _repr_(self): r""" Returns the string representation of this parametrized surface. @@ -391,7 +419,6 @@ def _repr_(self): {'designation': name, 'eq': str(self.equation)} return s - def point(self, coords): r""" Returns a point on the surface given its intrinsic coordinates. @@ -407,7 +434,9 @@ def point(self, coords): EXAMPLES:: sage: u, v = var('u, v', domain='real') - sage: torus = ParametrizedSurface3D(((2 + cos(u))*cos(v),(2 + cos(u))*sin(v), sin(u)),[u,v],'torus') + sage: torus = ParametrizedSurface3D(((2 + cos(u))*cos(v), + ....: (2 + cos(u))*sin(v), + ....: sin(u)), [u,v], 'torus') sage: torus.point((0, pi/2)) (0, 3, 0) sage: torus.point((pi/2, pi)) @@ -420,7 +449,6 @@ def point(self, coords): d = dict(zip(self.variables_list, coords)) return vector([f.subs(d) for f in self.equation]) - def tangent_vector(self, coords, components): r""" Returns the components of a tangent vector given the intrinsic @@ -445,7 +473,7 @@ def tangent_vector(self, coords, components): sage: u, v = var('u,v', domain='real') sage: eq = (3*u + 3*u*v^2 - u^3, 3*v + 3*u^2*v - v^3, 3*(u^2-v^2)) - sage: e = ParametrizedSurface3D(eq, (u, v),'Enneper Surface') + sage: e = ParametrizedSurface3D(eq, (u, v), 'Enneper Surface') sage: w1 = e.tangent_vector((1, 2), (1, 0)); w1 (12, 12, 6) @@ -467,7 +495,6 @@ def tangent_vector(self, coords, components): for f in self.equation]) return jacobian * components - def plot(self, urange=None, vrange=None, **kwds): r""" Enable easy plotting directly from the surface class. @@ -488,7 +515,7 @@ def plot(self, urange=None, vrange=None, **kwds): sage: u, v = var('u, v', domain='real') sage: eq = (3*u + 3*u*v^2 - u^3, 3*v + 3*u^2*v - v^3, 3*(u^2-v^2)) sage: enneper = ParametrizedSurface3D(eq, (u, v), 'Enneper Surface') - sage: enneper.plot((-5, 5), (-5, 5)) # optional - sage.plot + sage: enneper.plot((-5, 5), (-5, 5)) # needs sage.plot Graphics3d Object """ @@ -512,7 +539,6 @@ def plot(self, urange=None, vrange=None, **kwds): return P - @cached_method def natural_frame(self): """ @@ -527,7 +553,8 @@ def natural_frame(self): EXAMPLES:: sage: u, v = var('u, v', domain='real') - sage: eparaboloid = ParametrizedSurface3D((u, v, u^2+v^2), (u, v), 'elliptic paraboloid') + sage: eparaboloid = ParametrizedSurface3D((u, v, u^2+v^2), (u, v), + ....: 'elliptic paraboloid') sage: eparaboloid.natural_frame() {1: (1, 0, 2*u), 2: (0, 1, 2*v)} """ @@ -541,7 +568,6 @@ def natural_frame(self): return {1:dr1, 2:dr2} - @cached_method def normal_vector(self, normalized=False): """ @@ -558,11 +584,14 @@ def normal_vector(self, normalized=False): EXAMPLES:: sage: u, v = var('u, v', domain='real') - sage: eparaboloid = ParametrizedSurface3D((u, v, u^2 + v^2), (u, v), 'elliptic paraboloid') + sage: eparaboloid = ParametrizedSurface3D((u, v, u^2 + v^2), (u, v), + ....: 'elliptic paraboloid') sage: eparaboloid.normal_vector(normalized=False) (-2*u, -2*v, 1) sage: eparaboloid.normal_vector(normalized=True) - (-2*u/sqrt(4*u^2 + 4*v^2 + 1), -2*v/sqrt(4*u^2 + 4*v^2 + 1), 1/sqrt(4*u^2 + 4*v^2 + 1)) + (-2*u/sqrt(4*u^2 + 4*v^2 + 1), + -2*v/sqrt(4*u^2 + 4*v^2 + 1), + 1/sqrt(4*u^2 + 4*v^2 + 1)) """ @@ -573,7 +602,6 @@ def normal_vector(self, normalized=False): normal /= normal.norm() return _simplify_full_rad(normal) - @cached_method def _compute_first_fundamental_form_coefficient(self, index): """ @@ -594,7 +622,6 @@ def _compute_first_fundamental_form_coefficient(self, index): dr = self.natural_frame() return _simplify_full_rad(dr[index[0]]*dr[index[1]]) - def first_fundamental_form_coefficient(self, index): r""" Compute a single component `g_{ij}` of the first fundamental form. If @@ -692,7 +719,6 @@ def first_fundamental_form(self, vector1, vector2): return sum(gamma[(i,j)] * vector1[i - 1] * vector2[j - 1] for i, j in product((1, 2), repeat=2)) - def area_form_squared(self): """ Returns the square of the coefficient of the area form on the surface. @@ -718,7 +744,6 @@ def area_form_squared(self): sq = gamma[(1,1)] * gamma[(2,2)] - gamma[(1,2)]**2 return _simplify_full_rad(sq) - def area_form(self): r""" Returns the coefficient of the area form on the surface. In terms of @@ -743,7 +768,6 @@ def area_form(self): f = abs(sqrt(self.area_form_squared())) return _simplify_full_rad(f) - def first_fundamental_form_inverse_coefficients(self): r""" Returns the coefficients `g^{ij}` of the inverse of the fundamental @@ -774,7 +798,6 @@ def first_fundamental_form_inverse_coefficients(self): return {(1,1): gi11, (1,2): gi12, (2,1): gi21, (2,2): gi22} - def first_fundamental_form_inverse_coefficient(self, index): r""" Returns a specific component `g^{ij}` of the inverse of the fundamental @@ -805,8 +828,6 @@ def first_fundamental_form_inverse_coefficient(self, index): else: raise ValueError("Index %s out of bounds." % str(index)) - - @cached_method def rotation(self,theta): r""" @@ -857,7 +878,6 @@ def rotation(self,theta): R22 = (cos(theta) - sin(theta)*gi[2,1]*w12).simplify_full() return matrix([[R11,R12],[R21,R22]]) - @cached_method def orthonormal_frame(self, coordinates='ext'): r""" @@ -905,28 +925,24 @@ def orthonormal_frame(self, coordinates='ext'): 0 sage: sphere.first_fundamental_form(frame_int[2], frame_int[2]) 1 - """ - - from sage.symbolic.constants import pi if coordinates not in ['ext', 'int']: raise ValueError("Coordinate system must be exterior ('ext') " "or interior ('int').") - c = self.first_fundamental_form_coefficient([1,1]) + c = self.first_fundamental_form_coefficient([1, 1]) if coordinates == 'ext': f1 = self.natural_frame()[1] - E1 = _simplify_full_rad(f1/sqrt(c)) + E1 = _simplify_full_rad(f1 / sqrt(c)) E2 = _simplify_full_rad( self.normal_vector(normalized=True).cross_product(E1)) else: - E1 = vector([_simplify_full_rad(1/sqrt(c)), 0]) - E2 = (self.rotation(pi/2)*E1).simplify_full() - return {1:E1, 2:E2} - + E1 = vector([_simplify_full_rad(1 / sqrt(c)), 0]) + E2 = (self.rotation(pi / 2) * E1).simplify_full() + return {1: E1, 2: E2} def orthonormal_frame_vector(self, index, coordinates='ext'): r""" @@ -964,7 +980,6 @@ def orthonormal_frame_vector(self, index, coordinates='ext'): return self.orthonormal_frame(coordinates)[index] - def lie_bracket(self, v, w): r""" Returns the Lie bracket of two vector fields that are tangent @@ -1003,7 +1018,6 @@ def lie_bracket(self, v, w): for u in variables] for component in w]) return vector(Dv*w - Dw*v).simplify_full() - def frame_structure_functions(self, e1, e2): r""" Returns the structure functions `c^k_{ij}` for a frame field @@ -1065,7 +1079,6 @@ def frame_structure_functions(self, e1, e2): return {(1,1,1): 0, (1,1,2): 0, (1,2,1): w[0], (1,2,2): w[1], (2,1,1): -w[0], (2,1,2): -w[1], (2,2,1): 0, (2,2,2): 0} - @cached_method def _compute_second_order_frame_element(self, index): """ @@ -1091,7 +1104,6 @@ def _compute_second_order_frame_element(self, index): return ddr_element - def second_order_natural_frame(self): r""" Returns the second-order frame of the surface, i.e. computes the @@ -1124,7 +1136,6 @@ def second_order_natural_frame(self): self._compute_second_order_frame_element(sorted_index) return vectors - def second_order_natural_frame_element(self, index): r""" Returns a vector in the second-order frame of the surface, i.e. @@ -1176,7 +1187,6 @@ def _compute_second_fundamental_form_coefficient(self, index): v = self.second_order_natural_frame_element(index) return _simplify_full_rad(v*N) - def second_fundamental_form_coefficient(self, index): r""" Returns the coefficient `h_{ij}` of the second fundamental form @@ -1209,7 +1219,6 @@ def second_fundamental_form_coefficient(self, index): else: raise ValueError("Index %s out of bounds." % str(index)) - def second_fundamental_form_coefficients(self): """ Returns the coefficients `h_{ij}` of the second fundamental form as @@ -1239,7 +1248,6 @@ def second_fundamental_form_coefficients(self): self._compute_second_fundamental_form_coefficient(index) return coefficients - def second_fundamental_form(self,vector1,vector2): r""" Evaluates the second fundamental form on two vectors on the surface. @@ -1279,7 +1287,6 @@ def second_fundamental_form(self,vector1,vector2): return sum(hh[(i, j)] * vector1[i - 1] * vector2[j - 1] for (i, j) in product((1, 2), repeat=2)) - def gauss_curvature(self): r""" Finds the gaussian curvature of the surface, given by @@ -1306,7 +1313,6 @@ def gauss_curvature(self): return _simplify_full_rad( (hh[(1,1)] * hh[(2,2)] - hh[(1,2)]**2)/self.area_form_squared()) - def mean_curvature(self): r""" Finds the mean curvature of the surface, given by @@ -1336,7 +1342,6 @@ def mean_curvature(self): gg[(1,1)]*hh[(2,2)]).simplify_full() return _simplify_full_rad(numer/denom) - @cached_method def shape_operator_coefficients(self): r""" @@ -1369,7 +1374,6 @@ def shape_operator_coefficients(self): return {(1,1): sh_op11, (1,2): sh_op12, (2,1): sh_op21, (2,2): sh_op22} - def shape_operator(self): r""" Returns the shape operator of the surface as a matrix. The shape @@ -1410,7 +1414,6 @@ def shape_operator(self): [shop[(2,1)],shop[(2,2)]]]) return shop_matrix - def principal_directions(self): r""" Finds the principal curvatures and principal directions of the surface @@ -1445,7 +1448,6 @@ def principal_directions(self): """ return self.shape_operator().eigenvectors_right() - @cached_method def connection_coefficients(self): r""" @@ -1498,7 +1500,6 @@ def connection_coefficients(self): structfun[(i,j,k)] = _simplify_full_rad(structfun[(i,j,k)]) return structfun - @cached_method def _create_geodesic_ode_system(self): r""" @@ -1535,7 +1536,6 @@ def _create_geodesic_ode_system(self): [u1_u2_v1_v2[2], u1_u2_v1_v2[3], fun1(*u1_u2_v1_v2), fun2(*u1_u2_v1_v2)]) return geodesic_ode - def geodesics_numerical(self, p0, v0, tinterval): r""" Numerical integration of the geodesic equations. Explicitly, the @@ -1601,7 +1601,6 @@ def geodesics_numerical(self, p0, v0, tinterval): return parsed_solution - @cached_method def _create_pt_ode_system(self, curve, t): """ @@ -1650,7 +1649,6 @@ def _create_pt_ode_system(self, curve, t): pt_ode.function = lambda t, v1_v2: [fun1(t, v1_v2[0], v1_v2[1]), fun2(t, v1_v2[0], v1_v2[1])] return pt_ode - def parallel_translation_numerical(self,curve,t,v0,tinterval): r""" Numerically solves the equations for parallel translation of a vector diff --git a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py index 3619c6c2952..ba8eff2ed2a 100644 --- a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py +++ b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py @@ -53,7 +53,7 @@ def Catenoid(c=1, name="Catenoid"): sage: cat = surfaces.Catenoid(); cat Parametrized surface ('Catenoid') with equation (cos(u)*cosh(v), cosh(v)*sin(u), v) - sage: cat.plot() # optional - sage.plot + sage: cat.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -86,7 +86,7 @@ def Crosscap(r=1, name="Crosscap"): sage: crosscap = surfaces.Crosscap(); crosscap Parametrized surface ('Crosscap') with equation ((cos(v) + 1)*cos(u), (cos(v) + 1)*sin(u), -sin(v)*tanh(-pi + u)) - sage: crosscap.plot() # optional - sage.plot + sage: crosscap.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -120,7 +120,7 @@ def Dini(a=1, b=1, name="Dini's surface"): sage: dini = surfaces.Dini(a=3, b=4); dini Parametrized surface ('Dini's surface') with equation (3*cos(u)*sin(v), 3*sin(u)*sin(v), 4*u + 3*cos(v) + 3*log(tan(1/2*v))) - sage: dini.plot() # optional - sage.plot + sage: dini.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -158,7 +158,7 @@ def Ellipsoid(center=(0, 0, 0), axes=(1, 1, 1), name="Ellipsoid"): sage: ell = surfaces.Ellipsoid(axes=(1, 2, 3)); ell Parametrized surface ('Ellipsoid') with equation (cos(u)*cos(v), 2*cos(v)*sin(u), 3*sin(v)) - sage: ell.plot() # optional - sage.plot + sage: ell.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -193,7 +193,7 @@ def Enneper(name="Enneper's surface"): sage: enn = surfaces.Enneper(); enn Parametrized surface ('Enneper's surface') with equation (-1/9*(u^2 - 3*v^2 - 3)*u, -1/9*(3*u^2 - v^2 + 3)*v, 1/3*u^2 - 1/3*v^2) - sage: enn.plot() # optional - sage.plot + sage: enn.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -227,7 +227,7 @@ def Helicoid(h=1, name="Helicoid"): sage: helicoid = surfaces.Helicoid(h=2); helicoid Parametrized surface ('Helicoid') with equation (rho*cos(theta), rho*sin(theta), theta/pi) - sage: helicoid.plot() # optional - sage.plot + sage: helicoid.plot() # needs sage.plot Graphics3d Object """ rho, theta = var('rho, theta') @@ -260,7 +260,7 @@ def Klein(r=1, name="Klein bottle"): sage: klein = surfaces.Klein(); klein Parametrized surface ('Klein bottle') with equation (-(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*cos(u), -(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*sin(u), cos(1/2*u)*sin(2*v) + sin(1/2*u)*sin(v)) - sage: klein.plot() # optional - sage.plot + sage: klein.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -291,7 +291,7 @@ def MonkeySaddle(name="Monkey saddle"): sage: saddle = surfaces.MonkeySaddle(); saddle Parametrized surface ('Monkey saddle') with equation (u, v, u^3 - 3*u*v^2) - sage: saddle.plot() # optional - sage.plot + sage: saddle.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -327,12 +327,12 @@ def Paraboloid(a=1, b=1, c=1, elliptic=True, name=None): sage: epar = surfaces.Paraboloid(1, 3, 2); epar Parametrized surface ('Elliptic paraboloid') with equation (u, v, 2*u^2 + 2/9*v^2) - sage: epar.plot() # optional - sage.plot + sage: epar.plot() # needs sage.plot Graphics3d Object sage: hpar = surfaces.Paraboloid(2, 3, 1, elliptic=False); hpar Parametrized surface ('Hyperbolic paraboloid') with equation (u, v, -1/4*u^2 + 1/9*v^2) - sage: hpar.plot() # optional - sage.plot + sage: hpar.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -372,7 +372,7 @@ def Sphere(center=(0, 0, 0), R=1, name="Sphere"): sage: sphere = surfaces.Sphere(center=(0, 1, -1), R=2); sphere Parametrized surface ('Sphere') with equation (2*cos(u)*cos(v), 2*cos(v)*sin(u) + 1, 2*sin(v) - 1) - sage: sphere.plot() # optional - sage.plot + sage: sphere.plot() # needs sage.plot Graphics3d Object Note that the radius of the sphere can be negative. The surface thus @@ -382,14 +382,14 @@ def Sphere(center=(0, 0, 0), R=1, name="Sphere"): sage: octant1 = surfaces.Sphere(R=1); octant1 Parametrized surface ('Sphere') with equation (cos(u)*cos(v), cos(v)*sin(u), sin(v)) - sage: octant1.plot((0, pi/2), (0, pi/2)) # optional - sage.plot + sage: octant1.plot((0, pi/2), (0, pi/2)) # needs sage.plot Graphics3d Object with the first octant of the unit sphere with negative radius:: sage: octant2 = surfaces.Sphere(R=-1); octant2 Parametrized surface ('Sphere') with equation (-cos(u)*cos(v), -cos(v)*sin(u), -sin(v)) - sage: octant2.plot((0, pi/2), (0, pi/2)) # optional - sage.plot + sage: octant2.plot((0, pi/2), (0, pi/2)) # needs sage.plot Graphics3d Object """ return SurfaceGenerators.Ellipsoid(center, (R, R, R), name) @@ -421,7 +421,7 @@ def Torus(r=2, R=3, name="Torus"): sage: torus = surfaces.Torus(); torus Parametrized surface ('Torus') with equation ((2*cos(v) + 3)*cos(u), (2*cos(v) + 3)*sin(u), 2*sin(v)) - sage: torus.plot() # optional - sage.plot + sage: torus.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') @@ -448,7 +448,7 @@ def WhitneyUmbrella(name="Whitney's umbrella"): sage: whitney = surfaces.WhitneyUmbrella(); whitney Parametrized surface ('Whitney's umbrella') with equation (u*v, u, v^2) - sage: whitney.plot() # optional - sage.plot + sage: whitney.plot() # needs sage.plot Graphics3d Object """ u, v = var('u, v') diff --git a/src/sage/geometry/toric_lattice.py b/src/sage/geometry/toric_lattice.py index 7f1665ee79a..c5d35bb2002 100644 --- a/src/sage/geometry/toric_lattice.py +++ b/src/sage/geometry/toric_lattice.py @@ -951,7 +951,7 @@ def __richcmp__(self, right, op): """ if self is right: return rich_to_bool(op, 0) - if type(self) != type(right): + if type(self) is not type(right): return NotImplemented lx = self.rank() @@ -1068,7 +1068,7 @@ def plot(self, **options): EXAMPLES:: sage: N = ToricLattice(3) - sage: N.plot() # optional - sage.plot + sage: N.plot() # needs sage.plot Graphics3d Object """ if "show_lattice" not in options: @@ -1169,7 +1169,7 @@ def _latex_(self): '\\left\\langle\\left(1,\\,2,\\,3\\right)_{L}, \\left(0,\\,4,\\,8\\right)_{L}\\right\\rangle' """ - s = '\\left\\langle' + s = '\\left\\langle' s += ', '.join([ b._latex_() for b in self.basis() ]) s += '\\right\\rangle' return s @@ -1215,12 +1215,12 @@ def plot(self, **options): sage: N = ToricLattice(3) sage: sublattice = N.submodule_with_basis([(1,1,0), (3,2,1)]) - sage: sublattice.plot() # optional - sage.plot + sage: sublattice.plot() # needs sage.plot Graphics3d Object Now we plot both the ambient lattice and its sublattice:: - sage: N.plot() + sublattice.plot(point_color="red") # optional - sage.plot + sage: N.plot() + sublattice.plot(point_color="red") # needs sage.plot Graphics3d Object """ if "show_lattice" not in options: @@ -1287,7 +1287,6 @@ class ToricLattice_sublattice(ToricLattice_sublattice_with_basis, pass - class ToricLattice_quotient_element(FGP_Element): r""" Create an element of a toric lattice quotient. diff --git a/src/sage/geometry/toric_lattice_element.pyx b/src/sage/geometry/toric_lattice_element.pyx index cdb2b6fa58f..40897c019f5 100644 --- a/src/sage/geometry/toric_lattice_element.pyx +++ b/src/sage/geometry/toric_lattice_element.pyx @@ -99,9 +99,9 @@ from sage.libs.gmp.mpz cimport * from sage.geometry.toric_plotter import ToricPlotter from sage.modules.vector_integer_dense cimport Vector_integer_dense from sage.structure.coerce_exceptions import CoercionException -from sage.structure.element cimport Element, Vector +from sage.structure.element cimport Vector from sage.rings.integer cimport Integer -from sage.structure.richcmp cimport richcmp_not_equal, richcmp +from sage.structure.richcmp cimport richcmp_not_equal def is_ToricLatticeElement(x): @@ -394,7 +394,7 @@ cdef class ToricLatticeElement(Vector_integer_dense): sage: N = ToricLattice(3) sage: n = N(1,2,3) - sage: n.plot() # optional - sage.plot + sage: n.plot() # needs sage.plot Graphics3d Object """ tp = ToricPlotter(options, self.parent().degree()) diff --git a/src/sage/geometry/toric_plotter.py b/src/sage/geometry/toric_plotter.py index 988c180431a..50b4008eb0f 100644 --- a/src/sage/geometry/toric_plotter.py +++ b/src/sage/geometry/toric_plotter.py @@ -14,8 +14,8 @@ In most cases, this module is used indirectly, e.g. :: - sage: fan = toric_varieties.dP6().fan() # optional - palp - sage: fan.plot() # optional - sage.plot # optional - palp + sage: fan = toric_varieties.dP6().fan() # needs palp sage.graphs + sage: fan.plot() # needs palp sage.graphs sage.plot Graphics object consisting of 31 graphics primitives You may change default plotting options as follows:: @@ -25,12 +25,12 @@ sage: toric_plotter.options(show_rays=False) sage: toric_plotter.options("show_rays") False - sage: fan.plot() # optional - sage.plot # optional - palp + sage: fan.plot() # needs palp sage.graphs sage.plot Graphics object consisting of 19 graphics primitives sage: toric_plotter.reset_options() sage: toric_plotter.options("show_rays") True - sage: fan.plot() # optional - sage.plot # optional - palp + sage: fan.plot() # needs palp sage.graphs sage.plot Graphics object consisting of 31 graphics primitives """ @@ -134,10 +134,10 @@ class ToricPlotter(SageObject): directly. Instead, use plotting method of the object which you want to plot, e.g. :: - sage: fan = toric_varieties.dP6().fan() # optional - palp - sage: fan.plot() # optional - sage.plot # optional - palp + sage: fan = toric_varieties.dP6().fan() # needs palp sage.graphs + sage: fan.plot() # needs palp sage.graphs sage.plot Graphics object consisting of 31 graphics primitives - sage: print(fan.plot()) # optional - sage.plot # optional - palp + sage: print(fan.plot()) # needs palp sage.graphs sage.plot Graphics object consisting of 31 graphics primitives If you do want to create your own plotting function for some toric @@ -163,24 +163,25 @@ class ToricPlotter(SageObject): For example, the plot from the previous example can be obtained as follows:: + sage: # needs palp sage.graphs sage.plot sage: from sage.geometry.toric_plotter import ToricPlotter - sage: options = dict() # use default for everything - sage: tp = ToricPlotter(options, fan.lattice().degree()) # optional - palp - sage: tp.include_points(fan.rays()) # optional - palp - sage: tp.adjust_options() # optional - palp - sage: tp.set_rays(fan.rays()) # optional - palp - sage: result = tp.plot_lattice() # optional - palp - sage: result += tp.plot_rays() # optional - palp - sage: result += tp.plot_generators() # optional - palp - sage: result += tp.plot_walls(fan(2)) # optional - palp - sage: result # optional - palp + sage: options = dict() # use default for everything + sage: tp = ToricPlotter(options, fan.lattice().degree()) + sage: tp.include_points(fan.rays()) + sage: tp.adjust_options() + sage: tp.set_rays(fan.rays()) + sage: result = tp.plot_lattice() + sage: result += tp.plot_rays() + sage: result += tp.plot_generators() + sage: result += tp.plot_walls(fan(2)) + sage: result Graphics object consisting of 31 graphics primitives In most situations it is only necessary to include generators of rays, in this case they can be passed to the constructor as an optional argument. In the example above, the toric plotter can be completely set up using :: - sage: tp = ToricPlotter(options, fan.lattice().degree(), fan.rays()) # optional - palp + sage: tp = ToricPlotter(options, fan.lattice().degree(), fan.rays()) # needs palp sage.graphs sage.plot All options are exposed as attributes of toric plotters and can be modified after constructions, however you will have to manually call @@ -389,7 +390,7 @@ def plot_generators(self): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2, [(3,4)]) - sage: tp.plot_generators() + sage: tp.plot_generators() # needs sage.plot Graphics object consisting of 1 graphics primitive """ generators = self.generators @@ -440,7 +441,7 @@ def plot_labels(self, labels, positions): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2) - sage: tp.plot_labels("u", [(1.5,0)]) + sage: tp.plot_labels("u", [(1.5,0)]) # needs sage.plot Graphics object consisting of 1 graphics primitive """ result = Graphics() @@ -474,7 +475,7 @@ def plot_lattice(self): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2) sage: tp.adjust_options() - sage: tp.plot_lattice() + sage: tp.plot_lattice() # needs sage.plot Graphics object consisting of 1 graphics primitive """ if not self.show_lattice: @@ -518,7 +519,7 @@ def plot_points(self, points): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2) sage: tp.adjust_options() - sage: tp.plot_points([(1,0), (0,1)]) + sage: tp.plot_points([(1,0), (0,1)]) # needs sage.plot Graphics object consisting of 1 graphics primitive """ return point(points, color=self.point_color, size=self.point_size, @@ -542,7 +543,7 @@ def plot_ray_labels(self): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2, [(3,4)]) - sage: tp.plot_ray_labels() + sage: tp.plot_ray_labels() # needs sage.plot Graphics object consisting of 1 graphics primitive """ return self.plot_labels(self.ray_label, @@ -563,7 +564,7 @@ def plot_rays(self): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2, [(3,4)]) - sage: tp.plot_rays() + sage: tp.plot_rays() # needs sage.plot Graphics object consisting of 2 graphics primitives """ result = Graphics() @@ -605,14 +606,14 @@ def plot_walls(self, walls): sage: quadrant = Cone([(1,0), (0,1)]) sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2, quadrant.rays()) - sage: tp.plot_walls([quadrant]) + sage: tp.plot_walls([quadrant]) # needs sage.plot Graphics object consisting of 2 graphics primitives Let's also check that the truncating polyhedron is functioning correctly:: sage: tp = ToricPlotter({"mode": "box"}, 2, quadrant.rays()) - sage: tp.plot_walls([quadrant]) + sage: tp.plot_walls([quadrant]) # needs sage.plot Graphics object consisting of 2 graphics primitives """ result = Graphics() @@ -702,12 +703,12 @@ def set_rays(self, generators): sage: from sage.geometry.toric_plotter import ToricPlotter sage: tp = ToricPlotter(dict(), 2) sage: tp.adjust_options() - sage: tp.plot_rays() + sage: tp.plot_rays() # needs sage.plot Traceback (most recent call last): ... AttributeError: 'ToricPlotter' object has no attribute 'rays' sage: tp.set_rays([(0,1)]) - sage: tp.plot_rays() + sage: tp.plot_rays() # needs sage.plot Graphics object consisting of 2 graphics primitives """ d = self.dimension @@ -731,7 +732,7 @@ def set_rays(self, generators): rays = generators elif self.mode == "round": r = self.radius - rays = [r * gen / gen.norm() for gen in generators] + rays = [r * gen / gen.norm() for gen in generators] self.rays = rays @@ -781,6 +782,7 @@ def color_list(color, n): EXAMPLES:: + sage: # needs sage.plot sage: from sage.geometry.toric_plotter import color_list sage: color_list("grey", 1) [RGB color (0.5019607843137255, 0.5019607843137255, 0.5019607843137255)] @@ -1106,9 +1108,9 @@ def sector(ray1, ray2, **extra_options): EXAMPLES:: sage: from sage.geometry.toric_plotter import sector - sage: sector((1,0), (0,1)) + sage: sector((1,0), (0,1)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive - sage: sector((3,2,1), (1,2,3)) + sage: sector((3,2,1), (1,2,3)) # needs sage.plot Graphics3d Object """ ray1 = vector(RDF, ray1) diff --git a/src/sage/geometry/triangulation/__init__.py b/src/sage/geometry/triangulation/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/geometry/triangulation/base.pyx b/src/sage/geometry/triangulation/base.pyx index dcb81f6c2b1..d66186db098 100644 --- a/src/sage/geometry/triangulation/base.pyx +++ b/src/sage/geometry/triangulation/base.pyx @@ -18,7 +18,7 @@ AUTHORS: # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ######################################################################## from sage.misc.fast_methods cimport hash_by_id @@ -26,7 +26,6 @@ from sage.structure.sage_object cimport SageObject from sage.structure.parent cimport Parent from sage.categories.sets_cat import Sets from sage.matrix.constructor import matrix -from sage.misc.cachefunc import cached_method from .functions cimport binomial from .triangulations cimport \ @@ -77,7 +76,6 @@ cdef class Point(SageObject): cdef object _point_configuration cdef object _reduced_affine_vector, _reduced_projective_vector - def __init__(self, point_configuration, i, projective, affine, reduced): r""" Construct a :class:`Point`. @@ -130,7 +128,6 @@ cdef class Point(SageObject): """ return self._point_configuration - def __iter__(self): r""" Iterate through the affine ambient space coordinates of the point. @@ -161,7 +158,6 @@ cdef class Point(SageObject): """ return len(self._affine) - cpdef index(self): """ Return the index of the point in the point configuration. @@ -176,7 +172,6 @@ cdef class Point(SageObject): """ return self._index - cpdef projective(self): r""" Return the projective coordinates of the point in the ambient space. @@ -203,7 +198,6 @@ cdef class Point(SageObject): """ return self._projective - cpdef affine(self): r""" Return the affine coordinates of the point in the ambient space. @@ -230,7 +224,6 @@ cdef class Point(SageObject): """ return self._affine - cpdef reduced_affine(self): r""" Return the affine coordinates of the point on the hyperplane @@ -258,7 +251,6 @@ cdef class Point(SageObject): """ return self._reduced_affine - cpdef reduced_projective(self): r""" Return the projective coordinates of the point on the hyperplane @@ -286,7 +278,6 @@ cdef class Point(SageObject): """ return tuple(self._reduced_affine)+(1,) - cpdef reduced_affine_vector(self): """ Return the affine coordinates of the point on the hyperplane @@ -314,7 +305,6 @@ cdef class Point(SageObject): """ return self._reduced_affine_vector - cpdef reduced_projective_vector(self): """ Return the affine coordinates of the point on the hyperplane @@ -360,7 +350,7 @@ cdef class Point(SageObject): sage: p._repr_() 'P(0, 0)' """ - return 'P'+str(self._affine) + return 'P' + str(self._affine) ######################################################################## @@ -399,7 +389,6 @@ cdef class PointConfiguration_base(Parent): self._init_points(points) self._is_affine = defined_affine - cdef tuple _pts cdef int _ambient_dim cdef int _dim @@ -407,7 +396,6 @@ cdef class PointConfiguration_base(Parent): cdef bint _is_affine cdef object _reduced_affine_vector_space, _reduced_projective_vector_space - cdef _init_points(self, tuple projective_points): """ Internal method to determine coordinates of points. @@ -450,20 +438,20 @@ cdef class PointConfiguration_base(Parent): else: raise NotImplementedError # TODO - if n>1: + if n > 1: # shift first point to origin - red = matrix([ aff.column(i)-aff.column(0) for i in range(n) ]).transpose() + red = matrix([aff.column(i)-aff.column(0) for i in range(n)]).transpose() # pick linearly independent rows - red = matrix([ red.row(i) for i in red.pivot_rows()]) + red = matrix([red.row(i) for i in red.pivot_rows()]) else: - red = matrix(0,1) + red = matrix(0, 1) self._dim = red.nrows() from sage.modules.free_module import VectorSpace self._reduced_affine_vector_space = VectorSpace(self._base_ring.fraction_field(), self._dim) self._reduced_projective_vector_space = VectorSpace(self._base_ring.fraction_field(), self._dim+1) self._pts = tuple([Point(self, i, proj.column(i), - aff.column(i), red.column(i)) + aff.column(i), red.column(i)) for i in range(n)]) def __hash__(self): @@ -498,7 +486,6 @@ cdef class PointConfiguration_base(Parent): """ return self._reduced_affine_vector_space - cpdef reduced_projective_vector_space(self): """ Return the vector space that is spanned by the homogeneous @@ -520,7 +507,6 @@ cdef class PointConfiguration_base(Parent): """ return self._reduced_projective_vector_space - cpdef ambient_dim(self): """ Return the dimension of the ambient space of the point @@ -538,11 +524,9 @@ cdef class PointConfiguration_base(Parent): """ return self._ambient_dim - cpdef dim(self): """ - Return the actual dimension of the point - configuration. + Return the actual dimension of the point configuration. See also :meth:`ambient_dim` @@ -556,7 +540,6 @@ cdef class PointConfiguration_base(Parent): """ return self._dim - cpdef base_ring(self): r""" Return the base ring, that is, the ring containing the @@ -582,10 +565,9 @@ cdef class PointConfiguration_base(Parent): """ return self._base_ring - cpdef bint is_affine(self): """ - Whether the configuration is defined by affine points. + Return whether the configuration is defined by affine points. OUTPUT: @@ -604,7 +586,6 @@ cdef class PointConfiguration_base(Parent): """ return self._is_affine - def _assert_is_affine(self): """ Raise a ``ValueError`` if the point configuration is not @@ -623,7 +604,6 @@ cdef class PointConfiguration_base(Parent): if not self.is_affine(): raise ValueError('The point configuration contains projective points.') - def __getitem__(self, i): """ Return the ``i``-th point. @@ -652,7 +632,6 @@ cdef class PointConfiguration_base(Parent): """ return self._pts[i] - cpdef n_points(self): """ Return the number of points. @@ -674,14 +653,13 @@ cdef class PointConfiguration_base(Parent): """ return len(self._pts) - cpdef points(self): """ Return a list of the points. OUTPUT: - Returns a list of the points. See also the :meth:`__iter__` + A list of the points. See also the :meth:`__iter__` method, which returns the corresponding generator. EXAMPLES:: @@ -700,7 +678,6 @@ cdef class PointConfiguration_base(Parent): """ return self._pts - def point(self, i): """ Return the i-th point of the configuration. @@ -754,10 +731,9 @@ cdef class PointConfiguration_base(Parent): """ return len(self._pts) - cpdef simplex_to_int(self, simplex): r""" - Returns an integer that uniquely identifies the given simplex. + Return an integer that uniquely identifies the given simplex. See also the inverse method :meth:`int_to_simplex`. @@ -791,19 +767,18 @@ cdef class PointConfiguration_base(Parent): cdef int k = 1 cdef int n = self.n_points() cdef int d = len(simplex) - assert d==self.dim()+1 + assert d == self.dim()+1 cdef int i, j - for i in range(1,d+1): + for i in range(1, d+1): l = simplex[i-1]+1 - for j in range(k,l): - s += binomial(n-j,d-i) + for j in range(k, l): + s += binomial(n-j, d-i) k = l+1 return s - cpdef int_to_simplex(self, int s): r""" - Reverses the enumeration of possible simplices in + Reverse the enumeration of possible simplices in :meth:`simplex_to_int`. The enumeration is compatible with [PUNTOS]_. @@ -835,25 +810,23 @@ cdef class PointConfiguration_base(Parent): simplex = [] cdef int l = 0 cdef int n = self.n_points() - cdef int d = self.dim()+1 + cdef int d = self.dim() + 1 cdef int k, b - for k in range(1,d): + for k in range(1, d): l += 1 - i = l j = 1 - b = binomial(n-l,d-k) - while (s>b) and (b>0): + b = binomial(n - l, d - k) + while s > b > 0: j += 1 l += 1 s -= b - b = binomial(n-l,d-k) - simplex.append(l-1) - simplex.append(s+l-1) + b = binomial(n - l, d - k) + simplex.append(l - 1) + simplex.append(s + l - 1) assert len(simplex) == d return tuple(simplex) - ######################################################################## cdef class ConnectedTriangulationsIterator(SageObject): r""" @@ -933,7 +906,6 @@ cdef class ConnectedTriangulationsIterator(SageObject): cdef triangulations_ptr _tp - def __cinit__(self): """ The Cython constructor. @@ -947,7 +919,6 @@ cdef class ConnectedTriangulationsIterator(SageObject): """ self._tp = NULL - def __init__(self, point_configuration, seed=None, star=None, fine=False): r""" The Python constructor. @@ -981,14 +952,12 @@ cdef class ConnectedTriangulationsIterator(SageObject): enumerated_simplices_seed, point_configuration.bistellar_flips()) - def __dealloc__(self): r""" The Cython destructor. """ delete_triangulations(self._tp) - def __iter__(self): r""" The iterator interface: Start iterating. diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index a436b40d441..7486488adb1 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -23,7 +23,7 @@ sage: points = PointConfiguration(p) sage: triang = points.triangulate(); triang (<0,1,2,5>, <0,1,3,5>, <1,3,4,5>) - sage: triang.plot(axes=False) # optional - sage.plot + sage: triang.plot(axes=False) # needs sage.plot Graphics3d Object See :mod:`sage.geometry.triangulation.point_configuration` for more details. @@ -68,7 +68,7 @@ def triangulation_render_2d(triangulation, **kwds): sage: points = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) sage: triang = points.triangulate() - sage: triang.plot(axes=False, aspect_ratio=1) # indirect doctest # optional - sage.plot + sage: triang.plot(axes=False, aspect_ratio=1) # indirect doctest # needs sage.plot Graphics object consisting of 12 graphics primitives """ from sage.plot.all import point2d, line2d, polygon2d @@ -111,8 +111,6 @@ def triangulation_render_2d(triangulation, **kwds): plot_triangs - - def triangulation_render_3d(triangulation, **kwds): r""" Return a graphical representation of a 3-d triangulation. @@ -132,7 +130,7 @@ def triangulation_render_3d(triangulation, **kwds): sage: p = [[0,-1,-1],[0,0,1],[0,1,0], [1,-1,-1],[1,0,1],[1,1,0]] sage: points = PointConfiguration(p) sage: triang = points.triangulate() - sage: triang.plot(axes=False) # indirect doctest # optional - sage.plot + sage: triang.plot(axes=False) # indirect doctest # needs sage.plot Graphics3d Object """ from sage.plot.plot3d.all import point3d, line3d, polygon3d @@ -363,7 +361,6 @@ def __getitem__(self, i): """ return self._triangulation[i] - def __len__(self): """ Return the length of the triangulation. @@ -380,7 +377,6 @@ def __len__(self): """ return len(self._triangulation) - def _repr_(self): r""" Return a string representation. @@ -401,7 +397,6 @@ def _repr_(self): s += ')' return s - def plot(self, **kwds): r""" Produce a graphical representation of the triangulation. @@ -412,7 +407,7 @@ def plot(self, **kwds): sage: triangulation = p.triangulate() sage: triangulation (<1,3,4>, <2,3,4>) - sage: triangulation.plot(axes=False) # optional - sage.plot + sage: triangulation.plot(axes=False) # needs sage.plot Graphics object consisting of 12 graphics primitives """ dim = self.point_configuration().dim() @@ -425,7 +420,6 @@ def plot(self, **kwds): raise NotImplementedError('Plotting '+str(dim)+'-dimensional triangulations not implemented!') - def gkz_phi(self): r""" Calculate the GKZ phi vector of the triangulation. @@ -460,7 +454,6 @@ def gkz_phi(self): vec[i] = vec[i] + vol return vec - def enumerate_simplices(self): r""" Return the enumerated simplices. @@ -505,7 +498,6 @@ def enumerate_simplices(self): pc = self._point_configuration return tuple( pc.simplex_to_int(t) for t in self ) - def fan(self, origin=None): r""" Construct the fan of cones over the simplices of the triangulation. @@ -532,18 +524,17 @@ def fan(self, origin=None): sage: triangulation = pc.triangulate() sage: fan = triangulation.fan(); fan Rational polyhedral fan in 2-d lattice N - sage: fan.is_equivalent( toric_varieties.P2().fan() ) # optional - palp + sage: fan.is_equivalent(toric_varieties.P2().fan()) # needs palp sage.graphs True Toric diagrams (the `\ZZ_5` hyperconifold):: sage: vertices=[(0, 1, 0), (0, 3, 1), (0, 2, 3), (0, 0, 2)] sage: interior=[(0, 1, 1), (0, 1, 2), (0, 2, 1), (0, 2, 2)] - sage: points = vertices+interior + sage: points = vertices + interior sage: pc = PointConfiguration(points, fine=True) sage: triangulation = pc.triangulate() - sage: fan = triangulation.fan( (-1,0,0) ) - sage: fan + sage: fan = triangulation.fan((-1,0,0)); fan Rational polyhedral fan in 3-d lattice N sage: fan.rays() N(1, 1, 0), @@ -564,7 +555,6 @@ def fan(self, origin=None): points = self.point_configuration().points() return Fan(self, (vector(R, p) - origin for p in points)) - @cached_method def simplicial_complex(self): r""" @@ -577,19 +567,17 @@ def simplicial_complex(self): EXAMPLES:: sage: p = polytopes.cuboctahedron() - sage: sc = p.triangulate(engine='internal').simplicial_complex() - sage: sc + sage: sc = p.triangulate(engine='internal').simplicial_complex(); sc # needs sage.graphs Simplicial complex with 12 vertices and 16 facets Any convex set is contractable, so its reduced homology groups vanish:: - sage: sc.homology() + sage: sc.homology() # needs sage.graphs {0: 0, 1: 0, 2: 0, 3: 0} """ from sage.topology.simplicial_complex import SimplicialComplex return SimplicialComplex(self) - @cached_method def _boundary_simplex_dictionary(self): """ @@ -633,7 +621,6 @@ def _boundary_simplex_dictionary(self): result[facet] = result.get(facet, tuple()) + (simplex,) return result - @cached_method def boundary(self): """ @@ -683,20 +670,19 @@ def boundary_simplicial_complex(self): sage: p = polytopes.cuboctahedron() sage: triangulation = p.triangulate(engine='internal') - sage: bd_sc = triangulation.boundary_simplicial_complex() - sage: bd_sc + sage: bd_sc = triangulation.boundary_simplicial_complex(); bd_sc # needs sage.graphs Simplicial complex with 12 vertices and 20 facets The boundary of every convex set is a topological sphere, so it has spherical homology:: - sage: bd_sc.homology() + sage: bd_sc.homology() # needs sage.graphs {0: 0, 1: 0, 2: Z} It is a subcomplex of ``self`` as a :meth:`simplicial_complex`:: - sage: sc = triangulation.simplicial_complex() - sage: all(f in sc for f in bd_sc.maximal_faces()) + sage: sc = triangulation.simplicial_complex() # needs sage.graphs + sage: all(f in sc for f in bd_sc.maximal_faces()) # needs sage.graphs True """ from sage.topology.simplicial_complex import SimplicialComplex @@ -753,9 +739,9 @@ def polyhedral_complex(self, **kwds): sage: pc = PointConfiguration(P.vertices()) sage: T = pc.placing_triangulation(); T (<0,1,2,7>, <0,1,5,7>, <0,2,3,7>, <0,3,4,7>, <0,4,5,7>, <1,5,6,7>) - sage: C = T.polyhedral_complex(); C + sage: C = T.polyhedral_complex(); C # needs sage.graphs Polyhedral complex with 6 maximal cells - sage: [P.vertices_list() for P in C.maximal_cells_sorted()] + sage: [P.vertices_list() for P in C.maximal_cells_sorted()] # needs sage.graphs [[[-1, -1, -1], [-1, -1, 1], [-1, 1, 1], [1, -1, -1]], [[-1, -1, -1], [-1, 1, -1], [-1, 1, 1], [1, 1, -1]], [[-1, -1, -1], [-1, 1, 1], [1, -1, -1], [1, 1, -1]], @@ -789,26 +775,26 @@ def boundary_polyhedral_complex(self, **kwds): sage: pc = PointConfiguration(P.vertices()) sage: T = pc.placing_triangulation(); T (<0,1,2,7>, <0,1,5,7>, <0,2,3,7>, <0,3,4,7>, <0,4,5,7>, <1,5,6,7>) - sage: bd_C = T.boundary_polyhedral_complex(); bd_C + sage: bd_C = T.boundary_polyhedral_complex(); bd_C # needs sage.graphs Polyhedral complex with 12 maximal cells - sage: [P.vertices_list() for P in bd_C.maximal_cells_sorted()] + sage: [P.vertices_list() for P in bd_C.maximal_cells_sorted()] # needs sage.graphs [[[-1, -1, -1], [-1, -1, 1], [-1, 1, 1]], - [[-1, -1, -1], [-1, -1, 1], [1, -1, -1]], - [[-1, -1, -1], [-1, 1, -1], [-1, 1, 1]], - [[-1, -1, -1], [-1, 1, -1], [1, 1, -1]], - [[-1, -1, -1], [1, -1, -1], [1, 1, -1]], - [[-1, -1, 1], [-1, 1, 1], [1, -1, 1]], - [[-1, -1, 1], [1, -1, -1], [1, -1, 1]], - [[-1, 1, -1], [-1, 1, 1], [1, 1, -1]], - [[-1, 1, 1], [1, -1, 1], [1, 1, 1]], - [[-1, 1, 1], [1, 1, -1], [1, 1, 1]], - [[1, -1, -1], [1, -1, 1], [1, 1, 1]], - [[1, -1, -1], [1, 1, -1], [1, 1, 1]]] + [[-1, -1, -1], [-1, -1, 1], [1, -1, -1]], + [[-1, -1, -1], [-1, 1, -1], [-1, 1, 1]], + [[-1, -1, -1], [-1, 1, -1], [1, 1, -1]], + [[-1, -1, -1], [1, -1, -1], [1, 1, -1]], + [[-1, -1, 1], [-1, 1, 1], [1, -1, 1]], + [[-1, -1, 1], [1, -1, -1], [1, -1, 1]], + [[-1, 1, -1], [-1, 1, 1], [1, 1, -1]], + [[-1, 1, 1], [1, -1, 1], [1, 1, 1]], + [[-1, 1, 1], [1, 1, -1], [1, 1, 1]], + [[1, -1, -1], [1, -1, 1], [1, 1, 1]], + [[1, -1, -1], [1, 1, -1], [1, 1, 1]]] It is a subcomplex of ``self`` as a :meth:`polyhedral_complex`:: - sage: C = T.polyhedral_complex() - sage: bd_C.is_subcomplex(C) + sage: C = T.polyhedral_complex() # needs sage.graphs + sage: bd_C.is_subcomplex(C) # needs sage.graphs True """ from sage.geometry.polyhedral_complex import PolyhedralComplex @@ -932,7 +918,7 @@ def adjacency_graph(self): sage: p = PointConfiguration([[1,0,0], [0,1,0], [0,0,1], [-1,0,1], ....: [1,0,-1], [-1,0,0], [0,-1,0], [0,0,-1]]) sage: t = p.triangulate() - sage: t.adjacency_graph() + sage: t.adjacency_graph() # needs sage.graphs Graph on 8 vertices """ diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index f970a5faf4a..d75af2af4ce 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -42,8 +42,7 @@ A 2-dimensional point configuration:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) - sage: p + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]); p A point configuration in affine 2-space over Integer Ring consisting of 5 points. The triangulations of this point configuration are assumed to be connected, not necessarily fine, not necessarily regular. @@ -51,13 +50,12 @@ .. PLOT:: :width: 300 px - p = PointConfiguration([[-1,-1],[1,1],[1,0],[0,1],[0,0]]) + p = PointConfiguration([[-1,-1], [1,1], [1,0], [0,1], [0,0]]) sphinx_plot(p.plot(axes=False)) A triangulation of it:: - sage: t = p.triangulate() # a single triangulation - sage: t + sage: t = p.triangulate(); t # a single triangulation (<1,3,4>, <2,3,4>) sage: len(t) 2 @@ -67,59 +65,62 @@ (2, 3, 4) sage: list(t) [(1, 3, 4), (2, 3, 4)] - sage: t.plot(axes=False) # optional - sage.plot + sage: t.plot(axes=False) # needs sage.plot Graphics object consisting of 12 graphics primitives .. PLOT:: :width: 300 px - p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) + p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) t = p.triangulate() sphinx_plot(t.plot(axes=False)) List triangulations of it:: - sage: list( p.triangulations() ) + sage: list(p.triangulations()) [(<1,3,4>, <2,3,4>), (<0,1,3>, <0,1,4>, <0,2,3>, <0,2,4>), (<1,2,3>, <1,2,4>), (<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>)] - sage: p_fine = p.restrict_to_fine_triangulations() - sage: p_fine + sage: p_fine = p.restrict_to_fine_triangulations(); p_fine A point configuration in affine 2-space over Integer Ring consisting of 5 points. The triangulations of this point configuration are assumed to be connected, fine, not necessarily regular. - sage: list( p_fine.triangulations() ) + sage: list(p_fine.triangulations()) [(<0,1,3>, <0,1,4>, <0,2,3>, <0,2,4>), (<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>)] A 3-dimensional point configuration:: - sage: p = [[0,-1,-1],[0,0,1],[0,1,0], [1,-1,-1],[1,0,1],[1,1,0]] + sage: p = [[0,-1,-1], [0,0,1], [0,1,0], [1,-1,-1], [1,0,1], [1,1,0]] sage: points = PointConfiguration(p) sage: triang = points.triangulate() - sage: triang.plot(axes=False) # optional - sage.plot + sage: triang.plot(axes=False) # needs sage.plot Graphics3d Object .. PLOT:: :width: 300 px - p = [[0,-1,-1],[0,0,1],[0,1,0], [1,-1,-1],[1,0,1],[1,1,0]] + p = [[0,-1,-1], [0,0,1], [0,1,0], [1,-1,-1], [1,0,1], [1,1,0]] points = PointConfiguration(p) triang = points.triangulate() sphinx_plot(triang.plot(axes=False)) The standard example of a non-regular triangulation (requires TOPCOM):: - sage: PointConfiguration.set_engine('topcom') # optional - topcom - sage: p = PointConfiguration([[-1,-5/9],[0,10/9],[1,-5/9],[-2,-10/9],[0,20/9],[2,-10/9]]) - sage: regular = p.restrict_to_regular_triangulations(True).triangulations_list() # optional - topcom - sage: nonregular = p.restrict_to_regular_triangulations(False).triangulations_list() # optional - topcom - sage: len(regular) # optional - topcom + sage: # optional - topcom + sage: PointConfiguration.set_engine('topcom') + sage: p = PointConfiguration([[-1,-5/9], [0,10/9], [1,-5/9], + ....: [-2,-10/9], [0,20/9], [2,-10/9]]) + sage: p_regular = p.restrict_to_regular_triangulations(True) + sage: regular = p_regular.triangulations_list() + sage: p_nonregular = p.restrict_to_regular_triangulations(False) + sage: nonregular = p_nonregular.triangulations_list() + sage: len(regular) 16 - sage: len(nonregular) # optional - topcom + sage: len(nonregular) 2 - sage: nonregular[0].plot(aspect_ratio=1, axes=False) # optional - topcom # optional - sage.plot + sage: nonregular[0].plot(aspect_ratio=1, axes=False) # needs sage.plot Graphics object consisting of 25 graphics primitives sage: PointConfiguration.set_engine('internal') # to make doctests independent of TOPCOM @@ -127,8 +128,9 @@ points may lie in a hyperplane and the linear dependencies will be removed before passing the data to TOPCOM which cannot handle it:: - sage: points = [[0,0,0,1],[0,3,0,1],[3,0,0,1],[0,0,1,1],[0,3,1,1],[3,0,1,1],[1,1,2,1]] - sage: points = [ p+[1,2,3] for p in points ] + sage: points = [[0,0,0,1], [0,3,0,1], [3,0,0,1], [0,0,1,1], + ....: [0,3,1,1], [3,0,1,1], [1,1,2,1]] + sage: points = [p + [1,2,3] for p in points] sage: pc = PointConfiguration(points) sage: pc.ambient_dim() 7 @@ -138,27 +140,27 @@ (<0,1,2,6>, <0,1,3,6>, <0,2,3,6>, <1,2,4,6>, <1,3,4,6>, <2,3,5,6>, <2,4,5,6>) sage: _ in pc.triangulations() True - sage: len( pc.triangulations_list() ) + sage: len(pc.triangulations_list()) 26 AUTHORS: - - Volker Braun: initial version, 2010 +- Volker Braun: initial version, 2010 - - Josh Whitney: added functionality for computing - volumes and secondary polytopes of PointConfigurations +- Josh Whitney: added functionality for computing + volumes and secondary polytopes of PointConfigurations - - Marshall Hampton: improved documentation and doctest coverage +- Marshall Hampton: improved documentation and doctest coverage - - Volker Braun: rewrite using Parent/Element and categories. Added - a Point class. More doctests. Less zombies. +- Volker Braun: rewrite using Parent/Element and categories. Added + a Point class. More doctests. Less zombies. - - Volker Braun: Cythonized parts of it, added a C++ implementation - of the bistellar flip algorithm to enumerate all connected - triangulations. +- Volker Braun: Cythonized parts of it, added a C++ implementation + of the bistellar flip algorithm to enumerate all connected + triangulations. - - Volker Braun 2011: switched the triangulate() method to the - placing triangulation (faster). +- Volker Braun 2011: switched the triangulate() method to the + placing triangulation (faster). """ ######################################################################## @@ -237,11 +239,11 @@ class PointConfiguration(UniqueRepresentation, PointConfiguration_base): function. In other words, the shadows of the faces of a polyhedron in one higher dimension. - * ``True``: Only regular triangulations. + * ``True``: Only regular triangulations. - * ``False``: Only non-regular triangulations. + * ``False``: Only non-regular triangulations. - * ``None`` (default): Both kinds of triangulation. + * ``None`` (default): Both kinds of triangulation. - ``star`` -- either ``None`` or a point. Whether the triangulations must be star. A triangulation is star if all @@ -251,8 +253,7 @@ class PointConfiguration(UniqueRepresentation, PointConfiguration_base): EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) - sage: p + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]); p A point configuration in affine 2-space over Integer Ring consisting of 5 points. The triangulations of this point configuration are assumed to be connected, not necessarily fine, @@ -261,7 +262,6 @@ class PointConfiguration(UniqueRepresentation, PointConfiguration_base): (<1,3,4>, <2,3,4>) """ - # we cache the output of _have_TOPCOM() in this class variable _have_TOPCOM_cached = None @@ -270,7 +270,6 @@ class PointConfiguration(UniqueRepresentation, PointConfiguration_base): # variable to decide whether to call TOPCOM or not _use_TOPCOM = None - @classmethod def _have_TOPCOM(cls): r""" @@ -296,7 +295,6 @@ def _have_TOPCOM(cls): PointConfiguration.set_engine('auto') return PointConfiguration._have_TOPCOM_cached - @staticmethod def __classcall__(cls, points, projective=False, connected=True, fine=False, regular=None, star=None): r""" @@ -304,8 +302,8 @@ def __classcall__(cls, points, projective=False, connected=True, fine=False, reg EXAMPLES:: - sage: pc1 = PointConfiguration([[1,2],[2,3],[3,4]], connected=True) - sage: pc2 = PointConfiguration(((1,2),(2,3),(3,4)), regular=None) + sage: pc1 = PointConfiguration([[1,2], [2,3], [3,4]], connected=True) + sage: pc2 = PointConfiguration(((1,2), (2,3), (3,4)), regular=None) sage: pc1 is pc2 # indirect doctest True """ @@ -334,7 +332,8 @@ def __init__(self, points, connected, fine, regular, star, defined_affine): EXAMPLES:: - sage: p = PointConfiguration([[0,4],[2,3],[3,2],[4,0],[3,-2],[2,-3],[0,-4],[-2,-3],[-3,-2],[-4,0],[-3,2],[-2,3]]) + sage: p = PointConfiguration([[0,4], [2,3], [3,2], [4,0], [3,-2], [2,-3], + ....: [0,-4], [-2,-3], [-3,-2], [-4,0], [-3,2], [-2,3]]) sage: len(p.triangulations_list()) # long time (26s on sage.math, 2012) 16796 @@ -370,21 +369,22 @@ def set_engine(cls, engine='auto'): INPUT: - - ``engine`` -- either 'auto' (default), 'internal', or - 'topcom'. The latter two instruct this package to always use + - ``engine`` -- either ``'auto'`` (default), ``'internal'``, or + ``'topcom'``. The latter two instruct this package to always use its own triangulation algorithms or TOPCOM's algorithms, - respectively. By default ('auto'), internal routines are used. + respectively. By default (``'auto'``), internal routines are used. EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) + sage: # optional - topcom + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) sage: p.set_engine('internal') # to make doctests independent of TOPCOM sage: p.triangulate() (<1,3,4>, <2,3,4>) - sage: p.set_engine('topcom') # optional - topcom - sage: p.triangulate() # optional - topcom + sage: p.set_engine('topcom') + sage: p.triangulate() (<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>) - sage: p.set_engine('internal') # optional - topcom + sage: p.set_engine('internal') """ engine = engine.lower() if engine not in ['auto', 'topcom', 'internal']: @@ -402,11 +402,11 @@ def star_center(self): A :class:`~sage.geometry.triangulation.base.Point` if a distinguished star central point has been fixed. - ``ValueError`` exception is raised otherwise. + :class:`ValueError` exception is raised otherwise. EXAMPLES:: - sage: pc = PointConfiguration([(1,0),(-1,0),(0,1),(0,2)], star=(0,1)); pc + sage: pc = PointConfiguration([(1,0), (-1,0), (0,1), (0,2)], star=(0,1)); pc A point configuration in affine 2-space over Integer Ring consisting of 4 points. The triangulations of this point configuration are assumed to be connected, not necessarily @@ -414,8 +414,7 @@ def star_center(self): sage: pc.star_center() P(0, 1) - sage: pc_nostar = pc.restrict_to_star_triangulations(None) - sage: pc_nostar + sage: pc_nostar = pc.restrict_to_star_triangulations(None); pc_nostar A point configuration in affine 2-space over Integer Ring consisting of 4 points. The triangulations of this point configuration are assumed to be connected, not necessarily @@ -430,7 +429,6 @@ def star_center(self): else: return self[self._star] - def __reduce__(self): r""" Override __reduce__ to correctly pickle/unpickle. @@ -441,7 +439,8 @@ def __reduce__(self): sage: loads(p.dumps()) is p True - sage: p = PointConfiguration([[0, 1, 1], [0, 0, 1], [1, 0, 1], [1,1, 1]], projective=True) + sage: p = PointConfiguration([[0, 1, 1], [0, 0, 1], [1, 0, 1], [1,1, 1]], + ....: projective=True) sage: loads(p.dumps()) is p True """ @@ -454,7 +453,6 @@ def __reduce__(self): return (PointConfiguration, (points, True, self._connected, self._fine, self._regular, self._star)) - def an_element(self): """ Synonymous for :meth:`triangulate`. @@ -467,7 +465,6 @@ def an_element(self): """ return self.triangulate() - def _element_constructor_(self, e): """ Construct a triangulation. @@ -475,15 +472,13 @@ def _element_constructor_(self, e): TESTS:: sage: p = PointConfiguration([[0, 1], [0, 0], [1, 0], [1,1]]) - sage: p._element_constructor_([ (0,1,2), (2,3,0) ]) + sage: p._element_constructor_([(0,1,2), (2,3,0)]) (<0,1,2>, <0,2,3>) """ return self.element_class(e, parent=self) - Element = Triangulation - def __iter__(self): """ Iterate through the points of the point configuration. @@ -499,32 +494,32 @@ def __iter__(self): sage: p = PointConfiguration([[1,1], [2,2], [3,3]]) sage: list(p) # indirect doctest [P(1, 1), P(2, 2), P(3, 3)] - sage: [ p[i] for i in range(p.n_points()) ] + sage: [p[i] for i in range(p.n_points())] [P(1, 1), P(2, 2), P(3, 3)] sage: list(p.points()) [P(1, 1), P(2, 2), P(3, 3)] - sage: [ p.point(i) for i in range(p.n_points()) ] + sage: [p.point(i) for i in range(p.n_points())] [P(1, 1), P(2, 2), P(3, 3)] """ for p in self.points(): yield p - def _repr_(self): r""" Return a string representation. TESTS:: - sage: p = PointConfiguration([[1,1,1],[-1,1,1],[1,-1,1],[-1,-1,1],[1,1,-1], - ....: [-1,1,-1],[1,-1,-1],[-1,-1,-1],[0,0,0]]) + sage: p = PointConfiguration([[1,1,1], [-1,1,1], [1,-1,1], [-1,-1,1], [1,1,-1], + ....: [-1,1,-1], [1,-1,-1], [-1,-1,-1], [0,0,0]]) sage: p._repr_() 'A point configuration in affine 3-space over Integer Ring consisting of 9 points. The triangulations of this point configuration are assumed to be connected, not necessarily fine, not necessarily regular.' - sage: PointConfiguration([[1, 1, 1], [-1, 1, 1], [1, -1, 1], [-1, -1, 1]], projective=True) + sage: PointConfiguration([[1, 1, 1], [-1, 1, 1], [1, -1, 1], [-1, -1, 1]], + ....: projective=True) A point configuration in projective 2-space over Integer Ring consisting of 4 points. The triangulations of this point configuration are assumed to be connected, @@ -568,7 +563,6 @@ def _repr_(self): s = 'The pointless empty configuration' return s - def _TOPCOM_points(self): r""" Convert the list of input points to a string that can be fed @@ -587,7 +581,6 @@ def _TOPCOM_points(self): s += ']' return s - @classmethod def _TOPCOM_exec(cls, executable, input_string, verbose=True): r""" @@ -606,7 +599,9 @@ def _TOPCOM_exec(cls, executable, input_string, verbose=True): TESTS:: sage: p = PointConfiguration([[1,1,1], [-1,1,1], [1,-1,1], [-1,-1,1], [1,1,-1]]) - sage: out = p._TOPCOM_exec('points2placingtriang', '[[0,0,0,1],[-2,0,0,1],[0,-2,0,1],[-2,-2,0,1],[0,0,-2,1]]', verbose=True) + sage: out = p._TOPCOM_exec('points2placingtriang', + ....: '[[0,0,0,1],[-2,0,0,1],[0,-2,0,1],[-2,-2,0,1],[0,0,-2,1]]', + ....: verbose=True) sage: list(out) # optional - topcom #### TOPCOM input #### # points2placingtriang @@ -661,7 +656,6 @@ def _TOPCOM_exec(cls, executable, input_string, verbose=True): print("#######################") sys.stdout.flush() - def _TOPCOM_communicate(self, executable, verbose=True): r""" Execute TOPCOM and parse the output into a @@ -694,14 +688,13 @@ def _TOPCOM_communicate(self, executable, verbose=True): yield self(triangulation) - def _TOPCOM_triangulations(self, verbose=True): r""" Returns all triangulations satisfying the restrictions imposed. EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) sage: iter = p._TOPCOM_triangulations(verbose=True) sage: next(iter) # optional - topcom #### TOPCOM input #### @@ -729,7 +722,6 @@ def _TOPCOM_triangulations(self, verbose=True): for t in self._TOPCOM_communicate(command, verbose): yield t - def _TOPCOM_triangulate(self, verbose=True): r""" Return one (in no particular order) triangulation subject @@ -748,13 +740,14 @@ def _TOPCOM_triangulate(self, verbose=True): EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) - sage: p.set_engine('topcom') # optional - topcom - sage: p._TOPCOM_triangulate(verbose=False) # optional - topcom + sage: # optional - topcom + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) + sage: p.set_engine('topcom') + sage: p._TOPCOM_triangulate(verbose=False) (<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>) - sage: list( p.triangulate() ) # optional - topcom + sage: list( p.triangulate() ) [(0, 1, 2), (0, 1, 4), (0, 2, 4), (1, 2, 3)] - sage: p.set_engine('internal') # optional - topcom + sage: p.set_engine('internal') """ assert self._regular is not False, \ 'When asked for a single triangulation TOPCOM ' + \ @@ -768,7 +761,6 @@ def _TOPCOM_triangulate(self, verbose=True): return next(self._TOPCOM_communicate(command, verbose)) - def restrict_to_regular_triangulations(self, regular=True): """ Restrict to regular triangulations. @@ -791,15 +783,14 @@ def restrict_to_regular_triangulations(self, regular=True): EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) - sage: p + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]); p A point configuration in affine 2-space over Integer Ring consisting of 5 points. The triangulations of this point configuration are assumed to be connected, not necessarily fine, not necessarily regular. sage: len(p.triangulations_list()) 4 - sage: PointConfiguration.set_engine('topcom') # optional - topcom + sage: PointConfiguration.set_engine('topcom') sage: p_regular = p.restrict_to_regular_triangulations() # optional - topcom sage: len(p_regular.triangulations_list()) # optional - topcom 4 @@ -813,7 +804,6 @@ def restrict_to_regular_triangulations(self, regular=True): regular=regular, star=self._star) - def restrict_to_connected_triangulations(self, connected=True): """ Restrict to connected triangulations. @@ -837,15 +827,14 @@ def restrict_to_connected_triangulations(self, connected=True): EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) - sage: p + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]); p A point configuration in affine 2-space over Integer Ring consisting of 5 points. The triangulations of this point configuration are assumed to be connected, not necessarily fine, not necessarily regular. sage: len(p.triangulations_list()) 4 - sage: PointConfiguration.set_engine('topcom') # optional - topcom + sage: PointConfiguration.set_engine('topcom') sage: p_all = p.restrict_to_connected_triangulations(connected=False) # optional - topcom sage: len(p_all.triangulations_list()) # optional - topcom 4 @@ -859,7 +848,6 @@ def restrict_to_connected_triangulations(self, connected=True): regular=self._regular, star=self._star) - def restrict_to_fine_triangulations(self, fine=True): """ Restrict to fine triangulations. @@ -876,7 +864,7 @@ def restrict_to_fine_triangulations(self, fine=True): EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) sage: p A point configuration in affine 2-space over Integer Ring consisting of 5 points. The triangulations of this point @@ -897,7 +885,6 @@ def restrict_to_fine_triangulations(self, fine=True): regular=self._regular, star=self._star) - def restrict_to_star_triangulations(self, star): """ Restrict to star triangulations with the given point as the @@ -918,8 +905,8 @@ def restrict_to_star_triangulations(self, star): EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) - sage: len(list( p.triangulations() )) + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) + sage: len(list(p.triangulations())) 4 sage: p_star = p.restrict_to_star_triangulations(0) sage: p_star is p.restrict_to_star_triangulations((0,0)) @@ -938,7 +925,6 @@ def restrict_to_star_triangulations(self, star): regular=self._regular, star=star) - def triangulations(self, verbose=False): r""" Returns all triangulations. @@ -954,7 +940,7 @@ def triangulations(self, verbose=False): EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) sage: iter = p.triangulations() sage: next(iter) (<1,3,4>, <2,3,4>) @@ -978,27 +964,28 @@ def triangulations(self, verbose=False): compute the triangulations. Using TOPCOM, we obtain the same triangulations but in a different order:: - sage: p.set_engine('topcom') # optional - topcom - sage: iter = p.triangulations() # optional - topcom - sage: next(iter) # optional - topcom + sage: # optional - topcom + sage: p.set_engine('topcom') + sage: iter = p.triangulations() + sage: next(iter) (<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>) - sage: next(iter) # optional - topcom + sage: next(iter) (<0,1,3>, <0,1,4>, <0,2,3>, <0,2,4>) - sage: next(iter) # optional - topcom + sage: next(iter) (<1,2,3>, <1,2,4>) - sage: next(iter) # optional - topcom + sage: next(iter) (<1,3,4>, <2,3,4>) - sage: p.triangulations_list() # optional - topcom + sage: p.triangulations_list() [(<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>), (<0,1,3>, <0,1,4>, <0,2,3>, <0,2,4>), (<1,2,3>, <1,2,4>), (<1,3,4>, <2,3,4>)] - sage: p_fine = p.restrict_to_fine_triangulations() # optional - topcom - sage: p_fine.set_engine('topcom') # optional - topcom - sage: p_fine.triangulations_list() # optional - topcom + sage: p_fine = p.restrict_to_fine_triangulations() + sage: p_fine.set_engine('topcom') + sage: p_fine.triangulations_list() [(<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>), (<0,1,3>, <0,1,4>, <0,2,3>, <0,2,4>)] - sage: p.set_engine('internal') # optional - topcom + sage: p.set_engine('internal') """ if self._use_TOPCOM: for triangulation in self._TOPCOM_triangulations(verbose): @@ -1012,7 +999,6 @@ def triangulations(self, verbose=False): for encoded_triangulation in ci: yield self(encoded_triangulation) - def triangulations_list(self, verbose=False): r""" Return all triangulations. @@ -1030,19 +1016,18 @@ def triangulations_list(self, verbose=False): EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1]]) + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1]]) sage: p.triangulations_list() [(<0,1,2>, <1,2,3>), (<0,1,3>, <0,2,3>)] sage: list(map(list, p.triangulations_list())) [[(0, 1, 2), (1, 2, 3)], [(0, 1, 3), (0, 2, 3)]] - sage: p.set_engine('topcom') # optional - topcom + sage: p.set_engine('topcom') sage: p.triangulations_list() # optional - topcom [(<0,1,2>, <1,2,3>), (<0,1,3>, <0,2,3>)] - sage: p.set_engine('internal') # optional - topcom + sage: p.set_engine('internal') """ return list(self.triangulations(verbose)) - def triangulate(self, verbose=False): r""" Return one (in no particular order) triangulation. @@ -1060,7 +1045,7 @@ def triangulate(self, verbose=False): EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) sage: p.triangulate() (<1,3,4>, <2,3,4>) sage: list( p.triangulate() ) @@ -1068,12 +1053,13 @@ def triangulate(self, verbose=False): Using TOPCOM yields a different, but equally good, triangulation:: - sage: p.set_engine('topcom') # optional - topcom - sage: p.triangulate() # optional - topcom + sage: # optional - topcom + sage: p.set_engine('topcom') + sage: p.triangulate() (<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>) - sage: list( p.triangulate() ) # optional - topcom + sage: list(p.triangulate()) [(0, 1, 2), (0, 1, 4), (0, 2, 4), (1, 2, 3)] - sage: p.set_engine('internal') # optional - topcom + sage: p.set_engine('internal') """ if self._use_TOPCOM and self._regular is not False: try: @@ -1092,14 +1078,13 @@ def triangulate(self, verbose=False): pass raise ValueError('No triangulation with the required properties.') - def convex_hull(self): """ Return the convex hull of the point configuration. EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) sage: p.convex_hull() A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices """ @@ -1145,21 +1130,22 @@ def restricted_automorphism_group(self): EXAMPLES:: - sage: pyramid = PointConfiguration([[1,0,0],[0,1,1],[0,1,-1],[0,-1,-1],[0,-1,1]]) - sage: G = pyramid.restricted_automorphism_group() - sage: G == PermutationGroup([[(3,5)], [(2,3),(4,5)], [(2,4)]]) + sage: pyramid = PointConfiguration([[1,0,0], [0,1,1], [0,1,-1], + ....: [0,-1,-1], [0,-1,1]]) + sage: G = pyramid.restricted_automorphism_group() # needs sage.graphs sage.groups + sage: G == PermutationGroup([[(3,5)], [(2,3),(4,5)], [(2,4)]]) # needs sage.graphs sage.groups True - sage: DihedralGroup(4).is_isomorphic(G) + sage: DihedralGroup(4).is_isomorphic(G) # needs sage.graphs sage.groups True The square with an off-center point in the middle. Note that the middle point breaks the restricted automorphism group `D_4` of the convex hull:: - sage: square = PointConfiguration([(3/4,3/4),(1,1),(1,-1),(-1,-1),(-1,1)]) - sage: square.restricted_automorphism_group() + sage: square = PointConfiguration([(3/4,3/4), (1,1), (1,-1), (-1,-1), (-1,1)]) + sage: square.restricted_automorphism_group() # needs sage.graphs sage.groups Permutation Group with generators [(3,5)] - sage: DihedralGroup(1).is_isomorphic(_) + sage: DihedralGroup(1).is_isomorphic(_) # needs sage.graphs sage.groups True """ v_list = [ vector(p.projective()) for p in self ] @@ -1192,13 +1178,14 @@ def face_codimension(self, point): P(1, 0) sage: triangle.face_codimension(2) 1 - sage: triangle.face_codimension( [1,0] ) + sage: triangle.face_codimension([1,0]) 1 This also works for degenerate cases like the tip of the pyramid over a square (which saturates four inequalities):: - sage: pyramid = PointConfiguration([[1,0,0],[0,1,1],[0,1,-1],[0,-1,-1],[0,-1,1]]) + sage: pyramid = PointConfiguration([[1,0,0], [0,1,1], [0,1,-1], + ....: [0,-1,-1], [0,-1,1]]) sage: pyramid.face_codimension(0) 3 """ @@ -1244,7 +1231,6 @@ def face_interior(self, dim=None, codim=None): return tuple( tuple(i for i in range(self.n_points()) if d[i]==codim ) for codim in range(self.dim()+1) ) - def exclude_points(self, point_idx_list): """ Return a new point configuration with the given points @@ -1268,7 +1254,7 @@ def exclude_points(self, point_idx_list): sage: q = p.exclude_points([3]) sage: list(q) [P(-1, 0), P(0, 0), P(1, -1), P(1, 1)] - sage: p.exclude_points( p.face_interior(codim=1) ).points() + sage: p.exclude_points(p.face_interior(codim=1)).points() (P(-1, 0), P(0, 0), P(1, -1), P(1, 1)) """ points = [self.point(i) for i in range(self.n_points()) @@ -1282,7 +1268,7 @@ def exclude_points(self, point_idx_list): def volume(self, simplex=None): """ - Find n! times the n-volume of a simplex of dimension n. + Find `n!` times the `n`-volume of a simplex of dimension `n`. INPUT: @@ -1291,16 +1277,16 @@ def volume(self, simplex=None): OUTPUT: - * If a simplex was passed as an argument: n!*(volume of ``simplex``). + * If a simplex was passed as an argument: `n!` * (volume of ``simplex``). - * Without argument: n!*(the total volume of the convex hull). + * Without argument: `n!` * (the total volume of the convex hull). EXAMPLES: The volume of the standard simplex should always be 1:: - sage: p = PointConfiguration([[0,0],[1,0],[0,1],[1,1]]) - sage: p.volume( [0,1,2] ) + sage: p = PointConfiguration([[0,0], [1,0], [0,1], [1,1]]) + sage: p.volume([0,1,2]) 1 sage: simplex = p.triangulate()[0] # first simplex of triangulation sage: p.volume(simplex) @@ -1314,9 +1300,9 @@ def volume(self, simplex=None): .. note:: - We return n!*(metric volume of the simplex) to ensure that + We return `n!` * (metric volume of the simplex) to ensure that the volume is an integer. Essentially, this normalizes - things so that the volume of the standard n-simplex is 1. + things so that the volume of the standard `n`-simplex is 1. See [GKZ1994]_ page 182. """ if (simplex is None): @@ -1328,7 +1314,6 @@ def volume(self, simplex=None): m = matrix([ v_i - v[0] for v_i in v[1:] ]) return abs(m.det()) - def secondary_polytope(self): r""" Calculate the secondary polytope of the point configuration. @@ -1348,7 +1333,7 @@ def secondary_polytope(self): EXAMPLES:: - sage: p = PointConfiguration([[0,0],[1,0],[2,1],[1,2],[0,1]]) + sage: p = PointConfiguration([[0,0], [1,0], [2,1], [1,2], [0,1]]) sage: poly = p.secondary_polytope() sage: poly.vertices_matrix() [1 1 3 3 5] @@ -1430,7 +1415,6 @@ def circuits_support(self): yield idx assert independent_k==[] # there are no independent (self.dim()+3)-tuples - def circuits(self): r""" Return the circuits of the point configuration. @@ -1462,7 +1446,7 @@ def circuits(self): EXAMPLES:: - sage: p = PointConfiguration([(0,0),(+1,0),(-1,0),(0,+1),(0,-1)]) + sage: p = PointConfiguration([(0,0), (+1,0), (-1,0), (0,+1), (0,-1)]) sage: sorted(p.circuits()) [((0,), (1, 2), (3, 4)), ((0,), (3, 4), (1, 2)), ((1, 2), (0,), (3, 4))] @@ -1477,7 +1461,7 @@ def circuits(self): ....: [ 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0] ....: ]) sage: p = PointConfiguration(U.columns()) - sage: len( p.circuits() ) # long time + sage: len(p.circuits()) # long time 218 """ try: @@ -1493,9 +1477,9 @@ def circuits(self): m = matrix([ U[i] for i in support ]).transpose() ker = m.right_kernel().basis()[0] assert len(ker)==len(support) - Cplus = [ support[i] for i in range(len(support)) if ker[i]>0 ] + Cplus = [ support[i] for i in range(len(support)) if ker[i]>0 ] Cminus = [ support[i] for i in range(len(support)) if ker[i]<0 ] - Czero = set( range(n) ).difference(support) + Czero = set( range(n) ).difference(support) Circuits += ( (tuple(Cplus), tuple(Czero), tuple(Cminus)), ) self._circuits = Circuits return Circuits @@ -1517,7 +1501,8 @@ def positive_circuits(self, *negative): EXAMPLES:: - sage: p = PointConfiguration([(1,0,0),(0,1,0),(0,0,1),(-2,0,-1),(-2,-1,0),(-3,-1,-1),(1,1,1),(-1,0,0),(0,0,0)]) + sage: p = PointConfiguration([(1,0,0), (0,1,0), (0,0,1), (-2,0,-1), (-2,-1,0), + ....: (-3,-1,-1), (1,1,1), (-1,0,0), (0,0,0)]) sage: sorted(p.positive_circuits(8)) [(0, 1, 2, 5), (0, 1, 4), (0, 2, 3), (0, 3, 4, 6), (0, 5, 6), (0, 7)] sage: p.positive_circuits(0,5,6) @@ -1534,7 +1519,6 @@ def positive_circuits(self, *negative): pos += ( Cpos, ) return pos - def bistellar_flips(self): r""" Return the bistellar flips. @@ -1551,9 +1535,9 @@ def bistellar_flips(self): sage: pc.bistellar_flips() (((<0,1,3>, <0,2,3>), (<0,1,2>, <1,2,3>)),) sage: Tpos, Tneg = pc.bistellar_flips()[0] - sage: Tpos.plot(axes=False) # optional - sage.plot + sage: Tpos.plot(axes=False) # needs sage.plot Graphics object consisting of 11 graphics primitives - sage: Tneg.plot(axes=False) # optional - sage.plot + sage: Tneg.plot(axes=False) # needs sage.plot Graphics object consisting of 11 graphics primitives The 3d analog:: @@ -1568,7 +1552,7 @@ def bistellar_flips(self): sage: pc.bistellar_flips() (((<0,1,3>, <0,2,3>), (<0,1,2>, <1,2,3>)),) sage: Tpos, Tneg = pc.bistellar_flips()[0] - sage: Tpos.plot(axes=False) # optional - sage.plot + sage: Tpos.plot(axes=False) # needs sage.plot Graphics3d Object """ flips = [] @@ -1591,13 +1575,13 @@ def lexicographic_triangulation(self): EXAMPLES:: - sage: p = PointConfiguration([(0,0),(+1,0),(-1,0),(0,+1),(0,-1)]) + sage: p = PointConfiguration([(0,0), (+1,0), (-1,0), (0,+1), (0,-1)]) sage: p.lexicographic_triangulation() (<1,3,4>, <2,3,4>) TESTS:: - sage: U=matrix([ + sage: U = matrix([ ....: [ 0, 0, 0, 0, 0, 2, 4,-1, 1, 1, 0, 0, 1, 0], ....: [ 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0], ....: [ 0, 2, 0, 0, 0, 0,-1, 0, 1, 0, 1, 0, 0, 1], @@ -1670,7 +1654,6 @@ def make_cotriang(basepts): return self(triangulation) - @cached_method def distance_affine(self, x, y): r""" @@ -1697,7 +1680,7 @@ def distance_affine(self, x, y): EXAMPLES:: sage: pc = PointConfiguration([(0,0),(1,0),(2,1),(1,2),(0,1)]) - sage: [ pc.distance_affine(pc.point(0), p) for p in pc.points() ] + sage: [pc.distance_affine(pc.point(0), p) for p in pc.points()] [0, 1, 5, 5, 1] """ self._assert_is_affine() @@ -1706,7 +1689,6 @@ def distance_affine(self, x, y): d += (xi-yi)**2 return d - @cached_method def distance_FS(self, x, y): r""" @@ -1733,8 +1715,8 @@ def distance_FS(self, x, y): EXAMPLES:: - sage: pc = PointConfiguration([(0,0),(1,0),(2,1),(1,2),(0,1)]) - sage: [ pc.distance_FS(pc.point(0), p) for p in pc.points() ] + sage: pc = PointConfiguration([(0,0), (1,0), (2,1), (1,2), (0,1)]) + sage: [pc.distance_FS(pc.point(0), p) for p in pc.points()] [0, 1/2, 5/6, 5/6, 1/2] """ x2 = y2 = xy = 0 @@ -1744,7 +1726,6 @@ def distance_FS(self, x, y): xy += xi*yi return 1-xy*xy/(x2*y2) - @cached_method def distance(self, x, y): """ @@ -1764,12 +1745,13 @@ def distance(self, x, y): EXAMPLES:: - sage: pc = PointConfiguration([(0,0),(1,0),(2,1),(1,2),(0,1)]) - sage: [ pc.distance(pc.point(0), p) for p in pc.points() ] + sage: pc = PointConfiguration([(0,0), (1,0), (2,1), (1,2), (0,1)]) + sage: [pc.distance(pc.point(0), p) for p in pc.points()] [0, 1, 5, 5, 1] - sage: pc = PointConfiguration([(0,0,1),(1,0,1),(2,1,1),(1,2,1),(0,1,1)], projective=True) - sage: [ pc.distance(pc.point(0), p) for p in pc.points() ] + sage: pc = PointConfiguration([(0,0,1), (1,0,1), (2,1,1), (1,2,1), (0,1,1)], + ....: projective=True) + sage: [pc.distance(pc.point(0), p) for p in pc.points()] [0, 1/2, 5/6, 5/6, 1/2] """ if self.is_affine(): @@ -1777,7 +1759,6 @@ def distance(self, x, y): else: return self.distance_FS(x,y) - def farthest_point(self, points, among=None): """ Return the point with the most distance from ``points``. @@ -1797,8 +1778,8 @@ def farthest_point(self, points, among=None): EXAMPLES:: - sage: pc = PointConfiguration([(0,0),(1,0),(1,1),(0,1)]) - sage: pc.farthest_point([ pc.point(0) ]) + sage: pc = PointConfiguration([(0,0), (1,0), (1,1), (0,1)]) + sage: pc.farthest_point([pc.point(0)]) P(1, 1) """ if len(points)==0: @@ -1818,7 +1799,6 @@ def farthest_point(self, points, among=None): p_max = p return p_max - def contained_simplex(self, large=True, initial_point=None, point_order=None): """ Return a simplex contained in the point configuration. @@ -1853,7 +1833,7 @@ def contained_simplex(self, large=True, initial_point=None, point_order=None): EXAMPLES:: - sage: pc = PointConfiguration([(0,0),(1,0),(2,1),(1,1),(0,1)]) + sage: pc = PointConfiguration([(0,0), (1,0), (2,1), (1,1), (0,1)]) sage: pc.contained_simplex() (P(0, 1), P(2, 1), P(1, 0)) sage: pc.contained_simplex(large=False) @@ -1861,23 +1841,23 @@ def contained_simplex(self, large=True, initial_point=None, point_order=None): sage: pc.contained_simplex(initial_point=pc.point(2)) (P(2, 1), P(0, 0), P(1, 0)) - sage: pc = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) + sage: pc = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) sage: pc.contained_simplex() (P(-1, -1), P(1, 1), P(0, 1)) - sage: pc.contained_simplex(point_order = [pc[1],pc[3],pc[4],pc[2],pc[0]]) + sage: pc.contained_simplex(point_order=[pc[1], pc[3], pc[4], pc[2], pc[0]]) (P(0, 1), P(1, 1), P(-1, -1)) Lower-dimensional example:: - sage: pc.contained_simplex(point_order = [pc[0],pc[3],pc[4]]) + sage: pc.contained_simplex(point_order=[pc[0], pc[3], pc[4]]) (P(0, 0), P(1, 1)) TESTS:: - sage: pc = PointConfiguration([[0,0],[0,1],[1,0]]) + sage: pc = PointConfiguration([[0,0], [0,1], [1,0]]) sage: pc.contained_simplex() (P(1, 0), P(0, 1), P(0, 0)) - sage: pc = PointConfiguration([[0,0],[0,1]]) + sage: pc = PointConfiguration([[0,0], [0,1]]) sage: pc.contained_simplex() (P(0, 1), P(0, 0)) sage: pc = PointConfiguration([[0,0]]) @@ -1921,7 +1901,6 @@ def contained_simplex(self, large=True, initial_point=None, point_order=None): ker = matrix(edges).right_kernel().matrix() return tuple(vertices) - def placing_triangulation(self, point_order=None): r""" Construct the placing (pushing) triangulation. @@ -1939,14 +1918,14 @@ def placing_triangulation(self, point_order=None): EXAMPLES:: - sage: pc = PointConfiguration([(0,0),(1,0),(2,1),(1,2),(0,1)]) + sage: pc = PointConfiguration([(0,0), (1,0), (2,1), (1,2), (0,1)]) sage: pc.placing_triangulation() (<0,1,2>, <0,2,4>, <2,3,4>) sage: pc.placing_triangulation(point_order=(3,2,1,4,0)) (<0,1,4>, <1,2,3>, <1,3,4>) - sage: pc.placing_triangulation(point_order=[pc[1],pc[3],pc[4],pc[0]]) + sage: pc.placing_triangulation(point_order=[pc[1], pc[3], pc[4], pc[0]]) (<0,1,4>, <1,3,4>) - sage: U=matrix([ + sage: U = matrix([ ....: [ 0, 0, 0, 0, 0, 2, 4,-1, 1, 1, 0, 0, 1, 0], ....: [ 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0], ....: [ 0, 2, 0, 0, 0, 0,-1, 0, 1, 0, 1, 0, 0, 1], @@ -1963,7 +1942,7 @@ def placing_triangulation(self, point_order=None): <3,4,6,7,11,12>, <3,4,7,11,12,13>, <3,6,7,11,12,13>, <4,6,7,11,12,13>) sage: sum(p.volume(t) for t in triangulation) 42 - sage: p0 = PointConfiguration([(0,0),(+1,0),(-1,0),(0,+1),(0,-1)]) + sage: p0 = PointConfiguration([(0,0), (+1,0), (-1,0), (0,+1), (0,-1)]) sage: p0.pushing_triangulation(point_order=[1,2,0,3,4]) (<1,2,3>, <1,2,4>) sage: p0.pushing_triangulation(point_order=[0,1,2,3,4]) @@ -1971,7 +1950,7 @@ def placing_triangulation(self, point_order=None): The same triangulation with renumbered points 0->4, 1->0, etc:: - sage: p1 = PointConfiguration([(+1,0),(-1,0),(0,+1),(0,-1),(0,0)]) + sage: p1 = PointConfiguration([(+1,0), (-1,0), (0,+1), (0,-1), (0,0)]) sage: p1.pushing_triangulation(point_order=[4,0,1,2,3]) (<0,2,4>, <0,3,4>, <1,2,4>, <1,3,4>) """ @@ -2081,7 +2060,7 @@ def Gale_transform(self, points=None): EXAMPLES:: - sage: pc = PointConfiguration([(0,0),(1,0),(2,1),(1,1),(0,1)]) + sage: pc = PointConfiguration([(0,0), (1,0), (2,1), (1,1), (0,1)]) sage: pc.Gale_transform() [ 1 -1 0 1 -1] [ 0 0 1 -2 1] @@ -2110,14 +2089,14 @@ def plot(self, **kwds): EXAMPLES:: - sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) - sage: p.plot(axes=False) # optional - sage.plot + sage: p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) + sage: p.plot(axes=False) # needs sage.plot Graphics object consisting of 5 graphics primitives .. PLOT:: :width: 300 px - p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) + p = PointConfiguration([[0,0], [0,1], [1,0], [1,1], [-1,-1]]) sphinx_plot(p.plot(axes=False)) """ return self.element_class([], parent=self, check=False).plot(**kwds) diff --git a/src/sage/geometry/triangulation/triangulations.cc b/src/sage/geometry/triangulation/triangulations.cc index 68e4efa75e1..8ea306d8f7c 100644 --- a/src/sage/geometry/triangulation/triangulations.cc +++ b/src/sage/geometry/triangulation/triangulations.cc @@ -117,7 +117,7 @@ triangulations_ptr init_triangulations compact_simplices seed; for (int i=0; i<PySequence_Size(py_seed); i++) { PyObject* simplex = PySequence_GetItem(py_seed,i); - seed.push_back(PyInt_AS_LONG(simplex)); + seed.push_back(PyLong_AsLong(simplex)); Py_DECREF(simplex); } @@ -133,7 +133,7 @@ triangulations_ptr init_triangulations vertices simplex; for (int k=0; k<PySequence_Size(py_simplex); k++) { PyObject* py_vertex = PySequence_GetItem(py_simplex,k); - simplex.insert(simplex.begin(), PyInt_AS_LONG(py_vertex)); + simplex.insert(simplex.begin(), PyLong_AsLong(py_vertex)); Py_DECREF(py_vertex); } pos.push_back(simplex); @@ -146,7 +146,7 @@ triangulations_ptr init_triangulations vertices simplex; for (int k=0; k<PySequence_Size(py_simplex); k++) { PyObject* py_vertex = PySequence_GetItem(py_simplex,k); - simplex.insert(simplex.begin(), PyInt_AS_LONG(py_vertex)); + simplex.insert(simplex.begin(), PyLong_AsLong(py_vertex)); Py_DECREF(py_vertex); } neg.push_back(simplex); @@ -195,7 +195,7 @@ PyObject* next_triangulation(triangulations_ptr t) const compact_simplices& triang = t->next_triangulation(); PyObject* py_triang = PyTuple_New(triang.size()); for (size_t i=0; i<triang.size(); i++) - PyTuple_SET_ITEM(py_triang, i, PyInt_FromLong(triang[i])); + PyTuple_SET_ITEM(py_triang, i, PyLong_FromLong(triang[i])); return py_triang; } diff --git a/src/sage/geometry/triangulation/triangulations.h b/src/sage/geometry/triangulation/triangulations.h index f42cef54725..3464bb62bff 100644 --- a/src/sage/geometry/triangulation/triangulations.h +++ b/src/sage/geometry/triangulation/triangulations.h @@ -4,9 +4,6 @@ #include "data.h" #include <Python.h> -#define PyInt_FromLong PyLong_FromLong -#define PyInt_AsLong PyLong_AsLong -#define PyInt_AS_LONG PyLong_AS_LONG class triangulations: public std::vector<compact_simplices> { diff --git a/src/sage/geometry/voronoi_diagram.py b/src/sage/geometry/voronoi_diagram.py index 1e9629aa646..0cea1e91377 100644 --- a/src/sage/geometry/voronoi_diagram.py +++ b/src/sage/geometry/voronoi_diagram.py @@ -51,18 +51,19 @@ class VoronoiDiagram(SageObject): Get the Voronoi diagram of a regular pentagon in ``AA^2``. All cells meet at the origin:: - sage: DV = VoronoiDiagram([[AA(c) for c in v] for v in polytopes.regular_polygon(5).vertices_list()]); DV # optional - sage.rings.number_field + sage: DV = VoronoiDiagram([[AA(c) for c in v] # needs sage.rings.number_field + ....: for v in polytopes.regular_polygon(5).vertices_list()]); DV The Voronoi diagram of 5 points of dimension 2 in the Algebraic Real Field - sage: all(P.contains([0, 0]) for P in DV.regions().values()) # optional - sage.rings.number_field + sage: all(P.contains([0, 0]) for P in DV.regions().values()) # needs sage.rings.number_field True - sage: any(P.interior_contains([0, 0]) for P in DV.regions().values()) # optional - sage.rings.number_field + sage: any(P.interior_contains([0, 0]) for P in DV.regions().values()) # needs sage.rings.number_field False If the vertices are not converted to ``AA`` before, the method throws an error:: - sage: polytopes.dodecahedron().vertices_list()[0][0].parent() # optional - sage.rings.number_field + sage: polytopes.dodecahedron().vertices_list()[0][0].parent() # needs sage.rings.number_field Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? - sage: VoronoiDiagram(polytopes.dodecahedron().vertices_list()) # optional - sage.rings.number_field + sage: VoronoiDiagram(polytopes.dodecahedron().vertices_list()) # needs sage.rings.number_field Traceback (most recent call last): ... NotImplementedError: Base ring of the Voronoi diagram must be @@ -230,9 +231,9 @@ def _repr_(self): EXAMPLES:: - sage: V = VoronoiDiagram(polytopes.regular_polygon(3).vertices()); V # optional - sage.rings.number_field + sage: V = VoronoiDiagram(polytopes.regular_polygon(3).vertices()); V # needs sage.rings.number_field The Voronoi diagram of 3 points of dimension 2 in the Algebraic Real Field - sage: VoronoiDiagram([]) # optional - sage.rings.number_field + sage: VoronoiDiagram([]) The empty Voronoi diagram. """ if self._n: @@ -260,18 +261,17 @@ def plot(self, cell_colors=None, **kwds): EXAMPLES:: - sage: P = [[0.671, 0.650], [0.258, 0.767], [0.562, 0.406], [0.254, 0.709], [0.493, 0.879]] - - sage: V = VoronoiDiagram(P); S=V.plot() # optional - sage.plot - sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) # optional - sage.plot - - sage: S=V.plot(cell_colors={0:'red', 1:'blue', 2:'green', 3:'white', 4:'yellow'}) # optional - sage.plot - sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) # optional - sage.plot - - sage: S=V.plot(cell_colors=['red','blue','red','white', 'white']) # optional - sage.plot - sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) # optional - sage.plot - - sage: S=V.plot(cell_colors='something else') # optional - sage.plot + sage: # needs sage.plot + sage: P = [[0.671, 0.650], [0.258, 0.767], [0.562, 0.406], + ....: [0.254, 0.709], [0.493, 0.879]] + sage: V = VoronoiDiagram(P); S=V.plot() + sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) + sage: S = V.plot(cell_colors={0: 'red', 1: 'blue', 2: 'green', + ....: 3: 'white', 4: 'yellow'}) + sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) + sage: S = V.plot(cell_colors=['red', 'blue', 'red', 'white', 'white']) + sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) + sage: S = V.plot(cell_colors='something else') Traceback (most recent call last): ... AssertionError: 'cell_colors' must be a list or a dictionary @@ -280,7 +280,7 @@ def plot(self, cell_colors=None, **kwds): Trying to plot a Voronoi diagram of dimension other than 2 gives an error:: - sage: VoronoiDiagram([[1, 2, 3], [6, 5, 4]]).plot() # optional - sage.plot + sage: VoronoiDiagram([[1, 2, 3], [6, 5, 4]]).plot() # needs sage.plot Traceback (most recent call last): ... NotImplementedError: Plotting of 3-dimensional Voronoi diagrams not diff --git a/src/sage/graphs/all.py b/src/sage/graphs/all.py index edb920f6897..2cbc65d0e23 100644 --- a/src/sage/graphs/all.py +++ b/src/sage/graphs/all.py @@ -4,7 +4,7 @@ lazy_import("sage.graphs.graph_generators", "graphs") lazy_import("sage.graphs.digraph_generators", "digraphs") lazy_import("sage.graphs.hypergraph_generators", "hypergraphs") -from .graph_database import GraphDatabase, GenericGraphQuery, GraphQuery +lazy_import("sage.graphs.graph_database", ["GraphDatabase", "GenericGraphQuery", "GraphQuery"]) from .graph import Graph from .digraph import DiGraph from .bipartite_graph import BipartiteGraph @@ -13,7 +13,7 @@ import sage.graphs.partial_cube from . import graph_list as graphs_list lazy_import("sage.graphs", "graph_coloring") -from .graph_database import graph_db_info +lazy_import("sage.graphs.graph_database", "graph_db_info") lazy_import("sage.graphs.graph_editor", "graph_editor") from sage.graphs.isgci import graph_classes diff --git a/src/sage/coding/__init__.py b/src/sage/graphs/all__sagemath_bliss.py similarity index 100% rename from src/sage/coding/__init__.py rename to src/sage/graphs/all__sagemath_bliss.py diff --git a/src/sage/coding/codecan/__init__.py b/src/sage/graphs/all__sagemath_mcqd.py similarity index 100% rename from src/sage/coding/codecan/__init__.py rename to src/sage/graphs/all__sagemath_mcqd.py diff --git a/src/sage/coding/guruswami_sudan/__init__.py b/src/sage/graphs/all__sagemath_tdlib.py similarity index 100% rename from src/sage/coding/guruswami_sudan/__init__.py rename to src/sage/graphs/all__sagemath_tdlib.py diff --git a/src/sage/graphs/base/__init__.py b/src/sage/graphs/base/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/coding/source_coding/__init__.py b/src/sage/graphs/base/all.py similarity index 100% rename from src/sage/coding/source_coding/__init__.py rename to src/sage/graphs/base/all.py diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index fb1c6c3acda..f158aaafd27 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -561,7 +561,7 @@ cpdef bandwidth_heuristics(g, algorithm='cuthill_mckee'): Given a wrong algorithm:: - from sage.graphs.base.boost_graph import bandwidth_heuristics + sage: from sage.graphs.base.boost_graph import bandwidth_heuristics sage: bandwidth_heuristics(graphs.PathGraph(3), algorithm='tip top') Traceback (most recent call last): ... @@ -569,10 +569,10 @@ cpdef bandwidth_heuristics(g, algorithm='cuthill_mckee'): Given a graph with no edges:: - from sage.graphs.base.boost_graph import bandwidth_heuristics + sage: from sage.graphs.base.boost_graph import bandwidth_heuristics sage: bandwidth_heuristics(Graph()) (0, []) - sage: bandwidth_heuristics(graphs.RandomGNM(10,0)) + sage: bandwidth_heuristics(graphs.RandomGNM(10,0)) # needs networkx (0, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) """ @@ -686,6 +686,16 @@ cpdef min_spanning_tree(g, Traceback (most recent call last): ... TypeError: float() argument must be a string or a... number... + + Check that the method is robust to incomparable vertices:: + + sage: G = Graph([(1, 2, 10), (1, 'a', 1), ('a', 'b', 1), ('b', 2, 1)], weighted=True) + sage: E = min_spanning_tree(G, algorithm='Kruskal') + sage: sum(w for _, _, w in E) + 3 + sage: F = min_spanning_tree(G, algorithm='Prim') + sage: sum(w for _, _, w in F) + 3 """ from sage.graphs.graph import Graph @@ -719,9 +729,8 @@ cpdef min_spanning_tree(g, if <v_index> result.size() != 2 * (n - 1): return [] - else: - edges = [(int_to_vertex[<int> result[2*i]], int_to_vertex[<int> result[2*i + 1]]) for i in range(n - 1)] - return [(min(e[0], e[1]), max(e[0], e[1]), g.edge_label(e[0], e[1])) for e in edges] + edges = [(int_to_vertex[<int> result[2*i]], int_to_vertex[<int> result[2*i + 1]]) for i in range(n - 1)] + return [(u, v, g.edge_label(u, v)) for u, v in edges] cpdef blocks_and_cut_vertices(g): @@ -1183,7 +1192,6 @@ cpdef johnson_shortest_paths(g, weight_function=None, distances=True, predecesso cdef BoostVecWeightedGraph g_boost_und cdef int N = g.num_verts() cdef vector[vector[double]] result - cdef int u_int, v_int if g.is_directed(): boost_weighted_graph_from_sage_graph(&g_boost_dir, g, v_to_int, weight_function) @@ -1340,7 +1348,6 @@ cpdef floyd_warshall_shortest_paths(g, weight_function=None, distances=True, pre cdef BoostVecWeightedGraph g_boost_und cdef int N = g.num_verts() cdef vector[vector[double]] result - cdef int u_int, v_int if g.is_directed(): boost_weighted_graph_from_sage_graph(&g_boost_dir, g, v_to_int, weight_function) @@ -1966,8 +1973,8 @@ cpdef diameter_DHV(g, weight_function=None, check_weight=True): TESTS:: - sage: G = graphs.RandomBarabasiAlbert(17,6) - sage: diameter_DHV(G) == G.diameter(algorithm = 'Dijkstra_Boost') + sage: G = graphs.RandomBarabasiAlbert(17,6) # needs networkx + sage: diameter_DHV(G) == G.diameter(algorithm = 'Dijkstra_Boost') # needs networkx True sage: G = Graph([(0,1,-1)], weighted=True) sage: diameter_DHV(G) @@ -2330,13 +2337,13 @@ cdef double diameter_DiFUB(BoostVecWeightedDiGraphU g_boost, import sys # These variables are automatically deleted when the function terminates. cdef double LB, LB_1, LB_2, UB - cdef v_index s, m, d, v, tmp + cdef v_index m, v, tmp cdef v_index i cdef vector[double] distances cdef vector[pair[double, v_index]] order_1, order_2 # We select a vertex with low eccentricity using 2Dsweep - LB, s, m, d = diameter_lower_bound_2Dsweep(g_boost, rev_g_boost, + LB, _, m, _ = diameter_lower_bound_2Dsweep(g_boost, rev_g_boost, source, algorithm) # If the lower bound is a very large number, it means that the digraph is @@ -2969,7 +2976,6 @@ cpdef wiener_index(g, algorithm=None, weight_function=None, check_weight=True): # These variables are automatically deleted when the function terminates. cdef v_index vi, u, v - cdef dict int_to_v = dict(enumerate(g)) cdef dict v_to_int = {vv: vi for vi, vv in enumerate(g)} cdef BoostVecWeightedDiGraphU g_boost_dir cdef BoostVecWeightedGraph g_boost_und diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index ae5461c72df..79e62e13a33 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -44,7 +44,7 @@ method :meth:`realloc <sage.graphs.base.c_graph.CGraph.realloc>`. # **************************************************************************** from sage.data_structures.bitset_base cimport * -from sage.rings.integer cimport Integer, smallInteger +from sage.rings.integer cimport smallInteger from sage.arith.long cimport pyobject_to_long from libcpp.queue cimport priority_queue, queue from libcpp.stack cimport stack @@ -1576,6 +1576,7 @@ cdef class CGraphBackend(GenericGraphBackend): We check that the bug described in :trac:`8406` is gone:: + sage: # needs sage.rings.finite_rings sage: G = Graph() sage: R.<a> = GF(3**3) sage: S.<x> = R[] @@ -2107,9 +2108,9 @@ cdef class CGraphBackend(GenericGraphBackend): Ensure that :trac:`13664` is fixed :: - sage: W = WeylGroup(["A",1]) - sage: G = W.cayley_graph() - sage: Graph(G).degree() + sage: W = WeylGroup(["A",1]) # needs sage.combinat sage.groups + sage: G = W.cayley_graph() # needs sage.combinat sage.groups + sage: Graph(G).degree() # needs sage.combinat sage.groups [1, 1] sage: h = Graph() sage: h.add_edge(1,2,"a") @@ -3751,7 +3752,6 @@ cdef class CGraphBackend(GenericGraphBackend): # studied. cdef int x_int = self.get_vertex(x) cdef int y_int = self.get_vertex(y) - cdef int u = 0 cdef int v = 0 cdef int w = 0 cdef int pred @@ -3978,7 +3978,6 @@ cdef class CGraphBackend(GenericGraphBackend): # studied. cdef int x_int = self.get_vertex(x) cdef int y_int = self.get_vertex(y) - cdef int u = 0 cdef int v = 0 cdef int w = 0 cdef int pred @@ -4408,9 +4407,9 @@ cdef class CGraphBackend(GenericGraphBackend): TESTS:: - sage: P = posets.PentagonPoset() - sage: H = P._hasse_diagram - sage: H._backend.is_connected() + sage: P = posets.PentagonPoset() # needs sage.modules + sage: H = P._hasse_diagram # needs sage.modules + sage: H._backend.is_connected() # needs sage.modules True """ cdef int v_int @@ -4550,7 +4549,7 @@ cdef class CGraphBackend(GenericGraphBackend): At first, the following graph is acyclic:: sage: D = DiGraph({ 0:[1,2,3], 4:[2,5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10] }) - sage: D.plot(layout='circular').show() + sage: D.plot(layout='circular').show() # needs sage.plot sage: D.is_directed_acyclic() True @@ -4586,14 +4585,14 @@ cdef class CGraphBackend(GenericGraphBackend): ....: return h ... sage: all( random_acyclic(100, .2).is_directed_acyclic() # long time - ....: for i in range(50)) # long time + ....: for i in range(50)) True TESTS:: - sage: m = Matrix(3,[0, 1, 1, 0, 0, 0, 0, 1, 0]) - sage: g = DiGraph(m) - sage: g.is_directed_acyclic(certificate=True) + sage: m = Matrix(3,[0, 1, 1, 0, 0, 0, 0, 1, 0]) # needs sage.modules + sage: g = DiGraph(m) # needs sage.modules + sage: g.is_directed_acyclic(certificate=True) # needs sage.modules (True, [0, 2, 1]) """ if not self._directed: @@ -4680,7 +4679,6 @@ cdef class CGraphBackend(GenericGraphBackend): # // answer = [u] cycle = [self.vertex_label(u)] - tmp = u while u != uu: u = parent.get(u, uu) cycle.append(self.vertex_label(u)) @@ -4822,7 +4820,7 @@ cdef class Search_iterator: Immutable graphs (see :trac:`16019`):: - sage: DiGraph([[1,2]], immutable=True).connected_components() + sage: DiGraph([(1, 2)], immutable=True).connected_components(sort=True) [[1, 2]] """ @@ -4899,7 +4897,7 @@ cdef class Search_iterator: sage: next(g.breadth_first_search(0)) 0 """ - cdef int v_int, v_dist + cdef int v_int cdef int w_int cdef int l cdef CGraph cg = self.graph.cg() diff --git a/src/sage/graphs/base/dense_graph.pyx b/src/sage/graphs/base/dense_graph.pyx index cd0aa5cf5a0..9cb0a1676ae 100644 --- a/src/sage/graphs/base/dense_graph.pyx +++ b/src/sage/graphs/base/dense_graph.pyx @@ -236,17 +236,15 @@ cdef class DenseGraph(CGraph): sage: D.realloc(30) sage: D.current_allocation() 30 - """ - cdef int i, j + cdef int i if not total_verts: raise RuntimeError('dense graphs must allocate space for vertices') cdef bitset_t bits - cdef int min_verts, min_longs + cdef int min_verts if <size_t>total_verts < self.active_vertices.size: min_verts = total_verts - min_longs = -1 bitset_init(bits, self.active_vertices.size) bitset_set_first_n(bits, total_verts) if not bitset_issubset(self.active_vertices, bits): @@ -402,7 +400,7 @@ cdef class DenseGraph(CGraph): """ cdef int num_arcs_old = self.num_arcs - cdef size_t i, j + cdef size_t i i = bitset_next(self.active_vertices, 0) while i != -1: self.add_arc_unsafe(i, i) diff --git a/src/sage/graphs/base/graph_backends.pyx b/src/sage/graphs/base/graph_backends.pyx index 3ff36d5cee2..c0ffc56533e 100644 --- a/src/sage/graphs/base/graph_backends.pyx +++ b/src/sage/graphs/base/graph_backends.pyx @@ -47,7 +47,6 @@ For an overview of graph data structures in sage, see Classes and methods ------------------- """ - # **************************************************************************** # Copyright (C) 2008 Robert L. Miller <rlmillster@gmail.com> # 2018 Julian Rรผth <julian.rueth@fsfe.org> @@ -58,8 +57,7 @@ Classes and methods # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - -from .c_graph cimport CGraphBackend, CGraph +from .c_graph cimport CGraphBackend cdef class GenericGraphBackend(SageObject): diff --git a/src/sage/graphs/base/sparse_graph.pxd b/src/sage/graphs/base/sparse_graph.pxd index c6f40497b16..719ad0ef8c9 100644 --- a/src/sage/graphs/base/sparse_graph.pxd +++ b/src/sage/graphs/base/sparse_graph.pxd @@ -1,12 +1,12 @@ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008-2009 Robert L. Miller <rlmillster@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from .c_graph cimport CGraph, CGraphBackend cimport cython @@ -23,6 +23,7 @@ cdef struct SparseGraphBTNode: SparseGraphBTNode *left SparseGraphBTNode *right + @cython.final cdef class SparseGraph(CGraph): cdef int hash_length diff --git a/src/sage/graphs/base/sparse_graph.pyx b/src/sage/graphs/base/sparse_graph.pyx index 491f679e9c9..714da06e519 100644 --- a/src/sage/graphs/base/sparse_graph.pyx +++ b/src/sage/graphs/base/sparse_graph.pyx @@ -1009,10 +1009,9 @@ cdef class SparseGraph(CGraph): - a pointer to the first label or ``NULL`` if there are none """ - cdef int i = (u * self.hash_length) + (v & self.hash_mask), j - cdef int compared, num_arcs + cdef int i = (u * self.hash_length) + (v & self.hash_mask) + cdef int compared cdef SparseGraphBTNode *temp = self.vertices[i] - cdef SparseGraphLLNode *label while temp: compared = compare(temp.vertex, v) if compared > 0: diff --git a/src/sage/graphs/base/static_dense_graph.pyx b/src/sage/graphs/base/static_dense_graph.pyx index f14ebf789cc..2014289457d 100644 --- a/src/sage/graphs/base/static_dense_graph.pyx +++ b/src/sage/graphs/base/static_dense_graph.pyx @@ -49,6 +49,9 @@ Functions """ from sage.data_structures.binary_matrix cimport * from cysignals.signals cimport sig_on, sig_off, sig_check +from memory_allocator cimport MemoryAllocator +from itertools import product +from sage.misc.flatten import flatten cdef dict dense_graph_init(binary_matrix_t m, g, translation=None, force_undirected=False): @@ -213,7 +216,7 @@ def is_strongly_regular(g, parameters=False): cdef bitset_t b_tmp cdef int n = g.order() cdef int inter - cdef int i, j, l, k + cdef int i, j, k if not g.order() or not g.size(): # no vertices or no edges return False @@ -378,9 +381,374 @@ def triangles_count(G): return ans -def connected_subgraph_iterator(G, k=None, bint vertices_only=False): +def _format_result(G, edges, edges_only, labels): r""" - Iterator over the induced connected subgraphs of order at most `k`. + Helper method for ``connected_full_subgraphs`` to return a result. + + INPUT: + + - ``G`` -- a :class:`DiGraph` + + - ``edges`` -- list of edges ignoring the orientation + + - ``edges_only`` -- boolean; whether to return DiGraph or list of vertices + + - ``labels`` -- boolean; whether to return labelled edges or not. This + parameter is used only when ``edges_only`` is ``True``. + + EXAMPLES: + + The complete graph of order 3 has 4 connected subgraphs:: + + sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs + sage: G = graphs.CompleteGraph(3) + sage: len(list(connected_full_subgraphs(G))) + 4 + """ + if edges_only: + if labels: + return [(u, v, G.edge_label(u, v)) for u, v in edges] + else: + return edges + else: + return G.subgraph(vertices=G, edges=edges) + + +def _yield_results_for_digraph(G, edges, edges_only, labels, min_edges, max_edges): + r""" + Helper method for ``connected_full_subgraphs`` to yield all subdigraphs. + + INPUT: + + - ``G`` -- a :class:`DiGraph` + + - ``edges`` -- list of edges ignoring the orientation + + - ``edges_only`` -- boolean; whether to return DiGraph or list of vertices + + - ``labels`` -- boolean; whether to return labelled edges or not. This + parameter is used only when ``edges_only`` is ``True``. + + - ``min_edges`` -- integer; minimum number of edges of reported subgraphs + + - ``max_edges`` -- integer; maximum number of edges of reported subgraphs + + EXAMPLES:: + + sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs + sage: G = digraphs.Complete(3) + sage: len(list(connected_full_subgraphs(G))) + 54 + """ + if not edges: + return + L = [] + for u, v in edges: + tmp = [] + if G.has_edge(u, v): + tmp.append([(u, v)]) + if G.has_edge(v, u): + tmp.append([(v, u)]) + if G.has_edge(u, v): + tmp.append([(u, v), (v, u)]) + L.append(tmp) + + if len(L) == 1: + for F in L[0]: + if min_edges <= len(F) and len(F) <= max_edges: + yield _format_result(G, F, edges_only, labels) + else: + for E in product(*L): + F = [e for le in E for e in le] + if min_edges <= len(F) and len(F) <= max_edges: + yield _format_result(G, F, edges_only, labels) + return + + +def connected_full_subgraphs(G, edges_only=False, labels=False, + min_edges=None, max_edges=None): + r""" + Return an iterator over the connected subgraphs of `G` with same vertex set. + + This method implements a iterator over the connected subgraphs of the input + (di)graph with the same ground set of vertices. That is, it iterates over + every subgraph `H = (V_H, E_H)` of `G = (V, E)` such that `V_H = V`, + `E_H \subseteq E` and `H` is connected. Hence, this method may yield a huge + number of graphs. + + When the input (di)graph `G` is not connected, this method returns nothing. + + As for method :meth:`sage.graphs.generic_graph.connected_components`, edge + orientation is ignored. Hence, the directed graph with a single arc `0 \to + 1` is considered connected. + + INPUT: + + - ``G`` -- a :class:`Graph` or a :class:`DiGraph`; loops and multiple edges + are *not* allowed + + - ``edges_only`` -- boolean (default: ``False``); whether to return + (Di)Graph or list of vertices + + - ``labels`` -- boolean (default: ``False``); whether to return labelled + edges or not. This parameter is used only when ``edges_only`` is ``True``. + + - ``min_edges`` -- integer (default: ``None``); minimum number of edges of + reported subgraphs. By default (``None``), this lower bound will be set to + `n - 1`. + + - ``max_edges`` -- integer (default: ``None``); maximum number of edges of + reported subgraphs. By default (``None``), this lower bound will be set to + the number of edges of the input (di)graph. + + .. NOTE:: + + Roughly, this method explores all possible subsets of neighbors of each + vertex, which represents a huge number of subsets. We have thus chosen + to limit the degree of the vertices of the graphs that can be + considered, even if the graph has a single connected subgraph (e.g., a + tree). It is therefore recommended to call this method on biconnected + components, as done in :meth:`connected_subgraph_iterator`. + + EXAMPLES: + + The complete graph of order 3 has 4 connected subgraphs:: + + sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs + sage: G = graphs.CompleteGraph(3) + sage: len(list(connected_full_subgraphs(G))) + 4 + + A cycle of order 5 has 6 connected subgraphs:: + + sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs + sage: G = graphs.CycleGraph(5) + sage: len(list(connected_full_subgraphs(G))) + 6 + + The House graph has 18 connected subgraphs of order 5:: + + sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs + sage: G = graphs.HouseGraph() + sage: L = list(connected_full_subgraphs(G)) + sage: len(L) + 18 + sage: all(g.order() == 5 for g in L) + True + sage: all(g.is_connected() for g in L) + True + sage: F = frozenset(frozenset(g.edges(sort=False, labels=False)) for g in L) + sage: len(F) + 18 + + Specifying bounds on the number of edges:: + + sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs + sage: G = graphs.HouseGraph() + sage: [g.size() for g in connected_full_subgraphs(G)] + [6, 5, 5, 5, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4] + sage: [g.size() for g in connected_full_subgraphs(G, max_edges=4)] + [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4] + sage: [g.size() for g in connected_full_subgraphs(G, min_edges=6)] + [6] + sage: [g.size() for g in connected_full_subgraphs(G, min_edges=5, max_edges=5)] + [5, 5, 5, 5, 5, 5] + + Asking for edges only:: + + sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs + sage: G = Graph([(0, 1, "01"), (0, 2, "02"), (1, 2, "12")]) + sage: it = connected_full_subgraphs(G, edges_only=True) + sage: next(it) + [(0, 1), (0, 2), (1, 2)] + sage: next(it) + [(0, 1), (0, 2)] + sage: it = connected_full_subgraphs(G, edges_only=True, labels=True) + sage: next(it) + [(0, 1, '01'), (0, 2, '02'), (1, 2, '12')] + sage: next(it) + [(0, 1, '01'), (0, 2, '02')] + + Subgraphs of a digraph:: + + sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs + sage: G = digraphs.Complete(2) + sage: list(connected_full_subgraphs(G, edges_only=True)) + [[(0, 1)], [(1, 0)], [(0, 1), (1, 0)]] + + TESTS: + + Non connected input graph:: + + sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs + sage: list(connected_full_subgraphs(Graph(2))) + Traceback (most recent call last): + ... + ValueError: the input (di)graph is not connected + + Too large degree:: + + sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs + sage: G = graphs.StarGraph(100) + sage: list(connected_full_subgraphs(G)) + Traceback (most recent call last): + ... + ValueError: the degree of the graph is too large for this method + + Wrong bounds on the number of edges:: + + sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs + sage: G = graphs.HouseGraph() + sage: [g.size() for g in connected_full_subgraphs(G, min_edges=G.size() + 1)] + Traceback (most recent call last): + ... + ValueError: we must have 4 <= min_edges <= max_edges <= 6 + sage: [g.size() for g in connected_full_subgraphs(G, max_edges=G.order() - 2)] + Traceback (most recent call last): + ... + ValueError: we must have 4 <= min_edges <= max_edges <= 6 + """ + G._scream_if_not_simple() + if not G.is_connected(): + raise ValueError("the input (di)graph is not connected") + + for d in G.degree(): + if d >= 8 * sizeof(unsigned long) - 1: + raise ValueError("the degree of the graph is too large for this method") + + cdef Py_ssize_t n = G.order() + cdef Py_ssize_t m = G.size() + if min_edges is None or min_edges < n - 1: + min_edges = n - 1 + if max_edges is None or max_edges > m: + max_edges = m + if min_edges > max_edges: + raise ValueError("we must have {} <= min_edges <= max_edges <= {}".format(n -1, m)) + + if n <= 1 or (not G.is_directed() and n == 2) or min_edges == m: + if edges_only: + yield list(G.edges(sort=False, labels=labels)) + else: + yield G.copy() + return + + # We map vertices to integers. We sort them by degree as a heuristic to + # reduce the number of operations. + cdef list int_to_vertex = sorted(G, key=G.degree) + cdef binary_matrix_t DG + sig_on() + dense_graph_init(DG, G, translation=int_to_vertex, force_undirected=True) + + cdef MemoryAllocator mem = MemoryAllocator() + cdef int * order = <int *> mem.calloc(n, sizeof(int)) + cdef mp_bitcnt_t * n_cpt = <mp_bitcnt_t *> mem.calloc(n, sizeof(mp_bitcnt_t)) + + # We use several bitsets to store the current boundary and active neighbors. + # We also need another bitset that we create at the same time + cdef binary_matrix_t boundaries + binary_matrix_init(boundaries, n + 1, n) + cdef binary_matrix_t neighborhoods + binary_matrix_init(neighborhoods, n, n) + sig_off() + + cdef bitset_t active = boundaries.rows[n] # remaining vertices to consider + cdef bitset_t boundary # neighbors of the current subset + + # Initialize the process + cdef Py_ssize_t i = 0 + order[0] = 0 + bitset_complement(active, active) + bitset_discard(active, 0) + bitset_copy(neighborhoods.rows[0], DG.rows[0]) + n_cpt[0] = 1 << bitset_len(DG.rows[0]) + + cdef long u, v, j + cdef mp_bitcnt_t c + cdef Py_ssize_t num_edges = 0 + cdef list E = [] + cdef list edges + + while i >= 0: + sig_check() + if i == n - 1 and num_edges >= min_edges: + # yield the current solution + edges = [(int_to_vertex[u], int_to_vertex[v]) for le in E for u, v in le] + if G.is_directed(): + yield from _yield_results_for_digraph(G, edges, edges_only, labels, min_edges, max_edges) + else: + yield _format_result(G, edges, edges_only, labels) + + if n_cpt[i] > 1: + # Consider the next neighborhood of the current vertex. + # If vertex u has k active neighbors, we have 2^k possibilities. We + # use the binary representation of n_cpt[i] to indicate which of the + # k neighbors are selected. We omit the empty neighborhood which is + # considered elsewhere. + n_cpt[i] -= 1 + c = n_cpt[i] + if num_edges + _bitset_len(&c, 1) > max_edges: + # Too many edges + continue + + boundary = boundaries.rows[i + 1] + bitset_copy(boundary, boundaries.rows[i]) + edges = [] + j = bitset_first(neighborhoods.rows[i]) + while c and j != -1: + if c & 1: + bitset_add(boundary, j) + edges.append((order[i], j)) + c >>= 1 + j = bitset_next(neighborhoods.rows[i], j + 1) + + if not bitset_len(boundary): + # We cannot extend + continue + + E.append(edges) + num_edges += len(edges) + # otherwise, we select a vertex from the boundary and extend the order + + elif bitset_len(boundaries.rows[i]): + # We prepare the boundary for the selection of the next vertex. + # This is equivalant to consider an empty neighborhood. + bitset_copy(boundaries.rows[i + 1], boundaries.rows[i]) + bitset_clear(boundaries.rows[i]) # to prevent doing twice this operation + E.append([]) + + else: + # We have considered all possible extensions + bitset_add(active, order[i]) + i -= 1 + if E: + num_edges -= len(E[-1]) + E.pop() + continue + + # We select a vertex from the boundary to add to the order + i += 1 + boundary = boundaries.rows[i] + u = bitset_first(boundary) + order[i] = u + bitset_discard(boundary, u) + bitset_discard(active, u) + # prepare neighborhood of u + bitset_and(neighborhoods.rows[i], active, DG.rows[u]) + j = bitset_len(neighborhoods.rows[i]) + n_cpt[i] = bool(j) << j # 0 if not j else 2^j + + sig_on() + binary_matrix_free(boundaries) + binary_matrix_free(neighborhoods) + binary_matrix_free(DG) + sig_off() + + +def connected_subgraph_iterator(G, k=None, bint vertices_only=False, + edges_only=False, labels=False, induced=True, + exactly_k=False): + r""" + Return an terator over the induced connected subgraphs of order at most `k`. This method implements a iterator over the induced connected subgraphs of the input (di)graph. An induced subgraph of a graph is another graph, formed @@ -401,7 +769,24 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False): (equivalent to ``k == n``) - ``vertices_only`` -- boolean (default: ``False``); whether to return - (Di)Graph or list of vertices + (Di)Graph or list of vertices. This parameter is ignored when ``induced`` + is ``True``. + + - ``edges_only`` -- boolean (default: ``False``); whether to + return (Di)Graph or list of edges. When ``vertices_only`` is + ``True``, this parameter is ignored. + + - ``labels`` -- boolean (default: ``False``); whether to return labelled + edges or not. This parameter is used only when ``vertices_only`` is + ``False`` and ``edges_only`` is ``True``. + + - ``induced`` -- boolean (default: ``True``); whether to return induced + connected sub(di)graph only or also non-induced sub(di)graphs. + This parameter can be set to ``False`` for simple (di)graphs only. + + - ``exactly_k`` -- boolean (default: ``False``); ``True`` if we only + return graphs of order `k`, ``False`` if we return graphs of order + at most `k`. EXAMPLES:: @@ -431,6 +816,8 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False): Subgraph of (): Digraph on 1 vertex, Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 1 vertex] + sage: list(G.connected_subgraph_iterator(k=3, vertices_only=True, exactly_k=True)) + [[1, 2, 3], [1, 2, 4], [2, 3, 4]] sage: list(G.connected_subgraph_iterator(k=2, vertices_only=True)) [[1], [1, 2], [2], [2, 3], [2, 4], [3], [3, 4], [4]] @@ -442,6 +829,26 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False): sage: list(G.connected_subgraph_iterator(vertices_only=True)) [[1], [1, 2], [2]] + sage: G = graphs.CompleteGraph(3) + sage: len(list(G.connected_subgraph_iterator())) + 7 + sage: len(list(G.connected_subgraph_iterator(vertices_only=True))) + 7 + sage: len(list(G.connected_subgraph_iterator(edges_only=True))) + 7 + sage: len(list(G.connected_subgraph_iterator(induced=False))) + 10 + + sage: G = DiGraph([(0, 1), (1, 0), (1, 2), (2, 1)]) + sage: len(list(G.connected_subgraph_iterator())) + 6 + sage: len(list(G.connected_subgraph_iterator(vertices_only=True))) + 6 + sage: len(list(G.connected_subgraph_iterator(edges_only=True))) + 6 + sage: len(list(G.connected_subgraph_iterator(induced=False))) + 18 + TESTS: The Path Graph of order `n` has `n (n + 1) / 2` connected subgraphs:: @@ -482,6 +889,10 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False): sage: len(list(G.connected_subgraph_iterator(vertices_only=True))) 3 """ + if not induced: + G._scream_if_not_simple() + vertices_only = False + cdef Py_ssize_t mk = G.order() if k is None else k cdef Py_ssize_t n = G.order() if not n or mk < 1: @@ -508,6 +919,7 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False): cdef Py_ssize_t level cdef Py_ssize_t u, v, a + cdef list vertices # We first generate subsets containing vertex 0, then the subsets containing # vertex 1 but not vertex 0 since we have already generated all subsets @@ -515,10 +927,16 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False): for u in range(n): sig_check() - if vertices_only: - yield [int_to_vertex[u]] - else: - yield G.subgraph([int_to_vertex[u]]) + vertices = [int_to_vertex[u]] + if not exactly_k or mk == 1: + if vertices_only: + yield vertices + else: + H = G.subgraph(vertices) + if edges_only: + yield H.edges(sort=False, labels=labels) + else: + yield H # We initialize the loop with vertices u in current, {u+1, ..., n-1} # in left, and N(u) in boundary @@ -558,12 +976,48 @@ def connected_subgraph_iterator(G, k=None, bint vertices_only=False): bitset_union(stack.rows[level + 2], boundary, DG.rows[v]) # We yield that new subset - if vertices_only: - yield [int_to_vertex[a] for a in range(u, n) - if bitset_in(stack.rows[level], a)] - else: - yield G.subgraph([int_to_vertex[a] for a in range(u, n) - if bitset_in(stack.rows[level], a)]) + vertices = [int_to_vertex[a] for a in range(u, n) + if bitset_in(stack.rows[level], a)] + if not exactly_k or bitset_len(current) == mk - 1: + if vertices_only: + yield vertices + else: + H = G.subgraph(vertices) + if induced: + if edges_only: + yield H.edges(sort=False, labels=labels) + else: + yield H + else: + # We use a decomposition into biconnected components to + # work on smaller graphs. + if H.is_directed(): + blocks = H.to_undirected().blocks_and_cut_vertices()[0] + else: + blocks = H.blocks_and_cut_vertices()[0] + if len(blocks) == 1: + # H is strongly connected or biconnected + yield from connected_full_subgraphs(H, edges_only=edges_only, + labels=labels) + else: + L = [] + for bloc in blocks: + if len(bloc) == 2: + bb = [[e] for e in H.edge_boundary(bloc, bloc, labels=labels)] + if len(bb) == 2: + # H is directed with edges (u, v) and (v, u) + bb.append(H.edge_boundary(bloc, bloc, labels=labels)) + L.append(bb) + else: + L.append(connected_full_subgraphs(H.subgraph(vertices=bloc), + edges_only=True, labels=labels)) + + for edges in product(*L): + good_edges = flatten(edges, ltypes=list) + if edges_only: + yield list(good_edges) + else: + yield H.subgraph(vertices=H, edges=good_edges) else: # We cannot extend the current subset, either due to a lack of diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index ebd1539101a..2eecc1a69d0 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -446,6 +446,7 @@ cdef class StaticSparseBackend(CGraphBackend): :: + sage: # needs sage.combinat sage: g = DiGraph(digraphs.DeBruijn(4, 3), data_structure="static_sparse") sage: gi = DiGraph(g, data_structure="static_sparse") sage: gi.edges(sort=True)[0] @@ -456,7 +457,7 @@ cdef class StaticSparseBackend(CGraphBackend): ('111', '112', '2'), ('111', '113', '3')] - sage: set(g.edges(sort=False)) == set(gi.edges(sort=False)) + sage: set(g.edges(sort=False)) == set(gi.edges(sort=False)) # needs sage.combinat True :: @@ -671,10 +672,10 @@ cdef class StaticSparseBackend(CGraphBackend): :: sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend - sage: g = StaticSparseBackend(digraphs.DeBruijn(3, 2)) - sage: g.has_edge('00', '01', '1') + sage: g = StaticSparseBackend(digraphs.DeBruijn(3, 2)) # needs sage.combinat + sage: g.has_edge('00', '01', '1') # needs sage.combinat True - sage: g.has_edge('00', '01', '0') + sage: g.has_edge('00', '01', '0') # needs sage.combinat False """ try: @@ -684,7 +685,6 @@ cdef class StaticSparseBackend(CGraphBackend): raise LookupError("one of the two vertices does not belong to the graph") cdef StaticSparseCGraph cg = self._cg - cdef list l cdef uint32_t * edge = has_edge(cg.g, u, v) if not edge: @@ -696,9 +696,7 @@ cdef class StaticSparseBackend(CGraphBackend): # all labels. if self.multiple_edges(None): return self._all_edge_labels(u, v, edge) - - else: - return edge_label(cg.g, edge) + return edge_label(cg.g, edge) cdef inline list _all_edge_labels(self, int u, int v, uint32_t* edge=NULL): """ @@ -1079,7 +1077,7 @@ cdef class StaticSparseBackend(CGraphBackend): - ``2`` -- as ``1`` but ignore the labels """ cdef object v, l - cdef int u_int, prev_u_int, v_int, l_int, l_int_other, tmp + cdef int u_int, prev_u_int, v_int, l_int_other, tmp cdef StaticSparseCGraph cg = self._cg cdef CGraph cg_other = other.cg() cdef list b_vertices_2 diff --git a/src/sage/graphs/base/static_sparse_graph.pxd b/src/sage/graphs/base/static_sparse_graph.pxd index 7fb0fa7725d..b7d6be3a823 100644 --- a/src/sage/graphs/base/static_sparse_graph.pxd +++ b/src/sage/graphs/base/static_sparse_graph.pxd @@ -8,17 +8,17 @@ ctypedef unsigned int uint cdef extern from "stdlib.h": ctypedef void const_void "const void" void qsort(void *base, int nmemb, int size, - int(*compar)(const_void *, const_void *)) nogil + int(*compar)(const_void *, const_void *)) nogil void *bsearch(const_void *key, const_void *base, size_t nmemb, size_t size, int(*compar)(const_void *, const_void *)) nogil ctypedef struct short_digraph_s: - uint32_t * edges - uint32_t ** neighbors - PyObject * edge_labels - int m - int n + uint32_t * edges + uint32_t ** neighbors + PyObject * edge_labels + int m + int n ctypedef short_digraph_s short_digraph[1] diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 6c4bc1b7edd..b5462299058 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -182,7 +182,6 @@ with C arguments). # **************************************************************************** cimport cpython -from libc.string cimport memset from libc.limits cimport INT_MAX from libc.math cimport sqrt from libcpp.vector cimport vector @@ -703,7 +702,7 @@ def tarjan_strongly_connected_components(G): sage: tarjan_strongly_connected_components(digraphs.Path(3)) [[2], [1], [0]] sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } ) - sage: D.connected_components() + sage: D.connected_components(sort=True) [[0, 1, 2, 3], [4, 5, 6]] sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } ) sage: D.strongly_connected_components() @@ -732,8 +731,8 @@ def tarjan_strongly_connected_components(G): Checking against NetworkX:: - sage: import networkx - sage: for i in range(10): # long time + sage: import networkx # needs networkx + sage: for i in range(10): # long time # needs networkx ....: g = digraphs.RandomDirectedGNP(100,.05) ....: h = g.networkx_graph() ....: scc1 = g.strongly_connected_components() @@ -783,7 +782,6 @@ cdef void strongly_connected_components_digraph_C(short_digraph g, int nscc, int cdef MemoryAllocator mem = MemoryAllocator() cdef size_t v, w, i cdef size_t s_nscc = <size_t>nscc - cdef int tmp = nscc + 1 cdef vector[vector[int]] scc_list = vector[vector[int]](nscc, vector[int]()) cdef vector[vector[int]] sons = vector[vector[int]](nscc + 1, vector[int]()) cdef vector[int].iterator iter @@ -827,7 +825,6 @@ cdef void strongly_connected_components_digraph_C(short_digraph g, int nscc, int output.neighbors[0] = output.edges for v in range(1, s_nscc + 1): - degv = sons[v].size() output.neighbors[v] = output.neighbors[v - 1] + sons[v - 1].size() for i in range(sons[v].size()): output.neighbors[v][i] = sons[v][i] @@ -1026,8 +1023,8 @@ def spectral_radius(G, prec=1e-10): sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(2,4),(3,4)]) sage: e_min, e_max = spectral_radius(G, 1e-14) - sage: e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False)) - sage: e_min < e < e_max + sage: e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False)) # needs sage.modules + sage: e_min < e < e_max # needs sage.modules True sage: G.spectral_radius() # abs tol 1e-9 @@ -1035,6 +1032,7 @@ def spectral_radius(G, prec=1e-10): A larger example:: + sage: # needs sage.modules sage: G = DiGraph() sage: G.add_edges((i,i+1) for i in range(200)) sage: G.add_edge(200,0) @@ -1063,7 +1061,7 @@ def spectral_radius(G, prec=1e-10): sage: G.add_edges([(0,0),(0,0),(0,1),(1,0)]) sage: spectral_radius(G, 1e-14) # abs tol 1e-14 (2.414213562373094, 2.414213562373095) - sage: max(G.adjacency_matrix().eigenvalues(AA)) + sage: max(G.adjacency_matrix().eigenvalues(AA)) # needs sage.modules 2.414213562373095? Some bipartite graphs:: @@ -1094,7 +1092,7 @@ def spectral_radius(G, prec=1e-10): ... ValueError: precision (=1.00000000000000e-20) is too small - sage: for _ in range(100): + sage: for _ in range(100): # needs sage.modules ....: G = digraphs.RandomDirectedGNM(10,35) ....: if not G.is_strongly_connected(): ....: continue diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 93e7464d17f..f707ee2a968 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -45,7 +45,10 @@ from .generic_graph import GenericGraph from .graph import Graph from sage.rings.integer import Integer -from sage.misc.decorators import rename_keyword +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import + +lazy_import('networkx', ['MultiGraph', 'Graph'], as_=['networkx_MultiGraph', 'networkx_Graph']) class BipartiteGraph(Graph): @@ -95,6 +98,11 @@ class BipartiteGraph(Graph): - ``weighted`` -- boolean (default: ``None``); whether graph thinks of itself as weighted or not. See ``self.weighted()`` + - ``hash_labels`` -- boolean (default: ``None``); whether to include edge + labels during hashing. This parameter defaults to ``True`` if the graph is + weighted. This parameter is ignored if the graph is mutable. + Beware that trying to hash unhashable labels will raise an error. + .. NOTE:: All remaining arguments are passed to the ``Graph`` constructor @@ -152,7 +160,7 @@ class BipartiteGraph(Graph): sage: B = BipartiteGraph(P, partition, check=False) sage: B.left {0, 1, 2, 3, 4} - sage: B.show() + sage: B.show() # needs sage.plot :: @@ -189,6 +197,7 @@ class BipartiteGraph(Graph): #. From a reduced adjacency matrix:: + sage: # needs sage.modules sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) sage: M @@ -215,9 +224,9 @@ class BipartiteGraph(Graph): :: - sage: M = Matrix([(1, 1, 2, 0, 0), (0, 2, 1, 1, 1), (0, 1, 2, 1, 1)]) - sage: B = BipartiteGraph(M, multiedges=True, sparse=True) - sage: B.edges(sort=True) + sage: M = Matrix([(1, 1, 2, 0, 0), (0, 2, 1, 1, 1), (0, 1, 2, 1, 1)]) # needs sage.modules + sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # needs sage.modules + sage: B.edges(sort=True) # needs sage.modules [(0, 5, None), (1, 5, None), (1, 6, None), @@ -235,6 +244,7 @@ class BipartiteGraph(Graph): :: + sage: # needs sage.modules sage.rings.finite_rings sage: F.<a> = GF(4) sage: MS = MatrixSpace(F, 2, 3) sage: M = MS.matrix([[0, 1, a + 1], [a, 1, 1]]) @@ -255,7 +265,7 @@ class BipartiteGraph(Graph): ....: 1 2 4 7 \n") ....: f.flush() ....: B = BipartiteGraph(f.name) - sage: B.is_isomorphic(H) + sage: B.is_isomorphic(H) # needs sage.modules True #. From a ``graph6`` string:: @@ -298,10 +308,11 @@ class BipartiteGraph(Graph): sage: B = BipartiteGraph('F?^T_\n', partition=[[0, 1, 2], [3, 4, 5, 6]], check=False) sage: B.left {0, 1, 2} - sage: B.show() + sage: B.show() # needs sage.plot #. From a NetworkX bipartite graph:: + sage: # needs networkx sage: import networkx sage: G = graphs.OctahedralGraph() sage: N = networkx.make_clique_bipartite(G.networkx_graph()) @@ -319,6 +330,7 @@ class BipartiteGraph(Graph): Ensure that we can construct a ``BipartiteGraph`` with isolated vertices via the reduced adjacency matrix (:trac:`10356`):: + sage: # needs sage.modules sage: a = BipartiteGraph(matrix(2, 2, [1, 0, 1, 0])) sage: a Bipartite graph on 4 vertices @@ -346,7 +358,7 @@ class BipartiteGraph(Graph): """ - def __init__(self, data=None, partition=None, check=True, *args, **kwds): + def __init__(self, data=None, partition=None, check=True, hash_labels=None, *args, **kwds): """ Create a bipartite graph. @@ -396,6 +408,7 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): Graph.__init__(self, **kwds) self.left = set() self.right = set() + self._hash_labels = hash_labels return # need to turn off partition checking for Graph.__init__() adding @@ -497,8 +510,7 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): if len(left) + len(right) != self.num_verts(): raise ValueError("not all vertices appear in partition") - import networkx - if isinstance(data, (networkx.MultiGraph, networkx.Graph)): + if isinstance(data, (networkx_MultiGraph, networkx_Graph)): if hasattr(data, "node_type"): # Assume the graph is bipartite self.left = set() @@ -543,8 +555,57 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): if alist_file: self.load_afile(data) + if hash_labels is None and hasattr(data, '_hash_labels'): + hash_labels = data._hash_labels + self._hash_labels = hash_labels + return + @cached_method + def __hash__(self): + """ + Compute a hash for ``self``, if ``self`` is immutable. + + EXAMPLES:: + + sage: A = BipartiteGraph([(1, 2, 1)], immutable=True) + sage: B = BipartiteGraph([(1, 2, 33)], immutable=True) + sage: A.__hash__() == B.__hash__() + True + sage: A = BipartiteGraph([(1, 2, 1)], immutable=True, hash_labels=True) + sage: B = BipartiteGraph([(1, 2, 33)], immutable=True, hash_labels=True) + sage: A.__hash__() == B.__hash__() + False + sage: A = BipartiteGraph([(1, 2, 1)], immutable=True, weighted=True) + sage: B = BipartiteGraph([(1, 2, 33)], immutable=True, weighted=True) + sage: A.__hash__() == B.__hash__() + False + + TESTS:: + + sage: A = BipartiteGraph([(1, 2, 1)], immutable=False) + sage: A.__hash__() + Traceback (most recent call last): + ... + TypeError: This graph is mutable, and thus not hashable. Create an immutable copy by `g.copy(immutable=True)` + sage: B = BipartiteGraph([(1, 2, {'length': 3})], immutable=True, hash_labels=True) + sage: B.__hash__() + Traceback (most recent call last): + ... + TypeError: unhashable type: 'dict' + """ + if self.is_immutable(): + # Determine whether to hash edge labels + use_labels = self._use_labels_for_hash() + edge_items = self.edge_iterator(labels=use_labels) + if self.allows_multiple_edges(): + from collections import Counter + edge_items = Counter(edge_items).items() + return hash((frozenset(self.left), frozenset(self.right), frozenset(edge_items))) + + raise TypeError("This graph is mutable, and thus not hashable. " + "Create an immutable copy by `g.copy(immutable=True)`") + def _upgrade_from_graph(self): """ Set the left and right sets of vertices from the input graph. @@ -1151,7 +1212,7 @@ def _check_bipartition_for_add_edges(self, edges): vertex_in_left[v] = False # Map each vertex to the connected component it belongs to - vertex_to_component = {v: comp for comp in self.connected_components() + vertex_to_component = {v: comp for comp in self.connected_components(sort=False) for v in comp} for e in edges: @@ -1233,10 +1294,10 @@ def is_bipartite(self, certificate=False): EXAMPLES:: - sage: g = BipartiteGraph(graphs.RandomBipartite(3, 3, .5)) - sage: g.is_bipartite() + sage: g = BipartiteGraph(graphs.RandomBipartite(3, 3, .5)) # needs numpy + sage: g.is_bipartite() # needs numpy True - sage: g.is_bipartite(certificate=True) # random + sage: g.is_bipartite(certificate=True) # random # needs numpy (True, {(0, 0): 0, (0, 1): 0, (0, 2): 0, (1, 0): 1, (1, 1): 1, (1, 2): 1}) TESTS:: @@ -1408,7 +1469,7 @@ def plot(self, *args, **kwds): EXAMPLES:: sage: B = BipartiteGraph(graphs.CycleGraph(20)) - sage: B.plot() + sage: B.plot() # needs sage.plot Graphics object consisting of 41 graphics primitives """ if "pos" not in kwds: @@ -1453,14 +1514,16 @@ def matching_polynomial(self, algorithm="Godsil", name=None): sage: x = polygen(QQ) sage: g = BipartiteGraph(graphs.CompleteBipartiteGraph(16, 16)) - sage: bool(factorial(16) * laguerre(16, x^2) == g.matching_polynomial(algorithm='rook')) # optional - sage.symbolic + sage: bool(factorial(16) * laguerre(16, x^2) # needs sage.symbolic + ....: == g.matching_polynomial(algorithm='rook')) True Compute the matching polynomial of a line with `60` vertices:: - sage: from sage.functions.orthogonal_polys import chebyshev_U # optional - sage.symbolic + sage: from sage.functions.orthogonal_polys import chebyshev_U # needs sage.symbolic sage: g = next(graphs.trees(60)) - sage: chebyshev_U(60, x/2) == BipartiteGraph(g).matching_polynomial(algorithm='rook') # optional - sage.symbolic + sage: (chebyshev_U(60, x/2) # needs sage.symbolic + ....: == BipartiteGraph(g).matching_polynomial(algorithm='rook')) True The matching polynomial of a tree is equal to its characteristic @@ -1569,7 +1632,7 @@ def perfect_matchings(self, labels=False): sage: B = BipartiteGraph(graphs.CompleteBipartiteGraph(4, 4)) sage: len(list(B.perfect_matchings())) 24 - sage: B.matching_polynomial(algorithm='rook')(0) + sage: B.matching_polynomial(algorithm='rook')(0) # needs sage.modules 24 TESTS:: @@ -1645,8 +1708,7 @@ def rec(G): # For each unlabeled matching, we yield all its possible labelings for m in rec(G): - for pm in itertools.product(*[edges[frozenset(e)] for e in m]): - yield pm + yield from itertools.product(*[edges[frozenset(e)] for e in m]) def load_afile(self, fname): r""" @@ -1747,6 +1809,7 @@ def save_afile(self, fname): EXAMPLES:: + sage: # needs sage.modules sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) sage: M @@ -1766,7 +1829,7 @@ def save_afile(self, fname): sage: import tempfile sage: f = tempfile.NamedTemporaryFile() - sage: for order in range(3, 13, 3): + sage: for order in range(3, 13, 3): # needs sage.combinat ....: num_chks = int(order / 3) ....: num_vars = order - num_chks ....: partition = (list(range(num_vars)), list(range(num_vars, num_vars+num_chks))) @@ -1864,11 +1927,11 @@ def reduced_adjacency_matrix(self, sparse=True, *, base_ring=None, **kwds): Bipartite graphs that are not weighted will return a matrix over ZZ, unless a base ring is specified:: + sage: # needs sage.modules sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) sage: B = BipartiteGraph(M) - sage: N = B.reduced_adjacency_matrix() - sage: N + sage: N = B.reduced_adjacency_matrix(); N [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] [0 1 0 1 0 1 0] @@ -1888,6 +1951,7 @@ def reduced_adjacency_matrix(self, sparse=True, *, base_ring=None, **kwds): Multi-edge graphs also return a matrix over ZZ, unless a base ring is specified:: + sage: # needs sage.modules sage: M = Matrix([(1,1,2,0,0), (0,2,1,1,1), (0,1,2,1,1)]) sage: B = BipartiteGraph(M, multiedges=True, sparse=True) sage: N = B.reduced_adjacency_matrix() @@ -1902,6 +1966,7 @@ def reduced_adjacency_matrix(self, sparse=True, *, base_ring=None, **kwds): Weighted graphs will return a matrix over the ring given by their (first) weights, unless a base ring is specified:: + sage: # needs sage.modules sage.rings.finite_rings sage: F.<a> = GF(4) sage: MS = MatrixSpace(F, 2, 3) sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) @@ -1918,19 +1983,20 @@ def reduced_adjacency_matrix(self, sparse=True, *, base_ring=None, **kwds): TESTS:: sage: B = BipartiteGraph() - sage: B.reduced_adjacency_matrix() + sage: B.reduced_adjacency_matrix() # needs sage.modules [] - sage: M = Matrix([[0,0], [0,0]]) - sage: BipartiteGraph(M).reduced_adjacency_matrix() == M + sage: M = Matrix([[0,0], [0,0]]) # needs sage.modules + sage: BipartiteGraph(M).reduced_adjacency_matrix() == M # needs sage.modules True - sage: M = Matrix([[10,2/3], [0,0]]) - sage: B = BipartiteGraph(M, weighted=True, sparse=True) - sage: M == B.reduced_adjacency_matrix() + sage: M = Matrix([[10,2/3], [0,0]]) # needs sage.modules + sage: B = BipartiteGraph(M, weighted=True, sparse=True) # needs sage.modules + sage: M == B.reduced_adjacency_matrix() # needs sage.modules True An error is raised if the specified base ring is not compatible with the type of the weights of the bipartite graph:: + sage: # needs sage.modules sage.rings.finite_rings sage: F.<a> = GF(4) sage: MS = MatrixSpace(F, 2, 3) sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) @@ -2041,14 +2107,14 @@ class :class:`MixedIntegerLinearProgram Maximum matching in a cycle graph:: sage: G = BipartiteGraph(graphs.CycleGraph(10)) - sage: G.matching() + sage: G.matching() # needs networkx [(0, 1, None), (2, 3, None), (4, 5, None), (6, 7, None), (8, 9, None)] The size of a maximum matching in a complete bipartite graph using Eppstein:: sage: G = BipartiteGraph(graphs.CompleteBipartiteGraph(4,5)) - sage: G.matching(algorithm="Eppstein", value_only=True) + sage: G.matching(algorithm="Eppstein", value_only=True) # needs networkx 4 TESTS: @@ -2066,11 +2132,11 @@ class :class:`MixedIntegerLinearProgram sage: G = graphs.CycleGraph(4) sage: B = BipartiteGraph([(u,v,2) for u,v in G.edges(sort=True, labels=0)]) - sage: sorted(B.matching(use_edge_labels=True)) + sage: sorted(B.matching(use_edge_labels=True)) # needs networkx [(0, 3, 2), (1, 2, 2)] - sage: B.matching(use_edge_labels=True, value_only=True) + sage: B.matching(use_edge_labels=True, value_only=True) # needs networkx 4 - sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Edmonds') + sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Edmonds') # needs networkx 4 sage: B.matching(use_edge_labels=True, value_only=True, algorithm='LP') 4 @@ -2082,11 +2148,13 @@ class :class:`MixedIntegerLinearProgram Traceback (most recent call last): ... ValueError: use_edge_labels cannot be used with "Hopcroft-Karp" or "Eppstein" - sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Hopcroft-Karp') + sage: B.matching(use_edge_labels=False, value_only=True, # needs networkx + ....: algorithm='Hopcroft-Karp') 2 - sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Eppstein') + sage: B.matching(use_edge_labels=False, value_only=True, # needs networkx + ....: algorithm='Eppstein') 2 - sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Edmonds') + sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Edmonds') # needs networkx 2 sage: B.matching(use_edge_labels=False, value_only=True, algorithm='LP') 2 @@ -2097,23 +2165,23 @@ class :class:`MixedIntegerLinearProgram sage: for e in G.edges(sort=True): ....: G.set_edge_label(e[0], e[1], int(e[0]) + int(e[1])) sage: G.allow_multiple_edges(True) - sage: G.matching(use_edge_labels=True, value_only=True) + sage: G.matching(use_edge_labels=True, value_only=True) # needs networkx 444 Empty bipartite graph and bipartite graphs without edges:: sage: B = BipartiteGraph() sage: algorithms = ["Hopcroft-Karp", "Eppstein", "Edmonds", "LP"] - sage: not any(B.matching(algorithm=algo) for algo in algorithms) + sage: not any(B.matching(algorithm=algo) for algo in algorithms) # needs networkx True - sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) + sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) # needs networkx True sage: B.add_vertex(1, left=True) sage: B.add_vertex(2, left=True) sage: B.add_vertex(3, right=True) - sage: not any(B.matching(algorithm=algo) for algo in algorithms) + sage: not any(B.matching(algorithm=algo) for algo in algorithms) # needs networkx True - sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) + sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) # needs networkx True """ if algorithm is None: @@ -2157,7 +2225,6 @@ class :class:`MixedIntegerLinearProgram raise ValueError('algorithm must be "Hopcroft-Karp", ' '"Eppstein", "Edmonds" or "LP"') - @rename_keyword(deprecation=32238, verbosity='verbose') def vertex_cover(self, algorithm="Konig", value_only=False, reduction_rules=True, solver=None, verbose=0, *, integrality_tolerance=1e-3): @@ -2228,13 +2295,14 @@ def vertex_cover(self, algorithm="Konig", value_only=False, On the Cycle Graph:: sage: B = BipartiteGraph(graphs.CycleGraph(6)) - sage: len(B.vertex_cover()) + sage: len(B.vertex_cover()) # needs networkx 3 - sage: B.vertex_cover(value_only=True) + sage: B.vertex_cover(value_only=True) # needs networkx 3 The two algorithms should return the same result:: + sage: # needs numpy sage: g = BipartiteGraph(graphs.RandomBipartite(10, 10, .5)) sage: vc1 = g.vertex_cover(algorithm="Konig") sage: vc2 = g.vertex_cover(algorithm="Cliquer") @@ -2246,7 +2314,7 @@ def vertex_cover(self, algorithm="Konig", value_only=False, Giving a non connected bipartite graph:: sage: B = BipartiteGraph(graphs.CycleGraph(4) * 2) - sage: len(B.vertex_cover()) + sage: len(B.vertex_cover()) # needs networkx 4 Empty bipartite graph and bipartite graphs without edges:: diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index 8c99ae1a184..0a1b5ea313f 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -1,4 +1,5 @@ # distutils: language = c++ +# distutils: extra_compile_args = -std=c++11 # distutils: libraries = bliss # sage_setup: distribution = sagemath-bliss @@ -47,27 +48,27 @@ cdef extern from "bliss/graph.hh" namespace "bliss": cdef cppclass Graph(AbstractGraph): Graph(const unsigned int) void add_edge(const unsigned int, const unsigned int) - void find_automorphisms(Stats&, void (*)(void*, unsigned int, - const unsigned int*), void*) void change_color(const unsigned int, const unsigned int) - const unsigned int* canonical_form(Stats&, void (*)(void*, unsigned int, - const unsigned int*), void*) + const unsigned int* canonical_form(Stats&) + +cdef extern from "bliss/digraph.hh" namespace "bliss": cdef cppclass Digraph(AbstractGraph): Digraph(const unsigned int) void add_edge(const unsigned int, const unsigned int) - void find_automorphisms(Stats&, void (*)(void*, unsigned int, - const unsigned int*), void*) void change_color(const unsigned int, const unsigned int) - const unsigned int* canonical_form(Stats&, void (*)(void*, unsigned int, - const unsigned int*), void*) + const unsigned int* canonical_form(Stats&) unsigned int get_hash() +cdef extern from "bliss_cpp/bliss_find_automorphisms.h": + + void bliss_find_automorphisms(Graph*, void (*)(void*, unsigned int, const unsigned int*), void*, Stats&) + void bliss_find_automorphisms(Digraph*, void (*)(void*, unsigned int, const unsigned int*), void*, Stats&) cdef int encoding_numbits(int n): r""" - Return the number of bits needed to encode the ``n`` numbers from ``1`` to ``n``. In - other words, the last bit set in ``n``. + Return the number of bits needed to encode the `n` numbers from `1` to + `n`. In other words, the last bit set in `n`. """ if n <= 0: return 0 @@ -124,10 +125,6 @@ cdef void add_gen(void *user_param, unsigned int n, const unsigned int *aut): sig_free(done) - -cdef void empty_hook(void *user_param, unsigned int n, const unsigned int *aut): - return - ##################################################### # constructing bliss graphs from edge lists ##################################################### @@ -346,10 +343,10 @@ cdef canonical_form_from_edge_list(int Vnr, list Vout, list Vin, int Lnr=1, list if directed: d = bliss_digraph_from_labelled_edges(Vnr, Lnr, Vout, Vin, labels, partition) - aut = d.canonical_form(s, empty_hook, NULL) + aut = d.canonical_form(s) else: g = bliss_graph_from_labelled_edges(Vnr, Lnr, Vout, Vin, labels, partition) - aut = g.canonical_form(s, empty_hook, NULL) + aut = g.canonical_form(s) for i in range(len(Vout)): x = Vout[i] @@ -378,8 +375,7 @@ cdef canonical_form_from_edge_list(int Vnr, list Vout, list Vin, int Lnr=1, list if certificate: return new_edges, relabel - else: - return new_edges + return new_edges cpdef canonical_form(G, partition=None, return_graph=False, use_edge_labels=True, certificate=False): @@ -440,12 +436,13 @@ cpdef canonical_form(G, partition=None, return_graph=False, use_edge_labels=True sage: g.is_isomorphic(canonical_form(g, return_graph=True)) # optional - bliss True - sage: g1 = graphs.RandomGNP(100, .4) # optional - bliss - sage: r = Permutations(range(100)).random_element() # optional - bliss - sage: g2 = Graph([(r[u],r[v]) for u,v in g1.edges(sort=True, labels=False)]) # optional - bliss - sage: g1 = canonical_form(g1, return_graph=True) # optional - bliss - sage: g2 = canonical_form(g2, return_graph=True) # optional - bliss - sage: g2 == g2 # optional - bliss + sage: # optional - bliss + sage: g1 = graphs.RandomGNP(100, .4) + sage: r = Permutations(range(100)).random_element() + sage: g2 = Graph([(r[u],r[v]) for u,v in g1.edges(sort=True, labels=False)]) + sage: g1 = canonical_form(g1, return_graph=True) + sage: g2 = canonical_form(g2, return_graph=True) + sage: g2 == g2 True sage: g = Graph({1: [2]}) @@ -479,11 +476,12 @@ cpdef canonical_form(G, partition=None, return_graph=False, use_edge_labels=True Check that it works with non hashable non sortable edge labels (relying on string representations of the labels):: + sage: # needs sage.modules sage: g1 = Graph([(0, 1, matrix(ZZ, 2)), (0, 2, RDF.pi()), (1, 2, 'a')]) sage: g2 = Graph([(1, 2, matrix(ZZ, 2)), (2, 0, RDF.pi()), (0, 1, 'a')]) - sage: g1can = canonical_form(g1, use_edge_labels=True) # optional - bliss - sage: g2can = canonical_form(g2, use_edge_labels=True) # optional - bliss - sage: g1can == g2can # optional - bliss + sage: g1can = canonical_form(g1, use_edge_labels=True) # optional - bliss + sage: g2can = canonical_form(g2, use_edge_labels=True) # optional - bliss + sage: g1can == g2can # optional - bliss True Check that :trac:`32395` is fixed:: @@ -643,11 +641,11 @@ cdef automorphism_group_gens_from_edge_list(int Vnr, Vout, Vin, int Lnr=1, label if directed: d = bliss_digraph_from_labelled_edges(Vnr, Lnr, Vout, Vin, labels, partition) - d.find_automorphisms(s, add_gen, <void*>data) + bliss_find_automorphisms(d, add_gen, <void*>data, s) del d else: g = bliss_graph_from_labelled_edges(Vnr, Lnr, Vout, Vin, labels, partition) - g.find_automorphisms(s, add_gen, <void*>data) + bliss_find_automorphisms(g, add_gen, <void*>data, s) del g return [[cyc for cyc in gen if cyc[0] is not None] for gen in gens] @@ -667,12 +665,12 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): - ``G`` -- a Sage graph - - ``partition`` -- ``list``(default: ``None``); a partition of the vertices + - ``partition`` -- ``list`` (default: ``None``); a partition of the vertices of ``G`` into color classes. Defaults to ``None``, which is equivalent to a partition of size 1. - - ``use_edge_labels`` -- boolean (default: ``True``); whether to consider edge - labels + - ``use_edge_labels`` -- boolean (default: ``True``); whether to consider + edge labels EXAMPLES:: @@ -680,44 +678,45 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): Computing the automorphism group of a graph or digraph:: - sage: G = graphs.CompleteMultipartiteGraph([1, 1, 1, 2]) # optional - bliss - sage: automorphism_group(G).cardinality() # optional - bliss + sage: # optional - bliss + sage: G = graphs.CompleteMultipartiteGraph([1, 1, 1, 2]) + sage: automorphism_group(G).cardinality() 12 - sage: D = DiGraph(G.edges(sort=True)) # optional - bliss - sage: automorphism_group(D).cardinality() # optional - bliss + sage: D = DiGraph(G.edges(sort=True)) + sage: automorphism_group(D).cardinality() 2 - Observe that the order 12 is given by permuting the first three vertices, or the last two - in the case of a graph, while only the latter two are possible in the case of a directed - graph. + Observe that the order 12 is given by permuting the first three vertices, or + the last two in the case of a graph, while only the latter two are possible + in the case of a directed graph. Partitioning the vertices into classes:: - sage: G = graphs.CompleteMultipartiteGraph([3, 2]) # optional - bliss - sage: automorphism_group(G).cardinality() # optional - bliss + sage: # optional - bliss + sage: G = graphs.CompleteMultipartiteGraph([3, 2]) + sage: automorphism_group(G).cardinality() 12 - sage: automorphism_group(G,partition=[[0],[1],[2],[3,4]]).cardinality() # optional - bliss + sage: automorphism_group(G,partition=[[0],[1],[2],[3,4]]).cardinality() 2 - sage: automorphism_group(G,partition=[[0],[1,2],[3,4]]).cardinality() # optional - bliss + sage: automorphism_group(G,partition=[[0],[1,2],[3,4]]).cardinality() 4 - - sage: automorphism_group(G,partition=[[1,2],[0,3],[4]]).cardinality() # optional - bliss + sage: automorphism_group(G,partition=[[1,2],[0,3],[4]]).cardinality() 2 Partitioning the edges into classes:: - sage: G = Graph(graphs.CompleteMultipartiteGraph([8, 2]), sparse=True) # optional - bliss - sage: for i,j in G.edges(labels=False, sort=False): # optional - bliss - ....: if 0 <= i < 3: # optional - bliss - ....: G.set_edge_label(i, j, "A") # optional - bliss - ....: if 3 <= i < 6: # optional - bliss - ....: G.set_edge_label(i, j, "B") # optional - bliss - ....: if 6 <= i < 8: # optional - bliss - ....: G.set_edge_label(i, j, "C") # optional - bliss - - sage: factor(automorphism_group(G).cardinality()) # optional - bliss + sage: # optional - bliss + sage: G = Graph(graphs.CompleteMultipartiteGraph([8, 2]), sparse=True) + sage: for i,j in G.edges(labels=False, sort=False): + ....: if 0 <= i < 3: + ....: G.set_edge_label(i, j, "A") + ....: if 3 <= i < 6: + ....: G.set_edge_label(i, j, "B") + ....: if 6 <= i < 8: + ....: G.set_edge_label(i, j, "C") + sage: factor(automorphism_group(G).cardinality()) 2^4 * 3^2 - sage: automorphism_group(G,[[0],[1],[2,3],[4,5],[6,7],[8],[9]]).cardinality() # optional - bliss + sage: automorphism_group(G,[[0],[1],[2,3],[4,5],[6,7],[8],[9]]).cardinality() 4 TESTS:: @@ -727,66 +726,73 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): sage: automorphism_group(G).is_isomorphic(G.automorphism_group()) # optional - bliss True - sage: G = graphs.HeawoodGraph() # optional - bliss - sage: p = G.bipartite_sets() # optional - bliss - sage: A = G.automorphism_group(partition=[list(p[0]), list(p[1])]) # optional - bliss - sage: automorphism_group(G, partition=p).is_isomorphic(A) # optional - bliss + sage: # optional - bliss + sage: G = graphs.HeawoodGraph() + sage: p = G.bipartite_sets() + sage: A = G.automorphism_group(partition=[list(p[0]), list(p[1])]) + sage: automorphism_group(G, partition=p).is_isomorphic(A) True - sage: G = graphs.CompleteMultipartiteGraph([5,7,11]) + sage: G = graphs.CompleteMultipartiteGraph([5, 7, 11]) sage: B = automorphism_group(G) # optional - bliss - sage: B.cardinality() == prod(factorial(n) for n in [5,7,11]) # optional - bliss + sage: B.cardinality() == prod(factorial(n) for n in [5, 7, 11]) # optional - bliss True - sage: G = Graph(graphs.CompleteMultipartiteGraph([8,8,8,5]),sparse=True)# optional - bliss - sage: for i,j in G.edges(labels=False, sort=False): # optional - bliss - ....: if 0 <= i < 3: # optional - bliss - ....: G.set_edge_label(i, j, "A") # optional - bliss - ....: if 3 <= i < 6: # optional - bliss - ....: G.set_edge_label(i, j, "B") # optional - bliss - ....: if 6 <= i < 8: # optional - bliss - ....: G.set_edge_label(i, j, "C") # optional - bliss - sage: automorphism_group(G).cardinality() == prod( factorial(n) for n in [3,3,2,8,8,5,2] ) # optional - bliss + sage: # optional - bliss + sage: G = Graph(graphs.CompleteMultipartiteGraph([8,8,8,5]),sparse=True) + sage: for i,j in G.edges(labels=False, sort=False): + ....: if 0 <= i < 3: + ....: G.set_edge_label(i, j, "A") + ....: if 3 <= i < 6: + ....: G.set_edge_label(i, j, "B") + ....: if 6 <= i < 8: + ....: G.set_edge_label(i, j, "C") + sage: card = automorphism_group(G).cardinality() + sage: card == prod(factorial(n) for n in [3, 3, 2, 8, 8, 5, 2]) True - sage: automorphism_group(G, use_edge_labels=False).cardinality() == prod( factorial(n) for n in [8,8,8,5,3] ) # optional - bliss + sage: card = automorphism_group(G, use_edge_labels=False).cardinality() + sage: card == prod(factorial(n) for n in [8, 8, 8, 5, 3]) True - sage: automorphism_group(G,[[0 .. 7],[8 .. 11],[12 .. 28]]).cardinality() == prod( factorial(n) for n in [3,3,2,4,4,8,5] ) # optional - bliss + sage: card = automorphism_group(G, [[0 .. 7], [8 .. 11] ,[12 .. 28]]).cardinality() + sage: card == prod(factorial(n) for n in [3, 3, 2, 4, 4, 8, 5]) True - sage: G = Graph() # optional - bliss - sage: G.add_edges((i,j,"A") for i in range(0, 2) for j in range(14,20)) # optional - bliss - sage: G.add_edges((i,j,"B") for i in range(2, 5) for j in range(14,20)) # optional - bliss - sage: G.add_edges((i,j,"C") for i in range(5, 9) for j in range(14,20)) # optional - bliss - sage: G.add_edges((i,j,"D") for i in range(9,14) for j in range(14,20)) # optional - bliss - sage: A = automorphism_group(G) # optional - bliss - sage: print(A.gens()) # random, optional - bliss - [(9,13), (18,19), (17,18), (16,17), (15,16), (14,15), (12,9), (11,12), - (10,11), (7,8), (6,7), (5,6), (3,4), (2,3), (0,1)] - sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) # optional - bliss + sage: # optional - bliss + sage: G = Graph() + sage: G.add_edges((i,j,"A") for i in range(0, 2) for j in range(14,20)) + sage: G.add_edges((i,j,"B") for i in range(2, 5) for j in range(14,20)) + sage: G.add_edges((i,j,"C") for i in range(5, 9) for j in range(14,20)) + sage: G.add_edges((i,j,"D") for i in range(9,14) for j in range(14,20)) + sage: A = automorphism_group(G) + sage: print(A.gens()) # random + ((12,13), (11,12), (10,11), (9,10), (7,8), (6,7), (5,6), (3,4), + (2,3), (1,0), (18,19), (17,18), (16,17), (15,16), (14,15)) + sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) True + sage: # optional - bliss + sage: G = Graph() sage: alpha = "abcdefghijklmnopqrstuvwxyz" - - sage: G = Graph() # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"A") for i in range(0, 2) for j in range(14,20)) # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"B") for i in range(2, 5) for j in range(14,20)) # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"C") for i in range(5, 9) for j in range(14,20)) # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"D") for i in range(9,14) for j in range(14,20)) # optional - bliss - sage: A = automorphism_group(G) # optional - bliss - sage: print(A.gens()) # random, optional - bliss - [('r','t'), ('s','r'), ('p','s'), ('q','p'), ('o','q'), ('l','n'), - ('m','l'), ('j','m'), ('k','j'), ('i','h'), ('f','i'), ('g','f'), - ('e','d'), ('c','e'), ('a','b')] - sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) # optional - bliss + sage: G.add_edges((alpha[i],alpha[j],"A") for i in range(0, 2) for j in range(14,20)) + sage: G.add_edges((alpha[i],alpha[j],"B") for i in range(2, 5) for j in range(14,20)) + sage: G.add_edges((alpha[i],alpha[j],"C") for i in range(5, 9) for j in range(14,20)) + sage: G.add_edges((alpha[i],alpha[j],"D") for i in range(9,14) for j in range(14,20)) + sage: A = automorphism_group(G) + sage: print(A.gens()) + (('m','n'), ('l','m'), ('k','l'), ('j','k'), ('h','i'), + ('g','h'), ('f','g'), ('d','e'), ('c','d'), ('s','t'), + ('r','s'), ('q','r'), ('p','q'), ('o','p'), ('a','b')) + sage: A.cardinality() == prod(factorial(n) for n in [2, 3, 4, 5, 6]) True - sage: gg = graphs.CompleteGraph(5) # optional - bliss - sage: gg.allow_loops(True) # optional - bliss - sage: gg.add_edge(0,0) # optional - bliss - sage: gg.add_edge(1,1) # optional - bliss - sage: automorphism_group(gg).cardinality() # optional - bliss + sage: # optional - bliss + sage: gg = graphs.CompleteGraph(5) + sage: gg.allow_loops(True) + sage: gg.add_edge(0, 0) + sage: gg.add_edge(1, 1) + sage: automorphism_group(gg).cardinality() 12 - sage: automorphism_group(gg,[[0],[1,2,3,4]]).cardinality() # optional - bliss + sage: automorphism_group(gg, [[0], [1, 2, 3, 4]]).cardinality() 6 """ # We need this to convert the numbers from <unsigned int> to diff --git a/src/sage/graphs/bliss_cpp/bliss_find_automorphisms.h b/src/sage/graphs/bliss_cpp/bliss_find_automorphisms.h new file mode 100644 index 00000000000..b87a14e7a8c --- /dev/null +++ b/src/sage/graphs/bliss_cpp/bliss_find_automorphisms.h @@ -0,0 +1,24 @@ +/* sage_setup: distribution = sagemath-bliss */ + +#include <bliss/graph.hh> +#include <bliss/digraph.hh> + +inline void bliss_find_automorphisms(bliss::Graph *graph, void (*hook)(void *user_param, unsigned int n, const unsigned int *aut), void *hook_user_param, bliss::Stats s) +{ + auto report_aut = [&](unsigned int n, const unsigned int *aut) -> void { + if(hook) + (*hook)(hook_user_param, n, aut); + }; + + graph->find_automorphisms(s, report_aut); +} + +inline void bliss_find_automorphisms(bliss::Digraph *graph, void (*hook)(void *user_param, unsigned int n, const unsigned int *aut), void *hook_user_param, bliss::Stats s) +{ + auto report_aut = [&](unsigned int n, const unsigned int *aut) -> void { + if(hook) + (*hook)(hook_user_param, n, aut); + }; + + graph->find_automorphisms(s, report_aut); +} diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index 852b86c34e8..161f3f710e2 100755 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -99,11 +99,12 @@ def centrality_betweenness(G, bint exact=False, bint normalize=True): Compare with NetworkX:: + sage: # needs networkx sage: import networkx sage: g = graphs.RandomGNP(100, .2) sage: nw = networkx.betweenness_centrality(g.networkx_graph()) sage: sg = centrality_betweenness(g) - sage: max(abs(nw[x] - sg[x]) for x in g) # abs tol 1e-10 + sage: max(abs(nw[x] - sg[x]) for x in g) # abs tol 1e-10 0 Stupid cases:: @@ -118,8 +119,7 @@ def centrality_betweenness(G, bint exact=False, bint normalize=True): """ if exact: return centrality_betweenness_C(G, <mpq_t> 0, normalize=normalize) - else: - return centrality_betweenness_C(G, <double>0, normalize=normalize) + return centrality_betweenness_C(G, <double>0, normalize=normalize) @cython.cdivision(True) @@ -637,6 +637,7 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0): The result is correct:: + sage: # needs networkx sage: from sage.graphs.centrality import centrality_closeness_top_k sage: import random sage: n = 20 @@ -653,6 +654,7 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0): Directed case:: + sage: # needs networkx sage: from sage.graphs.centrality import centrality_closeness_top_k sage: import random sage: n = 20 diff --git a/src/sage/graphs/chrompoly.pyx b/src/sage/graphs/chrompoly.pyx index 441ba58643d..d0611a3df84 100644 --- a/src/sage/graphs/chrompoly.pyx +++ b/src/sage/graphs/chrompoly.pyx @@ -185,7 +185,7 @@ def chromatic_polynomial(G, return_tree_basis=False, algorithm='C', cache=None): # Breadth first search from 0: bfs_reorder[0] = 0 mpz_init(tot[0]) # sets to 0 - for i from 0 < i < nverts: + for i in range(1, nverts): bfs_reorder[i] = -1 mpz_init(tot[i]) # sets to 0 mpz_init(tot[nverts]) # sets to 0 @@ -230,12 +230,12 @@ def chromatic_polynomial(G, return_tree_basis=False, algorithm='C', cache=None): for i in range(nverts): mpz_clear(tot[i]) raise - for i from 0 <= i <= nverts: + for i in range(nverts + 1): mpz_init(coeffs[i]) # also sets them to 0 mpz_init(coeff) mpz_init_set_si(m, -1) # start with the zero polynomial: f(x) = 0 - for i from nverts >= i > 0: + for i in range(nverts, 0, -1): # nverts >= i > 0 if not mpz_sgn(tot[i]): continue mpz_neg(m, m) @@ -244,7 +244,7 @@ def chromatic_polynomial(G, return_tree_basis=False, algorithm='C', cache=None): # f += tot[i]*m*x*(x-1)**(i-1) mpz_addmul(coeffs[i], m, tot[i]) mpz_set_si(coeff, 1) - for j from 1 <= j < i: + for j in range(1, i): # an iterative method for binomial coefficients... mpz_mul_si(coeff, coeff, j-i) mpz_divexact_ui(coeff, coeff, j) @@ -254,13 +254,13 @@ def chromatic_polynomial(G, return_tree_basis=False, algorithm='C', cache=None): mpz_mul(coeff, coeff, m) coeffs_ZZ = [] cdef Integer c_ZZ - for i from 0 <= i <= nverts: + for i in range(nverts + 1): c_ZZ = Integer(0) mpz_set(c_ZZ.value, coeffs[i]) coeffs_ZZ.append(c_ZZ) f = R(coeffs_ZZ) - for i from 0 <= i <= nverts: + for i in range(nverts + 1): mpz_clear(tot[i]) mpz_clear(coeffs[i]) diff --git a/src/sage/graphs/cliquer.pyx b/src/sage/graphs/cliquer.pyx index e53d90d2dbc..6f232d97e16 100644 --- a/src/sage/graphs/cliquer.pyx +++ b/src/sage/graphs/cliquer.pyx @@ -115,7 +115,7 @@ def all_max_clique(graph): [2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10], [5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]] sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) + sage: G.show(figsize=[2,2]) # needs sage.plot sage: G.cliques_maximum() [[0, 1, 2], [0, 1, 3]] sage: C = graphs.PetersenGraph() @@ -302,7 +302,7 @@ def clique_number(graph): sage: C.clique_number() 4 sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) + sage: G.show(figsize=[2,2]) # needs sage.plot sage: G.clique_number() 3 diff --git a/src/sage/graphs/comparability.pyx b/src/sage/graphs/comparability.pyx index 3957e425cc9..b10ce489268 100644 --- a/src/sage/graphs/comparability.pyx +++ b/src/sage/graphs/comparability.pyx @@ -257,7 +257,7 @@ def greedy_is_comparability(g, no_certificate=False, equivalence_class=False): # Each vertex can partition its neighbors into equivalence classes equivalence_classes = {} for v in g: - equivalence_classes[v] = g.subgraph(vertices=g.neighbors(v)).complement().connected_components() + equivalence_classes[v] = g.subgraph(vertices=g.neighbors(v)).complement().connected_components(sort=False) # We build a graph h with one vertex per (vertex of g + equivalence class) from sage.graphs.graph import Graph @@ -288,7 +288,7 @@ def greedy_is_comparability(g, no_certificate=False, equivalence_class=False): if equivalence_class: # Returning the largest equivalence class - cc = sorted(h.connected_components(), key=len)[-1] + cc = sorted(h.connected_components(sort=False), key=len)[-1] edges = [] for v, sid in cc: @@ -306,15 +306,13 @@ def greedy_is_comparability(g, no_certificate=False, equivalence_class=False): # added twice. return True, sorted(set(edges)) - else: - return True - else: - if no_certificate: - certif.append(certif[0]) - cycle = [v for v, _ in certif] - return False, cycle - else: - return False + return True + + if no_certificate: + certif.append(certif[0]) + cycle = [v for v, _ in certif] + return False, cycle + return False def greedy_is_comparability_with_certificate(g, certificate=False): @@ -361,8 +359,7 @@ def greedy_is_comparability_with_certificate(g, certificate=False): if not isit: if certificate: return False, certif - else: - return False + return False elif not certificate: return True @@ -417,20 +414,20 @@ def is_comparability_MILP(g, certificate=False, solver=None, verbose=0): The 5-cycle or the Petersen Graph are not transitively orientable:: sage: from sage.graphs.comparability import is_comparability_MILP as is_comparability - sage: is_comparability(graphs.CycleGraph(5), certificate = True) + sage: is_comparability(graphs.CycleGraph(5), certificate=True) # needs sage.numerical.mip (False, None) sage: g = graphs.PetersenGraph() - sage: is_comparability(g, certificate = True) + sage: is_comparability(g, certificate=True) # needs sage.numerical.mip (False, None) But the Bull graph is:: sage: g = graphs.BullGraph() - sage: is_comparability(g) + sage: is_comparability(g) # needs sage.numerical.mip True - sage: is_comparability(g, certificate = True) + sage: is_comparability(g, certificate=True) # needs sage.numerical.mip (True, Digraph on 5 vertices) - sage: is_comparability(g, certificate = True)[1].is_transitive() + sage: is_comparability(g, certificate=True)[1].is_transitive() # needs sage.numerical.mip True """ from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException @@ -552,8 +549,7 @@ def is_comparability(g, algorithm="greedy", certificate=False, check=True, if certificate: from sage.graphs.digraph import DiGraph return True, DiGraph(g) - else: - return True + return True if algorithm == "greedy": comparability_test = greedy_is_comparability_with_certificate(g, certificate=certificate) @@ -642,7 +638,7 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True, sage: p1 = Permutation([nn+1 for nn in perm[0]]) sage: p2 = Permutation([nn+1 for nn in perm[1]]) sage: p = p2 * p1.inverse() - sage: p.show(representation = "braid") + sage: p.show(representation="braid") # needs sage.plot TESTS: @@ -664,7 +660,7 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True, Then with MILP:: sage: from sage.graphs.comparability import is_permutation - sage: for i in range(20): + sage: for i in range(20): # needs sage.numerical.mip ....: p = Permutations(10).random_element() ....: g1 = graphs.PermutationGraph(p) ....: isit, certif = is_permutation(g1, algorithm="MILP", certificate=True) @@ -677,47 +673,44 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True, ....: break """ - from sage.graphs.comparability import is_comparability - if certificate: - - # First poset, we stop if it fails - isit, certif = is_comparability(g, algorithm=algorithm, certificate=True, - solver=solver, verbose=verbose) - if not isit: - return False, certif - - # Second poset - isit, co_certif = is_comparability(g.complement(), algorithm=algorithm, certificate=True, - solver=solver, verbose=verbose) - if not isit: - return False, co_certif - - # Building the two orderings - tmp = list(co_certif.edges(labels=False, sort=False)) - for u, v in certif.edge_iterator(labels=False): - co_certif.add_edge(v, u) - certif.add_edges(tmp) - - ordering = certif.topological_sort() - co_ordering = co_certif.topological_sort() - - # Try to build the Permutation graph from the permutations, just to make - # sure nothing weird happened ! - if check: - from sage.graphs.graph_generators import GraphGenerators - pg = GraphGenerators().PermutationGraph(ordering, co_ordering) - if not pg.is_isomorphic(g): - raise ValueError("There is a mistake somewhere ! It looks like " - "the Permutation Graph model computed does " - "not match the input graph !") - - return True, (ordering, co_ordering) - - # No certificate... A piece of cake - else: + if not certificate: + # No certificate... A piece of cake return (is_comparability(g, algorithm=algorithm, solver=solver, verbose=verbose) and is_comparability(g.complement(), algorithm=algorithm, solver=solver, verbose=verbose)) + # First poset, we stop if it fails + isit, certif = is_comparability(g, algorithm=algorithm, certificate=True, + solver=solver, verbose=verbose) + if not isit: + return False, certif + + # Second poset + isit, co_certif = is_comparability(g.complement(), algorithm=algorithm, certificate=True, + solver=solver, verbose=verbose) + if not isit: + return False, co_certif + + # Building the two orderings + tmp = list(co_certif.edges(labels=False, sort=False)) + for u, v in certif.edge_iterator(labels=False): + co_certif.add_edge(v, u) + certif.add_edges(tmp) + + ordering = certif.topological_sort() + co_ordering = co_certif.topological_sort() + + # Try to build the Permutation graph from the permutations, just to make + # sure nothing weird happened ! + if check: + from sage.graphs.graph_generators import GraphGenerators + pg = GraphGenerators().PermutationGraph(ordering, co_ordering) + if not pg.is_isomorphic(g): + raise ValueError("There is a mistake somewhere ! It looks like " + "the Permutation Graph model computed does " + "not match the input graph !") + + return True, (ordering, co_ordering) + def is_transitive(g, certificate=False): r""" @@ -745,15 +738,15 @@ def is_transitive(g, certificate=False): (0, 2) sage: digraphs.RandomDirectedGNP(30,.2).is_transitive() False - sage: D = digraphs.DeBruijn(5, 2) - sage: D.is_transitive() + sage: D = digraphs.DeBruijn(5, 2) # needs sage.combinat + sage: D.is_transitive() # needs sage.combinat False - sage: cert = D.is_transitive(certificate=True) - sage: D.has_edge(*cert) + sage: cert = D.is_transitive(certificate=True) # needs sage.combinat + sage: D.has_edge(*cert) # needs sage.combinat False - sage: bool(D.shortest_path(*cert)) + sage: bool(D.shortest_path(*cert)) # needs sage.combinat True - sage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive() + sage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive() # needs networkx True """ cdef int n = g.order() diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx index a1241800ac9..9e4942e75e6 100644 --- a/src/sage/graphs/connectivity.pyx +++ b/src/sage/graphs/connectivity.pyx @@ -58,9 +58,18 @@ Methods ------- """ -from sage.rings.integer cimport Integer -from cysignals.memory cimport sig_malloc, sig_free - +# **************************************************************************** +# +# Copyright (C) 2023 David Coudert <david.coudert@inria.fr> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.misc.superseded import deprecation def is_connected(G): """ @@ -122,7 +131,7 @@ def is_connected(G): return len(conn_verts) == G.num_verts() -def connected_components(G, sort=True): +def connected_components(G, sort=None, key=None): """ Return the list of connected components. @@ -133,20 +142,30 @@ def connected_components(G, sort=True): - ``G`` -- the input graph - - ``sort`` -- boolean (default ``True``); whether to sort vertices inside - each component + - ``sort`` -- boolean (default: ``None``); if ``True``, vertices inside each + component are sorted according to the default ordering + + As of :trac:`35889`, this argument must be explicitly specified (unless a + ``key`` is given); otherwise a warning is printed and ``sort=True`` is + used. The default will eventually be changed to ``False``. + + - ``key`` -- a function (default: ``None``); a function that takes a + vertex as its one argument and returns a value that can be used for + comparisons in the sorting algorithm (we must have ``sort=True``) EXAMPLES:: sage: from sage.graphs.connectivity import connected_components sage: G = Graph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) - sage: connected_components(G) + sage: connected_components(G, sort=True) [[0, 1, 2, 3], [4, 5, 6]] - sage: G.connected_components() + sage: G.connected_components(sort=True) [[0, 1, 2, 3], [4, 5, 6]] sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) - sage: connected_components(D) + sage: connected_components(D, sort=True) [[0, 1, 2, 3], [4, 5, 6]] + sage: connected_components(D, sort=True, key=lambda x: -x) + [[3, 2, 1, 0], [6, 5, 4]] TESTS: @@ -157,16 +176,40 @@ def connected_components(G, sort=True): Traceback (most recent call last): ... TypeError: the input must be a Sage graph + + When parameter ``key`` is set, parameter ``sort`` must be ``True``:: + + sage: G = Graph(2) + sage: G.connected_components(sort=False, key=lambda x: x) + Traceback (most recent call last): + ... + ValueError: sort keyword is False, yet a key function is given + + Deprecation warning for ``sort=None`` (:trac:`35889`):: + + sage: G = graphs.HouseGraph() + sage: G.connected_components() + doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future + See https://github.com/sagemath/sage/issues/35889 for details. + [[0, 1, 2, 3, 4]] """ from sage.graphs.generic_graph import GenericGraph if not isinstance(G, GenericGraph): raise TypeError("the input must be a Sage graph") + if sort is None: + if key is None: + deprecation(35889, "parameter 'sort' will be set to False by default in the future") + sort = True + + if (not sort) and key: + raise ValueError('sort keyword is False, yet a key function is given') + cdef set seen = set() cdef list components = [] for v in G: if v not in seen: - c = connected_component_containing_vertex(G, v, sort=sort) + c = connected_component_containing_vertex(G, v, sort=sort, key=key) seen.update(c) components.append(c) components.sort(key=lambda comp: -len(comp)) @@ -215,12 +258,12 @@ def connected_components_subgraphs(G): sage: from sage.graphs.connectivity import connected_components_subgraphs sage: G = Graph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: L = connected_components_subgraphs(G) - sage: graphs_list.show_graphs(L) + sage: graphs_list.show_graphs(L) # needs sage.plot sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: L = connected_components_subgraphs(D) - sage: graphs_list.show_graphs(L) + sage: graphs_list.show_graphs(L) # needs sage.plot sage: L = D.connected_components_subgraphs() - sage: graphs_list.show_graphs(L) + sage: graphs_list.show_graphs(L) # needs sage.plot TESTS: @@ -239,7 +282,7 @@ def connected_components_subgraphs(G): return [G.subgraph(c, inplace=False) for c in connected_components(G, sort=False)] -def connected_component_containing_vertex(G, vertex, sort=True): +def connected_component_containing_vertex(G, vertex, sort=None, key=None): """ Return a list of the vertices connected to vertex. @@ -249,20 +292,30 @@ def connected_component_containing_vertex(G, vertex, sort=True): - ``v`` -- the vertex to search for - - ``sort`` -- boolean (default ``True``); whether to sort vertices inside - the component + - ``sort`` -- boolean (default: ``None``); if ``True``, vertices inside the + component are sorted according to the default ordering + + As of :trac:`35889`, this argument must be explicitly specified (unless a + ``key`` is given); otherwise a warning is printed and ``sort=True`` is + used. The default will eventually be changed to ``False``. + + - ``key`` -- a function (default: ``None``); a function that takes a + vertex as its one argument and returns a value that can be used for + comparisons in the sorting algorithm (we must have ``sort=True``) EXAMPLES:: sage: from sage.graphs.connectivity import connected_component_containing_vertex sage: G = Graph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) - sage: connected_component_containing_vertex(G, 0) + sage: connected_component_containing_vertex(G, 0, sort=True) [0, 1, 2, 3] - sage: G.connected_component_containing_vertex(0) + sage: G.connected_component_containing_vertex(0, sort=True) [0, 1, 2, 3] sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) - sage: connected_component_containing_vertex(D, 0) + sage: connected_component_containing_vertex(D, 0, sort=True) [0, 1, 2, 3] + sage: connected_component_containing_vertex(D, 0, sort=True, key=lambda x: -x) + [3, 2, 1, 0] TESTS: @@ -273,18 +326,52 @@ def connected_component_containing_vertex(G, vertex, sort=True): Traceback (most recent call last): ... TypeError: the input must be a Sage graph + + :trac:`35889` is fixed:: + + sage: G = Graph([('A', 1)]) + sage: G.connected_component_containing_vertex(1, sort=False) + [1, 'A'] + sage: G.connected_component_containing_vertex(1, sort=True) + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' + + When parameter ``key`` is set, parameter ``sort`` must be ``True``:: + + sage: G = Graph(2) + sage: G.connected_component_containing_vertex(1, sort=False, key=lambda x: x) + Traceback (most recent call last): + ... + ValueError: sort keyword is False, yet a key function is given + + Deprecation warning for ``sort=None`` (:trac:`35889`):: + + sage: G = graphs.HouseGraph() + sage: G.connected_component_containing_vertex(1) + doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future + See https://github.com/sagemath/sage/issues/35889 for details. + [0, 1, 2, 3, 4] """ from sage.graphs.generic_graph import GenericGraph if not isinstance(G, GenericGraph): raise TypeError("the input must be a Sage graph") + if sort is None: + if key is None: + deprecation(35889, "parameter 'sort' will be set to False by default in the future") + sort = True + + if (not sort) and key: + raise ValueError('sort keyword is False, yet a key function is given') + try: c = list(G._backend.depth_first_search(vertex, ignore_direction=True)) except AttributeError: c = list(G.depth_first_search(vertex, ignore_direction=True)) if sort: - c.sort() + return sorted(c, key=key) return c @@ -328,7 +415,7 @@ def connected_components_sizes(G): return [len(cc) for cc in connected_components(G, sort=False)] -def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False): +def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False, key=None): """ Return the blocks and cut vertices of the graph. @@ -354,6 +441,10 @@ def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False): the components and the list of cut vertices **currently only available for ``"Tarjan_Sage"``** + - ``key`` -- a function (default: ``None``); a function that takes a + vertex as its one argument and returns a value that can be used for + comparisons in the sorting algorithm (we must have ``sort=True``) + OUTPUT: ``(B, C)``, where ``B`` is a list of blocks - each is a list of vertices and the blocks are the corresponding induced subgraphs - and ``C`` is a list of cut vertices. @@ -442,6 +533,9 @@ def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False): raise NotImplementedError("blocks and cut vertices algorithm '%s' is not implemented" % algorithm) # If algorithm is "Tarjan_Sage" + if (not sort) and key: + raise ValueError('sort keyword is False, yet a key function is given') + blocks = [] cut_vertices = set() @@ -534,7 +628,7 @@ def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False): u1, u2 = edge_stack.pop() new_block.add(u1) if sort: - this_block = sorted(new_block) + this_block = sorted(new_block, key=key) else: this_block = list(new_block) blocks.append(this_block) @@ -549,9 +643,8 @@ def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False): start_already_seen = True if sort: - return blocks, sorted(cut_vertices) - else: - return blocks, list(cut_vertices) + return blocks, sorted(cut_vertices, key=key) + return blocks, list(cut_vertices) def blocks_and_cuts_tree(G): @@ -1045,7 +1138,9 @@ def edge_connectivity(G, sage: g = graphs.PetersenGraph() sage: edge_connectivity((2 * g), vertices=True) - [0, [], [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]]] + [0, [], [{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}]] + sage: edge_connectivity(Graph(), vertices=True) + [0, [], [{}, {}]] If ``G`` is not a Sage graph, an error is raised:: @@ -1081,9 +1176,8 @@ def edge_connectivity(G, if value_only: return 0 elif vertices: - return [0, [], [[], []]] - else: - return [0, []] + return [0, [], [{}, {}]] + return [0, []] if implementation == "boost": from sage.graphs.base.boost_graph import edge_connectivity @@ -1104,9 +1198,9 @@ def edge_connectivity(G, b = set(H).difference(a) val.append([a, b]) else: - val.append(connected_components(H)) + val.append([set(c) for c in connected_components(H, sort=False)]) elif vertices: - val.append(connected_components(G)) + val.append([set(c) for c in connected_components(G, sort=False)]) return val @@ -1180,29 +1274,27 @@ def edge_connectivity(G, if value_only: return obj - else: - val = [obj] - - in_set = p.get_values(in_set, convert=bool, tolerance=integrality_tolerance) + val = [obj] + in_set = p.get_values(in_set, convert=bool, tolerance=integrality_tolerance) - if g.is_directed(): - edges = [(u, v, l) for u, v, l in g.edge_iterator() if in_cut[u, v]] - else: - edges = [(u, v, l) for u, v, l in g.edge_iterator() if in_cut[frozenset((u, v))]] + if g.is_directed(): + edges = [(u, v, l) for u, v, l in g.edge_iterator() if in_cut[u, v]] + else: + edges = [(u, v, l) for u, v, l in g.edge_iterator() if in_cut[frozenset((u, v))]] - val.append(edges) + val.append(edges) - if vertices: - a = [] - b = [] - for v in g: - if in_set[0, v]: - a.append(v) - else: - b.append(v) - val.append([a, b]) + if vertices: + a = {} + b = {} + for v in g: + if in_set[0, v]: + a.add(v) + else: + b.add(v) + val.append([a, b]) - return val + return val def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, verbose=0, @@ -1266,25 +1358,25 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver A basic application on a ``PappusGraph``:: sage: from sage.graphs.connectivity import vertex_connectivity - sage: g=graphs.PappusGraph() - sage: vertex_connectivity(g) + sage: g = graphs.PappusGraph() + sage: vertex_connectivity(g) # needs sage.numerical.mip 3 - sage: g.vertex_connectivity() + sage: g.vertex_connectivity() # needs sage.numerical.mip 3 In a grid, the vertex connectivity is equal to the minimum degree, in which case one of the two sets is of cardinality `1`:: sage: g = graphs.GridGraph([ 3,3 ]) - sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True) - sage: len(setA) == 1 or len(setB) == 1 + sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True) # needs sage.numerical.mip + sage: len(setA) == 1 or len(setB) == 1 # needs sage.numerical.mip True A vertex cut in a tree is any internal vertex:: sage: tree = graphs.RandomTree(15) - sage: val, [cut_vertex] = vertex_connectivity(tree, value_only=False) - sage: tree.degree(cut_vertex) > 1 + sage: val, [cut_vertex] = vertex_connectivity(tree, value_only=False) # needs sage.numerical.mip + sage: tree.degree(cut_vertex) > 1 # needs sage.numerical.mip True When ``value_only = True``, this function is optimized for small @@ -1293,41 +1385,41 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver It is the case for connected graphs which are not connected:: sage: g = 2 * graphs.PetersenGraph() - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 0 Or if they are just 1-connected:: sage: g = graphs.PathGraph(10) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 1 For directed graphs, the strong connectivity is tested through the dedicated function:: sage: g = digraphs.ButterflyGraph(3) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 0 A complete graph on `10` vertices is `9`-connected:: sage: g = graphs.CompleteGraph(10) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 9 A complete digraph on `10` vertices is `9`-connected:: sage: g = DiGraph(graphs.CompleteGraph(10)) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 9 When parameter ``k`` is set, we only check for the existence of a vertex cut of order at least ``k``:: sage: g = graphs.PappusGraph() - sage: vertex_connectivity(g, k=3) + sage: vertex_connectivity(g, k=3) # needs sage.numerical.mip True - sage: vertex_connectivity(g, k=4) + sage: vertex_connectivity(g, k=4) # needs sage.numerical.mip False TESTS: @@ -1346,13 +1438,13 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver sage: from sage.graphs.connectivity import is_strongly_connected sage: from sage.graphs.connectivity import is_connected sage: empty = Graph() - sage: vertex_connectivity(empty) + sage: vertex_connectivity(empty) # needs sage.numerical.mip 0 - sage: vertex_connectivity(empty, k=1) == is_connected(empty) + sage: vertex_connectivity(empty, k=1) == is_connected(empty) # needs sage.numerical.mip True - sage: vertex_connectivity(Graph(), k=2) == empty.is_biconnected() + sage: vertex_connectivity(Graph(), k=2) == empty.is_biconnected() # needs sage.numerical.mip True - sage: vertex_connectivity(DiGraph(), k=1) == is_strongly_connected(DiGraph()) + sage: vertex_connectivity(DiGraph(), k=1) == is_strongly_connected(DiGraph()) # needs sage.numerical.mip True If ``G`` is not a Sage (Di)Graph, an error is raised:: @@ -1365,16 +1457,16 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver Complete Graph with loops or multiple edges (:trac:`25589`):: sage: G = Graph([(0, 1), (0, 1)], multiedges=True) - sage: G.vertex_connectivity() + sage: G.vertex_connectivity() # needs sage.numerical.mip 1 sage: G = graphs.CompleteGraph(4) sage: G.allow_loops(True) sage: G.add_edge(0, 0) - sage: G.vertex_connectivity(value_only=False, verbose=1) + sage: G.vertex_connectivity(value_only=False, verbose=1) # needs sage.numerical.mip (3, []) sage: G.allow_multiple_edges(True) sage: G.add_edge(0, 1) - sage: G.vertex_connectivity(value_only=False, verbose=1) + sage: G.vertex_connectivity(value_only=False, verbose=1) # needs sage.numerical.mip (3, []) """ from sage.graphs.generic_graph import GenericGraph @@ -1408,8 +1500,7 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver return max(g.order() - 1, 0) elif not sets: return max(g.order() - 1, 0), [] - else: - return max(g.order() - 1, 0), [], [[], []] + return max(g.order() - 1, 0), [], [[], []] if value_only: if G.is_directed(): @@ -2128,7 +2219,7 @@ def cleave(G, cut_vertices=None, virtual_edges=True, solver=None, verbose=0, H = G.copy(immutable=False) H.delete_vertices(cut_vertices) - CC = H.connected_components() + CC = H.connected_components(sort=False) if len(CC) == 1: raise ValueError("the set cut_vertices is not a vertex cut of the graph") @@ -2284,21 +2375,21 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0, sage: T = spqr_tree(G, algorithm="Hopcroft_Tarjan") sage: G.is_isomorphic(spqr_tree_to_graph(T)) True - sage: T2 = spqr_tree(G, algorithm='cleave') - sage: G.is_isomorphic(spqr_tree_to_graph(T2)) + sage: T2 = spqr_tree(G, algorithm='cleave') # needs sage.numerical.mip + sage: G.is_isomorphic(spqr_tree_to_graph(T2)) # needs sage.numerical.mip True sage: G = Graph([(0, 1)], multiedges=True) - sage: T = spqr_tree(G, algorithm='cleave') - sage: T.vertices(sort=True) + sage: T = spqr_tree(G, algorithm='cleave') # needs sage.numerical.mip + sage: T.vertices(sort=True) # needs sage.numerical.mip [('Q', Multi-graph on 2 vertices)] - sage: G.is_isomorphic(spqr_tree_to_graph(T)) + sage: G.is_isomorphic(spqr_tree_to_graph(T)) # needs sage.numerical.mip True sage: T = spqr_tree(G, algorithm='Hopcroft_Tarjan') sage: T.vertices(sort=True) [('Q', Multi-graph on 2 vertices)] sage: G.add_edge(0, 1) - sage: spqr_tree(G, algorithm='cleave').vertices(sort=True) + sage: spqr_tree(G, algorithm='cleave').vertices(sort=True) # needs sage.numerical.mip [('P', Multi-graph on 2 vertices)] sage: from collections import Counter @@ -2306,24 +2397,24 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0, sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan") sage: Counter(u[0] for u in T) Counter({'R': 1}) - sage: T = G.spqr_tree(algorithm="cleave") - sage: Counter(u[0] for u in T) + sage: T = G.spqr_tree(algorithm="cleave") # needs sage.numerical.mip + sage: Counter(u[0] for u in T) # needs sage.numerical.mip Counter({'R': 1}) sage: for u,v in list(G.edges(labels=False, sort=False)): ....: G.add_path([u, G.add_vertex(), G.add_vertex(), v]) sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan") sage: sorted(Counter(u[0] for u in T).items()) [('P', 15), ('R', 1), ('S', 15)] - sage: T = G.spqr_tree(algorithm="cleave") - sage: sorted(Counter(u[0] for u in T).items()) + sage: T = G.spqr_tree(algorithm="cleave") # needs sage.numerical.mip + sage: sorted(Counter(u[0] for u in T).items()) # needs sage.numerical.mip [('P', 15), ('R', 1), ('S', 15)] sage: for u,v in list(G.edges(labels=False, sort=False)): ....: G.add_path([u, G.add_vertex(), G.add_vertex(), v]) sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan") sage: sorted(Counter(u[0] for u in T).items()) [('P', 60), ('R', 1), ('S', 75)] - sage: T = G.spqr_tree(algorithm="cleave") # long time - sage: sorted(Counter(u[0] for u in T).items()) # long time + sage: T = G.spqr_tree(algorithm="cleave") # long time # needs sage.numerical.mip + sage: sorted(Counter(u[0] for u in T).items()) # long time # needs sage.numerical.mip [('P', 60), ('R', 1), ('S', 75)] TESTS:: @@ -2719,7 +2810,7 @@ cdef class _Component: ....: 'comp.add_edge(3)', ....: 'comp.finish_tric_or_poly(4)', ....: 'print(comp)'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython Polygon: 2 3 4 """ self.mem = MemoryAllocator() @@ -2766,7 +2857,7 @@ cdef class _Component: ....: 'comp.add_edge(3)', ....: 'comp.finish_tric_or_poly(4)', ....: 'print(comp)'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython Polygon: 2 3 4 """ if self.component_type == 0: @@ -3203,8 +3294,7 @@ cdef class TriconnectivitySPQR: cdef _LinkedListNode * head = _LinkedList_get_head(self.highpt[v]) if head: return head.data - else: - return 0 + return 0 cdef __del_high(self, int e_index): """ @@ -4249,8 +4339,8 @@ def is_triconnected(G): Comparing different methods on random graphs that are not always triconnected:: - sage: G = graphs.RandomBarabasiAlbert(50, 3) - sage: G.is_triconnected() == G.vertex_connectivity(k=3) + sage: G = graphs.RandomBarabasiAlbert(50, 3) # needs networkx + sage: G.is_triconnected() == G.vertex_connectivity(k=3) # needs networkx True .. SEEALSO:: diff --git a/src/sage/graphs/convexity_properties.pyx b/src/sage/graphs/convexity_properties.pyx index a7243cc8d7a..b2a96335d44 100644 --- a/src/sage/graphs/convexity_properties.pyx +++ b/src/sage/graphs/convexity_properties.pyx @@ -41,7 +41,6 @@ from sage.numerical.backends.generic_backend cimport GenericBackend from sage.numerical.backends.generic_backend import get_solver from sage.graphs.distances_all_pairs cimport c_distances_all_pairs from cysignals.memory cimport sig_free -from cysignals.signals cimport sig_on, sig_off from memory_allocator cimport MemoryAllocator from libc.stdint cimport uint32_t from sage.graphs.base.static_sparse_graph cimport (short_digraph, @@ -436,7 +435,7 @@ cdef class ConvexityProperties: p.add_variables(self._n, 0, None, True, False, False, 1, None) # We know that at least 2 vertices are required to cover the whole graph - p.add_linear_constraint([(i, 1) for i in xrange(self._n)], 2, None) + p.add_linear_constraint([(i, 1) for i in range(self._n)], 2, None) # The set of vertices generated by the current LP solution cdef bitset_t current_hull diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 448a0d280d1..d30d5e63efa 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -84,7 +84,6 @@ :meth:`~DiGraph.strongly_connected_components_subgraphs` | Return the strongly connected components as a list of subgraphs. :meth:`~DiGraph.strongly_connected_component_containing_vertex` | Return the strongly connected component containing a given vertex :meth:`~DiGraph.strongly_connected_components` | Return the list of strongly connected components. - :meth:`~DiGraph.immediate_dominators` | Return the immediate dominators of all vertices reachable from `root`. :meth:`~DiGraph.strong_articulation_points` | Return the strong articulation points of this digraph. @@ -315,6 +314,11 @@ class DiGraph(GenericGraph): immutable digraph. Note that ``immutable=True`` is actually a shortcut for ``data_structure='static_sparse'``. + - ``hash_labels`` -- boolean (default: ``None``); whether to include edge + labels during hashing. This parameter defaults to ``True`` if the digraph + is weighted. This parameter is ignored if the digraph is mutable. + Beware that trying to hash unhashable labels will raise an error. + - ``vertex_labels`` -- boolean (default: ``True``); whether to allow any object as a vertex (slower), or only the integers `0,...,n-1`, where `n` is the number of vertices. @@ -352,7 +356,7 @@ class DiGraph(GenericGraph): sage: g = DiGraph([[1..12], lambda i,j: i != j and i.divides(j)]) sage: g.vertices(sort=True) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] - sage: g.adjacency_matrix() + sage: g.adjacency_matrix() # needs sage.modules [0 1 1 1 1 1 1 1 1 1 1 1] [0 0 0 1 0 1 0 1 0 1 0 1] [0 0 0 0 0 1 0 0 1 0 0 1] @@ -372,34 +376,36 @@ class DiGraph(GenericGraph): - an adjacency matrix:: - sage: M = Matrix([[0, 1, 1, 1, 0],[0, 0, 0, 0, 0],[0, 0, 0, 0, 1],[0, 0, 0, 0, 0],[0, 0, 0, 0, 0]]); M + sage: M = Matrix([[0, 1, 1, 1, 0], [0, 0, 0, 0, 0], # needs sage.modules + ....: [0, 0, 0, 0, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]); M [0 1 1 1 0] [0 0 0 0 0] [0 0 0 0 1] [0 0 0 0 0] [0 0 0 0 0] - sage: DiGraph(M) + sage: DiGraph(M) # needs sage.modules Digraph on 5 vertices - sage: M = Matrix([[0,1,-1],[-1,0,-1/2],[1,1/2,0]]); M + sage: M = Matrix([[0,1,-1], [-1,0,-1/2], [1,1/2,0]]); M # needs sage.modules [ 0 1 -1] [ -1 0 -1/2] [ 1 1/2 0] - sage: G = DiGraph(M,sparse=True,weighted=True); G + sage: G = DiGraph(M, sparse=True, weighted=True); G # needs sage.modules Digraph on 3 vertices - sage: G.weighted() + sage: G.weighted() # needs sage.modules True - an incidence matrix:: - sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M + sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, # needs sage.modules + ....: 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M [-1 0 0 0 1] [ 1 -1 0 0 0] [ 0 1 -1 0 0] [ 0 0 1 -1 0] [ 0 0 0 1 -1] [ 0 0 0 0 0] - sage: DiGraph(M) + sage: DiGraph(M) # needs sage.modules Digraph on 6 vertices #. A ``dig6`` string: Sage automatically recognizes whether a string is in @@ -422,17 +428,17 @@ class DiGraph(GenericGraph): #. A NetworkX MultiDiGraph:: - sage: import networkx - sage: g = networkx.MultiDiGraph({0: [1, 2, 3], 2: [4]}) - sage: DiGraph(g) + sage: import networkx # needs networkx + sage: g = networkx.MultiDiGraph({0: [1, 2, 3], 2: [4]}) # needs networkx + sage: DiGraph(g) # needs networkx Multi-digraph on 5 vertices #. A NetworkX digraph:: - sage: import networkx - sage: g = networkx.DiGraph({0: [1, 2, 3], 2: [4]}) - sage: DiGraph(g) + sage: import networkx # needs networkx + sage: g = networkx.DiGraph({0: [1, 2, 3], 2: [4]}) # needs networkx + sage: DiGraph(g) # needs networkx Digraph on 5 vertices #. An igraph directed Graph (see also @@ -446,11 +452,12 @@ class DiGraph(GenericGraph): If ``vertex_labels`` is ``True``, the names of the vertices are given by the vertex attribute ``'name'``, if available:: - sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'name':['a','b','c']}) # optional - python_igraph - sage: DiGraph(g).vertices(sort=True) # optional - python_igraph + sage: # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'name':['a','b','c']}) + sage: DiGraph(g).vertices(sort=True) ['a', 'b', 'c'] - sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'label':['a','b','c']}) # optional - python_igraph - sage: DiGraph(g).vertices(sort=True) # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'label':['a','b','c']}) + sage: DiGraph(g).vertices(sort=True) [0, 1, 2] If the igraph Graph has edge attributes, they are used as edge labels:: @@ -472,6 +479,7 @@ class DiGraph(GenericGraph): Demonstrate that digraphs using the static backend are equal to mutable graphs but can be used as dictionary keys:: + sage: # needs networkx sage: import networkx sage: g = networkx.DiGraph({0:[1,2,3], 2:[4]}) sage: G = DiGraph(g) @@ -493,10 +501,10 @@ class DiGraph(GenericGraph): specifying the ``immutable`` optional argument (not only by ``data_structure='static_sparse'`` as above):: - sage: J_imm = DiGraph(G, immutable=True) - sage: J_imm == G_imm + sage: J_imm = DiGraph(G, immutable=True) # needs networkx + sage: J_imm == G_imm # needs networkx True - sage: type(J_imm._backend) == type(G_imm._backend) + sage: type(J_imm._backend) == type(G_imm._backend) # needs networkx True From a list of vertices and a list of edges:: @@ -508,7 +516,7 @@ class DiGraph(GenericGraph): Check that :trac:`27505` is fixed:: - sage: DiGraph(DiGraph().networkx_graph(), weighted=None, format='NX') + sage: DiGraph(DiGraph().networkx_graph(), weighted=None, format='NX') # needs networkx Digraph on 0 vertices """ _directed = True @@ -517,7 +525,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, data_structure="sparse", vertex_labels=True, name=None, multiedges=None, convert_empty_dict_labels_to_None=None, - sparse=True, immutable=False): + sparse=True, immutable=False, hash_labels=None): """ TESTS:: @@ -525,12 +533,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None, sage: loads(dumps(D)) == D True - sage: a = matrix(2,2,[1,2,0,1]) - sage: DiGraph(a,sparse=True).adjacency_matrix() == a + sage: a = matrix(2,2,[1,2,0,1]) # needs sage.modules + sage: DiGraph(a, sparse=True).adjacency_matrix() == a # needs sage.modules True - sage: a = matrix(2,2,[3,2,0,1]) - sage: DiGraph(a,sparse=True).adjacency_matrix() == a + sage: a = matrix(2,2,[3,2,0,1]) # needs sage.modules + sage: DiGraph(a, sparse=True).adjacency_matrix() == a # needs sage.modules True The positions are copied when the DiGraph is built from another DiGraph @@ -570,11 +578,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None, Problem with weighted adjacency matrix (:trac:`13919`):: - sage: B = {0:{1:2,2:5,3:4},1:{2:2,4:7},2:{3:1,4:4,5:3},3:{5:4},4:{5:1,6:5},5:{4:1,6:7,5:1}} + sage: B = {0:{1:2,2:5,3:4},1:{2:2,4:7},2:{3:1,4:4,5:3}, + ....: 3:{5:4},4:{5:1,6:5},5:{4:1,6:7,5:1}} sage: grafo3 = DiGraph(B, weighted=True) - sage: matad = grafo3.weighted_adjacency_matrix() - sage: grafo4 = DiGraph(matad, format="adjacency_matrix", weighted=True) - sage: grafo4.shortest_path(0, 6, by_weight=True) + sage: matad = grafo3.weighted_adjacency_matrix() # needs sage.modules + sage: grafo4 = DiGraph(matad, format="adjacency_matrix", weighted=True) # needs sage.modules + sage: grafo4.shortest_path(0, 6, by_weight=True) # needs sage.modules [0, 1, 2, 5, 4, 6] Building a DiGraph with ``immutable=False`` returns a mutable graph:: @@ -842,6 +851,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None, # weighted, multiedges, loops, verts and num_verts should now be set self._weighted = weighted + if hash_labels is None and hasattr(data, '_hash_labels'): + hash_labels = data._hash_labels + self._hash_labels = hash_labels + self._pos = copy(pos) if format != 'DiGraph' or name is not None: @@ -856,6 +869,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, self._immutable = True # Formats + def dig6_string(self): r""" Return the ``dig6`` representation of the digraph as an ASCII string. @@ -910,8 +924,8 @@ def is_directed(self): # Properties def is_directed_acyclic(self, certificate=False): - """ - Return whether the digraph is acyclic or not. + r""" + Check whether the digraph is acyclic or not. A directed graph is acyclic if for any vertex `v`, there is no directed path that starts and ends at `v`. Every directed acyclic graph (DAG) @@ -930,8 +944,8 @@ def is_directed_acyclic(self, certificate=False): * When ``certificate=True``: * If the graph is acyclic, returns a pair ``(True, ordering)`` where - ``ordering`` is a list of the vertices such that ``u`` appears - before ``v`` in ``ordering`` if ``u, v`` is an edge. + ``ordering`` is a list of the vertices such that `u` appears + before `v` in ``ordering`` if `uv` is an edge. * Else, returns a pair ``(False, cycle)`` where ``cycle`` is a list of vertices representing a circuit in the graph. @@ -941,7 +955,7 @@ def is_directed_acyclic(self, certificate=False): At first, the following graph is acyclic:: sage: D = DiGraph({0:[1, 2, 3], 4:[2, 5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10]}) - sage: D.plot(layout='circular').show() + sage: D.plot(layout='circular').show() # needs sage.plot sage: D.is_directed_acyclic() True @@ -977,7 +991,7 @@ def is_directed_acyclic(self, certificate=False): ....: return h ... sage: all(random_acyclic(100, .2).is_directed_acyclic() # long time - ....: for i in range(50)) # long time + ....: for i in range(50)) True TESTS: @@ -1259,8 +1273,7 @@ def in_degree(self, vertices=None, labels=False): return self._backend.in_degree(vertices) elif labels: return {v: d for v, d in self.in_degree_iterator(vertices, labels=labels)} - else: - return list(self.in_degree_iterator(vertices, labels=labels)) + return list(self.in_degree_iterator(vertices, labels=labels)) def in_degree_iterator(self, vertices=None, labels=False): """ @@ -1330,8 +1343,7 @@ def out_degree(self, vertices=None, labels=False): return self._backend.out_degree(vertices) elif labels: return {v: d for v, d in self.out_degree_iterator(vertices, labels=labels)} - else: - return list(self.out_degree_iterator(vertices, labels=labels)) + return list(self.out_degree_iterator(vertices, labels=labels)) def out_degree_iterator(self, vertices=None, labels=False): """ @@ -1444,12 +1456,12 @@ def degree_polynomial(self): EXAMPLES:: - sage: G = posets.PentagonPoset().hasse_diagram() - sage: G.degree_polynomial() + sage: G = posets.PentagonPoset().hasse_diagram() # needs sage.modules + sage: G.degree_polynomial() # needs sage.modules x^2 + 3*x*y + y^2 sage: G = posets.BooleanLattice(4).hasse_diagram() - sage: G.degree_polynomial().factor() + sage: G.degree_polynomial().factor() # needs sage.libs.pari (x + y)^4 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -1550,7 +1562,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, sage: dcycle=DiGraph(cycle) sage: cycle.size() 5 - sage: dcycle.feedback_edge_set(value_only=True) + sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip 5 And in this situation, for any edge `uv` of the first graph, `uv` of @@ -1560,9 +1572,9 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, sage: while not g.num_edges(): ....: g = graphs.RandomGNP(5,.3) sage: dg = DiGraph(g) - sage: feedback = dg.feedback_edge_set() + sage: feedback = dg.feedback_edge_set() # needs sage.numerical.mip sage: u,v,l = next(g.edge_iterator()) - sage: (u,v) in feedback or (v,u) in feedback + sage: (u,v) in feedback or (v,u) in feedback # needs sage.numerical.mip True TESTS: @@ -1570,7 +1582,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, Comparing with/without constraint generation. Also double-checks issue :trac:`12833`:: - sage: for i in range(20): + sage: for i in range(20): # needs sage.numerical.mip ....: g = digraphs.RandomDirectedGNP(10, .3) ....: x = g.feedback_edge_set(value_only=True) ....: y = g.feedback_edge_set(value_only=True, @@ -1581,34 +1593,37 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, Loops are part of the feedback edge set (:trac:`23989`):: + sage: # needs sage.combinat sage: D = digraphs.DeBruijn(2, 2) sage: sorted(D.loops(labels=None)) [('00', '00'), ('11', '11')] - sage: FAS = D.feedback_edge_set(value_only=False) - sage: all(l in FAS for l in D.loops(labels=None)) + sage: FAS = D.feedback_edge_set(value_only=False) # needs sage.numerical.mip + sage: all(l in FAS for l in D.loops(labels=None)) # needs sage.numerical.mip True - sage: FAS2 = D.feedback_edge_set(value_only=False, constraint_generation=False) - sage: len(FAS) == len(FAS2) + sage: FAS2 = D.feedback_edge_set(value_only=False, # needs sage.numerical.mip + ....: constraint_generation=False) + sage: len(FAS) == len(FAS2) # needs sage.numerical.mip True Check that multi-edges are properly taken into account:: sage: cycle = graphs.CycleGraph(5) sage: dcycle = DiGraph(cycle) - sage: dcycle.feedback_edge_set(value_only=True) + sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip 5 sage: dcycle.allow_multiple_edges(True) sage: dcycle.add_edges(dcycle.edges(sort=True)) - sage: dcycle.feedback_edge_set(value_only=True) + sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip 10 - sage: dcycle.feedback_edge_set(value_only=True, constraint_generation=False) + sage: dcycle.feedback_edge_set(value_only=True, # needs sage.numerical.mip + ....: constraint_generation=False) 10 Strongly connected components are well handled (:trac:`23989`):: sage: g = digraphs.Circuit(3) * 2 sage: g.add_edge(0, 3) - sage: g.feedback_edge_set(value_only=True) + sage: g.feedback_edge_set(value_only=True) # needs sage.numerical.mip 2 """ # It would be a pity to start a LP if the digraph is already acyclic @@ -1618,14 +1633,16 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, if self.has_loops(): # We solve the problem on a copy without loops of the digraph D = DiGraph(self.edges(sort=False), multiedges=self.allows_multiple_edges(), loops=True) - D.allow_loops(False) + loops = D.loops(labels=None) + D.delete_edges(loops) + D.allow_loops(False, check=False) FAS = D.feedback_edge_set(constraint_generation=constraint_generation, value_only=value_only, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if value_only: - return FAS + self.number_of_loops() + return FAS + len(loops) else: - return FAS + self.loops(labels=None) + return FAS + loops if not self.is_strongly_connected(): # If the digraph is not strongly connected, we solve the problem on @@ -1634,6 +1651,8 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, FAS = 0 if value_only else [] for h in self.strongly_connected_components_subgraphs(): + if not h.size(): + continue if value_only: FAS += h.feedback_edge_set(constraint_generation=constraint_generation, value_only=True, solver=solver, verbose=verbose, @@ -1678,9 +1697,8 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, if isok: if value_only: return sum(1 for e in self.edge_iterator(labels=False) if val[e]) - else: - # listing the edges contained in the MFAS - return [e for e in self.edge_iterator(labels=False) if val[e]] + # listing the edges contained in the MFAS + return [e for e in self.edge_iterator(labels=False) if val[e]] # There is a circuit left. Let's add the corresponding # constraint ! @@ -1723,28 +1741,92 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, if value_only: return sum(1 for e in self.edge_iterator(labels=False) if b_sol[e]) - else: - return [e for e in self.edge_iterator(labels=False) if b_sol[e]] + return [e for e in self.edge_iterator(labels=False) if b_sol[e]] # Construction - def reverse(self): + def reverse(self, immutable=None): """ Return a copy of digraph with edges reversed in direction. + INPUT: + + - ``immutable`` -- boolean (default: ``None``); whether to return an + immutable digraph or not. By default (``None``), the returned digraph + has the same setting than ``self``. That is, if ``self`` is immutable, + the returned digraph also is. + EXAMPLES:: - sage: D = DiGraph({0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1]}) - sage: D.reverse() + sage: adj = {0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1]} + sage: D = DiGraph(adj) + sage: R = D.reverse(); R Reverse of (): Digraph on 6 vertices + sage: H = R.reverse() + sage: adj == H.to_dictionary() + True + + TESTS:: + + sage: adj = {0: [1, 1], 1: [1]} + sage: D = DiGraph(adj, immutable=True, multiedges=True, loops=True) + sage: R = D.reverse() + sage: R.is_immutable() and R.allows_loops() and R.allows_multiple_edges() + True + sage: adj == R.reverse().to_dictionary(multiple_edges=True) + True + + Check the behavior of parameter ``immutable``:: + + sage: D = DiGraph([(0, 1)], immutable=False) + sage: R = D.reverse() + sage: R.is_immutable() + False + sage: R = D.reverse(immutable=True) + sage: R.is_immutable() + True + sage: H = R.reverse() + sage: H.is_immutable() + True + sage: H = R.reverse(immutable=False) + sage: H.is_immutable() + False """ - H = DiGraph(multiedges=self.allows_multiple_edges(), loops=self.allows_loops()) + from sage.graphs.base.dense_graph import DenseGraphBackend + if isinstance(self._backend, DenseGraphBackend): + data_structure = "dense" + else: + data_structure = "sparse" + + H = DiGraph(data_structure=data_structure, + multiedges=self.allows_multiple_edges(), loops=self.allows_loops(), + pos=copy(self._pos), weighted=self.weighted(), + hash_labels=self._hash_labels) H.add_vertices(self) H.add_edges((v, u, d) for u, v, d in self.edge_iterator()) name = self.name() if name is None: name = '' H.name("Reverse of (%s)" % name) + + attributes_to_copy = ('_assoc', '_embedding') + for attr in attributes_to_copy: + if hasattr(self, attr): + copy_attr = {} + old_attr = getattr(self, attr) + if isinstance(old_attr, dict): + for v, value in old_attr.items(): + try: + copy_attr[v] = value.copy() + except AttributeError: + copy_attr[v] = copy(value) + setattr(H, attr, copy_attr) + else: + setattr(H, attr, copy(old_attr)) + + if immutable or (immutable is None and self.is_immutable()): + return H.copy(immutable=True) + return H def reverse_edge(self, u, v=None, label=None, inplace=True, multiedges=None): @@ -2058,9 +2140,10 @@ def reverse_edges(self, edges, inplace=True, multiedges=None): [(0, 5, None), (1, 0, None), (2, 1, None), (3, 2, None), (4, 3, None), (5, 4, None)] - sage: D = digraphs.Kautz(2, 3) - sage: Dr = D.reverse_edges(D.edges(sort=True), inplace=False, multiedges=True) - sage: Dr.edges(sort=True) == D.reverse().edges(sort=True) + sage: D = digraphs.Kautz(2, 3) # needs sage.combinat + sage: Dr = D.reverse_edges(D.edges(sort=True), inplace=False, # needs sage.combinat + ....: multiedges=True) + sage: Dr.edges(sort=True) == D.reverse().edges(sort=True) # needs sage.combinat True """ tempG = self if inplace else copy(self) @@ -2163,37 +2246,37 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, sage: G.eccentricity(with_labels=True) {0: 0} sage: G = DiGraph([(0,1,2), (1,2,3), (2,0,2)]) - sage: G.eccentricity(algorithm = 'BFS') + sage: G.eccentricity(algorithm='BFS') [2, 2, 2] - sage: G.eccentricity(algorithm = 'Floyd-Warshall-Cython') + sage: G.eccentricity(algorithm='Floyd-Warshall-Cython') [2, 2, 2] - sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_NetworkX') + sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_NetworkX') # needs networkx [5, 5, 4] - sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_Boost') + sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_Boost') [5, 5, 4] - sage: G.eccentricity(by_weight = True, algorithm = 'Johnson_Boost') + sage: G.eccentricity(by_weight=True, algorithm='Johnson_Boost') [5, 5, 4] - sage: G.eccentricity(by_weight = True, algorithm = 'Floyd-Warshall-Python') + sage: G.eccentricity(by_weight=True, algorithm='Floyd-Warshall-Python') [5, 5, 4] - sage: G.eccentricity(dist_dict = G.shortest_path_all_pairs(by_weight = True)[0]) + sage: G.eccentricity(dist_dict=G.shortest_path_all_pairs(by_weight=True)[0]) [5, 5, 4] TESTS: A non-implemented algorithm:: - sage: G.eccentricity(algorithm = 'boh') + sage: G.eccentricity(algorithm='boh') Traceback (most recent call last): ... ValueError: unknown algorithm "boh" An algorithm that does not work with edge weights:: - sage: G.eccentricity(by_weight = True, algorithm = 'BFS') + sage: G.eccentricity(by_weight=True, algorithm='BFS') Traceback (most recent call last): ... ValueError: algorithm 'BFS' does not work with weights - sage: G.eccentricity(by_weight = True, algorithm = 'Floyd-Warshall-Cython') + sage: G.eccentricity(by_weight=True, algorithm='Floyd-Warshall-Cython') Traceback (most recent call last): ... ValueError: algorithm 'Floyd-Warshall-Cython' does not work with weights @@ -2201,15 +2284,15 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, An algorithm that computes the all-pair-shortest-paths when not all vertices are needed:: - sage: G.eccentricity(0, algorithm = 'Floyd-Warshall-Cython') + sage: G.eccentricity(0, algorithm='Floyd-Warshall-Cython') Traceback (most recent call last): ... ValueError: algorithm 'Floyd-Warshall-Cython' works only if all eccentricities are needed - sage: G.eccentricity(0, algorithm = 'Floyd-Warshall-Python') + sage: G.eccentricity(0, algorithm='Floyd-Warshall-Python') Traceback (most recent call last): ... ValueError: algorithm 'Floyd-Warshall-Python' works only if all eccentricities are needed - sage: G.eccentricity(0, algorithm = 'Johnson_Boost') + sage: G.eccentricity(0, algorithm='Johnson_Boost') Traceback (most recent call last): ... ValueError: algorithm 'Johnson_Boost' works only if all eccentricities are needed @@ -2249,7 +2332,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, if with_labels: return dict(zip(v, eccentricity(self, algorithm=algo, vertex_list=v))) else: - return eccentricity(self, algorithm=algo) + return eccentricity(self, algorithm=algo, vertex_list=v) if algorithm in ['Floyd-Warshall-Python', 'Floyd-Warshall-Cython', 'Johnson_Boost']: dist_dict = self.shortest_path_all_pairs(by_weight=by_weight, algorithm=algorithm, @@ -2343,11 +2426,17 @@ def radius(self, by_weight=False, algorithm=None, weight_function=None, Traceback (most recent call last): ... ValueError: radius is not defined for the empty DiGraph + + Check that :trac:`35300` is fixed:: + + sage: H = DiGraph([[42, 'John'], [(42, 'John')]]) + sage: H.radius() + 1 """ if not self.order(): raise ValueError("radius is not defined for the empty DiGraph") - return min(self.eccentricity(v=None, by_weight=by_weight, + return min(self.eccentricity(v=list(self), by_weight=by_weight, weight_function=weight_function, check_weight=check_weight, algorithm=algorithm)) @@ -2426,6 +2515,7 @@ def diameter(self, by_weight=False, algorithm=None, weight_function=None, EXAMPLES:: + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(5,4) sage: G.diameter() 4 @@ -2476,6 +2566,15 @@ def diameter(self, by_weight=False, algorithm=None, weight_function=None, 3 sage: G.diameter(algorithm='DiFUB', by_weight=True) 3.0 + + Check that :trac:`35300` is fixed:: + + sage: H = DiGraph([[42, 'John'], [(42, 'John')]]) + sage: H.diameter() + +Infinity + sage: H.add_edge('John', 42) + sage: H.diameter() + 1 """ if not self.order(): raise ValueError("diameter is not defined for the empty DiGraph") @@ -2507,7 +2606,7 @@ def diameter(self, by_weight=False, algorithm=None, weight_function=None, from sage.graphs.distances_all_pairs import diameter return diameter(self, algorithm='standard') - return max(self.eccentricity(v=None, by_weight=by_weight, + return max(self.eccentricity(v=list(self), by_weight=by_weight, weight_function=weight_function, check_weight=False, algorithm=algorithm)) @@ -3115,7 +3214,7 @@ def topological_sort(self, implementation="default"): sage: D = DiGraph({0: [1, 2, 3], 4: [2, 5], 1: [8], 2: [7], 3: [7], ....: 5: [6, 7], 7: [8], 6: [9], 8: [10], 9: [10]}) - sage: D.plot(layout='circular').show() + sage: D.plot(layout='circular').show() # needs sage.plot sage: D.topological_sort() [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10] @@ -3127,9 +3226,10 @@ def topological_sort(self, implementation="default"): Using the NetworkX implementation :: - sage: s = list(D.topological_sort(implementation="NetworkX")); s # random + sage: s = list(D.topological_sort(implementation="NetworkX")); s # random # needs networkx [0, 4, 1, 3, 2, 5, 6, 9, 7, 8, 10] - sage: all(s.index(u) < s.index(v) for u, v in D.edges(sort=False, labels=False)) + sage: all(s.index(u) < s.index(v) # needs networkx + ....: for u, v in D.edges(sort=False, labels=False)) True :: @@ -3195,13 +3295,14 @@ def topological_sort_generator(self): EXAMPLES:: sage: D = DiGraph({0: [1, 2], 1: [3], 2: [3, 4]}) - sage: D.plot(layout='circular').show() - sage: list(D.topological_sort_generator()) - [[0, 1, 2, 3, 4], [0, 2, 1, 3, 4], [0, 2, 1, 4, 3], [0, 2, 4, 1, 3], [0, 1, 2, 4, 3]] + sage: D.plot(layout='circular').show() # needs sage.plot + sage: list(D.topological_sort_generator()) # needs sage.modules sage.rings.finite_rings + [[0, 1, 2, 3, 4], [0, 2, 1, 3, 4], [0, 2, 1, 4, 3], + [0, 2, 4, 1, 3], [0, 1, 2, 4, 3]] :: - sage: for sort in D.topological_sort_generator(): + sage: for sort in D.topological_sort_generator(): # needs sage.modules sage.rings.finite_rings ....: for u, v in D.edge_iterator(labels=False): ....: if sort.index(u) > sort.index(v): ....: print("this should never happen") @@ -3561,7 +3662,7 @@ def flow_polytope(self, edges=None, ends=None, backend=None): Flow polytopes can also be built through the ``polytopes.<tab>`` object:: - sage: polytopes.flow_polytope(digraphs.Path(5)) + sage: polytopes.flow_polytope(digraphs.Path(5)) # needs sage.geometry.polyhedron A 0-dimensional polyhedron in QQ^4 defined as the convex hull of 1 vertex EXAMPLES: @@ -3569,26 +3670,27 @@ def flow_polytope(self, edges=None, ends=None, backend=None): A commutative square:: sage: G = DiGraph({1: [2, 3], 2: [4], 3: [4]}) - sage: fl = G.flow_polytope(); fl + sage: fl = G.flow_polytope(); fl # needs sage.geometry.polyhedron A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices - sage: fl.vertices() + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 1, 0, 1), A vertex at (1, 0, 1, 0)) Using a different order for the edges of the graph:: - sage: fl = G.flow_polytope(edges=G.edges(key=lambda x: x[0] - x[1])); fl + sage: ordered_edges = G.edges(sort=True, key=lambda x: x[0] - x[1]) + sage: fl = G.flow_polytope(edges=ordered_edges); fl # needs sage.geometry.polyhedron A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices - sage: fl.vertices() + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 1, 1, 0), A vertex at (1, 0, 0, 1)) A tournament on 4 vertices:: sage: H = digraphs.TransitiveTournament(4) - sage: fl = H.flow_polytope(); fl + sage: fl = H.flow_polytope(); fl # needs sage.geometry.polyhedron A 3-dimensional polyhedron in QQ^6 defined as the convex hull of 4 vertices - sage: fl.vertices() + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 0, 1, 0, 0, 0), A vertex at (0, 1, 0, 0, 0, 1), A vertex at (1, 0, 0, 0, 1, 0), @@ -3596,16 +3698,16 @@ def flow_polytope(self, edges=None, ends=None, backend=None): Restricting to a subset of the edges:: - sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), - ....: (2, 3, None), (0, 3, None)]) - sage: fl + sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), # needs sage.geometry.polyhedron + ....: (2, 3, None), (0, 3, None)]); fl A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices - sage: fl.vertices() + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 0, 0, 1), A vertex at (1, 1, 1, 0)) Using a different choice of sources and sinks:: + sage: # needs sage.geometry.polyhedron sage: fl = H.flow_polytope(ends=([1], [3])); fl A 1-dimensional polyhedron in QQ^6 defined as the convex hull of 2 vertices @@ -3639,27 +3741,25 @@ def flow_polytope(self, edges=None, ends=None, backend=None): A digraph with one source and two sinks:: sage: Y = DiGraph({1: [2], 2: [3, 4]}) - sage: Y.flow_polytope() + sage: Y.flow_polytope() # needs sage.geometry.polyhedron The empty polyhedron in QQ^3 A digraph with one vertex and no edge:: sage: Z = DiGraph({1: []}) - sage: Z.flow_polytope() + sage: Z.flow_polytope() # needs sage.geometry.polyhedron A 0-dimensional polyhedron in QQ^0 defined as the convex hull of 1 vertex A digraph with multiple edges (:trac:`28837`):: - sage: G = DiGraph([(0, 1), (0,1)], multiedges=True) - sage: G + sage: G = DiGraph([(0, 1), (0,1)], multiedges=True); G Multi-digraph on 2 vertices - sage: P = G.flow_polytope() - sage: P + sage: P = G.flow_polytope(); P # needs sage.geometry.polyhedron A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices - sage: P.vertices() + sage: P.vertices() # needs sage.geometry.polyhedron (A vertex at (1, 0), A vertex at (0, 1)) - sage: P.lines() + sage: P.lines() # needs sage.geometry.polyhedron () """ from sage.geometry.polyhedron.constructor import Polyhedron diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index 2b864b54284..3070cb2f37f 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -226,22 +226,23 @@ def ButterflyGraph(self, n, vertices='strings'): sage: digraphs.ButterflyGraph(2).edges(sort=True, labels=False) [(('00', 0), ('00', 1)), - (('00', 0), ('10', 1)), - (('00', 1), ('00', 2)), - (('00', 1), ('01', 2)), - (('01', 0), ('01', 1)), - (('01', 0), ('11', 1)), - (('01', 1), ('00', 2)), - (('01', 1), ('01', 2)), - (('10', 0), ('00', 1)), - (('10', 0), ('10', 1)), - (('10', 1), ('10', 2)), - (('10', 1), ('11', 2)), - (('11', 0), ('01', 1)), - (('11', 0), ('11', 1)), - (('11', 1), ('10', 2)), - (('11', 1), ('11', 2))] - sage: digraphs.ButterflyGraph(2,vertices='vectors').edges(sort=True, labels=False) + (('00', 0), ('10', 1)), + (('00', 1), ('00', 2)), + (('00', 1), ('01', 2)), + (('01', 0), ('01', 1)), + (('01', 0), ('11', 1)), + (('01', 1), ('00', 2)), + (('01', 1), ('01', 2)), + (('10', 0), ('00', 1)), + (('10', 0), ('10', 1)), + (('10', 1), ('10', 2)), + (('10', 1), ('11', 2)), + (('11', 0), ('01', 1)), + (('11', 0), ('11', 1)), + (('11', 1), ('10', 2)), + (('11', 1), ('11', 2))] + sage: digraphs.ButterflyGraph(2, vertices='vectors').edges(sort=True, # needs sage.modules sage.rings.finite_rings + ....: labels=False) [(((0, 0), 0), ((0, 0), 1)), (((0, 0), 0), ((1, 0), 1)), (((0, 0), 1), ((0, 0), 2)), @@ -338,7 +339,7 @@ def Path(self, n): [0, 1, 2, 3, 4] sage: g.size() 4 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 1 """ g = DiGraph(n, name="Path") @@ -370,9 +371,11 @@ def StronglyRegular(self, n): A Strongly Regular digraph satisfies the condition `AJ = JA = kJ` where `A` is the adjacency matrix:: + sage: # needs sage.modules sage: g = digraphs.StronglyRegular(7); g Strongly regular digraph: Digraph on 7 vertices - sage: A = g.adjacency_matrix()*ones_matrix(7); B = ones_matrix(7)*g.adjacency_matrix() + sage: A = g.adjacency_matrix()*ones_matrix(7) + sage: B = ones_matrix(7)*g.adjacency_matrix() sage: A == B == A[0, 0]*ones_matrix(7) True @@ -380,7 +383,7 @@ def StronglyRegular(self, n): Wrong parameter:: - sage: digraphs.StronglyRegular(73) + sage: digraphs.StronglyRegular(73) # needs sage.modules Traceback (most recent call last): ... ValueError: strongly regular digraph with 73 vertices not yet implemented @@ -413,16 +416,16 @@ def Paley(self, q): A Paley digraph has `n * (n-1) / 2` edges, its underlying graph is a clique, and so it is a tournament:: - sage: g = digraphs.Paley(7); g + sage: g = digraphs.Paley(7); g # needs sage.rings.finite_rings Paley digraph with parameter 7: Digraph on 7 vertices - sage: g.size() == g.order() * (g.order() - 1) / 2 + sage: g.size() == g.order() * (g.order() - 1) / 2 # needs sage.rings.finite_rings True - sage: g.to_undirected().is_clique() + sage: g.to_undirected().is_clique() # needs sage.rings.finite_rings True A Paley digraph is always self-complementary:: - sage: g.complement().is_isomorphic(g) + sage: g.complement().is_isomorphic(g) # needs sage.rings.finite_rings True TESTS: @@ -470,7 +473,7 @@ def TransitiveTournament(self, n): [0, 1, 2, 3, 4] sage: g.size() 10 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 1 .. SEEALSO:: @@ -890,15 +893,16 @@ def DeBruijn(self, k, n, vertices='strings'): de Bruijn digraph of degree 2 and diameter 2:: - sage: db = digraphs.DeBruijn(2, 2); db + sage: db = digraphs.DeBruijn(2, 2); db # needs sage.combinat De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices - sage: db.order(), db.size() + sage: db.order(), db.size() # needs sage.combinat (4, 8) - sage: db.diameter() + sage: db.diameter() # needs sage.combinat 2 Building a de Bruijn digraph on a different alphabet:: + sage: # needs sage.combinat sage: g = digraphs.DeBruijn(['a', 'b'], 2) sage: g.vertices(sort=True) ['aa', 'ab', 'ba', 'bb'] @@ -914,20 +918,20 @@ def DeBruijn(self, k, n, vertices='strings'): Alphabet of null size or words of length zero:: - sage: digraphs.DeBruijn(5, 0) + sage: digraphs.DeBruijn(5, 0) # needs sage.combinat De Bruijn digraph (k=5, n=0): Looped multi-digraph on 1 vertex - sage: digraphs.DeBruijn(0, 0) + sage: digraphs.DeBruijn(0, 0) # needs sage.combinat De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices :trac:`22355`:: - sage: db = digraphs.DeBruijn(2, 2, vertices='strings') - sage: db.vertices(sort=True) + sage: db = digraphs.DeBruijn(2, 2, vertices='strings') # needs sage.combinat + sage: db.vertices(sort=True) # needs sage.combinat ['00', '01', '10', '11'] sage: h = digraphs.DeBruijn(2, 2, vertices='integers') sage: h.vertices(sort=True) [0, 1, 2, 3] - sage: db.is_isomorphic(h) + sage: db.is_isomorphic(h) # needs sage.combinat True sage: digraphs.DeBruijn(0, 0, vertices='integers') De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices @@ -998,8 +1002,9 @@ def GeneralizedDeBruijn(self, n, d): EXAMPLES:: sage: GB = digraphs.GeneralizedDeBruijn(8, 2) - sage: GB.is_isomorphic(digraphs.DeBruijn(2, 3), certificate = True) - (True, {0: '000', 1: '001', 2: '010', 3: '011', 4: '100', 5: '101', 6: '110', 7: '111'}) + sage: GB.is_isomorphic(digraphs.DeBruijn(2, 3), certificate=True) # needs sage.combinat + (True, {0: '000', 1: '001', 2: '010', 3: '011', + 4: '100', 5: '101', 6: '110', 7: '111'}) TESTS: @@ -1054,14 +1059,15 @@ def ImaseItoh(self, n, d): EXAMPLES:: sage: II = digraphs.ImaseItoh(8, 2) - sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certificate = True) - (True, {0: '010', 1: '011', 2: '000', 3: '001', 4: '110', 5: '111', 6: '100', 7: '101'}) + sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certificate=True) # needs sage.combinat + (True, {0: '010', 1: '011', 2: '000', 3: '001', + 4: '110', 5: '111', 6: '100', 7: '101'}) sage: II = digraphs.ImaseItoh(12, 2) - sage: b,D = II.is_isomorphic(digraphs.Kautz(2, 3), certificate=True) - sage: b + sage: b,D = II.is_isomorphic(digraphs.Kautz(2, 3), certificate=True) # needs sage.combinat + sage: b # needs sage.combinat True - sage: D # random isomorphism + sage: D # random isomorphism # needs sage.combinat {0: '202', 1: '201', 2: '210', 3: '212', 4: '121', 5: '120', 6: '102', 7: '101', 8: '010', 9: '012', 10: '021', 11: '020'} @@ -1132,23 +1138,24 @@ def Kautz(self, k, D, vertices='strings'): EXAMPLES:: + sage: # needs sage.combinat sage: K = digraphs.Kautz(2, 3) - sage: b,D = K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate=True) + sage: b, D = K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate=True) sage: b True sage: D # random isomorphism {'010': 8, '012': 9, '020': 11, '021': 10, '101': 7, '102': 6, '120': 5, '121': 4, '201': 1, '202': 0, '210': 2, '212': 3} - sage: K = digraphs.Kautz([1,'a','B'], 2) - sage: K.edges(sort=True) + sage: K = digraphs.Kautz([1,'a','B'], 2) # needs sage.combinat + sage: K.edges(sort=True) # needs sage.combinat [('1B', 'B1', '1'), ('1B', 'Ba', 'a'), ('1a', 'a1', '1'), ('1a', 'aB', 'B'), ('B1', '1B', 'B'), ('B1', '1a', 'a'), ('Ba', 'a1', '1'), ('Ba', 'aB', 'B'), ('a1', '1B', 'B'), ('a1', '1a', 'a'), ('aB', 'B1', '1'), ('aB', 'Ba', 'a')] - sage: K = digraphs.Kautz([1,'aA','BB'], 2) - sage: K.edges(sort=True) + sage: K = digraphs.Kautz([1,'aA','BB'], 2) # needs sage.combinat + sage: K.edges(sort=True) # needs sage.combinat [('1,BB', 'BB,1', '1'), ('1,BB', 'BB,aA', 'aA'), ('1,aA', 'aA,1', '1'), ('1,aA', 'aA,BB', 'BB'), ('BB,1', '1,BB', 'BB'), ('BB,1', '1,aA', 'aA'), @@ -1160,12 +1167,12 @@ def Kautz(self, k, D, vertices='strings'): An exception is raised when the degree is less than one:: - sage: G = digraphs.Kautz(0, 2) + sage: G = digraphs.Kautz(0, 2) # needs sage.combinat Traceback (most recent call last): ... ValueError: degree must be greater than or equal to one - sage: G = digraphs.Kautz(['a'], 2) + sage: G = digraphs.Kautz(['a'], 2) # needs sage.combinat Traceback (most recent call last): ... ValueError: degree must be greater than or equal to one @@ -1173,23 +1180,23 @@ def Kautz(self, k, D, vertices='strings'): An exception is raised when the diameter of the graph is less than one:: - sage: G = digraphs.Kautz(2, 0) + sage: G = digraphs.Kautz(2, 0) # needs sage.combinat Traceback (most recent call last): ... ValueError: diameter must be greater than or equal to one :trac:`22355`:: - sage: K = digraphs.Kautz(2, 2, vertices='strings') - sage: K.vertices(sort=True) + sage: K = digraphs.Kautz(2, 2, vertices='strings') # needs sage.combinat + sage: K.vertices(sort=True) # needs sage.combinat ['01', '02', '10', '12', '20', '21'] sage: h = digraphs.Kautz(2, 2, vertices='integers') sage: h.vertices(sort=True) [0, 1, 2, 3, 4, 5] - sage: h.is_isomorphic(K) + sage: h.is_isomorphic(K) # needs sage.combinat True sage: h = digraphs.Kautz([1,'aA','BB'], 2, vertices='integers') - sage: h.is_isomorphic(K) + sage: h.is_isomorphic(K) # needs sage.combinat True sage: h.vertices(sort=True) [0, 1, 2, 3, 4, 5] @@ -1346,6 +1353,7 @@ def RandomDirectedGN(self, n, kernel=lambda x: x, seed=None): EXAMPLES:: + sage: # needs networkx sage: D = digraphs.RandomDirectedGN(25) sage: D.num_verts() 25 @@ -1355,7 +1363,7 @@ def RandomDirectedGN(self, n, kernel=lambda x: x, seed=None): True sage: D.parent() is DiGraph True - sage: D.show() # long time + sage: D.show() # long time """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1382,12 +1390,13 @@ def RandomDirectedGNC(self, n, seed=None): EXAMPLES:: + sage: # needs networkx sage: D = digraphs.RandomDirectedGNC(25) sage: D.is_directed_acyclic() True sage: D.topological_sort() [24, 23, ..., 1, 0] - sage: D.show() # long time + sage: D.show() # long time """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1583,12 +1592,13 @@ def RandomDirectedGNR(self, n, p, seed=None): EXAMPLES:: + sage: # needs networkx sage: D = digraphs.RandomDirectedGNR(25, .2) sage: D.is_directed_acyclic() True sage: D.to_undirected().is_tree() True - sage: D.show() # long time + sage: D.show() # long time # needs sage.plot """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1747,8 +1757,7 @@ def extra_property(x): if vertices is None: vertices = 0 while True: - for g in self(vertices, sparse=sparse, copy=copy): - yield g + yield from self(vertices, sparse=sparse, copy=copy) vertices += 1 from sage.graphs.graph_generators import canaug_traverse_edge diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index 87e83b4f5ce..73bbd2c62d6 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -545,7 +545,7 @@ def is_distance_regular(G, parameters=False): sage: graphs.PathGraph(2).is_distance_regular(parameters=True) ([1, None], [None, 1]) - sage: graphs.Tutte12Cage().is_distance_regular(parameters=True) + sage: graphs.Tutte12Cage().is_distance_regular(parameters=True) # needs networkx ([3, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 3]) """ @@ -629,8 +629,7 @@ def is_distance_regular(G, parameters=False): bi[diameter] = None ci[0] = None return bi, ci - else: - return True + return True ################################### @@ -843,8 +842,8 @@ cdef uint32_t * c_eccentricity_DHV(short_digraph sd) except NULL: TESTS: - sage: G = graphs.RandomBarabasiAlbert(50, 2) - sage: eccentricity(G, algorithm='bounds') == eccentricity(G, algorithm='DHV') + sage: G = graphs.RandomBarabasiAlbert(50, 2) # needs networkx + sage: eccentricity(G, algorithm='bounds') == eccentricity(G, algorithm='DHV') # needs networkx True """ cdef uint32_t n = sd.n @@ -1777,6 +1776,7 @@ def diameter(G, algorithm=None, source=None): Comparison of exact algorithms for graphs:: + sage: # needs networkx sage: G = graphs.RandomBarabasiAlbert(100, 2) sage: d1 = diameter(G, algorithm='standard') sage: d2 = diameter(G, algorithm='iFUB') @@ -1786,12 +1786,13 @@ def diameter(G, algorithm=None, source=None): Comparison of lower bound algorithms:: - sage: lb2 = diameter(G, algorithm='2sweep') - sage: lbm = diameter(G, algorithm='multi-sweep') - sage: if not (lb2 <= lbm and lbm <= d3): print("Something goes wrong!") + sage: lb2 = diameter(G, algorithm='2sweep') # needs networkx + sage: lbm = diameter(G, algorithm='multi-sweep') # needs networkx + sage: if not (lb2 <= lbm and lbm <= d3): print("Something goes wrong!") # needs networkx Comparison of exact algorithms for digraphs:: + sage: # needs networkx sage: D = DiGraph(graphs.RandomBarabasiAlbert(50, 2)) sage: d1 = diameter(D, algorithm='standard') sage: d2 = diameter(D, algorithm='DiFUB') @@ -1880,8 +1881,7 @@ def diameter(G, algorithm=None, source=None): if LB < 0 or LB > n: from sage.rings.infinity import Infinity return +Infinity - else: - return int(LB) + return int(LB) ########### @@ -2294,10 +2294,11 @@ def szeged_index(G, algorithm=None): Check that both algorithms return same value:: - sage: G = graphs.RandomBarabasiAlbert(100, 2) # long time - sage: a = szeged_index(G, algorithm='low') # long time - sage: b = szeged_index(G, algorithm='high') # long time - sage: a == b # long time + sage: # long time + sage: G = graphs.RandomBarabasiAlbert(100, 2) + sage: a = szeged_index(G, algorithm='low') + sage: b = szeged_index(G, algorithm='high') + sage: a == b True The Szeged index of a directed circuit of order `n` is `(n-1)^2`:: @@ -2438,8 +2439,8 @@ def distances_distribution(G): The de Bruijn digraph dB(2,3):: - sage: D = digraphs.DeBruijn(2,3) - sage: D.distances_distribution() + sage: D = digraphs.DeBruijn(2,3) # needs sage.combinat + sage: D.distances_distribution() # needs sage.combinat {1: 1/4, 2: 11/28, 3: 5/14} """ cdef size_t n = G.order() @@ -2572,7 +2573,7 @@ def antipodal_graph(G): if not G.is_connected(): import itertools - CC = G.connected_components() + CC = G.connected_components(sort=False) for c1, c2 in itertools.combinations(CC, 2): A.add_edges(itertools.product(c1, c2)) return A @@ -2719,8 +2720,7 @@ def floyd_warshall(gg, paths=True, distances=False): if not gverts: if distances and paths: return {}, {} - else: - return {} + return {} cdef unsigned int n = max(gverts) + 1 diff --git a/src/sage/graphs/domination.py b/src/sage/graphs/domination.py index 7997270e655..37416d428a8 100644 --- a/src/sage/graphs/domination.py +++ b/src/sage/graphs/domination.py @@ -11,6 +11,7 @@ :delim: | :meth:`~dominating_set` | Return a minimum distance-`k` dominating set of the graph. + :meth:`~dominating_sets` | Return an iterator over the minimum distance-`k` dominating sets of the graph. :meth:`~minimal_dominating_sets` | Return an iterator over the minimal dominating sets of a graph. :meth:`~is_dominating` | Check whether a set of vertices dominates a graph. :meth:`~is_redundant` | Check whether a set of vertices has redundant vertices (with respect to domination). @@ -23,7 +24,7 @@ We compute the size of a minimum dominating set of the Petersen graph:: sage: g = graphs.PetersenGraph() - sage: g.dominating_set(value_only=True) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip 3 We enumerate the minimal dominating sets of the 5-star graph:: @@ -54,7 +55,8 @@ # **************************************************************************** # Copyright (C) 2009 Nathann Cohen <nathann.cohen@gmail.com> -# 2019 Jean-Florent Raymond <j-florent.raymond@uca.fr> +# 2019 Jean-Florent Raymond <j-florent.raymond@uca.fr> +# 2023 David Coudert <david.coudert@inria.fr> # # 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 @@ -135,7 +137,7 @@ def is_redundant(G, dom, focus=None): False """ dom = list(dom) - focus = list(G) if focus is None else list(focus) + focus = G if focus is None else set(focus) # dominator[v] (for v in focus) will be equal to: # - (0, None) if v has no neighbor in dom @@ -214,13 +216,14 @@ def private_neighbors(G, vertex, dom): # ============================================================================== -# Computation of minimum dominating +# Computation of minimum dominating sets # ============================================================================== -def dominating_set(g, k=1, independent=False, total=False, value_only=False, - solver=None, verbose=0, *, integrality_tolerance=1e-3): +def dominating_sets(g, k=1, independent=False, total=False, connected=False, + solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" - Return a minimum distance-`k` dominating set of the graph. + Return an iterator over the minimum distance-`k` dominating sets + of the graph. A minimum dominating set `S` of a graph `G` is a set of its vertices of minimal cardinality such that any vertex of `G` is in `S` or has one of its @@ -242,21 +245,24 @@ def dominating_set(g, k=1, independent=False, total=False, value_only=False, \mbox{Such that : }&\forall v \in G, b_v+\sum_{u \in N^k(v)} b_u\geq 1\\ &\forall x\in G, b_x\mbox{ is a binary variable} + We use constraints generation to iterate over the minimum distance-`k` + dominating sets. That is, after reporting a solution, we add a constraint to + discard it and solve the problem again until no more solution can be found. + INPUT: - ``k`` -- a non-negative integer (default: ``1``); the domination distance - - ``independent`` -- boolean (default: ``False``); when ``True``, computes a - minimum independent dominating set, that is a minimum dominating set that - is also an independent set (see also + - ``independent`` -- boolean (default: ``False``); when ``True``, computes + minimum independent dominating sets, that is minimum dominating sets that + are also independent sets (see also :meth:`~sage.graphs.graph.independent_set`) - - ``total`` -- boolean (default: ``False``); when ``True``, computes a total - dominating set (see the See the :wikipedia:`Dominating_set`) + - ``total`` -- boolean (default: ``False``); when ``True``, computes total + dominating sets (see the See the :wikipedia:`Dominating_set`) - - ``value_only`` -- boolean (default: ``False``); whether to only return the - cardinality of the computed dominating set, or to return its list of - vertices (default) + - ``connected`` -- boolean (default: ``False``); when ``True``, computes + connected dominating sets (see :wikipedia:`Connected_dominating_set`) - ``solver`` -- string (default: ``None``); specify a Mixed Integer Linear Programming (MILP) solver to be used. If set to ``None``, the default one @@ -275,11 +281,11 @@ def dominating_set(g, k=1, independent=False, total=False, value_only=False, EXAMPLES: - A basic illustration on a ``PappusGraph``:: + Number of distance-`k` dominating sets of a Path graph of order 10:: - sage: g = graphs.PappusGraph() - sage: g.dominating_set(value_only=True) - 5 + sage: g = graphs.PathGraph(10) + sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] # needs sage.numerical.mip + [1, 13, 1, 13, 25, 2, 4, 6, 8, 10, 10] If we build a graph from two disjoint stars, then link their centers we will find a difference between the cardinality of an independent set and a stable @@ -287,50 +293,117 @@ def dominating_set(g, k=1, independent=False, total=False, value_only=False, sage: g = 2 * graphs.StarGraph(5) sage: g.add_edge(0, 6) - sage: len(g.dominating_set()) - 2 - sage: len(g.dominating_set(independent=True)) - 6 + sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] # needs sage.numerical.mip + [1, 1, 2, 12, 12, 12, 12, 12, 12, 12, 12] The total dominating set of the Petersen graph has cardinality 4:: sage: G = graphs.PetersenGraph() - sage: G.dominating_set(total=True, value_only=True) + sage: G.dominating_set(total=True, value_only=True) # needs sage.numerical.mip 4 + sage: sorted(G.dominating_sets(k=1)) # needs sage.numerical.mip + [[0, 2, 6], + [0, 3, 9], + [0, 7, 8], + [1, 3, 7], + [1, 4, 5], + [1, 8, 9], + [2, 4, 8], + [2, 5, 9], + [3, 5, 6], + [4, 6, 7]] + + Independent distance-`k` dominating sets of a Path graph:: + + sage: # needs sage.numerical.mip + sage: G = graphs.PathGraph(6) + sage: sorted(G.dominating_sets(k=1, independent=True)) + [[1, 4]] + sage: sorted(G.dominating_sets(k=2, independent=True)) + [[0, 3], [0, 4], [0, 5], [1, 3], [1, 4], [1, 5], [2, 4], [2, 5]] + sage: sorted(G.dominating_sets(k=3, independent=True)) + [[2], [3]] The dominating set is calculated for both the directed and undirected graphs (modification introduced in :trac:`17905`):: + sage: # needs sage.numerical.mip sage: g = digraphs.Path(3) sage: g.dominating_set(value_only=True) 2 + sage: list(g.dominating_sets()) + [[0, 1], [0, 2]] + sage: list(g.dominating_sets(k=2)) + [[0]] sage: g = graphs.PathGraph(3) sage: g.dominating_set(value_only=True) 1 + sage: next(g.dominating_sets()) + [1] - Cardinality of distance-`k` dominating sets:: + Minimum connected dominating sets of the Peterson graph:: sage: G = graphs.PetersenGraph() - sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] - [10, 3, 1] - sage: G = graphs.PathGraph(5) - sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] - [5, 2, 1] + sage: G.dominating_set(total=True, value_only=True) + 4 + sage: sorted(G.dominating_sets(k=1, connected=True)) + [[0, 1, 2, 6], + [0, 1, 4, 5], + [0, 3, 4, 9], + [0, 5, 7, 8], + [1, 2, 3, 7], + [1, 6, 8, 9], + [2, 3, 4, 8], + [2, 5, 7, 9], + [3, 5, 6, 8], + [4, 6, 7, 9]] + + Subgraph induced by the dominating set is connected:: + + sage: G = graphs.PetersenGraph() + sage: all(G.subgraph(vertices=dom).is_connected() for dom in G.dominating_set(k=1, connected=True)) + True + + Minimum distance-k connected dominating sets of the Tietze graph:: + + sage: G = graphs.TietzeGraph() + sage: sorted(G.dominating_sets(k=2, connected=True)) + [[0, 9], [1, 0], [2, 3], [4, 3], [5, 6], [7, 6], [8, 0], [10, 3], [11, 6]] + sage: sorted(G.dominating_sets(k=3, connected=True)) + [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11]] + + TESTS:: + + sage: g = Graph([(0, 1)]) + sage: next(g.dominating_sets(k=-1)) # needs sage.numerical.mip + Traceback (most recent call last): + ... + ValueError: the domination distance must be a non-negative integer + + The method is robust to vertices with incomparable labels:: + + sage: G = Graph([(1, 'A'), ('A', 2), (2, 3), (3, 1)]) + sage: L = list(G.dominating_sets()) + sage: len(L) + 6 """ g._scream_if_not_simple(allow_multiple_edges=True, allow_loops=not total) if not k: - return g.order() if value_only else list(g) - elif k < 0: + yield list(g) + return + if k < 0: raise ValueError("the domination distance must be a non-negative integer") from sage.numerical.mip import MixedIntegerLinearProgram - p = MixedIntegerLinearProgram(maximization=False, solver=solver) + from sage.numerical.mip import MIPSolverException + p = MixedIntegerLinearProgram(maximization=False, solver=solver, + constraint_generation=True) b = p.new_variable(binary=True) if k == 1: # For any vertex v, one of its neighbors or v itself is in the minimum - # dominating set. If g is directed, we use the in neighbors of v + # dominating set. If g is directed, we use the in-neighbors of v # instead. neighbors_iter = g.neighbor_in_iterator if g.is_directed() else g.neighbor_iterator else: @@ -356,14 +429,159 @@ def neighbors_iter(x): for u, v in g.edge_iterator(labels=None): p.add_constraint(b[u] + b[v], max=1) + if connected: + E = set(frozenset(e) for e in g.edge_iterator(labels=False)) + # edges used in the spanning tree + edge = p.new_variable(binary=True, name='e') + # relaxed edges to test for acyclicity + r_edge = p.new_variable(nonnegative=True, name='re') + + # 1. We want a tree + p.add_constraint(p.sum(edge[fe] for fe in E) + == p.sum(b[u] for u in g) - 1) + + # 2. An edge can be in the tree if its end vertices are selected + for fe in E: + u, v = fe + p.add_constraint(edge[fe] <= b[u]) + p.add_constraint(edge[fe] <= b[v]) + + # 3. Subtour elimination constraints + for fe in E: + u, v = fe + p.add_constraint(edge[fe] <= r_edge[u, v] + r_edge[v, u]) + + eps = 1 / (5 * Integer(g.order())) + for v in g: + p.add_constraint(p.sum(r_edge[u, v] for u in g.neighbor_iterator(v)), max=1 - eps) + # Minimizes the number of vertices used p.set_objective(p.sum(b[v] for v in g)) - p.solve(log=verbose) - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - dom = [v for v in g if b[v]] - return Integer(len(dom)) if value_only else dom + best = g.order() + while True: + try: + p.solve(log=verbose) + except MIPSolverException: + # No more solutions + break + b_val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) + dom = [v for v in g if b_val[v]] + if len(dom) > best: + # All minimum solution have been reported + break + yield dom + best = len(dom) + # Prevent finding twice a solution + p.add_constraint(p.sum(b[u] for u in dom) <= best - 1) + +def dominating_set(g, k=1, independent=False, total=False, connected=False, value_only=False, + solver=None, verbose=0, *, integrality_tolerance=1e-3): + r""" + Return a minimum distance-`k` dominating set of the graph. + + A minimum dominating set `S` of a graph `G` is a set of its vertices of + minimal cardinality such that any vertex of `G` is in `S` or has one of its + neighbors in `S`. See the :wikipedia:`Dominating_set`. + + A minimum distance-`k` dominating set is a set `S` of vertices of `G` of + minimal cardinality such that any vertex of `G` is in `S` or at distance at + most `k` from a vertex in `S`. A distance-`0` dominating set is the set of + vertices itself, and when `k` is the radius of the graph, any vertex + dominates all the other vertices. + + As an optimization problem, it can be expressed as follows, where `N^k(u)` + denotes the set of vertices at distance at most `k` from `u` (the set of + neighbors when `k=1`): + + .. MATH:: + + \mbox{Minimize : }&\sum_{v\in G} b_v\\ + \mbox{Such that : }&\forall v \in G, b_v+\sum_{u \in N^k(v)} b_u\geq 1\\ + &\forall x\in G, b_x\mbox{ is a binary variable} + + INPUT: + + - ``k`` -- a non-negative integer (default: ``1``); the domination distance + + - ``independent`` -- boolean (default: ``False``); when ``True``, computes a + minimum independent dominating set, that is a minimum dominating set that + is also an independent set (see also + :meth:`~sage.graphs.graph.independent_set`) + + - ``total`` -- boolean (default: ``False``); when ``True``, computes a total + dominating set (see the See the :wikipedia:`Dominating_set`) + + - ``connected`` -- boolean (default: ``False``); when ``True``, computes a + connected dominating set (see :wikipedia:`Connected_dominating_set`) + + - ``value_only`` -- boolean (default: ``False``); whether to only return the + cardinality of the computed dominating set, or to return its list of + vertices (default) + + - ``solver`` -- string (default: ``None``); specify a Mixed Integer Linear + Programming (MILP) solver to be used. If set to ``None``, the default one + is used. For more information on MILP solvers and which default solver is + used, see the method :meth:`solve + <sage.numerical.mip.MixedIntegerLinearProgram.solve>` of the class + :class:`MixedIntegerLinearProgram + <sage.numerical.mip.MixedIntegerLinearProgram>`. + + - ``verbose`` -- integer (default: ``0``); sets the level of verbosity. Set + to 0 by default, which means quiet. + + - ``integrality_tolerance`` -- float; parameter for use with MILP solvers + over an inexact base ring; see + :meth:`MixedIntegerLinearProgram.get_values`. + + EXAMPLES: + + A basic illustration on a ``PappusGraph``:: + + sage: g = graphs.PappusGraph() + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip + 5 + + If we build a graph from two disjoint stars, then link their centers we will + find a difference between the cardinality of an independent set and a stable + independent set:: + + sage: g = 2 * graphs.StarGraph(5) + sage: g.add_edge(0, 6) + sage: len(g.dominating_set()) # needs sage.numerical.mip + 2 + sage: len(g.dominating_set(independent=True)) # needs sage.numerical.mip + 6 + + The total dominating set of the Petersen graph has cardinality 4:: + + sage: G = graphs.PetersenGraph() + sage: G.dominating_set(total=True, value_only=True) # needs sage.numerical.mip + 4 + + The dominating set is calculated for both the directed and undirected graphs + (modification introduced in :trac:`17905`):: + + sage: g = digraphs.Path(3) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip + 2 + sage: g = graphs.PathGraph(3) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip + 1 + Cardinality of distance-`k` dominating sets:: + + sage: G = graphs.PetersenGraph() + sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] # needs sage.numerical.mip + [10, 3, 1] + sage: G = graphs.PathGraph(5) + sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] # needs sage.numerical.mip + [5, 2, 1] + """ + dom = next(dominating_sets(g, k=k, independent=independent, total=total, + connected=connected, solver=solver, verbose=verbose, + integrality_tolerance=integrality_tolerance)) + return Integer(len(dom)) if value_only else dom # ============================================================================== # Enumeration of minimal dominating set as described in [BDHPR2019]_ @@ -572,8 +790,8 @@ def _aux_with_rep(H, to_dom, u_next): # Here we use aux_with_rep twice to enumerate the minimal # dominating sets while avoiding repeated outputs - for (X, i) in _aux_with_rep(G, to_dom, u_next): - for (Y, j) in _aux_with_rep(G, to_dom, u_next): + for X, i in _aux_with_rep(G, to_dom, u_next): + for Y, j in _aux_with_rep(G, to_dom, u_next): if j >= i: # This is the first time we meet X: we output it yield X @@ -583,7 +801,7 @@ def _aux_with_rep(H, to_dom, u_next): break -def minimal_dominating_sets(G, to_dominate=None, work_on_copy=True): +def minimal_dominating_sets(G, to_dominate=None, work_on_copy=True, k=1): r""" Return an iterator over the minimal dominating sets of a graph. @@ -598,6 +816,8 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=True): a copy of the input graph; if set to ``False``, the input graph will be modified (relabeled). + - ``k`` -- a non-negative integer (default: ``1``); the domination distance + OUTPUT: An iterator over the inclusion-minimal sets of vertices of ``G``. @@ -631,35 +851,73 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=True): sage: ll = list(graphs.PetersenGraph().minimal_dominating_sets()) sage: pp = [{0, 2, 6}, - ....: {0, 9, 3}, - ....: {0, 8, 7}, - ....: {1, 3, 7}, - ....: {1, 4, 5}, - ....: {8, 1, 9}, - ....: {8, 2, 4}, - ....: {9, 2, 5}, - ....: {3, 5, 6}, - ....: {4, 6, 7}, - ....: {0, 8, 2, 9}, - ....: {0, 3, 6, 7}, - ....: {1, 3, 5, 9}, - ....: {8, 1, 4, 7}, - ....: {2, 4, 5, 6}, - ....: {0, 1, 2, 3, 4}, - ....: {0, 1, 2, 5, 7}, - ....: {0, 1, 4, 6, 9}, - ....: {0, 1, 5, 6, 8}, - ....: {0, 8, 3, 4, 5}, - ....: {0, 9, 4, 5, 7}, - ....: {8, 1, 2, 3, 6}, - ....: {1, 2, 9, 6, 7}, - ....: {9, 2, 3, 4, 7}, - ....: {8, 2, 3, 5, 7}, - ....: {8, 9, 3, 4, 6}, - ....: {8, 9, 5, 6, 7}] + ....: {0, 9, 3}, + ....: {0, 8, 7}, + ....: {1, 3, 7}, + ....: {1, 4, 5}, + ....: {8, 1, 9}, + ....: {8, 2, 4}, + ....: {9, 2, 5}, + ....: {3, 5, 6}, + ....: {4, 6, 7}, + ....: {0, 8, 2, 9}, + ....: {0, 3, 6, 7}, + ....: {1, 3, 5, 9}, + ....: {8, 1, 4, 7}, + ....: {2, 4, 5, 6}, + ....: {0, 1, 2, 3, 4}, + ....: {0, 1, 2, 5, 7}, + ....: {0, 1, 4, 6, 9}, + ....: {0, 1, 5, 6, 8}, + ....: {0, 8, 3, 4, 5}, + ....: {0, 9, 4, 5, 7}, + ....: {8, 1, 2, 3, 6}, + ....: {1, 2, 9, 6, 7}, + ....: {9, 2, 3, 4, 7}, + ....: {8, 2, 3, 5, 7}, + ....: {8, 9, 3, 4, 6}, + ....: {8, 9, 5, 6, 7}] sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp) True + Listing minimal distance-`k` dominating sets:: + + sage: G = graphs.Grid2dGraph(2, 3) + sage: list(G.minimal_dominating_sets(k=0)) + [{(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)}] + sage: list(G.minimal_dominating_sets(k=1)) + [{(0, 0), (0, 2), (1, 1)}, + {(0, 1), (1, 1)}, + {(0, 0), (0, 1), (0, 2)}, + {(0, 2), (1, 0)}, + {(0, 0), (1, 2)}, + {(0, 1), (1, 0), (1, 2)}, + {(1, 0), (1, 1), (1, 2)}] + sage: list(G.minimal_dominating_sets(k=2)) + [{(0, 0), (1, 2)}, + {(0, 2), (1, 2)}, + {(1, 0), (1, 2)}, + {(0, 1)}, + {(0, 0), (0, 2)}, + {(0, 2), (1, 0)}, + {(0, 0), (1, 0)}, + {(1, 1)}] + sage: list(G.minimal_dominating_sets(k=3)) + [{(0, 0)}, {(0, 1)}, {(0, 2)}, {(1, 0)}, {(1, 1)}, {(1, 2)}] + + When parameter ``work_on_copy`` is ``False``, the input graph is modified + (relabeled):: + + sage: G = Graph([('A', 'B')]) + sage: _ = list(G.minimal_dominating_sets(work_on_copy=True)) + sage: set(G) == {'A', 'B'} + True + sage: _ = list(G.minimal_dominating_sets(work_on_copy=False)) + sage: set(G) == {'A', 'B'} + False + sage: set(G) == {0, 1} + True + TESTS: The empty graph is handled correctly:: @@ -701,8 +959,30 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=True): ....: return True sage: check_uniqueness(graphs.RandomGNP(9, 0.5)) True - """ + Asking for a negative distance:: + + sage: next(Graph(1).minimal_dominating_sets(k=-1)) + Traceback (most recent call last): + ... + ValueError: the domination distance must be a non-negative integer + + Trying to dominate vertices that are not part of the graph:: + + sage: next(Graph(1).minimal_dominating_sets(to_dominate=['foo'])) + Traceback (most recent call last): + ... + ValueError: vertex (foo) is not a vertex of the graph + + The method is robust to vertices with incomparable labels:: + + sage: G = Graph([(1, 'A'), ('A', 2), (2, 3), (3, 1)]) + sage: L = list(G.minimal_dominating_sets()) + sage: len(L) + 6 + sage: {3, 'A'} in L + True + """ def tree_search(H, plng, dom, i): r""" Enumerate minimal dominating sets recursively. @@ -755,7 +1035,8 @@ def tree_search(H, plng, dom, i): # We complete dom with can_ext -> canD canD = set().union(can_ext, dom) - if (not H.is_redundant(canD, V_next)) and set(dom) == set(_parent(H, canD, plng[i][1])): + if (not H.is_redundant(canD, V_next) + and set(dom) == set(_parent(H, canD, plng[i][1]))): # By construction, can_ext is a dominating set of # `V_next - N[dom]`, so canD dominates V_next. # If canD is a legitimate child of dom and is not redundant, we @@ -765,24 +1046,41 @@ def tree_search(H, plng, dom, i): ## # end of tree-search routine + if k < 0: + raise ValueError("the domination distance must be a non-negative integer") + if not k: + yield set(G) if to_dominate is None else set(to_dominate) + return + int_to_vertex = list(G) vertex_to_int = {u: i for i, u in enumerate(int_to_vertex)} - if work_on_copy: - G.relabel(perm=vertex_to_int) - else: - G = G.relabel(perm=vertex_to_int, inplace=False) - if to_dominate is None: - vertices_to_dominate = set(G) + vertices_to_dominate = set(range(G.order())) else: - vertices_to_dominate = set(to_dominate) + for u in to_dominate: + if u not in G: + raise ValueError(f"vertex ({u}) is not a vertex of the graph") + vertices_to_dominate = {vertex_to_int[u] for u in to_dominate} if not vertices_to_dominate: # base case: vertices_to_dominate is empty # the empty set/list is the only minimal DS of the empty set yield set() return + if k > 1: + # We build a graph H with an edge between u and v if these vertices are + # at distance at most k in G + H = G.__class__(G.order()) + for u, ui in vertex_to_int.items(): + H.add_edges((ui, vertex_to_int[v]) + for v in G.breadth_first_search(u, distance=k) if u != v) + G = H + elif work_on_copy: + G = G.relabel(perm=vertex_to_int, inplace=False) + else: + # The input graph is modified + G.relabel(perm=vertex_to_int, inplace=True) peeling = _peel(G, vertices_to_dominate) @@ -915,6 +1213,12 @@ def greedy_dominating_set(G, k=1, vertices=None, ordering=None, return_sets=Fals sage: G = graphs.PathGraph(5) sage: dom = greedy_dominating_set(G, vertices=[0, 1, 3, 4]) + The method is robust to vertices with incomparable labels:: + + sage: G = Graph([(1, 'A')]) + sage: len(greedy_dominating_set(G)) + 1 + Check parameters:: sage: greedy_dominating_set(G, ordering="foo") diff --git a/src/sage/graphs/dot2tex_utils.py b/src/sage/graphs/dot2tex_utils.py index 75e27d0f158..ce2cd873c8b 100644 --- a/src/sage/graphs/dot2tex_utils.py +++ b/src/sage/graphs/dot2tex_utils.py @@ -74,13 +74,12 @@ def quoted_latex(x): EXAMPLES:: - sage: sage.graphs.dot2tex_utils.quoted_latex(matrix([[1,1],[0,1],[0,0]])) + sage: sage.graphs.dot2tex_utils.quoted_latex(matrix([[1,1],[0,1],[0,0]])) # needs sage.modules '\\left(\\begin{array}{rr}1 & 1 \\\\0 & 1 \\\\0 & 0\\end{array}\\right)' """ return re.sub("\"|\r|(%[^\n]*)?\n", "", latex(x)) - def quoted_str(x): r""" Strip the string representation of ``x`` to make it suitable for @@ -90,9 +89,9 @@ def quoted_str(x): EXAMPLES:: - sage: sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]])) + sage: sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]])) # needs sage.modules '[1 1]\\n\\\n[0 1]\\n\\\n[0 0]' - sage: print(sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]]))) + sage: print(sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]]))) # needs sage.modules [1 1]\n\ [0 1]\n\ [0 0] diff --git a/src/sage/graphs/edge_connectivity.pyx b/src/sage/graphs/edge_connectivity.pyx index 5263e712db5..014e46f7500 100644 --- a/src/sage/graphs/edge_connectivity.pyx +++ b/src/sage/graphs/edge_connectivity.pyx @@ -56,27 +56,31 @@ cdef class GabowEdgeConnectivity: A random `d`-regular digraph is `d`-edge-connected:: sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity - sage: D = DiGraph(graphs.RandomRegular(6, 50)) - sage: while not D.is_strongly_connected(): + sage: D = DiGraph(graphs.RandomRegular(6, 50)) # needs networkx + sage: while not D.is_strongly_connected(): # needs networkx ....: D = DiGraph(graphs.RandomRegular(6, 50)) - sage: GabowEdgeConnectivity(D).edge_connectivity() + sage: GabowEdgeConnectivity(D).edge_connectivity() # needs networkx 6 A complete digraph with `n` vertices is `n-1`-edge-connected:: sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity sage: D = DiGraph(digraphs.Complete(10)) - sage: GabowEdgeConnectivity(D, use_rec = True).edge_connectivity() + sage: GabowEdgeConnectivity(D, use_rec=True).edge_connectivity() 9 Check that we get the same result when with and without the DFS-based speed-up initialization proposed in [GKLP2021]_:: + sage: # needs networkx sage: G = graphs.RandomBarabasiAlbert(100, 2) sage: D = DiGraph(G) - sage: ec1 = GabowEdgeConnectivity(D, dfs_preprocessing=False).edge_connectivity() - sage: ec2 = GabowEdgeConnectivity(D, dfs_preprocessing=True).edge_connectivity() - sage: ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True, use_rec=True).edge_connectivity() + sage: ec1 = GabowEdgeConnectivity(D, + ....: dfs_preprocessing=False).edge_connectivity() + sage: ec2 = GabowEdgeConnectivity(D, + ....: dfs_preprocessing=True).edge_connectivity() + sage: ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True, + ....: use_rec=True).edge_connectivity() sage: ec1 == ec2 and ec2 == ec3 True @@ -1193,7 +1197,6 @@ cdef class GabowEdgeConnectivity: raise ValueError("the value of the edge connectivity has not been " "properly computed. This may result from an interruption") - # # Packing arborescences # diff --git a/src/sage/graphs/generators/__init__.py b/src/sage/graphs/generators/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/combinat/__init__.py b/src/sage/graphs/generators/all.py similarity index 100% rename from src/sage/combinat/__init__.py rename to src/sage/graphs/generators/all.py diff --git a/src/sage/graphs/generators/basic.py b/src/sage/graphs/generators/basic.py index 84d520dd969..314d66aef43 100644 --- a/src/sage/graphs/generators/basic.py +++ b/src/sage/graphs/generators/basic.py @@ -170,7 +170,7 @@ def CircularLadderGraph(n): Construct and show a circular ladder graph with 26 nodes:: sage: g = graphs.CircularLadderGraph(13) - sage: g.show() # long time + sage: g.show() # long time Create several circular ladder graphs in a Sage graphics array:: @@ -179,13 +179,13 @@ def CircularLadderGraph(n): sage: for i in range(9): ....: k = graphs.CircularLadderGraph(i+3) ....: g.append(k) - sage: for i in range(3): + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) - sage: G.show() # long time + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot """ G = Graph(2 * n, name="Circular Ladder graph") G._circle_embedding(list(range(n)), radius=1, angle=pi/2) @@ -248,16 +248,18 @@ def CycleGraph(n): Compare plotting using the predefined layout and networkx:: + sage: # needs networkx sage.plot sage: import networkx sage: n = networkx.cycle_graph(23) sage: spring23 = Graph(n) sage: posdict23 = graphs.CycleGraph(23) - sage: spring23.show() # long time - sage: posdict23.show() # long time + sage: spring23.show() # long time + sage: posdict23.show() # long time We next view many cycle graphs as a Sage graphics array. First we use the ``CycleGraph`` constructor, which fills in the position dictionary:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -269,10 +271,11 @@ def CycleGraph(n): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time Compare to plotting with the spring-layout algorithm:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -285,7 +288,7 @@ def CycleGraph(n): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time TESTS: @@ -334,6 +337,7 @@ def CompleteGraph(n): We view many Complete graphs with a Sage Graphics Array, first with this constructor (i.e., the position dictionary filled):: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -345,10 +349,11 @@ def CompleteGraph(n): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time We compare to plotting with the spring-layout algorithm:: + sage: # needs networkx sage.plot sage: import networkx sage: g = [] sage: j = [] @@ -362,10 +367,11 @@ def CompleteGraph(n): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time Compare the constructors (results will vary):: + sage: # needs networkx sage: import networkx sage: t = cputime() sage: n = networkx.complete_graph(389); spring389 = Graph(n) @@ -378,12 +384,13 @@ def CompleteGraph(n): We compare plotting:: + sage: # needs networkx sage: import networkx sage: n = networkx.complete_graph(23) sage: spring23 = Graph(n) sage: posdict23 = graphs.CompleteGraph(23) - sage: spring23.show() # long time - sage: posdict23.show() # long time + sage: spring23.show() # long time # needs sage.plot + sage: posdict23.show() # long time # needs sage.plot """ G = Graph(n, name="Complete graph") if n == 1: @@ -393,6 +400,46 @@ def CompleteGraph(n): G.add_edges(((i, j) for i in range(n) for j in range(i + 1, n))) return G +def CorrelationGraph(seqs, alpha, include_anticorrelation): + """ + Constructs and returns a correlation graph with a node corresponding to each sequence in `seqs`. + + Edges are added between nodes where the corresponding sequences have a correlation coeffecient greater than alpha. + + If include_anticorrelation is true, then edges are also added between nodes with correlation coeffecient less than -alpha. + + EXAMPLES: + + sage: # needs numpy + sage: from sage.graphs.generators.basic import CorrelationGraph + sage: data = [[1,2,3], [4,5,6], [7,8,9999]] + sage: CG1 = CorrelationGraph(data, 0.9, False) + sage: CG2 = CorrelationGraph(data, 0.9, True) + sage: CG3 = CorrelationGraph(data, 0.1, True) + sage: CG1.edges(sort=False) + [(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)] + sage: CG2.edges(sort=False) + [(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)] + sage: CG3.edges(sort=False) + [(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2, None)] + + """ + from numpy import corrcoef + from sage.matrix.constructor import Matrix + + # compute pairwise correlation coeffecients + corrs = corrcoef(seqs) + + # compare against alpha to get adjacency matrix + if include_anticorrelation: + boolean_adjacency_matrix = abs(corrs)>=alpha + else: + boolean_adjacency_matrix = corrs>=alpha + + adjacency_matrix = Matrix(boolean_adjacency_matrix.astype(int)) + + # call graph constructor + return Graph(adjacency_matrix, format="adjacency_matrix", name="Correlation Graph") def CompleteBipartiteGraph(p, q, set_position=True): r""" @@ -438,19 +485,21 @@ def CompleteBipartiteGraph(p, q, set_position=True): Two ways of constructing the complete bipartite graph, using different layout algorithms:: + sage: # needs networkx sage: import networkx - sage: n = networkx.complete_bipartite_graph(389, 157); spring_big = Graph(n) # long time - sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157) # long time + sage: n = networkx.complete_bipartite_graph(389, 157) # long time + sage: spring_big = Graph(n) # long time + sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157) # long time Compare the plotting:: - sage: n = networkx.complete_bipartite_graph(11, 17) - sage: spring_med = Graph(n) + sage: n = networkx.complete_bipartite_graph(11, 17) # needs networkx + sage: spring_med = Graph(n) # needs networkx sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17) Notice here how the spring-layout tends to center the nodes of `n1`:: - sage: spring_med.show() # long time + sage: spring_med.show() # long time # needs networkx sage: posdict_med.show() # long time View many complete bipartite graphs with a Sage Graphics Array, with this @@ -461,16 +510,17 @@ def CompleteBipartiteGraph(p, q, set_position=True): sage: for i in range(9): ....: k = graphs.CompleteBipartiteGraph(i+1,4) ....: g.append(k) - sage: for i in range(3): + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) - sage: G.show() # long time + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot We compare to plotting with the spring-layout algorithm:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -483,7 +533,7 @@ def CompleteBipartiteGraph(p, q, set_position=True): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time :trac:`12155`:: @@ -785,13 +835,13 @@ def Toroidal6RegularGrid2dGraph(p, q): sage: g = graphs.Toroidal6RegularGrid2dGraph(5,5) sage: g.is_regular(k=6) True - sage: g.is_vertex_transitive() + sage: g.is_vertex_transitive() # needs sage.groups True - sage: g.line_graph().is_vertex_transitive() + sage: g.line_graph().is_vertex_transitive() # needs sage.groups True - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 300 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True TESTS: @@ -933,9 +983,9 @@ def GridGraph(dim_list): sage: dim = [randint(1,4) for i in range(4)] sage: g = graphs.GridGraph(dim) - sage: import networkx - sage: h = Graph( networkx.grid_graph(list(dim)) ) - sage: g.is_isomorphic(h) + sage: import networkx # needs networkx + sage: h = Graph(networkx.grid_graph(list(dim))) # needs networkx + sage: g.is_isomorphic(h) # needs networkx True Trivial cases:: @@ -1070,6 +1120,7 @@ def LadderGraph(n): Create several ladder graphs in a Sage graphics array:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -1081,7 +1132,7 @@ def LadderGraph(n): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time """ pos_dict = {} for i in range(n): @@ -1223,14 +1274,15 @@ def StarGraph(n): EXAMPLES:: - sage: import networkx + sage: import networkx # needs networkx Compare the plots:: + sage: # needs networkx sage.plot sage: n = networkx.star_graph(23) sage: spring23 = Graph(n) sage: posdict23 = graphs.StarGraph(23) - sage: spring23.show() # long time + sage: spring23.show() # long time sage: posdict23.show() # long time View many star graphs as a Sage Graphics Array @@ -1239,6 +1291,7 @@ def StarGraph(n): :: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -1250,12 +1303,13 @@ def StarGraph(n): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time Compared to plotting with the spring-layout algorithm :: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -1268,7 +1322,7 @@ def StarGraph(n): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time """ G = Graph({0: list(range(1, n + 1))}, name="Star graph", format="dict_of_lists") G.set_pos({0: (0, 0)}) diff --git a/src/sage/graphs/generators/chessboard.py b/src/sage/graphs/generators/chessboard.py index 2835fbe987f..dfe5b15b273 100644 --- a/src/sage/graphs/generators/chessboard.py +++ b/src/sage/graphs/generators/chessboard.py @@ -4,11 +4,11 @@ The methods defined here appear in :mod:`sage.graphs.graph_generators`. -- :meth:`BishopGraph <GraphGenerators.BishopGraph>` -- :meth:`KingGraph <GraphGenerators.KingGraph>` -- :meth:`KnightGraph <GraphGenerators.KnightGraph>` -- :meth:`QueenGraph <GraphGenerators.QueenGraph>` -- :meth:`RookGraph <GraphGenerators.RookGraph>` +- :meth:`BishopGraph <sage.graphs.graph_generators.GraphGenerators.BishopGraph>` +- :meth:`KingGraph <sage.graphs.graph_generators.GraphGenerators.KingGraph>` +- :meth:`KnightGraph <sage.graphs.graph_generators.GraphGenerators.KnightGraph>` +- :meth:`QueenGraph <sage.graphs.graph_generators.GraphGenerators.QueenGraph>` +- :meth:`RookGraph <sage.graphs.graph_generators.GraphGenerators.RookGraph>` AUTHORS: @@ -414,7 +414,7 @@ def KnightGraph(dim_list, one=1, two=2, relabel=False): The `(6,6)`-Knight Graph is Hamiltonian:: sage: G = graphs.KnightGraph( [6, 6] ) - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True """ G, dimstr = ChessboardGraphGenerator(dim_list, diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 059d46d0c7f..bf1aa04e933 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.modules r""" Families of graphs derived from classical geometries over finite fields @@ -39,7 +39,7 @@ def SymplecticPolarGraph(d, q, algorithm=None): - ``d,q`` -- integers; note that only even values of `d` are accepted by the function. - - ``algorithm`` -- string (default: ``None``); if set to 'gap' then the + - ``algorithm`` -- string (default: ``None``); if set to ``'gap'``, then the computation is carried via GAP library interface, computing totally singular subspaces, which is faster for `q>3`. Otherwise it is done directly. @@ -48,31 +48,34 @@ def SymplecticPolarGraph(d, q, algorithm=None): Computation of the spectrum of `Sp(6,2)`:: - sage: g = graphs.SymplecticPolarGraph(6,2) + sage: g = graphs.SymplecticPolarGraph(6, 2) sage: g.is_strongly_regular(parameters=True) (63, 30, 13, 15) - sage: set(g.spectrum()) == {-5, 3, 30} + sage: set(g.spectrum()) == {-5, 3, 30} # needs sage.rings.number_field True The parameters of `Sp(4,q)` are the same as of `O(5,q)`, but they are not isomorphic if `q` is odd:: - sage: G = graphs.SymplecticPolarGraph(4,3) + sage: G = graphs.SymplecticPolarGraph(4, 3) sage: G.is_strongly_regular(parameters=True) (40, 12, 2, 4) - sage: O=graphs.OrthogonalPolarGraph(5,3) + + sage: # needs sage.libs.gap + sage: O = graphs.OrthogonalPolarGraph(5, 3) sage: O.is_strongly_regular(parameters=True) (40, 12, 2, 4) sage: O.is_isomorphic(G) False - sage: graphs.SymplecticPolarGraph(6,4,algorithm="gap").is_strongly_regular(parameters=True) # not tested (long time) + sage: S = graphs.SymplecticPolarGraph(6, 4, algorithm="gap") # not tested (long time) + sage: S.is_strongly_regular(parameters=True) # not tested (long time) (1365, 340, 83, 85) TESTS:: - sage: graphs.SymplecticPolarGraph(4,4,algorithm="gap").is_strongly_regular(parameters=True) + sage: graphs.SymplecticPolarGraph(4,4,algorithm="gap").is_strongly_regular(parameters=True) # needs sage.libs.gap (85, 20, 3, 5) - sage: graphs.SymplecticPolarGraph(4,4).is_strongly_regular(parameters=True) + sage: graphs.SymplecticPolarGraph(4,4).is_strongly_regular(parameters=True) # needs sage.libs.pari (85, 20, 3, 5) sage: graphs.SymplecticPolarGraph(4,4,algorithm="blah") Traceback (most recent call last): @@ -146,13 +149,14 @@ def AffineOrthogonalPolarGraph(d, q, sign="+"): The :meth:`Brouwer-Haemers graph <BrouwerHaemersGraph>` is isomorphic to `VO^-(4,3)`:: - sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-") - sage: g.is_isomorphic(graphs.BrouwerHaemersGraph()) + sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-") # needs sage.libs.gap + sage: g.is_isomorphic(graphs.BrouwerHaemersGraph()) # needs sage.libs.gap True Some examples from `Brouwer's table or strongly regular graphs <https://www.win.tue.nl/~aeb/graphs/srg/srgtab.html>`_:: + sage: # needs sage.libs.gap sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g Affine Polar Graph VO^-(6,2): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) @@ -164,6 +168,7 @@ def AffineOrthogonalPolarGraph(d, q, sign="+"): When ``sign is None``:: + sage: # needs sage.libs.gap sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g Affine Polar Graph VO^-(5,2): Graph on 32 vertices sage: g.is_strongly_regular(parameters=True) @@ -223,60 +228,61 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): Petersen graph:: sage: from sage.graphs.generators.classical_geometries import _orthogonal_polar_graph - sage: g=_orthogonal_polar_graph(3,5,point_type=[2,3]) - sage: g.is_strongly_regular(parameters=True) + sage: g = _orthogonal_polar_graph(3,5,point_type=[2,3]) # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (10, 3, 0, 1) A locally Petersen graph (a.k.a. Doro graph, a.k.a. Hall graph):: - sage: g=_orthogonal_polar_graph(4,5,'-',point_type=[2,3]) - sage: g.is_distance_regular(parameters=True) + sage: g = _orthogonal_polar_graph(4,5,'-',point_type=[2,3]) # needs sage.libs.gap + sage: g.is_distance_regular(parameters=True) # needs sage.libs.gap ([10, 6, 4, None], [None, 1, 2, 5]) Various big and slow to build graphs: `NO^+(7,3)`:: - sage: g=_orthogonal_polar_graph(7,3,point_type=[1]) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g = _orthogonal_polar_graph(7,3,point_type=[1]) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (378, 117, 36, 36) `NO^-(7,3)`:: - sage: g=_orthogonal_polar_graph(7,3,point_type=[-1]) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g = _orthogonal_polar_graph(7,3,point_type=[-1]) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (351, 126, 45, 45) `NO^+(6,3)`:: - sage: g=_orthogonal_polar_graph(6,3,point_type=[1]) - sage: g.is_strongly_regular(parameters=True) + sage: g = _orthogonal_polar_graph(6,3,point_type=[1]) # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (117, 36, 15, 9) `NO^-(6,3)`:: - sage: g=_orthogonal_polar_graph(6,3,'-',point_type=[1]) - sage: g.is_strongly_regular(parameters=True) + sage: g = _orthogonal_polar_graph(6,3,'-',point_type=[1]) # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (126, 45, 12, 18) `NO^{-,\perp}(5,5)`:: - sage: g=_orthogonal_polar_graph(5,5,point_type=[2,3]) # long time - sage: g.is_strongly_regular(parameters=True) # long time + sage: g = _orthogonal_polar_graph(5,5,point_type=[2,3]) # long time, needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (300, 65, 10, 15) `NO^{+,\perp}(5,5)`:: - sage: g=_orthogonal_polar_graph(5,5,point_type=[1,-1]) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g = _orthogonal_polar_graph(5,5,point_type=[1,-1]) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (325, 60, 15, 10) TESTS:: - sage: g=_orthogonal_polar_graph(5,3,point_type=[-1]) + sage: # needs sage.libs.gap + sage: g = _orthogonal_polar_graph(5,3,point_type=[-1]) sage: g.is_strongly_regular(parameters=True) (45, 12, 3, 3) - sage: g=_orthogonal_polar_graph(5,3,point_type=[1]) + sage: g = _orthogonal_polar_graph(5,3,point_type=[1]) sage: g.is_strongly_regular(parameters=True) (36, 15, 6, 6) @@ -341,6 +347,7 @@ def OrthogonalPolarGraph(m, q, sign="+"): EXAMPLES:: + sage: # needs sage.libs.gap sage: G = graphs.OrthogonalPolarGraph(6,3,"+"); G Orthogonal Polar Graph O^+(6, 3): Graph on 130 vertices sage: G.is_strongly_regular(parameters=True) @@ -364,11 +371,11 @@ def OrthogonalPolarGraph(m, q, sign="+"): TESTS:: - sage: G = graphs.OrthogonalPolarGraph(4,3,"") + sage: G = graphs.OrthogonalPolarGraph(4,3,"") # needs sage.libs.gap Traceback (most recent call last): ... ValueError: sign must be equal to either '-' or '+' when m is even - sage: G = graphs.OrthogonalPolarGraph(5,3,"-") + sage: G = graphs.OrthogonalPolarGraph(5,3,"-") # needs sage.libs.gap Traceback (most recent call last): ... ValueError: sign must be equal to either '' or '+' when m is odd @@ -416,71 +423,81 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): `NO^-(4,2)` is isomorphic to Petersen graph:: - sage: g=graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g + sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g # needs sage.libs.gap NO^-(4, 2): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (10, 3, 0, 1) `NO^-(6,2)` and `NO^+(6,2)`:: - sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,2,'-') + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'-') sage: g.is_strongly_regular(parameters=True) (36, 15, 6, 6) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g NO^+(6, 2): Graph on 28 vertices sage: g.is_strongly_regular(parameters=True) (28, 15, 6, 10) `NO^+(8,2)`:: - sage: g=graphs.NonisotropicOrthogonalPolarGraph(8,2,'+') - sage: g.is_strongly_regular(parameters=True) + sage: g = graphs.NonisotropicOrthogonalPolarGraph(8,2,'+') # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (120, 63, 30, 36) Wilbrink's graphs for `q=5`:: - sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1).is_strongly_regular(parameters=True) # long time + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1) + sage: g.is_strongly_regular(parameters=True) # long time (325, 60, 15, 10) - sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1).is_strongly_regular(parameters=True) # long time + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1) + sage: g.is_strongly_regular(parameters=True) # long time (300, 65, 10, 15) Wilbrink's graphs:: - sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'+') + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'+') sage: g.is_strongly_regular(parameters=True) (136, 75, 42, 40) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') sage: g.is_strongly_regular(parameters=True) (120, 51, 18, 24) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time) + sage: g = graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time) NO^+(7, 4): Graph on 2080 vertices - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (2080, 1071, 558, 544) TESTS:: - sage: g=graphs.NonisotropicOrthogonalPolarGraph(4,2); g + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2); g NO^+(4, 2): Graph on 6 vertices - sage: graphs.NonisotropicOrthogonalPolarGraph(4,3,'-').is_strongly_regular(parameters=True) + sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,3,'-') + sage: g.is_strongly_regular(parameters=True) (15, 6, 1, 3) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g + sage: g = graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g NO^-,perp(3, 5): Graph on 10 vertices sage: g.is_strongly_regular(parameters=True) (10, 3, 0, 1) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time - sage: g.is_strongly_regular(parameters=True) # long time + + sage: # long time, needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') + sage: g.is_strongly_regular(parameters=True) (117, 36, 15, 9) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g NO^-(6, 3): Graph on 126 vertices - sage: g.is_strongly_regular(parameters=True) # long time + sage: g.is_strongly_regular(parameters=True) (126, 45, 12, 18) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') # long time - sage: g.is_strongly_regular(parameters=True) # long time + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') + sage: g.is_strongly_regular(parameters=True) (300, 104, 28, 40) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') # long time - sage: g.is_strongly_regular(parameters=True) # long time + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') + sage: g.is_strongly_regular(parameters=True) (325, 144, 68, 60) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,4,'+') + + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,4,'+') Traceback (most recent call last): ... ValueError: for m even q must be 2 or 3 @@ -561,9 +578,9 @@ def _polar_graph(m, q, g, intersection_size=None): TESTS:: sage: from sage.graphs.generators.classical_geometries import _polar_graph - sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2)) + sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2)) # needs sage.libs.gap Graph on 45 vertices - sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1) + sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1) # needs sage.libs.gap Graph on 27 vertices """ from sage.libs.gap.libgap import libgap @@ -605,20 +622,21 @@ def UnitaryPolarGraph(m, q, algorithm="gap"): EXAMPLES:: + sage: # needs sage.libs.gap sage: G = graphs.UnitaryPolarGraph(4,2); G Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices sage: G.is_strongly_regular(parameters=True) (45, 12, 3, 3) sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True) (165, 36, 3, 9) - sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time) + sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time) Unitary Polar Graph U(6, 2): Graph on 693 vertices TESTS:: - sage: graphs.UnitaryPolarGraph(4,3, algorithm="gap").is_strongly_regular(parameters=True) + sage: graphs.UnitaryPolarGraph(4,3, algorithm="gap").is_strongly_regular(parameters=True) # needs sage.libs.gap (280, 36, 8, 4) - sage: graphs.UnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) + sage: graphs.UnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # needs sage.libs.gap (280, 36, 8, 4) sage: graphs.UnitaryPolarGraph(4,3, algorithm="foo") Traceback (most recent call last): @@ -672,16 +690,16 @@ def NonisotropicUnitaryPolarGraph(m, q): EXAMPLES:: - sage: g=graphs.NonisotropicUnitaryPolarGraph(5,2); g + sage: g = graphs.NonisotropicUnitaryPolarGraph(5,2); g # needs sage.libs.gap NU(5, 2): Graph on 176 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (176, 135, 102, 108) TESTS:: - sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True) + sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True) # needs sage.libs.gap (40, 27, 18, 18) - sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time + sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (540, 224, 88, 96) sage: graphs.NonisotropicUnitaryPolarGraph(6,6) Traceback (most recent call last): @@ -738,16 +756,16 @@ def UnitaryDualPolarGraph(m, q): The point graph of a generalized quadrangle (see :wikipedia:`Generalized_quadrangle`, [PT2009]_) of order (8,4):: - sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time + sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time # needs sage.libs.gap Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices - sage: G.is_strongly_regular(parameters=True) # long time + sage: G.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap (297, 40, 7, 5) Another way to get the generalized quadrangle of order (2,4):: - sage: G = graphs.UnitaryDualPolarGraph(4,2); G + sage: G = graphs.UnitaryDualPolarGraph(4,2); G # needs sage.libs.gap Unitary Dual Polar Graph DU(4, 2); GQ(2, 4): Graph on 27 vertices - sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2,'-')) + sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2,'-')) # needs sage.libs.gap True A bigger graph:: @@ -759,7 +777,7 @@ def UnitaryDualPolarGraph(m, q): TESTS:: - sage: graphs.UnitaryDualPolarGraph(6,6) + sage: graphs.UnitaryDualPolarGraph(6,6) # needs sage.libs.gap Traceback (most recent call last): ... GAPError: Error, <subfield> must be a prime or a finite field @@ -796,11 +814,11 @@ def SymplecticDualPolarGraph(m, q): TESTS:: - sage: G = graphs.SymplecticDualPolarGraph(6,2); G + sage: G = graphs.SymplecticDualPolarGraph(6,2); G # needs sage.libs.gap Symplectic Dual Polar Graph DSp(6, 2): Graph on 135 vertices - sage: G.is_distance_regular(parameters=True) + sage: G.is_distance_regular(parameters=True) # needs sage.libs.gap ([14, 12, 8, None], [None, 1, 3, 7]) - sage: graphs.SymplecticDualPolarGraph(6,6) + sage: graphs.SymplecticDualPolarGraph(6,6) # needs sage.libs.gap Traceback (most recent call last): ... GAPError: Error, <subfield> must be a prime or a finite field @@ -844,21 +862,23 @@ def TaylorTwographDescendantSRG(q, clique_partition=False): EXAMPLES:: - sage: g=graphs.TaylorTwographDescendantSRG(3); g + sage: # needs sage.rings.finite_rings + sage: g = graphs.TaylorTwographDescendantSRG(3); g Taylor two-graph descendant SRG: Graph on 27 vertices sage: g.is_strongly_regular(parameters=True) (27, 10, 1, 5) sage: from sage.combinat.designs.twographs import taylor_twograph - sage: T = taylor_twograph(3) # long time + sage: T = taylor_twograph(3) # long time sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time True - sage: g=graphs.TaylorTwographDescendantSRG(5) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g = graphs.TaylorTwographDescendantSRG(5) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (125, 52, 15, 26) TESTS:: - sage: g,l,_=graphs.TaylorTwographDescendantSRG(3,clique_partition=True) + sage: # needs sage.rings.finite_rings + sage: g,l,_ = graphs.TaylorTwographDescendantSRG(3, clique_partition=True) sage: all(g.is_clique(x) for x in l) True sage: graphs.TaylorTwographDescendantSRG(4) @@ -918,9 +938,9 @@ def TaylorTwographSRG(q): EXAMPLES:: - sage: t=graphs.TaylorTwographSRG(3); t + sage: t = graphs.TaylorTwographSRG(3); t # needs sage.rings.finite_rings Taylor two-graph SRG: Graph on 28 vertices - sage: t.is_strongly_regular(parameters=True) + sage: t.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (28, 15, 6, 10) """ G, l, v0 = TaylorTwographDescendantSRG(q, clique_partition=True) @@ -955,11 +975,11 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): EXAMPLES:: - sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g + sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g AS(5); GQ(4, 6): Graph on 125 vertices sage: g.is_strongly_regular(parameters=True) (125, 28, 3, 7) - sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5,dual=True); g + sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5, dual=True); g AS(5)*; GQ(6, 4): Graph on 175 vertices sage: g.is_strongly_regular(parameters=True) (175, 30, 5, 5) @@ -1025,33 +1045,37 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, using the built-in construction:: - sage: g=graphs.T2starGeneralizedQuadrangleGraph(4); g + sage: # needs sage.rings.finite_rings + sage: g = graphs.T2starGeneralizedQuadrangleGraph(4); g T2*(O,4); GQ(3, 5): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 18, 2, 6) - sage: g=graphs.T2starGeneralizedQuadrangleGraph(4,dual=True); g + sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, dual=True); g T2*(O,4)*; GQ(5, 3): Graph on 96 vertices sage: g.is_strongly_regular(parameters=True) (96, 20, 4, 4) supplying your own hyperoval:: - sage: F=GF(4,'b') - sage: O=[vector(F,(0,0,0,1)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] - sage: g=graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g + sage: # needs sage.rings.finite_rings + sage: F = GF(4,'b') + sage: O = [vector(F,(0,0,0,1)),vector(F,(0,0,1,0))] + [vector(F, (0,1,x^2,x)) + ....: for x in F] + sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g T2*(O,4); GQ(3, 5): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 18, 2, 6) TESTS:: - sage: F=GF(4,'b') # repeating a point... - sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: # needs sage.rings.finite_rings + sage: F = GF(4,'b') # repeating a point... + sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... @@ -1144,35 +1168,36 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h using the built-in constructions:: - sage: g=graphs.HaemersGraph(4); g + sage: g = graphs.HaemersGraph(4); g # needs sage.rings.finite_rings Haemers(4): Graph on 96 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (96, 19, 2, 4) supplying your own hyperoval_matching:: - sage: g=graphs.HaemersGraph(4,hyperoval_matching=((0,5),(1,4),(2,3))); g + sage: g = graphs.HaemersGraph(4, hyperoval_matching=((0,5),(1,4),(2,3))); g # needs sage.rings.finite_rings Haemers(4): Graph on 96 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (96, 19, 2, 4) TESTS:: - sage: F=GF(4,'b') # repeating a point... - sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: # needs sage.rings.finite_rings + sage: F = GF(4,'b') # repeating a point... + sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] sage: graphs.HaemersGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] sage: graphs.HaemersGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval - sage: g=graphs.HaemersGraph(8); g # not tested (long time) + sage: g = graphs.HaemersGraph(8); g # not tested (long time) # needs sage.rings.finite_rings Haemers(8): Graph on 640 vertices - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) # needs sage.rings.finite_rings (640, 71, 6, 8) """ @@ -1259,20 +1284,20 @@ def CossidentePenttilaGraph(q): For `q=3` one gets Sims-Gewirtz graph. :: - sage: G=graphs.CossidentePenttilaGraph(3) # optional - gap_packages (grape) - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) + sage: G = graphs.CossidentePenttilaGraph(3) # optional - gap_package_grape + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_grape (56, 10, 0, 2) For `q>3` one gets new graphs. :: - sage: G=graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape) - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) + sage: G = graphs.CossidentePenttilaGraph(5) # optional - gap_package_grape + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_grape (378, 52, 1, 8) TESTS:: - sage: G=graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) # long time + sage: G = graphs.CossidentePenttilaGraph(7) # optional - gap_package_grape, long time + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_grape, long time (1376, 150, 2, 18) sage: graphs.CossidentePenttilaGraph(2) Traceback (most recent call last): @@ -1367,32 +1392,36 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov using the built-in construction:: - sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(8); g + sage: # needs sage.rings.finite_rings + sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8); g Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices sage: g.is_strongly_regular(parameters=True) (196, 60, 14, 20) - sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (1800, 728, 268, 312) supplying your own hyperoval:: - sage: F=GF(8) - sage: O=[vector(F,(0,0,1)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] - sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F); g + sage: # needs sage.rings.finite_rings + sage: F = GF(8) + sage: O = [vector(F,(0,0,1)),vector(F,(0,1,0))] + [vector(F, (1,x^2,x)) + ....: for x in F] + sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F); g Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices sage: g.is_strongly_regular(parameters=True) (196, 60, 14, 20) TESTS:: - sage: F=GF(8) # repeating a point... - sage: O=[vector(F,(1,0,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] + sage: # needs sage.rings.finite_rings + sage: F = GF(8) # repeating a point... + sage: O = [vector(F,(1,0,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O=[vector(F,(1,1,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] + sage: O = [vector(F,(1,1,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) Traceback (most recent call last): ... @@ -1461,13 +1490,14 @@ def OrthogonalDualPolarGraph(e, d, q): EXAMPLES:: + sage: # needs sage.libs.gap sage: G = graphs.OrthogonalDualPolarGraph(1,3,2) sage: G.is_distance_regular(True) ([7, 6, 4, None], [None, 1, 3, 7]) - sage: G = graphs.OrthogonalDualPolarGraph(0,3,3) # long time - sage: G.is_distance_regular(True) # long time + sage: G = graphs.OrthogonalDualPolarGraph(0,3,3) # long time + sage: G.is_distance_regular(True) # long time ([39, 36, 27, None], [None, 1, 4, 13]) - sage: G.order() # long time + sage: G.order() # long time 1120 REFERENCES: @@ -1476,11 +1506,12 @@ def OrthogonalDualPolarGraph(e, d, q): TESTS:: + sage: # needs sage.libs.gap sage: G = graphs.OrthogonalDualPolarGraph(0,3,2) sage: G.is_distance_regular(True) ([14, 12, 8, None], [None, 1, 3, 7]) - sage: G = graphs.OrthogonalDualPolarGraph(-1,3,2) # long time - sage: G.is_distance_regular(True) # long time + sage: G = graphs.OrthogonalDualPolarGraph(-1,3,2) # long time + sage: G.is_distance_regular(True) # long time ([28, 24, 16, None], [None, 1, 3, 7]) sage: G = graphs.OrthogonalDualPolarGraph(1,3,4) sage: G.is_distance_regular(True) diff --git a/src/sage/graphs/generators/degree_sequence.py b/src/sage/graphs/generators/degree_sequence.py index 606f96fb3fd..ed89ce43abc 100644 --- a/src/sage/graphs/generators/degree_sequence.py +++ b/src/sage/graphs/generators/degree_sequence.py @@ -41,25 +41,25 @@ def DegreeSequence(deg_sequence): EXAMPLES:: - sage: G = graphs.DegreeSequence([3,3,3,3]) - sage: G.edges(sort=True, labels=False) + sage: G = graphs.DegreeSequence([3,3,3,3]) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: G.show() # long time + sage: G.show() # long time # needs networkx sage.plot :: - sage: G = graphs.DegreeSequence([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) - sage: G.show() # long time + sage: G = graphs.DegreeSequence([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) # needs networkx + sage: G.show() # long time # needs networkx sage.plot :: - sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4]) - sage: G.show() # long time + sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4]) # needs networkx + sage: G.show() # long time # needs networkx sage.plot :: - sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1]) - sage: G.show() # long time + sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1]) # needs networkx + sage: G.show() # long time # needs networkx sage.plot """ import networkx return Graph(networkx.havel_hakimi_graph([int(i) for i in deg_sequence])) @@ -93,15 +93,15 @@ def DegreeSequenceBipartite(s1, s2): If we are given as sequences ``[2,2,2,2,2]`` and ``[5,5]`` we are given as expected the complete bipartite graph `K_{2,5}`:: - sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]) - sage: g.is_isomorphic(graphs.CompleteBipartiteGraph(5,2)) + sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]) # needs sage.modules + sage: g.is_isomorphic(graphs.CompleteBipartiteGraph(5,2)) # needs sage.modules True Some sequences being incompatible if, for example, their sums are different, the functions raises a ``ValueError`` when no graph corresponding to the degree sequences exists:: - sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,1],[5,5]) + sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,1],[5,5]) # needs sage.modules Traceback (most recent call last): ... ValueError: there exists no bipartite graph corresponding to the given degree sequences @@ -110,7 +110,7 @@ def DegreeSequenceBipartite(s1, s2): :trac:`12155`:: - sage: graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]).complement() + sage: graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]).complement() # needs sage.modules Graph on 7 vertices """ from sage.combinat.integer_vector import gale_ryser_theorem @@ -147,20 +147,21 @@ def DegreeSequenceConfigurationModel(deg_sequence, seed=None): EXAMPLES:: - sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) - sage: G.adjacency_matrix() + sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) # needs networkx + sage: G.adjacency_matrix() # needs networkx sage.modules [0 1] [1 0] The output is allowed to contain both loops and multiple edges:: + sage: # needs networkx sage: deg_sequence = [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3] sage: G = graphs.DegreeSequenceConfigurationModel(deg_sequence) sage: G.order(), G.size() (20, 30) sage: G.has_loops() or G.has_multiple_edges() # random True - sage: G.show() # long time + sage: G.show() # long time # needs sage.plot REFERENCE: @@ -191,10 +192,9 @@ def DegreeSequenceTree(deg_sequence): EXAMPLES:: - sage: G = graphs.DegreeSequenceTree([3,1,3,3,1,1,1,2,1]) - sage: G + sage: G = graphs.DegreeSequenceTree([3,1,3,3,1,1,1,2,1]); G # needs networkx Graph on 9 vertices - sage: G.show() # long time + sage: G.show() # long time # needs networkx sage.plot """ import networkx return Graph(networkx.degree_sequence_tree([int(i) for i in deg_sequence])) @@ -220,10 +220,9 @@ def DegreeSequenceExpected(deg_sequence, seed=None): EXAMPLES:: - sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3]) - sage: G + sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3]); G # needs networkx Looped graph on 5 vertices - sage: G.show() # long time + sage: G.show() # long time # needs networkx sage.plot REFERENCE: diff --git a/src/sage/graphs/generators/distance_regular.pyx b/src/sage/graphs/generators/distance_regular.pyx index 9cf706540f7..b90795b86a1 100644 --- a/src/sage/graphs/generators/distance_regular.pyx +++ b/src/sage/graphs/generators/distance_regular.pyx @@ -35,15 +35,12 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.coding import codes_catalog as codes -from sage.graphs.graph import Graph -from sage.libs.gap.libgap import libgap -from sage.modules.free_module import VectorSpace -from sage.modules.free_module_element import vector -from sage.rings.finite_rings.finite_field_constructor import GF -from sage.matrix.constructor import Matrix import itertools + from cysignals.signals cimport sig_check + +from sage.graphs.graph import Graph +from sage.misc.lazy_import import LazyImport from sage.graphs.generators.smallgraphs import (FosterGraph, BiggsSmithGraph, CoxeterGraph, LivingstoneGraph, WellsGraph, GossetGraph, @@ -53,6 +50,13 @@ from sage.graphs.generators.smallgraphs import (FosterGraph, BiggsSmithGraph, from sage.graphs.generators.platonic_solids import DodecahedralGraph from sage.graphs.strongly_regular_db import strongly_regular_graph +codes = LazyImport('sage.coding', 'codes_catalog', as_name='codes') +libgap = LazyImport('sage.libs.gap.libgap', 'libgap') +Matrix = LazyImport('sage.matrix.constructor', 'Matrix') +VectorSpace = LazyImport('sage.modules.free_module', 'VectorSpace') +vector = LazyImport('sage.modules.free_module_element', 'vector') +GF = LazyImport('sage.rings.finite_rings.finite_field_constructor', 'GF') + def cocliques_HoffmannSingleton(): r""" @@ -99,8 +103,8 @@ def locally_GQ42_distance_transitive_graph(): EXAMPLES:: - sage: G = graphs.locally_GQ42_distance_transitive_graph() # optional - internet gap_packages - sage: G.is_distance_regular(True) # optional - internet gap_packages + sage: G = graphs.locally_GQ42_distance_transitive_graph() # optional - internet gap_package_atlasrep + sage: G.is_distance_regular(True) # optional - internet gap_package_atlasrep ([45, 32, 12, 1, None], [None, 1, 6, 32, 45]) REFERENCES: @@ -128,8 +132,8 @@ def ConwaySmith_for_3S7(): EXAMPLES:: - sage: G = graphs.ConwaySmith_for_3S7() - sage: G.is_distance_regular(True) + sage: G = graphs.ConwaySmith_for_3S7() # needs sage.modules sage.rings.finite_rings sage.rings.number_field + sage: G.is_distance_regular(True) # needs sage.modules sage.rings.finite_rings sage.rings.number_field ([10, 6, 4, 1, None], [None, 1, 2, 6, 10]) REFERENCES: @@ -213,8 +217,8 @@ def graph_3O73(): EXAMPLES:: - sage: G = graphs.graph_3O73() # optional - internet gap_packages - sage: G.is_distance_regular(True) # optional - internet gap_packages + sage: G = graphs.graph_3O73() # optional - internet gap_package_atlasrep + sage: G.is_distance_regular(True) # optional - internet gap_package_atlasrep ([117, 80, 24, 1, None], [None, 1, 12, 80, 117]) REFERENCES: @@ -239,8 +243,8 @@ def FosterGraph3S6(): EXAMPLES:: - sage: G = graphs.FosterGraph3S6() - sage: G.is_distance_regular(True) + sage: G = graphs.FosterGraph3S6() # needs sage.libs.gap + sage: G.is_distance_regular(True) # needs sage.libs.gap ([6, 4, 2, 1, None], [None, 1, 1, 4, 6]) REFERENCES: @@ -268,8 +272,8 @@ def J2Graph(): EXAMPLES:: - sage: G = graphs.J2Graph() # optional - internet gap_packages - sage: G.is_distance_regular(True) # optional - internet gap_packages + sage: G = graphs.J2Graph() # optional - internet gap_package_atlasrep + sage: G.is_distance_regular(True) # optional - internet gap_package_atlasrep ([10, 8, 8, 2, None], [None, 1, 1, 4, 5]) REFERENCES: @@ -291,8 +295,8 @@ def IvanovIvanovFaradjevGraph(): EXAMPLES:: - sage: G = graphs.IvanovIvanovFaradjevGraph() # optional - internet gap_packages - sage: G.is_distance_regular(True) # optional - internet gap_packages + sage: G = graphs.IvanovIvanovFaradjevGraph() # optional - internet gap_package_atlasrep + sage: G.is_distance_regular(True) # optional - internet gap_package_atlasrep ([7, 6, 4, 4, 4, 1, 1, 1, None], [None, 1, 1, 1, 2, 4, 4, 6, 7]) REFERENCES: @@ -317,8 +321,8 @@ def LargeWittGraph(): EXAMPLES:: - sage: g = graphs.LargeWittGraph() - sage: g.is_distance_regular(True) + sage: g = graphs.LargeWittGraph() # needs sage.modules + sage: g.is_distance_regular(True) # needs sage.modules ([30, 28, 24, None], [None, 1, 3, 15]) REFERENCES: @@ -355,8 +359,8 @@ def TruncatedWittGraph(): EXAMPLES:: - sage: G = graphs.TruncatedWittGraph() # long time - sage: G.is_distance_regular(True) # long time (due to above) + sage: G = graphs.TruncatedWittGraph() # long time # needs sage.modules + sage: G.is_distance_regular(True) # long time (due to above) # needs sage.modules ([15, 14, 12, None], [None, 1, 1, 9]) REFERENCES: @@ -384,8 +388,8 @@ def DoublyTruncatedWittGraph(): EXAMPLES:: - sage: G = graphs.DoublyTruncatedWittGraph() - sage: G.is_distance_regular(True) + sage: G = graphs.DoublyTruncatedWittGraph() # needs sage.modules + sage: G.is_distance_regular(True) # needs sage.modules ([7, 6, 4, 4, None], [None, 1, 1, 1, 6]) REFERENCES: @@ -407,8 +411,8 @@ def distance_3_doubly_truncated_Golay_code_graph(): EXAMPLES:: - sage: G = graphs.distance_3_doubly_truncated_Golay_code_graph() # long time - sage: G.is_distance_regular(True) # long time (due to above) + sage: G = graphs.distance_3_doubly_truncated_Golay_code_graph() # long time, needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time (due to above) # needs sage.modules sage.rings.finite_rings ([9, 8, 6, 3, None], [None, 1, 1, 3, 8]) ALGORITHM: @@ -442,8 +446,8 @@ def shortened_00_11_binary_Golay_code_graph(): EXAMPLES:: - sage: G = graphs.shortened_00_11_binary_Golay_code_graph() # long time (9 s) - sage: G.is_distance_regular(True) # long time + sage: G = graphs.shortened_00_11_binary_Golay_code_graph() # long time (9 s), needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time # needs sage.modules sage.rings.finite_rings ([21, 20, 16, 6, 2, 1, None], [None, 1, 2, 6, 16, 20, 21]) ALGORITHM: @@ -481,8 +485,8 @@ def shortened_000_111_extended_binary_Golay_code_graph(): EXAMPLES:: - sage: G = graphs.shortened_000_111_extended_binary_Golay_code_graph() # long time (25 s) - sage: G.is_distance_regular(True) # long time + sage: G = graphs.shortened_000_111_extended_binary_Golay_code_graph() # long time (25 s), needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time # needs sage.modules sage.rings.finite_rings ([21, 20, 16, 9, 2, 1, None], [None, 1, 2, 3, 16, 20, 21]) ALGORITHM: @@ -522,8 +526,8 @@ def vanLintSchrijverGraph(): EXAMPLES:: - sage: G = graphs.vanLintSchrijverGraph() - sage: G.is_distance_regular(True) + sage: G = graphs.vanLintSchrijverGraph() # needs sage.modules + sage: G.is_distance_regular(True) # needs sage.modules ([6, 5, 5, 4, None], [None, 1, 1, 2, 6]) REFERENCES: @@ -553,8 +557,8 @@ def LeonardGraph(): EXAMPLES:: - sage: G = graphs.LeonardGraph() - sage: G.is_distance_regular(True) + sage: G = graphs.LeonardGraph() # needs sage.combinat sage.modules + sage: G.is_distance_regular(True) # needs sage.combinat sage.modules ([12, 11, 10, 7, None], [None, 1, 2, 5, 12]) REFERENCES: @@ -593,8 +597,8 @@ def UstimenkoGraph(const int m, const int q): EXAMPLES:: - sage: G = graphs.UstimenkoGraph(4, 2) - sage: G.is_distance_regular(True) + sage: G = graphs.UstimenkoGraph(4, 2) # needs sage.libs.gap + sage: G.is_distance_regular(True) # needs sage.libs.gap ([70, 32, None], [None, 1, 35]) REFERENCES: @@ -603,13 +607,14 @@ def UstimenkoGraph(const int m, const int q): TESTS:: - sage: G = graphs.UstimenkoGraph(5, 2) # long time - sage: G.order() # long time + sage: # long time, needs sage.libs.gap + sage: G = graphs.UstimenkoGraph(5, 2) + sage: G.order() 2295 - sage: G.is_distance_regular(True) # long time + sage: G.is_distance_regular(True) ([310, 224, None], [None, 1, 35]) - sage: G = graphs.UstimenkoGraph(4,3) # long time - sage: G.is_distance_regular(True) # long time + sage: G = graphs.UstimenkoGraph(4,3) + sage: G.is_distance_regular(True) ([390, 243, None], [None, 1, 130]) """ from sage.graphs.graph_generators import graphs @@ -648,14 +653,15 @@ def BilinearFormsGraph(const int d, const int e, const int q): EXAMPLES:: + sage: # needs sage.modules sage: G = graphs.BilinearFormsGraph(3, 3, 2) sage: G.is_distance_regular(True) ([49, 36, 16, None], [None, 1, 6, 28]) - sage: G = graphs.BilinearFormsGraph(3,3,3) # not tested (20 s) - sage: G.order() # not tested (due to above) + sage: G = graphs.BilinearFormsGraph(3,3,3) # not tested (20 s) # needs sage.rings.finite_rings + sage: G.order() # not tested (due to above) # needs sage.rings.finite_rings 19683 - sage: G = graphs.BilinearFormsGraph(3, 4, 2) # long time - sage: G.is_distance_regular(True) # long time + sage: G = graphs.BilinearFormsGraph(3, 4, 2) # long time # needs sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time # needs sage.rings.finite_rings ([105, 84, 48, None], [None, 1, 6, 28]) REFERENCES: @@ -665,6 +671,7 @@ def BilinearFormsGraph(const int d, const int e, const int q): TESTS:: + sage: # needs sage.modules sage: G = graphs.BilinearFormsGraph(2,3,2) sage: G.is_distance_regular(True) ([21, 12, None], [None, 1, 6]) @@ -750,10 +757,11 @@ def AlternatingFormsGraph(const int n, const int q): TESTS:: - sage: G = graphs.AlternatingFormsGraph(6,2) # not tested (2 min) - sage: G.order() # not tested (because of above) + sage: # needs sage.modules + sage: G = graphs.AlternatingFormsGraph(6,2) # not tested (2 min) # needs sage.rings.finite_rings + sage: G.order() # not tested (because of above) # needs sage.rings.finite_rings 32768 - sage: G.is_distance_regular(True) # not tested (33 min) + sage: G.is_distance_regular(True) # not tested (33 min) # needs sage.rings.finite_rings ([651, 560, 256, None], [None, 1, 20, 336]) sage: G = graphs.AlternatingFormsGraph(4, 3) sage: G.is_distance_regular(True) @@ -836,11 +844,12 @@ def HermitianFormsGraph(const int n, const int r): EXAMPLES:: + sage: # needs sage.modules sage.rings.finite_rings sage: G = graphs.HermitianFormsGraph(2, 2) sage: G.is_distance_regular(True) ([5, 4, None], [None, 1, 2]) - sage: G = graphs.HermitianFormsGraph(3, 3) # not tested (2 min) - sage: G.order() # not tested (bacuase of the above) + sage: G = graphs.HermitianFormsGraph(3, 3) # not tested (2 min) + sage: G.order() # not tested (bacuase of the above) 19683 REFERENCES: @@ -849,6 +858,7 @@ def HermitianFormsGraph(const int n, const int r): TESTS:: + sage: # needs sage.modules sage.rings.finite_rings sage: G = graphs.HermitianFormsGraph(3, 2) sage: G.is_distance_regular(True) ([21, 20, 16, None], [None, 1, 2, 12]) @@ -1075,8 +1085,8 @@ def GrassmannGraph(const int q, const int n, const int input_e): EXAMPLES:: - sage: G = graphs.GrassmannGraph(2, 4, 2) - sage: G.is_distance_regular(True) + sage: G = graphs.GrassmannGraph(2, 4, 2) # needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # needs sage.modules sage.rings.finite_rings ([18, 8, None], [None, 1, 9]) REFERENCES: @@ -1085,8 +1095,9 @@ def GrassmannGraph(const int q, const int n, const int input_e): TESTS:: - sage: G = graphs.GrassmannGraph(2, 6, 3) # long time - sage: G.is_distance_regular(True) # long time + sage: # needs sage.modules sage.rings.finite_rings + sage: G = graphs.GrassmannGraph(2, 6, 3) # long time + sage: G.is_distance_regular(True) # long time ([98, 72, 32, None], [None, 1, 9, 49]) sage: G = graphs.GrassmannGraph(3, 4, 2) sage: G.is_distance_regular(True) @@ -1128,10 +1139,10 @@ def DoubleGrassmannGraph(const int q, const int e): EXAMPLES:: - sage: G = graphs.DoubleGrassmannGraph(2,1) - sage: G.diameter() + sage: G = graphs.DoubleGrassmannGraph(2,1) # needs sage.modules + sage: G.diameter() # needs sage.modules 3 - sage: G.is_distance_regular(True) + sage: G.is_distance_regular(True) # needs sage.modules ([3, 2, 2, None], [None, 1, 1, 3]) @@ -1141,15 +1152,16 @@ def DoubleGrassmannGraph(const int q, const int e): TESTS:: + sage: # needs sage.modules sage: G = graphs.DoubleGrassmannGraph(5,1) sage: G.order() 62 sage: G.is_distance_regular(True) ([6, 5, 5, None], [None, 1, 1, 6]) - sage: G = graphs.DoubleGrassmannGraph(3, 2) # long time - sage: G.order() # long time + sage: G = graphs.DoubleGrassmannGraph(3, 2) # long time # needs sage.rings.finite_rings + sage: G.order() # long time # needs sage.rings.finite_rings 2420 - sage: G.is_distance_regular(True) # long time + sage: G.is_distance_regular(True) # long time # needs sage.rings.finite_rings ([13, 12, 12, 9, 9, None], [None, 1, 1, 4, 4, 13]) """ n = 2*e + 1 @@ -1183,10 +1195,10 @@ def is_from_GQ_spread(list arr): sage: from sage.graphs.generators.distance_regular import \ ....: is_from_GQ_spread, graph_from_GQ_spread - sage: is_from_GQ_spread([125, 120, 1, 1, 24, 125]) + sage: is_from_GQ_spread([125, 120, 1, 1, 24, 125]) # needs sage.libs.pari (5, 25) - sage: G = graph_from_GQ_spread(5, 25) - sage: G.is_distance_regular(True) + sage: G = graph_from_GQ_spread(5, 25) # needs sage.libs.pari + sage: G.is_distance_regular(True) # needs sage.libs.pari ([125, 120, 1, None], [None, 1, 24, 125]) REFERENCES: @@ -1198,9 +1210,9 @@ def is_from_GQ_spread(list arr): sage: from sage.graphs.generators.distance_regular import \ ....: is_from_GQ_spread - sage: is_from_GQ_spread([343, 336, 1, 1, 48, 343]) + sage: is_from_GQ_spread([343, 336, 1, 1, 48, 343]) # needs sage.libs.pari (7, 49) - sage: is_from_GQ_spread([343, 336, 1, 2, 48, 343]) + sage: is_from_GQ_spread([343, 336, 1, 2, 48, 343]) # needs sage.libs.pari False Check that we don't get ``True`` for inexisting GQs:: @@ -1211,7 +1223,7 @@ def is_from_GQ_spread(list arr): sage: t = 6 sage: [s * t, s * (t-1), 1, 1, t - 1, s * t] [30, 25, 1, 1, 5, 30] - sage: is_from_GQ_spread([30, 25, 1, 1, 5, 30]) + sage: is_from_GQ_spread([30, 25, 1, 1, 5, 30]) # needs sage.libs.pari False """ from sage.combinat.designs import design_catalog as designs @@ -1254,8 +1266,8 @@ def graph_from_GQ_spread(const int s, const int t): sage: from sage.graphs.generators.distance_regular import \ ....: graph_from_GQ_spread - sage: G = graph_from_GQ_spread(4, 16) - sage: G.is_distance_regular(True) + sage: G = graph_from_GQ_spread(4, 16) # needs sage.libs.pari + sage: G.is_distance_regular(True) # needs sage.libs.pari ([64, 60, 1, None], [None, 1, 15, 64]) REFERENCES: @@ -1266,18 +1278,17 @@ def graph_from_GQ_spread(const int s, const int t): sage: from sage.graphs.generators.distance_regular import \ ....: graph_from_GQ_spread, is_from_GQ_spread - sage: is_from_GQ_spread([64, 60, 1, 1, 15, 64]) + sage: is_from_GQ_spread([64, 60, 1, 1, 15, 64]) # needs sage.libs.pari (4, 16) - sage: graph_from_GQ_spread(*is_from_GQ_spread([27, 24, 1, 1, 8, 27])) + sage: graph_from_GQ_spread(*is_from_GQ_spread([27, 24, 1, 1, 8, 27])) # needs sage.libs.pari Graph on 112 vertices - sage: _.is_distance_regular(True) + sage: _.is_distance_regular(True) # needs sage.libs.pari ([27, 24, 1, None], [None, 1, 8, 27]) """ from sage.combinat.designs import design_catalog as designs (GQ, S) = designs.generalised_quadrangle_with_spread(s, t, check=False) - k = len(GQ.blocks()[0]) edges = [] for b in GQ.blocks(): if b in S: # skip blocks in spread @@ -1286,8 +1297,7 @@ def graph_from_GQ_spread(const int s, const int t): sig_check() edges.append((p1, p2)) - G = Graph(edges, format="list_of_edges") - return G + return Graph(edges, format="list_of_edges") def GeneralisedDodecagonGraph(const int s, const int t): @@ -1300,13 +1310,14 @@ def GeneralisedDodecagonGraph(const int s, const int t): EXAMPLES:: - sage: G = graphs.GeneralisedDodecagonGraph(1, 5) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_package_atlasrep internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 5) + sage: G.is_distance_regular(True) ([6, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 6]) - sage: H = graphs.GeneralisedDodecagonGraph(5, 1) # optional - gap_packages internet - sage: H.order() # optional - gap_packages internet + sage: H = graphs.GeneralisedDodecagonGraph(5, 1) + sage: H.order() 23436 - sage: H.is_distance_regular(True) # not tested (6 min); optional - gap_packages internet + sage: H.is_distance_regular(True) # not tested (6 min) ([10, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 2]) .. NOTE:: @@ -1324,29 +1335,31 @@ def GeneralisedDodecagonGraph(const int s, const int t): Test all graphs of order `(1, q)`:: - sage: G = graphs.GeneralisedDodecagonGraph(1, 4) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_package_atlasrep internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 4) + sage: G.is_distance_regular(True) ([5, 4, 4, 4, 4, 4, None], [None, 1, 1, 1, 1, 1, 5]) - sage: G = graphs.GeneralisedDodecagonGraph(1, 3) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 3) + sage: G.is_distance_regular(True) ([4, 3, 3, 3, 3, 3, None], [None, 1, 1, 1, 1, 1, 4]) - sage: G = graphs.GeneralisedDodecagonGraph(1, 2) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 2) + sage: G.is_distance_regular(True) ([3, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 3]) - sage: G = graphs.GeneralisedDodecagonGraph(1, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 1) + sage: G.is_distance_regular(True) ([2, 1, 1, 1, 1, 1, None], [None, 1, 1, 1, 1, 1, 2]) Now test all graphs of order `(q, 1)`:: - sage: G = graphs.GeneralisedDodecagonGraph(4, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_package_atlasrep internet + sage: G = graphs.GeneralisedDodecagonGraph(4, 1) + sage: G.is_distance_regular(True) ([8, 4, 4, 4, 4, 4, None], [None, 1, 1, 1, 1, 1, 2]) - sage: G = graphs.GeneralisedDodecagonGraph(3, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(3, 1) + sage: G.is_distance_regular(True) ([6, 3, 3, 3, 3, 3, None], [None, 1, 1, 1, 1, 1, 2]) - sage: G = graphs.GeneralisedDodecagonGraph(2, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(2, 1) + sage: G.is_distance_regular(True) ([4, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 2]) """ from sage.arith.misc import is_prime_power @@ -1405,15 +1418,16 @@ def GeneralisedOctagonGraph(const int s, const int t): EXAMPLES:: - sage: G = graphs.GeneralisedOctagonGraph(1, 4) - sage: G.is_distance_regular(True) - ([5, 4, 4, 4, None], [None, 1, 1, 1, 5]) - sage: G = graphs.GeneralisedOctagonGraph(2, 4) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet - ([10, 8, 8, 8, None], [None, 1, 1, 1, 5]) - sage: G = graphs.GeneralisedOctagonGraph(5, 1) - sage: G.is_distance_regular(True) - ([10, 5, 5, 5, None], [None, 1, 1, 1, 2]) + sage: # needs sage.libs.gap + sage: G = graphs.GeneralisedOctagonGraph(1, 4) + sage: G.is_distance_regular(True) + ([5, 4, 4, 4, None], [None, 1, 1, 1, 5]) + sage: G = graphs.GeneralisedOctagonGraph(2, 4) # optional - gap_package_atlasrep internet + sage: G.is_distance_regular(True) # optional - gap_package_atlasrep internet + ([10, 8, 8, 8, None], [None, 1, 1, 1, 5]) + sage: G = graphs.GeneralisedOctagonGraph(5, 1) + sage: G.is_distance_regular(True) + ([10, 5, 5, 5, None], [None, 1, 1, 1, 2]) .. NOTE:: @@ -1428,11 +1442,11 @@ def GeneralisedOctagonGraph(const int s, const int t): TESTS:: - sage: G = graphs.GeneralisedOctagonGraph(8, 64) + sage: G = graphs.GeneralisedOctagonGraph(8, 64) # needs sage.libs.gap Traceback (most recent call last): ... NotImplementedError: Graph would be too big - sage: G = graphs.GeneralisedOctagonGraph(4, 16) + sage: G = graphs.GeneralisedOctagonGraph(4, 16) # needs sage.libs.gap Traceback (most recent call last): ... ValueError: generalised octagons of order (q, q^2) are known only for odd powers q of 2 @@ -1515,8 +1529,9 @@ def GeneralisedHexagonGraph(const int s, const int t): EXAMPLES:: - sage: G = graphs.GeneralisedHexagonGraph(5, 5) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # needs sage.libs.gap + sage: G = graphs.GeneralisedHexagonGraph(5, 5) # optional - gap_package_atlasrep internet + sage: G.is_distance_regular(True) # optional - gap_package_atlasrep internet ([30, 25, 25, None], [None, 1, 1, 6]) sage: G = graphs.GeneralisedHexagonGraph(7, 1) sage: G.is_distance_regular(True) @@ -1537,17 +1552,18 @@ def GeneralisedHexagonGraph(const int s, const int t): TESTS:: - sage: G = graphs.GeneralisedHexagonGraph(4, 4) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_package_atlasrep internet + sage: G = graphs.GeneralisedHexagonGraph(4, 4) + sage: G.is_distance_regular(True) ([20, 16, 16, None], [None, 1, 1, 5]) - sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedHexagonGraph(3, 3) + sage: G.is_distance_regular(True) ([12, 9, 9, None], [None, 1, 1, 4]) - sage: G = graphs.GeneralisedHexagonGraph(2, 2) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedHexagonGraph(2, 2) + sage: G.is_distance_regular(True) ([6, 4, 4, None], [None, 1, 1, 3]) - sage: G = graphs.GeneralisedHexagonGraph(2, 8) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedHexagonGraph(2, 8) + sage: G.is_distance_regular(True) ([18, 16, 16, None], [None, 1, 1, 9]) """ from sage.arith.misc import is_prime_power @@ -1670,6 +1686,7 @@ def _extract_lines(G): EXAMPLES:: + sage: # needs sage.libs.gap sage: from sage.graphs.generators.distance_regular import _extract_lines sage: G = graphs.GeneralisedHexagonGraph(1, 8) sage: lines = _extract_lines(G) @@ -1737,16 +1754,17 @@ def _line_graph_generalised_polygon(H): EXAMPLES:: - sage: from sage.graphs.generators.distance_regular import \ - ....: _line_graph_generalised_polygon - sage: G = graphs.GeneralisedHexagonGraph(1, 8) - sage: H = _line_graph_generalised_polygon(G) - sage: H.is_distance_regular(True) - ([16, 8, 8, None], [None, 1, 1, 2]) - sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_packages internet - sage: H = _line_graph_generalised_polygon(G) # optional - gap_packages internet - sage: G.is_isomorphic(H) # optional - gap_packages internet - True + sage: # needs sage.libs.gap + sage: from sage.graphs.generators.distance_regular import ( + ....: _line_graph_generalised_polygon) + sage: G = graphs.GeneralisedHexagonGraph(1, 8) + sage: H = _line_graph_generalised_polygon(G) + sage: H.is_distance_regular(True) + ([16, 8, 8, None], [None, 1, 1, 2]) + sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_package_atlasrep internet + sage: H = _line_graph_generalised_polygon(G) # optional - gap_package_atlasrep internet + sage: G.is_isomorphic(H) # optional - gap_package_atlasrep internet + True REFERENCES: @@ -1763,8 +1781,6 @@ def _line_graph_generalised_polygon(H): sig_check() vToLines[p].append(l) - k = len(vToLines[lines[0][0]]) - edges = [] for v in vToLines: lines = vToLines[v] @@ -1772,8 +1788,7 @@ def _line_graph_generalised_polygon(H): sig_check() edges.append((l1, l2)) - G = Graph(edges, format="list_of_edges") - return G + return Graph(edges, format="list_of_edges") def _intersection_array_from_graph(G): @@ -1793,9 +1808,9 @@ def _intersection_array_from_graph(G): sage: from sage.graphs.generators.distance_regular import \ ....: _intersection_array_from_graph - sage: _intersection_array_from_graph(graphs.FosterGraph()) + sage: _intersection_array_from_graph(graphs.FosterGraph()) # needs networkx [3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3] - sage: graphs.FosterGraph().is_distance_regular(True) + sage: graphs.FosterGraph().is_distance_regular(True) # needs networkx ([3, 2, 2, 2, 2, 1, 1, 1, None], [None, 1, 1, 1, 1, 2, 2, 2, 3]) sage: graphs.DartGraph().is_distance_regular() False @@ -1878,7 +1893,7 @@ def is_classical_parameters_graph(list array): sage: G = graphs.HammingGraph(5, 4) sage: G.is_distance_regular(True) ([15, 12, 9, 6, 3, None], [None, 1, 2, 3, 4, 5]) - sage: is_classical_parameters_graph([15, 12, 9, 6, 3, 1, 2, 3, 4, 5]) + sage: is_classical_parameters_graph([15, 12, 9, 6, 3, 1, 2, 3, 4, 5]) # needs sage.combinat (5, 1, 0, 3, 2) REFERENCES: @@ -1891,12 +1906,12 @@ def is_classical_parameters_graph(list array): sage: from sage.graphs.generators.distance_regular import \ ....: is_classical_parameters_graph - sage: is_classical_parameters_graph([68, 64, 1, 17]) # srg not drg + sage: is_classical_parameters_graph([68, 64, 1, 17]) # srg not drg # needs sage.combinat False - sage: G = graphs.GossetGraph() # sporadic classical parameters graph + sage: G = graphs.GossetGraph() # sporadic classical parameters graph sage: G.is_distance_regular(True) ([27, 10, 1, None], [None, 1, 10, 27]) - sage: is_classical_parameters_graph([27, 10, 1, 1, 10, 27]) + sage: is_classical_parameters_graph([27, 10, 1, 1, 10, 27]) # needs sage.combinat False """ from sage.misc.functional import log @@ -2102,7 +2117,7 @@ def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma): Hamming Graph with parameters 3,4: Graph on 64 vertices sage: G = _; G.is_distance_regular(True) ([9, 6, 3, None], [None, 1, 2, 3]) - sage: is_classical_parameters_graph([9, 6, 3, 1, 2, 3]) + sage: is_classical_parameters_graph([9, 6, 3, 1, 2, 3]) # needs sage.combinat (3, 1, 0, 3, 2) Two families of graphs are not implemented yet:: @@ -2126,11 +2141,11 @@ def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma): sage: graph_with_classical_parameters(3, 1, 2, 3, 3) Half 4 Cube: Graph on 8 vertices - sage: graph_with_classical_parameters(3, 2, 0, 2, 9) + sage: graph_with_classical_parameters(3, 2, 0, 2, 9) # needs sage.libs.gap Symplectic Dual Polar Graph DSp(6, 2): Graph on 135 vertices sage: graph_with_classical_parameters(3, 2, 2, 14, 7) # long time Grassmann graph J_2(6, 3): Graph on 1395 vertices - sage: graph_with_classical_parameters(3, -2, -2, 6, 6) # optional - gap_packages internet + sage: graph_with_classical_parameters(3, -2, -2, 6, 6) # optional - gap_package_atlasrep internet Generalised hexagon of order (2, 8): Graph on 819 vertices """ from sage.rings.rational import Rational @@ -2310,7 +2325,7 @@ def pseudo_partition_graph(int m, int a): EXAMPLES:: sage: from sage.graphs.generators.distance_regular import * - sage: pseudo_partition_graph(6, 1) + sage: pseudo_partition_graph(6, 1) # long time Folded Johnson graph with parameters 12,6: Graph on 462 vertices Not all graphs built with this function are pseudo partition graphs as @@ -2390,7 +2405,7 @@ def is_near_polygon(array): sage: from sage.graphs.generators.distance_regular import ( ....: is_near_polygon, near_polygon_graph) - sage: is_near_polygon([7, 6, 6, 5, 5, 4, 1, 1, 2, 2, 3, 3]) + sage: is_near_polygon([7, 6, 6, 5, 5, 4, 1, 1, 2, 2, 3, 3]) # needs sage.combinat (2, 7) sage: near_polygon_graph(2, 7) Odd Graph with parameter 7: Graph on 1716 vertices @@ -2404,19 +2419,20 @@ def is_near_polygon(array): TESTS:: + sage: # needs sage.combinat sage.libs.pari sage: from sage.graphs.generators.distance_regular import ( ....: is_near_polygon, near_polygon_graph) sage: is_near_polygon([7, 6, 6, 4, 4, 1, 1, 3, 3, 7]) (4, (2, 2)) sage: near_polygon_graph(4, (2, 2)) Double Grassmann graph (5, 2, 2): Graph on 310 vertices - sage: near_polygon_graph(*is_near_polygon([3, 2, 2, 1, 1, 3])) + sage: near_polygon_graph(*is_near_polygon([3, 2, 2, 1, 1, 3])) # needs sage.rings.finite_rings Generalised hexagon of order (1, 2): Graph on 14 vertices sage: is_near_polygon([16, 12, 8, 4, 1, 2, 3, 4]) (6, (4, 5)) sage: is_near_polygon([]) False - sage: is_near_polygon([25, 16, 9, 4, 1, 1, 4, 9, 16, 25]) # JohnsonGraph + sage: is_near_polygon([25, 16, 9, 4, 1, 1, 4, 9, 16, 25]) # JohnsonGraph False """ from sage.arith.misc import is_prime_power @@ -2526,12 +2542,11 @@ def near_polygon_graph(family, params): EXAMPLES:: - sage: from sage.graphs.generators.distance_regular import ( - ....: is_near_polygon, near_polygon_graph) - sage: near_polygon_graph(*is_near_polygon([6, 5, 5, 4, 4, 3, 3, 2, 2, \ - ....: 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])) + sage: from sage.graphs.generators.distance_regular import is_near_polygon, near_polygon_graph + sage: near_polygon_graph(*is_near_polygon( # needs sage.combinat + ....: [6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])) Bipartite double of Odd graph on a set of 11 elements: Graph on 924 vertices - sage: G=_; G.is_distance_regular(True) + sage: G=_; G.is_distance_regular(True) # needs sage.combinat ([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None], [None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6]) @@ -2542,6 +2557,7 @@ def near_polygon_graph(family, params): TESTS:: + sage: # needs sage.combinat sage: near_polygon_graph(12, 9) Traceback (most recent call last): ... @@ -2696,8 +2712,8 @@ def distance_regular_graph(list arr, existence=False, check=True): sage: graphs.distance_regular_graph([21,20,16,1,2,12], existence=True) True - sage: G = graphs.distance_regular_graph([12,11,10,7,1,2,5,12], check=False) - sage: G.is_distance_regular(True) + sage: G = graphs.distance_regular_graph([12,11,10,7,1,2,5,12], check=False) # needs sage.combinat sage.modules + sage: G.is_distance_regular(True) # needs sage.combinat sage.modules ([12, 11, 10, 7, None], [None, 1, 2, 5, 12]) REFERENCES: @@ -2706,16 +2722,18 @@ def distance_regular_graph(list arr, existence=False, check=True): TESTS:: - sage: graphs.distance_regular_graph([3, 2, 2, 1, 1, 1, 1, 2, 2, 3], - ....: existence=True) + sage: graphs.distance_regular_graph([3, 2, 2, 1, 1, 1, 1, 2, 2, 3], # needs sage.combinat + ....: existence=True) True sage: graphs.distance_regular_graph([3, 2, 2, 1, 2, 1, 1, 2, 2, 3], - ....: existence=True) + ....: existence=True) False - sage: graphs.distance_regular_graph([18, 16, 16, 1, 1, 9]) # optional - internet gap_packages + sage: graphs.distance_regular_graph([18, 16, 16, 1, 1, 9]) # optional - internet gap_package_atlasrep Generalised hexagon of order (2, 8): Graph on 819 vertices + + sage: # needs sage.combinat sage: graphs.distance_regular_graph([14, 12, 10, 8, 6, 4, 2, - ....: 1, 2, 3, 4, 5, 6, 7]) + ....: 1, 2, 3, 4, 5, 6, 7]) Hamming Graph with parameters 7,3: Graph on 2187 vertices sage: graphs.distance_regular_graph([66, 45, 28, 1, 6, 30]) Graph on 1024 vertices diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index ec6a5c19e60..a5916a13b5c 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -40,13 +40,13 @@ def JohnsonGraph(n, k): The Johnson graph is a Hamiltonian graph:: sage: g = graphs.JohnsonGraph(7, 3) - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True Every Johnson graph is vertex transitive:: sage: g = graphs.JohnsonGraph(6, 4) - sage: g.is_vertex_transitive() + sage: g.is_vertex_transitive() # needs sage.groups True The complement of the Johnson graph `J(n,2)` is isomorphic to the Kneser @@ -452,7 +452,7 @@ def HammingGraph(n, q, X=None): True sage: g.is_regular() True - sage: g.is_vertex_transitive() + sage: g.is_vertex_transitive() # needs sage.groups True A Hamming graph with parameters (1,q) is isomorphic to the @@ -526,9 +526,9 @@ def BalancedTree(r, h): A balanced tree whose root node has degree `r = 2`, and of height `h = 1`, has order 3 and size 2:: - sage: G = graphs.BalancedTree(2, 1); G + sage: G = graphs.BalancedTree(2, 1); G # needs networkx Balanced tree: Graph on 3 vertices - sage: G.order(); G.size() + sage: G.order(); G.size() # needs networkx 3 2 sage: r = 2; h = 1 @@ -539,11 +539,12 @@ def BalancedTree(r, h): Plot a balanced tree of height 5, whose root node has degree `r = 3`:: - sage: G = graphs.BalancedTree(3, 5) - sage: G.show() # long time + sage: G = graphs.BalancedTree(3, 5) # needs networkx + sage: G.show() # long time # needs networkx sage.plot A tree is bipartite. If its vertex set is finite, then it is planar. :: + sage: # needs networkx sage: r = randint(2, 5); h = randint(1, 7) sage: T = graphs.BalancedTree(r, h) sage: T.is_bipartite() @@ -562,13 +563,13 @@ def BalancedTree(r, h): has degree `r \geq 2`, but the construction degenerates gracefully:: - sage: graphs.BalancedTree(1, 10) + sage: graphs.BalancedTree(1, 10) # needs networkx Balanced tree: Graph on 11 vertices Similarly, we usually want the tree must have height `h \geq 1` but the algorithm also degenerates gracefully here:: - sage: graphs.BalancedTree(3, 0) + sage: graphs.BalancedTree(3, 0) # needs networkx Balanced tree: Graph on 1 vertex """ import networkx @@ -613,7 +614,7 @@ def BarbellGraph(n1, n2): sage: g = graphs.BarbellGraph(9, 4); g Barbell graph: Graph on 22 vertices - sage: g.show() # long time + sage: g.show() # long time An ``n1 >= 2``, ``n2 >= 0`` barbell graph has order ``2*n1 + n2``. It has the complete graph on ``n1`` vertices as a subgraph. It also has @@ -627,6 +628,8 @@ def BarbellGraph(n1, n2): True sage: K_n1 = graphs.CompleteGraph(n1) sage: P_n2 = graphs.PathGraph(n2) + + sage: # needs sage.modules sage: s_K = g.subgraph_search(K_n1, induced=True) sage: s_P = g.subgraph_search(P_n2, induced=True) sage: K_n1.is_isomorphic(s_K) @@ -640,7 +643,7 @@ def BarbellGraph(n1, n2): sage: g = graphs.BarbellGraph(n1, n2) sage: g.num_verts() == 2 * n1 + n2 True - sage: g.num_edges() == 2 * binomial(n1, 2) + n2 + 1 + sage: g.num_edges() == 2 * binomial(n1, 2) + n2 + 1 # needs sage.symbolic True sage: g.is_connected() True @@ -709,7 +712,7 @@ def LollipopGraph(n1, n2): sage: g = graphs.LollipopGraph(13,4); g Lollipop graph: Graph on 17 vertices - sage: g.show() # long time + sage: g.show() # long time TESTS:: @@ -717,7 +720,7 @@ def LollipopGraph(n1, n2): sage: g = graphs.LollipopGraph(n1, n2) sage: g.num_verts() == n1 + n2 True - sage: g.num_edges() == binomial(n1, 2) + n2 + sage: g.num_edges() == binomial(n1, 2) + n2 # needs sage.symbolic True sage: g.is_connected() True @@ -782,7 +785,7 @@ def TadpoleGraph(n1, n2): sage: g = graphs.TadpoleGraph(13, 4); g Tadpole graph: Graph on 17 vertices - sage: g.show() # long time + sage: g.show() # long time TESTS:: @@ -874,7 +877,7 @@ def DipoleGraph(n): sage: g = graphs.DipoleGraph(13); g Dipole graph: Multi-graph on 2 vertices - sage: g.show() # long time + sage: g.show() # long time TESTS:: @@ -932,7 +935,7 @@ def BubbleSortGraph(n): sage: g = graphs.BubbleSortGraph(4); g Bubble sort: Graph on 24 vertices - sage: g.plot() # long time + sage: g.plot() # long time Graphics object consisting of 61 graphics primitives The bubble sort graph on `n = 1` symbol is the trivial graph `K_1`:: @@ -1025,13 +1028,13 @@ def chang_graphs(): Construct the Chang graphs by Seidel switching:: - sage: c3c5=graphs.CycleGraph(3).disjoint_union(graphs.CycleGraph(5)) - sage: c8=graphs.CycleGraph(8) - sage: s=[K8.subgraph_search(c8).edges(sort=False), - ....: [(0,1,None),(2,3,None),(4,5,None),(6,7,None)], - ....: K8.subgraph_search(c3c5).edges(sort=False)] - sage: list(map(lambda x,G: T8.seidel_switching(x, inplace=False).is_isomorphic(G), - ....: s, chang_graphs)) + sage: c3c5 = graphs.CycleGraph(3).disjoint_union(graphs.CycleGraph(5)) + sage: c8 = graphs.CycleGraph(8) + sage: s = [K8.subgraph_search(c8).edges(sort=False), # needs sage.modules + ....: [(0,1,None),(2,3,None),(4,5,None),(6,7,None)], + ....: K8.subgraph_search(c3c5).edges(sort=False)] + sage: [T8.seidel_switching(x, inplace=False).is_isomorphic(G) # needs sage.modules + ....: for x, G in zip(s, chang_graphs)] [True, True, True] """ @@ -1076,17 +1079,19 @@ def CirculantGraph(n, adjacency): EXAMPLES: Compare plotting using the predefined layout and networkx:: + sage: # needs networkx sage: import networkx sage: n = networkx.cycle_graph(23) sage: spring23 = Graph(n) sage: posdict23 = graphs.CirculantGraph(23,2) - sage: spring23.show() # long time - sage: posdict23.show() # long time + sage: spring23.show() # long time + sage: posdict23.show() # long time We next view many cycle graphs as a Sage graphics array. First we use the ``CirculantGraph`` constructor, which fills in the position dictionary:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -1098,10 +1103,11 @@ def CirculantGraph(n, adjacency): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time Compare to plotting with the spring-layout algorithm:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -1114,13 +1120,13 @@ def CirculantGraph(n, adjacency): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time Passing a 1 into adjacency should give the cycle. :: - sage: graphs.CirculantGraph(6,1)==graphs.CycleGraph(6) + sage: graphs.CirculantGraph(6,1) == graphs.CycleGraph(6) True sage: graphs.CirculantGraph(7,[1,3]).edges(sort=True, labels=false) [(0, 1), @@ -1187,6 +1193,7 @@ def CubeGraph(n, embedding=1): Plot several `n`-cubes in a Sage Graphics Array:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(6): @@ -1200,14 +1207,14 @@ def CubeGraph(n, embedding=1): ....: j.append(n) ... sage: G = graphics_array(j) - sage: G.show(figsize=[6,4]) # long time + sage: G.show(figsize=[6,4]) # long time Use the plot options to display larger `n`-cubes:: sage: g = graphs.CubeGraph(9, embedding=1) - sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time + sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time, needs sage.plot sage: g = graphs.CubeGraph(9, embedding=2) - sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time + sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time, needs sage.plot AUTHORS: @@ -1306,9 +1313,9 @@ def GoethalsSeidelGraph(k, r): EXAMPLES:: - sage: graphs.GoethalsSeidelGraph(3,3) + sage: graphs.GoethalsSeidelGraph(3,3) # needs sage.modules Graph on 28 vertices - sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True) + sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True) # needs sage.modules (28, 15, 6, 10) """ from sage.combinat.designs.bibd import balanced_incomplete_block_design @@ -1353,8 +1360,8 @@ def DorogovtsevGoltsevMendesGraph(n): EXAMPLES:: - sage: G = graphs.DorogovtsevGoltsevMendesGraph(8) - sage: G.size() + sage: G = graphs.DorogovtsevGoltsevMendesGraph(8) # needs networkx + sage: G.size() # needs networkx 6561 REFERENCE: @@ -1438,6 +1445,7 @@ def FriendshipGraph(n): The first few friendship graphs. :: + sage: # needs sage.plot sage: A = []; B = [] sage: for i in range(9): ....: g = graphs.FriendshipGraph(i + 1) @@ -1448,14 +1456,14 @@ def FriendshipGraph(n): ....: n.append(A[3*i + j].plot(vertex_size=20, vertex_labels=False)) ....: B.append(n) sage: G = graphics_array(B) - sage: G.show() # long time + sage: G.show() # long time For `n = 1`, the friendship graph `F_1` is isomorphic to the cycle graph `C_3`, whose visual representation is a triangle. :: sage: G = graphs.FriendshipGraph(1); G Friendship graph: Graph on 3 vertices - sage: G.show() # long time + sage: G.show() # long time # needs sage.plot sage: G.is_isomorphic(graphs.CycleGraph(3)) True @@ -1538,7 +1546,7 @@ def FuzzyBallGraph(partition, q): EXAMPLES:: sage: F = graphs.FuzzyBallGraph([3,1],2) - sage: F.adjacency_matrix(vertices=list(F)) + sage: F.adjacency_matrix(vertices=list(F)) # needs sage.modules [0 0 1 1 1 0 0 0] [0 0 0 0 0 1 0 0] [1 0 0 1 1 1 1 1] @@ -1553,10 +1561,14 @@ def FuzzyBallGraph(partition, q): `k` parts should be cospectral with respect to the normalized Laplacian:: - sage: m=4; q=2; k=2 - sage: g_list=[graphs.FuzzyBallGraph(p,q) for p in Partitions(m, length=k)] - sage: set([g.laplacian_matrix(normalized=True, vertices=list(g)).charpoly() for g in g_list]) # long time (7s on sage.math, 2011) - {x^8 - 8*x^7 + 4079/150*x^6 - 68689/1350*x^5 + 610783/10800*x^4 - 120877/3240*x^3 + 1351/100*x^2 - 931/450*x} + sage: m = 4; q = 2; k = 2 + sage: g_list = [graphs.FuzzyBallGraph(p,q) # needs sage.combinat sage.modules + ....: for p in Partitions(m, length=k)] + sage: set(g.laplacian_matrix(normalized=True, # long time (7s on sage.math, 2011), needs sage.combinat sage.modules + ....: vertices=list(g)).charpoly() + ....: for g in g_list) + {x^8 - 8*x^7 + 4079/150*x^6 - 68689/1350*x^5 + 610783/10800*x^4 + - 120877/3240*x^3 + 1351/100*x^2 - 931/450*x} """ from sage.graphs.generators.basic import CompleteGraph if len(partition) < 1: @@ -1584,15 +1596,15 @@ def FibonacciTree(n): EXAMPLES:: - sage: g = graphs.FibonacciTree(3) - sage: g.is_tree() + sage: g = graphs.FibonacciTree(3) # needs sage.libs.pari + sage: g.is_tree() # needs sage.libs.pari True :: - sage: l1 = [ len(graphs.FibonacciTree(_)) + 1 for _ in range(6) ] - sage: l2 = list(fibonacci_sequence(2,8)) - sage: l1 == l2 + sage: l1 = [ len(graphs.FibonacciTree(_)) + 1 for _ in range(6) ] # needs sage.libs.pari + sage: l2 = list(fibonacci_sequence(2,8)) # needs sage.libs.pari + sage: l1 == l2 # needs sage.libs.pari True AUTHORS: @@ -2070,15 +2082,15 @@ def HararyGraph(k, n): 9 sage: h.size() 23 - sage: h.vertex_connectivity() + sage: h.vertex_connectivity() # needs sage.numerical.mip 5 TESTS: Connectivity of some Harary graphs:: - sage: n=10 - sage: for k in range(2,n): + sage: n = 10 + sage: for k in range(2,n): # needs sage.numerical.mip ....: g = graphs.HararyGraph(k,n) ....: if k != g.vertex_connectivity(): ....: print("Connectivity of Harary graphs not satisfied.") @@ -2203,30 +2215,32 @@ def LCFGraph(n, shift_list, repeats): EXAMPLES:: - sage: G = graphs.LCFGraph(4, [2,-2], 2) - sage: G.is_isomorphic(graphs.TetrahedralGraph()) + sage: G = graphs.LCFGraph(4, [2,-2], 2) # needs networkx + sage: G.is_isomorphic(graphs.TetrahedralGraph()) # needs networkx True :: - sage: G = graphs.LCFGraph(20, [10,7,4,-4,-7,10,-4,7,-7,4], 2) - sage: G.is_isomorphic(graphs.DodecahedralGraph()) + sage: G = graphs.LCFGraph(20, [10,7,4,-4,-7,10,-4,7,-7,4], 2) # needs networkx + sage: G.is_isomorphic(graphs.DodecahedralGraph()) # needs networkx True :: - sage: G = graphs.LCFGraph(14, [5,-5], 7) - sage: G.is_isomorphic(graphs.HeawoodGraph()) + sage: G = graphs.LCFGraph(14, [5,-5], 7) # needs networkx + sage: G.is_isomorphic(graphs.HeawoodGraph()) # needs networkx True The largest cubic nonplanar graph of diameter three:: - sage: G = graphs.LCFGraph(20, [-10,-7,-5,4,7,-10,-7,-4,5,7,-10,-7,6,-5,7,-10,-7,5,-6,7], 1) + sage: # needs networkx + sage: G = graphs.LCFGraph(20, [-10,-7,-5,4,7,-10,-7,-4,5,7, + ....: -10,-7,6,-5,7,-10,-7,5,-6,7], 1) sage: G.degree() [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] sage: G.diameter() 3 - sage: G.show() # long time + sage: G.show() # long time # needs sage.plot PLOTTING: LCF Graphs are plotted as an n-cycle with edges in the middle, as described above. @@ -2392,7 +2406,7 @@ def NKStarGraph(n, k): EXAMPLES:: sage: g = graphs.NKStarGraph(4,2) - sage: g.plot() # long time + sage: g.plot() # long time Graphics object consisting of 31 graphics primitives REFERENCES: @@ -2451,7 +2465,7 @@ def NStarGraph(n): EXAMPLES:: sage: g = graphs.NStarGraph(4) - sage: g.plot() # long time + sage: g.plot() # long time Graphics object consisting of 61 graphics primitives REFERENCES: @@ -2533,14 +2547,14 @@ def PaleyGraph(q): EXAMPLES:: - sage: G = graphs.PaleyGraph(9); G + sage: G = graphs.PaleyGraph(9); G # needs sage.rings.finite_rings Paley graph with parameter 9: Graph on 9 vertices - sage: G.is_regular() + sage: G.is_regular() # needs sage.rings.finite_rings True A Paley graph is always self-complementary:: - sage: G.is_self_complementary() + sage: G.is_self_complementary() # needs sage.rings.finite_rings True TESTS: @@ -2583,9 +2597,9 @@ def PasechnikGraph(n): EXAMPLES:: - sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True) + sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (225, 98, 43, 42) - sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True) # long time + sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True) # long time, needs sage.combinat sage.modules (361, 162, 73, 72) sage: graphs.PasechnikGraph(9).is_strongly_regular(parameters=True) # not tested (1225, 578, 273, 272) @@ -2625,11 +2639,15 @@ def SquaredSkewHadamardMatrixGraph(n): EXAMPLES:: - sage: graphs.SquaredSkewHadamardMatrixGraph(4).is_strongly_regular(parameters=True) + sage: # needs sage.modules + sage: G = graphs.SquaredSkewHadamardMatrixGraph(4) + sage: G.is_strongly_regular(parameters=True) (225, 112, 55, 56) - sage: graphs.SquaredSkewHadamardMatrixGraph(5).is_strongly_regular(parameters=True) # long time + sage: G = graphs.SquaredSkewHadamardMatrixGraph(5) + sage: G.is_strongly_regular(parameters=True) # long time (361, 180, 89, 90) - sage: graphs.SquaredSkewHadamardMatrixGraph(9).is_strongly_regular(parameters=True) # not tested + sage: G = graphs.SquaredSkewHadamardMatrixGraph(9) + sage: G.is_strongly_regular(parameters=True) # not tested (1225, 612, 305, 306) TESTS:: @@ -2675,13 +2693,14 @@ def SwitchedSquaredSkewHadamardMatrixGraph(n): EXAMPLES:: - sage: g=graphs.SwitchedSquaredSkewHadamardMatrixGraph(4) - sage: g.is_strongly_regular(parameters=True) + sage: g = graphs.SwitchedSquaredSkewHadamardMatrixGraph(4) # needs sage.modules + sage: g.is_strongly_regular(parameters=True) # needs sage.modules (226, 105, 48, 49) sage: from sage.combinat.designs.twographs import twograph_descendant - sage: twograph_descendant(g,0).is_strongly_regular(parameters=True) + sage: twograph_descendant(g, 0).is_strongly_regular(parameters=True) # needs sage.modules (225, 112, 55, 56) - sage: twograph_descendant(g.complement(),0).is_strongly_regular(parameters=True) + sage: gc = g.complement() # needs sage.modules + sage: twograph_descendant(gc, 0).is_strongly_regular(parameters=True) # needs sage.modules (225, 112, 55, 56) TESTS:: @@ -2812,7 +2831,7 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True): :: sage: H = graphs.HanoiTowerGraph(3, 4, labels=False, positions=False) - sage: H.automorphism_group().is_isomorphic(SymmetricGroup(3)) # optional - sage.groups + sage: H.automorphism_group().is_isomorphic(SymmetricGroup(3)) # needs sage.groups True sage: H.chromatic_number() 3 @@ -3060,10 +3079,10 @@ def petersen_family(generate=False): The two different inputs generate the same graphs:: sage: F1 = graphs.petersen_family(generate=False) - sage: F2 = graphs.petersen_family(generate=True) + sage: F2 = graphs.petersen_family(generate=True) # needs sage.modules sage: F1 = [g.canonical_label().graph6_string() for g in F1] - sage: F2 = [g.canonical_label().graph6_string() for g in F2] - sage: set(F1) == set(F2) + sage: F2 = [g.canonical_label().graph6_string() for g in F2] # needs sage.modules + sage: set(F1) == set(F2) # needs sage.modules True """ from sage.graphs.generators.smallgraphs import PetersenGraph @@ -3178,6 +3197,7 @@ def SierpinskiGasketGraph(n): EXAMPLES:: + sage: # needs sage.modules sage: s4 = graphs.SierpinskiGasketGraph(4); s4 Graph on 42 vertices sage: s4.size() @@ -3267,14 +3287,15 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): of `G` are isomorphic to Hanoi Tower graphs:: sage: k = randint(1, 5) - sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k) + sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k) # needs sage.modules sage: H = graphs.HanoiTowerGraph(3, k) - sage: S.is_isomorphic(H) + sage: S.is_isomorphic(H) # needs sage.modules True The generalized Sierpinski graph of dimension `k` of any graph `G` with `n` vertices and `m` edges has `n^k` vertices and `m\sum_{i=0}^{k-1}n^i` edges:: + sage: # needs sage.modules sage: n = randint(2, 6) sage: k = randint(1, 5) sage: G = graphs.RandomGNP(n, .5) @@ -3297,14 +3318,14 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): sage: G = graphs.HouseGraph() sage: G.get_pos() is not None True - sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) - sage: H.get_pos() is not None + sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # needs sage.symbolic + sage: H.get_pos() is not None # needs sage.symbolic True sage: G = Graph([(0, 1)]) sage: G.get_pos() is not None False - sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) - sage: H.get_pos() is not None + sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # needs sage.symbolic + sage: H.get_pos() is not None # needs sage.symbolic False .. PLOT:: @@ -3313,6 +3334,7 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): TESTS:: + sage: # needs sage.modules sage: graphs.GeneralizedSierpinskiGraph(Graph(), 3) Generalized Sierpinski Graph of Graph on 0 vertices of dimension 3: Graph on 0 vertices sage: graphs.GeneralizedSierpinskiGraph(Graph(1), 3).vertices(sort=False) @@ -3392,6 +3414,7 @@ def WheelGraph(n): We view many wheel graphs with a Sage Graphics Array, first with this constructor (i.e., the position dictionary filled):: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -3405,10 +3428,11 @@ def WheelGraph(n): ....: j.append(n) ... sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time Next, using the spring-layout algorithm:: + sage: # needs networkx sage.plot sage: import networkx sage: g = [] sage: j = [] @@ -3424,15 +3448,16 @@ def WheelGraph(n): ....: j.append(n) ... sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time Compare the plotting:: + sage: # needs networkx sage.plot sage: n = networkx.wheel_graph(23) sage: spring23 = Graph(n) sage: posdict23 = graphs.WheelGraph(23) - sage: spring23.show() # long time - sage: posdict23.show() # long time + sage: spring23.show() # long time + sage: posdict23.show() # long time """ from sage.graphs.generators.basic import CycleGraph if n < 4: @@ -3660,7 +3685,7 @@ def nauty_gentreeg(options="", debug=False): sage: gen = graphs.nauty_gentreeg("4", debug=True) sage: print(next(gen)) - >A ...gentreeg Z=2:3 D=3 n=4 + >A ...gentreeg ... sage: gen = graphs.nauty_gentreeg("4 -q", debug=True) sage: next(gen) '' @@ -3687,7 +3712,7 @@ def nauty_gentreeg(options="", debug=False): sage: list(graphs.nauty_gentreeg("3 -x", debug=True)) ['>E Usage: ...gentreeg [-D#] [-Z#:#] [-ulps] [-q] n [res/mod] ... sage: list(graphs.nauty_gentreeg("3", debug=True)) - ['>A ...gentreeg Z=2:2 D=2 n=3\n', Graph on 3 vertices] + ['>A ...gentreeg ...\n', Graph on 3 vertices] """ import shlex from sage.features.nauty import NautyExecutable @@ -3735,9 +3760,10 @@ def RingedTree(k, vertex_labels=True): EXAMPLES:: + sage: # needs networkx sage: G = graphs.RingedTree(5) - sage: P = G.plot(vertex_labels=False, vertex_size=10) - sage: P.show() # long time + sage: P = G.plot(vertex_labels=False, vertex_size=10) # needs sage.plot + sage: P.show() # long time # needs sage.plot sage: G.vertices(sort=True) ['', '0', '00', '000', '0000', '0001', '001', '0010', '0011', '01', '010', '0100', '0101', '011', '0110', '0111', '1', '10', '100', @@ -3750,8 +3776,8 @@ def RingedTree(k, vertex_labels=True): Traceback (most recent call last): ... ValueError: The number of levels must be >= 1. - sage: G = graphs.RingedTree(5, vertex_labels = False) - sage: G.vertices(sort=True) + sage: G = graphs.RingedTree(5, vertex_labels=False) # needs networkx + sage: G.vertices(sort=True) # needs networkx [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30] """ @@ -3814,22 +3840,22 @@ def MathonPseudocyclicMergingGraph(M, t): sage: from sage.graphs.generators.families import MathonPseudocyclicMergingGraph as mer sage: from sage.graphs.generators.smallgraphs import _EllipticLinesProjectivePlaneScheme as ES - sage: G = mer(ES(3), 0) # long time + sage: G = mer(ES(3), 0) # long time sage: G.is_strongly_regular(parameters=True) # long time (784, 243, 82, 72) - sage: G = mer(ES(3), 1) # long time + sage: G = mer(ES(3), 1) # long time sage: G.is_strongly_regular(parameters=True) # long time (784, 270, 98, 90) - sage: G = mer(ES(3), 2) # long time + sage: G = mer(ES(3), 2) # long time sage: G.is_strongly_regular(parameters=True) # long time (784, 297, 116, 110) - sage: G = mer(ES(2), 2) + sage: G = mer(ES(2), 2) # needs sage.libs.gap Traceback (most recent call last): ... AssertionError... - sage: M = ES(3) - sage: M = [M[1],M[0],M[2],M[3]] - sage: G = mer(M, 2) + sage: M = ES(3) # needs sage.libs.gap + sage: M = [M[1],M[0],M[2],M[3]] # needs sage.libs.gap + sage: G = mer(M, 2) # needs sage.libs.gap Traceback (most recent call last): ... AssertionError... @@ -3884,13 +3910,14 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): Using default ``G`` and ``L``. :: sage: from sage.graphs.generators.families import MathonPseudocyclicStronglyRegularGraph - sage: G=MathonPseudocyclicStronglyRegularGraph(1); G + sage: G = MathonPseudocyclicStronglyRegularGraph(1); G # needs sage.modules sage.rings.finite_rings Mathon's PC SRG on 45 vertices: Graph on 45 vertices - sage: G.is_strongly_regular(parameters=True) + sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (45, 22, 10, 11) Supplying ``G`` and ``L`` (constructed from the automorphism group of ``G``). :: + sage: # needs sage.groups sage.libs.gap sage.rings.finite_rings sage: G = graphs.PaleyGraph(9) sage: a = G.automorphism_group(partition=[sorted(G)]) sage: it = (x for x in a.normal_subgroups() if x.order() == 9) @@ -3910,21 +3937,22 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): [-4 -3 -2 2 3 4 -1 0 1] [-2 -4 -3 4 2 3 1 -1 0] + sage: # needs sage.modules sage.rings.finite_rings sage.groups sage.libs.gap sage: G.relabel(range(9)) - sage: G3x3=graphs.MathonPseudocyclicStronglyRegularGraph(2,G=G,L=L) + sage: G3x3 = graphs.MathonPseudocyclicStronglyRegularGraph(2, G=G, L=L) sage: G3x3.is_strongly_regular(parameters=True) (441, 220, 109, 110) - sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss + sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss 27 - sage: G9=graphs.MathonPseudocyclicStronglyRegularGraph(2) + sage: G9 = graphs.MathonPseudocyclicStronglyRegularGraph(2) sage: G9.is_strongly_regular(parameters=True) (441, 220, 109, 110) - sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss + sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss 9 TESTS:: - sage: graphs.MathonPseudocyclicStronglyRegularGraph(5) + sage: graphs.MathonPseudocyclicStronglyRegularGraph(5) # needs sage.modules Traceback (most recent call last): ... ValueError: 21 must be a sum of two squares!... @@ -4118,18 +4146,20 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): EXAMPLES:: - sage: graphs.MuzychukS6Graph(3, 3).is_strongly_regular(parameters=True) + sage: graphs.MuzychukS6Graph(3, 3).is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (378, 116, 34, 36) - sage: phi={(2,(0,2)):0,(1,(1,3)):1,(0,(0,3)):1,(2,(1,2)):1,(1,(1, - ....: 2)):0,(0,(0,2)):0,(3,(0,3)):0,(3,(1,3)):1} - sage: graphs.MuzychukS6Graph(2,2,Phi=phi).is_strongly_regular(parameters=True) + sage: phi = {(2,(0,2)):0, (1,(1,3)):1, (0,(0,3)):1, (2,(1,2)):1, # needs sage.modules + ....: (1,(1,2)):0, (0,(0,2)):0, (3,(0,3)):0, (3,(1,3)):1} + sage: graphs.MuzychukS6Graph(2, 2, # needs sage.modules sage.rings.finite_rings + ....: Phi=phi).is_strongly_regular(parameters=True) (16, 5, 0, 2) TESTS:: - sage: graphs.MuzychukS6Graph(2,2,Phi='random',Sigma='random').is_strongly_regular(parameters=True) + sage: # needs sage.modules + sage: graphs.MuzychukS6Graph(2,2,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (16, 5, 0, 2) - sage: graphs.MuzychukS6Graph(3,3,Phi='random',Sigma='random').is_strongly_regular(parameters=True) + sage: graphs.MuzychukS6Graph(3,3,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (378, 116, 34, 36) sage: graphs.MuzychukS6Graph(3,2) Traceback (most recent call last): @@ -4143,11 +4173,11 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): Traceback (most recent call last): ... AssertionError: d must be at least 2 - sage: graphs.MuzychukS6Graph(3,3,Phi=42) + sage: graphs.MuzychukS6Graph(3,3,Phi=42) # needs sage.rings.finite_rings Traceback (most recent call last): ... AssertionError: Phi must be a dictionary or 'random' or 'fixed' - sage: graphs.MuzychukS6Graph(3,3,Sigma=42) + sage: graphs.MuzychukS6Graph(3,3,Sigma=42) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: Sigma must be 'random' or 'fixed' diff --git a/src/sage/graphs/generators/intersection.py b/src/sage/graphs/generators/intersection.py index f2cd8b248ad..0de3715e0e1 100644 --- a/src/sage/graphs/generators/intersection.py +++ b/src/sage/graphs/generators/intersection.py @@ -417,9 +417,10 @@ def OrthogonalArrayBlockGraph(k, n, OA=None): EXAMPLES:: - sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G + sage: # needs sage.modules + sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G # needs sage.schemes OA(5,5): Graph on 25 vertices - sage: G.is_strongly_regular(parameters=True) + sage: G.is_strongly_regular(parameters=True) # needs sage.schemes (25, 20, 15, 20) sage: G = graphs.OrthogonalArrayBlockGraph(4,10); G OA(4,10): Graph on 100 vertices @@ -428,20 +429,21 @@ def OrthogonalArrayBlockGraph(k, n, OA=None): Two graphs built from different orthogonal arrays are also different:: - sage: k=4;n=10 + sage: # needs sage.modules + sage: k = 4; n = 10 sage: OAa = designs.orthogonal_arrays.build(k,n) sage: OAb = [[(x+1)%n for x in R] for R in OAa] sage: set(map(tuple,OAa)) == set(map(tuple,OAb)) False - sage: Ga = graphs.OrthogonalArrayBlockGraph(k,n,OAa) - sage: Gb = graphs.OrthogonalArrayBlockGraph(k,n,OAb) + sage: Ga = graphs.OrthogonalArrayBlockGraph(k, n, OAa) + sage: Gb = graphs.OrthogonalArrayBlockGraph(k, n, OAb) sage: Ga == Gb False As ``OAb`` was obtained from ``OAa`` by a relabelling the two graphs are isomorphic:: - sage: Ga.is_isomorphic(Gb) + sage: Ga.is_isomorphic(Gb) # needs sage.modules True But there are examples of `OA(k,n)` for which the resulting graphs are not @@ -455,31 +457,31 @@ def OrthogonalArrayBlockGraph(k, n, OA=None): ....: [1, 0, 3], [1, 1, 2], [1, 2, 0], [1, 3, 1], ....: [2, 0, 0], [2, 1, 1], [2, 2, 2], [2, 3, 3], ....: [3, 0, 2], [3, 1, 3], [3, 2, 1], [3, 3, 0]] - sage: g0 = graphs.OrthogonalArrayBlockGraph(3,4,oa0) - sage: g1 = graphs.OrthogonalArrayBlockGraph(3,4,oa1) - sage: g0.is_isomorphic(g1) + sage: g0 = graphs.OrthogonalArrayBlockGraph(3, 4, oa0) # needs sage.modules + sage: g1 = graphs.OrthogonalArrayBlockGraph(3, 4, oa1) # needs sage.modules + sage: g0.is_isomorphic(g1) # needs sage.modules False But nevertheless isospectral:: - sage: g0.spectrum() + sage: g0.spectrum() # needs sage.modules [9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3] - sage: g1.spectrum() + sage: g1.spectrum() # needs sage.modules [9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3] Note that the graph ``g0`` is actually isomorphic to the affine polar graph `VO^+(4,2)`:: - sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0) + sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0) # needs sage.modules True TESTS:: - sage: G = graphs.OrthogonalArrayBlockGraph(4,6) + sage: G = graphs.OrthogonalArrayBlockGraph(4,6) # needs sage.modules Traceback (most recent call last): ... NotImplementedError: I don't know how to build an OA(4,6)! - sage: G = graphs.OrthogonalArrayBlockGraph(8,2) + sage: G = graphs.OrthogonalArrayBlockGraph(8,2) # needs sage.modules Traceback (most recent call last): ... ValueError: There is no OA(8,2). Beware, Brouwer's website uses OA(n,k) instead of OA(k,n) ! diff --git a/src/sage/graphs/generators/platonic_solids.py b/src/sage/graphs/generators/platonic_solids.py index f6244d587ea..38e070a054a 100644 --- a/src/sage/graphs/generators/platonic_solids.py +++ b/src/sage/graphs/generators/platonic_solids.py @@ -39,15 +39,16 @@ def TetrahedralGraph(): Construct and show a Tetrahedral graph:: sage: g = graphs.TetrahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot The following example requires networkx:: - sage: import networkx as NX + sage: import networkx as NX # needs networkx Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted with the spring-layout algorithm below in a Sage graphics array:: + sage: # needs networkx sage.plot sage: tetra_pos = graphs.TetrahedralGraph() sage: tetra_spring = Graph(NX.tetrahedral_graph()) sage: wheel = graphs.WheelGraph(4) @@ -60,7 +61,7 @@ def TetrahedralGraph(): ....: n.append(g[i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time """ edges = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] pos = {0: (0, 0), @@ -88,11 +89,12 @@ def HexahedralGraph(): Construct and show a Hexahedral graph:: sage: g = graphs.HexahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot Create several hexahedral graphs in a Sage graphics array. They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -104,7 +106,7 @@ def HexahedralGraph(): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time """ adj = {0: [1, 3, 4], 1: [2, 5], 2: [3, 6], 3: [7], 4: [5, 7], 5: [6], 6: [7]} pos = { @@ -145,6 +147,7 @@ def OctahedralGraph(): Create several octahedral graphs in a Sage graphics array They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -156,7 +159,7 @@ def OctahedralGraph(): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time """ adj = {0: [1, 2, 3, 4], 1: [2, 3, 5], 2: [4, 5], 3: [4, 5], 4: [5]} G = Graph(adj, format='dict_of_lists', name="Octahedron") @@ -184,11 +187,12 @@ def IcosahedralGraph(): Construct and show an Octahedral graph:: sage: g = graphs.IcosahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot Create several icosahedral graphs in a Sage graphics array. They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -200,7 +204,7 @@ def IcosahedralGraph(): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time """ adj = {0: [1, 5, 7, 8, 11], 1: [2, 5, 6, 8], 2: [3, 6, 8, 9], 3: [4, 6, 9, 10], 4: [5, 6, 10, 11], 5: [6, 11], @@ -228,11 +232,12 @@ def DodecahedralGraph(): Construct and show a Dodecahedral graph:: sage: g = graphs.DodecahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot Create several dodecahedral graphs in a Sage graphics array They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -244,7 +249,7 @@ def DodecahedralGraph(): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time """ adj = {0: [1, 10, 19], 1: [2, 8], 2: [3, 6], 3: [4, 19], 4: [5, 17], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 1b0f4cd9d4d..5dab4071f49 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -78,13 +78,13 @@ def RandomGNP(n, p, seed=None, fast=True, algorithm='Sage'): sage: for i in range(9): ....: k = graphs.RandomGNP(i+3,.43) ....: g.append(k) - sage: for i in range(3): + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) - sage: G.show() # long time + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot sage: graphs.RandomGNP(4,1) Complete graph: Graph on 4 vertices @@ -97,7 +97,7 @@ def RandomGNP(n, p, seed=None, fast=True, algorithm='Sage'): sage: set_random_seed(0) sage: graphs.RandomGNP(50,.2, algorithm="Sage").size() 243 - sage: graphs.RandomGNP(50,.2, algorithm="networkx").size() + sage: graphs.RandomGNP(50,.2, algorithm="networkx").size() # needs networkx 279 # 32-bit 209 # 64-bit """ @@ -149,19 +149,20 @@ def RandomBarabasiAlbert(n, m, seed=None): We show the edge list of a random graph on 6 nodes with `m = 2`:: - sage: G = graphs.RandomBarabasiAlbert(6,2) - sage: G.order(), G.size() + sage: G = graphs.RandomBarabasiAlbert(6,2) # needs networkx + sage: G.order(), G.size() # needs networkx (6, 8) - sage: G.degree_sequence() # random + sage: G.degree_sequence() # random # needs networkx [4, 3, 3, 2, 2, 2] We plot a random graph on 12 nodes with `m = 3`:: - sage: ba = graphs.RandomBarabasiAlbert(12,3) - sage: ba.show() # long time + sage: ba = graphs.RandomBarabasiAlbert(12,3) # needs networkx + sage: ba.show() # long time # needs networkx sage.plot We view many random graphs using a graphics array:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] sage: for i in range(1,10): @@ -173,11 +174,11 @@ def RandomBarabasiAlbert(n, m, seed=None): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time When `m = 1`, the generated graph is a tree:: - sage: graphs.RandomBarabasiAlbert(6, 1).is_tree() + sage: graphs.RandomBarabasiAlbert(6, 1).is_tree() # needs networkx True """ if seed is None: @@ -206,28 +207,29 @@ def RandomBipartite(n1, n2, p, set_position=False, seed=None): EXAMPLES:: - sage: g = graphs.RandomBipartite(5, 2, 0.5) - sage: g.vertices(sort=True) + sage: g = graphs.RandomBipartite(5, 2, 0.5) # needs numpy + sage: g.vertices(sort=True) # needs numpy [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)] TESTS:: - sage: g = graphs.RandomBipartite(5, -3, 0.5) + sage: g = graphs.RandomBipartite(5, -3, 0.5) # needs numpy Traceback (most recent call last): ... ValueError: n1 and n2 should be integers strictly greater than 0 - sage: g = graphs.RandomBipartite(5, 3, 1.5) + sage: g = graphs.RandomBipartite(5, 3, 1.5) # needs numpy Traceback (most recent call last): ... ValueError: parameter p is a probability, and so should be a real value between 0 and 1 :trac:`12155`:: - sage: graphs.RandomBipartite(5, 6, .2).complement() + sage: graphs.RandomBipartite(5, 6, .2).complement() # needs numpy complement(Random bipartite graph of order 5+6 with edge probability 0.200000000000000): Graph on 11 vertices Test assigned positions:: + sage: # needs numpy sage: graphs.RandomBipartite(1, 2, .1, set_position=True).get_pos() {(0, 0): (1, 1.0), (1, 0): (0, 0), (1, 1): (2.0, 0.0)} sage: graphs.RandomBipartite(2, 1, .1, set_position=True).get_pos() @@ -512,7 +514,7 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False, seed=None): sage: m, k = 6, 4 sage: IS = graphs.RandomBlockGraph(m, k, incidence_structure=True) sage: from sage.combinat.designs.incidence_structures import IncidenceStructure - sage: IncidenceStructure(IS) + sage: IncidenceStructure(IS) # needs sage.modules Incidence structure with 19 points and 6 blocks sage: m*(k-1)+1 19 @@ -665,12 +667,12 @@ def RandomGNM(n, m, dense=False, seed=None): INPUT: - - ``n`` - number of vertices. + - ``n`` -- number of vertices. - - ``m`` - number of edges. + - ``m`` -- number of edges. - - ``dense`` - whether to use NetworkX's - dense_gnm_random_graph or gnm_random_graph + - ``dense`` -- whether to use NetworkX's + :func:`dense_gnm_random_graph` or :func:`gnm_random_graph` - ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the random number generator (default: ``None``) @@ -679,16 +681,17 @@ def RandomGNM(n, m, dense=False, seed=None): We show the edge list of a random graph on 5 nodes with 10 edges:: - sage: graphs.RandomGNM(5, 10).edges(sort=True, labels=False) + sage: graphs.RandomGNM(5, 10).edges(sort=True, labels=False) # needs networkx [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] We plot a random graph on 12 nodes with m = 12:: - sage: gnm = graphs.RandomGNM(12, 12) - sage: gnm.show() # long time + sage: gnm = graphs.RandomGNM(12, 12) # needs networkx + sage: gnm.show() # long time # needs networkx sage.plot We view many random graphs using a graphics array:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] sage: for i in range(9): @@ -700,7 +703,7 @@ def RandomGNM(n, m, dense=False, seed=None): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) - sage: G.show() # long time + sage: G.show() # long time """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -737,6 +740,7 @@ def RandomNewmanWattsStrogatz(n, k, p, seed=None): We check that the generated graph contains a cycle of order `n`:: + sage: # needs networkx sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0.2) sage: G.order() 7 @@ -748,22 +752,22 @@ def RandomNewmanWattsStrogatz(n, k, p, seed=None): :: - sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3) - sage: G.show() # long time + sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3) # needs networkx + sage: G.show() # long time # needs networkx sage.plot TESTS: We check that when `k = 2` and `p = 0`, the generated graph is a cycle:: - sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0) - sage: G.is_cycle() + sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0) # needs networkx + sage: G.is_cycle() # needs networkx True We check that when `k = 4` and `p = 0`, the generated graph is a circulant graph of parameters ``[1, 2]``:: - sage: G = graphs.RandomNewmanWattsStrogatz(7, 4, 0) - sage: G.is_isomorphic(graphs.CirculantGraph(7, [1, 2])) + sage: G = graphs.RandomNewmanWattsStrogatz(7, 4, 0) # needs networkx + sage: G.is_isomorphic(graphs.CirculantGraph(7, [1, 2])) # needs networkx True REFERENCE: @@ -807,8 +811,8 @@ def RandomHolmeKim(n, m, p, seed=None): EXAMPLES:: - sage: G = graphs.RandomHolmeKim(12, 3, .3) - sage: G.show() # long time + sage: G = graphs.RandomHolmeKim(12, 3, .3) # needs networkx + sage: G.show() # long time # needs networkx sage.plot REFERENCE: @@ -952,8 +956,8 @@ def connecting_nodes(T, l): sage: from sage.graphs.generators.random import connecting_nodes sage: T = graphs.RandomTree(10) - sage: S = connecting_nodes(T, 5) - sage: len(S) + sage: S = connecting_nodes(T, 5) # needs numpy + sage: len(S) # needs numpy 10 """ from sage.combinat.permutation import Permutations @@ -1178,8 +1182,8 @@ def RandomChordalGraph(n, algorithm="growing", k=None, l=None, f=None, s=None, s sage: T = RandomChordalGraph(20, algorithm="growing", k=5) sage: T.is_chordal() True - sage: T = RandomChordalGraph(20, algorithm="connecting", l=3) - sage: T.is_chordal() + sage: T = RandomChordalGraph(20, algorithm="connecting", l=3) # needs numpy + sage: T.is_chordal() # needs numpy True sage: T = RandomChordalGraph(20, algorithm="pruned", f=1/3, s=.5) sage: T.is_chordal() @@ -1303,6 +1307,7 @@ def RandomLobster(n, p, q, seed=None): We check a random graph with 12 backbone nodes and probabilities `p = 0.7` and `q = 0.3`:: + sage: # needs networkx sage: G = graphs.RandomLobster(12, 0.7, 0.3) sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1] sage: G.delete_vertices(leaves) # caterpillar @@ -1318,8 +1323,8 @@ def RandomLobster(n, p, q, seed=None): :: - sage: G = graphs.RandomLobster(9, .6, .3) - sage: G.show() # long time + sage: G = graphs.RandomLobster(9, .6, .3) # needs networkx + sage: G.show() # long time # needs networkx sage.plot """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1434,17 +1439,17 @@ def RandomTreePowerlaw(n, gamma=3, tries=1000, seed=None): We check that the generated graph is a tree:: - sage: G = graphs.RandomTreePowerlaw(10, 3) - sage: G.is_tree() + sage: G = graphs.RandomTreePowerlaw(10, 3) # needs networkx + sage: G.is_tree() # needs networkx True - sage: G.order(), G.size() + sage: G.order(), G.size() # needs networkx (10, 9) :: - sage: G = graphs.RandomTreePowerlaw(15, 2) - sage: if G: - ....: G.show() # random output, long time + sage: G = graphs.RandomTreePowerlaw(15, 2) # needs networkx + sage: if G: # random output # long time, needs networkx sage.plot + ....: G.show() """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1474,17 +1479,17 @@ def RandomRegular(d, n, seed=None): We check that a random graph with 8 nodes each of degree 3 is 3-regular:: - sage: G = graphs.RandomRegular(3, 8) - sage: G.is_regular(k=3) + sage: G = graphs.RandomRegular(3, 8) # needs networkx + sage: G.is_regular(k=3) # needs networkx True - sage: G.degree_histogram() + sage: G.degree_histogram() # needs networkx [0, 0, 0, 8] :: - sage: G = graphs.RandomRegular(3, 20) - sage: if G: - ....: G.show() # random output, long time + sage: G = graphs.RandomRegular(3, 20) # needs networkx + sage: if G: # random output # long time, needs networkx sage.plot + ....: G.show() REFERENCES: @@ -1524,10 +1529,10 @@ def RandomShell(constructor, seed=None): EXAMPLES:: - sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)]) - sage: G.order(), G.size() + sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)]) # needs networkx + sage: G.order(), G.size() # needs networkx (30, 52) - sage: G.show() # long time + sage: G.show() # long time # needs networkx sage.plot """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1889,7 +1894,7 @@ def RandomTriangulation(n, set_position=False, k=3, seed=None): True sage: G.girth() 3 - sage: G.plot(vertex_size=0, vertex_labels=False) + sage: G.plot(vertex_size=0, vertex_labels=False) # needs sage.plot Graphics object consisting of 13 graphics primitives sage: H = graphs.RandomTriangulation(7, k=5) @@ -2005,16 +2010,16 @@ def blossoming_contour(t, shift=0, seed=None): sage: print(blossoming_contour(BinaryTrees(1).an_element())) [('i', 0), ('xb',), ('i', 0), ('xb',), ('i', 0)] - sage: t = BinaryTrees(2).random_element() - sage: print(blossoming_contour(t)) # random + sage: t = BinaryTrees(2).random_element() # needs sage.combinat + sage: print(blossoming_contour(t)) # random # needs sage.combinat [('i', 0), ('xb',), ('i', 0), ('n', 2), ('i', 1), ('xb',), ('i', 1), ('xb',), ('i', 1), ('n', 2), ('x',), ('n', 2), ('i', 0)] - sage: w = blossoming_contour(BinaryTrees(3).random_element()); len(w) + sage: w = blossoming_contour(BinaryTrees(3).random_element()); len(w) # needs sage.combinat 21 - sage: w.count(('xb',)) + sage: w.count(('xb',)) # needs sage.combinat 4 - sage: w.count(('x',)) + sage: w.count(('x',)) # needs sage.combinat 2 TESTS:: @@ -2098,6 +2103,7 @@ def RandomBicubicPlanar(n, seed=None): EXAMPLES:: + sage: # needs sage.combinat sage: n = randint(200, 300) sage: G = graphs.RandomBicubicPlanar(n) sage: G.order() == 2*n @@ -2106,9 +2112,9 @@ def RandomBicubicPlanar(n, seed=None): True sage: G.is_bipartite() and G.is_planar() and G.is_regular(3) True - sage: dic = {'red':[v for v in G.vertices(sort=False) if v[0] == 'n'], + sage: dic = {'red': [v for v in G.vertices(sort=False) if v[0] == 'n'], ....: 'blue': [v for v in G.vertices(sort=False) if v[0] != 'n']} - sage: G.plot(vertex_labels=False,vertex_size=20,vertex_colors=dic) + sage: G.plot(vertex_labels=False, vertex_size=20, vertex_colors=dic) # needs sage.plot Graphics object consisting of ... graphics primitives .. PLOT:: @@ -2210,6 +2216,7 @@ def RandomUnitDiskGraph(n, radius=.1, side=1, seed=None): When using twice the same seed, the vertices get the same positions:: + sage: # needs scipy sage: from sage.misc.randstate import current_randstate sage: seed = current_randstate().seed() sage: G = graphs.RandomUnitDiskGraph(20, radius=.5, side=1, seed=seed) @@ -2225,8 +2232,8 @@ def RandomUnitDiskGraph(n, radius=.1, side=1, seed=None): When the radius is more than `\sqrt{2 \text{side}}`, the graph is a clique:: - sage: G = graphs.RandomUnitDiskGraph(10, radius=2, side=1) - sage: G.is_clique() + sage: G = graphs.RandomUnitDiskGraph(10, radius=2, side=1) # needs scipy + sage: G.is_clique() # needs scipy True """ if seed is not None: diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 00ce30403bb..a090eb3f73d 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -139,6 +139,7 @@ def HarriesGraph(embedding=1): EXAMPLES:: + sage: # needs networkx sage: g = graphs.HarriesGraph() sage: g.order() 70 @@ -148,12 +149,12 @@ def HarriesGraph(embedding=1): 10 sage: g.diameter() 6 - sage: g.show(figsize=[10, 10]) # long time - sage: graphs.HarriesGraph(embedding=2).show(figsize=[10, 10]) # long time + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot + sage: graphs.HarriesGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot TESTS:: - sage: graphs.HarriesGraph(embedding=3) + sage: graphs.HarriesGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -257,6 +258,7 @@ def HarriesWongGraph(embedding=1): EXAMPLES:: + sage: # needs networkx sage: g = graphs.HarriesWongGraph() sage: g.order() 70 @@ -266,16 +268,16 @@ def HarriesWongGraph(embedding=1): 10 sage: g.diameter() 6 - sage: orbits = g.automorphism_group(orbits=True)[-1] # long time - sage: g.show(figsize=[15, 15], partition=orbits) # long time + sage: orbits = g.automorphism_group(orbits=True)[-1] # long time # needs sage.groups + sage: g.show(figsize=[15, 15], partition=orbits) # long time # needs sage.groups sage.plot Alternative embedding:: - sage: graphs.HarriesWongGraph(embedding=2).show() # long time + sage: graphs.HarriesWongGraph(embedding=2).show() # long time # needs networkx sage.plot TESTS:: - sage: graphs.HarriesWongGraph(embedding=3) + sage: graphs.HarriesWongGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -453,12 +455,13 @@ def Cell600(embedding=1): EXAMPLES:: - sage: g = graphs.Cell600() # long time - sage: g.size() # long time + sage: # long time + sage: g = graphs.Cell600() + sage: g.size() 720 - sage: g.is_regular(12) # long time + sage: g.is_regular(12) True - sage: g.is_vertex_transitive() # long time + sage: g.is_vertex_transitive() True """ from sage.rings.polynomial.polynomial_ring import polygen @@ -528,12 +531,13 @@ def Cell120(): EXAMPLES:: - sage: g = graphs.Cell120() # long time - sage: g.size() # long time + sage: # long time + sage: g = graphs.Cell120() + sage: g.size() 1200 - sage: g.is_regular(4) # long time + sage: g.is_regular(4) True - sage: g.is_vertex_transitive() # long time + sage: g.is_vertex_transitive() True """ from sage.rings.polynomial.polynomial_ring import polygen @@ -679,7 +683,7 @@ def HallJankoGraph(from_string=True): sage: g = graphs.HallJankoGraph() sage: g.is_regular(36) True - sage: g.is_vertex_transitive() + sage: g.is_vertex_transitive() # needs sage.groups True Is it really strongly regular with parameters 14, 12? :: @@ -702,7 +706,7 @@ def HallJankoGraph(from_string=True): 2 sage: g.girth() 3 - sage: factor(g.characteristic_polynomial()) + sage: factor(g.characteristic_polynomial()) # needs sage.libs.pari sage.modules (x - 36) * (x - 6)^36 * (x + 4)^63 TESTS:: @@ -804,6 +808,7 @@ def Balaban10Cage(embedding=1): EXAMPLES:: + sage: # needs networkx sage: g = graphs.Balaban10Cage() sage: g.girth() 10 @@ -811,13 +816,13 @@ def Balaban10Cage(embedding=1): 2 sage: g.diameter() 6 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True - sage: g.show(figsize=[10,10]) # long time + sage: g.show(figsize=[10,10]) # long time # needs sage.plot TESTS:: - sage: graphs.Balaban10Cage(embedding='foo') + sage: graphs.Balaban10Cage(embedding='foo') # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -897,21 +902,21 @@ def Balaban11Cage(embedding=1): 11 sage: g.diameter() 8 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 64 Our many embeddings:: sage: g1 = graphs.Balaban11Cage(embedding=1) - sage: g2 = graphs.Balaban11Cage(embedding=2) - sage: g3 = graphs.Balaban11Cage(embedding=3) - sage: g1.show(figsize=[10,10]) # long time - sage: g2.show(figsize=[10,10]) # long time - sage: g3.show(figsize=[10,10]) # long time + sage: g2 = graphs.Balaban11Cage(embedding=2) # needs networkx + sage: g3 = graphs.Balaban11Cage(embedding=3) # needs networkx + sage: g1.show(figsize=[10,10]) # long time # needs sage.plot + sage: g2.show(figsize=[10,10]) # long time # needs networkx sage.plot + sage: g3.show(figsize=[10,10]) # long time # needs networkx sage.plot Proof that the embeddings are the same graph:: - sage: g1.is_isomorphic(g2) # g2 and g3 are obviously isomorphic + sage: g1.is_isomorphic(g2) # g2 and g3 are obviously isomorphic # needs networkx True TESTS:: @@ -1071,7 +1076,7 @@ def BidiakisCube(): It is a Hamiltonian graph with diameter 3 and girth 4:: - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True sage: g.diameter() 3 @@ -1084,11 +1089,11 @@ def BidiakisCube(): sage: g.is_planar() True - sage: char_poly = g.characteristic_polynomial() - sage: x = char_poly.parent()('x') - sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x - 4)^2 + sage: char_poly = g.characteristic_polynomial() # needs sage.modules + sage: x = char_poly.parent()('x') # needs sage.modules + sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x - 4)^2 # needs sage.modules True - sage: g.chromatic_number() + sage: g.chromatic_number() # needs sage.modules 3 """ edge_dict = { @@ -1114,6 +1119,7 @@ def BiggsSmithGraph(embedding=1): Basic properties:: + sage: # needs networkx sage: g = graphs.BiggsSmithGraph() sage: g.order() 102 @@ -1123,17 +1129,17 @@ def BiggsSmithGraph(embedding=1): 9 sage: g.diameter() 7 - sage: g.automorphism_group().cardinality() # long time + sage: g.automorphism_group().cardinality() # long time 2448 - sage: g.show(figsize=[10, 10]) # long time + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot The other embedding:: - sage: graphs.BiggsSmithGraph(embedding=2).show() # long time + sage: graphs.BiggsSmithGraph(embedding=2).show() # long time # needs networkx TESTS:: - sage: graphs.BiggsSmithGraph(embedding='xyzzy') + sage: graphs.BiggsSmithGraph(embedding='xyzzy') # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -1208,7 +1214,7 @@ def BlanusaFirstSnarkGraph(): 4 sage: g.girth() 5 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 8 """ g = Graph({17: [4, 7, 1], 0: [5], 3: [8], 13: [9], 12: [16], @@ -1243,7 +1249,7 @@ def BlanusaSecondSnarkGraph(): 4 sage: g.girth() 5 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 4 """ c0 = (-1, 0) @@ -1312,15 +1318,15 @@ def BrinkmannGraph(): The Brinkmann graph is also Hamiltonian with chromatic number 4:: - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.chromatic_number() 4 Its automorphism group is isomorphic to `D_7`:: - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(7)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(7)) # needs sage.groups True """ edge_dict = { @@ -1361,18 +1367,17 @@ def BrouwerHaemersGraph(): EXAMPLES:: - sage: g = graphs.BrouwerHaemersGraph() - sage: g + sage: g = graphs.BrouwerHaemersGraph(); g # needs sage.modules Brouwer-Haemers: Graph on 81 vertices It is indeed strongly regular with parameters `(81,20,1,6)`:: - sage: g.is_strongly_regular(parameters=True) # long time + sage: g.is_strongly_regular(parameters=True) # long time # needs sage.modules sage.rings.finite_rings (81, 20, 1, 6) Its has as eigenvalues `20,2` and `-7`:: - sage: set(g.spectrum()) == {20,2,-7} + sage: set(g.spectrum()) == {20,2,-7} # needs sage.modules sage.rings.finite_rings True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -1419,6 +1424,7 @@ def BuckyBall(): The Bucky Ball can also be created by extracting the 1-skeleton of the Bucky Ball polyhedron, but this is much slower:: + sage: # needs sage.geometry.polyhedron sage.rings.number_field sage: g = polytopes.buckyball().vertex_graph() sage: g.remove_loops() sage: h = graphs.BuckyBall() @@ -1428,7 +1434,7 @@ def BuckyBall(): The graph is returned along with an attractive embedding:: sage: g = graphs.BuckyBall() # long time - sage: g.plot(vertex_labels=False, vertex_size=10).show() # long time + sage: g.plot(vertex_labels=False, vertex_size=10).show() # long time, needs sage.plot """ edges = [(0, 2), (0, 48), (0, 59), (1, 3), (1, 9), (1, 58), (2, 3), (2, 36), (3, 17), (4, 6), (4, 8), (4, 12), @@ -1573,11 +1579,11 @@ def DoubleStarSnark(): 45 sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip False - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 80 - sage: g.show() + sage: g.show() # needs sage.plot """ d = {0: [1, 14, 15], 1: [0, 2, 11], @@ -1641,7 +1647,7 @@ def MeredithGraph(): 4 sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() # long time + sage: g.is_hamiltonian() # long time # needs sage.numerical.mip False """ g = Graph(name="Meredith Graph") @@ -1735,12 +1741,13 @@ def CameronGraph(): EXAMPLES:: + sage: # needs sage.groups sage: g = graphs.CameronGraph() sage: g.order() 231 sage: g.size() 3465 - sage: g.is_strongly_regular(parameters = True) # long time + sage: g.is_strongly_regular(parameters=True) # long time (231, 30, 9, 3) """ from sage.groups.perm_gps.permgroup_named import MathieuGroup @@ -1804,9 +1811,9 @@ def ChvatalGraph(): TESTS:: - sage: import networkx + sage: import networkx # needs networkx sage: G = graphs.ChvatalGraph() - sage: G.is_isomorphic(Graph(networkx.chvatal_graph())) + sage: G.is_isomorphic(Graph(networkx.chvatal_graph())) # needs networkx True """ edges = {0: [1, 4, 6, 9], 1: [2, 5, 7], 2: [3, 6, 8], 3: [4, 7, 9], @@ -1828,7 +1835,7 @@ def ClebschGraph(): EXAMPLES:: sage: g = graphs.ClebschGraph() - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 1920 sage: g.girth() 4 @@ -1836,7 +1843,7 @@ def ClebschGraph(): 4 sage: g.diameter() 2 - sage: g.show(figsize=[10, 10]) # long time + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot """ g = Graph(pos={}) x = 0 @@ -1865,7 +1872,7 @@ def CoxeterGraph(): EXAMPLES:: sage: g = graphs.CoxeterGraph() - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 336 sage: g.girth() 7 @@ -1873,7 +1880,7 @@ def CoxeterGraph(): 3 sage: g.diameter() 4 - sage: g.show(figsize=[10, 10]) # long time + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot """ g = Graph({ 27: [6, 22, 14], @@ -1904,11 +1911,11 @@ def DejterGraph(): EXAMPLES:: - sage: g = graphs.DejterGraph(); g + sage: g = graphs.DejterGraph(); g # needs sage.rings.finite_rings Dejter Graph: Graph on 112 vertices - sage: g.is_regular(k=6) + sage: g.is_regular(k=6) # needs sage.rings.finite_rings True - sage: g.girth() + sage: g.girth() # needs sage.rings.finite_rings 4 """ from sage.graphs.generators.families import CubeGraph @@ -1931,10 +1938,10 @@ def DesarguesGraph(): EXAMPLES:: sage: D = graphs.DesarguesGraph() - sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5) - sage: D.is_isomorphic(L) + sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5) # needs networkx + sage: D.is_isomorphic(L) # needs networkx True - sage: D.show() # long time + sage: D.show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph G = GeneralizedPetersenGraph(10, 3) @@ -1973,8 +1980,8 @@ def DurerGraph(): Its automorphism group is isomorphic to `D_6`:: - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(6)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups True """ from sage.graphs.generators.families import GeneralizedPetersenGraph @@ -2012,7 +2019,7 @@ def DyckGraph(): sage: G.is_planar() False - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.is_bipartite() True @@ -2030,12 +2037,12 @@ def DyckGraph(): sage: G.chromatic_number() 2 - sage: G.automorphism_group().cardinality() + sage: G.automorphism_group().cardinality() # needs sage.groups 192 It is a non-integral graph as it has irrational eigenvalues:: - sage: G.characteristic_polynomial().factor() + sage: G.characteristic_polynomial().factor() # needs sage.libs.pari sage.modules (x - 3) * (x + 3) * (x - 1)^9 * (x + 1)^9 * (x^2 - 5)^6 It is a toroidal graph, and its embedding on a torus is dual to an embedding @@ -2085,6 +2092,7 @@ def HortonGraph(): EXAMPLES:: + sage: # needs networkx sage: g = graphs.HortonGraph() sage: g.order() 96 @@ -2100,7 +2108,7 @@ def HortonGraph(): 96 sage: g.chromatic_number() 2 - sage: g.is_hamiltonian() # not tested -- veeeery long + sage: g.is_hamiltonian() # not tested (veeeery long) # needs sage.numerical.mip False """ g = Graph(name="Horton Graph") @@ -2160,14 +2168,14 @@ def EllinghamHorton54Graph(): It is 3-connected and bipartite:: - sage: g.vertex_connectivity() # not tested - too long + sage: g.vertex_connectivity() # not tested - too long 3 sage: g.is_bipartite() True It is not Hamiltonian:: - sage: g.is_hamiltonian() # not tested - too long + sage: g.is_hamiltonian() # not tested # needs sage.numerical.mip False ... and it has a nice drawing :: @@ -2237,23 +2245,23 @@ def EllinghamHorton78Graph(): It is 3-connected and bipartite:: - sage: g.vertex_connectivity() # not tested - too long + sage: g.vertex_connectivity() # not tested (too long) 3 sage: g.is_bipartite() True It is not Hamiltonian:: - sage: g.is_hamiltonian() # not tested - too long + sage: g.is_hamiltonian() # not tested # needs sage.numerical.mip False ... and it has a nice drawing :: - sage: g.show(figsize=[10,10]) # not tested - too long + sage: g.show(figsize=[10,10]) # not tested (too long) TESTS:: - sage: g.show(figsize=[10, 10]) # not tested - too long + sage: g.show(figsize=[10, 10]) # not tested (too long) """ g = Graph({ 0: [1, 5, 60], 1: [2, 12], 2: [3, 7], 3: [4, 14], 4: [5, 9], @@ -2321,7 +2329,7 @@ def ErreraGraph(): The Errera graph is Hamiltonian with radius 3, diameter 4, girth 3, and chromatic number 4:: - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.radius() 3 @@ -2343,8 +2351,8 @@ def ErreraGraph(): The automorphism group of the Errera graph is isomorphic to the dihedral group of order 20:: - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(10)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(10)) # needs sage.groups True """ edge_dict = { @@ -2374,9 +2382,10 @@ def F26AGraph(): EXAMPLES:: + sage: # needs networkx sage: g = graphs.F26AGraph(); g F26A Graph: Graph on 26 vertices - sage: g.order(),g.size() + sage: g.order(), g.size() (26, 39) sage: g.automorphism_group().cardinality() 78 @@ -2435,6 +2444,7 @@ def FolkmanGraph(): EXAMPLES:: + sage: # needs networkx sage: g = graphs.FolkmanGraph() sage: g.order() 20 @@ -2450,7 +2460,7 @@ def FolkmanGraph(): 2 sage: g.is_eulerian() True - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical_mip True sage: g.is_vertex_transitive() False @@ -2471,6 +2481,7 @@ def FosterGraph(): EXAMPLES:: + sage: # needs networkx sage: g = graphs.FosterGraph() sage: g.order() 90 @@ -2482,7 +2493,7 @@ def FosterGraph(): 10 sage: g.automorphism_group().cardinality() 4320 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical_mip True """ from sage.graphs.generators.families import LCFGraph @@ -2514,7 +2525,7 @@ def FranklinGraph(): The Franklin graph is a Hamiltonian, bipartite graph with radius 3, diameter 3, and girth 4:: - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical_mip True sage: G.is_bipartite() True @@ -2570,13 +2581,13 @@ def FruchtGraph(): Frucht graph: Graph on 12 vertices sage: FRUCHT.graph6_string() 'KhCKM?_EGK?L' - sage: (graphs.FruchtGraph()).show() # long time + sage: (graphs.FruchtGraph()).show() # long time # needs networkx TESTS:: - sage: import networkx + sage: import networkx # needs networkx sage: G = graphs.FruchtGraph() - sage: G.is_isomorphic(Graph(networkx.frucht_graph())) + sage: G.is_isomorphic(Graph(networkx.frucht_graph())) # needs networkx True """ edges = {0: [1, 6, 7], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 9], @@ -2624,8 +2635,8 @@ def GoldnerHararyGraph(): sage: G.chromatic_number() 4 - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(6)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups True """ edge_dict = { @@ -2668,11 +2679,12 @@ def GolombGraph(): and 18 edges. It has chromatic number 4, diameter 3, radius 2 and girth 3. It can be drawn in the plane as a unit distance graph:: - sage: G = graphs.GolombGraph(); G + sage: G = graphs.GolombGraph(); G # needs sage.symbolic Golomb graph: Graph on 10 vertices - sage: pos = G.get_pos() - sage: dist2 = lambda u,v:(u[0]-v[0])**2 + (u[1]-v[1])**2 - sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None)) + sage: pos = G.get_pos() # needs sage.symbolic + sage: def dist2(u, v): + ....: return (u[0]-v[0])**2 + (u[1]-v[1])**2 + sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None)) # needs sage.symbolic True """ edge_dict = { @@ -2712,6 +2724,7 @@ def GrayGraph(embedding=1): EXAMPLES:: + sage: # needs networkx sage: g = graphs.GrayGraph() sage: g.order() 54 @@ -2721,12 +2734,12 @@ def GrayGraph(embedding=1): 8 sage: g.diameter() 6 - sage: g.show(figsize=[10, 10]) # long time - sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10]) # long time + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot + sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot TESTS:: - sage: graphs.GrayGraph(embedding=3) + sage: graphs.GrayGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1, 2, or 3 @@ -2761,7 +2774,7 @@ def GrotzschGraph(): sage: G = graphs.GrotzschGraph(); G Grotzsch graph: Graph on 11 vertices - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.order() 11 @@ -2785,8 +2798,8 @@ def GrotzschGraph(): sage: G.chromatic_number() 4 - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(5)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(5)) # needs sage.groups True """ edges = [(0, u) for u in range(1, 6)] @@ -2835,9 +2848,9 @@ def HeawoodGraph(): TESTS:: - sage: import networkx + sage: import networkx # needs networkx sage: G = graphs.HeawoodGraph() - sage: G.is_isomorphic(Graph(networkx.heawood_graph())) + sage: G.is_isomorphic(Graph(networkx.heawood_graph())) # needs networkx True """ edges = {0: [1, 5, 13], 1: [2, 10], 2: [3, 7], 3: [4, 12], 4: [5, 9], @@ -2887,8 +2900,8 @@ def HerschelGraph(): sage: G.chromatic_number() 2 - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(6)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups True """ edge_dict = { @@ -2918,9 +2931,9 @@ def GritsenkoGraph(): EXAMPLES:: - sage: H = graphs.GritsenkoGraph(); H + sage: H = graphs.GritsenkoGraph(); H # needs sage.groups Gritsenko strongly regular graph: Graph on 65 vertices - sage: H.is_strongly_regular(parameters=True) + sage: H.is_strongly_regular(parameters=True) # needs sage.groups (65, 32, 15, 16) """ from sage.groups.perm_gps.permgroup import PermutationGroup @@ -2999,13 +3012,13 @@ def HigmanSimsGraph(relabel=True): which is of index 2 and is simple. It is known as the Higman-Sims group:: sage: H = graphs.HigmanSimsGraph() - sage: G = H.automorphism_group() - sage: g=G.order(); g + sage: G = H.automorphism_group() # needs sage.groups + sage: g = G.order(); g # needs sage.groups 88704000 - sage: K = G.normal_subgroups()[1] - sage: K.is_simple() + sage: K = G.normal_subgroups()[1] # needs sage.groups + sage: K.is_simple() # needs sage.groups True - sage: g//K.order() + sage: g//K.order() # needs sage.groups 2 AUTHOR: @@ -3185,13 +3198,13 @@ def HoffmanGraph(): sage: g = graphs.HoffmanGraph() sage: g.is_bipartite() True - sage: g.is_hamiltonian() # long time + sage: g.is_hamiltonian() # long time # needs sage.numerical.mip True sage: g.radius() 3 sage: g.diameter() 4 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 48 """ g = Graph({ @@ -3230,11 +3243,11 @@ def HoltGraph(): Holt graph: Graph on 27 vertices sage: g.is_regular() True - sage: g.is_vertex_transitive() + sage: g.is_vertex_transitive() # needs sage.groups True sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() # long time + sage: g.is_hamiltonian() # long time # needs sage.numerical.mip True sage: g.radius() 3 @@ -3242,7 +3255,7 @@ def HoltGraph(): 3 sage: g.girth() 5 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 54 """ g = Graph(loops=False, name="Holt graph", pos={}) @@ -3294,9 +3307,9 @@ def KrackhardtKiteGraph(): TESTS:: - sage: import networkx + sage: import networkx # needs networkx sage: G = graphs.KrackhardtKiteGraph() - sage: G.is_isomorphic(Graph(networkx.krackhardt_kite_graph())) + sage: G.is_isomorphic(Graph(networkx.krackhardt_kite_graph())) # needs networkx True """ edges = {0: [1, 2, 3, 5], 1: [3, 4, 6], 2: [3, 5], 3: [4, 5, 6], @@ -3323,7 +3336,7 @@ def Klein3RegularGraph(): (56, 84) sage: g.girth() 7 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 336 sage: g.chromatic_number() 3 @@ -3356,7 +3369,7 @@ def Klein7RegularGraph(): (24, 84) sage: g.girth() 3 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 336 sage: g.chromatic_number() 4 @@ -3381,9 +3394,9 @@ def LocalMcLaughlinGraph(): EXAMPLES:: - sage: g = graphs.LocalMcLaughlinGraph(); g # long time # optional - gap_packages + sage: g = graphs.LocalMcLaughlinGraph(); g # long time, optional - gap_package_design Local McLaughlin Graph: Graph on 162 vertices - sage: g.is_strongly_regular(parameters=True) # long time # optional - gap_packages + sage: g.is_strongly_regular(parameters=True) # long time, optional - gap_package_design (162, 56, 10, 24) """ g = McLaughlinGraph() @@ -3412,6 +3425,7 @@ def LjubljanaGraph(embedding=1): EXAMPLES:: + sage: # needs networkx sage: g = graphs.LjubljanaGraph() sage: g.order() 112 @@ -3421,12 +3435,12 @@ def LjubljanaGraph(embedding=1): 10 sage: g.diameter() 8 - sage: g.show(figsize=[10, 10]) # long time - sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10]) # long time + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot + sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot TESTS:: - sage: graphs.LjubljanaGraph(embedding=3) + sage: graphs.LjubljanaGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -3485,16 +3499,17 @@ def LivingstoneGraph(): EXAMPLES:: - sage: g = graphs.LivingstoneGraph() # optional - internet - sage: g.order() # optional - internet + sage: # optional - internet + sage: g = graphs.LivingstoneGraph() + sage: g.order() 266 - sage: g.size() # optional - internet + sage: g.size() 1463 - sage: g.girth() # optional - internet + sage: g.girth() 5 - sage: g.is_vertex_transitive() # optional - internet + sage: g.is_vertex_transitive() True - sage: g.is_distance_regular() # optional - internet + sage: g.is_distance_regular() True """ from sage.groups.perm_gps.permgroup_named import JankoGroup @@ -3517,12 +3532,13 @@ def M22Graph(): EXAMPLES:: + sage: # needs sage.groups sage: g = graphs.M22Graph() sage: g.order() 77 sage: g.size() 616 - sage: g.is_strongly_regular(parameters = True) + sage: g.is_strongly_regular(parameters=True) (77, 16, 0, 4) """ from sage.groups.perm_gps.permgroup_named import MathieuGroup @@ -3560,11 +3576,11 @@ def MarkstroemGraph(): True sage: g.is_regular(3) True - sage: g.subgraph_search(graphs.CycleGraph(4)) is None + sage: g.subgraph_search(graphs.CycleGraph(4)) is None # needs sage.modules True - sage: g.subgraph_search(graphs.CycleGraph(8)) is None + sage: g.subgraph_search(graphs.CycleGraph(8)) is None # needs sage.modules True - sage: g.subgraph_search(graphs.CycleGraph(16)) + sage: g.subgraph_search(graphs.CycleGraph(16)) # needs sage.modules Subgraph of (Markstroem Graph): Graph on 16 vertices """ g = Graph(name="Markstroem Graph") @@ -3601,6 +3617,7 @@ def McGeeGraph(embedding=2): EXAMPLES:: + sage: # needs networkx sage: g = graphs.McGeeGraph() sage: g.order() 24 @@ -3610,12 +3627,12 @@ def McGeeGraph(embedding=2): 7 sage: g.diameter() 4 - sage: g.show() - sage: graphs.McGeeGraph(embedding=1).show() # long time + sage: g.show() # needs sage.plot + sage: graphs.McGeeGraph(embedding=1).show() # long time # needs sage.plot TESTS:: - sage: graphs.McGeeGraph(embedding=3) + sage: graphs.McGeeGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -3660,10 +3677,10 @@ def McLaughlinGraph(): EXAMPLES:: - sage: g = graphs.McLaughlinGraph() # optional gap_packages - sage: g.is_strongly_regular(parameters=True) # optional gap_packages + sage: g = graphs.McLaughlinGraph() # optional - gap_package_design + sage: g.is_strongly_regular(parameters=True) # optional - gap_package_design (275, 112, 30, 56) - sage: set(g.spectrum()) == {112, 2, -28} # optional gap_packages + sage: set(g.spectrum()) == {112, 2, -28} # optional - gap_package_design True """ from sage.combinat.designs.block_design import WittDesign @@ -3725,7 +3742,7 @@ def MoebiusKantorGraph(): Moebius-Kantor Graph: Graph on 16 vertices sage: MK.graph6_string() 'OhCGKE?O@?ACAC@I?Q_AS' - sage: (graphs.MoebiusKantorGraph()).show() # long time + sage: (graphs.MoebiusKantorGraph()).show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph G = GeneralizedPetersenGraph(8, 3) @@ -3743,6 +3760,7 @@ def MoserSpindle(): The Moser spindle is a planar graph having 7 vertices and 11 edges:: + sage: # needs sage.symbolic sage: G = graphs.MoserSpindle(); G Moser spindle: Graph on 7 vertices sage: G.is_planar() @@ -3754,7 +3772,8 @@ def MoserSpindle(): It is a Hamiltonian graph with radius 2, diameter 2, and girth 3:: - sage: G.is_hamiltonian() + sage: # needs sage.symbolic + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.radius() 2 @@ -3767,6 +3786,7 @@ def MoserSpindle(): has chromatic number 4, and its automorphism group is isomorphic to the dihedral group `D_4`:: + sage: # needs sage.symbolic sage: pos = G.get_pos() sage: all(sum((ui-vi)**2 for ui, vi in zip(pos[u], pos[v])) == 1 ....: for u, v in G.edge_iterator(labels=None)) @@ -3820,8 +3840,8 @@ def NauruGraph(embedding=2): 6 sage: g.diameter() 4 - sage: g.show() - sage: graphs.NauruGraph(embedding=1).show() # long time + sage: g.show() # needs sage.plot + sage: graphs.NauruGraph(embedding=1).show() # long time # needs sage.plot TESTS:: @@ -3829,7 +3849,7 @@ def NauruGraph(embedding=2): Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 - sage: graphs.NauruGraph(embedding=1).is_isomorphic(g) + sage: graphs.NauruGraph(embedding=1).is_isomorphic(g) # needs networkx True """ @@ -3856,10 +3876,10 @@ def PappusGraph(): EXAMPLES:: sage: G = graphs.PappusGraph() - sage: G.show() # long time - sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3) - sage: L.show() # long time - sage: G.is_isomorphic(L) + sage: G.show() # long time # needs sage.plot + sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3) # needs networkx + sage: L.show() # long time # needs networkx sage.plot + sage: G.is_isomorphic(L) # needs networkx True """ edges = {0: [1, 5, 6], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 10], 5: [11], @@ -3922,9 +3942,9 @@ def PetersenGraph(): ....: 3:[2,4,8], 4:[0,3,9], 5:[0,7,8], ....: 6:[1,8,9], 7:[2,5,9], 8:[3,5,6], ....: 9:[4,6,7]}) - sage: petersen_spring.show() # long time + sage: petersen_spring.show() # long time # needs sage.plot sage: petersen_database = graphs.PetersenGraph() - sage: petersen_database.show() # long time + sage: petersen_database.show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph P = GeneralizedPetersenGraph(5, 2) @@ -3969,6 +3989,7 @@ def RobertsonGraph(): EXAMPLES:: + sage: # needs networkx sage: g = graphs.RobertsonGraph() sage: g.order() 19 @@ -3979,10 +4000,11 @@ def RobertsonGraph(): sage: g.girth() 5 sage: g.charpoly().factor() - (x - 4) * (x - 1)^2 * (x^2 + x - 5) * (x^2 + x - 1) * (x^2 - 3)^2 * (x^2 + x - 4)^2 * (x^2 + x - 3)^2 + (x - 4) * (x - 1)^2 * (x^2 + x - 5) * (x^2 + x - 1) + * (x^2 - 3)^2 * (x^2 + x - 4)^2 * (x^2 + x - 3)^2 sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True sage: g.is_vertex_transitive() False @@ -4017,12 +4039,12 @@ def SchlaefliGraph(): Checking that the method actually returns the Schlรคfli graph:: sage: S = graphs.SchlaefliGraph() - sage: S.is_strongly_regular(parameters = True) + sage: S.is_strongly_regular(parameters=True) (27, 16, 10, 8) The graph is vertex-transitive:: - sage: S.is_vertex_transitive() + sage: S.is_vertex_transitive() # needs sage.groups True The neighborhood of each vertex is isomorphic to the complement of the @@ -4077,7 +4099,7 @@ def ShrikhandeGraph(): sage: G.is_planar() False - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.is_eulerian() True @@ -4095,12 +4117,12 @@ def ShrikhandeGraph(): sage: G.chromatic_number() 4 - sage: G.automorphism_group().cardinality() + sage: G.automorphism_group().cardinality() # needs sage.groups 192 It is an integral graph since it has only integral eigenvalues:: - sage: G.characteristic_polynomial().factor() + sage: G.characteristic_polynomial().factor() # needs sage.libs.pari sage.modules (x - 6) * (x - 2)^6 * (x + 2)^9 It is a toroidal graph, and its embedding on a torus is dual to an @@ -4234,12 +4256,12 @@ def SousselierGraph(): 2 sage: g.diameter() 3 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 2 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip False sage: g.delete_vertex(g.random_vertex()) - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True """ g = Graph(name="Sousselier Graph") @@ -4315,7 +4337,7 @@ def ThomsenGraph(): Thomsen graph: Graph on 6 vertices sage: T.graph6_string() 'EFz_' - sage: (graphs.ThomsenGraph()).show() # long time + sage: (graphs.ThomsenGraph()).show() # long time # needs sage.plot """ from sage.graphs.generators.basic import CompleteBipartiteGraph G = CompleteBipartiteGraph(3, 3) @@ -4341,9 +4363,9 @@ def TietzeGraph(): 3 sage: g.girth() 3 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 12 - sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6)) + sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6)) # needs sage.groups True """ g = Graph([(0, 9), (3, 10), (6, 11), (1, 5), (2, 7), (4, 8)], @@ -4368,11 +4390,11 @@ def TruncatedIcosidodecahedralGraph(): Unfortunately, this graph can not be constructed currently, due to numerical issues:: - sage: g = graphs.TruncatedIcosidodecahedralGraph(); g + sage: g = graphs.TruncatedIcosidodecahedralGraph(); g # needs sage.geometry.polyhedron sage.groups sage.rings.number_field Traceback (most recent call last): ... ValueError: *Error: Numerical inconsistency is found. Use the GMP exact arithmetic. - sage: g.order(), g.size() # not tested + sage: g.order(), g.size() # not tested # needs sage.geometry.polyhedron sage.groups sage.rings.number_field (120, 180) """ from sage.geometry.polyhedron.library import polytopes @@ -4395,7 +4417,7 @@ def TruncatedTetrahedralGraph(): Truncated Tetrahedron: Graph on 12 vertices sage: g.order(), g.size() (12, 18) - sage: g.is_isomorphic(polytopes.simplex(3).truncation().graph()) + sage: g.is_isomorphic(polytopes.simplex(3).truncation().graph()) # needs sage.geometry.polyhedron True """ g = Graph(':K`ESwC_EOyDl\\MCi', loops=False, multiedges=False) @@ -4414,6 +4436,7 @@ def Tutte12Cage(): EXAMPLES:: + sage: # needs networkx sage: g = graphs.Tutte12Cage() sage: g.order() 126 @@ -4423,7 +4446,7 @@ def Tutte12Cage(): 12 sage: g.diameter() 6 - sage: g.show() + sage: g.show() # needs sage.plot """ L = [17, 27, -13, -59, -35, 35, -11, 13, -53, 53, -27, 21, 57, 11, -21, -57, 59, -17] @@ -4447,6 +4470,7 @@ def TutteCoxeterGraph(embedding=2): EXAMPLES:: + sage: # needs networkx sage: g = graphs.TutteCoxeterGraph() sage: g.order() 30 @@ -4456,12 +4480,12 @@ def TutteCoxeterGraph(embedding=2): 8 sage: g.diameter() 4 - sage: g.show() - sage: graphs.TutteCoxeterGraph(embedding=1).show() # long time + sage: g.show() # needs sage.plot + sage: graphs.TutteCoxeterGraph(embedding=1).show() # long time # needs sage.plot TESTS:: - sage: graphs.TutteCoxeterGraph(embedding=3) + sage: graphs.TutteCoxeterGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -4514,9 +4538,9 @@ def TutteGraph(): 3 sage: g.girth() 4 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 3 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip False """ g = Graph(name="Tutte Graph") @@ -4560,6 +4584,7 @@ def WagnerGraph(): EXAMPLES:: + sage: # needs networkx sage: g = graphs.WagnerGraph() sage: g.order() 8 @@ -4569,7 +4594,7 @@ def WagnerGraph(): 4 sage: g.diameter() 2 - sage: g.show() + sage: g.show() # needs sage.plot """ from sage.graphs.generators.families import LCFGraph g = LCFGraph(8, [4], 8) @@ -4635,10 +4660,10 @@ def WienerArayaGraph(): 4 sage: g.is_planar() True - sage: g.is_hamiltonian() # not tested -- around 30s long + sage: g.is_hamiltonian() # not tested (30s) # needs sage.numerical.mip False sage: g.delete_vertex(g.random_vertex()) - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True """ g = Graph(name="Wiener-Araya Graph") @@ -4693,7 +4718,7 @@ def _EllipticLinesProjectivePlaneScheme(k): TESTS:: sage: from sage.graphs.generators.smallgraphs import _EllipticLinesProjectivePlaneScheme - sage: _EllipticLinesProjectivePlaneScheme(2) + sage: _EllipticLinesProjectivePlaneScheme(2) # needs sage.libs.gap [ [1 0 0 0 0 0] [0 1 1 1 1 0] [0 0 0 0 0 1] [0 1 0 0 0 0] [1 0 1 1 0 1] [0 0 0 0 1 0] @@ -4736,11 +4761,12 @@ def MathonStronglyRegularGraph(t): TESTS:: - sage: G = graphs.MathonStronglyRegularGraph(1) # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: # long time + sage: G = graphs.MathonStronglyRegularGraph(1) + sage: G.is_strongly_regular(parameters=True) (784, 270, 98, 90) - sage: G = graphs.MathonStronglyRegularGraph(2) # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: G = graphs.MathonStronglyRegularGraph(2) + sage: G.is_strongly_regular(parameters=True) (784, 297, 116, 110) """ @@ -5007,12 +5033,12 @@ def IoninKharaghani765Graph(): EXAMPLES:: - sage: g = graphs.IoninKharaghani765Graph(); g + sage: g = graphs.IoninKharaghani765Graph(); g # needs sage.modules sage.rings.finite_rings Ionin-Kharaghani: Graph on 765 vertices TESTS:: - sage: graphs.strongly_regular_graph(765, 192, 48, 48) + sage: graphs.strongly_regular_graph(765, 192, 48, 48) # needs sage.modules sage.rings.finite_rings Ionin-Kharaghani: Graph on 765 vertices .. TODO:: @@ -5103,8 +5129,8 @@ def U42Graph216(): EXAMPLES:: - sage: G=graphs.U42Graph216() # optional - gap_packages (grape) - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) + sage: G=graphs.U42Graph216() # optional - gap_package_grape + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_grape (216, 40, 4, 8) """ from sage.libs.gap.libgap import libgap @@ -5150,8 +5176,8 @@ def U42Graph540(): EXAMPLES:: - sage: G=graphs.U42Graph540() # optional - gap_packages (grape) - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) + sage: G = graphs.U42Graph540() # optional - gap_package_grape + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_grape (540, 187, 58, 68) """ from sage.libs.gap.libgap import libgap diff --git a/src/sage/graphs/generators/world_map.py b/src/sage/graphs/generators/world_map.py index 42d0a95372f..76c32335f60 100644 --- a/src/sage/graphs/generators/world_map.py +++ b/src/sage/graphs/generators/world_map.py @@ -95,7 +95,7 @@ def AfricaMap(continental=False, year=2018): G = Graph(common_border, format='dict_of_lists') if continental: - G = G.subgraph(G.connected_component_containing_vertex('Central Africa')) + G = G.subgraph(G.connected_component_containing_vertex('Central Africa', sort=False)) G.name(new="Continental Africa Map") else: G.add_vertices(no_land_border) @@ -172,7 +172,7 @@ def EuropeMap(continental=False, year=2018): G = Graph(common_border, format='dict_of_lists') if continental: - G = G.subgraph(G.connected_component_containing_vertex('Austria')) + G = G.subgraph(G.connected_component_containing_vertex('Austria', sort=False)) G.name(new="Continental Europe Map") else: G.add_vertices(no_land_border) @@ -308,7 +308,7 @@ def WorldMap(): True sage: g.gps_coordinates["Bolivia"] [[17, 'S'], [65, 'W']] - sage: sorted(g.connected_component_containing_vertex('Ireland')) + sage: g.connected_component_containing_vertex('Ireland', sort=True) ['Ireland', 'United Kingdom'] TESTS: diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 38e1f8d5751..66703a0f7c1 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -421,7 +421,7 @@ # 2018 Erik M. Bray <erik.bray@lri.fr> # Meghana M Reddy <mreddymeghana@gmail.com> # 2019 Rajat Mittal <rajat.mttl@gmail.com> -# 2020 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# 2020 Jonathan Kliem <jonathan.kliem@gmail.com> # # 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 @@ -439,16 +439,16 @@ from sage.misc.decorators import options from sage.misc.cachefunc import cached_method from sage.misc.prandom import random -from sage.misc.superseded import deprecation -from sage.misc.lazy_import import LazyImport +from sage.misc.lazy_import import lazy_import, LazyImport from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer from sage.rings.rational import Rational -from sage.matrix.constructor import matrix from sage.rings.rational_field import QQ from sage.features.igraph import python_igraph as igraph_feature +lazy_import('sage.matrix.constructor', 'matrix') + to_hex = LazyImport('matplotlib.colors', 'to_hex') @@ -615,6 +615,38 @@ def __eq__(self, other): return self._backend.is_subgraph(other._backend, self, ignore_labels=not self.weighted()) + def _use_labels_for_hash(self): + r""" + Helper method for method ``__hash__``. + + This method checks whether parameter ``hash_labels`` has been specified + by the user. Otherwise, defaults to the value of parameter ``weigthed``. + + TESTS:: + + sage: G = Graph() + sage: G._use_labels_for_hash() + False + sage: G = Graph(hash_labels=True) + sage: G._use_labels_for_hash() + True + sage: G = Graph(hash_labels=False) + sage: G._use_labels_for_hash() + False + sage: G = Graph(weighted=True) + sage: G._use_labels_for_hash() + True + sage: G = Graph(weighted=False) + sage: G._use_labels_for_hash() + False + sage: G = Graph(hash_labels=False, weighted=True) + sage: G._use_labels_for_hash() + False + """ + if not hasattr(self, "_hash_labels") or self._hash_labels is None: + self._hash_labels = self.weighted() + return self._hash_labels + @cached_method def __hash__(self): """ @@ -685,9 +717,29 @@ def __hash__(self): sage: G1.__hash__() == G2.__hash__() True + Make sure ``hash_labels`` parameter behaves as expected + (:trac:`33255`):: + + sage: A = Graph([(1, 2, 1)], immutable=True) + sage: B = Graph([(1, 2, 33)], immutable=True) + sage: A.__hash__() == B.__hash__() + True + sage: A = Graph([(1, 2, 1)], immutable=True, hash_labels=True) + sage: B = Graph([(1, 2, 33)], immutable=True, hash_labels=True) + sage: A.__hash__() == B.__hash__() + False + sage: A = Graph([(1, 2, 1)], immutable=True, weighted=True) + sage: B = Graph([(1, 2, 33)], immutable=True, weighted=True) + sage: A.__hash__() == B.__hash__() + False + sage: A = Graph([(1, 2, 1)], immutable=True, hash_labels=False, weighted=True) + sage: B = Graph([(1, 2, 33)], immutable=True, hash_labels=False, weighted=True) + sage: A.__hash__() == B.__hash__() + True """ if self.is_immutable(): - edge_items = self.edge_iterator(labels=self._weighted) + use_labels = self._use_labels_for_hash() + edge_items = self.edge_iterator(labels=use_labels) if self.allows_multiple_edges(): from collections import Counter edge_items = Counter(edge_items).items() @@ -856,7 +908,7 @@ def _latex_(self): sage: from sage.graphs.graph_latex import check_tkz_graph sage: check_tkz_graph() # random - depends on TeX installation sage: g = graphs.CompleteGraph(2) - sage: print(g._latex_()) + sage: print(g._latex_()) # needs sage.plot \begin{tikzpicture} \definecolor{cv0}{rgb}{0.0,0.0,0.0} \definecolor{cfv0}{rgb}{1.0,1.0,1.0} @@ -893,21 +945,21 @@ def _matrix_(self, R=None, vertices=None): EXAMPLES:: sage: G = graphs.CompleteBipartiteGraph(2, 3) - sage: m = matrix(G); m.parent() + sage: m = matrix(G); m.parent() # needs sage.modules Full MatrixSpace of 5 by 5 dense matrices over Integer Ring - sage: m + sage: m # needs sage.modules [0 0 1 1 1] [0 0 1 1 1] [1 1 0 0 0] [1 1 0 0 0] [1 1 0 0 0] - sage: G._matrix_() + sage: G._matrix_() # needs sage.modules [0 0 1 1 1] [0 0 1 1 1] [1 1 0 0 0] [1 1 0 0 0] [1 1 0 0 0] - sage: factor(m.charpoly()) + sage: factor(m.charpoly()) # needs sage.modules x^3 * (x^2 - 6) """ return self.am(vertices=vertices, base_ring=R) @@ -955,7 +1007,7 @@ def is_immutable(self): # Formats - def copy(self, weighted=None, data_structure=None, sparse=None, immutable=None): + def copy(self, weighted=None, data_structure=None, sparse=None, immutable=None, hash_labels=None): """ Change the graph implementation @@ -985,6 +1037,12 @@ def copy(self, weighted=None, data_structure=None, sparse=None, immutable=None): used to copy an immutable graph, the data structure used is ``"sparse"`` unless anything else is specified. + - ``hash_labels`` -- boolean (default: ``None``); whether to include + edge labels during hashing of the copy. This parameter defaults to + ``True`` if the graph is weighted. This parameter is ignored when + parameter ``immutable`` is not ``True``. + Beware that trying to hash unhashable labels will raise an error. + .. NOTE:: If the graph uses @@ -1141,6 +1199,43 @@ def copy(self, weighted=None, data_structure=None, sparse=None, immutable=None): sage: G._immutable = True sage: G.copy()._backend <sage.graphs.base.sparse_graph.SparseGraphBackend object at ...> + + Copying and changing ``hash_labels`` parameter:: + + sage: G = Graph({0: {1: 'edge label A'}}, immutable=True, hash_labels=False) + sage: hash(G.copy(hash_labels=True, immutable=True)) == hash(G) + False + sage: hash(G.copy(hash_labels=False, immutable=True)) == hash(G) + True + sage: hash(G.copy(hash_labels=None, immutable=True)) == hash(G) + True + sage: G = Graph({0: {1: 'edge label A'}}, immutable=True, hash_labels=True) + sage: hash(G.copy(hash_labels=True, immutable=True)) == hash(G) + True + sage: hash(G.copy(hash_labels=False, immutable=True)) == hash(G) + False + sage: hash(G.copy(hash_labels=None, immutable=True)) == hash(G) + True + sage: G1 = Graph({0: {1: 'edge label A'}}, immutable=True, hash_labels=False) + sage: G2 = Graph({0: {1: 'edge label B'}}, immutable=True, hash_labels=False) + sage: hash(G1) == hash(G2) + True + sage: G1c = G1.copy(hash_labels=True, immutable=True) + sage: G2c = G2.copy(hash_labels=True, immutable=True) + sage: hash(G1c) == hash(G2c) + False + sage: G = Graph({0: {1: 'edge label A'}}, immutable=True, hash_labels=False) + sage: H = G.copy(hash_labels=True) + sage: H.is_immutable() + False + sage: H._hash_labels + True + sage: I = H.copy(immutable=True) + sage: hash(G) == hash(I) + False + sage: G = Graph({0: {1: 'edge label A'}}, immutable=True, hash_labels=True) + sage: hash(G) == hash(I) + True """ # Which data structure should be used ? if data_structure is not None: @@ -1169,7 +1264,8 @@ def copy(self, weighted=None, data_structure=None, sparse=None, immutable=None): # Immutable copy of an immutable graph ? return self ! # (if okay for weightedness) if (self.is_immutable() and - (weighted is None or self._weighted == weighted)): + (weighted is None or self._weighted == weighted) and + (hash_labels is None or self._hash_labels == hash_labels)): from sage.graphs.base.static_sparse_backend import StaticSparseBackend if (isinstance(self._backend, StaticSparseBackend) and (data_structure == 'static_sparse' or data_structure is None)): @@ -1183,7 +1279,7 @@ def copy(self, weighted=None, data_structure=None, sparse=None, immutable=None): data_structure = "sparse" G = self.__class__(self, name=self.name(), pos=copy(self._pos), - weighted=weighted, + weighted=weighted, hash_labels=hash_labels, data_structure=data_structure) attributes_to_copy = ('_assoc', '_embedding') @@ -1272,24 +1368,24 @@ def export_to_file(self, filename, format=None, **kwds): sage: g = graphs.PetersenGraph() sage: filename = tmp_filename(ext=".pajek") - sage: g.export_to_file(filename) - sage: import networkx - sage: G_networkx = networkx.read_pajek(filename) - sage: Graph(G_networkx).is_isomorphic(g) + sage: g.export_to_file(filename) # needs networkx + sage: import networkx # needs networkx + sage: G_networkx = networkx.read_pajek(filename) # needs networkx + sage: Graph(G_networkx).is_isomorphic(g) # needs networkx True sage: filename = tmp_filename(ext=".edgelist") - sage: g.export_to_file(filename, data=False) - sage: h = Graph(networkx.read_edgelist(filename)) - sage: g.is_isomorphic(h) + sage: g.export_to_file(filename, data=False) # needs networkx + sage: h = Graph(networkx.read_edgelist(filename)) # needs networkx + sage: g.is_isomorphic(h) # needs networkx True TESTS:: - sage: g.export_to_file("hey", format="When I feel heavy metaaaaaallll...") + sage: g.export_to_file("hey", format="When I feel heavy metaaaaaallll...") # needs networkx Traceback (most recent call last): ... ValueError: format 'When I feel heavy metaaaaaallll...' unknown - sage: g.export_to_file("my_file.Yeeeeppeeeeee") + sage: g.export_to_file("my_file.Yeeeeppeeeeee") # needs networkx Traceback (most recent call last): ... RuntimeError: the file format could not be guessed from 'my_file.Yeeeeppeeeeee' @@ -1411,20 +1507,24 @@ def networkx_graph(self, weight_function=None): EXAMPLES:: sage: G = graphs.TetrahedralGraph() - sage: N = G.networkx_graph() - sage: type(N) + sage: N = G.networkx_graph() # needs networkx + sage: type(N) # needs networkx <class 'networkx.classes.graph.Graph'> sage: def weight_fn(e): ....: return e[2] sage: G1 = Graph([(1,2,1), (1,3,4), (2,3,3), (3,4,4)]) - sage: H = G1.networkx_graph(weight_function=weight_fn) - sage: H.edges(data=True) - EdgeDataView([(1, 2, {'weight': 1}), (1, 3, {'weight': 4}), (2, 3, {'weight': 3}), (3, 4, {'weight': 4})]) - sage: G2 = DiGraph([(1,2,1), (1,3,4), (2,3,3), (3,4,4), (3,4,5)], multiedges=True) - sage: H = G2.networkx_graph(weight_function=weight_fn) - sage: H.edges(data=True) - OutMultiEdgeDataView([(1, 2, {'weight': 1}), (1, 3, {'weight': 4}), (2, 3, {'weight': 3}), (3, 4, {'weight': 5}), (3, 4, {'weight': 4})]) + sage: H = G1.networkx_graph(weight_function=weight_fn) # needs networkx + sage: H.edges(data=True) # needs networkx + EdgeDataView([(1, 2, {'weight': 1}), (1, 3, {'weight': 4}), + (2, 3, {'weight': 3}), (3, 4, {'weight': 4})]) + sage: G2 = DiGraph([(1,2,1), (1,3,4), (2,3,3), (3,4,4), (3,4,5)], + ....: multiedges=True) + sage: H = G2.networkx_graph(weight_function=weight_fn) # needs networkx + sage: H.edges(data=True) # needs networkx + OutMultiEdgeDataView([(1, 2, {'weight': 1}), (1, 3, {'weight': 4}), + (2, 3, {'weight': 3}), (3, 4, {'weight': 5}), + (3, 4, {'weight': 4})]) """ if weight_function is not None: @@ -1609,9 +1709,20 @@ def igraph_graph(self, vertex_list=None, vertex_attrs={}, edge_attrs={}): True sage: G.edges(sort=True) == H.edges(sort=True) # optional - python_igraph False + + Check input parameter ``vertex_list``:: + + sage: G = Graph(3) + sage: G.igraph_graph(vertex_list=[]) # optional - python_igraph + Traceback (most recent call last): + ... + ValueError: parameter vertex_list must be a permutation of the vertices """ if vertex_list is None: - vertex_list = self.vertices(sort=False) + vertex_list = self + elif (len(vertex_list) != self.order() or + set(vertex_list) != set(self)): + raise ValueError("parameter vertex_list must be a permutation of the vertices") v_to_int = {v: i for i, v in enumerate(vertex_list)} edges = [(v_to_int[v], v_to_int[w]) for v, w in self.edge_iterator(labels=False)] @@ -1799,6 +1910,9 @@ def adjacency_matrix(self, sparse=None, vertices=None, *, base_ring=None, **kwds the vertices defining how they should appear in the matrix. By default, the ordering given by :meth:`GenericGraph.vertices` with ``sort=True`` is used. + If the vertices are not comparable, the keyword ``vertices`` must be + used to specify an ordering, or a :class:`TypeError` exception will + be raised. - ``base_ring`` -- a ring (default: ``ZZ``); the base ring of the matrix space to use. @@ -1809,7 +1923,7 @@ def adjacency_matrix(self, sparse=None, vertices=None, *, base_ring=None, **kwds EXAMPLES:: sage: G = graphs.CubeGraph(4) - sage: G.adjacency_matrix() + sage: G.adjacency_matrix() # needs sage.modules [0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0] [1 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0] [1 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0] @@ -1829,7 +1943,7 @@ def adjacency_matrix(self, sparse=None, vertices=None, *, base_ring=None, **kwds :: - sage: matrix(GF(2),G) # matrix over GF(2) + sage: matrix(GF(2), G) # matrix over GF(2) # needs sage.modules sage.rings.finite_rings [0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0] [1 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0] [1 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0] @@ -1849,8 +1963,9 @@ def adjacency_matrix(self, sparse=None, vertices=None, *, base_ring=None, **kwds :: - sage: D = DiGraph({0: [1, 2, 3], 1: [0, 2], 2: [3], 3: [4], 4: [0, 5], 5: [1]}) - sage: D.adjacency_matrix() + sage: D = DiGraph({0: [1, 2, 3], 1: [0, 2], 2: [3], + ....: 3: [4], 4: [0, 5], 5: [1]}) + sage: D.adjacency_matrix() # needs sage.modules [0 1 1 1 0 0] [1 0 1 0 0 0] [0 0 0 1 0 0] @@ -1860,7 +1975,7 @@ def adjacency_matrix(self, sparse=None, vertices=None, *, base_ring=None, **kwds A different ordering of the vertices:: - sage: graphs.PathGraph(5).adjacency_matrix(vertices=[2, 4, 1, 3, 0]) + sage: graphs.PathGraph(5).adjacency_matrix(vertices=[2, 4, 1, 3, 0]) # needs sage.modules [0 0 1 1 0] [0 0 0 1 0] [1 0 0 0 1] @@ -1869,18 +1984,19 @@ def adjacency_matrix(self, sparse=None, vertices=None, *, base_ring=None, **kwds A different base ring:: - sage: graphs.PathGraph(5).adjacency_matrix(base_ring=RDF) + sage: graphs.PathGraph(5).adjacency_matrix(base_ring=RDF) # needs sage.modules [0.0 1.0 0.0 0.0 0.0] [1.0 0.0 1.0 0.0 0.0] [0.0 1.0 0.0 1.0 0.0] [0.0 0.0 1.0 0.0 1.0] [0.0 0.0 0.0 1.0 0.0] - sage: type(_) + sage: type(_) # needs sage.modules <class 'sage.matrix.matrix_real_double_dense.Matrix_real_double_dense'> A different matrix implementation:: - sage: graphs.PathGraph(5).adjacency_matrix(sparse=False, implementation='numpy') + sage: graphs.PathGraph(5).adjacency_matrix(sparse=False, # needs sage.modules + ....: implementation='numpy') [0 1 0 0 0] [1 0 1 0 0] [0 1 0 1 0] @@ -1891,33 +2007,44 @@ def adjacency_matrix(self, sparse=None, vertices=None, *, base_ring=None, **kwds As an immutable matrix:: - sage: M = graphs.PathGraph(5).adjacency_matrix(sparse=False, immutable=True); M + sage: M = graphs.PathGraph(5).adjacency_matrix(sparse=False, # needs sage.modules + ....: immutable=True); M [0 1 0 0 0] [1 0 1 0 0] [0 1 0 1 0] [0 0 1 0 1] [0 0 0 1 0] - sage: M[2, 2] = 1 + sage: M[2, 2] = 1 # needs sage.modules Traceback (most recent call last): ... - ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M). + ValueError: matrix is immutable; please change a copy instead + (i.e., use copy(M) to change a copy of M). TESTS:: - sage: graphs.CubeGraph(8).adjacency_matrix().parent() + sage: graphs.CubeGraph(8).adjacency_matrix().parent() # needs sage.modules Full MatrixSpace of 256 by 256 dense matrices over Integer Ring - sage: graphs.CubeGraph(9).adjacency_matrix().parent() + sage: graphs.CubeGraph(9).adjacency_matrix().parent() # needs sage.modules Full MatrixSpace of 512 by 512 sparse matrices over Integer Ring - sage: Graph([(i,i+1) for i in range(500)]+[(0,1),], multiedges=True).adjacency_matrix().parent() + sage: Graph([(i, i+1) for i in range(500)] + [(0,1),], # needs sage.modules + ....: multiedges=True).adjacency_matrix().parent() Full MatrixSpace of 501 by 501 dense matrices over Integer Ring - sage: graphs.PathGraph(5).adjacency_matrix(vertices=[0,0,0,0,0]) + sage: graphs.PathGraph(5).adjacency_matrix(vertices=[0,0,0,0,0]) # needs sage.modules + Traceback (most recent call last): + ... + ValueError: parameter vertices must be a permutation of the vertices + sage: graphs.PathGraph(5).adjacency_matrix(vertices=[1,2,3]) # needs sage.modules Traceback (most recent call last): ... - ValueError: ``vertices`` must be a permutation of the vertices - sage: graphs.PathGraph(5).adjacency_matrix(vertices=[1,2,3]) + ValueError: parameter vertices must be a permutation of the vertices + sage: Graph ([[0, 42, 'John'], [(42, 'John')]]).adjacency_matrix() Traceback (most recent call last): ... - ValueError: ``vertices`` must be a permutation of the vertices + TypeError: Vertex labels are not comparable. You must specify an ordering using parameter ``vertices`` + sage: Graph ([[0, 42, 'John'], [(42, 'John')]]).adjacency_matrix(vertices=['John', 42, 0]) + [0 1 0] + [1 0 0] + [0 0 0] """ n = self.order() if sparse is None: @@ -1926,10 +2053,15 @@ def adjacency_matrix(self, sparse=None, vertices=None, *, base_ring=None, **kwds sparse = False if vertices is None: - vertices = self.vertices(sort=True) + try: + vertices = self.vertices(sort=True) + except TypeError: + raise TypeError("Vertex labels are not comparable. You must " + "specify an ordering using parameter " + "``vertices``") elif (len(vertices) != n or set(vertices) != set(self.vertex_iterator())): - raise ValueError("``vertices`` must be a permutation of the vertices") + raise ValueError("parameter vertices must be a permutation of the vertices") new_indices = {v: i for i, v in enumerate(vertices)} D = {} @@ -2008,7 +2140,7 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None EXAMPLES:: sage: G = graphs.PetersenGraph() - sage: G.incidence_matrix() + sage: G.incidence_matrix() # needs sage.modules [1 1 1 0 0 0 0 0 0 0 0 0 0 0 0] [1 0 0 1 1 0 0 0 0 0 0 0 0 0 0] [0 0 0 1 0 1 1 0 0 0 0 0 0 0 0] @@ -2019,7 +2151,7 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None [0 0 0 0 0 0 1 0 0 0 1 0 0 0 1] [0 0 0 0 0 0 0 0 1 0 0 1 1 0 0] [0 0 0 0 0 0 0 0 0 1 0 0 0 1 1] - sage: G.incidence_matrix(oriented=True) + sage: G.incidence_matrix(oriented=True) # needs sage.modules [-1 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0] [ 1 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0] [ 0 0 0 1 0 -1 -1 0 0 0 0 0 0 0 0] @@ -2032,18 +2164,18 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None [ 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1] sage: G = digraphs.Circulant(4, [1, 3]) - sage: G.incidence_matrix() + sage: G.incidence_matrix() # needs sage.modules [-1 -1 1 0 0 0 1 0] [ 1 0 -1 -1 1 0 0 0] [ 0 0 0 1 -1 -1 0 1] [ 0 1 0 0 0 1 -1 -1] - sage: graphs.CompleteGraph(3).incidence_matrix() + sage: graphs.CompleteGraph(3).incidence_matrix() # needs sage.modules [1 1 0] [1 0 1] [0 1 1] sage: G = Graph([(0, 0), (0, 1), (0, 1)], loops=True, multiedges=True) - sage: G.incidence_matrix(oriented=False) + sage: G.incidence_matrix(oriented=False) # needs sage.modules [2 1 1] [0 1 1] @@ -2052,30 +2184,30 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None Kirchhoff matrix:: sage: G = graphs.PetersenGraph() - sage: m = G.incidence_matrix(oriented=True) - sage: m * m.transpose() == G.kirchhoff_matrix() + sage: m = G.incidence_matrix(oriented=True) # needs sage.modules + sage: m * m.transpose() == G.kirchhoff_matrix() # needs sage.modules True sage: K = graphs.CompleteGraph(3) - sage: m = K.incidence_matrix(oriented=True) - sage: m * m.transpose() == K.kirchhoff_matrix() + sage: m = K.incidence_matrix(oriented=True) # needs sage.modules + sage: m * m.transpose() == K.kirchhoff_matrix() # needs sage.modules True sage: H = Graph([(0, 0), (0, 1), (0, 1)], loops=True, multiedges=True) - sage: m = H.incidence_matrix(oriented=True) - sage: m * m.transpose() == H.kirchhoff_matrix() + sage: m = H.incidence_matrix(oriented=True) # needs sage.modules + sage: m * m.transpose() == H.kirchhoff_matrix() # needs sage.modules True A different ordering of the vertices:: sage: P5 = graphs.PathGraph(5) - sage: P5.incidence_matrix() + sage: P5.incidence_matrix() # needs sage.modules [1 0 0 0] [1 1 0 0] [0 1 1 0] [0 0 1 1] [0 0 0 1] - sage: P5.incidence_matrix(vertices=[2, 4, 1, 3, 0]) + sage: P5.incidence_matrix(vertices=[2, 4, 1, 3, 0]) # needs sage.modules [0 1 1 0] [0 0 0 1] [1 1 0 0] @@ -2085,13 +2217,13 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None A different ordering of the edges:: sage: E = list(P5.edge_iterator(labels=False)) - sage: P5.incidence_matrix(edges=E[::-1]) + sage: P5.incidence_matrix(edges=E[::-1]) # needs sage.modules [0 0 0 1] [0 0 1 1] [0 1 1 0] [1 1 0 0] [1 0 0 0] - sage: P5.incidence_matrix(vertices=[2, 4, 1, 3, 0], edges=E[::-1]) + sage: P5.incidence_matrix(vertices=[2, 4, 1, 3, 0], edges=E[::-1]) # needs sage.modules [0 1 1 0] [1 0 0 0] [0 0 1 1] @@ -2100,7 +2232,7 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None A different base ring:: - sage: P5.incidence_matrix(base_ring=RDF) + sage: P5.incidence_matrix(base_ring=RDF) # needs sage.modules [1.0 0.0 0.0 0.0] [1.0 1.0 0.0 0.0] [0.0 1.0 1.0 0.0] @@ -2109,29 +2241,30 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None Creating an immutable matrix:: - sage: m = P5.incidence_matrix(immutable=True); m + sage: m = P5.incidence_matrix(immutable=True); m # needs sage.modules [1 0 0 0] [1 1 0 0] [0 1 1 0] [0 0 1 1] [0 0 0 1] - sage: m[1,2] = 1 + sage: m[1,2] = 1 # needs sage.modules Traceback (most recent call last): ... - ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M). + ValueError: matrix is immutable; please change a copy instead + (i.e., use copy(M) to change a copy of M). TESTS:: sage: P5 = graphs.PathGraph(5) - sage: P5.incidence_matrix(vertices=[1] * P5.order()) + sage: P5.incidence_matrix(vertices=[1] * P5.order()) # needs sage.modules Traceback (most recent call last): ... - ValueError: ``vertices`` must be a permutation of the vertices - sage: P5.incidence_matrix(edges=[(0, 1)] * P5.size()) + ValueError: parameter vertices must be a permutation of the vertices + sage: P5.incidence_matrix(edges=[(0, 1)] * P5.size()) # needs sage.modules Traceback (most recent call last): ... - ValueError: ``edges`` must be a permutation of the edges - sage: P5.incidence_matrix(edges=P5.edges(sort=False, labels=True)) + ValueError: parameter edges must be a permutation of the edges + sage: P5.incidence_matrix(edges=P5.edges(sort=False, labels=True)) # needs sage.modules [1 0 0 0] [1 1 0 0] [0 1 1 0] @@ -2145,13 +2278,13 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None vertices = self.vertices(sort=False) elif (len(vertices) != self.num_verts() or set(vertices) != set(self.vertex_iterator())): - raise ValueError("``vertices`` must be a permutation of the vertices") + raise ValueError("parameter vertices must be a permutation of the vertices") verts = {v: i for i, v in enumerate(vertices)} if edges is None: edges = self.edge_iterator(labels=False) elif len(edges) != self.size(): - raise ValueError("``edges`` must be a permutation of the edges") + raise ValueError("parameter edges must be a permutation of the edges") else: # We check that we have the same set of unlabeled edges if oriented: @@ -2163,7 +2296,7 @@ def reorder(u, v): i_edges = [reorder(verts[e[0]], verts[e[1]]) for e in edges] s_edges = [reorder(verts[u], verts[v]) for u, v in self.edge_iterator(labels=False)] if sorted(i_edges) != sorted(s_edges): - raise ValueError("``edges`` must be a permutation of the edges") + raise ValueError("parameter edges must be a permutation of the edges") from sage.matrix.constructor import matrix if base_ring is None: @@ -2220,19 +2353,19 @@ def distance_matrix(self, vertices=None, *, base_ring=None, **kwds): EXAMPLES:: sage: d = DiGraph({1: [2, 3], 2: [3], 3: [4], 4: [1]}) - sage: d.distance_matrix() + sage: d.distance_matrix() # needs sage.modules [0 1 1 2] [3 0 1 2] [2 3 0 1] [1 2 2 0] - sage: d.distance_matrix(vertices=[4, 3, 2, 1]) + sage: d.distance_matrix(vertices=[4, 3, 2, 1]) # needs sage.modules [0 2 2 1] [1 0 3 2] [2 1 0 3] [2 1 1 0] sage: G = graphs.CubeGraph(3) - sage: G.distance_matrix() + sage: G.distance_matrix() # needs sage.modules [0 1 1 2 1 2 2 3] [1 0 2 1 2 1 3 2] [1 2 0 1 2 3 1 2] @@ -2246,7 +2379,8 @@ def distance_matrix(self, vertices=None, *, base_ring=None, **kwds): of the distance matrix of any tree of order `n` is `(-1)^{n-1}(n-1)2^{n-2}`:: - sage: all(T.distance_matrix().det() == (-1)^9*(9)*2^8 for T in graphs.trees(10)) + sage: all(T.distance_matrix().det() == (-1)^9*(9)*2^8 # needs sage.modules + ....: for T in graphs.trees(10)) True .. SEEALSO:: @@ -2259,18 +2393,18 @@ def distance_matrix(self, vertices=None, *, base_ring=None, **kwds): Asking for an immutable matrix:: sage: G = Graph([(0, 1)]) - sage: G.distance_matrix().is_immutable() + sage: G.distance_matrix().is_immutable() # needs sage.modules False - sage: G.distance_matrix(immutable=True).is_immutable() + sage: G.distance_matrix(immutable=True).is_immutable() # needs sage.modules True Specifying a base ring:: sage: G = Graph([(0, 1)]) - sage: G.distance_matrix(vertices=[0, 1], base_ring=ZZ) + sage: G.distance_matrix(vertices=[0, 1], base_ring=ZZ) # needs sage.modules [0 1] [1 0] - sage: G.distance_matrix(vertices=[0, 1], base_ring=RDF) + sage: G.distance_matrix(vertices=[0, 1], base_ring=RDF) # needs sage.modules [0.0 1.0] [1.0 0.0] @@ -2278,7 +2412,7 @@ def distance_matrix(self, vertices=None, *, base_ring=None, **kwds): constructor:: sage: G = Graph([(0, 1)]) - sage: G.distance_matrix(vertices=[0, 1], weight_function=lambda e:2) + sage: G.distance_matrix(vertices=[0, 1], weight_function=lambda e:2) # needs sage.modules [0 2] [2 0] """ @@ -2292,7 +2426,7 @@ def distance_matrix(self, vertices=None, *, base_ring=None, **kwds): vertices = self.vertices(sort=True) elif (len(vertices) != self.order() or set(vertices) != set(self.vertex_iterator())): - raise ValueError("``vertices`` must be a permutation of the vertices") + raise ValueError("parameter vertices must be a permutation of the vertices") # We extract from **kwds the arguments for distance_all_pairs keys = ['by_weight', 'algorithm', 'weight_function', 'check_weight'] @@ -2356,15 +2490,15 @@ def weighted_adjacency_matrix(self, sparse=True, vertices=None, sage: G = Graph(sparse=True, weighted=True) sage: G.add_edges([(0, 1, 1), (1, 2, 2), (0, 2, 3), (0, 3, 4)]) - sage: M = G.weighted_adjacency_matrix(); M + sage: M = G.weighted_adjacency_matrix(); M # needs sage.modules [0 1 3 4] [1 0 2 0] [3 2 0 0] [4 0 0 0] - sage: H = Graph(data=M, format='weighted_adjacency_matrix', sparse=True) - sage: H == G + sage: H = Graph(data=M, format='weighted_adjacency_matrix', sparse=True) # needs sage.modules + sage: H == G # needs sage.modules True - sage: G.weighted_adjacency_matrix(vertices=[3, 2, 1, 0]) + sage: G.weighted_adjacency_matrix(vertices=[3, 2, 1, 0]) # needs sage.modules [0 0 0 4] [0 0 2 3] [0 2 0 1] @@ -2372,7 +2506,8 @@ def weighted_adjacency_matrix(self, sparse=True, vertices=None, Using a different matrix implementation:: - sage: M = G.weighted_adjacency_matrix(sparse=False, base_ring=ZZ, implementation='numpy'); M + sage: M = G.weighted_adjacency_matrix(sparse=False, base_ring=ZZ, # needs numpy sage.modules + ....: implementation='numpy'); M [0 1 3 4] [1 0 2 0] [3 2 0 0] @@ -2380,22 +2515,23 @@ def weighted_adjacency_matrix(self, sparse=True, vertices=None, As an immutable matrix:: - sage: M = G.weighted_adjacency_matrix(immutable=True); M + sage: M = G.weighted_adjacency_matrix(immutable=True); M # needs sage.modules [0 1 3 4] [1 0 2 0] [3 2 0 0] [4 0 0 0] - sage: M[2, 2] = 1 + sage: M[2, 2] = 1 # needs sage.modules Traceback (most recent call last): ... - ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M). + ValueError: matrix is immutable; please change a copy instead + (i.e., use copy(M) to change a copy of M). TESTS: The following doctest verifies that :trac:`4888` is fixed:: sage: G = DiGraph({0:{}, 1:{0:1}, 2:{0:1}}, weighted=True, sparse=True) - sage: G.weighted_adjacency_matrix() + sage: G.weighted_adjacency_matrix() # needs sage.modules [0 0 0] [1 0 0] [1 0 0] @@ -2403,15 +2539,16 @@ def weighted_adjacency_matrix(self, sparse=True, vertices=None, Check error message for non numerical edge weights (:trac:`33562`):: sage: G = Graph([(0, 1)]) - sage: G.weighted_adjacency_matrix() + sage: G.weighted_adjacency_matrix() # needs sage.modules Traceback (most recent call last): ... - ValueError: cannot find the weight of (0, 1, None). Consider setting parameter 'default_weight' - sage: G.weighted_adjacency_matrix(default_weight=3) + ValueError: cannot find the weight of (0, 1, None). + Consider setting parameter 'default_weight' + sage: G.weighted_adjacency_matrix(default_weight=3) # needs sage.modules [0 3] [3 0] sage: G = Graph([(0, 1, 'a')]) - sage: G.weighted_adjacency_matrix() + sage: G.weighted_adjacency_matrix() # needs sage.modules Traceback (most recent call last): ... TypeError: Cannot convert NoneType to sage.structure.parent.Parent @@ -2423,7 +2560,7 @@ def weighted_adjacency_matrix(self, sparse=True, vertices=None, vertices = self.vertices(sort=True) elif (len(vertices) != self.num_verts() or set(vertices) != set(self.vertex_iterator())): - raise ValueError("``vertices`` must be a permutation of the vertices") + raise ValueError("parameter vertices must be a permutation of the vertices") # Method for checking edge weights and setting default weight if default_weight is None: @@ -2530,33 +2667,33 @@ def kirchhoff_matrix(self, weighted=None, indegree=True, normalized=False, signl sage: G = Graph(sparse=True) sage: G.add_edges([(0, 1, 1), (1, 2, 2), (0, 2, 3), (0, 3, 4)]) - sage: M = G.kirchhoff_matrix(weighted=True); M + sage: M = G.kirchhoff_matrix(weighted=True); M # needs sage.modules [ 8 -1 -3 -4] [-1 3 -2 0] [-3 -2 5 0] [-4 0 0 4] - sage: M = G.kirchhoff_matrix(); M + sage: M = G.kirchhoff_matrix(); M # needs sage.modules [ 3 -1 -1 -1] [-1 2 -1 0] [-1 -1 2 0] [-1 0 0 1] - sage: M = G.laplacian_matrix(normalized=True); M # optional - sage.symbolic + sage: M = G.laplacian_matrix(normalized=True); M # needs sage.modules sage.symbolic [ 1 -1/6*sqrt(3)*sqrt(2) -1/6*sqrt(3)*sqrt(2) -1/3*sqrt(3)] [-1/6*sqrt(3)*sqrt(2) 1 -1/2 0] [-1/6*sqrt(3)*sqrt(2) -1/2 1 0] [ -1/3*sqrt(3) 0 0 1] - sage: M = G.kirchhoff_matrix(weighted=True, signless=True); M + sage: M = G.kirchhoff_matrix(weighted=True, signless=True); M # needs sage.modules [8 1 3 4] [1 3 2 0] [3 2 5 0] [4 0 0 4] sage: G = Graph({0: [], 1: [2]}) - sage: G.laplacian_matrix(normalized=True) + sage: G.laplacian_matrix(normalized=True) # needs sage.modules [ 0 0 0] [ 0 1 -1] [ 0 -1 1] - sage: G.laplacian_matrix(normalized=True,signless=True) + sage: G.laplacian_matrix(normalized=True, signless=True) # needs sage.modules [0 0 0] [0 1 1] [0 1 1] @@ -2564,14 +2701,14 @@ def kirchhoff_matrix(self, weighted=None, indegree=True, normalized=False, signl A weighted directed graph with loops, changing the variable ``indegree`` :: sage: G = DiGraph({1: {1: 2, 2: 3}, 2: {1: 4}}, weighted=True, sparse=True) - sage: G.laplacian_matrix() + sage: G.laplacian_matrix() # needs sage.modules [ 4 -3] [-4 3] :: sage: G = DiGraph({1: {1: 2, 2: 3}, 2: {1: 4}}, weighted=True, sparse=True) - sage: G.laplacian_matrix(indegree=False) + sage: G.laplacian_matrix(indegree=False) # needs sage.modules [ 3 -3] [-4 4] @@ -2580,12 +2717,12 @@ def kirchhoff_matrix(self, weighted=None, indegree=True, normalized=False, signl sage: G = Graph(sparse=True) sage: G.add_edges([(0, 1, 1), (1, 2, 2), (0, 2, 3), (0, 3, 4)]) - sage: M = G.kirchhoff_matrix(vertices=[3, 2, 1, 0]); M + sage: M = G.kirchhoff_matrix(vertices=[3, 2, 1, 0]); M # needs sage.modules [ 1 0 0 -1] [ 0 2 -1 -1] [ 0 -1 2 -1] [-1 -1 -1 3] - sage: M = G.kirchhoff_matrix(weighted=True, vertices=[3, 2, 1, 0]); M + sage: M = G.kirchhoff_matrix(weighted=True, vertices=[3, 2, 1, 0]); M # needs sage.modules [ 4 0 0 -4] [ 0 5 -2 -3] [ 0 -2 3 -1] @@ -2595,8 +2732,8 @@ def kirchhoff_matrix(self, weighted=None, indegree=True, normalized=False, signl immutable:: sage: G = Graph([(0, 1)]) - sage: M = G.kirchhoff_matrix(vertices=[0, 1], immutable=True) - sage: M.is_immutable() + sage: M = G.kirchhoff_matrix(vertices=[0, 1], immutable=True) # needs sage.modules + sage: M.is_immutable() # needs sage.modules True """ from sage.matrix.constructor import diagonal_matrix @@ -3100,8 +3237,7 @@ def loop_edges(self, labels=True): return [(v, v) for v in self.loop_vertices() for l in self.edge_label(v, v)] elif labels: return [(v, v, self.edge_label(v, v)) for v in self.loop_vertices()] - else: - return [(v, v) for v in self.loop_vertices()] + return [(v, v) for v in self.loop_vertices()] # As discussed in trac 22911, we make method loops an alias for loop_edges loops = loop_edges @@ -3142,8 +3278,7 @@ def loop_vertices(self): """ if self.allows_loops(): return [v for v in self if self.has_edge(v, v)] - else: - return [] + return [] def has_multiple_edges(self, to_undirected=False): """ @@ -3389,7 +3524,7 @@ def allow_multiple_edges(self, new, check=True, keep_label='any'): self._backend.multiple_edges(new) - def multiple_edges(self, to_undirected=False, labels=True, sort=False): + def multiple_edges(self, to_undirected=False, labels=True, sort=False, key=None): """ Return any multiple edges in the (di)graph. @@ -3399,7 +3534,11 @@ def multiple_edges(self, to_undirected=False, labels=True, sort=False): - ``labels`` -- boolean (default: ``True``); whether to include labels - - ``sort`` - boolean (default: ``False``); whether to sort the result + - ``sort`` -- boolean (default: ``False``); whether to sort the result + + - ``key`` -- a function (default: ``None``); a function that takes an + edge as its one argument and returns a value that can be used for + comparisons in the sorting algorithm (we must have ``sort=True``) EXAMPLES:: @@ -3448,7 +3587,36 @@ def multiple_edges(self, to_undirected=False, labels=True, sort=False): [] sage: G.multiple_edges(to_undirected=True, sort=True) [(1, 2, 'h'), (2, 1, 'g')] + + Using the ``key`` argument to order multiple edges of incomparable + types (see :trac:`35903`):: + + sage: G = Graph([('A', 'B', 3), (1, 2, 1), ('A', 'B', 4), (1, 2, 2)], multiedges=True) + sage: G.multiple_edges(sort=True) + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for <: 'Integer Ring' and '<class 'str'>' + sage: G.multiple_edges(labels=False, sort=True, key=str) + [('A', 'B'), ('A', 'B'), (1, 2), (1, 2)] + sage: G.multiple_edges(sort=True, key=str) + [('A', 'B', 3), ('A', 'B', 4), (1, 2, 1), (1, 2, 2)] + sage: G.multiple_edges(labels=True, sort=True, key=lambda e:e[2]) + [(1, 2, 1), (1, 2, 2), ('A', 'B', 3), ('A', 'B', 4)] + sage: G.multiple_edges(labels=False, sort=True, key=lambda e:e[2]) + Traceback (most recent call last): + ... + IndexError: tuple index out of range + + TESTS:: + + sage: Graph().multiple_edges(sort=False, key=str) + Traceback (most recent call last): + ... + ValueError: sort keyword is False, yet a key function is given """ + if (not sort) and key: + raise ValueError('sort keyword is False, yet a key function is given') + multi_edges = [] seen = set() @@ -3521,7 +3689,7 @@ def multiple_edges(self, to_undirected=False, labels=True, sort=False): multi_edges.extend((u, v) for _ in L) if sort: - multi_edges.sort() + return sorted(multi_edges, key=key) return multi_edges def name(self, new=None): @@ -3591,8 +3759,8 @@ def get_pos(self, dim=2): sage: G.get_pos() sage: G.get_pos() is None True - sage: P = G.plot(save_pos=True) - sage: G.get_pos() + sage: P = G.plot(save_pos=True) # needs sage.plot + sage: G.get_pos() # needs sage.plot {} Some of the named graphs come with a pre-specified positioning:: @@ -3717,8 +3885,8 @@ def set_pos(self, pos, dim=2): invalid positioning are ignored:: sage: G.set_pos(dict(enumerate('abcdefghi'))) - sage: P = G.plot() # positions are ignored - sage: G.get_pos() is None + sage: P = G.plot() # positions are ignored # needs sage.plot + sage: G.get_pos() is None # needs sage.plot True """ if pos is None: @@ -3848,21 +4016,21 @@ def antisymmetric(self): A directed acyclic graph is antisymmetric:: - sage: G = digraphs.RandomDirectedGNR(20, 0.5) - sage: G.antisymmetric() + sage: G = digraphs.RandomDirectedGNR(20, 0.5) # needs networkx + sage: G.antisymmetric() # needs networkx True Loops are allowed:: - sage: G.allow_loops(True) - sage: G.add_edge(0, 0) - sage: G.antisymmetric() + sage: G.allow_loops(True) # needs networkx + sage: G.add_edge(0, 0) # needs networkx + sage: G.antisymmetric() # needs networkx True An undirected graph is never antisymmetric unless it is just a union of isolated vertices (with possible loops):: - sage: graphs.RandomGNP(20, 0.5).antisymmetric() + sage: graphs.RandomGNP(20, 0.5).antisymmetric() # needs networkx False sage: Graph(3).antisymmetric() True @@ -3879,8 +4047,7 @@ def antisymmetric(self): g = self.transitive_closure() g.allow_loops(False) return g.is_directed_acyclic() - else: - return self.is_directed_acyclic() + return self.is_directed_acyclic() def density(self): """ @@ -3916,15 +4083,13 @@ def density(self): return Rational(0) if self._directed: return Rational(self.size()) / Rational(n ** 2) - else: - return Rational(self.size()) / Rational((n ** 2 + n) / 2) + return Rational(self.size()) / Rational((n ** 2 + n) / 2) else: if n < 2: return Rational(0) if self._directed: return Rational(self.size()) / Rational((n ** 2 - n)) - else: - return Rational(self.size()) / Rational((n ** 2 - n) / 2) + return Rational(self.size()) / Rational((n ** 2 - n) / 2) def is_bipartite(self, certificate=False): r""" @@ -3944,7 +4109,7 @@ def is_bipartite(self, certificate=False): True sage: graphs.CycleGraph(5).is_bipartite() False - sage: graphs.RandomBipartite(10, 10, 0.7).is_bipartite() + sage: graphs.RandomBipartite(10, 10, 0.7).is_bipartite() # needs numpy True A random graph is very rarely bipartite:: @@ -3985,8 +4150,7 @@ def is_bipartite(self, certificate=False): if self.has_edge(u, u): if certificate: return (False, [u]) - else: - return False + return False color = {} # inheritance of colors along the DFS to recover an odd @@ -4037,8 +4201,7 @@ def is_bipartite(self, certificate=False): return False, cycle - else: - return False + return False # We color a new vertex else: @@ -4048,8 +4211,7 @@ def is_bipartite(self, certificate=False): if certificate: return True, color - else: - return True + return True def is_eulerian(self, path=False): r""" @@ -4115,12 +4277,18 @@ def is_eulerian(self, path=False): sage: g = Graph({0:[], 1:[], 2:[], 3:[]}); g.is_eulerian() True - """ + Issue :trac:`35168` is fixed:: + + sage: Graph([[0, 42, 'John'], [(42, 0)]]).is_eulerian() + False + sage: Graph([[0, 42, 'John'], [(42, 'John')]]).is_eulerian() + False + """ # unconnected graph can still be Eulerian if all components # up to one doesn't contain any edge nontrivial_components = 0 - for cc in self.connected_components(): + for cc in self.connected_components(sort=False): if len(cc) > 1: nontrivial_components += 1 if nontrivial_components > 1: @@ -4452,8 +4620,7 @@ def eulerian_circuit(self, return_vertices=False, labels=True, path=False): if return_vertices: return edges, vertices - else: - return edges + return edges def min_spanning_tree(self, weight_function=None, @@ -4540,63 +4707,88 @@ def min_spanning_tree(self, sage: len(g.min_spanning_tree()) 4 sage: weight = lambda e: 1 / ((e[0] + 1) * (e[1] + 1)) - sage: sorted(g.min_spanning_tree(weight_function=weight)) - [(0, 4, None), (1, 4, None), (2, 4, None), (3, 4, None)] - sage: sorted(g.min_spanning_tree(weight_function=weight, algorithm='Kruskal_Boost')) - [(0, 4, None), (1, 4, None), (2, 4, None), (3, 4, None)] + sage: E = g.min_spanning_tree(weight_function=weight) + sage: T = Graph(E) + sage: set(g) == set(T) and T.order() == T.size() + 1 and T.is_tree() + True + sage: sum(map(weight, E)) + 5/12 + sage: E = g.min_spanning_tree(weight_function=weight, + ....: algorithm='Kruskal_Boost') + sage: Graph(E).is_tree(); sum(map(weight, E)) + True + 5/12 sage: g = graphs.PetersenGraph() sage: g.allow_multiple_edges(True) sage: g.add_edges(g.edge_iterator()) - sage: sorted(g.min_spanning_tree()) - [(0, 1, None), (0, 4, None), (0, 5, None), (1, 2, None), (1, 6, None), (3, 8, None), (5, 7, None), (5, 8, None), (6, 9, None)] + sage: T = Graph(g.min_spanning_tree()) + sage: set(g) == set(T) and T.order() == T.size() + 1 and T.is_tree() + True Boruvka's algorithm:: sage: sorted(g.min_spanning_tree(algorithm='Boruvka')) - [(0, 1, None), (0, 4, None), (0, 5, None), (1, 2, None), (1, 6, None), (2, 3, None), (2, 7, None), (3, 8, None), (4, 9, None)] + [(0, 1, None), (0, 4, None), (0, 5, None), (1, 2, None), (1, 6, None), + (2, 3, None), (2, 7, None), (3, 8, None), (4, 9, None)] Prim's algorithm:: sage: g = graphs.CompleteGraph(5) - sage: sorted(g.min_spanning_tree(algorithm='Prim_edge', starting_vertex=2, weight_function=weight)) - [(0, 4, None), (1, 4, None), (2, 4, None), (3, 4, None)] - sage: sorted(g.min_spanning_tree(algorithm='Prim_fringe', starting_vertex=2, weight_function=weight)) - [(0, 4, None), (1, 4, None), (2, 4, None), (3, 4, None)] - sage: sorted(g.min_spanning_tree(weight_function=weight, algorithm='Prim_Boost')) - [(0, 4, None), (1, 4, None), (2, 4, None), (3, 4, None)] + sage: for algo in ['Prim_edge', 'Prim_fringe', 'Prim_Boost']: + ....: E = g.min_spanning_tree(algorithm=algo, weight_function=weight) + ....: T = Graph(E) + ....: print(set(g) == set(T) and T.order() == T.size() + 1 and T.is_tree()) + True + True + True NetworkX algorithm:: - sage: sorted(g.min_spanning_tree(algorithm='NetworkX')) + sage: sorted(g.min_spanning_tree(algorithm='NetworkX')) # needs networkx [(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None)] More complicated weights:: - sage: G = Graph([(0,1,{'name':'a','weight':1}), (0,2,{'name':'b','weight':3}), (1,2,{'name':'b','weight':1})]) - sage: sorted(G.min_spanning_tree(weight_function=lambda e: e[2]['weight'])) + sage: G = Graph([(0, 1, {'name': 'a', 'weight': 1}), + ....: (0, 2, {'name': 'b', 'weight': 3}), + ....: (1, 2, {'name': 'b', 'weight': 1})]) + sage: sorted(G.min_spanning_tree(algorithm='Boruvka', + ....: weight_function=lambda e: e[2]['weight'])) [(0, 1, {'name': 'a', 'weight': 1}), (1, 2, {'name': 'b', 'weight': 1})] If the graph is not weighted, edge labels are not considered, even if they are numbers:: sage: g = Graph([(1, 2, 1), (1, 3, 2), (2, 3, 1)]) - sage: sorted(g.min_spanning_tree()) + sage: sorted(g.min_spanning_tree(algorithm='Boruvka')) [(1, 2, 1), (1, 3, 2)] In order to use weights, we need either to set variable ``weighted`` to ``True``, or to specify a weight function or set by_weight to ``True``:: sage: g.weighted(True) - sage: sorted(g.min_spanning_tree()) + sage: Graph(g.min_spanning_tree()).edges(sort=True) [(1, 2, 1), (2, 3, 1)] sage: g.weighted(False) - sage: sorted(g.min_spanning_tree()) + sage: Graph(g.min_spanning_tree()).edges(sort=True) [(1, 2, 1), (1, 3, 2)] - sage: sorted(g.min_spanning_tree(by_weight=True)) + sage: Graph(g.min_spanning_tree(by_weight=True)).edges(sort=True) + [(1, 2, 1), (2, 3, 1)] + sage: Graph(g.min_spanning_tree(weight_function=lambda e: e[2])).edges(sort=True) + [(1, 2, 1), (2, 3, 1)] + + Note that the order of the vertices on each edge is not guaranteed and + may differ from an algorithm to the other:: + + sage: g.weighted(True) + sage: sorted(g.min_spanning_tree()) + [(2, 1, 1), (3, 2, 1)] + sage: sorted(g.min_spanning_tree(algorithm='Boruvka')) [(1, 2, 1), (2, 3, 1)] - sage: sorted(g.min_spanning_tree(weight_function=lambda e: e[2])) + sage: Graph(g.min_spanning_tree()).edges(sort=True) [(1, 2, 1), (2, 3, 1)] + TESTS: Check that, if ``weight_function`` is not provided, then edge weights @@ -4604,21 +4796,21 @@ def min_spanning_tree(self, sage: g = Graph(weighted=True) sage: g.add_edges([[0, 1, 1], [1, 2, 1], [2, 0, 10]]) - sage: sorted(g.min_spanning_tree()) + sage: Graph(g.min_spanning_tree()).edges(sort=True) [(0, 1, 1), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Filter_Kruskal')) + sage: Graph(g.min_spanning_tree(algorithm='Filter_Kruskal')).edges(sort=True) [(0, 1, 1), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Kruskal_Boost')) + sage: Graph(g.min_spanning_tree(algorithm='Kruskal_Boost')).edges(sort=True) [(0, 1, 1), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Prim_fringe')) + sage: Graph(g.min_spanning_tree(algorithm='Prim_fringe')).edges(sort=True) [(0, 1, 1), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Prim_edge')) + sage: Graph(g.min_spanning_tree(algorithm='Prim_edge')).edges(sort=True) [(0, 1, 1), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Prim_Boost')) + sage: Graph(g.min_spanning_tree(algorithm='Prim_Boost')).edges(sort=True) [(0, 1, 1), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='NetworkX')) + sage: Graph(g.min_spanning_tree(algorithm='Boruvka')).edges(sort=True) [(0, 1, 1), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Boruvka')) + sage: Graph(g.min_spanning_tree(algorithm='NetworkX')).edges(sort=True) # needs networkx [(0, 1, 1), (1, 2, 1)] Check that, if ``weight_function`` is provided, it overrides edge @@ -4626,29 +4818,27 @@ def min_spanning_tree(self, sage: g = Graph([[0, 1, 1], [1, 2, 1], [2, 0, 10]], weighted=True) sage: weight = lambda e: 3 - e[0] - e[1] - sage: sorted(g.min_spanning_tree(weight_function=weight)) + sage: Graph(g.min_spanning_tree(weight_function=weight)).edges(sort=True) [(0, 2, 10), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Filter_Kruskal', weight_function=weight)) + sage: Graph(g.min_spanning_tree(algorithm='Filter_Kruskal', weight_function=weight)).edges(sort=True) [(0, 2, 10), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Kruskal_Boost', weight_function=weight)) + sage: Graph(g.min_spanning_tree(algorithm='Kruskal_Boost', weight_function=weight)).edges(sort=True) [(0, 2, 10), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Prim_fringe', weight_function=weight)) + sage: Graph(g.min_spanning_tree(algorithm='Prim_fringe', weight_function=weight)).edges(sort=True) [(0, 2, 10), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Prim_edge', weight_function=weight)) + sage: Graph(g.min_spanning_tree(algorithm='Prim_edge', weight_function=weight)).edges(sort=True) [(0, 2, 10), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Prim_Boost', weight_function=weight)) + sage: Graph(g.min_spanning_tree(algorithm='Prim_Boost', weight_function=weight)).edges(sort=True) [(0, 2, 10), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='NetworkX', weight_function=weight)) - [(0, 2, 10), (1, 2, 1)] - sage: sorted(g.min_spanning_tree(algorithm='Boruvka', weight_function=weight)) + sage: Graph(g.min_spanning_tree(algorithm='NetworkX', weight_function=weight)).edges(sort=True) # needs networkx [(0, 2, 10), (1, 2, 1)] If the graph is directed, it is transformed into an undirected graph:: sage: g = digraphs.Circuit(3) - sage: sorted(g.min_spanning_tree(weight_function=weight)) + sage: Graph(g.min_spanning_tree(weight_function=weight)).edges(sort=True) [(0, 2, None), (1, 2, None)] - sage: sorted(g.to_undirected().min_spanning_tree(weight_function=weight)) + sage: Graph(g.to_undirected().min_spanning_tree(weight_function=weight)).edges(sort=True) [(0, 2, None), (1, 2, None)] If at least an edge weight is not convertible to a float, an error is @@ -4669,6 +4859,17 @@ def min_spanning_tree(self, sage: graphs.EmptyGraph().min_spanning_tree() [] + + Check that the method is robust to incomparable vertices:: + + sage: G = Graph([(1, 2, 10), (1, 'a', 1), ('a', 'b', 1), ('b', 2, 1)]) + sage: E = G.min_spanning_tree(algorithm='Prim_Boost', by_weight=True) + sage: E = G.min_spanning_tree(algorithm='Prim_fringe', by_weight=True) + sage: E = G.min_spanning_tree(algorithm='Prim_edge', by_weight=True) + sage: E = G.min_spanning_tree(algorithm='Kruskal_Boost', by_weight=True) + sage: E = G.min_spanning_tree(algorithm='Filter_Kruskal', by_weight=True) + sage: E = G.min_spanning_tree(algorithm='Boruvka', by_weight=True) + sage: E = G.min_spanning_tree(algorithm='NetworkX', by_weight=True) # needs networkx """ if not self.order(): return [] @@ -4778,8 +4979,7 @@ def cmp_fun(x): E = networkx.minimum_spanning_edges(G, data=False) return [(u, v, self.edge_label(u, v)) if hash(u) < hash(v) else (v, u, self.edge_label(u, v)) for u, v in E] - else: - raise NotImplementedError("minimum spanning tree algorithm '%s' is not implemented" % algorithm) + raise NotImplementedError("minimum spanning tree algorithm '%s' is not implemented" % algorithm) def spanning_trees_count(self, root_vertex=None): r""" @@ -4824,19 +5024,20 @@ def spanning_trees_count(self, root_vertex=None): EXAMPLES:: sage: G = graphs.PetersenGraph() - sage: G.spanning_trees_count() + sage: G.spanning_trees_count() # needs sage.modules 2000 :: sage: n = 11 sage: G = graphs.CompleteGraph(n) - sage: ST = G.spanning_trees_count() - sage: ST == n ^ (n - 2) + sage: ST = G.spanning_trees_count() # needs sage.modules + sage: ST == n ^ (n - 2) # needs sage.modules True :: + sage: # needs sage.modules sage: M = matrix(3, 3, [0, 1, 0, 0, 0, 1, 1, 1, 0]) sage: D = DiGraph(M) sage: D.spanning_trees_count() @@ -4855,18 +5056,18 @@ def spanning_trees_count(self, root_vertex=None): M.subdivide(1, 1) M2 = M.subdivision(1, 1) return M2.determinant() + + if root_vertex is None: + root_vertex = vertices[0] + index = 0 + elif root_vertex not in vertices: + raise ValueError("vertex (%s) not in the graph" % root_vertex) else: - if root_vertex is None: - root_vertex = vertices[0] - index = 0 - elif root_vertex not in vertices: - raise ValueError("vertex (%s) not in the graph" % root_vertex) - else: - index = vertices.index(root_vertex) + index = vertices.index(root_vertex) - M = self.kirchhoff_matrix(vertices=vertices) - M[index, index] += 1 - return abs(M.determinant()) + M = self.kirchhoff_matrix(vertices=vertices) + M[index, index] += 1 + return abs(M.determinant()) def cycle_basis(self, output='vertex'): r""" @@ -4901,33 +5102,35 @@ def cycle_basis(self, output='vertex'): A cycle basis in Petersen's Graph :: sage: g = graphs.PetersenGraph() - sage: g.cycle_basis() - [[1, 6, 8, 5, 0], [4, 9, 6, 8, 5, 0], [7, 9, 6, 8, 5], [4, 3, 8, 5, 0], [1, 2, 3, 8, 5, 0], [7, 2, 3, 8, 5]] + sage: g.cycle_basis() # needs networkx + [[1, 6, 8, 5, 0], [4, 9, 6, 8, 5, 0], [7, 9, 6, 8, 5], + [4, 3, 8, 5, 0], [1, 2, 3, 8, 5, 0], [7, 2, 3, 8, 5]] One can also get the result as a list of lists of edges:: - sage: g.cycle_basis(output='edge') + sage: g.cycle_basis(output='edge') # needs networkx [[(1, 6, None), (6, 8, None), (8, 5, None), (5, 0, None), - (0, 1, None)], [(4, 9, None), (9, 6, None), (6, 8, None), - (8, 5, None), (5, 0, None), (0, 4, None)], [(7, 9, None), - (9, 6, None), (6, 8, None), (8, 5, None), (5, 7, None)], - [(4, 3, None), (3, 8, None), (8, 5, None), (5, 0, None), - (0, 4, None)], [(1, 2, None), (2, 3, None), (3, 8, None), - (8, 5, None), (5, 0, None), (0, 1, None)], [(7, 2, None), - (2, 3, None), (3, 8, None), (8, 5, None), (5, 7, None)]] + (0, 1, None)], [(4, 9, None), (9, 6, None), (6, 8, None), + (8, 5, None), (5, 0, None), (0, 4, None)], [(7, 9, None), + (9, 6, None), (6, 8, None), (8, 5, None), (5, 7, None)], + [(4, 3, None), (3, 8, None), (8, 5, None), (5, 0, None), + (0, 4, None)], [(1, 2, None), (2, 3, None), (3, 8, None), + (8, 5, None), (5, 0, None), (0, 1, None)], [(7, 2, None), + (2, 3, None), (3, 8, None), (8, 5, None), (5, 7, None)]] Checking the given cycles are algebraically free:: - sage: g = graphs.RandomGNP(30, .4) - sage: basis = g.cycle_basis() + sage: g = graphs.RandomGNP(30, .4) # needs networkx + sage: basis = g.cycle_basis() # needs networkx Building the space of (directed) edges over `Z/2Z`. On the way, building a dictionary associating a unique vector to each undirected edge:: sage: m = g.size() - sage: edge_space = VectorSpace(FiniteField(2), m) - sage: edge_vector = dict(zip(g.edges(labels=False, sort=False), edge_space.basis())) - sage: for (u, v), vec in list(edge_vector.items()): + sage: edge_space = VectorSpace(FiniteField(2), m) # needs sage.modules sage.rings.finite_rings + sage: edge_vector = dict(zip(g.edges(labels=False, sort=False), # needs sage.modules sage.rings.finite_rings + ....: edge_space.basis())) + sage: for (u, v), vec in list(edge_vector.items()): # needs sage.modules sage.rings.finite_rings ....: edge_vector[(v, u)] = vec Defining a lambda function associating a vector to the vertices of a @@ -4938,30 +5141,32 @@ def cycle_basis(self, output='vertex'): Finally checking the cycles are a free set:: - sage: basis_as_vectors = [cycle_to_vector(_) for _ in basis] - sage: edge_space.span(basis_as_vectors).rank() == len(basis) + sage: basis_as_vectors = [cycle_to_vector(_) for _ in basis] # needs networkx sage.modules sage.rings.finite_rings + sage: edge_space.span(basis_as_vectors).rank() == len(basis) # needs networkx sage.modules sage.rings.finite_rings True For undirected graphs with multiple edges:: - sage: G = Graph([(0, 2, 'a'), (0, 2, 'b'), (0, 1, 'c'), (1, 2, 'd')], multiedges=True) - sage: G.cycle_basis() + sage: G = Graph([(0, 2, 'a'), (0, 2, 'b'), (0, 1, 'c'), (1, 2, 'd')], + ....: multiedges=True) + sage: G.cycle_basis() # needs networkx [[0, 2], [2, 1, 0]] - sage: G.cycle_basis(output='edge') - [[(0, 2, 'a'), (2, 0, 'b')], [(2, 1, 'd'), (1, 0, 'c'), (0, 2, 'a')]] - sage: H = Graph([(1, 2), (2, 3), (2, 3), (3, 4), (1, 4), (1, 4), (4, 5), (5, 6), (4, 6), (6, 7)], multiedges=True) - sage: H.cycle_basis() + sage: G.cycle_basis(output='edge') # needs networkx + [[(0, 2, 'b'), (2, 0, 'a')], [(2, 1, 'd'), (1, 0, 'c'), (0, 2, 'a')]] + sage: H = Graph([(1, 2), (2, 3), (2, 3), (3, 4), (1, 4), + ....: (1, 4), (4, 5), (5, 6), (4, 6), (6, 7)], multiedges=True) + sage: H.cycle_basis() # needs networkx [[1, 4], [2, 3], [4, 3, 2, 1], [6, 5, 4]] Disconnected graph:: sage: G.add_cycle(["Hey", "Wuuhuu", "Really ?"]) - sage: [sorted(c) for c in G.cycle_basis()] + sage: [sorted(c) for c in G.cycle_basis()] # needs networkx [['Hey', 'Really ?', 'Wuuhuu'], [0, 2], [0, 1, 2]] - sage: [sorted(c) for c in G.cycle_basis(output='edge')] - [[('Hey', 'Wuuhuu', None), - ('Really ?', 'Hey', None), - ('Wuuhuu', 'Really ?', None)], + sage: [sorted(c) for c in G.cycle_basis(output='edge')] # needs networkx + [[('Hey', 'Really ?', None), + ('Really ?', 'Wuuhuu', None), + ('Wuuhuu', 'Hey', None)], [(0, 2, 'a'), (2, 0, 'b')], [(0, 2, 'b'), (1, 0, 'c'), (2, 1, 'd')]] @@ -4969,13 +5174,13 @@ def cycle_basis(self, output='vertex'): sage: G = graphs.CycleGraph(3) sage: G.allow_multiple_edges(True) - sage: G.cycle_basis() + sage: G.cycle_basis() # needs networkx [[2, 1, 0]] Not yet implemented for directed graphs:: sage: G = DiGraph([(0, 2, 'a'), (0, 1, 'c'), (1, 2, 'd')]) - sage: G.cycle_basis() + sage: G.cycle_basis() # needs networkx Traceback (most recent call last): ... NotImplementedError: not implemented for directed graphs @@ -4984,14 +5189,14 @@ def cycle_basis(self, output='vertex'): :trac:`27538`:: - sage: G= Graph([(1, 2, 'a'), (2, 3, 'b'), (2, 3, 'c'), (3, 4, 'd'), (3, 4, 'e'), (4, 1, 'f')], multiedges=True) - sage: G.cycle_basis() + sage: G = Graph([(1, 2, 'a'), (2, 3, 'b'), (2, 3, 'c'), + ....: (3, 4, 'd'), (3, 4, 'e'), (4, 1, 'f')], multiedges=True) + sage: G.cycle_basis() # needs networkx [[2, 3], [4, 3, 2, 1], [4, 3, 2, 1]] - sage: G.cycle_basis(output='edge') - [[(2, 3, 'b'), (3, 2, 'c')], + sage: G.cycle_basis(output='edge') # needs networkx + [[(2, 3, 'c'), (3, 2, 'b')], [(4, 3, 'd'), (3, 2, 'b'), (2, 1, 'a'), (1, 4, 'f')], [(4, 3, 'e'), (3, 2, 'b'), (2, 1, 'a'), (1, 4, 'f')]] - """ if output not in ['vertex', 'edge']: raise ValueError('output must be either vertex or edge') @@ -5062,14 +5267,15 @@ def minimum_cycle_basis(self, algorithm=None, weight_function=None, by_weight=Fa EXAMPLES:: - sage: g = Graph([(1, 2, 3), (2, 3, 5), (3, 4, 8), (4, 1, 13), (1, 3, 250), (5, 6, 9), (6, 7, 17), (7, 5, 20)]) + sage: g = Graph([(1, 2, 3), (2, 3, 5), (3, 4, 8), (4, 1, 13), + ....: (1, 3, 250), (5, 6, 9), (6, 7, 17), (7, 5, 20)]) sage: sorted(g.minimum_cycle_basis(by_weight=True)) [[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]] sage: sorted(g.minimum_cycle_basis(by_weight=False)) [[1, 2, 3], [1, 3, 4], [5, 6, 7]] - sage: sorted(g.minimum_cycle_basis(by_weight=True, algorithm='NetworkX')) + sage: sorted(g.minimum_cycle_basis(by_weight=True, algorithm='NetworkX')) # needs networkx [[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]] - sage: g.minimum_cycle_basis(by_weight=False, algorithm='NetworkX') + sage: g.minimum_cycle_basis(by_weight=False, algorithm='NetworkX') # needs networkx [[1, 2, 3], [1, 3, 4], [5, 6, 7]] :: @@ -5077,7 +5283,7 @@ def minimum_cycle_basis(self, algorithm=None, weight_function=None, by_weight=Fa sage: g = Graph([(1, 2), (2, 3), (3, 4), (4, 5), (5, 1), (5, 3)]) sage: sorted(g.minimum_cycle_basis(by_weight=False)) [[1, 2, 3, 5], [3, 4, 5]] - sage: sorted(g.minimum_cycle_basis(by_weight=False, algorithm='NetworkX')) + sage: sorted(g.minimum_cycle_basis(by_weight=False, algorithm='NetworkX')) # needs networkx [[1, 2, 3, 5], [3, 4, 5]] TESTS:: @@ -5123,8 +5329,7 @@ def minimum_cycle_basis(self, algorithm=None, weight_function=None, by_weight=Fa basis.append(min_cycle_basis(comp, weight_function=weight_function, by_weight=by_weight)) return sum(basis, []) - else: - raise NotImplementedError("only 'NetworkX' and Cython implementation is supported") + raise NotImplementedError("only 'NetworkX' and Cython implementation is supported") # Planarity @@ -5206,7 +5411,7 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, se :: sage: g = graphs.PetersenGraph() - sage: (g.is_planar(kuratowski=True))[1].adjacency_matrix() + sage: (g.is_planar(kuratowski=True))[1].adjacency_matrix() # needs sage.modules [0 1 0 0 0 1 0 0 0] [1 0 1 0 0 0 1 0 0] [0 1 0 1 0 0 0 1 0] @@ -5221,7 +5426,8 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, se sage: k43 = graphs.CompleteBipartiteGraph(4, 3) sage: result = k43.is_planar(kuratowski=True); result - (False, Graph on 6 vertices) + (False, + Kuratowski subgraph of (Complete bipartite graph of order 4+3): Graph on 6 vertices) sage: result[1].is_isomorphic(graphs.CompleteBipartiteGraph(3, 3)) True @@ -5233,17 +5439,62 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, se sage: G.is_planar(on_embedding={}) Traceback (most recent call last): ... - NotImplementedError: cannot compute with embeddings of multiple-edged or looped graphs + NotImplementedError: cannot compute with embeddings of + multiple-edged or looped graphs + sage: G.is_planar(set_embedding=True) + Traceback (most recent call last): + ... + NotImplementedError: cannot compute with embeddings of + multiple-edged or looped graphs + sage: G.is_planar(kuratowski=True) + (True, None) sage: G.is_planar(set_pos=True) + True + sage: sorted(G.get_pos().items()) + [(0, [0, 0]), (1, [0, 1])] + + Digraphs with multiple edges or loops or pairs of opposite arcs are + partially supported (:trac:`35152`):: + + sage: D = digraphs.Complete(3) + sage: D.is_planar() + True + sage: D.is_planar(set_pos=True) + True + sage: sorted(D.get_pos().items()) + [(0, [0, 1]), (1, [1, 1]), (2, [1, 0])] + sage: D.is_planar(on_embedding={}) Traceback (most recent call last): ... - NotImplementedError: cannot compute with embeddings of multiple-edged or looped graphs - sage: G.is_planar(set_embedding=True) + NotImplementedError: cannot compute with embeddings of + digraphs with pairs of opposite arcs + sage: D.is_planar(set_embedding=True) Traceback (most recent call last): ... - NotImplementedError: cannot compute with embeddings of multiple-edged or looped graphs - sage: G.is_planar(kuratowski=True) + NotImplementedError: cannot compute with embeddings of + digraphs with pairs of opposite arcs + sage: D.is_planar(kuratowski=True) + (True, None) + sage: D.allow_multiple_edges(True) + sage: D.add_edges(D.edges(sort=False)) + sage: D.allow_loops(True) + sage: D.add_edges((u, u) for u in D) + sage: D.is_planar() + True + sage: D.is_planar(kuratowski=True) (True, None) + sage: D.is_planar(set_pos=True) + True + sage: D.is_planar(set_embedding=True) + Traceback (most recent call last): + ... + NotImplementedError: cannot compute with embeddings of + multiple-edged or looped graphs + sage: D.is_planar(on_embedding={}) + Traceback (most recent call last): + ... + NotImplementedError: cannot compute with embeddings of + multiple-edged or looped graphs :: @@ -5304,31 +5555,35 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, se if self.order() > 4 and self.size() > 3 * self.order() - 6: return False - if self.has_multiple_edges() or self.has_loops(): - if set_embedding or (on_embedding is not None) or set_pos: + if set_embedding or (on_embedding is not None): + # So far, working with embeddings is not working properly when a + # (di)graph has multiple edges or loops, or when a digraph has pairs + # of opposite arcs + if self.has_multiple_edges() or self.has_loops(): raise NotImplementedError("cannot compute with embeddings of multiple-edged or looped graphs") - else: - return self.to_simple().is_planar(kuratowski=kuratowski) + elif (self.is_directed() and + any(self.has_edge(v, u) for u, v in self.edge_iterator(labels=False))): + raise NotImplementedError("cannot compute with embeddings of digraphs with pairs of opposite arcs") if on_embedding is not None: self._check_embedding_validity(on_embedding, boolean=False) return (0 == self.genus(minimal=False, set_embedding=False, on_embedding=on_embedding)) + + # We take the underlying undirected and simple graph + G = self.to_simple(to_undirected=True, immutable=False) + # And check if it is planar + from sage.graphs.planarity import is_planar + planar = is_planar(G, kuratowski=kuratowski, set_pos=set_pos, set_embedding=set_embedding) + if kuratowski: + bool_result = planar[0] else: - from sage.graphs.planarity import is_planar - G = self.to_undirected() - if hasattr(G, '_immutable'): - G = copy(G) - planar = is_planar(G, kuratowski=kuratowski, set_pos=set_pos, set_embedding=set_embedding) - if kuratowski: - bool_result = planar[0] - else: - bool_result = planar - if bool_result: - if set_pos: - self._pos = G._pos - if set_embedding: - self._embedding = G._embedding - return planar + bool_result = planar + if bool_result: + if set_pos: + self._pos = G._pos + if set_embedding: + self._embedding = G._embedding + return planar def is_circular_planar(self, on_embedding=None, kuratowski=False, set_embedding=True, boundary=None, @@ -5406,11 +5661,11 @@ def is_circular_planar(self, on_embedding=None, kuratowski=False, EXAMPLES:: sage: g439 = Graph({1: [5, 7], 2: [5, 6], 3: [6, 7], 4: [5, 6, 7]}) - sage: g439.show() + sage: g439.show() # needs sage.plot sage: g439.is_circular_planar(boundary=[1, 2, 3, 4]) False sage: g439.is_circular_planar(kuratowski=True, boundary=[1, 2, 3, 4]) - (False, Graph on 8 vertices) + (False, Kuratowski subgraph of (): Graph on 8 vertices) sage: g439.is_circular_planar(kuratowski=True, boundary=[1, 2, 3]) (True, None) sage: g439.get_embedding() @@ -5582,11 +5837,11 @@ def layout_planar(self, set_embedding=False, on_embedding=None, 7: [2, 4], 8: [1, 6], 9: [2, 5]} - sage: g = graphs.BalancedTree(3, 4) - sage: pos = g.layout(layout='planar', save_pos=True, test=True) - sage: pos[0] + sage: g = graphs.BalancedTree(3, 4) # needs networkx + sage: pos = g.layout(layout='planar', save_pos=True, test=True) # needs networkx + sage: pos[0] # needs networkx [0, 119] - sage: pos[120] + sage: pos[120] # needs networkx [21, 37] sage: g = graphs.CycleGraph(7) sage: g.layout(layout='planar', save_pos=True, test=True) @@ -5605,23 +5860,24 @@ def layout_planar(self, set_embedding=False, on_embedding=None, sage: g.layout(layout='planar', external_face=(3,1)) {0: [2, 1], 1: [0, 2], 2: [1, 1], 3: [1, 0]} - Choose the embedding: + Choose the embedding:: sage: H = graphs.LadderGraph(4) - sage: em = {0:[1,4], 4:[0,5], 1:[5,2,0], 5:[4,6,1], 2:[1,3,6], 6:[7,5,2], 3:[7,2], 7:[3,6]} + sage: em = {0:[1,4], 4:[0,5], 1:[5,2,0], 5:[4,6,1], + ....: 2:[1,3,6], 6:[7,5,2], 3:[7,2], 7:[3,6]} sage: p = H.layout_planar(on_embedding=em) - sage: p # random + sage: p # random {2: [8.121320343559642, 1], - 3: [2.1213203435596424, 6], - 7: [3.1213203435596424, 0], - 0: [5.121320343559642, 3], - 1: [3.1213203435596424, 5], - 4: [4.121320343559642, 3], - 5: [4.121320343559642, 2], - 6: [3.1213203435596424, 1], - 9: [9.698670612749268, 1], - 8: [8.698670612749268, 1], - 10: [9.698670612749268, 0]} + 3: [2.1213203435596424, 6], + 7: [3.1213203435596424, 0], + 0: [5.121320343559642, 3], + 1: [3.1213203435596424, 5], + 4: [4.121320343559642, 3], + 5: [4.121320343559642, 2], + 6: [3.1213203435596424, 1], + 9: [9.698670612749268, 1], + 8: [8.698670612749268, 1], + 10: [9.698670612749268, 0]} TESTS:: @@ -5629,7 +5885,8 @@ def layout_planar(self, set_embedding=False, on_embedding=None, sage: G.layout(layout='planar', external_face=(1, 2)) Traceback (most recent call last): ... - ValueError: (1, 2) is not an edge of Graph on 4 vertices but has been provided as an edge of the external face + ValueError: (1, 2) is not an edge of Graph on 4 vertices + but has been provided as an edge of the external face Check the dependence of the computed position on the given combinatorial embedding (:trac:`28152`):: @@ -6064,8 +6321,7 @@ def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=Fal H = G.subgraph(block) g += genus.simple_connected_graph_genus(H, set_embedding=False, check=False, minimal=True) return g - else: - return genus.simple_connected_graph_genus(G, set_embedding=False, check=False, minimal=minimal) + return genus.simple_connected_graph_genus(G, set_embedding=False, check=False, minimal=minimal) def crossing_number(self): r""" @@ -6356,7 +6612,7 @@ def num_faces(self, embedding=None): ... ValueError: no embedding is provided and the graph is not planar - Issue :trac:`22003` is fixed: + Issue :trac:`22003` is fixed:: sage: Graph(1).num_faces() 1 @@ -6376,7 +6632,7 @@ def num_faces(self, embedding=None): else: if self.is_planar(): # We use Euler's formula: V-E+F-C=1 - C = len(self.connected_components()) + C = self.connected_components_number() return self.size() - self.order() + C + 1 else: raise ValueError("no embedding is provided and the graph is not planar") @@ -6583,7 +6839,7 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, # Can the problem be solved ? Are all the vertices in the same # connected component ? - cc = g.connected_component_containing_vertex(vertices[0]) + cc = g.connected_component_containing_vertex(vertices[0], sort=False) if any(v not in cc for v in vertices): from sage.categories.sets_cat import EmptySetError raise EmptySetError("the given vertices do not all belong to the " @@ -6708,34 +6964,36 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None The Petersen Graph does have a spanning tree (it is connected):: sage: g = graphs.PetersenGraph() - sage: [T] = g.edge_disjoint_spanning_trees(1) - sage: T.is_tree() + sage: [T] = g.edge_disjoint_spanning_trees(1) # needs sage.numerical.mip + sage: T.is_tree() # needs sage.numerical.mip True Though, it does not have 2 edge-disjoint trees (as it has less than `2(|V|-1)` edges):: - sage: g.edge_disjoint_spanning_trees(2) + sage: g.edge_disjoint_spanning_trees(2) # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: this graph does not contain the required number of trees/arborescences - By Edmond's theorem, a graph which is `k`-connected always has `k` + By Edmonds' theorem, a graph which is `k`-connected always has `k` edge-disjoint arborescences, regardless of the root we pick:: + sage: # needs sage.numerical.mip sage: g = digraphs.RandomDirectedGNP(11, .3) # reduced from 30 to 11, cf. #32169 sage: k = Integer(g.edge_connectivity()) sage: while not k: ....: g = digraphs.RandomDirectedGNP(11, .3) ....: k = Integer(g.edge_connectivity()) - sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011) - sage: all(a.is_directed_acyclic() for a in arborescences) # long time + sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011) + sage: all(a.is_directed_acyclic() for a in arborescences) # long time True sage: all(a.is_connected() for a in arborescences) # long time True In the undirected case, we can only ensure half of it:: + sage: # needs sage.numerical.mip sage: g = graphs.RandomGNP(14, .3) # reduced from 30 to 14, see #32169 sage: while not g.is_biconnected(): ....: g = graphs.RandomGNP(14, .3) @@ -6746,6 +7004,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None Check the validity of the algorithms for undirected graphs:: + sage: # needs sage.numerical.mip sage: g = graphs.RandomGNP(12, .7) sage: k = Integer(g.edge_connectivity()) // 2 sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="MILP") @@ -6767,7 +7026,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None sage: G = DiGraph(d6, format='dig6') sage: G.edge_connectivity() 5 - sage: G.edge_disjoint_spanning_trees(5) # long time + sage: G.edge_disjoint_spanning_trees(5) # long time # needs sage.numerical.mip [Digraph on 28 vertices, Digraph on 28 vertices, Digraph on 28 vertices, @@ -6776,6 +7035,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None Small cases:: + sage: # needs sage.numerical.mip sage: Graph().edge_disjoint_spanning_trees(0) [] sage: Graph(1).edge_disjoint_spanning_trees(0) @@ -6795,11 +7055,11 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None Choice of the algorithm:: - sage: Graph().edge_disjoint_spanning_trees(0, algorithm=None) + sage: Graph().edge_disjoint_spanning_trees(0, algorithm=None) # needs sage.numerical.mip [] sage: Graph().edge_disjoint_spanning_trees(0, algorithm="Roskind-Tarjan") [] - sage: Graph().edge_disjoint_spanning_trees(0, algorithm="MILP") + sage: Graph().edge_disjoint_spanning_trees(0, algorithm="MILP") # needs sage.numerical.mip [] sage: Graph().edge_disjoint_spanning_trees(0, algorithm="foo") Traceback (most recent call last): @@ -6807,7 +7067,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None ValueError: algorithm must be None, "Rosking-Tarjan" or "MILP" for undirected graphs sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm=None) [] - sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="MILP") + sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="MILP") # needs sage.numerical.mip [] sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="foo") Traceback (most recent call last): @@ -7218,25 +7478,25 @@ def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose A basic application in the Pappus graph:: sage: g = graphs.PappusGraph() - sage: g.vertex_cut(1, 16, value_only=True) + sage: g.vertex_cut(1, 16, value_only=True) # needs sage.numerical.mip 3 In the bipartite complete graph `K_{2,8}`, a cut between the two vertices in the size `2` part consists of the other `8` vertices:: sage: g = graphs.CompleteBipartiteGraph(2, 8) - sage: [value, vertices] = g.vertex_cut(0, 1, value_only=False) - sage: print(value) + sage: [value, vertices] = g.vertex_cut(0, 1, value_only=False) # needs sage.numerical.mip + sage: print(value) # needs sage.numerical.mip 8 - sage: vertices == list(range(2, 10)) + sage: vertices == list(range(2, 10)) # needs sage.numerical.mip True Clearly, in this case the two sides of the cut are singletons:: - sage: [value, vertices, [set1, set2]] = g.vertex_cut(0, 1, vertices=True) - sage: len(set1) == 1 + sage: [value, vertices, [set1, set2]] = g.vertex_cut(0, 1, vertices=True) # needs sage.numerical.mip + sage: len(set1) == 1 # needs sage.numerical.mip True - sage: len(set2) == 1 + sage: len(set2) == 1 # needs sage.numerical.mip True """ from sage.numerical.mip import MixedIntegerLinearProgram @@ -7343,35 +7603,35 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, edge cut:: sage: g = graphs.PetersenGraph() - sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only = True) + sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only=True) # needs sage.numerical.mip True As Petersen's graph is `3`-regular, a minimum multiway cut between three vertices contains at most `2\times 3` edges (which could correspond to the neighborhood of 2 vertices):: - sage: g.multiway_cut([0,3,9], value_only = True) == 2*3 + sage: g.multiway_cut([0,3,9], value_only=True) == 2*3 # needs sage.numerical.mip True In this case, though, the vertices are an independent set. If we pick instead vertices `0,9,` and `7`, we can save `4` edges in the multiway cut:: - sage: g.multiway_cut([0,7,9], value_only = True) == 2*3 - 1 + sage: g.multiway_cut([0,7,9], value_only=True) == 2*3 - 1 # needs sage.numerical.mip True This example, though, does not work in the directed case anymore, as it is not possible in Petersen's graph to mutualise edges:: sage: g = DiGraph(g) - sage: g.multiway_cut([0,7,9], value_only = True) == 3*3 + sage: g.multiway_cut([0,7,9], value_only=True) == 3*3 # needs sage.numerical.mip True Of course, a multiway cut between the whole vertex set contains all the edges of the graph:: - sage: C = g.multiway_cut(g.vertices(sort=False)) - sage: set(C) == set(g.edges(sort=False)) + sage: C = g.multiway_cut(g.vertices(sort=False)) # needs sage.numerical.mip + sage: set(C) == set(g.edges(sort=False)) # needs sage.numerical.mip True """ self._scream_if_not_simple(allow_loops=True) @@ -7481,18 +7741,20 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, Quite obviously, the max cut of a bipartite graph is the number of edges, and the two sets of vertices are the two sides:: + sage: # needs sage.numerical.mip sage: g = graphs.CompleteBipartiteGraph(5,6) sage: [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True) sage: value == 5*6 True - sage: bsetA, bsetB = map(list,g.bipartite_sets()) - sage: (bsetA == setA and bsetB == setB ) or ((bsetA == setB and bsetB == setA )) + sage: bsetA, bsetB = map(list, g.bipartite_sets()) + sage: ((bsetA == setA and bsetB == setB) + ....: or (bsetA == setB and bsetB == setA)) True The max cut of a Petersen graph:: - sage: g=graphs.PetersenGraph() - sage: g.max_cut() + sage: g = graphs.PetersenGraph() + sage: g.max_cut() # needs sage.numerical.mip 12 TESTS:: @@ -7572,22 +7834,22 @@ def good_edge(e): if value_only: return obj - else: - edges = [(u, v, l) for u, v, l in g.edge_iterator() if in_cut[good_edge((u, v))]] - val = [obj, edges] - if vertices: - in_set = p.get_values(in_set, convert=bool, tolerance=integrality_tolerance) - a = [] - b = [] - for v in g: - if in_set[0, v]: - a.append(v) - else: - b.append(v) - val.append([a, b]) + edges = [(u, v, l) for u, v, l in g.edge_iterator() if in_cut[good_edge((u, v))]] + val = [obj, edges] + + if vertices: + in_set = p.get_values(in_set, convert=bool, tolerance=integrality_tolerance) + a = [] + b = [] + for v in g: + if in_set[0, v]: + a.append(v) + else: + b.append(v) + val.append([a, b]) - return val + return val def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", solver=None, verbose=0, *, integrality_tolerance=1e-3): @@ -7657,8 +7919,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", `n - 2`:: sage: g = graphs.PetersenGraph() - sage: lp = g.longest_path() - sage: lp.order() >= g.order() - 2 + sage: lp = g.longest_path() # needs sage.numerical.mip + sage: lp.order() >= g.order() - 2 # needs sage.numerical.mip True The heuristic totally agrees:: @@ -7679,8 +7941,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: g = graphs.RandomGNP(15, 0.3) sage: for u, v in g.edge_iterator(labels=False): ....: g.set_edge_label(u, v, random()) - sage: lp = g.longest_path() - sage: (not lp.is_forest() or not max(lp.degree()) <= 2 + sage: lp = g.longest_path() # needs sage.numerical.mip + sage: (not lp.is_forest() or not max(lp.degree()) <= 2 # needs sage.numerical.mip ....: or not lp.is_connected()) False @@ -7698,9 +7960,9 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: g1 = graphs.PetersenGraph() sage: g2 = 2 * g1 - sage: lp1 = g1.longest_path() - sage: lp2 = g2.longest_path() - sage: len(lp1) == len(lp2) + sage: lp1 = g1.longest_path() # needs sage.numerical.mip + sage: lp2 = g2.longest_path() # needs sage.numerical.mip + sage: len(lp1) == len(lp2) # needs sage.numerical.mip True Disconnected graphs weighted:: @@ -7709,13 +7971,14 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: for u,v in g.edge_iterator(labels=False): ....: g.set_edge_label(u, v, random()) sage: g2 = 2 * g1 - sage: lp1 = g1.longest_path(use_edge_labels=True) - sage: lp2 = g2.longest_path(use_edge_labels=True) - sage: lp1[0] == lp2[0] + sage: lp1 = g1.longest_path(use_edge_labels=True) # needs sage.numerical.mip + sage: lp2 = g2.longest_path(use_edge_labels=True) # needs sage.numerical.mip + sage: lp1[0] == lp2[0] # needs sage.numerical.mip True Empty graphs:: + sage: # needs sage.numerical.mip sage: Graph().longest_path() Graph on 0 vertices sage: Graph().longest_path(use_edge_labels=True) @@ -7727,6 +7990,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", Trivial graphs:: + sage: # needs sage.numerical.mip sage: G = Graph() sage: G.add_vertex(0) sage: G.longest_path() @@ -7743,8 +8007,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: g = digraphs.RandomDirectedGNP(15, 0.3) sage: for u, v in g.edge_iterator(labels=False): ....: g.set_edge_label(u, v, random()) - sage: lp = g.longest_path() - sage: (not lp.is_directed_acyclic() or + sage: lp = g.longest_path() # needs sage.numerical.mip + sage: (not lp.is_directed_acyclic() or # needs sage.numerical.mip ....: not max(lp.out_degree()) <= 1 or ....: not max(lp.in_degree()) <= 1 or ....: not lp.is_connected()) @@ -7753,7 +8017,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", :trac:`13019`:: sage: g = graphs.CompleteGraph(5).to_directed() - sage: g.longest_path(s=1, t=2) + sage: g.longest_path(s=1, t=2) # needs sage.numerical.mip Subgraph of (Complete graph): Digraph on 5 vertices :trac:`14412`:: @@ -7761,7 +8025,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: l = [(0, 1), (0, 3), (2, 0), (3, 4)] sage: G = DiGraph(l) sage: H = {(0, 3), (2, 0), (3, 4)} - sage: H == {x for x in G.longest_path().edge_iterator(labels=False)} + sage: H == {x for x in G.longest_path().edge_iterator(labels=False)} # needs sage.numerical.mip True """ self._scream_if_not_simple() @@ -7779,12 +8043,12 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", algorithm=algorithm) for g in self.connected_components_subgraphs()), key=lambda x: x[0]) - else: - return max((g.longest_path(s=s, t=t, - use_edge_labels=use_edge_labels, - algorithm=algorithm) - for g in self.connected_components_subgraphs()), - key=lambda x: x.order()) + + return max((g.longest_path(s=s, t=t, + use_edge_labels=use_edge_labels, + algorithm=algorithm) + for g in self.connected_components_subgraphs()), + key=lambda x: x.order()) # Stupid cases # - Graph having <= 1 vertex. @@ -7958,8 +8222,7 @@ def weight(x): if edge_used[frozenset((u, v))])) if use_edge_labels: return sum(map(weight, g.edge_labels())), g - else: - return g + return g def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, maximize=False, algorithm='MILP', solver=None, verbose=0, @@ -8037,6 +8300,7 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, starting from vertex `(0, 0)` and ending at vertex `(2, 2)`, but no Hamiltonian path starting from `(0, 0)` and ending at `(0, 1)`:: + sage: # needs sage.numerical.mip sage: g = graphs.Grid2dGraph(3, 3) sage: g.hamiltonian_path() Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices @@ -8054,13 +8318,13 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, Empty and one-element graphs:: sage: g = Graph() - sage: g.hamiltonian_path() + sage: g.hamiltonian_path() # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the Hamiltonian path problem is not well defined for empty and one-element (di)graphs sage: g = Graph(1) - sage: g.hamiltonian_path() + sage: g.hamiltonian_path() # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the Hamiltonian path problem is not well defined @@ -8069,20 +8333,22 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, A non-connected (di)graph has no hamiltonian path:: sage: g = Graph(2) - sage: g.hamiltonian_path() is None + sage: g.hamiltonian_path() is None # needs sage.numerical.mip True - sage: g.hamiltonian_path(use_edge_labels=True) + sage: g.hamiltonian_path(use_edge_labels=True) # needs sage.numerical.mip (0, None) sage: g = DiGraph(2) - sage: g.hamiltonian_path() is None + sage: g.hamiltonian_path() is None # needs sage.numerical.mip True Asking for a minimum (resp., maximum) weight Hamiltonian path:: sage: G = Graph([(0, 1, 1), (0, 2, 2), (0, 3, 1), (1, 2, 1), (1, 3, 2), (2, 3, 1)]) - sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, maximize=False)[0]) + sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, # needs sage.numerical.mip + ....: maximize=False)[0]) 3 - sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, maximize=True)[0]) + sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, # needs sage.numerical.mip + ....: maximize=True)[0]) 5 Parameter ``algorithm`` must be either ``'backtrack'`` or ``'MILP'``:: @@ -8292,29 +8558,28 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, The Heawood graph is known to be Hamiltonian:: sage: g = graphs.HeawoodGraph() - sage: tsp = g.traveling_salesman_problem() - sage: tsp + sage: tsp = g.traveling_salesman_problem(); tsp # needs sage.numerical.mip TSP from Heawood graph: Graph on 14 vertices The solution to the TSP has to be connected:: - sage: tsp.is_connected() + sage: tsp.is_connected() # needs sage.numerical.mip True It must also be a `2`-regular graph:: - sage: tsp.is_regular(k=2) + sage: tsp.is_regular(k=2) # needs sage.numerical.mip True And obviously it is a subgraph of the Heawood graph:: - sage: tsp.is_subgraph(g, induced=False) + sage: tsp.is_subgraph(g, induced=False) # needs sage.numerical.mip True On the other hand, the Petersen Graph is known not to be Hamiltonian:: sage: g = graphs.PetersenGraph() - sage: tsp = g.traveling_salesman_problem() + sage: tsp = g.traveling_salesman_problem() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the given graph is not Hamiltonian @@ -8333,8 +8598,8 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, ....: g.add_edge(u, v) ....: g.set_edge_label(u, v, 2) - sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) - sage: sum( tsp.edge_labels() ) < 2 * 10 + sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum( tsp.edge_labels() ) < 2 * 10 # needs sage.numerical.mip True If we pick `1/2` instead of `2` as a cost for these new edges, they @@ -8343,17 +8608,20 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, sage: for u, v in cycle.edges(labels=None, sort=False): ....: g.set_edge_label(u,v,1/2) - sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) - sage: sum(tsp.edge_labels()) == (1/2) * 10 + sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum(tsp.edge_labels()) == (1/2) * 10 # needs sage.numerical.mip True Search for a minimum and a maximum weight Hamiltonian cycle:: + sage: # needs sage.numerical.mip sage: G = Graph([(0, 1, 1), (0, 2, 2), (0, 3, 1), (1, 2, 1), (1, 3, 2), (2, 3, 1)]) - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, maximize=False) + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, + ....: maximize=False) sage: print(sum(tsp.edge_labels())) 4 - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, maximize=True) + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, + ....: maximize=True) sage: print(sum(tsp.edge_labels())) 6 @@ -8371,9 +8639,10 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, sage: for u, v in graphs.CycleGraph(n).edges(labels=False, sort=False): ....: if not g.has_edge(u, v): ....: g.add_edge(u, v, ZZ.random_element(1,100000)) - sage: v1 = g.traveling_salesman_problem(constraint_generation=False, use_edge_labels=True) - sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) - sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) + sage: v1 = g.traveling_salesman_problem(constraint_generation=False, # needs sage.numerical.mip + ....: use_edge_labels=True) + sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) # needs sage.numerical.mip True Then for digraphs:: @@ -8387,13 +8656,15 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, sage: for u, v in digraphs.Circuit(n).edges(labels=False, sort=False): ....: if not g.has_edge(u, v): ....: g.add_edge(u, v, ZZ.random_element(1,100000)) - sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) - sage: v1 = g.traveling_salesman_problem(constraint_generation=False, use_edge_labels=True) - sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) + sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: v1 = g.traveling_salesman_problem(constraint_generation=False, # needs sage.numerical.mip + ....: use_edge_labels=True) + sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) # needs sage.numerical.mip True Simple tests for multiple edges and loops:: + sage: # needs sage.numerical.mip sage: G = DiGraph(multiedges=True, loops=True) sage: G.is_hamiltonian() False @@ -8421,6 +8692,7 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, Graphs on 2 vertices:: + sage: # needs sage.numerical.mip sage: Graph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() True sage: DiGraph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() @@ -8440,8 +8712,8 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, Check that weight 0 edges are handled correctly (see :trac:`16214`):: sage: G = Graph([(0, 1, 1), (0, 2, 0), (0, 3, 1), (1, 2, 1), (1, 3, 0), (2, 3, 1)]) - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) - sage: sum(tsp.edge_labels()) + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum(tsp.edge_labels()) # needs sage.numerical.mip 2 """ from sage.categories.sets_cat import EmptySetError @@ -8801,13 +9073,13 @@ def hamiltonian_cycle(self, algorithm='tsp', solver=None, constraint_generation= The Heawood Graph is known to be Hamiltonian :: sage: g = graphs.HeawoodGraph() - sage: g.hamiltonian_cycle() + sage: g.hamiltonian_cycle() # needs sage.numerical.mip TSP from Heawood graph: Graph on 14 vertices The Petersen Graph, though, is not :: sage: g = graphs.PetersenGraph() - sage: g.hamiltonian_cycle() + sage: g.hamiltonian_cycle() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the given graph is not Hamiltonian @@ -8854,8 +9126,7 @@ def hamiltonian_cycle(self, algorithm='tsp', solver=None, constraint_generation= from sage.graphs.generic_graph_pyx import find_hamiltonian as fh return fh(self) - else: - raise ValueError("algorithm (%s) should be 'tsp' or 'backtrack'." % (algorithm)) + raise ValueError("algorithm (%s) should be 'tsp' or 'backtrack'." % (algorithm)) def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, constraint_generation=True, *, integrality_tolerance=1e-3): @@ -8940,6 +9211,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, The necessary example:: + sage: # needs sage.numerical.mip sage: g = graphs.PetersenGraph() sage: fvs = g.feedback_vertex_set() sage: len(fvs) @@ -8954,6 +9226,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, of its neighbors removed: a feedback vertex set is in this situation a vertex cover:: + sage: # needs sage.numerical.mip sage: cycle = graphs.CycleGraph(5) sage: dcycle = DiGraph(cycle) sage: cycle.vertex_cover(value_only=True) @@ -8968,7 +9241,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, For a circuit, the minimum feedback arc set is clearly `1`:: sage: circuit = digraphs.Circuit(5) - sage: circuit.feedback_vertex_set(value_only=True) == 1 + sage: circuit.feedback_vertex_set(value_only=True) == 1 # needs sage.numerical.mip True TESTS: @@ -8976,19 +9249,25 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, Comparing with/without constraint generation:: sage: g = digraphs.RandomDirectedGNP(10, .3) - sage: x = g.feedback_vertex_set(value_only=True) - sage: y = g.feedback_vertex_set(value_only=True, - ....: constraint_generation=False) - sage: x == y + sage: x = g.feedback_vertex_set(value_only=True) # needs sage.numerical.mip + sage: y = g.feedback_vertex_set(value_only=True, # needs sage.numerical.mip + ....: constraint_generation=False) + sage: x == y # needs sage.numerical.mip True Bad algorithm:: sage: g = graphs.PetersenGraph() - sage: g.feedback_vertex_set(constraint_generation=False) + sage: g.feedback_vertex_set(constraint_generation=False) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the only implementation available for undirected graphs is with constraint_generation set to True + + :trac:`35889` is fixed:: + + sage: G = Graph([('A', 1)]) + sage: G.feedback_vertex_set() + [] """ if not constraint_generation and not self.is_directed(): raise ValueError("the only implementation available for " @@ -9037,8 +9316,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, if isok: if value_only: return Integer(self.order() - h.order()) - else: - return [v for v in self if b_val[v]] + return [v for v in self if b_val[v]] # There is a circuit left. Let's add the corresponding # constraint ! @@ -9080,8 +9358,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, b_sol = p.get_values(b, convert=bool, tolerance=integrality_tolerance) if value_only: return Integer(sum(1 for v in self if b_sol[v])) - else: - return [v for v in self if b_sol[v]] + return [v for v in self if b_sol[v]] def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, vertex_bound=False, algorithm=None, solver=None, verbose=0, @@ -9463,19 +9740,19 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler 4-nowhere zero flow:: sage: g = graphs.PetersenGraph() - sage: h = g.nowhere_zero_flow(k=5) - sage: sorted(set(h.edge_labels())) + sage: h = g.nowhere_zero_flow(k=5) # needs sage.numerical.mip + sage: sorted(set(h.edge_labels())) # needs sage.numerical.mip [1, 2, 3, 4] - sage: h = g.nowhere_zero_flow(k=3) + sage: h = g.nowhere_zero_flow(k=3) # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the problem has no feasible solution The de Bruijn digraph admits a 2-nowhere zero flow:: - sage: g = digraphs.DeBruijn(2, 3) - sage: h = g.nowhere_zero_flow(k=2) - sage: sorted(set(h.edge_labels())) + sage: g = digraphs.DeBruijn(2, 3) # needs sage.combinat + sage: h = g.nowhere_zero_flow(k=2) # needs sage.combinat sage.numerical.mip + sage: sorted(set(h.edge_labels())) # needs sage.combinat sage.numerical.mip [-1, 1] TESTS: @@ -9483,7 +9760,7 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler Empty graph:: sage: G = Graph() - sage: G.nowhere_zero_flow() + sage: G.nowhere_zero_flow() # needs sage.numerical.mip Digraph on 0 vertices Graph with one vertex:: @@ -9491,11 +9768,12 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler sage: G = Graph([[1], []]) sage: G Graph on 1 vertex - sage: G.nowhere_zero_flow() + sage: G.nowhere_zero_flow() # needs sage.numerical.mip Digraph on 1 vertex Loops and multiple edges:: + sage: # needs sage.numerical.mip sage: g = Graph([(0, 0), (0, 0)], loops=True, multiedges=True) sage: g.nowhere_zero_flow().edges(sort=True) [(0, 0, 1), (0, 0, 1)] @@ -9512,26 +9790,26 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler Multiple connected components:: sage: g = graphs.CycleGraph(3) * 2 - sage: h = g.nowhere_zero_flow() - sage: h.connected_components_sizes() + sage: h = g.nowhere_zero_flow() # needs sage.numerical.mip + sage: h.connected_components_sizes() # needs sage.numerical.mip [3, 3] (Di)Graphs with bridges:: sage: g = graphs.PathGraph(2) - sage: g.nowhere_zero_flow() + sage: g.nowhere_zero_flow() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: (di)graphs with bridges have no feasible solution sage: g = digraphs.Path(2) - sage: g.nowhere_zero_flow() + sage: g.nowhere_zero_flow() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: (di)graphs with bridges have no feasible solution Too small value of ``k``:: - sage: Graph().nowhere_zero_flow(k=1) + sage: Graph().nowhere_zero_flow(k=1) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: parameter 'k' must be at least 2 @@ -9852,22 +10130,22 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, matching in a graph, and to consider the paired vertices as terminals :: sage: g = graphs.PetersenGraph() - sage: matching = [(u,v) for u,v,_ in g.matching()] - sage: h = g.multicommodity_flow(matching) - sage: len(h) + sage: matching = [(u,v) for u,v,_ in g.matching()] # needs networkx + sage: h = g.multicommodity_flow(matching) # needs networkx + sage: len(h) # needs networkx 5 We could also have considered ``g`` as symmetric and computed the multicommodity flow in this version instead. In this case, however edges can be used in both directions at the same time:: - sage: h = DiGraph(g).multicommodity_flow(matching) - sage: len(h) + sage: h = DiGraph(g).multicommodity_flow(matching) # needs networkx + sage: len(h) # needs networkx 5 An exception is raised when the problem has no solution :: - sage: h = g.multicommodity_flow([(u,v,3) for u,v in matching]) + sage: h = g.multicommodity_flow([(u,v,3) for u,v in matching]) # needs networkx Traceback (most recent call last): ... EmptySetError: the multicommodity flow problem has no solution @@ -10010,19 +10288,21 @@ def _build_flow_graph(self, flow, integer): The method removes zero-cost flow cycles and updates the values accordingly:: - sage: g = digraphs.DeBruijn(2,3) - sage: flow = {('001', '010'): 1, ('010', '100'): 1, ('010', '101'): 1, ('101', '010'): 1} + sage: g = digraphs.DeBruijn(2,3) # needs sage.combinat + sage: flow = {('001', '010'): 1, ('010', '100'): 1, + ....: ('010', '101'): 1, ('101', '010'): 1} sage: flow_graph = g._build_flow_graph(flow, True) sage: flow_graph.edges(sort=True) [('001', '010', 1), ('010', '100', 1)] - sage: flow = {('001', '010'): 2, ('010', '101'): 3, ('101', '011'): 2, ('101', '010'): 1} + sage: flow = {('001', '010'): 2, ('010', '101'): 3, + ....: ('101', '011'): 2, ('101', '010'): 1} sage: flow_graph = g._build_flow_graph(flow, True) sage: flow_graph.edges(sort=True) [('001', '010', 2), ('010', '101', 2), ('101', '011', 2)] Isolated zero-cost flow cycles are also removed:: - sage: g = digraphs.DeBruijn(2, 3) + sage: g = digraphs.DeBruijn(2, 3) # needs sage.combinat sage: flow = {('000', '001'): 1, ('010', '101'): 1, ('101', '010'): 1} sage: flow_graph = g._build_flow_graph(flow, True) sage: flow_graph.edges(sort=True) @@ -10098,13 +10378,13 @@ def disjoint_routed_paths(self, pairs, solver=None, verbose=0, top-right corner to the bottom-right corner is easy:: sage: g = graphs.Grid2dGraph(5, 5) - sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (0, 4)), ((4, 4), (4, 0))]) + sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (0, 4)), ((4, 4), (4, 0))]) # needs sage.numerical.mip Though there is obviously no solution to the problem in which each corner is sending information to the opposite one:: sage: g = graphs.Grid2dGraph(5, 5) - sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (4, 4)), ((0, 4), (4, 0))]) + sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (4, 4)), ((0, 4), (4, 0))]) # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the disjoint routed paths do not exist @@ -10224,7 +10504,7 @@ def vertex_disjoint_paths(self, s, t, solver=None, verbose=0, In a complete bipartite graph :: sage: g = graphs.CompleteBipartiteGraph(2, 3) - sage: g.vertex_disjoint_paths(0, 1) + sage: g.vertex_disjoint_paths(0, 1) # needs sage.numerical.mip [[0, 2, 1], [0, 3, 1], [0, 4, 1]] TESTS: @@ -10232,9 +10512,9 @@ def vertex_disjoint_paths(self, s, t, solver=None, verbose=0, Fix issues reported in :trac:`22990`:: sage: g = digraphs.Path(2) - sage: g.vertex_disjoint_paths(0, 1) + sage: g.vertex_disjoint_paths(0, 1) # needs sage.numerical.mip [[0, 1]] - sage: g.vertex_disjoint_paths(1, 0) + sage: g.vertex_disjoint_paths(1, 0) # needs sage.numerical.mip [] """ obj, flow_graph = self.flow(s, t, value_only=False, integer=True, use_edge_labels=False, @@ -10327,54 +10607,55 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, EXAMPLES:: sage: G = graphs.CycleGraph(4) - sage: G.pagerank(algorithm="Networkx") + sage: G.pagerank(algorithm="Networkx") # needs networkx {0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25} - sage: G.pagerank(alpha=0.50, algorithm="igraph") # optional - python_igraph # abs tol 1e-9 + sage: G.pagerank(alpha=0.50, algorithm="igraph") # abs tol 1e-9, optional - python_igraph {0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25} - sage: G = Graph([(1, 2, 40), (2, 3, 50), (3, 4, 60), (1, 4, 70), (4, 5, 80), (5, 6, 20)]) - sage: G.pagerank(algorithm="NetworkX") # abs tol 1e-9 + sage: G = Graph([(1, 2, 40), (2, 3, 50), (3, 4, 60), + ....: (1, 4, 70), (4, 5, 80), (5, 6, 20)]) + sage: G.pagerank(algorithm="NetworkX") # abs tol 1e-9 # needs networkx {1: 0.16112205885619563, 2: 0.1619531043247219, 3: 0.16112205885619563, 4: 0.2374999999999999, 5: 0.17775588228760858, 6: 0.100546895675278} - sage: G.pagerank(algorithm="NetworkX", by_weight=True) # abs tol 1e-9 + sage: G.pagerank(algorithm="NetworkX", by_weight=True) # abs tol 1e-9 # needs networkx {1: 0.16459583718588994, 2: 0.13977928595154515, 3: 0.16539840184339605, 4: 0.3063198690713853, 5: 0.1700057609707141, 6: 0.05390084497706962} - sage: G.pagerank(algorithm="Scipy") # abs tol 1e-9 + sage: G.pagerank(algorithm="Scipy") # abs tol 1e-9 # needs networkx scipy {1: 0.16112205885619563, 2: 0.1619531043247219, 3: 0.16112205885619563, 4: 0.2374999999999999, 5: 0.17775588228760858, 6: 0.100546895675278} - sage: G.pagerank(algorithm="Scipy", by_weight=True) # abs tol 1e-9 + sage: G.pagerank(algorithm="Scipy", by_weight=True) # abs tol 1e-9 # needs networkx scipy {1: 0.16459583718588994, 2: 0.13977928595154515, 3: 0.16539840184339605, 4: 0.3063198690713853, 5: 0.1700057609707141, 6: 0.05390084497706962} - sage: G.pagerank(algorithm="igraph") # optional - python_igraph # abs tol 1e-9 + sage: G.pagerank(algorithm="igraph") # abs tol 1e-9, optional - python_igraph {1: 0.16112198303979128, 2: 0.16195368558382262, 3: 0.16112198303979125, 4: 0.23749999999999993, 5: 0.17775603392041744, 6: 0.10054631441617742} - sage: G.pagerank() # abs tol 1e-9 + sage: G.pagerank() # abs tol 1e-9 # needs networkx {1: 0.16112205885619563, 2: 0.1619531043247219, 3: 0.16112205885619563, 4: 0.2374999999999999, 5: 0.17775588228760858, 6: 0.100546895675278} - sage: G.pagerank(by_weight=True) # abs tol 1e-9 + sage: G.pagerank(by_weight=True) # abs tol 1e-9 # needs networkx {1: 0.16459583718588994, 2: 0.13977928595154515, 3: 0.16539840184339605, @@ -10385,7 +10666,8 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, TESTS:: sage: G = Graph([(1, 2), (2, 3), (3, 4), (1, 3)]) - sage: G.pagerank(algorithm="NetworkX", personalization={1:0, 2:3, 3:-2, 4:-1}) + sage: G.pagerank(algorithm="NetworkX", # needs networkx + ....: personalization={1:0, 2:3, 3:-2, 4:-1}) Traceback (most recent call last): ... ZeroDivisionError... @@ -10428,8 +10710,8 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, I = self.igraph_graph() page_rank = I.pagerank(damping=alpha, weights=weight) return {v: page_rank[i] for i, v in enumerate(self)} - else: - raise NotImplementedError("only 'NetworkX', 'Scipy', and 'igraph' are supported") + + raise NotImplementedError("only 'NetworkX', 'Scipy', and 'igraph' are supported") # Vertex handlers @@ -10522,7 +10804,8 @@ def delete_vertex(self, vertex, in_order=False): EXAMPLES:: sage: G = Graph(graphs.WheelGraph(9)) - sage: G.delete_vertex(0); G.show() + sage: G.delete_vertex(0) + sage: G.show() # needs sage.plot :: @@ -11149,19 +11432,15 @@ def neighbor_iterator(self, vertex, closed=False): for u in self._backend.iterator_nbrs(vertex): yield u - def vertices(self, sort=None, key=None, degree=None, vertex_property=None): + def vertices(self, sort=False, key=None, degree=None, vertex_property=None): r""" Return a list of the vertices. INPUT: - - ``sort`` -- boolean (default: ``None``); if ``True``, vertices are - sorted according to the default ordering - - As of :trac:`22349`, this argument must be explicitly - specified (unless a ``key`` is given); otherwise a warning - is printed and ``sort=True`` is used. The default will - eventually be changed to ``False``. + - ``sort`` -- boolean (default: ``False``); whether to sort vertices + according the ordering specified with parameter ``key``. If ``False`` + (default), vertices are not sorted. - ``key`` -- a function (default: ``None``); a function that takes a vertex as its one argument and returns a value that can be used for @@ -11198,13 +11477,14 @@ def vertices(self, sort=None, key=None, degree=None, vertex_property=None): If you do not care about sorted output and you are concerned about the time taken to sort, consider the following alternative:: - sage: timeit V = P.vertices(sort=True) # not tested + sage: # not tested + sage: timeit V = P.vertices(sort=True) 625 loops, best of 3: 3.86 [micro]s per loop - sage: timeit V = P.vertices(sort=False) # not tested + sage: timeit V = P.vertices(sort=False) 625 loops, best of 3: 2.06 [micro]s per loop - sage: timeit V = list(P.vertex_iterator()) # not tested + sage: timeit V = list(P.vertex_iterator()) 625 loops, best of 3: 2.05 [micro]s per loop - sage: timeit('V = list(P)') # not tested + sage: timeit('V = list(P)') 625 loops, best of 3: 1.98 [micro]s per loop We illustrate various ways to use a ``key`` to sort the list:: @@ -11229,11 +11509,12 @@ def vertices(self, sort=None, key=None, degree=None, vertex_property=None): are first-class objects in Python, we can specify precisely the function from the Sage library that we wish to use as the key:: + sage: # needs sage.libs.flint sage: t = polygen(QQ, 't') sage: K = Graph({5*t: [t^2], t^2: [t^2+2], t^2+2: [4*t^2-6], 4*t^2-6: [5*t]}) - sage: dsc = sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint.discriminant - sage: verts = K.vertices(sort=True, key=dsc) - sage: verts + sage: from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint + sage: dsc = Polynomial_rational_flint.discriminant + sage: verts = K.vertices(sort=True, key=dsc); verts [t^2 + 2, t^2, 5*t, 4*t^2 - 6] sage: [x.discriminant() for x in verts] [-8, 0, 1, 96] @@ -11247,20 +11528,7 @@ def vertices(self, sort=None, key=None, degree=None, vertex_property=None): Traceback (most recent call last): ... ValueError: sort keyword is False, yet a key function is given - - Deprecation warning for ``sort=None`` (:trac:`22349`):: - - sage: G = graphs.HouseGraph() - sage: G.vertices() - doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future - See https://github.com/sagemath/sage/issues/22349 for details. - [0, 1, 2, 3, 4] """ - if sort is None: - if key is None: - deprecation(22349, "parameter 'sort' will be set to False by default in the future") - sort = True - if (not sort) and key: raise ValueError('sort keyword is False, yet a key function is given') @@ -12186,7 +12454,7 @@ def has_edge(self, u, v=None, label=None): label = None return self._backend.has_edge(u, v, label) - def edges(self, vertices=None, labels=True, sort=None, key=None, + def edges(self, vertices=None, labels=True, sort=False, key=None, ignore_direction=False, sort_vertices=True): r""" Return a :class:`~EdgesView` of edges. @@ -12210,13 +12478,10 @@ def edges(self, vertices=None, labels=True, sort=None, key=None, - ``labels`` -- boolean (default: ``True``); if ``False``, each edge is simply a pair ``(u, v)`` of vertices - - ``sort`` -- boolean (default: ``None``); if ``True``, edges are sorted - according to the default ordering - - As of :trac:`22349`, this argument must be explicitly - specified (unless a ``key`` is given); otherwise a warning - is printed and ``sort=True`` is used. The default will - eventually be changed to ``False``. + - ``sort`` -- boolean (default: ``False``); whether to sort edges + according the ordering specified with parameter ``key``. If ``False`` + (default), edges are not sorted. This is the fastest and less memory + consuming method for iterating over edges. - ``key`` -- a function (default: ``None``); a function that takes an edge (a pair or a triple, according to the ``labels`` keyword) as its @@ -12312,7 +12577,7 @@ def edges(self, vertices=None, labels=True, sort=None, key=None, ....: G.set_edge_label(e[0], e[1], chr(ord('A') + e[0] + 5 * e[1])) sage: G.edges(sort=True) [(0, 1, 'F'), (0, 4, 'U'), (1, 2, 'L'), (2, 3, 'R'), (3, 4, 'X')] - sage: G.edges(key=lambda x: x[2]) + sage: G.edges(sort=True, key=lambda x: x[2]) [(0, 1, 'F'), (1, 2, 'L'), (2, 3, 'R'), (0, 4, 'U'), (3, 4, 'X')] We can restrict considered edges to those incident to a given set:: @@ -12363,27 +12628,14 @@ def edges(self, vertices=None, labels=True, sort=None, key=None, sage: G.edge_label(0, 1)[0] += 1 sage: G.edges(sort=True) [(0, 1, [8]), (0, 2, [7])] - - Deprecation warning for ``sort=None`` (:trac:`27408`):: - - sage: G = graphs.HouseGraph() - sage: G.edges(sort=None) - doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future - See https://github.com/sagemath/sage/issues/27408 for details. - [(0, 1, None), (0, 2, None), (1, 3, None), (2, 3, None), (2, 4, None), (3, 4, None)] """ - if sort is None: - if key is None: - deprecation(27408, "parameter 'sort' will be set to False by default in the future") - sort = True - if vertices is not None and vertices in self: vertices = [vertices] return EdgesView(self, vertices=vertices, labels=labels, sort=sort, key=key, ignore_direction=ignore_direction, sort_vertices=sort_vertices) - def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): + def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False, key=None): r""" Return a list of edges ``(u,v,l)`` with ``u`` in ``vertices1`` and ``v`` in ``vertices2``. @@ -12401,6 +12653,10 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): - ``sort`` -- boolean (default: ``False``); whether to sort the result + - ``key`` -- a function (default: ``None``); a function that takes an + edge as its one argument and returns a value that can be used for + comparisons in the sorting algorithm (we must have ``sort=True``) + EXAMPLES:: sage: K = graphs.CompleteBipartiteGraph(9, 3) @@ -12425,6 +12681,23 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): sage: D.edge_boundary([0], labels=False, sort=True) [(0, 1), (0, 2)] + Using the ``key`` argument to order multiple edges of incomparable + types (see :trac:`35903`):: + + sage: G = Graph([(1, 'A', 4), (1, 2, 3)]) + sage: G.edge_boundary([1], sort=True) + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for <: 'Integer Ring' and '<class 'str'>' + sage: G.edge_boundary([1], sort=True, key=str) + [('A', 1, 4), (1, 2, 3)] + sage: G.edge_boundary([1], sort=True, key=lambda e:e[2]) + [(1, 2, 3), ('A', 1, 4)] + sage: G.edge_boundary([1], labels=False, sort=True, key=lambda e:e[2]) + Traceback (most recent call last): + ... + IndexError: tuple index out of range + TESTS:: sage: G = graphs.DiamondGraph() @@ -12434,7 +12707,14 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): [] sage: G.edge_boundary([2], [0]) [(0, 2, None)] + sage: G.edge_boundary([2], [0], sort=False, key=str) + Traceback (most recent call last): + ... + ValueError: sort keyword is False, yet a key function is given """ + if (not sort) and key: + raise ValueError('sort keyword is False, yet a key function is given') + vertices1 = set(v for v in vertices1 if v in self) if self._directed: if vertices2 is not None: @@ -12454,7 +12734,7 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): output = [e for e in self.edges(vertices=vertices1, labels=labels, sort=False) if e[1] not in vertices1 or e[0] not in vertices1] if sort: - output.sort() + return sorted(output, key=key) return output def edge_iterator(self, vertices=None, labels=True, ignore_direction=False, sort_vertices=True): @@ -12546,8 +12826,7 @@ def edge_iterator(self, vertices=None, labels=True, ignore_direction=False, sort return self._backend.iterator_out_edges(vertices, labels) elif not sort_vertices: return self._backend.iterator_unsorted_edges(vertices, labels) - else: - return self._backend.iterator_edges(vertices, labels) + return self._backend.iterator_edges(vertices, labels) def edges_incident(self, vertices=None, labels=True, sort=False): r""" @@ -12823,6 +13102,7 @@ def degree(self, vertices=None, labels=False): returned list is the degree of the `i`-th vertex in the list ``list(self)``:: + sage: # needs sage.combinat sage: D = digraphs.DeBruijn(4, 2) sage: D.delete_vertex('20') sage: print(D.degree()) @@ -12836,8 +13116,7 @@ def degree(self, vertices=None, labels=False): return dict(self.degree_iterator(vertices, labels)) elif vertices in self and not labels: return next(self.degree_iterator(vertices, labels)) - else: - return list(self.degree_iterator(vertices, labels)) + return list(self.degree_iterator(vertices, labels)) def average_degree(self): r""" @@ -12967,11 +13246,11 @@ def degree_iterator(self, vertices=None, labels=False): When ``vertices=None`` yields values in the order of ``list(D)``:: sage: V = list(D) - sage: D = digraphs.DeBruijn(4, 2) - sage: D.delete_vertex('20') - sage: print(list(D.degree_iterator())) + sage: D = digraphs.DeBruijn(4, 2) # needs sage.combinat + sage: D.delete_vertex('20') # needs sage.combinat + sage: print(list(D.degree_iterator())) # needs sage.combinat [7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8] - sage: print([D.degree(v) for v in D]) + sage: print([D.degree(v) for v in D]) # needs sage.combinat [7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8] """ if vertices is None: @@ -13231,10 +13510,9 @@ def subgraph(self, vertices=None, edges=None, inplace=False, inplace=inplace, edge_property=edge_property, immutable=immutable) - else: - return self._subgraph_by_adding(vertices=vertices, edges=edges, - edge_property=edge_property, - immutable=immutable) + return self._subgraph_by_adding(vertices=vertices, edges=edges, + edge_property=edge_property, + immutable=immutable) def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, immutable=None): r""" @@ -13602,19 +13880,20 @@ def subgraph_search(self, G, induced=False): The Petersen graph contains the path graph `P_5`:: sage: g = graphs.PetersenGraph() - sage: h1 = g.subgraph_search(graphs.PathGraph(5)); h1 + sage: h1 = g.subgraph_search(graphs.PathGraph(5)); h1 # needs sage.modules Subgraph of (Petersen graph): Graph on 5 vertices - sage: h1.vertices(sort=True); h1.edges(sort=True, labels=False) + sage: h1.vertices(sort=True); h1.edges(sort=True, labels=False) # needs sage.modules [0, 1, 2, 3, 4] [(0, 1), (1, 2), (2, 3), (3, 4)] - sage: I1 = g.subgraph_search(graphs.PathGraph(5), induced=True); I1 + sage: I1 = g.subgraph_search(graphs.PathGraph(5), induced=True); I1 # needs sage.modules Subgraph of (Petersen graph): Graph on 5 vertices - sage: I1.vertices(sort=True); I1.edges(sort=True, labels=False) + sage: I1.vertices(sort=True); I1.edges(sort=True, labels=False) # needs sage.modules [0, 1, 2, 3, 8] [(0, 1), (1, 2), (2, 3), (3, 8)] It also contains the claw `K_{1,3}`:: + sage: # needs sage.modules sage: h2 = g.subgraph_search(graphs.ClawGraph()); h2 Subgraph of (Petersen graph): Graph on 4 vertices sage: h2.vertices(sort=True); h2.edges(sort=True, labels=False) @@ -13629,72 +13908,72 @@ def subgraph_search(self, G, induced=False): Of course the induced copies are isomorphic to the graphs we were looking for:: - sage: I1.is_isomorphic(graphs.PathGraph(5)) + sage: I1.is_isomorphic(graphs.PathGraph(5)) # needs sage.modules True - sage: I2.is_isomorphic(graphs.ClawGraph()) + sage: I2.is_isomorphic(graphs.ClawGraph()) # needs sage.modules True However, the Petersen graph does not contain a subgraph isomorphic to `K_3`:: - sage: g.subgraph_search(graphs.CompleteGraph(3)) is None + sage: g.subgraph_search(graphs.CompleteGraph(3)) is None # needs sage.modules True Nor does it contain a nonempty induced subgraph isomorphic to `P_6`:: - sage: g.subgraph_search(graphs.PathGraph(6), induced=True) is None + sage: g.subgraph_search(graphs.PathGraph(6), induced=True) is None # needs sage.modules True The empty graph is a subgraph of every graph:: - sage: g.subgraph_search(graphs.EmptyGraph()) + sage: g.subgraph_search(graphs.EmptyGraph()) # needs sage.modules Graph on 0 vertices - sage: g.subgraph_search(graphs.EmptyGraph(), induced=True) + sage: g.subgraph_search(graphs.EmptyGraph(), induced=True) # needs sage.modules Graph on 0 vertices The subgraph may just have edges missing:: sage: k3 = graphs.CompleteGraph(3); p3 = graphs.PathGraph(3) sage: k3.relabel(list('abc')) - sage: s = k3.subgraph_search(p3) - sage: s.edges(sort=True, labels=False) + sage: s = k3.subgraph_search(p3) # needs sage.modules + sage: s.edges(sort=True, labels=False) # needs sage.modules [('a', 'b'), ('b', 'c')] Of course, `P_3` is not an induced subgraph of `K_3`, though:: sage: k3 = graphs.CompleteGraph(3); p3 = graphs.PathGraph(3) sage: k3.relabel(list('abc')) - sage: k3.subgraph_search(p3, induced=True) is None + sage: k3.subgraph_search(p3, induced=True) is None # needs sage.modules True If the graph has labels, the labels are just ignored:: sage: g.set_vertex(0, 'foo') - sage: c = g.subgraph_search(graphs.PathGraph(5)) - sage: c.get_vertices() + sage: c = g.subgraph_search(graphs.PathGraph(5)) # needs sage.modules + sage: c.get_vertices() # needs sage.modules {0: 'foo', 1: None, 2: None, 3: None, 4: None} TESTS: Inside of a small graph (:trac:`13906`):: - sage: Graph(5).subgraph_search(Graph(1)) + sage: Graph(5).subgraph_search(Graph(1)) # needs sage.modules Graph on 1 vertex For labelled edges (:trac:`14999`):: sage: G = graphs.CompleteGraph(10) - sage: C = G.subgraph_search(graphs.CycleGraph(4)) - sage: C.size() + sage: C = G.subgraph_search(graphs.CycleGraph(4)) # needs sage.modules + sage: C.size() # needs sage.modules 4 - sage: C.edges(sort=True) + sage: C.edges(sort=True) # needs sage.modules [(0, 1, None), (0, 3, None), (1, 2, None), (2, 3, None)] sage: for (u,v) in G.edges(sort=True, labels=False): ....: G.set_edge_label(u, v, u) - sage: C = G.subgraph_search(graphs.CycleGraph(4)) - sage: C.edges(sort=True) + sage: C = G.subgraph_search(graphs.CycleGraph(4)) # needs sage.modules + sage: C.edges(sort=True) # needs sage.modules [(0, 1, 0), (0, 3, 0), (1, 2, 1), (2, 3, 2)] """ @@ -13735,12 +14014,12 @@ def subgraph_search_count(self, G, induced=False): Counting the number of paths `P_5` in a PetersenGraph:: sage: g = graphs.PetersenGraph() - sage: g.subgraph_search_count(graphs.PathGraph(5)) + sage: g.subgraph_search_count(graphs.PathGraph(5)) # needs sage.modules 240 Requiring these subgraphs be induced:: - sage: g.subgraph_search_count(graphs.PathGraph(5), induced=True) + sage: g.subgraph_search_count(graphs.PathGraph(5), induced=True) # needs sage.modules 120 If we define the graph `T_k` (the transitive tournament on `k` vertices) @@ -13749,36 +14028,36 @@ def subgraph_search_count(self, G, induced=False): `0`:: sage: T5 = digraphs.TransitiveTournament(5) - sage: T5.subgraph_search_count(digraphs.Circuit(3)) + sage: T5.subgraph_search_count(digraphs.Circuit(3)) # needs sage.modules 0 If we count instead the number of `T_3` in `T_5`, we expect the answer to be `\binom{5}{3}`:: sage: T3 = digraphs.TransitiveTournament(3) - sage: T5.subgraph_search_count(T3) + sage: T5.subgraph_search_count(T3) # needs sage.modules 10 - sage: binomial(5,3) + sage: binomial(5,3) # needs sage.symbolic 10 - sage: T3.is_isomorphic(T5.subgraph(vertices=[0, 1, 2])) + sage: T3.is_isomorphic(T5.subgraph(vertices=[0, 1, 2])) # needs sage.modules True The empty graph is a subgraph of every graph:: - sage: g.subgraph_search_count(graphs.EmptyGraph()) + sage: g.subgraph_search_count(graphs.EmptyGraph()) # needs sage.modules 1 If the graph has vertex labels or edge labels, the label is just ignored:: sage: g.set_vertex(0, 'foo') - sage: g.subgraph_search_count(graphs.PathGraph(5)) + sage: g.subgraph_search_count(graphs.PathGraph(5)) # needs sage.modules 240 TESTS: Inside of a small graph (:trac:`13906`):: - sage: Graph(5).subgraph_search_count(Graph(1)) + sage: Graph(5).subgraph_search_count(Graph(1)) # needs sage.modules 5 """ from sage.graphs.generic_graph_pyx import SubgraphSearch @@ -13845,7 +14124,7 @@ def subgraph_search_iterator(self, G, induced=False, return_graphs=True): sage: g = graphs.PathGraph(5) sage: P3 = graphs.PathGraph(3) - sage: for p in g.subgraph_search_iterator(P3, return_graphs=False): + sage: for p in g.subgraph_search_iterator(P3, return_graphs=False): # needs sage.modules ....: print(p) [0, 1, 2] [1, 2, 3] @@ -13853,7 +14132,7 @@ def subgraph_search_iterator(self, G, induced=False, return_graphs=True): [2, 3, 4] [3, 2, 1] [4, 3, 2] - sage: for p in g.subgraph_search_iterator(P3, return_graphs=True): + sage: for p in g.subgraph_search_iterator(P3, return_graphs=True): # needs sage.modules ....: print(p) Subgraph of (Path graph) Subgraph of (Path graph) @@ -13861,13 +14140,13 @@ def subgraph_search_iterator(self, G, induced=False, return_graphs=True): Subgraph of (Path graph) Subgraph of (Path graph) Subgraph of (Path graph) - sage: all(h.is_isomorphic(P3) for h in g.subgraph_search_iterator(P3)) + sage: all(h.is_isomorphic(P3) for h in g.subgraph_search_iterator(P3)) # needs sage.modules True If the graph has vertex labels or edge labels, the label is just ignored:: sage: g.set_vertex(0, 'foo') - sage: for p in g.subgraph_search_iterator(P3, return_graphs=False): + sage: for p in g.subgraph_search_iterator(P3, return_graphs=False): # needs sage.modules ....: print(p) [0, 1, 2] [1, 2, 3] @@ -13880,45 +14159,47 @@ def subgraph_search_iterator(self, G, induced=False, return_graphs=True): sage: H = graphs.HouseGraph() sage: P4 = graphs.PathGraph(4) - sage: all(h.is_isomorphic(P4) for h in H.subgraph_search_iterator(P4, induced=True)) + sage: all(h.is_isomorphic(P4) # needs sage.modules + ....: for h in H.subgraph_search_iterator(P4, induced=True)) True - sage: sum(1 for h in H.subgraph_search_iterator(P4, induced=True)) + sage: sum(1 for h in H.subgraph_search_iterator(P4, induced=True)) # needs sage.modules 4 - sage: sum(1 for h in H.subgraph_search_iterator(P4, induced=False)) + sage: sum(1 for h in H.subgraph_search_iterator(P4, induced=False)) # needs sage.modules 20 Search for subdigraphs:: sage: H = digraphs.Complete(5) sage: P4 = digraphs.Path(4) - sage: sum(1 for _ in H.subgraph_search_iterator(P4, induced=True)) + sage: sum(1 for _ in H.subgraph_search_iterator(P4, induced=True)) # needs sage.modules 0 - sage: sum(1 for _ in H.subgraph_search_iterator(P4, induced=False)) + sage: sum(1 for _ in H.subgraph_search_iterator(P4, induced=False)) # needs sage.modules 120 This method also works for bipartite graphs:: sage: K33 = BipartiteGraph(graphs.CompleteBipartiteGraph(3, 3)) sage: K22 = BipartiteGraph(graphs.CompleteBipartiteGraph(2, 2)) - sage: sum(1 for _ in K33.subgraph_search_iterator(K22)) + sage: sum(1 for _ in K33.subgraph_search_iterator(K22)) # needs sage.modules 72 TESTS: Inside of a small graph (:trac:`13906`):: - sage: list(Graph(5).subgraph_search_iterator(Graph(1))) - [Graph on 1 vertex, Graph on 1 vertex, Graph on 1 vertex, Graph on 1 vertex, Graph on 1 vertex] + sage: list(Graph(5).subgraph_search_iterator(Graph(1))) # needs sage.modules + [Graph on 1 vertex, Graph on 1 vertex, Graph on 1 vertex, + Graph on 1 vertex, Graph on 1 vertex] Check that the behavior of the method is consistent (:trac:`34004`):: sage: g = graphs.CycleGraph(3) - sage: for i in range(3): + sage: for i in range(3): # needs sage.modules ....: g.subgraph_search_iterator(graphs.PathGraph(i)) <generator object GenericGraph.subgraph_search_iterator... <generator object GenericGraph.subgraph_search_iterator... <generator object GenericGraph.subgraph_search_iterator... - sage: for i in range(3): + sage: for i in range(3): # needs sage.modules ....: g.subgraph_search_iterator(graphs.PathGraph(i), return_graphs=False) <generator object GenericGraph.subgraph_search_iterator... <generator object GenericGraph.subgraph_search_iterator... @@ -13926,39 +14207,39 @@ def subgraph_search_iterator(self, G, induced=False, return_graphs=True): Corner cases:: - sage: list(Graph().subgraph_search_iterator(graphs.PathGraph(2))) + sage: list(Graph().subgraph_search_iterator(graphs.PathGraph(2))) # needs sage.modules [] - sage: list(Graph(1).subgraph_search_iterator(graphs.PathGraph(2))) + sage: list(Graph(1).subgraph_search_iterator(graphs.PathGraph(2))) # needs sage.modules [] - sage: list(Graph(2).subgraph_search_iterator(graphs.PathGraph(2))) + sage: list(Graph(2).subgraph_search_iterator(graphs.PathGraph(2))) # needs sage.modules [] Check the type of yielded graphs:: sage: H = graphs.HouseGraph() sage: P4 = graphs.PathGraph(4) - sage: for g in H.subgraph_search_iterator(P4, return_graphs=True): + sage: for g in H.subgraph_search_iterator(P4, return_graphs=True): # needs sage.modules ....: print(type(g)) ....: break <class 'sage.graphs.graph.Graph'> sage: K4 = digraphs.Complete(4) sage: K3 = digraphs.Complete(3) - sage: for g in K4.subgraph_search_iterator(K3, return_graphs=True): + sage: for g in K4.subgraph_search_iterator(K3, return_graphs=True): # needs sage.modules ....: print(type(g)) ....: break <class 'sage.graphs.digraph.DiGraph'> sage: K33 = BipartiteGraph(graphs.CompleteBipartiteGraph(3, 3)) sage: K22 = BipartiteGraph(graphs.CompleteBipartiteGraph(2, 2)) - sage: for b in K33.subgraph_search_iterator(K22, return_graphs=True): + sage: for b in K33.subgraph_search_iterator(K22, return_graphs=True): # needs sage.modules ....: print(type(b)) ....: break <class 'sage.graphs.bipartite_graph.BipartiteGraph'> sage: P5 = graphs.PathGraph(5) - sage: for b in K33.subgraph_search_iterator(P5, return_graphs=True): + sage: for b in K33.subgraph_search_iterator(P5, return_graphs=True): # needs sage.modules ....: print(type(b)) ....: break <class 'sage.graphs.bipartite_graph.BipartiteGraph'> - sage: for b in Graph(K33).subgraph_search_iterator(K22, return_graphs=True): + sage: for b in Graph(K33).subgraph_search_iterator(K22, return_graphs=True): # needs sage.modules ....: print(type(b)) ....: break <class 'sage.graphs.graph.Graph'> @@ -14024,7 +14305,7 @@ def is_chordal(self, certificate=False, algorithm="B"): cycle of length at least 4). Alternatively, chordality can be defined using a Perfect Elimination - Order : + Order: A Perfect Elimination Order of a graph `G` is an ordering `v_1,...,v_n` of its vertex set such that for all `i`, the neighbors of `v_i` whose @@ -14059,20 +14340,18 @@ def is_chordal(self, certificate=False, algorithm="B"): a hole. - ``algorithm`` -- string (default: ``"B"``); the algorithm to choose - among ``"A"`` or ``"B"`` (see next section). While they will agree on - whether the given graph is chordal, they cannot be expected to return - the same certificates. + among ``"A"`` or ``"B"``. While they will agree on whether the given + graph is chordal, they cannot be expected to return the same + certificates. ALGORITHM: - This algorithm works through computing a Lex BFS on the graph, then - checking whether the order is a Perfect Elimination Order by computing - for each vertex `v` the subgraph induces by its non-deleted neighbors, - then testing whether this graph is complete. - - This problem can be solved in `O(m)` [RT1975]_ ( where `m` is the number - of edges in the graph ) but this implementation is not linear because of - the complexity of Lex BFS. + This method implements the algorithm proposed in [RT1975]_ for the + recognition of chordal graphs with time complexity in `O(m)`. The + algorithm works through computing a Lex BFS on the graph, then checking + whether the order is a Perfect Elimination Order by computing for each + vertex `v` the subgraph induced by its non-deleted neighbors, then + testing whether this graph is complete. EXAMPLES: @@ -14086,20 +14365,21 @@ def is_chordal(self, certificate=False, algorithm="B"): The same goes with the product of a random lobster (which is a tree) and a Complete Graph :: - sage: g = graphs.RandomLobster(10, .5, .5).lexicographic_product(graphs.CompleteGraph(3)) - sage: g.is_chordal() + sage: grl = graphs.RandomLobster(10, .5, .5) # needs networkx + sage: g = grl.lexicographic_product(graphs.CompleteGraph(3)) # needs networkx + sage: g.is_chordal() # needs networkx True The disjoint union of chordal graphs is still chordal:: - sage: (2 * g).is_chordal() + sage: (2 * g).is_chordal() # needs networkx True Let us check the certificate given by Sage is indeed a perfect elimination order:: - sage: _, peo = g.is_chordal(certificate=True) - sage: for v in peo: + sage: _, peo = g.is_chordal(certificate=True) # needs networkx + sage: for v in peo: # needs networkx ....: if not g.subgraph(g.neighbors(v)).is_clique(): ....: raise ValueError("this should never happen") ....: g.delete_vertex(v) @@ -14185,7 +14465,7 @@ def is_chordal(self, certificate=False, algorithm="B"): continue x = next(t_peo.neighbor_out_iterator(v)) - S = self.neighbors(x) + [x] + S = self.neighbors(x, closed=True) if not frozenset(g.neighbor_iterator(v)).issubset(S): @@ -14221,7 +14501,7 @@ def is_chordal(self, certificate=False, algorithm="B"): peo, t_peo = self.lex_BFS(reverse=True, tree=True) # Remembering the (closed) neighborhoods of each vertex - neighbors_subsets = {v: frozenset(self.neighbors(v) + [v]) for v in g} + neighbors_subsets = {v: frozenset(self.neighbor_iterator(v, closed=True)) for v in g} pos_in_peo = dict(zip(peo, range(self.order()))) # Iteratively removing vertices and checking everything is fine. @@ -14281,9 +14561,7 @@ def is_chordal(self, certificate=False, algorithm="B"): # 2- The graph is chordal if certificate: return True, peo - - else: - return True + return True def is_circulant(self, certificate=False): r""" @@ -14319,27 +14597,27 @@ def is_circulant(self, certificate=False): The Petersen graph is not a circulant graph:: sage: g = graphs.PetersenGraph() - sage: g.is_circulant() + sage: g.is_circulant() # needs sage.groups False A cycle is obviously a circulant graph, but several sets of parameters can be used to define it:: sage: g = graphs.CycleGraph(5) - sage: g.is_circulant(certificate=True) + sage: g.is_circulant(certificate=True) # needs sage.groups (True, [(5, [1, 4]), (5, [2, 3])]) The same goes for directed graphs:: sage: g = digraphs.Circuit(5) - sage: g.is_circulant(certificate=True) + sage: g.is_circulant(certificate=True) # needs sage.groups (True, [(5, [1]), (5, [3]), (5, [2]), (5, [4])]) With this information, it is very easy to create (and plot) all possible drawings of a circulant graph:: sage: g = graphs.CirculantGraph(13, [2, 3, 10, 11]) - sage: for param in g.is_circulant(certificate=True)[1]: + sage: for param in g.is_circulant(certificate=True)[1]: # needs sage.groups ....: graphs.CirculantGraph(*param) Circulant graph ([2, 3, 10, 11]): Graph on 13 vertices Circulant graph ([1, 5, 8, 12]): Graph on 13 vertices @@ -14347,7 +14625,8 @@ def is_circulant(self, certificate=False): TESTS:: - sage: digraphs.DeBruijn(3,1).is_circulant(certificate=True) + sage: # needs sage.groups + sage: digraphs.DeBruijn(3,1).is_circulant(certificate=True) # needs sage.combinat (True, [(3, [0, 1, 2])]) sage: Graph(1).is_circulant(certificate=True) (True, (1, [])) @@ -14361,8 +14640,7 @@ def is_circulant(self, certificate=False): if self.order() <= 1: if certificate: return (True, (self.order(), [0] if self.size() else [])) - else: - return True + return True certif_list = [] @@ -14401,11 +14679,9 @@ def is_circulant(self, certificate=False): if not certificate: return False - else: - if certif_list: - return (True, certif_list) - else: - return (False, None) + if certif_list: + return (True, certif_list) + return (False, None) def is_interval(self, certificate=False): r""" @@ -14587,7 +14863,7 @@ def is_gallai_tree(self): a special vertex `-1` is a ''star-shaped'' Gallai tree:: sage: g = 8 * graphs.CompleteGraph(6) - sage: g.add_edges([(-1, c[0]) for c in g.connected_components()]) + sage: g.add_edges([(-1, c[0]) for c in g.connected_components(sort=False)]) sage: g.is_gallai_tree() True @@ -14765,12 +15041,10 @@ def R(u, v): # we only need to check that we have the right set of edges. return len(edges) >= M - else: - # The graph is simple - if G.allows_loops() and not induced and not loops: - return G.size() - len(loop_edges) == M - - return G.size() == M + # The graph is simple + if G.allows_loops() and not induced and not loops: + return G.size() - len(loop_edges) == M + return G.size() == M def is_cycle(self, directed_cycle=True): r""" @@ -14841,11 +15115,11 @@ def is_cycle(self, directed_cycle=True): if g._directed: if directed_cycle: return g.order() == g.size() and g.is_strongly_connected() - else: - # We make a copy of self ignoring the direction of edges - from sage.graphs.graph import Graph - g = Graph(multiedges=True, loops=True) - g.add_edges(self.edge_iterator(labels=False)) + + # We make a copy of self ignoring the direction of edges + from sage.graphs.graph import Graph + g = Graph(multiedges=True, loops=True) + g.add_edges(self.edge_iterator(labels=False)) return g.is_regular(k=2) and g.is_connected() @@ -14943,11 +15217,11 @@ def is_subgraph(self, other, induced=True, up_to_isomorphism=False): sage: p11 = graphs.PathGraph(11) sage: p15 = graphs.PathGraph(15) sage: g = graphs.Grid2dGraph(4, 4) - sage: p15.is_subgraph(g, induced=False, up_to_isomorphism=True) + sage: p15.is_subgraph(g, induced=False, up_to_isomorphism=True) # needs sage.modules True - sage: p15.is_subgraph(g, induced=True, up_to_isomorphism=True) + sage: p15.is_subgraph(g, induced=True, up_to_isomorphism=True) # needs sage.modules False - sage: p11.is_subgraph(g, induced=True, up_to_isomorphism=True) + sage: p11.is_subgraph(g, induced=True, up_to_isomorphism=True) # needs sage.modules True TESTS: @@ -14989,8 +15263,7 @@ def is_subgraph(self, other, induced=True, up_to_isomorphism=False): # and whether the induced subgraph of ``other`` is contained in ``self``. return (self._backend.is_subgraph(other._backend, self) and other._backend.is_subgraph(self._backend, self)) - else: - return self._backend.is_subgraph(other._backend, self) + return self._backend.is_subgraph(other._backend, self) # Cluster @@ -15025,15 +15298,15 @@ def cluster_triangles(self, nbunch=None, implementation=None): :: sage: G = graphs.RandomGNP(20, .3) - sage: d1 = G.cluster_triangles(implementation="networkx") + sage: d1 = G.cluster_triangles(implementation="networkx") # needs networkx sage: d2 = G.cluster_triangles(implementation="dense_copy") sage: d3 = G.cluster_triangles(implementation="sparse_copy") - sage: d1 == d2 and d1 == d3 + sage: d1 == d2 and d1 == d3 # needs networkx True TESTS:: - sage: DiGraph().cluster_triangles(implementation="networkx") + sage: DiGraph().cluster_triangles(implementation="networkx") # needs networkx Traceback (most recent call last): ... ValueError: the 'networkx' implementation does not support directed graphs @@ -15093,7 +15366,7 @@ def clustering_average(self, implementation=None): sage: (graphs.FruchtGraph()).clustering_average() 1/4 - sage: (graphs.FruchtGraph()).clustering_average(implementation='networkx') + sage: (graphs.FruchtGraph()).clustering_average(implementation='networkx') # needs networkx 0.25 TESTS: @@ -15107,10 +15380,13 @@ def clustering_average(self, implementation=None): The result is the same with all implementations:: + sage: # needs networkx sage: G = graphs.RandomGNM(10,20) + sage: impls = ['boost', 'sparse_copy', 'dense_copy'] + sage: impls += ['networkx'] sage: coeffs = [G.clustering_average(implementation=impl) - ....: for impl in ['boost','sparse_copy','dense_copy','networkx']] - sage: max(coeffs)-min(coeffs) # tol abs 1e-12 + ....: for impl in impls] + sage: max(coeffs) - min(coeffs) # tol abs 1e-12 0 """ @@ -15136,9 +15412,8 @@ def clustering_average(self, implementation=None): elif implementation == 'networkx': import networkx return networkx.average_clustering(self.networkx_graph()) - else: - coeffs = self.clustering_coeff(implementation=implementation) - return sum(coeffs.values()) / len(coeffs) + coeffs = self.clustering_coeff(implementation=implementation) + return sum(coeffs.values()) / len(coeffs) def clustering_coeff(self, nodes=None, @@ -15185,18 +15460,18 @@ def clustering_coeff(self, {0: 1/3, 1: 1/3, 2: 0, 3: 1/3, 4: 1/3, 5: 1/3, 6: 1/3, 7: 1/3, 8: 0, 9: 1/3, 10: 1/3, 11: 0} - sage: (graphs.FruchtGraph()).clustering_coeff(weight=True) + sage: (graphs.FruchtGraph()).clustering_coeff(weight=True) # needs networkx {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0, - 3: 0.3333333333333333, 4: 0.3333333333333333, - 5: 0.3333333333333333, 6: 0.3333333333333333, - 7: 0.3333333333333333, 8: 0, 9: 0.3333333333333333, - 10: 0.3333333333333333, 11: 0} + 3: 0.3333333333333333, 4: 0.3333333333333333, + 5: 0.3333333333333333, 6: 0.3333333333333333, + 7: 0.3333333333333333, 8: 0, 9: 0.3333333333333333, + 10: 0.3333333333333333, 11: 0} sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2]) {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0.0} - sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2], - ....: weight=True) + sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2], # needs networkx + ....: weight=True) {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0} sage: (graphs.GridGraph([5,5])).clustering_coeff(nodes=[(0,0),(0,1),(2,2)]) @@ -15220,6 +15495,7 @@ def clustering_coeff(self, Check that the result is the same with all implementations:: + sage: # needs networkx sage: G = graphs.RandomGNM(10, 20) sage: G.relabel(list("abcdefghik")) sage: coeffs = [G.clustering_coeff(implementation=impl) @@ -15293,7 +15569,7 @@ def cluster_transitivity(self): EXAMPLES:: - sage: graphs.FruchtGraph().cluster_transitivity() + sage: graphs.FruchtGraph().cluster_transitivity() # needs networkx 0.25 """ import networkx @@ -15498,7 +15774,7 @@ def girth(self, certificate=False): Issue :trac:`12355`:: - sage: H=Graph([(0, 1), (0, 3), (0, 4), (0, 5), (1, 2), (1, 3), (1, 4), (1, 6), (2, 5), (3, 4), (5, 6)]) + sage: H = Graph([(0, 1), (0, 3), (0, 4), (0, 5), (1, 2), (1, 3), (1, 4), (1, 6), (2, 5), (3, 4), (5, 6)]) sage: H.girth() 3 @@ -15528,13 +15804,13 @@ def girth(self, certificate=False): sage: g = digraphs.Circuit(6) sage: g.girth() 6 - sage: g = digraphs.RandomDirectedGNC(10) - sage: g.girth() + sage: g = digraphs.RandomDirectedGNC(10) # needs networkx + sage: g.girth() # needs networkx +Infinity - sage: g = DiGraph([(0, 1), (1, 2), (1, 3), (2, 3), (3, 4), (4, 0)]) - sage: g.girth() + sage: g = DiGraph([(0, 1), (1, 2), (1, 3), (2, 3), (3, 4), (4, 0)]) # needs networkx + sage: g.girth() # needs networkx 4 - sage: Graph(g).girth() + sage: Graph(g).girth() # needs networkx 3 """ # Cases where girth <= 2 @@ -15585,10 +15861,10 @@ def odd_girth(self, algorithm="bfs", certificate=False): The McGee graph has girth 7 and therefore its odd girth is 7 as well:: - sage: G = graphs.McGeeGraph() - sage: G.girth() + sage: G = graphs.McGeeGraph() # needs networkx + sage: G.girth() # needs networkx 7 - sage: G.odd_girth() + sage: G.odd_girth() # needs networkx 7 Any complete (directed) graph on more than 2 vertices contains @@ -15604,8 +15880,8 @@ def odd_girth(self, algorithm="bfs", certificate=False): Bipartite graphs have no odd cycle and consequently have infinite odd girth:: - sage: G = graphs.RandomBipartite(6, 6, .5) - sage: G.odd_girth() + sage: G = graphs.RandomBipartite(6, 6, .5) # needs numpy + sage: G.odd_girth() # needs numpy +Infinity sage: G = graphs.Grid2dGraph(3, 4) sage: G.odd_girth() @@ -15613,6 +15889,7 @@ def odd_girth(self, algorithm="bfs", certificate=False): The odd girth of a (directed) graph with loops is 1:: + sage: # needs networkx sage: G = graphs.RandomGNP(10, .5) sage: G.allow_loops(True) sage: G.add_edge(0, 0) @@ -15759,8 +16036,7 @@ def _girth_bfs(self, odd=False, certificate=False): cycles[x].append(y) u, v = ends return (best, list(reversed(cycles[u])) + cycles[v]) - else: - return best + return best # Centrality @@ -15826,17 +16102,17 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, 9: 3.333333333333333, 10: 3.333333333333333, 11: 3.333333333333333} sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: D.show(figsize=[2,2]) + sage: D.show(figsize=[2,2]) # needs sage.plot sage: D = D.to_undirected() - sage: D.show(figsize=[2,2]) + sage: D.show(figsize=[2,2]) # needs sage.plot sage: D.centrality_betweenness() # abs tol abs 1e-10 {0: 0.16666666666666666, 1: 0.16666666666666666, 2: 0.0, 3: 0.0} TESTS:: - sage: tests = ([graphs.RandomGNP(30,.1) for i in range(10)]+ + sage: tests = ([graphs.RandomGNP(30,.1) for i in range(10)]+ # needs networkx ....: [digraphs.RandomDirectedGNP(30,.1) for i in range(10)]) - sage: for g in tests: + sage: for g in tests: # needs networkx ....: r1 = g.centrality_betweenness(algorithm="Sage",exact=0) ....: r2 = g.centrality_betweenness(algorithm="Sage",exact=1) ....: r3 = g.centrality_betweenness(algorithm="NetworkX") @@ -15866,8 +16142,7 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, weight=weight, endpoints=endpoints, seed=seed) - else: - raise ValueError("'algorithm' can be \"NetworkX\", \"Sage\" or None") + raise ValueError("'algorithm' can be \"NetworkX\", \"Sage\" or None") def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, weight_function=None, check_weight=True): @@ -15966,11 +16241,11 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, 8: 0.61111111111111..., 9: 0.61111111111111..., 10: 0.61111111111111..., 11: 0.61111111111111...} sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: D.show(figsize=[2,2]) + sage: D.show(figsize=[2,2]) # needs sage.plot sage: D.centrality_closeness(vert=[0,1]) {0: 1.0, 1: 0.3333333333333333} sage: D = D.to_undirected() - sage: D.show(figsize=[2,2]) + sage: D.show(figsize=[2,2]) # needs sage.plot sage: D.centrality_closeness() {0: 1.0, 1: 1.0, 2: 0.75, 3: 0.75} @@ -16011,6 +16286,7 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, The result does not depend on the algorithm:: + sage: # needs networkx sage: import random sage: import itertools sage: n = random.randint(2,20) @@ -16037,20 +16313,21 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, sage: m = random.randint(0, n*(n-1)/2) sage: g = digraphs.RandomDirectedGNM(n,m) sage: c1 = g.centrality_closeness(algorithm='BFS') - sage: c2 = g.centrality_closeness(algorithm='NetworkX') + sage: c2 = g.centrality_closeness(algorithm='NetworkX') # needs networkx sage: c3 = g.centrality_closeness(algorithm='Dijkstra_Boost') sage: c4 = g.centrality_closeness(algorithm='Floyd-Warshall-Cython') sage: c5 = g.centrality_closeness(algorithm='Floyd-Warshall-Python') sage: c6 = g.centrality_closeness(algorithm='Johnson_Boost') - sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6) + sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6) # needs networkx True - sage: c = [c1,c2,c3,c4,c5,c6] - sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.out_degree(v)) < 1e-12 + sage: c = [c1,c2,c3,c4,c5,c6] # needs networkx + sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.out_degree(v)) < 1e-12 # needs networkx ....: for ci, cj in itertools.combinations(c, 2) ) True Weighted graphs:: + sage: # needs networkx sage: import random sage: import itertools sage: n = random.randint(2,20) @@ -16120,42 +16397,39 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, closeness[x] = networkx.closeness_centrality(G, x, distance='weight' if by_weight else None) if onlyone: return closeness.get(vert, None) - else: - return closeness + return closeness elif algorithm == "Johnson_Boost": from sage.graphs.base.boost_graph import johnson_closeness_centrality self.weighted(by_weight) closeness = johnson_closeness_centrality(self, weight_function) if onlyone: return closeness.get(vert, None) + return {v: closeness[v] for v in v_iter if v in closeness} + + closeness = dict() + distances = None + if algorithm in ["Floyd-Warshall-Cython", + "Floyd-Warshall-Python"]: + distances = self.shortest_path_all_pairs(algorithm=algorithm, + by_weight=by_weight, + weight_function=weight_function, + check_weight=False)[0] + + for v in v_iter: + if distances is None: + distv = self.shortest_path_lengths(v, algorithm=algorithm, + by_weight=by_weight, + weight_function=weight_function, + check_weight=False) else: - return {v: closeness[v] for v in v_iter if v in closeness} - else: - closeness = dict() - distances = None - if algorithm in ["Floyd-Warshall-Cython", - "Floyd-Warshall-Python"]: - distances = self.shortest_path_all_pairs(algorithm=algorithm, - by_weight=by_weight, - weight_function=weight_function, - check_weight=False)[0] - - for v in v_iter: - if distances is None: - distv = self.shortest_path_lengths(v, algorithm=algorithm, - by_weight=by_weight, - weight_function=weight_function, - check_weight=False) - else: - distv = distances[v] - try: - closeness[v] = float(len(distv) - 1) * (len(distv) - 1) / (float(sum(distv.values())) * (self.num_verts() - 1)) - except ZeroDivisionError: - pass - if onlyone: - return closeness.get(vert, None) - else: - return closeness + distv = distances[v] + try: + closeness[v] = float(len(distv) - 1) * (len(distv) - 1) / (float(sum(distv.values())) * (self.num_verts() - 1)) + except ZeroDivisionError: + pass + if onlyone: + return closeness.get(vert, None) + return closeness def triangles_count(self, algorithm=None): r""" @@ -16199,29 +16473,29 @@ def triangles_count(self, algorithm=None): have:: sage: G = graphs.CompleteGraph(15) - sage: G.triangles_count() == binomial(15, 3) + sage: G.triangles_count() == binomial(15, 3) # needs sage.symbolic True The 2-dimensional DeBruijn graph of 2 symbols has 2 directed `C_3`:: - sage: G = digraphs.DeBruijn(2,2) - sage: G.triangles_count() + sage: G = digraphs.DeBruijn(2,2) # needs sage.combinat + sage: G.triangles_count() # needs sage.combinat 2 The directed `n`-cycle is trivially triangle free for `n > 3`:: sage: G = digraphs.Circuit(10) - sage: G.triangles_count() + sage: G.triangles_count() # needs sage.modules 0 TESTS: Comparison of algorithms:: - sage: G = graphs.RandomBarabasiAlbert(50,2) + sage: G = graphs.RandomBarabasiAlbert(50,2) # needs networkx sage: results = [] sage: results.append(G.triangles_count(algorithm='matrix')) - sage: results.append(G.triangles_count(algorithm='iter')) + sage: results.append(G.triangles_count(algorithm='iter')) # needs sage.modules sage: results.append(G.triangles_count(algorithm='sparse_copy')) sage: results.append(G.triangles_count(algorithm='dense_copy')) sage: any(x != results[0] for x in results) @@ -16248,30 +16522,28 @@ def triangles_count(self, algorithm=None): from sage.graphs.digraph_generators import digraphs return self.subgraph_search_count(digraphs.Circuit(3)) // 3 - else: - self._scream_if_not_simple() - if algorithm is None: - from sage.graphs.base.dense_graph import DenseGraphBackend - algorithm = ('dense_copy' if isinstance(self._backend, DenseGraphBackend) else - 'sparse_copy') + self._scream_if_not_simple() + if algorithm is None: + from sage.graphs.base.dense_graph import DenseGraphBackend + algorithm = ('dense_copy' if isinstance(self._backend, DenseGraphBackend) else + 'sparse_copy') - if algorithm == 'iter': - tr = 0 - for u in self: - Nu = set(self.neighbors(u)) - for v in Nu: - tr += len(Nu.intersection(self.neighbors(v))) - return Integer(tr // 6) - elif algorithm == "sparse_copy": - from sage.graphs.base.static_sparse_graph import triangles_count - return sum(triangles_count(self).values()) // 3 - elif algorithm == "dense_copy": - from sage.graphs.base.static_dense_graph import triangles_count - return sum(triangles_count(self).values()) // 3 - elif algorithm == 'matrix': - return (self.adjacency_matrix(vertices=list(self))**3).trace() // 6 - else: - raise ValueError('unknown algorithm "{}"'.format(algorithm)) + if algorithm == 'iter': + tr = 0 + for u in self: + Nu = set(self.neighbors(u)) + for v in Nu: + tr += len(Nu.intersection(self.neighbors(v))) + return Integer(tr // 6) + elif algorithm == "sparse_copy": + from sage.graphs.base.static_sparse_graph import triangles_count + return sum(triangles_count(self).values()) // 3 + elif algorithm == "dense_copy": + from sage.graphs.base.static_dense_graph import triangles_count + return sum(triangles_count(self).values()) // 3 + elif algorithm == 'matrix': + return (self.adjacency_matrix(vertices=list(self))**3).trace() // 6 + raise ValueError('unknown algorithm "{}"'.format(algorithm)) def shortest_path(self, u, v, by_weight=False, algorithm=None, weight_function=None, check_weight=True): @@ -16342,9 +16614,9 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, [4, 17, 16, 12, 13, 9] sage: D.shortest_path(4, 9, algorithm='BFS') [4, 3, 2, 1, 8, 9] - sage: D.shortest_path(4, 8, algorithm='Dijkstra_NetworkX') + sage: D.shortest_path(4, 8, algorithm='Dijkstra_NetworkX') # needs networkx [4, 3, 2, 1, 8] - sage: D.shortest_path(4, 8, algorithm='Dijkstra_Bid_NetworkX') + sage: D.shortest_path(4, 8, algorithm='Dijkstra_Bid_NetworkX') # needs networkx [4, 3, 2, 1, 8] sage: D.shortest_path(4, 9, algorithm='Dijkstra_Bid') [4, 3, 19, 0, 10, 9] @@ -16353,15 +16625,18 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, sage: D.delete_edges(D.edges_incident(13)) sage: D.shortest_path(13, 4) [] - sage: G = Graph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}}, sparse = True) + sage: G = Graph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}}, + ....: sparse=True) sage: G.plot(edge_labels=True).show() # long time sage: G.shortest_path(0, 3) [0, 4, 3] sage: G.shortest_path(0, 3, by_weight=True) [0, 1, 2, 3] - sage: G.shortest_path(0, 3, by_weight=True, algorithm='Dijkstra_NetworkX') + sage: G.shortest_path(0, 3, by_weight=True, # needs networkx + ....: algorithm='Dijkstra_NetworkX') [0, 1, 2, 3] - sage: G.shortest_path(0, 3, by_weight=True, algorithm='Dijkstra_Bid_NetworkX') + sage: G.shortest_path(0, 3, by_weight=True, # needs networkx + ....: algorithm='Dijkstra_Bid_NetworkX') [0, 1, 2, 3] TESTS: @@ -16399,15 +16674,11 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, sage: G = Graph() sage: G.add_vertices([1, 2]) - sage: for alg in ['BFS', 'BFS_Bid', 'Dijkstra_NetworkX', 'Dijkstra_Bid_NetworkX', - ....: 'Dijkstra_Bid', 'Bellman-Ford_Boost']: - ....: G.shortest_path(1, 2, algorithm=alg) - [] - [] - [] - [] - [] - [] + sage: algs = ['BFS', 'BFS_Bid', 'Dijkstra_Bid', 'Bellman-Ford_Boost'] + sage: algs += ['Dijkstra_NetworkX', 'Dijkstra_Bid_NetworkX'] # needs networkx + sage: all(G.shortest_path(1, 2, algorithm=alg) == [] + ....: for alg in algs) + True .. TODO:: @@ -16454,8 +16725,7 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, return [] elif algorithm == "BFS_Bid": return self._backend.shortest_path(u, v) - else: - raise ValueError('unknown algorithm "{}"'.format(algorithm)) + raise ValueError('unknown algorithm "{}"'.format(algorithm)) def shortest_path_length(self, u, v, by_weight=False, algorithm=None, weight_function=None, check_weight=True): @@ -16528,9 +16798,9 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, 5 sage: D.shortest_path_length(4, 9, algorithm='BFS') 5 - sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_NetworkX') + sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_NetworkX') # needs networkx 5 - sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_Bid_NetworkX') + sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_Bid_NetworkX') # needs networkx 5 sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_Bid') 5 @@ -16541,31 +16811,37 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, sage: D.delete_edges(D.edges_incident(13)) sage: D.shortest_path_length(13, 4) +Infinity - sage: G = Graph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}}, sparse = True) - sage: G.plot(edge_labels=True).show() # long time + sage: G = Graph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}}, + ....: sparse=True) + sage: G.plot(edge_labels=True).show() # long time sage: G.shortest_path_length(0, 3) 2 sage: G.shortest_path_length(0, 3, by_weight=True) 3 - sage: G.shortest_path_length(0, 3, by_weight=True, algorithm='Dijkstra_NetworkX') + sage: G.shortest_path_length(0, 3, by_weight=True, # needs networkx + ....: algorithm='Dijkstra_NetworkX') 3 - sage: G.shortest_path_length(0, 3, by_weight=True, algorithm='Dijkstra_Bid_NetworkX') + sage: G.shortest_path_length(0, 3, by_weight=True, # needs networkx + ....: algorithm='Dijkstra_Bid_NetworkX') 3 If Dijkstra is used with negative weights, usually it raises an error:: - sage: G = DiGraph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: -2}}, sparse = True) + sage: G = DiGraph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: -2}}, + ....: sparse=True) sage: G.shortest_path_length(4, 1, by_weight=True, algorithm=None) Traceback (most recent call last): ... ValueError: the graph contains an edge with negative weight - sage: G.shortest_path_length(4, 1, by_weight=True, algorithm='Bellman-Ford_Boost') + sage: G.shortest_path_length(4, 1, by_weight=True, + ....: algorithm='Bellman-Ford_Boost') -1 However, sometimes the result may be wrong, and no error is raised:: - sage: G = DiGraph([(0,1,1),(1,2,1),(0,3,1000),(3,4,-3000), (4,2,1000)]) - sage: G.shortest_path_length(0, 2, by_weight=True, algorithm='Bellman-Ford_Boost') + sage: G = DiGraph([(0,1,1), (1,2,1), (0,3,1000), (3,4,-3000), (4,2,1000)]) + sage: G.shortest_path_length(0, 2, by_weight=True, + ....: algorithm='Bellman-Ford_Boost') -1000 sage: G.shortest_path_length(0, 2, by_weight=True) 2 @@ -16587,15 +16863,11 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, sage: G = Graph() sage: G.add_vertices([1, 2]) - sage: for alg in ['BFS', 'BFS_Bid', 'Dijkstra_NetworkX', 'Dijkstra_Bid_NetworkX', - ....: 'Dijkstra_Bid', 'Bellman-Ford_Boost']: - ....: G.shortest_path_length(1, 2, algorithm=alg) - +Infinity - +Infinity - +Infinity - +Infinity - +Infinity - +Infinity + sage: algs = ['BFS', 'BFS_Bid', 'Dijkstra_Bid', 'Bellman-Ford_Boost'] + sage: algs += ['Dijkstra_NetworkX', 'Dijkstra_Bid_NetworkX'] # needs networkx + sage: all(G.shortest_path_length(1, 2, algorithm=alg) == Infinity + ....: for alg in algs) + True """ if not self.has_vertex(u): raise ValueError("vertex '{}' is not in the (di)graph".format(u)) @@ -16639,8 +16911,7 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, return Infinity elif algorithm == "BFS_Bid": return self._backend.shortest_path(u, v, distance_flag=True) - else: - raise ValueError('unknown algorithm "{}"'.format(algorithm)) + raise ValueError('unknown algorithm "{}"'.format(algorithm)) def _check_weight_function(self, weight_function=None): r""" @@ -16878,7 +17149,8 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, However, if ``check_weight`` is set to ``False``, unexpected behavior may occur:: - sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', weight_function=lambda e:e[2], check_weight=False) + sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', # needs networkx + ....: weight_function=lambda e:e[2], check_weight=False) Traceback (most recent call last): ... TypeError: unsupported operand type(s) for +: 'int' and 'dict' @@ -16921,7 +17193,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, Traceback (most recent call last): ... RuntimeError: Dijkstra algorithm does not work with negative weights, use Bellman-Ford instead - sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', by_weight=True) + sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', by_weight=True) # needs networkx Traceback (most recent call last): ... ValueError: ('Contradictory paths found:', 'negative weights?') @@ -16972,8 +17244,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, paths[v] = path return paths - else: - raise ValueError('unknown algorithm "{}"'.format(algorithm)) + raise ValueError('unknown algorithm "{}"'.format(algorithm)) def _path_length(self, path, by_weight=False, weight_function=None): r""" @@ -17039,8 +17310,7 @@ def _path_length(self, path, by_weight=False, weight_function=None): check_weight=False) return sum(weight_function((u, v, self.edge_label(u, v))) for u, v in zip(path[:-1], path[1:])) - else: - return len(path) - 1 + return len(path) - 1 def shortest_path_lengths(self, u, by_weight=False, algorithm=None, weight_function=None, check_weight=True): @@ -17096,20 +17366,23 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, sage: D = graphs.DodecahedralGraph() sage: D.shortest_path_lengths(0) - {0: 0, 1: 1, 2: 2, 3: 2, 4: 3, 5: 4, 6: 3, 7: 3, 8: 2, 9: 2, 10: 1, 11: 2, 12: 3, 13: 3, 14: 4, 15: 5, 16: 4, 17: 3, 18: 2, 19: 1} + {0: 0, 1: 1, 2: 2, 3: 2, 4: 3, 5: 4, 6: 3, 7: 3, 8: 2, 9: 2, 10: 1, + 11: 2, 12: 3, 13: 3, 14: 4, 15: 5, 16: 4, 17: 3, 18: 2, 19: 1} Weighted case:: - sage: G = Graph( { 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} }, sparse=True) - sage: G.plot(edge_labels=True).show() # long time + sage: G = Graph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}}, + ....: sparse=True) + sage: G.plot(edge_labels=True).show() # long time # needs sage.plot sage: G.shortest_path_lengths(0, by_weight=True) {0: 0, 1: 1, 2: 2, 3: 3, 4: 2} Using a weight function:: - sage: D = DiGraph([(0,1,{'weight':1}),(1,2,{'weight':3}),(0,2,{'weight':5})]) - sage: weight_function = lambda e:e[2]['weight'] - sage: D.shortest_path_lengths(1, algorithm='Dijkstra_NetworkX', by_weight=False) + sage: D = DiGraph([(0,1,{'weight':1}), (1,2,{'weight':3}), (0,2,{'weight':5})]) + sage: weight_function = lambda e: e[2]['weight'] + sage: D.shortest_path_lengths(1, algorithm='Dijkstra_NetworkX', # needs networkx + ....: by_weight=False) {1: 0, 2: 1} sage: D.shortest_path_lengths(0, weight_function=weight_function) {0: 0, 1: 1, 2: 4} @@ -17118,13 +17391,13 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, Negative weights:: - sage: D = DiGraph([(0,1,{'weight':-1}),(1,2,{'weight':3}),(0,2,{'weight':5})]) + sage: D = DiGraph([(0,1,{'weight':-1}), (1,2,{'weight':3}), (0,2,{'weight':5})]) sage: D.shortest_path_lengths(0, weight_function=weight_function) {0: 0, 1: -1, 2: 2} Negative cycles:: - sage: D = DiGraph([(0,1,{'weight':-5}),(1,2,{'weight':3}),(2,0,{'weight':1})]) + sage: D = DiGraph([(0,1,{'weight':-5}), (1,2,{'weight':3}), (2,0,{'weight':1})]) sage: D.shortest_path_lengths(0, weight_function=weight_function) Traceback (most recent call last): ... @@ -17134,10 +17407,10 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, sage: g = graphs.Grid2dGraph(5,5) sage: d1 = g.shortest_path_lengths((0,0), algorithm="BFS") - sage: d2 = g.shortest_path_lengths((0,0), algorithm="Dijkstra_NetworkX") + sage: d2 = g.shortest_path_lengths((0,0), algorithm="Dijkstra_NetworkX") # needs networkx sage: d3 = g.shortest_path_lengths((0,0), algorithm="Dijkstra_Boost") sage: d4 = g.shortest_path_lengths((0,0), algorithm="Bellman-Ford_Boost") - sage: d1 == d2 == d3 == d4 + sage: d1 == d2 == d3 == d4 # needs networkx True """ by_weight, weight_function = self._get_weight_function(by_weight=by_weight, @@ -17175,8 +17448,7 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, from sage.graphs.base.boost_graph import shortest_paths return shortest_paths(self, u, weight_function, algorithm)[0] - else: - raise ValueError('unknown algorithm "{}"'.format(algorithm)) + raise ValueError('unknown algorithm "{}"'.format(algorithm)) def shortest_path_all_pairs(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): @@ -17325,12 +17597,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: d1, _ = g.shortest_path_all_pairs(algorithm="BFS") sage: d2, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Cython") sage: d3, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python") - sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") + sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") - sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") - sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 + sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy + sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 # needs networkx scipy True Checking that distances are equal regardless of the algorithm used:: @@ -17339,12 +17611,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: d1, _ = g.shortest_path_all_pairs(algorithm="BFS") sage: d2, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Cython") sage: d3, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python") - sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") + sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") - sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") - sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 + sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy + sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 # needs networkx scipy True Checking that weighted distances are equal regardless of the algorithm @@ -17355,12 +17627,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: for v, w in g.edges(labels=False, sort=False): ....: g.add_edge(v, w, random.uniform(1, 10)) sage: d1, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python") - sage: d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") + sage: d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx sage: d3, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d4, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") sage: d5, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") - sage: d6, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") - sage: d1 == d2 == d3 == d4 == d5 == d6 + sage: d6, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy + sage: d1 == d2 == d3 == d4 == d5 == d6 # needs networkx scipy True Checking a random path is valid:: @@ -17387,7 +17659,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: g.shortest_path_all_pairs(algorithm='BFS') ({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}}, {0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}}) - sage: g.shortest_path_all_pairs(algorithm='Dijkstra_NetworkX') + sage: g.shortest_path_all_pairs(algorithm='Dijkstra_NetworkX') # needs networkx ({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}}, {0: {0: None, 1: 1, 2: 1}, 1: {1: None, 2: 2}, 2: {2: None}}) sage: g.shortest_path_all_pairs(algorithm='Dijkstra_Boost') @@ -17399,7 +17671,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall-Cython') ({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}}, {0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}}) - sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall_SciPy') + sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall_SciPy') # needs scipy ({0: {0: 0.0, 1: 1.0, 2: 2.0}, 1: {1: 0.0, 2: 1.0}, 2: {2: 0.0}}, {0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}}) @@ -17671,7 +17943,7 @@ def wiener_index(self, by_weight=False, algorithm=None, 15 sage: G.wiener_index(algorithm='Johnson_Boost') 15 - sage: G.wiener_index(algorithm='Dijkstra_NetworkX') + sage: G.wiener_index(algorithm='Dijkstra_NetworkX') # needs networkx 15 Wiener index of complete (di)graphs:: @@ -17966,8 +18238,9 @@ def breadth_first_search(self, start, ignore_direction=False, [0, 1, 4, 5, 2, 6, 3, 9, 7, 8] sage: D = DiGraph({0: [1, 3], 1: [0, 2], 2: [0, 3], 3: [4]}) - sage: D.show() - sage: list(D.breadth_first_search(4, neighbors=D.neighbor_in_iterator, report_distance=True)) + sage: D.show() # needs sage.plot + sage: list(D.breadth_first_search(4, neighbors=D.neighbor_in_iterator, + ....: report_distance=True)) [(4, 0), (3, 1), (0, 2), (2, 2), (1, 3)] sage: C = graphs.CycleGraph(4) @@ -18269,6 +18542,9 @@ def add_clique(self, vertices, loops=False): True sage: G.vertices(sort=True) [0, 1, 2, 3] + sage: G.add_clique({4}) + sage: G.vertices(sort=True) + [0, 1, 2, 3, 4] sage: D = DiGraph(4, loops=True) sage: D.add_clique(range(4), loops=True) sage: D.is_clique(directed_clique=True, loops=True) @@ -18281,6 +18557,7 @@ def add_clique(self, vertices, loops=False): else: self.add_edges(itertools.combinations_with_replacement(vertices, 2)) else: + self.add_vertices(vertices) if self.is_directed(): self.add_edges(itertools.permutations(vertices, 2)) else: @@ -18306,11 +18583,11 @@ def add_cycle(self, vertices): sage: G = Graph() sage: G.add_vertices(range(10)); G Graph on 10 vertices - sage: show(G) + sage: show(G) # needs sage.plot sage: G.add_cycle(list(range(10, 20))) - sage: show(G) + sage: show(G) # needs sage.plot sage: G.add_cycle(list(range(10))) - sage: show(G) + sage: show(G) # needs sage.plot :: @@ -18362,11 +18639,11 @@ def add_path(self, vertices): sage: G = Graph() sage: G.add_vertices(range(10)); G Graph on 10 vertices - sage: show(G) + sage: show(G) # needs sage.plot sage: G.add_path(list(range(10, 20))) - sage: show(G) + sage: show(G) # needs sage.plot sage: G.add_path(list(range(10))) - sage: show(G) + sage: show(G) # needs sage.plot :: @@ -18391,10 +18668,10 @@ def complement(self): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.plot() # long time + sage: P.plot() # long time # needs sage.plot Graphics object consisting of 26 graphics primitives sage: PC = P.complement() - sage: PC.plot() # long time + sage: PC.plot() # long time # needs sage.plot Graphics object consisting of 41 graphics primitives :: @@ -18476,7 +18753,8 @@ def to_simple(self, to_undirected=True, keep_label='any', immutable=None): EXAMPLES:: sage: G = DiGraph(loops=True, multiedges=True, sparse=True) - sage: G.add_edges([(0, 0, None), (1, 1, None), (2, 2, None), (2, 3, 1), (2, 3, 2), (3, 2, None)]) + sage: G.add_edges([(0, 0, None), (1, 1, None), (2, 2, None), + ....: (2, 3, 1), (2, 3, 2), (3, 2, None)]) sage: G.edges(sort=True, labels=False) [(0, 0), (1, 1), (2, 2), (2, 3), (2, 3), (3, 2)] sage: H = G.to_simple() @@ -18658,8 +18936,8 @@ def union(self, other, immutable=None): raise TypeError('both arguments must be of the same class') multiedges = self.allows_multiple_edges() or other.allows_multiple_edges() - loops = self.allows_loops() or other.allows_loops() - weighted = self.weighted() and other.weighted() + loops = self.allows_loops() or other.allows_loops() + weighted = self.weighted() and other.weighted() if self._directed: from sage.graphs.digraph import DiGraph @@ -18722,9 +19000,9 @@ def cartesian_product(self, other): Cartesian product of digraphs:: sage: P = DiGraph([(0, 1)]) - sage: B = digraphs.DeBruijn(['a', 'b'], 2) - sage: Q = P.cartesian_product(B) - sage: Q.edges(sort=True, labels=None) + sage: B = digraphs.DeBruijn(['a', 'b'], 2) # needs sage.combinat + sage: Q = P.cartesian_product(B) # needs sage.combinat + sage: Q.edges(sort=True, labels=None) # needs sage.combinat [((0, 'aa'), (0, 'aa')), ((0, 'aa'), (0, 'ab')), ((0, 'aa'), (1, 'aa')), ((0, 'ab'), (0, 'ba')), ((0, 'ab'), (0, 'bb')), ((0, 'ab'), (1, 'ab')), @@ -18735,10 +19013,10 @@ def cartesian_product(self, other): ((1, 'ab'), (1, 'ba')), ((1, 'ab'), (1, 'bb')), ((1, 'ba'), (1, 'aa')), ((1, 'ba'), (1, 'ab')), ((1, 'bb'), (1, 'ba')), ((1, 'bb'), (1, 'bb'))] - sage: Q.strongly_connected_components_digraph().num_verts() + sage: Q.strongly_connected_components_digraph().num_verts() # needs sage.combinat 2 - sage: V = Q.strongly_connected_component_containing_vertex((0, 'aa')) - sage: B.is_isomorphic(Q.subgraph(V)) + sage: V = Q.strongly_connected_component_containing_vertex((0, 'aa')) # needs sage.combinat + sage: B.is_isomorphic(Q.subgraph(V)) # needs sage.combinat True """ self._scream_if_not_simple(allow_loops=True) @@ -18819,6 +19097,7 @@ def tensor_product(self, other): The tensor product of two DeBruijn digraphs of same diameter is a DeBruijn digraph:: + sage: # needs sage.combinat sage: B1 = digraphs.DeBruijn(2, 3) sage: B2 = digraphs.DeBruijn(3, 3) sage: T = B1.tensor_product(B2) @@ -18973,6 +19252,7 @@ def strong_product(self, other): Counting the edges (see :trac:`13699`):: + sage: # needs networkx sage: g = graphs.RandomGNP(5, .5) sage: gn,gm = g.order(), g.size() sage: h = graphs.RandomGNP(5, .5) @@ -19182,19 +19462,17 @@ def transitive_reduction(self): G.add_edge(e) return G - else: - # The transitive reduction of each connected component of an - # undirected graph is a spanning tree - from sage.graphs.graph import Graph - if self.is_connected(): - return Graph(self.min_spanning_tree(weight_function=lambda e: 1)) - else: - G = Graph(list(self)) - for cc in self.connected_components(): - if len(cc) > 1: - edges = self.subgraph(cc).min_spanning_tree(weight_function=lambda e: 1) - G.add_edges(edges) - return G + # The transitive reduction of each connected component of an + # undirected graph is a spanning tree + from sage.graphs.graph import Graph + if self.is_connected(): + return Graph(self.min_spanning_tree(weight_function=lambda e: 1)) + G = Graph(list(self)) + for cc in self.connected_components(sort=False): + if len(cc) > 1: + edges = self.subgraph(cc).min_spanning_tree(weight_function=lambda e: 1) + G.add_edges(edges) + return G def is_transitively_reduced(self): r""" @@ -19273,33 +19551,36 @@ def _color_by_label(self, format='hex', as_function=False, default_color="black" We consider the Cayley graph of the symmetric group, whose edges are labelled by the numbers 1,2, and 3:: - sage: G = SymmetricGroup(4).cayley_graph() # optional - sage.groups - sage: set(G.edge_labels()) # optional - sage.groups + sage: G = SymmetricGroup(4).cayley_graph() # needs sage.groups + sage: set(G.edge_labels()) # needs sage.groups {1, 2, 3} We first request the coloring as a function:: - sage: f = G._color_by_label(as_function=True) # optional - sage.groups - sage: [f(1), f(2), f(3)] # optional - sage.groups + sage: # needs sage.groups + sage: f = G._color_by_label(as_function=True) + sage: [f(1), f(2), f(3)] ['#0000ff', '#ff0000', '#00ff00'] - sage: f = G._color_by_label({1: "blue", 2: "red", 3: "green"}, as_function=True) # optional - sage.groups - sage: [f(1), f(2), f(3)] # optional - sage.groups + sage: f = G._color_by_label({1: "blue", 2: "red", 3: "green"}, + ....: as_function=True) + sage: [f(1), f(2), f(3)] ['blue', 'red', 'green'] - sage: f = G._color_by_label({1: "red"}, as_function=True) # optional - sage.groups - sage: [f(1), f(2), f(3)] # optional - sage.groups + sage: f = G._color_by_label({1: "red"}, as_function=True) + sage: [f(1), f(2), f(3)] ['red', 'black', 'black'] - sage: f = G._color_by_label({1: "red"}, as_function=True, default_color='blue') # optional - sage.groups - sage: [f(1), f(2), f(3)] # optional - sage.groups + sage: f = G._color_by_label({1: "red"}, as_function=True, + ....: default_color='blue') + sage: [f(1), f(2), f(3)] ['red', 'blue', 'blue'] The default output is a dictionary assigning edges to colors:: - sage: G._color_by_label() # optional - sage.groups + sage: G._color_by_label() # needs sage.groups {'#0000ff': [((), (1,2), 1), ...], '#00ff00': [((), (3,4), 3), ...], '#ff0000': [((), (2,3), 2), ...]} - sage: G._color_by_label({1: "blue", 2: "red", 3: "green"}) # optional - sage.groups + sage: G._color_by_label({1: "blue", 2: "red", 3: "green"}) # needs sage.groups {'blue': [((), (1,2), 1), ...], 'green': [((), (3,4), 3), ...], 'red': [((), (2,3), 2), ...]} @@ -19308,12 +19589,13 @@ def _color_by_label(self, format='hex', as_function=False, default_color="black" We check what happens when several labels have the same color:: - sage: result = G._color_by_label({1: "blue", 2: "blue", 3: "green"}) # optional - sage.groups - sage: sorted(result) # optional - sage.groups + sage: # needs sage.groups + sage: result = G._color_by_label({1: "blue", 2: "blue", 3: "green"}) + sage: sorted(result) ['blue', 'green'] - sage: len(result['blue']) # optional - sage.groups + sage: len(result['blue']) 48 - sage: len(result['green']) # optional - sage.groups + sage: len(result['green']) 24 """ if format is True: @@ -19367,8 +19649,8 @@ def latex_options(self): sage: opts = g.latex_options() sage: opts LaTeX options for Petersen graph: {} - sage: opts.set_option('tkz_style', 'Classic') - sage: opts + sage: opts.set_option('tkz_style', 'Classic') # needs sage.plot + sage: opts # needs sage.plot LaTeX options for Petersen graph: {'tkz_style': 'Classic'} """ if self._latex_opts is None: @@ -19396,9 +19678,9 @@ def set_latex_options(self, **kwds): EXAMPLES:: sage: g = graphs.PetersenGraph() - sage: g.set_latex_options(tkz_style='Welsh') - sage: opts = g.latex_options() - sage: opts.get_option('tkz_style') + sage: g.set_latex_options(tkz_style='Welsh') # needs sage.plot + sage: opts = g.latex_options() # needs sage.plot + sage: opts.get_option('tkz_style') # needs sage.plot 'Welsh' """ opts = self.latex_options() @@ -19562,7 +19844,7 @@ def layout_spring(self, by_component=True, **options): 4: [2.14..., -0.30...], 5: [2.80..., 0.22...]} sage: g = graphs.LadderGraph(7) - sage: g.plot(layout="spring") + sage: g.plot(layout="spring") # needs sage.plot Graphics object consisting of 34 graphics primitives """ return spring_layout_fast(self, by_component=by_component, **options) @@ -19602,7 +19884,7 @@ def layout_ranked(self, heights=None, dim=2, spring=False, **options): 4: [1.33..., 1], 5: [1.33..., 2]} sage: g = graphs.LadderGraph(7) - sage: g.plot(layout="ranked", heights={i: (i, i+7) for i in range(7)}) + sage: g.plot(layout="ranked", heights={i: (i, i+7) for i in range(7)}) # needs sage.plot Graphics object consisting of 34 graphics primitives """ assert heights is not None @@ -19730,7 +20012,7 @@ def layout_circular(self, dim=2, center=(0, 0), radius=1, shift=0, angle=0, **op 4: (0.43..., -0.90...), 5: (0.97..., -0.22...), 6: (0.78..., 0.62...)} - sage: G.plot(layout="circular") + sage: G.plot(layout="circular") # needs sage.plot Graphics object consisting of 22 graphics primitives """ assert dim == 2, "3D circular layout not implemented" @@ -19764,18 +20046,19 @@ def layout_forest(self, tree_orientation="down", forest_roots=None, sage: G = graphs.RandomTree(4) + graphs.RandomTree(5) + graphs.RandomTree(6) sage: p = G.layout_forest() - sage: G.plot(pos=p) # random + sage: G.plot(pos=p) # random # needs sage.plot Graphics object consisting of 28 graphics primitives - sage: H = graphs.PathGraph(5) + graphs.PathGraph(5) + graphs.BalancedTree(2,2) - sage: p = H.layout_forest(forest_roots=[14,3]) - sage: H.plot(pos=p) + sage: P5 = graphs.PathGraph(5) + sage: H = P5 + P5 + graphs.BalancedTree(2,2) # needs networkx + sage: p = H.layout_forest(forest_roots=[14,3]) # needs networkx + sage: H.plot(pos=p) # needs networkx sage.plot Graphics object consisting of 32 graphics primitives TESTS:: sage: G = Graph(0) - sage: G.plot(layout='forest') + sage: G.plot(layout='forest') # needs sage.plot Graphics object consisting of 0 graphics primitives Works for forests that are trees:: @@ -19795,13 +20078,12 @@ def layout_forest(self, tree_orientation="down", forest_roots=None, """ if not self: return dict() - else: - # Compute the layout component by component - return layout_split(self.__class__.layout_tree, - self, - tree_orientation=tree_orientation, - forest_roots=forest_roots, - **options) + # Compute the layout component by component + return layout_split(self.__class__.layout_tree, + self, + tree_orientation=tree_orientation, + forest_roots=forest_roots, + **options) def layout_tree(self, tree_orientation="down", tree_root=None, dim=2, **options): @@ -19836,19 +20118,19 @@ def layout_tree(self, tree_orientation="down", tree_root=None, EXAMPLES:: sage: G = graphs.RandomTree(80) - sage: G.plot(layout="tree", tree_orientation="right") + sage: G.plot(layout="tree", tree_orientation="right") # needs sage.plot Graphics object consisting of 160 graphics primitives - sage: T = graphs.RandomLobster(25, 0.3, 0.3) - sage: T.show(layout='tree', tree_orientation='up') + sage: T = graphs.RandomLobster(25, 0.3, 0.3) # needs networkx + sage: T.show(layout='tree', tree_orientation='up') # needs networkx sage.plot sage: G = graphs.HoffmanSingletonGraph() sage: T = Graph() sage: T.add_edges(G.min_spanning_tree(starting_vertex=0)) - sage: T.show(layout='tree', tree_root=0) + sage: T.show(layout='tree', tree_root=0) # needs sage.plot - sage: G = graphs.BalancedTree(2, 2) - sage: G.layout_tree(tree_root=0) + sage: G = graphs.BalancedTree(2, 2) # needs networkx + sage: G.layout_tree(tree_root=0) # needs networkx {0: [1.5, 0], 1: [2.5, -1], 2: [0.5, -1], @@ -19857,8 +20139,8 @@ def layout_tree(self, tree_orientation="down", tree_root=None, 5: [1.0, -2], 6: [0.0, -2]} - sage: G = graphs.BalancedTree(2, 4) - sage: G.plot(layout="tree", tree_root=0, tree_orientation="up") + sage: G = graphs.BalancedTree(2, 4) # needs networkx + sage: G.plot(layout="tree", tree_root=0, tree_orientation="up") # needs networkx sage.plot Graphics object consisting of 62 graphics primitives Using the embedding when it exists:: @@ -19876,13 +20158,13 @@ def layout_tree(self, tree_orientation="down", tree_root=None, 6: [2.0, -1], 7: [1.0, -2], 8: [0.0, -2]} - sage: T.plot(layout="tree", tree_root=3) + sage: T.plot(layout="tree", tree_root=3) # needs sage.plot Graphics object consisting of 18 graphics primitives TESTS:: - sage: G = graphs.BalancedTree(2, 2) - sage: G.layout_tree(tree_root=0, tree_orientation='left') + sage: G = graphs.BalancedTree(2, 2) # needs networkx + sage: G.layout_tree(tree_root=0, tree_orientation='left') # needs networkx {0: [0, 1.5], 1: [-1, 2.5], 2: [-1, 0.5], @@ -19892,12 +20174,12 @@ def layout_tree(self, tree_orientation="down", tree_root=None, 6: [-2, 0.0]} sage: G = graphs.CycleGraph(3) - sage: G.plot(layout='tree') + sage: G.plot(layout='tree') # needs sage.plot Traceback (most recent call last): ... RuntimeError: cannot use tree layout on this graph: self.is_tree() returns False sage: G = Graph(0) - sage: G.plot(layout='tree') + sage: G.plot(layout='tree') # needs sage.plot Graphics object consisting of 0 graphics primitives """ if dim != 2: @@ -20056,16 +20338,17 @@ def layout_graphviz(self, dim=2, prog='dot', **options): By default, an acyclic layout is computed using ``graphviz``'s ``dot`` layout program. One may specify an alternative layout program:: - sage: g.plot(layout = "graphviz", prog = "dot") # optional - dot2tex graphviz + sage: # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="dot") Graphics object consisting of 29 graphics primitives - sage: g.plot(layout = "graphviz", prog = "neato") # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="neato") Graphics object consisting of 29 graphics primitives - sage: g.plot(layout = "graphviz", prog = "twopi") # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="twopi") Graphics object consisting of 29 graphics primitives - sage: g.plot(layout = "graphviz", prog = "fdp") # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="fdp") Graphics object consisting of 29 graphics primitives - sage: g = graphs.BalancedTree(5,2) - sage: g.plot(layout = "graphviz", prog = "circo") # optional - dot2tex graphviz + sage: g = graphs.BalancedTree(5,2) # needs networkx + sage: g.plot(layout="graphviz", prog="circo") # needs networkx Graphics object consisting of 62 graphics primitives .. TODO:: @@ -20090,13 +20373,14 @@ def layout_graphviz(self, dim=2, prog='dot', **options): Make sure that :trac:`12364` is fixed:: + sage: # needs sage.combinat sage.modules sage: m = WordMorphism('a->abb,b->ba') sage: w = m.fixed_point('a') sage: prefix = Word(list(w[:100])) sage: pals = prefix.palindromes() sage: poset = Poset((pals, lambda x,y: x.is_factor(y))) sage: H = poset.hasse_diagram() - sage: d = H.layout_graphviz() # optional - dot2tex graphviz + sage: d = H.layout_graphviz() # optional - dot2tex graphviz """ assert_have_dot2tex() assert dim == 2, "3D graphviz layout not implemented" @@ -20190,7 +20474,7 @@ def _circle_embedding(self, vertices, center=(0, 0), radius=1, shift=0, angle=0, sage: g = graphs.CycleGraph(5) sage: g._circle_embedding([0, 2, 4, 1, 3], radius=2, shift=.5) - sage: g.show() + sage: g.show() # needs sage.plot sage: g._circle_embedding(g.vertices(sort=True), angle=0) sage: g._pos[0] @@ -20270,9 +20554,10 @@ def _line_embedding(self, vertices, first=(0, 0), last=(0, 1), return_dict=False sage: g = graphs.PathGraph(5) sage: g._line_embedding([0, 2, 4, 1, 3], first=(-1, -1), last=(1, 1)) - sage: g.show() + sage: g.show() # needs sage.plot - sage: pos = g._line_embedding([4, 2, 0, 1, 3], first=(-1, -1), last=(1, 1), return_dict=True) + sage: pos = g._line_embedding([4, 2, 0, 1, 3], first=(-1, -1), last=(1, 1), + ....: return_dict=True) sage: pos[0] (0.0, 0.0) sage: g.get_pos()[0] @@ -20339,13 +20624,15 @@ def graphplot(self, **options): sage: g = Graph({}, loops=True, multiedges=True, sparse=True) sage: g.add_edges([(0,0,'a'),(0,0,'b'),(0,1,'c'),(0,1,'d'), ....: (0,1,'e'),(0,1,'f'),(0,1,'f'),(2,1,'g'),(2,2,'h')]) - sage: GP = g.graphplot(edge_labels=True, color_by_label=True, edge_style='dashed') - sage: GP.plot() + sage: GP = g.graphplot(edge_labels=True, color_by_label=True, # needs sage.plot + ....: edge_style='dashed') + sage: GP.plot() # needs sage.plot Graphics object consisting of 22 graphics primitives We can modify the :class:`~sage.graphs.graph_plot.GraphPlot` object. Notice that the changes are cumulative:: + sage: # needs sage.plot sage: GP.set_edges(edge_style='solid') sage: GP.plot() Graphics object consisting of 22 graphics primitives @@ -20375,7 +20662,7 @@ def _rich_repr_(self, display_manager, **kwds): sage: dm.preferences.supplemental_plot 'never' sage: del dm.preferences.supplemental_plot - sage: graphs.RandomGNP(20,0.0) + sage: graphs.RandomGNP(20,0.0) # needs networkx RandomGNP(20,0.000000000000000): Graph on 20 vertices (use the .plot() method to plot) sage: dm.preferences.supplemental_plot = 'never' """ @@ -20520,7 +20807,8 @@ def plot(self, **options): sage: from math import sin, cos, pi sage: P = graphs.PetersenGraph() - sage: d = {'#FF0000': [0, 5], '#FF9900': [1, 6], '#FFFF00': [2, 7], '#00FF00': [3, 8], '#0000FF': [4, 9]} + sage: d = {'#FF0000': [0, 5], '#FF9900': [1, 6], '#FFFF00': [2, 7], + ....: '#00FF00': [3, 8], '#0000FF': [4, 9]} sage: pos_dict = {} sage: for i in range(5): ....: x = float(cos(pi/2 + ((2*pi)/5)*i)) @@ -20530,21 +20818,21 @@ def plot(self, **options): ....: x = float(0.5*cos(pi/2 + ((2*pi)/5)*i)) ....: y = float(0.5*sin(pi/2 + ((2*pi)/5)*i)) ....: pos_dict[i] = [x,y] - sage: pl = P.plot(pos=pos_dict, vertex_colors=d) - sage: pl.show() + sage: pl = P.plot(pos=pos_dict, vertex_colors=d) # needs sage.plot + sage: pl.show() # needs sage.plot :: sage: C = graphs.CubeGraph(8) - sage: P = C.plot(vertex_labels=False, vertex_size=0, graph_border=True) - sage: P.show() + sage: P = C.plot(vertex_labels=False, vertex_size=0, graph_border=True) # needs sage.plot + sage: P.show() # needs sage.plot :: sage: G = graphs.HeawoodGraph() sage: for u, v, l in G.edges(sort=False): ....: G.set_edge_label(u, v, '(' + str(u) + ',' + str(v) + ')') - sage: G.plot(edge_labels=True).show() + sage: G.plot(edge_labels=True).show() # needs sage.plot :: @@ -20555,10 +20843,11 @@ def plot(self, **options): ....: 16: [17], 17: [18], 18: [19]}, sparse=True) sage: for u,v,l in D.edges(sort=False): ....: D.set_edge_label(u, v, '(' + str(u) + ',' + str(v) + ')') - sage: D.plot(edge_labels=True, layout='circular').show() + sage: D.plot(edge_labels=True, layout='circular').show() # needs sage.plot :: + sage: # needs sage.plot sage: from sage.plot.colors import rainbow sage: C = graphs.CubeGraph(5) sage: R = rainbow(5) @@ -20567,43 +20856,45 @@ def plot(self, **options): ....: for i in range(5): ....: if u[i] != v[i]: ....: edge_colors[R[i]].append((u, v, l)) - sage: C.plot(vertex_labels=False, vertex_size=0, edge_colors=edge_colors).show() + sage: C.plot(vertex_labels=False, vertex_size=0, + ....: edge_colors=edge_colors).show() :: sage: D = graphs.DodecahedralGraph() sage: Pi = [[6,5,15,14,7], [16,13,8,2,4], [12,17,9,3,1], [0,19,18,10,11]] - sage: D.show(partition=Pi) + sage: D.show(partition=Pi) # needs sage.plot :: sage: G = graphs.PetersenGraph() sage: G.allow_loops(True) sage: G.add_edge(0, 0) - sage: G.show() + sage: G.show() # needs sage.plot :: sage: D = DiGraph({0: [0, 1], 1: [2], 2: [3]}, loops=True) - sage: D.show() - sage: D.show(edge_colors={(0, 1, 0): [(0, 1, None), (1, 2, None)], (0, 0, 0): [(2, 3, None)]}) + sage: D.show() # needs sage.plot + sage: D.show(edge_colors={(0, 1, 0): [(0, 1, None), (1, 2, None)], # needs sage.plot + ....: (0, 0, 0): [(2, 3, None)]}) :: sage: pos = {0: [0.0, 1.5], 1: [-0.8, 0.3], 2: [-0.6, -0.8], 3: [0.6, -0.8], 4: [0.8, 0.3]} sage: g = Graph({0: [1], 1: [2], 2: [3], 3: [4], 4: [0]}) - sage: g.plot(pos=pos, layout='spring', iterations=0) + sage: g.plot(pos=pos, layout='spring', iterations=0) # needs sage.plot Graphics object consisting of 11 graphics primitives :: sage: G = Graph() - sage: P = G.plot() - sage: P.axes() + sage: P = G.plot() # needs sage.plot + sage: P.axes() # needs sage.plot False sage: G = DiGraph() - sage: P = G.plot() - sage: P.axes() + sage: P = G.plot() # needs sage.plot + sage: P.axes() # needs sage.plot False :: @@ -20620,11 +20911,11 @@ def plot(self, **options): 7: (-0.29..., -0.40...), 8: (0.29..., -0.40...), 9: (0.47..., 0.15...)} - sage: P = G.plot(save_pos=True, layout='spring') + sage: P = G.plot(save_pos=True, layout='spring') # needs sage.plot - The following illustrates the format of a position dictionary. + The following illustrates the format of a position dictionary:: - sage: G.get_pos() # currently random across platforms, see #9593 + sage: G.get_pos() # currently random across platforms, see #9593 # needs sage.plot {0: [1.17..., -0.855...], 1: [1.81..., -0.0990...], 2: [1.35..., 0.184...], @@ -20640,14 +20931,14 @@ def plot(self, **options): sage: T = list(graphs.trees(7)) sage: t = T[3] - sage: t.plot(heights={0: [0], 1: [4, 5, 1], 2: [2], 3: [3, 6]}) + sage: t.plot(heights={0: [0], 1: [4, 5, 1], 2: [2], 3: [3, 6]}) # needs sage.plot Graphics object consisting of 14 graphics primitives :: sage: T = list(graphs.trees(7)) sage: t = T[3] - sage: t.plot(heights={0: [0], 1: [4, 5, 1], 2: [2], 3: [3, 6]}) + sage: t.plot(heights={0: [0], 1: [4, 5, 1], 2: [2], 3: [3, 6]}) # needs sage.plot Graphics object consisting of 14 graphics primitives sage: t.set_edge_label(0, 1, -7) sage: t.set_edge_label(0, 5, 3) @@ -20656,58 +20947,64 @@ def plot(self, **options): sage: t.set_edge_label(3, 2, 'spam') sage: t.set_edge_label(2, 6, 3/2) sage: t.set_edge_label(0, 4, 66) - sage: t.plot(heights={0: [0], 1: [4, 5, 1], 2: [2], 3: [3, 6]}, edge_labels=True) + sage: t.plot(heights={0: [0], 1: [4, 5, 1], 2: [2], 3: [3, 6]}, # needs sage.plot + ....: edge_labels=True) Graphics object consisting of 20 graphics primitives :: sage: T = list(graphs.trees(7)) sage: t = T[3] - sage: t.plot(layout='tree') + sage: t.plot(layout='tree') # needs sage.plot Graphics object consisting of 14 graphics primitives :: sage: t = DiGraph('JCC???@A??GO??CO??GO??') - sage: t.plot(layout='tree', tree_root=0, tree_orientation="up") + sage: t.plot(layout='tree', tree_root=0, tree_orientation="up") # needs sage.plot Graphics object consisting of 22 graphics primitives sage: D = DiGraph({0: [1, 2, 3], 2: [1, 4], 3: [0]}) - sage: D.plot() + sage: D.plot() # needs sage.plot Graphics object consisting of 16 graphics primitives sage: D = DiGraph(multiedges=True,sparse=True) sage: for i in range(5): ....: D.add_edge((i, i + 1, 'a')) ....: D.add_edge((i, i - 1, 'b')) - sage: D.plot(edge_labels=True, edge_colors=D._color_by_label()) + sage: D.plot(edge_labels=True, edge_colors=D._color_by_label()) # needs sage.plot Graphics object consisting of 34 graphics primitives - sage: D.plot(edge_labels=True, color_by_label={'a': 'blue', 'b': 'red'}, edge_style='dashed') + sage: D.plot(edge_labels=True, color_by_label={'a': 'blue', 'b': 'red'}, # needs sage.plot + ....: edge_style='dashed') Graphics object consisting of 34 graphics primitives sage: g = Graph({}, loops=True, multiedges=True, sparse=True) sage: g.add_edges([(0, 0, 'a'), (0, 0, 'b'), (0, 1, 'c'), (0, 1, 'd'), ....: (0, 1, 'e'), (0, 1, 'f'), (0, 1, 'f'), (2, 1, 'g'), (2, 2, 'h')]) - sage: g.plot(edge_labels=True, color_by_label=True, edge_style='dashed') + sage: g.plot(edge_labels=True, color_by_label=True, edge_style='dashed') # needs sage.plot Graphics object consisting of 22 graphics primitives :: + sage: # needs sage.modular sage: S = SupersingularModule(389) sage: H = S.hecke_matrix(2) - sage: D = DiGraph(H,sparse=True) - sage: P = D.plot() + sage: D = DiGraph(H, sparse=True) + sage: P = D.plot() # needs sage.plot :: - sage: G=Graph({'a':['a','b','b','b','e'],'b':['c','d','e'],'c':['c','d','d','d'],'d':['e']}, sparse=True) - sage: G.show(pos={'a':[0,1],'b':[1,1],'c':[2,0],'d':[1,0],'e':[0,0]}) + sage: G = Graph({'a': ['a','b','b','b','e'], 'b': ['c','d','e'], + ....: 'c':['c','d','d','d'],'d':['e']}, sparse=True) + sage: G.show(pos={'a':[0,1],'b':[1,1],'c':[2,0],'d':[1,0],'e':[0,0]}) # needs sage.plot TESTS:: sage: G = DiGraph({0: {1: 'a', 2: 'a'}, 1: {0: 'b'}, 2: {0: 'c'}}) - sage: p = G.plot(edge_labels=True, color_by_label={'a': 'yellow', 'b': 'purple'}); p + sage: p = G.plot(edge_labels=True, # needs sage.plot + ....: color_by_label={'a': 'yellow', 'b': 'purple'}); p Graphics object consisting of 14 graphics primitives - sage: sorted([x.options()['rgbcolor'] for x in p if isinstance(x, sage.plot.arrow.CurveArrow)]) + sage: sorted(x.options()['rgbcolor'] for x in p # needs sage.plot + ....: if isinstance(x, sage.plot.arrow.CurveArrow)) ['black', 'purple', 'yellow', 'yellow'] """ return self.graphplot(**options).plot() @@ -20733,8 +21030,8 @@ def show(self, method="matplotlib", **kwds): EXAMPLES:: sage: C = graphs.CubeGraph(8) - sage: P = C.plot(vertex_labels=False, vertex_size=0, graph_border=True) - sage: P.show() # long time (3s on sage.math, 2011) + sage: P = C.plot(vertex_labels=False, vertex_size=0, graph_border=True) # needs sage.plot + sage: P.show() # long time (3s on sage.math, 2011), needs sage.plot """ if method == "js": @@ -20822,37 +21119,45 @@ def plot3d(self, bgcolor=(1, 1, 1), EXAMPLES:: sage: G = graphs.CubeGraph(5) - sage: G.plot3d(iterations=500, edge_size=None, vertex_size=0.04) # long time + sage: G.plot3d(iterations=500, edge_size=None, vertex_size=0.04) # long time, needs sage.plot Graphics3d Object We plot a fairly complicated Cayley graph:: - sage: A5 = AlternatingGroup(5); A5 + sage: A5 = AlternatingGroup(5); A5 # needs sage.groups Alternating group of order 5!/2 as a permutation group - sage: G = A5.cayley_graph() - sage: G.plot3d(vertex_size=0.03, edge_size=0.01, vertex_colors={(1,1,1): list(G)}, bgcolor=(0,0,0), color_by_label=True, iterations=200) # long time + sage: G = A5.cayley_graph() # needs sage.groups + sage: G.plot3d(vertex_size=0.03, edge_size=0.01, # long time # needs sage.groups sage.plot + ....: vertex_colors={(1,1,1): list(G)}, bgcolor=(0,0,0), + ....: color_by_label=True, iterations=200) Graphics3d Object Some :class:`~sage.plot.plot3d.tachyon.Tachyon` examples:: sage: D = graphs.DodecahedralGraph() - sage: P3D = D.plot3d(engine='tachyon') - sage: P3D.show() # long time + sage: P3D = D.plot3d(engine='tachyon') # needs sage.plot + sage: P3D.show() # long time # needs sage.plot :: sage: G = graphs.PetersenGraph() - sage: G.plot3d(engine='tachyon', vertex_colors={(0,0,1): list(G)}).show() # long time + sage: G.plot3d(engine='tachyon', # long time # needs sage.plot + ....: vertex_colors={(0,0,1): list(G)}).show() :: sage: C = graphs.CubeGraph(4) - sage: C.plot3d(engine='tachyon', edge_colors={(0,1,0): C.edges(sort=False)}, vertex_colors={(1,1,1): list(C)}, bgcolor=(0,0,0)).show() # long time + sage: C.plot3d(engine='tachyon', # long time # needs sage.plot + ....: edge_colors={(0,1,0): C.edges(sort=False)}, + ....: vertex_colors={(1,1,1): list(C)}, bgcolor=(0,0,0)).show() :: sage: K = graphs.CompleteGraph(3) - sage: K.plot3d(engine='tachyon', edge_colors={(1,0,0): [(0,1,None)], (0,1,0): [(0,2,None)], (0,0,1): [(1,2,None)]}).show() # long time + sage: K.plot3d(engine='tachyon', # long time # needs sage.plot + ....: edge_colors={(1,0,0): [(0,1,None)], + ....: (0,1,0): [(0,2,None)], + ....: (0,0,1): [(1,2,None)]}).show() A directed version of the dodecahedron @@ -20863,20 +21168,21 @@ def plot3d(self, bgcolor=(1, 1, 1), ....: 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], ....: 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], ....: 17: [18], 18: [19], 19: []}) - sage: D.plot3d().show() # long time + sage: D.plot3d().show() # long time # needs sage.plot :: sage: P = graphs.PetersenGraph().to_directed() - sage: from sage.plot.colors import rainbow - sage: R = rainbow(P.size(), 'rgbtuple') - sage: edge_colors = {R[i]: [e] for i, e in enumerate(P.edge_iterator())} - sage: P.plot3d(engine='tachyon', edge_colors=edge_colors).show() # long time + sage: from sage.plot.colors import rainbow # needs sage.plot + sage: R = rainbow(P.size(), 'rgbtuple') # needs sage.plot + sage: edge_colors = {R[i]: [e] for i, e in enumerate(P.edge_iterator())} # needs sage.plot + sage: P.plot3d(engine='tachyon', edge_colors=edge_colors).show() # long time, needs sage.plot :: - sage: G=Graph({'a':['a','b','b','b','e'],'b':['c','d','e'],'c':['c','d','d','d'],'d':['e']},sparse=True) + sage: G = Graph({'a': ['a','b','b','b','e'], 'b': ['c','d','e'], + ....: 'c': ['c','d','d','d'], 'd': ['e']}, sparse=True) sage: G.show3d() Traceback (most recent call last): ... @@ -20885,23 +21191,24 @@ def plot3d(self, bgcolor=(1, 1, 1), Using the ``partition`` keyword:: sage: G = graphs.WheelGraph(7) - sage: G.plot3d(partition=[[0], [1, 2, 3, 4, 5, 6]]) + sage: G.plot3d(partition=[[0], [1, 2, 3, 4, 5, 6]]) # needs sage.plot Graphics3d Object TESTS:: sage: G = DiGraph({0: {1: 'a', 2: 'a'}, 1: {0: 'b'}, 2: {0: 'c'}}) - sage: p = G.plot3d(edge_labels=True, color_by_label={'a': 'yellow', 'b': 'cyan'}) - sage: s = p.x3d_str() + sage: p = G.plot3d(edge_labels=True, # needs sage.plot + ....: color_by_label={'a': 'yellow', 'b': 'cyan'}) + sage: s = p.x3d_str() # needs sage.plot This 3D plot contains four yellow objects (two cylinders and two cones), two black objects and 2 cyan objects:: - sage: s.count("Material diffuseColor='1.0 1.0 0.0'") + sage: s.count("Material diffuseColor='1.0 1.0 0.0'") # needs sage.plot 4 - sage: s.count("Material diffuseColor='0.0 0.0 0.0'") + sage: s.count("Material diffuseColor='0.0 0.0 0.0'") # needs sage.plot 2 - sage: s.count("Material diffuseColor='0.0 1.0 1.0'") + sage: s.count("Material diffuseColor='0.0 1.0 1.0'") # needs sage.plot 2 .. SEEALSO:: @@ -20911,7 +21218,7 @@ def plot3d(self, bgcolor=(1, 1, 1), """ from . import graph_plot layout_options = {key: kwds[key] for key in kwds.keys() if key in graph_plot.layout_options} - kwds = {key: kwds[key] for key in kwds.keys() if key not in graph_plot.layout_options} + kwds = {key: kwds[key] for key in kwds.keys() if key not in graph_plot.layout_options} if pos3d is None: pos3d = self.layout(dim=3, **layout_options) @@ -20933,7 +21240,7 @@ def plot3d(self, bgcolor=(1, 1, 1), vertex_colors = {(1, 0, 0) : list(self)} if color_by_label: - if edge_colors is None: + if edge_colors is None: # do the coloring edge_colors = self._color_by_label(format=color_by_label) elif edge_colors is None: @@ -20975,7 +21282,7 @@ def plot3d(self, bgcolor=(1, 1, 1), vertex_size=vertex_size, pos3d=pos3d, **kwds) if color_by_label: - if edge_colors is None: + if edge_colors is None: # do the coloring edge_colors = self._color_by_label(format=color_by_label) @@ -21006,8 +21313,7 @@ def plot3d(self, bgcolor=(1, 1, 1), return TT - else: - raise TypeError("rendering engine (%s) not implemented" % engine) + raise TypeError("rendering engine (%s) not implemented" % engine) def show3d(self, bgcolor=(1, 1, 1), vertex_colors=None, vertex_size=0.06, edge_colors=None, edge_size=0.02, edge_size2=0.0325, @@ -21070,36 +21376,43 @@ def show3d(self, bgcolor=(1, 1, 1), vertex_colors=None, vertex_size=0.06, EXAMPLES:: sage: G = graphs.CubeGraph(5) - sage: G.show3d(iterations=500, edge_size=None, vertex_size=0.04) # long time + sage: G.show3d(iterations=500, edge_size=None, vertex_size=0.04) # long time, needs sage.plot We plot a fairly complicated Cayley graph:: - sage: A5 = AlternatingGroup(5); A5 + sage: A5 = AlternatingGroup(5); A5 # needs sage.groups Alternating group of order 5!/2 as a permutation group - sage: G = A5.cayley_graph() - sage: G.show3d(vertex_size=0.03, edge_size=0.01, edge_size2=0.02, + sage: G = A5.cayley_graph() # needs sage.groups + sage: G.show3d(vertex_size=0.03, # long time # needs sage.groups sage.plot + ....: edge_size=0.01, edge_size2=0.02, ....: vertex_colors={(1,1,1): list(G)}, bgcolor=(0,0,0), - ....: color_by_label=True, iterations=200) # long time + ....: color_by_label=True, iterations=200) Some :class:`~sage.plot.plot3d.tachyon.Tachyon` examples:: sage: D = graphs.DodecahedralGraph() - sage: D.show3d(engine='tachyon') # long time + sage: D.show3d(engine='tachyon') # long time # needs sage.plot :: sage: G = graphs.PetersenGraph() - sage: G.show3d(engine='tachyon', vertex_colors={(0,0,1): list(G)}) # long time + sage: G.show3d(engine='tachyon', # long time # needs sage.plot + ....: vertex_colors={(0,0,1): list(G)}) :: sage: C = graphs.CubeGraph(4) - sage: C.show3d(engine='tachyon', edge_colors={(0,1,0): C.edges(sort=False)}, vertex_colors={(1,1,1): list(C)}, bgcolor=(0,0,0)) # long time + sage: C.show3d(engine='tachyon', # long time # needs sage.plot + ....: edge_colors={(0,1,0): C.edges(sort=False)}, + ....: vertex_colors={(1,1,1): list(C)}, bgcolor=(0,0,0)) :: sage: K = graphs.CompleteGraph(3) - sage: K.show3d(engine='tachyon', edge_colors={(1,0,0): [(0, 1, None)], (0, 1, 0): [(0, 2, None)], (0, 0, 1): [(1, 2, None)]}) # long time + sage: K.show3d(engine='tachyon', # long time # needs sage.plot + ....: edge_colors={(1,0,0): [(0, 1, None)], + ....: (0, 1, 0): [(0, 2, None)], + ....: (0, 0, 1): [(1, 2, None)]}) """ self.plot3d(bgcolor=bgcolor, vertex_colors=vertex_colors, edge_colors=edge_colors, vertex_size=vertex_size, engine=engine, @@ -21206,7 +21519,9 @@ def graphviz_string(self, **options): EXAMPLES:: - sage: G = Graph({0: {1: None, 2: None}, 1: {0: None, 2: None}, 2: {0: None, 1: None, 3: 'foo'}, 3: {2: 'foo'}}, sparse=True) + sage: G = Graph({0: {1: None, 2: None}, 1: {0: None, 2: None}, + ....: 2: {0: None, 1: None, 3: 'foo'}, 3: {2: 'foo'}}, + ....: sparse=True) sage: print(G.graphviz_string(edge_labels=True)) graph { node_0 [label="0"]; @@ -21239,7 +21554,8 @@ def graphviz_string(self, **options): Same, with a digraph and a color for edges:: - sage: G = DiGraph({0: {1: None, 2: None}, 1: {2: None}, 2: {3: 'foo'}, 3: {}}, sparse=True) + sage: G = DiGraph({0: {1: None, 2: None}, 1: {2: None}, 2: {3: 'foo'}, 3: {}}, + ....: sparse=True) sage: print(G.graphviz_string(edge_color="red")) digraph { node_0 [label="0"]; @@ -21256,12 +21572,14 @@ def graphviz_string(self, **options): A digraph using latex labels for vertices and edges:: - sage: f(x) = -1 / x # optional - sage.symbolic - sage: g(x) = 1 / (x + 1) # optional - sage.symbolic - sage: G = DiGraph() # optional - sage.symbolic - sage: G.add_edges((i, f(i), f) for i in (1, 2, 1/2, 1/4)) # optional - sage.symbolic - sage: G.add_edges((i, g(i), g) for i in (1, 2, 1/2, 1/4)) # optional - sage.symbolic - sage: print(G.graphviz_string(labels="latex", edge_labels=True)) # random # optional - sage.symbolic + sage: # needs sage.symbolic + sage: f(x) = -1 / x + sage: g(x) = 1 / (x + 1) + sage: G = DiGraph() + sage: G.add_edges((i, f(i), f) for i in (1, 2, 1/2, 1/4)) + sage: G.add_edges((i, g(i), g) for i in (1, 2, 1/2, 1/4)) + sage: print(G.graphviz_string(labels="latex", # random + ....: edge_labels=True)) digraph { node [shape="plaintext"]; node_10 [label=" ", texlbl="$1$"]; @@ -21287,7 +21605,8 @@ def graphviz_string(self, **options): node_4 -> node_9 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"]; } - sage: print(G.graphviz_string(labels="latex", color_by_label=True)) # random # optional - sage.symbolic + sage: print(G.graphviz_string(labels="latex", # random # needs sage.symbolic + ....: color_by_label=True)) digraph { node [shape="plaintext"]; node_10 [label=" ", texlbl="$1$"]; @@ -21313,7 +21632,8 @@ def graphviz_string(self, **options): node_4 -> node_9 [color = "#00ffff"]; } - sage: print(G.graphviz_string(labels="latex", color_by_label={f: "red", g: "blue"})) # random # optional - sage.symbolic + sage: print(G.graphviz_string(labels="latex", # random # needs sage.symbolic + ....: color_by_label={f: "red", g: "blue"})) digraph { node [shape="plaintext"]; node_10 [label=" ", texlbl="$1$"]; @@ -21400,7 +21720,7 @@ def graphviz_string(self, **options): sage: def edge_options(data): ....: u, v, label = data ....: return {"dir":"back"} if u == 1 else {} - sage: print(G.graphviz_string(edge_options=edge_options)) # random # optional - sage.symbolic + sage: print(G.graphviz_string(edge_options=edge_options)) # random # needs sage.symbolic digraph { node_0 [label="-1"]; node_1 [label="-1/2"]; @@ -21434,7 +21754,7 @@ def graphviz_string(self, **options): ....: if (u,v) == (1, -1): options["label_style"] = "latex" ....: if (u,v) == (1, 1/2): options["dir"] = "back" ....: return options - sage: print(G.graphviz_string(edge_options=edge_options)) # random # optional - sage.symbolic + sage: print(G.graphviz_string(edge_options=edge_options)) # random # needs sage.symbolic digraph { node_0 [label="-1"]; node_1 [label="-1/2"]; @@ -21530,6 +21850,7 @@ def graphviz_string(self, **options): The following digraph has vertices with newlines in their string representations:: + sage: # needs sage.modules sage: m1 = matrix(3, 3) sage: m2 = matrix(3, 3, 1) sage: m1.set_immutable() @@ -21593,12 +21914,12 @@ def graphviz_string(self, **options): Check that :trac:`25121` is fixed:: sage: G = Graph([(0, 1)]) - sage: G.graphviz_string(edge_colors={(0.25, 0.5, 1.0): [(0, 1)]}) + sage: G.graphviz_string(edge_colors={(0.25, 0.5, 1.0): [(0, 1)]}) # needs sage.plot 'graph {\n node_0 [label="0"];\n node_1 [label="1"];\n\n node_0 -- node_1 [color = "#4080ff"];\n}' sage: G = Graph([(0, 1)]) - sage: G.set_latex_options(edge_colors={(0, 1): (0.25, 0.5, 1.0)}) - sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz + sage: G.set_latex_options(edge_colors={(0, 1): (0.25, 0.5, 1.0)}) # needs sage.plot + sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz, needs sage.plot \begin{tikzpicture}[>=latex,line join=bevel,] ... \definecolor{strokecolor}{rgb}{0.25,0.5,1.0}; @@ -21800,7 +22121,9 @@ def graphviz_to_file_named(self, filename, **options): EXAMPLES:: - sage: G = Graph({0: {1: None, 2: None}, 1: {0: None, 2: None}, 2: {0: None, 1: None, 3: 'foo'}, 3: {2: 'foo'}}, sparse=True) + sage: G = Graph({0: {1: None, 2: None}, 1: {0: None, 2: None}, + ....: 2: {0: None, 1: None, 3: 'foo'}, 3: {2: 'foo'}}, + ....: sparse=True) sage: import tempfile sage: with tempfile.NamedTemporaryFile(mode="a+t") as f: ....: G.graphviz_to_file_named(f.name, edge_labels=True) @@ -21844,26 +22167,26 @@ def spectrum(self, laplacian=False): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.spectrum() + sage: P.spectrum() # needs sage.modules sage.rings.number_field [3, 1, 1, 1, 1, 1, -2, -2, -2, -2] - sage: P.spectrum(laplacian=True) + sage: P.spectrum(laplacian=True) # needs sage.modules sage.rings.number_field [5, 5, 5, 5, 2, 2, 2, 2, 2, 0] sage: D = P.to_directed() sage: D.delete_edge(7, 9) - sage: D.spectrum() + sage: D.spectrum() # needs sage.modules sage.rings.number_field [2.9032119259..., 1, 1, 1, 1, 0.8060634335..., -1.7092753594..., -2, -2, -2] :: sage: C = graphs.CycleGraph(8) - sage: C.spectrum() + sage: C.spectrum() # needs sage.modules sage.rings.number_field [2, 1.4142135623..., 1.4142135623..., 0, 0, -1.4142135623..., -1.4142135623..., -2] A digraph may have complex eigenvalues. Previously, the complex parts of graph eigenvalues were being dropped. For a 3-cycle, we have:: sage: T = DiGraph({0: [1], 1: [2], 2: [0]}) - sage: T.spectrum() + sage: T.spectrum() # needs sage.modules sage.rings.number_field [1, -0.5000000000... + 0.8660254037...*I, -0.5000000000... - 0.8660254037...*I] TESTS: @@ -21876,6 +22199,7 @@ def spectrum(self, laplacian=False): test both the Laplacian construction and the computation of eigenvalues. :: + sage: # needs sage.modules sage.rings.number_field sage: H = graphs.HoffmanSingletonGraph() sage: evals = H.spectrum() sage: lap = [7 - x for x in evals] @@ -21926,18 +22250,17 @@ def characteristic_polynomial(self, var='x', laplacian=False): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.characteristic_polynomial() + sage: P.characteristic_polynomial() # needs sage.modules x^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48 - sage: P.charpoly() + sage: P.charpoly() # needs sage.modules x^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48 - sage: P.characteristic_polynomial(laplacian=True) + sage: P.characteristic_polynomial(laplacian=True) # needs sage.modules x^10 - 30*x^9 + 390*x^8 - 2880*x^7 + 13305*x^6 - 39882*x^5 + 77640*x^4 - 94800*x^3 + 66000*x^2 - 20000*x """ if laplacian: return self.kirchhoff_matrix(vertices=list(self)).charpoly(var=var) - else: - return self.adjacency_matrix(vertices=list(self)).charpoly(var=var) + return self.adjacency_matrix(vertices=list(self)).charpoly(var=var) # alias, consistent with linear algebra code charpoly = characteristic_polynomial @@ -21966,7 +22289,7 @@ def eigenvectors(self, laplacian=False): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.eigenvectors() + sage: P.eigenvectors() # needs sage.modules sage.rings.number_field [(3, [ (1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ], 1), (-2, [ @@ -21986,7 +22309,7 @@ def eigenvectors(self, laplacian=False): graph is regular. However, since the output also contains the eigenvalues, the two outputs are slightly different:: - sage: P.eigenvectors(laplacian=True) + sage: P.eigenvectors(laplacian=True) # needs sage.modules sage.rings.number_field [(0, [ (1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ], 1), (5, [ @@ -22005,7 +22328,7 @@ def eigenvectors(self, laplacian=False): :: sage: C = graphs.CycleGraph(8) - sage: C.eigenvectors() + sage: C.eigenvectors() # needs sage.modules sage.rings.number_field [(2, [ (1, 1, 1, 1, 1, 1, 1, 1) @@ -22035,7 +22358,7 @@ def eigenvectors(self, laplacian=False): graph eigenvalues were being dropped. For a 3-cycle, we have:: sage: T = DiGraph({0:[1], 1:[2], 2:[0]}) - sage: T.eigenvectors() + sage: T.eigenvectors() # needs sage.modules sage.rings.number_field [(1, [ (1, 1, 1) @@ -22076,48 +22399,48 @@ def eigenspaces(self, laplacian=False): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.eigenspaces() + sage: P.eigenspaces() # needs sage.modules sage.rings.number_field [ - (3, Vector space of degree 10 and dimension 1 over Rational Field - User basis matrix: - [1 1 1 1 1 1 1 1 1 1]), + (3, Vector space of degree 10 and dimension 1 over Rational Field + User basis matrix: + [1 1 1 1 1 1 1 1 1 1]), (-2, Vector space of degree 10 and dimension 4 over Rational Field - User basis matrix: - [ 1 0 0 0 -1 -1 -1 0 1 1] - [ 0 1 0 0 -1 0 -2 -1 1 2] - [ 0 0 1 0 -1 1 -1 -2 0 2] - [ 0 0 0 1 -1 1 0 -1 -1 1]), - (1, Vector space of degree 10 and dimension 5 over Rational Field - User basis matrix: - [ 1 0 0 0 0 1 -1 0 0 -1] - [ 0 1 0 0 0 -1 1 -1 0 0] - [ 0 0 1 0 0 0 -1 1 -1 0] - [ 0 0 0 1 0 0 0 -1 1 -1] - [ 0 0 0 0 1 -1 0 0 -1 1]) + User basis matrix: + [ 1 0 0 0 -1 -1 -1 0 1 1] + [ 0 1 0 0 -1 0 -2 -1 1 2] + [ 0 0 1 0 -1 1 -1 -2 0 2] + [ 0 0 0 1 -1 1 0 -1 -1 1]), + (1, Vector space of degree 10 and dimension 5 over Rational Field + User basis matrix: + [ 1 0 0 0 0 1 -1 0 0 -1] + [ 0 1 0 0 0 -1 1 -1 0 0] + [ 0 0 1 0 0 0 -1 1 -1 0] + [ 0 0 0 1 0 0 0 -1 1 -1] + [ 0 0 0 0 1 -1 0 0 -1 1]) ] Eigenspaces for the Laplacian should be identical since the Petersen graph is regular. However, since the output also contains the eigenvalues, the two outputs are slightly different:: - sage: P.eigenspaces(laplacian=True) + sage: P.eigenspaces(laplacian=True) # needs sage.modules sage.rings.number_field [ (0, Vector space of degree 10 and dimension 1 over Rational Field - User basis matrix: - [1 1 1 1 1 1 1 1 1 1]), + User basis matrix: + [1 1 1 1 1 1 1 1 1 1]), (5, Vector space of degree 10 and dimension 4 over Rational Field - User basis matrix: - [ 1 0 0 0 -1 -1 -1 0 1 1] - [ 0 1 0 0 -1 0 -2 -1 1 2] - [ 0 0 1 0 -1 1 -1 -2 0 2] - [ 0 0 0 1 -1 1 0 -1 -1 1]), + User basis matrix: + [ 1 0 0 0 -1 -1 -1 0 1 1] + [ 0 1 0 0 -1 0 -2 -1 1 2] + [ 0 0 1 0 -1 1 -1 -2 0 2] + [ 0 0 0 1 -1 1 0 -1 -1 1]), (2, Vector space of degree 10 and dimension 5 over Rational Field - User basis matrix: - [ 1 0 0 0 0 1 -1 0 0 -1] - [ 0 1 0 0 0 -1 1 -1 0 0] - [ 0 0 1 0 0 0 -1 1 -1 0] - [ 0 0 0 1 0 0 0 -1 1 -1] - [ 0 0 0 0 1 -1 0 0 -1 1]) + User basis matrix: + [ 1 0 0 0 0 1 -1 0 0 -1] + [ 0 1 0 0 0 -1 1 -1 0 0] + [ 0 0 1 0 0 0 -1 1 -1 0] + [ 0 0 0 1 0 0 0 -1 1 -1] + [ 0 0 0 0 1 -1 0 0 -1 1]) ] Notice how one eigenspace below is described with a square root of 2. @@ -22125,36 +22448,38 @@ def eigenspaces(self, laplacian=False): corresponding eigenspace:: sage: C = graphs.CycleGraph(8) - sage: C.eigenspaces() + sage: C.eigenspaces() # needs sage.modules sage.rings.number_field [ - (2, Vector space of degree 8 and dimension 1 over Rational Field - User basis matrix: - [1 1 1 1 1 1 1 1]), + (2, Vector space of degree 8 and dimension 1 over Rational Field + User basis matrix: + [1 1 1 1 1 1 1 1]), (-2, Vector space of degree 8 and dimension 1 over Rational Field - User basis matrix: - [ 1 -1 1 -1 1 -1 1 -1]), - (0, Vector space of degree 8 and dimension 2 over Rational Field - User basis matrix: - [ 1 0 -1 0 1 0 -1 0] - [ 0 1 0 -1 0 1 0 -1]), - (a3, Vector space of degree 8 and dimension 2 over Number Field in a3 with defining polynomial x^2 - 2 - User basis matrix: - [ 1 0 -1 -a3 -1 0 1 a3] - [ 0 1 a3 1 0 -1 -a3 -1]) + User basis matrix: + [ 1 -1 1 -1 1 -1 1 -1]), + (0, Vector space of degree 8 and dimension 2 over Rational Field + User basis matrix: + [ 1 0 -1 0 1 0 -1 0] + [ 0 1 0 -1 0 1 0 -1]), + (a3, Vector space of degree 8 and dimension 2 over + Number Field in a3 with defining polynomial x^2 - 2 + User basis matrix: + [ 1 0 -1 -a3 -1 0 1 a3] + [ 0 1 a3 1 0 -1 -a3 -1]) ] A digraph may have complex eigenvalues and eigenvectors. For a 3-cycle, we have:: sage: T = DiGraph({0: [1], 1: [2], 2: [0]}) - sage: T.eigenspaces() + sage: T.eigenspaces() # needs sage.modules sage.rings.number_field [ - (1, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [1 1 1]), - (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 + x + 1 - User basis matrix: - [ 1 a1 -a1 - 1]) + (1, Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [1 1 1]), + (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 + with defining polynomial x^2 + x + 1 + User basis matrix: + [ 1 a1 -a1 - 1]) ] """ if laplacian: @@ -22224,7 +22549,7 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input=True, c EXAMPLES:: sage: G = graphs.PathGraph(3) - sage: G.am() + sage: G.am() # needs sage.modules [0 1 0] [1 0 1] [0 1 0] @@ -22232,7 +22557,7 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input=True, c Relabeling using a dictionary. Note that the dictionary does not define the new label of vertex `0`:: - sage: G.relabel({1:2,2:1}, inplace=False).am() + sage: G.relabel({1:2,2:1}, inplace=False).am() # needs sage.modules [0 0 1] [0 0 1] [1 1 0] @@ -22242,21 +22567,22 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input=True, c vertices have an image can require some time, and this feature can be disabled (at your own risk):: - sage: G.relabel({1:2,2:1}, inplace=False, complete_partial_function = False).am() + sage: G.relabel({1:2,2:1}, inplace=False, # needs sage.modules + ....: complete_partial_function=False).am() Traceback (most recent call last): ... KeyError: 0 Relabeling using a list:: - sage: G.relabel([0,2,1], inplace=False).am() + sage: G.relabel([0,2,1], inplace=False).am() # needs sage.modules [0 0 1] [0 0 1] [1 1 0] Relabeling using an iterable:: - sage: G.relabel(iter((0,2,1)), inplace=False).am() + sage: G.relabel(iter((0,2,1)), inplace=False).am() # needs sage.modules [0 0 1] [0 0 1] [1 1 0] @@ -22264,10 +22590,10 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input=True, c Relabeling using a Sage permutation:: sage: G = graphs.PathGraph(3) - sage: from sage.groups.perm_gps.permgroup_named import SymmetricGroup # optional - sage.groups - sage: S = SymmetricGroup(3) # optional - sage.groups - sage: gamma = S('(1,2)') # optional - sage.groups - sage: G.relabel(gamma, inplace=False).am() # optional - sage.groups + sage: from sage.groups.perm_gps.permgroup_named import SymmetricGroup # needs sage.groups + sage: S = SymmetricGroup(3) # needs sage.groups + sage: gamma = S('(1,2)') # needs sage.groups + sage: G.relabel(gamma, inplace=False).am() # needs sage.groups sage.modules [0 0 1] [0 0 1] [1 1 0] @@ -22386,7 +22712,10 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input=True, c sage: G.relabel( [ i+1 for i in range(G.order()) ], inplace=True ) sage: G.relabel( [ i+1 for i in range(G.order()) ], inplace=True ) """ - from sage.groups.perm_gps.permgroup_element import PermutationGroupElement + try: + from sage.groups.perm_gps.permgroup_element import PermutationGroupElement + except ImportError: + PermutationGroupElement = () if not inplace: G = copy(self) @@ -22514,9 +22843,9 @@ def degree_to_cell(self, vertex, cell): in_neighbors_in_cell = set([a for a, _, _ in self.incoming_edges(vertex)]) & set(cell) out_neighbors_in_cell = set([a for _, a, _ in self.outgoing_edges(vertex)]) & set(cell) return (len(in_neighbors_in_cell), len(out_neighbors_in_cell)) - else: - neighbors_in_cell = set(self.neighbors(vertex)) & set(cell) - return len(neighbors_in_cell) + + neighbors_in_cell = set(self.neighbors(vertex)) & set(cell) + return len(neighbors_in_cell) def is_equitable(self, partition, quotient_matrix=False): """ @@ -22547,7 +22876,7 @@ def is_equitable(self, partition, quotient_matrix=False): False sage: G.is_equitable([[0,4],[1,3,5,9],[2,6,8,7]]) True - sage: G.is_equitable([[0,4],[1,3,5,9],[2,6,8,7]], quotient_matrix=True) + sage: G.is_equitable([[0,4],[1,3,5,9],[2,6,8,7]], quotient_matrix=True) # needs sage.modules [1 2 0] [1 0 2] [0 2 1] @@ -22562,7 +22891,8 @@ def is_equitable(self, partition, quotient_matrix=False): sage: ss.is_equitable(prt) Traceback (most recent call last): ... - TypeError: Partition ([[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)], [(2, 3), (3, 4)]]) is not valid for this graph: vertices are incorrect. + TypeError: Partition ([[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)], + [(2, 3), (3, 4)]]) is not valid for this graph: vertices are incorrect. :: @@ -22592,13 +22922,13 @@ def is_equitable(self, partition, quotient_matrix=False): else: M[i, j] = degrees[0] return M - else: - for cell1 in partition: - for cell2 in partition: - degrees = [self.degree_to_cell(u, cell2) for u in cell1] - if len(set(degrees)) > 1: - return False - return True + + for cell1 in partition: + for cell2 in partition: + degrees = [self.degree_to_cell(u, cell2) for u in cell1] + if len(set(degrees)) > 1: + return False + return True def coarsest_equitable_refinement(self, partition, sparse=True): r""" @@ -22647,7 +22977,8 @@ def coarsest_equitable_refinement(self, partition, sparse=True): sage: ss.coarsest_equitable_refinement(prt) Traceback (most recent call last): ... - TypeError: partition ([[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)], [(2, 3), (3, 4)]]) is not valid for this graph: vertices are incorrect + TypeError: partition ([[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)], + [(2, 3), (3, 4)]]) is not valid for this graph: vertices are incorrect :: @@ -22701,25 +23032,25 @@ def automorphism_group(self, partition=None, verbosity=0, INPUT: - - ``partition`` - default is the unit partition, + - ``partition`` -- default is the unit partition, otherwise computes the subgroup of the full automorphism group respecting the partition. - - ``edge_labels`` - default False, otherwise allows + - ``edge_labels`` -- default ``False``, otherwise allows only permutations respecting edge labels. - - ``order`` - (default False) if True, compute the + - ``order`` -- (default ``False``) if ``True``, compute the order of the automorphism group - - ``return_group`` - default True + - ``return_group`` -- default ``True`` - - ``orbits`` - returns the orbits of the group acting + - ``orbits`` -- returns the orbits of the group acting on the vertices of the graph - - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group is + - ``algorithm`` -- If ``algorithm = "bliss"``, the automorphism group is computed using the optional package bliss (http://www.tcs.tkk.fi/Software/bliss/index.html). Setting it to - "sage" uses Sage's implementation. If set to ``None`` (default), bliss + ``"sage"`` uses Sage's implementation. If set to ``None`` (default), bliss is used when available. OUTPUT: The order of the output is group, order, orbits. However, there @@ -22729,9 +23060,10 @@ def automorphism_group(self, partition=None, verbosity=0, Graphs:: + sage: # needs sage.groups sage: graphs_query = GraphQuery(display_cols=['graph6'],num_vertices=4) sage: L = graphs_query.get_graphs_list() - sage: graphs_list.show_graphs(L) + sage: graphs_list.show_graphs(L) # needs sage.plot sage: for g in L: ....: G = g.automorphism_group() ....: G.order(), G.gens() @@ -22756,6 +23088,7 @@ def automorphism_group(self, partition=None, verbosity=0, :: + sage: # needs sage.groups sage: D = graphs.DodecahedralGraph() sage: G = D.automorphism_group() sage: A5 = AlternatingGroup(5) @@ -22770,34 +23103,35 @@ def automorphism_group(self, partition=None, verbosity=0, sage: G.add_edge(('a', 'b')) sage: G.add_edge(('a', 'b')) sage: G.add_edge(('a', 'b')) - sage: G.automorphism_group() + sage: G.automorphism_group() # needs sage.groups Permutation Group with generators [('a','b')] Digraphs:: sage: D = DiGraph( { 0:[1], 1:[2], 2:[3], 3:[4], 4:[0] } ) - sage: D.automorphism_group() + sage: D.automorphism_group() # needs sage.groups Permutation Group with generators [(0,1,2,3,4)] Edge labeled graphs:: sage: G = Graph(sparse=True) sage: G.add_edges( [(0,1,'a'),(1,2,'b'),(2,3,'c'),(3,4,'b'),(4,0,'a')] ) - sage: G.automorphism_group(edge_labels=True) + sage: G.automorphism_group(edge_labels=True) # needs sage.groups Permutation Group with generators [(1,4)(2,3)] sage: G.automorphism_group(edge_labels=True, algorithm="bliss") # optional - bliss Permutation Group with generators [(1,4)(2,3)] - sage: G.automorphism_group(edge_labels=True, algorithm="sage") + sage: G.automorphism_group(edge_labels=True, algorithm="sage") # needs sage.groups Permutation Group with generators [(1,4)(2,3)] :: sage: G = Graph({0 : {1 : 7}}) - sage: G.automorphism_group(edge_labels=True) + sage: G.automorphism_group(edge_labels=True) # needs sage.groups Permutation Group with generators [(0,1)] + sage: # needs sage.groups sage: foo = Graph(sparse=True) sage: bar = Graph(sparse=True) sage: foo.add_edges([(0,1,1),(1,2,2), (2,3,3)]) @@ -22812,32 +23146,34 @@ def automorphism_group(self, partition=None, verbosity=0, You can also ask for just the order of the group:: sage: G = graphs.PetersenGraph() - sage: G.automorphism_group(return_group=False, order=True) + sage: G.automorphism_group(return_group=False, order=True) # needs sage.groups 120 Or, just the orbits (note that each graph here is vertex transitive) :: + sage: # needs sage.groups sage: G = graphs.PetersenGraph() - sage: G.automorphism_group(return_group=False, orbits=True,algorithm='sage') + sage: G.automorphism_group(return_group=False, orbits=True, algorithm='sage') [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]] sage: orb = G.automorphism_group(partition=[[0],list(range(1,10))], - ....: return_group=False, orbits=True,algorithm='sage') + ....: return_group=False, orbits=True, algorithm='sage') sage: sorted([sorted(o) for o in orb], key=len) [[0], [1, 4, 5], [2, 3, 6, 7, 8, 9]] sage: C = graphs.CubeGraph(3) - sage: orb = C.automorphism_group(orbits=True, return_group=False,algorithm='sage') + sage: orb = C.automorphism_group(orbits=True, return_group=False, algorithm='sage') sage: [sorted(o) for o in orb] [['000', '001', '010', '011', '100', '101', '110', '111']] One can also use the faster algorithm for computing the automorphism group of the graph - bliss:: - sage: G = graphs.HallJankoGraph() # optional - bliss - sage: A1 = G.automorphism_group() # optional - bliss - sage: A2 = G.automorphism_group(algorithm='bliss') # optional - bliss - sage: A1.is_isomorphic(A2) # optional - bliss + sage: # optional - bliss + sage: G = graphs.HallJankoGraph() + sage: A1 = G.automorphism_group() # needs sage.groups + sage: A2 = G.automorphism_group(algorithm='bliss') + sage: A1.is_isomorphic(A2) # needs sage.groups True TESTS: @@ -22846,13 +23182,14 @@ def automorphism_group(self, partition=None, verbosity=0, sage: g=graphs.CubeGraph(3) sage: g.relabel() - sage: g.automorphism_group(partition=[[0,1,2],[3,4,5]],algorithm='sage') + sage: g.automorphism_group(partition=[[0,1,2],[3,4,5]],algorithm='sage') # needs sage.groups Traceback (most recent call last): ... KeyError: ... Labeled automorphism group:: + sage: # needs sage.combinat sage.groups sage: d = digraphs.DeBruijn(3,2) sage: A = d.automorphism_group(algorithm='sage') sage: A_target = PermutationGroup(["('02','10','21')('00','11','22')('01','12','20')", @@ -22869,24 +23206,24 @@ def automorphism_group(self, partition=None, verbosity=0, The labeling is correct:: sage: g = graphs.PetersenGraph() - sage: ag = g.automorphism_group() - sage: all(len(ag.orbit(e, action="OnPairs")) == 30 + sage: ag = g.automorphism_group() # needs sage.groups + sage: all(len(ag.orbit(e, action="OnPairs")) == 30 # needs sage.groups ....: for e in g.edge_iterator(labels=False)) True Empty group, correct domain:: - sage: ag = Graph({'a':['a'], 'b':[]}).automorphism_group() - sage: ag + sage: ag = Graph({'a':['a'], 'b':[]}).automorphism_group() # needs sage.groups + sage: ag # needs sage.groups Permutation Group with generators [()] - sage: sorted(ag.domain()) + sage: sorted(ag.domain()) # needs sage.groups ['a', 'b'] We can check that the subgroups are labelled correctly (:trac:`15656`):: sage: G1 = Graph(':H`ECw@HGXGAGUG`e') - sage: G = G1.automorphism_group() + sage: G = G1.automorphism_group() # needs sage.groups sage: G.subgroups() [Subgroup generated by [()] of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)]), Subgroup generated by [(0,7)(1,4)(2,3)(6,8)] of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)])] @@ -22894,6 +23231,7 @@ def automorphism_group(self, partition=None, verbosity=0, We check that the representations of the groups returned with ``'sage'`` and ``'bliss'`` are the same (:trac:`27571`):: + sage: # needs sage.groups sage.libs.pari sage: G = graphs.PaleyGraph(9) sage: a1 = G.automorphism_group(algorithm='sage') sage: V = sorted(G, reverse=True) @@ -22905,8 +23243,9 @@ def automorphism_group(self, partition=None, verbosity=0, sage: b1 = G.automorphism_group(algorithm='bliss') # optional - bliss sage: str(a1) == str(b1) # optional - bliss True - sage: b2 = G.automorphism_group(algorithm='bliss', partition=[V]) # optional - bliss - sage: str(a2) == str(b2) # optional - bliss + sage: b2 = G.automorphism_group(algorithm='bliss', # optional - bliss + ....: partition=[V]) + sage: str(a2) == str(b2) # optional - bliss True """ from sage.features.bliss import Bliss @@ -23069,13 +23408,13 @@ def is_vertex_transitive(self, partition=None, verbosity=0, sage: G.is_vertex_transitive() False sage: P = graphs.PetersenGraph() - sage: P.is_vertex_transitive() + sage: P.is_vertex_transitive() # needs sage.groups True sage: D = graphs.DodecahedralGraph() - sage: D.is_vertex_transitive() + sage: D.is_vertex_transitive() # needs sage.groups True - sage: R = graphs.RandomGNP(2000, .01) - sage: R.is_vertex_transitive() + sage: R = graphs.RandomGNP(2000, .01) # needs networkx + sage: R.is_vertex_transitive() # needs networkx False """ if partition is None: @@ -23153,19 +23492,19 @@ def is_hamiltonian(self, solver=None, constraint_generation=None, The Heawood Graph is known to be Hamiltonian :: sage: g = graphs.HeawoodGraph() - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True The Petergraph, though, is not :: sage: g = graphs.PetersenGraph() - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip False TESTS:: sage: g = graphs.ChvatalGraph() - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True :trac:`16210`:: @@ -23173,7 +23512,7 @@ def is_hamiltonian(self, solver=None, constraint_generation=None, sage: g = graphs.CycleGraph(10) sage: g.allow_loops(True) sage: g.add_edge(0,0) - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True """ from sage.categories.sets_cat import EmptySetError @@ -23207,21 +23546,21 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False Graphs:: - sage: from sage.groups.perm_gps.permgroup_named import SymmetricGroup # optional - sage.groups + sage: from sage.groups.perm_gps.permgroup_named import SymmetricGroup # needs sage.groups sage: D = graphs.DodecahedralGraph() sage: E = copy(D) - sage: gamma = SymmetricGroup(20).random_element() # optional - sage.groups - sage: E.relabel(gamma) # optional - sage.groups + sage: gamma = SymmetricGroup(20).random_element() # needs sage.groups + sage: E.relabel(gamma) # needs sage.groups sage: D.is_isomorphic(E) True :: sage: D = graphs.DodecahedralGraph() - sage: S = SymmetricGroup(20) # optional - sage.groups - sage: gamma = S.random_element() # optional - sage.groups - sage: E = copy(D) # optional - sage.groups - sage: E.relabel(gamma) # optional - sage.groups + sage: S = SymmetricGroup(20) # needs sage.groups + sage: gamma = S.random_element() # needs sage.groups + sage: E = copy(D) # needs sage.groups + sage: E.relabel(gamma) # needs sage.groups sage: a,b = D.is_isomorphic(E, certificate=True); a True sage: from sage.graphs.generic_graph_pyx import spring_layout_fast @@ -23497,18 +23836,17 @@ def multilabel(e): return False elif not certificate: return True + isom_trans = {} + if edge_labels or self.has_multiple_edges(): + relabeling2_inv = {} + for x in relabeling2: + relabeling2_inv[relabeling2[x]] = x + for v in self: + isom_trans[v] = relabeling2_inv[other_vertices[isom[G_to[relabeling[v]]]]] else: - isom_trans = {} - if edge_labels or self.has_multiple_edges(): - relabeling2_inv = {} - for x in relabeling2: - relabeling2_inv[relabeling2[x]] = x - for v in self: - isom_trans[v] = relabeling2_inv[other_vertices[isom[G_to[relabeling[v]]]]] - else: - for v in self: - isom_trans[v] = other_vertices[isom[G_to[v]]] - return True, isom_trans + for v in self: + isom_trans[v] = other_vertices[isom[G_to[v]]] + return True, isom_trans def canonical_label(self, partition=None, certificate=False, edge_labels=False, algorithm=None, return_graph=True): @@ -23586,7 +23924,7 @@ class by some canonization function `c`. If `G` and `H` are graphs, sage: P = graphs.PetersenGraph() sage: DP = P.to_directed() - sage: DP.canonical_label(algorithm='sage').adjacency_matrix() + sage: DP.canonical_label(algorithm='sage').adjacency_matrix() # needs sage.modules [0 0 0 0 0 0 0 1 1 1] [0 0 0 0 1 0 1 0 0 1] [0 0 0 1 0 0 1 0 1 0] @@ -23604,10 +23942,12 @@ class by some canonization function `c`. If `G` and `H` are graphs, sage: G.add_edges( [(0,1,'a'),(1,2,'b'),(2,3,'c'),(3,4,'b'),(4,0,'a')] ) sage: G.canonical_label(edge_labels=True) Graph on 5 vertices - sage: G.canonical_label(edge_labels=True, algorithm="bliss", certificate=True) # optional - bliss + sage: G.canonical_label(edge_labels=True, algorithm="bliss", # optional - bliss + ....: certificate=True) (Graph on 5 vertices, {0: 4, 1: 3, 2: 1, 3: 0, 4: 2}) - sage: G.canonical_label(edge_labels=True, algorithm="sage", certificate=True) + sage: G.canonical_label(edge_labels=True, algorithm="sage", + ....: certificate=True) (Graph on 5 vertices, {0: 4, 1: 3, 2: 0, 3: 1, 4: 2}) Another example where different canonization algorithms give @@ -23615,10 +23955,10 @@ class by some canonization function `c`. If `G` and `H` are graphs, sage: g = Graph({'a': ['b'], 'c': ['d']}) sage: g_sage = g.canonical_label(algorithm='sage') - sage: g_bliss = g.canonical_label(algorithm='bliss') # optional - bliss + sage: g_bliss = g.canonical_label(algorithm='bliss') # optional - bliss sage: g_sage.edges(sort=True, labels=False) [(0, 3), (1, 2)] - sage: g_bliss.edges(sort=True, labels=False) # optional - bliss + sage: g_bliss.edges(sort=True, labels=False) # optional - bliss [(0, 1), (2, 3)] TESTS:: @@ -23626,7 +23966,7 @@ class by some canonization function `c`. If `G` and `H` are graphs, sage: G = Graph([['a', 'b'], [('a', 'b')]]) sage: G.canonical_label(algorithm='sage', certificate=True) (Graph on 2 vertices, {'a': 0, 'b': 1}) - sage: G.canonical_label(algorithm='bliss', certificate=True) # optional - bliss + sage: G.canonical_label(algorithm='bliss', certificate=True) # optional - bliss (Graph on 2 vertices, {'a': 1, 'b': 0}) Check for immutable graphs (:trac:`16602`):: @@ -23668,7 +24008,7 @@ class by some canonization function `c`. If `G` and `H` are graphs, sage: algos = ['sage'] sage: algos.append('bliss') # optional - bliss sage: S = Set([0,1,2]) - sage: for (algo, edges) in product(algos, edges_list): + sage: for (algo, edges) in product(algos, edges_list): # needs sage.combinat ....: L = cartesian_product([S] * len(edges)) ....: O = OrderedSetPartitions([0,1,2,3]) ....: P = Permutations([0,1,2,3]) @@ -23759,8 +24099,7 @@ class by some canonization function `c`. If `G` and `H` are graphs, H.relabel(c_new) if certificate: return H, c_new - else: - return H + return H def is_cayley(self, return_group=False, mapping=False, generators=False, allow_disconnected=False): @@ -23782,16 +24121,16 @@ def is_cayley(self, return_group=False, mapping=False, INPUT: - - ``return_group`` (boolean; ``False``) -- If True, return a group for + - ``return_group`` (boolean; ``False``) -- If ``True``, return a group for which the graph is a Cayley graph. - - ``mapping`` (boolean; ``False``) -- If True, return a mapping from + - ``mapping`` (boolean; ``False``) -- If ``True``, return a mapping from vertices to group elements. - - ``generators`` (boolean; ``False``) -- If True, return the generating + - ``generators`` (boolean; ``False``) -- If ``True``, return the generating set of the Cayley graph. - - ``allow_disconnected`` (boolean; ``False``) -- If True, disconnected + - ``allow_disconnected`` (boolean; ``False``) -- If ``True``, disconnected graphs are considered Cayley if they can be obtained from the Cayley construction with a generating set that does not generate the group. @@ -23808,25 +24147,26 @@ def is_cayley(self, return_group=False, mapping=False, A Petersen Graph is not a Cayley graph:: sage: g = graphs.PetersenGraph() - sage: g.is_cayley() + sage: g.is_cayley() # needs sage.groups False A Cayley digraph is a Cayley graph:: - sage: C7 = groups.permutation.Cyclic(7) + sage: C7 = groups.permutation.Cyclic(7) # needs sage.groups sage: S = [(1,2,3,4,5,6,7), (1,3,5,7,2,4,6), (1,5,2,6,3,7,4)] - sage: d = C7.cayley_graph(generators=S) - sage: d.is_cayley() + sage: d = C7.cayley_graph(generators=S) # needs sage.groups + sage: d.is_cayley() # needs sage.groups True Graphs with loops and multiedges will have identity and repeated elements, respectively, among the generators:: + sage: # needs sage.rings.finite_rings sage: g = Graph(graphs.PaleyGraph(9), loops=True, multiedges=True) sage: g.add_edges([(u, u) for u in g]) sage: g.add_edges([(u, u+1) for u in g]) - sage: _, S = g.is_cayley(generators=True) - sage: S # random + sage: _, S = g.is_cayley(generators=True) # needs sage.groups + sage: S # random # needs sage.groups [(), (0,2,1)(a,a + 2,a + 1)(2*a,2*a + 2,2*a + 1), (0,2,1)(a,a + 2,a + 1)(2*a,2*a + 2,2*a + 1), @@ -23839,24 +24179,27 @@ def is_cayley(self, return_group=False, mapping=False, Cayley graphs can be reconstructed from the group and generating set:: - sage: g = graphs.PaleyGraph(9) - sage: _, G, S = g.is_cayley(return_group=True, generators=True) - sage: Graph(G.cayley_graph(generators=S)).is_isomorphic(g) + sage: g = graphs.PaleyGraph(9) # needs sage.rings.finite_rings + sage: _, G, S = g.is_cayley(return_group=True, generators=True) # needs sage.groups sage.rings.finite_rings + sage: Graph(G.cayley_graph(generators=S)).is_isomorphic(g) # needs sage.groups sage.rings.finite_rings True A disconnected graphs may also be a Cayley graph:: + sage: # needs sage.rings.finite_rings sage: g = graphs.PaleyGraph(9) sage: h = g.disjoint_union(g) sage: h = h.disjoint_union(h) sage: h = h.disjoint_union(g) - sage: _, G, d, S = h.is_cayley(return_group=True, mapping=True, generators=True, allow_disconnected=True) - sage: all(set(d[u] for u in h.neighbors(v)) == set(d[v]*x for x in S) for v in h) + sage: _, G, d, S = h.is_cayley(return_group=True, mapping=True, # needs sage.groups + ....: generators=True, allow_disconnected=True) + sage: all(set(d[u] for u in h.neighbors(v)) == set(d[v]*x for x in S) # needs sage.groups + ....: for v in h) True The method also works efficiently with dense simple graphs:: - sage: graphs.CompleteBipartiteGraph(50, 50).is_cayley() + sage: graphs.CompleteBipartiteGraph(50, 50).is_cayley() # needs sage.groups True TESTS:: @@ -23927,8 +24270,7 @@ def is_cayley(self, return_group=False, mapping=False, if generators: out.append(genset) return tuple(out) - else: - return c + return c def is_self_complementary(self): r""" @@ -23962,8 +24304,8 @@ def is_self_complementary(self): Every Paley graph is self-complementary:: - sage: G = graphs.PaleyGraph(9) - sage: G.is_self_complementary() + sage: G = graphs.PaleyGraph(9) # needs sage.libs.pari + sage: G.is_self_complementary() # needs sage.libs.pari True TESTS: @@ -24043,9 +24385,11 @@ def is_self_complementary(self): from sage.graphs.connectivity import edge_connectivity from sage.graphs.connectivity import vertex_connectivity from sage.graphs.distances_all_pairs import szeged_index + from sage.graphs.domination import dominating_sets from sage.graphs.domination import dominating_set from sage.graphs.domination import greedy_dominating_set from sage.graphs.base.static_dense_graph import connected_subgraph_iterator + rooted_product = LazyImport('sage.graphs.graph_decompositions.graph_products', 'rooted_product') from sage.graphs.path_enumeration import shortest_simple_paths from sage.graphs.path_enumeration import all_paths from sage.graphs.traversals import lex_BFS @@ -24089,7 +24433,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): We find the Katz matrix of an undirected 4-cycle. :: sage: G = graphs.CycleGraph(4) - sage: G.katz_matrix(1/20) + sage: G.katz_matrix(1/20) # needs sage.modules sage.rings.number_field [1/198 5/99 1/198 5/99] [ 5/99 1/198 5/99 1/198] [1/198 5/99 1/198 5/99] @@ -24098,7 +24442,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): We find the Katz matrix of an undirected 4-cycle with all entries other than those which correspond to non-edges zeroed out. :: - sage: G.katz_matrix(1/20, True) + sage: G.katz_matrix(1/20, True) # needs sage.modules sage.rings.number_field [ 0 0 1/198 0] [ 0 0 0 1/198] [1/198 0 0 0] @@ -24110,7 +24454,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): We find the Katz matrix in a fan on 6 vertices. :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.katz_matrix(1/10) + sage: H.katz_matrix(1/10) # needs sage.modules sage.rings.number_field [ 169/2256 545/4512 25/188 605/4512 25/188 545/4512 485/4512] [ 545/4512 7081/297792 4355/37224 229/9024 595/37224 4073/297792 109/9024] [ 25/188 4355/37224 172/4653 45/376 125/4653 595/37224 5/376] @@ -24126,6 +24470,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): TESTS:: + sage: # needs sage.modules sage.rings.number_field sage: (graphs.CompleteGraph(4)).katz_matrix(1/4) [3/5 4/5 4/5 4/5] [4/5 3/5 4/5 4/5] @@ -24157,7 +24502,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): vertices = self.vertices(sort=True) elif (len(vertices) != n or set(vertices) != set(self)): - raise ValueError("``vertices`` must be a permutation of the vertices") + raise ValueError("parameter vertices must be a permutation of the vertices") A = self.adjacency_matrix(vertices=vertices) @@ -24174,8 +24519,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): onesmat = matrix(QQ, n, n, lambda i, j: 1) Missing = onesmat - A - In return K.elementwise_product(Missing) - else: - return K + return K def katz_centrality(self, alpha, u=None): r""" @@ -24206,15 +24550,16 @@ def katz_centrality(self, alpha, u=None): all 4 vertices have the same centrality) :: sage: G = graphs.CycleGraph(4) - sage: G.katz_centrality(1/20) + sage: G.katz_centrality(1/20) # needs sage.modules {0: 1/9, 1: 1/9, 2: 1/9, 3: 1/9} Note that in the below example the nodes having indegree `0` also have the Katz centrality value as `0`, as these nodes are not influenced by other nodes. :: - sage: G = DiGraph({1: [10], 2:[10,11], 3:[10,11], 4:[], 5:[11, 4], 6:[11], 7:[10,11], 8:[10,11], 9:[10], 10:[11, 5, 8], 11:[6]}) - sage: G.katz_centrality(.85) # rel tol 1e-14 + sage: G = DiGraph({1: [10], 2:[10,11], 3:[10,11], 4:[], 5:[11, 4], 6:[11], + ....: 7:[10,11], 8:[10,11], 9:[10], 10:[11, 5, 8], 11:[6]}) + sage: G.katz_centrality(.85) # rel tol 1e-14 # needs sage.modules {1: 0.000000000000000, 2: 0.000000000000000, 3: 0.000000000000000, @@ -24235,6 +24580,7 @@ def katz_centrality(self, alpha, u=None): TESTS:: + sage: # needs sage.modules sage: graphs.PathGraph(3).katz_centrality(1/20) {0: 11/199, 1: 21/199, 2: 11/199} sage: graphs.PathGraph(4).katz_centrality(1/20) @@ -24267,13 +24613,13 @@ def katz_centrality(self, alpha, u=None): verts = list(self) M = self.katz_matrix(alpha, nonedgesonly=False, vertices=verts) return {u: sum(M[i]) for i, u in enumerate(verts)} - else: - K = {} - for g in self.connected_components_subgraphs(): - verts = list(g) - M = g.katz_matrix(alpha, nonedgesonly=False, vertices=verts) - K.update({u: sum(M[i]) for i, u in enumerate(verts)}) - return K + + K = {} + for g in self.connected_components_subgraphs(): + verts = list(g) + M = g.katz_matrix(alpha, nonedgesonly=False, vertices=verts) + K.update({u: sum(M[i]) for i, u in enumerate(verts)}) + return K def edge_polytope(self, backend=None): r""" @@ -24294,29 +24640,29 @@ def edge_polytope(self, backend=None): The EP of a `4`-cycle is a square:: sage: G = graphs.CycleGraph(4) - sage: P = G.edge_polytope(); P + sage: P = G.edge_polytope(); P # needs sage.geometry.polyhedron A 2-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices The EP of a complete graph on `4` vertices is cross polytope:: sage: G = graphs.CompleteGraph(4) - sage: P = G.edge_polytope(); P + sage: P = G.edge_polytope(); P # needs sage.geometry.polyhedron A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 6 vertices - sage: P.is_combinatorially_isomorphic(polytopes.cross_polytope(3)) + sage: P.is_combinatorially_isomorphic(polytopes.cross_polytope(3)) # needs sage.geometry.polyhedron True The EP of a graph is isomorphic to the subdirect sum of its connected components EPs:: sage: n = randint(3, 6) - sage: G1 = graphs.RandomGNP(n, 0.2) + sage: G1 = graphs.RandomGNP(n, 0.2) # needs networkx sage: n = randint(3, 6) - sage: G2 = graphs.RandomGNP(n, 0.2) - sage: G = G1.disjoint_union(G2) - sage: P = G.edge_polytope() - sage: P1 = G1.edge_polytope() - sage: P2 = G2.edge_polytope() - sage: P.is_combinatorially_isomorphic(P1.subdirect_sum(P2)) + sage: G2 = graphs.RandomGNP(n, 0.2) # needs networkx + sage: G = G1.disjoint_union(G2) # needs networkx + sage: P = G.edge_polytope() # needs networkx sage.geometry.polyhedron + sage: P1 = G1.edge_polytope() # needs networkx sage.geometry.polyhedron + sage: P2 = G2.edge_polytope() # needs networkx sage.geometry.polyhedron + sage: P.is_combinatorially_isomorphic(P1.subdirect_sum(P2)) # needs networkx sage.geometry.polyhedron True All trees on `n` vertices have isomorphic EPs:: @@ -24324,9 +24670,9 @@ def edge_polytope(self, backend=None): sage: n = randint(4, 10) sage: G1 = graphs.RandomTree(n) sage: G2 = graphs.RandomTree(n) - sage: P1 = G1.edge_polytope() - sage: P2 = G2.edge_polytope() - sage: P1.is_combinatorially_isomorphic(P2) + sage: P1 = G1.edge_polytope() # needs sage.geometry.polyhedron + sage: P2 = G2.edge_polytope() # needs sage.geometry.polyhedron + sage: P1.is_combinatorially_isomorphic(P2) # needs sage.geometry.polyhedron True However, there are still many different EPs:: @@ -24334,14 +24680,14 @@ def edge_polytope(self, backend=None): sage: len(list(graphs(5))) 34 sage: polys = [] - sage: for G in graphs(5): + sage: for G in graphs(5): # needs sage.geometry.polyhedron ....: P = G.edge_polytope() ....: for P1 in polys: ....: if P.is_combinatorially_isomorphic(P1): ....: break ....: else: ....: polys.append(P) - sage: len(polys) + sage: len(polys) # needs sage.geometry.polyhedron 19 TESTS: @@ -24349,7 +24695,7 @@ def edge_polytope(self, backend=None): Obtain the EP with unsortable vertices:: sage: G = Graph([[1, (1, 2)]]) - sage: G.edge_polytope() + sage: G.edge_polytope() # needs sage.geometry.polyhedron A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex """ from sage.matrix.special import identity_matrix @@ -24380,17 +24726,17 @@ def symmetric_edge_polytope(self, backend=None): The SEP of a `4`-cycle is a cube:: sage: G = graphs.CycleGraph(4) - sage: P = G.symmetric_edge_polytope(); P + sage: P = G.symmetric_edge_polytope(); P # needs sage.geometry.polyhedron A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 8 vertices - sage: P.is_combinatorially_isomorphic(polytopes.cube()) + sage: P.is_combinatorially_isomorphic(polytopes.cube()) # needs sage.geometry.polyhedron True The SEP of a complete graph on `4` vertices is a cuboctahedron:: sage: G = graphs.CompleteGraph(4) - sage: P = G.symmetric_edge_polytope(); P + sage: P = G.symmetric_edge_polytope(); P # needs sage.geometry.polyhedron A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 12 vertices - sage: P.is_combinatorially_isomorphic(polytopes.cuboctahedron()) + sage: P.is_combinatorially_isomorphic(polytopes.cuboctahedron()) # needs sage.geometry.polyhedron True The SEP of a graph with edges on `n` vertices has dimension `n` @@ -24398,26 +24744,26 @@ def symmetric_edge_polytope(self, backend=None): sage: n = randint(5, 12) sage: G = Graph() - sage: while not G.num_edges(): + sage: while not G.num_edges(): # needs networkx ....: G = graphs.RandomGNP(n, 0.2) - sage: P = G.symmetric_edge_polytope() - sage: P.ambient_dim() == n + sage: P = G.symmetric_edge_polytope() # needs networkx sage.geometry.polyhedron + sage: P.ambient_dim() == n # needs networkx sage.geometry.polyhedron True - sage: P.dim() == n - G.connected_components_number() + sage: P.dim() == n - G.connected_components_number() # needs networkx sage.geometry.polyhedron True The SEP of a graph is isomorphic to the subdirect sum of its connected components SEP's:: sage: n = randint(3, 6) - sage: G1 = graphs.RandomGNP(n, 0.2) + sage: G1 = graphs.RandomGNP(n, 0.2) # needs networkx sage: n = randint(3, 6) - sage: G2 = graphs.RandomGNP(n, 0.2) - sage: G = G1.disjoint_union(G2) - sage: P = G.symmetric_edge_polytope() - sage: P1 = G1.symmetric_edge_polytope() - sage: P2 = G2.symmetric_edge_polytope() - sage: P.is_combinatorially_isomorphic(P1.subdirect_sum(P2)) + sage: G2 = graphs.RandomGNP(n, 0.2) # needs networkx + sage: G = G1.disjoint_union(G2) # needs networkx + sage: P = G.symmetric_edge_polytope() # needs networkx sage.geometry.polyhedron + sage: P1 = G1.symmetric_edge_polytope() # needs networkx sage.geometry.polyhedron + sage: P2 = G2.symmetric_edge_polytope() # needs networkx sage.geometry.polyhedron + sage: P.is_combinatorially_isomorphic(P1.subdirect_sum(P2)) # needs networkx sage.geometry.polyhedron True All trees on `n` vertices have isomorphic SEPs:: @@ -24425,9 +24771,9 @@ def symmetric_edge_polytope(self, backend=None): sage: n = randint(4, 10) sage: G1 = graphs.RandomTree(n) sage: G2 = graphs.RandomTree(n) - sage: P1 = G1.symmetric_edge_polytope() - sage: P2 = G2.symmetric_edge_polytope() - sage: P1.is_combinatorially_isomorphic(P2) + sage: P1 = G1.symmetric_edge_polytope() # needs sage.geometry.polyhedron + sage: P2 = G2.symmetric_edge_polytope() # needs sage.geometry.polyhedron + sage: P1.is_combinatorially_isomorphic(P2) # needs sage.geometry.polyhedron True However, there are still many different SEPs:: @@ -24435,14 +24781,14 @@ def symmetric_edge_polytope(self, backend=None): sage: len(list(graphs(5))) 34 sage: polys = [] - sage: for G in graphs(5): + sage: for G in graphs(5): # needs sage.geometry.polyhedron ....: P = G.symmetric_edge_polytope() ....: for P1 in polys: ....: if P.is_combinatorially_isomorphic(P1): ....: break ....: else: ....: polys.append(P) - sage: len(polys) + sage: len(polys) # needs sage.geometry.polyhedron 25 A non-trivial example of two graphs with isomorphic SEPs:: @@ -24454,24 +24800,24 @@ def symmetric_edge_polytope(self, backend=None): sage: G2.add_edges([[0, 7], [7, 3]]) sage: G1.is_isomorphic(G2) False - sage: P1 = G1.symmetric_edge_polytope() - sage: P2 = G2.symmetric_edge_polytope() - sage: P1.is_combinatorially_isomorphic(P2) + sage: P1 = G1.symmetric_edge_polytope() # needs sage.geometry.polyhedron + sage: P2 = G2.symmetric_edge_polytope() # needs sage.geometry.polyhedron + sage: P1.is_combinatorially_isomorphic(P2) # needs sage.geometry.polyhedron True Apparently, glueing two graphs together on a vertex gives isomorphic SEPs:: sage: n = randint(3, 7) - sage: g1 = graphs.RandomGNP(n, 0.2) - sage: g2 = graphs.RandomGNP(n, 0.2) - sage: G = g1.disjoint_union(g2) - sage: H = copy(G) - sage: G.merge_vertices(((0, randrange(n)), (1, randrange(n)))) - sage: H.merge_vertices(((0, randrange(n)), (1, randrange(n)))) - sage: PG = G.symmetric_edge_polytope() - sage: PH = H.symmetric_edge_polytope() - sage: PG.is_combinatorially_isomorphic(PH) + sage: g1 = graphs.RandomGNP(n, 0.2) # needs networkx + sage: g2 = graphs.RandomGNP(n, 0.2) # needs networkx + sage: G = g1.disjoint_union(g2) # needs networkx + sage: H = copy(G) # needs networkx + sage: G.merge_vertices(((0, randrange(n)), (1, randrange(n)))) # needs networkx + sage: H.merge_vertices(((0, randrange(n)), (1, randrange(n)))) # needs networkx + sage: PG = G.symmetric_edge_polytope() # needs networkx sage.geometry.polyhedron + sage: PH = H.symmetric_edge_polytope() # needs networkx sage.geometry.polyhedron + sage: PG.is_combinatorially_isomorphic(PH) # needs networkx sage.geometry.polyhedron True TESTS: @@ -24479,7 +24825,7 @@ def symmetric_edge_polytope(self, backend=None): Obtain the SEP with unsortable vertices:: sage: G = Graph([[1, (1, 2)]]) - sage: G.symmetric_edge_polytope() + sage: G.symmetric_edge_polytope() # needs sage.geometry.polyhedron A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices """ from itertools import chain @@ -24515,10 +24861,10 @@ def tachyon_vertex_plot(g, bgcolor=(1, 1, 1), sage: G = graphs.TetrahedralGraph() sage: from sage.graphs.generic_graph import tachyon_vertex_plot - sage: T,p = tachyon_vertex_plot(G, pos3d=G.layout(dim=3)) - sage: type(T) + sage: T,p = tachyon_vertex_plot(G, pos3d=G.layout(dim=3)) # needs sage.plot + sage: type(T) # needs sage.plot <class 'sage.plot.plot3d.tachyon.Tachyon'> - sage: type(p) + sage: type(p) # needs sage.plot <... 'dict'> """ assert pos3d is not None @@ -24659,7 +25005,8 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab sage: g.edges(sort=True) [(0, 3, None), (1, 4, None), (2, 4, None), (2, 5, None), (3, 5, None)] - sage: g = graph_isom_equivalent_non_edge_labeled_graph(G,standard_label='string',return_edge_labels=True) + sage: g = graph_isom_equivalent_non_edge_labeled_graph(G, standard_label='string', + ....: return_edge_labels=True) sage: g[0] Graph on 6 vertices sage: g[0].edges(sort=True) diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 022c02c3b06..c8777a62f23 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -35,6 +35,7 @@ from sage.libs.gmp.mpz cimport * from sage.misc.prandom import random from sage.graphs.base.static_sparse_graph cimport short_digraph from sage.graphs.base.static_sparse_graph cimport init_short_digraph +from sage.graphs.base.static_sparse_graph cimport init_reverse from sage.graphs.base.static_sparse_graph cimport free_short_digraph from sage.graphs.base.static_sparse_graph cimport out_degree, has_edge @@ -399,7 +400,7 @@ cdef inline double sqrt_approx(double x, double y, double xx, double yy): ....: y = abs(y) ....: return max(x,y) + min(x,y)**2/(2*max(x,y)) - sage: polar_plot([1,lambda x:dist(cos(x),sin(x))], (0, 2*math.pi)) + sage: polar_plot([1,lambda x:dist(cos(x),sin(x))], (0, 2*math.pi)) # needs sage.plot Graphics object consisting of 2 graphics primitives """ if xx < yy: @@ -486,11 +487,10 @@ def small_integer_to_graph6(n): """ if n < 63: return chr(n + 63) - else: - # get 18-bit rep of n - n = int_to_binary_string(n) - n = '0'*(18 - len(n)) + n - return chr(126) + binary_string_to_graph6(n) + # get 18-bit rep of n + n = int_to_binary_string(n) + n = '0'*(18 - len(n)) + n + return chr(126) + binary_string_to_graph6(n) def length_and_string_from_graph6(s): @@ -529,7 +529,7 @@ def length_and_string_from_graph6(s): else: # only first byte is N o = ord(s[0]) if o > 126 or o < 63: - raise RuntimeError("the string seems corrupt: valid characters are \n" + ''.join(chr(i) for i in xrange(63, 127))) + raise RuntimeError("the string seems corrupt: valid characters are \n" + ''.join(chr(i) for i in range(63, 127))) n = o - 63 s = s[1:] return n, s @@ -568,7 +568,7 @@ def binary_string_from_graph6(s, n): for i in range(len(s)): o = ord(s[i]) if o > 126 or o < 63: - raise RuntimeError("the string seems corrupt: valid characters are \n" + ''.join(chr(i) for i in xrange(63, 127))) + raise RuntimeError("the string seems corrupt: valid characters are \n" + ''.join(chr(i) for i in range(63, 127))) a = int_to_binary_string(o - 63) l.append('0'*(6 - len(a)) + a) m = "".join(l) @@ -606,7 +606,7 @@ def binary_string_from_dig6(s, n): for i in range(len(s)): o = ord(s[i]) if o > 126 or o < 63: - raise RuntimeError("the string seems corrupt: valid characters are \n" + ''.join(chr(i) for i in xrange(63, 127))) + raise RuntimeError("the string seems corrupt: valid characters are \n" + ''.join(chr(i) for i in range(63, 127))) a = int_to_binary_string(o - 63) l.append('0'*(6 - len(a)) + a) m = "".join(l) @@ -650,7 +650,7 @@ cdef class SubgraphSearch: EXAMPLES:: sage: g = graphs.PetersenGraph() - sage: g.subgraph_search(graphs.CycleGraph(5)) + sage: g.subgraph_search(graphs.CycleGraph(5)) # needs sage.modules Subgraph of (Petersen graph): Graph on 5 vertices TESTS: @@ -660,18 +660,18 @@ cdef class SubgraphSearch: computations with it:: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch - sage: SubgraphSearch(Graph(5), Graph(1)) + sage: SubgraphSearch(Graph(5), Graph(1)) # needs sage.modules Traceback (most recent call last): ... - ValueError: Searched graph should have at least 2 vertices. - sage: SubgraphSearch(Graph(5), Graph(2)) + ValueError: searched graph should have at least 2 vertices + sage: SubgraphSearch(Graph(5), Graph(2)) # needs sage.modules <sage.graphs.generic_graph_pyx.SubgraphSearch ...> """ if H.order() <= 1: - raise ValueError("Searched graph should have at least 2 vertices.") + raise ValueError("searched graph should have at least 2 vertices") - if sum([G.is_directed(), H.is_directed()]) == 1: - raise ValueError("One graph cannot be directed while the other is not.") + if G.is_directed() != H.is_directed(): + raise ValueError("one graph cannot be directed while the other is not") G._scream_if_not_simple(allow_loops=True) H._scream_if_not_simple(allow_loops=True) @@ -690,8 +690,8 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) - sage: for p in S: + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: for p in S: # needs sage.modules ....: print(p) [0, 1, 2] [1, 2, 3] @@ -721,9 +721,21 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) - sage: S.cardinality() + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: S.cardinality() # needs sage.modules 6 + + Check that the method is working even when vertices or edges are of + incomparable types (see :trac:`35904`):: + + sage: from sage.graphs.generic_graph_pyx import SubgraphSearch + sage: G = Graph() + sage: G.add_cycle(['A', 1, 2, 3, ('a', 1)]) + sage: H = Graph() + sage: H.add_path("xyz") + sage: S = SubgraphSearch(G, H) # needs sage.modules + sage: S.cardinality() # needs sage.modules + 10 """ if self.nh > self.ng: return 0 @@ -756,18 +768,18 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) - sage: S.__next__() + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: S.__next__() # needs sage.modules [0, 1, 2] - sage: S._initialization() - sage: S.__next__() + sage: S._initialization() # needs sage.modules + sage: S.__next__() # needs sage.modules [0, 1, 2] TESTS: Check that :trac:`21828` is fixed:: - sage: Poset().is_incomparable_chain_free(1,1) # indirect doctest + sage: Poset().is_incomparable_chain_free(1,1) # indirect doctest # needs sage.modules True """ cdef int i @@ -802,7 +814,7 @@ cdef class SubgraphSearch: EXAMPLES:: sage: g = graphs.PetersenGraph() - sage: g.subgraph_search(graphs.CycleGraph(5)) + sage: g.subgraph_search(graphs.CycleGraph(5)) # needs sage.modules Subgraph of (Petersen graph): Graph on 5 vertices """ self.mem = MemoryAllocator() @@ -812,7 +824,8 @@ cdef class SubgraphSearch: self.nh = H.order() # Storing the list of vertices - self.g_vertices = G.vertices(sort=True) + self.g_vertices = list(G) + cdef list h_vertices = list(H) # Are the graphs directed (in __init__(), we check # whether both are of the same type) @@ -846,15 +859,22 @@ cdef class SubgraphSearch: self.h = DenseGraph(self.nh) # copying the adjacency relations in both G and H - for i, row in enumerate(G.adjacency_matrix()): - for j, k in enumerate(row): - if k: - self.g.add_arc(i, j) - - for i, row in enumerate(H.adjacency_matrix()): - for j, k in enumerate(row): - if k: - self.h.add_arc(i, j) + cdef dict vertex_to_int = {v: i for i, v in enumerate(self.g_vertices)} + cdef bint undirected = not G.is_directed() + for u, v in G.edge_iterator(labels=False): + i = vertex_to_int[u] + j = vertex_to_int[v] + self.g.add_arc(i, j) + if undirected: + self.g.add_arc(j, i) + + vertex_to_int = {v: i for i, v in enumerate(h_vertices)} + for u, v in H.edge_iterator(labels=False): + i = vertex_to_int[u] + j = vertex_to_int[v] + self.h.add_arc(i, j) + if undirected: + self.h.add_arc(j, i) # vertices is equal to range(nh), as an int *variable for i in range(self.nh): @@ -862,14 +882,14 @@ cdef class SubgraphSearch: # line_h_out[i] represents the adjacency sequence of vertex i # in h relative to vertices 0, 1, ..., i-1 - for i in xrange(self.nh): + for i in range(self.nh): self.line_h_out[i] = self.line_h_out[0] + i*self.nh self.h.adjacency_sequence_out(i, self.vertices, i, self.line_h_out[i]) # Similarly in the opposite direction (only useful if the # graphs are directed) if self.directed: - for i in xrange(self.nh): + for i in range(self.nh): self.line_h_in[i] = self.line_h_in[0] + i*self.nh self.h.adjacency_sequence_in(i, self.vertices, i, self.line_h_in[i]) @@ -883,8 +903,8 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) - sage: S.__next__() + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: S.__next__() # needs sage.modules [0, 1, 2] """ if not self.ng: @@ -935,7 +955,7 @@ cdef class SubgraphSearch: if self.active == self.nh-1: sig_off() return [self.g_vertices[self.stack[l]] - for l in xrange(self.nh)] + for l in range(self.nh)] # We are still missing several vertices ... else: @@ -1237,11 +1257,29 @@ cpdef tuple find_hamiltonian(G, long max_iter=100000, long reset_bound=30000, Finally, an example on a graph which does not have a Hamiltonian path:: - sage: G=graphs.HyperStarGraph(5,2) - sage: fh(G,find_path=False) - (False, ['00110', '10100', '01100', '11000', '01010', '10010', '00011', '10001', '00101']) - sage: fh(G,find_path=True) - (False, ['01001', '10001', '00101', '10100', '00110', '10010', '01010', '11000', '01100']) + sage: G = graphs.HyperStarGraph(5, 2) + sage: G.order() + 10 + sage: b, P = fh(G,find_path=False) + sage: b, len(P) + (False, 9) + sage: b, P = fh(G,find_path=True) + sage: b, len(P) + (False, 9) + + The method can also be used for directed graphs:: + + sage: G = DiGraph([(0, 1), (1, 2), (2, 3)]) + sage: fh(G) + (False, [0, 1, 2, 3]) + sage: G = G.reverse() + sage: fh(G) + (False, [3, 2, 1, 0]) + sage: G = DiGraph() + sage: G.add_cycle([0, 1, 2, 3, 4, 5]) + sage: b, P = fh(G) + sage: b, len(P) + (True, 6) TESTS: @@ -1289,15 +1327,21 @@ cpdef tuple find_hamiltonian(G, long max_iter=100000, long reset_bound=30000, sage: fh(G, find_path=True) (False, [0, 1, 2, 3]) + Check that the method is robust to incomparable vertices:: + + sage: G = Graph([(1, 'a'), ('a', 2), (2, 3), (3, 1)]) + sage: b, C = fh(G, find_path=False) + sage: b, len(C) + (True, 4) """ + G._scream_if_not_simple() + from sage.misc.prandom import randint cdef int n = G.order() # Easy cases - if not n: - return False, [] - if n == 1: - return False, G.vertices(sort=False) + if n < 2: + return False, list(G) # To clean the output when find_path is None or a number find_path = (find_path > 0) @@ -1305,7 +1349,7 @@ cpdef tuple find_hamiltonian(G, long max_iter=100000, long reset_bound=30000, if G.is_clique(induced=False): # We have an hamiltonian path since n >= 2, but we have an hamiltonian # cycle only if n >= 3 - return find_path or n >= 3, G.vertices(sort=True) + return find_path or n >= 3, list(G) cdef list best_path, p if not G.is_connected(): @@ -1313,6 +1357,8 @@ cpdef tuple find_hamiltonian(G, long max_iter=100000, long reset_bound=30000, # longest path in its connected components. best_path = [] for H in G.connected_components_subgraphs(): + if H.order() <= len(best_path): + continue _, p = find_hamiltonian(H, max_iter=max_iter, reset_bound=reset_bound, backtrack_bound=backtrack_bound, find_path=True) if len(p) > len(best_path): @@ -1321,20 +1367,24 @@ cpdef tuple find_hamiltonian(G, long max_iter=100000, long reset_bound=30000, # Misc variables used below cdef int i, j - cdef int n_available + cdef bint directed = G.is_directed() # Initialize the path. cdef MemoryAllocator mem = MemoryAllocator() cdef int *path = <int *>mem.allocarray(n, sizeof(int)) - memset(path, -1, n * sizeof(int)) # Initialize the membership array cdef bint *member = <bint *>mem.allocarray(n, sizeof(int)) memset(member, 0, n * sizeof(int)) # static copy of the graph for more efficient operations + cdef list int_to_vertex = list(G) cdef short_digraph sd - init_short_digraph(sd, G) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) + cdef short_digraph rev_sd + cdef bint reverse = False + if directed: + init_reverse(rev_sd, sd) # A list to store the available vertices at each step cdef list available_vertices = [] @@ -1344,7 +1394,7 @@ cpdef tuple find_hamiltonian(G, long max_iter=100000, long reset_bound=30000, cdef int u = randint(0, n - 1) while not out_degree(sd, u): u = randint(0, n - 1) - # Then we pick at random a neighbor of u + # Then we pick at random a neighbor of u cdef int x = randint(0, out_degree(sd, u) - 1) cdef int v = sd.neighbors[u][x] # This will be the first edge in the path @@ -1362,34 +1412,35 @@ cpdef tuple find_hamiltonian(G, long max_iter=100000, long reset_bound=30000, # Initialize a path to contain the longest path cdef int *longest_path = <int *>mem.allocarray(n, sizeof(int)) - memset(longest_path, -1, n * sizeof(int)) for i in range(length): longest_path[i] = path[i] - # Initialize a temporary path for flipping - cdef int *temp_path = <int *>mem.allocarray(n, sizeof(int)) - memset(temp_path, -1, n * sizeof(int)) - cdef bint longer = False - cdef bint good = True + cdef bint longest_reversed = False cdef bint flag while not done: counter = counter + 1 if counter % 10 == 0: # Reverse the path - for i in range(length//2): t = path[i] path[i] = path[length - i - 1] path[length - i - 1] = t + if directed: + # We now work on the reverse graph + reverse = not reverse + if counter > reset_bound: bigcount = bigcount + 1 counter = 1 # Time to reset the procedure memset(member, 0, n * sizeof(int)) + if directed and reverse: + # We restore the original orientation + reverse = False # First we pick a random vertex u of (out-)degree at least one u = randint(0, n - 1) @@ -1405,37 +1456,44 @@ cpdef tuple find_hamiltonian(G, long max_iter=100000, long reset_bound=30000, member[u] = True member[v] = True - if counter % backtrack_bound == 0: + if length > 5 and counter % backtrack_bound == 0: for i in range(5): member[path[length - i - 1]] = False length = length - 5 longer = False + # We search for a possible extension of the path available_vertices = [] u = path[length - 1] - for i in range(out_degree(sd, u)): - v = sd.neighbors[u][i] - if not member[v]: - available_vertices.append(v) + if directed and reverse: + for i in range(out_degree(rev_sd, u)): + v = rev_sd.neighbors[u][i] + if not member[v]: + available_vertices.append(v) + else: + for i in range(out_degree(sd, u)): + v = sd.neighbors[u][i] + if not member[v]: + available_vertices.append(v) - n_available = len(available_vertices) - if n_available > 0: + if available_vertices: longer = True - x = randint(0, n_available - 1) - path[length] = available_vertices[x] + x = randint(0, len(available_vertices) - 1) + v = available_vertices[x] + path[length] = v length = length + 1 - member[available_vertices[x]] = True + member[v] = True if not longer and length > longest: - + # Store the current best solution for i in range(length): longest_path[i] = path[i] longest = length + longest_reversed = reverse - if not longer: - - memset(temp_path, -1, n * sizeof(int)) + if not directed and not longer and out_degree(sd, path[length - 1]) > 1: + # We revert a cycle to change the extremity of the path degree = out_degree(sd, path[length - 1]) while True: x = randint(0, degree - 1) @@ -1455,37 +1513,53 @@ cpdef tuple find_hamiltonian(G, long max_iter=100000, long reset_bound=30000, j += 1 if path[i] == u: flag = True + if length == n: if find_path: done = True + elif directed and reverse: + done = has_edge(rev_sd, path[0], path[n - 1]) != NULL else: done = has_edge(sd, path[n - 1], path[0]) != NULL if bigcount * reset_bound > max_iter: - verts = G.vertices(sort=True) - output = [verts[longest_path[i]] for i in range(longest)] + output = [int_to_vertex[longest_path[i]] for i in range(longest)] free_short_digraph(sd) + if directed: + free_short_digraph(rev_sd) + if longest_reversed: + return (False, output[::-1]) return (False, output) # # # # Output test # # + if directed and reverse: + # We revert the path to work on sd + for i in range(length//2): + t = path[i] + path[i] = path[length - i - 1] + path[length - i - 1] = t + # Test adjacencies + cdef bint good = True for i in range(n - 1): u = path[i] v = path[i + 1] - # Graph is simple, so both arcs are present if has_edge(sd, u, v) == NULL: good = False break if good is False: - raise RuntimeError('vertices %d and %d are consecutive in the cycle but are not adjacent' % (u, v)) - if not find_path and has_edge(sd, path[0], path[n - 1]) == NULL: - raise RuntimeError('vertices %d and %d are not adjacent' % (path[0], path[n - 1])) + raise RuntimeError(f"vertices {int_to_vertex[u]} and {int_to_vertex[v]}" + " are consecutive in the cycle but are not adjacent") + if not find_path and has_edge(sd, path[n - 1], path[0]) == NULL: + raise RuntimeError(f"vertices {int_to_vertex[path[n - 1]]} and " + f"{int_to_vertex[path[0]]} are not adjacent") - verts = G.vertices(sort=True) - output = [verts[path[i]] for i in range(length)] + output = [int_to_vertex[path[i]] for i in range(length)] free_short_digraph(sd) + if directed: + free_short_digraph(rev_sd) return (True, output) diff --git a/src/sage/graphs/genus.pyx b/src/sage/graphs/genus.pyx index d56c1ba8461..90fb4bf4c52 100644 --- a/src/sage/graphs/genus.pyx +++ b/src/sage/graphs/genus.pyx @@ -597,31 +597,31 @@ def simple_connected_graph_genus(G, set_embedding=False, check=True, minimal=Tru if minimal and G.is_planar(set_embedding=set_embedding): return 0 + + if check: + if not G.is_connected(): + raise ValueError("Cannot compute the genus of a disconnected graph") + + if G.is_directed() or G.has_multiple_edges() or G.has_loops(): + G = G.to_simple() + + G, vmap = G.relabel(inplace=False, return_map=True) + backmap = {u: v for v, u in vmap.items()} + G = Graph(G, sparse=False) + GG = simple_connected_genus_backtracker(G._backend.c_graph()[0]) + + if minimal: + style = 1 + cutoff = 1 else: - if check: - if not G.is_connected(): - raise ValueError("Cannot compute the genus of a disconnected graph") - - if G.is_directed() or G.has_multiple_edges() or G.has_loops(): - G = G.to_simple() - - G, vmap = G.relabel(inplace=False, return_map=True) - backmap = {u: v for v, u in vmap.items()} - G = Graph(G, sparse=False) - GG = simple_connected_genus_backtracker(G._backend.c_graph()[0]) - - if minimal: - style = 1 - cutoff = 1 - else: - style = 2 - cutoff = 1 + (G.num_edges() - G.num_verts()) / 2 # rounding here is ok - - g = GG.genus(style=style, cutoff=cutoff, record_embedding=set_embedding) - if set_embedding: - oE = {} - E = GG.get_embedding() - for v in E: - oE[backmap[v]] = [backmap[x] for x in E[v]] - oG.set_embedding(oE) - return g + style = 2 + cutoff = 1 + (G.num_edges() - G.num_verts()) / 2 # rounding here is ok + + g = GG.genus(style=style, cutoff=cutoff, record_embedding=set_embedding) + if set_embedding: + oE = {} + E = GG.get_embedding() + for v in E: + oE[backmap[v]] = [backmap[x] for x in E[v]] + oG.set_embedding(oE) + return g diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index d03ad093fe6..fe02be46c77 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -106,12 +106,13 @@ 5: [7, 8], 6: [8,9], 7: [9]} sage: G = Graph(d); G Graph on 10 vertices - sage: G.plot().show() # or G.show() + sage: G.plot().show() # or G.show() # needs sage.plot - A NetworkX graph: :: + sage: # needs networkx sage: import networkx sage: K = networkx.complete_bipartite_graph(12,7) sage: G = Graph(K) @@ -125,7 +126,7 @@ sage: s = ':I`AKGsaOs`cI]Gb~' sage: G = Graph(s, sparse=True); G Looped multi-graph on 10 vertices - sage: G.plot().show() # or G.show() + sage: G.plot().show() # or G.show() # needs sage.plot Note that the ``\`` character is an escape character in Python, and also a character used by graph6 strings: @@ -142,17 +143,18 @@ :: sage: G = Graph('Ihe\\n@GUA') - sage: G.plot().show() # or G.show() + sage: G.plot().show() # or G.show() # needs sage.plot - adjacency matrix: In an adjacency matrix, each column and each row represent a vertex. If a 1 shows up in row `i`, column `j`, there is an edge `(i,j)`. :: - sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0),(1,0,1,0,0,0,1,0,0,0), \ - (0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0),(1,0,0,1,0,0,0,0,0,1), \ - (1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1),(0,0,1,0,0,1,0,0,0,1), \ - (0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)]) + sage: # needs sage.modules + sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0), (1,0,1,0,0,0,1,0,0,0), + ....: (0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0), + ....: (1,0,0,1,0,0,0,0,0,1), (1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1), + ....: (0,0,1,0,0,1,0,0,0,1), (0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)]) sage: M [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] @@ -166,13 +168,14 @@ [0 0 0 0 1 0 1 1 0 0] sage: G = Graph(M); G Graph on 10 vertices - sage: G.plot().show() # or G.show() + sage: G.plot().show() # or G.show() # needs sage.plot - incidence matrix: In an incidence matrix, each row represents a vertex and each column represents an edge. :: + sage: # needs sage.modules sage: M = Matrix([(-1, 0, 0, 0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0), ....: ( 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0), ....: ( 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0), @@ -196,8 +199,8 @@ [ 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 1] sage: G = Graph(M); G Graph on 10 vertices - sage: G.plot().show() # or G.show() - sage: DiGraph(matrix(2,[0,0,-1,1]), format="incidence_matrix") + sage: G.plot().show() # or G.show() # needs sage.plot + sage: DiGraph(matrix(2, [0,0,-1,1]), format="incidence_matrix") Traceback (most recent call last): ... ValueError: there must be two nonzero entries (-1 & 1) per column @@ -254,10 +257,10 @@ :: sage: G = graphs.PetersenGraph() - sage: G.plot().show() # or G.show() + sage: G.plot().show() # or G.show() # needs sage.plot sage: G.degree_histogram() [0, 0, 0, 10] - sage: G.adjacency_matrix() + sage: G.adjacency_matrix() # needs sage.modules [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] [0 1 0 1 0 0 0 1 0 0] @@ -272,7 +275,7 @@ :: sage: S = G.subgraph([0,1,2,3]) - sage: S.plot().show() # or S.show() + sage: S.plot().show() # or S.show() # needs sage.plot sage: S.density() 1/2 @@ -280,7 +283,7 @@ sage: G = GraphQuery(display_cols=['graph6'], num_vertices=7, diameter=5) sage: L = G.get_graphs_list() - sage: graphs_list.show_graphs(L) + sage: graphs_list.show_graphs(L) # needs sage.plot .. _Graph:labels: @@ -295,8 +298,8 @@ Note that vertex labels themselves cannot be mutable items:: - sage: M = Matrix( [[0,0],[0,0]] ) - sage: G = Graph({ 0 : { M : None } }) + sage: M = Matrix([[0,0], [0,0]]) # needs sage.modules + sage: G = Graph({ 0 : { M : None } }) # needs sage.modules Traceback (most recent call last): ... TypeError: mutable matrices are unhashable @@ -349,7 +352,7 @@ Show each graph as you iterate through the results:: - sage: for g in Q: + sage: for g in Q: # needs sage.plot ....: show(g) Visualization @@ -359,11 +362,11 @@ view the graph in two dimensions via matplotlib with ``show()``. :: sage: G = graphs.RandomGNP(15,.3) - sage: G.show() + sage: G.show() # needs sage.plot And you can view it in three dimensions via jmol with ``show3d()``. :: - sage: G.show3d() + sage: G.show3d() # needs sage.plot Or it can be rendered with `\LaTeX`. This requires the right additions to a standard `\mbox{\rm\TeX}` installation. Then standard Sage commands, such as @@ -422,14 +425,13 @@ from sage.graphs.independent_sets import IndependentSets from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index from sage.graphs.views import EdgesView +from sage.parallel.decorate import parallel -from sage.misc.lazy_import import lazy_import +from sage.misc.lazy_import import lazy_import, LazyImport from sage.features import PythonModule lazy_import('sage.graphs.mcqd', ['mcqd'], feature=PythonModule('sage.graphs.mcqd', spkg='mcqd')) -from sage.misc.decorators import rename_keyword - class Graph(GenericGraph): r""" @@ -570,6 +572,11 @@ class Graph(GenericGraph): immutable graph. Note that ``immutable=True`` is actually a shortcut for ``data_structure='static_sparse'``. Set to ``False`` by default. + - ``hash_labels`` -- boolean (default: ``None``); whether to include edge + labels during hashing. This parameter defaults to ``True`` if the graph is + weighted. This parameter is ignored if the graph is mutable. + Beware that trying to hash unhashable labels will raise an error. + - ``vertex_labels`` -- boolean (default: ``True``); whether to allow any object as a vertex (slower), or only the integers `0,...,n-1`, where `n` is the number of vertices. @@ -602,8 +609,8 @@ class Graph(GenericGraph): 'out' is the label for the edge on 2 and 5. Labels can be used as weights, if all the labels share some common parent.:: - sage: a, b, c, d, e, f = sorted(SymmetricGroup(3)) # optional - sage.groups - sage: Graph({b: {d: 'c', e: 'p'}, c: {d: 'p', e: 'c'}}) # optional - sage.groups + sage: a, b, c, d, e, f = sorted(SymmetricGroup(3)) # needs sage.groups + sage: Graph({b: {d: 'c', e: 'p'}, c: {d: 'p', e: 'c'}}) # needs sage.groups Graph on 4 vertices #. A dictionary of lists:: @@ -617,10 +624,10 @@ class Graph(GenericGraph): Construct the Paley graph over GF(13).:: - sage: g=Graph([GF(13), lambda i,j: i!=j and (i-j).is_square()]) - sage: g.vertices(sort=True) + sage: g = Graph([GF(13), lambda i,j: i!=j and (i-j).is_square()]) # needs sage.rings.finite_rings + sage: g.vertices(sort=True) # needs sage.rings.finite_rings [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] - sage: g.adjacency_matrix() + sage: g.adjacency_matrix() # needs sage.modules sage.rings.finite_rings [0 1 0 1 1 0 0 0 0 1 1 0 1] [1 0 1 0 1 1 0 0 0 0 1 1 0] [0 1 0 1 0 1 1 0 0 0 0 1 1] @@ -643,7 +650,7 @@ class Graph(GenericGraph): loops=False) sage: line_graph.vertices(sort=True) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: line_graph.adjacency_matrix() + sage: line_graph.adjacency_matrix() # needs sage.modules [0 1 1 1 1 0] [1 0 1 1 0 1] [1 1 0 0 1 1] @@ -691,7 +698,7 @@ class Graph(GenericGraph): - an adjacency matrix:: - sage: M = graphs.PetersenGraph().am(); M + sage: M = graphs.PetersenGraph().am(); M # needs sage.modules [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] [0 1 0 1 0 0 0 1 0 0] @@ -702,82 +709,85 @@ class Graph(GenericGraph): [0 0 1 0 0 1 0 0 0 1] [0 0 0 1 0 1 1 0 0 0] [0 0 0 0 1 0 1 1 0 0] - sage: Graph(M) + sage: Graph(M) # needs sage.modules Graph on 10 vertices :: - sage: Graph(matrix([[1,2],[2,4]]),loops=True,sparse=True) + sage: Graph(matrix([[1,2], [2,4]]), loops=True, sparse=True) # needs sage.modules Looped multi-graph on 2 vertices - sage: M = Matrix([[0,1,-1],[1,0,-1/2],[-1,-1/2,0]]); M + sage: M = Matrix([[0,1,-1], [1,0,-1/2], [-1,-1/2,0]]); M # needs sage.modules [ 0 1 -1] [ 1 0 -1/2] [ -1 -1/2 0] - sage: G = Graph(M,sparse=True); G + sage: G = Graph(M, sparse=True); G # needs sage.modules Graph on 3 vertices - sage: G.weighted() + sage: G.weighted() # needs sage.modules True - an incidence matrix:: - sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M + sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, # needs sage.modules + ....: 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M [-1 0 0 0 1] [ 1 -1 0 0 0] [ 0 1 -1 0 0] [ 0 0 1 -1 0] [ 0 0 0 1 -1] [ 0 0 0 0 0] - sage: Graph(M) + sage: Graph(M) # needs sage.modules Graph on 6 vertices - sage: Graph(Matrix([[1],[1],[1]])) + sage: Graph(Matrix([[1],[1],[1]])) # needs sage.modules Traceback (most recent call last): ... - ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1, 1] in column 0 - sage: Graph(Matrix([[1],[1],[0]])) + ValueError: there must be one or two nonzero entries per column + in an incidence matrix, got entries [1, 1, 1] in column 0 + sage: Graph(Matrix([[1],[1],[0]])) # needs sage.modules Graph on 3 vertices - sage: M = Matrix([[0,1,-1],[1,0,-1],[-1,-1,0]]); M + sage: M = Matrix([[0,1,-1], [1,0,-1], [-1,-1,0]]); M # needs sage.modules [ 0 1 -1] [ 1 0 -1] [-1 -1 0] - sage: Graph(M,sparse=True) + sage: Graph(M, sparse=True) # needs sage.modules Graph on 3 vertices - sage: M = Matrix([[0,1,1],[1,0,1],[-1,-1,0]]); M + sage: M = Matrix([[0,1,1], [1,0,1], [-1,-1,0]]); M # needs sage.modules [ 0 1 1] [ 1 0 1] [-1 -1 0] - sage: Graph(M) + sage: Graph(M) # needs sage.modules Traceback (most recent call last): ... ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1] in column 2 Check that :trac:`9714` is fixed:: + sage: # needs sage.modules sage: MA = Matrix([[1,2,0], [0,2,0], [0,0,1]]) sage: GA = Graph(MA, format='adjacency_matrix') - sage: MI = GA.incidence_matrix(oriented=False) - sage: MI + sage: MI = GA.incidence_matrix(oriented=False); MI [2 1 1 0 0 0] [0 1 1 2 2 0] [0 0 0 0 0 2] sage: Graph(MI).edges(sort=True, labels=None) [(0, 0), (0, 1), (0, 1), (1, 1), (1, 1), (2, 2)] - sage: M = Matrix([[1], [-1]]); M + sage: M = Matrix([[1], [-1]]); M # needs sage.modules [ 1] [-1] - sage: Graph(M).edges(sort=True) + sage: Graph(M).edges(sort=True) # needs sage.modules [(0, 1, None)] #. A Seidel adjacency matrix:: - sage: from sage.combinat.matrices.hadamard_matrix import \ - ....: regular_symmetric_hadamard_matrix_with_constant_diagonal as rshcd - sage: m=rshcd(16,1)- matrix.identity(16) - sage: Graph(m,format="seidel_adjacency_matrix").is_strongly_regular(parameters=True) + sage: from sage.combinat.matrices.hadamard_matrix import ( # needs sage.modules + ....: regular_symmetric_hadamard_matrix_with_constant_diagonal as rshcd) + sage: m = rshcd(16,1) - matrix.identity(16) # needs sage.modules + sage: Graph(m, # needs sage.modules + ....: format="seidel_adjacency_matrix").is_strongly_regular(parameters=True) (16, 6, 2, 2) #. List of edges, or labelled edges:: @@ -795,16 +805,16 @@ class Graph(GenericGraph): #. A NetworkX MultiGraph:: - sage: import networkx - sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]}) - sage: Graph(g) + sage: import networkx # needs networkx + sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]}) # needs networkx + sage: Graph(g) # needs networkx Multi-graph on 5 vertices #. A NetworkX graph:: - sage: import networkx - sage: g = networkx.Graph({0:[1,2,3], 2:[4]}) - sage: DiGraph(g) + sage: import networkx # needs networkx + sage: g = networkx.Graph({0:[1,2,3], 2:[4]}) # needs networkx + sage: DiGraph(g) # needs networkx Digraph on 5 vertices #. An igraph Graph (see also @@ -818,11 +828,12 @@ class Graph(GenericGraph): If ``vertex_labels`` is ``True``, the names of the vertices are given by the vertex attribute ``'name'``, if available:: - sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'name':['a','b','c']}) # optional - python_igraph - sage: Graph(g).vertices(sort=True) # optional - python_igraph + sage: # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'name':['a','b','c']}) + sage: Graph(g).vertices(sort=True) ['a', 'b', 'c'] - sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'label':['a','b','c']}) # optional - python_igraph - sage: Graph(g).vertices(sort=True) # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'label':['a','b','c']}) + sage: Graph(g).vertices(sort=True) [0, 1, 2] If the igraph Graph has edge attributes, they are used as edge labels:: @@ -877,6 +888,7 @@ class Graph(GenericGraph): ... ValueError: An *undirected* igraph graph was expected. To build an directed graph, call the DiGraph constructor. + sage: # needs sage.modules sage: m = matrix([[0, -1], [-1, 0]]) sage: Graph(m, format="seidel_adjacency_matrix") Graph on 2 vertices @@ -886,8 +898,8 @@ class Graph(GenericGraph): ... ValueError: the adjacency matrix of a Seidel graph must be symmetric - sage: m[0,1] = -1; m[1,1] = 1 - sage: Graph(m, format="seidel_adjacency_matrix") + sage: m[0,1] = -1; m[1,1] = 1 # needs sage.modules + sage: Graph(m, format="seidel_adjacency_matrix") # needs sage.modules Traceback (most recent call last): ... ValueError: the adjacency matrix of a Seidel graph must have 0s on the main diagonal @@ -901,7 +913,7 @@ class Graph(GenericGraph): Check that :trac:`27505` is fixed:: - sage: Graph(Graph().networkx_graph(), weighted=None, format='NX') + sage: Graph(Graph().networkx_graph(), weighted=None, format='NX') # needs networkx Graph on 0 vertices """ _directed = False @@ -910,19 +922,19 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, data_structure="sparse", vertex_labels=True, name=None, multiedges=None, convert_empty_dict_labels_to_None=None, - sparse=True, immutable=False): + sparse=True, immutable=False, hash_labels=None): """ TESTS:: sage: G = Graph() sage: loads(dumps(G)) == G True - sage: a = matrix(2,2,[1,0,0,1]) - sage: Graph(a).adjacency_matrix() == a + sage: a = matrix(2,2,[1,0,0,1]) # needs sage.modules + sage: Graph(a).adjacency_matrix() == a # needs sage.modules True - sage: a = matrix(2,2,[2,0,0,1]) - sage: Graph(a,sparse=True).adjacency_matrix() == a + sage: a = matrix(2,2,[2,0,0,1]) # needs sage.modules + sage: Graph(a,sparse=True).adjacency_matrix() == a # needs sage.modules True The positions are copied when the graph is built from another graph :: @@ -967,7 +979,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, Verify that the int format works as expected (:trac:`12557`):: - sage: Graph(2).adjacency_matrix() + sage: Graph(2).adjacency_matrix() # needs sage.modules [0 0] [0 0] sage: Graph(3) == Graph(3,format='int') @@ -976,10 +988,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None, Problem with weighted adjacency matrix (:trac:`13919`):: sage: B = {0:{1:2,2:5,3:4},1:{2:2,4:7},2:{3:1,4:4,5:3},3:{5:4},4:{5:1,6:5},5:{6:7}} - sage: grafo3 = Graph(B,weighted=True) - sage: matad = grafo3.weighted_adjacency_matrix() - sage: grafo4 = Graph(matad,format = "adjacency_matrix", weighted=True) - sage: grafo4.shortest_path(0,6,by_weight=True) + sage: grafo3 = Graph(B, weighted=True) + sage: matad = grafo3.weighted_adjacency_matrix() # needs sage.modules + sage: grafo4 = Graph(matad, format="adjacency_matrix", weighted=True) # needs sage.modules + sage: grafo4.shortest_path(0, 6, by_weight=True) # needs sage.modules [0, 1, 2, 5, 4, 6] Graphs returned when setting ``immutable=False`` are mutable:: @@ -997,15 +1009,17 @@ def __init__(self, data=None, pos=None, loops=None, format=None, Check error messages for graphs built from incidence matrices (see :trac:`18440`):: - sage: Graph(matrix([[-1, 1, 0],[1, 0, 0]])) + sage: Graph(matrix([[-1, 1, 0],[1, 0, 0]])) # needs sage.modules Traceback (most recent call last): ... - ValueError: column 1 of the (oriented) incidence matrix contains only one nonzero value - sage: Graph(matrix([[1,1],[1,1],[1,0]])) + ValueError: column 1 of the (oriented) incidence matrix + contains only one nonzero value + sage: Graph(matrix([[1,1],[1,1],[1,0]])) # needs sage.modules Traceback (most recent call last): ... - ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1, 1] in column 0 - sage: Graph(matrix([[3,1,1],[0,1,1]])) + ValueError: there must be one or two nonzero entries per column + in an incidence matrix, got entries [1, 1, 1] in column 0 + sage: Graph(matrix([[3,1,1],[0,1,1]])) # needs sage.modules Traceback (most recent call last): ... ValueError: each column of a non-oriented incidence matrix must sum to 2, but column 0 does not @@ -1253,6 +1267,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted = False self._weighted = getattr(self, '_weighted', weighted) + if hash_labels is None and hasattr(data, '_hash_labels'): + hash_labels = data._hash_labels + self._hash_labels = hash_labels + self._pos = copy(pos) if format != 'Graph' or name is not None: @@ -1504,7 +1522,7 @@ def is_tree(self, certificate=False, output='vertex'): sage: G.is_tree(certificate=True) (False, [1, 2]) sage: G.is_tree(certificate=True, output='edge') - (False, [(1, 2, 'a'), (2, 1, 'b')]) + (False, [(1, 2, 'b'), (2, 1, 'a')]) TESTS: @@ -1532,6 +1550,16 @@ def is_tree(self, certificate=False, output='vertex'): (False, [0]) sage: G.is_tree(certificate=True, output='edge') (False, [(0, 0, None)]) + + Case of edges with incomparable types (see :trac:`35903`):: + + sage: G = Graph(multiedges=True) + sage: G.add_cycle(['A', 1, 2, 3]) + sage: G.add_cycle(['A', 1, 2, 3]) + sage: G.is_tree(certificate=True, output='vertex') + (False, ['A', 1]) + sage: G.is_tree(certificate=True, output='edge') + (False, [('A', 1, None), (1, 'A', None)]) """ if output not in ['vertex', 'edge']: raise ValueError('output must be either vertex or edge') @@ -1549,12 +1577,18 @@ def is_tree(self, certificate=False, output='vertex'): return False, L[:1] if self.has_multiple_edges(): + multiple_edges = self.multiple_edges(sort=False) if output == 'vertex': - return (False, list(self.multiple_edges(sort=True)[0][:2])) - edge1, edge2 = self.multiple_edges(sort=True)[:2] - if edge1[0] != edge2[0]: - return (False, [edge1, edge2]) - return (False, [edge1, (edge2[1], edge2[0], edge2[2])]) + return (False, list(multiple_edges[0][:2])) + # Search for 2 edges between u and v. + # We do this way to handle the case of edges with incomparable + # types + u1, v1, w1 = multiple_edges[0] + for u2, v2, w2 in multiple_edges[1:]: + if u1 == u2 and v1 == v2: + return (False, [(u1, v1, w1), (v2, u2, w2)]) + elif u1 == v2 and v1 == u2: + return (False, [(u1, v1, w1), (u2, v2, w2)]) if output == 'edge': if self.allows_multiple_edges(): @@ -1624,9 +1658,9 @@ def is_forest(self, certificate=False, output='vertex'): sage: g.is_forest(certificate=True) (True, None) sage: (2*g + graphs.PetersenGraph() + g).is_forest(certificate=True) - (False, [68, 66, 69, 67, 65]) + (False, [64, 69, 67, 65, 60]) """ - connected_components = self.connected_components() + connected_components = self.connected_components(sort=False) number_of_connected_components = len(connected_components) isit = (self.order() == self.size() + number_of_connected_components) @@ -1685,7 +1719,7 @@ def is_cactus(self): Test a graph that is not outerplanar, see :trac:`24480`:: - sage: graphs.Balaban10Cage().is_cactus() + sage: graphs.Balaban10Cage().is_cactus() # needs networkx False """ self._scream_if_not_simple() @@ -1806,7 +1840,7 @@ def is_cograph(self): sage: graphs.HouseXGraph().is_cograph() True - sage: graphs.HouseGraph().is_cograph() + sage: graphs.HouseGraph().is_cograph() # needs sage.modules False .. TODO:: @@ -1817,9 +1851,9 @@ def is_cograph(self): TESTS:: - sage: [graphs.PathGraph(i).is_cograph() for i in range(6)] + sage: [graphs.PathGraph(i).is_cograph() for i in range(6)] # needs sage.modules [True, True, True, True, False, False] - sage: graphs.CycleGraph(5).is_cograph() # Self-complemented + sage: graphs.CycleGraph(5).is_cograph() # Self-complemented # needs sage.modules False """ # A cograph has no 4-vertex path as an induced subgraph. @@ -2126,7 +2160,7 @@ def is_overfull(self): sage: g = graphs.ClawGraph() sage: g Claw graph: Graph on 4 vertices - sage: edge_coloring(g, value_only=True) + sage: edge_coloring(g, value_only=True) # needs sage.numerical_mip 3 sage: g.is_overfull() False @@ -2181,7 +2215,7 @@ def is_overfull(self): sage: g.is_overfull() False sage: from sage.graphs.graph_coloring import edge_coloring - sage: max(g.degree()) + 1 == edge_coloring(g, value_only=True) + sage: max(g.degree()) + 1 == edge_coloring(g, value_only=True) # needs sage.numerical_mip True """ # # A possible optimized version. But the gain in speed is very little. @@ -2216,25 +2250,25 @@ def is_even_hole_free(self, certificate=False): Is the Petersen Graph even-hole-free :: sage: g = graphs.PetersenGraph() - sage: g.is_even_hole_free() + sage: g.is_even_hole_free() # needs sage.modules False As any chordal graph is hole-free, interval graphs behave the same way:: sage: g = graphs.RandomIntervalGraph(20) - sage: g.is_even_hole_free() + sage: g.is_even_hole_free() # needs sage.modules True It is clear, though, that a random Bipartite Graph which is not a forest has an even hole:: - sage: g = graphs.RandomBipartite(10, 10, .5) - sage: g.is_even_hole_free() and not g.is_forest() + sage: g = graphs.RandomBipartite(10, 10, .5) # needs numpy + sage: g.is_even_hole_free() and not g.is_forest() # needs numpy sage.modules False We can check the certificate returned is indeed an even cycle:: - sage: if not g.is_forest(): + sage: if not g.is_forest(): # needs numpy sage.modules ....: cycle = g.is_even_hole_free(certificate=True) ....: if cycle.order() % 2 == 1: ....: print("Error !") @@ -2249,17 +2283,18 @@ def is_even_hole_free(self, certificate=False): Bug reported in :trac:`9925`, and fixed by :trac:`9420`:: - sage: g = Graph(':SiBFGaCEF_@CE`DEGH`CEFGaCDGaCDEHaDEF`CEH`ABCDEF', loops=False, multiedges=False) - sage: g.is_even_hole_free() + sage: g = Graph(':SiBFGaCEF_@CE`DEGH`CEFGaCDGaCDEHaDEF`CEH`ABCDEF', + ....: loops=False, multiedges=False) + sage: g.is_even_hole_free() # needs sage.modules False - sage: g.is_even_hole_free(certificate=True) + sage: g.is_even_hole_free(certificate=True) # needs sage.modules Subgraph of (): Graph on 4 vertices Making sure there are no other counter-examples around :: sage: t = lambda x: (Graph(x).is_forest() or ....: isinstance(Graph(x).is_even_hole_free(certificate=True), Graph)) - sage: all( t(graphs.RandomBipartite(10, 10, .5)) for i in range(100) ) + sage: all(t(graphs.RandomBipartite(10, 10, .5)) for i in range(100)) # needs numpy sage.modules True """ girth = self.girth() @@ -2316,7 +2351,7 @@ def is_odd_hole_free(self, certificate=False): Is the Petersen Graph odd-hole-free :: sage: g = graphs.PetersenGraph() - sage: g.is_odd_hole_free() + sage: g.is_odd_hole_free() # needs sage.modules False Which was to be expected, as its girth is 5 :: @@ -2326,14 +2361,14 @@ def is_odd_hole_free(self, certificate=False): We can check the certificate returned is indeed a 5-cycle:: - sage: cycle = g.is_odd_hole_free(certificate=True) - sage: cycle.is_isomorphic(graphs.CycleGraph(5)) + sage: cycle = g.is_odd_hole_free(certificate=True) # needs sage.modules + sage: cycle.is_isomorphic(graphs.CycleGraph(5)) # needs sage.modules True As any chordal graph is hole-free, no interval graph has an odd hole:: sage: g = graphs.RandomIntervalGraph(20) - sage: g.is_odd_hole_free() + sage: g.is_odd_hole_free() # needs sage.modules True """ girth = self.odd_girth() @@ -2399,7 +2434,7 @@ def is_triangle_free(self, algorithm='dense_graph', certificate=False): or a complete Bipartite Graph:: sage: G = graphs.CompleteBipartiteGraph(5,6) - sage: G.is_triangle_free(algorithm='matrix') + sage: G.is_triangle_free(algorithm='matrix') # needs sage.modules True sage: G.is_triangle_free(algorithm='bitset') True @@ -2409,7 +2444,7 @@ def is_triangle_free(self, algorithm='dense_graph', certificate=False): a tripartite graph, though, contains many triangles:: sage: G = (3 * graphs.CompleteGraph(5)).complement() - sage: G.is_triangle_free(algorithm='matrix') + sage: G.is_triangle_free(algorithm='matrix') # needs sage.modules False sage: G.is_triangle_free(algorithm='bitset') False @@ -2532,8 +2567,11 @@ def is_split(self): graph if and only if does not contain the 4-cycle, 5-cycle or `2K_2` as an induced subgraph. Hence for the above graph we have:: - sage: forbidden_subgraphs = [graphs.CycleGraph(4), graphs.CycleGraph(5), 2 * graphs.CompleteGraph(2)] - sage: sum(g.subgraph_search_count(H,induced=True) for H in forbidden_subgraphs) + sage: forbidden_subgraphs = [graphs.CycleGraph(4), + ....: graphs.CycleGraph(5), + ....: 2 * graphs.CompleteGraph(2)] + sage: sum(g.subgraph_search_count(H, induced=True) # needs sage.modules + ....: for H in forbidden_subgraphs) 0 """ self._scream_if_not_simple() @@ -2583,45 +2621,45 @@ def is_perfect(self, certificate=False): A Bipartite Graph is always perfect :: - sage: g = graphs.RandomBipartite(8,4,.5) - sage: g.is_perfect() + sage: g = graphs.RandomBipartite(8,4,.5) # needs numpy + sage: g.is_perfect() # needs numpy sage.modules True So is the line graph of a bipartite graph:: - sage: g = graphs.RandomBipartite(4,3,0.7) - sage: g.line_graph().is_perfect() # long time + sage: g = graphs.RandomBipartite(4,3,0.7) # needs numpy + sage: g.line_graph().is_perfect() # long time # needs numpy sage.modules True As well as the Cartesian product of two complete graphs:: sage: g = graphs.CompleteGraph(3).cartesian_product(graphs.CompleteGraph(3)) - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules True Interval Graphs, which are chordal graphs, too :: sage: g = graphs.RandomIntervalGraph(7) - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules True The PetersenGraph, which is triangle-free and has chromatic number 3 is obviously not perfect:: sage: g = graphs.PetersenGraph() - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules False We can obtain an induced 5-cycle as a certificate:: - sage: g.is_perfect(certificate=True) + sage: g.is_perfect(certificate=True) # needs sage.modules Subgraph of (Petersen graph): Graph on 5 vertices TESTS: Check that :trac:`13546` has been fixed:: - sage: Graph(':FgGE@I@GxGs', loops=False, multiedges=False).is_perfect() + sage: Graph(':FgGE@I@GxGs', loops=False, multiedges=False).is_perfect() # needs sage.modules False sage: g = Graph({0: [2, 3, 4, 5], ....: 1: [3, 4, 5, 6], @@ -2630,12 +2668,12 @@ def is_perfect(self, certificate=False): ....: 4: [0, 1, 2, 6], ....: 5: [0, 1, 2, 3], ....: 6: [1, 2, 3, 4]}) - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules False TESTS:: - sage: Graph(':Ab').is_perfect() + sage: Graph(':Ab').is_perfect() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is only defined for simple graphs, and yours is not one of them ! @@ -2644,7 +2682,7 @@ def is_perfect(self, certificate=False): sage: g.add_edge(0,0) sage: g.edges(sort=True) [(0, 0, None)] - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is only defined for simple graphs, and yours is not one of them ! @@ -2669,7 +2707,6 @@ def is_perfect(self, certificate=False): return self_complement.is_odd_hole_free(certificate=certificate) - @doc_index("Graph properties") def is_edge_transitive(self): r""" @@ -2692,16 +2729,16 @@ def is_edge_transitive(self): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.is_edge_transitive() + sage: P.is_edge_transitive() # needs sage.libs.gap True sage: C = graphs.CubeGraph(3) - sage: C.is_edge_transitive() + sage: C.is_edge_transitive() # needs sage.libs.gap True - sage: G = graphs.GrayGraph() - sage: G.is_edge_transitive() + sage: G = graphs.GrayGraph() # needs networkx + sage: G.is_edge_transitive() # needs networkx sage.libs.gap True sage: P = graphs.PathGraph(4) - sage: P.is_edge_transitive() + sage: P.is_edge_transitive() # needs sage.libs.gap False """ from sage.libs.gap.libgap import libgap @@ -2738,10 +2775,10 @@ def is_arc_transitive(self): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.is_arc_transitive() + sage: P.is_arc_transitive() # needs sage.libs.gap True - sage: G = graphs.GrayGraph() - sage: G.is_arc_transitive() + sage: G = graphs.GrayGraph() # needs networkx + sage: G.is_arc_transitive() # needs networkx sage.libs.gap False """ from sage.libs.gap.libgap import libgap @@ -2775,13 +2812,13 @@ def is_half_transitive(self): The Petersen Graph is not half-transitive:: sage: P = graphs.PetersenGraph() - sage: P.is_half_transitive() + sage: P.is_half_transitive() # needs sage.libs.gap False The smallest half-transitive graph is the Holt Graph:: sage: H = graphs.HoltGraph() - sage: H.is_half_transitive() + sage: H.is_half_transitive() # needs sage.libs.gap True """ # A half-transitive graph always has only vertices of even degree @@ -2812,19 +2849,19 @@ def is_semi_symmetric(self): The Petersen graph is not semi-symmetric:: sage: P = graphs.PetersenGraph() - sage: P.is_semi_symmetric() + sage: P.is_semi_symmetric() # needs sage.libs.gap False The Gray graph is the smallest possible cubic semi-symmetric graph:: - sage: G = graphs.GrayGraph() - sage: G.is_semi_symmetric() + sage: G = graphs.GrayGraph() # needs networkx + sage: G.is_semi_symmetric() # needs networkx sage.libs.gap True Another well known semi-symmetric graph is the Ljubljana graph:: - sage: L = graphs.LjubljanaGraph() - sage: L.is_semi_symmetric() + sage: L = graphs.LjubljanaGraph() # needs networkx + sage: L.is_semi_symmetric() # needs networkx sage.libs.gap True """ # A semi-symmetric graph is always bipartite @@ -2888,7 +2925,6 @@ def is_path(self): return False return deg_one_counter == 2 and seen_counter == order - @doc_index("Connectivity, orientations, trees") def degree_constrained_subgraph(self, bounds, solver=None, verbose=0, *, integrality_tolerance=1e-3): @@ -2947,8 +2983,8 @@ def degree_constrained_subgraph(self, bounds, solver=None, verbose=0, sage: g = graphs.CycleGraph(6) sage: bounds = lambda x: [1,1] - sage: m = g.degree_constrained_subgraph(bounds=bounds) - sage: m.size() + sage: m = g.degree_constrained_subgraph(bounds=bounds) # needs sage.numerical.mip + sage: m.size() # needs sage.numerical.mip 3 """ self._scream_if_not_simple() @@ -3153,8 +3189,8 @@ def minimum_outdegree_orientation(self, use_edge_labels=False, solver=None, verb optimal orientation is `\left\lceil \frac {nm} {n+m}\right\rceil`:: sage: g = graphs.CompleteBipartiteGraph(3,4) - sage: o = g.minimum_outdegree_orientation() - sage: max(o.out_degree()) == integer_ceil((4*3)/(3+4)) + sage: o = g.minimum_outdegree_orientation() # needs sage.numerical.mip + sage: max(o.out_degree()) == integer_ceil((4*3)/(3+4)) # needs sage.numerical.mip True """ self._scream_if_not_simple() @@ -3624,23 +3660,23 @@ def chromatic_index(self, solver=None, verbose=0, *, integrality_tolerance=1e-3) The path `P_n` with `n \geq 2` has chromatic index 2:: - sage: graphs.PathGraph(5).chromatic_index() + sage: graphs.PathGraph(5).chromatic_index() # needs sage.numerical.mip 2 The windmill graph with parameters `k,n` has chromatic index `(k-1)n`:: sage: k,n = 3,4 sage: G = graphs.WindmillGraph(k,n) - sage: G.chromatic_index() == (k-1)*n + sage: G.chromatic_index() == (k-1)*n # needs sage.numerical.mip True TESTS: Graphs without vertices or edges:: - sage: Graph().chromatic_index() + sage: Graph().chromatic_index() # needs sage.numerical.mip 0 - sage: Graph(2).chromatic_index() + sage: Graph(2).chromatic_index() # needs sage.numerical.mip 0 """ if not self.order() or not self.size(): @@ -3659,24 +3695,29 @@ def chromatic_number(self, algorithm="DLX", solver=None, verbose=0, INPUT: - - ``algorithm`` -- Select an algorithm from the following supported + - ``algorithm`` -- string (default: ``"DLX"``); one of the following algorithms: - - If ``algorithm="DLX"`` (default), the chromatic number is computed - using the dancing link algorithm. It is inefficient speedwise to - compute the chromatic number through the dancing link algorithm - because this algorithm computes *all* the possible colorings to - check that one exists. + - ``"DLX"`` (default): the chromatic number is computed using the + dancing link algorithm. It is inefficient speedwise to compute the + chromatic number through the dancing link algorithm because this + algorithm computes *all* the possible colorings to check that one + exists. - - If ``algorithm="CP"``, the chromatic number is computed using the - coefficients of the chromatic polynomial. Again, this method is - inefficient in terms of speed and it only useful for small graphs. + - ``"CP"``: the chromatic number is computed using the coefficients of + the chromatic polynomial. Again, this method is inefficient in terms + of speed and it only useful for small graphs. - - If ``algorithm="MILP"``, the chromatic number is computed using a - mixed integer linear program. The performance of this implementation - is affected by whether optional MILP solvers have been installed - (see the :mod:`MILP module <sage.numerical.mip>`, or Sage's tutorial - on Linear Programming). + - ``"MILP"``: the chromatic number is computed using a mixed integer + linear program. The performance of this implementation is affected + by whether optional MILP solvers have been installed (see the + :mod:`MILP module <sage.numerical.mip>`, or Sage's tutorial on + Linear Programming). + + - ``"parallel"``: all the above algorithms are executed in parallel + and the result is returned as soon as one algorithm ends. Observe + that the speed of the above algorithms depends on the size and + structure of the graph. - ``solver`` -- string (default: ``None``); specify a Mixed Integer Linear Programming (MILP) solver to be used. If set to ``None``, the @@ -3707,10 +3748,12 @@ def chromatic_number(self, algorithm="DLX", solver=None, verbose=0, 3 sage: G.chromatic_number(algorithm="CP") 3 + sage: G.chromatic_number(algorithm="parallel") + 3 A bipartite graph has (by definition) chromatic number 2:: - sage: graphs.RandomBipartite(50,50,0.7).chromatic_number() + sage: graphs.RandomBipartite(50,50,0.7).chromatic_number() # needs numpy 2 A complete multipartite graph with k parts has chromatic number `k`:: @@ -3745,42 +3788,47 @@ def chromatic_number(self, algorithm="DLX", solver=None, verbose=0, 0 sage: G.chromatic_number(algorithm="CP") 0 + sage: G.chromatic_number(algorithm="parallel") + 0 sage: G = Graph({0: [1, 2, 3], 1: [2]}) sage: G.chromatic_number(algorithm="foo") Traceback (most recent call last): ... - ValueError: The 'algorithm' keyword must be set to either 'DLX', 'MILP' or 'CP'. + ValueError: the 'algorithm' keyword must be set to either 'DLX', 'MILP', 'CP' or 'parallel' - Test on a random graph (:trac:`33559`):: + Test on a random graph (:trac:`33559`, modified in :trac:`12379`):: sage: G = graphs.RandomGNP(15, .2) - sage: c1 = G.chromatic_number(algorithm='DLX') - sage: c2 = G.chromatic_number(algorithm='MILP') - sage: c3 = G.chromatic_number(algorithm='CP') - sage: c1 == c2 and c2 == c3 + sage: algorithms = ['DLX', 'MILP', 'CP', 'parallel'] + sage: len(set([G.chromatic_number(algorithm=algo) for algo in algorithms])) == 1 True """ self._scream_if_not_simple(allow_multiple_edges=True) - # default built-in algorithm; bad performance if algorithm == "DLX": from sage.graphs.graph_coloring import chromatic_number return chromatic_number(self) - # Algorithm with good performance, but requires an optional - # package: choose any of GLPK or CBC. elif algorithm == "MILP": from sage.graphs.graph_coloring import vertex_coloring return vertex_coloring(self, value_only=True, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) - # another algorithm with bad performance; only good for small graphs elif algorithm == "CP": f = self.chromatic_polynomial() i = 0 while not f(i): i += 1 return i + elif algorithm == "parallel": + def use_all(algorithms): + @parallel(len(algorithms), verbose=False) + def func(alg): + return self.chromatic_number(algorithm=alg, solver=solver, verbose=verbose, + integrality_tolerance=integrality_tolerance) + for input, output in func(algorithms): + return output + return use_all(['DLX', 'MILP', 'CP']) else: - raise ValueError("The 'algorithm' keyword must be set to either 'DLX', 'MILP' or 'CP'.") + raise ValueError("the 'algorithm' keyword must be set to either 'DLX', 'MILP', 'CP' or 'parallel'") @doc_index("Coloring") def coloring(self, algorithm="DLX", hex_colors=False, solver=None, verbose=0, @@ -3835,12 +3883,13 @@ def coloring(self, algorithm="DLX", hex_colors=False, solver=None, verbose=0, True sage: are_equal_colorings(P, Q) True + + sage: # needs sage.plot sage: G.plot(partition=P) Graphics object consisting of 16 graphics primitives sage: G.coloring(hex_colors=True, algorithm="MILP") {'#0000ff': [4], '#00ff00': [0, 6, 5], '#ff0000': [2, 1, 3]} - sage: H = G.coloring(hex_colors=True, algorithm="DLX") - sage: H + sage: H = G.coloring(hex_colors=True, algorithm="DLX"); H {'#0000ff': [4], '#00ff00': [1, 2, 3], '#ff0000': [0, 5, 6]} sage: G.plot(vertex_colors=H) Graphics object consisting of 16 graphics primitives @@ -3891,25 +3940,26 @@ def chromatic_symmetric_function(self, R=None): EXAMPLES:: - sage: s = SymmetricFunctions(ZZ).s() + sage: s = SymmetricFunctions(ZZ).s() # needs sage.combinat sage.modules sage: G = graphs.CycleGraph(5) - sage: XG = G.chromatic_symmetric_function(); XG + sage: XG = G.chromatic_symmetric_function(); XG # needs sage.combinat sage.modules p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1] + 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5] - sage: s(XG) + sage: s(XG) # needs sage.combinat sage.modules 30*s[1, 1, 1, 1, 1] + 10*s[2, 1, 1, 1] + 10*s[2, 2, 1] Not all graphs have a positive Schur expansion:: sage: G = graphs.ClawGraph() - sage: XG = G.chromatic_symmetric_function(); XG + sage: XG = G.chromatic_symmetric_function(); XG # needs sage.combinat sage.modules p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4] - sage: s(XG) + sage: s(XG) # needs sage.combinat sage.modules 8*s[1, 1, 1, 1] + 5*s[2, 1, 1] - s[2, 2] + s[3, 1] We show that given a triangle `\{e_1, e_2, e_3\}`, we have `X_G = X_{G - e_1} + X_{G - e_2} - X_{G - e_1 - e_2}`:: + sage: # needs sage.combinat sage.modules sage: G = Graph([[1,2],[1,3],[2,3]]) sage: XG = G.chromatic_symmetric_function() sage: G1 = copy(G) @@ -3926,7 +3976,7 @@ def chromatic_symmetric_function(self, R=None): """ from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import _Partitions - from sage.misc.misc import powerset + from sage.combinat.subset import powerset if R is None: R = ZZ p = SymmetricFunctions(R).p() @@ -3967,6 +4017,7 @@ def chromatic_quasisymmetric_function(self, t=None, R=None): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: G = Graph([[1,2,3], [[1,3], [2,3]]]) sage: G.chromatic_quasisymmetric_function() (2*t^2+2*t+2)*M[1, 1, 1] + M[1, 2] + t^2*M[2, 1] @@ -3985,27 +4036,27 @@ def chromatic_quasisymmetric_function(self, t=None, R=None): Not all chromatic quasisymmetric functions are symmetric:: sage: G = Graph([[1,2], [1,5], [3,4], [3,5]]) - sage: G.chromatic_quasisymmetric_function().is_symmetric() + sage: G.chromatic_quasisymmetric_function().is_symmetric() # needs sage.combinat sage.modules False We check that at `t = 1`, we recover the usual chromatic symmetric function:: - sage: p = SymmetricFunctions(QQ).p() + sage: p = SymmetricFunctions(QQ).p() # needs sage.combinat sage.modules sage: G = graphs.CycleGraph(5) - sage: XG = G.chromatic_quasisymmetric_function(t=1); XG + sage: XG = G.chromatic_quasisymmetric_function(t=1); XG # needs sage.combinat sage.modules 120*M[1, 1, 1, 1, 1] + 30*M[1, 1, 1, 2] + 30*M[1, 1, 2, 1] + 30*M[1, 2, 1, 1] + 10*M[1, 2, 2] + 30*M[2, 1, 1, 1] + 10*M[2, 1, 2] + 10*M[2, 2, 1] - sage: p(XG.to_symmetric_function()) + sage: p(XG.to_symmetric_function()) # needs sage.combinat sage.modules p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1] + 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5] sage: G = graphs.ClawGraph() - sage: XG = G.chromatic_quasisymmetric_function(t=1); XG + sage: XG = G.chromatic_quasisymmetric_function(t=1); XG # needs sage.combinat sage.modules 24*M[1, 1, 1, 1] + 6*M[1, 1, 2] + 6*M[1, 2, 1] + M[1, 3] + 6*M[2, 1, 1] + M[3, 1] - sage: p(XG.to_symmetric_function()) + sage: p(XG.to_symmetric_function()) # needs sage.combinat sage.modules p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4] """ from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions @@ -4109,7 +4160,7 @@ def matching(self, value_only=False, algorithm="Edmonds", Maximum matching in a Pappus Graph:: sage: g = graphs.PappusGraph() - sage: g.matching(value_only=True) + sage: g.matching(value_only=True) # needs sage.networkx 9 Same test with the Linear Program formulation:: @@ -4129,7 +4180,7 @@ def matching(self, value_only=False, algorithm="Edmonds", and LP formulation:: sage: g = Graph([(0,1,0), (1,2,999), (2,3,-5)]) - sage: sorted(g.matching()) + sage: sorted(g.matching()) # needs sage.networkx [(0, 1, 0), (2, 3, -5)] sage: sorted(g.matching(algorithm="LP")) [(0, 1, 0), (2, 3, -5)] @@ -4138,7 +4189,7 @@ def matching(self, value_only=False, algorithm="Edmonds", LP formulation:: sage: g = Graph([(0,1,0), (1,2,999), (2,3,-5)]) - sage: g.matching(use_edge_labels=True) + sage: g.matching(use_edge_labels=True) # needs sage.networkx [(1, 2, 999)] sage: g.matching(algorithm="LP", use_edge_labels=True) [(1, 2, 999)] @@ -4148,10 +4199,10 @@ def matching(self, value_only=False, algorithm="Edmonds", sage: edge_list = [(0,0,5), (0,1,1), (0,2,2), (0,3,3), (1,2,6) ....: , (1,2,3), (1,3,3), (2,3,3)] sage: g = Graph(edge_list, loops=True, multiedges=True) - sage: m = g.matching(use_edge_labels=True) - sage: type(m) + sage: m = g.matching(use_edge_labels=True) # needs sage.networkx + sage: type(m) # needs sage.networkx <class 'sage.graphs.views.EdgesView'> - sage: sorted(m) + sage: sorted(m) # needs sage.networkx [(0, 3, 3), (1, 2, 6)] TESTS: @@ -4286,9 +4337,9 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve Odd length cycles and odd cliques of order at least 3 are factor-critical graphs:: - sage: [graphs.CycleGraph(2*i + 1).is_factor_critical() for i in range(5)] + sage: [graphs.CycleGraph(2*i + 1).is_factor_critical() for i in range(5)] # needs networkx [True, True, True, True, True] - sage: [graphs.CompleteGraph(2*i + 1).is_factor_critical() for i in range(5)] + sage: [graphs.CompleteGraph(2*i + 1).is_factor_critical() for i in range(5)] # needs networkx [True, True, True, True, True] More generally, every Hamiltonian graph with an odd number of vertices @@ -4299,18 +4350,18 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve sage: G.add_edge(14, 0) sage: G.is_hamiltonian() True - sage: G.is_factor_critical() + sage: G.is_factor_critical() # needs networkx True Friendship graphs are non-Hamiltonian factor-critical graphs:: - sage: [graphs.FriendshipGraph(i).is_factor_critical() for i in range(1, 5)] + sage: [graphs.FriendshipGraph(i).is_factor_critical() for i in range(1, 5)] # needs networkx [True, True, True, True] Bipartite graphs are not factor-critical:: - sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5) - sage: G.is_factor_critical() + sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5) # needs numpy + sage: G.is_factor_critical() # needs numpy False Graphs with even order are not factor critical:: @@ -4322,10 +4373,10 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve One can specify a matching:: sage: F = graphs.FriendshipGraph(4) - sage: M = F.matching() - sage: F.is_factor_critical(matching=M) + sage: M = F.matching() # needs networkx + sage: F.is_factor_critical(matching=M) # needs networkx True - sage: F.is_factor_critical(matching=Graph(M)) + sage: F.is_factor_critical(matching=Graph(M)) # needs networkx True TESTS: @@ -4335,8 +4386,8 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve sage: G = graphs.RandomGNP(15, .3) sage: while not G.is_biconnected(): ....: G = graphs.RandomGNP(15, .3) - sage: M = G.matching() - sage: G.is_factor_critical(matching=M[:-1]) + sage: M = G.matching() # needs networkx + sage: G.is_factor_critical(matching=M[:-1]) # needs networkx Traceback (most recent call last): ... ValueError: the input is not a near perfect matching of the graph @@ -4478,8 +4529,8 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, with this method :: sage: g = graphs.CycleGraph(10) - sage: mapping = g.has_homomorphism_to(g, core = True) - sage: print("The size of the core is {}".format(len(set(mapping.values())))) + sage: mapping = g.has_homomorphism_to(g, core=True) # needs sage.numerical.mip + sage: print("The size of the core is {}".format(len(set(mapping.values())))) # needs sage.numerical.mip The size of the core is 2 OUTPUT: @@ -4493,18 +4544,18 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, Is Petersen's graph 3-colorable:: sage: P = graphs.PetersenGraph() - sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False + sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False # needs sage.numerical.mip True An odd cycle admits a homomorphism to a smaller odd cycle, but not to an even cycle:: sage: g = graphs.CycleGraph(9) - sage: g.has_homomorphism_to(graphs.CycleGraph(5)) is not False + sage: g.has_homomorphism_to(graphs.CycleGraph(5)) is not False # needs sage.numerical.mip True - sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False + sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False # needs sage.numerical.mip True - sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False + sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False # needs sage.numerical.mip False """ self._scream_if_not_simple() @@ -4596,7 +4647,7 @@ def fractional_clique_number(self, solver='PPL', verbose=0, The fractional clique number of a `C_7` is `7/3`:: sage: g = graphs.CycleGraph(7) - sage: g.fractional_clique_number() + sage: g.fractional_clique_number() # needs sage.numerical.mip 7/3 """ return self.fractional_chromatic_number(solver=solver, verbose=verbose, @@ -4640,35 +4691,57 @@ def maximum_average_degree(self, value_only=True, solver=None, verbose=0): In any graph, the `Mad` is always larger than the average degree:: sage: g = graphs.RandomGNP(20,.3) - sage: mad_g = g.maximum_average_degree() - sage: g.average_degree() <= mad_g + sage: mad_g = g.maximum_average_degree() # needs sage.numerical.mip + sage: g.average_degree() <= mad_g # needs sage.numerical.mip True Unlike the average degree, the `Mad` of the disjoint union of two graphs is the maximum of the `Mad` of each graphs:: sage: h = graphs.RandomGNP(20,.3) - sage: mad_h = h.maximum_average_degree() - sage: (g+h).maximum_average_degree() == max(mad_g, mad_h) + sage: mad_h = h.maximum_average_degree() # needs sage.numerical.mip + sage: (g+h).maximum_average_degree() == max(mad_g, mad_h) # needs sage.numerical.mip True The subgraph of a regular graph realizing the maximum average degree is always the whole graph :: sage: g = graphs.CompleteGraph(5) - sage: mad_g = g.maximum_average_degree(value_only=False) - sage: g.is_isomorphic(mad_g) + sage: mad_g = g.maximum_average_degree(value_only=False) # needs sage.numerical.mip + sage: g.is_isomorphic(mad_g) # needs sage.numerical.mip True This also works for complete bipartite graphs :: sage: g = graphs.CompleteBipartiteGraph(3,4) - sage: mad_g = g.maximum_average_degree(value_only=False) - sage: g.is_isomorphic(mad_g) + sage: mad_g = g.maximum_average_degree(value_only=False) # needs sage.numerical.mip + sage: g.is_isomorphic(mad_g) # needs sage.numerical.mip True + + TESTS: + + Check corner cases:: + + sage: # needs sage.numerical.mip + sage: Graph().maximum_average_degree(value_only=True) + 0 + sage: Graph().maximum_average_degree(value_only=False) + Graph on 0 vertices + sage: Graph(1).maximum_average_degree(value_only=True) + 0 + sage: Graph(1).maximum_average_degree(value_only=False) + Graph on 1 vertex + sage: Graph(2).maximum_average_degree(value_only=True) + 0 + sage: Graph(2).maximum_average_degree(value_only=False) + Graph on 1 vertex """ self._scream_if_not_simple() g = self + if not g: + return ZZ.zero() if value_only else g.parent()() + elif not g.size(): + return ZZ.zero() if value_only else g.parent()([[next(g.vertex_iterator())], []]) from sage.numerical.mip import MixedIntegerLinearProgram p = MixedIntegerLinearProgram(maximization=True, solver=solver) @@ -4753,7 +4826,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0, sage: g = graphs.CompleteBipartiteGraph(3,3) sage: g.delete_edge(1,4) - sage: g.independent_set_of_representatives([[0,1,2],[3,4,5]]) + sage: g.independent_set_of_representatives([[0,1,2],[3,4,5]]) # needs sage.numerical.mip [1, 4] The Petersen Graph is 3-colorable, which can be expressed as an @@ -4762,6 +4835,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0, partition of the set of vertices the family defined by the three copies of each vertex. The ISR of such a family defines a 3-coloring:: + sage: # needs sage.numerical.mip sage: g = 3 * graphs.PetersenGraph() sage: n = g.order() / 3 sage: f = [[i, i + n, i + 2*n] for i in range(n)] @@ -4882,6 +4956,7 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): Trying to find a minor isomorphic to `K_4` in the `4\times 4` grid:: + sage: # needs sage.numerical.mip sage: g = graphs.GridGraph([4,4]) sage: h = graphs.CompleteGraph(4) sage: L = g.minor(h) @@ -4894,11 +4969,11 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): as it has a `K_5` minor:: sage: g = graphs.PetersenGraph() - sage: K5_minor = g.minor(graphs.CompleteGraph(5)) # long time + sage: K5_minor = g.minor(graphs.CompleteGraph(5)) # long time # needs sage.numerical.mip And even a `K_{3,3}` minor:: - sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3)) # long time + sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3)) # long time, needs sage.numerical.mip (It is much faster to use the linear-time test of planarity in this situation, though.) @@ -4910,7 +4985,7 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): sage: g = g.subgraph(edges = g.min_spanning_tree()) sage: g.is_tree() True - sage: L = g.minor(graphs.CompleteGraph(3)) + sage: L = g.minor(graphs.CompleteGraph(3)) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: This graph has no minor isomorphic to H ! @@ -5193,7 +5268,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, [1, 1, 1] sage: G.eccentricity(algorithm = 'Floyd-Warshall-Cython') [1, 1, 1] - sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_NetworkX') + sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_NetworkX') # needs networkx [2, 1, 2] sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_Boost') [2, 1, 2] @@ -5728,7 +5803,7 @@ def distance_graph(self, dist): sage: G = graphs.CompleteGraph(3) sage: H = G.cartesian_product(graphs.CompleteGraph(2)) sage: K = H.distance_graph(2) - sage: K.am() + sage: K.am() # needs sage.modules [0 0 0 1 0 1] [0 0 1 0 1 0] [0 1 0 0 0 1] @@ -5756,8 +5831,8 @@ def distance_graph(self, dist): that sum to the matrix of all ones:: sage: P = graphs.PathGraph(20) - sage: all_ones = sum([P.distance_graph(i).am() for i in range(20)]) - sage: all_ones == matrix(ZZ, 20, 20, [1]*400) + sage: all_ones = sum([P.distance_graph(i).am() for i in range(20)]) # needs sage.modules + sage: all_ones == matrix(ZZ, 20, 20, [1]*400) # needs sage.modules True Four-bit strings differing in one bit is the same as @@ -5771,11 +5846,12 @@ def distance_graph(self, dist): The graph of eight-bit strings, adjacent if different in an odd number of bits:: - sage: G = graphs.CubeGraph(8) # long time - sage: H = G.distance_graph([1,3,5,7]) # long time - sage: degrees = [0]*sum([binomial(8,j) for j in [1,3,5,7]]) # long time - sage: degrees.append(2^8) # long time - sage: degrees == H.degree_histogram() # long time + sage: # long time + sage: G = graphs.CubeGraph(8) + sage: H = G.distance_graph([1,3,5,7]) + sage: degrees = [0]*sum([binomial(8,j) for j in [1,3,5,7]]) + sage: degrees.append(2^8) + sage: degrees == H.degree_histogram() True An example of using ``Infinity`` as the distance in a graph that is not @@ -5784,7 +5860,7 @@ def distance_graph(self, dist): sage: G = graphs.CompleteGraph(3) sage: H = G.disjoint_union(graphs.CompleteGraph(2)) sage: L = H.distance_graph(Infinity) - sage: L.am() + sage: L.am() # needs sage.modules [0 0 0 1 1] [0 0 0 1 1] [0 0 0 1 1] @@ -5908,13 +5984,13 @@ def to_directed(self, data_structure=None, sparse=None): :trac:`22424`:: - sage: G1=graphs.RandomGNP(5,0.5) - sage: gp1 = G1.graphplot(save_pos=True) - sage: G2=G1.to_directed() + sage: G1 = graphs.RandomGNP(5,0.5) + sage: gp1 = G1.graphplot(save_pos=True) # needs sage.plot + sage: G2 = G1.to_directed() sage: G2.delete_vertex(0) sage: G2.add_vertex(5) - sage: gp2 = G2.graphplot() - sage: gp1 = G1.graphplot() + sage: gp2 = G2.graphplot() # needs sage.plot + sage: gp1 = G1.graphplot() # needs sage.plot Vertex labels will be retained (:trac:`14708`):: @@ -6073,14 +6149,14 @@ def seidel_adjacency_matrix(self, vertices=None, *, base_ring=None, **kwds): sage: G = graphs.CycleGraph(5) sage: G = G.disjoint_union(graphs.CompleteGraph(1)) - sage: G.seidel_adjacency_matrix().minpoly() + sage: G.seidel_adjacency_matrix().minpoly() # needs sage.libs.pari sage.modules x^2 - 5 Selecting the base ring:: - sage: G.seidel_adjacency_matrix()[0, 0].parent() + sage: G.seidel_adjacency_matrix()[0, 0].parent() # needs sage.modules Integer Ring - sage: G.seidel_adjacency_matrix(base_ring=RDF)[0, 0].parent() + sage: G.seidel_adjacency_matrix(base_ring=RDF)[0, 0].parent() # needs sage.modules Real Double Field """ set_immutable = kwds.pop('immutable', False) @@ -6120,7 +6196,7 @@ def seidel_switching(self, s, inplace=True): sage: G = graphs.CycleGraph(5) sage: G = G.disjoint_union(graphs.CompleteGraph(1)) sage: G.seidel_switching([(0,1),(1,0),(0,0)]) - sage: G.seidel_adjacency_matrix().minpoly() + sage: G.seidel_adjacency_matrix().minpoly() # needs sage.libs.pari sage.modules x^2 - 5 sage: G.is_connected() True @@ -6151,13 +6227,14 @@ def twograph(self): EXAMPLES:: - sage: p=graphs.PetersenGraph() - sage: p.twograph() + sage: p = graphs.PetersenGraph() + sage: p.twograph() # needs sage.modules Incidence structure with 10 points and 60 blocks sage: p=graphs.chang_graphs() sage: T8 = graphs.CompleteGraph(8).line_graph() - sage: C = T8.seidel_switching([(0,1,None),(2,3,None),(4,5,None),(6,7,None)],inplace=False) - sage: T8.twograph() == C.twograph() + sage: C = T8.seidel_switching([(0,1,None), (2,3,None), (4,5,None), (6,7,None)], + ....: inplace=False) + sage: T8.twograph() == C.twograph() # needs sage.modules True sage: T8.is_isomorphic(C) False @@ -6165,8 +6242,8 @@ def twograph(self): TESTS:: sage: from sage.combinat.designs.twographs import TwoGraph - sage: p=graphs.PetersenGraph().twograph() - sage: TwoGraph(p, check=True) + sage: p = graphs.PetersenGraph().twograph() # needs sage.modules + sage: TwoGraph(p, check=True) # needs sage.modules Incidence structure with 10 points and 60 blocks .. SEEALSO:: @@ -6300,19 +6377,19 @@ def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose Petersen's graph has a topological `K_4`-minor:: sage: g = graphs.PetersenGraph() - sage: g.topological_minor(graphs.CompleteGraph(4)) + sage: g.topological_minor(graphs.CompleteGraph(4)) # needs sage.numerical.mip Subgraph of (Petersen graph): Graph on ... And a topological `K_{3,3}`-minor:: - sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3)) + sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3)) # needs sage.numerical.mip Subgraph of (Petersen graph): Graph on ... And of course, a tree has no topological `C_3`-minor:: sage: g = graphs.RandomGNP(15,.3) - sage: g = g.subgraph(edges = g.min_spanning_tree()) - sage: g.topological_minor(graphs.CycleGraph(3)) + sage: g = g.subgraph(edges=g.min_spanning_tree()) + sage: g.topological_minor(graphs.CycleGraph(3)) # needs sage.numerical.mip False """ self._scream_if_not_simple() @@ -6504,7 +6581,7 @@ def cliques_maximal(self, algorithm="native"): [2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10], [5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]] sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2, 2]) + sage: G.show(figsize=[2, 2]) # needs sage.plot sage: G.cliques_maximal() [[0, 1, 2], [0, 1, 3]] sage: C = graphs.PetersenGraph() @@ -6518,9 +6595,9 @@ def cliques_maximal(self, algorithm="native"): Comparing the two implementations:: sage: g = graphs.RandomGNP(20,.7) - sage: s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX"))) + sage: s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX"))) # needs networkx sage: s2 = Set(map(Set, g.cliques_maximal(algorithm="native"))) - sage: s1 == s2 + sage: s1 == s2 # needs networkx True """ if algorithm == "native": @@ -6679,7 +6756,7 @@ def clique_number(self, algorithm="Cliquer", cliques=None, solver=None, verbose= sage: C.clique_number() 4 sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) + sage: G.show(figsize=[2,2]) # needs sage.plot sage: G.clique_number() 3 @@ -6690,23 +6767,25 @@ def clique_number(self, algorithm="Cliquer", cliques=None, solver=None, verbose= A non-empty graph without edges has a clique number of 1:: - sage: all((i*graphs.CompleteGraph(1)).clique_number() == 1 for i in range(1,15)) + sage: all((i*graphs.CompleteGraph(1)).clique_number() == 1 + ....: for i in range(1,15)) True A complete multipartite graph with k parts has clique number k:: - sage: all((i*graphs.CompleteMultipartiteGraph(i*[5])).clique_number() == i for i in range(1,6)) + sage: all((i*graphs.CompleteMultipartiteGraph(i*[5])).clique_number() == i + ....: for i in range(1,6)) True TESTS:: sage: g = graphs.PetersenGraph() - sage: g.clique_number(algorithm="MILP") + sage: g.clique_number(algorithm="MILP") # needs sage.numerical.mip 2 - sage: for i in range(10): # optional - mcqd - ....: g = graphs.RandomGNP(15,.5) # optional - mcqd - ....: if g.clique_number() != g.clique_number(algorithm="mcqd"): # optional - mcqd - ....: print("This is dead wrong !") # optional - mcqd + sage: for i in range(10): # optional - mcqd # needs sage.numerical.mip + ....: g = graphs.RandomGNP(15,.5) + ....: if g.clique_number() != g.clique_number(algorithm="mcqd"): + ....: print("This is dead wrong !") """ self._scream_if_not_simple(allow_loops=False) if algorithm == "Cliquer": @@ -6746,25 +6825,38 @@ def cliques_number_of(self, vertices=None, cliques=None): EXAMPLES:: sage: C = Graph('DJ{') - sage: C.cliques_number_of() + sage: C.cliques_number_of() # needs networkx {0: 1, 1: 1, 2: 1, 3: 1, 4: 2} sage: E = C.cliques_maximal() sage: E [[0, 4], [1, 2, 3, 4]] - sage: C.cliques_number_of(cliques=E) + sage: C.cliques_number_of(cliques=E) # needs networkx {0: 1, 1: 1, 2: 1, 3: 1, 4: 2} sage: F = graphs.Grid2dGraph(2,3) - sage: F.cliques_number_of() + sage: F.cliques_number_of() # needs networkx {(0, 0): 2, (0, 1): 3, (0, 2): 2, (1, 0): 2, (1, 1): 3, (1, 2): 2} - sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)]) + sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)]) # needs networkx {(0, 1): 3, (1, 2): 2} + sage: F.cliques_number_of(vertices=(0, 1)) + 3 sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) - sage: G.cliques_number_of() + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_number_of() # needs networkx {0: 2, 1: 2, 2: 1, 3: 1} """ - import networkx - return networkx.number_of_cliques(self.networkx_graph(), vertices, cliques) + if cliques is None: + cliques = self.cliques_maximal() + + if vertices in self: # single vertex + return sum(1 for c in cliques if vertices in c) + + from collections import Counter + count = Counter() + + for c in cliques: + count.update(c) + + return {v : count[v] for v in vertices or self} @doc_index("Clique-related methods") def cliques_get_max_clique_graph(self): @@ -6784,14 +6876,14 @@ def cliques_get_max_clique_graph(self): EXAMPLES:: - sage: (graphs.ChvatalGraph()).cliques_get_max_clique_graph() + sage: MCG = graphs.ChvatalGraph().cliques_get_max_clique_graph(); MCG # needs networkx Graph on 24 vertices - sage: ((graphs.ChvatalGraph()).cliques_get_max_clique_graph()).show(figsize=[2,2], vertex_size=20, vertex_labels=False) + sage: MCG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # needs networkx sage.plot sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) - sage: G.cliques_get_max_clique_graph() + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_get_max_clique_graph() # needs networkx Graph on 2 vertices - sage: (G.cliques_get_max_clique_graph()).show(figsize=[2,2]) + sage: G.cliques_get_max_clique_graph().show(figsize=[2,2]) # needs networkx sage.plot """ import networkx return Graph(networkx.make_max_clique_graph(self.networkx_graph(), create_using=networkx.MultiGraph()), @@ -6812,21 +6904,20 @@ def cliques_get_clique_bipartite(self, **kwds): EXAMPLES:: - sage: (graphs.ChvatalGraph()).cliques_get_clique_bipartite() + sage: CBG = graphs.ChvatalGraph().cliques_get_clique_bipartite(); CBG # needs networkx Bipartite graph on 36 vertices - sage: ((graphs.ChvatalGraph()).cliques_get_clique_bipartite()).show(figsize=[2,2], vertex_size=20, vertex_labels=False) + sage: CBG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # needs networkx sage.plot sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) - sage: G.cliques_get_clique_bipartite() + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_get_clique_bipartite() # needs networkx Bipartite graph on 6 vertices - sage: (G.cliques_get_clique_bipartite()).show(figsize=[2,2]) + sage: G.cliques_get_clique_bipartite().show(figsize=[2,2]) # needs networkx sage.plot """ from .bipartite_graph import BipartiteGraph import networkx return BipartiteGraph(networkx.make_clique_bipartite(self.networkx_graph(), **kwds)) @doc_index("Algorithmically hard stuff") - @rename_keyword(deprecation=32238, verbosity='verbose') def independent_set(self, algorithm="Cliquer", value_only=False, reduction_rules=True, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" @@ -6902,7 +6993,7 @@ def independent_set(self, algorithm="Cliquer", value_only=False, reduction_rules As a linear program:: sage: C = graphs.PetersenGraph() - sage: len(C.independent_set(algorithm="MILP")) + sage: len(C.independent_set(algorithm="MILP")) # needs sage.numerical.mip 4 .. PLOT:: @@ -6921,7 +7012,6 @@ def independent_set(self, algorithm="Cliquer", value_only=False, reduction_rules return [u for u in self if u not in my_cover] @doc_index("Algorithmically hard stuff") - @rename_keyword(deprecation=32238, verbosity='verbose') def vertex_cover(self, algorithm="Cliquer", value_only=False, reduction_rules=True, solver=None, verbose=0, *, integrality_tolerance=1e-3): @@ -7001,9 +7091,9 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, The two algorithms should return the same result:: sage: g = graphs.RandomGNP(10, .5) - sage: vc1 = g.vertex_cover(algorithm="MILP") + sage: vc1 = g.vertex_cover(algorithm="MILP") # needs sage.numerical.mip sage: vc2 = g.vertex_cover(algorithm="Cliquer") - sage: len(vc1) == len(vc2) + sage: len(vc1) == len(vc2) # needs sage.numerical.mip True The cardinality of the vertex cover is unchanged when reduction rules @@ -7054,9 +7144,9 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, Issue :trac:`24287` is fixed:: sage: G = Graph([(0,1)]*5 + [(1,2)]*2, multiedges=True) - sage: G.vertex_cover(reduction_rules=True, algorithm='MILP') + sage: G.vertex_cover(reduction_rules=True, algorithm='MILP') # needs sage.numerical.mip [1] - sage: G.vertex_cover(reduction_rules=False) + sage: G.vertex_cover(reduction_rules=False) # needs sage.numerical.mip [1] Issue :trac:`25988` is fixed:: @@ -7389,7 +7479,7 @@ def cliques_vertex_clique_number(self, algorithm="cliquer", vertices=None, .. NOTE:: - Currently only implemented for undirected graphs. Use to_undirected + Currently only implemented for undirected graphs. Use :meth:`to_undirected` to convert a digraph to an undirected graph. INPUT: @@ -7412,18 +7502,19 @@ def cliques_vertex_clique_number(self, algorithm="cliquer", vertices=None, sage: C = Graph('DJ{') sage: C.cliques_vertex_clique_number() {0: 2, 1: 4, 2: 4, 3: 4, 4: 4} - sage: E = C.cliques_maximal() - sage: E + sage: E = C.cliques_maximal(); E [[0, 4], [1, 2, 3, 4]] - sage: C.cliques_vertex_clique_number(cliques=E,algorithm="networkx") + sage: C.cliques_vertex_clique_number(cliques=E, algorithm="networkx") # needs networkx {0: 2, 1: 4, 2: 4, 3: 4, 4: 4} + sage: F = graphs.Grid2dGraph(2,3) - sage: F.cliques_vertex_clique_number(algorithm="networkx") + sage: F.cliques_vertex_clique_number(algorithm="networkx") # needs networkx {(0, 0): 2, (0, 1): 2, (0, 2): 2, (1, 0): 2, (1, 1): 2, (1, 2): 2} sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)]) {(0, 1): 2, (1, 2): 2} + sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) + sage: G.show(figsize=[2,2]) # needs sage.plot sage: G.cliques_vertex_clique_number() {0: 3, 1: 3, 2: 3, 3: 3} """ @@ -7463,23 +7554,39 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): EXAMPLES:: + sage: # needs networkx sage: C = Graph('DJ{') sage: C.cliques_containing_vertex() - {0: [[4, 0]], 1: [[4, 1, 2, 3]], 2: [[4, 1, 2, 3]], 3: [[4, 1, 2, 3]], 4: [[4, 0], [4, 1, 2, 3]]} - sage: E = C.cliques_maximal() - sage: E + {0: [[0, 4]], + 1: [[1, 2, 3, 4]], + 2: [[1, 2, 3, 4]], + 3: [[1, 2, 3, 4]], + 4: [[0, 4], [1, 2, 3, 4]]} + sage: C.cliques_containing_vertex(4) + [[0, 4], [1, 2, 3, 4]] + sage: C.cliques_containing_vertex([0, 1]) + {0: [[0, 4]], 1: [[1, 2, 3, 4]]} + sage: E = C.cliques_maximal(); E [[0, 4], [1, 2, 3, 4]] sage: C.cliques_containing_vertex(cliques=E) - {0: [[0, 4]], 1: [[1, 2, 3, 4]], 2: [[1, 2, 3, 4]], 3: [[1, 2, 3, 4]], 4: [[0, 4], [1, 2, 3, 4]]} + {0: [[0, 4]], + 1: [[1, 2, 3, 4]], + 2: [[1, 2, 3, 4]], + 3: [[1, 2, 3, 4]], + 4: [[0, 4], [1, 2, 3, 4]]} sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) - sage: G.cliques_containing_vertex() - {0: [[0, 1, 2], [0, 1, 3]], 1: [[0, 1, 2], [0, 1, 3]], 2: [[0, 1, 2]], 3: [[0, 1, 3]]} + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_containing_vertex() # needs networkx + {0: [[0, 1, 2], [0, 1, 3]], + 1: [[0, 1, 2], [0, 1, 3]], + 2: [[0, 1, 2]], + 3: [[0, 1, 3]]} Since each clique of a 2 dimensional grid corresponds to an edge, the number of cliques in which a vertex is involved equals its degree:: + sage: # needs networkx sage: F = graphs.Grid2dGraph(2,3) sage: d = F.cliques_containing_vertex() sage: all(F.degree(u) == len(cliques) for u,cliques in d.items()) @@ -7490,8 +7597,20 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): sage: sorted(sorted(x for x in L) for L in d[(0, 1)]) [[(0, 0), (0, 1)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]] """ - import networkx - return networkx.cliques_containing_node(self.networkx_graph(), vertices, cliques) + if cliques is None: + cliques = self.cliques_maximal() + + if vertices in self: # single vertex + return [c for c in cliques if vertices in c] + + from collections import defaultdict + d = defaultdict(list) + + for c in cliques: + for v in c: + d[v].append(c) + + return {v : d[v] for v in vertices or self} @doc_index("Clique-related methods") def clique_complex(self): @@ -7634,20 +7753,23 @@ def cores(self, k=None, with_labels=False): [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] sage: (graphs.FruchtGraph()).cores(with_labels=True) {0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 3, 11: 3} + + sage: # needs sage.modules sage: set_random_seed(0) sage: a = random_matrix(ZZ, 20, x=2, sparse=True, density=.1) sage: b = Graph(20) sage: b.add_edges(a.nonzero_positions(), loops=False) sage: cores = b.cores(with_labels=True); cores - {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3} - sage: [v for v,c in cores.items() if c >= 2] # the vertices in the 2-core + {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, + 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3} + sage: [v for v,c in cores.items() if c >= 2] # the vertices in the 2-core [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] Checking the 2-core of a random lobster is indeed the empty set:: - sage: g = graphs.RandomLobster(20, .5, .5) - sage: ordering, core = g.cores(2) - sage: len(core) == 0 + sage: g = graphs.RandomLobster(20, .5, .5) # needs networkx + sage: ordering, core = g.cores(2) # needs networkx + sage: len(core) == 0 # needs networkx True Checking the cores of a bull graph:: @@ -8045,22 +8167,22 @@ def is_circumscribable(self, solver="ppl", verbose=0): EXAMPLES:: sage: C = graphs.CubeGraph(3) - sage: C.is_circumscribable() + sage: C.is_circumscribable() # needs sage.numerical.mip True sage: O = graphs.OctahedralGraph() - sage: O.is_circumscribable() + sage: O.is_circumscribable() # needs sage.numerical.mip True - sage: TT = polytopes.truncated_tetrahedron().graph() - sage: TT.is_circumscribable() + sage: TT = polytopes.truncated_tetrahedron().graph() # needs sage.geometry.polyhedron + sage: TT.is_circumscribable() # needs sage.geometry.polyhedron sage.numerical.mip False Stellating in a face of the octahedral graph is not circumscribable:: sage: f = set(flatten(choice(O.faces()))) sage: O.add_edges([[6, i] for i in f]) - sage: O.is_circumscribable() + sage: O.is_circumscribable() # needs sage.numerical.mip False .. SEEALSO:: @@ -8167,7 +8289,7 @@ def is_inscribable(self, solver="ppl", verbose=0): True sage: C = graphs.CubeGraph(3) - sage: C.is_inscribable() + sage: C.is_inscribable() # needs sage.numerical.mip True Cutting off a vertex from the cube yields an uninscribable graph:: @@ -8178,7 +8300,7 @@ def is_inscribable(self, solver="ppl", verbose=0): sage: C.add_edges(Combinations(triangle, 2)) sage: C.add_edges(zip(triangle, C.neighbors(v))) sage: C.delete_vertex(v) - sage: C.is_inscribable() + sage: C.is_inscribable() # needs sage.numerical.mip False Breaking a face of the cube yields an uninscribable graph:: @@ -8186,7 +8308,7 @@ def is_inscribable(self, solver="ppl", verbose=0): sage: C = graphs.CubeGraph(3) sage: face = choice(C.faces()) sage: C.add_edge([face[0][0], face[2][0]]) - sage: C.is_inscribable() + sage: C.is_inscribable() # needs sage.numerical.mip False @@ -8472,22 +8594,24 @@ def two_factor_petersen(self, solver=None, verbose=0, *, integrality_tolerance=1 edge-partitionned into `2`-regular graphs:: sage: g = graphs.CompleteGraph(7) - sage: classes = g.two_factor_petersen() - sage: for c in classes: + sage: classes = g.two_factor_petersen() # needs sage.numerical.mip + sage: for c in classes: # needs sage.numerical.mip ....: gg = Graph() ....: gg.add_edges(c) ....: print(max(gg.degree())<=2) True True True - sage: Set(set(classes[0]) | set(classes[1]) | set(classes[2])).cardinality() == g.size() + sage: Set(set(classes[0]) # needs sage.numerical.mip + ....: | set(classes[1]) + ....: | set(classes[2])).cardinality() == g.size() True :: sage: g = graphs.CirculantGraph(24, [7, 11]) - sage: cl = g.two_factor_petersen() - sage: g.plot(edge_colors={'black':cl[0], 'red':cl[1]}) + sage: cl = g.two_factor_petersen() # needs sage.numerical.mip + sage: g.plot(edge_colors={'black':cl[0], 'red':cl[1]}) # needs sage.numerical.mip sage.plot Graphics object consisting of 73 graphics primitives """ @@ -8559,30 +8683,30 @@ def kirchhoff_symanzik_polynomial(self, name='t'): For the cycle of length 5:: sage: G = graphs.CycleGraph(5) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0 + t1 + t2 + t3 + t4 One can use another letter for variables:: - sage: G.kirchhoff_symanzik_polynomial(name='u') + sage: G.kirchhoff_symanzik_polynomial(name='u') # needs networkx sage.modules u0 + u1 + u2 + u3 + u4 For the 'coffee bean' graph:: sage: G = Graph([(0,1,'a'),(0,1,'b'),(0,1,'c')], multiedges=True) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0*t1 + t0*t2 + t1*t2 For the 'parachute' graph:: sage: G = Graph([(0,2,'a'),(0,2,'b'),(0,1,'c'),(1,2,'d')], multiedges=True) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0*t1 + t0*t2 + t1*t2 + t1*t3 + t2*t3 For the complete graph with 4 vertices:: sage: G = graphs.CompleteGraph(4) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0*t1*t3 + t0*t2*t3 + t1*t2*t3 + t0*t1*t4 + t0*t2*t4 + t1*t2*t4 + t1*t3*t4 + t2*t3*t4 + t0*t1*t5 + t0*t2*t5 + t1*t2*t5 + t0*t3*t5 + t2*t3*t5 + t0*t4*t5 + t1*t4*t5 + t3*t4*t5 @@ -8632,44 +8756,44 @@ def magnitude_function(self): EXAMPLES:: sage: g = Graph({1:[], 2:[]}) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 2 sage: g = graphs.CycleGraph(4) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 4/(q^2 + 2*q + 1) sage: g = graphs.CycleGraph(5) - sage: m = g.magnitude_function(); m + sage: m = g.magnitude_function(); m # needs sage.modules 5/(2*q^2 + 2*q + 1) One can expand the magnitude as a power series in `q` as follows:: sage: q = QQ[['q']].gen() - sage: m(q) + sage: m(q) # needs sage.modules 5 - 10*q + 10*q^2 - 20*q^4 + 40*q^5 - 40*q^6 + ... One can also use the substitution `q = exp(-t)` to obtain the magnitude function as a function of `t`:: sage: g = graphs.CycleGraph(6) - sage: m = g.magnitude_function() - sage: t = var('t') # optional - sage.symbolic - sage: m(exp(-t)) # optional - sage.symbolic + sage: m = g.magnitude_function() # needs sage.modules + sage: t = var('t') # needs sage.modules sage.symbolic + sage: m(exp(-t)) # needs sage.modules sage.symbolic 6/(2*e^(-t) + 2*e^(-2*t) + e^(-3*t) + 1) TESTS:: sage: g = Graph() - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 0 sage: g = Graph({1:[]}) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 1 sage: g = graphs.PathGraph(4) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules (-2*q + 4)/(q + 1) REFERENCES: @@ -8723,20 +8847,20 @@ def ihara_zeta_function_inverse(self): EXAMPLES:: sage: G = graphs.CompleteGraph(4) - sage: factor(G.ihara_zeta_function_inverse()) + sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules (2*t - 1) * (t + 1)^2 * (t - 1)^3 * (2*t^2 + t + 1)^3 sage: G = graphs.CompleteGraph(5) - sage: factor(G.ihara_zeta_function_inverse()) + sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules (-1) * (3*t - 1) * (t + 1)^5 * (t - 1)^6 * (3*t^2 + t + 1)^4 sage: G = graphs.PetersenGraph() - sage: factor(G.ihara_zeta_function_inverse()) + sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules (-1) * (2*t - 1) * (t + 1)^5 * (t - 1)^6 * (2*t^2 + 2*t + 1)^4 * (2*t^2 - t + 1)^5 sage: G = graphs.RandomTree(10) - sage: G.ihara_zeta_function_inverse() + sage: G.ihara_zeta_function_inverse() # needs sage.libs.pari sage.modules 1 REFERENCES: @@ -8828,7 +8952,7 @@ def perfect_matchings(self, labels=False): if not self: yield [] return - if self.order() % 2 or any(len(cc) % 2 for cc in self.connected_components()): + if self.order() % 2 or any(len(cc) % 2 for cc in self.connected_components(sort=False)): return def rec(G): @@ -8919,11 +9043,11 @@ def has_perfect_matching(self, algorithm="Edmonds", solver=None, verbose=0, EXAMPLES:: - sage: graphs.PetersenGraph().has_perfect_matching() + sage: graphs.PetersenGraph().has_perfect_matching() # needs networkx True - sage: graphs.WheelGraph(6).has_perfect_matching() + sage: graphs.WheelGraph(6).has_perfect_matching() # needs networkx True - sage: graphs.WheelGraph(5).has_perfect_matching() + sage: graphs.WheelGraph(5).has_perfect_matching() # needs networkx False sage: graphs.PetersenGraph().has_perfect_matching(algorithm="LP_matching") True @@ -8941,14 +9065,16 @@ def has_perfect_matching(self, algorithm="Edmonds", solver=None, verbose=0, TESTS:: sage: G = graphs.EmptyGraph() - sage: all(G.has_perfect_matching(algorithm=algo) for algo in ['Edmonds', 'LP_matching', 'LP']) + sage: all(G.has_perfect_matching(algorithm=algo) # needs networkx + ....: for algo in ['Edmonds', 'LP_matching', 'LP']) True Be careful with isolated vertices:: sage: G = graphs.PetersenGraph() sage: G.add_vertex(11) - sage: any(G.has_perfect_matching(algorithm=algo) for algo in ['Edmonds', 'LP_matching', 'LP']) + sage: any(G.has_perfect_matching(algorithm=algo) # needs networkx + ....: for algo in ['Edmonds', 'LP_matching', 'LP']) False """ if self.order() % 2: @@ -9006,6 +9132,7 @@ def effective_resistance(self, i, j, *, base_ring=None): Effective resistances in a straight linear 2-tree on 6 vertices :: + sage: # needs sage.modules sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) sage: G.effective_resistance(0,1) 34/55 @@ -9018,6 +9145,7 @@ def effective_resistance(self, i, j, *, base_ring=None): Effective resistances in a fan on 6 vertices :: + sage: # needs sage.modules sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) sage: H.effective_resistance(1,5) 6/5 @@ -9028,9 +9156,9 @@ def effective_resistance(self, i, j, *, base_ring=None): Using a different base ring:: - sage: H.effective_resistance(1, 5, base_ring=RDF) # abs tol 1e-14 + sage: H.effective_resistance(1, 5, base_ring=RDF) # abs tol 1e-14 # needs sage.modules 1.2000000000000000 - sage: H.effective_resistance(1, 1, base_ring=RDF) + sage: H.effective_resistance(1, 1, base_ring=RDF) # needs sage.modules 0.0 .. SEEALSO:: @@ -9046,8 +9174,10 @@ def effective_resistance(self, i, j, *, base_ring=None): TESTS:: + sage: # needs sage.modules sage: G = graphs.CompleteGraph(4) - sage: all(G.effective_resistance(u, v) == 1/2 for u,v in G.edge_iterator(labels=False)) + sage: all(G.effective_resistance(u, v) == 1/2 + ....: for u,v in G.edge_iterator(labels=False)) True sage: Graph(1).effective_resistance(0,0) 0 @@ -9082,7 +9212,7 @@ def effective_resistance(self, i, j, *, base_ring=None): self._scream_if_not_simple() if not self.is_connected(): - connected_i = self.connected_component_containing_vertex(i) + connected_i = self.connected_component_containing_vertex(i, sort=False) if j in connected_i: component = self.subgraph(connected_i) return component.effective_resistance(i, j) @@ -9139,7 +9269,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, only non-adjacent vertex pairs :: sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G.effective_resistance_matrix() + sage: G.effective_resistance_matrix() # needs sage.modules [ 0 0 0 49/55 59/55 15/11] [ 0 0 0 0 9/11 59/55] [ 0 0 0 0 0 49/55] @@ -9150,7 +9280,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, The same effective resistance matrix, this time including adjacent vertices :: - sage: G.effective_resistance_matrix(nonedgesonly=False) + sage: G.effective_resistance_matrix(nonedgesonly=False) # needs sage.modules [ 0 34/55 34/55 49/55 59/55 15/11] [34/55 0 26/55 31/55 9/11 59/55] [34/55 26/55 0 5/11 31/55 49/55] @@ -9162,7 +9292,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, vertices counting only non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.effective_resistance_matrix() + sage: H.effective_resistance_matrix() # needs sage.modules [ 0 0 0 0 0 0 0] [ 0 0 0 49/55 56/55 6/5 89/55] [ 0 0 0 0 4/5 56/55 81/55] @@ -9173,7 +9303,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, A different base ring:: - sage: H.effective_resistance_matrix(base_ring=RDF)[0, 0].parent() + sage: H.effective_resistance_matrix(base_ring=RDF)[0, 0].parent() # needs sage.modules Real Double Field .. SEEALSO:: @@ -9188,7 +9318,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, TESTS:: - sage: graphs.CompleteGraph(4).effective_resistance_matrix() + sage: graphs.CompleteGraph(4).effective_resistance_matrix() # needs sage.modules [0 0 0 0] [0 0 0 0] [0 0 0 0] @@ -9196,7 +9326,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, sage: G = Graph(multiedges=True, sparse=True) sage: G.add_edges([(0, 1)] * 3) - sage: G.effective_resistance_matrix() + sage: G.effective_resistance_matrix() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is not known to work on graphs with @@ -9204,6 +9334,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, in the meantime if you want to use it please disallow multiedges using allow_multiple_edges(). + sage: # needs sage.modules sage: graphs.CompleteGraph(4).effective_resistance_matrix(nonedgesonly=False) [ 0 1/2 1/2 1/2] [1/2 0 1/2 1/2] @@ -9223,11 +9354,12 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, [0 1 0 0] sage: G = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(2,3),(3,4),(4,5),(5,1)]) sage: r = G.effective_resistance_matrix(nonedgesonly=False)[0,3] - sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) + sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) # needs sage.libs.pari True Ask for an immutable matrix:: + sage: # needs sage.modules sage: G = Graph([(0, 1)]) sage: M = G.effective_resistance_matrix(immutable=False) sage: M.is_immutable() @@ -9293,20 +9425,20 @@ def least_effective_resistance(self, nonedgesonly=True): straight linear 2-tree on 6 vertices:: sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G.least_effective_resistance() + sage: G.least_effective_resistance() # needs sage.modules [(1, 4)] Pairs of (adjacent or non-adjacent) nodes with least effective resistance in a straight linear 2-tree on 6 vertices :: - sage: G.least_effective_resistance(nonedgesonly = False) + sage: G.least_effective_resistance(nonedgesonly=False) # needs sage.modules [(2, 3)] Pairs of non-adjacent nodes with least effective resistance in a fan on 6 vertices counting only non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.least_effective_resistance() + sage: H.least_effective_resistance() # needs sage.modules [(2, 4)] .. SEEALSO:: @@ -9323,6 +9455,7 @@ def least_effective_resistance(self, nonedgesonly=True): TESTS:: + sage: # needs sage.modules sage: graphs.CompleteGraph(4).least_effective_resistance() [] sage: graphs.CompleteGraph(4).least_effective_resistance(nonedgesonly=False) @@ -9388,7 +9521,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, sage: G1 = Graph() sage: G1.add_edges([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G1.common_neighbors_matrix(nonedgesonly = True) + sage: G1.common_neighbors_matrix(nonedgesonly=True) # needs sage.modules [0 0 0 2 1 0] [0 0 0 0 2 1] [0 0 0 0 0 2] @@ -9399,7 +9532,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, We now show the common neighbors matrix which includes adjacent vertices :: - sage: G1.common_neighbors_matrix(nonedgesonly = False) + sage: G1.common_neighbors_matrix(nonedgesonly=False) # needs sage.modules [0 1 1 2 1 0] [1 0 2 1 2 1] [1 2 0 2 1 2] @@ -9411,7 +9544,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.common_neighbors_matrix() + sage: H.common_neighbors_matrix() # needs sage.modules [0 0 0 0 0 0 0] [0 0 0 2 1 1 1] [0 0 0 0 2 1 1] @@ -9422,7 +9555,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, A different base ring:: - sage: H.common_neighbors_matrix(base_ring=RDF) + sage: H.common_neighbors_matrix(base_ring=RDF) # needs sage.modules [0.0 0.0 0.0 0.0 0.0 0.0 0.0] [0.0 0.0 0.0 2.0 1.0 1.0 1.0] [0.0 0.0 0.0 0.0 2.0 1.0 1.0] @@ -9433,8 +9566,8 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, It is an error to input anything other than a simple graph:: - sage: G = Graph([(0,0)],loops=True) - sage: G.common_neighbors_matrix() + sage: G = Graph([(0,0)], loops=True) + sage: G.common_neighbors_matrix() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is not known to work on graphs with loops. @@ -9449,6 +9582,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, TESTS:: + sage: # needs sage.modules sage: G = graphs.CompleteGraph(4) sage: M = G.common_neighbors_matrix() sage: M.is_zero() @@ -9466,6 +9600,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, Asking for an immutable matrix:: + sage: # needs sage.modules sage: G = Graph([(0, 1)]) sage: M = G.common_neighbors_matrix() sage: M.is_immutable() @@ -9511,19 +9646,19 @@ def most_common_neighbors(self, nonedgesonly=True): linear 2-tree :: sage: G1 = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G1.most_common_neighbors() + sage: G1.most_common_neighbors() # needs sage.modules [(0, 3), (1, 4), (2, 5)] If we include non-adjacent pairs :: - sage: G1.most_common_neighbors(nonedgesonly = False) + sage: G1.most_common_neighbors(nonedgesonly=False) # needs sage.modules [(0, 3), (1, 2), (1, 4), (2, 3), (2, 5), (3, 4)] The common neighbors matrix for a fan on 6 vertices counting only non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.most_common_neighbors() + sage: H.most_common_neighbors() # needs sage.modules [(1, 3), (2, 4), (3, 5)] .. SEEALSO:: @@ -9533,7 +9668,8 @@ def most_common_neighbors(self, nonedgesonly=True): TESTS:: - sage: G=graphs.CompleteGraph(4) + sage: # needs sage.modules + sage: G = graphs.CompleteGraph(4) sage: G.most_common_neighbors() [] sage: G.most_common_neighbors(nonedgesonly=False) @@ -9600,18 +9736,18 @@ def arboricity(self, certificate=False): EXAMPLES:: sage: G = graphs.PetersenGraph() - sage: a,F = G.arboricity(True) - sage: a + sage: a, F = G.arboricity(True) # needs sage.modules + sage: a # needs sage.modules 2 - sage: all([f.is_forest() for f in F]) + sage: all([f.is_forest() for f in F]) # needs sage.modules True - sage: len(set.union(*[set(f.edges(sort=False)) for f in F])) == G.size() + sage: len(set.union(*[set(f.edges(sort=False)) for f in F])) == G.size() # needs sage.modules True TESTS:: sage: g = Graph() - sage: g.arboricity(True) + sage: g.arboricity(True) # needs sage.modules (0, []) """ from sage.matroids.constructor import Matroid @@ -9940,13 +10076,15 @@ def bipartite_double(self, extended=False): # Aliases to functions defined in other modules from sage.graphs.weakly_chordal import is_long_hole_free, is_long_antihole_free, is_weakly_chordal from sage.graphs.asteroidal_triples import is_asteroidal_triple_free - from sage.graphs.chrompoly import chromatic_polynomial + chromatic_polynomial = LazyImport('sage.graphs.chrompoly', 'chromatic_polynomial', at_startup=True) from sage.graphs.graph_decompositions.rankwidth import rank_decomposition from sage.graphs.graph_decompositions.tree_decomposition import treewidth from sage.graphs.graph_decompositions.vertex_separation import pathwidth from sage.graphs.graph_decompositions.tree_decomposition import treelength from sage.graphs.graph_decompositions.clique_separators import atoms_and_clique_separators - from sage.graphs.matchpoly import matching_polynomial + from sage.graphs.graph_decompositions.bandwidth import bandwidth + from sage.graphs.graph_decompositions.cutwidth import cutwidth + matching_polynomial = LazyImport('sage.graphs.matchpoly', 'matching_polynomial', at_startup=True) from sage.graphs.cliquer import all_max_clique as cliques_maximum from sage.graphs.cliquer import all_cliques from sage.graphs.spanning_tree import random_spanning_tree @@ -9963,7 +10101,7 @@ def bipartite_double(self, extended=False): from sage.graphs.connectivity import is_triconnected from sage.graphs.comparability import is_comparability from sage.graphs.comparability import is_permutation - from sage.graphs.convexity_properties import geodetic_closure + geodetic_closure = LazyImport('sage.graphs.convexity_properties', 'geodetic_closure', at_startup=True) from sage.graphs.domination import is_dominating from sage.graphs.domination import is_redundant from sage.graphs.domination import private_neighbors diff --git a/src/sage/graphs/graph_coloring.pyx b/src/sage/graphs/graph_coloring.pyx index f5e4ce2ab18..764ee160766 100644 --- a/src/sage/graphs/graph_coloring.pyx +++ b/src/sage/graphs/graph_coloring.pyx @@ -46,7 +46,6 @@ do : :meth:`acyclic_edge_coloring` | Compute an acyclic edge coloring of the current graph - AUTHORS: - Tom Boothby (2008-02-21): Initial version @@ -65,16 +64,81 @@ Methods # **************************************************************************** from copy import copy -from sage.combinat.matrices.dlxcpp import DLXCPP from libcpp.vector cimport vector from libcpp.pair cimport pair -from sage.numerical.mip import MixedIntegerLinearProgram -from sage.numerical.mip import MIPSolverException from sage.graphs.independent_sets import IndependentSets +from sage.misc.lazy_import import LazyImport + +DLXCPP = LazyImport('sage.combinat.matrices.dlxcpp', 'DLXCPP') +MixedIntegerLinearProgram = LazyImport('sage.numerical.mip', 'MixedIntegerLinearProgram') + + +def format_coloring(data, value_only=False, hex_colors=False, vertex_color_dict=False): + r""" + Helper method for vertex and edge coloring methods. + + INPUT: + + - ``data`` -- either a number when ``value_only`` is ``True`` or a list of + color classes + + - ``value_only`` -- boolean (default: ``False``); when set to ``True``, it + simply returns ``data`` + + - ``hex_colors`` -- boolean (default: ``False``); when set to ``False``, + colors are labeled [0, 1, ..., `n - 1`], otherwise the RGB Hex labeling + is used + + - ``vertex_color_dict`` -- boolean (default: ``False``); when set to + ``True``, it returns a dictionary ``{vertex: color}``, otherwise it + returns a dictionary ``{color: [list of vertices]}`` + + EXAMPLES:: + + sage: from sage.graphs.graph_coloring import format_coloring + sage: color_classes = [['a', 'b'], ['c'], ['d']] + sage: format_coloring(color_classes, value_only=True) + [['a', 'b'], ['c'], ['d']] + sage: format_coloring(len(color_classes), value_only=True) + 3 + sage: format_coloring(color_classes, value_only=False) + {0: ['a', 'b'], 1: ['c'], 2: ['d']} + sage: format_coloring(color_classes, value_only=False, hex_colors=True) # needs sage.plot + {'#0000ff': ['d'], '#00ff00': ['c'], '#ff0000': ['a', 'b']} + sage: format_coloring(color_classes, value_only=False, hex_colors=False, vertex_color_dict=True) + {'a': 0, 'b': 0, 'c': 1, 'd': 2} + sage: format_coloring(color_classes, value_only=False, hex_colors=True, # needs sage.plot + ....: vertex_color_dict=True) + {'a': '#ff0000', 'b': '#ff0000', 'c': '#00ff00', 'd': '#0000ff'} + + TESTS:: + + sage: from sage.graphs.graph_coloring import format_coloring + sage: format_coloring([], value_only=True) + [] + sage: format_coloring([], value_only=False, hex_colors=True) # needs sage.plot + {} + sage: format_coloring([], value_only=False, hex_colors=True, # needs sage.plot + ....: vertex_color_dict=True) + {} + sage: format_coloring([], value_only=False, hex_colors=False, vertex_color_dict=True) + {} + """ + if value_only: + return data + if hex_colors: + from sage.plot.colors import rainbow + colors = rainbow(len(data)) + else: + colors = list(range(len(data))) + if vertex_color_dict: + return {u: col for col, C in zip(colors, data) for u in C} + return {col: C for col, C in zip(colors, data) if C} -def all_graph_colorings(G, n, count_only=False, hex_colors=False, vertex_color_dict=False): +def all_graph_colorings(G, n, count_only=False, hex_colors=False, + vertex_color_dict=False, color_classes=False): r""" Compute all `n`-colorings of a graph. @@ -89,7 +153,7 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, vertex_color_d * ``n`` -- a positive integer; the number of colors * ``count_only`` -- boolean (default: ``False``); when set to ``True``, it - returns 1 for each coloring + returns 1 for each coloring and ignores other parameters * ``hex_colors`` -- boolean (default: ``False``); when set to ``False``, colors are labeled [0, 1, ..., `n - 1`], otherwise the RGB Hex labeling @@ -99,6 +163,10 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, vertex_color_d ``True``, it returns a dictionary ``{vertex: color}``, otherwise it returns a dictionary ``{color: [list of vertices]}`` + * ``color_classes`` -- boolean (default: ``False``); when set to ``True``, + the method returns only a list of the color classes and ignores parameters + ``hex_colors`` and ``vertex_color_dict`` + .. WARNING:: This method considers only colorings using exactly `n` colors, even if a @@ -144,7 +212,7 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, vertex_color_d sage: from sage.graphs.graph_coloring import all_graph_colorings sage: G = Graph({0: [1, 2, 3], 1: [2]}) sage: n = 0 - sage: for C in all_graph_colorings(G, 3, hex_colors=True): + sage: for C in all_graph_colorings(G, 3, hex_colors=True): # needs sage.plot ....: parts = [C[k] for k in C] ....: for P in parts: ....: l = len(P) @@ -152,8 +220,8 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, vertex_color_d ....: for j in range(i + 1, l): ....: if G.has_edge(P[i], P[j]): ....: raise RuntimeError("Coloring Failed.") - ....: n+=1 - sage: print("G has %s 3-colorings." % n) + ....: n += 1 + sage: print("G has %s 3-colorings." % n) # needs sage.plot G has 12 3-colorings. TESTS:: @@ -169,27 +237,30 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, vertex_color_d sage: G = Graph({0: [1], 1: [2]}) sage: for c in all_graph_colorings(G, 2, vertex_color_dict=True): ....: print(c) - {0: 0, 1: 1, 2: 0} - {0: 1, 1: 0, 2: 1} - sage: for c in all_graph_colorings(G, 2, hex_colors=True): + {0: 0, 2: 0, 1: 1} + {1: 0, 0: 1, 2: 1} + sage: for c in all_graph_colorings(G, 2, hex_colors=True): # needs sage.plot ....: print(sorted(c.items())) [('#00ffff', [1]), ('#ff0000', [0, 2])] [('#00ffff', [0, 2]), ('#ff0000', [1])] - sage: for c in all_graph_colorings(G, 2, hex_colors=True, vertex_color_dict=True): + sage: for c in all_graph_colorings(G, 2, hex_colors=True, # needs sage.plot + ....: vertex_color_dict=True): ....: print(c) - {0: '#ff0000', 1: '#00ffff', 2: '#ff0000'} - {0: '#00ffff', 1: '#ff0000', 2: '#00ffff'} + {0: '#ff0000', 2: '#ff0000', 1: '#00ffff'} + {1: '#ff0000', 0: '#00ffff', 2: '#00ffff'} sage: for c in all_graph_colorings(G, 2, vertex_color_dict=True): ....: print(c) - {0: 0, 1: 1, 2: 0} - {0: 1, 1: 0, 2: 1} + {0: 0, 2: 0, 1: 1} + {1: 0, 0: 1, 2: 1} sage: for c in all_graph_colorings(G, 2, count_only=True, vertex_color_dict=True): ....: print(c) 1 1 + sage: for c in all_graph_colorings(G, 2, color_classes=True): + ....: print(c) + [[0, 2], [1]] + [[1], [0, 2]] """ - from sage.plot.colors import rainbow - G._scream_if_not_simple(allow_multiple_edges=True) if not n or n > G.order(): @@ -229,48 +300,29 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, vertex_color_d for i in range(n * nE): ones.push_back((k + i, [nV + i])) - cdef list colors = rainbow(n) - cdef dict color_dict = {col: i for i, col in enumerate(colors)} - cdef list ones_second = [ones[i].second for i in range(len(ones))] - cdef dict coloring + cdef list coloring cdef set used_colors try: for a in DLXCPP(ones_second): - coloring = {} + coloring = [[] for _ in range(n)] used_colors = set() if count_only: used_colors = set(colormap[x][1] for x in a if x in colormap) - elif vertex_color_dict: - for x in a: - if x in colormap: - v, c = colormap[x] - used_colors.add(c) - if hex_colors: - coloring[v] = colors[c] - else: - coloring[v] = color_dict[colors[c]] else: for x in a: if x in colormap: v, c = colormap[x] used_colors.add(c) - if hex_colors: - if colors[c] in coloring: - coloring[colors[c]].append(v) - else: - coloring[colors[c]] = [v] - else: - if color_dict[colors[c]] in coloring: - coloring[color_dict[colors[c]]].append(v) - else: - coloring[color_dict[colors[c]]] = [v] + coloring[c].append(v) if len(used_colors) == n: if count_only: yield 1 else: - yield coloring + yield format_coloring(coloring, value_only=color_classes, + hex_colors=hex_colors, + vertex_color_dict=vertex_color_dict) except RuntimeError: raise RuntimeError("too much recursion, Graph coloring failed") @@ -309,11 +361,8 @@ cpdef first_coloring(G, n=0, hex_colors=False): G._scream_if_not_simple(allow_multiple_edges=True) cdef int o = G.order() for m in range(n, o + 1): - for C in all_graph_colorings(G, m, hex_colors=True): - if hex_colors: - return C - else: - return list(C.values()) + for C in all_graph_colorings(G, m, hex_colors=hex_colors, color_classes=not hex_colors): + return C cpdef number_of_n_colorings(G, n): @@ -401,7 +450,7 @@ cpdef chromatic_number(G): # don't waste our time coloring. return m for n in range(m, o + 1): - for C in all_graph_colorings(G, n): + for C in all_graph_colorings(G, n, count_only=True): return n @@ -467,7 +516,7 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, sage: from sage.graphs.graph_coloring import vertex_coloring sage: g = graphs.PetersenGraph() - sage: vertex_coloring(g, value_only=True) + sage: vertex_coloring(g, value_only=True) # needs sage.numerical.mip 3 TESTS: @@ -486,11 +535,10 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, :trac:`33559` is fixed:: sage: G = Graph('MgCgS?_O@IeTHKG??') - sage: len(G.coloring(algorithm='MILP')) + sage: len(G.coloring(algorithm='MILP')) # needs sage.numerical.mip 4 """ g._scream_if_not_simple(allow_multiple_edges=True) - from sage.plot.colors import rainbow cdef list colorings cdef set vertices cdef list deg @@ -507,24 +555,20 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, return 0 elif hex_colors: return dict() - else: - return [] + return [] # - Independent set if not g.size(): if value_only: return 1 - elif hex_colors: - return {rainbow(1)[0]: list(g)} - else: - return [list(g)] + return format_coloring([list(g)], value_only=not hex_colors, + hex_colors=hex_colors) # - Bipartite set if g.is_bipartite(): if value_only: return 2 - elif hex_colors: - return dict(zip(rainbow(2), g.bipartite_sets())) - else: - return g.bipartite_sets() + return format_coloring(g.bipartite_sets(), + value_only=not hex_colors, + hex_colors=hex_colors) # - No need to try any k smaller than the maximum clique in the graph # - No need to try k less than |G|/alpha(G), as each color @@ -552,16 +596,15 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, if not g.order(): if value_only: return True - elif hex_colors: - return {color: [] for color in rainbow(k)} - else: - return [[] for i in range(k)] + return format_coloring([[] for i in range(k)], + value_only=not hex_colors, + hex_colors=hex_colors) # Is the graph connected? # This is not so stupid, as the graph could be disconnected # by the test of degeneracy (as previously). if not g.is_connected(): if value_only: - for component in g.connected_components(): + for component in g.connected_components(sort=False): tmp = vertex_coloring(g.subgraph(component), k=k, value_only=value_only, hex_colors=hex_colors, @@ -571,7 +614,7 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, return False return True colorings = [] - for component in g.connected_components(): + for component in g.connected_components(sort=False): tmp = vertex_coloring(g.subgraph(component), k=k, value_only=value_only, hex_colors=False, @@ -584,10 +627,9 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, for color in range(k): for component in colorings: value[color].extend(component[color]) - if hex_colors: - return dict(zip(rainbow(k), value)) - else: - return value + + return format_coloring(value, value_only=not hex_colors, + hex_colors=hex_colors) # Degeneracy # Vertices whose degree is less than k are of no importance in @@ -622,10 +664,9 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, classe.append(deg[-1]) deg.pop(-1) break - if hex_colors: - return dict(zip(rainbow(k), value)) - else: - return value + + return format_coloring(value, value_only=not hex_colors, + hex_colors=hex_colors) p = MixedIntegerLinearProgram(maximization=True, solver=solver) color = p.new_variable(binary=True) @@ -643,6 +684,7 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, # it, and it can help. p.add_constraint(color[next(g.vertex_iterator()), 0], max=1, min=1) + from sage.numerical.mip import MIPSolverException try: if value_only: p.solve(objective_only=True, log=verbose) @@ -662,10 +704,8 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, classes[i].append(v) break - if hex_colors: - return dict(zip(rainbow(len(classes)), classes)) - else: - return classes + return format_coloring(classes, value_only=not hex_colors, + hex_colors=hex_colors) # Fractional relaxations @@ -737,15 +777,15 @@ def fractional_chromatic_number(G, solver='PPL', verbose=0, The fractional chromatic number of a `C_5` is `5/2`:: sage: g = graphs.CycleGraph(5) - sage: g.fractional_chromatic_number() + sage: g.fractional_chromatic_number() # needs sage.numerical.mip 5/2 TESTS:: sage: G = graphs.RandomGNP(20, .2) - sage: a = G.fractional_chromatic_number(check_components=True) - sage: b = G.fractional_chromatic_number(check_components=False) - sage: a == b + sage: a = G.fractional_chromatic_number(check_components=True) # needs sage.numerical.mip + sage: b = G.fractional_chromatic_number(check_components=False) # needs sage.numerical.mip + sage: a == b # needs sage.numerical.mip True """ G._scream_if_not_simple() @@ -846,7 +886,7 @@ def fractional_chromatic_index(G, solver="PPL", verbose_constraints=False, verbo The fractional chromatic index of a `C_5` is `5/2`:: sage: g = graphs.CycleGraph(5) - sage: g.fractional_chromatic_index() + sage: g.fractional_chromatic_index() # needs sage.numerical.mip 5/2 TESTS: @@ -855,9 +895,9 @@ def fractional_chromatic_index(G, solver="PPL", verbose_constraints=False, verbo solvers:: sage: g = graphs.PetersenGraph() - sage: g.fractional_chromatic_index(solver='GLPK') # known bug (#23798) + sage: g.fractional_chromatic_index(solver='GLPK') # known bug # needs sage.numerical.mip 3.0 - sage: g.fractional_chromatic_index(solver='PPL') + sage: g.fractional_chromatic_index(solver='PPL') # needs sage.numerical.mip 3 """ G._scream_if_not_simple() @@ -987,13 +1027,13 @@ def grundy_coloring(g, k, value_only=True, solver=None, verbose=0, sage: from sage.graphs.graph_coloring import grundy_coloring sage: g = graphs.PathGraph(4) - sage: grundy_coloring(g, 4) + sage: grundy_coloring(g, 4) # needs sage.numerical.mip 3 The Grundy number of the PetersenGraph is equal to 4:: sage: g = graphs.PetersenGraph() - sage: grundy_coloring(g, 5) + sage: grundy_coloring(g, 5) # needs sage.numerical.mip 4 It would have been sufficient to set the value of ``k`` to 4 in @@ -1038,6 +1078,7 @@ def grundy_coloring(g, k, value_only=True, solver=None, verbose=0, # Trying to use as many colors as possible p.set_objective(p.sum(is_used[i] for i in range(k))) + from sage.numerical.mip import MIPSolverException try: p.solve(log=verbose) except MIPSolverException: @@ -1085,9 +1126,9 @@ def b_coloring(g, k, value_only=True, solver=None, verbose=0, proper coloring where each color class has a b-vertex. In the worst case, after successive applications of the above procedure, one - get a proper coloring that uses a number of colors equal to the the - b-chromatic number of `G` (denoted `\chi_b(G)`): the maximum `k` such that - `G` admits a b-coloring with `k` colors. + get a proper coloring that uses a number of colors equal to the b-chromatic + number of `G` (denoted `\chi_b(G)`): the maximum `k` such that `G` admits a + b-coloring with `k` colors. A useful upper bound for calculating the b-chromatic number is the following. If `G` admits a b-coloring with `k` colors, then there are `k` @@ -1140,13 +1181,13 @@ def b_coloring(g, k, value_only=True, solver=None, verbose=0, sage: from sage.graphs.graph_coloring import b_coloring sage: g = graphs.PathGraph(5) - sage: b_coloring(g, 5) + sage: b_coloring(g, 5) # needs sage.numerical.mip 3 The b-chromatic number of the Petersen Graph is equal to 3:: sage: g = graphs.PetersenGraph() - sage: b_coloring(g, 5) + sage: b_coloring(g, 5) # needs sage.numerical.mip 3 It would have been sufficient to set the value of ``k`` to 4 in this case, @@ -1227,6 +1268,7 @@ def b_coloring(g, k, value_only=True, solver=None, verbose=0, # We want to maximize the number of used colors p.set_objective(p.sum(is_used[i] for i in range(k))) + from sage.numerical.mip import MIPSolverException try: p.solve(log=verbose) except MIPSolverException: @@ -1338,50 +1380,51 @@ def edge_coloring(g, value_only=False, vizing=False, hex_colors=False, solver=No The Petersen graph has chromatic index 4:: - sage: from sage.graphs.graph_coloring import edge_coloring - sage: g = graphs.PetersenGraph() - sage: edge_coloring(g, value_only=True, solver='GLPK') - 4 - sage: color_classes = edge_coloring(g, value_only=False, solver='GLPK') - sage: len(color_classes) - 4 - sage: len(set(frozenset(e) for C in color_classes for e in C)) == g.size() - True - sage: all(g.has_edge(e) for C in color_classes for e in C) - True - sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) - True - sage: color_classes = edge_coloring(g, value_only=False, hex_colors=True, solver='GLPK') - sage: sorted(color_classes.keys()) - ['#00ffff', '#7f00ff', '#7fff00', '#ff0000'] + sage: # needs sage.numerical.mip + sage: from sage.graphs.graph_coloring import edge_coloring + sage: g = graphs.PetersenGraph() + sage: edge_coloring(g, value_only=True, solver='GLPK') + 4 + sage: color_classes = edge_coloring(g, value_only=False, solver='GLPK') + sage: len(color_classes) + 4 + sage: len(set(frozenset(e) for C in color_classes for e in C)) == g.size() + True + sage: all(g.has_edge(e) for C in color_classes for e in C) + True + sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) # needs networkx + True + sage: color_classes = edge_coloring(g, value_only=False, + ....: hex_colors=True, solver='GLPK') + sage: sorted(color_classes.keys()) + ['#00ffff', '#7f00ff', '#7fff00', '#ff0000'] Complete graphs are colored using the linear-time round-robin coloring:: - sage: from sage.graphs.graph_coloring import edge_coloring - sage: len(edge_coloring(graphs.CompleteGraph(20))) - 19 + sage: from sage.graphs.graph_coloring import edge_coloring + sage: len(edge_coloring(graphs.CompleteGraph(20))) # needs sage.numerical.mip + 19 The chromatic index of a non connected graph is the maximum over its connected components:: - sage: g = graphs.CompleteGraph(4) + graphs.CompleteGraph(10) - sage: edge_coloring(g, value_only=True) - 9 + sage: g = graphs.CompleteGraph(4) + graphs.CompleteGraph(10) + sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip + 9 TESTS: Graph without edge:: - sage: g = Graph(2) - sage: edge_coloring(g) - [] - sage: edge_coloring(g, value_only=True) - 0 - sage: edge_coloring(g, hex_colors=True) - {} + sage: g = Graph(2) + sage: edge_coloring(g) # needs sage.numerical.mip + [] + sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip + 0 + sage: edge_coloring(g, hex_colors=True) # needs sage.numerical.mip + {} """ g._scream_if_not_simple() - from sage.plot.colors import rainbow if not g.order() or not g.size(): if value_only: @@ -1458,6 +1501,8 @@ def edge_coloring(g, value_only=False, vizing=False, hex_colors=False, solver=No # We color the edges of the vertex of maximum degree for i, v in enumerate(h.neighbor_iterator(X)): p.add_constraint(color[frozenset((v, X)), i] == 1) + + from sage.numerical.mip import MIPSolverException try: p.solve(objective_only=value_only, log=verbose) except MIPSolverException: @@ -1486,10 +1531,7 @@ def edge_coloring(g, value_only=False, vizing=False, hex_colors=False, solver=No return chi # if needed, builds a dictionary from the color classes adding colors - if hex_colors: - return dict(zip(rainbow(len(classes)), classes)) - else: - return classes + return format_coloring(classes, value_only=not hex_colors, hex_colors=hex_colors) def _vizing_edge_coloring(g): @@ -1498,11 +1540,11 @@ def _vizing_edge_coloring(g): INPUT: - - ``g`` -- a graph. + - ``g`` -- a graph OUTPUT: - - Returns a partition of the edge set into at most `\Delta + 1` matchings. + a partition of the edge set into at most `\Delta + 1` matchings .. SEEALSO:: @@ -1512,7 +1554,7 @@ def _vizing_edge_coloring(g): ALGORITHM: This function's implementation is based on the algorithm described at [MG1992]_ - + EXAMPLES: Coloring the edges of the Petersen Graph:: @@ -1526,7 +1568,7 @@ def _vizing_edge_coloring(g): True sage: all(g.has_edge(e) for C in color_classes for e in C) True - sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) + sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) # needs networkx True Coloring the edges of the Star Graph:: @@ -1643,7 +1685,7 @@ def _vizing_edge_coloring(g): e_colors[frozenset((fan_center, fan[-1]))] = d matchings = dict() - for edge, c in e_colors.items(): + for edge, c in e_colors.items(): matchings[c] = matchings.get(c, []) + [tuple(edge)] classes = list(matchings.values()) @@ -1711,11 +1753,10 @@ def round_robin(n): g.set_edge_label(n - 1, i, i) for j in range(1, (n - 1) // 2 + 1): g.set_edge_label(my_mod(i - j, n - 1), my_mod(i + j, n - 1), i) - return g else: g = round_robin(n + 1) g.delete_vertex(n) - return g + return g def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False, @@ -1794,22 +1835,23 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False, horizontal lines and the set of vertical lines are an admissible partition:: sage: from sage.graphs.graph_coloring import linear_arboricity - sage: g = graphs.Grid2dGraph(4, 4) - sage: g1,g2 = linear_arboricity(g) + sage: g = graphs.Grid2dGraph(4, 4) # needs sage.numerical.mip + sage: g1,g2 = linear_arboricity(g) # needs sage.numerical.mip Each graph is of course a forest:: - sage: g1.is_forest() and g2.is_forest() + sage: g1.is_forest() and g2.is_forest() # needs sage.numerical.mip True Of maximum degree 2:: - sage: max(g1.degree()) <= 2 and max(g2.degree()) <= 2 + sage: max(g1.degree()) <= 2 and max(g2.degree()) <= 2 # needs sage.numerical.mip True Which constitutes a partition of the whole edge set:: - sage: all((g1.has_edge(e) or g2.has_edge(e)) for e in g.edge_iterator(labels=None)) + sage: all((g1.has_edge(e) or g2.has_edge(e)) # needs sage.numerical.mip + ....: for e in g.edge_iterator(labels=None)) True TESTS: @@ -1817,15 +1859,15 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False, Asking for the value of the linear arboricity only (:trac:`24991`):: sage: from sage.graphs.graph_coloring import linear_arboricity - sage: sorted(linear_arboricity(G, value_only=True) for G in graphs(4)) + sage: sorted(linear_arboricity(G, value_only=True) for G in graphs(4)) # needs sage.numerical.mip [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2] Test parameter ``hex_color`` (:trac:`26228`):: sage: from sage.graphs.graph_coloring import linear_arboricity sage: g = graphs.Grid2dGraph(4, 4) - sage: d = linear_arboricity(g, hex_colors=True) - sage: sorted(d) + sage: d = linear_arboricity(g, hex_colors=True) # needs sage.numerical.mip + sage: sorted(d) # needs sage.numerical.mip ['#00ffff', '#ff0000'] """ g._scream_if_not_simple() @@ -1855,8 +1897,6 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False, else: raise ValueError("plus_one must be equal to 0,1, or to None!") - from sage.plot.colors import rainbow - p = MixedIntegerLinearProgram(solver=solver) # c is a boolean value such that c[i,(u,v)] = 1 if and only if (u,v) is @@ -1885,6 +1925,7 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False, # no cycles p.add_constraint(p.sum(r[i, (u, v)] for v in g.neighbor_iterator(u)), max=MAD) + from sage.numerical.mip import MIPSolverException try: p.solve(objective_only=value_only, log=verbose) if value_only: @@ -1921,10 +1962,7 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False, if c[i, frozenset((u, v))]: add((u, v), i) - if hex_colors: - return dict(zip(rainbow(len(answer)), answer)) - else: - return answer + return format_coloring(answer, value_only=not hex_colors, hex_colors=hex_colors) def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, @@ -2002,21 +2040,22 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, sage: from sage.graphs.graph_coloring import acyclic_edge_coloring sage: g = graphs.CompleteGraph(8) - sage: colors = acyclic_edge_coloring(g) + sage: colors = acyclic_edge_coloring(g) # needs sage.numerical.mip Each color class is of course a matching :: - sage: all(max(gg.degree()) <= 1 for gg in colors) + sage: all(max(gg.degree()) <= 1 for gg in colors) # needs sage.numerical.mip True These matchings being a partition of the edge set:: - sage: all(any(gg.has_edge(e) for gg in colors) for e in g.edge_iterator(labels=False)) + sage: all(any(gg.has_edge(e) for gg in colors) # needs sage.numerical.mip + ....: for e in g.edge_iterator(labels=False)) True Besides, the union of any two of them is a forest :: - sage: all(g1.union(g2).is_forest() for g1 in colors for g2 in colors) + sage: all(g1.union(g2).is_forest() for g1 in colors for g2 in colors) # needs sage.numerical.mip True If one wants to acyclically color a cycle on `4` vertices, at least 3 colors @@ -2024,15 +2063,15 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, with only 2:: sage: g = graphs.CycleGraph(4) - sage: acyclic_edge_coloring(g, k=2) + sage: acyclic_edge_coloring(g, k=2) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: this graph cannot be colored with the given number of colors The optimal coloring give us `3` classes:: - sage: colors = acyclic_edge_coloring(g, k=None) - sage: len(colors) + sage: colors = acyclic_edge_coloring(g, k=None) # needs sage.numerical.mip + sage: len(colors) # needs sage.numerical.mip 3 TESTS: @@ -2040,39 +2079,38 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, Issue :trac:`24991` is fixed:: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring - sage: sorted(acyclic_edge_coloring(G, value_only=True) for G in graphs(4)) + sage: sorted(acyclic_edge_coloring(G, value_only=True) for G in graphs(4)) # needs sage.numerical.mip [2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5] Test parameter ``hex_color`` (:trac:`26228`):: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring sage: g = graphs.CompleteGraph(4) - sage: d = acyclic_edge_coloring(g, hex_colors=True) - sage: sorted(d) + sage: d = acyclic_edge_coloring(g, hex_colors=True) # needs sage.numerical.mip + sage: sorted(d) # needs sage.numerical.mip ['#0066ff', '#00ff66', '#cbff00', '#cc00ff', '#ff0000'] The acyclic chromatic index of a graph without edge is 0 (:trac:`27079`):: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring sage: g = Graph(3) - sage: acyclic_edge_coloring(g, k=None, value_only=True) + sage: acyclic_edge_coloring(g, k=None, value_only=True) # needs sage.numerical.mip 0 - sage: acyclic_edge_coloring(g, k=None, hex_colors=True) + sage: acyclic_edge_coloring(g, k=None, hex_colors=True) # needs sage.numerical.mip {} - sage: acyclic_edge_coloring(g, k=None, hex_colors=False) + sage: acyclic_edge_coloring(g, k=None, hex_colors=False) # needs sage.numerical.mip [] Empty graph (:trac:`27079`):: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring - sage: acyclic_edge_coloring(Graph(), k=None, value_only=True) + sage: acyclic_edge_coloring(Graph(), k=None, value_only=True) # needs sage.numerical.mip 0 """ g._scream_if_not_simple(allow_multiple_edges=True) from sage.rings.integer import Integer from sage.combinat.subset import Subsets - from sage.plot.colors import rainbow if not g.order() or not g.size(): if k == 0: @@ -2082,7 +2120,10 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, else: if k is None: return {} if hex_colors else [] - return {c: [] for c in rainbow(k)} if hex_colors else [copy(g) for _ in range(k)] + if hex_colors: + return format_coloring([[] for _ in range(k)], hex_colors=True) + else: + return [copy(g) for _ in range(k)] if k is None: k = max(g.degree()) @@ -2139,6 +2180,7 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, p.set_objective(None) + from sage.numerical.mip import MIPSolverException try: p.solve(objective_only=value_only, log=verbose) if value_only: @@ -2173,17 +2215,14 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, if c[i, E(u, v)]: add((u, v), i) - if hex_colors: - return dict(zip(rainbow(len(answer)), answer)) - else: - return answer + return format_coloring(answer, value_only=not hex_colors, hex_colors=hex_colors) cdef class Test: r""" - This class performs randomized testing for all_graph_colorings. + This class performs randomized testing for :func:`all_graph_colorings`. - Since everything else in this file is derived from all_graph_colorings, this + Since everything else in this file is derived from :func:`all_graph_colorings`, this is a pretty good randomized tester for the entire file. Note that for a graph `G`, ``G.chromatic_polynomial()`` uses an entirely different algorithm, so we provide a good, independent test. diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index a875f00396d..b8e9226bc2c 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -73,7 +73,7 @@ def degseq_to_data(degree_sequence): 3221 """ degree_sequence.sort() - return sum(degree_sequence[i]*10**i for i in range(len(degree_sequence))) + return sum(di * 10**i for i, di in enumerate(degree_sequence)) def data_to_degseq(data, graph6=None): @@ -101,9 +101,8 @@ def data_to_degseq(data, graph6=None): if not degseq: # compute number of 0's in list from graph6 string from sage.graphs.generic_graph_pyx import length_and_string_from_graph6 - return length_and_string_from_graph6(str(graph6))[0]*[0] - else: - return degseq + return length_and_string_from_graph6(str(graph6))[0] * [0] + return degseq def graph6_to_plot(graph6): @@ -121,7 +120,7 @@ def graph6_to_plot(graph6): EXAMPLES:: sage: from sage.graphs.graph_database import graph6_to_plot - sage: type(graph6_to_plot('D??')) + sage: type(graph6_to_plot('D??')) # needs sage.plot <class 'sage.plot.graphics.Graphics'> """ g = Graph(str(graph6)) @@ -180,44 +179,44 @@ def subgraphs_to_query(subgraphs, db): # tables columns input data type sqlite data type # ----------------------------------------------------------------------------- -aut_grp = ['aut_grp_size', # Integer INTEGER - 'num_orbits', # Integer INTEGER - 'num_fixed_points', # Integer INTEGER - 'vertex_transitive', # bool BOOLEAN - 'edge_transitive'] # bool BOOLEAN -degrees = ['degree_sequence', # list INTEGER (see degseq_to_data module function) - 'min_degree', # Integer INTEGER - 'max_degree', # Integer INTEGER - 'average_degree', # Real REAL - 'degrees_sd', # Real REAL - 'regular'] # bool BOOLEAN -misc = ['vertex_connectivity', # Integer INTEGER - 'edge_connectivity', # Integer INTEGER - 'num_components', # Integer INTEGER - 'girth', # Integer INTEGER - 'radius', # Integer INTEGER - 'diameter', # Integer INTEGER - 'clique_number', # Integer INTEGER - 'independence_number', # Integer INTEGER - 'num_cut_vertices', # Integer INTEGER - 'min_vertex_cover_size', # Integer INTEGER - 'num_spanning_trees', # Integer INTEGER - 'induced_subgraphs'] # String STRING +aut_grp = ['aut_grp_size', # Integer INTEGER + 'num_orbits', # Integer INTEGER + 'num_fixed_points', # Integer INTEGER + 'vertex_transitive', # bool BOOLEAN + 'edge_transitive'] # bool BOOLEAN +degrees = ['degree_sequence', # list INTEGER (see degseq_to_data module function) + 'min_degree', # Integer INTEGER + 'max_degree', # Integer INTEGER + 'average_degree', # Real REAL + 'degrees_sd', # Real REAL + 'regular'] # bool BOOLEAN +misc = ['vertex_connectivity', # Integer INTEGER + 'edge_connectivity', # Integer INTEGER + 'num_components', # Integer INTEGER + 'girth', # Integer INTEGER + 'radius', # Integer INTEGER + 'diameter', # Integer INTEGER + 'clique_number', # Integer INTEGER + 'independence_number', # Integer INTEGER + 'num_cut_vertices', # Integer INTEGER + 'min_vertex_cover_size', # Integer INTEGER + 'num_spanning_trees', # Integer INTEGER + 'induced_subgraphs'] # String STRING spectrum = ['spectrum', # String STRING 'min_eigenvalue', # Real REAL 'max_eigenvalue', # Real REAL 'eigenvalues_sd', # Real REAL 'energy'] # Real REAL -graph_data=['complement_graph6', # String STRING - 'eulerian', # bool BOOLEAN - 'graph6', # String STRING - 'lovasz_number', # Real REAL - 'num_cycles', # Integer INTEGER - 'num_edges', # Integer INTEGER - 'num_hamiltonian_cycles', # Integer INTEGER - 'num_vertices', # Integer INTEGER - 'perfect', # bool BOOLEAN - 'planar'] # bool BOOLEAN +graph_data = ['complement_graph6', # String STRING + 'eulerian', # bool BOOLEAN + 'graph6', # String STRING + 'lovasz_number', # Real REAL + 'num_cycles', # Integer INTEGER + 'num_edges', # Integer INTEGER + 'num_hamiltonian_cycles', # Integer INTEGER + 'num_vertices', # Integer INTEGER + 'perfect', # bool BOOLEAN + 'planar'] # bool BOOLEAN valid_kwds = aut_grp + degrees + misc + spectrum + graph_data diff --git a/src/sage/combinat/chas/__init__.py b/src/sage/graphs/graph_decompositions/all__sagemath_tdlib.py similarity index 100% rename from src/sage/combinat/chas/__init__.py rename to src/sage/graphs/graph_decompositions/all__sagemath_tdlib.py diff --git a/src/sage/graphs/graph_decompositions/bandwidth.pyx b/src/sage/graphs/graph_decompositions/bandwidth.pyx index 9f0491c0078..bbd3916ac2b 100644 --- a/src/sage/graphs/graph_decompositions/bandwidth.pyx +++ b/src/sage/graphs/graph_decompositions/bandwidth.pyx @@ -1,3 +1,4 @@ +# cython: binding=True r""" Bandwidth of undirected graphs @@ -108,7 +109,7 @@ Functions # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** from libc.stdint cimport uint16_t @@ -116,7 +117,6 @@ from cysignals.signals cimport sig_check from memory_allocator cimport MemoryAllocator from sage.graphs.distances_all_pairs cimport all_pairs_shortest_path_BFS -from sage.graphs.base.boost_graph import bandwidth_heuristics ctypedef uint16_t index_t @@ -160,7 +160,7 @@ def bandwidth(G, k=None): False sage: bandwidth(G) (5, [0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) - sage: G.adjacency_matrix(vertices=[0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) + sage: G.adjacency_matrix(vertices=[0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) # needs sage.modules [0 1 1 0 1 0 0 0 0 0] [1 0 0 0 0 1 1 0 0 0] [1 0 0 1 0 0 0 1 0 0] @@ -174,7 +174,7 @@ def bandwidth(G, k=None): sage: G = graphs.ChvatalGraph() sage: bandwidth(G) (6, [0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) - sage: G.adjacency_matrix(vertices=[0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) + sage: G.adjacency_matrix(vertices=[0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) # needs sage.modules [0 0 1 1 0 1 1 0 0 0 0 0] [0 0 0 1 1 1 0 1 0 0 0 0] [1 0 0 0 1 0 0 1 1 0 0 0] @@ -254,7 +254,7 @@ def bandwidth(G, k=None): cdef range_t ** ith_range_array = <range_t **> mem.allocarray(n, sizeof(range_t *)) cdef range_t * range_array_tmp = <range_t *> mem.allocarray(n, sizeof(range_t)) - cdef int i, j, kk + cdef int i, kk # compute the distance matrix all_pairs_shortest_path_BFS(G, NULL, distances, NULL, vertex_list=int_to_vertex) diff --git a/src/sage/graphs/graph_decompositions/clique_separators.pyx b/src/sage/graphs/graph_decompositions/clique_separators.pyx index 35a1cf2a4b8..b4f92db5172 100644 --- a/src/sage/graphs/graph_decompositions/clique_separators.pyx +++ b/src/sage/graphs/graph_decompositions/clique_separators.pyx @@ -21,7 +21,6 @@ Methods # https://www.gnu.org/licenses/ # **************************************************************************** -from libcpp.pair cimport pair from libcpp.vector cimport vector from libc.stdint cimport uint32_t from cysignals.signals cimport sig_on, sig_off, sig_check @@ -424,7 +423,7 @@ def atoms_and_clique_separators(G, tree=False, rooted_tree=False, separators=Fal if not G.is_connected(): from sage.graphs.graph import Graph - for cc in G.connected_components(): + for cc in G.connected_components(sort=False): g = Graph([cc, G.edge_boundary(cc, cc, False, False)], format='vertices_and_edges', loops=True, multiedges=True) @@ -523,8 +522,6 @@ def atoms_and_clique_separators(G, tree=False, rooted_tree=False, separators=Fal cdef vector[int] Sint_min cdef vector[int] Cint cdef vector[int] Hx - cdef size_t ui, vi - cdef bint stop for i in range(N): sig_check() diff --git a/src/sage/graphs/graph_decompositions/cutwidth.pyx b/src/sage/graphs/graph_decompositions/cutwidth.pyx index 4984be70a74..208bd69dea4 100644 --- a/src/sage/graphs/graph_decompositions/cutwidth.pyx +++ b/src/sage/graphs/graph_decompositions/cutwidth.pyx @@ -1,3 +1,4 @@ +# cython: binding=True r""" Cutwidth @@ -371,7 +372,7 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False, sage: G = Graph([(0, 1)]) sage: cutwidth(G, algorithm="exponential") (1, [0, 1]) - sage: cutwidth(G, algorithm="MILP", solver='GLPK') + sage: cutwidth(G, algorithm="MILP", solver='GLPK') # needs sage.numerical.mip (1, [0, 1]) Cutwidth of a disconnected graph:: @@ -381,7 +382,7 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False, sage: G.add_edge(2, 3) sage: cutwidth(G, algorithm="exponential") (1, [2, 3, 0, 1, 4]) - sage: cutwidth(G, algorithm="MILP", solver='GLPK') + sage: cutwidth(G, algorithm="MILP", solver='GLPK') # needs sage.numerical.mip (1, [2, 3, 0, 1, 4]) """ from sage.graphs.graph import Graph @@ -528,6 +529,7 @@ def cutwidth_dyn(G, lower_bound=0): finally: sig_free(neighborhoods) + cdef inline int exists(FastDigraph g, uint8_t* neighborhoods, int S, int cost_S, int v, int k): r""" Check whether an ordering with the given cost `k` exists, and updates data @@ -571,7 +573,6 @@ cdef inline int exists(FastDigraph g, uint8_t* neighborhoods, int S, int cost_S, cdef int mini = (<uint8_t> -1) cdef int i - cdef int next_set # For each possible extension of the current set with a vertex, check whether # there exists a cheap path toward {1..n}, and update the cost. @@ -642,9 +643,9 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.CycleGraph(5) - sage: cw, L = cutwidth.cutwidth_MILP(G); cw + sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip 2 - sage: cw == cutwidth.width_of_cut_decomposition(G, L) + sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip True sage: cwe, Le = cutwidth.cutwidth_dyn(G); cwe 2 @@ -653,18 +654,18 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.CompleteGraph(4) - sage: cw, L = cutwidth.cutwidth_MILP(G); cw + sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip 4 - sage: cw == cutwidth.width_of_cut_decomposition(G, L) + sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip True Cutwidth of a Path graph:: sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.PathGraph(3) - sage: cw, L = cutwidth.cutwidth_MILP(G); cw + sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip 1 - sage: cw == cutwidth.width_of_cut_decomposition(G, L) + sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip True TESTS: @@ -672,7 +673,7 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, Comparison with exponential algorithm:: sage: from sage.graphs.graph_decompositions import cutwidth - sage: for i in range(2): # long time + sage: for i in range(2): # long time # needs sage.numerical.mip ....: G = graphs.RandomGNP(7, 0.3) ....: ve, le = cutwidth.cutwidth_dyn(G) ....: vm, lm = cutwidth.cutwidth_MILP(G, solver='GLPK') @@ -683,7 +684,7 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, sage: from sage.graphs.graph_decompositions.cutwidth import cutwidth_MILP sage: G = graphs.CycleGraph(3) - sage: cutwidth_MILP(G, lower_bound=G.size()+1) + sage: cutwidth_MILP(G, lower_bound=G.size()+1) # needs sage.numerical.mip Traceback (most recent call last): ... MIPSolverException: ... @@ -735,7 +736,7 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, p.set_objective(z['z']) - obj = p.solve(log=verbose) + _ = p.solve(log=verbose) # We now extract the ordering and the cost of the solution val_x = p.get_values(x, convert=bool, tolerance=integrality_tolerance) diff --git a/src/sage/graphs/graph_decompositions/fast_digraph.pxd b/src/sage/graphs/graph_decompositions/fast_digraph.pxd index eee5267ecd3..85466f67ac1 100644 --- a/src/sage/graphs/graph_decompositions/fast_digraph.pxd +++ b/src/sage/graphs/graph_decompositions/fast_digraph.pxd @@ -10,5 +10,3 @@ cdef int compute_out_neighborhood_cardinality(FastDigraph, int) cdef int popcount32(int) cdef int slow_popcount32(int) - - diff --git a/src/sage/graphs/graph_decompositions/fast_digraph.pyx b/src/sage/graphs/graph_decompositions/fast_digraph.pyx index 667a1cb3972..3d7c4b2fea7 100644 --- a/src/sage/graphs/graph_decompositions/fast_digraph.pyx +++ b/src/sage/graphs/graph_decompositions/fast_digraph.pyx @@ -12,10 +12,9 @@ cardinality). In the following code, sets are represented as integers, where the `i`-th bit is set if element `i` belongs to the set. """ - -from libc.stdint cimport uint8_t from cysignals.memory cimport check_allocarray, check_calloc, sig_free + cdef class FastDigraph: def __cinit__(self, D, vertex_list=None): @@ -42,7 +41,7 @@ cdef class FastDigraph: ....: 'cdef FastDigraph F = FastDigraph(G)', ....: 'cdef int i', ....: 'print([F.degree[i] for i in range(F.n)])'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython [1, 2, 1] """ if D.order() > 8*sizeof(int): @@ -53,7 +52,7 @@ cdef class FastDigraph: self.n = D.order() self.graph = <int *>check_calloc(self.n, sizeof(int)) - cdef int i, j + cdef int i cdef int tmp # When the vertices are not consecutive integers @@ -99,7 +98,7 @@ cdef class FastDigraph: ....: 'from sage.graphs.graph import Graph', ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport FastDigraph', ....: 'FastDigraph(Graph([(0, 1), (1, 2)])).print_adjacency_matrix()'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython 010 101 010 @@ -129,7 +128,7 @@ cdef inline int compute_out_neighborhood_cardinality(FastDigraph g, int S): ....: 'cdef FastDigraph F = FastDigraph(Graph([(0, 1), (1, 2)]))', ....: 'cdef int i', ....: 'print([compute_out_neighborhood_cardinality(F, 1<<i) for i in range(F.n)])'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython [1, 2, 1] """ cdef int i @@ -153,7 +152,7 @@ cdef inline int popcount32(int i): ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport popcount32', ....: 'cdef int i', ....: 'print([popcount32(i) for i in range(16)])'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4] """ i = i - ((i >> 1) & 0x55555555) @@ -199,7 +198,7 @@ cdef inline int slow_popcount32(int i): ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport slow_popcount32', ....: 'cdef int i', ....: 'print(all(popcount32(i) == slow_popcount32(i) for i in range(16)))'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython True """ # Slow popcount for 32bits integers diff --git a/src/sage/graphs/graph_decompositions/graph_products.pyx b/src/sage/graphs/graph_decompositions/graph_products.pyx index a51013e6df4..31f49206586 100644 --- a/src/sage/graphs/graph_decompositions/graph_products.pyx +++ b/src/sage/graphs/graph_decompositions/graph_products.pyx @@ -130,8 +130,6 @@ Methods # https://www.gnu.org/licenses/ # **************************************************************************** -from copy import copy - def is_cartesian_product(g, certificate=False, relabeling=False): r""" @@ -208,8 +206,8 @@ def is_cartesian_product(g, certificate=False, relabeling=False): Wagner's Graph (:trac:`13599`):: - sage: g = graphs.WagnerGraph() - sage: g.is_cartesian_product() + sage: g = graphs.WagnerGraph() # needs networkx + sage: g.is_cartesian_product() # needs networkx False Empty and one-element graph (:trac:`19546`):: @@ -311,7 +309,7 @@ def is_cartesian_product(g, certificate=False, relabeling=False): # Gathering the connected components, relabeling the vertices on-the-fly edges = [[(int_to_vertex[u], int_to_vertex[v]) for u, v in cc] - for cc in h.connected_components()] + for cc in h.connected_components(sort=False)] # Only one connected component ? if len(edges) == 1: @@ -322,7 +320,7 @@ def is_cartesian_product(g, certificate=False, relabeling=False): for cc in edges: tmp = Graph() tmp.add_edges(cc) - factors.append(tmp.subgraph(vertices=tmp.connected_components()[0])) + factors.append(tmp.subgraph(vertices=tmp.connected_components(sort=False)[0])) # Computing the product of these graphs answer = factors[0] @@ -341,3 +339,123 @@ def is_cartesian_product(g, certificate=False, relabeling=False): return factors else: return True + + +def rooted_product(G, H, root=None): + r""" + Return the rooted product of `G` and `H`. + + The rooted product of two graphs `G` and `H` is the graph `R` defined as + follows: take a copy of `G` and `|V(G)|` copies of `H`, and for every vertex + `g_i` of `G`, identify `g_i` with the root of the `i`-th copy of `H`. + Mode formally, let `V(G) = \{g_1, g_2, \ldots, g_n\}`, + `V(H) = \{h_1, h_2, \ldots, h_m\}`, and let `h_1` be the root vertex of `H`. + The vertex set `V(R)` is equal to the cartesian product of the sets of + vertices `V(G)` and `V(H)`, that is + `V(R) = \{(g_i, h_j) : g_i \in V(G), h_j \in V(H)\}`. The edge set `E(R)` + is the union of the edges of a copy of `G`, that is + `\{((g_i, h_1), (g_j, h_1)) : (g_i, g_j) \in E(G)\}`, and the edges of the + copies of `H` for every `g_i \in V(G)`, that is + `\{((g_i, h_j), (g_i, h_k)) : (h_j, h_k) \in V(H)\}`. + + See :wikipedia:`Rooted_product_of_graphs` for more details. + + .. SEEALSO:: + + - :meth:`~sage.graphs.generic_graph.cartesian_product` + -- return the cartesian product of two graphs + + - :mod:`~sage.graphs.graph_decompositions.graph_products` + -- a module on graph products + + EXAMPLES: + + The rooted product of two trees is a tree:: + + sage: T1 = graphs.RandomTree(7) + sage: T2 = graphs.RandomTree(8) + sage: T = T1.rooted_product(T2) + sage: T.is_tree() + True + + The rooted product of `G` and `H` depends on the selected root in `H`:: + + sage: G = graphs.CycleGraph(4) + sage: H = graphs.PathGraph(3) + sage: R1 = G.rooted_product(H, root=0) + sage: R2 = G.rooted_product(H, root=1) + sage: R1.is_isomorphic(R2) + False + sage: sorted(R1.degree()) + [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3] + sage: sorted(R2.degree()) + [1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4] + + The domination number of the rooted product of any graph `G` and a path of + order 2 is the order of `G`:: + + sage: G = graphs.RandomGNP(20, .3) + sage: P = graphs.PathGraph(2) + sage: R = G.rooted_product(P) + sage: len(R.dominating_set()) == G.order() + True + sage: G = digraphs.RandomDirectedGNP(20, .3) + sage: P = digraphs.Path(2) + sage: R = G.rooted_product(P) + sage: len(R.dominating_set()) == G.order() + True + + The rooted product of two graphs is a subgraph of the cartesian product of + the same two graphs:: + + sage: G = graphs.RandomGNP(6, .4) + sage: H = graphs.RandomGNP(7, .4) + sage: R = G.rooted_product(H) + sage: C = G.cartesian_product(H) + sage: R.is_subgraph(C, induced=False) + True + + Corner cases:: + + sage: Graph().rooted_product(Graph()) + Rooted product of Graph on 0 vertices and Graph on 0 vertices: Graph on 0 vertices + sage: Graph(1).rooted_product(Graph()) + Rooted product of Graph on 1 vertex and Graph on 0 vertices: Graph on 0 vertices + sage: Graph().rooted_product(Graph(1)) + Rooted product of Graph on 0 vertices and Graph on 1 vertex: Graph on 0 vertices + sage: Graph(1).rooted_product(Graph(1)) + Rooted product of Graph on 1 vertex and Graph on 1 vertex: Graph on 1 vertex + + TESTS:: + + sage: Graph().rooted_product(DiGraph()) + Traceback (most recent call last): + ... + TypeError: the graphs should be both directed or both undirected + """ + G._scream_if_not_simple(allow_loops=True) + if G._directed and H._directed: + from sage.graphs.digraph import DiGraph + R = DiGraph(loops=(G.has_loops() or H.has_loops())) + elif (not G._directed) and (not H._directed): + from sage.graphs.graph import Graph + R = Graph(loops=(G.has_loops() or H.has_loops())) + else: + raise TypeError('the graphs should be both directed or both undirected') + + R.name(f'Rooted product of {G} and {H}') + + if not G or not H: + return R + if root is None: + root = next(H.vertex_iterator()) + elif root not in H: + raise ValueError("the specified root is not a vertex of H") + + R.add_vertices((u, x) for u in G for x in H) + for u, v in G.edge_iterator(labels=False): + R.add_edge((u, root), (v, root)) + for x, y in H.edge_iterator(labels=False): + R.add_edges(((u, x), (u, y)) for u in G) + + return R diff --git a/src/sage/graphs/graph_decompositions/modular_decomposition.py b/src/sage/graphs/graph_decompositions/modular_decomposition.py index 0c1ae4da5b3..7a0c71c2fb1 100644 --- a/src/sage/graphs/graph_decompositions/modular_decomposition.py +++ b/src/sage/graphs/graph_decompositions/modular_decomposition.py @@ -16,8 +16,12 @@ # **************************************************************************** from enum import Enum + +from sage.misc.lazy_import import lazy_import from sage.misc.random_testing import random_testing +lazy_import('sage.groups.perm_gps.permgroup_element', 'PermutationGroupElement') + class NodeType(Enum): """ @@ -447,7 +451,7 @@ def gamma_classes(graph): pieces = DisjointSet(frozenset(e) for e in graph.edge_iterator(labels=False)) for v in graph: neighborhood = graph.subgraph(vertices=graph.neighbors(v)) - for component in neighborhood.complement().connected_components(): + for component in neighborhood.complement().connected_components(sort=False): v1 = component[0] e = frozenset([v1, v]) for vi in component[1:]: @@ -606,7 +610,7 @@ def habib_maurer_algorithm(graph, g_classes=None): decompositions. :: sage: from sage.graphs.graph_decompositions.modular_decomposition import permute_decomposition - sage: permute_decomposition(2, habib_maurer_algorithm, 20, 0.5) + sage: permute_decomposition(2, habib_maurer_algorithm, 20, 0.5) # needs sage.groups """ if graph.is_directed(): raise ValueError("Graph must be undirected") @@ -621,7 +625,7 @@ def habib_maurer_algorithm(graph, g_classes=None): elif not graph.is_connected(): root = create_parallel_node() root.children = [habib_maurer_algorithm(graph.subgraph(vertices=sg), g_classes) - for sg in graph.connected_components()] + for sg in graph.connected_components(sort=False)] return root g_comp = graph.complement() @@ -646,7 +650,7 @@ def habib_maurer_algorithm(graph, g_classes=None): root = create_series_node() root.children = [habib_maurer_algorithm(graph.subgraph(vertices=sg), g_classes) - for sg in g_comp.connected_components()] + for sg in g_comp.connected_components(sort=False)] return root @@ -1167,7 +1171,6 @@ def relabel_tree(root, perm): 2 1 """ - from sage.groups.perm_gps.permgroup_element import PermutationGroupElement # If perm is not a dictionary, we build one ! if perm is None: diff --git a/src/sage/graphs/graph_decompositions/rankwidth.pxd b/src/sage/graphs/graph_decompositions/rankwidth.pxd index 8483ba64a83..d24460b5bb9 100644 --- a/src/sage/graphs/graph_decompositions/rankwidth.pxd +++ b/src/sage/graphs/graph_decompositions/rankwidth.pxd @@ -10,6 +10,3 @@ cdef extern from "rw.h": subset_t *adjacency_matrix cdef void print_rank_dec(subset_t s, int l) - - - diff --git a/src/sage/graphs/graph_decompositions/sage_tdlib.cpp b/src/sage/graphs/graph_decompositions/sage_tdlib.cpp index ad1e3fb1f03..3644edf6ac7 100644 --- a/src/sage/graphs/graph_decompositions/sage_tdlib.cpp +++ b/src/sage/graphs/graph_decompositions/sage_tdlib.cpp @@ -1,3 +1,5 @@ +// sage.setup: distribution = sagemath-tdlib + #include <boost/tuple/tuple.hpp> #include <map> diff --git a/src/sage/graphs/graph_decompositions/tdlib.pyx b/src/sage/graphs/graph_decompositions/tdlib.pyx index 017b120abd3..ad3ded3e876 100644 --- a/src/sage/graphs/graph_decompositions/tdlib.pyx +++ b/src/sage/graphs/graph_decompositions/tdlib.pyx @@ -125,18 +125,20 @@ def treedecomposition_exact(G, lb=-1): EXAMPLES:: - sage: import sage.graphs.graph_decompositions.tdlib as tdlib # optional - tdlib - sage: G = graphs.HouseGraph() # optional - tdlib - sage: T = tdlib.treedecomposition_exact(G) # optional - tdlib - sage: T.show(vertex_size=2000) # optional - tdlib + sage: # optional - tdlib + sage: import sage.graphs.graph_decompositions.tdlib as tdlib + sage: G = graphs.HouseGraph() + sage: T = tdlib.treedecomposition_exact(G) + sage: T.show(vertex_size=2000) TESTS:: - sage: import sage.graphs.graph_decompositions.tdlib as tdlib # optional - tdlib - sage: G = graphs.HouseGraph() # optional - tdlib - sage: T = tdlib.treedecomposition_exact(G) # optional - tdlib - sage: G = graphs.PetersenGraph() # optional - tdlib - sage: T = tdlib.treedecomposition_exact(G) # optional - tdlib + sage: # optional - tdlib + sage: import sage.graphs.graph_decompositions.tdlib as tdlib + sage: G = graphs.HouseGraph() + sage: T = tdlib.treedecomposition_exact(G) + sage: G = graphs.PetersenGraph() + sage: T = tdlib.treedecomposition_exact(G) """ cdef vector[unsigned int] V_G, E_G, E_T @@ -175,10 +177,11 @@ def get_width(T): EXAMPLES:: - sage: import sage.graphs.graph_decompositions.tdlib as tdlib # optional - tdlib - sage: G = graphs.PetersenGraph() # optional - tdlib - sage: T = tdlib.treedecomposition_exact(G) # optional - tdlib - sage: tdlib.get_width(T) # optional - tdlib + sage: # optional - tdlib + sage: import sage.graphs.graph_decompositions.tdlib as tdlib + sage: G = graphs.PetersenGraph() + sage: T = tdlib.treedecomposition_exact(G) + sage: tdlib.get_width(T) 4 """ return (max(len(x) for x in T) - 1) if T else -1 diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index 2d699a2c314..1e364277c8c 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -99,18 +99,17 @@ Methods # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** from sage.sets.set import Set from sage.misc.cachefunc import cached_function -from itertools import combinations from itertools import chain from sage.features import PythonModule from sage.sets.disjoint_set import DisjointSet from sage.rings.infinity import Infinity from sage.graphs.distances_all_pairs cimport c_distances_all_pairs -from cysignals.memory cimport sig_malloc, sig_calloc, sig_free +from cysignals.memory cimport sig_calloc, sig_free def is_valid_tree_decomposition(G, T): @@ -1118,7 +1117,7 @@ cdef class TreelengthConnected: # Removing v may have disconnected cc. We iterate on its # connected components - for _cci in g.subgraph(ccv).connected_components(): + for _cci in g.subgraph(ccv).connected_components(sort=False): cci = frozenset(_cci) # The recursive subcalls. We remove on-the-fly the vertices diff --git a/src/sage/graphs/graph_decompositions/vertex_separation.pyx b/src/sage/graphs/graph_decompositions/vertex_separation.pyx index 3138ee1fea2..90fb086e1ae 100644 --- a/src/sage/graphs/graph_decompositions/vertex_separation.pyx +++ b/src/sage/graphs/graph_decompositions/vertex_separation.pyx @@ -268,10 +268,9 @@ from cysignals.memory cimport check_malloc, sig_malloc, sig_free from cysignals.signals cimport sig_check, sig_on, sig_off from sage.graphs.graph_decompositions.fast_digraph cimport FastDigraph, compute_out_neighborhood_cardinality, popcount32 -from libc.stdint cimport uint8_t, int8_t +from libc.stdint cimport uint8_t from sage.data_structures.binary_matrix cimport * from sage.graphs.base.static_dense_graph cimport dense_graph_init -from sage.misc.decorators import rename_keyword ############### @@ -665,7 +664,7 @@ def path_decomposition(G, algorithm="BAB", cut_off=None, upper_bound=None, verbo 2 sage: pw, L = path_decomposition(g, algorithm = "exponential"); pw 2 - sage: pw, L = path_decomposition(g, algorithm = "MILP"); pw + sage: pw, L = path_decomposition(g, algorithm="MILP"); pw # needs sage.numerical.mip 2 TESTS: @@ -766,19 +765,22 @@ def vertex_separation(G, algorithm="BAB", cut_off=None, upper_bound=None, verbos Comparison of methods:: sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation + + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2,3) sage: vs,L = vertex_separation(G, algorithm="BAB"); vs 2 sage: vs,L = vertex_separation(G, algorithm="exponential"); vs 2 - sage: vs,L = vertex_separation(G, algorithm="MILP"); vs + sage: vs,L = vertex_separation(G, algorithm="MILP"); vs # needs sage.numerical.mip 2 + sage: G = graphs.Grid2dGraph(3,3) sage: vs,L = vertex_separation(G, algorithm="BAB"); vs 3 sage: vs,L = vertex_separation(G, algorithm="exponential"); vs 3 - sage: vs,L = vertex_separation(G, algorithm="MILP"); vs + sage: vs,L = vertex_separation(G, algorithm="MILP"); vs # needs sage.numerical.mip 3 Digraphs with multiple strongly connected components:: @@ -805,7 +807,7 @@ def vertex_separation(G, algorithm="BAB", cut_off=None, upper_bound=None, verbos sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation sage: G = graphs.PetersenGraph() - sage: vs, L = vertex_separation(G, algorithm="MILP", solver="SCIP"); vs # optional - pyscipopt + sage: vs, L = vertex_separation(G, algorithm="MILP", solver="SCIP"); vs # optional - pyscipopt, needs sage.numerical.mip 5 TESTS: @@ -954,8 +956,8 @@ def vertex_separation_exp(G, verbose=False): Graphs with non-integer vertices:: sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation_exp - sage: D=digraphs.DeBruijn(2,3) - sage: vertex_separation_exp(D) + sage: D = digraphs.DeBruijn(2,3) # needs sage.combinat + sage: vertex_separation_exp(D) # needs sage.combinat (2, ['000', '001', '100', '010', '101', '011', '110', '111']) Given a too large graph:: @@ -985,7 +987,7 @@ def vertex_separation_exp(G, verbose=False): memset(neighborhoods, <uint8_t> -1, mem) - cdef int i, j, k + cdef int i, k for k in range(g.n): if verbose: print("Looking for a strategy of cost", str(k)) @@ -1210,6 +1212,7 @@ def width_of_path_decomposition(G, L): Path decomposition of a BalancedTree:: + sage: # needs networkx sage: from sage.graphs.graph_decompositions import vertex_separation sage: G = graphs.BalancedTree(3,2) sage: pw, L = vertex_separation.path_decomposition(G) @@ -1305,9 +1308,9 @@ def _vertex_separation_MILP_formulation(G, integrality=False, solver=None): EXAMPLES:: sage: from sage.graphs.graph_decompositions.vertex_separation import _vertex_separation_MILP_formulation - sage: G = digraphs.DeBruijn(2,3) - sage: p, x, u, y, z = _vertex_separation_MILP_formulation(G) - sage: p + sage: G = digraphs.DeBruijn(2,3) # needs sage.combinat + sage: p, x, u, y, z = _vertex_separation_MILP_formulation(G) # needs sage.combinat sage.numerical.mip + sage: p # needs sage.combinat sage.numerical.mip Mixed Integer Program (minimization, 193 variables, 449 constraints) """ from sage.graphs.graph import Graph @@ -1373,7 +1376,6 @@ def _vertex_separation_MILP_formulation(G, integrality=False, solver=None): return p, x, u, y, z -@rename_keyword(deprecation=32222, verbosity='verbose') def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" @@ -1419,11 +1421,12 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Vertex separation of a De Bruijn digraph:: + sage: # needs sage.combinat sage: from sage.graphs.graph_decompositions import vertex_separation sage: G = digraphs.DeBruijn(2,3) - sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs + sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs # needs sage.numerical.mip 2 - sage: vs == vertex_separation.width_of_path_decomposition(G, L) + sage: vs == vertex_separation.width_of_path_decomposition(G, L) # needs sage.numerical.mip True sage: vse, Le = vertex_separation.vertex_separation(G); vse 2 @@ -1432,7 +1435,7 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, sage: from sage.graphs.graph_decompositions import vertex_separation sage: G = digraphs.Circuit(6) - sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs + sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs # needs sage.numerical.mip 1 TESTS: @@ -1440,7 +1443,7 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Comparison with exponential algorithm:: sage: from sage.graphs.graph_decompositions import vertex_separation - sage: for i in range(10): + sage: for i in range(10): # needs sage.numerical.mip ....: G = digraphs.RandomDirectedGNP(10, 0.2) ....: ve, le = vertex_separation.vertex_separation(G) ....: vm, lm = vertex_separation.vertex_separation_MILP(G) @@ -1450,7 +1453,7 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Comparison with different values of the integrality parameter:: sage: from sage.graphs.graph_decompositions import vertex_separation - sage: for i in range(10): # long time (11s on sage.math, 2012) + sage: for i in range(10): # long time (11s on sage.math, 2012), needs sage.numerical.mip ....: G = digraphs.RandomDirectedGNP(10, 0.2) ....: va, la = vertex_separation.vertex_separation_MILP(G, integrality=False) ....: vb, lb = vertex_separation.vertex_separation_MILP(G, integrality=True) @@ -1460,19 +1463,19 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Giving anything else than a Graph or a DiGraph:: sage: from sage.graphs.graph_decompositions import vertex_separation - sage: vertex_separation.vertex_separation_MILP([]) + sage: vertex_separation.vertex_separation_MILP([]) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the first input parameter must be a Graph or a DiGraph """ from sage.numerical.mip import MIPSolverException - p, x, u, y, z = _vertex_separation_MILP_formulation(G, integrality=integrality, solver=solver) + p, _, _, y, z = _vertex_separation_MILP_formulation(G, integrality=integrality, solver=solver) N = G.order() V = list(G) try: - obj = p.solve(log=verbose) + _ = p.solve(log=verbose) except MIPSolverException: if integrality: raise ValueError("unbounded or unexpected error") @@ -1835,9 +1838,9 @@ cdef int vertex_separation_BAB_C(binary_matrix_t H, # ==> Allocate local data structures - cdef bitset_s *loc_b_prefix = bm_pool.rows[3 * level] + cdef bitset_s *loc_b_prefix = bm_pool.rows[3 * level] cdef bitset_s *loc_b_pref_and_neigh = bm_pool.rows[3 * level + 1] - cdef bitset_s *b_tmp = bm_pool.rows[3 * level + 2] + cdef bitset_s *b_tmp = bm_pool.rows[3 * level + 2] bitset_copy(loc_b_prefix, b_prefix) bitset_copy(loc_b_pref_and_neigh, b_prefix_and_neighborhood) diff --git a/src/sage/graphs/graph_editor.py b/src/sage/graphs/graph_editor.py index d4d8722369f..fc1fc72ccc8 100644 --- a/src/sage/graphs/graph_editor.py +++ b/src/sage/graphs/graph_editor.py @@ -64,10 +64,10 @@ def graph_editor(graph=None, **display_options): Using different display options:: - sage: e = graph_editor(graphs.PetersenGraph(), width=300, height=300, # optional - phitigra - ....: default_radius=12, default_vertex_color='orange', # optional - phitigra - ....: default_edge_color='#666', show_vertex_labels=False) # optional - phitigra - sage: e.show() # not tested + sage: e = graph_editor(graphs.PetersenGraph(), width=300, height=300, # optional - phitigra + ....: default_radius=12, default_vertex_color='orange', + ....: default_edge_color='#666', show_vertex_labels=False) + sage: e.show() # not tested .. NOTE:: diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index df88bbe2713..f1d53f31e95 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Common graphs @@ -69,6 +68,7 @@ def wrap_name(x): "CompleteBipartiteGraph", "CompleteGraph", "CompleteMultipartiteGraph", + "CorrelationGraph", "DiamondGraph", "GemGraph", "DartGraph", @@ -651,9 +651,9 @@ class GraphGenerators(): except for appropriately inheritable properties:: sage: property = lambda G: G.is_vertex_transitive() - sage: len(list(graphs(4, property))) + sage: len(list(graphs(4, property))) # needs sage.groups 1 - sage: sum(1 for g in graphs(4) if property(g)) + sage: sum(1 for g in graphs(4) if property(g)) # needs sage.groups 4 sage: property = lambda G: G.is_bipartite() @@ -682,7 +682,7 @@ class GraphGenerators(): sage: L = list(graphs(5,augment='vertices',loops=True)) # long time sage: for i in [0..5]: # long time - ....: print((i, len([g for g in L if g.order() == i]))) # long time + ....: print((i, len([g for g in L if g.order() == i]))) (0, 1) (1, 2) (2, 6) @@ -966,7 +966,7 @@ def nauty_geng(self, options="", debug=False): ... ValueError: wrong format of parameter option sage: list(graphs.nauty_geng("-c3", debug=True)) - ['>E Usage: ...geng [-cCmtfbd#D#] [-uygsnh] [-lvq] ... + ['>E Usage: ...geng ...\n'] sage: list(graphs.nauty_geng("-c 3", debug=True)) ['>A ...geng -cd1D2 n=3 e=2-3\n', Graph on 3 vertices, Graph on 3 vertices] """ @@ -1231,15 +1231,16 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr EXAMPLES:: - sage: g=graphs.cospectral_graphs(5) - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) + sage: g = graphs.cospectral_graphs(5) # needs sage.modules + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules [['Dr?', 'Ds_']] - sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() + sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() # needs sage.modules True There are two sets of cospectral graphs on six vertices with no isolated vertices:: - sage: g=graphs.cospectral_graphs(6, graphs=lambda x: min(x.degree())>0) + sage: # needs sage.modules + sage: g = graphs.cospectral_graphs(6, graphs=lambda x: min(x.degree())>0) sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) [['Ep__', 'Er?G'], ['ExGg', 'ExoG']] sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() @@ -1249,16 +1250,17 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr There is one pair of cospectral trees on eight vertices:: - sage: g=graphs.cospectral_graphs(6, graphs=graphs.trees(8)) - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) + sage: g = graphs.cospectral_graphs(6, graphs=graphs.trees(8)) # needs sage.modules + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules [['GiPC?C', 'GiQCC?']] - sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() + sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() # needs sage.modules True There are two sets of cospectral graphs (with respect to the Laplacian matrix) on six vertices:: - sage: g=graphs.cospectral_graphs(6, matrix_function=lambda g: g.laplacian_matrix()) + sage: # needs sage.modules + sage: g = graphs.cospectral_graphs(6, matrix_function=lambda g: g.laplacian_matrix()) sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) [['Edq_', 'ErcG'], ['Exoo', 'EzcG']] sage: g[0][1].laplacian_matrix().charpoly()==g[0][1].laplacian_matrix().charpoly() @@ -1278,10 +1280,12 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr ....: for i in range(g.order()): ....: A.rescale_row(i, 1 / len(A.nonzero_positions_in_row(i))) ....: return A - sage: g = graphs.cospectral_graphs(5, matrix_function=DinverseA, graphs=lambda g: min(g.degree()) > 0) - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) + sage: g = graphs.cospectral_graphs(5, matrix_function=DinverseA, # needs sage.modules + ....: graphs=lambda g: min(g.degree()) > 0) + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules [['Dlg', 'Ds_']] - sage: g[0][1].laplacian_matrix(normalized=True).charpoly()==g[0][1].laplacian_matrix(normalized=True).charpoly() # optional - sage.symbolic + sage: (g[0][1].laplacian_matrix(normalized=True).charpoly() # needs sage.modules sage.symbolic + ....: == g[0][1].laplacian_matrix(normalized=True).charpoly()) True """ from sage.graphs.graph_generators import graphs as graph_gen @@ -1461,11 +1465,12 @@ def fullerenes(self, order, ipr=False): The unique fullerene graph on 20 vertices is isomorphic to the dodecahedron graph. :: - sage: gen = graphs.fullerenes(20) # optional buckygen - sage: g = next(gen) # optional buckygen - sage: g.is_isomorphic(graphs.DodecahedralGraph()) # optional buckygen + sage: # optional - buckygen + sage: gen = graphs.fullerenes(20) + sage: g = next(gen) + sage: g.is_isomorphic(graphs.DodecahedralGraph()) True - sage: g.get_embedding() # optional buckygen + sage: g.get_embedding() {1: [2, 3, 4], 2: [1, 5, 6], 3: [1, 7, 8], @@ -1486,7 +1491,7 @@ def fullerenes(self, order, ipr=False): 18: [12, 20, 13], 19: [14, 20, 15], 20: [17, 19, 18]} - sage: g.plot3d(layout='spring') # optional buckygen + sage: g.plot3d(layout='spring') Graphics3d Object """ # number of vertices should be positive @@ -1739,12 +1744,13 @@ def plantri_gen(self, options=""): (usually inside a loop). Or it can be used to create an entire list all at once if there is sufficient memory to contain it:: - sage: gen = graphs.plantri_gen("6") # optional plantri - sage: next(gen) # optional plantri + sage: # optional - plantri + sage: gen = graphs.plantri_gen("6") + sage: next(gen) Graph on 6 vertices - sage: next(gen) # optional plantri + sage: next(gen) Graph on 6 vertices - sage: next(gen) # optional plantri + sage: next(gen) Traceback (most recent call last): ... StopIteration @@ -1752,10 +1758,10 @@ def plantri_gen(self, options=""): An overview of the number of quadrangulations on up to 12 vertices. This agrees with :oeis:`A113201`:: - sage: for i in range(4,13): # optional plantri - ....: cmd = '-qm2c2 {}'.format(i) # optional plantri - ....: L = len(list(graphs.plantri_gen(cmd))) # optional plantri - ....: print("{:2d} {:3d}".format(i, L)) # optional plantri + sage: for i in range(4, 13): # optional plantri + ....: cmd = '-qm2c2 {}'.format(i) + ....: L = len(list(graphs.plantri_gen(cmd))) + ....: print("{:2d} {:3d}".format(i, L)) 4 1 5 1 6 2 @@ -1913,13 +1919,14 @@ def planar_graphs(self, order, minimum_degree=None, Specifying lower and upper bounds on the number of edges:: - sage: len(list(graphs.planar_graphs(4))) # optional plantri + sage: # optional - plantri + sage: len(list(graphs.planar_graphs(4))) 6 - sage: len(list(graphs.planar_graphs(4, minimum_edges=4))) # optional plantri + sage: len(list(graphs.planar_graphs(4, minimum_edges=4))) 4 - sage: len(list(graphs.planar_graphs(4, maximum_edges=4))) # optional plantri + sage: len(list(graphs.planar_graphs(4, maximum_edges=4))) 4 - sage: len(list(graphs.planar_graphs(4, minimum_edges=4, maximum_edges=4))) # optional plantri + sage: len(list(graphs.planar_graphs(4, minimum_edges=4, maximum_edges=4))) 2 Specifying the maximum size of a face:: @@ -1934,11 +1941,12 @@ def planar_graphs(self, order, minimum_degree=None, The number of edges in a planar graph is equal to the number of edges in its dual:: - sage: planar = list(graphs.planar_graphs(5,dual=True)) # optional -- plantri - sage: dual_planar = list(graphs.planar_graphs(5,dual=False)) # optional -- plantri - sage: planar_sizes = [g.size() for g in planar] # optional -- plantri - sage: dual_planar_sizes = [g.size() for g in dual_planar] # optional -- plantri - sage: planar_sizes == dual_planar_sizes # optional -- plantri + sage: # optional - plantri + sage: planar = list(graphs.planar_graphs(5,dual=True)) + sage: dual_planar = list(graphs.planar_graphs(5,dual=False)) + sage: planar_sizes = [g.size() for g in planar] + sage: dual_planar_sizes = [g.size() for g in dual_planar] + sage: planar_sizes == dual_planar_sizes True """ if order < 0: @@ -2115,8 +2123,8 @@ def triangulations(self, order, minimum_degree=None, minimum_connectivity=None, agrees with :oeis:`A081621`:: sage: for i in range(12, 23): # optional plantri - ....: L = len(list(graphs.triangulations(i, minimum_connectivity=5))) # optional plantri - ....: print("{} {:3d}".format(i,L)) # optional plantri + ....: L = len(list(graphs.triangulations(i, minimum_connectivity=5))) + ....: print("{} {:3d}".format(i,L)) 12 1 13 0 14 1 @@ -2260,11 +2268,12 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None The cube is the only 3-connected planar quadrangulation on 8 vertices:: - sage: gen = graphs.quadrangulations(8, minimum_connectivity=3) # optional plantri - sage: g = next(gen) # optional plantri - sage: g.is_isomorphic(graphs.CubeGraph(3)) # optional plantri + sage: # optional - plantri + sage: gen = graphs.quadrangulations(8, minimum_connectivity=3) + sage: g = next(gen) + sage: g.is_isomorphic(graphs.CubeGraph(3)) True - sage: next(gen) # optional plantri + sage: next(gen) Traceback (most recent call last): ... StopIteration @@ -2273,8 +2282,8 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None agrees with :oeis:`A113201`:: sage: for i in range(4,13): # optional plantri - ....: L = len(list(graphs.quadrangulations(i))) # optional plantri - ....: print("{:2d} {:3d}".format(i,L)) # optional plantri + ....: L = len(list(graphs.quadrangulations(i))) + ....: print("{:2d} {:3d}".format(i,L)) 4 1 5 1 6 2 @@ -2355,6 +2364,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None CompleteGraph = staticmethod(basic.CompleteGraph) CompleteBipartiteGraph = staticmethod(basic.CompleteBipartiteGraph) CompleteMultipartiteGraph = staticmethod(basic.CompleteMultipartiteGraph) + CorrelationGraph = staticmethod(basic.CorrelationGraph) DiamondGraph = staticmethod(basic.DiamondGraph) GemGraph = staticmethod(basic.GemGraph) DartGraph = staticmethod(basic.DartGraph) diff --git a/src/sage/graphs/graph_generators_pyx.pyx b/src/sage/graphs/graph_generators_pyx.pyx index 8b5b68b7d26..060ea9275c6 100644 --- a/src/sage/graphs/graph_generators_pyx.pyx +++ b/src/sage/graphs/graph_generators_pyx.pyx @@ -55,8 +55,8 @@ def RandomGNP(n, p, bint directed=False, bint loops=False, seed=None): TESTS:: - sage: from numpy import mean - sage: abs(mean([RandomGNP(200, .2).density() for i in range(30)]) - .2) < .001 + sage: from numpy import mean # needs numpy + sage: abs(mean([RandomGNP(200, .2).density() for i in range(30)]) - .2) < .001 # needs numpy True sage: RandomGNP(150, .2, loops=True) Traceback (most recent call last): diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index fe1de72dcc5..193afc9c4eb 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -185,8 +185,9 @@ def from_seidel_adjacency_matrix(G, M): sage: from sage.graphs.graph_input import from_seidel_adjacency_matrix sage: g = Graph() - sage: from_seidel_adjacency_matrix(g, graphs.PetersenGraph().seidel_adjacency_matrix()) - sage: g.is_isomorphic(graphs.PetersenGraph()) + sage: sam = graphs.PetersenGraph().seidel_adjacency_matrix() # needs sage.modules + sage: from_seidel_adjacency_matrix(g, sam) # needs sage.modules + sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules True """ from sage.structure.element import is_Matrix @@ -235,8 +236,8 @@ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): sage: from sage.graphs.graph_input import from_adjacency_matrix sage: g = Graph() - sage: from_adjacency_matrix(g, graphs.PetersenGraph().adjacency_matrix()) - sage: g.is_isomorphic(graphs.PetersenGraph()) + sage: from_adjacency_matrix(g, graphs.PetersenGraph().adjacency_matrix()) # needs sage.modules + sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules True """ from sage.structure.element import is_Matrix @@ -311,8 +312,8 @@ def from_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False): sage: from sage.graphs.graph_input import from_incidence_matrix sage: g = Graph() - sage: from_incidence_matrix(g, graphs.PetersenGraph().incidence_matrix()) - sage: g.is_isomorphic(graphs.PetersenGraph()) + sage: from_incidence_matrix(g, graphs.PetersenGraph().incidence_matrix()) # needs sage.modules + sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules True """ from sage.structure.element import is_Matrix @@ -377,38 +378,37 @@ def from_oriented_incidence_matrix(G, M, loops=False, multiedges=False, weighted sage: from sage.graphs.graph_input import from_oriented_incidence_matrix sage: g = DiGraph() - sage: from_oriented_incidence_matrix(g, digraphs.Circuit(10).incidence_matrix()) - sage: g.is_isomorphic(digraphs.Circuit(10)) + sage: im = digraphs.Circuit(10).incidence_matrix() # needs sage.modules + sage: from_oriented_incidence_matrix(g, im) # needs sage.modules + sage: g.is_isomorphic(digraphs.Circuit(10)) # needs sage.modules True TESTS: Fix bug reported in :trac:`22985`:: - sage: DiGraph(matrix ([[1,0,0,1],[0,0,1,1],[0,0,1,1]]).transpose()) + sage: DiGraph(matrix ([[1,0,0,1],[0,0,1,1],[0,0,1,1]]).transpose()) # needs sage.modules Traceback (most recent call last): ... ValueError: each column represents an edge: -1 goes to 1 Handle incidence matrix containing a column with only zeros (:trac:`29275`):: - sage: m = Matrix([[0,1],[0,-1],[0,0]]) - sage: m + sage: m = Matrix([[0,1],[0,-1],[0,0]]); m # needs sage.modules [ 0 1] [ 0 -1] [ 0 0] - sage: G = DiGraph(m,format='incidence_matrix') - sage: list(G.edges(sort=True, labels=False)) + sage: G = DiGraph(m, format='incidence_matrix') # needs sage.modules + sage: list(G.edges(sort=True, labels=False)) # needs sage.modules [(1, 0)] Handle incidence matrix [[1],[-1]] (:trac:`29275`):: - sage: m = Matrix([[1],[-1]]) - sage: m + sage: m = Matrix([[1],[-1]]); m # needs sage.modules [ 1] [-1] - sage: G = DiGraph(m,format='incidence_matrix') - sage: list(G.edges(sort=True, labels=False)) + sage: G = DiGraph(m, format='incidence_matrix') # needs sage.modules + sage: list(G.edges(sort=True, labels=False)) # needs sage.modules [(1, 0)] """ from sage.structure.element import is_Matrix @@ -613,6 +613,7 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, Feeding a :class:`Graph` with a NetworkX ``Graph``:: + sage: # needs networkx sage: from sage.graphs.graph_input import from_networkx_graph sage: import networkx sage: G = Graph() @@ -625,6 +626,7 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, Feeding a :class:`Graph` with a NetworkX ``MultiGraph``:: + sage: # needs networkx sage: G = Graph() sage: gnx = networkx.MultiGraph() sage: _ = gnx.add_edge(0, 1) @@ -640,6 +642,7 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, When feeding a :class:`Graph` `G` with a NetworkX ``DiGraph`` `D`, `G` has one edge `(u, v)` whenever `D` has arc `(u, v)` or `(v, u)` or both:: + sage: # needs networkx sage: G = Graph() sage: D = networkx.DiGraph() sage: _ = D.add_edge(0, 1) @@ -656,6 +659,7 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, number of edges between `u` and `v` in `G` is the maximum between the number of arcs `(u, v)` and the number of arcs `(v, u)` in D`:: + sage: # needs networkx sage: G = Graph() sage: D = networkx.MultiDiGraph() sage: _ = D.add_edge(0, 1) @@ -669,6 +673,7 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, Feeding a :class:`DiGraph` with a NetworkX ``DiGraph``:: + sage: # needs networkx sage: from sage.graphs.graph_input import from_networkx_graph sage: import networkx sage: G = DiGraph() @@ -681,6 +686,7 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, Feeding a :class:`DiGraph` with a NetworkX ``MultiDiGraph``:: + sage: # needs networkx sage: G = DiGraph() sage: gnx = networkx.MultiDiGraph() sage: _ = gnx.add_edge(0, 1) @@ -696,6 +702,7 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, When feeding a :class:`DiGraph` `G` with a NetworkX ``Graph`` `H`, `G` has both arcs `(u, v)` and `(v, u)` if `G` has edge `(u, v)`:: + sage: # needs networkx sage: G = DiGraph() sage: H = networkx.Graph() sage: _ = H.add_edge(0, 1) @@ -707,6 +714,7 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, has `k` arcs `(u, v)` and `k` arcs `(v, u)` if `H` has `k` edges `(u, v)`, unless parameter ``multiedges`` is set to ``False``:: + sage: # needs networkx sage: G = DiGraph() sage: H = networkx.MultiGraph() sage: _ = H.add_edge(0, 1) @@ -736,7 +744,7 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, ``DiGraph`` or ``MultiDiGraph``:: sage: from sage.graphs.graph_input import from_networkx_graph - sage: from_networkx_graph(Graph(), "bar") + sage: from_networkx_graph(Graph(), "bar") # needs networkx Traceback (most recent call last): ... ValueError: the second parameter must be a NetworkX (Multi)(Di)Graph diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index 7666151fb50..e495ca160a4 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -84,12 +84,12 @@ sage: H = graphs.HeawoodGraph() sage: H.set_latex_options( - ....: graphic_size=(5,5), - ....: vertex_size=0.2, - ....: edge_thickness=0.04, - ....: edge_color='green', - ....: vertex_color='green', - ....: vertex_label_color='red' + ....: graphic_size=(5,5), + ....: vertex_size=0.2, + ....: edge_thickness=0.04, + ....: edge_color='green', + ....: vertex_color='green', + ....: vertex_label_color='red' ....: ) At this point, ``view(H)`` should call ``pdflatex`` to process the string @@ -265,49 +265,50 @@ package. So it is worth viewing this in the notebook to see the effects of various defaults and choices.:: - sage: var('x y u w') # optional - sage.symbolic + sage: # needs sage.symbolic + sage: var('x y u w') (x, y, u, w) sage: G = Graph(loops=True) - sage: for i in range(5): # optional - sage.symbolic + sage: for i in range(5): ....: for j in range(i+1, 5): ....: G.add_edge((i, j), label=(x^i*y^j).expand()) - sage: G.add_edge((0,0), label=sin(u)) # optional - sage.symbolic - sage: G.add_edge((4,4), label=w^5) # optional - sage.symbolic + sage: G.add_edge((0,0), label=sin(u)) + sage: G.add_edge((4,4), label=w^5) sage: G.set_pos(G.layout_circular()) sage: G.set_latex_options( - ....: units='in', - ....: graphic_size=(8,8), - ....: margins=(1,2,2,1), - ....: scale=0.5, - ....: vertex_color='0.8', - ....: vertex_colors={1:'aqua', 3:'y', 4:'#0000FF'}, - ....: vertex_fill_color='blue', - ....: vertex_fill_colors={1:'green', 3:'b', 4:'#FF00FF'}, - ....: vertex_label_color='brown', - ....: vertex_label_colors={0:'g',1:'purple',2:'#007F00'}, - ....: vertex_shape='diamond', - ....: vertex_shapes={1:'rectangle', 2:'sphere', 3:'sphere', 4:'circle'}, - ....: vertex_size=0.3, - ....: vertex_sizes={0:1.0, 2:0.3, 4:1.0}, - ....: vertex_label_placements = {2:(0.6, 180), 4:(0,45)}, - ....: edge_color='purple', - ....: edge_colors={(0,2):'g',(3,4):'red'}, - ....: edge_fills=True, - ....: edge_fill_color='green', - ....: edge_label_colors={(2,3):'y',(0,4):'blue'}, - ....: edge_thickness=0.05, - ....: edge_thicknesses={(3,4):0.2, (0,4):0.02}, - ....: edge_labels=True, - ....: edge_label_sloped=True, - ....: edge_label_slopes={(0,3):False, (2,4):False}, - ....: edge_label_placement=0.50, - ....: edge_label_placements={(0,4):'above', (2,3):'left', (0,0):'above', (4,4):'below'}, - ....: loop_placement=(2.0, 'NO'), - ....: loop_placements={4:(8.0, 'EA')} + ....: units='in', + ....: graphic_size=(8,8), + ....: margins=(1,2,2,1), + ....: scale=0.5, + ....: vertex_color='0.8', + ....: vertex_colors={1:'aqua', 3:'y', 4:'#0000FF'}, + ....: vertex_fill_color='blue', + ....: vertex_fill_colors={1:'green', 3:'b', 4:'#FF00FF'}, + ....: vertex_label_color='brown', + ....: vertex_label_colors={0:'g',1:'purple',2:'#007F00'}, + ....: vertex_shape='diamond', + ....: vertex_shapes={1:'rectangle', 2:'sphere', 3:'sphere', 4:'circle'}, + ....: vertex_size=0.3, + ....: vertex_sizes={0:1.0, 2:0.3, 4:1.0}, + ....: vertex_label_placements = {2:(0.6, 180), 4:(0,45)}, + ....: edge_color='purple', + ....: edge_colors={(0,2):'g',(3,4):'red'}, + ....: edge_fills=True, + ....: edge_fill_color='green', + ....: edge_label_colors={(2,3):'y',(0,4):'blue'}, + ....: edge_thickness=0.05, + ....: edge_thicknesses={(3,4):0.2, (0,4):0.02}, + ....: edge_labels=True, + ....: edge_label_sloped=True, + ....: edge_label_slopes={(0,3):False, (2,4):False}, + ....: edge_label_placement=0.50, + ....: edge_label_placements={(0,4):'above', (2,3):'left', (0,0):'above', (4,4):'below'}, + ....: loop_placement=(2.0, 'NO'), + ....: loop_placements={4:(8.0, 'EA')} ....: ) sage: from sage.graphs.graph_latex import check_tkz_graph sage: check_tkz_graph() # random - depends on TeX installation - sage: print(latex(G)) # optional - sage.symbolic + sage: print(latex(G)) \begin{tikzpicture} \definecolor{cv0}{rgb}{0.8,0.8,0.8} \definecolor{cfv0}{rgb}{0.0,0.0,1.0} diff --git a/src/sage/graphs/graph_list.py b/src/sage/graphs/graph_list.py index d22a639adb9..6994a821948 100644 --- a/src/sage/graphs/graph_list.py +++ b/src/sage/graphs/graph_list.py @@ -258,17 +258,17 @@ def to_graphics_array(graph_list, **kwds): sage: glist = [] sage: for i in range(999): ....: glist.append(graphs.RandomGNP(6, .45)) - sage: garray = graphs_list.to_graphics_array(glist) - sage: garray.nrows(), garray.ncols() + sage: garray = graphs_list.to_graphics_array(glist) # needs sage.plot + sage: garray.nrows(), garray.ncols() # needs sage.plot (250, 4) See the .plot() or .show() documentation for an individual graph for options, all of which are available from :func:`to_graphics_array`:: sage: glist = [] - sage: for _ in range(10): + sage: for _ in range(10): # needs networkx ....: glist.append(graphs.RandomLobster(41, .3, .4)) - sage: graphs_list.to_graphics_array(glist, layout='spring', vertex_size=20) + sage: graphs_list.to_graphics_array(glist, layout='spring', vertex_size=20) # needs networkx sage.plot Graphics Array of size 3 x 4 """ from sage.graphs import graph @@ -342,7 +342,7 @@ def show_graphs(graph_list, **kwds): Show the graphs in a graphics array:: - sage: graphs_list.show_graphs(glist) + sage: graphs_list.show_graphs(glist) # needs sage.plot Example where more than one graphics array is used:: @@ -350,15 +350,15 @@ def show_graphs(graph_list, **kwds): sage: g = gq.get_graphs_list() sage: len(g) 34 - sage: graphs_list.show_graphs(g) + sage: graphs_list.show_graphs(g) # needs sage.plot See the .plot() or .show() documentation for an individual graph for options, all of which are available from :func:`to_graphics_array`:: sage: glist = [] - sage: for _ in range(10): + sage: for _ in range(10): # needs networkx ....: glist.append(graphs.RandomLobster(41, .3, .4)) - sage: graphs_list.show_graphs(glist, layout='spring', vertex_size=20) + sage: graphs_list.show_graphs(glist, layout='spring', vertex_size=20) # needs sage.plot """ graph_list = list(graph_list) for i in range(len(graph_list) // 20 + 1): diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index afe875945ff..7908454db54 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.plot r""" Graph plotting @@ -168,8 +168,7 @@ 'Which graphviz layout program to use -- one of ' '"circo", "dot", "fdp", "neato", or "twopi".', 'by_component': - 'Whether to do the spring layout by connected component -- a boolean.', - } + 'Whether to do the spring layout by connected component -- a boolean.'} graphplot_options = layout_options.copy() @@ -225,8 +224,7 @@ 'graph_border': 'Whether or not to draw a frame around the graph.', 'edge_labels_background': - 'The color of the background of the edge labels.', - }) + 'The color of the background of the edge labels.'}) _PLOT_OPTIONS_TABLE = "" @@ -235,9 +233,7 @@ __doc__ = __doc__.format(PLOT_OPTIONS_TABLE=_PLOT_OPTIONS_TABLE) -DEFAULT_SHOW_OPTIONS = { - 'figsize' : (4, 4) - } +DEFAULT_SHOW_OPTIONS = {'figsize': (4, 4)} DEFAULT_PLOT_OPTIONS = { 'vertex_size' : 200, @@ -258,8 +254,7 @@ 'dist' : .075, 'max_dist' : 1.5, 'loop_size' : .075, - 'edge_labels_background' : 'white' - } + 'edge_labels_background' : 'white'} class GraphPlot(SageObject): @@ -582,7 +577,7 @@ def set_edges(self, **edge_options): Set edge plotting parameters for the ``GraphPlot`` object. This function is called by the constructor but can also be called to - update the vertex options of an existing ``GraphPlot`` object. + update the edge options of an existing ``GraphPlot`` object. Note that the changes are cumulative. EXAMPLES:: @@ -719,8 +714,8 @@ def set_edges(self, **edge_options): if 'edge_style' in self._options: from sage.plot.misc import get_matplotlib_linestyle eoptions['linestyle'] = get_matplotlib_linestyle( - self._options['edge_style'], - return_type='long') + self._options['edge_style'], + return_type='long') if 'edge_thickness' in self._options: eoptions['thickness'] = self._options['edge_thickness'] @@ -832,20 +827,20 @@ def set_edges(self, **edge_options): # Compute perpendicular bisector p1 = self._pos[a] p2 = self._pos[b] - m = ((p1[0] + p2[0])/2., (p1[1] + p2[1])/2.) # midpoint + m = ((p1[0] + p2[0]) / 2., (p1[1] + p2[1]) / 2.) # midpoint if not p1[1] == p2[1]: - s = (p1[0] - p2[0])/(p2[1] - p1[1]) # perp slope + s = (p1[0] - p2[0]) / (p2[1] - p1[1]) # perp slope def y(x): - return s*(x - m[0]) + m[1] # perp bisector line + return s * (x - m[0]) + m[1] # perp bisector line # f, g are functions to determine x-values of point # on line y at distance d from point m (on each side) def f(d): - return sqrt(d**2/(1. + s**2)) + m[0] + return sqrt(d**2 / (1. + s**2)) + m[0] def g(d): - return -sqrt(d**2/(1. + s**2)) + m[0] + return -sqrt(d**2 / (1. + s**2)) + m[0] odd_x = f even_x = g @@ -897,31 +892,31 @@ def even_xy(d): even_end = ph(even_xy(k), p2, vr)[1] self._plot_components['edges'].append( arrow(path=[[odd_start, odd_xy(k), odd_end]], - head=local_labels[2*i][2], zorder=1, - rgbcolor=local_labels[2*i][1], + head=local_labels[2 * i][2], zorder=1, + rgbcolor=local_labels[2 * i][1], **eoptions)) self._plot_components['edges'].append( arrow(path=[[even_start, even_xy(k), even_end]], - head=local_labels[2*i + 1][2], zorder=1, - rgbcolor=local_labels[2*i + 1][1], + head=local_labels[2 * i + 1][2], zorder=1, + rgbcolor=local_labels[2 * i + 1][1], **eoptions)) else: self._plot_components['edges'].append( bezier_path([[p1, odd_xy(k), p2]], zorder=1, - rgbcolor=local_labels[2*i][1], + rgbcolor=local_labels[2 * i][1], **eoptions)) self._plot_components['edges'].append( bezier_path([[p1, even_xy(k), p2]], zorder=1, - rgbcolor=local_labels[2*i + 1][1], + rgbcolor=local_labels[2 * i + 1][1], **eoptions)) if labels: j = k / 2.0 bg = self._options['edge_labels_background'] self._plot_components['edge_labels'].append( - text(local_labels[2*i][0], odd_xy(j), + text(local_labels[2 * i][0], odd_xy(j), background_color=bg)) self._plot_components['edge_labels'].append( - text(local_labels[2*i + 1][0], even_xy(j), + text(local_labels[2 * i + 1][0], even_xy(j), background_color=bg)) if len_local_labels % 2: # draw line for last odd @@ -941,7 +936,7 @@ def even_xy(d): bg = self._options['edge_labels_background'] self._plot_components['edge_labels'].append( text(str(edges_to_draw[a, b][0][0]), - [(C[0] + D[0])/2., (C[1] + D[1])/2.], + [(C[0] + D[0]) / 2., (C[1] + D[1]) / 2.], background_color=bg)) elif is_directed: self._plot_components['edges'].append( @@ -959,8 +954,8 @@ def even_xy(d): bg = self._options['edge_labels_background'] self._plot_components['edge_labels'].append( text(str(edges_to_draw[a, b][0][0]), - [(self._pos[a][0] + self._pos[b][0])/2., - (self._pos[a][1] + self._pos[b][1])/2.], + [(self._pos[a][0] + self._pos[b][0]) / 2., + (self._pos[a][1] + self._pos[b][1]) / 2.], background_color=bg)) def _polar_hack_for_multidigraph(self, A, B, VR): @@ -991,7 +986,6 @@ def _polar_hack_for_multidigraph(self, A, B, VR): sage: GP._polar_hack_for_multidigraph((int(0), int(1)), ....: (int(2), int(2)), .1) ([0.08..., 1.04...], [1.91..., 1.95...]) - """ D = [float(B[i] - A[i]) for i in range(2)] R = sqrt(D[0]**2 + D[1]**2) @@ -1415,7 +1409,7 @@ def plot(self, **kwds): sage: p = graphs.PetersenGraph().plot(egabrag='garbage') Traceback (most recent call last): ... - ValueError: Invalid input 'egabrag=garbage' + ValueError: invalid input 'egabrag=garbage' Make sure that no graphics primitive is clipped:: @@ -1441,7 +1435,7 @@ def plot(self, **kwds): # Check the arguments for o in options: if o not in graphplot_options and o not in G._extra_kwds: - raise ValueError("Invalid input '{}={}'".format(o, options[o])) + raise ValueError("invalid input '{}={}'".format(o, options[o])) for comp in self._plot_components.values(): if not isinstance(comp, list): @@ -1488,13 +1482,12 @@ def layout_tree(self, root, orientation): sage: T = Graph() sage: T.add_edges(G.min_spanning_tree(starting_vertex=0)) sage: T.show(layout='tree', tree_root=0) # indirect doctest - """ T = self._graph if not self._graph.is_tree(): - raise RuntimeError("Cannot use tree layout on this graph: " - "self.is_tree() returns False.") + raise RuntimeError("cannot use tree layout on this graph: " + "self.is_tree() returns False") children = {root: T.neighbors(root)} @@ -1544,7 +1537,7 @@ def slide(v, dx): if x < ox: slide(p, ox - x) x = ox - obstruction[y] = x+1 + obstruction[y] = x + 1 continue t = C.pop() diff --git a/src/sage/graphs/graph_plot_js.py b/src/sage/graphs/graph_plot_js.py index 3843cafec07..3bcabb58152 100644 --- a/src/sage/graphs/graph_plot_js.py +++ b/src/sage/graphs/graph_plot_js.py @@ -164,15 +164,17 @@ def gen_html_code(G, EXAMPLES:: - sage: graphs.RandomTree(50).show(method="js") # optional -- internet + sage: graphs.RandomTree(50).show(method="js") # optional - internet, needs sage.plot sage: g = graphs.PetersenGraph() - sage: g.show(method="js", vertex_partition=g.coloring()) # optional -- internet + sage: g.show(method="js", vertex_partition=g.coloring()) # optional - internet, needs sage.plot - sage: graphs.DodecahedralGraph().show(method="js", force_spring_layout=True) # optional -- internet + sage: graphs.DodecahedralGraph().show(method="js", # optional - internet, needs sage.plot + ....: force_spring_layout=True) - sage: graphs.DodecahedralGraph().show(method="js") # optional -- internet + sage: graphs.DodecahedralGraph().show(method="js") # optional - internet, needs sage.plot + sage: # needs sage.combinat sage: g = digraphs.DeBruijn(2, 2) sage: g.allow_multiple_edges(True) sage: g.add_edge("10", "10", "a") @@ -180,10 +182,10 @@ def gen_html_code(G, sage: g.add_edge("10", "10", "c") sage: g.add_edge("10", "10", "d") sage: g.add_edge("01", "11", "1") - sage: g.show(method="js", vertex_labels=True,edge_labels=True, + sage: g.show(method="js", vertex_labels=True, edge_labels=True, # optional - internet, needs sage.plot ....: link_distance=200, gravity=.05, charge=-500, ....: edge_partition=[[("11", "12", "2"), ("21", "21", "a")]], - ....: edge_thickness=4) # optional -- internet + ....: edge_thickness=4) TESTS:: diff --git a/src/sage/graphs/hyperbolicity.pyx b/src/sage/graphs/hyperbolicity.pyx index a76b5477961..d256c01e870 100644 --- a/src/sage/graphs/hyperbolicity.pyx +++ b/src/sage/graphs/hyperbolicity.pyx @@ -146,7 +146,7 @@ Methods # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** from libc.string cimport memset @@ -157,8 +157,6 @@ from memory_allocator cimport MemoryAllocator from sage.graphs.distances_all_pairs cimport c_distances_all_pairs from sage.arith.misc import binomial from sage.rings.integer_ring import ZZ -from sage.rings.real_mpfr import RR -from sage.data_structures.bitset import Bitset from sage.graphs.base.static_sparse_graph cimport short_digraph from sage.graphs.base.static_sparse_graph cimport init_short_digraph from sage.graphs.base.static_sparse_graph cimport free_short_digraph @@ -329,8 +327,7 @@ cdef tuple hyperbolicity_basic_algorithm(int N, # Last, we return the computed value and the certificate if h_LB != -1: return (h_LB, certificate) - else: - return (-1, []) + return (-1, []) ###################################################################### @@ -827,10 +824,10 @@ cdef tuple hyperbolicity_BCCM(int N, # Last, we return the computed value and the certificate if not certificate: return (-1, [], h_UB) - else: - # When using far-apart pairs, the loops may end before improving the - # upper-bound - return (h, certificate, h_UB) + + # When using far-apart pairs, the loops may end before improving the + # upper-bound + return (h, certificate, h_UB) ###################################################################### @@ -1045,10 +1042,10 @@ cdef tuple hyperbolicity_CCL(int N, # Last, we return the computed value and the certificate if not certificate: return (-1, [], h_UB) - else: - # When using far-apart pairs, the loops may end before improving the - # upper-bound - return (h, certificate, h_UB if GOTO_RETURN else h) + + # When using far-apart pairs, the loops may end before improving the + # upper-bound + return (h, certificate, h_UB if GOTO_RETURN else h) def hyperbolicity(G, @@ -1288,6 +1285,8 @@ def hyperbolicity(G, elif approximation_factor == 1.0: pass elif algorithm in ['CCL', 'CCL+FA', 'BCCM']: + from sage.rings.real_mpfr import RR + if approximation_factor not in RR or approximation_factor < 1.0: raise ValueError("the approximation factor must be >= 1.0") else: @@ -1298,6 +1297,8 @@ def hyperbolicity(G, elif additive_gap == 0.0: pass elif algorithm in ['CCL', 'CCL+FA', 'BCCM']: + from sage.rings.real_mpfr import RR + if additive_gap not in RR or additive_gap < 0.0: raise ValueError("the additive gap must be a real positive number") else: diff --git a/src/sage/graphs/hypergraph_generators.py b/src/sage/graphs/hypergraph_generators.py index e90beaee76d..3d6a7d28cd6 100644 --- a/src/sage/graphs/hypergraph_generators.py +++ b/src/sage/graphs/hypergraph_generators.py @@ -217,7 +217,7 @@ def CompleteUniform(self, n, k): sage: h = hypergraphs.CompleteUniform(5, 2); h Incidence structure with 5 points and 10 blocks - sage: len(h.packing()) + sage: len(h.packing()) # needs sage.numerical.mip 2 """ from sage.combinat.designs.incidence_structures import IncidenceStructure @@ -306,13 +306,14 @@ def BinomialRandomUniform(self, n, k, p): EXAMPLES:: - sage: hypergraphs.BinomialRandomUniform(50, 3, 1).num_blocks() + sage: hypergraphs.BinomialRandomUniform(50, 3, 1).num_blocks() # needs numpy 19600 - sage: hypergraphs.BinomialRandomUniform(50, 3, 0).num_blocks() + sage: hypergraphs.BinomialRandomUniform(50, 3, 0).num_blocks() # needs numpy 0 TESTS:: + sage: # needs numpy sage: hypergraphs.BinomialRandomUniform(50, 3, -0.1) Traceback (most recent call last): ... @@ -355,7 +356,7 @@ def BinomialRandomUniform(self, n, k, p): raise ValueError("edge probability should be in [0,1]") import numpy.random as nrn - from sage.functions.other import binomial + from sage.arith.misc import binomial m = nrn.binomial(binomial(nverts, uniformity), p) return hypergraphs.UniformRandomUniform(n, k, m) diff --git a/src/sage/graphs/independent_sets.pyx b/src/sage/graphs/independent_sets.pyx index d894f1706ed..23c8677b34a 100644 --- a/src/sage/graphs/independent_sets.pyx +++ b/src/sage/graphs/independent_sets.pyx @@ -162,7 +162,7 @@ cdef class IndependentSets: ....: IS2.extend(map(Set, list(G.subgraph_search_iterator(Graph(n), induced=True, return_graphs=False)))) ....: if len(IS) != len(set(IS2)): ....: raise ValueError("something goes wrong") - sage: for i in range(5): + sage: for i in range(5): # needs sage.modules ....: check_with_subgraph_search(graphs.RandomGNP(11, .3)) Empty graph:: diff --git a/src/sage/graphs/isgci.py b/src/sage/graphs/isgci.py index 147e2ba2778..e19c4a8103e 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -135,28 +135,28 @@ * - Apex - - :meth:`~Graph.is_apex()`, - :meth:`~Graph.apex_vertices()` + - :meth:`~sage.graphs.graph.Graph.is_apex`, + :meth:`~sage.graphs.graph.Graph.apex_vertices` * - AT_free - - :meth:`~Graph.is_asteroidal_triple_free` + - :meth:`~sage.graphs.graph.Graph.is_asteroidal_triple_free` * - Biconnected - - :meth:`~Graph.is_biconnected`, - :meth:`~GenericGraph.blocks_and_cut_vertices`, - :meth:`~GenericGraph.blocks_and_cuts_tree` + - :meth:`~sage.graphs.graph.Graph.is_biconnected`, + :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices`, + :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cuts_tree` * - BinaryTrees - :meth:`~sage.graphs.graph_generators.GraphGenerators.BalancedTree`, - :meth:`~Graph.is_tree` + :meth:`~sage.graphs.graph.Graph.is_tree` * - Bipartite - :meth:`~sage.graphs.graph_generators.GraphGenerators.BalancedTree`, - :meth:`~sage.graphs.graph.Graph.is_bipartite` + :meth:`~sage.graphs.generic_graph.GenericGraph.is_bipartite` * - Block @@ -212,7 +212,7 @@ * - Polyhedral - - :meth:`~sage.graphs.generic_graph.Graph.is_polyhedral` + - :meth:`~sage.graphs.graph.Graph.is_polyhedral` * - Split diff --git a/src/sage/graphs/isoperimetric_inequalities.pyx b/src/sage/graphs/isoperimetric_inequalities.pyx index 763a2da494e..1d01e311c1c 100644 --- a/src/sage/graphs/isoperimetric_inequalities.pyx +++ b/src/sage/graphs/isoperimetric_inequalities.pyx @@ -23,7 +23,7 @@ Authors: from cysignals.signals cimport sig_on, sig_off from cysignals.memory cimport check_malloc, sig_free -from sage.graphs.base.static_sparse_graph cimport short_digraph, init_short_digraph, free_short_digraph, out_degree +from sage.graphs.base.static_sparse_graph cimport short_digraph, init_short_digraph, free_short_digraph from sage.data_structures.binary_matrix cimport * from sage.graphs.base.static_dense_graph cimport dense_graph_init @@ -209,8 +209,8 @@ def edge_isoperimetric_number(g): In general, for `d`-regular graphs the edge-isoperimetric number is `d` times larger than the Cheeger constant of the graph:: - sage: g = graphs.RandomRegular(3, 10) - sage: g.edge_isoperimetric_number() == g.cheeger_constant() * 3 + sage: g = graphs.RandomRegular(3, 10) # needs networkx + sage: g.edge_isoperimetric_number() == g.cheeger_constant() * 3 # needs networkx True And the edge-isoperimetric constant of a disconnected graph is `0`:: diff --git a/src/sage/graphs/line_graph.pyx b/src/sage/graphs/line_graph.pyx index 426bb4feaf3..cef56940d38 100644 --- a/src/sage/graphs/line_graph.pyx +++ b/src/sage/graphs/line_graph.pyx @@ -176,8 +176,8 @@ def is_line_graph(g, certificate=False): This is indeed the subgraph returned:: - sage: C = graphs.PetersenGraph().is_line_graph(certificate=True)[1] - sage: C.is_isomorphic(graphs.ClawGraph()) + sage: C = graphs.PetersenGraph().is_line_graph(certificate=True)[1] # needs sage.modules + sage: C.is_isomorphic(graphs.ClawGraph()) # needs sage.modules True The house graph is a line graph:: @@ -188,10 +188,11 @@ def is_line_graph(g, certificate=False): But what is the graph whose line graph is the house ?:: + sage: # needs sage.modules sage: is_line, R, isom = g.is_line_graph(certificate=True) sage: R.sparse6_string() ':DaHI~' - sage: R.show() + sage: R.show() # needs sage.plot sage: isom {0: (0, 1), 1: (0, 2), 2: (1, 3), 3: (2, 3), 4: (3, 4)} @@ -201,8 +202,8 @@ def is_line_graph(g, certificate=False): sage: g = 2 * graphs.CycleGraph(3) sage: gl = g.line_graph().relabel(inplace=False) - sage: new_g = gl.is_line_graph(certificate=True)[1] - sage: g.line_graph().is_isomorphic(gl) + sage: new_g = gl.is_line_graph(certificate=True)[1] # needs sage.modules + sage: g.line_graph().is_isomorphic(gl) # needs sage.modules True Verify that :trac:`29740` is fixed:: @@ -231,15 +232,13 @@ def is_line_graph(g, certificate=False): R, isom = root_graph(g) if certificate: return True, R, isom - else: - return True + return True except ValueError as VE: if str(VE) == "this graph is not a line graph !": # g is not a line graph if certificate: return False, get_certificate(g) - else: - return False + return False raise VE # g is not connected, so we apply the above procedure to each connected @@ -255,15 +254,13 @@ def is_line_graph(g, certificate=False): # gg is not a line graph if certificate: return False, get_certificate(gg) - else: - return False + return False raise VE if certificate: _, isom = g.is_isomorphic(R.line_graph(labels=False), certificate=True) return True, R, isom - else: - return True + return True def line_graph(g, labels=True): @@ -309,12 +306,12 @@ def line_graph(g, labels=True): sage: h = g.line_graph() sage: h.vertices(sort=True) [(0, 1, None), - (0, 2, None), - (0, 3, None), - (1, 2, None), - (1, 3, None), - (2, 3, None)] - sage: h.am() + (0, 2, None), + (0, 3, None), + (1, 2, None), + (1, 3, None), + (2, 3, None)] + sage: h.am() # needs sage.modules [0 1 1 1 1 0] [1 0 1 1 0 1] [1 1 0 0 1 1] @@ -324,17 +321,17 @@ def line_graph(g, labels=True): sage: h2 = g.line_graph(labels=False) sage: h2.vertices(sort=True) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: h2.am() == h.am() + sage: h2.am() == h.am() # needs sage.modules True sage: g = DiGraph([[1..4], lambda i,j: i < j]) sage: h = g.line_graph() sage: h.vertices(sort=True) [(1, 2, None), - (1, 3, None), - (1, 4, None), - (2, 3, None), - (2, 4, None), - (3, 4, None)] + (1, 3, None), + (1, 4, None), + (2, 3, None), + (2, 4, None), + (3, 4, None)] sage: h.edges(sort=True) [((1, 2, None), (2, 3, None), None), ((1, 2, None), (2, 4, None), None), @@ -365,54 +362,52 @@ def line_graph(g, labels=True): G.add_edges((e, f) for e in g.incoming_edge_iterator(v, labels=labels) for f in g.outgoing_edge_iterator(v, labels=labels)) return G - else: - from sage.graphs.graph import Graph - G = Graph() - - # We must sort the edges' endpoints so that (1,2,None) is seen as the - # same edge as (2,1,None). - # - # We do so by comparing hashes, just in case all the natural order (<) - # on vertices would not be a total order (for instance when vertices are - # sets). If two adjacent vertices have the same hash, then we store the - # pair in the dictionary of conflicts - # 1) List of vertices in the line graph - - for e in g.edge_iterator(labels=labels): + from sage.graphs.graph import Graph + G = Graph() + + # We must sort the edges' endpoints so that (1,2,None) is seen as the + # same edge as (2,1,None). + # + # We do so by comparing hashes, just in case all the natural order (<) + # on vertices would not be a total order (for instance when vertices are + # sets). If two adjacent vertices have the same hash, then we store the + # pair in the dictionary of conflicts + + # 1) List of vertices in the line graph + for e in g.edge_iterator(labels=labels): + if hash(e[0]) < hash(e[1]): + elist.append(e) + elif hash(e[0]) > hash(e[1]): + elist.append((e[1], e[0]) + e[2:]) + else: + # Settle the conflict arbitrarily + conflicts[e] = e + conflicts[(e[1], e[0]) + e[2:]] = e + elist.append(e) + + G.add_vertices(elist) + + # 2) adjacencies in the line graph + for v in g: + elist = [] + + # Add the edge to the list, according to hashes, as previously + for e in g.edge_iterator(v, labels=labels): if hash(e[0]) < hash(e[1]): elist.append(e) elif hash(e[0]) > hash(e[1]): elist.append((e[1], e[0]) + e[2:]) else: - # Settle the conflict arbitrarily - conflicts[e] = e - conflicts[(e[1], e[0]) + e[2:]] = e - elist.append(e) - - G.add_vertices(elist) + elist.append(conflicts[e]) - # 2) adjacencies in the line graph - for v in g: - elist = [] - - # Add the edge to the list, according to hashes, as previously - for e in g.edge_iterator(v, labels=labels): - if hash(e[0]) < hash(e[1]): - elist.append(e) - elif hash(e[0]) > hash(e[1]): - elist.append((e[1], e[0]) + e[2:]) - else: - elist.append(conflicts[e]) - - # All pairs of elements in elist are edges of the - # line graph - while elist: - x = elist.pop() - for y in elist: - G.add_edge(x, y) + # All pairs of elements in elist are edges of the line graph + while elist: + x = elist.pop() + for y in elist: + G.add_edge(x, y) - return G + return G def root_graph(g, verbose=False): @@ -442,9 +437,9 @@ def root_graph(g, verbose=False): ....: gl = g.line_graph(labels=False) ....: d = root_graph(gl) sage: for i,g in enumerate(graphs(6)): # long time - ....: if not g.is_connected(): # long time - ....: continue # long time - ....: test(g) # long time + ....: if not g.is_connected(): + ....: continue + ....: test(g) Non line-graphs:: @@ -628,5 +623,4 @@ def root_graph(g, verbose=False): is_isom, isom = g.is_isomorphic(R.line_graph(labels=False), certificate=True) if is_isom: return R, isom - else: - raise ValueError(not_line_graph) + raise ValueError(not_line_graph) diff --git a/src/sage/graphs/matchpoly.pyx b/src/sage/graphs/matchpoly.pyx index 4a8c24be8ca..22361379291 100644 --- a/src/sage/graphs/matchpoly.pyx +++ b/src/sage/graphs/matchpoly.pyx @@ -32,7 +32,7 @@ Methods # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** from cysignals.memory cimport check_allocarray, sig_free @@ -41,7 +41,6 @@ from cysignals.signals cimport sig_on, sig_off from sage.rings.polynomial.polynomial_ring import polygen from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer -from sage.misc.misc_c import prod from sage.libs.flint.fmpz cimport * from sage.libs.flint.fmpz_poly cimport * @@ -217,14 +216,14 @@ def matching_polynomial(G, complement=True, name=None): cdef int i, j, d cdef fmpz_poly_t pol - cdef nverts = G.num_verts() + cdef int nverts = G.num_verts() # Using Godsil's duality theorem when the graph is dense if complement and G.density() > 0.5: # this cutoff could probably be tuned f_comp = matching_polynomial(G.complement()).list() f = x.parent().zero() - for i from 0 <= i <= nverts / 2: # implicit floor + for i in range(nverts // 2 + 1): j = nverts - 2 * i f += complete_poly(j) * f_comp[j] * (-1)**i return f @@ -329,9 +328,9 @@ def complete_poly(n): Checking the numerical results up to 20:: - sage: from sage.functions.orthogonal_polys import hermite # optional - sage.symbolic - sage: p = lambda n: 2^(-n/2)*hermite(n, x/sqrt(2)) # optional - sage.symbolic - sage: all(p(i) == complete_poly(i) for i in range(2, 20)) # optional - sage.symbolic + sage: from sage.functions.orthogonal_polys import hermite # needs sage.symbolic + sage: p = lambda n: 2^(-n/2)*hermite(n, x/sqrt(2)) # needs sage.symbolic + sage: all(p(i) == complete_poly(i) for i in range(2, 20)) # needs sage.symbolic True """ # global complete_matching_polys # if we do eventually make it a C array... diff --git a/src/sage/graphs/mcqd.pxd b/src/sage/graphs/mcqd.pxd index d8d8b01bc72..d7a2faa6d58 100644 --- a/src/sage/graphs/mcqd.pxd +++ b/src/sage/graphs/mcqd.pxd @@ -1,3 +1,5 @@ +# sage_setup: distribution = sagemath-mcqd + from libcpp cimport bool cdef extern from "mcqd.h": @@ -5,4 +7,3 @@ cdef extern from "mcqd.h": Maxclique() Maxclique(bool **, int n) void mcqdyn(int * maxclique, int& size) - diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index 4aeb71248b9..7b7fa8681fc 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -25,17 +25,31 @@ Methods ------- """ +# **************************************************************************** +# Copyright (C) 2017 Kolja Knauer <kolja.knauer@gmail.com> +# 2017 Petru Valicov <petru.valicov@lirmm.fr> +# 2017-2023 David Coudert <david.coudert@inria.fr> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from copy import copy from sage.graphs.digraph import DiGraph def strong_orientations_iterator(G): r""" - Returns an iterator over all strong orientations of a graph `G`. + Return an iterator over all strong orientations of a graph `G`. - A strong orientation of a graph is an orientation of its edges such that - the obtained digraph is strongly connected (i.e. there exist a directed path - between each pair of vertices). + A strong orientation of a graph is an orientation of its edges such that the + obtained digraph is strongly connected (i.e. there exist a directed path + between each pair of vertices). According to Robbins' theorem (see the + :wikipedia:`Robbins_theorem`), the graphs that have strong orientations are + exactly the 2-edge-connected graphs (i.e., the bridgeless graphs). ALGORITHM: @@ -84,7 +98,7 @@ def strong_orientations_iterator(G): A tree cannot be strongly oriented:: - sage: g = graphs.RandomTree(100) + sage: g = graphs.RandomTree(10) sage: len(list(g.strong_orientations_iterator())) 0 @@ -115,44 +129,37 @@ def strong_orientations_iterator(G): sage: g = graphs.PetersenGraph() sage: nr1 = len(list(g.strong_orientations_iterator())) sage: nr2 = g.tutte_polynomial()(0,2) - sage: nr1 == nr2/2 # The Tutte polynomial counts also the symmetrical orientations + sage: nr1 == nr2/2 # The Tutte polynomial counts also the symmetrical orientations True - """ # if the graph has a bridge or is disconnected, # then it cannot be strongly oriented - if G.order() < 3 or not G.is_biconnected(): + if G.order() < 3 or not G.is_connected() or any(G.bridges(labels=False)): return - V = G.vertices(sort=False) - Dg = DiGraph([V, G.edges(sort=False)], pos=G.get_pos()) + V = list(G) # compute an arbitrary spanning tree of the undirected graph - te = G.min_spanning_tree() - treeEdges = [(u, v) for u, v, _ in te] - tree_edges_set = set(treeEdges) - A = [edge for edge in G.edge_iterator(labels=False) if edge not in tree_edges_set] + T = G.subgraph(vertices=G, edges=G.min_spanning_tree(), inplace=False) + treeEdges = list(T.edges(labels=False, sort=False)) + A = [edge for edge in G.edge_iterator(labels=False) if not T.has_edge(edge)] + + # Initialize a digraph with the edges of the spanning tree doubly oriented + Dg = T.to_directed(sparse=True) + Dg.add_edges(A) # initialization of the first binary word 00...0 # corresponding to the current orientation of the non-tree edges existingAedges = [0] * len(A) - # Make the edges of the spanning tree doubly oriented - for e in treeEdges: - if Dg.has_edge(e): - Dg.add_edge(e[1], e[0]) - else: - Dg.add_edge(e) - # Generate all orientations for non-tree edges (using Gray code) # Each of these orientations can be extended to a strong orientation # of G by orienting properly the tree-edges previousWord = 0 - i = 0 # the orientation of one edge is fixed so we consider one edge less nr = 2**(len(A) - 1) - while i < nr: + for i in range(nr): word = (i >> 1) ^ i bitChanged = word ^ previousWord @@ -169,9 +176,7 @@ def strong_orientations_iterator(G): Dg.reverse_edge(A[bit][1], A[bit][0]) existingAedges[bit] = 0 # launch the algorithm for enumeration of the solutions - for sol in _strong_orientations_of_a_mixed_graph(Dg, V, treeEdges): - yield sol - i = i + 1 + yield from _strong_orientations_of_a_mixed_graph(Dg, V, treeEdges) def _strong_orientations_of_a_mixed_graph(Dg, V, E): @@ -201,9 +206,9 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E): sage: from sage.graphs.orientations import _strong_orientations_of_a_mixed_graph sage: g = graphs.CycleGraph(5) - sage: Dg = DiGraph(g) # all edges of g will be doubly oriented + sage: Dg = DiGraph(g) # all edges of g will be doubly oriented sage: it = _strong_orientations_of_a_mixed_graph(Dg, list(g), list(g.edges(labels=False, sort=False))) - sage: len(list(it)) # there are two orientations of this multigraph + sage: len(list(it)) # there are two orientations of this multigraph 2 """ length = len(E) @@ -213,7 +218,9 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E): u, v = E[i] Dg.delete_edge(u, v) if not (v in Dg.depth_first_search(u)): - del E[i] + # del E[i] in constant time + E[i] = E[-1] + E.pop() length -= 1 Dg.add_edge(u, v) Dg.delete_edge(v, u) @@ -222,7 +229,9 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E): Dg.add_edge(u, v) Dg.delete_edge(v, u) if not (u in Dg.depth_first_search(v)): - del E[i] + # del E[i] in constant time + E[i] = E[-1] + E.pop() length -= 1 boundEdges.append((u, v)) Dg.delete_edge(u, v) diff --git a/src/sage/graphs/partial_cube.py b/src/sage/graphs/partial_cube.py index bce06dee677..70456e548c9 100644 --- a/src/sage/graphs/partial_cube.py +++ b/src/sage/graphs/partial_cube.py @@ -110,8 +110,8 @@ def breadth_first_level_search(G, start): EXAMPLES:: - sage: H = digraphs.DeBruijn(3,2) - sage: list(sage.graphs.partial_cube.breadth_first_level_search(H, '00')) + sage: H = digraphs.DeBruijn(3,2) # needs sage.combinat + sage: list(sage.graphs.partial_cube.breadth_first_level_search(H, '00')) # needs sage.combinat [{'00': {'01', '02'}}, {'01': {'10', '11', '12'}, '02': {'20', '21', '22'}}, {'10': set(), @@ -162,9 +162,9 @@ def depth_first_traversal(G, start): EXAMPLES:: - sage: H = digraphs.DeBruijn(3,2) - sage: t = list(sage.graphs.partial_cube.depth_first_traversal(H, '00')) - sage: len(t) + sage: H = digraphs.DeBruijn(3,2) # needs sage.combinat + sage: t = list(sage.graphs.partial_cube.depth_first_traversal(H, '00')) # needs sage.combinat + sage: len(t) # needs sage.combinat 16 """ neighbors = G.neighbor_out_iterator @@ -342,7 +342,7 @@ def is_partial_cube(G, certificate=False): # Map vertices to components of labeled-edge graph component = {} - for i, SCC in enumerate(labeled.connected_components()): + for i, SCC in enumerate(labeled.connected_components(sort=False)): for v in SCC: component[v] = i diff --git a/src/sage/graphs/path_enumeration.pyx b/src/sage/graphs/path_enumeration.pyx index 0ef63dd0c17..6ef3e79143e 100644 --- a/src/sage/graphs/path_enumeration.pyx +++ b/src/sage/graphs/path_enumeration.pyx @@ -31,10 +31,9 @@ Functions # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from itertools import product -from sage.categories.cartesian_product import cartesian_product from sage.misc.misc_c import prod -from libcpp.vector cimport vector from libcpp.queue cimport priority_queue from libcpp.pair cimport pair from sage.rings.integer_ring import ZZ @@ -264,7 +263,7 @@ def all_paths(G, start, end, use_multiedges=False, report_edges=False, labels=Fa if report_edges and labels: path_with_labels = [] for p in all_paths: - path_with_labels.extend(cartesian_product([edge_labels[e] for e in zip(p[:-1], p[1:])])) + path_with_labels.extend(product(*[edge_labels[e] for e in zip(p[:-1], p[1:])])) return path_with_labels elif use_multiedges and G.has_multiple_edges(): multiple_all_paths = [] @@ -347,41 +346,49 @@ def shortest_simple_paths(self, source, target, weight_function=None, EXAMPLES:: - sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5, 30)]) + sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), + ....: (2, 5, 20), (3, 5, 10), (4, 5, 30)]) sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Yen")) [[1, 3, 5], [1, 2, 5], [1, 4, 5]] sage: list(g.shortest_simple_paths(1, 5, algorithm="Yen")) [[1, 2, 5], [1, 3, 5], [1, 4, 5]] sage: list(g.shortest_simple_paths(1, 1)) [[1]] - sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True, report_weight=True, labels=True)) + sage: list(g.shortest_simple_paths(1, 5, by_weight=True, + ....: report_edges=True, report_weight=True, labels=True)) [(20, [(1, 3, 10), (3, 5, 10)]), (40, [(1, 2, 20), (2, 5, 20)]), (60, [(1, 4, 30), (4, 5, 30)])] - sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", report_edges=True, report_weight=True)) + sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", + ....: report_edges=True, report_weight=True)) [(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])] sage: list(g.shortest_simple_paths(1, 5, report_edges=True, report_weight=True)) [(2, [(1, 4), (4, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 2), (2, 5)])] sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True)) [[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]] - sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", report_edges=True, labels=True)) + sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", + ....: report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]] - sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5, 30), (1, 6, 100), (5, 6, 5)]) + sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), + ....: (3, 5, 10), (4, 5, 30), (1, 6, 100), (5, 6, 5)]) sage: list(g.shortest_simple_paths(1, 6, by_weight = True)) [[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]] sage: list(g.shortest_simple_paths(1, 6, algorithm="Yen")) [[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]] - sage: list(g.shortest_simple_paths(1, 6, report_edges=True, report_weight=True, labels=True)) + sage: list(g.shortest_simple_paths(1, 6, + ....: report_edges=True, report_weight=True, labels=True)) [(1, [(1, 6, 100)]), (3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])] - sage: list(g.shortest_simple_paths(1, 6, report_edges=True, report_weight=True, labels=True, by_weight=True)) + sage: list(g.shortest_simple_paths(1, 6, by_weight=True, + ....: report_edges=True, report_weight=True, labels=True)) [(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]), (100, [(1, 6, 100)])] - sage: list(g.shortest_simple_paths(1, 6, report_edges=True, labels=True, by_weight=True)) + sage: list(g.shortest_simple_paths(1, 6, by_weight=True, + ....: report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10), (5, 6, 5)], [(1, 2, 20), (2, 5, 20), (5, 6, 5)], [(1, 4, 30), (4, 5, 30), (5, 6, 5)], @@ -433,6 +440,8 @@ def shortest_simple_paths(self, source, target, weight_function=None, [1, 2, 3, 4, 5], [1, 6, 9, 3, 4, 5], [1, 6, 9, 11, 10, 5]] + + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2, 3) sage: for u,v in G.edges(sort=True, labels=False): ....: G.set_edge_label(u, v, 1) @@ -471,6 +480,7 @@ def shortest_simple_paths(self, source, target, weight_function=None, Check for consistency of results of Yen's and Feng's:: + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2, 4) sage: s = set() sage: for p in G.shortest_simple_paths('0000', '1111', by_weight=False, algorithm='Yen'): @@ -1576,7 +1586,7 @@ def _all_paths_iterator(self, vertex, ending_vertices=None, neighbor in ending_vertices): newpath = path + [neighbor] if report_edges and labels: - for p in cartesian_product([my_dict[e] for e in zip(newpath[:-1], newpath[1:])]): + for p in product(*[my_dict[e] for e in zip(newpath[:-1], newpath[1:])]): yield list(p) elif use_multiedges and self.has_multiple_edges(): m = prod(edge_multiplicity[e] for e in zip(newpath[:-1], newpath[1:])) @@ -1600,7 +1610,7 @@ def _all_paths_iterator(self, vertex, ending_vertices=None, if path[-1] in ending_vertices: # yield good path if report_edges and labels: - for p in cartesian_product([my_dict[e] for e in zip(path[:-1], path[1:])]): + for p in product(*[my_dict[e] for e in zip(path[:-1], path[1:])]): yield list(p) elif use_multiedges and self.has_multiple_edges(): m = prod(edge_multiplicity[e] for e in zip(path[:-1], path[1:])) diff --git a/src/sage/graphs/planarity.pyx b/src/sage/graphs/planarity.pyx index b5a78f0bf14..1088a7659de 100644 --- a/src/sage/graphs/planarity.pyx +++ b/src/sage/graphs/planarity.pyx @@ -30,7 +30,7 @@ cdef extern from "planarity/graph.h": cdef int gp_SortVertices(graphP theGraph) -def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular=None): +def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False): r""" Check whether ``g`` is planar using Boyer's planarity algorithm. @@ -55,8 +55,6 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= combinatorial embedding returned (see :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding`) - - ``circular`` -- deprecated argument - EXAMPLES:: sage: G = graphs.DodecahedralGraph() @@ -72,17 +70,18 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= vertices. In fact, to try to track down a segfault, we do it twice. :: - sage: import networkx.generators.atlas # long time - sage: atlas_graphs = [Graph(i) for i in networkx.generators.atlas.graph_atlas_g()] # long time - sage: a = [i for i in [1..1252] if atlas_graphs[i].is_planar()] # long time - sage: b = [i for i in [1..1252] if atlas_graphs[i].is_planar()] # long time - sage: a == b # long time + sage: # long time, needs networkx + sage: import networkx.generators.atlas + sage: atlas_graphs = [Graph(i) for i in networkx.generators.atlas.graph_atlas_g()] + sage: a = [i for i in [1..1252] if atlas_graphs[i].is_planar()] + sage: b = [i for i in [1..1252] if atlas_graphs[i].is_planar()] + sage: a == b True There were some problems with ``set_pos`` stability in the past, so let's check if this runs without exception:: - sage: for i, g in enumerate(atlas_graphs): # long time + sage: for i, g in enumerate(atlas_graphs): # long time # needs networkx ....: if (not g.is_connected() or i == 0): ....: continue ....: _ = g.is_planar(set_embedding=True, set_pos=True) @@ -97,10 +96,7 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= ....: assert (hasattr(G, '_pos') and G._pos is not None) == set_pos, (set_embedding, set_pos) """ - if circular is not None: - from sage.misc.superseded import deprecation - deprecation(33759, 'the circular argument of is_planar is deprecated and has no effect') - + g._scream_if_not_simple() if set_pos and not g.is_connected(): raise ValueError("is_planar() cannot set vertex positions for a disconnected graph") @@ -123,9 +119,8 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= # (planarity 3 uses 1-based array indexing, with 0 representing NIL) cdef int i cdef list listto = list(g) - cdef dict ffrom = {vvv: i + 1 for i, vvv in enumerate(listto)} - cdef dict to = {i + 1: vvv for i, vvv in enumerate(listto)} - g.relabel(ffrom) + cdef dict ffrom = {vvv: i for i, vvv in enumerate(listto, start=1)} + cdef dict to = {i: vvv for i, vvv in enumerate(listto, start=1)} cdef graphP theGraph theGraph = gp_New() @@ -134,7 +129,7 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= if status != OK: raise RuntimeError("gp_InitGraph status is not ok") for u, v in g.edge_iterator(labels=False): - status = gp_AddEdge(theGraph, u, 0, v, 0) + status = gp_AddEdge(theGraph, ffrom[u], 0, ffrom[v], 0) if status == NOTOK: raise RuntimeError("gp_AddEdge status is not ok") elif status == NONEMBEDDABLE: @@ -146,15 +141,16 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= break status = gp_Embed(theGraph, EMBEDFLAGS_PLANAR) - gp_SortVertices(theGraph) - - # Use to and from mappings to relabel vertices back from the set {1,...,n} - g.relabel(to) if status == NOTOK: raise RuntimeError("status is not ok") - elif status == NONEMBEDDABLE: + + gp_SortVertices(theGraph) + + if status == NONEMBEDDABLE: # Kuratowski subgraph isolator + if not kuratowski: + return False g_dict = {} from sage.graphs.graph import Graph for i in range(1, theGraph.N + 1): @@ -165,29 +161,30 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= j = theGraph.E[j].link[1] if linked_list: g_dict[to[i]] = linked_list - G = Graph(g_dict) gp_Free(&theGraph) - if kuratowski: - return (False, G) - else: - return False - else: - if set_pos or set_embedding: - emb_dict = {} - for i in range(1, theGraph.N + 1): - linked_list = [] - j = theGraph.V[i].link[1] - while j: - linked_list.append(to[theGraph.E[j].neighbor]) - j = theGraph.E[j].link[1] - emb_dict[to[i]] = linked_list - if set_embedding: - g._embedding = emb_dict - if set_pos: - g.layout(layout='planar', save_pos=True, on_embedding=emb_dict) + G = g.__class__(data=g_dict, weighted=g._weighted, + loops=g.allows_loops(), + multiedges=g.allows_multiple_edges(), + name="Kuratowski subgraph of (%s)" % g.name()) + if g.get_pos(): + G.set_pos({u: g._pos[u] for u in g_dict}) + return (False, G) + + if set_pos or set_embedding: + emb_dict = {} + for i in range(1, theGraph.N + 1): + linked_list = [] + j = theGraph.V[i].link[1] + while j: + linked_list.append(to[theGraph.E[j].neighbor]) + j = theGraph.E[j].link[1] + emb_dict[to[i]] = linked_list + if set_embedding: + g._embedding = emb_dict + if set_pos: + g.layout(layout='planar', save_pos=True, on_embedding=emb_dict) - gp_Free(&theGraph) - if kuratowski: - return (True, None) - else: - return True + gp_Free(&theGraph) + if kuratowski: + return (True, None) + return True diff --git a/src/sage/graphs/pq_trees.py b/src/sage/graphs/pq_trees.py index 4c3f25081bf..2ddd39691e8 100644 --- a/src/sage/graphs/pq_trees.py +++ b/src/sage/graphs/pq_trees.py @@ -365,8 +365,7 @@ def __iter__(self): {2, 3} ('P', [{2, 4}, {8, 2}, {9, 2}]) """ - for i in self._children: - yield i + yield from self._children def number_of_children(self): r""" @@ -795,13 +794,11 @@ def orderings(self): ({2, 4}, {0, 8}, {1, 2}, {0, 5}) ({2, 4}, {0, 8}, {0, 5}, {1, 2}) ... - """ from itertools import permutations, product for p in permutations(self._children): - for o in product(*[x.orderings() if isinstance(x, PQ) else [x] - for x in p]): - yield o + yield from product(*[x.orderings() if isinstance(x, PQ) else [x] + for x in p]) class Q(PQ): @@ -1124,8 +1121,7 @@ def orderings(self): """ if len(self._children) == 1: c = self._children[0] - for o in (c.orderings() if isinstance(c, PQ) else [c]): - yield o + yield from (c.orderings() if isinstance(c, PQ) else [c]) else: from itertools import product for o in product(*[x.orderings() if isinstance(x, PQ) else [x] diff --git a/src/sage/graphs/schnyder.py b/src/sage/graphs/schnyder.py index 8a33cc8c70e..40f6d923656 100644 --- a/src/sage/graphs/schnyder.py +++ b/src/sage/graphs/schnyder.py @@ -743,7 +743,7 @@ def minimal_schnyder_wood(graph, root_edge=None, minimal=True, check=True): sage: newg = minimal_schnyder_wood(g) sage: newg.edges(sort=True) [(0, -3, 'red'), (0, -2, 'blue'), (0, -1, 'green')] - sage: newg.plot(color_by_label={'red':'red','blue':'blue', + sage: newg.plot(color_by_label={'red':'red','blue':'blue', # needs sage.plot ....: 'green':'green',None:'black'}) Graphics object consisting of 8 graphics primitives diff --git a/src/sage/graphs/spanning_tree.pyx b/src/sage/graphs/spanning_tree.pyx index 5c017314724..7576a341701 100644 --- a/src/sage/graphs/spanning_tree.pyx +++ b/src/sage/graphs/spanning_tree.pyx @@ -34,13 +34,10 @@ Methods # https://www.gnu.org/licenses/ # **************************************************************************** -cimport cython from memory_allocator cimport MemoryAllocator from sage.sets.disjoint_set cimport DisjointSet_of_hashables -from sage.misc.decorators import rename_keyword -@rename_keyword(deprecation=32805, wfunction='weight_function') def kruskal(G, by_weight=True, weight_function=None, check_weight=False, check=False): r""" Minimum spanning tree using Kruskal's algorithm. @@ -197,6 +194,7 @@ def kruskal(G, by_weight=True, weight_function=None, check_weight=False, check=F The input graph must be connected. :: + sage: # long time sage: def my_disconnected_graph(n, ntries, directed=False, multiedges=False, loops=False): ....: G = Graph() ....: k = randint(2, n) @@ -217,14 +215,14 @@ def kruskal(G, by_weight=True, weight_function=None, check_weight=False, check=F ....: v = randint(0, k-1) ....: G.delete_edge(u, v) ....: return G - sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=False, loops=False) # long time - sage: kruskal(G, check=True) # long time + sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=False, loops=False) + sage: kruskal(G, check=True) [] - sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=False) # long time - sage: kruskal(G, check=True) # long time + sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=False) + sage: kruskal(G, check=True) [] - sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=True) # long time - sage: kruskal(G, check=True) # long time + sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=True) + sage: kruskal(G, check=True) [] If the input graph is a tree, then return its edges:: @@ -244,18 +242,17 @@ def kruskal(G, by_weight=True, weight_function=None, check_weight=False, check=F ... ValueError: the input graph must be undirected - Rename warning for parameter ``wfunction`` (:trac:`32805`):: + Check that the method is robust to incomparable vertices:: - sage: kruskal(Graph(1), wfunction=lambda e: 2) - doctest:...: DeprecationWarning: use the option 'weight_function' instead of 'wfunction' - See https://github.com/sagemath/sage/issues/32805 for details. - [] + sage: G = Graph([(1, 2, 10), (1, 'a', 1), ('a', 'b', 1), ('b', 2, 1)]) + sage: E = kruskal(G, by_weight=True) + sage: sum(w for _, _, w in E) + 3 """ return list(kruskal_iterator(G, by_weight=by_weight, weight_function=weight_function, check_weight=check_weight, check=check)) -@rename_keyword(deprecation=32805, wfunction='weight_function') def kruskal_iterator(G, by_weight=True, weight_function=None, check_weight=False, bint check=False): """ Return an iterator implementation of Kruskal algorithm. @@ -324,12 +321,12 @@ def kruskal_iterator(G, by_weight=True, weight_function=None, check_weight=False ... ValueError: the input graph must be undirected - Rename warning for parameter ``wfunction`` (:trac:`32805`):: + Check that the method is robust to incomparable vertices:: - sage: list(kruskal_iterator(Graph(1), wfunction=lambda e: 2)) - doctest:...: DeprecationWarning: use the option 'weight_function' instead of 'wfunction' - See https://github.com/sagemath/sage/issues/32805 for details. - [] + sage: G = Graph([(1, 2, 10), (1, 'a', 1), ('a', 'b', 1), ('b', 2, 1)]) + sage: E = list(kruskal_iterator(G, by_weight=True)) + sage: sum(w for _, _, w in E) + 3 """ from sage.graphs.graph import Graph if not isinstance(G, Graph): @@ -357,7 +354,6 @@ def kruskal_iterator(G, by_weight=True, weight_function=None, check_weight=False check_weight=False) -@rename_keyword(deprecation=32805, weighted='by_weight') def kruskal_iterator_from_edges(edges, union_find, by_weight=True, weight_function=None, check_weight=False): """ @@ -401,17 +397,13 @@ def kruskal_iterator_from_edges(edges, union_find, by_weight=True, sage: next(kruskal_iterator_from_edges(G.edges(sort=False), union_set, by_weight=G.weighted())) (1, 6, 10) - TESTS: - - Rename warning for parameter ``weighted`` (:trac:`32805`):: + Check that the method is robust to incomparable vertices:: - sage: from sage.graphs.spanning_tree import kruskal_iterator_from_edges - sage: G = Graph([(0, 1)]) + sage: G = Graph([(1, 2, 10), (1, 'a', 1), ('a', 'b', 1), ('b', 2, 1)]) sage: union_set = DisjointSet(G) - sage: next(kruskal_iterator_from_edges(G.edges(sort=True), union_set, weighted=False)) - doctest:...: DeprecationWarning: use the option 'by_weight' instead of 'weighted' - See https://github.com/sagemath/sage/issues/32805 for details. - (0, 1, None) + sage: E = list(kruskal_iterator_from_edges(G.edges(sort=False), union_set, by_weight=True)) + sage: sum(w for _, _, w in E) + 3 """ # We sort edges, as specified. if weight_function is not None: @@ -502,6 +494,15 @@ def filter_kruskal(G, threshold=10000, by_weight=True, weight_function=None, sage: filter_kruskal(Graph(2), check=True) [] + + TESTS: + + Check that the method is robust to incomparable vertices:: + + sage: G = Graph([(1, 2, 10), (1, 'a', 1), ('a', 'b', 1), ('b', 2, 1)]) + sage: E = filter_kruskal(G, by_weight=True) + sage: sum(w for _, _, w in E) + 3 """ return list(filter_kruskal_iterator(G, threshold=threshold, by_weight=by_weight, weight_function=weight_function, @@ -569,12 +570,14 @@ def filter_kruskal_iterator(G, threshold=10000, by_weight=True, weight_function= The weights of the spanning trees returned by :func:`kruskal_iterator` and :func:`filter_kruskal_iterator` are the same:: + sage: # needs networkx sage: from sage.graphs.spanning_tree import kruskal_iterator sage: G = graphs.RandomBarabasiAlbert(50, 2) sage: for u, v in G.edge_iterator(labels=False): ....: G.set_edge_label(u, v, randint(1, 10)) sage: G.weighted(True) - sage: sum(e[2] for e in kruskal_iterator(G)) == sum(e[2] for e in filter_kruskal_iterator(G, threshold=20)) + sage: sum(e[2] for e in kruskal_iterator(G)) == sum(e[2] + ....: for e in filter_kruskal_iterator(G, threshold=20)) True TESTS: @@ -591,6 +594,13 @@ def filter_kruskal_iterator(G, threshold=10000, by_weight=True, weight_function= sage: len(list(filter_kruskal_iterator(graphs.HouseGraph(), threshold=1))) 4 + + Check that the method is robust to incomparable vertices:: + + sage: G = Graph([(1, 2, 10), (1, 'a', 1), ('a', 'b', 1), ('b', 2, 1)]) + sage: E = list(filter_kruskal_iterator(G, by_weight=True)) + sage: sum(w for _, _, w in E) + 3 """ from sage.graphs.graph import Graph if not isinstance(G, Graph): @@ -696,7 +706,6 @@ def filter_kruskal_iterator(G, threshold=10000, by_weight=True, weight_function= stack.append((begin, i - 1)) -@rename_keyword(deprecation=32805, wfunction='weight_function') def boruvka(G, by_weight=True, weight_function=None, check_weight=True, check=False): r""" Minimum spanning tree using Boruvka's algorithm. @@ -806,12 +815,12 @@ def boruvka(G, by_weight=True, weight_function=None, check_weight=True, check=Fa ... ValueError: the input graph must be undirected - Rename warning for parameter ``wfunction`` (:trac:`32805`):: + Check that the method is robust to incomparable vertices:: - sage: boruvka(Graph(1), wfunction=lambda e: 2) - doctest:...: DeprecationWarning: use the option 'weight_function' instead of 'wfunction' - See https://github.com/sagemath/sage/issues/32805 for details. - [] + sage: G = Graph([(1, 2, 10), (1, 'a', 1), ('a', 'b', 1), ('b', 2, 1)]) + sage: E = boruvka(G, by_weight=True) + sage: sum(w for _, _, w in E) + 3 """ from sage.graphs.graph import Graph if not isinstance(G, Graph): @@ -976,7 +985,7 @@ def random_spanning_tree(G, output_as_graph=False, by_weight=False, weight_funct sage: pos = G.get_pos() sage: T = G.random_spanning_tree(True) sage: T.set_pos(pos) - sage: T.show(vertex_labels=False) + sage: T.show(vertex_labels=False) # needs sage.plot We can also use edge weights to change the probability of returning a spanning tree:: @@ -1000,6 +1009,7 @@ def random_spanning_tree(G, output_as_graph=False, by_weight=False, weight_funct Check that the spanning tree returned when using weights is a tree:: + sage: # needs networkx sage: G = graphs.RandomBarabasiAlbert(50, 2) sage: for u, v in G.edge_iterator(labels=False): ....: G.set_edge_label(u, v, randint(1, 10)) @@ -1020,6 +1030,13 @@ def random_spanning_tree(G, output_as_graph=False, by_weight=False, weight_funct Traceback (most recent call last): ... ValueError: works only for non-empty connected graphs + + Check that the method is robust to incomparable vertices:: + + sage: G = Graph([(1, 2, 10), (1, 'a', 1), ('a', 'b', 1), ('b', 2, 1)]) + sage: T = G.random_spanning_tree(by_weight=True, output_as_graph=True) + sage: T.is_tree() + True """ from sage.misc.prandom import randint from sage.misc.prandom import random @@ -1088,12 +1105,12 @@ def spanning_trees(g, labels=False): sage: G = Graph([(1,2),(1,2),(1,3),(1,3),(2,3),(1,4)], multiedges=True) sage: len(list(G.spanning_trees())) 8 - sage: G.spanning_trees_count() + sage: G.spanning_trees_count() # needs sage.modules 8 sage: G = Graph([(1,2),(2,3),(3,1),(3,4),(4,5),(4,5),(4,6)], multiedges=True) sage: len(list(G.spanning_trees())) 6 - sage: G.spanning_trees_count() + sage: G.spanning_trees_count() # needs sage.modules 6 .. SEEALSO:: @@ -1148,6 +1165,12 @@ def spanning_trees(g, labels=False): Traceback (most recent call last): ... ValueError: this method is for undirected graphs only + + Check that the method is robust to incomparable vertices:: + + sage: G = Graph([(1, 2, 10), (1, 'a', 1), ('a', 'b', 1), ('b', 2, 1)]) + sage: len(list(G.spanning_trees(labels=False))) + 4 """ from sage.graphs.graph import Graph if not isinstance(g, Graph): @@ -1178,8 +1201,8 @@ def spanning_trees(g, labels=False): # e=xy links the CC (connected component) of forest containing x # with the CC containing y. Any other edge which does that cannot be # added to forest anymore, and B is the list of them - c1 = forest.connected_component_containing_vertex(e[0]) - c2 = forest.connected_component_containing_vertex(e[1]) + c1 = forest.connected_component_containing_vertex(e[0], sort=False) + c2 = forest.connected_component_containing_vertex(e[1], sort=False) G.delete_edge(e) B = G.edge_boundary(c1, c2, sort=False) G.add_edge(e) @@ -1292,6 +1315,14 @@ def edge_disjoint_spanning_trees(G, k, by_weight=False, weight_function=None, ch Traceback (most recent call last): ... ValueError: this method is for undirected graphs only + + Check that the method is robust to incomparable vertices:: + + sage: G = Graph() + sage: G.add_clique([0, 1, 2, 'a', 'b']) + sage: F = G.edge_disjoint_spanning_trees(k=2) + sage: len(F) + 2 """ if G.is_directed(): raise ValueError("this method is for undirected graphs only") diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 945b2301159..25e803cc5d8 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -30,21 +30,22 @@ Functions import json import os +from libc.math cimport sqrt, floor +from libc.stdint cimport uint_fast32_t + +from sage.arith.misc import divisors, is_prime_power, is_square from sage.categories.sets_cat import EmptySetError -from sage.misc.unknown import Unknown -from sage.arith.misc import is_square -from sage.arith.misc import is_prime_power -from sage.arith.misc import divisors -from sage.misc.cachefunc import cached_function -from sage.combinat.designs.orthogonal_arrays import orthogonal_array -from sage.combinat.designs.bibd import balanced_incomplete_block_design from sage.graphs.graph import Graph -from libc.math cimport sqrt, floor -from sage.matrix.constructor import Matrix -from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from sage.coding.linear_code import LinearCode +from sage.misc.cachefunc import cached_function +from sage.misc.lazy_import import LazyImport +from sage.misc.unknown import Unknown from sage.rings.sum_of_squares cimport two_squares_c -from libc.stdint cimport uint_fast32_t + +orthogonal_array = LazyImport('sage.combinat.designs.orthogonal_arrays', 'orthogonal_array') +balanced_incomplete_block_design = LazyImport('sage.combinat.designs.bibd', 'balanced_incomplete_block_design') +GF = LazyImport('sage.rings.finite_rings.finite_field_constructor', 'GF') +Matrix = LazyImport('sage.matrix.constructor', 'Matrix') +LinearCode = LazyImport('sage.coding.linear_code', 'LinearCode') cdef dict _brouwer_database = None _small_srg_database = None @@ -69,9 +70,9 @@ def is_paley(int v, int k, int l, int mu): sage: from sage.graphs.strongly_regular_db import is_paley sage: t = is_paley(13,6,2,3); t (..., 13) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings Paley graph with parameter 13: Graph on 13 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (13, 6, 2, 3) sage: t = is_paley(5,5,5,5); t """ @@ -109,18 +110,18 @@ def is_mathon_PC_srg(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_mathon_PC_srg - sage: t = is_mathon_PC_srg(45,22,10,11); t + sage: t = is_mathon_PC_srg(45,22,10,11); t # needs sage.libs.pari (..., 1) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari Mathon's PC SRG on 45 vertices: Graph on 45 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (45, 22, 10, 11) TESTS:: - sage: t = is_mathon_PC_srg(5,5,5,5); t - sage: mu = 1895 # t=5 case -- the construction cannot work - sage: t = is_mathon_PC_srg(4*mu+1,2*mu,mu-1,mu); t + sage: t = is_mathon_PC_srg(5,5,5,5); t # needs sage.libs.pari + sage: mu = 1895 # t=5 case -- the construction cannot work # needs sage.libs.pari + sage: t = is_mathon_PC_srg(4*mu+1,2*mu,mu-1,mu); t # needs sage.libs.pari """ cdef int t if (v % 4 == 1 and @@ -161,6 +162,7 @@ def is_muzychuk_S6(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_muzychuk_S6 sage: t = is_muzychuk_S6(378, 116, 34, 36) sage: G = t[0](*t[1:]); G @@ -210,6 +212,7 @@ def is_orthogonal_array_block_graph(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: from sage.graphs.strongly_regular_db import is_orthogonal_array_block_graph sage: t = is_orthogonal_array_block_graph(64, 35, 18, 20); t (..., 5, 8) @@ -217,20 +220,20 @@ def is_orthogonal_array_block_graph(int v, int k, int l, int mu): OA(5,8): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 35, 18, 20) - sage: t=is_orthogonal_array_block_graph(225,98,43,42); t + sage: t = is_orthogonal_array_block_graph(225,98,43,42); t (..., 4) sage: g = t[0](*t[1:]); g Pasechnik Graph_4: Graph on 225 vertices sage: g.is_strongly_regular(parameters=True) (225, 98, 43, 42) - sage: t=is_orthogonal_array_block_graph(225,112,55,56); t + sage: t = is_orthogonal_array_block_graph(225,112,55,56); t (..., 4) sage: g = t[0](*t[1:]); g skewhad^2_4: Graph on 225 vertices sage: g.is_strongly_regular(parameters=True) (225, 112, 55, 56) - sage: t = is_orthogonal_array_block_graph(5,5,5,5); t + sage: t = is_orthogonal_array_block_graph(5,5,5,5); t # needs sage.combinat sage.modules """ # notations from # https://www.win.tue.nl/~aeb/graphs/OA.html @@ -355,11 +358,11 @@ def is_affine_polar(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_affine_polar - sage: t = is_affine_polar(81,32,13,12); t + sage: t = is_affine_polar(81,32,13,12); t # needs sage.rings.finite_rings (..., 4, 3) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings Affine Polar Graph VO^+(4,3): Graph on 81 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (81, 32, 13, 12) sage: t = is_affine_polar(5,5,5,5); t @@ -412,12 +415,12 @@ def is_orthogonal_polar(int v, int k, int l, int mu): sage: from sage.graphs.strongly_regular_db import is_orthogonal_polar sage: t = is_orthogonal_polar(85, 20, 3, 5); t (<function OrthogonalPolarGraph at ...>, 5, 4, '') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings Orthogonal Polar Graph O(5, 4): Graph on 85 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (85, 20, 3, 5) - sage: t = is_orthogonal_polar(5,5,5,5); t + sage: t = is_orthogonal_polar(5,5,5,5); t # needs sage.rings.finite_rings TESTS: @@ -427,7 +430,7 @@ def is_orthogonal_polar(int v, int k, int l, int mu): (<function OrthogonalPolarGraph at ...>, 5, 4, '') sage: is_orthogonal_polar(119,54,21,27) (<function OrthogonalPolarGraph at ...>, 8, 2, '-') - sage: is_orthogonal_polar(130,48,20,16) + sage: is_orthogonal_polar(130,48,20,16) # needs sage.rings.finite_rings (<function OrthogonalPolarGraph at ...>, 6, 3, '+') """ @@ -486,25 +489,26 @@ def is_goethals_seidel(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_goethals_seidel - sage: t = is_goethals_seidel(28, 15, 6, 10); t + sage: t = is_goethals_seidel(28, 15, 6, 10); t # needs sage.combinat sage.modules [<function GoethalsSeidelGraph at ...>, 3, 3] - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules Graph on 28 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (28, 15, 6, 10) - sage: t = is_goethals_seidel(256, 135, 70, 72); t + sage: t = is_goethals_seidel(256, 135, 70, 72); t # needs sage.combinat sage.modules [<function GoethalsSeidelGraph at ...>, 2, 15] - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules Graph on 256 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (256, 135, 70, 72) - sage: t = is_goethals_seidel(5,5,5,5); t + sage: t = is_goethals_seidel(5,5,5,5); t # needs sage.combinat sage.modules TESTS:: - sage: for p in [(16, 9, 4, 6), (28, 15, 6, 10), (64, 35, 18, 20), (120, 63, 30, 36), + sage: for p in [(16, 9, 4, 6), (28, 15, 6, 10), # needs sage.combinat sage.modules + ....: (64, 35, 18, 20), (120, 63, 30, 36), ....: (144, 77, 40, 42), (256, 135, 70, 72), (400, 209, 108, 110), ....: (496, 255, 126, 136), (540, 275, 130, 150), (576, 299, 154, 156), ....: (780, 399, 198, 210), (784, 405, 208, 210), (976, 495, 238, 264)]: @@ -566,26 +570,27 @@ def is_NOodd(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NOodd - sage: t = is_NOodd(120, 51, 18, 24); t + sage: t = is_NOodd(120, 51, 18, 24); t # needs sage.libs.pari (<function NonisotropicOrthogonalPolarGraph at ...>, 5, 4, '-') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-(5, 4): Graph on 120 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (120, 51, 18, 24) TESTS: All of ``NO^+(2m+1,q)`` and ``NO^-(2m+1,q)`` appear:: + sage: # needs sage.libs.pari sage: t = is_NOodd(120, 51, 18, 24); t (<function NonisotropicOrthogonalPolarGraph at ...>, 5, 4, '-') sage: t = is_NOodd(136, 75, 42, 40); t (<function NonisotropicOrthogonalPolarGraph at ...>, 5, 4, '+') - sage: t=is_NOodd(378, 260, 178, 180); t + sage: t = is_NOodd(378, 260, 178, 180); t (<function NonisotropicOrthogonalPolarGraph at ...>, 7, 3, '+') - sage: t=is_NOodd(45, 32, 22, 24); t + sage: t = is_NOodd(45, 32, 22, 24); t (<function NonisotropicOrthogonalPolarGraph at ...>, 5, 3, '+') - sage: t=is_NOodd(351, 224, 142, 144); t + sage: t = is_NOodd(351, 224, 142, 144); t (<function NonisotropicOrthogonalPolarGraph at ...>, 7, 3, '-') sage: t = is_NOodd(325, 144, 68, 60); t (<function NonisotropicOrthogonalPolarGraph at ...>, 5, 5, '+') @@ -636,22 +641,22 @@ def is_NOperp_F5(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NOperp_F5 - sage: t = is_NOperp_F5(10, 3, 0, 1); t + sage: t = is_NOperp_F5(10, 3, 0, 1); t # needs sage.libs.pari (<function NonisotropicOrthogonalPolarGraph at ...>, 3, 5, '-', 1) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-,perp(3, 5): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (10, 3, 0, 1) TESTS: All of ``NO^+,perp(2m+1,5)`` and ``NO^-,perp(2m+1,5)`` appear:: - sage: t = is_NOperp_F5(325, 60, 15, 10); t + sage: t = is_NOperp_F5(325, 60, 15, 10); t # needs sage.libs.pari (<function NonisotropicOrthogonalPolarGraph at ...>, 5, 5, '+', 1) - sage: t = is_NOperp_F5(300, 65, 10, 15); t + sage: t = is_NOperp_F5(300, 65, 10, 15); t # needs sage.libs.pari (<function NonisotropicOrthogonalPolarGraph at ...>, 5, 5, '-', 1) - sage: t = is_NOperp_F5(5,5,5,5); t + sage: t = is_NOperp_F5(5,5,5,5); t # needs sage.libs.pari """ cdef int n r, s = eigenvalues(v, k, l, mu) # 2*e*5**(n-1), -e*5**(n-1); note exceptional case n=1 @@ -691,22 +696,22 @@ def is_NO_F2(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NO_F2 - sage: t = is_NO_F2(10, 3, 0, 1); t + sage: t = is_NO_F2(10, 3, 0, 1); t # needs sage.libs.pari (<function NonisotropicOrthogonalPolarGraph at ...>, 4, 2, '-') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-(4, 2): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (10, 3, 0, 1) TESTS: All of ``NO^+(2m,2)`` and ``NO^-(2m,2)`` appear:: - sage: t = is_NO_F2(36, 15, 6, 6); t + sage: t = is_NO_F2(36, 15, 6, 6); t # needs sage.libs.pari (<function NonisotropicOrthogonalPolarGraph at ...>, 6, 2, '-') - sage: t = is_NO_F2(28, 15, 6, 10); t + sage: t = is_NO_F2(28, 15, 6, 10); t # needs sage.libs.pari (<function NonisotropicOrthogonalPolarGraph at ...>, 6, 2, '+') - sage: t = is_NO_F2(5,5,5,5); t + sage: t = is_NO_F2(5,5,5,5); t # needs sage.libs.pari """ cdef int n, e, p p, n = is_prime_power(k+1, get_data=True) # k+1==2**(2*n-2) @@ -742,22 +747,22 @@ def is_NO_F3(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NO_F3 - sage: t = is_NO_F3(15, 6, 1, 3); t + sage: t = is_NO_F3(15, 6, 1, 3); t # needs sage.libs.pari (<function NonisotropicOrthogonalPolarGraph at ...>, 4, 3, '-') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-(4, 3): Graph on 15 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (15, 6, 1, 3) TESTS: All of ``NO^+(2m,3)`` and ``NO^-(2m,3)`` appear:: - sage: t = is_NO_F3(126, 45, 12, 18); t + sage: t = is_NO_F3(126, 45, 12, 18); t # needs sage.libs.pari (<function NonisotropicOrthogonalPolarGraph at ...>, 6, 3, '-') - sage: t = is_NO_F3(117, 36, 15, 9); t + sage: t = is_NO_F3(117, 36, 15, 9); t # needs sage.libs.pari (<function NonisotropicOrthogonalPolarGraph at ...>, 6, 3, '+') - sage: t = is_NO_F3(5,5,5,5); t + sage: t = is_NO_F3(5,5,5,5); t # needs sage.libs.pari """ cdef int n, e, p r, s = eigenvalues(v, k, l, mu) # e*3**(n-1), -e*3**(n-2) @@ -798,15 +803,16 @@ def is_NU(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NU - sage: t = is_NU(40, 27, 18, 18); t + sage: t = is_NU(40, 27, 18, 18); t # needs sage.libs.pari (<function NonisotropicUnitaryPolarGraph at ...>, 4, 2) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NU(4, 2): Graph on 40 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (40, 27, 18, 18) TESTS:: + sage: # needs sage.libs.pari sage: t = is_NU(176, 135, 102, 108); t (<function NonisotropicUnitaryPolarGraph at ...>, 5, 2) sage: t = is_NU(540, 224, 88, 96); t @@ -865,16 +871,16 @@ def is_haemers(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_haemers - sage: t = is_haemers(96, 19, 2, 4); t + sage: t = is_haemers(96, 19, 2, 4); t # needs sage.libs.pari (<function HaemersGraph at ...>, 4) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari Haemers(4): Graph on 96 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (96, 19, 2, 4) TESTS:: - sage: t = is_haemers(5,5,5,5); t + sage: t = is_haemers(5,5,5,5); t # needs sage.libs.pari """ cdef int q, n, p p, n = is_prime_power(mu, get_data=True) @@ -907,20 +913,20 @@ def is_cossidente_penttila(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_cossidente_penttila - sage: t = is_cossidente_penttila(378, 52, 1, 8); t + sage: t = is_cossidente_penttila(378, 52, 1, 8); t # needs sage.libs.pari (<function CossidentePenttilaGraph at ...>, 5) - sage: g = t[0](*t[1:]); g # optional - gap_packages + sage: g = t[0](*t[1:]); g # optional - gap_package_design, needs sage.libs.pari CossidentePenttila(5): Graph on 378 vertices - sage: g.is_strongly_regular(parameters=True) # optional - gap_packages + sage: g.is_strongly_regular(parameters=True) # optional - gap_package_design, needs sage.libs.pari (378, 52, 1, 8) TESTS:: - sage: t = is_cossidente_penttila(56,10,0,2); t + sage: t = is_cossidente_penttila(56,10,0,2); t # needs sage.libs.pari (<function CossidentePenttilaGraph at ...>, 3) - sage: t = is_cossidente_penttila(1376,150,2,18); t + sage: t = is_cossidente_penttila(1376,150,2,18); t # needs sage.libs.pari (<function CossidentePenttilaGraph at ...>, 7) - sage: t = is_cossidente_penttila(5,5,5,5); t + sage: t = is_cossidente_penttila(5,5,5,5); t # needs sage.libs.pari """ cdef int q, n, p q = 2*l + 3 @@ -1007,12 +1013,13 @@ def is_polhill(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.graphs.strongly_regular_db import is_polhill sage: t = is_polhill(1024, 231, 38, 56); t [<cyfunction is_polhill.<locals>.<lambda> at ...>] - sage: g = t[0](*t[1:]); g # not tested (too long) + sage: g = t[0](*t[1:]); g # not tested (too long) Graph on 1024 vertices - sage: g.is_strongly_regular(parameters=True) # not tested (too long) + sage: g.is_strongly_regular(parameters=True) # not tested (too long) (1024, 231, 38, 56) sage: t = is_polhill(1024, 264, 56, 72); t [<cyfunction is_polhill.<locals>.<lambda> at ...>] @@ -1063,25 +1070,25 @@ def is_polhill(int v, int k, int l, int mu): # We now define the P_{i,j}. see section 6. P = {} - P[0,1] = list(xrange((-1) + 1 , 2**(s-2)+1)) - P[1,1] = list(xrange((-1) + 2**(s-2)+2 , 2**(s-1)+1)) - P[2,1] = list(xrange((-1) + 2**(s-1)+2 , 2**(s-1)+2**(s-2)+1)) - P[3,1] = list(xrange((-1) + 2**(s-1)+2**(s-2)+2, 2**(s)+1)) - - P[0,2] = list(xrange((-1) + 2**(s-2)+2 , 2**(s-1)+2)) - P[1,2] = list(xrange((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+2)) - P[2,2] = list(xrange((-1) + 2**(s-1)+2**(s-2)+3, 2**(s)+1)) + [0] - P[3,2] = list(xrange((-1) + 2 , 2**(s-2)+1)) - - P[0,3] = list(xrange((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+3)) - P[1,3] = list(xrange((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [0,1] - P[2,3] = list(xrange((-1) + 3 , 2**(s-2)+2)) - P[3,3] = list(xrange((-1) + 2**(s-2)+3 , 2**(s-1)+2)) - - P[0,4] = list(xrange((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) - P[1,4] = list(xrange((-1) + 3 , 2**(s-2)+1)) + [2**(s-1)+1,2**(s-1)+2**(s-2)+2] - P[2,4] = list(xrange((-1) + 2**(s-2)+3 , 2**(s-1)+1)) + [2**(s-1)+2**(s-2)+1,1] - P[3,4] = list(xrange((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+1)) + [2**(s-2)+1,0] + P[0,1] = list(range((-1) + 1 , 2**(s-2)+1)) + P[1,1] = list(range((-1) + 2**(s-2)+2 , 2**(s-1)+1)) + P[2,1] = list(range((-1) + 2**(s-1)+2 , 2**(s-1)+2**(s-2)+1)) + P[3,1] = list(range((-1) + 2**(s-1)+2**(s-2)+2, 2**(s)+1)) + + P[0,2] = list(range((-1) + 2**(s-2)+2 , 2**(s-1)+2)) + P[1,2] = list(range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+2)) + P[2,2] = list(range((-1) + 2**(s-1)+2**(s-2)+3, 2**(s)+1)) + [0] + P[3,2] = list(range((-1) + 2 , 2**(s-2)+1)) + + P[0,3] = list(range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+3)) + P[1,3] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [0,1] + P[2,3] = list(range((-1) + 3 , 2**(s-2)+2)) + P[3,3] = list(range((-1) + 2**(s-2)+3 , 2**(s-1)+2)) + + P[0,4] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + P[1,4] = list(range((-1) + 3 , 2**(s-2)+1)) + [2**(s-1)+1,2**(s-1)+2**(s-2)+2] + P[2,4] = list(range((-1) + 2**(s-2)+3 , 2**(s-1)+1)) + [2**(s-1)+2**(s-2)+1,1] + P[3,4] = list(range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+1)) + [2**(s-2)+1,0] R = {x: copy(P[x]) for x in P} @@ -1095,10 +1102,10 @@ def is_polhill(int v, int k, int l, int mu): # We now define the R_{i,j}. see *end* of section 6. - R[0,3] = list(xrange((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+2)) - R[1,3] = list(xrange((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [0,1,2**(s-1)+2**(s-2)+2] - R[0,4] = list(xrange((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [2**(s-1)+2**(s-2)+2] - R[1,4] = list(xrange((-1) + 3 , 2**(s-2)+1)) + [2**(s-1)+1] + R[0,3] = list(range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+2)) + R[1,3] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [0,1,2**(s-1)+2**(s-2)+2] + R[0,4] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [2**(s-1)+2**(s-2)+2] + R[1,4] = list(range((-1) + 3 , 2**(s-2)+1)) + [2**(s-1)+1] for x in R: R[x] = [K[i] for i in R[x]] @@ -1155,11 +1162,11 @@ def is_RSHCD(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_RSHCD - sage: t = is_RSHCD(64,27,10,12); t + sage: t = is_RSHCD(64,27,10,12); t # needs sage.combinat sage.modules [<built-in function SRG_from_RSHCD>, 64, 27, 10, 12] - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (64, 27, 10, 12) """ if SRG_from_RSHCD(v, k, l, mu, existence=True) is True: @@ -1190,26 +1197,27 @@ def SRG_from_RSHCD(v, k, l, mu, existence=False, check=True): some graphs :: sage: from sage.graphs.strongly_regular_db import SRG_from_RSHCD - sage: SRG_from_RSHCD(784, 0, 14, 38, existence=True) + sage: SRG_from_RSHCD(784, 0, 14, 38, existence=True) # needs sage.combinat sage.modules False - sage: SRG_from_RSHCD(784, 377, 180, 182, existence=True) + sage: SRG_from_RSHCD(784, 377, 180, 182, existence=True) # needs sage.combinat sage.modules True - sage: SRG_from_RSHCD(144, 65, 28, 30) + sage: SRG_from_RSHCD(144, 65, 28, 30) # needs sage.combinat sage.modules Graph on 144 vertices an example with vertex-transitive automorphism group, found during the implementation of the case `v=324` :: - sage: G=SRG_from_RSHCD(324,152,70,72) # long time - sage: a=G.automorphism_group() # long time - sage: a.order() # long time + sage: # long time, needs sage.combinat sage.modules + sage: G = SRG_from_RSHCD(324,152,70,72) + sage: a = G.automorphism_group() + sage: a.order() 2592 - sage: len(a.orbits()) # long time + sage: len(a.orbits()) 1 TESTS:: - sage: SRG_from_RSHCD(784, 0, 14, 38) + sage: SRG_from_RSHCD(784, 0, 14, 38) # needs sage.combinat sage.modules Traceback (most recent call last): ... ValueError: I do not know how to build a (784, 0, 14, 38)-SRG from a RSHCD @@ -1266,19 +1274,20 @@ def is_unitary_polar(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_unitary_polar - sage: t = is_unitary_polar(45, 12, 3, 3); t + sage: t = is_unitary_polar(45, 12, 3, 3); t # needs sage.libs.pari (<function UnitaryPolarGraph at ...>, 4, 2) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (45, 12, 3, 3) - sage: t = is_unitary_polar(5,5,5,5); t + sage: t = is_unitary_polar(5,5,5,5); t # needs sage.libs.pari TESTS: All the ``U(n,q)`` appear:: + sage: # needs sage.libs.pari sage: t = is_unitary_polar(45, 12, 3, 3); t (<function UnitaryPolarGraph at ...>, 4, 2) sage: t = is_unitary_polar(165, 36, 3, 9); t @@ -1341,6 +1350,7 @@ def is_unitary_dual_polar(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_unitary_dual_polar sage: t = is_unitary_dual_polar(297, 40, 7, 5); t (<function UnitaryDualPolarGraph at ...>, 5, 2) @@ -1352,7 +1362,7 @@ def is_unitary_dual_polar(int v, int k, int l, int mu): TESTS:: - sage: is_unitary_dual_polar(6832, 270, 26, 10) + sage: is_unitary_dual_polar(6832, 270, 26, 10) # needs sage.libs.pari (<function UnitaryDualPolarGraph at ...>, 5, 3) """ r, s = eigenvalues(v, k, l, mu) @@ -1391,6 +1401,7 @@ def is_GQqmqp(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_GQqmqp sage: t = is_GQqmqp(27,10,1,5); t (<function AhrensSzekeresGeneralizedQuadrangleGraph at ...>, 3, False) @@ -1417,16 +1428,17 @@ def is_GQqmqp(int v, int k, int l, int mu): TESTS:: - sage: (S,T)=(127,129) + sage: # needs sage.libs.pari + sage: (S,T) = (127,129) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (<function T2starGeneralizedQuadrangleGraph at ...>, 128, False) - sage: (S,T)=(129,127) + sage: (S,T) = (129,127) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (<function T2starGeneralizedQuadrangleGraph at ...>, 128, True) - sage: (S,T)=(124,126) + sage: (S,T) = (124,126) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (<function AhrensSzekeresGeneralizedQuadrangleGraph at ...>, 125, False) - sage: (S,T)=(126,124) + sage: (S,T) = (126,124) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (<function AhrensSzekeresGeneralizedQuadrangleGraph at ...>, 125, True) sage: t = is_GQqmqp(5,5,5,5); t @@ -1483,19 +1495,19 @@ def is_twograph_descendant_of_srg(int v, int k0, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_twograph_descendant_of_srg - sage: t = is_twograph_descendant_of_srg(27, 10, 1, 5); t + sage: t = is_twograph_descendant_of_srg(27, 10, 1, 5); t # needs sage.rings.finite_rings (<cyfunction is_twograph_descendant_of_srg.<locals>.la at... - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings descendant of complement(Johnson graph with parameters 8,2) at {0, 1}: Graph on 27 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (27, 10, 1, 5) sage: t = is_twograph_descendant_of_srg(5,5,5,5); t TESTS:: - sage: graphs.strongly_regular_graph(279, 150, 85, 75, existence=True) + sage: graphs.strongly_regular_graph(279, 150, 85, 75, existence=True) # needs sage.combinat True - sage: graphs.strongly_regular_graph(279, 150, 85, 75).is_strongly_regular(parameters=True) # optional - gap_packages internet + sage: graphs.strongly_regular_graph(279, 150, 85, 75).is_strongly_regular(parameters=True) # optional - gap_package_design internet (279, 150, 85, 75) """ cdef int b, k, s @@ -1544,6 +1556,7 @@ def is_taylor_twograph_srg(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_taylor_twograph_srg sage: t = is_taylor_twograph_srg(28, 15, 6, 10); t (<function TaylorTwographSRG at ...>, 3) @@ -1555,7 +1568,7 @@ def is_taylor_twograph_srg(int v, int k, int l, int mu): TESTS:: - sage: is_taylor_twograph_srg(730, 369, 168, 205) + sage: is_taylor_twograph_srg(730, 369, 168, 205) # needs sage.libs.pari (<function TaylorTwographSRG at ...>, 9) """ @@ -1594,13 +1607,13 @@ def is_switch_skewhad(int v, int k, int l, int mu): EXAMPLES:: - sage: graphs.strongly_regular_graph(226, 105, 48, 49) + sage: graphs.strongly_regular_graph(226, 105, 48, 49) # needs sage.combinat sage.modules switch skewhad^2+*_4: Graph on 226 vertices TESTS:: sage: from sage.graphs.strongly_regular_db import is_switch_skewhad - sage: t = is_switch_skewhad(5,5,5,5); t + sage: t = is_switch_skewhad(5,5,5,5); t # needs sage.combinat sage.modules """ from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix @@ -1641,22 +1654,22 @@ def is_switch_OA_srg(int v, int k, int l, int mu): EXAMPLES:: - sage: graphs.strongly_regular_graph(170, 78, 35, 36) # indirect doctest + sage: graphs.strongly_regular_graph(170, 78, 35, 36) # indirect doctest # needs sage.combinat sage.modules Graph on 170 vertices TESTS:: sage: from sage.graphs.strongly_regular_db import is_switch_OA_srg sage: t = is_switch_OA_srg(5,5,5,5); t - sage: t = is_switch_OA_srg(170, 78, 35, 36) - sage: t[0](*t[1:]).is_strongly_regular(parameters=True) + sage: t = is_switch_OA_srg(170, 78, 35, 36) # needs sage.schemes + sage: t[0](*t[1:]).is_strongly_regular(parameters=True) # needs sage.schemes (170, 78, 35, 36) - sage: t = is_switch_OA_srg(290, 136, 63, 64) - sage: t[0](*t[1:]).is_strongly_regular(parameters=True) + sage: t = is_switch_OA_srg(290, 136, 63, 64) # needs sage.schemes + sage: t[0](*t[1:]).is_strongly_regular(parameters=True) # needs sage.schemes (290, 136, 63, 64) - sage: is_switch_OA_srg(626, 300, 143, 144) + sage: is_switch_OA_srg(626, 300, 143, 144) # needs sage.schemes (<cyfunction is_switch_OA_srg.<locals>.switch_OA_srg at ..., 12, 25) - sage: is_switch_OA_srg(842, 406, 195, 196) + sage: is_switch_OA_srg(842, 406, 195, 196) # needs sage.schemes (<cyfunction is_switch_OA_srg.<locals>.switch_OA_srg at ..., 14, 29) """ cdef int n_2_p_1 = v @@ -1699,15 +1712,15 @@ def is_nowhere0_twoweight(int v, int k, int l, int mu): EXAMPLES:: - sage: graphs.strongly_regular_graph(196, 60, 14, 20) + sage: graphs.strongly_regular_graph(196, 60, 14, 20) # needs sage.combinat sage.modules Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices TESTS:: sage: from sage.graphs.strongly_regular_db import is_nowhere0_twoweight - sage: t = is_nowhere0_twoweight(1800, 728, 268, 312); t + sage: t = is_nowhere0_twoweight(1800, 728, 268, 312); t # needs sage.libs.pari (<function Nowhere0WordsTwoWeightCodeGraph at ...>, 16) - sage: t = is_nowhere0_twoweight(5,5,5,5); t + sage: t = is_nowhere0_twoweight(5,5,5,5); t # needs sage.libs.pari """ from sage.graphs.generators.classical_geometries import Nowhere0WordsTwoWeightCodeGraph @@ -1786,22 +1799,22 @@ def eigenmatrix(int v, int k, int l, int mu): Petersen's graph's C-algebra does not have a dual coming from an s.r.g.:: sage: from sage.graphs.strongly_regular_db import eigenmatrix - sage: P=eigenmatrix(10,3,0,1); P + sage: P = eigenmatrix(10,3,0,1); P # needs sage.modules [ 1 3 6] [ 1 1 -2] [ 1 -2 1] - sage: 10*P^-1 + sage: 10*P^-1 # needs sage.modules [ 1 5 4] [ 1 5/3 -8/3] [ 1 -5/3 2/3] The line graph of `K_{3,3}` is self-dual:: - sage: P=eigenmatrix(9,4,1,2); P + sage: P = eigenmatrix(9,4,1,2); P # needs sage.modules [ 1 4 4] [ 1 1 -2] [ 1 -2 1] - sage: 9*P^-1 + sage: 9*P^-1 # needs sage.modules [ 1 4 4] [ 1 1 -2] [ 1 -2 1] @@ -1809,11 +1822,12 @@ def eigenmatrix(int v, int k, int l, int mu): A strongly regular graph with a non-isomorphic dual coming from another strongly regular graph:: - sage: graphs.strongly_regular_graph(243,220,199,200, existence=True) + sage: # needs sage.modules + sage: graphs.strongly_regular_graph(243,220,199,200, existence=True) # needs sage.combinat True - sage: graphs.strongly_regular_graph(243,110,37,60, existence=True) + sage: graphs.strongly_regular_graph(243,110,37,60, existence=True) # needs sage.combinat True - sage: P=eigenmatrix(243,220,199,200); P + sage: P = eigenmatrix(243,220,199,200); P [ 1 220 22] [ 1 4 -5] [ 1 -5 4] @@ -1881,7 +1895,7 @@ def _H_3_cayley_graph(L): TESTS:: sage: from sage.graphs.strongly_regular_db import _H_3_cayley_graph - sage: _H_3_cayley_graph(["100","110","130","140","200","230","240","300"]) + sage: _H_3_cayley_graph(["100","110","130","140","200","230","240","300"]) # needs sage.groups Graph on 100 vertices """ from sage.groups.free_group import FreeGroup @@ -1908,8 +1922,8 @@ def SRG_100_44_18_20(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_100_44_18_20 - sage: G = SRG_100_44_18_20() # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: G = SRG_100_44_18_20() # long time + sage: G.is_strongly_regular(parameters=True) # long time (100, 44, 18, 20) """ L = ['100', '110', '130', '140', '200', '230', '240', '300', '310', '320', @@ -1930,8 +1944,8 @@ def SRG_100_45_20_20(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_100_45_20_20 - sage: G = SRG_100_45_20_20() # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: G = SRG_100_45_20_20() # long time + sage: G.is_strongly_regular(parameters=True) # long time (100, 45, 20, 20) """ L = ['120', '140', '200', '210', '201', '401', '411', '321', '002', '012', @@ -1954,9 +1968,9 @@ def SRG_105_32_4_12(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_105_32_4_12 - sage: G = SRG_105_32_4_12(); G + sage: G = SRG_105_32_4_12(); G # needs sage.rings.finite_rings Aut L(3,4) on flags: Graph on 105 vertices - sage: G.is_strongly_regular(parameters=True) + sage: G.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (105, 32, 4, 12) """ from sage.combinat.designs.block_design import ProjectiveGeometryDesign @@ -1984,8 +1998,8 @@ def SRG_120_77_52_44(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_120_77_52_44 - sage: G = SRG_120_77_52_44() # optional - gap_packages - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages + sage: G = SRG_120_77_52_44() # optional - gap_package_design + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_design (120, 77, 52, 44) """ from sage.combinat.designs.block_design import WittDesign @@ -2008,8 +2022,8 @@ def SRG_144_39_6_12(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_144_39_6_12 - sage: G = SRG_144_39_6_12() - sage: G.is_strongly_regular(parameters=True) + sage: G = SRG_144_39_6_12() # needs sage.libs.gap + sage: G.is_strongly_regular(parameters=True) # needs sage.libs.gap (144, 39, 6, 12) """ from sage.libs.gap.libgap import libgap @@ -2042,8 +2056,8 @@ def SRG_176_49_12_14(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_176_49_12_14 - sage: G = SRG_176_49_12_14() # optional - gap_packages # long time - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages # long time + sage: G = SRG_176_49_12_14() # long time, optional - gap_package_design + sage: G.is_strongly_regular(parameters=True) # long time, optional - gap_package_design (176, 49, 12, 14) """ from sage.combinat.designs.database import HigmanSimsDesign @@ -2079,8 +2093,8 @@ def SRG_176_105_68_54(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_176_105_68_54 - sage: G = SRG_176_105_68_54() # optional - gap_packages - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages + sage: G = SRG_176_105_68_54() # optional - gap_package_design + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_design (176, 105, 68, 54) """ from sage.combinat.designs.block_design import WittDesign @@ -2106,8 +2120,8 @@ def SRG_210_99_48_45(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_210_99_48_45 - sage: g=SRG_210_99_48_45() - sage: g.is_strongly_regular(parameters=True) + sage: g = SRG_210_99_48_45() # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (210, 99, 48, 45) """ from sage.libs.gap.libgap import libgap @@ -2153,14 +2167,14 @@ def SRG_243_110_37_60(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_243_110_37_60 - sage: G = SRG_243_110_37_60() - sage: G.is_strongly_regular(parameters=True) + sage: G = SRG_243_110_37_60() # needs sage.modules sage.rings.finite_rings + sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (243, 110, 37, 60) """ from sage.coding.golay_code import GolayCode M = GolayCode(GF(3), False).generator_matrix() V = list(M.right_kernel()) - g = Graph([list(xrange(len(V))), lambda x, y: (V[x] - V[y]).hamming_weight() == 9]) + g = Graph([list(range(len(V))), lambda x, y: (V[x] - V[y]).hamming_weight() == 9]) g.name('Ternary Golay code') return g @@ -2177,8 +2191,8 @@ def SRG_253_140_87_65(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_253_140_87_65 - sage: G = SRG_253_140_87_65() # optional - gap_packages - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages + sage: G = SRG_253_140_87_65() # optional - gap_package_design + sage: G.is_strongly_regular(parameters=True) # optional - gap_package_design (253, 140, 87, 65) """ from sage.combinat.designs.block_design import WittDesign @@ -2260,8 +2274,8 @@ def SRG_276_140_58_84(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_276_140_58_84 - sage: g=SRG_276_140_58_84() # long time # optional - gap_packages - sage: g.is_strongly_regular(parameters=True) # long time # optional - gap_packages + sage: g = SRG_276_140_58_84() # long time, optional - gap_package_design + sage: g.is_strongly_regular(parameters=True) # long time, optional - gap_package_design (276, 140, 58, 84) """ from sage.graphs.generators.smallgraphs import McLaughlinGraph @@ -2289,8 +2303,8 @@ def SRG_280_135_70_60(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_280_135_70_60 - sage: g=SRG_280_135_70_60() # long time # optional - internet - sage: g.is_strongly_regular(parameters=True) # long time # optional - internet + sage: g=SRG_280_135_70_60() # long time, optional - internet + sage: g.is_strongly_regular(parameters=True) # long time, optional - internet (280, 135, 70, 60) """ from sage.libs.gap.libgap import libgap @@ -2364,13 +2378,13 @@ def strongly_regular_from_two_weight_code(L): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import strongly_regular_from_two_weight_code - sage: x=("100022021001111", - ....: "010011211122000", - ....: "001021112100011", - ....: "000110120222220") - sage: M = Matrix(GF(3),[list(l) for l in x]) - sage: G = strongly_regular_from_two_weight_code(LinearCode(M)) - sage: G.is_strongly_regular(parameters=True) + sage: x = ("100022021001111", + ....: "010011211122000", + ....: "001021112100011", + ....: "000110120222220") + sage: M = Matrix(GF(3),[list(l) for l in x]) # needs sage.modules sage.rings.finite_rings + sage: G = strongly_regular_from_two_weight_code(LinearCode(M)) # needs sage.modules sage.rings.finite_rings + sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (81, 50, 31, 30) """ from sage.structure.element import is_Matrix @@ -2397,8 +2411,8 @@ def SRG_416_100_36_20(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_416_100_36_20 - sage: g = SRG_416_100_36_20() # long time # optional - internet - sage: g.is_strongly_regular(parameters=True) # long time # optional - internet + sage: g = SRG_416_100_36_20() # long time, optional - internet + sage: g.is_strongly_regular(parameters=True) # long time, optional - internet (416, 100, 36, 20) """ from sage.libs.gap.libgap import libgap @@ -2421,8 +2435,8 @@ def SRG_560_208_72_80(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_560_208_72_80 - sage: g = SRG_560_208_72_80() # not tested (~2s) - sage: g.is_strongly_regular(parameters=True) # not tested (~2s) + sage: g = SRG_560_208_72_80() # not tested (~2s) + sage: g.is_strongly_regular(parameters=True) # not tested (~2s) (560, 208, 72, 80) """ from sage.libs.gap.libgap import libgap @@ -2471,10 +2485,10 @@ def strongly_regular_from_two_intersection_set(M): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import strongly_regular_from_two_intersection_set - sage: S = Matrix([(0,0,1),(0,1,0)] + [(1,x^2,x) for x in GF(4,'b')]) - sage: g = strongly_regular_from_two_intersection_set(S); g + sage: S = Matrix([(0,0,1),(0,1,0)] + [(1,x^2,x) for x in GF(4,'b')]) # needs sage.modules sage.rings.finite_rings + sage: g = strongly_regular_from_two_intersection_set(S); g # needs sage.modules sage.rings.finite_rings two-intersection set in PG(3,4): Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (64, 18, 2, 6) """ from itertools import product @@ -2574,8 +2588,6 @@ def SRG_176_90_38_54(): sage: G.is_strongly_regular(parameters=True) (176, 90, 38, 54) """ - from sage.graphs.generators.basic import CompleteGraph - from sage.misc.flatten import flatten g = SRG_175_72_20_36() g.relabel(range(175)) # c=filter(lambda x: len(x)==5, g.cliques_maximal()) @@ -2637,7 +2649,6 @@ def SRG_126_50_13_24(): sage: G.is_strongly_regular(parameters=True) (126, 50, 13, 24) """ - from sage.graphs.strongly_regular_db import SRG_175_72_20_36 from sage.graphs.generators.smallgraphs import HoffmanSingletonGraph hs = HoffmanSingletonGraph() s = set(hs.vertices(sort=False)).difference(hs.neighbors(0) + [0]) @@ -2663,8 +2674,8 @@ def SRG_1288_792_476_504(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_1288_792_476_504 - sage: G = SRG_1288_792_476_504() # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: G = SRG_1288_792_476_504() # long time # needs sage.rings.finite_rings + sage: G.is_strongly_regular(parameters=True) # long time # needs sage.rings.finite_rings (1288, 792, 476, 504) """ from sage.coding.golay_code import GolayCode @@ -2692,7 +2703,7 @@ cdef bint seems_feasible(int v, int k, int l, int mu): :trac:`32306` is fixed:: sage: from sage.graphs.strongly_regular_db import strongly_regular_graph - sage: strongly_regular_graph(16384, 8256, 4160, 4160, existence=True) + sage: strongly_regular_graph(16384, 8256, 4160, 4160, existence=True) # needs sage.combinat sage.modules True """ cdef uint_fast32_t tmp[2] @@ -2822,9 +2833,9 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, An set of parameters proved in a paper to be infeasible:: - sage: graphs.strongly_regular_graph(324,57,0,12,existence=True) + sage: graphs.strongly_regular_graph(324,57,0,12,existence=True) # needs sage.combinat sage.modules False - sage: graphs.strongly_regular_graph(324,57,0,12) + sage: graphs.strongly_regular_graph(324,57,0,12) # needs sage.combinat sage.modules Traceback (most recent call last): ... EmptySetError: Andries Brouwer's database reports that no (324, 57, 0, @@ -2833,9 +2844,9 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, A set of parameters unknown to be realizable in Andries Brouwer's database:: - sage: graphs.strongly_regular_graph(324,95,22,30,existence=True) + sage: graphs.strongly_regular_graph(324,95,22,30,existence=True) # needs sage.combinat Unknown - sage: graphs.strongly_regular_graph(324,95,22,30) + sage: graphs.strongly_regular_graph(324,95,22,30) # needs sage.combinat Traceback (most recent call last): ... RuntimeError: Andries Brouwer's database reports that no @@ -2844,9 +2855,9 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, A large unknown set of parameters (not in Andries Brouwer's database):: - sage: graphs.strongly_regular_graph(1394,175,0,25,existence=True) + sage: graphs.strongly_regular_graph(1394,175,0,25,existence=True) # needs sage.combinat Unknown - sage: graphs.strongly_regular_graph(1394,175,0,25) + sage: graphs.strongly_regular_graph(1394,175,0,25) # needs sage.combinat Traceback (most recent call last): ... RuntimeError: Sage cannot figure out if a (1394, 175, 0, 25)-strongly @@ -2861,25 +2872,25 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, Check that :trac:`26513` is fixed:: - sage: graphs.strongly_regular_graph(539, 288, 162, 144) + sage: graphs.strongly_regular_graph(539, 288, 162, 144) # needs sage.combinat descendant of (540, 264, 138, 120)-strongly regular graph at ... 539 vertices - sage: graphs.strongly_regular_graph(539, 250, 105, 125) + sage: graphs.strongly_regular_graph(539, 250, 105, 125) # needs sage.combinat descendant of (540, 275, 130, 150)-strongly regular graph at ... 539 vertices - sage: graphs.strongly_regular_graph(209, 100, 45, 50) + sage: graphs.strongly_regular_graph(209, 100, 45, 50) # needs sage.libs.pari descendant of complement(merging of S_7 on Circulant(6,[1,4])s) at ... 209 vertices Check that all of our constructions are correct - you will need gap_packages spkg installed:: sage: from sage.graphs.strongly_regular_db import apparently_feasible_parameters - sage: for p in sorted(apparently_feasible_parameters(1300)): # not tested - ....: if graphs.strongly_regular_graph(*p,existence=True) is True: # not tested - ....: try: # not tested - ....: _ = graphs.strongly_regular_graph(*p) # not tested - ....: print(p, "built successfully") # not tested - ....: except RuntimeError as e: # not tested - ....: if 'Brouwer' not in str(e): # not tested - ....: raise # not tested + sage: for p in sorted(apparently_feasible_parameters(1300)): # not tested, optional gap_package_design + ....: if graphs.strongly_regular_graph(*p,existence=True) is True: + ....: try: + ....: _ = graphs.strongly_regular_graph(*p) + ....: print(p, "built successfully") + ....: except RuntimeError as e: + ....: if 'Brouwer' not in str(e): + ....: raise `\mu=0` behaves correctly (:trac:`19712`):: @@ -2931,11 +2942,11 @@ def strongly_regular_graph_lazy(int v, int k, int l, int mu=-1, bint existence=F (3, 4)) sage: g(p) complement(Multipartite Graph with set sizes [4, 4, 4]): Graph on 12 vertices - sage: g=strongly_regular_graph_lazy(539,250,105); g + sage: g = strongly_regular_graph_lazy(539,250,105); g # needs sage.combinat sage.modules (<cyfunction is_twograph_descendant_of_srg.<locals>.la at...>, 5, 11) - sage: g[0](*g[1:]) + sage: g[0](*g[1:]) # needs sage.combinat sage.modules descendant of (540, 275, 130, 150)-strongly regular graph at 0: Graph on 539 vertices """ load_brouwer_database() @@ -3066,14 +3077,16 @@ def apparently_feasible_parameters(int n): (16, 9, 4, 6), (16, 10, 6, 6), (17, 8, 3, 4)} - sage: all(graphs.strongly_regular_graph(*x,existence=True) is True for x in small_feasible) + sage: all(graphs.strongly_regular_graph(*x,existence=True) is True # needs sage.libs.pari + ....: for x in small_feasible) True But that becomes wrong for `v<60` (because of the non-existence of a `(49,16,3,6)`-strongly regular graph):: sage: small_feasible = apparently_feasible_parameters(60) - sage: all(graphs.strongly_regular_graph(*x,existence=True) is True for x in small_feasible) + sage: all(graphs.strongly_regular_graph(*x,existence=True) is True # needs sage.libs.pari + ....: for x in small_feasible) False """ cdef int v, k, l, mu @@ -3101,57 +3114,57 @@ def _build_small_srg_database(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import _build_small_srg_database - sage: _build_small_srg_database() + sage: _build_small_srg_database() # needs sage.modules sage.rings.finite_rings TESTS: Make sure that all two-weight codes yield the strongly regular graphs we expect:: - sage: graphs.strongly_regular_graph(81, 50, 31, 30) + sage: graphs.strongly_regular_graph(81, 50, 31, 30) # needs sage.libs.pari complement(two-intersection set in PG(4,3)): Graph on 81 vertices - sage: graphs.strongly_regular_graph(243, 220, 199, 200) # long time + sage: graphs.strongly_regular_graph(243, 220, 199, 200) # long time, needs sage.rings.finite_rings two-weight code: [55, 5] linear code over GF(3): Graph on 243 vertices - sage: graphs.strongly_regular_graph(256, 153, 92, 90) + sage: graphs.strongly_regular_graph(256, 153, 92, 90) # needs sage.combinat complement(two-intersection set in PG(4,4)): Graph on 256 vertices - sage: graphs.strongly_regular_graph(256, 170, 114, 110) + sage: graphs.strongly_regular_graph(256, 170, 114, 110) # needs sage.combinat complement(two-intersection set in PG(8,2)): Graph on 256 vertices - sage: graphs.strongly_regular_graph(256, 187, 138, 132) + sage: graphs.strongly_regular_graph(256, 187, 138, 132) # needs sage.combinat complement(two-intersection set in PG(8,2)): Graph on 256 vertices - sage: graphs.strongly_regular_graph(512, 73, 12, 10) # not tested (too long) + sage: graphs.strongly_regular_graph(512, 73, 12, 10) # not tested (too long), needs sage.rings.finite_rings two-weight code: [219, 9] linear code over GF(2): Graph on 512 vertices - sage: graphs.strongly_regular_graph(512, 219, 106, 84) # long time + sage: graphs.strongly_regular_graph(512, 219, 106, 84) # long time two-intersection set in PG(9,2): Graph on 512 vertices - sage: graphs.strongly_regular_graph(512, 315, 202, 180) # not tested (too long) + sage: graphs.strongly_regular_graph(512, 315, 202, 180) # not tested (too long), needs sage.rings.finite_rings two-weight code: [70, 9] linear code over GF(2): Graph on 512 vertices - sage: graphs.strongly_regular_graph(625, 364, 213, 210) # long time + sage: graphs.strongly_regular_graph(625, 364, 213, 210) # long time complement(two-intersection set in PG(4,5)): Graph on 625 vertices - sage: graphs.strongly_regular_graph(625, 416, 279, 272) # long time + sage: graphs.strongly_regular_graph(625, 416, 279, 272) # long time complement(two-intersection set in PG(4,5)): Graph on 625 vertices - sage: graphs.strongly_regular_graph(625, 468, 353, 342) # long time + sage: graphs.strongly_regular_graph(625, 468, 353, 342) # long time complement(two-intersection set in PG(4,5)): Graph on 625 vertices - sage: graphs.strongly_regular_graph(729, 336, 153,156) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 336, 153,156) # not tested (too long) two-intersection set in PG(6,3): Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 420, 243, 240) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 420, 243, 240) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 448, 277, 272) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 448, 277, 272) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 476, 313, 306) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 476, 313, 306) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 532, 391, 380) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 532, 391, 380) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 560, 433, 420) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 560, 433, 420) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices Graph on 729 vertices - sage: graphs.strongly_regular_graph(729, 616, 523, 506) # not tested (too long) + sage: graphs.strongly_regular_graph(729, 616, 523, 506) # not tested (too long) complement(two-intersection set in PG(6,3)): Graph on 729 vertices - sage: graphs.strongly_regular_graph(1024, 363, 122, 132)# not tested (too long) + sage: graphs.strongly_regular_graph(1024, 363, 122, 132) # not tested (too long) two-intersection set in PG(5,4): Graph on 1024 vertices - sage: graphs.strongly_regular_graph(1024, 396, 148, 156)# not tested (too long) + sage: graphs.strongly_regular_graph(1024, 396, 148, 156) # not tested (too long) two-intersection set in PG(5,4): Graph on 1024 vertices - sage: graphs.strongly_regular_graph(1024, 429, 176, 182)# not tested (too long) + sage: graphs.strongly_regular_graph(1024, 429, 176, 182) # not tested (too long) two-intersection set in PG(5,4): Graph on 1024 vertices - sage: graphs.strongly_regular_graph(1024, 825, 668, 650)# not tested (too long) + sage: graphs.strongly_regular_graph(1024, 825, 668, 650) # not tested (too long) complement(two-intersection set in PG(10,2)): Graph on 1024 vertices """ from sage.graphs.generators.smallgraphs import McLaughlinGraph @@ -3160,7 +3173,6 @@ def _build_small_srg_database(): from sage.graphs.generators.smallgraphs import M22Graph from sage.graphs.generators.smallgraphs import SimsGewirtzGraph from sage.graphs.generators.smallgraphs import HoffmanSingletonGraph - from sage.graphs.generators.smallgraphs import SchlaefliGraph from sage.graphs.generators.smallgraphs import HigmanSimsGraph from sage.graphs.generators.smallgraphs import IoninKharaghani765Graph from sage.graphs.generators.smallgraphs import JankoKharaghaniGraph diff --git a/src/sage/graphs/traversals.pyx b/src/sage/graphs/traversals.pyx index a16ac6d701e..8769f14f602 100644 --- a/src/sage/graphs/traversals.pyx +++ b/src/sage/graphs/traversals.pyx @@ -42,12 +42,12 @@ from libc.stdint cimport uint32_t from libcpp.queue cimport priority_queue from libcpp.pair cimport pair from libcpp.vector cimport vector -from cysignals.signals cimport sig_on, sig_off, sig_check +from cysignals.signals cimport sig_on, sig_off from memory_allocator cimport MemoryAllocator from sage.graphs.base.static_sparse_graph cimport init_short_digraph from sage.graphs.base.static_sparse_graph cimport free_short_digraph -from sage.graphs.base.static_sparse_graph cimport out_degree, has_edge +from sage.graphs.base.static_sparse_graph cimport out_degree def _is_valid_lex_BFS_order(G, L): @@ -338,6 +338,7 @@ def lex_BFS(G, reverse=False, tree=False, initial_vertex=None, algorithm="fast") Different orderings for different traversals:: + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2,3) sage: G.lex_BFS(initial_vertex='000', algorithm="fast") ['000', '001', '100', '010', '011', '110', '101', '111'] @@ -474,8 +475,7 @@ def lex_BFS(G, reverse=False, tree=False, initial_vertex=None, algorithm="fast") edges = [(int_to_v[i], int_to_v[pred[i]]) for i in range(n) if pred[i] != i] g = DiGraph([G, edges], format='vertices_and_edges', sparse=True) return sigma, g - else: - return sigma + return sigma def lex_UP(G, reverse=False, tree=False, initial_vertex=None): @@ -541,6 +541,7 @@ def lex_UP(G, reverse=False, tree=False, initial_vertex=None): Different orderings for different traversals:: + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2,3) sage: G.lex_BFS(initial_vertex='000') ['000', '001', '100', '010', '011', '110', '101', '111'] @@ -595,8 +596,7 @@ def lex_UP(G, reverse=False, tree=False, initial_vertex=None): from sage.graphs.digraph import DiGraph g = DiGraph(sparse=True) return [], g - else: - return [] + return [] # Build adjacency list of G cdef list int_to_v = list(G) @@ -647,9 +647,7 @@ def lex_UP(G, reverse=False, tree=False, initial_vertex=None): edges = [(int_to_v[i], int_to_v[pred[i]]) for i in range(nV) if pred[i] != -1] g.add_edges(edges) return value, g - - else: - return value + return value def lex_DFS(G, reverse=False, tree=False, initial_vertex=None): @@ -714,6 +712,7 @@ def lex_DFS(G, reverse=False, tree=False, initial_vertex=None): Different orderings for different traversals:: + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2,3) sage: G.lex_BFS(initial_vertex='000') ['000', '001', '100', '010', '011', '110', '101', '111'] @@ -768,8 +767,7 @@ def lex_DFS(G, reverse=False, tree=False, initial_vertex=None): from sage.graphs.digraph import DiGraph g = DiGraph(sparse=True) return [], g - else: - return [] + return [] # Build adjacency list of G cdef list int_to_v = list(G) @@ -821,9 +819,7 @@ def lex_DFS(G, reverse=False, tree=False, initial_vertex=None): edges = [(int_to_v[i], int_to_v[pred[i]]) for i in range(nV) if pred[i] != -1] g.add_edges(edges) return value, g - - else: - return value + return value def lex_DOWN(G, reverse=False, tree=False, initial_vertex=None): @@ -889,6 +885,7 @@ def lex_DOWN(G, reverse=False, tree=False, initial_vertex=None): Different orderings for different traversals:: + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2,3) sage: G.lex_BFS(initial_vertex='000') ['000', '001', '100', '010', '011', '110', '101', '111'] @@ -943,8 +940,7 @@ def lex_DOWN(G, reverse=False, tree=False, initial_vertex=None): from sage.graphs.digraph import DiGraph g = DiGraph(sparse=True) return [], g - else: - return [] + return [] # Build adjacency list of G cdef list int_to_v = list(G) @@ -996,9 +992,7 @@ def lex_DOWN(G, reverse=False, tree=False, initial_vertex=None): edges = [(int_to_v[i], int_to_v[pred[i]]) for i in range(nV) if pred[i] != -1] g.add_edges(edges) return value, g - - else: - return value + return value def lex_M(self, triangulation=False, labels=False, initial_vertex=None, algorithm=None): @@ -1147,10 +1141,9 @@ def lex_M(self, triangulation=False, labels=False, initial_vertex=None, algorith if algorithm == "lex_M_slow": return lex_M_slow(self, triangulation=triangulation, labels=labels, initial_vertex=initial_vertex) - else: - if labels: - raise ValueError("'{}' cannot return labels assigned to vertices".format(algorithm)) - return lex_M_fast(self, triangulation=triangulation, initial_vertex=initial_vertex) + if labels: + raise ValueError("'{}' cannot return labels assigned to vertices".format(algorithm)) + return lex_M_fast(self, triangulation=triangulation, initial_vertex=initial_vertex) def lex_M_slow(G, triangulation=False, labels=False, initial_vertex=None): @@ -1313,8 +1306,7 @@ def lex_M_slow(G, triangulation=False, labels=False, initial_vertex=None): return alpha, F elif labels: return alpha, label - else: - return alpha + return alpha def lex_M_fast(G, triangulation=False, initial_vertex=None): @@ -1518,8 +1510,7 @@ def lex_M_fast(G, triangulation=False, initial_vertex=None): if triangulation: return ordering, F - else: - return ordering + return ordering def is_valid_lex_M_order(G, alpha, F): @@ -2009,7 +2000,7 @@ def maximum_cardinality_search_M(G, initial_vertex=None): ....: if len(X) < k - 1: ....: raise ValueError("something goes wrong") sage: G = graphs.RandomGNP(10, .2) - sage: cc = G.connected_components() + sage: cc = G.connected_components(sort=False) sage: _, _, X = G.maximum_cardinality_search_M() sage: len(X) >= len(cc) - 1 True diff --git a/src/sage/graphs/tutte_polynomial.py b/src/sage/graphs/tutte_polynomial.py index 62d48f98c61..5a7b048ddfe 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -317,7 +317,7 @@ def find_ear(g): in g.degree_iterator(labels=True) if degree == 2] subgraph = g.subgraph(degree_two_vertices) - for component in subgraph.connected_components(): + for component in subgraph.connected_components(sort=False): edges = g.edges_incident(vertices=component, labels=True) all_vertices = sorted(set(sum([e[:2] for e in edges], ()))) if len(all_vertices) < 3: @@ -532,7 +532,7 @@ def tutte_polynomial(G, edge_selector=None, cache=None): The Tutte polynomial of any tree of order `n` is `x^{n-1}`:: - sage: all(T.tutte_polynomial() == x**9 for T in graphs.trees(10)) + sage: all(T.tutte_polynomial() == x**9 for T in graphs.trees(10)) # needs sage.symbolic True The Tutte polynomial of the Petersen graph is:: @@ -550,7 +550,7 @@ def tutte_polynomial(G, edge_selector=None, cache=None): sage: G = graphs.RandomGNP(10,0.6) sage: while not G.is_connected(): ....: G = graphs.RandomGNP(10,0.6) - sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count() + sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count() # needs sage.modules True Given that `T(x,y)` is the Tutte polynomial of a graph `G` with @@ -560,7 +560,7 @@ def tutte_polynomial(G, edge_selector=None, cache=None): sage: G = graphs.OctahedralGraph() sage: T = G.tutte_polynomial() sage: R = PolynomialRing(ZZ, 'x') - sage: R((-1)^5*x*T(1-x,0)).factor() + sage: R((-1)^5*x*T(1-x,0)).factor() # needs sage.symbolic (x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32) sage: G.chromatic_polynomial().factor() (x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 51a4a738e46..05534c744ef 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -64,18 +64,10 @@ cdef class EdgesView: - ``ignore_direction`` -- boolean (default: ``False``); only applies to directed graphs. If ``True``, searches across edges in either direction. - - ``sort`` -- boolean (default: ``None``); whether to sort edges - - - if ``None``, sort edges according to the default ordering and give a - deprecation warning as sorting will be set to ``False`` by default in - the future - - - if ``True``, edges are sorted according the ordering specified with - parameter ``key`` - - - if ``False``, edges are not sorted. This is the fastest and less memory - consuming method for iterating over edges. This will become the default - behavior in the future. + - ``sort`` -- boolean (default: ``False``); whether to sort edges according + the ordering specified with parameter ``key``. If ``False`` (default), + edges are not sorted. This is the fastest and less memory consuming method + for iterating over edges. - ``key`` -- a function (default: ``None``); a function that takes an edge (a pair or a triple, according to the ``labels`` keyword) as its one @@ -175,11 +167,11 @@ cdef class EdgesView: With a directed graph:: - sage: G = digraphs.DeBruijn(2, 2) - sage: E = EdgesView(G, labels=False, sort=True); E + sage: G = digraphs.DeBruijn(2, 2) # needs sage.combinat + sage: E = EdgesView(G, labels=False, sort=True); E # needs sage.combinat [('00', '00'), ('00', '01'), ('01', '10'), ('01', '11'), ('10', '00'), ('10', '01'), ('11', '10'), ('11', '11')] - sage: E = EdgesView(G, labels=False, sort=True, key=lambda e:(e[1], e[0])); E + sage: E = EdgesView(G, labels=False, sort=True, key=lambda e:(e[1], e[0])); E # needs sage.combinat [('00', '00'), ('10', '00'), ('00', '01'), ('10', '01'), ('01', '10'), ('11', '10'), ('01', '11'), ('11', '11')] @@ -350,7 +342,7 @@ cdef class EdgesView: def __init__(self, G, vertices=None, vertices2=None, labels=True, ignore_direction=False, - sort=None, key=None, sort_vertices=True): + sort=False, key=None, sort_vertices=True): """ Construction of this :class:`EdgesView`. @@ -420,8 +412,7 @@ cdef class EdgesView: if self._graph._directed and self._ignore_direction: return 2 * self._graph.size() return self._graph.size() - else: - return sum(1 for _ in self) + return sum(1 for _ in self) def __repr__(self): """ @@ -654,20 +645,20 @@ cdef class EdgesView: return (self._graph._backend.has_edge(u, v, label) or self._graph._backend.has_edge(v, u, label)) return self._graph._backend.has_edge(u, v, label) - else: - if u not in self._vertex_set2 and v not in self._vertex_set2: - return False - if (self._vertex_set is not None - and u not in self._vertex_set and v not in self._vertex_set): + + if u not in self._vertex_set2 and v not in self._vertex_set2: + return False + if (self._vertex_set is not None + and u not in self._vertex_set and v not in self._vertex_set): + return False + if self._graph._directed: + if self._ignore_direction: + return (self._graph._backend.has_edge(u, v, label) + or self._graph._backend.has_edge(v, u, label)) + elif ((self._vertex_set is not None and u not in self._vertex_set) + or v not in self._vertex_set2): return False - if self._graph._directed: - if self._ignore_direction: - return (self._graph._backend.has_edge(u, v, label) - or self._graph._backend.has_edge(v, u, label)) - elif ((self._vertex_set is not None and u not in self._vertex_set) - or v not in self._vertex_set2): - return False - return self._graph._backend.has_edge(u, v, label) + return self._graph._backend.has_edge(u, v, label) def __getitem__(self, i): r""" @@ -711,11 +702,10 @@ cdef class EdgesView: return list(self)[i] elif i < 0: return list(self)[i] - else: - try: - return next(islice(self, i, i + 1, 1)) - except StopIteration: - raise IndexError('index out of range') + try: + return next(islice(self, i, i + 1, 1)) + except StopIteration: + raise IndexError('index out of range') def __add__(left, right): """ @@ -799,6 +789,5 @@ cdef class EdgesView: """ if isinstance(left, EdgesView): return list(left) * right - else: - # Case __rmul__ - return list(right) * left + # Case __rmul__ + return list(right) * left diff --git a/src/sage/graphs/weakly_chordal.pyx b/src/sage/graphs/weakly_chordal.pyx index 79e574fc4f5..44c35e39dbe 100644 --- a/src/sage/graphs/weakly_chordal.pyx +++ b/src/sage/graphs/weakly_chordal.pyx @@ -263,8 +263,7 @@ def is_long_hole_free(g, certificate=False): if certificate: return False, hole - else: - return False + return False InPath[v] = -1 InPath[u] = -1 @@ -275,8 +274,7 @@ def is_long_hole_free(g, certificate=False): if certificate: return True, [] - else: - return True + return True cdef inline is_long_antihole_free_process(g, short_digraph sd, bitset_t dense_graph, @@ -495,8 +493,7 @@ def is_long_antihole_free(g, certificate=False): if certificate: return False, antihole - else: - return False + return False InPath[v] = -1 InPath[u] = -1 @@ -507,8 +504,7 @@ def is_long_antihole_free(g, certificate=False): if certificate: return True, [] - else: - return True + return True def is_weakly_chordal(g, certificate=False): @@ -562,5 +558,5 @@ def is_weakly_chordal(g, certificate=False): return False, forbid_subgr return g.is_long_antihole_free(certificate=True) - else: - return g.is_long_hole_free() and g.is_long_antihole_free() + + return g.is_long_hole_free() and g.is_long_antihole_free() diff --git a/src/sage/groups/__init__.py b/src/sage/groups/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/groups/abelian_gps/__init__.py b/src/sage/groups/abelian_gps/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/groups/abelian_gps/abelian_aut.py b/src/sage/groups/abelian_gps/abelian_aut.py index bf54b8a0ad9..86051c72b28 100644 --- a/src/sage/groups/abelian_gps/abelian_aut.py +++ b/src/sage/groups/abelian_gps/abelian_aut.py @@ -55,8 +55,8 @@ Only automorphism groups of finite abelian groups are supported:: - sage: G = AbelianGroupGap([0,2]) # optional gap_packages - sage: autG = G.aut() # optional gap_packages + sage: G = AbelianGroupGap([0,2]) # optional - gap_package_polycyclic + sage: autG = G.aut() # optional - gap_package_polycyclic Traceback (most recent call last): ... ValueError: only finite abelian groups are supported diff --git a/src/sage/groups/abelian_gps/abelian_group.py b/src/sage/groups/abelian_gps/abelian_group.py index a56ae71d8bd..898ca9cebb5 100644 --- a/src/sage/groups/abelian_gps/abelian_group.py +++ b/src/sage/groups/abelian_gps/abelian_group.py @@ -201,22 +201,24 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from itertools import product -from sage.rings.integer import Integer -from sage.rings.integer_ring import ZZ -from sage.structure.category_object import normalize_names -from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.infinity import infinity -from sage.arith.all import divisors, gcd, lcm +from sage.arith.functions import lcm +from sage.arith.misc import divisors, gcd +from sage.categories.groups import Groups from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement -from sage.misc.cachefunc import cached_method -from sage.misc.misc_c import prod -from sage.misc.mrange import mrange, cartesian_product_iterator from sage.groups.group import AbelianGroup as AbelianGroupBase -from sage.categories.groups import Groups from sage.matrix.constructor import matrix from sage.matrix.special import diagonal_matrix +from sage.misc.cachefunc import cached_method +from sage.misc.misc_c import prod +from sage.misc.mrange import mrange from sage.modules.free_module_element import vector +from sage.rings.infinity import infinity +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.structure.category_object import normalize_names +from sage.structure.unique_representation import UniqueRepresentation # TODO: this uses perm groups - the AbelianGroupElement instance method @@ -253,35 +255,38 @@ def word_problem(words, g, verbose=False): EXAMPLES:: - sage: G.<a,b,c> = AbelianGroup(3,[2,3,4]); G + sage: # needs sage.libs.gap + sage: G.<a,b,c> = AbelianGroup(3, [2,3,4]); G Multiplicative Abelian group isomorphic to C2 x C3 x C4 - sage: w = word_problem([a*b,a*c], b*c); w #random + sage: w = word_problem([a*b,a*c], b*c); w # random [[a*b, 1], [a*c, 1]] sage: prod([x^i for x,i in w]) == b*c True - sage: w = word_problem([a*c,c],a); w #random + sage: w = word_problem([a*c,c], a); w # random [[a*c, 1], [c, -1]] sage: prod([x^i for x,i in w]) == a True - sage: word_problem([a*c,c],a,verbose=True) #random + sage: word_problem([a*c,c], a, verbose=True) # random a = (a*c)^1*(c)^-1 [[a*c, 1], [c, -1]] :: - sage: A.<a,b,c,d,e> = AbelianGroup(5,[4, 5, 5, 7, 8]) + sage: # needs sage.libs.gap + sage: A.<a,b,c,d,e> = AbelianGroup(5, [4, 5, 5, 7, 8]) sage: b1 = a^3*b*c*d^2*e^5 sage: b2 = a^2*b*c^2*d^3*e^3 sage: b3 = a^7*b^3*c^5*d^4*e^4 sage: b4 = a^3*b^2*c^2*d^3*e^5 sage: b5 = a^2*b^4*c^2*d^4*e^5 - sage: w = word_problem([b1,b2,b3,b4,b5],e); w #random - [[a^3*b*c*d^2*e^5, 1], [a^2*b*c^2*d^3*e^3, 1], [a^3*b^3*d^4*e^4, 3], [a^2*b^4*c^2*d^4*e^5, 1]] + sage: w = word_problem([b1,b2,b3,b4,b5], e); w # random + [[a^3*b*c*d^2*e^5, 1], [a^2*b*c^2*d^3*e^3, 1], + [a^3*b^3*d^4*e^4, 3], [a^2*b^4*c^2*d^4*e^5, 1]] sage: prod([x^i for x,i in w]) == e True - sage: word_problem([a,b,c,d,e],e) + sage: word_problem([a,b,c,d,e], e) [[e, 1]] - sage: word_problem([a,b,c,d,e],b) + sage: word_problem([a,b,c,d,e], b) [[b, 1]] .. warning:: @@ -412,7 +417,7 @@ def AbelianGroup(n, gens_orders=None, names="f"): a^2*b^2*c^2*d^2 sage: d * b**2 * c**3 b^2*c^3*d - sage: F = AbelianGroup(3,[2]*3); F + sage: F = AbelianGroup(3, [2]*3); F Multiplicative Abelian group isomorphic to C2 x C2 x C2 sage: H = AbelianGroup([2,3], names="xy"); H Multiplicative Abelian group isomorphic to C2 x C3 @@ -446,7 +451,7 @@ def is_AbelianGroup(x): EXAMPLES:: sage: from sage.groups.abelian_gps.abelian_group import is_AbelianGroup - sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F + sage: F = AbelianGroup(5,[5,5,7,8,9], names=list("abcde")); F Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9 sage: is_AbelianGroup(F) True @@ -486,9 +491,9 @@ class AbelianGroup_class(UniqueRepresentation, AbelianGroupBase): sage: Z2xZ3.is_isomorphic(Z6) True - sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F + sage: F = AbelianGroup(5,[5,5,7,8,9], names=list("abcde")); F Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9 - sage: F = AbelianGroup(5,[2, 4, 12, 24, 120],names = list("abcde")); F + sage: F = AbelianGroup(5,[2, 4, 12, 24, 120], names=list("abcde")); F Multiplicative Abelian group isomorphic to C2 x C4 x C12 x C24 x C120 sage: F.elementary_divisors() (2, 4, 12, 24, 120) @@ -515,7 +520,7 @@ def __init__(self, generator_orders, names, category=None): TESTS:: - sage: G = AbelianGroup([0,5,0,7],names = list("abcd")); G + sage: G = AbelianGroup([0,5,0,7], names=list("abcd")); G Multiplicative Abelian group isomorphic to Z x C5 x Z x C7 sage: TestSuite(G).run() @@ -576,8 +581,8 @@ def is_subgroup(left, right): sage: G.is_subgroup(G) True - sage: H = G.subgroup([G.1]) - sage: H.is_subgroup(G) + sage: H = G.subgroup([G.1]) # needs sage.libs.gap + sage: H.is_subgroup(G) # needs sage.libs.gap True sage: G.<a, b> = AbelianGroup(2) @@ -653,7 +658,7 @@ def __bool__(self) -> bool: EXAMPLES:: sage: T = AbelianGroup([2, 3]) - sage: bool(T) # indirect doctest + sage: bool(T) # indirect doctest True sage: bool(AbelianGroup([])) False @@ -682,11 +687,11 @@ def dual_group(self, names="X", base_ring=None): EXAMPLES:: sage: G = AbelianGroup([2]) - sage: G.dual_group() + sage: G.dual_group() # needs sage.rings.number_field Dual of Abelian Group isomorphic to Z/2Z over Cyclotomic Field of order 2 and degree 1 - sage: G.dual_group().gens() + sage: G.dual_group().gens() # needs sage.rings.number_field (X,) - sage: G.dual_group(names='Z').gens() + sage: G.dual_group(names='Z').gens() # needs sage.rings.number_field (Z,) sage: G.dual_group(base_ring=QQ) @@ -735,13 +740,13 @@ def elementary_divisors(self): EXAMPLES:: - sage: G = AbelianGroup(2,[2,3]) + sage: G = AbelianGroup(2, [2,3]) sage: G.elementary_divisors() (6,) sage: G = AbelianGroup(1, [6]) sage: G.elementary_divisors() (6,) - sage: G = AbelianGroup(2,[2,6]) + sage: G = AbelianGroup(2, [2,6]) sage: G Multiplicative Abelian group isomorphic to C2 x C6 sage: G.gens_orders() @@ -751,7 +756,7 @@ def elementary_divisors(self): sage: J = AbelianGroup([1,3,5,12]) sage: J.elementary_divisors() (3, 60) - sage: G = AbelianGroup(2,[0,6]) + sage: G = AbelianGroup(2, [0,6]) sage: G.elementary_divisors() (6, 0) sage: AbelianGroup([3,4,5]).elementary_divisors() @@ -844,18 +849,18 @@ def _libgap_(self): EXAMPLES:: sage: G = AbelianGroup([2,3,9]) - sage: libgap(G) + sage: libgap(G) # needs sage.libs.gap <pc group of size 54 with 3 generators> The result is cached:: - sage: libgap(G) is libgap(G) + sage: libgap(G) is libgap(G) # needs sage.libs.gap True Requires the optional ``gap_packages`` for infinite groups:: sage: G = AbelianGroup(3, [0,3,4], names="abc") - sage: libgap(G) # optional - gap_packages + sage: libgap(G) # optional - gap_package_polycyclic Pcp-group with orders [ 0, 3, 4 ] """ from sage.libs.gap.libgap import libgap @@ -877,14 +882,14 @@ def _gap_init_(self): sage: G = AbelianGroup([2,3,9]) sage: G._gap_init_() 'AbelianGroup([2, 3, 9])' - sage: gap(G) + sage: gap(G) # needs sage.libs.gap Group( [ f1, f2, f3 ] ) Requires the optional ``gap_packages`` for infinite groups:: sage: G = AbelianGroup(3,[0,3,4], names="abc"); G Multiplicative Abelian group isomorphic to Z x C3 x C4 - sage: G._gap_init_() # optional - gap_packages + sage: G._gap_init_() # optional - gap_package_polycyclic 'AbelianPcpGroup([0, 3, 4])' """ if self.is_finite(): @@ -932,10 +937,10 @@ def gens(self): EXAMPLES:: - sage: F = AbelianGroup(5,[3,2],names='abcde') + sage: F = AbelianGroup(5, [3,2], names='abcde') sage: F.gens() (a, b, c, d, e) - sage: [ g.order() for g in F.gens() ] + sage: [g.order() for g in F.gens()] [+Infinity, +Infinity, +Infinity, 3, 2] """ return tuple( self.gen(i) for i in range(self.ngens()) ) @@ -1058,12 +1063,12 @@ def is_cyclic(self): (2, 4) sage: H.is_cyclic() False - sage: H.permutation_group().is_cyclic() + sage: H.permutation_group().is_cyclic() # needs sage.groups False sage: T = AbelianGroup([]) sage: T.is_cyclic() True - sage: T = AbelianGroup(1,[0]); T + sage: T = AbelianGroup(1, [0]); T Multiplicative Abelian group isomorphic to Z sage: T.is_cyclic() True @@ -1093,10 +1098,10 @@ def order(self): EXAMPLES:: - sage: G = AbelianGroup(2,[2,3]) + sage: G = AbelianGroup(2, [2,3]) sage: G.order() 6 - sage: G = AbelianGroup(3,[2,3,0]) + sage: G = AbelianGroup(3, [2,3,0]) sage: G.order() +Infinity """ @@ -1120,7 +1125,7 @@ def permutation_group(self): sage: G = AbelianGroup(2,[2,3]); G Multiplicative Abelian group isomorphic to C2 x C3 - sage: G.permutation_group() + sage: G.permutation_group() # needs sage.groups Permutation Group with generators [(3,4,5), (1,2)] TESTS: @@ -1197,27 +1202,29 @@ def subgroup(self, gensH, names="f"): INPUT: - ``gensH`` -- list of elements which are products of the - generators of the ambient abelian group G = self + generators of the ambient abelian group `G` = ``self`` EXAMPLES:: - sage: G.<a,b,c> = AbelianGroup(3, [2,3,4]); G - Multiplicative Abelian group isomorphic to C2 x C3 x C4 - sage: H = G.subgroup([a*b,a]); H - Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a*b, a} - sage: H < G - True - sage: F = G.subgroup([a,b^2]) - sage: F - Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2} - sage: F.gens() - (a, b^2) - sage: F = AbelianGroup(5,[30,64,729],names = list("abcde")) - sage: a,b,c,d,e = F.gens() - sage: F.subgroup([a,b]) - Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b} - sage: F.subgroup([c,e]) - Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 x C729 generated by {c, e} + sage: # needs sage.libs.gap + sage: G.<a,b,c> = AbelianGroup(3, [2,3,4]); G + Multiplicative Abelian group isomorphic to C2 x C3 x C4 + sage: H = G.subgroup([a*b,a]); H + Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a*b, a} + sage: H < G + True + sage: F = G.subgroup([a,b^2]) + sage: F + Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2} + sage: F.gens() + (a, b^2) + sage: F = AbelianGroup(5, [30,64,729], names=list("abcde")) + sage: a,b,c,d,e = F.gens() + sage: F.subgroup([a,b]) + Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b} + sage: F.subgroup([c,e]) + Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 x C729 + generated by {c, e} """ G = self gensH = tuple(gensH) @@ -1326,10 +1333,12 @@ def number_of_subgroups(self, order=None): EXAMPLES:: - sage: AbelianGroup([2,3]).number_of_subgroups() - 4 sage: AbelianGroup([2,0,0,3,0]).number_of_subgroups() +Infinity + + sage: # needs sage.combinat + sage: AbelianGroup([2,3]).number_of_subgroups() + 4 sage: AbelianGroup([2,4,8]).number_of_subgroups() 81 sage: AbelianGroup([2,4,8]).number_of_subgroups(order=4) @@ -1343,6 +1352,7 @@ def number_of_subgroups(self, order=None): TESTS:: + sage: # needs sage.combinat sage: AbelianGroup([]).number_of_subgroups() 1 sage: AbelianGroup([1,3,1]).number_of_subgroups() @@ -1351,7 +1361,7 @@ def number_of_subgroups(self, order=None): 0 sage: AbelianGroup([1,3,1]).number_of_subgroups(order=2) 0 - sage: AbelianGroup([1,3,0,1]).number_of_subgroups(order=3) + sage: AbelianGroup([1,3,0,1]).number_of_subgroups(order=3) # needs sage.libs.gap 1 sage: AbelianGroup([1,3,1]).number_of_subgroups(order=-2) Traceback (most recent call last): @@ -1441,12 +1451,12 @@ def subgroups(self, check=False): EXAMPLES:: - sage: AbelianGroup([2,3]).subgroups() + sage: AbelianGroup([2,3]).subgroups() # needs sage.libs.gap [Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {f0*f1^2}, Multiplicative Abelian subgroup isomorphic to C2 generated by {f0}, Multiplicative Abelian subgroup isomorphic to C3 generated by {f1}, Trivial Abelian subgroup] - sage: len(AbelianGroup([2,4,8]).subgroups()) + sage: len(AbelianGroup([2,4,8]).subgroups()) # needs sage.libs.gap 81 TESTS:: @@ -1457,10 +1467,10 @@ def subgroups(self, check=False): Check that :trac:`14196` is fixed:: sage: B = AbelianGroup([1,2]) - sage: B.subgroups() + sage: B.subgroups() # needs sage.libs.gap [Multiplicative Abelian subgroup isomorphic to C2 generated by {f1}, Trivial Abelian subgroup] - sage: B.subgroups(check=True) + sage: B.subgroups(check=True) # needs sage.libs.gap [Multiplicative Abelian subgroup isomorphic to C2 generated by {f1}, Trivial Abelian subgroup] """ @@ -1489,7 +1499,7 @@ def subgroups(self, check=False): # H = the subgroup of *index* H. its = [range(0, H, H // gcd(H, G.gen(i).order())) for i in range(ngens)] - for f in cartesian_product_iterator(its): + for f in product(*its): verbose("using hom from G to C_%s sending gens to %s" % (H, f)) new_sub = [] for a in range(ngens): @@ -1524,10 +1534,10 @@ def subgroup_reduced(self, elts, verbose=False): EXAMPLES:: sage: G = AbelianGroup([4,4]) - sage: G.subgroup( [ G([1,0]), G([1,2]) ]) + sage: G.subgroup( [ G([1,0]), G([1,2]) ]) # needs sage.libs.gap Multiplicative Abelian subgroup isomorphic to C2 x C4 generated by {f0, f0*f1^2} - sage: AbelianGroup([4,4]).subgroup_reduced( [ [1,0], [1,2] ]) + sage: AbelianGroup([4,4]).subgroup_reduced( [ [1,0], [1,2] ]) # needs sage.libs.gap Multiplicative Abelian subgroup isomorphic to C2 x C4 generated by {f0^2*f1^2, f0^3} """ @@ -1558,6 +1568,7 @@ def torsion_subgroup(self, n=None): EXAMPLES:: + sage: # needs sage.libs.gap sage: G = AbelianGroup([2, 3]) sage: G.torsion_subgroup() Multiplicative Abelian subgroup isomorphic to C2 x C3 generated @@ -1576,7 +1587,7 @@ def torsion_subgroup(self, n=None): :: sage: G = AbelianGroup([2, 2*3, 2*3*5, 0, 2*3*5*7, 2*3*5*7*11]) - sage: G.torsion_subgroup(5) + sage: G.torsion_subgroup(5) # needs sage.libs.gap Multiplicative Abelian subgroup isomorphic to C5 x C5 x C5 generated by {f2^6, f4^42, f5^462} """ if n is None: @@ -1609,7 +1620,8 @@ def __init__(self, ambient, gens, names="f", category=None): """ EXAMPLES:: - sage: F = AbelianGroup(5,[30,64,729],names = list("abcde")) + sage: # needs sage.libs.gap + sage: F = AbelianGroup(5, [30,64,729], names=list("abcde")) sage: a,b,c,d,e = F.gens() sage: F.subgroup([a^3,b]) Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a^3, b} @@ -1621,11 +1633,11 @@ def __init__(self, ambient, gens, names="f", category=None): Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b*c} sage: F.subgroup([b*c, d]) Multiplicative Abelian subgroup isomorphic to C64 x Z generated by {b*c, d} - sage: F.subgroup([a*b, c^6, d],names=list("xyz")) + sage: F.subgroup([a*b, c^6, d], names=list("xyz")) Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d} sage: H.<x,y,z> = F.subgroup([a*b, c^6, d]); H Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d} - sage: G = F.subgroup([a*b, c^6, d],names = list("xyz")); G + sage: G = F.subgroup([a*b, c^6, d], names=list("xyz")); G Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d} sage: x,y,z = G.gens() sage: x.order() @@ -1634,7 +1646,7 @@ def __init__(self, ambient, gens, names="f", category=None): 5 sage: z.order() 64 - sage: A = AbelianGroup(5,[3, 5, 5, 7, 8], names = "abcde") + sage: A = AbelianGroup(5, [3, 5, 5, 7, 8], names="abcde") sage: a,b,c,d,e = A.gens() sage: A.subgroup([a,b]) Multiplicative Abelian subgroup isomorphic to C3 x C5 generated by {a, b} @@ -1646,7 +1658,7 @@ def __init__(self, ambient, gens, names="f", category=None): Multiplicative Abelian subgroup isomorphic to C4 x C5 x C5 x C7 generated by {b, c, d, e^2} sage: B.gens_orders() (4, 5, 5, 7) - sage: A = AbelianGroup(4,[1009, 2003, 3001, 4001], names = "abcd") + sage: A = AbelianGroup(4,[1009, 2003, 3001, 4001], names="abcd") sage: a,b,c,d = A.gens() sage: B = A.subgroup([a^3,b,c,d]) sage: B.gens_orders() @@ -1655,7 +1667,7 @@ def __init__(self, ambient, gens, names="f", category=None): 24266473210027 sage: B.order() 24266473210027 - sage: A = AbelianGroup(4,[1008, 2003, 3001, 4001], names = "abcd") + sage: A = AbelianGroup(4, [1008, 2003, 3001, 4001], names="abcd") sage: a,b,c,d = A.gens() sage: B = A.subgroup([a^3,b,c,d]); B Multiplicative Abelian subgroup isomorphic @@ -1663,23 +1675,25 @@ def __init__(self, ambient, gens, names="f", category=None): Infinite groups can also be handled:: - sage: G = AbelianGroup([3,4,0], names = "abc") + sage: G = AbelianGroup([3,4,0], names="abc") sage: a,b,c = G.gens() - sage: F = G.subgroup([a, b^2, c]); F - Multiplicative Abelian subgroup isomorphic to C2 x C3 x Z generated by {a, b^2, c} + sage: F = G.subgroup([a, b^2, c]); F # needs sage.libs.gap + Multiplicative Abelian subgroup isomorphic to C2 x C3 x Z + generated by {a, b^2, c} - sage: F.gens_orders() + sage: F.gens_orders() # needs sage.libs.gap (2, 3, 0) - sage: F.gens() + sage: F.gens() # needs sage.libs.gap (a, b^2, c) - sage: F.order() + sage: F.order() # needs sage.libs.gap +Infinity Testing issue :trac:`18863`:: sage: G = AbelianGroup(5,[2]) - sage: G.subgroup([prod(g^k for g,k in zip(G.gens(),[1,-2,3,-4,5]))]) - Multiplicative Abelian subgroup isomorphic to Z generated by {f0*f1^-2*f2^3*f3^-4*f4} + sage: G.subgroup([prod(g^k for g,k in zip(G.gens(),[1,-2,3,-4,5]))]) # needs sage.libs.gap + Multiplicative Abelian subgroup isomorphic to Z + generated by {f0*f1^-2*f2^3*f3^-4*f4} """ from sage.libs.gap.libgap import libgap if not isinstance(ambient, AbelianGroup_class): @@ -1712,10 +1726,10 @@ def __contains__(self, x): EXAMPLES:: sage: G.<a,b> = AbelianGroup(2) - sage: A = G.subgroup([a]) + sage: A = G.subgroup([a]) # needs sage.libs.gap sage: a in G True - sage: a in A + sage: a in A # needs sage.libs.gap True TESTS: @@ -1724,22 +1738,22 @@ def __contains__(self, x): sage: G.<a,b> = AbelianGroup(2, [4, 576]) sage: Hgens = [a^2, a*b^2] - sage: H = G.subgroup(Hgens) - sage: [g in H for g in (a^3, b^2, b^3, a^3*b^2, "junk")] + sage: H = G.subgroup(Hgens) # needs sage.libs.gap + sage: [g in H for g in (a^3, b^2, b^3, a^3*b^2, "junk")] # needs sage.libs.gap [False, False, False, True, False] Check that :trac:`31507` is fixed:: sage: G = AbelianGroup(2, gens_orders=[16, 16]) sage: f0, f1 = G.gens() - sage: H = G.subgroup([f0*f1^3]) - sage: [g in H for g in (f0, f0*f1^2, f0*f1^3, f0*f1^4)] + sage: H = G.subgroup([f0*f1^3]) # needs sage.libs.gap + sage: [g in H for g in (f0, f0*f1^2, f0*f1^3, f0*f1^4)] # needs sage.libs.gap [False, False, True, False] sage: G.<a,b> = AbelianGroup(2) sage: Hgens = [a*b, a*b^-1] - sage: H = G.subgroup(Hgens) - sage: b^2 in H + sage: H = G.subgroup(Hgens) # needs sage.libs.gap + sage: b^2 in H # needs sage.libs.gap True """ if not isinstance(x, AbelianGroupElement): @@ -1768,8 +1782,8 @@ def ambient_group(self): EXAMPLES:: sage: G.<a,b,c> = AbelianGroup([2,3,4]) - sage: H = G.subgroup([a, b^2]) - sage: H.ambient_group() is G + sage: H = G.subgroup([a, b^2]) # needs sage.libs.gap + sage: H.ambient_group() is G # needs sage.libs.gap True """ return self._ambient_group @@ -1794,15 +1808,16 @@ def equals(left, right): sage: G = AbelianGroup(3, [2,3,4], names="abc"); G Multiplicative Abelian group isomorphic to C2 x C3 x C4 sage: a,b,c = G.gens() - sage: F = G.subgroup([a,b^2]); F + sage: F = G.subgroup([a,b^2]); F # needs sage.libs.gap Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2} - sage: F<G + sage: F<G # needs sage.libs.gap True sage: A = AbelianGroup(1, [6]) - sage: A.subgroup(list(A.gens())) == A + sage: A.subgroup(list(A.gens())) == A # needs sage.libs.gap True + sage: # needs sage.libs.gap sage: G.<a,b> = AbelianGroup(2) sage: A = G.subgroup([a]) sage: B = G.subgroup([b]) @@ -1834,8 +1849,8 @@ def _repr_(self): sage: G.<a,b> = AbelianGroup(2) sage: G._repr_() 'Multiplicative Abelian group isomorphic to Z x Z' - sage: A = G.subgroup([a]) - sage: A._repr_() + sage: A = G.subgroup([a]) # needs sage.libs.gap + sage: A._repr_() # needs sage.libs.gap 'Multiplicative Abelian subgroup isomorphic to Z generated by {a}' """ eldv = self._abinvs @@ -1858,10 +1873,10 @@ def gens(self): EXAMPLES:: sage: G.<a,b> = AbelianGroup(2) - sage: A = G.subgroup([a]) + sage: A = G.subgroup([a]) # needs sage.libs.gap sage: G.gens() (a, b) - sage: A.gens() + sage: A.gens() # needs sage.libs.gap (a,) """ return self._gens @@ -1873,11 +1888,12 @@ def gen(self, n): EXAMPLES:: sage: G.<a,b> = AbelianGroup(2) - sage: A = G.subgroup([a]) - sage: A.gen(0) + sage: A = G.subgroup([a]) # needs sage.libs.gap + sage: A.gen(0) # needs sage.libs.gap a """ return self._gens[n] + # We allow subclasses to override this, analogous to Element AbelianGroup_class.Subgroup = AbelianGroup_subgroup diff --git a/src/sage/groups/abelian_gps/abelian_group_element.py b/src/sage/groups/abelian_gps/abelian_group_element.py index 1b0c9cd590c..6ae81844f98 100644 --- a/src/sage/groups/abelian_gps/abelian_group_element.py +++ b/src/sage/groups/abelian_gps/abelian_group_element.py @@ -97,16 +97,16 @@ def as_permutation(self): EXAMPLES:: - sage: G = AbelianGroup(3,[2,3,4],names="abc"); G + sage: G = AbelianGroup(3, [2,3,4], names="abc"); G Multiplicative Abelian group isomorphic to C2 x C3 x C4 sage: a,b,c = G.gens() - sage: Gp = G.permutation_group(); Gp + sage: Gp = G.permutation_group(); Gp # needs sage.groups Permutation Group with generators [(6,7,8,9), (3,4,5), (1,2)] - sage: a.as_permutation() + sage: a.as_permutation() # needs sage.libs.gap (1,2) - sage: ap = a.as_permutation(); ap + sage: ap = a.as_permutation(); ap # needs sage.libs.gap (1,2) - sage: ap in Gp + sage: ap in Gp # needs sage.groups sage.libs.gap True """ from sage.libs.gap.libgap import libgap @@ -138,13 +138,14 @@ def word_problem(self, words): EXAMPLES:: - sage: G = AbelianGroup(2,[2,3], names="xy") + sage: # needs sage.libs.gap + sage: G = AbelianGroup(2, [2,3], names="xy") sage: x,y = G.gens() sage: x.word_problem([x,y]) [[x, 1]] sage: y.word_problem([x,y]) [[y, 1]] - sage: v = (y*x).word_problem([x,y]); v #random + sage: v = (y*x).word_problem([x,y]); v # random [[x, 1], [y, 1]] sage: prod([x^i for x,i in v]) == y*x True diff --git a/src/sage/groups/abelian_gps/abelian_group_gap.py b/src/sage/groups/abelian_gps/abelian_group_gap.py index a4b047113c5..04ebb9d3ed1 100644 --- a/src/sage/groups/abelian_gps/abelian_group_gap.py +++ b/src/sage/groups/abelian_gps/abelian_group_gap.py @@ -11,7 +11,7 @@ For infinite abelian groups we use the GAP package ``Polycyclic``:: - sage: AbelianGroupGap([3,0]) # optional - gap_packages + sage: AbelianGroupGap([3,0]) # optional - gap_package_polycyclic Abelian group with gap, generator orders (3, 0) AUTHORS: @@ -183,9 +183,9 @@ def order(self): sage: g = G.gens()[0] sage: g.order() 4 - sage: G = AbelianGroupGap([0]) # optional - gap_packages - sage: g = G.gens()[0] # optional - gap_packages - sage: g.order() # optional - gap_packages + sage: G = AbelianGroupGap([0]) # optional - gap_package_polycyclic + sage: g = G.gens()[0] # optional - gap_package_polycyclic + sage: g.order() # optional - gap_package_polycyclic +Infinity """ return self.gap().Order().sage() @@ -197,8 +197,8 @@ class AbelianGroupElement_polycyclic(AbelianGroupElement_gap): TESTS:: sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap - sage: G = AbelianGroupGap([4,7,0]) # optional - gap_packages - sage: TestSuite(G.an_element()).run() # optional - gap_packages + sage: G = AbelianGroupGap([4,7,0]) # optional - gap_package_polycyclic + sage: TestSuite(G.an_element()).run() # optional - gap_package_polycyclic """ def exponents(self): r""" @@ -210,18 +210,20 @@ def exponents(self): EXAMPLES:: + sage: # optional - gap_package_polycyclic sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap - sage: G = AbelianGroupGap([4,7,0]) # optional - gap_packages - sage: gens = G.gens() # optional - gap_packages - sage: g = gens[0]^2 * gens[1]^4 * gens[2]^8 # optional - gap_packages - sage: g.exponents() # optional - gap_packages + sage: G = AbelianGroupGap([4,7,0]) + sage: gens = G.gens() + sage: g = gens[0]^2 * gens[1]^4 * gens[2]^8 + sage: g.exponents() (2, 4, 8) Efficiently handles very large groups:: - sage: G = AbelianGroupGap([2^30,5^30,0]) # optional - gap_packages - sage: f1, f2, f3 = G.gens() # optional - gap_packages - sage: (f1^12345*f2^123456789).exponents() # optional - gap_packages + sage: # optional - gap_package_polycyclic + sage: G = AbelianGroupGap([2^30,5^30,0]) + sage: f1, f2, f3 = G.gens() + sage: (f1^12345*f2^123456789).exponents() (12345, 123456789, 0) """ return tuple(self.gap().Exponents().sage()) @@ -338,7 +340,7 @@ def _element_constructor_(self, x, check=True): if isinstance(x, AbelianGroupElement_gap): try: if x in self._cover: - x = self.gap().NaturalHomomorphism().Image(x.gap()) + x = self._cover.gap().NaturalHomomorphismByNormalSubgroup(self._relations).Image(x.gap()) else: x = x.gap() except AttributeError: @@ -613,12 +615,14 @@ def subgroup(self, gens): sage: s = S.an_element() sage: g * s f2^2*f3*f5 - sage: G = AbelianGroupGap([3,4,0,2]) # optional - gap_packages - sage: gen = G.gens()[:2] # optional - gap_packages - sage: S = G.subgroup(gen) # optional - gap_packages - sage: g = G.an_element() # optional - gap_packages - sage: s = S.an_element() # optional - gap_packages - sage: g * s # optional - gap_packages + + sage: # optional - gap_package_polycyclic + sage: G = AbelianGroupGap([3,4,0,2]) + sage: gen = G.gens()[:2] + sage: S = G.subgroup(gen) + sage: g = G.an_element() + sage: s = S.an_element() + sage: g * s g1^2*g2^2*g3*g4 TESTS:: @@ -650,7 +654,7 @@ class AbelianGroupGap(AbelianGroup_gap): Abelian group with gap, generator orders (3, 6) sage: AbelianGroupGap([3,6,5]) Abelian group with gap, generator orders (3, 6, 5) - sage: AbelianGroupGap([3,6,0]) # optional - gap_packages + sage: AbelianGroupGap([3,6,0]) # optional - gap_package_polycyclic Abelian group with gap, generator orders (3, 6, 0) .. WARNING:: @@ -777,13 +781,14 @@ def __init__(self, ambient, gens): Check that we are in the correct category:: - sage: G = AbelianGroupGap([2,3,0]) # optional - gap_packages - sage: g = G.gens() # optional - gap_packages - sage: H1 = G.subgroup([g[0],g[1]]) # optional - gap_packages - sage: H1 in Groups().Finite() # optional - gap_packages + sage: # optional - gap_package_polycyclic + sage: G = AbelianGroupGap([2,3,0]) + sage: g = G.gens() + sage: H1 = G.subgroup([g[0],g[1]]) + sage: H1 in Groups().Finite() True - sage: H2 = G.subgroup([g[0],g[2]]) # optional - gap_packages - sage: H2 in Groups().Infinite() # optional - gap_packages + sage: H2 = G.subgroup([g[0],g[2]]) + sage: H2 in Groups().Infinite() True """ gens_gap = tuple([g.gap() for g in gens]) @@ -994,7 +999,6 @@ def _coerce_map_from_(self, S): if isinstance(S, AbelianGroup_gap): return self._cover._coerce_map_from_(S) - def cover(self): r""" Return the covering group of this quotient group. @@ -1043,7 +1047,7 @@ def natural_homomorphism(self): From: Abelian group with gap, generator orders (4,) To: Quotient abelian group with generator orders (2,) """ - phi = self.gap().NaturalHomomorphism() + phi = self._cover.gap().NaturalHomomorphismByNormalSubgroup(self._relations) Hom = self._cover.Hom(self) return Hom(phi) diff --git a/src/sage/groups/abelian_gps/dual_abelian_group.py b/src/sage/groups/abelian_gps/dual_abelian_group.py index a1650f4eab0..2ee86f7f423 100644 --- a/src/sage/groups/abelian_gps/dual_abelian_group.py +++ b/src/sage/groups/abelian_gps/dual_abelian_group.py @@ -25,6 +25,7 @@ sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde') sage: (a, b, c, d, e) = F.gens() + sage: # needs sage.rings.number_field sage: Fd = F.dual_group(names='ABCDE') sage: Fd.base_ring() Cyclotomic Field of order 2520 and degree 576 @@ -34,6 +35,7 @@ sage: A(b), A(c), A(d), A(e) (1, 1, 1, 1) + sage: # needs sage.rings.real_mpfr sage: Fd = F.dual_group(names='ABCDE', base_ring=CC) sage: A,B,C,D,E = Fd.gens() sage: A(a) # abs tol 1e-8 @@ -78,6 +80,7 @@ def is_DualAbelianGroup(x): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroup sage: F = AbelianGroup(5,[3,5,7,8,9], names=list("abcde")) sage: Fd = F.dual_group() @@ -100,11 +103,12 @@ class DualAbelianGroup_class(UniqueRepresentation, AbelianGroupBase): EXAMPLES:: sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde") - sage: F.dual_group() + sage: F.dual_group() # needs sage.rings.number_field Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z over Cyclotomic Field of order 2520 and degree 576 + sage: F = AbelianGroup(4,[15,7,8,9], names="abcd") - sage: F.dual_group(base_ring=CC) + sage: F.dual_group(base_ring=CC) # needs sage.rings.real_mpfr Dual of Abelian Group isomorphic to Z/15Z x Z/7Z x Z/8Z x Z/9Z over Complex Field with 53 bits of precision """ @@ -117,7 +121,7 @@ def __init__(self, G, names, base_ring): EXAMPLES:: sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde") - sage: F.dual_group() + sage: F.dual_group() # needs sage.rings.number_field Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z over Cyclotomic Field of order 2520 and degree 576 """ @@ -174,12 +178,13 @@ def _repr_(self): EXAMPLES:: sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde') - sage: Fd = F.dual_group(names='ABCDE', base_ring=CyclotomicField(2*5*7*8*9)) - sage: Fd # indirect doctest + sage: Fd = F.dual_group(names='ABCDE', # needs sage.rings.number_field + ....: base_ring=CyclotomicField(2*5*7*8*9)) + sage: Fd # indirect doctest # needs sage.rings.number_field Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z over Cyclotomic Field of order 5040 and degree 1152 - sage: Fd = F.dual_group(names='ABCDE', base_ring=CC) - sage: Fd + sage: Fd = F.dual_group(names='ABCDE', base_ring=CC) # needs sage.rings.real_mpfr + sage: Fd # needs sage.rings.real_mpfr Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z over Complex Field with 53 bits of precision """ @@ -202,8 +207,8 @@ def _latex_(self): EXAMPLES:: sage: F = AbelianGroup(3, [2]*3) - sage: Fd = F.dual_group() - sage: Fd._latex_() + sage: Fd = F.dual_group() # needs sage.rings.number_field + sage: Fd._latex_() # needs sage.rings.number_field '$\\mathrm{DualAbelianGroup}( AbelianGroup ( 3, (2, 2, 2) ) )$' """ return r"$\mathrm{DualAbelianGroup}( AbelianGroup ( %s, %s ) )$" % (self.ngens(), self.gens_orders()) @@ -215,12 +220,13 @@ def random_element(self): EXAMPLES:: sage: G = AbelianGroup([2,3,9]) - sage: Gd = G.dual_group(base_ring=CC) - sage: Gd.random_element().parent() is Gd + sage: Gd = G.dual_group(base_ring=CC) # needs sage.rings.real_mpfr + sage: Gd.random_element().parent() is Gd # needs sage.rings.real_mpfr True - sage: N = 43^2-1 - sage: G = AbelianGroup([N],names="a") + sage: # needs sage.rings.real_mpfr + sage: N = 43^2 - 1 + sage: G = AbelianGroup([N], names="a") sage: Gd = G.dual_group(names="A", base_ring=CC) sage: a, = G.gens() sage: A, = Gd.gens() @@ -243,7 +249,8 @@ def gen(self, i=0): EXAMPLES:: - sage: F = AbelianGroup(3,[1,2,3],names='a') + sage: # needs sage.rings.number_field + sage: F = AbelianGroup(3, [1,2,3], names='a') sage: Fd = F.dual_group(names="A") sage: Fd.0 1 @@ -270,8 +277,8 @@ def gens(self): EXAMPLES:: - sage: F = AbelianGroup([7,11]).dual_group() - sage: F.gens() + sage: F = AbelianGroup([7,11]).dual_group() # needs sage.rings.number_field + sage: F.gens() # needs sage.rings.number_field (X0, X1) """ n = self.group().ngens() @@ -284,8 +291,8 @@ def ngens(self): EXAMPLES:: sage: F = AbelianGroup([7]*100) - sage: Fd = F.dual_group() - sage: Fd.ngens() + sage: Fd = F.dual_group() # needs sage.rings.number_field + sage: Fd.ngens() # needs sage.rings.number_field 100 """ return self.group().ngens() @@ -301,8 +308,8 @@ def gens_orders(self): EXAMPLES:: sage: F = AbelianGroup([5]*1000) - sage: Fd = F.dual_group() - sage: invs = Fd.gens_orders(); len(invs) + sage: Fd = F.dual_group() # needs sage.rings.number_field + sage: invs = Fd.gens_orders(); len(invs) # needs sage.rings.number_field 1000 """ return self.group().gens_orders() @@ -316,8 +323,8 @@ def invariants(self): EXAMPLES:: sage: F = AbelianGroup([5]*1000) - sage: Fd = F.dual_group() - sage: invs = Fd.gens_orders(); len(invs) + sage: Fd = F.dual_group() # needs sage.rings.number_field + sage: invs = Fd.gens_orders(); len(invs) # needs sage.rings.number_field 1000 """ # TODO: deprecate @@ -331,9 +338,9 @@ def __contains__(self, X): sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde") sage: a,b,c,d,e = F.gens() - sage: Fd = F.dual_group(names = "ABCDE") - sage: A,B,C,D,E = Fd.gens() - sage: A*B^2*D^7 in Fd + sage: Fd = F.dual_group(names="ABCDE") # needs sage.rings.number_field + sage: A,B,C,D,E = Fd.gens() # needs sage.rings.number_field + sage: A*B^2*D^7 in Fd # needs sage.rings.number_field True """ return X.parent() == self and is_DualAbelianGroupElement(X) @@ -345,8 +352,8 @@ def order(self): EXAMPLES:: sage: G = AbelianGroup([2,3,9]) - sage: Gd = G.dual_group() - sage: Gd.order() + sage: Gd = G.dual_group() # needs sage.rings.number_field + sage: Gd.order() # needs sage.rings.number_field 54 """ G = self.group() @@ -359,10 +366,10 @@ def is_commutative(self): EXAMPLES:: sage: G = AbelianGroup([2,3,9]) - sage: Gd = G.dual_group() - sage: Gd.is_commutative() + sage: Gd = G.dual_group() # needs sage.rings.number_field + sage: Gd.is_commutative() # needs sage.rings.number_field True - sage: Gd.is_abelian() + sage: Gd.is_abelian() # needs sage.rings.number_field True """ return True @@ -375,8 +382,8 @@ def list(self): EXAMPLES:: sage: G = AbelianGroup([2,3], names="ab") - sage: Gd = G.dual_group(names="AB") - sage: Gd.list() + sage: Gd = G.dual_group(names="AB") # needs sage.rings.number_field + sage: Gd.list() # needs sage.rings.number_field (1, B, B^2, A, A*B, A*B^2) """ if not self.is_finite(): @@ -391,19 +398,21 @@ def __iter__(self): EXAMPLES:: sage: G = AbelianGroup([2,3], names="ab") - sage: Gd = G.dual_group(names="AB") - sage: [X for X in Gd] + sage: Gd = G.dual_group(names="AB") # needs sage.rings.number_field + sage: [X for X in Gd] # needs sage.rings.number_field [1, B, B^2, A, A*B, A*B^2] - sage: N = 43^2-1 - sage: G = AbelianGroup([N],names="a") + + sage: # needs sage.rings.real_mpfr + sage: N = 43^2 - 1 + sage: G = AbelianGroup([N], names="a") sage: Gd = G.dual_group(names="A", base_ring=CC) sage: a, = G.gens() sage: A, = Gd.gens() sage: x = a^(N/4) sage: y = a^(N/3) sage: z = a^(N/14) - sage: len([X for X in Gd if abs(X(x)-1)>0.01 and abs(X(y)-1)>0.01 and abs(X(z)-1)>0.01]) + sage: len([X for X in Gd + ....: if abs(X(x)-1)>0.01 and abs(X(y)-1)>0.01 and abs(X(z)-1)>0.01]) 880 """ - for g in self.list(): - yield g + yield from self.list() diff --git a/src/sage/groups/abelian_gps/dual_abelian_group_element.py b/src/sage/groups/abelian_gps/dual_abelian_group_element.py index 18fac135c94..407323d4f34 100644 --- a/src/sage/groups/abelian_gps/dual_abelian_group_element.py +++ b/src/sage/groups/abelian_gps/dual_abelian_group_element.py @@ -8,13 +8,13 @@ sage: F Multiplicative Abelian group isomorphic to C2 x C3 x C5 x C7 x C8 - sage: Fd = F.dual_group(names="ABCDE") - sage: Fd + sage: Fd = F.dual_group(names="ABCDE"); Fd # needs sage.rings.number_field Dual of Abelian Group isomorphic to Z/2Z x Z/3Z x Z/5Z x Z/7Z x Z/8Z over Cyclotomic Field of order 840 and degree 192 The elements of the dual group can be evaluated on elements of the original group:: + sage: # needs sage.rings.number_field sage: a,b,c,d,e = F.gens() sage: A,B,C,D,E = Fd.gens() sage: A*B^2*D^7 @@ -52,7 +52,7 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.all import LCM +from sage.arith.functions import lcm as LCM from sage.groups.abelian_gps.element_base import AbelianGroupElementBase @@ -71,10 +71,10 @@ def is_DualAbelianGroupElement(x) -> bool: EXAMPLES:: sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroupElement - sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")).dual_group() - sage: is_DualAbelianGroupElement(F) + sage: F = AbelianGroup(5, [5,5,7,8,9], names=list("abcde")).dual_group() # needs sage.rings.number_field + sage: is_DualAbelianGroupElement(F) # needs sage.rings.number_field False - sage: is_DualAbelianGroupElement(F.an_element()) + sage: is_DualAbelianGroupElement(F.an_element()) # needs sage.rings.number_field True """ return isinstance(x, DualAbelianGroupElement) @@ -96,6 +96,7 @@ def __call__(self, g): EXAMPLES:: + sage: # needs sage.rings.number_field sage: F = AbelianGroup(5, [2,3,5,7,8], names="abcde") sage: a,b,c,d,e = F.gens() sage: Fd = F.dual_group(names="ABCDE") @@ -117,7 +118,7 @@ def __call__(self, g): sage: a, = F.gens() sage: Fd = F.dual_group(names="A", base_ring=GF(29)) sage: A, = Fd.gens() - sage: A(a) + sage: A(a) # needs sage.libs.pari 16 """ F = self.parent().base_ring() @@ -146,7 +147,8 @@ def word_problem(self, words): EXAMPLES:: - sage: G = AbelianGroup(5,[3, 5, 5, 7, 8],names="abcde") + sage: # needs sage.rings.number_field + sage: G = AbelianGroup(5,[3, 5, 5, 7, 8], names="abcde") sage: Gd = G.dual_group(names="abcde") sage: a,b,c,d,e = Gd.gens() sage: u = a^3*b*c*d^2*e^5 diff --git a/src/sage/groups/abelian_gps/element_base.py b/src/sage/groups/abelian_gps/element_base.py index c1eec7ecb1f..6a46bd7f444 100644 --- a/src/sage/groups/abelian_gps/element_base.py +++ b/src/sage/groups/abelian_gps/element_base.py @@ -20,7 +20,8 @@ from sage.structure.element import MultiplicativeGroupElement from sage.misc.cachefunc import cached_method -from sage.arith.all import GCD, LCM +from sage.arith.misc import GCD +from sage.arith.functions import lcm as LCM from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity @@ -47,9 +48,9 @@ class AbelianGroupElementBase(MultiplicativeGroupElement): EXAMPLES:: sage: F = AbelianGroup(3,[7,8,9]) - sage: Fd = F.dual_group(names="ABC") - sage: A,B,C = Fd.gens() - sage: A*B^-1 in Fd + sage: Fd = F.dual_group(names="ABC") # needs sage.rings.number_field + sage: A,B,C = Fd.gens() # needs sage.rings.number_field + sage: A*B^-1 in Fd # needs sage.rings.number_field True """ @@ -60,19 +61,29 @@ def __init__(self, parent, exponents): EXAMPLES:: sage: F = AbelianGroup(3,[7,8,9]) - sage: Fd = F.dual_group(names="ABC") - sage: A,B,C = Fd.gens() - sage: A*B^-1 in Fd + sage: Fd = F.dual_group(names="ABC") # needs sage.rings.number_field + sage: A,B,C = Fd.gens() # needs sage.rings.number_field + sage: A*B^-1 in Fd # needs sage.rings.number_field + True + + Check that :issue:`35216` is fixed:: + + sage: M = AbelianGroup([3]) + sage: M([5]) == M([2]) + True + sage: M([3]).is_trivial() True """ MultiplicativeGroupElement.__init__(self, parent) n = parent.ngens() if exponents == 1: - self._exponents = tuple( ZZ.zero() for i in range(n) ) + self._exponents = tuple(ZZ.zero() for i in range(n)) else: - self._exponents = tuple( ZZ(e) for e in exponents ) - if len(self._exponents) != n: - raise IndexError('argument length (= %s) must be %s.'%(len(exponents), n)) + if len(exponents) != n: + raise IndexError('argument length (= %s) must be %s' + % (len(exponents), n)) + self._exponents = tuple(ZZ(e % o if o else e) for e, o in + zip(exponents, parent.gens_orders())) def __hash__(self): r""" @@ -114,7 +125,7 @@ def _libgap_(self): TESTS:: sage: F.<a,b,c> = AbelianGroup([7,8,9]) - sage: libgap(a**2 * c) * libgap(b * c**2) + sage: libgap(a**2 * c) * libgap(b * c**2) # needs sage.libs.gap f1^2*f2*f6 """ from sage.misc.misc_c import prod @@ -136,6 +147,7 @@ def list(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde") sage: a,b,c,d,e = F.gens() sage: Ad = F.dual_group(names="ABCDE") @@ -197,8 +209,8 @@ def _richcmp_(self, other, op): sage: a > b True - sage: Gd.<A,B> = G.dual_group() - sage: A > B + sage: Gd.<A,B> = G.dual_group() # needs sage.rings.number_field + sage: A > B # needs sage.rings.number_field True """ return richcmp(self._exponents, other._exponents, op) @@ -215,9 +227,9 @@ def order(self): EXAMPLES:: sage: F = AbelianGroup(3,[7,8,9]) - sage: Fd = F.dual_group() - sage: A,B,C = Fd.gens() - sage: (B*C).order() + sage: Fd = F.dual_group() # needs sage.rings.number_field + sage: A,B,C = Fd.gens() # needs sage.rings.number_field + sage: (B*C).order() # needs sage.rings.number_field 72 sage: F = AbelianGroup(3,[7,8,9]); F @@ -256,9 +268,8 @@ def _div_(left, right): """ G = left.parent() assert G is right.parent() - exponents = [ (x-y)%order if order!=0 else x-y - for x, y, order in - zip(left._exponents, right._exponents, G.gens_orders()) ] + exponents = [x - y for x, y in + zip(left._exponents, right._exponents)] return G.element_class(G, exponents) def _mul_(left, right): @@ -275,9 +286,8 @@ def _mul_(left, right): """ G = left.parent() assert G is right.parent() - exponents = [ (x+y)%order if order!=0 else x+y - for x, y, order in - zip(left._exponents, right._exponents, G.gens_orders()) ] + exponents = [x + y for x, y in + zip(left._exponents, right._exponents)] return G.element_class(G, exponents) def __pow__(self, n): @@ -294,8 +304,7 @@ def __pow__(self, n): if n != m: raise TypeError('argument n (= '+str(n)+') must be an integer.') G = self.parent() - exponents = [ (m*e) % order if order!=0 else m*e - for e,order in zip(self._exponents, G.gens_orders()) ] + exponents = [m * e for e in self._exponents] return G.element_class(G, exponents) def __invert__(self): @@ -319,8 +328,7 @@ def __invert__(self): (-1, 4) """ G = self.parent() - exponents = [(-e) % order if order != 0 else -e - for e, order in zip(self._exponents, G.gens_orders())] + exponents = [-e for e in self._exponents] return G.element_class(G, exponents) def is_trivial(self): diff --git a/src/sage/groups/abelian_gps/values.py b/src/sage/groups/abelian_gps/values.py index e476176cb7d..3db117123f0 100644 --- a/src/sage/groups/abelian_gps/values.py +++ b/src/sage/groups/abelian_gps/values.py @@ -48,6 +48,7 @@ :meth:`~AbelianGroupWithValues_class.values_group`, so you can use the group elements instead of the values:: + sage: # needs sage.rings.number_field sage: CF3.<zeta> = CyclotomicField(3) sage: Z3.<g> = AbelianGroupWithValues([zeta], [3]) sage: Z3.values_group() @@ -159,6 +160,7 @@ class AbelianGroupWithValuesEmbedding(Morphism): EXAMPLES:: + sage: # needs sage.symbolic sage: Z4.<g> = AbelianGroupWithValues([I], [4]) sage: embedding = Z4.values_embedding(); embedding Generic morphism: @@ -178,9 +180,9 @@ def __init__(self, domain, codomain): TESTS:: - sage: Z4 = AbelianGroupWithValues([I], [4]) + sage: Z4 = AbelianGroupWithValues([I], [4]) # needs sage.symbolic sage: from sage.groups.abelian_gps.values import AbelianGroupWithValuesEmbedding - sage: AbelianGroupWithValuesEmbedding(Z4, Z4.values_group()) + sage: AbelianGroupWithValuesEmbedding(Z4, Z4.values_group()) # needs sage.symbolic Generic morphism: From: Multiplicative Abelian group isomorphic to C4 To: Number Field in I with defining polynomial x^2 + 1 with I = 1*I @@ -203,6 +205,7 @@ def _call_(self, x): EXAMPLES:: + sage: # needs sage.symbolic sage: Z4.<g> = AbelianGroupWithValues([I], [4]) sage: embedding = Z4.values_embedding() sage: embedding(g) @@ -417,7 +420,7 @@ def gen(self, i=0): EXAMPLES:: - sage: F = AbelianGroupWithValues([1,2,3,4,5], 5,[],names='a') + sage: F = AbelianGroupWithValues([1,2,3,4,5], 5, [], names='a') sage: F.0 a0 sage: F.0.value() @@ -473,8 +476,8 @@ def values_group(self): sage: G.values_group() Integer Ring - sage: Z4 = AbelianGroupWithValues([I], [4]) - sage: Z4.values_group() + sage: Z4 = AbelianGroupWithValues([I], [4]) # needs sage.symbolic + sage: Z4.values_group() # needs sage.symbolic Number Field in I with defining polynomial x^2 + 1 with I = 1*I """ return self._values_group @@ -489,8 +492,8 @@ def values_embedding(self): EXAMPLES:: - sage: Z4 = AbelianGroupWithValues([I], [4]) - sage: Z4.values_embedding() + sage: Z4 = AbelianGroupWithValues([I], [4]) # needs sage.symbolic + sage: Z4.values_embedding() # needs sage.symbolic Generic morphism: From: Multiplicative Abelian group isomorphic to C4 To: Number Field in I with defining polynomial x^2 + 1 with I = 1*I diff --git a/src/sage/groups/additive_abelian/__init__.py b/src/sage/groups/additive_abelian/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/groups/additive_abelian/additive_abelian_group.py b/src/sage/groups/additive_abelian/additive_abelian_group.py index 49f0dc97a4b..358302ffd13 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_group.py +++ b/src/sage/groups/additive_abelian/additive_abelian_group.py @@ -143,7 +143,6 @@ def cover_and_relations_from_invariants(invs): return (A, B) - class AdditiveAbelianGroupElement(FGP_Element): """ An element of an :class:`AdditiveAbelianGroup_class`. @@ -354,7 +353,7 @@ def exponent(self): if not self.invariants(): return ZZ(1) else: - ann = self.annihilator().gen() + ann = self.annihilator().gen() if ann: return ann return ZZ(0) @@ -451,7 +450,7 @@ def permutation_group(self): EXAMPLES:: sage: G = AdditiveAbelianGroup([2, 3]) - sage: G.permutation_group() + sage: G.permutation_group() # needs sage.groups Permutation Group with generators [(3,4,5), (1,2)] TESTS: diff --git a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py index 720d99844a0..2a7496cb215 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py +++ b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py @@ -11,10 +11,10 @@ We create a toy example based on the Mordell-Weil group of an elliptic curve over `\QQ`:: + sage: # needs sage.schemes sage: E = EllipticCurve('30a2') sage: pts = [E(4,-7,1), E(7/4, -11/8, 1), E(3, -2, 1)] - sage: M = AdditiveAbelianGroupWrapper(pts[0].parent(), pts, [3, 2, 2]) - sage: M + sage: M = AdditiveAbelianGroupWrapper(pts[0].parent(), pts, [3, 2, 2]); M Additive abelian group isomorphic to Z/3 + Z/2 + Z/2 embedded in Abelian group of points on Elliptic Curve defined by y^2 + x*y + y = x^3 - 19*x + 26 over Rational Field @@ -24,7 +24,7 @@ (0 : 1 : 0) sage: 3000000000000001 * M.0 (4 : -7 : 1) - sage: M == loads(dumps(M)) # known bug, see https://github.com/sagemath/sage/issues/11599#comment:7 + sage: M == loads(dumps(M)) # known bug (https://github.com/sagemath/sage/issues/11599#comment:7) True TESTS: @@ -33,7 +33,7 @@ sage: from sage.misc.verbose import set_verbose sage: set_verbose(2, 'additive_abelian_wrapper.py') - sage: 300001 * M.0 + sage: 300001 * M.0 # needs sage.schemes verbose 1 (...: additive_abelian_wrapper.py, discrete_exp) Calling discrete exp on (1, 0, 0) (4 : -7 : 1) sage: set_verbose(0, 'additive_abelian_wrapper.py') @@ -50,6 +50,7 @@ - David Loeffler (2010) - Lorenz Panny (2017): :meth:`AdditiveAbelianGroupWrapper.discrete_log` +- Lorenz Panny (2023): :meth:`AdditiveAbelianGroupWrapper.from_generators` """ # **************************************************************************** @@ -71,6 +72,7 @@ from sage.rings.integer_ring import ZZ from sage.categories.morphism import Morphism from sage.structure.element import parent +from sage.structure.sequence import Sequence from sage.modules.free_module_element import vector from sage.misc.superseded import deprecated_function_alias @@ -83,12 +85,13 @@ def __init__(self, domain): r""" EXAMPLES:: - sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) - sage: F = QQbar.coerce_map_from(G); F + sage: G = AdditiveAbelianGroupWrapper(QQbar, # needs sage.rings.number_field + ....: [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) + sage: F = QQbar.coerce_map_from(G); F # needs sage.rings.number_field Generic morphism: From: Additive abelian group isomorphic to Z + Z embedded in Algebraic Field To: Algebraic Field - sage: type(F) + sage: type(F) # needs sage.rings.number_field <class 'sage.groups.additive_abelian.additive_abelian_wrapper.UnwrappingMorphism'> """ Morphism.__init__(self, domain.Hom(domain.universe())) @@ -97,13 +100,14 @@ def _call_(self, x): r""" TESTS:: + sage: # needs sage.schemes sage: E = EllipticCurve("65a1") sage: G = E.torsion_subgroup() sage: isinstance(G, sage.groups.additive_abelian.additive_abelian_wrapper.AdditiveAbelianGroupWrapper) True sage: P1 = E([1,-1,1]) sage: P2 = E([0,1,0]) - sage: P1 in G # indirect doctest + sage: P1 in G # indirect doctest False sage: P2 in G True @@ -125,8 +129,9 @@ def __init__(self, parent, vector, element=None, check=False): EXAMPLES:: sage: from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper - sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) - sage: G.0 # indirect doctest + sage: G = AdditiveAbelianGroupWrapper(QQbar, # needs sage.rings.number_field + ....: [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) + sage: G.0 # indirect doctest # needs sage.rings.number_field 1.414213562373095? """ addgp.AdditiveAbelianGroupElement.__init__(self, parent, vector, check) @@ -140,11 +145,11 @@ def element(self): EXAMPLES:: - sage: T = EllipticCurve('65a').torsion_subgroup().gen(0) - sage: T; type(T) + sage: T = EllipticCurve('65a').torsion_subgroup().gen(0) # needs sage.schemes + sage: T; type(T) # needs sage.schemes (0 : 0 : 1) <class 'sage.schemes.elliptic_curves.ell_torsion.EllipticCurveTorsionSubgroup_with_category.element_class'> - sage: T.element(); type(T.element()) + sage: T.element(); type(T.element()) # needs sage.schemes (0 : 0 : 1) <class 'sage.schemes.elliptic_curves.ell_point.EllipticCurvePoint_number_field'> """ @@ -158,8 +163,8 @@ def _repr_(self): EXAMPLES:: - sage: T = EllipticCurve('65a').torsion_subgroup().gen(0) - sage: repr(T) # indirect doctest + sage: T = EllipticCurve('65a').torsion_subgroup().gen(0) # needs sage.schemes + sage: repr(T) # indirect doctest # needs sage.schemes '(0 : 0 : 1)' """ return repr(self.element()) @@ -177,19 +182,22 @@ class AdditiveAbelianGroupWrapper(addgp.AdditiveAbelianGroup_fixed_gens): sage: G6 = AdditiveAbelianGroupWrapper(Zmod(42), [6], [7]); G6 Additive abelian group isomorphic to Z/7 embedded in Ring of integers modulo 42 sage: G = AdditiveAbelianGroupWrapper(Zmod(42), [21,14,6], [2,3,7]); G - Additive abelian group isomorphic to Z/2 + Z/3 + Z/7 embedded in Ring of integers modulo 42 + Additive abelian group isomorphic to Z/2 + Z/3 + Z/7 embedded in + Ring of integers modulo 42 sage: G.invariants() (42,) :: - sage: AdditiveAbelianGroupWrapper(QQbar, [sqrt(2), sqrt(3)], [0, 0]) + sage: AdditiveAbelianGroupWrapper(QQbar, [sqrt(2), sqrt(3)], [0, 0]) # needs sage.rings.number_field sage.symbolic Additive abelian group isomorphic to Z + Z embedded in Algebraic Field :: - sage: EllipticCurve(GF(419**2), [1,0]).abelian_group() # indirect doctest - Additive abelian group isomorphic to Z/420 + Z/420 embedded in Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 419^2 + sage: EllipticCurve(GF(419**2), [1,0]).abelian_group() # indirect doctest # needs sage.rings.finite_rings sage.schemes + Additive abelian group isomorphic to Z/420 + Z/420 embedded in + Abelian group of points on Elliptic Curve + defined by y^2 = x^3 + x over Finite Field in z2 of size 419^2 """ Element = AdditiveAbelianGroupWrapperElement @@ -198,7 +206,8 @@ def __init__(self, universe, gens, invariants): r""" EXAMPLES:: - sage: AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) # indirect doctest + sage: AdditiveAbelianGroupWrapper(QQbar, # indirect doctest # needs sage.rings.number_field + ....: [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) Additive abelian group isomorphic to Z + Z embedded in Algebraic Field """ self._universe = universe @@ -215,8 +224,10 @@ def universe(self): EXAMPLES:: - sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) - sage: G.universe() + sage: G = AdditiveAbelianGroupWrapper(QQbar, # needs sage.rings.number_field + ....: [sqrt(QQbar(2)), sqrt(QQbar(3))], + ....: [0, 0]) + sage: G.universe() # needs sage.rings.number_field Algebraic Field """ return self._universe @@ -244,12 +255,36 @@ def _repr_(self): r""" EXAMPLES:: - sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) - sage: repr(G) # indirect doctest + sage: G = AdditiveAbelianGroupWrapper(QQbar, # needs sage.rings.number_field + ....: [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) + sage: repr(G) # indirect doctest # needs sage.rings.number_field 'Additive abelian group isomorphic to Z + Z embedded in Algebraic Field' """ return addgp.AdditiveAbelianGroup_fixed_gens._repr_(self) + " embedded in " + self.universe()._repr_() + def _element_constructor_(self, x, check=False): + r""" + Create an element from ``x``. + + This may be either an element of self, an element of the ambient + group, or an iterable (in which case the result is the corresponding + product of the generators of self). + + EXAMPLES:: + + sage: V = Zmod(8)**2 + sage: G = AdditiveAbelianGroupWrapper(V, [[2,2],[4,0]], [4, 2]) + sage: G(V([6,2])) + (6, 2) + sage: G([1,1]) + (6, 2) + sage: G(G([1,1])) + (6, 2) + """ + if parent(x) is self.universe(): + return self.element_class(self, self.discrete_log(x), element=x) + return addgp.AdditiveAbelianGroup_fixed_gens._element_constructor_(self, x, check) + def discrete_exp(self, v): r""" Given a list (or other iterable) of length equal to the number of @@ -258,10 +293,11 @@ def discrete_exp(self, v): EXAMPLES:: - sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), -1], [0, 0]) - sage: v = G.discrete_exp([3, 5]); v + sage: G = AdditiveAbelianGroupWrapper(QQbar, # needs sage.rings.number_field + ....: [sqrt(QQbar(2)), -1], [0, 0]) + sage: v = G.discrete_exp([3, 5]); v # needs sage.rings.number_field -0.7573593128807148? - sage: v.parent() is QQbar + sage: v.parent() is QQbar # needs sage.rings.number_field True This method is an inverse of :meth:`discrete_log`:: @@ -307,15 +343,17 @@ def discrete_log(self, x, gens=None): EXAMPLES:: sage: G = AdditiveAbelianGroup([2, 2*3, 2*3*5, 2*3*5*7, 2*3*5*7*11]) - sage: A = AdditiveAbelianGroupWrapper(G.0.parent(), G.gens(), [g.order() for g in G.gens()]) + sage: A = AdditiveAbelianGroupWrapper(G.0.parent(), G.gens(), + ....: [g.order() for g in G.gens()]) sage: A.discrete_log(A.discrete_exp([1,5,23,127,539])) (1, 5, 23, 127, 539) :: - sage: F.<t> = GF(1009**2, modulus=x**2+11); E = EllipticCurve(j=F(940)) - sage: P, Q = E(900*t + 228, 974*t + 185), E(1007*t + 214, 865*t + 802) - sage: E.abelian_group().discrete_log(123 * P + 777 * Q, [P, Q]) + sage: x = polygen(ZZ, 'x') + sage: F.<t> = GF(1009**2, modulus=x**2+11); E = EllipticCurve(j=F(940)) # needs sage.rings.finite_rings sage.schemes + sage: P, Q = E(900*t + 228, 974*t + 185), E(1007*t + 214, 865*t + 802) # needs sage.rings.finite_rings sage.schemes + sage: E.abelian_group().discrete_log(123 * P + 777 * Q, [P, Q]) # needs sage.rings.finite_rings sage.schemes (123, 777) :: @@ -331,8 +369,8 @@ def discrete_log(self, x, gens=None): :: - sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(2)], [0]) - sage: G.discrete_log(QQbar(2*sqrt(2))) + sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(2)], [0]) # needs sage.rings.number_field sage.symbolic + sage: G.discrete_log(QQbar(2*sqrt(2))) # needs sage.rings.number_field sage.symbolic Traceback (most recent call last): ... NotImplementedError: No black-box discrete log for infinite abelian groups @@ -400,33 +438,43 @@ def torsion_subgroup(self, n=None): sage: A = AdditiveAbelianGroupWrapper(G.0.parent(), G.gens(), ords) sage: T = A.torsion_subgroup(5) sage: T - Additive abelian group isomorphic to Z/5 + Z/5 + Z/5 embedded in Additive abelian group isomorphic to Z/2 + Z/6 + Z/30 + Z + Z/210 + Z/2310 + Additive abelian group isomorphic to Z/5 + Z/5 + Z/5 embedded in + Additive abelian group isomorphic to Z/2 + Z/6 + Z/30 + Z + Z/210 + Z/2310 sage: T.gens() ((0, 0, 6, 0, 0, 0), (0, 0, 0, 0, 42, 0), (0, 0, 0, 0, 0, 462)) :: + sage: # needs sage.rings.finite_rings sage.schemes sage: E = EllipticCurve(GF(487^2), [311,205]) - sage: T = E.abelian_group().torsion_subgroup(42) - sage: T - Additive abelian group isomorphic to Z/42 + Z/6 embedded in Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 311*x + 205 over Finite Field in z2 of size 487^2 + sage: T = E.abelian_group().torsion_subgroup(42); T + Additive abelian group isomorphic to Z/42 + Z/6 embedded in + Abelian group of points on Elliptic Curve + defined by y^2 = x^3 + 311*x + 205 over Finite Field in z2 of size 487^2 sage: [P.order() for P in T.gens()] [42, 6] :: + sage: # needs sage.schemes sage: E = EllipticCurve('574i1') sage: pts = [E(103,172), E(61,18)] sage: assert pts[0].order() == 7 and pts[1].order() == infinity - sage: M = AdditiveAbelianGroupWrapper(pts[0].parent(), pts, [7,0]) - sage: M - Additive abelian group isomorphic to Z/7 + Z embedded in Abelian group of points on Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 19353*x + 958713 over Rational Field + sage: M = AdditiveAbelianGroupWrapper(pts[0].parent(), pts, [7,0]); M + Additive abelian group isomorphic to Z/7 + Z embedded in + Abelian group of points on Elliptic Curve defined by + y^2 + x*y + y = x^3 - x^2 - 19353*x + 958713 over Rational Field sage: M.torsion_subgroup() - Additive abelian group isomorphic to Z/7 embedded in Abelian group of points on Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 19353*x + 958713 over Rational Field + Additive abelian group isomorphic to Z/7 embedded in + Abelian group of points on Elliptic Curve defined by + y^2 + x*y + y = x^3 - x^2 - 19353*x + 958713 over Rational Field sage: M.torsion_subgroup(7) - Additive abelian group isomorphic to Z/7 embedded in Abelian group of points on Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 19353*x + 958713 over Rational Field + Additive abelian group isomorphic to Z/7 embedded in + Abelian group of points on Elliptic Curve defined by + y^2 + x*y + y = x^3 - x^2 - 19353*x + 958713 over Rational Field sage: M.torsion_subgroup(5) - Trivial group embedded in Abelian group of points on Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 19353*x + 958713 over Rational Field + Trivial group embedded in Abelian group of points on Elliptic Curve + defined by y^2 + x*y + y = x^3 - x^2 - 19353*x + 958713 over Rational Field AUTHORS: @@ -450,26 +498,54 @@ def torsion_subgroup(self, n=None): ords.append(d) return AdditiveAbelianGroupWrapper(self.universe(), gens, ords) - def _element_constructor_(self, x, check=False): + @staticmethod + def from_generators(gens, universe=None): r""" - Create an element from x. This may be either an element of self, an element of the - ambient group, or an iterable (in which case the result is the corresponding - product of the generators of self). + This method constructs the subgroup generated by a sequence + of *finite-order* elements in an additive abelian group. + + The elements need not be independent, hence this can be used + to perform tasks such as finding relations between some given + elements of an abelian group, computing the structure of the + generated subgroup, enumerating all elements of the subgroup, + and solving discrete-logarithm problems. EXAMPLES:: - sage: V = Zmod(8)**2 - sage: G = AdditiveAbelianGroupWrapper(V, [[2,2],[4,0]], [4, 2]) - sage: G(V([6,2])) - (6, 2) - sage: G([1,1]) - (6, 2) - sage: G(G([1,1])) - (6, 2) + sage: G = AdditiveAbelianGroup([15, 30, 45]) + sage: gs = [G((1,2,3)), G((4,5,6)), G((7,7,7)), G((3,2,1))] + sage: H = AdditiveAbelianGroupWrapper.from_generators(gs); H + Additive abelian group isomorphic to Z/90 + Z/15 embedded in + Additive abelian group isomorphic to Z/15 + Z/30 + Z/45 + sage: H.gens() + ((12, 13, 14), (1, 26, 21)) + + TESTS: + + Random testing:: + + sage: invs = [] + sage: while not 1 < prod(invs) < 10^4: + ....: invs = [randrange(1,100) for _ in range(randrange(1,20))] + sage: G = AdditiveAbelianGroup(invs) + sage: gs = [G.random_element() for _ in range(randrange(1,10))] + sage: H = AdditiveAbelianGroupWrapper.from_generators(gs) + sage: os = H.generator_orders() + sage: vecs = cartesian_product_iterator(list(map(range, os))) + sage: els = {sum(i*g for i,g in zip(vec, H.gens())) for vec in vecs} + sage: len(els) == prod(os) + True """ - if parent(x) is self.universe(): - return self.element_class(self, self.discrete_log(x), element=x) - return addgp.AdditiveAbelianGroup_fixed_gens._element_constructor_(self, x, check) + if not gens: + if universe is None: + raise ValueError('need universe if no generators are given') + return AdditiveAbelianGroupWrapper(universe, [], []) + + if universe is None: + universe = Sequence(gens).universe() + + basis, ords = basis_from_generators(gens) + return AdditiveAbelianGroupWrapper(universe, basis, ords) def _discrete_log_pgroup(p, vals, aa, b): @@ -499,12 +575,13 @@ def _discrete_log_pgroup(p, vals, aa, b): Check for :trac:`34716`:: + sage: # needs sage.rings.finite_rings sage.schemes sage: E = EllipticCurve(GF(487^2), [311,205]) sage: G = E.abelian_group().torsion_subgroup(42) sage: G.invariants() (6, 42) sage: P, Q = G.torsion_subgroup(6).gens() - sage: G.discrete_log(2*P + 3*Q, [P, Q]) # indirect doctest + sage: G.discrete_log(2*P + 3*Q, [P, Q]) # indirect doctest # needs sage.groups (2, 3) """ from itertools import product as iproduct @@ -566,3 +643,210 @@ def _rec(j, k, c): return x return _rec(0, max(vals), b) + + +def _expand_basis_pgroup(p, alphas, vals, beta, h, rel): + r""" + Given a basis of a `p`-subgroup of a finite abelian group + and an element lying outside the subgroup, extend the basis + to the subgroup spanned jointly by the original subgroup and + the new element. + + Used as a subroutine in :func:`basis_from_generators`. + + This function modifies ``alphas`` and ``vals`` in place. + + ALGORITHM: [Suth2007]_, Algorithm 9.2 + + INPUT: + + - ``p`` -- prime integer `p` + - ``alphas`` -- list; basis for a `p`-subgroup of an abelian group + - ``vals`` -- list; valuation at `p` of the orders of the ``alphas`` + - ``beta`` -- element of the same abelian group as the ``alphas`` + - ``h`` -- integer; valuation at `p` of the order of ``beta`` + - ``rel`` -- list of integers; relation on ``alphas + [beta]`` + + OUTPUT: basis of the subgroup generated by ``alphas + [beta]`` + + EXAMPLES:: + + sage: from sage.groups.additive_abelian.additive_abelian_wrapper import _expand_basis_pgroup + sage: A = AdditiveAbelianGroup([9,3]) + sage: alphas = [A((5,2))] + sage: beta = A((1,0)) + sage: vals = [2] + sage: rel = next([ZZ(r),ZZ(s)] for s in range(9) for r in range(9) if s > 1 and not r*alphas[0] + s*beta) + sage: _expand_basis_pgroup(3, alphas, vals, beta, 2, rel) + sage: alphas + [(5, 2), (6, 2)] + sage: vals + [2, 1] + sage: len({i*alphas[0] + j*alphas[1] for i in range(3^2) for j in range(3^1)}) + 27 + """ + # The given assertions should hold, but were commented out for speed. + + k = len(rel) + if not (isinstance(alphas, list) and isinstance(vals, list)): + raise TypeError('alphas and vals must be lists for mutability') + if not len(alphas) == len(vals) == k - 1: + raise ValueError(f'alphas and/or vals have incorrect length') +# assert not sum(r*a for r,a in zip(rel, alphas+[beta])) +# assert all(a.order() == p**v for a,v in zip(alphas,vals)) + + if rel[-1] < 0: + raise ValueError('rel must have nonnegative entries') + + # step 1 + min_r = rel[-1] or float('inf') + for i in range(k-1): + if not rel[i]: + continue + if rel[i] < 0: + raise ValueError('rel must have nonnegative entries') + q = rel[i].p_primary_part(p) + alphas[i] *= rel[i] // q + rel[i] = q + if q < min_r: + min_r = q + if min_r == float('inf'): + raise ValueError('rel must have at least one nonzero entry') + val_rlast = rel[-1].valuation(p) +# assert rel[-1] == p ** val_rlast +# assert not sum(r*a for r,a in zip(rel, alphas+[beta])) + + # step 2 + if rel[-1] == min_r: + for i in range(k-1): + beta += alphas[i] * (rel[i]//rel[-1]) + alphas.append(beta) + vals.append(val_rlast) +# assert alphas[-1].order() == p**vals[-1] + return + + # step 3 + j = next(j for j,r in enumerate(rel) if r == min_r) + alphas[j] = sum(a * (r//rel[j]) for a,r in zip(alphas+[beta], rel)) + + # step 4 + if not alphas[j]: + del alphas[j], vals[j] + if not alphas: + alphas.append(beta) + vals.append(val_rlast) +# assert alphas[-1].order() == p**vals[-1] + return + + # step 5 + beta_q = beta + for v in range(1, h): + beta_q *= p + try: + e = _discrete_log_pgroup(p, vals, alphas, -beta_q) + except TypeError: + continue + # step 6 + _expand_basis_pgroup(p, alphas, vals, beta, h, list(e) + [p**v]) + break + else: + alphas.append(beta) + vals.append(h) +# assert alphas[-1].order() == p**vals[-1] + +def basis_from_generators(gens, ords=None): + r""" + Given a generating set of some finite abelian group + (additively written), compute and return a basis of + the group. + + .. NOTE:: + + A *basis* of a finite abelian group is a generating + set `\{g_1, \ldots, g_n\}` such that each element of the + group can be written as a unique linear combination + `\alpha_1 g_1 + \cdots + \alpha_n g_n` with each + `\alpha_i \in \{0, \ldots, \mathrm{ord}(g_i)-1\}`. + + ALGORITHM: [Suth2007]_, Algorithm 9.1 & Remark 9.1 + + EXAMPLES:: + + sage: # needs sage.groups sage.rings.finite_rings + sage: from sage.groups.additive_abelian.additive_abelian_wrapper import basis_from_generators + sage: E = EllipticCurve(GF(31337^6,'a'), j=37) + sage: E.order() + 946988065073788930380545280 + sage: (R,S), (ordR,ordS) = basis_from_generators(E.gens()) + sage: ordR, ordS + (313157428926517503432720, 3024) + sage: R.order() == ordR + True + sage: S.order() == ordS + True + sage: ordR * ordS == E.order() + True + sage: R.weil_pairing(S, ordR).multiplicative_order() == ordS + True + sage: E.abelian_group().invariants() + (3024, 313157428926517503432720) + """ + if not gens: + return [], [] + if ords is None: + ords = [g.order() for g in gens] + + from sage.arith.functions import lcm + lam = lcm(ords) + ps = sorted(lam.prime_factors(), key=lam.valuation) + + gammas = [] + ms = [] + for p in ps: + pgens = [(o.prime_to_m_part(p) * g, o.p_primary_part(p)) for g, o in zip(gens, ords) if not o % p] + assert pgens + pgens.sort(key=lambda tup: tup[1]) + + alpha, ord_alpha = pgens.pop() + vals = [ord_alpha.valuation(p)] + alphas = [alpha] + + while pgens: + beta, ord_beta = pgens.pop() + try: + dlog = _discrete_log_pgroup(p, vals, alphas, beta) + except TypeError: + pass + else: + continue + + # step 4 + val_beta = ord_beta.valuation(p) + beta_q = beta + for v in range(1, val_beta): + beta_q *= p +# assert beta_q == beta * p**v + try: + e = _discrete_log_pgroup(p, vals, alphas, -beta_q) + except TypeError: + continue + _expand_basis_pgroup(p, alphas, vals, beta, val_beta, list(e) + [p**v]) +# assert all(a.order() == p**v for a,v in zip(alphas, vals)) + break + else: + alphas.append(beta) + vals.append(val_beta) + + for i, (v, a) in enumerate(sorted(zip(vals, alphas), reverse=True)): + if i < len(gammas): + gammas[i] += a + ms[i] *= p ** v + else: + gammas.append(a) + ms.append(p ** v) + +## assert len({sum(i*g for i,g in zip(vec,gammas)) +## for vec in __import__('itertools').product(*map(range,ms))}) \ +## == __import__('sage').misc.misc_c.prod(ms) + + return gammas, ms diff --git a/src/sage/groups/affine_gps/__init__.py b/src/sage/groups/affine_gps/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/groups/affine_gps/affine_group.py b/src/sage/groups/affine_gps/affine_group.py index cef1788deea..bfcdd282df1 100644 --- a/src/sage/groups/affine_gps/affine_group.py +++ b/src/sage/groups/affine_gps/affine_group.py @@ -21,8 +21,8 @@ from sage.categories.groups import Groups from sage.groups.matrix_gps.linear import GL from sage.categories.rings import Rings -from sage.matrix.all import MatrixSpace -from sage.modules.all import FreeModule +from sage.matrix.matrix_space import MatrixSpace +from sage.modules.free_module import FreeModule from sage.structure.unique_representation import UniqueRepresentation from sage.misc.cachefunc import cached_method @@ -129,11 +129,11 @@ class AffineGroup(UniqueRepresentation, Group): Some additional ways to create affine groups:: - sage: A = AffineSpace(2, GF(4,'a')); A + sage: A = AffineSpace(2, GF(4,'a')); A # needs sage.rings.finite_rings Affine Space of dimension 2 over Finite Field in a of size 2^2 - sage: G = AffineGroup(A); G + sage: G = AffineGroup(A); G # needs sage.rings.finite_rings Affine Group of degree 2 over Finite Field in a of size 2^2 - sage: G is AffineGroup(2,4) # shorthand + sage: G is AffineGroup(2,4) # shorthand # needs sage.rings.finite_rings True sage: V = ZZ^3; V @@ -152,10 +152,10 @@ def __classcall__(cls, *args, **kwds): EXAMPLES:: - sage: A = AffineSpace(2, GF(4,'a')) - sage: AffineGroup(A) is AffineGroup(2,4) + sage: A = AffineSpace(2, GF(4,'a')) # needs sage.rings.finite_rings + sage: AffineGroup(A) is AffineGroup(2,4) # needs sage.rings.finite_rings True - sage: AffineGroup(A) is AffineGroup(2, GF(4,'a')) + sage: AffineGroup(A) is AffineGroup(2, GF(4,'a')) # needs sage.rings.finite_rings True sage: A = AffineGroup(2, QQ) sage: V = QQ^2 @@ -301,9 +301,7 @@ def degree(self): """ Return the dimension of the affine space. - OUTPUT: - - An integer. + OUTPUT: An integer. EXAMPLES:: @@ -388,9 +386,7 @@ def linear(self, A): - ``A`` -- anything that determines a matrix - OUTPUT: - - The affine group element `x \mapsto A x`. + OUTPUT: The affine group element `x \mapsto A x`. EXAMPLES:: @@ -411,9 +407,7 @@ def translation(self, b): - ``b`` -- anything that determines a vector - OUTPUT: - - The affine group element `x \mapsto x + b`. + OUTPUT: The affine group element `x \mapsto x + b`. EXAMPLES:: diff --git a/src/sage/combinat/cluster_algebra_quiver/__init__.py b/src/sage/groups/affine_gps/all.py similarity index 100% rename from src/sage/combinat/cluster_algebra_quiver/__init__.py rename to src/sage/groups/affine_gps/all.py diff --git a/src/sage/groups/affine_gps/euclidean_group.py b/src/sage/groups/affine_gps/euclidean_group.py index 969dbfe1f81..07349c40292 100644 --- a/src/sage/groups/affine_gps/euclidean_group.py +++ b/src/sage/groups/affine_gps/euclidean_group.py @@ -21,7 +21,7 @@ class EuclideanGroup(AffineGroup): r""" - an Euclidean group. + A Euclidean group. The Euclidean group `E(A)` (or general affine group) of an affine space `A` is the group of all invertible affine transformations from @@ -121,11 +121,11 @@ class EuclideanGroup(AffineGroup): Some additional ways to create Euclidean groups:: - sage: A = AffineSpace(2, GF(4,'a')); A + sage: A = AffineSpace(2, GF(4,'a')); A # needs sage.rings.finite_rings Affine Space of dimension 2 over Finite Field in a of size 2^2 - sage: G = EuclideanGroup(A); G + sage: G = EuclideanGroup(A); G # needs sage.rings.finite_rings Euclidean Group of degree 2 over Finite Field in a of size 2^2 - sage: G is EuclideanGroup(2,4) # shorthand + sage: G is EuclideanGroup(2,4) # shorthand # needs sage.rings.finite_rings True sage: V = ZZ^3; V diff --git a/src/sage/groups/affine_gps/group_element.py b/src/sage/groups/affine_gps/group_element.py index cb5fd945239..74d8b684bbb 100644 --- a/src/sage/groups/affine_gps/group_element.py +++ b/src/sage/groups/affine_gps/group_element.py @@ -67,16 +67,14 @@ class AffineGroupElement(MultiplicativeGroupElement): correct vector space. - ``check`` - bool (default: ``True``). Whether to do some - checks or just accept the input as valid. + checks or just accept the input as valid. As a special case, ``A`` can be a matrix obtained from :meth:`matrix`, that is, one row and one column larger. In that case, the group element defining that matrix is reconstructed. - OUTPUT: - - The affine group element `x \mapsto Ax + b` + OUTPUT: The affine group element `x \mapsto Ax + b` EXAMPLES:: @@ -144,9 +142,7 @@ def A(self): """ Return the general linear part of an affine group element. - OUTPUT: - - The matrix `A` of the affine group element `Ax + b`. + OUTPUT: The matrix `A` of the affine group element `Ax + b`. EXAMPLES:: @@ -163,9 +159,7 @@ def b(self): """ Return the translation part of an affine group element. - OUTPUT: - - The vector `b` of the affine group element `Ax + b`. + OUTPUT: The vector `b` of the affine group element `Ax + b`. EXAMPLES:: @@ -361,9 +355,7 @@ def __call__(self, v): - ``v`` -- a polynomial, a multivariate polynomial, a polyhedron, a vector, or anything that can be converted into a vector. - OUTPUT: - - The image of ``v`` under the affine group element. + OUTPUT: The image of ``v`` under the affine group element. EXAMPLES:: @@ -403,8 +395,8 @@ def __call__(self, v): sage: M = matrix(3, [-1, -2, 0, 0, 0, 1, -2, 1, -1]) sage: v = vector(QQ,(1,2,3)) sage: f = F(M, v) - sage: cube = polytopes.cube() - sage: f(cube) + sage: cube = polytopes.cube() # needs sage.geometry.polyhedron + sage: f(cube) # needs sage.geometry.polyhedron A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 8 vertices """ @@ -414,13 +406,13 @@ def __call__(self, v): if v in parent.vector_space(): return self._A*v + self._b - from sage.rings.polynomial.polynomial_element import is_Polynomial - if is_Polynomial(v) and parent.degree() == 1: + from sage.rings.polynomial.polynomial_element import Polynomial + if isinstance(v, Polynomial) and parent.degree() == 1: ring = v.parent() return ring([self._A[0,0], self._b[0]]) - from sage.rings.polynomial.multi_polynomial import is_MPolynomial - if is_MPolynomial(v) and parent.degree() == v.parent().ngens(): + from sage.rings.polynomial.multi_polynomial import MPolynomial + if isinstance(v, MPolynomial) and parent.degree() == v.parent().ngens(): ring = v.parent() from sage.modules.free_module_element import vector image_coords = self._A * vector(ring, ring.gens()) + self._b @@ -459,9 +451,7 @@ def __invert__(self): """ Return the inverse group element. - OUTPUT: - - Another affine group element. + OUTPUT: Another affine group element. EXAMPLES:: @@ -488,9 +478,7 @@ def _richcmp_(self, other, op): """ Compare ``self`` with ``other``. - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: diff --git a/src/sage/groups/artin.py b/src/sage/groups/artin.py index f36789cc792..4387e503ba7 100644 --- a/src/sage/groups/artin.py +++ b/src/sage/groups/artin.py @@ -12,7 +12,7 @@ - Travis Scrimshaw (2018-02-05): Initial version """ -#**************************************************************************** +# **************************************************************************** # Copyright (C) 2018 Travis Scrimshaw <tcscrims at gmail.com> # # This program is free software: you can redistribute it and/or modify @@ -20,7 +20,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.groups.free_group import FreeGroup @@ -39,6 +39,7 @@ class ArtinGroupElement(FinitelyPresentedGroupElement): EXAMPLES:: + sage: # needs sage.rings.number_field sage: A.<s1,s2,s3> = ArtinGroup(['B',3]) sage: A Artin group of type ['B', 3] @@ -57,9 +58,9 @@ def _latex_(self): TESTS:: - sage: A = ArtinGroup(['B',3]) - sage: b = A([1, 2, 3, -1, 2, -3]) - sage: b._latex_() + sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field + sage: b = A([1, 2, 3, -1, 2, -3]) # needs sage.rings.number_field + sage: b._latex_() # needs sage.rings.number_field '\\sigma_{1}\\sigma_{2}\\sigma_{3}\\sigma_{1}^{-1}\\sigma_{2}\\sigma_{3}^{-1}' sage: B = BraidGroup(4) @@ -80,6 +81,7 @@ def exponent_sum(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: A = ArtinGroup(['E',6]) sage: b = A([1, 4, -3, 2]) sage: b.exponent_sum() @@ -98,30 +100,61 @@ def exponent_sum(self): """ return sum(s.sign() for s in self.Tietze()) - def coxeter_group_element(self): + def coxeter_group_element(self, W=None): """ Return the corresponding Coxeter group element under the natural projection. + INPUT: + + - ``W`` -- (default: ``self.parent().coxeter_group()``) the image Coxeter group + OUTPUT: - A permutation. + An element of the Coxeter group ``W``. EXAMPLES:: - sage: A.<s1,s2,s3> = ArtinGroup(['B',3]) + sage: # needs sage.rings.number_field + sage: B.<s1,s2,s3> = ArtinGroup(['B',3]) sage: b = s1 * s2 / s3 / s2 - sage: b.coxeter_group_element() + sage: b1 = b.coxeter_group_element(); b1 [ 1 -1 0] [ 2 -1 0] [ a -a 1] sage: b.coxeter_group_element().reduced_word() [1, 2, 3, 2] + sage: A.<s1,s2,s3> = ArtinGroup(['A',3]) + sage: c = s1 * s2 *s3 + sage: c1 = c.coxeter_group_element(); c1 + [4, 1, 2, 3] + sage: c1.reduced_word() + [3, 2, 1] + sage: c.coxeter_group_element(W=SymmetricGroup(4)) + (1,4,3,2) + sage: A.<s1,s2,s3> = BraidGroup(4) + sage: c = s1 * s2 * s3^-1 + sage: c0 = c.coxeter_group_element(); c0 + [4, 1, 2, 3] + sage: c1 = c.coxeter_group_element(W=SymmetricGroup(4)); c1 + (1,4,3,2) + + From an element of the Coxeter group it is possible to recover + the image by the standard section to the Artin group:: + + sage: B(b1) + s1*s2*s3*s2 + sage: A(c0) + s1*s2*s3 + sage: A(c0) == A(c1) + True """ - W = self.parent().coxeter_group() + if W is None: + W = self.parent().coxeter_group() s = W.simple_reflections() - I = W.index_set() - return W.prod(s[I[abs(i)-1]] for i in self.Tietze()) + In = W.index_set() + return W.prod(s[In[abs(i)-1]] for i in self.Tietze()) + class FiniteTypeArtinGroupElement(ArtinGroupElement): """ @@ -133,6 +166,7 @@ def _richcmp_(self, other, op): TESTS:: + sage: # needs sage.rings.number_field sage: A = ArtinGroup(['B',3]) sage: x = A([1, 2, 1]) sage: y = A([2, 1, 2]) @@ -161,6 +195,7 @@ def __hash__(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: B.<s1,s2,s3> = ArtinGroup(['B',3]) sage: hash(s1*s3) == hash(s3*s1) True @@ -188,6 +223,7 @@ def left_normal_form(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: A = ArtinGroup(['B',3]) sage: A([1]).left_normal_form() (1, s1) @@ -207,7 +243,7 @@ def left_normal_form(self): sage: B = BraidGroup(4) sage: b = B([1, 2, 3, -1, 2, -3]) sage: b.left_normal_form() - (s0^-1*s1^-1*s2^-1*s0^-1*s1^-1*s0^-1, s0*s1*s2*s1*s0, s0*s2*s1) + (s0^-1*s1^-1*s0^-1*s2^-1*s1^-1*s0^-1, s0*s1*s2*s1*s0, s0*s2*s1) sage: c = B([1]) sage: c.left_normal_form() (1, s0) @@ -229,6 +265,7 @@ def _left_normal_form_coxeter(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: A = ArtinGroup(['E',6]) sage: A([2, -4, 2, 3, 1, 3, 2, 1, -2])._left_normal_form_coxeter() ( @@ -256,11 +293,11 @@ def _left_normal_form_coxeter(self): delta = 0 Delta = self.parent().coxeter_group().long_element() sr = self.parent().coxeter_group().simple_reflections() - l = self.Tietze() - if l == (): + tz = self.Tietze() + if tz == (): return (0,) form = [] - for i in l: + for i in tz: if i > 0: form.append(sr[i]) else: @@ -293,6 +330,7 @@ def _left_normal_form_coxeter(self): delta -= 1 return tuple([-delta] + form) + class ArtinGroup(FinitelyPresentedGroup): r""" An Artin group. @@ -344,9 +382,9 @@ class ArtinGroup(FinitelyPresentedGroup): EXAMPLES:: - sage: A.<a,b,c> = ArtinGroup(['B',3]); A + sage: A.<a,b,c> = ArtinGroup(['B',3]); A # needs sage.rings.number_field Artin group of type ['B', 3] - sage: ArtinGroup(['B',3]) + sage: ArtinGroup(['B',3]) # needs sage.rings.number_field Artin group of type ['B', 3] The input must always include the Coxeter data, but the ``names`` @@ -354,11 +392,11 @@ class ArtinGroup(FinitelyPresentedGroup): the explicit names of the generators. Otherwise the default prefix of ``'s'`` is used:: - sage: ArtinGroup(['B',2]).generators() + sage: ArtinGroup(['B',2]).generators() # needs sage.rings.number_field (s1, s2) - sage: ArtinGroup(['B',2], 'g').generators() + sage: ArtinGroup(['B',2], 'g').generators() # needs sage.rings.number_field (g1, g2) - sage: ArtinGroup(['B',2], 'x,y').generators() + sage: ArtinGroup(['B',2], 'x,y').generators() # needs sage.rings.number_field (x, y) REFERENCES: @@ -376,26 +414,28 @@ def __classcall_private__(cls, coxeter_data, names=None): TESTS:: + sage: # needs sage.rings.number_field sage: A1 = ArtinGroup(['B',3]) sage: A2 = ArtinGroup(['B',3], 's') sage: A3 = ArtinGroup(['B',3], ['s1','s2','s3']) sage: A1 is A2 and A2 is A3 True + sage: # needs sage.rings.number_field sage: A1 = ArtinGroup(['B',2], 'a,b') sage: A2 = ArtinGroup([[1,4],[4,1]], 'a,b') sage: A3.<a,b> = ArtinGroup('B2') sage: A1 is A2 and A2 is A3 True - sage: ArtinGroup(['A',3]) is BraidGroup(4, 's1,s2,s3') + sage: ArtinGroup(['A',3]) is BraidGroup(4, 's1,s2,s3') # needs sage.rings.number_field True sage: G = graphs.PathGraph(3) sage: CM = CoxeterMatrix([[1,-1,2],[-1,1,-1],[2,-1,1]], index_set=G.vertices(sort=True)) - sage: A = groups.misc.Artin(CM) - sage: Ap = groups.misc.RightAngledArtin(G, 's') - sage: A is Ap + sage: A = groups.misc.Artin(CM) # needs sage.rings.number_field + sage: Ap = groups.misc.RightAngledArtin(G, 's') # needs sage.rings.number_field + sage: A is Ap # needs sage.rings.number_field True """ coxeter_data = CoxeterMatrix(coxeter_data) @@ -426,6 +466,7 @@ def __init__(self, coxeter_matrix, names): TESTS:: + sage: # needs sage.rings.number_field sage: A = ArtinGroup(['D',4]) sage: TestSuite(A).run() sage: A = ArtinGroup(['B',3], ['x','y','z']) @@ -436,12 +477,12 @@ def __init__(self, coxeter_matrix, names): rels = [] # Generate the relations based on the Coxeter graph I = coxeter_matrix.index_set() - for ii,i in enumerate(I): - for j in I[ii+1:]: - m = coxeter_matrix[i,j] + for ii, i in enumerate(I): + for j in I[ii + 1:]: + m = coxeter_matrix[i, j] if m == Infinity: # no relation continue - elt = [i,j]*m + elt = [i, j] * m for ind in range(m, 2*m): elt[ind] = -elt[ind] rels.append(free_group(elt)) @@ -453,9 +494,9 @@ def _repr_(self): TESTS:: - sage: ArtinGroup(['B',3]) + sage: ArtinGroup(['B',3]) # needs sage.rings.number_field Artin group of type ['B', 3] - sage: ArtinGroup(['D',4], 'g') + sage: ArtinGroup(['D',4], 'g') # needs sage.rings.number_field Artin group of type ['D', 4] """ try: @@ -480,8 +521,8 @@ def cardinality(self): sage: G.cardinality() +Infinity - sage: A = ArtinGroup(['A',1]) - sage: A.cardinality() + sage: A = ArtinGroup(['A',1]) # needs sage.rings.number_field + sage: A.cardinality() # needs sage.rings.number_field +Infinity """ from sage.rings.infinity import Infinity @@ -505,8 +546,8 @@ def as_permutation_group(self): ... ValueError: the group is infinite - sage: A = ArtinGroup(['D',4], 'g') - sage: A.as_permutation_group() + sage: A = ArtinGroup(['D',4], 'g') # needs sage.rings.number_field + sage: A.as_permutation_group() # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: the group is infinite @@ -519,8 +560,8 @@ def coxeter_type(self): EXAMPLES:: - sage: A = ArtinGroup(['D',4]) - sage: A.coxeter_type() + sage: A = ArtinGroup(['D',4]) # needs sage.rings.number_field + sage: A.coxeter_type() # needs sage.rings.number_field Coxeter type of ['D', 4] """ return self._coxeter_group.coxeter_type() @@ -531,8 +572,8 @@ def coxeter_matrix(self): EXAMPLES:: - sage: A = ArtinGroup(['B',3]) - sage: A.coxeter_matrix() + sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field + sage: A.coxeter_matrix() # needs sage.rings.number_field [1 3 2] [3 1 4] [2 4 1] @@ -545,8 +586,8 @@ def coxeter_group(self): EXAMPLES:: - sage: A = ArtinGroup(['D',4]) - sage: A.coxeter_group() + sage: A = ArtinGroup(['D',4]) # needs sage.rings.number_field + sage: A.coxeter_group() # needs sage.rings.number_field Finite Coxeter group over Integer Ring with Coxeter matrix: [1 3 2 2] [3 1 3 3] @@ -565,8 +606,8 @@ def index_set(self): EXAMPLES:: - sage: A = ArtinGroup(['E',7]) - sage: A.index_set() + sage: A = ArtinGroup(['E',7]) # needs sage.rings.number_field + sage: A.index_set() # needs sage.rings.number_field (1, 2, 3, 4, 5, 6, 7) """ return self._coxeter_group.index_set() @@ -575,8 +616,8 @@ def _element_constructor_(self, x): """ TESTS:: - sage: A = ArtinGroup(['B',3]) - sage: A([2,1,-2,3,3,3,1]) + sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field + sage: A([2,1,-2,3,3,3,1]) # needs sage.rings.number_field s2*s1*s2^-1*s3^3*s1 """ if x in self._coxeter_group: @@ -590,8 +631,8 @@ def an_element(self): EXAMPLES:: - sage: A = ArtinGroup(['B',2]) - sage: A.an_element() + sage: A = ArtinGroup(['B',2]) # needs sage.rings.number_field + sage: A.an_element() # needs sage.rings.number_field s1 """ return self.gen(0) @@ -602,14 +643,14 @@ def some_elements(self): EXAMPLES:: - sage: A = ArtinGroup(['B',3]) - sage: A.some_elements() + sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field + sage: A.some_elements() # needs sage.rings.number_field [s1, s1*s2*s3, (s1*s2*s3)^3] """ rank = self.coxeter_matrix().rank() elements_list = [self.gen(0)] elements_list.append(self.prod(self.gens())) - elements_list.append(elements_list[-1] ** min(rank,3)) + elements_list.append(elements_list[-1] ** min(rank, 3)) return elements_list def _standard_lift_Tietze(self, w): @@ -623,8 +664,8 @@ def _standard_lift_Tietze(self, w): EXAMPLES:: - sage: A = ArtinGroup(['B',3]) - sage: A._standard_lift_Tietze(A.coxeter_group().long_element()) + sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field + sage: A._standard_lift_Tietze(A.coxeter_group().long_element()) # needs sage.rings.number_field [3, 2, 3, 1, 2, 3, 1, 2, 1] """ return w.reduced_word() @@ -641,14 +682,14 @@ def _standard_lift(self, w): EXAMPLES:: - sage: A = ArtinGroup(['B',3]) - sage: A._standard_lift(A.coxeter_group().long_element()) + sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field + sage: A._standard_lift(A.coxeter_group().long_element()) # needs sage.rings.number_field s3*(s2*s3*s1)^2*s2*s1 sage: B = BraidGroup(5) sage: P = Permutation([5, 3, 1, 2, 4]) sage: B._standard_lift(P) - s0*s1*s0*s2*s1*s3 + s0*s1*s2*s3*s0*s1 """ return self(self._standard_lift_Tietze(w)) @@ -670,7 +711,7 @@ class FiniteTypeArtinGroup(ArtinGroup): EXAMPLES:: - sage: ArtinGroup(['E',7]) + sage: ArtinGroup(['E',7]) # needs sage.rings.number_field Artin group of type ['E', 7] Since the word problem for finite-type Artin groups is solvable, their @@ -683,15 +724,15 @@ class FiniteTypeArtinGroup(ArtinGroup): ....: for w in Words(alphabet=group.gens(), length=length): ....: ret.add(prod(w)) ....: return ret - sage: A = ArtinGroup(['B',3]) - sage: GA = A.cayley_graph(elements=ball(A, 4), generators=A.gens()); GA + sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field + sage: GA = A.cayley_graph(elements=ball(A, 4), generators=A.gens()); GA # needs sage.rings.number_field Digraph on 32 vertices Since the Artin group has nontrivial relations, this graph contains less vertices than the one associated to the free group (which is a tree):: sage: F = FreeGroup(3) - sage: GF = F.cayley_graph(elements=ball(F, 4), generators=F.gens()); GF + sage: GF = F.cayley_graph(elements=ball(F, 4), generators=F.gens()); GF # needs sage.combinat Digraph on 40 vertices """ def delta(self): @@ -700,17 +741,17 @@ def delta(self): EXAMPLES:: - sage: A = ArtinGroup(['B',3]) - sage: A.delta() + sage: A = ArtinGroup(['B',3]) # needs sage.rings.number_field + sage: A.delta() # needs sage.rings.number_field s3*(s2*s3*s1)^2*s2*s1 - sage: A = ArtinGroup(['G',2]) - sage: A.delta() + sage: A = ArtinGroup(['G',2]) # needs sage.rings.number_field + sage: A.delta() # needs sage.rings.number_field (s2*s1)^3 sage: B = BraidGroup(5) sage: B.delta() - s0*s1*s0*s2*s1*s0*s3*s2*s1*s0 + s0*s1*s2*s3*s0*s1*s2*s0*s1*s0 """ return self._standard_lift(self._coxeter_group.long_element()) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 78769348a66..8d6c062bd63 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -67,32 +67,39 @@ # https://www.gnu.org/licenses/ ############################################################################## -from sage.rings.integer import Integer -from sage.rings.integer_ring import IntegerRing +from itertools import combinations +from sage.categories.action import Action +from sage.categories.groups import Groups +from sage.combinat.permutation import Permutation +from sage.combinat.permutation import Permutations +from sage.combinat.subset import Subsets +from sage.features import PythonModule +from sage.groups.artin import FiniteTypeArtinGroup, FiniteTypeArtinGroupElement +from sage.groups.finitely_presented import FinitelyPresentedGroup +from sage.groups.finitely_presented import GroupMorphismWithGensImages +from sage.groups.free_group import FreeGroup, is_FreeGroup +from sage.functions.generalized import sign +from sage.groups.perm_gps.permgroup_named import SymmetricGroup +from sage.groups.perm_gps.permgroup_named import SymmetricGroupElement +from sage.knots.knot import Knot +from sage.libs.gap.libgap import libgap +from sage.matrix.constructor import identity_matrix, matrix from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import lazy_import from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod -from sage.categories.groups import Groups -from sage.groups.free_group import FreeGroup, is_FreeGroup +from sage.rings.integer import Integer +from sage.rings.integer_ring import IntegerRing from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.matrix.constructor import identity_matrix, matrix -from sage.combinat.permutation import Permutations -from sage.combinat.subset import Subsets -from sage.categories.action import Action -from sage.knots.knot import Knot from sage.sets.set import Set -from sage.groups.finitely_presented import FinitelyPresentedGroup -from sage.groups.artin import FiniteTypeArtinGroup, FiniteTypeArtinGroupElement +from sage.structure.element import Expression from sage.structure.richcmp import richcmp, rich_to_bool -from sage.features import PythonModule - lazy_import('sage.libs.braiding', - ['rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor', + ['leftnormalform', 'rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor', 'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset', 'thurston_type', 'rigidity', 'sliding_circuits'], - feature=PythonModule('sage.libs.braiding', spkg='libbraiding')) + feature=PythonModule('sage.libs.braiding', spkg='libbraiding', type='standard')) class Braid(FiniteTypeArtinGroupElement): @@ -427,24 +434,41 @@ def alexander_polynomial(self, var='t', normalized=True): p = -p return p - def permutation(self): + def permutation(self, W=None): """ Return the permutation induced by the braid in its strands. + INPUT: + + - ``W`` -- (optional) the permutation group to project + ``self`` to; the default is ``self.parent().coxeter_group()`` + OUTPUT: - A permutation. + The image of ``self`` under the natural projection map to ``W``. EXAMPLES:: sage: B.<s0,s1,s2> = BraidGroup() + sage: S = SymmetricGroup(4) sage: b = s0*s1/s2/s1 - sage: b.permutation() + sage: c0 = b.permutation(W=S); c0 + (1,4,2) + sage: c1 = b.permutation(W=Permutations(4)); c1 [4, 1, 3, 2] - sage: b.permutation().cycle_string() - '(1,4,2)' + sage: c1 == b.permutation() + True + + The canonical section from the symmetric group to the braid group + (sending a permutation to its associated permutation braid) + can be recovered:: + + sage: B(c0) + s0*s1*s2*s1 + sage: B(c0) == B(c1) + True """ - return self.coxeter_group_element() + return self.coxeter_group_element(W) def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, aspect_ratio=1, axes=False, **kwds): """ @@ -483,16 +507,27 @@ def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, aspect_ratio EXAMPLES:: + sage: B = BraidGroup(3) + sage: a = B([2, 2, -1, -1]) + sage: b = B([2, 1, 2, 1]) + sage: c = b * a / b + sage: d = a.conjugating_braid(c) + sage: d * c / d == a + True + sage: d + s1*s0 + sage: d * a / d == c + False sage: B = BraidGroup(4, 's') sage: b = B([1, 2, 3, 1, 2, 1]) - sage: b.plot() + sage: b.plot() # needs sage.plot Graphics object consisting of 30 graphics primitives - sage: b.plot(color=["red", "blue", "red", "blue"]) + sage: b.plot(color=["red", "blue", "red", "blue"]) # needs sage.plot Graphics object consisting of 30 graphics primitives sage: B.<s,t> = BraidGroup(3) sage: b = t^-1*s^2 - sage: b.plot(orientation="left-right", color="red") + sage: b.plot(orientation="left-right", color="red") # needs sage.plot Graphics object consisting of 12 graphics primitives """ from sage.plot.bezier_path import bezier_path @@ -586,11 +621,11 @@ def plot3d(self, color='rainbow'): sage: B = BraidGroup(4, 's') sage: b = B([1, 2, 3, 1, 2, 1]) - sage: b.plot3d() + sage: b.plot3d() # needs sage.plot sage.symbolic Graphics3d Object - sage: b.plot3d(color="red") + sage: b.plot3d(color="red") # needs sage.plot sage.symbolic Graphics3d Object - sage: b.plot3d(color=["red", "blue", "red", "blue"]) + sage: b.plot3d(color=["red", "blue", "red", "blue"]) # needs sage.plot sage.symbolic Graphics3d Object """ from sage.plot.plot3d.shapes2 import bezier3d @@ -767,7 +802,7 @@ def TL_matrix(self, drain_size, variab=None, sparse=True): def links_gould_matrix(self, symbolics=False): r""" Return the representation matrix of ``self`` according to the R-matrix - representation being attached to the quantum superalgebra `sl_q(2|1)`. + representation being attached to the quantum superalgebra `\mathfrak{sl}_q(2|1)`. See [MW2012]_, section 3 and references given there. INPUT: @@ -792,8 +827,8 @@ def links_gould_matrix(self, symbolics=False): Univariate Quotient Polynomial Ring in Yrbar over Multivariate Laurent Polynomial Ring in s0r, s1r over Integer Ring with modulus Yr^2 + s0r^2*s1r^2 - s0r^2 - s1r^2 + 1 - sage: HopfLGs = Hopf.links_gould_matrix(symbolics=True) - sage: HopfLGs.base_ring() + sage: HopfLGs = Hopf.links_gould_matrix(symbolics=True) # needs sage.symbolic + sage: HopfLGs.base_ring() # needs sage.symbolic Symbolic Ring """ rep = self.parent()._links_gould_representation(symbolics=symbolics) @@ -844,8 +879,8 @@ def links_gould_polynomial(self, varnames=None, use_symbolics=False): varnames = 't0, t1' rep = self.parent()._links_gould_representation(symbolics=use_symbolics) - l = len(rep) - mu = rep[l-1] # quantum trace factor + ln = len(rep) + mu = rep[ln - 1] # quantum trace factor M = mu * self.links_gould_matrix(symbolics=use_symbolics) d1, d2 = M.dimensions() e = d1//4 @@ -853,13 +888,13 @@ def links_gould_polynomial(self, varnames=None, use_symbolics=False): R = LaurentPolynomialRing(ZZ, varnames) # partial quantum trace according to I. Marin section 2.5 - part_trace = matrix(B, 4, 4, lambda i, j: sum(M[e*i+ k, e*j+k] for k in range(e))) - ptemp = part_trace[0,0] # part_trace == psymb*M.parent().one() + part_trace = matrix(B, 4, 4, lambda i, j: sum(M[e * i + k, e * j + k] for k in range(e))) + ptemp = part_trace[0, 0] # part_trace == psymb*M.parent().one() if use_symbolics: v1, v2 = R.variable_names() pstr = str(ptemp._sympy_().simplify()) pstr = pstr.replace('t0', v1).replace('t1', v2) - F = R.fraction_field() # to make coercion work + F = R.fraction_field() # to make coercion work return R(F(pstr)) else: ltemp = ptemp.lift().constant_coefficient() @@ -996,15 +1031,15 @@ def _jones_polynomial(self): sage: B = BraidGroup(9) sage: b = B([1, 2, 3, 4, 5, 6, 7, 8]) - sage: b.jones_polynomial() + sage: b.jones_polynomial() # needs sage.symbolic 1 sage: B = BraidGroup(2) sage: b = B([]) - sage: b._jones_polynomial + sage: b._jones_polynomial # needs sage.symbolic -A^-2 - A^2 sage: b = B([-1, -1, -1]) - sage: b._jones_polynomial + sage: b._jones_polynomial # needs sage.symbolic -A^-16 + A^-12 + A^-4 """ trace = self.markov_trace(normalized=False) @@ -1015,7 +1050,7 @@ def _jones_polynomial(self): return (-1)**(num_comp-1) * A**(2*exp_sum) * trace // D def jones_polynomial(self, variab=None, skein_normalization=False): - """ + r""" Return the Jones polynomial of the trace closure of the braid. The normalization is so that the unknot has Jones polynomial `1`. If @@ -1034,7 +1069,7 @@ def jones_polynomial(self, variab=None, skein_normalization=False): - ``variab`` -- variable (default: ``None``); the variable in the resulting polynomial; if unspecified, use either a default variable - in `ZZ[A,A^{-1}]` or the variable `t` in the symbolic ring + in `\ZZ[A,A^{-1}]` or the variable `t` in the symbolic ring - ``skein_normalization`` -- boolean (default: ``False``); determines the variable of the resulting polynomial @@ -1052,25 +1087,26 @@ def jones_polynomial(self, variab=None, skein_normalization=False): sage: B = BraidGroup(9) sage: b = B([1, 2, 3, 4, 5, 6, 7, 8]) - sage: b.jones_polynomial() + sage: b.jones_polynomial() # needs sage.symbolic 1 Two unlinked unknots:: sage: B = BraidGroup(2) sage: b = B([]) - sage: b.jones_polynomial() + sage: b.jones_polynomial() # needs sage.symbolic -sqrt(t) - 1/sqrt(t) The Hopf link:: sage: B = BraidGroup(2) sage: b = B([-1,-1]) - sage: b.jones_polynomial() + sage: b.jones_polynomial() # needs sage.symbolic -1/sqrt(t) - 1/t^(5/2) Different representations of the trefoil and one of its mirror:: + sage: # needs sage.symbolic sage: B = BraidGroup(2) sage: b = B([-1, -1, -1]) sage: b.jones_polynomial(skein_normalization=True) @@ -1095,7 +1131,7 @@ def jones_polynomial(self, variab=None, skein_normalization=False): sage: B = BraidGroup(4) sage: b11n42 = B([1, -2, 3, -2, 3, -2, -2, -1, 2, -3, -3, 2, 2]) sage: b11n34 = B([1, 1, 2, -3, 2, -3, 1, -2, -2, -3, -3]) - sage: bool(b11n42.jones_polynomial() == b11n34.jones_polynomial()) + sage: bool(b11n42.jones_polynomial() == b11n34.jones_polynomial()) # needs sage.symbolic True """ if skein_normalization: @@ -1104,12 +1140,14 @@ def jones_polynomial(self, variab=None, skein_normalization=False): else: return self._jones_polynomial(variab) else: - from sage.symbolic.ring import SR from sage.rings.integer_ring import ZZ if variab is None: variab = 't' + if not isinstance(variab, Expression): + from sage.symbolic.ring import SR + variab = SR(variab) # We force the result to be in the symbolic ring because of the expand - return self._jones_polynomial(SR(variab)**(ZZ(1)/ZZ(4))).expand() + return self._jones_polynomial(variab**(ZZ(1)/ZZ(4))).expand() @cached_method def _enhanced_states(self): @@ -1302,8 +1340,6 @@ def _annular_khovanov_complex_cached(self, qagrad, ring=None): sage: B = BraidGroup(3) sage: B([1,2,1,2])._annular_khovanov_complex_cached((5,-1)).homology() {1: Z, 2: Z, 3: 0} - - """ from sage.homology.chain_complex import ChainComplex if ring is None: @@ -1447,6 +1483,55 @@ def annular_khovanov_homology(self, qagrad=None, ring=IntegerRing()): return {qa: C[qa].homology() for qa in C} return self.annular_khovanov_complex(qagrad, ring).homology() + @cached_method + def left_normal_form(self, algorithm='libbraiding'): + r""" + Return the left normal form of the braid. + + INPUT: + + - ``algorithm`` -- string (default: ``'artin'``); must be one of the following: + + * ``'artin'`` -- the general method for Artin groups is used + * ``'libbraiding'`` -- the algorithm from the ``libbraiding`` package + + OUTPUT: + + A tuple of simple generators in the left normal form. The first + element is a power of `\Delta`, and the rest are elements of the + natural section lift from the corresponding symmetric group. + + EXAMPLES:: + + sage: B = BraidGroup(6) + sage: B.one().left_normal_form() + (1,) + sage: b = B([-2, 2, -4, -4, 4, -5, -1, 4, -1, 1]) + sage: L1 = b.left_normal_form(); L1 + (s0^-1*s1^-1*s0^-1*s2^-1*s1^-1*s0^-1*s3^-1*s2^-1*s1^-1*s0^-1*s4^-1*s3^-1*s2^-1*s1^-1*s0^-1, + s0*s2*s1*s0*s3*s2*s1*s0*s4*s3*s2*s1, + s3) + sage: L1 == b.left_normal_form() + True + sage: B([1]).left_normal_form(algorithm='artin') + (1, s0) + sage: B([-3]).left_normal_form(algorithm='artin') + (s0^-1*s1^-1*s0^-1*s2^-1*s1^-1*s0^-1*s3^-1*s2^-1*s1^-1*s0^-1*s4^-1*s3^-1*s2^-1*s1^-1*s0^-1, + s0*s1*s2*s3*s4*s0*s1*s2*s3*s1*s2*s0*s1*s0) + sage: B = BraidGroup(3) + sage: B([1,2,-1]).left_normal_form() + (s0^-1*s1^-1*s0^-1, s1*s0, s0*s1) + sage: B([1,2,1]).left_normal_form() + (s0*s1*s0,) + """ + if algorithm == 'libbraiding': + lnf = leftnormalform(self) + B = self.parent() + return tuple([B.delta()**lnf[0][0]] + [B(b) for b in lnf[1:]]) + elif algorithm == 'artin': + return FiniteTypeArtinGroupElement.left_normal_form.f(self) + raise ValueError("invalid algorithm") + def _left_normal_form_coxeter(self): r""" Return the left normal form of the braid, in permutation form. @@ -1471,6 +1556,10 @@ def _left_normal_form_coxeter(self): (-2, [3, 5, 4, 2, 6, 1], [1, 6, 3, 5, 2, 4], [5, 6, 2, 4, 1, 3], [3, 2, 4, 1, 5, 6], [1, 5, 2, 3, 4, 6]) + .. NOTE:: + + For long braids this method is slower than ``algorithm='libbraiding'``. + .. TODO:: Remove this method and use the default one from @@ -1479,11 +1568,11 @@ def _left_normal_form_coxeter(self): delta = 0 Delta = self.parent()._coxeter_group.long_element() sr = self.parent()._coxeter_group.simple_reflections() - l = self.Tietze() - if not l: + tz = self.Tietze() + if not tz: return (0,) form = [] - for i in l: + for i in tz: if i > 0: form.append(sr[i]) else: @@ -1517,9 +1606,13 @@ def _left_normal_form_coxeter(self): return tuple([-delta] + form) def right_normal_form(self): - """ + r""" Return the right normal form of the braid. + A tuple of simple generators in the right normal form. The last + element is a power of `\Delta`, and the rest are elements of the + natural section lift from the corresponding symmetric group. + EXAMPLES:: sage: B = BraidGroup(4) @@ -1527,9 +1620,9 @@ def right_normal_form(self): sage: b.right_normal_form() (s1*s0, s0*s2, 1) """ - l = rightnormalform(self) + rnf = rightnormalform(self) B = self.parent() - return tuple([B(b) for b in l[:-1]] + [B.delta()**l[-1][0]]) + return tuple([B(b) for b in rnf[:-1]] + [B.delta()**rnf[-1][0]]) def centralizer(self): """ @@ -1543,9 +1636,9 @@ def centralizer(self): [s1*s0*s2*s1, s0*s2] """ - l = centralizer(self) + c = centralizer(self) B = self.parent() - return [B._element_from_libbraiding(b) for b in l] + return [B._element_from_libbraiding(b) for b in c] def super_summit_set(self): """ @@ -1557,14 +1650,14 @@ def super_summit_set(self): sage: b = B([1, 2, -1, -2, -2, 1]) sage: b.super_summit_set() [s0^-1*s1^-1*s0^-2*s1^2*s0^2, - (s0^-1*s1^-1*s0^-1)^2*s1^2*s0^3*s1, - (s0^-1*s1^-1*s0^-1)^2*s1*s0^3*s1^2, - s0^-1*s1^-1*s0^-2*s1^-1*s0*s1^3*s0] + (s0^-1*s1^-1*s0^-1)^2*s1^2*s0^3*s1, + (s0^-1*s1^-1*s0^-1)^2*s1*s0^3*s1^2, + s0^-1*s1^-1*s0^-2*s1^-1*s0*s1^3*s0] """ - l = supersummitset(self) + sss = supersummitset(self) B = self.parent() - return [B._element_from_libbraiding(b) for b in l] + return [B._element_from_libbraiding(b) for b in sss] def gcd(self, other): """ @@ -1614,27 +1707,64 @@ def conjugating_braid(self, other): INPUT: - - ``other`` -- the other braid to look for conjugating braid + - ``other`` -- a braid in the same braid group as ``self`` + + OUTPUT: + + A conjugating braid. + + More precisely, if the output is `d`, `o` equals ``other``, and `s` equals ``self`` + then `o = d^{-1} \cdot s \cdot d`. EXAMPLES:: sage: B = BraidGroup(3) + sage: B.one().conjugating_braid(B.one()) + 1 + sage: B.one().conjugating_braid(B.gen(0)) is None + True + sage: B.gen(0).conjugating_braid(B.gen(1)) + s1*s0 + sage: B.gen(0).conjugating_braid(B.gen(1).inverse()) is None + True sage: a = B([2, 2, -1, -1]) sage: b = B([2, 1, 2, 1]) sage: c = b * a / b - sage: d = a.conjugating_braid(c) - sage: d * c / d == a - True - sage: d + sage: d1 = a.conjugating_braid(c) + sage: d1 s1*s0 - sage: d * a / d == c + sage: d1 * c / d1 == a + True + sage: d1 * a / d1 == c False + sage: l = sage.groups.braid.conjugatingbraid(a,c) # needs sage.groups + sage: d1 == B._element_from_libbraiding(l) # needs sage.groups + True + sage: b = B([2, 2, 2, 2, 1]) + sage: c = b * a / b + sage: d1 = a.conjugating_braid(c) + sage: len(d1.Tietze()) + 7 + sage: d1 * c / d1 == a + True + sage: d1 * a / d1 == c + False + sage: d1 + s1^2*s0^2*s1^2*s0 + sage: l = sage.groups.braid.conjugatingbraid(a,c) # needs sage.groups + sage: d2 = B._element_from_libbraiding(l) # needs sage.groups + sage: len(d2.Tietze()) # needs sage.groups + 13 + sage: c.conjugating_braid(b) is None + True """ - l = conjugatingbraid(self, other) - if not l: + cb = conjugatingbraid(self, other) + if not cb: return None else: - return self.parent()._element_from_libbraiding(l) + B = self.parent() + cb[0][0] %= 2 + return B._element_from_libbraiding(cb) def is_conjugated(self, other): """ @@ -1655,8 +1785,102 @@ def is_conjugated(self, other): sage: c.is_conjugated(b) False """ - l = conjugatingbraid(self, other) - return bool(l) + cb = conjugatingbraid(self, other) + return bool(cb) + + def pure_conjugating_braid(self, other): + r""" + Return a pure conjugating braid, i.e. a conjugating braid whose + associated permutation is the identity, if it exists. + + INPUT: + + - ``other`` -- a braid in the same braid group as ``self`` + + OUTPUT: + + A pure conjugating braid. + + More precisely, if the output is `d`, `o` equals ``other``, and `s` equals ``self`` + then `o = d^{-1} \cdot s \cdot d`. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: B.one().pure_conjugating_braid(B.one()) + 1 + sage: B.one().pure_conjugating_braid(B.gen(0)) is None + True + sage: B.gen(0).pure_conjugating_braid(B.gen(1)) is None + True + sage: B.gen(0).conjugating_braid(B.gen(2).inverse()) is None + True + sage: a = B([1, 2, 3]) + sage: b = B([3, 2,]) + sage: c = b ^ 12 * a / b ^ 12 + sage: d1 = a.conjugating_braid(c) + sage: len(d1.Tietze()) + 30 + sage: S = SymmetricGroup(4) + sage: d1.permutation(W=S) + (1,3)(2,4) + sage: d1 * c / d1 == a + True + sage: d1 * a / d1 == c + False + sage: d2 = a.pure_conjugating_braid(c) + sage: len(d2.Tietze()) + 24 + sage: d2.permutation(W=S) + () + sage: d2 * c / d2 == a + True + sage: d2 + (s0*s1*s2^2*s1*s0)^4 + sage: a.conjugating_braid(b) is None + True + sage: a.pure_conjugating_braid(b) is None + True + sage: a1 = B([1]) + sage: a2 = B([2]) + sage: a1.conjugating_braid(a2) + s1*s0 + sage: a1.permutation(W=S) + (1,2) + sage: a2.permutation(W=S) + (2,3) + sage: a1.pure_conjugating_braid(a2) is None + True + sage: (a1^2).conjugating_braid(a2^2) + s1*s0 + sage: (a1^2).pure_conjugating_braid(a2^2) is None + True + """ + B = self.parent() + n = B.strands() + S = SymmetricGroup(n) + p1 = self.permutation(W=S) + p2 = other.permutation(W=S) + if p1 != p2: + return None + b0 = self.conjugating_braid(other) + if b0 is None: + return None + p3 = b0.permutation(W=S).inverse() + if p3.is_one(): + return b0 + LP = {a.permutation(W=S): a for a in self.centralizer()} + if p3 not in S.subgroup(LP): + return None + P = p3.word_problem(list(LP), display=False, as_list=True) + b1 = prod(LP[S(a)] ** b for a, b in P) + b0 = b1 * b0 + n0 = len(b0.Tietze()) + L = leftnormalform(b0) + L[0][0] %= 2 + b2 = B._element_from_libbraiding(L) + n2 = len(b2.Tietze()) + return b2 if n2 <= n0 else b0 def ultra_summit_set(self): """ @@ -1671,17 +1895,17 @@ def ultra_summit_set(self): [[s0*s1*s0^2, (s0*s1)^2]] sage: a.ultra_summit_set() [[(s0^-1*s1^-1*s0^-1)^2*s1^3*s0^2*s1^3, - (s0^-1*s1^-1*s0^-1)^2*s1^2*s0^2*s1^4, - (s0^-1*s1^-1*s0^-1)^2*s1*s0^2*s1^5, - s0^-1*s1^-1*s0^-2*s1^5*s0, - (s0^-1*s1^-1*s0^-1)^2*s1^5*s0^2*s1, - (s0^-1*s1^-1*s0^-1)^2*s1^4*s0^2*s1^2], - [s0^-1*s1^-1*s0^-2*s1^-1*s0^2*s1^2*s0^3, - s0^-1*s1^-1*s0^-2*s1^-1*s0*s1^2*s0^4, - s0^-1*s1^-1*s0^-2*s1*s0^5, - (s0^-1*s1^-1*s0^-1)^2*s1*s0^6*s1, - s0^-1*s1^-1*s0^-2*s1^-1*s0^4*s1^2*s0, - s0^-1*s1^-1*s0^-2*s1^-1*s0^3*s1^2*s0^2]] + (s0^-1*s1^-1*s0^-1)^2*s1^2*s0^2*s1^4, + (s0^-1*s1^-1*s0^-1)^2*s1*s0^2*s1^5, + s0^-1*s1^-1*s0^-2*s1^5*s0, + (s0^-1*s1^-1*s0^-1)^2*s1^5*s0^2*s1, + (s0^-1*s1^-1*s0^-1)^2*s1^4*s0^2*s1^2], + [s0^-1*s1^-1*s0^-2*s1^-1*s0^2*s1^2*s0^3, + s0^-1*s1^-1*s0^-2*s1^-1*s0*s1^2*s0^4, + s0^-1*s1^-1*s0^-2*s1*s0^5, + (s0^-1*s1^-1*s0^-1)^2*s1*s0^6*s1, + s0^-1*s1^-1*s0^-2*s1^-1*s0^4*s1^2*s0, + s0^-1*s1^-1*s0^-2*s1^-1*s0^3*s1^2*s0^2]] """ uss = ultrasummitset(self) B = self.parent() @@ -1860,7 +2084,7 @@ def deformed_burau_matrix(self, variab='q'): OUTPUT: - A matrix with elements in the free algebra `self._algebra`. + A matrix with elements in the free algebra ``self._algebra``. EXAMPLES:: @@ -1902,19 +2126,19 @@ def deformed_burau_matrix(self, variab='q'): """ R = LaurentPolynomialRing(IntegerRing(), variab) n = self.strands() - m = len(self.Tietze()) + tz = self.Tietze() + m = len(tz) from sage.algebras.free_algebra import FreeAlgebra - alg = FreeAlgebra(R, m*3, [f'{s}p_{i}' - for i in range(m) if self.Tietze()[i] > 0 - for s in 'bca'] - + [f'{s}m_{i}' - for i in range(m) if self.Tietze()[i] < 0 - for s in 'bca']) - gen_indices = ([i for i in range(m) if self.Tietze()[i] > 0] - + [i for i in range(m) if self.Tietze()[i] < 0]) + alg = FreeAlgebra(R, m*3, + [f'{s}p_{i}' for i in range(m) if tz[i] > 0 + for s in 'bca'] + + [f'{s}m_{i}' for i in range(m) if tz[i] < 0 + for s in 'bca']) + gen_indices = ([i for i in range(m) if tz[i] > 0] + + [i for i in range(m) if tz[i] < 0]) M = identity_matrix(alg, n) - for k, i in enumerate(self.Tietze()): + for k, i in enumerate(tz): A = identity_matrix(alg, n) gen_index = gen_indices.index(k) b, c, a = alg.gens()[3*gen_index:3*gen_index+3] @@ -2261,8 +2485,8 @@ def eps_monom(q_tuple): ret_q *= prod(prod(1 - q**(N - 1 - q_tuple[3*i + 1] - h) for h in range(q_tuple[3*i + 2])) for i in range(self._minus_begin//3)) - ret_q *= prod(prod(1 - q**(q_tuple[3*j + 1] + l + 1 - N) - for l in range(q_tuple[3*j + 2])) + ret_q *= prod(prod(1 - q**(q_tuple[3*j + 1] + k + 1 - N) + for k in range(q_tuple[3*j + 2])) for j in range(self._minus_begin//3, len(q_tuple)//3)) return ret_q @@ -2353,10 +2577,10 @@ def __init__(self, names): d*f*d^-1*f^-1, e*f*e*f^-1*e^-1*f^-1) - sage: BraidGroup([]) - Traceback (most recent call last): - ... - ValueError: the number of strands must be at least 2 + sage: BraidGroup([]) + Traceback (most recent call last): + ... + ValueError: the number of strands must be at least 2 """ n = len(names) # n is the number of generators, not the number of strands @@ -2405,7 +2629,7 @@ def _repr_(self): TESTS:: sage: B1 = BraidGroup(5) - sage: B1 # indirect doctest + sage: B1 # indirect doctest Braid group on 5 strands """ return "Braid group on %s strands" % self._nstrands @@ -2470,7 +2694,14 @@ def _element_constructor_(self, x): sage: B = BraidGroup(4) sage: B([1, 2, 3]) # indirect doctest s0*s1*s2 - """ + sage: p = Permutation([3,1,2,4]); B(p) + s0*s1 + sage: q = SymmetricGroup(4)((1,2)); B(q) + s0 + """ + if not isinstance(x, (tuple, list)): + if isinstance(x, (SymmetricGroupElement, Permutation)): + x = self._standard_lift_Tietze(x) return self.element_class(self, x) def an_element(self): @@ -2524,7 +2755,7 @@ def _standard_lift_Tietze(self, p): OUTPUT: - The lexicographically smallest word that represents the braid, + A shortest word that represents the braid, in Tietze list form. EXAMPLES:: @@ -2532,22 +2763,11 @@ def _standard_lift_Tietze(self, p): sage: B = BraidGroup(5) sage: P = Permutation([5, 3, 1, 2, 4]) sage: B._standard_lift_Tietze(P) - (1, 2, 1, 3, 2, 4) - """ - if not p.length(): - return () - pl = p - l = [] - while pl.length(): - i = 1 - while i < max(pl): - if pl(i) > pl(i+1): - l.append(i) - pl = self._coxeter_group.simple_reflection(i) * pl - i = 1 - else: - i += 1 - return tuple(l) + (1, 2, 3, 4, 1, 2) + """ + G = SymmetricGroup(self.strands()) + pl = G(p) + return tuple(pl.reduced_word()) @cached_method def _links_gould_representation(self, symbolics=False): @@ -2580,7 +2800,7 @@ def _links_gould_representation(self, symbolics=False): """ from sage.matrix.constructor import matrix n = self.strands() - d = 4 # dimension of the natural module + d = 4 # dimension of the natural module from sage.matrix.special import diagonal_matrix if symbolics: from sage.symbolic.ring import SR as BR @@ -2597,7 +2817,7 @@ def _links_gould_representation(self, symbolics=False): LR = LaurentPolynomialRing(ZZ, 's0r, s1r') PR = PolynomialRing(LR, 'Yr') s0r, s1r, Yr = PR.gens_dict_recursive().values() - pqr = Yr**2 + (s0r**2-1)*(s1r**2 -1) + pqr = Yr**2 + (s0r**2 - 1) * (s1r**2 - 1) BR = PR.quotient_ring(pqr) s0 = BR(s0r) s1 = BR(s1r) @@ -2611,12 +2831,12 @@ def _links_gould_representation(self, symbolics=False): if n == 2: # R-Matrix taken from I. Marin R = matrix(BR, {(0, 0): t0, (1, 4): s0, (2, 8): s0, (3, 12): 1, - (4, 1): s0, (4, 4): t0 - 1, (5, 5): -1, (6, 6): t0*t1 - 1, - (6, 9): -s0*s1, (6, 12): -Y*s0*s1, (7, 13): s1, (8, 2): s0, - (8, 8): t0 - 1, (9, 6): -s0*s1, (9, 12): Y, (10, 10): -1, - (11, 14): s1, (12, 3): 1, (12, 6): -Y*s0*s1, (12, 9): Y, - (12, 12): -(t0 - 1)*(t1 - 1), (13, 7): s1, (13, 13): t1 - 1, - (14, 11): s1, (14, 14): t1 - 1, (15, 15): t1}, sparse=sparse) + (4, 1): s0, (4, 4): t0 - 1, (5, 5): -1, (6, 6): t0*t1 - 1, + (6, 9): -s0*s1, (6, 12): -Y*s0*s1, (7, 13): s1, (8, 2): s0, + (8, 8): t0 - 1, (9, 6): -s0*s1, (9, 12): Y, (10, 10): -1, + (11, 14): s1, (12, 3): 1, (12, 6): -Y*s0*s1, (12, 9): Y, + (12, 12): -(t0 - 1)*(t1 - 1), (13, 7): s1, (13, 13): t1 - 1, + (14, 11): s1, (14, 14): t1 - 1, (15, 15): t1}, sparse=sparse) RI = (~t0 + ~t1)*(1 + R) - ~t0*~t1*(R + R**2) - 1 # quantum trace operator on two fold tensor space @@ -2693,58 +2913,58 @@ def _LKB_matrix_(self, braid, variab): for i in braid[1:]: A = A*self._LKB_matrix_((i,), variab) return A - l = list(Set(range(n)).subsets(2)) + n2 = [set(X) for X in combinations(range(n), 2)] R = LaurentPolynomialRing(IntegerRing(), variab) q = R.gens()[0] t = R.gens()[1] if not braid: - return identity_matrix(R, len(l), sparse=True) - A = matrix(R, len(l), sparse=True) + return identity_matrix(R, len(n2), sparse=True) + A = matrix(R, len(n2), sparse=True) if braid[0] > 0: - i = braid[0]-1 - for m in range(len(l)): - j = min(l[m]) - k = max(l[m]) + i = braid[0] - 1 + for m in range(len(n2)): + j = min(n2[m]) + k = max(n2[m]) if i == j-1: - A[l.index(Set([i, k])), m] = q - A[l.index(Set([i, j])), m] = q*q-q - A[l.index(Set([j, k])), m] = 1-q + A[n2.index(Set([i, k])), m] = q + A[n2.index(Set([i, j])), m] = q*q-q + A[n2.index(Set([j, k])), m] = 1-q elif i == j and not j == k-1: - A[l.index(Set([j, k])), m] = 0 - A[l.index(Set([j+1, k])), m] = 1 + A[n2.index(Set([j, k])), m] = 0 + A[n2.index(Set([j+1, k])), m] = 1 elif k-1 == i and not k-1 == j: - A[l.index(Set([j, i])), m] = q - A[l.index(Set([j, k])), m] = 1-q - A[l.index(Set([i, k])), m] = (1-q)*q*t + A[n2.index(Set([j, i])), m] = q + A[n2.index(Set([j, k])), m] = 1-q + A[n2.index(Set([i, k])), m] = (1-q)*q*t elif i == k: - A[l.index(Set([j, k])), m] = 0 - A[l.index(Set([j, k+1])), m] = 1 + A[n2.index(Set([j, k])), m] = 0 + A[n2.index(Set([j, k+1])), m] = 1 elif i == j and j == k-1: - A[l.index(Set([j, k])), m] = -t*q*q + A[n2.index(Set([j, k])), m] = -t*q*q else: - A[l.index(Set([j, k])), m] = 1 + A[n2.index(Set([j, k])), m] = 1 return A else: i = -braid[0]-1 - for m in range(len(l)): - j = min(l[m]) - k = max(l[m]) + for m in range(len(n2)): + j = min(n2[m]) + k = max(n2[m]) if i == j-1: - A[l.index(Set([j-1, k])), m] = 1 + A[n2.index(Set([j-1, k])), m] = 1 elif i == j and not j == k-1: - A[l.index(Set([j+1, k])), m] = q**(-1) - A[l.index(Set([j, k])), m] = 1-q**(-1) - A[l.index(Set([j, j+1])), m] = t**(-1)*q**(-1)-t**(-1)*q**(-2) + A[n2.index(Set([j+1, k])), m] = q**(-1) + A[n2.index(Set([j, k])), m] = 1-q**(-1) + A[n2.index(Set([j, j+1])), m] = t**(-1)*q**(-1)-t**(-1)*q**(-2) elif k-1 == i and not k-1 == j: - A[l.index(Set([j, k-1])), m] = 1 + A[n2.index(Set([j, k-1])), m] = 1 elif i == k: - A[l.index(Set([j, k+1])), m] = q**(-1) - A[l.index(Set([j, k])), m] = 1-q**(-1) - A[l.index(Set([k, k+1])), m] = -q**(-1)+q**(-2) + A[n2.index(Set([j, k+1])), m] = q**(-1) + A[n2.index(Set([j, k])), m] = 1-q**(-1) + A[n2.index(Set([k, k+1])), m] = -q**(-1)+q**(-2) elif i == j and j == k-1: - A[l.index(Set([j, k])), m] = -t**(-1)*q**(-2) + A[n2.index(Set([j, k])), m] = -t**(-1)*q**(-2) else: - A[l.index(Set([j, k])), m] = 1 + A[n2.index(Set([j, k])), m] = 1 return A def dimension_of_TL_space(self, drain_size): @@ -2773,11 +2993,11 @@ def dimension_of_TL_space(self, drain_size): The direct sum of endomorphism spaces of these vector spaces make up the entire Temperley--Lieb algebra:: - sage: import sage.combinat.diagram_algebras as da + sage: import sage.combinat.diagram_algebras as da # needs sage.combinat sage: B = BraidGroup(6) sage: dimensions = [B.dimension_of_TL_space(d)**2 for d in [0, 2, 4, 6]] sage: total_dim = sum(dimensions) - sage: total_dim == len(list(da.temperley_lieb_diagrams(6))) # long time + sage: total_dim == len(list(da.temperley_lieb_diagrams(6))) # long time, needs sage.combinat True """ n = self.strands() @@ -3156,7 +3376,7 @@ def _element_from_libbraiding(self, nf): sage: B = BraidGroup(5) sage: B._element_from_libbraiding([[-2], [2, 1], [1, 2], [2, 1]]) - (s0^-1*s1^-1*s2^-1*s3^-1*s0^-1*s1^-1*s2^-1*s0^-1*s1^-1*s0^-1)^2*s1*s0^2*s1^2*s0 + (s0^-1*s1^-1*s0^-1*s2^-1*s1^-1*s0^-1*s3^-1*s2^-1*s1^-1*s0^-1)^2*s1*s0^2*s1^2*s0 sage: B._element_from_libbraiding([[0]]) 1 """ @@ -3189,6 +3409,96 @@ def mirror_involution(self): gens_mirr = [~g for g in self.gens()] return self.hom(gens_mirr, check=False) + def presentation_two_generators(self, isomorphisms=False): + r""" + Construct a finitely presented group isomorphic to ``self`` with only two generators. + + INPUT: + + - ``isomorphism`` -- boolean (default ``False``); if ``True``, then an isomorphism + from ``self`` and the isomorphic group and its inverse is also returned + + EXAMPLES:: + + sage: B = BraidGroup(3) + sage: B.presentation_two_generators() + Finitely presented group < x0, x1 | x1^3*x0^-2 > + sage: B = BraidGroup(4) + sage: G, hom1, hom2 = B.presentation_two_generators(isomorphisms=True) + sage: G + Finitely presented group < x0, x1 | x1^4*x0^-3, x0*x1*x0*x1^-2*x0^-1*x1^3*x0^-1*x1^-2 > + sage: hom1(B.gen(0)) + x0*x1^-1 + sage: hom1(B.gen(1)) + x1*x0*x1^-2 + sage: hom1(B.gen(2)) + x1^2*x0*x1^-3 + sage: all(hom2(hom1(a)) == a for a in B.gens()) + True + sage: all(hom2(a) == B.one() for a in G.relations()) + True + """ + n = self.strands() + F = FreeGroup(2, "x") + rel = [n * (2,) + (n - 1) * (-1,)] + rel += [(1,) + (j - 1) * (2,) + (1,) + j * (-2,) + (-1,) + (j + 1) * (2,) + (-1,) + j * (-2,) + for j in range(2, n - 1)] + G = F / rel + if not isomorphisms: + return G + a1 = (1, -2) + L1 = [j * (2,) + a1 + j * (-2,) for j in range(n - 1)] + h1 = self.hom(codomain=G, im_gens=[G(a) for a in L1], check=False) + a2 = tuple(range(1, n)) + L2 = [(1,) + a2, a2] + h2 = G.hom(codomain=self, im_gens=[self(a) for a in L2], check=False) + return (G, h1, h2) + + def epimorphisms(self, H): + r""" + Return the epimorphisms from ``self`` to ``H``, up to automorphism of `H` passing + through the :meth:`two generator presentation + <presentation_two_generators>` of ``self``. + + INPUT: + + - `H` -- another group + + EXAMPLES:: + + sage: B = BraidGroup(5) + sage: B.epimorphisms(SymmetricGroup(5)) + [Generic morphism: + From: Braid group on 5 strands + To: Symmetric group of order 5! as a permutation group + Defn: s0 |--> (1,5) + s1 |--> (4,5) + s2 |--> (3,4) + s3 |--> (2,3)] + + ALGORITHM: + + Uses libgap's GQuotients function. + """ + G, hom1, hom2 = self.presentation_two_generators(isomorphisms=True) + from sage.misc.misc_c import prod + HomSpace = self.Hom(H) + G0g = libgap(self) + Gg = libgap(G) + Hg = libgap(H) + gquotients = Gg.GQuotients(Hg) + hom1g = libgap.GroupHomomorphismByImagesNC(G0g, Gg, [libgap(hom1(u)) for u in self.gens()]) + g0quotients = [hom1g * h for h in gquotients] + res = [] + # the following closure is needed to attach a specific value of quo to + # each function in the different morphisms + fmap = lambda tup: (lambda a: H(prod(tup[abs(i)-1]**sign(i) for i in a.Tietze()))) + for quo in g0quotients: + tup = tuple(H(quo.ImageElm(i.gap()).sage()) for i in self.gens()) + fhom = GroupMorphismWithGensImages(HomSpace, fmap(tup)) + res.append(fhom) + return res + def BraidGroup(n=None, names='s'): """ @@ -3233,14 +3543,14 @@ def BraidGroup(n=None, names='s'): ....: ret.add(prod(w)) ....: return ret sage: B = BraidGroup(4) - sage: GB = B.cayley_graph(elements=ball(B, 4), generators=B.gens()); GB + sage: GB = B.cayley_graph(elements=ball(B, 4), generators=B.gens()); GB # needs sage.combinat sage.graphs Digraph on 31 vertices Since the braid group has nontrivial relations, this graph contains less vertices than the one associated to the free group (which is a tree):: sage: F = FreeGroup(3) - sage: GF = F.cayley_graph(elements=ball(F, 4), generators=F.gens()); GF + sage: GF = F.cayley_graph(elements=ball(F, 4), generators=F.gens()); GF # needs sage.combinat sage.graphs Digraph on 40 vertices TESTS:: diff --git a/src/sage/groups/cactus_group.py b/src/sage/groups/cactus_group.py index 9a481cc783c..a12fbb88563 100644 --- a/src/sage/groups/cactus_group.py +++ b/src/sage/groups/cactus_group.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.number_field r""" Cactus Groups @@ -970,7 +971,7 @@ def gens(self): sage: gen == b True """ - from sage.functions.other import factorial + from sage.arith.misc import factorial J = self.ambient() G = J.gens() one = J.one() diff --git a/src/sage/groups/class_function.py b/src/sage/groups/class_function.py index 56be7eedb29..c788a596809 100644 --- a/src/sage/groups/class_function.py +++ b/src/sage/groups/class_function.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.number_field r""" Class functions of groups. @@ -27,10 +28,12 @@ from sage.structure.richcmp import richcmp, richcmp_method from sage.interfaces.gap import gap from sage.rings.integer import Integer -from sage.rings.all import CyclotomicField from sage.libs.gap.element import GapElement from sage.libs.gap.libgap import libgap from sage.libs.gap.element import GapElement as LibGapElement +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.rings.number_field.number_field', 'CyclotomicField') # TODO: # @@ -74,7 +77,6 @@ class function on the conjugacy classes, in that order. return ClassFunction_gap(group, values) - ##################################################################### ### ### GAP Interface-based Class Function @@ -245,7 +247,6 @@ def __reduce__(self): """ return ClassFunction_gap, (self._group, self.values()) - def domain(self): r""" Returns the domain of the self. @@ -261,7 +262,6 @@ def domain(self): """ return self._group - def __call__(self, g): """ Evaluate the character on the group element `g`. @@ -292,7 +292,6 @@ def __call__(self, g): """ return self._base_ring(gap(g)._operation("^", self._gap_classfunction)) - def __add__(self, other): r""" Returns the sum of the characters self and other. @@ -320,7 +319,6 @@ def __add__(self, other): s = self._gap_classfunction + other._gap_classfunction return ClassFunction(self._group, s) - def __sub__(self, other): r""" Returns the difference of the characters ``self`` and ``other``. @@ -350,7 +348,6 @@ def __sub__(self, other): s = self._gap_classfunction - other._gap_classfunction return ClassFunction(self._group, s) - def __mul__(self, other): r""" Return the product of the character with ``other``. @@ -400,7 +397,6 @@ def __mul__(self, other): else: return ClassFunction(self._group, other * self._gap_classfunction) - def __rmul__(self, other): r""" Return the reverse multiplication of ``self`` and ``other``. @@ -438,7 +434,6 @@ def __pos__(self): """ return ClassFunction(self._group, self._gap_classfunction) - def __neg__(self): r""" Return the additive inverse of ``self``. @@ -459,7 +454,6 @@ def __neg__(self): """ return ClassFunction(self._group, -self._gap_classfunction) - def __pow__(self, other): r""" Returns the product of self with itself other times. @@ -477,7 +471,6 @@ def __pow__(self, other): raise NotImplementedError return ClassFunction(self._group, self._gap_classfunction ** other) - def symmetric_power(self, n): r""" Returns the symmetrized product of self with itself ``n`` times. @@ -504,7 +497,6 @@ def symmetric_power(self, n): tbl = gap.UnderlyingCharacterTable(self) return ClassFunction(self._group, gap.SymmetricParts(tbl,[self],n)[1]) - def exterior_power(self, n): r""" Returns the anti-symmetrized product of self with itself ``n`` times. @@ -533,7 +525,6 @@ def exterior_power(self, n): tbl = gap.UnderlyingCharacterTable(self) return ClassFunction(self._group, gap.AntiSymmetricParts(tbl,[self],n)[1]) - def scalar_product(self, other): r""" Returns the scalar product of self with other. @@ -551,7 +542,6 @@ def scalar_product(self, other): """ return self._gap_classfunction.ScalarProduct(other) - def is_irreducible(self): r""" Returns True if self cannot be written as the sum of two nonzero @@ -566,7 +556,6 @@ def is_irreducible(self): """ return bool(self._gap_classfunction.IsIrreducible()) - def degree(self): r""" Returns the degree of the character self. @@ -580,7 +569,6 @@ def degree(self): """ return Integer(self._gap_classfunction.DegreeOfCharacter()) - def irreducible_constituents(self): r""" Returns a list of the characters that appear in the decomposition @@ -615,7 +603,6 @@ def irreducible_constituents(self): L = self._gap_classfunction.ConstituentsOfCharacter() return tuple(ClassFunction(self._group, list(l)) for l in L) - def decompose(self): r""" Returns a list of the characters that appear in the decomposition @@ -634,7 +621,6 @@ def decompose(self): L.append((self.scalar_product(irr), irr)) return tuple(L) - def norm(self): r""" Returns the norm of self. @@ -647,7 +633,6 @@ def norm(self): """ return self._gap_classfunction.Norm() - def values(self): r""" Return the list of values of self on the conjugacy classes. @@ -676,7 +661,6 @@ def values(self): """ return list(self) - def central_character(self): r""" Returns the central character of self. @@ -689,7 +673,6 @@ def central_character(self): """ return ClassFunction(self._group, self._gap_classfunction.CentralCharacter()) - def determinant_character(self): r""" Returns the determinant character of self. @@ -702,7 +685,6 @@ def determinant_character(self): """ return ClassFunction(self._group, self._gap_classfunction.DeterminantOfCharacter()) - def tensor_product(self, other): r""" EXAMPLES:: @@ -714,7 +696,6 @@ def tensor_product(self, other): """ return ClassFunction(self._group, gap.Tensored([self],[other])[1]) - def restrict(self, H): r""" Return the restricted character. @@ -734,14 +715,14 @@ def restrict(self, H): Character of Symmetric group of order 5! as a permutation group sage: H = G.subgroup([(1,2,3), (1,2), (4,5)]) sage: chi.restrict(H) - Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of (Symmetric group of order 5! as a permutation group) + Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of + (Symmetric group of order 5! as a permutation group) sage: chi.restrict(H).values() [3, -3, -3, -1, 0, 0] """ rest = self._gap_classfunction.RestrictedClassFunction(H._gap_()) return ClassFunction(H, rest) - def induct(self, G): r""" Return the induced character. @@ -761,7 +742,8 @@ def induct(self, G): sage: G = SymmetricGroup(5) sage: H = G.subgroup([(1,2,3), (1,2), (4,5)]) sage: xi = H.trivial_character(); xi - Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of (Symmetric group of order 5! as a permutation group) + Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of + (Symmetric group of order 5! as a permutation group) sage: xi.induct(G) Character of Symmetric group of order 5! as a permutation group sage: xi.induct(G).values() @@ -770,7 +752,6 @@ def induct(self, G): rest = self._gap_classfunction.InducedClassFunction(G._gap_()) return ClassFunction(G, rest) - def adams_operation(self, k): r""" Return the ``k``-th Adams operation on ``self``. @@ -809,10 +790,6 @@ def adams_operation(self, k): return ClassFunction(self._group, [self(x**k) for x in reprs]) - - - - ##################################################################### ### ### Class function using the GAP library @@ -862,7 +839,6 @@ def __init__(self, G, values): e = self._gap_classfunction.Conductor().sage() self._base_ring = CyclotomicField(e) - def gap(self): r""" Return the underlying LibGAP element. @@ -884,7 +860,6 @@ def gap(self): _libgap_ = _gap_ = gap - def _repr_(self): r""" Return a string representation. @@ -902,7 +877,6 @@ def _repr_(self): """ return "Character of %s" % repr(self._group) - def __iter__(self): r""" Iterate through the values. @@ -966,7 +940,6 @@ def __reduce__(self): """ return ClassFunction_libgap, (self._group, self.values()) - def domain(self): r""" Return the domain of ``self``. @@ -982,7 +955,6 @@ def domain(self): """ return self._group - def __call__(self, g): """ Evaluate the character on the group element `g`. @@ -1015,7 +987,6 @@ def __call__(self, g): value = g.gap() ** self.gap() return value.sage(self._base_ring) - def __add__(self, other): r""" Return the sum of the characters ``self`` and ``other``. @@ -1043,7 +1014,6 @@ def __add__(self, other): s = self._gap_classfunction + other._gap_classfunction return ClassFunction(self._group, s) - def __sub__(self, other): r""" Return the difference of the characters ``self`` and ``other``. @@ -1073,7 +1043,6 @@ def __sub__(self, other): s = self._gap_classfunction - other._gap_classfunction return ClassFunction(self._group, s) - def __mul__(self, other): r""" Return the product of the character with ``other``. @@ -1123,7 +1092,6 @@ def __mul__(self, other): else: return ClassFunction(self._group, other * self._gap_classfunction) - def __rmul__(self, other): r""" Return the reverse multiplication of ``self`` and ``other``. @@ -1141,7 +1109,6 @@ def __rmul__(self, other): """ return self.__mul__(other) - def __pos__(self): r""" Return ``self``. @@ -1162,7 +1129,6 @@ def __pos__(self): """ return ClassFunction(self._group, self._gap_classfunction) - def __neg__(self): r""" Return the additive inverse of ``self``. @@ -1183,7 +1149,6 @@ def __neg__(self): """ return ClassFunction(self._group, -self._gap_classfunction) - def __pow__(self, other): r""" Return the product of ``self`` with itself ``other`` times. @@ -1201,7 +1166,6 @@ def __pow__(self, other): raise NotImplementedError return ClassFunction(self._group, self._gap_classfunction ** other) - def symmetric_power(self, n): r""" Return the symmetrized product of ``self`` with itself ``n`` times. @@ -1228,7 +1192,6 @@ def symmetric_power(self, n): tbl = self._gap_classfunction.UnderlyingCharacterTable(self) return ClassFunction(self._group, tbl.SymmetricParts([self],n)[1]) - def exterior_power(self, n): r""" Return the anti-symmetrized product of ``self`` with itself ``n`` times. @@ -1257,7 +1220,6 @@ def exterior_power(self, n): tbl = self._gap_classfunction.UnderlyingCharacterTable(self) return ClassFunction(self._group, tbl.AntiSymmetricParts([self],n)[1]) - def scalar_product(self, other): r""" Return the scalar product of ``self`` with ``other``. @@ -1275,7 +1237,6 @@ def scalar_product(self, other): """ return self._gap_classfunction.ScalarProduct(other).sage() - def is_irreducible(self): r""" Return ``True`` if ``self`` cannot be written as the sum of two nonzero @@ -1290,7 +1251,6 @@ def is_irreducible(self): """ return self._gap_classfunction.IsIrreducible().sage() - def degree(self): r""" Return the degree of the character ``self``. @@ -1304,7 +1264,6 @@ def degree(self): """ return self._gap_classfunction.DegreeOfCharacter().sage() - def irreducible_constituents(self): r""" Return a list of the characters that appear in the decomposition @@ -1340,7 +1299,6 @@ def irreducible_constituents(self): L = self._gap_classfunction.ConstituentsOfCharacter() return tuple(ClassFunction_libgap(self._group, l) for l in L) - def decompose(self): r""" Return a list of the characters that appear in the decomposition @@ -1359,7 +1317,6 @@ def decompose(self): L.append((self.scalar_product(irr), irr)) return tuple(L) - def norm(self): r""" Return the norm of ``self``. @@ -1372,7 +1329,6 @@ def norm(self): """ return self._gap_classfunction.Norm().sage() - def values(self): r""" Return the list of values of self on the conjugacy classes. @@ -1380,7 +1336,7 @@ def values(self): EXAMPLES:: sage: G = GL(2,3) - sage: [x.values() for x in G.irreducible_characters()] #random + sage: [x.values() for x in G.irreducible_characters()] # random [[1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, -1, -1, -1], [2, -1, 2, -1, 2, 0, 0, 0], @@ -1401,7 +1357,6 @@ def values(self): """ return list(self) - def central_character(self): r""" Return the central character of ``self``. @@ -1414,7 +1369,6 @@ def central_character(self): """ return ClassFunction(self._group, self._gap_classfunction.CentralCharacter()) - def determinant_character(self): r""" Return the determinant character of ``self``. @@ -1427,7 +1381,6 @@ def determinant_character(self): """ return ClassFunction(self._group, self._gap_classfunction.DeterminantOfCharacter()) - def tensor_product(self, other): r""" Return the tensor product of ``self`` and ``other``. @@ -1442,7 +1395,6 @@ def tensor_product(self, other): product = libgap.Tensored([self], [other]) return ClassFunction(self._group, product[0]) - def restrict(self, H): r""" Return the restricted character. @@ -1462,7 +1414,8 @@ def restrict(self, H): Character of Symmetric group of order 5! as a permutation group sage: H = G.subgroup([(1,2,3), (1,2), (4,5)]) sage: chi.restrict(H) - Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of (Symmetric group of order 5! as a permutation group) + Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of + (Symmetric group of order 5! as a permutation group) sage: chi.restrict(H).values() [3, -3, -3, -1, 0, 0] """ @@ -1474,7 +1427,6 @@ def restrict(self, H): rest = self._gap_classfunction.RestrictedClassFunction(gapH) return ClassFunction(H, rest) - def induct(self, G): r""" Return the induced character. @@ -1494,7 +1446,8 @@ def induct(self, G): sage: G = SymmetricGroup(5) sage: H = G.subgroup([(1,2,3), (1,2), (4,5)]) sage: xi = H.trivial_character(); xi - Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of (Symmetric group of order 5! as a permutation group) + Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of + (Symmetric group of order 5! as a permutation group) sage: xi.induct(G) Character of Symmetric group of order 5! as a permutation group sage: xi.induct(G).values() @@ -1508,7 +1461,6 @@ def induct(self, G): ind = self._gap_classfunction.InducedClassFunction(gapG) return ClassFunction(G, ind) - def adams_operation(self, k): r""" Return the ``k``-th Adams operation on ``self``. diff --git a/src/sage/groups/conjugacy_classes.py b/src/sage/groups/conjugacy_classes.py index fd79d60ee5b..4ad8200ef23 100644 --- a/src/sage/groups/conjugacy_classes.py +++ b/src/sage/groups/conjugacy_classes.py @@ -24,7 +24,7 @@ sage: G = SymmetricGroup(4) sage: g = G((1,2,3,4)) - sage: G.conjugacy_class(g) + sage: G.conjugacy_class(g) # needs sage.combinat Conjugacy class of cycle type [4] in Symmetric group of order 4! as a permutation group Conjugacy classes for groups of matrices:: @@ -90,7 +90,7 @@ def __init__(self, group, element): sage: ConjugacyClass(G,g) Conjugacy class of (1,2,3,4) in Symmetric group of order 4! as a permutation group - sage: TestSuite(G).run() + sage: TestSuite(G).run() # needs sage.rings.number_field """ self._parent = group self._representative = element @@ -432,6 +432,7 @@ def cardinality(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: W = WeylGroup(['C',6]) sage: cc = W.conjugacy_class(W.an_element()) sage: cc.cardinality() @@ -449,6 +450,7 @@ def __contains__(self, g): TESTS:: + sage: # needs sage.rings.number_field sage: W = WeylGroup(['C',6]) sage: g0,g1,g2,g3,g4,g5 = W.gens() sage: cc = W.conjugacy_class(g0) diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index a9465ef2b3d..e8cb4a4e19f 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -80,19 +80,22 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from enum import Enum + +import sage.rings.abc + from sage.categories.groups import Groups from sage.categories.shephard_groups import ShephardGroups -from sage.misc.cachefunc import cached_method -from sage.libs.gap.element import GapElement from sage.groups.free_group import FreeGroup from sage.groups.finitely_presented import FinitelyPresentedGroup, FinitelyPresentedGroupElement from sage.groups.braid import BraidGroup +from sage.misc.cachefunc import cached_method from sage.rings.integer import Integer -from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField -from sage.rings.number_field.number_field import CyclotomicField -from sage.rings.finite_rings.finite_field_constructor import GF -from enum import Enum +try: + from sage.libs.gap.element import GapElement +except ImportError: + GapElement = () ############################################################################## @@ -155,7 +158,6 @@ def eliminate_item(tietze_list): return tietze_list - ############################################################################## # # Functions to create Instances of the CubicBraidGroup @@ -387,13 +389,15 @@ def burau_matrix(self, root_bur=None, domain=None, characteristic=None, sage: C3.<c1, c2> = CubicBraidGroup(3) sage: ele = c1*c2*c1 + + sage: # needs sage.rings.number_field sage: BuMa = ele.burau_matrix(); BuMa [ -zeta3 1 zeta3] [ -zeta3 zeta3 + 1 0] [ 1 0 0] sage: BuMa.base_ring() Cyclotomic Field of order 3 and degree 2 - sage: BuMa == ele.burau_matrix(characteristic = 0) + sage: BuMa == ele.burau_matrix(characteristic=0) True sage: BuMa = ele.burau_matrix(domain=QQ); BuMa [-t + 1 1 t - 1] @@ -401,18 +405,21 @@ def burau_matrix(self, root_bur=None, domain=None, characteristic=None, [ 1 0 0] sage: BuMa.base_ring() Number Field in t with defining polynomial t^2 - t + 1 - sage: BuMa = ele.burau_matrix(domain = QQ[I, sqrt(3)]); BuMa + sage: BuMa = ele.burau_matrix(domain = QQ[I, sqrt(3)]); BuMa # needs sage.symbolic [ 1/2*sqrt3*I + 1/2 1 -1/2*sqrt3*I - 1/2] [ 1/2*sqrt3*I + 1/2 -1/2*sqrt3*I + 1/2 0] [ 1 0 0] - sage: BuMa.base_ring() + sage: BuMa.base_ring() # needs sage.symbolic Number Field in I with defining polynomial x^2 + 1 over its base field + sage: BuMa = ele.burau_matrix(characteristic=7); BuMa [3 1 4] [3 5 0] [1 0 0] sage: BuMa.base_ring() Finite Field of size 7 + + sage: # needs sage.rings.finite_rings sage: BuMa = ele.burau_matrix(characteristic=2); BuMa [t + 1 1 t + 1] [t + 1 t 0] @@ -432,6 +439,8 @@ def burau_matrix(self, root_bur=None, domain=None, characteristic=None, [ 1 0 0] sage: BuMa.base_ring() Finite Field in t of size 5^2 + + sage: # needs sage.rings.number_field sage: BuMa, BuMaAd, H = ele.burau_matrix(reduced='unitary'); BuMa [ 0 zeta12^3] [zeta12^3 0] @@ -439,10 +448,11 @@ def burau_matrix(self, root_bur=None, domain=None, characteristic=None, True sage: BuMa.base_ring() Cyclotomic Field of order 12 and degree 4 - sage: BuMa, BuMaAd, H = ele.burau_matrix(domain = QQ[I, sqrt(3)], reduced='unitary'); BuMa + sage: BuMa, BuMaAd, H = ele.burau_matrix(domain=QQ[I, sqrt(3)], # needs sage.symbolic + ....: reduced='unitary'); BuMa [0 I] [I 0] - sage: BuMa.base_ring() + sage: BuMa.base_ring() # needs sage.symbolic Number Field in I with defining polynomial x^2 + 1 over its base field """ braid = self.braid() @@ -461,8 +471,8 @@ def burau_matrix(self, root_bur=None, domain=None, characteristic=None, burau_ori, burau_ori_adj, herm_form_ori = burau_ori if domain is not None: - if isinstance(domain, UniversalCyclotomicField): - if root_bur is None: + if isinstance(domain, sage.rings.abc.UniversalCyclotomicField): + if root_bur is None: if unitary: root_bur = domain.gen(12) else: @@ -484,7 +494,6 @@ def find_root(domain): break return root_bur - if domain is None: if characteristic is None: # -------------------------------------------------------------------- @@ -503,14 +512,16 @@ def find_root(domain): except ValueError: raise ValueError('characteristic must be in integer') - if not characteristic.is_zero() and not characteristic.is_prime(): + if not characteristic.is_zero() and not characteristic.is_prime(): raise ValueError('characteristic must be a prime') if characteristic.is_zero(): + from sage.rings.number_field.number_field import CyclotomicField if unitary: domain = CyclotomicField(12) else: domain = CyclotomicField(3) else: + from sage.rings.finite_rings.finite_field_constructor import GF domain = GF(characteristic) root_bur = find_root(domain) domain = root_bur.parent() @@ -549,7 +560,6 @@ def conv2domain(laur_pol): return burau_mat - ############################################################################## # # Class CubicBraidGroup @@ -631,13 +641,15 @@ class CubicBraidGroup(FinitelyPresentedGroup): #I Forcing finiteness test True sage: U3.as_classical_group() - Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] + Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), + (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] of (The projective general unitary group of degree 3 over Finite Field of size 2) sage: C3.as_classical_group() Subgroup with 2 generators ( [ E(3)^2 0] [ 1 -E(12)^7] [-E(12)^7 1], [ 0 E(3)^2] - ) of General Unitary Group of degree 2 over Universal Cyclotomic Field with respect to positive definite hermitian form + ) of General Unitary Group of degree 2 over Universal Cyclotomic Field + with respect to positive definite hermitian form [-E(12)^7 + E(12)^11 -1] [ -1 -E(12)^7 + E(12)^11] @@ -674,7 +686,6 @@ class type(Enum): AssionS = 'S' AssionU = 'U' - ########################################################################################### # private methods ########################################################################################### @@ -793,7 +804,6 @@ def __init__(self, names, cbg_type=None): self._centralizing_element = None # image under nat. map of the former one in the proj. classical group return - def _repr_(self): r""" Return a string representation. @@ -810,9 +820,9 @@ def _repr_(self): Assion group on 2 strands of type U """ if self._cbg_type == CubicBraidGroup.type.Coxeter: - return "Cubic Braid group on %s strands"%(self.strands()) + return "Cubic Braid group on %s strands" % (self.strands()) else: - return "Assion group on %s strands of type %s"%(self.strands() ,self._cbg_type.value) + return "Assion group on %s strands of type %s" % (self.strands() ,self._cbg_type.value) def index_set(self): r""" @@ -906,7 +916,7 @@ def _internal_test_attached_group(self, attached_group, tester): elem = self.an_element() att_grp_elem = attached_group(elem) if self.is_finite() and self.strands() <= 7: # not realistic for larger number of strands - att_grp_elem_back= self(att_grp_elem) + att_grp_elem_back = self(att_grp_elem) tester.assertEqual(att_grp_elem_back, elem) return @@ -968,12 +978,19 @@ def _test_matrix_group(self, **options): sage: CBG2._test_matrix_group() """ tester = self._tester(**options) + + MatDEF = self.as_matrix_group() + self._internal_test_attached_group(MatDEF, tester) + + try: + from sage.rings.finite_rings.finite_field_constructor import GF + except ImportError: + return + F3 = GF(3) r63 = F3(2) F4 = GF(4) r64 = F4.gen() - MatDEF = self.as_matrix_group() - self._internal_test_attached_group(MatDEF, tester) if self._cbg_type != CubicBraidGroup.type.AssionU or self.strands() < 5: # not well defined else-wise matrix_grpF3 = self.as_matrix_group(root_bur=r63) @@ -991,7 +1008,6 @@ def _test_matrix_group(self, **options): self._internal_test_attached_group(matrix_grpF7, tester) return - def _test_reflection_group(self, **options): r""" Check the reflection group properties. @@ -1007,7 +1023,7 @@ def _test_reflection_group(self, **options): sage: CBG2 = CubicBraidGroup(2) sage: CBG2._test_reflection_group() """ - if self._cbg_type == CubicBraidGroup.type.Coxeter and self.is_finite() and self.strands() > 2: + if self._cbg_type == CubicBraidGroup.type.Coxeter and self.is_finite() and self.strands() > 2: from sage.combinat.root_system.reflection_group_real import is_chevie_available if is_chevie_available(): tester = self._tester(**options) @@ -1015,7 +1031,6 @@ def _test_reflection_group(self, **options): self._internal_test_attached_group(reflgrp, tester) return - # ------------------------------------------------------------------------------- # ------------------------------------------------------------------------------- # local utility-methods @@ -1168,14 +1183,14 @@ def create_sympl_realization(self, m): # computing a hyperbolic decomposition basis with respect # to the invariant bilinear form. # ----------------------------------------------------------- - xbas =[bas[mhalf -i -1] for i in range(mhalf)] - ybas =[bas[mhalf +i] for i in range(mhalf)] + xbas = [bas[mhalf - i - 1] for i in range(mhalf)] + ybas = [bas[mhalf + i] for i in range(mhalf)] # ----------------------------------------------------------- # computing the List of transvection vectors according to # the Assion paper, page 292. # ----------------------------------------------------------- - transvections =[xbas[0]] # t_1 = x_1 + transvections = [xbas[0]] # t_1 = x_1 for i in range(mhalf-1): transvections.append(ybas[i]) # t_{2i} = y_i transvections.append(xbas[i] + xbas[i+1]) # t_{2i+1} = x_j + x_(j+1) @@ -1241,26 +1256,26 @@ def create_unitary_realization(self, m): # computing a orthonormal basis with respect # to the invariant bilinear form. # ----------------------------------------------------------- - xbas =[] + xbas = [] for i in range(m): if 2*i == m-1: xbas.append(bas[i]) else: - xbas.append(a*bas[i] + a.frobenius()*bas[m-1 -i]) + xbas.append(a*bas[i] + a.frobenius()*bas[m-1 - i]) # ----------------------------------------------------------- # computing the List of transvection vectors according to # Assion paper, page 293. # ----------------------------------------------------------- - transvections =[xbas[0]] # t_1 = x_1 + transvections = [xbas[0]] # t_1 = x_1 if m > 1: transvections.append(xbas[0]+xbas[1]+xbas[2]) # t_2 = x_1 + x_2 + x_3 for j in range(mthird): pos = 3*(j+1)-1 transvections.append(xbas[pos-1]) # t_{3i} = x_{3i-1} - if pos +1 < m: + if pos + 1 < m: transvections.append(xbas[pos-1]+xbas[pos]+xbas[pos+1]) # t_{3i+1} = x_{3i-1} + x_{3i} + x_{3i+1} - if pos +3 < m: + if pos + 3 < m: transvections.append(xbas[pos+1]+xbas[pos+2]+xbas[pos+3]) # t_{3i+2} = x_{3i+1} + x_{3i+2} + x_{3i+3} # ----------------------------------------------------------- @@ -1271,7 +1286,7 @@ def create_unitary_realization(self, m): def transvec2mat(v, bas=bas, bform=bform, fact=a): # note x does not change under conjugation, since it belongs to standard basis - t = [x + fact *(x * bform * v.conjugate()) * v for x in bas] + t = [x + fact * (x * bform * v.conjugate()) * v for x in bas] return matrix(F, t) # ------------------------------------------------------------------------------ @@ -1324,6 +1339,8 @@ def transvec2mat(v, bas=bas, bform=bform, fact=a): # now 1 + 2*cos(\pi/6)*i\theta = 1 + sqrt(3)*(-sqrt(3)/2 + I/2) = 1- 3/2 + sqrt(3)I/2 = z12^4 = - ~z12^2 # finally: Coxeter's Realization is the unitary Burau representation of Squier for s = ~z12 # ----------------------------------------------------------------------------------------------- + from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + UCF = UniversalCyclotomicField() z12 = UCF.gen(12) classical_group = self.as_matrix_group(root_bur=~z12, domain=UCF, reduced='unitary') @@ -1400,7 +1417,6 @@ def strands(self): """ return self._nstrands - # ---------------------------------------------------------------------------------- # braid_group # ---------------------------------------------------------------------------------- @@ -1445,7 +1461,6 @@ def braid_group(self): """ return self._braid_group - # ---------------------------------------------------------------------------------- # as_matrix_group # ---------------------------------------------------------------------------------- @@ -1473,6 +1488,7 @@ def as_matrix_group(self, root_bur=None, domain=None, characteristic=None, var=' EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: C5 = CubicBraidGroup(5) sage: C5Mch5 = C5.as_matrix_group(characteristic=5); C5Mch5 Matrix group over Finite Field in t of size 5^2 with 4 generators ( @@ -1543,10 +1559,10 @@ def as_matrix_group(self, root_bur=None, domain=None, characteristic=None, var=' self._classical_invariant_form = herm_form if unitary: - from sage.rings.finite_rings.finite_field_base import is_FiniteField + from sage.rings.finite_rings.finite_field_base import FiniteField from sage.groups.matrix_gps.unitary import GU d, d = herm_form.dimensions() - if is_FiniteField(domain): + if isinstance(domain, FiniteField): base_group = GU(d, domain, var=domain.gen(), invariant_form=herm_form) else: base_group = GU(d, domain, invariant_form=herm_form) @@ -1568,7 +1584,6 @@ def as_matrix_group(self, root_bur=None, domain=None, characteristic=None, var=' matrix_group.register_conversion(hom_to_mat) return matrix_group - # ---------------------------------------------------------------------------------- # Although this method is available for finitely presented group # we use the classical group implementation (by performance reason) to get @@ -1651,10 +1666,12 @@ def as_classical_group(self, embedded=False): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: U3 = AssionGroupU(3) sage: U3Cl = U3.as_classical_group(); U3Cl - Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] - of (The projective general unitary group of degree 3 over Finite Field of size 2) + Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), + (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] of + (The projective general unitary group of degree 3 over Finite Field of size 2) sage: U3Clemb = U3.as_classical_group(embedded=True); U3Clemb Subgroup with 2 generators ( [0 0 a] [a + 1 a a] @@ -1678,6 +1695,8 @@ def as_classical_group(self, embedded=False): General Unitary Group of degree 3 over Finite Field in a of size 2^2 sage: U3Clemb.ambient() == U4Cl True + + sage: # needs sage.rings.number_field sage: C4 = CubicBraidGroup(4) sage: C4Cl = C4.as_classical_group(); C4Cl Subgroup with 3 generators ( @@ -1688,7 +1707,8 @@ def as_classical_group(self, embedded=False): [ 1 0 0] [ 0 1 -E(12)^7] [ 0 0 E(3)^2] - ) of General Unitary Group of degree 3 over Universal Cyclotomic Field with respect to positive definite hermitian form + ) of General Unitary Group of degree 3 over Universal Cyclotomic Field + with respect to positive definite hermitian form [-E(12)^7 + E(12)^11 -1 0] [ -1 -E(12)^7 + E(12)^11 -1] [ 0 -1 -E(12)^7 + E(12)^11] @@ -1717,7 +1737,6 @@ def as_classical_group(self, embedded=False): raise ValueError("no classical embedding defined") - # ---------------------------------------------------------------------------------- # as_refection_group # ---------------------------------------------------------------------------------- @@ -1737,27 +1756,29 @@ def as_reflection_group(self): EXAMPLES:: - sage: C3.<c1,c2> = CubicBraidGroup(3) # optional - gap3 - sage: R3 = C3.as_reflection_group(); R3 # optional - gap3 + sage: # optional - gap3 + sage: C3.<c1,c2> = CubicBraidGroup(3) + sage: R3 = C3.as_reflection_group(); R3 Irreducible complex reflection group of rank 2 and type ST4 - sage: R3.cartan_matrix() # optional - gap3 + sage: R3.cartan_matrix() [-2*E(3) - E(3)^2 E(3)^2] [ -E(3)^2 -2*E(3) - E(3)^2] - sage: R3.simple_roots() # optional - gap3 + sage: R3.simple_roots() Finite family {1: (0, -2*E(3) - E(3)^2), 2: (2*E(3)^2, E(3)^2)} - sage: R3.simple_coroots() # optional - gap3 + sage: R3.simple_coroots() Finite family {1: (0, 1), 2: (1/3*E(3) - 1/3*E(3)^2, 1/3*E(3) - 1/3*E(3)^2)} Conversion maps:: - sage: r = R3.an_element() # optional - gap3 - sage: cr = C3(r); cr # optional - gap3 + sage: # optional - gap3 + sage: r = R3.an_element() + sage: cr = C3(r); cr c1*c2 - sage: mr = r.matrix(); mr # optional - gap3 + sage: mr = r.matrix(); mr [ 1/3*E(3) - 1/3*E(3)^2 2/3*E(3) + 1/3*E(3)^2] [-2/3*E(3) + 2/3*E(3)^2 2/3*E(3) + 1/3*E(3)^2] - sage: C3Cl = C3.as_classical_group() # optional - gap3 - sage: C3Cl(cr) # optional - gap3 + sage: C3Cl = C3.as_classical_group() + sage: C3Cl(cr) [ E(3)^2 -E(4)] [-E(12)^7 0] @@ -1767,13 +1788,14 @@ def as_reflection_group(self): the classical group due to different hermitian forms for the unitary groups they live in:: - sage: C4 = CubicBraidGroup(4) # optional - gap3 - sage: R4 = C4.as_reflection_group() # optional - gap3 - sage: R4.invariant_form() # optional - gap3 + sage: # optional - gap3 + sage: C4 = CubicBraidGroup(4) + sage: R4 = C4.as_reflection_group() + sage: R4.invariant_form() [1 0 0] [0 1 0] [0 0 1] - sage: _ == C4.classical_invariant_form() # optional - gap3 + sage: _ == C4.classical_invariant_form() False """ # ------------------------------------------------------------------------------- @@ -1797,8 +1819,8 @@ def as_reflection_group(self): from sage.combinat.root_system.reflection_group_real import ReflectionGroup - if self.strands() == 2: - reflection_group = ReflectionGroup([2 ,1 ,1]) + if self.strands() == 2: + reflection_group = ReflectionGroup([2, 1, 1]) elif self.strands() == 3: reflection_group = ReflectionGroup(4) elif self.strands() == 4: @@ -1810,7 +1832,6 @@ def as_reflection_group(self): reflection_group.register_conversion(hom_to_refl) return reflection_group - # ---------------------------------------------------------------------------------- # classical invariant form returns the invariant form of the classical realization # ---------------------------------------------------------------------------------- @@ -1875,7 +1896,6 @@ def classical_invariant_form(self): return self._classical_invariant_form - # ---------------------------------------------------------------------------------- # centralizing element in the classical symplectic resp. unitary group # ---------------------------------------------------------------------------------- @@ -1908,7 +1928,8 @@ def centralizing_element(self, embedded=False): sage: U3 = AssionGroupU(3); U3 Assion group on 3 strands of type U sage: U3Cl = U3.as_classical_group(); U3Cl - Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] + Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), + (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] of (The projective general unitary group of degree 3 over Finite Field of size 2) sage: c = U3.centralizing_element(); c (1,16)(2,9)(3,10)(4,19)(6,12)(7,20)(13,21)(14,15) @@ -1945,7 +1966,6 @@ def centralizing_element(self, embedded=False): else: return self._centralizing_element - # ---------------------------------------------------------------------------------- # calculating the order by formula # ---------------------------------------------------------------------------------- diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 8d6e443683c..96d03e90c83 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -128,18 +128,22 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.arith.misc import GCD as gcd +from sage.categories.morphism import SetMorphism +from sage.functions.generalized import sign +from sage.groups.free_group import FreeGroup +from sage.groups.free_group import FreeGroupElement from sage.groups.group import Group from sage.groups.libgap_wrapper import ParentLibGAP, ElementLibGAP from sage.groups.libgap_mixin import GroupMixinLibGAP -from sage.structure.unique_representation import UniqueRepresentation -from sage.libs.gap.libgap import libgap from sage.libs.gap.element import GapElement -from sage.misc.cachefunc import cached_method -from sage.groups.free_group import FreeGroupElement -from sage.functions.generalized import sign +from sage.libs.gap.libgap import libgap from sage.matrix.constructor import matrix -from sage.categories.morphism import SetMorphism - +from sage.misc.cachefunc import cached_method +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing +from sage.rings.rational_field import QQ +from sage.sets.set import Set +from sage.structure.unique_representation import UniqueRepresentation class GroupMorphismWithGensImages(SetMorphism): r""" @@ -161,7 +165,6 @@ class GroupMorphismWithGensImages(SetMorphism): Defn: x0 |--> () x1 |--> () x2 |--> () - """ def _repr_defn(self): r""" @@ -177,11 +180,9 @@ def _repr_defn(self): sage: f = GroupMorphismWithGensImages(HS, lambda a: H.one()) sage: f._repr_defn() 'x0 |--> ()\nx1 |--> ()\nx2 |--> ()' - """ - D = self.domain() - return '\n'.join(['%s |--> %s'%(i, self(i)) for\ - i in D.gens()]) + return '\n'.join(f'{i} |--> {self(i)}' for i in self.domain().gens()) + class FinitelyPresentedGroupElement(FreeGroupElement): """ @@ -409,8 +410,8 @@ def wrap_FpGroup(libgap_fpgroup): libgap_fpgroup._set_compare_by_id() from sage.groups.free_group import wrap_FreeGroup free_group = wrap_FreeGroup(libgap_fpgroup.FreeGroupOfFpGroup()) - relations = tuple( free_group(rel.UnderlyingElement()) - for rel in libgap_fpgroup.RelatorsOfFpGroup() ) + relations = tuple(free_group(rel.UnderlyingElement()) + for rel in libgap_fpgroup.RelatorsOfFpGroup()) return FinitelyPresentedGroup(free_group, relations) @@ -511,7 +512,7 @@ def __repr__(self): a^2 ---> 1 """ ret = "Rewriting system of {}\nwith rules:".format(self._fp_group) - for i in sorted(self.rules().items()): # Make sure they are sorted to the repr is unique + for i in sorted(self.rules().items()): # Make sure they are sorted to the repr is unique ret += "\n {} ---> {}".format(i[0], i[1]) return ret @@ -596,9 +597,9 @@ def gap(self): sage: k = G.rewriting_system() sage: k.gap() Knuth Bendix Rewriting System for Monoid( [ a, A, b, B ] ) with rules - [ [ a^2, <identity ...> ], [ a*A, <identity ...> ], - [ A*a, <identity ...> ], [ b^2, <identity ...> ], - [ b*B, <identity ...> ], [ B*b, <identity ...> ] ] + [ [ a*A, <identity ...> ], [ A*a, <identity ...> ], + [ b*B, <identity ...> ], [ B*b, <identity ...> ], + [ a^2, <identity ...> ], [ b^2, <identity ...> ] ] """ return self._gap @@ -644,7 +645,7 @@ def rules(self): bfg = self._monoid_isomorphism.PreImagesRepresentative(bfpmon) btz = bfg.UnderlyingElement().TietzeWordAbstractWord(self._free_group.gap().GeneratorsOfGroup()) bf = self._free_group(btz.sage()) - dic[af]=bf + dic[af] = bf return dic def is_confluent(self): @@ -738,8 +739,7 @@ def make_confluent(self): raise ValueError('could not make the system confluent') -class FinitelyPresentedGroup(GroupMixinLibGAP, UniqueRepresentation, - Group, ParentLibGAP): +class FinitelyPresentedGroup(GroupMixinLibGAP, UniqueRepresentation, Group, ParentLibGAP): """ A class that wraps GAP's Finitely Presented Groups. @@ -826,8 +826,8 @@ def _repr_(self): 'Finitely presented group < a, b | a, b^3 >' """ gens = ', '.join(self.variable_names()) - rels = ', '.join([ str(r) for r in self.relations() ]) - return 'Finitely presented group ' + '< '+ gens + ' | ' + rels + ' >' + rels = ', '.join([str(r) for r in self.relations()]) + return 'Finitely presented group ' + '< ' + gens + ' | ' + rels + ' >' def _latex_(self): """ @@ -1110,14 +1110,14 @@ def direct_product(self, H, reduced=False, new_names=True): fp_product = libgap.DirectProduct([self.gap(), H.gap()]) GAP_gens = fp_product.FreeGeneratorsOfFpGroup() if new_names: - name_itr = _lexi_gen() # Python generator for lexicographical variable names + name_itr = _lexi_gen() # Python generator for lexicographical variable names gen_names = [next(name_itr) for i in GAP_gens] else: - gen_names= [str(g) for g in self.gens()] + [str(g) for g in H.gens()] + gen_names = [str(g) for g in self.gens()] + [str(g) for g in H.gens()] # Build the direct product in Sage for better variable names ret_F = FreeGroup(gen_names) ret_rls = tuple([ret_F(rel_word.TietzeWordAbstractWord(GAP_gens).sage()) - for rel_word in fp_product.RelatorsOfFpGroup()]) + for rel_word in fp_product.RelatorsOfFpGroup()]) ret_fpg = FinitelyPresentedGroup(ret_F, ret_rls) if reduced: ret_fpg = ret_fpg.simplified() @@ -1269,8 +1269,8 @@ def semidirect_product(self, H, hom, check=True, reduced=False): auto_grp = libgap.AutomorphismGroup(H.gap()) self_gens = [h.gap() for h in hom[0]] # construct image automorphisms in GAP - GAP_aut_imgs = [ libgap.GroupHomomorphismByImages(GAP_H, GAP_H, [g.gap() for g in gns], - [i.gap() for i in img]) for (gns, img) in hom[1] ] + GAP_aut_imgs = [libgap.GroupHomomorphismByImages(GAP_H, GAP_H, [g.gap() for g in gns], + [i.gap() for i in img]) for (gns, img) in hom[1]] # check for automorphism validity in images of operation defining homomorphism, # and construct the defining homomorphism. @@ -1280,22 +1280,22 @@ def semidirect_product(self, H, hom, check=True, reduced=False): raise ValueError("images of input homomorphism must be automorphisms") GAP_def_hom = libgap.GroupHomomorphismByImages(GAP_self, auto_grp, self_gens, GAP_aut_imgs) else: - GAP_def_hom = GAP_self.GroupHomomorphismByImagesNC( auto_grp, self_gens, GAP_aut_imgs) + GAP_def_hom = GAP_self.GroupHomomorphismByImagesNC(auto_grp, self_gens, GAP_aut_imgs) prod = libgap.SemidirectProduct(GAP_self, GAP_def_hom, GAP_H) # Convert pc group to fp group if prod.IsPcGroup(): - prod = libgap.Image(libgap.IsomorphismFpGroupByPcgs(prod.FamilyPcgs() , 'x')) + prod = libgap.Image(libgap.IsomorphismFpGroupByPcgs(prod.FamilyPcgs(), 'x')) if not prod.IsFpGroup(): raise NotImplementedError("unable to convert GAP output to equivalent Sage fp group") # Convert GAP group object to Sage via Tietze # lists for readability of variable names GAP_gens = prod.FreeGeneratorsOfFpGroup() - name_itr = _lexi_gen() # Python generator for lexicographical variable names + name_itr = _lexi_gen() # Python generator for lexicographical variable names ret_F = FreeGroup([next(name_itr) for i in GAP_gens]) ret_rls = tuple([ret_F(rel_word.TietzeWordAbstractWord(GAP_gens).sage()) - for rel_word in prod.RelatorsOfFpGroup()]) + for rel_word in prod.RelatorsOfFpGroup()]) ret_fpg = FinitelyPresentedGroup(ret_F, ret_rls) if reduced: ret_fpg = ret_fpg.simplified() @@ -1314,10 +1314,10 @@ def _element_constructor_(self, *args, **kwds): sage: H([1, 2, 1, -2]) # indirect doctest a*b*a*b^-1 """ - if len(args)!=1: + if len(args) != 1: return self.element_class(self, *args, **kwds) x = args[0] - if x==1: + if x == 1: return self.one() try: P = x.parent() @@ -1350,7 +1350,106 @@ def abelian_invariants(self): Uses GAP. """ invariants = self.gap().AbelianInvariants() - return tuple( i.sage() for i in invariants ) + return tuple(i.sage() for i in invariants) + + @cached_method + def abelianization_map(self): + r""" + Return the abelianization map of ``self``. + + OUTPUT: + + The abelianization map of ``self`` as a homomorphism of finitely presented groups. + + EXAMPLES:: + + sage: G = FreeGroup(4, 'g') + sage: G.inject_variables(verbose=False) + sage: H = G.quotient([g1^2, g2*g1*g2^(-1)*g1^(-1), g1*g3^(-2), g0^4]) + sage: H.abelianization_map() + Group morphism: + From: Finitely presented group < g0, g1, g2, g3 | g1^2, g2*g1*g2^-1*g1^-1, g1*g3^-2, g0^4 > + To: Finitely presented group < f2, f3, f4 | f2^-1*f3^-1*f2*f3, f2^-1*f4^-1*f2*f4, f3^-1*f4^-1*f3*f4, f2^4, f3^4 > + sage: g = FreeGroup(0) / [] + sage: g.abelianization_map() + Group endomorphism of Finitely presented group < | > + """ + if not self.generators(): + return self.hom(codomain=self, im_gens=[]) + hom_ab_libgap = libgap(self).MaximalAbelianQuotient() + ab_libgap = hom_ab_libgap.Range() + hom_ab_fp = ab_libgap.IsomorphismFpGroup() + ab_libgap_fp = hom_ab_fp.Range() + hom_simply = ab_libgap_fp.IsomorphismSimplifiedFpGroup() + ab = wrap_FpGroup(hom_simply.Range()) + images = [] + for f in self.gens(): + f0 = hom_ab_libgap.Image(f) + f1 = hom_ab_fp.Image(f0) + f2 = hom_simply.Image(f1) + L = f2.UnderlyingElement().LetterRepAssocWord() + images.append(ab([int(j) for j in L])) + return self.hom(codomain=ab, im_gens=images) + + @cached_method + def abelianization_to_algebra(self, ring=QQ): + r""" + Return the group algebra of the abelianization of ``self`` + together with the monomials representing the generators of ``self``. + + INPUT: + + - ``ring`` -- (default: ``QQ``); the base ring for + the group algebra of ``self`` + + OUTPUT: + + - ``ab`` -- the abelianization of ``self`` as a finitely presented group + with a minimal number `n` of generators. + - ``R`` -- a Laurent polynomial ring with `n` variables with base ring ``ring``. + - ``ideal`` -- a list of generators of an ideal ``I`` in ``R`` such that ``R/I`` + is the group algebra of the abelianization over ``ring`` + - ``image`` -- a list with the images of the generators of ``self`` in ``R/I`` + + EXAMPLES:: + + sage: G = FreeGroup(4, 'g') + sage: G.inject_variables() + Defining g0, g1, g2, g3 + sage: H = G.quotient([g1^2, g2*g1*g2^(-1)*g1^(-1), g1*g3^(-2), g0^4]) + sage: H.abelianization_to_algebra() + (Finitely presented group < f2, f3, f4 | f2^-1*f3^-1*f2*f3, f2^-1*f4^-1*f2*f4, + f3^-1*f4^-1*f3*f4, f2^4, f3^4 >, + Multivariate Laurent Polynomial Ring in f2, f3, f4 over Rational Field, + [f2^4 - 1, f3^4 - 1], [f2^-1*f3^-2, f3^-2, f4, f3]) + sage: g=FreeGroup(0) / [] + sage: g.abelianization_to_algebra() + (Finitely presented group < | >, Rational Field, [], []) + """ + if not self.generators(): + return self, ring, [], [] + hom_ab = self.abelianization_map() + ab = hom_ab.codomain() + R = LaurentPolynomialRing(ring, ab.gens()) + ideal = [] + for a in ab.relations(): + a_T = a.Tietze() + a_S = Set(a_T) + if a_S.cardinality() == 1: + j = a_T[0] + m = len(a_T) + ideal.append(R.gen(j - 1) ** m - 1) + images0 = [hom_ab(g).Tietze() for g in self.gens()] + images = [] + for L in images0: + p = R.one() + for a in L: + if a > 0: + p *= R.gen(a - 1) + elif a < 0: + p /= R.gen(-a - 1) + images.append(p) + return ab, R, ideal, images def simplification_isomorphism(self): """ @@ -1390,9 +1489,9 @@ def simplification_isomorphism(self): Uses GAP. """ - I = self.gap().IsomorphismSimplifiedFpGroup() - codomain = wrap_FpGroup(I.Range()) - phi = lambda x: codomain(I.ImageElm(x.gap())) + II = self.gap().IsomorphismSimplifiedFpGroup() + codomain = wrap_FpGroup(II.Range()) + phi = lambda x: codomain(II.ImageElm(x.gap())) HS = self.Hom(codomain) return GroupMorphismWithGensImages(HS, phi) @@ -1428,9 +1527,38 @@ def simplified(self): """ return self.simplification_isomorphism().codomain() + def sorted_presentation(self): + """ + Return the same presentation with the relations sorted to ensure equality. + + OUTPUT: + + A new finitely presented group with the relations sorted. + + EXAMPLES:: + + sage: G = FreeGroup(2) / [(1, 2, -1, -2), ()]; G + Finitely presented group < x0, x1 | x0*x1*x0^-1*x1^-1, 1 > + sage: G.sorted_presentation() + Finitely presented group < x0, x1 | 1, x1^-1*x0^-1*x1*x0 > + """ + F = FreeGroup(self.ngens()) + L0 = [r.Tietze() for r in self.relations()] + L1 = [] + for rel in L0: + C = [rel] + for j in range(len(rel) - 1): + C.append(rel[j + 1:] + rel[:j + 1]) + C1 = [tuple(-j for j in reversed(l)) for l in C] + C += C1 + C.sort() + L1.append(C[0]) + L1.sort() + return F/L1 + def epimorphisms(self, H): r""" - Return the epimorphisms from `self` to `H`, up to automorphism of `H`. + Return the epimorphisms from ``self`` to `H`, up to automorphism of `H`. INPUT: @@ -1534,7 +1662,165 @@ def alexander_matrix(self, im_gens=None): rel = self.relations() gen = self._free_group.gens() return matrix(len(rel), len(gen), - lambda i,j: rel[i].fox_derivative(gen[j], im_gens)) + lambda i, j: rel[i].fox_derivative(gen[j], im_gens)) + + @cached_method + def abelian_alexander_matrix(self, ring=QQ, simplified=True): + """ + Return the Alexander matrix of the group with values in the group + algebra of the abelianized. + + INPUT: + + - ``ring`` -- (default: ``QQ``) the base ring of the + group algebra + - ``simplified`` -- boolean (default: ``False``); if set to + ``True`` use Gauss elimination and erase rows and columns + + OUTPUT: + + - ``A`` -- a matrix with coefficients in ``R`` + - ``ideal`` -- an list of generators of an ideal ``I`` of ``R = A.base_ring()`` such that ``R/I`` is + the group algebra of the abelianization of ``self`` + + EXAMPLES:: + + sage: G.<a,b,c> = FreeGroup() + sage: H = G.quotient([a*b/a/b, a*c/a/c, c*b/c/b]) + sage: A, ideal = H.abelian_alexander_matrix() + sage: A + [-f2 + 1 f1 - 1 0] + [-f3 + 1 0 f1 - 1] + [ 0 f3 - 1 -f2 + 1] + sage: A.base_ring() + Multivariate Laurent Polynomial Ring in f1, f2, f3 over Rational Field + sage: ideal + [] + sage: G = FreeGroup(3)/[(2, 1, 1), (1, 2, 2, 3, 3)] + sage: A, ideal = G.abelian_alexander_matrix(simplified=True); A + [-f3^2 - f3^4 - f3^6 f3^3 + f3^6] + sage: g = FreeGroup(1) / [] + sage: g.abelian_alexander_matrix() + ([], []) + sage: g = FreeGroup(0) / [] + sage: g.abelian_alexander_matrix() + ([], []) + """ + ab, R, ideal, images = self.abelianization_to_algebra(ring=ring) + A = self.alexander_matrix(im_gens=images) + if simplified: + n, m = A.dimensions() + if n == 0 or m == 0: + return A, ideal + simpli = True + while simpli: + i = 0 + j = 0 + unidad = False + while not unidad and i < n and j < m: + p = A[i, j] + unidad = p.is_unit() + if unidad: + A.swap_rows(0, i) + A.swap_columns(0, j) + for k in range(1, n): + A.add_multiple_of_row(k, 0, -A[k, 0] * p ** -1) + A = A.delete_rows([0]).delete_columns([0]) + n, m = A.dimensions() + else: + if j < m - 1: + j += 1 + else: + i += 1 + j = 0 + simpli = unidad + return A, ideal + + def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): + r""" + Return the characteristic varieties of the group ``self``. + + There are several definitions of the characteristic varieties of a group `G`, see e.g. [CS1999a]_. Let `\Lambda` be the + group algebra of `G/G'` and `\mathbb{T}` its associated algebraic variety (a torus). Each + element `\xi\in\mathbb{T}` defines a local system of coefficients and the `k` th-characteristic + variety is + + .. MATH:: + + V_k(G) = \{\xi\in\mathbb{T}\mid \dim H^1(G;\xi)\geq k\}. + + These varieties are defined by ideals in `\Lambda`. + + INPUT: + + - ``ring`` -- (default: ``QQ``) the base ring of the group algebra + - ``groebner`` -- boolean (default: ``False``); If set to + ``True`` the minimal associated primes of the ideals and their + groebner bases are computed; ignored if the base ring + is not a field + + OUTPUT: + + If ``groebner`` is ``False`` a list of ideals defining the characteristic varieties. + If it is ``True``, a list of lists for Grรถbner bases for each ideal. + + EXAMPLES:: + + sage: L = [2*(i, j) + 2* (-i, -j) for i, j in ((1, 2), (2, 3), (3, 1))] + sage: G = FreeGroup(3) / L + sage: G.characteristic_varieties(groebner=True) + [[(f1 - 1, f2 - 1, f3 - 1), + (f1 + 1, f2 - 1, f3 - 1), + (f1 - 1, f2 - 1, f3 + 1), + (f3^2 + 1, f1 - f3, f2 - f3), + (f1 - 1, f2 + 1, f3 - 1)], + [(f1 - 1, f2 - 1, f3 - 1), + (f1*f3 + 1, f2 - 1), + (f1*f2 + 1, f3 - 1), + (f2*f3 + 1, f1 - 1), + (f2*f3 + 1, f1 - f2), + (f2*f3 + 1, f1 - f3), + (f1*f3 + 1, f2 - f3)]] + sage: G = FreeGroup(2)/[2*(1,2,-1,-2)] + sage: G.characteristic_varieties() + [Ideal (-2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field] + sage: G.characteristic_varieties(ring=ZZ) + [Ideal (-2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring] + sage: G = FreeGroup(2)/[(1,2,1,-2,-1,-2)] + sage: G.characteristic_varieties() + [Ideal (1 - f2 + f2^2, -1 + f2 - f2^2) of Univariate Laurent Polynomial Ring in f2 over Rational Field] + sage: G.characteristic_varieties(groebner=True) + [[1 - f2 + f2^2]] + """ + A, ideal = self.abelian_alexander_matrix(ring=ring, simplified=True) + R = A.base_ring() + res = [] + S = R.polynomial_ring() + ideal = [S(elt) for elt in ideal] + for j in range(1, A.ncols()): + L = [p.monomial_reduction()[0] for p in A.minors(j)] + J = R.ideal(L + ideal) + res.append(J) + if not groebner or not R.base_ring().is_field(): + return res + if R.ngens() == 1: + res0 = [gcd(S(p) for p in J.gens()) for J in res] + res1 = [] + for p in res0: + if p == 0: + res1.append([R(0)]) + else: + fct = [q[0] for q in R(p).factor()] + if fct: + res1.append(fct) + return res1 + res1 = [] + for J in res: + LJ = J.minimal_associated_primes() + fct = [id.groebner_basis() for id in LJ] + if fct != [(S.one(),)]: + res1.append(fct) + return res1 def rewriting_system(self): """ diff --git a/src/sage/groups/finitely_presented_named.py b/src/sage/groups/finitely_presented_named.py index 248049fadb7..d800bf014d0 100644 --- a/src/sage/groups/finitely_presented_named.py +++ b/src/sage/groups/finitely_presented_named.py @@ -101,9 +101,10 @@ def CyclicPresentation(n): n = Integer(n) if n < 1: raise ValueError('finitely presented group order must be positive') - F = FreeGroup( 'a' ) + F = FreeGroup('a') rls = F([1])**n, - return FinitelyPresentedGroup( F, rls ) + return FinitelyPresentedGroup(F, rls) + def FinitelyGeneratedAbelianPresentation(int_list): r""" @@ -196,7 +197,7 @@ def FinitelyGeneratedAbelianPresentation(int_list): invariants = FGP_Module(ZZ**(len(int_list)), col_sp).invariants() name_gen = _lexi_gen() F = FreeGroup([next(name_gen) for i in invariants]) - ret_rls = [F([i+1])**invariants[i] for i in range(len(invariants)) if invariants[i]!=0] + ret_rls = [F([i+1])**invariants[i] for i in range(len(invariants)) if invariants[i] != 0] # Build commutator relations gen_pairs = [[F.gen(i),F.gen(j)] for i in range(F.ngens()-1) for j in range(i+1,F.ngens())] @@ -285,7 +286,7 @@ def commutator(a, b): # Third set of relations: [z, yi] = 1 r3 = [commutator(z, y[i]) for i in range(n)] # Fourth set of relations: [xi, yi] = 1 for i != j - r4 = [commutator(x[i], y[j]) for i in range(n) for j in range(n) if i!=j] + r4 = [commutator(x[i], y[j]) for i in range(n) for j in range(n) if i != j] rls = r1 + r2 + r3 + r4 from sage.sets.primes import Primes @@ -381,9 +382,10 @@ def DiCyclicPresentation(n): raise ValueError('input integer must be greater than 1') F = FreeGroup(['a','b']) - rls = F([1])**(2*n), F([2,2])*F([-1])**n, F([-2,1,2,1]) + rls = F([1])**(2*n), F([2,2])*F([-1])**n, F([-2,1,2,1]) return FinitelyPresentedGroup(F, rls) + def SymmetricPresentation(n): r""" Build the Symmetric group of order `n!` as a finitely presented group. @@ -422,14 +424,18 @@ def SymmetricPresentation(n): from sage.groups.free_group import _lexi_gen n = Integer(n) + if n <= 1: + return FinitelyPresentedGroup(FreeGroup(()), ()) + perm_rep = SymmetricGroup(n) GAP_fp_rep = libgap.Image(libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens())) image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup() - name_itr = _lexi_gen() # Python generator object for variable names + name_itr = _lexi_gen() # Python generator object for variable names F = FreeGroup([next(name_itr) for x in perm_rep.gens()]) ret_rls = tuple([F(rel_word.TietzeWordAbstractWord(image_gens).sage()) - for rel_word in GAP_fp_rep.RelatorsOfFpGroup()]) - return FinitelyPresentedGroup(F,ret_rls) + for rel_word in GAP_fp_rep.RelatorsOfFpGroup()]) + return FinitelyPresentedGroup(F, ret_rls) + def QuaternionPresentation(): r""" @@ -481,9 +487,10 @@ def AlternatingPresentation(n): sage: A6.as_permutation_group().is_isomorphic(AlternatingGroup(6)), A6.order() (True, 360) - TESTS:: + TESTS: + + Even permutation tests:: - sage: #even permutation test.. sage: A1 = groups.presentation.Alternating(1); A2 = groups.presentation.Alternating(2) sage: A1.is_isomorphic(A2), A1.order() (True, 1) @@ -496,14 +503,18 @@ def AlternatingPresentation(n): from sage.groups.free_group import _lexi_gen n = Integer(n) + if n <= 2: + return FinitelyPresentedGroup(FreeGroup(()), ()) + perm_rep = AlternatingGroup(n) GAP_fp_rep = libgap.Image(libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens())) image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup() - name_itr = _lexi_gen() # Python generator object for variable names + name_itr = _lexi_gen() # Python generator object for variable names F = FreeGroup([next(name_itr) for x in perm_rep.gens()]) ret_rls = tuple([F(rel_word.TietzeWordAbstractWord(image_gens).sage()) - for rel_word in GAP_fp_rep.RelatorsOfFpGroup()]) - return FinitelyPresentedGroup(F,ret_rls) + for rel_word in GAP_fp_rep.RelatorsOfFpGroup()]) + return FinitelyPresentedGroup(F, ret_rls) + def KleinFourPresentation(): r""" @@ -548,7 +559,7 @@ def BinaryDihedralPresentation(n): TESTS:: - sage: for n in range(3, 9): + sage: for n in range(3, 9): # needs sage.modules ....: P = groups.presentation.BinaryDihedral(n) ....: M = groups.matrix.BinaryDihedral(n) ....: assert P.is_isomorphic(M) @@ -574,7 +585,7 @@ def CactusPresentation(n): EXAMPLES:: - sage: J3 = groups.presentation.Cactus(3); J3 + sage: J3 = groups.presentation.Cactus(3); J3 # needs sage.graphs Finitely presented group < s12, s13, s23 | s12^2, s13^2, s23^2, s13*s12*s13^-1*s23^-1, s13*s23*s13^-1*s12^-1 > """ diff --git a/src/sage/groups/fqf_orthogonal.py b/src/sage/groups/fqf_orthogonal.py index 7fc4dbe7548..3d0c79ed7c3 100644 --- a/src/sage/groups/fqf_orthogonal.py +++ b/src/sage/groups/fqf_orthogonal.py @@ -8,19 +8,20 @@ EXAMPLES:: - sage: L = IntegralLattice("A2").twist(2) - sage: T = L.discriminant_group() - sage: Oq = T.orthogonal_group() + sage: L = IntegralLattice("A2").twist(2) # needs sage.graphs + sage: T = L.discriminant_group() # needs sage.graphs + sage: Oq = T.orthogonal_group() # needs sage.graphs The isometries act on elements of their domain:: - sage: g = Oq(matrix(ZZ, 2, [0, 3, 1, 2])) - sage: T.gen(0) * g + sage: g = Oq(matrix(ZZ, 2, [0, 3, 1, 2])) # needs sage.graphs + sage: T.gen(0) * g # needs sage.graphs (0, 3) Isometries are represented with respect to the Smith form generators of `T`:: + sage: # needs sage.graphs sage: L = IntegralLattice("A2").twist(2).direct_sum(IntegralLattice('U')) sage: T = L.discriminant_group().normal_form() sage: OT = T.orthogonal_group() @@ -143,7 +144,7 @@ class FqfOrthogonalGroup(AbelianGroupAutomorphismGroup_subgroup): [2/3 0 0] [ 0 2/3 0] [ 0 0 4/3] - generated by 2 elements + generated by 3 elements sage: q = matrix.diagonal(QQ, [3/2, 1/4, 1/4]) sage: T = TorsionQuadraticForm(q) sage: T.orthogonal_group().order() @@ -216,6 +217,7 @@ def _element_constructor_(self, x, check=True): EXAMPLES:: + sage: # needs sage.graphs sage: L = IntegralLattice("A2").twist(2).direct_sum(IntegralLattice("A2")) sage: q = L.discriminant_group() sage: OL = L.orthogonal_group() @@ -230,18 +232,19 @@ def _element_constructor_(self, x, check=True): Note that the following does not work since it may lead to ambiguities, see :trac:`30669`:: - sage: Oq(f.matrix()) + sage: Oq(f.matrix()) # needs sage.graphs Traceback (most recent call last): ... ValueError: ... But a matrix in the covering works:: - sage: fbar == Oq(fbar.matrix()) + sage: fbar == Oq(fbar.matrix()) # needs sage.graphs True TESTS:: + sage: # needs sage.graphs sage: all(x*f==x*fbar for x in q.gens()) True sage: L = IntegralLattice("A2").twist(3) @@ -377,7 +380,7 @@ def _repr_(self): [ 0 2/3] generated by 2 elements """ - return "Group of isometries of \n%s\ngenerated by %s elements"%(self.invariant_form(), len(self.gens())) + return "Group of isometries of \n%s\ngenerated by %s elements" % (self.invariant_form(), len(self.gens())) class ActionOnFqf(Action): r""" @@ -512,9 +515,9 @@ def _isom_fqf(A, B=None): TESTS:: sage: for p in primes_first_n(7)[1:]: # long time - ....: q = matrix.diagonal(QQ, 3 * [2/p]) # long time - ....: q = TorsionQuadraticForm(q) # long time - ....: assert q.orthogonal_group().order()==GO(3, p).order() # long time + ....: q = matrix.diagonal(QQ, 3 * [2/p]) + ....: q = TorsionQuadraticForm(q) + ....: assert q.orthogonal_group().order()==GO(3, p).order() """ def orbits(G, L): r""" @@ -544,7 +547,7 @@ def orbits(G, L): raise ValueError("torsion quadratic modules are not isometric") n = len(A.smith_form_gens()) # separating the different primes here would speed things up - b_cand = [[b for b in B if b.q()==a.q() and b.order() == a.order()] for a in A.smith_form_gens()] + b_cand = [[b for b in B if b.q() == a.q() and b.order() == a.order()] for a in A.smith_form_gens()] G = B.orthogonal_group(tuple()) ambient = G.ambient() @@ -566,7 +569,7 @@ def orbits(G, L): a = A.smith_form_gens()[i] card = ZZ.prod(A.smith_form_gen(k).order() for k in range(i+1)) for b in b_cand[i]: - if all(b.b(f[k])==a.b(A.smith_form_gens()[k]) for k in range(i)): + if all(b.b(f[k]) == a.b(A.smith_form_gens()[k]) for k in range(i)): fnew = f + [b] # check that the elements of fnew are independent if B.submodule(fnew).cardinality() == card: diff --git a/src/sage/groups/free_group.py b/src/sage/groups/free_group.py index 0c51deafc64..6f3c4400779 100644 --- a/src/sage/groups/free_group.py +++ b/src/sage/groups/free_group.py @@ -89,11 +89,11 @@ def is_FreeGroup(x): EXAMPLES:: sage: from sage.groups.free_group import is_FreeGroup - sage: is_FreeGroup('a string') + sage: is_FreeGroup('a string') # needs sage.combinat False sage: is_FreeGroup(FreeGroup(0)) True - sage: is_FreeGroup(FreeGroup(index_set=ZZ)) + sage: is_FreeGroup(FreeGroup(index_set=ZZ)) # needs sage.combinat True """ if isinstance(x, FreeGroup_class): @@ -213,20 +213,20 @@ def __init__(self, parent, x): l = x.Tietze() except AttributeError: l = list(x) - if len(l)>0: + if len(l) > 0: if min(l) < -parent.ngens() or parent.ngens() < max(l): raise ValueError('generators not in the group') if 0 in l: raise ValueError('zero does not denote a generator') - i=0 - while i<len(l)-1: - if l[i]==-l[i+1]: + i = 0 + while i < len(l)-1: + if l[i] == -l[i+1]: l.pop(i) l.pop(i) - if i>0: - i=i-1 + if i > 0: + i = i-1 else: - i=i+1 + i = i+1 AbstractWordTietzeWord = libgap.eval('AbstractWordTietzeWord') x = AbstractWordTietzeWord(l, parent.gap().GeneratorsOfGroup()) ElementLibGAP.__init__(self, parent, x) @@ -645,9 +645,9 @@ def FreeGroup(n=None, names='x', index_set=None, abelian=False, **kwds): We give two examples using the ``index_set`` option:: - sage: FreeGroup(index_set=ZZ) + sage: FreeGroup(index_set=ZZ) # needs sage.combinat Free group indexed by Integer Ring - sage: FreeGroup(index_set=ZZ, abelian=True) + sage: FreeGroup(index_set=ZZ, abelian=True) # needs sage.combinat Free abelian group indexed by Integer Ring TESTS:: @@ -788,7 +788,7 @@ def _repr_(self): sage: G._repr_() 'Free Group on generators {a, b}' """ - return 'Free Group on generators {'+ ', '.join(self.variable_names()) + '}' + return 'Free Group on generators {' + ', '.join(self.variable_names()) + '}' def rank(self): """ @@ -870,10 +870,10 @@ def _element_constructor_(self, *args, **kwds): ... TypeError: 'sage.rings.integer.Integer' object is not iterable """ - if len(args)!=1: + if len(args) != 1: return self.element_class(self, *args, **kwds) x = args[0] - if x==1 or x == [] or x == (): + if x == 1 or x == [] or x == (): return self.one() try: P = x.parent() @@ -885,7 +885,7 @@ def _element_constructor_(self, *args, **kwds): return self([i.sign()*(self._names.index(P._names[abs(i)-1])+1) for i in x.Tietze()]) else: - raise ValueError('generators of %s not in the group'%x) + raise ValueError('generators of %s not in the group' % x) return self.element_class(self, x, **kwds) def abelian_invariants(self): diff --git a/src/sage/groups/galois_group.py b/src/sage/groups/galois_group.py index aa1d69d11d4..ed9e6d61bd4 100644 --- a/src/sage/groups/galois_group.py +++ b/src/sage/groups/galois_group.py @@ -31,9 +31,9 @@ def _alg_key(self, algorithm=None, recompute=False): sage: from sage.groups.galois_group import _alg_key sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^3 + 2*x + 2) - sage: G = K.galois_group() - sage: _alg_key(G, algorithm="pari", recompute=True) + sage: K.<a> = NumberField(x^3 + 2*x + 2) # needs sage.rings.number_field + sage: G = K.galois_group() # needs sage.rings.number_field + sage: _alg_key(G, algorithm="pari", recompute=True) # needs sage.rings.number_field 'pari' """ if recompute: @@ -55,9 +55,9 @@ def _default_algorithm(self): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^3 + 2*x + 2) - sage: G = K.galois_group() - sage: G._default_algorithm + sage: K.<a> = NumberField(x^3 + 2*x + 2) # needs sage.rings.number_field + sage: G = K.galois_group() # needs sage.rings.number_field + sage: G._default_algorithm # needs sage.rings.number_field 'pari' """ return NotImplemented @@ -74,9 +74,9 @@ def _gcdata(self): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^3 - 2) - sage: G = K.galois_group() - sage: G._gcdata + sage: K.<a> = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: G = K.galois_group() # needs sage.rings.number_field + sage: G._gcdata # needs sage.rings.number_field (Number Field in ac with defining polynomial x^6 + 108, Ring morphism: From: Number Field in a with defining polynomial x^3 - 2 @@ -91,6 +91,7 @@ def _get_algorithm(self, algorithm): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = ZZ[] sage: K.<a> = NumberField(x^3 + 2*x + 2) sage: G = K.galois_group() @@ -109,9 +110,9 @@ def _galois_closure(self): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^3 + 2*x + 2) - sage: G = K.galois_group(names='b') - sage: G._galois_closure + sage: K.<a> = NumberField(x^3 + 2*x + 2) # needs sage.rings.number_field + sage: G = K.galois_group(names='b') # needs sage.rings.number_field + sage: G._galois_closure # needs sage.rings.number_field Number Field in b with defining polynomial x^6 + 12*x^4 + 36*x^2 + 140 """ return self._gcdata[0] @@ -122,6 +123,8 @@ def splitting_field(self): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^3 - x + 1, 'a') sage: K.galois_group(names='b').splitting_field() Number Field in b with defining polynomial x^6 - 6*x^4 + 9*x^2 + 23 @@ -138,9 +141,9 @@ def _gc_map(self): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^3 + 2*x + 2) - sage: G = K.galois_group(names='b') - sage: G._gc_map + sage: K.<a> = NumberField(x^3 + 2*x + 2) # needs sage.rings.number_field + sage: G = K.galois_group(names='b') # needs sage.rings.number_field + sage: G._gc_map # needs sage.rings.number_field Ring morphism: From: Number Field in a with defining polynomial x^3 + 2*x + 2 To: Number Field in b with defining polynomial x^6 + 12*x^4 + 36*x^2 + 140 @@ -161,9 +164,9 @@ def _field(self): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^3 + 2*x + 2) - sage: G = K.galois_group() - sage: G._field + sage: K.<a> = NumberField(x^3 + 2*x + 2) # needs sage.rings.number_field + sage: G = K.galois_group() # needs sage.rings.number_field + sage: G._field # needs sage.rings.number_field Number Field in a with defining polynomial x^3 + 2*x + 2 """ return NotImplemented @@ -176,9 +179,9 @@ def _repr_(self): sage: from sage.groups.galois_group import GaloisGroup_perm sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^3 + 2*x + 2) - sage: G = K.galois_group() - sage: GaloisGroup_perm._repr_(G) + sage: K.<a> = NumberField(x^3 + 2*x + 2) # needs sage.rings.number_field + sage: G = K.galois_group() # needs sage.rings.number_field + sage: GaloisGroup_perm._repr_(G) # needs sage.rings.number_field 'Galois group of x^3 + 2*x + 2' """ f = self._field.defining_polynomial() @@ -192,6 +195,7 @@ def top_field(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = ZZ[] sage: K.<a> = NumberField(x^3 + 2*x + 2) sage: L = K.galois_closure('b') @@ -211,6 +215,7 @@ def _field_degree(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = ZZ[] sage: K.<a> = NumberField(x^3 + 2*x + 2) sage: L.<b> = K.extension(x^2 + 3*a^2 + 8) @@ -228,11 +233,11 @@ def _field_degree(self): This behavior may change in the future:: - sage: GL._field_degree + sage: GL._field_degree # needs sage.rings.number_field 6 - sage: GL.transitive_label() + sage: GL.transitive_label() # needs sage.rings.number_field '6T2' - sage: GL + sage: GL # needs sage.rings.number_field Galois group 6T2 ([3]2) with order 6 of x^2 + 3*a^2 + 8 """ try: @@ -248,9 +253,9 @@ def transitive_label(self): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^8 - x^5 + x^4 - x^3 + 1) - sage: G = K.galois_group() - sage: G.transitive_label() + sage: K.<a> = NumberField(x^8 - x^5 + x^4 - x^3 + 1) # needs sage.rings.number_field + sage: G = K.galois_group() # needs sage.rings.number_field + sage: G.transitive_label() # needs sage.rings.number_field '8T44' """ return "%sT%s" % (self._field_degree, self.transitive_number()) @@ -262,10 +267,10 @@ def is_galois(self): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^8 - x^5 + x^4 - x^3 + 1) - sage: G = K.galois_group() + sage: K.<a> = NumberField(x^8 - x^5 + x^4 - x^3 + 1) # needs sage.rings.number_field + sage: G = K.galois_group() # needs sage.rings.number_field sage: from sage.groups.galois_group import GaloisGroup_perm - sage: GaloisGroup_perm.is_galois(G) + sage: GaloisGroup_perm.is_galois(G) # needs sage.rings.number_field False """ return self.order() == self._field_degree @@ -282,6 +287,8 @@ def _ambient_group(self): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: L.<a> = NumberField(x^4 + 1) sage: G = L.galois_group() sage: H = G.decomposition_group(L.primes_above(3)[0]) @@ -307,6 +314,7 @@ def fixed_field(self, name=None, polred=None, threshold=None): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(3^12) sage: g = k.galois_group()([8]) sage: k0, embed = g.fixed_field() @@ -321,10 +329,12 @@ def _gcdata(self): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: L.<a> = NumberField(x^4 + 1) sage: G = L.galois_group() sage: H = G.decomposition_group(L.primes_above(3)[0]) - sage: H.splitting_field() # indirect doctest + sage: H.splitting_field() # indirect doctest Number Field in a with defining polynomial x^4 + 1 """ return self._ambient_group._gcdata @@ -352,9 +362,9 @@ def transitive_number(self, algorithm=None, recompute=False): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^3 + 2*x + 2) - sage: G = K.galois_group() - sage: G.transitive_number() + sage: K.<a> = NumberField(x^3 + 2*x + 2) # needs sage.rings.number_field + sage: G = K.galois_group() # needs sage.rings.number_field + sage: G.transitive_number() # needs sage.rings.number_field 2 """ @@ -368,9 +378,9 @@ def _gens(self): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^5-2) - sage: G = K.galois_group(gc_numbering=False) - sage: G._gens + sage: K.<a> = NumberField(x^5 - 2) # needs sage.rings.number_field + sage: G = K.galois_group(gc_numbering=False) # needs sage.rings.number_field + sage: G._gens # needs sage.rings.number_field [(1,2,3,5), (1,4,3,2,5)] """ return NotImplemented @@ -380,9 +390,9 @@ def __init__(self, field, algorithm=None, names=None, gc_numbering=False): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^3 + 2*x + 2) - sage: G = K.galois_group() - sage: TestSuite(G).run() + sage: K.<a> = NumberField(x^3 + 2*x + 2) # needs sage.rings.number_field + sage: G = K.galois_group() # needs sage.rings.number_field + sage: TestSuite(G).run() # needs sage.rings.number_field """ self._field = field self._default_algorithm = algorithm @@ -410,8 +420,9 @@ def _deg(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^5-2) + sage: K.<a> = NumberField(x^5 - 2) sage: G = K.galois_group(gc_numbering=False); G Galois group 5T3 (5:4) with order 20 of x^5 - 2 sage: G._deg @@ -434,8 +445,9 @@ def _domain(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^5-2) + sage: K.<a> = NumberField(x^5 - 2) sage: G = K.galois_group(gc_numbering=False); G Galois group 5T3 (5:4) with order 20 of x^5 - 2 sage: G._domain @@ -453,9 +465,9 @@ def _domain_to_gap(self): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^5-2) - sage: G = K.galois_group(gc_numbering=False) - sage: G._domain_to_gap[5] + sage: K.<a> = NumberField(x^5 - 2) # needs sage.rings.number_field + sage: G = K.galois_group(gc_numbering=False) # needs sage.rings.number_field + sage: G._domain_to_gap[5] # needs sage.rings.number_field 5 """ return dict((key, i+1) for i, key in enumerate(self._domain)) @@ -468,9 +480,9 @@ def _domain_from_gap(self): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^5-2) - sage: G = K.galois_group(gc_numbering=True) - sage: G._domain_from_gap[20] + sage: K.<a> = NumberField(x^5 - 2) # needs sage.rings.number_field + sage: G = K.galois_group(gc_numbering=True) # needs sage.rings.number_field + sage: G._domain_from_gap[20] # needs sage.rings.number_field 20 """ return dict((i+1, key) for i, key in enumerate(self._domain)) @@ -481,7 +493,7 @@ def ngens(self): EXAMPLES:: - sage: QuadraticField(-23, 'a').galois_group().ngens() + sage: QuadraticField(-23, 'a').galois_group().ngens() # needs sage.rings.number_field 1 """ return len(self._gens) @@ -496,7 +508,7 @@ def __init__(self, field, generator_orders, algorithm=None, gen_names='sigma'): TESTS:: - sage: TestSuite(GF(9).galois_group()).run() + sage: TestSuite(GF(9).galois_group()).run() # needs sage.rings.finite_rings """ self._field = field self._default_algorithm = algorithm @@ -510,7 +522,7 @@ def is_galois(self): EXAMPLES:: - sage: GF(9).galois_group().is_galois() + sage: GF(9).galois_group().is_galois() # needs sage.rings.finite_rings True """ return True @@ -522,7 +534,7 @@ def _gcdata(self): EXAMPLES:: - sage: GF(3^2).galois_group()._gcdata + sage: GF(3^2).galois_group()._gcdata # needs sage.rings.finite_rings (Finite Field in z2 of size 3^2, Identity endomorphism of Finite Field in z2 of size 3^2) """ @@ -534,11 +546,12 @@ def permutation_group(self): r""" Return a permutation group giving the action on the roots of a defining polynomial. - This is the regular representation for the abelian group, which is not necessarily the smallest degree permutation representation. + This is the regular representation for the abelian group, which is + not necessarily the smallest degree permutation representation. EXAMPLES:: - sage: GF(3^10).galois_group().permutation_group() + sage: GF(3^10).galois_group().permutation_group() # needs sage.rings.finite_rings Permutation Group with generators [(1,2,3,4,5,6,7,8,9,10)] """ return PermutationGroup(gap_group=self._gap_().RegularActionHomomorphism().Image()) @@ -570,11 +583,11 @@ def transitive_number(self, algorithm=None, recompute=False): EXAMPLES:: - sage: GF(2^8).galois_group().transitive_number() + sage: GF(2^8).galois_group().transitive_number() # needs sage.rings.finite_rings 1 - sage: GF(3^32).galois_group().transitive_number() + sage: GF(3^32).galois_group().transitive_number() # needs sage.rings.finite_rings 33 - sage: GF(2^60).galois_group().transitive_number() + sage: GF(2^60).galois_group().transitive_number() # needs sage.rings.finite_rings Traceback (most recent call last): ... NotImplementedError: transitive database only computed up to degree 47 @@ -594,9 +607,9 @@ def signature(self): EXAMPLES:: - sage: GF(3^2).galois_group().signature() + sage: GF(3^2).galois_group().signature() # needs sage.rings.finite_rings -1 - sage: GF(3^3).galois_group().signature() + sage: GF(3^3).galois_group().signature() # needs sage.rings.finite_rings 1 """ return ZZ(1) if (self._field.degree() % 2) else ZZ(-1) @@ -619,5 +632,6 @@ class GaloisSubgroup_ab(AbelianGroup_subgroup, _SubGaloisMixin): """ pass + GaloisGroup_perm.Subgroup = GaloisSubgroup_perm GaloisGroup_ab.Subgroup = GaloisSubgroup_ab diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index d5823ebf9e0..17deee71ef6 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -5,15 +5,15 @@ groups, including additive and multiplicative groups. In all cases the group operation is specified by a parameter -'operation', which is a string either one of the set of -multiplication_names or addition_names specified below, or 'other'. -In the latter case, the caller must provide an identity, inverse() and -op() functions. +``operation``, which is a string either one of the set of +``multiplication_names`` or ``addition_names`` specified below, or other. +In the latter case, the caller must provide an identity, ``inverse()`` and +``op()`` functions. :: - multiplication_names = ( 'multiplication', 'times', 'product', '*') - addition_names = ( 'addition', 'plus', 'sum', '+') + multiplication_names = ('multiplication', 'times', 'product', '*') + addition_names = ('addition', 'plus', 'sum', '+') Also included are a generic function for computing multiples (or @@ -25,14 +25,16 @@ - Discrete logs:: + sage: # needs sage.rings.finite_rings sage: K = GF(3^6,'b') sage: b = K.gen() sage: a = b^210 - sage: discrete_log(a, b, K.order()-1) + sage: discrete_log(a, b, K.order() - 1) 210 - Linear relation finder:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(3^6,'a') sage: a.multiplicative_order().factor() 2^3 * 7 * 13 @@ -45,18 +47,20 @@ - Orders of elements:: + sage: # needs sage.rings.finite_rings sage: from sage.groups.generic import order_from_multiple, order_from_bounds sage: k.<a> = GF(5^5) sage: b = a^4 - sage: order_from_multiple(b,5^5-1,operation='*') + sage: order_from_multiple(b, 5^5 - 1, operation='*') 781 - sage: order_from_bounds(b,(5^4,5^5),operation='*') + sage: order_from_bounds(b, (5^4, 5^5), operation='*') 781 Some examples in the group of points of an elliptic curve over a finite field: - Discrete logs:: + sage: # needs sage.libs.gap sage.rings.finite_rings sage.schemes sage: F = GF(37^2,'a') sage: E = EllipticCurve(F,[1,1]) sage: F.<a> = GF(37^2,'a') @@ -66,11 +70,12 @@ 672 sage: Q = 39*P; Q (36*a + 32 : 5*a + 12 : 1) - sage: discrete_log(Q,P,P.order(),operation='+') + sage: discrete_log(Q, P, P.order(), operation='+') 39 - Linear relation finder:: + sage: # needs sage.libs.gap sage.rings.finite_rings sage.schemes sage: F.<a> = GF(3^6,'a') sage: E = EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a, a^4 + a^3 + 2*a + 1]) sage: P = E(a^5 + a^4 + a^3 + a^2 + a + 2 , 0) @@ -82,10 +87,11 @@ - Orders of elements:: + sage: # needs sage.libs.gap sage.rings.finite_rings sage.schemes sage: from sage.groups.generic import order_from_multiple, order_from_bounds sage: k.<a> = GF(5^5) sage: E = EllipticCurve(k,[2,4]) - sage: P = E(3*a^4 + 3*a , 2*a + 1 ) + sage: P = E(3*a^4 + 3*a, 2*a + 1) sage: M = E.cardinality(); M 3227 sage: plist = M.prime_factors() @@ -134,36 +140,37 @@ def multiple(a, n, operation='*', identity=None, inverse=None, op=None): EXAMPLES:: - sage: multiple(2,5) + sage: multiple(2, 5) 32 - sage: multiple(RealField()('2.5'),4) + sage: multiple(RealField()('2.5'), 4) # needs sage.rings.real_mpfr 39.0625000000000 - sage: multiple(2,-3) + sage: multiple(2, -3) 1/8 - sage: multiple(2,100,'+') == 100*2 + sage: multiple(2, 100, '+') == 100*2 True - sage: multiple(2,100) == 2**100 + sage: multiple(2, 100) == 2**100 True - sage: multiple(2,-100,) == 2**-100 + sage: multiple(2, -100,) == 2**-100 True - sage: R.<x>=ZZ[] - sage: multiple(x,100) + sage: R.<x> = ZZ[] + sage: multiple(x, 100) x^100 - sage: multiple(x,100,'+') + sage: multiple(x, 100, '+') 100*x - sage: multiple(x,-10) + sage: multiple(x, -10) 1/x^10 Idempotence is detected, making the following fast:: - sage: multiple(1,10^1000) + sage: multiple(1, 10^1000) 1 + sage: # needs sage.schemes sage: E = EllipticCurve('389a1') sage: P = E(-1,1) - sage: multiple(P,10,'+') + sage: multiple(P, 10, '+') (645656132358737542773209599489/22817025904944891235367494656 : 525532176124281192881231818644174845702936831/3446581505217248068297884384990762467229696 : 1) - sage: multiple(P,-10,'+') + sage: multiple(P, -10, '+') (645656132358737542773209599489/22817025904944891235367494656 : -528978757629498440949529703029165608170166527/3446581505217248068297884384990762467229696 : 1) """ from operator import inv, mul, neg, add @@ -247,14 +254,14 @@ class multiples: EXAMPLES:: - sage: list(multiples(1,10)) + sage: list(multiples(1, 10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - sage: list(multiples(1,10,100)) + sage: list(multiples(1, 10, 100)) [100, 101, 102, 103, 104, 105, 106, 107, 108, 109] - sage: E = EllipticCurve('389a1') - sage: P = E(-1,1) - sage: for Q in multiples(P,5): print((Q, Q.height()/P.height())) + sage: E = EllipticCurve('389a1') # needs sage.schemes + sage: P = E(-1,1) # needs sage.schemes + sage: for Q in multiples(P, 5): print((Q, Q.height()/P.height())) # needs sage.schemes ((0 : 1 : 0), 0.000000000000000) ((-1 : 1 : 1), 1.00000000000000) ((10/9 : -35/27 : 1), 4.00000000000000) @@ -262,22 +269,23 @@ class multiples: ((47503/16641 : 9862190/2146689 : 1), 16.0000000000000) sage: R.<x> = ZZ[] - sage: list(multiples(x,5)) + sage: list(multiples(x, 5)) [0, x, 2*x, 3*x, 4*x] - sage: list(multiples(x,5,operation='*')) + sage: list(multiples(x, 5, operation='*')) [1, x, x^2, x^3, x^4] - sage: list(multiples(x,5,indexed=True)) + sage: list(multiples(x, 5, indexed=True)) [(0, 0), (1, x), (2, 2*x), (3, 3*x), (4, 4*x)] - sage: list(multiples(x,5,indexed=True,operation='*')) + sage: list(multiples(x, 5, indexed=True, operation='*')) [(0, 1), (1, x), (2, x^2), (3, x^3), (4, x^4)] - sage: for i,y in multiples(x,5,indexed=True): print("%s times %s = %s"%(i,x,y)) + sage: for i,y in multiples(x, 5, indexed=True): print("%s times %s = %s"%(i,x,y)) 0 times x = 0 1 times x = x 2 times x = 2*x 3 times x = 3*x 4 times x = 4*x - sage: for i,n in multiples(3,5,indexed=True,operation='*'): print("3 to the power %s = %s" % (i,n)) + sage: for i,n in multiples(3, 5, indexed=True, operation='*'): + ....: print("3 to the power %s = %s" % (i,n)) 3 to the power 0 = 1 3 to the power 1 = 3 3 to the power 2 = 9 @@ -286,26 +294,25 @@ class multiples: """ def __init__(self, P, n, P0=None, indexed=False, operation='+', op=None): """ - Create a multiples iterator + Create a multiples iterator. INPUT: - - ``P`` - step value: any Sage object on which a binary - operation is defined - - ``n`` - number of multiples: non-negative integer + - ``P`` -- step value: any Sage object on which a binary operation is defined + - ``n`` -- number of multiples: non-negative integer - ``P0`` - offset (default 0): Sage object which can be 'added' to P - - ``indexed`` - boolean (default False) + - ``indexed`` -- boolean (default ``False``) - If ``indexed==False`` then the iterator delivers ``P0+i*P`` + If ``indexed==False``, then the iterator delivers ``P0+i*P`` (if ``operation=='+'``) or ``P0*P**i`` (if ``operation=='*'``), for ``i`` in ``range(n)``. If ``indexed==True`` then the iterator delivers tuples - ``(i,P0+i*P)`` or ``(i,P0*P**i)``. + ``(i, P0+i*P)`` or ``(i, P0*P**i)``. - - ``operation`` - string: '+' (default ) or '*' or `other`. + - ``operation`` -- string: ``'+'`` (the default) or ``'*'`` or other. - If `other`, a function ``op()`` must be supplied (a function + If other, a function ``op()`` must be supplied (a function of 2 arguments) defining the group binary operation; also ``P0`` must be supplied. """ @@ -377,18 +384,18 @@ def bsgs(a, b, bounds, operation='*', identity=None, inverse=None, op=None): INPUT: - - ``a`` - group element - - ``b`` - group element - - ``bounds`` - a 2-tuple of integers ``(lower,upper)`` with ``0<=lower<=upper`` - - ``operation`` - string: '*', '+', 'other' - - ``identity`` - the identity element of the group - - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` + - ``a`` -- group element + - ``b`` -- group element + - ``bounds`` -- a 2-tuple of integers ``(lower,upper)`` with ``0<=lower<=upper`` + - ``operation`` -- string: ``'*'``, ``'+'``, other + - ``identity`` -- the identity element of the group + - ``inverse()`` -- function of 1 argument ``x``, returning inverse of ``x`` - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in the group OUTPUT: An integer `n` such that `a^n = b` (or `na = b`). If no - such `n` exists, this function raises a ValueError exception. + such `n` exists, this function raises a :class:`ValueError` exception. NOTE: This is a generalization of discrete logarithm. One situation where this version is useful is to find the order of @@ -403,27 +410,29 @@ def bsgs(a, b, bounds, operation='*', identity=None, inverse=None, op=None): sage: from sage.groups.generic import bsgs sage: b = Mod(2,37); a = b^20 - sage: bsgs(b, a, (0,36)) + sage: bsgs(b, a, (0, 36)) 20 - sage: p = next_prime(10^20) - sage: a = Mod(2,p); b = a^(10^25) - sage: bsgs(a, b, (10^25-10^6,10^25+10^6)) == 10^25 + sage: p = next_prime(10^20) # needs sage.libs.pari + sage: a = Mod(2,p); b = a^(10^25) # needs sage.libs.pari + sage: bsgs(a, b, (10^25 - 10^6, 10^25 + 10^6)) == 10^25 # needs sage.libs.pari True + sage: # needs sage.rings.finite_rings sage: K = GF(3^6,'b') sage: a = K.gen() sage: b = a^210 - sage: bsgs(a, b, (0,K.order()-1)) + sage: bsgs(a, b, (0, K.order() - 1)) 210 - sage: K.<z> = CyclotomicField(230) - sage: w = z^500 - sage: bsgs(z,w,(0,229)) + sage: K.<z> = CyclotomicField(230) # needs sage.rings.number_field + sage: w = z^500 # needs sage.rings.number_field + sage: bsgs(z, w, (0, 229)) # needs sage.rings.number_field 40 An additive example in an elliptic curve group:: + sage: # needs sage.rings.finite_rings sage.schemes sage: F.<a> = GF(37^5) sage: E = EllipticCurve(F, [1,1]) sage: P = E.lift_x(a); P @@ -431,7 +440,7 @@ def bsgs(a, b, bounds, operation='*', identity=None, inverse=None, op=None): This will return a multiple of the order of P:: - sage: bsgs(P,P.parent()(0),Hasse_bounds(F.order()),operation='+') + sage: bsgs(P, P.parent()(0), Hasse_bounds(F.order()), operation='+') # needs sage.rings.finite_rings sage.schemes 69327408 AUTHOR: @@ -513,9 +522,9 @@ def discrete_log_rho(a, base, ord=None, operation='*', identity=None, inverse=No to compute it - ``operation`` -- a string (default: ``'*'``) denoting whether we are in an additive group or a multiplicative one - - ``identity`` - the group's identity - - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` - - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in the group + - ``identity`` -- the group's identity + - ``inverse()`` -- function of 1 argument ``x``, returning inverse of ``x`` + - ``op()`` - function of 2 arguments ``x``, ``y``, returning ``x*y`` in the group - ``hash_function`` -- having an efficient hash function is critical for this algorithm (see examples) @@ -527,11 +536,12 @@ def discrete_log_rho(a, base, ord=None, operation='*', identity=None, inverse=No EXAMPLES:: - sage: F.<a> = GF(2^13) - sage: g = F.gen() - sage: discrete_log_rho(g^1234, g) + sage: F.<a> = GF(2^13) # needs sage.rings.finite_rings + sage: g = F.gen() # needs sage.rings.finite_rings + sage: discrete_log_rho(g^1234, g) # needs sage.rings.finite_rings 1234 + sage: # needs sage.rings.finite_rings sage.schemes sage: F.<a> = GF(37^5) sage: E = EllipticCurve(F, [1,1]) sage: G = (3*31*2^4)*E.lift_x(a) @@ -540,33 +550,36 @@ def discrete_log_rho(a, base, ord=None, operation='*', identity=None, inverse=No It also works with matrices:: - sage: A = matrix(GF(50021),[[10577,23999,28893],[14601,41019,30188],[3081,736,27092]]) - sage: discrete_log_rho(A^1234567, A) + sage: A = matrix(GF(50021), [[10577, 23999, 28893], # needs sage.rings.finite_rings + ....: [14601, 41019, 30188], + ....: [3081, 736, 27092]]) + sage: discrete_log_rho(A^1234567, A) # needs sage.rings.finite_rings 1234567 Beware, the order must be prime:: sage: I = IntegerModRing(171980) - sage: discrete_log_rho(I(2), I(3)) + sage: discrete_log_rho(I(2), I(3)) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: for Pollard rho algorithm the order of the group must be prime - If it fails to find a suitable logarithm, it raises a ``ValueError``:: + If it fails to find a suitable logarithm, it raises a :class:`ValueError`:: sage: I = IntegerModRing(171980) - sage: discrete_log_rho(I(31002),I(15501)) + sage: discrete_log_rho(I(31002), I(15501)) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: Pollard rho algorithm failed to find a logarithm The main limitation on the hash function is that we don't want to have - `hash(x*y) = hash(x) + hash(y)`:: + ``hash(x*y) == hash(x) + hash(y)``:: + sage: # needs sage.libs.pari sage: I = IntegerModRing(next_prime(2^23)) sage: def test(): ....: try: - ....: discrete_log_rho(I(123456),I(1),operation='+') + ....: discrete_log_rho(I(123456), I(1), operation='+') ....: except Exception: ....: print("FAILURE") sage: test() # random failure @@ -574,7 +587,8 @@ def discrete_log_rho(a, base, ord=None, operation='*', identity=None, inverse=No If this happens, we can provide a better hash function:: - sage: discrete_log_rho(I(123456),I(1),operation='+', hash_function=lambda x: hash(x*x)) + sage: discrete_log_rho(I(123456), I(1), operation='+', # needs sage.libs.pari + ....: hash_function=lambda x: hash(x*x)) 123456 AUTHOR: @@ -673,21 +687,21 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i INPUT: - - ``a`` - group element - - ``base`` - group element (the base) - - ``ord`` - integer (multiple of order of base, or ``None``) - - ``bounds`` - a priori bounds on the log - - ``operation`` - string: '*', '+', 'other' - - ``identity`` - the group's identity - - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` - - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in the group - - ``algorithm`` - string denoting what algorithm to use for prime-order logarithms: 'bsgs', 'rho', 'lambda' + - ``a`` -- group element + - ``base`` -- group element (the base) + - ``ord`` -- integer (multiple of order of base, or ``None``) + - ``bounds`` -- a priori bounds on the log + - ``operation`` -- string: ``'*'``, ``'+'``, other + - ``identity`` -- the group's identity + - ``inverse()`` - function of 1 argument ``x``, returning inverse of ``x`` + - ``op()`` - function of 2 arguments ``x``, ``y``, returning ``x*y`` in the group + - ``algorithm`` -- string denoting what algorithm to use for prime-order logarithms: ``'bsgs'``, ``'rho'``, ``'lambda'`` ``a`` and ``base`` must be elements of some group with identity - given by identity, inverse of ``x`` by ``inverse(x)``, and group + given by ``identity``, inverse of ``x`` by ``inverse(x)``, and group operation on ``x``, ``y`` by ``op(x,y)``. - If operation is '*' or '+' then the other + If operation is ``'*'`` or ``'+'``, then the other arguments are provided automatically; otherwise they must be provided by the caller. @@ -697,13 +711,13 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i assuming that ``ord`` is a multiple of the order of the base `b`. If ``ord`` is not specified, an attempt is made to compute it. - If no such `n` exists, this function raises a ``ValueError`` exception. + If no such `n` exists, this function raises a :class:`ValueError` exception. .. warning:: - If ``x`` has a log method, it is likely to be vastly faster + If ``x`` has a ``log`` method, it is likely to be vastly faster than using this function. E.g., if ``x`` is an integer modulo - `n`, use its log method instead! + `n`, use its ``log`` method instead! ALGORITHM: Pohlig-Hellman, Baby step giant step, Pollard's lambda/kangaroo, and Pollard's rho. @@ -716,10 +730,11 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: discrete_log(a, b, bounds=(10, 100)) 20 - sage: K = GF(3^6,'b') + sage: # needs sage.rings.finite_rings + sage: K = GF(3^6, 'b') sage: b = K.gen() sage: a = b^210 - sage: discrete_log(a, b, K.order()-1) + sage: discrete_log(a, b, K.order() - 1) 210 sage: b = Mod(1,37); x = Mod(2,37) @@ -735,63 +750,66 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i See :trac:`2356`:: - sage: F.<w> = GF(121) - sage: v = w^120 - sage: v.log(w) + sage: F.<w> = GF(121) # needs sage.rings.finite_rings + sage: v = w^120 # needs sage.rings.finite_rings + sage: v.log(w) # needs sage.rings.finite_rings 0 - sage: K.<z> = CyclotomicField(230) - sage: w = z^50 - sage: discrete_log(w,z) + sage: K.<z> = CyclotomicField(230) # needs sage.rings.number_field + sage: w = z^50 # needs sage.rings.number_field + sage: discrete_log(w, z) # needs sage.rings.number_field 50 An example where the order is infinite: note that we must give an upper bound here:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(23) - sage: eps = 5*a-24 # a fundamental unit + sage: eps = 5*a - 24 # a fundamental unit sage: eps.multiplicative_order() +Infinity sage: eta = eps^100 - sage: discrete_log(eta,eps,bounds=(0,1000)) + sage: discrete_log(eta, eps, bounds=(0,1000)) 100 In this case we cannot detect negative powers:: - sage: eta = eps^(-3) - sage: discrete_log(eta,eps,bounds=(0,100)) + sage: eta = eps^(-3) # needs sage.rings.number_field + sage: discrete_log(eta,eps,bounds=(0,100)) # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: no discrete log of -11515*a - 55224 found to base 5*a - 24 But we can invert the base (and negate the result) instead:: - sage: - discrete_log(eta^-1,eps,bounds=(0,100)) + sage: -discrete_log(eta^-1, eps, bounds=(0,100)) # needs sage.rings.number_field -3 An additive example: elliptic curve DLOG:: + sage: # needs sage.libs.gap sage.rings.finite_rings sage.schemes sage: F = GF(37^2,'a') - sage: E = EllipticCurve(F,[1,1]) + sage: E = EllipticCurve(F, [1,1]) sage: F.<a> = GF(37^2,'a') - sage: E = EllipticCurve(F,[1,1]) - sage: P = E(25*a + 16 , 15*a + 7 ) + sage: E = EllipticCurve(F, [1,1]) + sage: P = E(25*a + 16, 15*a + 7) sage: P.order() 672 sage: Q = 39*P; Q (36*a + 32 : 5*a + 12 : 1) - sage: discrete_log(Q,P,P.order(),operation='+') + sage: discrete_log(Q, P, P.order(), operation='+') 39 An example of big smooth group:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(2^63) sage: g = F.gen() sage: u = g**123456789 sage: discrete_log(u,g) 123456789 - The above examples also work when the 'rho' and 'lambda' algorithms are used:: + The above examples also work when the ``'rho'`` and ``'lambda'`` algorithms are used:: sage: b = Mod(2,37); a = b^20 sage: discrete_log(a, b, algorithm='rho') @@ -800,6 +818,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: discrete_log(a, b, algorithm='lambda', bounds=(10, 100)) 20 + sage: # needs sage.rings.finite_rings sage: K = GF(3^6,'b') sage: b = K.gen() sage: a = b^210 @@ -817,22 +836,24 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i ... ValueError: no discrete log of 2 found to base 1 - sage: F=GF(37^2,'a') - sage: E=EllipticCurve(F,[1,1]) - sage: F.<a>=GF(37^2,'a') - sage: E=EllipticCurve(F,[1,1]) - sage: P=E(25*a + 16 , 15*a + 7 ) + sage: # needs sage.libs.gap sage.rings.finite_rings sage.schemes + sage: F = GF(37^2,'a') + sage: E = EllipticCurve(F, [1,1]) + sage: F.<a> = GF(37^2,'a') + sage: E = EllipticCurve(F, [1,1]) + sage: P = E(25*a + 16, 15*a + 7) sage: P.order() 672 - sage: Q=39*P; Q + sage: Q = 39*P; Q (36*a + 32 : 5*a + 12 : 1) - sage: discrete_log(Q,P,P.order(),operation='+',algorithm='lambda') + sage: discrete_log(Q, P, P.order(), operation='+', algorithm='lambda') 39 + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(2^63) sage: g = F.gen() sage: u = g**123456789 - sage: discrete_log(u,g,algorithm='rho') + sage: discrete_log(u, g, algorithm='rho') 123456789 TESTS: @@ -849,8 +870,8 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: kwargs = {'operation': '+'} sage: kwargs['algorithm'] = choice(['bsgs', 'rho', 'lambda']) sage: if randrange(2): - ....: lo = randrange(-order, sol+1) - ....: hi = randrange(sol+1, 2*order) + ....: lo = randrange(-order, sol + 1) + ....: hi = randrange(sol + 1, 2*order) ....: assert lo <= sol <= hi ....: kwargs['bounds'] = (lo, hi) sage: try: @@ -935,7 +956,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i if running_mod > bound: break # we have log%running_mod. if we know that log<running_mod, then we have the value of log. l = l[:i + 1] - from sage.arith.all import CRT_list + from sage.arith.misc import CRT_list return (CRT_list(l, mods) + offset) % ord except ValueError: raise ValueError("no discrete log of %s found to base %s" % (a, base)) @@ -973,10 +994,11 @@ def discrete_log_lambda(a, base, bounds, operation='*', identity=None, inverse=N EXAMPLES:: - sage: F.<a> = GF(2^63) - sage: discrete_log_lambda(a^1234567, a, (1200000,1250000)) + sage: F.<a> = GF(2^63) # needs sage.rings.finite_rings + sage: discrete_log_lambda(a^1234567, a, (1200000,1250000)) # needs sage.rings.finite_rings 1234567 + sage: # needs sage.rings.finite_rings sage.schemes sage: F.<a> = GF(37^5) sage: E = EllipticCurve(F, [1,1]) sage: P = E.lift_x(a); P @@ -984,12 +1006,14 @@ def discrete_log_lambda(a, base, bounds, operation='*', identity=None, inverse=N This will return a multiple of the order of P:: - sage: discrete_log_lambda(P.parent()(0), P, Hasse_bounds(F.order()), operation='+') + sage: discrete_log_lambda(P.parent()(0), P, Hasse_bounds(F.order()), # needs sage.rings.finite_rings sage.schemes + ....: operation='+') 69327408 - sage: K.<a> = GF(89**5) + sage: K.<a> = GF(89**5) # needs sage.rings.finite_rings sage: hs = lambda x: hash(x) + 15 - sage: discrete_log_lambda(a**(89**3 - 3), a, (89**2, 89**4), operation = '*', hash_function = hs) # long time (10s on sage.math, 2011) + sage: discrete_log_lambda(a**(89**3 - 3), # long time (10s on sage.math, 2011), needs sage.rings.finite_rings + ....: a, (89**2, 89**4), operation='*', hash_function=hs) 704966 AUTHOR: @@ -1082,25 +1106,27 @@ def linear_relation(P, Q, operation='+', identity=None, inverse=None, op=None): An additive example (in an elliptic curve group):: + sage: # needs sage.rings.finite_rings sage.schemes sage: F.<a> = GF(3^6,'a') - sage: E = EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a,a^4 + a^3 + 2*a + 1]) - sage: P = E(a^5 + a^4 + a^3 + a^2 + a + 2 , 0) - sage: Q = E(2*a^3 + 2*a^2 + 2*a , a^3 + 2*a^2 + 1) - sage: linear_relation(P,Q,'+') + sage: E = EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a, a^4 + a^3 + 2*a + 1]) + sage: P = E(a^5 + a^4 + a^3 + a^2 + a + 2, 0) + sage: Q = E(2*a^3 + 2*a^2 + 2*a, a^3 + 2*a^2 + 1) + sage: linear_relation(P, Q, '+') (1, 2) sage: P == 2*Q True A multiplicative example (in a finite field's multiplicative group):: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(3^6,'a') sage: a.multiplicative_order().factor() 2^3 * 7 * 13 sage: b = a^7 sage: c = a^13 - sage: linear_relation(b,c,'*') + sage: linear_relation(b, c, '*') (13, 7) - sage: b^13==c^7 + sage: b^13 == c^7 True """ Z = integer_ring.ZZ @@ -1164,16 +1190,16 @@ def order_from_multiple(P, m, plist=None, factorization=None, check=True, INPUT: - - ``P`` - a Sage object which is a group element; - - ``m`` - a Sage integer which is a multiple of the order of ``P``, + - ``P`` -- a Sage object which is a group element; + - ``m`` -- a Sage integer which is a multiple of the order of ``P``, i.e. we require that ``m*P=0`` (or ``P**m=1``); - - ``check`` - a Boolean (default:True), indicating whether we check if ``m`` + - ``check`` -- a Boolean (default: ``True``), indicating whether we check if ``m`` really is a multiple of the order; - - ``factorization`` - the factorization of ``m``, or ``None`` in which + - ``factorization`` -- the factorization of ``m``, or ``None`` in which case this function will need to factor ``m``; - - ``plist`` - a list of the prime factors of ``m``, or ``None`` - kept for compatibility only, + - ``plist`` -- a list of the prime factors of ``m``, or ``None`` - kept for compatibility only, prefer the use of ``factorization``; - - ``operation`` - string: '+' (default) or '*'. + - ``operation`` -- string: ``'+'`` (default) or ``'*'``. .. note:: @@ -1183,12 +1209,16 @@ def order_from_multiple(P, m, plist=None, factorization=None, check=True, EXAMPLES:: sage: from sage.groups.generic import order_from_multiple + + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^5) sage: b = a^4 - sage: order_from_multiple(b,5^5-1,operation='*') + sage: order_from_multiple(b, 5^5 - 1, operation='*') 781 - sage: E = EllipticCurve(k,[2,4]) - sage: P = E(3*a^4 + 3*a , 2*a + 1 ) + + sage: # needs sage.rings.finite_rings sage.schemes + sage: E = EllipticCurve(k, [2,4]) + sage: P = E(3*a^4 + 3*a, 2*a + 1) sage: M = E.cardinality(); M 3227 sage: F = M.factor() @@ -1198,18 +1228,22 @@ def order_from_multiple(P, m, plist=None, factorization=None, check=True, sage: order_from_multiple(Q, M, factorization=F, operation='+') 7 + sage: # needs sage.rings.number_field sage: K.<z> = CyclotomicField(230) sage: w = z^50 - sage: order_from_multiple(w,230,operation='*') + sage: order_from_multiple(w, 230, operation='*') 23 + sage: # needs sage.rings.finite_rings sage: F = GF(2^1279,'a') - sage: n = F.cardinality()-1 # Mersenne prime - sage: order_from_multiple(F.random_element(),n,factorization=[(n,1)],operation='*') == n + sage: n = F.cardinality() - 1 # Mersenne prime + sage: order_from_multiple(F.random_element(), n, + ....: factorization=[(n,1)], operation='*') == n True + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(3^60) - sage: order_from_multiple(a, 3^60-1, operation='*', check=False) + sage: order_from_multiple(a, 3^60 - 1, operation='*', check=False) 42391158275216203514294433200 """ Z = integer_ring.ZZ @@ -1294,21 +1328,21 @@ def order_from_bounds(P, bounds, d=None, operation='+', INPUT: - - ``P`` - a Sage object which is a group element + - ``P`` -- a Sage object which is a group element - - ``bounds`` - a 2-tuple ``(lb,ub)`` such that ``m*P=0`` (or + - ``bounds`` -- a 2-tuple ``(lb,ub)`` such that ``m*P=0`` (or ``P**m=1``) for some ``m`` with ``lb<=m<=ub``. - - ``d`` - (optional) a positive integer; only ``m`` which are + - ``d`` -- (optional) a positive integer; only ``m`` which are multiples of this will be considered. - - ``operation`` - string: '+' (default ) or '*' or other. + - ``operation`` -- string: ``'+'`` (default ) or ``'*'`` or other. If other, the following must be supplied: - - ``identity``: the identity element for the group; - - ``inverse()``: a function of one argument giving the inverse + - ``identity`` -- the identity element for the group; + - ``inverse()`` -- a function of one argument giving the inverse of a group element; - - ``op()``: a function of 2 arguments defining the group binary + - ``op()`` -- a function of 2 arguments defining the group binary operation. @@ -1321,12 +1355,16 @@ def order_from_bounds(P, bounds, d=None, operation='+', EXAMPLES:: sage: from sage.groups.generic import order_from_bounds + + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^5) sage: b = a^4 - sage: order_from_bounds(b,(5^4,5^5),operation='*') + sage: order_from_bounds(b, (5^4, 5^5), operation='*') 781 - sage: E = EllipticCurve(k,[2,4]) - sage: P = E(3*a^4 + 3*a , 2*a + 1 ) + + sage: # needs sage.rings.finite_rings sage.schemes + sage: E = EllipticCurve(k, [2,4]) + sage: P = E(3*a^4 + 3*a, 2*a + 1) sage: bounds = Hasse_bounds(5^5) sage: Q = E(0,2) sage: order_from_bounds(Q, bounds, operation='+') @@ -1334,9 +1372,10 @@ def order_from_bounds(P, bounds, d=None, operation='+', sage: order_from_bounds(P, bounds, 7, operation='+') 3227 - sage: K.<z>=CyclotomicField(230) + sage: # needs sage.rings.number_field + sage: K.<z> = CyclotomicField(230) sage: w = z^50 - sage: order_from_bounds(w,(200,250),operation='*') + sage: order_from_bounds(w, (200, 250), operation='*') 23 """ from operator import mul, add @@ -1378,15 +1417,14 @@ def merge_points(P1, P2, operation='+', - ``P1`` -- a pair `(g_1,n_1)` where `g_1` is a group element of order `n_1` - ``P2`` -- a pair `(g_2,n_2)` where `g_2` is a group element of order `n_2` - - ``operation`` -- string: '+' (default ) or '*' or other. If + - ``operation`` -- string: ``'+'`` (default) or ``'*'`` or other. If other, the following must be supplied: - - ``identity``: the identity element for the group; - - ``inverse()``: a function of one argument giving the inverse - of a group element; - - ``op()``: a function of 2 arguments defining the group - binary operation. - + - ``identity`` -- the identity element for the group; + - ``inverse()`` -- a function of one argument giving the inverse + of a group element; + - ``op()`` -- a function of 2 arguments defining the group + binary operation. OUTPUT: @@ -1394,28 +1432,30 @@ def merge_points(P1, P2, operation='+', EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.groups.generic import merge_points - sage: F.<a>=GF(3^6,'a') + sage: F.<a> = GF(3^6,'a') sage: b = a^7 sage: c = a^13 sage: ob = (3^6-1)//7 sage: oc = (3^6-1)//13 - sage: merge_points((b,ob),(c,oc),operation='*') + sage: merge_points((b,ob), (c,oc), operation='*') (a^4 + 2*a^3 + 2*a^2, 728) - sage: d,od = merge_points((b,ob),(c,oc),operation='*') + sage: d, od = merge_points((b,ob), (c,oc), operation='*') sage: od == d.multiplicative_order() True - sage: od == lcm(ob,oc) + sage: od == lcm(ob, oc) True - sage: E = EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a,a^4 + a^3 + 2*a + 1]) - sage: P = E(2*a^5 + 2*a^4 + a^3 + 2 , a^4 + a^3 + a^2 + 2*a + 2) + sage: # needs sage.libs.gap sage.rings.finite_rings sage.schemes + sage: E = EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a, a^4 + a^3 + 2*a + 1]) + sage: P = E(2*a^5 + 2*a^4 + a^3 + 2, a^4 + a^3 + a^2 + 2*a + 2) sage: P.order() 7 - sage: Q = E(2*a^5 + 2*a^4 + 1 , a^5 + 2*a^3 + 2*a + 2 ) + sage: Q = E(2*a^5 + 2*a^4 + 1, a^5 + 2*a^3 + 2*a + 2) sage: Q.order() 4 - sage: R,m = merge_points((P,7),(Q,4), operation='+') + sage: R, m = merge_points((P,7), (Q,4), operation='+') sage: R.order() == m True sage: m == lcm(7,4) @@ -1466,12 +1506,12 @@ def structure_description(G, latex=False): INPUT: - - ``latex`` -- a boolean (default: ``False``). If ``True`` return a + - ``latex`` -- a boolean (default: ``False``). If ``True``, return a LaTeX formatted string. OUTPUT: - - string + string .. WARNING:: @@ -1483,6 +1523,7 @@ def structure_description(G, latex=False): EXAMPLES:: + sage: # needs sage.groups sage: G = CyclicPermutationGroup(6) sage: G.structure_description() 'C6' @@ -1495,26 +1536,26 @@ def structure_description(G, latex=False): This method is mainly intended for small groups or groups with few normal subgroups. Even then there are some surprises:: - sage: D3 = DihedralGroup(3) - sage: D3.structure_description() + sage: D3 = DihedralGroup(3) # needs sage.groups + sage: D3.structure_description() # needs sage.groups 'S3' We use the Sage notation for the degree of dihedral groups:: - sage: D4 = DihedralGroup(4) - sage: D4.structure_description() + sage: D4 = DihedralGroup(4) # needs sage.groups + sage: D4.structure_description() # needs sage.groups 'D4' Works for finitely presented groups (:trac:`17573`):: - sage: F.<x, y> = FreeGroup() - sage: G = F / [x^2*y^-1, x^3*y^2, x*y*x^-1*y^-1] - sage: G.structure_description() + sage: F.<x, y> = FreeGroup() # needs sage.groups + sage: G = F / [x^2*y^-1, x^3*y^2, x*y*x^-1*y^-1] # needs sage.groups + sage: G.structure_description() # needs sage.groups 'C7' And matrix groups (:trac:`17573`):: - sage: groups.matrix.GL(4,2).structure_description() + sage: groups.matrix.GL(4,2).structure_description() # needs sage.libs.gap sage.modules 'A8' """ import re diff --git a/src/sage/groups/group.pyx b/src/sage/groups/group.pyx index b829bbf68bf..cd2521e3478 100644 --- a/src/sage/groups/group.pyx +++ b/src/sage/groups/group.pyx @@ -17,12 +17,8 @@ Base class for groups # https://www.gnu.org/licenses/ # **************************************************************************** -import random - from sage.structure.parent cimport Parent from sage.rings.infinity import infinity -from sage.rings.integer_ring import ZZ -from sage.misc.lazy_attribute import lazy_attribute def is_Group(x): @@ -39,9 +35,9 @@ def is_Group(x): EXAMPLES:: - sage: F.<a,b> = FreeGroup() + sage: F.<a,b> = FreeGroup() # needs sage.combinat sage: from sage.groups.group import is_Group - sage: is_Group(F) + sage: is_Group(F) # needs sage.combinat True sage: is_Group("a string") False @@ -91,7 +87,7 @@ cdef class Group(Parent): sage: G = Group(category=Groups()) # todo: do the same test with some subcategory of Groups when there will exist one sage: G.category() Category of groups - sage: G = Group(category = CommutativeAdditiveGroups()) + sage: G = Group(category=CommutativeAdditiveGroups()) Traceback (most recent call last): ... ValueError: (Category of commutative additive groups,) is not a subcategory of Category of groups @@ -100,6 +96,7 @@ cdef class Group(Parent): Check for :trac:`8119`:: + sage: # needs sage.groups sage: G = SymmetricGroup(2) sage: h = hash(G) sage: G.rename('S2') @@ -143,7 +140,7 @@ cdef class Group(Parent): EXAMPLES:: - sage: SL(2, 7).is_commutative() + sage: SL(2, 7).is_commutative() # needs sage.modules sage.rings.finite_rings False """ return self.is_abelian() @@ -165,8 +162,8 @@ cdef class Group(Parent): TESTS:: - sage: H = SL(2, QQ) - sage: H.order() + sage: H = SL(2, QQ) # needs sage.modules + sage: H.order() # needs sage.modules +Infinity """ try: @@ -215,17 +212,15 @@ cdef class Group(Parent): EXAMPLES:: - sage: G = AbelianGroup([2,3,4,5]) - sage: G.an_element() + sage: G = AbelianGroup([2,3,4,5]) # needs sage.groups + sage: G.an_element() # needs sage.groups f0*f1*f2*f3 """ - from sage.misc.misc_c import prod - return prod(self.gens()) + return self.prod(self.gens()) def quotient(self, H, **kwds): """ - Return the quotient of this group by the normal subgroup - `H`. + Return the quotient of this group by the normal subgroup `H`. EXAMPLES:: diff --git a/src/sage/groups/group_exp.py b/src/sage/groups/group_exp.py index 4f3d27a8def..ffae5e73cb2 100644 --- a/src/sage/groups/group_exp.py +++ b/src/sage/groups/group_exp.py @@ -357,4 +357,5 @@ def group_generators(self): raise AttributeError("Additive group has no method 'gens'") return tuple([self(x) for x in additive_generators]) + GroupExp_Class.Element = GroupExpElement diff --git a/src/sage/groups/group_semidirect_product.py b/src/sage/groups/group_semidirect_product.py index 3ac629b9411..1805dbbc53a 100644 --- a/src/sage/groups/group_semidirect_product.py +++ b/src/sage/groups/group_semidirect_product.py @@ -33,7 +33,8 @@ def _repr_(self): sage: def twist(x,y): ....: return y - sage: GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), WeylGroup(['A',3],prefix="t"),twist) # indirect doctest + sage: GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), # indirect doctest + ....: WeylGroup(['A',3],prefix="t"), twist) Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space) acting on Weyl Group of type ['A', 3] @@ -67,6 +68,7 @@ def __invert__(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: L = RootSystem(['A',2]).root_lattice() sage: from sage.groups.group_exp import GroupExp sage: EL = GroupExp()(L) @@ -95,6 +97,7 @@ def to_opposite(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: L = RootSystem(['A',2]).root_lattice(); L Root lattice of the Root system of type ['A', 2] sage: from sage.groups.group_exp import GroupExp @@ -117,7 +120,10 @@ def to_opposite(self): sage: g.to_opposite() t[-2*alpha[1]] * s1*s2 sage: g.to_opposite().parent() - Semidirect product of Multiplicative form of Root lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the root lattice) + Semidirect product of + Multiplicative form of Root lattice of the Root system of type ['A', 2] + acted upon by Weyl Group of type ['A', 2] + (as a matrix group acting on the root lattice) """ par = self.parent() Gop = par.opposite_semidirect_product() @@ -141,7 +147,7 @@ class GroupSemidirectProduct(CartesianProduct): - ``prefix0`` -- (default: ``None``) optional string - ``prefix1`` -- (default: ``None``) optional string - ``print_tuple`` -- ``True`` or ``False`` (default: ``False``) - - ``category`` -- A category (default: Groups()) + - ``category`` -- A category (default: ``Groups()``) A semidirect product of groups `G` and `H` is a group structure on the Cartesian product `G \times H` whose product agrees with that @@ -207,10 +213,10 @@ class GroupSemidirectProduct(CartesianProduct): sage: G = GL(2,QQ) sage: V = QQ^2 - sage: EV = GroupExp()(V) # make a multiplicative version of V + sage: EV = GroupExp()(V) # make a multiplicative version of V sage: def twist(g,v): ....: return EV(g*v.value) - sage: H = GroupSemidirectProduct(G, EV, twist=twist, prefix1 = 't'); H + sage: H = GroupSemidirectProduct(G, EV, twist=twist, prefix1='t'); H Semidirect product of General Linear Group of degree 2 over Rational Field acting on Multiplicative form of Vector space of dimension 2 over Rational Field @@ -218,11 +224,13 @@ class GroupSemidirectProduct(CartesianProduct): t[(1, 0)] sage: x^2 t[(2, 0)] + + sage: # needs sage.rings.number_field sage: cartan_type = CartanType(['A',2]) sage: W = WeylGroup(cartan_type, prefix="s") sage: def twist(w,v): ....: return w*v*(~w) - sage: WW = GroupSemidirectProduct(W,W, twist=twist, print_tuple=True) + sage: WW = GroupSemidirectProduct(W, W, twist=twist, print_tuple=True) sage: s = Family(cartan_type.index_set(), lambda i: W.simple_reflection(i)) sage: y = WW((s[1],s[2])); y (s1, s2) @@ -247,7 +255,8 @@ def __init__(self, G, H, twist=None, act_to_right=True, prefix0=None, ....: return y sage: import __main__ sage: __main__.twist = twist - sage: G = GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), WeylGroup(['A',3],prefix="t"),twist) + sage: G = GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), + ....: WeylGroup(['A',3],prefix="t"), twist) sage: TestSuite(G).run() The ``__main__`` business is a trick to pass the pickling test. @@ -289,7 +298,8 @@ def act_to_right(self): sage: def twist(x,y): ....: return y - sage: GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), WeylGroup(['A',3],prefix="t"),twist).act_to_right() + sage: GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), + ....: WeylGroup(['A',3],prefix="t"), twist).act_to_right() True """ return self._act_to_right @@ -302,7 +312,8 @@ def _repr_(self): sage: def twist(x,y): ....: return y - sage: GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), WeylGroup(['A',3],prefix="t"),twist) # indirect doctest + sage: GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), # indirect doctest + ....: WeylGroup(['A',3],prefix="t"), twist) Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space) acting on Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space) @@ -324,7 +335,8 @@ def _element_constructor_(self, x): ....: return y sage: import __main__ sage: __main__.twist = twist - sage: g = GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), WeylGroup(['A',3],prefix="t"),twist).an_element() + sage: g = GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), + ....: WeylGroup(['A',3],prefix="t"), twist).an_element() sage: TestSuite(g).run() """ def type_error(): @@ -354,10 +366,10 @@ def one(self): sage: G = GL(2,QQ) sage: V = QQ^2 - sage: EV = GroupExp()(V) # make a multiplicative version of V + sage: EV = GroupExp()(V) # make a multiplicative version of V sage: def twist(g,v): ....: return EV(g*v.value) - sage: one = GroupSemidirectProduct(G, EV, twist=twist, prefix1 = 't').one(); one + sage: one = GroupSemidirectProduct(G, EV, twist=twist, prefix1='t').one(); one 1 sage: one.cartesian_projection(0) [1 0] @@ -378,7 +390,7 @@ def group_generators(self): sage: import __main__ sage: __main__.twist = twist sage: EZ = GroupExp()(ZZ) - sage: GroupSemidirectProduct(EZ,EZ,twist,print_tuple=True).group_generators() + sage: GroupSemidirectProduct(EZ, EZ, twist, print_tuple=True).group_generators() ((1, 0), (0, 1)) """ def has_gens(G): @@ -404,10 +416,10 @@ def product(self, x, y): sage: G = GL(2,QQ) sage: V = QQ^2 - sage: EV = GroupExp()(V) # make a multiplicative version of V + sage: EV = GroupExp()(V) # make a multiplicative version of V sage: def twist(g,v): ....: return EV(g*v.value) - sage: S = GroupSemidirectProduct(G, EV, twist=twist, prefix1 = 't') + sage: S = GroupSemidirectProduct(G, EV, twist=twist, prefix1='t') sage: g = G([[2,1],[3,1]]); g [2 1] [3 1] @@ -442,7 +454,8 @@ def opposite_semidirect_product(self): sage: G = GL(2,QQ) sage: L = QQ^2 sage: EL = GroupExp()(L) - sage: H = GroupSemidirectProduct(G, EL, twist = lambda g,v: EL(g*v.value), prefix1 = 't'); H + sage: H = GroupSemidirectProduct(G, EL, prefix1='t', + ....: twist=lambda g,v: EL(g*v.value)); H Semidirect product of General Linear Group of degree 2 over Rational Field acting on Multiplicative form of Vector space of dimension 2 over Rational Field @@ -479,7 +492,8 @@ def construction(self): sage: def twist(x,y): ....: return y - sage: H = GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), WeylGroup(['A',3],prefix="t"), twist) + sage: H = GroupSemidirectProduct(WeylGroup(['A',2],prefix="s"), + ....: WeylGroup(['A',3],prefix="t"), twist) sage: H.construction() """ return None diff --git a/src/sage/groups/groups_catalog.py b/src/sage/groups/groups_catalog.py index 47e6e230508..a95ffaefb4a 100644 --- a/src/sage/groups/groups_catalog.py +++ b/src/sage/groups/groups_catalog.py @@ -101,9 +101,13 @@ # groups.presentation - free groups with relations # groups.symmetries - permutation groups of regular solids, or similar -from sage.groups.matrix_gps import catalog as matrix -from sage.groups.perm_gps import permutation_groups_catalog as permutation -from sage.groups.misc_gps import misc_groups_catalog as misc -from sage.groups.affine_gps import catalog as affine -from sage.groups.lie_gps import catalog as lie -from sage.groups import finitely_presented_catalog as presentation +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.groups.matrix_gps', 'catalog', as_='matrix') +lazy_import('sage.groups.perm_gps', 'permutation_groups_catalog', as_='permutation') +lazy_import('sage.groups.misc_gps', 'misc_groups_catalog', as_='misc') +lazy_import('sage.groups.affine_gps', 'catalog', as_='affine') +lazy_import('sage.groups', 'finitely_presented_catalog', as_='presentation') +lazy_import('sage.groups.lie_gps', 'catalog', as_='lie') + +del lazy_import diff --git a/src/sage/groups/indexed_free_group.py b/src/sage/groups/indexed_free_group.py index 0cbcf9b8a2d..287ab021b1d 100644 --- a/src/sage/groups/indexed_free_group.py +++ b/src/sage/groups/indexed_free_group.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat """ Indexed Free Groups diff --git a/src/sage/groups/kernel_subgroup.py b/src/sage/groups/kernel_subgroup.py index 024e8f47b3b..605778784e4 100644 --- a/src/sage/groups/kernel_subgroup.py +++ b/src/sage/groups/kernel_subgroup.py @@ -94,8 +94,8 @@ def defining_morphism(self): EXAMPLES:: - sage: PJ3 = groups.misc.PureCactus(3) - sage: PJ3.defining_morphism() + sage: PJ3 = groups.misc.PureCactus(3) # needs sage.rings.number_field + sage: PJ3.defining_morphism() # needs sage.rings.number_field Conversion via _from_cactus_group_element map: From: Cactus Group with 3 fruit To: Symmetric group of order 3! as a permutation group @@ -109,8 +109,8 @@ def ambient(self): EXAMPLES:: - sage: PJ3 = groups.misc.PureCactus(3) - sage: PJ3.ambient() + sage: PJ3 = groups.misc.PureCactus(3) # needs sage.rings.number_field + sage: PJ3.ambient() # needs sage.rings.number_field Cactus Group with 3 fruit """ return self._morphism.domain() @@ -121,8 +121,8 @@ def _an_element_(self): EXAMPLES:: - sage: PJ3 = groups.misc.PureCactus(3) - sage: PJ3.an_element() + sage: PJ3 = groups.misc.PureCactus(3) # needs sage.rings.number_field + sage: PJ3.an_element() # needs sage.rings.number_field 1 """ return self.element_class(self, self.ambient().one()) @@ -133,8 +133,8 @@ def lift(self, x): EXAMPLES:: - sage: PJ3 = groups.misc.PureCactus(3) - sage: PJ3.lift(PJ3.an_element()).parent() + sage: PJ3 = groups.misc.PureCactus(3) # needs sage.rings.number_field + sage: PJ3.lift(PJ3.an_element()).parent() # needs sage.rings.number_field Cactus Group with 3 fruit """ return x.value @@ -145,6 +145,7 @@ def retract(self, x): EXAMPLES:: + sage: # needs sage.rings.number_field sage: J3 = groups.misc.Cactus(3) sage: s12,s13,s23 = J3.group_generators() sage: PJ3 = groups.misc.PureCactus(3) @@ -161,6 +162,7 @@ def _element_constructor_(self, x): EXAMPLES:: + sage: # needs sage.rings.number_field sage: J3 = groups.misc.Cactus(3) sage: s12,s13,s23 = J3.group_generators() sage: PJ3 = groups.misc.PureCactus(3) @@ -200,6 +202,7 @@ def _mul_(self, other): EXAMPLES:: + sage: # needs sage.rings.number_field sage: J3 = groups.misc.Cactus(3) sage: s12,s13,s23 = J3.group_generators() sage: PJ3 = groups.misc.PureCactus(3) @@ -215,6 +218,7 @@ def __invert__(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: J3 = groups.misc.Cactus(3) sage: s12,s13,s23 = J3.group_generators() sage: PJ3 = groups.misc.PureCactus(3) diff --git a/src/sage/groups/libgap_mixin.py b/src/sage/groups/libgap_mixin.py index b51679410e1..e2da04e9ed3 100644 --- a/src/sage/groups/libgap_mixin.py +++ b/src/sage/groups/libgap_mixin.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules """ Mix-in Class for GAP-based Groups @@ -250,8 +251,8 @@ def conjugacy_classes_representatives(self): EXAMPLES:: - sage: G = SU(3,GF(2)) - sage: len(G.conjugacy_classes_representatives()) + sage: G = SU(3,GF(2)) # needs sage.rings.finite_rings + sage: len(G.conjugacy_classes_representatives()) # needs sage.rings.finite_rings 16 sage: G = GL(2,GF(3)) @@ -261,7 +262,7 @@ def conjugacy_classes_representatives(self): [0 1], [1 1], [0 2], [1 2], [1 0], [1 2], [1 1], [0 1] ) - sage: len(GU(2,GF(5)).conjugacy_classes_representatives()) + sage: len(GU(2,GF(5)).conjugacy_classes_representatives()) # needs sage.rings.finite_rings 36 :: @@ -338,8 +339,8 @@ class function on the conjugacy classes, in that order. EXAMPLES:: sage: G = GL(2,GF(3)) - sage: chi = G.class_function(range(8)) - sage: list(chi) + sage: chi = G.class_function(range(8)) # needs sage.rings.number_field + sage: list(chi) # needs sage.rings.number_field [0, 1, 2, 3, 4, 5, 6, 7] """ from sage.groups.class_function import ClassFunction_libgap @@ -348,7 +349,7 @@ class function on the conjugacy classes, in that order. @cached_method def center(self): """ - Return the center of this linear group as a subgroup. + Return the center of this group as a subgroup. OUTPUT: @@ -356,25 +357,25 @@ def center(self): EXAMPLES:: - sage: G = SU(3,GF(2)) - sage: G.center() + sage: G = SU(3, GF(2)) # needs sage.rings.finite_rings + sage: G.center() # needs sage.rings.finite_rings Subgroup with 1 generators ( [a 0 0] [0 a 0] [0 0 a] ) of Special Unitary Group of degree 3 over Finite Field in a of size 2^2 - sage: GL(2,GF(3)).center() + sage: GL(2, GF(3)).center() Subgroup with 1 generators ( [2 0] [0 2] ) of General Linear Group of degree 2 over Finite Field of size 3 - sage: GL(3,GF(3)).center() + sage: GL(3, GF(3)).center() Subgroup with 1 generators ( [2 0 0] [0 2 0] [0 0 2] ) of General Linear Group of degree 3 over Finite Field of size 3 - sage: GU(3,GF(2)).center() + sage: GU(3, GF(2)).center() # needs sage.rings.finite_rings Subgroup with 1 generators ( [a + 1 0 0] [ 0 a + 1 0] @@ -393,13 +394,219 @@ def center(self): [0 3 0] [0 1 0] [0 0 1], [0 1 1] ) + + sage: GL = groups.matrix.GL(3, ZZ) + sage: GL.center() + Traceback (most recent call last): + ... + NotImplementedError: group must be finite """ + if not self.is_finite(): + raise NotImplementedError("group must be finite") G = self.gap() center = list(G.Center().GeneratorsOfGroup()) - if len(center) == 0: + if not center: center = [G.One()] return self.subgroup(center) + def centralizer(self, g): + r""" + Return the centralizer of ``g`` in ``self``. + + EXAMPLES:: + + sage: G = groups.matrix.GL(2, 3) + sage: g = G([[1,1], [1,0]]) + sage: C = G.centralizer(g); C + Subgroup with 3 generators ( + [1 1] [2 0] [2 1] + [1 0], [0 2], [1 1] + ) of General Linear Group of degree 2 over Finite Field of size 3 + sage: C.order() + 8 + + sage: S = G.subgroup([G([[2,0],[0,2]]), G([[0,1],[2,0]])]); S + Subgroup with 2 generators ( + [2 0] [0 1] + [0 2], [2 0] + ) of General Linear Group of degree 2 over Finite Field of size 3 + sage: G.centralizer(S) + Subgroup with 3 generators ( + [2 0] [0 1] [2 2] + [0 2], [2 0], [1 2] + ) of General Linear Group of degree 2 over Finite Field of size 3 + sage: G = GL(3,2) + sage: all(G.order() == G.centralizer(x).order() * G.conjugacy_class(x).cardinality() + ....: for x in G) + True + sage: H = groups.matrix.Heisenberg(2) + sage: H.centralizer(H.an_element()) + Traceback (most recent call last): + ... + NotImplementedError: group must be finite + """ + if not self.is_finite(): + raise NotImplementedError("group must be finite") + G = self.gap() + centralizer_gens = list(G.Centralizer(g).GeneratorsOfGroup()) + if not centralizer_gens: + centralizer_gens = [G.One()] + return self.subgroup(centralizer_gens) + + def subgroups(self): + r""" + Return a list of all the subgroups of ``self``. + + OUTPUT: + + Each possible subgroup of ``self`` is contained once in the returned + list. The list is in order, according to the size of the subgroups, + from the trivial subgroup with one element on through up to the whole + group. Conjugacy classes of subgroups are contiguous in the list. + + .. WARNING:: + + For even relatively small groups this method can take a very long + time to execute, or create vast amounts of output. Likely both. + Its purpose is instructional, as it can be useful for studying + small groups. + + For faster results, which still exhibit the structure of + the possible subgroups, use :meth:`conjugacy_classes_subgroups`. + + EXAMPLES:: + + sage: G = groups.matrix.GL(2, 2) + sage: G.subgroups() + [Subgroup with 0 generators () + of General Linear Group of degree 2 over Finite Field of size 2, + Subgroup with 1 generators ( + [0 1] + [1 0] + ) of General Linear Group of degree 2 over Finite Field of size 2, + Subgroup with 1 generators ( + [1 0] + [1 1] + ) of General Linear Group of degree 2 over Finite Field of size 2, + Subgroup with 1 generators ( + [1 1] + [0 1] + ) of General Linear Group of degree 2 over Finite Field of size 2, + Subgroup with 1 generators ( + [0 1] + [1 1] + ) of General Linear Group of degree 2 over Finite Field of size 2, + Subgroup with 2 generators ( + [0 1] [1 1] + [1 1], [0 1] + ) of General Linear Group of degree 2 over Finite Field of size 2] + + sage: H = groups.matrix.Heisenberg(2) + sage: H.subgroups() + Traceback (most recent call last): + ... + NotImplementedError: group must be finite + """ + if not self.is_finite(): + raise NotImplementedError("group must be finite") + ccs = self.gap().ConjugacyClassesSubgroups() + return [self.subgroup(h.GeneratorsOfGroup()) + for cc in ccs for h in cc.Elements()] + + def conjugacy_classes_subgroups(self): + r""" + Return a complete list of representatives of conjugacy classes of + subgroups in ``self``. + + The ordering is that given by GAP. + + EXAMPLES:: + + sage: G = groups.matrix.GL(2,2) + sage: G.conjugacy_classes_subgroups() + [Subgroup with 0 generators () + of General Linear Group of degree 2 over Finite Field of size 2, + Subgroup with 1 generators ( + [1 1] + [0 1] + ) of General Linear Group of degree 2 over Finite Field of size 2, + Subgroup with 1 generators ( + [0 1] + [1 1] + ) of General Linear Group of degree 2 over Finite Field of size 2, + Subgroup with 2 generators ( + [0 1] [1 1] + [1 1], [0 1] + ) of General Linear Group of degree 2 over Finite Field of size 2] + + sage: H = groups.matrix.Heisenberg(2) + sage: H.conjugacy_classes_subgroups() + Traceback (most recent call last): + ... + NotImplementedError: group must be finite + """ + if not self.is_finite(): + raise NotImplementedError("group must be finite") + return [self.subgroup(sub.Representative().GeneratorsOfGroup()) + for sub in self.gap().ConjugacyClassesSubgroups()] + + def group_id(self): + r""" + Return the ID code of ``self``, which is a list of two integers. + + It is a unique identified assigned by GAP for groups in the + ``SmallGroup`` library. + + EXAMPLES:: + + sage: PGL(2,3).group_id() + [24, 12] + sage: SymmetricGroup(4).group_id() + [24, 12] + + sage: G = groups.matrix.GL(2, 2) + sage: G.group_id() + [6, 1] + sage: G = groups.matrix.GL(2, 3) + sage: G.id() + [48, 29] + + sage: G = groups.matrix.GL(2, ZZ) + sage: G.group_id() + Traceback (most recent call last): + ... + GAPError: Error, the group identification for groups of size infinity is not available + """ + from sage.rings.integer import Integer + return [Integer(n) for n in self.gap().IdGroup()] + + id = group_id + + def exponent(self): + r""" + Computes the exponent of the group. + + The exponent `e` of a group `G` is the LCM of the orders of its + elements, that is, `e` is the smallest integer such that `g^e = 1` + for all `g \in G`. + + EXAMPLES:: + + sage: G = groups.matrix.GL(2, 3) + sage: G.exponent() + 24 + + sage: H = groups.matrix.Heisenberg(2) + sage: H.exponent() + Traceback (most recent call last): + ... + NotImplementedError: group must be finite + """ + if not self.is_finite(): + raise NotImplementedError("group must be finite") + from sage.rings.integer import Integer + return Integer(self._libgap_().Exponent()) + def intersection(self, other): """ Return the intersection of two groups (if it makes sense) as a @@ -418,10 +625,10 @@ def intersection(self, other): [-2 -1 2] [ 0 0 1] ) of Matrix group over Rational Field with 2 generators ( - [ 0 1/2 0] [ 0 1/2 0] - [ 2 0 0] [ -2 -1 2] - [ 0 0 1], [ 0 0 1] - ) + [ 0 1/2 0] [ 0 1/2 0] + [ 2 0 0] [ -2 -1 2] + [ 0 0 1], [ 0 0 1] + ) sage: GL(3,ZZ).intersection(G) Subgroup with 1 generators ( [ 1 0 0] @@ -429,11 +636,12 @@ def intersection(self, other): [ 0 0 1] ) of General Linear Group of degree 3 over Integer Ring sage: G.intersection(SL(3,ZZ)) - Subgroup with 0 generators () of Matrix group over Rational Field with 2 generators ( - [ 0 1/2 0] [ 0 1/2 0] - [ 2 0 0] [ -2 -1 2] - [ 0 0 1], [ 0 0 1] - ) + Subgroup with 0 generators () + of Matrix group over Rational Field with 2 generators ( + [ 0 1/2 0] [ 0 1/2 0] + [ 2 0 0] [ -2 -1 2] + [ 0 0 1], [ 0 0 1] + ) """ G = self.gap() H = other.gap() @@ -452,7 +660,7 @@ def irreducible_characters(self): EXAMPLES:: sage: G = GL(2,2) - sage: G.irreducible_characters() + sage: G.irreducible_characters() # needs sage.rings.number_field (Character of General Linear Group of degree 2 over Finite Field of size 2, Character of General Linear Group of degree 2 over Finite Field of size 2, Character of General Linear Group of degree 2 over Finite Field of size 2) @@ -487,7 +695,7 @@ def character(self, values): EXAMPLES:: sage: G = MatrixGroup(AlternatingGroup(4)) - sage: G.character([1]*len(G.conjugacy_classes_representatives())) + sage: G.character([1]*len(G.conjugacy_classes_representatives())) # needs sage.rings.number_field Character of Matrix group over Integer Ring with 12 generators :: @@ -510,7 +718,7 @@ def trivial_character(self): EXAMPLES:: - sage: MatrixGroup(SymmetricGroup(3)).trivial_character() + sage: MatrixGroup(SymmetricGroup(3)).trivial_character() # needs sage.rings.number_field Character of Matrix group over Integer Ring with 6 generators :: @@ -538,14 +746,14 @@ def character_table(self): EXAMPLES:: - sage: MatrixGroup(SymmetricGroup(2)).character_table() + sage: MatrixGroup(SymmetricGroup(2)).character_table() # needs sage.rings.number_field [ 1 -1] [ 1 1] - sage: MatrixGroup(SymmetricGroup(3)).character_table() + sage: MatrixGroup(SymmetricGroup(3)).character_table() # needs sage.rings.number_field [ 1 1 -1] [ 2 -1 0] [ 1 1 1] - sage: MatrixGroup(SymmetricGroup(5)).character_table() + sage: MatrixGroup(SymmetricGroup(5)).character_table() # long time [ 1 -1 -1 1 -1 1 1] [ 4 0 1 -1 -2 1 0] [ 5 1 -1 0 -1 -1 1] @@ -563,13 +771,13 @@ def character_table(self): irrG = G.Irr() ct = [[irrG[i][j] for j in range(n)] for i in range(n)] - from sage.rings.all import CyclotomicField + from sage.rings.number_field.number_field import CyclotomicField e = irrG.Flat().Conductor() K = CyclotomicField(e) ct = [[K(x) for x in v] for v in ct] # Finally return the result as a matrix. - from sage.matrix.all import MatrixSpace + from sage.matrix.matrix_space import MatrixSpace MS = MatrixSpace(K, n) return MS(ct) @@ -593,7 +801,7 @@ def random_element(self): True sage: F = GF(5); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])] + sage: gens = [MS([[1,2],[-1,1]]), MS([[1,1],[0,1]])] sage: G = MatrixGroup(gens) sage: G.random_element() # random [1 3] @@ -622,8 +830,7 @@ def __iter__(self): 60 """ if self.list.cache is not None: - for g in self.list(): - yield g + yield from self.list() return iterator = self.gap().Iterator() while not iterator.IsDoneIterator().sage(): diff --git a/src/sage/groups/libgap_morphism.py b/src/sage/groups/libgap_morphism.py index 64c5061b91d..f1a47fcb279 100644 --- a/src/sage/groups/libgap_morphism.py +++ b/src/sage/groups/libgap_morphism.py @@ -108,7 +108,7 @@ class GroupMorphism_libgap(Morphism): [1 0] [1 1] sage: F = GF(7); MS = MatrixSpace(F,2,2) - sage: F.multiplicative_generator() + sage: F.multiplicative_generator() # needs sage.libs.pari 3 sage: G = MatrixGroup([MS([3,0,0,1])]) sage: a = G.gens()[0]^2 @@ -136,7 +136,7 @@ class GroupMorphism_libgap(Morphism): <class 'sage.libs.gap.element.GapElement'> sage: F = GF(7); MS = MatrixSpace(F,2,2) - sage: F.multiplicative_generator() + sage: F.multiplicative_generator() # needs sage.libs.pari 3 sage: G = MatrixGroup([MS([3,0,0,1])]) sage: a = G.gens()[0]^2 @@ -151,7 +151,7 @@ class GroupMorphism_libgap(Morphism): ) sage: F = GF(7); MS = MatrixSpace(F,2,2) - sage: F.multiplicative_generator() + sage: F.multiplicative_generator() # needs sage.libs.pari 3 sage: G = MatrixGroup([MS([3,0,0,1])]) sage: a = G.gens()[0]^2 @@ -212,6 +212,7 @@ class GroupMorphism_libgap(Morphism): sage: phi(G.one()).parent() General Linear Group of degree 3 over Finite Field of size 3 + sage: # needs sage.symbolic sage: MS = MatrixSpace(SR, 2, 2) sage: G = MatrixGroup([MS(1), MS([1,2,3,4])]) sage: G.Hom(G) @@ -280,7 +281,6 @@ def __init__(self, homset, gap_hom, check=True): Morphism.__init__(self, homset) self._phi = gap_hom - def __reduce__(self): r""" Implements pickling. @@ -401,12 +401,15 @@ def pushforward(self, J, *args, **kwds): a sage: x.parent() Finitely presented group < a, b | a, b^3 > + + sage: # needs sage.rings.finite_rings sage: G = GU(3,2) sage: P = PGU(3,2) sage: pr = Hom(G, P).natural_map() sage: GS = G.subgroup([G.gen(0)]) sage: pr.pushforward(GS) - Subgroup generated by [(3,4,5)(10,18,14)(11,19,15)(12,20,16)(13,21,17)] of (The projective general unitary group of degree 3 over Finite Field of size 2) + Subgroup generated by [(3,4,5)(10,18,14)(11,19,15)(12,20,16)(13,21,17)] of + (The projective general unitary group of degree 3 over Finite Field of size 2) """ dom = self.domain() codom = self.codomain() @@ -547,13 +550,12 @@ def preimage(self, S): phi = self.gap() from sage.groups.perm_gps.permgroup import PermutationGroup_generic if not isinstance(S, (ParentLibGAP, PermutationGroup_generic)): - raise TypeError("%s must be a GAP or permutation group of %s"%(S, self)) + raise TypeError("%s must be a GAP or permutation group of %s" % (S, self)) if not self.codomain().gap().IsSubgroup(S.gap()).sage(): - raise ValueError("%s must be a subgroup of %s"%(S, self)) + raise ValueError("%s must be a subgroup of %s" % (S, self)) preimage = phi.PreImage(S.gap()) return self.domain()._subgroup_constructor(preimage) - def section(self): r""" This method returns a section map of self by use of :meth:`lift`. @@ -566,6 +568,7 @@ def section(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: G = GU(3,2) sage: P = PGU(3,2) sage: pr = Hom(G, P).natural_map() @@ -628,7 +631,6 @@ def __init__(self, G, H, category=None, check=True): Element = GroupMorphism_libgap - def _element_constructor_(self, x, check=True, **options): r""" Handle conversions and coercions. @@ -647,6 +649,7 @@ def _element_constructor_(self, x, check=True, **options): A group homomorphism between a finitely presented group and a subgroup of a permutation group:: + sage: # needs sage.rings.finite_rings sage: PG = PGU(6,2) sage: g, h = PG.gens() sage: p1 = h^-3*(h^-1*g^-1)^2*h*g*h^2*g^-1*h^2*g*h^-5*g^-1 diff --git a/src/sage/groups/libgap_wrapper.pyx b/src/sage/groups/libgap_wrapper.pyx index d25121aa792..c65afa447e5 100644 --- a/src/sage/groups/libgap_wrapper.pyx +++ b/src/sage/groups/libgap_wrapper.pyx @@ -25,7 +25,7 @@ Note how we call the constructor of both superclasses to initialize its output via LibGAP:: sage: FooGroup() - <pc group of size 3 with 1 generators> + <pc group of size 3 with 1 generator> sage: type(FooGroup().gap()) <class 'sage.libs.gap.element.GapElement'> @@ -65,7 +65,6 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import IntegerRing from sage.misc.cachefunc import cached_method from sage.structure.sage_object import SageObject -from sage.structure.element cimport Element from sage.structure.richcmp cimport richcmp @@ -106,7 +105,7 @@ class ParentLibGAP(SageObject): ....: ParentLibGAP.__init__(self, lg) ....: Group.__init__(self) sage: FooGroup() - <pc group of size 3 with 1 generators> + <pc group of size 3 with 1 generator> """ def __init__(self, libgap_parent, ambient=None): @@ -461,7 +460,7 @@ cdef class ElementLibGAP(MultiplicativeGroupElement): ....: ParentLibGAP.__init__(self, lg) ....: Group.__init__(self) sage: FooGroup() - <pc group of size 3 with 1 generators> + <pc group of size 3 with 1 generator> sage: FooGroup().gens() (f1,) """ diff --git a/src/sage/groups/lie_gps/__init__.py b/src/sage/groups/lie_gps/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/combinat/crystals/__init__.py b/src/sage/groups/lie_gps/all.py similarity index 100% rename from src/sage/combinat/crystals/__init__.py rename to src/sage/groups/lie_gps/all.py diff --git a/src/sage/groups/matrix_gps/__init__.py b/src/sage/groups/matrix_gps/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/groups/matrix_gps/binary_dihedral.py b/src/sage/groups/matrix_gps/binary_dihedral.py index 0edae3511c2..ccce9eeb17b 100644 --- a/src/sage/groups/matrix_gps/binary_dihedral.py +++ b/src/sage/groups/matrix_gps/binary_dihedral.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.gap sage.modules sage.rings.number_field """ Binary Dihedral Groups @@ -16,7 +17,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.structure.unique_representation import UniqueRepresentation from sage.rings.number_field.number_field import CyclotomicField from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/groups/matrix_gps/coxeter_group.py b/src/sage/groups/matrix_gps/coxeter_group.py index 607eda9519a..27d65a55a37 100644 --- a/src/sage/groups/matrix_gps/coxeter_group.py +++ b/src/sage/groups/matrix_gps/coxeter_group.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs """ Coxeter Groups As Matrix Groups @@ -19,23 +20,19 @@ # http://www.gnu.org/licenses/ ############################################################################## -from sage.structure.unique_representation import UniqueRepresentation +import sage.rings.abc + from sage.categories.coxeter_groups import CoxeterGroups from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_generic from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic from sage.matrix.args import SparseEntry from sage.matrix.matrix_space import MatrixSpace - -import sage.rings.abc +from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity -from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField -from sage.rings.number_field.number_field import QuadraticField - -from sage.misc.cachefunc import cached_method - from sage.sets.family import Family +from sage.structure.unique_representation import UniqueRepresentation class CoxeterMatrixGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_generic): @@ -82,8 +79,8 @@ class CoxeterMatrixGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gene We can create Coxeter groups from Coxeter matrices:: - sage: W = CoxeterGroup([[1, 6, 3], [6, 1, 10], [3, 10, 1]]) - sage: W + sage: # needs sage.rings.number_field + sage: W = CoxeterGroup([[1, 6, 3], [6, 1, 10], [3, 10, 1]]); W Coxeter group over Universal Cyclotomic Field with Coxeter matrix: [ 1 6 3] [ 6 1 10] @@ -102,6 +99,7 @@ class CoxeterMatrixGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gene [ 0 1 0] [ 1 E(20) - E(20)^9 -1] ) + sage: m = matrix([[1,3,3,3], [3,1,3,2], [3,3,1,2], [3,2,2,1]]) sage: W = CoxeterGroup(m) sage: W.gens() @@ -143,7 +141,7 @@ class CoxeterMatrixGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gene [3 1 3 2] [3 3 1 2] [3 2 2 1] - sage: CoxeterGroup([[1,4],[4,1]], base_ring=QQ) + sage: CoxeterGroup([[1,4],[4,1]], base_ring=QQ) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert sqrt(2) to a rational @@ -152,6 +150,7 @@ class CoxeterMatrixGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gene graphs, we can input a Coxeter graph. Following the standard convention, edges with no label (i.e. labelled by ``None``) are treated as 3:: + sage: # needs sage.rings.number_field sage: G = Graph([(0,3,None), (1,3,15), (2,3,7), (0,1,3)]) sage: W = CoxeterGroup(G); W Coxeter group over Universal Cyclotomic Field with Coxeter matrix: @@ -166,6 +165,7 @@ class CoxeterMatrixGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gene Because there currently is no class for `\ZZ \cup \{ \infty \}`, labels of `\infty` are given by `-1` in the Coxeter matrix:: + sage: # needs sage.rings.number_field sage: G = Graph([(0,1,None), (1,2,4), (0,2,oo)]) sage: W = CoxeterGroup(G) sage: W.coxeter_matrix() @@ -176,20 +176,20 @@ class CoxeterMatrixGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gene We can also create Coxeter groups from Cartan types using the ``implementation`` keyword:: - sage: W = CoxeterGroup(['D',5], implementation="reflection") - sage: W + sage: W = CoxeterGroup(['D',5], implementation="reflection"); W Finite Coxeter group over Integer Ring with Coxeter matrix: [1 3 2 2 2] [3 1 3 2 2] [2 3 1 3 3] [2 2 3 1 2] [2 2 3 2 1] - sage: W = CoxeterGroup(['H',3], implementation="reflection") - sage: W - Finite Coxeter group over Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? with Coxeter matrix: - [1 3 2] - [3 1 5] - [2 5 1] + sage: W = CoxeterGroup(['H',3], implementation="reflection"); W # needs sage.rings.number_field + Finite Coxeter group over + Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? + with Coxeter matrix: + [1 3 2] + [3 1 5] + [2 5 1] """ @staticmethod def __classcall_private__(cls, data, base_ring=None, index_set=None): @@ -217,6 +217,7 @@ def __classcall_private__(cls, data, base_ring=None, index_set=None): if data.is_simply_laced(): base_ring = ZZ elif data.is_finite(): + from sage.rings.number_field.number_field import QuadraticField letter = data.coxeter_type().cartan_type().type() if letter in ['B', 'C', 'F']: base_ring = QuadraticField(2) @@ -225,8 +226,10 @@ def __classcall_private__(cls, data, base_ring=None, index_set=None): elif letter == 'H': base_ring = QuadraticField(5) else: + from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField base_ring = UniversalCyclotomicField() else: + from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField base_ring = UniversalCyclotomicField() return super().__classcall__(cls, data, base_ring, data.index_set()) @@ -238,6 +241,8 @@ def __init__(self, coxeter_matrix, base_ring, index_set): sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]]) sage: TestSuite(W).run() # long time + + sage: # needs sage.rings.number_field sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar) sage: TestSuite(W).run() # long time sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]]) @@ -249,6 +254,8 @@ def __init__(self, coxeter_matrix, base_ring, index_set): sage: CoxeterGroup(['D',4], base_ring=QQ).category() Category of finite irreducible coxeter groups + + sage: # needs sage.rings.number_field sage: CoxeterGroup(['H',4], base_ring=QQbar).category() Category of finite irreducible coxeter groups sage: F = CoxeterGroups().Finite() @@ -272,8 +279,8 @@ def __init__(self, coxeter_matrix, base_ring, index_set): MS = MatrixSpace(base_ring, n, sparse=True) one = MS.one() # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty - E = UniversalCyclotomicField().gen - if base_ring is UniversalCyclotomicField(): + if isinstance(base_ring, sage.rings.abc.UniversalCyclotomicField): + E = base_ring.gen def val(x): if x == -1: @@ -281,6 +288,9 @@ def val(x): else: return E(2 * x) + ~E(2 * x) elif isinstance(base_ring, sage.rings.abc.NumberField_quadratic): + from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + + E = UniversalCyclotomicField().gen def val(x): if x == -1: @@ -330,7 +340,7 @@ def _repr_(self): EXAMPLES:: - sage: CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]]) + sage: CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]]) # needs sage.rings.number_field Finite Coxeter group over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? with Coxeter matrix: [1 3 2] [3 1 4] @@ -347,6 +357,7 @@ def _coerce_map_from_(self, P): EXAMPLES:: + sage: # needs sage.combinat sage: W = CoxeterGroup(["A",4]) sage: W2 = WeylGroup(["A",4]) sage: W._coerce_map_from_(W2) @@ -372,7 +383,7 @@ def coxeter_matrix(self): sage: W.coxeter_matrix() [1 3] [3 1] - sage: W = CoxeterGroup(['H',3]) + sage: W = CoxeterGroup(['H',3]) # needs sage.rings.number_field sage: W.coxeter_matrix() [1 3 2] [3 1 5] @@ -398,7 +409,7 @@ def bilinear_form(self): EXAMPLES:: sage: W = CoxeterGroup(['D',4]) - sage: W.bilinear_form() + sage: W.bilinear_form() # needs sage.symbolic [ 1 -1/2 0 0] [-1/2 1 -1/2 -1/2] [ 0 -1/2 1 0] @@ -412,6 +423,7 @@ def is_finite(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: [l for l in range(2, 9) if ....: CoxeterGroup([[1,3,2],[3,1,l],[2,l,1]]).is_finite()] [2, 3, 4, 5] @@ -466,6 +478,7 @@ def order(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: W = CoxeterGroup([[1,3],[3,1]]) sage: W.order() 6 @@ -579,6 +592,8 @@ def positive_roots(self): sage: W = CoxeterGroup(['A',3], implementation='reflection') sage: W.positive_roots() ((1, 0, 0), (1, 1, 0), (0, 1, 0), (1, 1, 1), (0, 1, 1), (0, 0, 1)) + + sage: # needs sage.rings.number_field sage: W = CoxeterGroup(['I',5], implementation='reflection') sage: W.positive_roots() ((1, 0), @@ -635,6 +650,8 @@ def roots(self): (-1, -1, -1), (0, -1, -1), (0, 0, -1)) + + sage: # needs sage.rings.number_field sage: W = CoxeterGroup(['I',5], implementation='reflection') sage: len(W.roots()) 10 @@ -675,7 +692,7 @@ def fundamental_weights(self): EXAMPLES:: sage: W = CoxeterGroup(['A',3], implementation='reflection') - sage: W.fundamental_weights() + sage: W.fundamental_weights() # needs sage.symbolic Finite family {1: (3/2, 1, 1/2), 2: (1, 2, 1), 3: (1/2, 1, 3/2)} """ simple_weights = self.bilinear_form().inverse() @@ -692,7 +709,7 @@ def fundamental_weight(self, i): EXAMPLES:: sage: W = CoxeterGroup(['A',3], implementation='reflection') - sage: W.fundamental_weight(1) + sage: W.fundamental_weight(1) # needs sage.symbolic (3/2, 1, 1/2) """ return self.fundamental_weights()[i] @@ -834,7 +851,7 @@ def action_on_root_indices(self, i, side="left"): """ Return the action on the set of roots. - The roots are ordered as in the output of the method `roots`. + The roots are ordered as in the output of the method :meth:`roots`. EXAMPLES:: diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index e177b180840..d0ec214bb3b 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -7,7 +7,7 @@ EXAMPLES:: sage: F = GF(3) - sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F,2, [1,1,0,1])] + sage: gens = [matrix(F, 2, [1,0, -1,1]), matrix(F, 2, [1,1,0,1])] sage: G = MatrixGroup(gens) sage: G.conjugacy_classes_representatives() ( @@ -18,7 +18,7 @@ The finitely generated matrix groups can also be constructed as subgroups of matrix groups:: - sage: SL2Z = SL(2,ZZ) + sage: SL2Z = SL(2, ZZ) sage: S, T = SL2Z.gens() sage: SL2Z.subgroup([T^2]) Subgroup with 1 generators ( @@ -51,35 +51,32 @@ - Sebastian Oehms (2019-01): Revision of :trac:`25706` (:trac:`26903` and :trac:`27143`). """ -############################################################################## +# ############################################################################# # Copyright (C) 2006 David Joyner and William Stein <wstein@gmail.com> -# Copyright (C) 2013 Volker Braun <vbraun.name@gmail.com> +# 2009 Mike Hansen +# 2012 Rob Beezer +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2013 Nathann Cohen +# 2013 Travis Scrimshaw +# 2017 Peter Bruin +# 2021 Frรฉdรฉric Chapoton +# 2023 Matthias Koeppe # # Distributed under the terms of the GNU General Public License (GPL) # # The full text of the GPL is available at: # # https://www.gnu.org/licenses/ -############################################################################## +# ############################################################################# +from sage.groups.matrix_gps.group_element import is_MatrixGroupElement +from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic +from sage.matrix.constructor import matrix +from sage.matrix.matrix_space import is_MatrixSpace +from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ -from sage.rings.all import QQbar from sage.structure.element import is_Matrix -from sage.matrix.matrix_space import MatrixSpace, is_MatrixSpace -from sage.matrix.constructor import matrix from sage.structure.sequence import Sequence -from sage.misc.cachefunc import cached_method -from sage.modules.free_module_element import vector -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.power_series_ring import PowerSeriesRing -from sage.rings.fraction_field import FractionField -from sage.misc.functional import cyclotomic_polynomial -from sage.rings.number_field.number_field import CyclotomicField -from sage.combinat.integer_vector import IntegerVectors - -from sage.groups.matrix_gps.matrix_group import (MatrixGroup_generic, - MatrixGroup_gap) -from sage.groups.matrix_gps.group_element import is_MatrixGroupElement def normalize_square_matrices(matrices): @@ -93,9 +90,9 @@ def normalize_square_matrices(matrices): EXAMPLES:: sage: from sage.groups.matrix_gps.finitely_generated import normalize_square_matrices - sage: m1 = [[1,2],[3,4]] + sage: m1 = [[1,2], [3,4]] sage: m2 = [2, 3, 4, 5] - sage: m3 = matrix(QQ, [[1/2,1/3],[1/4,1/5]]) + sage: m3 = matrix(QQ, [[1/2,1/3], [1/4,1/5]]) sage: m4 = MatrixGroup(m3).gen(0) sage: normalize_square_matrices([m1, m2, m3, m4]) [ @@ -144,7 +141,7 @@ def normalize_square_matrices(matrices): def QuaternionMatrixGroupGF3(): r""" - The quaternion group as a set of `2\times 2` matrices over `GF(3)`. + The quaternion group as a set of `2\times 2` matrices over `\GF{3}`. OUTPUT: @@ -179,7 +176,7 @@ def QuaternionMatrixGroupGF3(): TESTS:: - sage: groups.matrix.QuaternionGF3() + sage: groups.matrix.QuaternionGF3() # needs sage.modules sage.rings.finite_rings Matrix group over Finite Field of size 3 with 2 generators ( [1 1] [2 1] [1 2], [1 1] @@ -189,12 +186,12 @@ def QuaternionMatrixGroupGF3(): sage: QP = Q.as_permutation_group() sage: QP.is_isomorphic(QuaternionGroup()) True - sage: H = DihedralGroup(4) - sage: H.order() + sage: H = DihedralGroup(4) # needs sage.groups + sage: H.order() # needs sage.groups 8 - sage: QP.is_abelian(), H.is_abelian() + sage: QP.is_abelian(), H.is_abelian() # needs sage.groups (False, False) - sage: QP.is_isomorphic(H) + sage: QP.is_isomorphic(H) # needs sage.groups False """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -220,7 +217,7 @@ def MatrixGroup(*gens, **kwds): EXAMPLES:: sage: F = GF(5) - sage: gens = [matrix(F,2,[1,2, -1, 1]), matrix(F,2, [1,1, 0,1])] + sage: gens = [matrix(F, 2, [1,2, -1,1]), matrix(F,2, [1,1, 0,1])] sage: G = MatrixGroup(gens); G Matrix group over Finite Field of size 5 with 2 generators ( [1 2] [1 1] @@ -233,7 +230,7 @@ def MatrixGroup(*gens, **kwds): matrices over the finite field, so creates that matrix group there:: - sage: gens = [matrix(2,[1,2, -1, 1]), matrix(GF(7), 2, [1,1, 0,1]), 2] + sage: gens = [matrix(2, [1,2, -1,1]), matrix(GF(7), 2, [1,1, 0,1]), 2] sage: G = MatrixGroup(gens); G Matrix group over Finite Field of size 7 with 3 generators ( [1 2] [1 1] [2 0] @@ -242,12 +239,12 @@ def MatrixGroup(*gens, **kwds): Each generator must be invertible:: - sage: G = MatrixGroup([matrix(ZZ,2,[1,2,3,4])]) + sage: G = MatrixGroup([matrix(ZZ, 2, [1,2,3,4])]) Traceback (most recent call last): ... ValueError: each generator must be an invertible matrix - sage: F = GF(5); MS = MatrixSpace(F,2,2) + sage: F = GF(5); MS = MatrixSpace(F, 2, 2) sage: MatrixGroup([MS.0]) Traceback (most recent call last): ... @@ -293,16 +290,23 @@ def MatrixGroup(*gens, **kwds): MS = gens.universe() base_ring = MS.base_ring() degree = ZZ(MS.ncols()) # == MS.nrows() - from sage.libs.gap.libgap import libgap category = kwds.get('category', None) try: - gap_gens = [libgap(matrix_gen) for matrix_gen in gens] - gap_group = libgap.Group(gap_gens) - return FinitelyGeneratedMatrixGroup_gap(degree, base_ring, gap_group, - category=category) - except (TypeError, ValueError): - return FinitelyGeneratedMatrixGroup_generic(degree, base_ring, gens, + from sage.libs.gap.libgap import libgap + from .finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap + except ImportError: + pass + else: + try: + gap_gens = [libgap(matrix_gen) for matrix_gen in gens] + gap_group = libgap.Group(gap_gens) + return FinitelyGeneratedMatrixGroup_gap(degree, base_ring, gap_group, category=category) + except (TypeError, ValueError): + pass + + return FinitelyGeneratedMatrixGroup_generic(degree, base_ring, gens, + category=category) ################################################################### # @@ -315,8 +319,9 @@ class FinitelyGeneratedMatrixGroup_generic(MatrixGroup_generic): """ TESTS:: - sage: m1 = matrix(SR, [[1,2],[3,4]]) - sage: m2 = matrix(SR, [[1,3],[-1,0]]) + sage: # needs sage.symbolic + sage: m1 = matrix(SR, [[1,2], [3,4]]) + sage: m2 = matrix(SR, [[1,3], [-1,0]]) sage: MatrixGroup(m1) == MatrixGroup(m1) True sage: MatrixGroup(m1) == MatrixGroup(m1.change_ring(QQ)) @@ -326,8 +331,8 @@ class FinitelyGeneratedMatrixGroup_generic(MatrixGroup_generic): sage: MatrixGroup(m1, m2) == MatrixGroup(m2, m1) False - sage: m1 = matrix(QQ, [[1,2],[3,4]]) - sage: m2 = matrix(QQ, [[1,3],[-1,0]]) + sage: m1 = matrix(QQ, [[1,2], [3,4]]) + sage: m2 = matrix(QQ, [[1,3], [-1,0]]) sage: MatrixGroup(m1) == MatrixGroup(m1) True sage: MatrixGroup(m1) == MatrixGroup(m2) @@ -347,8 +352,9 @@ def __init__(self, degree, base_ring, generator_matrices, category=None): EXAMPLES:: - sage: m1 = matrix(SR, [[1,2],[3,4]]) - sage: m2 = matrix(SR, [[1,3],[-1,0]]) + sage: # needs sage.symbolic + sage: m1 = matrix(SR, [[1,2], [3,4]]) + sage: m2 = matrix(SR, [[1,3], [-1,0]]) sage: G = MatrixGroup(m1, m2) sage: TestSuite(G).run() sage: type(G) @@ -356,7 +362,7 @@ def __init__(self, degree, base_ring, generator_matrices, category=None): sage: from sage.groups.matrix_gps.finitely_generated import \ ....: FinitelyGeneratedMatrixGroup_generic - sage: G = FinitelyGeneratedMatrixGroup_generic(2, QQ, [matrix(QQ,[[1,2],[3,4]])]) + sage: G = FinitelyGeneratedMatrixGroup_generic(2, QQ, [matrix(QQ, [[1,2], [3,4]])]) sage: G.gens() ( [1 2] @@ -373,18 +379,18 @@ def gens(self): EXAMPLES:: - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]), MS([[1,1],[0,1]])] + sage: F = GF(3); MS = MatrixSpace(F, 2, 2) + sage: gens = [MS([[1,0], [0,1]]), MS([[1,1], [0,1]])] sage: G = MatrixGroup(gens) sage: gens[0] in G True sage: gens = G.gens() sage: gens[0] in G True - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: gens = [MS([[1,0], [0,1]]), MS([[1,1], [0,1]])] - sage: F = GF(5); MS = MatrixSpace(F,2,2) - sage: G = MatrixGroup([MS(1), MS([1,2,3,4])]) + sage: F = GF(5); MS = MatrixSpace(F, 2, 2) + sage: G = MatrixGroup([MS(1), MS([1,2, 3,4])]) sage: G Matrix group over Finite Field of size 5 with 2 generators ( [1 0] [1 2] @@ -410,7 +416,7 @@ def gen(self, i): EXAMPLES:: sage: H = GL(2, GF(3)) - sage: h1, h2 = H([[1,0],[2,1]]), H([[1,1],[0,1]]) + sage: h1, h2 = H([[1,0], [2,1]]), H([[1,1], [0,1]]) sage: G = H.subgroup([h1, h2]) sage: G.gen(0) [1 0] @@ -431,7 +437,7 @@ def ngens(self): EXAMPLES:: sage: H = GL(2, GF(3)) - sage: h1, h2 = H([[1,0],[2,1]]), H([[1,1],[0,1]]) + sage: h1, h2 = H([[1,0], [2,1]]), H([[1,1], [0,1]]) sage: G = H.subgroup([h1, h2]) sage: G.ngens() 2 @@ -444,13 +450,14 @@ def __reduce__(self): TESTS:: - sage: G = MatrixGroup([matrix(CC, [[1,2],[3,4]]), - ....: matrix(CC, [[1,3],[-1,0]])]) + sage: G = MatrixGroup([matrix(CC, [[1,2], [3,4]]), + ....: matrix(CC, [[1,3], [-1,0]])]) sage: loads(dumps(G)) == G True Check that :trac:`22128` is fixed:: + sage: # needs sage.symbolic sage: R = MatrixSpace(SR, 2) sage: G = MatrixGroup([R([[1, 1], [0, 1]])]) sage: G.register_embedding(R) @@ -466,865 +473,12 @@ def _test_matrix_generators(self, **options): """ EXAMPLES:: - sage: m1 = matrix(SR, [[1,2],[3,4]]) - sage: m2 = matrix(SR, [[1,3],[-1,0]]) + sage: # needs sage.symbolic + sage: m1 = matrix(SR, [[1,2], [3,4]]) + sage: m2 = matrix(SR, [[1,3], [-1,0]]) sage: G = MatrixGroup(m1, m2) sage: G._test_matrix_generators() """ tester = self._tester(**options) for g,h in zip(self.gens(), MatrixGroup(self.gens()).gens()): tester.assertEqual(g.matrix(), h.matrix()) - -################################################################### -# -# Matrix group over a ring that GAP understands -# -################################################################### - - -class FinitelyGeneratedMatrixGroup_gap(MatrixGroup_gap): - """ - Matrix group generated by a finite number of matrices. - - EXAMPLES:: - - sage: m1 = matrix(GF(11), [[1,2],[3,4]]) - sage: m2 = matrix(GF(11), [[1,3],[10,0]]) - sage: G = MatrixGroup(m1, m2); G - Matrix group over Finite Field of size 11 with 2 generators ( - [1 2] [ 1 3] - [3 4], [10 0] - ) - sage: type(G) - <class 'sage.groups.matrix_gps.finitely_generated.FinitelyGeneratedMatrixGroup_gap_with_category'> - sage: TestSuite(G).run() - """ - - def __reduce__(self): - """ - Implement pickling. - - EXAMPLES:: - - sage: m1 = matrix(QQ, [[1,2],[3,4]]) - sage: m2 = matrix(QQ, [[1,3],[-1,0]]) - sage: loads(MatrixGroup(m1, m2).dumps()) - Matrix group over Rational Field with 2 generators ( - [1 2] [ 1 3] - [3 4], [-1 0] - ) - """ - return (MatrixGroup, - tuple(g.matrix() for g in self.gens()) + ({'check':False},)) - - def as_permutation_group(self, algorithm=None, seed=None): - r""" - Return a permutation group representation for the group. - - In most cases occurring in practice, this is a permutation - group of minimal degree (the degree being determined from - orbits under the group action). When these orbits are hard to - compute, the procedure can be time-consuming and the degree - may not be minimal. - - INPUT: - - - ``algorithm`` -- ``None`` or ``'smaller'``. In the latter - case, try harder to find a permutation representation of - small degree. - - ``seed`` -- ``None`` or an integer specifying the seed - to fix results depending on pseudo-random-numbers. Here - it makes sense to be used with respect to the ``'smaller'`` - option, since gap produces random output in that context. - - OUTPUT: - - A permutation group isomorphic to ``self``. The - ``algorithm='smaller'`` option tries to return an isomorphic - group of low degree, but is not guaranteed to find the - smallest one and must not even differ from the one obtained - without the option. In that case repeating the invocation - may help (see the example below). - - EXAMPLES:: - - sage: MS = MatrixSpace(GF(2), 5, 5) - sage: A = MS([[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0]]) - sage: G = MatrixGroup([A]) - sage: G.as_permutation_group().order() - 2 - - A finite subgroup of GL(12,Z) as a permutation group:: - - sage: imf = libgap.function_factory('ImfMatrixGroup') - sage: GG = imf( 12, 3 ) - sage: G = MatrixGroup(GG.GeneratorsOfGroup()) - sage: G.cardinality() - 21499084800 - sage: P = G.as_permutation_group() - sage: Psmaller = G.as_permutation_group(algorithm="smaller", seed=6) - sage: P == Psmaller # see the note below - True - sage: Psmaller = G.as_permutation_group(algorithm="smaller") - sage: P == Psmaller - False - sage: P.cardinality() - 21499084800 - sage: P.degree() - 144 - sage: Psmaller.cardinality() - 21499084800 - sage: Psmaller.degree() - 80 - - .. NOTE:: - - In this case, the "smaller" option returned an isomorphic - group of lower degree. The above example used GAP's library - of irreducible maximal finite ("imf") integer matrix groups - to construct the MatrixGroup G over GF(7). The section - "Irreducible Maximal Finite Integral Matrix Groups" in the - GAP reference manual has more details. - - .. NOTE:: - - Concerning the option ``algorithm='smaller'`` you should note - the following from GAP documentation: "The methods used might - involve the use of random elements and the permutation - representation (or even the degree of the representation) is - not guaranteed to be the same for different calls of - SmallerDegreePermutationRepresentation." - - To obtain a reproducible result the optional argument ``seed`` - may be used as in the example above. - - TESTS:: - - sage: A = matrix(QQ, 2, [0, 1, 1, 0]) - sage: B = matrix(QQ, 2, [1, 0, 0, 1]) - sage: a, b = MatrixGroup([A, B]).as_permutation_group().gens() - sage: a.order(), b.order() - (2, 1) - - The above example in GL(12,Z), reduced modulo 7:: - - sage: MS = MatrixSpace(GF(7), 12, 12) - sage: G = MatrixGroup([MS(g) for g in GG.GeneratorsOfGroup()]) - sage: G.cardinality() - 21499084800 - sage: P = G.as_permutation_group() - sage: P.cardinality() - 21499084800 - - Check that large degree is still working:: - - sage: Sp(6,3).as_permutation_group().cardinality() - 9170703360 - - Check that :trac:`25706` still works after :trac:`26903`:: - - sage: MG = GU(3,2).as_matrix_group() - sage: PG = MG.as_permutation_group() - sage: mg = MG.an_element() - sage: PG(mg).order() # particular element depends on the set of GAP packages installed - 6 - """ - # Note that the output of IsomorphismPermGroup() depends on - # memory locations and will change if you change the order of - # doctests and/or architecture - from sage.groups.perm_gps.permgroup import PermutationGroup - if not self.is_finite(): - raise NotImplementedError("group must be finite") - if seed is not None: - from sage.libs.gap.libgap import libgap - libgap.set_seed(ZZ(seed)) - iso = self._libgap_().IsomorphismPermGroup() - if algorithm == "smaller": - iso = iso.Image().SmallerDegreePermutationRepresentation() - return PermutationGroup(iso.Image().GeneratorsOfGroup().sage(), - canonicalize=False) - - def module_composition_factors(self, algorithm=None): - r""" - Return a list of triples consisting of [base field, dimension, - irreducibility], for each of the Meataxe composition factors - modules. The ``algorithm="verbose"`` option returns more information, - but in Meataxe notation. - - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,4,4) - sage: M = MS(0) - sage: M[0,1]=1;M[1,2]=1;M[2,3]=1;M[3,0]=1 - sage: G = MatrixGroup([M]) - sage: G.module_composition_factors() - [(Finite Field of size 3, 1, True), - (Finite Field of size 3, 1, True), - (Finite Field of size 3, 2, True)] - sage: F = GF(7); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])] - sage: G = MatrixGroup(gens) - sage: G.module_composition_factors() - [(Finite Field of size 7, 2, True)] - - Type ``G.module_composition_factors(algorithm='verbose')`` to get a - more verbose version. - - For more on MeatAxe notation, see - https://www.gap-system.org/Manuals/doc/ref/chap69.html - """ - from sage.libs.gap.libgap import libgap - F = self.base_ring() - if not F.is_finite(): - raise NotImplementedError("base ring must be finite") - n = self.degree() - MS = MatrixSpace(F, n, n) - mats = [MS(g.matrix()) for g in self.gens()] - # initializing list of mats by which the gens act on self - mats_gap = libgap(mats) - M = mats_gap.GModuleByMats(F) - compo = libgap.function_factory('MTX.CompositionFactors') - MCFs = compo(M) - if algorithm == "verbose": - print(str(MCFs) + "\n") - return sorted((MCF['field'].sage(), - MCF['dimension'].sage(), - MCF['IsIrreducible'].sage()) for MCF in MCFs) - - def invariant_generators(self): - r""" - Return invariant ring generators. - - Computes generators for the polynomial ring - `F[x_1,\ldots,x_n]^G`, where `G` in `GL(n,F)` is a finite matrix - group. - - In the "good characteristic" case the polynomials returned - form a minimal generating set for the algebra of `G`-invariant - polynomials. In the "bad" case, the polynomials returned - are primary and secondary invariants, forming a not - necessarily minimal generating set for the algebra of - `G`-invariant polynomials. - - ALGORITHM: - - Wraps Singular's ``invariant_algebra_reynolds`` and ``invariant_ring`` - in ``finvar.lib``. - - EXAMPLES:: - - sage: F = GF(7); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])] - sage: G = MatrixGroup(gens) - sage: G.invariant_generators() - [x1^7*x2 - x1*x2^7, - x1^12 - 2*x1^9*x2^3 - x1^6*x2^6 + 2*x1^3*x2^9 + x2^12, - x1^18 + 2*x1^15*x2^3 + 3*x1^12*x2^6 + 3*x1^6*x2^12 - 2*x1^3*x2^15 + x2^18] - - sage: q = 4; a = 2 - sage: MS = MatrixSpace(QQ, 2, 2) - sage: gen1 = [[1/a,(q-1)/a],[1/a, -1/a]]; gen2 = [[1,0],[0,-1]]; gen3 = [[-1,0],[0,1]] - sage: G = MatrixGroup([MS(gen1),MS(gen2),MS(gen3)]) - sage: G.cardinality() - 12 - sage: G.invariant_generators() - [x1^2 + 3*x2^2, x1^6 + 15*x1^4*x2^2 + 15*x1^2*x2^4 + 33*x2^6] - - sage: F = CyclotomicField(8) - sage: z = F.gen() - sage: a = z+1/z - sage: b = z^2 - sage: MS = MatrixSpace(F,2,2) - sage: g1 = MS([[1/a, 1/a], [1/a, -1/a]]) - sage: g2 = MS([[-b, 0], [0, b]]) - sage: G = MatrixGroup([g1,g2]) - sage: G.invariant_generators() - [x1^4 + 2*x1^2*x2^2 + x2^4, - x1^5*x2 - x1*x2^5, - x1^8 + 28/9*x1^6*x2^2 + 70/9*x1^4*x2^4 + 28/9*x1^2*x2^6 + x2^8] - - AUTHORS: - - - David Joyner, Simon King and Martin Albrecht. - - REFERENCES: - - - Singular reference manual - - - [Stu1993]_ - - - S. King, "Minimal Generating Sets of non-modular invariant - rings of finite groups", :arxiv:`math/0703035`. - """ - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - from sage.interfaces.singular import singular - gens = self.gens() - singular.LIB("finvar.lib") - n = self.degree() # len((gens[0].matrix()).rows()) - F = self.base_ring() - q = F.characteristic() - # test if the field is admissible - if F.gen() == 1: # we got the rationals or GF(prime) - FieldStr = str(F.characteristic()) - elif hasattr(F,'polynomial'): # we got an algebraic extension - if len(F.gens()) > 1: - raise NotImplementedError("can only deal with finite fields and (simple algebraic extensions of) the rationals") - FieldStr = '(%d,%s)' % (F.characteristic(), str(F.gen())) - else: # we have a transcendental extension - FieldStr = '(%d,%s)' % (F.characteristic(), - ','.join(str(p) for p in F.gens())) - - # Setting Singular's variable names - # We need to make sure that field generator and variables get different names. - if str(F.gen())[0] == 'x': - VarStr = 'y' - else: - VarStr = 'x' - VarNames = '(' + ','.join((VarStr+str(i) for i in range(1, n+1)))+')' - # The function call and affectation below have side-effects. Do not remove! - # (even if pyflakes say so) - R = singular.ring(FieldStr, VarNames, 'dp') - if hasattr(F, 'polynomial') and F.gen() != 1: - # we have to define minpoly - singular.eval('minpoly = '+str(F.polynomial()).replace('x',str(F.gen()))) - A = [singular.matrix(n,n,str((x.matrix()).list())) for x in gens] - Lgens = ','.join((x.name() for x in A)) - PR = PolynomialRing(F, n, [VarStr+str(i) for i in range(1,n+1)]) - - if q == 0 or (q > 0 and self.cardinality() % q): - from sage.all import Matrix - try: - elements = [g.matrix() for g in self.list()] - except (TypeError, ValueError): - elements - if elements is not None: - ReyName = 't'+singular._next_var_name() - singular.eval('matrix %s[%d][%d]' % (ReyName, - self.cardinality(), n)) - for i in range(1,self.cardinality()+1): - M = Matrix(F, elements[i-1]) - D = [{} for foobar in range(self.degree())] - for x,y in M.dict().items(): - D[x[0]][x[1]] = y - for row in range(self.degree()): - for t in D[row].items(): - singular.eval('%s[%d,%d]=%s[%d,%d]+(%s)*var(%d)' - % (ReyName,i,row+1,ReyName,i,row+1, repr(t[1]),t[0]+1)) - IRName = 't'+singular._next_var_name() - singular.eval('matrix %s = invariant_algebra_reynolds(%s)' % (IRName,ReyName)) - else: - ReyName = 't'+singular._next_var_name() - singular.eval('list %s=group_reynolds((%s))' % (ReyName, Lgens)) - IRName = 't'+singular._next_var_name() - singular.eval('matrix %s = invariant_algebra_reynolds(%s[1])' % (IRName, ReyName)) - - OUT = [singular.eval(IRName+'[1,%d]' % (j)) - for j in range(1, 1+int(singular('ncols('+IRName+')')))] - return [PR(gen) for gen in OUT] - if self.cardinality() % q == 0: - PName = 't' + singular._next_var_name() - SName = 't' + singular._next_var_name() - singular.eval('matrix %s,%s=invariant_ring(%s)' % (PName, SName, Lgens)) - OUT = [singular.eval(PName+'[1,%d]' % (j)) - for j in range(1,1+singular('ncols('+PName+')'))] - OUT += [singular.eval(SName+'[1,%d]' % (j)) - for j in range(2,1+singular('ncols('+SName+')'))] - return [PR(gen) for gen in OUT] - - def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): - r""" - Compute the Molien series of this finite group with respect to the - character ``chi``. It can be returned either as a rational function - in one variable or a power series in one variable. The base field - must be a finite field, the rationals, or a cyclotomic field. - - Note that the base field characteristic cannot divide the group - order (i.e., the non-modular case). - - ALGORITHM: - - For a finite group `G` in characteristic zero we construct the Molien series as - - .. MATH:: - - \frac{1}{|G|}\sum_{g \in G} \frac{\chi(g)}{\text{det}(I-tg)}, - - where `I` is the identity matrix and `t` an indeterminate. - - For characteristic `p` not dividing the order of `G`, let `k` be the base field - and `N` the order of `G`. Define `\lambda` as a primitive `N`-th root of unity over `k` - and `\omega` as a primitive `N`-th root of unity over `\QQ`. For each `g \in G` - define `k_i(g)` to be the positive integer such that - `e_i = \lambda^{k_i(g)}` for each eigenvalue `e_i` of `g`. Then the Molien series - is computed as - - .. MATH:: - - \frac{1}{|G|}\sum_{g \in G} \frac{\chi(g)}{\prod_{i=1}^n(1 - t\omega^{k_i(g)})}, - - where `t` is an indeterminant. [Dec1998]_ - - INPUT: - - - ``chi`` -- (default: trivial character) a linear group character of this group - - - ``return_series`` -- boolean (default: ``True``) if ``True``, then returns - the Molien series as a power series, ``False`` as a rational function - - - ``prec`` -- integer (default: 20); power series default precision - - - ``variable`` -- string (default: ``'t'``); Variable name for the Molien series - - OUTPUT: single variable rational function or power series with integer coefficients - - EXAMPLES:: - - sage: MatrixGroup(matrix(QQ,2,2,[1,1,0,1])).molien_series() - Traceback (most recent call last): - ... - NotImplementedError: only implemented for finite groups - sage: MatrixGroup(matrix(GF(3),2,2,[1,1,0,1])).molien_series() - Traceback (most recent call last): - ... - NotImplementedError: characteristic cannot divide group order - - Tetrahedral Group:: - - sage: K.<i> = CyclotomicField(4) - sage: Tetra = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [0,i, -i,0]) - sage: Tetra.molien_series(prec=30) - 1 + t^8 + 2*t^12 + t^16 + 2*t^20 + 3*t^24 + 2*t^28 + O(t^30) - sage: mol = Tetra.molien_series(return_series=False); mol - (t^8 - t^4 + 1)/(t^16 - t^12 - t^4 + 1) - sage: mol.parent() - Fraction Field of Univariate Polynomial Ring in t over Integer Ring - sage: chi = Tetra.character(Tetra.character_table()[1]) - sage: Tetra.molien_series(chi, prec=30, variable='u') - u^6 + u^14 + 2*u^18 + u^22 + 2*u^26 + 3*u^30 + 2*u^34 + O(u^36) - sage: chi = Tetra.character(Tetra.character_table()[2]) - sage: Tetra.molien_series(chi) - t^10 + t^14 + t^18 + 2*t^22 + 2*t^26 + O(t^30) - - :: - - sage: S3 = MatrixGroup(SymmetricGroup(3)) - sage: mol = S3.molien_series(prec=10); mol - 1 + t + 2*t^2 + 3*t^3 + 4*t^4 + 5*t^5 + 7*t^6 + 8*t^7 + 10*t^8 + 12*t^9 + O(t^10) - sage: mol.parent() - Power Series Ring in t over Integer Ring - - Octahedral Group:: - - sage: K.<v> = CyclotomicField(8) - sage: a = v-v^3 #sqrt(2) - sage: i = v^2 - sage: Octa = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [(1+i)/a,0, 0,(1-i)/a]) - sage: Octa.molien_series(prec=30) - 1 + t^8 + t^12 + t^16 + t^18 + t^20 + 2*t^24 + t^26 + t^28 + O(t^30) - - Icosahedral Group:: - - sage: K.<v> = CyclotomicField(10) - sage: z5 = v^2 - sage: i = z5^5 - sage: a = 2*z5^3 + 2*z5^2 + 1 #sqrt(5) - sage: Ico = MatrixGroup([[z5^3,0, 0,z5^2], [0,1, -1,0], [(z5^4-z5)/a, (z5^2-z5^3)/a, (z5^2-z5^3)/a, -(z5^4-z5)/a]]) - sage: Ico.molien_series(prec=40) - 1 + t^12 + t^20 + t^24 + t^30 + t^32 + t^36 + O(t^40) - - :: - - sage: G = MatrixGroup(CyclicPermutationGroup(3)) - sage: chi = G.character(G.character_table()[1]) - sage: G.molien_series(chi, prec=10) - t + 2*t^2 + 3*t^3 + 5*t^4 + 7*t^5 + 9*t^6 + 12*t^7 + 15*t^8 + 18*t^9 + 22*t^10 + O(t^11) - - :: - - sage: K = GF(5) - sage: S = MatrixGroup(SymmetricGroup(4)) - sage: G = MatrixGroup([matrix(K,4,4,[K(y) for u in m.list() for y in u])for m in S.gens()]) - sage: G.molien_series(return_series=False) - 1/(t^10 - t^9 - t^8 + 2*t^5 - t^2 - t + 1) - - :: - - sage: i = GF(7)(3) - sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) - sage: chi = G.character(G.character_table()[4]) - sage: G.molien_series(chi) - 3*t^5 + 6*t^11 + 9*t^17 + 12*t^23 + O(t^25) - """ - if not self.is_finite(): - raise NotImplementedError("only implemented for finite groups") - if chi is None: - chi = self.trivial_character() - M = self.matrix_space() - R = FractionField(self.base_ring()) - N = self.order() - if R.characteristic() == 0: - P = PolynomialRing(R, variable) - t = P.gen() - # it is possible the character is over a larger cyclotomic field - K = chi.values()[0].parent() - if K.degree() != 1: - if R.degree() != 1: - L = K.composite_fields(R)[0] - else: - L = K - else: - L = R - mol = P(0) - for g in self: - mol += L(chi(g)) / (M.identity_matrix()-t*g.matrix()).det().change_ring(L) - elif R.characteristic().divides(N): - raise NotImplementedError("characteristic cannot divide group order") - else: # char p>0 - # find primitive Nth roots of unity over base ring and QQ - F = cyclotomic_polynomial(N).change_ring(R) - w = F.roots(ring=R.algebraic_closure(), multiplicities=False)[0] - # don't need to extend further in this case since the order of - # the roots of unity in the character divide the order of the group - L = CyclotomicField(N, 'v') - v = L.gen() - # construct Molien series - P = PolynomialRing(L, variable) - t = P.gen() - mol = P(0) - for g in self: - # construct Phi - phi = L(chi(g)) - for e in g.matrix().eigenvalues(): - # find power such that w**n = e - n = 1 - while w**n != e and n < N+1: - n += 1 - # raise v to that power - phi *= (1-t*v**n) - mol += P(1)/phi - # We know the coefficients will be integers - mol = mol.numerator().change_ring(ZZ) / mol.denominator().change_ring(ZZ) - # divide by group order - mol /= N - if return_series: - PS = PowerSeriesRing(ZZ, variable, default_prec=prec) - return PS(mol) - return mol - - def reynolds_operator(self, poly, chi=None): - r""" - Compute the Reynolds operator of this finite group `G`. - - This is the projection from a polynomial ring to the ring of - relative invariants [Stu1993]_. If possible, the invariant is - returned defined over the base field of the given polynomial - ``poly``, otherwise, it is returned over the compositum of the - fields involved in the computation. - Only implemented for absolute fields. - - ALGORITHM: - - Let `K[x]` be a polynomial ring and `\chi` a linear character for `G`. Let - - .. MATH: - - K[x]^G_{\chi} = \{f \in K[x] | \pi f = \chi(\pi) f \forall \pi\in G\} - - be the ring of invariants of `G` relative to `\chi`. Then the Reynold's operator - is a map `R` from `K[x]` into `K[x]^G_{\chi}` defined by - - .. MATH: - - f \mapsto \frac{1}{|G|} \sum_{ \pi \in G} \chi(\pi) f. - - INPUT: - - - ``poly`` -- a polynomial - - - ``chi`` -- (default: trivial character) a linear group character of this group - - OUTPUT: an invariant polynomial relative to `\chi` - - AUTHORS: - - Rebecca Lauren Miller and Ben Hutz - - EXAMPLES:: - - sage: S3 = MatrixGroup(SymmetricGroup(3)) - sage: R.<x,y,z> = QQ[] - sage: f = x*y*z^3 - sage: S3.reynolds_operator(f) - 1/3*x^3*y*z + 1/3*x*y^3*z + 1/3*x*y*z^3 - - :: - - sage: G = MatrixGroup(CyclicPermutationGroup(4)) - sage: chi = G.character(G.character_table()[3]) - sage: K.<v> = CyclotomicField(4) - sage: R.<x,y,z,w> = K[] - sage: G.reynolds_operator(x, chi) - 1/4*x + (1/4*v)*y - 1/4*z + (-1/4*v)*w - sage: chi = G.character(G.character_table()[2]) - sage: R.<x,y,z,w> = QQ[] - sage: G.reynolds_operator(x*y, chi) - 1/4*x*y + (-1/4*zeta4)*y*z + (1/4*zeta4)*x*w - 1/4*z*w - - :: - - sage: K.<i> = CyclotomicField(4) - sage: G = MatrixGroup(CyclicPermutationGroup(3)) - sage: chi = G.character(G.character_table()[1]) - sage: R.<x,y,z> = K[] - sage: G.reynolds_operator(x*y^5, chi) - 1/3*x*y^5 + (-2/3*izeta3^3 - izeta3^2 - 8/3*izeta3 - 4/3)*x^5*z + (2/3*izeta3^3 + izeta3^2 + 8/3*izeta3 + 1)*y*z^5 - sage: R.<x,y,z> = QQbar[] - sage: G.reynolds_operator(x*y^5, chi) - 1/3*x*y^5 + (-0.1666666666666667? + 0.2886751345948129?*I)*x^5*z + (-0.1666666666666667? - 0.2886751345948129?*I)*y*z^5 - - :: - - sage: K.<i> = CyclotomicField(4) - sage: Tetra = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [0,i, -i,0]) - sage: chi = Tetra.character(Tetra.character_table()[4]) - sage: L.<v> = QuadraticField(-3) - sage: R.<x,y> = L[] - sage: Tetra.reynolds_operator(x^4) - 0 - sage: Tetra.reynolds_operator(x^4, chi) - 1/4*x^4 + (1/2*v)*x^2*y^2 + 1/4*y^4 - sage: R.<x>=L[] - sage: LL.<w> = L.extension(x^2+v) - sage: R.<x,y> = LL[] - sage: Tetra.reynolds_operator(x^4, chi) - Traceback (most recent call last): - ... - NotImplementedError: only implemented for absolute fields - - :: - - sage: G = MatrixGroup(DihedralGroup(4)) - sage: chi = G.character(G.character_table()[1]) - sage: R.<x,y> = QQ[] - sage: f = x^4 - sage: G.reynolds_operator(f, chi) - Traceback (most recent call last): - ... - TypeError: number of variables in polynomial must match size of matrices - sage: R.<x,y,z,w> = QQ[] - sage: f = x^3*y - sage: G.reynolds_operator(f, chi) - 1/8*x^3*y - 1/8*x*y^3 + 1/8*y^3*z - 1/8*y*z^3 - 1/8*x^3*w + 1/8*z^3*w + - 1/8*x*w^3 - 1/8*z*w^3 - - Characteristic p>0 examples:: - - sage: G = MatrixGroup([[0,1,1,0]]) - sage: R.<w,x> = GF(2)[] - sage: G.reynolds_operator(x) - Traceback (most recent call last): - ... - NotImplementedError: not implemented when characteristic divides group order - - :: - - sage: i = GF(7)(3) - sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) - sage: chi = G.character(G.character_table()[4]) - sage: R.<w,x> = GF(7)[] - sage: f = w^5*x + x^6 - sage: G.reynolds_operator(f, chi) - Traceback (most recent call last): - ... - NotImplementedError: nontrivial characters not implemented for characteristic > 0 - sage: G.reynolds_operator(f) - x^6 - - :: - - sage: K = GF(3^2,'t') - sage: G = MatrixGroup([matrix(K,2,2, [0,K.gen(),1,0])]) - sage: R.<x,y> = GF(3)[] - sage: G.reynolds_operator(x^8) - -x^8 - y^8 - - :: - - sage: K = GF(3^2,'t') - sage: G = MatrixGroup([matrix(GF(3),2,2, [0,1,1,0])]) - sage: R.<x,y> = K[] - sage: f = -K.gen()*x - sage: G.reynolds_operator(f) - t*x + t*y - """ - if poly.parent().ngens() != self.degree(): - raise TypeError("number of variables in polynomial must match size of matrices") - R = FractionField(poly.base_ring()) - C = FractionField(self.base_ring()) - if chi is None: # then this is the trivial character - if R.characteristic() == 0: - # non-modular case - if C == QQbar or R == QQbar: - L = QQbar - elif not C.is_absolute() or not R.is_absolute(): - raise NotImplementedError("only implemented for absolute fields") - else: # create the compositum - if C.absolute_degree() == 1: - L = R - elif R.absolute_degree() == 1: - L = C - else: - L = C.composite_fields(R)[0] - elif not R.characteristic().divides(self.order()): - if R.characteristic() != C.characteristic(): - raise ValueError("base fields must have same characteristic") - else: - if R.degree() >= C.degree(): - L = R - else: - L = C - else: - raise NotImplementedError("not implemented when characteristic divides group order") - poly = poly.change_ring(L) - poly_gens = vector(poly.parent().gens()) - F = L.zero() - for g in self: - F += poly(*g.matrix()*vector(poly.parent().gens())) - F /= self.order() - return F - # non-trivial character case - K = chi.values()[0].parent() - if R.characteristic() == 0: - # extend base_ring to compositum - if C == QQbar or K == QQbar or R == QQbar: - L = QQbar - elif not C.is_absolute() or not K.is_absolute() or not R.is_absolute(): - raise NotImplementedError("only implemented for absolute fields") - else: - fields = [] - for M in [R,K,C]: - if M.absolute_degree() != 1: - fields.append(M) - l = len(fields) - if l == 0: - # all are QQ - L = R - elif l == 1: - # only one is an extension - L = fields[0] - elif l == 2: - # only two are extensions - L = fields[0].composite_fields(fields[1])[0] - else: - # all three are extensions - L1 = fields[0].composite_fields(fields[1])[0] - L = L1.composite_fields(fields[2])[0] - else: - raise NotImplementedError("nontrivial characters not implemented for characteristic > 0") - poly = poly.change_ring(L) - poly_gens = vector(poly.parent().gens()) - F = L.zero() - for g in self: - F += L(chi(g)) * poly(*g.matrix().change_ring(L)*poly_gens) - F /= self.order() - try: # attempt to move F to base_ring of polynomial - F = F.change_ring(R) - except (TypeError, ValueError): - pass - return F - - def invariants_of_degree(self, deg, chi=None, R=None): - r""" - Return the (relative) invariants of given degree for this group. - - For this group, compute the invariants of degree ``deg`` - with respect to the group character ``chi``. The method - is to project each possible monomial of degree ``deg`` via - the Reynolds operator. Note that if the polynomial ring ``R`` - is specified it's base ring may be extended if the resulting - invariant is defined over a bigger field. - - INPUT: - - - ``degree`` -- a positive integer - - - ``chi`` -- (default: trivial character) a linear group character of this group - - - ``R`` -- (optional) a polynomial ring - - OUTPUT: list of polynomials - - EXAMPLES:: - - sage: Gr = MatrixGroup(SymmetricGroup(2)) - sage: sorted(Gr.invariants_of_degree(3)) - [x0^2*x1 + x0*x1^2, x0^3 + x1^3] - sage: R.<x,y> = QQ[] - sage: sorted(Gr.invariants_of_degree(4, R=R)) - [x^2*y^2, x^3*y + x*y^3, x^4 + y^4] - - :: - - sage: R.<x,y,z> = QQ[] - sage: Gr = MatrixGroup(DihedralGroup(3)) - sage: ct = Gr.character_table() - sage: chi = Gr.character(ct[0]) - sage: all(f(*(g.matrix()*vector(R.gens()))) == chi(g)*f - ....: for f in Gr.invariants_of_degree(3, R=R, chi=chi) for g in Gr) - True - - :: - - sage: i = GF(7)(3) - sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) - sage: G.invariants_of_degree(25) - [] - - :: - - sage: G = MatrixGroup(SymmetricGroup(5)) - sage: R = QQ['x,y'] - sage: G.invariants_of_degree(3, R=R) - Traceback (most recent call last): - ... - TypeError: number of variables in polynomial ring must match size of matrices - - :: - - sage: K.<i> = CyclotomicField(4) - sage: G = MatrixGroup(CyclicPermutationGroup(3)) - sage: chi = G.character(G.character_table()[1]) - sage: R.<x,y,z> = K[] - sage: sorted(G.invariants_of_degree(2, R=R, chi=chi)) - [x*y + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*x*z + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y*z, - x^2 + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y^2 + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*z^2] - - :: - - sage: S3 = MatrixGroup(SymmetricGroup(3)) - sage: chi = S3.character(S3.character_table()[0]) - sage: sorted(S3.invariants_of_degree(5, chi=chi)) - [x0^3*x1^2 - x0^2*x1^3 - x0^3*x2^2 + x1^3*x2^2 + x0^2*x2^3 - x1^2*x2^3, - x0^4*x1 - x0*x1^4 - x0^4*x2 + x1^4*x2 + x0*x2^4 - x1*x2^4] - """ - D = self.degree() - deg = int(deg) - if deg <= 0: - raise ValueError("degree must be a positive integer") - if R is None: - R = PolynomialRing(self.base_ring(), 'x', D) - elif R.ngens() != D: - raise TypeError("number of variables in polynomial ring must match size of matrices") - - ms = self.molien_series(prec=deg+1,chi=chi) - if ms[deg].is_zero(): - return [] - inv = set() - for e in IntegerVectors(deg, D): - F = self.reynolds_operator(R.monomial(*e), chi=chi) - if not F.is_zero(): - F = F / F.lc() - inv.add(F) - if len(inv) == ms[deg]: - break - return list(inv) diff --git a/src/sage/groups/matrix_gps/finitely_generated_gap.py b/src/sage/groups/matrix_gps/finitely_generated_gap.py new file mode 100644 index 00000000000..5864f64afd3 --- /dev/null +++ b/src/sage/groups/matrix_gps/finitely_generated_gap.py @@ -0,0 +1,945 @@ +""" +Finitely Generated Matrix Groups with GAP +""" + +# ############################################################################# +# Copyright (C) 2006 William Stein <wstein@gmail.com> +# 2006-2008 David Joyner +# 2008-2010 Simon King +# 2009 Mike Hansen +# 2011-2013 Volker Braun <vbraun.name@gmail.com> +# 2013-2023 Travis Scrimshaw +# 2015 Pierre Guillot +# 2017 Ben Hutz +# 2017 Rebecca Lauren Miller +# 2018 Dima Pasechnik +# 2018-2019 Sebastian Oehms +# 2018-2020 Frรฉdรฉric Chapoton +# 2019 Vincent Delecroix +# 2023 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# The full text of the GPL is available at: +# +# https://www.gnu.org/licenses/ +# ############################################################################# + +from sage.combinat.integer_vector import IntegerVectors +from sage.groups.matrix_gps.finitely_generated import MatrixGroup +from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap +from sage.matrix.matrix_space import MatrixSpace +from sage.misc.cachefunc import cached_method +from sage.misc.functional import cyclotomic_polynomial +from sage.modules.free_module_element import vector +from sage.rings.fraction_field import FractionField +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence + + +class FinitelyGeneratedMatrixGroup_gap(MatrixGroup_gap): + """ + Matrix group generated by a finite number of matrices. + + EXAMPLES:: + + sage: m1 = matrix(GF(11), [[1,2],[3,4]]) + sage: m2 = matrix(GF(11), [[1,3],[10,0]]) + sage: G = MatrixGroup(m1, m2); G + Matrix group over Finite Field of size 11 with 2 generators ( + [1 2] [ 1 3] + [3 4], [10 0] + ) + sage: type(G) + <class 'sage.groups.matrix_gps.finitely_generated_gap.FinitelyGeneratedMatrixGroup_gap_with_category'> + sage: TestSuite(G).run() + """ + + def __reduce__(self): + """ + Implement pickling. + + EXAMPLES:: + + sage: m1 = matrix(QQ, [[1,2],[3,4]]) + sage: m2 = matrix(QQ, [[1,3],[-1,0]]) + sage: loads(MatrixGroup(m1, m2).dumps()) + Matrix group over Rational Field with 2 generators ( + [1 2] [ 1 3] + [3 4], [-1 0] + ) + """ + return (MatrixGroup, + tuple(g.matrix() for g in self.gens()) + ({'check':False},)) + + def as_permutation_group(self, algorithm=None, seed=None): + r""" + Return a permutation group representation for the group. + + In most cases occurring in practice, this is a permutation + group of minimal degree (the degree being determined from + orbits under the group action). When these orbits are hard to + compute, the procedure can be time-consuming and the degree + may not be minimal. + + INPUT: + + - ``algorithm`` -- ``None`` or ``'smaller'``. In the latter + case, try harder to find a permutation representation of + small degree. + - ``seed`` -- ``None`` or an integer specifying the seed + to fix results depending on pseudo-random-numbers. Here + it makes sense to be used with respect to the ``'smaller'`` + option, since GAP produces random output in that context. + + OUTPUT: + + A permutation group isomorphic to ``self``. The + ``algorithm='smaller'`` option tries to return an isomorphic + group of low degree, but is not guaranteed to find the + smallest one and must not even differ from the one obtained + without the option. In that case repeating the invocation + may help (see the example below). + + EXAMPLES:: + + sage: MS = MatrixSpace(GF(2), 5, 5) + sage: A = MS([[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0]]) + sage: G = MatrixGroup([A]) + sage: G.as_permutation_group().order() + 2 + + A finite subgroup of `GL(12,\ZZ)` as a permutation group:: + + sage: imf = libgap.function_factory('ImfMatrixGroup') + sage: GG = imf( 12, 3 ) + sage: G = MatrixGroup(GG.GeneratorsOfGroup()) + sage: G.cardinality() + 21499084800 + sage: P = G.as_permutation_group() + sage: Psmaller = G.as_permutation_group(algorithm="smaller", seed=6) + sage: P == Psmaller + False + sage: P.cardinality() + 21499084800 + sage: P.degree() + 144 + sage: Psmaller.cardinality() + 21499084800 + sage: Psmaller.degree() # random + 80 + + .. NOTE:: + + In this case, the "smaller" option returned an isomorphic + group of lower degree. The above example used GAP's library + of irreducible maximal finite ("imf") integer matrix groups + to construct the :class:`MatrixGroup` `G` over `\GF{7}`. The section + "Irreducible Maximal Finite Integral Matrix Groups" in the + GAP reference manual has more details. + + .. NOTE:: + + Concerning the option ``algorithm='smaller'`` you should note + the following from GAP documentation: "The methods used might + involve the use of random elements and the permutation + representation (or even the degree of the representation) is + not guaranteed to be the same for different calls of + ``SmallerDegreePermutationRepresentation``." + + To obtain a reproducible result the optional argument ``seed`` + may be used as in the example above. + + TESTS:: + + sage: A = matrix(QQ, 2, [0, 1, 1, 0]) + sage: B = matrix(QQ, 2, [1, 0, 0, 1]) + sage: a, b = MatrixGroup([A, B]).as_permutation_group().gens() + sage: a.order(), b.order() + (2, 1) + + The above example in `GL(12,\ZZ)`, reduced modulo 7:: + + sage: MS = MatrixSpace(GF(7), 12, 12) + sage: G = MatrixGroup([MS(g) for g in GG.GeneratorsOfGroup()]) + sage: G.cardinality() + 21499084800 + sage: P = G.as_permutation_group() + sage: P.cardinality() + 21499084800 + + Check that large degree is still working:: + + sage: Sp(6,3).as_permutation_group().cardinality() + 9170703360 + + Check that :trac:`25706` still works after :trac:`26903`:: + + sage: # needs sage.libs.pari + sage: MG = GU(3,2).as_matrix_group() + sage: PG = MG.as_permutation_group() + sage: mg = MG.an_element() + sage: PG(mg).order() # particular element depends on the set of GAP packages installed + 6 + """ + # Note that the output of IsomorphismPermGroup() depends on + # memory locations and will change if you change the order of + # doctests and/or architecture + from sage.groups.perm_gps.permgroup import PermutationGroup + if not self.is_finite(): + raise NotImplementedError("group must be finite") + if seed is not None: + from sage.libs.gap.libgap import libgap + libgap.set_seed(ZZ(seed)) + iso = self._libgap_().IsomorphismPermGroup() + if algorithm == "smaller": + iso = iso.Image().SmallerDegreePermutationRepresentation() + return PermutationGroup(iso.Image().GeneratorsOfGroup().sage(), + canonicalize=False) + + def module_composition_factors(self, algorithm=None): + r""" + Return a list of triples consisting of [base field, dimension, + irreducibility], for each of the Meataxe composition factors + modules. The ``algorithm="verbose"`` option returns more information, + but in Meataxe notation. + + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,4,4) + sage: M = MS(0) + sage: M[0,1] = 1; M[1,2] = 1; M[2,3] = 1; M[3,0] = 1 + sage: G = MatrixGroup([M]) + sage: G.module_composition_factors() + [(Finite Field of size 3, 1, True), + (Finite Field of size 3, 1, True), + (Finite Field of size 3, 2, True)] + sage: F = GF(7); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[0,1],[-1,0]]), MS([[1,1],[2,3]])] + sage: G = MatrixGroup(gens) + sage: G.module_composition_factors() + [(Finite Field of size 7, 2, True)] + + Type ``G.module_composition_factors(algorithm='verbose')`` to get a + more verbose version. + + For more on MeatAxe notation, see + https://www.gap-system.org/Manuals/doc/ref/chap69.html + """ + from sage.libs.gap.libgap import libgap + F = self.base_ring() + if not F.is_finite(): + raise NotImplementedError("base ring must be finite") + n = self.degree() + MS = MatrixSpace(F, n, n) + mats = [MS(g.matrix()) for g in self.gens()] + # initializing list of mats by which the gens act on self + mats_gap = libgap(mats) + M = mats_gap.GModuleByMats(F) + compo = libgap.function_factory('MTX.CompositionFactors') + MCFs = compo(M) + if algorithm == "verbose": + print(str(MCFs) + "\n") + return sorted((MCF['field'].sage(), + MCF['dimension'].sage(), + MCF['IsIrreducible'].sage()) for MCF in MCFs) + + def invariant_generators(self): + r""" + Return invariant ring generators. + + Computes generators for the polynomial ring + `F[x_1,\ldots,x_n]^G`, where `G` in `GL(n,F)` is a finite matrix + group. + + In the "good characteristic" case the polynomials returned + form a minimal generating set for the algebra of `G`-invariant + polynomials. In the "bad" case, the polynomials returned + are primary and secondary invariants, forming a not + necessarily minimal generating set for the algebra of + `G`-invariant polynomials. + + ALGORITHM: + + Wraps Singular's ``invariant_algebra_reynolds`` and ``invariant_ring`` + in ``finvar.lib``. + + EXAMPLES:: + + sage: F = GF(7); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])] + sage: G = MatrixGroup(gens) + sage: G.invariant_generators() # needs sage.libs.singular + [x1^7*x2 - x1*x2^7, + x1^12 - 2*x1^9*x2^3 - x1^6*x2^6 + 2*x1^3*x2^9 + x2^12, + x1^18 + 2*x1^15*x2^3 + 3*x1^12*x2^6 + 3*x1^6*x2^12 - 2*x1^3*x2^15 + x2^18] + + sage: q = 4; a = 2 + sage: MS = MatrixSpace(QQ, 2, 2) + sage: gen1 = [[1/a, (q-1)/a], [1/a, -1/a]] + sage: gen2 = [[1,0], [0,-1]]; gen3 = [[-1,0], [0,1]] + sage: G = MatrixGroup([MS(gen1), MS(gen2), MS(gen3)]) + sage: G.cardinality() + 12 + sage: G.invariant_generators() # needs sage.libs.singular + [x1^2 + 3*x2^2, x1^6 + 15*x1^4*x2^2 + 15*x1^2*x2^4 + 33*x2^6] + + sage: # needs sage.rings.number_field + sage: F = CyclotomicField(8) + sage: z = F.gen() + sage: a = z+1/z + sage: b = z^2 + sage: MS = MatrixSpace(F,2,2) + sage: g1 = MS([[1/a, 1/a], [1/a, -1/a]]) + sage: g2 = MS([[-b, 0], [0, b]]) + sage: G = MatrixGroup([g1,g2]) + sage: G.invariant_generators() # needs sage.libs.singular + [x1^4 + 2*x1^2*x2^2 + x2^4, + x1^5*x2 - x1*x2^5, + x1^8 + 28/9*x1^6*x2^2 + 70/9*x1^4*x2^4 + 28/9*x1^2*x2^6 + x2^8] + + AUTHORS: + + - David Joyner, Simon King and Martin Albrecht. + + REFERENCES: + + - Singular reference manual + + - [Stu1993]_ + + - S. King, "Minimal Generating Sets of non-modular invariant + rings of finite groups", :arxiv:`math/0703035`. + """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + from sage.interfaces.singular import singular + gens = self.gens() + singular.LIB("finvar.lib") + n = self.degree() # len((gens[0].matrix()).rows()) + F = self.base_ring() + q = F.characteristic() + # test if the field is admissible + if F.gen() == 1: # we got the rationals or GF(prime) + FieldStr = str(F.characteristic()) + elif hasattr(F,'polynomial'): # we got an algebraic extension + if len(F.gens()) > 1: + raise NotImplementedError("can only deal with finite fields and (simple algebraic extensions of) the rationals") + FieldStr = '(%d,%s)' % (F.characteristic(), str(F.gen())) + else: # we have a transcendental extension + FieldStr = '(%d,%s)' % (F.characteristic(), + ','.join(str(p) for p in F.gens())) + + # Setting Singular's variable names + # We need to make sure that field generator and variables get different names. + if str(F.gen())[0] == 'x': + VarStr = 'y' + else: + VarStr = 'x' + VarNames = '(' + ','.join((VarStr+str(i) for i in range(1, n+1)))+')' + # The function call and affectation below have side-effects. Do not remove! + # (even if pyflakes say so) + R = singular.ring(FieldStr, VarNames, 'dp') + if hasattr(F, 'polynomial') and F.gen() != 1: + # we have to define minpoly + singular.eval('minpoly = '+str(F.polynomial()).replace('x',str(F.gen()))) + A = [singular.matrix(n,n,str((x.matrix()).list())) for x in gens] + Lgens = ','.join((x.name() for x in A)) + PR = PolynomialRing(F, n, [VarStr+str(i) for i in range(1,n+1)]) + + if q == 0 or (q > 0 and self.cardinality() % q): + from sage.matrix.constructor import Matrix + try: + elements = [g.matrix() for g in self.list()] + except (TypeError, ValueError): + elements + if elements is not None: + ReyName = 't'+singular._next_var_name() + singular.eval('matrix %s[%d][%d]' % (ReyName, + self.cardinality(), n)) + for i in range(1,self.cardinality()+1): + M = Matrix(F, elements[i-1]) + D = [{} for foobar in range(self.degree())] + for x,y in M.dict().items(): + D[x[0]][x[1]] = y + for row in range(self.degree()): + for t in D[row].items(): + singular.eval('%s[%d,%d]=%s[%d,%d]+(%s)*var(%d)' + % (ReyName,i,row+1,ReyName,i,row+1, repr(t[1]),t[0]+1)) + IRName = 't'+singular._next_var_name() + singular.eval('matrix %s = invariant_algebra_reynolds(%s)' % (IRName,ReyName)) + else: + ReyName = 't'+singular._next_var_name() + singular.eval('list %s=group_reynolds((%s))' % (ReyName, Lgens)) + IRName = 't'+singular._next_var_name() + singular.eval('matrix %s = invariant_algebra_reynolds(%s[1])' % (IRName, ReyName)) + + OUT = [singular.eval(IRName+'[1,%d]' % (j)) + for j in range(1, 1+int(singular('ncols('+IRName+')')))] + return [PR(gen) for gen in OUT] + if self.cardinality() % q == 0: + PName = 't' + singular._next_var_name() + SName = 't' + singular._next_var_name() + singular.eval('matrix %s,%s=invariant_ring(%s)' % (PName, SName, Lgens)) + OUT = [singular.eval(PName+'[1,%d]' % (j)) + for j in range(1,1+singular('ncols('+PName+')'))] + OUT += [singular.eval(SName+'[1,%d]' % (j)) + for j in range(2,1+singular('ncols('+SName+')'))] + return [PR(gen) for gen in OUT] + + def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): + r""" + Compute the Molien series of this finite group with respect to the + character ``chi``. + + It can be returned either as a rational function in one variable + or a power series in one variable. The base field must be a + finite field, the rationals, or a cyclotomic field. + + Note that the base field characteristic cannot divide the group + order (i.e., the non-modular case). + + ALGORITHM: + + For a finite group `G` in characteristic zero we construct + the Molien series as + + .. MATH:: + + \frac{1}{|G|}\sum_{g \in G} \frac{\chi(g)}{\text{det}(I-tg)}, + + where `I` is the identity matrix and `t` an indeterminate. + + For characteristic `p` not dividing the order of `G`, let `k` be + the base field and `N` the order of `G`. Define `\lambda` as a + primitive `N`-th root of unity over `k` and `\omega` as a + primitive `N`-th root of unity over `\QQ`. For each `g \in G` + define `k_i(g)` to be the positive integer such that + `e_i = \lambda^{k_i(g)}` for each eigenvalue `e_i` of `g`. + Then the Molien series is computed as + + .. MATH:: + + \frac{1}{|G|}\sum_{g \in G} \frac{\chi(g)}{\prod_{i=1}^n + (1 - t\omega^{k_i(g)})}, + + where `t` is an indeterminant. [Dec1998]_ + + INPUT: + + - ``chi`` -- (default: trivial character) a linear group character of this group + - ``return_series`` -- boolean (default: ``True``) if ``True``, then returns + the Molien series as a power series, ``False`` as a rational function + - ``prec`` -- integer (default: 20); power series default precision + (possibly infinite, in which case it is computed lazily) + - ``variable`` -- string (default: ``'t'``); variable name for the Molien series + + OUTPUT: single variable rational function or power series with integer coefficients + + EXAMPLES:: + + sage: MatrixGroup(matrix(QQ,2,2,[1,1,0,1])).molien_series() + Traceback (most recent call last): + ... + NotImplementedError: only implemented for finite groups + sage: MatrixGroup(matrix(GF(3),2,2,[1,1,0,1])).molien_series() # needs sage.rings.number_field + Traceback (most recent call last): + ... + NotImplementedError: characteristic cannot divide group order + + Tetrahedral Group:: + + sage: # needs sage.rings.number_field + sage: K.<i> = CyclotomicField(4) + sage: Tetra = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [0,i, -i,0]) + sage: Tetra.molien_series(prec=30) + 1 + t^8 + 2*t^12 + t^16 + 2*t^20 + 3*t^24 + 2*t^28 + O(t^30) + sage: mol = Tetra.molien_series(return_series=False); mol + (t^8 - t^4 + 1)/(t^16 - t^12 - t^4 + 1) + sage: mol.parent() + Fraction Field of Univariate Polynomial Ring in t over Integer Ring + sage: chi = Tetra.character(Tetra.character_table()[1]) + sage: Tetra.molien_series(chi, prec=30, variable='u') + u^6 + u^14 + 2*u^18 + u^22 + 2*u^26 + 3*u^30 + 2*u^34 + O(u^36) + sage: chi = Tetra.character(Tetra.character_table()[2]) + sage: Tetra.molien_series(chi) + t^10 + t^14 + t^18 + 2*t^22 + 2*t^26 + O(t^30) + + :: + + sage: # needs sage.groups sage.rings.number_field + sage: S3 = MatrixGroup(SymmetricGroup(3)) + sage: mol = S3.molien_series(prec=10); mol + 1 + t + 2*t^2 + 3*t^3 + 4*t^4 + 5*t^5 + 7*t^6 + 8*t^7 + 10*t^8 + 12*t^9 + O(t^10) + sage: mol.parent() + Power Series Ring in t over Integer Ring + sage: mol = S3.molien_series(prec=oo); mol + 1 + t + 2*t^2 + 3*t^3 + 4*t^4 + 5*t^5 + 7*t^6 + O(t^7) + sage: mol.parent() + Lazy Taylor Series Ring in t over Integer Ring + + Octahedral Group:: + + sage: # needs sage.rings.number_field + sage: K.<v> = CyclotomicField(8) + sage: a = v - v^3 # sqrt(2) + sage: i = v^2 + sage: Octa = MatrixGroup([(-1+i)/2, (-1+i)/2, (1+i)/2, (-1-i)/2], # needs sage.symbolic + ....: [(1+i)/a, 0, 0, (1-i)/a]) + sage: Octa.molien_series(prec=30) # needs sage.symbolic + 1 + t^8 + t^12 + t^16 + t^18 + t^20 + 2*t^24 + t^26 + t^28 + O(t^30) + + Icosahedral Group:: + + sage: # needs sage.rings.number_field + sage: K.<v> = CyclotomicField(10) + sage: z5 = v^2 + sage: i = z5^5 + sage: a = 2*z5^3 + 2*z5^2 + 1 #sqrt(5) + sage: Ico = MatrixGroup([[z5^3,0, 0,z5^2], + ....: [0,1, -1,0], + ....: [(z5^4-z5)/a, (z5^2-z5^3)/a, + ....: (z5^2-z5^3)/a, -(z5^4-z5)/a]]) + sage: Ico.molien_series(prec=40) + 1 + t^12 + t^20 + t^24 + t^30 + t^32 + t^36 + O(t^40) + + :: + + sage: # needs sage.groups sage.rings.number_field + sage: G = MatrixGroup(CyclicPermutationGroup(3)) + sage: chi = G.character(G.character_table()[1]) + sage: G.molien_series(chi, prec=10) + t + 2*t^2 + 3*t^3 + 5*t^4 + 7*t^5 + 9*t^6 + + 12*t^7 + 15*t^8 + 18*t^9 + 22*t^10 + O(t^11) + + :: + + sage: # needs sage.groups sage.rings.number_field + sage: K = GF(5) + sage: S = MatrixGroup(SymmetricGroup(4)) + sage: G = MatrixGroup([matrix(K, 4, 4, + ....: [K(y) for u in m.list() for y in u]) + ....: for m in S.gens()]) + sage: G.molien_series(return_series=False) + 1/(t^10 - t^9 - t^8 + 2*t^5 - t^2 - t + 1) + + :: + + sage: # needs sage.rings.number_field + sage: i = GF(7)(3) + sage: G = MatrixGroup([[i^3,0, 0,-i^3], [i^2,0, 0,-i^2]]) + sage: chi = G.character(G.character_table()[4]) + sage: G.molien_series(chi) + 3*t^5 + 6*t^11 + 9*t^17 + 12*t^23 + O(t^25) + """ + if not self.is_finite(): + raise NotImplementedError("only implemented for finite groups") + if chi is None: + chi = self.trivial_character() + M = self.matrix_space() + R = FractionField(self.base_ring()) + N = self.order() + if R.characteristic() == 0: + P = PolynomialRing(R, variable) + t = P.gen() + # it is possible the character is over a larger cyclotomic field + K = chi.values()[0].parent() + if K.degree() != 1: + if R.degree() != 1: + L = K.composite_fields(R)[0] + else: + L = K + else: + L = R + mol = P(0) + for g in self: + mol += L(chi(g)) / (M.identity_matrix()-t*g.matrix()).det().change_ring(L) + elif R.characteristic().divides(N): + raise NotImplementedError("characteristic cannot divide group order") + else: # char p>0 + # find primitive Nth roots of unity over base ring and QQ + F = cyclotomic_polynomial(N).change_ring(R) + w = F.roots(ring=R.algebraic_closure(), multiplicities=False)[0] + # don't need to extend further in this case since the order of + # the roots of unity in the character divide the order of the group + from sage.rings.number_field.number_field import CyclotomicField + L = CyclotomicField(N, 'v') + v = L.gen() + # construct Molien series + P = PolynomialRing(L, variable) + t = P.gen() + mol = P(0) + for g in self: + # construct Phi + phi = L(chi(g)) + for e in g.matrix().eigenvalues(): + # find power such that w**n = e + n = 1 + while w**n != e and n < N+1: + n += 1 + # raise v to that power + phi *= (1-t*v**n) + mol += P(1)/phi + # We know the coefficients will be integers + mol = mol.numerator().change_ring(ZZ) / mol.denominator().change_ring(ZZ) + # divide by group order + mol /= N + if return_series: + if prec == float('inf'): + from sage.rings.lazy_series_ring import LazyPowerSeriesRing + PS = LazyPowerSeriesRing(ZZ, names=(variable,), sparse=P.is_sparse()) + else: + PS = PowerSeriesRing(ZZ, variable, default_prec=prec) + return PS(mol) + return mol + + def reynolds_operator(self, poly, chi=None): + r""" + Compute the Reynolds operator of this finite group `G`. + + This is the projection from a polynomial ring to the ring of + relative invariants [Stu1993]_. If possible, the invariant is + returned defined over the base field of the given polynomial + ``poly``, otherwise, it is returned over the compositum of the + fields involved in the computation. + Only implemented for absolute fields. + + ALGORITHM: + + Let `K[x]` be a polynomial ring and `\chi` a linear character for `G`. Let + + .. MATH: + + K[x]^G_{\chi} = \{f \in K[x] | \pi f = \chi(\pi) f \forall \pi\in G\} + + be the ring of invariants of `G` relative to `\chi`. Then the Reynolds operator + is a map `R` from `K[x]` into `K[x]^G_{\chi}` defined by + + .. MATH: + + f \mapsto \frac{1}{|G|} \sum_{ \pi \in G} \chi(\pi) f. + + INPUT: + + - ``poly`` -- a polynomial + + - ``chi`` -- (default: trivial character) a linear group character of this group + + OUTPUT: an invariant polynomial relative to `\chi` + + AUTHORS: + + Rebecca Lauren Miller and Ben Hutz + + EXAMPLES:: + + sage: S3 = MatrixGroup(SymmetricGroup(3)) + sage: R.<x,y,z> = QQ[] + sage: f = x*y*z^3 + sage: S3.reynolds_operator(f) # needs sage.rings.number_field + 1/3*x^3*y*z + 1/3*x*y^3*z + 1/3*x*y*z^3 + + :: + + sage: # needs sage.groups sage.rings.number_field + sage: G = MatrixGroup(CyclicPermutationGroup(4)) + sage: chi = G.character(G.character_table()[3]) + sage: K.<v> = CyclotomicField(4) + sage: R.<x,y,z,w> = K[] + sage: G.reynolds_operator(x, chi) + 1/4*x + (1/4*v)*y - 1/4*z + (-1/4*v)*w + sage: chi = G.character(G.character_table()[2]) + sage: R.<x,y,z,w> = QQ[] + sage: G.reynolds_operator(x*y, chi) + 1/4*x*y + (-1/4*zeta4)*y*z + (1/4*zeta4)*x*w - 1/4*z*w + + :: + + sage: # needs sage.groups sage.rings.number_field + sage: K.<i> = CyclotomicField(4) + sage: G = MatrixGroup(CyclicPermutationGroup(3)) + sage: chi = G.character(G.character_table()[1]) + sage: R.<x,y,z> = K[] + sage: G.reynolds_operator(x*y^5, chi) + 1/3*x*y^5 + (-2/3*izeta3^3 - izeta3^2 - 8/3*izeta3 - 4/3)*x^5*z + + (2/3*izeta3^3 + izeta3^2 + 8/3*izeta3 + 1)*y*z^5 + sage: R.<x,y,z> = QQbar[] + sage: G.reynolds_operator(x*y^5, chi) + 1/3*x*y^5 + (-0.1666666666666667? + 0.2886751345948129?*I)*x^5*z + + (-0.1666666666666667? - 0.2886751345948129?*I)*y*z^5 + + :: + + sage: # needs sage.rings.number_field + sage: K.<i> = CyclotomicField(4) + sage: Tetra = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [0,i, -i,0]) + sage: chi = Tetra.character(Tetra.character_table()[4]) + sage: L.<v> = QuadraticField(-3) + sage: R.<x,y> = L[] + sage: Tetra.reynolds_operator(x^4) + 0 + sage: Tetra.reynolds_operator(x^4, chi) + 1/4*x^4 + (1/2*v)*x^2*y^2 + 1/4*y^4 + sage: R.<x>=L[] + sage: LL.<w> = L.extension(x^2 + v) + sage: R.<x,y> = LL[] + sage: Tetra.reynolds_operator(x^4, chi) + Traceback (most recent call last): + ... + NotImplementedError: only implemented for absolute fields + + :: + + sage: # needs sage.groups sage.rings.number_field + sage: G = MatrixGroup(DihedralGroup(4)) + sage: chi = G.character(G.character_table()[1]) + sage: R.<x,y> = QQ[] + sage: f = x^4 + sage: G.reynolds_operator(f, chi) + Traceback (most recent call last): + ... + TypeError: number of variables in polynomial must match size of matrices + sage: R.<x,y,z,w> = QQ[] + sage: f = x^3*y + sage: G.reynolds_operator(f, chi) + 1/8*x^3*y - 1/8*x*y^3 + 1/8*y^3*z - 1/8*y*z^3 - 1/8*x^3*w + 1/8*z^3*w + + 1/8*x*w^3 - 1/8*z*w^3 + + Characteristic `p>0` examples:: + + sage: G = MatrixGroup([[0,1, 1,0]]) + sage: R.<w,x> = GF(2)[] + sage: G.reynolds_operator(x) + Traceback (most recent call last): + ... + NotImplementedError: not implemented when characteristic divides group order + + :: + + sage: i = GF(7)(3) + sage: G = MatrixGroup([[i^3,0, 0,-i^3], [i^2,0, 0,-i^2]]) + sage: chi = G.character(G.character_table()[4]) # needs sage.rings.number_field + sage: R.<w,x> = GF(7)[] + sage: f = w^5*x + x^6 + sage: G.reynolds_operator(f, chi) # needs sage.rings.number_field + Traceback (most recent call last): + ... + NotImplementedError: nontrivial characters not implemented for characteristic > 0 + sage: G.reynolds_operator(f) + x^6 + + :: + + sage: # needs sage.rings.finite_rings + sage: K = GF(3^2,'t') + sage: G = MatrixGroup([matrix(K, 2, 2, [0,K.gen(), 1,0])]) + sage: R.<x,y> = GF(3)[] + sage: G.reynolds_operator(x^8) + -x^8 - y^8 + + :: + + sage: # needs sage.rings.finite_rings + sage: K = GF(3^2,'t') + sage: G = MatrixGroup([matrix(GF(3), 2, 2, [0,1, 1,0])]) + sage: R.<x,y> = K[] + sage: f = -K.gen()*x + sage: G.reynolds_operator(f) + t*x + t*y + """ + if poly.parent().ngens() != self.degree(): + raise TypeError("number of variables in polynomial must match size of matrices") + R = FractionField(poly.base_ring()) + C = FractionField(self.base_ring()) + if chi is None: # then this is the trivial character + if R.characteristic() == 0: + from sage.rings.qqbar import QQbar + # non-modular case + if C == QQbar or R == QQbar: + L = QQbar + elif not C.is_absolute() or not R.is_absolute(): + raise NotImplementedError("only implemented for absolute fields") + else: # create the compositum + if C.absolute_degree() == 1: + L = R + elif R.absolute_degree() == 1: + L = C + else: + L = C.composite_fields(R)[0] + elif not R.characteristic().divides(self.order()): + if R.characteristic() != C.characteristic(): + raise ValueError("base fields must have same characteristic") + else: + if R.degree() >= C.degree(): + L = R + else: + L = C + else: + raise NotImplementedError("not implemented when characteristic divides group order") + poly = poly.change_ring(L) + poly_gens = vector(poly.parent().gens()) + F = L.zero() + for g in self: + F += poly(*g.matrix()*vector(poly.parent().gens())) + F /= self.order() + return F + # non-trivial character case + K = chi.values()[0].parent() + if R.characteristic() == 0: + from sage.rings.qqbar import QQbar + # extend base_ring to compositum + if C == QQbar or K == QQbar or R == QQbar: + L = QQbar + elif not C.is_absolute() or not K.is_absolute() or not R.is_absolute(): + raise NotImplementedError("only implemented for absolute fields") + else: + fields = [] + for M in [R,K,C]: + if M.absolute_degree() != 1: + fields.append(M) + l = len(fields) + if l == 0: + # all are QQ + L = R + elif l == 1: + # only one is an extension + L = fields[0] + elif l == 2: + # only two are extensions + L = fields[0].composite_fields(fields[1])[0] + else: + # all three are extensions + L1 = fields[0].composite_fields(fields[1])[0] + L = L1.composite_fields(fields[2])[0] + else: + raise NotImplementedError("nontrivial characters not implemented for characteristic > 0") + poly = poly.change_ring(L) + poly_gens = vector(poly.parent().gens()) + F = L.zero() + for g in self: + F += L(chi(g)) * poly(*g.matrix().change_ring(L)*poly_gens) + F /= self.order() + try: # attempt to move F to base_ring of polynomial + F = F.change_ring(R) + except (TypeError, ValueError): + pass + return F + + def invariants_of_degree(self, deg, chi=None, R=None): + r""" + Return the (relative) invariants of given degree for this group. + + For this group, compute the invariants of degree ``deg`` + with respect to the group character ``chi``. The method + is to project each possible monomial of degree ``deg`` via + the Reynolds operator. Note that if the polynomial ring ``R`` + is specified it's base ring may be extended if the resulting + invariant is defined over a bigger field. + + INPUT: + + - ``degree`` -- a positive integer + + - ``chi`` -- (default: trivial character) a linear group character of this group + + - ``R`` -- (optional) a polynomial ring + + OUTPUT: list of polynomials + + EXAMPLES:: + + sage: # needs sage.groups sage.rings.number_field + sage: Gr = MatrixGroup(SymmetricGroup(2)) + sage: sorted(Gr.invariants_of_degree(3)) + [x0^2*x1 + x0*x1^2, x0^3 + x1^3] + sage: R.<x,y> = QQ[] + sage: sorted(Gr.invariants_of_degree(4, R=R)) + [x^2*y^2, x^3*y + x*y^3, x^4 + y^4] + + :: + + sage: # needs sage.groups sage.rings.number_field + sage: R.<x,y,z> = QQ[] + sage: Gr = MatrixGroup(DihedralGroup(3)) + sage: ct = Gr.character_table() + sage: chi = Gr.character(ct[0]) + sage: all(f(*(g.matrix()*vector(R.gens()))) == chi(g)*f + ....: for f in Gr.invariants_of_degree(3, R=R, chi=chi) for g in Gr) + True + + :: + + sage: i = GF(7)(3) + sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) + sage: G.invariants_of_degree(25) # needs sage.rings.number_field + [] + + :: + + sage: # needs sage.groups + sage: G = MatrixGroup(SymmetricGroup(5)) + sage: R = QQ['x,y'] + sage: G.invariants_of_degree(3, R=R) + Traceback (most recent call last): + ... + TypeError: number of variables in polynomial ring must match size of matrices + + :: + + sage: # needs sage.groups sage.rings.number_field + sage: K.<i> = CyclotomicField(4) + sage: G = MatrixGroup(CyclicPermutationGroup(3)) + sage: chi = G.character(G.character_table()[1]) + sage: R.<x,y,z> = K[] + sage: sorted(G.invariants_of_degree(2, R=R, chi=chi)) + [x*y + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*x*z + + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y*z, + x^2 + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y^2 + + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*z^2] + + :: + + sage: # needs sage.groups sage.rings.number_field + sage: S3 = MatrixGroup(SymmetricGroup(3)) + sage: chi = S3.character(S3.character_table()[0]) + sage: sorted(S3.invariants_of_degree(5, chi=chi)) + [x0^3*x1^2 - x0^2*x1^3 - x0^3*x2^2 + x1^3*x2^2 + x0^2*x2^3 - x1^2*x2^3, + x0^4*x1 - x0*x1^4 - x0^4*x2 + x1^4*x2 + x0*x2^4 - x1*x2^4] + """ + D = self.degree() + deg = int(deg) + if deg <= 0: + raise ValueError("degree must be a positive integer") + if R is None: + R = PolynomialRing(self.base_ring(), 'x', D) + elif R.ngens() != D: + raise TypeError("number of variables in polynomial ring must match size of matrices") + + ms = self.molien_series(prec=deg+1,chi=chi) + if ms[deg].is_zero(): + return [] + inv = set() + for e in IntegerVectors(deg, D): + F = self.reynolds_operator(R.monomial(*e), chi=chi) + if not F.is_zero() and _new_invariant_is_linearly_independent((F:=F/F.lc()), inv): + inv.add(F) + if len(inv) == ms[deg]: + break + return list(inv) + +def _new_invariant_is_linearly_independent(F, invariants): + """ + EXAMPLES:: + + sage: gens = [matrix(QQ, [[-1,1],[-1,0]]), matrix(QQ, [[0,1],[1,0]])] + sage: G = MatrixGroup(gens) + sage: s = Sequence(G.invariants_of_degree(14)) # needs sage.rings.number_field + sage: s.coefficient_matrix()[0].rank() # needs sage.rings.number_field + 3 + sage: len(s) # needs sage.rings.number_field + 3 + """ + if len(invariants)==0: + return True + return PolynomialSequence(invariants).coefficient_matrix()[0].rank() != PolynomialSequence(list(invariants)+[F]).coefficient_matrix()[0].rank() diff --git a/src/sage/groups/matrix_gps/group_element.pxd b/src/sage/groups/matrix_gps/group_element.pxd index df5f99aeca9..36a5a9fc4ce 100644 --- a/src/sage/groups/matrix_gps/group_element.pxd +++ b/src/sage/groups/matrix_gps/group_element.pxd @@ -1,5 +1,4 @@ from sage.structure.element cimport MultiplicativeGroupElement, Element, MonoidElement, Matrix -from sage.groups.libgap_wrapper cimport ElementLibGAP cpdef is_MatrixGroupElement(x) @@ -9,8 +8,3 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): cpdef _act_on_(self, x, bint self_on_left) cpdef _mul_(self, other) cpdef list list(self) - -cdef class MatrixGroupElement_gap(ElementLibGAP): - cpdef _act_on_(self, x, bint self_on_left) - cpdef list list(self) - diff --git a/src/sage/groups/matrix_gps/group_element.pyx b/src/sage/groups/matrix_gps/group_element.pyx index 777b141beb0..2764e33a7a8 100644 --- a/src/sage/groups/matrix_gps/group_element.pyx +++ b/src/sage/groups/matrix_gps/group_element.pyx @@ -3,15 +3,14 @@ Matrix Group Elements EXAMPLES:: - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: F = GF(3); MS = MatrixSpace(F, 2, 2) + sage: gens = [MS([[1,0], [0,1]]), MS([[1,1], [0,1]])] sage: G = MatrixGroup(gens); G Matrix group over Finite Field of size 3 with 2 generators ( [1 0] [1 1] - [0 1], [0 1] - ) - sage: g = G([[1,1],[0,1]]) - sage: h = G([[1,2],[0,1]]) + [0 1], [0 1] ) + sage: g = G([[1,1], [0,1]]) + sage: h = G([[1,2], [0,1]]) sage: g*h [1 0] [0 1] @@ -43,10 +42,10 @@ do it with the underlying matrices:: sage: 2*g Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Integer Ring' and 'Matrix group over Finite Field of size 3 with 2 generators ( + TypeError: unsupported operand parent(s) for *: 'Integer Ring' + and 'Matrix group over Finite Field of size 3 with 2 generators ( [1 0] [1 1] - [0 1], [0 1] - )' + [0 1], [0 1] )' AUTHORS: @@ -64,27 +63,30 @@ AUTHORS: """ #***************************************************************************** -# Copyright (C) 2006 David Joyner and William Stein <wstein@gmail.com> -# Copyright (C) 2013 Volker Braun <vbraun.name@gmail.com> -# Copyright (C) 2016 Travis Scrimshaw <tscrimsh at umn.edu> +# Copyright (C) 2006 David Joyner and William Stein <wstein@gmail.com> +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2016 Travis Scrimshaw <tscrimsh at umn.edu> +# 2016-2018 Jeroen Demeyer +# 2023 Matthias Koeppe # # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.element cimport MultiplicativeGroupElement, Element, MonoidElement, Matrix +from sage.rings.integer_ring import ZZ +from sage.structure.element cimport MultiplicativeGroupElement, Matrix +from sage.structure.element import is_Matrix from sage.structure.parent cimport Parent from sage.structure.richcmp cimport richcmp -from sage.libs.gap.element cimport GapElement, GapElement_List -from sage.groups.libgap_wrapper cimport ElementLibGAP -from sage.structure.element import is_Matrix -from sage.structure.factorization import Factorization -from sage.misc.cachefunc import cached_method -from sage.rings.integer_ring import ZZ + +try: + from .group_element_gap import MatrixGroupElement_gap +except ImportError: + MatrixGroupElement_gap = () cpdef is_MatrixGroupElement(x): @@ -95,9 +97,7 @@ cpdef is_MatrixGroupElement(x): - ``x`` -- anything. - OUTPUT: - - Boolean. + OUTPUT: Boolean. EXAMPLES:: @@ -130,16 +130,15 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): - ``parent`` -- the parent - ``check`` -- bool (default: ``True``); if ``True``, then - does some type checking + do some type checking - ``convert`` -- bool (default: ``True``); if ``True``, then convert ``M`` to the right matrix space EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: g + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # needs sage.graphs + sage: g = W.an_element(); g # needs sage.graphs [ 0 0 -1] [ 1 0 -1] [ 0 1 -1] @@ -150,9 +149,9 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): TESTS:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: TestSuite(g).run() + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # needs sage.graphs + sage: g = W.an_element() # needs sage.graphs + sage: TestSuite(g).run() # needs sage.graphs """ if convert: M = parent.matrix_space()(M) @@ -173,9 +172,9 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): r""" TESTS:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: hash(g) + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # needs sage.graphs + sage: g = W.an_element() # needs sage.graphs + sage: hash(g) # needs sage.graphs 660522311176098153 # 64-bit -606138007 # 32-bit """ @@ -187,9 +186,9 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): TESTS:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: loads(g.dumps()) == g + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # needs sage.graphs + sage: g = W.an_element() # needs sage.graphs + sage: loads(g.dumps()) == g # needs sage.graphs True """ return (_unpickle_generic_element, (self.parent(), self._matrix,)) @@ -200,8 +199,8 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: W.an_element() + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # needs sage.graphs + sage: W.an_element() # needs sage.graphs [ 0 0 -1] [ 1 0 -1] [ 0 1 -1] @@ -212,9 +211,9 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): r""" EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: latex(g) + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # needs sage.graphs + sage: g = W.an_element() # needs sage.graphs + sage: latex(g) # needs sage.graphs \left(\begin{array}{rrr} 0 & 0 & -1 \\ 1 & 0 & -1 \\ @@ -227,6 +226,7 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): """ EXAMPLES:: + sage: # needs sage.combinat sage.libs.gap sage: W = CoxeterGroup(['A',4], base_ring=ZZ) sage: g = W.gen(0) sage: g * vector([1,1,1,1]) @@ -249,6 +249,7 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): """ EXAMPLES:: + sage: # needs sage.combinat sage.libs.gap sage: W = CoxeterGroup(['A',3], base_ring=ZZ) sage: g = W.an_element() sage: TestSuite(g).run() @@ -271,6 +272,7 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: + sage: # needs sage.combinat sage.libs.gap sage: W = CoxeterGroup(['A',3], base_ring=ZZ) sage: g = W.gen(0) sage: g @@ -292,6 +294,7 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: + sage: # needs sage.combinat sage.libs.gap sage: W = CoxeterGroup(['A',3], base_ring=ZZ) sage: g = W.gen(0) sage: g.matrix() @@ -304,7 +307,7 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): Matrices have extra functionality that matrix group elements do not have:: - sage: g.matrix().charpoly('t') + sage: g.matrix().charpoly('t') # needs sage.combinat sage.libs.gap t^3 - t^2 - t + 1 """ return self._matrix @@ -315,9 +318,9 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: - sage: W = CoxeterGroup(['A', 3], base_ring=ZZ) - sage: g = W.gen(0) - sage: matrix(RDF, g) + sage: W = CoxeterGroup(['A', 3], base_ring=ZZ) # needs sage.graphs + sage: g = W.gen(0) # needs sage.graphs + sage: matrix(RDF, g) # needs sage.graphs [-1.0 1.0 0.0] [ 0.0 1.0 0.0] [ 0.0 0.0 1.0] @@ -331,6 +334,7 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: + sage: # needs sage.combinat sage.libs.gap sage: W = CoxeterGroup(['A',3], base_ring=ZZ) sage: g = W.gen(0) sage: h = W.an_element() @@ -352,11 +356,11 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: + sage: # needs sage.graphs sage: W = CoxeterGroup(['A',3]) sage: g = W.gen(0) sage: g.is_one() False - sage: W.an_element().is_one() False sage: W.one().is_one() @@ -368,12 +372,11 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): """ Return the inverse group element - OUTPUT: - - A matrix group element. + OUTPUT: A matrix group element. EXAMPLES:: + sage: # needs sage.combinat sage.libs.gap sage: W = CoxeterGroup(['A',3], base_ring=ZZ) sage: g = W.an_element() sage: ~g @@ -385,6 +388,7 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): sage: ~g * g == W.one() True + sage: # needs sage.combinat sage.libs.gap sage.rings.number_field sage: W = CoxeterGroup(['B',3]) sage: W.base_ring() Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? @@ -409,404 +413,6 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): inverse = __invert__ -################################################################### -# -# Matrix group elements implemented in GAP -# -################################################################### - -cdef class MatrixGroupElement_gap(ElementLibGAP): - """ - Element of a matrix group over a generic ring. - - The group elements are implemented as wrappers around libGAP matrices. - - INPUT: - - - ``M`` -- a matrix - - - ``parent`` -- the parent - - - ``check`` -- bool (default: ``True``); if ``True`` does some - type checking - - - ``convert`` -- bool (default: ``True``); if ``True`` convert - ``M`` to the right matrix space - """ - def __init__(self, parent, M, check=True, convert=True): - r""" - Initialize ``self``. - - TESTS:: - - sage: MS = MatrixSpace(GF(3),2,2) - sage: G = MatrixGroup(MS([[1,0],[0,1]]), MS([[1,1],[0,1]])) - sage: G.gen(0) - [1 0] - [0 1] - sage: g = G.random_element() - sage: TestSuite(g).run() - """ - if isinstance(M, GapElement): - ElementLibGAP.__init__(self, parent, M) - return - if convert: - M = parent.matrix_space()(M) - from sage.libs.gap.libgap import libgap - M_gap = libgap(M) - if check: - if not is_Matrix(M): - raise TypeError('M must be a matrix') - if M.parent() is not parent.matrix_space(): - raise TypeError('M must be a in the matrix space of the group') - parent._check_matrix(M, M_gap) - ElementLibGAP.__init__(self, parent, M_gap) - - def __reduce__(self): - """ - Implement pickling. - - TESTS:: - - sage: MS = MatrixSpace(GF(3), 2, 2) - sage: G = MatrixGroup(MS([[1,0],[0,1]]), MS([[1,1],[0,1]])) - sage: loads(G.gen(0).dumps()) - [1 0] - [0 1] - """ - return (self.parent(), (self.matrix(),)) - - def __hash__(self): - r""" - TESTS:: - - sage: MS = MatrixSpace(GF(3), 2) - sage: G = MatrixGroup([MS([1,1,0,1]), MS([1,0,1,1])]) - sage: g = G.an_element() - sage: hash(g) - -5306160029685893860 # 64-bit - -181258980 # 32-bit - """ - return hash(self.matrix()) - - def _repr_(self): - r""" - Return string representation of this matrix. - - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] - sage: G = MatrixGroup(gens) - sage: g = G([[1, 1], [0, 1]]) - sage: g # indirect doctest - [1 1] - [0 1] - sage: g._repr_() - '[1 1]\n[0 1]' - """ - return str(self.matrix()) - - def _latex_(self): - r""" - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] - sage: G = MatrixGroup(gens) - sage: g = G([[1, 1], [0, 1]]) - sage: print(g._latex_()) - \left(\begin{array}{rr} - 1 & 1 \\ - 0 & 1 - \end{array}\right) - - Type ``view(g._latex_())`` to see the object in an - xdvi window (assuming you have latex and xdvi installed). - """ - return self.matrix()._latex_() - - cpdef _act_on_(self, x, bint self_on_left): - """ - EXAMPLES:: - - sage: G = GL(4,7) - sage: G.0 * vector([1,2,3,4]) - (3, 2, 3, 4) - sage: v = vector(GF(7), [3,2,1,-1]) - sage: g = G.1 - sage: v * g == v * g.matrix() # indirect doctest - True - """ - if not is_MatrixGroupElement(x) and x not in self.parent().base_ring(): - try: - if self_on_left: - return self.matrix() * x - else: - return x * self.matrix() - except TypeError: - return None - - cpdef _richcmp_(self, other, int op): - """ - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2) - sage: gens = [MS([1,0, 0,1]), MS([1,1, 0,1])] - sage: G = MatrixGroup(gens) - sage: g = G([1,1, 0,1]) - sage: h = G([1,1, 0,1]) - sage: g == h - True - sage: g == G.one() - False - """ - return richcmp(self.matrix(), other.matrix(), op) - - @cached_method - def matrix(self): - """ - Obtain the usual matrix (as an element of a matrix space) - associated to this matrix group element. - - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] - sage: G = MatrixGroup(gens) - sage: m = G.gen(0).matrix(); m - [1 0] - [0 1] - sage: m.parent() - Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 3 - - sage: k = GF(7); G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]) - sage: g = G.0 - sage: g.matrix() - [1 1] - [0 1] - sage: parent(g.matrix()) - Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 - - Matrices have extra functionality that matrix group elements - do not have:: - - sage: g.matrix().charpoly('t') - t^2 + 5*t + 1 - """ - # We do a slightly specialized version of sage.libs.gap.element.GapElement.matrix() - # in order to use our current matrix space directly and avoid - # some overhead safety checks. - entries = self.gap().Flat() - MS = self.parent().matrix_space() - ring = MS.base_ring() - m = MS([x.sage(ring=ring) for x in entries]) - m.set_immutable() - return m - - def _matrix_(self, base=None): - """ - Method used by the :func:`matrix` constructor. - - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: G = MatrixGroup([MS([1,1,0,1])]) - sage: g = G.gen(0) - sage: M = matrix(GF(9), g); M; parent(M) - [1 1] - [0 1] - Full MatrixSpace of 2 by 2 dense matrices over Finite Field in z2 of size 3^2 - """ - return self.matrix() - - cpdef list list(self): - """ - Return list representation of this matrix. - - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] - sage: G = MatrixGroup(gens) - sage: g = G.0 - sage: g - [1 0] - [0 1] - sage: g.list() - [[1, 0], [0, 1]] - """ - return [r.list() for r in self.matrix().rows()] - - @cached_method - def multiplicative_order(self): - """ - Return the order of this group element, which is the smallest - positive integer `n` such that `g^n = 1`, or - +Infinity if no such integer exists. - - EXAMPLES:: - - sage: k = GF(7) - sage: G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]); G - Matrix group over Finite Field of size 7 with 2 generators ( - [1 1] [1 0] - [0 1], [0 2] - ) - sage: G.order() - 21 - sage: G.gen(0).multiplicative_order(), G.gen(1).multiplicative_order() - (7, 3) - - ``order`` is just an alias for ``multiplicative_order``:: - - sage: G.gen(0).order(), G.gen(1).order() - (7, 3) - - sage: k = QQ - sage: G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]); G - Matrix group over Rational Field with 2 generators ( - [1 1] [1 0] - [0 1], [0 2] - ) - sage: G.order() - +Infinity - sage: G.gen(0).order(), G.gen(1).order() - (+Infinity, +Infinity) - - sage: gl = GL(2, ZZ); gl - General Linear Group of degree 2 over Integer Ring - sage: g = gl.gen(2); g - [1 1] - [0 1] - sage: g.order() - +Infinity - """ - order = self.gap().Order() - if order.IsInt(): - return order.sage() - else: - assert order.IsInfinity() - from sage.rings.all import Infinity - return Infinity - - def word_problem(self, gens=None): - r""" - Solve the word problem. - - This method writes the group element as a product of the - elements of the list ``gens``, or the standard generators of - the parent of self if ``gens`` is None. - - INPUT: - - - ``gens`` -- a list/tuple/iterable of elements (or objects - that can be converted to group elements), or ``None`` - (default). By default, the generators of the parent group - are used. - - OUTPUT: - - A factorization object that contains information about the - order of factors and the exponents. A ``ValueError`` is raised - if the group element cannot be written as a word in ``gens``. - - ALGORITHM: - - Use GAP, which has optimized algorithms for solving the word - problem (the GAP functions ``EpimorphismFromFreeGroup`` and - ``PreImagesRepresentative``). - - EXAMPLES:: - - sage: G = GL(2,5); G - General Linear Group of degree 2 over Finite Field of size 5 - sage: G.gens() - ( - [2 0] [4 1] - [0 1], [4 0] - ) - sage: G(1).word_problem([G.gen(0)]) - 1 - sage: type(_) - <class 'sage.structure.factorization.Factorization'> - - sage: g = G([0,4,1,4]) - sage: g.word_problem() - ([4 1] - [4 0])^-1 - - Next we construct a more complicated element of the group from the - generators:: - - sage: s,t = G.0, G.1 - sage: a = (s * t * s); b = a.word_problem(); b - ([2 0] - [0 1]) * - ([4 1] - [4 0]) * - ([2 0] - [0 1]) - sage: flatten(b) - [ - [2 0] [4 1] [2 0] - [0 1], 1, [4 0], 1, [0 1], 1 - ] - sage: b.prod() == a - True - - We solve the word problem using some different generators:: - - sage: s = G([2,0,0,1]); t = G([1,1,0,1]); u = G([0,-1,1,0]) - sage: a.word_problem([s,t,u]) - ([2 0] - [0 1])^-1 * - ([1 1] - [0 1])^-1 * - ([0 4] - [1 0]) * - ([2 0] - [0 1])^-1 - - We try some elements that don't actually generate the group:: - - sage: a.word_problem([t,u]) - Traceback (most recent call last): - ... - ValueError: word problem has no solution - - AUTHORS: - - - David Joyner and William Stein - - David Loeffler (2010): fixed some bugs - - Volker Braun (2013): LibGAP - """ - from sage.libs.gap.libgap import libgap - G = self.parent() - if gens: - gen = lambda i:gens[i] - H = libgap.Group([G(x).gap() for x in gens]) - else: - gen = G.gen - H = G.gap() - hom = H.EpimorphismFromFreeGroup() - preimg = hom.PreImagesRepresentative(self.gap()) - - if preimg.is_bool(): - assert preimg == libgap.eval('fail') - raise ValueError('word problem has no solution') - - result = [] - n = preimg.NumberSyllables().sage() - exponent_syllable = libgap.eval('ExponentSyllable') - generator_syllable = libgap.eval('GeneratorSyllable') - for i in range(n): - exponent = exponent_syllable(preimg, i+1).sage() - generator = gen(generator_syllable(preimg, i+1).sage() - 1) - result.append( (generator, exponent) ) - result = Factorization(result) - result._set_cr(True) - return result def _unpickle_generic_element(G, mat): """ @@ -814,8 +420,9 @@ def _unpickle_generic_element(G, mat): EXAMPLES:: - sage: m1 = matrix(SR, [[1,2],[3,4]]) - sage: m2 = matrix(SR, [[1,3],[-1,0]]) + sage: # needs sage.symbolic + sage: m1 = matrix(SR, [[1,2], [3,4]]) + sage: m2 = matrix(SR, [[1,3], [-1,0]]) sage: G = MatrixGroup(m1, m2) sage: m = G.an_element() sage: from sage.groups.matrix_gps.group_element import _unpickle_generic_element diff --git a/src/sage/groups/matrix_gps/group_element_gap.pxd b/src/sage/groups/matrix_gps/group_element_gap.pxd new file mode 100644 index 00000000000..e0ecbefea5c --- /dev/null +++ b/src/sage/groups/matrix_gps/group_element_gap.pxd @@ -0,0 +1,5 @@ +from sage.groups.libgap_wrapper cimport ElementLibGAP + +cdef class MatrixGroupElement_gap(ElementLibGAP): + cpdef _act_on_(self, x, bint self_on_left) + cpdef list list(self) diff --git a/src/sage/groups/matrix_gps/group_element_gap.pyx b/src/sage/groups/matrix_gps/group_element_gap.pyx new file mode 100644 index 00000000000..b07c0f01a44 --- /dev/null +++ b/src/sage/groups/matrix_gps/group_element_gap.pyx @@ -0,0 +1,419 @@ +r""" +Matrix group elements implemented in GAP +""" + +#***************************************************************************** +# Copyright (C) 2006 David Joyner and William Stein <wstein@gmail.com> +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2015-2017 Vincent Delecroix +# 2016 Travis Scrimshaw <tscrimsh at umn.edu> +# 2018 Jeroen Demeyer +# 2023 Matthias Koeppe +# +# 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. +# https://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.groups.matrix_gps.group_element cimport is_MatrixGroupElement +from sage.libs.gap.element cimport GapElement +from sage.misc.cachefunc import cached_method +from sage.structure.element import is_Matrix +from sage.structure.factorization import Factorization +from sage.structure.richcmp cimport richcmp + + +cdef class MatrixGroupElement_gap(ElementLibGAP): + """ + Element of a matrix group over a generic ring. + + The group elements are implemented as wrappers around libGAP matrices. + + INPUT: + + - ``M`` -- a matrix + + - ``parent`` -- the parent + + - ``check`` -- bool (default: ``True``); if ``True``, do some + type checking + + - ``convert`` -- bool (default: ``True``); if ``True``, convert + ``M`` to the right matrix space + """ + def __init__(self, parent, M, check=True, convert=True): + r""" + Initialize ``self``. + + TESTS:: + + sage: MS = MatrixSpace(GF(3),2,2) + sage: G = MatrixGroup(MS([[1,0],[0,1]]), MS([[1,1],[0,1]])) + sage: G.gen(0) + [1 0] + [0 1] + sage: g = G.random_element() + sage: TestSuite(g).run() + """ + if isinstance(M, GapElement): + ElementLibGAP.__init__(self, parent, M) + return + if convert: + M = parent.matrix_space()(M) + from sage.libs.gap.libgap import libgap + M_gap = libgap(M) + if check: + if not is_Matrix(M): + raise TypeError('M must be a matrix') + if M.parent() is not parent.matrix_space(): + raise TypeError('M must be a in the matrix space of the group') + parent._check_matrix(M, M_gap) + ElementLibGAP.__init__(self, parent, M_gap) + + def __reduce__(self): + """ + Implement pickling. + + TESTS:: + + sage: MS = MatrixSpace(GF(3), 2, 2) + sage: G = MatrixGroup(MS([[1,0],[0,1]]), MS([[1,1],[0,1]])) + sage: loads(G.gen(0).dumps()) + [1 0] + [0 1] + """ + return (self.parent(), (self.matrix(),)) + + def __hash__(self): + r""" + TESTS:: + + sage: MS = MatrixSpace(GF(3), 2) + sage: G = MatrixGroup([MS([1,1,0,1]), MS([1,0,1,1])]) + sage: g = G.an_element() + sage: hash(g) + -5306160029685893860 # 64-bit + -181258980 # 32-bit + """ + return hash(self.matrix()) + + def _repr_(self): + r""" + Return string representation of this matrix. + + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: G = MatrixGroup(gens) + sage: g = G([[1, 1], [0, 1]]) + sage: g # indirect doctest + [1 1] + [0 1] + sage: g._repr_() + '[1 1]\n[0 1]' + """ + return str(self.matrix()) + + def _latex_(self): + r""" + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: G = MatrixGroup(gens) + sage: g = G([[1, 1], [0, 1]]) + sage: print(g._latex_()) + \left(\begin{array}{rr} + 1 & 1 \\ + 0 & 1 + \end{array}\right) + + Type ``view(g._latex_())`` to see the object in an + xdvi window (assuming you have latex and xdvi installed). + """ + return self.matrix()._latex_() + + cpdef _act_on_(self, x, bint self_on_left): + """ + EXAMPLES:: + + sage: G = GL(4,7) + sage: G.0 * vector([1,2,3,4]) + (3, 2, 3, 4) + sage: v = vector(GF(7), [3,2,1,-1]) + sage: g = G.1 + sage: v * g == v * g.matrix() # indirect doctest + True + """ + if not is_MatrixGroupElement(x) and x not in self.parent().base_ring(): + try: + if self_on_left: + return self.matrix() * x + else: + return x * self.matrix() + except TypeError: + return None + + cpdef _richcmp_(self, other, int op): + """ + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2) + sage: gens = [MS([1,0, 0,1]), MS([1,1, 0,1])] + sage: G = MatrixGroup(gens) + sage: g = G([1,1, 0,1]) + sage: h = G([1,1, 0,1]) + sage: g == h + True + sage: g == G.one() + False + """ + return richcmp(self.matrix(), other.matrix(), op) + + @cached_method + def matrix(self): + """ + Obtain the usual matrix (as an element of a matrix space) + associated to this matrix group element. + + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: G = MatrixGroup(gens) + sage: m = G.gen(0).matrix(); m + [1 0] + [0 1] + sage: m.parent() + Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 3 + + sage: k = GF(7); G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]) + sage: g = G.0 + sage: g.matrix() + [1 1] + [0 1] + sage: parent(g.matrix()) + Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 + + Matrices have extra functionality that matrix group elements + do not have:: + + sage: g.matrix().charpoly('t') + t^2 + 5*t + 1 + """ + # We do a slightly specialized version of sage.libs.gap.element.GapElement.matrix() + # in order to use our current matrix space directly and avoid + # some overhead safety checks. + entries = self.gap().Flat() + MS = self.parent().matrix_space() + ring = MS.base_ring() + m = MS([x.sage(ring=ring) for x in entries]) + m.set_immutable() + return m + + def _matrix_(self, base=None): + """ + Method used by the :func:`matrix` constructor. + + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2,2) + sage: G = MatrixGroup([MS([1,1,0,1])]) + sage: g = G.gen(0) + sage: M = matrix(GF(9), g); M; parent(M) # needs sage.rings.finite_rings + [1 1] + [0 1] + Full MatrixSpace of 2 by 2 dense matrices over Finite Field in z2 of size 3^2 + """ + return self.matrix() + + cpdef list list(self): + """ + Return list representation of this matrix. + + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: G = MatrixGroup(gens) + sage: g = G.0 + sage: g + [1 0] + [0 1] + sage: g.list() + [[1, 0], [0, 1]] + """ + return [r.list() for r in self.matrix().rows()] + + @cached_method + def multiplicative_order(self): + """ + Return the order of this group element, which is the smallest + positive integer `n` such that `g^n = 1`, or + +Infinity if no such integer exists. + + EXAMPLES:: + + sage: k = GF(7) + sage: G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]); G + Matrix group over Finite Field of size 7 with 2 generators ( + [1 1] [1 0] + [0 1], [0 2] + ) + sage: G.order() + 21 + sage: G.gen(0).multiplicative_order(), G.gen(1).multiplicative_order() + (7, 3) + + ``order`` is just an alias for ``multiplicative_order``:: + + sage: G.gen(0).order(), G.gen(1).order() + (7, 3) + + sage: k = QQ + sage: G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]); G + Matrix group over Rational Field with 2 generators ( + [1 1] [1 0] + [0 1], [0 2] + ) + sage: G.order() + +Infinity + sage: G.gen(0).order(), G.gen(1).order() + (+Infinity, +Infinity) + + sage: gl = GL(2, ZZ); gl + General Linear Group of degree 2 over Integer Ring + sage: g = gl.gen(2); g + [1 1] + [0 1] + sage: g.order() + +Infinity + """ + order = self.gap().Order() + if order.IsInt(): + return order.sage() + else: + assert order.IsInfinity() + from sage.rings.infinity import Infinity + return Infinity + + def word_problem(self, gens=None): + r""" + Solve the word problem. + + This method writes the group element as a product of the + elements of the list ``gens``, or the standard generators of + the parent of self if ``gens`` is None. + + INPUT: + + - ``gens`` -- a list/tuple/iterable of elements (or objects + that can be converted to group elements), or ``None`` + (default). By default, the generators of the parent group + are used. + + OUTPUT: + + A factorization object that contains information about the + order of factors and the exponents. A :class:`ValueError` is raised + if the group element cannot be written as a word in ``gens``. + + ALGORITHM: + + Use GAP, which has optimized algorithms for solving the word + problem (the GAP functions ``EpimorphismFromFreeGroup`` and + ``PreImagesRepresentative``). + + EXAMPLES:: + + sage: G = GL(2,5); G + General Linear Group of degree 2 over Finite Field of size 5 + sage: G.gens() + ( + [2 0] [4 1] + [0 1], [4 0] + ) + sage: G(1).word_problem([G.gen(0)]) + 1 + sage: type(_) + <class 'sage.structure.factorization.Factorization'> + + sage: g = G([0,4,1,4]) + sage: g.word_problem() + ([4 1] + [4 0])^-1 + + Next we construct a more complicated element of the group from the + generators:: + + sage: s,t = G.0, G.1 + sage: a = (s * t * s); b = a.word_problem(); b + ([2 0] + [0 1]) * + ([4 1] + [4 0]) * + ([2 0] + [0 1]) + sage: flatten(b) + [ + [2 0] [4 1] [2 0] + [0 1], 1, [4 0], 1, [0 1], 1 + ] + sage: b.prod() == a + True + + We solve the word problem using some different generators:: + + sage: s = G([2,0,0,1]); t = G([1,1,0,1]); u = G([0,-1,1,0]) + sage: a.word_problem([s,t,u]) + ([2 0] + [0 1])^-1 * + ([1 1] + [0 1])^-1 * + ([0 4] + [1 0]) * + ([2 0] + [0 1])^-1 + + We try some elements that don't actually generate the group:: + + sage: a.word_problem([t,u]) + Traceback (most recent call last): + ... + ValueError: word problem has no solution + + AUTHORS: + + - David Joyner and William Stein + - David Loeffler (2010): fixed some bugs + - Volker Braun (2013): LibGAP + """ + from sage.libs.gap.libgap import libgap + G = self.parent() + if gens: + gen = lambda i:gens[i] + H = libgap.Group([G(x).gap() for x in gens]) + else: + gen = G.gen + H = G.gap() + hom = H.EpimorphismFromFreeGroup() + preimg = hom.PreImagesRepresentative(self.gap()) + + if preimg.is_bool(): + assert preimg == libgap.eval('fail') + raise ValueError('word problem has no solution') + + result = [] + n = preimg.NumberSyllables().sage() + exponent_syllable = libgap.eval('ExponentSyllable') + generator_syllable = libgap.eval('GeneratorSyllable') + for i in range(n): + exponent = exponent_syllable(preimg, i+1).sage() + generator = gen(generator_syllable(preimg, i+1).sage() - 1) + result.append( (generator, exponent) ) + result = Factorization(result) + result._set_cr(True) + return result diff --git a/src/sage/groups/matrix_gps/heisenberg.py b/src/sage/groups/matrix_gps/heisenberg.py index 68832525331..8a262ddf1c7 100644 --- a/src/sage/groups/matrix_gps/heisenberg.py +++ b/src/sage/groups/matrix_gps/heisenberg.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.gap sage.modules """ Heisenberg Group @@ -16,7 +17,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.structure.unique_representation import UniqueRepresentation from sage.misc.latex import latex from sage.matrix.matrix_space import MatrixSpace @@ -223,3 +224,33 @@ def order(self): return ZZ(self._ring.cardinality() ** (2*self._n + 1)) cardinality = order + + def center(self): + """ + Return the center of ``self``. + + This is the subgroup generated by the `z`, the matrix with a `1` + in the upper right corner and along the diagonal. + + EXAMPLES:: + + sage: H = groups.matrix.Heisenberg(2) + sage: H.center() + Subgroup with 1 generators ( + [1 0 0 1] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + ) of Heisenberg group of degree 2 over Integer Ring + + sage: H = groups.matrix.Heisenberg(3, 4) + sage: H.center() + Subgroup with 1 generators ( + [1 0 0 0 1] + [0 1 0 0 0] + [0 0 1 0 0] + [0 0 0 1 0] + [0 0 0 0 1] + ) of Heisenberg group of degree 3 over Ring of integers modulo 4 + """ + return self.subgroup([self.gens()[-1]]) diff --git a/src/sage/groups/matrix_gps/isometries.py b/src/sage/groups/matrix_gps/isometries.py index cca45e71752..cbc88ccb184 100644 --- a/src/sage/groups/matrix_gps/isometries.py +++ b/src/sage/groups/matrix_gps/isometries.py @@ -1,5 +1,5 @@ r""" -Groups of isometries. +Groups of isometries Let `M = \ZZ^n` or `\QQ^n`, `b: M \times M \rightarrow \QQ` a bilinear form and `f: M \rightarrow M` a linear map. We say that `f` is an isometry if for all @@ -8,9 +8,8 @@ EXAMPLES:: - sage: L = IntegralLattice("D4") - sage: O = L.orthogonal_group() - sage: O + sage: L = IntegralLattice("D4") # needs sage.graphs + sage: O = L.orthogonal_group(); O # needs sage.graphs Group of isometries with 3 generators ( [0 0 0 1] [ 1 1 0 0] [ 1 0 0 0] [0 1 0 0] [ 0 0 1 0] [-1 -1 -1 -1] @@ -20,9 +19,9 @@ Basic functionality is provided by GAP:: - sage: O.cardinality() + sage: O.cardinality() # needs sage.graphs 1152 - sage: len(O.conjugacy_classes_representatives()) + sage: len(O.conjugacy_classes_representatives()) # needs sage.graphs 25 AUTHORS: @@ -39,7 +38,7 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.categories.action import Action @@ -68,9 +67,9 @@ class GroupOfIsometries(FinitelyGeneratedMatrixGroup_gap): EXAMPLES:: sage: from sage.groups.matrix_gps.isometries import GroupOfIsometries - sage: bil = Matrix(ZZ,2,[3,2,2,3]) - sage: gens = [-Matrix(ZZ,2,[0,1,1,0])] - sage: O = GroupOfIsometries(2,ZZ,gens,bil) + sage: bil = Matrix(ZZ, 2, [3,2,2,3]) + sage: gens = [-Matrix(ZZ, 2, [0,1,1,0])] + sage: O = GroupOfIsometries(2, ZZ, gens, bil) sage: O Group of isometries with 1 generator ( [ 0 -1] @@ -83,7 +82,7 @@ class GroupOfIsometries(FinitelyGeneratedMatrixGroup_gap): sage: bil = Matrix(ZZ,4,[0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0]) sage: f = Matrix(ZZ,4,[0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, 1, 1, 1]) - sage: O = GroupOfIsometries(2,ZZ,[f],bil) + sage: O = GroupOfIsometries(2, ZZ, [f], bil) sage: O.cardinality() +Infinity """ @@ -135,9 +134,7 @@ def _repr_(self): r""" Return the string representation of this matrix group. - OUTPUT: - - - a string + OUTPUT: a string EXAMPLES:: @@ -186,9 +183,7 @@ def invariant_bilinear_form(self): r""" Return the symmetric bilinear form preserved by the orthogonal group. - OUTPUT: - - - the matrix defining the bilinear form + OUTPUT: the matrix defining the bilinear form EXAMPLES:: @@ -278,9 +273,11 @@ class GroupActionOnSubmodule(Action): EXAMPLES:: sage: from sage.groups.matrix_gps.isometries import GroupOfIsometries - sage: S = span(ZZ,[[0,1]]) - sage: g = Matrix(QQ,2,[1,0,0,-1]) - sage: G = GroupOfIsometries(2, ZZ, [g], invariant_bilinear_form=matrix.identity(2), invariant_submodule=S) + sage: S = span(ZZ, [[0,1]]) + sage: g = Matrix(QQ, 2, [1,0,0,-1]) + sage: G = GroupOfIsometries(2, ZZ, [g], + ....: invariant_bilinear_form=matrix.identity(2), + ....: invariant_submodule=S) sage: g = G.an_element() sage: x = S.an_element() sage: x*g @@ -297,11 +294,11 @@ def __init__(self, MatrixGroup,submodule, is_left=False): TESTS:: sage: from sage.groups.matrix_gps.isometries import GroupOfIsometries, GroupActionOnSubmodule - sage: S = span(ZZ,[[0,1]]) - sage: g = Matrix(QQ,2,[1,0,0,-1]) + sage: S = span(ZZ, [[0,1]]) + sage: g = Matrix(QQ, 2, [1,0,0,-1]) sage: e = Matrix.identity(2) sage: G = GroupOfIsometries(2, ZZ, [g], e) - sage: GroupActionOnSubmodule(G,S) + sage: GroupActionOnSubmodule(G, S) Right action by Group of isometries with 1 generator ( [ 1 0] [ 0 -1] @@ -406,9 +403,7 @@ def _act_(self, g, a): - ``a`` -- an element of the invariant submodule - OUTPUT: - - - an element of the invariant quotient module + OUTPUT: an element of the invariant quotient module EXAMPLES:: diff --git a/src/sage/groups/matrix_gps/linear.py b/src/sage/groups/matrix_gps/linear.py index 4d100d01aec..d13904dec51 100644 --- a/src/sage/groups/matrix_gps/linear.py +++ b/src/sage/groups/matrix_gps/linear.py @@ -3,18 +3,18 @@ EXAMPLES:: - sage: GL(4,QQ) + sage: GL(4, QQ) General Linear Group of degree 4 over Rational Field - sage: GL(1,ZZ) + sage: GL(1, ZZ) General Linear Group of degree 1 over Integer Ring - sage: GL(100,RR) + sage: GL(100, RR) General Linear Group of degree 100 over Real Field with 53 bits of precision - sage: GL(3,GF(49,'a')) + sage: GL(3, GF(49,'a')) # needs sage.rings.finite_rings General Linear Group of degree 3 over Finite Field in a of size 7^2 sage: SL(2, ZZ) Special Linear Group of degree 2 over Integer Ring - sage: G = SL(2,GF(3)); G + sage: G = SL(2, GF(3)); G Special Linear Group of degree 2 over Finite Field of size 3 sage: G.is_finite() True @@ -23,7 +23,7 @@ [1 0] [0 2] [0 1] [2 0] [0 2] [0 1] [0 2] [0 1], [1 1], [2 1], [0 2], [1 2], [2 2], [1 0] ) - sage: G = SL(6,GF(5)) + sage: G = SL(6, GF(5)) sage: G.gens() ( [2 0 0 0 0 0] [4 0 0 0 0 1] @@ -59,12 +59,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.misc.latex import latex -from sage.groups.matrix_gps.named_group import ( - normalize_args_vectorspace, NamedMatrixGroup_generic, NamedMatrixGroup_gap ) from sage.categories.fields import Fields from sage.categories.groups import Groups -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.named_group import ( + normalize_args_vectorspace, NamedMatrixGroup_generic) +from sage.misc.latex import latex ############################################################################### @@ -94,7 +93,7 @@ def GL(n, R, var='a'): EXAMPLES:: - sage: G = GL(6,GF(5)) + sage: G = GL(6, GF(5)) sage: G.order() 11064475422000000000000000 sage: G.base_ring() @@ -111,17 +110,18 @@ def GL(n, R, var='a'): Here is the Cayley graph of (relatively small) finite General Linear Group:: sage: g = GL(2,3) - sage: d = g.cayley_graph(); d + sage: d = g.cayley_graph(); d # needs sage.graphs Digraph on 48 vertices - sage: d.plot(color_by_label=True, vertex_size=0.03, vertex_labels=False) # long time + sage: d.plot(color_by_label=True, vertex_size=0.03, # long time # needs sage.graphs sage.plot + ....: vertex_labels=False) Graphics object consisting of 144 graphics primitives - sage: d.plot3d(color_by_label=True) # long time + sage: d.plot3d(color_by_label=True) # long time # needs sage.graphs sage.plot Graphics3d Object :: - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[2,0],[0,1]]), MS([[2,1],[2,0]])] + sage: F = GF(3); MS = MatrixSpace(F, 2, 2) + sage: gens = [MS([[2,0], [0,1]]), MS([[2,1], [2,0]])] sage: G = MatrixGroup(gens) sage: G.order() 48 @@ -164,13 +164,19 @@ def GL(n, R, var='a'): name = 'General Linear Group of degree {0} over {1}'.format(degree, ring) ltx = 'GL({0}, {1})'.format(degree, latex(ring)) try: - cmd = 'GL({0}, {1})'.format(degree, ring._gap_init_()) - return LinearMatrixGroup_gap(degree, ring, False, name, ltx, cmd, - category=cat) - except ValueError: - return LinearMatrixGroup_generic(degree, ring, False, name, ltx, + from .linear_gap import LinearMatrixGroup_gap + except ImportError: + pass + else: + try: + cmd = 'GL({0}, {1})'.format(degree, ring._gap_init_()) + return LinearMatrixGroup_gap(degree, ring, False, name, ltx, cmd, category=cat) + except ValueError: + pass + return LinearMatrixGroup_generic(degree, ring, False, name, ltx, + category=cat) ############################################################################### @@ -189,7 +195,7 @@ def SL(n, R, var='a'): This group is also available via ``groups.matrix.SL()``. - INPUT: + INPUT: - ``n`` -- a positive integer. @@ -223,7 +229,7 @@ def SL(n, R, var='a'): Next we compute generators for `\mathrm{SL}_3(\ZZ)` :: - sage: G = SL(3,ZZ); G + sage: G = SL(3, ZZ); G Special Linear Group of degree 3 over Integer Ring sage: G.gens() ( @@ -249,13 +255,19 @@ def SL(n, R, var='a'): name = 'Special Linear Group of degree {0} over {1}'.format(degree, ring) ltx = 'SL({0}, {1})'.format(degree, latex(ring)) try: - cmd = 'SL({0}, {1})'.format(degree, ring._gap_init_()) - return LinearMatrixGroup_gap(degree, ring, True, name, ltx, cmd, - category=cat) - except ValueError: - return LinearMatrixGroup_generic(degree, ring, True, name, ltx, + from .linear_gap import LinearMatrixGroup_gap + except ImportError: + pass + else: + try: + cmd = 'SL({0}, {1})'.format(degree, ring._gap_init_()) + return LinearMatrixGroup_gap(degree, ring, True, name, ltx, cmd, category=cat) + except ValueError: + pass + return LinearMatrixGroup_generic(degree, ring, True, name, ltx, + category=cat) ######################################################################## @@ -265,7 +277,7 @@ def SL(n, R, var='a'): class LinearMatrixGroup_generic(NamedMatrixGroup_generic): def _check_matrix(self, x, *args): - """a + r""" Check whether the matrix ``x`` is special linear. See :meth:`~sage.groups.matrix_gps.matrix_group._check_matrix` @@ -273,7 +285,7 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = SL(2,GF(5)) + sage: G = SL(2, GF(5)) sage: G._check_matrix(G.an_element().matrix()) """ if self._special: @@ -282,19 +294,3 @@ def _check_matrix(self, x, *args): else: if x.determinant() == 0: raise TypeError('matrix must non-zero determinant') - - -class LinearMatrixGroup_gap(NamedMatrixGroup_gap, LinearMatrixGroup_generic, FinitelyGeneratedMatrixGroup_gap): - r""" - The general or special linear group in GAP. - - TESTS: - - Check that :trac:`20867` is fixed:: - - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap - sage: G = GL(3,3) - sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) - True - """ - pass diff --git a/src/sage/groups/matrix_gps/linear_gap.py b/src/sage/groups/matrix_gps/linear_gap.py new file mode 100644 index 00000000000..37d33d5d2be --- /dev/null +++ b/src/sage/groups/matrix_gps/linear_gap.py @@ -0,0 +1,23 @@ +""" +Linear Groups with GAP +""" + +from sage.groups.matrix_gps.linear import LinearMatrixGroup_generic +from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap + + +class LinearMatrixGroup_gap(NamedMatrixGroup_gap, LinearMatrixGroup_generic, FinitelyGeneratedMatrixGroup_gap): + r""" + The general or special linear group in GAP. + + TESTS: + + Check that :trac:`20867` is fixed:: + + sage: from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap + sage: G = GL(3,3) + sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) + True + """ + pass diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index 8cea6a6ef66..c0c22456320 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -1,6 +1,8 @@ """ Base classes for Matrix Groups +TESTS: + Loading, saving, ... works:: sage: G = GL(2,5); G @@ -41,6 +43,12 @@ # **************************************************************************** # Copyright (C) 2006 David Joyner and William Stein <wstein@gmail.com> +# 2009 Mike Hansen +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2017-2021 Frรฉdรฉric Chapoton +# 2018-2019 Sebastian Oehms +# 2020 Siddharth Singh +# 2023 Matthias Koeppe # # 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 @@ -58,11 +66,8 @@ richcmp_method, richcmp) from sage.misc.cachefunc import cached_method from sage.groups.group import Group -from sage.groups.libgap_wrapper import ParentLibGAP -from sage.groups.libgap_mixin import GroupMixinLibGAP -from sage.groups.matrix_gps.group_element import ( - MatrixGroupElement_generic, MatrixGroupElement_gap) +from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic def is_MatrixGroup(x): @@ -72,13 +77,13 @@ def is_MatrixGroup(x): EXAMPLES:: sage: from sage.groups.matrix_gps.matrix_group import is_MatrixGroup - sage: is_MatrixGroup(MatrixSpace(QQ,3)) + sage: is_MatrixGroup(MatrixSpace(QQ, 3)) False - sage: is_MatrixGroup(Mat(QQ,3)) + sage: is_MatrixGroup(Mat(QQ, 3)) False - sage: is_MatrixGroup(GL(2,ZZ)) + sage: is_MatrixGroup(GL(2, ZZ)) True - sage: is_MatrixGroup(MatrixGroup([matrix(2,[1,1,0,1])])) + sage: is_MatrixGroup(MatrixGroup([matrix(2, [1,1,0,1])])) True """ return isinstance(x, MatrixGroup_base) @@ -132,9 +137,9 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = SU(2,GF(5)); F = G.base_ring() # this is GF(5^2,'a') - sage: G._check_matrix(identity_matrix(F,2)) - sage: G._check_matrix(matrix(F,[[1,1],[0,1]])) + sage: G = SU(2, GF(5)); F = G.base_ring() # this is GF(5^2,'a') # needs sage.rings.finite_rings + sage: G._check_matrix(identity_matrix(F, 2)) # needs sage.rings.finite_rings + sage: G._check_matrix(matrix(F, [[1,1], [0,1]])) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: matrix must be unitary with respect to the hermitian form @@ -153,8 +158,8 @@ def as_matrix_group(self): EXAMPLES:: - sage: G = SU(4,GF(5)) - sage: G.as_matrix_group() + sage: G = SU(4, GF(5)) # needs sage.rings.finite_rings + sage: G.as_matrix_group() # needs sage.rings.finite_rings Matrix group over Finite Field in a of size 5^2 with 2 generators ( [ a 0 0 0] [ 1 0 4*a + 3 0] [ 0 2*a + 3 0 0] [ 1 0 0 0] @@ -179,16 +184,17 @@ def subgroup(self, generators, check=True): INPUT: - - ``generators`` -- a list/tuple/iterable of group elements of self + - ``generators`` -- a list/tuple/iterable of group elements of ``self`` - ``check`` -- boolean (optional, default: ``True``). Whether to check that each matrix is invertible. - OUTPUT: The subgroup generated by ``generators`` as an instance of FinitelyGeneratedMatrixGroup_gap + OUTPUT: The subgroup generated by ``generators`` as an instance of :class:`FinitelyGeneratedMatrixGroup_gap` EXAMPLES:: + sage: # needs sage.libs.gap sage.rings.number_field sage: UCF = UniversalCyclotomicField() sage: G = GL(3, UCF) - sage: e3 = UCF.gen(3); e5 =UCF.gen(5) + sage: e3 = UCF.gen(3); e5 = UCF.gen(5) sage: m = matrix(UCF, 3,3, [[e3, 1, 0], [0, e5, 7],[4, 3, 2]]) sage: S = G.subgroup([m]); S Subgroup with 1 generators ( @@ -197,6 +203,7 @@ def subgroup(self, generators, check=True): [ 4 3 2] ) of General Linear Group of degree 3 over Universal Cyclotomic Field + sage: # needs sage.rings.number_field sage: CF3 = CyclotomicField(3) sage: G = GL(3, CF3) sage: e3 = CF3.gen() @@ -210,31 +217,14 @@ def subgroup(self, generators, check=True): TESTS:: - sage: TestSuite(G).run() - sage: TestSuite(S).run() - - sage: W = CoxeterGroup(['I',7]) - sage: s = W.simple_reflections() - sage: G = W.subgroup([s[1]]) - sage: G.category() - Category of finite groups - - sage: W = WeylGroup(['A',2]) - sage: s = W.simple_reflections() - sage: G = W.subgroup([s[1]]) - sage: G.category() - Category of finite groups + sage: TestSuite(G).run() # needs sage.rings.number_field + sage: TestSuite(S).run() # needs sage.rings.number_field """ try: test = self.is_finite() except NotImplementedError: test = self in Groups().Finite() cat = Groups().Finite() if test else Groups() - # this method enlarges the method with same name of - # ParentLibGAP to cases where the ambient group is not - # inherited from ParentLibGAP. - if isinstance(self, ParentLibGAP): - return ParentLibGAP.subgroup(self, generators) for g in generators: if g not in self: @@ -256,8 +246,8 @@ def ambient(self): EXAMPLES:: - sage: G = GL(2,QQ) - sage: m = matrix(QQ, 2,2, [[3, 0],[~5,1]]) + sage: G = GL(2, QQ) + sage: m = matrix(QQ, 2, 2, [[3, 0], [~5,1]]) sage: S = G.subgroup([m]) sage: S.ambient() is G True @@ -277,8 +267,8 @@ def _repr_(self): EXAMPLES:: - sage: F = GF(5); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])] + sage: F = GF(5); MS = MatrixSpace(F, 2, 2) + sage: gens = [MS([[1,2], [-1,1]]), MS([[1,1], [0,1]])] sage: G = MatrixGroup(gens) sage: G Matrix group over Finite Field of size 5 with 2 generators ( @@ -288,10 +278,11 @@ def _repr_(self): case of being a subgroup:: + sage: # needs sage.rings.number_field sage: CF3 = CyclotomicField(3) sage: G = GL(2, CF3) sage: e3 = CF3.gen() - sage: m = matrix(CF3, 2,2, [[e3, 1], [0, ~e3]]) + sage: m = matrix(CF3, 2, 2, [[e3, 1], [0, ~e3]]) sage: S = G.subgroup([m]); S Subgroup with 1 generators ( [ zeta3 1] @@ -325,8 +316,8 @@ def _repr_option(self, key): EXAMPLES:: - sage: SO3 = groups.matrix.SO(3, QQ) - sage: SO3._repr_option('element_ascii_art') + sage: SO3 = groups.matrix.SO(3, QQ) # needs sage.groups sage.modules + sage: SO3._repr_option('element_ascii_art') # needs sage.groups sage.modules True """ if key == 'element_ascii_art': @@ -338,7 +329,7 @@ def _latex_(self): EXAMPLES:: sage: MS = MatrixSpace(GF(5), 2, 2) - sage: G = MatrixGroup(MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])) + sage: G = MatrixGroup(MS([[1,2], [-1,1]]), MS([[1,1], [0,1]])) sage: latex(G) \left\langle \left(\begin{array}{rr} 1 & 2 \\ @@ -355,7 +346,9 @@ def sign_representation(self, base_ring=None, side="twosided"): r""" Return the sign representation of ``self`` over ``base_ring``. - WARNING: assumes ``self`` is a matrix group over a field which has embedding over real numbers. + .. WARNING:: + + Assumes ``self`` is a matrix group over a field which has embedding over real numbers. INPUT: @@ -442,7 +435,7 @@ def degree(self): EXAMPLES:: - sage: SU(5,5).degree() + sage: SU(5,5).degree() # needs sage.rings.finite_rings 5 """ return self._deg @@ -457,7 +450,7 @@ def matrix_space(self): EXAMPLES:: - sage: F = GF(5); MS = MatrixSpace(F,2,2) + sage: F = GF(5); MS = MatrixSpace(F, 2, 2) sage: G = MatrixGroup([MS(1), MS([1,2,3,4])]) sage: G.matrix_space() Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5 @@ -502,6 +495,7 @@ def __richcmp__(self, other, op): TESTS:: + sage: # needs sage.groups sage.rings.finite_rings sage: G = groups.matrix.GL(4,2) sage: H = MatrixGroup(G.gens()) sage: G == H @@ -548,238 +542,3 @@ def __richcmp__(self, other, op): if lx != rx: return richcmp_not_equal(lx, rx, op) return rich_to_bool(op, 0) - -################################################################### -# -# Matrix group over a ring that GAP understands -# -################################################################### - - -class MatrixGroup_gap(GroupMixinLibGAP, MatrixGroup_generic, ParentLibGAP): - - Element = MatrixGroupElement_gap - - def __init__(self, degree, base_ring, libgap_group, ambient=None, category=None): - """ - Base class for matrix groups that implements GAP interface. - - INPUT: - - - ``degree`` -- integer. The degree (matrix size) of the - matrix group. - - - ``base_ring`` -- ring. The base ring of the matrices. - - - ``libgap_group`` -- the defining libgap group. - - - ``ambient`` -- A derived class of :class:`ParentLibGAP` or - ``None`` (default). The ambient class if ``libgap_group`` - has been defined as a subgroup. - - TESTS: - - :: - - sage: from sage.groups.matrix_gps.matrix_group import MatrixGroup_gap - sage: MatrixGroup_gap(2, ZZ, libgap.eval('GL(2, Integers)')) - Matrix group over Integer Ring with 3 generators ( - [0 1] [-1 0] [1 1] - [1 0], [ 0 1], [0 1] - ) - - Check that the slowness of GAP iterators and enumerators for matrix groups - (cf. http://tracker.gap-system.org/issues/369) has been fixed:: - - sage: i = iter(GL(6,5)) - sage: [ next(i) for j in range(8) ] - [ - [1 0 0 0 0 0] [4 0 0 0 0 1] [0 4 0 0 0 0] [0 4 0 0 0 0] - [0 1 0 0 0 0] [4 0 0 0 0 0] [0 0 4 0 0 0] [0 0 4 0 0 0] - [0 0 1 0 0 0] [0 4 0 0 0 0] [0 0 0 4 0 0] [0 0 0 4 0 0] - [0 0 0 1 0 0] [0 0 4 0 0 0] [0 0 0 0 4 0] [0 0 0 0 4 0] - [0 0 0 0 1 0] [0 0 0 4 0 0] [0 0 0 0 0 4] [0 0 0 0 0 4] - [0 0 0 0 0 1], [0 0 0 0 4 0], [1 4 0 0 0 0], [2 4 0 0 0 0], - [3 0 0 0 0 1] [4 0 0 1 3 3] [0 0 0 2 0 0] [1 0 0 0 4 4] - [3 0 0 0 0 0] [4 0 0 0 3 3] [0 0 0 0 4 0] [1 0 0 0 0 4] - [0 4 0 0 0 0] [3 0 0 0 0 1] [2 2 0 0 0 2] [1 0 0 0 0 0] - [0 0 4 0 0 0] [3 0 0 0 0 0] [1 4 0 0 0 0] [0 1 0 0 0 0] - [0 0 0 4 0 0] [0 4 0 0 0 0] [0 2 4 0 0 0] [0 0 1 0 0 0] - [4 0 0 0 2 3], [2 0 3 4 4 4], [0 0 1 4 0 0], [0 0 0 1 0 0] - ] - - And the same for listing the group elements, as well as few other issues:: - - sage: F = GF(3) - sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F, 2, [1,1,0,1])] - sage: G = MatrixGroup(gens) - sage: G.cardinality() - 24 - sage: v = G.list() - sage: len(v) - 24 - sage: v[:5] - ( - [1 0] [2 0] [0 1] [0 2] [1 2] - [0 1], [0 2], [2 0], [1 0], [2 2] - ) - sage: all(g in G for g in G.list()) - True - - An example over a ring (see :trac:`5241`):: - - sage: M1 = matrix(ZZ,2,[[-1,0],[0,1]]) - sage: M2 = matrix(ZZ,2,[[1,0],[0,-1]]) - sage: M3 = matrix(ZZ,2,[[-1,0],[0,-1]]) - sage: MG = MatrixGroup([M1, M2, M3]) - sage: MG.list() - ( - [1 0] [ 1 0] [-1 0] [-1 0] - [0 1], [ 0 -1], [ 0 1], [ 0 -1] - ) - sage: MG.list()[1] - [ 1 0] - [ 0 -1] - sage: MG.list()[1].parent() - Matrix group over Integer Ring with 3 generators ( - [-1 0] [ 1 0] [-1 0] - [ 0 1], [ 0 -1], [ 0 -1] - ) - - An example over a field (see :trac:`10515`):: - - sage: gens = [matrix(QQ,2,[1,0,0,1])] - sage: MatrixGroup(gens).list() - ( - [1 0] - [0 1] - ) - - Another example over a ring (see :trac:`9437`):: - - sage: len(SL(2, Zmod(4)).list()) - 48 - - An error is raised if the group is not finite:: - - sage: GL(2,ZZ).list() - Traceback (most recent call last): - ... - NotImplementedError: group must be finite - - """ - ParentLibGAP.__init__(self, libgap_group, ambient=ambient) - MatrixGroup_generic.__init__(self, degree, base_ring, category=category) - - def __iter__(self): - """ - Iterate over the elements of the group. - - This method overrides the matrix group enumerator in GAP which - does not (and often just cannot) work for infinite groups. - - TESTS: - - infinite groups can be dealt with:: - - sage: import itertools - sage: W = WeylGroup(["A",3,1]) - sage: list(itertools.islice(W, int(4))) - [ - [1 0 0 0] [-1 1 0 1] [ 1 0 0 0] [ 1 0 0 0] - [0 1 0 0] [ 0 1 0 0] [ 1 -1 1 0] [ 0 1 0 0] - [0 0 1 0] [ 0 0 1 0] [ 0 0 1 0] [ 0 1 -1 1] - [0 0 0 1], [ 0 0 0 1], [ 0 0 0 1], [ 0 0 0 1] - ] - - and finite groups, too:: - - sage: G = GL(6,5) - sage: list(itertools.islice(G, int(4))) - [ - [1 0 0 0 0 0] [4 0 0 0 0 1] [0 4 0 0 0 0] [0 4 0 0 0 0] - [0 1 0 0 0 0] [4 0 0 0 0 0] [0 0 4 0 0 0] [0 0 4 0 0 0] - [0 0 1 0 0 0] [0 4 0 0 0 0] [0 0 0 4 0 0] [0 0 0 4 0 0] - [0 0 0 1 0 0] [0 0 4 0 0 0] [0 0 0 0 4 0] [0 0 0 0 4 0] - [0 0 0 0 1 0] [0 0 0 4 0 0] [0 0 0 0 0 4] [0 0 0 0 0 4] - [0 0 0 0 0 1], [0 0 0 0 4 0], [1 4 0 0 0 0], [2 4 0 0 0 0] - ] - """ - if not self.is_finite(): - # use implementation from category framework - for g in super(Group, self).__iter__(): - yield g - return - # Use the standard GAP iterator for finite groups - for g in super().__iter__(): - yield g - return - - def _check_matrix(self, x_sage, x_gap): - """ - Check whether the matrix ``x`` defines a group element. - - This is used by the element constructor (if you pass - ``check=True``, the default) that the defining matrix is valid - for this parent. Derived classes must override this to verify - that the matrix is, for example, orthogonal or symplectic. - - INPUT: - - - ``x_sage`` -- a Sage matrix in the correct matrix space (degree - and base ring). - - - ``x_gap`` -- the corresponding LibGAP matrix. - - OUTPUT: - - A ``TypeError`` must be raised if ``x`` is invalid. - - EXAMPLES:: - - sage: m1 = matrix(GF(11), [(0, -1), (1, 0)]) - sage: m2 = matrix(GF(11), [(0, -1), (1, -1)]) - sage: G = MatrixGroup([m1, m2]) - sage: G([1,2,0,1]) - [1 2] - [0 1] - sage: G([1,1,1,0]) - Traceback (most recent call last): - ... - TypeError: matrix is not in the finitely generated group - """ - from sage.libs.gap.libgap import libgap - libgap_contains = libgap.eval(r'\in') - is_contained = libgap_contains(x_gap, self.gap()) - if not is_contained.sage(): - raise TypeError('matrix is not in the finitely generated group') - - def _subgroup_constructor(self, libgap_subgroup): - """ - Return a finitely generated subgroup. - - See - :meth:`sage.groups.libgap_wrapper.ParentLibGAP._subgroup_constructor` - for details. - - TESTS:: - - sage: SL2Z = SL(2,ZZ) - sage: S, T = SL2Z.gens() - sage: G = SL2Z.subgroup([T^2]); G # indirect doctest - Subgroup with 1 generators ( - [1 2] - [0 1] - ) of Special Linear Group of degree 2 over Integer Ring - sage: G.ambient() is SL2Z - True - """ - cat = Groups() - if self in Groups().Finite(): - cat = cat.Finite() - from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap - return FinitelyGeneratedMatrixGroup_gap(self.degree(), self.base_ring(), - libgap_subgroup, ambient=self, - category=cat) - - from sage.groups.generic import structure_description diff --git a/src/sage/groups/matrix_gps/matrix_group_gap.py b/src/sage/groups/matrix_gps/matrix_group_gap.py new file mode 100644 index 00000000000..9205951ccdd --- /dev/null +++ b/src/sage/groups/matrix_gps/matrix_group_gap.py @@ -0,0 +1,315 @@ +r""" +Matrix group over a ring that GAP understands +""" + +# **************************************************************************** +# Copyright (C) 2006 William Stein <wstein@gmail.com> +# 2006-2008 David Joyner +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2017 Dima Pasechnik +# 2021 Frรฉdรฉric Chapoton +# 2018-2019 Sebastian Oehms +# 2020 Vincent Delecroix +# 2023 Matthias Koeppe +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.categories.groups import Groups +from sage.groups.group import Group +from sage.groups.libgap_mixin import GroupMixinLibGAP +from sage.groups.libgap_wrapper import ParentLibGAP +from sage.groups.matrix_gps.group_element import MatrixGroupElement_gap +from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic + + +class MatrixGroup_gap(GroupMixinLibGAP, MatrixGroup_generic, ParentLibGAP): + + Element = MatrixGroupElement_gap + + def __init__(self, degree, base_ring, libgap_group, ambient=None, category=None): + """ + Base class for matrix groups that implements GAP interface. + + INPUT: + + - ``degree`` -- integer. The degree (matrix size) of the + matrix group. + + - ``base_ring`` -- ring. The base ring of the matrices. + + - ``libgap_group`` -- the defining libgap group. + + - ``ambient`` -- A derived class of :class:`ParentLibGAP` or + ``None`` (default). The ambient class if ``libgap_group`` + has been defined as a subgroup. + + TESTS: + + :: + + sage: from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap + sage: MatrixGroup_gap(2, ZZ, libgap.eval('GL(2, Integers)')) + Matrix group over Integer Ring with 3 generators ( + [0 1] [-1 0] [1 1] + [1 0], [ 0 1], [0 1] + ) + + Check that the slowness of GAP iterators and enumerators for matrix groups + (cf. http://tracker.gap-system.org/issues/369) has been fixed:: + + sage: i = iter(GL(6,5)) + sage: [ next(i) for j in range(8) ] + [ + [1 0 0 0 0 0] [4 0 0 0 0 1] [0 4 0 0 0 0] [0 4 0 0 0 0] + [0 1 0 0 0 0] [4 0 0 0 0 0] [0 0 4 0 0 0] [0 0 4 0 0 0] + [0 0 1 0 0 0] [0 4 0 0 0 0] [0 0 0 4 0 0] [0 0 0 4 0 0] + [0 0 0 1 0 0] [0 0 4 0 0 0] [0 0 0 0 4 0] [0 0 0 0 4 0] + [0 0 0 0 1 0] [0 0 0 4 0 0] [0 0 0 0 0 4] [0 0 0 0 0 4] + [0 0 0 0 0 1], [0 0 0 0 4 0], [1 4 0 0 0 0], [2 4 0 0 0 0], + [3 0 0 0 0 1] [4 0 0 1 3 3] [0 0 0 2 0 0] [1 0 0 0 4 4] + [3 0 0 0 0 0] [4 0 0 0 3 3] [0 0 0 0 4 0] [1 0 0 0 0 4] + [0 4 0 0 0 0] [3 0 0 0 0 1] [2 2 0 0 0 2] [1 0 0 0 0 0] + [0 0 4 0 0 0] [3 0 0 0 0 0] [1 4 0 0 0 0] [0 1 0 0 0 0] + [0 0 0 4 0 0] [0 4 0 0 0 0] [0 2 4 0 0 0] [0 0 1 0 0 0] + [4 0 0 0 2 3], [2 0 3 4 4 4], [0 0 1 4 0 0], [0 0 0 1 0 0] + ] + + And the same for listing the group elements, as well as few other issues:: + + sage: F = GF(3) + sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F, 2, [1,1,0,1])] + sage: G = MatrixGroup(gens) + sage: G.cardinality() + 24 + sage: v = G.list() + sage: len(v) + 24 + sage: v[:5] + ( + [1 0] [2 0] [0 1] [0 2] [1 2] + [0 1], [0 2], [2 0], [1 0], [2 2] + ) + sage: all(g in G for g in G.list()) + True + + An example over a ring (see :trac:`5241`):: + + sage: M1 = matrix(ZZ,2,[[-1,0],[0,1]]) + sage: M2 = matrix(ZZ,2,[[1,0],[0,-1]]) + sage: M3 = matrix(ZZ,2,[[-1,0],[0,-1]]) + sage: MG = MatrixGroup([M1, M2, M3]) + sage: MG.list() + ( + [1 0] [ 1 0] [-1 0] [-1 0] + [0 1], [ 0 -1], [ 0 1], [ 0 -1] + ) + sage: MG.list()[1] + [ 1 0] + [ 0 -1] + sage: MG.list()[1].parent() + Matrix group over Integer Ring with 3 generators ( + [-1 0] [ 1 0] [-1 0] + [ 0 1], [ 0 -1], [ 0 -1] + ) + + An example over a field (see :trac:`10515`):: + + sage: gens = [matrix(QQ,2,[1,0,0,1])] + sage: MatrixGroup(gens).list() + ( + [1 0] + [0 1] + ) + + Another example over a ring (see :trac:`9437`):: + + sage: len(SL(2, Zmod(4)).list()) + 48 + + An error is raised if the group is not finite:: + + sage: GL(2,ZZ).list() + Traceback (most recent call last): + ... + NotImplementedError: group must be finite + + """ + ParentLibGAP.__init__(self, libgap_group, ambient=ambient) + MatrixGroup_generic.__init__(self, degree, base_ring, category=category) + + def __iter__(self): + """ + Iterate over the elements of the group. + + This method overrides the matrix group enumerator in GAP which + does not (and often just cannot) work for infinite groups. + + TESTS: + + infinite groups can be dealt with:: + + sage: import itertools + sage: W = WeylGroup(["A",3,1]) # needs sage.rings.number_field + sage: list(itertools.islice(W, int(4))) # needs sage.rings.number_field + [ + [1 0 0 0] [-1 1 0 1] [ 1 0 0 0] [ 1 0 0 0] + [0 1 0 0] [ 0 1 0 0] [ 1 -1 1 0] [ 0 1 0 0] + [0 0 1 0] [ 0 0 1 0] [ 0 0 1 0] [ 0 1 -1 1] + [0 0 0 1], [ 0 0 0 1], [ 0 0 0 1], [ 0 0 0 1] + ] + + and finite groups, too:: + + sage: G = GL(6,5) + sage: list(itertools.islice(G, int(4))) + [ + [1 0 0 0 0 0] [4 0 0 0 0 1] [0 4 0 0 0 0] [0 4 0 0 0 0] + [0 1 0 0 0 0] [4 0 0 0 0 0] [0 0 4 0 0 0] [0 0 4 0 0 0] + [0 0 1 0 0 0] [0 4 0 0 0 0] [0 0 0 4 0 0] [0 0 0 4 0 0] + [0 0 0 1 0 0] [0 0 4 0 0 0] [0 0 0 0 4 0] [0 0 0 0 4 0] + [0 0 0 0 1 0] [0 0 0 4 0 0] [0 0 0 0 0 4] [0 0 0 0 0 4] + [0 0 0 0 0 1], [0 0 0 0 4 0], [1 4 0 0 0 0], [2 4 0 0 0 0] + ] + """ + if not self.is_finite(): + # use implementation from category framework + for g in super(Group, self).__iter__(): + yield g + return + # Use the standard GAP iterator for finite groups + for g in super().__iter__(): + yield g + return + + def _check_matrix(self, x_sage, x_gap): + """ + Check whether the matrix ``x`` defines a group element. + + This is used by the element constructor (if you pass + ``check=True``, the default) that the defining matrix is valid + for this parent. Derived classes must override this to verify + that the matrix is, for example, orthogonal or symplectic. + + INPUT: + + - ``x_sage`` -- a Sage matrix in the correct matrix space (degree + and base ring). + + - ``x_gap`` -- the corresponding LibGAP matrix. + + OUTPUT: + + A ``TypeError`` must be raised if ``x`` is invalid. + + EXAMPLES:: + + sage: m1 = matrix(GF(11), [(0, -1), (1, 0)]) + sage: m2 = matrix(GF(11), [(0, -1), (1, -1)]) + sage: G = MatrixGroup([m1, m2]) + sage: G([1,2,0,1]) + [1 2] + [0 1] + sage: G([1,1,1,0]) + Traceback (most recent call last): + ... + TypeError: matrix is not in the finitely generated group + """ + from sage.libs.gap.libgap import libgap + libgap_contains = libgap.eval(r'\in') + is_contained = libgap_contains(x_gap, self.gap()) + if not is_contained.sage(): + raise TypeError('matrix is not in the finitely generated group') + + def subgroup(self, generators, check=True): + """ + Return the subgroup generated by the given generators. + + INPUT: + + - ``generators`` -- a list/tuple/iterable of group elements of ``self`` + - ``check`` -- boolean (optional, default: ``True``). Whether to check that each matrix is invertible. + + OUTPUT: The subgroup generated by ``generators`` as an instance of :class:`FinitelyGeneratedMatrixGroup_gap` + + EXAMPLES:: + + sage: # needs sage.rings.number_field + sage: UCF = UniversalCyclotomicField() + sage: G = GL(3, UCF) + sage: e3 = UCF.gen(3); e5 = UCF.gen(5) + sage: m = matrix(UCF, 3,3, [[e3, 1, 0], [0, e5, 7],[4, 3, 2]]) + sage: S = G.subgroup([m]); S + Subgroup with 1 generators ( + [E(3) 1 0] + [ 0 E(5) 7] + [ 4 3 2] + ) of General Linear Group of degree 3 over Universal Cyclotomic Field + + sage: # needs sage.rings.number_field + sage: CF3 = CyclotomicField(3) + sage: G = GL(3, CF3) + sage: e3 = CF3.gen() + sage: m = matrix(CF3, 3,3, [[e3, 1, 0], [0, ~e3, 7],[4, 3, 2]]) + sage: S = G.subgroup([m]); S + Subgroup with 1 generators ( + [ zeta3 1 0] + [ 0 -zeta3 - 1 7] + [ 4 3 2] + ) of General Linear Group of degree 3 over Cyclotomic Field of order 3 and degree 2 + + TESTS:: + + sage: TestSuite(G).run() # needs sage.rings.number_field + sage: TestSuite(S).run() # needs sage.rings.number_field + + sage: # needs sage.rings.number_field + sage: W = CoxeterGroup(['I',7]) + sage: s = W.simple_reflections() + sage: G = W.subgroup([s[1]]) + sage: G.category() + Category of finite groups + + sage: # needs sage.rings.number_field + sage: W = WeylGroup(['A',2]) + sage: s = W.simple_reflections() + sage: G = W.subgroup([s[1]]) + sage: G.category() + Category of finite groups + """ + # Override MatrixGroup_generic.subgroup + return ParentLibGAP.subgroup(self, generators) + + def _subgroup_constructor(self, libgap_subgroup): + """ + Return a finitely generated subgroup. + + See + :meth:`sage.groups.libgap_wrapper.ParentLibGAP._subgroup_constructor` + for details. + + TESTS:: + + sage: SL2Z = SL(2,ZZ) + sage: S, T = SL2Z.gens() + sage: G = SL2Z.subgroup([T^2]); G # indirect doctest + Subgroup with 1 generators ( + [1 2] + [0 1] + ) of Special Linear Group of degree 2 over Integer Ring + sage: G.ambient() is SL2Z + True + """ + cat = Groups() + if self in Groups().Finite(): + cat = cat.Finite() + from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap + return FinitelyGeneratedMatrixGroup_gap(self.degree(), self.base_ring(), + libgap_subgroup, ambient=self, + category=cat) + + from sage.groups.generic import structure_description diff --git a/src/sage/groups/matrix_gps/morphism.py b/src/sage/groups/matrix_gps/morphism.py index 9805161d016..e2fc2e0fd59 100644 --- a/src/sage/groups/matrix_gps/morphism.py +++ b/src/sage/groups/matrix_gps/morphism.py @@ -42,6 +42,7 @@ def to_libgap(x): from sage.libs.gap.libgap import libgap return libgap(x) + lazy_import('sage.groups.libgap_morphism', 'GroupMorphism_libgap', 'MatrixGroupMorphism_im_gens', deprecation=25444) diff --git a/src/sage/groups/matrix_gps/named_group.py b/src/sage/groups/matrix_gps/named_group.py index 39bb43c710a..4568c43d326 100644 --- a/src/sage/groups/matrix_gps/named_group.py +++ b/src/sage/groups/matrix_gps/named_group.py @@ -8,7 +8,7 @@ sage: SL(2, ZZ) Special Linear Group of degree 2 over Integer Ring - sage: G = SL(2,GF(3)); G + sage: G = SL(2, GF(3)); G Special Linear Group of degree 2 over Finite Field of size 3 sage: G.is_finite() True @@ -17,7 +17,7 @@ [1 0] [0 2] [0 1] [2 0] [0 2] [0 1] [0 2] [0 1], [1 1], [2 1], [0 2], [1 2], [2 2], [1 0] ) - sage: G = SL(6,GF(5)) + sage: G = SL(6, GF(5)) sage: G.gens() ( [2 0 0 0 0 0] [4 0 0 0 0 1] @@ -31,7 +31,10 @@ ############################################################################## # Copyright (C) 2006 David Joyner and William Stein <wstein@gmail.com> -# Copyright (C) 2013 Volker Braun <vbraun.name@gmail.com> +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2017 Frรฉdรฉric Chapoton +# 2018 Travis Scrimshaw +# 2018 Sebastian Oehms # # Distributed under the terms of the GNU General Public License (GPL) # @@ -40,9 +43,8 @@ # http://www.gnu.org/licenses/ ############################################################################## +from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic from sage.structure.unique_representation import CachedRepresentation -from sage.groups.matrix_gps.matrix_group import ( - MatrixGroup_generic, MatrixGroup_gap ) def normalize_args_vectorspace(*args, **kwds): @@ -81,12 +83,12 @@ def normalize_args_vectorspace(*args, **kwds): TESTS:: sage: from sage.groups.matrix_gps.named_group import normalize_args_vectorspace - sage: A = AffineSpace(2, GF(4,'a')); A + sage: A = AffineSpace(2, GF(4,'a')); A # needs sage.rings.finite_rings Affine Space of dimension 2 over Finite Field in a of size 2^2 - sage: normalize_args_vectorspace(A) + sage: normalize_args_vectorspace(A) # needs sage.rings.finite_rings (2, Finite Field in a of size 2^2) - sage: normalize_args_vectorspace(2,4) # shorthand + sage: normalize_args_vectorspace(2,4) # shorthand # needs sage.rings.finite_rings (2, Finite Field in a of size 2^2) sage: V = ZZ^3; V @@ -148,12 +150,12 @@ def normalize_args_invariant_form(R, d, invariant_form): TESTS:: sage: from sage.groups.matrix_gps.named_group import normalize_args_invariant_form - sage: CF3 = CyclotomicField(3) - sage: m = normalize_args_invariant_form(CF3, 3, (1,2,3,0,2,0,0,2,1)); m + sage: CF3 = CyclotomicField(3) # needs sage.rings.number_field + sage: m = normalize_args_invariant_form(CF3, 3, (1,2,3,0,2,0,0,2,1)); m # needs sage.rings.number_field [1 2 3] [0 2 0] [0 2 1] - sage: m.base_ring() == CF3 + sage: m.base_ring() == CF3 # needs sage.rings.number_field True sage: normalize_args_invariant_form(ZZ, 3, (1,2,3,0,2,0,0,2)) @@ -290,7 +292,8 @@ def __richcmp__(self, other, op): sage: G == MatrixGroup(G.gens()) True - sage: G = groups.matrix.GL(4,2) + sage: # needs sage.rings.finite_rings + sage: G = groups.matrix.GL(4,2) # needs sage.modules sage: H = MatrixGroup(G.gens()) sage: G == H True @@ -298,42 +301,3 @@ def __richcmp__(self, other, op): False """ return MatrixGroup_generic.__richcmp__(self, other, op) - - -class NamedMatrixGroup_gap(NamedMatrixGroup_generic, MatrixGroup_gap): - - def __init__(self, degree, base_ring, special, sage_name, latex_string, - gap_command_string, category=None): - """ - Base class for "named" matrix groups using LibGAP - - INPUT: - - - ``degree`` -- integer. The degree (number of rows/columns of - matrices). - - - ``base_ring`` -- ring. The base ring of the matrices. - - - ``special`` -- boolean. Whether the matrix group is special, - that is, elements have determinant one. - - - ``latex_string`` -- string. The latex representation. - - - ``gap_command_string`` -- string. The GAP command to construct - the matrix group. - - EXAMPLES:: - - sage: G = GL(2, GF(3)) - sage: from sage.groups.matrix_gps.named_group import NamedMatrixGroup_gap - sage: isinstance(G, NamedMatrixGroup_gap) - True - """ - from sage.libs.gap.libgap import libgap - group = libgap.eval(gap_command_string) - MatrixGroup_gap.__init__(self, degree, base_ring, group, - category=category) - self._special = special - self._gap_string = gap_command_string - self._name_string = sage_name - self._latex_string = latex_string diff --git a/src/sage/groups/matrix_gps/named_group_gap.py b/src/sage/groups/matrix_gps/named_group_gap.py new file mode 100644 index 00000000000..b8b1f54722c --- /dev/null +++ b/src/sage/groups/matrix_gps/named_group_gap.py @@ -0,0 +1,57 @@ +""" +Base for Classical Matrix Groups with GAP +""" + +############################################################################## +# Copyright (C) 2006 David Joyner and William Stein <wstein@gmail.com> +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2017 John Palmieri +# 2023 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# The full text of the GPL is available at: +# +# http://www.gnu.org/licenses/ +############################################################################## + +from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap +from sage.groups.matrix_gps.named_group import NamedMatrixGroup_generic + +class NamedMatrixGroup_gap(NamedMatrixGroup_generic, MatrixGroup_gap): + + def __init__(self, degree, base_ring, special, sage_name, latex_string, + gap_command_string, category=None): + """ + Base class for "named" matrix groups using LibGAP + + INPUT: + + - ``degree`` -- integer. The degree (number of rows/columns of + matrices). + + - ``base_ring`` -- ring. The base ring of the matrices. + + - ``special`` -- boolean. Whether the matrix group is special, + that is, elements have determinant one. + + - ``latex_string`` -- string. The latex representation. + + - ``gap_command_string`` -- string. The GAP command to construct + the matrix group. + + EXAMPLES:: + + sage: G = GL(2, GF(3)) + sage: from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap + sage: isinstance(G, NamedMatrixGroup_gap) + True + """ + from sage.libs.gap.libgap import libgap + group = libgap.eval(gap_command_string) + MatrixGroup_gap.__init__(self, degree, base_ring, group, + category=category) + self._special = special + self._gap_string = gap_command_string + self._name_string = sage_name + self._latex_string = latex_string diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 8ff96051a8b..b05be536955 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -36,8 +36,9 @@ sage: GO(3,7) General Orthogonal Group of degree 3 over Finite Field of size 7 - sage: G = SO( 4, GF(7), 1); G - Special Orthogonal Group of degree 4 and form parameter 1 over Finite Field of size 7 + sage: G = SO(4, GF(7), 1); G + Special Orthogonal Group of degree 4 and form parameter 1 + over Finite Field of size 7 sage: G.random_element() # random [4 3 5 2] [6 6 4 0] @@ -75,7 +76,11 @@ # **************************************************************************** # Copyright (C) 2006 David Joyner and William Stein -# Copyright (C) 2013 Volker Braun <vbraun.name@gmail.com> +# 2009 Mike Hansen +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2018 Sebastian Oehms +# 2018 Travis Scrimshaw +# 2023 Matthias Koeppe # # 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 @@ -85,13 +90,13 @@ # **************************************************************************** from sage.rings.integer_ring import ZZ -from sage.rings.finite_rings.finite_field_base import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.misc.latex import latex from sage.misc.cachefunc import cached_method from sage.groups.matrix_gps.named_group import ( normalize_args_vectorspace, normalize_args_invariant_form, - NamedMatrixGroup_generic, NamedMatrixGroup_gap) -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + NamedMatrixGroup_generic) + def normalize_args_e(degree, ring, e): """ @@ -127,7 +132,7 @@ def normalize_args_e(degree, ring, e): ... ValueError: must have e=-1 or e=1 for even degree """ - if is_FiniteField(ring) and degree%2 == 0: + if isinstance(ring, FiniteField) and degree%2 == 0: if e not in (-1, +1): raise ValueError('must have e=-1 or e=1 for even degree') else: @@ -149,7 +154,7 @@ def _OG(n, R, special, e=0, var='a', invariant_form=None): Check that :trac:`26028` is fixed:: - sage: GO(3,25).order() # indirect doctest + sage: GO(3,25).order() # indirect doctest # needs sage.rings.finite_rings 31200 Check that :trac:`28054` is fixed:: @@ -171,7 +176,7 @@ def _OG(n, R, special, e=0, var='a', invariant_form=None): e = normalize_args_e(degree, ring, e) if invariant_form is not None: - if is_FiniteField(ring): + if isinstance(ring, FiniteField): raise NotImplementedError("invariant_form for finite groups is fixed by GAP") if e == 0: @@ -202,12 +207,16 @@ def _OG(n, R, special, e=0, var='a', invariant_form=None): latex(ring), '+' if e == 1 else '-') - if is_FiniteField(ring): - cmd = '{0}O({1}, {2}, {3})'.format(ltx_prefix, e, degree, ring.order()) - return OrthogonalMatrixGroup_gap(degree, ring, False, name, ltx, cmd) - else: - return OrthogonalMatrixGroup_generic(degree, ring, False, name, ltx, invariant_form=invariant_form) + if isinstance(ring, FiniteField): + try: + from .orthogonal_gap import OrthogonalMatrixGroup_gap + except ImportError: + pass + else: + cmd = '{0}O({1}, {2}, {3})'.format(ltx_prefix, e, degree, ring.order()) + return OrthogonalMatrixGroup_gap(degree, ring, False, name, ltx, cmd) + return OrthogonalMatrixGroup_generic(degree, ring, False, name, ltx, invariant_form=invariant_form) ######################################################################## @@ -259,11 +268,11 @@ def GO(n, R, e=0, var='a', invariant_form=None): EXAMPLES:: - sage: GO( 3, GF(7)) + sage: GO(3, GF(7)) General Orthogonal Group of degree 3 over Finite Field of size 7 - sage: GO( 3, GF(7)).order() + sage: GO(3, GF(7)).order() 672 - sage: GO( 3, GF(7)).gens() + sage: GO(3, GF(7)).gens() ( [3 0 0] [0 1 0] [0 5 0] [1 6 6] @@ -272,9 +281,9 @@ def GO(n, R, e=0, var='a', invariant_form=None): Using the ``invariant_form`` option:: - sage: m = matrix(QQ, 3,3, [[0, 1, 0], [1, 0, 0], [0, 0, 3]]) - sage: GO3 = GO(3,QQ) - sage: GO3m = GO(3,QQ, invariant_form=m) + sage: m = matrix(QQ, 3, 3, [[0, 1, 0], [1, 0, 0], [0, 0, 3]]) + sage: GO3 = GO(3, QQ) + sage: GO3m = GO(3, QQ, invariant_form=m) sage: GO3 == GO3m False sage: GO3.invariant_form() @@ -299,15 +308,16 @@ def GO(n, R, e=0, var='a', invariant_form=None): [1 0 0] [0 0 3] - sage: GO(3,3, invariant_form=[[1,0,0],[0,2,0],[0,0,1]]) + sage: GO(3,3, invariant_form=[[1,0,0], [0,2,0], [0,0,1]]) Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP - sage: 5+5 + sage: 5 + 5 10 sage: R.<x> = ZZ[] - sage: GO(2, R, invariant_form=[[x,0],[0,1]]) - General Orthogonal Group of degree 2 over Univariate Polynomial Ring in x over Integer Ring with respect to symmetric form + sage: GO(2, R, invariant_form=[[x,0], [0,1]]) + General Orthogonal Group of degree 2 over + Univariate Polynomial Ring in x over Integer Ring with respect to symmetric form [x 0] [0 1] @@ -320,7 +330,6 @@ def GO(n, R, e=0, var='a', invariant_form=None): return _OG(n, R, False, e=e, var=var, invariant_form=invariant_form) - ######################################################################## # Special Orthogonal Group ######################################################################## @@ -366,8 +375,7 @@ def SO(n, R, e=None, var='a', invariant_form=None): EXAMPLES:: - sage: G = SO(3,GF(5)) - sage: G + sage: G = SO(3,GF(5)); G Special Orthogonal Group of degree 3 over Finite Field of size 5 sage: G = SO(3,GF(5)) @@ -387,8 +395,9 @@ def SO(n, R, e=None, var='a', invariant_form=None): Using the ``invariant_form`` option:: + sage: # needs sage.rings.number_field sage: CF3 = CyclotomicField(3); e3 = CF3.gen() - sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3,2,0],[0,0,1]]) + sage: m = matrix(CF3, 3, 3, [[1,e3,0], [e3,2,0], [0,0,1]]) sage: SO3 = SO(3, CF3) sage: SO3m = SO(3, CF3, invariant_form=m) sage: SO3 == SO3m @@ -415,7 +424,7 @@ def SO(n, R, e=None, var='a', invariant_form=None): [zeta3 2 0] [ 0 0 1] - sage: SO(3,5, invariant_form=[[1,0,0],[0,2,0],[0,0,3]]) + sage: SO(3, 5, invariant_form=[[1,0,0], [0,2,0], [0,0,3]]) Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP @@ -424,14 +433,13 @@ def SO(n, R, e=None, var='a', invariant_form=None): TESTS:: - sage: TestSuite(SO3m).run() + sage: TestSuite(SO3m).run() # needs sage.rings.number_field sage: groups.matrix.SO(2, 3, e=1) Special Orthogonal Group of degree 2 and form parameter 1 over Finite Field of size 3 """ return _OG(n, R, True, e=e, var=var, invariant_form=invariant_form) - ######################################################################## # Orthogonal Group class ######################################################################## @@ -452,6 +460,7 @@ class OrthogonalMatrixGroup_generic(NamedMatrixGroup_generic): sage: latex(G) \text{SO}_{3}(\Bold{F}_{5}) + sage: # needs sage.rings.number_field sage: CF3 = CyclotomicField(3); e3 = CF3.gen() sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3,2,0],[0,0,1]]) sage: G = SO(3, CF3, invariant_form=m) @@ -486,7 +495,7 @@ def invariant_bilinear_form(self): [0 1 0 0] [0 0 1 0] [0 0 0 1] - sage: GO3m = GO(3,QQ, invariant_form=(1,0,0,0,2,0,0,0,3)) + sage: GO3m = GO(3, QQ, invariant_form=(1,0,0, 0,2,0, 0,0,3)) sage: GO3m.invariant_bilinear_form() [1 0 0] [0 2 0] @@ -531,120 +540,3 @@ def _check_matrix(self, x, *args): else: raise TypeError('matrix must be orthogonal with respect to the symmetric form\n%s' %(F)) # TODO: check that quadratic form is preserved in characteristic two - -class OrthogonalMatrixGroup_gap(OrthogonalMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): - r""" - The general or special orthogonal group in GAP. - - TESTS: - - Check that :trac:`20867` is fixed:: - - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap - sage: G = GO(3,3) - sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) - True - """ - @cached_method - def invariant_bilinear_form(self): - """ - Return the symmetric bilinear form preserved by the orthogonal - group. - - OUTPUT: - - A matrix `M` such that, for every group element g, the - identity `g m g^T = m` holds. In characteristic different from - two, this uniquely determines the orthogonal group. - - EXAMPLES:: - - sage: G = GO(4, GF(7), -1) - sage: G.invariant_bilinear_form() - [0 1 0 0] - [1 0 0 0] - [0 0 2 0] - [0 0 0 2] - - sage: G = GO(4, GF(7), +1) - sage: G.invariant_bilinear_form() - [0 1 0 0] - [1 0 0 0] - [0 0 6 0] - [0 0 0 2] - - sage: G = SO(4, GF(7), -1) - sage: G.invariant_bilinear_form() - [0 1 0 0] - [1 0 0 0] - [0 0 2 0] - [0 0 0 2] - - TESTS:: - - sage: G.invariant_form() - [0 1 0 0] - [1 0 0 0] - [0 0 2 0] - [0 0 0 2] - """ - m = self.gap().InvariantBilinearForm()['matrix'].matrix() - m.set_immutable() - return m - - invariant_form = invariant_bilinear_form # alias (analogues to symplectic and unitary cases) - - @cached_method - def invariant_quadratic_form(self): - r""" - Return the quadratic form preserved by the orthogonal group. - - OUTPUT: - - The matrix `Q` defining "orthogonal" as follows. The matrix - determines a quadratic form `q` on the natural vector space - `V`, on which `G` acts, by `q(v) = v Q v^t`. A matrix `M` is - an element of the orthogonal group if `q(v) = q(v M)` for all - `v \in V`. - - EXAMPLES:: - - sage: G = GO(4, GF(7), -1) - sage: G.invariant_quadratic_form() - [0 1 0 0] - [0 0 0 0] - [0 0 1 0] - [0 0 0 1] - - sage: G = GO(4, GF(7), +1) - sage: G.invariant_quadratic_form() - [0 1 0 0] - [0 0 0 0] - [0 0 3 0] - [0 0 0 1] - - sage: G = GO(4, QQ) - sage: G.invariant_quadratic_form() - [1 0 0 0] - [0 1 0 0] - [0 0 1 0] - [0 0 0 1] - - sage: G = SO(4, GF(7), -1) - sage: G.invariant_quadratic_form() - [0 1 0 0] - [0 0 0 0] - [0 0 1 0] - [0 0 0 1] - - TESTS:: - - sage: GO(4, GF(7), -1).invariant_form() - [0 1 0 0] - [1 0 0 0] - [0 0 2 0] - [0 0 0 2] - """ - m = self.gap().InvariantQuadraticForm()['matrix'].matrix() - m.set_immutable() - return m diff --git a/src/sage/groups/matrix_gps/orthogonal_gap.py b/src/sage/groups/matrix_gps/orthogonal_gap.py new file mode 100644 index 00000000000..17dabb698f2 --- /dev/null +++ b/src/sage/groups/matrix_gps/orthogonal_gap.py @@ -0,0 +1,141 @@ +r""" +Orthogonal Linear Groups with GAP +""" + +# **************************************************************************** +# Copyright (C) 2006 David Joyner and William Stein +# 2009 Mike Hansen +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2018 Sebastian Oehms +# 2018 Travis Scrimshaw +# 2023 Matthias Koeppe +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap +from sage.groups.matrix_gps.orthogonal import OrthogonalMatrixGroup_generic +from sage.misc.cachefunc import cached_method + + +class OrthogonalMatrixGroup_gap(OrthogonalMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): + r""" + The general or special orthogonal group in GAP. + + TESTS: + + Check that :trac:`20867` is fixed:: + + sage: from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap + sage: G = GO(3,3) + sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) + True + """ + @cached_method + def invariant_bilinear_form(self): + """ + Return the symmetric bilinear form preserved by the orthogonal + group. + + OUTPUT: + + A matrix `M` such that, for every group element `g`, the + identity `g m g^T = m` holds. In characteristic different from + two, this uniquely determines the orthogonal group. + + EXAMPLES:: + + sage: G = GO(4, GF(7), -1) + sage: G.invariant_bilinear_form() + [0 1 0 0] + [1 0 0 0] + [0 0 2 0] + [0 0 0 2] + + sage: G = GO(4, GF(7), +1) + sage: G.invariant_bilinear_form() + [0 1 0 0] + [1 0 0 0] + [0 0 6 0] + [0 0 0 2] + + sage: G = SO(4, GF(7), -1) + sage: G.invariant_bilinear_form() + [0 1 0 0] + [1 0 0 0] + [0 0 2 0] + [0 0 0 2] + + TESTS:: + + sage: G.invariant_form() + [0 1 0 0] + [1 0 0 0] + [0 0 2 0] + [0 0 0 2] + """ + m = self.gap().InvariantBilinearForm()['matrix'].matrix() + m.set_immutable() + return m + + invariant_form = invariant_bilinear_form # alias (analogues to symplectic and unitary cases) + + @cached_method + def invariant_quadratic_form(self): + r""" + Return the quadratic form preserved by the orthogonal group. + + OUTPUT: + + The matrix `Q` defining "orthogonal" as follows. The matrix + determines a quadratic form `q` on the natural vector space + `V`, on which `G` acts, by `q(v) = v Q v^t`. A matrix `M` is + an element of the orthogonal group if `q(v) = q(v M)` for all + `v \in V`. + + EXAMPLES:: + + sage: G = GO(4, GF(7), -1) + sage: G.invariant_quadratic_form() + [0 1 0 0] + [0 0 0 0] + [0 0 1 0] + [0 0 0 1] + + sage: G = GO(4, GF(7), +1) + sage: G.invariant_quadratic_form() + [0 1 0 0] + [0 0 0 0] + [0 0 3 0] + [0 0 0 1] + + sage: G = GO(4, QQ) + sage: G.invariant_quadratic_form() + [1 0 0 0] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + + sage: G = SO(4, GF(7), -1) + sage: G.invariant_quadratic_form() + [0 1 0 0] + [0 0 0 0] + [0 0 1 0] + [0 0 0 1] + + TESTS:: + + sage: GO(4, GF(7), -1).invariant_form() + [0 1 0 0] + [1 0 0 0] + [0 0 2 0] + [0 0 0 2] + """ + m = self.gap().InvariantQuadraticForm()['matrix'].matrix() + m.set_immutable() + return m diff --git a/src/sage/groups/matrix_gps/pickling_overrides.py b/src/sage/groups/matrix_gps/pickling_overrides.py index d8d68ffd22f..9a62d03e6c4 100644 --- a/src/sage/groups/matrix_gps/pickling_overrides.py +++ b/src/sage/groups/matrix_gps/pickling_overrides.py @@ -4,12 +4,11 @@ from sage.structure.sage_object import register_unpickle_override -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap -from sage.groups.matrix_gps.group_element import MatrixGroupElement_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.group_element_gap import MatrixGroupElement_gap from sage.groups.matrix_gps.linear import GL, LinearMatrixGroup_generic - class LegacyMatrixGroup(FinitelyGeneratedMatrixGroup_gap): def __setstate__(self, state): diff --git a/src/sage/groups/matrix_gps/symplectic.py b/src/sage/groups/matrix_gps/symplectic.py index 3715f531913..3a7e7258fe9 100644 --- a/src/sage/groups/matrix_gps/symplectic.py +++ b/src/sage/groups/matrix_gps/symplectic.py @@ -3,7 +3,7 @@ EXAMPLES:: - sage: G = Sp(4,GF(7)); G + sage: G = Sp(4, GF(7)); G Symplectic Group of degree 4 over Finite Field of size 7 sage: g = prod(G.gens()); g [3 0 3 0] @@ -31,7 +31,9 @@ # **************************************************************************** # Copyright (C) 2006 David Joyner and William Stein -# Copyright (C) 2013 Volker Braun <vbraun.name@gmail.com> +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2018 Sebastian Oehms +# 2018 Travis Scrimshaw # # 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 @@ -42,11 +44,10 @@ from sage.misc.latex import latex from sage.misc.cachefunc import cached_method -from sage.rings.finite_rings.finite_field_base import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.groups.matrix_gps.named_group import ( normalize_args_vectorspace, normalize_args_invariant_form, - NamedMatrixGroup_generic, NamedMatrixGroup_gap) -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + NamedMatrixGroup_generic) ############################################################################### @@ -134,7 +135,7 @@ def Sp(n, R, var='a', invariant_form=None): sage: TestSuite(Sp4).run() sage: TestSuite(Sp4m).run() - sage: groups.matrix.Sp(2, 3) + sage: groups.matrix.Sp(2, 3) # needs sage.modules sage.rings.finite_rings Symplectic Group of degree 2 over Finite Field of size 3 sage: G = Sp(4,5) @@ -145,7 +146,7 @@ def Sp(n, R, var='a', invariant_form=None): raise ValueError('the degree must be even') if invariant_form is not None: - if is_FiniteField(ring): + if isinstance(ring, FiniteField): raise NotImplementedError("invariant_form for finite groups is fixed by GAP") invariant_form = normalize_args_invariant_form(ring, degree, invariant_form) @@ -161,11 +162,17 @@ def Sp(n, R, var='a', invariant_form=None): ltx = r'\text{{Sp}}_{{{0}}}({1})'.format(degree, latex(ring)) try: - cmd = 'Sp({0}, {1})'.format(degree, ring._gap_init_()) - return SymplecticMatrixGroup_gap(degree, ring, True, name, ltx, cmd) - except ValueError: - return SymplecticMatrixGroup_generic(degree, ring, True, name, ltx, invariant_form=invariant_form) + from .symplectic_gap import SymplecticMatrixGroup_gap + except ImportError: + pass + else: + try: + cmd = 'Sp({0}, {1})'.format(degree, ring._gap_init_()) + return SymplecticMatrixGroup_gap(degree, ring, True, name, ltx, cmd) + except ValueError: + pass + return SymplecticMatrixGroup_generic(degree, ring, True, name, ltx, invariant_form=invariant_form) class SymplecticMatrixGroup_generic(NamedMatrixGroup_generic): @@ -179,8 +186,10 @@ class SymplecticMatrixGroup_generic(NamedMatrixGroup_generic): sage: latex(Sp43) \text{Sp}_{4}(\Bold{F}_{3}) - sage: Sp4m = Sp(4,QQ, invariant_form=(0, 0, 1, 0, 0, 0, 0, 2, -1, 0, 0, 0, 0, -2, 0, 0)); Sp4m - Symplectic Group of degree 4 over Rational Field with respect to alternating bilinear form + sage: Sp4m = Sp(4, QQ, invariant_form=(0, 0, 1, 0, 0, 0, 0, 2, + ....: -1, 0, 0, 0, 0, -2, 0, 0)); Sp4m + Symplectic Group of degree 4 over Rational Field + with respect to alternating bilinear form [ 0 0 1 0] [ 0 0 0 2] [-1 0 0 0] @@ -199,9 +208,7 @@ def invariant_form(self): """ Return the quadratic form preserved by the symplectic group. - OUTPUT: - - A matrix. + OUTPUT: A matrix. EXAMPLES:: @@ -232,53 +239,9 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = Sp(4,GF(5)) + sage: G = Sp(4, GF(5)) sage: G._check_matrix(G.an_element().matrix()) """ F = self.invariant_form() if x * F * x.transpose() != F: raise TypeError('matrix must be symplectic with respect to the alternating form\n{}'.format(F)) - - -class SymplecticMatrixGroup_gap(SymplecticMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): - r""" - Symplectic group in GAP. - - EXAMPLES:: - - sage: Sp(2,4) - Symplectic Group of degree 2 over Finite Field in a of size 2^2 - - sage: latex(Sp(4,5)) - \text{Sp}_{4}(\Bold{F}_{5}) - - TESTS: - - Check that :trac:`20867` is fixed:: - - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap - sage: G = Sp(4,3) - sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) - True - """ - - @cached_method - def invariant_form(self): - """ - Return the quadratic form preserved by the symplectic group. - - OUTPUT: - - A matrix. - - EXAMPLES:: - - sage: Sp(4, GF(3)).invariant_form() - [0 0 0 1] - [0 0 1 0] - [0 2 0 0] - [2 0 0 0] - """ - m = self.gap().InvariantBilinearForm()['matrix'].matrix() - m.set_immutable() - return m diff --git a/src/sage/groups/matrix_gps/symplectic_gap.py b/src/sage/groups/matrix_gps/symplectic_gap.py new file mode 100644 index 00000000000..96bf1fb5a75 --- /dev/null +++ b/src/sage/groups/matrix_gps/symplectic_gap.py @@ -0,0 +1,63 @@ +""" +Symplectic Linear Groups with GAP +""" + +# **************************************************************************** +# Copyright (C) 2006 David Joyner and William Stein +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2018 Travis Scrimshaw +# 2023 Matthias Koeppe +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap +from sage.groups.matrix_gps.symplectic import SymplecticMatrixGroup_generic +from sage.misc.cachefunc import cached_method + + +class SymplecticMatrixGroup_gap(SymplecticMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): + r""" + Symplectic group in GAP. + + EXAMPLES:: + + sage: Sp(2,4) # needs sage.rings.finite_rings + Symplectic Group of degree 2 over Finite Field in a of size 2^2 + + sage: latex(Sp(4,5)) + \text{Sp}_{4}(\Bold{F}_{5}) + + TESTS: + + Check that :trac:`20867` is fixed:: + + sage: from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap + sage: G = Sp(4,3) + sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) + True + """ + + @cached_method + def invariant_form(self): + """ + Return the quadratic form preserved by the symplectic group. + + OUTPUT: A matrix. + + EXAMPLES:: + + sage: Sp(4, GF(3)).invariant_form() + [0 0 0 1] + [0 0 1 0] + [0 2 0 0] + [2 0 0 0] + """ + m = self.gap().InvariantBilinearForm()['matrix'].matrix() + m.set_immutable() + return m diff --git a/src/sage/groups/matrix_gps/unitary.py b/src/sage/groups/matrix_gps/unitary.py index f4d8df525be..22dd25b1a4b 100644 --- a/src/sage/groups/matrix_gps/unitary.py +++ b/src/sage/groups/matrix_gps/unitary.py @@ -6,6 +6,7 @@ EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: G = SU(3,5) sage: G.order() 378000 @@ -40,7 +41,12 @@ # **************************************************************************** # Copyright (C) 2006 David Joyner and William Stein -# Copyright (C) 2013 Volker Braun <vbraun.name@gmail.com> +# 2012 Rob Beezer +# 2013 Volker Braun <vbraun.name@gmail.com> +# 2018 Sebastian Oehms +# 2018 Travis Scrimshaw +# 2019 Jeroen Demeyer +# 2023 Matthias Koeppe # # 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 @@ -50,34 +56,31 @@ # **************************************************************************** from sage.rings.finite_rings.finite_field_constructor import GF -from sage.rings.finite_rings.finite_field_base import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.misc.latex import latex from sage.misc.cachefunc import cached_method from sage.groups.matrix_gps.named_group import ( normalize_args_vectorspace, normalize_args_invariant_form, - NamedMatrixGroup_generic, NamedMatrixGroup_gap ) -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + NamedMatrixGroup_generic) def finite_field_sqrt(ring): """ Helper function. - INPUT: - - A ring. + INPUT: A ring. OUTPUT: - Integer q such that ``ring`` is the finite field with `q^2` elements. + Integer `q` such that ``ring`` is the finite field with `q^2` elements. EXAMPLES:: sage: from sage.groups.matrix_gps.unitary import finite_field_sqrt - sage: finite_field_sqrt(GF(4, 'a')) + sage: finite_field_sqrt(GF(4, 'a')) # needs sage.rings.finite_rings 2 """ - if not is_FiniteField(ring): + if not isinstance(ring, FiniteField): raise ValueError('not a finite field') q, rem = ring.cardinality().sqrtrem() if rem: @@ -97,7 +100,7 @@ def _UG(n, R, special, var='a', invariant_form=None): TESTS:: - sage: GU(3,25).order() # indirect doctest + sage: GU(3,25).order() # indirect doctest # needs sage.rings.finite_rings 3961191000000 """ prefix = 'General' @@ -107,7 +110,7 @@ def _UG(n, R, special, var='a', invariant_form=None): latex_prefix ='S' degree, ring = normalize_args_vectorspace(n, R, var=var) - if is_FiniteField(ring): + if isinstance(ring, FiniteField): q = ring.cardinality() ring = GF(q**2, name=var) if invariant_form is not None: @@ -134,12 +137,17 @@ def _UG(n, R, special, var='a', invariant_form=None): name = '{0} Unitary Group of degree {1} over {2}'.format(prefix, degree, ring) ltx = r'\text{{{0}U}}_{{{1}}}({2})'.format(latex_prefix, degree, latex(ring)) - if is_FiniteField(ring): - cmd = '{0}U({1}, {2})'.format(latex_prefix, degree, q) - return UnitaryMatrixGroup_gap(degree, ring, special, name, ltx, cmd) - else: - return UnitaryMatrixGroup_generic(degree, ring, special, name, ltx, invariant_form=invariant_form) + if isinstance(ring, FiniteField): + try: + from .unitary_gap import UnitaryMatrixGroup_gap + except ImportError: + pass + else: + cmd = '{0}U({1}, {2})'.format(latex_prefix, degree, q) + return UnitaryMatrixGroup_gap(degree, ring, special, name, ltx, cmd) + return UnitaryMatrixGroup_generic(degree, ring, special, name, ltx, + invariant_form=invariant_form) ############################################################################### @@ -156,9 +164,9 @@ def GU(n, R, var='a', invariant_form=None): .. NOTE:: - For a finite field the matrices that preserve a sesquilinear - form over `F_q` live over `F_{q^2}`. So ``GU(n,q)`` for - a prime power ``q`` constructs the matrix group over the base + For a finite field, the matrices that preserve a sesquilinear + form over `\GF{q}` live over `\GF{q^2}`. So ``GU(n,q)`` for + a prime power `q` constructs the matrix group over the base ring ``GF(q^2)``. .. NOTE:: @@ -177,31 +185,29 @@ def GU(n, R, var='a', invariant_form=None): - ``invariant_form`` -- (optional) instances being accepted by the matrix-constructor which define a `n \times n` square matrix - over R describing the hermitian form to be kept invariant + over `R` describing the hermitian form to be kept invariant by the unitary group; the form is checked to be non-degenerate and hermitian but not to be positive definite - OUTPUT: - - Return the general unitary group. + OUTPUT: The general unitary group. EXAMPLES:: - sage: G = GU(3, 7); G + sage: G = GU(3, 7); G # needs sage.rings.finite_rings General Unitary Group of degree 3 over Finite Field in a of size 7^2 - sage: G.gens() + sage: G.gens() # needs sage.rings.finite_rings ( [ a 0 0] [6*a 6 1] [ 0 1 0] [ 6 6 0] [ 0 0 5*a], [ 1 0 0] ) - sage: GU(2,QQ) + sage: GU(2, QQ) General Unitary Group of degree 2 over Rational Field - sage: G = GU(3, 5, var='beta') - sage: G.base_ring() + sage: G = GU(3, 5, var='beta') # needs sage.rings.finite_rings + sage: G.base_ring() # needs sage.rings.finite_rings Finite Field in beta of size 5^2 - sage: G.gens() + sage: G.gens() # needs sage.rings.finite_rings ( [ beta 0 0] [4*beta 4 1] [ 0 1 0] [ 4 4 0] @@ -210,8 +216,9 @@ def GU(n, R, var='a', invariant_form=None): Using the ``invariant_form`` option:: - sage: UCF = UniversalCyclotomicField(); e5=UCF.gen(5) - sage: m = matrix(UCF, 3,3, [[1,e5,0],[e5.conjugate(),2,0],[0,0,1]]) + sage: # needs sage.libs.gap sage.rings.number_field + sage: UCF = UniversalCyclotomicField(); e5 = UCF.gen(5) + sage: m = matrix(UCF, 3, 3, [[1,e5,0], [e5.conjugate(),2,0], [0,0,1]]) sage: G = GU(3, UCF) sage: Gm = GU(3, UCF, invariant_form=m) sage: G == Gm @@ -225,12 +232,12 @@ def GU(n, R, var='a', invariant_form=None): [E(5)^4 2 0] [ 0 0 1] sage: pm = Permutation((1,2,3)).to_matrix() - sage: g = G(pm); g in G; g + sage: g = G(pm); g in G; g # needs sage.combinat True [0 0 1] [1 0 0] [0 1 0] - sage: Gm(pm) + sage: Gm(pm) # needs sage.combinat Traceback (most recent call last): ... TypeError: matrix must be unitary with respect to the hermitian form @@ -238,26 +245,25 @@ def GU(n, R, var='a', invariant_form=None): [E(5)^4 2 0] [ 0 0 1] - sage: GU(3,3, invariant_form=[[1,0,0],[0,2,0],[0,0,1]]) + sage: GU(3, 3, invariant_form=[[1,0,0], [0,2,0], [0,0,1]]) # needs sage.libs.pari Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP - sage: GU(2,QQ, invariant_form=[[1,0],[2,0]]) + sage: GU(2, QQ, invariant_form=[[1,0], [2,0]]) Traceback (most recent call last): ... ValueError: invariant_form must be non-degenerate TESTS:: - sage: TestSuite(G).run() - sage: groups.matrix.GU(2, 3) + sage: TestSuite(G).run() # needs sage.libs.gap sage.rings.number_field + sage: groups.matrix.GU(2, 3) # needs sage.groups sage.rings.finite_rings General Unitary Group of degree 2 over Finite Field in a of size 3^2 """ return _UG(n, R, False, var=var, invariant_form=invariant_form) - ############################################################################### # Special Unitary Group ############################################################################### @@ -271,8 +277,8 @@ def SU(n, R, var='a', invariant_form=None): .. NOTE:: For a finite field the matrices that preserve a sesquilinear - form over `F_q` live over `F_{q^2}`. So ``SU(n,q)`` for - a prime power ``q`` constructs the matrix group over the base + form over `\GF{q}` live over `\GF{q^2}`. So ``SU(n,q)`` for + a prime power `q` constructs the matrix group over the base ring ``GF(q^2)``. .. NOTE:: @@ -301,17 +307,18 @@ def SU(n, R, var='a', invariant_form=None): EXAMPLES:: - sage: SU(3,5) + sage: SU(3,5) # needs sage.rings.finite_rings Special Unitary Group of degree 3 over Finite Field in a of size 5^2 - sage: SU(3, GF(5)) + sage: SU(3, GF(5)) # needs sage.rings.finite_rings Special Unitary Group of degree 3 over Finite Field in a of size 5^2 - sage: SU(3,QQ) + sage: SU(3, QQ) Special Unitary Group of degree 3 over Rational Field Using the ``invariant_form`` option:: + sage: # needs sage.rings.number_field sage: CF3 = CyclotomicField(3); e3 = CF3.gen() - sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3.conjugate(),2,0],[0,0,1]]) + sage: m = matrix(CF3, 3, 3, [[1,e3,0], [e3.conjugate(),2,0], [0,0,1]]) sage: G = SU(3, CF3) sage: Gm = SU(3, CF3, invariant_form=m) sage: G == Gm @@ -325,11 +332,11 @@ def SU(n, R, var='a', invariant_form=None): [-zeta3 - 1 2 0] [ 0 0 1] sage: pm = Permutation((1,2,3)).to_matrix() - sage: G(pm) + sage: G(pm) # needs sage.combinat [0 0 1] [1 0 0] [0 1 0] - sage: Gm(pm) + sage: Gm(pm) # needs sage.combinat Traceback (most recent call last): ... TypeError: matrix must be unitary with respect to the hermitian form @@ -337,21 +344,20 @@ def SU(n, R, var='a', invariant_form=None): [-zeta3 - 1 2 0] [ 0 0 1] - sage: SU(3,5, invariant_form=[[1,0,0],[0,2,0],[0,0,3]]) + sage: SU(3, 5, invariant_form=[[1,0,0], [0,2,0], [0,0,3]]) # needs sage.rings.finite_rings Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP TESTS:: - sage: TestSuite(Gm).run() - sage: groups.matrix.SU(2, 3) + sage: TestSuite(Gm).run() # needs sage.rings.number_field + sage: groups.matrix.SU(2, 3) # needs sage.modules sage.rings.finite_rings Special Unitary Group of degree 2 over Finite Field in a of size 3^2 """ return _UG(n, R, True, var=var, invariant_form=invariant_form) - ######################################################################## # Unitary Group class ######################################################################## @@ -362,18 +368,19 @@ class UnitaryMatrixGroup_generic(NamedMatrixGroup_generic): EXAMPLES:: - sage: G = GU(3, GF(7)); G + sage: G = GU(3, GF(7)); G # needs sage.rings.finite_rings General Unitary Group of degree 3 over Finite Field in a of size 7^2 - sage: latex(G) + sage: latex(G) # needs sage.rings.finite_rings \text{GU}_{3}(\Bold{F}_{7^{2}}) - sage: G = SU(3, GF(5)); G + sage: G = SU(3, GF(5)); G # needs sage.rings.finite_rings Special Unitary Group of degree 3 over Finite Field in a of size 5^2 - sage: latex(G) + sage: latex(G) # needs sage.rings.finite_rings \text{SU}_{3}(\Bold{F}_{5^{2}}) + sage: # needs sage.rings.number_field sage: CF3 = CyclotomicField(3); e3 = CF3.gen() - sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3.conjugate(),2,0],[0,0,1]]) + sage: m = matrix(CF3, 3, 3, [[1,e3,0], [e3.conjugate(),2,0], [0,0,1]]) sage: G = SU(3, CF3, invariant_form=m) sage: latex(G) \text{SU}_{3}(\Bold{Q}(\zeta_{3}))\text{ with respect to positive definite hermitian form }\left(\begin{array}{rrr} @@ -389,13 +396,11 @@ def invariant_form(self): Return the hermitian form preserved by the unitary group. - OUTPUT: - - A square matrix describing the bilinear form + OUTPUT: A square matrix describing the bilinear form EXAMPLES:: - sage: SU4 = SU(4,QQ) + sage: SU4 = SU(4, QQ) sage: SU4.invariant_form() [1 0 0 0] [0 1 0 0] @@ -410,7 +415,6 @@ def invariant_form(self): m.set_immutable() return m - def _check_matrix(self, x, *args): """ Check whether the matrix ``x`` is unitary. @@ -420,6 +424,7 @@ def _check_matrix(self, x, *args): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: G = GU(2, GF(5)) sage: G._check_matrix(G.an_element().matrix()) sage: G = SU(2, GF(5)) @@ -434,43 +439,3 @@ def _check_matrix(self, x, *args): raise TypeError('matrix must be unitary') else: raise TypeError('matrix must be unitary with respect to the hermitian form\n{}'.format(H)) - -class UnitaryMatrixGroup_gap(UnitaryMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): - r""" - The general or special unitary group in GAP. - - TESTS: - - Check that :trac:`20867` is fixed:: - - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap - sage: G = GU(3,3) - sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) - True - """ - - @cached_method - def invariant_form(self): - """ - Return the hermitian form preserved by the unitary group. - - OUTPUT: - - A square matrix describing the bilinear form - - EXAMPLES:: - - sage: G32=GU(3,2) - sage: G32.invariant_form() - [0 0 1] - [0 1 0] - [1 0 0] - """ - d = self.degree() - R = self.base_ring() - # note that self.gap().InvariantSesquilinearForm()['matrix'].matrix().base_ring() != R for example for self = GU(3.2) - # therefore we have to coerce into the right matrix space - from sage.matrix.constructor import matrix - m = matrix(R, d, d, self.gap().InvariantSesquilinearForm()['matrix'].matrix()) - m.set_immutable() - return m diff --git a/src/sage/groups/matrix_gps/unitary_gap.py b/src/sage/groups/matrix_gps/unitary_gap.py new file mode 100644 index 00000000000..0aa547f32e2 --- /dev/null +++ b/src/sage/groups/matrix_gps/unitary_gap.py @@ -0,0 +1,63 @@ +# sage.doctest: needs sage.rings.finite_rings +r""" +Unitary Groups `GU(n,q)` and `SU(n,q)` with GAP +""" + +# **************************************************************************** +# Copyright (C) 2006 David Joyner and William Stein +# 2018 Sebastian Oehms +# 2018 Travis Scrimshaw +# 2023 Matthias Koeppe +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap +from sage.groups.matrix_gps.unitary import UnitaryMatrixGroup_generic +from sage.misc.cachefunc import cached_method + + +class UnitaryMatrixGroup_gap(UnitaryMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): + r""" + The general or special unitary group in GAP. + + TESTS: + + Check that :trac:`20867` is fixed:: + + sage: from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap + sage: G = GU(3,3) + sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) + True + """ + + @cached_method + def invariant_form(self): + """ + Return the hermitian form preserved by the unitary group. + + OUTPUT: + + A square matrix describing the bilinear form + + EXAMPLES:: + + sage: G32 = GU(3,2) + sage: G32.invariant_form() + [0 0 1] + [0 1 0] + [1 0 0] + """ + d = self.degree() + R = self.base_ring() + # note that self.gap().InvariantSesquilinearForm()['matrix'].matrix().base_ring() != R for example for self = GU(3.2) + # therefore we have to coerce into the right matrix space + from sage.matrix.constructor import matrix + m = matrix(R, d, d, self.gap().InvariantSesquilinearForm()['matrix'].matrix()) + m.set_immutable() + return m diff --git a/src/sage/groups/misc_gps/__init__.py b/src/sage/groups/misc_gps/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/combinat/designs/__init__.py b/src/sage/groups/misc_gps/all.py similarity index 100% rename from src/sage/combinat/designs/__init__.py rename to src/sage/groups/misc_gps/all.py diff --git a/src/sage/groups/misc_gps/argument_groups.py b/src/sage/groups/misc_gps/argument_groups.py index 9fa0fe07974..1c949a57f51 100644 --- a/src/sage/groups/misc_gps/argument_groups.py +++ b/src/sage/groups/misc_gps/argument_groups.py @@ -191,13 +191,13 @@ def _eq_(self, other): sage: from sage.groups.misc_gps.argument_groups import ArgumentByElementGroup sage: C = ArgumentByElementGroup(CC) - sage: C(I) == C(I) + sage: C(I) == C(I) # needs sage.symbolic True As we do not have normalization in :class:`ArgumentByElement`, then following, although equal, is not equal:: - sage: C(I) == C(2*I) + sage: C(I) == C(2*I) # needs sage.symbolic False """ return self._element_ == other._element_ @@ -256,12 +256,12 @@ def _act_on_(self, other, is_left): :: sage: from sage.groups.misc_gps.argument_groups import ArgumentByElementGroup - sage: C = ArgumentByElementGroup(SR) - sage: C(-1) * 4 + sage: C = ArgumentByElementGroup(SR) # needs sage.symbolic + sage: C(-1) * 4 # needs sage.symbolic -4 sage: _.parent() Symbolic Ring - sage: 4 * C(-1) + sage: 4 * C(-1) # needs sage.symbolic -4 sage: _.parent() Symbolic Ring @@ -704,10 +704,10 @@ def _element_constructor_(self, data, exponent=None, **kwds): sage: U(exponent=1/3) zeta3 - sage: C.<z> = CyclotomicField(6) - sage: z, U(z) + sage: C.<z> = CyclotomicField(6) # needs sage.rings.number_field + sage: z, U(z) # needs sage.rings.number_field (z, zeta6) - sage: z^2, U(z^2) + sage: z^2, U(z^2) # needs sage.rings.number_field (z - 1, zeta3) sage: U(ZZ(-1)) @@ -805,12 +805,12 @@ def _create_element_in_extension_(self, exponent): sage: from sage.groups.misc_gps.argument_groups import UnitCircleGroup, RootsOfUnityGroup sage: C = UnitCircleGroup(QQ) - sage: C._create_element_in_extension_(2.12).parent() + sage: C._create_element_in_extension_(2.12).parent() # needs sage.rings.number_field Unit Circle Group with Exponents in Real Field with 53 bits of precision modulo ZZ sage: U = RootsOfUnityGroup() - sage: U._create_element_in_extension_(2.12).parent() + sage: U._create_element_in_extension_(2.12).parent() # needs sage.rings.number_field Unit Circle Group with Exponents in Real Field with 53 bits of precision modulo ZZ """ @@ -1070,7 +1070,7 @@ def __init__(self, parent, element, normalize=True): sage: from sage.groups.misc_gps.argument_groups import ArgumentByElementGroup sage: C = ArgumentByElementGroup(CC) - sage: C(1+2*I) # indirect doctest + sage: C(1+2*I) # indirect doctest # needs sage.symbolic e^(I*arg(1.00000000000000 + 2.00000000000000*I)) """ super().__init__(parent, element, normalize=normalize) @@ -1108,7 +1108,7 @@ def _repr_(self): sage: from sage.groups.misc_gps.argument_groups import ArgumentByElementGroup sage: C = ArgumentByElementGroup(CC) - sage: C(2+3*I) # indirect doctest + sage: C(2+3*I) # indirect doctest # needs sage.symbolic e^(I*arg(2.00000000000000 + 3.00000000000000*I)) """ return 'e^(I*arg({}))'.format(self._element_) @@ -1131,7 +1131,7 @@ def _symbolic_(self, R=None): sage: from sage.groups.misc_gps.argument_groups import ArgumentByElementGroup sage: C = ArgumentByElementGroup(ZZ) - sage: C(-2)._symbolic_() + sage: C(-2)._symbolic_() # needs sage.symbolic -1 sage: _.parent() Symbolic Ring @@ -1153,7 +1153,7 @@ def _mul_(self, other): sage: from sage.groups.misc_gps.argument_groups import ArgumentByElementGroup sage: C = ArgumentByElementGroup(CC) - sage: C(I) * C(1 + I) # indirect doctest + sage: C(I) * C(1 + I) # indirect doctest # needs sage.symbolic e^(I*arg(-1.00000000000000 + 1.00000000000000*I)) """ P = self.parent() @@ -1168,12 +1168,12 @@ def __pow__(self, exponent): sage: from sage.groups.misc_gps.argument_groups import ArgumentByElementGroup sage: C = ArgumentByElementGroup(CC) - sage: C(I)^5 # indirect doctest + sage: C(I)^5 # indirect doctest # needs sage.symbolic e^(I*arg(1.00000000000000*I)) sage: _.parent() Unit Circle Group with Argument of Elements in Complex Field with 53 bits of precision - sage: C(1+I)^3 # indirect doctest + sage: C(1+I)^3 # indirect doctest # needs sage.symbolic e^(I*arg(-2.00000000000000 + 2.00000000000000*I)) sage: _.parent() Unit Circle Group with Argument of Elements in @@ -1192,7 +1192,7 @@ def __pow__(self, exponent): sage: a.parent() Symbolic Ring """ - from sage.symbolic.ring import SymbolicRing + from sage.rings.abc import SymbolicRing element = self._element_ ** exponent parent = element.parent() @@ -1208,7 +1208,7 @@ def __invert__(self): sage: from sage.groups.misc_gps.argument_groups import ArgumentByElementGroup sage: C = ArgumentByElementGroup(CC) - sage: ~C(I) # indirect doctest + sage: ~C(I) # indirect doctest # needs sage.symbolic e^(I*arg(-1.00000000000000*I)) """ P = self.parent() @@ -1233,7 +1233,7 @@ class ArgumentByElementGroup(AbstractArgumentGroup): sage: C = ArgumentByElementGroup(CC); C Unit Circle Group with Argument of Elements in Complex Field with 53 bits of precision - sage: C(1 + 2*I) + sage: C(1 + 2*I) # needs sage.symbolic e^(I*arg(1.00000000000000 + 2.00000000000000*I)) """ @@ -1283,7 +1283,7 @@ def _element_constructor_(self, data, **kwds): sage: from sage.groups.misc_gps.argument_groups import ArgumentByElementGroup sage: C = ArgumentByElementGroup(CC) - sage: C(1 + 2*I) # indirect doctest + sage: C(1 + 2*I) # indirect doctest # needs sage.symbolic e^(I*arg(1.00000000000000 + 2.00000000000000*I)) sage: C(1) e^(I*arg(1.00000000000000)) @@ -1545,7 +1545,7 @@ def _act_on_(self, other, is_left): -4.00000000000000 sage: _.parent() Complex Field with 53 bits of precision - sage: S(-1) * SR.var('x') + sage: S(-1) * SR.var('x') # needs sage.symbolic -x sage: _.parent() Symbolic Ring @@ -1760,9 +1760,10 @@ class ArgumentGroupFactory(UniqueFactory): sage: from sage.groups.misc_gps.argument_groups import ArgumentGroup - sage: ArgumentGroup('UU') + sage: ArgumentGroup('UU') # needs sage.rings.number_field Group of Roots of Unity + sage: # needs sage.rings.number_field sage: ArgumentGroup(ZZ) Sign Group sage: ArgumentGroup(QQ) @@ -1772,19 +1773,19 @@ class ArgumentGroupFactory(UniqueFactory): sage: ArgumentGroup(AA) Sign Group - sage: ArgumentGroup(RR) + sage: ArgumentGroup(RR) # needs sage.rings.number_field Sign Group - sage: ArgumentGroup('Arg_RR') + sage: ArgumentGroup('Arg_RR') # needs sage.rings.number_field Sign Group - sage: ArgumentGroup(RIF) + sage: ArgumentGroup(RIF) # needs sage.rings.real_interval_field Sign Group sage: ArgumentGroup(RBF) Sign Group - sage: ArgumentGroup(CC) + sage: ArgumentGroup(CC) # needs sage.rings.number_field Unit Circle Group with Exponents in Real Field with 53 bits of precision modulo ZZ - sage: ArgumentGroup('Arg_CC') + sage: ArgumentGroup('Arg_CC') # needs sage.rings.number_field Unit Circle Group with Exponents in Real Field with 53 bits of precision modulo ZZ sage: ArgumentGroup(CIF) @@ -1794,7 +1795,7 @@ class ArgumentGroupFactory(UniqueFactory): Unit Circle Group with Exponents in Real ball field with 53 bits of precision modulo ZZ - sage: ArgumentGroup(CyclotomicField(3)) + sage: ArgumentGroup(CyclotomicField(3)) # needs sage.rings.number_field Unit Circle Group with Argument of Elements in Cyclotomic Field of order 3 and degree 2 """ @@ -1813,6 +1814,7 @@ def create_key_and_extra_args(self, sage: from sage.groups.misc_gps.argument_groups import ArgumentGroup + sage: # needs sage.rings.number_field sage: ArgumentGroup(specification='UU') Group of Roots of Unity sage: ArgumentGroup('UU') is ArgumentGroup(exponents=QQ) # indirect doctest @@ -1887,7 +1889,7 @@ def create_object(self, version, key, **kwds): TESTS:: sage: from sage.groups.misc_gps.argument_groups import ArgumentGroup - sage: ArgumentGroup('UU') # indirect doctest + sage: ArgumentGroup('UU') # indirect doctest # needs sage.rings.number_field Group of Roots of Unity """ cls, args = key diff --git a/src/sage/groups/misc_gps/imaginary_groups.py b/src/sage/groups/misc_gps/imaginary_groups.py index ff2d34ddade..41fe79f9959 100644 --- a/src/sage/groups/misc_gps/imaginary_groups.py +++ b/src/sage/groups/misc_gps/imaginary_groups.py @@ -81,9 +81,9 @@ def imag(self): sage: from sage.groups.misc_gps.imaginary_groups import ImaginaryGroup sage: J = ImaginaryGroup(ZZ) - sage: J(I).imag() + sage: J(I).imag() # needs sage.symbolic 1 - sage: imag_part(J(I)) # indirect doctest + sage: imag_part(J(I)) # indirect doctest # needs sage.symbolic 1 """ return self._imag_ @@ -96,9 +96,9 @@ def real(self): sage: from sage.groups.misc_gps.imaginary_groups import ImaginaryGroup sage: J = ImaginaryGroup(ZZ) - sage: J(I).real() + sage: J(I).real() # needs sage.symbolic 0 - sage: real_part(J(I)) # indirect doctest + sage: real_part(J(I)) # indirect doctest # needs sage.symbolic 0 """ return self.parent().base().zero() @@ -111,7 +111,7 @@ def __hash__(self): sage: from sage.groups.misc_gps.imaginary_groups import ImaginaryGroup sage: J = ImaginaryGroup(ZZ) - sage: hash(J(I)) # indirect doctest, random + sage: hash(J(I)) # indirect doctest, random # needs sage.symbolic 42 """ return hash((self.parent(), self._imag_)) @@ -247,9 +247,9 @@ class ImaginaryGroup(UniqueRepresentation, Parent): 0 sage: J(imag=100) 100*I - sage: J(3*I) + sage: J(3*I) # needs sage.symbolic 3*I - sage: J(1+2*I) + sage: J(1 + 2*I) # needs sage.symbolic Traceback (most recent call last): ... ValueError: 2*I + 1 is not in @@ -393,6 +393,7 @@ def _element_constructor_(self, data, imag=None): sage: J(imag=100) 100*I + sage: # needs sage.symbolic sage: J(3*I) 3*I sage: J(1+2*I) diff --git a/src/sage/groups/old.pyx b/src/sage/groups/old.pyx index c17082f59cb..761034cff65 100644 --- a/src/sage/groups/old.pyx +++ b/src/sage/groups/old.pyx @@ -20,9 +20,6 @@ Base class for groups doc=""" Base class for all groups """ - -import random - from sage.rings.infinity import infinity import sage.rings.integer_ring @@ -50,6 +47,7 @@ cdef class Group(sage.structure.parent.Parent): Check for :trac:`8119`:: + sage: # needs sage.groups sage: G = SymmetricGroup(2) sage: h = hash(G) sage: G.rename('S2') @@ -123,7 +121,7 @@ cdef class Group(sage.structure.parent.Parent): EXAMPLES:: - sage: SL(2, 7).is_commutative() + sage: SL(2, 7).is_commutative() # needs sage.libs.gap sage.modules False """ return self.is_abelian() diff --git a/src/sage/groups/pari_group.py b/src/sage/groups/pari_group.py index c54cd4885df..bbcb1c0a6c9 100644 --- a/src/sage/groups/pari_group.py +++ b/src/sage/groups/pari_group.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari r""" PARI Groups diff --git a/src/sage/groups/perm_gps/__init__.py b/src/sage/groups/perm_gps/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/groups/perm_gps/all.py b/src/sage/groups/perm_gps/all.py index 83afad7c691..ae405f298a2 100644 --- a/src/sage/groups/perm_gps/all.py +++ b/src/sage/groups/perm_gps/all.py @@ -6,7 +6,7 @@ MathieuGroup, KleinFourGroup, QuaternionGroup, PrimitiveGroup, PrimitiveGroups, SuzukiGroup, TransitiveGroups, - GeneralDihedralGroup) + GeneralDihedralGroup, SmallPermutationGroup) from .permgroup import PermutationGroup, PermutationGroup_generic, PermutationGroup_subgroup, direct_product_permgroups diff --git a/src/sage/groups/perm_gps/constructor.py b/src/sage/groups/perm_gps/constructor.py index 73dc5f94c41..5a130eb19be 100644 --- a/src/sage/groups/perm_gps/constructor.py +++ b/src/sage/groups/perm_gps/constructor.py @@ -23,10 +23,15 @@ from sage.misc.sage_eval import sage_eval from sage.misc.lazy_import import lazy_import from sage.interfaces.gap import GapElement -from sage.libs.pari.all import pari_gen from sage.libs.gap.element import GapElement_Permutation + lazy_import('sage.combinat.permutation', ['Permutation', 'from_cycles']) +try: + from sage.libs.pari.all import pari_gen +except ImportError: + pari_gen = () + def PermutationGroupElement(g, parent=None, check=True): r""" @@ -156,8 +161,8 @@ def standardize_generator(g, convert_dict=None, as_cycles=False): INPUT: - - ``g`` -- a list, tuple, string, GapElement, - PermutationGroupElement, Permutation + - ``g`` -- a :class:`list`, :class:`tuple`, :class:`string`, :class:`GapElement`, + :class:`PermutationGroupElement`, or :class:`Permutation` - ``convert_dict`` -- (optional) a dictionary used to convert the points to a number compatible with GAP diff --git a/src/sage/groups/perm_gps/cubegroup.py b/src/sage/groups/perm_gps/cubegroup.py index 921c6201c43..128d3beb480 100644 --- a/src/sage/groups/perm_gps/cubegroup.py +++ b/src/sage/groups/perm_gps/cubegroup.py @@ -191,7 +191,8 @@ def polygon_plot3d(points, tilt=30, turn=30, **kwargs): EXAMPLES:: sage: from sage.groups.perm_gps.cubegroup import polygon_plot3d,green - sage: P = polygon_plot3d([[1,3,1],[2,3,1],[2,3,2],[1,3,2],[1,3,1]],rgbcolor=green) + sage: P = polygon_plot3d([[1,3,1],[2,3,1],[2,3,2],[1,3,2],[1,3,1]], # needs sage.plot + ....: rgbcolor=green) """ rot = rotation_list(tilt, turn) points2 = [(xproj(x, y, z, rot), yproj(x, y, z, rot)) @@ -288,13 +289,14 @@ def create_poly(face, color): EXAMPLES:: sage: from sage.groups.perm_gps.cubegroup import create_poly, red - sage: create_poly('ur', red) + sage: create_poly('ur', red) # needs sage.plot Graphics object consisting of 1 graphics primitive """ return polygon(face_polys[face], rgbcolor=color) #################################################### + singmaster_indices = { 1: "ulb", 2: "ub", @@ -431,21 +433,21 @@ def cubie_colors(label, state0): clr_any = named_colors['white'] state = inv_list(state0) if label == 1: - return [clr_any, named_colors[color_of_square(state[1-1])], clr_any] #ulb, + return [clr_any, named_colors[color_of_square(state[1-1])], clr_any] #ulb, if label == 2: - return [clr_any,named_colors[color_of_square(state[2-1])],clr_any] # ub, + return [clr_any,named_colors[color_of_square(state[2-1])],clr_any] # ub, if label == 3: - return [clr_any, named_colors[color_of_square(state[3-1])], named_colors[color_of_square(state[27-1])]] # ubr, + return [clr_any, named_colors[color_of_square(state[3-1])], named_colors[color_of_square(state[27-1])]] # ubr, if label == 4: - return [clr_any, named_colors[color_of_square(state[4-1])], clr_any] # ul, + return [clr_any, named_colors[color_of_square(state[4-1])], clr_any] # ul, if label == 5: - return [clr_any, named_colors[color_of_square(state[5-1])], named_colors[color_of_square(state[26-1])]] # ur, + return [clr_any, named_colors[color_of_square(state[5-1])], named_colors[color_of_square(state[26-1])]] # ur, if label == 6: - return [named_colors[color_of_square(state[17-1])], named_colors[color_of_square(state[6-1])], clr_any] # ufl, + return [named_colors[color_of_square(state[17-1])], named_colors[color_of_square(state[6-1])], clr_any] # ufl, if label == 7: - return [named_colors[color_of_square(state[18-1])], named_colors[color_of_square(state[7-1])], clr_any] # uf, + return [named_colors[color_of_square(state[18-1])], named_colors[color_of_square(state[7-1])], clr_any] # uf, if label == 8: - return [named_colors[color_of_square(state[19-1])], named_colors[color_of_square(state[8-1])], named_colors[color_of_square(state[25-1])]] # urf, + return [named_colors[color_of_square(state[19-1])], named_colors[color_of_square(state[8-1])], named_colors[color_of_square(state[25-1])]] # urf, if label == 17: return [named_colors[color_of_square(state[17-1])], named_colors[color_of_square(state[6-1])], clr_any] # flu if label == 18: @@ -491,7 +493,7 @@ def plot3d_cubie(cnt, clrs): sage: from sage.groups.perm_gps.cubegroup import plot3d_cubie, blue, red, green sage: clrF = blue; clrU = red; clrR = green - sage: P = plot3d_cubie([1/2,1/2,1/2],[clrF,clrU,clrR]) + sage: P = plot3d_cubie([1/2,1/2,1/2],[clrF,clrU,clrR]) # needs sage.plot """ half = QQ((1, 2)) x = cnt[0] - half @@ -929,15 +931,15 @@ def repr2d(self, mv): """ g = self.parse(mv) lst = self.facets(g) - line1 = " +--------------+\n" - line2 = " |%3d %3d %3d |\n"%(lst[0],lst[1],lst[2]) - line3 = " |%3d top %3d |\n"%(lst[3],lst[4]) - line4 = " |%3d %3d %3d |\n"%(lst[5],lst[6],lst[7]) - line5 = "+------------+--------------+-------------+------------+\n" - line6 = "|%3d %3d %3d |%3d %3d %3d |%3d %3d %3d |%3d %3d %3d |\n"%(lst[8],lst[9],lst[10],lst[16],lst[17],lst[18],lst[24],lst[25],lst[26],lst[32],lst[33],lst[34]) - line7 = "|%3d left%3d |%3d front%3d |%3d right%3d |%3d rear%3d |\n"%(lst[11],lst[12],lst[19],lst[20],lst[27],lst[28],lst[35],lst[36]) - line8 = "|%3d %3d %3d |%3d %3d %3d |%3d %3d %3d |%3d %3d %3d |\n"%(lst[13],lst[14],lst[15],lst[21],lst[22],lst[23],lst[29],lst[30],lst[31],lst[37],lst[38],lst[39]) - line9 = "+------------+--------------+-------------+------------+\n" + line1 = " +--------------+\n" + line2 = " |%3d %3d %3d |\n"%(lst[0],lst[1],lst[2]) + line3 = " |%3d top %3d |\n"%(lst[3],lst[4]) + line4 = " |%3d %3d %3d |\n"%(lst[5],lst[6],lst[7]) + line5 = "+------------+--------------+-------------+------------+\n" + line6 = "|%3d %3d %3d |%3d %3d %3d |%3d %3d %3d |%3d %3d %3d |\n"%(lst[8],lst[9],lst[10],lst[16],lst[17],lst[18],lst[24],lst[25],lst[26],lst[32],lst[33],lst[34]) + line7 = "|%3d left%3d |%3d front%3d |%3d right%3d |%3d rear%3d |\n"%(lst[11],lst[12],lst[19],lst[20],lst[27],lst[28],lst[35],lst[36]) + line8 = "|%3d %3d %3d |%3d %3d %3d |%3d %3d %3d |%3d %3d %3d |\n"%(lst[13],lst[14],lst[15],lst[21],lst[22],lst[23],lst[29],lst[30],lst[31],lst[37],lst[38],lst[39]) + line9 = "+------------+--------------+-------------+------------+\n" line10 = " |%3d %3d %3d |\n"%(lst[40],lst[41],lst[42]) line11 = " |%3d bottom%3d |\n"%(lst[43],lst[44]) line12 = " |%3d %3d %3d |\n"%(lst[45],lst[46],lst[47]) @@ -954,11 +956,11 @@ def plot_cube(self, mv, title=True, colors=[lpurple, yellow, red, green, orange, EXAMPLES:: sage: rubik = CubeGroup() - sage: P = rubik.plot_cube("R^2*U^2*R^2*U^2*R^2*U^2", title = False) + sage: P = rubik.plot_cube("R^2*U^2*R^2*U^2*R^2*U^2", title=False) # needs sage.plot sage: # (R^2U^2)^3 permutes 2 pairs of edges (uf,ub)(fr,br) - sage: P = rubik.plot_cube("R*L*D^2*B^3*L^2*F^2*R^2*U^3*D*R^3*D^2*F^3*B^3*D^3*F^2*D^3*R^2*U^3*F^2*D^3") + sage: P = rubik.plot_cube("R*L*D^2*B^3*L^2*F^2*R^2*U^3*D*R^3*D^2*F^3*B^3*D^3*F^2*D^3*R^2*U^3*F^2*D^3") # needs sage.plot sage: # the superflip (in 20f* moves) - sage: P = rubik.plot_cube("U^2*F*U^2*L*R^(-1)*F^2*U*F^3*B^3*R*L*U^2*R*D^3*U*L^3*R*D*R^3*L^3*D^2") + sage: P = rubik.plot_cube("U^2*F*U^2*L*R^(-1)*F^2*U*F^3*B^3*R*L*U^2*R*D^3*U*L^3*R*D*R^3*L^3*D^2") # needs sage.plot sage: # "superflip+4 spot" (in 26q* moves) """ g = self.parse(mv) @@ -991,8 +993,8 @@ def plot3d_cube(self, mv, title=True): EXAMPLES:: sage: rubik = CubeGroup() - sage: P = rubik.plot3d_cube("U^2*F*U^2*L*R^(-1)*F^2*U*F^3*B^3*R*L*U^2*R*D^3*U*L^3*R*D*R^3*L^3*D^2") - sage: P = rubik.plot3d_cube("R*L*D^2*B^3*L^2*F^2*R^2*U^3*D*R^3*D^2*F^3*B^3*D^3*F^2*D^3*R^2*U^3*F^2*D^3") + sage: P = rubik.plot3d_cube("U^2*F*U^2*L*R^(-1)*F^2*U*F^3*B^3*R*L*U^2*R*D^3*U*L^3*R*D*R^3*L^3*D^2") # needs sage.plot + sage: P = rubik.plot3d_cube("R*L*D^2*B^3*L^2*F^2*R^2*U^3*D*R^3*D^2*F^3*B^3*D^3*F^2*D^3*R^2*U^3*F^2*D^3") # needs sage.plot """ g = self.parse(mv) state = self.facets(g) @@ -1002,9 +1004,9 @@ def plot3d_cube(self, mv, title=True): cubeU = sum(cubiesU) cubiesF = [plot3d_cubie(cubie_centers(c),cubie_colors(c,state)) for c in [22,23,24,20,21]] cubeF = sum(cubiesF) - centerR = polygon_plot3d([[1,3,1],[2,3,1],[2,3,2],[1,3,2],[1,3,1]],rgbcolor=green) - centerF = polygon_plot3d([[3,1,1],[3,2,1],[3,2,2],[3,1,2],[3,1,1]],rgbcolor=red) - centerU = polygon_plot3d([[1,1,3],[1,2,3],[2,2,3],[2,1,3],[1,1,3]],rgbcolor=lpurple) + centerR = polygon_plot3d([[1,3,1],[2,3,1],[2,3,2],[1,3,2],[1,3,1]],rgbcolor=green) + centerF = polygon_plot3d([[3,1,1],[3,2,1],[3,2,2],[3,1,2],[3,1,1]],rgbcolor=red) + centerU = polygon_plot3d([[1,1,3],[1,2,3],[2,2,3],[2,1,3],[1,1,3]],rgbcolor=lpurple) centers = centerF+centerR+centerU P = cubeR+cubeF+cubeU+centers P.axes(show=False) @@ -1180,6 +1182,7 @@ def cubie_faces(): return cubies + cubie_face_list = cubie_faces() @@ -1194,7 +1197,7 @@ class RubiksCube(SageObject): EXAMPLES:: sage: C = RubiksCube().move("R U R'") - sage: C.show3d() + sage: C.show3d() # needs sage.plot :: @@ -1212,7 +1215,7 @@ class RubiksCube(SageObject): | 37 bottom 21 | | 35 47 24 | +--------------+ - sage: C.show() + sage: C.show() # needs sage.plot sage: C.solve(algorithm='gap') # long time 'L*R' sage: C == RubiksCube("L*R") @@ -1315,7 +1318,7 @@ def plot(self): EXAMPLES:: sage: C = RubiksCube("R*U") - sage: C.plot() + sage: C.plot() # needs sage.plot Graphics object consisting of 55 graphics primitives """ return self._group.plot_cube(self._state) @@ -1327,7 +1330,7 @@ def show(self): EXAMPLES:: sage: C = RubiksCube("R*U") - sage: C.show() + sage: C.show() # needs sage.plot """ self.plot().show() @@ -1346,7 +1349,7 @@ def cubie(self, size, gap, x, y, z, colors, stickers=True): EXAMPLES:: sage: C = RubiksCube("R*U") - sage: C.cubie(0.15, 0.025, 0,0,0, C.colors*3) + sage: C.cubie(0.15, 0.025, 0,0,0, C.colors*3) # needs sage.plot Graphics3d Object """ sides = cubie_face_list[x,y,z] @@ -1366,7 +1369,7 @@ def plot3d(self, stickers=True): EXAMPLES:: sage: C = RubiksCube("R*U") - sage: C.plot3d() + sage: C.plot3d() # needs sage.plot Graphics3d Object """ while len(self.colors) < 7: @@ -1389,7 +1392,7 @@ def show3d(self): EXAMPLES:: sage: C = RubiksCube("R*U") - sage: C.show3d() + sage: C.show3d() # needs sage.plot """ return self.plot3d().show() diff --git a/src/sage/groups/perm_gps/partn_ref/__init__.py b/src/sage/groups/perm_gps/partn_ref/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/combinat/matrices/__init__.py b/src/sage/groups/perm_gps/partn_ref/all.py similarity index 100% rename from src/sage/combinat/matrices/__init__.py rename to src/sage/groups/perm_gps/partn_ref/all.py diff --git a/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx b/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx index ad30101e161..04d978afef3 100644 --- a/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +++ b/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups r""" Automorphism groups and canonical labels @@ -116,9 +117,12 @@ from .data_structures cimport * from sage.data_structures.bitset_base cimport * cdef inline int agcl_cmp(int a, int b): - if a < b: return -1 - elif a == b: return 0 - else: return 1 + if a < b: + return -1 + elif a == b: + return 0 + else: + return 1 # Functions @@ -212,9 +216,10 @@ cdef int compare_perms(int *gamma_1, int *gamma_2, void *S1, void *S2, int degre cdef list MS1 = <list> S1 cdef list MS2 = <list> S2 cdef int i, j - for i from 0 <= i < degree: + for i in range(degree): j = agcl_cmp(MS1[gamma_1[i]], MS2[gamma_2[i]]) - if j != 0: return j + if j != 0: + return j return 0 def coset_rep(list perm=[0,1,2,3,4,5], list gens=[[1,2,3,4,5,0]]): @@ -278,8 +283,8 @@ def coset_rep(list perm=[0,1,2,3,4,5], list gens=[[1,2,3,4,5,0]]): output = get_aut_gp_and_can_lab(<void *> perm, part, n, &all_children_are_equivalent_trivial, &refine_and_return_invariant_trivial, &compare_perms, 1, group, NULL, NULL) SC_order(output.group, 0, I.value) assert I == 1 - r_inv = list(xrange(n)) - for i from 0 <= i < n: + r_inv = list(range(n)) + for i in range(n): r_inv[output.relabeling[i]] = i label = [perm[r_inv[i]] for i in range(n)] PS_dealloc(part) @@ -393,9 +398,10 @@ cdef void deallocate_agcl_work_space(agcl_work_space *work_space): cdef aut_gp_and_can_lab *get_aut_gp_and_can_lab(void *S, PartitionStack *partition, int n, bint (*all_children_are_equivalent)(PartitionStack *PS, void *S), - int (*refine_and_return_invariant)\ - (PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len), - int (*compare_structures)(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree), + int (*refine_and_return_invariant)(PartitionStack *PS, void *S, + int *cells_to_refine_by, int ctrb_len), + int (*compare_structures)(int *gamma_1, int *gamma_2, void *S1, void *S2, + int degree), bint canonical_label, StabilizerChain *input_group, agcl_work_space *work_space_prealloc, aut_gp_and_can_lab *output_prealloc) except NULL: """ @@ -479,7 +485,7 @@ cdef aut_gp_and_can_lab *get_aut_gp_and_can_lab(void *S, cdef int i, j, k, ell, b cdef bint discrete, automorphism, update_label - cdef bint backtrack, new_vertex, narrow, mem_err = 0 + cdef bint backtrack, new_vertex, mem_err = 0 cdef aut_gp_and_can_lab *output cdef agcl_work_space *work_space diff --git a/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx b/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx index ac4c40b9b34..d6cc56d585a 100644 --- a/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx +++ b/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx @@ -211,7 +211,8 @@ cdef void *canonical_generator_next(void *can_gen_data, int *degree, bint *mem_e aug, cgd.object_stack[cgd.level], &cgd.degree_stack[cgd.level], &cgd.mem_err) cgd.object_stack[cgd.level] = next_candidate - if cgd.mem_err: continue + if cgd.mem_err: + continue next_cand_deg = cgd.degree_stack[cgd.level] if cgd.agcl_work_spaces[cgd.level] is NULL: # allocate a work space if it hasn't been allocated already @@ -380,11 +381,13 @@ cdef void deallocate_cgd(canonical_generator_data *cgd): sig_free(cgd.parent_stack) sig_free(cgd) + cdef iterator *setup_canonical_generator(int degree, bint (*all_children_are_equivalent)(PartitionStack *PS, void *S), - int (*refine_and_return_invariant)\ - (PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len), - int (*compare_structures)(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree), + int (*refine_and_return_invariant)(PartitionStack *PS, void *S, + int *cells_to_refine_by, int ctrb_len), + int (*compare_structures)(int *gamma_1, int *gamma_2, void *S1, void *S2, + int degree), int (*generate_children)(void *, aut_gp_and_can_lab *, iterator *), void *(*apply_augmentation)(void *, void *, void *, int *, bint *), void (*free_object)(void *), diff --git a/src/sage/groups/perm_gps/partn_ref/data_structures.pxd b/src/sage/groups/perm_gps/partn_ref/data_structures.pxd index b469d09c2b5..8c5ae14b5bb 100644 --- a/src/sage/groups/perm_gps/partn_ref/data_structures.pxd +++ b/src/sage/groups/perm_gps/partn_ref/data_structures.pxd @@ -13,7 +13,6 @@ from sage.data_structures.bitset_base cimport * from libc.string cimport memcpy from libc.stdlib cimport rand from sage.libs.gmp.mpz cimport * -from sage.groups.perm_gps.partn_ref2.refinement_generic cimport PartitionRefinement_generic cdef enum: @@ -260,8 +259,7 @@ cdef PS_print(PartitionStack *PS) cdef void PS_unit_partition(PartitionStack *PS) -cdef int PS_first_smallest(PartitionStack *PS, bitset_t b, int *second_pos=?, - PartitionRefinement_generic partn_ref_alg=?) +cdef int PS_first_smallest(PartitionStack *PS, bitset_t b, int *second_pos=?) cdef PartitionStack *PS_from_list(list L) diff --git a/src/sage/groups/perm_gps/partn_ref/data_structures.pyx b/src/sage/groups/perm_gps/partn_ref/data_structures.pyx index 74065fe1fec..c3b87a3bc1f 100644 --- a/src/sage/groups/perm_gps/partn_ref/data_structures.pyx +++ b/src/sage/groups/perm_gps/partn_ref/data_structures.pyx @@ -23,7 +23,7 @@ REFERENCES: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from libc.math cimport log, ceil @@ -33,7 +33,10 @@ from cysignals.memory cimport sig_malloc, sig_calloc, sig_realloc, sig_free from sage.data_structures.bitset_base cimport * from sage.rings.integer cimport Integer -from sage.libs.flint.ulong_extras cimport n_is_prime +# from sage.libs.flint.ulong_extras cimport n_is_prime +# -- avoid modularization obstruction -- function is only used for a doctest helper +from sage.arith.misc import is_prime as n_is_prime + # OrbitPartition (OP) @@ -70,7 +73,7 @@ cdef OP_string(OrbitPartition *OP): """ cdef i,j s = "" - for i from 0 <= i < OP.degree: + for i in range(OP.degree): s += " " j = OP_find(OP, i) s += "%d -> %d"%(i, j) @@ -130,18 +133,19 @@ def OP_represent(int n, merges, perm): print("Allocation passed.") print("Checking that each element reports itself as its root.") good = True - for i from 0 <= i < n: + for i in range(n): if not OP_find(OP, i) == i: print("Failed at i = %d!" % i) good = False - if good: print("Each element reports itself as its root.") + if good: + print("Each element reports itself as its root.") print("Merging:") for i,j in merges: OP_join(OP, i, j) print("Merged %d and %d." % (i, j)) print("Done merging.") print("Finding:") - for i from 0 <= i < n: + for i in range(n): j = OP_find(OP, i) s = "%d -> %d"%(i, j) if i == j: @@ -155,13 +159,13 @@ def OP_represent(int n, merges, perm): OP_dealloc(OP) return print("Allocation passed.") - for i from 0 <= i < n: + for i in range(n): gamma[i] = perm[i] print("Merging permutation: %s" % perm) OP_merge_list_perm(OP, gamma) print("Done merging.") print("Finding:") - for i from 0 <= i < n: + for i in range(n): j = OP_find(OP, i) s = "%d -> %d"%(i, j) if i == j: @@ -203,7 +207,7 @@ cdef void PS_unit_partition(PartitionStack *PS): """ cdef int i, n = PS.degree PS.depth = 0 - for i from 0 <= i < n-1: + for i in range(n - 1): PS.entries[i] = i PS.levels[i] = n PS.entries[n-1] = n-1 @@ -239,14 +243,14 @@ cdef PartitionStack *PS_from_list(list L): null pointer in the case of an allocation failure. """ cdef int cell, i, num_cells = len(L), cur_start = 0, cur_len, n = 0 - for cell from 0 <= cell < num_cells: + for cell in range(num_cells): n += len(L[cell]) cdef PartitionStack *PS = PS_new(n, 0) if PS is NULL: return NULL - for cell from 0 <= cell < num_cells: + for cell in range(num_cells): cur_len = len(L[cell]) - for i from 0 <= i < cur_len: + for i in range(cur_len): PS.entries[cur_start + i] = L[cell][i] PS.levels[cur_start + i] = n PS_move_min_to_front(PS, cur_start, cur_start+cur_len-1) @@ -263,7 +267,7 @@ cdef PS_print(PartitionStack *PS): Print a visual representation of PS. """ cdef int i - for i from 0 <= i <= PS.depth: + for i in range(PS.depth + 1): PS_print_partition(PS, i) cdef PS_print_partition(PartitionStack *PS, int k): @@ -271,7 +275,7 @@ cdef PS_print_partition(PartitionStack *PS, int k): Print the partition at depth k. """ s = '(' - for i from 0 <= i < PS.degree: + for i in range(PS.degree): s += str(PS.entries[i]) if PS.levels[i] <= k: s += '|' @@ -280,8 +284,7 @@ cdef PS_print_partition(PartitionStack *PS, int k): s = s[:-1] + ')' print(s) -cdef int PS_first_smallest(PartitionStack *PS, bitset_t b, int *second_pos=NULL, - PartitionRefinement_generic partn_ref_alg=None): +cdef int PS_first_smallest(PartitionStack *PS, bitset_t b, int *second_pos=NULL): """ Find the first occurrence of the smallest cell of size greater than one, which is admissible (checked by the function ``test_allowance``). @@ -289,30 +292,30 @@ cdef int PS_first_smallest(PartitionStack *PS, bitset_t b, int *second_pos=NULL, """ cdef int i = 0, j = 0, location = 0, n = PS.degree bitset_zero(b) - while 1: + while True: if PS.levels[i] <= PS.depth: - if i != j and n > i - j + 1 and (partn_ref_alg is None or - partn_ref_alg._minimization_allowed_on_col(PS.entries[j])): + if i != j and n > i - j + 1: n = i - j + 1 location = j j = i + 1 - if PS.levels[i] == -1: break + if PS.levels[i] == -1: + break i += 1 # location now points to the beginning of the first, smallest, # nontrivial cell i = location - while 1: + while True: bitset_flip(b, PS.entries[i]) - if PS.levels[i] <= PS.depth: break + if PS.levels[i] <= PS.depth: + break i += 1 if second_pos != NULL: - if n==2: - second_pos[0] = PS.entries[location+1] + if n == 2: + second_pos[0] = PS.entries[location + 1] else: second_pos[0] = -1 - return PS.entries[location] @@ -337,7 +340,7 @@ cdef int PS_all_new_cells(PartitionStack *PS, bitset_t** nonsingletons_ptr): if end != n: if PS.levels[end] == PS.depth: bitset_zero(scratch) - for i from beg <= i <= end: + for i in range(beg, end + 1): bitset_set(scratch, PS.entries[i]) count +=1 nonsingletons = <bitset_t*> sig_realloc(nonsingletons, count * sizeof(bitset_t)) @@ -365,7 +368,7 @@ cdef int PS_find_element(PartitionStack *PS, bitset_t b, int x) except -1: """ cdef int i, location, n = PS.degree bitset_zero(b) - for i from 0 <= i < n: + for i in range(n): if PS.entries[i] == x: location = i break @@ -469,7 +472,7 @@ def PS_represent(partition, splits): PS_print(PS) print("Checking that entries are in order and correct level.") good = True - for i from 0 <= i < n-1: + for i in range(n - 1): if not (PS.entries[i] == i and PS.levels[i] == n): print("Failed at i = %d!" % i) print(PS.entries[i], PS.levels[i], i, n) @@ -480,14 +483,15 @@ def PS_represent(partition, splits): if not PS.degree == n or not PS.depth == 0: print("Incorrect degree or depth!") good = False - if good: print("Everything seems in order, deallocating.") + if good: + print("Everything seems in order, deallocating.") PS_dealloc(PS) print("Deallocated.") - print("Creating PartitionStack from partition %s."%partition) + print("Creating PartitionStack from partition %s." % partition) PS = PS_from_list(partition) print("PartitionStack's data:") - print("entries -> %s"%[PS.entries[i] for i from 0 <= i < n]) - print("levels -> %s"%[PS.levels[i] for i from 0 <= i < n]) + print("entries -> %s"%[PS.entries[i] for i in range(n)]) + print("levels -> %s"%[PS.levels[i] for i in range(n)]) print("depth = %d, degree = %d" % (PS.depth,PS.degree)) PS_print(PS) print("Checking PS_is_discrete:") @@ -495,7 +499,7 @@ def PS_represent(partition, splits): print("Checking PS_num_cells:") print(PS_num_cells(PS)) print("Checking PS_is_mcr, min cell reps are:") - L = [PS.entries[i] for i from 0 <= i < n if PS_is_mcr(PS, i)] + L = [PS.entries[i] for i in range(n) if PS_is_mcr(PS, i)] print(L) print("Checking PS_is_fixed, fixed elements are:") print([PS.entries[l] for l in L if PS_is_fixed(PS, l)]) @@ -504,7 +508,7 @@ def PS_represent(partition, splits): PS_print(PS2) print("Checking for consistency.") good = True - for i from 0 <= i < n: + for i in range(n): if PS.entries[i] != PS2.entries[i] or PS.levels[i] != PS2.levels[i]: print("Failed at i = %d!"%i) good = False @@ -523,7 +527,7 @@ def PS_represent(partition, splits): print("Getting permutation from PS2->PS:") gamma = <int *> sig_malloc(n * sizeof(int)) PS_get_perm_from(PS, PS2, gamma) - print([gamma[i] for i from 0 <= i < n]) + print([gamma[i] for i in range(n)]) sig_free(gamma) print("Finding first smallest:") bitset_init(b, n) @@ -605,7 +609,7 @@ cdef StabilizerChain *SC_new(int n, bint init_gens=True): SC.base_orbits = int_ptrs + 2*n SC.parents = int_ptrs + 3*n SC.labels = int_ptrs + 4*n - for i from 0 <= i < n: + for i in range(n): SC.base_orbits[i] = int_array SC.parents[i] = int_array + n SC.labels[i] = int_array + 2*n @@ -613,7 +617,7 @@ cdef StabilizerChain *SC_new(int n, bint init_gens=True): # second level allocations if init_gens: - for i from 0 <= i < n: + for i in range(n): SC.array_size[i] = default_num_gens SC.generators[i] = <int *> sig_malloc( default_num_gens*n * sizeof(int) ) SC.gen_inverses[i] = <int *> sig_malloc( default_num_gens*n * sizeof(int) ) @@ -633,11 +637,13 @@ cdef inline int SC_realloc_gens(StabilizerChain *SC, int level, int size): cdef int n = SC.degree temp = <int *> sig_realloc( SC.generators[level], n * size * sizeof(int) ) - if temp is NULL: return 1 + if temp is NULL: + return 1 SC.generators[level] = temp temp = <int *> sig_realloc( SC.gen_inverses[level], n * size * sizeof(int) ) - if temp is NULL: return 1 + if temp is NULL: + return 1 SC.gen_inverses[level] = temp SC.array_size[level] = size @@ -648,7 +654,7 @@ cdef inline void SC_dealloc(StabilizerChain *SC): if SC is not NULL: n = SC.degree if SC.generators is not NULL: - for i from 0 <= i < n: + for i in range(n): sig_free(SC.generators[i]) sig_free(SC.gen_inverses[i]) sig_free(SC.generators) # frees int_ptrs @@ -669,29 +675,29 @@ cdef StabilizerChain *SC_symmetric_group(int n): if SC is NULL: return NULL SC.base_size = n-1 - for i from 0 <= i < n-1: + for i in range(n - 1): SC.array_size[i] = n-i-1 SC.array_size[n-1] = default_num_gens - for i from 0 <= i < n: + for i in range(n): SC.generators[i] = <int *> sig_malloc( SC.array_size[i]*n * sizeof(int) ) SC.gen_inverses[i] = <int *> sig_malloc( SC.array_size[i]*n * sizeof(int) ) if SC.generators[i] is NULL or SC.gen_inverses[i] is NULL: SC_dealloc(SC) return NULL cdef int *id_perm = SC.perm_scratch - for i from 0 <= i < n: + for i in range(n): id_perm[i] = i - for i from 0 <= i < n-1: + for i in range(n - 1): b = i SC.orbit_sizes[i] = n-i SC.num_gens[i] = n-i-1 - for j from 0 <= j < i: + for j in range(i): SC.parents[i][j] = -1 - for j from 0 <= j < n-i: + for j in range(n - i): SC.base_orbits[i][j] = i+j SC.parents[i][i+j] = b SC.labels[i][i+j] = j - for j from 0 <= j < n-i-1: + for j in range(n - i - 1): #j-th generator sends i+j+1 to b memcpy(SC.generators[i] + n*j, id_perm, n * sizeof(int) ) SC.generators[i][n*j + i+j+1] = b @@ -710,31 +716,31 @@ cdef StabilizerChain *SC_alternating_group(int n): if SC is NULL: return NULL SC.base_size = n-2 - for i from 0 <= i < n-2: + for i in range(n - 2): SC.array_size[i] = n-i-1 SC.array_size[n-2] = default_num_gens SC.array_size[n-1] = default_num_gens - for i from 0 <= i < n: + for i in range(n): SC.generators[i] = <int *> sig_malloc( SC.array_size[i]*n * sizeof(int) ) SC.gen_inverses[i] = <int *> sig_malloc( SC.array_size[i]*n * sizeof(int) ) if SC.generators[i] is NULL or SC.gen_inverses[i] is NULL: SC_dealloc(SC) return NULL cdef int *id_perm = SC.perm_scratch - for i from 0 <= i < n: + for i in range(n): id_perm[i] = i - for i from 0 <= i < n-2: + for i in range(n - 2): b = i SC.orbit_sizes[i] = n-i SC.num_gens[i] = n-i-2 - for j from 0 <= j < i: + for j in range(i): SC.parents[i][j] = -1 - for j from 0 <= j < n-i: + for j in range(n - i): SC.base_orbits[i][j] = i+j SC.parents[i][i+j] = b SC.labels[i][i+j] = j SC.labels[i][n-1] = -(n-i-2) - for j from 0 <= j < n-i-2: + for j in range(n - i - 2): #j-th generator sends i+j+1 to b, i+j+2 to i+j+1, and b to i+j+2 memcpy(SC.generators[i] + n*j, id_perm, n * sizeof(int) ) SC.generators[i][n*j + i+j+1] = b @@ -751,7 +757,8 @@ cdef int SC_realloc_bitsets(StabilizerChain *SC, unsigned long size): Returns 1 in case of an allocation failure. """ cdef unsigned long size_old = SC.gen_used.size - if size <= size_old: return 0 + if size <= size_old: + return 0 cdef unsigned long new_size = size_old while new_size < size: new_size *= 2 @@ -788,14 +795,14 @@ cdef StabilizerChain *SC_copy(StabilizerChain *SC, int level): if SCC is NULL: return NULL level = min(level, SC.base_size) - for i from 0 <= i < level: + for i in range(level): SCC.generators[i] = <int *> sig_malloc( SC.array_size[i]*n * sizeof(int) ) SCC.gen_inverses[i] = <int *> sig_malloc( SC.array_size[i]*n * sizeof(int) ) if SCC.generators[i] is NULL or SCC.gen_inverses[i] is NULL: SC_dealloc(SCC) return NULL SCC.array_size[i] = SC.array_size[i] - for i from level <= i < n: + for i in range(level, n): SCC.generators[i] = <int *> sig_malloc( default_num_gens*n * sizeof(int) ) SCC.gen_inverses[i] = <int *> sig_malloc( default_num_gens*n * sizeof(int) ) if SCC.generators[i] is NULL or SCC.gen_inverses[i] is NULL: @@ -811,11 +818,11 @@ cdef int SC_copy_nomalloc(StabilizerChain *SC_dest, StabilizerChain *SC, int lev SC_dest.base_size = level memcpy(SC_dest.orbit_sizes, SC.orbit_sizes, 2*n * sizeof(int) ) # copies orbit_sizes, num_gens memcpy(SC_dest.base_orbits[0], SC.base_orbits[0], 3*n*n * sizeof(int) ) # copies base_orbits, parents, labels - for i from 0 <= i < level: + for i in range(level): if SC.num_gens[i] > SC_dest.array_size[i]: if SC_realloc_gens(SC_dest, i, max(SC.num_gens[i], 2*SC_dest.array_size[i])): return 1 - memcpy(SC_dest.generators[i], SC.generators[i], SC.num_gens[i]*n * sizeof(int) ) + memcpy(SC_dest.generators[i], SC.generators[i], SC.num_gens[i]*n * sizeof(int) ) memcpy(SC_dest.gen_inverses[i], SC.gen_inverses[i], SC.num_gens[i]*n * sizeof(int) ) return 0 @@ -823,12 +830,17 @@ cdef SC_print_level(StabilizerChain *SC, int level): cdef int i, j, n = SC.degree if level < SC.base_size: print('/ level {}'.format(level)) - print('| orbit {}'.format([SC.base_orbits[level][i] for i from 0 <= i < SC.orbit_sizes[level]])) - print('| parents {}'.format([SC.parents [level][i] for i from 0 <= i < n])) - print('| labels {}'.format([SC.labels [level][i] for i from 0 <= i < n])) + print('| orbit {}'.format([SC.base_orbits[level][i] + for i in range(SC.orbit_sizes[level])])) + print('| parents {}'.format([SC.parents[level][i] for i in range(n)])) + print('| labels {}'.format([SC.labels[level][i] for i in range(n)])) print('|') - print('| generators {}'.format([[SC.generators [level][n*i + j] for j from 0 <= j < n] for i from 0 <= i < SC.num_gens[level]])) - print(r'\ inverses {}'.format([[SC.gen_inverses[level][n*i + j] for j from 0 <= j < n] for i from 0 <= i < SC.num_gens[level]])) + print('| generators {}'.format([[SC.generators[level][n*i + j] + for j in range(n)] + for i in range(SC.num_gens[level])])) + print(r'\ inverses {}'.format([[SC.gen_inverses[level][n*i + j] + for j in range(n)] + for i in range(SC.num_gens[level])])) else: print('/ level {}'.format(level)) print('|') @@ -856,7 +868,7 @@ cdef StabilizerChain *SC_new_base(StabilizerChain *SC, int *base, int base_len): cdef int SC_new_base_nomalloc(StabilizerChain *SC_dest, StabilizerChain *SC, int *base, int base_len): cdef int i, n = SC.degree SC_dest.base_size = 0 - for i from 0 <= i < base_len: + for i in range(base_len): SC_add_base_point(SC_dest, base[i]) if SC_update(SC_dest, SC, 0): SC_dealloc(SC_dest) @@ -880,14 +892,14 @@ cdef int SC_update(StabilizerChain *dest, StabilizerChain *source, int level): break i += 1 else: - for b from 0 <= b < dest.degree: + for b in range(dest.degree): if perm[b] != b: break else: continue SC_add_base_point(dest, b) first_moved = i - for i from level <= i <= first_moved: + for i in range(level, first_moved + 1): if SC_insert_and_sift(dest, i, perm, 1, 0): # don't sift! mpz_clear(dst_order) mpz_clear(src_order) @@ -915,7 +927,7 @@ cdef StabilizerChain *SC_insert_base_point(StabilizerChain *SC, int level, int p if NEW is NULL: return NULL SC_add_base_point(NEW, p) - for i from level <= i < SC.base_size: + for i in range(level, SC.base_size): b = SC.base_orbits[i][0] if b != p: SC_add_base_point(NEW, b) @@ -928,7 +940,7 @@ cdef int SC_insert_base_point_nomalloc(StabilizerChain *SC_dest, StabilizerChain cdef int i, b, n = SC.degree SC_copy_nomalloc(SC_dest, SC, level) SC_add_base_point(SC_dest, p) - for i from level <= i < SC.base_size: + for i in range(level, SC.base_size): b = SC.base_orbits[i][0] if b != p: SC_add_base_point(SC_dest, b) @@ -950,7 +962,7 @@ cdef int SC_re_tree(StabilizerChain *SC, int level, int *perm, int x): if SC.array_size[level] == SC.num_gens[level]: if SC_realloc_gens(SC, level, 2*SC.array_size[level]): return 1 - cdef int *new_gen = SC.generators [level] + n*SC.num_gens[level] + cdef int *new_gen = SC.generators[level] + n*SC.num_gens[level] cdef int *new_gen_inv = SC.gen_inverses[level] + n*SC.num_gens[level] # new generator is perm^(-1) * (path from x to base) (left to right composition) @@ -961,7 +973,7 @@ cdef int SC_re_tree(StabilizerChain *SC, int level, int *perm, int x): # now that we have our generators, regenerate the tree, breadth-first b = SC.base_orbits[level][0] - for i from 0 <= i < n: + for i in range(n): SC.parents[level][i] = -1 SC.parents[level][b] = b i = 0 @@ -972,7 +984,7 @@ cdef int SC_re_tree(StabilizerChain *SC, int level, int *perm, int x): gen_inv = SC.gen_inverses[level] + n*gen_index SC_scan(SC, level, x, gen_index, gen_inv, 1) for gen_index from 0 <= gen_index < SC.num_gens[level]: - gen = SC.generators [level] + n*gen_index + gen = SC.generators[level] + n*gen_index SC_scan(SC, level, x, gen_index, gen, -1) i += 1 return 0 @@ -1041,8 +1053,10 @@ cdef int SC_insert_and_sift(StabilizerChain *SC, int level, int *pi, int num_per break else: bitset_set(&SC.gen_is_id, perm_gen_index) - if b != -1: break - if b == -1: return 0 + if b != -1: + break + if b == -1: + return 0 if sift and level == SC.base_size: SC_add_base_point(SC, b) else: @@ -1064,18 +1078,22 @@ cdef int SC_insert_and_sift(StabilizerChain *SC, int level, int *pi, int num_per for i from 0 <= i < SC.orbit_sizes[level]: x = SC.base_orbits[level][i] for perm_gen_index from 0 <= perm_gen_index < num_perms: - if sift and bitset_check(&SC.gen_is_id, perm_gen_index): continue + if sift and bitset_check(&SC.gen_is_id, perm_gen_index): + continue perm = pi + n*perm_gen_index if SC.parents[level][perm[x]] == -1: # now we have an x which maps to a new point under perm, re_treed = 1 - if sift: bitset_set(&SC.gen_used, perm_gen_index) + if sift: + bitset_set(&SC.gen_used, perm_gen_index) if SC_re_tree(SC, level, perm, x): return 1 start_over = 1 # we must look anew break - if start_over: break - if not re_treed: continue + if start_over: + break + if not re_treed: + continue for perm_gen_index from 0 <= perm_gen_index < old_num_gens: perm = SC.generators[level] + n*perm_gen_index if SC.parents[level][perm[x]] == -1: @@ -1084,7 +1102,8 @@ cdef int SC_insert_and_sift(StabilizerChain *SC, int level, int *pi, int num_per return 1 start_over = 1 # we must look anew break - if start_over: break + if start_over: + break for j from level < j < SC.base_size: for perm_gen_index from 0 <= perm_gen_index < SC.num_gens[j]: perm = SC.generators[j] + n*perm_gen_index @@ -1210,6 +1229,7 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, TESTS:: + sage: # needs sage.groups sage: from sage.groups.perm_gps.partn_ref.data_structures import SC_test_list_perms sage: limit = 10^7 sage: def test_Sn_on_m_points(n, m, gap, contains): @@ -1220,8 +1240,8 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, ....: test_Sn_on_m_points(i,i,1,0) sage: for i in range(2,9): ....: test_Sn_on_m_points(i,i,0,1) - sage: for i in range(2,9): # long time - ....: test_Sn_on_m_points(i,i,1,1) # long time + sage: for i in range(2,9): # long time + ....: test_Sn_on_m_points(i,i,1,1) sage: test_Sn_on_m_points(8,8,1,1) sage: def test_stab_chain_fns_1(n, gap, contains): ....: perm1 = sum([[2*i+1,2*i] for i in range(n)], []) @@ -1232,7 +1252,7 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, sage: for n in range(1,11): ....: test_stab_chain_fns_1(n, 0, 1) sage: for n in range(1,9): # long time - ....: test_stab_chain_fns_1(n, 1, 1) # long time + ....: test_stab_chain_fns_1(n, 1, 1) sage: test_stab_chain_fns_1(11, 1, 1) sage: def test_stab_chain_fns_2(n, gap, contains): ....: perms = [] @@ -1244,8 +1264,8 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, ....: test_stab_chain_fns_2(n, 1, 0) sage: for n in range(2,11): ....: test_stab_chain_fns_2(n, 0, 1) - sage: for n in range(2,11): # long time - ....: test_stab_chain_fns_2(n, 1, 1) # long time + sage: for n in range(2,11): # long time + ....: test_stab_chain_fns_2(n, 1, 1) sage: test_stab_chain_fns_2(11, 1, 1) sage: def test_stab_chain_fns_3(n, gap, contains): ....: perm1 = [(-i)%n for i in range( n )] @@ -1255,8 +1275,8 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, ....: test_stab_chain_fns_3(n, 1, 0) sage: for n in range(2,20): ....: test_stab_chain_fns_3(n, 0, 1) - sage: for n in range(2,14): # long time - ....: test_stab_chain_fns_3(n, 1, 1) # long time + sage: for n in range(2,14): # long time + ....: test_stab_chain_fns_3(n, 1, 1) sage: test_stab_chain_fns_3(20, 1, 1) sage: def test_stab_chain_fns_4(n, g, gap, contains): ....: perms = [] @@ -1265,23 +1285,23 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, ....: shuffle(perm) ....: perms.append(perm) ....: SC_test_list_perms(perms, n, limit, gap, 0, contains) - sage: for n in range(4,9): # long time - ....: test_stab_chain_fns_4(n, 1, 1, 0) # long time - ....: test_stab_chain_fns_4(n, 2, 1, 0) # long time - ....: test_stab_chain_fns_4(n, 2, 1, 0) # long time - ....: test_stab_chain_fns_4(n, 2, 1, 0) # long time - ....: test_stab_chain_fns_4(n, 2, 1, 0) # long time - ....: test_stab_chain_fns_4(n, 3, 1, 0) # long time - sage: for n in range(4,9): # not tested, known bug (see :trac:`32187`) + sage: for n in range(4,9): # long time + ....: test_stab_chain_fns_4(n, 1, 1, 0) + ....: test_stab_chain_fns_4(n, 2, 1, 0) + ....: test_stab_chain_fns_4(n, 2, 1, 0) + ....: test_stab_chain_fns_4(n, 2, 1, 0) + ....: test_stab_chain_fns_4(n, 2, 1, 0) + ....: test_stab_chain_fns_4(n, 3, 1, 0) + sage: for n in range(4,9): # known bug (see :trac:`32187`), not tested ....: test_stab_chain_fns_4(n, 1, 0, 1) ....: for j in range(6): ....: test_stab_chain_fns_4(n, 2, 0, 1) ....: test_stab_chain_fns_4(n, 3, 0, 1) - sage: for n in range(4,8): # long time - ....: test_stab_chain_fns_4(n, 1, 1, 1) # long time - ....: test_stab_chain_fns_4(n, 2, 1, 1) # long time - ....: test_stab_chain_fns_4(n, 2, 1, 1) # long time - ....: test_stab_chain_fns_4(n, 3, 1, 1) # long time + sage: for n in range(4,8): # long time + ....: test_stab_chain_fns_4(n, 1, 1, 1) + ....: test_stab_chain_fns_4(n, 2, 1, 1) + ....: test_stab_chain_fns_4(n, 2, 1, 1) + ....: test_stab_chain_fns_4(n, 3, 1, 1) sage: test_stab_chain_fns_4(8, 2, 1, 1) sage: def test_stab_chain_fns_5(n, gap, contains): ....: perms = [] @@ -1293,13 +1313,13 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, ....: shuffle(perm2) ....: perm2 = list(range(m)) + perm2 ....: SC_test_list_perms([perm1, perm2], n, limit, gap, 0, contains) - sage: for n in [4..9]: # long time - ....: for _ in range(2): # long time - ....: test_stab_chain_fns_5(n, 1, 0) # long time - sage: for n in [4..8]: # long time - ....: test_stab_chain_fns_5(n, 0, 1) # long time - sage: for n in [4..9]: # long time - ....: test_stab_chain_fns_5(n, 1, 1) # long time + sage: for n in [4..9]: # long time + ....: for _ in range(2): + ....: test_stab_chain_fns_5(n, 1, 0) + sage: for n in [4..8]: # long time + ....: test_stab_chain_fns_5(n, 0, 1) + sage: for n in [4..9]: # long time + ....: test_stab_chain_fns_5(n, 1, 1) sage: def random_perm(x): ....: shuffle(x) ....: return x @@ -1309,10 +1329,10 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, ....: perm = sum([random_perm(list(range(i*(n//m),min(n,(i+1)*(n//m))))) for i in range(m)], []) ....: perms.append(perm) ....: SC_test_list_perms(perms, m*(n//m), limit, gap, 0, contains) - sage: for m in range(2,9): # long time - ....: for n in range(m,3*m): # long time - ....: for k in range(1,3): # long time - ....: test_stab_chain_fns_6(m,n,k, 1, 0) # long time + sage: for m in range(2,9): # long time + ....: for n in range(m,3*m): + ....: for k in range(1,3): + ....: test_stab_chain_fns_6(m,n,k, 1, 0) sage: for m in range(2,10): ....: for n in range(m,4*m): ....: for k in range(1,3): @@ -1339,9 +1359,9 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, sage: for n in [6..30]: ....: test_stab_chain_fns_7(n, 1, 0, 1) ....: test_stab_chain_fns_7(n, 0, 0, 1) - sage: for n in [6..14]: # long time - ....: test_stab_chain_fns_7(n, 1, 1, 1) # long time - ....: test_stab_chain_fns_7(n, 0, 1, 1) # long time + sage: for n in [6..14]: # long time + ....: test_stab_chain_fns_7(n, 1, 1, 1) + ....: test_stab_chain_fns_7(n, 0, 1, 1) sage: test_stab_chain_fns_7(20, 1, 1, 1) sage: test_stab_chain_fns_7(20, 0, 1, 1) @@ -1361,7 +1381,8 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, if gap: G = PermutationGroup([[i+1 for i in p] for p in L]) if G.order() > limit: - if limit_complain: print('TOO BIG') + if limit_complain: + print('TOO BIG') return SC = SC_new(n) cdef int *perm = <int *>sig_malloc(n * (len(L)+3) * sizeof(int)) @@ -1411,7 +1432,7 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, if SC_is_giant(n, len(L), perm, 0.9, giant_support): giant = True m = bitset_len(giant_support) - from sage.arith.all import factorial + from sage.arith.misc import factorial if not (order == factorial(m) or order == factorial(m)/2): print("SC_is_giant failed: %s %s"%(str(L), order)) raise AssertionError @@ -1530,7 +1551,7 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, perm[n*j + i] = Lperm[i] j += 1 if SC_is_giant(n, len(L), perm, 0.9, giant_support): - from sage.arith.all import factorial + from sage.arith.misc import factorial m = bitset_len(giant_support) if order != factorial(m) and order != factorial(m)/2: print("SC_is_giant failed: %s %s"%(str(L), order)) @@ -1555,7 +1576,7 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, print('element {}'.format(permy)) print('GAP says it is an element, SC_contains(modify=1) does not') raise AssertionError - permy = list(xrange(1, n + 1)) + permy = list(range(1, n + 1)) shuffle(permy) gap_says = (PermutationGroupElement(permy) in G) for j from 0 <= j < n: diff --git a/src/sage/groups/perm_gps/partn_ref/double_coset.pyx b/src/sage/groups/perm_gps/partn_ref/double_coset.pyx index 3f726879292..e3c7bc75f05 100644 --- a/src/sage/groups/perm_gps/partn_ref/double_coset.pyx +++ b/src/sage/groups/perm_gps/partn_ref/double_coset.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups r""" Double cosets @@ -110,9 +111,10 @@ cdef int compare_perms(int *gamma_1, int *gamma_2, void *S1, void *S2, int degre cdef list MS1 = <list> S1 cdef list MS2 = <list> S2 cdef int i, j - for i from 0 <= i < degree: + for i in range(degree): j = int_cmp(MS1[gamma_1[i]], MS2[gamma_2[i]]) - if j != 0: return j + if j != 0: + return j return 0 def coset_eq(list perm1=[0,1,2,3,4,5], list perm2=[1,2,3,4,5,0], list gens=[[1,2,3,4,5,0]]): @@ -268,9 +270,10 @@ cdef void deallocate_dc_work_space(dc_work_space *work_space): cdef int double_coset(void *S1, void *S2, PartitionStack *partition1, int *ordering2, int n, bint (*all_children_are_equivalent)(PartitionStack *PS, void *S), - int (*refine_and_return_invariant)\ - (PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len), - int (*compare_structures)(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree), + int (*refine_and_return_invariant)(PartitionStack *PS, void *S, + int *cells_to_refine_by, int ctrb_len), + int (*compare_structures)(int *gamma_1, int *gamma_2, void *S1, void *S2, + int degree), StabilizerChain *input_group, dc_work_space *work_space_prealloc, int *isom) except -1: """ @@ -350,8 +353,8 @@ cdef int double_coset(void *S1, void *S2, PartitionStack *partition1, int *order cdef StabilizerChain *tmp_gp cdef int i, j, k, ell, b - cdef bint discrete, automorphism, update_label - cdef bint backtrack, new_vertex, narrow, mem_err = 0 + cdef bint automorphism + cdef bint new_vertex, mem_err = 0 if n == 0: return 0 @@ -590,7 +593,7 @@ cdef int double_coset(void *S1, void *S2, PartitionStack *partition1, int *order # (same!) primary orbit, then all children of the first # stack at this point are equivalent. j = 0 - for i from 0 <= i < n: + for i in range(n): if bitset_check(vertices_to_split[current_ps.depth], i): j += 1 if j == subgroup_primary_orbit_size and first_kids_are_same == current_ps.depth+1: @@ -607,7 +610,6 @@ cdef int double_coset(void *S1, void *S2, PartitionStack *partition1, int *order # II. Refine down to a discrete partition, or until # we leave the part of the tree we are interested in - discrete = 0 while True: i = current_ps.depth while True: @@ -641,7 +643,8 @@ cdef int double_coset(void *S1, void *S2, PartitionStack *partition1, int *order possible = 1 vertices_determining_current_stack[i] = j current_ps.depth -= 1 # reset for next refinement - else: break + else: + break if not possible: break if PS_is_discrete(current_ps): @@ -681,7 +684,7 @@ cdef int double_coset(void *S1, void *S2, PartitionStack *partition1, int *order index_in_fp_and_mcr += 1 bitset_zero(fixed_points_of_generators[index_in_fp_and_mcr]) bitset_zero(minimal_cell_reps_of_generators[index_in_fp_and_mcr]) - for i from 0 <= i < n: + for i in range(n): if permutation[i] == i: bitset_set(fixed_points_of_generators[index_in_fp_and_mcr], i) bitset_set(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i) @@ -690,7 +693,8 @@ cdef int double_coset(void *S1, void *S2, PartitionStack *partition1, int *order k = i j = permutation[i] while j != i: - if j < k: k = j + if j < k: + k = j j = permutation[j] if k == i: bitset_set(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i) diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx index e18fdf5f41a..56e4a062d02 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings """ Partition backtrack functions for binary codes @@ -23,7 +24,7 @@ REFERENCE: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from sage.data_structures.bitset_base cimport * @@ -63,16 +64,18 @@ cdef class LinearBinaryCodeStruct(BinaryCodeStruct): raise MemoryError cdef bint memerr = 0 - for i from 0 <= i < self.dimension: - try: bitset_init(&self.basis[i], self.degree) + for i in range(self.dimension): + try: + bitset_init(&self.basis[i], self.degree) except MemoryError: for j from 0 <= j < i: bitset_free(&self.basis[j]) memerr = 1 break if not memerr: - for i from 0 <= i < 2*self.dimension+2: - try: bitset_init(&self.scratch_bitsets[i], self.degree) + for i in range(2*self.dimension+2): + try: + bitset_init(&self.scratch_bitsets[i], self.degree) except MemoryError: for j from 0 <= j < i: bitset_free(&self.scratch_bitsets[j]) @@ -81,7 +84,8 @@ cdef class LinearBinaryCodeStruct(BinaryCodeStruct): memerr = 1 break if not memerr: - try: bitset_init(self.alpha_is_wd, self.nwords + self.degree) + try: + bitset_init(self.alpha_is_wd, self.nwords + self.degree) except MemoryError: for j from 0 <= j < 2*self.dimension+2: bitset_free(&self.scratch_bitsets[j]) @@ -98,7 +102,7 @@ cdef class LinearBinaryCodeStruct(BinaryCodeStruct): for j from 0 <= j < self.dimension: bitset_zero(&self.basis[j]) - for i,j in matrix.nonzero_positions(): + for i, j in matrix.nonzero_positions(): bitset_set(&self.basis[i], j) self.output = NULL @@ -265,11 +269,11 @@ cdef class LinearBinaryCodeStruct(BinaryCodeStruct): if self.output is NULL: self.run() generators = [] - for i from 0 <= i < self.output.num_gens: + for i in range(self.output.num_gens): generators.append([self.output.generators[i*self.degree + j] for j from 0 <= j < self.degree]) order = Integer() SC_order(self.output.group, 0, order.value) - base = [self.output.group.base_orbits[i][0] for i from 0 <= i < self.output.group.base_size] + base = [self.output.group.base_orbits[i][0] for i in range(self.output.group.base_size)] return generators, order, base def canonical_relabeling(self): @@ -294,7 +298,7 @@ cdef class LinearBinaryCodeStruct(BinaryCodeStruct): cdef int i if self.output is NULL: self.run() - return [self.output.relabeling[i] for i from 0 <= i < self.degree] + return [self.output.relabeling[i] for i in range(self.degree)] def is_isomorphic(self, LinearBinaryCodeStruct other): """ @@ -322,7 +326,7 @@ cdef class LinearBinaryCodeStruct(BinaryCodeStruct): sig_free(ordering) sig_free(output) raise MemoryError - for i from 0 <= i < n: + for i in range(n): ordering[i] = i self.first_time = 1 other.first_time = 1 @@ -332,7 +336,7 @@ cdef class LinearBinaryCodeStruct(BinaryCodeStruct): PS_dealloc(part) sig_free(ordering) if isomorphic: - output_py = [output[i] for i from 0 <= i < n] + output_py = [output[i] for i in range(n)] else: output_py = False sig_free(output) @@ -391,16 +395,18 @@ cdef class NonlinearBinaryCodeStruct(BinaryCodeStruct): raise MemoryError cdef bint memerr = 0 - for i from 0 <= i < self.nwords: - try: bitset_init(&self.words[i], self.degree) + for i in range(self.nwords): + try: + bitset_init(&self.words[i], self.degree) except MemoryError: for j from 0 <= j < i: bitset_free(&self.words[j]) memerr = 1 break if not memerr: - for i from 0 <= i < 4*self.nwords: - try: bitset_init(&self.scratch_bitsets[i], self.degree) + for i in range(4*self.nwords): + try: + bitset_init(&self.scratch_bitsets[i], self.degree) except MemoryError: for j from 0 <= j < i: bitset_free(&self.scratch_bitsets[j]) @@ -409,7 +415,8 @@ cdef class NonlinearBinaryCodeStruct(BinaryCodeStruct): memerr = 1 break if not memerr: - try: bitset_init(&self.scratch_bitsets[4*self.nwords], self.nwords) + try: + bitset_init(&self.scratch_bitsets[4*self.nwords], self.nwords) except MemoryError: for j from 0 <= j < 4*self.nwords: bitset_free(&self.scratch_bitsets[j]) @@ -417,7 +424,8 @@ cdef class NonlinearBinaryCodeStruct(BinaryCodeStruct): bitset_free(&self.words[j]) memerr = 1 if not memerr: - try: bitset_init(self.alpha_is_wd, self.nwords + self.degree) + try: + bitset_init(self.alpha_is_wd, self.nwords + self.degree) except MemoryError: for j from 0 <= j < 4*self.nwords + 1: bitset_free(&self.scratch_bitsets[j]) @@ -435,7 +443,7 @@ cdef class NonlinearBinaryCodeStruct(BinaryCodeStruct): bitset_zero(&self.words[j]) if is_Matrix(arg): - for i,j in arg.nonzero_positions(): + for i, j in arg.nonzero_positions(): bitset_set(&self.words[i], j) self.output = NULL @@ -534,11 +542,11 @@ cdef class NonlinearBinaryCodeStruct(BinaryCodeStruct): if self.output is NULL: self.run() generators = [] - for i from 0 <= i < self.output.num_gens: + for i in range(self.output.num_gens): generators.append([self.output.generators[i*self.degree + j] for j from 0 <= j < self.degree]) order = Integer() SC_order(self.output.group, 0, order.value) - base = [self.output.group.base_orbits[i][0] for i from 0 <= i < self.output.group.base_size] + base = [self.output.group.base_orbits[i][0] for i in range(self.output.group.base_size)] return generators, order, base def canonical_relabeling(self): @@ -557,7 +565,7 @@ cdef class NonlinearBinaryCodeStruct(BinaryCodeStruct): cdef int i if self.output is NULL: self.run() - return [self.output.relabeling[i] for i from 0 <= i < self.degree] + return [self.output.relabeling[i] for i in range(self.degree)] def is_isomorphic(self, NonlinearBinaryCodeStruct other): """ @@ -585,7 +593,7 @@ cdef class NonlinearBinaryCodeStruct(BinaryCodeStruct): sig_free(ordering) sig_free(output) raise MemoryError - for i from 0 <= i < n: + for i in range(n): ordering[i] = i self.first_time = 1 other.first_time = 1 @@ -595,7 +603,7 @@ cdef class NonlinearBinaryCodeStruct(BinaryCodeStruct): PS_dealloc(part) sig_free(ordering) if isomorphic: - output_py = [output[i] for i from 0 <= i < n] + output_py = [output[i] for i in range(n)] else: output_py = False sig_free(output) @@ -1062,9 +1070,7 @@ def random_tests(num=50, n_max=50, k_max=6, nwords_max=200, perms_per_code=10, d sage: import sage.groups.perm_gps.partn_ref.refinement_binary sage: sage.groups.perm_gps.partn_ref.refinement_binary.random_tests() # long time (up to 5s on sage.math, 2012) All passed: ... random tests on ... codes. - """ - from sage.misc.misc import walltime from sage.misc.prandom import random, randint from sage.combinat.permutation import Permutations from sage.matrix.constructor import random_matrix, matrix diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx index 1acb46201a0..5046a718853 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx @@ -70,7 +70,6 @@ def isomorphic(G1, G2, partn, ordering2, dig, use_indicator_function, sparse=Fal cdef bint loops = 0 from sage.graphs.graph import Graph - from sage.graphs.digraph import DiGraph from sage.graphs.generic_graph import GenericGraph from copy import copy which_G = 1 @@ -88,7 +87,7 @@ def isomorphic(G1, G2, partn, ordering2, dig, use_indicator_function, sparse=Fal n = G_in.num_verts() elif n != G_in.num_verts(): return False - if G_in.vertices(sort=True) != list(xrange(n)): + if G_in.vertices(sort=True) != list(range(n)): G_in = copy(G_in) to = G_in.relabel(return_map=True) frm = {} @@ -99,19 +98,19 @@ def isomorphic(G1, G2, partn, ordering2, dig, use_indicator_function, sparse=Fal else: if first: partition = partn - to = list(xrange(n)) + to = list(range(n)) frm = to if sparse: G = SparseGraph(n) else: G = DenseGraph(n) if G_in.is_directed(): - for i,j in G_in.edge_iterator(labels=False): - G.add_arc(i,j) + for i, j in G_in.edge_iterator(labels=False): + G.add_arc(i, j) else: - for i,j in G_in.edge_iterator(labels=False): - G.add_arc(i,j) - G.add_arc(j,i) + for i, j in G_in.edge_iterator(labels=False): + G.add_arc(i, j) + G.add_arc(j, i) elif isinstance(G_in, CGraph): G = <CGraph> G_in if n == -1: @@ -119,18 +118,23 @@ def isomorphic(G1, G2, partn, ordering2, dig, use_indicator_function, sparse=Fal elif n != <int>G.num_verts: return False if not loops: - for i from 0 <= i < n: + for i in range(n): if G.has_arc_unsafe(i,i): loops = 1 to = {} - for a in G.verts(): to[a]=a + for a in G.verts(): + to[a] = a frm = to if first: partition = partn else: raise TypeError("G must be a Sage graph") - if first: frm1=frm;to1=to - else: frm2=frm;to2=to + if first: + frm1 = frm + to1 = to + else: + frm2 = frm + to2 = to GS.G = G GS.directed = 1 if dig else 0 GS.loops = 1 @@ -300,7 +304,10 @@ def search_tree(G_in, partition, lab=True, dig=False, dict_rep=False, certificat ....: if bde.has_arc(i,j): ....: bdg.add_edge(i,j) sage: a, b.graph6_string() - ([[0, 19, 3, 2, 6, 5, 4, 17, 18, 11, 10, 9, 13, 12, 16, 15, 14, 7, 8, 1], [0, 1, 8, 9, 13, 14, 7, 6, 2, 3, 19, 18, 17, 4, 5, 15, 16, 12, 11, 10], [1, 8, 9, 10, 11, 12, 13, 14, 7, 6, 2, 3, 4, 5, 15, 16, 17, 18, 19, 0]], 'S?[PG__OQ@?_?_?P?CO?_?AE?EC?Ac?@O') + ([[0, 19, 3, 2, 6, 5, 4, 17, 18, 11, 10, 9, 13, 12, 16, 15, 14, 7, 8, 1], + [0, 1, 8, 9, 13, 14, 7, 6, 2, 3, 19, 18, 17, 4, 5, 15, 16, 12, 11, 10], + [1, 8, 9, 10, 11, 12, 13, 14, 7, 6, 2, 3, 4, 5, 15, 16, 17, 18, 19, 0]], + 'S?[PG__OQ@?_?_?P?CO?_?AE?EC?Ac?@O') sage: a == asp True sage: a == ade @@ -380,13 +387,12 @@ def search_tree(G_in, partition, lab=True, dig=False, dict_rep=False, certificat cdef aut_gp_and_can_lab *output cdef PartitionStack *part from sage.graphs.graph import Graph - from sage.graphs.digraph import DiGraph from sage.graphs.generic_graph import GenericGraph from copy import copy if isinstance(G_in, GenericGraph): loops = G_in.has_loops() n = G_in.num_verts() - if G_in.vertices(sort=False) != list(xrange(n)): + if G_in.vertices(sort=False) != list(range(n)): G_in = copy(G_in) to = G_in.relabel(return_map=True) frm = {} @@ -401,21 +407,22 @@ def search_tree(G_in, partition, lab=True, dig=False, dict_rep=False, certificat else: G = DenseGraph(n) if G_in.is_directed(): - for i,j in G_in.edge_iterator(labels=False): - G.add_arc(i,j) + for i, j in G_in.edge_iterator(labels=False): + G.add_arc(i, j) else: - for i,j in G_in.edge_iterator(labels=False): - G.add_arc(i,j) - G.add_arc(j,i) + for i, j in G_in.edge_iterator(labels=False): + G.add_arc(i, j) + G.add_arc(j, i) elif isinstance(G_in, CGraph): G = <CGraph> G_in n = G.num_verts loops = 0 - for i from 0 <= i < n: - if G.has_arc_unsafe(i,i): + for i in range(n): + if G.has_arc_unsafe(i, i): loops = 1 to = {} - for a in G.verts(): to[a]=a + for a in G.verts(): + to[a] = a frm = to else: raise TypeError("G must be a Sage graph") @@ -847,7 +854,7 @@ def random_tests(num=10, n_max=60, perms_per_graph=5): print(H.graph6_string()) print(perm) return - isom = isomorphic(G, H, [list(xrange(n))], list(xrange(n)), 0, 1) + isom = isomorphic(G, H, [list(range(n))], list(range(n)), 0, 1) if not isom or G.relabel(isom, inplace=False) != H: print("isom FAILURE: graph6-") print(H.graph6_string()) @@ -872,7 +879,7 @@ def random_tests(num=10, n_max=60, perms_per_graph=5): print(E.dig6_string()) print(perm) return - isom = isomorphic(D, E, [list(xrange(n))], list(xrange(n)), 1, 1) + isom = isomorphic(D, E, [list(range(n))], list(range(n)), 1, 1) if not isom or D.relabel(isom, inplace=False) != E: print("isom FAILURE: dig6-") print(E.dig6_string()) @@ -883,6 +890,7 @@ def random_tests(num=10, n_max=60, perms_per_graph=5): num_graphs += 2 print("All passed: %d random tests on %d graphs." % (num_tests, num_graphs)) + def orbit_partition(gamma, list_perm=False): r""" Assuming that G is a graph on vertices 0,1,...,n-1, and gamma is an @@ -899,6 +907,7 @@ def orbit_partition(gamma, list_perm=False): EXAMPLES:: + sage: # needs sage.groups sage: from sage.groups.perm_gps.partn_ref.refinement_graphs import orbit_partition sage: G = graphs.PetersenGraph() sage: S = SymmetricGroup(10) @@ -934,7 +943,8 @@ def orbit_partition(gamma, list_perm=False): l = [] for i in range(1,n+1): orb = gamma.orbit(i) - if orb not in l: l.append(orb) + if orb not in l: + l.append(orb) for i in l: for j in range(len(i)): if i[j] == n: @@ -1082,7 +1092,8 @@ cdef void *dg_edge_gen_next(void *data, int *degree, bint *mem_err): else: u = bitset_first(&edge_candidate.bits) v = bitset_next(&edge_candidate.bits, u+1) - if v == -1: v = u + if v == -1: + v = u if graph.G.has_arc_unsafe(u, v): reject = 1 if not reject: @@ -1288,7 +1299,7 @@ def generate_dense_graphs_edge_addition(int n, bint loops, G=None, depth=None, 34 156 1044 - sage: generate_dense_graphs_edge_addition(8,0) # long time - about 14 seconds at 2.4 GHz + sage: generate_dense_graphs_edge_addition(8,0) # long time (about 14 seconds at 2.4 GHz) 12346 """ @@ -1352,7 +1363,8 @@ def generate_dense_graphs_edge_addition(int n, bint loops, G=None, depth=None, if construct: while True: thing = graph_iterator.next(graph_iterator.data, NULL, &mem_err) - if thing is NULL: break + if thing is NULL: + break ODG = (<GraphStruct>thing).G G = Graph(0, implementation='c_graph', sparse=False) DG = DenseGraph(ODG.active_vertices.size, extra_vertices=0) @@ -1362,7 +1374,8 @@ def generate_dense_graphs_edge_addition(int n, bint loops, G=None, depth=None, else: while True: thing = graph_iterator.next(graph_iterator.data, NULL, &mem_err) - if thing is NULL: break + if thing is NULL: + break number += 1 free_dg_edge_gen(graph_iterator) @@ -1555,7 +1568,7 @@ def generate_dense_graphs_vert_addition(int n, base_G=None, 53 209 1253 - sage: generate_dense_graphs_vert_addition(8) # long time + sage: generate_dense_graphs_vert_addition(8) # long time 13599 TESTS:: @@ -1627,7 +1640,8 @@ def generate_dense_graphs_vert_addition(int n, base_G=None, if construct: while True: thing = graph_iterator.next(graph_iterator.data, NULL, &mem_err) - if thing is NULL: break + if thing is NULL: + break ODG = (<GraphStruct>thing).G G = Graph(0, implementation='c_graph', sparse=False) DG = DenseGraph(ODG.active_vertices.size, extra_vertices=0) @@ -1637,7 +1651,8 @@ def generate_dense_graphs_vert_addition(int n, base_G=None, else: while True: thing = graph_iterator.next(graph_iterator.data, NULL, &mem_err) - if thing is NULL: break + if thing is NULL: + break number += 1 free_dg_vert_gen(graph_iterator) diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_lists.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_lists.pyx index 5d8e3ff032a..5942edd5438 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_lists.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_lists.pyx @@ -15,7 +15,7 @@ EXAMPLES:: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from cysignals.memory cimport sig_malloc, sig_free @@ -75,7 +75,8 @@ cdef int compare_lists(int *gamma_1, int *gamma_2, void *S1, void *S2, int degre cdef list MS1 = <list> S1 cdef list MS2 = <list> S2 cdef int i, j - for i from 0 <= i < degree: + for i in range(degree): j = int_cmp(MS1[gamma_1[i]], MS2[gamma_2[i]]) - if j != 0: return j + if j != 0: + return j return 0 diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pyx index 736659318d6..e2388616a34 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pyx @@ -23,7 +23,7 @@ REFERENCE: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from libc.string cimport memcmp @@ -59,7 +59,7 @@ cdef class MatrixStruct: PS_dealloc(self.temp_col_ps) raise MemoryError - for i from 0 <= i < self.nsymbols: + for i in range(self.nsymbols): num_rows[i] = 0 for row in self.matrix.rows(): row = set(row.list()) @@ -67,11 +67,11 @@ cdef class MatrixStruct: row.remove(0) for s in row: num_rows[self.symbols.index(s)] += 1 - for i from 0 <= i < self.nsymbols: + for i in range(self.nsymbols): S_temp = NonlinearBinaryCodeStruct( (self.degree, num_rows[i]) ) self.symbol_structs.append(S_temp) - for i from 0 <= i < self.nsymbols: + for i in range(self.nsymbols): num_rows[i] = 0 for row in self.matrix.rows(): row_list = row.list() @@ -118,7 +118,7 @@ cdef class MatrixStruct: cdef NonlinearBinaryCodeStruct S_temp for S in self.symbol_structs: S_temp = <NonlinearBinaryCodeStruct>S - for i from 0 <= i < S_temp.nwords: + for i in range(S_temp.nwords): print(bitset_string(&S_temp.words[i])) print(self.symbols[j]) print("") @@ -158,7 +158,7 @@ cdef class MatrixStruct: cdef int i, n = self.degree cdef PartitionStack *part cdef NonlinearBinaryCodeStruct S_temp - for i from 0 <= i < self.nsymbols: + for i in range(self.nsymbols): S_temp = <NonlinearBinaryCodeStruct> self.symbol_structs[i] S_temp.first_time = 1 @@ -197,11 +197,11 @@ cdef class MatrixStruct: if self.output is NULL: self.run() generators = [] - for i from 0 <= i < self.output.num_gens: + for i in range(self.output.num_gens): generators.append([self.output.generators[i*self.degree + j] for j from 0 <= j < self.degree]) order = Integer() SC_order(self.output.group, 0, order.value) - base = [self.output.group.base_orbits[i][0] for i from 0 <= i < self.output.group.base_size] + base = [self.output.group.base_orbits[i][0] for i in range(self.output.group.base_size)] return generators, order, base def canonical_relabeling(self): @@ -222,7 +222,7 @@ cdef class MatrixStruct: cdef int i if self.output is NULL: self.run() - return [self.output.relabeling[i] for i from 0 <= i < self.degree] + return [self.output.relabeling[i] for i in range(self.degree)] def is_isomorphic(self, MatrixStruct other): """ @@ -237,12 +237,12 @@ cdef class MatrixStruct: [0, 2, 4, 1, 3, 5] """ - cdef int i, j, n = self.degree + cdef int i, n = self.degree cdef int *output cdef int *ordering cdef PartitionStack *part cdef NonlinearBinaryCodeStruct S_temp - for i from 0 <= i < self.nsymbols: + for i in range(self.nsymbols): S_temp = self.symbol_structs[i] S_temp.first_time = 1 S_temp = other.symbol_structs[i] @@ -255,7 +255,7 @@ cdef class MatrixStruct: sig_free(ordering) sig_free(output) raise MemoryError - for i from 0 <= i < self.degree: + for i in range(self.degree): ordering[i] = i cdef bint isomorphic = double_coset(<void *> self, <void *> other, part, ordering, self.degree, &all_matrix_children_are_equivalent, &refine_matrix, &compare_matrices, NULL, NULL, output) @@ -263,7 +263,7 @@ cdef class MatrixStruct: PS_dealloc(part) sig_free(ordering) if isomorphic: - output_py = [output[i] for i from 0 <= i < self.degree] + output_py = [output[i] for i in range(self.degree)] else: output_py = False sig_free(output) @@ -271,7 +271,7 @@ cdef class MatrixStruct: cdef int refine_matrix(PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len): cdef MatrixStruct M = <MatrixStruct> S - cdef int i, temp_inv, invariant = 1 + cdef int temp_inv, invariant = 1 cdef bint changed = 1 while changed: PS_copy_from_to(PS, M.temp_col_ps) @@ -290,7 +290,7 @@ cdef int compare_matrices(int *gamma_1, int *gamma_2, void *S1, void *S2, int de cdef int i MM1 = Matrix(M1.base_ring(), M1.nrows(), M1.ncols(), sparse=M1.is_sparse()) MM2 = Matrix(M2.base_ring(), M2.nrows(), M2.ncols(), sparse=M2.is_sparse()) - for i from 0 <= i < degree: + for i in range(degree): MM1.set_column(i, M1.column(gamma_1[i])) MM2.set_column(i, M2.column(gamma_2[i])) rows1 = sorted(MM1.rows()) @@ -330,15 +330,13 @@ def random_tests(n=10, nrows_max=50, ncols_max=50, nsymbols_max=10, perms_per_ma sage: import sage.groups.perm_gps.partn_ref.refinement_matrices sage: sage.groups.perm_gps.partn_ref.refinement_matrices.random_tests() # long time (up to 30s on sage.math, 2011) All passed: ... random tests on ... matrices. - """ - from sage.misc.misc import walltime from sage.misc.prandom import random, randint from sage.combinat.permutation import Permutations from sage.matrix.constructor import random_matrix, matrix from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF - from sage.arith.all import next_prime - cdef int h, i, j, nrows, k, num_tests = 0, num_matrices = 0 + from sage.arith.misc import next_prime + cdef int i, j, nrows, num_tests = 0, num_matrices = 0 cdef MatrixStruct M, N for m in range(n): p = random()*(density_range[1]-density_range[0]) + density_range[0] @@ -350,7 +348,7 @@ def random_tests(n=10, nrows_max=50, ncols_max=50, nsymbols_max=10, perms_per_ma M = MatrixStruct( MM ) M.run() - for i from 0 <= i < perms_per_matrix: + for i in range(perms_per_matrix): perm = [a-1 for a in list(S.random_element())] NN = matrix(GF(nsymbols), nrows, ncols) for j from 0 <= j < ncols: diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx index a24b0499888..4d53f3a0332 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx @@ -27,7 +27,7 @@ debugger. # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from cysignals.memory cimport sig_malloc, sig_free @@ -35,7 +35,7 @@ from cysignals.memory cimport sig_malloc, sig_free from .data_structures cimport * from .automorphism_group_canonical_label cimport ( get_aut_gp_and_can_lab, aut_gp_and_can_lab, - allocate_agcl_output, deallocate_agcl_output) + deallocate_agcl_output) from .double_coset cimport double_coset from sage.rings.integer cimport Integer @@ -471,7 +471,6 @@ def aut_gp_and_can_lab_python(S, partition, n, """ obj_wrapper = PythonObjectWrapper(S, all_children_are_equivalent, refine_and_return_invariant, compare_structures, n) cdef aut_gp_and_can_lab *output - cdef PythonPartitionStack Py_PS = PythonPartitionStack(n) cdef int i, j cdef Integer I @@ -486,11 +485,11 @@ def aut_gp_and_can_lab_python(S, partition, n, canonical_label, NULL, NULL, NULL) list_of_gens = [] - for i from 0 <= i < output.num_gens: - list_of_gens.append([output.generators[j+i*n] for j from 0 <= j < n]) + for i in range(output.num_gens): + list_of_gens.append([output.generators[j+i*n] for j in range(n)]) return_tuple = [list_of_gens] if canonical_label: - return_tuple.append([output.relabeling[i] for i from 0 <= i < n]) + return_tuple.append([output.relabeling[i] for i in range(n)]) if base: return_tuple.append([output.group.base_orbits[i][0] for i from 0 <= i < output.group.base_size]) if order: diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx index 912c9a31a0d..7affe0cd965 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx @@ -383,7 +383,7 @@ def sets_isom_py(generators, set1, set2): set2 = set(set2) if not generators: if set1 == set2: - return list(xrange(max(set1) + 1)) + return list(range(max(set1) + 1)) else: return False @@ -453,7 +453,7 @@ cdef int refine_set(PartitionStack *PS, void *S, int *cells_to_refine_by, int ct return 0 cdef subset *subset1 = <subset *> S cdef int *scratch = subset1.scratch - cdef int start, i, n = PS.degree, x + cdef int start, i, n = PS.degree start = 0 while start < n: i = 0 @@ -463,7 +463,7 @@ cdef int refine_set(PartitionStack *PS, void *S, int *cells_to_refine_by, int ct break i += 1 sort_by_function(PS, start, scratch) - start += i+1 + start += i + 1 return 0 cdef inline int _bint_cmp(bint a, bint b): @@ -478,9 +478,10 @@ cdef int compare_sets(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree cdef bitset_s set1 = subset1.bits cdef bitset_s set2 = subset2.bits cdef int i, j - for i from 0 <= i < degree: + for i in range(degree): j = _bint_cmp(bitset_in(&set1, gamma_1[i]), bitset_in(&set2, gamma_2[i])) - if j != 0: return j + if j != 0: + return j return 0 cdef void *allocate_subset(int n): @@ -554,12 +555,11 @@ cdef int generate_child_subsets(void *S, aut_gp_and_can_lab *group, iterator *ch Sets up an iterator of augmentations, i.e., elements to add to the given set. """ cdef subset *subset1 = <subset *> S - cdef bitset_s set1 = subset1.bits cdef int i, j, n = group.group.degree cdef subset_generator_data *sgd = <subset_generator_data *> child_iterator.data OP_clear(sgd.orbits) - for i from 0 <= i < group.num_gens: - for j from 0 <= j < n: + for i in range(group.num_gens): + for j in range(n): OP_join(sgd.orbits, j, group.generators[n*i + j]) i = bitset_first(&subset1.bits) j = bitset_next(&subset1.bits, i+1) @@ -594,7 +594,6 @@ cdef void *canonical_set_parent(void *child, void *parent, int *permutation, int storing the result to ``parent``. """ cdef subset *set1 = <subset *> child - cdef bitset_t can_par cdef int i, max_in_can_lab, max_loc, n = set1.bits.size cdef subset *par if parent is NULL: @@ -659,7 +658,8 @@ cdef void free_subset_gen(iterator *subset_gen): r""" Frees the iterator of subsets. """ - if subset_gen is NULL: return + if subset_gen is NULL: + return cdef canonical_generator_data *cgd = <canonical_generator_data *> subset_gen.data deallocate_cgd(cgd) sig_free(subset_gen) @@ -800,7 +800,6 @@ def sets_modulo_perm_group(list generators, int max_size, sage: X = sets_modulo_perm_group([[0,2,1,4,3,5,8,7,6],[8,7,6,3,5,4,2,1,0]], 9) sage: len(X) 74 - """ cdef list out_list = [] cdef int i @@ -809,7 +808,7 @@ def sets_modulo_perm_group(list generators, int max_size, if len(generators) == 0: ll = [] for i in range(max_size,-1,-1): - ll.append(list(xrange(i))) + ll.append(list(range(i))) return ll cdef int n = len(generators[0]), n_gens = len(generators) cdef iterator *subset_iterator @@ -844,7 +843,8 @@ def sets_modulo_perm_group(list generators, int max_size, start_canonical_generator(group, NULL, n, subset_gen) while not mem_err: thing = <subset *> subset_iterator.next(subset_iterator.data, NULL, &mem_err) - if thing is NULL: break + if thing is NULL: + break out_list.append( bitset_list(&thing.bits) ) free_subset_gen(subset_gen) SC_dealloc(group) diff --git a/src/sage/groups/perm_gps/partn_ref2/__init__.py b/src/sage/groups/perm_gps/partn_ref2/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/combinat/ncsf_qsym/__init__.py b/src/sage/groups/perm_gps/partn_ref2/all.py similarity index 100% rename from src/sage/combinat/ncsf_qsym/__init__.py rename to src/sage/groups/perm_gps/partn_ref2/all.py diff --git a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd index e45afd3e578..df300e4e0ce 100644 --- a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd +++ b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd @@ -7,6 +7,7 @@ # http://www.gnu.org/licenses/ #******************************************************************************* +from sage.data_structures.bitset_base cimport * from sage.groups.perm_gps.partn_ref.data_structures cimport OrbitPartition, PartitionStack from sage.libs.gap.element cimport GapElement, GapElement_Permutation from sage.structure.parent cimport Parent @@ -82,3 +83,7 @@ cdef class PartitionRefinement_generic: bint* inner_group_changed, bint* changed_partition, str refine_name) cdef int len(self) + + +cdef int PS_first_smallest_PR(PartitionStack *PS, bitset_t b, int *second_pos=?, + PartitionRefinement_generic partn_ref_alg=?) diff --git a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx index f2ccca042ac..6e4e2b27eeb 100644 --- a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx +++ b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx @@ -427,7 +427,7 @@ cdef class LabelledBranching: sage: from sage.groups.perm_gps.partn_ref2.refinement_generic import LabelledBranching sage: L = LabelledBranching(3) sage: L.small_generating_set() - [] + [()] sage: L.add_gen(libgap.eval('(1,2,3)')) sage: L.small_generating_set() [(1,2,3)] @@ -684,8 +684,7 @@ cdef class PartitionRefinement_generic: bitset_init(b, self._n) PS_move_all_mins_to_front(self._part) cdef int second_pos - cdef int smallest = PS_first_smallest(self._part, b, &second_pos, - self) + cdef int smallest = PS_first_smallest_PR(self._part, b, &second_pos, self) if second_pos != -1: self._fixed_not_minimized.append(second_pos) cdef int pos = smallest @@ -941,3 +940,42 @@ cdef class PartitionRefinement_generic: """ if BACKTRACK_WITHLATEX_DEBUG: self._latex_debug_string += "]\n" + + +cdef int PS_first_smallest_PR(PartitionStack *PS, bitset_t b, int *second_pos=NULL, + PartitionRefinement_generic partn_ref_alg=None): + """ + Find the first occurrence of the smallest cell of size greater than one, + which is admissible (checked by the function ``test_allowance``). + Its entries are stored to b and its minimum element is returned. + + This generalizes :func:`sage.groups.perm_gps.partn_ref.data_structures.PS_first_smallest`. + """ + cdef int i = 0, j = 0, location = 0, n = PS.degree + bitset_zero(b) + while True: + if PS.levels[i] <= PS.depth: + if i != j and n > i - j + 1 and (partn_ref_alg is None or + partn_ref_alg._minimization_allowed_on_col(PS.entries[j])): + n = i - j + 1 + location = j + j = i + 1 + if PS.levels[i] == -1: + break + i += 1 + # location now points to the beginning of the first, smallest, + # nontrivial cell + i = location + while True: + bitset_flip(b, PS.entries[i]) + if PS.levels[i] <= PS.depth: + break + i += 1 + + if second_pos != NULL: + if n == 2: + second_pos[0] = PS.entries[location + 1] + else: + second_pos[0] = -1 + + return PS.entries[location] diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index a7372d3d77e..cf2ed82f239 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Permutation groups @@ -141,7 +140,8 @@ from sage.misc.randstate import current_randstate from sage.groups.group import FiniteGroup -from sage.rings.all import QQ, Integer +from sage.rings.rational_field import QQ +from sage.rings.integer import Integer from sage.interfaces.abc import ExpectElement, GapElement from sage.libs.gap.libgap import libgap from sage.libs.gap.element import GapElement as LibGapElement @@ -151,7 +151,7 @@ from sage.misc.cachefunc import cached_method from sage.groups.class_function import ClassFunction_libgap from sage.sets.finite_enumerated_set import FiniteEnumeratedSet -from sage.categories.all import FiniteEnumeratedSets +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.groups.conjugacy_classes import ConjugacyClassGAP from sage.structure.richcmp import (richcmp_method, richcmp, rich_to_bool, op_EQ, op_NE) @@ -163,7 +163,7 @@ def load_hap(): EXAMPLES:: - sage: sage.groups.perm_gps.permgroup.load_hap() # optional - gap_packages + sage: sage.groups.perm_gps.permgroup.load_hap() # optional - gap_package_hap """ from sage.features.gap import GapPackage GapPackage("hap", spkg="gap_packages").require() @@ -178,16 +178,17 @@ def hap_decorator(f): EXAMPLES:: + sage: # optional - gap_package_hap sage: from sage.groups.perm_gps.permgroup import hap_decorator sage: def foo(self, n, p=0): print("Done") sage: foo = hap_decorator(foo) - sage: foo(None, 3) #optional - gap_packages + sage: foo(None, 3) Done - sage: foo(None, 3, 0) # optional - gap_packages + sage: foo(None, 3, 0) Done - sage: foo(None, 3, 5) # optional - gap_packages + sage: foo(None, 3, 5) Done - sage: foo(None, 3, 4) #optional - gap_packages + sage: foo(None, 3, 4) Traceback (most recent call last): ... ValueError: p must be 0 or prime @@ -195,7 +196,7 @@ def hap_decorator(f): @wraps(f) def wrapped(self, n, p=0): load_hap() - from sage.arith.all import is_prime + from sage.arith.misc import is_prime if not (p == 0 or is_prime(p)): raise ValueError("p must be 0 or prime") @@ -285,6 +286,7 @@ def PermutationGroup(gens=None, *args, **kwds): We can also make permutation groups from PARI groups:: + sage: # needs sage.libs.pari sage: H = pari('x^4 - 2*x^3 - 2*x + 1').polgalois() sage: G = PariGroup(H, 4); G PARI group [8, -1, 3, "D(4)"] of degree 4 @@ -293,7 +295,7 @@ def PermutationGroup(gens=None, *args, **kwds): sage: H.gens() ((1,2,3,4), (1,3)) - We can also create permutation groups whose generators are Gap + We can also create permutation groups whose generators are GAP permutation objects:: sage: p = gap('(1,2)(3,7)(4,6)(5,8)'); p @@ -333,10 +335,10 @@ def PermutationGroup(gens=None, *args, **kwds): We can create a permutation group from a group action:: sage: a = lambda x: (2*x) % 7 - sage: H = PermutationGroup(action=a, domain=range(7)) - sage: H.orbits() + sage: H = PermutationGroup(action=a, domain=range(7)) # needs sage.combinat + sage: H.orbits() # needs sage.libs.pari ((0,), (1, 2, 4), (3, 6, 5)) - sage: H.gens() + sage: H.gens() # needs sage.libs.pari ((1,2,4), (3,6,5)) Note that we provide generators for the acting group. The @@ -360,7 +362,9 @@ def PermutationGroup(gens=None, *args, **kwds): i.e., in bijection with integer partitions:: sage: a = lambda g, x: g*x*g^-1 - sage: [len(PermutationGroup(SymmetricGroup(n).gens(), action=a, domain=SymmetricGroup(n)).orbits()) for n in range(1, 8)] + sage: [len(PermutationGroup(SymmetricGroup(n).gens(), action=a, # needs sage.combinat + ....: domain=SymmetricGroup(n)).orbits()) + ....: for n in range(1, 8)] [1, 2, 3, 5, 7, 11, 15] TESTS:: @@ -425,7 +429,8 @@ class PermutationGroup_generic(FiniteGroup): sage: G Permutation Group with generators [(3,4), (1,2,3)(4,5)] sage: G.center() - Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) + Subgroup generated by [()] of + (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.group_id() [120, 34] sage: n = G.order(); n @@ -612,14 +617,14 @@ def _has_natural_domain(self): def _gap_init_(self): r""" - Return a string showing how to declare / initialize ``self`` in Gap. + Return a string showing how to declare / initialize ``self`` in GAP. Stored in the ``self._gap_string`` attribute. EXAMPLES: The ``_gap_init_`` method shows how you would define the Sage ``PermutationGroup_generic`` - object in Gap:: + object in GAP:: sage: A4 = PermutationGroup([[(1,2,3)],[(2,3,4)]]); A4 Permutation Group with generators [(2,3,4), (1,2,3)] @@ -631,7 +636,7 @@ def _gap_init_(self): @cached_method def gap(self): r""" - this method from :class:`sage.groups.libgap_wrapper.ParentLibGAP` is added in order to achieve + This method from :class:`sage.groups.libgap_wrapper.ParentLibGAP` is added in order to achieve compatibility and have :class:`sage.groups.libgap_morphism.GroupHomset_libgap` work for permutation groups, as well @@ -641,7 +646,7 @@ def gap(self): EXAMPLES:: - sage: P8=PSp(8,3) + sage: P8 = PSp(8,3) sage: P8.gap() <permutation group of size 65784756654489600 with 2 generators> sage: gap(P8) == P8.gap() @@ -654,7 +659,7 @@ def gap(self): TESTS: - see that this method does not harm pickling: + see that this method does not harm pickling:: sage: A4 = PermutationGroup([[(1,2,3)],[(2,3,4)]]) sage: A4.gap() @@ -662,8 +667,9 @@ def gap(self): sage: TestSuite(A4).run() the following test shows, that support for the ``self._libgap`` - attribute is needed in the constructor of the class: + attribute is needed in the constructor of the class:: + sage: # needs sage.libs.pari sage: PG = PGU(6,2) sage: g, h = PG.gens() sage: p1 = h^-3*(h^-1*g^-1)^2*h*g*h^2*g^-1*h^2*g*h^-5*g^-1 @@ -738,7 +744,7 @@ def __richcmp__(self, right, op): The comparison extends the subgroup relation. Hence, it is first checked whether one of the groups is subgroup of the other. If this is not the - case then the ordering is whatever it is in Gap. + case then the ordering is whatever it is in GAP. .. NOTE:: @@ -760,9 +766,9 @@ def __richcmp__(self, right, op): sage: H1 = PermutationGroup([[(1,2)],[(5,6)]]) sage: H2 = PermutationGroup([[(3,4)]]) sage: H3 = PermutationGroup([[(1,2)]]) - sage: H1 < H2 # according to Gap's ordering + sage: H1 < H2 # according to GAP's ordering True - sage: H2 < H3 # according to Gap's ordering + sage: H2 < H3 # according to GAP's ordering True sage: H3 < H1 # since H3 is a subgroup of H1 True @@ -848,7 +854,8 @@ def _element_constructor_(self, x, check=True): sage: G([(1,2)]) Traceback (most recent call last): ... - ValueError: permutation [(1, 2)] not in Permutation Group with generators [(1,2,3,4)] + ValueError: permutation [(1, 2)] not in + Permutation Group with generators [(1,2,3,4)] TESTS: @@ -921,12 +928,13 @@ def _coerce_map_from_(self, G): If this permutation group has been constructed via ``as_permutation_group`` method (from finite matrix groups):: + sage: # needs sage.libs.pari sage: MG = GU(3,2).as_matrix_group() sage: PG = MG.as_permutation_group() sage: f = PG._coerce_map_from_(MG) sage: mg = MG.an_element() sage: p = f(mg); p - (2,33,32,23,31,55)(3,49,38,44,40,28)(4,17,59,62,58,46)(5,21,47,20,43,8)(6,53,50)(7,37,12,57,14,29)(9,41,56,34,64,10)(11,25,19)(13,61,26,51,22,15)(16,45,36)(18,27,35,48,52,54)(24,63,42)(30,39,60) + (1,2,6,19,35,33)(3,9,26,14,31,23)(4,13,5)(7,22,17)(8,24,12)(10,16,32,27,20,28)(11,30,18)(15,25,36,34,29,21) sage: PG(p._gap_()) == p True @@ -972,12 +980,12 @@ def _coerce_map_from_(self, G): sage: P = G.as_permutation_group(algorithm='smaller', seed=5) sage: P1 = G.as_permutation_group() sage: P == P1 - False + True sage: g1, g2, g3 = G.gens() sage: P(g1*g2) - (1,3,7,12)(2,4,8,10)(5,11)(6,9) + (1,4,13,11)(2,5,14,18)(3,15,8,16)(6,7)(9,20,19,12)(10,17) sage: P1(g1*g2) - (2,29,25,68)(3,57,13,54)(4,11,72,37)(5,39,60,23)(6,64,75,63)(7,21,50,73)(8,46,38,32)(9,74,35,18)(10,44,49,48)(12,16,34,71)(14,79,27,40)(15,26)(17,62,59,76)(19,78,70,65)(20,22,58,51)(24,33,36,43)(28,81,80,52)(30,53,56,69)(31,61)(41,42,67,55)(45,77)(47,66) + (1,4,13,11)(2,5,14,18)(3,15,8,16)(6,7)(9,20,19,12)(10,17) Another check for :trac:`5583`:: @@ -1164,11 +1172,11 @@ def iteration(self, algorithm="SGS"): - ``algorithm`` -- (default: ``"SGS"``) either - * ``"SGS"`` - using strong generating system - * ``"BFS"`` - a breadth first search on the Cayley graph with - respect to ``self.gens()`` - * ``"DFS"`` - a depth first search on the Cayley graph with - respect to ``self.gens()`` + * ``"SGS"`` -- using strong generating system + * ``"BFS"`` -- a breadth first search on the Cayley graph with + respect to ``self.gens()`` + * ``"DFS"`` -- a depth first search on the Cayley graph with + respect to ``self.gens()`` .. NOTE:: @@ -1271,7 +1279,7 @@ def gens(self) -> tuple: We make sure that the trivial group gets handled correctly:: sage: SymmetricGroup(1).gens() - ((),) + () """ return self._gens @@ -1302,7 +1310,7 @@ def gens_small(self): sage: G.gens_small() # random [('b','c'), ('a','c','b')] ## (on 64-bit Linux) [('a','b'), ('a','c','b')] ## (on Solaris) - sage: len(G.gens_small()) == 2 + sage: len(G.gens_small()) == 2 # random True """ gens = self._libgap_().SmallGeneratingSet() @@ -1310,7 +1318,7 @@ def gens_small(self): def gen(self, i=None): r""" - Return the i-th generator of ``self``; that is, the i-th element of + Return the `i`-th generator of ``self``; that is, the `i`-th element of the list ``self.gens()``. The argument `i` may be omitted if there is only one generator (but @@ -1365,8 +1373,7 @@ def one(self): EXAMPLES:: sage: G = PermutationGroup([[(1,2,3),(4,5)]]) - sage: e = G.identity() # indirect doctest - sage: e + sage: e = G.identity(); e # indirect doctest () sage: g = G.gen(0) sage: g*e @@ -1529,13 +1536,13 @@ def representative_action(self,x,y): INPUT: - - ``x,y`` -- two elements of the domain. + - ``x``, ``y`` -- two elements of the domain. EXAMPLES:: sage: G = groups.permutation.Cyclic(14) - sage: g = G.representative_action(1,10) - sage: all(g(x) == 1+((x+9-1)%14) for x in G.domain()) + sage: g = G.representative_action(1, 10) + sage: all(g(x) == 1 + ((x+9-1)%14) for x in G.domain()) True TESTS:: @@ -1655,7 +1662,7 @@ def orbit(self, point, action="OnPoints"): Action of `S_4` (on a nonstandard domain) on tuples of sets:: sage: S4 = PermutationGroup([ [('c','d')], [('a','c')], [('a','b')] ]) - sage: orb = S4.orbit((('a','c'),('b','d')),"OnTuplesSets") + sage: orb = S4.orbit((('a','c'),('b','d')), "OnTuplesSets") sage: expect = (({'a', 'c'}, {'b', 'd'}), ({'a', 'd'}, {'c', 'b'}), ....: ({'c', 'b'}, {'a', 'd'}), ({'b', 'd'}, {'a', 'c'}), ....: ({'c', 'd'}, {'a', 'b'}), ({'a', 'b'}, {'c', 'd'})) @@ -1666,7 +1673,8 @@ def orbit(self, point, action="OnPoints"): sage: S4 = PermutationGroup([ [((11,(12,13)),'d')], ....: [((12,(12,11)),(11,(12,13)))], [((12,(12,11)),'b')] ]) - sage: orb = S4.orbit((( (11,(12,13)), (12,(12,11))),('b','d')),"OnTuplesSets") + sage: orb = S4.orbit((( (11,(12,13)), (12,(12,11))),('b','d')), + ....: "OnTuplesSets") sage: expect = (({(11, (12, 13)), (12, (12, 11))}, {'b', 'd'}), ....: ({'d', (12, (12, 11))}, {(11, (12, 13)), 'b'}), ....: ({(11, (12, 13)), 'b'}, {'d', (12, (12, 11))}), @@ -1753,9 +1761,9 @@ def stabilizer(self, point, action="OnPoints"): - ``point`` -- a point of the :meth:`domain`, or a set of points depending on the value of ``action``. - - ``action`` (string; default ``"OnPoints"``) -- should the group be + - ``action`` -- (string; default ``"OnPoints"``) should the group be considered to act on points (``action="OnPoints"``) or on sets of - points (``action="OnSets"``) ? In the latter case, the first argument + points (``action="OnSets"``)? In the latter case, the first argument must be a subset of :meth:`domain`. EXAMPLES:: @@ -1846,8 +1854,8 @@ def base(self, seed=None): INPUT: - ``seed`` (optional, default: ``None``), if given must be a - subset of the domain of `base`. When used, an attempt to - create a base containing all or part of `seed` will be + subset of the domain of a base. When used, an attempt to + create a base containing all or part of ``seed`` will be made. EXAMPLES:: @@ -1913,10 +1921,10 @@ def strong_generating_system(self, base_of_group=None, implementation="sage"): - ``implementation`` -- (default: ``"sage"``) either - * ``"sage"`` - use the direct implementation in Sage + * ``"sage"`` -- use the direct implementation in Sage - * ``"gap"`` - if used, the ``base_of_group`` must be ``None`` - and the computation is directly performed in GAP + * ``"gap"`` -- if used, the ``base_of_group`` must be ``None`` + and the computation is directly performed in GAP OUTPUT: @@ -2026,8 +2034,11 @@ def strong_generating_system(self, base_of_group=None, implementation="sage"): end; return CosetsStabChain(S0); end;""") - G = libgap.Group(self.gens()) # G = libgap(self) - S = G.StabChain() + if self._gens: + G = libgap.Group(self.gens()) # G = libgap(self) + else: + G = libgap.SymmetricGroup([]) + S = G.StabChainImmutable() cosets = gap_cosets(S) one = self.one() return [[one._generate_new_GAP(libgap.ListPerm(elt)) @@ -2138,7 +2149,7 @@ def _order(self): # This special case only works with more than 1 generator. if not gens or len(gens) < 2: return None - # Special case: certain subgroups of the symmetric group for which Gap reports + # Special case: certain subgroups of the symmetric group for which GAP reports # generators of the form ((1, 2), (1, 3), ...) # This means that this group is isomorphic to a smaller symmetric group # S_n, where n is the number of generators supported. @@ -2186,7 +2197,8 @@ def _order(self): def order(self): """ Return the number of elements of this group. - See also: G.degree() + + See also: :meth:`degree`. EXAMPLES:: @@ -2200,7 +2212,7 @@ def order(self): sage: G.order() 1 - ``cardinality`` is just an alias:: + :meth:`cardinality` is just an alias:: sage: PermutationGroup([(1,2,3)]).cardinality() 3 @@ -2253,8 +2265,9 @@ def group_id(self): def id(self): """ - (Same as ``self.group_id()``.) Return the ID code of this group, which - is a list of two integers. + Return the ID code of this group, which is a list of two integers. + + Same as :meth:`group_id`. EXAMPLES:: @@ -2271,7 +2284,7 @@ def group_primitive_id(self): OUTPUT: A positive integer, following GAP's conventions. A - ``ValueError`` is raised if the group is not primitive. + :class:`ValueError` is raised if the group is not primitive. EXAMPLES:: @@ -2305,10 +2318,12 @@ def center(self): sage: G = PermutationGroup([[(1,2,3,4)]]) sage: G.center() - Subgroup generated by [(1,2,3,4)] of (Permutation Group with generators [(1,2,3,4)]) + Subgroup generated by [(1,2,3,4)] of + (Permutation Group with generators [(1,2,3,4)]) sage: G = PermutationGroup([[(1,2,3,4)], [(1,2)]]) sage: G.center() - Subgroup generated by [()] of (Permutation Group with generators [(1,2), (1,2,3,4)]) + Subgroup generated by [()] of + (Permutation Group with generators [(1,2), (1,2,3,4)]) """ return self.subgroup(gap_group=self._libgap_().Center()) @@ -2323,9 +2338,12 @@ def socle(self): sage: G = SymmetricGroup(4) sage: G.socle() - Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] of (Symmetric group of order 4! as a permutation group) + Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] of + (Symmetric group of order 4! as a permutation group) sage: G.socle().socle() - Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] of (Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] of (Symmetric group of order 4! as a permutation group)) + Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] of + (Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] + of (Symmetric group of order 4! as a permutation group)) """ return self.subgroup(gap_group=self._gap_().Socle()) @@ -2340,10 +2358,12 @@ def frattini_subgroup(self): sage: G = PermutationGroup([[(1,2,3,4)],[(2,4)]]) sage: G.frattini_subgroup() - Subgroup generated by [(1,3)(2,4)] of (Permutation Group with generators [(2,4), (1,2,3,4)]) + Subgroup generated by [(1,3)(2,4)] of + (Permutation Group with generators [(2,4), (1,2,3,4)]) sage: G = SymmetricGroup(4) sage: G.frattini_subgroup() - Subgroup generated by [()] of (Symmetric group of order 4! as a permutation group) + Subgroup generated by [()] of + (Symmetric group of order 4! as a permutation group) """ return self.subgroup(gap_group=self._libgap_().FrattiniSubgroup()) @@ -2359,10 +2379,12 @@ def fitting_subgroup(self): sage: G = PermutationGroup([[(1,2,3,4)],[(2,4)]]) sage: G.fitting_subgroup() - Subgroup generated by [(2,4), (1,2,3,4), (1,3)] of (Permutation Group with generators [(2,4), (1,2,3,4)]) + Subgroup generated by [(2,4), (1,2,3,4), (1,3)] of + (Permutation Group with generators [(2,4), (1,2,3,4)]) sage: G = PermutationGroup([[(1,2,3,4)],[(1,2)]]) sage: G.fitting_subgroup() - Subgroup generated by [(1,2)(3,4), (1,3)(2,4)] of (Permutation Group with generators [(1,2), (1,2,3,4)]) + Subgroup generated by [(1,2)(3,4), (1,3)(2,4)] of + (Permutation Group with generators [(1,2), (1,2,3,4)]) """ return self.subgroup(gap_group=self._libgap_().FittingSubgroup()) @@ -2378,10 +2400,12 @@ def solvable_radical(self): sage: G = SymmetricGroup(4) sage: G.solvable_radical() - Subgroup generated by [(1,2), (1,2,3,4)] of (Symmetric group of order 4! as a permutation group) + Subgroup generated by [(1,2), (1,2,3,4)] of + (Symmetric group of order 4! as a permutation group) sage: G = SymmetricGroup(5) sage: G.solvable_radical() - Subgroup generated by [()] of (Symmetric group of order 5! as a permutation group) + Subgroup generated by [()] of + (Symmetric group of order 5! as a permutation group) """ return self.subgroup(gap_group=self._libgap_().RadicalGroup()) @@ -2487,7 +2511,7 @@ def conjugate(self, g): INPUT: - - ``g`` - a permutation group element, or an object that converts + - ``g`` -- a permutation group element, or an object that converts to a permutation group element, such as a list of integers or a string of cycles. @@ -2581,28 +2605,27 @@ def direct_product(self, other, maps=True): INPUT: - - ``self, other`` - permutation groups + - ``self``, ``other`` -- permutation groups OUTPUT: - - ``D`` - a direct product of the inputs, returned as + - ``D`` -- a direct product of the inputs, returned as a permutation group as well - - ``iota1`` - an embedding of ``self`` into ``D`` + - ``iota1`` -- an embedding of ``self`` into ``D`` - - ``iota2`` - an embedding of ``other`` into ``D`` + - ``iota2`` -- an embedding of ``other`` into ``D`` - - ``pr1`` - the projection of ``D`` onto ``self`` (giving a - splitting 1 - other - D - self - 1) + - ``pr1`` -- the projection of ``D`` onto ``self`` (giving a + splitting ``1 - other - D - self - 1``) - - ``pr2`` - the projection of ``D`` onto ``other`` (giving a - splitting 1 - self - D - other - 1) + - ``pr2`` -- the projection of ``D`` onto ``other`` (giving a + splitting ``1 - self - D - other - 1``) EXAMPLES:: sage: G = CyclicPermutationGroup(4) - sage: D = G.direct_product(G,False) - sage: D + sage: D = G.direct_product(G, False); D Permutation Group with generators [(5,6,7,8), (1,2,3,4)] sage: D,iota1,iota2,pr1,pr2 = G.direct_product(G) sage: D; iota1; iota2; pr1; pr2 @@ -2655,22 +2678,22 @@ def semidirect_product(self, N, mapping, check=True): naturally embeds as a normal subgroup of the returned semidirect product. - - ``mapping`` - A pair of lists that together define a - homomorphism, `\phi :` self `\rightarrow` Aut(N), by giving, + - ``mapping`` -- A pair of lists that together define a + homomorphism, `\phi :` ``self`` `\rightarrow` Aut(``N``), by giving, in the second list, the images of the generators of ``self`` in the order given in the first list. - - ``check`` - A boolean that, if set to False, will skip the + - ``check`` -- A boolean that, if set to ``False``, will skip the initial tests which are made on ``mapping``. This may be beneficial for large ``N``, since in such cases the injectivity test can be - expensive. Set to True by default. + expensive. Set to ``True`` by default. OUTPUT: The semidirect product of ``self`` and ``N`` defined by the action of ``self`` on ``N`` given in ``mapping`` (note that a - homomorphism from A to the automorphism group of B is - equivalent to an action of A on the B's underlying set). The + homomorphism from `A` to the automorphism group of `B` is + equivalent to an action of `A` on `B`'s underlying set). The semidirect product of two groups, `H` and `N`, is a construct similar to the direct product in so far as the elements are the Cartesian product of the elements of `H` and the elements @@ -2737,7 +2760,8 @@ def semidirect_product(self, N, mapping, check=True): sage: S1.is_isomorphic(DiCyclicGroup(6)) False sage: S1.center() - Subgroup generated by [(1,3)(2,4)] of (Permutation Group with generators [(5,6,7), (1,2,3,4)(6,7), (1,3)]) + Subgroup generated by [(1,3)(2,4)] of + (Permutation Group with generators [(5,6,7), (1,2,3,4)(6,7), (1,3)]) sage: len(S1.conjugacy_classes_representatives()) 9 @@ -2853,7 +2877,8 @@ def holomorph(self): sage: A.is_abelian() False sage: A.center() - Subgroup generated by [()] of (Permutation Group with generators [(5,6,7,8,9), (1,2,4,3)(6,7,9,8)]) + Subgroup generated by [()] of + (Permutation Group with generators [(5,6,7,8,9), (1,2,4,3)(6,7,9,8)]) sage: A Permutation Group with generators [(5,6,7,8,9), (1,2,4,3)(6,7,9,8)] @@ -2901,14 +2926,15 @@ def subgroup(self, gens=None, gap_group=None, domain=None, category=None, canoni sage: G = PermutationGroup([(1,2,3),(3,4,5)]) sage: g = G((1,2,3)) sage: G.subgroup([g]) - Subgroup generated by [(1,2,3)] of (Permutation Group with generators [(3,4,5), (1,2,3)]) + Subgroup generated by [(1,2,3)] of + (Permutation Group with generators [(3,4,5), (1,2,3)]) """ return self.Subgroup(self, gens=gens, gap_group=gap_group, domain=None, category=category, canonicalize=canonicalize, check=check) def _subgroup_constructor(self, libgap_group): """ - this method is added for compatibility reason with the + This method is added for compatibility reason with the :meth:`sage.groups.libgap_wrapper.ParentLibGAP_subgroup_constructor` and for usage in :class:`sage.groups.libgap_morphism.GroupMorphism_libgap` @@ -2919,10 +2945,11 @@ def _subgroup_constructor(self, libgap_group): OUTPUT: - the corresponding subgroup of self as an instance of this class + The corresponding subgroup of ``self`` as an instance of this class EXAMPLES:: + sage: # needs sage.libs.pari sage: G = PGU(3,2); G The projective general unitary group of degree 3 over Finite Field of size 2 sage: g1, g2 = G.gens() @@ -2931,12 +2958,12 @@ def _subgroup_constructor(self, libgap_group): sage: type(Hgap) <class 'sage.libs.gap.element.GapElement'> sage: H = G._subgroup_constructor(Hgap); H - Subgroup generated by [(1,6,21,12,20,17)(2,10,15,9,11,5)(3,14,8)(4,18)(7,16)] of (The projective general unitary group of degree 3 over Finite Field of size 2) + Subgroup generated by [(1,6,21,12,20,17)(2,10,15,9,11,5)(3,14,8)(4,18)(7,16)] of + (The projective general unitary group of degree 3 over Finite Field of size 2) """ gens = [gen.sage() for gen in libgap_group.GeneratorsOfGroup()] return self.subgroup(gens=gens, gap_group=libgap_group) - def as_finitely_presented_group(self, reduced=False): """ Return a finitely presented group isomorphic to ``self``. @@ -2946,15 +2973,15 @@ def as_finitely_presented_group(self, reduced=False): INPUT: - - ``reduced`` -- Default ``False``, if ``True`` :meth:`FinitelyPresentedGroup.simplified + - ``reduced`` -- (default ``False``) if ``True``, :meth:`FinitelyPresentedGroup.simplified <sage.groups.finitely_presented.FinitelyPresentedGroup.simplified>` is called, attempting to simplify the presentation of the finitely presented group to be returned. OUTPUT: - Finite presentation of self, obtained by taking the image - of the isomorphism returned by the GAP function, ``IsomorphismFpGroupByGenerators``. + Finite presentation of ``self``, obtained by taking the image + of the isomorphism returned by the GAP function ``IsomorphismFpGroupByGenerators``. ALGORITHM: @@ -2981,9 +3008,10 @@ def as_finitely_presented_group(self, reduced=False): We can attempt to reduce the output presentation:: - sage: PermutationGroup(['(1,2,3,4,5)','(1,3,5,2,4)']).as_finitely_presented_group() + sage: H = PermutationGroup(['(1,2,3,4,5)', '(1,3,5,2,4)']) + sage: H.as_finitely_presented_group() Finitely presented group < a, b | b^-2*a^-1, b*a^-2 > - sage: PermutationGroup(['(1,2,3,4,5)','(1,3,5,2,4)']).as_finitely_presented_group(reduced=True) + sage: H.as_finitely_presented_group(reduced=True) Finitely presented group < a | a^5 > TESTS:: @@ -3079,11 +3107,11 @@ def commutator(self, other=None): INPUT: - - ``other`` - default: ``None`` - a permutation group. + - ``other`` -- (default: ``None``) a permutation group. OUTPUT: - Let `G` denote ``self``. If ``other`` is ``None`` then this method + Let `G` denote ``self``. If ``other`` is ``None``, then this method returns the subgroup of `G` generated by the set of commutators, .. MATH:: @@ -3186,16 +3214,16 @@ def cohomology(self, n, p=0): EXAMPLES:: sage: G = SymmetricGroup(4) - sage: G.cohomology(1,2) # optional - gap_packages + sage: G.cohomology(1,2) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 sage: G = SymmetricGroup(3) - sage: G.cohomology(5) # optional - gap_packages + sage: G.cohomology(5) # optional - gap_package_hap Trivial Abelian group - sage: G.cohomology(5,2) # optional - gap_packages + sage: G.cohomology(5,2) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 - sage: G.homology(5,3) # optional - gap_packages + sage: G.homology(5,3) # optional - gap_package_hap Trivial Abelian group - sage: G.homology(5,4) # optional - gap_packages + sage: G.homology(5,4) # optional - gap_package_hap Traceback (most recent call last): ... ValueError: p must be 0 or prime @@ -3238,10 +3266,10 @@ def cohomology_part(self, n, p=0): EXAMPLES:: sage: G = SymmetricGroup(5) - sage: G.cohomology_part(7,2) # optional - gap_packages + sage: G.cohomology_part(7,2) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 x C2 x C2 sage: G = SymmetricGroup(3) - sage: G.cohomology_part(2,3) # optional - gap_packages + sage: G.cohomology_part(2,3) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C3 AUTHORS: @@ -3276,19 +3304,18 @@ def homology(self, n, p=0): `H_7(S_5, \ZZ / 2 \ZZ)`, `H_7(S_5, \ZZ / 3 \ZZ)`, and `H_7(S_5, \ZZ / 5 \ZZ)`, respectively. To compute the - `2`-part of `H_7(S_5, \ZZ)`, use the ``homology_part`` - function. + `2`-part of `H_7(S_5, \ZZ)`, use the method :meth:`homology_part`. EXAMPLES:: sage: G = SymmetricGroup(5) - sage: G.homology(7) # optional - gap_packages + sage: G.homology(7) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 x C2 x C4 x C3 x C5 - sage: G.homology(7,2) # optional - gap_packages + sage: G.homology(7,2) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 x C2 x C2 x C2 x C2 - sage: G.homology(7,3) # optional - gap_packages + sage: G.homology(7,3) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C3 - sage: G.homology(7,5) # optional - gap_packages + sage: G.homology(7,5) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C5 REFERENCES: @@ -3320,7 +3347,7 @@ def homology_part(self, n, p=0): EXAMPLES:: sage: G = SymmetricGroup(5) - sage: G.homology_part(7,2) # optional - gap_packages + sage: G.homology_part(7,2) # optional - gap_package_hap Multiplicative Abelian group isomorphic to C2 x C2 x C2 x C2 x C4 AUTHORS: @@ -3351,7 +3378,7 @@ def character_table(self): sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3)]]) sage: G.order() 12 - sage: G.character_table() + sage: G.character_table() # needs sage.rings.number_field [ 1 1 1 1] [ 1 -zeta3 - 1 zeta3 1] [ 1 zeta3 -zeta3 - 1 1] @@ -3366,7 +3393,7 @@ def character_table(self): sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) sage: G.order() 8 - sage: G.character_table() + sage: G.character_table() # needs sage.rings.number_field [ 1 1 1 1 1] [ 1 -1 -1 1 1] [ 1 -1 1 -1 1] @@ -3378,6 +3405,7 @@ def character_table(self): :: + sage: # needs sage.rings.number_field sage: SymmetricGroup(2).character_table() [ 1 -1] [ 1 1] @@ -3394,7 +3422,10 @@ def character_table(self): [ 4 2 0 1 -1 0 -1] [ 1 1 1 1 1 1 1] sage: list(AlternatingGroup(6).character_table()) - [(1, 1, 1, 1, 1, 1, 1), (5, 1, 2, -1, -1, 0, 0), (5, 1, -1, 2, -1, 0, 0), (8, 0, -1, -1, 0, zeta5^3 + zeta5^2 + 1, -zeta5^3 - zeta5^2), (8, 0, -1, -1, 0, -zeta5^3 - zeta5^2, zeta5^3 + zeta5^2 + 1), (9, 1, 0, 0, 1, -1, -1), (10, -2, 1, 1, 0, 0, 0)] + [(1, 1, 1, 1, 1, 1, 1), (5, 1, 2, -1, -1, 0, 0), (5, 1, -1, 2, -1, 0, 0), + (8, 0, -1, -1, 0, zeta5^3 + zeta5^2 + 1, -zeta5^3 - zeta5^2), + (8, 0, -1, -1, 0, -zeta5^3 - zeta5^2, zeta5^3 + zeta5^2 + 1), + (9, 1, 0, 0, 1, -1, -1), (10, -2, 1, 1, 0, 0, 0)] Suppose that you have a class function `f(g)` on `G` and you know the values `v_1, \ldots, v_n` on @@ -3421,13 +3452,13 @@ def character_table(self): irrG = G.Irr() ct = [[irrG[i, j] for j in range(n)] for i in range(n)] - from sage.rings.all import CyclotomicField + from sage.rings.number_field.number_field import CyclotomicField e = irrG.Flat().Conductor() K = CyclotomicField(e) ct = [[K(x) for x in v] for v in ct] # Finally return the result as a matrix. - from sage.matrix.all import MatrixSpace + from sage.matrix.matrix_space import MatrixSpace MS = MatrixSpace(K, n) return MS(ct) @@ -3437,8 +3468,8 @@ def irreducible_characters(self): EXAMPLES:: - sage: irr = SymmetricGroup(3).irreducible_characters() - sage: [x.values() for x in irr] + sage: irr = SymmetricGroup(3).irreducible_characters() # needs sage.rings.number_field + sage: [x.values() for x in irr] # needs sage.rings.number_field [[1, -1, 1], [2, 0, -1], [1, 1, 1]] """ return [ClassFunction_libgap(self, irr) for irr in self._libgap_().Irr()] @@ -3449,7 +3480,7 @@ def trivial_character(self): EXAMPLES:: - sage: SymmetricGroup(3).trivial_character() + sage: SymmetricGroup(3).trivial_character() # needs sage.rings.number_field Character of Symmetric group of order 3! as a permutation group """ values = [1]*self._libgap_().NrConjugacyClasses().sage() @@ -3465,7 +3496,7 @@ def character(self, values): sage: G = AlternatingGroup(4) sage: n = len(G.conjugacy_classes_representatives()) - sage: G.character([1]*n) + sage: G.character([1]*n) # needs sage.rings.number_field Character of Alternating group of order 4!/2 as a permutation group """ return ClassFunction_libgap(self, values) @@ -3488,13 +3519,13 @@ def conjugacy_classes_representatives(self): :: sage: G = SymmetricGroup(5) - sage: G.conjugacy_classes_representatives() + sage: G.conjugacy_classes_representatives() # needs sage.combinat [(), (1,2), (1,2)(3,4), (1,2,3), (1,2,3)(4,5), (1,2,3,4), (1,2,3,4,5)] :: sage: S = SymmetricGroup(['a','b','c']) - sage: S.conjugacy_classes_representatives() + sage: S.conjugacy_classes_representatives() # needs sage.combinat [(), ('a','b'), ('a','b','c')] AUTHORS: @@ -3514,25 +3545,36 @@ def conjugacy_classes_subgroups(self): EXAMPLES:: sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) - sage: cl = G.conjugacy_classes_subgroups() - sage: cl - [Subgroup generated by [()] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), - Subgroup generated by [(1,2)(3,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), - Subgroup generated by [(1,3)(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), - Subgroup generated by [(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), - Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), - Subgroup generated by [(2,4), (1,3)(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), - Subgroup generated by [(1,2,3,4), (1,3)(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), - Subgroup generated by [(2,4), (1,2)(3,4), (1,4)(2,3)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)])] + sage: cl = G.conjugacy_classes_subgroups(); cl + [Subgroup generated by [()] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(1,2)(3,4)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(1,3)(2,4)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(2,4)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(2,4), (1,3)(2,4)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(1,2,3,4), (1,3)(2,4)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(2,4), (1,2)(3,4), (1,4)(2,3)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)])] :: sage: G = SymmetricGroup(3) sage: G.conjugacy_classes_subgroups() - [Subgroup generated by [()] of (Symmetric group of order 3! as a permutation group), - Subgroup generated by [(2,3)] of (Symmetric group of order 3! as a permutation group), - Subgroup generated by [(1,2,3)] of (Symmetric group of order 3! as a permutation group), - Subgroup generated by [(2,3), (1,2,3)] of (Symmetric group of order 3! as a permutation group)] + [Subgroup generated by [()] of + (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(2,3)] of + (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(1,2,3)] of + (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(2,3), (1,2,3)] of + (Symmetric group of order 3! as a permutation group)] AUTHORS: @@ -3574,19 +3616,30 @@ def subgroups(self): sage: G = SymmetricGroup(3) sage: G.subgroups() - [Subgroup generated by [()] of (Symmetric group of order 3! as a permutation group), - Subgroup generated by [(2,3)] of (Symmetric group of order 3! as a permutation group), - Subgroup generated by [(1,2)] of (Symmetric group of order 3! as a permutation group), - Subgroup generated by [(1,3)] of (Symmetric group of order 3! as a permutation group), - Subgroup generated by [(1,2,3)] of (Symmetric group of order 3! as a permutation group), - Subgroup generated by [(2,3), (1,2,3)] of (Symmetric group of order 3! as a permutation group)] + [Subgroup generated by [()] of + (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(2,3)] of + (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(1,2)] of + (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(1,3)] of + (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(1,2,3)] of + (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(2,3), (1,2,3)] of + (Symmetric group of order 3! as a permutation group)] sage: G = CyclicPermutationGroup(14) sage: G.subgroups() - [Subgroup generated by [()] of (Cyclic group of order 14 as a permutation group), - Subgroup generated by [(1,8)(2,9)(3,10)(4,11)(5,12)(6,13)(7,14)] of (Cyclic group of order 14 as a permutation group), - Subgroup generated by [(1,3,5,7,9,11,13)(2,4,6,8,10,12,14)] of (Cyclic group of order 14 as a permutation group), - Subgroup generated by [(1,2,3,4,5,6,7,8,9,10,11,12,13,14), (1,3,5,7,9,11,13)(2,4,6,8,10,12,14)] of (Cyclic group of order 14 as a permutation group)] + [Subgroup generated by [()] of + (Cyclic group of order 14 as a permutation group), + Subgroup generated by [(1,8)(2,9)(3,10)(4,11)(5,12)(6,13)(7,14)] of + (Cyclic group of order 14 as a permutation group), + Subgroup generated by [(1,3,5,7,9,11,13)(2,4,6,8,10,12,14)] of + (Cyclic group of order 14 as a permutation group), + Subgroup generated by [(1,2,3,4,5,6,7,8,9,10,11,12,13,14), + (1,3,5,7,9,11,13)(2,4,6,8,10,12,14)] of + (Cyclic group of order 14 as a permutation group)] AUTHOR: @@ -3635,9 +3688,9 @@ def has_regular_subgroup(self, return_group=False): INPUT: - - ``return_group`` (boolean) -- If ``return_group = True``, a regular + - ``return_group`` -- (boolean) If ``True``, a regular subgroup is returned if there is one, and ``None`` if there isn't. - When ``return_group = False`` (default), only a boolean indicating + When ``return_group=False`` (default), only a boolean indicating whether such a group exists is returned instead. EXAMPLES: @@ -3647,8 +3700,9 @@ def has_regular_subgroup(self, return_group=False): sage: S4 = groups.permutation.Symmetric(4) sage: S4.has_regular_subgroup() True - sage: S4.has_regular_subgroup(return_group = True) # random - Subgroup of (Symmetric group of order 4! as a permutation group) generated by [(1,3)(2,4), (1,4)(2,3)] + sage: S4.has_regular_subgroup(return_group=True) # random + Subgroup of (Symmetric group of order 4! as a permutation group) + generated by [(1,3)(2,4), (1,4)(2,3)] But the automorphism group of Petersen's graph does not:: @@ -3681,7 +3735,7 @@ def blocks_all(self, representatives=True): INPUT: - - ``representative`` (boolean) -- whether to return all possible block + - ``representative`` -- (boolean) whether to return all possible block systems of imprimitivity or only one of their representatives (the block can be obtained from its representative set `S` by computing the orbit of `S` under ``self``). @@ -3697,13 +3751,13 @@ def blocks_all(self, representatives=True): * A list of length (#number of different block systems) of - * block systems, each of them being defined as + * block systems, each of them being defined as - * If ``representatives = True`` : a list of representatives of - each set of the block system + * If ``representatives=True``: a list of representatives of + each set of the block system - * If ``representatives = False`` : a partition of the elements - defining an imprimitivity block. + * If ``representatives=False``: a partition of the elements + defining an imprimitivity block. .. SEEALSO:: @@ -3728,7 +3782,8 @@ def blocks_all(self, representatives=True): Now the full block:: sage: sorted(ag.blocks_all(representatives = False)[0]) - [[0, 15], [1, 16], [2, 12], [3, 13], [4, 9], [5, 10], [6, 11], [7, 18], [8, 17], [14, 19]] + [[0, 15], [1, 16], [2, 12], [3, 13], [4, 9], + [5, 10], [6, 11], [7, 18], [8, 17], [14, 19]] TESTS:: @@ -3753,13 +3808,13 @@ def cosets(self, S, side='right'): INPUT: - - ``S`` - a subgroup of ``self``. An error is raised + - ``S`` -- a subgroup of ``self``. An error is raised if ``S`` is not a subgroup. - - ``side`` - default: 'right' - determines if right cosets or + - ``side`` -- (default: ``'right'``) Determines if right cosets or left cosets are returned. ``side`` refers to where the representative is placed in the products forming the cosets - and thus allowable values are only 'right' and 'left'. + and thus allowable values are only ``'right'`` and ``'left'``. OUTPUT: @@ -3946,13 +4001,16 @@ def normalizer(self, g): sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) sage: g = G([(1,3)]) sage: G.normalizer(g) - Subgroup generated by [(2,4), (1,3)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) + Subgroup generated by [(2,4), (1,3)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) sage: g = G([(1,2,3,4)]) sage: G.normalizer(g) - Subgroup generated by [(2,4), (1,2,3,4), (1,3)(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) + Subgroup generated by [(2,4), (1,2,3,4), (1,3)(2,4)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) sage: H = G.subgroup([G([(1,2,3,4)])]) sage: G.normalizer(H) - Subgroup generated by [(2,4), (1,2,3,4), (1,3)(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) + Subgroup generated by [(2,4), (1,2,3,4), (1,3)(2,4)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) """ return self.subgroup(gap_group=self._libgap_().Normalizer(g)) @@ -3965,13 +4023,16 @@ def centralizer(self, g): sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) sage: g = G([(1,3)]) sage: G.centralizer(g) - Subgroup generated by [(2,4), (1,3)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) + Subgroup generated by [(2,4), (1,3)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) sage: g = G([(1,2,3,4)]) sage: G.centralizer(g) - Subgroup generated by [(1,2,3,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) + Subgroup generated by [(1,2,3,4)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) sage: H = G.subgroup([G([(1,2,3,4)])]) sage: G.centralizer(H) - Subgroup generated by [(1,2,3,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) + Subgroup generated by [(1,2,3,4)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) """ return self.subgroup(gap_group=self._libgap_().Centralizer(g)) @@ -4079,9 +4140,9 @@ def isomorphism_to(self, right): INPUT: - - ``self`` - this group + - ``self`` -- this group - - ``right`` - a permutation group + - ``right`` -- a permutation group OUTPUT: @@ -4132,9 +4193,9 @@ def is_isomorphic(self, right): INPUT: - - ``self`` - this group + - ``self`` -- this group - - ``right`` - a permutation group + - ``right`` -- a permutation group OUTPUT: @@ -4242,7 +4303,7 @@ def is_polycyclic(self): Return ``True`` if this group is polycyclic. A group is polycyclic if it has a subnormal series with cyclic factors. (For finite groups, this is the same as if the group is solvable - see - ``is_solvable``.) + :meth:`is_solvable`.) EXAMPLES:: @@ -4370,17 +4431,23 @@ def is_transitive(self, domain=None): :: - sage: G = PermutationGroup([[(1,2,3,4,5)],[(1,2)]]) #S_5 on [1..5] - sage: G.is_transitive([1,4,5]) + sage: G = PermutationGroup([[(1,2,3,4,5)],[(1,2)],[(6,7)]]) + sage: G.is_transitive([1,2,3,4,5]) True - sage: G.is_transitive([2..6]) + sage: G.is_transitive([1..7]) False sage: G.is_transitive(G.non_fixed_points()) - True + False sage: H = PermutationGroup([[(1,2,3)],[(4,5,6)]]) sage: H.is_transitive(H.non_fixed_points()) False + If `G` does not act on the domain, it always returns ``False``:: + + sage: G = PermutationGroup([[(1,2,3,4,5)],[(1,2)]]) #S_5 on [1..5] + sage: G.is_transitive([1,4,5]) + False + Note that this differs from the definition in GAP, where ``IsTransitive`` returns whether the group is transitive on the set of points moved by the group. @@ -4436,12 +4503,16 @@ def is_primitive(self, domain=None): sage: G = PermutationGroup([[(1,2,3,4)],[(2,4)]]) sage: G.is_primitive([1..4]) False - sage: G.is_primitive([1,2,3]) - True sage: G = PermutationGroup([[(3,4,5,6)],[(3,4)]]) #S_4 on [3..6] sage: G.is_primitive(G.non_fixed_points()) True + If `G` does not act on the domain, it always returns ``False``:: + + sage: G = PermutationGroup([[(1,2,3,4)],[(2,4)]]) + sage: G.is_primitive([1,2,3]) + False + """ #If the domain is not a subset of self.domain(), then the #action isn't primitive. @@ -4518,7 +4589,6 @@ def is_regular(self, domain=None): return False return bool(self._libgap_().IsRegular(domain)) - def normalizes(self, other): r""" Return ``True`` if the group ``other`` is normalized by ``self``. @@ -4564,13 +4634,17 @@ def composition_series(self): sage: set_random_seed(0) sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.composition_series() - [Subgroup generated by [(3,4), (1,2,3)(4,5)] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]), - Subgroup generated by [(1,3,5), (1,5)(3,4), (1,5)(2,4)] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]), - Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)])] + [Subgroup generated by [(3,4), (1,2,3)(4,5)] of + (Permutation Group with generators [(3,4), (1,2,3)(4,5)]), + Subgroup generated by [(1,3,5), (1,5)(3,4), (1,5)(2,4)] of + (Permutation Group with generators [(3,4), (1,2,3)(4,5)]), + Subgroup generated by [()] of + (Permutation Group with generators [(3,4), (1,2,3)(4,5)])] sage: G = PermutationGroup([[(1,2,3),(4,5)], [(1,2)]]) sage: CS = G.composition_series() sage: CS[3] - Subgroup generated by [()] of (Permutation Group with generators [(1,2), (1,2,3)(4,5)]) + Subgroup generated by [()] of + (Permutation Group with generators [(1,2), (1,2,3)(4,5)]) """ libgap.set_seed() CS = self._libgap_().CompositionSeries() @@ -4591,8 +4665,10 @@ def derived_series(self): sage: set_random_seed(0) sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.derived_series() - [Subgroup generated by [(3,4), (1,2,3)(4,5)] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]), - Subgroup generated by [(1,3,5), (1,5)(3,4), (1,5)(2,4)] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)])] + [Subgroup generated by [(3,4), (1,2,3)(4,5)] of + (Permutation Group with generators [(3,4), (1,2,3)(4,5)]), + Subgroup generated by [(1,3,5), (1,5)(3,4), (1,5)(2,4)] of + (Permutation Group with generators [(3,4), (1,2,3)(4,5)])] """ libgap.set_seed() DS = self._libgap_().DerivedSeries() @@ -4613,8 +4689,10 @@ def lower_central_series(self): sage: set_random_seed(0) sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.lower_central_series() - [Subgroup generated by [(3,4), (1,2,3)(4,5)] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]), - Subgroup generated by [(1,3,5), (1,5)(3,4), (1,5)(2,4)] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)])] + [Subgroup generated by [(3,4), (1,2,3)(4,5)] of + (Permutation Group with generators [(3,4), (1,2,3)(4,5)]), + Subgroup generated by [(1,3,5), (1,5)(3,4), (1,5)(2,4)] of + (Permutation Group with generators [(3,4), (1,2,3)(4,5)])] """ libgap.set_seed() LCS = self._libgap_().LowerCentralSeriesOfGroup() @@ -4691,11 +4769,11 @@ def molien_series(self): R(str(dd).replace("_1", ""))) def normal_subgroups(self): - """ + r""" Return the normal subgroups of this group as a (sorted in increasing order) list of permutation groups. - The normal subgroups of `H = PSL(2,7) \\times PSL(2,7)` are + The normal subgroups of `H = PSL(2,7) \times PSL(2,7)` are `1`, two copies of `PSL(2,7)` and `H` itself, as the following example shows. @@ -4730,10 +4808,10 @@ def poincare_series(self, p=2, n=10): EXAMPLES:: sage: G = SymmetricGroup(5) - sage: G.poincare_series(2,10) # optional - gap_packages + sage: G.poincare_series(2, 10) # optional - gap_package_hap (x^2 + 1)/(x^4 - x^3 - x + 1) sage: G = SymmetricGroup(3) - sage: G.poincare_series(2,10) # optional - gap_packages + sage: G.poincare_series(2, 10) # optional - gap_package_hap -1/(x - 1) AUTHORS: @@ -4742,7 +4820,7 @@ def poincare_series(self, p=2, n=10): """ load_hap() - from sage.arith.all import is_prime + from sage.arith.misc import is_prime if not (p == 0 or is_prime(p)): raise ValueError("p must be 0 or prime") @@ -4753,7 +4831,6 @@ def poincare_series(self, p=2, n=10): return (R(str(nn).replace('x_1', 'x')) / R(str(dd).replace('x_1', 'x'))) - def sylow_subgroup(self, p): """ Return a Sylow `p`-subgroup of the finite group `G`, where `p` is a @@ -4768,9 +4845,11 @@ def sylow_subgroup(self, p): sage: G = PermutationGroup(['(1,2,3)', '(2,3)']) sage: G.sylow_subgroup(2) - Subgroup generated by [(2,3)] of (Permutation Group with generators [(2,3), (1,2,3)]) + Subgroup generated by [(2,3)] of + (Permutation Group with generators [(2,3), (1,2,3)]) sage: G.sylow_subgroup(5) - Subgroup generated by [()] of (Permutation Group with generators [(2,3), (1,2,3)]) + Subgroup generated by [()] of + (Permutation Group with generators [(2,3), (1,2,3)]) TESTS: @@ -4795,13 +4874,15 @@ def upper_central_series(self): sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.upper_central_series() - [Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)])] + [Subgroup generated by [()] of + (Permutation Group with generators [(3,4), (1,2,3)(4,5)])] """ libgap.set_seed() UCS = self._libgap_().UpperCentralSeriesOfGroup() return [self.subgroup(gap_group=group) for group in UCS] from sage.groups.generic import structure_description + def sign_representation(self, base_ring=None, side="twosided"): r""" Return the sign representation of ``self`` over ``base_ring``. @@ -4825,7 +4906,6 @@ def sign_representation(self, base_ring=None, side="twosided"): return SignRepresentationPermgroup(self, base_ring) - class PermutationGroup_subgroup(PermutationGroup_generic): """ Subgroup subclass of ``PermutationGroup_generic``, so instance methods @@ -4837,7 +4917,8 @@ class PermutationGroup_subgroup(PermutationGroup_generic): sage: gens = G.gens() sage: H = DihedralGroup(4) sage: H.subgroup(gens) - Subgroup generated by [(1,2,3,4)] of (Dihedral group of order 8 as a permutation group) + Subgroup generated by [(1,2,3,4)] of + (Dihedral group of order 8 as a permutation group) sage: K = H.subgroup(gens) sage: K.list() [(), (1,2,3,4), (1,3)(2,4), (1,4,3,2)] @@ -4854,18 +4935,18 @@ def __init__(self, ambient, gens=None, gap_group=None, domain=None, INPUT: - - ``ambient`` - the ambient group from which to construct this + - ``ambient`` -- the ambient group from which to construct this subgroup - - ``gens`` - the generators of the subgroup + - ``gens`` -- the generators of the subgroup - - ``gap_group`` - a GAP permutation group contained in the ambient group; - constructed from ``gens`` if not given. + - ``gap_group`` -- a GAP permutation group contained in the ambient group; + constructed from ``gens`` if not given. - - ``check`` - ``True``: checks if ``gens`` are indeed elements of the + - ``check`` -- ``True``: checks if ``gens`` are indeed elements of the ambient group - - ``canonicalize`` - boolean (default: ``True``); if ``True``, sort + - ``canonicalize`` -- boolean (default: ``True``); if ``True``, sort generators and remove duplicates EXAMPLES: @@ -5059,7 +5140,6 @@ def ambient_group(self): """ return self._ambient_group - def is_normal(self, other=None): """ Return ``True`` if this group is a normal subgroup of @@ -5070,7 +5150,8 @@ def is_normal(self, other=None): sage: S = SymmetricGroup(['a','b','c']) sage: H = S.subgroup([('a', 'b', 'c')]); H - Subgroup generated by [('a','b','c')] of (Symmetric group of order 3! as a permutation group) + Subgroup generated by [('a','b','c')] of + (Symmetric group of order 3! as a permutation group) sage: H.is_normal() True @@ -5079,6 +5160,7 @@ def is_normal(self, other=None): other = self.ambient_group() return PermutationGroup_generic.is_normal(self, other) + # Allow for subclasses to use a different subgroup class PermutationGroup_generic.Subgroup = PermutationGroup_subgroup @@ -5092,9 +5174,9 @@ class PermutationGroup_action(PermutationGroup_generic): sage: n = 3 sage: a = lambda x: SetPartition([[e % n + 1 for e in b] for b in x]) - sage: S = SetPartitions(n) - sage: G = PermutationGroup(action=a, domain=S) - sage: G.orbits() + sage: S = SetPartitions(n) # needs sage.combinat + sage: G = PermutationGroup(action=a, domain=S) # needs sage.combinat + sage: G.orbits() # needs sage.combinat (({{1}, {2}, {3}},), ({{1, 2}, {3}}, {{1}, {2, 3}}, {{1, 3}, {2}}), ({{1, 2, 3}},)) @@ -5103,13 +5185,14 @@ class PermutationGroup_action(PermutationGroup_generic): sage: a = lambda g, x: g*x*g^-1 sage: S = SymmetricGroup(3) - sage: G = PermutationGroup(S.gens(), action=a, domain=S) - sage: G.orbits() + sage: G = PermutationGroup(S.gens(), action=a, domain=S) # needs sage.combinat + sage: G.orbits() # needs sage.combinat (((),), ((1,3,2), (1,2,3)), ((2,3), (1,3), (1,2))) The trivial action of the symmetric group:: - sage: PermutationGroup(SymmetricGroup(3).gens(), action=lambda g, x: x, domain=[1]) + sage: PermutationGroup(SymmetricGroup(3).gens(), # needs sage.combinat + ....: action=lambda g, x: x, domain=[1]) Permutation Group with generators [()] """ def __init__(self, gens, action, domain, gap_group=None, category=None, canonicalize=None): @@ -5139,8 +5222,8 @@ def __init__(self, gens, action, domain, gap_group=None, category=None, canonica EXAMPLES:: sage: a = lambda x: (2*x) % 7 - sage: G = PermutationGroup(action=a, domain=range(7)) - sage: G.orbits() + sage: G = PermutationGroup(action=a, domain=range(7)) # needs sage.combinat + sage: G.orbits() # needs sage.combinat ((0,), (1, 2, 4), (3, 6, 5)) """ @@ -5180,11 +5263,12 @@ def orbits(self): EXAMPLES:: sage: a = lambda x: (2*x) % 7 - sage: G = PermutationGroup(action=a, domain=range(7)) - sage: G.orbits() + sage: G = PermutationGroup(action=a, domain=range(7)) # needs sage.combinat + sage: G.orbits() # needs sage.combinat ((0,), (1, 2, 4), (3, 6, 5)) """ return self._orbits + from sage.misc.rest_index_of_methods import gen_rest_table_index __doc__ = __doc__.format(METHODS_OF_PermutationGroup_generic=gen_rest_table_index(PermutationGroup_generic)) diff --git a/src/sage/groups/perm_gps/permgroup_element.pxd b/src/sage/groups/perm_gps/permgroup_element.pxd index a2ac8f20eaa..0a584745f96 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pxd +++ b/src/sage/groups/perm_gps/permgroup_element.pxd @@ -22,7 +22,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): cpdef PermutationGroupElement _generate_new_GAP(self, old) cpdef _gap_list(self) cpdef domain(self) - cdef public __custom_name + cdef public _SageObject__custom_name cpdef list _act_on_list_on_position(self, list x) cpdef ClonableIntArray _act_on_array_on_position(self, ClonableIntArray x) cpdef ETuple _act_on_etuple_on_position(self, ETuple x) diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 6582bd16c00..2522b5c346d 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -86,6 +86,14 @@ We create element of a permutation group of large degree:: sage: G = SymmetricGroup(30) sage: s = G(srange(30,0,-1)); s (1,30)(2,29)(3,28)(4,27)(5,26)(6,25)(7,24)(8,23)(9,22)(10,21)(11,20)(12,19)(13,18)(14,17)(15,16) + +TESTS: + +Check that :trac:`13569` is fixed:: + + sage: [g*h for g in SymmetricGroup(3) for h in AlternatingGroup(3)] + [(), (1,2,3), (1,3,2), (1,3,2), (), (1,2,3), (1,2,3), (1,3,2), (), (2,3), + (1,2), (1,3), (1,3), (2,3), (1,2), (1,2), (1,3), (2,3)] """ # **************************************************************************** @@ -101,39 +109,38 @@ We create element of a permutation group of large degree:: # **************************************************************************** import copy -import random - -import sage.groups.old as group from libc.stdlib cimport qsort from cysignals.memory cimport sig_malloc, sig_calloc, sig_realloc, sig_free from cpython.list cimport * -from cypari2.gen cimport Gen +try: + from cypari2.gen import Gen +except ImportError: + Gen = () from sage.ext.stdsage cimport HAS_DICTIONARY -from sage.rings.all import ZZ, Integer -from sage.rings.polynomial.polynomial_element import is_Polynomial -from sage.rings.polynomial.multi_polynomial import is_MPolynomial -from sage.structure.element import is_Matrix -from sage.matrix.all import MatrixSpace +from sage.interfaces.abc import GpElement +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.multi_polynomial import MPolynomial +from sage.rings.polynomial.polynomial_element import Polynomial from sage.sets.finite_enumerated_set import FiniteEnumeratedSet -import sage.structure.coerce as coerce -from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool from sage.structure.coerce cimport coercion_model -from sage.interfaces.abc import GpElement +from sage.structure.element import is_Matrix +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool import sage.interfaces.abc from sage.libs.gap.libgap import libgap from sage.libs.gap.gap_includes cimport (UInt, UInt2, UInt4, T_PERM2, T_PERM4, - NEW_PERM2, NEW_PERM4, TNUM_OBJ, DEG_PERM2, DEG_PERM4, CONST_ADDR_PERM2, - CONST_ADDR_PERM4, ADDR_PERM2, ADDR_PERM4) + NEW_PERM2, TNUM_OBJ, DEG_PERM2, DEG_PERM4, CONST_ADDR_PERM2, + CONST_ADDR_PERM4, ADDR_PERM2) from sage.libs.gap.util cimport initialize from sage.libs.gap.element cimport (GapElement, GapElement_List, GapElement_String, GapElement_Permutation, make_GapElement_Permutation) -from sage.libs.gap.gap_includes cimport Obj, INT_INTOBJ, ELM_LIST +from sage.libs.gap.gap_includes cimport Obj, GAP_ValueInt, ELM_LIST import operator @@ -146,8 +153,8 @@ cdef int etuple_index_cmp(const void * a, const void * b) nogil: return ((<int *> a)[0] > (<int *> b)[0]) - ((<int *> a)[0] < (<int *> b)[0]) def make_permgroup_element(G, x): - """ - Returns a PermutationGroupElement given the permutation group + r""" + Return a :class:`PermutationGroupElement` given the permutation group ``G`` and the permutation ``x`` in list notation. This is function is used when unpickling old (pre-domain) versions @@ -166,8 +173,8 @@ def make_permgroup_element(G, x): return make_permgroup_element_v2(G, x, domain) def make_permgroup_element_v2(G, x, domain): - """ - Returns a PermutationGroupElement given the permutation group + r""" + Return a :class:`PermutationGroupElement` given the permutation group ``G``, the permutation ``x`` in list notation, and the domain ``domain`` of the permutation group. @@ -193,8 +200,8 @@ def make_permgroup_element_v2(G, x, domain): return G.element_class(x, G, check=False) def is_PermutationGroupElement(x): - """ - Returns True if ``x`` is a PermutationGroupElement. + r""" + Return ``True`` if ``x`` is a :class:`PermutationGroupElement`. EXAMPLES:: @@ -206,13 +213,12 @@ def is_PermutationGroupElement(x): return isinstance(x, PermutationGroupElement) cdef class PermutationGroupElement(MultiplicativeGroupElement): - """ + r""" An element of a permutation group. EXAMPLES:: - sage: G = PermutationGroup(['(1,2,3)(4,5)']) - sage: G + sage: G = PermutationGroup(['(1,2,3)(4,5)']); G Permutation Group with generators [(1,2,3)(4,5)] sage: g = G.random_element() sage: g in G @@ -257,7 +263,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): There are several ways to define a permutation group element: - Define a permutation group `G`, then use - ``G.gens()`` and multiplication \* to construct + ``G.gens()`` and multiplication ``*`` to construct elements. - Define a permutation group `G`, then use, e.g., @@ -273,9 +279,9 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): - ``g`` -- defines element - ``parent`` -- defines parent group (``g`` must be in - parent if specified, or a ``TypeError`` is raised) + parent if specified, or a :class:`TypeError` is raised) - - ``check`` - bool (default: ``True``); if ``False`` assumes ``g`` + - ``check`` -- bool (default: ``True``); if ``False`` assumes ``g`` is a gap element in parent (if specified) @@ -305,8 +311,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): :: - sage: g = G([(1,2),(3,5,6)]) - sage: g + sage: g = G([(1,2),(3,5,6)]); g (1,2)(3,5,6) sage: g.parent() Permutation Group with generators [(1,2)(3,4), (3,4,5,6)] @@ -323,15 +328,14 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): True We can also make a permutation group element directly using the - ``PermutationGroupElement`` command. Note that the + :class:`PermutationGroupElement` command. Note that the parent is then the full symmetric group `S_n`, where `n` is the largest integer that is moved by the permutation. :: - sage: k = PermutationGroupElement('(1,2)(3,5,6)') - sage: k + sage: k = PermutationGroupElement('(1,2)(3,5,6)'); k (1,2)(3,5,6) sage: k.parent() Symmetric group of order 6! as a permutation group @@ -363,11 +367,11 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): sage: S = SymmetricGroup(5) sage: S(Permutation([5,1,4,3,2])) (1,5,2)(3,4) - sage: S(gp.Vecsmall([5,1,4,3,2])) + sage: S(gp.Vecsmall([5,1,4,3,2])) # needs sage.libs.pari (1,5,2)(3,4) sage: S(gap.PermList([5,1,4,3,2])) (1,5,2)(3,4) - sage: S(pari.Vecsmall([5,1,4,3,2])) + sage: S(pari.Vecsmall([5,1,4,3,2])) # needs sage.libs.pari (1,5,2)(3,4) sage: S(libgap.PermList([5,1,4,3,2])) (1,5,2)(3,4) @@ -446,7 +450,6 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): ValueError: permutation (1,2) not in Permutation Group with generators [(1,2,3)] """ cdef int i, degree = parent.degree() - cdef PermutationGroupElement g_pge self._parent = parent self._alloc(degree) @@ -790,7 +793,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): def __reduce__(self): - """ + r""" Returns a function and its arguments needed to create this permutation group element. This is used in pickling. @@ -824,7 +827,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return other def _gap_(self, gap=None): - """ + r""" TESTS:: sage: g = PermutationGroupElement([(1,2,3),(4,5)]); g @@ -850,12 +853,14 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): sage: S(p_libgap) == p True + sage: # needs sage.rings.finite_rings sage: P = PGU(8,2) sage: p, q = P.gens() sage: p_libgap = p.gap() TESTS:: + sage: # needs sage.rings.finite_rings sage: P = PGU(8,2) sage: p, q = P.gens() sage: p_pexpect = gap(p) @@ -895,7 +900,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): gap = _libgap_ def _gap_init_(self): - """ + r""" Returns a GAP string representation for this PermutationGroupElement. @@ -907,9 +912,8 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): """ return 'PermList(%s)' % self._gap_list() - def _repr_(self): - """ + r""" Return string representation of this permutation. EXAMPLES: @@ -952,8 +956,8 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): for cycle in self.cycle_tuples()) def __getitem__(self, i): - """ - Return the ith permutation cycle in the disjoint cycle + r""" + Return the ``i``-th permutation cycle in the disjoint cycle representation of self. INPUT: @@ -974,7 +978,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return self.cycles()[i] cpdef _richcmp_(self, other, int op): - """ + r""" Compare group elements ``self`` and ``other``. EXAMPLES:: @@ -1020,7 +1024,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return rich_to_bool(op, 0) def __call__(self, i): - """ + r""" Returns the image of the integer i under this permutation. Alternately, if i is a list, tuple or string, returns the result of self acting on i. @@ -1042,7 +1046,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): :: - sage: g(x) + sage: g(x) # needs sage.symbolic Traceback (most recent call last): ... ValueError: must be in the domain or a list, tuple or string @@ -1083,7 +1087,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return from_gap[i] cpdef list _act_on_list_on_position(self, list x): - """ + r""" Returns the right action of ``self`` on the list ``x``. This is the action on positions. @@ -1111,7 +1115,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return [ x[self.perm[i]] for i in range(self.n) ] cpdef ClonableIntArray _act_on_array_on_position(self, ClonableIntArray x): - """ + r""" Returns the right action of ``self`` on the ClonableIntArray ``x``. This is the action on positions. @@ -1225,12 +1229,12 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): """ if not self_on_left: left = x - if is_Polynomial(left): + if isinstance(left, Polynomial): if self != 1: raise ValueError("%s does not act on %s" % (self, left.parent())) return left - elif is_MPolynomial(left): + elif isinstance(left, MPolynomial): R = left.parent() vars = R.gens() try: @@ -1295,7 +1299,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return coercion_model.bin_op(left, right, operator.mul) cpdef _mul_(left, _right): - """ + r""" EXAMPLES:: sage: S = SymmetricGroup(['a', 'b']) @@ -1312,7 +1316,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return prod cpdef PermutationGroupElement _generate_new(self, list v): - """ + r""" Generate a new permutation group element with the same parent as ``self`` from ``v``. @@ -1330,7 +1334,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return new cpdef PermutationGroupElement _generate_new_GAP(self, lst_in): - """ + r""" Generate a new permutation group element with the same parent as ``self`` from the GAP list ``lst_in``. @@ -1356,14 +1360,14 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): assert vn <= self.n for i in range(vn): - j = INT_INTOBJ(ELM_LIST(obj, i+1)) + j = GAP_ValueInt(ELM_LIST(obj, i+1)) new.perm[i] = j - 1 for i in range(vn, self.n): new.perm[i] = i return new def __invert__(self): - """ + r""" Return the inverse of this permutation. EXAMPLES:: @@ -1381,7 +1385,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return inv cpdef _gap_list(self): - """ + r""" Returns this permutation in list notation compatible with the GAP numbering. @@ -1405,7 +1409,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return [self.perm[i]+1 for i from 0 <= i < self.n] def _gap_cycle_string(self): - """ + r""" Returns a cycle string for this permutation compatible with the GAP numbering. @@ -1429,8 +1433,8 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return Permutation(self._gap_list()).cycle_string() cpdef domain(self): - """ - Returns the domain of self. + r""" + Return the domain of ``self``. EXAMPLES:: @@ -1462,7 +1466,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return [from_gap[self.perm[i]+1] for i from 0 <= i < self.n] def __hash__(self): - """ + r""" Return a hash for this permutation. EXAMPLES:: @@ -1491,8 +1495,8 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return ans def tuple(self): - """ - Return tuple of images of the domain under self. + r""" + Return tuple of images of the domain under ``self``. EXAMPLES:: @@ -1513,8 +1517,8 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return tuple([from_gap[self.perm[i]+1] for i in range(self.n)]) def dict(self): - """ - Returns a dictionary associating each element of the domain with its + r""" + Return a dictionary associating each element of the domain with its image. EXAMPLES:: @@ -1537,7 +1541,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return {e:from_gap[self.perm[i-1]+1] for e,i in to_gap.iteritems()} def multiplicative_order(self): - """ + r""" Return the order of this group element, which is the smallest positive integer `n` for which `g^n = 1`. @@ -1547,13 +1551,14 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): sage: s.multiplicative_order() 6 - ``order`` is just an alias for ``multiplicative_order``:: + :meth:`order` is just an alias for :meth:`multiplicative_order`:: sage: s.order() 6 TESTS:: + sage: # needs sage.libs.pari sage: prod(primes(150)) 1492182350939279320058875736615841068547583863326864530410 sage: L = [tuple(range(sum(primes(p))+1, sum(primes(p))+1+p)) for p in primes(150)] @@ -1567,8 +1572,9 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): cdef int cycle_len cdef int i, k cdef bint* seen = <bint *>sig_malloc(sizeof(bint) * self.n) - for i from 0 <= i < self.n: seen[i] = 0 - for i from 0 <= i < self.n: + for i in range(self.n): + seen[i] = 0 + for i in range(self.n): if seen[i] or self.perm[i] == i: continue k = self.perm[i] @@ -1588,7 +1594,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): def inverse(self): r""" - Returns the inverse permutation. + Return the inverse permutation. OUTPUT: @@ -1620,7 +1626,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): def sign(self): r""" - Returns the sign of self, which is `(-1)^{s}`, where + Return the sign of ``self``, which is `(-1)^{s}`, where `s` is the number of swaps. EXAMPLES:: @@ -1641,8 +1647,9 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): cdef int cycle_len_sum = 0 cdef int i, k cdef bint* seen = <bint *>sig_malloc(sizeof(bint) * self.n) - for i from 0 <= i < self.n: seen[i] = 0 - for i from 0 <= i < self.n: + for i in range(self.n): + seen[i] = 0 + for i in range(self.n): if seen[i] or self.perm[i] == i: continue k = self.perm[i] @@ -1655,8 +1662,8 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): def orbit(self, n, bint sorted=True): - """ - Returns the orbit of the integer `n` under this group + r""" + Return the orbit of the integer `n` under this group element, as a sorted list. EXAMPLES:: @@ -1699,8 +1706,8 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return from_gap[n] def cycles(self): - """ - Return self as a list of disjoint cycles. + r""" + Return ``self`` as a list of disjoint cycles. EXAMPLES:: @@ -1716,12 +1723,14 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): cdef PermutationGroupElement cycle cdef int i, j, k, next_k cdef bint* seen = <bint *>sig_malloc(sizeof(bint) * self.n) - for i from 0 <= i < self.n: seen[i] = 0 - for i from 0 <= i < self.n: + for i in range(self.n): + seen[i] = 0 + for i in range(self.n): if seen[i] or self.perm[i] == i: continue cycle = self._new_c() - for j from 0 <= j < self.n: cycle.perm[j] = j + for j in range(self.n): + cycle.perm[j] = j k = cycle.perm[i] = self.perm[i] while k != i: seen[k] = 1 @@ -1732,13 +1741,13 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return L def cycle_tuples(self, singletons=False): - """ - Return self as a list of disjoint cycles, represented as tuples + r""" + Return ``self`` as a list of disjoint cycles, represented as tuples rather than permutation group elements. INPUT: - - ``singletons`` - boolean (default: False) whether or not consider the + - ``singletons`` -- boolean (default: ``False``) whether or not consider the cycle that correspond to fixed point EXAMPLES:: @@ -1767,8 +1776,9 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): L = [] cdef int i, k cdef bint* seen = <bint *>sig_malloc(sizeof(bint) * self.n) - for i from 0 <= i < self.n: seen[i] = 0 - for i from 0 <= i < self.n: + for i in range(self.n): + seen[i] = 0 + for i in range(self.n): if seen[i]: continue if self.perm[i] == i: @@ -1790,10 +1800,10 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return L def cycle_string(self, singletons=False): - """ + r""" Return string representation of this permutation. - EXAMPLES:: + EXAMPLES:: sage: g = PermutationGroupElement([(1,2,3),(4,5)]) sage: g.cycle_string() @@ -1811,29 +1821,30 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): def cycle_type(self, singletons=True, as_list=False): r""" - Return the partition that gives the cycle type of ``g`` as an element of - ``self``. + Return the partition that gives the cycle type of ``self`` as an element of + its parent. INPUT: - ``g`` -- an element of the permutation group ``self.parent()`` - - ``singletons`` -- ``True`` or ``False`` depending on whether on or not + - ``singletons`` -- ``True`` or ``False`` depending on whether or not trivial cycles should be counted (default: ``True``) - ``as_list`` -- ``True`` or ``False`` depending on whether the cycle - type should be returned as a ``list`` or as a :class:`Partition` + type should be returned as a :class:`list` or as a :class:`Partition` (default: ``False``) OUTPUT: - A :class:`Partition`, or list if ``is_list`` is ``True``, - giving the cycle type of ``g`` + A :class:`Partition`, or :class:`list` if ``is_list`` is ``True``, + giving the cycle type of ``self`` - If speed is a concern then ``as_list=True`` should be used. + If speed is a concern, then ``as_list=True`` should be used. EXAMPLES:: + sage: # needs sage.combinat sage: G = DihedralGroup(3) sage: [g.cycle_type() for g in G] [[1, 1, 1], [3], [3], [2, 1], [2, 1], [2, 1]] @@ -1861,11 +1872,11 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): INPUT: - ``i`` -- an element of the index set - - ``side`` -- "left" or "right" (default: "right") - - ``positive`` -- a boolean (default: False) + - ``side`` -- ``"left"`` or ``"right"`` (default: ``"right"``) + - ``positive`` -- a boolean (default: ``False``) Returns whether ``self`` has a left (resp. right) descent at - position ``i``. If ``positive`` is True, then test for a non + position ``i``. If ``positive`` is ``True``, then test for a non descent instead. Beware that, since permutations are acting on the right, the @@ -1882,13 +1893,13 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): False sage: s = S.simple_reflections() sage: x = s[1]*s[2] - sage: x.has_descent(1, side = "right") + sage: x.has_descent(1, side="right") False - sage: x.has_descent(2, side = "right") + sage: x.has_descent(2, side="right") True - sage: x.has_descent(1, side = "left") + sage: x.has_descent(1, side="left") True - sage: x.has_descent(2, side = "left") + sage: x.has_descent(2, side="left") False sage: S._test_has_descent() @@ -1915,9 +1926,9 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return (to_gap[self(i)] > to_gap[self(i1)]) is not positive def matrix(self): - """ - Returns deg x deg permutation matrix associated to the permutation - self + r""" + Return a deg `\times` deg permutation matrix associated to the permutation + ``self``. EXAMPLES:: @@ -1930,6 +1941,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): [0 0 0 0 1] [0 0 0 1 0] """ + from sage.matrix.matrix_space import MatrixSpace M = MatrixSpace(ZZ, self.n, self.n, sparse=True) cdef int i entries = {} @@ -1938,7 +1950,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return M(entries) def word_problem(self, words, display=True, as_list=False): - """ + r""" Try to solve the word problem for ``self``. INPUT: @@ -1970,8 +1982,8 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): This function does not solve the word problem in Sage. Rather it pushes it over to GAP, which has optimized algorithms for the word problem. Essentially, this function is a wrapper for the GAP - functions "EpimorphismFromFreeGroup" and - "PreImagesRepresentative". + functions ``EpimorphismFromFreeGroup`` and + ``PreImagesRepresentative``. EXAMPLES:: @@ -2036,11 +2048,11 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): cdef class SymmetricGroupElement(PermutationGroupElement): - """ + r""" An element of the symmetric group. """ def absolute_length(self): - """ + r""" Return the absolute length of ``self``. The absolute length is the size minus the number of its disjoint @@ -2054,14 +2066,14 @@ cdef class SymmetricGroupElement(PermutationGroupElement): EXAMPLES:: sage: S = SymmetricGroup(3) - sage: [x.absolute_length() for x in S] + sage: [x.absolute_length() for x in S] # needs sage.combinat [0, 2, 2, 1, 1, 1] """ from sage.combinat.permutation import Permutation return Permutation(self).absolute_length() def has_left_descent(self, i): - """ + r""" Return whether `i` is a left descent of ``self``. EXAMPLES:: @@ -2075,7 +2087,7 @@ cdef class SymmetricGroupElement(PermutationGroupElement): cdef bint is_valid_permutation(int* perm, int n): - """ + r""" This is used in the __init__ method. Returns True iff the first n elements of perm are literally a diff --git a/src/sage/groups/perm_gps/permgroup_morphism.py b/src/sage/groups/perm_gps/permgroup_morphism.py index 917ddd01865..0a86068790b 100644 --- a/src/sage/groups/perm_gps/permgroup_morphism.py +++ b/src/sage/groups/perm_gps/permgroup_morphism.py @@ -15,7 +15,8 @@ sage: g = G([(1,2,3,4)]) sage: phi = PermutationGroupMorphism_im_gens(G, H, map(H, G.gens())) sage: phi.image(G) - Subgroup generated by [(1,2,3,4)] of (Dihedral group of order 8 as a permutation group) + Subgroup generated by [(1,2,3,4)] of + (Dihedral group of order 8 as a permutation group) sage: phi.kernel() Subgroup generated by [()] of (Cyclic group of order 4 as a permutation group) sage: phi.image(g) @@ -42,11 +43,11 @@ class PermutationGroupMorphism(Morphism): - """ + r""" A set-theoretic map between PermutationGroups. """ def _repr_type(self): - """ + r""" Return the type of this morphism. This is used for printing the morphism. @@ -61,7 +62,7 @@ def _repr_type(self): return "Permutation group" def kernel(self): - """ + r""" Return the kernel of this homomorphism as a permutation group. EXAMPLES:: @@ -71,7 +72,8 @@ def kernel(self): sage: g = G([(1,2,3,4)]) sage: phi = PermutationGroupMorphism_im_gens(G, H, [1]) sage: phi.kernel() - Subgroup generated by [(1,2,3,4)] of (Cyclic group of order 4 as a permutation group) + Subgroup generated by [(1,2,3,4)] of + (Cyclic group of order 4 as a permutation group) :: @@ -85,9 +87,10 @@ def kernel(self): return self.domain().subgroup(gap_group=self._gap_().Kernel()) def image(self, J): - """ - J must be a subgroup of G. Computes the subgroup of H which is the - image of J. + r""" + Compute the subgroup of the codomain `H` which is the image of `J`. + + `J` must be a subgroup of the domain `G`. EXAMPLES:: @@ -96,7 +99,8 @@ def image(self, J): sage: g = G([(1,2,3,4)]) sage: phi = PermutationGroupMorphism_im_gens(G, H, map(H, G.gens())) sage: phi.image(G) - Subgroup generated by [(1,2,3,4)] of (Dihedral group of order 8 as a permutation group) + Subgroup generated by [(1,2,3,4)] of + (Dihedral group of order 8 as a permutation group) sage: phi.image(g) (1,2,3,4) @@ -107,12 +111,14 @@ def image(self, J): sage: H = D[0] sage: pr1 = D[3] sage: pr1.image(G) - Subgroup generated by [(3,7,5)(4,8,6), (1,2,6)(3,4,8)] of (The projective special linear group of degree 2 over Finite Field of size 7) + Subgroup generated by [(3,7,5)(4,8,6), (1,2,6)(3,4,8)] of + (The projective special linear group of degree 2 over Finite Field of size 7) sage: G.is_isomorphic(pr1.image(G)) True Check that :trac:`28324` is fixed:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: f = x^4 + x^2 - 3 sage: L.<a> = f.splitting_field() @@ -134,9 +140,9 @@ def image(self, J): return H.subgroup(gap_group=G) def __call__(self, g): - """ - Some python code for wrapping GAP's Images function but only for - permutation groups. This returns an error if g is not in G. + r""" + Some python code for wrapping GAP's ``Images`` function but only for + permutation groups. This raises an error if g is not in G. EXAMPLES:: @@ -157,18 +163,18 @@ class PermutationGroupMorphism_id(PermutationGroupMorphism): class PermutationGroupMorphism_from_gap(PermutationGroupMorphism): def __init__(self, G, H, gap_hom): - """ + r""" This is a Python trick to allow Sage programmers to create a group homomorphism using GAP using very general constructions. An example of its usage is in the direct_product instance method of the - PermutationGroup_generic class in permgroup.py. + :class:`PermutationGroup_generic` class in permgroup.py. Basic syntax: - PermutationGroupMorphism_from_gap(domain_group, - range_group,'phi:=gap_hom_command;','phi') And don't forget the - line: from sage.groups.perm_gps.permgroup_morphism import - PermutationGroupMorphism_from_gap in your program. + ``PermutationGroupMorphism_from_gap(domain_group, + range_group, 'phi:=gap_hom_command;', 'phi')``. And don't forget the + line: ``from sage.groups.perm_gps.permgroup_morphism import + PermutationGroupMorphism_from_gap`` in your program. EXAMPLES:: @@ -177,7 +183,8 @@ def __init__(self, G, H, gap_hom): sage: H = G.subgroup([G([(1,2,3,4)])]) sage: PermutationGroupMorphism_from_gap(H, G, gap.Identity) Permutation group morphism: - From: Subgroup generated by [(1,2,3,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) + From: Subgroup generated by [(1,2,3,4)] of + (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) To: Permutation Group with generators [(1,2)(3,4), (1,2,3,4)] Defn: Identity """ @@ -187,7 +194,7 @@ def __init__(self, G, H, gap_hom): self._gap_hom = gap_hom def _repr_defn(self): - """ + r""" Return the definition of this morphism. This is used when printing the morphism. @@ -204,7 +211,7 @@ def _repr_defn(self): return str(self._gap_hom).replace('\n', '') def _gap_(self, gap=None): - """ + r""" Return a GAP version of this morphism. EXAMPLES:: @@ -219,7 +226,7 @@ def _gap_(self, gap=None): return self._gap_hom def __call__(self, g): - """ + r""" Some python code for wrapping GAP's Images function but only for permutation groups. This returns an error if g is not in G. @@ -237,8 +244,8 @@ def __call__(self, g): class PermutationGroupMorphism_im_gens(PermutationGroupMorphism): def __init__(self, G, H, gens=None): - """ - Some python code for wrapping GAP's GroupHomomorphismByImages + r""" + Some python code for wrapping GAP's ``GroupHomomorphismByImages`` function but only for permutation groups. Can be expensive if G is large. This returns "fail" if gens does not generate self or if the map does not extend to a group homomorphism, self - other. @@ -273,7 +280,7 @@ def __init__(self, G, H, gens=None): self._images = [H(img) for img in gens] def _repr_defn(self): - """ + r""" Return the definition of this morphism. This is used when printing the morphism. @@ -289,7 +296,7 @@ def _repr_defn(self): return "%s -> %s" % (list(self.domain().gens()), self._images) def _gap_(self): - """ + r""" Return a GAP representation of this morphism. EXAMPLES:: @@ -305,8 +312,8 @@ def _gap_(self): def is_PermutationGroupMorphism(f) -> bool: - """ - Return True if the argument ``f`` is a PermutationGroupMorphism. + r""" + Return ``True`` if the argument ``f`` is a :class:`PermutationGroupMorphism`. EXAMPLES:: diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 0381e1912a1..14187399ba6 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -3,63 +3,64 @@ You can construct the following permutation groups: --- SymmetricGroup, `S_n` of order `n!` (n can also be a list `X` of distinct - positive integers, in which case it returns `S_X`) +- :class:`SymmetricGroup`, `S_n` of order `n!` (`n` can also be a list `X` of distinct + positive integers, in which case it returns `S_X`) --- AlternatingGroup, `A_n` of order `n!/2` (n can also be a list `X` - of distinct positive integers, in which case it returns - `A_X`) +- :class:`AlternatingGroup`, `A_n` of order `n!/2` (n can also be a list `X` + of distinct positive integers, in which case it returns `A_X`) --- DihedralGroup, `D_n` of order `2n` +- :class:`DihedralGroup`, `D_n` of order `2n` --- GeneralDihedralGroup, `Dih(G)`, where G is an abelian group +- :class:`GeneralDihedralGroup`, `Dih(G)`, where `G` is an abelian group --- CyclicPermutationGroup, `C_n` of order `n` +- :class:`CyclicPermutationGroup`, `C_n` of order `n` --- DiCyclicGroup, nonabelian groups of order `4m` with a unique element of order 2 +- :class:`DiCyclicGroup`, nonabelian groups of order `4m` with a unique element of order 2 --- TransitiveGroup, `n^{th}` transitive group of degree `d` - from the GAP tables of transitive groups +- :class:`TransitiveGroup`, `n`-th` transitive group of degree `d` + from the GAP tables of transitive groups --- TransitiveGroups(d), TransitiveGroups(), set of all of the above +- ``TransitiveGroups(d)``, ``TransitiveGroups()``, set of all of the above --- PrimitiveGroup, `n^{th}` primitive group of degree `d` - from the GAP tables of primitive groups +- :class:`PrimitiveGroup`, `n`-th` primitive group of degree `d` + from the GAP tables of primitive groups --- PrimitiveGroups(d), PrimitiveGroups(), set of all of the above +- ``PrimitiveGroups(d)``, ``PrimitiveGroups()``, set of all of the above --- MathieuGroup(degree), Mathieu group of degree 9, 10, 11, 12, 21, 22, 23, or 24. +- ``MathieuGroup(degree)``, Mathieu group of degree 9, 10, 11, 12, 21, 22, 23, or 24. --- KleinFourGroup, subgroup of `S_4` of order `4` which is not `C_2 \times C_2` +- :class:`KleinFourGroup`, subgroup of `S_4` of order `4` which is not `C_2 \times C_2` --- QuaternionGroup, non-abelian group of order `8`, `\{\pm 1, \pm I, \pm J, \pm K\}` +- :class:`QuaternionGroup`, non-abelian group of order `8`, `\{\pm 1, \pm I, \pm J, \pm K\}` --- SplitMetacyclicGroup, nonabelian groups of order `p^m` with cyclic -subgroups of index p +- :class:`SplitMetacyclicGroup`, nonabelian groups of order `p^m` with cyclic + subgroups of index p --- SemidihedralGroup, nonabelian 2-groups with cyclic subgroups of index 2 +- :class:`SemidihedralGroup`, nonabelian 2-groups with cyclic subgroups of index 2 --- PGL(n,q), projective general linear group of `n\times n` matrices over - the finite field GF(q) +- ``PGL(n,q)``, projective general linear group of `n\times n` matrices over + the finite field `\GF(q)` --- PSL(n,q), projective special linear group of `n\times n` matrices over - the finite field GF(q) +- ``PSL(n,q)``, projective special linear group of `n\times n` matrices over + the finite field `\GF(q)` --- PSp(2n,q), projective symplectic linear group of `2n\times 2n` matrices - over the finite field GF(q) +- ``PSp(2n,q)``, projective symplectic linear group of `2n\times 2n` matrices + over the finite field `\GF(q)` --- PSU(n,q), projective special unitary group of `n \times n` matrices having - coefficients in the finite field `GF(q^2)` that respect a - fixed nondegenerate sesquilinear form, of determinant 1. +- ``PSU(n,q)``, projective special unitary group of `n \times n` matrices having + coefficients in the finite field `\GF(q^2)` that respect a + fixed nondegenerate sesquilinear form, of determinant 1. --- PGU(n,q), projective general unitary group of `n\times n` matrices having - coefficients in the finite field `GF(q^2)` that respect a - fixed nondegenerate sesquilinear form, modulo the centre. +- ``PGU(n,q)``, projective general unitary group of `n\times n` matrices having + coefficients in the finite field `\GF(q^2)` that respect a + fixed nondegenerate sesquilinear form, modulo the centre. --- SuzukiGroup(q), Suzuki group over GF(q), `^2 B_2(2^{2k+1}) = Sz(2^{2k+1})`. +- ``SuzukiGroup(q)``, Suzuki group over `\GF(q)`, `^2 B_2(2^{2k+1}) = Sz(2^{2k+1})`. --- ComplexReflectionGroup, the complex reflection group `G(m, p, n)` or - the exceptional complex reflection group `G_m` +- :class:`ComplexReflectionGroup`, the complex reflection group `G(m, p, n)` or + the exceptional complex reflection group `G_m` + +- :class:`SmallPermutationGroup`, a permutation realization of a group specified by its GAP id. AUTHOR: @@ -86,24 +87,24 @@ # **************************************************************************** from pathlib import Path -from sage.rings.all import Integer -from sage.libs.gap.libgap import libgap -from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from sage.arith.all import factor, valuation +from sage.arith.misc import factor, valuation +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.groups.abelian_gps.abelian_group import AbelianGroup -from sage.misc.functional import is_even -from sage.misc.cachefunc import cached_method, weak_cached_function from sage.groups.perm_gps.permgroup import PermutationGroup_generic from sage.groups.perm_gps.permgroup_element import SymmetricGroupElement -from sage.structure.unique_representation import CachedRepresentation -from sage.structure.parent import Parent -from sage.structure.richcmp import richcmp -from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.sets.finite_enumerated_set import FiniteEnumeratedSet +from sage.libs.gap.libgap import libgap +from sage.misc.cachefunc import cached_method, weak_cached_function +from sage.misc.functional import is_even +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.integer import Integer from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets -from sage.sets.non_negative_integers import NonNegativeIntegers from sage.sets.family import Family +from sage.sets.finite_enumerated_set import FiniteEnumeratedSet +from sage.sets.non_negative_integers import NonNegativeIntegers from sage.sets.primes import Primes +from sage.structure.parent import Parent +from sage.structure.richcmp import richcmp +from sage.structure.unique_representation import CachedRepresentation class PermutationGroup_unique(CachedRepresentation, PermutationGroup_generic): @@ -132,7 +133,7 @@ def __classcall__(cls, *args, **kwds): EXAMPLES:: - sage: SymmetricGroup(['a','b']).domain() #indirect doctest + sage: SymmetricGroup(['a','b']).domain() # indirect doctest {'a', 'b'} """ domain = kwds.pop('domain', None) @@ -146,7 +147,7 @@ def __classcall__(cls, *args, **kwds): class PermutationGroup_symalt(PermutationGroup_unique): """ This is a class used to factor out some of the commonality - in the SymmetricGroup and AlternatingGroup classes. + in the :class:`SymmetricGroup` and :class:`AlternatingGroup` classes. """ @staticmethod @@ -242,6 +243,12 @@ class SymmetricGroup(PermutationGroup_symalt): sage: groups.permutation.Symmetric(4) Symmetric group of order 4! as a permutation group + sage: groups.permutation.Symmetric(1).gens() + () + + Check for :issue:`36204`:: + + sage: h = SymmetricGroup(1).hom(SymmetricGroup(2)) """ def __init__(self, domain=None): """ @@ -249,9 +256,9 @@ def __init__(self, domain=None): TESTS:: - sage: TestSuite(SymmetricGroup(0)).run() - sage: TestSuite(SymmetricGroup(1)).run() - sage: TestSuite(SymmetricGroup(3)).run() + sage: TestSuite(SymmetricGroup(0)).run() # needs sage.rings.number_field + sage: TestSuite(SymmetricGroup(1)).run() # needs sage.rings.number_field + sage: TestSuite(SymmetricGroup(3)).run() # needs sage.rings.number_field """ from sage.categories.finite_weyl_groups import FiniteWeylGroups from sage.categories.finite_permutation_groups import FinitePermutationGroups @@ -260,7 +267,8 @@ def __init__(self, domain=None): # Note that we skip the call to the superclass initializer in order to # avoid infinite recursion since SymmetricGroup is called by # PermutationGroupElement - cat = Category.join([FinitePermutationGroups(), FiniteWeylGroups().Irreducible()]) + cat = Category.join([FinitePermutationGroups(), + FiniteWeylGroups().Irreducible()]) super(PermutationGroup_generic, self).__init__(category=cat) self._domain = domain @@ -269,11 +277,14 @@ def __init__(self, domain=None): self._domain_from_gap = {i+1: key for i, key in enumerate(self._domain)} # Create the generators for the symmetric group - gens = [tuple(self._domain)] - if len(self._domain) > 2: - gens.append(tuple(self._domain[:2])) - self._gens = tuple([self.element_class(g, self, check=False) - for g in gens]) + if self._deg <= 1: + self._gens = () + else: + gens = [tuple(self._domain)] + if self._deg > 2: + gens.append(tuple(self._domain[:2])) + self._gens = tuple([self.element_class(g, self, check=False) + for g in gens]) def _gap_init_(self, gap=None): """ @@ -337,14 +348,14 @@ def _coerce_map_from_(self, G): EXAMPLES:: - sage: J3 = groups.misc.Cactus(3) + sage: J3 = groups.misc.Cactus(3) # needs sage.rings.number_field sage: S5 = SymmetricGroup(5) - sage: S5.coerce_map_from(J3) + sage: S5.coerce_map_from(J3) # needs sage.rings.number_field Conversion via _from_cactus_group_element map: From: Cactus Group with 3 fruit To: Symmetric group of order 5! as a permutation group sage: S2 = SymmetricGroup(2) - sage: S2._coerce_map_from_(J3) is None + sage: S2._coerce_map_from_(J3) is None # needs sage.rings.number_field True """ from sage.groups.cactus_group import CactusGroup @@ -358,6 +369,7 @@ def _from_cactus_group_element(self, x): EXAMPLES:: + sage: # needs sage.rings.number_field sage: J3 = groups.misc.Cactus(3) sage: s12,s13,s23 = J3.gens() sage: elt = s12*s23*s13 @@ -390,7 +402,7 @@ def coxeter_matrix(self): EXAMPLES:: - sage: A = SymmetricGroup([2,3,7,'a']); A.coxeter_matrix() + sage: A = SymmetricGroup([2,3,7,'a']); A.coxeter_matrix() # needs sage.graphs [1 3 2] [3 1 3] [2 3 1] @@ -399,7 +411,7 @@ def coxeter_matrix(self): def simple_reflection(self, i): r""" - For `i` in the index set of ``self``, this returns the + For `i` in the index set of ``self``, return the elementary transposition `s_i = (i,i+1)`. EXAMPLES:: @@ -437,11 +449,13 @@ def young_subgroup(self, comp): sage: S = SymmetricGroup(8) sage: c = Composition([2,2,2,2]) sage: S.young_subgroup(c) - Subgroup generated by [(7,8), (5,6), (3,4), (1,2)] of (Symmetric group of order 8! as a permutation group) + Subgroup generated by [(7,8), (5,6), (3,4), (1,2)] of + (Symmetric group of order 8! as a permutation group) sage: S = SymmetricGroup(['a','b','c']) sage: S.young_subgroup([2,1]) - Subgroup generated by [('a','b')] of (Symmetric group of order 3! as a permutation group) + Subgroup generated by [('a','b')] of + (Symmetric group of order 3! as a permutation group) sage: Y = S.young_subgroup([2,2,2,2,2]) Traceback (most recent call last): @@ -481,10 +495,10 @@ def major_index(self, parameter=None): EXAMPLES:: sage: S4 = SymmetricGroup(4) - sage: S4.major_index() + sage: S4.major_index() # needs sage.combinat q^6 + 3*q^5 + 5*q^4 + 6*q^3 + 5*q^2 + 3*q + 1 sage: K.<t> = QQ[] - sage: S4.major_index(t) + sage: S4.major_index(t) # needs sage.combinat t^6 + 3*t^5 + 5*t^4 + 6*t^3 + 5*t^2 + 3*t + 1 """ from sage.combinat.q_analogues import q_factorial @@ -503,14 +517,14 @@ def conjugacy_classes_representatives(self): EXAMPLES:: sage: G = SymmetricGroup(5) - sage: G.conjugacy_classes_representatives() + sage: G.conjugacy_classes_representatives() # needs sage.combinat [(), (1,2), (1,2)(3,4), (1,2,3), (1,2,3)(4,5), (1,2,3,4), (1,2,3,4,5)] :: sage: S = SymmetricGroup(['a','b','c']) - sage: S.conjugacy_classes_representatives() + sage: S.conjugacy_classes_representatives() # needs sage.combinat [(), ('a','b'), ('a','b','c')] TESTS: @@ -518,10 +532,10 @@ def conjugacy_classes_representatives(self): Check some border cases:: sage: S = SymmetricGroup(0) - sage: S.conjugacy_classes_representatives() + sage: S.conjugacy_classes_representatives() # needs sage.combinat [()] sage: S = SymmetricGroup(1) - sage: S.conjugacy_classes_representatives() + sage: S.conjugacy_classes_representatives() # needs sage.combinat [()] """ from sage.combinat.partition import Partitions_n @@ -537,7 +551,7 @@ def conjugacy_classes_iterator(self): EXAMPLES:: sage: G = SymmetricGroup(5) - sage: list(G.conjugacy_classes_iterator()) == G.conjugacy_classes() + sage: list(G.conjugacy_classes_iterator()) == G.conjugacy_classes() # needs sage.combinat True """ from sage.combinat.partition import Partitions_n @@ -553,7 +567,7 @@ def conjugacy_classes(self): EXAMPLES:: sage: G = SymmetricGroup(5) - sage: G.conjugacy_classes() + sage: G.conjugacy_classes() # needs sage.combinat [Conjugacy class of cycle type [1, 1, 1, 1, 1] in Symmetric group of order 5! as a permutation group, Conjugacy class of cycle type [2, 1, 1, 1] in @@ -588,7 +602,7 @@ def conjugacy_class(self, g): sage: G = SymmetricGroup(5) sage: g = G((1,2,3,4)) - sage: G.conjugacy_class(g) + sage: G.conjugacy_class(g) # needs sage.combinat Conjugacy class of cycle type [4, 1] in Symmetric group of order 5! as a permutation group """ @@ -612,37 +626,37 @@ def algebra(self, base_ring, category=None): EXAMPLES:: sage: S4 = SymmetricGroup(4) - sage: S4.algebra(QQ) + sage: S4.algebra(QQ) # needs sage.combinat Symmetric group algebra of order 4 over Rational Field sage: S3 = SymmetricGroup([1,2,3]) - sage: A = S3.algebra(QQ); A + sage: A = S3.algebra(QQ); A # needs sage.combinat Symmetric group algebra of order 3 over Rational Field sage: a = S3.an_element(); a (2,3) - sage: A(a) + sage: A(a) # needs sage.combinat (2,3) We illustrate the choice of the category:: - sage: A.category() + sage: A.category() # needs sage.combinat Join of Category of coxeter group algebras over Rational Field and Category of finite group algebras over Rational Field and Category of finite dimensional cellular algebras with basis over Rational Field - sage: A = S3.algebra(QQ, category=Semigroups()) - sage: A.category() + sage: A = S3.algebra(QQ, category=Semigroups()) # needs sage.combinat + sage: A.category() # needs sage.combinat Category of finite dimensional unital cellular semigroup algebras over Rational Field - In the following case, a usual group algebra is returned: + In the following case, a usual group algebra is returned:: sage: S = SymmetricGroup([2,3,5]) - sage: S.algebra(QQ) + sage: S.algebra(QQ) # needs sage.combinat Algebra of Symmetric group of order 3! as a permutation group over Rational Field sage: a = S.an_element(); a (3,5) - sage: S.algebra(QQ)(a) + sage: S.algebra(QQ)(a) # needs sage.combinat (3,5) """ from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra @@ -677,7 +691,7 @@ def __init__(self, domain=None): Alternating group of order 6!/2 as a permutation group sage: G.category() Category of finite enumerated permutation groups - sage: TestSuite(G).run() # long time + sage: TestSuite(G).run() # long time sage: G = AlternatingGroup([1,2,4,5]) sage: G @@ -723,11 +737,11 @@ def _gap_init_(self, gap=None): class CyclicPermutationGroup(PermutationGroup_unique): def __init__(self, n): """ - A cyclic group of order n, as a permutation group. + A cyclic group of order `n`, as a permutation group. INPUT: - n -- a positive integer + - ``n`` -- a positive integer .. note:: @@ -772,7 +786,7 @@ def _repr_(self): def is_commutative(self): """ - Return True if this group is commutative. + Return ``True`` if this group is commutative. EXAMPLES:: @@ -784,7 +798,7 @@ def is_commutative(self): def is_abelian(self): """ - Return True if this group is abelian. + Return ``True`` if this group is abelian. EXAMPLES:: @@ -796,7 +810,7 @@ def is_abelian(self): def as_AbelianGroup(self): """ - Returns the corresponding Abelian Group instance. + Return the corresponding :class:`AbelianGroup` instance. EXAMPLES:: @@ -817,7 +831,7 @@ class DiCyclicGroup(PermutationGroup_unique): INPUT: - - n -- a positive integer, two or greater + - ``n`` -- a positive integer, two or greater OUTPUT: @@ -918,7 +932,7 @@ class DiCyclicGroup(PermutationGroup_unique): TESTS:: sage: groups.permutation.DiCyclic(6) - Diyclic group of order 24 as a permutation group + Dicyclic group of order 24 as a permutation group AUTHOR: @@ -974,9 +988,9 @@ def _repr_(self): EXAMPLES:: sage: DiCyclicGroup(12) - Diyclic group of order 48 as a permutation group + Dicyclic group of order 48 as a permutation group """ - return "Diyclic group of order %s as a permutation group"%self.order() + return "Dicyclic group of order %s as a permutation group"%self.order() def is_commutative(self): r""" @@ -1061,14 +1075,15 @@ def __init__(self, n): EXAMPLES:: - sage: G = groups.permutation.Janko(1); G # optional - gap_packages internet + sage: G = groups.permutation.Janko(1); G # optional - gap_package_atlasrep internet Janko group J1 of order 175560 as a permutation group TESTS:: - sage: G.category() # optional - gap_packages internet + sage: G.category() # optional - gap_package_atlasrep internet Category of finite enumerated permutation groups - sage: TestSuite(G).run(skip=["_test_enumerated_set_contains", "_test_enumerated_set_iter_list"]) # optional - gap_packages internet + sage: TestSuite(G).run(skip=["_test_enumerated_set_contains", # optional - gap_package_atlasrep internet + ....: "_test_enumerated_set_iter_list"]) """ if n not in [1, 2, 3]: raise ValueError("n must belong to {1,2,3}") @@ -1081,7 +1096,7 @@ def _repr_(self): """ EXAMPLES:: - sage: G = groups.permutation.Janko(1); G # optional - gap_packages internet + sage: G = groups.permutation.Janko(1); G # optional - gap_package_atlasrep internet Janko group J1 of order 175560 as a permutation group """ return "Janko group J%s of order %s as a permutation group" % (self._n, self.order()) @@ -1094,14 +1109,15 @@ def __init__(self): EXAMPLES:: - sage: G = groups.permutation.SuzukiSporadic(); G # optional - gap_packages internet + sage: G = groups.permutation.SuzukiSporadic(); G # optional - gap_package_atlasrep internet Sporadic Suzuki group acting on 1782 points TESTS:: - sage: G.category() # optional - gap_packages internet + sage: G.category() # optional - gap_package_atlasrep internet Category of finite enumerated permutation groups - sage: TestSuite(G).run(skip=["_test_enumerated_set_contains", "_test_enumerated_set_iter_list"]) # optional - gap_packages internet + sage: TestSuite(G).run(skip=["_test_enumerated_set_contains", # optional - gap_package_atlasrep internet + ....: "_test_enumerated_set_iter_list"]) """ libgap.load_package("atlasrep") PermutationGroup_generic.__init__(self, gap_group='AtlasGroup("Suz")') @@ -1110,7 +1126,7 @@ def _repr_(self): """ EXAMPLES:: - sage: G = groups.permutation.SuzukiSporadic(); G # optional - gap_packages internet + sage: G = groups.permutation.SuzukiSporadic(); G # optional - gap_package_atlasrep internet Sporadic Suzuki group acting on 1782 points """ return "Sporadic Suzuki group acting on 1782 points" @@ -1123,7 +1139,7 @@ class QuaternionGroup(DiCyclicGroup): OUTPUT: The quaternion group of order 8, as a permutation group. - See the ``DiCyclicGroup`` class for a generalization of this + See the :class:`DiCyclicGroup` class for a generalization of this construction. .. note:: @@ -1194,7 +1210,7 @@ class GeneralDihedralGroup(PermutationGroup_generic): INPUT: - - ``factors`` - a list of the sizes of the cyclic factors of the + - ``factors`` -- a list of the sizes of the cyclic factors of the abelian group being dihedralized (this will be sorted once entered) @@ -1262,7 +1278,7 @@ class GeneralDihedralGroup(PermutationGroup_generic): If two nonidentical input lists generate isomorphic abelian groups, then they will generate identical groups (with each direct factor broken up into its prime factors), but they will still have - distinct descriptions. Note that If `gcd(n,m)=1`, then `C_n \times + distinct descriptions. Note that if `\gcd(n,m)=1`, then `C_n \times C_m \cong C_{nm}`, while the general dihedral groups generated by isomorphic abelian groups should be themselves isomorphic. :: @@ -1429,7 +1445,8 @@ def __init__(self, n): sage: DihedralGroup(5).gens() ((1,2,3,4,5), (1,5)(2,4)) sage: sorted(DihedralGroup(5)) - [(), (2,5)(3,4), (1,2)(3,5), (1,2,3,4,5), (1,3)(4,5), (1,3,5,2,4), (1,4)(2,3), (1,4,2,5,3), (1,5,4,3,2), (1,5)(2,4)] + [(), (2,5)(3,4), (1,2)(3,5), (1,2,3,4,5), (1,3)(4,5), (1,3,5,2,4), + (1,4)(2,3), (1,4,2,5,3), (1,5,4,3,2), (1,5)(2,4)] sage: G = DihedralGroup(6) sage: G.order() @@ -1640,7 +1657,7 @@ def __init__(self, m): INPUT: - - ``m`` - a positive integer; the power of 2 that is the + - ``m`` -- a positive integer; the power of 2 that is the group's order OUTPUT: @@ -1750,11 +1767,11 @@ def __init__(self, n): INPUT: - n -- a positive integer in {9, 10, 11, 12, 21, 22, 23, 24}. + - ``n`` -- a positive integer in {9, 10, 11, 12, 21, 22, 23, 24}. OUTPUT: - the Mathieu group of degree n, as a permutation group + the Mathieu group of degree `n`, as a permutation group .. note:: @@ -1762,8 +1779,7 @@ def __init__(self, n): EXAMPLES:: - sage: G = MathieuGroup(12) - sage: G + sage: G = MathieuGroup(12); G Mathieu group of degree 12 and order 95040 as a permutation group TESTS:: @@ -1803,13 +1819,13 @@ def __init__(self, d, n): INPUT: - - d -- non-negative integer; the degree - - n -- positive integer; the index of the group in the GAP database, + - ``d`` -- non-negative integer; the degree + - ``n`` -- positive integer; the index of the group in the GAP database, starting at 1 OUTPUT: - the n-th transitive group of degree d + the `n`-th transitive group of degree `d` .. note:: @@ -1843,7 +1859,8 @@ def __init__(self, d, n): sage: TransitiveGroup(32,1) Traceback (most recent call last): ... - NotImplementedError: only the transitive groups of degree at most 31 are available in GAP's database + NotImplementedError: only the transitive groups of degree at most 31 + are available in GAP's database TESTS:: @@ -1911,7 +1928,7 @@ def TransitiveGroups(d=None): - ``d`` -- an integer (optional) - Returns the set of all transitive groups of a given degree + Return the set of all transitive groups of a given degree ``d`` up to isomorphisms. If ``d`` is not specified, it returns the set of all transitive groups up to isomorphisms. @@ -1933,16 +1950,17 @@ def TransitiveGroups(d=None): sage: TransitiveGroups(32).cardinality() Traceback (most recent call last): ... - NotImplementedError: only the transitive groups of degree at most 31 are available in GAP's database + NotImplementedError: only the transitive groups of degree at most 31 + are available in GAP's database """ if d is None: return TransitiveGroupsAll() - else: - d = Integer(d) - if d < 0: - raise ValueError("a transitive group acts on a non negative integer number of positions") - return TransitiveGroupsOfDegree(d) + + d = Integer(d) + if d < 0: + raise ValueError("a transitive group acts on a non negative integer number of positions") + return TransitiveGroupsOfDegree(d) class TransitiveGroupsAll(DisjointUnionEnumeratedSets): @@ -1985,7 +2003,7 @@ def _repr_(self): """ TESTS:: - sage: TransitiveGroups() # indirect doctest + sage: TransitiveGroups() # indirect doctest Transitive Groups """ return "Transitive Groups" @@ -2099,7 +2117,7 @@ def __iter__(self): """ EXAMPLES:: - sage: list(TransitiveGroups(5)) # indirect doctest + sage: list(TransitiveGroups(5)) # indirect doctest [Transitive group number 1 of degree 5, Transitive group number 2 of degree 5, Transitive group number 3 of degree 5, @@ -2163,7 +2181,8 @@ def cardinality(self): sage: TransitiveGroups(32).cardinality() Traceback (most recent call last): ... - NotImplementedError: only the transitive groups of degree at most 31 are available in GAP's database + NotImplementedError: only the transitive groups of degree at most 31 + are available in GAP's database TESTS:: @@ -2373,7 +2392,7 @@ class PrimitiveGroupsAll(DisjointUnionEnumeratedSets): The following test is broken, see :trac:`22576`:: - sage: TestSuite(PrimitiveGroups()).run() # known bug # long time + sage: TestSuite(PrimitiveGroups()).run() # known bug, long time """ def __init__(self): """ @@ -2397,7 +2416,7 @@ def _repr_(self): TESTS:: - sage: PrimitiveGroups() # indirect doctest + sage: PrimitiveGroups() # indirect doctest Primitive Groups """ return "Primitive Groups" @@ -2531,7 +2550,7 @@ def __iter__(self): """ EXAMPLES:: - sage: list(PrimitiveGroups(5)) # indirect doctest + sage: list(PrimitiveGroups(5)) # indirect doctest [C(5), D(2*5), AGL(1, 5), A(5), S(5)] """ for n in range(1, self.cardinality() + 1): @@ -2613,18 +2632,18 @@ def matrix_degree(self): class PGL(PermutationGroup_plg): def __init__(self, n, q, name='a'): - """ - The projective general linear groups over GF(q). + r""" + The projective general linear groups over `\GF(q)`. INPUT: - - n -- positive integer; the degree - - q -- prime power; the size of the ground field - - name -- (default: 'a') variable name of indeterminate of finite field GF(q) + - ``n`` -- positive integer; the degree + - ``q`` -- prime power; the size of the ground field + - ``name`` -- (default: ``'a'``) variable name of indeterminate of finite field `\GF(q)` OUTPUT: - PGL(n,q) + PGL(`n`, `q`) .. note:: @@ -2641,14 +2660,14 @@ def __init__(self, n, q, name='a'): sage: G.order() 24 - sage: G = PGL(2, 9, 'b'); G + sage: G = PGL(2, 9, 'b'); G # needs sage.rings.finite_rings Permutation Group with generators [(3,10,9,8,4,7,6,5), (1,2,4)(5,6,8)(7,9,10)] sage: G.base_ring() Finite Field in b of size 3^2 sage: G.category() Category of finite enumerated permutation groups - sage: TestSuite(G).run() # long time + sage: TestSuite(G).run() # long time TESTS:: @@ -2675,18 +2694,18 @@ def __str__(self): class PSL(PermutationGroup_plg): def __init__(self, n, q, name='a'): - """ - The projective special linear groups over GF(q). + r""" + The projective special linear groups over `\GF(q)`. INPUT: - - n -- positive integer; the degree - - q -- either a prime power (the size of the ground field) or a finite field - - name -- (default: 'a') variable name of indeterminate of finite field GF(q) + - ``n`` -- positive integer; the degree + - ``q`` -- either a prime power (the size of the ground field) or a finite field + - ``name`` -- (default: ``'a'``) variable name of indeterminate of finite field `\GF(q)` OUTPUT: - the group PSL(n,q) + the group PSL(`n`, `q`) .. note:: @@ -2705,18 +2724,18 @@ def __init__(self, n, q, name='a'): We create two groups over nontrivial finite fields:: - sage: G = PSL(2, 4, 'b'); G + sage: G = PSL(2, 4, 'b'); G # needs sage.rings.finite_rings Permutation Group with generators [(3,4,5), (1,2,3)] sage: G.base_ring() Finite Field in b of size 2^2 - sage: G = PSL(2, 8); G + sage: G = PSL(2, 8); G # needs sage.rings.finite_rings Permutation Group with generators [(3,8,6,4,9,7,5), (1,2,3)(4,7,5)(6,9,8)] sage: G.base_ring() Finite Field in a of size 2^3 sage: G.category() Category of finite enumerated permutation groups - sage: TestSuite(G).run() # long time + sage: TestSuite(G).run() # long time TESTS:: @@ -2762,7 +2781,7 @@ def __str__(self): def ramification_module_decomposition_hurwitz_curve(self): r""" Helps compute the decomposition of the ramification module - for the Hurwitz curves X (over CC say) with automorphism group + for the Hurwitz curves X (over `\CC` say) with automorphism group G = PSL(2,q), q a "Hurwitz prime" (ie, p is `\pm 1 \pmod 7`). Using this computation and Borne's formula helps determine the G-module structure of the RR spaces of equivariant @@ -2775,14 +2794,16 @@ def ramification_module_decomposition_hurwitz_curve(self): Here IrrRepns(G) = [pi_1,...,pi_n] (in the order listed in the output of self.character_table()). - REFERENCE: David Joyner, Amy Ksir, Roger Vogeler, - "Group representations on Riemann-Roch spaces of some - Hurwitz curves," preprint, 2006. + REFERENCE: + + David Joyner, Amy Ksir, Roger Vogeler, + "Group representations on Riemann-Roch spaces of some + Hurwitz curves," preprint, 2006. EXAMPLES:: sage: G = PSL(2,13) - sage: G.ramification_module_decomposition_hurwitz_curve() # random, optional - gap_packages + sage: G.ramification_module_decomposition_hurwitz_curve() # random, optional - gap_packages [0, 7, 7, 12, 12, 12, 13, 15, 14] This means, for example, that the trivial representation does not @@ -2809,7 +2830,7 @@ def ramification_module_decomposition_hurwitz_curve(self): return mults.sage() def ramification_module_decomposition_modular_curve(self): - """ + r""" Helps compute the decomposition of the ramification module for the modular curve X(p) (over CC say) with automorphism group G = PSL(2,q), q a prime > 5. Using this computation and Borne's formula helps determine the @@ -2832,7 +2853,7 @@ def ramification_module_decomposition_modular_curve(self): EXAMPLES:: sage: G = PSL(2,7) - sage: G.ramification_module_decomposition_modular_curve() # random, optional - gap_packages + sage: G.ramification_module_decomposition_modular_curve() # random, optional - gap_packages [0, 4, 3, 6, 7, 8] This means, for example, that the trivial representation does not @@ -2855,18 +2876,18 @@ def ramification_module_decomposition_modular_curve(self): class PSp(PermutationGroup_plg): def __init__(self, n, q, name='a'): - """ - The projective symplectic linear groups over GF(q). + r""" + The projective symplectic linear groups over `\GF(q)`. INPUT: - - n -- positive integer; the degree - - q -- prime power; the size of the ground field - - name -- (default: 'a') variable name of indeterminate of finite field GF(q) + - ``n`` -- positive integer; the degree + - ``q`` -- prime power; the size of the ground field + - ``name`` -- (default: ``'a'``) variable name of indeterminate of finite field `\GF(q)` OUTPUT: - PSp(n,q) + PSp(`n`, `q`) .. note:: @@ -2887,7 +2908,7 @@ def __init__(self, n, q, name='a'): sage: G.base_ring() Finite Field of size 3 - sage: G = PSp(2, 8, name='alpha'); G + sage: G = PSp(2, 8, name='alpha'); G # needs sage.rings.finite_rings Permutation Group with generators [(3,8,6,4,9,7,5), (1,2,3)(4,7,5)(6,9,8)] sage: G.base_ring() Finite Field in alpha of size 2^3 @@ -2925,7 +2946,7 @@ def field_of_definition(self): """ EXAMPLES:: - sage: PSU(2,3).field_of_definition() + sage: PSU(2,3).field_of_definition() # needs sage.rings.finite_rings Finite Field in a of size 3^2 """ return self._field_of_definition @@ -2933,8 +2954,8 @@ def field_of_definition(self): class PSU(PermutationGroup_pug): def __init__(self, n, q, name='a'): - """ - The projective special unitary groups over GF(q). + r""" + The projective special unitary groups over `\GF(q)`. INPUT: @@ -2952,17 +2973,17 @@ def __init__(self, n, q, name='a'): EXAMPLES:: - sage: PSU(2,3) + sage: PSU(2,3) # needs sage.rings.finite_rings The projective special unitary group of degree 2 over Finite Field of size 3 - sage: G = PSU(2, 8, name='alpha'); G + sage: G = PSU(2, 8, name='alpha'); G # needs sage.rings.finite_rings The projective special unitary group of degree 2 over Finite Field in alpha of size 2^3 - sage: G.base_ring() + sage: G.base_ring() # needs sage.rings.finite_rings Finite Field in alpha of size 2^3 TESTS:: - sage: groups.permutation.PSU(2, 3) + sage: groups.permutation.PSU(2, 3) # needs sage.rings.finite_rings The projective special unitary group of degree 2 over Finite Field of size 3 """ id = 'PSU(%s,%s)' % (n, q) @@ -2976,7 +2997,7 @@ def _repr_(self): """ EXAMPLES:: - sage: PSU(2,3) + sage: PSU(2,3) # needs sage.rings.finite_rings The projective special unitary group of degree 2 over Finite Field of size 3 """ @@ -2985,18 +3006,18 @@ def _repr_(self): class PGU(PermutationGroup_pug): def __init__(self, n, q, name='a'): - """ - The projective general unitary groups over GF(q). + r""" + The projective general unitary groups over `\GF(q)`. INPUT: - - n -- positive integer; the degree - - q -- prime power; the size of the ground field - - name -- (default: 'a') variable name of indeterminate of finite field GF(q) + - ``n`` -- positive integer; the degree + - ``q`` -- prime power; the size of the ground field + - ``name`` -- (default: ``'a'``) variable name of indeterminate of finite field `\GF(q)` OUTPUT: - PGU(n,q) + PGU(`n`, `q`) .. note:: @@ -3004,17 +3025,18 @@ def __init__(self, n, q, name='a'): EXAMPLES:: - sage: PGU(2,3) + sage: PGU(2,3) # needs sage.rings.finite_rings The projective general unitary group of degree 2 over Finite Field of size 3 - sage: G = PGU(2, 8, name='alpha'); G - The projective general unitary group of degree 2 over Finite Field in alpha of size 2^3 - sage: G.base_ring() + sage: G = PGU(2, 8, name='alpha'); G # needs sage.rings.finite_rings + The projective general unitary group of degree 2 + over Finite Field in alpha of size 2^3 + sage: G.base_ring() # needs sage.rings.finite_rings Finite Field in alpha of size 2^3 TESTS:: - sage: groups.permutation.PGU(2, 3) + sage: groups.permutation.PGU(2, 3) # needs sage.rings.finite_rings The projective general unitary group of degree 2 over Finite Field of size 3 """ id = 'PGU(%s,%s)' % (n, q) @@ -3028,7 +3050,7 @@ def _repr_(self): """ EXAMPLES:: - sage: PGU(2,3) + sage: PGU(2,3) # needs sage.rings.finite_rings The projective general unitary group of degree 2 over Finite Field of size 3 """ @@ -3038,22 +3060,22 @@ def _repr_(self): class SuzukiGroup(PermutationGroup_unique): def __init__(self, q, name='a'): r""" - The Suzuki group over GF(q), + The Suzuki group over `\GF(q)`, `^2 B_2(2^{2k+1}) = Sz(2^{2k+1})`. - A wrapper for the GAP function SuzukiGroup. + A wrapper for the GAP function ``SuzukiGroup``. INPUT: - - q -- 2^n, an odd power of 2; the size of the ground - field. (Strictly speaking, n should be greater than 1, or - else this group os not simple.) - - name -- (default: 'a') variable name of indeterminate of - finite field GF(q) + - ``q`` -- `2^n`, an odd power of 2; the size of the ground + field. (Strictly speaking, `n` should be greater than 1, or + else this group is not simple.) + - ``name`` -- (default: ``'a'``) variable name of indeterminate of + finite field `\GF(q)` OUTPUT: - - A Suzuki group. + A Suzuki group. .. note:: @@ -3061,12 +3083,13 @@ def __init__(self, q, name='a'): EXAMPLES:: - sage: SuzukiGroup(8) + sage: SuzukiGroup(8) # needs sage.rings.finite_rings Permutation Group with generators [(1,2)(3,10)(4,42)(5,18)(6,50)(7,26)(8,58)(9,34)(12,28)(13,45)(14,44)(15,23)(16,31)(17,21)(19,39)(20,38)(22,25)(24,61)(27,60)(29,65)(30,55)(32,33)(35,52)(36,49)(37,59)(40,54)(41,62)(43,53)(46,48)(47,56)(51,63)(57,64), (1,28,10,44)(3,50,11,42)(4,43,53,64)(5,9,39,52)(6,36,63,13)(7,51,60,57)(8,33,37,16)(12,24,55,29)(14,30,48,47)(15,19,61,54)(17,59,22,62)(18,23,34,31)(20,38,49,25)(21,26,45,58)(27,32,41,65)(35,46,40,56)] - sage: print(SuzukiGroup(8)) + sage: print(SuzukiGroup(8)) # needs sage.rings.finite_rings The Suzuki group over Finite Field in a of size 2^3 + sage: # needs sage.rings.finite_rings sage: G = SuzukiGroup(32, name='alpha') sage: G.order() 32537600 @@ -3077,7 +3100,7 @@ def __init__(self, q, name='a'): TESTS:: - sage: groups.permutation.Suzuki(8) + sage: groups.permutation.Suzuki(8) # needs sage.rings.finite_rings Permutation Group with generators [(1,2)(3,10)(4,42)(5,18)(6,50)(7,26)(8,58)(9,34)(12,28)(13,45)(14,44)(15,23)(16,31)(17,21)(19,39)(20,38)(22,25)(24,61)(27,60)(29,65)(30,55)(32,33)(35,52)(36,49)(37,59)(40,54)(41,62)(43,53)(46,48)(47,56)(51,63)(57,64), (1,28,10,44)(3,50,11,42)(4,43,53,64)(5,9,39,52)(6,36,63,13)(7,51,60,57)(8,33,37,16)(12,24,55,29)(14,30,48,47)(15,19,61,54)(17,59,22,62)(18,23,34,31)(20,38,49,25)(21,26,45,58)(27,32,41,65)(35,46,40,56)] @@ -3098,8 +3121,8 @@ def base_ring(self): """ EXAMPLES:: - sage: G = SuzukiGroup(32, name='alpha') - sage: G.base_ring() + sage: G = SuzukiGroup(32, name='alpha') # needs sage.rings.finite_rings + sage: G.base_ring() # needs sage.rings.finite_rings Finite Field in alpha of size 2^5 """ return self._base_ring @@ -3108,8 +3131,8 @@ def __str__(self): """ EXAMPLES:: - sage: G = SuzukiGroup(32, name='alpha') - sage: print(G) + sage: G = SuzukiGroup(32, name='alpha') # needs sage.rings.finite_rings + sage: print(G) # needs sage.rings.finite_rings The Suzuki group over Finite Field in alpha of size 2^5 """ @@ -3435,3 +3458,110 @@ def codegrees(self): ret = [self._m * i for i in reversed(range(self._n-1))] ret.append((self._n-1)*self._m - self._n) return tuple(sorted(ret, reverse=True)) + + +class SmallPermutationGroup(PermutationGroup_generic): + r""" + A GAP SmallGroup, returned as a permutation group. + + GAP contains a library SGL of small groups, each identified by + its GAP SmallGroup id. (MAGMA uses the same identifiers). + The GAP SmallGroup id is a pair ``[n,k]`` consisting of + ``n``, the order of the group, and ``k``, an index determining + the group specifically. This class can construct the group as a + permutation group from this data. + + INPUT: + + - ``order`` -- the order of the group + + - ``gap_id`` -- the numerical index in the GAP id of the group + + Generators may be obtained through the :meth:`gens` method. + These could change for a particular group in later releases + of GAP. In many instances the degree of the constructed group + ``SmallPermutationGroup(n,k)`` will be a permutation group on + `n` letters, but this will not always be true. + + EXAMPLES:: + + sage: G = SmallPermutationGroup(12,4); G + Group of order 12 and GAP Id 4 as a permutation group + sage: G.gens() + ((1,2)(3,5)(4,10)(6,8)(7,12)(9,11), + (1,3)(2,5)(4,7)(6,9)(8,11)(10,12), + (1,4,8)(2,6,10)(3,7,11)(5,9,12)) + sage: G.character_table() # needs sage.rings.number_field + [ 1 1 1 1 1 1] + [ 1 -1 -1 1 1 -1] + [ 1 -1 1 1 -1 1] + [ 1 1 -1 1 -1 -1] + [ 2 0 -2 -1 0 1] + [ 2 0 2 -1 0 -1] + sage: def numgps(n): return ZZ(libgap.NumberSmallGroups(n)) + sage: all(SmallPermutationGroup(n,k).id() == [n,k] + ....: for n in [1..64] for k in [1..numgps(n)]) + True + sage: H = SmallPermutationGroup(6,1) + sage: H.is_abelian() + False + sage: [H.centralizer(g) for g in H.conjugacy_classes_representatives()] + [Subgroup generated by [(1,2)(3,6)(4,5), (1,3,5)(2,4,6)] of + (Group of order 6 and GAP Id 1 as a permutation group), + Subgroup generated by [(1,2)(3,6)(4,5)] of + (Group of order 6 and GAP Id 1 as a permutation group), + Subgroup generated by [(1,3,5)(2,4,6), (1,5,3)(2,6,4)] of + (Group of order 6 and GAP Id 1 as a permutation group)] + """ + + def __init__(self, order, gap_id): + """ + Initialize ``self``. + + TESTS:: + + sage: TestSuite(SmallPermutationGroup(60,5)).run() + """ + self._n = order + self._gap_id = gap_id + self._gap_small_group = libgap.SmallGroup(order, gap_id) + gap_permutation_group = self._gap_small_group.IsomorphismPermGroup().Image(self._gap_small_group) + PermutationGroup_generic.__init__(self, gap_group=gap_permutation_group) + + def _repr_(self): + r""" + EXAMPLES:: + + sage: G = SmallPermutationGroup(12,4); G + Group of order 12 and GAP Id 4 as a permutation group + """ + return "Group of order %s and GAP Id %s as a permutation group"%(self._n, self._gap_id) + + def order(self): + """ + Return the order of the group corresponding to ``self``. + + EXAMPLES:: + + sage: [SmallPermutationGroup(21,k).order() for k in [1,2]] + [21, 21] + """ + return self._n + + def gap_small_group(self): + r""" + Return the GAP small group object corresponding to ``self``. + + GAP realizes some small groups as ``PermutationGroup``, others as ``PcGroups`` + (polycyclic groups). The :class:`SmallPermutationGroup` class always + returns a ``PermutationGroup``, but in the process of creating this group + a GAP ``SmallGroup`` is generated. This method returns that group. + + EXAMPLES:: + + sage: SmallPermutationGroup(168,41).gap_small_group() + <pc group of size 168 with 5 generators> + sage: SmallPermutationGroup(168,42).gap_small_group() + Group([ (3,4)(5,6), (1,2,3)(4,5,7) ]) + """ + return self._gap_small_group diff --git a/src/sage/groups/perm_gps/symgp_conjugacy_class.py b/src/sage/groups/perm_gps/symgp_conjugacy_class.py index d6112df67af..5a8d5f435fa 100644 --- a/src/sage/groups/perm_gps/symgp_conjugacy_class.py +++ b/src/sage/groups/perm_gps/symgp_conjugacy_class.py @@ -28,8 +28,8 @@ def __init__(self, domain, part): sage: G = SymmetricGroup(5) sage: g = G([(1,2), (3,4,5)]) - sage: C = G.conjugacy_class(Partition([3,2])) - sage: type(C._part) + sage: C = G.conjugacy_class(Partition([3,2])) # needs sage.combinat + sage: type(C._part) # needs sage.combinat <class 'sage.combinat.partition.Partitions_n_with_category.element_class'> """ P = Partitions_n(len(domain)) @@ -44,7 +44,7 @@ def _repr_(self): EXAMPLES:: sage: G = SymmetricGroup(4) - sage: G.conjugacy_class(Partition([4])) + sage: G.conjugacy_class(Partition([4])) # needs sage.combinat Conjugacy class of cycle type [4] in Symmetric group of order 4! as a permutation group """ @@ -59,9 +59,9 @@ def __eq__(self, other): sage: G = SymmetricGroup(5) sage: g = G([(1,2), (3,4,5)]) - sage: C = G.conjugacy_class(Partition([3,2])) - sage: Cp = G.conjugacy_class(g) - sage: C == Cp + sage: C = G.conjugacy_class(Partition([3,2])) # needs sage.combinat + sage: Cp = G.conjugacy_class(g) # needs sage.combinat + sage: C == Cp # needs sage.combinat True """ if not isinstance(other, SymmetricGroupConjugacyClassMixin): @@ -76,9 +76,9 @@ def __ne__(self, other): sage: G = SymmetricGroup(5) sage: g = G([(1,3), (2,4,5)]) - sage: C = G.conjugacy_class(Partition([3,2])) - sage: Cp = G.conjugacy_class(g) - sage: C != Cp + sage: C = G.conjugacy_class(Partition([3,2])) # needs sage.combinat + sage: Cp = G.conjugacy_class(g) # needs sage.combinat + sage: C != Cp # needs sage.combinat False """ return not (self == other) @@ -91,7 +91,7 @@ def partition(self): sage: G = SymmetricGroup(5) sage: g = G([(1,2), (3,4,5)]) - sage: C = G.conjugacy_class(g) + sage: C = G.conjugacy_class(g) # needs sage.combinat """ return self._part @@ -111,6 +111,7 @@ def __init__(self, group, part): EXAMPLES:: + sage: # needs sage.combinat sage: G = SymmetricGroup(5) sage: g = G([(1,2), (3,4,5)]) sage: C = G.conjugacy_class(g) @@ -133,8 +134,8 @@ def __iter__(self): EXAMPLES:: sage: G = SymmetricGroup(4) - sage: C = G.conjugacy_class(Partition([3,1])) - sage: for x in C: x + sage: C = G.conjugacy_class(Partition([3,1])) # needs sage.combinat + sage: for x in C: x # needs sage.combinat (2,3,4) (2,4,3) (1,2,3) @@ -160,9 +161,9 @@ def set(self): sage: G = SymmetricGroup(3) sage: g = G((1,2)) - sage: C = G.conjugacy_class(g) + sage: C = G.conjugacy_class(g) # needs sage.combinat sage: S = [(2,3), (1,2), (1,3)] - sage: C.set() == Set(G(x) for x in S) + sage: C.set() == Set(G(x) for x in S) # needs sage.combinat True """ if not self._set: @@ -186,6 +187,7 @@ def __init__(self, P, part): EXAMPLES:: + sage: # needs sage.combinat sage: G = Permutations(5) sage: g = G([2, 1, 4, 5, 3]) sage: C = G.conjugacy_class(g) @@ -208,8 +210,8 @@ def __iter__(self): EXAMPLES:: sage: G = Permutations(4) - sage: C = G.conjugacy_class(Partition([3,1])) - sage: for x in C: x + sage: C = G.conjugacy_class(Partition([3,1])) # needs sage.combinat + sage: for x in C: x # needs sage.combinat [1, 3, 4, 2] [1, 4, 2, 3] [2, 3, 1, 4] @@ -235,9 +237,9 @@ def set(self): sage: G = Permutations(3) sage: g = G([2, 1, 3]) - sage: C = G.conjugacy_class(g) + sage: C = G.conjugacy_class(g) # needs sage.combinat sage: S = [[1, 3, 2], [2, 1, 3], [3, 2, 1]] - sage: C.set() == Set(G(x) for x in S) + sage: C.set() == Set(G(x) for x in S) # needs sage.combinat True """ if not self._set: @@ -272,9 +274,9 @@ def default_representative(part, G): EXAMPLES:: - sage: from sage.groups.perm_gps.symgp_conjugacy_class import default_representative + sage: from sage.groups.perm_gps.symgp_conjugacy_class import default_representative # needs sage.combinat sage: S = SymmetricGroup(4) - sage: for p in Partitions(4): + sage: for p in Partitions(4): # needs sage.combinat ....: print(default_representative(p, S)) (1,2,3,4) (1,2,3) @@ -312,8 +314,8 @@ def conjugacy_class_iterator(part, S=None): EXAMPLES:: - sage: from sage.groups.perm_gps.symgp_conjugacy_class import conjugacy_class_iterator - sage: for p in conjugacy_class_iterator([2,2]): print(p) + sage: from sage.groups.perm_gps.symgp_conjugacy_class import conjugacy_class_iterator # needs sage.combinat + sage: for p in conjugacy_class_iterator([2,2]): print(p) # needs sage.combinat [(1, 2), (3, 4)] [(1, 4), (2, 3)] [(1, 3), (2, 4)] @@ -321,7 +323,7 @@ def conjugacy_class_iterator(part, S=None): In order to get permutations, one just has to wrap:: sage: S = SymmetricGroup(5) - sage: for p in conjugacy_class_iterator([3,2]): print(S(p)) + sage: for p in conjugacy_class_iterator([3,2]): print(S(p)) # needs sage.combinat (1,3)(2,4,5) (1,3)(2,5,4) (1,2)(3,4,5) @@ -334,15 +336,15 @@ def conjugacy_class_iterator(part, S=None): the conjugacy class:: sage: s = lambda p: sum(1 for _ in conjugacy_class_iterator(p)) - sage: all(s(p) == p.conjugacy_class_size() for p in Partitions(5)) + sage: all(s(p) == p.conjugacy_class_size() for p in Partitions(5)) # needs sage.combinat True It is also possible to specify any underlying set:: - sage: it = conjugacy_class_iterator([2,2,2], 'abcdef') - sage: sorted(flatten(next(it))) + sage: it = conjugacy_class_iterator([2,2,2], 'abcdef') # needs sage.combinat + sage: sorted(flatten(next(it))) # needs sage.combinat ['a', 'b', 'c', 'd', 'e', 'f'] - sage: all(len(x) == 2 for x in next(it)) + sage: all(len(x) == 2 for x in next(it)) # needs sage.combinat True """ n = sum(part) diff --git a/src/sage/groups/raag.py b/src/sage/groups/raag.py index 736430e8af2..4bd3787d484 100644 --- a/src/sage/groups/raag.py +++ b/src/sage/groups/raag.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs sage.rings.number_field r""" Right-Angled Artin Groups diff --git a/src/sage/groups/semimonomial_transformations/__init__.py b/src/sage/groups/semimonomial_transformations/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/combinat/ncsym/__init__.py b/src/sage/groups/semimonomial_transformations/all.py similarity index 100% rename from src/sage/combinat/ncsym/__init__.py rename to src/sage/groups/semimonomial_transformations/all.py diff --git a/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pyx b/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pyx index d84683ce5ee..ae9ce18efb1 100644 --- a/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pyx +++ b/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Elements of a semimonomial transformation group @@ -9,13 +10,13 @@ the semidirect product of the monomial transformation group of degree `n` The multiplication of two elements `(\phi, \pi, \alpha)(\psi, \sigma, \beta)` with - - `\phi, \psi \in {R^{\times}}^n` +- `\phi, \psi \in {R^{\times}}^n` - - `\pi, \sigma \in S_n` (with the multiplication `\pi\sigma` - done from left to right (like in GAP) -- - that is, `(\pi\sigma)(i) = \sigma(\pi(i))` for all `i`.) +- `\pi, \sigma \in S_n` (with the multiplication `\pi\sigma` + done from left to right (like in GAP) -- + that is, `(\pi\sigma)(i) = \sigma(\pi(i))` for all `i`.) - - `\alpha, \beta \in Aut(R)` +- `\alpha, \beta \in Aut(R)` is defined by @@ -114,7 +115,7 @@ cdef class SemimonomialTransformation(MultiplicativeGroupElement): ((2*a + 1, 1, 2, 2); (1,2,3,4), Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> 2*a + 1) sage: S(g) ((2, a, 1, 2); (), Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> a) - sage: S(1) # the one element in the group + sage: S(1) # the one element in the group ((1, 1, 1, 1); (), Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> a) """ def __init__(self, parent, v, perm, alpha): @@ -127,7 +128,7 @@ cdef class SemimonomialTransformation(MultiplicativeGroupElement): sage: F.<a> = GF(9) sage: S = SemimonomialTransformationGroup(F, 4) - sage: g = S(v = [2, a, 1, 2]) #indirect doctest + sage: g = S(v = [2, a, 1, 2]) #indirect doctest """ MultiplicativeGroupElement.__init__(self, parent) self.v = tuple(v) @@ -152,7 +153,7 @@ cdef class SemimonomialTransformation(MultiplicativeGroupElement): sage: F.<a> = GF(9) sage: s = SemimonomialTransformationGroup(F, 4).an_element() - sage: t = copy(s) #indirect doctest + sage: t = copy(s) # indirect doctest sage: t is s False sage: t == s @@ -203,7 +204,7 @@ cdef class SemimonomialTransformation(MultiplicativeGroupElement): sage: F.<a> = GF(9) sage: s = SemimonomialTransformationGroup(F, 4).an_element() - sage: s*s #indirect doctest + sage: s*s # indirect doctest ((a, 2*a + 1, 1, 1); (1,3)(2,4), Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> a) """ cdef SemimonomialTransformation right = <SemimonomialTransformation> _right @@ -223,7 +224,7 @@ cdef class SemimonomialTransformation(MultiplicativeGroupElement): sage: F.<a> = GF(9) sage: S = SemimonomialTransformationGroup(F, 4) sage: s = S.an_element() - sage: s*s**(-1) == S(1) # indirect doctest + sage: s*s**(-1) == S(1) # indirect doctest True """ cdef i @@ -240,7 +241,7 @@ cdef class SemimonomialTransformation(MultiplicativeGroupElement): EXAMPLES:: sage: F.<a> = GF(9) - sage: SemimonomialTransformationGroup(F, 4).an_element() # indirect doctest + sage: SemimonomialTransformationGroup(F, 4).an_element() # indirect doctest ((a, 1, 1, 1); (1,4,3,2), Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> 2*a + 1) """ return "(%s; %s, %s)"%(self.v, self.perm.cycle_string(), @@ -254,9 +255,9 @@ cdef class SemimonomialTransformation(MultiplicativeGroupElement): sage: F.<a> = GF(9) sage: g = SemimonomialTransformationGroup(F, 4).gens() - sage: g[0] > g[1] # indirect doctest + sage: g[0] > g[1] # indirect doctest True - sage: g[1] != g[2] # indirect doctest + sage: g[1] != g[2] # indirect doctest True """ cdef SemimonomialTransformation right = <SemimonomialTransformation> _right diff --git a/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py b/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py index 78c485bfc02..40bbed2c6bb 100644 --- a/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py +++ b/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Semimonomial transformation group @@ -105,13 +106,17 @@ class SemimonomialTransformationGroup(FiniteGroup, UniqueRepresentation): sage: g = S(v = [2, a, 1, 2]) sage: h = S(perm = Permutation('(1,2,3,4)'), autom=F.hom([a**3])) sage: g*h - ((2, a, 1, 2); (1,2,3,4), Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> 2*a + 1) + ((2, a, 1, 2); (1,2,3,4), + Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> 2*a + 1) sage: h*g - ((2*a + 1, 1, 2, 2); (1,2,3,4), Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> 2*a + 1) + ((2*a + 1, 1, 2, 2); (1,2,3,4), + Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> 2*a + 1) sage: S(g) - ((2, a, 1, 2); (), Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> a) + ((2, a, 1, 2); (), + Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> a) sage: S(1) - ((1, 1, 1, 1); (), Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> a) + ((1, 1, 1, 1); (), + Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> a) """ Element = SemimonomialTransformation @@ -256,7 +261,7 @@ def _an_element_(self): EXAMPLES:: sage: F.<a> = GF(4) - sage: SemimonomialTransformationGroup(F, 3).an_element() # indirect doctest + sage: SemimonomialTransformationGroup(F, 3).an_element() # indirect doctest ((a, 1, 1); (1,3,2), Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a + 1) """ R = self.base_ring() @@ -275,9 +280,9 @@ def __contains__(self, item) -> bool: sage: F.<a> = GF(4) sage: S = SemimonomialTransformationGroup(F, 3) - sage: 1 in S # indirect doctest + sage: 1 in S # indirect doctest True - sage: a in S # indirect doctest + sage: a in S # indirect doctest False """ try: @@ -294,11 +299,14 @@ def gens(self) -> tuple: sage: F.<a> = GF(4) sage: SemimonomialTransformationGroup(F, 3).gens() - (((a, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2 - Defn: a |--> a), ((1, 1, 1); (1,2,3), Ring endomorphism of Finite Field in a of size 2^2 - Defn: a |--> a), ((1, 1, 1); (1,2), Ring endomorphism of Finite Field in a of size 2^2 - Defn: a |--> a), ((1, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2 - Defn: a |--> a + 1)) + (((a, 1, 1); (), + Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), + ((1, 1, 1); (1,2,3), + Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), + ((1, 1, 1); (1,2), + Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), + ((1, 1, 1); (), + Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a + 1)) """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup R = self.base_ring() @@ -349,7 +357,7 @@ def _get_action_(self, X, op, self_on_left): sage: s*v # indirect doctest (0, 1, 0) sage: M = MatrixSpace(F, 3).one() - sage: s*M # indirect doctest + sage: s*M # indirect doctest [ 0 1 0] [ 0 0 1] [a + 1 0 0] @@ -376,7 +384,7 @@ def _repr_(self) -> str: EXAMPLES:: sage: F.<a> = GF(4) - sage: SemimonomialTransformationGroup(F, 3) # indirect doctest + sage: SemimonomialTransformationGroup(F, 3) # indirect doctest Semimonomial transformation group over Finite Field in a of size 2^2 of degree 3 """ return ('Semimonomial transformation group over %s' % self.base_ring() + @@ -389,7 +397,7 @@ def _latex_(self) -> str: EXAMPLES:: sage: F.<a> = GF(4) - sage: latex(SemimonomialTransformationGroup(F, 3)) # indirect doctest + sage: latex(SemimonomialTransformationGroup(F, 3)) # indirect doctest \left(\Bold{F}_{2^{2}}^3\wr\langle (1,2,3), (1,2) \rangle \right) \rtimes \operatorname{Aut}(\Bold{F}_{2^{2}}) """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -470,7 +478,7 @@ def __init__(self, G, M, check=True): sage: F.<a> = GF(4) sage: s = SemimonomialTransformationGroup(F, 3).an_element() sage: M = MatrixSpace(F, 3).one() - sage: s*M # indirect doctest + sage: s*M # indirect doctest [ 0 1 0] [ 0 0 1] [a + 1 0 0] @@ -497,7 +505,7 @@ def _act_(self, a, b): sage: F.<a> = GF(4) sage: s = SemimonomialTransformationGroup(F, 3).an_element() sage: M = MatrixSpace(F, 3).one() - sage: s*M # indirect doctest + sage: s*M # indirect doctest [ 0 1 0] [ 0 0 1] [a + 1 0 0] diff --git a/src/sage/homology/__init__.py b/src/sage/homology/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/homology/algebraic_topological_model.py b/src/sage/homology/algebraic_topological_model.py index f89a1529dd9..c7856836f28 100644 --- a/src/sage/homology/algebraic_topological_model.py +++ b/src/sage/homology/algebraic_topological_model.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Algebraic topological model for a cell complex @@ -33,6 +33,7 @@ from .chain_homotopy import ChainContraction from sage.rings.rational_field import QQ + def algebraic_topological_model(K, base_ring=None): r""" Algebraic topological model for cell complex ``K`` @@ -123,7 +124,8 @@ def algebraic_topological_model(K, base_ring=None): 1 sage: phi.dual() Chain homotopy between: - Chain complex endomorphism of Chain complex with at most 3 nonzero terms over Rational Field + Chain complex endomorphism of + Chain complex with at most 3 nonzero terms over Rational Field and Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field @@ -335,6 +337,7 @@ def algebraic_topological_model(K, base_ring=None): phi = ChainContraction(phi_data, pi, iota) return phi, M + def algebraic_topological_model_delta_complex(K, base_ring=None): r""" Algebraic topological model for cell complex ``K`` @@ -485,7 +488,7 @@ def conditionally_sparse(m): iota_cols = {} pi_cols_old = pi_cols pi_cols = [] - phi_old = MatrixSpace(base_ring, rank, old_rank, sparse=(base_ring==QQ)).zero() + phi_old = MatrixSpace(base_ring, rank, old_rank, sparse=(base_ring == QQ)).zero() phi_old_cols = phi_old.columns() phi_old = conditionally_sparse(phi_old) to_be_deleted = [] @@ -542,8 +545,8 @@ def conditionally_sparse(m): # The matrices involved have many zero entries. For # such matrices, using sparse matrices is faster over # the rationals, slower over finite fields. - phi_old = matrix(base_ring, phi_old_cols, sparse=(base_ring==QQ)).transpose() - keep = vector(base_ring, pi_nrows, {i:1 for i in range(pi_nrows) + phi_old = matrix(base_ring, phi_old_cols, sparse=(base_ring == QQ)).transpose() + keep = vector(base_ring, pi_nrows, {i: 1 for i in range(pi_nrows) if i not in to_be_deleted}) cols = [v.pairwise_product(keep) for v in pi_cols_old] pi_old = MS_pi_t.matrix(cols).transpose() diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py deleted file mode 100644 index 23292d902e3..00000000000 --- a/src/sage/homology/cell_complex.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -r""" -Generic cell complexes: deprecated - -The current version is :mod:`sage.topology.cell_complexes`. -""" - -from sage.misc.superseded import deprecated_function_alias -import sage.topology.cell_complex - -GenericCellComplex = deprecated_function_alias(31925, - sage.topology.cell_complex.GenericCellComplex) diff --git a/src/sage/homology/chain_complex.py b/src/sage/homology/chain_complex.py index b7392642cd4..7a56cf3fc4b 100644 --- a/src/sage/homology/chain_complex.py +++ b/src/sage/homology/chain_complex.py @@ -62,8 +62,9 @@ from sage.matrix.constructor import matrix from sage.misc.latex import latex from sage.misc.superseded import deprecation -from sage.rings.all import GF, prime_range +from sage.rings.fast_arith import prime_range from sage.homology.homology_group import HomologyGroup +from sage.misc.persist import register_unpickle_override def _latex_module(R, m): @@ -213,20 +214,21 @@ def ChainComplex(data=None, base_ring=None, grading_group=None, sage: ChainComplex([matrix(QQ, 3, 1), matrix(ZZ, 4, 3)]) Chain complex with at most 3 nonzero terms over Rational Field - sage: ChainComplex([matrix(GF(125, 'a'), 3, 1), matrix(ZZ, 4, 3)]) + sage: ChainComplex([matrix(GF(125, 'a'), 3, 1), matrix(ZZ, 4, 3)]) # needs sage.rings.finite_rings Chain complex with at most 3 nonzero terms over Finite Field in a of size 5^3 If the matrices are defined over incompatible rings, an error results:: - sage: ChainComplex([matrix(GF(125, 'a'), 3, 1), matrix(QQ, 4, 3)]) + sage: ChainComplex([matrix(GF(125, 'a'), 3, 1), matrix(QQ, 4, 3)]) # needs sage.rings.finite_rings Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Finite Field in a of size 5^3' and 'Rational Field' + TypeError: no common canonical parent for objects with parents: + 'Finite Field in a of size 5^3' and 'Rational Field' If the base ring is given explicitly but is not compatible with the matrices, an error results:: - sage: ChainComplex([matrix(GF(125, 'a'), 3, 1)], base_ring=QQ) + sage: ChainComplex([matrix(GF(125, 'a'), 3, 1)], base_ring=QQ) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: unable to convert 0 to a rational @@ -247,7 +249,7 @@ def ChainComplex(data=None, base_ring=None, grading_group=None, data_dict = {} elif isinstance(data, dict): # data is dictionary data_dict = data - else: # data is list/tuple/iterable + else: # data is list/tuple/iterable data_matrices = [x for x in data if isinstance(x, Matrix)] if degree != 1: raise ValueError('degree must be +1 if the data argument is a list or tuple') @@ -334,14 +336,15 @@ def __init__(self, parent, vectors, check=True): EXAMPLES:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, base_ring=GF(7)) + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, + ....: base_ring=GF(7)) sage: C.category() Category of chain complexes over Finite Field of size 7 TESTS:: sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) - sage: c = C({0:vector([0, 1, 2]), 1:vector([3, 4])}) + sage: c = C({0: vector([0, 1, 2]), 1: vector([3, 4])}) sage: TestSuite(c).run() """ # only nonzero vectors shall be stored, ensuring this is the @@ -359,7 +362,7 @@ def vector(self, degree): EXAMPLES:: sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) - sage: c = C({0:vector([1, 2, 3]), 1:vector([4, 5])}) + sage: c = C({0: vector([1, 2, 3]), 1: vector([4, 5])}) sage: c.vector(0) (1, 2, 3) sage: c.vector(1) @@ -381,9 +384,9 @@ def _repr_(self): sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) sage: C() Trivial chain - sage: C({0:vector([1, 2, 3])}) + sage: C({0: vector([1, 2, 3])}) Chain(0:(1, 2, 3)) - sage: c = C({0:vector([1, 2, 3]), 1:vector([4, 5])}); c + sage: c = C({0: vector([1, 2, 3]), 1: vector([4, 5])}); c Chain with 2 nonzero terms over Integer Ring sage: c._repr_() 'Chain with 2 nonzero terms over Integer Ring' @@ -408,8 +411,9 @@ def _ascii_art_(self): EXAMPLES:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0]), 1:zero_matrix(1,2)}) - sage: c = C({0:vector([1, 2, 3]), 1:vector([4, 5])}) + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0]), + ....: 1: zero_matrix(1,2)}) + sage: c = C({0: vector([1, 2, 3]), 1: vector([4, 5])}) sage: ascii_art(c) d_2 d_1 d_0 [1] d_-1 0 <---- [0] <---- [4] <---- [2] <----- 0 @@ -454,8 +458,9 @@ def _unicode_art_(self): EXAMPLES:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0]), 1:zero_matrix(1,2)}) - sage: c = C({0:vector([1, 2, 3]), 1:vector([4, 5])}) + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0]), + ....: 1: zero_matrix(1,2)}) + sage: c = C({0: vector([1, 2, 3]), 1: vector([4, 5])}) sage: unicode_art(c) โŽ›1โŽž d_2 d_1 โŽ›4โŽž d_0 โŽœ2โŽŸ d_-1 @@ -504,7 +509,7 @@ def is_cycle(self): EXAMPLES:: sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) - sage: c = C({0:vector([0, 1, 2]), 1:vector([3, 4])}) + sage: c = C({0: vector([0, 1, 2]), 1: vector([3, 4])}) sage: c.is_cycle() True """ @@ -527,7 +532,7 @@ def is_boundary(self): EXAMPLES:: sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) - sage: c = C({0:vector([0, 1, 2]), 1:vector([3, 4])}) + sage: c = C({0: vector([0, 1, 2]), 1: vector([3, 4])}) sage: c.is_boundary() False sage: z3 = C({1:(1, 0)}) @@ -552,7 +557,7 @@ def _add_(self, other): EXAMPLES:: sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) - sage: c = C({0:vector([0, 1, 2]), 1:vector([3, 4])}) + sage: c = C({0: vector([0, 1, 2]), 1: vector([3, 4])}) sage: c + c Chain with 2 nonzero terms over Integer Ring sage: ascii_art(c + c) @@ -576,7 +581,7 @@ def _lmul_(self, scalar): EXAMPLES:: sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) - sage: c = C({0:vector([0, 1, 2]), 1:vector([3, 4])}) + sage: c = C({0: vector([0, 1, 2]), 1: vector([3, 4])}) sage: 2 * c Chain with 2 nonzero terms over Integer Ring sage: 2 * c == c + c == c * 2 @@ -598,13 +603,13 @@ def __eq__(self, other): EXAMPLES:: sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) - sage: c = C({0:vector([0, 1, 2]), 1:vector([3, 4])}) + sage: c = C({0: vector([0, 1, 2]), 1: vector([3, 4])}) sage: c == c True sage: c == C(0) False """ - if type(self) != type(other) or self.parent() != other.parent(): + if type(self) is not type(other) or self.parent() != other.parent(): return False return self._vec == other._vec @@ -615,7 +620,7 @@ def __ne__(self, other): EXAMPLES:: sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) - sage: c = C({0:vector([0, 1, 2]), 1:vector([3, 4])}) + sage: c = C({0: vector([0, 1, 2]), 1: vector([3, 4])}) sage: c != c False sage: c != C(0) @@ -663,8 +668,8 @@ def __init__(self, grading_group, degree_of_differential, base_ring, differentia sage: TestSuite(C).run() """ if any(d.base_ring() != base_ring or not d.is_immutable() or - (d.ncols(), d.nrows()) == (0, 0) - for d in differentials.values()): + (d.ncols(), d.nrows()) == (0, 0) + for d in differentials.values()): raise ValueError('invalid differentials') if degree_of_differential.parent() is not grading_group: raise ValueError('the degree_of_differential.parent() must be grading_group') @@ -1074,8 +1079,11 @@ def __eq__(self, other): EXAMPLES:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, base_ring=GF(2)) - sage: D = ChainComplex({0: matrix(GF(2), 2, 3, [1, 0, 0, 0, 0, 0]), 1: matrix(ZZ, 0, 2), 3: matrix(ZZ, 0, 0)}) # base_ring determined from the matrices + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, + ....: base_ring=GF(2)) + sage: D = ChainComplex({0: matrix(GF(2), 2, 3, [1, 0, 0, 0, 0, 0]), + ....: 1: matrix(ZZ, 0, 2), + ....: 3: matrix(ZZ, 0, 0)}) # base_ring determined from the matrices sage: C == D True """ @@ -1100,11 +1108,15 @@ def __ne__(self, other): EXAMPLES:: - sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, base_ring=GF(2)) - sage: D = ChainComplex({0: matrix(GF(2), 2, 3, [1, 0, 0, 0, 0, 0]), 1: matrix(ZZ, 0, 2), 3: matrix(ZZ, 0, 0)}) # base_ring determined from the matrices + sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, + ....: base_ring=GF(2)) + sage: D = ChainComplex({0: matrix(GF(2), 2, 3, [1, 0, 0, 0, 0, 0]), + ....: 1: matrix(ZZ, 0, 2), + ....: 3: matrix(ZZ, 0, 0)}) # base_ring determined from the matrices sage: C != D False - sage: E = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, base_ring=ZZ) + sage: E = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, + ....: base_ring=ZZ) sage: C != E True """ @@ -1132,14 +1144,14 @@ def _homology_chomp(self, deg, base_ring, verbose, generators): EXAMPLES:: sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}, base_ring=GF(2)) - sage: C._homology_chomp(None, GF(2), False, False) # optional - CHomP + sage: C._homology_chomp(None, GF(2), False, False) # optional - chomp, needs sage.rings.finite_rings doctest:...: DeprecationWarning: the CHomP interface is deprecated; hence so is this function See https://github.com/sagemath/sage/issues/33777 for details. {0: Vector space of dimension 2 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2} sage: D = ChainComplex({0: matrix(ZZ,1,0,[]), 1: matrix(ZZ,1,1,[0]), ....: 2: matrix(ZZ,0,1,[])}) - sage: D._homology_chomp(None, GF(2), False, False) # optional - CHomP + sage: D._homology_chomp(None, GF(2), False, False) # optional - chomp, needs sage.rings.finite_rings {1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} """ @@ -1241,7 +1253,7 @@ def homology(self, deg=None, base_ring=None, generators=False, sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) sage: C.homology() {0: Z x Z, 1: Z x C3} - sage: C.homology(deg=1, base_ring = GF(3)) + sage: C.homology(deg=1, base_ring=GF(3)) Vector space of dimension 2 over Finite Field of size 3 sage: D = ChainComplex({0: identity_matrix(ZZ, 4), 4: identity_matrix(ZZ, 30)}) sage: D.homology() @@ -1268,9 +1280,9 @@ def homology(self, deg=None, base_ring=None, generators=False, From a torus using a field:: - sage: T = simplicial_complexes.Torus() - sage: C_t = T.chain_complex() - sage: C_t.homology(base_ring=QQ, generators=True) + sage: T = simplicial_complexes.Torus() # needs sage.graphs + sage: C_t = T.chain_complex() # needs sage.graphs + sage: C_t.homology(base_ring=QQ, generators=True) # needs sage.graphs {0: [(Vector space of dimension 1 over Rational Field, Chain(0:(0, 0, 0, 0, 0, 0, 1)))], 1: [(Vector space of dimension 1 over Rational Field, @@ -1338,15 +1350,15 @@ def change_ring(X): d_out_nullity = d_out.ncols() - d_out_rank if d_in.is_zero(): - if generators: #Include the generators of the nullspace - return [(HomologyGroup(1, base_ring), self({deg:gen})) + if generators: # Include the generators of the nullspace + return [(HomologyGroup(1, base_ring), self({deg: gen})) for gen in d_out.right_kernel().basis()] else: return HomologyGroup(d_out_nullity, base_ring) if generators: orders, gens = self._homology_generators_snf(d_in, d_out, d_out_rank) - answer = [(HomologyGroup(1, base_ring, [order]), self({deg:gen})) + answer = [(HomologyGroup(1, base_ring, [order]), self({deg: gen})) for order, gen in zip(orders, gens)] else: if base_ring.is_field(): @@ -1449,7 +1461,7 @@ def betti(self, deg=None, base_ring=None): sage: C.betti() {0: 2, 1: 1} - sage: D = ChainComplex({0:matrix(GF(5), [[3, 1],[1, 2]])}) + sage: D = ChainComplex({0: matrix(GF(5), [[3, 1],[1, 2]])}) sage: D.betti() {0: 1, 1: 1} """ @@ -1488,7 +1500,7 @@ def torsion_list(self, max_prime, min_prime=2): ALGORITHM: - let `C` denote the chain complex. Let `P` equal + Let `C` denote the chain complex. Let `P` equal ``max_prime``. Compute the mod `P` homology of `C`, and use this as the base-line computation: the assumption is that this is isomorphic to the integral homology tensored with @@ -1501,18 +1513,21 @@ def torsion_list(self, max_prime, min_prime=2): sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) sage: C.homology() {0: Z x Z, 1: Z x C3} - sage: C.torsion_list(11) + sage: C.torsion_list(11) # needs sage.rings.finite_rings [(3, [1])] sage: C = ChainComplex([matrix(ZZ, 1, 1, [2]), matrix(ZZ, 1, 1), matrix(1, 1, [3])]) sage: C.homology(1) C2 sage: C.homology(3) C3 - sage: C.torsion_list(5) + sage: C.torsion_list(5) # needs sage.rings.finite_rings [(2, [1]), (3, [3])] """ if self.base_ring() != ZZ: raise NotImplementedError('only implemented for base ring the integers') + + from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + answer = [] torsion_free = self.betti(base_ring=GF(max_prime)) for p in prime_range(min_prime, max_prime): @@ -1538,7 +1553,7 @@ def torsion_list(self, max_prime, min_prime=2): for i in diff_dict: if diff_dict[i] != 0: differences.append(i) - answer.append((p,differences)) + answer.append((p, differences)) return answer def _Hom_(self, other, category=None): @@ -1548,11 +1563,12 @@ def _Hom_(self, other, category=None): EXAMPLES:: + sage: # needs sage.graphs sage: S = simplicial_complexes.Sphere(2) sage: T = simplicial_complexes.Torus() - sage: C = S.chain_complex(augmented=True,cochain=True) - sage: D = T.chain_complex(augmented=True,cochain=True) - sage: Hom(C,D) # indirect doctest + sage: C = S.chain_complex(augmented=True, cochain=True) + sage: D = T.chain_complex(augmented=True, cochain=True) + sage: Hom(C, D) # indirect doctest Set of Morphisms from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring in Category of chain complexes over Integer Ring @@ -1614,6 +1630,7 @@ def shift(self, n=1): EXAMPLES:: + sage: # needs sage.graphs sage: S1 = simplicial_complexes.Sphere(1).chain_complex() sage: S1.shift(1).differential(2) == -S1.differential(1) True @@ -1626,6 +1643,7 @@ def shift(self, n=1): direction. Topologically, this makes sense if we grade the cochain complex for a space negatively:: + sage: # needs sage.graphs sage: T = simplicial_complexes.Torus() sage: co_T = T.chain_complex()._flip_() sage: co_T.homology() @@ -1640,7 +1658,7 @@ def shift(self, n=1): ``-n * deg``, if ``deg`` is the degree of the differential:: sage: C = ChainComplex({-2: matrix(ZZ, 0, 1)}) - sage: C.tensor(co_T).homology() + sage: C.tensor(co_T).homology() # needs sage.graphs {-4: Z, -3: Z x Z, -2: Z} """ deg = self.degree_of_differential() @@ -1676,7 +1694,7 @@ def _chomp_repr_(self): deprecation(33777, "the CHomP interface is deprecated; hence so is this function") deg = self.degree_of_differential() if (self.grading_group() != ZZ or - (deg != 1 and deg != -1)): + (deg != 1 and deg != -1)): raise ValueError('CHomP only works on Z-graded chain complexes with ' 'differential of degree 1 or -1') base_ring = self.base_ring() @@ -1688,7 +1706,7 @@ def _chomp_repr_(self): diffs = self._flip_().differential() if len(diffs) == 0: - diffs = {0: matrix(ZZ, 0,0)} + diffs = {0: matrix(ZZ, 0, 0)} maxdim = max(diffs) mindim = min(diffs) @@ -2003,7 +2021,7 @@ def cartesian_product(self, *factors, **kwds): diffs = [D.differential() for D in factors] keys = reduce(lambda X, d: X.union(d.keys()), diffs, set()) ret = {k: matrix.block_diagonal([d.get(k, zero) for d in diffs], - subdivide=subdivide) + subdivide=subdivide) for k in keys} return ChainComplex(ret, degree_of_differential=deg_diff, grading_group=self._grading_group) @@ -2168,32 +2186,32 @@ def scalar(a): # Our choice for tensor products will be x # y = x1 * y + x2 * y + ... # Generate the data for the differential - for a,r in deg: - for b,s in degD: + for a, r in deg: + for b, s in degD: rp = d[a].nrows() sp = dD[b].nrows() if a+b not in diff: diff[a+b] = {} mor = diff[a+b] cur = {} - cur[(a+deg_diff,b)] = [] - cur[(a,b+deg_diff)] = [] + cur[(a+deg_diff, b)] = [] + cur[(a, b+deg_diff)] = [] for i in range(r): for j in range(s): # \partial x_i \otimes y_j vec = [zero]*(rp*s) - for k,val in enumerate(d[a].column(i)): + for k, val in enumerate(d[a].column(i)): vec[s*k+j] += val - cur[(a+deg_diff,b)].append(vec) + cur[(a+deg_diff, b)].append(vec) # (-1)^a x_i \otimes \partial y_j vec = [zero]*(r*sp) - for k,val in enumerate(dD[b].column(j)): + for k, val in enumerate(dD[b].column(j)): vec[sp*i+k] += scalar(a) * val - cur[(a,b+deg_diff)].append(vec) + cur[(a, b+deg_diff)].append(vec) - mor[a,b] = cur + mor[a, b] = cur # Parse the data into matrices to_delete = [] @@ -2236,5 +2254,5 @@ def scalar(a): return ret -from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.homology.chain_complex', 'ChainComplex', ChainComplex_class) diff --git a/src/sage/homology/chain_complex_homspace.py b/src/sage/homology/chain_complex_homspace.py index 5679b275a82..ad7a6bf9b84 100644 --- a/src/sage/homology/chain_complex_homspace.py +++ b/src/sage/homology/chain_complex_homspace.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs (because all doctests use SimplicialComplex) r""" Homspaces between chain complexes @@ -12,77 +13,80 @@ sage: S = simplicial_complexes.Sphere(2) sage: T = simplicial_complexes.Torus() - sage: C = S.chain_complex(augmented=True,cochain=True) - sage: D = T.chain_complex(augmented=True,cochain=True) - sage: G = Hom(C,D) - sage: G - Set of Morphisms from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring in Category of chain complexes over Integer Ring - - sage: S = simplicial_complexes.ChessboardComplex(3,3) + sage: C = S.chain_complex(augmented=True, cochain=True) + sage: D = T.chain_complex(augmented=True, cochain=True) + sage: G = Hom(C, D); G + Set of Morphisms + from Chain complex with at most 4 nonzero terms over Integer Ring + to Chain complex with at most 4 nonzero terms over Integer Ring + in Category of chain complexes over Integer Ring + + sage: S = simplicial_complexes.ChessboardComplex(3, 3) sage: H = Hom(S,S) sage: i = H.identity() - sage: x = i.associated_chain_complex_morphism(augmented=True) - sage: x + sage: x = i.associated_chain_complex_morphism(augmented=True); x Chain complex morphism: From: Chain complex with at most 4 nonzero terms over Integer Ring - To: Chain complex with at most 4 nonzero terms over Integer Ring + To: Chain complex with at most 4 nonzero terms over Integer Ring sage: x._matrix_dictionary - {-1: [1], 0: [1 0 0 0 0 0 0 0 0] - [0 1 0 0 0 0 0 0 0] - [0 0 1 0 0 0 0 0 0] - [0 0 0 1 0 0 0 0 0] - [0 0 0 0 1 0 0 0 0] - [0 0 0 0 0 1 0 0 0] - [0 0 0 0 0 0 1 0 0] - [0 0 0 0 0 0 0 1 0] - [0 0 0 0 0 0 0 0 1], 1: [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] - [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] - [0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] - [0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0] - [0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0] - [0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0] - [0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0] - [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0] - [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0] - [0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0] - [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] - [0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0] - [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0] - [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0] - [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0] - [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0] - [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0] - [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1], 2: [1 0 0 0 0 0] - [0 1 0 0 0 0] - [0 0 1 0 0 0] - [0 0 0 1 0 0] - [0 0 0 0 1 0] - [0 0 0 0 0 1]} + {-1: [1], + 0: [1 0 0 0 0 0 0 0 0] + [0 1 0 0 0 0 0 0 0] + [0 0 1 0 0 0 0 0 0] + [0 0 0 1 0 0 0 0 0] + [0 0 0 0 1 0 0 0 0] + [0 0 0 0 0 1 0 0 0] + [0 0 0 0 0 0 1 0 0] + [0 0 0 0 0 0 0 1 0] + [0 0 0 0 0 0 0 0 1], + 1: [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0] + [0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0] + [0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0] + [0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0] + [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0] + [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0] + [0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0] + [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] + [0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0] + [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0] + [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0] + [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0] + [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0] + [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0] + [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1], + 2: [1 0 0 0 0 0] + [0 1 0 0 0 0] + [0 0 1 0 0 0] + [0 0 0 1 0 0] + [0 0 0 0 1 0] + [0 0 0 0 0 1]} sage: S = simplicial_complexes.Sphere(2) - sage: A = Hom(S,S) + sage: A = Hom(S, S) sage: i = A.identity() - sage: x = i.associated_chain_complex_morphism() - sage: x + sage: x = i.associated_chain_complex_morphism(); x Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Integer Ring To: Chain complex with at most 3 nonzero terms over Integer Ring sage: y = x*4 sage: z = y*y - sage: (y+z) + sage: y + z Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Integer Ring To: Chain complex with at most 3 nonzero terms over Integer Ring sage: f = x._matrix_dictionary sage: C = S.chain_complex() - sage: G = Hom(C,C) + sage: G = Hom(C, C) sage: w = G(f) sage: w == x True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 D. Benjamin Antieau <d.ben.antieau@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) @@ -96,7 +100,7 @@ # # https://www.gnu.org/licenses/ # -#***************************************************************************** +# **************************************************************************** import sage.categories.homset from sage.homology.chain_complex_morphism import ChainComplexMorphism @@ -111,7 +115,7 @@ def is_ChainComplexHomspace(x): sage: from sage.homology.chain_complex_homspace import is_ChainComplexHomspace sage: T = SimplicialComplex([[1,2,3,4],[7,8,9]]) sage: C = T.chain_complex(augmented=True, cochain=True) - sage: G = Hom(C,C) + sage: G = Hom(C, C) sage: is_ChainComplexHomspace(G) True @@ -127,9 +131,12 @@ class ChainComplexHomspace(sage.categories.homset.Homset): sage: T = SimplicialComplex([[1,2,3,4],[7,8,9]]) sage: C = T.chain_complex(augmented=True, cochain=True) - sage: G = Hom(C,C) + sage: G = Hom(C, C) sage: G - Set of Morphisms from Chain complex with at most 5 nonzero terms over Integer Ring to Chain complex with at most 5 nonzero terms over Integer Ring in Category of chain complexes over Integer Ring + Set of Morphisms + from Chain complex with at most 5 nonzero terms over Integer Ring + to Chain complex with at most 5 nonzero terms over Integer Ring + in Category of chain complexes over Integer Ring """ def __call__(self, f): @@ -139,10 +146,10 @@ def __call__(self, f): EXAMPLES:: sage: S = simplicial_complexes.Sphere(5) - sage: H = Hom(S,S) + sage: H = Hom(S, S) sage: i = H.identity() sage: C = S.chain_complex() - sage: G = Hom(C,C) + sage: G = Hom(C, C) sage: x = i.associated_chain_complex_morphism() sage: f = x._matrix_dictionary sage: y = G(f) diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index b049b534e0b..2a182b24cdc 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -14,28 +14,29 @@ EXAMPLES:: - sage: S = simplicial_complexes.Sphere(1) - sage: S + sage: # needs sage.graphs + sage: S = simplicial_complexes.Sphere(1); S Minimal triangulation of the 1-sphere sage: C = S.chain_complex() sage: C.differential() {0: [], 1: [-1 -1 0] [ 1 0 -1] [ 0 1 1], 2: []} - sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)} - sage: G = Hom(C,C) - sage: x = G(f) - sage: x - Chain complex endomorphism of Chain complex with at most 2 nonzero terms over Integer Ring + sage: f = {0: zero_matrix(ZZ,3,3), 1: zero_matrix(ZZ,3,3)} + sage: G = Hom(C, C) + sage: x = G(f); x + Chain complex endomorphism of + Chain complex with at most 2 nonzero terms over Integer Ring sage: x._matrix_dictionary {0: [0 0 0] - [0 0 0] - [0 0 0], 1: [0 0 0] - [0 0 0] - [0 0 0]} + [0 0 0] + [0 0 0], + 1: [0 0 0] + [0 0 0] + [0 0 0]} """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 D. Benjamin Antieau <d.ben.antieau@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) @@ -49,7 +50,7 @@ # # https://www.gnu.org/licenses/ # -#***************************************************************************** +# **************************************************************************** from sage.matrix.constructor import block_diagonal_matrix, zero_matrix from sage.categories.morphism import Morphism @@ -63,10 +64,11 @@ def is_ChainComplexMorphism(x): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.homology.chain_complex_morphism import is_ChainComplexMorphism sage: S = simplicial_complexes.Sphere(14) sage: H = Hom(S,S) - sage: i = H.identity() # long time (8s on sage.math, 2011) + sage: i = H.identity() # long time (8s on sage.math, 2011) sage: S = simplicial_complexes.Sphere(6) sage: H = Hom(S,S) sage: i = H.identity() @@ -91,31 +93,35 @@ def __init__(self, matrices, C, D, check=True): EXAMPLES:: - sage: S = simplicial_complexes.Sphere(1) - sage: S + sage: # needs sage.graphs + sage: S = simplicial_complexes.Sphere(1); S Minimal triangulation of the 1-sphere sage: C = S.chain_complex() sage: C.differential() - {0: [], 1: [-1 -1 0] - [ 1 0 -1] - [ 0 1 1], 2: []} + {0: [], + 1: [-1 -1 0] + [ 1 0 -1] + [ 0 1 1], + 2: []} sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)} sage: G = Hom(C,C) - sage: x = G(f) - sage: x - Chain complex endomorphism of Chain complex with at most 2 nonzero terms over Integer Ring + sage: x = G(f); x + Chain complex endomorphism of + Chain complex with at most 2 nonzero terms over Integer Ring sage: x._matrix_dictionary {0: [0 0 0] - [0 0 0] - [0 0 0], 1: [0 0 0] - [0 0 0] - [0 0 0]} + [0 0 0] + [0 0 0], + 1: [0 0 0] + [0 0 0] + [0 0 0]} Check that the bug in :trac:`13220` has been fixed:: + sage: # needs sage.graphs sage: X = simplicial_complexes.Simplex(1) sage: Y = simplicial_complexes.Simplex(0) - sage: g = Hom(X,Y)({0:0, 1:0}) + sage: g = Hom(X,Y)({0: 0, 1: 0}) sage: g.associated_chain_complex_morphism() Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Integer Ring @@ -163,8 +169,8 @@ def __init__(self, matrices, C, D, check=True): # Check sizes of matrices. for i in matrices: if (matrices[i].nrows() != D.free_module_rank(i) or - matrices[i].ncols() != C.free_module_rank(i)): - raise ValueError('matrix in degree {} is not the right size'.format(i)) + matrices[i].ncols() != C.free_module_rank(i)): + raise ValueError(f'matrix in degree {i} is not the right size') # Check commutativity. for i in degrees: if i - d not in degrees: @@ -185,11 +191,11 @@ def __init__(self, matrices, C, D, check=True): # Use immutable matrices because they're hashable. m.set_immutable() self._matrix_dictionary[i] = m - Morphism.__init__(self, Hom(C,D, ChainComplexes(C.base_ring()))) + Morphism.__init__(self, Hom(C, D, ChainComplexes(C.base_ring()))) def in_degree(self, n): """ - The matrix representing this morphism in degree n + The matrix representing this morphism in degree `n`. INPUT: @@ -264,6 +270,7 @@ def dual(self): EXAMPLES:: + sage: # needs sage.graphs sage: X = simplicial_complexes.Simplex(1) sage: Y = simplicial_complexes.Simplex(0) sage: g = Hom(X,Y)({0:0, 1:0}) @@ -273,7 +280,7 @@ def dual(self): sage: f.dual() Chain complex morphism: From: Chain complex with at most 1 nonzero terms over Integer Ring - To: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: f.dual().in_degree(0) [1] [1] @@ -295,6 +302,7 @@ def __neg__(self): EXAMPLES:: + sage: # needs sage.graphs sage: S = simplicial_complexes.Sphere(2) sage: H = Hom(S,S) sage: i = H.identity() @@ -302,19 +310,19 @@ def __neg__(self): sage: w = -x sage: w._matrix_dictionary {0: [-1 0 0 0] - [ 0 -1 0 0] - [ 0 0 -1 0] - [ 0 0 0 -1], + [ 0 -1 0 0] + [ 0 0 -1 0] + [ 0 0 0 -1], 1: [-1 0 0 0 0 0] - [ 0 -1 0 0 0 0] - [ 0 0 -1 0 0 0] - [ 0 0 0 -1 0 0] - [ 0 0 0 0 -1 0] - [ 0 0 0 0 0 -1], + [ 0 -1 0 0 0 0] + [ 0 0 -1 0 0 0] + [ 0 0 0 -1 0 0] + [ 0 0 0 0 -1 0] + [ 0 0 0 0 0 -1], 2: [-1 0 0 0] - [ 0 -1 0 0] - [ 0 0 -1 0] - [ 0 0 0 -1]} + [ 0 -1 0 0] + [ 0 0 -1 0] + [ 0 0 0 -1]} """ f = dict() @@ -322,12 +330,13 @@ def __neg__(self): f[i] = -self._matrix_dictionary[i] return ChainComplexMorphism(f, self.domain(), self.codomain()) - def __add__(self,x): + def __add__(self, x): """ Return ``self + x``. EXAMPLES:: + sage: # needs sage.graphs sage: S = simplicial_complexes.Sphere(2) sage: H = Hom(S,S) sage: i = H.identity() @@ -335,19 +344,19 @@ def __add__(self,x): sage: z = x+x sage: z._matrix_dictionary {0: [2 0 0 0] - [0 2 0 0] - [0 0 2 0] - [0 0 0 2], + [0 2 0 0] + [0 0 2 0] + [0 0 0 2], 1: [2 0 0 0 0 0] - [0 2 0 0 0 0] - [0 0 2 0 0 0] - [0 0 0 2 0 0] - [0 0 0 0 2 0] - [0 0 0 0 0 2], + [0 2 0 0 0 0] + [0 0 2 0 0 0] + [0 0 0 2 0 0] + [0 0 0 0 2 0] + [0 0 0 0 0 2], 2: [2 0 0 0] - [0 2 0 0] - [0 0 2 0] - [0 0 0 2]} + [0 2 0 0] + [0 0 2 0] + [0 0 0 2]} """ if not isinstance(x, ChainComplexMorphism) or self.codomain() != x.codomain() or self.domain() != x.domain() or self._matrix_dictionary.keys() != x._matrix_dictionary.keys(): raise TypeError("unsupported operation") @@ -363,6 +372,7 @@ def __mul__(self, x): EXAMPLES:: + sage: # needs sage.graphs sage: S = simplicial_complexes.Sphere(2) sage: H = Hom(S,S) sage: i = H.identity() @@ -370,35 +380,35 @@ def __mul__(self, x): sage: y = x*2 sage: y._matrix_dictionary {0: [2 0 0 0] - [0 2 0 0] - [0 0 2 0] - [0 0 0 2], + [0 2 0 0] + [0 0 2 0] + [0 0 0 2], 1: [2 0 0 0 0 0] - [0 2 0 0 0 0] - [0 0 2 0 0 0] - [0 0 0 2 0 0] - [0 0 0 0 2 0] - [0 0 0 0 0 2], + [0 2 0 0 0 0] + [0 0 2 0 0 0] + [0 0 0 2 0 0] + [0 0 0 0 2 0] + [0 0 0 0 0 2], 2: [2 0 0 0] - [0 2 0 0] - [0 0 2 0] - [0 0 0 2]} + [0 2 0 0] + [0 0 2 0] + [0 0 0 2]} sage: z = y*y sage: z._matrix_dictionary {0: [4 0 0 0] - [0 4 0 0] - [0 0 4 0] - [0 0 0 4], + [0 4 0 0] + [0 0 4 0] + [0 0 0 4], 1: [4 0 0 0 0 0] - [0 4 0 0 0 0] - [0 0 4 0 0 0] - [0 0 0 4 0 0] - [0 0 0 0 4 0] - [0 0 0 0 0 4], + [0 4 0 0 0 0] + [0 0 4 0 0 0] + [0 0 0 4 0 0] + [0 0 0 0 4 0] + [0 0 0 0 0 4], 2: [4 0 0 0] - [0 4 0 0] - [0 0 4 0] - [0 0 0 4]} + [0 4 0 0] + [0 0 4 0] + [0 0 0 4]} TESTS: @@ -413,7 +423,7 @@ def __mul__(self, x): [2] Before :trac:`19065`, the following multiplication produced a - ``KeyError`` because `f` was not explicitly defined in degree 2:: + :class:`KeyError` because `f` was not explicitly defined in degree 2:: sage: C0 = ChainComplex({0: zero_matrix(ZZ, 0, 1)}) sage: C1 = ChainComplex({1: zero_matrix(ZZ, 0, 1)}) @@ -429,7 +439,7 @@ def __mul__(self, x): sage: g._matrix_dictionary {1: [], 2: []} """ - if not isinstance(x,ChainComplexMorphism) or self.domain() != x.codomain(): + if not isinstance(x, ChainComplexMorphism) or self.domain() != x.codomain(): try: y = self.domain().base_ring()(x) except TypeError: @@ -437,18 +447,19 @@ def __mul__(self, x): f = dict() for i in self._matrix_dictionary: f[i] = self._matrix_dictionary[i] * y - return ChainComplexMorphism(f,self.domain(),self.codomain()) - f = dict() + return ChainComplexMorphism(f, self.domain(), self.codomain()) + f = {} for i in self._matrix_dictionary: f[i] = self._matrix_dictionary[i]*x.in_degree(i) - return ChainComplexMorphism(f,x.domain(),self.codomain()) + return ChainComplexMorphism(f, x.domain(), self.codomain()) - def __rmul__(self,x): + def __rmul__(self, x): """ Return ``x * self`` if ``x`` is an element of the base ring. EXAMPLES:: + sage: # needs sage.graphs sage: S = simplicial_complexes.Sphere(2) sage: H = Hom(S,S) sage: i = H.identity() @@ -463,21 +474,22 @@ def __rmul__(self,x): except TypeError: raise TypeError("multiplication is not defined") f = dict() - for i in self._matrix_dictionary.keys(): + for i in self._matrix_dictionary: f[i] = y * self._matrix_dictionary[i] - return ChainComplexMorphism(f,self.domain(),self.codomain()) + return ChainComplexMorphism(f, self.domain(), self.codomain()) - def __sub__(self,x): + def __sub__(self, x): """ Return ``self - x``. EXAMPLES:: + sage: # needs sage.graphs sage: S = simplicial_complexes.Sphere(2) sage: H = Hom(S,S) sage: i = H.identity() sage: x = i.associated_chain_complex_morphism() - sage: y = x-x + sage: y = x - x sage: y._matrix_dictionary {0: [0 0 0 0] [0 0 0 0] @@ -496,17 +508,17 @@ def __sub__(self,x): """ return self + (-x) - def __eq__(self,x): + def __eq__(self, x): """ Return ``True`` if and only if ``self == x``. EXAMPLES:: + sage: # needs sage.graphs sage: S = SimplicialComplex(is_mutable=False) sage: H = Hom(S,S) sage: i = H.identity() - sage: x = i.associated_chain_complex_morphism() - sage: x + sage: x = i.associated_chain_complex_morphism(); x Chain complex morphism: From: Trivial chain complex over Integer Ring To: Trivial chain complex over Integer Ring @@ -517,17 +529,18 @@ def __eq__(self,x): sage: x == y True """ - return isinstance(x,ChainComplexMorphism) \ - and self.codomain() == x.codomain() \ - and self.domain() == x.domain() \ - and self._matrix_dictionary == x._matrix_dictionary + return isinstance(x, ChainComplexMorphism) \ + and self.codomain() == x.codomain() \ + and self.domain() == x.domain() \ + and self._matrix_dictionary == x._matrix_dictionary - def is_identity(self): + def is_identity(self) -> bool: """ - True if this is the identity map. + Return ``True`` if this is the identity map. EXAMPLES:: + sage: # needs sage.graphs sage: S = SimplicialComplex(is_mutable=False) sage: H = Hom(S,S) sage: i = H.identity() @@ -537,18 +550,20 @@ def is_identity(self): """ return self.to_matrix().is_one() - def is_surjective(self): + def is_surjective(self) -> bool: """ - True if this map is surjective. + Return ``True`` if this map is surjective. EXAMPLES:: + sage: # needs sage.graphs sage: S1 = simplicial_complexes.Sphere(1) sage: H = Hom(S1, S1) sage: flip = H({0:0, 1:2, 2:1}) sage: flip.associated_chain_complex_morphism().is_surjective() True + sage: # needs sage.graphs sage: pt = simplicial_complexes.Simplex(0) sage: inclusion = Hom(pt, S1)({0:2}) sage: inclusion.associated_chain_complex_morphism().is_surjective() @@ -561,16 +576,18 @@ def is_surjective(self): def is_injective(self): """ - True if this map is injective. + Return ``True`` if this map is injective. EXAMPLES:: + sage: # needs sage.graphs sage: S1 = simplicial_complexes.Sphere(1) sage: H = Hom(S1, S1) sage: flip = H({0:0, 1:2, 2:1}) sage: flip.associated_chain_complex_morphism().is_injective() True + sage: # needs sage.graphs sage: pt = simplicial_complexes.Simplex(0) sage: inclusion = Hom(pt, S1)({0:2}) sage: inclusion.associated_chain_complex_morphism().is_injective() diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index afeaee2430c..91ae14eda11 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -121,7 +121,8 @@ def __init__(self, matrices, f, g=None): `f - (H \partial + \partial H)`. :: sage: from sage.homology.chain_homotopy import ChainHomotopy - sage: C = ChainComplex({1: matrix(ZZ, 1, 2, (1,0)), 2: matrix(ZZ, 2, 1, (0, 2))}, degree_of_differential=-1) + sage: C = ChainComplex({1: matrix(ZZ, 1, 2, (1,0)), 2: matrix(ZZ, 2, 1, (0, 2))}, + ....: degree_of_differential=-1) sage: D = ChainComplex({2: matrix(ZZ, 1, 1, (6,))}, degree_of_differential=-1) sage: f_d = {1: matrix(ZZ, 1, 2, (0,3)), 2: identity_matrix(ZZ, 1)} sage: f = Hom(C,D)(f_d) @@ -212,15 +213,23 @@ def is_algebraic_gradient_vector_field(self): `\ZZ` in degree 0. Two chain maps `C \to C` will be chain homotopic as long as they agree in degree 0. :: - sage: f = Hom(C,C)({0: identity_matrix(ZZ, 1), 1: matrix(ZZ, 1, 1, [3]), 2: matrix(ZZ, 1, 1, [3])}) - sage: g = Hom(C,C)({0: identity_matrix(ZZ, 1), 1: matrix(ZZ, 1, 1, [2]), 2: matrix(ZZ, 1, 1, [2])}) - sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, f, g) + sage: f = Hom(C,C)({0: identity_matrix(ZZ, 1), + ....: 1: matrix(ZZ, 1, 1, [3]), + ....: 2: matrix(ZZ, 1, 1, [3])}) + sage: g = Hom(C,C)({0: identity_matrix(ZZ, 1), + ....: 1: matrix(ZZ, 1, 1, [2]), + ....: 2: matrix(ZZ, 1, 1, [2])}) + sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), + ....: 1: zero_matrix(ZZ, 1), + ....: 2: identity_matrix(ZZ, 1)}, f, g) sage: H.is_algebraic_gradient_vector_field() True A chain homotopy which is not an algebraic gradient vector field:: - sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: identity_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, f, g) + sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), + ....: 1: identity_matrix(ZZ, 1), + ....: 2: identity_matrix(ZZ, 1)}, f, g) sage: H.is_algebraic_gradient_vector_field() False """ @@ -251,9 +260,15 @@ def is_homology_gradient_vector_field(self): sage: from sage.homology.chain_homotopy import ChainHomotopy sage: C = ChainComplex({0: zero_matrix(ZZ, 1), 1: identity_matrix(ZZ, 1)}) - sage: f = Hom(C,C)({0: identity_matrix(ZZ, 1), 1: matrix(ZZ, 1, 1, [3]), 2: matrix(ZZ, 1, 1, [3])}) - sage: g = Hom(C,C)({0: identity_matrix(ZZ, 1), 1: matrix(ZZ, 1, 1, [2]), 2: matrix(ZZ, 1, 1, [2])}) - sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, f, g) + sage: f = Hom(C,C)({0: identity_matrix(ZZ, 1), + ....: 1: matrix(ZZ, 1, 1, [3]), + ....: 2: matrix(ZZ, 1, 1, [3])}) + sage: g = Hom(C,C)({0: identity_matrix(ZZ, 1), + ....: 1: matrix(ZZ, 1, 1, [2]), + ....: 2: matrix(ZZ, 1, 1, [2])}) + sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), + ....: 1: zero_matrix(ZZ, 1), + ....: 2: identity_matrix(ZZ, 1)}, f, g) sage: H.is_homology_gradient_vector_field() True """ @@ -281,8 +296,8 @@ def in_degree(self, n): EXAMPLES:: sage: from sage.homology.chain_homotopy import ChainHomotopy - sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 - sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 + sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 sage: f = Hom(C, D)({}) sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) sage: H.in_degree(1) @@ -316,8 +331,8 @@ def dual(self): EXAMPLES:: sage: from sage.homology.chain_homotopy import ChainHomotopy - sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 - sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 + sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 sage: f = Hom(C, D)({}) sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) sage: H.in_degree(1) @@ -336,8 +351,8 @@ def __hash__(self): TESTS:: sage: from sage.homology.chain_homotopy import ChainHomotopy - sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 - sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 + sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 sage: f = Hom(C, D)({}) sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) sage: hash(H) # random @@ -347,7 +362,7 @@ def __hash__(self): def _repr_(self): """ - String representation + String representation. EXAMPLES:: @@ -370,6 +385,7 @@ def _repr_(self): s += '\n and {}'.format('\n '.join(self._g._repr_().split('\n'))) return s + class ChainContraction(ChainHomotopy): r""" A chain contraction. @@ -403,7 +419,9 @@ class ChainContraction(ChainHomotopy): sage: pi = Hom(C,D)({0: identity_matrix(ZZ, 1)}) sage: iota = Hom(D,C)({0: identity_matrix(ZZ, 1)}) - sage: H = ChainContraction({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, pi, iota) + sage: H = ChainContraction({0: zero_matrix(ZZ, 0, 1), + ....: 1: zero_matrix(ZZ, 1), + ....: 2: identity_matrix(ZZ, 1)}, pi, iota) """ def __init__(self, matrices, pi, iota): r""" @@ -488,6 +506,7 @@ def pi(self): EXAMPLES:: + sage: # needs sage.graphs sage: S2 = simplicial_complexes.Sphere(2) sage: phi, M = S2.algebraic_topological_model(QQ) sage: phi.pi() @@ -501,7 +520,7 @@ def pi(self): The degree 2 homology generator is detected on a single simplex:: - sage: phi.pi().in_degree(2) + sage: phi.pi().in_degree(2) # needs sage.graphs [0 0 0 1] """ return self._pi @@ -512,16 +531,16 @@ def iota(self): EXAMPLES:: - sage: S2 = simplicial_complexes.Sphere(2) - sage: phi, M = S2.algebraic_topological_model(QQ) - sage: phi.iota() + sage: S2 = simplicial_complexes.Sphere(2) # needs sage.graphs + sage: phi, M = S2.algebraic_topological_model(QQ) # needs sage.graphs + sage: phi.iota() # needs sage.graphs Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field Lifting the degree zero homology class gives a single vertex:: - sage: phi.iota().in_degree(0) + sage: phi.iota().in_degree(0) # needs sage.graphs [0] [0] [0] @@ -530,7 +549,7 @@ def iota(self): Lifting the degree two homology class gives the signed sum of all of the 2-simplices:: - sage: phi.iota().in_degree(2) + sage: phi.iota().in_degree(2) # needs sage.graphs [-1] [ 1] [-1] @@ -546,9 +565,9 @@ def dual(self): EXAMPLES:: - sage: S2 = simplicial_complexes.Sphere(2) - sage: phi, M = S2.algebraic_topological_model(QQ) - sage: phi.iota() + sage: S2 = simplicial_complexes.Sphere(2) # needs sage.graphs + sage: phi, M = S2.algebraic_topological_model(QQ) # needs sage.graphs + sage: phi.iota() # needs sage.graphs Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field @@ -557,6 +576,7 @@ def dual(self): but the degree zero cohomology class needs to be detected on every vertex, and vice versa for degree 2:: + sage: # needs sage.graphs sage: phi.iota().in_degree(0) [0] [0] diff --git a/src/sage/homology/chains.py b/src/sage/homology/chains.py index 7bd375f35fd..87c0947c0b0 100644 --- a/src/sage/homology/chains.py +++ b/src/sage/homology/chains.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs (because all doctests use the catalogs simplicial_complexes, cubical_complexes) r""" Chains and cochains @@ -10,14 +10,14 @@ complex. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Volker Braun <vbraun.name@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.free_module import CombinatorialFreeModule @@ -672,9 +672,9 @@ def cup_product(self, cochain): accumulator = codomain.zero() for cell in codomain.indices(): for (coeff, left_cell, right_cell) in cx.alexander_whitney(cell, left_deg): - if not coeff: - continue - left = left_chains(left_cell) - right = right_chains(right_cell) - accumulator += codomain(cell) * coeff * self.eval(left) * cochain.eval(right) + if not coeff: + continue + left = left_chains(left_cell) + right = right_chains(right_cell) + accumulator += codomain(cell) * coeff * self.eval(left) * cochain.eval(right) return accumulator diff --git a/src/sage/homology/cubical_complex.py b/src/sage/homology/cubical_complex.py deleted file mode 100644 index 1149da028c0..00000000000 --- a/src/sage/homology/cubical_complex.py +++ /dev/null @@ -1,17 +0,0 @@ -# -*- coding: utf-8 -*- -r""" -Finite cubical complexes: deprecated - -The current version is :mod:`sage.topology.cubical_complexes`. -""" - -from sage.misc.superseded import deprecated_function_alias -import sage.topology.cubical_complex - -Cube = deprecated_function_alias(31925, sage.topology.cubical_complex.Cube) -CubicalComplex = deprecated_function_alias(31925, - sage.topology.cubical_complex.CubicalComplex) -CubicalComplexExamples = deprecated_function_alias(31925, - sage.topology.cubical_complex.CubicalComplexExamples) -cubical_complexes = deprecated_function_alias(31925, - sage.topology.cubical_complex.cubical_complexes) diff --git a/src/sage/homology/delta_complex.py b/src/sage/homology/delta_complex.py deleted file mode 100644 index cfd5fc6119f..00000000000 --- a/src/sage/homology/delta_complex.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- -r""" -Finite Delta-complexes: deprecated - -The current version is :mod:`sage.topology.delta_complexes`. -""" -from sage.misc.superseded import deprecated_function_alias -import sage.topology.delta_complex - -DeltaComplex = deprecated_function_alias(31925, - sage.topology.delta_complex.DeltaComplex) -DeltaComplexExamples = deprecated_function_alias(31925, - sage.topology.delta_complex.DeltaComplexExamples) -delta_complexes = deprecated_function_alias(31925, - sage.topology.delta_complex.delta_complexes) diff --git a/src/sage/homology/examples.py b/src/sage/homology/examples.py deleted file mode 100644 index c469f9d6c54..00000000000 --- a/src/sage/homology/examples.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Examples of simplicial complexes: deprecated - -The current version is :mod:`sage.topology.simplicial_complex_examples`. -""" - -from sage.misc.superseded import deprecated_function_alias -import sage.topology.simplicial_complex_examples - -for f in ['facets_for_RP4', - 'facets_for_K3', - 'matching', - 'UniqueSimplicialComplex', - 'Sphere', - 'Simplex', - 'Torus', - 'RealProjectivePlane', - 'ProjectivePlane', - 'KleinBottle', - 'SurfaceOfGenus', - 'MooreSpace', - 'ComplexProjectivePlane', - 'QuaternionicProjectivePlane', - 'PoincareHomologyThreeSphere', - 'RealProjectiveSpace', - 'K3Surface', - 'BarnetteSphere', - 'BrucknerGrunbaumSphere', - 'NotIConnectedGraphs', - 'MatchingComplex', - 'ChessboardComplex', - 'RandomComplex', - 'SumComplex', - 'RandomTwoSphere', - 'ShiftedComplex', - 'RudinBall', - 'ZieglerBall', - 'DunceHat', - 'FareyMap']: - exec('{} = deprecated_function_alias(31925, sage.topology.simplicial_complex_examples.{})'.format(f, f)) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 424086d283e..e3d38de4240 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular r""" Free resolutions @@ -17,29 +18,25 @@ sage: from sage.homology.free_resolution import FreeResolution sage: S.<x,y,z,w> = PolynomialRing(QQ) sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() - sage: r = FreeResolution(m, name='S') - sage: r + sage: r = FreeResolution(m, name='S'); r S^1 <-- S^3 <-- S^2 <-- 0 sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = I.free_resolution() - sage: r + sage: r = I.free_resolution(); r S^1 <-- S^3 <-- S^2 <-- 0 :: sage: S.<x,y,z,w> = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = I.graded_free_resolution() - sage: r + sage: r = I.graded_free_resolution(); r S(0) <-- S(-2)โŠ•S(-2)โŠ•S(-2) <-- S(-3)โŠ•S(-3) <-- 0 An example of a minimal free resolution from [CLO2005]_:: sage: R.<x,y,z,w> = QQ[] sage: I = R.ideal([y*z - x*w, y^3 - x^2*z, x*z^2 - y^2*w, z^3 - y*w^2]) - sage: r = I.free_resolution() - sage: r + sage: r = I.free_resolution(); r S^1 <-- S^4 <-- S^4 <-- S^1 <-- 0 sage: len(r) 3 @@ -66,8 +63,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.libs.singular.singular import si2sa_resolution -from sage.libs.singular.function import singular_function from sage.misc.lazy_attribute import lazy_attribute from sage.misc.abstract_method import abstract_method from sage.misc.classcall_metaclass import ClasscallMetaclass @@ -136,8 +131,8 @@ def __classcall_private__(cls, module, *args, graded=False, degrees=None, shifts sage: Q = R.quo(I) sage: Q.is_integral_domain() False - sage: xb, yb = Q.gens() - sage: FreeResolution(Q.ideal([xb])) # has torsion + sage: xb, yb = Q.gens() # needs sage.rings.function_field + sage: FreeResolution(Q.ideal([xb])) # has torsion # needs sage.rings.function_field Traceback (most recent call last): ... NotImplementedError: the ring must be a polynomial ring using Singular @@ -298,12 +293,13 @@ def target(self): sage: r S(0) <-- S(-2)โŠ•S(-2)โŠ•S(-2) <-- S(-3)โŠ•S(-3) <-- 0 sage: r.target() - Quotient module by Submodule of Ambient free module of rank 1 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field - Generated by the rows of the matrix: - [-z^2 + y*w] - [ y*z - x*w] - [-y^2 + x*z] + Quotient module by + Submodule of Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] """ return self.differential(0).codomain() @@ -337,13 +333,14 @@ class FiniteFreeResolution(FreeResolution): sage: r.differential(0) Coercion map: From: Ambient free module of rank 1 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field - To: Quotient module by Submodule of Ambient free module of rank 1 - over the integral domain Multivariate Polynomial Ring in x, y, z, w over Rational Field - Generated by the rows of the matrix: - [-z^2 + y*w] - [ y*z - x*w] - [-y^2 + x*z] + Multivariate Polynomial Ring in x, y, z, w over Rational Field + To: Quotient module by + Submodule of Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] """ @lazy_attribute def _length(self): @@ -373,8 +370,7 @@ def _repr_(self): sage: S.<x,y,z,w> = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = I.graded_free_resolution() - sage: r + sage: r = I.graded_free_resolution(); r S(0) <-- S(-2)โŠ•S(-2)โŠ•S(-2) <-- S(-3)โŠ•S(-3) <-- 0 """ s = self._repr_module(0) @@ -393,8 +389,7 @@ def __len__(self): sage: S.<x,y,z,w> = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = I.graded_free_resolution() - sage: r + sage: r = I.graded_free_resolution(); r S(0) <-- S(-2)โŠ•S(-2)โŠ•S(-2) <-- S(-3)โŠ•S(-3) <-- 0 sage: len(r) 2 @@ -413,8 +408,7 @@ def __getitem__(self, i): sage: S.<x,y,z,w> = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = I.graded_free_resolution() - sage: r + sage: r = I.graded_free_resolution(); r S(0) <-- S(-2)โŠ•S(-2)โŠ•S(-2) <-- S(-3)โŠ•S(-3) <-- 0 sage: r.target() Quotient module by Submodule of Ambient free module of rank 1 over the integral domain @@ -450,38 +444,38 @@ def differential(self, i): sage: r S(0) <-- S(-2)โŠ•S(-2)โŠ•S(-2) <-- S(-3)โŠ•S(-3) <-- 0 sage: r.differential(3) - Free module morphism defined by the matrix - [] - Domain: Ambient free module of rank 0 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field - Codomain: Ambient free module of rank 2 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field + Free module morphism defined by the matrix [] + Domain: Ambient free module of rank 0 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 2 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field sage: r.differential(2) Free module morphism defined as left-multiplication by the matrix - [-y x] - [ z -y] - [-w z] - Domain: Ambient free module of rank 2 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field - Codomain: Ambient free module of rank 3 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field + [-y x] + [ z -y] + [-w z] + Domain: Ambient free module of rank 2 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 3 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field sage: r.differential(1) Free module morphism defined as left-multiplication by the matrix - [z^2 - y*w y*z - x*w y^2 - x*z] - Domain: Ambient free module of rank 3 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field - Codomain: Ambient free module of rank 1 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field + [z^2 - y*w y*z - x*w y^2 - x*z] + Domain: Ambient free module of rank 3 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field sage: r.differential(0) Coercion map: From: Ambient free module of rank 1 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field - To: Quotient module by Submodule of Ambient free module of rank 1 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field - Generated by the rows of the matrix: - [-z^2 + y*w] - [ y*z - x*w] - [-y^2 + x*z] + Multivariate Polynomial Ring in x, y, z, w over Rational Field + To: Quotient module by + Submodule of Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] """ if i < 0: raise IndexError('invalid index') @@ -516,8 +510,7 @@ def matrix(self, i): sage: S.<x,y,z,w> = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = I.graded_free_resolution() - sage: r + sage: r = I.graded_free_resolution(); r S(0) <-- S(-2)โŠ•S(-2)โŠ•S(-2) <-- S(-3)โŠ•S(-3) <-- 0 sage: r.matrix(3) [] @@ -572,9 +565,10 @@ def _initial_differential(self): sage: r._initial_differential Coercion map: From: Ambient free module of rank 1 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field - To: Quotient module by Submodule of Ambient free module of rank 1 - over the integral domain Multivariate Polynomial Ring in x, y, z, w over Rational Field + Multivariate Polynomial Ring in x, y, z, w over Rational Field + To: Quotient module by + Submodule of Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field Generated by the rows of the matrix: [-z^2 + y*w] [ y*z - x*w] @@ -646,15 +640,13 @@ class FiniteFreeResolution_free_module(FiniteFreeResolution): sage: M = R^3 sage: v = M([x^2, 2*x^2, 3*x^2]) sage: w = M([0, x, 2*x]) - sage: S = M.submodule([v, w]) - sage: S + sage: S = M.submodule([v, w]); S Free module of degree 3 and rank 2 over Univariate Polynomial Ring in x over Rational Field - Echelon basis matrix: - [ x^2 2*x^2 3*x^2] - [ 0 x 2*x] - sage: res = S.free_resolution() - sage: res + Echelon basis matrix: + [ x^2 2*x^2 3*x^2] + [ 0 x 2*x] + sage: res = S.free_resolution(); res S^3 <-- S^2 <-- 0 sage: ascii_art(res.chain_complex()) [ x^2 0] @@ -664,8 +656,7 @@ class FiniteFreeResolution_free_module(FiniteFreeResolution): sage: R.<x> = PolynomialRing(QQ) sage: I = R.ideal([x^4 + 3*x^2 + 2]) - sage: res = I.free_resolution() - sage: res + sage: res = I.free_resolution(); res S^1 <-- S^1 <-- 0 """ @lazy_attribute @@ -680,8 +671,7 @@ def _maps(self): sage: v = M([x^2, 2*x^2, 3*x^2]) sage: w = M([0, x, 2*x]) sage: S = M.submodule([v, w]) - sage: res = S.free_resolution() - sage: res + sage: res = S.free_resolution(); res S^3 <-- S^2 <-- 0 sage: ascii_art(res.chain_complex()) [ x^2 0] @@ -705,8 +695,7 @@ def _maps(self): sage: M = matrix([[x^2, 2], ....: [3*x^2, 5], ....: [5*x^2, 4]]) - sage: res = FreeResolution(M.transpose()) - sage: res + sage: res = FreeResolution(M.transpose()); res S^3 <-- S^2 <-- 0 sage: res._m() [ 1 0] @@ -721,8 +710,7 @@ def _maps(self): An overdetermined system over a PID:: - sage: res = FreeResolution(M) - sage: res + sage: res = FreeResolution(M); res S^2 <-- S^2 <-- 0 sage: res._m() [x^2 0] @@ -776,8 +764,7 @@ class FiniteFreeResolution_singular(FiniteFreeResolution): sage: from sage.homology.free_resolution import FreeResolution sage: S.<x,y,z,w> = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = FreeResolution(I) - sage: r + sage: r = FreeResolution(I); r S^1 <-- S^3 <-- S^2 <-- 0 sage: len(r) 2 @@ -797,8 +784,7 @@ class FiniteFreeResolution_singular(FiniteFreeResolution): the initial differential:: sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() - sage: r = FreeResolution(m, name='S') - sage: r + sage: r = FreeResolution(m, name='S'); r S^1 <-- S^3 <-- S^2 <-- 0 sage: r.matrix(1) [z^2 - y*w y*z - x*w y^2 - x*z] @@ -806,15 +792,13 @@ class FiniteFreeResolution_singular(FiniteFreeResolution): An additional construction is using a submodule of a free module:: sage: M = m.image() - sage: r = FreeResolution(M, name='S') - sage: r + sage: r = FreeResolution(M, name='S'); r S^1 <-- S^3 <-- S^2 <-- 0 A nonhomogeneous ideal:: sage: I = S.ideal([z^2 - y*w, y*z - x*w, y^2 - x]) - sage: R = FreeResolution(I) - sage: R + sage: R = FreeResolution(I); R S^1 <-- S^3 <-- S^3 <-- S^1 <-- 0 sage: R.matrix(2) [ y*z - x*w y^2 - x 0] @@ -866,6 +850,9 @@ def _maps(self): [z^2 - y*w y*z - x*w y^2 - x*z], [-w z] ] """ + from sage.libs.singular.singular import si2sa_resolution + from sage.libs.singular.function import singular_function + # This ensures the first component of the Singular resolution to be a # module, like the later components. This is important when the # components are converted to Sage modules. diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index d9aa9e11119..0c01ad6f423 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular r""" Graded free resolutions @@ -24,16 +25,16 @@ sage: d = r.differential(2) sage: d Free module morphism defined as left-multiplication by the matrix - [ y x] - [-z -y] - [ w z] - Domain: Ambient free module of rank 2 over the integral domain Multivariate Polynomial Ring - in x, y, z, w over Rational Field - Codomain: Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring - in x, y, z, w over Rational Field + [ y x] + [-z -y] + [ w z] + Domain: Ambient free module of rank 2 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 3 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field sage: d.image() - Submodule of Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring - in x, y, z, w over Rational Field + Submodule of Ambient free module of rank 3 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field Generated by the rows of the matrix: [ y -z w] [ x -y z] @@ -46,8 +47,9 @@ sage: R.<s,t> = QQ[] sage: S.<a,b,c,d> = QQ[] sage: phi = S.hom([s, s*t, s*t^2, s*t^3]) - sage: I = phi.kernel(); I - Ideal (c^2 - b*d, b*c - a*d, b^2 - a*c) of Multivariate Polynomial Ring in a, b, c, d over Rational Field + sage: I = phi.kernel(); I # needs sage.rings.function_field + Ideal (c^2 - b*d, b*c - a*d, b^2 - a*c) of + Multivariate Polynomial Ring in a, b, c, d over Rational Field sage: P3 = ProjectiveSpace(S) sage: C = P3.subscheme(I) # twisted cubic curve sage: r = I.graded_free_resolution(degrees=[(1,0), (1,1), (1,2), (1,3)]) @@ -73,8 +75,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.libs.singular.singular import si2sa_resolution_graded -from sage.libs.singular.function import singular_function from sage.misc.lazy_attribute import lazy_attribute from sage.structure.element import Matrix from sage.modules.free_module_element import vector @@ -86,6 +86,7 @@ from sage.homology.free_resolution import (FiniteFreeResolution, FiniteFreeResolution_free_module, FiniteFreeResolution_singular) +from sage.misc.superseded import deprecated_function_alias class GradedFiniteFreeResolution(FiniteFreeResolution): @@ -124,8 +125,7 @@ def __init__(self, module, degrees=None, shifts=None, name='S', **kwds): sage: M = matrix([[x^2, 2*x^2], ....: [3*x^2, 5*x^2], ....: [5*x^2, 4*x^2]]) - sage: res = FreeResolution(M, graded=True) - sage: res + sage: res = FreeResolution(M, graded=True); res S(0)โŠ•S(0) <-- S(-2)โŠ•S(-2) <-- 0 sage: res._res_shifts [[2, 2]] @@ -143,7 +143,7 @@ def __init__(self, module, degrees=None, shifts=None, name='S', **kwds): if degrees[0] in ZZ: zero_deg = 0 multigrade = False - else: # degrees are integer vectors + else: # degrees are integer vectors degrees = tuple([vector(v) for v in degrees]) zero_deg = degrees[0].parent().zero() multigrade = True @@ -327,8 +327,7 @@ class GradedFiniteFreeResolution_free_module(GradedFiniteFreeResolution, FiniteF sage: R.<x> = QQ[] sage: M = matrix([[x^3, 3*x^3, 5*x^3], ....: [0, x, 2*x]]) - sage: res = FreeResolution(M, graded=True) - sage: res + sage: res = FreeResolution(M, graded=True); res S(0)โŠ•S(0)โŠ•S(0) <-- S(-3)โŠ•S(-1) <-- 0 """ def __init__(self, module, degrees=None, *args, **kwds): @@ -363,8 +362,7 @@ def _maps(self): sage: R.<x> = QQ[] sage: M = matrix([[x^3, 3*x^3, 5*x^3], ....: [0, x, 2*x]]) - sage: res = FreeResolution(M, graded=True) - sage: res + sage: res = FreeResolution(M, graded=True); res S(0)โŠ•S(0)โŠ•S(0) <-- S(-3)โŠ•S(-1) <-- 0 sage: res._maps [ @@ -376,8 +374,7 @@ def _maps(self): [[3, 1]] sage: I = R.ideal([x^4]) - sage: res = I.graded_free_resolution(shifts=[1], degrees=[2]) - sage: res + sage: res = I.graded_free_resolution(shifts=[1], degrees=[2]); res S(-1) <-- S(-9) <-- 0 sage: res._maps [[x^4]] @@ -406,7 +403,7 @@ def compute_degree(base, i): def find_deg(i): for j in range(M.nrows()): - ret = M[j,i].degree() + ret = M[j, i].degree() if ret != -1: return ret raise NotImplementedError("a generator maps to 0") @@ -473,8 +470,7 @@ class GradedFiniteFreeResolution_singular(GradedFiniteFreeResolution, FiniteFree sage: S.<x,y,z,w> = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = I.graded_free_resolution() - sage: r + sage: r = I.graded_free_resolution(); r S(0) <-- S(-2)โŠ•S(-2)โŠ•S(-2) <-- S(-3)โŠ•S(-3) <-- 0 sage: len(r) 2 @@ -482,8 +478,7 @@ class GradedFiniteFreeResolution_singular(GradedFiniteFreeResolution, FiniteFree sage: I = S.ideal([z^2 - y*w, y*z - x*w, y - x]) sage: I.is_homogeneous() True - sage: r = I.graded_free_resolution() - sage: r + sage: r = I.graded_free_resolution(); r S(0) <-- S(-1)โŠ•S(-2)โŠ•S(-2) <-- S(-3)โŠ•S(-3)โŠ•S(-4) <-- S(-5) <-- 0 """ def __init__(self, module, degrees=None, shifts=None, name='S', algorithm='heuristic', **kwds): @@ -521,8 +516,11 @@ def _maps(self): sage: r._res_shifts [[2, 2, 2], [3, 3]] """ - #cdef int i, j, k, ncols, nrows - #cdef list res_shifts, prev_shifts, new_shifts + from sage.libs.singular.singular import si2sa_resolution_graded + from sage.libs.singular.function import singular_function + + # cdef int i, j, k, ncols, nrows + # cdef list res_shifts, prev_shifts, new_shifts # This ensures the first component of the Singular resolution to be a # module, like the later components. This is important when the @@ -575,5 +573,4 @@ def _maps(self): return res_mats -from sage.misc.superseded import deprecated_function_alias GradedFreeResolution = deprecated_function_alias(34873, GradedFiniteFreeResolution_singular) diff --git a/src/sage/homology/hochschild_complex.py b/src/sage/homology/hochschild_complex.py index f372a08e0e8..ea42164ef9d 100644 --- a/src/sage/homology/hochschild_complex.py +++ b/src/sage/homology/hochschild_complex.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat (because all doctests use FreeAlgebra, SymmetricGroupAlgebra, etc.) """ Hochschild Complexes """ @@ -272,13 +273,13 @@ def boundary(self, d): def on_basis(k): p = self._M.monomial(k[0]) * self._A.monomial(k[1]) - ret = Fd._from_dict({(m,) + k[2:]: c for m,c in p}, remove_zeros=False) + ret = Fd._from_dict({(m,) + k[2:]: c for m, c in p}, remove_zeros=False) for i in range(1, d): p = self._A.monomial(k[i]) * self._A.monomial(k[i+1]) ret += mone**i * Fd._from_dict({k[:i] + (m,) + k[i+2:]: c - for m,c in p}, remove_zeros=False) + for m, c in p}, remove_zeros=False) p = self._A.monomial(k[-1]) * self._M.monomial(k[0]) - ret += mone**d * Fd._from_dict({(m,) + k[1:-1]: c for m,c in p}, + ret += mone**d * Fd._from_dict({(m,) + k[1:-1]: c for m, c in p}, remove_zeros=False) return ret return Fd1.module_morphism(on_basis, codomain=Fd) @@ -492,7 +493,7 @@ def _element_constructor_(self, vectors): return self.element_class(self, {0: vec}) if isinstance(vectors, (Chain_class, self.element_class)): vectors = vectors._vec - data = dict() + data = {} if not isinstance(vectors, dict): raise ValueError("cannot construct an element from {}".format(vectors)) # Special handling for the 0 free module @@ -623,10 +624,9 @@ def _repr_(self): if n == 1: (deg, vec), = self._vec.items() - return 'Chain({0}: {1})'.format(deg, vec) + return f'Chain({deg}: {vec})' - return 'Chain with {0} nonzero terms over {1}'.format(n, - self.parent().base_ring()) + return f'Chain with {n} nonzero terms over {self.parent().base_ring()}' def _ascii_art_(self): """ @@ -690,7 +690,7 @@ def _add_(self, other): 3*F[1] # F[1] + 2*F[1] # F[x] + 3*F[1] # F[y], 3*F[1] # F[1] # F[1] + 2*F[1] # F[1] # F[x] + 3*F[1] # F[1] # F[y]] """ - vectors = dict(self._vec) # Make a (shallow) copy + vectors = dict(self._vec) # Make a (shallow) copy for d in other._vec: if d in vectors: vectors[d] += other._vec[d] @@ -718,7 +718,7 @@ def _lmul_(self, scalar): """ if scalar == 0: return self.zero() - vectors = dict() + vectors = {} for d in self._vec: vec = scalar * self._vec[d] if vec: diff --git a/src/sage/homology/homology_group.py b/src/sage/homology/homology_group.py index 0b27087a362..8d86d477ad8 100644 --- a/src/sage/homology/homology_group.py +++ b/src/sage/homology/homology_group.py @@ -32,13 +32,13 @@ class HomologyGroup_class(AdditiveAbelianGroup_fixed_gens): EXAMPLES:: sage: from sage.homology.homology_group import HomologyGroup - sage: G = AbelianGroup(5, [5,5,7,8,9]); G + sage: G = AbelianGroup(5, [5,5,7,8,9]); G # needs sage.groups Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9 sage: H = HomologyGroup(5, ZZ, [5,5,7,8,9]); H C5 x C5 x C7 x C8 x C9 - sage: G == loads(dumps(G)) + sage: G == loads(dumps(G)) # needs sage.groups True - sage: AbelianGroup(4) + sage: AbelianGroup(4) # needs sage.groups Multiplicative Abelian group isomorphic to Z x Z x Z x Z sage: HomologyGroup(4, ZZ) Z x Z x Z x Z @@ -120,7 +120,7 @@ def _latex_(self): g = ["\\ZZ^{{{}}}".format(rank)] else: g = ["\\ZZ"] * rank - if len(torsion) != 0: + if torsion: printed = [] for t in torsion: numfac = torsion.count(t) @@ -134,6 +134,7 @@ def _latex_(self): times = " \\times " return times.join(g) + def HomologyGroup(n, base_ring, invfac=None): """ Abelian group on `n` generators which represents a homology group in a @@ -156,14 +157,16 @@ def HomologyGroup(n, base_ring, invfac=None): EXAMPLES:: sage: from sage.homology.homology_group import HomologyGroup - sage: G = AbelianGroup(5, [5,5,7,8,9]); G + sage: G = AbelianGroup(5, [5,5,7,8,9]); G # needs sage.groups Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9 sage: H = HomologyGroup(5, ZZ, [5,5,7,8,9]); H C5 x C5 x C7 x C8 x C9 - sage: AbelianGroup(4) + sage: AbelianGroup(4) # needs sage.groups Multiplicative Abelian group isomorphic to Z x Z x Z x Z sage: HomologyGroup(4, ZZ) Z x Z x Z x Z + + sage: # needs sage.libs.flint (otherwise timeout) sage: HomologyGroup(100, ZZ) Z^100 """ diff --git a/src/sage/homology/homology_morphism.py b/src/sage/homology/homology_morphism.py index 7dfd5fc8b08..1b4a69c2e7e 100644 --- a/src/sage/homology/homology_morphism.py +++ b/src/sage/homology/homology_morphism.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs (because all doctests use the catalog simplicial_complexes) r""" Induced morphisms on homology @@ -27,12 +28,19 @@ # - associated_chain_complex_morphism # Once this is done, the code here ought to work without modification. +import itertools + from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis from sage.categories.graded_modules_with_basis import GradedModulesWithBasis from sage.categories.morphism import Morphism from sage.categories.homset import Hom from sage.rings.rational_field import QQ -from sage.topology.simplicial_complex import SimplicialComplex + +try: + from sage.topology.simplicial_complex import SimplicialComplex +except ImportError: + SimplicialComplex = () + class InducedHomologyMorphism(Morphism): r""" @@ -61,12 +69,13 @@ class InducedHomologyMorphism(Morphism): sage: f = H({0:0, 1:2, 2:1}) # f switches two vertices sage: f_star = f.induced_homology_morphism(QQ, cohomology=True) sage: f_star - Graded algebra endomorphism of Cohomology ring of Minimal triangulation of the 1-sphere over Rational Field + Graded algebra endomorphism of + Cohomology ring of Minimal triangulation of the 1-sphere over Rational Field Defn: induced by: - Simplicial complex endomorphism of Minimal triangulation of the 1-sphere - Defn: 0 |--> 0 - 1 |--> 2 - 2 |--> 1 + Simplicial complex endomorphism of Minimal triangulation of the 1-sphere + Defn: 0 |--> 0 + 1 |--> 2 + 2 |--> 1 sage: f_star.to_matrix(1) [-1] sage: f_star.to_matrix() @@ -86,7 +95,7 @@ class in the torus, we can define a map `S^1 \to T` inducing an sage: Hom(S1, T)({0:0, 1:2, 2:5}) Simplicial complex morphism: From: Minimal triangulation of the 1-sphere - To: Minimal triangulation of the torus + To: Minimal triangulation of the torus Defn: 0 |--> 0 1 |--> 2 2 |--> 5 @@ -157,8 +166,8 @@ def __init__(self, map, base_ring=None, cohomology=False): sage: h = g.induced_homology_morphism(QQ) """ if (isinstance(map.domain(), SimplicialComplex) - and (map.domain().is_mutable() or map.codomain().is_mutable())): - raise ValueError('the domain and codomain complexes must be immutable') + and (map.domain().is_mutable() or map.codomain().is_mutable())): + raise ValueError('the domain and codomain complexes must be immutable') if base_ring is None: base_ring = QQ if not base_ring.is_field(): @@ -180,7 +189,7 @@ def __init__(self, map, base_ring=None, cohomology=False): def base_ring(self): """ - The base ring for this map + The base ring for this map. EXAMPLES:: @@ -234,14 +243,13 @@ def to_matrix(self, deg=None): mat = mat.transpose() H_domain, H_codomain = H_codomain, H_domain if deg is None: - import numpy as np betti_domain = [H_domain.free_module_rank(n) - for n in range(domain.dimension()+1)] + for n in range(domain.dimension() + 1)] betti_codomain = [H_codomain.free_module_rank(n) - for n in range(codomain.dimension()+1)] + for n in range(codomain.dimension() + 1)] # Compute cumulative sums of Betti numbers to get subdivisions: - row_subdivs = list(np.cumsum(betti_codomain[:-1])) - col_subdivs = list(np.cumsum(betti_domain[:-1])) + row_subdivs = list(itertools.accumulate(betti_codomain[:-1])) + col_subdivs = list(itertools.accumulate(betti_domain[:-1])) mat.subdivide(row_subdivs, col_subdivs) return mat @@ -280,7 +288,7 @@ def __call__(self, elt): return codomain.from_vector(self.to_matrix() * elt.to_vector()) - def __eq__(self, other): + def __eq__(self, other) -> bool: """ Return ``True`` if and only if this map agrees with ``other``. @@ -311,16 +319,16 @@ def __eq__(self, other): False """ if (self._map.domain() != other._map.domain() - or self._map.codomain() != other._map.codomain() - or self.base_ring() != other.base_ring() - or self._cohomology != other._cohomology): + or self._map.codomain() != other._map.codomain() + or self.base_ring() != other.base_ring() + or self._cohomology != other._cohomology): return False dim = min(self._map.domain().dimension(), self._map.codomain().dimension()) - return all(self.to_matrix(d) == other.to_matrix(d) for d in range(dim+1)) + return all(self.to_matrix(d) == other.to_matrix(d) for d in range(dim + 1)) - def is_identity(self): + def is_identity(self) -> bool: """ - True if this is the identity map on (co)homology. + Return ``True`` if this is the identity map on (co)homology. EXAMPLES:: @@ -337,9 +345,9 @@ def is_identity(self): """ return self.to_matrix().is_one() - def is_surjective(self): + def is_surjective(self) -> bool: """ - True if this map is surjective on (co)homology. + Return ``True`` if this map is surjective on (co)homology. EXAMPLES:: @@ -355,9 +363,9 @@ def is_surjective(self): m = self.to_matrix() return m.rank() == m.nrows() - def is_injective(self): + def is_injective(self) -> bool: """ - True if this map is injective on (co)homology. + Return ``True`` if this map is injective on (co)homology. EXAMPLES:: diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index 63a80657917..bf53c7b6113 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -1,4 +1,5 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs (because all doctests use the catalogs simplicial_complexes, cubical_complexes) + """ Homology and cohomology with a basis @@ -30,8 +31,13 @@ from sage.categories.modules import Modules from sage.combinat.free_module import CombinatorialFreeModule from sage.sets.family import Family -from sage.topology.simplicial_complex import SimplicialComplex -from sage.topology.simplicial_set import SimplicialSet_arbitrary + +try: + from sage.topology.simplicial_complex import SimplicialComplex + from sage.topology.simplicial_set import SimplicialSet_arbitrary +except ImportError: + SimplicialComplex = SimplicialSet_arbitrary = () + class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): r""" @@ -129,6 +135,7 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): `\Delta`-complex model can be obtained by sending `x` to `u+v`, `y` to `v`. :: + sage: # needs sage.groups sage: X = simplicial_sets.RealProjectiveSpace(6) sage: H_X = X.cohomology_ring(GF(2)) sage: a = H_X.basis()[1,0] @@ -140,6 +147,7 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): All products of positive-dimensional elements in a suspension should be zero:: + sage: # needs sage.groups sage: Y = X.suspension() sage: H_Y = Y.cohomology_ring(GF(2)) sage: b = H_Y.basis()[2,0] @@ -403,7 +411,8 @@ def to_cycle(self): """ if not self.is_homogeneous(): raise ValueError("only defined for homogeneous elements") - return sum(c * self.parent()._to_cycle_on_basis(i) for i,c in self) + return sum(c * self.parent()._to_cycle_on_basis(i) for i, c in self) + class CohomologyRing(HomologyVectorSpaceWithBasis): """ @@ -446,6 +455,7 @@ class CohomologyRing(HomologyVectorSpaceWithBasis): sage: y.Sq(2) h^{4,0} + sage: # needs sage.groups sage: Y = simplicial_sets.RealProjectiveSpace(6).suspension() sage: H_Y = Y.cohomology_ring(GF(2)) sage: b = H_Y.basis()[2,0] @@ -502,7 +512,7 @@ def one(self): True """ one = self.base_ring().one() - d = {(0,i): one for i in self._graded_indices[0]} + d = {(0, i): one for i in self._graded_indices[0]} return self._from_dict(d, remove_zeros=False) @cached_method @@ -570,9 +580,9 @@ def product_on_basis(self, li, ri): and simplicial sets:: sage: from sage.topology.simplicial_set_examples import RealProjectiveSpace - sage: RP5 = RealProjectiveSpace(5) - sage: x = RP5.cohomology_ring(GF(2)).basis()[1,0] - sage: x**4 + sage: RP5 = RealProjectiveSpace(5) # needs sage.groups + sage: x = RP5.cohomology_ring(GF(2)).basis()[1,0] # needs sage.groups + sage: x**4 # needs sage.groups h^{4,0} A non-connected example:: @@ -711,9 +721,9 @@ def Sq(self, i): one machine, 20 seconds with a simplicial complex, 4 ms with a simplicial set). :: - sage: RP4_ss = simplicial_sets.RealProjectiveSpace(4) - sage: z_ss = RP4_ss.cohomology_ring(GF(2)).basis()[3,0] - sage: z_ss.Sq(1) + sage: RP4_ss = simplicial_sets.RealProjectiveSpace(4) # needs sage.groups + sage: z_ss = RP4_ss.cohomology_ring(GF(2)).basis()[3,0] # needs sage.groups + sage: z_ss.Sq(1) # needs sage.groups h^{4,0} TESTS:: @@ -749,7 +759,7 @@ def Sq(self, i): ret = P.zero() H = scomplex.homology_with_basis(base_ring) deg_comp = {} - for index,coeff in self: + for index, coeff in self: d = deg_comp.get(index[0], {}) d[index] = coeff deg_comp[index[0]] = d @@ -822,7 +832,7 @@ def Sq(self, i): if ((hasattr(left, 'is_nondegenerate') and left.is_nondegenerate() and right.is_nondegenerate()) - or not hasattr(left, 'is_nondegenerate')): + or not hasattr(left, 'is_nondegenerate')): left = n_chains(left) right = n_chains(right) gamma_coeff += coeff * cycle.eval(left) * cycle.eval(right) @@ -831,6 +841,7 @@ def Sq(self, i): ret += P._from_dict(result, remove_zeros=False) return ret + def sum_indices(k, i_k_plus_one, S_k_plus_one): r""" This is a recursive function for computing the indices for the diff --git a/src/sage/homology/koszul_complex.py b/src/sage/homology/koszul_complex.py index 858d5a71283..a8b050e09bc 100644 --- a/src/sage/homology/koszul_complex.py +++ b/src/sage/homology/koszul_complex.py @@ -14,7 +14,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.combinat.combination import rank -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix from sage.homology.chain_complex import ChainComplex_class @@ -108,12 +108,12 @@ def __classcall_private__(cls, R=None, elements=None): R = () elements = R if not elements: - R = ZZ # default to ZZ as the base ring if no elements are given + R = ZZ # default to ZZ as the base ring if no elements are given elif isinstance(R, Parent): elements = () else: R = elements[0].parent() - elif R is None: # elements is not None + elif R is None: # elements is not None R = elements[0].parent() return super(KoszulComplex, cls).__classcall__(cls, R, tuple(elements)) @@ -134,12 +134,12 @@ def __init__(self, R, elements): diff = {} zero = R.zero() for i in I: - M = matrix(R, binomial(n,i), binomial(n,i+1), zero) + M = matrix(R, binomial(n, i), binomial(n, i+1), zero) j = 0 for comb in itertools.combinations(I, i+1): - for k,val in enumerate(comb): + for k, val in enumerate(comb): r = rank(comb[:k] + comb[k+1:], n, False) - M[r,j] = (-1)**k * elements[val] + M[r, j] = (-1)**k * elements[val] j += 1 M.set_immutable() diff[i+1] = M diff --git a/src/sage/homology/matrix_utils.py b/src/sage/homology/matrix_utils.py index b1edc656e58..4f10ae415a3 100644 --- a/src/sage/homology/matrix_utils.py +++ b/src/sage/homology/matrix_utils.py @@ -96,11 +96,11 @@ def dhsw_snf(mat, verbose=False): check_leading = True while check_leading: i = new_col.nonzero_positions_in_column(0)[0] - entry = new_col[i,0] + entry = new_col[i, 0] check_leading = False if i in leading_positions: for c in leading_positions[i]: - earlier = new_mat[i,c] + earlier = new_mat[i, c] # right now we don't check to see if entry divides # earlier, because we don't want to modify the # earlier columns of the matrix. Deal with this @@ -137,7 +137,7 @@ def dhsw_snf(mat, verbose=False): j = leading_positions[i][0] jth = new_mat[i, j] for n in leading_positions[i][1:]: - nth = new_mat[i,n] + nth = new_mat[i, n] if jth.divides(nth): quo = nth.divide_knowing_divisible_by(jth) new_mat.add_multiple_of_column(n, j, -quo) @@ -147,8 +147,8 @@ def dhsw_snf(mat, verbose=False): new_mat.swap_columns(n, j) new_mat.add_multiple_of_column(n, j, -quo) else: - (g,r,s) = jth.xgcd(nth) - (unit,A,B) = r.xgcd(-s) # unit ought to be 1 here + g, r, s = jth.xgcd(nth) + unit, A, B = r.xgcd(-s) # unit ought to be 1 here jth_col = new_mat.column(j) nth_col = new_mat.column(n) new_mat.set_column(j, r*jth_col + s*nth_col) @@ -176,15 +176,15 @@ def dhsw_snf(mat, verbose=False): max_leading = 1 for i in leading_positions: j = leading_positions[i][0] - entry = new_mat[i,j] + entry = new_mat[i, j] if entry.abs() == 1: add_to_rank += 1 keep_columns.remove(j) for c in new_mat.nonzero_positions_in_row(i): if c in keep_columns: - new_mat.add_multiple_of_column(c, j, -entry * new_mat[i,c]) + new_mat.add_multiple_of_column(c, j, -entry * new_mat[i, c]) else: - max_leading = max(max_leading, new_mat[i,j].abs()) + max_leading = max(max_leading, new_mat[i, j].abs()) # form the new matrix if max_leading != 1: new_mat = new_mat.matrix_from_columns(keep_columns) diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py deleted file mode 100644 index 8c8399d3b24..00000000000 --- a/src/sage/homology/simplicial_complex.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- -r""" -Finite simplicial complexes: deprecated - -The current version is :mod:`sage.topology.simplicial_complexes`. -""" -from sage.misc.superseded import deprecated_function_alias -import sage.topology.simplicial_complex - -for f in ['lattice_paths', - 'rename_vertex', - 'Simplex', - 'SimplicialComplex', - 'facets_for_RP4', - 'facets_for_K3']: - exec('{} = deprecated_function_alias(31925, sage.topology.simplicial_complex.{})'.format(f, f)) diff --git a/src/sage/homology/simplicial_complex_homset.py b/src/sage/homology/simplicial_complex_homset.py deleted file mode 100644 index f5b54a59dc2..00000000000 --- a/src/sage/homology/simplicial_complex_homset.py +++ /dev/null @@ -1,12 +0,0 @@ -r""" -Homsets between simplicial complexes: deprecated - -The current version is :mod:`sage.topology.simplicial_complex_homset`. -""" -from sage.misc.superseded import deprecated_function_alias -import sage.topology.simplicial_complex_homset - -is_SimplicialComplexHomset = deprecated_function_alias(31925, - sage.topology.simplicial_complex_homset.is_SimplicialComplexHomset) -SimplicialComplexHomset = deprecated_function_alias(31925, - sage.topology.simplicial_complex_homset.SimplicialComplexHomset) diff --git a/src/sage/homology/simplicial_complex_morphism.py b/src/sage/homology/simplicial_complex_morphism.py deleted file mode 100644 index 889c266dc0a..00000000000 --- a/src/sage/homology/simplicial_complex_morphism.py +++ /dev/null @@ -1,12 +0,0 @@ -r""" -Morphisms of simplicial complexes: deprecated - -The current version is :mod:`sage.topology.simplicial_complex_morphism`. -""" -from sage.misc.superseded import deprecated_function_alias -import sage.topology.simplicial_complex_morphism - -is_SimplicialComplexMorphism = deprecated_function_alias(31925, - sage.topology.simplicial_complex_morphism.is_SimplicialComplexMorphism) -SimplicialComplexMorphism = deprecated_function_alias(31925, - sage.topology.simplicial_complex_morphism.SimplicialComplexMorphism) diff --git a/src/sage/homology/simplicial_set.py b/src/sage/homology/simplicial_set.py deleted file mode 100644 index 51e1a36047a..00000000000 --- a/src/sage/homology/simplicial_set.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -r""" -Simplicial sets: deprecated - -The current version is :mod:`sage.topology.simplicial_set`. -""" -from sage.misc.superseded import deprecated_function_alias -import sage.topology.simplicial_set - -for f in ['AbstractSimplex_class', - 'NonDegenerateSimplex', - 'AbstractSimplex', - 'SimplicialSet_arbitrary', - 'SimplicialSet_finite', - 'SimplicialSet', - 'standardize_degeneracies', - 'all_degeneracies', - 'standardize_face_maps', - 'face_degeneracies', - 'shrink_simplicial_complex']: - exec('{} = deprecated_function_alias(31925, sage.topology.simplicial_set.{})'.format(f, f)) diff --git a/src/sage/homology/simplicial_set_constructions.py b/src/sage/homology/simplicial_set_constructions.py deleted file mode 100644 index c8943f62034..00000000000 --- a/src/sage/homology/simplicial_set_constructions.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -r""" -Methods of constructing simplicial sets: deprecated - -The current version is :mod:`sage.topology.simplicial_set_constructions`. -""" -from sage.misc.superseded import deprecated_function_alias -import sage.topology.simplicial_set_constructions - -for f in ['SubSimplicialSet', - 'PullbackOfSimplicialSets', - 'PullbackOfSimplicialSets_finite', - 'Factors', - 'ProductOfSimplicialSets', - 'ProductOfSimplicialSets_finite', - 'PushoutOfSimplicialSets', - 'PushoutOfSimplicialSets_finite', - 'QuotientOfSimplicialSet', - 'QuotientOfSimplicialSet_finite', - 'SmashProductOfSimplicialSets_finite', - 'WedgeOfSimplicialSets', - 'WedgeOfSimplicialSets_finite', - 'DisjointUnionOfSimplicialSets', - 'DisjointUnionOfSimplicialSets_finite', - 'ConeOfSimplicialSet', - 'ConeOfSimplicialSet_finite', - 'ReducedConeOfSimplicialSet', - 'ReducedConeOfSimplicialSet_finite', - 'SuspensionOfSimplicialSet', - 'SuspensionOfSimplicialSet_finite']: - exec('{} = deprecated_function_alias(31925, sage.topology.simplicial_set_constructions.{})'.format(f, f)) diff --git a/src/sage/homology/simplicial_set_examples.py b/src/sage/homology/simplicial_set_examples.py deleted file mode 100644 index 8945e2b51de..00000000000 --- a/src/sage/homology/simplicial_set_examples.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -r""" -Examples of simplicial sets: deprecated - -The current version is :mod:`sage.topology.simplicial_set_examples`. -""" -from sage.misc.superseded import deprecated_function_alias -import sage.topology.simplicial_set_examples - -for f in ['Nerve', - 'Sphere', - 'ClassifyingSpace', - 'RealProjectiveSpace', - 'KleinBottle', - 'Torus', - 'Simplex', - 'Empty', - 'Point', - 'Horn', - 'ComplexProjectiveSpace', - 'simplicial_data_from_kenzo_output', - 'HopfMap']: - exec('{} = deprecated_function_alias(31925, sage.topology.simplicial_set_examples.{})'.format(f, f)) diff --git a/src/sage/homology/simplicial_set_morphism.py b/src/sage/homology/simplicial_set_morphism.py deleted file mode 100644 index 9df5cb9a40d..00000000000 --- a/src/sage/homology/simplicial_set_morphism.py +++ /dev/null @@ -1,12 +0,0 @@ -r""" -Morphisms and homsets for simplicial sets: deprecated - -The current version is :mod:`sage.topology.simplicial_set_morphism`. -""" -from sage.misc.superseded import deprecated_function_alias -import sage.topology.simplicial_set_morphism - -deprecated_function_alias(31925, - sage.topology.simplicial_set_morphism.SimplicialSetHomset) -deprecated_function_alias(31925, - sage.topology.simplicial_set_morphism.SimplicialSetMorphism) diff --git a/src/sage/homology/tests.py b/src/sage/homology/tests.py index 10ef05e9c77..ab55168ac16 100644 --- a/src/sage/homology/tests.py +++ b/src/sage/homology/tests.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules """ Tests for chain complexes, simplicial complexes, etc. @@ -32,6 +33,7 @@ from sage.rings.integer_ring import ZZ from sage.topology.simplicial_complex_examples import RandomComplex + def random_chain_complex(level=1): """ Return a random chain complex, defined by specifying a single @@ -54,7 +56,7 @@ def random_chain_complex(level=1): sage: C.degree_of_differential() in [-1, 1] True """ - bound = 50*level + bound = 50 * level nrows = randint(0, bound) ncols = randint(0, bound) sparseness = bool(randint(0, 1)) @@ -100,6 +102,7 @@ def test_random_chain_complex(level=1, trials=1, verbose=False): print("Chain complex: %s" % C.differential()) raise ValueError + def random_simplicial_complex(level=1, p=0.5): """ Return a random simplicial complex. @@ -120,10 +123,11 @@ def random_simplicial_complex(level=1, p=0.5): sage: X.dimension() < 11 True """ - n = randint(2, 4*level) + n = randint(2, 4 * level) dim = randint(1, n) return RandomComplex(n, dim, p) + @random_testing def test_random_simplicial_complex(level=1, trials=1, verbose=False): """ diff --git a/src/sage/interacts/__init__.py b/src/sage/interacts/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/interacts/library.py b/src/sage/interacts/library.py index d806c2b5ab3..ccb8fc6d3c2 100644 --- a/src/sage/interacts/library.py +++ b/src/sage/interacts/library.py @@ -161,7 +161,7 @@ def html(obj): sage: html("<h1>Hello world</h1>") <h1>Hello world</h1> """ - from sage.all import html + from sage.misc.html import html pretty_print(html(obj)) @@ -716,6 +716,7 @@ def special_points( """ import math # Return the intersection point of the bisector of the angle <(A[a],A[c],A[b]) and the unit circle. Angles given in radians. + def half(A, a, b, c): if (A[a] < A[b] and (A[c] < A[a] or A[c] > A[b])) or (A[a] > A[b] and (A[c] > A[a] or A[c] < A[b])): p = A[a] + 0.5 * (A[b] - A[a]) @@ -848,7 +849,7 @@ def line_to_points(x1_y1, x2_y2, **plot_kwargs): @library_interact( n=lambda: slider(2, 10000, 100, default=1000, label="Number of Tosses"), interval=lambda: range_slider( - 0, 1, default=(0.45, 0.55), label="Plotting range (y)" + 0.0, 1.0, default=(0.45, 0.55), label="Plotting range (y)" ), ) def coin(n, interval): @@ -877,7 +878,7 @@ def coin(n, interval): sage: interacts.statistics.coin() ...Interactive function <function coin at ...> with 2 widgets n: IntSlider(value=1000, description='Number of Tosses', max=10000, min=2, step=100) - interval: IntRangeSlider(value=(0, 0), description='Plotting range (y)', max=1) + interval: FloatRangeSlider(value=(0.45, 0.55), description='Plotting range (y)', max=1.0) """ from random import random c = [] @@ -1032,7 +1033,7 @@ def _secant_method(f, a, b, maxn, h): L = sum(line([(c,k*i), (d,k*i)]) for i, (c,d) in enumerate(intervals) ) L += sum(line([(c,k*i-k/4), (c,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) L += sum(line([(d,k*i-k/4), (d,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) - S = sum(line([(c,f(c)), (d,f(d)), (d-(d-c)*f(d)/(f(d)-f(c)), 0)], color="green") for (c,d) in intervals) + S = sum(line([(c,f(c)), (d,f(d)), (d-(d-c)*f(d)/(f(d)-f(c)), 0)], color="green") for (c, d) in intervals) show(P + L + S, xmin=a, xmax=b) @@ -1300,8 +1301,9 @@ def simpson_integration( interval = interval_s else: interval = interval_g[0] + def parabola(a, b, c): - from sage.all import solve + from sage.symbolic.relation import solve A, B, C = SR.var("A, B, C") K = solve([A*a[0]**2+B*a[0]+C==a[1], A*b[0]**2+B*b[0]+C==b[1], A*c[0]**2+B*c[0]+C==c[1]], [A, B, C], solution_dict=True)[0] f = K[A]*x**2+K[B]*x+K[C] @@ -1436,7 +1438,7 @@ def riemann_sum( sage: interacts.calculus.riemann_sum() Manual interactive function <function riemann_sum at ...> with 9 widgets title: HTMLText(value='<h2>Riemann integral with random sampling</h2>') - f: EvalText(value='x^2+1', description='$f(x)=$', layout=Layout(max_width='41em')) + f: EvalText(value='x^2+1',... description='$f(x)=$', layout=Layout(max_width='41em')) n: IntSlider(value=5, description='# divisions', max=30, min=1) hr1: HTMLText(value='<hr>') interval_input: ToggleButtons(description='Integration interval', options=('from slider', 'from keyboard'), value='from slider') @@ -1548,7 +1550,7 @@ def function_tool(f, g, xrange, yrange, a, action, do_plot): it will simply return the underlying HTML and Sage code which creates the mathlet:: - sage: interacts.calculus.function_tool() + sage: interacts.calculus.function_tool() # long time ...Interactive function <function function_tool at ...> with 7 widgets f: EvalText(value='sin(x)', description='f') g: EvalText(value='cos(x)', description='g') @@ -1678,7 +1680,7 @@ def julia(expo, c_real, c_imag, iterations, zoom_x, zoom_y, plot_points, dpi): it will simply return the underlying HTML and Sage code which creates the mathlet:: - sage: interacts.fractals.julia() + sage: interacts.fractals.julia() # long time ...Interactive function <function julia at ...> with 8 widgets expo: FloatSlider(value=2.0, description='expo', max=10.0, min=-10.0) c_real: FloatSlider(value=0.5, description='real part const.', max=2.0, min=-2.0, step=0.01) @@ -1730,7 +1732,7 @@ def mandelbrot(expo, iterations, zoom_x, zoom_y, plot_points, dpi): it will simply return the underlying HTML and Sage code which creates the mathlet:: - sage: interacts.fractals.mandelbrot() + sage: interacts.fractals.mandelbrot() # long time ...Interactive function <function mandelbrot at ...> with 6 widgets expo: FloatSlider(value=2.0, description='expo', max=10.0, min=-10.0) iterations: IntSlider(value=20, description='# iterations', min=1) @@ -1775,7 +1777,7 @@ def cellular_automaton(N, rule_number, size): it will simply return the underlying HTML and Sage code which creates the mathlet:: - sage: interacts.fractals.cellular_automaton() + sage: interacts.fractals.cellular_automaton() # long time ...Interactive function <function cellular_automaton at ...> with 3 widgets N: IntSlider(value=100, description='Number of iterations', max=500, min=1) rule_number: IntSlider(value=110, description='Rule number', max=255) @@ -1834,7 +1836,7 @@ def polar_prime_spiral(interval, show_factors, highlight_primes, show_curves, n, it will simply return the underlying HTML and Sage code which creates the mathlet:: - sage: sage.interacts.algebra.polar_prime_spiral() + sage: sage.interacts.algebra.polar_prime_spiral() # long time ...Interactive function <function polar_prime_spiral at ...> with 6 widgets interval: IntRangeSlider(value=(1, 1000), description='range', max=4000, min=1, step=10) show_factors: Checkbox(value=True, description='show_factors') diff --git a/src/sage/interacts/library_cython.pyx b/src/sage/interacts/library_cython.pyx index daf20c648c8..37e75a16e7d 100644 --- a/src/sage/interacts/library_cython.pyx +++ b/src/sage/interacts/library_cython.pyx @@ -6,18 +6,15 @@ AUTHORS: - Harald Schilly (2011-01-16): initial version (#9623) partially based on work by Lauri Ruotsalainen """ - #***************************************************************************** # Copyright (C) 2011 Harald Schilly <harald.schilly@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.misc_c import prod - cpdef julia(ff_j, z, int iterations): """ @@ -31,6 +28,7 @@ cpdef julia(ff_j, z, int iterations): TESTS:: + sage: # needs sage.symbolic sage: from sage.interacts.library_cython import julia sage: z = var('z') sage: c_real, c_imag = 1, 1 @@ -58,6 +56,7 @@ cpdef mandel(ff_m, z, int iterations): TESTS:: + sage: # needs sage.symbolic sage: from sage.interacts.library_cython import mandel sage: z, c = var('z, c') sage: f = symbolic_expression(z**2 + c).function(z,c) diff --git a/src/sage/interacts/test_jupyter.rst b/src/sage/interacts/test_jupyter.rst index 3335a7423c3..7bbacee4903 100644 --- a/src/sage/interacts/test_jupyter.rst +++ b/src/sage/interacts/test_jupyter.rst @@ -192,7 +192,7 @@ Test all interacts from the Sage interact library:: sage: test(interacts.calculus.riemann_sum) ...Manual interactive function <function riemann_sum at ...> with 9 widgets title: HTMLText(value='<h2>Riemann integral with random sampling</h2>') - f: EvalText(value='x^2+1', description='$f(x)=$', layout=Layout(max_width='41em')) + f: EvalText(value='x^2+1',... description='$f(x)=$', layout=Layout(max_width='41em')) n: IntSlider(value=5, description='# divisions', max=30, min=1) hr1: HTMLText(value='<hr>') interval_input: ToggleButtons(description='Integration interval', options=('from slider', 'from keyboard'), value='from slider') @@ -281,7 +281,7 @@ Test all interacts from the Sage interact library:: sage: test(interacts.statistics.coin) ...Interactive function <function coin at ...> with 2 widgets n: IntSlider(value=1000, description='Number of Tosses', max=10000, min=2, step=100) - interval: IntRangeSlider(value=(0, 0), description='Plotting range (y)', max=1) + interval: FloatRangeSlider(value=(0.45, 0.55), description='Plotting range (y)', max=1.0) Test matrix control (see :trac:`27735`):: diff --git a/src/sage/interfaces/all.py b/src/sage/interfaces/all.py index bb1d65494e1..1e0623ec4ec 100644 --- a/src/sage/interfaces/all.py +++ b/src/sage/interfaces/all.py @@ -38,7 +38,6 @@ lazy_import('sage.interfaces.povray', 'povray') lazy_import('sage.interfaces.psage', 'PSage') lazy_import('sage.interfaces.qepcad', ['qepcad', 'qepcad_version', 'qepcad_formula']) -lazy_import('sage.interfaces.qsieve', 'qsieve') lazy_import('sage.interfaces.r', ['r', 'R', 'r_version']) lazy_import('sage.interfaces.read_data', 'read_data') lazy_import('sage.interfaces.scilab', 'scilab') diff --git a/src/sage/combinat/path_tableaux/__init__.py b/src/sage/interfaces/all__sagemath_polyhedra.py similarity index 100% rename from src/sage/combinat/path_tableaux/__init__.py rename to src/sage/interfaces/all__sagemath_polyhedra.py diff --git a/src/sage/interfaces/axiom.py b/src/sage/interfaces/axiom.py index 2ec63939630..939a142aa70 100644 --- a/src/sage/interfaces/axiom.py +++ b/src/sage/interfaces/axiom.py @@ -275,8 +275,7 @@ def _read_in_file_command(self, filename): # For some reason this trivial comp # keeps certain random freezes from occurring. Do not remove this. # The space before the \n is also important. - return ')read %s \n'%filename - + return ')read %s \n' % filename def _quit_string(self): """ @@ -321,7 +320,6 @@ def _commands(self): s = s[i+len(start):j].split() return s - def _tab_completion(self, verbose=True, use_disk_cache=True): """ Returns a list of all the commands defined in Axiom and optionally @@ -386,12 +384,11 @@ def set(self, var, value): '2' """ - cmd = '%s := %s'%(var, value) + cmd = '%s := %s' % (var, value) out = self._eval_line(cmd, reformat=False) if out.find("error") != -1: - raise TypeError("Error executing code in Axiom\nCODE:\n\t%s\nAxiom ERROR:\n\t%s"%(cmd, out)) - + raise TypeError("Error executing code in Axiom\nCODE:\n\t%s\nAxiom ERROR:\n\t%s" % (cmd, out)) def get(self, var): r""" @@ -568,7 +565,7 @@ def __call__(self, x): """ self._check_valid() P = self.parent() - return P('%s(%s)'%(self.name(), x)) + return P('%s(%s)' % (self.name(), x)) def _richcmp_(self, other, op): """ @@ -604,11 +601,11 @@ def _richcmp_(self, other, op): """ P = self.parent() - if 'true' in P.eval("(%s = %s) :: Boolean"%(self.name(),other.name())): + if 'true' in P.eval("(%s = %s) :: Boolean" % (self.name(),other.name())): return rich_to_bool(op, 0) - elif 'true' in P.eval("(%s < %s) :: Boolean"%(self.name(), other.name())): + elif 'true' in P.eval("(%s < %s) :: Boolean" % (self.name(), other.name())): return rich_to_bool(op, -1) - elif 'true' in P.eval("(%s > %s) :: Boolean"%(self.name(),other.name())): + elif 'true' in P.eval("(%s > %s) :: Boolean" % (self.name(),other.name())): return rich_to_bool(op, 1) return NotImplemented @@ -638,7 +635,7 @@ def __len__(self): 6 """ P = self._check_valid() - s = P.eval('# %s '%self.name()) + s = P.eval('# %s ' % self.name()) i = s.rfind('Type') return int(s[:i-1]) @@ -670,9 +667,9 @@ def __getitem__(self, n): raise IndexError("index out of range") P = self._check_valid() if not isinstance(n, tuple): - return P.new('%s(%s)'%(self._name, n)) + return P.new('%s(%s)' % (self._name, n)) else: - return P.new('%s(%s)'%(self._name, str(n)[1:-1])) + return P.new('%s(%s)' % (self._name, str(n)[1:-1])) def comma(self, *args): """ @@ -687,14 +684,13 @@ def comma(self, *args): [2,3,4] sage: _.type() #optional - axiom Tuple PositiveInteger - """ P = self._check_valid() args = list(args) for i, arg in enumerate(args): if not isinstance(arg, AxiomElement) or arg.parent() is not P: args[i] = P(arg) - cmd = "(" + ",".join([x.name() for x in [self]+args]) + ")" + cmd = "(" + ",".join(x.name() for x in [self] + args) + ")" return P(cmd) def _latex_(self): @@ -737,7 +733,7 @@ def as_type(self, type): """ P = self._check_valid() type = P(type) - return P.new("%s :: %s"%(self.name(), type.name())) + return P.new("%s :: %s" % (self.name(), type.name())) def unparsed_input_form(self): """ @@ -754,7 +750,7 @@ def unparsed_input_form(self): """ P = self._check_valid() - s = P.eval('unparse(%s::InputForm)'%self._name) + s = P.eval('unparse(%s::InputForm)' % self._name) if 'translation error' in s or 'Cannot convert' in s: raise NotImplementedError s = multiple_replace({'\r\n':'', # fix stupid Fortran-ish @@ -768,7 +764,6 @@ def unparsed_input_form(self): else: return s - def _sage_(self): """ Convert self to a Sage object. @@ -836,7 +831,8 @@ def _sage_(self): return self._sage_domain() if type == "Float": - from sage.rings.all import RealField, ZZ + from sage.rings.real_mpfr import RealField + from sage.rings.integer_ring import ZZ prec = max(self.mantissa().length()._sage_(), 53) R = RealField(prec) x,e,b = self.unparsed_input_form().lstrip('float(').rstrip(')').split(',') @@ -859,7 +855,7 @@ def _sage_(self): #If all else fails, try using the unparsed input form try: import sage.misc.sage_eval - vars=sage.symbolic.ring.var(str(self.variables())[1:-1]) + vars = sage.symbolic.ring.var(str(self.variables())[1:-1]) if isinstance(vars,tuple): return sage.misc.sage_eval.sage_eval(self.unparsed_input_form(), locals={str(x):x for x in vars}) else: @@ -867,7 +863,6 @@ def _sage_(self): except Exception: raise NotImplementedError - def _sage_domain(self): """ A helper function for converting Axiom domains to the corresponding @@ -921,6 +916,7 @@ def __init__(self, object, name): name = name[:-2] + "!" FunctionElement.__init__(self, object, name) + AxiomFunctionElement = PanAxiomFunctionElement @@ -941,6 +937,7 @@ def __init__(self, parent, name): name = name[:-2] + "!" ExpectFunction.__init__(self, parent, name) + AxiomExpectFunction = PanAxiomExpectFunction diff --git a/src/sage/interfaces/chomp.py b/src/sage/interfaces/chomp.py index b499f2a33b5..9e1b92d7709 100644 --- a/src/sage/interfaces/chomp.py +++ b/src/sage/interfaces/chomp.py @@ -151,7 +151,8 @@ def __call__(self, program, complex, subcomplex=None, **kwds): from subprocess import Popen, PIPE from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ - from sage.modules.all import VectorSpace, vector + from sage.modules.free_module import VectorSpace + from sage.modules.free_module_element import free_module_element as vector from sage.combinat.free_module import CombinatorialFreeModule deprecation(33777, "the CHomP interface is deprecated") diff --git a/src/sage/interfaces/expect.py b/src/sage/interfaces/expect.py index 0f322f76e91..30d3843852e 100644 --- a/src/sage/interfaces/expect.py +++ b/src/sage/interfaces/expect.py @@ -28,7 +28,6 @@ - Franรงois Bissey, Bill Page, Jeroen Demeyer (2015-12-09): Upgrade to pexpect 4.0.1 + patches, see :trac:`10295`. """ - # **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # @@ -38,7 +37,6 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - import io import os import re @@ -219,7 +217,7 @@ def set_server_and_command(self, server=None, command=None, server_tmpdir=None, def server(self): """ - Returns the server used in this interface. + Return the server used in this interface. EXAMPLES:: @@ -232,7 +230,7 @@ def server(self): def command(self): """ - Returns the command used in this interface. + Return the command used in this interface. EXAMPLES:: @@ -563,7 +561,7 @@ def _close(self, force=True): try: if self._expect is not None: self._expect.close(force=force) - except ExceptionPexpect: + except (ExceptionPexpect, OSError): self._expect.ptyproc.fd = -1 self._expect.ptyproc.closed = True self._expect.child_fd = -1 @@ -622,7 +620,7 @@ def quit(self, verbose=False): sage: a = maxima('y') sage: maxima.quit(verbose=True) - Exiting Maxima with PID ... running .../bin/maxima... + Exiting Maxima with PID ... running ...maxima... sage: a._check_valid() Traceback (most recent call last): ... @@ -1082,11 +1080,11 @@ def interrupt(self, tries=5, timeout=2.0, quit_on_fail=True): # BEGIN Synchronization code. ########################################################################### - def _before(self, encoding=None, errors=None): + def _before(self, encoding=None, errors=None) -> str: r""" Return the previous string that was sent through the interface. - Returns ``str`` objects on both Python 2 and Python 3. + This returns a ``str`` object. The ``encoding`` and ``errors`` arguments are passed to :func:`sage.misc.cpython.bytes_to_str`. @@ -1126,7 +1124,7 @@ def _after(self, encoding=None, errors=None): return after - def _readline(self, size=-1, encoding=None, errors=None): + def _readline(self, size=-1, encoding=None, errors=None) -> str: r""" Wraps ``spawn.readline`` to pass the return values through ``bytes_to_str``, like `Expect._before` and `Expect._after`. @@ -1139,7 +1137,6 @@ def _readline(self, size=-1, encoding=None, errors=None): sage: singular._readline() '2\r\n' """ - return bytes_to_str(self._expect.readline(size=size), encoding, errors) def _interrupt(self): @@ -1166,12 +1163,10 @@ def _expect_expr(self, expr=None, timeout=None): INPUT: - - - ``expr`` - None or a string or list of strings + - ``expr`` -- None or a string or list of strings (default: None) - - ``timeout`` - None or a number (default: None) - + - ``timeout`` -- None or a number (default: None) EXAMPLES: @@ -1181,15 +1176,13 @@ def _expect_expr(self, expr=None, timeout=None): sage: singular._sendstr('def abc = 10 + 15;\n') Then we tell singular to print 10, which is an arbitrary number - different from the expected result 35. + different from the expected result 35:: sage: singular._sendstr('10;\n') Here an exception is raised because 25 hasn't appeared yet in the output stream. The key thing is that this doesn't lock, but instead - quickly raises an exception. - - :: + quickly raises an exception:: sage: t = walltime() sage: try: @@ -1203,21 +1196,15 @@ def _expect_expr(self, expr=None, timeout=None): sage: w = walltime(t); 0.3 < w < 10 True - We tell Singular to print abc, which equals 25. - - :: + We tell Singular to print abc, which equals 25:: sage: singular._sendstr('abc;\n') - Now 25 is in the output stream, so we can wait for it. - - :: + Now 25 is in the output stream, so we can wait for it:: sage: singular._expect_expr('25') - This gives us everything before the 25, including the 10 we printed earlier. - - :: + This gives us everything before the 25, including the 10 we printed earlier:: sage: singular._expect.before.decode('ascii') '...10\r\n> ' @@ -1353,7 +1340,6 @@ def eval(self, code, strip=True, synchronize=False, locals=None, allow_use_file= """ INPUT: - - ``code`` -- text to evaluate - ``strip`` -- bool; whether to strip output prompts, @@ -1401,8 +1387,8 @@ def eval(self, code, strip=True, synchronize=False, locals=None, allow_use_file= self._eval_using_file_cutoff and len(code) > self._eval_using_file_cutoff): return self._eval_line_using_file(code) elif split_lines: - return '\n'.join([self._eval_line(L, allow_use_file=allow_use_file, **kwds) - for L in code.split('\n') if L != '']) + return '\n'.join(self._eval_line(L, allow_use_file=allow_use_file, **kwds) + for L in code.split('\n') if L) else: return self._eval_line(code, allow_use_file=allow_use_file, **kwds) # DO NOT CATCH KeyboardInterrupt, as it is being caught @@ -1520,7 +1506,9 @@ def __init__(self, parent, value, is_name=False, name=None): def __hash__(self): """ - Returns the hash of self. This is a default implementation of hash + Return the hash of self. + + This is a default implementation of hash which just takes the hash of the string of self. """ return hash('%s%s' % (self, self._session_number)) @@ -1552,7 +1540,7 @@ def __del__(self): if P is not None: P.clear(self._name) - except (RuntimeError, ExceptionPexpect): # needed to avoid infinite loops in some rare cases + except (RuntimeError, ExceptionPexpect): # needed to avoid infinite loops in some rare cases pass # def _sage_repr(self): @@ -1571,11 +1559,11 @@ def __init__(self, interface, silent=False, stdout=None): INPUT: - - ``interface`` - the interface whose communication shall be dumped. + - ``interface`` -- the interface whose communication shall be dumped. - - ``silent`` - if ``True`` this context does nothing + - ``silent`` -- if ``True`` this context does nothing - - ``stdout`` - optional parameter for alternative stdout device (default: ``None``) + - ``stdout`` -- optional parameter for alternative stdout device (default: ``None``) EXAMPLES:: @@ -1629,7 +1617,3 @@ def __exit__(self, typ, value, tb): self.interface._expect.logfile.flush() self.stdout.write("\n") self.interface._expect.logfile = self._logfile_backup - - -def console(cmd): - os.system(cmd) diff --git a/src/sage/interfaces/four_ti_2.py b/src/sage/interfaces/four_ti_2.py index 79a07dcdad4..1f5a6beb559 100644 --- a/src/sage/interfaces/four_ti_2.py +++ b/src/sage/interfaces/four_ti_2.py @@ -176,7 +176,7 @@ def write_array(self, array, nrows, ncols, filename): sage: four_ti_2.write_array([[1,2,3],[3,4,5]], 2, 3, "test_file") """ f = open(os.path.join(self.directory(), filename), 'w') - f.write("%s %s\n"%(nrows, ncols)) + f.write("%s %s\n" % (nrows, ncols)) for row in array: f.write(" ".join(map(str, row))) f.write("\n") @@ -444,7 +444,7 @@ def ppi(self, n): """ self.call('ppi', f'{n} 2> /dev/null') - return self.read_matrix('ppi%s.gra'%n) + return self.read_matrix('ppi%s.gra' % n) def circuits(self, mat=None, project=None): r""" diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index 202a756b0ef..c771aea716c 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -478,7 +478,6 @@ def _read_in_file_command(self, filename): return ')read %s )quiet' % filename - def _remote_tmpfile(self): """ Return a remote tmpfile ending with ".input" used to buffer long @@ -712,7 +711,7 @@ def get_string(self, var): We test that strings are returned properly:: sage: r = fricas.get_string('concat([concat(string(i)," ") for i in 0..299])') # optional - fricas - sage: r == " ".join([str(i) for i in range(300)]) + ' ' # optional - fricas + sage: r == " ".join(str(i) for i in range(300)) + ' ' # optional - fricas True sage: fricas.get_string('concat([string(1) for i in 1..5])') == "1"*5 # optional - fricas @@ -1217,7 +1216,9 @@ def _get_sage_type(self, domain): sage: fricas(0)._get_sage_type(m) # optional - fricas Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Algebraic Field """ - from sage.rings.all import QQbar, RDF, PolynomialRing + from sage.rings.qqbar import QQbar + from sage.rings.real_double import RDF + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.fraction_field import FractionField from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -1730,7 +1731,8 @@ def convert_rootOf(x, y): ex, _ = FriCASElement._parse_and_eval(fricas_InputForm) # postprocessing of rootOf - from sage.rings.all import QQbar, PolynomialRing + from sage.rings.qqbar import QQbar + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing while rootOf: for var, poly in rootOf.items(): pvars = poly.variables() diff --git a/src/sage/interfaces/frobby.py b/src/sage/interfaces/frobby.py index 9f514422528..aab3bd9b58f 100644 --- a/src/sage/interfaces/frobby.py +++ b/src/sage/interfaces/frobby.py @@ -52,7 +52,7 @@ def __call__(self, action, input=None, options=[], verbose=False): We compute the lcm of an ideal provided in Monos format. :: sage: frobby("analyze", input="vars x,y,z;[x^2,x*y];", # optional - frobby - ....: options=["lcm", "iformat monos", "oformat 4ti2"]) # optional - frobby + ....: options=["lcm", "iformat monos", "oformat 4ti2"]) ' 2 1 0\n\n2 generators\n3 variables\n' @@ -123,7 +123,7 @@ def alexander_dual(self, monomial_ideal): True We see how it is much faster to compute this with frobby than the built-in - procedure for simplicial complexes. + procedure for simplicial complexes:: sage: t=simplicial_complexes.PoincareHomologyThreeSphere() # optional - frobby sage: R=PolynomialRing(QQ,16,'x') # optional - frobby @@ -168,14 +168,14 @@ def hilbert(self, monomial_ideal): """ frobby_input = self._ideal_to_string(monomial_ideal) frobby_output = self('hilbert', input=frobby_input) - ring=monomial_ideal.ring() - lines=frobby_output.split('\n') - if lines[-1]=='': + ring = monomial_ideal.ring() + lines = frobby_output.split('\n') + if lines[-1] == '': lines.pop(-1) - if lines[-1]=='(coefficient)': + if lines[-1] == '(coefficient)': lines.pop(-1) lines.pop(0) - resul=0 + resul = 0 for l in lines: lis = [int(_) for _ in l.split()] resul += lis[0]+prod([ring.gen(i)**lis[i+1] for i in range(len(lis)-1)]) @@ -206,9 +206,9 @@ def associated_primes(self, monomial_ideal): """ frobby_input = self._ideal_to_string(monomial_ideal) frobby_output = self('assoprimes', input=frobby_input) - lines=frobby_output.split('\n') + lines = frobby_output.split('\n') lines.pop(0) - if lines[-1]=='': + if lines[-1] == '': lines.pop(-1) lists = [[int(_) for _ in a.split()] for a in lines] @@ -276,9 +276,9 @@ def irreducible_decomposition(self, monomial_ideal): sage: rings = [ZZ['x'], CC['x,y']] # optional - frobby sage: allOK = True # optional - frobby sage: for ring in rings: # optional - frobby - ....: id0 = ring.ideal(0) # optional - frobby - ....: decom0 = frobby.irreducible_decomposition(id0) # optional - frobby - ....: allOK = allOK and decom0 == [id0] # optional - frobby + ....: id0 = ring.ideal(0) + ....: decom0 = frobby.irreducible_decomposition(id0) + ....: allOK = allOK and decom0 == [id0] sage: allOK # optional - frobby True @@ -288,9 +288,9 @@ def irreducible_decomposition(self, monomial_ideal): sage: rings = [ZZ['x'], CC['x,y']] # optional - frobby sage: allOK = True # optional - frobby sage: for ring in rings: # optional - frobby - ....: id1 = ring.ideal(1) # optional - frobby - ....: decom1 = frobby.irreducible_decomposition(id1) # optional - frobby - ....: allOK = allOK and decom1 == [id1] # optional - frobby + ....: id1 = ring.ideal(1) + ....: decom1 = frobby.irreducible_decomposition(id1) + ....: allOK = allOK and decom1 == [id1] sage: allOK # optional - frobby True """ @@ -334,10 +334,10 @@ def _parse_ideals(self, string, ring): lines.pop(0) matrices.append('1 '+str(ring.ngens())+'\n'+'0 '*ring.ngens()+'\n') else: - nrows=int(lines[0].split()[0]) - nmatrix=lines.pop(0)+'\n' + nrows = int(lines[0].split()[0]) + nmatrix = lines.pop(0)+'\n' for i in range(nrows): - nmatrix+=lines.pop(0)+'\n' + nmatrix += lines.pop(0)+'\n' matrices.append(nmatrix) def to_ideal(exps): @@ -466,5 +466,6 @@ def _monomial_to_string(self, monomial): strings = [str(exponents[var]) for var in range(len(exponents))] return ' '.join(strings) + '\n' + # This singleton instance is what should be used outside this file. frobby = Frobby() diff --git a/src/sage/interfaces/gap.py b/src/sage/interfaces/gap.py index a38d2bd6d02..61f38af2d26 100644 --- a/src/sage/interfaces/gap.py +++ b/src/sage/interfaces/gap.py @@ -222,10 +222,11 @@ # suppress unaligned access to 0x..., ip=0x... warnings gap_cmd = 'prctl --unaligned=silent ' + gap_cmd + def gap_command(use_workspace_cache=True, local=True): if use_workspace_cache: if local: - return "%s -L %s"%(gap_cmd, WORKSPACE), False + return "%s -L %s" % (gap_cmd, WORKSPACE), False else: # TO DO: Use remote workspace return gap_cmd, False @@ -442,7 +443,7 @@ def load_package(self, pkg, verbose=False): print("Loading GAP package {}".format(pkg)) x = self.eval('LoadPackage("{}")'.format(pkg)) if x == 'fail': - raise RuntimeError("Error loading Gap package "+str(pkg)+". "+ + raise RuntimeError("Error loading Gap package "+str(pkg)+". " + "You may want to install gap_packages SPKG.") def eval(self, x, newlines=False, strip=True, split_lines=True, **kwds): @@ -501,7 +502,7 @@ def eval(self, x, newlines=False, strip=True, split_lines=True, **kwds): #it is occurring in a string. If it is not in a string, we #strip off the comment. if not split_lines: - input_line=str(x) + input_line = str(x) else: input_line = "" for line in str(x).rstrip().split('\n'): @@ -518,7 +519,6 @@ def eval(self, x, newlines=False, strip=True, split_lines=True, **kwds): result = result.replace("\\\n","") return result.rstrip() - def _execute_line(self, line, wait_for_prompt=True, expect_eof=False): if self._expect is None: # interface is down self._start() @@ -528,10 +528,10 @@ def _execute_line(self, line, wait_for_prompt=True, expect_eof=False): raise RuntimeError("Passing commands this long to gap would hang") E.sendline(line) except OSError: - raise RuntimeError("Error evaluating %s in %s"%(line, self)) + raise RuntimeError("Error evaluating %s in %s" % (line, self)) if not wait_for_prompt: return (b'',b'') - if len(line)==0: + if len(line) == 0: return (b'',b'') try: terminal_echo = [] # to be discarded @@ -566,23 +566,23 @@ def _execute_line(self, line, wait_for_prompt=True, expect_eof=False): break elif x == 9: # @m finished running a child pass # there is no need to do anything - elif x==10: #@n normal output line + elif x == 10: #@n normal output line current_outputs = normal_outputs - elif x==11: #@r echoing input + elif x == 11: #@r echoing input current_outputs = terminal_echo - elif x==12: #@sN shouldn't happen + elif x == 12: #@sN shouldn't happen warnings.warn("this should never happen") - elif x==13: #@w GAP is trying to send a Window command + elif x == 13: #@w GAP is trying to send a Window command warnings.warn("this should never happen") - elif x ==14: #@x seems to be safely ignorable + elif x == 14: #@x seems to be safely ignorable pass elif x == 15:#@z GAP starting a subprocess pass # there is no need to do anything except pexpect.EOF: if not expect_eof: - raise RuntimeError("Unexpected EOF from %s executing %s"%(self,line)) + raise RuntimeError("Unexpected EOF from %s executing %s" % (self,line)) except IOError: - raise RuntimeError("IO Error from %s executing %s"%(self,line)) + raise RuntimeError("IO Error from %s executing %s" % (self,line)) return (b"".join(normal_outputs), b"".join(error_outputs)) def _keyboard_interrupt(self): @@ -603,7 +603,7 @@ def _keyboard_interrupt(self): 2 """ self.quit() - raise KeyboardInterrupt("Ctrl-c pressed while running %s"%self) + raise KeyboardInterrupt("Ctrl-c pressed while running %s" % self) def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=True): r""" @@ -688,7 +688,7 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if self.quit() gap_reset_workspace() error = error.replace('\r','') - raise RuntimeError("%s produced error output\n%s\n executing %s"%(self, error,line)) + raise RuntimeError("%s produced error output\n%s\n executing %s" % (self, error,line)) if not normal: return '' @@ -726,7 +726,7 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if except KeyboardInterrupt: self._keyboard_interrupt() - raise KeyboardInterrupt("Ctrl-c pressed while running %s"%self) + raise KeyboardInterrupt("Ctrl-c pressed while running %s" % self) def unbind(self, var): """ @@ -745,7 +745,7 @@ def unbind(self, var): Error, Variable: 'x' must have a value ... """ - self.eval('Unbind(%s)'%var) + self.eval('Unbind(%s)' % var) self.clear(var) def _contains(self, v1, v2): @@ -762,7 +762,7 @@ def _contains(self, v1, v2): sage: 2 in gap('Integers') True """ - return self.eval('%s in %s'%(v1,v2)) == "true" + return self.eval('%s in %s' % (v1,v2)) == "true" def _true_symbol(self): """ @@ -866,8 +866,8 @@ def function_call(self, function, args=None, kwds=None): #value, then that value will be in 'last', otherwise it will #be the marker. marker = '__SAGE_LAST__:="__SAGE_LAST__";;' - cmd = "%s(%s);;"%(function, ",".join([s.name() for s in args]+ - ['%s=%s'%(key,value.name()) for key, value in kwds.items()])) + cmd = "%s(%s);;" % (function, ",".join([s.name() for s in args] + + ['%s=%s' % (key,value.name()) for key, value in kwds.items()])) if len(marker) + len(cmd) <= self._eval_using_file_cutoff: # We combine the two commands so we only run eval() once and the # only output would be from the second command @@ -978,9 +978,9 @@ def __len__(self): it is false """ P = self.parent() - if P.eval('%s = true'%self.name()) == 'true': + if P.eval('%s = true' % self.name()) == 'true': return 1 - elif P.eval('%s = false'%self.name()) == 'true': + elif P.eval('%s = false' % self.name()) == 'true': return 0 else: return int(self.Length()) @@ -1038,7 +1038,6 @@ def _matrix_(self, R): entries = [[R(self[r,c]) for c in range(1,m+1)] for r in range(1,n+1)] return M(entries) -############ class Gap(Gap_generic): r""" @@ -1146,7 +1145,7 @@ def _next_var_name(self): del self._available_vars[0] return v self.__seq += 1 - return r'\$sage%s'%self.__seq + return r'\$sage%s' % self.__seq def _start(self): """ @@ -1219,7 +1218,6 @@ def _function_class(self): """ return GapFunction - def cputime(self, t=None): r""" Returns the amount of CPU time that the GAP session has used. If @@ -1255,10 +1253,10 @@ def save_workspace(self): sage: ORIGINAL_WORKSPACE = sage.interfaces.gap.WORKSPACE sage: import tempfile - sage: with tempfile.NamedTemporaryFile(prefix="0"*80) as f: + sage: with tempfile.NamedTemporaryFile(prefix="0"*80) as f: # long time (4s on sage.math, 2013) ....: sage.interfaces.gap.WORKSPACE = f.name ....: gap = Gap() - ....: gap('3+2') # long time (4s on sage.math, 2013) + ....: gap('3+2') 5 sage: sage.interfaces.gap.WORKSPACE = ORIGINAL_WORKSPACE """ @@ -1272,7 +1270,7 @@ def save_workspace(self): from sage.misc.temporary_file import atomic_write with atomic_write(WORKSPACE) as f: f.close() - self.eval('SaveWorkspace("%s");'%(f.name), allow_use_file=False) + self.eval('SaveWorkspace("%s");' % (f.name), allow_use_file=False) # Todo -- this -- but there is a tricky "when does it end" issue! # Maybe do via a file somehow? @@ -1358,14 +1356,14 @@ def get(self, var, use_file=False): tmp = self._local_tmpfile() if os.path.exists(tmp): os.unlink(tmp) - self.eval('PrintTo("%s", %s);'%(tmp,var), strip=False) + self.eval('PrintTo("%s", %s);' % (tmp,var), strip=False) with open(tmp) as f: r = f.read() r = r.strip().replace("\\\n","") os.unlink(tmp) return r else: - return self.eval('Print(%s);'%var, newlines=False) + return self.eval('Print(%s);' % var, newlines=False) def _pre_interact(self): """ @@ -1392,7 +1390,7 @@ def _eval_line_using_file(self, line): if j >= 0 and j < i: i = -1 if i == -1: - line0 = 'Print( %s );'%line.rstrip().rstrip(';') + line0 = 'Print( %s );' % line.rstrip().rstrip(';') try: # this is necessary, since Print requires something as input, and some functions (e.g., Read) return nothing. return Expect._eval_line_using_file(self, line0) except RuntimeError: @@ -1467,8 +1465,6 @@ def _tab_completion(self): return [n for n in names if n[0] in string.ascii_letters] -############ - def gap_reset_workspace(max_workspace_size=None, verbose=False): r""" Call this to completely reset the GAP workspace, which is used by @@ -1512,6 +1508,8 @@ def gap_reset_workspace(max_workspace_size=None, verbose=False): """ # Create new workspace with filename WORKSPACE g = Gap(use_workspace_cache=False, max_workspace_size=None) + g.eval('ColorPrompt(false)') + g.eval('SetUserPreference("UseColorPrompt", false)') g.eval('SetUserPreference("HistoryMaxLines", 30)') from sage.tests.gap_packages import all_installed_packages for pkg in all_installed_packages(gap=g): @@ -1564,7 +1562,7 @@ def _latex_(self): """ P = self._check_valid() try: - s = P.eval('LaTeXObj(%s)'%self.name()) + s = P.eval('LaTeXObj(%s)' % self.name()) s = s.replace('\\\\','\\').replace('"','') s = s.replace('%\\n',' ') return s @@ -1587,7 +1585,7 @@ def _tab_completion(self): True """ P = self.parent() - v = P.eval(r'\$SAGE.OperationsAdmittingFirstArgument(%s)'%self.name()) + v = P.eval(r'\$SAGE.OperationsAdmittingFirstArgument(%s)' % self.name()) v = v.replace('Tester(','').replace('Setter(','').replace(')','').replace('\n', '') v = v.split(',') v = [ oper.split('"')[1] for oper in v ] @@ -1753,7 +1751,7 @@ def intmod_gap_to_sage(x): sage: b.parent() Ring of integers modulo 65537 """ - from sage.rings.finite_rings.all import FiniteField + from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.rings.finite_rings.integer_mod import Mod from sage.rings.integer import Integer s = str(x) @@ -1765,10 +1763,10 @@ def intmod_gap_to_sage(x): return Mod(Integer(m.group(1)), Integer(m.group(2))) raise ValueError("Unable to convert Gap element '%s'" % s) -############# gap = Gap() + def reduce_load_GAP(): """ Returns the GAP interface object defined in sage.interfaces.gap. diff --git a/src/sage/interfaces/gap3.py b/src/sage/interfaces/gap3.py index 78d05035cbf..beef28e562a 100644 --- a/src/sage/interfaces/gap3.py +++ b/src/sage/interfaces/gap3.py @@ -490,7 +490,7 @@ def help(self, topic, pager=True): elif x == 10: # matched @n (normal input mode); it seems we're done break - elif x==11: + elif x == 11: # matched @r (echoing input); skip to end of line E.expect_list(self._compiled_small_pattern) @@ -743,7 +743,7 @@ def _latex_(self): """ gap3_session = self._check_valid() try: - s = gap3_session.eval('FormatLaTeX(%s)'%self.name()) + s = gap3_session.eval('FormatLaTeX(%s)' % self.name()) s = s.replace('\\\\','\\').replace('"','') s = s.replace('%\\n',' ') return s diff --git a/src/sage/interfaces/gap_workspace.py b/src/sage/interfaces/gap_workspace.py index 33a87dd5076..03b40be6856 100644 --- a/src/sage/interfaces/gap_workspace.py +++ b/src/sage/interfaces/gap_workspace.py @@ -16,7 +16,8 @@ import os import time import hashlib -from sage.env import DOT_SAGE, GAP_SO +import subprocess +from sage.env import DOT_SAGE, HOSTNAME, GAP_LIB_DIR, GAP_SHARE_DIR def gap_workspace_file(system="gap", name="workspace", dir=None): @@ -59,11 +60,13 @@ def gap_workspace_file(system="gap", name="workspace", dir=None): if dir is None: dir = os.path.join(DOT_SAGE, 'gap') - if GAP_SO: - h = hashlib.sha1(GAP_SO.encode('utf-8')).hexdigest() - else: - h = 'unknown' - return os.path.join(dir, '%s-%s-%s' % (system, name, h)) + data = f'{GAP_LIB_DIR}:{GAP_SHARE_DIR}' + for path in GAP_LIB_DIR, GAP_SHARE_DIR: + sysinfo = os.path.join(path, "sysinfo.gap") + if os.path.exists(sysinfo): + data += subprocess.getoutput(f'. "{sysinfo}" && echo ":$GAP_VERSION:$GAParch"') + h = hashlib.sha1(data.encode('utf-8')).hexdigest() + return os.path.join(dir, f'{system}-{name}-{HOSTNAME}-{h}') def prepare_workspace_dir(dir=None): diff --git a/src/sage/interfaces/genus2reduction.py b/src/sage/interfaces/genus2reduction.py index 7a4794daf22..eeb63fcb939 100644 --- a/src/sage/interfaces/genus2reduction.py +++ b/src/sage/interfaces/genus2reduction.py @@ -34,7 +34,9 @@ # **************************************************************************** from sage.structure.sage_object import SageObject -from sage.rings.all import ZZ, QQ, PolynomialRing +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.libs.pari.all import pari roman_numeral = ["", "I", "II", "III", "IV", "V", "VI", "VII"] @@ -158,17 +160,17 @@ def _repr_(self): if self.Q == 0: yterm = '' else: - yterm = '+ (%s)*y '%self.Q + yterm = '+ (%s)*y ' % self.Q s = 'Reduction data about this proper smooth genus 2 curve:\n' - s += '\ty^2 %s= %s\n'%(yterm, self.P) + s += '\ty^2 %s= %s\n' % (yterm, self.P) if self.Qmin: - s += 'A Minimal Equation:\n\ty^2 + (%s)y = %s\n'%(self.Qmin, self.Pmin) + s += 'A Minimal Equation:\n\ty^2 + (%s)y = %s\n' % (self.Qmin, self.Pmin) else: - s += 'A Minimal Equation:\n\ty^2 = %s\n'%self.Pmin - s += 'Minimal Discriminant: %s\n'%self.minimal_disc - s += 'Conductor: %s\n'%self.conductor - s += 'Local Data:\n%s'%self._local_data_str() + s += 'A Minimal Equation:\n\ty^2 = %s\n' % self.Pmin + s += 'Minimal Discriminant: %s\n' % self.minimal_disc + s += 'Conductor: %s\n' % self.conductor + s += 'Local Data:\n%s' % self._local_data_str() return s def _local_data_str(self): @@ -176,7 +178,7 @@ def _local_data_str(self): D = self.local_data K = sorted(D.keys()) for p in K: - s += 'p=%s\n%s\n'%(p, D[p]) + s += 'p=%s\n%s\n' % (p, D[p]) s = '\t' + '\n\t'.join(s.strip().split('\n')) return s @@ -215,7 +217,7 @@ def divisors_to_string(divs): # Next divisor is different or we are done? Print current one if s: s += "x" - s += "(%s)"%divs[i] + s += "(%s)" % divs[i] if n > 1: s += "^%s" % n n = 0 @@ -455,6 +457,7 @@ def __call__(self, Q, P): def __reduce__(self): return _reduce_load_genus2reduction, tuple([]) + # An instance genus2reduction = Genus2reduction() diff --git a/src/sage/interfaces/gnuplot.py b/src/sage/interfaces/gnuplot.py index 8ab14c75e1c..76841963721 100644 --- a/src/sage/interfaces/gnuplot.py +++ b/src/sage/interfaces/gnuplot.py @@ -99,7 +99,7 @@ def plot(self, cmd, file=None, verbose=True, reset=True): print("Saving plot to %s" % file) self(cmd) time.sleep(0.1) - os.system('mv %s %s 2>/dev/null'%(tmp, file)) + os.system('mv %s %s 2>/dev/null' % (tmp, file)) time.sleep(0.1) self('set terminal x11') @@ -110,7 +110,7 @@ def plot3d(self, f, xmin=-1, xmax=1, ymin=-1, ymax=1, zmin=-1, zmax=1, if title is None: title = str(f) f = f.replace('^','**') - cmd=""" + cmd = """ set xlabel "%s" set ylabel "%s" set key top @@ -125,7 +125,7 @@ def plot3d(self, f, xmin=-1, xmax=1, ymin=-1, ymax=1, zmin=-1, zmax=1, #show pm3d #show palette splot %s - """%(xlabel, ylabel, + """ % (xlabel, ylabel, xmin, xmax, ymin, ymax, #zmin, zmax, samples, isosamples, title, f) @@ -159,11 +159,11 @@ def plot3d_parametric(self, f='cos(u)*(3 + v*cos(u/2)), sin(u)*(3 + v*cos(u/2)), EXAMPLES:: - sage: gnuplot.plot3d_parametric('v^2*sin(u), v*cos(u), v*(1-v)') # optional - gnuplot (not tested, since something pops up). + sage: gnuplot.plot3d_parametric('v^2*sin(u), v*cos(u), v*(1-v)') # optional - gnuplot, not tested (since something pops up) """ if title is None: title = str(f) - cmd=""" + cmd = """ set key top set border 4095 set samples %s @@ -187,6 +187,7 @@ def interact(self, cmd): def console(self): gnuplot_console() + # An instance gnuplot = Gnuplot() diff --git a/src/sage/interfaces/gp.py b/src/sage/interfaces/gp.py index d3c8756a69c..49b1a8a06fb 100644 --- a/src/sage/interfaces/gp.py +++ b/src/sage/interfaces/gp.py @@ -617,7 +617,7 @@ def _next_var_name(self): sage: g = Gp(stacksize=10^4,init_list_length=12000) # long time sage: for n in [1..13000]: # long time - ....: a = g(n) # long time + ....: a = g(n) sage: g('length(sage)') # long time 24000 """ diff --git a/src/sage/interfaces/interface.py b/src/sage/interfaces/interface.py index ae1b656b77f..78f94269ff4 100644 --- a/src/sage/interfaces/interface.py +++ b/src/sage/interfaces/interface.py @@ -324,7 +324,7 @@ def _coerce_from_special_method(self, x): If no such method is defined, raises an AttributeError instead of a TypeError. """ - s = '_%s_'%self.name() + s = '_%s_' % self.name() if s == '_maxima_lib_': s = '_maxima_' if s == '_pari_': @@ -375,11 +375,11 @@ def _coerce_impl(self, x, use_special=True): A.append(w.name()) z.append(w) X = ','.join(A) - r = self.new('%s%s%s'%(self._left_list_delim(), X, self._right_list_delim())) + r = self.new('%s%s%s' % (self._left_list_delim(), X, self._right_list_delim())) r.__sage_list = z # do this to avoid having the entries of the list be garbage collected return r - raise TypeError("unable to coerce element into %s"%self.name()) + raise TypeError("unable to coerce element into %s" % self.name()) def new(self, code): return self(code) @@ -412,14 +412,14 @@ def _true_symbol(self): try: return self.__true_symbol except AttributeError: - self.__true_symbol = self.get('1 %s 1'%self._equality_symbol()) + self.__true_symbol = self.get('1 %s 1' % self._equality_symbol()) return self.__true_symbol def _false_symbol(self): try: return self.__false_symbol except AttributeError: - self.__false_symbol = self.get('1 %s 2'%self._equality_symbol()) + self.__false_symbol = self.get('1 %s 2' % self._equality_symbol()) return self.__false_symbol def _lessthan_symbol(self): @@ -470,7 +470,7 @@ def set(self, var, value): """ Set the variable var to the given value. """ - cmd = '%s%s%s;'%(var,self._assign_symbol(), value) + cmd = '%s%s%s;' % (var,self._assign_symbol(), value) self.eval(cmd) def get(self, var): @@ -509,7 +509,7 @@ def _next_var_name(self): del self._available_vars[0] return v self.__seq += 1 - return "sage%s"%self.__seq + return "sage%s" % self.__seq def _create(self, value, name=None): name = self._next_var_name() if name is None else name @@ -612,7 +612,7 @@ def function_call(self, function, args=None, kwds=None): self._check_valid_function_name(function) s = self._function_call_string(function, [s.name() for s in args], - ['%s=%s'%(key,value.name()) for key, value in kwds.items()]) + ['%s=%s' % (key,value.name()) for key, value in kwds.items()]) return self.new(s) def _function_call_string(self, function, args, kwds): @@ -624,7 +624,7 @@ def _function_call_string(self, function, args, kwds): sage: maxima._function_call_string('diff', ['f(x)', 'x'], []) 'diff(f(x),x)' """ - return "%s(%s)"%(function, ",".join(list(args) + list(kwds))) + return "%s(%s)" % (function, ",".join(list(args) + list(kwds))) def call(self, function_name, *args, **kwds): return self.function_call(function_name, args, kwds) @@ -709,7 +709,6 @@ def _instancedoc_(self): return M.help(self._name) - def is_InterfaceElement(x): """ Return True if ``x`` is of type :class:`InterfaceElement`. @@ -880,7 +879,7 @@ def _reduce(self): `"'abc'"` instead. That is dependant on the Elements `is_string` function to be implemented correctly. This has gone wrong in the past and remained uncaught by the doctests because the original identifier was reused. This test makes sure - that does not happen again: + that does not happen again:: sage: a = r("'abc'") # optional - rpy2 sage: b = dumps(a) # optional - rpy2 @@ -963,18 +962,18 @@ def _richcmp_(self, other, op): """ P = self._check_valid() try: - if P.eval("%s %s %s"%(self.name(), P._equality_symbol(), + if P.eval("%s %s %s" % (self.name(), P._equality_symbol(), other.name())) == P._true_symbol(): return rich_to_bool(op, 0) except RuntimeError: pass try: - if P.eval("%s %s %s"%(self.name(), P._lessthan_symbol(), other.name())) == P._true_symbol(): + if P.eval("%s %s %s" % (self.name(), P._lessthan_symbol(), other.name())) == P._true_symbol(): return rich_to_bool(op, -1) except RuntimeError: pass try: - if P.eval("%s %s %s"%(self.name(), P._greaterthan_symbol(), other.name())) == P._true_symbol(): + if P.eval("%s %s %s" % (self.name(), P._greaterthan_symbol(), other.name())) == P._true_symbol(): return rich_to_bool(op, 1) except Exception: pass @@ -1005,7 +1004,7 @@ def _check_valid(self): try: P = self.parent() if P is None: - raise ValueError("The %s session in which this object was defined is no longer running."%P.name()) + raise ValueError("The %s session in which this object was defined is no longer running." % P.name()) except AttributeError: raise ValueError("The session in which this object was defined is no longer running.") return P @@ -1100,7 +1099,6 @@ def _sage_(self): except Exception: raise NotImplementedError("Unable to parse output: %s" % string) - def sage(self, *args, **kwds): """ Attempt to return a Sage version of this object. @@ -1171,11 +1169,8 @@ def __repr__(self): s = cr else: s = self._repr_() - if self._name in s: - try: - s = s.replace(self._name, getattr(self, '__custom_name')) - except AttributeError: - pass + if self._name in s and self.get_custom_name() is not None: + s = s.replace(self._name, self.get_custom_name()) if cr: self._cached_repr = s return s @@ -1290,14 +1285,14 @@ def attribute(self, attrname): -122023936/161051 """ P = self._check_valid() - return P('%s.%s'%(self.name(), attrname)) + return P('%s.%s' % (self.name(), attrname)) def __getitem__(self, n): P = self._check_valid() if not isinstance(n, tuple): - return P.new('%s[%s]'%(self._name, n)) + return P.new('%s[%s]' % (self._name, n)) else: - return P.new('%s[%s]'%(self._name, str(n)[1:-1])) + return P.new('%s[%s]' % (self._name, str(n)[1:-1])) def __int__(self): """ @@ -1434,7 +1429,7 @@ def name(self, new_name=None): def gen(self, n): P = self._check_valid() - return P.new('%s.%s'%(self._name, int(n))) + return P.new('%s.%s' % (self._name, int(n))) def _operation(self, operation, other=None): r""" @@ -1471,9 +1466,9 @@ def _operation(self, operation, other=None): """ P = self._check_valid() if other is None: - cmd = '%s %s'%(operation, self._name) + cmd = '%s %s' % (operation, self._name) else: - cmd = '%s %s %s'%(self._name, operation, other._name) + cmd = '%s %s %s' % (self._name, operation, other._name) try: return P.new(cmd) except Exception as msg: @@ -1581,20 +1576,20 @@ def _mul_(self, right): :: sage: f = maxima.function('x','sin(x)') - sage: g = maxima('-cos(x)') # not a function! + sage: g = maxima('cos(x)') # not a function! sage: f*g - -cos(x)*sin(x) + cos(x)*sin(x) sage: _(2) - -cos(2)*sin(2) + cos(2)*sin(2) :: sage: f = maxima.function('x','sin(x)') - sage: g = maxima('-cos(x)') + sage: g = maxima('cos(x)') sage: g*f - -cos(x)*sin(x) + cos(x)*sin(x) sage: _(2) - -cos(2)*sin(2) + cos(2)*sin(2) sage: 2*f 2*sin(x) """ @@ -1614,20 +1609,20 @@ def _div_(self, right): :: sage: f = maxima.function('x','sin(x)') - sage: g = maxima('-cos(x)') + sage: g = maxima('cos(x)') sage: f/g - -sin(x)/cos(x) + sin(x)/cos(x) sage: _(2) - -sin(2)/cos(2) + sin(2)/cos(2) :: sage: f = maxima.function('x','sin(x)') - sage: g = maxima('-cos(x)') + sage: g = maxima('cos(x)') sage: g/f - -cos(x)/sin(x) + cos(x)/sin(x) sage: _(2) - -cos(2)/sin(2) + cos(2)/sin(2) sage: 2/f 2/sin(x) """ diff --git a/src/sage/interfaces/jmoldata.py b/src/sage/interfaces/jmoldata.py index 6660a14e1cc..a68e53e2d85 100644 --- a/src/sage/interfaces/jmoldata.py +++ b/src/sage/interfaces/jmoldata.py @@ -165,12 +165,12 @@ def export_image(self, datafile = cygwin.cygpath(datafile, 'w') launchscript = "" - if (datafile_cmd!='script'): + if (datafile_cmd != 'script'): launchscript = "load " launchscript = launchscript + datafile imagescript = 'write {} {!r}\n'.format(image_type, target_native) - size_arg = "%sx%s" %(figsize*100,figsize*100) + size_arg = "%sx%s" % (figsize*100,figsize*100) # Scratch file for Jmol errors scratchout = tmp_filename(ext=".txt") with open(scratchout, 'w') as jout: diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index e005b5b6832..3607dd7879e 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -493,7 +493,7 @@ def basis(self, dim): sage: kenzo_chcm # optional - kenzo [K... Chain-Complex] sage: for i in range(6): # optional - kenzo - ....: print("Basis in dimension %i: %s" % (i, kenzo_chcm.basis(i))) # optional - kenzo + ....: print("Basis in dimension %i: %s" % (i, kenzo_chcm.basis(i))) Basis in dimension 0: ['G0G0', 'G0G1', 'G0G2'] Basis in dimension 1: ['G1G0', 'G1G1'] Basis in dimension 2: None @@ -1157,8 +1157,8 @@ def SAbstractSimplex(simplex, dim): EXAMPLES:: sage: from sage.libs.ecl import EclObject, ecl_eval - sage: from sage.interfaces.kenzo import KenzoObject,\ - ....: SAbstractSimplex # optional - kenzo + sage: from sage.interfaces.kenzo import ( # optional - kenzo + ....: KenzoObject, SAbstractSimplex) sage: KAbSm = KenzoObject(ecl_eval("(ABSM 15 'K)")) # optional - kenzo sage: SAbSm1 = SAbstractSimplex(KAbSm, 2) # optional - kenzo sage: SAbSm2 = SAbstractSimplex(KAbSm, 7) # optional - kenzo @@ -1193,8 +1193,8 @@ def KAbstractSimplex(simplex): EXAMPLES:: sage: from sage.topology.simplicial_set import AbstractSimplex - sage: from sage.interfaces.kenzo import KAbstractSimplex,\ - ....: SAbstractSimplex # optional - kenzo + sage: from sage.interfaces.kenzo import ( # optional - kenzo + ....: KAbstractSimplex, SAbstractSimplex) sage: SAbSm = AbstractSimplex(1, (2,0,3,2,1), name = 'SAbSm') # optional - kenzo sage: KAbSm = KAbstractSimplex(SAbSm) # optional - kenzo sage: SAbSm2 = SAbstractSimplex(KAbSm, 1) # optional - kenzo @@ -1290,8 +1290,9 @@ def SFiniteSimplicialSet(ksimpset, limit): EXAMPLES:: sage: from sage.topology.simplicial_set import SimplicialSet - sage: from sage.interfaces.kenzo import AbstractSimplex,\ - ....: KFiniteSimplicialSet, SFiniteSimplicialSet, Sphere # optional - kenzo + sage: from sage.interfaces.kenzo import ( # optional - kenzo + ....: AbstractSimplex, KFiniteSimplicialSet, + ....: SFiniteSimplicialSet, Sphere) sage: s0 = AbstractSimplex(0, name='s0') # optional - kenzo sage: s1 = AbstractSimplex(0, name='s1') # optional - kenzo sage: s2 = AbstractSimplex(0, name='s2') # optional - kenzo @@ -1299,8 +1300,10 @@ def SFiniteSimplicialSet(ksimpset, limit): sage: s02 = AbstractSimplex(1, name='s02') # optional - kenzo sage: s12 = AbstractSimplex(1, name='s12') # optional - kenzo sage: s012 = AbstractSimplex(2, name='s012') # optional - kenzo - sage: Triangle = SimplicialSet({s01: (s1, s0),\ - ....: s02: (s2, s0), s12: (s2, s1)}, base_point = s0) # optional - kenzo + sage: Triangle = SimplicialSet({s01: (s1, s0), # optional - kenzo + ....: s02: (s2, s0), + ....: s12: (s2, s1)}, + ....: base_point = s0) sage: KTriangle = KFiniteSimplicialSet(Triangle) # optional - kenzo sage: STriangle = SFiniteSimplicialSet(KTriangle, 1) # optional - kenzo sage: STriangle.homology() # optional - kenzo @@ -1645,8 +1648,8 @@ def sum(self, object=None): sage: null # optional - kenzo [K... Morphism (degree 0): K... -> K...] sage: idx2 = idnt.sum(idnt) # optional - kenzo - sage: idx5 = idx2.sum(\ - ....: (opps_id, idnt, idnt, null, idx2.sum(idnt), opps_id)) # optional - kenzo + sage: idx5 = idx2.sum( # optional - kenzo + ....: (opps_id, idnt, idnt, null, idx2.sum(idnt), opps_id)) sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] sage: idx2.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo @@ -1711,8 +1714,8 @@ def substract(self, object=None): sage: null # optional - kenzo [K... Morphism (degree 0): K... -> K...] sage: idx2 = idnt.substract(opps_id) # optional - kenzo - sage: opps_idx2 = idx2.substract\ - ....: ((opps_id, idnt, idnt, null, idx2.substract(opps_id))) # optional - kenzo + sage: opps_idx2 = idx2.substract( # optional - kenzo + ....: (opps_id, idnt, idnt, null, idx2.substract(opps_id))) sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] sage: idx2.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo @@ -1861,13 +1864,14 @@ def build_morphism(source_complex, target_complex, degree, algorithm, strategy, EXAMPLES:: - sage: from sage.interfaces.kenzo import KenzoChainComplex,\ - ....: build_morphism # optional - kenzo + sage: from sage.interfaces.kenzo import (KenzoChainComplex, + ....: build_morphism) sage: from sage.libs.ecl import ecl_eval sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo - sage: A = build_morphism(ZCC, ZCC, -1,\ - ....: ecl_eval("#'(lambda (comb) (cmbn (1- (degr comb))))"),\ - ....: "cmbn", ["zero morphism on ZCC"]) # optional - kenzo + sage: A = build_morphism( # optional - kenzo + ....: ZCC, ZCC, -1, + ....: ecl_eval("#'(lambda (comb) (cmbn (1- (degr comb))))"), + ....: "cmbn", ["zero morphism on ZCC"]) sage: A.target_complex() # optional - kenzo [K... Chain-Complex] sage: A.degree() # optional - kenzo diff --git a/src/sage/interfaces/lisp.py b/src/sage/interfaces/lisp.py index c4d8542a5ed..3d6e620c4d1 100644 --- a/src/sage/interfaces/lisp.py +++ b/src/sage/interfaces/lisp.py @@ -136,7 +136,7 @@ def eval(self, code, strip=True, **kwds): x.append(M.strip()) self.__in_seq = s except TypeError as s: - return 'error evaluating "%s":\n%s'%(code,s) + return 'error evaluating "%s":\n%s' % (code,s) return '\n'.join(x) def _an_element_impl(self): @@ -165,10 +165,10 @@ def set(self, var, value): sage: lisp.eval('x') '2' """ - cmd = '(setq %s %s)'%(var, value) + cmd = '(setq %s %s)' % (var, value) out = self.eval(cmd) if '***' in out: - raise TypeError("Error executing code in Sage\nCODE:\n\t%s\nSAGE ERROR:\n\t%s"%(cmd, out)) + raise TypeError("Error executing code in Sage\nCODE:\n\t%s\nSAGE ERROR:\n\t%s" % (cmd, out)) def get(self, var): """ @@ -202,7 +202,7 @@ def _synchronize(self): E = self._expect r = random.randrange(2147483647) s = str(r+1) - cmd = "(+ 1 %s)"%r + cmd = "(+ 1 %s)" % r E.sendline(cmd) E.expect(s) E.expect(self._prompt) @@ -410,9 +410,9 @@ def _richcmp_(self, other, op): if parent(other) is not P: other = P(other) - if P.eval('(= %s %s)'%(self.name(), other.name())) == P._true_symbol(): + if P.eval('(= %s %s)' % (self.name(), other.name())) == P._true_symbol(): return rich_to_bool(op, 0) - elif P.eval('(< %s %s)'%(self.name(), other.name())) == P._true_symbol(): + elif P.eval('(< %s %s)' % (self.name(), other.name())) == P._true_symbol(): return rich_to_bool(op, -1) else: return rich_to_bool(op, 1) @@ -454,7 +454,7 @@ def _sub_(self, right): -1 """ P = self._check_valid() - return P.new('(- %s %s)'%(self._name, right._name)) + return P.new('(- %s %s)' % (self._name, right._name)) def _mul_(self, right): """ @@ -465,7 +465,7 @@ def _mul_(self, right): 2 """ P = self._check_valid() - return P.new('(* %s %s)'%(self._name, right._name)) + return P.new('(* %s %s)' % (self._name, right._name)) def _div_(self, right): """ @@ -476,7 +476,7 @@ def _div_(self, right): 1/2 """ P = self._check_valid() - return P.new('(/ %s %s)'%(self._name, right._name)) + return P.new('(/ %s %s)' % (self._name, right._name)) def __pow__(self, n): """ @@ -537,6 +537,7 @@ def is_LispElement(x): return isinstance(x, LispElement) + # An instance lisp = Lisp() @@ -550,6 +551,7 @@ def reduce_load_Lisp(): """ return lisp + import os def lisp_console(): """ diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 09d17c4f2a4..1d575b4ff7c 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -845,7 +845,7 @@ def new_from(self, type, value): """ type = self(type) value = self(value) - return self.new("new %s from %s"%(type.name(), value.name())) + return self.new("new %s from %s" % (type.name(), value.name())) def _macaulay2_input_ring(self, base_ring, vars, order='GRevLex'): """ @@ -972,13 +972,13 @@ def external_string(self): 'QQ(monoid[x..y, Degrees => {2:1}, Heft => {1}, MonomialOrder => VerticalList{MonomialSize => 32, GRevLex => {2:1}, Position => Up}, DegreeRank => 1])' """ P = self._check_valid() - code = 'toExternalString(%s)'%self.name() + code = 'toExternalString(%s)' % self.name() X = P.eval(code, strip=True) if 'stdio:' in X: if 'to external string' in X: - return P.eval('%s'%self.name()) - raise RuntimeError("Error evaluating Macaulay2 code.\nIN:%s\nOUT:%s"%(code, X)) + return P.eval('%s' % self.name()) + raise RuntimeError("Error evaluating Macaulay2 code.\nIN:%s\nOUT:%s" % (code, X)) s = multiple_replace({'\r':'', '\n':' '}, X) return s @@ -1050,7 +1050,7 @@ def __len__(self): """ self._check_valid() # we use str instead of repr to avoid wrapping - return int(str(self.parent()("#%s"%self.name()))) + return int(str(self.parent()("#%s" % self.name()))) def __getitem__(self, n): """ @@ -1062,7 +1062,7 @@ def __getitem__(self, n): """ self._check_valid() n = self.parent()(n) - return self.parent().new('%s # %s'%(self.name(), n.name())) + return self.parent().new('%s # %s' % (self.name(), n.name())) def __setitem__(self, index, value): """ @@ -1077,7 +1077,7 @@ def __setitem__(self, index, value): P = self.parent() index = P(index) value = P(value) - res = P.eval("%s # %s = %s"%(self.name(), index.name(), value.name())) + res = P.eval("%s # %s = %s" % (self.name(), index.name(), value.name())) if "assignment attempted to element of immutable list" in res: raise TypeError("item assignment not supported") @@ -1095,7 +1095,7 @@ def __call__(self, x): self._check_valid() P = self.parent() r = P(x) - return P('%s %s'%(self.name(), r.name())) + return P('%s %s' % (self.name(), r.name())) def __floordiv__(self, x): """ @@ -1119,10 +1119,10 @@ def __floordiv__(self, x): """ if isinstance(x, (list, tuple)): y = self.parent(x) - z = self.parent().new('%s // matrix{%s}'%(self.name(), y.name())) + z = self.parent().new('%s // matrix{%s}' % (self.name(), y.name())) return list(z.entries().flatten()) else: - return self.parent().new('%s // %s'%(self.name(), x.name())) + return self.parent().new('%s // %s' % (self.name(), x.name())) def __mod__(self, x): """ @@ -1148,10 +1148,10 @@ def __mod__(self, x): """ if isinstance(x, (list, tuple)): y = self.parent(x) - return self.parent().new('%s %% matrix{%s}'%(self.name(), y.name())) + return self.parent().new('%s %% matrix{%s}' % (self.name(), y.name())) if not isinstance(x, Macaulay2Element): x = self.parent(x) - return self.parent().new('%s %% %s'%(self.name(), x.name())) + return self.parent().new('%s %% %s' % (self.name(), x.name())) def __bool__(self): """ @@ -1219,7 +1219,7 @@ def structure_sheaf(self): """ from sage.misc.superseded import deprecation deprecation(27848, 'The function `structure_sheaf` is deprecated. Use `self.sheaf()` instead.') - return self.parent()('OO_%s'%self.name()) + return self.parent()('OO_%s' % self.name()) def substitute(self, *args, **kwds): """ @@ -1300,7 +1300,7 @@ def cls(self): Ring """ - return self.parent()("class %s"%self.name()) + return self.parent()("class %s" % self.name()) def after_print_text(self): r""" @@ -1356,7 +1356,7 @@ def _operator(self, opstr, x): """ parent = self.parent() x = parent(x) - return parent("%s%s%s"%(self.name(), opstr, x.name())) + return parent("%s%s%s" % (self.name(), opstr, x.name())) def sharp(self, x): """ @@ -1618,7 +1618,7 @@ def _sage_(self): elif cls_str == "String": return str(repr_str) elif cls_str == "Module": - from sage.modules.all import FreeModule + from sage.modules.free_module import FreeModule if self.isFreeModule()._sage_(): ring = self.ring()._sage_() rank = self.rank()._sage_() @@ -1683,7 +1683,7 @@ def _sage_(self): try: return sage_eval(repr_str) except Exception: - raise NotImplementedError("cannot convert %s to a Sage object"%repr_str) + raise NotImplementedError("cannot convert %s to a Sage object" % repr_str) to_sage = deprecated_function_alias(27848, ExpectElement.sage) @@ -1854,6 +1854,7 @@ def is_Macaulay2Element(x): return isinstance(x, Macaulay2Element) + # An instance macaulay2 = Macaulay2() diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index b909dbc30f7..b7a0ac20d03 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -209,14 +209,15 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** from __future__ import annotations import re import sys +import os from sage.structure.parent import Parent -from .expect import console, Expect, ExpectElement, ExpectFunction, FunctionElement +from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement PROMPT = ">>>" SAGE_REF = "_sage_ref" @@ -252,7 +253,6 @@ def extcode_dir(iface=None): shutil.copytree('%s/magma/' % SAGE_EXTCODE, tmp + '/data') EXTCODE_DIR = "%s/data/" % tmp else: - import os tmp = iface._remote_tmpdir() command = 'scp -q -r "%s/magma/" "%s:%s/data" 1>&2 2>/dev/null' % (SAGE_EXTCODE, iface._server, tmp) try: @@ -330,7 +330,6 @@ def __init__(self, script_subdirectory=None, Magma """ if command is None: - import os command = os.getenv('SAGE_MAGMA_COMMAND') or 'magma' if not user_config: @@ -339,7 +338,6 @@ def __init__(self, script_subdirectory=None, # Obtain the parameters from the environment, to allow the magma = Magma() phrase # to work with non-default parameters. if seed is None: - import os seed = os.getenv('SAGE_MAGMA_SEED') Expect.__init__(self, @@ -1887,9 +1885,7 @@ def __getattr__(self, attrname): """ INPUT: - - - ``attrname`` - string - + - ``attrname`` -- string OUTPUT: a Magma function partially evaluated with self as the first input. @@ -1897,8 +1893,8 @@ def __getattr__(self, attrname): .. note:: If the input ``attrname`` starts with an underscore, an - AttributeError is raised so that the actual Python _ method/value - can be accessed. + :class:`AttributeError` is raised so that the actual + Python _ method/value can be accessed. EXAMPLES:: @@ -2753,7 +2749,6 @@ def ideal(self, gens): """ return self.parent().bar_call(self, 'ideal', gens, nvals=1) -########################################################################### magma = Magma() @@ -2787,7 +2782,7 @@ def magma_console(): from sage.repl.rich_output.display_manager import get_display_manager if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%magma magics instead.') - console('magma') + os.system('magma') class MagmaGBLogPrettyPrinter: diff --git a/src/sage/interfaces/magma_free.py b/src/sage/interfaces/magma_free.py index b82b9c4699d..d01d291c337 100644 --- a/src/sage/interfaces/magma_free.py +++ b/src/sage/interfaces/magma_free.py @@ -42,7 +42,7 @@ def magma_free_eval(code, strip=True, columns=0): processPath = "/xml/calculator.xml" refererPath = "/calc/" refererUrl = "http://%s%s" % ( server, refererPath) - code = "SetColumns(%s);\n"%columns + code + code = "SetColumns(%s);\n" % columns + code params = urlencode({'input':code}) headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "Accept: text/html, application/xml, application/xhtml+xml", "Referer": refererUrl} @@ -81,7 +81,9 @@ class MagmaFree: """ def eval(self, x, **kwds): return magma_free_eval(x) + def __call__(self, code, strip=True, columns=0): return magma_free_eval(code, strip=strip, columns=columns) + magma_free = MagmaFree() diff --git a/src/sage/interfaces/matlab.py b/src/sage/interfaces/matlab.py index d3701a553b8..24c40a3647c 100644 --- a/src/sage/interfaces/matlab.py +++ b/src/sage/interfaces/matlab.py @@ -273,7 +273,6 @@ def strip_answer(self, s): i = s.find('=') return s[i+1:].strip('\n') - def console(self): matlab_console() @@ -357,6 +356,7 @@ def set(self, i, j, x): z = P(x) P.eval('{0}({1},{2}) = {3}'.format(self.name(), i, j, z.name())) + # An instance matlab = Matlab() diff --git a/src/sage/interfaces/maxima.py b/src/sage/interfaces/maxima.py index 27b1e98a6ac..c55f9797ef2 100644 --- a/src/sage/interfaces/maxima.py +++ b/src/sage/interfaces/maxima.py @@ -49,9 +49,14 @@ :: + sage: x,y = SR.var('x,y') sage: F = maxima.factor('x^5 - y^5') - sage: F - -(y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4) + sage: F # not tested - depends on maxima version + -((y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4)) + sage: actual = F.sage() + sage: expected = -(y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4) + sage: bool(actual == expected) + True sage: type(F) <class 'sage.interfaces.maxima.MaximaElement'> @@ -71,18 +76,19 @@ :: + sage: F = maxima('x * y') sage: repr(F) - '-(y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4)' + 'x*y' sage: F.str() - '-(y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4)' + 'x*y' The ``maxima.eval`` command evaluates an expression in maxima and returns the result as a *string* not a maxima object. :: - sage: print(maxima.eval('factor(x^5 - y^5)')) - -(y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4) + sage: print(maxima.eval('factor(x^5 - 1)')) + (x-1)*(x^4+x^3+x^2+x+1) We can create the polynomial `f` as a Maxima polynomial, then call the factor method on it. Notice that the notation @@ -91,11 +97,11 @@ :: - sage: f = maxima('x^5 - y^5') + sage: f = maxima('x^5 + y^5') sage: f^2 - (x^5-y^5)^2 + (y^5+x^5)^2 sage: f.factor() - -(y-x)*(y^4+x*y^3+x^2*y^2+x^3*y+x^4) + (y+x)*(y^4-x*y^3+x^2*y^2-x^3*y+x^4) Control-C interruption works well with the maxima interface, because of the excellent implementation of maxima. For example, try @@ -161,20 +167,20 @@ sage: eqn = maxima(['a+b*c=1', 'b-a*c=0', 'a+b=5']) sage: s = eqn.solve('[a,b,c]'); s - [[a = -(sqrt(79)*%i-11)/4,b = (sqrt(79)*%i+9)/4, c = (sqrt(79)*%i+1)/10], [a = (sqrt(79)*%i+11)/4,b = -(sqrt(79)*%i-9)/4, c = -(sqrt(79)*%i-1)/10]] + [[a = -...(sqrt(79)*%i-11)/4...,b = (sqrt(79)*%i+9)/4, c = (sqrt(79)*%i+1)/10], [a = (sqrt(79)*%i+11)/4,b = -...(sqrt(79)*%i-9)/4..., c = -...(sqrt(79)*%i-1)/10...]] Here is an example of solving an algebraic equation:: sage: maxima('x^2+y^2=1').solve('y') [y = -sqrt(1-x^2),y = sqrt(1-x^2)] sage: maxima('x^2 + y^2 = (x^2 - y^2)/sqrt(x^2 + y^2)').solve('y') - [y = -sqrt(((-y^2)-x^2)*sqrt(y^2+x^2)+x^2), y = sqrt(((-y^2)-x^2)*sqrt(y^2+x^2)+x^2)] + [y = -sqrt((...-y^2...-x^2)*sqrt(y^2+x^2)+x^2), y = sqrt((...-y^2...-x^2)*sqrt(y^2+x^2)+x^2)] You can even nicely typeset the solution in latex:: sage: latex(s) - \left[ \left[ a=-{{\sqrt{79}\,i-11}\over{4}} , b={{\sqrt{79}\,i+9 }\over{4}} , c={{\sqrt{79}\,i+1}\over{10}} \right] , \left[ a={{ \sqrt{79}\,i+11}\over{4}} , b=-{{\sqrt{79}\,i-9}\over{4}} , c=-{{ \sqrt{79}\,i-1}\over{10}} \right] \right] + \left[ \left[ a=-...{{\sqrt{79}\,i-11}\over{4}}... , b={{...\sqrt{79}\,i+9...}\over{4}} , c={{\sqrt{79}\,i+1}\over{10}} \right] , \left[ a={{...\sqrt{79}\,i+11}\over{4}} , b=-...{{\sqrt{79}\,i-9...}\over{4}}... , c=-...{{...\sqrt{79}\,i-1}\over{10}}... \right] \right] To have the above appear onscreen via ``xdvi``, type ``view(s)``. (TODO: For OS X should create pdf output @@ -200,7 +206,7 @@ sage: f.diff('x') k*x^3*%e^(k*x)*sin(w*x)+3*x^2*%e^(k*x)*sin(w*x)+w*x^3*%e^(k*x) *cos(w*x) sage: f.integrate('x') - (((k*w^6+3*k^3*w^4+3*k^5*w^2+k^7)*x^3 +(3*w^6+3*k^2*w^4-3*k^4*w^2-3*k^6)*x^2+((-18*k*w^4)-12*k^3*w^2+6*k^5)*x-6*w^4 +36*k^2*w^2-6*k^4) *%e^(k*x)*sin(w*x) +(((-w^7)-3*k^2*w^5-3*k^4*w^3-k^6*w)*x^3 +(6*k*w^5+12*k^3*w^3+6*k^5*w)*x^2+(6*w^5-12*k^2*w^3-18*k^4*w)*x-24*k*w^3 +24*k^3*w) *%e^(k*x)*cos(w*x)) /(w^8+4*k^2*w^6+6*k^4*w^4+4*k^6*w^2+k^8) + (((k*w^6+3*k^3*w^4+3*k^5*w^2+k^7)*x^3 +(3*w^6+3*k^2*w^4-3*k^4*w^2-3*k^6)*x^2+(...-...18*k*w^4)-12*k^3*w^2+6*k^5)*x-6*w^4 +36*k^2*w^2-6*k^4) *%e^(k*x)*sin(w*x) +((...-w^7...-3*k^2*w^5-3*k^4*w^3-k^6*w)*x^3...+(6*k*w^5+12*k^3*w^3+6*k^5*w)*x^2...+(6*w^5-12*k^2*w^3-18*k^4*w)*x-24*k*w^3 +24*k^3*w) *%e^(k*x)*cos(w*x)) /(w^8+4*k^2*w^6+6*k^4*w^4+4*k^6*w^2+k^8) :: @@ -234,7 +240,7 @@ sage: A.eigenvalues() [[0,4],[3,1]] sage: A.eigenvectors() - [[[0,4],[3,1]],[[[1,0,0,-4],[0,1,0,-2],[0,0,1,-4/3]],[[1,2,3,4]]]] + [[[0,4],[3,1]],[[[1,0,0,-4],[0,1,0,-2],[0,0,1,-...4/3...]],[[1,2,3,4]]]] We can also compute the echelon form in Sage:: @@ -287,12 +293,12 @@ :: sage: maxima("laplace(diff(x(t),t,2),t,s)") - (-%at('diff(x(t),t,1),t = 0))+s^2*'laplace(x(t),t,s)-x(0)*s + ...-...%at('diff(x(t),t,1),t = 0))+s^2*'laplace(x(t),t,s)-x(0)*s It is difficult to read some of these without the 2d representation:: - sage: print(maxima("laplace(diff(x(t),t,2),t,s)")) + sage: print(maxima("laplace(diff(x(t),t,2),t,s)")) # not tested - depends on maxima version ! d ! 2 (- -- (x(t))! ) + s laplace(x(t), t, s) - x(0) s @@ -396,7 +402,7 @@ sage: g = maxima('exp(3*%i*x)/(6*%i) + exp(%i*x)/(2*%i) + c') sage: latex(g) - -{{i\,e^{3\,i\,x}}\over{6}}-{{i\,e^{i\,x}}\over{2}}+c + -...{{i\,e^{3\,i\,x}}\over{6}}...-{{i\,e^{i\,x}}\over{2}}+c Long Input ---------- @@ -622,11 +628,6 @@ def _start(self): sage: m.is_running() True - Test that we can use more than 256MB RAM (see :trac:`6772`):: - - sage: a = maxima(10)^(10^5) - sage: b = a^600 # long time -- about 10-15 seconds - """ Expect._start(self) self._sendline(r":lisp (defun tex-derivative (x l r) (tex (if $derivabbrev (tex-dabbrev x) (tex-d x '\\partial)) l r lop rop ))") @@ -634,9 +635,6 @@ def _start(self): # Don't use ! for factorials (#11539) self._sendline(":lisp (remprop 'mfactorial 'grind)") - # Remove limit on the max heapsize (since otherwise it defaults - # to 256MB with ECL). - self._sendline(":lisp (ext:set-limit 'ext:heap-size 0)") self._eval_line('0;') # set random seed @@ -692,7 +690,7 @@ def _expect_expr(self, expr=None, timeout=None): sage: maxima.assume('a>0') [a > 0] sage: maxima('integrate(1/(x^3*(a+b*x)^(1/3)),x)') - (-(b^2*log((b*x+a)^(2/3)+a^(1/3)*(b*x+a)^(1/3)+a^(2/3)))/(9*a^(7/3))) +(2*b^2*atan((2*(b*x+a)^(1/3)+a^(1/3))/(sqrt(3)*a^(1/3))))/(3^(3/2)*a^(7/3)) +(2*b^2*log((b*x+a)^(1/3)-a^(1/3)))/(9*a^(7/3)) +(4*b^2*(b*x+a)^(5/3)-7*a*b^2*(b*x+a)^(2/3)) /(6*a^2*(b*x+a)^2-12*a^3*(b*x+a)+6*a^4) + ...-...(b^2*log((b*x+a)^(2/3)+a^(1/3)*(b*x+a)^(1/3)+a^(2/3)))/(9*a^(7/3))) +(2*b^2*atan((2*(b*x+a)^(1/3)+a^(1/3))/(sqrt(3)*a^(1/3))))/(3^(3/2)*a^(7/3)) +(2*b^2*log((b*x+a)^(1/3)-a^(1/3)))/(9*a^(7/3)) +(4*b^2*(b*x+a)^(5/3)-7*a*b^2*(b*x+a)^(2/3)) /(6*a^2*(b*x+a)^2-12*a^3*(b*x+a)+6*a^4) sage: maxima('integrate(x^n,x)') Traceback (most recent call last): ... @@ -889,7 +887,7 @@ def _batch(self, s, batchload=True): sage: maxima._batch('10003;',batchload=False) '...batch...10003...' """ - filename = '%s-%s'%(self._local_tmpfile(),randrange(2147483647)) + filename = '%s-%s' % (self._local_tmpfile(),randrange(2147483647)) F = open(filename, 'w') F.write(s) F.close() @@ -899,13 +897,13 @@ def _batch(self, s, batchload=True): tmp_to_use = filename if batchload: - cmd = 'batchload("%s");'%tmp_to_use + cmd = 'batchload("%s");' % tmp_to_use else: - cmd = 'batch("%s");'%tmp_to_use + cmd = 'batch("%s");' % tmp_to_use r = randrange(2147483647) s = str(r+1) - cmd = "%s1+%s;\n"%(cmd,r) + cmd = "%s1+%s;\n" % (cmd,r) self._sendline(cmd) self._expect_expr(s) @@ -971,7 +969,7 @@ def _error_msg(self, cmd, out): Maxima ERROR: Principal Value """ - raise TypeError("Error executing code in Maxima\nCODE:\n\t%s\nMaxima ERROR:\n\t%s"%(cmd, out.replace('-- an error. To debug this try debugmode(true);',''))) + raise TypeError("Error executing code in Maxima\nCODE:\n\t%s\nMaxima ERROR:\n\t%s" % (cmd, out.replace('-- an error. To debug this try debugmode(true);',''))) ########################################### # Direct access to underlying lisp interpreter. @@ -991,7 +989,7 @@ def lisp(self, cmd): 19 ( """ - self._eval_line(':lisp %s\n""'%cmd, allow_use_file=False, + self._eval_line(':lisp %s\n""' % cmd, allow_use_file=False, wait_for_prompt=False, reformat=False, error_check=False) self._expect_expr('(%i)') return self._before() @@ -1018,7 +1016,7 @@ def set(self, var, value): """ if not isinstance(value, str): raise TypeError - cmd = '%s : %s$'%(var, value.rstrip(';')) + cmd = '%s : %s$' % (var, value.rstrip(';')) if len(cmd) > self.__eval_using_file_cutoff: self._batch(cmd, batchload=True) else: @@ -1198,7 +1196,7 @@ def display2d(self, onscreen=True): P = self.parent() with gc_disabled(): P._eval_line('display2d : true$') - s = P._eval_line('disp(%s)$'%self.name(), reformat=False) + s = P._eval_line('disp(%s)$' % self.name(), reformat=False) P._eval_line('display2d : false$') s = s.strip('\r\n') diff --git a/src/sage/interfaces/maxima_abstract.py b/src/sage/interfaces/maxima_abstract.py index cc1d88160bb..9fe624a7f02 100644 --- a/src/sage/interfaces/maxima_abstract.py +++ b/src/sage/interfaces/maxima_abstract.py @@ -131,7 +131,7 @@ def chdir(self, dir): sage: maxima.chdir('/') """ - self.lisp('(ext::cd "%s")'%dir) + self.lisp('(ext::cd "%s")' % dir) ########################################### # Interactive help @@ -291,7 +291,7 @@ def completions(self, s, verbose=True): # create NAME-IMPL, without the leading $). This causes # name-impl to show up in $APROPOS. We remove it. # https://sourceforge.net/p/maxima/bugs/3643/ - cmd_list = self._eval_line('apropos("%s")'%s, error_check=False) + cmd_list = self._eval_line('apropos("%s")' % s, error_check=False) cmd_list = cmd_list.replace(' ', '').replace('\n', '').replace('\\ - ','-').replace('\\-','-') cmd_list = [x for x in cmd_list[1:-1].split(',') if x[0] != '?' and not x.endswith('-impl')] return [x for x in cmd_list if x.find(s) == 0] @@ -322,7 +322,7 @@ def _commands(self, verbose=True): return self.__commands except AttributeError: self.__commands = sum( - [self.completions(chr(65+n), verbose=verbose)+ + [self.completions(chr(65+n), verbose=verbose) + self.completions(chr(97+n), verbose=verbose) for n in range(26)], []) return self.__commands @@ -746,12 +746,12 @@ def plot2d_parametric(self, r, var, trange, nticks=50, options=None): """ tmin = trange[0] tmax = trange[1] - cmd = "plot2d([parametric, %s, %s, [%s, %s, %s], [nticks, %s]]"%( \ - r[0], r[1], var, tmin, tmax, nticks) + cmd = "plot2d([parametric, %s, %s, [%s, %s, %s], [nticks, %s]]" % ( + r[0], r[1], var, tmin, tmax, nticks) if options is None: cmd += ")" else: - cmd += ", %s)"%options + cmd += ", %s)" % options self(cmd) def plot3d(self, *args): @@ -826,12 +826,12 @@ def plot3d_parametric(self, r, vars, urange, vrange, options=None): umax = urange[1] vmin = vrange[0] vmax = vrange[1] - cmd = 'plot3d([%s, %s, %s], [%s, %s, %s], [%s, %s, %s]'%( + cmd = 'plot3d([%s, %s, %s], [%s, %s, %s], [%s, %s, %s]' % ( r[0], r[1], r[2], vars[0], umin, umax, vars[1], vmin, vmax) if options is None: cmd += ')' else: - cmd += ', %s)'%options + cmd += ', %s)' % options self(cmd) def de_solve(self, de, vars, ics=None): @@ -856,23 +856,23 @@ def de_solve(self, de, vars, ics=None): sage: maxima.de_solve('diff(y,x,2) + 3*x = y', ['x','y']) y = %k1*%e^x+%k2*%e^-x+3*x sage: maxima.de_solve('diff(y,x) + 3*x = y', ['x','y']) - y = (%c-3*((-x)-1)*%e^-x)*%e^x + y = (%c-3*(...-x...-1)*%e^-x)*%e^x sage: maxima.de_solve('diff(y,x) + 3*x = y', ['x','y'],[1,1]) - y = -%e^-1*(5*%e^x-3*%e*x-3*%e) + y = -...%e^-1*(5*%e^x-3*%e*x-3*%e)... """ if not isinstance(vars, str): - str_vars = '%s, %s'%(vars[1], vars[0]) + str_vars = '%s, %s' % (vars[1], vars[0]) else: str_vars = vars - self.eval('depends(%s)'%str_vars) + self.eval('depends(%s)' % str_vars) m = self(de) - a = 'ode2(%s, %s)'%(m.name(), str_vars) + a = 'ode2(%s, %s)' % (m.name(), str_vars) if ics is not None: if len(ics) == 3: - cmd = "ic2("+a+",%s=%s,%s=%s,diff(%s,%s)=%s);"%(vars[0],ics[0], vars[1],ics[1], vars[1], vars[0], ics[2]) + cmd = "ic2("+a+",%s=%s,%s=%s,diff(%s,%s)=%s);" % (vars[0],ics[0], vars[1],ics[1], vars[1], vars[0], ics[2]) return self(cmd) if len(ics) == 2: - return self("ic1("+a+",%s=%s,%s=%s);"%(vars[0],ics[0], vars[1],ics[1])) + return self("ic1("+a+",%s=%s,%s=%s);" % (vars[0],ics[0], vars[1],ics[1])) return self(a+";") def de_solve_laplace(self, de, vars, ics=None): @@ -921,10 +921,10 @@ def de_solve_laplace(self, de, vars, ics=None): if not (ics is None): d = len(ics) for i in range(0,d-1): - ic = 'atvalue(diff(%s(%s), %s, %s), %s = %s, %s)'%( + ic = 'atvalue(diff(%s(%s), %s, %s), %s = %s, %s)' % ( vars[1], vars[0], vars[0], i, vars[0], ics[0], ics[1+i]) self.eval(ic) - return self('desolve(%s, %s(%s))'%(de, vars[1], vars[0])) + return self('desolve(%s, %s(%s))' % (de, vars[1], vars[0])) def solve_linear(self, eqns,vars): """ @@ -947,17 +947,17 @@ def solve_linear(self, eqns,vars): """ eqs = "[" for i in range(len(eqns)): - if i<len(eqns)-1: - eqs = eqs + eqns[i]+"," - if i==len(eqns)-1: - eqs = eqs + eqns[i]+"]" + if i < len(eqns) - 1: + eqs = eqs + eqns[i] + "," + if i == len(eqns) - 1: + eqs = eqs + eqns[i] + "]" vrs = "[" for i in range(len(vars)): - if i<len(vars)-1: - vrs = vrs + vars[i]+"," - if i==len(vars)-1: - vrs = vrs + vars[i]+"]" - return self('linsolve(%s, %s)'%(eqs, vrs)) + if i < len(vars) - 1: + vrs = vrs + vars[i] + "," + if i == len(vars) - 1: + vrs = vrs + vars[i] + "]" + return self('linsolve(%s, %s)' % (eqs, vrs)) def unit_quadratic_integer(self, n): r""" @@ -1026,14 +1026,13 @@ def plot_list(self, ptsx, ptsy, options=None): sage: opts='[gnuplot_preamble, "set nokey"], [gnuplot_term, ps], [gnuplot_out_file, "zeta.eps"]' sage: maxima.plot_list(zeta_ptsx, zeta_ptsy, opts) # not tested """ - cmd = 'plot2d([discrete,%s, %s]'%(ptsx, ptsy) + cmd = 'plot2d([discrete,%s, %s]' % (ptsx, ptsy) if options is None: cmd += ')' else: - cmd += ', %s)'%options + cmd += ', %s)' % options self(cmd) - def plot_multilist(self, pts_list, options=None): r""" Plots a list of list of points pts_list=[pts1,pts2,...,ptsn], @@ -1075,7 +1074,7 @@ def plot_multilist(self, pts_list, options=None): for i in range(n): if i < n-1: cmd = cmd+'[discrete,'+str(pts_list[i][0])+','+str(pts_list[i][1])+'],' - if i==n-1: + if i == n-1: cmd = cmd+'[discrete,'+str(pts_list[i][0])+','+str(pts_list[i][1])+']]' if options is None: self('plot2d('+cmd+')') @@ -1183,11 +1182,11 @@ def _richcmp_(self, other, op): # are what Maxima needs P = self.parent() try: - if P.eval("is (%s < %s)"%(self.name(), other.name())) == P._true_symbol(): + if P.eval("is (%s < %s)" % (self.name(), other.name())) == P._true_symbol(): return rich_to_bool(op, -1) - elif P.eval("is (%s > %s)"%(self.name(), other.name())) == P._true_symbol(): + elif P.eval("is (%s > %s)" % (self.name(), other.name())) == P._true_symbol(): return rich_to_bool(op, 1) - elif P.eval("is (%s = %s)"%(self.name(), other.name())) == P._true_symbol(): + elif P.eval("is (%s = %s)" % (self.name(), other.name())) == P._true_symbol(): return rich_to_bool(op, 0) except TypeError: pass @@ -1573,8 +1572,9 @@ def integral(self, var='x', min=None, max=None): :: - sage: f = maxima('exp(x^2)').integral('x',0,1); f - -(sqrt(%pi)*%i*erf(%i))/2 + sage: f = maxima('exp(x^2)').integral('x',0,1) + sage: f.sage() + -1/2*I*sqrt(pi)*erf(I) sage: f.numer() 1.46265174590718... """ @@ -1608,7 +1608,7 @@ def __float__(self): try: return float(repr(self.numer())) except ValueError: - raise TypeError("unable to coerce '%s' to float"%repr(self)) + raise TypeError("unable to coerce '%s' to float" % repr(self)) def __len__(self): """ @@ -1625,7 +1625,7 @@ def __len__(self): 6 """ P = self._check_valid() - return int(P.eval('length(%s)'%self.name())) + return int(P.eval('length(%s)' % self.name())) def dot(self, other): """ @@ -1646,7 +1646,7 @@ def dot(self, other): """ P = self._check_valid() Q = P(other) - return P('%s . %s'%(self.name(), Q.name())) + return P('%s . %s' % (self.name(), Q.name())) def __getitem__(self, n): r""" @@ -1678,7 +1678,7 @@ def __getitem__(self, n): """ n = int(n) if n < 0 or n >= len(self): - raise IndexError("n = (%s) must be between %s and %s"%(n, 0, len(self)-1)) + raise IndexError("n = (%s) must be between %s and %s" % (n, 0, len(self)-1)) # If you change the n+1 to n below, better change __iter__ as well. return InterfaceElement.__getitem__(self, n+1) @@ -1740,7 +1740,7 @@ def comma(self, args): """ self._check_valid() P = self.parent() - return P('%s, %s'%(self.name(), args)) + return P('%s, %s' % (self.name(), args)) def _latex_(self): r""" @@ -1846,13 +1846,13 @@ def _matrix_(self, R): [ 3 3/2 1 3/4] [ 4 2 4/3 1] """ - from sage.matrix.all import MatrixSpace + from sage.matrix.matrix_space import MatrixSpace self._check_valid() P = self.parent() - nrows = int(P.eval('length(%s)'%self.name())) + nrows = int(P.eval('length(%s)' % self.name())) if nrows == 0: return MatrixSpace(R, 0, 0)(0) - ncols = int(P.eval('length(%s[1])'%self.name())) + ncols = int(P.eval('length(%s[1])' % self.name())) M = MatrixSpace(R, nrows, ncols) s = self.str().replace('matrix','').replace(',',"','").\ replace("]','[","','").replace('([',"['").replace('])',"']") @@ -1920,12 +1920,12 @@ def _operation(self, operation, other=None): P = self._check_valid() if other is None: - cmd = '%s %s'%(operation, self._name) + cmd = '%s %s' % (operation, self._name) elif isinstance(other, P._object_function_class()): fself = P.function('', repr(self)) return fself._operation(operation, other) else: - cmd = '%s %s %s'%(self._name, operation, other._name) + cmd = '%s %s %s' % (self._name, operation, other._name) try: return P.new(cmd) except Exception as msg: @@ -2026,8 +2026,8 @@ def __call__(self, *args): """ P = self._check_valid() if len(args) == 1: - args = '(%s)'%args - return P('%s%s'%(self.name(), args)) + args = '(%s)' % args + return P('%s%s' % (self.name(), args)) def _repr_(self): """ @@ -2132,7 +2132,7 @@ def integral(self, var): """ var = str(var) P = self._check_valid() - f = P('integrate(%s(%s), %s)'%(self.name(), + f = P('integrate(%s(%s), %s)' % (self.name(), self.arguments(split=False), var)) args = self.arguments() diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index c9ca5e30939..211018e52cc 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -77,6 +77,26 @@ sage: bar == foo True +TESTS: + +Check our workaround for a race in ecl works, see :trac:`26968`. +We use a temporary `MAXIMA_USERDIR` so it's empty; we place it +in `DOT_SAGE` since we expect it to have more latency than `/tmp`. + + sage: import tempfile, subprocess + sage: tmpdir = tempfile.TemporaryDirectory(dir=DOT_SAGE) + sage: _ = subprocess.run(['sage', '-c', # long time + ....: f''' + ....: import os + ....: os.environ["MAXIMA_USERDIR"] = "{tmpdir.name}" + ....: if not os.fork(): + ....: import sage.interfaces.maxima_lib + ....: else: + ....: import sage.interfaces.maxima_lib + ....: os.wait() + ....: ''']) + sage: tmpdir.cleanup() + """ # **************************************************************************** @@ -94,6 +114,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.structure.element import Expression from sage.symbolic.ring import SR from sage.libs.ecl import EclObject, ecl_eval @@ -113,10 +134,29 @@ else: ecl_eval("(require 'maxima)") ecl_eval("(in-package :maxima)") -ecl_eval("(setq $nolabels t))") -ecl_eval("(defvar *MAXIMA-LANG-SUBDIR* NIL)") ecl_eval("(set-locale-subdir)") -ecl_eval("(set-pathnames)") + +# This workaround has to happen before any call to (set-pathnames). +# To be safe please do not call anything other than +# (set-locale-subdir) before this block. +try: + ecl_eval("(set-pathnames)") +except RuntimeError: + # Recover from :trac:`26968` by creating `*maxima-objdir*` here. + # This cannot be done before calling `(set-pathnames)` since + # `*maxima-objdir*` is computed there. + # We use python `os.makedirs()` which is immune to the race. + # Using `(ensure-directories-exist ...)` in lisp would be + # subject to the same race condition and since `*maxima-objdir*` + # has multiple components this is quite plausible to happen. + maxima_objdir = ecl_eval("*maxima-objdir*").python()[1:-1] + import os + os.makedirs(maxima_objdir, exist_ok=True) + # Call `(set-pathnames)` again to complete its job. + ecl_eval("(set-pathnames)") + +ecl_eval("(initialize-runtime-globals)") +ecl_eval("(setq $nolabels t))") ecl_eval("(defun add-lineinfo (x) x)") ecl_eval('(defun principal nil (cond ($noprincipal (diverg)) ((not pcprntd) (merror "Divergent Integral"))))') ecl_eval("(remprop 'mfactorial 'grind)") # don't use ! for factorials (#11539) @@ -182,14 +222,14 @@ # See trac # 6818. init_code.append('nolabels : true') for l in init_code: - ecl_eval("#$%s$"%l) + ecl_eval("#$%s$" % l) # To get more debug information uncomment the next line # should allow to do this through a method #ecl_eval("(setf *standard-output* original-standard-output)") # This is the main function (ECL object) used for evaluation # This returns an EclObject -maxima_eval=ecl_eval(""" +maxima_eval = ecl_eval(""" (defun maxima-eval( form ) (with-$error (meval form))) """) @@ -200,27 +240,27 @@ # Here we define several useful ECL/Maxima objects # The Maxima string function can change the structure of its input #maxprint=EclObject("$STRING") -maxprint=EclObject(r"""(defun mstring-for-sage (form) +maxprint = EclObject(r"""(defun mstring-for-sage (form) (coerce (mstring form) 'string))""").eval() -meval=EclObject("MEVAL") -msetq=EclObject("MSETQ") -mlist=EclObject("MLIST") -mequal=EclObject("MEQUAL") -cadadr=EclObject("CADADR") - -max_integrate=EclObject("$INTEGRATE") -max_sum=EclObject("$SUM") -max_simplify_sum=EclObject("$SIMPLIFY_SUM") -max_prod=EclObject("$PRODUCT") -max_simplify_prod=EclObject("$SIMPLIFY_PRODUCT") -max_ratsimp=EclObject("$RATSIMP") -max_limit=EclObject("$LIMIT") -max_tlimit=EclObject("$TLIMIT") -max_plus=EclObject("$PLUS") -max_minus=EclObject("$MINUS") -max_use_grobner=EclObject("$USE_GROBNER") -max_to_poly_solve=EclObject("$TO_POLY_SOLVE") -max_at=EclObject("%AT") +meval = EclObject("MEVAL") +msetq = EclObject("MSETQ") +mlist = EclObject("MLIST") +mequal = EclObject("MEQUAL") +cadadr = EclObject("CADADR") + +max_integrate = EclObject("$INTEGRATE") +max_sum = EclObject("$SUM") +max_simplify_sum = EclObject("$SIMPLIFY_SUM") +max_prod = EclObject("$PRODUCT") +max_simplify_prod = EclObject("$SIMPLIFY_PRODUCT") +max_ratsimp = EclObject("$RATSIMP") +max_limit = EclObject("$LIMIT") +max_tlimit = EclObject("$TLIMIT") +max_plus = EclObject("$PLUS") +max_minus = EclObject("$MINUS") +max_use_grobner = EclObject("$USE_GROBNER") +max_to_poly_solve = EclObject("$TO_POLY_SOLVE") +max_at = EclObject("%AT") def stdout_to_string(s): r""" @@ -244,7 +284,7 @@ def stdout_to_string(s): '2\n\n' """ return ecl_eval(r"""(with-output-to-string (*standard-output*) - (maxima-eval #$%s$))"""%s).python()[1:-1] + (maxima-eval #$%s$))""" % s).python()[1:-1] def max_to_string(s): r""" @@ -265,7 +305,8 @@ def max_to_string(s): """ return maxprint(s).python()[1:-1] -my_mread=ecl_eval(""" + +my_mread = ecl_eval(""" (defun my-mread (cmd) (caddr (mread (make-string-input-stream cmd)))) """) @@ -286,7 +327,7 @@ def parse_max_string(s): sage: parse_max_string('1+1') <ECL: ((MPLUS) 1 1)> """ - return my_mread('"%s;"'%s) + return my_mread('"%s;"' % s) class MaximaLib(MaximaAbstract): """ @@ -417,9 +458,9 @@ def _eval_line(self, line, locals=None, reformat=True, **kwds): """ result = '' while line: - ind_dollar=line.find("$") - ind_semi=line.find(";") - if ind_dollar == -1 or (ind_semi >=0 and ind_dollar > ind_semi): + ind_dollar = line.find("$") + ind_semi = line.find(";") + if ind_dollar == -1 or (ind_semi >= 0 and ind_dollar > ind_semi): if ind_semi == -1: statement = line line = '' @@ -427,7 +468,7 @@ def _eval_line(self, line, locals=None, reformat=True, **kwds): statement = line[:ind_semi] line = line[ind_semi+1:] if statement: - result = ((result + '\n') if result else '') + max_to_string(maxima_eval("#$%s$"%statement)) + result = ((result + '\n') if result else '') + max_to_string(maxima_eval("#$%s$" % statement)) else: statement = line[:ind_dollar] line = line[ind_dollar+1:] @@ -485,7 +526,7 @@ def set(self, var, value): """ if not isinstance(value, str): raise TypeError - cmd = '%s : %s$'%(var, value.rstrip(';')) + cmd = '%s : %s$' % (var, value.rstrip(';')) self.eval(cmd) def clear(self, var): @@ -509,8 +550,8 @@ def clear(self, var): 'xxxxx' """ try: - self.eval('kill(%s)$'%var) - ecl_eval("(unintern '$%s)"%var) + self.eval('kill(%s)$' % var) + ecl_eval("(unintern '$%s)" % var) except (TypeError, AttributeError): pass @@ -531,7 +572,7 @@ def get(self, var): sage: maxima_lib.get('xxxxx') '2' """ - s = self.eval('%s;'%var) + s = self.eval('%s;' % var) return s def _create(self, value, name=None): @@ -576,7 +617,7 @@ def _create(self, value, name=None): name = self._next_var_name() if name is None else name try: if isinstance(value,EclObject): - maxima_eval([[msetq],cadadr("#$%s$#$"%name),value]) + maxima_eval([[msetq],cadadr("#$%s$#$" % name),value]) else: self.set(name, value) except RuntimeError as error: @@ -897,8 +938,15 @@ def sr_limit(self, expr, v, a, dir=None): e sage: limit(f,x = 5) 7776/3125 - sage: limit(f,x = 1.2) + + Domain to real, a regression in 5.46.0, see https://sf.net/p/maxima/bugs/4138 :: + + sage: maxima_calculus.eval("domain:real") + ... + sage: limit(f,x = 1.2).n() 2.06961575467... + sage: maxima_calculus.eval("domain:complex"); + ... sage: var('a') a sage: limit(x^a,x=0) @@ -910,7 +958,7 @@ def sr_limit(self, expr, v, a, dir=None): for more details) Is a positive, negative or zero? sage: assume(a>0) - sage: limit(x^a,x=0) + sage: limit(x^a,x=0) # random - not needed for maxima 5.46.0 Traceback (most recent call last): ... ValueError: Computation failed ... @@ -1003,7 +1051,7 @@ def _missing_assumption(self,errstr): k = errstr.find(' ',jj+1) outstr = "Computation failed since Maxima requested additional constraints; using the 'assume' command before evaluation *may* help (example of legal syntax is 'assume("\ - + errstr[jj+1:k] +">0)', see `assume?` for more details)\n" + errstr + + errstr[jj+1:k] + ">0)', see `assume?` for more details)\n" + errstr outstr = outstr.replace('_SAGE_VAR_','') raise ValueError(outstr) @@ -1062,7 +1110,7 @@ def ecl(self): try: return self._ecl except AttributeError: - self._ecl=maxima_eval("#$%s$"%self._name) + self._ecl = maxima_eval("#$%s$" % self._name) return self._ecl def to_poly_solve(self,vars,options=""): @@ -1088,10 +1136,10 @@ def to_poly_solve(self,vars,options=""): [[x == pi*z...]] """ if options.find("use_grobner=true") != -1: - cmd=EclObject([[max_to_poly_solve], self.ecl(), sr_to_max(vars), + cmd = EclObject([[max_to_poly_solve], self.ecl(), sr_to_max(vars), [[mequal],max_use_grobner,True]]) else: - cmd=EclObject([[max_to_poly_solve], self.ecl(), sr_to_max(vars)]) + cmd = EclObject([[max_to_poly_solve], self.ecl(), sr_to_max(vars)]) return self.parent()(maxima_eval(cmd)) def display2d(self, onscreen=True): @@ -1118,7 +1166,7 @@ def display2d(self, onscreen=True): self._check_valid() P = self.parent() P._eval_line('display2d : true$') - s = stdout_to_string('disp(%s)'%self.name()) + s = stdout_to_string('disp(%s)' % self.name()) #s = P._eval_line('disp(%s)$'%self.name()) P._eval_line('display2d : false$') s = s.strip('\r\n') @@ -1164,19 +1212,21 @@ def reduce_load_MaximaLib(): import sage.rings.real_double import sage.symbolic.expression import sage.symbolic.integration.integral + +from sage.rings.number_field.number_field_element_base import NumberFieldElement_base from sage.symbolic.operators import FDerivativeOperator, add_vararg, mul_vararg -car=EclObject("car") -cdr=EclObject("cdr") -caar=EclObject("caar") -cadr=EclObject("cadr") -cddr=EclObject("cddr") -caddr=EclObject("caddr") -caaadr=EclObject("caaadr") -cadadr=EclObject("cadadr") -meval=EclObject("meval") -NIL=EclObject("NIL") -lisp_length=EclObject("length") +car = EclObject("car") +cdr = EclObject("cdr") +caar = EclObject("caar") +cadr = EclObject("cadr") +cddr = EclObject("cddr") +caddr = EclObject("caddr") +caaadr = EclObject("caaadr") +cadadr = EclObject("cadadr") +meval = EclObject("meval") +NIL = EclObject("NIL") +lisp_length = EclObject("length") # Dictionaries for standard operators sage_op_dict = { @@ -1229,12 +1279,13 @@ def sage_rat(x,y): """ return x/y -mplus=EclObject("MPLUS") -mtimes=EclObject("MTIMES") -rat=EclObject("RAT") -max_op_dict[mplus]=add_vararg -max_op_dict[mtimes]=mul_vararg -max_op_dict[rat]=sage_rat + +mplus = EclObject("MPLUS") +mtimes = EclObject("MTIMES") +rat = EclObject("RAT") +max_op_dict[mplus] = add_vararg +max_op_dict[mtimes] = mul_vararg +max_op_dict[rat] = sage_rat # Here we build dictionaries for operators needing special conversions. @@ -1314,9 +1365,9 @@ def mqapply_to_sage(expr): mlist_to_sage(car(cdr(cdr(cdr(expr))))), max_to_sr(car(cdr(cdr(cdr(cdr(expr))))))) else: - op=max_to_sr(cadr(expr)) - max_args=cddr(expr) - args=[max_to_sr(a) for a in max_args] + op = max_to_sr(cadr(expr)) + max_args = cddr(expr) + args = [max_to_sr(a) for a in max_args] return op(*args) def mdiff_to_sage(expr): @@ -1385,13 +1436,13 @@ def max_at_to_sage(expr): sage: max_at_to_sage(a.ecl()) f(1, y, z) """ - arg=max_to_sr(expr.cadr()) - subsarg=caddr(expr) - if caar(subsarg)==mlist: - subsvalues=dict( (v.lhs(),v.rhs()) for v in max_to_sr(subsarg)) + arg = max_to_sr(expr.cadr()) + subsarg = caddr(expr) + if caar(subsarg) == mlist: + subsvalues = dict( (v.lhs(),v.rhs()) for v in max_to_sr(subsarg)) else: - v=max_to_sr(subsarg) - subsvalues=dict([(v.lhs(),v.rhs())]) + v = max_to_sr(subsarg) + subsvalues = dict([(v.lhs(),v.rhs())]) return SR(arg).subs(subsvalues) def dummy_integrate(expr): @@ -1475,24 +1526,24 @@ def max_pochhammer_to_sage(expr): max_pochhammer: max_pochhammer_to_sage } -special_sage_to_max={ +special_sage_to_max = { sage.functions.log.polylog : lambda N,X : [[mqapply],[[max_li, max_array],N],X], sage.functions.gamma.psi1 : lambda X : [[mqapply],[[max_psi, max_array],0],X], sage.functions.gamma.psi2 : lambda N,X : [[mqapply],[[max_psi, max_array],N],X], - sage.functions.log.lambert_w : lambda N,X : [[max_lambert_w], X] if N==EclObject(0) else [[mqapply],[[max_lambert_w, max_array],N],X], + sage.functions.log.lambert_w : lambda N,X : [[max_lambert_w], X] if N == EclObject(0) else [[mqapply],[[max_lambert_w, max_array],N],X], sage.functions.log.harmonic_number : lambda N,X : [[max_harmo],X,N], sage.functions.hypergeometric.hypergeometric : lambda A, B, X : [[mqapply],[[max_hyper, max_array],lisp_length(A.cdr()),lisp_length(B.cdr())],A,B,X] } # Dictionaries for symbols -sage_sym_dict={} -max_sym_dict={} +sage_sym_dict = {} +max_sym_dict = {} # Generic conversion functions -max_i=EclObject("$%I") +max_i = EclObject("$%I") def pyobject_to_max(obj): r""" Convert a (simple) Python object into a Maxima object. @@ -1523,9 +1574,11 @@ def pyobject_to_max(obj): """ if isinstance(obj,sage.rings.rational.Rational): return EclObject(obj) if (obj.denom().is_one()) else EclObject([[rat], obj.numer(),obj.denom()]) - elif isinstance(obj,sage.rings.number_field.number_field_element_quadratic.NumberFieldElement_quadratic) and obj.parent().defining_polynomial().list() == [1,0,1]: - re, im = obj.list() - return EclObject([[mplus], pyobject_to_max(re), [[mtimes], pyobject_to_max(im), max_i]]) + elif isinstance(obj, NumberFieldElement_base): + from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_quadratic + if isinstance(obj, NumberFieldElement_quadratic) and obj.parent().defining_polynomial().list() == [1,0,1]: + re, im = obj.list() + return EclObject([[mplus], pyobject_to_max(re), [[mtimes], pyobject_to_max(im), max_i]]) return EclObject(obj) # This goes from SR to EclObject @@ -1575,9 +1628,8 @@ def sr_to_max(expr): # For that, we should change the API of the functions there # (we need to have access to op, not only to expr.operands() if isinstance(op, FDerivativeOperator): - from sage.symbolic.ring import is_SymbolicVariable args = expr.operands() - if (not all(is_SymbolicVariable(v) for v in args) or + if (not all(isinstance(v, Expression) and v.is_symbol() for v in args) or len(args) != len(set(args))): # An evaluated derivative of the form f'(1) is not a # symbolic variable, yet we would like to treat it @@ -1587,13 +1639,13 @@ def sr_to_max(expr): # _symbol0=1. See trac #12796. Note that we cannot use # SR.temp_var here since two conversions of the same # expression have to be equal. - temp_args = [SR.symbol("_symbol%s"%i) for i in range(len(args))] + temp_args = [SR.symbol("_symbol%s" % i) for i in range(len(args))] f = sr_to_max(op.function()(*temp_args)) params = op.parameter_set() deriv_max = [[mdiff],f] for i in set(params): deriv_max.extend([sr_to_max(temp_args[i]), EclObject(params.count(i))]) - at_eval=sr_to_max([temp_args[i]==args[i] for i in range(len(args))]) + at_eval = sr_to_max([temp_args[i] == args[i] for i in range(len(args))]) return EclObject([[max_at],deriv_max,at_eval]) f = sr_to_max(op.function()(*args)) @@ -1633,6 +1685,7 @@ def sr_to_max(expr): except TypeError: return maxima(expr).ecl() + # This goes from EclObject to SR from sage.symbolic.expression import symbol_table max_to_pynac_table = symbol_table['maxima'] @@ -1665,7 +1718,7 @@ def max_to_sr(expr): True """ if expr.consp(): - op_max=caar(expr) + op_max = caar(expr) if op_max in special_max_to_sage: return special_max_to_sage[op_max](expr) if op_max not in max_op_dict: @@ -1679,8 +1732,8 @@ def max_to_sr(expr): op = sage_expr.operator() if op in sage_op_dict: raise RuntimeError("Encountered operator mismatch in maxima-to-sr translation") - max_op_dict[op_max]=op - sage_op_dict[op]=op_max + max_op_dict[op_max] = op + sage_op_dict[op] = op_max else: op = max_op_dict[op_max] max_args = cdr(expr) diff --git a/src/sage/interfaces/mupad.py b/src/sage/interfaces/mupad.py index 00034b4af16..956de696806 100644 --- a/src/sage/interfaces/mupad.py +++ b/src/sage/interfaces/mupad.py @@ -264,11 +264,11 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, global seq seq += 1 - START = '__start__(%s+1)'%seq - END = '__end__(%s+1)'%seq - line = '%s; %s; %s;'%(START, line, END) - START = '__start__(%s)'%(seq+1) - END = '__end__(%s)'%(seq+1) + START = '__start__(%s+1)' % seq + END = '__end__(%s+1)' % seq + line = '%s; %s; %s;' % (START, line, END) + START = '__start__(%s)' % (seq+1) + END = '__end__(%s)' % (seq+1) E = self._expect E.sendline(line) @@ -276,7 +276,7 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, z = E.before i = z.find(START) if i == -1: - raise RuntimeError("%s\nError evaluating code in MuPAD"%z) + raise RuntimeError("%s\nError evaluating code in MuPAD" % z) z = z[i+len(START)+2:] z = z.rstrip().rstrip(END).rstrip('"').rstrip().strip('\n').strip('\r').strip('\n').replace('\\\r\n','') i = z.find('Error: ') @@ -294,7 +294,7 @@ def cputime(self, t=None): if t is None: return float(str(self('time()')))/1000 else: - return float(str(self('time() - %s'%float(t))))/1000 + return float(str(self('time() - %s' % float(t))))/1000 def set(self, var, value): """ @@ -306,7 +306,7 @@ def set(self, var, value): sage: mupad.get('a').strip() # optional - mupad '4' """ - cmd = '%s:=%s:'%(var,value) + cmd = '%s:=%s:' % (var,value) out = self.eval(cmd) i = out.find('Error: ') if i != -1: @@ -323,7 +323,7 @@ def get(self, var): '4' """ - s = self.eval('%s'%var) + s = self.eval('%s' % var) i = s.find('=') return s[i+1:] @@ -425,7 +425,7 @@ def completions(self, string, strip=False): sage: mupad.completions('linal') # optional - mupad ['linalg'] """ - res = self.eval('_pref(Complete)("%s")'%string).strip() + res = self.eval('_pref(Complete)("%s")' % string).strip() res = res.replace('\n', '').split(',') res = [s.strip().strip('"') for s in res] res = [s for s in res if not s.endswith('::')] @@ -507,7 +507,7 @@ def __getattr__(self, attrname): else: return self.__dict__[attrname] name = self._name+"::"+attrname - if P.eval('type(%s)'%name) == "DOM_DOMAIN": + if P.eval('type(%s)' % name) == "DOM_DOMAIN": return MupadElement(P, name) else: return MupadFunctionElement(self._obj, name) @@ -524,7 +524,6 @@ def _tab_completion(self): res = P.completions(self._name+"::", strip=True) return res if res != [] else P._tab_completion() - def __call__(self, *args): """ EXAMPLES:: @@ -539,7 +538,7 @@ def __call__(self, *args): s[1, 1, 1] """ P = self._obj.parent() - if P.eval('type(%s)'%(self._obj.name())).strip() == "DOM_DOMAIN": + if P.eval('type(%s)' % (self._obj.name())).strip() == "DOM_DOMAIN": return P.function_call(self._name, list(args)) else: return P.function_call(self._name, [self._obj] + list(args)) @@ -573,8 +572,8 @@ def __getattr__(self, attrname): name = self._name + "::" + attrname try: - if P.eval('type(%s::%s)'%(self.name(),attrname)).strip() == "DOM_DOMAIN": - return P.new("%s::%s"%(self.name(),attrname)) + if P.eval('type(%s::%s)' % (self.name(),attrname)).strip() == "DOM_DOMAIN": + return P.new("%s::%s" % (self.name(),attrname)) else: return MupadFunctionElement(self, name) except RuntimeError as err: @@ -606,7 +605,7 @@ def _latex_(self): """ self._check_valid() P = self.parent() - s = P._eval_line('generate::TeX(%s)'%self.name()) + s = P._eval_line('generate::TeX(%s)' % self.name()) s = s.replace('\\\\','\\').strip().strip('"') return s @@ -639,6 +638,7 @@ def __len__(self): """ return mupad.nops(self) + # An instance mupad = Mupad() diff --git a/src/sage/interfaces/mwrank.py b/src/sage/interfaces/mwrank.py index ae65d0ffea0..35d73277109 100644 --- a/src/sage/interfaces/mwrank.py +++ b/src/sage/interfaces/mwrank.py @@ -67,6 +67,7 @@ def Mwrank(options="", server=None, server_tmpdir=None): instances[options] = weakref.ref(X) return X + import re # regex matching '[a1,a2,a3,a4,a6]', no spaces, each ai a possibly signed integer AINVS_LIST_RE = re.compile(r'\[[+-]?(\d+)(,[+-]?\d+){4}]') @@ -87,7 +88,8 @@ def validate_mwrank_input(s): OUTPUT: - For valid input, a string of the form '[a1,a2,a3,a4,a6]'. For invalid input a ValueError is raised. + For valid input, a string of the form '[a1,a2,a3,a4,a6]'. + For invalid input a :class:`ValueError` is raised. EXAMPLES: @@ -124,7 +126,7 @@ def validate_mwrank_input(s): """ if isinstance(s,(list,tuple)): from sage.rings.integer_ring import ZZ - if len(s)!=5: + if len(s) != 5: raise ValueError("%s is not valid input to mwrank (should have 5 entries)" % s) try: ai = [ZZ(a) for a in s] diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index 81d48cf3c10..a1a9ba50582 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -294,18 +294,18 @@ def _eval_line(self, line, reformat=True, allow_use_file=False, return '' if self._expect is None: self._start() - if allow_use_file and len(line)>3000: + if allow_use_file and len(line) > 3000: return self._eval_line_using_file(line) try: E = self._expect # debug # self._synchronize(cmd='1+%s\n') - verbose("in = '%s'"%line,level=3) + verbose("in = '%s'" % line,level=3) E.sendline(line) E.expect(self._prompt) out = bytes_to_str(E.before) # debug - verbose("out = '%s'"%out,level=3) + verbose("out = '%s'" % out,level=3) except EOF: if self._quit_string() in line: return '' @@ -321,7 +321,7 @@ def _eval_line(self, line, reformat=True, allow_use_file=False, return '' def _keyboard_interrupt(self): - print("CntrlC: Interrupting %s..."%self) + print("CntrlC: Interrupting %s..." % self) if self._restart_on_ctrlc: try: self._expect.close(force=1) @@ -411,7 +411,7 @@ def set(self, var, value): cmd = '%s=%s;' % (var, value) out = self.eval(cmd) if out.find("error") != -1 or out.find("Error") != -1: - raise TypeError("Error executing code in Octave\nCODE:\n\t%s\nOctave ERROR:\n\t%s"%(cmd, out)) + raise TypeError("Error executing code in Octave\nCODE:\n\t%s\nOctave ERROR:\n\t%s" % (cmd, out)) def get(self, var): """ @@ -423,7 +423,7 @@ def get(self, var): sage: octave.get('x') # optional - octave ' 2' """ - s = self.eval('%s'%var) + s = self.eval('%s' % var) i = s.find('=') return s[i+1:] @@ -508,7 +508,7 @@ def solve_linear_system(self, A, b): m = A.nrows() if m != len(b): raise ValueError("dimensions of A and b must be compatible") - from sage.matrix.all import MatrixSpace + from sage.matrix.matrix_space import MatrixSpace from sage.rings.rational_field import QQ MS = MatrixSpace(QQ,m,1) b = MS(list(b)) # converted b to a "column vector" @@ -578,11 +578,11 @@ def de_system_plot(self, f, ics, trange): """ eqn1 = f[0].replace('x','x(1)').replace('y','x(2)') eqn2 = f[1].replace('x','x(1)').replace('y','x(2)') - fcn = "function xdot = f(x,t) xdot(1) = %s; xdot(2) = %s; endfunction"%(eqn1, eqn2) + fcn = "function xdot = f(x,t) xdot(1) = %s; xdot(2) = %s; endfunction" % (eqn1, eqn2) self.eval(fcn) - x0_eqn = "x0 = [%s; %s]"%(ics[0], ics[1]) + x0_eqn = "x0 = [%s; %s]" % (ics[0], ics[1]) self.eval(x0_eqn) - t_eqn = "t = linspace(%s, %s, 200)'"%(trange[0], trange[1]) + t_eqn = "t = linspace(%s, %s, 200)'" % (trange[0], trange[1]) self.eval(t_eqn) x_eqn = 'x = lsode("f",x0,t);' self.eval(x_eqn) @@ -707,7 +707,7 @@ def _matrix_(self, R=None): if self.iscomplex(): w = [[to_complex(x,R) for x in row] for row in w] - from sage.matrix.all import MatrixSpace + from sage.matrix.matrix_space import MatrixSpace return MatrixSpace(R, nrows, ncols)(w) def _vector_(self, R=None): @@ -808,6 +808,7 @@ def _sage_(self): else: raise NotImplementedError('octave type is not recognized') + # An instance octave = Octave() diff --git a/src/sage/interfaces/primecount.py b/src/sage/interfaces/primecount.py deleted file mode 100644 index 518378e1fe2..00000000000 --- a/src/sage/interfaces/primecount.py +++ /dev/null @@ -1,5 +0,0 @@ -from sage.misc.superseded import deprecation -deprecation(32894, "the module sage.interfaces.primecount is deprecated - use primecountpy.primecount instead") -from sage.misc.lazy_import import lazy_import -lazy_import("primecountpy.primecount", ['phi', 'nth_prime', 'prime_pi', 'prime_pi_128'], - deprecation=(32894, "the module sage.interfaces.primecount is deprecated - use primecountpy.primecount instead")) diff --git a/src/sage/interfaces/process.pyx b/src/sage/interfaces/process.pyx index ea90d5b0de4..016de82a30f 100644 --- a/src/sage/interfaces/process.pyx +++ b/src/sage/interfaces/process.pyx @@ -2,15 +2,15 @@ Utilities for subprocess management """ -#***************************************************************************** +# *************************************************************************** # Copyright (C) 2015 Jeroen Demeyer <jdemeyer@cage.ugent.be> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** import errno import signal @@ -163,7 +163,7 @@ cdef class ContainChildren(): if exc[0] is not None: # Exception was raised exitcode = self.exceptcode if not self.silent: - sys.stderr.write("Exception raised by child process with pid=%s:\n"%pid) + sys.stderr.write("Exception raised by child process with pid=%s:\n" % pid) import traceback traceback.print_exception(*exc) sys.stdout.flush() @@ -245,9 +245,7 @@ def terminate(sp, interval=1, signals=[signal.SIGTERM, signal.SIGKILL]): sage: t = walltime() - t0 sage: t <= 4.0 or t True - """ - try: yield sp finally: diff --git a/src/sage/interfaces/psage.py b/src/sage/interfaces/psage.py index 0979ef60a62..b64a0b15c5f 100644 --- a/src/sage/interfaces/psage.py +++ b/src/sage/interfaces/psage.py @@ -74,7 +74,7 @@ def _repr_(self): A running non-blocking (parallel) instance of Sage (number ...) """ - return 'A running non-blocking (parallel) instance of Sage (number %s)'%(self._number) + return 'A running non-blocking (parallel) instance of Sage (number %s)' % (self._number) def _unlock(self): self._locked = False @@ -124,7 +124,7 @@ def __del__(self): pass if not (self._expect is None): - cmd = 'kill -9 %s'%self._expect.pid + cmd = 'kill -9 %s' % self._expect.pid os.system(cmd) def eval(self, x, strip=True, **kwds): @@ -145,7 +145,6 @@ def eval(self, x, strip=True, **kwds): except ExceptionPexpect: return "<<currently executing code>>" - def get(self, var): """ Get the value of the variable var. @@ -159,7 +158,7 @@ def set(self, var, value): """ Set the variable var to the given value. """ - cmd = '%s=%s'%(var,value) + cmd = '%s=%s' % (var,value) self._send_nowait(cmd) time.sleep(0.02) diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index fb850931b91..b6b657515bc 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -660,7 +660,8 @@ def _qepcad_cmd(memcells=None): memcells_arg = '+N%s' % memcells else: memcells_arg = '' - return "env qe=%s qepcad %s"%(SAGE_LOCAL, memcells_arg) + return "env qe=%s qepcad %s" % (SAGE_LOCAL, memcells_arg) + _command_info_cache = None @@ -834,7 +835,7 @@ def __init__(self, formula, self._cell_cache = {} if verbose: - logfile=sys.stdout + logfile = sys.stdout varlist = None if vars is not None: @@ -1319,14 +1320,14 @@ def _function_call(self, name, args): name = name.replace('_', '-') args = [str(_) for _ in args] pre_phase = self.phase() - result = self._eval_line('%s %s'%(name, ' '.join(args))) + result = self._eval_line('%s %s' % (name, ' '.join(args))) post_phase = self.phase() if len(result) and post_phase != 'EXITED': return AsciiArtString(result) if pre_phase != post_phase: if post_phase == 'EXITED' and name != 'quit': return self.answer() - return AsciiArtString("QEPCAD object has moved to phase '%s'"%post_phase) + return AsciiArtString("QEPCAD object has moved to phase '%s'" % post_phase) def _format_cell_index(a): """ @@ -2427,7 +2428,7 @@ def __init__(self, parent, lines): index = (index,) self._index = index - self._dimension = sum([r&1 for r in index]) + self._dimension = sum([r & 1 for r in index]) if 'Level ' in line: self._level = int(line.split(':')[1].strip()) if 'Number of children' in line: diff --git a/src/sage/interfaces/qsieve.py b/src/sage/interfaces/qsieve.py index aff8ef1c165..94764b7f76a 100644 --- a/src/sage/interfaces/qsieve.py +++ b/src/sage/interfaces/qsieve.py @@ -1,289 +1,4 @@ -""" -Interface to Bill Hart's Quadratic Sieve -""" +from sage.misc.superseded import deprecated_function_alias +import sage.libs.flint.qsieve -import os -import subprocess as sp - -import sage.rings.integer - -from sage.cpython.string import bytes_to_str -from sage.misc.temporary_file import tmp_dir - - -def qsieve(n, block=True, time=False, verbose=False): - r""" - Run Hart's quadratic sieve and return the distinct proper factors - of the integer n that it finds. - - CONDITIONS: - - The conditions for the quadratic sieve to work are as follows: - - - No small factors - - Not a perfect power - - Not prime - - If any of these fails, the sieve will also. - - - INPUT: - - - n -- an integer with at least 40 digits - - block -- (default: True) if True, you must wait until the - sieve computation is complete before using Sage further. - If False, Sage will run while the sieve computation - runs in parallel. If q is the returned object, use - q.quit() to terminate a running factorization. - - time -- (default: False) if True, time the command using - the UNIX "time" command (which you might have to install). - - verbose -- (default: False) if True, print out verbose - logging information about what happened during - the Sieve run (for non-blocking Sieve, verbose information - is always available via the log() method.) - - OUTPUT: - - - list -- a list of the distinct proper factors of n found - - str -- the time in cpu seconds that the computation took, as given - by the command line time command. (If time is False, - this is always an empty string.) - - EXAMPLES:: - - sage: k = 19; n = next_prime(10^k)*next_prime(10^(k+1)) - sage: factor(n) # (currently) uses PARI - 10000000000000000051 * 100000000000000000039 - sage: v, t = qsieve(n, time=True) # uses qsieve; optional - time - sage: v # optional - time - [10000000000000000051, 100000000000000000039] - sage: t # random; optional - time - '0.36 real 0.19 user 0.00 sys' - """ - Z = sage.rings.integer.Integer - n = Z(n) - if len(str(n)) < 40: - raise ValueError("n must have at least 40 digits") - if block: - return qsieve_block(n, time, verbose) - else: - return qsieve_nonblock(n, time) - -def qsieve_block(n, time, verbose=False): - """ - Compute the factorization of n using Hart's quadratic Sieve - blocking until complete. - """ - - cmd = ['QuadraticSieve'] - if time: - cmd = ['time'] + cmd - - env = os.environ.copy() - env['TMPDIR'] = tmp_dir('qsieve') - p = sp.Popen(cmd, env=env, stdout=sp.PIPE, stderr=sp.STDOUT, - stdin=sp.PIPE, encoding='latin1') - out, err = p.communicate(str(n)) - z = data_to_list(out, n, time=time) - if verbose: - print(z[-1]) - return z[:2] - -def data_to_list(out, n, time): - """ - Convert output of Hart's sieve and n to a list and time. - - INPUT: - - - out -- snapshot of text output of Hart's QuadraticSieve program - - n -- the integer being factored - - OUTPUT: - - - list -- proper factors found so far - - str -- time information - """ - i = out.find('FACTORS:') - if i == -1: - return [], '', out # whole thing - else: - verbose = out[:i] - out = out[i+len('FACTORS:')+1:].strip() - if time: - w = out.split('\n') - for i in range(len(w)): - if 'user' in w[i]: - break - if i < len(w): - t = w[i].strip() - out = '\n'.join(w[j] for j in range(i)) - else: - t = '' - else: - t = '' - Z = sage.rings.integer.Integer - v = out.split() - v = sorted(set([Z(m) for m in v if Z(m) != n])) - return v, t, verbose - - -from sage.interfaces.sagespawn import SageSpawn -import pexpect -from . import quit -class qsieve_nonblock: - """ - A non-blocking version of Hart's quadratic sieve. - - The sieve starts running when you create the object, but you can - still use Sage in parallel. - - EXAMPLES:: - - sage: k = 19; n = next_prime(10^k)*next_prime(10^(k+1)) - sage: q = qsieve(n, block=False, time=True) # optional - time - sage: q # random output; optional - time - Proper factors so far: [] - sage: q # random output; optional - time - ([10000000000000000051, 100000000000000000039], '0.21') - sage: q.list() # random output; optional - time - [10000000000000000051, 100000000000000000039] - sage: q.time() # random output; optional - time - '0.21' - - sage: q = qsieve(next_prime(10^20)*next_prime(10^21), block=False) - sage: q # random output - Proper factors so far: [100000000000000000039, 1000000000000000000117] - sage: q # random output - [100000000000000000039, 1000000000000000000117] - """ - def __init__(self, n, time): - self._n = n - if time: - cmd = 'time QuadraticSieve' - else: - cmd = 'QuadraticSieve' - env = os.environ.copy() - env['TMPDIR'] = tmp_dir('qsieve') - self._p = SageSpawn(cmd, env=env) - quit.register_spawned_process(self._p.pid, 'QuadraticSieve') - self._p.sendline(str(self._n)+'\n\n\n') - self._done = False - self._out = '' - self._time = '' - self._do_time = time - - def n(self): - """ - Return the integer that is being factored. - """ - return self._n - - def pid(self): - """ - Return the PIN id of the QuadraticSieve process (actually - of the time process that spawns the sieve process). - """ - return self._p.pid - - def done(self): - """ - Return True if the sieve process has completed. - """ - return self._done - - def __repr__(self): - """ - Return a text representation of self. - """ - if self._done: - if hasattr(self, '_killed') and self._killed: - return "Factorization was terminated early." - v = data_to_list(self._get(), self._n, self._do_time) - if self._do_time: - return str(v[:2]) - else: - return str(v[0]) - else: - return 'Proper factors so far: %s'%self.list() - - def cputime(self): - """ - Return the time in seconds (as a string) that it took to - factor n, or return '?' if the factorization has not - completed or the time is unknown. - """ - if not self._do_time: - raise ValueError("you have to start the sieve with the option time=True in order to get timing information") - try: - return data_to_list(self._get(), self._n, self._do_time)[1] - except IndexError: - return '?' - time = cputime - - def log(self): - """ - Return all output of running the sieve so far. - """ - return self._get() - - def __getitem__(self, i): - """ - Return the i-th factor (in sorted order) found so far. - """ - return self.list()[i] - - def __len__(self): - """ - Return the number of factors found so far. If q is the - Sieve object, type len(q) to see the number of factors. - """ - return len(self.list()) - - def list(self): - """ - Return a list of the factors found so far, as Sage - integers. - """ - try: - return data_to_list(self._get(), self._n, self._do_time)[0] - except IndexError: - return [] - - def quit(self): - """ - Terminate the QuadraticSieve process, in case you want - to give up on computing this factorization. - - EXAMPLES:: - - sage: n = next_prime(2^310)*next_prime(2^300) - sage: qs = qsieve(n, block=False) - sage: qs - Proper factors so far: [] - sage: qs.quit() - sage: qs - Factorization was terminated early. - """ - pid = self.pid() - os.killpg(int(pid),9) - #self._p.close() - self._killed = True - self._done = True - - def _get(self, timeout=0.1): - """ - Used internally to get information about what has been - computed so far. - """ - if self._done: - return self._out - e = self._p - try: - e.expect('xxx', timeout=timeout) - except pexpect.TIMEOUT: - pass - except pexpect.EOF: - self._done = True - self._p.close() - self._out += bytes_to_str(e.before) - return self._out +qsieve = deprecated_function_alias(1, sage.libs.flint.qsieve.qsieve) diff --git a/src/sage/interfaces/quit.py b/src/sage/interfaces/quit.py index 3bbd3ae24d3..575646f2365 100644 --- a/src/sage/interfaces/quit.py +++ b/src/sage/interfaces/quit.py @@ -45,7 +45,7 @@ def register_spawned_process(pid, cmd=''): # This is safe, since only this process writes to this file. try: with open(sage_spawned_process_file(), 'a') as o: - o.write('%s %s\n'%(pid, cmd)) + o.write('%s %s\n' % (pid, cmd)) except IOError: pass else: @@ -149,7 +149,7 @@ def invalidate_all(): sage: b (invalid PARI/GP interpreter object -- The pari session in which this object was defined is no longer running.) - However the maxima and gp sessions should still work out, though with their state reset: + However the maxima and gp sessions should still work out, though with their state reset:: sage: a = maxima(2); b = gp(3) sage: a, b diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index e195936bc2d..068e65a2096 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -66,13 +66,14 @@ sage: x.var() # optional - rpy2 [1] 53.853 - sage: x.sort() # optional - rpy2 + sage: # optional - rpy2 + sage: x.sort() [1] 3.1 5.6 6.4 10.4 21.7 - sage: x.min() # optional - rpy2 + sage: x.min() [1] 3.1 - sage: x.max() # optional - rpy2 + sage: x.max() [1] 21.7 - sage: x # optional - rpy2 + sage: x [1] 10.4 5.6 3.1 6.4 21.7 sage: r(-17).sqrt() # optional - rpy2 @@ -92,42 +93,44 @@ sage: r.seq(length=10, from_=-1, by=.2) # optional - rpy2 [1] -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 - sage: x = r([10.4,5.6,3.1,6.4,21.7]) # optional - rpy2 - sage: x.rep(2) # optional - rpy2 + sage: # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]) + sage: x.rep(2) [1] 10.4 5.6 3.1 6.4 21.7 10.4 5.6 3.1 6.4 21.7 - sage: x.rep(times=2) # optional - rpy2 + sage: x.rep(times=2) [1] 10.4 5.6 3.1 6.4 21.7 10.4 5.6 3.1 6.4 21.7 - sage: x.rep(each=2) # optional - rpy2 + sage: x.rep(each=2) [1] 10.4 10.4 5.6 5.6 3.1 3.1 6.4 6.4 21.7 21.7 Missing Values:: - sage: na = r('NA') # optional - rpy2 - sage: z = r([1,2,3,na]) # optional - rpy2 - sage: z # optional - rpy2 + sage: # optional - rpy2 + sage: na = r('NA') + sage: z = r([1,2,3,na]) + sage: z [1] 1 2 3 NA - sage: ind = r.is_na(z) # optional - rpy2 - sage: ind # optional - rpy2 + sage: ind = r.is_na(z) + sage: ind [1] FALSE FALSE FALSE TRUE - sage: zero = r(0) # optional - rpy2 - sage: zero / zero # optional - rpy2 + sage: zero = r(0) + sage: zero / zero [1] NaN - sage: inf = r('Inf') # optional - rpy2 - sage: inf-inf # optional - rpy2 + sage: inf = r('Inf') + sage: inf-inf [1] NaN - sage: r.is_na(inf) # optional - rpy2 + sage: r.is_na(inf) [1] FALSE - sage: r.is_na(inf-inf) # optional - rpy2 + sage: r.is_na(inf-inf) [1] TRUE - sage: r.is_na(zero/zero) # optional - rpy2 + sage: r.is_na(zero/zero) [1] TRUE - sage: r.is_na(na) # optional - rpy2 + sage: r.is_na(na) [1] TRUE - sage: r.is_nan(inf-inf) # optional - rpy2 + sage: r.is_nan(inf-inf) [1] TRUE - sage: r.is_nan(zero/zero) # optional - rpy2 + sage: r.is_nan(zero/zero) [1] TRUE - sage: r.is_nan(na) # optional - rpy2 + sage: r.is_nan(na) [1] FALSE @@ -145,13 +148,14 @@ sage: x['!is.na(self)'] # optional - rpy2 [1] 10.4 5.6 3.1 6.4 21.7 - sage: x = r([10.4,5.6,3.1,6.4,21.7,na]); x # optional - rpy2 + sage: # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7,na]); x [1] 10.4 5.6 3.1 6.4 21.7 NA - sage: (x+1)['(!is.na(self)) & self>0'] # optional - rpy2 + sage: (x+1)['(!is.na(self)) & self>0'] [1] 11.4 6.6 4.1 7.4 22.7 - sage: x = r([10.4,-2,3.1,-0.5,21.7,na]); x # optional - rpy2 + sage: x = r([10.4,-2,3.1,-0.5,21.7,na]); x [1] 10.4 -2.0 3.1 -0.5 21.7 NA - sage: (x+1)['(!is.na(self)) & self>0'] # optional - rpy2 + sage: (x+1)['(!is.na(self)) & self>0'] [1] 11.4 4.1 0.5 22.7 Distributions:: @@ -187,16 +191,17 @@ Or you get a dictionary to be able to access all the information:: - sage: rs = r.summary(r.c(1,4,3,4,3,2,5,1)) # optional - rpy2 - sage: rs # optional - rpy2 + sage: # optional - rpy2 + sage: rs = r.summary(r.c(1,4,3,4,3,2,5,1)) + sage: rs Min. 1st Qu. Median Mean 3rd Qu. Max. 1.000 1.750 3.000 2.875 4.000 5.000 - sage: d = rs._sage_() # optional - rpy2 - sage: d['DATA'] # optional - rpy2 + sage: d = rs._sage_() + sage: d['DATA'] [1, 1.75, 3, 2.875, 4, 5] - sage: d['_Names'] # optional - rpy2 + sage: d['_Names'] ['Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.'] - sage: d['_r_class'] # optional - rpy2 + sage: d['_r_class'] ['summaryDefault', 'table'] It is also possible to access the plotting capabilities of R @@ -282,7 +287,7 @@ lazy_import("rpy2.robjects.help", "Package") lazy_import("rpy2", "rinterface") -COMMANDS_CACHE = '%s/r_commandlist.sobj'%DOT_SAGE +COMMANDS_CACHE = '%s/r_commandlist.sobj' % DOT_SAGE #there is a mirror network, but lets take #1 for now RRepositoryURL = "http://cran.r-project.org/" @@ -346,13 +351,14 @@ def _setup_r_to_sage_converter(): The conversion can handle "not a number", infinity, imaginary values and missing values:: - sage: r(-17).sqrt().sage() # optional - rpy2 + sage: # optional - rpy2 + sage: r(-17).sqrt().sage() nan - sage: r('-17+0i').sqrt().sage() # optional - rpy2 + sage: r('-17+0i').sqrt().sage() 4.123105625617661j - sage: r('NA').sage() # optional - rpy2 + sage: r('NA').sage() NA - sage: inf = r('Inf'); inf.sage() # optional - rpy2 + sage: inf = r('Inf'); inf.sage() inf Character Vectors are represented by regular python arrays:: @@ -504,30 +510,33 @@ def _lazy_init(self): Initialization happens on eval:: - sage: my_r = R() # optional - rpy2 - sage: my_r._initialized # optional - rpy2 + sage: # optional - rpy2 + sage: my_r = R() + sage: my_r._initialized False - sage: my_r(42) # indirect doctest # optional - rpy2 + sage: my_r(42) # indirect doctest [1] 42 - sage: my_r._initialized # optional - rpy2 + sage: my_r._initialized True - And on package import: + And on package import:: - sage: my_r = R() # optional - rpy2 - sage: my_r._initialized # optional - rpy2 + sage: # optional - rpy2 + sage: my_r = R() + sage: my_r._initialized False - sage: my_r.library('grid') # optional - rpy2 - sage: my_r._initialized # optional - rpy2 + sage: my_r.library('grid') + sage: my_r._initialized True - And when fetching help pages: + And when fetching help pages:: - sage: my_r = R() # optional - rpy2 - sage: my_r._initialized # optional - rpy2 + sage: # optional - rpy2 + sage: my_r = R() + sage: my_r._initialized False - sage: _ = my_r.help('c') # optional - rpy2 - sage: my_r._initialized # optional - rpy2 + sage: _ = my_r.help('c') + sage: my_r._initialized True """ if not self._initialized: @@ -587,8 +596,8 @@ def _start(self): # pager needed to replace help view from less to printout # option device= is for plotting, is set to x11, NULL would be better? self.eval('options(pager="cat",device="png")') - self.eval('options(repos="%s")'%RRepositoryURL) - self.eval('options(CRAN="%s")'%RRepositoryURL) + self.eval('options(repos="%s")' % RRepositoryURL) + self.eval('options(CRAN="%s")' % RRepositoryURL) # don't abort on errors, just raise them! # necessary for non-interactive execution @@ -611,15 +620,16 @@ def png(self, *args, **kwds): EXAMPLES:: - sage: filename = tmp_filename() + '.png' # optional - rpy2 - sage: r.png(filename='"%s"'%filename) # optional -- rgraphics # optional - rpy2 + sage: # optional - rpy2 + sage: filename = tmp_filename() + '.png' + sage: r.png(filename='"%s"'%filename) # optional - rgraphics NULL - sage: x = r([1,2,3]) # optional - rpy2 - sage: y = r([4,5,6]) # optional - rpy2 - sage: r.plot(x,y) # This saves to filename, but is not viewable from command line; optional -- rgraphics # optional - rpy2 + sage: x = r([1,2,3]) + sage: y = r([4,5,6]) + sage: r.plot(x,y) # optional - rgraphics null device 1 - sage: import os; os.unlink(filename) # We remove the file for doctesting; optional -- rgraphics # optional - rpy2 + sage: import os; os.unlink(filename) # optional - rgraphics We want to make sure that we actually can view R graphics, which happens differently on different platforms:: @@ -673,8 +683,8 @@ def install_packages(self, package_name): ... Please restart Sage in order to use 'aaMI'. """ - cmd = """options(repos="%s"); install.packages("%s")"""%(RRepositoryURL, package_name) - os.system("time echo '%s' | R --vanilla"%cmd) + cmd = """options(repos="%s"); install.packages("%s")""" % (RRepositoryURL, package_name) + os.system("time echo '%s' | R --vanilla" % cmd) print("Please restart Sage in order to use '%s'." % package_name) def _repr_(self): @@ -724,7 +734,6 @@ def __getattr__(self, attrname): raise AttributeError("Attribute {} is not allowed to start with an underscore.".format(attrname)) return RFunction(self, attrname) - def _read_in_file_command(self, filename): r""" Return the R command (as a string) to read in a file named @@ -735,7 +744,7 @@ def _read_in_file_command(self, filename): sage: r._read_in_file_command('file.txt') # optional - rpy2 'file=file("file.txt",open="r")\nsource(file)' """ - return 'file=file("%s",open="r")\nsource(file)'%filename + return 'file=file("%s",open="r")\nsource(file)' % filename def read(self, filename): r""" @@ -744,12 +753,13 @@ def read(self, filename): EXAMPLES:: - sage: filename = tmp_filename() # optional - rpy2 - sage: f = open(filename, 'w') # optional - rpy2 - sage: _ = f.write('a <- 2+2\n') # optional - rpy2 - sage: f.close() # optional - rpy2 - sage: r.read(filename) # optional - rpy2 - sage: r.get('a') # optional - rpy2 + sage: # optional - rpy2 + sage: filename = tmp_filename() + sage: f = open(filename, 'w') + sage: _ = f.write('a <- 2+2\n') + sage: f.close() + sage: r.read(filename) + sage: r.get('a') '[1] 4' """ self.eval( self._read_in_file_command(filename) ) @@ -778,7 +788,7 @@ def _source(self, s): """ if s[-2:] == "()": s = s[-2:] - return self.eval('%s'%s) + return self.eval('%s' % s) def source(self, s): """ @@ -805,12 +815,13 @@ def version(self): EXAMPLES:: - sage: r.version() # not tested # optional - rpy2 + sage: # optional - rpy2 + sage: r.version() # not tested ((3, 0, 1), 'R version 3.0.1 (2013-05-16)') - sage: rint, rstr = r.version() # optional - rpy2 - sage: rint[0] >= 3 # optional - rpy2 + sage: rint, rstr = r.version() + sage: rint[0] >= 3 True - sage: rstr.startswith('R version') # optional - rpy2 + sage: rstr.startswith('R version') True """ major_re = re.compile(r'^major\s*(\d.*?)$', re.M) @@ -880,7 +891,7 @@ def available_packages(self): sage: len(ap) > 20 # optional - internet # optional - rpy2 True """ - p = self.new('available.packages("%s/src/contrib")'%RRepositoryURL) + p = self.new('available.packages("%s/src/contrib")' % RRepositoryURL) s = str(p).splitlines()[1:] v = [x.split()[0].strip("'") for x in s] return v @@ -1060,7 +1071,7 @@ def function_call(self, function, args=None, kwds=None): """ args, kwds = self._convert_args_kwds(args, kwds) self._check_valid_function_name(function) - return self.new("%s(%s)"%(function, ",".join([s.name() for s in args] + + return self.new("%s(%s)" % (function, ",".join([s.name() for s in args] + [self._sage_to_r_name(key)+'='+kwds[key].name() for key in kwds ] ))) def call(self, function_name, *args, **kwds): @@ -1106,7 +1117,7 @@ def set(self, var, value): '[1] 5' """ - cmd = '%s <- %s'%(var,value) + cmd = '%s <- %s' % (var,value) out = self.eval(cmd) def get(self, var): @@ -1125,7 +1136,7 @@ def get(self, var): sage: r.get('a') # optional - rpy2 '[1] 2' """ - return self.eval('%s'%var) + return self.eval('%s' % var) def na(self): """ @@ -1184,7 +1195,7 @@ def _commands(self): if lib.find("package:") != 0: continue #only packages - raw = self('objects("%s")'%lib)._sage_() + raw = self('objects("%s")' % lib)._sage_() #TODO are there others? many of them are shortcuts or #should be done on another level, like selections in lists @@ -1272,15 +1283,16 @@ def plot(self, *args, **kwds): the output device to that file. If this is done in the notebook, it must be done in the same cell as the plot itself:: - sage: filename = tmp_filename() + '.png' # optional - rpy2 - sage: r.png(filename='"%s"'%filename) # Note the double quotes in single quotes!; optional -- rgraphics # optional - rpy2 + sage: # optional - rpy2 + sage: filename = tmp_filename() + '.png' + sage: r.png(filename='"%s"'%filename) # optional - rgraphics NULL - sage: x = r([1,2,3]) # optional - rpy2 - sage: y = r([4,5,6]) # optional - rpy2 - sage: r.plot(x,y) # optional -- rgraphics # optional - rpy2 + sage: x = r([1,2,3]) + sage: y = r([4,5,6]) + sage: r.plot(x,y) # optional - rgraphics null device 1 - sage: import os; os.unlink(filename) # For doctesting, we remove the file; optional -- rgraphics # optional - rpy2 + sage: import os; os.unlink(filename) # optional - rgraphics Please note that for more extensive use of R's plotting capabilities (such as the lattices package), it is advisable @@ -1288,23 +1300,25 @@ def plot(self, *args, **kwds): notebook. The following examples are not tested, because they differ depending on operating system:: - sage: r.X11() # not tested - opens interactive device on systems with X11 support # optional - rpy2 - sage: r.quartz() # not tested - opens interactive device on OSX # optional - rpy2 - sage: r.hist("rnorm(100)") # not tested - makes a plot # optional - rpy2 - sage: r.library("lattice") # not tested - loads R lattice plotting package # optional - rpy2 - sage: r.histogram(x = "~ wt | cyl", data="mtcars") # not tested - makes a lattice plot # optional - rpy2 - sage: r.dev_off() # not tested, turns off the interactive viewer # optional - rpy2 + sage: # not tested, optional - rpy2 + sage: r.X11() + sage: r.quartz() + sage: r.hist("rnorm(100)") + sage: r.library("lattice") + sage: r.histogram(x = "~ wt | cyl", data="mtcars") + sage: r.dev_off() In the notebook, one can use r.png() to open the device, but would need to use the following since R lattice graphics do not automatically print away from the command line:: - sage: filename = tmp_filename() + '.png' # Not needed in notebook, used for doctesting # optional - rpy2 - sage: r.png(filename='"%s"'%filename) # filename not needed in notebook, used for doctesting; optional -- rgraphics # optional - rpy2 + sage: # optional - rpy2 + sage: filename = tmp_filename() + '.png' # Not needed in notebook, used for doctesting + sage: r.png(filename='"%s"'%filename) # optional - rgraphics NULL - sage: r.library("lattice") # optional - rpy2 - sage: r("print(histogram(~wt | cyl, data=mtcars))") # plot should appear; optional -- rgraphics # optional - rpy2 - sage: import os; os.unlink(filename) # We remove the file for doctesting, not needed in notebook; optional -- rgraphics # optional - rpy2 + sage: r.library("lattice") + sage: r("print(histogram(~wt | cyl, data=mtcars))") # optional - rgraphics + sage: import os; os.unlink(filename) # optional - rgraphics """ # We have to define this to override the plot function defined in the # superclass. @@ -1324,7 +1338,6 @@ def eval(self, code, *args, **kwds): self._lazy_init() return str(robjects.r(code)).rstrip() - def _r_to_sage_name(self, s): """ Returns a Sage/Python identifier from an R one. This involves @@ -1339,14 +1352,15 @@ def _r_to_sage_name(self, s): EXAMPLES:: - sage: f = r._r_to_sage_name # optional - rpy2 - sage: f('t.test') # optional - rpy2 + sage: # optional - rpy2 + sage: f = r._r_to_sage_name + sage: f('t.test') 't_test' - sage: f('attr<-') # optional - rpy2 + sage: f('attr<-') 'attr__' - sage: f('parent.env<-') # optional - rpy2 + sage: f('parent.env<-') 'parent_env__' - sage: f('class') # optional - rpy2 + sage: f('class') 'class_' """ from keyword import iskeyword @@ -1362,16 +1376,17 @@ def _sage_to_r_name(self, s): EXAMPLES:: - sage: f = r._sage_to_r_name # optional - rpy2 - sage: f('t_test') # optional - rpy2 + sage: # optional - rpy2 + sage: f = r._sage_to_r_name + sage: f('t_test') 't.test' - sage: f('attr__') # optional - rpy2 + sage: f('attr__') 'attr<-' - sage: f('parent_env__') # optional - rpy2 + sage: f('parent_env__') 'parent.env<-' - sage: r._r_to_sage_name(f('parent_env__')) # optional - rpy2 + sage: r._r_to_sage_name(f('parent_env__')) 'parent_env__' - sage: f('class_') # optional - rpy2 + sage: f('class_') 'class' """ if len(s) > 1 and s[-2:] == "__": @@ -1453,11 +1468,12 @@ def tilde(self, x): EXAMPLES:: - sage: x = r([1,2,3,4,5]) # optional - rpy2 - sage: y = r([3,5,7,9,11]) # optional - rpy2 - sage: a = r.lm( y.tilde(x) ) # lm( y ~ x ) # optional - rpy2 - sage: d = a._sage_() # optional - rpy2 - sage: d['DATA']['coefficients']['DATA'][1] # optional - rpy2 + sage: # optional - rpy2 + sage: x = r([1,2,3,4,5]) + sage: y = r([3,5,7,9,11]) + sage: a = r.lm( y.tilde(x) ) # lm( y ~ x ) + sage: d = a._sage_() + sage: d['DATA']['coefficients']['DATA'][1] 2 """ par = self.parent() @@ -1492,7 +1508,7 @@ def __len__(self): sage: len(x) # optional - rpy2 5 """ - return self.parent()('length(%s)'%self.name()).sage() + return self.parent()('length(%s)' % self.name()).sage() def __getattr__(self, attrname): """ @@ -1507,11 +1523,12 @@ def __getattr__(self, attrname): EXAMPLES:: - sage: x = r([1,2,3]) # optional - rpy2 - sage: length = x.length # optional - rpy2 - sage: type(length) # optional - rpy2 + sage: # optional - rpy2 + sage: x = r([1,2,3]) + sage: length = x.length + sage: type(length) <class 'sage.interfaces.r.RFunctionElement'> - sage: length() # optional - rpy2 + sage: length() [1] 3 """ try: @@ -1537,24 +1554,25 @@ def __getitem__(self, n): EXAMPLES:: - sage: x = r([10.4,5.6,3.1,6.4,21.7]) # optional - rpy2 - sage: x[0] # optional - rpy2 + sage: # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]) + sage: x[0] numeric(0) - sage: x[1] # optional - rpy2 + sage: x[1] [1] 10.4 - sage: x[-1] # optional - rpy2 + sage: x[-1] [1] 5.6 3.1 6.4 21.7 - sage: x[-2] # optional - rpy2 + sage: x[-2] [1] 10.4 3.1 6.4 21.7 - sage: x[-3] # optional - rpy2 + sage: x[-3] [1] 10.4 5.6 6.4 21.7 - sage: x['c(2,3)'] # optional - rpy2 + sage: x['c(2,3)'] [1] 5.6 3.1 - sage: key = r.c(2,3) # optional - rpy2 - sage: x[key] # optional - rpy2 + sage: key = r.c(2,3) + sage: x[key] [1] 5.6 3.1 - sage: m = r.array('1:3',r.c(2,4,2)) # optional - rpy2 - sage: m # optional - rpy2 + sage: m = r.array('1:3',r.c(2,4,2)) + sage: m , , 1 [,1] [,2] [,3] [,4] [1,] 1 3 2 1 @@ -1563,19 +1581,19 @@ def __getitem__(self, n): [,1] [,2] [,3] [,4] [1,] 3 2 1 3 [2,] 1 3 2 1 - sage: m[1,2,2] # optional - rpy2 + sage: m[1,2,2] [1] 2 - sage: m[1,r.c(1,2),1] # optional - rpy2 + sage: m[1,r.c(1,2),1] [1] 1 3 """ P = self._check_valid() if isinstance(n, str): n = n.replace('self', self._name) - return P.new('%s[%s]'%(self._name, n)) + return P.new('%s[%s]' % (self._name, n)) elif parent(n) is P: # the key is RElement itself - return P.new('%s[%s]'%(self._name, n.name())) + return P.new('%s[%s]' % (self._name, n.name())) elif not isinstance(n,tuple): - return P.new('%s[%s]'%(self._name, n)) + return P.new('%s[%s]' % (self._name, n)) else: L = [] for i in range(len(n)): @@ -1583,7 +1601,7 @@ def __getitem__(self, n): L.append(n[i].name()) else: L.append(str(n[i])) - return P.new('%s[%s]'%(self._name, ','.join(L))) + return P.new('%s[%s]' % (self._name, ','.join(L))) def __bool__(self): """ @@ -1595,15 +1613,16 @@ def __bool__(self): EXAMPLES:: - sage: x = r([10.4,5.6,3.1,6.4,21.7]) # optional - rpy2 - sage: bool(x) # optional - rpy2 + sage: # optional - rpy2 + sage: x = r([10.4,5.6,3.1,6.4,21.7]) + sage: bool(x) True - sage: y = r([0,0,0,0]) # optional - rpy2 - sage: bool(y) # optional - rpy2 + sage: y = r([0,0,0,0]) + sage: bool(y) False - sage: bool(r(0)) # optional - rpy2 + sage: bool(r(0)) False - sage: bool(r(1)) # optional - rpy2 + sage: bool(r(1)) True """ return "FALSE" in repr(self == 0) @@ -1627,7 +1646,7 @@ def _comparison(self, other, symbol): """ P = self.parent() other = P(other) - return P('%s %s %s'%(self.name(), symbol, other.name())) + return P('%s %s %s' % (self.name(), symbol, other.name())) def __eq__(self, other): """ @@ -1772,7 +1791,7 @@ def dot_product(self, other): P = self._check_valid() Q = P(other) # the R operator is %*% for matrix multiplication - return P('%s %%*%% %s'%(self.name(), Q.name())) + return P('%s %%*%% %s' % (self.name(), Q.name())) def _sage_(self): r""" @@ -1802,7 +1821,6 @@ def _sage_(self): parsed = robjects.r(self.name()) return parsed - def _latex_(self): r""" Return LaTeX representation of this R object. @@ -2012,6 +2030,7 @@ def is_RElement(x): return isinstance(x, RElement) + # An instance of R r = R() @@ -2027,6 +2046,7 @@ def reduce_load_R(): """ return r + import os def r_console(): """ @@ -2052,12 +2072,13 @@ def r_version(): EXAMPLES:: - sage: r_version() # not tested # optional - rpy2 + sage: # optional - rpy2 + sage: r_version() # not tested ((3, 0, 1), 'R version 3.0.1 (2013-05-16)') - sage: rint, rstr = r_version() # optional - rpy2 - sage: rint[0] >= 3 # optional - rpy2 + sage: rint, rstr = r_version() + sage: rint[0] >= 3 True - sage: rstr.startswith('R version') # optional - rpy2 + sage: rstr.startswith('R version') True """ return r.version() diff --git a/src/sage/interfaces/rubik.py b/src/sage/interfaces/rubik.py index 45857555caa..109a2623c95 100644 --- a/src/sage/interfaces/rubik.py +++ b/src/sage/interfaces/rubik.py @@ -45,18 +45,18 @@ # Can't seem to find consistency in letter ordering # between us and them... These are copied from the source. -optimal_solver_tokens = ["UF", "UR", "UB", "UL", \ - "DF", "DR", "DB", "DL", \ - "FR", "FL", "BR", "BL", \ - "FU", "RU", "BU", "LU", \ - "FD", "RD", "BD", "LD", \ - "RF", "LF", "RB", "LB", \ - "UFR", "URB", "UBL", "ULF", \ - "DRF", "DFL", "DLB", "DBR", \ - "FRU", "RBU", "BLU", "LFU", \ - "RFD", "FLD", "LBD", "BRD", \ - "RUF", "BUR", "LUB", "FUL", \ - "FDR", "LDF", "BDL", "RDB"] +optimal_solver_tokens = ["UF", "UR", "UB", "UL", + "DF", "DR", "DB", "DL", + "FR", "FL", "BR", "BL", + "FU", "RU", "BU", "LU", + "FD", "RD", "BD", "LD", + "RF", "LF", "RB", "LB", + "UFR", "URB", "UBL", "ULF", + "DRF", "DFL", "DLB", "DBR", + "FRU", "RBU", "BLU", "LFU", + "RFD", "FLD", "LBD", "BRD", + "RUF", "BUR", "LUB", "FUL", + "FDR", "LDF", "BDL", "RDB"] # The input format. optimal_solver_format = "UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR" @@ -309,18 +309,17 @@ def format_cube(self, facets): facet_colors[16+i*3] = i return "".join(str(c) for c in facet_colors) - facet_map = [ 1, 2, 3, \ - 4, 0, 5, \ - 6, 7, 8, \ - 9, 10, 11, 17, 18, 19, 25, 26, 27, 33, 34, 35, \ - 12, 0, 13, 20, 0, 21, 28, 0, 29, 36, 0, 37, \ - 14, 15, 16, 22, 23, 24, 30, 31, 32, 38, 39, 40, \ - 41, 42, 43, \ - 44, 0, 45, \ - 46, 47, 48, \ + facet_map = [ 1, 2, 3, + 4, 0, 5, + 6, 7, 8, + 9, 10, 11, 17, 18, 19, 25, 26, 27, 33, 34, 35, + 12, 0, 13, 20, 0, 21, 28, 0, 29, 36, 0, 37, + 14, 15, 16, 22, 23, 24, 30, 31, 32, 38, 39, 40, + 41, 42, 43, + 44, 0, 45, + 46, 47, 48, ] - # to compensate for different face naming rot_map = dict(zip("BLURDF", "ULFRBD")) diff --git a/src/sage/interfaces/sage0.py b/src/sage/interfaces/sage0.py index a43a059e0ec..9eddb7019f7 100644 --- a/src/sage/interfaces/sage0.py +++ b/src/sage/interfaces/sage0.py @@ -159,7 +159,8 @@ def __init__(self, if python: command = 'python -u' prompt = re.compile(b'>>> ') - init_code.append('from sage.all import *') + environment = 'sage.all' + init_code.append(f'from {environment} import *') else: command = ' '.join([ 'sage-ipython', diff --git a/src/sage/interfaces/sagespawn.pyx b/src/sage/interfaces/sagespawn.pyx index 2303d3297bb..6bb9b90e580 100644 --- a/src/sage/interfaces/sagespawn.pyx +++ b/src/sage/interfaces/sagespawn.pyx @@ -10,15 +10,15 @@ AUTHOR: see :trac:`10295`. """ -#***************************************************************************** +# *************************************************************************** # Copyright (C) 2015 Jeroen Demeyer <jdemeyer@cage.ugent.be> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from pexpect import * from ptyprocess import PtyProcess @@ -26,7 +26,7 @@ from ptyprocess import PtyProcess from cpython.ref cimport Py_INCREF from libc.signal cimport * from posix.signal cimport killpg -from posix.unistd cimport getpid, getpgid, close, fork +from posix.unistd cimport getpid, getpgid, fork from time import sleep diff --git a/src/sage/interfaces/scilab.py b/src/sage/interfaces/scilab.py index 8349739633c..54c28f55598 100644 --- a/src/sage/interfaces/scilab.py +++ b/src/sage/interfaces/scilab.py @@ -349,10 +349,10 @@ def set(self, var, value): sage: scilab.get('a') # optional - scilab '\n \n 123.' """ - cmd = '%s=%s;'%(var,value) + cmd = '%s=%s;' % (var,value) out = self.eval(cmd) if out.find("error") != -1: - raise TypeError("Error executing code in Scilab\nCODE:\n\t%s\nScilab ERROR:\n\t%s"%(cmd, out)) + raise TypeError("Error executing code in Scilab\nCODE:\n\t%s\nScilab ERROR:\n\t%s" % (cmd, out)) def get(self, var): """ @@ -365,7 +365,7 @@ def get(self, var): sage: scilab.get('b') # optional - scilab '\n \n 124.' """ - s = self.eval('%s'%var) + s = self.eval('%s' % var) i = s.find('=') return s[i+1:] @@ -486,7 +486,7 @@ def _matrix_(self, R): [1.00000000000000 2.00000000000000] [3.00000000000000 4.50000000000000] """ - from sage.matrix.all import MatrixSpace + from sage.matrix.matrix_space import MatrixSpace s = str(self).strip() v = s.split('\n ') nrows = len(v) @@ -509,7 +509,8 @@ def set(self, i, j, x): """ P = self._check_valid() z = P(x) - P.eval('%s(%s,%s) = %s'%(self.name(), i, j, z.name())) + P.eval('%s(%s,%s) = %s' % (self.name(), i, j, z.name())) + # An instance scilab = Scilab() diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 0518caaa9b2..f4e5c6a9158 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -584,7 +584,7 @@ def eval(self, x, allow_semicolon=True, strip=True, **kwds): - ``x`` - string (of code) - ``allow_semicolon`` - default: False; if False then - raise a TypeError if the input line contains a semicolon. + raise a :class:`TypeError` if the input line contains a semicolon. - ``strip`` - ignored @@ -604,8 +604,7 @@ def eval(self, x, allow_semicolon=True, strip=True, **kwds): sage: i = singular.ideal(['x^2','y^2','z^2']) sage: s = i.std() sage: singular.eval('hilb(%s)'%(s.name())) - '// 1 t^0\n// -3 t^2\n// 3 t^4\n// -1 t^6\n\n// 1 t^0\n// - 3 t^1\n// 3 t^2\n// 1 t^3\n// dimension (affine) = 0\n// + '...// dimension (affine) = 0\n// degree (affine) = 8' :: @@ -613,15 +612,7 @@ def eval(self, x, allow_semicolon=True, strip=True, **kwds): sage: from sage.misc.verbose import set_verbose sage: set_verbose(1) sage: o = singular.eval('hilb(%s)'%(s.name())) - // 1 t^0 - // -3 t^2 - // 3 t^4 - // -1 t^6 - // 1 t^0 - // 3 t^1 - // 3 t^2 - // 1 t^3 - // dimension (affine) = 0 + ...// dimension (affine) = 0 // degree (affine) = 8 This is mainly useful if this method is called implicitly. Because @@ -631,15 +622,7 @@ def eval(self, x, allow_semicolon=True, strip=True, **kwds): :: sage: o = s.hilb() - // 1 t^0 - // -3 t^2 - // 3 t^4 - // -1 t^6 - // 1 t^0 - // 3 t^1 - // 3 t^2 - // 1 t^3 - // dimension (affine) = 0 + ...// dimension (affine) = 0 // degree (affine) = 8 // ** right side is not a datum, assignment ignored ... @@ -681,7 +664,7 @@ def eval(self, x, allow_semicolon=True, strip=True, **kwds): # "Segment fault" is not a typo: # Singular actually does use that string if s.find("error occurred") != -1 or s.find("Segment fault") != -1: - raise SingularError('Singular error:\n%s'%s) + raise SingularError('Singular error:\n%s' % s) if get_verbose() > 0: for line in s.splitlines(): @@ -720,8 +703,8 @@ def set(self, type, name, value): '0' """ - cmd = ''.join('if(defined(%s)){kill %s;};'%(v,v) for v in self.__to_clear) - cmd += '%s %s=%s;'%(type, name, value) + cmd = ''.join('if(defined(%s)){kill %s;};' % (v,v) for v in self.__to_clear) + cmd += '%s %s=%s;' % (type, name, value) self.__to_clear = [] self.eval(cmd) @@ -735,7 +718,7 @@ def get(self, var): sage: singular.get('x') '2' """ - return self.eval('print(%s);'%var) + return self.eval('print(%s);' % var) def clear(self, var): """ @@ -860,13 +843,13 @@ def cputime(self, t=None): 0.02 """ if t: - return float(self.eval('timer-(%d)'%(int(1000*t))))/1000.0 + return float(self.eval('timer-(%d)' % (int(1000*t))))/1000.0 else: return float(self.eval('timer'))/1000.0 - ################################################################### + ########################################################### # Singular libraries - ################################################################### + ########################################################### def lib(self, lib, reload=False): """ Load the Singular library named lib. @@ -890,9 +873,9 @@ def lib(self, lib, reload=False): LIB = lib load = lib - ################################################################### + ########################################################## # constructors - ################################################################### + ########################################################## def ideal(self, *gens): """ Return the ideal generated by gens. @@ -1058,9 +1041,9 @@ def matrix(self, nrows, ncols, entries=None): """ name = self._next_var_name() if entries is None: - self.eval('matrix %s[%s][%s]'%(name, nrows, ncols)) + self.eval('matrix %s[%s][%s]' % (name, nrows, ncols)) else: - self.eval('matrix %s[%s][%s] = %s'%(name, nrows, ncols, entries)) + self.eval('matrix %s[%s][%s] = %s' % (name, nrows, ncols, entries)) return SingularElement(self, None, name, True) def ring(self, char=0, vars='(x)', order='lp', check=None): @@ -1417,8 +1400,8 @@ def _repr_(self): """ s = super(SingularElement, self)._repr_() if self._name in s: - if (not hasattr(self, "__custom_name")) and self.type() == 'matrix': - s = self.parent().eval('pmat(%s,20)'%(self.name())) + if self.get_custom_name() is None and self.type() == 'matrix': + s = self.parent().eval('pmat(%s,20)' % (self.name())) return s def __copy__(self): @@ -1459,13 +1442,13 @@ def __copy__(self): 0, y,0, x*y,0,0 """ - if (self.type()=='ring') or (self.type()=='qring'): + if (self.type() == 'ring') or (self.type() == 'qring'): # Problem: singular has no clean method to produce # a copy of a ring/qring. We use ringlist, but this # is only possible if we make self the active ring, # use ringlist, and switch back to the previous # base ring. - br=self.parent().current_ring() + br = self.parent().current_ring() self.set_ring() OUT = (self.ringlist()).ring() br.set_ring() @@ -1525,9 +1508,9 @@ def __setitem__(self, n, value): if len(n) != 2: raise ValueError("If n (=%s) is a tuple, it must be a 2-tuple" % n) x, y = n - P.eval('%s[%s,%s] = %s'%(self.name(), x, y, value.name())) + P.eval('%s[%s,%s] = %s' % (self.name(), x, y, value.name())) else: - P.eval('%s[%s] = %s'%(self.name(), n, value.name())) + P.eval('%s[%s] = %s' % (self.name(), n, value.name())) def __bool__(self): """ @@ -1651,20 +1634,24 @@ def sage_global_ring(self): singular = self.parent() charstr = singular.eval('charstr(basering)').split(',',1) from sage.rings.integer_ring import ZZ - is_extension = len(charstr)==2 + is_extension = len(charstr) == 2 if charstr[0] in ['integer', 'ZZ']: br = ZZ is_extension = False elif charstr[0] in ['0', 'QQ']: - from sage.all import QQ + from sage.rings.rational_field import QQ br = QQ elif charstr[0].startswith('Float'): - from sage.all import RealField, ceil, log + from sage.rings.real_mpfr import RealField + from sage.functions.other import ceil + from sage.misc.functional import log prec = singular.eval('ringlist(basering)[1][2][1]') br = RealField(ceil((ZZ(prec)+1)/log(2,10))) is_extension = False - elif charstr[0]=='complex': - from sage.all import ComplexField, ceil, log + elif charstr[0] == 'complex': + from sage.rings.complex_mpfr import ComplexField + from sage.functions.other import ceil + from sage.misc.functional import log prec = singular.eval('ringlist(basering)[1][2][1]') br = ComplexField(ceil((ZZ(prec)+1)/log(2,10))) is_extension = False @@ -1684,14 +1671,14 @@ def sage_global_ring(self): if is_extension: minpoly = singular.eval('minpoly') if minpoly == '0': - from sage.all import Frac + from sage.rings.fraction_field import FractionField as Frac BR = Frac(br[charstr[1]]) else: is_short = singular.eval('short') if is_short != '0': singular.eval('short=0') minpoly = ZZ[charstr[1]](singular.eval('minpoly')) - singular.eval('short=%s'%is_short) + singular.eval('short=%s' % is_short) else: minpoly = ZZ[charstr[1]](minpoly) BR = br.extension(minpoly,names=charstr[1]) @@ -1701,11 +1688,11 @@ def sage_global_ring(self): # Now, we form the polynomial ring over BR with the given variables, # using Singular's term order from sage.rings.polynomial.term_order import termorder_from_singular - from sage.all import PolynomialRing + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing # Meanwhile Singulars quotient rings are also of 'ring' type, not 'qring' as it was in the past. # To find out if a singular ring is a quotient ring or not checking for ring type does not help # and instead of that we check if the quotient ring is zero or not: - if (singular.eval('ideal(basering)==0')=='1'): + if (singular.eval('ideal(basering)==0') == '1'): return PolynomialRing(BR, names=singular.eval('varstr(basering)'), order=termorder_from_singular(singular)) P = PolynomialRing(BR, names=singular.eval('varstr(basering)'), order=termorder_from_singular(singular)) return P.quotient(singular('ringlist(basering)[4]')._sage_(P), names=singular.eval('varstr(basering)')) @@ -1835,20 +1822,20 @@ def sage_poly(self, R=None, kcache=None): # as we know what to expect. is_short = self.parent().eval('short') - if is_short!='0': + if is_short != '0': self.parent().eval('short=0') if isinstance(R, MPolynomialRing_libsingular): out = R(self) - self.parent().eval('short=%s'%is_short) + self.parent().eval('short=%s' % is_short) return out - singular_poly_list = self.parent().eval("string(coef(%s,%s))" % (\ - self.name(),variable_str)).split(",") - self.parent().eval('short=%s'%is_short) + singular_poly_list = self.parent().eval("string(coef(%s,%s))" % ( + self.name(),variable_str)).split(",") + self.parent().eval('short=%s' % is_short) else: if isinstance(R, MPolynomialRing_libsingular): return R(self) - singular_poly_list = self.parent().eval("string(coef(%s,%s))" % (\ - self.name(),variable_str)).split(",") + singular_poly_list = self.parent().eval("string(coef(%s,%s))" % ( + self.name(),variable_str)).split(",") # Directly treat constants if singular_poly_list[0] in ['1', '(1.000e+00)']: @@ -1877,19 +1864,19 @@ def sage_poly(self, R=None, kcache=None): variables = [var.split("^") for var in monomial.split("*") ] for e in variables: var = e[0] - if len(e)==int(2): + if len(e) == int(2): power = int(e[1]) else: - power=1 - exp[var_dict[var]]=power + power = 1 + exp[var_dict[var]] = power if kcache is None: - sage_repr[ETuple(exp,ngens)]=k(singular_poly_list[coeff_start+i]) + sage_repr[ETuple(exp,ngens)] = k(singular_poly_list[coeff_start+i]) else: elem = singular_poly_list[coeff_start+i] if elem not in kcache: kcache[elem] = k( elem ) - sage_repr[ETuple(exp,ngens)]= kcache[elem] + sage_repr[ETuple(exp,ngens)] = kcache[elem] return R(sage_repr) @@ -1902,8 +1889,8 @@ def sage_poly(self, R=None, kcache=None): exp = int(0) if monomial not in ['1', '(1.000e+00)']: - term = monomial.split("^") - if len(term)==int(2): + term = monomial.split("^") + if len(term) == int(2): exp = int(term[1]) else: exp = int(1) @@ -1914,7 +1901,7 @@ def sage_poly(self, R=None, kcache=None): elem = singular_poly_list[coeff_start+i] if elem not in kcache: kcache[elem] = k( elem ) - sage_repr[ exp ]= kcache[elem] + sage_repr[ exp ] = kcache[elem] return R(sage_repr) @@ -1954,14 +1941,14 @@ def sage_matrix(self, R, sparse=True): #this is slow for x in range(nrows): for y in range(ncols): - A[x,y]=self[x+1,y+1].sage_poly(R) + A[x,y] = self[x+1,y+1].sage_poly(R) return A A = Matrix(R, nrows, ncols, sparse=sparse) #this is slow for x in range(nrows): for y in range(ncols): - A[x,y]=R(self[x+1,y+1]) + A[x,y] = R(self[x+1,y+1]) return A @@ -2040,9 +2027,9 @@ def _sage_(self, R=None): """ typ = self.type() - if typ=='poly': + if typ == 'poly': return self.sage_poly(R) - elif typ=='int': + elif typ == 'int': return sage.rings.integer.Integer(repr(self)) elif typ == 'module': return self.sage_matrix(R,sparse=True) @@ -2056,7 +2043,7 @@ def _sage_(self, R=None): elif typ == 'intmat': from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ - A = matrix(ZZ, int(self.nrows()), int(self.ncols())) + A = matrix(ZZ, int(self.nrows()), int(self.ncols())) for i in range(A.nrows()): for j in range(A.ncols()): A[i,j] = sage.rings.integer.Integer(str(self[i+1,j+1])) @@ -2162,7 +2149,7 @@ def sage_structured_str_list(self): sage: RL.sage_structured_str_list() ['0', ['x', 'y'], [['dp', '1,\n1'], ['C', '0']], '0'] """ - if not (self.type()=='list'): + if not (self.type() == 'list'): return str(self) return [X.sage_structured_str_list() for X in self] @@ -2401,7 +2388,7 @@ def generate_docstring_dictionary(): a, b = m.groups() node_names[a] = b.strip() - if line == "6 Index\n": + if line in ("6 Index\n", "F Index\n"): in_node = False nodes[curr_node] = "".join(L) # last node @@ -2431,10 +2418,10 @@ def get_docstring(name): except KeyError: return "" -################################## singular = Singular() + def reduce_load_Singular(): """ EXAMPLES:: @@ -2492,7 +2479,7 @@ class SingularGBLogPrettyPrinter: cri_hilb = re.compile("h") # used Hilbert series criterion hig_corn = re.compile(r"H\(\d+\)") # found a 'highest corner' of degree d, no need to consider higher degrees num_crit = re.compile(r"\(\d+\)") # n critical pairs are still to be reduced - red_num = re.compile(r"\(S:\d+\)") # doing complete reduction of n elements + red_num = re.compile(r"\(S:\d+\)") # doing complete reduction of n elements deg_lead = re.compile(r"\d+") # the degree of the leading terms is currently d # SlimGB diff --git a/src/sage/interfaces/sympy.py b/src/sage/interfaces/sympy.py index 2c847d56892..a334c241127 100644 --- a/src/sage/interfaces/sympy.py +++ b/src/sage/interfaces/sympy.py @@ -65,6 +65,17 @@ def _sympysage_float(self): from sage.rings.real_mpfr import create_RealNumber return create_RealNumber(str(self)) +def _sympysage_integer_ring(self): + r""" + EXAMPLES:: + + sage: import sympy + sage: sympy.ZZ._sage_() + Integer Ring + """ + from sage.rings.integer_ring import ZZ + return ZZ + def _sympysage_integer(self): """ EXAMPLES:: @@ -90,6 +101,121 @@ def _sympysage_rational(self): from sage.rings.rational import Rational return Rational((Integer(self.p), Integer(self.q))) +def _sympysage_rational_field(self): + r""" + EXAMPLES:: + + sage: import sympy + sage: sympy.QQ._sage_() + Rational Field + """ + from sage.rings.rational_field import QQ + return QQ + +def _sympysage_real_interval(self): + r""" + EXAMPLES:: + + sage: from sage.interfaces.sympy import sympy_init + sage: sympy_init() + + sage: from sympy import CRootOf + sage: from sympy.abc import x + sage: root = CRootOf(x**3 - x^2 - x - 1, 0) + sage: interval = root._get_interval() + sage: interval._sage_() + 2.? + sage: interval._sage_().parent() + Real Interval Field with 1024 bits of precision + """ + # NOTE: this is a very approximate conversion as we do not consider any + # potential issue with precision + # Just to be (a little bit) safe, we set it to 1024 + from sage.rings.real_mpfi import RealIntervalField + RIF = RealIntervalField(1024) + # NOTE: we call fraction_field since sympy stores mpq even + # for integral entries + domain = self.dom._sage_().fraction_field() + return RIF(domain(self.a)).union(RIF(domain(self.b))) + +def _sympysage_complex_interval(self): + r""" + EXAMPLES:: + + sage: from sage.interfaces.sympy import sympy_init + sage: sympy_init() + + sage: from sympy import CRootOf + sage: from sympy.abc import x + sage: root = CRootOf(x**10 - 2*x + 3, 9) + sage: interval = root._get_interval() + sage: interval._sage_() + 0.1? + 1.2?*I + sage: interval._sage_().parent() + Complex Interval Field with 1024 bits of precision + """ + # NOTE: this is a very approximate conversion as we do not consider any + # potential issue with precision + # Just to be (a little bit) safe, we set it to 1024 + from sage.rings.complex_interval_field import ComplexIntervalField + CIF = ComplexIntervalField(1024) + # NOTE: we call fraction_field since sympy stores mpq even + # for integral entries + domain = self.dom._sage_().fraction_field() + return CIF(domain(self.ax), domain(self.ay)).union(CIF(domain(self.bx), domain(self.by))) + +def _sympysage_polynomial_ring(self): + r""" + EXAMPLES:: + + sage: from sage.interfaces.sympy import sympy_init + sage: sympy_init() + + sage: import sympy + sage: ZZx = sympy.PolynomialRing(sympy.ZZ, 'x') + sage: ZZx._sage_() + Univariate Polynomial Ring in x over Integer Ring + + sage: ZZxy = sympy.PolynomialRing(ZZx, 'y') + sage: ZZxy._sage_() + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Integer Ring + """ + base_ring = self.domain._sage_() + variables = ','.join(map(str, self.gens)) + return base_ring[variables] + +def _sympysage_polynomial(self): + r""" + EXAMPLES:: + + sage: from sage.interfaces.sympy import sympy_init + sage: sympy_init() + + sage: import sympy + sage: from sympy.abc import x, y + sage: p = sympy.Poly(x*(x**2 + x - 1)**2) + sage: p._sage_() + x^5 + 2*x^4 - x^3 - 2*x^2 + x + sage: p._sage_().parent() + Univariate Polynomial Ring in x over Integer Ring + + sage: p = sympy.Poly(y*x**2 + x*y + 1) + sage: p._sage_() + x^2*y + x*y + 1 + sage: p._sage_().parent() + Multivariate Polynomial Ring in x, y over Integer Ring + + sage: p = sympy.Poly(y*x**2 + x*y + 1, x) + sage: p._sage_() + y*x^2 + y*x + 1 + sage: p._sage_().parent() + Univariate Polynomial Ring in x over Univariate Polynomial Ring in y over Integer Ring + """ + base_ring = self.domain._sage_() + variables = ','.join(map(str, self.gens)) + R = base_ring[variables] + return R.sum(base_ring(coeff) * R.monomial(*exp) for exp, coeff in self.rep.terms(order=None)) + def _sympysage_pinfty(self): """ EXAMPLES:: @@ -453,7 +579,7 @@ def _sympysage_rf(self): sage: assert rising_factorial(x,y)._sympy_() == rfxy.rewrite('gamma', piecewise=False) sage: assert rising_factorial(x,y) == rfxy._sage_() """ - from sage.arith.all import rising_factorial + from sage.arith.misc import rising_factorial return rising_factorial(self.args[0]._sage_(), self.args[1]._sage_()) def _sympysage_ff(self): @@ -466,7 +592,7 @@ def _sympysage_ff(self): sage: assert falling_factorial(x,y)._sympy_() == ffxy.rewrite('gamma') # known bug sage: assert falling_factorial(x,y) == ffxy._sage_() """ - from sage.arith.all import falling_factorial + from sage.arith.misc import falling_factorial return falling_factorial(self.args[0]._sage_(), self.args[1]._sage_()) def _sympysage_lgamma(self): @@ -890,7 +1016,7 @@ def _sympysage_true(self): #------------------------------------------------------------------ -from sage.repl.ipython_extension import run_once +from sage.misc.misc import run_once @run_once def sympy_init(): @@ -938,13 +1064,24 @@ def sympy_init(): from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.logic.boolalg import BooleanTrue, BooleanFalse from sympy.integrals.integrals import Integral + from sympy.polys import Poly + from sympy.polys.domains.integerring import IntegerRing + from sympy.polys.domains.rationalfield import RationalField + from sympy.polys.domains.polynomialring import PolynomialRing from sympy.polys.rootoftools import CRootOf + from sympy.polys.rootisolation import RealInterval, ComplexInterval from sympy.series.order import Order from sympy.matrices import ImmutableMatrix, ImmutableSparseMatrix, Matrix, SparseMatrix Float._sage_ = _sympysage_float Integer._sage_ = _sympysage_integer Rational._sage_ = _sympysage_rational + RealInterval._sage_ = _sympysage_real_interval + ComplexInterval._sage_ = _sympysage_complex_interval + IntegerRing._sage_ = _sympysage_integer_ring + RationalField._sage_ = _sympysage_rational_field + PolynomialRing._sage_ = _sympysage_polynomial_ring + Poly._sage_ = _sympysage_polynomial Infinity._sage_ = _sympysage_pinfty NegativeInfinity._sage_ = _sympysage_ninfty ComplexInfinity._sage_ = _sympysage_uinfty diff --git a/src/sage/interfaces/tachyon.py b/src/sage/interfaces/tachyon.py index a7e45c3c294..6053d2519e4 100644 --- a/src/sage/interfaces/tachyon.py +++ b/src/sage/interfaces/tachyon.py @@ -683,12 +683,14 @@ #***************************************************************************** import os +import re from sage.cpython.string import bytes_to_str from sage.misc.pager import pager from sage.misc.superseded import deprecation from sage.misc.temporary_file import tmp_filename from sage.structure.sage_object import SageObject +from sage.misc.cachefunc import cached_method class TachyonRT(SageObject): @@ -799,6 +801,11 @@ def __call__(self, model, outfile='sage.png', verbose=1, extra_opts=''): Parser failed due to an input file syntax error. Aborting render. """ + if self.version() >= '0.99.2': + # this keyword was changed in 0.99.2 + model = model.replace( + " focallength ", + " focaldist ") modelfile = tmp_filename(ext='.dat') with open(modelfile, 'w') as file: file.write(model) @@ -851,6 +858,25 @@ def usage(self, use_pager=True): else: print(r) + @cached_method + def version(self): + """ + Returns the version of the Tachyon raytracer being used. + + TESTS:: + + sage: tachyon_rt.version() # random + 0.98.9 + sage: tachyon_rt.version() >= '0.98.9' + True + """ + with os.popen('tachyon') as f: + r = f.readline() + res = re.search(r"Version ([\d.]*)", r) + # debian patches tachyon so it won't report the version + # we hardcode '0.99' since that's indeed the version they ship + return res[1] if res else '0.99' + def help(self, use_pager=True): """ Deprecated: type 'sage.interfaces.tachyon?' for help @@ -865,4 +891,5 @@ def help(self, use_pager=True): """ deprecation(34066, "type 'sage.interfaces.tachyon?' for help") + tachyon_rt = TachyonRT() diff --git a/src/sage/interfaces/tests.py b/src/sage/interfaces/tests.py index 7e1fa9d68db..8c760c2a2c0 100644 --- a/src/sage/interfaces/tests.py +++ b/src/sage/interfaces/tests.py @@ -43,7 +43,7 @@ """ from .all import * -from sage.misc.misc import cputime, walltime +from sage.misc.timing import cputime, walltime import sys def manyvars(s, num=70000, inlen=1, step=2000): @@ -51,14 +51,14 @@ def manyvars(s, num=70000, inlen=1, step=2000): Test that > 65,000 variable names works in each system. """ print("Testing -- %s" % s) - t = '"%s"'%('9'*int(inlen)) + t = '"%s"' % ('9'*int(inlen)) try: t = cputime() w = walltime() v = [] for i in range(num): - if i%step==0: - sys.stdout.write('%s '%i) + if i % step == 0: + sys.stdout.write('%s ' % i) sys.stdout.flush() v.append(s(t)) print('\nsuccess -- time = cpu: %s, wall: %s' % (cputime(t), diff --git a/src/sage/interfaces/tides.py b/src/sage/interfaces/tides.py index 3e8541a14ad..765b8bd3cb4 100644 --- a/src/sage/interfaces/tides.py +++ b/src/sage/interfaces/tides.py @@ -37,10 +37,7 @@ - [TIDES]_ """ - - - -from sage.rings.real_mpfr import RealField +from sage.rings.real_mpfr import RealField from sage.calculus.all import symbolic_expression from sage.misc.flatten import flatten from sage.ext.fast_callable import fast_callable @@ -50,8 +47,6 @@ from sage.misc.functional import sqrt - - def subexpressions_list(f, pars=None): """ Construct the lists with the intermediate steps on the evaluation of the @@ -161,9 +156,9 @@ def subexpressions_list(f, pars=None): F = symbolic_expression([i(*variables) for i in f]).function(*varpar) lis = flatten([fast_callable(i,vars=varpar).op_list() for i in F], max_level=1) stack = [] - const =[] - stackcomp=[] - detail=[] + const = [] + stackcomp = [] + detail = [] for i in lis: if i[0] == 'load_arg': stack.append(varpar[i[1]]) @@ -171,76 +166,76 @@ def subexpressions_list(f, pars=None): if i[1] in NN: basis = stack[-1] for j in range(i[1]-1): - a=stack.pop(-1) + a = stack.pop(-1) detail.append(('mul', a, basis)) stack.append(a*basis) stackcomp.append(stack[-1]) else: detail.append(('pow',stack[-1],i[1])) - stack[-1]=stack[-1]**i[1] + stack[-1] = stack[-1]**i[1] stackcomp.append(stack[-1]) elif i[0] == 'load_const': const.append(i[1]) stack.append(i[1]) elif i == 'mul': - a=stack.pop(-1) - b=stack.pop(-1) + a = stack.pop(-1) + b = stack.pop(-1) detail.append(('mul', a, b)) stack.append(a*b) stackcomp.append(stack[-1]) elif i == 'div': - a=stack.pop(-1) - b=stack.pop(-1) + a = stack.pop(-1) + b = stack.pop(-1) detail.append(('div', a, b)) stack.append(b/a) stackcomp.append(stack[-1]) elif i == 'add': - a=stack.pop(-1) - b=stack.pop(-1) + a = stack.pop(-1) + b = stack.pop(-1) detail.append(('add',a,b)) stack.append(a+b) stackcomp.append(stack[-1]) elif i == 'pow': - a=stack.pop(-1) - b=stack.pop(-1) + a = stack.pop(-1) + b = stack.pop(-1) detail.append(('pow', b, a)) stack.append(b**a) stackcomp.append(stack[-1]) - elif i[0] == 'py_call' and str(i[1])=='log': - a=stack.pop(-1) + elif i[0] == 'py_call' and str(i[1]) == 'log': + a = stack.pop(-1) detail.append(('log', a)) stack.append(log(a)) stackcomp.append(stack[-1]) - elif i[0] == 'py_call' and str(i[1])=='exp': - a=stack.pop(-1) + elif i[0] == 'py_call' and str(i[1]) == 'exp': + a = stack.pop(-1) detail.append(('exp', a)) stack.append(exp(a)) stackcomp.append(stack[-1]) - elif i[0] == 'py_call' and str(i[1])=='sin': - a=stack.pop(-1) + elif i[0] == 'py_call' and str(i[1]) == 'sin': + a = stack.pop(-1) detail.append(('sin', a)) detail.append(('cos', a)) stackcomp.append(sin(a)) stackcomp.append(cos(a)) stack.append(sin(a)) - elif i[0] == 'py_call' and str(i[1])=='cos': - a=stack.pop(-1) + elif i[0] == 'py_call' and str(i[1]) == 'cos': + a = stack.pop(-1) detail.append(('sin', a)) detail.append(('cos', a)) stackcomp.append(sin(a)) stackcomp.append(cos(a)) stack.append(cos(a)) - elif i[0] == 'py_call' and str(i[1])=='tan': - a=stack.pop(-1) + elif i[0] == 'py_call' and str(i[1]) == 'tan': + a = stack.pop(-1) b = sin(a) c = cos(a) detail.append(('sin', a)) @@ -251,8 +246,8 @@ def subexpressions_list(f, pars=None): stackcomp.append(b/c) stack.append(b/c) - elif i[0] == 'py_call' and str(i[1])=='arctan': - a=stack.pop(-1) + elif i[0] == 'py_call' and str(i[1]) == 'arctan': + a = stack.pop(-1) detail.append(('mul', a, a)) detail.append(('add', 1, a*a)) detail.append(('atan', a)) @@ -261,12 +256,12 @@ def subexpressions_list(f, pars=None): stackcomp.append(arctan(a)) stack.append(arctan(a)) - elif i[0] == 'py_call' and str(i[1])=='arcsin': - a=stack.pop(-1) + elif i[0] == 'py_call' and str(i[1]) == 'arcsin': + a = stack.pop(-1) detail.append(('mul', a, a)) detail.append(('mul', -1, a*a)) detail.append(('add', 1, -a*a)) - detail.append(('pow', 1- a*a, 0.5)) + detail.append(('pow', 1 - a*a, 0.5)) detail.append(('asin', a)) stackcomp.append(a*a) stackcomp.append(-a*a) @@ -275,12 +270,12 @@ def subexpressions_list(f, pars=None): stackcomp.append(arcsin(a)) stack.append(arcsin(a)) - elif i[0] == 'py_call' and str(i[1])=='arccos': - a=stack.pop(-1) + elif i[0] == 'py_call' and str(i[1]) == 'arccos': + a = stack.pop(-1) detail.append(('mul', a, a)) detail.append(('mul', -1, a*a)) detail.append(('add', 1, -a*a)) - detail.append(('pow', 1- a*a, 0.5)) + detail.append(('pow', 1 - a*a, 0.5)) detail.append(('mul', -1, sqrt(1-a*a))) detail.append(('acos', a)) stackcomp.append(a*a) @@ -292,12 +287,11 @@ def subexpressions_list(f, pars=None): stack.append(arccos(a)) elif i[0] == 'py_call' and 'sqrt' in str(i[1]): - a=stack.pop(-1) + a = stack.pop(-1) detail.append(('pow', a, 0.5)) stackcomp.append(sqrt(a)) stack.append(sqrt(a)) - elif i == 'neg': a = stack.pop(-1) detail.append(('mul', -1, a)) @@ -307,7 +301,6 @@ def subexpressions_list(f, pars=None): return stackcomp,detail - def remove_repeated(l1, l2): """ Given two lists, remove the repeated elements in l1, and the elements @@ -341,14 +334,13 @@ def remove_repeated(l1, l2): """ for i in range(len(l1)-1): - j=i+1 - while j<len(l1): + j = i+1 + while j < len(l1): if str(l1[j]) == str(l1[i]): l1.pop(j) l2.pop(j) else: - j+=1 - + j += 1 def remove_constants(l1,l2): @@ -356,6 +348,8 @@ def remove_constants(l1,l2): Given two lists, remove the entries in the first that are real constants, and also the corresponding elements in the second one. + EXAMPLES:: + sage: from sage.interfaces.tides import subexpressions_list, remove_constants sage: f(a)=[1+cos(7)*a] sage: l1, l2 = subexpressions_list(f) @@ -367,14 +361,13 @@ def remove_constants(l1,l2): ([a*cos(7), a*cos(7) + 1], [('mul', cos(7), a), ('add', 1, a*cos(7))]) """ - i=0 + i = 0 while i < len(l1): if l1[i] in RealField(): l1.pop(i) l2.pop(i) else: - i+=1 - + i += 1 def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, @@ -479,7 +472,7 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, l0 = [str(l) for l in l1] #generate the corresponding c lines - l3=[] + l3 = [] var = f[0].arguments() lv = [str(v) for v in var] for i in l2: @@ -492,17 +485,17 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, l3.append((oper, 'XX[{}]'.format(l0.index(str(a))+len(var)))) else: - a=i[1] - b=i[2] - consta=False - constb=False + a = i[1] + b = i[2] + consta = False + constb = False if str(a) in lv: aa = 'XX[{}]'.format(lv.index(str(a))) elif str(a) in l0: aa = 'XX[{}]'.format(l0.index(str(a))+len(var)) else: - consta=True + consta = True aa = RR(a).str() if str(b) in lv: bb = 'XX[{}]'.format(lv.index(str(b))) @@ -513,26 +506,25 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, bb = RR(b).str() if consta: oper += '_c' - if not oper=='div': + if not oper == 'div': bb, aa = aa, bb elif constb: oper += '_c' l3.append((oper, aa, bb)) - n = len(var) res = [] for i in range(len(l3)): el = l3[i] string = "XX[{}][i] = ".format(i + n) if el[0] == 'add': - string += el[1] + "[i] + " + el[2] +"[i];" + string += el[1] + "[i] + " + el[2] + "[i];" elif el[0] == 'add_c': - string += "(i==0)? {}+".format(el[2]) + el[1] + "[0] : "+ el[1]+ "[i];" + string += "(i==0)? {}+".format(el[2]) + el[1] + "[0] : " + el[1] + "[i];" elif el[0] == 'mul': string += "mul_mc("+el[1]+","+el[2]+",i);" elif el[0] == 'mul_c': - string += el[2] + "*"+ el[1] + "[i];" + string += el[2] + "*" + el[1] + "[i];" elif el[0] == 'pow_c': string += "pow_mc_c("+el[1]+","+el[2]+",XX[{}], i);".format(i+n) elif el[0] == 'div': @@ -548,7 +540,6 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, elif el[0] == 'cos': string += "cos_mc("+el[1]+",XX[{}], i);".format(i+n-1) - res.append(string) l0 = lv + l0 @@ -622,7 +613,7 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, double tolrel, tolabs, tini, tend, dt; double v[VARS], p[PARS]; - """%(n-1) + """ % (n-1) outfile.write(auxstring) for i in range(len(ics)): outfile.write('\tv[{}] = {} ; \n'.format(i, RR(ics[i]).str())) @@ -632,7 +623,7 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, outfile.write('\ttolrel = {} ;\n'.format(RR(tolrel).str())) outfile.write('\ttolabs = {} ;\n'.format(RR(tolabs).str())) outfile.write('\textern char ofname[500];') - outfile.write('\tstrcpy(ofname, "'+ output +'");\n') + outfile.write('\tstrcpy(ofname, "' + output + '");\n') outfile.write('\tminc_tides(v,VARS,p,PARS,tini,tend,dt,tolrel,tolabs);\n') outfile.write('\treturn 0; \n }') outfile.close() @@ -760,7 +751,7 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, l1, l2 = subexpressions_list(f, parameters) remove_repeated(l1, l2) remove_constants(l1, l2) - l3=[] + l3 = [] var = f[0].arguments() l0 = [str(l) for l in l1] lv = [str(v) for v in var] @@ -777,12 +768,12 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, l3.append((oper, 'link[{}]'.format(l0.index(str(a))))) else: - a=i[1] - b=i[2] + a = i[1] + b = i[2] sa = str(a) sb = str(b) - consta=False - constb=False + consta = False + constb = False if sa in lv: aa = 'var[{}]'.format(lv.index(sa)) @@ -791,7 +782,7 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, elif sa in lp: aa = 'par[{}]'.format(lp.index(sa)) else: - consta=True + consta = True aa = RR(a).str() if sb in lv: bb = 'var[{}]'.format(lv.index(sb)) @@ -800,11 +791,11 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, elif sb in lp: bb = 'par[{}]'.format(lp.index(sb)) else: - constb=True + constb = True bb = RR(b).str() if consta: oper += '_c' - if not oper=='div': + if not oper == 'div': bb, aa = aa,bb elif constb: oper += '_c' @@ -860,7 +851,7 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, VAR = n-1 PAR = len(parameters) - TT = len(code)+1-VAR + TT = len(code)+1-VAR outfile = open(integrator, 'a') @@ -902,7 +893,6 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, outfile.write(auxstring) outfile.close() - npar = len(parameter_values) outfile = open(driver, 'a') @@ -946,7 +936,6 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, outfile.write('\tmpfr_init2(tini, TIDES_PREC); \n') outfile.write('\tmpfr_init2(dt, TIDES_PREC); \n') - outfile.write('\tmpfr_set_str(tini, "{}", 10, TIDES_RND);;\n'.format(RR(initial).str())) outfile.write('\tmpfr_set_str(dt, "{}", 10, TIDES_RND);\n'.format(RR(delta).str())) outfile.write('\tint nipt = {};\n'.format(floor((final-initial)/delta))) diff --git a/src/sage/knots/__init__.py b/src/sage/knots/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index cefd33aebb4..0e1e45d2cbe 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -31,12 +31,11 @@ lines of the examples, are unnecessary. Be aware that there are a couple of conventions used differently on KnotInfo as -in Sage, especially concerning the selection of the symmetry version of the link. +in Sage. -In this context you should note that the PD notation is recorded counter -clockwise in KnotInfo (see note in :meth:`KnotInfoBase.link`). In our transition -to Sage objects this is translated (by default) in order to avoid confusion about -exchanged mirror versions. +For different conventions regarding normalization of the polynomial invariants see +the according documentation of :meth:`KnotInfoBase.homfly_polynomial`, +:meth:`KnotInfoBase.jones_polynomial` and :meth:`KnotInfoBase.alexander_polynomial`. Also, note that the braid notation is used according to Sage, even thought in the source where it is taken from, the braid generators are assumed to have a @@ -44,9 +43,11 @@ 3 of :arxiv:`Gittings, T., "Minimum Braids: A Complete Invariant of Knots and Links" <math/0401051>`). -For different conventions regarding normalization of the polynomial invariants see -the according documentation of :meth:`KnotInfoBase.homfly_polynomial`, -:meth:`KnotInfoBase.jones_polynomial` and :meth:`KnotInfoBase.alexander_polynomial`. +Furthermore, note that not all columns available in the database are visible on the web +pages (see also the related note under :meth:`KnotInfoBase.khovanov_polynomial`). +It is planned to remove non-visible columns from the database in the future (see +the `Python Wrapper <https://github.com/soehms/database_knotinfo#readme>`__ for +updated information). EXAMPLES:: @@ -106,7 +107,7 @@ sage: type(l6s) # optional - snappy <class 'spherogram.links.invariants.Link'> - sage: l6 = L6.link().mirror_image() + sage: l6 = L6.link() sage: l6 == l6s.sage_link() # optional - snappy True sage: L6.link(L6.items.name, snappy=True) # optional - snappy @@ -114,7 +115,8 @@ sage: l6sn = _ # optional - snappy sage: l6s == l6sn # optional - snappy False - sage: l6sn.sage_link().is_isotopic(l6) # optional - snappy + sage: l6m = l6.mirror_image() # optional - snappy + sage: l6sn.sage_link().is_isotopic(l6m) # optional - snappy True But observe that the name conversion to SnapPy does not distinguish orientation @@ -173,13 +175,14 @@ You can launch web-pages attached to the links:: - sage: K.diagram() # not tested + sage: # not tested + sage: K.diagram() True - sage: L.diagram(single=True) # not tested + sage: L.diagram(single=True) True - sage: L.knot_atlas_webpage() # not tested + sage: L.knot_atlas_webpage() True - sage: K.knotilus_webpage() # not tested + sage: K.knotilus_webpage() True and the description web-pages of the properties:: @@ -233,7 +236,6 @@ ############################################################################## - from enum import Enum from sage.misc.cachefunc import cached_method from sage.misc.sage_eval import sage_eval @@ -245,8 +247,6 @@ from sage.databases.knotinfo_db import KnotInfoColumns, db - - def eval_knotinfo(string, locals={}, to_tuple=True): r""" Preparse a string from the KnotInfo database and evaluate it by ``sage_eval``. @@ -295,7 +295,6 @@ def knotinfo_bool(string): raise ValueError('%s is not a KnotInfo boolean') - # --------------------------------------------------------------------------------- # KnotInfoBase # --------------------------------------------------------------------------------- @@ -441,7 +440,6 @@ def _braid_group(self): else: return BraidGroup(n) - @cached_method def _homfly_pol_ring(self, var1, var2): r""" @@ -1153,7 +1151,6 @@ def is_oriented(self): """ return not knotinfo_bool(self[self.items.unoriented]) - @cached_method def homfly_polynomial(self, var1='v', var2='z', original=False): r""" @@ -1339,7 +1336,6 @@ def kauffman_polynomial(self, var1='a', var2='z', original=False): lc = {'a': a, 'z': z} return R(eval_knotinfo(kauffman_polynomial, locals=lc)) - @cached_method def jones_polynomial(self, variab=None, skein_normalization=False, puiseux=False, original=False, use_sqrt=False): r""" @@ -1492,15 +1488,15 @@ def jones_polynomial(self, variab=None, skein_normalization=False, puiseux=False if skein_normalization: if not variab: - variab='A' + variab = 'A' from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing R = LaurentPolynomialRing(ZZ, variab) else: if not variab: if use_sqrt or self.is_knot() or puiseux: - variab='t' + variab = 't' else: - variab='x' + variab = 'x' if puiseux: from sage.rings.puiseux_series_ring import PuiseuxSeriesRing # since PuiseuxPolynomial is not available, so far R = PuiseuxSeriesRing(ZZ, variab) @@ -1528,10 +1524,8 @@ def jones_polynomial(self, variab=None, skein_normalization=False, puiseux=False else: lc = {'x': t} - return R(eval_knotinfo(jones_polynomial, locals=lc)) - @cached_method def alexander_polynomial(self, var='t', original=False, laurent_poly=False): r""" @@ -1691,7 +1685,7 @@ def conway_polynomial(self, var='t', original=False): return R(eval_knotinfo(conway_polynomial, locals=lc)) @cached_method - def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ, original=False): + def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ, original=False, reduced=False, odd=False, KhoHo=False): r""" Return the Khovanov polynomial according to the value of column ``khovanov_polynomial`` for this knot or link as an instance of @@ -1703,8 +1697,16 @@ def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ, original=False): - ``var2`` -- (default: ``'t'``) the second variable - ``base_ring`` -- (default: ``ZZ``) the ring of the polynomial's coefficients - - ``original`` -- boolean (optional, default ``False``) if set to + - ``original`` -- boolean (default: ``False``); if set to ``True`` the original table entry is returned as a string + - ``reduced`` -- boolean (default: ``False``); if set to ``True`` + the reduced version of the homology is used + - ``odd`` -- boolean (default: ``False``); if set to ``True`` + the odd version of the homology is used + - ``KhoHo`` -- boolean (default: ``False`` for knots and ``True`` + for multi-component links); if set to ``True`` the data calculated + using `KhoHo <https://github.com/AShumakovitch/KhoHo>`__ is used + (see the note below) OUTPUT: @@ -1714,8 +1716,24 @@ def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ, original=False): .. NOTE :: - The Khovanov polynomial given in KnotInfo corresponds to the mirror - image of the given knot for a `list of 140 exceptions + The data used for multi-component links were calculated with the program + `KhoHo <https://github.com/AShumakovitch/KhoHo>`__. These can still be + used for knots by setting the optional argument ``KhoHo`` to ``True``, + even though they will no longer be visible on the Knot website as of + October 30, 2022. Otherwise, for knots data calculated with + `KnotJob <https://www.maths.dur.ac.uk/users/dirk.schuetz/knotjob.html>`__ + are used. The latter program is more accurate in terms of orientation + and reflection as it is based on ``PD`` code. + + Note that in the future columns that are not visible on the web page may + also be removed in the database (see the + `Python wrapper <https://github.com/soehms/database_knotinfo#readme>`__ + for updated information). Therefore, the ``KhoHo`` option cannot be + guaranteed to work after upgrading the ``database_knotinfo``-SPKG. + + Furthermore, since the results of ``KhoHo`` were computed using the ``DT`` + notation, the Khovanov polynomial returned by this option belongs to the + mirror image of the given knot for a `list of 140 exceptions <https://raw.githubusercontent.com/soehms/database_knotinfo/main/hints/list_of_mirrored_khovanov_polynonmial.txt>`__. EXAMPLES:: @@ -1731,6 +1749,35 @@ def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ, original=False): sage: L = KnotInfo.L5a1_0 sage: Lk = L.khovanov_polynomial(); Lk q^4*t^2 + t + 2 + 2*q^-2 + q^-2*t^-1 + q^-4*t^-2 + q^-6*t^-2 + q^-8*t^-3 + sage: L.khovanov_polynomial(original=True) + '2 + 2/q^2 + 1/(q^8*t^3) + 1/(q^6*t^2) + 1/(q^4*t^2) + 1/(q^2*t) + t + q^4*t^2' + + Obtaining the reduced homology (for knots only):: + + sage: Kkr = K.khovanov_polynomial(reduced=True); Kkr + q^6*t^3 + 2*q^4*t^2 + 2*q^2*t + 3 + 2*q^-2*t^-1 + 2*q^-4*t^-2 + q^-6*t^-3 + sage: K.khovanov_polynomial(base_ring=QQ, reduced=True) == Kkr + True + sage: Kkr2 = K.khovanov_polynomial(base_ring=GF(2), reduced=True); Kkr2 + q^6*t^3 + 1 + q^-6*t^-3 + sage: KnotInfo.K8_19.inject() # optional database_knotinfo + Defining K8_19 + sage: K8kr = K8_19.khovanov_polynomial(reduced=True); K8kr # optional database_knotinfo + q^16*t^5 + q^12*t^4 + q^12*t^3 + q^10*t^2 + q^6 + + Obtaining the odd Khovanov homology (for knots only):: + + sage: K.khovanov_polynomial(odd=True) == Kkr + True + sage: K.khovanov_polynomial(base_ring=QQ, odd=True) == Kkr + True + sage: K.khovanov_polynomial(base_ring=GF(2), odd=True) == Kkr2 + True + sage: K8ko = K8_19.khovanov_polynomial(odd=True); K8ko # optional database_knotinfo + q^16*t^5 + q^10*t^2 + q^6 + sage: K8kr == K8ko # optional database_knotinfo + False + Comparision to Sage's results:: @@ -1740,8 +1787,65 @@ def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ, original=False): True sage: Lk == L.link().khovanov_polynomial() True + + TESTS:: + + sage: KnotInfo.K0_1.inject() + Defining K0_1 + sage: K0_1.khovanov_polynomial() + q + q^-1 + sage: K0_1.khovanov_polynomial(reduced=True) + 1 + sage: K0_1.khovanov_polynomial(odd=True) + 1 + sage: K0_1.khovanov_polynomial(base_ring=GF(3), reduced=True) + Traceback (most recent call last): + ... + ValueError: Characteristic 3 of base ring is not valid + sage: K0_1.khovanov_polynomial(base_ring=GF(3), odd=True) + Traceback (most recent call last): + ... + ValueError: Characteristic 3 of base ring is not valid + sage: L.khovanov_polynomial(base_ring=GF(2)) + Traceback (most recent call last): + ... + NotImplementedError: Khovanov polynomial available only for knots in characteristic 2 + + REFERENCES: + + - :wikipedia:`Khovanov_homology` + - :wikipedia:`Reduced_homology` + - [ORS2013]_ """ - khovanov_polynomial = self[self.items.khovanov_polynomial] + ch = base_ring.characteristic() + integral = ch == 0 and base_ring.is_field() + if not self.is_knot(): + # KnotJob calculated results only available for knots + KhoHo = True + if KhoHo: + # use the old results obtained by the KhoHo software + khovanov_polynomial = self[self.items.khovanov_polynomial] + else: + if reduced: + if integral: + khovanov_polynomial = self[self.items.khovanov_reduced_integral_polynomial] + elif ch == 0: + khovanov_polynomial = self[self.items.khovanov_reduced_rational_polynomial] + elif ch == 2: + khovanov_polynomial = self[self.items.khovanov_reduced_mod2_polynomial] + else: + raise ValueError('Characteristic %s of base ring is not valid' % ch) + elif odd: + if integral: + khovanov_polynomial = self[self.items.khovanov_odd_integral_polynomial] + elif ch == 0: + khovanov_polynomial = self[self.items.khovanov_odd_rational_polynomial] + elif ch == 2: + khovanov_polynomial = self[self.items.khovanov_odd_mod2_polynomial] + else: + raise ValueError('Characteristic %s of base ring is not valid' % ch) + else: + khovanov_polynomial = self[self.items.khovanov_unreduced_integral_polynomial] if original: return khovanov_polynomial @@ -1751,15 +1855,18 @@ def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ, original=False): R = LaurentPolynomialRing(base_ring, var_names) if not khovanov_polynomial and self.crossing_number() == 0: - return R({(1, 0): 1, (-1, 0): 1}) + if reduced or odd: + return R.one() + else: + return R({(1, 0): 1, (-1, 0): 1}) - ch = base_ring.characteristic() if ch == 2: if not self.is_knot(): raise NotImplementedError('Khovanov polynomial available only for knots in characteristic 2') - khovanov_torsion_polynomial = self[self.items.khovanov_torsion_polynomial] - khovanov_torsion_polynomial = khovanov_torsion_polynomial.replace('Q', 'q') - khovanov_polynomial = '%s + %s' % (khovanov_polynomial, khovanov_torsion_polynomial) + if KhoHo: + khovanov_torsion_polynomial = self[self.items.khovanov_torsion_polynomial] + khovanov_torsion_polynomial = khovanov_torsion_polynomial.replace('Q', 'q') + khovanov_polynomial = '%s + %s' % (khovanov_polynomial, khovanov_torsion_polynomial) if not khovanov_polynomial: # given just for links with less than 12 crossings @@ -1768,14 +1875,18 @@ def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ, original=False): from sage.repl.preparse import implicit_mul # since implicit_mul does not know about the choice of variable names # we have to insert * between them separately - for i in ['q', 't',')']: - for j in ['q', 't', '(']: + for i in ['q', 't', 'T', ')']: + for j in ['q', 't', 'T', '(']: khovanov_polynomial = khovanov_polynomial.replace('%s%s' % (i, j), '%s*%s' % (i, j)) khovanov_polynomial = implicit_mul(khovanov_polynomial) gens = R.gens_dict() lc = {} lc['q'] = gens[var1] lc['t'] = gens[var2] + if ch == 2: + lc['T'] = 1 + else: + lc['T'] = 0 return R(eval_knotinfo(khovanov_polynomial, locals=lc)) @@ -1813,14 +1924,6 @@ def link(self, use_item=db.columns().pd_notation, snappy=False): coincides with the crossing number as a topological invariant. - But attention: The convention on how the edges are - listed are opposite to each other - - - KnotInfo: counter clockwise - - Sage: clockwise - - Therefore, we take the mirror version of the ``pd_notation``! - Furthermore, note that the mirror version may depend on the used KnotInfo-notation. For instance, regarding to the knot ``5_1`` the Gauss- and the DT-notation refer to @@ -1855,25 +1958,23 @@ def link(self, use_item=db.columns().pd_notation, snappy=False): using ``snappy``:: - sage: K7 = KnotInfo.K7_2 - sage: k7s = K7.link(snappy=True); k7s # optional - snappy - <Link: 1 comp; 7 cross> - sage: K7.link(K7.items.name, snappy=True) # optional - snappy - <Link 7_2: 1 comp; 7 cross> - sage: k7sn = _ # optional - snappy - sage: k7s == k7sn # optional - snappy - False - sage: k7s.sage_link().is_isotopic(k7sn.sage_link()) # optional - snappy - True - - but observe:: - sage: L2 = KnotInfo.L2a1_1 sage: l2 = L2.link() sage: l2s = L2.link(snappy=True).sage_link() # optional - snappy sage: l2 == l2s # optional - snappy + True + + but observe:: + + sage: K7 = KnotInfo.K7_2 + sage: k7s = K7.link(snappy=True); k7s # optional - snappy + <Link: 1 comp; 7 cross> + sage: k7sn = K7.link(K7.items.name, snappy=True); k7sn # optional - snappy + <Link 7_2: 1 comp; 7 cross> + sage: k7s.sage_link().is_isotopic(k7sn) # optional - snappy False - sage: l2 == l2s.mirror_image() # optional - snappy + sage: k7snm = k7sn.sage_link().mirror_image() # optional - snappy + sage: k7s.sage_link().is_isotopic(k7snm) # optional - snappy True using ``braid_notation``:: @@ -1894,7 +1995,7 @@ def link(self, use_item=db.columns().pd_notation, snappy=False): sage: K4_1 = KnotInfo.K4_1 sage: K4_1.link().pd_code() - [[4, 1, 5, 2], [8, 5, 1, 6], [6, 4, 7, 3], [2, 8, 3, 7]] + [[4, 2, 5, 1], [8, 6, 1, 5], [6, 3, 7, 4], [2, 7, 3, 8]] sage: K4_1.pd_notation() [[4, 2, 5, 1], [8, 6, 1, 5], [6, 3, 7, 4], [2, 7, 3, 8]] @@ -1907,7 +2008,7 @@ def link(self, use_item=db.columns().pd_notation, snappy=False): s^-5 """ if not isinstance(use_item, KnotInfoColumns): - raise TypeError('%s must be an instance of %s' %(use_item, KnotInfoColumns)) + raise TypeError('%s must be an instance of %s' % (use_item, KnotInfoColumns)) if snappy: try: @@ -1919,9 +2020,8 @@ def link(self, use_item=db.columns().pd_notation, snappy=False): else: from sage.knots.link import Link - if use_item == self.items.pd_notation: - pd_code = [[a[0], a[3], a[2], a[1]] for a in self.pd_notation()] # take mirror version, see note above - return Link(pd_code) + if use_item == self.items.pd_notation: + return Link(self.pd_notation()) elif use_item == self.items.braid_notation: return Link(self.braid()) elif use_item == self.items.name and snappy: @@ -1936,8 +2036,7 @@ def link(self, use_item=db.columns().pd_notation, snappy=False): elif use_item == self.items.gauss_notation: return Knots().from_gauss_code(self.gauss_notation()) - raise ValueError('Link construction using %s not possible' %use_item) - + raise ValueError('Link construction using %s not possible' % use_item) @cached_method def is_unique(self): @@ -2150,7 +2249,6 @@ def diagram(self, single=False, new=0, autoraise=True): else: return webbrowser.open(filename.diagram_url(self[self.items.name]), new=new, autoraise=autoraise) - def knot_atlas_webpage(self, new=0, autoraise=True): r""" Launch the Knot Atlas web-page for ``self``. @@ -2192,7 +2290,6 @@ def knotilus_webpage(self, new=0, autoraise=True): return webbrowser.open(self[self.items.knotilus_page_anon], new=new, autoraise=autoraise) - # -------------------------------------------------------------------------------------------- # KnotInfoSeries # -------------------------------------------------------------------------------------------- @@ -2236,7 +2333,6 @@ class KnotInfoSeries(UniqueRepresentation, SageObject): True """ - def __init__(self, crossing_number, is_knot, is_alternating, name_unoriented=None): r""" Python constructor. @@ -2322,7 +2418,7 @@ def list(self, oriented=False, comp=None, det=None, homfly=None): if K.crossing_number() != cross_nr: continue if not is_knot or cross_nr > 10: - if K.is_alternating() != is_alt: + if K.is_alternating() != is_alt: continue if is_knot or oriented: res.append(K) @@ -2343,7 +2439,6 @@ def list(self, oriented=False, comp=None, det=None, homfly=None): res.append(KnotInfoSeries(cross_nr, is_knot, is_alt, curr_n_unori)) return res - @cached_method def lower_list(self, oriented=False, comp=None, det=None, homfly=None): r""" @@ -2388,7 +2483,6 @@ def lower_list(self, oriented=False, comp=None, det=None, homfly=None): l = LS.lower_list(oriented=oriented, comp=comp, det=det, homfly=homfly) return l + self.list(oriented=oriented, comp=comp, det=det, homfly=homfly) - def __repr__(self): r""" Return the representation string of ``self``. @@ -2402,10 +2496,9 @@ def __repr__(self): 'Series of knots K6' """ if self._is_knot: - return 'Series of knots %s' %(self._name()) + return 'Series of knots %s' % (self._name()) else: - return 'Series of links %s' %(self._name()) - + return 'Series of links %s' % (self._name()) def __getitem__(self, item): r""" @@ -2421,12 +2514,12 @@ def __getitem__(self, item): [<KnotInfo.K6_1: '6_1'>, <KnotInfo.K6_2: '6_2'>, <KnotInfo.K6_3: '6_3'>] """ from sage.rings.integer import Integer - if not type(item) in (int, Integer): + if not type(item) in (int, Integer): raise ValueError('Item must be an integer') l = self.list() max_item = len(l) - if item < 0 or item > max_item: - raise ValueError('Item must be non negative and smaller than %s' %(max_item)) + if item < 0 or item > max_item: + raise ValueError('Item must be non negative and smaller than %s' % (max_item)) return l[item] @@ -2458,18 +2551,18 @@ def __call__(self, item): True """ if self._name_unoriented: - if type(item) == str: + if isinstance(item, str): # allow input as dual number according to naming item = int(item, 2) return self[item] from sage.rings.integer import Integer - if not type(item) in (int, Integer): + if not type(item) in (int, Integer): raise ValueError('Item must be an integer') - l =self.list() - max_item = len(l)+1 - if item < 1 or item > max_item: - raise ValueError('Item must be positive and smaller than %s' %(max_item)) + l = self.list() + max_item = len(l) + 1 + if item < 1 or item > max_item: + raise ValueError('Item must be positive and smaller than %s' % (max_item)) return l[item-1] @@ -2485,7 +2578,7 @@ def _name(self): """ is_knot = self._is_knot cross_nr = self._crossing_number - is_alt = self._is_alternating + is_alt = self._is_alternating n_unori = self._name_unoriented alt = 'a' @@ -2494,13 +2587,13 @@ def _name(self): if is_knot: if cross_nr > 10: - res = 'K%s%s' %(cross_nr, alt) + res = 'K%s%s' % (cross_nr, alt) else: - res = 'K%s' %(cross_nr) + res = 'K%s' % (cross_nr) elif n_unori: - res = '%s' %(n_unori) + res = '%s' % (n_unori) else: - res = 'L%s%s' %(cross_nr, alt) + res = 'L%s%s' % (cross_nr, alt) return res def is_recoverable(self, unique=True, max_samples=8): @@ -2566,7 +2659,6 @@ def _test_recover(self, **options): else: tester.assertTrue(self.is_recoverable(unique=False)) - def inject(self, verbose=True): r""" Inject ``self`` with its name into the namespace of the diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index 12e159db251..a5ecdb5490c 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -39,6 +39,8 @@ - Amit Jamadagni - Sebastian Oehms (October 2020, add :meth:`get_knotinfo` and :meth:`is_isotopic`) - Sebastian Oehms (May 2022): add :meth:`links_gould_polynomial` +- Sebastian Oehms (May 2023): change the convention about the ``pd_code`` from + clockwise to anti-clockwise (see :trac:`35665`). """ # **************************************************************************** @@ -127,7 +129,7 @@ class Link(SageObject): The diagram of the link is formed by segments that are adjacent to the crossings. Label each one of this segments with a positive number, and for each crossing, write down the four incident segments. The - order of these segments is clockwise, starting with the incoming + order of these segments is anti-clockwise, starting with the incoming undercrossing. There is no particular distinction between knots and links for @@ -189,9 +191,9 @@ class Link(SageObject): We construct the "monster" unknot using a planar code, and then construct the oriented Gauss code and braid representation:: - sage: L = Link([[3,1,2,4], [8,9,1,7], [5,6,7,3], [4,18,6,5], - ....: [17,19,8,18], [9,10,11,14], [10,12,13,11], - ....: [12,19,15,13], [20,16,14,15], [16,20,17,2]]) + sage: L = Link([[3,4,2,1], [8,7,1,9], [5,3,7,6], [4,5,6,18], + ....: [17,18,8,19], [9,14,11,10], [10,11,13,12], + ....: [12,13,15,19], [20,15,14,16], [16,2,17,20]]) sage: L.oriented_gauss_code() [[[1, -4, 3, -1, 10, -9, 6, -7, 8, 5, 4, -3, 2, -6, 7, -8, 9, -10, -5, -2]], [1, -1, 1, 1, 1, -1, -1, -1, -1, -1]] @@ -201,9 +203,9 @@ class Link(SageObject): .. PLOT:: :width: 300 px - L = Link([[3,1,2,4],[8,9,1,7],[5,6,7,3],[4,18,6,5], - [17,19,8,18],[9,10,11,14],[10,12,13,11], - [12,19,15,13],[20,16,14,15],[16,20,17,2]]) + L = Link([[3,4,2,1], [8,7,1,9], [5,3,7,6], [4,5,6,18], + [17,18,8,19], [9,14,11,10], [10,11,13,12], + [12,13,15,19], [20,15,14,16], [16,2,17,20]]) sphinx_plot(L.plot()) We construct the Ochiai unknot by using an oriented Gauss code:: @@ -212,10 +214,10 @@ class Link(SageObject): ....: -11,-16,4,3,-5,6,-9,7,-15,14,16,-10,8,9,-6,5]], ....: [-1,-1,1,1,1,1,-1,1,1,-1,1,-1,-1,-1,-1,-1]]) sage: L.pd_code() - [[10, 2, 11, 1], [2, 12, 3, 11], [3, 20, 4, 21], [12, 19, 13, 20], - [21, 32, 22, 1], [31, 22, 32, 23], [9, 25, 10, 24], [4, 29, 5, 30], - [23, 30, 24, 31], [28, 14, 29, 13], [17, 14, 18, 15], [5, 17, 6, 16], - [15, 7, 16, 6], [7, 27, 8, 26], [25, 9, 26, 8], [18, 28, 19, 27]] + [[10, 1, 11, 2], [2, 11, 3, 12], [3, 21, 4, 20], [12, 20, 13, 19], + [21, 1, 22, 32], [31, 23, 32, 22], [9, 24, 10, 25], [4, 30, 5, 29], + [23, 31, 24, 30], [28, 13, 29, 14], [17, 15, 18, 14], [5, 16, 6, 17], + [15, 6, 16, 7], [7, 26, 8, 27], [25, 8, 26, 9], [18, 27, 19, 28]] .. PLOT:: :width: 300 px @@ -426,14 +428,15 @@ def arcs(self, presentation='pd'): [[-1, -2], [2, 1]] """ if presentation == 'pd': + pd_code = self.pd_code() G = DiGraph() - for e in set(flatten(self.pd_code())): + for e in set(flatten(pd_code)): G.add_vertex(e) - for cr in zip(self.pd_code(), self.orientation()): + for cr in zip(pd_code, self.orientation()): if cr[1] == 1: - G.add_edge(cr[0][1], cr[0][3]) - else: G.add_edge(cr[0][3], cr[0][1]) + else: + G.add_edge(cr[0][1], cr[0][3]) res = [] for S in G.connected_components_subgraphs(): check = S.is_directed_acyclic(certificate=True) @@ -480,7 +483,7 @@ def fundamental_group(self, presentation='wirtinger'): EXAMPLES:: - sage: L = Link([[1, 2, 3, 4], [3, 2, 1, 4]]) + sage: L = Link([[1, 4, 3, 2], [3, 4, 1, 2]]) sage: L.fundamental_group() Finitely presented group < x0, x1, x2 | x1*x0^-1*x2^-1*x0, x2*x0*x1^-1*x0^-1 > sage: L.fundamental_group('braid') @@ -519,7 +522,7 @@ def fundamental_group(self, presentation='wirtinger'): rels = [] for crossing, orientation in zip(self.pd_code(), self.orientation()): a = arcs.index([i for i in arcs if crossing[0] in i][0]) - b = arcs.index([i for i in arcs if crossing[1] in i][0]) + b = arcs.index([i for i in arcs if crossing[3] in i][0]) c = arcs.index([i for i in arcs if crossing[2] in i][0]) ela = F.gen(a) elb = F.gen(b) @@ -621,13 +624,13 @@ def braid(self): EXAMPLES:: - sage: L = Link([[2, 3, 1, 4], [4, 1, 3, 2]]) + sage: L = Link([[2, 4, 1, 3], [4, 2, 3, 1]]) sage: L.braid() s^2 sage: L = Link([[[-1, 2, -3, 1, -2, 3]], [-1, -1, -1]]) sage: L.braid() s^-3 - sage: L = Link([[1,8,2,7], [8,4,9,5], [3,9,4,10], [10,1,7,6], [5,3,6,2]]) + sage: L = Link([[1,7,2,8], [8,5,9,4], [3,10,4,9], [10,6,7,1], [5,2,6,3]]) sage: L.braid() (s0*s1^-1)^2*s1^-1 @@ -670,6 +673,7 @@ def braid(self): B = BraidGroup(2) self._braid = B.one() return self._braid + seifert_circles = self.seifert_circles() newedge = max(flatten(pd_code)) + 1 for region in self.regions(): @@ -685,21 +689,45 @@ def braid(self): newPD = [list(vertex) for vertex in pd_code] if sign(a) == 1: + # ------------------------------------------------- + # Visualize insertion of the two new crossings D, E + # \ / + # a\ /b existing edges, a down, b up + # D + # n3/ \n0 newedge + 3, newedge + # \ / + # E + # n1/ \n2 newedge + 1, newedge + 2 + # / \ + # C1 C2 existing crossings + # ------------------------------------------------- C1 = newPD[newPD.index(heads[a])] C1[C1.index(a)] = newedge + 1 C2 = newPD[newPD.index(tails[b])] C2[C2.index(b)] = newedge + 2 - newPD.append([newedge + 3, a, b, newedge]) - newPD.append([newedge + 2, newedge + 1, newedge + 3, newedge]) + newPD.append([newedge + 3, newedge, b, a]) # D + newPD.append([newedge + 2, newedge, newedge + 3, newedge + 1]) # E self._braid = Link(newPD).braid() return self._braid else: + # ------------------------------------------------- + # Visualize insertion of the two new crossings D, E + # C1 C2 existing crossings + # \ / + # n1\ /n2 newedge + 1, newedge + 2 + # D + # n3/ \n0 newedge + 3, newedge + # \ / + # E + # a/ \b existing edges, a up, b down + # / \ + # ------------------------------------------------- C1 = newPD[newPD.index(heads[-a])] C1[C1.index(-a)] = newedge + 1 C2 = newPD[newPD.index(tails[-b])] C2[C2.index(-b)] = newedge + 2 - newPD.append([newedge + 2, newedge, newedge + 3, newedge + 1]) - newPD.append([newedge + 3, newedge, -b, -a]) + newPD.append([newedge + 2, newedge + 1, newedge + 3, newedge]) # D + newPD.append([newedge + 3, -a, -b, newedge]) # E self._braid = Link(newPD).braid() return self._braid @@ -708,11 +736,11 @@ def braid(self): G.add_vertices([tuple(c) for c in seifert_circles]) for i,c in enumerate(pd_code): if self.orientation()[i] == 1: - a = [x for x in seifert_circles if c[1] in x][0] + a = [x for x in seifert_circles if c[3] in x][0] b = [x for x in seifert_circles if c[0] in x][0] else: a = [x for x in seifert_circles if c[0] in x][0] - b = [x for x in seifert_circles if c[3] in x][0] + b = [x for x in seifert_circles if c[1] in x][0] G.add_edge(tuple(a), tuple(b)) # Get a simple path from a source to a sink in the digraph @@ -733,10 +761,10 @@ def braid(self): if orientation[crossing_index] == 1: b = B([1]) status[0] = crossing[2] - status[1] = crossing[3] + status[1] = crossing[1] else: b = B([-1]) - status[0] = crossing[1] + status[0] = crossing[3] status[1] = crossing[2] counter = 0 while available_crossings: @@ -748,10 +776,10 @@ def braid(self): if orientation[pd_code.index(added)] == 1: b *= B([counter + 1]) status[counter] = added[2] - status[counter + 1] = added[3] + status[counter + 1] = added[1] else: b *= B([-counter - 1]) - status[counter] = added[1] + status[counter] = added[3] status[counter + 1] = added[2] if counter > 0: counter -= 1 @@ -773,50 +801,50 @@ def _directions_of_edges(self): EXAMPLES:: - sage: L = Link([[1, 3, 2, 4], [2, 3, 1, 4]]) + sage: L = Link([[1, 4, 2, 3], [2, 4, 1, 3]]) sage: tails, heads = L._directions_of_edges() sage: tails - {1: [2, 3, 1, 4], 2: [1, 3, 2, 4], 3: [1, 3, 2, 4], 4: [2, 3, 1, 4]} + {1: [2, 4, 1, 3], 2: [1, 4, 2, 3], 3: [1, 4, 2, 3], 4: [2, 4, 1, 3]} sage: heads - {1: [1, 3, 2, 4], 2: [2, 3, 1, 4], 3: [2, 3, 1, 4], 4: [1, 3, 2, 4]} + {1: [1, 4, 2, 3], 2: [2, 4, 1, 3], 3: [2, 4, 1, 3], 4: [1, 4, 2, 3]} :: - sage: L = Link([[1,5,2,4], [5,3,6,2], [3,1,4,6]]) + sage: L = Link([[1,4,2,5], [5,2,6,3], [3,6,4,1]]) sage: tails, heads = L._directions_of_edges() sage: tails - {1: [3, 1, 4, 6], - 2: [1, 5, 2, 4], - 3: [5, 3, 6, 2], - 4: [3, 1, 4, 6], - 5: [1, 5, 2, 4], - 6: [5, 3, 6, 2]} + {1: [3, 6, 4, 1], + 2: [1, 4, 2, 5], + 3: [5, 2, 6, 3], + 4: [3, 6, 4, 1], + 5: [1, 4, 2, 5], + 6: [5, 2, 6, 3]} sage: heads - {1: [1, 5, 2, 4], - 2: [5, 3, 6, 2], - 3: [3, 1, 4, 6], - 4: [1, 5, 2, 4], - 5: [5, 3, 6, 2], - 6: [3, 1, 4, 6]} + {1: [1, 4, 2, 5], + 2: [5, 2, 6, 3], + 3: [3, 6, 4, 1], + 4: [1, 4, 2, 5], + 5: [5, 2, 6, 3], + 6: [3, 6, 4, 1]} :: - sage: L = Link([[1,2,3,3], [2,4,5,5], [4,1,7,7]]) + sage: L = Link([[1,3,3,2], [2,5,5,4], [4,7,7,1]]) sage: tails, heads = L._directions_of_edges() sage: tails - {1: [4, 1, 7, 7], - 2: [1, 2, 3, 3], - 3: [1, 2, 3, 3], - 4: [2, 4, 5, 5], - 5: [2, 4, 5, 5], - 7: [4, 1, 7, 7]} + {1: [4, 7, 7, 1], + 2: [1, 3, 3, 2], + 3: [1, 3, 3, 2], + 4: [2, 5, 5, 4], + 5: [2, 5, 5, 4], + 7: [4, 7, 7, 1]} sage: heads - {1: [1, 2, 3, 3], - 2: [2, 4, 5, 5], - 3: [1, 2, 3, 3], - 4: [4, 1, 7, 7], - 5: [2, 4, 5, 5], - 7: [4, 1, 7, 7]} + {1: [1, 3, 3, 2], + 2: [2, 5, 5, 4], + 3: [1, 3, 3, 2], + 4: [4, 7, 7, 1], + 5: [2, 5, 5, 4], + 7: [4, 7, 7, 1]} """ tails = {} heads = {} @@ -832,10 +860,10 @@ def _directions_of_edges(self): tails[a] = D if D[0] == a: a = D[2] - elif D[1] == a: - a = D[3] - else: + elif D[3] == a: a = D[1] + else: + a = D[3] else: heads[a] = next_crossing[0] tails[a] = D @@ -887,7 +915,7 @@ def _enhanced_states(self): sage: K = Link([[[1,-2,3,-1,2,-3]],[-1,-1,-1]]) sage: K.pd_code() - [[4, 2, 5, 1], [2, 6, 3, 5], [6, 4, 1, 3]] + [[4, 1, 5, 2], [2, 5, 3, 6], [6, 3, 1, 4]] sage: K._enhanced_states() (((0, 0, 0), (((1, 4, 7), (4, 1, 9)), ((2, 5, 7), (5, 2, 8)), ((3, 6, 9), (6, 3, 8))), @@ -1053,16 +1081,16 @@ def _enhanced_states(self): n = nmax + j if not v[j]: # For negative crossings, we go from undercrossings to the left - G.add_edge((cr[3], cr[0], n), cr[0]) - G.add_edge((cr[3], cr[0], n), cr[3]) - G.add_edge((cr[1], cr[2], n), cr[2]) - G.add_edge((cr[1], cr[2], n), cr[1]) + G.add_edge((cr[1], cr[0], n), cr[0]) + G.add_edge((cr[1], cr[0], n), cr[1]) + G.add_edge((cr[3], cr[2], n), cr[2]) + G.add_edge((cr[3], cr[2], n), cr[3]) else: # positive crossings, from undercrossing to the right - G.add_edge((cr[0], cr[1], n), cr[0]) - G.add_edge((cr[0], cr[1], n), cr[1]) - G.add_edge((cr[2], cr[3], n), cr[2]) - G.add_edge((cr[2], cr[3], n), cr[3]) + G.add_edge((cr[0], cr[3], n), cr[0]) + G.add_edge((cr[0], cr[3], n), cr[3]) + G.add_edge((cr[2], cr[1], n), cr[2]) + G.add_edge((cr[2], cr[1], n), cr[1]) sm = set(tuple(sorted(x for x in b if isinstance(x, tuple))) for b in G.connected_components(sort=False)) iindex = (writhe - ncross + 2 * sum(v)) // 2 @@ -1265,10 +1293,10 @@ def oriented_gauss_code(self): EXAMPLES:: - sage: L = Link([[1, 11, 2, 10], [6, 2, 7, 3], [3, 12, 4, 9], [9, 5, 10, 6], [8, 1, 5, 4], [11, 8, 12, 7]]) + sage: L = Link([[1, 10, 2, 11], [6, 3, 7, 2], [3, 9, 4, 12], [9, 6, 10, 5], [8, 4, 5, 1], [11, 7, 12, 8]]) sage: L.oriented_gauss_code() [[[-1, 2, -3, 5], [4, -2, 6, -5], [-4, 1, -6, 3]], [-1, 1, 1, 1, -1, -1]] - sage: L = Link([[1, 4, 2, 3], [6, 1, 3, 2], [7, 4, 8, 5], [5, 8, 6, 7]]) + sage: L = Link([[1, 3, 2, 4], [6, 2, 3, 1], [7, 5, 8, 4], [5, 7, 6, 8]]) sage: L.oriented_gauss_code() [[[-1, 2], [-3, 4], [1, 3, -4, -2]], [-1, -1, 1, 1]] sage: B = BraidGroup(8) @@ -1295,10 +1323,10 @@ def oriented_gauss_code(self): for i, j in enumerate(pd): if orient[i] == -1: crossing_info[(j[0], -1, i + 1)] = j[2] - crossing_info[(j[3], 1, i + 1)] = j[1] + crossing_info[(j[1], 1, i + 1)] = j[3] elif orient[i] == 1: crossing_info[(j[0], -1, i + 1)] = j[2] - crossing_info[(j[1], 1, i + 1)] = j[3] + crossing_info[(j[3], 1, i + 1)] = j[1] edges = {} cross_number = {} for i, j in crossing_info.items(): @@ -1327,27 +1355,37 @@ def pd_code(self): The planar diagram is returned in the following format. We construct the crossing by starting with the entering component - of the undercrossing, move in the clockwise direction and then - generate the list. If the crossing is given by `[a, b, c, d]`, - then we interpret this information as: + of the undercrossing, move in the anti-clockwise direction (see the + note below) and then generate the list. If the crossing is given by + `[a, b, c, d]`, then we interpret this information as: 1. `a` is the entering component of the undercrossing; 2. `b, d` are the components of the overcrossing; 3. `c` is the leaving component of the undercrossing. + .. NOTE:: + + Until version 10.0 the convention to read the ``PD`` code has been + to list the components in clockwise direction. As of version 10.1 + the convention has changed, since it was opposite to the usage in + most other places. + + Thus, if you use ``PD`` codes from former Sage releases with this + version you should check for the correct mirror type. + EXAMPLES:: sage: L = Link([[[1, -2, 3, -4, 2, -1, 4, -3]], [1, 1, -1, -1]]) sage: L.pd_code() - [[6, 1, 7, 2], [2, 5, 3, 6], [8, 4, 1, 3], [4, 8, 5, 7]] + [[6, 2, 7, 1], [2, 6, 3, 5], [8, 3, 1, 4], [4, 7, 5, 8]] sage: B = BraidGroup(2) sage: b = B([1, 1, 1, 1, 1]) sage: L = Link(b) sage: L.pd_code() - [[2, 1, 3, 4], [4, 3, 5, 6], [6, 5, 7, 8], [8, 7, 9, 10], [10, 9, 1, 2]] + [[2, 4, 3, 1], [4, 6, 5, 3], [6, 8, 7, 5], [8, 10, 9, 7], [10, 2, 1, 9]] sage: L = Link([[[2, -1], [1, -2]], [1, 1]]) sage: L.pd_code() - [[2, 3, 1, 4], [4, 1, 3, 2]] + [[2, 4, 1, 3], [4, 2, 3, 1]] sage: L = Link([[1, 2, 3, 3], [2, 4, 5, 5], [4, 1, 7, 7]]) sage: L.pd_code() [[1, 2, 3, 3], [2, 4, 5, 5], [4, 1, 7, 7]] @@ -1380,11 +1418,11 @@ def pd_code(self): crossing_dic = {} for i,x in enumerate(oriented_gauss_code[1]): if x == -1: - crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][1], - d_dic[-(i + 1)][1], d_dic[i + 1][0]] - elif x == 1: crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][0], d_dic[-(i + 1)][1], d_dic[i + 1][1]] + elif x == 1: + crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][1], + d_dic[-(i + 1)][1], d_dic[i + 1][0]] elif len(oriented_gauss_code[0]) == 1: for i, j in enumerate(oriented_gauss_code[0][0]): d_dic[j] = [i + 1, i + 2] @@ -1392,11 +1430,11 @@ def pd_code(self): crossing_dic = {} for i, x in enumerate(oriented_gauss_code[1]): if x == -1: - crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][1], - d_dic[-(i + 1)][1], d_dic[i + 1][0]] - elif x == 1: crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][0], d_dic[-(i + 1)][1], d_dic[i + 1][1]] + elif x == 1: + crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][1], + d_dic[-(i + 1)][1], d_dic[i + 1][0]] else: crossing_dic = {} @@ -1412,10 +1450,10 @@ def pd_code(self): for i in b: if i > 0: pd.append( - [strings[i], strings[i - 1], strings_max + 1, strings_max + 2]) + [strings[i], strings_max + 2, strings_max + 1, strings[i - 1]]) else: pd.append( - [strings[abs(i) - 1], strings_max + 1, strings_max + 2, strings[abs(i)]]) + [strings[abs(i) - 1], strings[abs(i)], strings_max + 2, strings_max + 1]) strings[abs(i) - 1] = strings_max + 1 strings[abs(i)] = strings_max + 2 strings_max = strings_max + 2 @@ -1485,7 +1523,7 @@ def dowker_notation(self): """ pd = self.pd_code() orient = self.orientation() - dn = [(i[0], i[3]) if orient[j] == -1 else (i[0], i[1]) + dn = [(i[0], i[1]) if orient[j] == -1 else (i[0], i[3]) for j, i in enumerate(pd)] return dn @@ -1690,7 +1728,7 @@ def number_of_components(self): G.add_vertices(set(flatten(pd))) for c in pd: G.add_edge(c[0], c[2]) - G.add_edge(c[1], c[3]) + G.add_edge(c[3], c[1]) return G.connected_components_number() def is_knot(self): @@ -2016,7 +2054,7 @@ def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ): gens = [g for g in H.gens() if g.order() == infinity or ch.divides(g.order())] l = len(gens) if l: - coeff[(h,d)]=l + coeff[(h,d)] = l return L(coeff) def determinant(self): @@ -2130,24 +2168,24 @@ def orientation(self): EXAMPLES:: - sage: L = Link([[1, 4, 5, 2], [3, 5, 6, 7], [4, 8, 9, 6], [7, 9, 10, 11], [8, 1, 13, 10], [11, 13, 2, 3]]) + sage: L = Link([[1, 2, 5, 4], [3, 7, 6, 5], [4, 6, 9, 8], [7, 11, 10, 9], [8, 10, 13, 1], [11, 3, 2, 13]]) sage: L.orientation() [-1, 1, -1, 1, -1, 1] - sage: L = Link([[1, 7, 2, 6], [7, 3, 8, 2], [3, 11, 4, 10], [11, 5, 12, 4], [14, 5, 1, 6], [13, 9, 14, 8], [12, 9, 13, 10]]) + sage: L = Link([[1, 6, 2, 7], [7, 2, 8, 3], [3, 10, 4, 11], [11, 4, 12, 5], [14, 6, 1, 5], [13, 8, 14, 9], [12, 10, 13, 9]]) sage: L.orientation() [-1, -1, -1, -1, 1, -1, 1] - sage: L = Link([[1, 2, 3, 3], [2, 4, 5, 5], [4, 1, 7, 7]]) + sage: L = Link([[1, 3, 3, 2], [2, 5, 5, 4], [4, 7, 7, 1]]) sage: L.orientation() [-1, -1, -1] """ directions = self._directions_of_edges()[0] orientation = [] for C in self.pd_code(): - if C[0] == C[1] or C[2] == C[3]: + if C[0] == C[3] or C[2] == C[1]: orientation.append(-1) - elif C[1] == C[2] or C[0] == C[3]: + elif C[3] == C[2] or C[0] == C[1]: orientation.append(1) - elif directions[C[1]] == C: + elif directions[C[3]] == C: orientation.append(-1) else: orientation.append(1) @@ -2193,11 +2231,12 @@ def seifert_circles(self): sage: A.seifert_circles() [[3], [7], [1, 5], [2, 4], [6, 8]] """ - available_segments = set(flatten(self.pd_code())) + pd = self.pd_code() + available_segments = set(flatten(pd)) result = [] # detect looped segments. They must be their own seifert circles for a in available_segments: - if any(C.count(a) > 1 for C in self.pd_code()): + if any(C.count(a) > 1 for C in pd): result.append([a]) # remove the looped segments from the available for a in result: @@ -2212,11 +2251,11 @@ def seifert_circles(self): par = [] while a not in par: par.append(a) - posnext = C[(C.index(a) + 1) % 4] + posnext = C[(C.index(a) - 1) % 4] if tails[posnext] == C and not [posnext] in result: a = posnext else: - a = C[(C.index(a) - 1) % 4] + a = C[(C.index(a) + 1) % 4] if a in available_segments: available_segments.remove(a) C = heads[a] @@ -2251,7 +2290,7 @@ def regions(self): sage: L = Link([[[1, -2, 3, -4], [-1, 5, -3, 2, -5, 4]], [-1, 1, 1, -1, -1]]) sage: L.regions() [[10, -4, -7], [9, 7, -3], [8, 3], [6, -9, -2], [5, 2, -8, 4], [1, -5], [-1, -10, -6]] - sage: L = Link([[1, 2, 3, 3], [2, 5, 4, 4], [5, 7, 6, 6], [7, 1, 8, 8]]) + sage: L = Link([[1, 3, 3, 2], [2, 4, 4, 5], [5, 6, 6, 7], [7, 8, 8, 1]]) sage: L.regions() [[-3], [-4], [-6], [-8], [7, 1, 2, 5], [-1, 8, -7, 6, -5, 4, -2, 3]] @@ -2274,7 +2313,7 @@ def regions(self): raise NotImplementedError("can only have one isolated component") pd = self.pd_code() if len(pd) == 1: - if pd[0][0] == pd[0][1]: + if pd[0][0] == pd[0][3]: return [[-pd[0][2]], [pd[0][0]], [pd[0][2], -pd[0][0]]] else: return [[pd[0][2]], [-pd[0][0]], [-pd[0][2], pd[0][0]]] @@ -2288,7 +2327,7 @@ def regions(self): for edge in loops: cros = heads[edge] - if cros[1] == edge: + if cros[3] == edge: regions.append([edge]) else: regions.append([-edge]) @@ -2307,13 +2346,13 @@ def regions(self): else: cros = tails[-edge] ind = cros.index(-edge) - next_edge = cros[(ind + 1) % 4] + next_edge = cros[(ind - 1) % 4] if [next_edge] in regions: region.append(-next_edge) - next_edge = cros[(ind - 1) % 4] + next_edge = cros[(ind + 1) % 4] elif [-next_edge] in regions: region.append(next_edge) - next_edge = cros[(ind - 1) % 4] + next_edge = cros[(ind + 1) % 4] if tails[next_edge] == cros: edge = next_edge else: @@ -2357,9 +2396,9 @@ def mirror_image(self): sage: K2 = K.mirror_image(); K2 Knot represented by 3 crossings sage: K.pd_code() - [[4, 1, 5, 2], [2, 5, 3, 6], [6, 3, 1, 4]] - sage: K2.pd_code() [[4, 2, 5, 1], [2, 6, 3, 5], [6, 4, 1, 3]] + sage: K2.pd_code() + [[4, 1, 5, 2], [2, 5, 3, 6], [6, 3, 1, 4]] .. PLOT:: :width: 300 px @@ -2429,9 +2468,9 @@ def reverse(self): a non reversable knot:: - sage: K8_17 = Knot([[6, 2, 7, 1], [14, 8, 15, 7], [8, 3, 9, 4], - ....: [2, 13, 3, 14], [12, 5, 13, 6], [4, 9, 5, 10], - ....: [16, 12, 1, 11], [10, 16, 11, 15]]) + sage: K8_17 = Knot([[6, 1, 7, 2], [14, 7, 15, 8], [8, 4, 9, 3], + ....: [2, 14, 3, 13], [12, 6, 13, 5], [4, 10, 5, 9], + ....: [16, 11, 1, 12], [10, 15, 11, 16]]) sage: K8_17r = K8_17.reverse() sage: b = K8_17.braid(); b s0^2*s1^-1*(s1^-1*s0)^2*s1^-1 @@ -2708,7 +2747,7 @@ def _bracket(self): if not pd_code: return t.parent().one() if len(pd_code) == 1: - if pd_code[0][0] == pd_code[0][1]: + if pd_code[0][0] == pd_code[0][3]: return -t**(-3) else: return -t**3 @@ -2716,42 +2755,42 @@ def _bracket(self): cross = pd_code[0] rest = [list(vertex) for vertex in pd_code[1:]] [a, b, c, d] = cross - if a == b and c == d and len(rest) > 0: + if a == d and c == b and len(rest) > 0: return (~t + t**(-5)) * Link(rest)._bracket() - elif a == d and c == b and len(rest) > 0: + elif a == b and c == d and len(rest) > 0: return (t + t**5) * Link(rest)._bracket() - elif a == b: + elif a == d: for cross in rest: - if d in cross: - cross[cross.index(d)] = c + if b in cross: + cross[cross.index(b)] = c return -t**(-3) * Link(rest)._bracket() - elif a == d: + elif a == b: for cross in rest: if c in cross: - cross[cross.index(c)] = b - return -t**3 * Link(rest)._bracket() - elif c == b: - for cross in rest: - if d in cross: - cross[cross.index(d)] = a + cross[cross.index(c)] = d return -t**3 * Link(rest)._bracket() elif c == d: for cross in rest: if b in cross: cross[cross.index(b)] = a + return -t**3 * Link(rest)._bracket() + elif c == b: + for cross in rest: + if d in cross: + cross[cross.index(d)] = a return -t**(-3) * Link(rest)._bracket() else: rest_2 = [list(vertex) for vertex in rest] for cross in rest: - if d in cross: - cross[cross.index(d)] = a + if b in cross: + cross[cross.index(b)] = a if c in cross: - cross[cross.index(c)] = b + cross[cross.index(c)] = d for cross in rest_2: - if d in cross: - cross[cross.index(d)] = c if b in cross: - cross[cross.index(b)] = a + cross[cross.index(b)] = c + if d in cross: + cross[cross.index(d)] = a return t * Link(rest)._bracket() + ~t * Link(rest_2)._bracket() @cached_method @@ -2834,7 +2873,7 @@ def homfly_polynomial(self, var1=None, var2=None, normalization='lm'): The Hopf link:: - sage: L = Link([[1,3,2,4],[4,2,3,1]]) + sage: L = Link([[1,4,2,3],[4,1,3,2]]) sage: L.homfly_polynomial('x', 'y') -x^-1*y + x^-1*y^-1 + x^-3*y^-1 @@ -2842,16 +2881,16 @@ def homfly_polynomial(self, var1=None, var2=None, normalization='lm'): has been changed. Therefore we substitute `x \mapsto L^{-1}` and `y \mapsto M`:: - sage: L = Link([[1,4,2,3], [4,1,3,2]]) + sage: L = Link([[1,3,2,4], [4,2,3,1]]) sage: L.homfly_polynomial() L^3*M^-1 - L*M + L*M^-1 - sage: L = Link([[1,4,2,3], [4,1,3,2]]) + sage: L = Link([[1,3,2,4], [4,2,3,1]]) sage: L.homfly_polynomial(normalization='az') a^3*z^-1 - a*z - a*z^-1 The figure-eight knot:: - sage: L = Link([[2,1,4,5], [5,6,7,3], [6,4,1,9], [9,2,3,7]]) + sage: L = Link([[2,5,4,1], [5,3,7,6], [6,9,1,4], [9,7,3,2]]) sage: L.homfly_polynomial() -L^2 + M^2 - 1 - L^-2 sage: L.homfly_polynomial('a', 'z', 'az') @@ -2888,7 +2927,7 @@ def homfly_polynomial(self, var1=None, var2=None, normalization='lm'): This works with isolated components:: sage: L = Link([[[1, -1], [2, -2]], [1, 1]]) - sage: L2 = Link([[1, 3, 2, 4], [2, 3, 1, 4]]) + sage: L2 = Link([[1, 4, 2, 3], [2, 4, 1, 3]]) sage: L2.homfly_polynomial() -L*M^-1 - L^-1*M^-1 sage: L.homfly_polynomial() @@ -2914,14 +2953,14 @@ def homfly_polynomial(self, var1=None, var2=None, normalization='lm'): - http://mathworld.wolfram.com/HOMFLYPolynomial.html """ if not var1: - if normalization == 'az': + if normalization == 'az': var1 = 'a' elif normalization == 'vz': var1 = 'v' else: var1 = 'L' if not var2: - if normalization == 'lm': + if normalization == 'lm': var2 = 'M' else: var2 = 'z' @@ -2989,7 +3028,7 @@ def links_gould_polynomial(self, varnames='t0, t1'): EXAMPLES:: - sage: Hopf = Link([[1, 4, 2, 3], [4, 1, 3, 2]]) + sage: Hopf = Link([[1, 3, 2, 4], [4, 2, 3, 1]]) sage: Hopf.links_gould_polynomial() -1 + t1^-1 + t0^-1 - t0^-1*t1^-1 """ @@ -3044,7 +3083,7 @@ def _coloring_matrix(self, n): crossing = crossings[i] for j in range(di): arc = arcs[j] - if crossing[1] in arc: + if crossing[3] in arc: M[i, j] += 2 if crossing[0] in arc: M[i, j] -= 1 @@ -3120,7 +3159,7 @@ def colorings(self, n): {(1, 2): 2, (3, 4): 0, (5, 6): 1}, {(1, 2): 2, (3, 4): 1, (5, 6): 0}] sage: K.pd_code() - [[4, 1, 5, 2], [2, 5, 3, 6], [6, 3, 1, 4]] + [[4, 2, 5, 1], [2, 6, 3, 5], [6, 4, 1, 3]] sage: K.arcs('pd') [[1, 2], [3, 4], [5, 6]] @@ -3321,8 +3360,9 @@ def plot(self, gap=0.1, component_gap=0.5, solver=None, sage: L.plot(solver='Gurobi') # optional - Gurobi Graphics object consisting of ... graphics primitives """ + pd_code = self.pd_code() if type(color) is not dict: - coloring = {int(i): color for i in set(flatten(self.pd_code()))} + coloring = {int(i): color for i in set(flatten(pd_code))} else: from sage.plot.colors import rainbow ncolors = len(set(color.values())) @@ -3359,7 +3399,7 @@ def plot(self, gap=0.1, component_gap=0.5, solver=None, from sage.plot.circle import circle # Special case for the unknot - if not self.pd_code(): + if not pd_code: return circle((0,0), ZZ(1)/ZZ(2), color=color, **kwargs) # The idea is the same followed in spherogram, but using MLP instead of @@ -3369,7 +3409,7 @@ def plot(self, gap=0.1, component_gap=0.5, solver=None, # with straight angles, and using the minimal number of bends. regions = sorted(self.regions(), key=len) regions = regions[:-1] - edges = list(set(flatten(self.pd_code()))) + edges = list(set(flatten(pd_code))) edges.sort() MLP = MixedIntegerLinearProgram(maximization=False, solver=solver) # v will be the list of variables in the MLP problem. There will be @@ -3493,8 +3533,8 @@ def plot(self, gap=0.1, component_gap=0.5, solver=None, v = MLP.get_values(v) lengths = {piece: sum(v[a] for a in pieces[piece]) for piece in pieces} image = line([], **kwargs) - crossings = {tuple(self.pd_code()[0]): (0, 0, 0)} - availables = self.pd_code()[1:] + crossings = {tuple(pd_code[0]): (0, 0, 0)} + availables = pd_code[1:] used_edges = [] ims = line([], **kwargs) while len(used_edges) < len(edges): @@ -3511,14 +3551,14 @@ def plot(self, gap=0.1, component_gap=0.5, solver=None, e = c[j] kwargs['color'] = coloring[e] used_edges.append(e) - direction = (crossings[c][2] - c.index(e)) % 4 - orien = self.orientation()[self.pd_code().index(list(c))] + direction = (crossings[c][2] + c.index(e)) % 4 + orien = self.orientation()[pd_code.index(list(c))] if s[edges.index(e)] < 0: turn = -1 else: turn = 1 lengthse = [lengths[(e,k)] for k in range(abs(s[edges.index(e)])+1)] - if c.index(e) == 0 or (c.index(e) == 1 and orien == 1) or (c.index(e) == 3 and orien == -1): + if c.index(e) == 0 or (c.index(e) == 3 and orien == 1) or (c.index(e) == 1 and orien == -1): turn = -turn lengthse.reverse() tailshort = (c.index(e) % 2 == 0) @@ -3546,8 +3586,8 @@ def plot(self, gap=0.1, component_gap=0.5, solver=None, c2 = [ee for ee in availables if e in ee] if len(c2) == 1: availables.remove(c2[0]) - crossings[tuple(c2[0])] = (x1, y1, (direction + c2[0].index(e) + 2) % 4) - c2 = [ee for ee in self.pd_code() if e in ee and ee != list(c)] + crossings[tuple(c2[0])] = (x1, y1, (direction - c2[0].index(e) + 2) % 4) + c2 = [ee for ee in pd_code if e in ee and ee != list(c)] if not c2: headshort = not tailshort else: @@ -3612,7 +3652,6 @@ def delta(u, v): ims += sum(line(a[0], **kwargs) for a in im) return image - def _markov_move_cmp(self, braid): r""" Return whether ``self`` can be transformed to the closure of ``braid`` @@ -3632,9 +3671,9 @@ def _markov_move_cmp(self, braid): EXAMPLES:: sage: b = BraidGroup(4)((1, 2, -3, 2, 2, 2, 2, 2, 2, -1, 2, 3, 2)) - sage: L = Link([[2, 1, 4, 5], [5, 4, 6, 7], [7, 6, 8, 9], [9, 8, 10, 11], - ....: [11, 10, 12, 13], [13, 12, 14, 15], [15, 14, 16, 17], - ....: [3, 17, 18, 19], [16, 1, 21, 18], [19, 21, 2, 3]]) + sage: L = Link([[2, 5, 4, 1], [5, 7, 6, 4], [7, 9, 8, 6], [9, 11, 10, 8], + ....: [11, 13, 12, 10], [13, 15, 14, 12], [15, 17, 16, 14], + ....: [3, 19, 18, 17], [16, 18, 21, 1], [19, 3, 2, 21]]) sage: L._markov_move_cmp(b) # both are isotopic to ``9_3`` True sage: bL = L.braid(); bL @@ -3712,7 +3751,8 @@ def _knotinfo_matching_list(self): """ from sage.knots.knotinfo import KnotInfoSeries - cr = len(self.pd_code()) + pd_code = self.pd_code() + cr = len(pd_code) co = self.number_of_components() # set the limits for the KnotInfoSeries @@ -3750,16 +3790,12 @@ def _knotinfo_matching_list(self): ln = Sn.lower_list(oriented=True, comp=co, det=det, homfly=Hp) l = sorted(list(set(la + ln))) - pdm = [[a[0], a[3], a[2], a[1]] for a in self.pd_code() ] br = self.braid() br_ind = br.strands() res = [] for L in l: - if L.pd_notation() == pdm: - # note that KnotInfo pd_notation works counter clockwise. Therefore, - # to compensate this we compare with the mirrored pd_code. See also, - # docstring of :meth:`link` of :class:`~sage.knots.knotinfo.KnotInfoBase`. + if L.pd_notation() == pd_code: return [L], True # pd_notation is unique in the KnotInfo database if L.braid_index() <= br_ind: @@ -3825,9 +3861,9 @@ def get_knotinfo(self, mirror_version=True, unique=True): EXAMPLES:: sage: from sage.knots.knotinfo import KnotInfo - sage: L = Link([[4,2,5,1], [10,3,11,4], [5,16,6,17], [7,12,8,13], - ....: [18,9,19,10], [2,11,3,12], [13,20,14,21], [15,6,16,7], - ....: [22,18,1,17], [8,19,9,20], [21,14,22,15]]) + sage: L = Link([[4,1,5,2], [10,4,11,3], [5,17,6,16], [7,13,8,12], + ....: [18,10,19,9], [2,12,3,11], [13,21,14,20], [15,7,16,6], + ....: [22,17,1,18], [8,20,9,19], [21,15,22,14]]) sage: L.get_knotinfo() # optional - database_knotinfo (<KnotInfo.K11n_121: '11n_121'>, True) @@ -3846,7 +3882,7 @@ def get_knotinfo(self, mirror_version=True, unique=True): ... NotImplementedError: this knot having more than 12 crossings cannot be determined - sage: Link([[1, 5, 2, 4], [3, 1, 4, 8], [5, 3, 6, 2], [6, 9, 7, 10], [10, 7, 9, 8]]) + sage: Link([[1, 4, 2, 5], [3, 8, 4, 1], [5, 2, 6, 3], [6, 10, 7, 9], [10, 8, 9, 7]]) Link with 2 components represented by 5 crossings sage: _.get_knotinfo() Traceback (most recent call last): @@ -4015,8 +4051,8 @@ def answer(L): achp = L.is_amphicheiral(positive=True) if ach is None and achp is None: if unique: - raise NotImplementedError('this link cannot be uniquely determined (unknown chirality)%s' %non_unique_hint) - elif L.is_amphicheiral() or L.is_amphicheiral(positive=True): + raise NotImplementedError('this link cannot be uniquely determined (unknown chirality)%s' % non_unique_hint) + elif L.is_amphicheiral() or L.is_amphicheiral(positive=True): chiral = False if not chiral: @@ -4032,7 +4068,7 @@ def answer(L): # polynomial does not distinguish mirror images (see the above # example ``k11m``). if unique: - raise NotImplementedError('mirror type of this link cannot be uniquely determined%s' %non_unique_hint) + raise NotImplementedError('mirror type of this link cannot be uniquely determined%s' % non_unique_hint) mirrored = '?' elif L in lm: mirrored = True @@ -4081,8 +4117,7 @@ def answer_list(l): if set(list(S)) == set(l): return answer_unori(S) - raise NotImplementedError('this link cannot be uniquely determined%s' %non_unique_hint) - + raise NotImplementedError('this link cannot be uniquely determined%s' % non_unique_hint) self_m = self.mirror_image() ls, proved_s = self._knotinfo_matching_list() @@ -4110,18 +4145,18 @@ def answer_list(l): cr = len(self.pd_code()) if self.is_knot() and cr > 12: # we cannot not be sure if this link is recorded in the KnotInfo database - raise NotImplementedError('this knot having more than 12 crossings cannot be%s determined%s' %uniq_txt) + raise NotImplementedError('this knot having more than 12 crossings cannot be%s determined%s' % uniq_txt) if not self.is_knot() and cr > 11: # we cannot not be sure if this link is recorded in the KnotInfo database - raise NotImplementedError('this link having more than 11 crossings cannot be%s determined%s' %uniq_txt) + raise NotImplementedError('this link having more than 11 crossings cannot be%s determined%s' % uniq_txt) H = self.homfly_polynomial(normalization='vz') if sum(exp for f, exp in H.factor()) > 1: # we cannot be sure if this is a prime link (see the example for the connected # sum of K4_1 and K5_2 in the doctest of :meth:`_knotinfo_matching_list`) - raise NotImplementedError('this (possibly non prime) link cannot be%s determined%s' %uniq_txt) + raise NotImplementedError('this (possibly non prime) link cannot be%s determined%s' % uniq_txt) if not l: from sage.features.databases import DatabaseKnotInfo @@ -4130,7 +4165,6 @@ def answer_list(l): return answer_list(l) - def is_isotopic(self, other): r""" Check whether ``self`` is isotopic to ``other``. @@ -4192,13 +4226,13 @@ def is_isotopic(self, other): try: ki, m = self.get_knotinfo() - verbose('KnotInfo self: %s mirrored %s' %(ki, m)) + verbose('KnotInfo self: %s mirrored %s' % (ki, m)) try: if ki.is_unique(): try: kio = other.get_knotinfo() - verbose('KnotInfo other: %s mirrored %s' %kio) - return (ki, m) == kio + verbose('KnotInfo other: %s mirrored %s' % kio) + return (ki, m) == kio except NotImplementedError: pass except AttributeError: diff --git a/src/sage/lfunctions/__init__.py b/src/sage/lfunctions/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/lfunctions/dokchitser.py b/src/sage/lfunctions/dokchitser.py index c526b9321a4..58499396d6c 100644 --- a/src/sage/lfunctions/dokchitser.py +++ b/src/sage/lfunctions/dokchitser.py @@ -33,7 +33,7 @@ import string from sage.structure.sage_object import SageObject -from sage.rings.all import ComplexField +from sage.rings.complex_mpfr import ComplexField from sage.rings.integer import Integer from sage.misc.sage_eval import sage_eval from sage.misc.verbose import verbose diff --git a/src/sage/lfunctions/lcalc.py b/src/sage/lfunctions/lcalc.py index d791460039b..73246cdd81e 100644 --- a/src/sage/lfunctions/lcalc.py +++ b/src/sage/lfunctions/lcalc.py @@ -30,9 +30,14 @@ import os from sage.structure.sage_object import SageObject +from sage.misc.lazy_import import lazy_import from sage.misc.pager import pager -import sage.rings.all -import sage.schemes.elliptic_curves.ell_generic +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ + +lazy_import('sage.rings.complex_mpfr', 'ComplexField') +lazy_import('sage.rings.real_mpfr', 'RealField') +lazy_import('sage.schemes.elliptic_curves.ell_generic', 'EllipticCurve_generic', as_='EllipticCurve') prec = 32 @@ -75,9 +80,8 @@ def _compute_L(self, L): if L == 'tau': return '--tau' return L - import sage.schemes.all - if sage.schemes.elliptic_curves.ell_generic.is_EllipticCurve(L): - if L.base_ring() == sage.rings.all.RationalField(): + if isinstance(L, EllipticCurve): + if L.base_ring() == QQ: L = L.minimal_model() return '-e --a1 %s --a2 %s --a3 %s --a4 %s --a6 %s' % tuple(L.a_invariants()) raise TypeError("$L$-function of %s not known" % L) @@ -127,7 +131,7 @@ def zeros(self, n, L=''): [0.000000000, 5.00317001, 6.87039122] """ L = self._compute_L(L) - RR = sage.rings.all.RealField(prec) + RR = RealField(prec) X = self('-z %s %s' % (int(n), L)) return [RR(z) for z in X.split()] @@ -162,7 +166,7 @@ def zeros_in_interval(self, x, y, stepsize, L=''): [(14.1347251, 0.184672916), (21.0220396, -0.0677893290), (25.0108576, -0.0555872781)] """ L = self._compute_L(L) - RR = sage.rings.all.RealField(prec) + RR = RealField(prec) X = self('--zeros-interval -x %s -y %s --stepsize=%s %s' % ( float(x), float(y), float(stepsize), L)) return [tuple([RR(z) for z in t.split()]) for t in X.split('\n')] @@ -193,7 +197,7 @@ def value(self, s, L=''): 2.69261988568132 - 0.0203860296025982*I """ L = self._compute_L(L) - CC = sage.rings.all.ComplexField(prec) + CC = ComplexField(prec) s = CC(s) x, y = self('-v -x %s -y %s %s' % (s.real(), s.imag(), L)).split() return CC((float(x), float(y))) @@ -275,7 +279,7 @@ def values_along_line(self, s0, s1, number_samples, L=''): """ L = self._compute_L(L) - CC = sage.rings.all.ComplexField(prec) + CC = ComplexField(prec) s0 = CC(s0) s1 = CC(s1) v = self('--value-line-segment -x %s -y %s -X %s -Y %s --number-samples %s %s' % ( @@ -343,8 +347,7 @@ def twist_values(self, s, dmin, dmax, L=''): 0.373691713 + 0.0*I """ L = self._compute_L(L) - CC = sage.rings.all.ComplexField(prec) - Z = sage.rings.all.Integer + CC = ComplexField(prec) s = CC(s) typ = '--twist-quadratic' dmin = int(dmin) @@ -358,7 +361,7 @@ def twist_values(self, s, dmin, dmax, L=''): return w for a in v.split('\n'): d, x, y = a.split() - w.append((Z(d), CC(x, y))) + w.append((ZZ(d), CC(x, y))) return w def twist_zeros(self, n, dmin, dmax, L=''): @@ -393,8 +396,7 @@ def twist_zeros(self, n, dmin, dmax, L=''): {-3: [8.03973716, 11.2492062, 15.7046192], 5: [6.64845335, 9.83144443, 11.9588456]} """ L = self._compute_L(L) - RR = sage.rings.all.RealField(prec) - Z = sage.rings.all.Integer + RR = RealField(prec) typ = '--twist-quadratic' n = int(n) v = self('-z %s %s --start %s --finish %s %s' % ( @@ -405,7 +407,7 @@ def twist_zeros(self, n, dmin, dmax, L=''): for a in v.split('\n'): d, x = a.split() x = RR(x) - d = Z(d) + d = ZZ(d) if d in w: w[d].append(x) else: @@ -439,10 +441,9 @@ def analytic_rank(self, L=''): 1 """ L = self._compute_L(L) - Z = sage.rings.all.Integer s = self('--rank-compute %s' % L) i = s.find('equals') - return Z(s[i + 6:]) + return ZZ(s[i + 6:]) # An instance diff --git a/src/sage/lfunctions/pari.py b/src/sage/lfunctions/pari.py index f75b232e595..bbf289aa21c 100644 --- a/src/sage/lfunctions/pari.py +++ b/src/sage/lfunctions/pari.py @@ -22,7 +22,10 @@ from cypari2.gen import Gen from sage.libs.pari import pari from sage.structure.sage_object import SageObject -from sage.rings.all import (ZZ, RealField, ComplexField, PowerSeriesRing) +from sage.rings.integer_ring import ZZ +from sage.rings.real_mpfr import RealField +from sage.rings.complex_mpfr import ComplexField +from sage.rings.power_series_ring import PowerSeriesRing class lfun_generic(): diff --git a/src/sage/lfunctions/sympow.py b/src/sage/lfunctions/sympow.py index 4cf14233aa2..796e2672d82 100644 --- a/src/sage/lfunctions/sympow.py +++ b/src/sage/lfunctions/sympow.py @@ -51,7 +51,7 @@ from sage.structure.sage_object import SageObject from sage.misc.pager import pager from sage.misc.verbose import verbose -import sage.rings.all +from sage.rings.integer import Integer class Sympow(SageObject): @@ -237,7 +237,7 @@ def modular_degree(self, E): if i == -1: print(self._fix_err(v)) raise RuntimeError("failed to compute modular degree") - return sage.rings.all.Integer(v[i + len(s):]) + return Integer(v[i + len(s):]) def analytic_rank(self, E): r""" @@ -296,7 +296,7 @@ def analytic_rank(self, E): print(self._fix_err(v)) raise RuntimeError("failed to compute analytic rank") j = v.rfind(':') - r = sage.rings.all.Integer(v[i + len(s):j]) + r = Integer(v[i + len(s):j]) i = v.rfind(' ') L = v[i + 1:] return r, L diff --git a/src/sage/lfunctions/zero_sums.pyx b/src/sage/lfunctions/zero_sums.pyx index 2b0ca332b2a..75ee990b1fc 100644 --- a/src/sage/lfunctions/zero_sums.pyx +++ b/src/sage/lfunctions/zero_sums.pyx @@ -18,20 +18,20 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.sage_object cimport SageObject -from sage.rings.integer_ring import ZZ -from sage.rings.real_double import RDF -from sage.rings.complex_double import CDF -from sage.rings.infinity import PlusInfinity -from sage.arith.all import prime_powers, next_prime +from sage.arith.misc import next_prime from sage.functions.log import log, exp from sage.functions.other import real, imag -from sage.symbolic.constants import pi, euler_gamma -from sage.libs.pari.all import pari +from sage.libs.flint.ulong_extras cimport n_is_prime from sage.misc.verbose import verbose from sage.parallel.decorate import parallel from sage.parallel.ncpus import ncpus as num_cpus -from sage.libs.flint.ulong_extras cimport n_is_prime +from sage.rings.complex_double import CDF +from sage.rings.infinity import PlusInfinity +from sage.rings.integer_ring import ZZ +from sage.rings.real_double import RDF +from sage.structure.sage_object cimport SageObject +from sage.symbolic.constants import euler_gamma, pi + cdef extern from "<math.h>": double c_exp "exp"(double) @@ -209,8 +209,8 @@ cdef class LFunctionZeroSum_abstract(SageObject): (11, -0.21799047934530644) """ if not python_floats: - return [self.cn(i) for i in xrange(n + 1)] - return [float(self.cn(i)) for i in xrange(n + 1)] + return [self.cn(i) for i in range(n + 1)] + return [float(self.cn(i)) for i in range(n + 1)] def digamma(self, s, include_constant_term=True): r""" @@ -373,7 +373,6 @@ cdef class LFunctionZeroSum_abstract(SageObject): z = s - 1 sigma = RDF(real(z)) - log2 = log(RDF(2)) # Compute maximum possible Dirichlet series truncation error # When s is in the critical strip: no guaranteed precision if abs(sigma) <= 0.5: @@ -653,7 +652,6 @@ cdef class LFunctionZeroSum_abstract(SageObject): """ npi = self._pi twopi = 2 * npi - eg = self._euler_gamma t = RDF(Delta * twopi) expt = RDF(exp(t)) @@ -746,7 +744,6 @@ cdef class LFunctionZeroSum_abstract(SageObject): from scipy.special import erfcx npi = self._pi - eg = self._euler_gamma Deltasqrtpi = Delta * npi.sqrt() t = RDF(Delta * npi * 2) @@ -1345,7 +1342,6 @@ cdef class LFunctionZeroSum_EllipticCurve(LFunctionZeroSum_abstract): cdef double z = 0 cdef double p = 0 - cdef double q = 0 cdef double sqrtp = 0 cdef double sqrtq = 0 cdef double logp = 0 @@ -1724,7 +1720,7 @@ cdef class LFunctionZeroSum_EllipticCurve(LFunctionZeroSum_abstract): sage: N = 3455601108357547341532253864901605231198511505793733138900595189472144724781456635380154149870961231592352897621963802238155192936274322687070 sage: Z = LFunctionZeroSum(E,N) sage: Z.analytic_rank_upper_bound(max_Delta=2.37,adaptive=False, # long time - ....: root_number=1,bad_primes=bad_primes,ncpus=2) # long time + ....: root_number=1,bad_primes=bad_primes,ncpus=2) 32 """ # Helper function: compute zero sum and apply parity if not False diff --git a/src/sage/libs/all.py b/src/sage/libs/all.py index 9fd69e148ff..50423191ca4 100644 --- a/src/sage/libs/all.py +++ b/src/sage/libs/all.py @@ -14,4 +14,6 @@ lazy_import('sage.libs.eclib.mwrank', 'set_precision', 'mwrank_set_precision') lazy_import('sage.libs.eclib.mwrank', 'initprimes', 'mwrank_initprimes') +lazy_import('sage.libs.flint.qsieve', 'qsieve') + lazy_import('sage.libs.giac.giac', 'libgiac') diff --git a/src/sage/combinat/posets/__init__.py b/src/sage/libs/all__sagemath_coxeter3.py similarity index 100% rename from src/sage/combinat/posets/__init__.py rename to src/sage/libs/all__sagemath_coxeter3.py diff --git a/src/sage/combinat/rigged_configurations/__init__.py b/src/sage/libs/all__sagemath_meataxe.py similarity index 100% rename from src/sage/combinat/rigged_configurations/__init__.py rename to src/sage/libs/all__sagemath_meataxe.py diff --git a/src/sage/combinat/root_system/__init__.py b/src/sage/libs/all__sagemath_sirocco.py similarity index 100% rename from src/sage/combinat/root_system/__init__.py rename to src/sage/libs/all__sagemath_sirocco.py diff --git a/src/sage/libs/arb/arb_version.pyx b/src/sage/libs/arb/arb_version.pyx index 6ad567e67ce..55736c392e9 100644 --- a/src/sage/libs/arb/arb_version.pyx +++ b/src/sage/libs/arb/arb_version.pyx @@ -1,5 +1,5 @@ # -*- coding: utf-8 -from sage.libs.arb.arb cimport arb_version +from sage.libs.arb.arb cimport arb_version from sage.cpython.string cimport char_to_str def version(): diff --git a/src/sage/libs/arb/arith.pyx b/src/sage/libs/arb/arith.pyx index d885f97b238..3b32fe7e8ed 100644 --- a/src/sage/libs/arb/arith.pyx +++ b/src/sage/libs/arb/arith.pyx @@ -81,5 +81,5 @@ def hilbert_class_polynomial(D): cdef long n = D cdef Polynomial_integer_dense_flint poly poly = PolynomialRing(ZZ, "x", implementation="FLINT")() - acb_modular_hilbert_class_poly(poly.__poly, n) + acb_modular_hilbert_class_poly(poly._poly, n) return poly diff --git a/src/sage/combinat/sf/__init__.py b/src/sage/libs/coxeter3/all__sagemath_coxeter3.py similarity index 100% rename from src/sage/combinat/sf/__init__.py rename to src/sage/libs/coxeter3/all__sagemath_coxeter3.py diff --git a/src/sage/libs/coxeter3/coxeter.pxd b/src/sage/libs/coxeter3/coxeter.pxd index cffa2505e39..dbd2b8a61c6 100644 --- a/src/sage/libs/coxeter3/coxeter.pxd +++ b/src/sage/libs/coxeter3/coxeter.pxd @@ -1,3 +1,5 @@ +# sage_setup: distribution = sagemath-coxeter3 + #***************************************************************************** # Copyright (C) 2009-2013 Mike Hansen <mhansen@gmail.com> # @@ -27,6 +29,3 @@ cdef class CoxGroupElement: cdef CoxGroup _parent_group cdef CoxGroupElement _new(self) cpdef CoxGroup parent_group(self) - -cdef class CoxGraph: - cdef c_CoxGraph x diff --git a/src/sage/libs/coxeter3/coxeter.pyx b/src/sage/libs/coxeter3/coxeter.pyx index 9ef1d075be5..492afca2768 100644 --- a/src/sage/libs/coxeter3/coxeter.pyx +++ b/src/sage/libs/coxeter3/coxeter.pyx @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # distutils: language = c++ # distutils: libraries = coxeter3 # sage_setup: distribution = sagemath-coxeter3 @@ -87,8 +86,10 @@ cdef class String: sage: all([tb > ta1, tb >= ta1, tb >= tb]) # optional - coxeter3 True """ - if type(other) != type(self): - return False + if type(other) is not type(self): + if op in (Py_LT, Py_LE, Py_GT, Py_GE): + return NotImplemented + return op == Py_NE s = repr(self) o = repr(other) @@ -200,8 +201,10 @@ cdef class Type: sage: all([tb > ta1, tb >= ta1, tb >= tb]) # optional - coxeter3 True """ - if type(other) != type(self): - return False + if type(other) is not type(self): + if op in (Py_LT, Py_LE, Py_GT, Py_GE): + return NotImplemented + return op == Py_NE s = repr(self) o = repr(other) @@ -364,8 +367,10 @@ cdef class CoxGroup(SageObject): sage: B4 >= A5 # optional - coxeter3 True """ - if type(other) != type(self): - return False + if type(other) is not type(self): + if op in (Py_LT, Py_LE, Py_GT, Py_GE): + return NotImplemented + return op == Py_NE s_t = self.type() o_t = other.type() @@ -777,7 +782,7 @@ cdef class CoxGroupElement: """ if isinstance(i, slice): #Get the start, stop, and step from the slice - return [self[ii] for ii in xrange(*i.indices(len(self)))] + return [self[ii] for ii in range(*i.indices(len(self)))] if i < 0: i += len(self) if i >= len(self): @@ -840,8 +845,10 @@ cdef class CoxGroupElement: sage: w1 != v1 # optional - coxeter3 True """ - if type(other) != type(self): - return False + if type(other) is not type(self): + if op in (Py_LT, Py_LE, Py_GT, Py_GE): + return NotImplemented + return op == Py_NE s_p = self.parent_group() o_p = other.parent_group() @@ -873,7 +880,7 @@ cdef class CoxGroupElement: sage: [a for a in w] # optional - coxeter3 [1, 2, 3] """ - return (self[i] for i in xrange(len(self))) + return (self[i] for i in range(len(self))) def __len__(self): """ diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 7588e6805ea..527cfc61c6f 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -1,4 +1,5 @@ -# -*- coding: utf-8 -*- +# sage_setup: distribution = sagemath-coxeter3 + """ Coxeter Groups implemented with Coxeter3 """ @@ -15,7 +16,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper from sage.structure.richcmp import richcmp -from sage.categories.all import CoxeterGroups +from sage.categories.coxeter_groups import CoxeterGroups from sage.structure.parent import Parent from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix @@ -37,7 +38,7 @@ def __classcall__(cls, cartan_type, *args, **options): Coxeter group of type ['B', 3] relabelled by {1: 3, 2: 2, 3: 1} implemented by Coxeter3 """ - from sage.combinat.all import CartanType + from sage.combinat.root_system.cartan_type import CartanType ct = CartanType(cartan_type) return super().__classcall__(cls, ct, *args, **options) diff --git a/src/sage/libs/coxeter3/decl.pxd b/src/sage/libs/coxeter3/decl.pxd index 56002154226..4f9c7b0c186 100644 --- a/src/sage/libs/coxeter3/decl.pxd +++ b/src/sage/libs/coxeter3/decl.pxd @@ -1,3 +1,5 @@ +# sage_setup: distribution = sagemath-coxeter3 + #***************************************************************************** # Copyright (C) 2009-2013 Mike Hansen <mhansen@gmail.com> # diff --git a/src/sage/libs/ecl.pyx b/src/sage/libs/ecl.pyx index 8f46570313d..a8e73e57b52 100644 --- a/src/sage/libs/ecl.pyx +++ b/src/sage/libs/ecl.pyx @@ -563,15 +563,15 @@ cdef class EclObject: Floats in Python are IEEE double, which LISP has as well. However, the printing of floating point types in LISP depends on settings:: - sage: a = EclObject(float(10^40)) + sage: a = EclObject(float(1.234e40)) sage: ecl_eval("(setf *read-default-float-format* 'single-float)") <ECL: SINGLE-FLOAT> sage: a - <ECL: 1.d40> + <ECL: 1.234d40> sage: ecl_eval("(setf *read-default-float-format* 'double-float)") <ECL: DOUBLE-FLOAT> sage: a - <ECL: 1.e40> + <ECL: 1.234e40> Tuples are translated to dotted lists:: diff --git a/src/sage/libs/eclib/constructor.py b/src/sage/libs/eclib/constructor.py index 19c39739b02..d8881077a75 100644 --- a/src/sage/libs/eclib/constructor.py +++ b/src/sage/libs/eclib/constructor.py @@ -44,7 +44,7 @@ def CremonaModularSymbols(level, sign=0, cuspidal=False, verbose=0): sage: M Cremona Modular Symbols space of dimension 7 for Gamma_0(43) of weight 2 with sign 0 - The input must be valid or a ValueError is raised:: + The input must be valid or a :class:`ValueError` is raised:: sage: M = CremonaModularSymbols(-1) Traceback (most recent call last): diff --git a/src/sage/libs/eclib/homspace.pyx b/src/sage/libs/eclib/homspace.pyx index 3feea84fda7..dc52b144328 100644 --- a/src/sage/libs/eclib/homspace.pyx +++ b/src/sage/libs/eclib/homspace.pyx @@ -3,18 +3,16 @@ from cysignals.signals cimport sig_on, sig_off from cython.operator cimport dereference as deref from cython.operator cimport preincrement as inc -from libcpp.map cimport map -from ..eclib cimport vec, svec, mat, smat +from ..eclib cimport svec, mat, smat from .mat cimport MatrixFactory -from sage.matrix.all import MatrixSpace -from sage.matrix.matrix_integer_sparse cimport Matrix_integer_sparse +from sage.matrix.matrix_space import MatrixSpace from sage.rings.integer_ring import ZZ -from sage.rings.integer cimport Integer cdef MatrixFactory MF = MatrixFactory() + cdef class ModularSymbols: """ Class of Cremona Modular Symbols of given level and sign (and weight 2). diff --git a/src/sage/libs/eclib/interface.py b/src/sage/libs/eclib/interface.py index 0faee97661e..4c842dca48e 100644 --- a/src/sage/libs/eclib/interface.py +++ b/src/sage/libs/eclib/interface.py @@ -194,7 +194,6 @@ def set_verbose(self, verbose): """ self.__verbose = verbose - def _curve_data(self): r""" Returns the underlying :class:`_Curvedata` class for this mwrank elliptic curve. diff --git a/src/sage/libs/eclib/mat.pyx b/src/sage/libs/eclib/mat.pyx index 2ad3474b221..39dee4afc94 100644 --- a/src/sage/libs/eclib/mat.pyx +++ b/src/sage/libs/eclib/mat.pyx @@ -4,7 +4,7 @@ Cremona matrices from ..eclib cimport scalar, addscalar -from sage.matrix.all import MatrixSpace +from sage.matrix.matrix_space import MatrixSpace from sage.rings.integer_ring import ZZ from sage.matrix.matrix_integer_sparse cimport Matrix_integer_sparse diff --git a/src/sage/libs/eclib/mwrank.pyx b/src/sage/libs/eclib/mwrank.pyx index 119d4d49dd4..11219ddefa6 100644 --- a/src/sage/libs/eclib/mwrank.pyx +++ b/src/sage/libs/eclib/mwrank.pyx @@ -18,9 +18,7 @@ EXAMPLES:: sage: t [[1:2:1]] """ - import os -import sys from cysignals.memory cimport sig_free from cysignals.signals cimport sig_on, sig_off @@ -593,9 +591,9 @@ cdef class _mw: Reducing saturation bound from given value 20 to computed index bound 3 Tamagawa index primes are [ 2 ] Checking saturation at [ 2 3 ] - Checking 2-saturation + Checking 2-saturation Points were proved 2-saturated (max q used = 7) - Checking 3-saturation + Checking 3-saturation Points were proved 3-saturated (max q used = 7) done P2 = [-2:3:1] is generator number 2 @@ -603,10 +601,10 @@ cdef class _mw: Reducing saturation bound from given value 20 to computed index bound 4 Tamagawa index primes are [ 2 ] Checking saturation at [ 2 3 ] - Checking 2-saturation + Checking 2-saturation possible kernel vector = [1,1] This point may be in 2E(Q): [14:-52:1] - ...and it is! + ...and it is! Replacing old generator #1 with new generator [1:-1:1] Reducing index bound from 4 to 2 Points have successfully been 2-saturated (max q used = 7) @@ -618,9 +616,9 @@ cdef class _mw: Reducing saturation bound from given value 20 to computed index bound 3 Tamagawa index primes are [ 2 ] Checking saturation at [ 2 3 ] - Checking 2-saturation + Checking 2-saturation Points were proved 2-saturated (max q used = 11) - Checking 3-saturation + Checking 3-saturation Points were proved 3-saturated (max q used = 13) done, index = 1. P4 = [-1:3:1] = -1*P1 + -1*P2 + -1*P3 (mod torsion) @@ -840,7 +838,7 @@ cdef class _mw: - ``sat_bnd`` (int, default -1) -- upper bound on primes at which to saturate. If -1 (default), compute a bound for the primes which may not be saturated, and use that. Otherwise, - the bound used is the minumum of the value of ``sat_bnd`` + the bound used is the minimum of the value of ``sat_bnd`` and the computed bound. - ``sat_low_bd`` (int, default 2) -- only do saturation at diff --git a/src/sage/libs/eclsig.h b/src/sage/libs/eclsig.h index e249ccf6874..005b2d99d0b 100644 --- a/src/sage/libs/eclsig.h +++ b/src/sage/libs/eclsig.h @@ -45,7 +45,11 @@ static inline void ecl_sig_off(void) sig_off(); } +#if ECL_VERSION_NUMBER < 230909 #define ecl_mpz_from_bignum(obj) ((obj)->big.big_num) +#else +#define ecl_mpz_from_bignum(obj) ecl_bignum(obj) +#endif cl_object ecl_bignum_from_mpz(mpz_t num) { diff --git a/src/sage/libs/flint/flint_wrap.h b/src/sage/libs/flint/flint_wrap.h index 1bfb23d0182..266535c3835 100644 --- a/src/sage/libs/flint/flint_wrap.h +++ b/src/sage/libs/flint/flint_wrap.h @@ -36,6 +36,7 @@ #include <flint/fmpq_mat.h> #include <flint/fmpq_poly.h> #include <flint/fmpz.h> +#include <flint/fmpz_factor.h> #include <flint/fmpz_mod.h> #include <flint/fmpz_mat.h> #include <flint/fmpz_poly_mat.h> @@ -50,6 +51,7 @@ #include <flint/padic.h> #include <flint/padic_poly.h> #include <flint/qadic.h> +#include <flint/qsieve.h> #include <flint/ulong_extras.h> #undef ulong diff --git a/src/sage/libs/flint/fmpz_factor.pxd b/src/sage/libs/flint/fmpz_factor.pxd new file mode 100644 index 00000000000..b596e0c04b6 --- /dev/null +++ b/src/sage/libs/flint/fmpz_factor.pxd @@ -0,0 +1,12 @@ +# distutils: libraries = flint +# distutils: depends = flint/fmpz_factor.h + +from sage.libs.flint.types cimport * + +# flint/fmpz_factor.h +cdef extern from "flint_wrap.h": + void fmpz_factor_clear(fmpz_factor_t) + void fmpz_factor_init(fmpz_factor_t) + void fmpz_factor(fmpz_factor_t, const fmpz_t) + +cdef fmpz_factor_to_pairlist(const fmpz_factor_t) diff --git a/src/sage/libs/flint/fmpz_factor.pyx b/src/sage/libs/flint/fmpz_factor.pyx new file mode 100644 index 00000000000..330ba3d4d4e --- /dev/null +++ b/src/sage/libs/flint/fmpz_factor.pyx @@ -0,0 +1,28 @@ +from cysignals.signals cimport sig_check +from sage.libs.flint.fmpz cimport fmpz_get_mpz +from sage.rings.integer cimport Integer + +cdef fmpz_factor_to_pairlist(const fmpz_factor_t factors): + r""" + Helper function that converts a fmpz_factor_t into a list of + (factor, exponent) pairs. The factors are Integers, and the + exponents are Python ints. This is used and indirectly tested by + both :func:`qsieve` and + :func:`sage.rings.factorint_flint.factor_using_flint`. The output + format was ultimately based on that of + :func:`sage.rings.factorint_pari.factor_using_pari`. + """ + cdef list pairs = [] + + if factors.sign < 0: + # FLINT doesn't return the plus/minus one factor. + pairs.append((Integer(-1), int(1))) + + for i in range(factors.num): + f = Integer() + fmpz_get_mpz(f.value, &factors.p[i]) + e = int(factors.exp[i]) + pairs.append((f, e)) + sig_check() + + return pairs diff --git a/src/sage/libs/flint/fmpz_poly.pyx b/src/sage/libs/flint/fmpz_poly.pyx index 23df744b440..74915b37612 100644 --- a/src/sage/libs/flint/fmpz_poly.pyx +++ b/src/sage/libs/flint/fmpz_poly.pyx @@ -27,7 +27,7 @@ from sage.arith.long cimport pyobject_to_long from sage.cpython.string cimport char_to_str, str_to_bytes from sage.structure.sage_object cimport SageObject from sage.rings.integer cimport Integer -from sage.libs.flint.fmpz_poly cimport * + cdef class Fmpz_poly(SageObject): @@ -152,7 +152,7 @@ cdef class Fmpz_poly(SageObject): sage: f.list() [2, 1, 0, -1] """ - return [self[i] for i in xrange(self.degree() + 1)] + return [self[i] for i in range(self.degree() + 1)] def __add__(left, right): """ @@ -222,13 +222,13 @@ cdef class Fmpz_poly(SageObject): """ cdef Fmpz_poly res = <Fmpz_poly>Fmpz_poly.__new__(Fmpz_poly) if not isinstance(left, Fmpz_poly) or not isinstance(right, Fmpz_poly): - if isinstance(left, int) : + if isinstance(left, int): fmpz_poly_scalar_mul_si(res.poly, (<Fmpz_poly>right).poly, left) - elif isinstance(left, Integer) : + elif isinstance(left, Integer): fmpz_poly_scalar_mul_mpz(res.poly, (<Fmpz_poly>right).poly, (<Integer>left).value) - elif isinstance(right, int) : + elif isinstance(right, int): fmpz_poly_scalar_mul_si(res.poly, (<Fmpz_poly>left).poly, right) - elif isinstance(right, Integer) : + elif isinstance(right, Integer): fmpz_poly_scalar_mul_mpz(res.poly, (<Fmpz_poly>left).poly, (<Integer>right).value) else: raise TypeError diff --git a/src/sage/libs/flint/nmod_poly_linkage.pxi b/src/sage/libs/flint/nmod_poly_linkage.pxi index 51c5fa196cb..45f4410d785 100644 --- a/src/sage/libs/flint/nmod_poly_linkage.pxi +++ b/src/sage/libs/flint/nmod_poly_linkage.pxi @@ -22,7 +22,7 @@ from cysignals.memory cimport sig_malloc, sig_free from sage.libs.flint.nmod_poly cimport * from sage.libs.flint.ulong_extras cimport * - +from sage.structure.factorization import Factorization cdef inline celement *celement_new(unsigned long n): cdef celement *g = <celement *>sig_malloc(sizeof(nmod_poly_t)) @@ -644,10 +644,12 @@ cdef factor_helper(Polynomial_zmod_flint poly, bint squarefree=False): cdef nmod_poly_factor_t factors_c nmod_poly_factor_init(factors_c) + sig_on() if squarefree: nmod_poly_factor_squarefree(factors_c, &poly.x) else: nmod_poly_factor(factors_c, &poly.x) + sig_off() factor_list = [] cdef Polynomial_zmod_flint t diff --git a/src/sage/libs/flint/qsieve.pxd b/src/sage/libs/flint/qsieve.pxd new file mode 100644 index 00000000000..ceab7a684a6 --- /dev/null +++ b/src/sage/libs/flint/qsieve.pxd @@ -0,0 +1,8 @@ +# distutils: libraries = flint +# distutils: depends = flint/qsieve.h + +from sage.libs.flint.types cimport * + +# flint/qsieve.h +cdef extern from "flint_wrap.h": + void qsieve_factor(fmpz_factor_t, const fmpz_t) diff --git a/src/sage/libs/flint/qsieve.pyx b/src/sage/libs/flint/qsieve.pyx new file mode 100644 index 00000000000..7d93d41f4cc --- /dev/null +++ b/src/sage/libs/flint/qsieve.pyx @@ -0,0 +1,63 @@ +""" +Interface to FLINT's ``qsieve_factor()``. This used to interact +with an external "QuadraticSieve" program, but its functionality has +been absorbed into flint. +""" + +from cysignals.signals cimport sig_on, sig_off +from sage.libs.flint.fmpz cimport fmpz_t, fmpz_init, fmpz_set_mpz +from sage.libs.flint.fmpz_factor cimport * +from sage.rings.integer cimport Integer + + +def qsieve(n): + r""" + Factor ``n`` using the quadratic sieve. + + INPUT: + + - ``n`` -- an integer; neither prime nor a perfect power. + + OUTPUT: + + A list of the factors of ``n``. There is no guarantee that the + factors found will be prime, or distinct. + + EXAMPLES:: + + sage: k = 19; n = next_prime(10^k)*next_prime(10^(k+1)) + sage: factor(n) # (currently) uses PARI + 10000000000000000051 * 100000000000000000039 + sage: qsieve(n) + [(10000000000000000051, 1), (100000000000000000039, 1)] + + TESTS: + + The factorization of zero is undefined, to match the behavior of + ``ZZ.zero().factor()``:: + + sage: qsieve(ZZ.zero()) + Traceback (most recent call last): + ... + ArithmeticError: factorization of 0 is not defined + + """ + n = Integer(n) + + if n.is_zero(): + raise ArithmeticError("factorization of 0 is not defined") + + cdef fmpz_t p + fmpz_init(p) + fmpz_set_mpz(p, (<Integer>n).value) + + cdef fmpz_factor_t factors + fmpz_factor_init(factors) + sig_on() + qsieve_factor(factors, p) + sig_off() + + pairs = fmpz_factor_to_pairlist(factors) + + fmpz_factor_clear(factors) + return pairs diff --git a/src/sage/libs/flint/types.pxd b/src/sage/libs/flint/types.pxd index 7208f89d9aa..aee66dc9aa2 100644 --- a/src/sage/libs/flint/types.pxd +++ b/src/sage/libs/flint/types.pxd @@ -1,4 +1,4 @@ -# distutils: depends = flint/flint.h flint/fmpz.h flint/fmpz_poly.h flint/fmpz_mat.h flint/fmpq.h flint/fmpq_poly.h flint/fmpq_mat.h flint/fmpz_mod_poly.h flint/nmod_poly.h flint/fq.h flint/fq_nmod.h flint/ulong_extras.h flint/padic.h flint/padic_poly.h flint/qadic.h flint/fmpz_poly_q.h +# distutils: depends = flint/flint.h flint/fmpz.h flint/fmpz_factor.h flint/fmpz_poly.h flint/fmpz_mat.h flint/fmpq.h flint/fmpq_poly.h flint/fmpq_mat.h flint/fmpz_mod_poly.h flint/nmod_poly.h flint/fq.h flint/fq_nmod.h flint/ulong_extras.h flint/padic.h flint/padic_poly.h flint/qadic.h flint/fmpz_poly_q.h """ Declarations for FLINT types @@ -42,6 +42,17 @@ cdef extern from "flint_wrap.h": ctypedef fmpz_preinvn_struct[1] fmpz_preinvn_t +# flint/fmpz_factor.h: +cdef extern from "flint_wrap.h": + ctypedef struct fmpz_factor_struct: + int sign + fmpz* p + ulong* exp + slong alloc + slong num + + ctypedef fmpz_factor_struct fmpz_factor_t[1] + # flint/fmpz_mod.h: cdef extern from "flint_wrap.h": ctypedef struct fmpz_mod_ctx_struct: diff --git a/src/sage/libs/gap/__init__.py b/src/sage/libs/gap/__init__.py deleted file mode 100644 index faee3554865..00000000000 --- a/src/sage/libs/gap/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# libgap diff --git a/src/sage/libs/gap/all_documented_functions.py b/src/sage/libs/gap/all_documented_functions.py index 7554a08f91f..0820dc71064 100644 --- a/src/sage/libs/gap/all_documented_functions.py +++ b/src/sage/libs/gap/all_documented_functions.py @@ -14,11 +14,9 @@ sage: List(_, Order) [ 2, 4, 2 ] """ - from sage.libs.gap.libgap import libgap from sage.libs.gap.assigned_names import FUNCTIONS as _FUNCTIONS - for _f in _FUNCTIONS: globals()[_f] = libgap.function_factory(_f) diff --git a/src/sage/libs/gap/element.pxd b/src/sage/libs/gap/element.pxd index a1bf8118d4f..d6bf4f8b3ff 100644 --- a/src/sage/libs/gap/element.pxd +++ b/src/sage/libs/gap/element.pxd @@ -15,7 +15,7 @@ from sage.structure.element cimport Element, ModuleElement, RingElement cdef Obj make_gap_list(sage_list) except NULL cdef Obj make_gap_matrix(sage_list, gap_ring) except NULL cdef Obj make_gap_record(sage_dict) except NULL -cdef Obj make_gap_integer(sage_dict) except NULL +cdef Obj make_gap_integer(sage_int) except NULL cdef Obj make_gap_string(sage_string) except NULL cdef GapElement make_any_gap_element(parent, Obj obj) diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index c555ea0333c..478caf9f9d0 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -5,7 +5,6 @@ This document describes the individual wrappers for various GAP elements. For general information about GAP, you should read the :mod:`~sage.libs.gap.libgap` module documentation. """ - # **************************************************************************** # Copyright (C) 2012 Volker Braun <vbraun.name@gmail.com> # @@ -24,38 +23,14 @@ from .libgap import libgap from .util cimport * from .util import GAPError from sage.cpython.string cimport str_to_bytes, char_to_str -from sage.misc.cachefunc import cached_method -from sage.structure.sage_object cimport SageObject -from sage.structure.parent import Parent -from sage.rings.all import ZZ, QQ, RDF +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.real_double import RDF from sage.groups.perm_gps.permgroup_element cimport PermutationGroupElement from sage.combinat.permutation import Permutation from sage.structure.coerce cimport coercion_model as cm -decode_type_number = { - 0: 'T_INT (integer)', - T_INTPOS: 'T_INTPOS (positive integer)', - T_INTNEG: 'T_INTNEG (negative integer)', - T_RAT: 'T_RAT (rational number)', - T_CYC: 'T_CYC (universal cyclotomic)', - T_FFE: 'T_FFE (finite field element)', - T_PERM2: 'T_PERM2', - T_PERM4: 'T_PERM4', - T_BOOL: 'T_BOOL', - T_CHAR: 'T_CHAR', - T_FUNCTION: 'T_FUNCTION', - T_PLIST: 'T_PLIST', - T_PLIST_CYC: 'T_PLIST_CYC', - T_BLIST: 'T_BLIST', - T_STRING: 'T_STRING', - T_MACFLOAT: 'T_MACFLOAT (hardware floating point number)', - T_COMOBJ: 'T_COMOBJ (component object)', - T_POSOBJ: 'T_POSOBJ (positional object)', - T_DATOBJ: 'T_DATOBJ (data object)', - T_WPOBJ: 'T_WPOBJ (weak pointer object)', - } - ############################################################################ ### helper functions to construct lists and records ######################## ############################################################################ @@ -72,16 +47,23 @@ cdef Obj make_gap_list(sage_list) except NULL: The list of the elements in ``a`` as a Gap ``Obj``. """ - cdef GapElement l = libgap.eval('[]') + cdef Obj l cdef GapElement elem - for x in sage_list: - if not isinstance(x, GapElement): - elem = <GapElement>libgap(x) - else: - elem = <GapElement>x + cdef int i + try: + GAP_Enter() + l = GAP_NewPlist(0) - AddList(l.value, elem.value) - return l.value + for i, x in enumerate(sage_list): + if not isinstance(x, GapElement): + elem = <GapElement>libgap(x) + else: + elem = <GapElement>x + + GAP_AssList(l, i + 1, elem.value) + return l + finally: + GAP_Leave() cdef Obj make_gap_matrix(sage_list, gap_ring) except NULL: @@ -102,22 +84,30 @@ cdef Obj make_gap_matrix(sage_list, gap_ring) except NULL: The list of the elements in ``sage_list`` as a Gap ``Obj``. """ - cdef GapElement l = libgap.eval('[]') + cdef Obj l cdef GapElement elem cdef GapElement one + cdef int i if gap_ring is not None: one = <GapElement>gap_ring.One() else: one = <GapElement>libgap(1) - for x in sage_list: - if not isinstance(x, GapElement): - elem = <GapElement>libgap(x) - elem = elem * one - else: - elem = <GapElement>x - AddList(l.value, elem.value) - return l.value + try: + GAP_Enter() + l = GAP_NewPlist(0) + + for i, x in enumerate(sage_list): + if not isinstance(x, GapElement): + elem = <GapElement>libgap(x) + elem = elem * one + else: + elem = <GapElement>x + + GAP_AssList(l, i + 1, elem.value) + return l + finally: + GAP_Leave() cdef char *capture_stdout(Obj func, Obj obj): @@ -129,7 +119,7 @@ cdef char *capture_stdout(Obj func, Obj obj): print objects such as ``Print()`` and ``ViewObj()``. """ cdef Obj s, stream, output_text_string - cdef UInt res + cdef Obj l # The only way to get a string representation of an object that is truly # consistent with how it would be represented at the GAP REPL is to call # ViewObj on it. Unfortunately, ViewObj *prints* to the output stream, @@ -143,15 +133,14 @@ cdef char *capture_stdout(Obj func, Obj obj): GAP_Enter() s = NEW_STRING(0) output_text_string = GAP_ValueGlobalVariable("OutputTextString") - stream = CALL_2ARGS(output_text_string, s, GAP_True) + stream = GAP_CallFunc2Args(output_text_string, s, GAP_True) - if not OpenOutputStream(stream): - raise GAPError("failed to open output capture stream for " - "representing GAP object") + l = GAP_NewPlist(1) + GAP_AssList(l, 1, obj) - CALL_1ARGS(func, obj) - CloseOutput() - return CSTR_STRING(s) + CALL_WITH_STREAM = GAP_ValueGlobalVariable("CALL_WITH_STREAM") + GAP_CallFunc3Args(CALL_WITH_STREAM, stream, func, l) + return GAP_CSTR_STRING(s) finally: GAP_Leave() @@ -163,9 +152,13 @@ cdef char *gap_element_repr(Obj obj): GAP on the command-line (i.e. when evaluating an expression that returns that object. """ - - cdef Obj func = GAP_ValueGlobalVariable("ViewObj") - return capture_stdout(func, obj) + cdef Obj func + try: + GAP_Enter() + func = GAP_ValueGlobalVariable("ViewObj") + return capture_stdout(func, obj) + finally: + GAP_Leave() cdef char *gap_element_str(Obj obj): @@ -178,13 +171,18 @@ cdef char *gap_element_str(Obj obj): slightly different approach more closely mirroring Python's str/repr difference (though this does not map perfectly onto GAP). """ - cdef Obj func = GAP_ValueGlobalVariable("Print") - return capture_stdout(func, obj) + cdef Obj func + try: + GAP_Enter() + func = GAP_ValueGlobalVariable("Print") + return capture_stdout(func, obj) + finally: + GAP_Leave() cdef Obj make_gap_record(sage_dict) except NULL: """ - Convert Sage lists into Gap lists + Convert Sage dictionary into Gap record INPUT: @@ -207,7 +205,7 @@ cdef Obj make_gap_record(sage_dict) except NULL: try: GAP_Enter() - rec = NEW_PREC(len(data)) + rec = GAP_NewPrecord(len(data)) for d in data: key, val = d rnam = RNamName(str_to_bytes(key)) @@ -234,13 +232,7 @@ cdef Obj make_gap_integer(sage_int) except NULL: sage: libgap(1) # indirect doctest 1 """ - cdef Obj result - try: - GAP_Enter() - result = INTOBJ_INT(<int>sage_int) - return result - finally: - GAP_Leave() + return GAP_NewObjIntFromInt(<int>sage_int) cdef Obj make_gap_string(sage_string) except NULL: @@ -264,7 +256,7 @@ cdef Obj make_gap_string(sage_string) except NULL: try: GAP_Enter() b = str_to_bytes(sage_string) - result = MakeStringWithLen(b, len(b)) + result = GAP_MakeStringWithLen(b, len(b)) return result finally: GAP_Leave() @@ -285,9 +277,9 @@ cdef GapElement make_any_gap_element(parent, Obj obj): TESTS:: - sage: T_CHAR = libgap.eval("'c'"); T_CHAR + sage: x = libgap.eval("'c'"); x "c" - sage: type(T_CHAR) + sage: type(x) <class 'sage.libs.gap.element.GapElement_String'> sage: libgap.eval("['a', 'b', 'c']") # gap strings are also lists of chars @@ -317,9 +309,9 @@ cdef GapElement make_any_gap_element(parent, Obj obj): if obj is NULL: return make_GapElement(parent, obj) num = TNUM_OBJ(obj) - if IS_INT(obj): + if GAP_IsInt(obj): return make_GapElement_Integer(parent, obj) - elif num == T_MACFLOAT: + elif GAP_IsMacFloat(obj): return make_GapElement_Float(parent, obj) elif num == T_CYC: return make_GapElement_Cyclotomic(parent, obj) @@ -333,17 +325,17 @@ cdef GapElement make_any_gap_element(parent, Obj obj): return make_GapElement_Function(parent, obj) elif num == T_PERM2 or num == T_PERM4: return make_GapElement_Permutation(parent, obj) - elif IS_REC(obj): + elif GAP_IsRecord(obj): return make_GapElement_Record(parent, obj) - elif IS_LIST(obj) and LEN_LIST(obj) == 0: + elif GAP_IsList(obj) and GAP_LenList(obj) == 0: # Empty lists are lists and not strings in Python return make_GapElement_List(parent, obj) elif IsStringConv(obj): # GAP strings are lists, too. Make sure this comes before non-empty make_GapElement_List return make_GapElement_String(parent, obj) - elif IS_LIST(obj): + elif GAP_IsList(obj): return make_GapElement_List(parent, obj) - elif num == T_CHAR: + elif GAP_ValueOfChar(obj) != -1: ch = make_GapElement(parent, obj).IntChar().sage() return make_GapElement_String(parent, make_gap_string(chr(ch))) result = make_GapElement(parent, obj) @@ -561,7 +553,7 @@ cdef class GapElement(RingElement): INPUT: - - ``mut`` - (boolean) wheter to return an mutable copy + - ``mut`` - (boolean) whether to return an mutable copy EXAMPLES:: @@ -669,11 +661,10 @@ cdef class GapElement(RingElement): sage: x = libgap(1) sage: x._type_number() - (0, 'T_INT (integer)') + (0, b'integer') """ n = TNUM_OBJ(self.value) - global decode_type_number - name = decode_type_number.get(n, 'unknown') + name = TNAM_OBJ(self.value) return (n, name) def __dir__(self): @@ -729,7 +720,7 @@ cdef class GapElement(RingElement): ... AttributeError: 'some_name' does not define a GAP function """ - if name in ('__dict__', '_getAttributeNames', '__custom_name', 'keys'): + if name in ('__dict__', '_getAttributeNames', '_SageObject__custom_name', 'keys'): raise AttributeError('Python special name, not a GAP function.') try: proxy = make_GapElement_MethodProxy\ @@ -757,7 +748,7 @@ cdef class GapElement(RingElement): sage: libgap(0).__str__() '0' """ - if self.value == NULL: + if self.value == NULL: return 'NULL' s = char_to_str(gap_element_str(self.value)) @@ -779,7 +770,7 @@ cdef class GapElement(RingElement): sage: libgap(0)._repr_() '0' """ - if self.value == NULL: + if self.value == NULL: return 'NULL' s = char_to_str(gap_element_repr(self.value)) @@ -955,7 +946,7 @@ cdef class GapElement(RingElement): sig_on() try: GAP_Enter() - return EQ(self.value, c_other.value) + return GAP_EQ(self.value, c_other.value) finally: GAP_Leave() sig_off() @@ -977,7 +968,7 @@ cdef class GapElement(RingElement): sig_on() try: GAP_Enter() - return LT(self.value, c_other.value) + return GAP_LT(self.value, c_other.value) finally: GAP_Leave() sig_off() @@ -1005,7 +996,7 @@ cdef class GapElement(RingElement): try: sig_GAP_Enter() sig_on() - result = SUM(self.value, (<GapElement>right).value) + result = GAP_SUM(self.value, (<GapElement>right).value) sig_off() finally: GAP_Leave() @@ -1033,7 +1024,7 @@ cdef class GapElement(RingElement): try: sig_GAP_Enter() sig_on() - result = DIFF(self.value, (<GapElement>right).value) + result = GAP_DIFF(self.value, (<GapElement>right).value) sig_off() finally: GAP_Leave() @@ -1063,7 +1054,7 @@ cdef class GapElement(RingElement): try: sig_GAP_Enter() sig_on() - result = PROD(self.value, (<GapElement>right).value) + result = GAP_PROD(self.value, (<GapElement>right).value) sig_off() finally: GAP_Leave() @@ -1097,7 +1088,7 @@ cdef class GapElement(RingElement): try: sig_GAP_Enter() sig_on() - result = QUO(self.value, (<GapElement>right).value) + result = GAP_QUO(self.value, (<GapElement>right).value) sig_off() finally: GAP_Leave() @@ -1124,7 +1115,7 @@ cdef class GapElement(RingElement): try: sig_GAP_Enter() sig_on() - result = MOD(self.value, (<GapElement>right).value) + result = GAP_MOD(self.value, (<GapElement>right).value) sig_off() finally: GAP_Leave() @@ -1173,7 +1164,7 @@ cdef class GapElement(RingElement): try: sig_GAP_Enter() sig_on() - result = POW(self.value, (<GapElement>other).value) + result = GAP_POW(self.value, (<GapElement>other).value) sig_off() finally: GAP_Leave() @@ -1222,7 +1213,7 @@ cdef class GapElement(RingElement): sage: libgap.eval('3/2').is_list() False """ - return IS_LIST(self.value) + return GAP_IsList(self.value) def is_record(self): r""" @@ -1239,7 +1230,7 @@ cdef class GapElement(RingElement): sage: libgap.eval('rec(a:=1, b:=3)').is_record() True """ - return IS_REC(self.value) + return GAP_IsRecord(self.value) cpdef is_bool(self): r""" @@ -1469,7 +1460,7 @@ cdef class GapElement_Integer(GapElement): sage: N.IsInt() true """ - return IS_INTOBJ(self.value) + return GAP_IsSmallInt(self.value) def _rational_(self): r""" @@ -1520,7 +1511,7 @@ cdef class GapElement_Integer(GapElement): if ring is None: ring = ZZ if self.is_C_int(): - return ring(INT_INTOBJ(self.value)) + return ring(GAP_ValueInt(self.value)) else: # TODO: waste of time! # gap integers are stored as a mp_limb_t and we have a much more direct @@ -1620,7 +1611,7 @@ cdef class GapElement_Float(GapElement): """ if ring is None: ring = RDF - return ring(VAL_MACFLOAT(self.value)) + return ring(GAP_ValueMacFloat(self.value)) def __float__(self): r""" @@ -1629,7 +1620,7 @@ cdef class GapElement_Float(GapElement): sage: float(libgap.eval("Float(3.5)")) 3.5 """ - return VAL_MACFLOAT(self.value) + return GAP_ValueMacFloat(self.value) @@ -2352,7 +2343,7 @@ cdef class GapElement_String(GapElement): sage: type(_) <class 'str'> """ - s = char_to_str(CSTR_STRING(self.value)) + s = char_to_str(GAP_CSTR_STRING(self.value)) return s sage = __str__ @@ -2495,8 +2486,8 @@ cdef class GapElement_Function(GapElement): GAPError: Error, no method found! Error, no 1st choice method found for `SumOp' on 2 arguments - sage: for i in range(0,100): - ....: rnd = [ randint(-10,10) for i in range(0,randint(0,7)) ] + sage: for i in range(100): + ....: rnd = [ randint(-10,10) for i in range(randint(0,7)) ] ....: # compute the sum in GAP ....: _ = libgap.Sum(rnd) ....: try: @@ -2512,9 +2503,9 @@ cdef class GapElement_Function(GapElement): """ cdef Obj result = NULL cdef Obj arg_list - cdef int i, n = len(args) + cdef int n = len(args) - if n > 0: + if n > 0 and n <= 3: libgap = self.parent() a = [x if isinstance(x, GapElement) else libgap(x) for x in args] @@ -2522,43 +2513,22 @@ cdef class GapElement_Function(GapElement): sig_GAP_Enter() sig_on() if n == 0: - result = CALL_0ARGS(self.value) + result = GAP_CallFunc0Args(self.value) elif n == 1: - result = CALL_1ARGS(self.value, + result = GAP_CallFunc1Args(self.value, (<GapElement>a[0]).value) elif n == 2: - result = CALL_2ARGS(self.value, + result = GAP_CallFunc2Args(self.value, (<GapElement>a[0]).value, (<GapElement>a[1]).value) elif n == 3: - result = CALL_3ARGS(self.value, + result = GAP_CallFunc3Args(self.value, (<GapElement>a[0]).value, (<GapElement>a[1]).value, (<GapElement>a[2]).value) - elif n == 4: - result = CALL_4ARGS(self.value, - (<GapElement>a[0]).value, - (<GapElement>a[1]).value, - (<GapElement>a[2]).value, - (<GapElement>a[3]).value) - elif n == 5: - result = CALL_5ARGS(self.value, - (<GapElement>a[0]).value, - (<GapElement>a[1]).value, - (<GapElement>a[2]).value, - (<GapElement>a[3]).value, - (<GapElement>a[4]).value) - elif n == 6: - result = CALL_6ARGS(self.value, - (<GapElement>a[0]).value, - (<GapElement>a[1]).value, - (<GapElement>a[2]).value, - (<GapElement>a[3]).value, - (<GapElement>a[4]).value, - (<GapElement>a[5]).value) - elif n >= 7: + else: arg_list = make_gap_list(args) - result = CALL_XARGS(self.value, arg_list) + result = GAP_CallFuncList(self.value, arg_list) sig_off() finally: GAP_Leave() @@ -2763,7 +2733,7 @@ cdef class GapElement_List(GapElement): sage: len(lst) 4 """ - return LEN_LIST(self.value) + return GAP_LenList(self.value) def __getitem__(self, i): r""" @@ -2811,15 +2781,15 @@ cdef class GapElement_List(GapElement): if isinstance(i, tuple): for j in i: - if not IS_LIST(obj): + if not GAP_IsList(obj): raise ValueError('too many indices') - if j < 0 or j >= LEN_LIST(obj): + if j < 0 or j >= GAP_LenList(obj): raise IndexError('index out of range') obj = ELM_LIST(obj, j+1) else: j = i - if j < 0 or j >= LEN_LIST(obj): + if j < 0 or j >= GAP_LenList(obj): raise IndexError('index out of range.') obj = ELM_LIST(obj, j+1) @@ -2882,12 +2852,12 @@ cdef class GapElement_List(GapElement): if isinstance(i, tuple): for j in i[:-1]: - if not IS_LIST(obj): + if not GAP_IsList(obj): raise ValueError('too many indices') - if j < 0 or j >= LEN_LIST(obj): + if j < 0 or j >= GAP_LenList(obj): raise IndexError('index out of range') obj = ELM_LIST(obj, j+1) - if not IS_LIST(obj): + if not GAP_IsList(obj): raise ValueError('too many indices') j = i[-1] else: @@ -2902,7 +2872,7 @@ cdef class GapElement_List(GapElement): else: celt= self.parent()(elt) - ASS_LIST(obj, j+1, celt.value) + GAP_AssList(obj, j+1, celt.value) def sage(self, **kwds): r""" @@ -3077,7 +3047,7 @@ cdef class GapElement_Permutation(GapElement): lst = libgap.ListPerm(self) if parent is None: - return Permutation(lst.sage(), check_input=False) + return Permutation(lst.sage(), check=False) else: return parent.one()._generate_new_GAP(lst) @@ -3306,7 +3276,7 @@ cdef class GapElement_RecordIterator(): raise StopIteration # note the abs: negative values mean the rec keys are not sorted key_index = abs(GET_RNAM_PREC(self.rec.value, i)) - key = char_to_str(CSTR_STRING(NAME_RNAM(key_index))) + key = char_to_str(GAP_CSTR_STRING(NAME_RNAM(key_index))) cdef Obj result = GET_ELM_PREC(self.rec.value,i) val = make_any_gap_element(self.rec.parent(), result) self.i += 1 diff --git a/src/sage/libs/gap/gap_functions.py b/src/sage/libs/gap/gap_functions.py index 8fb29399479..5e35ca672bf 100644 --- a/src/sage/libs/gap/gap_functions.py +++ b/src/sage/libs/gap/gap_functions.py @@ -7,11 +7,10 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ############################################################################### - # selected gap functions to use in tab completion common_gap_functions = set([ 'AbelianGroup', diff --git a/src/sage/libs/gap/gap_includes.pxd b/src/sage/libs/gap/gap_includes.pxd index 6d22e32540b..1ed4378a6c7 100644 --- a/src/sage/libs/gap/gap_includes.pxd +++ b/src/sage/libs/gap/gap_includes.pxd @@ -9,11 +9,11 @@ # http://www.gnu.org/licenses/ ############################################################################### -from libc.stdint cimport uintptr_t, uint8_t, uint16_t, uint32_t, uint64_t +from libc.stdint cimport intptr_t, uintptr_t, uint8_t, uint16_t, uint32_t, uint64_t cdef extern from "gap/system.h" nogil: ctypedef char Char - ctypedef int Int + ctypedef intptr_t Int ctypedef uintptr_t UInt ctypedef uint8_t UInt1 ctypedef uint16_t UInt2 @@ -22,62 +22,8 @@ cdef extern from "gap/system.h" nogil: ctypedef void* Obj -cdef extern from "gap/ariths.h" nogil: - Obj SUM(Obj, Obj) - Obj DIFF(Obj, Obj) - Obj PROD(Obj, Obj) - Obj QUO(Obj, Obj) - Obj POW(Obj, Obj) - Obj MOD(Obj, Obj) - bint EQ(Obj opL, Obj opR) - bint LT(Obj opL, Obj opR) - - -cdef extern from "gap/bool.h" nogil: - cdef Obj GAP_True "True" - cdef Obj GAP_False "False" - - cdef extern from "gap/calls.h" nogil: bint IS_FUNC(Obj) - Obj CALL_0ARGS(Obj f) # 0 arguments - Obj CALL_1ARGS(Obj f, Obj a1) # 1 argument - Obj CALL_2ARGS(Obj f, Obj a1, Obj a2) - Obj CALL_3ARGS(Obj f, Obj a1, Obj a2, Obj a3) - Obj CALL_4ARGS(Obj f, Obj a1, Obj a2, Obj a3, Obj a4) - Obj CALL_5ARGS(Obj f, Obj a1, Obj a2, Obj a3, Obj a4, Obj a5) - Obj CALL_6ARGS(Obj f, Obj a1, Obj a2, Obj a3, Obj a4, Obj a5, Obj a6) - Obj CALL_XARGS(Obj f, Obj args) # more than 6 arguments - - -cdef extern from "gap/gasman.h" nogil: - Obj NewBag "NewBag"(UInt type, UInt size) - void MarkBag(Obj bag) - UInt CollectBags(UInt size, UInt full) - - -cdef extern from "gap/gasman_intern.h" nogil: - void CallbackForAllBags(void (*func)(Obj)) - - -cdef extern from "gap/gvars.h" nogil: - UInt GVarName "GVarName"(char* name) - void AssGVar "AssGVar"(UInt gvar, Obj val) - - -cdef extern from "gap/integer.h" nogil: - Int IS_INT(Obj) - - -cdef extern from "gap/intobj.h" nogil: - bint IS_INTOBJ(Obj obj) - Obj INTOBJ_INT(Int) - Int INT_INTOBJ(Obj) - - -cdef extern from "gap/io.h" nogil: - UInt OpenOutputStream(Obj stream) - UInt CloseOutput() cdef extern from "gap/libgap-api.h" nogil: @@ -98,21 +44,56 @@ cdef extern from "gap/libgap-api.h" nogil: cdef void GAP_Leave() cdef int GAP_Error_Setjmp() except 0 + void GAP_MarkBag(Obj bag) + void GAP_CollectBags(UInt full) -cdef extern from "gap/lists.h" nogil: - bint IS_LIST(Obj lst) - int LEN_LIST(Obj lst) - Obj ELM_LIST(Obj lst, int pos) - Obj ELM0_LIST(Obj lst, int pos) - void ASS_LIST(Obj lst, int pos, Obj elt) + Obj GAP_SUM(Obj, Obj) + Obj GAP_DIFF(Obj, Obj) + Obj GAP_PROD(Obj, Obj) + Obj GAP_QUO(Obj, Obj) + Obj GAP_POW(Obj, Obj) + Obj GAP_MOD(Obj, Obj) + bint GAP_EQ(Obj opL, Obj opR) + bint GAP_LT(Obj opL, Obj opR) + bint GAP_IN(Obj opL, Obj opR) + + cdef Obj GAP_True + cdef Obj GAP_False + Obj GAP_CallFuncList(Obj func, Obj args); + Obj GAP_CallFuncArray(Obj func, UInt narg, Obj * args); + Obj GAP_CallFunc0Args(Obj func); + Obj GAP_CallFunc1Args(Obj func, Obj a1); + Obj GAP_CallFunc2Args(Obj func, Obj a1, Obj a2); + Obj GAP_CallFunc3Args(Obj func, Obj a1, Obj a2, Obj a3); -cdef extern from "gap/listfunc.h" nogil: - void AddList(Obj list, Obj obj) + bint GAP_IsMacFloat(Obj obj) + double GAP_ValueMacFloat(Obj obj) + bint GAP_IsInt(Obj) + bint GAP_IsSmallInt(Obj) + Obj GAP_NewObjIntFromInt(Int val) + Int GAP_ValueInt(Obj) -cdef extern from "gap/macfloat.h" nogil: - double VAL_MACFLOAT(Obj obj) + bint GAP_IsList(Obj lst) + UInt GAP_LenList(Obj lst) + void GAP_AssList(Obj lst, UInt pos, Obj val) + Obj GAP_ElmList(Obj lst, UInt pos) + Obj GAP_NewPlist(Int capacity) + + bint GAP_IsRecord(Obj obj) + Obj GAP_NewPrecord(Int capacity) + + bint GAP_IsString(Obj obj) + UInt GAP_LenString(Obj string) + char* GAP_CSTR_STRING(Obj list) + Obj GAP_MakeStringWithLen(const char* buf, UInt len) + + Int GAP_ValueOfChar(Obj obj) + + +cdef extern from "gap/lists.h" nogil: + Obj ELM_LIST(Obj lst, int pos) cdef extern from "gap/objects.h" nogil: @@ -120,35 +101,19 @@ cdef extern from "gap/objects.h" nogil: Obj SHALLOW_COPY_OBJ(Obj obj) Obj CopyObj(Obj obj, int mut) - UInt SIZE_OBJ(Obj obj) UInt TNUM_OBJ(Obj obj) char* TNAM_OBJ(Obj obj) cdef enum TNUM: - T_INT - T_INTPOS - T_INTNEG T_RAT T_CYC T_FFE - T_MACFLOAT T_PERM2 T_PERM4 - T_TRANS2 - T_TRANS4 - T_PPERM2 - T_PPERM4 T_BOOL - T_CHAR T_FUNCTION - T_PLIST - T_PLIST_CYC - T_BLIST - T_STRING T_COMOBJ T_POSOBJ - T_DATOBJ - T_WPOBJ cdef extern from "gap/permutat.h" nogil: @@ -163,7 +128,6 @@ cdef extern from "gap/permutat.h" nogil: cdef extern from "gap/precord.h" nogil: - Obj NEW_PREC(int len) int LEN_PREC(Obj rec) int GET_RNAM_PREC(Obj rec, int i) Obj GET_ELM_PREC(Obj rec, int i) @@ -172,14 +136,26 @@ cdef extern from "gap/precord.h" nogil: cdef extern from "gap/records.h" nogil: char* NAME_RNAM(UInt rnam) - bint IS_REC(Obj obj) Obj ELM_REC(Obj rec, UInt rnam) UInt RNamName(Char* name) cdef extern from "gap/stringobj.h" nogil: - char* CSTR_STRING(Obj list) bint IS_STRING(Obj obj) bint IsStringConv(Obj obj) Obj NEW_STRING(Int) - Obj MakeStringWithLen(const char* buf, size_t len) + + +cdef extern from "<structmember.h>" nogil: + """ + /* Hack: Cython 3.0 automatically includes <structmember.h>, which + * defines several macros that collides with enum definitions in + * gap/objects.h. We need to include the header explicitly and + * undefine these macros. + */ + #undef T_INT + #undef T_STRING + #undef T_CHAR + #undef T_BOOL + """ + pass diff --git a/src/sage/libs/gap/libgap.pyx b/src/sage/libs/gap/libgap.pyx index b1a64e57939..05ca5f7d4fb 100644 --- a/src/sage/libs/gap/libgap.pyx +++ b/src/sage/libs/gap/libgap.pyx @@ -217,6 +217,7 @@ from .gap_includes cimport * from .util cimport * from .element cimport * +from sage.cpython.string cimport str_to_bytes from sage.structure.parent cimport Parent from sage.structure.element cimport Vector from sage.rings.integer_ring import ZZ @@ -309,7 +310,7 @@ class Gap(Parent): return make_GapElement_Boolean(self, GAP_True if x else GAP_False) elif isinstance(x, int): return make_GapElement_Integer(self, make_gap_integer(x)) - elif isinstance(x, basestring): + elif isinstance(x, str): return make_GapElement_String(self, make_gap_string(x)) elif isinstance(x, Path): return make_GapElement_String(self, make_gap_string(str(x))) @@ -397,7 +398,7 @@ class Gap(Parent): """ cdef GapElement elem - if not isinstance(gap_command, basestring): + if not isinstance(gap_command, str): gap_command = str(gap_command._libgap_init_()) initialize() @@ -478,9 +479,7 @@ class Gap(Parent): 1 sage: libgap.unset_global('FooBar') sage: libgap.get_global('FooBar') - Traceback (most recent call last): - ... - GAPError: Error, VAL_GVAR: No value bound to FooBar + NULL """ is_bound = self.function_factory('IsBoundGlobal') bind_global = self.function_factory('BindGlobal') @@ -503,9 +502,7 @@ class Gap(Parent): 1 sage: libgap.unset_global('FooBar') sage: libgap.get_global('FooBar') - Traceback (most recent call last): - ... - GAPError: Error, VAL_GVAR: No value bound to FooBar + NULL """ is_readonlyglobal = self.function_factory('IsReadOnlyGlobal') make_readwrite = self.function_factory('MakeReadWriteGlobal') @@ -535,12 +532,9 @@ class Gap(Parent): 1 sage: libgap.unset_global('FooBar') sage: libgap.get_global('FooBar') - Traceback (most recent call last): - ... - GAPError: Error, VAL_GVAR: No value bound to FooBar + NULL """ - value_global = self.function_factory('ValueGlobal') - return value_global(variable) + return make_any_gap_element(self, GAP_ValueGlobalVariable(str_to_bytes(variable))) def global_context(self, variable, value): """ @@ -695,7 +689,7 @@ class Gap(Parent): sage: libgap.List <Gap function "List"> sage: libgap.GlobalRandomSource - <RandomSource in IsGlobalRandomSource> + <RandomSource in IsGAPRandomSource> """ if name in dir(self.__class__): return getattr(self.__class__, name) @@ -782,9 +776,7 @@ class Gap(Parent): sage: libgap.collect() """ initialize() - rc = CollectBags(0, 1) - if rc != 1: - raise RuntimeError('Garbage collection failed.') + GAP_CollectBags(1) libgap = Gap() diff --git a/src/sage/libs/gap/saved_workspace.py b/src/sage/libs/gap/saved_workspace.py index ad5adec36d0..7636707f557 100644 --- a/src/sage/libs/gap/saved_workspace.py +++ b/src/sage/libs/gap/saved_workspace.py @@ -8,7 +8,7 @@ import os import glob -from sage.env import GAP_ROOT_DIR +from sage.env import GAP_LIB_DIR from sage.interfaces.gap_workspace import gap_workspace_file @@ -31,7 +31,7 @@ def timestamp(): """ libgap_dir = os.path.dirname(__file__) libgap_files = glob.glob(os.path.join(libgap_dir, '*')) - gap_packages = glob.glob(os.path.join(GAP_ROOT_DIR, 'pkg', '*')) + gap_packages = glob.glob(os.path.join(GAP_LIB_DIR, 'pkg', '*')) files = libgap_files + gap_packages if len(files) == 0: print('Unable to find LibGAP files.') diff --git a/src/sage/libs/gap/util.pyx b/src/sage/libs/gap/util.pyx index 344ab88c42a..3c286d2020d 100644 --- a/src/sage/libs/gap/util.pyx +++ b/src/sage/libs/gap/util.pyx @@ -13,7 +13,7 @@ Utility functions for GAP #***************************************************************************** from libc.signal cimport signal, SIGCHLD, SIG_DFL -from posix.dlfcn cimport dlopen, dlclose, RTLD_NOW, RTLD_GLOBAL +from posix.dlfcn cimport dlopen, dlclose, dlerror, RTLD_LAZY, RTLD_GLOBAL from cpython.exc cimport PyErr_Fetch, PyErr_Restore from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE @@ -157,40 +157,13 @@ cdef void gasman_callback() with gil: """ global owned_objects_refcount for obj in owned_objects_refcount: - MarkBag((<ObjWrapper>obj).value) + GAP_MarkBag((<ObjWrapper>obj).value) ############################################################################ ### Initialization of GAP ################################################## ############################################################################ -def gap_root(): - """ - Find the location of the GAP root install which is stored in the gap - startup script. - - EXAMPLES:: - - sage: from sage.libs.gap.util import gap_root - sage: gap_root() # random output - '/home/vbraun/opt/sage-5.3.rc0/local/gap/latest' - """ - if os.path.exists(sage.env.GAP_ROOT_DIR): - return sage.env.GAP_ROOT_DIR - - # Attempt to figure out the appropriate GAP_ROOT by reading the - # local/bin/gap shell script; this is an ugly hack that exists for - # historical reasons; the best approach to setting where Sage looks for - # the appropriate GAP_ROOT is to set the GAP_ROOT_DIR variable - SAGE_LOCAL = sage.env.SAGE_LOCAL - with open(os.path.join(SAGE_LOCAL, 'bin', 'gap')) as f: - gap_sh = f.read().splitlines() - gapdir = next(x for x in gap_sh if x.strip().startswith('GAP_ROOT')) - gapdir = gapdir.split('"')[1] - gapdir = gapdir.replace('$SAGE_LOCAL', SAGE_LOCAL) - return gapdir - - # To ensure that we call initialize_libgap only once. cdef bint _gap_is_initialized = False @@ -232,12 +205,12 @@ cdef initialize(): # this isn't portable cdef void* handle - libgapname = str_to_bytes(sage.env.GAP_SO) - handle = dlopen(libgapname, RTLD_NOW | RTLD_GLOBAL) + # reload the current module to force reload of libgap (see #33446) + lib = str_to_bytes(__loader__.path, FS_ENCODING, "surrogateescape") + handle = dlopen(lib, RTLD_GLOBAL|RTLD_LAZY) if handle is NULL: - raise RuntimeError( - "Could not dlopen() libgap even though it should already " - "be loaded!") + err = dlerror() + raise RuntimeError(f"Could not reload gap library with RTLD_GLOBAL ({err})") dlclose(handle) # Define argv variable, which we will pass in to @@ -245,7 +218,7 @@ cdef initialize(): cdef char* argv[16] argv[0] = "sage" argv[1] = "-l" - s = str_to_bytes(gap_root(), FS_ENCODING, "surrogateescape") + s = str_to_bytes(sage.env.GAP_LIB_DIR + ";" + sage.env.GAP_SHARE_DIR, FS_ENCODING, "surrogateescape") argv[2] = s argv[3] = "-m" @@ -301,10 +274,6 @@ cdef initialize(): # receive error output GAP_EvalString(_reset_error_output_cmd) - # Prepare global GAP variable to hold temporary GAP objects - global reference_holder - reference_holder = GVarName("$SAGE_libgap_reference_holder") - # Finished! _gap_is_initialized = True @@ -362,15 +331,9 @@ cdef Obj gap_eval(str gap_string) except? NULL: GAPError: Error, Variable: 'Complex' must have a value Syntax error: ; expected in stream:1 Complex Field with 53 bits of precision;; - ^^^^^^^^^^^^ + ^^^^^ Error, Variable: 'with' must have a value - Syntax error: ; expected in stream:1 - Complex Field with 53 bits of precision;; - ^^^^^^^^^^^^^^^^^^^^ Error, Variable: 'bits' must have a value - Syntax error: ; expected in stream:1 - Complex Field with 53 bits of precision;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error, Variable: 'precision' must have a value Test that on a subsequent attempt we get the same message (no garbage was @@ -405,15 +368,15 @@ cdef Obj gap_eval(str gap_string) except? NULL: # If an error occurred in GAP_EvalString we won't even get # here if the error handler was set; but in case it wasn't # let's still check the result... - nresults = LEN_LIST(result) + nresults = GAP_LenList(result) if nresults > 1: # to mimick the old libGAP # TODO: Get rid of this restriction eventually? raise GAPError("can only evaluate a single statement") # Get the result of the first statement - result = ELM0_LIST(result, 1) # 1-indexed! + result = GAP_ElmList(result, 1) # 1-indexed! - if ELM0_LIST(result, 1) != GAP_True: + if GAP_ElmList(result, 1) != GAP_True: # An otherwise unhandled error occurred in GAP (such as a # syntax error). Try running the error handler manually # to capture the error output, if any. @@ -425,35 +388,12 @@ cdef Obj gap_eval(str gap_string) except? NULL: # 0 is returned without setting a Python exception, so we should treat # this like returning None) - return ELM0_LIST(result, 2) + return GAP_ElmList(result, 2) finally: GAP_Leave() sig_off() -########################################################################### -### Helper to protect temporary objects from deletion ###################### -############################################################################ - -# Hold a reference (inside the GAP kernel) to obj so that it doesn't -# get deleted this works by assigning it to a global variable. This is -# very simple, but you can't use it to keep two objects alive. Be -# careful. -cdef UInt reference_holder - -cdef void hold_reference(Obj obj): - """ - Hold a reference (inside the GAP kernel) to obj - - This ensures that the GAP garbage collector does not delete - ``obj``. This works by assigning it to a global variable. This is - very simple, but you can't use it to keep two objects alive. Be - careful. - """ - global reference_holder - AssGVar(reference_holder, obj) - - ############################################################################ ### Error handler ########################################################## ############################################################################ @@ -476,7 +416,7 @@ cdef str extract_libgap_errout(): # Grab a pointer to the C string underlying the GAP string libgap_errout # then copy it to a Python str (char_to_str contains an implicit strcpy) - msg = CSTR_STRING(r) + msg = GAP_CSTR_STRING(r) if msg != NULL: msg_py = char_to_str(msg) msg_py = msg_py.replace('For debugging hints type ?Recovery from ' diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index ccad5169836..c5f738eadc0 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -27,8 +27,7 @@ in giac, but the mathematical computation is not done. This class is mainly for cython users. Here A is a Pygen element, and it is ready for any giac function.:: - sage: from sage.libs.giac.giac import * # random - //... + sage: from sage.libs.giac.giac import * sage: A = Pygen('2+2') sage: A 2+2 @@ -152,9 +151,11 @@ import math # sage includes from sage.ext.stdsage cimport PY_NEW -from sage.libs.gmp.mpz cimport mpz_t, mpz_init_set +from sage.libs.gmp.mpz cimport mpz_set -from sage.rings.all import ZZ, QQ, IntegerModRing +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational from sage.structure.element cimport Matrix @@ -1265,11 +1266,10 @@ cdef class Pygen(GiacMethods_base): GIAC_archive( <string>encstring23(filename), (<Pygen>self).gptr[0], context_ptr) sig_off() - - # NB: with giac <= 1.2.3-57 redim doesn't have a non evaluated for so Pygen('redim') fails. # hence replacement for redim: - def redim(self,a,b=None): + + def redim(self, a, b=None): """ Increase the size of a matrix when possible, otherwise return self. @@ -1408,7 +1408,7 @@ cdef class Pygen(GiacMethods_base): return result else: - raise TypeError("Cannot convert non giac integers to Integer") + raise TypeError("cannot convert non giac integers to Integer") def _rational_(self,Z=None): @@ -1433,7 +1433,7 @@ cdef class Pygen(GiacMethods_base): # giac _RAT_ return ZZ(self.numer()) / ZZ(self.denom()) else: - raise TypeError("Cannot convert non giac _FRAC_ to QQ") + raise TypeError("cannot convert non giac _FRAC_ to QQ") def sage(self): @@ -1676,11 +1676,11 @@ cdef class Pygen(GiacMethods_base): xyplot=[[(u.real())._double,(u.im())._double] for u in l] - if (xyscat != []): - result=scatter_plot(xyscat) + if xyscat: + result = scatter_plot(xyscat) else: - result=line(xyplot) + result = line(xyplot) sig_off() return result @@ -1694,11 +1694,11 @@ cdef class Pygen(GiacMethods_base): # # # # # # # # # # # # # # # # # # # # # # # # # # - def __richcmp__( self, other,op): + def __richcmp__(self, other, op): if not isinstance(other, Pygen): - other=Pygen(other) + other = Pygen(other) if not isinstance(self, Pygen): - self=Pygen(self) + self = Pygen(self) sig_on() result= giacgenrichcmp((<Pygen>self).gptr[0],(<Pygen>other).gptr[0], op, context_ptr ) sig_off() @@ -1707,10 +1707,11 @@ cdef class Pygen(GiacMethods_base): # # Some attributes of the gen class: # + property _type: def __get__(self): sig_on() - result=self.gptr.type + result = self.gptr.type sig_off() return result @@ -1722,41 +1723,36 @@ cdef class Pygen(GiacMethods_base): sig_off() return result - - property _val: # immediate int (type _INT_) """ immediate int value of an _INT_ type gen. """ def __get__(self): - if(self._type == 0): + if self._type == 0: sig_on() - result=self.gptr.val + result = self.gptr.val sig_off() return result else: - raise TypeError("Cannot convert non _INT_ giac gen") - + raise TypeError("cannot convert non _INT_ giac gen") property _double: # immediate double (type _DOUBLE_) """ immediate conversion to float for a gen of _DOUBLE_ type. """ def __get__(self): - if(self._type == 1): + if self._type == 1: sig_on() - result=self.gptr._DOUBLE_val + result = self.gptr._DOUBLE_val sig_off() return result else: - raise TypeError("Cannot convert non _DOUBLE_ giac gen") + raise TypeError("cannot convert non _DOUBLE_ giac gen") property help: def __get__(self): return self._help() - - ################################################### # Add the others methods ################################################### @@ -1766,30 +1762,22 @@ cdef class Pygen(GiacMethods_base): # # def __getattr__(self, name): # return GiacMethods[str(name)](self) - ## + # test - #test def giacAiry_Ai(self, *args): - cdef gen result=GIAC_Airy_Ai(self.gptr[0], context_ptr) + cdef gen result = GIAC_Airy_Ai(self.gptr[0], context_ptr) return _wrap_gen(result) def giacifactor(self, *args): cdef gen result sig_on() - result=GIAC_eval(self.gptr[0], <int>1, context_ptr) - result=GIAC_ifactor(result, context_ptr) + result = GIAC_eval(self.gptr[0], <int>1, context_ptr) + result = GIAC_ifactor(result, context_ptr) sig_off() return _wrap_gen(result) - - - - - - -## ################################################################ # A wrapper from a cpp element of type giac gen to create # # the Python object # @@ -2010,7 +1998,6 @@ class GiacFunctionNoEV(Pygen): # Some convenient settings ############################################################ Pygen('printpow(1)').eval() # default power is ^ -Pygen('add_language(1)').eval() # Add the french keywords in the giac library language. # FIXME: print I for sqrt(-1) instead of i # GIAC_try_parse_i(False,context_ptr); (does not work??) diff --git a/src/sage/libs/gmp/pylong.pyx b/src/sage/libs/gmp/pylong.pyx index 2f7ed35be9d..d5993cca5a5 100644 --- a/src/sage/libs/gmp/pylong.pyx +++ b/src/sage/libs/gmp/pylong.pyx @@ -26,7 +26,6 @@ AUTHORS: from cpython.object cimport Py_SIZE -from cpython.int cimport PyInt_FromLong from cpython.long cimport PyLong_FromLong from cpython.longintrepr cimport _PyLong_New, py_long, digit, PyLong_SHIFT from .mpz cimport * @@ -85,7 +84,7 @@ cdef mpz_get_pyintlong(mpz_srcptr z): if the value is too large. """ if mpz_fits_slong_p(z): - return PyInt_FromLong(mpz_get_si(z)) + return PyLong_FromLong(mpz_get_si(z)) return mpz_get_pylong_large(z) diff --git a/src/sage/libs/lcalc/lcalc_Lfunction.pxd b/src/sage/libs/lcalc/lcalc_Lfunction.pxd index 5edf0844f3e..1d595180a6f 100644 --- a/src/sage/libs/lcalc/lcalc_Lfunction.pxd +++ b/src/sage/libs/lcalc/lcalc_Lfunction.pxd @@ -99,19 +99,19 @@ cdef extern from "lcalc_sage.h": ################ # strange bug, I can't compile without this trick ??? -# it's only used in __typedN +# it's only used in _typedN ctypedef double Double cdef class Lfunction: cdef void *thisptr - cdef void __init_fun(self, char *NAME, int what_type, dirichlet_coeff, long long Period, double q, c_Complex w, int A, double *g, c_Complex *l, int n_poles, c_Complex *p, c_Complex *r) - cdef c_Complex __value(self,c_Complex s,int derivative) - cdef c_Complex __hardy_z_function(self,c_Complex s) - cdef int __compute_rank(self) + cdef void _init_fun(self, char *NAME, int what_type, dirichlet_coeff, long long Period, double q, c_Complex w, int A, double *g, c_Complex *l, int n_poles, c_Complex *p, c_Complex *r) + cdef c_Complex _value(self,c_Complex s,int derivative) + cdef c_Complex _hardy_z_function(self,c_Complex s) + cdef int _compute_rank(self) #strange bug, replacing Double with double gives me a compile error - cdef Double __typedN(self, double T) - cdef void __find_zeros_v(self, double T1, double T2, double stepsize,doublevec *result) - cdef int __find_zeros(self, long count, long start, double max_refine, int rank, const char* message_stamp, doublevec* result) + cdef Double _typedN(self, double T) + cdef void _find_zeros_v(self, double T1, double T2, double stepsize,doublevec *result) + cdef int _find_zeros(self, long count, long start, double max_refine, int rank, const char* message_stamp, doublevec* result) cdef str _repr diff --git a/src/sage/libs/lcalc/lcalc_Lfunction.pyx b/src/sage/libs/lcalc/lcalc_Lfunction.pyx index efb738714cc..7b871ed049f 100644 --- a/src/sage/libs/lcalc/lcalc_Lfunction.pyx +++ b/src/sage/libs/lcalc/lcalc_Lfunction.pyx @@ -99,7 +99,7 @@ cdef class Lfunction: tmpc=CCC(residue[i]) r[i+1] = new_Complex(mpfr_get_d(tmpc.__re, MPFR_RNDN), mpfr_get_d(tmpc.__im, MPFR_RNDN)) - self.__init_fun(NAME, what_type, dirichlet_coefficient, Period, q, w, A, g, l, n_poles, p, r) + self._init_fun(NAME, what_type, dirichlet_coefficient, Period, q, w, A, g, l, n_poles, p, r) if name: name += ': ' @@ -180,7 +180,7 @@ cdef class Lfunction: """ cdef ComplexNumber complexified_s = CCC(s) cdef c_Complex z = new_Complex(mpfr_get_d(complexified_s.__re, MPFR_RNDN), mpfr_get_d(complexified_s.__im, MPFR_RNDN)) - cdef c_Complex result = self.__value(z, derivative) + cdef c_Complex result = self._value(z, derivative) return CCC(result.real(),result.imag()) def hardy_z_function(self, s): @@ -223,7 +223,7 @@ cdef class Lfunction: #This takes s -> .5 + I*s cdef ComplexNumber complexified_s = CCC(0.5)+ CCC(0,1)*CCC(s) cdef c_Complex z = new_Complex(mpfr_get_d(complexified_s.__re, MPFR_RNDN), mpfr_get_d(complexified_s.__im, MPFR_RNDN)) - cdef c_Complex result = self.__hardy_z_function(z) + cdef c_Complex result = self._hardy_z_function(z) return CCC(result.real(),result.imag()) @@ -249,9 +249,9 @@ cdef class Lfunction: 3 """ - return self.__compute_rank() + return self._compute_rank() - def __N(self, T): + def _N(self, T): """ Compute the number of zeroes upto height `T` using the formula for `N(T)` with the error of `S(T)`. Please do not use this. It is only @@ -262,17 +262,17 @@ cdef class Lfunction: sage: from sage.libs.lcalc.lcalc_Lfunction import * sage: chi = DirichletGroup(5)[2] #This is a quadratic character sage: L=Lfunction_from_character(chi, type="complex") - sage: L.__N(10) # abs tol 1e-8 + sage: L._N(10) # abs tol 1e-8 4.0 """ cdef RealNumber real_T=RRR(T) cdef double double_T = mpfr_get_d(real_T.value, MPFR_RNDN) - cdef double res_d = self.__typedN(double_T) + cdef double res_d = self._typedN(double_T) return RRR(res_d) def find_zeros(self, T1, T2, stepsize): """ - Finds zeros on critical line between ``T1`` and ``T2`` using step size + Finds zeros on critical line between ``T1`` and ``T2`` using step size of stepsize. This function might miss zeros if step size is too large. This function computes the zeros of the L-function by using change in signs of areal valued function whose zeros coincide with @@ -323,7 +323,7 @@ cdef class Lfunction: cdef RealNumber real_T2 = RRR(T2) cdef RealNumber real_stepsize = RRR(stepsize) sig_on() - self.__find_zeros_v( mpfr_get_d(real_T1.value, MPFR_RNDN), mpfr_get_d(real_T2.value, MPFR_RNDN), mpfr_get_d(real_stepsize.value, MPFR_RNDN),&result) + self._find_zeros_v( mpfr_get_d(real_T1.value, MPFR_RNDN), mpfr_get_d(real_T2.value, MPFR_RNDN), mpfr_get_d(real_stepsize.value, MPFR_RNDN),&result) sig_off() i=result.size() returnvalue = [] @@ -399,7 +399,7 @@ cdef class Lfunction: cdef const char* message_stamp = "" cdef doublevec result sig_on() - self.__find_zeros(count, start, max_refine, rank, message_stamp, &result) + self._find_zeros(count, start, max_refine, rank, message_stamp, &result) sig_off() returnvalue = [] for i in range(result.size()): @@ -408,25 +408,25 @@ cdef class Lfunction: return returnvalue # Needs to be overriden - cdef void __init_fun(self, char *NAME, int what_type, dirichlet_coeff, long long Period, double q, c_Complex w, int A, double *g, c_Complex *l, int n_poles, c_Complex *p, c_Complex *r): + cdef void _init_fun(self, char *NAME, int what_type, dirichlet_coeff, long long Period, double q, c_Complex w, int A, double *g, c_Complex *l, int n_poles, c_Complex *p, c_Complex *r): raise NotImplementedError - cdef c_Complex __value(self,c_Complex s,int derivative): + cdef c_Complex _value(self,c_Complex s,int derivative): raise NotImplementedError - cdef c_Complex __hardy_z_function(self,c_Complex s): + cdef c_Complex _hardy_z_function(self,c_Complex s): raise NotImplementedError - cdef int __compute_rank(self): + cdef int _compute_rank(self): raise NotImplementedError - cdef double __typedN(self,double T): + cdef double _typedN(self,double T): raise NotImplementedError - cdef void __find_zeros_v(self,double T1, double T2, double stepsize, doublevec *result): + cdef void _find_zeros_v(self,double T1, double T2, double stepsize, doublevec *result): raise NotImplementedError - cdef int __find_zeros(self, long count, long start, double max_refine, int rank, const char* message_stamp, doublevec *result): + cdef int _find_zeros(self, long count, long start, double max_refine, int rank, const char* message_stamp, doublevec *result): raise NotImplementedError ############################################################################## @@ -497,7 +497,7 @@ cdef class Lfunction_I(Lfunction): self._repr += " with integer Dirichlet coefficients" # override - cdef void __init_fun(self, char *NAME, int what_type, dirichlet_coeff, long long Period, double q, c_Complex w, int A, double *g, c_Complex *l, int n_poles, c_Complex *p, c_Complex *r): + cdef void _init_fun(self, char *NAME, int what_type, dirichlet_coeff, long long Period, double q, c_Complex w, int A, double *g, c_Complex *l, int n_poles, c_Complex *p, c_Complex *r): cdef int N = len(dirichlet_coeff) cdef Integer tmpi cdef int * coeffs = new_ints(N+1) #lcalc ignores 0the coefficient @@ -507,22 +507,22 @@ cdef class Lfunction_I(Lfunction): self.thisptr=new_c_Lfunction_I(NAME, what_type, N, coeffs, Period, q, w, A, g, l, n_poles, p, r) del_ints(coeffs) - cdef inline c_Complex __value(self,c_Complex s,int derivative): + cdef inline c_Complex _value(self,c_Complex s,int derivative): return (<c_Lfunction_I *>(self.thisptr)).value(s, derivative, "pure") - cdef inline c_Complex __hardy_z_function(self,c_Complex s): + cdef inline c_Complex _hardy_z_function(self,c_Complex s): return (<c_Lfunction_I *>(self.thisptr)).value(s, 0, "rotated pure") - cdef int __compute_rank(self): + cdef int _compute_rank(self): return (<c_Lfunction_I *>(self.thisptr)).compute_rank() - cdef void __find_zeros_v(self, double T1, double T2, double stepsize, doublevec *result): + cdef void _find_zeros_v(self, double T1, double T2, double stepsize, doublevec *result): (<c_Lfunction_I *>self.thisptr).find_zeros_v(T1,T2,stepsize,result[0]) - cdef double __typedN(self, double T): + cdef double _typedN(self, double T): return (<c_Lfunction_I *>self.thisptr).N(T) - cdef int __find_zeros(self, long count, long start, double max_refine, int rank, const char* message_stamp, doublevec *result): + cdef int _find_zeros(self, long count, long start, double max_refine, int rank, const char* message_stamp, doublevec *result): (<c_Lfunction_I *>self.thisptr).find_zeros(count, start, max_refine, rank, message_stamp, result) # debug tools @@ -633,7 +633,7 @@ cdef class Lfunction_D(Lfunction): self._repr += " with real Dirichlet coefficients" # override - cdef void __init_fun(self, char *NAME, int what_type, dirichlet_coeff, long long Period, double q, c_Complex w, int A, double *g, c_Complex *l, int n_poles, c_Complex *p, c_Complex *r): + cdef void _init_fun(self, char *NAME, int what_type, dirichlet_coeff, long long Period, double q, c_Complex w, int A, double *g, c_Complex *l, int n_poles, c_Complex *p, c_Complex *r): cdef int i cdef RealNumber tmpr cdef int N = len(dirichlet_coeff) @@ -644,23 +644,23 @@ cdef class Lfunction_D(Lfunction): self.thisptr=new_c_Lfunction_D(NAME, what_type, N, coeffs, Period, q, w, A, g, l, n_poles, p, r) del_doubles(coeffs) - cdef inline c_Complex __value(self,c_Complex s,int derivative): + cdef inline c_Complex _value(self,c_Complex s,int derivative): return (<c_Lfunction_D *>(self.thisptr)).value(s, derivative, "pure") - cdef inline c_Complex __hardy_z_function(self,c_Complex s): + cdef inline c_Complex _hardy_z_function(self,c_Complex s): return (<c_Lfunction_D *>(self.thisptr)).value(s, 0, "rotated pure") - cdef inline int __compute_rank(self): + cdef inline int _compute_rank(self): return (<c_Lfunction_D *>(self.thisptr)).compute_rank() - cdef void __find_zeros_v(self, double T1, double T2, double stepsize, doublevec *result): + cdef void _find_zeros_v(self, double T1, double T2, double stepsize, doublevec *result): (<c_Lfunction_D *>self.thisptr).find_zeros_v(T1,T2,stepsize,result[0]) - cdef double __typedN(self, double T): + cdef double _typedN(self, double T): return (<c_Lfunction_D *>self.thisptr).N(T) - cdef int __find_zeros(self, long count, long start,double max_refine, int rank, const char* message_stamp, doublevec *result): + cdef int _find_zeros(self, long count, long start,double max_refine, int rank, const char* message_stamp, doublevec *result): (<c_Lfunction_D *>self.thisptr).find_zeros(count, start, max_refine, rank, message_stamp, result) # debug tools @@ -773,7 +773,7 @@ cdef class Lfunction_C: self._repr += " with complex Dirichlet coefficients" # override - cdef void __init_fun(self, char *NAME, int what_type, dirichlet_coeff, long long Period, double q, c_Complex w, int A, double *g, c_Complex *l, int n_poles, c_Complex *p, c_Complex *r): + cdef void _init_fun(self, char *NAME, int what_type, dirichlet_coeff, long long Period, double q, c_Complex w, int A, double *g, c_Complex *l, int n_poles, c_Complex *p, c_Complex *r): cdef int i cdef int N = len(dirichlet_coeff) cdef ComplexNumber tmpc @@ -788,24 +788,24 @@ cdef class Lfunction_C: del_Complexes(coeffs) - cdef inline c_Complex __value(self,c_Complex s,int derivative): + cdef inline c_Complex _value(self,c_Complex s,int derivative): return (<c_Lfunction_C *>(self.thisptr)).value(s, derivative, "pure") - cdef inline c_Complex __hardy_z_function(self,c_Complex s): + cdef inline c_Complex _hardy_z_function(self,c_Complex s): return (<c_Lfunction_C *>(self.thisptr)).value(s, 0,"rotated pure") - cdef inline int __compute_rank(self): + cdef inline int _compute_rank(self): return (<c_Lfunction_C *>(self.thisptr)).compute_rank() - cdef void __find_zeros_v(self, double T1, double T2, double stepsize, doublevec *result): + cdef void _find_zeros_v(self, double T1, double T2, double stepsize, doublevec *result): (<c_Lfunction_C *>self.thisptr).find_zeros_v(T1,T2,stepsize,result[0]) - cdef double __typedN(self, double T): + cdef double _typedN(self, double T): return (<c_Lfunction_C *>self.thisptr).N(T) - cdef int __find_zeros(self, long count, long start, double max_refine, int rank, const char* message_stamp, doublevec *result): + cdef int _find_zeros(self, long count, long start, double max_refine, int rank, const char* message_stamp, doublevec *result): (<c_Lfunction_C *>self.thisptr).find_zeros(count, start, max_refine, rank, message_stamp, result) # debug tools @@ -873,24 +873,24 @@ cdef class Lfunction_Zeta(Lfunction): self.thisptr = new_c_Lfunction_Zeta() self._repr = "The Riemann zeta function" - cdef inline c_Complex __value(self,c_Complex s,int derivative): + cdef inline c_Complex _value(self,c_Complex s,int derivative): return (<c_Lfunction_Zeta *>(self.thisptr)).value(s, derivative, "pure") - cdef inline c_Complex __hardy_z_function(self,c_Complex s): + cdef inline c_Complex _hardy_z_function(self,c_Complex s): return (<c_Lfunction_Zeta *>(self.thisptr)).value(s, 0, "rotated pure") - cdef inline int __compute_rank(self): + cdef inline int _compute_rank(self): return (<c_Lfunction_Zeta *>(self.thisptr)).compute_rank() - cdef void __find_zeros_v(self, double T1, double T2, double stepsize, doublevec *result): + cdef void _find_zeros_v(self, double T1, double T2, double stepsize, doublevec *result): (<c_Lfunction_Zeta *>self.thisptr).find_zeros_v(T1,T2,stepsize,result[0]) - cdef double __typedN(self, double T): + cdef double _typedN(self, double T): return (<c_Lfunction_Zeta *>self.thisptr).N(T) - cdef int __find_zeros(self, long count, long start, double max_refine, int rank, const char* message_stamp, doublevec *result): + cdef int _find_zeros(self, long count, long start, double max_refine, int rank, const char* message_stamp, doublevec *result): (<c_Lfunction_Zeta *>self.thisptr).find_zeros(count, start, max_refine, rank, message_stamp, result) def __dealloc__(self): @@ -949,17 +949,17 @@ def Lfunction_from_character(chi, type="complex"): OMEGA=1.0/ ( CCC(0,1)**a * (CCC(modulus)).sqrt()/chi.gauss_sum() ) if type == "complex": - dir_coeffs = [CCC(chi(n)) for n in xrange(1, modulus + 1)] + dir_coeffs = [CCC(chi(n)) for n in range(1, modulus + 1)] return Lfunction_C("", 1,dir_coeffs, period,Q,OMEGA,[.5],[a/2.],poles,residues) if type not in ["double", "int"]: raise ValueError("unknown type") if chi.order() != 2: raise ValueError("For non quadratic characters you must use type=\"complex\"") if type == "double": - dir_coeffs = [RRR(chi(n)) for n in xrange(1, modulus + 1)] + dir_coeffs = [RRR(chi(n)) for n in range(1, modulus + 1)] return Lfunction_D("", 1,dir_coeffs, period,Q,OMEGA,[.5],[a/2.],poles,residues) if type == "int": - dir_coeffs = [Integer(chi(n)) for n in xrange(1, modulus + 1)] + dir_coeffs = [Integer(chi(n)) for n in range(1, modulus + 1)] return Lfunction_I("", 1,dir_coeffs, period,Q,OMEGA,[.5],[a/2.],poles,residues) @@ -990,15 +990,13 @@ def Lfunction_from_elliptic_curve(E, number_of_coeffs=10000): True sage: (L.value(0.5, derivative=1) - 0.305999773835200).abs() < 1e-6 True - """ - import sage.libs.lcalc.lcalc_Lfunction Q = RRR(E.conductor()).sqrt() / RRR(2 * pi) poles = [] residues = [] dir_coeffs = E.anlist(number_of_coeffs) dir_coeffs = [RRR(dir_coeffs[i]) / (RRR(i)).sqrt() - for i in xrange(1, number_of_coeffs)] + for i in range(1, number_of_coeffs)] OMEGA = E.root_number() return Lfunction_D("", 2, dir_coeffs, 0, Q, OMEGA, [1], [.5], poles, residues) diff --git a/src/sage/libs/linbox/conversion.pxd b/src/sage/libs/linbox/conversion.pxd index 7794c9edc39..1753277b1f1 100644 --- a/src/sage/libs/linbox/conversion.pxd +++ b/src/sage/libs/linbox/conversion.pxd @@ -177,9 +177,8 @@ cdef inline Vector_integer_dense new_sage_vector_integer_dense(P, DenseVector_in - v -- linbox vector """ cdef Vector_integer_dense res = P() - cdef cppvector[Integer] * vec = &v.refRep() cdef size_t i for i in range(<size_t> res._degree): - mpz_set(res._entries[i], vec[0][i].get_mpz_const()) + mpz_set(res._entries[i], v.getEntry(i).get_mpz_const()) return res diff --git a/src/sage/libs/linbox/linbox.pxd b/src/sage/libs/linbox/linbox.pxd index 9112d151f8b..bfeda4b6042 100644 --- a/src/sage/libs/linbox/linbox.pxd +++ b/src/sage/libs/linbox/linbox.pxd @@ -32,7 +32,6 @@ cdef extern from "linbox/matrix/dense-matrix.h": ctypedef Modular_double Field ctypedef double Element DenseMatrix_Modular_double(Field F, size_t m, size_t n) - DenseMatrix_Modular_double(Field F, Element*, size_t m, size_t n) void setEntry(size_t i, size_t j, Element& a) Element &getEntry(size_t i, size_t j) @@ -42,7 +41,6 @@ cdef extern from "linbox/matrix/dense-matrix.h": ctypedef Modular_float Field ctypedef float Element DenseMatrix_Modular_float(Field F, size_t m, size_t n) - DenseMatrix_Modular_float(Field F, Element*, size_t m, size_t n) void setEntry(size_t i, size_t j, Element& a) Element &getEntry(size_t i, size_t j) @@ -101,7 +99,6 @@ cdef extern from "linbox/vector/vector.h": DenseVector_integer (Field &F) DenseVector_integer (Field &F, long& m) DenseVector_integer (Field &F, cppvector[Integer]&) - cppvector[Element]& refRep() size_t size() void resize(size_t) void resize(size_t n, const Element&) diff --git a/src/sage/libs/linbox/linbox_flint_interface.pyx b/src/sage/libs/linbox/linbox_flint_interface.pyx index 337cdf65754..415cd473947 100644 --- a/src/sage/libs/linbox/linbox_flint_interface.pyx +++ b/src/sage/libs/linbox/linbox_flint_interface.pyx @@ -21,7 +21,7 @@ and C. Pernet. The functions available are: - ``void linbox_fmpz_mat_det(fmpz_t det, fmpz_mat_t A)``: set ``det`` to the determinant of the square matrix ``A`` """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Martin Albrecht # Copyright (C) 2008 Clement Pernet # Copyright (C) 2017-2018 Vincent Delecroix @@ -30,15 +30,13 @@ and C. Pernet. The functions available are: # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -from sage.libs.gmp.types cimport mpz_t, mpz_srcptr, mpz_ptr -from sage.libs.gmp.mpz cimport mpz_set -from sage.libs.flint.types cimport fmpz, fmpz_t +from sage.libs.flint.types cimport fmpz_t from sage.libs.flint.fmpz cimport fmpz_get_mpz, fmpz_set_mpz from sage.libs.flint.fmpz_mat cimport fmpz_mat_entry, fmpz_mat_nrows, fmpz_mat_ncols -from sage.libs.flint.fmpz_poly cimport fmpz_poly_set_coeff_mpz, fmpz_poly_fit_length, _fmpz_poly_set_length, fmpz_poly_one +from sage.libs.flint.fmpz_poly cimport fmpz_poly_set_coeff_mpz, fmpz_poly_fit_length, _fmpz_poly_set_length cimport sage.libs.linbox.givaro as givaro cimport sage.libs.linbox.linbox as linbox diff --git a/src/sage/libs/linkages/padics/API.pxi b/src/sage/libs/linkages/padics/API.pxi index 41db95ef8ae..529fc49a95b 100644 --- a/src/sage/libs/linkages/padics/API.pxi +++ b/src/sage/libs/linkages/padics/API.pxi @@ -201,8 +201,8 @@ cdef inline long cremove(celement out, celement a, long prec, PowComputer_class - ``a`` -- the element whose valuation and unit are desired. - ``prec`` -- a long, used if `a = 0`. - ``prime_pow`` -- the PowComputer for the ring. - - ``reduce_relative`` -- a bint: whether the final result - should be reduced at precision ``prec`` (case ``False``) + - ``reduce_relative`` -- a bint: whether the final result + should be reduced at precision ``prec`` (case ``False``) or ``prec - valuation`` (case ``True``) OUTPUT: diff --git a/src/sage/libs/linkages/padics/Polynomial_ram.pxi b/src/sage/libs/linkages/padics/Polynomial_ram.pxi index 1ac51f1211f..e0584ecb8ad 100644 --- a/src/sage/libs/linkages/padics/Polynomial_ram.pxi +++ b/src/sage/libs/linkages/padics/Polynomial_ram.pxi @@ -55,16 +55,16 @@ cdef inline bint creduce(celement out, celement a, long prec, PowComputer_ prime """ cdef celement ared = a % prime_pow.modulus if ared is a and out is not a: - out.__coeffs = ared.__coeffs[:] + out._coeffs = ared._coeffs[:] else: - out.__coeffs = ared.__coeffs + out._coeffs = ared._coeffs cdef long coeff_prec = prec / prime_pow.e + 1 cdef long break_pt = prec % prime_pow.e - for i in range(len(out.__coeffs)): + for i in range(len(out._coeffs)): if i == break_pt: coeff_prec -= 1 - out.__coeffs[i] = out.__coeffs[i].add_bigoh(coeff_prec) - out.__normalize() + out._coeffs[i] = out._coeffs[i].add_bigoh(coeff_prec) + out._normalize() return out == 0 cdef inline bint creduce_small(celement out, celement a, long prec, PowComputer_ prime_pow) except -1: @@ -116,7 +116,7 @@ cdef inline long cvaluation(celement a, long prec, PowComputer_ prime_pow) excep higher. """ - C = a.__coeffs + C = a._coeffs if not C: return prec cdef long ret = maxordp @@ -161,7 +161,7 @@ cdef inline int cshift(celement shifted, celement rem, celement a, long n, long v = cvaluation(a, prec, prime_pow) notrunc = (v >= -n) if notrunc: - rem.__coeffs = [] + rem._coeffs = [] return cshift_notrunc(shifted, a, n, prec, prime_pow, reduce_afterward) if v > 0: b = prime_pow.poly_ring(0) @@ -185,7 +185,7 @@ cdef inline int cshift(celement shifted, celement rem, celement a, long n, long if reduce_afterward: creduce(shifted, a, prec, prime_pow) else: - shifted.__coeffs = a.__coeffs[:] + shifted._coeffs = a._coeffs[:] cdef inline int cshift_notrunc(celement out, celement a, long n, long prec, PowComputer_ prime_pow, bint reduce_afterward) except -1: r""" @@ -236,7 +236,7 @@ cdef inline int cshift_notrunc(celement out, celement a, long n, long prec, PowC if reduce_afterward: creduce(out, a, prec, prime_pow) else: - out.__coeffs = a.__coeffs[:] + out._coeffs = a._coeffs[:] cdef inline int cinvert(celement out, celement a, long prec, PowComputer_ prime_pow) except -1: r""" @@ -253,7 +253,7 @@ cdef inline int cinvert(celement out, celement a, long prec, PowComputer_ prime_ - ``prime_pow`` -- the ``PowComputer`` for the ring """ - out.__coeffs = prime_pow.invert(a, prec).__coeffs + out._coeffs = prime_pow.invert(a, prec)._coeffs creduce(out, out, prec, prime_pow) cdef inline int cdivunit(celement out, celement a, celement b, long prec, PowComputer_ prime_pow) except -1: @@ -335,7 +335,7 @@ cdef inline cexpansion_next(celement value, expansion_mode mode, long curpower, # the following is specific to the ramified over unramified case. modp_rep, term = value[0]._modp_rep(mode == smallest_mode) if term: - value.__coeffs[0] -= modp_rep + value._coeffs[0] -= modp_rep cshift_notrunc(value, value, -1, curpower, prime_pow, False) return term @@ -354,10 +354,10 @@ cdef inline cexpansion_getitem(celement value, long m, PowComputer_ prime_pow): while m >= 0: modp_rep, term = value[0]._modp_rep() if m: - if len(value.__coeffs): - value.__coeffs[0] -= modp_rep + if len(value._coeffs): + value._coeffs[0] -= modp_rep else: - value.__coeffs.append(-modp_rep) + value._coeffs.append(-modp_rep) cshift_notrunc(value, value, -1, 1, prime_pow, False) m -= 1 return term @@ -379,9 +379,9 @@ cdef int cteichmuller(celement out, celement value, long prec, PowComputer_ prim """ if value[0].valuation() > 0: - out.__coeffs = [] + out._coeffs = [] else: - out.__coeffs = [value[0].parent().teichmuller(value[0])] + out._coeffs = [value[0].parent().teichmuller(value[0])] cdef list ccoefficients(celement x, long valshift, long prec, PowComputer_ prime_pow): """ diff --git a/src/sage/libs/linkages/padics/Polynomial_shared.pxi b/src/sage/libs/linkages/padics/Polynomial_shared.pxi index 738ab9bf457..367bbc2f33d 100644 --- a/src/sage/libs/linkages/padics/Polynomial_shared.pxi +++ b/src/sage/libs/linkages/padics/Polynomial_shared.pxi @@ -106,7 +106,7 @@ cdef inline int ccmp(celement a, celement b, long prec, bint reduce_a, bint redu if not (reduce_a or reduce_b): return 0 if a == b else 1 csub(prime_pow.tmp_ccmp_a, a, b, prec, prime_pow) - coeffs = prime_pow.tmp_ccmp_a.__coeffs + coeffs = prime_pow.tmp_ccmp_a._coeffs cdef long i, coeff_prec, break_pt if prime_pow.e == 1: for i in range(prime_pow.tmp_ccmp_a.degree()+1): @@ -128,14 +128,14 @@ cdef inline long cremove(celement out, celement a, long prec, PowComputer_ prime INPUT: - ``out`` -- a ``celement`` to store the unit part - + - ``a`` -- the ``celement`` whose valuation and unit are desired - + - ``prec`` -- a ``long``, the return value if ``a`` is zero - + - ``prime_pow`` -- the ``PowComputer`` for the ring - - ``reduce_relative`` -- a bint: whether the final result + - ``reduce_relative`` -- a bint: whether the final result should be reduced at precision ``prec`` (case ``False``) or ``prec - valuation`` (case ``True``) @@ -186,9 +186,9 @@ cdef inline int cneg(celement out, celement a, long prec, PowComputer_ prime_pow """ cdef celement ma = -a if ma is a: - out.__coeffs = ma.__coeffs[:] + out._coeffs = ma._coeffs[:] else: - out.__coeffs = ma.__coeffs + out._coeffs = ma._coeffs cdef inline int cadd(celement out, celement a, celement b, long prec, PowComputer_ prime_pow) except -1: r""" @@ -211,9 +211,9 @@ cdef inline int cadd(celement out, celement a, celement b, long prec, PowCompute """ cdef celement sm = a + b if sm is a or sm is b: - out.__coeffs = sm.__coeffs[:] + out._coeffs = sm._coeffs[:] else: - out.__coeffs = sm.__coeffs + out._coeffs = sm._coeffs cdef inline int csub(celement out, celement a, celement b, long prec, PowComputer_ prime_pow) except -1: r""" @@ -236,9 +236,9 @@ cdef inline int csub(celement out, celement a, celement b, long prec, PowCompute """ cdef celement df = a - b if df is a or df is b: - out.__coeffs = df.__coeffs[:] + out._coeffs = df._coeffs[:] else: - out.__coeffs = df.__coeffs + out._coeffs = df._coeffs cdef inline int cmul(celement out, celement a, celement b, long prec, PowComputer_ prime_pow) except -1: r""" @@ -261,9 +261,9 @@ cdef inline int cmul(celement out, celement a, celement b, long prec, PowCompute """ cdef celement pd = a*b if pd is a or pd is b: - out.__coeffs = pd.__coeffs[:] + out._coeffs = pd._coeffs[:] else: - out.__coeffs = pd.__coeffs + out._coeffs = pd._coeffs cdef inline int csetone(celement out, PowComputer_ prime_pow) except -1: r""" @@ -276,7 +276,7 @@ cdef inline int csetone(celement out, PowComputer_ prime_pow) except -1: - ``prime_pow`` -- the ``PowComputer`` for the ring """ - out.__coeffs = [prime_pow.base_ring(1)] + out._coeffs = [prime_pow.base_ring(1)] cdef inline int csetzero(celement out, PowComputer_ prime_pow) except -1: r""" @@ -289,7 +289,7 @@ cdef inline int csetzero(celement out, PowComputer_ prime_pow) except -1: - ``prime_pow`` -- the ``PowComputer`` for the ring """ - out.__coeffs = [] + out._coeffs = [] cdef inline bint cisone(celement a, PowComputer_ prime_pow) except -1: r""" @@ -330,7 +330,7 @@ cdef inline int ccopy(celement out, celement a, PowComputer_ prime_pow) except - - ``prime_pow`` -- the ``PowComputer`` for the ring """ - out.__coeffs = a.__coeffs[:] + out._coeffs = a._coeffs[:] cdef inline cpickle(celement a, PowComputer_ prime_pow): r""" @@ -343,7 +343,7 @@ cdef inline cpickle(celement a, PowComputer_ prime_pow): - ``prime_pow`` the ``PowComputer`` for the ring """ - return a.__coeffs + return a._coeffs cdef inline int cunpickle(celement out, x, PowComputer_ prime_pow) except -1: r""" @@ -358,7 +358,7 @@ cdef inline int cunpickle(celement out, x, PowComputer_ prime_pow) except -1: - ``prime_pow`` -- the ``PowComputer`` for the ring """ - out.__coeffs = x + out._coeffs = x cdef inline long chash(celement a, long ordp, long prec, PowComputer_ prime_pow) except -1: r""" @@ -413,9 +413,9 @@ cdef int cconv(celement out, x, long prec, long valshift, PowComputer_ prime_pow else: xx = prime_pow.poly_ring(x) if xx is x: - out.__coeffs = xx.__coeffs[:] + out._coeffs = xx._coeffs[:] else: - out.__coeffs = xx.__coeffs + out._coeffs = xx._coeffs if valshift > 0: cshift_notrunc(out, out, -valshift, prec, prime_pow, True) elif valshift == 0: @@ -458,12 +458,12 @@ cdef inline long cconv_mpz_t(celement out, mpz_t x, long prec, bint absolute, Po mpz_set(n.value, x) if n: - out.__coeffs = [prime_pow.base_ring(n)] + out._coeffs = [prime_pow.base_ring(n)] if not absolute: valuation = cremove(out, out, prec, prime_pow) creduce(out, out, prec, prime_pow) else: - out.__coeffs = [] + out._coeffs = [] return valuation @@ -492,12 +492,12 @@ cdef inline int cconv_mpz_t_out(mpz_t out, celement x, long valshift, long prec, else: prime_pow.powhelper_cconv_out = x - if len(prime_pow.powhelper_cconv_out.__coeffs) == 0: + if len(prime_pow.powhelper_cconv_out._coeffs) == 0: mpz_set_ui(out, 0) - elif len(prime_pow.powhelper_cconv_out.__coeffs) == 1: + elif len(prime_pow.powhelper_cconv_out._coeffs) == 1: # recursively let the underlying polynomial convert the constant # coefficient to an integer (if possible) - n = ZZ(prime_pow.powhelper_cconv_out.__coeffs[0]) + n = ZZ(prime_pow.powhelper_cconv_out._coeffs[0]) mpz_set(out, n.value) else: raise ValueError("cannot convert to integer") @@ -532,7 +532,7 @@ cdef inline long cconv_mpq_t(celement out, mpq_t x, long prec, bint absolute, Po """ cdef Rational r = PY_NEW(Rational) mpq_set(r.value, x) - out.__coeffs = [prime_pow.base_ring(r)] + out._coeffs = [prime_pow.base_ring(r)] if not absolute: return cremove(out, out, prec, prime_pow) @@ -565,12 +565,12 @@ cdef inline int cconv_mpq_t_out(mpq_t out, celement x, long valshift, long prec, else: prime_pow.powhelper_cconv_out = x - if len(prime_pow.powhelper_cconv_out.__coeffs) == 0: + if len(prime_pow.powhelper_cconv_out._coeffs) == 0: mpq_set_ui(out, 0, 1) - elif len(prime_pow.powhelper_cconv_out.__coeffs) == 1: + elif len(prime_pow.powhelper_cconv_out._coeffs) == 1: # recursively let the underlying polynomial convert the constant # coefficient to a rational (if possible) - c = QQ(prime_pow.powhelper_cconv_out.__coeffs[0]) + c = QQ(prime_pow.powhelper_cconv_out._coeffs[0]) mpq_set(out, c.value) else: raise ValueError("cannot convert to rational") diff --git a/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi b/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi index 60fb9439388..8b1b80cf0a9 100644 --- a/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi +++ b/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi @@ -194,7 +194,7 @@ cdef inline long cremove(celement out, celement a, long prec, PowComputer_ prime - ``a`` -- the element whose valuation and unit are desired. - ``prec`` -- a long, used if `a = 0`. - ``prime_pow`` -- the PowComputer for the ring. - - ``reduce_relative`` -- a bint: whether the final result + - ``reduce_relative`` -- a bint: whether the final result should be reduced at precision ``prec`` (case ``False``) or ``prec - valuation`` (case ``True``) diff --git a/src/sage/libs/linkages/padics/mpz.pxi b/src/sage/libs/linkages/padics/mpz.pxi index a7200b0c4fa..2844a3934f5 100644 --- a/src/sage/libs/linkages/padics/mpz.pxi +++ b/src/sage/libs/linkages/padics/mpz.pxi @@ -367,7 +367,7 @@ cdef inline int csetone(mpz_t out, PowComputer_ prime_pow) except -1: - ``prime_pow`` -- the PowComputer for the ring. """ mpz_set_ui(out, 1) - + cdef inline int csetzero(mpz_t out, PowComputer_ prime_pow) except -1: """ Sets to 0. @@ -378,7 +378,7 @@ cdef inline int csetzero(mpz_t out, PowComputer_ prime_pow) except -1: - ``prime_pow`` -- the PowComputer for the ring. """ mpz_set_ui(out, 0) - + cdef inline bint cisone(mpz_t out, PowComputer_ prime_pow) except -1: """ Returns whether this element is equal to 1. diff --git a/src/sage/libs/linkages/padics/relaxed/API.pxi b/src/sage/libs/linkages/padics/relaxed/API.pxi index 29a051b808c..4e9ea075bb2 100644 --- a/src/sage/libs/linkages/padics/relaxed/API.pxi +++ b/src/sage/libs/linkages/padics/relaxed/API.pxi @@ -362,7 +362,7 @@ cdef inline void element_get_slice(celement res, celement x, long start, long le .. NOTE:: This function only sets up a pointer to the requested slice - (the slice is not copied). Hence any future modification + (the slice is not copied). Hence any future modification of the slice ``res`` will affect the container ``x``. """ pass diff --git a/src/sage/libs/linkages/padics/unram_shared.pxi b/src/sage/libs/linkages/padics/unram_shared.pxi index 10a2f5adde8..708cf7ac736 100644 --- a/src/sage/libs/linkages/padics/unram_shared.pxi +++ b/src/sage/libs/linkages/padics/unram_shared.pxi @@ -41,6 +41,7 @@ def frobenius_unram(self, arithmetic=True): An error will be raised if the parent of self is a ramified extension:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = Qp(5).extension(x^2 - 5) sage: a.frobenius() Traceback (most recent call last): diff --git a/src/sage/libs/meataxe.pxd b/src/sage/libs/meataxe.pxd index 68c8b3467b0..0a928e19c37 100644 --- a/src/sage/libs/meataxe.pxd +++ b/src/sage/libs/meataxe.pxd @@ -1,3 +1,5 @@ +# sage_setup: distribution = sagemath-meataxe + #***************************************************************************** # Copyright (C) 2015 Simon King <simon.king@uni-jena.de> # diff --git a/src/sage/libs/meataxe.pyx b/src/sage/libs/meataxe.pyx index e965b19da0b..40cb7c6a286 100644 --- a/src/sage/libs/meataxe.pyx +++ b/src/sage/libs/meataxe.pyx @@ -1,15 +1,15 @@ # distutils: libraries = mtx # sage_setup: distribution = sagemath-meataxe -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Simon King <simon.king@uni-jena.de> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cpython.exc cimport PyErr_SetObject from cysignals.signals cimport sig_block, sig_unblock @@ -70,7 +70,6 @@ cdef Matrix_t *rawMatrix(int Field, list entries) except NULL: ## to make sure that MeatAxe is initialised. from sage.cpython.string cimport str_to_bytes, char_to_str -import os cdef void sage_meataxe_error_handler(const MtxErrorRecord_t *err): sig_block() diff --git a/src/sage/libs/mpmath/ext_impl.pyx b/src/sage/libs/mpmath/ext_impl.pyx index 15557561806..2d8d2470273 100644 --- a/src/sage/libs/mpmath/ext_impl.pyx +++ b/src/sage/libs/mpmath/ext_impl.pyx @@ -25,7 +25,6 @@ See if :trac:`15118` is fixed:: # http://www.gnu.org/licenses/ #***************************************************************************** -from cpython.int cimport * from cpython.long cimport * from cpython.float cimport * from cpython.complex cimport * @@ -413,11 +412,16 @@ cdef void MPF_neg(MPF *r, MPF *s): Sets r = -s. MPF_neg(x, x) negates in place. """ if s.special: - if s.special == S_ZERO: r.special = S_ZERO #r.special = S_NZERO - elif s.special == S_NZERO: r.special = S_ZERO - elif s.special == S_INF: r.special = S_NINF - elif s.special == S_NINF: r.special = S_INF - else: r.special = s.special + if s.special == S_ZERO: + r.special = S_ZERO # r.special = S_NZERO + elif s.special == S_NZERO: + r.special = S_ZERO + elif s.special == S_INF: + r.special = S_NINF + elif s.special == S_NINF: + r.special = S_INF + else: + r.special = s.special return r.special = s.special mpz_neg(r.man, s.man) @@ -429,8 +433,10 @@ cdef void MPF_abs(MPF *r, MPF *s): Sets r = abs(s). MPF_abs(r, r) sets the absolute value in place. """ if s.special: - if s.special == S_NINF: r.special = S_INF - else: r.special = s.special + if s.special == S_NINF: + r.special = S_INF + else: + r.special = s.special return r.special = s.special mpz_abs(r.man, s.man) @@ -1847,8 +1853,8 @@ cdef MPF_complex_pow_int(MPF *zre, MPF *zim, MPF *xre, MPF *xim, mpz_t n, MPopts xret = MPF_to_tuple(xre) ximt = MPF_to_tuple(xim) from mpmath.libmp import mpc_pow_int - vr, vi = mpc_pow_int((xret, ximt), mpzi(n), \ - opts.prec, rndmode_to_python(opts.rounding)) + vr, vi = mpc_pow_int((xret, ximt), mpzi(n), + opts.prec, rndmode_to_python(opts.rounding)) MPF_set_tuple(zre, vr) MPF_set_tuple(zim, vi) @@ -1891,9 +1897,9 @@ cdef MPF_complex_pow_re(MPF *zre, MPF *zim, MPF *xre, MPF *xim, MPF *y, MPopts o xret = MPF_to_tuple(xre) ximt = MPF_to_tuple(xim) yret = MPF_to_tuple(y) - from mpmath.libmp import mpc_pow_mpf, fzero - vr, vi = mpc_pow_mpf((xret, ximt), yret, \ - opts.prec, rndmode_to_python(opts.rounding)) + from mpmath.libmp import mpc_pow_mpf + vr, vi = mpc_pow_mpf((xret, ximt), yret, + opts.prec, rndmode_to_python(opts.rounding)) MPF_set_tuple(zre, vr) MPF_set_tuple(zim, vi) @@ -1910,8 +1916,8 @@ cdef MPF_complex_pow(MPF *zre, MPF *zim, MPF *xre, MPF *xim, MPF *yre, MPF *yim, yret = MPF_to_tuple(yre) yimt = MPF_to_tuple(yim) from mpmath.libmp import mpc_pow - vr, vi = mpc_pow((xret,ximt), (yret,yimt), \ - opts.prec, rndmode_to_python(opts.rounding)) + vr, vi = mpc_pow((xret, ximt), (yret, yimt), + opts.prec, rndmode_to_python(opts.rounding)) MPF_set_tuple(zre, vr) MPF_set_tuple(zim, vi) diff --git a/src/sage/libs/mpmath/ext_libmp.pyx b/src/sage/libs/mpmath/ext_libmp.pyx index 6f4ab6b2914..5dccf596a91 100644 --- a/src/sage/libs/mpmath/ext_libmp.pyx +++ b/src/sage/libs/mpmath/ext_libmp.pyx @@ -1,11 +1,10 @@ """ Faster versions of some key functions in mpmath.libmp """ - from .ext_impl cimport * from sage.libs.gmp.all cimport * -from sage.rings.integer cimport Integer +# the next line is used by mpmath from .ext_impl import exp_fixed, cos_sin_fixed, log_int_fixed # Note: not thread-safe @@ -14,6 +13,7 @@ cdef MPF tmp2 MPF_init(&tmp1) MPF_init(&tmp2) + def mpf_add(tuple x, tuple y, int prec=0, str rnd='d'): cdef MPopts opts MPF_set_tuple(&tmp1, x) @@ -23,6 +23,7 @@ def mpf_add(tuple x, tuple y, int prec=0, str rnd='d'): MPF_add(&tmp1, &tmp1, &tmp2, opts) return MPF_to_tuple(&tmp1) + def mpf_sub(tuple x, tuple y, int prec=0, str rnd='d'): cdef MPopts opts MPF_set_tuple(&tmp1, x) @@ -32,6 +33,7 @@ def mpf_sub(tuple x, tuple y, int prec=0, str rnd='d'): MPF_sub(&tmp1, &tmp1, &tmp2, opts) return MPF_to_tuple(&tmp1) + def mpf_mul(tuple x, tuple y, int prec=0, str rnd='d'): cdef MPopts opts MPF_set_tuple(&tmp1, x) @@ -41,6 +43,7 @@ def mpf_mul(tuple x, tuple y, int prec=0, str rnd='d'): MPF_mul(&tmp1, &tmp1, &tmp2, opts) return MPF_to_tuple(&tmp1) + def mpf_div(tuple x, tuple y, int prec, str rnd='d'): cdef MPopts opts MPF_set_tuple(&tmp1, x) @@ -50,9 +53,10 @@ def mpf_div(tuple x, tuple y, int prec, str rnd='d'): MPF_div(&tmp1, &tmp1, &tmp2, opts) return MPF_to_tuple(&tmp1) + def mpf_sqrt(tuple x, int prec, str rnd='d'): """ - Computes sqrt(x) with mpf value tuples. + Compute sqrt(x) with mpf value tuples. EXAMPLES:: @@ -61,7 +65,6 @@ def mpf_sqrt(tuple x, int prec, str rnd='d'): sage: y = mpf_sqrt(x, 53, 'n') sage: to_float(y) 1.4142135623730951 - """ if x[0]: import mpmath.libmp as libmp @@ -73,9 +76,10 @@ def mpf_sqrt(tuple x, int prec, str rnd='d'): MPF_sqrt(&tmp1, &tmp1, opts) return MPF_to_tuple(&tmp1) + def mpf_log(tuple x, int prec, str rnd='d'): """ - Computes log(x) with mpf value tuples. + Compute log(x) with mpf value tuples. EXAMPLES:: @@ -84,7 +88,6 @@ def mpf_log(tuple x, int prec, str rnd='d'): sage: y = mpf_log(x, 53, 'n') sage: to_float(y) 0.6931471805599453 - """ if x[0]: import mpmath.libmp as libmp @@ -96,9 +99,10 @@ def mpf_log(tuple x, int prec, str rnd='d'): MPF_log(&tmp1, &tmp1, opts) return MPF_to_tuple(&tmp1) + def mpf_exp(tuple x, int prec, str rnd='d'): """ - Computes exp(x) with mpf value tuples. + Compute exp(x) with mpf value tuples. EXAMPLES:: @@ -107,7 +111,6 @@ def mpf_exp(tuple x, int prec, str rnd='d'): sage: z = mpf_exp(x, 53, 'n') sage: to_float(z) 7.38905609893065 - """ cdef MPopts opts MPF_set_tuple(&tmp1, x) @@ -116,9 +119,10 @@ def mpf_exp(tuple x, int prec, str rnd='d'): MPF_exp(&tmp1, &tmp1, opts) return MPF_to_tuple(&tmp1) + def mpf_cos(tuple x, int prec, str rnd='d'): """ - Computes cos(x) with mpf value tuples. + Compute cos(x) with mpf value tuples. EXAMPLES:: @@ -127,7 +131,6 @@ def mpf_cos(tuple x, int prec, str rnd='d'): sage: y = mpf_cos(x, 53, 'n') sage: to_float(y) 0.5403023058681398 - """ cdef MPopts opts MPF_set_tuple(&tmp1, x) @@ -136,9 +139,10 @@ def mpf_cos(tuple x, int prec, str rnd='d'): MPF_cos(&tmp1, &tmp1, opts) return MPF_to_tuple(&tmp1) + def mpf_sin(tuple x, int prec, str rnd='d'): """ - Computes sin(x) with mpf value tuples. + Compute sin(x) with mpf value tuples. EXAMPLES:: @@ -147,7 +151,6 @@ def mpf_sin(tuple x, int prec, str rnd='d'): sage: y = mpf_sin(x, 53, 'n') sage: to_float(y) 0.8414709848078965 - """ cdef MPopts opts MPF_set_tuple(&tmp1, x) @@ -156,9 +159,10 @@ def mpf_sin(tuple x, int prec, str rnd='d'): MPF_sin(&tmp1, &tmp1, opts) return MPF_to_tuple(&tmp1) + def mpc_sqrt(tuple z, int prec, str rnd='d'): """ - Computes sqrt(z) with mpc value tuples. + Compute sqrt(z) with mpc value tuples. EXAMPLES:: @@ -178,9 +182,10 @@ def mpc_sqrt(tuple z, int prec, str rnd='d'): MPF_complex_sqrt(&tmp1, &tmp2, &tmp1, &tmp2, opts) return MPF_to_tuple(&tmp1), MPF_to_tuple(&tmp2) + def mpc_exp(tuple z, int prec, str rnd='d'): """ - Computes exp(z) with mpc value tuples. + Compute exp(z) with mpc value tuples. EXAMPLES:: @@ -200,9 +205,10 @@ def mpc_exp(tuple z, int prec, str rnd='d'): MPF_complex_exp(&tmp1, &tmp2, &tmp1, &tmp2, opts) return MPF_to_tuple(&tmp1), MPF_to_tuple(&tmp2) + def mpf_pow(tuple x, tuple y, int prec, str rnd='d'): """ - Computes x ^ y with mpf value tuples. + Compute x ^ y with mpf value tuples. EXAMPLES:: diff --git a/src/sage/libs/mpmath/ext_main.pyx b/src/sage/libs/mpmath/ext_main.pyx index 81abdf0cd4b..845c85234a6 100644 --- a/src/sage/libs/mpmath/ext_main.pyx +++ b/src/sage/libs/mpmath/ext_main.pyx @@ -14,7 +14,6 @@ context class, and related utilities. # http://www.gnu.org/licenses/ #***************************************************************************** -from cpython.int cimport * from cpython.long cimport * from cpython.float cimport * from cpython.complex cimport * @@ -176,7 +175,7 @@ cdef int MPF_set_any(MPF *re, MPF *im, x, MPopts opts, bint str_tuple_ok) except elif len(x) == 4: MPF_set_tuple(re, x) return 1 - if isinstance(x, basestring): + if isinstance(x, str): try: st = libmp.from_str(x, opts.prec, rndmode_to_python(opts.rounding)) @@ -480,7 +479,7 @@ cdef class Context: 100 sage: mp.prec = 53 """ - return libmp.prec_to_dps(global_opts.prec) + return prec_to_dps(global_opts.prec) dps = property(_get_dps, _set_dps, doc=_get_dps.__doc__) prec = property(_get_prec, _set_prec, doc=_get_dps.__doc__) @@ -1007,7 +1006,7 @@ cdef class Context: if not p % q: return p // q, 'Z' return rationallib.mpq((p,q)), 'Q' - if isinstance(x, basestring) and '/' in x: + if isinstance(x, str) and '/' in x: p, q = x.split('/') p = int(p) q = int(q) @@ -2068,7 +2067,7 @@ cdef class mpf(mpf_base): """ MPF_init(&self.value) - def __dealloc__(self): + def __dealloc__(self): MPF_clear(&self.value) def __neg__(s): @@ -2359,7 +2358,7 @@ cdef class mpc(mpnumber): MPF_init(&self.re) MPF_init(&self.im) - def __dealloc__(self): + def __dealloc__(self): MPF_clear(&self.re) MPF_clear(&self.im) @@ -2602,13 +2601,15 @@ def hypsum_internal(int p, int q, param_types, str ztype, coeffs, z, sage: print(mp.hyp1f1(1,2,3)) 6.36184564106256 - TODO: convert mpf/mpc parameters to fixed-point numbers here - instead of converting to tuples within MPF_hypsum. + .. TODO:: + + convert mpf/mpc parameters to fixed-point numbers here + instead of converting to tuples within MPF_hypsum. """ cdef mpf f cdef mpc c c = mpc.__new__(mpc) - have_complex, magn = MPF_hypsum(&c.re, &c.im, p, q, param_types, \ + have_complex, magn = MPF_hypsum(&c.re, &c.im, p, q, param_types, ztype, coeffs, z, prec, wp, epsshift, magnitude_check, kwargs) if have_complex: v = c diff --git a/src/sage/libs/mpmath/utils.pyx b/src/sage/libs/mpmath/utils.pyx index 466334e929a..83f8108be08 100644 --- a/src/sage/libs/mpmath/utils.pyx +++ b/src/sage/libs/mpmath/utils.pyx @@ -128,7 +128,7 @@ cpdef normalize(long sign, Integer man, exp, long bc, long prec, str rnd): res = PY_NEW(Integer) if shift > 0: if rnd == 'n': - if mpz_tstbit(man.value, shift-1) and (mpz_tstbit(man.value, shift)\ + if mpz_tstbit(man.value, shift-1) and (mpz_tstbit(man.value, shift) or (mpz_scan1(man.value, 0) < (shift-1))): mpz_cdiv_q_2exp(res.value, man.value, shift) else: diff --git a/src/sage/libs/ntl/all.py b/src/sage/libs/ntl/all.py index 20993d2cac8..e9d4271879a 100644 --- a/src/sage/libs/ntl/all.py +++ b/src/sage/libs/ntl/all.py @@ -5,8 +5,7 @@ Features of this library include *incredibly fast* arithmetic with polynomials and asymptotically fast factorization of polynomials. """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) @@ -18,14 +17,14 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.libs.ntl.ntl_ZZ import ( - ntl_setSeed, \ - ntl_ZZ as ZZ, - randomBnd as ZZ_random, - randomBits as ZZ_random_bits ) + ntl_setSeed, + ntl_ZZ as ZZ, + randomBnd as ZZ_random, + randomBits as ZZ_random_bits) from sage.libs.ntl.ntl_ZZ_pContext import ntl_ZZ_pContext as ZZ_pContext @@ -56,16 +55,14 @@ from sage.libs.ntl.ntl_GF2 import ntl_GF2 as GF2 from sage.libs.ntl.ntl_GF2X import ( - ntl_GF2X as GF2X, - GF2XHexOutput, - ) + ntl_GF2X as GF2X, + GF2XHexOutput) from sage.libs.ntl.ntl_GF2EContext import ntl_GF2EContext as GF2EContext from sage.libs.ntl.ntl_GF2E import ( - ntl_GF2E as GF2E, \ - ntl_GF2E_random as GF2E_random, \ - ) + ntl_GF2E as GF2E, + ntl_GF2E_random as GF2E_random) from sage.libs.ntl.ntl_GF2EX import ntl_GF2EX as GF2EX diff --git a/src/sage/libs/ntl/ntl_GF2.pyx b/src/sage/libs/ntl/ntl_GF2.pyx index d6ada6cb100..7bbdaa09d05 100644 --- a/src/sage/libs/ntl/ntl_GF2.pyx +++ b/src/sage/libs/ntl/ntl_GF2.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Martin Albrecht <malb@informatik.uni-bremen.de> # # Distributed under the terms of the GNU General Public License (GPL) @@ -17,10 +17,9 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' @@ -28,7 +27,6 @@ include 'decl.pxi' from cpython.object cimport Py_EQ, Py_NE from sage.rings.integer cimport Integer -from sage.rings.integer_ring cimport IntegerRing_class ############################################################################## # GF2: Bits diff --git a/src/sage/libs/ntl/ntl_GF2E.pyx b/src/sage/libs/ntl/ntl_GF2E.pyx index 54c7eef492a..c78fd6704db 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_GF2E.pyx @@ -33,7 +33,7 @@ from .ntl_GF2X cimport ntl_GF2X from .ntl_GF2EContext cimport ntl_GF2EContext_class from .ntl_GF2EContext import ntl_GF2EContext from sage.libs.ntl.ntl_ZZ import unpickle_class_args -from sage.misc.randstate cimport randstate, current_randstate +from sage.misc.randstate cimport current_randstate ############################################################################## diff --git a/src/sage/libs/ntl/ntl_GF2X.pyx b/src/sage/libs/ntl/ntl_GF2X.pyx index d4581467952..787169e6dc7 100644 --- a/src/sage/libs/ntl/ntl_GF2X.pyx +++ b/src/sage/libs/ntl/ntl_GF2X.pyx @@ -21,7 +21,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' @@ -29,7 +28,6 @@ include 'decl.pxi' from cpython.object cimport Py_EQ, Py_NE from sage.rings.integer cimport Integer -from sage.misc.superseded import deprecation_cython as deprecation from .ntl_ZZ import unpickle_class_value from .ntl_GF2 cimport ntl_GF2 diff --git a/src/sage/libs/ntl/ntl_GF2X_linkage.pxi b/src/sage/libs/ntl/ntl_GF2X_linkage.pxi index 91d52652cd5..3f01c91ab00 100644 --- a/src/sage/libs/ntl/ntl_GF2X_linkage.pxi +++ b/src/sage/libs/ntl/ntl_GF2X_linkage.pxi @@ -180,7 +180,7 @@ cdef inline int celement_cmp(GF2X_c *a, GF2X_c *b, long parent) except -2: elif diff < 0: return -1 else: - for i in xrange(GF2X_NumBits(a[0])-1, -1, -1): + for i in range(GF2X_NumBits(a[0])-1, -1, -1): ca = GF2_conv_to_long(GF2X_coeff(a[0], i)) cb = GF2_conv_to_long(GF2X_coeff(b[0], i)) if ca < cb: @@ -339,12 +339,23 @@ cdef inline int celement_pow(GF2X_c* res, GF2X_c* x, long e, GF2X_c *modulus, lo x^9 + x^8 + x^7 + x^5 + x^3 sage: pow(f, 2, h) x^9 + x^8 + x^7 + x^5 + x^3 + sage: pow(x, 1000, h) + x^8 + x^7 + x^4 + + Check that deg x >= deg modulus works (:issue:`35324`):: + + sage: pow(x+1, 2, x^2+x+1) + x + sage: pow(x^2+1, 2, x^2+x+1) + x + 1 + """ cdef GF2XModulus_c mod + cdef GF2X_c xmod if modulus == NULL: if GF2X_IsX(x[0]): - GF2X_LeftShift(res[0], x[0], e - 1) + GF2X_LeftShift(res[0], x[0], e - 1) else: do_sig = GF2X_deg(x[0]) > 1e5 if do_sig: @@ -353,14 +364,17 @@ cdef inline int celement_pow(GF2X_c* res, GF2X_c* x, long e, GF2X_c *modulus, lo if do_sig: sig_off() else: + GF2X_rem(xmod, x[0], modulus[0]) GF2XModulus_build(mod, modulus[0]) - - do_sig = GF2X_deg(x[0]) > 1e5 - if do_sig: - sig_on() - GF2X_PowerMod_long_pre(res[0], x[0], e, mod) - if do_sig: - sig_off() + if GF2X_IsX(xmod): + GF2X_PowerXMod_long_pre(res[0], e, mod) + else: + do_sig = GF2X_deg(x[0]) > 1e5 + if do_sig: + sig_on() + GF2X_PowerMod_long_pre(res[0], xmod, e, mod) + if do_sig: + sig_off() cdef inline int celement_gcd(GF2X_c* res, GF2X_c* a, GF2X_c *b, long parent) except -2: diff --git a/src/sage/libs/ntl/ntl_ZZ.pyx b/src/sage/libs/ntl/ntl_ZZ.pyx index 48a329f3055..41e14fdcf09 100644 --- a/src/sage/libs/ntl/ntl_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_ZZ.pyx @@ -28,9 +28,8 @@ include 'decl.pxi' from sage.rings.integer cimport Integer from sage.libs.ntl.convert cimport PyLong_to_ZZ, mpz_to_ZZ -from sage.misc.randstate cimport randstate, current_randstate +from sage.misc.randstate cimport current_randstate from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE -from cpython.int cimport PyInt_AS_LONG cdef make_ZZ(ZZ_c* x): @@ -93,8 +92,8 @@ cdef class ntl_ZZ(): v = str(v) if not v: v = '0' - if not ((v[0].isdigit() or v[0] == '-') and \ - (v[1:-1].isdigit() or (len(v) <= 2)) and \ + if not ((v[0].isdigit() or v[0] == '-') and + (v[1:-1].isdigit() or (len(v) <= 2)) and (v[-1].isdigit() or (v[-1].lower() in ['l','r']))): raise ValueError("invalid integer: %s" % v) ccreadstr(self.x, v) diff --git a/src/sage/libs/ntl/ntl_ZZX.pyx b/src/sage/libs/ntl/ntl_ZZX.pyx index e369f7152e4..34fd47a8527 100644 --- a/src/sage/libs/ntl/ntl_ZZX.pyx +++ b/src/sage/libs/ntl/ntl_ZZX.pyx @@ -32,10 +32,7 @@ from cpython.object cimport Py_EQ, Py_NE from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ from sage.libs.ntl.ntl_ZZ import unpickle_class_value -from sage.rings.integer import Integer from sage.rings.integer_ring import IntegerRing -from sage.rings.integer cimport Integer -from sage.rings.integer_ring cimport IntegerRing_class from sage.arith.power cimport generic_power_pos ZZ = IntegerRing() @@ -1000,7 +997,7 @@ cdef class ntl_ZZX(): sage: f.trace_list() [5, 0, -6, 0, 10] - The input polynomial must be monic or a ValueError is raised:: + The input polynomial must be monic or a :class:`ValueError` is raised:: sage: f = ntl.ZZX([1,2,0,3,0,2]) sage: f.trace_list() diff --git a/src/sage/libs/ntl/ntl_ZZ_p.pyx b/src/sage/libs/ntl/ntl_ZZ_p.pyx index b5511abb891..d032d9b81b9 100644 --- a/src/sage/libs/ntl/ntl_ZZ_p.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_p.pyx @@ -17,7 +17,7 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from cysignals.signals cimport sig_on, sig_off @@ -32,7 +32,6 @@ from sage.rings.integer_ring import IntegerRing from sage.rings.integer cimport Integer from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ from sage.rings.rational cimport Rational -from sage.rings.integer_ring cimport IntegerRing_class from sage.libs.ntl.ntl_ZZ import unpickle_class_args from sage.libs.ntl.convert cimport PyLong_to_ZZ, mpz_to_ZZ @@ -40,7 +39,7 @@ from sage.libs.ntl.convert cimport PyLong_to_ZZ, mpz_to_ZZ from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class from sage.libs.ntl.ntl_ZZ_pContext import ntl_ZZ_pContext -from sage.misc.randstate cimport randstate, current_randstate +from sage.misc.randstate cimport current_randstate ZZ_sage = IntegerRing() diff --git a/src/sage/libs/ntl/ntl_ZZ_pE.pyx b/src/sage/libs/ntl/ntl_ZZ_pE.pyx index ed45e34f0be..790d5c59648 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pE.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pE.pyx @@ -28,19 +28,13 @@ include 'decl.pxi' from cpython.object cimport Py_EQ, Py_NE -from sage.rings.integer import Integer from sage.rings.integer_ring import IntegerRing from sage.rings.integer cimport Integer from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p from sage.rings.integer cimport Integer -from sage.rings.integer_ring cimport IntegerRing_class from sage.libs.ntl.convert cimport PyLong_to_ZZ, mpz_to_ZZ -from sage.libs.ntl.ntl_ZZ import unpickle_class_args - -from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class -from sage.libs.ntl.ntl_ZZ_pContext import ntl_ZZ_pContext from sage.libs.ntl.ntl_ZZ_pEContext cimport ntl_ZZ_pEContext_class from sage.libs.ntl.ntl_ZZ_pEContext import ntl_ZZ_pEContext diff --git a/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx b/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx index b6ff3c66b01..fca10d5667f 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx @@ -17,7 +17,7 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** include 'misc.pxi' @@ -25,8 +25,6 @@ include 'decl.pxi' from sage.ext.cplusplus cimport ccrepr from sage.libs.ntl.ntl_ZZ_pX cimport ntl_ZZ_pX -from sage.libs.ntl.ntl_ZZ_pContext import ntl_ZZ_pContext -from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ ZZ_pEContextDict = {} diff --git a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx index d5f10218a77..c12df77c2f0 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx @@ -36,14 +36,10 @@ include 'misc.pxi' include 'decl.pxi' from cpython.object cimport Py_EQ, Py_NE -from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ -from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p from sage.libs.ntl.ntl_ZZ_pE cimport ntl_ZZ_pE -from sage.libs.ntl.ntl_ZZ_pX cimport ntl_ZZ_pX from sage.libs.ntl.ntl_ZZ_pEContext cimport ntl_ZZ_pEContext_class from sage.libs.ntl.ntl_ZZ_pEContext import ntl_ZZ_pEContext from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class -from sage.libs.ntl.ntl_ZZ import unpickle_class_args from sage.arith.power cimport generic_power_pos ############################################################################## @@ -393,8 +389,9 @@ cdef class ntl_ZZ_pEX(): there exist polynomials q, r in ZZ_pE[X] such that a = b*q + r, deg(r) < deg(b). This function returns r. - If p is not prime or the modulus is not irreducible, this function may raise a - RuntimeError due to division by a noninvertible element of ZZ_p. + If p is not prime or the modulus is not irreducible, this + function may raise a :class:`RuntimeError` due to division by + a noninvertible element of ZZ_p. EXAMPLES:: @@ -1082,7 +1079,7 @@ cdef class ntl_ZZ_pEX(): # sage: f.trace_list() # [5, 0, 14, 0, 10] # - # The input polynomial must be monic or a ValueError is raised:: + # The input polynomial must be monic or a :class:`ValueError` is raised:: # # sage: c=ntl.ZZ_pContext(ntl.ZZ(20)) # sage: f = c.ZZ_pX([1,2,0,3,0,2] diff --git a/src/sage/libs/ntl/ntl_ZZ_pX.pyx b/src/sage/libs/ntl/ntl_ZZ_pX.pyx index 73151b5d481..4ad48fb3496 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pX.pyx @@ -34,7 +34,7 @@ from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class from sage.libs.ntl.ntl_ZZ_pContext import ntl_ZZ_pContext from sage.libs.ntl.ntl_ZZ import unpickle_class_args -from sage.misc.randstate cimport randstate, current_randstate +from sage.misc.randstate cimport current_randstate from sage.libs.gmp.mpz cimport * @@ -264,9 +264,7 @@ cdef class ntl_ZZ_pX(): if i < 0: r.set_from_int(0) else: - sig_on() r.x = ZZ_pX_coeff( self.x, i) - sig_off() return r cdef int getitem_as_int(ntl_ZZ_pX self, long i): @@ -419,8 +417,8 @@ cdef class ntl_ZZ_pX(): in ZZ_p[X] such that a = b*q + r, deg(r) < deg(b). This function returns r. - If p is not prime this function may raise a RuntimeError due to division by a noninvertible - element of ZZ_p. + If p is not prime this function may raise a :class:`RuntimeError` + due to division by a noninvertible element of ZZ_p. EXAMPLES:: @@ -1238,7 +1236,7 @@ cdef class ntl_ZZ_pX(): sage: f.trace_list() [5, 0, 14, 0, 10] - The input polynomial must be monic or a ValueError is raised:: + The input polynomial must be monic or a :class:`ValueError` is raised:: sage: c = ntl.ZZ_pContext(20) sage: f = ntl.ZZ_pX([1,2,0,3,0,2],c) diff --git a/src/sage/libs/ntl/ntl_lzz_p.pyx b/src/sage/libs/ntl/ntl_lzz_p.pyx index 983e3056404..af86b9bcf69 100644 --- a/src/sage/libs/ntl/ntl_lzz_p.pyx +++ b/src/sage/libs/ntl/ntl_lzz_p.pyx @@ -43,7 +43,6 @@ from cpython.object cimport Py_EQ, Py_NE from sage.rings.integer import Integer from sage.rings.integer_ring import IntegerRing from sage.rings.integer cimport Integer -from sage.rings.integer_ring cimport IntegerRing_class from sage.rings.finite_rings.integer_mod cimport IntegerMod_gmp, IntegerMod_int, IntegerMod_int64 @@ -90,19 +89,19 @@ cdef class ntl_zz_p(): #self.c.restore_c() ## This was done in __new__ if isinstance(a, IntegerMod_int): - if (self.c.p == (<IntegerMod_int>a).__modulus.int32): ## this is slow + if (self.c.p == (<IntegerMod_int>a)._modulus.int32): ## this is slow self.x = (<IntegerMod_int>a).ivalue else: raise ValueError("Mismatched modulus for converting to zz_p.") elif isinstance(a, IntegerMod_int64): - if (self.c.p == (<IntegerMod_int64>a).__modulus.int64): ## this is slow + if (self.c.p == (<IntegerMod_int64>a)._modulus.int64): ## this is slow self.x = (<IntegerMod_int64>a).ivalue else: raise ValueError("Mismatched modulus for converting to zz_p.") elif isinstance(a, IntegerMod_gmp): - if (p_sage == (<IntegerMod_gmp>a).__modulus.sageInteger): ## this is slow + if (p_sage == (<IntegerMod_gmp>a)._modulus.sageInteger): ## this is slow self.x = mpz_get_si((<IntegerMod_gmp>a).value) else: raise ValueError("Mismatched modulus for converting to zz_p.") diff --git a/src/sage/libs/ntl/ntl_lzz_pX.pyx b/src/sage/libs/ntl/ntl_lzz_pX.pyx index 98bd0d58658..7d19cc55e37 100644 --- a/src/sage/libs/ntl/ntl_lzz_pX.pyx +++ b/src/sage/libs/ntl/ntl_lzz_pX.pyx @@ -34,7 +34,6 @@ from cpython.object cimport Py_EQ, Py_NE from sage.rings.integer import Integer from sage.rings.integer_ring import IntegerRing from sage.rings.integer cimport Integer -from sage.rings.integer_ring cimport IntegerRing_class from sage.rings.finite_rings.integer_mod cimport IntegerMod_gmp, IntegerMod_int, IntegerMod_int64 @@ -109,17 +108,17 @@ cdef class ntl_zz_pX(): a = ls[i] if isinstance(a, IntegerMod_int): - if (self.c.p == (<IntegerMod_int>a).__modulus.int32): ## this is slow + if (self.c.p == (<IntegerMod_int>a)._modulus.int32): ## this is slow zz_pX_SetCoeff_long(self.x, i, (<IntegerMod_int>a).ivalue) else: raise ValueError("Mismatched modulus for converting to zz_pX.") elif isinstance(a, IntegerMod_int64): - if (self.c.p == (<IntegerMod_int64>a).__modulus.int64): ## this is slow + if (self.c.p == (<IntegerMod_int64>a)._modulus.int64): ## this is slow zz_pX_SetCoeff_long(self.x, i, (<IntegerMod_int64>a).ivalue) else: raise ValueError("Mismatched modulus for converting to zz_pX.") elif isinstance(a, IntegerMod_gmp): - if (p_sage == (<IntegerMod_gmp>a).__modulus.sageInteger): ## this is slow + if (p_sage == (<IntegerMod_gmp>a)._modulus.sageInteger): ## this is slow zz_pX_SetCoeff_long(self.x, i, mpz_get_si((<IntegerMod_gmp>a).value)) else: raise ValueError("Mismatched modulus for converting to zz_pX.") diff --git a/src/sage/libs/ntl/ntl_mat_GF2E.pyx b/src/sage/libs/ntl/ntl_mat_GF2E.pyx index f88f20c63c6..46a5c9bc59e 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2E.pyx @@ -726,27 +726,27 @@ cdef class ntl_mat_GF2E(): if not nonzero: if _density == 1.0: - for i in xrange(self.x.NumRows()): - for j in xrange(self.x.NumCols()): + for i in range(self.x.NumRows()): + for j in range(self.x.NumCols()): tmp = GF2E_random() mat_GF2E_setitem(&self.x, i, j, &tmp) else: - for i in xrange(self.x.NumRows()): - for j in xrange(self.x.NumCols()): + for i in range(self.x.NumRows()): + for j in range(self.x.NumCols()): if rstate.c_rand_double() <= _density: tmp = GF2E_random() mat_GF2E_setitem(&self.x, i, j, &tmp) else: if _density == 1.0: - for i in xrange(self.x.NumRows()): - for j in xrange(self.x.NumCols()): + for i in range(self.x.NumRows()): + for j in range(self.x.NumCols()): tmp = GF2E_random() while GF2E_IsZero(tmp): tmp = GF2E_random() mat_GF2E_setitem(&self.x, i, j, &tmp) else: - for i in xrange(self.x.NumRows()): - for j in xrange(self.x.NumCols()): + for i in range(self.x.NumRows()): + for j in range(self.x.NumCols()): if rstate.c_rand_double() <= _density: tmp = GF2E_random() while GF2E_IsZero(tmp): diff --git a/src/sage/libs/pari/__init__.py b/src/sage/libs/pari/__init__.py index ba4c5ad0efd..95b93560892 100644 --- a/src/sage/libs/pari/__init__.py +++ b/src/sage/libs/pari/__init__.py @@ -202,4 +202,5 @@ def _get_pari_instance(): return P + pari = _get_pari_instance() diff --git a/src/sage/libs/pari/convert_flint.pyx b/src/sage/libs/pari/convert_flint.pyx index 4c4be33ccef..07dd6cfc3dd 100644 --- a/src/sage/libs/pari/convert_flint.pyx +++ b/src/sage/libs/pari/convert_flint.pyx @@ -9,19 +9,19 @@ AUTHORS: generic C-interface in ``Pari`` (:trac:`20241`) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Luca De Feo <luca.defeo@polytechnique.edu> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on -from sage.libs.flint.fmpz cimport fmpz_get_mpz, COEFF_IS_MPZ, COEFF_TO_PTR, fmpz_is_one +from sage.libs.flint.fmpz cimport COEFF_IS_MPZ, COEFF_TO_PTR, fmpz_is_one from sage.libs.flint.fmpq cimport fmpq_numref, fmpq_denref from sage.libs.flint.fmpz_mat cimport fmpz_mat_nrows, fmpz_mat_ncols, fmpz_mat_entry from sage.libs.flint.fmpq_mat cimport fmpq_mat_nrows, fmpq_mat_ncols, fmpq_mat_entry diff --git a/src/sage/libs/pari/convert_gmp.pyx b/src/sage/libs/pari/convert_gmp.pyx index a39caa379b4..fcd212a8703 100644 --- a/src/sage/libs/pari/convert_gmp.pyx +++ b/src/sage/libs/pari/convert_gmp.pyx @@ -17,10 +17,10 @@ AUTHORS: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** -from cysignals.signals cimport sig_on, sig_off +from cysignals.signals cimport sig_on from sage.libs.gmp.all cimport * diff --git a/src/sage/libs/pari/convert_sage.pyx b/src/sage/libs/pari/convert_sage.pyx index 62fe5185cfb..71a1744698e 100644 --- a/src/sage/libs/pari/convert_sage.pyx +++ b/src/sage/libs/pari/convert_sage.pyx @@ -2,7 +2,7 @@ r""" Convert PARI objects to Sage types """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Jeroen Demeyer <jdemeyer@cage.ugent.be> # Copyright (C) 2016 Luca De Feo <luca.defeo@polytechnique.edu> # Copyright (C) 2016 Vincent Delecroix <vincent.delecroix@u-bordeaux.fr> @@ -11,8 +11,8 @@ Convert PARI objects to Sage types # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off @@ -20,9 +20,7 @@ from cypari2.types cimport (GEN, typ, t_INT, t_FRAC, t_REAL, t_COMPLEX, t_INTMOD, t_PADIC, t_INFINITY, t_VEC, t_COL, t_VECSMALL, t_MAT, t_STR, lg, precp) -from cypari2.pari_instance cimport prec_words_to_bits from cypari2.paridecl cimport * -from cypari2.gen cimport objtogen from cypari2.stack cimport new_gen from .convert_gmp cimport INT_to_mpz, new_gen_from_mpz_t, new_gen_from_mpq_t, INTFRAC_to_mpq @@ -30,7 +28,9 @@ from sage.ext.stdsage cimport PY_NEW from sage.libs.gmp.mpz cimport mpz_fits_slong_p, mpz_sgn, mpz_get_ui, mpz_set, mpz_set_si, mpz_set_ui from sage.libs.gmp.mpq cimport mpq_denref, mpq_numref from sage.rings.integer cimport smallInteger -from sage.rings.all import RealField, ComplexField, QuadraticField +from sage.rings.real_mpfr import RealField +from sage.rings.complex_mpfr import ComplexField +from sage.rings.number_field.number_field import QuadraticField from sage.matrix.args cimport (MatrixArgs, MA_ENTRIES_SEQ_SEQ, MA_ENTRIES_SEQ_FLAT, MA_ENTRIES_CALLABLE, MA_ENTRIES_UNKNOWN, MA_ENTRIES_SCALAR) @@ -352,7 +352,7 @@ cpdef set_integer_from_gen(Integer self, Gen x): break elif paritype == t_PADIC: if x._valp() < 0: - raise TypeError("Cannot convert p-adic with negative valuation to an integer") + raise TypeError("cannot convert p-adic with negative valuation to an integer") # Lifting a PADIC yields an integer x = x.lift() break diff --git a/src/sage/libs/singular/decl.pxd b/src/sage/libs/singular/decl.pxd index 747a6b1e2fb..aa6c5515432 100644 --- a/src/sage/libs/singular/decl.pxd +++ b/src/sage/libs/singular/decl.pxd @@ -978,11 +978,23 @@ cdef extern from "singular/Singular/libsingular.h": void setFlag(leftv *A, int F) void resetFlag(leftv *A, int F) + ctypedef number* (*nMapFunc)(number *c,const n_Procs_s* src,const n_Procs_s* dst) + +cdef extern from "singular/coeffs/coeffs.h": + + number *ndCopyMap(number *, const n_Procs_s* src,const n_Procs_s* dst) + cdef extern from "singular/coeffs/rmodulo2m.h": #init 2^m from a long number *nr2mMapZp(number *,const n_Procs_s* src,const n_Procs_s* dst) +cdef extern from "singular/kernel/maps/gen_maps.h": + + # mapping from p in r1 by i2 to r2 + + poly *maMapPoly(poly *p, ring *r1, ideal *i2, ring *r2, const nMapFunc nMap) + cdef extern from "singular/kernel/maps/fast_maps.h": # mapping from ideal i1 in r1 by i2 to r2 @@ -993,8 +1005,6 @@ cdef extern from "singular/polys/ext_fields/algext.h": naInitChar(n_Procs_s* cf, void * infoStruct) - ctypedef number* (*nMapFunc)(number *c,const n_Procs_s* src,const n_Procs_s* dst) - nMapFunc naSetMap(const n_Procs_s* src, const n_Procs_s* dst) cdef extern from "singular/coeffs/rmodulon.h": diff --git a/src/sage/libs/singular/function.pyx b/src/sage/libs/singular/function.pyx index f103a3b8654..c597c63aafe 100644 --- a/src/sage/libs/singular/function.pyx +++ b/src/sage/libs/singular/function.pyx @@ -93,11 +93,11 @@ from sage.rings.polynomial.plural cimport NCPolynomialRing_plural, NCPolynomial_ from sage.rings.polynomial.multi_polynomial_ideal import NCPolynomialIdeal from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal from sage.rings.polynomial.multi_polynomial_ideal_libsingular cimport sage_ideal_to_singular_ideal, singular_ideal_to_sage_sequence -from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence, PolynomialSequence_generic +from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence_generic from sage.libs.singular.decl cimport * from sage.libs.singular.option import opt_ctx -from sage.libs.singular.polynomial cimport singular_vector_maximal_component, singular_polynomial_check +from sage.libs.singular.polynomial cimport singular_vector_maximal_component from sage.libs.singular.singular cimport sa2si, si2sa, si2sa_intvec from sage.libs.singular.singular import error_messages @@ -686,8 +686,8 @@ cdef class Converter(SageObject): ncols = mat.ncols nrows = mat.nrows result = Matrix(self._sage_ring, nrows, ncols) - for i in xrange(nrows): - for j in xrange(ncols): + for i in range(nrows): + for j in range(ncols): p = new_sage_polynomial(self._sage_ring, mat.m[i*ncols+j]) mat.m[i*ncols+j]=NULL result[i,j] = p @@ -767,8 +767,8 @@ cdef class Converter(SageObject): nrows = mat.rows() result = Matrix(ZZ, nrows, ncols) - for i in xrange(nrows): - for j in xrange(ncols): + for i in range(nrows): + for j in range(ncols): result[i,j] = mat.get(i*ncols+j) return result @@ -828,8 +828,8 @@ cdef class Converter(SageObject): ncols = mat.ncols() nrows = mat.nrows() cdef matrix* _m=mpNew(nrows,ncols) - for i in xrange(nrows): - for j in xrange(ncols): + for i in range(nrows): + for j in range(ncols): #FIXME p = copy_sage_polynomial_into_singular_poly(mat[i,j]) _m.m[ncols*i+j]=p @@ -853,7 +853,7 @@ cdef class Converter(SageObject): cdef lists *singular_list=<lists*>omAlloc0Bin(slists_bin) singular_list.Init(n) cdef leftv* iv - for i in xrange(n): + for i in range(n): iv=c.pop_front() memcpy(&singular_list.m[i],iv,sizeof(leftv)) omFreeBin(iv, sleftv_bin) @@ -868,7 +868,7 @@ cdef class Converter(SageObject): cdef intvec *iv = new intvec() iv.resize(s) - for i in xrange(s): + for i in range(s): iv.ivGetVec()[i]=<int>a[i] return self._append(<void*>iv, INTVEC_CMD) @@ -896,8 +896,8 @@ cdef class Converter(SageObject): cdef int ncols = <int> a.ncols() cdef intvec *iv = new intvec(nrows, ncols, 0) - for i in xrange(nrows): - for j in xrange(ncols): + for i in range(nrows): + for j in range(ncols): iv.ivGetVec()[i*ncols+j]=<int>a[i,j] return self._append(<void*>iv, INTMAT_CMD) @@ -971,7 +971,7 @@ cdef class Converter(SageObject): elif rtyp == LIST_CMD: singular_list = <lists*> to_convert.data ret = [] - for i in xrange(singular_list.nr+1): + for i in range(singular_list.nr+1): ret.append(self.to_python(&(singular_list.m[i]))) return ret elif rtyp == MODUL_CMD: @@ -1241,32 +1241,22 @@ cdef class SingularFunction(SageObject): sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) sage: I = Ideal(I.groebner_basis()) sage: hilb = sage.libs.singular.function_factory.ff.hilb - sage: hilb(I) # Singular will print // ** _ is no standard basis - // ** _ is no standard basis - // 1 t^0 - // -1 t^5 - <BLANKLINE> - // 1 t^0 - // 1 t^1 - // 1 t^2 - // 1 t^3 - // 1 t^4 - // dimension (proj.) = 1 - // degree (proj.) = 5 + sage: from sage.misc.sage_ostools import redirection + sage: out = tmp_filename() + sage: with redirection(sys.stdout, open(out, 'w')): + ....: hilb(I) # Singular will print // ** _ is no standard basis + sage: with open(out) as f: + ....: 'is no standard basis' in f.read() + True So we tell Singular that ``I`` is indeed a Groebner basis:: - sage: hilb(I,attributes={I:{'isSB':1}}) # no complaint from Singular - // 1 t^0 - // -1 t^5 - <BLANKLINE> - // 1 t^0 - // 1 t^1 - // 1 t^2 - // 1 t^3 - // 1 t^4 - // dimension (proj.) = 1 - // degree (proj.) = 5 + sage: out = tmp_filename() + sage: with redirection(sys.stdout, open(out, 'w')): + ....: hilb(I,attributes={I:{'isSB':1}}) # no complaint from Singular + sage: with open(out) as f: + ....: 'is no standard basis' in f.read() + False TESTS: @@ -1299,12 +1289,12 @@ cdef class SingularFunction(SageObject): ring = self.common_ring(args, ring) if ring is None: if dummy_ring is None: - from sage.rings.polynomial.all import PolynomialRing + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ dummy_ring = PolynomialRing(QQ, "dummy", implementation="singular") # seems a reasonable default ring = dummy_ring if not (isinstance(ring, MPolynomialRing_libsingular) or isinstance(ring, NCPolynomialRing_plural)): - raise TypeError("Cannot call Singular function '%s' with ring parameter of type '%s'"%(self._name,type(ring))) + raise TypeError("cannot call Singular function '%s' with ring parameter of type '%s'" % (self._name,type(ring))) return call_function(self, args, ring, interruptible, attributes) def _instancedoc_(self): diff --git a/src/sage/libs/singular/option.pyx b/src/sage/libs/singular/option.pyx index fc3b576ff71..d35415c2864 100644 --- a/src/sage/libs/singular/option.pyx +++ b/src/sage/libs/singular/option.pyx @@ -93,12 +93,12 @@ AUTHOR: - Martin Albrecht (2010-01): better interface, verbosity options - Simon King (2010-07): Python-ic option names; deg_bound and mult_bound """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Martin Albrecht <M.R.Albrecht@rhul.ac.uk> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.libs.singular.decl cimport singular_options, singular_verbose_options, Kstd1_deg, Kstd1_mu @@ -108,7 +108,7 @@ from sage.libs.singular.decl cimport OPT_WEIGHTM, Sy_bit from sage.libs.singular.decl cimport V_SHOW_MEM, V_YACC, V_REDEFINE, V_READING, V_LOAD_LIB, V_DEBUG_LIB from sage.libs.singular.decl cimport V_LOAD_PROC, V_DEF_RES, V_SHOW_USE, V_IMAP, V_PROMPT -from sage.libs.singular.decl cimport V_NSB, V_CONTENTSB, V_CANCELUNIT, V_DEG_STOP +from sage.libs.singular.decl cimport V_NSB, V_CONTENTSB, V_CANCELUNIT _options_py_to_singular={'return_sb':'returnSB', 'fast_hc':'fastHC', diff --git a/src/sage/libs/singular/polynomial.pyx b/src/sage/libs/singular/polynomial.pyx index b2efc7dfbcb..9f81a20b0a7 100644 --- a/src/sage/libs/singular/polynomial.pyx +++ b/src/sage/libs/singular/polynomial.pyx @@ -32,9 +32,10 @@ from sage.libs.singular.decl cimport p_Copy, p_Add_q, p_Neg, pp_Mult_nn, p_GetCo from sage.libs.singular.decl cimport p_GetMaxExp, pp_Mult_qq, pPower, p_String, p_GetExp, p_LDeg from sage.libs.singular.decl cimport n_Delete, idInit, fast_map_common_subexp, id_Delete from sage.libs.singular.decl cimport omAlloc0, omStrDup, omFree -from sage.libs.singular.decl cimport p_GetComp, p_SetComp +from sage.libs.singular.decl cimport p_GetComp from sage.libs.singular.decl cimport pSubst from sage.libs.singular.decl cimport p_Normalize +from sage.libs.singular.decl cimport ndCopyMap, maMapPoly from sage.libs.singular.singular cimport sa2si, si2sa, overflow_check @@ -200,25 +201,33 @@ cdef int singular_polynomial_call(poly **ret, poly *p, ring *r, list args, poly """ cdef long l = len(args) cdef ideal *to_id = idInit(l,1) + cdef bint constant_args = 1 for i from 0 <= i < l: to_id.m[i]= p_Copy( get_element(args[i]), r) + if not p_IsConstant(to_id.m[i], r): + constant_args = 0 - cdef ideal *from_id=idInit(1,1) - from_id.m[0] = p - + cdef ideal *from_id rChangeCurrRing(r) - cdef ideal *res_id = fast_map_common_subexp(from_id, r, to_id, r) - ret[0] = res_id.m[0] + cdef ideal *res_id + if not constant_args: + from_id = idInit(1,1) + from_id.m[0] = p + + res_id = fast_map_common_subexp(from_id, r, to_id, r) + ret[0] = res_id.m[0] + + from_id.m[0] = NULL + res_id.m[0] = NULL + id_Delete(&from_id, r) + id_Delete(&res_id, r) + else: + ret[0] = maMapPoly(p, r, to_id, r, ndCopyMap) # Unsure why we have to normalize here. See #16958 p_Normalize(ret[0], r) - from_id.m[0] = NULL - res_id.m[0] = NULL - id_Delete(&to_id, r) - id_Delete(&from_id, r) - id_Delete(&res_id, r) return 0 @@ -489,25 +498,25 @@ cdef object singular_polynomial_latex(poly *p, ring *r, object base, object late for j in range(1, n+1): e = p_GetExp(p, j, r) if e > 0: - multi += " "+latex_gens[j-1] + multi += " " + latex_gens[j-1] if e > 1: - multi += "^{%d}"%e + multi += "^{%d}" % e multi = multi.lstrip().rstrip() # Next determine coefficient of multinomial - c = si2sa( p_GetCoeff(p, r), r, base) + c = si2sa(p_GetCoeff(p, r), r, base) if not multi: multi = latex(c) elif c != 1: - if c == -1: - multi = "-%s"%(multi) + if c == -1: + multi = "-%s" % (multi) else: sc = latex(c) # Add parenthesis if the coefficient consists of terms divided by +, - # (starting with - is not enough) and is not the constant term if not atomic_repr and multi and (sc.find("+") != -1 or sc[1:].find("-") != -1): - sc = "\\left(%s\\right)"%sc - multi = "%s %s"%(sc,multi) + sc = "\\left(%s\\right)" % sc + multi = "%s %s" % (sc, multi) # Now add on coefficiented multinomials if poly: diff --git a/src/sage/libs/singular/ring.pyx b/src/sage/libs/singular/ring.pyx index 04bd16e8784..56dc364219c 100644 --- a/src/sage/libs/singular/ring.pyx +++ b/src/sage/libs/singular/ring.pyx @@ -9,30 +9,28 @@ AUTHORS: - Miguel Marco (2021): added transcendental extensions over Q """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Martin Albrecht <malb@informatik.uni-bremen.de> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.cpython.string cimport str_to_bytes from sage.libs.gmp.types cimport __mpz_struct -from sage.libs.gmp.mpz cimport mpz_init_set_ui, mpz_init_set +from sage.libs.gmp.mpz cimport mpz_init_set_ui -from sage.libs.singular.decl cimport number, poly, ring, currRing -from sage.libs.singular.decl cimport rChangeCurrRing, rCopy0, rComplete, rDelete, idInit -from sage.libs.singular.decl cimport omAlloc0, omStrDup, omAlloc, omAlloc0Bin, sip_sring_bin, rnumber_bin +from sage.libs.singular.decl cimport ring, currRing +from sage.libs.singular.decl cimport rChangeCurrRing, rComplete, rDelete, idInit +from sage.libs.singular.decl cimport omAlloc0, omStrDup, omAlloc from sage.libs.singular.decl cimport ringorder_dp, ringorder_Dp, ringorder_lp, ringorder_rp, ringorder_ds, ringorder_Ds, ringorder_ls, ringorder_M, ringorder_c, ringorder_C, ringorder_wp, ringorder_Wp, ringorder_ws, ringorder_Ws, ringorder_a, rRingOrder_t -from sage.libs.singular.decl cimport p_Copy, prCopyR -from sage.libs.singular.decl cimport n_unknown, n_Zp, n_Q, n_R, n_GF, n_long_R, n_algExt,n_transExt,n_long_C, n_Z, n_Zn, n_Znm, n_Z2m, n_CF -from sage.libs.singular.decl cimport n_coeffType, cfInitCharProc -from sage.libs.singular.decl cimport rDefault, GFInfo, ZnmInfo, nInitChar, AlgExtInfo, nRegister, naInitChar, TransExtInfo +from sage.libs.singular.decl cimport prCopyR +from sage.libs.singular.decl cimport n_unknown, n_algExt, n_transExt, n_Z, n_Zn, n_Znm, n_Z2m +from sage.libs.singular.decl cimport n_coeffType +from sage.libs.singular.decl cimport rDefault, GFInfo, ZnmInfo, nInitChar, AlgExtInfo, TransExtInfo - -from sage.rings.integer cimport Integer from sage.rings.integer_ring cimport IntegerRing_class from sage.rings.integer_ring import ZZ import sage.rings.abc @@ -46,7 +44,7 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import PolynomialRing_field -from sage.rings.fraction_field import FractionField_generic, FractionField_1poly_field +from sage.rings.fraction_field import FractionField_generic from cpython.object cimport Py_EQ, Py_NE diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index 3eb4db32dab..f357ce611c9 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -37,18 +37,17 @@ from sage.rings.integer_ring cimport IntegerRing_class from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.polynomial.polynomial_ring import PolynomialRing_field -from sage.rings.fraction_field import FractionField_generic, FractionField_1poly_field +from sage.rings.fraction_field import FractionField_generic from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn from sage.rings.finite_rings.finite_field_givaro import FiniteField_givaro from sage.rings.finite_rings.finite_field_ntl_gf2e import FiniteField_ntl_gf2e -from sage.libs.pari.all import pari from sage.libs.gmp.all cimport * from sage.cpython.string import FS_ENCODING from sage.cpython.string cimport str_to_bytes, char_to_str, bytes_to_str -from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular, MPolynomialRing_libsingular +from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular ctypedef struct fraction "fractionObject": poly *numerator @@ -526,6 +525,7 @@ cdef object si2sa_NF(number *n, ring *_ring, object base): TESTS:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 2) sage: P.<x,y,z> = K[] sage: f = a^21*x^2 + 1 # indirect doctest @@ -1393,7 +1393,8 @@ cdef number *sa2si_NF(object elem, ring *_ring): TESTS:: - sage: F = NumberField(x^3+x+1, 'a') + sage: x = polygen(ZZ, 'x') + sage: F = NumberField(x^3 + x + 1, 'a') sage: type(F) <class 'sage.rings.number_field.number_field.NumberField_absolute_with_category'> sage: R.<x,y,z> = F[] @@ -1705,14 +1706,7 @@ cdef object si2sa_intvec(intvec *v): cdef extern from *: # hack to get at cython macro int unlikely(int) -cdef extern from "dlfcn.h": - void *dlopen(char *, long) - char *dlerror() - void dlclose(void *handle) - -cdef extern from "dlfcn.h": - cdef long RTLD_LAZY - cdef long RTLD_GLOBAL +from posix.dlfcn cimport dlopen, dlclose, dlerror, RTLD_LAZY, RTLD_GLOBAL cdef int overflow_check(unsigned long e, ring *_ring) except -1: """ @@ -1768,8 +1762,6 @@ cdef init_libsingular(): cdef void *handle = NULL - from sage.env import LIBSINGULAR_PATH - lib = str_to_bytes(LIBSINGULAR_PATH, FS_ENCODING, "surrogateescape") # This is a workaround for https://github.com/Singular/Singular/issues/1113 # and can be removed once that fix makes it into release of Singular that @@ -1786,10 +1778,12 @@ cdef init_libsingular(): import platform if not platform.system().startswith("CYGWIN"): + # reload the current module to force reload of libSingular (see #33446) + lib = str_to_bytes(__loader__.path, FS_ENCODING, "surrogateescape") handle = dlopen(lib, RTLD_GLOBAL|RTLD_LAZY) if not handle: err = dlerror() - raise ImportError(f"cannot load Singular library from {LIBSINGULAR_PATH} ({err})") + raise RuntimeError(f"Could not reload Singular library with RTLD_GLOBAL ({err})") # load SINGULAR siInit(lib) diff --git a/src/sage/libs/symmetrica/sb.pxi b/src/sage/libs/symmetrica/sb.pxi index 9bde08effa7..b884d33dafd 100644 --- a/src/sage/libs/symmetrica/sb.pxi +++ b/src/sage/libs/symmetrica/sb.pxi @@ -111,7 +111,7 @@ def t_POLYNOM_SCHUBERT_symmetrica(a): cdef OP ca = callocobject(), cres = callocobject() - if not is_MPolynomial(a): + if not isinstance(a, MPolynomial): freeall(ca) freeall(cres) raise TypeError("a (= %s) must be a multivariate polynomial") diff --git a/src/sage/libs/symmetrica/symmetrica.pxi b/src/sage/libs/symmetrica/symmetrica.pxi index 7244b7e9655..95f9e52fbda 100644 --- a/src/sage/libs/symmetrica/symmetrica.pxi +++ b/src/sage/libs/symmetrica/symmetrica.pxi @@ -401,7 +401,7 @@ cdef void late_import(): SymmetricFunctions, \ sqrt, \ builtinlist, \ - MPolynomialRing_base, is_MPolynomial,\ + MPolynomialRing_base, MPolynomial,\ SchubertPolynomialRing, SchubertPolynomial_class,\ two, fifteen, thirty, zero, sage_maxint @@ -453,8 +453,8 @@ cdef void late_import(): import sage.rings.polynomial.multi_polynomial_ring MPolynomialRing_base = sage.rings.polynomial.multi_polynomial_ring.MPolynomialRing_base - import sage.rings.polynomial.multi_polynomial_element - is_MPolynomial = sage.rings.polynomial.multi_polynomial_element.is_MPolynomial + import sage.rings.polynomial.multi_polynomial + MPolynomial = sage.rings.polynomial.multi_polynomial.MPolynomial import sage.combinat.schubert_polynomial SchubertPolynomialRing = sage.combinat.schubert_polynomial.SchubertPolynomialRing diff --git a/src/sage/logic/__init__.py b/src/sage/logic/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/logic/boolformula.py b/src/sage/logic/boolformula.py index 137edb8e8a2..ae2c1ee6aba 100644 --- a/src/sage/logic/boolformula.py +++ b/src/sage/logic/boolformula.py @@ -1167,7 +1167,7 @@ def convert_opt(self, tree): lval = ('prop', tree[1]) else: lval = tree[1] - if not isinstance(tree[2], tuple) and not(tree[2] is None): + if not isinstance(tree[2], tuple) and tree[2] is not None: rval = ('prop', tree[2]) else: rval = tree[2] @@ -1557,5 +1557,6 @@ def length(self): # `len(self)`, but this may be deprecated in the future (see :trac:`32148`): __len__ = length + # allow is_consequence to be called as a function (not only as a method of BooleanFormula) is_consequence = BooleanFormula.is_consequence diff --git a/src/sage/logic/logic.py b/src/sage/logic/logic.py index 13a45b337ff..16a9cf9a1da 100644 --- a/src/sage/logic/logic.py +++ b/src/sage/logic/logic.py @@ -326,10 +326,9 @@ def combine(self, statement1, statement2): var_order = statement1[2] + statement2[2] return [toks, variables, var_order] - - #TODO: implement the simplify function which calls - #a c++ implementation of the ESPRESSO algorithm - #to simplify the truthtable: probably Minilog + # TODO: implement the simplify function which calls + # a c++ implementation of the ESPRESSO algorithm + # to simplify the truthtable: probably Minilog def simplify(self, table): """ Call a C++ implementation of the ESPRESSO algorithm to simplify the diff --git a/src/sage/logic/logicparser.py b/src/sage/logic/logicparser.py index b854f416127..7c234f2ff7e 100644 --- a/src/sage/logic/logicparser.py +++ b/src/sage/logic/logicparser.py @@ -158,7 +158,7 @@ def polish_parse(s): raise SyntaxError("malformed statement") toks, vars_order = tokenize(s) - tree = tree_parse(toks, polish = True) + tree = tree_parse(toks, polish=True) # special case where the formula s is a single variable if isinstance(tree, str): return vars_order @@ -568,7 +568,7 @@ def tree_parse(toks, polish=False): while tok != '(': tok = stack.pop() lrtoks.insert(0, tok) - branch = parse_ltor(lrtoks[1:-1], polish = polish) + branch = parse_ltor(lrtoks[1:-1], polish=polish) stack.append(branch) return stack[0] @@ -643,7 +643,7 @@ def parse_ltor(toks, n=0, polish=False): toks[j - 1] = args del toks[j] j -= 1 - return parse_ltor(toks, n = n, polish = polish) + return parse_ltor(toks, n=n, polish=polish) else: args = [toks[i - 1], toks[i], toks[i + 1]] toks[i - 1] = [args[1], args[0], args[2]] diff --git a/src/sage/logic/propcalc.py b/src/sage/logic/propcalc.py index 2ff45801bf0..2533cdac702 100644 --- a/src/sage/logic/propcalc.py +++ b/src/sage/logic/propcalc.py @@ -310,5 +310,6 @@ def consistent(*formulas): # if conjunction is a contradiction, the formulas are inconsistent return not conjunction.is_contradiction() + # define function ``valid_consequence`` for backward compatibility valid_consequence = deprecated_function_alias(28052, boolformula.is_consequence) diff --git a/src/sage/manifolds/__init__.py b/src/sage/manifolds/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/manifolds/chart.py b/src/sage/manifolds/chart.py index 8d0c89c3fd8..92c4cabbccd 100644 --- a/src/sage/manifolds/chart.py +++ b/src/sage/manifolds/chart.py @@ -2266,7 +2266,7 @@ def _display_coord_range(self, xx, rtxt, rlatex): rlatex += r"\right]" if bounds[1][1] == 'periodic': rtxt += " (periodic)" - rlatex += r"\mbox{(periodic)}" + rlatex += r"\text{(periodic)}" else: rtxt += ")" rlatex += r"\right)" diff --git a/src/sage/manifolds/continuous_map.py b/src/sage/manifolds/continuous_map.py index 20cc672a644..b6404a9bd94 100644 --- a/src/sage/manifolds/continuous_map.py +++ b/src/sage/manifolds/continuous_map.py @@ -505,7 +505,7 @@ def _latex_(self): """ if self._latex_name is None: - return r'\mbox{' + str(self) + r'}' + return r'\text{' + str(self) + r'}' else: return self._latex_name @@ -1119,7 +1119,7 @@ def display(self, chart1=None, chart2=None): sage: latex(Phi.display(c_xy, c_cart)) \begin{array}{llcl} \Phi:& S^2 & \longrightarrow & \RR^3 - \\ \mbox{on}\ U : & \left(x, y\right) & \longmapsto + \\ \text{on}\ U : & \left(x, y\right) & \longmapsto & \left(X, Y, Z\right) = \left(\frac{2 \, x}{x^{2} + y^{2} + 1}, \frac{2 \, y}{x^{2} + y^{2} + 1}, \frac{x^{2} + y^{2} - 1}{x^{2} + y^{2} + 1}\right) @@ -1176,7 +1176,7 @@ def display(self, chart1=None, chart2=None): 2*y/(x**2 + y**2 + 1), (x**2 + y**2 - 1)/(x**2 + y**2 + 1)) sage: latex(Phi.display(c_xy, c_cart)) \begin{array}{llcl} \Phi:& S^2 & \longrightarrow & \RR^3 - \\ \mbox{on}\ U : & \left(x, y\right) & \longmapsto + \\ \text{on}\ U : & \left(x, y\right) & \longmapsto & \left(X, Y, Z\right) = \left(\frac{2 x}{x^{2} + y^{2} + 1}, \frac{2 y}{x^{2} + y^{2} + 1}, \frac{x^{2} + y^{2} - 1}{x^{2} + y^{2} + 1}\right) @@ -1212,7 +1212,7 @@ def _display_expression(self, chart1, chart2, result): result._latex += ' & ' else: result._txt += 'on ' + chart1._domain._name + ': ' - result._latex += r'\mbox{on}\ ' + latex(chart1._domain) + \ + result._latex += r'\text{on}\ ' + latex(chart1._domain) + \ r': & ' result._txt += repr(coords1) + ' ' + unicode_mapsto + ' ' result._latex += latex(coords1) + r'& \longmapsto & ' diff --git a/src/sage/manifolds/differentiable/__init__.py b/src/sage/manifolds/differentiable/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/manifolds/differentiable/affine_connection.py b/src/sage/manifolds/differentiable/affine_connection.py index 008f13be22e..1a45b219872 100644 --- a/src/sage/manifolds/differentiable/affine_connection.py +++ b/src/sage/manifolds/differentiable/affine_connection.py @@ -289,7 +289,7 @@ class AffineConnection(SageObject): True sage: nab.restrict(V)(a.restrict(U)) == da.restrict(W) True - sage: nab.restrict(U)(a.restrict(V)) == da.restrict(W) + sage: nab.restrict(U)(a.restrict(V)) == da.restrict(W) # long time True Same examples with SymPy as the engine for symbolic calculus:: @@ -1918,17 +1918,17 @@ def riemann(self): ....: for j in M.irange(): ....: for k in M.irange(): ....: nab.add_coef(eV)[i,j,k] = nab.coef(eVW)[i,j,k,c_uvW].expr() - sage: r = nab.riemann() ; r + sage: r = nab.riemann() ; r # long time Tensor field of type (1,3) on the 2-dimensional differentiable manifold M - sage: r.parent() + sage: r.parent() # long time Module T^(1,3)(M) of type-(1,3) tensors fields on the 2-dimensional differentiable manifold M - sage: r.display(eU) + sage: r.display(eU) # long time (x^2*y - x*y^2) โˆ‚/โˆ‚xโŠ—dxโŠ—dxโŠ—dy + (-x^2*y + x*y^2) โˆ‚/โˆ‚xโŠ—dxโŠ—dyโŠ—dx + โˆ‚/โˆ‚xโŠ—dyโŠ—dxโŠ—dy - โˆ‚/โˆ‚xโŠ—dyโŠ—dyโŠ—dx - (x^2 - 1)*y โˆ‚/โˆ‚yโŠ—dxโŠ—dxโŠ—dy + (x^2 - 1)*y โˆ‚/โˆ‚yโŠ—dxโŠ—dyโŠ—dx + (-x^2*y + x*y^2) โˆ‚/โˆ‚yโŠ—dyโŠ—dxโŠ—dy + (x^2*y - x*y^2) โˆ‚/โˆ‚yโŠ—dyโŠ—dyโŠ—dx - sage: r.display(eV) + sage: r.display(eV) # long time (1/32*u^3 - 1/32*u*v^2 - 1/32*v^3 + 1/32*(u^2 + 4)*v - 1/8*u - 1/4) โˆ‚/โˆ‚uโŠ—duโŠ—duโŠ—dv + (-1/32*u^3 + 1/32*u*v^2 + 1/32*v^3 - 1/32*(u^2 + 4)*v + 1/8*u + 1/4) โˆ‚/โˆ‚uโŠ—duโŠ—dvโŠ—du + (1/32*u^3 - 1/32*u*v^2 + 3/32*v^3 - 1/32*(3*u^2 - 4)*v - 1/8*u + 1/4) โˆ‚/โˆ‚uโŠ—dvโŠ—duโŠ—dv @@ -1941,20 +1941,20 @@ def riemann(self): The same computation parallelized on 2 cores:: sage: Parallelism().set(nproc=2) - sage: r_backup = r + sage: r_backup = r # long time sage: nab = M.affine_connection('nabla', r'\nabla') sage: nab[0,0,0], nab[0,1,0], nab[1,0,1] = x, x-y, x*y sage: for i in M.irange(): ....: for j in M.irange(): ....: for k in M.irange(): ....: nab.add_coef(eV)[i,j,k] = nab.coef(eVW)[i,j,k,c_uvW].expr() - sage: r = nab.riemann() ; r + sage: r = nab.riemann() ; r # long time Tensor field of type (1,3) on the 2-dimensional differentiable manifold M - sage: r.parent() + sage: r.parent() # long time Module T^(1,3)(M) of type-(1,3) tensors fields on the 2-dimensional differentiable manifold M - sage: r == r_backup + sage: r == r_backup # long time True sage: Parallelism().set(nproc=1) # switch off parallelization @@ -1996,15 +1996,16 @@ def riemann(self): @parallel(p_iter='multiprocessing', ncpus=nproc) def make_Riem(frame, gam, gam_gam, gam_sc, local_list_ijkl): partial = [] - for i,j,k,l in local_list_ijkl: - partial.append([i,j,k,l, frame[k](gam[[i,j,l]]) - \ - frame[l](gam[[i,j,k]]) + \ - gam_gam[[i,k,j,l]] - \ - gam_gam[[i,l,j,k]] - \ - gam_sc[[i,j,k,l]]]) + for i, j, k, l in local_list_ijkl: + partial.append([i, j, k, l, + frame[k](gam[[i, j, l]]) - + frame[l](gam[[i, j, k]]) + + gam_gam[[i, k, j, l]] - + gam_gam[[i, l, j, k]] - + gam_sc[[i, j, k, l]]]) return partial # Computation and assignation of values - for ii,val in make_Riem(listParalInput): + for ii, val in make_Riem(listParalInput): for jj in val: res[jj[0], jj[1], jj[2], jj[3]] = jj[4] @@ -2177,13 +2178,13 @@ def connection_form(self, i, j, frame=None): sage: v = M.vector_field() sage: v[:] = (x*y, z^2-3*x, z+2*y) sage: b = M.default_frame() - sage: for j in M.irange(): # check on M's default frame + sage: for j in M.irange(): # check on M's default frame # long time ....: nab(b[j]).contract(v) == \ ....: sum( nab.connection_form(i,j)(v)*b[i] for i in M.irange()) True True True - sage: for j in M.irange(): # check on frame e + sage: for j in M.irange(): # check on frame e # long time ....: nab(e[j]).contract(v) == \ ....: sum( nab.connection_form(i,j,e)(v)*e[i] for i in M.irange()) True @@ -2210,7 +2211,7 @@ def connection_form(self, i, j, frame=None): comega[k] = coef_frame[[i1,j1,k]] forms[(i1,j1)] = omega self._connection_forms[frame] = forms - return self._connection_forms[frame][(i,j)] + return self._connection_forms[frame][(i,j)] def torsion_form(self, i, frame=None): r""" @@ -2270,10 +2271,10 @@ def torsion_form(self, i, frame=None): sage: ef = e.coframe() sage: ef[1][:], ef[2][:], ef[3][:] ([1/y, 0, 0], [0, 1/z, 0], [0, 0, 1/x]) - sage: nab.torsion_form(1, e) + sage: nab.torsion_form(1, e) # long time 2-form torsion (1) of connection nabla w.r.t. Vector frame (M, (e_1,e_2,e_3)) on the 3-dimensional differentiable manifold M - sage: nab.torsion_form(1, e).comp(e)[:] + sage: nab.torsion_form(1, e).comp(e)[:] # long time [ 0 -x^2*z (x*y^2 + x*y)*z] [ x^2*z 0 (x^4 - x^3 + x*y^2)*z/y] [ -(x*y^2 + x*y)*z -(x^4 - x^3 + x*y^2)*z/y 0] @@ -2312,7 +2313,7 @@ def torsion_form(self, i, frame=None): ctheta[k,l] = torsion_comp[[i1,k,l]] forms[i1] = theta self._torsion_forms[frame] = forms - return self._torsion_forms[frame][i] + return self._torsion_forms[frame][i] def curvature_form(self, i, j, frame=None): r""" @@ -2422,7 +2423,7 @@ def curvature_form(self, i, j, frame=None): comega[k,l] = riemann_comp[[i1,j1,k,l]] forms[(i1,j1)] = omega self._curvature_forms[frame] = forms - return self._curvature_forms[frame][(i,j)] + return self._curvature_forms[frame][(i, j)] def set_calc_order(self, symbol, order, truncate=False): r""" diff --git a/src/sage/combinat/species/__init__.py b/src/sage/manifolds/differentiable/all.py similarity index 100% rename from src/sage/combinat/species/__init__.py rename to src/sage/manifolds/differentiable/all.py diff --git a/src/sage/manifolds/differentiable/automorphismfield_group.py b/src/sage/manifolds/differentiable/automorphismfield_group.py index 0791f0b9f24..72955d48b3c 100644 --- a/src/sage/manifolds/differentiable/automorphismfield_group.py +++ b/src/sage/manifolds/differentiable/automorphismfield_group.py @@ -175,7 +175,6 @@ def __init__(self, vector_field_module): Parent.__init__(self, category=Groups()) self._vmodule = vector_field_module - #### Parent methods #### def _element_constructor_(self, comp=[], frame=None, name=None, @@ -266,7 +265,6 @@ def _an_element_(self): #### End of parent methods #### - #### Monoid methods #### @cached_method diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 689760625da..7289f67b913 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -290,7 +290,7 @@ from .bundle_connection import BundleConnection from .levi_civita_connection import LeviCivitaConnection from sage.symbolic.expression import Expression -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -795,7 +795,7 @@ def _element_constructor_(self, x, **kwargs): Characteristic cohomology class pontr(TM) of the Tangent bundle TM over the 8-dimensional differentiable manifold M """ - if isinstance(x, (str, Expression)) or is_Polynomial(x): + if isinstance(x, (str, Expression)) or isinstance(x, Polynomial): return self._build_element(x, **kwargs) R = self.base_ring() @@ -983,7 +983,7 @@ def _build_element(self, *args, **kwargs): val = P(val.taylor(x, 0, pow_range)) # turn polynomial into a characteristic cohomology class via sequences - if is_Polynomial(val): + if isinstance(val, Polynomial): if class_type is None: raise TypeError(f'class_type must be stated if {val} ' f'is a polynomial') @@ -1301,9 +1301,9 @@ def get_local(self, cmat): sage: g = M.metric() sage: nab = g.connection() sage: e = M.frames()[0] # select standard frame - sage: cmat = [ [nab.curvature_form(i, j, e) # long time - ....: for j in TM.irange()] # long time - ....: for i in TM.irange()] # long time + sage: cmat = [ [nab.curvature_form(i, j, e) # long time + ....: for j in TM.irange()] + ....: for i in TM.irange()] Import the algorithm:: @@ -1500,8 +1500,8 @@ def get_local(self, cmat): sage: nab = g.connection() sage: e = M.frames()[0] # select standard frame sage: cmat = [ [nab.curvature_form(i, j, e) # long time - ....: for j in TM.irange()] # long time - ....: for i in TM.irange()] # long time + ....: for j in TM.irange()] + ....: for i in TM.irange()] Import the algorithm:: @@ -1797,9 +1797,9 @@ def get_local(self, cmat): sage: g = M.metric() sage: nab = g.connection() sage: e = M.frames()[0] # select the standard frame - sage: cmat = [ [nab.curvature_form(i, j, e) # long time - ....: for j in TM.irange()] # long time - ....: for i in TM.irange()] # long time + sage: cmat = [ [nab.curvature_form(i, j, e) # long time + ....: for j in TM.irange()] + ....: for i in TM.irange() ] Import the algorithm:: diff --git a/src/sage/manifolds/differentiable/chart.py b/src/sage/manifolds/differentiable/chart.py index 098f85516bf..6ea06b662ed 100644 --- a/src/sage/manifolds/differentiable/chart.py +++ b/src/sage/manifolds/differentiable/chart.py @@ -679,7 +679,6 @@ def symbolic_velocities(self, left='D', right=None): return list(var(list_strings_velocities)) - #***************************************************************************** class RealDiffChart(DiffChart, RealChart): @@ -1001,7 +1000,6 @@ def __init__(self, domain, coordinates, calc_method=None, self._frame = CoordFrame(self) self._coframe = self._frame._coframe - def restrict(self, subset, restrictions=None): r""" Return the restriction of the chart to some subset. diff --git a/src/sage/manifolds/differentiable/curve.py b/src/sage/manifolds/differentiable/curve.py index ca7cef3f626..7ee1517c43d 100644 --- a/src/sage/manifolds/differentiable/curve.py +++ b/src/sage/manifolds/differentiable/curve.py @@ -186,7 +186,7 @@ class DifferentiableCurve(DiffMap): sage: c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi)) sage: latex(c) - \mbox{Curve in the 2-dimensional differentiable manifold M} + \text{Curve in the 2-dimensional differentiable manifold M} sage: c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c') sage: latex(c) c diff --git a/src/sage/manifolds/differentiable/degenerate.py b/src/sage/manifolds/differentiable/degenerate.py index 0fddd642e17..30846aa6891 100644 --- a/src/sage/manifolds/differentiable/degenerate.py +++ b/src/sage/manifolds/differentiable/degenerate.py @@ -368,7 +368,6 @@ def open_subset(self, name, latex_name=None, coord_def={}): return resu - #******************************************************************************************* from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal diff --git a/src/sage/manifolds/differentiable/degenerate_submanifold.py b/src/sage/manifolds/differentiable/degenerate_submanifold.py index 5d5ebb3de0f..67d5228f2d9 100644 --- a/src/sage/manifolds/differentiable/degenerate_submanifold.py +++ b/src/sage/manifolds/differentiable/degenerate_submanifold.py @@ -1323,7 +1323,6 @@ def principal_directions(self, screen=None): self._principal_directions[screen._name] = res return res - def mean_curvature(self, screen=None): r""" diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index ec6a8d353f3..d5d817ab404 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -619,6 +619,7 @@ def hodge_dual( nondegenerate_tensor: Union[ PseudoRiemannianMetric, SymplecticForm, None ] = None, + minus_eigenvalues_convention: bool = False, ) -> DiffForm: r""" Compute the Hodge dual of the differential form with respect to some non-degenerate @@ -630,13 +631,18 @@ def hodge_dual( .. MATH:: - *A_{i_1\ldots i_{n-p}} = \frac{1}{p!} A_{k_1\ldots k_p} - \epsilon^{k_1\ldots k_p}_{\qquad\ i_1\ldots i_{n-p}} + *A_{i_1\ldots i_{n-p}} = \frac{1}{p!} A^{k_1\ldots k_p} + \epsilon_{k_1\ldots k_p\, i_1\ldots i_{n-p}} where `n` is the manifold's dimension, `\epsilon` is the volume `n`-form associated with `g` (see :meth:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric.volume_form`) and the indices `k_1,\ldots, k_p` are raised with `g`. + If `g` is a pseudo-Riemannian metric, sometimes an additional multiplicative + factor of `(-1)^s` is introduced on the right-hand side, + where `s` is the number of negative eigenvalues of `g`. + This convention can be enforced by setting the option + ``minus_eigenvalues_convention``. INPUT: @@ -646,6 +652,9 @@ def hodge_dual( :class:`~sage.manifolds.differentiable.symplectic_form.SymplecticForm`. If none is provided, the ambient domain of ``self`` is supposed to be endowed with a default metric and this metric is then used. + - ``minus_eigenvalues_convention`` -- if `true`, a factor of `(-1)^s` is + introduced with `s` being the number of negative eigenvalues of the + ``nondegenerate_tensor``. OUTPUT: @@ -772,6 +781,9 @@ def hodge_dual( nondegenerate_tensor = self._vmodule._ambient_domain.metric() p = self.tensor_type()[1] + # For performance reasons, we raise the indicies of the volume form + # and not of the differential form; in the symplectic case this is wrong by + # a factor of (-1)^p, which will be corrected below eps = nondegenerate_tensor.volume_form(p) if p == 0: common_domain = nondegenerate_tensor.domain().intersection(self.domain()) @@ -780,6 +792,15 @@ def hodge_dual( result = self.contract(*range(p), eps, *range(p)) if p > 1: result = result / factorial(p) + if minus_eigenvalues_convention: + from sage.manifolds.differentiable.metric import PseudoRiemannianMetric + if isinstance(nondegenerate_tensor, PseudoRiemannianMetric): + result = result * nondegenerate_tensor._indic_signat + from sage.manifolds.differentiable.symplectic_form import SymplecticForm + if isinstance(nondegenerate_tensor, SymplecticForm): + # correction because we lifted the indicies of the volume (see above) + result = result * (-1)**p + result.set_name( name=format_unop_txt("*", self._name), latex_name=format_unop_latex(r"\star ", self._latex_name), @@ -1556,7 +1577,6 @@ def wedge(self, other): other_r = other.restrict(dom_resu) return FreeModuleAltForm.wedge(self_r, other_r) - def interior_product(self, qvect): r""" Interior product with a multivector field. diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index 04d85a0817d..e11a32d2131 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -498,7 +498,7 @@ def _latex_(self): """ if self._latex_name is None: - return r'\mbox{' + str(self) + r'}' + return r'\text{' + str(self) + r'}' else: return self._latex_name diff --git a/src/sage/manifolds/differentiable/diff_map.py b/src/sage/manifolds/differentiable/diff_map.py index 7f0c09a6b7c..ded6843afb3 100644 --- a/src/sage/manifolds/differentiable/diff_map.py +++ b/src/sage/manifolds/differentiable/diff_map.py @@ -32,11 +32,17 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from __future__ import annotations + +from typing import TYPE_CHECKING from sage.manifolds.continuous_map import ContinuousMap from sage.parallel.decorate import parallel from sage.parallel.parallelism import Parallelism +if TYPE_CHECKING: + from sage.manifolds.point import ManifoldPoint + from sage.tensor.modules.free_module_morphism import FiniteRankFreeModuleMorphism class DiffMap(ContinuousMap): r""" @@ -515,7 +521,7 @@ def _del_derived(self): # class self._diff.clear() - def differential(self, point): + def differential(self, point: ManifoldPoint) -> FiniteRankFreeModuleMorphism: r""" Return the differential of ``self`` at a given point. @@ -949,8 +955,12 @@ def pullback(self, tensor_or_codomain_subset, name=None, latex_name=None): tensor = tensor_or_codomain_subset from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal - from sage.tensor.modules.comp import (Components, CompWithSym, - CompFullySym, CompFullyAntiSym) + from sage.tensor.modules.comp import ( + CompFullyAntiSym, + CompFullySym, + Components, + CompWithSym, + ) def _pullback_chart(diff_map, tensor, chart1, chart2): r""" @@ -1134,7 +1144,6 @@ def paral_comp(tcomp, chart1, chart2, coord2_1, jacob, resu._components[frame] = comp return resu - def pushforward(self, tensor): r""" Pushforward operator associated with ``self``. @@ -1195,9 +1204,13 @@ def pushforward(self, tensor): Psi_*(u) = -sin(t) โˆ‚/โˆ‚x + cos(t) โˆ‚/โˆ‚y + โˆ‚/โˆ‚z """ - from sage.tensor.modules.comp import (Components, CompWithSym, - CompFullySym, CompFullyAntiSym) from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal + from sage.tensor.modules.comp import ( + CompFullyAntiSym, + CompFullySym, + Components, + CompWithSym, + ) vmodule = tensor.base_module() dest_map = vmodule.destination_map() dom1 = tensor.domain() diff --git a/src/sage/manifolds/differentiable/examples/__init__.py b/src/sage/manifolds/differentiable/examples/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/crypto/block_cipher/__init__.py b/src/sage/manifolds/differentiable/examples/all.py similarity index 100% rename from src/sage/crypto/block_cipher/__init__.py rename to src/sage/manifolds/differentiable/examples/all.py diff --git a/src/sage/manifolds/differentiable/examples/euclidean.py b/src/sage/manifolds/differentiable/examples/euclidean.py index 3c24482356b..21ae796fad5 100644 --- a/src/sage/manifolds/differentiable/examples/euclidean.py +++ b/src/sage/manifolds/differentiable/examples/euclidean.py @@ -694,7 +694,7 @@ def __classcall_private__(cls, n=None, name=None, latex_name=None, if names[1] in ['p', 'ph', 'phi']: names[1] = names[1] + ':\\phi' - symbols = ' '.join(x for x in names) + symbols = ' '.join(names) # Technical bit for UniqueRepresentation from sage.misc.prandom import getrandbits diff --git a/src/sage/manifolds/differentiable/integrated_curve.py b/src/sage/manifolds/differentiable/integrated_curve.py index 8b62aab4f39..74f76ab3e33 100644 --- a/src/sage/manifolds/differentiable/integrated_curve.py +++ b/src/sage/manifolds/differentiable/integrated_curve.py @@ -579,7 +579,6 @@ def fast_CoF(pos, vel, M=M): for f in transf] self._fast_changes_of_chart[CoC] = fast_transf - self._velocities = list(velocities) # converts to list # since might not already be a list (which is later required) self._curve_parameter = curve_parameter @@ -1376,13 +1375,11 @@ def jacobian(t,y): # 'tangent_vector_eval_at', and in 'plot' when plotting the # tangent vectors.) - if isinstance(sol, list): coords_sol = [point[0:dim + 1] for point in sol] else: coords_sol = sol[:, 0:dim + 1].tolist() # far faster in numpy - if verbose: print("Numerical integration completed.\n\n" + "Checking all points are in the chart domain...") @@ -1779,7 +1776,6 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, new_vel = self._fast_changes_of_frame[(new_chart.frame().restrict(inter), chart.frame().restrict(inter))](last_pts, last_vel) - ics = new_pts + new_vel chart = new_chart @@ -2434,7 +2430,6 @@ def plot_integrated(self, chart=None, ambient_coords=None, thickness = kwds.pop('thickness') aspect_ratio = kwds.pop('aspect_ratio') - # # The mapping, if present, and the chart with respect to which the curve # is plotted @@ -3425,7 +3420,6 @@ def __init__(self, parent, affine_connection, curve_parameter, velocities = chart.symbolic_velocities() - dim = parent.codomain().dim() i0 = parent.codomain().start_index() @@ -3470,7 +3464,6 @@ def __init__(self, parent, affine_connection, curve_parameter, equations_rhs_chart += [rhs.simplify_full()] equations_rhs[chart] = equations_rhs_chart - IntegratedCurve.__init__(self, parent, equations_rhs, velocities, curve_parameter, initial_tangent_vector, chart=chart, @@ -3479,7 +3472,6 @@ def __init__(self, parent, affine_connection, curve_parameter, self._affine_connection = affine_connection - def _repr_(self): r""" Return a string representation of ``self``. @@ -3825,7 +3817,6 @@ class IntegratedGeodesic(IntegratedAutoparallelCurve): def __init__(self, parent, metric, curve_parameter, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): - r""" Construct a geodesic curve with respect to the given metric with the given initial tangent vector. diff --git a/src/sage/manifolds/differentiable/levi_civita_connection.py b/src/sage/manifolds/differentiable/levi_civita_connection.py index 3b8095004e3..7ff2643e32b 100644 --- a/src/sage/manifolds/differentiable/levi_civita_connection.py +++ b/src/sage/manifolds/differentiable/levi_civita_connection.py @@ -387,7 +387,6 @@ def _new_coef(self, frame): start_index=self._domain._sindex, output_formatter=DiffScalarField.coord_function) - def coef(self, frame=None): r""" Return the connection coefficients relative to the given frame. diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index e674ad8db05..904e291ab8e 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -454,6 +454,7 @@ if TYPE_CHECKING: from sage.manifolds.differentiable.diff_map import DiffMap + from sage.manifolds.differentiable.diff_form import DiffForm from sage.manifolds.differentiable.metric import PseudoRiemannianMetric from sage.manifolds.differentiable.vectorfield_module import ( VectorFieldFreeModule, @@ -2177,7 +2178,7 @@ def multivector_field(self, *args, **kwargs): resu._init_components(args[1], **kwargs) return resu - def diff_form(self, *args, **kwargs): + def diff_form(self, *args, **kwargs) -> DiffForm: r""" Define a differential form on ``self``. @@ -2281,7 +2282,7 @@ def diff_form(self, *args, **kwargs): resu._init_components(args[1], **kwargs) return resu - def one_form(self, *comp, **kwargs): + def one_form(self, *comp, **kwargs) -> DiffForm: r""" Define a 1-form on the manifold. @@ -2977,7 +2978,6 @@ def change_of_frame(self, frame1, frame2): " has not been defined on the {}".format(self)) return self._frame_changes[(frame1, frame2)] - def set_change_of_frame(self, frame1, frame2, change_of_frame, compute_inverse=True): r""" diff --git a/src/sage/manifolds/differentiable/manifold_homset.py b/src/sage/manifolds/differentiable/manifold_homset.py index 7152774ec75..2d35505f63c 100644 --- a/src/sage/manifolds/differentiable/manifold_homset.py +++ b/src/sage/manifolds/differentiable/manifold_homset.py @@ -777,7 +777,6 @@ def _repr_(self): description += "which actually are integrated curves" return description - def _element_constructor_(self, equations_rhs, velocities, curve_parameter, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): @@ -1221,7 +1220,6 @@ def _repr_(self): description += "curves with respect to a certain affine connection" return description - def _element_constructor_(self, affine_connection, curve_parameter, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): diff --git a/src/sage/manifolds/differentiable/metric.py b/src/sage/manifolds/differentiable/metric.py index 6dece42f0fe..8211ad1a625 100644 --- a/src/sage/manifolds/differentiable/metric.py +++ b/src/sage/manifolds/differentiable/metric.py @@ -447,7 +447,7 @@ def _new_instance(self): """ return type(self)(self._vmodule, 'unnamed metric', signature=self._signature, - latex_name=r'\mbox{unnamed metric}') + latex_name=r'\text{unnamed metric}') def _init_derived(self): r""" @@ -662,7 +662,6 @@ def set(self, symbiform): rst = self.restrict(dom) rst.set(symbiform_rst) - def inverse(self, expansion_symbol=None, order=1): r""" Return the inverse metric. @@ -879,7 +878,6 @@ def christoffel_symbols(self, chart=None): frame = chart._frame return self.connection().coef(frame) - def christoffel_symbols_display(self, chart=None, symbol=None, latex_symbol=None, index_labels=None, index_latex_labels=None, coordinate_labels=True, only_nonzero=True, @@ -1069,7 +1067,6 @@ def riemann(self, name=None, latex_name=None): """ return self.connection().riemann(name, latex_name) - def ricci(self, name=None, latex_name=None): r""" Return the Ricci tensor associated with the metric. @@ -2271,7 +2268,6 @@ def restrict(self, subdomain, dest_map=None): self._restrictions[subdomain] = resu return self._restrictions[subdomain] - def set(self, symbiform): r""" Define the metric from a field of symmetric bilinear forms. @@ -2706,7 +2702,7 @@ def _new_instance(self): """ return type(self)(self._vmodule, 'unnamed metric', signature=self._signature, - latex_name=r'\mbox{unnamed metric}') + latex_name=r'\text{unnamed metric}') def signature(self): r""" diff --git a/src/sage/manifolds/differentiable/mixed_form.py b/src/sage/manifolds/differentiable/mixed_form.py index 2a30ececa45..7c6872c594b 100644 --- a/src/sage/manifolds/differentiable/mixed_form.py +++ b/src/sage/manifolds/differentiable/mixed_form.py @@ -12,22 +12,21 @@ AUTHORS: - Michael Jung (2019) : initial version - """ - -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2019 Michael Jung <micjung@uni-potsdam.de> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#****************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.structure.element import AlgebraElement, ModuleElementWithMutability from sage.rings.integer import Integer + class MixedForm(AlgebraElement, ModuleElementWithMutability): r""" An instance of this class is a mixed form along some differentiable map @@ -253,9 +252,9 @@ def __init__(self, parent, name=None, latex_name=None): self._domain = vmodule._domain self._ambient_domain = vmodule._ambient_domain self._max_deg = vmodule._ambient_domain.dim() - self._is_zero = False # a priori, may be changed below or via - # method __bool__() - self._comp = None # initialized on demand; see _init_comp + self._is_zero = False # a priori, may be changed below or via + # method __bool__() + self._comp = None # initialized on demand; see _init_comp # Set names: self._name = name if latex_name is None: @@ -289,7 +288,7 @@ def _init_comp(self): comp_latex_name = '{' + self._latex_name + '}_{' + str(i) + '}' diff_form = self._domain.diff_form self._comp.append(diff_form(i, name=comp_name, - latex_name=comp_latex_name)) + latex_name=comp_latex_name)) def _repr_(self): r""" @@ -347,7 +346,7 @@ def _latex_(self): """ if self._name is None: - return r'\mbox{' + repr(self) + r'}' + return r'\text{' + repr(self) + r'}' else: return self._latex_name @@ -487,7 +486,7 @@ def display_expansion(self, frame=None, chart=None, from_chart=None): if is_atomic(coef_latex): terms_latex.append(coef_latex + basis_term_latex) else: - terms_latex.append(r"\left(" + coef_latex + \ + terms_latex.append(r"\left(" + coef_latex + r"\right)" + basis_term_latex) if not terms_txt: resu_txt += "0" @@ -549,7 +548,7 @@ def display(self): else: resu_txt += self[0]._name if self[0]._latex_name is None: - resu_latex += r"\mbox{(unnamed scalar field)}" + resu_latex += r"\text{(unnamed scalar field)}" else: resu_latex += latex(self[0]) # Differential forms: @@ -559,7 +558,7 @@ def display(self): else: resu_txt += " + " + self[j]._name if self[j]._latex_name is None: - resu_latex += r"+\mbox{(unnamed " + str(j) + r"-form)}" + resu_latex += r"+\text{(unnamed " + str(j) + r"-form)}" else: resu_latex += r"+" + latex(self[j]) return FormattedExpansion(resu_txt, resu_latex) @@ -614,11 +613,10 @@ def set_name(self, name=None, latex_name=None, apply_to_comp=True): sage: F[0].set_name(name='g'); F.display() eta = g + F_1 + F_2 + F_3 + F_4 - """ if self.is_immutable(): raise ValueError("the name of an immutable element " - "cannot be changed") + "cannot be changed") if name is not None: self._name = name if latex_name is None: @@ -991,7 +989,7 @@ def wedge(self, other): return self # Generic case: resu = self._new_instance() - resu._comp = [sum(self[k].wedge(other[j-k]) for k in range(j+1)) + resu._comp = [sum(self[k].wedge(other[j - k]) for k in range(j + 1)) for j in self.irange()] # Compose name: from sage.typeset.unicode_characters import unicode_wedge diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py index 6fda4d48567..83c741fa8af 100644 --- a/src/sage/manifolds/differentiable/multivector_module.py +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -444,7 +444,7 @@ def _latex_(self): """ if self._latex_name is None: - return r'\mbox{' + str(self) + r'}' + return r'\text{' + str(self) + r'}' else: return self._latex_name diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 307e35495f5..2590803b0fa 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -1393,25 +1393,29 @@ def bracket(self, other): Let us check the graded Leibniz rule for `p=1` and `q=1`:: - sage: a.bracket(b.wedge(c)) == a.bracket(b).wedge(c) + b.wedge(a.bracket(c)) + sage: a.bracket(b.wedge(c)) == a.bracket(b).wedge(c) + b.wedge(a.bracket(c)) # long time True as well as for `p=2` and `q=1`:: - sage: c.bracket(a.wedge(b)) == c.bracket(a).wedge(b) - a.wedge(c.bracket(b)) + sage: c.bracket(a.wedge(b)) == c.bracket(a).wedge(b) - a.wedge(c.bracket(b)) # long time True Finally let us check the graded Jacobi identity for `p=1`, `q=1` and `r=2`:: - sage: a.bracket(b.bracket(c)) + b.bracket(c.bracket(a)) \ - ....: + c.bracket(a.bracket(b)) == 0 + sage: a_bc = a.bracket(b.bracket(c)) # long time + sage: b_ca = b.bracket(c.bracket(a)) # long time + sage: c_ab = c.bracket(a.bracket(b)) # long time + sage: a_bc + b_ca + c_ab == 0 # long time True as well as for `p=1`, `q=2` and `r=2`:: - sage: a.bracket(c.bracket(d)) + c.bracket(d.bracket(a)) \ - ....: - d.bracket(a.bracket(c)) == 0 + sage: a_cd = a.bracket(c.bracket(d)) # long time + sage: c_da = c.bracket(d.bracket(a)) # long time + sage: d_ac = d.bracket(a.bracket(c)) # long time + sage: a_cd + c_da - d_ac == 0 # long time True """ diff --git a/src/sage/manifolds/differentiable/scalarfield.py b/src/sage/manifolds/differentiable/scalarfield.py index 9763bf46352..ba5c5d70f2c 100644 --- a/src/sage/manifolds/differentiable/scalarfield.py +++ b/src/sage/manifolds/differentiable/scalarfield.py @@ -38,13 +38,15 @@ #****************************************************************************** from __future__ import annotations -from typing import Union, TYPE_CHECKING + +from typing import TYPE_CHECKING, Union + from sage.manifolds.scalarfield import ScalarField if TYPE_CHECKING: from sage.manifolds.differentiable.diff_form import DiffForm - from sage.manifolds.differentiable.symplectic_form import SymplecticForm from sage.manifolds.differentiable.metric import PseudoRiemannianMetric + from sage.manifolds.differentiable.symplectic_form import SymplecticForm class DiffScalarField(ScalarField): @@ -713,7 +715,7 @@ def tensor_type(self): """ return self._tensor_type - def differential(self): + def differential(self) -> DiffForm: r""" Return the differential of ``self``. @@ -817,7 +819,6 @@ def differential(self): derivative = differential # allows one to use functional notation, # e.g. diff(f) for f.differential() - def lie_derivative(self, vector): r""" Compute the Lie derivative with respect to a vector field. diff --git a/src/sage/manifolds/differentiable/symplectic_form.py b/src/sage/manifolds/differentiable/symplectic_form.py index c72f50b70fa..381fab1e72c 100644 --- a/src/sage/manifolds/differentiable/symplectic_form.py +++ b/src/sage/manifolds/differentiable/symplectic_form.py @@ -185,7 +185,7 @@ def _new_instance(self): return type(self)( self._vmodule, "unnamed symplectic form", - latex_name=r"\mbox{unnamed symplectic form}", + latex_name=r"\text{unnamed symplectic form}", ) def _init_derived(self): @@ -290,9 +290,9 @@ def wrap( sage: from sage.manifolds.differentiable.symplectic_form import SymplecticForm sage: M = manifolds.Sphere(2, coordinates='stereographic') - sage: vol_form = M.induced_metric().volume_form() - sage: omega = SymplecticForm.wrap(vol_form, 'omega', r'\omega') - sage: omega.display() + sage: vol_form = M.induced_metric().volume_form() # long time + sage: omega = SymplecticForm.wrap(vol_form, 'omega', r'\omega') # long time + sage: omega.display() # long time omega = -4/(y1^4 + y2^4 + 2*(y1^2 + 1)*y2^2 + 2*y1^2 + 1) dy1โˆงdy2 """ if form.degree() != 2: @@ -575,10 +575,10 @@ def hodge_star(self, pform: DiffForm) -> DiffForm: sage: omega = M.symplectic_form() sage: a = M.one_form(1, 0, name='a') sage: omega.hodge_star(a).display() - *a = -dq + *a = dq sage: b = M.one_form(0, 1, name='b') sage: omega.hodge_star(b).display() - *b = -dp + *b = dp sage: f = M.scalar_field(1, name='f') sage: omega.hodge_star(f).display() *f = -dqโˆงdp @@ -588,6 +588,54 @@ def hodge_star(self, pform: DiffForm) -> DiffForm: """ return pform.hodge_dual(self) + def on_forms(self, first: DiffForm, second: DiffForm) -> DiffScalarField: + r""" + Return the contraction of the two forms with respect to the symplectic form. + + The symplectic form `\omega` gives rise to a bilinear form, + also denoted by `\omega` on the space of `1`-forms by + + .. MATH:: + \omega(\alpha, \beta) = \omega(\alpha^\sharp, \beta^\sharp), + + where `\alpha^\sharp` is the dual of `\alpha` with respect to `\omega`, see + :meth:`~sage.manifolds.differentiable.tensor_field.TensorField.up`. + This bilinear form induces a bilinear form on the space of all forms determined + by its value on decomposable elements as: + + .. MATH:: + \omega(\alpha_1 \wedge \ldots \wedge\alpha_p, \beta_1 \wedge \ldots \wedge\beta_p) + = det(\omega(\alpha_i, \beta_j)). + + INPUT: + + - ``first`` -- a `p`-form `\alpha` + - ``second`` -- a `p`-form `\beta` + + OUTPUT: + + - the scalar field `\omega(\alpha, \beta)` + + EXAMPLES: + + sage: M = manifolds.StandardSymplecticSpace(2) + sage: omega = M.symplectic_form() + sage: a = M.one_form(1, 0, name='a') + sage: b = M.one_form(0, 1, name='b') + sage: omega.on_forms(a, b).display() + R2 โ†’ โ„ + (q, p) โ†ฆ -1 + """ + from sage.arith.misc import factorial + + if first.degree() != second.degree(): + raise ValueError("the two forms must have the same degree") + + all_positions = range(first.degree()) + return first.contract( + *all_positions, second.up(self), *all_positions + ) / factorial(first.degree()) + class SymplecticFormParal(SymplecticForm, DiffFormParal): r""" diff --git a/src/sage/manifolds/differentiable/symplectic_form_test.py b/src/sage/manifolds/differentiable/symplectic_form_test.py index f33f59d5adb..5bc519af6d3 100644 --- a/src/sage/manifolds/differentiable/symplectic_form_test.py +++ b/src/sage/manifolds/differentiable/symplectic_form_test.py @@ -1,8 +1,7 @@ +# pylint: disable=missing-function-docstring from _pytest.fixtures import FixtureRequest import pytest -# TODO: Remove sage.all import as soon as it's no longer necessary to load everything upfront -import sage.all from sage.manifolds.manifold import Manifold from sage.manifolds.differentiable.manifold import DifferentiableManifold from sage.manifolds.differentiable.examples.sphere import Sphere @@ -36,7 +35,7 @@ def test_new_instance_repr(self, omega: SymplecticForm): def test_new_instance_same_type(self, omega: SymplecticForm): omega1 = omega._new_instance() # type: ignore reportPrivateUsage - assert type(omega1) == type(omega) + assert type(omega1) is type(omega) def test_new_instance_same_parent(self, omega: SymplecticForm): omega1 = omega._new_instance() # type: ignore reportPrivateUsage @@ -125,6 +124,39 @@ def test_poisson_bracket_as_commutator_hamiltonian_vector_fields( omega.hamiltonian_vector_field(g) ) == omega.hamiltonian_vector_field(omega.poisson_bracket(f, g)) + def test_hodge_star_of_one_is_volume( + self, M: DifferentiableManifold, omega: SymplecticForm + ): + assert M.one_scalar_field().hodge_dual(omega) == omega.volume_form() + + def test_hodge_star_of_volume_is_one( + self, M: DifferentiableManifold, omega: SymplecticForm + ): + assert omega.volume_form().hodge_dual(omega) == M.one_scalar_field() + + def test_trace_of_two_form_is_given_using_contraction_with_omega( + self, M: DifferentiableManifold, omega: SymplecticForm + ): + a = M.diff_form(2) + a[1,2] = 3 + assert a.trace(using=omega) == a.up(omega, 1).trace() + + def test_omega_on_forms_is_determinant_for_decomposables( + self, M: DifferentiableManifold, omega: SymplecticForm + ): + a = M.one_form(1,2) + b = M.one_form(3,4) + c = M.one_form(5,6) + d = M.one_form(7,8) + + assert omega.on_forms(a.wedge(b), c.wedge(d)) == omega.on_forms(a,c) * omega.on_forms(b, d) - omega.on_forms(a,d) * omega.on_forms(b,c) + + def test_omega_on_one_forms_is_omega_on_dual_vectors( + self, M: DifferentiableManifold, omega: SymplecticForm + ): + a = M.one_form(1,2) + b = M.one_form(3,4) + assert omega.on_forms(a, b) == omega(a.up(omega), b.up(omega)) def generic_scalar_field(M: DifferentiableManifold, name: str) -> DiffScalarField: chart_functions = {chart: function(name)(*chart[:]) for chart in M.atlas()} @@ -158,3 +190,29 @@ def test_flat(self, M: StandardSymplecticSpace, omega: SymplecticForm): X = M.vector_field(1, 2, name="X") assert str(X.display()) == r"X = e_q + 2 e_p" assert str(omega.flat(X).display()) == r"X_flat = 2 dq - dp" + + def test_hodge_star(self, M: StandardSymplecticSpace, omega: SymplecticForm): + # Standard basis + e = M.one_form(0,1, name='e') + f = M.one_form(1,0, name='f') + assert e.wedge(f) == omega + + assert M.one_scalar_field().hodge_dual(omega) == omega + assert e.hodge_dual(omega) == e + assert f.hodge_dual(omega) == f + assert omega.hodge_dual(omega) == M.one_scalar_field() + + def test_omega_on_one_forms(self, M: StandardSymplecticSpace, omega: SymplecticForm): + # Standard basis + e = M.one_form(0,1, name='e') + f = M.one_form(1,0, name='f') + assert e.wedge(f) == omega + + assert omega.on_forms(e, f) == 1 + + def test_hodge_star_is_given_using_omega_on_forms( + self, M: StandardSymplecticSpace, omega: SymplecticForm + ): + a = M.one_form(1,2) + b = M.one_form(3,4) + assert a.wedge(b.hodge_dual(omega)) == omega.on_forms(a, b) * omega.volume_form() diff --git a/src/sage/manifolds/differentiable/tangent_space.py b/src/sage/manifolds/differentiable/tangent_space.py index aa14cc90f70..4b90e711a79 100644 --- a/src/sage/manifolds/differentiable/tangent_space.py +++ b/src/sage/manifolds/differentiable/tangent_space.py @@ -24,10 +24,16 @@ # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #****************************************************************************** +from __future__ import annotations +from typing import TYPE_CHECKING + +from sage.manifolds.differentiable.tangent_vector import TangentVector from sage.symbolic.ring import SR from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule -from sage.manifolds.differentiable.tangent_vector import TangentVector + +if TYPE_CHECKING: + from sage.manifolds.point import ManifoldPoint class TangentSpace(FiniteRankFreeModule): r""" @@ -222,7 +228,7 @@ class TangentSpace(FiniteRankFreeModule): """ Element = TangentVector - def __init__(self, point, base_ring=None): + def __init__(self, point: ManifoldPoint, base_ring=None): r""" Construct the tangent space at a given point. diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index db4a2a05aa1..861b05c1d1b 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -69,6 +69,7 @@ from sage.manifolds.differentiable.poisson_tensor import PoissonTensorField from sage.manifolds.differentiable.symplectic_form import SymplecticForm from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule + from sage.manifolds.point import ManifoldPoint from sage.tensor.modules.comp import Components @@ -108,8 +109,8 @@ class TensorField(ModuleElementWithMutability): .. MATH:: - t(p):\ \underbrace{T_q^*M\times\cdots\times T_q^*M}_{k\ \; \mbox{times}} - \times \underbrace{T_q M\times\cdots\times T_q M}_{l\ \; \mbox{times}} + t(p):\ \underbrace{T_q^*M\times\cdots\times T_q^*M}_{k\ \; \text{times}} + \times \underbrace{T_q M\times\cdots\times T_q M}_{l\ \; \text{times}} \longrightarrow K, where `T_q^* M` is the dual vector space to `T_q M` and `K` is the @@ -589,7 +590,7 @@ def _latex_(self): """ if self._latex_name is None: - return r'\mbox{' + str(self) + r'}' + return r'\text{' + str(self) + r'}' else: return self._latex_name @@ -3030,10 +3031,20 @@ def __call__(self, *args): resu._latex_name = res_latex return resu - def trace(self, pos1=0, pos2=1): + def trace( + self, + pos1=0, + pos2=1, + using: Optional[ + Union[PseudoRiemannianMetric, SymplecticForm, PoissonTensorField] + ] = None, + ): r""" Trace (contraction) on two slots of the tensor field. + If a non-degenerate form is provided, the trace of a `(0,2)` tensor field + is computed by first raising the last index. + INPUT: - ``pos1`` -- (default: 0) position of the first index for the @@ -3041,6 +3052,7 @@ def trace(self, pos1=0, pos2=1): - ``pos2`` -- (default: 1) position of the second index for the contraction, with the same convention as for ``pos1``. The variance type of ``pos2`` must be opposite to that of ``pos1`` + - ``using`` -- (default: ``None``) a non-degenerate form OUTPUT: @@ -3073,6 +3085,15 @@ def trace(self, pos1=0, pos2=1): sage: s == a.trace(0,1) # explicit mention of the positions True + The trace of a type-`(0,2)` tensor field using a metric:: + + sage: g = M.metric('g') + sage: g[0,0], g[0,1], g[1,1] = 1, 0, 1 + sage: g.trace(using=g).display() + M โ†’ โ„ + on U: (x, y) โ†ฆ 2 + on W: (u, v) โ†ฆ 2 + Instead of the explicit call to the method :meth:`trace`, one may use the index notation with Einstein convention (summation over repeated indices); it suffices to pass the indices as a string inside @@ -3139,6 +3160,13 @@ def trace(self, pos1=0, pos2=1): True """ + if using is not None: + if self.tensor_type() != (0, 2): + raise ValueError( + "trace with respect to a non-degenerate form is only defined for type-(0,2) tensor fields" + ) + return self.up(using, 1).trace() + # The indices at pos1 and pos2 must be of different types: k_con = self._tensor_type[0] l_cov = self._tensor_type[1] @@ -3634,7 +3662,7 @@ def lie_derivative(self, vector): lie_der = lie_derivative - def at(self, point): + def at(self, point: ManifoldPoint) -> FreeModuleTensor: r""" Value of ``self`` at a point of its domain. @@ -4146,7 +4174,7 @@ def divergence(self, metric=None): metric = self._domain.metric() nabla = metric.connection() if n_cov == 0: - resu = nabla(self).trace(n_con-1, n_con) + resu = nabla(self).trace(n_con-1, n_con) else: tup = self.up(metric, self._tensor_rank-1) resu = nabla(tup).trace(n_con, self._tensor_rank) diff --git a/src/sage/manifolds/differentiable/tensorfield_module.py b/src/sage/manifolds/differentiable/tensorfield_module.py index 6347189848f..8d31d670137 100644 --- a/src/sage/manifolds/differentiable/tensorfield_module.py +++ b/src/sage/manifolds/differentiable/tensorfield_module.py @@ -520,7 +520,7 @@ def _latex_(self): """ if self._latex_name is None: - return r'\mbox{' + str(self) + r'}' + return r'\text{' + str(self) + r'}' else: return self._latex_name diff --git a/src/sage/manifolds/differentiable/tensorfield_paral.py b/src/sage/manifolds/differentiable/tensorfield_paral.py index eb517832382..7cf7c40896c 100644 --- a/src/sage/manifolds/differentiable/tensorfield_paral.py +++ b/src/sage/manifolds/differentiable/tensorfield_paral.py @@ -355,8 +355,8 @@ class TensorFieldParal(FreeModuleTensor, TensorField): .. MATH:: - t(p):\ \underbrace{T_q^*M\times\cdots\times T_q^*M}_{k\ \; \mbox{times}} - \times \underbrace{T_q M\times\cdots\times T_q M}_{l\ \; \mbox{times}} + t(p):\ \underbrace{T_q^*M\times\cdots\times T_q^*M}_{k\ \; \text{times}} + \times \underbrace{T_q M\times\cdots\times T_q M}_{l\ \; \text{times}} \longrightarrow K, where `T_q^* M` is the dual vector space to `T_q M` and `K` is the @@ -657,7 +657,6 @@ def __init__(self, vector_field_module, tensor_type, name=None, # Initialization of derived quantities: self._init_derived() - def _repr_(self): r""" String representation of ``self``. @@ -769,7 +768,6 @@ def _preparse_display(self, basis=None, format_spec=None): basis = basis.frame() return (basis, format_spec) - def _set_comp_unsafe(self, basis=None): r""" Return the components of the tensor field in a given vector frame @@ -1511,7 +1509,6 @@ def paral_lie_deriv(a, b , coord_frame, chart_cp, local_list_ind): vc[[i]].coord_function(chart).diff(ind[k]) resc[[ind]] = rsum.scalar_field() - # # 3/ Final result (the tensor) res = vf_module.tensor_from_comp(self._tensor_type, resc) @@ -1590,8 +1587,9 @@ def restrict(self, subdomain: DifferentiableManifold, dest_map: Optional[DiffMap return self if subdomain not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError("the provided domain is not a subset of " + - "the field's domain") + raise ValueError( + f"the provided domain {subdomain} is not a subset of the field's domain {self._domain}" + ) if dest_map is None: dest_map = self._fmodule._dest_map.restrict(subdomain) elif not dest_map._codomain.is_subset(self._ambient_domain): diff --git a/src/sage/manifolds/differentiable/tensorfield_paral_test.py b/src/sage/manifolds/differentiable/tensorfield_paral_test.py new file mode 100644 index 00000000000..7eda28c5c49 --- /dev/null +++ b/src/sage/manifolds/differentiable/tensorfield_paral_test.py @@ -0,0 +1,15 @@ +# pylint: disable=missing-function-docstring,missing-class-docstring +import pytest + +from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace +from sage.manifolds.differentiable.manifold import DifferentiableManifold + + +class TestR3VectorSpace: + @pytest.fixture + def manifold(self): + return EuclideanSpace(3) + + def test_trace_using_metric_works(self, manifold: DifferentiableManifold): + metric = manifold.metric('g') + assert metric.trace(using=metric) == manifold.scalar_field(3) diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 4177a406cac..18d1169064d 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -362,8 +362,8 @@ class TensorBundle(DifferentiableVectorBundle): .. MATH:: - t:\ \underbrace{T_q^*N\times\cdots\times T_q^*N}_{k\ \; \mbox{times}} - \times \underbrace{T_q N\times\cdots\times T_q N}_{l\ \; \mbox{times}} + t:\ \underbrace{T_q^*N\times\cdots\times T_q^*N}_{k\ \; \text{times}} + \times \underbrace{T_q N\times\cdots\times T_q N}_{l\ \; \text{times}} \longrightarrow K (`k` is called the *contravariant* and `l` the *covariant* rank of the @@ -464,7 +464,7 @@ def __init__(self, base_space, k, l, dest_map=None): else: name = self._dest_map._name + "^*" if self._dest_map._latex_name is None: - latex_name = r'\mbox{(unnamed map)}^* ' + latex_name = r'\text{(unnamed map)}^* ' else: latex_name = self._dest_map._latex_name + r'^* ' else: @@ -1356,8 +1356,8 @@ def local_frame(self, *args, **kwargs): .. MATH:: - p \mapsto \Big(\underbrace{e^*(p), \dots, e^*(p)}_{k\ \; \mbox{times}}, - \underbrace{e(p), \dots, e(p)}_{l\ \; \mbox{times}}\Big) \in + p \mapsto \Big(\underbrace{e^*(p), \dots, e^*(p)}_{k\ \; \text{times}}, + \underbrace{e(p), \dots, e(p)}_{l\ \; \text{times}}\Big) \in T^{(k,l)}_q N , with `q=\Phi(p)`, defines a basis at each point `p \in U` and diff --git a/src/sage/manifolds/differentiable/vectorfield.py b/src/sage/manifolds/differentiable/vectorfield.py index acf07f25aca..01a9c52d93c 100644 --- a/src/sage/manifolds/differentiable/vectorfield.py +++ b/src/sage/manifolds/differentiable/vectorfield.py @@ -359,7 +359,6 @@ def __call__(self, scalar): resu.set_name(name=name, latex_name=latex_name) return resu - @options(max_range=8, scale=1, color='blue') def plot(self, chart=None, ambient_coords=None, mapping=None, chart_domain=None, fixed_coords=None, ranges=None, @@ -799,8 +798,8 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, list_xx = [] while ind != ind_max: - for i in range(ncp): - xx[ind_coord[i]] = xmin[i] + ind[i]*step_tab[i] + for i in range(ncp): + xx[ind_coord[i]] = xmin[i] + ind[i] * step_tab[i] if chart_domain.valid_coordinates(*xx, tolerance=1e-13, parameters=parameters): diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 12060175278..d954b5d4839 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -45,7 +45,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Literal, Optional, overload from sage.categories.modules import Modules from sage.manifolds.differentiable.vectorfield import VectorField, VectorFieldParal @@ -57,6 +57,8 @@ from sage.tensor.modules.reflexive_module import ReflexiveModule_base if TYPE_CHECKING: + from sage.manifolds.differentiable.diff_form import DiffForm + from sage.manifolds.scalarfield import ScalarField from sage.manifolds.differentiable.diff_map import DiffMap from sage.manifolds.differentiable.manifold import DifferentiableManifold @@ -396,7 +398,7 @@ def _latex_(self): """ if self._latex_name is None: - return r'\mbox{' + str(self) + r'}' + return r"\text{" + str(self) + r"}" else: return self._latex_name @@ -949,9 +951,16 @@ def alternating_contravariant_tensor(self, degree, name=None, return self.element_class(self, name=name, latex_name=latex_name) return self.exterior_power(degree).element_class(self, degree, - name=name, latex_name=latex_name) + name=name, + latex_name=latex_name) + + @overload + def alternating_form( + self, degree: Literal[0], name=None, latex_name=None + ) -> ScalarField: + pass - def alternating_form(self, degree, name=None, latex_name=None): + def alternating_form(self, degree: int, name=None, latex_name=None) -> DiffForm: r""" Construct an alternating form on the vector field module ``self``. @@ -1206,7 +1215,6 @@ def metric(self, name: str, signature: Optional[int] = None, latex_name: Optiona return PseudoRiemannianMetric(self, name, signature=signature[0]-signature[1], latex_name=latex_name) - def symplectic_form( self, name: Optional[str] = None, latex_name: Optional[str] = None ): diff --git a/src/sage/manifolds/differentiable/vectorframe.py b/src/sage/manifolds/differentiable/vectorframe.py index 8f8c26c0c61..a02d69da5d0 100644 --- a/src/sage/manifolds/differentiable/vectorframe.py +++ b/src/sage/manifolds/differentiable/vectorframe.py @@ -764,7 +764,6 @@ def __init__(self, vector_field_module, symbol, latex_symbol=None, # NB: set(self._restrictions.values()) is identical to # self._subframes - ###### Methods that must be redefined by derived classes of ###### ###### FreeModuleBasis ###### @@ -1777,7 +1776,6 @@ def __init__(self, chart): # - force_free=True ensures that a free module is constructed in case # it is the first call to the vector field module on chart.domain() - ###### Methods that must be redefined by derived classes of ###### ###### FreeModuleBasis ###### diff --git a/src/sage/manifolds/manifold.py b/src/sage/manifolds/manifold.py index 04db412a8fc..89be2fddf7f 100644 --- a/src/sage/manifolds/manifold.py +++ b/src/sage/manifolds/manifold.py @@ -2724,8 +2724,9 @@ def set_simplify_function(self, simplifying_func, method=None): chart.calculus_method().set_simplify_function(simplifying_func, method=method) -############################################################################## -## Constructor function + +########################################################### +# Constructor function _manifold_id = Integer(0) diff --git a/src/sage/manifolds/manifold_homset.py b/src/sage/manifolds/manifold_homset.py index e33dea15ee9..492e460ab47 100644 --- a/src/sage/manifolds/manifold_homset.py +++ b/src/sage/manifolds/manifold_homset.py @@ -207,7 +207,7 @@ def _latex_(self): \mathrm{Hom}\left(M,N\right) """ if self._latex_name is None: - return r'\mbox{' + str(self) + r'}' + return r'\text{' + str(self) + r'}' else: return self._latex_name diff --git a/src/sage/manifolds/point.py b/src/sage/manifolds/point.py index abd019834a3..750e56320a2 100644 --- a/src/sage/manifolds/point.py +++ b/src/sage/manifolds/point.py @@ -258,7 +258,7 @@ def _latex_(self): sage: X.<x,y> = M.chart() sage: p = M((2,-3)) sage: p._latex_() - '\\mbox{Point on the 2-dimensional topological manifold M}' + '\\text{Point on the 2-dimensional topological manifold M}' sage: p = M((2,-3), name='p') sage: p._latex_() 'p' @@ -270,7 +270,7 @@ def _latex_(self): """ if self._latex_name is None: - return r'\mbox{' + str(self) + r'}' + return r'\text{' + str(self) + r'}' return self._latex_name def coordinates(self, chart=None, old_chart=None): diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index 4b43a9dca14..102de8caf3c 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -40,13 +40,19 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from typing import Optional +from __future__ import annotations +from typing import Optional, TYPE_CHECKING from sage.structure.element import (CommutativeAlgebraElement, ModuleElementWithMutability) from sage.symbolic.expression import Expression from sage.manifolds.chart_func import ChartFunction from sage.misc.cachefunc import cached_method +if TYPE_CHECKING: + from sage.tensor.modules.format_utilities import FormattedExpansion + from sage.manifolds.chart import Chart + + class ScalarField(CommutativeAlgebraElement, ModuleElementWithMutability): r""" Scalar field on a topological manifold. @@ -1128,15 +1134,19 @@ def __init__(self, parent, coord_expression=None, chart=None, name=None, domain = parent._domain self._domain = domain self._manifold = domain.manifold() - self._is_zero = False # a priori, may be changed below or via - # method __bool__() + self._is_zero = False + # a priori, may be changed below or via + # method __bool__() + self._name = name if latex_name is None: self._latex_name = self._name else: self._latex_name = latex_name - self._express = {} # dict of coordinate expressions (ChartFunction - # instances) with charts as keys + self._express = {} + # dict of coordinate expressions (ChartFunction + # instances) with charts as keys + if coord_expression is not None: if isinstance(coord_expression, dict): for chart, expression in coord_expression.items(): @@ -1158,7 +1168,7 @@ def __init__(self, parent, coord_expression=None, chart=None, name=None, self._express[chart] = chart.function(coord_expression) self._init_derived() # initialization of derived quantities - ####### Required methods for an algebra element (beside arithmetic) ####### + # ### Required methods for an algebra element (beside arithmetic) ### def __bool__(self): r""" @@ -1420,11 +1430,10 @@ def __ne__(self, other): sage: g = M.scalar_field({X: x+y}) sage: f != g False - """ return not (self == other) - ####### End of required methods for an algebra element (beside arithmetic) ####### + # ## End of required methods for an algebra element (beside arithmetic) ## def _init_derived(self): r""" @@ -1436,10 +1445,10 @@ def _init_derived(self): sage: X.<x,y> = M.chart() sage: f = M.scalar_field({X: x+y}) sage: f._init_derived() - """ - self._restrictions = {} # dict. of restrictions of self on subsets - # of self._domain, with the subsets as keys + self._restrictions = {} + # dict. of restrictions of self on subsets + # of self._domain, with the subsets as keys def _del_derived(self): r""" @@ -1461,7 +1470,6 @@ def _del_derived(self): sage: f._del_derived() sage: f._restrictions # restrictions are derived quantities {} - """ self._restrictions.clear() @@ -1481,7 +1489,6 @@ def _repr_(self): 'Scalar field f on the 2-dimensional topological manifold M' sage: f Scalar field f on the 2-dimensional topological manifold M - """ description = "Scalar field" if self._name is not None: @@ -1499,7 +1506,7 @@ def _latex_(self): sage: X.<x,y> = M.chart() sage: f = M.scalar_field({X: x+y}) sage: f._latex_() - '\\mbox{Scalar field on the 2-dimensional topological manifold M}' + '\\text{Scalar field on the 2-dimensional topological manifold M}' sage: f = M.scalar_field({X: x+y}, name='f') sage: f._latex_() 'f' @@ -1508,12 +1515,10 @@ def _latex_(self): '\\Phi' sage: latex(f) \Phi - """ if self._latex_name is None: - return r'\mbox{' + str(self) + r'}' - else: - return self._latex_name + return r'\text{' + str(self) + r'}' + return self._latex_name def set_name(self, name=None, latex_name=None): r""" @@ -1546,7 +1551,7 @@ def set_name(self, name=None, latex_name=None): """ if self.is_immutable(): raise ValueError("the name of an immutable element " - "cannot be changed") + "cannot be changed") if name is not None: self._name = name if latex_name is None: @@ -1782,7 +1787,7 @@ def coord_function(self, chart=None, from_chart=None): found = True if skchart not in self._express: self._express[skchart] = skchart.function( - self._express[kchart].expr()) + self._express[kchart].expr()) break if found: break @@ -1791,8 +1796,8 @@ def coord_function(self, chart=None, from_chart=None): "compute the expression in the {}".format(chart)) change = self._domain._coord_changes[(chart, from_chart)] # old coordinates expressed in terms of the new ones: - coords = [ change._transf._functions[i].expr() - for i in range(self._manifold.dim()) ] + coords = [change._transf._functions[i].expr() + for i in range(self._manifold.dim())] new_expr = self._express[from_chart](*coords) self._express[chart] = chart.function(new_expr) self._del_derived() @@ -1916,7 +1921,7 @@ def set_expr(self, coord_expression, chart=None): chart = self._domain._def_chart self._express.clear() self._express[chart] = chart.function(coord_expression) - self._is_zero = False # a priori + self._is_zero = False # a priori self._del_derived() def add_expr(self, coord_expression, chart=None): @@ -2045,13 +2050,13 @@ def add_expr_by_continuation(self, chart, subdomain): """ if self.is_immutable(): raise ValueError("the expressions of an immutable element " - "cannot be changed") + "cannot be changed") if not chart.domain().is_subset(self._domain): raise ValueError("the chart is not defined on a subset of " + "the scalar field domain") schart = chart.restrict(subdomain) self._express[chart] = chart.function(self.expr(schart)) - self._is_zero = False # a priori + self._is_zero = False # a priori self._del_derived() def set_restriction(self, rst): @@ -2096,7 +2101,7 @@ def set_restriction(self, rst): self._express[chart.restrict(intersection)] = expr self._is_zero = False # a priori - def display(self, chart=None): + def display(self, chart: Optional[Chart] = None) -> FormattedExpansion: r""" Display the expression of the scalar field in a given chart. @@ -2149,12 +2154,13 @@ def display(self, chart=None): f: M โ†’ โ„ on U: (x, y) โ†ฆ y^2 sage: latex(f.display()) - \begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ \mbox{on}\ U : & \left(x, y\right) & \longmapsto & y^{2} \end{array} - + \begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ \text{on}\ U : & \left(x, y\right) & \longmapsto & y^{2} \end{array} """ from sage.misc.latex import latex from sage.typeset.unicode_characters import (unicode_to, - unicode_mapsto, unicode_mathbbR, unicode_mathbbC) + unicode_mapsto, + unicode_mathbbR, + unicode_mathbbC) from sage.tensor.modules.format_utilities import FormattedExpansion def _display_expression(self, chart, result): @@ -2176,12 +2182,12 @@ def _display_expression(self, chart, result): result._latex += " & " else: result._txt += "on " + chart.domain()._name + ": " - result._latex += r"\mbox{on}\ " + latex(chart.domain()) \ + result._latex += r"\text{on}\ " + latex(chart.domain()) \ + r": & " result._txt += repr(coords) + " " + unicode_mapsto + " " \ - + repr(expression) + "\n" + + repr(expression) + "\n" result._latex += latex(coords) + r"& \longmapsto & " \ - + latex(expression) + r"\\" + + latex(expression) + r"\\" # Name of the base field: field = self._domain.base_field() @@ -2202,7 +2208,7 @@ def _display_expression(self, chart, result): else: symbol = self._name + ": " result._txt = symbol + self._domain._name + " " + unicode_to + " " \ - + field_name + "\n" + + field_name + "\n" if self._latex_name is None: symbol = "" else: @@ -2306,7 +2312,7 @@ def restrict(self, subdomain): self._restrictions[subdomain] = rst.restrict(subdomain) break else: - # If this fails, the restriction must be created from scratch: + # If this fails, the restriction must be created from scratch: sexpress = {} for chart, funct in self._express.items(): for schart in subdomain.atlas(): @@ -2510,7 +2516,7 @@ def __call__(self, p, chart=None): (-3, 7) """ - #!# it should be "if p not in self_domain:" instead, but this test is + # ! # it should be "if p not in self_domain:" instead, but this test is # skipped for efficiency if p not in self._manifold: raise ValueError("the {} ".format(p) + "does not belong " + @@ -2652,8 +2658,7 @@ def __neg__(self): result._latex_name = '-' + self._latex_name return result - - ######### CommutativeAlgebraElement arithmetic operators ######## + # ### CommutativeAlgebraElement arithmetic operators ### def _add_(self, other): r""" @@ -2806,7 +2811,7 @@ def _mul_(self, other): result._express[chart] = self._express[chart] * other._express[chart] result._name = format_mul_txt(self._name, '*', other._name) result._latex_name = format_mul_latex(self._latex_name, r' \cdot ', - other._latex_name) + other._latex_name) return result def _div_(self, other): @@ -2839,10 +2844,9 @@ def _div_(self, other): Traceback (most recent call last): ... ZeroDivisionError: division of a scalar field by zero - """ from sage.tensor.modules.format_utilities import format_mul_txt, \ - format_mul_latex + format_mul_latex # Trivial cases: if other.is_trivial_zero(): raise ZeroDivisionError("division of a scalar field by zero") @@ -2858,7 +2862,7 @@ def _div_(self, other): result._express[chart] = self._express[chart] / other._express[chart] result._name = format_mul_txt(self._name, '/', other._name) result._latex_name = format_mul_latex(self._latex_name, '/', - other._latex_name) + other._latex_name) return result def _lmul_(self, number): @@ -2962,7 +2966,7 @@ def _lmul_(self, number): result._express[chart] = number * expr return result - ######### End of CommutativeAlgebraElement arithmetic operators ######## + # ### End of CommutativeAlgebraElement arithmetic operators ### def _function_name(self, func, func_latex, parentheses=True): r""" @@ -2981,7 +2985,6 @@ def _function_name(self, func, func_latex, parentheses=True): sage: f = M.scalar_field({X: x+y}) # no name given to f sage: f._function_name("cos", r"\cos") (None, None) - """ if self._name is None: name = None @@ -2989,12 +2992,10 @@ def _function_name(self, func, func_latex, parentheses=True): name = func + "(" + self._name + ")" if self._latex_name is None: latex_name = None + elif parentheses: + latex_name = func_latex + r"\left(" + self._latex_name + r"\right)" else: - if parentheses: - latex_name = func_latex + r"\left(" + self._latex_name + \ - r"\right)" - else: - latex_name = func_latex + r"{" + self._latex_name + r"}" + latex_name = func_latex + r"{" + self._latex_name + r"}" return name, latex_name def exp(self): diff --git a/src/sage/manifolds/section.py b/src/sage/manifolds/section.py index 7a2ce1c7a50..e48b2b5ee29 100644 --- a/src/sage/manifolds/section.py +++ b/src/sage/manifolds/section.py @@ -345,7 +345,7 @@ def _latex_(self): """ if self._latex_name is None: - return r'\mbox{' + str(self) + r'}' + return r'\text{' + str(self) + r'}' else: return self._latex_name diff --git a/src/sage/manifolds/structure.py b/src/sage/manifolds/structure.py index 688e4c46833..dd9fc2a3f8a 100644 --- a/src/sage/manifolds/structure.py +++ b/src/sage/manifolds/structure.py @@ -93,7 +93,7 @@ class DifferentialStructure(Singleton): chart = DiffChart name = "differentiable" scalar_field_algebra = DiffScalarFieldAlgebra - homset = DifferentiableManifoldHomset + homset = DifferentiableManifoldHomset def subcategory(self, cat): """ @@ -118,7 +118,7 @@ class RealDifferentialStructure(Singleton): chart = RealDiffChart name = "differentiable" scalar_field_algebra = DiffScalarFieldAlgebra - homset = DifferentiableManifoldHomset + homset = DifferentiableManifoldHomset def subcategory(self, cat): """ @@ -142,7 +142,7 @@ class PseudoRiemannianStructure(Singleton): chart = RealDiffChart name = "pseudo-Riemannian" scalar_field_algebra = DiffScalarFieldAlgebra - homset = DifferentiableManifoldHomset + homset = DifferentiableManifoldHomset def subcategory(self, cat): """ @@ -166,7 +166,7 @@ class RiemannianStructure(Singleton): chart = RealDiffChart name = "Riemannian" scalar_field_algebra = DiffScalarFieldAlgebra - homset = DifferentiableManifoldHomset + homset = DifferentiableManifoldHomset def subcategory(self, cat): """ @@ -190,7 +190,7 @@ class LorentzianStructure(Singleton): chart = RealDiffChart name = "Lorentzian" scalar_field_algebra = DiffScalarFieldAlgebra - homset = DifferentiableManifoldHomset + homset = DifferentiableManifoldHomset def subcategory(self, cat): """ @@ -214,7 +214,7 @@ class DegenerateStructure(Singleton): chart = RealDiffChart name = "degenerate_metric" scalar_field_algebra = DiffScalarFieldAlgebra - homset = DifferentiableManifoldHomset + homset = DifferentiableManifoldHomset def subcategory(self, cat): """ diff --git a/src/sage/manifolds/subset.py b/src/sage/manifolds/subset.py index 074e3758e19..0e6833380b8 100644 --- a/src/sage/manifolds/subset.py +++ b/src/sage/manifolds/subset.py @@ -907,7 +907,7 @@ def subset_digraph(self, loops=False, quotient=False, open_covers=False, points= sage: U = M.open_subset('U'); V = M.open_subset('V'); W = M.open_subset('W') sage: D = M.subset_digraph(); D Digraph on 4 vertices - sage: D.edges(key=lambda e: (e[0]._name, e[1]._name)) + sage: D.edges(sort=True, key=lambda e: (e[0]._name, e[1]._name)) [(Set {U} of open subsets of the 3-dimensional differentiable manifold M, Set {M} of open subsets of the 3-dimensional differentiable manifold M, None), @@ -2635,11 +2635,13 @@ def complement(self, superset=None, name=None, latex_name=None, is_open=False): - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the complement in the case the latter has to be created; the default is built upon the symbol `\setminus` + - ``is_open`` -- (default: ``False``) if ``True``, the created subset + is assumed to be open with respect to the manifold's topology OUTPUT: - - instance of :class:`ManifoldSubset` representing the - subset that is difference of ``superset`` minus ``self`` + - instance of :class:`ManifoldSubset` representing the subset that + is ``superset`` minus ``self`` EXAMPLES:: @@ -2656,6 +2658,15 @@ def complement(self, superset=None, name=None, latex_name=None, is_open=False): ... TypeError: superset must be a superset of self + Demanding that the complement is open makes ``self`` a closed subset:: + + sage: A.is_closed() # False a priori + False + sage: A.complement(is_open=True) + Open subset M_minus_A of the 2-dimensional topological manifold M + sage: A.is_closed() + True + """ if superset is None: superset = self.manifold() @@ -2678,11 +2689,13 @@ def difference(self, other, name=None, latex_name=None, is_open=False): - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the difference in the case the latter has to be created; the default is built upon the symbol `\setminus` + - ``is_open`` -- (default: ``False``) if ``True``, the created subset + is assumed to be open with respect to the manifold's topology OUTPUT: - - instance of :class:`ManifoldSubset` representing the - subset that is difference of ``self`` minus ``other`` + - instance of :class:`ManifoldSubset` representing the subset that is + ``self`` minus ``other`` EXAMPLES:: @@ -2712,6 +2725,13 @@ def difference(self, other, name=None, latex_name=None, is_open=False): sage: M.difference(O, is_open=True) Open subset CO2 of the 2-dimensional topological manifold M + Since `O` is open and we have asked `M\setminus O` to be open, `O` + is a clopen set (if `O\neq M` and `O\neq\emptyset`, this implies that + `M` is not connected):: + + sage: O.is_closed() and O.is_open() + True + """ # See if it has been created already diffs = [] diff --git a/src/sage/manifolds/subsets/__init__.py b/src/sage/manifolds/subsets/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/crypto/public_key/__init__.py b/src/sage/manifolds/subsets/all.py similarity index 100% rename from src/sage/crypto/public_key/__init__.py rename to src/sage/manifolds/subsets/all.py diff --git a/src/sage/manifolds/subsets/pullback.py b/src/sage/manifolds/subsets/pullback.py index 2ed36070642..b28365601f8 100644 --- a/src/sage/manifolds/subsets/pullback.py +++ b/src/sage/manifolds/subsets/pullback.py @@ -261,23 +261,23 @@ def _is_open(codomain_subset): PPL polyhedra and not-necessarily-closed polyhedra:: - sage: from ppl import Variable, C_Polyhedron, NNC_Polyhedron, Constraint_System - sage: u = Variable(0) - sage: v = Variable(1) - sage: CS = Constraint_System() - sage: CS.insert(0 < u) - sage: CS.insert(u < 1) - sage: CS.insert(0 < v) - sage: CS.insert(v < 1) - sage: CS.insert(u + v <= 3) # redundant inequality - sage: P = NNC_Polyhedron(CS); P + sage: from ppl import Variable, C_Polyhedron, NNC_Polyhedron, Constraint_System # optional - pplpy + sage: u = Variable(0) # optional - pplpy + sage: v = Variable(1) # optional - pplpy + sage: CS = Constraint_System() # optional - pplpy + sage: CS.insert(0 < u) # optional - pplpy + sage: CS.insert(u < 1) # optional - pplpy + sage: CS.insert(0 < v) # optional - pplpy + sage: CS.insert(v < 1) # optional - pplpy + sage: CS.insert(u + v <= 3) # redundant inequality # optional - pplpy + sage: P = NNC_Polyhedron(CS); P # optional - pplpy A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 4 closure_points - sage: ManifoldSubsetPullback._is_open(P) + sage: ManifoldSubsetPullback._is_open(P) # optional - pplpy True - sage: CS.insert(u + v <= 1) - sage: T = NNC_Polyhedron(CS); T + sage: CS.insert(u + v <= 1) # optional - pplpy + sage: T = NNC_Polyhedron(CS); T # optional - pplpy A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 3 closure_points - sage: ManifoldSubsetPullback._is_open(T) + sage: ManifoldSubsetPullback._is_open(T) # optional - pplpy False """ @@ -494,7 +494,7 @@ def _coord_def(map, codomain_subset): - ``codomain_subset`` - if ``map`` is a :class:`ScalarField`, an instance of :class:`RealSet`; if ``map`` is a :class:`Chart`, the relative interior of a polyhedron. - For other inputs, a ``NotImplementedError`` will be raised. + For other inputs, a :class:`NotImplementedError` will be raised. OUTPUT: diff --git a/src/sage/manifolds/trivialization.py b/src/sage/manifolds/trivialization.py index dcdaad390d9..ed3a8b4ed9f 100644 --- a/src/sage/manifolds/trivialization.py +++ b/src/sage/manifolds/trivialization.py @@ -693,7 +693,6 @@ def matrix(self): """ return self._automorphism.matrix(self._frame1) - def __eq__(self, other): r""" Equality operator. diff --git a/src/sage/manifolds/utilities.py b/src/sage/manifolds/utilities.py index de83d63326f..c66d54e774e 100644 --- a/src/sage/manifolds/utilities.py +++ b/src/sage/manifolds/utilities.py @@ -987,7 +987,7 @@ def _repr_(self): for i in diffargs) res = "d" + str(numargs) + "(" + str(funcname) + ")/d" + "d".join( - [i for i in occ.values()]) + occ.values()) # str representation of the operator s = self._parent._repr_element_(m[0]) @@ -1040,7 +1040,7 @@ def _latex_(self): sage: latex(ExpressionNice(fun)) \frac{\partial\,f_{x}}{\partial y} - If latex_name, it should be used in LaTeX output: + If latex_name, it should be used in LaTeX output:: sage: f = function('f_x', latex_name=r"{\cal F}")(x,y) sage: fun = f.diff(y) @@ -1357,4 +1357,5 @@ def exterior_derivative(form): """ return form.exterior_derivative() + xder = exterior_derivative diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index dc057d1dce5..5c6296a1c35 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -209,23 +209,23 @@ cdef class MatrixMatrixAction(MatrixMulAction): Respects compatible subdivisions:: - sage: M = matrix(5, 5, prime_range(100)) - sage: M.subdivide(2,3); M + sage: M = matrix(5, 5, prime_range(100)) # needs sage.libs.pari + sage: M.subdivide(2, 3); M # needs sage.libs.pari [ 2 3 5| 7 11] [13 17 19|23 29] [--------+-----] [31 37 41|43 47] [53 59 61|67 71] [73 79 83|89 97] - sage: N = matrix(5,2,[n^2 for n in range(10)]) - sage: N.subdivide(3,1); N + sage: N = matrix(5, 2, [n^2 for n in range(10)]) + sage: N.subdivide(3, 1); N [ 0| 1] [ 4| 9] [16|25] [--+--] [36|49] [64|81] - sage: M*N + sage: M*N # needs sage.libs.pari [ 1048| 1388] [ 3056| 4117] [-----+-----] @@ -235,7 +235,7 @@ cdef class MatrixMatrixAction(MatrixMulAction): Note that this is just like block matrix multiplication:: - sage: M.subdivision(0,0) * N.subdivision(0,0) + M.subdivision(0,1) * N.subdivision(1,0) + sage: M.subdivision(0,0) * N.subdivision(0,0) + M.subdivision(0,1) * N.subdivision(1,0) # needs sage.libs.pari [1048] [3056] @@ -249,7 +249,7 @@ cdef class MatrixMatrixAction(MatrixMulAction): [16|25] [36|49] [64|81] - sage: M*N + sage: M*N # needs sage.libs.pari [ 1048 1388] [ 3056 4117] [ 5360 7303] @@ -268,7 +268,7 @@ cdef class MatrixMatrixAction(MatrixMulAction): B = B.dense_matrix() else: A = A.dense_matrix() - assert type(A) == type(B), (type(A), type(B)) + assert type(A) is type(B), (type(A), type(B)) prod = A._matrix_times_matrix_(B) if A._subdivisions is not None or B._subdivisions is not None: Asubs = A.subdivisions() diff --git a/src/sage/data_structures/__init__.py b/src/sage/matrix/all__sagemath_meataxe.py similarity index 100% rename from src/sage/data_structures/__init__.py rename to src/sage/matrix/all__sagemath_meataxe.py diff --git a/src/sage/matrix/args.pyx b/src/sage/matrix/args.pyx index 9e738312c27..c5a121743a5 100644 --- a/src/sage/matrix/args.pyx +++ b/src/sage/matrix/args.pyx @@ -21,6 +21,7 @@ from cysignals.signals cimport sig_check MatrixSpace = None from sage.rings.integer_ring import ZZ +from sage.rings.integer cimport Integer from sage.structure.coerce cimport (coercion_model, is_numpy_type, py_scalar_parent) from sage.structure.element cimport Element, RingElement, Vector @@ -82,7 +83,7 @@ cdef class SparseEntry: sage: from sage.matrix.args import SparseEntry sage: SparseEntry(123, 456, "abc") SparseEntry(123, 456, 'abc') - sage: SparseEntry(1/3, 2/3, x) + sage: SparseEntry(1/3, 2/3, x) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert rational 1/3 to an integer @@ -175,8 +176,10 @@ cdef class MatrixArgs: <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Real Double Field; typ=SCALAR; entries=3.141592653589793> [3.141592653589793 0.0] [ 0.0 3.141592653589793] - sage: ma = MatrixArgs(2, 2, entries=pi); ma.finalized(); ma.matrix() - <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Symbolic Ring; typ=SCALAR; entries=pi> + sage: ma = MatrixArgs(2, 2, entries=pi); ma.finalized() # needs sage.symbolic + <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices + over Symbolic Ring; typ=SCALAR; entries=pi> + sage: ma.matrix() # needs sage.symbolic [pi 0] [ 0 pi] sage: ma = MatrixArgs(ZZ, 2, 2, entries={(0,0):7}); ma.finalized(); ma.matrix() @@ -191,18 +194,27 @@ cdef class MatrixArgs: <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Integer Ring; typ=SEQ_FLAT; entries=(1, 2, 3, 4)> [1 2] [3 4] - sage: ma = MatrixArgs(QQ, entries=pari("[1,2;3,4]")); ma.finalized(); ma.matrix() - <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Rational Field; typ=SEQ_FLAT; entries=[1, 2, 3, 4]> + + sage: # needs sage.libs.pari + sage: ma = MatrixArgs(QQ, entries=pari("[1,2;3,4]")); ma.finalized() + <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices + over Rational Field; typ=SEQ_FLAT; entries=[1, 2, 3, 4]> + sage: ma.matrix() [1 2] [3 4] - sage: ma = MatrixArgs(QQ, 2, 2, entries=pari("[1,2,3,4]")); ma.finalized(); ma.matrix() - <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Rational Field; typ=SEQ_FLAT; entries=[1, 2, 3, 4]> + sage: ma = MatrixArgs(QQ, 2, 2, entries=pari("[1,2,3,4]")); ma.finalized() + <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices + over Rational Field; typ=SEQ_FLAT; entries=[1, 2, 3, 4]> + sage: ma.matrix() [1 2] [3 4] - sage: ma = MatrixArgs(QQ, 2, 2, entries=pari("3/5")); ma.finalized(); ma.matrix() - <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Rational Field; typ=SCALAR; entries=3/5> + sage: ma = MatrixArgs(QQ, 2, 2, entries=pari("3/5")); ma.finalized() + <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices + over Rational Field; typ=SCALAR; entries=3/5> + sage: ma.matrix() [3/5 0] [ 0 3/5] + sage: ma = MatrixArgs(entries=matrix(2,2)); ma.finalized(); ma.matrix() <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Integer Ring; typ=MATRIX; entries=[0 0] [0 0]> @@ -216,26 +228,37 @@ cdef class MatrixArgs: <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Integer Ring; typ=CALLABLE; entries=<function ...>> [1 2] [3 4] + + sage: # needs numpy sage: from numpy import array - sage: ma = MatrixArgs(array([[1,2],[3,4]])); ma.finalized(); ma.matrix() - <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Integer Ring; typ=SEQ_SEQ; entries=array([[1, 2], - [3, 4]])> + sage: ma = MatrixArgs(array([[1,2],[3,4]])); ma.finalized() + <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices + over Integer Ring; typ=SEQ_SEQ; entries=array([[1, 2], [3, 4]])> + sage: ma.matrix() [1 2] [3 4] - sage: ma = MatrixArgs(array([[1.,2.],[3.,4.]])); ma.finalized(); ma.matrix() - <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Real Double Field; typ=MATRIX; entries=[1.0 2.0] - [3.0 4.0]> + sage: ma = MatrixArgs(array([[1.,2.],[3.,4.]])); ma.finalized() + <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices + over Real Double Field; typ=MATRIX; entries=[1.0 2.0] + [3.0 4.0]> + sage: ma.matrix() [1.0 2.0] [3.0 4.0] - sage: ma = MatrixArgs(RealField(20), array([[1.,2.],[3.,4.]])); ma.finalized(); ma.matrix() - <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Real Field with 20 bits of precision; typ=MATRIX; entries=[1.0 2.0] - [3.0 4.0]> + sage: ma = MatrixArgs(RealField(20), array([[1.,2.],[3.,4.]])); ma.finalized() + <MatrixArgs for Full MatrixSpace of 2 by 2 dense matrices over Real Field + with 20 bits of precision; typ=MATRIX; entries=[1.0 2.0] + [3.0 4.0]> + sage: ma.matrix() [1.0000 2.0000] [3.0000 4.0000] - sage: ma = MatrixArgs(graphs.CycleGraph(3)); ma.finalized(); ma.matrix() - <MatrixArgs for Full MatrixSpace of 3 by 3 dense matrices over Integer Ring; typ=MATRIX; entries=[0 1 1] - [1 0 1] - [1 1 0]> + + sage: # needs sage.graphs + sage: ma = MatrixArgs(graphs.CycleGraph(3)); ma.finalized() + <MatrixArgs for Full MatrixSpace of 3 by 3 dense matrices + over Integer Ring; typ=MATRIX; entries=[0 1 1] + [1 0 1] + [1 1 0]> + sage: ma.matrix() [0 1 1] [1 0 1] [1 1 0] @@ -457,8 +480,8 @@ cdef class MatrixArgs: Sparse examples:: - sage: ma = MatrixArgs(3, 3, pi) - sage: list(ma.iter(sparse=True)) + sage: ma = MatrixArgs(3, 3, pi) # needs sage.symbolic + sage: list(ma.iter(sparse=True)) # needs sage.symbolic [SparseEntry(0, 0, pi), SparseEntry(1, 1, pi), SparseEntry(2, 2, pi)] sage: ma = MatrixArgs(2, 3) sage: list(ma.iter(sparse=True)) @@ -716,7 +739,6 @@ cdef class MatrixArgs: """ self.finalize() - cdef long i cdef list L if self.typ == MA_ENTRIES_SEQ_FLAT and not convert: # Try to re-use existing list @@ -765,7 +787,6 @@ cdef class MatrixArgs: """ self.finalize() - R = self.base cdef dict D = {} for t in self.iter(convert, True): se = <SparseEntry>t @@ -818,11 +839,11 @@ cdef class MatrixArgs: EXAMPLES:: sage: from sage.matrix.args import MatrixArgs - sage: MatrixArgs(pi).finalized() + sage: MatrixArgs(pi).finalized() # needs sage.symbolic Traceback (most recent call last): ... TypeError: the dimensions of the matrix must be specified - sage: MatrixArgs(RR, pi).finalized() + sage: MatrixArgs(RR, pi).finalized() # needs sage.symbolic Traceback (most recent call last): ... TypeError: the dimensions of the matrix must be specified @@ -847,6 +868,24 @@ cdef class MatrixArgs: Traceback (most recent call last): ... ValueError: sequence too short (expected length 6, got 1) + + Check github issue #36065: + + sage: class MyAlgebraicNumber(sage.rings.qqbar.AlgebraicNumber): + ....: def __bool__(self): + ....: raise ValueError + sage: matrix(1, 1, MyAlgebraicNumber(0)) + [0] + sage: matrix(1, 1, MyAlgebraicNumber(3)) + [3] + sage: matrix(1, 2, MyAlgebraicNumber(0)) + Traceback (most recent call last): + ... + TypeError: scalar matrix must be square if the value cannot be determined to be zero + sage: matrix(1, 2, MyAlgebraicNumber(3)) + Traceback (most recent call last): + ... + TypeError: scalar matrix must be square if the value cannot be determined to be zero """ self.finalize() return self @@ -924,11 +963,18 @@ cdef class MatrixArgs: raise AssertionError(f"nrows={self.nrows} ncols={self.ncols} base={self.base} type={self.typ}") # Non-zero scalar matrices must be square + # also ensure type is MA_ENTRIES_ZERO for scalar zero matrices if self.typ == MA_ENTRIES_SCALAR: - if self.nrows != self.ncols: - if self.entries: - raise TypeError("nonzero scalar matrix must be square") - self.typ = MA_ENTRIES_ZERO + try: + if not self.entries: + self.typ = MA_ENTRIES_ZERO + except Exception: + # "not self.entries" has failed, self.entries cannot be determined to be zero + if self.nrows != self.ncols: + raise TypeError("scalar matrix must be square if the value cannot be determined to be zero") + if self.typ == MA_ENTRIES_SCALAR and self.nrows != self.ncols: + # self.typ is still SCALAR -> "not self.entries" has successfully evaluated, to False + raise TypeError("nonzero scalar matrix must be square") if self.sparse == -1: self.sparse = (self.typ & MA_FLAG_SPARSE) != 0 @@ -1196,6 +1242,7 @@ cdef class MatrixArgs: Check that :trac:`26655` is fixed:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(9) sage: M = MatrixSpace(F, 2, 2) sage: A = M([[1, a], [0, 1]]) @@ -1206,11 +1253,11 @@ cdef class MatrixArgs: Constructing a matrix from a PARI ``t_VEC`` or ``t_COL`` with ``t_VEC`` or ``t_COL`` elements is currently not supported:: - sage: M(pari([1, a, 0, 1])) + sage: M(pari([1, a, 0, 1])) # needs sage.libs.pari sage.rings.finite_rings Traceback (most recent call last): ... NameError: name 'a' is not defined - sage: M(pari([[1, a], [0, 1]])) + sage: M(pari([[1, a], [0, 1]])) # needs sage.libs.pari sage.rings.finite_rings Traceback (most recent call last): ... NameError: name 'a' is not defined @@ -1219,12 +1266,14 @@ cdef class MatrixArgs: # hurt to do these first. if self.entries is None: return MA_ENTRIES_ZERO + if isinstance(self.entries, (int, float, complex, Integer)): + if self.entries: + return MA_ENTRIES_SCALAR + return MA_ENTRIES_ZERO if isinstance(self.entries, (list, tuple)): return self.sequence_type() if isinstance(self.entries, dict): return MA_ENTRIES_MAPPING - if isinstance(self.entries, (int, float, complex)): - return MA_ENTRIES_SCALAR # Note: some objects are callable, iterable and act like a # scalar, e.g. polynomials. So the order of these checks @@ -1260,7 +1309,7 @@ cdef class MatrixArgs: if isinstance(self.entries, MatrixArgs): # Prevent recursion return MA_ENTRIES_UNKNOWN - if isinstance(self.entries, basestring): + if isinstance(self.entries, str): # Blacklist strings, we don't want them to be considered a sequence return MA_ENTRIES_UNKNOWN try: @@ -1300,7 +1349,7 @@ cdef class MatrixArgs: return MA_ENTRIES_SEQ_FLAT if isinstance(x, Element) and element_is_scalar(<Element>x): return MA_ENTRIES_SEQ_FLAT - if isinstance(x, basestring): + if isinstance(x, str): # Blacklist strings, we don't want them to be considered a sequence return MA_ENTRIES_UNKNOWN try: @@ -1323,7 +1372,7 @@ cpdef MatrixArgs MatrixArgs_init(space, entries): sage: from sage.matrix.args import MatrixArgs_init sage: S = MatrixSpace(GF(2), 2, 4) - sage: ma = MatrixArgs_init(S, {(1,3):7}) + sage: ma = MatrixArgs_init(S, {(1, 3): 7}) sage: M = ma.matrix(); M [0 0 0 0] [0 0 0 1] diff --git a/src/sage/matrix/benchmark.py b/src/sage/matrix/benchmark.py index 811a1cbfc98..97117632584 100644 --- a/src/sage/matrix/benchmark.py +++ b/src/sage/matrix/benchmark.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.flint """ Benchmarks for matrices @@ -18,13 +19,14 @@ """ from .constructor import random_matrix, Matrix +from sage.misc.lazy_import import lazy_import from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from sage.misc.misc import cputime +from sage.misc.timing import cputime from cysignals.alarm import AlarmInterrupt, alarm, cancel_alarm -from sage.interfaces.magma import magma +lazy_import('sage.interfaces.magma', 'magma') verbose = False @@ -562,7 +564,6 @@ def vecmat_ZZ(n=300, min=-9, max=9, system='sage', times=200): raise ValueError('unknown system "%s"'%system) - ####################################################################### # Dense Benchmarks over GF(p), for small p. ####################################################################### @@ -721,7 +722,6 @@ def matrix_add_GF(n=1000, p=16411, system='sage',times=100): raise ValueError('unknown system "%s"'%system) - # Matrix multiplication over GF(p) def matrix_multiply_GF(n=100, p=16411, system='sage', times=3): @@ -900,7 +900,7 @@ def hilbert_matrix(n): A = Matrix(QQ,n,n) for i in range(A.nrows()): for j in range(A.ncols()): - A[i,j] = QQ(1)/((i+1)+(j+1)-1) + A[i,j] = QQ(1)/((i+1)+(j+1)-1) return A # Reduced row echelon form over QQ diff --git a/src/sage/matrix/berlekamp_massey.py b/src/sage/matrix/berlekamp_massey.py index 716ed428745..a6fe70c50e6 100644 --- a/src/sage/matrix/berlekamp_massey.py +++ b/src/sage/matrix/berlekamp_massey.py @@ -55,11 +55,11 @@ def berlekamp_massey(a): sage: from sage.matrix.berlekamp_massey import berlekamp_massey sage: berlekamp_massey([1,2,1,2,1,2]) x^2 - 1 - sage: berlekamp_massey([GF(7)(1),19,1,19]) + sage: berlekamp_massey([GF(7)(1), 19, 1, 19]) x^2 + 6 sage: berlekamp_massey([2,2,1,2,1,191,393,132]) x^4 - 36727/11711*x^3 + 34213/5019*x^2 + 7024942/35133*x - 335813/1673 - sage: berlekamp_massey(prime_range(2,38)) + sage: berlekamp_massey(prime_range(2, 38)) # needs sage.libs.pari x^6 - 14/9*x^5 - 7/9*x^4 + 157/54*x^3 - 25/27*x^2 - 73/18*x + 37/9 TESTS:: @@ -84,15 +84,11 @@ def berlekamp_massey(a): K = a[0].parent().fraction_field() except AttributeError: K = sage.rings.rational_field.RationalField() - R = K['x'] - x = R.gen() - - f = {-1: R(a), 0: x**(2 * M)} - s = {-1: 1, 0: 0} - j = 0 - while f[j].degree() >= M: - j += 1 - qj, f[j] = f[j - 2].quo_rem(f[j - 1]) - s[j] = s[j - 2] - qj * s[j - 1] - t = s[j].reverse() - return ~(t[t.degree()]) * t # make monic (~ is inverse in python) + + R, x = K['x'].objgen() + f0, f1 = R(a), x**(2 * M) + s0, s1 = 1, 0 + while f1.degree() >= M: + f0, (q, f1) = f1, f0.quo_rem(f1) + s0, s1 = s1, s0 - q * s1 + return s1.reverse().monic() diff --git a/src/sage/matrix/compute_J_ideal.py b/src/sage/matrix/compute_J_ideal.py index 7c31c0160f1..3055f283a78 100644 --- a/src/sage/matrix/compute_J_ideal.py +++ b/src/sage/matrix/compute_J_ideal.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari (for charpoly, minimal_polynomial in __init__) r""" `J`-ideals of matrices @@ -190,7 +191,6 @@ def lifting(p, t, A, G): """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - DX = A.parent().base() (X,) = DX.variable_names() D = DX.base_ring() @@ -203,7 +203,6 @@ def lifting(p, t, A, G): if not (A*G % p**(t-1)).is_zero(): raise ValueError("A*G not zero mod %s^%s" % (p, t-1)) - R = A*G/p**(t-1) R.change_ring(DX) @@ -351,7 +350,6 @@ def __init__(self, B): self._DX = X.parent() self._cache = {} - def find_monic_replacements(self, p, t, pt_generators, prev_nu): r""" Replace possibly non-monic generators of `N_{(p^t)}(B)` by monic @@ -432,7 +430,6 @@ def find_monic_replacements(self, p, t, pt_generators, prev_nu): return replacements - def current_nu(self, p, t, pt_generators, prev_nu): r""" Compute `(p^t)`-minimal polynomial of `B`. @@ -482,7 +479,6 @@ def current_nu(self, p, t, pt_generators, prev_nu): from sage.misc.verbose import verbose - if not all((g(self._B) % p**t).is_zero() for g in pt_generators): raise ValueError("%s not in N_{(%s^%s)}(B)" % @@ -519,7 +515,6 @@ def current_nu(self, p, t, pt_generators, prev_nu): return g - def mccoy_column(self, p, t, nu): r""" Compute matrix for McCoy's criterion. @@ -577,7 +572,6 @@ def mccoy_column(self, p, t, nu): return column - def p_minimal_polynomials(self, p, s_max=None): r""" Compute `(p^s)`-minimal polynomials `\nu_s` of `B`. @@ -768,7 +762,6 @@ def p_minimal_polynomials(self, p, s_max=None): d = self._A.ncols() G = matrix(self._DX, d, 0) - while t < s_max: deg_prev_nu = nu.degree() t += 1 @@ -812,7 +805,6 @@ def p_minimal_polynomials(self, p, s_max=None): return p_min_polys - def null_ideal(self, b=0): r""" Return the `(b)`-ideal `N_{(b)}(B)=\{f\in D[X] \mid f(B)\in M_n(bD)\}`. @@ -877,7 +869,6 @@ def null_ideal(self, b=0): return self._DX.ideal(generators) - def prime_candidates(self): r""" Determine those primes `p` where `\mu_B` might not be a @@ -910,7 +901,6 @@ def prime_candidates(self): return [p for (p, t) in factor(T.det())] - def integer_valued_polynomials_generators(self): r""" Determine the generators of the ring of integer valued polynomials on `B`. diff --git a/src/sage/matrix/constructor.pyx b/src/sage/matrix/constructor.pyx index ae4652c45f8..a31543e0795 100644 --- a/src/sage/matrix/constructor.pyx +++ b/src/sage/matrix/constructor.pyx @@ -172,9 +172,9 @@ def matrix(*args, **kwds): :: - sage: import numpy - sage: n = numpy.array([[1,2],[3,4]],float) - sage: m = matrix(n); m; m.parent() + sage: import numpy # needs numpy + sage: n = numpy.array([[1,2], [3,4]], float) # needs numpy + sage: m = matrix(n); m; m.parent() # needs numpy [1.0 2.0] [3.0 4.0] Full MatrixSpace of 2 by 2 dense matrices over Real Double Field @@ -196,15 +196,15 @@ def matrix(*args, **kwds): :: - sage: matrix(pari.mathilbert(3)) + sage: matrix(pari.mathilbert(3)) # needs sage.libs.pari [ 1 1/2 1/3] [1/2 1/3 1/4] [1/3 1/4 1/5] :: - sage: g = graphs.PetersenGraph() - sage: m = matrix(g); m; m.parent() + sage: g = graphs.PetersenGraph() # needs sage.graphs + sage: m = matrix(g); m; m.parent() # needs sage.graphs [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] [0 1 0 1 0 0 0 1 0 0] @@ -238,7 +238,8 @@ def matrix(*args, **kwds): sage: M[0] = [9,9,9] Traceback (most recent call last): ... - ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M). + ValueError: matrix is immutable; please change a copy instead + (i.e., use copy(M) to change a copy of M). TESTS: @@ -456,42 +457,43 @@ def matrix(*args, **kwds): Check conversion from numpy:: + sage: # needs numpy sage: import numpy - sage: n = numpy.array([[complex(0,1),complex(0,2)],[3,4]],complex) + sage: n = numpy.array([[complex(0,1),complex(0,2)], [3,4]], complex) sage: m = matrix(n); m; m.parent() [1.0*I 2.0*I] [ 3.0 4.0] Full MatrixSpace of 2 by 2 dense matrices over Complex Double Field - sage: n = numpy.array([[1,2],[3,4]],'int32') + sage: n = numpy.array([[1,2], [3,4]], 'int32') sage: m = matrix(n); m; m.parent() [1 2] [3 4] Full MatrixSpace of 2 by 2 dense matrices over Integer Ring - sage: n = numpy.array([[1,2,3],[4,5,6],[7,8,9]],'float32') + sage: n = numpy.array([[1,2,3], [4,5,6], [7,8,9]], 'float32') sage: m = matrix(n); m; m.parent() [1.0 2.0 3.0] [4.0 5.0 6.0] [7.0 8.0 9.0] Full MatrixSpace of 3 by 3 dense matrices over Real Double Field - sage: n = numpy.matrix([[1,2,3],[4,5,6],[7,8,9]],'float64') + sage: n = numpy.matrix([[1,2,3], [4,5,6], [7,8,9]], 'float64') sage: m = matrix(n); m; m.parent() [1.0 2.0 3.0] [4.0 5.0 6.0] [7.0 8.0 9.0] Full MatrixSpace of 3 by 3 dense matrices over Real Double Field - sage: n = numpy.array([[1,2,3],[4,5,6],[7,8,9]],'complex64') + sage: n = numpy.array([[1,2,3], [4,5,6], [7,8,9]], 'complex64') sage: m = matrix(n); m; m.parent() [1.0 2.0 3.0] [4.0 5.0 6.0] [7.0 8.0 9.0] Full MatrixSpace of 3 by 3 dense matrices over Complex Double Field - sage: n = numpy.matrix([[1,2,3],[4,5,6],[7,8,9]],'complex128') + sage: n = numpy.matrix([[1,2,3], [4,5,6], [7,8,9]], 'complex128') sage: m = matrix(n); m; m.parent() [1.0 2.0 3.0] [4.0 5.0 6.0] [7.0 8.0 9.0] Full MatrixSpace of 3 by 3 dense matrices over Complex Double Field - sage: a = matrix([[1,2],[3,4]]) + sage: a = matrix([[1,2], [3,4]]) sage: b = matrix(a.numpy()); b [1 2] [3 4] @@ -507,7 +509,8 @@ def matrix(*args, **kwds): A ring and a numpy array:: - sage: n = numpy.array([[1,2,3],[4,5,6],[7,8,9]],'float32') + sage: # needs numpy + sage: n = numpy.array([[1,2,3], [4,5,6], [7,8,9]], 'float32') sage: m = matrix(ZZ, n); m; m.parent() [1 2 3] [4 5 6] @@ -522,11 +525,11 @@ def matrix(*args, **kwds): The dimensions of a matrix may be given as numpy types:: - sage: matrix(numpy.int32(2), numpy.int32(3)) + sage: matrix(numpy.int32(2), numpy.int32(3)) # needs numpy [0 0 0] [0 0 0] - sage: matrix(nrows=numpy.int32(2), ncols=numpy.int32(3)) + sage: matrix(nrows=numpy.int32(2), ncols=numpy.int32(3)) # needs numpy [0 0 0] [0 0 0] @@ -542,7 +545,8 @@ def matrix(*args, **kwds): sage: v = vector(ZZ, [1, 10, 100]) sage: m = matrix(ZZ['x'], v); m; m.parent() [ 1 10 100] - Full MatrixSpace of 1 by 3 dense matrices over Univariate Polynomial Ring in x over Integer Ring + Full MatrixSpace of 1 by 3 dense matrices + over Univariate Polynomial Ring in x over Integer Ring sage: matrix(ZZ, 10, 10, range(100)).parent() Full MatrixSpace of 10 by 10 dense matrices over Integer Ring sage: m = matrix(GF(7), [[1/3,2/3,1/2], [3/4,4/5,7]]); m; m.parent() @@ -576,6 +580,7 @@ def matrix(*args, **kwds): Check :trac:`24459`:: + sage: # needs sage.libs.flint sage: Matrix(ZZ, sys.maxsize, sys.maxsize) Traceback (most recent call last): ... @@ -645,10 +650,13 @@ def matrix(*args, **kwds): M.set_immutable() return M + Matrix = matrix + from .special import * + @matrix_method class options(GlobalOptions): r""" diff --git a/src/sage/matrix/echelon_matrix.pyx b/src/sage/matrix/echelon_matrix.pyx index 3fc43b485ca..7f5457a7f7b 100644 --- a/src/sage/matrix/echelon_matrix.pyx +++ b/src/sage/matrix/echelon_matrix.pyx @@ -48,7 +48,7 @@ def reduced_echelon_matrix_iterator(K, k, n, bint sparse=False, bint copy=True, EXAMPLES:: sage: from sage.matrix.echelon_matrix import reduced_echelon_matrix_iterator - sage: it = reduced_echelon_matrix_iterator(GF(2),2,3) + sage: it = reduced_echelon_matrix_iterator(GF(2), 2, 3) sage: for m in it: ....: print(m) ....: print(m.pivots()) @@ -95,12 +95,12 @@ def reduced_echelon_matrix_iterator(K, k, n, bint sparse=False, bint copy=True, Testing options:: - sage: it = reduced_echelon_matrix_iterator(GF(4,'z'), 2, 4, copy=False) - sage: next(it) is next(it) + sage: it = reduced_echelon_matrix_iterator(GF(4, 'z'), 2, 4, copy=False) # needs sage.rings.finite_rings + sage: next(it) is next(it) # needs sage.rings.finite_rings True sage: for a in it: pass - sage: it = reduced_echelon_matrix_iterator(GF(4,'z'), 2, 4, set_immutable=True) + sage: it = reduced_echelon_matrix_iterator(GF(4, 'z'), 2, 4, set_immutable=True) # needs sage.rings.finite_rings sage: all(a.is_immutable() and a.echelon_form() == a for a in it) True """ diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index d3a5fee358e..d781fc822b0 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -30,13 +30,11 @@ import sage.misc.latex import sage.rings.integer from sage.arith.power cimport generic_power -from sage.misc.verbose import verbose, get_verbose from sage.structure.sequence import Sequence from sage.structure.parent cimport Parent cimport sage.structure.element -from sage.structure.element cimport ModuleElement, Element, RingElement, Vector -from sage.structure.mutability cimport Mutability +from sage.structure.element cimport Element, Vector from sage.misc.misc_c cimport normalize_index from sage.categories.fields import Fields @@ -526,7 +524,7 @@ cdef class Matrix(sage.structure.element.Matrix): This is fast since it is a cdef function and there is no bounds checking. """ - raise NotImplementedError("this must be defined in the derived class (type=%s)"%type(self)) + raise NotImplementedError("this must be defined in the derived class (type=%s)" % type(self)) cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j): """ @@ -545,11 +543,11 @@ cdef class Matrix(sage.structure.element.Matrix): TESTS:: - sage: class MyAlgebraicNumber(sage.rings.qqbar.AlgebraicNumber): + sage: class MyAlgebraicNumber(sage.rings.qqbar.AlgebraicNumber): # needs sage.rings.number_fields ....: def __bool__(self): ....: raise ValueError - sage: mat = matrix(1,1,MyAlgebraicNumber(1)) - sage: bool(mat) + sage: mat = matrix(1, 1, MyAlgebraicNumber(1)) # needs sage.rings.number_fields + sage: bool(mat) # needs sage.rings.number_fields Traceback (most recent call last): ... ValueError @@ -583,26 +581,25 @@ cdef class Matrix(sage.structure.element.Matrix): self.set_unsafe(i, j, elt + self.get_unsafe(i, j)) + ## def _get_very_unsafe(self, i, j): + ## r""" + ## Entry access, but potentially fast since it might be without + ## bounds checking. (I know of no cases where this is actually + ## faster.) -## def _get_very_unsafe(self, i, j): -## r""" -## Entry access, but potentially fast since it might be without -## bounds checking. (I know of no cases where this is actually -## faster.) + ## This function it can very easily !! SEG FAULT !! if you call + ## it with invalid input. Use with *extreme* caution. -## This function it can very easily !! SEG FAULT !! if you call -## it with invalid input. Use with *extreme* caution. + ## EXAMPLES:: + ## + ## sage: a = matrix(ZZ,2,range(4)) + ## sage: a._get_very_unsafe(0,1) + ## 1 -## EXAMPLES:: -## -## sage: a = matrix(ZZ,2,range(4)) -## sage: a._get_very_unsafe(0,1) -## 1 - -## If you do \code{a.\_get\_very\_unsafe(0,10)} you'll very likely crash Sage -## completely. -## """ -## return self.get_unsafe(i, j) + ## If you do \code{a.\_get\_very\_unsafe(0,10)} you'll very likely crash Sage + ## completely. + ## """ + ## return self.get_unsafe(i, j) def __iter__(self): """ @@ -909,16 +906,19 @@ cdef class Matrix(sage.structure.element.Matrix): Check that submatrices with a specified implementation have the same implementation:: + sage: # needs sage.libs.pari sage: M = MatrixSpace(GF(2), 3, 3, implementation='generic') sage: m = M(range(9)) sage: type(m) <class 'sage.matrix.matrix_generic_dense.Matrix_generic_dense'> sage: parent(m) - Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 2 (using Matrix_generic_dense) + Full MatrixSpace of 3 by 3 dense matrices + over Finite Field of size 2 (using Matrix_generic_dense) sage: type(m[:2,:2]) <class 'sage.matrix.matrix_generic_dense.Matrix_generic_dense'> sage: parent(m[:2,:2]) - Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 2 (using Matrix_generic_dense) + Full MatrixSpace of 2 by 2 dense matrices + over Finite Field of size 2 (using Matrix_generic_dense) """ cdef list row_list cdef list col_list @@ -965,7 +965,7 @@ cdef class Matrix(sage.structure.element.Matrix): if ind < 0 or ind >= nrows: raise IndexError("matrix index out of range") elif isinstance(row_index, slice): - row_list = list(xrange(*row_index.indices(nrows))) + row_list = list(range(*row_index.indices(nrows))) else: if not PyIndex_Check(row_index): raise TypeError("index must be an integer") @@ -998,7 +998,7 @@ cdef class Matrix(sage.structure.element.Matrix): if ind < 0 or ind >= ncols: raise IndexError("matrix index out of range") elif isinstance(col_index, slice): - col_list = list(xrange(*col_index.indices(ncols))) + col_list = list(range(*col_index.indices(ncols))) else: if not PyIndex_Check(col_index): raise TypeError("index must be an integer") @@ -1049,7 +1049,7 @@ cdef class Matrix(sage.structure.element.Matrix): raise IndexError("matrix index out of range") r = self.matrix_from_rows(row_list) elif isinstance(row_index, slice): - row_list = list(xrange(*row_index.indices(nrows))) + row_list = list(range(*row_index.indices(nrows))) r = self.matrix_from_rows(row_list) else: if not PyIndex_Check(row_index): @@ -1396,7 +1396,6 @@ cdef class Matrix(sage.structure.element.Matrix): """ cdef list row_list cdef list col_list - cdef object index cdef Py_ssize_t row_list_len, col_list_len cdef list value_list cdef bint value_list_one_dimensional = 0 @@ -1638,13 +1637,14 @@ cdef class Matrix(sage.structure.element.Matrix): sage: A = Matrix(QQ, 2, 2, [1/2, 1/3, 1/3, 1/4]) sage: A.parent() - Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: A.change_ring(GF(25,'a')) + Full MatrixSpace of 2 by 2 dense matrices over Rational Field + sage: A.change_ring(GF(25,'a')) # needs sage.rings.finite_rings [3 2] [2 4] - sage: A.change_ring(GF(25,'a')).parent() - Full MatrixSpace of 2 by 2 dense matrices over Finite Field in a of size 5^2 - sage: A.change_ring(ZZ) + sage: A.change_ring(GF(25,'a')).parent() # needs sage.rings.finite_rings + Full MatrixSpace of 2 by 2 dense matrices + over Finite Field in a of size 5^2 + sage: A.change_ring(ZZ) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: matrix has denominators so can...t change to ZZ @@ -1655,7 +1655,7 @@ cdef class Matrix(sage.structure.element.Matrix): [1/2 1/3] [-------] [1/3 1/4] - sage: A.change_ring(GF(25,'a')) + sage: A.change_ring(GF(25,'a')) # needs sage.rings.finite_rings [3 2] [---] [2 4] @@ -1924,9 +1924,10 @@ cdef class Matrix(sage.structure.element.Matrix): Prior to :trac:`11544` this could take a full minute to run (2011). :: + sage: # needs sage.rings.number_field sage: A = matrix(QQ, 4, 4, [1, 2, -2, 2, 1, 0, -1, -1, 0, -1, 1, 1, -1, 2, 1/2, 0]) sage: e = A.eigenvalues()[3] - sage: K = (A-e).kernel() + sage: K = (A - e).kernel() sage: P = K.basis_matrix() sage: P.str() '[ 1.000000000000000? + 0.?e-17*I -2.116651487479748? + 0.0255565807096352?*I -0.2585224251020429? + 0.2886023409047535?*I -0.4847545623533090? - 1.871890760086142?*I]' @@ -2239,13 +2240,12 @@ cdef class Matrix(sage.structure.element.Matrix): tmp = [align*(b-a) for a,b in zip([0] + col_divs, col_divs + [nc])] format = '|'.join(tmp) - return "\\left" + matrix_delimiters[0] + "\\begin{array}{%s}\n"%format + s + "\n\\end{array}\\right" + matrix_delimiters[1] - - + return "\\left" + matrix_delimiters[0] + "\\begin{array}{%s}\n" % format + s + "\n\\end{array}\\right" + matrix_delimiters[1] ################################################### ## Basic Properties ################################################### + def ncols(self): """ Return the number of columns of this matrix. @@ -2313,22 +2313,20 @@ cdef class Matrix(sage.structure.element.Matrix): """ return (self._nrows,self._ncols) - ################################################### # Functions ################################################### + def act_on_polynomial(self, f): r""" Return the polynomial f(self\*x). INPUT: - - ``self`` - an nxn matrix - ``f`` - a polynomial in n variables x=(x1,...,xn) - OUTPUT: The polynomial f(self\*x). EXAMPLES:: @@ -2346,7 +2344,6 @@ cdef class Matrix(sage.structure.element.Matrix): if self._nrows != self._ncols: raise ArithmeticError("self must be a square matrix") - F = f.base_ring() vars = f.parent().gens() n = len(self.rows()) ans = [] @@ -2363,17 +2360,18 @@ cdef class Matrix(sage.structure.element.Matrix): EXAMPLES:: - sage: f(x,y) = x^2+y - sage: m = matrix([[f,f*f],[f^3,f^4]]); m + sage: # needs sage.symbolic + sage: f(x,y) = x^2 + y + sage: m = matrix([[f, f*f], [f^3, f^4]]); m [ (x, y) |--> x^2 + y (x, y) |--> (x^2 + y)^2] [(x, y) |--> (x^2 + y)^3 (x, y) |--> (x^2 + y)^4] - sage: m(1,2) + sage: m(1, 2) [ 3 9] [27 81] - sage: m(y=2,x=1) + sage: m(y=2, x=1) [ 3 9] [27 81] - sage: m(2,1) + sage: m(2, 1) [ 5 25] [125 625] """ @@ -2561,6 +2559,7 @@ cdef class Matrix(sage.structure.element.Matrix): Next of all, create a permutation group element and act on ``M`` with it:: + sage: # needs sage.groups sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)']) sage: sigma, tau = G.gens() sage: sigma @@ -2612,6 +2611,7 @@ cdef class Matrix(sage.structure.element.Matrix): Next of all, create a permutation group element and act on ``M``:: + sage: # needs sage.groups sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)']) sage: sigma, tau = G.gens() sage: sigma @@ -2743,6 +2743,7 @@ cdef class Matrix(sage.structure.element.Matrix): Next of all, create a permutation group element and act on ``M``:: + sage: # needs sage.groups sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)']) sage: sigma, tau = G.gens() sage: sigma @@ -2792,6 +2793,7 @@ cdef class Matrix(sage.structure.element.Matrix): Next of all, create a permutation group element and act on ``M``:: + sage: # needs sage.groups sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)']) sage: sigma, tau = G.gens() sage: sigma @@ -2850,6 +2852,7 @@ cdef class Matrix(sage.structure.element.Matrix): Next of all, create a permutation group element and act on ``M``:: + sage: # needs sage.groups sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)']) sage: sigma, tau = G.gens() sage: sigma @@ -2895,6 +2898,7 @@ cdef class Matrix(sage.structure.element.Matrix): Next of all, create a permutation group element and act on ``M``:: + sage: # needs sage.groups sage: G = PermutationGroup(['(1,2,3)(4,5)', '(1,2,3,4,5)']) sage: sigma, tau = G.gens() sage: sigma @@ -2933,10 +2937,11 @@ cdef class Matrix(sage.structure.element.Matrix): If not, we get an error message:: - sage: a.add_multiple_of_row(1,0,SR.I()) + sage: a.add_multiple_of_row(1, 0, SR.I()) # needs sage.symbolic Traceback (most recent call last): ... - TypeError: Multiplying row by Symbolic Ring element cannot be done over Rational Field, use change_ring or with_added_multiple_of_row instead. + TypeError: Multiplying row by Symbolic Ring element cannot be done over + Rational Field, use change_ring or with_added_multiple_of_row instead. """ self.check_row_bounds_and_mutability(i,j) try: @@ -3017,10 +3022,11 @@ cdef class Matrix(sage.structure.element.Matrix): If not, we get an error message:: - sage: a.add_multiple_of_column(1,0,SR.I()) + sage: a.add_multiple_of_column(1, 0, SR.I()) # needs sage.symbolic Traceback (most recent call last): ... - TypeError: Multiplying column by Symbolic Ring element cannot be done over Rational Field, use change_ring or with_added_multiple_of_column instead. + TypeError: Multiplying column by Symbolic Ring element cannot be done over + Rational Field, use change_ring or with_added_multiple_of_column instead. """ self.check_column_bounds_and_mutability(i,j) try: @@ -3124,7 +3130,8 @@ cdef class Matrix(sage.structure.element.Matrix): sage: a.rescale_row(1,1/2) Traceback (most recent call last): ... - TypeError: Rescaling row by Rational Field element cannot be done over Integer Ring, use change_ring or with_rescaled_row instead. + TypeError: Rescaling row by Rational Field element cannot be done + over Integer Ring, use change_ring or with_rescaled_row instead. To rescale the matrix by 1/2, you must change the base ring to the rationals:: @@ -3238,7 +3245,8 @@ cdef class Matrix(sage.structure.element.Matrix): sage: a.rescale_col(2,1/2) Traceback (most recent call last): ... - TypeError: Rescaling column by Rational Field element cannot be done over Integer Ring, use change_ring or with_rescaled_col instead. + TypeError: Rescaling column by Rational Field element cannot be done + over Integer Ring, use change_ring or with_rescaled_col instead. To rescale the matrix by 1/2, you must change the base ring to the rationals:: @@ -3735,8 +3743,8 @@ cdef class Matrix(sage.structure.element.Matrix): - [FZ2001]_ """ cdef dict d = {} - cdef list queue = list(xrange(self._ncols)) - cdef int l, sign, i, j + cdef list queue = list(range(self._ncols)) + cdef int l, sign, i if skew: # testing the diagonal entries to be zero @@ -3762,7 +3770,7 @@ cdef class Matrix(sage.structure.element.Matrix): else: L.extend( L_prime ) if return_diag: - return [d[i] for i in xrange(self._nrows)] + return [d[i] for i in range(self._nrows)] else: return True @@ -3929,21 +3937,21 @@ cdef class Matrix(sage.structure.element.Matrix): def is_symmetric(self): """ - Return True if this is a symmetric matrix. + Return ``True`` if this is a symmetric matrix. A symmetric matrix is necessarily square. EXAMPLES:: - sage: m=Matrix(QQ,2,range(0,4)) + sage: m = Matrix(QQ, 2, range(0,4)) sage: m.is_symmetric() False - sage: m=Matrix(QQ,2,(1,1,1,1,1,1)) + sage: m = Matrix(QQ, 2, (1,1,1,1,1,1)) sage: m.is_symmetric() False - sage: m=Matrix(QQ,1,(2,)) + sage: m = Matrix(QQ, 1, (2,)) sage: m.is_symmetric() True @@ -3989,6 +3997,7 @@ cdef class Matrix(sage.structure.element.Matrix): EXAMPLES:: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[ 1 + I, 1 - 6*I, -1 - I], ....: [-3 - I, -4*I, -2], ....: [-1 + I, -2 - 8*I, 2 + I]]) @@ -4001,6 +4010,7 @@ cdef class Matrix(sage.structure.element.Matrix): Sage has several fields besides the entire complex numbers where conjugation is non-trivial:: + sage: # needs sage.rings.number_field sage: F.<b> = QuadraticField(-7) sage: C = matrix(F, [[-2*b - 3, 7*b - 6, -b + 3], ....: [-2*b - 3, -3*b + 2, -2*b], @@ -4014,19 +4024,20 @@ cdef class Matrix(sage.structure.element.Matrix): A matrix that is nearly Hermitian, but for a non-real diagonal entry:: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[ 2, 2-I, 1+4*I], ....: [ 2+I, 3+I, 2-6*I], ....: [1-4*I, 2+6*I, 5]]) sage: A._is_hermitian(skew=False, tolerance=0) False - sage: A[1,1] = 132 + sage: A[1, 1] = 132 sage: A._is_hermitian(skew=False, tolerance=0) True Rectangular matrices are never Hermitian:: - sage: A = matrix(QQbar, 3, 4) - sage: A._is_hermitian(skew=False, tolerance=0) + sage: A = matrix(QQbar, 3, 4) # needs sage.rings.number_field + sage: A._is_hermitian(skew=False, tolerance=0) # needs sage.rings.number_field False A square, empty matrix is trivially Hermitian:: @@ -4036,8 +4047,9 @@ cdef class Matrix(sage.structure.element.Matrix): True A matrix that is skew-Hermitian:: - sage: A = matrix(QQbar, [[-I, 2+I], [-2+I, 0]]) - sage: A._is_hermitian(skew=False, tolerance=0) + + sage: A = matrix(QQbar, [[-I, 2+I], [-2+I, 0]]) # needs sage.rings.number_field + sage: A._is_hermitian(skew=False, tolerance=0) # needs sage.rings.number_field False sage: A._is_hermitian(skew=True, tolerance=0) True @@ -4131,18 +4143,20 @@ cdef class Matrix(sage.structure.element.Matrix): EXAMPLES:: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[ 1 + I, 1 - 6*I, -1 - I], ....: [-3 - I, -4*I, -2], ....: [-1 + I, -2 - 8*I, 2 + I]]) sage: A.is_hermitian() False - sage: B = A*A.conjugate_transpose() + sage: B = A * A.conjugate_transpose() sage: B.is_hermitian() True Sage has several fields besides the entire complex numbers where conjugation is non-trivial. :: + sage: # needs sage.rings.number_field sage: F.<b> = QuadraticField(-7) sage: C = matrix(F, [[-2*b - 3, 7*b - 6, -b + 3], ....: [-2*b - 3, -3*b + 2, -2*b], @@ -4156,19 +4170,20 @@ cdef class Matrix(sage.structure.element.Matrix): A matrix that is nearly Hermitian, but for a non-real diagonal entry. :: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[ 2, 2-I, 1+4*I], ....: [ 2+I, 3+I, 2-6*I], ....: [1-4*I, 2+6*I, 5]]) sage: A.is_hermitian() False - sage: A[1,1] = 132 + sage: A[1, 1] = 132 sage: A.is_hermitian() True Rectangular matrices are never Hermitian. :: - sage: A = matrix(QQbar, 3, 4) - sage: A.is_hermitian() + sage: A = matrix(QQbar, 3, 4) # needs sage.rings.number_field + sage: A.is_hermitian() # needs sage.rings.number_field False A square, empty matrix is trivially Hermitian. :: @@ -4206,27 +4221,28 @@ cdef class Matrix(sage.structure.element.Matrix): EXAMPLES:: - sage: A = matrix(QQbar, [[0, -1], + sage: A = matrix(QQbar, [[0, -1], # needs sage.rings.number_field ....: [1, 0]]) - sage: A.is_skew_hermitian() + sage: A.is_skew_hermitian() # needs sage.rings.number_field True A matrix that is nearly skew-Hermitian, but for a non-real diagonal entry. :: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[ -I, -1, 1-I], ....: [ 1, 1, -1], ....: [-1-I, 1, -I]]) sage: A.is_skew_hermitian() False - sage: A[1,1] = -I + sage: A[1, 1] = -I sage: A.is_skew_hermitian() True Rectangular matrices are never skew-Hermitian. :: - sage: A = matrix(QQbar, 3, 4) - sage: A.is_skew_hermitian() + sage: A = matrix(QQbar, 3, 4) # needs sage.rings.number_field + sage: A.is_skew_hermitian() # needs sage.rings.number_field False A square, empty matrix is trivially Hermitian. :: @@ -4620,7 +4636,7 @@ cdef class Matrix(sage.structure.element.Matrix): print(self) print(self.nrows()) print(self.dict()) - raise RuntimeError("BUG: matrix pivots should have been set but weren't, matrix parent = '%s'"%self.parent()) + raise RuntimeError("BUG: matrix pivots should have been set but weren't, matrix parent = '%s'" % self.parent()) return tuple(x) def rank(self): @@ -4629,7 +4645,7 @@ cdef class Matrix(sage.structure.element.Matrix): EXAMPLES:: - sage: m = matrix(GF(7),5,range(25)) + sage: m = matrix(GF(7), 5, range(25)) sage: m.rank() 2 @@ -4647,8 +4663,8 @@ cdef class Matrix(sage.structure.element.Matrix): entries are polynomials over a finite field (:trac:`5014`):: sage: P.<x> = PolynomialRing(GF(17)) - sage: m = matrix(P, [ [ 6*x^2 + 8*x + 12, 10*x^2 + 4*x + 11], - ....: [8*x^2 + 12*x + 15, 8*x^2 + 9*x + 16] ]) + sage: m = matrix(P, [[ 6*x^2 + 8*x + 12, 10*x^2 + 4*x + 11], + ....: [8*x^2 + 12*x + 15, 8*x^2 + 9*x + 16]]) sage: m.rank() 2 """ @@ -4687,7 +4703,7 @@ cdef class Matrix(sage.structure.element.Matrix): X = set(self.pivots()) np = [] - for j in xrange(self.ncols()): + for j in range(self.ncols()): if j not in X: np.append(j) np = tuple(np) @@ -4881,17 +4897,18 @@ cdef class Matrix(sage.structure.element.Matrix): Over finite fields:: - sage: A = matrix(GF(59),3,[10,56,39,53,56,33,58,24,55]) - sage: A.multiplicative_order() + sage: A = matrix(GF(59), 3, [10,56,39,53,56,33,58,24,55]) + sage: A.multiplicative_order() # needs sage.groups 580 sage: (A^580).is_one() True - sage: B = matrix(GF(10007^3,'b'),0) - sage: B.multiplicative_order() + sage: B = matrix(GF(10007^3, 'b'), 0) # needs sage.rings.finite_rings + sage: B.multiplicative_order() # needs sage.rings.finite_rings 1 - sage: M = MatrixSpace(GF(11^2,'e'),5) + sage: # needs sage.rings.finite_rings + sage: M = MatrixSpace(GF(11^2, 'e'), 5) sage: E = M.random_element() sage: while E.det() == 0: ....: E = M.random_element() @@ -4900,23 +4917,23 @@ cdef class Matrix(sage.structure.element.Matrix): Over `\ZZ`:: - sage: m = matrix(ZZ,2,2,[-1,1,-1,0]) - sage: m.multiplicative_order() + sage: m = matrix(ZZ, 2, 2, [-1,1,-1,0]) + sage: m.multiplicative_order() # needs sage.groups 3 - sage: m = posets.ChainPoset(6).coxeter_transformation() - sage: m.multiplicative_order() + sage: m = posets.ChainPoset(6).coxeter_transformation() # needs sage.combinat sage.graphs + sage: m.multiplicative_order() # needs sage.combinat sage.graphs sage.groups 7 - sage: P = posets.TamariLattice(4).coxeter_transformation() - sage: P.multiplicative_order() + sage: P = posets.TamariLattice(4).coxeter_transformation() # needs sage.combinat sage.graphs + sage: P.multiplicative_order() # needs sage.combinat sage.graphs sage.groups 10 sage: M = matrix(ZZ, 2, 2, [1, 1, 0, 1]) - sage: M.multiplicative_order() + sage: M.multiplicative_order() # needs sage.groups +Infinity - sage: for k in range(600): + sage: for k in range(600): # needs sage.groups ....: m = SL2Z.random_element() ....: o = m.multiplicative_order() ....: if o != Infinity and m**o != SL2Z.one(): @@ -4931,18 +4948,18 @@ cdef class Matrix(sage.structure.element.Matrix): ....: else: ....: return ZZ.random_element(-100,100) sage: rnd = matrix(ZZ, 8, 8, val) - sage: (rnd * m24 * rnd.inverse_of_unit()).multiplicative_order() + sage: (rnd * m24 * rnd.inverse_of_unit()).multiplicative_order() # needs sage.groups 24 TESTS:: - sage: C = matrix(GF(2^10,'c'),2,3,[1]*6) - sage: C.multiplicative_order() + sage: C = matrix(GF(2^10, 'c'), 2, 3, [1]*6) # needs sage.rings.finite_rings + sage: C.multiplicative_order() # needs sage.rings.finite_rings Traceback (most recent call last): ... ArithmeticError: self must be invertible ... - sage: D = matrix(IntegerModRing(6),3,[5,5,3,0,2,5,5,4,0]) + sage: D = matrix(IntegerModRing(6), 3, [5,5,3,0,2,5,5,4,0]) sage: D.multiplicative_order() Traceback (most recent call last): ... @@ -5062,6 +5079,7 @@ cdef class Matrix(sage.structure.element.Matrix): Check that :trac:`8198` is fixed:: + sage: # needs sage.rings.padics sage: R = Qp(5, 5) sage: x = R(5).add_bigoh(1) sage: I = matrix(R, [[1, 0], [0, 1]]) @@ -5075,7 +5093,7 @@ cdef class Matrix(sage.structure.element.Matrix): raise ArithmeticError("number of rows of matrix must equal degree of vector") cdef Py_ssize_t i return sum([v[i] * self.row(i, from_list=True) - for i in xrange(self._nrows)], M(0)) + for i in range(self._nrows)], M(0)) cdef _matrix_times_vector_(self, Vector v): """ @@ -5096,6 +5114,7 @@ cdef class Matrix(sage.structure.element.Matrix): Check that :trac:`8198` is fixed:: + sage: # needs sage.rings.padics sage: R = Qp(5, 5) sage: x = R(5).add_bigoh(1) sage: I = matrix(R, [[1, 0], [0, 1]]) @@ -5109,7 +5128,7 @@ cdef class Matrix(sage.structure.element.Matrix): raise ArithmeticError("number of columns of matrix must equal degree of vector") cdef Py_ssize_t i return sum([self.column(i, from_list=True) * v[i] - for i in xrange(self._ncols)], M(0)) + for i in range(self._ncols)], M(0)) def iterates(self, v, n, rows=True): r""" @@ -5193,10 +5212,11 @@ cdef class Matrix(sage.structure.element.Matrix): EXAMPLES:: - sage: R.<x,y> = FreeAlgebra(QQ,2) - sage: a = matrix(2,2, [1,2,x*y,y*x]) - sage: b = matrix(2,2, [1,2,y*x,y*x]) - sage: a+b # indirect doctest + sage: # needs sage.combinat + sage: R.<x,y> = FreeAlgebra(QQ, 2) + sage: a = matrix(2, 2, [1,2,x*y,y*x]) + sage: b = matrix(2, 2, [1,2,y*x,y*x]) + sage: a + b # indirect doctest [ 2 4] [x*y + y*x 2*y*x] @@ -5216,10 +5236,11 @@ cdef class Matrix(sage.structure.element.Matrix): EXAMPLES:: + sage: # needs sage.combinat sage: R.<x,y> = FreeAlgebra(QQ,2) - sage: a = matrix(2,2, [1,2,x*y,y*x]) - sage: b = matrix(2,2, [1,2,y*x,y*x]) - sage: a-b # indirect doctest + sage: a = matrix(2, 2, [1,2,x*y,y*x]) + sage: b = matrix(2, 2, [1,2,y*x,y*x]) + sage: a - b # indirect doctest [ 0 0] [x*y - y*x 0] @@ -5292,11 +5313,12 @@ cdef class Matrix(sage.structure.element.Matrix): [ x*y x^2*y x*y^2] [ -x^2*y^2 x^2*y + x*y^2 x^2*y - x*y^2] + sage: # needs sage.combinat sage: R.<x,y> = FreeAlgebra(ZZ,2) - sage: a = matrix(R,2,3,[1,x,y,-x*y,x+y,x-y]); a + sage: a = matrix(R, 2, 3, [1,x,y, -x*y,x+y,x-y]); a [ 1 x y] [ -x*y x + y x - y] - sage: (x*y) * a # indirect doctest + sage: (x*y) * a # indirect doctest [ x*y x*y*x x*y^2] [ -x*y*x*y x*y*x + x*y^2 x*y*x - x*y^2] """ @@ -5325,8 +5347,9 @@ cdef class Matrix(sage.structure.element.Matrix): An example in which the base ring is not commutative:: + sage: # needs sage.combinat sage: F.<x,y> = FreeAlgebra(QQ,2) - sage: a = matrix(2,[x,y,x^2,y^2]); a + sage: a = matrix(2, [x,y, x^2,y^2]); a [ x y] [x^2 y^2] sage: x * a # indirect doctest @@ -5336,8 +5359,9 @@ cdef class Matrix(sage.structure.element.Matrix): [ x*y y^2] [x^2*y y^3] + sage: # needs sage.combinat sage: R.<x,y> = FreeAlgebra(ZZ,2) - sage: a = matrix(R,2,3,[1,x,y,-x*y,x+y,x-y]); a + sage: a = matrix(R, 2, 3, [1,x,y, -x*y,x+y,x-y]); a [ 1 x y] [ -x*y x + y x - y] sage: a * (x*y) @@ -5371,10 +5395,10 @@ cdef class Matrix(sage.structure.element.Matrix): [ 1 -x*y] [ x x + y] [ y x - y] - sage: a*b # indirect doctest + sage: a*b # indirect doctest [ x^2 + y^2 + 1 x^2 + x*y - y^2] [ x^2 + x*y - y^2 x^2*y^2 + 2*x^2 + 2*y^2] - sage: b*a # indirect doctest + sage: b*a # indirect doctest [ x^2*y^2 + 1 -x^2*y - x*y^2 + x -x^2*y + x*y^2 + y] [ -x^2*y - x*y^2 + x 2*x^2 + 2*x*y + y^2 x^2 + x*y - y^2] [ -x^2*y + x*y^2 + y x^2 + x*y - y^2 x^2 - 2*x*y + 2*y^2] @@ -5382,47 +5406,49 @@ cdef class Matrix(sage.structure.element.Matrix): We verify that the matrix multiplies are correct by comparing them with what PARI gets:: - sage: gp(a)*gp(b) - gp(a*b) + sage: gp(a)*gp(b) - gp(a*b) # needs sage.libs.pari [0, 0; 0, 0] - sage: gp(b)*gp(a) - gp(b*a) + sage: gp(b)*gp(a) - gp(b*a) # needs sage.libs.pari [0, 0, 0; 0, 0, 0; 0, 0, 0] EXAMPLE of matrix times matrix over different base rings:: - sage: a = matrix(ZZ,2,2,range(4)) - sage: b = matrix(GF(7),2,2,range(4)) - sage: c = matrix(QQ,2,2,range(4)) - sage: d = a*b; d + sage: a = matrix(ZZ, 2, 2, range(4)) + sage: b = matrix(GF(7), 2, 2, range(4)) + sage: c = matrix(QQ, 2, 2, range(4)) + sage: d = a * b; d [2 3] [6 4] sage: parent(d) Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 - sage: parent(b*a) + sage: parent(b * a) Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 - sage: d = a*c; d + sage: d = a * c; d [ 2 3] [ 6 11] sage: parent(d) Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: d = b+c + sage: d = b + c Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for +: 'Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7' and 'Full MatrixSpace of 2 by 2 dense matrices over Rational Field' - sage: d = b+c.change_ring(GF(7)); d + TypeError: unsupported operand parent(s) for +: + 'Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7' and + 'Full MatrixSpace of 2 by 2 dense matrices over Rational Field' + sage: d = b + c.change_ring(GF(7)); d [0 2] [4 6] EXAMPLE of matrix times matrix where one matrix is sparse and the other is dense (in such mixed cases, the result is always dense):: - sage: a = matrix(ZZ,2,2,range(4),sparse=True) - sage: b = matrix(GF(7),2,2,range(4),sparse=False) - sage: c = a*b; c + sage: a = matrix(ZZ, 2, 2, range(4), sparse=True) + sage: b = matrix(GF(7), 2, 2, range(4), sparse=False) + sage: c = a * b; c [2 3] [6 4] sage: parent(c) Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 - sage: c = b*a; c + sage: c = b * a; c [2 3] [6 4] sage: parent(c) @@ -5430,11 +5456,12 @@ cdef class Matrix(sage.structure.element.Matrix): EXAMPLE of matrix multiplication over a noncommutative base ring:: - sage: R.<x,y> = FreeAlgebra(QQ,2) + sage: # needs sage.combinat + sage: R.<x,y> = FreeAlgebra(QQ, 2) sage: x*y - y*x x*y - y*x - sage: a = matrix(2,2, [1,2,x,y]) - sage: b = matrix(2,2, [x,y,x^2,y^2]) + sage: a = matrix(2, 2, [1,2, x,y]) + sage: b = matrix(2, 2, [x,y, x^2,y^2]) sage: a*b [ x + 2*x^2 y + 2*y^2] [x^2 + y*x^2 x*y + y^3] @@ -5459,7 +5486,9 @@ cdef class Matrix(sage.structure.element.Matrix): sage: a*v Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 3 dense matrices over Integer Ring' and 'Ambient free module of rank 2 over the principal ideal domain Integer Ring' + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 3 dense matrices over Integer Ring' and + 'Ambient free module of rank 2 over the principal ideal domain Integer Ring' This illustrates how coercion works:: @@ -5506,8 +5535,9 @@ cdef class Matrix(sage.structure.element.Matrix): EXAMPLE of scalar multiplication in the noncommutative case:: - sage: R.<x,y> = FreeAlgebra(ZZ,2) - sage: a = matrix(2,[x,y,x^2,y^2]) + sage: # needs sage.combinat + sage: R.<x,y> = FreeAlgebra(ZZ, 2) + sage: a = matrix(2, [x,y, x^2,y^2]) sage: a * x [ x^2 y*x] [ x^3 y^2*x] @@ -5634,17 +5664,18 @@ cdef class Matrix(sage.structure.element.Matrix): sage: m = matrix(Zmod(2^100),2,[2,1,3,3]) sage: type(m) <class 'sage.matrix.matrix_generic_dense.Matrix_generic_dense'> - sage: (~m)*m + sage: (~m)*m # needs sage.libs.pari [1 0] [0 1] - sage: ~m + sage: ~m # needs sage.libs.pari [ 1 422550200076076467165567735125] [1267650600228229401496703205375 422550200076076467165567735126] Matrices over p-adics. See :trac:`17272` :: - sage: R = ZpCA(5,5,print_mode='val-unit') - sage: A = matrix(R,3,3,[250,2369,1147,106,927,362,90,398,2483]) + sage: # needs sage.rings.padics + sage: R = ZpCA(5, 5, print_mode='val-unit') + sage: A = matrix(R, 3, 3, [250,2369,1147,106,927,362,90,398,2483]) sage: A [5^3 * 2 + O(5^5) 2369 + O(5^5) 1147 + O(5^5)] [ 106 + O(5^5) 927 + O(5^5) 362 + O(5^5)] @@ -5770,19 +5801,19 @@ cdef class Matrix(sage.structure.element.Matrix): EXAMPLES:: sage: R.<a,b,c,d> = ZZ[] - sage: RR = R.quotient(a*d-b*c-1) - sage: a,b,c,d = RR.gens() - sage: m = matrix(2, [a,b,c,d]) - sage: n = m.inverse_of_unit() - sage: m * n + sage: RR = R.quotient(a*d - b*c - 1) + sage: a,b,c,d = RR.gens() # needs sage.libs.singular + sage: m = matrix(2, [a,b, c,d]) + sage: n = m.inverse_of_unit() # needs sage.libs.singular + sage: m * n # needs sage.libs.singular [1 0] [0 1] - sage: matrix(RR, 2, 1, [a,b]).inverse_of_unit() + sage: matrix(RR, 2, 1, [a,b]).inverse_of_unit() # needs sage.libs.singular Traceback (most recent call last): ... ArithmeticError: self must be a square matrix - sage: matrix(RR, 1, 1, [2]).inverse_of_unit() + sage: matrix(RR, 1, 1, [2]).inverse_of_unit() # needs sage.libs.singular Traceback (most recent call last): ... NotImplementedError: Lifting of multivariate polynomials over non-fields is not implemented. @@ -5795,9 +5826,9 @@ cdef class Matrix(sage.structure.element.Matrix): Tests for :trac:`28570`:: - sage: P = posets.TamariLattice(7) - sage: M = P._hasse_diagram._leq_matrix - sage: M.inverse_of_unit() # this was very slow, now 1s + sage: P = posets.TamariLattice(7) # needs sage.combinat sage.graphs + sage: M = P._hasse_diagram._leq_matrix # needs sage.combinat sage.graphs + sage: M.inverse_of_unit() # this was very slow, now 1s # needs sage.combinat sage.graphs 429 x 429 sparse matrix over Integer Ring... sage: m = matrix(Zmod(2**2), 1, 1, [1], sparse=True) @@ -5890,9 +5921,9 @@ cdef class Matrix(sage.structure.element.Matrix): Non-integer (symbolic) exponents are also supported:: - sage: k = var('k') + sage: k = var('k') # needs sage.symbolic sage: A = matrix([[2, -1], [1, 0]]) - sage: A^(2*k+1) + sage: A^(2*k+1) # needs sage.symbolic [ 2*k + 2 -2*k - 1] [ 2*k + 1 -2*k] """ diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index f38c429d994..2ee50b25b7b 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -5,7 +5,7 @@ For design documentation see :mod:`sage.matrix.docs`. TESTS:: - sage: A = Matrix(GF(5),3,3,srange(9)) + sage: A = Matrix(GF(5), 3, 3, srange(9)) sage: TestSuite(A).run() """ @@ -40,11 +40,11 @@ cdef class Matrix(Matrix0): sage: a = matrix(R,2,[x+1,2/3, x^2/2, 1+x^3]); a [ x + 1 2/3] [1/2*x^2 x^3 + 1] - sage: b = gp(a); b # indirect doctest + sage: b = gp(a); b # indirect doctest # needs sage.libs.pari [x + 1, 2/3; 1/2*x^2, x^3 + 1] sage: a.determinant() x^4 + x^3 - 1/3*x^2 + x + 1 - sage: b.matdet() + sage: b.matdet() # needs sage.libs.pari x^4 + x^3 - 1/3*x^2 + x + 1 """ w = self.list() @@ -69,11 +69,11 @@ cdef class Matrix(Matrix0): sage: a = matrix(R,2,[x+1,2/3, x^2/2, 1+x^3]); a [ x + 1 2/3] [1/2*x^2 x^3 + 1] - sage: b = pari(a); b # indirect doctest + sage: b = pari(a); b # indirect doctest # needs sage.libs.pari [x + 1, 2/3; 1/2*x^2, x^3 + 1] sage: a.determinant() x^4 + x^3 - 1/3*x^2 + x + 1 - sage: b.matdet() + sage: b.matdet() # needs sage.libs.pari x^4 + x^3 - 1/3*x^2 + x + 1 This function preserves precision for entries of inexact type (e.g. @@ -83,7 +83,7 @@ cdef class Matrix(Matrix0): sage: a = matrix(R, 2, [1, 2, 3, 1]); a [1.0 2.0] [3.0 1.0] - sage: b = pari(a); b + sage: b = pari(a); b # needs sage.libs.pari [1.000000000, 2.000000000; 3.000000000, 1.000000000] # 32-bit [1.00000000000000, 2.00000000000000; 3.00000000000000, 1.00000000000000] # 64-bit """ @@ -96,8 +96,9 @@ cdef class Matrix(Matrix0): EXAMPLES:: + sage: # needs sage.libs.gap sage: A = MatrixSpace(QQ,3,3)([0,1,2,3,4,5,6,7,8]) - sage: g = gap(A) # indirect doctest + sage: g = gap(A) # indirect doctest sage: g [ [ 0, 1, 2 ], [ 3, 4, 5 ], [ 6, 7, 8 ] ] sage: g.CharacteristicPolynomial() @@ -110,8 +111,9 @@ cdef class Matrix(Matrix0): Particularly difficult is the case of matrices over cyclotomic fields and general number fields. See :trac:`5618` and :trac:`8909`:: + sage: # needs sage.libs.gap sage.rings.number_field sage: K.<zeta> = CyclotomicField(8) - sage: A = MatrixSpace(K,2,2)([0,1+zeta,2*zeta,3]) + sage: A = MatrixSpace(K, 2, 2)([0, 1+zeta, 2*zeta, 3]) sage: g = gap(A); g [ [ 0, 1+E(8) ], [ 2*E(8), 3 ] ] sage: matrix(K, g) == A @@ -119,8 +121,10 @@ cdef class Matrix(Matrix0): sage: g.IsMatrix() true - sage: L.<tau> = NumberField(x^3-2) - sage: A = MatrixSpace(L,2,2)([0,1+tau,2*tau,3]) + sage: # needs sage.libs.gap sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: L.<tau> = NumberField(x^3 - 2) + sage: A = MatrixSpace(L, 2, 2)([0, 1+tau, 2*tau, 3]) sage: g = gap(A); g [ [ !0, tau+1 ], [ 2*tau, !3 ] ] sage: matrix(L, g) == A @@ -152,9 +156,9 @@ cdef class Matrix(Matrix0): EXAMPLES:: - sage: libgap(identity_matrix(ZZ,2)) + sage: libgap(identity_matrix(ZZ, 2)) # needs sage.libs.gap [ [ 1, 0 ], [ 0, 1 ] ] - sage: libgap(matrix(GF(3),2,2,[4,5,6,7])) + sage: libgap(matrix(GF(3), 2, 2, [4,5,6,7])) # needs sage.libs.gap [ [ Z(3)^0, Z(3) ], [ 0*Z(3), Z(3)^0 ] ] """ from sage.libs.gap.libgap import libgap @@ -191,9 +195,9 @@ cdef class Matrix(Matrix0): :: - sage: y = var('y') - sage: M = matrix(SR, 2, [y+sin(y), y - 4, 1/y, dilog(y)]) - sage: M == fricas(M).sage() # optional - fricas + sage: y = var('y') # needs sage.symbolic + sage: M = matrix(SR, 2, [y+sin(y), y - 4, 1/y, dilog(y)]) # needs sage.symbolic + sage: M == fricas(M).sage() # optional - fricas # needs sage.symbolic True """ s = ','.join('[' + ','.join(cf._fricas_init_() for cf in row) + ']' @@ -211,22 +215,22 @@ cdef class Matrix(Matrix0): EXAMPLES:: - sage: M = matrix(ZZ,2,range(4)) - sage: giac(M) + sage: M = matrix(ZZ, 2, range(4)) + sage: giac(M) # needs sage.libs.giac [[0,1],[2,3]] - sage: M = matrix(QQ,3,[1,2,3,4/3,5/3,6/4,7,8,9]) - sage: giac(M) + sage: M = matrix(QQ, 3, [1,2,3, 4/3,5/3,6/4, 7,8,9]) + sage: giac(M) # needs sage.libs.giac [[1,2,3],[4/3,5/3,3/2],[7,8,9]] sage: P.<x> = ZZ[] sage: M = matrix(P, 2, [-9*x^2-2*x+2, x-1, x^2+8*x, -3*x^2+5]) - sage: giac(M) + sage: giac(M) # needs sage.libs.giac [[-9*sageVARx^2-2*sageVARx+2,sageVARx-1],[sageVARx^2+8*sageVARx,-3*sageVARx^2+5]] - sage: y = var('y') - sage: M = matrix(SR, 2, [y+sin(y), y - 4, 1/y, dilog(y)]) - sage: giac(M).det().sage() + sage: y = var('y') # needs sage.symbolic + sage: M = matrix(SR, 2, [y+sin(y), y - 4, 1/y, dilog(y)]) # needs sage.symbolic + sage: giac(M).det().sage() # needs sage.libs.giac sage.symbolic (y^2*dilog(y) + y*dilog(y)*sin(y) - y + 4)/y """ s = ','.join('[' + ','.join(cf._giac_init_() for cf in row) + ']' @@ -243,12 +247,12 @@ cdef class Matrix(Matrix0): [0 1 2] [3 4 5] [6 7 8] - sage: m._maxima_init_() + sage: m._maxima_init_() # needs sage.symbolic 'matrix([0,1,2],[3,4,5],[6,7,8])' - sage: a = maxima(m); a + sage: a = maxima(m); a # needs sage.symbolic matrix([0,1,2],[3,4,5],[6,7,8]) - sage: a.charpoly('x').expand() - (-x^3)+12*x^2+18*x + sage: a.charpoly('x').expand() # needs sage.symbolic + ...-x^3...+12*x^2+18*x sage: m.charpoly() x^3 - 12*x^2 - 18*x """ @@ -270,7 +274,7 @@ cdef class Matrix(Matrix0): sage: A = MatrixSpace(QQ,3)([1,2,3,4/3,5/3,6/4,7,8,9]) sage: g = mathematica(A); g # optional - mathematica {{1, 2, 3}, {4/3, 5/3, 3/2}, {7, 8, 9}} - sage: A._mathematica_init_() + sage: A._mathematica_init_() # needs sage.symbolic '{{1/1, 2/1, 3/1}, {4/3, 5/3, 3/2}, {7/1, 8/1, 9/1}}' :: @@ -281,10 +285,10 @@ cdef class Matrix(Matrix0): :: - sage: a = matrix([[pi, sin(x)], [cos(x), 1/e]]); a + sage: a = matrix([[pi, sin(x)], [cos(x), 1/e]]); a # needs sage.symbolic [ pi sin(x)] [cos(x) e^(-1)] - sage: a._mathematica_init_() + sage: a._mathematica_init_() # needs sage.symbolic '{{Pi, Sin[x]}, {Cos[x], Exp[-1]}}' """ return '{' + ', '.join([v._mathematica_init_() for v in self.rows()]) + '}' @@ -298,26 +302,28 @@ cdef class Matrix(Matrix0): We first coerce a square matrix. :: + sage: # optional - magma sage: A = MatrixSpace(QQ,3)([1,2,3,4/3,5/3,6/4,7,8,9]) - sage: B = magma(A); B # (indirect doctest) optional - magma + sage: B = magma(A); B # indirect doctest [ 1 2 3] [4/3 5/3 3/2] [ 7 8 9] - sage: B.Type() # optional - magma + sage: B.Type() AlgMatElt - sage: B.Parent() # optional - magma + sage: B.Parent() Full Matrix Algebra of degree 3 over Rational Field We coerce a non-square matrix over `\ZZ/8\ZZ`. :: + sage: # optional - magma sage: A = MatrixSpace(Integers(8),2,3)([-1,2,3,4,4,-2]) - sage: B = magma(A); B # optional - magma + sage: B = magma(A); B [7 2 3] [4 4 6] - sage: B.Type() # optional - magma + sage: B.Type() ModMatRngElt - sage: B.Parent() # optional - magma + sage: B.Parent() Full RMatrixSpace of 2 by 3 matrices over IntegerRing(8) sage: R.<x,y> = QQ[] @@ -335,17 +341,17 @@ cdef class Matrix(Matrix0): We coerce a matrix over a cyclotomic field, where the generator must be named during the coercion. :: - sage: K = CyclotomicField(9) ; z = K.0 - sage: M = matrix(K,3,3,[0,1,3,z,z**4,z-1,z**17,1,0]) - sage: M + sage: # optional - magma, needs sage.rings.number_field + sage: K = CyclotomicField(9); z = K.0 + sage: M = matrix(K, 3, 3, [0,1,3,z,z**4,z-1,z**17,1,0]); M [ 0 1 3] [ zeta9 zeta9^4 zeta9 - 1] [-zeta9^5 - zeta9^2 1 0] - sage: magma(M) # optional - magma + sage: magma(M) [ 0 1 3] [ zeta9 zeta9^4 zeta9 - 1] [-zeta9^5 - zeta9^2 1 0] - sage: magma(M**2) == magma(M)**2 # optional - magma + sage: magma(M**2) == magma(M)**2 True One sparse matrix:: @@ -388,9 +394,9 @@ cdef class Matrix(Matrix0): sage: maple(M) # optional - maple Matrix(2, 2, [[-9*x^2-2*x+2,x-1],[x^2+8*x,-3*x^2+5]]) - sage: y = var('y') - sage: M = matrix(SR, 2, [y+sin(y), y - 4, 1/y, dilog(y)]) - sage: M == maple(M).sage() # optional - maple + sage: y = var('y') # needs sage.symbolic + sage: M = matrix(SR, 2, [y+sin(y), y - 4, 1/y, dilog(y)]) # needs sage.symbolic + sage: M == maple(M).sage() # optional - maple # needs sage.symbolic True """ s = ','.join('[' + ','.join(cf._maple_init_() for cf in row) + ']' @@ -404,12 +410,12 @@ cdef class Matrix(Matrix0): EXAMPLES:: sage: M = matrix(ZZ,2,range(4)) - sage: polymake(M) # optional - jupymake + sage: polymake(M) # optional - jupymake 0 1 2 3 - sage: K.<sqrt5> = QuadraticField(5) - sage: M = matrix(K, [[1, 2], [sqrt5, 3]]) - sage: polymake(M) # optional - jupymake + sage: K.<sqrt5> = QuadraticField(5) # needs sage.rings.number_field + sage: M = matrix(K, [[1, 2], [sqrt5, 3]]) # needs sage.rings.number_field + sage: polymake(M) # optional - jupymake # needs sage.rings.number_field 1 2 0+1r5 3 """ @@ -435,7 +441,7 @@ cdef class Matrix(Matrix0): EXAMPLES:: sage: m = matrix(ZZ, [[1,2],[3,4]]) - sage: macaulay2(m) #optional - macaulay2 (indirect doctest) + sage: macaulay2(m) # indirect doctest # optional - macaulay2 | 1 2 | | 3 4 | @@ -443,7 +449,7 @@ cdef class Matrix(Matrix0): sage: R.<x,y> = QQ[] sage: m = matrix([[x,y],[1+x,1+y]]) - sage: macaulay2(m) #optional - macaulay2 + sage: macaulay2(m) # optional - macaulay2 | x y | | x+1 y+1 | @@ -459,9 +465,9 @@ cdef class Matrix(Matrix0): Check that degenerate matrix dimensions are handled correctly (:trac:`28591`):: - sage: macaulay2(matrix(QQ, 2, 0)).numrows() # optional - macaulay2 + sage: macaulay2(matrix(QQ, 2, 0)).numrows() # optional - macaulay2 2 - sage: macaulay2(matrix(QQ, 0, 2)).numcols() # optional - macaulay2 + sage: macaulay2(matrix(QQ, 0, 2)).numcols() # optional - macaulay2 2 """ if macaulay2 is None: @@ -484,7 +490,7 @@ cdef class Matrix(Matrix0): [1 2 3] [4 5 6] [7 8 9] - sage: a._scilab_init_() + sage: a._scilab_init_() # needs sage.libs.pari '[1,2,3;4,5,6;7,8,9]' AUTHORS: @@ -513,7 +519,7 @@ cdef class Matrix(Matrix0): [1 2 3] [4 5 6] [7 8 9] - sage: b = scilab(a); b # optional - scilab (indirect doctest) + sage: b = scilab(a); b # indirect doctest # optional - scilab 1. 2. 3. 4. 5. 6. 7. 8. 9. @@ -539,41 +545,42 @@ cdef class Matrix(Matrix0): [1 2 3] [4 5 6] [7 8 9] - sage: sA = A._sympy_(); sA + sage: sA = A._sympy_(); sA # needs sympy Matrix([ [1, 2, 3], [4, 5, 6], [7, 8, 9]]) - sage: type(sA) + sage: type(sA) # needs sympy <class 'sympy.matrices.immutable.ImmutableDenseMatrix'> sage: I = MatrixSpace(QQ, 5, 5, sparse=True).identity_matrix() - sage: sI = I._sympy_(); sI + sage: sI = I._sympy_(); sI # needs sympy Matrix([ [1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]]) - sage: type(sI) + sage: type(sI) # needs sympy <class 'sympy.matrices.immutable.ImmutableSparseMatrix'> If ``self`` was immutable, then converting the result to Sage gives back ``self``:: sage: immA = matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]], immutable=True) - sage: immA._sympy_()._sage_() is immA + sage: immA._sympy_()._sage_() is immA # needs sympy True If ``self`` was mutable, then converting back to Sage creates a new matrix:: - sage: sA._sage_() is A + sage: sA._sage_() is A # needs sympy sage.symbolic False - sage: sA._sage_() == A + sage: sA._sage_() == A # needs sympy sage.symbolic True Symbolic matrices are supported:: + sage: # needs sympy sage.symbolic sage: M = matrix([[sin(x), cos(x)], [-cos(x), sin(x)]]); M [ sin(x) cos(x)] [-cos(x) sin(x)] @@ -592,12 +599,12 @@ cdef class Matrix(Matrix0): sage: ZeroCol = matrix(QQ, 3, 0, sparse=False); ZeroCol [] - sage: sZeroCol = ZeroCol._sympy_(); sZeroCol + sage: sZeroCol = ZeroCol._sympy_(); sZeroCol # needs sympy Matrix(3, 0, []) sage: ZeroRow = matrix(QQ, 0, 2, sparse=False); ZeroRow [] - sage: sZeroRow = ZeroRow._sympy_(); sZeroRow + sage: sZeroRow = ZeroRow._sympy_(); sZeroRow # needs sympy Matrix(0, 2, []) """ @@ -677,7 +684,8 @@ cdef class Matrix(Matrix0): EXAMPLES:: - sage: a = matrix(3,range(12)) + sage: # needs numpy + sage: a = matrix(3, range(12)) sage: a.numpy() array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], @@ -698,16 +706,20 @@ cdef class Matrix(Matrix0): Type ``numpy.typecodes`` for a list of the possible typecodes:: - sage: import numpy - sage: sorted(numpy.typecodes.items()) - [('All', '?bhilqpBHILQPefdgFDGSUVOMm'), ('AllFloat', 'efdgFDG'), ('AllInteger', 'bBhHiIlLqQpP'), ('Character', 'c'), ('Complex', 'FDG'), ('Datetime', 'Mm'), ('Float', 'efdg'), ('Integer', 'bhilqp'), ('UnsignedInteger', 'BHILQP')] + sage: import numpy # needs numpy + sage: sorted(numpy.typecodes.items()) # needs numpy + [('All', '?bhilqpBHILQPefdgFDGSUVOMm'), ('AllFloat', 'efdgFDG'), + ('AllInteger', 'bBhHiIlLqQpP'), ('Character', 'c'), ('Complex', 'FDG'), + ('Datetime', 'Mm'), ('Float', 'efdg'), ('Integer', 'bhilqp'), + ('UnsignedInteger', 'BHILQP')] Alternatively, numpy automatically calls this function (via the magic :meth:`__array__` method) to convert Sage matrices to numpy arrays:: + sage: # needs numpy sage: import numpy - sage: b=numpy.array(a); b + sage: b = numpy.array(a); b array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) @@ -756,7 +768,7 @@ cdef class Matrix(Matrix0): EXAMPLES:: - sage: M = Matrix(Integers(7), 2, 2, [5, 9, 13, 15]) ; M + sage: M = Matrix(Integers(7), 2, 2, [5, 9, 13, 15]); M [5 2] [6 1] sage: M.lift() @@ -800,7 +812,7 @@ cdef class Matrix(Matrix0): EXAMPLES:: - sage: M = Matrix(Integers(8), 2, 4, range(8)) ; M + sage: M = Matrix(Integers(8), 2, 4, range(8)); M [0 1 2 3] [4 5 6 7] sage: L = M.lift_centered(); L @@ -972,14 +984,14 @@ cdef class Matrix(Matrix0): sage: matrix(3, [1..9]).columns() [(1, 4, 7), (2, 5, 8), (3, 6, 9)] - sage: matrix(RR, 2, [sqrt(2), pi, exp(1), 0]).columns() + sage: matrix(RR, 2, [sqrt(2), pi, exp(1), 0]).columns() # needs sage.symbolic [(1.41421356237310, 2.71828182845905), (3.14159265358979, 0.000000000000000)] sage: matrix(RR, 0, 2, []).columns() [(), ()] sage: matrix(RR, 2, 0, []).columns() [] - sage: m = matrix(RR, 3, 3, {(1,2): pi, (2, 2): -1, (0,1): sqrt(2)}) - sage: parent(m.columns()[0]) + sage: m = matrix(RR, 3, 3, {(1,2): pi, (2, 2): -1, (0,1): sqrt(2)}) # needs sage.symbolic + sage: parent(m.columns()[0]) # needs sage.symbolic Sparse vector space of dimension 3 over Real Field with 53 bits of precision Sparse matrices produce sparse columns. :: @@ -1028,14 +1040,14 @@ cdef class Matrix(Matrix0): sage: matrix(3, [1..9]).rows() [(1, 2, 3), (4, 5, 6), (7, 8, 9)] - sage: matrix(RR, 2, [sqrt(2), pi, exp(1), 0]).rows() + sage: matrix(RR, 2, [sqrt(2), pi, exp(1), 0]).rows() # needs sage.symbolic [(1.41421356237310, 3.14159265358979), (2.71828182845905, 0.000000000000000)] sage: matrix(RR, 0, 2, []).rows() [] sage: matrix(RR, 2, 0, []).rows() [(), ()] - sage: m = matrix(RR, 3, 3, {(1,2): pi, (2, 2): -1, (0,1): sqrt(2)}) - sage: parent(m.rows()[0]) + sage: m = matrix(RR, 3, 3, {(1,2): pi, (2, 2): -1, (0,1): sqrt(2)}) # needs sage.symbolic + sage: parent(m.rows()[0]) # needs sage.symbolic Sparse vector space of dimension 3 over Real Field with 53 bits of precision Sparse matrices produce sparse rows. :: @@ -1100,7 +1112,8 @@ cdef class Matrix(Matrix0): sage: c = a.dense_columns(); c [(x, 2/3*x), (x^2, x^5 + 1)] sage: parent(c[1]) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field + Ambient free module of rank 2 over the principal ideal domain + Univariate Polynomial Ring in x over Rational Field TESTS: @@ -1460,10 +1473,10 @@ cdef class Matrix(Matrix0): tmp = [self.get_unsafe(i,j) for j in range(self._ncols)] return V(tmp, coerce=False, copy=False, check=False) - ########################################################################### # Building matrices out of other matrices, rows, or columns ########################################################################### + def stack(self, bottom, subdivide=False): r""" Return a new matrix formed by appending the matrix (or vector) @@ -1614,13 +1627,15 @@ cdef class Matrix(Matrix0): [ 1.00000000000000 2.00000000000000] [0.891207360061435 0.808496403819590] sage: C.parent() - Full MatrixSpace of 2 by 2 dense matrices over Real Field with 53 bits of precision + Full MatrixSpace of 2 by 2 dense matrices + over Real Field with 53 bits of precision sage: D = B.stack(A); D [0.891207360061435 0.808496403819590] [ 1.00000000000000 2.00000000000000] sage: D.parent() - Full MatrixSpace of 2 by 2 dense matrices over Real Field with 53 bits of precision + Full MatrixSpace of 2 by 2 dense matrices + over Real Field with 53 bits of precision :: @@ -1632,7 +1647,8 @@ cdef class Matrix(Matrix0): [ 1 2/3] [ y y^2] sage: C.parent() - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Rational Field Stacking a dense matrix atop a sparse one returns a sparse matrix:: @@ -1878,17 +1894,18 @@ cdef class Matrix(Matrix0): sage: A = matrix(QQ, 2, [1,2]) sage: B = matrix(RR, 2, [sin(1.1), sin(2.2)]) - sage: C = A.augment(B); C + sage: C = A.augment(B); C # needs sage.symbolic [ 1 183017397/205358938] [ 2 106580492/131825561] - sage: C.parent() + sage: C.parent() # needs sage.symbolic Full MatrixSpace of 2 by 2 dense matrices over Rational Field sage: D = B.augment(A); D [0.89120736006... 1.00000000000000] [0.80849640381... 2.00000000000000] sage: D.parent() - Full MatrixSpace of 2 by 2 dense matrices over Real Field with 53 bits of precision + Full MatrixSpace of 2 by 2 dense matrices + over Real Field with 53 bits of precision Sometimes it is not possible to coerce into the base ring of ``self``. A solution is to change the base ring of ``self`` to @@ -1902,7 +1919,8 @@ cdef class Matrix(Matrix0): sage: C = B.augment(A); C [ y y^2 1 2] sage: C.parent() - Full MatrixSpace of 1 by 4 dense matrices over Univariate Polynomial Ring in y over Rational Field + Full MatrixSpace of 1 by 4 dense matrices over + Univariate Polynomial Ring in y over Rational Field sage: D = A.augment(B) Traceback (most recent call last): @@ -1913,7 +1931,8 @@ cdef class Matrix(Matrix0): sage: F = E.augment(B); F [ 1 2 y y^2] sage: F.parent() - Full MatrixSpace of 1 by 4 dense matrices over Univariate Polynomial Ring in y over Rational Field + Full MatrixSpace of 1 by 4 dense matrices over + Univariate Polynomial Ring in y over Rational Field AUTHORS: @@ -2089,8 +2108,8 @@ cdef class Matrix(Matrix0): INPUT: - * ``drows`` - list of indices of rows to be deleted from self. - * ``check`` - checks whether any index in ``drows`` is out of range. Defaults to ``True``. + * ``drows`` -- list of indices of rows to be deleted from ``self``. + * ``check`` -- (boolean, default: ``True``); whether to check if any index in ``drows`` is out of range. .. SEEALSO:: @@ -2152,7 +2171,7 @@ cdef class Matrix(Matrix0): def matrix_from_rows_and_columns(self, rows, columns): """ - Return the matrix constructed from self from the given rows and + Return the matrix constructed from ``self`` from the given rows and columns. EXAMPLES:: @@ -2175,9 +2194,7 @@ cdef class Matrix(Matrix0): [5 4] For example here we take from row 1 columns 2 then 0 twice, and do - this 3 times. - - :: + this 3 times:: sage: A.matrix_from_rows_and_columns([1,1,1],[2,0,0]) [5 3 3] @@ -2465,16 +2482,17 @@ cdef class Matrix(Matrix0): :: - sage: W.<a> = CyclotomicField(100) - sage: M = Matrix(2, 3, [a, a/2, 0, a^2, a^100-1, a^2 - a]); M + sage: W.<a> = CyclotomicField(100) # needs sage.rings.number_field + sage: M = Matrix(2, 3, [a, a/2, 0, a^2, a^100-1, a^2 - a]); M # needs sage.rings.number_field [ a 1/2*a 0] [ a^2 0 a^2 - a] - sage: M.zero_pattern_matrix() + sage: M.zero_pattern_matrix() # needs sage.rings.number_field [0 0 1] [0 1 0] :: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(2^4) sage: l = [a^2 + 1, a^3 + 1, 0, 0, a, a^3 + a + 1, a + 1, ....: a + 1, a^2, a^3 + a + 1, a^3 + a, a^3 + a] @@ -2489,6 +2507,7 @@ cdef class Matrix(Matrix0): :: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(25) sage: M = Matrix(K, 2, 3, [0, 2, 3, 5, a, a^2]) sage: M @@ -2520,10 +2539,9 @@ cdef class Matrix(Matrix0): M.set_unsafe(i, j, one) return M - - #################################################################################### + ###################################################################### # Change of representation between dense and sparse. - #################################################################################### + ###################################################################### def dense_matrix(self): """ @@ -2581,7 +2599,7 @@ cdef class Matrix(Matrix0): dict items are ETuples (see :trac:`17658`):: sage: from sage.rings.polynomial.polydict import ETuple - sage: matrix(GF(5^2,"z"),{ETuple((1, 1)): 2}).dense_matrix() + sage: matrix(GF(5^2, "z"), {ETuple((1, 1)): 2}).dense_matrix() # needs sage.rings.finite_rings [0 0] [0 2] """ diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index ab96459e66e..86aca6e00d8 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -79,18 +79,20 @@ AUTHORS: from cpython cimport * from cysignals.signals cimport sig_check -from sage.misc.randstate cimport randstate, current_randstate +from sage.misc.lazy_string import lazy_string +from sage.misc.randstate cimport current_randstate from sage.structure.coerce cimport py_scalar_parent from sage.structure.sequence import Sequence from sage.structure.coerce cimport coercion_model from sage.structure.element import is_Vector from sage.structure.element cimport have_same_parent -from sage.misc.verbose import verbose, get_verbose -from sage.categories.all import Fields, IntegralDomains +from sage.misc.verbose import verbose +from sage.categories.fields import Fields +from sage.categories.integral_domains import IntegralDomains +from sage.categories.principal_ideal_domains import PrincipalIdealDomains from sage.rings.ring import is_Ring -from sage.rings.number_field.number_field_base import is_NumberField +from sage.rings.number_field.number_field_base import NumberField from sage.rings.integer_ring import ZZ, is_IntegerRing -from sage.rings.integer import Integer from sage.rings.rational_field import QQ, is_RationalField import sage.rings.abc from sage.arith.numerical_approx cimport digits_to_bits @@ -101,11 +103,22 @@ from . import berlekamp_massey from sage.modules.free_module_element import is_FreeModuleElement from sage.matrix.matrix_misc import permanental_minor_polynomial +from sage.misc.misc_c import prod + # used to deprecate only adjoint method from sage.misc.superseded import deprecated_function_alias + +# temporary hack to silence the warnings from #34806 +def ideal_or_fractional(R, *args): + if isinstance(R, sage.rings.abc.Order): + R = R.number_field() + return R.ideal(*args) + + _Fields = Fields() + cdef class Matrix(Matrix1): """ Base class for matrices, part 2 @@ -159,6 +172,7 @@ cdef class Matrix(Matrix1): EXAMPLES:: + sage: # needs sage.symbolic sage: var('a,b,d,e') (a, b, d, e) sage: m = matrix([[a,b], [d,e]]) @@ -168,7 +182,7 @@ cdef class Matrix(Matrix1): sage: m.subs(a=b, b=d) [b d] [d e] - sage: m.subs({a: 3, b:2, d:1, e:-1}) + sage: m.subs({a: 3, b: 2, d: 1, e: -1}) [ 3 2] [ 1 -1] @@ -339,6 +353,8 @@ cdef class Matrix(Matrix1): True sage: X (-1, 2, 0, 0) + + sage: # needs sage.libs.pari sage: A = Matrix(Zmod(128), 2, 3, [5, 29, 33, 64, 0, 7]) sage: B = vector(Zmod(128), [31,39,56]) sage: X = A.solve_left(B); X @@ -383,6 +399,7 @@ cdef class Matrix(Matrix1): The vector of constants needs to be compatible with the base ring of the coefficient matrix:: + sage: # needs sage.rings.finite_rings sage: F.<a> = FiniteField(27) sage: b = vector(F, [a,a,a,a,a]) sage: A.solve_left(b) @@ -404,9 +421,9 @@ cdef class Matrix(Matrix1): any are inexact, however, the ``check`` is still skipped (:trac:`29729` and :trac:`33159`):: - sage: A = matrix(SR, [[1, 1]]) # optional - sage.symbolic - sage: b = vector(SR, [2, 3]) # optional - sage.symbolic - sage: A.solve_left(b) # optional - sage.symbolic + sage: A = matrix(SR, [[1, 1]]) # needs sage.symbolic + sage: b = vector(SR, [2, 3]) # needs sage.symbolic + sage: A.solve_left(b) # needs sage.symbolic Traceback (most recent call last): ... ValueError: matrix equation has no solutions @@ -414,7 +431,7 @@ cdef class Matrix(Matrix1): In this case, turning off the ``check`` leads to a wrong result:: - sage: A.solve_left(b, check=False) # optional - sage.symbolic + sage: A.solve_left(b, check=False) # needs sage.symbolic (2) """ @@ -422,12 +439,12 @@ cdef class Matrix(Matrix1): try: return self.transpose().solve_right(B, check=check) except ValueError as e: - raise ValueError(str(e).replace('row', 'column')) + raise e.__class__(str(e).replace('row', 'column')) else: try: return self.transpose().solve_right(B.transpose(), check=check).transpose() except ValueError as e: - raise ValueError(str(e).replace('row', 'column')) + raise e.__class__(str(e).replace('row', 'column')) def solve_right(self, B, check=True): r""" @@ -527,7 +544,7 @@ cdef class Matrix(Matrix1): ... ValueError: matrix equation has no solutions - A ValueError is raised if the input is invalid:: + A :class:`ValueError` is raised if the input is invalid:: sage: A = matrix(QQ,4,2, [0, -1, 1, 0, -2, 2, 1, 0]) sage: B = matrix(QQ,2,2, [1, 0, 1, -1]) @@ -584,6 +601,7 @@ cdef class Matrix(Matrix1): Solving some systems over `\ZZ/n\ZZ`:: + sage: # needs sage.libs.pari sage: A = Matrix(Zmod(6), 3, 2, [1,2,3,4,5,6]) sage: B = vector(Zmod(6), [1,1,1]) sage: A.solve_right(B) @@ -610,8 +628,9 @@ cdef class Matrix(Matrix1): Solving a system over the p-adics:: - sage: k = Qp(5,4) - sage: a = matrix(k, 3, [1,7,3,2,5,4,1,1,2]); a + sage: # needs sage.rings.padics + sage: k = Qp(5, 4) + sage: a = matrix(k, 3, [1,7,3, 2,5,4, 1,1,2]); a [ 1 + O(5^4) 2 + 5 + O(5^4) 3 + O(5^4)] [ 2 + O(5^4) 5 + O(5^5) 4 + O(5^4)] [ 1 + O(5^4) 1 + O(5^4) 2 + O(5^4)] @@ -624,20 +643,21 @@ cdef class Matrix(Matrix1): Solving a system of linear equations symbolically using symbolic matrices:: - sage: var('a,b,c,d,x,y') # optional - sage.symbolic + sage: # needs sage.symbolic + sage: var('a,b,c,d,x,y') (a, b, c, d, x, y) - sage: A = matrix(SR, 2, [a,b,c,d]); A # optional - sage.symbolic + sage: A = matrix(SR, 2, [a,b,c,d]); A [a b] [c d] - sage: result = vector(SR, [3,5]); result # optional - sage.symbolic + sage: result = vector(SR, [3,5]); result (3, 5) - sage: soln = A.solve_right(result); soln # optional - sage.symbolic + sage: soln = A.solve_right(result); soln (-b*(3*c/a - 5)/(a*(b*c/a - d)) + 3/a, (3*c/a - 5)/(b*c/a - d)) - sage: (a*x+b*y).subs(x=soln[0], y=soln[1]).simplify_full() # optional - sage.symbolic + sage: (a*x + b*y).subs(x=soln[0], y=soln[1]).simplify_full() 3 - sage: (c*x+d*y).subs(x=soln[0], y=soln[1]).simplify_full() # optional - sage.symbolic + sage: (c*x + d*y).subs(x=soln[0], y=soln[1]).simplify_full() 5 - sage: (A*soln).apply_map(lambda x: x.simplify_full()) # optional - sage.symbolic + sage: (A*soln).apply_map(lambda x: x.simplify_full()) (3, 5) Over inexact rings, the output of this function may not be an exact @@ -712,8 +732,8 @@ cdef class Matrix(Matrix1): (:trac:`12406`):: sage: A = matrix(QQ, 2, [1, 2, 3, 4]) - sage: b = vector(RDF, [pi, e]) - sage: A.solve_right(b) # tol 1e-15 + sage: b = vector(RDF, [pi, e]) # needs sage.symbolic + sage: A.solve_right(b) # tol 1e-15 # needs sage.symbolic (-3.564903478720541, 3.353248066155167) sage: R.<t> = ZZ[] sage: b = vector(R, [1, t]) @@ -728,7 +748,7 @@ cdef class Matrix(Matrix1): sage: A = Matrix(Zmod(6), 3, 2, [1,2,3,4,5,6]) sage: b = vector(ZZ, [1,1,1]) - sage: A.solve_right(b).base_ring() is Zmod(6) + sage: A.solve_right(b).base_ring() is Zmod(6) # needs sage.libs.pari True Check that the coercion mechanism gives consistent results @@ -769,9 +789,9 @@ cdef class Matrix(Matrix1): The vector of constants needs to be compatible with the base ring of the coefficient matrix. :: - sage: F.<a> = FiniteField(27) - sage: b = vector(F, [a,a,a,a,a]) - sage: A.solve_right(b) + sage: F.<a> = FiniteField(27) # needs sage.rings.finite_rings + sage: b = vector(F, [a,a,a,a,a]) # needs sage.rings.finite_rings + sage: A.solve_right(b) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: ... @@ -807,31 +827,32 @@ cdef class Matrix(Matrix1): any are inexact, however, the ``check`` is still skipped (:trac:`29729` and :trac:`33159`):: - sage: m = matrix(SR, [0]) # optional - sage.symbolic - sage: b = vector(SR, [1]) # optional - sage.symbolic - sage: m.solve_right(b, check=True) # optional - sage.symbolic + sage: m = matrix(SR, [0]) # needs sage.symbolic + sage: b = vector(SR, [1]) # needs sage.symbolic + sage: m.solve_right(b, check=True) # needs sage.symbolic Traceback (most recent call last): ... ValueError: matrix equation has no solutions In this case, turning off the ``check`` leads to a wrong result:: - sage: m.solve_right(b, check=False) # optional - sage.symbolic + sage: m.solve_right(b, check=False) # needs sage.symbolic (0) In the following, we have an inexact entry in the matrix, so the ``check`` is still skipped leading to a wrong result:: - sage: m = matrix(SR, [0.0]) # optional - sage.symbolic - sage: m.solve_right(b, check=True) # optional - sage.symbolic + sage: m = matrix(SR, [0.0]) # needs sage.symbolic + sage: m.solve_right(b, check=True) # needs sage.symbolic (0) :: - sage: SC = SR.subring(no_variables=True) # optional - sage.symbolic - sage: m = matrix(SC, [0]) # optional - sage.symbolic - sage: b = vector(SC, [1]) # optional - sage.symbolic - sage: m.solve_right(b) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: SC = SR.subring(no_variables=True) + sage: m = matrix(SC, [0]) + sage: b = vector(SC, [1]) + sage: m.solve_right(b) Traceback (most recent call last): ... ValueError: matrix equation has no solutions @@ -1111,6 +1132,7 @@ cdef class Matrix(Matrix1): Notice the base ring of the results in the next two examples. :: + sage: x = polygen(ZZ, 'x') sage: D = matrix(ZZ['x'],2,[1+x^2,2,3,4-x]) sage: E = matrix(QQ,2,[1,2,3,4]) sage: F = D.elementwise_product(E) @@ -1122,17 +1144,19 @@ cdef class Matrix(Matrix1): :: - sage: G = matrix(GF(3),2,[0,1,2,2]) - sage: H = matrix(ZZ,2,[1,2,3,4]) + sage: G = matrix(GF(3), 2, [0, 1, 2, 2]) + sage: H = matrix(ZZ, 2, [1, 2, 3, 4]) sage: J = G.elementwise_product(H) sage: J [0 2] [0 2] sage: J.parent() - Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 3 + Full MatrixSpace of 2 by 2 dense matrices + over Finite Field of size 3 Non-commutative rings behave as expected. These are the usual quaternions. :: + sage: # needs sage.combinat sage: R.<i,j,k> = QuaternionAlgebra(-1, -1) sage: A = matrix(R, 2, [1,i,j,k]) sage: B = matrix(R, 2, [i,i,i,i]) @@ -1174,7 +1198,9 @@ cdef class Matrix(Matrix1): sage: A.elementwise_product(B) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Full MatrixSpace of 3 by 2 dense matrices over Rational Field' and 'Full MatrixSpace of 3 by 2 dense matrices over Finite Field of size 3' + TypeError: no common canonical parent for objects with parents: + 'Full MatrixSpace of 3 by 2 dense matrices over Rational Field' and + 'Full MatrixSpace of 3 by 2 dense matrices over Finite Field of size 3' We illustrate various combinations of sparse and dense matrices. The usual coercion rules apply:: @@ -1542,14 +1568,15 @@ cdef class Matrix(Matrix1): sage: Mx = M.pseudoinverse(algorithm="exact") sage: (Mx*M).norm() # huge error 11.5... - sage: Mx = M.pseudoinverse(algorithm="numpy") - sage: (Mx*M).norm() # still OK + sage: Mx = M.pseudoinverse(algorithm="numpy") # needs numpy + sage: (Mx * M).norm() # still OK 1.00... When multiplying the given matrix with the pseudoinverse, the result is symmetric for the ``exact`` algorithm or hermitian for the ``exactconj`` algorithm:: + sage: # needs sage.rings.number_field sage.symbolic sage: M = matrix(QQbar, 2, 2, [1, sqrt(-3), -sqrt(-3), 3]) sage: M * M.pseudoinverse() [ 0.2500000000000000? 0.4330127018922193?*I] @@ -1574,13 +1601,13 @@ cdef class Matrix(Matrix1): Numpy gives a strange answer due to rounding errors:: - sage: M.pseudoinverse(algorithm="numpy") # random + sage: M.pseudoinverse(algorithm="numpy") # random # needs numpy [-1286742750677287/643371375338643 1000799917193445/1000799917193444] [ 519646110850445/346430740566963 -300239975158034/600479950316067] Although it is not too far off:: - sage: (~M-M.pseudoinverse(algorithm="numpy")).norm() < 1e-14 + sage: (~M - M.pseudoinverse(algorithm="numpy")).norm() < 1e-14 # needs numpy True TESTS:: @@ -1696,7 +1723,7 @@ cdef class Matrix(Matrix1): These numbers are the coefficients of a modified Laguerre polynomial:: sage: x = polygen(QQ) - sage: factorial(8) * laguerre(8,-x) + sage: factorial(8) * laguerre(8,-x) # needs sage.symbolic x^8 + 64*x^7 + 1568*x^6 + 18816*x^5 + 117600*x^4 + 376320*x^3 + 564480*x^2 + 322560*x + 40320 @@ -1707,7 +1734,7 @@ cdef class Matrix(Matrix1): sage: A = identity_matrix(21) sage: A.rook_vector(complement=True)[-1] 18795307255050944540 - sage: Derangements(21).cardinality() + sage: Derangements(21).cardinality() # needs sage.combinat 18795307255050944540 An other example that we convert into a rook polynomial:: @@ -1731,7 +1758,7 @@ cdef class Matrix(Matrix1): [1, 8, 20, 16, 4] sage: A.rook_vector(algorithm="Ryser") [1, 8, 20, 16, 4] - sage: A.rook_vector(algorithm="Godsil") + sage: A.rook_vector(algorithm="Godsil") # needs sage.graphs [1, 8, 20, 16, 4] When the matrix `A` has more ones then zeroes it is usually faster @@ -1750,7 +1777,7 @@ cdef class Matrix(Matrix1): Ryser algorithms are available):: sage: R.<x,y> = PolynomialRing(GF(5)) - sage: A = matrix(R,[[1,x,y],[x*y,x**2+y,0]]) + sage: A = matrix(R, [[1, x, y], [x*y, x**2+y, 0]]) sage: A.rook_vector(algorithm="ButeraPernici") [1, x^2 + x*y + x + 2*y + 1, 2*x^2*y + x*y^2 + x^2 + y^2 + y] sage: A.rook_vector(algorithm="Ryser") @@ -1771,15 +1798,17 @@ cdef class Matrix(Matrix1): [1, 0, 0] sage: matrix([[0,0],[0,0]]).rook_vector(algorithm="Ryser") [1, 0, 0] - sage: matrix([[0,0],[0,0]]).rook_vector(algorithm="Godsil") + sage: matrix([[0,0],[0,0]]).rook_vector(algorithm="Godsil") # needs sage.graphs [1, 0, 0] sage: matrix.ones(4, 2).rook_vector("Ryser") [1, 8, 12] - sage: matrix.ones(4, 2).rook_vector("Godsil") + sage: matrix.ones(4, 2).rook_vector("Godsil") # needs sage.graphs [1, 8, 12] sage: m = matrix(ZZ,4,5) sage: m[:4,:4] = identity_matrix(4) - sage: for algorithm in ("Godsil","Ryser","ButeraPernici"): + sage: algos = ["Ryser", "ButeraPernici"] + sage: algos += ["Godsil"] + sage: for algorithm in algos: # needs sage.graphs ....: v = m.rook_vector(complement=True, use_complement=True, algorithm=algorithm) ....: if v != [1, 16, 78, 128, 53]: ....: print("ERROR with algorithm={} use_complement=True".format(algorithm)) @@ -1907,9 +1936,11 @@ cdef class Matrix(Matrix1): sage: k = GF(37) sage: P.<x0,x1,x2> = PolynomialRing(k) - sage: A = Matrix(P,2,3,[x0*x1, x0, x1, x2, x2 + 16, x2 + 5*x1 ]) - sage: A.minors(2) - [x0*x1*x2 + 16*x0*x1 - x0*x2, 5*x0*x1^2 + x0*x1*x2 - x1*x2, 5*x0*x1 + x0*x2 - x1*x2 - 16*x1] + sage: A = Matrix(P, 2, 3, [x0*x1, x0, x1, x2, x2 + 16, x2 + 5*x1]) + sage: A.minors(2) # needs sage.rings.finite_rings + [x0*x1*x2 + 16*x0*x1 - x0*x2, + 5*x0*x1^2 + x0*x1*x2 - x1*x2, + 5*x0*x1 + x0*x2 - x1*x2 - 16*x1] This test addresses an issue raised at :trac:`20512`:: @@ -2004,16 +2035,16 @@ cdef class Matrix(Matrix1): TESTS:: - sage: A = matrix(5, 5, [next_prime(i^2) for i in range(25)]) - sage: B = MatrixSpace(ZZ['x'], 5, 5)(A) - sage: A.det() - B.det() + sage: A = matrix(5, 5, [next_prime(i^2) for i in range(25)]) # needs sage.libs.pari + sage: B = MatrixSpace(ZZ['x'], 5, 5)(A) # needs sage.libs.pari + sage: A.det() - B.det() # needs sage.libs.pari 0 We verify that :trac:`5569` is resolved (otherwise the following would hang for hours):: - sage: d = random_matrix(GF(next_prime(10^20)),50).det() - sage: d = random_matrix(Integers(10^50),50).det() + sage: d = random_matrix(GF(next_prime(10^20)), 50).det() # needs sage.rings.finite_rings + sage: d = random_matrix(Integers(10^50), 50).det() # needs sage.rings.finite_rings We verify that :trac:`7704` is resolved:: @@ -2027,12 +2058,17 @@ cdef class Matrix(Matrix1): sage: A = GF(2)['x,y,z'] sage: A.inject_variables() Defining x, y, z - sage: R = A.quotient(x^2 + 1).quotient(y^2 + 1).quotient(z^2 + 1) - sage: R.inject_variables() + sage: R = A.quotient(x^2 + 1).quotient(y^2 + 1).quotient(z^2 + 1) # needs sage.rings.finite_rings + sage: R.inject_variables() # needs sage.rings.finite_rings Defining xbarbarbar, ybarbarbar, zbarbarbar - sage: M = matrix([[1,1,1,1],[xbarbarbar,ybarbarbar,1,1],[0,1,zbarbarbar,1],[xbarbarbar,zbarbarbar,1,1]]) - sage: M.determinant() - xbarbarbar*ybarbarbar*zbarbarbar + xbarbarbar*ybarbarbar + xbarbarbar*zbarbarbar + ybarbarbar*zbarbarbar + xbarbarbar + ybarbarbar + zbarbarbar + 1 + sage: M = matrix([[1, 1, 1, 1], # needs sage.rings.finite_rings + ....: [xbarbarbar, ybarbarbar, 1, 1], + ....: [0, 1, zbarbarbar, 1], + ....: [xbarbarbar, zbarbarbar, 1, 1]]) + sage: M.determinant() # needs sage.rings.finite_rings + xbarbarbar*ybarbarbar*zbarbarbar + xbarbarbar*ybarbarbar + + xbarbarbar*zbarbarbar + ybarbarbar*zbarbarbar + xbarbarbar + + ybarbarbar + zbarbarbar + 1 Check that the determinant is computed from a cached charpoly properly:: @@ -2151,7 +2187,7 @@ cdef class Matrix(Matrix1): Compute the determinant of the upper-left level x level submatrix of self. Does not handle degenerate cases, level MUST be >= 2 """ - cdef Py_ssize_t n, i + cdef Py_ssize_t i if level == 2: return self.get_unsafe(0,0) * self.get_unsafe(1,1) - self.get_unsafe(0,1) * self.get_unsafe(1,0) else: @@ -2194,14 +2230,14 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: A = matrix(SR, 2, lambda i, j: f'a{i}{j}'); A # optional - sage.symbolic + sage: A = matrix(SR, 2, lambda i, j: f'a{i}{j}'); A # needs sage.symbolic [a00 a01] [a10 a11] - sage: A.quantum_determinant() # optional - sage.symbolic + sage: A.quantum_determinant() # needs sage.symbolic -a01*a10*q + a00*a11 - sage: A = matrix(SR, 3, lambda i, j: f'a{i}{j}') # optional - sage.symbolic - sage: A.quantum_determinant() # optional - sage.symbolic + sage: A = matrix(SR, 3, lambda i, j: f'a{i}{j}') # needs sage.symbolic + sage: A.quantum_determinant() # needs sage.symbolic -a02*a11*a20*q^3 + (a01*a12*a20 + a02*a10*a21)*q^2 + (-a00*a12*a21 - a01*a10*a22)*q + a00*a11*a22 @@ -2405,7 +2441,7 @@ cdef class Matrix(Matrix1): In that case, the definition by perfect matchings is used instead:: - sage: A.pfaffian() + sage: A.pfaffian() # needs sage.combinat sage.rings.finite_rings 2 """ @@ -2490,7 +2526,7 @@ cdef class Matrix(Matrix1): ....: (2, -1, 0, 0, 1, 5/2), ....: (-2, 1, -3/2, -1, 0, 1/2), ....: (1/2, -3/2, -1, -5/2, -1/2, 0)]) - sage: A._pf_perfect_matchings() + sage: A._pf_perfect_matchings() # needs sage.combinat -1/2 """ @@ -2546,9 +2582,9 @@ cdef class Matrix(Matrix1): TESTS:: - sage: A = random_matrix(ZZ[x], 6) + sage: A = random_matrix(ZZ['x'], 6) sage: A = A - A.transpose() - sage: A.pfaffian(algorithm='bfl') == A._pf_perfect_matchings() + sage: A.pfaffian(algorithm='bfl') == A._pf_perfect_matchings() # needs sage.combinat True """ @@ -2599,7 +2635,8 @@ cdef class Matrix(Matrix1): [3 4 0] [1 2 3] sage: parent(m.apply_morphism(phi)) - Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 5 + Full MatrixSpace of 3 by 3 dense matrices + over Finite Field of size 5 We apply a morphism to a matrix over a polynomial ring:: @@ -2641,14 +2678,15 @@ cdef class Matrix(Matrix1): EXAMPLES:: sage: m = matrix(ZZ, 3, 3, range(9)) - sage: k.<a> = GF(9) + sage: k.<a> = GF(9) # needs sage.rings.finite_rings sage: f = lambda x: k(x) - sage: n = m.apply_map(f); n + sage: n = m.apply_map(f); n # needs sage.rings.finite_rings [0 1 2] [0 1 2] [0 1 2] - sage: n.parent() - Full MatrixSpace of 3 by 3 dense matrices over Finite Field in a of size 3^2 + sage: n.parent() # needs sage.rings.finite_rings + Full MatrixSpace of 3 by 3 dense matrices + over Finite Field in a of size 3^2 In this example, we explicitly specify the codomain. @@ -2656,12 +2694,13 @@ cdef class Matrix(Matrix1): sage: s = GF(3) sage: f = lambda x: s(x) - sage: n = m.apply_map(f, k); n + sage: n = m.apply_map(f, k); n # needs sage.rings.finite_rings [0 1 2] [0 1 2] [0 1 2] - sage: n.parent() - Full MatrixSpace of 3 by 3 dense matrices over Finite Field in a of size 3^2 + sage: n.parent() # needs sage.rings.finite_rings + Full MatrixSpace of 3 by 3 dense matrices + over Finite Field in a of size 3^2 If self is subdivided, the result will be as well:: @@ -2754,7 +2793,7 @@ cdef class Matrix(Matrix1): sage: a = matrix(QQ, 2,2, [1,2,3,4]); a [1 2] [3 4] - sage: a.characteristic_polynomial('T') + sage: a.characteristic_polynomial('T') # needs sage.libs.pari T^2 - 5*T - 2 """ return self.charpoly(*args, **kwds) @@ -2766,9 +2805,9 @@ cdef class Matrix(Matrix1): EXAMPLES:: sage: a = matrix(QQ, 4, 4, range(16)) - sage: a.minimal_polynomial('z') + sage: a.minimal_polynomial('z') # needs sage.libs.pari z^3 - 30*z^2 - 80*z - sage: a.minpoly() + sage: a.minpoly() # needs sage.libs.pari x^3 - 30*x^2 - 80*x """ return self.minpoly(var, **kwds) @@ -2783,7 +2822,8 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: A = matrix(GF(9,'c'), 4, [1, 1, 0,0, 0,1,0,0, 0,0,5,0, 0,0,0,5]) + sage: # needs sage.rings.finite_rings + sage: A = matrix(GF(9, 'c'), 4, [1,1,0,0, 0,1,0,0, 0,0,5,0, 0,0,0,5]) sage: factor(A.minpoly()) (x + 1) * (x + 2)^2 sage: A.minpoly()(A) == 0 @@ -2794,7 +2834,7 @@ cdef class Matrix(Matrix1): The default variable name is `x`, but you can specify another name:: - sage: factor(A.minpoly('y')) + sage: factor(A.minpoly('y')) # needs sage.rings.finite_rings (y + 1) * (y + 2)^2 """ f = self.fetch('minpoly') @@ -2841,8 +2881,8 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: a = matrix([[1,2],[3,4]]) - sage: a._test_minpoly() + sage: a = matrix([[1,2], [3,4]]) + sage: a._test_minpoly() # needs sage.libs.pari """ if self.nrows() == self.ncols() and self.base_ring().is_exact(): tester = self._tester(**options) @@ -2902,8 +2942,8 @@ cdef class Matrix(Matrix1): An example over `\QQ`:: - sage: A = MatrixSpace(QQ,3)(range(9)) - sage: A.charpoly('x') + sage: A = MatrixSpace(QQ, 3)(range(9)) + sage: A.charpoly('x') # needs sage.libs.pari x^3 - 12*x^2 - 18*x sage: A.trace() 12 @@ -2914,7 +2954,7 @@ cdef class Matrix(Matrix1): polynomial ring `\ZZ[a]`:: sage: R.<a> = PolynomialRing(ZZ) - sage: M = MatrixSpace(R,2)([a,1, a,a+1]); M + sage: M = MatrixSpace(R, 2)([a,1, a,a+1]); M [ a 1] [ a a + 1] sage: f = M.charpoly('x'); f @@ -2947,6 +2987,7 @@ cdef class Matrix(Matrix1): Here is an example over a number field:: + sage: # needs sage.rings.number_field sage: x = QQ['x'].gen() sage: K.<a> = NumberField(x^2 - 2) sage: m = matrix(K, [[a-1, 2], [a, a+1]]) @@ -2968,7 +3009,7 @@ cdef class Matrix(Matrix1): sage: R.<a,b> = QQ[] sage: S.<x,y> = R.quo((b^3)) - sage: A = matrix(S, [[x*y^2,2*x],[2,x^10*y]]) + sage: A = matrix(S, [[x*y^2, 2*x], [2, x^10*y]]) sage: A [ x*y^2 2*x] [ 2 x^10*y] @@ -2988,6 +3029,7 @@ cdef class Matrix(Matrix1): and crash if an empty dictionary was cached. We don't cache dictionaries anymore, but this test should still pass:: + sage: # needs sage.rings.padics sage: z = Zp(p=5) sage: A = matrix(z, [ [3 + O(5^1), 4 + O(5^1), 4 + O(5^1)], ....: [2*5^2 + O(5^3), 2 + O(5^1), 1 + O(5^1)], @@ -3105,8 +3147,8 @@ cdef class Matrix(Matrix1): Test that :trac:`27937` is fixed:: - sage: R = FreeAbelianMonoid('u,v').algebra(QQ) - sage: matrix(4, 4, lambda i, j: R.an_element())._charpoly_df() + sage: R = FreeAbelianMonoid('u,v').algebra(QQ) # needs sage.combinat + sage: matrix(4, 4, lambda i, j: R.an_element())._charpoly_df() # needs sage.combinat B[1]*x^4 - 4*B[u]*x^3 .. NOTE:: @@ -3162,24 +3204,24 @@ cdef class Matrix(Matrix1): A = [R.zero()] * n F[0] = - M.get_unsafe(0, 0) - for t in xrange(1,n): + for t in range(1,n): # Set a(1, t) to be M(<=t, t) # - for i in xrange(t+1): + for i in range(t+1): a.set_unsafe(0, i, M.get_unsafe(i, t)) # Set A[1, t] to be the (t)th entry in a[1, t] # A[0] = M.get_unsafe(t, t) - for p in xrange(1, t): + for p in range(1, t): # Set a(p, t) to the product of M[<=t, <=t] * a(p-1, t) # - for i in xrange(t+1): + for i in range(t+1): s = R.zero() - for j in xrange(t+1): + for j in range(t+1): s = s + M.get_unsafe(i, j) * a.get_unsafe(p-1, j) a.set_unsafe(p, i, s) @@ -3190,13 +3232,13 @@ cdef class Matrix(Matrix1): # Set A[t, t] to be M[t, <=t] * a(p-1, t) # s = R.zero() - for j in xrange(t+1): + for j in range(t+1): s = s + M.get_unsafe(t, j) * a.get_unsafe(t-1, j) A[t] = s - for p in xrange(t+1): + for p in range(t+1): s = F[p] - for k in xrange(p): + for k in range(p): s = s - A[k] * F[p-k-1] F[p] = s - A[p] @@ -3215,12 +3257,12 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: M = MatrixSpace(QQ,3,3) - sage: A = M([1,9,-7,4/5,4,3,6,4,3]) - sage: A.fcp() + sage: M = MatrixSpace(QQ, 3, 3) + sage: A = M([1,9,-7, 4/5,4,3, 6,4,3]) + sage: A.fcp() # needs sage.libs.pari x^3 - 8*x^2 + 209/5*x - 286 sage: A = M([3, 0, -2, 0, -2, 0, 0, 0, 0]) - sage: A.fcp('T') + sage: A.fcp('T') # needs sage.libs.pari (T - 3) * T * (T + 2) """ return self.charpoly(var).factor() @@ -3265,9 +3307,10 @@ cdef class Matrix(Matrix1): Here's an example involving a cyclotomic field:: + sage: # needs sage.rings.number_field sage: K.<z> = CyclotomicField(3) - sage: M = MatrixSpace(K,3,sparse=True) - sage: A = M([(1+z)/3,(2+z)/3,z/3,1,1+z,-2,1,5,-1+z]) + sage: M = MatrixSpace(K, 3, sparse=True) + sage: A = M([(1+z)/3, (2+z)/3, z/3, 1, 1+z, -2, 1, 5, -1+z]) sage: print(A) [1/3*z + 1/3 1/3*z + 2/3 1/3*z] [ 1 z + 1 -2] @@ -3276,8 +3319,7 @@ cdef class Matrix(Matrix1): 3 """ if self.nrows() == 0 or self.ncols() == 0: - return ZZ(1) - R = self.base_ring() + return ZZ.one() x = self.list() try: d = x[0].denominator() @@ -3548,7 +3590,7 @@ cdef class Matrix(Matrix1): Z^3 - 12*Z^2 - 18*Z sage: matrix(ZZ,3,3,range(9))._charpoly_hessenberg('Z') Z^3 - 12*Z^2 - 18*Z - sage: matrix(GF(7),3,3,range(9))._charpoly_hessenberg('Z') + sage: matrix(GF(7), 3, 3, range(9))._charpoly_hessenberg('Z') Z^3 + 2*Z^2 + 3*Z sage: matrix(QQ['x'],3,3,range(9))._charpoly_hessenberg('Z') Z^3 - 12*Z^2 - 18*Z @@ -3675,7 +3717,7 @@ cdef class Matrix(Matrix1): OUTPUT: - Returns a pair. First item is the string 'pivot-pari-numberfield' + Returns a pair. First item is the string ``'pivot-pari-numberfield'`` that identifies the nature of the basis vectors. Second item is a matrix whose rows are a basis for the right kernel, @@ -3683,22 +3725,24 @@ cdef class Matrix(Matrix1): EXAMPLES:: + sage: # needs sage.libs.pari sage.rings.number_field sage: Q = QuadraticField(-7) sage: a = Q.gen(0) - sage: A = matrix(Q, [[ 2, 5-a, 15-a], - ....: [2+a, a, -7 + 5*a]]) + sage: A = matrix(Q, [[ 2, 5 - a, 15 - a], + ....: [2 + a, a, -7 + 5*a]]) sage: result = A._right_kernel_matrix_over_number_field() sage: result[0] 'pivot-pari-numberfield' sage: P = result[1]; P [-a -3 1] - sage: A*P.transpose() == zero_matrix(Q, 2, 1) + sage: A * P.transpose() == zero_matrix(Q, 2, 1) True TESTS: We test some trivial cases. :: + sage: # needs sage.libs.pari sage.rings.number_field sage: Q = QuadraticField(-7) sage: A = matrix(Q, 0, 2) sage: A._right_kernel_matrix_over_number_field()[1] @@ -3706,7 +3750,9 @@ cdef class Matrix(Matrix1): [0 1] sage: A = matrix(Q, 2, 0) sage: A._right_kernel_matrix_over_number_field()[1].parent() - Full MatrixSpace of 0 by 0 dense matrices over Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I + Full MatrixSpace of 0 by 0 dense matrices + over Number Field in a with defining polynomial x^2 + 7 + with a = 2.645751311064591?*I sage: A = zero_matrix(Q, 4, 3) sage: A._right_kernel_matrix_over_number_field()[1] [1 0 0] @@ -3737,6 +3783,7 @@ cdef class Matrix(Matrix1): EXAMPLES:: + sage: # needs sage.rings.number_field sage: C = CyclotomicField(14) sage: a = C.gen(0) sage: A = matrix(C, 3, 4, [[ 1, a, 1+a, a^3+a^5], @@ -3748,13 +3795,14 @@ cdef class Matrix(Matrix1): sage: P = result[1]; P [ -1 -1 1 0] [-zeta14^3 -zeta14^4 0 1] - sage: A*P.transpose() == zero_matrix(C, 3, 2) + sage: A * P.transpose() == zero_matrix(C, 3, 2) True TESTS: We test some trivial cases. :: + sage: # needs sage.rings.number_field sage: C = CyclotomicField(14) sage: A = matrix(C, 0, 2) sage: A._right_kernel_matrix_over_field()[1] @@ -3762,7 +3810,8 @@ cdef class Matrix(Matrix1): [0 1] sage: A = matrix(C, 2, 0) sage: A._right_kernel_matrix_over_field()[1].parent() - Full MatrixSpace of 0 by 0 dense matrices over Cyclotomic Field of order 14 and degree 6 + Full MatrixSpace of 0 by 0 dense matrices + over Cyclotomic Field of order 14 and degree 6 sage: A = zero_matrix(C, 4, 3) sage: A._right_kernel_matrix_over_field()[1] [1 0 0] @@ -3858,7 +3907,7 @@ cdef class Matrix(Matrix1): """ tm = verbose("computing right kernel matrix over a domain for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) - d, u, v = self.smith_form() + d, _, v = self.smith_form() basis = [] cdef Py_ssize_t i, nrows = self._nrows for i in range(self._ncols): @@ -3883,7 +3932,8 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: A = matrix(Zmod(24480), [[1,2,3,4,5],[7,7,7,7,7]]) + sage: # needs sage.libs.pari + sage: A = matrix(Zmod(24480), [[1,2,3,4,5], [7,7,7,7,7]]) sage: result = A._right_kernel_matrix_over_integer_mod_ring() sage: result[0] 'computed-pari-matkermod' @@ -3891,7 +3941,7 @@ cdef class Matrix(Matrix1): [ 1 24478 1 0 0] [ 2 24477 0 1 0] [ 3 24476 0 0 1] - sage: A*P.transpose() == 0 + sage: A * P.transpose() == 0 True """ R = self.base_ring() @@ -4044,6 +4094,7 @@ cdef class Matrix(Matrix1): basis, so the `basis` keywords 'computed' and 'pivot' will return the same results. :: + sage: # needs sage.rings.number_field sage: Q = QuadraticField(-7) sage: a = Q.gen(0) sage: A = matrix(Q, [[2, 5-a, 15-a, 16+4*a], @@ -4053,10 +4104,10 @@ cdef class Matrix(Matrix1): [ -2 -a - 1 0 1] sage: A*C.transpose() == zero_matrix(Q, 2, 2) True - sage: P = A.right_kernel_matrix(algorithm='pari', basis='pivot'); P + sage: P = A.right_kernel_matrix(algorithm='pari', basis='pivot'); P # needs sage.libs.pari [ -a -3 1 0] [ -2 -a - 1 0 1] - sage: A*P.transpose() == zero_matrix(Q, 2, 2) + sage: A*P.transpose() == zero_matrix(Q, 2, 2) # needs sage.libs.pari True sage: E = A.right_kernel_matrix(algorithm='default', basis='echelon'); E [ 1 0 7/88*a + 3/88 -3/176*a - 39/176] @@ -4068,9 +4119,10 @@ cdef class Matrix(Matrix1): code for matrices over any field. The basis vectors as computed are in pivot format. :: + sage: # needs sage.rings.number_field sage: Q = QuadraticField(-7) sage: a = Q.gen(0) - sage: A = matrix(Q, [[2, 5-a, 15-a, 16+4*a],[2+a, a, -7 + 5*a, -3+3*a]]) + sage: A = matrix(Q, [[2, 5-a, 15-a, 16+4*a], [2+a, a, -7 + 5*a, -3+3*a]]) sage: G = A.right_kernel_matrix(algorithm='generic', basis='computed'); G [ -a -3 1 0] [ -2 -a - 1 0 1] @@ -4080,16 +4132,18 @@ cdef class Matrix(Matrix1): We check that number fields are handled by the right routine as part of typical right kernel computation. :: + sage: # needs sage.rings.number_field sage: Q = QuadraticField(-7) sage: a = Q.gen(0) - sage: A = matrix(Q, [[2, 5-a, 15-a, 16+4*a],[2+a, a, -7 + 5*a, -3+3*a]]) + sage: A = matrix(Q, [[2, 5-a, 15-a, 16+4*a], [2+a, a, -7 + 5*a, -3+3*a]]) sage: set_verbose(1) sage: A.right_kernel(algorithm='default') verbose ... verbose 1 (<module>) computing right kernel matrix over a number field for 2x4 matrix verbose 1 (<module>) done computing right kernel matrix over a number field for 2x4 matrix ... - Vector space of degree 4 and dimension 2 over Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I + Vector space of degree 4 and dimension 2 over + Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I Basis matrix: [ 1 0 7/88*a + 3/88 -3/176*a - 39/176] [ 0 1 -1/88*a - 13/88 13/176*a - 7/176] @@ -4118,9 +4172,9 @@ cdef class Matrix(Matrix1): keywords, 'pluq', 'default' and unspecified, all have the same effect as there is no optional behavior. :: - sage: A = matrix(GF(2),[[0, 1, 1, 0, 0, 0], - ....: [1, 0, 0, 0, 1, 1,], - ....: [1, 0, 0, 0, 1, 1]]) + sage: A = matrix(GF(2), [[0, 1, 1, 0, 0, 0], + ....: [1, 0, 0, 0, 1, 1,], + ....: [1, 0, 0, 0, 1, 1]]) sage: P = A.right_kernel_matrix(algorithm='generic', basis='pivot'); P [0 1 1 0 0 0] [0 0 0 1 0 0] @@ -4143,9 +4197,9 @@ cdef class Matrix(Matrix1): We test that the mod 2 code is called for matrices over GF(2). :: - sage: A = matrix(GF(2),[[0, 1, 1, 0, 0, 0], - ....: [1, 0, 0, 0, 1, 1,], - ....: [1, 0, 0, 0, 1, 1]]) + sage: A = matrix(GF(2), [[0, 1, 1, 0, 0, 0], + ....: [1, 0, 0, 0, 1, 1,], + ....: [1, 0, 0, 0, 1, 1]]) sage: set_verbose(1) sage: A.right_kernel(algorithm='default') verbose ... @@ -4166,6 +4220,7 @@ cdef class Matrix(Matrix1): will compute a set of basis vectors in the pivot format. These could be returned as a basis in echelon form. :: + sage: # needs sage.rings.finite_rings sage: F.<a> = FiniteField(5^2) sage: A = matrix(F, 3, 4, [[ 1, a, 1+a, a^3+a^5], ....: [ a, a^4, a+a^4, a^4+a^8], @@ -4205,6 +4260,7 @@ cdef class Matrix(Matrix1): We test that the generic code is called for matrices over fields, lacking any more specific routine. :: + sage: # needs sage.rings.finite_rings sage: F.<a> = FiniteField(5^2) sage: A = matrix(F, 3, 4, [[ 1, a, 1+a, a^3+a^5], ....: [ a, a^4, a+a^4, a^4+a^8], @@ -4250,6 +4306,7 @@ cdef class Matrix(Matrix1): sage: A*X.transpose() == zero_matrix(ZZ, 4, 3) True + sage: # needs sage.libs.pari sage: X = A.right_kernel_matrix(algorithm='pari', basis='computed'); X [ 3 1 -5 -7 -2 3 2] [ 3 1 2 5 -5 2 -6] @@ -4324,7 +4381,8 @@ cdef class Matrix(Matrix1): sage: A.right_kernel_matrix() Traceback (most recent call last): ... - ArithmeticError: Ideal Ideal (x^2 - x, x^2 - 8) of Univariate Polynomial Ring in x over Integer Ring not principal + ArithmeticError: Ideal Ideal (x^2 - x, x^2 - 8) of + Univariate Polynomial Ring in x over Integer Ring not principal We test that the domain code is called for domains that lack any extra structure. :: @@ -4338,7 +4396,8 @@ cdef class Matrix(Matrix1): verbose 1 (<module>) computing right kernel matrix over a domain for 2x3 matrix verbose 1 (<module>) done computing right kernel matrix over a domain for 2x3 matrix ... - Free module of degree 3 and rank 1 over Univariate Polynomial Ring in y over Rational Field + Free module of degree 3 and rank 1 over + Univariate Polynomial Ring in y over Rational Field Echelon basis matrix: [-1 -y 1] sage: set_verbose(0) @@ -4449,7 +4508,7 @@ cdef class Matrix(Matrix1): raise ValueError("'padic' matrix kernel algorithm only available over the rationals and the integers, not over %s" % R) elif algorithm == 'flint' and not (is_IntegerRing(R) or is_RationalField(R)): raise ValueError("'flint' matrix kernel algorithm only available over the rationals and the integers, not over %s" % R) - elif algorithm == 'pari' and not (is_IntegerRing(R) or (is_NumberField(R) and not is_RationalField(R))): + elif algorithm == 'pari' and not (is_IntegerRing(R) or (isinstance(R, NumberField) and not is_RationalField(R))): raise ValueError("'pari' matrix kernel algorithm only available over non-trivial number fields and the integers, not over %s" % R) elif algorithm == 'generic' and R not in _Fields: raise ValueError("'generic' matrix kernel algorithm only available over a field, not over %s" % R) @@ -4506,7 +4565,7 @@ cdef class Matrix(Matrix1): except AttributeError: pass - if M is None and is_NumberField(R): + if M is None and isinstance(R, NumberField): format, M = self._right_kernel_matrix_over_number_field() if M is None and R in _Fields: @@ -4689,16 +4748,18 @@ cdef class Matrix(Matrix1): Over an arbitrary field, with two basis formats. Same vector space, different bases. :: + sage: # needs sage.rings.finite_rings sage: F.<a> = FiniteField(5^2) sage: A = matrix(F, 3, 4, [[ 1, a, 1+a, a^3+a^5], ....: [ a, a^4, a+a^4, a^4+a^8], ....: [a^2, a^6, a^2+a^6, a^5+a^10]]) sage: K = A.right_kernel(); K - Vector space of degree 4 and dimension 2 over Finite Field in a of size 5^2 + Vector space of degree 4 and dimension 2 + over Finite Field in a of size 5^2 Basis matrix: [ 1 0 3*a + 4 2*a + 2] [ 0 1 2*a 3*a + 3] - sage: A*K.basis_matrix().transpose() == zero_matrix(F, 3, 2) + sage: A * K.basis_matrix().transpose() == zero_matrix(F, 3, 2) True In the following test, we have to force usage of @@ -4709,8 +4770,9 @@ cdef class Matrix(Matrix1): sage: from sage.matrix.matrix_generic_dense import Matrix_generic_dense sage: B = Matrix_generic_dense(A.parent(), A.list(), False, False) - sage: P = B.right_kernel(basis = 'pivot'); P - Vector space of degree 4 and dimension 2 over Finite Field in a of size 5^2 + sage: P = B.right_kernel(basis='pivot'); P # needs sage.rings.finite_rings + Vector space of degree 4 and dimension 2 + over Finite Field in a of size 5^2 User basis matrix: [ 4 4 1 0] [ a + 2 3*a + 3 0 1] @@ -4718,32 +4780,36 @@ cdef class Matrix(Matrix1): If the optional meataxe package is installed, we again have to make sure to work with a copy of B that has the same type as ``P.basis_matrix()``:: - sage: B.parent()(B.list())*P.basis_matrix().transpose() == zero_matrix(F, 3, 2) + sage: (B.parent()(B.list()) * P.basis_matrix().transpose() # needs sage.rings.finite_rings + ....: == zero_matrix(F, 3, 2)) True - sage: K == P + sage: K == P # needs sage.rings.finite_rings True Over number fields, PARI is used by default, but general-purpose code can be requested. Same vector space, same bases, different code.:: + sage: # needs sage.rings.number_field sage: Q = QuadraticField(-7) sage: a = Q.gen(0) - sage: A = matrix(Q, [[ 2, 5-a, 15-a, 16+4*a], - ....: [2+a, a, -7 + 5*a, -3+3*a]]) + sage: A = matrix(Q, [[ 2, 5 - a, 15 - a, 16 + 4*a], + ....: [2 + a, a, -7 + 5*a, -3 + 3*a]]) sage: K = A.right_kernel(algorithm='default'); K - Vector space of degree 4 and dimension 2 over Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I + Vector space of degree 4 and dimension 2 + over Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I Basis matrix: [ 1 0 7/88*a + 3/88 -3/176*a - 39/176] [ 0 1 -1/88*a - 13/88 13/176*a - 7/176] - sage: A*K.basis_matrix().transpose() == zero_matrix(Q, 2, 2) + sage: A * K.basis_matrix().transpose() == zero_matrix(Q, 2, 2) True sage: B = copy(A) sage: G = A.right_kernel(algorithm='generic'); G - Vector space of degree 4 and dimension 2 over Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I + Vector space of degree 4 and dimension 2 + over Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I Basis matrix: [ 1 0 7/88*a + 3/88 -3/176*a - 39/176] [ 0 1 -1/88*a - 13/88 13/176*a - 7/176] - sage: B*G.basis_matrix().transpose() == zero_matrix(Q, 2, 2) + sage: B * G.basis_matrix().transpose() == zero_matrix(Q, 2, 2) True sage: K == G True @@ -4904,11 +4970,10 @@ cdef class Matrix(Matrix1): """ K = self.fetch('right_kernel') if K is not None: - verbose("retrieving cached right kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) return K R = self.base_ring() - tm = verbose("computing a right kernel for %sx%s matrix over %s" % (self.nrows(), self.ncols(), R),level=1) + tm = verbose(lazy_string("computing a right kernel for %sx%s matrix over %s", self.nrows(), self.ncols(), R), level=1) # Sanitize basis format # 'computed' is OK in right_kernel_matrix(), but not here @@ -4930,7 +4995,7 @@ cdef class Matrix(Matrix1): else: K = ambient.submodule_with_basis(M.rows(), already_echelonized=False, check=False) - verbose("done computing a right kernel for %sx%s matrix over %s" % (self.nrows(), self.ncols(), R),level=1, t=tm) + verbose(lazy_string("done computing a right kernel for %sx%s matrix over %s", self.nrows(), self.ncols(), R), level=1, t=tm) self.cache('right_kernel', K) return K @@ -5080,7 +5145,6 @@ cdef class Matrix(Matrix1): """ K = self.fetch('left_kernel') if K is not None: - verbose("retrieving cached left kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) return K tm = verbose("computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) @@ -5124,7 +5188,7 @@ cdef class Matrix(Matrix1): [ 0 2 0 -1] [ 0 1 -2 0] [ 0 2 0 -2] - sage: t.fcp() + sage: t.fcp() # needs sage.libs.pari (x - 39) * (x + 2) * (x^2 - 2) sage: s = (t-39)*(t^2-2) sage: V = s.kernel(); V @@ -5220,13 +5284,16 @@ cdef class Matrix(Matrix1): An example over a bigger ring:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: L.<w> = NumberField(x^2 - x + 2) sage: OL = L.ring_of_integers() sage: A = matrix(L, 2, [1, w/2]) sage: A.integer_kernel(OL) - Free module of degree 2 and rank 1 over Maximal Order in Number Field in w with defining polynomial x^2 - x + 2 - Echelon basis matrix: - [ -1 -w + 1] + Free module of degree 2 and rank 1 over + Maximal Order in Number Field in w with defining polynomial x^2 - x + 2 + Echelon basis matrix: + [ -1 -w + 1] """ try: @@ -5436,23 +5503,23 @@ cdef class Matrix(Matrix1): [198 209 220 231 242 253] [264 275 286 297 308 319] [330 341 352 363 374 385] - sage: A.decomposition() - [ - (Ambient free module of rank 4 over the principal ideal domain Integer Ring, True) - ] - sage: B.decomposition() - [ - (Vector space of degree 6 and dimension 2 over Rational Field - Basis matrix: - [ 1 0 -1 -2 -3 -4] - [ 0 1 2 3 4 5], True), - (Vector space of degree 6 and dimension 4 over Rational Field - Basis matrix: - [ 1 0 0 0 -5 4] - [ 0 1 0 0 -4 3] - [ 0 0 1 0 -3 2] - [ 0 0 0 1 -2 1], False) - ] + sage: A.decomposition() # needs sage.libs.pari + [ (Ambient free module of rank 4 + over the principal ideal domain Integer Ring, + True) ] + sage: B.decomposition() # needs sage.libs.pari + [ (Vector space of degree 6 and dimension 2 over Rational Field + Basis matrix: + [ 1 0 -1 -2 -3 -4] + [ 0 1 2 3 4 5], + True), + (Vector space of degree 6 and dimension 4 over Rational Field + Basis matrix: + [ 1 0 0 0 -5 4] + [ 0 1 0 0 -4 3] + [ 0 0 1 0 -3 2] + [ 0 0 0 1 -2 1], + False) ] """ if algorithm == 'kernel' or self.base_ring() not in _Fields: return self._decomposition_using_kernels(is_diagonalizable = is_diagonalizable, dual=dual) @@ -5625,26 +5692,25 @@ cdef class Matrix(Matrix1): EXAMPLES:: + sage: # needs sage.libs.pari sage: t = matrix(QQ, 3, [3, 0, -2, 0, -2, 0, 0, 0, 0]); t [ 3 0 -2] [ 0 -2 0] [ 0 0 0] - sage: t.fcp('X') # factored charpoly + sage: t.fcp('X') # factored charpoly (X - 3) * X * (X + 2) - sage: v = kernel(t*(t+2)); v # an invariant subspace + sage: v = kernel(t*(t+2)); v # an invariant subspace Vector space of degree 3 and dimension 2 over Rational Field Basis matrix: [0 1 0] [0 0 1] sage: D = t.decomposition_of_subspace(v); D - [ - (Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [0 0 1], True), - (Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [0 1 0], True) - ] + [ (Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: [0 0 1], + True), + (Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: [0 1 0], + True) ] sage: t.restrict(D[0][0]) [0] sage: t.restrict(D[1][0]) @@ -5652,25 +5718,30 @@ cdef class Matrix(Matrix1): We do a decomposition over ZZ:: - sage: a = matrix(ZZ,6,[0, 0, -2, 0, 2, 0, 2, -4, -2, 0, 2, 0, 0, 0, -2, -2, 0, 0, 2, 0, -2, -4, 2, -2, 0, 2, 0, -2, -2, 0, 0, 2, 0, -2, 0, 0]) - sage: a.decomposition_of_subspace(ZZ^6) - [ - (Free module of degree 6 and rank 2 over Integer Ring - Echelon basis matrix: - [ 1 0 1 -1 1 -1] - [ 0 1 0 -1 2 -1], False), - (Free module of degree 6 and rank 4 over Integer Ring - Echelon basis matrix: - [ 1 0 -1 0 1 0] - [ 0 1 0 0 0 0] - [ 0 0 0 1 0 0] - [ 0 0 0 0 0 1], False) - ] + sage: a = matrix(ZZ, 6, [0, 0, -2, 0, 2, 0, + ....: 2, -4, -2, 0, 2, 0, + ....: 0, 0, -2, -2, 0, 0, + ....: 2, 0, -2, -4, 2, -2, + ....: 0, 2, 0, -2, -2, 0, + ....: 0, 2, 0, -2, 0, 0]) + sage: a.decomposition_of_subspace(ZZ^6) # needs sage.libs.pari + [ (Free module of degree 6 and rank 2 over Integer Ring + Echelon basis matrix: + [ 1 0 1 -1 1 -1] + [ 0 1 0 -1 2 -1], + False), + (Free module of degree 6 and rank 4 over Integer Ring + Echelon basis matrix: + [ 1 0 -1 0 1 0] + [ 0 1 0 0 0 0] + [ 0 0 0 1 0 0] + [ 0 0 0 0 0 1], + False) ] TESTS:: sage: t = matrix(QQ, 3, [3, 0, -2, 0, -2, 0, 0, 0, 0]) - sage: t.decomposition_of_subspace(v, check_restrict = False) == t.decomposition_of_subspace(v) + sage: t.decomposition_of_subspace(v, check_restrict=False) == t.decomposition_of_subspace(v) # needs sage.libs.pari True """ if not sage.modules.free_module.is_FreeModule(M): @@ -5944,7 +6015,7 @@ cdef class Matrix(Matrix1): [6 7 8] sage: t.wiedemann(0) x^2 - 12*x - 18 - sage: t.charpoly() + sage: t.charpoly() # needs sage.libs.pari x^3 - 12*x^2 - 18*x """ i = int(i); t=int(t) @@ -5960,7 +6031,7 @@ cdef class Matrix(Matrix1): # sequence corresponding to the 0-th entries of the iterates, # then the 1-th entries, etc. if t == 0: - R = list(xrange(n)) + R = list(range(n)) else: R = [t] for i in R: @@ -5981,14 +6052,14 @@ cdef class Matrix(Matrix1): INPUT: - - ``format`` - ``None``, ``'all'`` or ``'galois'`` + - ``format`` -- ``None``, ``'all'`` or ``'galois'`` OUTPUT: Any format except ``None`` is just passed through. When the - format is ``None`` a choice is made about the style of the output. + format is ``None``, a choice is made about the style of the output. If there is an algebraically closed field that will contain the - possible eigenvalues, then 'all" of the eigenspaces are given. + possible eigenvalues, then ``'all'`` of the eigenspaces are given. However if this is not the case, then only one eigenspace is output for each irreducible factor of the characteristic polynomial. @@ -6008,17 +6079,17 @@ cdef class Matrix(Matrix1): of finite fields:: sage: A = matrix(QQ, 2, range(4)) - sage: A._eigenspace_format(None) == 'all' + sage: A._eigenspace_format(None) == 'all' # needs sage.rings.number_field True sage: B = matrix(GF(13), 2, range(4)) - sage: B._eigenspace_format(None) + sage: B._eigenspace_format(None) # needs sage.rings.finite_rings 'all' Subrings are promoted to fraction fields and then checked for the existence of algebraic closures. :: sage: A = matrix(ZZ, 2, range(4)) - sage: A._eigenspace_format(None) == 'all' + sage: A._eigenspace_format(None) == 'all' # needs sage.rings.number_field True """ if format not in [None, 'all', 'galois']: @@ -6029,7 +6100,7 @@ cdef class Matrix(Matrix1): # subrings of fields of which an algebraic closure is implemented. if format is None: try: - F = self.base_ring().fraction_field().algebraic_closure() + self.base_ring().fraction_field().algebraic_closure() return 'all' except (NotImplementedError, AttributeError): return 'galois' @@ -6040,48 +6111,48 @@ cdef class Matrix(Matrix1): r""" Compute the left eigenspaces of a matrix. - Note that ``eigenspaces_left()`` and ``left_eigenspaces()`` + Note that :meth:`eigenspaces_left` and :meth:`left_eigenspaces` are identical methods. Here "left" refers to the eigenvectors being placed to the left of the matrix. INPUT: - - ``self`` - a square matrix over an exact field. For inexact + - ``self`` -- a square matrix over an exact field. For inexact matrices consult the numerical or symbolic matrix classes. - - ``format`` - default: ``None`` + - ``format`` -- one of: - - ``'all'`` - attempts to create every eigenspace. This will + - ``'all'`` -- Attempts to create every eigenspace. This will always be possible for matrices with rational entries. - - ``'galois'`` - for each irreducible factor of the characteristic + - ``'galois'`` -- For each irreducible factor of the characteristic polynomial, a single eigenspace will be output for a single root/eigenvalue for the irreducible factor. - - ``None`` - Uses the 'all' format if the base ring is contained + - ``None`` (default) -- Uses the ``'all'`` format if the base ring is contained in an algebraically closed field which is implemented. - Otherwise, uses the 'galois' format. + Otherwise, uses the ``'galois'`` format. - - ``var`` - default: 'a' - variable name used to + - ``var`` -- string (default: ``'a'``); variable name used to represent elements of the root field of each irreducible factor of the characteristic polynomial. - If var='a', then the root fields will be in terms of - a0, a1, a2, ...., where the numbering runs across all + If ``var='a'``, then the root fields will be in terms of + ``a0, a1, a2, ...``, where the numbering runs across all the irreducible factors of the characteristic polynomial, even for linear factors. - - ``algebraic_multiplicity`` - default: False - whether or - not to include the algebraic multiplicity of each eigenvalue + - ``algebraic_multiplicity`` -- (boolean, default: ``False``); + whether to include the algebraic multiplicity of each eigenvalue in the output. See the discussion below. OUTPUT: - If algebraic_multiplicity=False, return a list of pairs (e, V) - where e is an eigenvalue of the matrix, and V is the corresponding + If ``algebraic_multiplicity=False``, return a list of pairs `(e, V)` + where `e` is an eigenvalue of the matrix, and `V` is the corresponding left eigenspace. For Galois conjugates of eigenvalues, there may be just one representative eigenspace, depending on the ``format`` keyword. - If algebraic_multiplicity=True, return a list of triples (e, V, n) - where e and V are as above and n is the algebraic multiplicity of + If ``algebraic_multiplicity=True``, return a list of triples `(e, V, n)` + where `e` and `V` are as above and `n` is the algebraic multiplicity of the eigenvalue. .. warning:: @@ -6093,46 +6164,53 @@ cdef class Matrix(Matrix1): EXAMPLES: We compute the left eigenspaces of a `3\times 3` - rational matrix. First, we request `all` of the eigenvalues, - so the results are in the field of algebraic numbers, `QQbar`. + rational matrix. First, we request ``'all'`` of the eigenvalues, + so the results are in the field of algebraic numbers, ``QQbar``. Then we request just one eigenspace per irreducible factor of - the characteristic polynomial with the `galois` keyword. :: + the characteristic polynomial with ``format='galois'``. :: - sage: A = matrix(QQ,3,3,range(9)); A + sage: A = matrix(QQ, 3, 3, range(9)); A [0 1 2] [3 4 5] [6 7 8] - sage: es = A.eigenspaces_left(format='all'); es - [ - (0, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (-1.348469228349535?, Vector space of degree 3 and dimension 1 over Algebraic Field - User basis matrix: - [ 1 0.3101020514433644? -0.3797958971132713?]), - (13.34846922834954?, Vector space of degree 3 and dimension 1 over Algebraic Field - User basis matrix: - [ 1 1.289897948556636? 1.579795897113272?]) - ] - + sage: es = A.eigenspaces_left(format='all'); es # needs sage.rings.number_field + [ (0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (-1.348469228349535?, + Vector space of degree 3 and dimension 1 over Algebraic Field + User basis matrix: + [ 1 0.3101020514433644? -0.3797958971132713?]), + (13.34846922834954?, + Vector space of degree 3 and dimension 1 over Algebraic Field + User basis matrix: + [ 1 1.289897948556636? 1.579795897113272?]) ] + + sage: # needs sage.rings.number_field sage: es = A.eigenspaces_left(format='galois'); es - [ - (0, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5]) - ] - sage: es = A.eigenspaces_left(format='galois', algebraic_multiplicity=True); es - [ - (0, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1], 1), - (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5], 1) - ] + [ (0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (a1, + Vector space of degree 3 and dimension 1 over + Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5]) ] + sage: es = A.eigenspaces_left(format='galois', + ....: algebraic_multiplicity=True); es + [ (0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1], + 1), + (a1, + Vector space of degree 3 and dimension 1 over + Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5], + 1) ] sage: e, v, n = es[0]; v = v.basis()[0] sage: delta = e*v - v*A sage: abs(abs(delta)) < 1e-10 @@ -6140,24 +6218,26 @@ cdef class Matrix(Matrix1): The same computation, but with implicit base change to a field. :: - sage: A = matrix(ZZ,3,3,range(9)); A + sage: A = matrix(ZZ, 3, 3, range(9)); A [0 1 2] [3 4 5] [6 7 8] - sage: A.eigenspaces_left(format='galois') - [ - (0, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5]) - ] + sage: A.eigenspaces_left(format='galois') # needs sage.rings.number_field + [ (0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (a1, + Vector space of degree 3 and dimension 1 over + Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5]) ] We compute the left eigenspaces of the matrix of the Hecke operator `T_2` on level 43 modular symbols, both with all eigenvalues (the default) and with one subspace per factor. :: + sage: # needs sage.modular sage: A = ModularSymbols(43).T(2).matrix(); A [ 3 0 0 0 0 0 -1] [ 0 -2 1 0 0 0 0] @@ -6173,40 +6253,52 @@ cdef class Matrix(Matrix1): sage: factor(f) (x - 3) * (x + 2)^2 * (x^2 - 2)^2 sage: A.eigenspaces_left(algebraic_multiplicity=True) - [ - (3, Vector space of degree 7 and dimension 1 over Rational Field - User basis matrix: - [ 1 0 1/7 0 -1/7 0 -2/7], 1), - (-2, Vector space of degree 7 and dimension 2 over Rational Field - User basis matrix: - [ 0 1 0 1 -1 1 -1] - [ 0 0 1 0 -1 2 -1], 2), - (-1.414213562373095?, Vector space of degree 7 and dimension 2 over Algebraic Field - User basis matrix: - [ 0 1 0 -1 0.4142135623730951? 1 -1] - [ 0 0 1 0 -1 0 2.414213562373095?], 2), - (1.414213562373095?, Vector space of degree 7 and dimension 2 over Algebraic Field - User basis matrix: - [ 0 1 0 -1 -2.414213562373095? 1 -1] - [ 0 0 1 0 -1 0 -0.4142135623730951?], 2) - ] + [ (3, + Vector space of degree 7 and dimension 1 over Rational Field + User basis matrix: + [ 1 0 1/7 0 -1/7 0 -2/7], + 1), + (-2, + Vector space of degree 7 and dimension 2 over Rational Field + User basis matrix: + [ 0 1 0 1 -1 1 -1] + [ 0 0 1 0 -1 2 -1], + 2), + (-1.414213562373095?, + Vector space of degree 7 and dimension 2 over Algebraic Field + User basis matrix: + [ 0 1 0 -1 0.4142135623730951? 1 -1] + [ 0 0 1 0 -1 0 2.414213562373095?], + 2), + (1.414213562373095?, + Vector space of degree 7 and dimension 2 over Algebraic Field + User basis matrix: + [ 0 1 0 -1 -2.414213562373095? 1 -1] + [ 0 0 1 0 -1 0 -0.4142135623730951?], + 2) ] sage: A.eigenspaces_left(format='galois', algebraic_multiplicity=True) - [ - (3, Vector space of degree 7 and dimension 1 over Rational Field - User basis matrix: - [ 1 0 1/7 0 -1/7 0 -2/7], 1), - (-2, Vector space of degree 7 and dimension 2 over Rational Field - User basis matrix: - [ 0 1 0 1 -1 1 -1] - [ 0 0 1 0 -1 2 -1], 2), - (a2, Vector space of degree 7 and dimension 2 over Number Field in a2 with defining polynomial x^2 - 2 - User basis matrix: - [ 0 1 0 -1 -a2 - 1 1 -1] - [ 0 0 1 0 -1 0 -a2 + 1], 2) - ] + [ (3, + Vector space of degree 7 and dimension 1 over Rational Field + User basis matrix: + [ 1 0 1/7 0 -1/7 0 -2/7], + 1), + (-2, + Vector space of degree 7 and dimension 2 over Rational Field + User basis matrix: + [ 0 1 0 1 -1 1 -1] + [ 0 0 1 0 -1 2 -1], + 2), + (a2, + Vector space of degree 7 and dimension 2 + over Number Field in a2 with defining polynomial x^2 - 2 + User basis matrix: + [ 0 1 0 -1 -a2 - 1 1 -1] + [ 0 0 1 0 -1 0 -a2 + 1], + 2) ] Next we compute the left eigenspaces over the finite field of order 11. :: + sage: # needs sage.modular sage.rings.finite_rings sage: A = ModularSymbols(43, base_ring=GF(11), sign=1).T(2).matrix(); A [ 3 0 9 0] [ 0 9 0 10] @@ -6216,17 +6308,16 @@ cdef class Matrix(Matrix1): Finite Field of size 11 sage: A.charpoly() x^4 + 10*x^3 + 3*x^2 + 2*x + 1 - sage: A.eigenspaces_left(format='galois', var = 'beta') - [ - (9, Vector space of degree 4 and dimension 1 over Finite Field of size 11 - User basis matrix: - [0 1 5 6]), - (3, Vector space of degree 4 and dimension 1 over Finite Field of size 11 - User basis matrix: - [1 0 1 6]), - (beta2, Vector space of degree 4 and dimension 1 over Univariate Quotient Polynomial Ring in beta2 over Finite Field of size 11 with modulus x^2 + 9 - User basis matrix: - [ 0 0 1 beta2 + 1]) + sage: A.eigenspaces_left(format='galois', var='beta') + [ (9, + Vector space of degree 4 and dimension 1 over Finite Field of size 11 + User basis matrix: [0 1 5 6]), + (3, Vector space of degree 4 and dimension 1 over Finite Field of size 11 + User basis matrix: [1 0 1 6]), + (beta2, Vector space of degree 4 and dimension 1 + over Univariate Quotient Polynomial Ring in beta2 + over Finite Field of size 11 with modulus x^2 + 9 + User basis matrix: [ 0 0 1 beta2 + 1]) ] This method is only applicable to exact matrices. @@ -6254,6 +6345,7 @@ cdef class Matrix(Matrix1): [ 0.897878732... 0.278434036... -0.341010658...] [ 0.408248290... -0.816496580... 0.408248290...] + sage: # needs sage.symbolic sage: x, y = var('x y') sage: S = matrix([[x, y], [y, 3*x^2]]) sage: em = S.eigenmatrix_left() @@ -6268,6 +6360,7 @@ cdef class Matrix(Matrix1): possible, will raise an error. Using the ``'galois'`` format option is more likely to be successful. :: + sage: # needs sage.rings.finite_rings sage: F.<b> = FiniteField(11^2) sage: A = matrix(F, [[b + 1, b + 1], [10*b + 4, 5*b + 4]]) sage: A.eigenspaces_left(format='all') @@ -6275,21 +6368,23 @@ cdef class Matrix(Matrix1): ... NotImplementedError: unable to construct eigenspaces for eigenvalues outside the base field, try the keyword option: format='galois' - sage: A.eigenspaces_left(format='galois') - [ - (a0, Vector space of degree 2 and dimension 1 over Univariate Quotient Polynomial Ring in a0 over Finite Field in b of size 11^2 with modulus x^2 + (5*b + 6)*x + 8*b + 10 - User basis matrix: - [ 1 6*b*a0 + 3*b + 1]) - ] + [ (a0, + Vector space of degree 2 and dimension 1 over + Univariate Quotient Polynomial Ring in a0 over + Finite Field in b of size 11^2 + with modulus x^2 + (5*b + 6)*x + 8*b + 10 + User basis matrix: + [ 1 6*b*a0 + 3*b + 1]) ] TESTS: We make sure that :trac:`13308` is fixed. :: - sage: M = ModularSymbols(Gamma1(23), sign=1) - sage: m = M.cuspidal_subspace().hecke_matrix(2) - sage: [j*m==i[0]*j for i in m.eigenspaces_left(format='all') for j in i[1].basis()] # long time (4s) + sage: M = ModularSymbols(Gamma1(23), sign=1) # needs sage.modular + sage: m = M.cuspidal_subspace().hecke_matrix(2) # needs sage.modular + sage: [j*m == i[0]*j # long time (4s) # needs sage.modular + ....: for i in m.eigenspaces_left(format='all') for j in i[1].basis()] [True, True, True, True, True, True, True, True, True, True, True, True] sage: B = matrix(QQ, 2, 3, range(6)) @@ -6442,40 +6537,47 @@ cdef class Matrix(Matrix1): We compute the right eigenspaces of a `3\times 3` rational matrix. :: - sage: A = matrix(QQ, 3 ,3, range(9)); A + sage: # needs sage.rings.number_field + sage: A = matrix(QQ, 3, 3, range(9)); A [0 1 2] [3 4 5] [6 7 8] sage: A.eigenspaces_right() - [ - (0, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (-1.348469228349535?, Vector space of degree 3 and dimension 1 over Algebraic Field - User basis matrix: - [ 1 0.1303061543300932? -0.7393876913398137?]), - (13.34846922834954?, Vector space of degree 3 and dimension 1 over Algebraic Field - User basis matrix: - [ 1 3.069693845669907? 5.139387691339814?]) - ] + [ (0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (-1.348469228349535?, + Vector space of degree 3 and dimension 1 over Algebraic Field + User basis matrix: + [ 1 0.1303061543300932? -0.7393876913398137?]), + (13.34846922834954?, + Vector space of degree 3 and dimension 1 over Algebraic Field + User basis matrix: + [ 1 3.069693845669907? 5.139387691339814?]) ] sage: es = A.eigenspaces_right(format='galois'); es - [ - (0, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5]) - ] - sage: es = A.eigenspaces_right(format='galois', algebraic_multiplicity=True); es - [ - (0, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1], 1), - (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5], 1) - ] + [ (0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (a1, + Vector space of degree 3 and dimension 1 over + Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5]) ] + sage: es = A.eigenspaces_right(format='galois', + ....: algebraic_multiplicity=True); es + [ (0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1], + 1), + (a1, + Vector space of degree 3 and dimension 1 over + Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5], + 1) ] sage: e, v, n = es[0]; v = v.basis()[0] sage: delta = v*e - A*v sage: abs(abs(delta)) < 1e-10 @@ -6487,15 +6589,16 @@ cdef class Matrix(Matrix1): [0 1 2] [3 4 5] [6 7 8] - sage: A.eigenspaces_right(format='galois') - [ - (0, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5]) - ] + sage: A.eigenspaces_right(format='galois') # needs sage.rings.number_field + [ (0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (a1, + Vector space of degree 3 and dimension 1 over + Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5]) ] This method is only applicable to exact matrices. The "eigenmatrix" routines for matrices with double-precision @@ -6509,11 +6612,12 @@ cdef class Matrix(Matrix1): sage: B.eigenspaces_right() Traceback (most recent call last): ... - NotImplementedError: eigenspaces cannot be computed reliably for inexact rings such as Real Field with 53 bits of precision, + NotImplementedError: eigenspaces cannot be computed reliably + for inexact rings such as Real Field with 53 bits of precision, consult numerical or symbolic matrix classes for other options sage: em = B.change_ring(RDF).eigenmatrix_right() - sage: eigenvalues = em[0]; eigenvalues.dense_matrix() # abs tol 1e-13 + sage: eigenvalues = em[0]; eigenvalues.dense_matrix() # abs tol 1e-13 [13.348469228349522 0.0 0.0] [ 0.0 -1.348469228349534 0.0] [ 0.0 0.0 0.0] @@ -6522,6 +6626,7 @@ cdef class Matrix(Matrix1): [ 0.505774475... 0.104205787... -0.816496580...] [ 0.846785134... -0.591288087... 0.408248290...] + sage: # needs sage.symbolic sage: x, y = var('x y') sage: S = matrix([[x, y], [y, 3*x^2]]) sage: em = S.eigenmatrix_right() @@ -6582,14 +6687,14 @@ cdef class Matrix(Matrix1): right_eigenspaces = eigenspaces_right - def eigenvalues(self,extend=True): + def eigenvalues(self, extend=True): r""" Return a sequence of the eigenvalues of a matrix, with - multiplicity. If the eigenvalues are roots of polynomials in QQ, - then QQbar elements are returned that represent each separate + multiplicity. If the eigenvalues are roots of polynomials in ``QQ``, + then ``QQbar`` elements are returned that represent each separate root. - If the option extend is set to False, only eigenvalues in the base + If the option ``extend`` is set to ``False``, only eigenvalues in the base ring are considered. EXAMPLES:: @@ -6599,33 +6704,40 @@ cdef class Matrix(Matrix1): [ 4 5 6 7] [ 8 9 10 11] [12 13 14 15] - sage: sorted(a.eigenvalues(), reverse=True) + sage: sorted(a.eigenvalues(), reverse=True) # needs sage.rings.number_field [32.46424919657298?, 0, 0, -2.464249196572981?] :: - sage: a=matrix([(1, 9, -1, -1), (-2, 0, -10, 2), (-1, 0, 15, -2), (0, 1, 0, -1)]) - sage: a.eigenvalues() - [-0.9386318578049146?, 15.50655435353258?, 0.2160387521361705? - 4.713151979747493?*I, 0.2160387521361705? + 4.713151979747493?*I] + sage: a = matrix([(1, 9, -1, -1), + ....: (-2, 0, -10, 2), + ....: (-1, 0, 15, -2), + ....: (0, 1, 0, -1)]) + sage: a.eigenvalues() # needs sage.rings.number_field + [-0.9386318578049146?, + 15.50655435353258?, + 0.2160387521361705? - 4.713151979747493?*I, + 0.2160387521361705? + 4.713151979747493?*I] - A symmetric matrix a+a.transpose() should have real eigenvalues + A symmetric matrix ``a + a.transpose()`` should have real eigenvalues :: - sage: b=a+a.transpose() - sage: ev = b.eigenvalues(); ev - [-8.35066086057957?, -1.107247901349379?, 5.718651326708515?, 33.73925743522043?] + sage: b = a + a.transpose() + sage: ev = b.eigenvalues(); ev # needs sage.rings.number_field + [-8.35066086057957?, -1.107247901349379?, + 5.718651326708515?, 33.73925743522043?] - The eigenvalues are elements of QQbar, so they really represent + The eigenvalues are elements of ``QQbar``, so they really represent exact roots of polynomials, not just approximations. :: - sage: e = ev[0]; e + sage: e = ev[0]; e # needs sage.rings.number_field -8.35066086057957? - sage: p = e.minpoly(); p + sage: p = e.minpoly(); p # needs sage.rings.number_field x^4 - 30*x^3 - 171*x^2 + 1460*x + 1784 - sage: p(e) == 0 + sage: p(e) == 0 # needs sage.rings.number_field True To perform computations on the eigenvalue as an element of a number @@ -6633,42 +6745,45 @@ cdef class Matrix(Matrix1): :: - sage: e.as_number_field_element() - (Number Field in a with defining polynomial y^4 - 2*y^3 - 507*y^2 - 3972*y - 4264, - a + 7, - Ring morphism: - From: Number Field in a with defining polynomial y^4 - 2*y^3 - 507*y^2 - 3972*y - 4264 - To: Algebraic Real Field - Defn: a |--> -15.35066086057957?) + sage: e.as_number_field_element() # needs sage.rings.number_field + (Number Field in a + with defining polynomial y^4 - 2*y^3 - 507*y^2 - 3972*y - 4264, + a + 7, + Ring morphism: + From: Number Field in a with defining polynomial y^4 - 2*y^3 - 507*y^2 - 3972*y - 4264 + To: Algebraic Real Field + Defn: a |--> -15.35066086057957?) - Notice the effect of the extend option. + Notice the effect of the ``extend`` option. :: - sage: M=matrix(QQ,[[0,-1,0],[1,0,0],[0,0,2]]) - sage: M.eigenvalues() + sage: M = matrix(QQ, [[0,-1,0], [1,0,0], [0,0,2]]) + sage: M.eigenvalues() # needs sage.rings.number_field [2, -1*I, 1*I] - sage: M.eigenvalues(extend=False) + sage: M.eigenvalues(extend=False) # needs sage.rings.number_field [2] The method also works for matrices over finite fields:: - sage: M = matrix(GF(3), [[0,1,1],[1,2,0],[2,0,1]]) - sage: ev = sorted(M.eigenvalues()); ev + sage: M = matrix(GF(3), [[0,1,1], [1,2,0], [2,0,1]]) + sage: ev = sorted(M.eigenvalues()); ev # needs sage.rings.finite_rings [2*z3, 2*z3 + 1, 2*z3 + 2] - Similarly as in the case of QQbar, the eigenvalues belong to some + Similarly as in the case of ``QQbar``, the eigenvalues belong to some algebraic closure but they can be converted to elements of a finite field:: - sage: e = ev[0] - sage: e.parent() + sage: e = ev[0] # needs sage.rings.finite_rings + sage: e.parent() # needs sage.rings.finite_rings Algebraic closure of Finite Field of size 3 - sage: e.as_finite_field_element() - (Finite Field in z3 of size 3^3, 2*z3, Ring morphism: - From: Finite Field in z3 of size 3^3 - To: Algebraic closure of Finite Field of size 3 - Defn: z3 |--> z3) + sage: e.as_finite_field_element() # needs sage.rings.finite_rings + (Finite Field in z3 of size 3^3, + 2*z3, + Ring morphism: + From: Finite Field in z3 of size 3^3 + To: Algebraic closure of Finite Field of size 3 + Defn: z3 |--> z3) """ x = self.fetch('eigenvalues') if x is not None: @@ -6681,7 +6796,7 @@ cdef class Matrix(Matrix1): warn("Using generic algorithm for an inexact ring, which will probably give incorrect results due to numerical precision issues.") if not extend: - return Sequence(r for r,m in self.charpoly().roots() for _ in xrange(m)) + return Sequence(r for r,m in self.charpoly().roots() for _ in range(m)) # now we need to find a natural algebraic closure for the base ring K = self.base_ring() @@ -6737,16 +6852,15 @@ cdef class Matrix(Matrix1): :: - sage: A = matrix(QQ,3,3,range(9)); A + sage: # needs sage.rings.number_field + sage: A = matrix(QQ, 3, 3, range(9)); A [0 1 2] [3 4 5] [6 7 8] sage: es = A.eigenvectors_left(); es - [(0, [ - (1, -2, 1) - ], 1), - (-1.348469228349535?, [(1, 0.3101020514433644?, -0.3797958971132713?)], 1), - (13.34846922834954?, [(1, 1.289897948556636?, 1.579795897113272?)], 1)] + [(0, [ (1, -2, 1) ], 1), + (-1.348469228349535?, [(1, 0.3101020514433644?, -0.3797958971132713?)], 1), + (13.34846922834954?, [(1, 1.289897948556636?, 1.579795897113272?)], 1)] sage: eval, [evec], mult = es[0] sage: delta = eval*evec - evec*A sage: abs(abs(delta)) < 1e-10 @@ -6756,15 +6870,13 @@ cdef class Matrix(Matrix1): :: - sage: M=matrix(QQ,[[0,-1,0],[1,0,0],[0,0,2]]) - sage: M.eigenvectors_left() - [(2, [ - (0, 0, 1) - ], 1), (-1*I, [(1, -1*I, 0)], 1), (1*I, [(1, 1*I, 0)], 1)] - sage: M.eigenvectors_left(extend=False) - [(2, [ - (0, 0, 1) - ], 1)] + sage: M = matrix(QQ, [[0,-1,0], [1,0,0], [0,0,2]]) + sage: M.eigenvectors_left() # needs sage.rings.number_field + [(2, [ (0, 0, 1) ], 1), + (-1*I, [(1, -1*I, 0)], 1), + (1*I, [(1, 1*I, 0)], 1)] + sage: M.eigenvectors_left(extend=False) # needs sage.rings.number_field + [(2, [ (0, 0, 1) ], 1)] TESTS:: @@ -6778,13 +6890,14 @@ cdef class Matrix(Matrix1): Check the deprecation:: - sage: matrix(QQ, [[1, 2], [3, 4]]).eigenvectors_left(False) + sage: matrix(QQ, [[1, 2], [3, 4]]).eigenvectors_left(False) # needs sage.rings.number_field doctest:...: DeprecationWarning: "extend" should be used as keyword argument See https://github.com/sagemath/sage/issues/29243 for details. [] Check :trac:`30518`:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: m = matrix(K, 4, [2,4*i,-i,0, -4*i,2,-1,0, 2*i,-2,0,0, 4*i+4, 4*i-4,1-i,-2]) sage: assert all(m*v == e*v for e, vs, _ in m.eigenvectors_right() for v in vs) @@ -6811,8 +6924,6 @@ cdef class Matrix(Matrix1): from warnings import warn warn("Using generic algorithm for an inexact ring, which may result in garbage from numerical precision issues.") - V = [] - from sage.rings.qqbar import QQbar from sage.categories.homset import hom eigenspaces = self.eigenspaces_left(format='galois', algebraic_multiplicity=True) evec_list=[] @@ -6828,6 +6939,7 @@ cdef class Matrix(Matrix1): evec_eval_list.append((eigval, eigbasis, eigmult)) else: try: + from sage.rings.qqbar import QQbar eigval_conj = eigval.galois_conjugates(QQbar) except AttributeError: raise NotImplementedError("eigenvectors are not implemented for matrices with eigenvalues that are not in the fraction field of the base ring or in QQbar") @@ -6871,20 +6983,17 @@ cdef class Matrix(Matrix1): :: - sage: A = matrix(QQ,3,3,range(9)); A + sage: # needs sage.rings.number_field + sage: A = matrix(QQ, 3, 3, range(9)); A [0 1 2] [3 4 5] [6 7 8] sage: es = A.eigenvectors_right(); es - [(0, [ - (1, -2, 1) - ], 1), - (-1.348469228349535?, [(1, 0.1303061543300932?, -0.7393876913398137?)], 1), - (13.34846922834954?, [(1, 3.069693845669907?, 5.139387691339814?)], 1)] + [(0, [ (1, -2, 1) ], 1), + (-1.348469228349535?, [(1, 0.1303061543300932?, -0.7393876913398137?)], 1), + (13.34846922834954?, [(1, 3.069693845669907?, 5.139387691339814?)], 1)] sage: A.eigenvectors_right(extend=False) - [(0, [ - (1, -2, 1) - ], 1)] + [(0, [ (1, -2, 1) ], 1)] sage: eval, [evec], mult = es[0] sage: delta = eval*evec - A*evec sage: abs(abs(delta)) < 1e-10 @@ -6943,7 +7052,8 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: A = matrix(QQ,3,3,range(9)); A + sage: # needs sage.rings.number_field + sage: A = matrix(QQ, 3, 3, range(9)); A [0 1 2] [3 4 5] [6 7 8] @@ -6963,7 +7073,7 @@ cdef class Matrix(Matrix1): :: - sage: A == (~P)*D*P + sage: A == (~P)*D*P # needs sage.rings.number_field True The matrix `P` may contain zero rows corresponding to eigenvalues for @@ -6972,7 +7082,8 @@ cdef class Matrix(Matrix1): :: - sage: A = jordan_block(2,3); A + sage: # needs sage.rings.number_field + sage: A = jordan_block(2, 3); A [2 1 0] [0 2 1] [0 0 2] @@ -7001,15 +7112,15 @@ cdef class Matrix(Matrix1): sage: A = matrix.identity(CDF, 2) sage: B = matrix(CDF, [[2, 1+I], [4, 2+2*I]]) sage: D, P = A.eigenmatrix_left(B) - sage: D.diagonal() # tol 1e-14 + sage: D.diagonal() # tol 1e-14 # needs sage.symbolic [0.2 - 0.1*I, +infinity] In this case, we can still verify the eigenvector equation for the first eigenvalue and first eigenvector:: - sage: l = D[0, 0] + sage: l = D[0, 0] # needs sage.symbolic sage: v = P[0, :] - sage: (v * A - l * v * B).norm() < 1e-14 + sage: (v * A - l * v * B).norm() < 1e-14 # needs sage.symbolic True The second eigenvector is contained in the left kernel of `B`:: @@ -7034,7 +7145,7 @@ cdef class Matrix(Matrix1): sage: A = matrix(QQ, 3, 3, range(9)) sage: em = A.change_ring(RDF).eigenmatrix_left() - sage: evalues = em[0]; evalues.dense_matrix() # abs tol 1e-13 + sage: evalues = em[0]; evalues.dense_matrix() # abs tol 1e-13 [13.348469228349522 0.0 0.0] [ 0.0 -1.348469228349534 0.0] [ 0.0 0.0 0.0] @@ -7070,21 +7181,24 @@ cdef class Matrix(Matrix1): the algebraic multiplicity. The following examples show that these cases are detected (:trac:`27842`):: - sage: A = matrix(SR, [(225/548, 0, -175/274*sqrt(193/1446)), # optional - sage.symbolic + sage: # needs sage.symbolic + sage: A = matrix(SR, [(225/548, 0, -175/274*sqrt(193/1446)), ....: (0, 1/2, 0), ....: (-63/548*sqrt(723/386), 0, 49/548)]) - sage: A.eigenmatrix_left() # optional - sage.symbolic + sage: A.eigenmatrix_left() Traceback (most recent call last): ... - RuntimeError: failed to compute eigenvectors for eigenvalue ..., check eigenvectors_left() for partial results - sage: B = matrix(SR, [(1/2, -7/2*sqrt(1/386), 0, 49/2*sqrt(1/279078)), # optional - sage.symbolic + RuntimeError: failed to compute eigenvectors for eigenvalue ..., + check eigenvectors_left() for partial results + sage: B = matrix(SR, [(1/2, -7/2*sqrt(1/386), 0, 49/2*sqrt(1/279078)), ....: (-7/2*sqrt(1/386), 211/772, 0, -8425/772*sqrt(1/723)), ....: (0, 0, 1/2, 0), ....: (49/2*sqrt(1/279078), -8425/772*sqrt(1/723), 0, 561/772)]) - sage: B.eigenmatrix_left() # long time (1.2 seconds) # optional - sage.symbolic + sage: B.eigenmatrix_left() # long time (1.2 seconds) Traceback (most recent call last): ... - RuntimeError: failed to compute eigenvectors for eigenvalue ..., check eigenvectors_left() for partial results + RuntimeError: failed to compute eigenvectors for eigenvalue ..., + check eigenvectors_left() for partial results The following example shows that :trac:`12595` has been resolved:: @@ -7159,7 +7273,8 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: A = matrix(QQ,3,3,range(9)); A + sage: # needs sage.rings.number_field + sage: A = matrix(QQ, 3, 3, range(9)); A [0 1 2] [3 4 5] [6 7 8] @@ -7179,7 +7294,7 @@ cdef class Matrix(Matrix1): :: - sage: A == P*D*(~P) + sage: A == P*D*(~P) # needs sage.rings.number_field True The matrix `P` may contain zero columns corresponding to eigenvalues @@ -7188,7 +7303,8 @@ cdef class Matrix(Matrix1): :: - sage: A = jordan_block(2,3); A + sage: # needs sage.rings.number_field + sage: A = jordan_block(2, 3); A [2 1 0] [0 2 1] [0 0 2] @@ -7223,9 +7339,9 @@ cdef class Matrix(Matrix1): In this case, we can still verify the eigenvector equation for the first eigenvalue and first eigenvector:: - sage: l = D[0, 0] + sage: l = D[0, 0] # needs sage.symbolic sage: v = P[:, 0] - sage: (A * v - B * v * l).norm() < 1e-14 + sage: (A * v - B * v * l).norm() < 1e-14 # needs sage.symbolic True The second eigenvector is contained in the right kernel of `B`:: @@ -7301,8 +7417,8 @@ cdef class Matrix(Matrix1): sage: M.eigenvalue_multiplicity(1) 0 - sage: M = posets.DiamondPoset(5).coxeter_transformation() - sage: [M.eigenvalue_multiplicity(x) for x in [-1, 1]] + sage: M = posets.DiamondPoset(5).coxeter_transformation() # needs sage.graphs + sage: [M.eigenvalue_multiplicity(x) for x in [-1, 1]] # needs sage.graphs [3, 2] TESTS:: @@ -7355,7 +7471,7 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: A=matrix(3,range(9)); A + sage: A = matrix(3,range(9)); A [0 1 2] [3 4 5] [6 7 8] @@ -7409,7 +7525,8 @@ cdef class Matrix(Matrix1): sage: C.echelon_form() Traceback (most recent call last): ... - NotImplementedError: Ideal Ideal (2, x + 1) of Univariate Polynomial Ring in x over Integer Ring not principal + NotImplementedError: Ideal Ideal (2, x + 1) of Univariate + Polynomial Ring in x over Integer Ring not principal Echelon form not implemented over 'Univariate Polynomial Ring in x over Integer Ring'. sage: C = matrix(3,[2,x,x^2,x+1,3-x,-1,3,2,1/2]) sage: C.echelon_form() @@ -7455,13 +7572,15 @@ cdef class Matrix(Matrix1): [ 0 4 8 12] [ 0 0 0 0] + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: L.<w> = NumberField(x^2 - x + 2) sage: OL = L.ring_of_integers() sage: m = matrix(OL, 2, 2, [1,2,3,4+w]) sage: m.echelon_form() [ 1 2] [ 0 w - 2] - sage: E, T = m.echelon_form(transformation=True); E,T + sage: E, T = m.echelon_form(transformation=True); E, T ( [ 1 2] [ 1 0] [ 0 w - 2], [-3 1] @@ -7604,8 +7723,8 @@ cdef class Matrix(Matrix1): We compute an echelon form both over a domain and fraction field:: sage: R.<x,y> = QQ[] - sage: a = matrix(R, 2, [x,y,x,y]) - sage: a.echelon_form() # not very useful? -- why two copies of the same row? + sage: a = matrix(R, 2, [x,y, x,y]) + sage: a.echelon_form() # not very useful? -- why two copies of the same row? # needs sage.rings.function_field [x y] [x y] @@ -7619,8 +7738,9 @@ cdef class Matrix(Matrix1): We check that the echelon form works for matrices over p-adics. See :trac:`17272`:: + sage: # needs sage.rings.padics sage: R = ZpCA(5,5,print_mode='val-unit') - sage: A = matrix(R,3,3,[250,2369,1147,106,927,362,90,398,2483]) + sage: A = matrix(R, 3,3, [250,2369,1147, 106,927,362, 90,398,2483]) sage: A [5^3 * 2 + O(5^5) 2369 + O(5^5) 1147 + O(5^5)] [ 106 + O(5^5) 927 + O(5^5) 362 + O(5^5)] @@ -7665,8 +7785,8 @@ cdef class Matrix(Matrix1): Check that :trac:`34724` is fixed (indirect doctest):: - sage: a=6.12323399573677e-17 - sage: m=matrix(RR,[[-a, -1.72508242466029], [ 0.579682446302195, a]]) + sage: a = 6.12323399573677e-17 + sage: m = matrix(RR,[[-a, -1.72508242466029], [ 0.579682446302195, a]]) sage: (~m*m).norm() 1.0 """ @@ -7762,7 +7882,7 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: MS = MatrixSpace(GF(19),2,3) + sage: MS = MatrixSpace(GF(19), 2, 3) sage: C = MS.matrix([1,2,3,4,5,6]) sage: C.rank() 2 @@ -7832,9 +7952,10 @@ cdef class Matrix(Matrix1): sage: a._echelon('classical') [ 1 0 -1] [ 0 1 2] - sage: R = ZpCA(5,5,print_mode='val-unit') - sage: A = matrix(R,3,3,[250,2369,1147,106,927,362,90,398,2483]) - sage: A + + sage: # needs sage.rings.padics + sage: R = ZpCA(5, 5, print_mode='val-unit') + sage: A = matrix(R, 3, 3, [250,2369,1147, 106,927,362, 90,398,2483]); A [5^3 * 2 + O(5^5) 2369 + O(5^5) 1147 + O(5^5)] [ 106 + O(5^5) 927 + O(5^5) 362 + O(5^5)] [ 5 * 18 + O(5^5) 398 + O(5^5) 2483 + O(5^5)] @@ -7911,9 +8032,10 @@ cdef class Matrix(Matrix1): sage: P = a._echelon_in_place('classical'); a [ 1 0 -1] [ 0 1 2] - sage: R = ZpCA(5,5,print_mode='val-unit') - sage: A = matrix(R,3,3,[250,2369,1147,106,927,362,90,398,2483]) - sage: A + + sage: # needs sage.rings.padics + sage: R = ZpCA(5, 5, print_mode='val-unit') + sage: A = matrix(R,3,3,[250,2369,1147,106,927,362,90,398,2483]); A [5^3 * 2 + O(5^5) 2369 + O(5^5) 1147 + O(5^5)] [ 106 + O(5^5) 927 + O(5^5) 362 + O(5^5)] [ 5 * 18 + O(5^5) 398 + O(5^5) 2483 + O(5^5)] @@ -7943,11 +8065,11 @@ cdef class Matrix(Matrix1): [ 1.00 0.000 10.0] [0.000 1.00 1.00] """ - tm = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm'%(self._nrows, self._ncols, algorithm)) cdef Py_ssize_t start_row, c, r, nr, nc, i, best_r if self.fetch('in_echelon_form'): return self.fetch('pivots') + _ = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm' % (self._nrows, self._ncols, algorithm)) self.check_mutability() cdef Matrix A @@ -8069,12 +8191,12 @@ cdef class Matrix(Matrix1): def extended_echelon_form(self, subdivide=False, **kwds): r""" - Returns the echelon form of ``self`` augmented with an identity matrix. + Return the echelon form of ``self`` augmented with an identity matrix. INPUT: - - ``subdivide`` - default: ``False`` - determines if the - returned matrix is subdivided. See the description of the + - ``subdivide`` -- (boolean, default: ``False``) whether to + subdivide the returned matrix. See the description of the (output) below for details. - ``kwds`` - additional keywords that can be passed to the method that computes the echelon form. @@ -8215,7 +8337,7 @@ cdef class Matrix(Matrix1): sage: F.is_mutable() False sage: G = copy(F) - sage: G.subdivide([],[]); G + sage: G.subdivide([], []); G [1 0 0 0 4 6] [0 1 0 4 2 2] [0 0 1 5 2 3] @@ -8246,7 +8368,6 @@ cdef class Matrix(Matrix1): """ if subdivide not in [True, False]: raise TypeError("subdivide must be True or False, not %s" % subdivide) - R = self.base_ring() ident = self.matrix_space(self.nrows(), self.nrows()).one() E = self.augment(ident) extended = E.echelon_form(**kwds) @@ -8289,8 +8410,8 @@ cdef class Matrix(Matrix1): [ 6 1/4] [ 8 -5] - sage: B = M.as_bipartite_graph() - sage: B + sage: # needs sage.graphs + sage: B = M.as_bipartite_graph(); B Bipartite graph on 5 vertices sage: B.edges(sort=True) [(1, 4, 1/3), (1, 5, 7), (2, 4, 6), (2, 5, 1/4), (3, 4, 8), (3, 5, -5)] @@ -8318,15 +8439,14 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: M = matrix(ZZ,[[1,0],[1,0],[0,1]]) - sage: M + sage: # needs sage.groups + sage: M = matrix(ZZ,[[1,0],[1,0],[0,1]]); M [1 0] [1 0] [0 1] - sage: A = M.automorphisms_of_rows_and_columns() - sage: A + sage: A = M.automorphisms_of_rows_and_columns(); A [((), ()), ((1,2), ())] - sage: M = matrix(ZZ,[[1,1,1,1],[1,1,1,1]]) + sage: M = matrix(ZZ, [[1,1,1,1],[1,1,1,1]]) sage: A = M.automorphisms_of_rows_and_columns() sage: len(A) 48 @@ -8334,7 +8454,7 @@ cdef class Matrix(Matrix1): One can now apply these automorphisms to ``M`` to show that it leaves it invariant:: - sage: all(M.with_permuted_rows_and_columns(*i) == M for i in A) + sage: all(M.with_permuted_rows_and_columns(*i) == M for i in A) # needs sage.groups True Check that :trac:`25426` is fixed:: @@ -8344,7 +8464,7 @@ cdef class Matrix(Matrix1): ....: (1, 0, 3, 0, 2), ....: (0, 1, 0, 2, 1), ....: (0, 0, 2, 1, 2)]) - sage: j.automorphisms_of_rows_and_columns() + sage: j.automorphisms_of_rows_and_columns() # needs sage.groups [((), ()), ((1,3)(2,5), (1,3)(2,5))] """ from sage.groups.perm_gps.constructor import \ @@ -8375,9 +8495,9 @@ cdef class Matrix(Matrix1): INPUT: - ``check`` -- (default: ``False``) If ``True`` return a tuple of - the maximal matrix and the permutations taking ``self`` - to the maximal matrix. - If ``False``, return only the maximal matrix. + the maximal matrix and the permutations taking ``self`` + to the maximal matrix. + If ``False``, return only the maximal matrix. OUTPUT: @@ -8402,7 +8522,7 @@ cdef class Matrix(Matrix1): [-1 5] [ 2 4] - sage: M.permutation_normal_form(check=True) + sage: M.permutation_normal_form(check=True) # needs sage.graphs sage.groups ( [ 5 -1] [ 4 2] @@ -8413,7 +8533,7 @@ cdef class Matrix(Matrix1): TESTS:: sage: M = matrix(ZZ, [[3, 4, 5], [3, 4, 5], [3, 5, 4], [2, 0,1]]) - sage: M.permutation_normal_form() + sage: M.permutation_normal_form() # needs sage.graphs [5 4 3] [5 4 3] [4 5 3] @@ -8464,7 +8584,7 @@ cdef class Matrix(Matrix1): aM.append(aN) # We construct line l: for l in range(1, nrows - 1): - if not S == list(xrange(first_row[0] + ncols, first_row[0], -1)): + if not S == list(range(first_row[0] + ncols, first_row[0], -1)): # Sort each row with respect to S for the first matrix in X = MS X = copy(MS) SM = [sorted([(S[j], X[0][k][j]) for j in range(ncols)], reverse=True) @@ -8554,29 +8674,29 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: M = matrix(ZZ,[[1,2,3],[3,5,3],[2,6,4]]) + sage: M = matrix(ZZ, [[1,2,3], [3,5,3], [2,6,4]]) sage: M [1 2 3] [3 5 3] [2 6 4] - sage: N = matrix(ZZ,[[1,2,3],[2,6,4],[3,5,3]]) + sage: N = matrix(ZZ, [[1,2,3], [2,6,4], [3,5,3]]) sage: N [1 2 3] [2 6 4] [3 5 3] - sage: M.is_permutation_of(N) + sage: M.is_permutation_of(N) # needs sage.graphs True Some examples that are not permutations of each other:: - sage: N = matrix(ZZ,[[1,2,3],[4,5,6],[7,8,9]]) + sage: N = matrix(ZZ, [[1,2,3], [4,5,6], [7,8,9]]) sage: N [1 2 3] [4 5 6] [7 8 9] - sage: M.is_permutation_of(N) + sage: M.is_permutation_of(N) # needs sage.graphs False - sage: N = matrix(ZZ,[[1,2],[3,4]]) + sage: N = matrix(ZZ, [[1,2], [3,4]]) sage: N [1 2] [3 4] @@ -8585,7 +8705,8 @@ cdef class Matrix(Matrix1): And for when ``check`` is True:: - sage: N = matrix(ZZ,[[3,5,3],[2,6,4],[1,2,3]]) + sage: # needs sage.graphs + sage: N = matrix(ZZ, [[3,5,3], [2,6,4], [1,2,3]]) sage: N [3 5 3] [2 6 4] @@ -8812,6 +8933,7 @@ cdef class Matrix(Matrix1): EXAMPLES:: + sage: # needs sage.libs.pari sage: M = matrix(5, 5, prime_range(100)) sage: M.subdivide(2,3); M [ 2 3 5| 7 11] @@ -8840,6 +8962,7 @@ cdef class Matrix(Matrix1): Degenerate cases work too:: + sage: # needs sage.libs.pari sage: M.subdivide([2,5], [0,1,3]); M [| 2| 3 5| 7 11] [|13|17 19|23 29] @@ -8869,7 +8992,7 @@ cdef class Matrix(Matrix1): Indices do not need to be in the right order (:trac:`14064`):: - sage: M.subdivide([4, 2], [3, 1]); M + sage: M.subdivide([4, 2], [3, 1]); M # needs sage.libs.pari [ 2| 3 5| 7 11] [13|17 19|23 29] [--+-----+-----] @@ -9198,10 +9321,12 @@ cdef class Matrix(Matrix1): sage: D = A.tensor_product(B) sage: D.parent() Full MatrixSpace of 6 by 12 dense matrices over Finite Field of size 23 - sage: E = C.tensor_product(B) + sage: E = C.tensor_product(B) # needs sage.rings.finite_rings Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Finite Field of size 29' and 'Full MatrixSpace of 3 by 4 dense matrices over Finite Field of size 23' + TypeError: unsupported operand parent(s) for *: + 'Finite Field of size 29' and + 'Full MatrixSpace of 3 by 4 dense matrices over Finite Field of size 23' The input is checked to be sure it is a matrix. :: @@ -9513,14 +9638,16 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: A = matrix(QQbar, [[(1/sqrt(5))*(1+i), (1/sqrt(55))*(3+2*I), (1/sqrt(22))*(2+2*I)], - ....: [(1/sqrt(5))*(1-i), (1/sqrt(55))*(2+2*I), (1/sqrt(22))*(-3+I)], - ....: [ (1/sqrt(5))*I, (1/sqrt(55))*(3-5*I), (1/sqrt(22))*(-2)]]) - sage: A.is_unitary() + sage: A = matrix(QQbar, # needs sage.rings.number_field sage.symbolic + ....: [[(1/sqrt(5))*(1+i), (1/sqrt(55))*(3+2*I), (1/sqrt(22))*(2+2*I)], + ....: [(1/sqrt(5))*(1-i), (1/sqrt(55))*(2+2*I), (1/sqrt(22))*(-3+I)], + ....: [ (1/sqrt(5))*I, (1/sqrt(55))*(3-5*I), (1/sqrt(22))*(-2)]]) + sage: A.is_unitary() # needs sage.rings.number_field sage.symbolic True A permutation matrix is always orthogonal. :: + sage: # needs sage.combinat sage: sigma = Permutation([1,3,4,5,2]) sage: P = sigma.to_matrix(); P [1 0 0 0 0] @@ -9530,9 +9657,9 @@ cdef class Matrix(Matrix1): [0 0 0 1 0] sage: P.is_unitary() True - sage: P.change_ring(GF(3)).is_unitary() + sage: P.change_ring(GF(3)).is_unitary() # needs sage.rings.finite_rings True - sage: P.change_ring(GF(3)).is_unitary() + sage: P.change_ring(GF(3)).is_unitary() # needs sage.rings.finite_rings True A square matrix far from unitary. :: @@ -9543,7 +9670,7 @@ cdef class Matrix(Matrix1): Rectangular matrices are never unitary. :: - sage: A = matrix(QQbar, 3, 4) + sage: A = matrix(QQbar, 3, 4) # needs sage.rings.number_field sage: A.is_unitary() False """ @@ -9582,7 +9709,7 @@ cdef class Matrix(Matrix1): sage: (2 * Matrix(5,5,1)).is_bistochastic() False - sage: (2 * Matrix(5,5,1)).is_bistochastic(normalized = False) + sage: (2 * Matrix(5,5,1)).is_bistochastic(normalized=False) True Here is a matrix whose row and column sums is 1, but not all entries are @@ -9630,6 +9757,7 @@ cdef class Matrix(Matrix1): Hermitian matrices are normal. :: + sage: # needs sage.symbolic sage: A = matrix(QQ, 5, 5, range(25)) + I*matrix(QQ, 5, 5, range(0, 50, 2)) sage: B = A*A.conjugate_transpose() sage: B.is_hermitian() @@ -9639,6 +9767,7 @@ cdef class Matrix(Matrix1): Circulant matrices are normal. :: + sage: # needs sage.graphs sage: G = graphs.CirculantGraph(20, [3, 7]) sage: D = digraphs.Circuit(20) sage: A = 3*D.adjacency_matrix() - 5*G.adjacency_matrix() @@ -9667,6 +9796,7 @@ cdef class Matrix(Matrix1): Sage has several fields besides the entire complex numbers where conjugation is non-trivial. :: + sage: # needs sage.rings.number_field sage: F.<b> = QuadraticField(-7) sage: C = matrix(F, [[-2*b - 3, 7*b - 6, -b + 3], ....: [-2*b - 3, -3*b + 2, -2*b], @@ -9678,6 +9808,7 @@ cdef class Matrix(Matrix1): A matrix that is nearly normal, but for a non-real diagonal entry. :: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[ 2, 2-I, 1+4*I], ....: [ 2+I, 3+I, 2-6*I], ....: [1-4*I, 2+6*I, 5]]) @@ -9689,8 +9820,8 @@ cdef class Matrix(Matrix1): Rectangular matrices are never normal. :: - sage: A = matrix(QQbar, 3, 4) - sage: A.is_normal() + sage: A = matrix(QQbar, 3, 4) # needs sage.rings.number_field + sage: A.is_normal() # needs sage.rings.number_field False A square, empty matrix is trivially normal. :: @@ -9755,19 +9886,20 @@ cdef class Matrix(Matrix1): try to deduce the decomposition from the matrix :: sage: L = [] - sage: L.append((9,Permutation([4, 1, 3, 5, 2]))) - sage: L.append((6,Permutation([5, 3, 4, 1, 2]))) - sage: L.append((3,Permutation([3, 1, 4, 2, 5]))) - sage: L.append((2,Permutation([1, 4, 2, 3, 5]))) - sage: M = sum([c * p.to_matrix() for (c,p) in L]) - sage: decomp = sage.combinat.permutation.bistochastic_as_sum_of_permutations(M) - sage: print(decomp) + sage: L.append((9, Permutation([4, 1, 3, 5, 2]))) + sage: L.append((6, Permutation([5, 3, 4, 1, 2]))) + sage: L.append((3, Permutation([3, 1, 4, 2, 5]))) + sage: L.append((2, Permutation([1, 4, 2, 3, 5]))) + sage: M = sum([c * p.to_matrix() for c, p in L]) + sage: from sage.combinat.permutation import bistochastic_as_sum_of_permutations + sage: decomp = bistochastic_as_sum_of_permutations(M) # needs sage.combinat + sage: print(decomp) # needs sage.combinat 2*B[[1, 4, 2, 3, 5]] + 3*B[[3, 1, 4, 2, 5]] + 9*B[[4, 1, 3, 5, 2]] + 6*B[[5, 3, 4, 1, 2]] An exception is raised when the matrix is not bistochastic:: sage: M = Matrix([[2,3],[2,2]]) - sage: decomp = sage.combinat.permutation.bistochastic_as_sum_of_permutations(M) + sage: decomp = bistochastic_as_sum_of_permutations(M) # needs sage.combinat Traceback (most recent call last): ... ValueError: The matrix is not bistochastic @@ -9803,15 +9935,17 @@ cdef class Matrix(Matrix1): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: M = random_matrix(CC, 5, 7) sage: for i in range(5): M[i,i] = 0 sage: M[4, 0] = M[0, 6] = M[4, 6] = 0 - sage: img = M.visualize_structure(); img + sage: img = M.visualize_structure(); img # needs pillow 7x5px 24-bit RGB image You can use :meth:`~sage.repl.image.Image.save` to save the resulting image:: + sage: # needs pillow sage.rings.real_mpfr sage: filename = tmp_filename(ext='.png') sage: img.save(filename) sage: with open(filename, 'rb') as fobj: @@ -9822,7 +9956,7 @@ cdef class Matrix(Matrix1): Test :trac:`17341`:: - sage: random_matrix(GF(2), 8, 586, sparse=True).visualize_structure() + sage: random_matrix(GF(2), 8, 586, sparse=True).visualize_structure() # needs pillow 512x6px 24-bit RGB image """ cdef Py_ssize_t x, y, _x, _y, v, bi, bisq @@ -9874,7 +10008,7 @@ cdef class Matrix(Matrix1): :: - sage: A = random_matrix(GF(127),200,200,density=0.3) + sage: A = random_matrix(GF(127), 200, 200, density=0.3) sage: A.density() <= 0.3 True @@ -9947,7 +10081,7 @@ cdef class Matrix(Matrix1): Test :trac:`27473`:: sage: F.<t> = LaurentSeriesRing(GF(2)) - sage: M = Matrix([[t,1],[0,t]]) + sage: M = Matrix([[t,1], [0,t]]) sage: ~M [t^-1 t^-2] [ 0 t^-1] @@ -9967,10 +10101,10 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: M = Matrix(ZZ,2,2,[5,2,3,4]) ; M + sage: M = Matrix(ZZ,2,2,[5,2,3,4]); M [5 2] [3 4] - sage: N = M.adjugate() ; N + sage: N = M.adjugate(); N [ 4 -2] [-3 5] sage: M * N @@ -9979,25 +10113,25 @@ cdef class Matrix(Matrix1): sage: N * M [14 0] [ 0 14] - sage: M = Matrix(QQ,2,2,[5/3,2/56,33/13,41/10]) ; M + sage: M = Matrix(QQ, 2, 2, [5/3,2/56, 33/13,41/10]); M [ 5/3 1/28] [33/13 41/10] - sage: N = M.adjugate() ; N + sage: N = M.adjugate(); N # needs sage.libs.pari [ 41/10 -1/28] [-33/13 5/3] - sage: M * N + sage: M * N # needs sage.libs.pari [7363/1092 0] [ 0 7363/1092] An alias is :meth:`adjoint_classical`, which replaces the deprecated :meth:`adjoint` method:: - sage: M.adjoint() + sage: M.adjoint() # needs sage.libs.pari ...: DeprecationWarning: adjoint is deprecated. Please use adjugate instead. See https://github.com/sagemath/sage/issues/10501 for details. [ 41/10 -1/28] [-33/13 5/3] - sage: M.adjoint_classical() + sage: M.adjoint_classical() # needs sage.libs.pari [ 41/10 -1/28] [-33/13 5/3] @@ -10065,9 +10199,10 @@ cdef class Matrix(Matrix1): Finally, an example over a general ring ``S`` that is not an integral domain:: + sage: # needs sage.libs.singular sage: R.<a,b> = QQ[] sage: S.<x,y> = R.quo((b^3)) - sage: A = matrix(S, [[x*y^2,2*x],[2,x^10*y]]) + sage: A = matrix(S, [[x*y^2, 2*x], [2, x^10*y]]) sage: A [ x*y^2 2*x] [ 2 x^10*y] @@ -10101,8 +10236,8 @@ cdef class Matrix(Matrix1): presence of non-integral powers of the variable `x` (:trac:`14403`):: - sage: x = var('x') - sage: Matrix([[sqrt(x),x],[1,0]]).adjugate() + sage: x = var('x') # needs sage.symbolic + sage: Matrix([[sqrt(x),x], [1,0]]).adjugate() # needs sage.symbolic [ 0 -x] [ -1 sqrt(x)] @@ -10177,6 +10312,7 @@ cdef class Matrix(Matrix1): For a nonsingular matrix, the QR decomposition is unique. :: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[-2, 0, -4, -1, -1], ....: [-2, 1, -6, -3, -1], ....: [1, 1, 7, 4, 5], @@ -10201,13 +10337,14 @@ cdef class Matrix(Matrix1): [ 0.?e-17 0.?e-17 1.000000000000000? 0.?e-16 0.?e-13] [ 0.?e-16 0.?e-16 0.?e-16 1.000000000000000? 0.?e-13] [ 0.?e-13 0.?e-13 0.?e-13 0.?e-13 1.0000000000000?] - sage: Q*R == A + sage: Q * R == A True An example with complex numbers in ``QQbar``, the field of algebraic numbers. :: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[-8, 4*I + 1, -I + 2, 2*I + 1], ....: [1, -2*I - 1, -I + 3, -I + 1], ....: [I + 7, 2*I + 1, -2*I + 7, -I + 1], @@ -10236,6 +10373,7 @@ cdef class Matrix(Matrix1): A rank-deficient rectangular matrix, with both values of the ``full`` keyword. :: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[2, -3, 3], ....: [-1, 1, -1], ....: [-1, 3, -3], @@ -10251,12 +10389,13 @@ cdef class Matrix(Matrix1): [ 0 3.569584777515583? -3.569584777515583?] [ 0 0 0] [ 0 0 0] - sage: Q.conjugate_transpose()*Q + sage: Q.conjugate_transpose() * Q [ 1 0.?e-18 0.?e-18 0.?e-18] [ 0.?e-18 1 0.?e-18 0.?e-18] [ 0.?e-18 0.?e-18 1.000000000000000? 0.?e-18] [ 0.?e-18 0.?e-18 0.?e-18 1.000000000000000?] + sage: # needs sage.rings.number_field sage: Q, R = A.QR(full=False) sage: Q [ 0.3592106040535498? -0.5693261797050169?] @@ -10273,6 +10412,7 @@ cdef class Matrix(Matrix1): Another rank-deficient rectangular matrix, with complex entries, as a reduced decomposition. :: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[-3*I - 3, I - 3, -12*I + 1, -2], ....: [-I - 1, -2, 5*I - 1, -I - 2], ....: [-4*I - 4, I - 5, -7*I, -I - 4]]) @@ -10287,7 +10427,7 @@ cdef class Matrix(Matrix1): sage: Q.conjugate_transpose()*Q [1 0] [0 1] - sage: Q*R-A + sage: Q*R - A [0 0 0 0] [0 0 0 0] [0 0 0 0] @@ -10295,6 +10435,7 @@ cdef class Matrix(Matrix1): Results of full decompositions are cached and thus returned immutable. :: + sage: # needs sage.rings.number_field sage: A = random_matrix(QQbar, 2, 2) sage: Q, R = A.QR() sage: Q.is_mutable() @@ -10305,6 +10446,7 @@ cdef class Matrix(Matrix1): Trivial cases return trivial results of the correct size, and we check `Q` itself in one case. :: + sage: # needs sage.rings.number_field sage: A = zero_matrix(QQbar, 0, 10) sage: Q, R = A.QR() sage: Q.nrows(), Q.ncols() @@ -10344,7 +10486,7 @@ cdef class Matrix(Matrix1): roots, though some small cases pass through. :: sage: A = matrix(ZZ, 3, 3, range(9)) - sage: A.QR() + sage: A.QR() # needs sage.symbolic Traceback (most recent call last): ... TypeError: QR decomposition unable to compute square roots in Rational Field @@ -10358,7 +10500,6 @@ cdef class Matrix(Matrix1): [2 3] [0 1] """ - from sage.modules.free_module_element import zero_vector from sage.matrix.constructor import zero_matrix, matrix from sage.misc.functional import sqrt @@ -10475,6 +10616,7 @@ cdef class Matrix(Matrix1): so we need to check with the conjugate-transpose. This example verifies that the bug on :trac:`10791` is fixed. :: + sage: # needs sage.rings.number_field sage: F.<a> = QuadraticField(-5) sage: A = matrix(F, [[ 1, a - 3, a - 2, a + 1], ....: [ a, 2*a + 1, 3*a + 1, 1], @@ -10531,7 +10673,8 @@ cdef class Matrix(Matrix1): sage: A._gram_schmidt_noscale() Traceback (most recent call last): ... - TypeError: Gram-Schmidt orthogonalization requires a base ring with a fraction field, not Ring of integers modulo 6 + TypeError: Gram-Schmidt orthogonalization requires a base ring + with a fraction field, not Ring of integers modulo 6 """ from sage.matrix.constructor import matrix, zero_matrix R = self.base_ring() @@ -10692,6 +10835,7 @@ cdef class Matrix(Matrix1): for small cases or instruction. Now we need to use the ``orthonormal`` keyword. :: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[6, -8, 1], ....: [4, 1, 3], ....: [6, 3, 3], @@ -10708,13 +10852,13 @@ cdef class Matrix(Matrix1): [ 1.492555785314984? 7.006153332071100? 1.638930357041381?] [ 2.885607851608969? 1.804330147889395? 7.963520581008761?] [ 7.064764050490923? 5.626248468100069? -1.197679876299471?] - sage: M*G-A + sage: M*G - A [0 0 0] [0 0 0] [0 0 0] [0 0 0] [0 0 0] - sage: (G*G.transpose()-identity_matrix(3)).norm() < 10^-10 + sage: (G*G.transpose() - identity_matrix(3)).norm() < 10^-10 True sage: G.row_space() == A.row_space() True @@ -10722,6 +10866,7 @@ cdef class Matrix(Matrix1): After :trac:`14047`, the matrix can also be over the algebraic reals ``AA``:: + sage: # needs sage.rings.number_field sage: A = matrix(AA, [[6, -8, 1], ....: [4, 1, 3], ....: [6, 3, 3], @@ -10743,22 +10888,24 @@ cdef class Matrix(Matrix1): Note the use of the conjugate-transpose when checking the orthonormality. :: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[ -2, -I - 1, 4*I + 2, -1], ....: [-4*I, -2*I + 17, 0, 9*I + 1], ....: [ 1, -2*I - 6, -I + 11, -5*I + 1]]) sage: G, M = A.gram_schmidt(orthonormal=True) - sage: (M*G-A).norm() < 10^-10 + sage: (M*G - A).norm() < 10^-10 True sage: id3 = G*G.conjugate().transpose() sage: (id3 - identity_matrix(3)).norm() < 10^-10 True - sage: G.row_space() == A.row_space() # long time + sage: G.row_space() == A.row_space() # long time True A square matrix with small rank. The zero vectors produced as a result of linear dependence get eliminated, so the rows of ``G`` are a basis for the row space of ``A``. :: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[2, -6, 3, 8], ....: [1, -3, 2, 5], ....: [0, 0, 2, 4], @@ -10774,12 +10921,12 @@ cdef class Matrix(Matrix1): [ 6.208757731331742? 0.6718090752798139?] [ 3.574739299857670? 2.687236301119256?] [10.630145812734649? 0] - sage: M*G-A + sage: M*G - A [0 0 0 0] [0 0 0 0] [0 0 0 0] [0 0 0 0] - sage: (G*G.transpose()-identity_matrix(2)).norm() < 10^-10 + sage: (G*G.transpose() - identity_matrix(2)).norm() < 10^-10 True sage: G.row_space() == A.row_space() True @@ -10825,10 +10972,12 @@ cdef class Matrix(Matrix1): A complex subfield of the complex numbers. :: + sage: # needs sage.rings.number_field sage: C.<z> = CyclotomicField(5) - sage: A = matrix(C, [[ -z^3 - 2*z, -z^3 - 1, 2*z^3 - 2*z^2 + 2*z, 1], - ....: [ z^3 - 2*z^2 + 1, -z^3 + 2*z^2 - z - 1, -1, z^2 + z], - ....: [-1/2*z^3 - 2*z^2 + z + 1, -z^3 + z - 2, -2*z^3 + 1/2*z^2, 2*z^2 - z + 2]]) + sage: A = matrix(C, + ....: [[ -z^3 - 2*z, -z^3 - 1, 2*z^3 - 2*z^2 + 2*z, 1], + ....: [ z^3 - 2*z^2 + 1, -z^3 + 2*z^2 - z - 1, -1, z^2 + z], + ....: [-1/2*z^3 - 2*z^2 + z + 1, -z^3 + z - 2, -2*z^3 + 1/2*z^2, 2*z^2 - z + 2]]) sage: G, M = A.gram_schmidt(orthonormal=False) sage: G [ -z^3 - 2*z -z^3 - 1 2*z^3 - 2*z^2 + 2*z 1] @@ -10950,6 +11099,7 @@ cdef class Matrix(Matrix1): EXAMPLES:: + sage: # needs sage.combinat sage: a = matrix(ZZ,4,[1, 0, 0, 0, 0, 1, 0, 0, ....: 1, -1, 1, 0, 1, -1, 1, 2]); a [ 1 0 0 0] @@ -10984,8 +11134,8 @@ cdef class Matrix(Matrix1): Here we need to specify a field, since the eigenvalues are not defined in the smallest ring containing the matrix entries (:trac:`14508`):: - sage: c = matrix([[0,1,0],[0,0,1],[1,0,0]]) - sage: c.jordan_form(CyclotomicField(3)) + sage: c = matrix([[0,1,0], [0,0,1], [1,0,0]]) + sage: c.jordan_form(CyclotomicField(3)) # needs sage.combinat sage.rings.number_field [ 1| 0| 0] [----------+----------+----------] [ 0| zeta3| 0] @@ -10995,20 +11145,20 @@ cdef class Matrix(Matrix1): If you need the transformation matrix as well as the Jordan form of ``self``, then pass the option ``transformation=True``. For example:: - sage: m = matrix([[5,4,2,1],[0,1,-1,-1],[-1,-1,3,0],[1,1,-1,2]]); m + sage: m = matrix([[5,4,2,1], [0,1,-1,-1], [-1,-1,3,0], [1,1,-1,2]]); m [ 5 4 2 1] [ 0 1 -1 -1] [-1 -1 3 0] [ 1 1 -1 2] - sage: jf, p = m.jordan_form(transformation=True) - sage: jf + sage: jf, p = m.jordan_form(transformation=True) # needs sage.combinat + sage: jf # needs sage.combinat [2|0|0 0] [-+-+---] [0|1|0 0] [-+-+---] [0|0|4 1] [0|0|0 4] - sage: ~p * m * p + sage: ~p * m * p # needs sage.combinat [2 0 0 0] [0 1 0 0] [0 0 4 1] @@ -11018,8 +11168,8 @@ cdef class Matrix(Matrix1): compute the Jordan normal form, since it is not numerically stable:: - sage: b = matrix(ZZ,3,3,range(9)) - sage: jf, p = b.jordan_form(RealField(15), transformation=True) + sage: b = matrix(ZZ, 3, 3, range(9)) + sage: jf, p = b.jordan_form(RealField(15), transformation=True) # needs sage.combinat Traceback (most recent call last): ... ValueError: Jordan normal form not implemented over inexact rings. @@ -11030,13 +11180,14 @@ cdef class Matrix(Matrix1): [1 1 1] [1 1 1] [1 1 1] - sage: c.jordan_form(subdivide=False) + sage: c.jordan_form(subdivide=False) # needs sage.combinat [3 0 0] [0 0 0] [0 0 0] :: + sage: # needs sage.combinat sage: evals = [(i,i) for i in range(1,6)] sage: n = sum(range(1,6)) sage: jf = block_diagonal_matrix([jordan_block(ev,size) for ev,size in evals]) @@ -11047,13 +11198,16 @@ cdef class Matrix(Matrix1): sage: mjf == jf True sage: m = diagonal_matrix([1,1,0,0]) - sage: jf,P = m.jordan_form(transformation=True) + sage: jf, P = m.jordan_form(transformation=True) sage: jf == ~P*m*P True We verify that the bug from :trac:`6942` is fixed:: - sage: M = Matrix(GF(2),[[1,0,1,0,0,0,1],[1,0,0,1,1,1,0],[1,1,0,1,1,1,1],[1,1,1,0,1,1,1],[1,1,1,0,0,1,0],[1,1,1,0,1,0,0],[1,1,1,1,1,1,0]]) + sage: # needs sage.combinat + sage: M = Matrix(GF(2),[[1,0,1,0,0,0,1], [1,0,0,1,1,1,0], [1,1,0,1,1,1,1], + ....: [1,1,1,0,1,1,1], [1,1,1,0,0,1,0], [1,1,1,0,1,0,0], + ....: [1,1,1,1,1,1,0]]) sage: J, T = M.jordan_form(transformation=True) sage: J [1 1|0 0|0 0|0] @@ -11075,8 +11229,8 @@ cdef class Matrix(Matrix1): We verify that the bug from :trac:`6932` is fixed:: - sage: M=Matrix(1,1,[1]) - sage: M.jordan_form(transformation=True) + sage: M = Matrix(1, 1, [1]) + sage: M.jordan_form(transformation=True) # needs sage.combinat ([1], [1]) We now go through three `10 \times 10` matrices to exhibit cases where @@ -11093,7 +11247,7 @@ cdef class Matrix(Matrix1): [ 20 26/3 -66 -199/3 -42 -41/3 0 13/3 -55/3 -2/3] [ 18 57 -9 -54 -57 0 0 0 -15 0] [ 0 0 0 0 0 0 0 0 0 3] - sage: J, T = A.jordan_form(transformation=True); J + sage: J, T = A.jordan_form(transformation=True); J # needs sage.combinat [3 1 0|0 0 0|0 0 0|0] [0 3 1|0 0 0|0 0 0|0] [0 0 3|0 0 0|0 0 0|0] @@ -11107,9 +11261,9 @@ cdef class Matrix(Matrix1): [0 0 0|0 0 0|0 0 3|0] [-----+-----+-----+-] [0 0 0|0 0 0|0 0 0|3] - sage: T * J * T**(-1) == A + sage: T * J * T**(-1) == A # needs sage.combinat True - sage: T.rank() + sage: T.rank() # needs sage.combinat 10 :: @@ -11125,7 +11279,7 @@ cdef class Matrix(Matrix1): [ 20 26/3 -66 -28/3 -42 -41/3 0 13/3 2/3 82/3] [ 18 57 -9 0 -57 0 0 0 3 28] [ 0 0 0 0 0 0 0 0 0 3] - sage: J, T = A.jordan_form(transformation=True); J + sage: J, T = A.jordan_form(transformation=True); J # needs sage.combinat [3 1 0|0 0 0|0 0|0 0] [0 3 1|0 0 0|0 0|0 0] [0 0 3|0 0 0|0 0|0 0] @@ -11139,9 +11293,9 @@ cdef class Matrix(Matrix1): [-----+-----+---+---] [0 0 0|0 0 0|0 0|3 1] [0 0 0|0 0 0|0 0|0 3] - sage: T * J * T**(-1) == A + sage: T * J * T**(-1) == A # needs sage.combinat True - sage: T.rank() + sage: T.rank() # needs sage.combinat 10 :: @@ -11157,7 +11311,7 @@ cdef class Matrix(Matrix1): [ 20 26/3 -30 -199/3 -42 -14/3 70 13/3 -55/3 -2/3] [ 18 57 -9 -54 -57 0 63 0 -15 0] [ 0 0 0 0 0 0 0 0 0 3] - sage: J, T = A.jordan_form(transformation=True); J + sage: J, T = A.jordan_form(transformation=True); J # needs sage.combinat [3 1 0|0 0|0 0|0 0|0] [0 3 1|0 0|0 0|0 0|0] [0 0 3|0 0|0 0|0 0|0] @@ -11172,15 +11326,16 @@ cdef class Matrix(Matrix1): [0 0 0|0 0|0 0|0 3|0] [-----+---+---+---+-] [0 0 0|0 0|0 0|0 0|3] - sage: T * J * T**(-1) == A + sage: T * J * T**(-1) == A # needs sage.combinat True - sage: T.rank() + sage: T.rank() # needs sage.combinat 10 Verify that we smoothly move to QQ from ZZ (:trac:`12693`), i.e. we work in the vector space over the field:: - sage: M = matrix(((2,2,2),(0,0,0),(-2,-2,-2))) + sage: # needs sage.combinat + sage: M = matrix(((2,2,2), (0,0,0), (-2,-2,-2))) sage: J, P = M.jordan_form(transformation=True) sage: J; P [0 1|0] @@ -11207,16 +11362,16 @@ cdef class Matrix(Matrix1): sage: Qx = PolynomialRing(QQ, 'x11, x12, x13, x21, x22, x23, x31, x32, x33') sage: x11, x12, x13, x21, x22, x23, x31, x32, x33 = Qx.gens() sage: M = matrix(Qx, [[0, 0, x31], [0, 0, x21], [0, 0, 0]]) # This is a nilpotent matrix. - sage: M.jordan_form(eigenvalues=[(0, 3)]) + sage: M.jordan_form(eigenvalues=[(0, 3)]) # needs sage.combinat [0 1|0] [0 0|0] [---+-] [0 0|0] - sage: M.jordan_form(eigenvalues=[(0, 2)]) + sage: M.jordan_form(eigenvalues=[(0, 2)]) # needs sage.combinat Traceback (most recent call last): ... ValueError: The provided list of eigenvalues is not correct. - sage: M.jordan_form(transformation=True, eigenvalues=[(0, 3)]) + sage: M.jordan_form(transformation=True, eigenvalues=[(0, 3)]) # needs sage.combinat ( [0 1|0] [0 0|0] [x31 0 1] @@ -11228,17 +11383,17 @@ cdef class Matrix(Matrix1): and it needs to be implemented. :: sage: A = matrix(Integers(6), 2, 2, range(4)) - sage: A.jordan_form() + sage: A.jordan_form() # needs sage.combinat Traceback (most recent call last): ... ValueError: Matrix entries must be from a field, not Ring of integers modulo 6 Test for :trac:`10563`:: - sage: R = FractionField(PolynomialRing(RationalField(),'a')) + sage: R = FractionField(PolynomialRing(RationalField(), 'a')) sage: a = R.gen() - sage: A = matrix(R,[[1,a],[a,1]]) - sage: A.jordan_form() + sage: A = matrix(R, [[1,a], [a,1]]) + sage: A.jordan_form() # needs sage.combinat [ a + 1| 0] [------+------] [ 0|-a + 1] @@ -11320,7 +11475,7 @@ cdef class Matrix(Matrix1): C = B*C ranks.append(C.rank()) i += 1 - diagram = [ranks[i]-ranks[i+1] for i in xrange(len(ranks)-1)] + diagram = [ranks[i]-ranks[i+1] for i in range(len(ranks)-1)] blocks.extend([(eval, i) for i in Partition(diagram).conjugate()]) @@ -11405,6 +11560,7 @@ cdef class Matrix(Matrix1): EXAMPLES:: + sage: # needs sage.libs.pari sage: A = matrix(QQ, 4, [-4, 6, 3, 3, -3, 5, 3, 3, 3, -6, -4, -3, -3, 6, 3, 2]) sage: A [-4 6 3 3] @@ -11424,18 +11580,19 @@ cdef class Matrix(Matrix1): sage: P^-1*A*P == D True + sage: # needs sage.libs.pari sage: A = matrix(QQ, 2, [0, 2, 1, 0]) sage: A.is_diagonalizable() False - sage: A.is_diagonalizable(QQbar) + sage: A.is_diagonalizable(QQbar) # needs sage.rings.number_field True - sage: D, P = A.diagonalization(QQbar) - sage: P^-1*A*P == D + sage: D, P = A.diagonalization(QQbar) # needs sage.rings.number_field + sage: P^-1*A*P == D # needs sage.rings.number_field True Matrices may fail to be diagonalizable for various reasons:: - sage: A = matrix(QQ, 2, [1,2,3,4,5,6]) + sage: A = matrix(QQ, 2, [1,2,3, 4,5,6]) sage: A [1 2 3] [4 5 6] @@ -11466,7 +11623,7 @@ cdef class Matrix(Matrix1): sage: D [0 2] [1 0] - sage: D.diagonalization() + sage: D.diagonalization() # needs sage.libs.pari Traceback (most recent call last): ... ValueError: not diagonalizable over Rational Field @@ -11475,11 +11632,11 @@ cdef class Matrix(Matrix1): sage: E [3 1] [0 3] - sage: E.diagonalization() + sage: E.diagonalization() # needs sage.libs.pari Traceback (most recent call last): ... ValueError: not diagonalizable - sage: E.jordan_form() + sage: E.jordan_form() # needs sage.combinat [3 1] [0 3] """ @@ -11562,9 +11719,9 @@ cdef class Matrix(Matrix1): ....: [ 9, -8, 11, -12, 51], ....: [ 3, -4, 0, -1, 9], ....: [-1, 0, -4, 4, -12]]) - sage: A.is_diagonalizable() + sage: A.is_diagonalizable() # needs sage.libs.pari True - sage: A.diagonalization() + sage: A.diagonalization() # needs sage.libs.pari ( [ 2 0 0 0 0] [ 1 1 0 1 0] [ 0 3 0 0 0] [ 1/2 0 1 0 1] @@ -11581,9 +11738,9 @@ cdef class Matrix(Matrix1): ....: [-2, -14, 0, 0, 10], ....: [3, 13, -2, 0, -11], ....: [-1, 6, 1, -3, 1]]) - sage: A.is_diagonalizable() + sage: A.is_diagonalizable() # needs sage.libs.pari False - sage: A.jordan_form(subdivide=False) + sage: A.jordan_form(subdivide=False) # needs sage.libs.pari [-1 1 0 0 0] [ 0 -1 0 0 0] [ 0 0 2 1 0] @@ -11600,24 +11757,25 @@ cdef class Matrix(Matrix1): ....: [2, -1, 1, 0, -2], ....: [0, -1, -1, -5, -8]]) - sage: [e in QQ for e in A.eigenvalues()] + sage: [e in QQ for e in A.eigenvalues()] # needs sage.rings.number_field [False, False, False, False, False] - sage: A.is_diagonalizable() + sage: A.is_diagonalizable() # needs sage.libs.pari False - sage: A.diagonalization() + sage: A.diagonalization() # needs sage.libs.pari Traceback (most recent call last): ... ValueError: not diagonalizable over Rational Field - sage: [e in QQbar for e in A.eigenvalues()] + sage: [e in QQbar for e in A.eigenvalues()] # needs sage.rings.number_field [True, True, True, True, True] - sage: A.is_diagonalizable(base_field=QQbar) + sage: A.is_diagonalizable(base_field=QQbar) # needs sage.rings.number_field True Other exact fields may be employed, though it will not always be possible to extend their base fields to contain all the eigenvalues. :: + sage: # needs sage.rings.finite_rings sage: F.<b> = FiniteField(5^2) sage: A = matrix(F, [[ 4, 3*b + 2, 3*b + 1, 3*b + 4], ....: [2*b + 1, 4*b, 0, 2], @@ -11632,6 +11790,7 @@ cdef class Matrix(Matrix1): [ 0 0|2*b + 1 1] [ 0 0| 0 2*b + 1] + sage: # needs sage.rings.number_field sage: F.<c> = QuadraticField(-7) sage: A = matrix(F, [[ c + 3, 2*c - 2, -2*c + 2, c - 1], ....: [2*c + 10, 13*c + 15, -13*c - 17, 11*c + 31], @@ -11650,7 +11809,7 @@ cdef class Matrix(Matrix1): A trivial matrix is diagonalizable, trivially. :: sage: A = matrix(QQ, 0, 0) - sage: A.is_diagonalizable() + sage: A.is_diagonalizable() # needs sage.libs.pari True A matrix must be square to be diagonalizable. :: @@ -11803,6 +11962,8 @@ cdef class Matrix(Matrix1): ....: [ 0, 6, 1]]) sage: A.is_similar(B) True + + sage: # needs sage.libs.pari sage: _, T = A.is_similar(B, transformation=True) sage: T [ 1.00000000000000? + 0.?e-14*I 0.?e-14 + 0.?e-14*I 0.?e-14 + 0.?e-14*I] @@ -11817,13 +11978,14 @@ cdef class Matrix(Matrix1): Other exact fields are supported. :: + sage: # needs sage.rings.finite_rings sage: F.<a> = FiniteField(7^2) - sage: A = matrix(F,[[2*a + 5, 6*a + 6, a + 3], - ....: [ a + 3, 2*a + 2, 4*a + 2], - ....: [2*a + 6, 5*a + 5, 3*a]]) - sage: B = matrix(F,[[5*a + 5, 6*a + 4, a + 1], - ....: [ a + 5, 4*a + 3, 3*a + 3], - ....: [3*a + 5, a + 4, 5*a + 6]]) + sage: A = matrix(F, [[2*a + 5, 6*a + 6, a + 3], + ....: [ a + 3, 2*a + 2, 4*a + 2], + ....: [2*a + 6, 5*a + 5, 3*a]]) + sage: B = matrix(F, [[5*a + 5, 6*a + 4, a + 1], + ....: [ a + 5, 4*a + 3, 3*a + 3], + ....: [3*a + 5, a + 4, 5*a + 6]]) sage: A.is_similar(B) True sage: B.is_similar(A) @@ -11833,7 +11995,7 @@ cdef class Matrix(Matrix1): [ 1 0 0] [6*a + 1 4*a + 3 4*a + 2] [6*a + 3 3*a + 5 3*a + 6] - sage: A == T.inverse()*B*T + sage: A == T.inverse() * B * T True Two matrices with different sets of eigenvalues, so they @@ -11847,7 +12009,7 @@ cdef class Matrix(Matrix1): ....: [-1, 2, -3, -7], ....: [-2, 3, -4, -7], ....: [ 0, -1, 0, 0]]) - sage: A.eigenvalues() == B.eigenvalues() + sage: A.eigenvalues() == B.eigenvalues() # needs sage.rings.number_field False sage: A.is_similar(B, transformation=True) (False, None) @@ -11865,7 +12027,7 @@ cdef class Matrix(Matrix1): sage: B = matrix(QQ, [[-38, -63, 42], ....: [ 14, 25, -14], ....: [-14, -21, 18]]) - sage: A.charpoly() == B.charpoly() + sage: A.charpoly() == B.charpoly() # needs sage.libs.pari True sage: A.rational_form() [ 0 0 -48] @@ -11892,9 +12054,10 @@ cdef class Matrix(Matrix1): design, but we are not able to resurrect a similarity transformation. :: + sage: # needs sage.rings.finite_rings sage: F.<a> = FiniteField(7^2) - sage: C = matrix(F,[[ a + 2, 5*a + 4], - ....: [6*a + 6, 6*a + 4]]) + sage: C = matrix(F, [[ a + 2, 5*a + 4], + ....: [6*a + 6, 6*a + 4]]) sage: S = matrix(F, [[0, 1], ....: [1, 0]]) sage: D = S.inverse()*C*S @@ -11914,9 +12077,10 @@ cdef class Matrix(Matrix1): algebraic closure of this field to find the change-of-basis matrix:: + sage: # needs sage.combinat sage.graphs sage.rings.finite_rings sage: cox = posets.TamariLattice(3).coxeter_transformation() sage: M = cox.change_ring(GF(3)) - sage: M.is_similar(M**3, True) # long time + sage: M.is_similar(M**3, True) # long time ( [1 0 0 0 0] [0 1 1 0 2] @@ -11951,7 +12115,7 @@ cdef class Matrix(Matrix1): sage: A = matrix(GF(3), 2, 2, range(4)) sage: B = matrix(GF(2), 2, 2, range(4)) - sage: A.is_similar(B, transformation=True) + sage: A.is_similar(B, transformation=True) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: @@ -11965,8 +12129,8 @@ cdef class Matrix(Matrix1): of ``QQ`` in ``QQbar``). :: sage: A = matrix(ZZ, 2, 2, range(4)) - sage: B = matrix(QQbar, 2, 2, range(4)) - sage: A.is_similar(B) + sage: B = matrix(QQbar, 2, 2, range(4)) # needs sage.rings.number_field + sage: A.is_similar(B) # needs sage.rings.number_field True TESTS: @@ -12063,7 +12227,7 @@ cdef class Matrix(Matrix1): Returns a pair (F, C) such that the rows of C form a symplectic basis for self and F = C \* self \* C.transpose(). - Raises a ValueError if not over a field, or self is not + Raises a :class:`ValueError` if not over a field, or self is not anti-symmetric, or self is not alternating. Anti-symmetric means that `M = -M^t`. Alternating means @@ -12375,7 +12539,7 @@ cdef class Matrix(Matrix1): ... TypeError: first input should be a vector, not junk - sage: A.cyclic_subspace(v, var=sin(x)) + sage: A.cyclic_subspace(v, var=sin(x)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: polynomial variable must be a string or polynomial ring generator, not sin(x) @@ -12415,10 +12579,10 @@ cdef class Matrix(Matrix1): ... TypeError: matrix entries must be from an exact field, not Ring of integers modulo 6 - sage: F.<a> = GF(2^4) + sage: F.<a> = GF(2^4) # needs sage.rings.finite_rings sage: G = matrix(QQ, 4, range(16)) - sage: w = vector(F, 4, [1, a, a^2, a^3]) - sage: G.cyclic_subspace(w) + sage: w = vector(F, 4, [1, a, a^2, a^3]) # needs sage.rings.finite_rings + sage: G.cyclic_subspace(w) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: unable to make vector entries compatible with matrix entries @@ -12428,7 +12592,7 @@ cdef class Matrix(Matrix1): R = self.base_ring() if not is_Vector(v): raise TypeError('first input should be a vector, not {0}'.format(v)) - if not (var is None or isinstance(var, basestring)): + if not (var is None or isinstance(var, str)): generator = False try: generator = var.is_gen() @@ -12540,8 +12704,7 @@ cdef class Matrix(Matrix1): ....: [ 2, -7, 4, 7]]) sage: A.is_symmetric() True - sage: L = A.cholesky() - sage: L + sage: L = A.cholesky(); L [ 2 0 0 0] [-1 3 0 0] [ 2 0 2 0] @@ -12562,21 +12725,21 @@ cdef class Matrix(Matrix1): ....: [ -2, -18, -38, 15]]) sage: A.is_symmetric() True - sage: L = A.cholesky() - sage: L + sage: L = A.cholesky(); L # needs sage.rings.number_field [ 8.83176086632785? 0 0 0] [ -3.396831102433787? 9.51112708681461? 0 0] [ -4.189425026335004? 17.32383862241232? 2.886751345948129? 0] [-0.2264554068289192? -1.973397116652010? -1.649572197684645? 2.886751345948129?] - sage: L.parent() + sage: L.parent() # needs sage.rings.number_field Full MatrixSpace of 4 by 4 dense matrices over Algebraic Real Field - sage: L*L.transpose() == A + sage: L*L.transpose() == A # needs sage.rings.number_field True Some subfields of the complex numbers, such as this number field of complex numbers with rational real and imaginary parts, allow for this computation:: + sage: # needs sage.rings.number_field sage: C.<I> = QuadraticField(-1) sage: A = matrix(C, [[ 23, 17*I + 3, 24*I + 25, 21*I], ....: [ -17*I + 3, 38, -69*I + 89, 7*I + 15], @@ -12584,8 +12747,7 @@ cdef class Matrix(Matrix1): ....: [ -21*I, -7*I + 15, -24*I + 6, 28]]) sage: A.is_hermitian() True - sage: L = A.cholesky() - sage: L + sage: L = A.cholesky(); L [ 4.79...? 0 0 0] [ 0.62...? - 3.54...?*I 5.00...? 0 0] [ 5.21...? - 5.00...?*I 13.58...? + 10.72...?*I 24.98...? 0] @@ -12598,6 +12760,7 @@ cdef class Matrix(Matrix1): The field of algebraic numbers is an ideal setting for this computation:: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[ 2, 4 + 2*I, 6 - 4*I], ....: [ -2*I + 4, 11, 10 - 12*I], ....: [ 4*I + 6, 10 + 12*I, 37]]) @@ -12646,8 +12809,8 @@ cdef class Matrix(Matrix1): Even symbolic matrices can sometimes be factored:: - sage: A = matrix(SR, [[pi,0], [0,pi]]) # optional - sage.symbolic - sage: A.cholesky() # optional - sage.symbolic + sage: A = matrix(SR, [[pi,0], [0,pi]]) # needs sage.symbolic + sage: A.cholesky() # needs sage.symbolic [sqrt(pi) 0] [ 0 sqrt(pi)] @@ -12666,15 +12829,16 @@ cdef class Matrix(Matrix1): The matrix may not be Hermitian:: - sage: F.<a> = FiniteField(5^4) - sage: A = matrix(F, [[2+a^3, 3], [3, 3]]) - sage: A.cholesky() + sage: F.<a> = FiniteField(5^4) # needs sage.rings.finite_rings + sage: A = matrix(F, [[2+a^3, 3], [3, 3]]) # needs sage.rings.finite_rings + sage: A.cholesky() # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: matrix is not Hermitian The matrix may not be positive-definite:: + sage: # needs sage.rings.number_field sage: C.<I> = QuadraticField(-1) sage: B = matrix(C, [[ 2, 4 - 2*I, 2 + 2*I], ....: [4 + 2*I, 8, 10*I], @@ -12706,11 +12870,11 @@ cdef class Matrix(Matrix1): sage: E = matrix(QQ, [[2, 1], [1, 1]]) sage: E.is_symmetric() True - sage: E.eigenvalues() + sage: E.eigenvalues() # needs sage.rings.number_field [0.38...?, 2.61...?] sage: E.det() 1 - sage: E.cholesky() + sage: E.cholesky() # needs sage.rings.number_field [ 1.414213562373095? 0] [0.7071067811865475? 0.7071067811865475?] @@ -12722,7 +12886,7 @@ cdef class Matrix(Matrix1): Rational Field sage: E = matrix(QQ, [[2, 1], [1, 1]]) - sage: E.cholesky().base_ring() + sage: E.cholesky().base_ring() # needs sage.rings.number_field Algebraic Real Field Check that sparse floating-point matrices can be factored @@ -12732,17 +12896,17 @@ cdef class Matrix(Matrix1): sage: A.cholesky() [1.0 0.0] [1.0 1.0] - sage: A = matrix(CDF, [[1, I], [-I, 2]], sparse=True) + sage: A = matrix(CDF, [[1, I], [-I, 2]], sparse=True) # needs sage.rings.number_field sage: A.cholesky() [ 1.0 0.0] [-1.0*I 1.0] Try the trivial case (:trac:`33107`):: - sage: all( matrix(R,[]).cholesky() == matrix(R,[]) + sage: all( matrix(R,[]).cholesky() == matrix(R,[]) # needs sage.rings.number_field ....: for R in (RR,CC,RDF,CDF,ZZ,QQ,AA,QQbar) ) True - sage: all( matrix(R,[]).cholesky().is_immutable() + sage: all( matrix(R,[]).cholesky().is_immutable() # needs sage.rings.number_field ....: for R in (RR,CC,RDF,CDF,ZZ,QQ,AA,QQbar) ) True @@ -12872,6 +13036,7 @@ cdef class Matrix(Matrix1): A matrix containing real roots:: + sage: # needs sage.rings.number_field sage.symbolic sage: A = matrix(AA, [ [1, 0, sqrt(2)], ....: [0, sqrt(3), 0 ], ....: [sqrt(2), 0, sqrt(5)] ]) @@ -12887,6 +13052,7 @@ cdef class Matrix(Matrix1): A Hermitian (but not symmetric) matrix with complex entries:: + sage: # needs sage.rings.number_field sage.symbolic sage: A = matrix(QQbar, [ [ 1, 0, I ], ....: [ 0, sqrt(5), 0 ], ....: [-I, 0, 3 ] ]) @@ -12925,6 +13091,7 @@ cdef class Matrix(Matrix1): and rational one because inverting a matrix with algebraic entries is harder and requires smaller test cases:: + sage: # needs sage.rings.number_field sage: from sage.misc.prandom import choice sage: n = ZZ.random_element(2) sage: ring = choice([AA, QQbar]) @@ -13187,13 +13354,15 @@ cdef class Matrix(Matrix1): sage: P, L, U = A.LU() Traceback (most recent call last): ... - TypeError: base ring of the matrix must be exact, not Real Field with 100 bits of precision + TypeError: base ring of the matrix must be exact, + not Real Field with 100 bits of precision sage: A = matrix(Integers(6), 3, 2, range(6)) sage: A.LU() Traceback (most recent call last): ... - TypeError: base ring of the matrix needs a field of fractions, not Ring of integers modulo 6 + TypeError: base ring of the matrix needs a field of fractions, + not Ring of integers modulo 6 sage: R.<y> = PolynomialRing(QQ, 'y') sage: B = matrix(R, [[y+1, y^2+y], [y^2, y^3]]) @@ -13216,6 +13385,7 @@ cdef class Matrix(Matrix1): sage: B == P*L*U True + sage: # needs sage.rings.finite_rings sage: F.<a> = FiniteField(5^2) sage: C = matrix(F, [[a + 3, 4*a + 4, 2, 4*a + 2], ....: [3, 2*a + 4, 2*a + 4, 2*a + 1], @@ -13227,17 +13397,17 @@ cdef class Matrix(Matrix1): [0 1 0 0] [0 0 1 0] [0 0 0 1] - sage: L + sage: L # needs sage.combinat [ 1 0 0 0] [3*a + 3 1 0 0] [ 2*a 4*a + 2 1 0] [2*a + 3 2 2*a + 4 1] - sage: U + sage: U # needs sage.combinat [ a + 3 4*a + 4 2 4*a + 2] [ 0 a + 1 a + 3 2*a + 4] [ 0 0 1 4*a + 2] [ 0 0 0 0] - sage: L.base_ring() + sage: L.base_ring() # needs sage.combinat Finite Field in a of size 5^2 sage: C == P*L*U True @@ -13316,6 +13486,7 @@ cdef class Matrix(Matrix1): absolute value must be handled carefully. This tests that situation in the case of cyclotomic fields. :: + sage: # needs sage.groups sage.rings.number_field sage: C = SymmetricGroup(5).character_table() sage: C.base_ring() Cyclotomic Field of order 1 and degree 1 @@ -13379,7 +13550,7 @@ cdef class Matrix(Matrix1): M = self.change_ring(F) m, n = M._nrows, M._ncols d = min(m, n) - perm = list(xrange(m)) + perm = list(range(m)) zero = F(0) for k in range(d): max_location = -1 @@ -13496,7 +13667,8 @@ cdef class Matrix(Matrix1): A Hermitian matrix. :: - sage: x = var('x') + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ) sage: C.<I> = NumberField(x^2 + 1) sage: A = matrix(C, [[ 23, 17*I + 3, 24*I + 25, 21*I], ....: [ -17*I + 3, 38, -69*I + 89, 7*I + 15], @@ -13577,7 +13749,7 @@ cdef class Matrix(Matrix1): ... ValueError: matrix is not symmetric (maybe try the 'hermitian' keyword) - sage: A = matrix([[3, 2+3*I], [5+6*I, 12]]) + sage: A = matrix([[3, 2+3*I], [5+6*I, 12]]) # needs sage.rings.number_field sage: A._indefinite_factorization('hermitian', check=True) Traceback (most recent call last): ... @@ -13779,6 +13951,7 @@ cdef class Matrix(Matrix1): with rational real and imaginary parts. As theory predicts, the diagonal entries will be real numbers. :: + sage: # needs sage.rings.number_field sage: C.<I> = QuadraticField(-1) sage: B = matrix(C, [[ 2, 4 - 2*I, 2 + 2*I], ....: [4 + 2*I, 8, 10*I], @@ -13821,6 +13994,7 @@ cdef class Matrix(Matrix1): may be factored. This provides a reasonable alternative to the Cholesky decomposition. :: + sage: # needs sage.rings.finite_rings sage: F.<a> = FiniteField(5^3) sage: A = matrix(F, ....: [[ a^2 + 2*a, 4*a^2 + 3*a + 4, 3*a^2 + a, 2*a^2 + 2*a + 1], @@ -14247,6 +14421,7 @@ cdef class Matrix(Matrix1): The same is true of the following complex Hermitian matrix:: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [ [ 0,I], ....: [-I,0] ]) sage: A.block_ldlt(classical=True) @@ -14341,11 +14516,11 @@ cdef class Matrix(Matrix1): An indefinite Hermitian matrix that happens to have a classical factorization:: - sage: F.<I> = QuadraticField(-1) - sage: A = matrix(F, [[ 2, 4 - 2*I, 2 + 2*I], + sage: F.<I> = QuadraticField(-1) # needs sage.rings.number_field + sage: A = matrix(F, [[ 2, 4 - 2*I, 2 + 2*I], # needs sage.rings.number_field ....: [4 + 2*I, 8, 10*I], ....: [2 - 2*I, -10*I, -3]]) - sage: A.block_ldlt(classical=True)[1:] + sage: A.block_ldlt(classical=True)[1:] # needs sage.rings.number_field ( [ 2| 0| 0] [--+--+--] @@ -14376,6 +14551,7 @@ cdef class Matrix(Matrix1): Ensure that a "random" complex Hermitian matrix is factored correctly:: + sage: # needs sage.rings.number_field sage: n = ZZ.random_element(6) sage: F = QuadraticField(-1, 'I') sage: A = matrix.random(F, n) @@ -14388,12 +14564,13 @@ cdef class Matrix(Matrix1): factored correctly and that the resulting block-diagonal matrix is in fact diagonal:: + sage: # needs sage.rings.number_field sage: n = ZZ.random_element(6) sage: F = QuadraticField(-1, 'I') sage: A = matrix.random(F, n) - sage: A = A*A.conjugate_transpose() + sage: A = A * A.conjugate_transpose() sage: P,L,D = A.block_ldlt() - sage: A == P*L*D*L.conjugate_transpose()*P.conjugate_transpose() + sage: A == P * L * D * L.conjugate_transpose() * P.conjugate_transpose() True sage: diagonal_matrix(D.diagonal()) == D True @@ -14529,7 +14706,7 @@ cdef class Matrix(Matrix1): sage: A = matrix(QQ, [ [2,1], ....: [1,2] ] ) - sage: A.eigenvalues() + sage: A.eigenvalues() # needs sage.rings.number_field [3, 1] sage: A.is_positive_semidefinite() True @@ -14538,7 +14715,7 @@ cdef class Matrix(Matrix1): sage: A = matrix(QQ, [ [1,1], ....: [1,1] ] ) - sage: A.eigenvalues() + sage: A.eigenvalues() # needs sage.rings.number_field [2, 0] sage: A.is_positive_semidefinite() True @@ -14547,7 +14724,7 @@ cdef class Matrix(Matrix1): sage: A = matrix(QQ, [ [0,1], ....: [1,0] ] ) - sage: A.eigenvalues() + sage: A.eigenvalues() # needs sage.rings.number_field [1, -1] sage: A.is_positive_semidefinite() False @@ -14557,7 +14734,7 @@ cdef class Matrix(Matrix1): sage: A = matrix(QQ, [ [2,1], ....: [0,0] ]) - sage: A.eigenvalues() + sage: A.eigenvalues() # needs sage.rings.number_field [2, 0] sage: A.is_positive_semidefinite() False @@ -14598,27 +14775,28 @@ cdef class Matrix(Matrix1): a Hermitian matrix (for a non-Hermitian matrix, both "obviously" return ``False``):: - sage: F = QuadraticField(-1, 'I') + sage: rings = [ZZ, QQ, RDF, CDF] + sage: rings.append(QuadraticField(-1, 'I')) # needs sage.rings.number_field sage: from sage.misc.prandom import choice - sage: ring = choice([ZZ, QQ, F, RDF, CDF]) + sage: ring = choice(rings) sage: A = matrix.random(ring, 10); A = A + A.conjugate_transpose() sage: def is_positive_semidefinite_naive(A): ....: if A.nrows() == 0: ....: return True ....: return ( A.is_hermitian() and ....: all(v >= 0 for v in A.eigenvalues()) ) - sage: expected = is_positive_semidefinite_naive(A) + sage: expected = is_positive_semidefinite_naive(A) # needs numpy sage: actual = A.is_positive_semidefinite() - sage: actual == expected + sage: actual == expected # needs numpy True We reject matrices whose base fields cannot be coerced to either real numbers, complex numbers, or symbolics; otherwise we risk returning nonsensical results:: - sage: F = FiniteField(5^2) - sage: A = matrix.identity(F, 1) - sage: A.is_positive_semidefinite() + sage: F = FiniteField(5^2) # needs sage.rings.finite_rings + sage: A = matrix.identity(F, 1) # needs sage.rings.finite_rings + sage: A.is_positive_semidefinite() # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: Could not see Finite Field in z2 of size 5^2 @@ -14726,6 +14904,8 @@ cdef class Matrix(Matrix1): confirmed by the positive determinants of its leading principal submatrices:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: C.<I> = NumberField(x^2 + 1, embedding=CC(0,1)) sage: A = matrix(C, [[ 23, 17*I + 3, 24*I + 25, 21*I], ....: [ -17*I + 3, 38, -69*I + 89, 7*I + 15], @@ -14739,6 +14919,7 @@ cdef class Matrix(Matrix1): An Hermitian matrix that is not positive-definite and a vector ``u`` that makes the corresponding quadratic form negative:: + sage: # needs sage.rings.number_field sage: C.<I> = QuadraticField(-1) sage: B = matrix(C, [[ 2, 4 - 2*I, 2 + 2*I], ....: [4 + 2*I, 8, 10*I], @@ -14753,12 +14934,13 @@ cdef class Matrix(Matrix1): confirmed by the positive determinants of its leading principal submatrices:: + sage: # needs sage.rings.number_field sage: A = matrix(QQbar, [[ 2, 4 + 2*I, 6 - 4*I], ....: [ -2*I + 4, 11, 10 - 12*I], ....: [ 4*I + 6, 10 + 12*I, 37]]) sage: A.is_positive_definite() True - sage: [A[:i,:i].determinant() for i in range(1,A.nrows()+1)] + sage: [A[:i,:i].determinant() for i in range(1, A.nrows() + 1)] [2, 2, 6] TESTS: @@ -14767,6 +14949,7 @@ cdef class Matrix(Matrix1): numbers, complex numbers, or symbolic ring, then this routine will fail since comparison to zero is meaningless:: + sage: # needs sage.rings.finite_rings sage: F.<a> = FiniteField(5^3) sage: a.conjugate() Traceback (most recent call last): @@ -14791,11 +14974,13 @@ cdef class Matrix(Matrix1): We can check positive-definiteness of matrices over approximate real/complex and symbolic rings:: + sage: # needs sage.rings.real_mpfr sage: matrix.identity(RR,4).is_positive_definite() True sage: matrix.identity(CC,4).is_positive_definite() True - sage: matrix.identity(SR,4).is_positive_definite() # optional - sage.symbolic + + sage: matrix.identity(SR,4).is_positive_definite() # needs sage.symbolic True """ result = self._is_positive_definite_or_semidefinite(False) @@ -14866,14 +15051,13 @@ cdef class Matrix(Matrix1): (automatically) using MPFR instead of doubles, since doubles overflow:: - sage: a = matrix(ZZ, 2, [2^10000,3^10000,2^50,3^19292]) + sage: a = matrix(ZZ, 2, [2^10000, 3^10000, 2^50, 3^19292]) sage: a.hadamard_bound() 12215 sage: len(str(a.det())) 12215 """ from sage.rings.real_double import RDF - from sage.rings.real_mpfr import RealField try: A = self.change_ring(RDF) m1 = A._hadamard_row_bound() @@ -14881,13 +15065,14 @@ cdef class Matrix(Matrix1): m2 = A._hadamard_row_bound() return min(m1, m2) except (OverflowError, TypeError): + from sage.rings.real_mpfr import RealField # Try using MPFR, which handles large numbers much better, but is slower. - from . import misc + from .misc_mpfr import hadamard_row_bound_mpfr R = RealField(53, rnd='RNDU') A = self.change_ring(R) - m1 = misc.hadamard_row_bound_mpfr(A) + m1 = hadamard_row_bound_mpfr(A) A = A.transpose() - m2 = misc.hadamard_row_bound_mpfr(A) + m2 = hadamard_row_bound_mpfr(A) return min(m1, m2) def find(self,f, indices=False): @@ -14914,7 +15099,7 @@ cdef class Matrix(Matrix1): EXAMPLES:: sage: M = matrix(4,3,[1, -1/2, -1, 1, -1, -1/2, -1, 0, 0, 2, 0, 1]) - sage: M.find(lambda entry:entry==0) + sage: M.find(lambda entry: entry == 0) [0 0 0] [0 0 0] [0 1 1] @@ -14922,7 +15107,7 @@ cdef class Matrix(Matrix1): :: - sage: M.find(lambda u:u<0) + sage: M.find(lambda u: u < 0) [0 1 1] [0 1 1] [1 0 0] @@ -14936,7 +15121,7 @@ cdef class Matrix(Matrix1): :: - sage: M.find(lambda u:u!=1/2) + sage: M.find(lambda u: u != 1/2) [1 1 1] [1 1 1] [1 1 1] @@ -14944,7 +15129,7 @@ cdef class Matrix(Matrix1): :: - sage: M.find(lambda u:u>1.2) + sage: M.find(lambda u: u > 1.2) [0 0 0] [0 0 0] [0 0 0] @@ -14952,7 +15137,7 @@ cdef class Matrix(Matrix1): :: - sage: sorted(M.find(lambda u:u!=0,indices=True).keys()) == M.nonzero_positions() + sage: sorted(M.find(lambda u: u != 0, indices=True).keys()) == M.nonzero_positions() True """ from sage.matrix.matrix_space import MatrixSpace @@ -14996,21 +15181,22 @@ cdef class Matrix(Matrix1): A matrix over a not-totally-real number field:: - sage: K.<j> = NumberField(x^2+5) - sage: M = matrix(K, [[1+j,1], [0,2*j]]) - sage: M.conjugate() + sage: x = polygen(ZZ, 'x') + sage: K.<j> = NumberField(x^2 + 5) # needs sage.rings.number_field + sage: M = matrix(K, [[1+j,1], [0,2*j]]) # needs sage.rings.number_field + sage: M.conjugate() # needs sage.rings.number_field [-j + 1 1] [ 0 -2*j] There is a shortcut for the conjugate:: - sage: M.C + sage: M.C # needs sage.rings.number_field [-j + 1 1] [ 0 -2*j] There is also a shortcut for the conjugate transpose, or "Hermitian transpose":: - sage: M.H + sage: M.H # needs sage.rings.number_field [-j + 1 0] [ 1 -2*j] @@ -15051,14 +15237,17 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: M = matrix(SR, 2, 2, [[2-I, 3+4*I], [9-6*I, 5*I]]) # optional - sage.symbolic - sage: M.base_ring() # optional - sage.symbolic + sage: M = matrix(SR, 2, 2, [[2-I, 3+4*I], [9-6*I, 5*I]]) # needs sage.symbolic + sage: M.base_ring() # needs sage.symbolic Symbolic Ring - sage: M.conjugate_transpose() # optional - sage.symbolic + sage: M.conjugate_transpose() # needs sage.symbolic [ I + 2 6*I + 9] [-4*I + 3 -5*I] - sage: P = matrix(CC, 3, 2, [0.95-0.63*I, 0.84+0.13*I, 0.94+0.23*I, 0.23+0.59*I, 0.52-0.41*I, -0.50+0.90*I]) + sage: # needs sage.rings.real_mpfr sage.symbolic + sage: P = matrix(CC, 3, 2, [0.95-0.63*I, 0.84+0.13*I, + ....: 0.94+0.23*I, 0.23+0.59*I, + ....: 0.52-0.41*I, -0.50+0.90*I]) sage: P.base_ring() Complex Field with 53 bits of precision sage: P.conjugate_transpose() @@ -15067,7 +15256,7 @@ cdef class Matrix(Matrix1): There is also a shortcut for the conjugate transpose, or "Hermitian transpose":: - sage: M.H + sage: M.H # needs sage.symbolic [ I + 2 6*I + 9] [-4*I + 3 -5*I] @@ -15084,6 +15273,7 @@ cdef class Matrix(Matrix1): (Matrices over quadratic number fields are another class of examples.) :: + sage: # needs sage.rings.number_field sage: C = CyclotomicField(5) sage: a = C.gen(); a zeta5 @@ -15097,11 +15287,11 @@ cdef class Matrix(Matrix1): Furthermore, this method can be applied to matrices over quadratic extensions of finite fields:: - sage: F.<a> = GF(9,'a') - sage: N = matrix(F, 2, [0,a,-a,1]); N + sage: F.<a> = GF(9,'a') # needs sage.rings.finite_rings + sage: N = matrix(F, 2, [0,a,-a,1]); N # needs sage.rings.finite_rings [ 0 a] [2*a 1] - sage: N.conjugate_transpose() + sage: N.conjugate_transpose() # needs sage.rings.finite_rings [ 0 a + 2] [2*a + 1 1] @@ -15112,7 +15302,8 @@ cdef class Matrix(Matrix1): sage: N.conjugate_transpose() Traceback (most recent call last): ... - AttributeError: 'sage.rings.finite_rings.integer_mod.IntegerMod_int' object has no attribute 'conjugate' + AttributeError: 'sage.rings.finite_rings.integer_mod.IntegerMod_int' object + has no attribute 'conjugate' """ # limited testing on a 1000 x 1000 matrix over CC: # transpose is fast, conjugate is slow @@ -15127,8 +15318,7 @@ cdef class Matrix(Matrix1): INPUT: - - ``self`` - a matrix whose entries are coercible into - CDF + - ``self`` - a matrix whose entries are coercible into ``CDF`` - ``p`` - one of the following options: @@ -15163,6 +15353,8 @@ cdef class Matrix(Matrix1): sage: Id = identity_matrix(12) sage: Id.norm(2) 1.0 + + sage: # needs sage.rings.real_mpfr sage: A = matrix(RR, 2, 2, [13,-4,-4,7]) sage: A.norm() # rel tol 2e-16 14.999999999999998 @@ -15171,6 +15363,7 @@ cdef class Matrix(Matrix1): Faster routines for double precision entries from `RDF` or `CDF` are provided by the :class:`~sage.matrix.matrix_double_dense.Matrix_double_dense` class. :: + sage: # needs sage.rings.real_mpfr sage: A = matrix(CC, 2, 3, [3*I,4,1-I,1,2,0]) sage: A.norm('frob') 5.656854249492381 @@ -15203,7 +15396,7 @@ cdef class Matrix(Matrix1): if p == 2: A = self.change_ring(CDF) A = A.conjugate().transpose() * A - U, S, V = A.SVD() + S = A.SVD()[1] return max(S.list()).real().sqrt() A = self.apply_map(abs, R=RDF) @@ -15239,32 +15432,24 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: d = matrix([[3, 0],[0,sqrt(2)]]) - sage: b = matrix([[1, -1], [2, 2]]) ; e = b * d * b.inverse();e + sage: # needs sage.symbolic + sage: d = matrix([[3, 0], [0, sqrt(2)]]) + sage: b = matrix([[1, -1], [2, 2]]); e = b * d * b.inverse(); e [ 1/2*sqrt(2) + 3/2 -1/4*sqrt(2) + 3/4] [ -sqrt(2) + 3 1/2*sqrt(2) + 3/2] - - :: - sage: e.numerical_approx(53) [ 2.20710678118655 0.396446609406726] [ 1.58578643762690 2.20710678118655] - - :: - sage: e.numerical_approx(20) [ 2.2071 0.39645] [ 1.5858 2.2071] - - :: - - sage: (e-I).numerical_approx(20) + sage: (e - I).numerical_approx(20) [2.2071 - 1.0000*I 0.39645] [ 1.5858 2.2071 - 1.0000*I] :: - sage: M=matrix(QQ,4,[i/(i+1) for i in range(12)]);M + sage: M = matrix(QQ, 4, [i/(i+1) for i in range(12)]); M [ 0 1/2 2/3] [ 3/4 4/5 5/6] [ 6/7 7/8 8/9] @@ -15280,7 +15465,7 @@ cdef class Matrix(Matrix1): :: - sage: matrix(SR, 2, 2, range(4)).n() # optional - sage.symbolic + sage: matrix(SR, 2, 2, range(4)).n() # needs sage.symbolic [0.000000000000000 1.00000000000000] [ 2.00000000000000 3.00000000000000] @@ -15294,9 +15479,9 @@ cdef class Matrix(Matrix1): We check that :trac:`29700` is fixed:: - sage: M = matrix(3,[1,1,1,1,0,0,0,1,0]) - sage: A,B = M.diagonalization(QQbar) - sage: _ = A.n() + sage: M = matrix(3, [1,1,1,1,0,0,0,1,0]) + sage: A, B = M.diagonalization(QQbar) # needs sage.rings.number_field + sage: _ = A.n() # needs sage.rings.number_field """ from sage.rings.real_mpfr import RealField @@ -15331,21 +15516,21 @@ cdef class Matrix(Matrix1): A matrix over ZZ colored with different grey levels:: sage: A = matrix([[1,3,5,1],[2,4,5,6],[1,3,5,7]]) - sage: A.plot() + sage: A.plot() # needs sage.plot Graphics object consisting of 1 graphics primitive - Here we make a random matrix over RR and use cmap='hsv' to color + Here we make a random matrix over ``RR`` and use ``cmap='hsv'`` to color the matrix elements different RGB colors (see documentation for ``matrix_plot`` for more information on cmaps):: sage: A = random_matrix(RDF, 50) - sage: plot(A, cmap='hsv') + sage: plot(A, cmap='hsv') # needs sage.plot Graphics object consisting of 1 graphics primitive Another random plot, but over GF(389):: sage: A = random_matrix(GF(389), 10) - sage: A.plot(cmap='Oranges') + sage: A.plot(cmap='Oranges') # needs sage.plot Graphics object consisting of 1 graphics primitive """ from sage.plot.matrix_plot import matrix_plot @@ -15361,6 +15546,7 @@ cdef class Matrix(Matrix1): EXAMPLES:: + sage: # needs sage.symbolic sage: v = vector([1,x,x^2]) sage: v.derivative(x) (0, 1, 2*x) @@ -15396,34 +15582,36 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: a=matrix([[1,2],[3,4]]) + sage: # needs sage.symbolic + sage: a = matrix([[1,2], [3,4]]) sage: a.exp() [-1/22*((sqrt(33) - 11)*e^sqrt(33) - sqrt(33) - 11)*e^(-1/2*sqrt(33) + 5/2) 2/33*(sqrt(33)*e^sqrt(33) - sqrt(33))*e^(-1/2*sqrt(33) + 5/2)] [ 1/11*(sqrt(33)*e^sqrt(33) - sqrt(33))*e^(-1/2*sqrt(33) + 5/2) 1/22*((sqrt(33) + 11)*e^sqrt(33) - sqrt(33) + 11)*e^(-1/2*sqrt(33) + 5/2)] - sage: type(a.exp()) + sage: type(a.exp()) # needs sage.symbolic <class 'sage.matrix.matrix_symbolic_dense.Matrix_symbolic_dense'> - sage: a=matrix([[1/2,2/3],[3/4,4/5]]) - sage: a.exp() + sage: a = matrix([[1/2,2/3], [3/4,4/5]]) + sage: a.exp() # needs sage.symbolic [-1/418*((3*sqrt(209) - 209)*e^(1/10*sqrt(209)) - 3*sqrt(209) - 209)*e^(-1/20*sqrt(209) + 13/20) 20/627*(sqrt(209)*e^(1/10*sqrt(209)) - sqrt(209))*e^(-1/20*sqrt(209) + 13/20)] [ 15/418*(sqrt(209)*e^(1/10*sqrt(209)) - sqrt(209))*e^(-1/20*sqrt(209) + 13/20) 1/418*((3*sqrt(209) + 209)*e^(1/10*sqrt(209)) - 3*sqrt(209) + 209)*e^(-1/20*sqrt(209) + 13/20)] - sage: a=matrix(RR,[[1,pi.n()],[1e2,1e-2]]) - sage: a.exp() + sage: a = matrix(RR, [[1,pi.n()], [1e2,1e-2]]) # needs sage.symbolic + sage: a.exp() # needs sage.symbolic [ 1/11882424341266*((11*sqrt(227345670387496707609) + 5941212170633)*e^(3/1275529100*sqrt(227345670387496707609)) - 11*sqrt(227345670387496707609) + 5941212170633)*e^(-3/2551058200*sqrt(227345670387496707609) + 101/200) 445243650/75781890129165569203*(sqrt(227345670387496707609)*e^(3/1275529100*sqrt(227345670387496707609)) - sqrt(227345670387496707609))*e^(-3/2551058200*sqrt(227345670387496707609) + 101/200)] [ 10000/53470909535697*(sqrt(227345670387496707609)*e^(3/1275529100*sqrt(227345670387496707609)) - sqrt(227345670387496707609))*e^(-3/2551058200*sqrt(227345670387496707609) + 101/200) -1/11882424341266*((11*sqrt(227345670387496707609) - 5941212170633)*e^(3/1275529100*sqrt(227345670387496707609)) - 11*sqrt(227345670387496707609) - 5941212170633)*e^(-3/2551058200*sqrt(227345670387496707609) + 101/200)] - sage: a.change_ring(RDF).exp() # rel tol 1e-14 + sage: a.change_ring(RDF).exp() # rel tol 1e-14 # needs sage.symbolic [42748127.31532951 7368259.244159399] [234538976.1381042 40426191.45156228] TESTS: - Check that sparse matrices are handled correctly (:trac:`28935`):: + Sparse matrices are handled correctly (:trac:`28935`), but may + require a patched version of maxima (:trac:`32898`) for now:: - sage: matrix.diagonal([0], sparse=True).exp() + sage: matrix.diagonal([0], sparse=True).exp() # not tested # needs sage.symbolic [1] - sage: matrix.zero(CBF, 2, sparse=True).exp() + sage: matrix.zero(CBF, 2, sparse=True).exp() # needs sage.libs.flint sage.symbolic [1.000000000000000 0] [ 0 1.000000000000000] """ @@ -15433,26 +15621,31 @@ cdef class Matrix(Matrix1): from sage.symbolic.ring import SR return self.change_ring(SR).exp() - def elementary_divisors(self): + def elementary_divisors(self, algorithm=None): r""" - If self is a matrix over a principal ideal domain R, return + If ``self`` is a matrix over a principal ideal domain `R`, return elements `d_i` for `1 \le i \le k = \min(r,s)` where `r` and `s` are the number of rows and - columns of self, such that the cokernel of self is isomorphic to + columns of self, such that the cokernel of ``self`` is isomorphic to .. MATH:: R/(d_1) \oplus R/(d_2) \oplus R/(d_k) with `d_i \mid d_{i+1}` for all `i`. These are - the diagonal entries of the Smith form of self (see - :meth:`smith_form()`). + the diagonal entries of the Smith form of ``self`` (see + :meth:`smith_form`). + + INPUT: + + - ``algorithm`` -- ignored EXAMPLES:: - sage: OE.<w> = EquationOrder(x^2 - x + 2) - sage: m = Matrix([ [1, w],[w,7]]) - sage: m.elementary_divisors() + sage: x = polygen(ZZ, 'x') + sage: OE.<w> = EquationOrder(x^2 - x + 2) # needs sage.rings.number_field + sage: m = Matrix([[1, w], [w, 7]]) # needs sage.rings.number_field + sage: m.elementary_divisors() # needs sage.rings.number_field [1, -w + 9] .. SEEALSO:: @@ -15461,7 +15654,7 @@ cdef class Matrix(Matrix1): """ d = self.smith_form(transformation=False) r = min(self.nrows(), self.ncols()) - return [d[i,i] for i in xrange(r)] + return [d[i,i] for i in range(r)] def smith_form(self, transformation=True, integral=None, exact=True): r""" @@ -15541,8 +15734,10 @@ cdef class Matrix(Matrix1): An example over the ring of integers of a number field (of class number 1):: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: OE.<w> = EquationOrder(x^2 - x + 2) - sage: m = Matrix([ [1, w],[w,7]]) + sage: m = Matrix([[1, w], [w, 7]]) sage: d, u, v = m.smith_form() sage: (d, u, v) ( @@ -15558,7 +15753,8 @@ cdef class Matrix(Matrix1): An example over the polynomial ring QQ[x]:: - sage: R.<x> = QQ[]; m=x*matrix(R,2,2,1) - matrix(R, 2,2,[3,-4,1,-1]); m.smith_form() + sage: R.<x> = QQ[]; m = x*matrix(R, 2, 2, 1) - matrix(R, 2, 2, [3,-4,1,-1]) + sage: m.smith_form() ( [ 1 0] [ 0 -1] [ 1 x + 1] [ 0 x^2 - 2*x + 1], [ 1 x - 3], [ 0 1] @@ -15566,12 +15762,13 @@ cdef class Matrix(Matrix1): An example over a field:: - sage: m = matrix( GF(17), 3, 3, [11,5,1,3,6,8,1,16,0]); d,u,v = m.smith_form() + sage: m = matrix(GF(17), 3, 3, [11,5,1, 3,6,8, 1,16,0]) + sage: d, u, v = m.smith_form() sage: d [1 0 0] [0 1 0] [0 0 0] - sage: u*m*v == d + sage: u * m * v == d True When the base ring has a ``ring_of_integers`` method and supports denominators, @@ -15591,45 +15788,57 @@ cdef class Matrix(Matrix1): Some examples over non-PID's work anyway:: - sage: R.<s> = EquationOrder(x^2 + 5) # class number 2 - sage: A = matrix(R, 2, 2, [s-1,-s,-s,2*s+1]) + sage: # needs sage.rings.number_field + sage: R.<s> = EquationOrder(x^2 + 5) # class number 2 + sage: A = matrix(R, 2, 2, [s - 1, -s, -s, 2*s + 1]) sage: D, U, V = A.smith_form() sage: D, U, V ( [ 1 0] [ 4 s + 4] [ 1 -5*s + 6] [ 0 -s - 6], [ s s - 1], [ 0 1] ) - sage: D == U*A*V + sage: D == U * A * V True Others don't, but they fail quite constructively:: - sage: matrix(R,2,2,[s-1,-s-2,-2*s,-s-2]).smith_form() + sage: matrix(R, 2, 2, [s - 1, -s - 2, -2*s, -s - 2]).smith_form() # needs sage.rings.number_field Traceback (most recent call last): ... ArithmeticError: Ideal Fractional ideal (2, s + 1) not principal Empty matrices are handled safely:: - sage: m = MatrixSpace(OE, 2,0)(0); d,u,v=m.smith_form(); u*m*v == d + sage: # needs sage.rings.number_field + sage: m = MatrixSpace(OE, 2,0)(0) + sage: d, u, v = m.smith_form(); u * m * v == d True - sage: m = MatrixSpace(OE, 0,2)(0); d,u,v=m.smith_form(); u*m*v == d + sage: m = MatrixSpace(OE, 0,2)(0) + sage: d, u, v = m.smith_form(); u * m * v == d True - sage: m = MatrixSpace(OE, 0,0)(0); d,u,v=m.smith_form(); u*m*v == d + sage: m = MatrixSpace(OE, 0,0)(0) + sage: d, u, v = m.smith_form(); u * m * v == d True Some pathological cases that crashed earlier versions:: - sage: m = Matrix(OE, [[2*w,2*w-1,-w+1],[2*w+2,-2*w-1,w-1],[-2*w-1,-2*w-2,2*w-1]]); d, u, v = m.smith_form(); u * m * v == d + sage: # needs sage.rings.number_field + sage: m = Matrix(OE, [[ 2*w, 2*w - 1, -w + 1], + ....: [ 2*w + 2, -2*w - 1, w - 1], + ....: [-2*w - 1, -2*w - 2, 2*w - 1]]) + sage: d, u, v = m.smith_form(); u * m * v == d True - sage: m = matrix(OE, 3, 3, [-5*w-1,-2*w-2,4*w-10,8*w,-w,w-1,-1,1,-8]); d,u,v = m.smith_form(); u*m*v == d + sage: m = matrix(OE, [[-5*w - 1, -2*w - 2, 4*w - 10], + ....: [ 8*w, -w, w - 1], + ....: [ -1, 1, -8]]) + sage: d, u, v = m.smith_form(); u * m * v == d True Over local fields, we can request the transformation matrices to be integral:; - sage: K = Qp(2, 5, print_mode='terse') - sage: M = matrix(K, 2, 3, [1/2, 1, 2, 1/3, 1, 3]) - sage: M.smith_form(integral=True) + sage: K = Qp(2, 5, print_mode='terse') # needs sage.rings.padics + sage: M = matrix(K, 2, 3, [1/2, 1, 2, 1/3, 1, 3]) # needs sage.rings.padics + sage: M.smith_form(integral=True) # needs sage.rings.padics ( [1/2 + O(2^4) 0 0] [ 1 + O(2^5) 0] [ 0 1 + O(2^5) 0], [42 + O(2^6) 1 + O(2^5)], @@ -15678,7 +15887,6 @@ cdef class Matrix(Matrix1): dd, uu, vv = mm.smith_form(transformation=True) else: dd = mm.smith_form(transformation=False) - mone = self.new_matrix(1, 1, [1]) d = dd.new_matrix(1,1,[t[0,0]]).block_sum(dd) if transformation: u = uu.new_matrix(1,1,[1]).block_sum(uu) * u @@ -15693,6 +15901,148 @@ cdef class Matrix(Matrix1): else: return dp + def fitting_ideal(self, i): + r""" + Return the `i`-th Fitting ideal of the matrix. This is the ideal generated + by the `n - i` minors, where `n` is the number of columns. + + INPUT: + + ``i`` -- an integer + + OUTPUT: + + An ideal on the base ring. + + EXAMPLES:: + + sage: R.<x,y,z> = QQ[] + sage: M = matrix(R, [[2*x-z, 0, y-z^2, 1], [0, z - y, z - x, 0],[z - y, x^2 - y, 0, 0]]) + sage: M + [ 2*x - z 0 -z^2 + y 1] + [ 0 -y + z -x + z 0] + [ -y + z x^2 - y 0 0] + sage: [R.ideal(M.minors(i)) == M.fitting_ideal(4-i) for i in range(5)] + [True, True, True, True, True] + sage: M.fitting_ideal(0) + Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: M.fitting_ideal(1) + Ideal (2*x^4 - 3*x^3*z + x^2*z^2 + y^2*z^2 - 2*y*z^3 + z^4 - 2*x^2*y - y^3 + 3*x*y*z + 2*y^2*z - 2*y*z^2, -x^3 + x^2*z + x*y - y*z, y^2 - 2*y*z + z^2, x*y - x*z - y*z + z^2) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: M.fitting_ideal(3) + Ideal (2*x - z, -z^2 + y, 1, -y + z, -x + z, -y + z, x^2 - y) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: M.fitting_ideal(4) + Ideal (1) of Multivariate Polynomial Ring in x, y, z over Rational Field + + + If the base ring is a field, the Fitting ideals are zero under the corank:: + + sage: M = matrix(QQ, [[2,1,3,5],[4,2,6,6],[0,3,2,0]]) + sage: M + [2 1 3 5] + [4 2 6 6] + [0 3 2 0] + sage: M.fitting_ideal(0) + Principal ideal (0) of Rational Field + sage: M.fitting_ideal(1) + Principal ideal (1) of Rational Field + sage: M.fitting_ideal(2) + Principal ideal (1) of Rational Field + sage: M.fitting_ideal(3) + Principal ideal (1) of Rational Field + sage: M.fitting_ideal(4) + Principal ideal (1) of Rational Field + + + In the case of principal ideal domains, it is given by the elementary + divisors:: + + sage: M = matrix([[2,1,3,5],[4,2,6,6],[0,3,2,0]]) + sage: M + [2 1 3 5] + [4 2 6 6] + [0 3 2 0] + sage: M.fitting_ideal(0) + Principal ideal (0) of Integer Ring + sage: M.fitting_ideal(1) + Principal ideal (4) of Integer Ring + sage: M.fitting_ideal(2) + Principal ideal (1) of Integer Ring + sage: M.fitting_ideal(3) + Principal ideal (1) of Integer Ring + sage: M.fitting_ideal(4) + Principal ideal (1) of Integer Ring + sage: M.elementary_divisors() + [1, 1, 4] + + This is also true for univariate polynomials over a field:: + + sage: R.<x> = QQ[] + sage: M = matrix(R,[[x^2-2*x+1, x-1,x^2-1],[0,x+1,1]]) + sage: M.fitting_ideal(0) + Principal ideal (0) of Univariate Polynomial Ring in x over Rational Field + sage: M.fitting_ideal(1) + Principal ideal (x - 1) of Univariate Polynomial Ring in x over Rational Field + sage: M.fitting_ideal(2) + Principal ideal (1) of Univariate Polynomial Ring in x over Rational Field + sage: M.smith_form()[0] + [ 1 0 0] + [ 0 x - 1 0] + + """ + R = self.base_ring() + if not R.is_exact(): + raise NotImplementedError("Fitting ideals over non-exact rings not implemented at present") + n = self.ncols() + rank_minors = n - i + if rank_minors > self.nrows(): + return R.ideal([R.zero()]) + elif rank_minors <= 0: + return R.ideal([R.one()]) + elif rank_minors == 1: + return R.ideal(self.coefficients()) + if R in _Fields: + if self.rank() >= rank_minors: + return R.ideal([1]) + else: + return R.ideal([0]) + try: + elemdiv = self.elementary_divisors() + if rank_minors > len(elemdiv): + return R.ideal([0]) + return R.ideal(prod(elemdiv[:rank_minors])) + except (TypeError, NotImplementedError, ArithmeticError): + pass + for (nr,r) in enumerate(self.rows()): + nz = [e for e in enumerate(r) if e[1]] + if len(nz) == 0: + N = self.delete_rows([nr]) + return N.fitting_ideal(i) + elif len(nz) == 1: + N = self.delete_rows([nr]) + F1 = N.fitting_ideal(i) + N = N.delete_columns([nz[0][0]]) + F2 = N.fitting_ideal(i) + return F1 + nz[0][1]*F2 + for (nc,c) in enumerate(self.columns()): + nz = [e for e in enumerate(c) if e[1]] + if len(nz) == 0: + N = self.delete_columns([nc]) + return N.fitting_ideal(i - 1) + elif len(nz) == 1: + N = self.delete_columns([nc]) + F1 = N.fitting_ideal(i-1) + N = N.delete_rows([nz[0][0]]) + F2 = N.fitting_ideal(i) + return F1 + nz[0][1]*F2 + if hasattr(self, '_fitting_ideal'): + try: + return self._fitting_ideal(i) + except NotImplementedError: + pass + return R.ideal(self.minors(rank_minors)) + + + def _hermite_form_euclidean(self, transformation=False, normalization=None): """ Transform the matrix in place to hermite normal form and optionally @@ -15736,7 +16086,8 @@ cdef class Matrix(Matrix1): [ -x + 1 -1 -x^2 + 2*x - 1] [-x^2 + 2*x - 1 -x + 1 -1] sage: H = A.__copy__() - sage: U = H._hermite_form_euclidean(transformation=True, normalization=lambda p: ~p.lc()) + sage: U = H._hermite_form_euclidean(transformation=True, + ....: normalization=lambda p: ~p.lc()) sage: H [ 1 x^2 - 2*x + 1 x - 1] [ 0 x^3 - 3*x^2 + 3*x - 2 0] @@ -15843,9 +16194,9 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: M = FunctionField(GF(7),'x').maximal_order() + sage: M = FunctionField(GF(7), 'x').maximal_order() sage: K.<x> = FunctionField(GF(7)); M = K.maximal_order() - sage: A = matrix(M, 2, 3, [x, 1, 2*x, x, 1+x, 2]) + sage: A = matrix(M, 2, 3, [x, 1, 2*x, x, 1 + x, 2]) sage: A.hermite_form() [ x 1 2*x] [ 0 x 5*x + 2] @@ -15857,31 +16208,31 @@ cdef class Matrix(Matrix1): sage: A = matrix(M, 2, 3, [x, 1, 2*x, 2*x, 2, 4*x]) sage: A.hermite_form(transformation=True, include_zero_rows=False) ([ x 1 2*x], [1 0]) - sage: H, U = A.hermite_form(transformation=True, include_zero_rows=True); H, U + sage: H, U = A.hermite_form(transformation=True, include_zero_rows=True) + sage: H, U ( [ x 1 2*x] [1 0] [ 0 0 0], [5 1] ) - sage: U*A == H + sage: U * A == H True sage: H, U = A.hermite_form(transformation=True, include_zero_rows=False) - sage: U*A + sage: U * A [ x 1 2*x] - sage: U*A == H + sage: U * A == H True """ - left, H, pivots = self._echelon_form_PID() + left, H, _ = self._echelon_form_PID() if not include_zero_rows: i = H.nrows() - 1 while H.row(i) == 0: i -= 1 - H = H[:i+1] + H = H[:i + 1] if transformation: - left = left[:i+1] + left = left[:i + 1] if transformation: return H, left - else: - return H + return H def _echelon_form_PID(self): r""" @@ -15894,11 +16245,13 @@ cdef class Matrix(Matrix1): column pivot. EXAMPLES:: - sage: L.<a> = NumberField(x^3 - 2) - sage: OL = L.ring_of_integers() + sage: x = polygen(ZZ, 'x') + sage: L.<a> = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: OL = L.ring_of_integers() # needs sage.rings.number_field We check some degenerate cases:: + sage: # needs sage.rings.number_field sage: m = matrix(OL, 0, 0, []); r,s,p = m._echelon_form_PID() sage: (r,s,p) ([], [], []) @@ -15917,17 +16270,18 @@ cdef class Matrix(Matrix1): A 2x2 matrix:: - sage: m = matrix(OL, 2, 2, [1,0, a, 2]) - sage: r,s,p = m._echelon_form_PID(); (r,s,p) + sage: m = matrix(OL, 2, 2, [1, 0, a, 2]) # needs sage.rings.number_field + sage: r,s,p = m._echelon_form_PID(); (r,s,p) # needs sage.rings.number_field ( [ 1 0] [1 0] [-a 1], [0 2], [0, 1] ) - sage: r * m == s and r.det() == 1 + sage: r * m == s and r.det() == 1 # needs sage.rings.number_field True A larger example:: + sage: # needs sage.rings.number_field sage: m = matrix(OL, 3, 5, [a^2 - 3*a - 1, a^2 - 3*a + 1, a^2 + 1, ....: -a^2 + 2, -3*a^2 - a - 1, -6*a - 1, a^2 - 3*a - 1, ....: 2*a^2 + a + 5, -2*a^2 + 5*a + 1, -a^2 + 13*a - 3, @@ -15990,9 +16344,9 @@ cdef class Matrix(Matrix1): try: - for i in xrange(1, len(pivs)): + for i in range(1, len(pivs)): y = a[i][pivs[i]] - I = R.ideal(y) + I = ideal_or_fractional(R, y) s = a[0][pivs[i]] t = I.small_residue(s) v = R( (s-t) / y) @@ -16367,7 +16721,7 @@ cdef class Matrix(Matrix1): sage: U.inverse()*B*U == Z True - sage: A.jordan_form() == B.jordan_form() + sage: A.jordan_form() == B.jordan_form() # needs sage.combinat True Two more examples, illustrating the two extremes of the zig-zag @@ -16428,13 +16782,14 @@ cdef class Matrix(Matrix1): sage: U.inverse()*D*U == Z True - sage: C.jordan_form() == D.jordan_form() + sage: C.jordan_form() == D.jordan_form() # needs sage.combinat True ZigZag form is achieved entirely with the operations of the field, so while the eigenvalues may lie outside the field, this does not impede the computation of the form. :: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(5^4) sage: A = matrix(F, [[ a, 0, 0, a + 3], ....: [ 0,a^2 + 1, 0, 0], @@ -16454,12 +16809,12 @@ cdef class Matrix(Matrix1): Subdivisions are optional. :: - sage: F.<a> = GF(5^4) - sage: A = matrix(F, [[ a, 0, 0, a + 3], + sage: F.<a> = GF(5^4) # needs sage.rings.finite_rings + sage: A = matrix(F, [[ a, 0, 0, a + 3], # needs sage.rings.finite_rings ....: [ 0,a^2 + 1, 0, 0], ....: [ 0, 0,a^3, 0], ....: [a^2 +4 , 0, 0,a + 2]]) - sage: A.zigzag_form(subdivide=False) + sage: A.zigzag_form(subdivide=False) # needs sage.rings.finite_rings [ 0 a^3 + 2*a^2 + 2*a + 2 0 0] [ 1 2*a + 2 0 0] [ 0 0 a^3 0] @@ -16630,13 +16985,13 @@ cdef class Matrix(Matrix1): sage: invariants [[4, -4, 1], [-12, 4, 9, -6, 1], [216, -108, -306, 271, 41, -134, 64, -13, 1]] sage: polys = [R(p) for p in invariants] - sage: [p.factor() for p in polys] + sage: [p.factor() for p in polys] # needs sage.rings.finite_rings [(x - 2)^2, (x - 3) * (x + 1) * (x - 2)^2, (x + 1)^2 * (x - 3)^3 * (x - 2)^3] sage: all(polys[i].divides(polys[i+1]) for i in range(len(polys)-1)) True - sage: polys[-1] == A.minimal_polynomial(var='x') + sage: polys[-1] == A.minimal_polynomial(var='x') # needs sage.libs.pari True - sage: prod(polys) == A.characteristic_polynomial(var='x') + sage: prod(polys) == A.characteristic_polynomial(var='x') # needs sage.libs.pari True Rational form is a canonical form. Any two matrices are similar @@ -16654,9 +17009,9 @@ cdef class Matrix(Matrix1): ....: [0, -42, 14, 8, 167, -17, -84, 13], ....: [0, -50, 17, 10, 199, -23, -98, 14], ....: [0, 15, -5, -2, -59, 7, 30, -2]]) - sage: C.minimal_polynomial().factor() + sage: C.minimal_polynomial().factor() # needs sage.libs.pari (x - 2)^2 - sage: C.characteristic_polynomial().factor() + sage: C.characteristic_polynomial().factor() # needs sage.libs.pari (x - 2)^8 sage: C.rational_form() [ 0 -4| 0 0| 0 0| 0 0] @@ -16679,9 +17034,9 @@ cdef class Matrix(Matrix1): ....: [ 31, -18, 135, 38, 12, 47, 155, -147], ....: [-33, 19, -138, -39, -13, -45, -156, 151], ....: [ -7, 4, -29, -8, -3, -10, -34, 34]]) - sage: D.minimal_polynomial().factor() + sage: D.minimal_polynomial().factor() # needs sage.libs.pari (x - 2)^2 - sage: D.characteristic_polynomial().factor() + sage: D.characteristic_polynomial().factor() # needs sage.libs.pari (x - 2)^8 sage: D.rational_form() [ 0 -4| 0 0| 0 0| 0 0] @@ -16704,9 +17059,9 @@ cdef class Matrix(Matrix1): ....: [-3, -7, 5, -6, -1, 5, -4, 14], ....: [ 6, 18, -10, 14, 4, -10, 10, -28], ....: [-2, -6, 4, -5, -1, 3, -3, 13]]) - sage: E.minimal_polynomial().factor() + sage: E.minimal_polynomial().factor() # needs sage.libs.pari (x - 2)^3 - sage: E.characteristic_polynomial().factor() + sage: E.characteristic_polynomial().factor() # needs sage.libs.pari (x - 2)^8 sage: E.rational_form() [ 2| 0 0| 0 0| 0 0 0] @@ -16743,9 +17098,9 @@ cdef class Matrix(Matrix1): ....: [ 139, -35, 99, -49, -18, 236, -41, -70, 370, -118, -377, -619], ....: [ 243, 9, 81, -72, -81, 386, 43, -105, 508, -124, -564, -911], ....: [-155, -3, -55, 45, 50, -245, -27, 65, -328, 77, 365, 583]]) - sage: A.characteristic_polynomial().factor() + sage: A.characteristic_polynomial().factor() # needs sage.libs.pari (x^2 - 2)^2 * (x^2 + 2*x + 5)^4 - sage: A.eigenvalues(extend=False) + sage: A.eigenvalues(extend=False) # needs sage.rings.number_field [] sage: A.rational_form() [ 0 -5| 0 0 0 0| 0 0 0 0 0 0] @@ -16764,12 +17119,13 @@ cdef class Matrix(Matrix1): [ 0 0| 0 0 0 0| 0 0 0 0 1 -4] sage: F.<x> = QQ[] sage: polys = A.rational_form(format='invariants') - sage: [F(p).factor() for p in polys] + sage: [F(p).factor() for p in polys] # needs sage.libs.pari [x^2 + 2*x + 5, (x^2 - 2) * (x^2 + 2*x + 5), (x^2 - 2) * (x^2 + 2*x + 5)^2] Rational form may be computed over any field. The matrix below is an example where the eigenvalues lie outside the field. :: + sage: # needs sage.rings.finite_rings sage: F.<a> = FiniteField(7^2) sage: A = matrix(F, ....: [[5*a + 3, 4*a + 1, 6*a + 2, 2*a + 5, 6, 4*a + 5, 4*a + 5, 5, a + 6, 5, 4*a + 4], @@ -16878,7 +17234,7 @@ cdef class Matrix(Matrix1): ... ValueError: 'subdivide' keyword must be True or False, not garbage """ - from sage.arith.all import gcd + from sage.arith.misc import GCD as gcd import sage.rings.polynomial.polynomial_ring_constructor from sage.matrix.constructor import (block_diagonal_matrix, companion_matrix) @@ -17005,26 +17361,28 @@ cdef class Matrix(Matrix1): Nonnegative matrices are positive operators on the nonnegative orthant:: - sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) - sage: L = random_matrix(QQ,3).apply_map(abs) - sage: L.is_positive_operator_on(K) + sage: K = Cone([(1,0,0), (0,1,0), (0,0,1)]) # needs sage.geometry.polyhedron + sage: L = random_matrix(QQ, 3).apply_map(abs) + sage: L.is_positive_operator_on(K) # needs sage.geometry.polyhedron True Symbolic entries also work in some easy cases:: - sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) - sage: L = matrix(SR, [ [0, e, 0 ], + sage: K = Cone([(1,0,0), (0,1,0), (0,0,1)]) # needs sage.geometry.polyhedron + sage: L = matrix(SR, [ [0, e, 0 ], # needs sage.symbolic ....: [0, 2, pi], ....: [sqrt(2), 0, 0 ] ]) - sage: L.is_positive_operator_on(K) + sage: L.is_positive_operator_on(K) # needs sage.geometry.polyhedron sage.symbolic True Your matrix can be over any exact ring, for example the ring of univariate polynomials with rational coefficients:: - sage: K = Cone([(1,0),(-1,0),(0,1),(0,-1)]) + sage: # needs sage.geometry.polyhedron + sage: K = Cone([(1,0), (-1,0), (0,1), (0,-1)]) sage: K.is_full_space() True + sage: x = polygen(ZZ, 'x') sage: L = matrix(QQ[x], [[x,0],[0,1]]) sage: L.is_positive_operator_on(K) True @@ -17033,6 +17391,7 @@ cdef class Matrix(Matrix1): The identity matrix is always a positive operator:: + sage: # needs sage.geometry.polyhedron sage: K = random_cone(max_ambient_dim=8) sage: R = K.lattice().vector_space().base_ring() sage: L = identity_matrix(R, K.lattice_dim()) @@ -17041,6 +17400,7 @@ cdef class Matrix(Matrix1): The zero matrix is always a positive operator:: + sage: # needs sage.geometry.polyhedron sage: K = random_cone(max_ambient_dim=8) sage: R = K.lattice().vector_space().base_ring() sage: L = zero_matrix(R, K.lattice_dim()) @@ -17052,10 +17412,12 @@ cdef class Matrix(Matrix1): the underlying ring symbolic (the usual case is tested by the ``positive_operators_gens`` method):: + sage: # needs sage.geometry.polyhedron sage.symbolic sage: K1 = random_cone(max_ambient_dim=5) sage: K2 = random_cone(max_ambient_dim=5) - sage: all(L.change_ring(SR).is_positive_operator_on(K1, K2) - ....: for L in K1.positive_operators_gens(K2)) # long time + sage: results = ( L.change_ring(SR).is_positive_operator_on(K1, K2) + ....: for L in K1.positive_operators_gens(K2) ) + sage: all(results) # long time True Technically we could test this, but for now only closed convex cones @@ -17070,9 +17432,9 @@ cdef class Matrix(Matrix1): We can't give reliable answers over inexact rings:: - sage: K = Cone([(1,2,3), (4,5,6)]) - sage: L = identity_matrix(RR,3) - sage: L.is_positive_operator_on(K) + sage: K = Cone([(1,2,3), (4,5,6)]) # needs sage.geometry.polyhedron + sage: L = identity_matrix(RR, 3) + sage: L.is_positive_operator_on(K) # needs sage.geometry.polyhedron Traceback (most recent call last): ... ValueError: The base ring of the matrix is neither symbolic nor @@ -17080,6 +17442,7 @@ cdef class Matrix(Matrix1): Symbolic subrings are fine:: + sage: # needs sage.geometry.polyhedron sage.symbolic sage: SCR = SR.subring(no_variables=True); SCR Symbolic Constants Subring sage: K = Cone([(1,2,3), (4,5,6)]) @@ -17162,26 +17525,27 @@ cdef class Matrix(Matrix1): Negative Z-matrices are cross-positive operators on the nonnegative orthant:: - sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) - sage: L = matrix(SR, [ [-1, 2, 0], + sage: K = Cone([(1,0,0), (0,1,0), (0,0,1)]) # needs sage.geometry.polyhedron + sage: L = matrix(SR, [ [-1, 2, 0], # needs sage.symbolic ....: [ 0, 2, 7], ....: [ 3, 0, 3] ]) - sage: L.is_cross_positive_on(K) + sage: L.is_cross_positive_on(K) # needs sage.geometry.polyhedron sage.symbolic True Symbolic entries also work in some easy cases:: - sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) - sage: L = matrix(SR, [ [-1, e, 0 ], + sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) # needs sage.geometry.polyhedron + sage: L = matrix(SR, [ [-1, e, 0 ], # needs sage.symbolic ....: [ 0, 2, pi], ....: [ sqrt(2), 0, 3 ] ]) - sage: L.is_cross_positive_on(K) + sage: L.is_cross_positive_on(K) # needs sage.geometry.polyhedron sage.symbolic True TESTS: The identity matrix is always cross-positive:: + sage: # needs sage.geometry.polyhedron sage: K = random_cone(max_ambient_dim=8) sage: R = K.lattice().vector_space().base_ring() sage: L = identity_matrix(R, K.lattice_dim()) @@ -17190,6 +17554,7 @@ cdef class Matrix(Matrix1): The zero matrix is always cross-positive:: + sage: # needs sage.geometry.polyhedron sage: K = random_cone(max_ambient_dim=8) sage: R = K.lattice().vector_space().base_ring() sage: L = zero_matrix(R, K.lattice_dim()) @@ -17201,9 +17566,11 @@ cdef class Matrix(Matrix1): symbolic (the usual case is tested by the ``cross_positive_operators_gens`` method):: + sage: # needs sage.geometry.polyhedron sage.symbolic sage: K = random_cone(max_ambient_dim=5) - sage: all(L.change_ring(SR).is_cross_positive_on(K) - ....: for L in K.cross_positive_operators_gens()) # long time + sage: results = ( L.change_ring(SR).is_cross_positive_on(K) + ....: for L in K.cross_positive_operators_gens() ) + sage: all(results) # long time True Technically we could test this, but for now only closed convex cones @@ -17218,9 +17585,9 @@ cdef class Matrix(Matrix1): We can't give reliable answers over inexact rings:: - sage: K = Cone([(1,2,3), (4,5,6)]) - sage: L = identity_matrix(RR,3) - sage: L.is_cross_positive_on(K) + sage: K = Cone([(1,2,3), (4,5,6)]) # needs sage.geometry.polyhedron + sage: L = identity_matrix(RR, 3) + sage: L.is_cross_positive_on(K) # needs sage.geometry.polyhedron Traceback (most recent call last): ... ValueError: The base ring of the matrix is neither symbolic nor @@ -17228,6 +17595,7 @@ cdef class Matrix(Matrix1): Symbolic subrings are fine:: + sage: # needs sage.geometry.polyhedron sage.symbolic sage: SCR = SR.subring(no_variables=True); SCR Symbolic Constants Subring sage: K = Cone([(1,2,3), (4,5,6)]) @@ -17299,26 +17667,27 @@ cdef class Matrix(Matrix1): Z-matrices are Z-operators on the nonnegative orthant:: - sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) - sage: L = matrix(SR, [ [-1, -2, 0], + sage: K = Cone([(1,0,0), (0,1,0), (0,0,1)]) # needs sage.geometry.polyhedron + sage: L = matrix(SR, [ [-1, -2, 0], # needs sage.symbolic ....: [ 0, 2, -7], ....: [-3, 0, 3] ]) - sage: L.is_Z_operator_on(K) + sage: L.is_Z_operator_on(K) # needs sage.geometry.polyhedron sage.symbolic True Symbolic entries also work in some easy cases:: - sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) - sage: L = matrix(SR, [ [-1, -e, 0 ], + sage: K = Cone([(1,0,0), (0,1,0), (0,0,1)]) # needs sage.geometry.polyhedron + sage: L = matrix(SR, [ [-1, -e, 0 ], # needs sage.symbolic ....: [ 0, 2, -pi], ....: [-sqrt(2), 0, 3 ] ]) - sage: L.is_Z_operator_on(K) + sage: L.is_Z_operator_on(K) # needs sage.geometry.polyhedron sage.symbolic True TESTS: The identity matrix is always a Z-operator:: + sage: # needs sage.geometry.polyhedron sage: K = random_cone(max_ambient_dim=8) sage: R = K.lattice().vector_space().base_ring() sage: L = identity_matrix(R, K.lattice_dim()) @@ -17327,6 +17696,7 @@ cdef class Matrix(Matrix1): The zero matrix is always a Z-operator:: + sage: # needs sage.geometry.polyhedron sage: K = random_cone(max_ambient_dim=8) sage: R = K.lattice().vector_space().base_ring() sage: L = zero_matrix(R, K.lattice_dim()) @@ -17337,9 +17707,9 @@ cdef class Matrix(Matrix1): ``K``, , even if we make the underlying ring symbolic (the usual case is tested by the ``Z_operators_gens`` method):: - sage: K = random_cone(max_ambient_dim=5) - sage: all(L.change_ring(SR).is_Z_operator_on(K) - ....: for L in K.Z_operators_gens()) # long time + sage: K = random_cone(max_ambient_dim=5) # needs sage.geometry.polyhedron + sage: all(L.change_ring(SR).is_Z_operator_on(K) # long time # needs sage.geometry.polyhedron sage.symbolic + ....: for L in K.Z_operators_gens()) True Technically we could test this, but for now only closed convex cones @@ -17354,9 +17724,9 @@ cdef class Matrix(Matrix1): We can't give reliable answers over inexact rings:: - sage: K = Cone([(1,2,3), (4,5,6)]) - sage: L = identity_matrix(RR,3) - sage: L.is_Z_operator_on(K) + sage: K = Cone([(1,2,3), (4,5,6)]) # needs sage.geometry.polyhedron + sage: L = identity_matrix(RR, 3) + sage: L.is_Z_operator_on(K) # needs sage.geometry.polyhedron Traceback (most recent call last): ... ValueError: The base ring of the matrix is neither symbolic nor @@ -17418,24 +17788,25 @@ cdef class Matrix(Matrix1): Diagonal matrices are Lyapunov-like operators on the nonnegative orthant:: - sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) - sage: L = diagonal_matrix(random_vector(QQ,3)) - sage: L.is_lyapunov_like_on(K) + sage: K = Cone([(1,0,0), (0,1,0), (0,0,1)]) # needs sage.geometry.polyhedron + sage: L = diagonal_matrix(random_vector(QQ, 3)) + sage: L.is_lyapunov_like_on(K) # needs sage.geometry.polyhedron True Symbolic entries also work in some easy cases:: - sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) - sage: L = matrix(SR, [ [e, 0, 0 ], + sage: K = Cone([(1,0,0), (0,1,0), (0,0,1)]) # needs sage.geometry.polyhedron + sage: L = matrix(SR, [ [e, 0, 0 ], # needs sage.symbolic ....: [0, pi, 0 ], ....: [0, 0, sqrt(2)] ]) - sage: L.is_lyapunov_like_on(K) + sage: L.is_lyapunov_like_on(K) # needs sage.geometry.polyhedron sage.symbolic True TESTS: The identity matrix is always Lyapunov-like:: + sage: # needs sage.geometry.polyhedron sage: K = random_cone(max_ambient_dim=8) sage: R = K.lattice().vector_space().base_ring() sage: L = identity_matrix(R, K.lattice_dim()) @@ -17444,6 +17815,7 @@ cdef class Matrix(Matrix1): The zero matrix is always Lyapunov-like:: + sage: # needs sage.geometry.polyhedron sage: K = random_cone(max_ambient_dim=8) sage: R = K.lattice().vector_space().base_ring() sage: L = zero_matrix(R, K.lattice_dim()) @@ -17455,9 +17827,9 @@ cdef class Matrix(Matrix1): symbolic (the usual case is tested by the ``lyapunov_like_basis`` method):: - sage: K = random_cone(max_ambient_dim=5) - sage: all(L.change_ring(SR).is_lyapunov_like_on(K) - ....: for L in K.lyapunov_like_basis()) # long time + sage: K = random_cone(max_ambient_dim=5) # needs sage.geometry.polyhedron + sage: all(L.change_ring(SR).is_lyapunov_like_on(K) # long time # needs sage.geometry.polyhedron sage.symbolic + ....: for L in K.lyapunov_like_basis()) True Technically we could test this, but for now only closed convex cones @@ -17472,9 +17844,9 @@ cdef class Matrix(Matrix1): We can't give reliable answers over inexact rings:: - sage: K = Cone([(1,2,3), (4,5,6)]) - sage: L = identity_matrix(RR,3) - sage: L.is_lyapunov_like_on(K) + sage: K = Cone([(1,2,3), (4,5,6)]) # needs sage.geometry.polyhedron + sage: L = identity_matrix(RR, 3) + sage: L.is_lyapunov_like_on(K) # needs sage.geometry.polyhedron Traceback (most recent call last): ... ValueError: The base ring of the matrix is neither symbolic nor @@ -17482,6 +17854,7 @@ cdef class Matrix(Matrix1): Symbolic subrings are fine:: + sage: # needs sage.geometry.polyhedron sage.symbolic sage: SCR = SR.subring(no_variables=True); SCR Symbolic Constants Subring sage: K = Cone([(1,2,3), (4,5,6)]) @@ -17492,13 +17865,14 @@ cdef class Matrix(Matrix1): A matrix is Lyapunov-like on a cone if and only if both the matrix and its negation are cross-positive on the cone:: + sage: # needs sage.geometry.polyhedron sage: K = random_cone(max_ambient_dim=5) sage: R = K.lattice().vector_space().base_ring() sage: L = random_matrix(R, K.lattice_dim()) - sage: actual = L.is_lyapunov_like_on(K) # long time - sage: expected = (L.is_cross_positive_on(K) and - ....: (-L).is_cross_positive_on(K)) # long time - sage: actual == expected # long time + sage: actual = L.is_lyapunov_like_on(K) # long time + sage: expected = (L.is_cross_positive_on(K) and # long time + ....: (-L).is_cross_positive_on(K)) + sage: actual == expected # long time True """ import sage.geometry.abc @@ -17559,9 +17933,9 @@ cdef class Matrix(Matrix1): Create a Gram matrix and LLL-reduce it:: sage: M = Matrix(ZZ, 2, 2, [5, 3, 3, 2]) - sage: U = M.LLL_gram() - sage: MM = U.transpose() * M * U - sage: M, U, MM + sage: U = M.LLL_gram() # needs sage.libs.pari + sage: MM = U.transpose() * M * U # needs sage.libs.pari + sage: M, U, MM # needs sage.libs.pari ( [5 3] [-1 1] [1 0] [3 2], [ 1 -2], [0 1] @@ -17573,28 +17947,28 @@ cdef class Matrix(Matrix1): preserve orientation). :: sage: M = Matrix(RDF, 2, 2, [1, 0, 0, 1e-5]) - sage: M.LLL_gram() + sage: M.LLL_gram() # needs sage.libs.pari [ 0 -1] [ 1 0] The algorithm might work for some semidefinite and indefinite forms:: - sage: Matrix(ZZ, 2, 2, [2, 6, 6, 3]).LLL_gram() + sage: Matrix(ZZ, 2, 2, [2, 6, 6, 3]).LLL_gram() # needs sage.libs.pari [-3 -1] [ 1 0] - sage: Matrix(ZZ, 2, 2, [1, 0, 0, -1]).LLL_gram() + sage: Matrix(ZZ, 2, 2, [1, 0, 0, -1]).LLL_gram() # needs sage.libs.pari [ 0 -1] [ 1 0] However, it might fail for others, either raising a ``ValueError``:: - sage: Matrix(ZZ, 1, 1, [0]).LLL_gram() + sage: Matrix(ZZ, 1, 1, [0]).LLL_gram() # needs sage.libs.pari Traceback (most recent call last): ... ValueError: qflllgram did not return a square matrix, perhaps the matrix is not positive definite - sage: Matrix(ZZ, 2, 2, [0, 1, 1, 0]).LLL_gram() + sage: Matrix(ZZ, 2, 2, [0, 1, 1, 0]).LLL_gram() # needs sage.libs.pari Traceback (most recent call last): ... ValueError: qflllgram did not return a square matrix, @@ -17602,14 +17976,14 @@ cdef class Matrix(Matrix1): or running forever:: - sage: Matrix(ZZ, 2, 2, [-5, -1, -1, -5]).LLL_gram() # not tested + sage: Matrix(ZZ, 2, 2, [-5, -1, -1, -5]).LLL_gram() # not tested, needs sage.libs.pari Traceback (most recent call last): ... RuntimeError: infinite loop while calling qflllgram Nonreal input leads to a value error:: - sage: Matrix(2, 2, [CDF(1, 1), 0, 0, 1]).LLL_gram() + sage: Matrix(2, 2, [CDF(1, 1), 0, 0, 1]).LLL_gram() # needs sage.libs.pari Traceback (most recent call last): ... ValueError: qflllgram failed, perhaps the matrix is not positive definite @@ -17663,10 +18037,10 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: A = matrix(QQbar, [[ -3, 5 - 3*I, 7 - 4*I], + sage: A = matrix(QQbar, [[ -3, 5 - 3*I, 7 - 4*I], # needs sage.rings.number_field ....: [7 + 3*I, -1 + 6*I, 3 + 5*I], ....: [3 + 3*I, -3 + 6*I, 5 + I]]) - sage: A.C + sage: A.C # needs sage.rings.number_field [ -3 5 + 3*I 7 + 4*I] [ 7 - 3*I -1 - 6*I 3 - 5*I] [ 3 - 3*I -3 - 6*I 5 - 1*I] @@ -17681,10 +18055,10 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: A = matrix(QQbar, [[ -3, 5 - 3*I, 7 - 4*I], + sage: A = matrix(QQbar, [[ -3, 5 - 3*I, 7 - 4*I], # needs sage.rings.number_field ....: [7 + 3*I, -1 + 6*I, 3 + 5*I], ....: [3 + 3*I, -3 + 6*I, 5 + I]]) - sage: A.H + sage: A.H # needs sage.rings.number_field [ -3 7 - 3*I 3 - 3*I] [ 5 + 3*I -1 - 6*I -3 - 6*I] [ 7 + 4*I 3 - 5*I 5 - 1*I] @@ -17703,9 +18077,11 @@ def _smith_diag(d, transformation=True): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.matrix.matrix2 import _smith_diag + sage: x = polygen(ZZ, 'x') sage: OE = EquationOrder(x^2 - x + 2, 'w') - sage: A = matrix(OE, 2, [2,0,0,3]) + sage: A = matrix(OE, 2, [2, 0, 0, 3]) sage: D,U,V = _smith_diag(A); D,U,V ( [1 0] [2 1] [ 1 -3] @@ -17713,7 +18089,7 @@ def _smith_diag(d, transformation=True): ) sage: D == U*A*V True - sage: m = matrix(GF(7),2, [3,0,0,6]); d,u,v = _smith_diag(m); d + sage: m = matrix(GF(7), 2, [3,0,0,6]); d,u,v = _smith_diag(m); d [1 0] [0 1] sage: u*m*v == d @@ -17728,24 +18104,24 @@ def _smith_diag(d, transformation=True): right = d.new_matrix(d.ncols(), d.ncols(), 1) else: left = right = None - for i in xrange(n): - I = R.ideal(dp[i,i]) + for i in range(n): + I = ideal_or_fractional(R, dp[i,i]) - if I == R.unit_ideal(): + if I == ideal_or_fractional(R, 1): if dp[i,i] != 1: if transformation: left.add_multiple_of_row(i,i,R(R(1)/(dp[i,i])) - 1) dp[i,i] = R(1) continue - for j in xrange(i+1,n): + for j in range(i+1,n): if dp[j,j] not in I: - t = R.ideal([dp[i,i], dp[j,j]]).gens_reduced() + t = ideal_or_fractional(R, [dp[i,i], dp[j,j]]).gens_reduced() if len(t) > 1: raise ArithmeticError t = t[0] # find lambda, mu such that lambda*d[i,i] + mu*d[j,j] = t - lamb = R(dp[i,i]/t).inverse_mod( R.ideal(dp[j,j]/t)) + lamb = R(dp[i,i]/t).inverse_mod( ideal_or_fractional(R, dp[j,j]/t)) mu = R((t - lamb*dp[i,i]) / dp[j,j]) newlmat = dp.new_matrix(dp.nrows(), dp.nrows(), 1) @@ -17780,10 +18156,13 @@ def _generic_clear_column(m): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: L.<w> = NumberField(x^2 - x + 2) sage: OL = L.ring_of_integers(); w = OL(w) - sage: m = matrix(OL, 8, 4, [2*w - 2, 2*w + 1, -2, w, 2, -2,-2*w - 2, -2*w + 2, -w + 2, 2*w + 1, -w + 2, -w - 2, -2*w, 2*w, -w+ 2, w - 1, -2*w + 2, 2*w + 2, 2*w - 1, -w, 2*w + 2, -w + 2, 2, 2*w -1, w - 4, -2*w - 2, 2*w - 1, 0, 6, 7, 2*w + 1, 14]) - sage: s,t = m.echelon_form(transformation=True); t*m == s # indirect doctest + sage: m = matrix(OL, 8, 4, [2*w - 2, 2*w + 1, -2, w, 2, -2, -2*w - 2, -2*w + 2, -w + 2, 2*w + 1, -w + 2, -w - 2, -2*w, + ....: 2*w, -w+ 2, w - 1, -2*w + 2, 2*w + 2, 2*w - 1, -w, 2*w + 2, -w + 2, 2, 2*w -1, w - 4, -2*w - 2, 2*w - 1, 0, 6, 7, 2*w + 1, 14]) + sage: s,t = m.echelon_form(transformation=True); t*m == s # indirect doctest True sage: s[0] (w, 0, 0, 0) @@ -17820,18 +18199,15 @@ def _generic_clear_column(m): # [e,f] # is invertible over R - if a[0,0] != 0: - I = R.ideal(a[0, 0]) # need to make sure we change this when a[0,0] changes - else: - I = R.zero_ideal() - for k in xrange(1, a.nrows()): + I = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes + for k in range(1, a.nrows()): if a[k,0] not in I: try: - v = R.ideal(a[0,0], a[k,0]).gens_reduced() + v = ideal_or_fractional(R, a[0,0], a[k,0]).gens_reduced() except Exception as msg: raise ArithmeticError("%s\nCan't create ideal on %s and %s" % (msg, a[0,0], a[k,0])) if len(v) > 1: - raise ArithmeticError("Ideal %s not principal" % R.ideal(a[0,0], a[k,0])) + raise ArithmeticError("Ideal %s not principal" % ideal_or_fractional(R, a[0,0], a[k,0])) B = v[0] # now we find c,d, using the fact that c * (a_{0,0}/B) - d * @@ -17840,7 +18216,7 @@ def _generic_clear_column(m): # need to handle carefully the case when a_{k,0}/B is a unit, i.e. a_{k,0} divides # a_{0,0}. - c = R(a[0,0] / B).inverse_mod(R.ideal(a[k,0] / B)) + c = R(a[0,0] / B).inverse_mod(ideal_or_fractional(R, a[k,0] / B)) d = R( (c*a[0,0] - B)/(a[k,0]) ) # sanity check @@ -17849,7 +18225,7 @@ def _generic_clear_column(m): # now we find e,f such that e*d + c*f = 1 in the same way if c != 0: - e = d.inverse_mod( R.ideal(c) ) + e = d.inverse_mod( ideal_or_fractional(R, c) ) f = R((1 - d*e)/c) else: e = R(-a[k,0]/B) # here d is a unit and this is just 1/d @@ -17865,13 +18241,13 @@ def _generic_clear_column(m): if newlmat.det() != 1: raise ArithmeticError a = newlmat*a - I = R.ideal(a[0,0]) + I = ideal_or_fractional(R, a[0,0]) left_mat = newlmat*left_mat if left_mat * m != a: raise ArithmeticError # now everything in column 0 is divisible by the pivot - for i in xrange(1,a.nrows()): + for i in range(1,a.nrows()): s = R( a[i, 0]/a[0, 0]) a.add_multiple_of_row(i, 0, -s ) left_mat.add_multiple_of_row(i, 0, -s) @@ -17889,9 +18265,11 @@ def _smith_onestep(m): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.matrix.matrix2 import _smith_onestep + sage: x = polygen(ZZ, 'x') sage: OE.<w> = EquationOrder(x^2 - x + 2) - sage: m = matrix(OE, 3,3,[1,0,7,2,w, w+17, 13+8*w, 0, 6]) + sage: m = matrix(OE, 3, 3, [1, 0, 7, 2, w, w+17, 13+8*w, 0, 6]) sage: a,b,c = _smith_onestep(m); b [ 1 0 0] [ 0 w w + 3] @@ -17923,7 +18301,7 @@ def _smith_onestep(m): # test if everything to the right of the pivot in row 0 is good as well isdone = True - for jj in xrange(j+1, a.ncols()): + for jj in range(j+1, a.ncols()): if a[0,jj] != 0: isdone = False @@ -17976,7 +18354,7 @@ def _choose(Py_ssize_t n, Py_ssize_t t): cdef Py_ssize_t j, temp x = [] # initialize T1 - c = list(xrange(t)) + c = list(range(t)) if t == n: x.append(c) return x @@ -18062,11 +18440,13 @@ def _jordan_form_vector_in_difference(V, W): sage: sage.matrix.matrix2._jordan_form_vector_in_difference([v,w], [u]) (1, 0, 0, 0) """ + from sage.modules.free_module import span + if not V: return None if not W: return V[0] - W_space = sage.all.span(W) + W_space = span(W) for v in V: if v not in W_space: return v @@ -18094,6 +18474,7 @@ def _matrix_power_symbolic(A, n): General power of a two by two matrix:: + sage: # needs sage.symbolic sage: n = SR.var('n') sage: A = matrix(QQ, [[2, -1], [1, 0]]) sage: B = A^n; B @@ -18104,9 +18485,9 @@ def _matrix_power_symbolic(A, n): General power of a three by three matrix in Jordan form:: + sage: # needs sage.symbolic sage: n = SR.var('n') - sage: A = matrix(QQ, 3, [[2, 1, 0], [0, 2, 0], [0, 0, 3]]) - sage: A + sage: A = matrix(QQ, 3, [[2, 1, 0], [0, 2, 0], [0, 0, 3]]); A [2 1 0] [0 2 0] [0 0 3] @@ -18119,8 +18500,8 @@ def _matrix_power_symbolic(A, n): General power of a three by three matrix not in Jordan form:: - sage: A = matrix([[4, 1, 2], [0, 2, -4], [0, 1, 6]]) - sage: A + sage: # needs sage.symbolic + sage: A = matrix([[4, 1, 2], [0, 2, -4], [0, 1, 6]]); A [ 4 1 2] [ 0 2 -4] [ 0 1 6] @@ -18141,9 +18522,9 @@ def _matrix_power_symbolic(A, n): Testing exponentiation in the symbolic ring:: - sage: n = var('n') - sage: A = matrix([[pi, e],[0, -2*I]]) - sage: (A^n).list() + sage: n = var('n') # needs sage.symbolic + sage: A = matrix([[pi, e],[0, -2*I]]) # needs sage.symbolic + sage: (A^n).list() # needs sage.symbolic [pi^n, -(-2*I)^n/(pi*e^(-1) + 2*I*e^(-1)) + pi^n/(pi*e^(-1) + 2*I*e^(-1)), 0, @@ -18152,22 +18533,22 @@ def _matrix_power_symbolic(A, n): If the base ring is inexact, the Jordan normal form is not available:: sage: A = matrix(RDF, [[2, -1], [1, 0]]) - sage: A^n + sage: A^n # needs sage.symbolic Traceback (most recent call last): ... ValueError: Jordan normal form not implemented over inexact rings. Testing exponentiation in the integer ring:: - sage: A = matrix(ZZ, [[1,-1],[-1,1]]) - sage: A^(2*n+1) + sage: A = matrix(ZZ, [[1,-1], [-1,1]]) + sage: A^(2*n+1) # needs sage.symbolic [ 1/2*2^(2*n + 1) -1/2*2^(2*n + 1)] [-1/2*2^(2*n + 1) 1/2*2^(2*n + 1)] Check if :trac:`23215` is fixed:: - sage: a, b, k = var('a, b, k') - sage: (matrix(2, [a, b, -b, a])^k).list() + sage: a, b, k = var('a, b, k') # needs sage.symbolic + sage: (matrix(2, [a, b, -b, a])^k).list() # needs sage.symbolic [1/2*(a + I*b)^k + 1/2*(a - I*b)^k, -1/2*I*(a + I*b)^k + 1/2*I*(a - I*b)^k, 1/2*I*(a + I*b)^k - 1/2*I*(a - I*b)^k, diff --git a/src/sage/matrix/matrix_cdv.pyx b/src/sage/matrix/matrix_cdv.pyx index a964b242c0f..dfbdb053328 100644 --- a/src/sage/matrix/matrix_cdv.pyx +++ b/src/sage/matrix/matrix_cdv.pyx @@ -30,11 +30,12 @@ cpdef hessenbergize_cdvf(Matrix_generic_dense H): a complete discrete valuation field. The pivot on each column is always chosen - with maximal relative precision, which ensures + with maximal relative precision, which ensures the numerical stability of the algorithm. TESTS:: + sage: # needs sage.rings.padics sage: K = Qp(5, print_mode="digits", prec=5) sage: H = matrix(K, 3, 3, range(9)) sage: H @@ -49,14 +50,16 @@ cpdef hessenbergize_cdvf(Matrix_generic_dense H): :: - sage: M = random_matrix(K, 6, 6) - sage: M.charpoly()[0] == M.determinant() + sage: M = random_matrix(K, 6, 6) # needs sage.rings.padics + sage: M.charpoly()[0] == M.determinant() # needs sage.rings.padics True We check that :trac:`31753` is resolved:: sage: R.<t> = GF(5)[[]] - sage: M = matrix(3, 3, [ 1, t + O(t^3), t^2, 1 + t + O(t^3), 2 + t^2, 3 + 2*t + O(t^3), t - t^2, 2*t, 1 + t ]) + sage: M = matrix(3, 3, [ 1, t + O(t^3), t^2, + ....: 1 + t + O(t^3), 2 + t^2, 3 + 2*t + O(t^3), + ....: t - t^2, 2*t, 1 + t ]) sage: M.charpoly() x^3 + (1 + 4*t + 4*t^2 + O(t^3))*x^2 + (t + 2*t^2 + O(t^3))*x + 3 + 2*t^2 + O(t^3) """ diff --git a/src/sage/matrix/matrix_complex_ball_dense.pyx b/src/sage/matrix/matrix_complex_ball_dense.pyx index 2a9f00d19ad..47ca41070fa 100644 --- a/src/sage/matrix/matrix_complex_ball_dense.pyx +++ b/src/sage/matrix/matrix_complex_ball_dense.pyx @@ -23,8 +23,7 @@ TESTS:: sage: loads(dumps(mat)).identical(mat) True """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Clemens Heuberger <clemens.heuberger@aau.at> # # This program is free software: you can redistribute it and/or modify @@ -32,8 +31,7 @@ TESTS:: # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** - +# **************************************************************************** from cpython.object cimport Py_EQ, Py_NE from cysignals.signals cimport sig_on, sig_str, sig_off @@ -42,9 +40,7 @@ from sage.libs.arb.acb cimport * from sage.libs.arb.acb_mat cimport * from sage.libs.gmp.mpz cimport mpz_fits_ulong_p, mpz_get_ui from sage.matrix.constructor import matrix -from sage.matrix.matrix_generic_sparse cimport Matrix_generic_sparse from .args cimport SparseEntry, MatrixArgs_init -from sage.rings.complex_interval_field import ComplexIntervalField_class, ComplexIntervalField from sage.rings.complex_interval cimport ComplexIntervalFieldElement from sage.rings.complex_arb cimport ( ComplexBall, @@ -52,12 +48,11 @@ from sage.rings.complex_arb cimport ( acb_to_ComplexIntervalFieldElement) from sage.rings.integer cimport Integer from sage.rings.polynomial.polynomial_complex_arb cimport Polynomial_complex_arb -from sage.structure.element cimport Element, RingElement, Matrix +from sage.structure.element cimport Element, Matrix from sage.structure.parent cimport Parent from sage.structure.sequence import Sequence from sage.misc.superseded import experimental -from sage.rings.integer_ring import ZZ from sage.rings.polynomial import polynomial_ring_constructor @@ -75,7 +70,7 @@ cdef void matrix_to_acb_mat(acb_mat_t target, source): None. """ - cdef unsigned long nrows, ncols, r, c, precision + cdef unsigned long nrows, ncols, r, c nrows = acb_mat_nrows(target) ncols = acb_mat_ncols(target) @@ -92,8 +87,7 @@ cdef ComplexIntervalFieldElement _to_CIF(acb_t source, ComplexIntervalFieldEleme result, source) return result -cdef Matrix_generic_dense acb_mat_to_matrix( - acb_mat_t source, Parent CIF): +cdef Matrix_generic_dense acb_mat_to_matrix(acb_mat_t source, Parent CIF): """ Convert an ``acb_mat_t`` to a matrix containing :class:`ComplexIntervalFieldElement`. @@ -670,7 +664,7 @@ cdef class Matrix_complex_ball_dense(Matrix_dense): Pol = polynomial_ring_constructor._single_variate(self.base_ring(), var) cdef Polynomial_complex_arb res = Polynomial_complex_arb(Pol) sig_on() - acb_mat_charpoly(res.__poly, self.value, prec(self)) + acb_mat_charpoly(res._poly, self.value, prec(self)) sig_off() return res @@ -776,7 +770,7 @@ cdef class Matrix_complex_ball_dense(Matrix_dense): EXAMPLES:: sage: from sage.matrix.benchmark import hilbert_matrix - sage: mat = hilbert_matrix(3).change_ring(CBF) + sage: mat = hilbert_matrix(3).change_ring(CBF) sage: eigval, eigvec, _ = mat.eigenvectors_right_approx()[0] doctest:...: FutureWarning: This class/method/function is marked as experimental. ... @@ -804,7 +798,7 @@ cdef class Matrix_complex_ball_dense(Matrix_dense): eigval = _acb_vec_to_list(_eigval, n, self._parent._base) finally: _acb_vec_clear(_eigval, n) - return [(l, [v], 1) for l, v in zip(eigval, eigvec.columns())] + return [(val, [vec], 1) for val, vec in zip(eigval, eigvec.columns())] @experimental(issue_number=30393) def eigenvectors_right(self, other=None, *, extend=None): @@ -834,7 +828,7 @@ cdef class Matrix_complex_ball_dense(Matrix_dense): EXAMPLES:: sage: from sage.matrix.benchmark import hilbert_matrix - sage: mat = hilbert_matrix(3).change_ring(CBF) + sage: mat = hilbert_matrix(3).change_ring(CBF) sage: eigval, eigvec, _ = mat.eigenvectors_right()[0] doctest:...: FutureWarning: This class/method/function is marked as experimental. ... @@ -867,7 +861,7 @@ cdef class Matrix_complex_ball_dense(Matrix_dense): acb_mat_clear(eigvec_approx) _acb_vec_clear(_eigval, n) _acb_vec_clear(eigval_approx, n) - return [(l, [v], 1) for l, v in zip(eigval, eigvec.columns())] + return [(val, [vec], 1) for val, vec in zip(eigval, eigvec.columns())] def eigenvectors_left_approx(self, other=None, *, extend=None): r""" @@ -951,7 +945,7 @@ cdef class Matrix_complex_ball_dense(Matrix_dense): EXAMPLES:: - sage: matrix(CBF, [[i*pi, 1], [0, i*pi]]).exp() + sage: matrix(CBF, [[i*pi, 1], [0, i*pi]]).exp() # needs sage.symbolic [[-1.00000000000000 +/- ...e-16] + [+/- ...e-16]*I [-1.00000000000000 +/- ...e-16] + [+/- ...e-16]*I] [ 0 [-1.00000000000000 +/- ...e-16] + [+/- ...e-16]*I] sage: matrix(CBF, [[1/2, 1/3]]).exp() diff --git a/src/sage/matrix/matrix_complex_double_dense.pyx b/src/sage/matrix/matrix_complex_double_dense.pyx index 9f8b8ec9fc8..162332eb44e 100644 --- a/src/sage/matrix/matrix_complex_double_dense.pyx +++ b/src/sage/matrix/matrix_complex_double_dense.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - numpy """ Dense matrices over the Complex Double Field using NumPy diff --git a/src/sage/matrix/matrix_cyclo_dense.pyx b/src/sage/matrix/matrix_cyclo_dense.pyx index 55e1b7d739e..f54f3423ded 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pyx +++ b/src/sage/matrix/matrix_cyclo_dense.pyx @@ -40,20 +40,20 @@ AUTHORS: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from cysignals.signals cimport sig_on, sig_off include "sage/libs/ntl/decl.pxi" -from sage.structure.element cimport ModuleElement, RingElement, Element, Vector +from sage.structure.element cimport Element from sage.misc.randstate cimport randstate, current_randstate from sage.libs.gmp.randomize cimport * -from sage.libs.flint.types cimport fmpz_t, fmpq -from sage.libs.flint.fmpz cimport fmpz_init, fmpz_clear, fmpz_set, fmpz_set_mpz, fmpz_one, fmpz_get_mpz, fmpz_add, fmpz_mul, fmpz_sub, fmpz_mul_si, fmpz_mul_si, fmpz_mul_si, fmpz_divexact, fmpz_lcm -from sage.libs.flint.fmpq cimport fmpq_is_zero, fmpq_get_mpq, fmpq_set_mpq, fmpq_canonicalise +from sage.libs.flint.types cimport fmpz_t +from sage.libs.flint.fmpz cimport fmpz_init, fmpz_clear, fmpz_set_mpz, fmpz_one, fmpz_get_mpz, fmpz_add, fmpz_mul, fmpz_sub, fmpz_mul_si, fmpz_mul_si, fmpz_mul_si, fmpz_divexact, fmpz_lcm +from sage.libs.flint.fmpq cimport fmpq_is_zero, fmpq_set_mpq, fmpq_canonicalise from sage.libs.flint.fmpq_mat cimport fmpq_mat_entry_num, fmpq_mat_entry_den, fmpq_mat_entry from .args cimport MatrixArgs_init @@ -63,21 +63,19 @@ from .matrix cimport Matrix from . import matrix_dense from .matrix_integer_dense cimport _lift_crt from sage.structure.element cimport Matrix as baseMatrix -from .misc import matrix_integer_dense_rational_reconstruction +from .misc_flint import matrix_integer_dense_rational_reconstruction +from sage.arith.misc import binomial, previous_prime from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ -from sage.arith.all import previous_prime, binomial from sage.rings.real_mpfr import create_RealNumber as RealNumber from sage.rings.integer cimport Integer -from sage.rings.rational cimport Rational from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.number_field.number_field_element cimport NumberFieldElement from sage.rings.number_field.number_field_element_quadratic cimport NumberFieldElement_quadratic from sage.structure.proof.proof import get_flag as get_proof_flag from sage.misc.verbose import verbose -import math from sage.matrix.matrix_modn_dense_double import MAX_MODULUS as MAX_MODULUS_modn_dense_double from sage.arith.multi_modular import MAX_MODULUS as MAX_MODULUS_multi_modular @@ -329,7 +327,7 @@ cdef class Matrix_cyclo_dense(Matrix_dense): cdef Py_ssize_t k, c cdef NumberFieldElement x cdef NumberFieldElement_quadratic xq - cdef mpz_t quo, tmp + cdef mpz_t tmp cdef fmpz_t denom, ftmp cdef ZZ_c coeff @@ -398,11 +396,11 @@ cdef class Matrix_cyclo_dense(Matrix_dense): # Now set k-th entry of x's numerator to tmp fmpz_get_mpz(tmp, ftmp) mpz_to_ZZ(&coeff, tmp) - ZZX_SetCoeff(x.__numerator, k, coeff) + ZZX_SetCoeff(x._numerator, k, coeff) # Set the denominator of x to denom. fmpz_get_mpz(tmp, denom) - mpz_to_ZZ(&x.__denominator, tmp) + mpz_to_ZZ(&x._denominator, tmp) fmpz_clear(denom) mpz_clear(tmp) fmpz_clear(ftmp) @@ -682,8 +680,9 @@ cdef class Matrix_cyclo_dense(Matrix_dense): cdef long _hash_(self) except -1: """ - Return hash of an immutable matrix. Raise a TypeError if input - matrix is mutable. + Return hash of an immutable matrix. + + This raises a :class:`TypeError` if input matrix is mutable. EXAMPLES: @@ -816,7 +815,6 @@ cdef class Matrix_cyclo_dense(Matrix_dense): A._matrix = -self._matrix return A - ######################################################################## # LEVEL 3 functionality (Optional) # * __deepcopy__ @@ -826,6 +824,7 @@ cdef class Matrix_cyclo_dense(Matrix_dense): # * Specialized echelon form # * tensor product ######################################################################## + def set_immutable(self): """ Change this matrix so that it is immutable. @@ -1038,7 +1037,6 @@ cdef class Matrix_cyclo_dense(Matrix_dense): """ cdef Py_ssize_t i cdef Matrix_rational_dense mat = self._matrix - cdef fmpq * entry cdef mpq_t tmp sig_on() @@ -1200,8 +1198,6 @@ cdef class Matrix_cyclo_dense(Matrix_dense): if self._nrows <= 3: return max(1, 3*B, 6*B**2, 4*B**3) - # This is an approximation to 2^(5/6*log_2(5) - 2/3*log_2(6)) - alpha = RealNumber('1.15799718800731') # This is 2*e^(1-(2(7\gamma-4))/(13(3-2\gamma))), where \gamma # is Euler's constant. delta = RealNumber('5.418236') @@ -1335,20 +1331,20 @@ cdef class Matrix_cyclo_dense(Matrix_dense): [4 0 0] [0 0 0] """ - tm = verbose("Computing characteristic polynomial of cyclotomic matrix modulo %s."%p) + tm = verbose("Computing characteristic polynomial of cyclotomic matrix modulo %s." % p) # Reduce self modulo all primes over p - R, denom = self._reductions(p) + R, _ = self._reductions(p) # Compute the characteristic polynomial of each reduced matrix F = [A.charpoly('x') for A in R] # Put the characteristic polynomials together as the rows of a mod-p matrix k = R[0].base_ring() - S = matrix(k, len(F), self.nrows()+1, [f.list() for f in F]) + S = matrix(k, len(F), self.nrows() + 1, [f.list() for f in F]) # multiply by inverse of reduction matrix to lift _, L = self._reduction_matrix(p) X = L * S # Now the columns of the matrix X define the entries of the # charpoly modulo p. - verbose("Finished computing charpoly mod %s."%p, tm) + verbose("Finished computing charpoly mod %s." % p, tm) return X def _charpoly_multimodular(self, var='x', proof=None): @@ -1411,7 +1407,7 @@ cdef class Matrix_cyclo_dense(Matrix_dense): # if we've used enough primes as determined by bound, or # if we've used 3 primes, we check to see if the result is # the same. - if prod >= bound or (not proof and (len(v) % 3 == 0)): + if prod >= bound or (not proof and (len(v) % 3 == 0)): M = matrix(ZZ, self._base_ring.degree(), self._nrows+1) L = _lift_crt(M, v) if not proof and L == L_last: @@ -1678,7 +1674,6 @@ cdef class Matrix_cyclo_dense(Matrix_dense): [ 1 0 7/19] [ 0 1 3/19] """ - cdef int i cdef Matrix_cyclo_dense res cdef bint is_square @@ -1829,14 +1824,11 @@ cdef class Matrix_cyclo_dense(Matrix_dense): Traceback (most recent call last): ... ValueError: echelon form mod 7 not defined - """ - cdef Matrix_cyclo_dense res cdef int i # Initialize variables - is_square = self._nrows == self._ncols - ls, denom = self._reductions(p) + ls, _ = self._reductions(p) # Find our first echelon form, and the associated list # of pivots @@ -1938,13 +1930,11 @@ cdef class Matrix_cyclo_dense(Matrix_dense): X = R._generator_matrix() d = self._degree MS = MatrixSpace(QQ, d, d) - mlst = self.list() for c in self._matrix.columns(): v = c.list() for n in range(d-1): c = c * X v += c.list() - temp = MS(v) rmul = MS([v[d*i+j] for j in range(d) for i in range(d)]) # We take the transpose l.append(rmul * A._rational_matrix()) diff --git a/src/sage/matrix/matrix_dense.pyx b/src/sage/matrix/matrix_dense.pyx index afc24c658e6..0f5089b5122 100644 --- a/src/sage/matrix/matrix_dense.pyx +++ b/src/sage/matrix/matrix_dense.pyx @@ -10,7 +10,6 @@ TESTS:: cimport sage.matrix.matrix as matrix -from sage.structure.element cimport Element, RingElement from sage.structure.richcmp cimport richcmp_item, rich_to_bool import sage.matrix.matrix_space import sage.structure.sequence @@ -75,6 +74,7 @@ cdef class Matrix_dense(matrix.Matrix): Check :trac:`27629`:: + sage: # needs sage.symbolic sage: var('x') x sage: assume(x, 'real') @@ -271,8 +271,8 @@ cdef class Matrix_dense(matrix.Matrix): EXAMPLES:: - sage: m = matrix(2, [x^i for i in range(4)]) - sage: m._derivative(x) + sage: m = matrix(2, [x^i for i in range(4)]) # needs sage.symbolic + sage: m._derivative(x) # needs sage.symbolic [ 0 1] [ 2*x 3*x^2] """ diff --git a/src/sage/matrix/matrix_double_dense.pyx b/src/sage/matrix/matrix_double_dense.pyx index 4515e01978e..bf8ade78c14 100644 --- a/src/sage/matrix/matrix_double_dense.pyx +++ b/src/sage/matrix/matrix_double_dense.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - numpy """ Dense matrices using a NumPy backend @@ -1374,7 +1375,7 @@ cdef class Matrix_double_dense(Matrix_numpy_dense): location = None best_fit = tol for i in range(len(ev_group)): - s, m, avg = ev_group[i] + _, m, avg = ev_group[i] d = numpy.abs(avg - e) if d < best_fit: best_fit = d @@ -1738,14 +1739,13 @@ cdef class Matrix_double_dense(Matrix_numpy_dense): import scipy import scipy.linalg X = self._new(self._ncols, B.ncols()) - arr, resid, rank, s = scipy.linalg.lstsq(self._matrix_numpy, B.numpy()) + arr = scipy.linalg.lstsq(self._matrix_numpy, B.numpy())[0] X._matrix_numpy = arr return X - def determinant(self): """ - Return the determinant of self. + Return the determinant of ``self``. ALGORITHM: @@ -1807,7 +1807,6 @@ cdef class Matrix_double_dense(Matrix_numpy_dense): [] sage: m.log_determinant() 0.0 - """ global numpy cdef Matrix_double_dense U @@ -1818,7 +1817,7 @@ cdef class Matrix_double_dense(Matrix_numpy_dense): if not self.is_square(): raise ArithmeticError("self must be a square matrix") - P, L, U = self.LU() + _, _, U = self.LU() if numpy is None: import numpy @@ -2489,7 +2488,7 @@ cdef class Matrix_double_dense(Matrix_numpy_dense): return True if numpy is None: import numpy - cdef Py_ssize_t i, j + cdef Py_ssize_t i cdef Matrix_double_dense T # A matrix M is skew-hermitian iff I*M is hermitian T = self.__mul__(1j) if skew else self.__copy__() @@ -2499,13 +2498,13 @@ cdef class Matrix_double_dense(Matrix_numpy_dense): hermitian = T._is_lower_triangular(tol) if hermitian: for i in range(T._nrows): - if abs(T.get_unsafe(i,i).imag()) > tol: + if abs(T.get_unsafe(i, i).imag()) > tol: hermitian = False break self.cache(key, hermitian) return hermitian - def is_hermitian(self, tol = 1e-12, algorithm = "naive"): + def is_hermitian(self, tol=1e-12, algorithm = "naive"): r""" Return ``True`` if the matrix is equal to its conjugate-transpose. diff --git a/src/sage/matrix/matrix_gap.pyx b/src/sage/matrix/matrix_gap.pyx index 8485760e9cb..f3f77dcbe15 100644 --- a/src/sage/matrix/matrix_gap.pyx +++ b/src/sage/matrix/matrix_gap.pyx @@ -12,7 +12,6 @@ Wrappers on GAP matrices # **************************************************************************** from sage.libs.gap.libgap import libgap -from . import matrix_space from sage.structure.element cimport Matrix from .args cimport MatrixArgs_init diff --git a/src/sage/matrix/matrix_generic_dense.pyx b/src/sage/matrix/matrix_generic_dense.pyx index 49df19eacbf..9c16ac3c486 100644 --- a/src/sage/matrix/matrix_generic_dense.pyx +++ b/src/sage/matrix/matrix_generic_dense.pyx @@ -13,7 +13,6 @@ from .args cimport MatrixArgs_init cimport sage.matrix.matrix as matrix -from sage.structure.element cimport parent as parent_c cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): r""" @@ -70,9 +69,10 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): We check that the problem related to :trac:`9049` is not an issue any more:: - sage: S.<t>=PolynomialRing(QQ) - sage: F.<q>=QQ.extension(t^4+1) - sage: R.<x,y>=PolynomialRing(F) + sage: # needs sage.rings.number_field + sage: S.<t> = PolynomialRing(QQ) + sage: F.<q> = QQ.extension(t^4 + 1) + sage: R.<x,y> = PolynomialRing(F) sage: M = MatrixSpace(R, 1, 2) sage: from sage.matrix.matrix_generic_dense import Matrix_generic_dense sage: Matrix_generic_dense(M, (x, y), True, True) @@ -215,7 +215,8 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): EXAMPLES:: - sage: R.<x,y> = FreeAlgebra(QQ,2) + sage: # needs sage.combinat + sage: R.<x,y> = FreeAlgebra(QQ, 2) sage: a = matrix(R, 2, 2, [1,2,x*y,y*x]) sage: b = matrix(R, 2, 2, [1,2,y*x,y*x]) sage: a._add_(b) @@ -238,7 +239,8 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): EXAMPLES:: - sage: R.<x,y> = FreeAlgebra(QQ,2) + sage: # needs sage.combinat + sage: R.<x,y> = FreeAlgebra(QQ, 2) sage: a = matrix(R, 2, 2, [1,2,x*y,y*x]) sage: b = matrix(R, 2, 2, [1,2,y*x,y*x]) sage: a._sub_(b) diff --git a/src/sage/matrix/matrix_generic_sparse.pyx b/src/sage/matrix/matrix_generic_sparse.pyx index a342d5b7353..4cd7cecc7e8 100644 --- a/src/sage/matrix/matrix_generic_sparse.pyx +++ b/src/sage/matrix/matrix_generic_sparse.pyx @@ -4,8 +4,9 @@ Sparse Matrices over a general ring EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: M = MatrixSpace(QQ['x'],2,3,sparse=True); M - Full MatrixSpace of 2 by 3 sparse matrices over Univariate Polynomial Ring in x over Rational Field + sage: M = MatrixSpace(QQ['x'], 2, 3, sparse=True); M + Full MatrixSpace of 2 by 3 sparse matrices over + Univariate Polynomial Ring in x over Rational Field sage: a = M(range(6)); a [0 1 2] [3 4 5] @@ -15,7 +16,7 @@ EXAMPLES:: sage: a * b.transpose() [ 2*x^2 + x 2*x^5 + x^4] [ 5*x^2 + 4*x + 3 5*x^5 + 4*x^4 + 3*x^3] - sage: pari(a)*pari(b.transpose()) + sage: pari(a)*pari(b.transpose()) # needs sage.libs.pari [2*x^2 + x, 2*x^5 + x^4; 5*x^2 + 4*x + 3, 5*x^5 + 4*x^4 + 3*x^3] sage: c = copy(b); c [ 1 x x^2] @@ -52,14 +53,10 @@ EXAMPLES:: sage: c.is_sparse() True """ - -cimport sage.matrix.matrix as matrix cimport sage.matrix.matrix_sparse as matrix_sparse cimport sage.structure.element -from sage.structure.element cimport ModuleElement from .args cimport MatrixArgs_init -import sage.misc.misc as misc cdef class Matrix_generic_sparse(matrix_sparse.Matrix_sparse): r""" diff --git a/src/sage/matrix/matrix_gf2e_dense.pyx b/src/sage/matrix/matrix_gf2e_dense.pyx index 922f6288696..977dbd0d6b5 100644 --- a/src/sage/matrix/matrix_gf2e_dense.pyx +++ b/src/sage/matrix/matrix_gf2e_dense.pyx @@ -83,11 +83,11 @@ REFERENCES: # https://www.gnu.org/licenses/ #***************************************************************************** -from cysignals.signals cimport sig_check, sig_on, sig_off +from cysignals.signals cimport sig_on, sig_off cimport sage.matrix.matrix_dense as matrix_dense -from sage.structure.element cimport Matrix, Vector -from sage.structure.element cimport ModuleElement, Element, RingElement +from sage.structure.element cimport Matrix +from sage.structure.element cimport Element from sage.structure.richcmp cimport rich_to_bool from sage.rings.finite_rings.element_base cimport Cache_base @@ -97,7 +97,7 @@ from sage.misc.randstate cimport randstate, current_randstate from sage.matrix.matrix_mod2_dense cimport Matrix_mod2_dense from .args cimport SparseEntry, MatrixArgs_init -from sage.libs.m4ri cimport m4ri_word, mzd_copy, mzd_init +from sage.libs.m4ri cimport m4ri_word, mzd_copy from sage.libs.m4rie cimport * from sage.libs.m4rie cimport mzed_t @@ -804,7 +804,6 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): cdef m4ri_word mask = (1<<(self._parent.base_ring().degree())) - 1 cdef randstate rstate = current_randstate() - K = self._parent.base_ring() if self._ncols == 0 or self._nrows == 0: return @@ -898,7 +897,7 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): self.cache('pivots', []) return self - cdef int k, n, full + cdef int full full = int(reduced) diff --git a/src/sage/matrix/matrix_gfpn_dense.pxd b/src/sage/matrix/matrix_gfpn_dense.pxd index 92b0a78d6d2..7a457876b9a 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pxd +++ b/src/sage/matrix/matrix_gfpn_dense.pxd @@ -1,3 +1,5 @@ +# sage_setup: distribution = sagemath-meataxe + #***************************************************************************** # Copyright (C) 2015 Simon King <simon.king@uni-jena.de> # diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index 7d605da8426..4cccf473de1 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -34,14 +34,11 @@ AUTHORS: # (at your option) any later version. # https://www.gnu.org/licenses/ # *************************************************************************** - from cysignals.memory cimport check_realloc, check_malloc, sig_free from cpython.bytes cimport PyBytes_AsString, PyBytes_FromStringAndSize from cysignals.signals cimport sig_on, sig_off, sig_check cimport cython -import os - #################### # # import sage types @@ -53,14 +50,12 @@ from sage.cpython.string import FS_ENCODING from sage.rings.integer import Integer from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.finite_rings.integer_mod import IntegerMod_int -from sage.matrix.constructor import random_matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.randstate import current_randstate from sage.misc.randstate cimport randstate -from sage.misc.cachefunc import cached_method, cached_function -from sage.structure.element cimport Element, ModuleElement, RingElement, Matrix +from sage.structure.element cimport Element, Matrix from sage.structure.richcmp import rich_to_bool -from .args cimport MatrixArgs_init +from sage.matrix.args cimport MatrixArgs_init from libc.string cimport memset, memcpy @@ -735,7 +730,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): x = self.Data.Data cdef int nr = self.Data.Nor cdef int nc = self.Data.Noc - cdef int i, j, k + cdef int i, j FfSetField(fl) FfSetNoc(nc) @@ -1397,15 +1392,13 @@ cdef class Matrix_gfpn_dense(Matrix_dense): True sage: M*int(-1)+M == 0 True - """ if self.Data == NULL: raise ValueError("The matrix must not be empty") - cdef Matrix_gfpn_dense left FfSetField(self.Data.Field) cdef FEL r with cython.cdivision(False): - r = FfFromInt(n%FfChar) + r = FfFromInt(n % FfChar) sig_on() try: mat = MatDup(self.Data) diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index b9f9d5791b4..8c276f2ca29 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -75,10 +75,10 @@ from sage.libs.gmp.mpz cimport * from sage.modules.vector_integer_dense cimport Vector_integer_dense -from sage.misc.misc import cputime +from sage.misc.timing import cputime from sage.misc.verbose import verbose, get_verbose -from sage.arith.all import previous_prime +from sage.arith.misc import previous_prime from sage.arith.long cimport integer_check_long_py from sage.arith.power cimport generic_power from sage.structure.element cimport Element @@ -86,7 +86,6 @@ from sage.structure.proof.proof import get_flag as get_proof_flag from sage.structure.richcmp cimport rich_to_bool from sage.misc.randstate cimport randstate, current_randstate -from sage.matrix.matrix_rational_dense cimport Matrix_rational_dense from .args cimport SparseEntry, MatrixArgs_init ######################################################### @@ -112,9 +111,8 @@ from sage.rings.integer_ring cimport IntegerRing_class from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint -from sage.structure.element cimport ModuleElement, RingElement, Element, Vector +from sage.structure.element cimport Element, Vector from sage.structure.element import is_Vector -from sage.structure.sequence import Sequence from .matrix_modn_dense_float cimport Matrix_modn_dense_template from .matrix_modn_dense_float cimport Matrix_modn_dense_float @@ -522,7 +520,6 @@ cdef class Matrix_integer_dense(Matrix_dense): # TODO: *maybe* redo this to use mpz_import and mpz_export # from sec 5.14 of the GMP manual. ?? cdef int i, j, len_so_far, m, n - cdef char *a cdef char *s cdef char *t cdef char *tmp @@ -1096,7 +1093,6 @@ cdef class Matrix_integer_dense(Matrix_dense): sig_off() return ans - ######################################################################## # LEVEL 3 functionality (Optional) # * __deepcopy__ @@ -1374,12 +1370,12 @@ cdef class Matrix_integer_dense(Matrix_dense): if algorithm == 'flint': g = (<Polynomial_integer_dense_flint> PolynomialRing(ZZ, names=var).gen())._new() sig_on() - fmpz_mat_charpoly(g.__poly, self._matrix) + fmpz_mat_charpoly(g._poly, self._matrix) sig_off() elif algorithm == 'linbox': g = (<Polynomial_integer_dense_flint> PolynomialRing(ZZ, names=var).gen())._new() sig_on() - linbox_fmpz_mat_charpoly(g.__poly, self._matrix) + linbox_fmpz_mat_charpoly(g._poly, self._matrix) sig_off() elif algorithm == 'generic': g = Matrix_dense.charpoly(self, var) @@ -1463,7 +1459,7 @@ cdef class Matrix_integer_dense(Matrix_dense): if algorithm == 'linbox': g = (<Polynomial_integer_dense_flint> PolynomialRing(ZZ, names=var).gen())._new() sig_on() - linbox_fmpz_mat_minpoly(g.__poly, self._matrix) + linbox_fmpz_mat_minpoly(g._poly, self._matrix) sig_off() elif algorithm == 'generic': g = Matrix_dense.minpoly(self, var) @@ -1540,18 +1536,13 @@ cdef class Matrix_integer_dense(Matrix_dense): """ cdef Integer h cdef Matrix_integer_dense left = <Matrix_integer_dense>self - cdef mod_int *moduli - cdef int i, n, k - cdef object parent + cdef int i, k nr = left._nrows nc = right._ncols - snc = left._ncols - cdef Matrix_integer_dense result - h = left.height() * right.height() * left.ncols() verbose('multiplying matrices of height %s and %s'%(left.height(),right.height())) mm = MultiModularBasis(h) @@ -1605,7 +1596,6 @@ cdef class Matrix_integer_dense(Matrix_dense): from .matrix_modn_dense_double import MAX_MODULUS as MAX_MODULUS_DOUBLE cdef Py_ssize_t i, j - cdef mpz_t* self_row cdef float* res_row_f cdef Matrix_modn_dense_float res_f @@ -1617,7 +1607,7 @@ cdef class Matrix_integer_dense(Matrix_dense): return self._mod_two() elif p < MAX_MODULUS_FLOAT: res_f = Matrix_modn_dense_float.__new__(Matrix_modn_dense_float, - matrix_space.MatrixSpace(IntegerModRing(p), self._nrows, self._ncols, sparse=False), None, None, None) + matrix_space.MatrixSpace(IntegerModRing(p), self._nrows, self._ncols, sparse=False), None, None, None, zeroed_alloc=False) for i from 0 <= i < self._nrows: res_row_f = res_f._matrix[i] for j from 0 <= j < self._ncols: @@ -1626,7 +1616,7 @@ cdef class Matrix_integer_dense(Matrix_dense): elif p < MAX_MODULUS_DOUBLE: res_d = Matrix_modn_dense_double.__new__(Matrix_modn_dense_double, - matrix_space.MatrixSpace(IntegerModRing(p), self._nrows, self._ncols, sparse=False), None, None, None) + matrix_space.MatrixSpace(IntegerModRing(p), self._nrows, self._ncols, sparse=False), None, None, None, zeroed_alloc=False) for i from 0 <= i < self._nrows: res_row_d = res_d._matrix[i] for j from 0 <= j < self._ncols: @@ -1652,11 +1642,11 @@ cdef class Matrix_integer_dense(Matrix_dense): if p < MAX_MODULUS_FLOAT: res.append( Matrix_modn_dense_float.__new__(Matrix_modn_dense_float, matrix_space.MatrixSpace(IntegerModRing(p), self._nrows, self._ncols, sparse=False), - None, None, None) ) + None, None, None, zeroed_alloc=False) ) elif p < MAX_MODULUS_DOUBLE: res.append( Matrix_modn_dense_double.__new__(Matrix_modn_dense_double, matrix_space.MatrixSpace(IntegerModRing(p), self._nrows, self._ncols, sparse=False), - None, None, None) ) + None, None, None, zeroed_alloc=False) ) else: raise ValueError("p=%d too big."%p) @@ -2019,7 +2009,7 @@ cdef class Matrix_integer_dense(Matrix_dense): if ans is not None: return ans - cdef Matrix_integer_dense H_m,w,U + cdef Matrix_integer_dense H_m, U cdef Py_ssize_t nr, nc, n, i, j nr = self._nrows nc = self._ncols @@ -2457,10 +2447,10 @@ cdef class Matrix_integer_dense(Matrix_dense): :meth:`elementary_divisors` """ - X = self.matrix_space()([self[i,j] for i in xrange(self._nrows-1,-1,-1) for j in xrange(self._ncols-1,-1,-1)]) + X = self.matrix_space()([self[i,j] for i in range(self._nrows-1,-1,-1) for j in range(self._ncols-1,-1,-1)]) v = X.__pari__().matsnf(1).sage() # need to reverse order of rows of U, columns of V, and both of D. - D = self.matrix_space()([v[2][i,j] for i in xrange(self._nrows-1,-1,-1) for j in xrange(self._ncols-1,-1,-1)]) + D = self.matrix_space()([v[2][i,j] for i in range(self._nrows-1,-1,-1) for j in range(self._ncols-1,-1,-1)]) if not transformation: return D @@ -2474,13 +2464,13 @@ cdef class Matrix_integer_dense(Matrix_dense): # silly special cases for matrices with 0 columns (PARI has a unique empty matrix) U = self.matrix_space(ncols = self._nrows)(1) else: - U = self.matrix_space(ncols = self._nrows)([v[0][i,j] for i in xrange(self._nrows-1,-1,-1) for j in xrange(self._nrows-1,-1,-1)]) + U = self.matrix_space(ncols = self._nrows)([v[0][i,j] for i in range(self._nrows-1,-1,-1) for j in range(self._nrows-1,-1,-1)]) if self._nrows == 0: # silly special cases for matrices with 0 rows (PARI has a unique empty matrix) V = self.matrix_space(nrows = self._ncols)(1) else: - V = self.matrix_space(nrows = self._ncols)([v[1][i,j] for i in xrange(self._ncols-1,-1,-1) for j in xrange(self._ncols-1,-1,-1)]) + V = self.matrix_space(nrows = self._ncols)([v[1][i,j] for i in range(self._ncols-1,-1,-1) for j in range(self._ncols-1,-1,-1)]) return D, U, V @@ -2746,10 +2736,9 @@ cdef class Matrix_integer_dense(Matrix_dense): import sage.libs.ntl.ntl_mat_ZZ return sage.libs.ntl.ntl_mat_ZZ.ntl_mat_ZZ(self._nrows,self._ncols, self.list()) - - #################################################################################### + ####################################################################### # LLL - #################################################################################### + ####################################################################### def BKZ(self, delta=None, algorithm="fpLLL", fp=None, block_size=10, prune=0, use_givens=False, precision=0, proof=None, **kwds): @@ -3313,7 +3302,7 @@ cdef class Matrix_integer_dense(Matrix_dense): #For any $i<d$, we have $\delta |b_i^*|^2 <= |b_{i+1}^* + mu_{i+1, i} b_i^* |^2$ norms = [G[i].norm()**2 for i in range(len(G))] - for i in xrange(1,self.nrows()): + for i in range(1,self.nrows()): if norms[i] < (delta - mu[i,i-1]**2) * norms[i-1]: return False return True @@ -3413,7 +3402,7 @@ cdef class Matrix_integer_dense(Matrix_dense): ... ZeroDivisionError: The modulus cannot be zero """ - from .misc import matrix_integer_dense_rational_reconstruction + from .misc_flint import matrix_integer_dense_rational_reconstruction return matrix_integer_dense_rational_reconstruction(self, N) def randomize(self, density=1, x=None, y=None, distribution=None, @@ -3762,7 +3751,6 @@ cdef class Matrix_integer_dense(Matrix_dense): if not self.is_square(): raise ValueError("self must be a square matrix") - cdef Py_ssize_t n = self.nrows() cdef Integer det = Integer() cdef fmpz_t e @@ -4681,7 +4669,7 @@ cdef class Matrix_integer_dense(Matrix_dense): """ if self._nrows == 0: pivots = [] - nonpivots = list(xrange(self._ncols)) + nonpivots = list(range(self._ncols)) X = self.__copy__() d = Integer(1) return pivots, nonpivots, X, d @@ -4889,7 +4877,7 @@ cdef class Matrix_integer_dense(Matrix_dense): [ 0 0 545], [0, 1, 2] ) """ - cdef Py_ssize_t i, j, piv, n = self._nrows, m = self._ncols + cdef Py_ssize_t i, j, n = self._nrows, m = self._ncols from .constructor import matrix @@ -4950,7 +4938,6 @@ cdef class Matrix_integer_dense(Matrix_dense): new_top = s*row_i + t*row_n new_bot = bg*row_i - ag*row_n - # OK -- now we have to make sure the top part of the matrix # but with row i replaced by # r = s*row_i[j] + t*row_n[j] @@ -4958,7 +4945,7 @@ cdef class Matrix_integer_dense(Matrix_dense): # function with the top part of A (all but last row) and the # row r. - zz = list(xrange(A.nrows() - 1)) + zz = list(range(A.nrows() - 1)) del zz[i] top_mat = A.matrix_from_rows(zz) new_pivots = list(pivots) @@ -5168,7 +5155,6 @@ cdef class Matrix_integer_dense(Matrix_dense): sig_free(T_rows) return res - ################################################################# # operations with matrices ################################################################# @@ -5387,9 +5373,8 @@ cdef class Matrix_integer_dense(Matrix_dense): n = ns + na cdef Matrix_integer_dense Z - Z = self.new_matrix(nrows = m, ncols = n) - cdef Py_ssize_t i, j, p, qs, qa - p, qs, qa = 0, 0, 0 + Z = self.new_matrix(nrows=m, ncols=n) + cdef Py_ssize_t i, j for i from 0 <= i < m: for j from 0 <= j < ns: fmpz_set(fmpz_mat_entry(Z._matrix,i,j), @@ -5462,7 +5447,7 @@ cdef class Matrix_integer_dense(Matrix_dense): Return matrix obtained from self by deleting all zero columns along with the positions of those columns. - OUTPUT: matrix list of integers + OUTPUT: (matrix, list of integers) EXAMPLES:: @@ -5475,10 +5460,9 @@ cdef class Matrix_integer_dense(Matrix_dense): [-1 5], [1] ) """ - C = self.columns() - zero_cols = [i for i,v in enumerate(self.columns()) if v.is_zero()] + zero_cols = [i for i, v in enumerate(self.columns()) if v.is_zero()] s = set(zero_cols) - nonzero_cols = [i for i in range(self.ncols()) if not (i in s)] + nonzero_cols = [i for i in range(self.ncols()) if i not in s] return self.matrix_from_columns(nonzero_cols), zero_cols def _insert_zero_columns(self, cols): diff --git a/src/sage/matrix/matrix_integer_dense_hnf.py b/src/sage/matrix/matrix_integer_dense_hnf.py index acdb0f09cc4..a899ae9f6e0 100644 --- a/src/sage/matrix/matrix_integer_dense_hnf.py +++ b/src/sage/matrix/matrix_integer_dense_hnf.py @@ -8,14 +8,13 @@ from copy import copy -from sage.misc.misc import cputime +from sage.arith.misc import CRT_list, previous_prime +from sage.matrix.constructor import identity_matrix, matrix, random_matrix +from sage.misc.timing import cputime from sage.misc.verbose import verbose -from sage.matrix.constructor import (random_matrix, matrix, identity_matrix) - +from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR -from sage.rings.integer import Integer -from sage.arith.all import previous_prime, CRT_list def max_det_prime(n): @@ -1189,9 +1188,9 @@ def benchmark_hnf(nrange, bits=4): EXAMPLES:: sage: import sage.matrix.matrix_integer_dense_hnf as hnf - sage: hnf.benchmark_hnf([50,100],32) - ('sage', 50, 32, ...), - ('sage', 100, 32, ...), + sage: hnf.benchmark_hnf([10,25],32) + ('sage', 10, 32, ...), + ('sage', 25, 32, ...), """ b = 2**bits for n in nrange: diff --git a/src/sage/matrix/matrix_integer_dense_saturation.py b/src/sage/matrix/matrix_integer_dense_saturation.py index a7ce81fc86a..365c8d830bf 100644 --- a/src/sage/matrix/matrix_integer_dense_saturation.py +++ b/src/sage/matrix/matrix_integer_dense_saturation.py @@ -2,14 +2,15 @@ Saturation over ZZ """ -from sage.rings.integer_ring import ZZ -from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from sage.arith.all import binomial, gcd +from copy import copy + +from sage.arith.misc import binomial, GCD as gcd +from sage.matrix import matrix_integer_dense_hnf from sage.matrix.constructor import identity_matrix, random_matrix -from sage.misc.verbose import verbose from sage.misc.randstate import current_randstate -from . import matrix_integer_dense_hnf -from copy import copy +from sage.misc.verbose import verbose +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.integer_ring import ZZ def p_saturation(A, p, proof=True): diff --git a/src/sage/matrix/matrix_integer_sparse.pyx b/src/sage/matrix/matrix_integer_sparse.pyx index a73432e588c..f6d79abf56a 100644 --- a/src/sage/matrix/matrix_integer_sparse.pyx +++ b/src/sage/matrix/matrix_integer_sparse.pyx @@ -29,7 +29,7 @@ TESTS:: from cysignals.memory cimport check_calloc, sig_free from cysignals.signals cimport sig_on, sig_off -from cpython.int cimport PyInt_FromSize_t +from cpython.long cimport PyLong_FromSize_t from sage.ext.stdsage cimport PY_NEW from sage.ext.mod_int cimport * @@ -62,7 +62,7 @@ from sage.libs.flint.fmpz_poly cimport fmpz_poly_fit_length, fmpz_poly_set_coeff from sage.libs.flint.fmpz_mat cimport fmpz_mat_entry from .matrix_modn_sparse cimport Matrix_modn_sparse -from sage.structure.element cimport ModuleElement, RingElement, Element, Vector +from sage.structure.element cimport Element import sage.matrix.matrix_space as matrix_space @@ -182,24 +182,21 @@ cdef class Matrix_integer_sparse(Matrix_sparse): return M cpdef _add_(self, right): - cdef Py_ssize_t i, j - cdef mpz_vector *self_row - cdef mpz_vector *M_row + cdef Py_ssize_t i cdef Matrix_integer_sparse M M = Matrix_integer_sparse.__new__(Matrix_integer_sparse, self._parent, None, None, None) cdef mpz_t mul mpz_init_set_si(mul,1) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): mpz_vector_clear(&M._matrix[i]) - add_mpz_vector_init(&M._matrix[i], &self._matrix[i], &(<Matrix_integer_sparse>right)._matrix[i], mul) + add_mpz_vector_init(&M._matrix[i], &self._matrix[i], + &(<Matrix_integer_sparse>right)._matrix[i], mul) mpz_clear(mul) return M cpdef _sub_(self, right): - cdef Py_ssize_t i, j - cdef mpz_vector *self_row - cdef mpz_vector *M_row + cdef Py_ssize_t i cdef Matrix_integer_sparse M M = Matrix_integer_sparse.__new__(Matrix_integer_sparse, self._parent, None, None, None) @@ -214,6 +211,7 @@ cdef class Matrix_integer_sparse(Matrix_sparse): def _dict(self): """ Unsafe version of the dict method, mainly for internal use. + This may return the dict of elements, but as an *unsafe* reference to the underlying dict of the object. It might be dangerous if you change entries of the returned dict. @@ -222,13 +220,13 @@ cdef class Matrix_integer_sparse(Matrix_sparse): if d is not None: return d - cdef Py_ssize_t i, j, k + cdef Py_ssize_t i, j d = {} - for i from 0 <= i < self._nrows: - for j from 0 <= j < self._matrix[i].num_nonzero: + for i in range(self._nrows): + for j in range(self._matrix[i].num_nonzero): x = Integer() mpz_set((<Integer>x).value, self._matrix[i].entries[j]) - d[(int(i),int(self._matrix[i].positions[j]))] = x + d[(int(i), int(self._matrix[i].positions[j]))] = x self.cache('dict', d) return d @@ -348,7 +346,7 @@ cdef class Matrix_integer_sparse(Matrix_sparse): if copy: return list(x) return x - nzc = [[] for _ in xrange(self._ncols)] + nzc = [[] for _ in range(self._ncols)] cdef Py_ssize_t i, j for i from 0 <= i < self._nrows: for j from 0 <= j < self._matrix[i].num_nonzero: @@ -399,13 +397,15 @@ cdef class Matrix_integer_sparse(Matrix_sparse): def rational_reconstruction(self, N): """ - Use rational reconstruction to lift self to a matrix over the - rational numbers (if possible), where we view self as a matrix - modulo N. + Use rational reconstruction to lift ``self`` to a matrix over the + rational numbers (if possible), where we view ``self`` as a matrix + modulo `N`. EXAMPLES:: - sage: A = matrix(ZZ, 3, 4, [(1/3)%500, 2, 3, (-4)%500, 7, 2, 2, 3, 4, 3, 4, (5/7)%500], sparse=True) + sage: A = matrix(ZZ, 3, 4, [(1/3)%500, 2, 3, (-4)%500, + ....: 7, 2, 2, 3, + ....: 4, 3, 4, (5/7)%500], sparse=True) sage: A.rational_reconstruction(500) [1/3 2 3 -4] [ 7 2 2 3] @@ -415,7 +415,7 @@ cdef class Matrix_integer_sparse(Matrix_sparse): Check that :trac:`9345` is fixed:: - sage: A = random_matrix(ZZ, 3, 3, sparse = True) + sage: A = random_matrix(ZZ, 3, 3, sparse=True) sage: A.rational_reconstruction(0) Traceback (most recent call last): ... @@ -721,7 +721,7 @@ cdef class Matrix_integer_sparse(Matrix_sparse): del M - return PyInt_FromSize_t(r) + return PyLong_FromSize_t(r) def _det_linbox(self): r""" @@ -867,10 +867,10 @@ cdef class Matrix_integer_sparse(Matrix_sparse): sig_off() cdef size_t i - fmpz_poly_fit_length(g.__poly, p.size()) + fmpz_poly_fit_length(g._poly, p.size()) for i in range(p.size()): - fmpz_poly_set_coeff_mpz(g.__poly, i, p[0][i].get_mpz_const()) - _fmpz_poly_set_length(g.__poly, p.size()) + fmpz_poly_set_coeff_mpz(g._poly, i, p[0][i].get_mpz_const()) + _fmpz_poly_set_length(g._poly, p.size()) del M del p @@ -966,10 +966,10 @@ cdef class Matrix_integer_sparse(Matrix_sparse): sig_off() cdef size_t i - fmpz_poly_fit_length(g.__poly, p.size()) + fmpz_poly_fit_length(g._poly, p.size()) for i in range(p.size()): - fmpz_poly_set_coeff_mpz(g.__poly, i, p[0][i].get_mpz_const()) - _fmpz_poly_set_length(g.__poly, p.size()) + fmpz_poly_set_coeff_mpz(g._poly, i, p[0][i].get_mpz_const()) + _fmpz_poly_set_length(g._poly, p.size()) del M del p diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 5ac8832ffe9..6365eb271aa 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -106,17 +106,15 @@ TESTS:: # **************************************************************************** from cysignals.memory cimport check_malloc, sig_free -from cysignals.signals cimport sig_check, sig_on, sig_str, sig_off +from cysignals.signals cimport sig_on, sig_str, sig_off cimport sage.matrix.matrix_dense as matrix_dense from .args cimport SparseEntry, MatrixArgs_init from libc.stdio cimport * -from sage.structure.element cimport (Matrix, Vector, - ModuleElement, Element) +from sage.structure.element cimport (Matrix, Vector) from sage.modules.free_module_element cimport FreeModuleElement from sage.libs.gmp.random cimport * from sage.misc.randstate cimport randstate, current_randstate -from sage.misc.misc import cputime from sage.misc.verbose import verbose, get_verbose VectorSpace = None from sage.modules.vector_mod2_dense cimport Vector_mod2_dense @@ -502,7 +500,6 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse i = i + self._nrows if from_list: return self.rows(copy=False)[i] - cdef Py_ssize_t j cdef Vector_mod2_dense z = Vector_mod2_dense.__new__(Vector_mod2_dense) global VectorSpace if VectorSpace is None: @@ -883,8 +880,6 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse sage: A^(-1) [] """ - cdef int k = 0 - cdef mzd_t *I cdef Matrix_mod2_dense A if self._nrows != self._ncols: @@ -1035,7 +1030,7 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse self.cache('rank', 0) self.cache('pivots', ()) return self - cdef int k, n, full + cdef int k, full full = int(reduced) @@ -1761,7 +1756,6 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse """ cdef Py_ssize_t i, j, k, n cdef char *s - cdef char *t if self._nrows == 0 or self._ncols == 0: data = '' @@ -2059,11 +2053,13 @@ def unpickle_matrix_mod2_dense_v2(r, c, data, size, immutable=False): return A + from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.matrix.matrix_mod2_dense', 'unpickle_matrix_mod2_dense_v1', unpickle_matrix_mod2_dense_v2) + def from_png(filename): """ Returns a dense matrix over GF(2) from a 1-bit PNG image read from diff --git a/src/sage/matrix/matrix_modn_dense_double.pyx b/src/sage/matrix/matrix_modn_dense_double.pyx index 08fb1c4e989..12bc79159d3 100644 --- a/src/sage/matrix/matrix_modn_dense_double.pyx +++ b/src/sage/matrix/matrix_modn_dense_double.pyx @@ -4,7 +4,7 @@ # distutils: include_dirs = CBLAS_INCDIR # distutils: extra_compile_args = -D_XPG6 r""" -Dense matrices over `\ZZ/n\ZZ` for `n < 2^{23}` using LinBox's ``Modular<double>`` +Dense matrices over `\ZZ/n\ZZ` for `n < 94906266` using LinBox's ``Modular<double>`` AUTHORS: @@ -38,7 +38,7 @@ from sage.libs.linbox.fflas cimport \ ctypedef Poly1Dom[ModField, Dense] ModDensePolyRing # Limit for LinBox Modular<double> -MAX_MODULUS = 2**23 +MAX_MODULUS = 94906266 from sage.rings.finite_rings.integer_mod cimport IntegerMod_int64 @@ -47,12 +47,13 @@ include "matrix_modn_dense_template.pxi" cdef class Matrix_modn_dense_double(Matrix_modn_dense_template): r""" - Dense matrices over `\ZZ/n\ZZ` for `n < 2^{23}` using LinBox's ``Modular<double>`` + Dense matrices over `\ZZ/n\ZZ` for `n < 94906266` using LinBox's ``Modular<double>`` These are matrices with integer entries mod ``n`` represented as floating-point numbers in a 64-bit word for use with LinBox routines. - This allows for ``n`` up to `2^{23}`. The analogous - ``Matrix_modn_dense_float`` class is used for smaller moduli. + This allows for ``n`` up to `94906266`. By default, the analogous + ``Matrix_modn_dense_float`` class is used for smaller moduli, specifically + for ``n`` up to `2^{8}`. Routines here are for the most basic access, see the ``matrix_modn_dense_template.pxi`` file for higher-level routines. @@ -69,7 +70,7 @@ cdef class Matrix_modn_dense_double(Matrix_modn_dense_template): <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int64'> """ self._get_template = self._base_ring.zero() - # note that INTEGER_MOD_INT32_LIMIT is ceil(sqrt(2^31-1)) < 2^23 + # note that INTEGER_MOD_INT32_LIMIT is ceil(sqrt(2^31-1)) < 94906266 self._fits_int32 = ((<Matrix_modn_dense_template>self).p <= INTEGER_MOD_INT32_LIMIT) cdef void set_unsafe_int(self, Py_ssize_t i, Py_ssize_t j, int value): diff --git a/src/sage/matrix/matrix_modn_dense_float.pyx b/src/sage/matrix/matrix_modn_dense_float.pyx index 646570ad65e..8744cf494e3 100644 --- a/src/sage/matrix/matrix_modn_dense_float.pyx +++ b/src/sage/matrix/matrix_modn_dense_float.pyx @@ -3,7 +3,7 @@ # distutils: library_dirs = CBLAS_LIBDIR # distutils: include_dirs = CBLAS_INCDIR r""" -Dense matrices over `\ZZ/n\ZZ` for `n < 2^{11}` using LinBox's ``Modular<float>`` +Dense matrices over `\ZZ/n\ZZ` for `n < 2^{8}` using LinBox's ``Modular<float>`` AUTHORS: - Burcin Erocal @@ -31,7 +31,7 @@ from sage.libs.linbox.linbox cimport \ from sage.libs.linbox.fflas cimport \ fgemm, pfgemm, fgemv, Det, pDet, Rank, pRank, ReducedRowEchelonForm, pReducedRowEchelonForm, applyP, \ - MinPoly, CharPoly, MinPoly, \ + MinPoly, CharPoly, \ ModFloatDensePolynomial as ModDensePoly ctypedef Poly1Dom[ModField, Dense] ModDensePolyRing @@ -44,15 +44,16 @@ include "matrix_modn_dense_template.pxi" cdef class Matrix_modn_dense_float(Matrix_modn_dense_template): r""" - Dense matrices over `\ZZ/n\ZZ` for `n < 2^{11}` using LinBox's ``Modular<float>`` + Dense matrices over `\ZZ/n\ZZ` for `n < 2^{8}` using LinBox's ``Modular<float>`` These are matrices with integer entries mod ``n`` represented as floating-point numbers in a 32-bit word for use with LinBox routines. - This allows for ``n`` up to `2^{11}`. The - ``Matrix_modn_dense_double`` class is used for larger moduli. + This could allow for ``n`` up to `2^{11}`, but for performance reasons + this is limited to ``n`` up to `2^{8}`, and for larger moduli the + ``Matrix_modn_dense_double`` class is used. Routines here are for the most basic access, see the - `matrix_modn_dense_template.pxi` file for higher-level routines. + ``matrix_modn_dense_template.pxi`` file for higher-level routines. """ def __cinit__(self): """ diff --git a/src/sage/matrix/matrix_modn_dense_template.pxi b/src/sage/matrix/matrix_modn_dense_template.pxi index 2f2acfd562a..69569297923 100644 --- a/src/sage/matrix/matrix_modn_dense_template.pxi +++ b/src/sage/matrix/matrix_modn_dense_template.pxi @@ -90,7 +90,7 @@ We test corner cases for multiplication:: from libc.stdint cimport uint64_t from cpython.bytes cimport * -from cysignals.memory cimport check_malloc, check_allocarray, sig_malloc, sig_free +from cysignals.memory cimport check_malloc, check_allocarray, check_calloc, sig_malloc, sig_free from cysignals.signals cimport sig_check, sig_on, sig_off from sage.libs.gmp.mpz cimport * @@ -109,13 +109,13 @@ from libc.stdio cimport snprintf from sage.modules.vector_modn_dense cimport Vector_modn_dense -from sage.arith.all import is_prime +from sage.arith.misc import is_prime from sage.structure.element cimport (Element, Vector, Matrix, ModuleElement, RingElement) from sage.matrix.matrix_dense cimport Matrix_dense from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense from sage.rings.finite_rings.integer_mod cimport IntegerMod_int, IntegerMod_abstract -from sage.misc.misc import cputime +from sage.misc.timing import cputime from sage.misc.verbose import verbose, get_verbose from sage.rings.integer cimport Integer from sage.rings.integer_ring import ZZ @@ -123,7 +123,7 @@ from sage.structure.proof.proof import get_flag as get_proof_flag from sage.structure.richcmp cimport rich_to_bool from sage.misc.randstate cimport randstate, current_randstate import sage.matrix.matrix_space as matrix_space -from .args cimport MatrixArgs_init +from .args cimport SparseEntry, MatrixArgs_init from sage.cpython.string cimport char_to_str @@ -221,9 +221,14 @@ cdef inline linbox_echelonize_efd(celement modulus, celement* entries, Py_ssize_ return 0,[] cdef ModField *F = new ModField(<long>modulus) - cdef DenseMatrix *A = new DenseMatrix(F[0], <ModField.Element*>entries,<Py_ssize_t>nrows, <Py_ssize_t>ncols) - cdef Py_ssize_t r = reducedRowEchelonize(A[0]) + cdef DenseMatrix *A = new DenseMatrix(F[0], nrows, ncols) + cdef Py_ssize_t i,j + for i in range(nrows): + for j in range(ncols): + A.setEntry(i, j, entries[i*ncols+j]) + + cdef Py_ssize_t r = reducedRowEchelonize(A[0]) for i in range(nrows): for j in range(ncols): entries[i*ncols+j] = <celement>A.getEntry(i,j) @@ -436,15 +441,18 @@ cpdef __matrix_from_rows_of_matrices(X): cdef class Matrix_modn_dense_template(Matrix_dense): - def __cinit__(self): + def __cinit__(self, *args, bint zeroed_alloc=True, **kwds): cdef long p = self._base_ring.characteristic() self.p = p if p >= MAX_MODULUS: raise OverflowError("p (=%s) must be < %s."%(p, MAX_MODULUS)) - self._entries = <celement *>check_allocarray(self._nrows * self._ncols, sizeof(celement)) + if zeroed_alloc: + self._entries = <celement *>check_calloc(self._nrows * self._ncols, sizeof(celement)) + else: + self._entries = <celement *>check_allocarray(self._nrows * self._ncols, sizeof(celement)) + self._matrix = <celement **>check_allocarray(self._nrows, sizeof(celement*)) - cdef unsigned int k cdef Py_ssize_t i k = 0 @@ -457,7 +465,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): TESTS:: sage: import gc - sage: for i in range(10): + sage: for i in range(10): # needs sage.rings.finite_rings ....: A = random_matrix(GF(7),1000,1000) ....: B = random_matrix(Integers(10),1000,1000) ....: C = random_matrix(GF(16007),1000,1000) @@ -503,37 +511,38 @@ cdef class Matrix_modn_dense_template(Matrix_dense): [6 5] [4 2] - sage: Matrix(GF(6434383), 2, 2, [-1, int(-2), GF(7)(-3), 1/4]) + sage: Matrix(GF(6434383), 2, 2, [-1, int(-2), GF(7)(-3), 1/4]) # needs sage.rings.finite_rings [6434382 6434381] [ 4 1608596] - sage: Matrix(Integers(4618990), 2, 2, [-1, int(-2), GF(7)(-3), 1/7]) + sage: Matrix(Integers(4618990), 2, 2, [-1, int(-2), GF(7)(-3), 1/7]) # needs sage.rings.finite_rings [4618989 4618988] [ 4 2639423] """ ma = MatrixArgs_init(parent, entries) cdef long i, j - it = ma.iter(False) + it = ma.iter(convert=False, sparse=True) R = ma.base p = R.characteristic() - for i in range(ma.nrows): - v = self._matrix[i] - for j in range(ma.ncols): - x = next(it) - if type(x) is int: - tmp = (<long>x) % p - v[j] = tmp + (tmp<0)*p - elif type(x) is IntegerMod_int and (<IntegerMod_int>x)._parent is R: - v[j] = <celement>(<IntegerMod_int>x).ivalue - elif type(x) is Integer: - if coerce: - v[j] = mpz_fdiv_ui((<Integer>x).value, p) - else: - v[j] = mpz_get_ui((<Integer>x).value) - elif coerce: - v[j] = R(x) + + for t in it: + se = <SparseEntry>t + x = se.entry + v = self._matrix[se.i] + if type(x) is int: + tmp = (<long>x) % p + v[se.j] = tmp + (tmp<0)*p + elif type(x) is IntegerMod_int and (<IntegerMod_int>x)._parent is R: + v[se.j] = <celement>(<IntegerMod_int>x).ivalue + elif type(x) is Integer: + if coerce: + v[se.j] = mpz_fdiv_ui((<Integer>x).value, p) else: - v[j] = <celement>x + v[se.j] = mpz_get_ui((<Integer>x).value) + elif coerce: + v[se.j] = R(x) + else: + v[se.j] = <celement>x cdef long _hash_(self) except -1: """ @@ -663,6 +672,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): And for larger modulus:: + sage: # needs sage.rings.finite_rings sage: A = random_matrix(GF(1009), 51, 5) sage: data, version = A._pickle() sage: B = A.parent()(0) @@ -781,7 +791,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef Matrix_modn_dense_template M cdef celement p = self.p - M = self.__class__.__new__(self.__class__, self._parent,None,None,None) + M = self.__class__.__new__(self.__class__, self._parent,None,None,None, zeroed_alloc=False) sig_on() for i in range(self._nrows*self._ncols): @@ -820,7 +830,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef celement p = self.p cdef celement a = left - M = self.__class__.__new__(self.__class__, self._parent,None,None,None) + M = self.__class__.__new__(self.__class__, self._parent,None,None,None,zeroed_alloc=False) sig_on() for i in range(self._nrows*self._ncols): @@ -839,7 +849,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): False """ cdef Matrix_modn_dense_template A - A = self.__class__.__new__(self.__class__, self._parent, 0, 0, 0) + A = self.__class__.__new__(self.__class__,self._parent,None,None,None,zeroed_alloc=False) memcpy(A._entries, self._entries, sizeof(celement)*self._nrows*self._ncols) if self._subdivisions is not None: A.subdivide(*self.subdivisions()) @@ -878,7 +888,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef celement k, p cdef Matrix_modn_dense_template M - M = self.__class__.__new__(self.__class__, self._parent,None,None,None) + M = self.__class__.__new__(self.__class__, self._parent,None,None,None,zeroed_alloc=False) p = self.p cdef celement* other_ent = (<Matrix_modn_dense_template>right)._entries @@ -915,7 +925,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef celement k, p cdef Matrix_modn_dense_template M - M = self.__class__.__new__(self.__class__, self._parent, None, None, None) + M = self.__class__.__new__(self.__class__, self._parent, None, None, None, zeroed_alloc=False) p = self.p cdef celement* other_ent = (<Matrix_modn_dense_template>right)._entries @@ -958,11 +968,11 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: A = matrix(ZZ, 10, 10, range(1000, 1100)) sage: A.change_ring(GF(17)) == A.change_ring(GF(17)) True - sage: A.change_ring(GF(17)) == A.change_ring(GF(19)) + sage: A.change_ring(GF(17)) == A.change_ring(GF(19)) # needs sage.rings.finite_rings False - sage: A.change_ring(GF(17)) == A.change_ring(Integers(2000)) + sage: A.change_ring(GF(17)) == A.change_ring(Integers(2000)) # needs sage.rings.finite_rings False - sage: A.change_ring(GF(17)) == A.change_ring(Integers(2000)) + sage: A.change_ring(GF(17)) == A.change_ring(Integers(2000)) # needs sage.rings.finite_rings False """ cdef Py_ssize_t i @@ -1056,8 +1066,8 @@ cdef class Matrix_modn_dense_template(Matrix_dense): :: - sage: A = random_matrix(GF(16007),2,2) - sage: B = random_matrix(GF(16007),2,2) + sage: A = random_matrix(GF(16007),2,2) # needs sage.rings.finite_rings + sage: B = random_matrix(GF(16007),2,2) # needs sage.rings.finite_rings sage: C = A*B sage: all(C[i, j] == sum(A[i, k]*B[k, j] for k in range(2)) for i in range(2) for j in range(2)) True @@ -1068,6 +1078,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): :: + sage: # needs sage.rings.finite_rings sage: A = random_matrix(GF(15991), 201, 117) sage: B = random_matrix(GF(15991), 117, 195) sage: C = random_matrix(GF(15991), 201, 117) @@ -1082,7 +1093,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): :: - sage: A = random_matrix(GF(16007), 200, 200) + sage: A = random_matrix(GF(16007), 200, 200) # needs sage.rings.finite_rings sage: MS = parent(A) sage: (MS(0) * A) == 0 True @@ -1155,13 +1166,13 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: matrix(v*A) == matrix(v)*A True - sage: A = random_matrix(GF(4796509), 10, 20) - sage: v = random_vector(GF(4796509), 10) + sage: A = random_matrix(GF(4796509), 10, 20) # needs sage.rings.finite_rings + sage: v = random_vector(GF(4796509), 10) # needs sage.rings.finite_rings sage: matrix(v*A) == matrix(v)*A True sage: A = random_matrix(Integers(16337), 10, 20) - sage: v = random_vector(Integers(16337), 10) + sage: v = random_vector(Integers(16337), 10) # needs sage.rings.finite_rings sage: matrix(v*A) == matrix(v)*A True @@ -1208,13 +1219,13 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: matrix(A*v).transpose() == A*matrix(v).transpose() True - sage: A = random_matrix(GF(4796509), 10, 20) - sage: v = random_vector(GF(4796509), 20) + sage: A = random_matrix(GF(4796509), 10, 20) # needs sage.rings.finite_rings + sage: v = random_vector(GF(4796509), 20) # needs sage.rings.finite_rings sage: matrix(A*v).transpose() == A*matrix(v).transpose() True sage: A = random_matrix(Integers(16337), 10, 20) - sage: v = random_vector(Integers(16337), 20) + sage: v = random_vector(Integers(16337), 20) # needs sage.rings.finite_rings sage: matrix(A*v).transpose() == A*matrix(v).transpose() True """ @@ -1284,7 +1295,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): :: - sage: A = random_matrix(GF(2916337), 7, 7) + sage: A = random_matrix(GF(2916337), 7, 7) # needs sage.rings.finite_rings sage: B = copy(A) sage: char_p = A.characteristic_polynomial() sage: char_p(A) == 0 @@ -1323,27 +1334,27 @@ cdef class Matrix_modn_dense_template(Matrix_dense): ValueError: matrix must be square sage: A = matrix(GF(19), 10, 10) - sage: A.minimal_polynomial() + sage: A.minimal_polynomial() # needs sage.libs.pari x - sage: A = random_matrix(GF(4198973), 0, 0) - sage: A.minimal_polynomial() + sage: A = random_matrix(GF(4198973), 0, 0) # needs sage.rings.finite_rings + sage: A.minimal_polynomial() # needs sage.rings.finite_rings 1 - sage: A = random_matrix(GF(4198973), 0, 1) - sage: A.minimal_polynomial() + sage: A = random_matrix(GF(4198973), 0, 1) # needs sage.rings.finite_rings + sage: A.minimal_polynomial() # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: matrix must be square - sage: A = random_matrix(GF(4198973), 1, 0) - sage: A.minimal_polynomial() + sage: A = random_matrix(GF(4198973), 1, 0) # needs sage.rings.finite_rings + sage: A.minimal_polynomial() # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: matrix must be square - sage: A = matrix(GF(4198973), 10, 10) - sage: A.minimal_polynomial() + sage: A = matrix(GF(4198973), 10, 10) # needs sage.rings.finite_rings + sage: A.minimal_polynomial() # needs sage.rings.finite_rings x sage: A = Mat(GF(7),3,3)([0, 1, 2] * 3) @@ -1438,7 +1449,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): :: - sage: A = random_matrix(GF(1214471), 10, 10) + sage: A = random_matrix(GF(1214471), 10, 10) # needs sage.rings.finite_rings sage: B = copy(A) sage: min_p = A.minimal_polynomial(proof=True) sage: min_p(A) == 0 @@ -1469,29 +1480,29 @@ cdef class Matrix_modn_dense_template(Matrix_dense): ValueError: matrix must be square sage: A = matrix(GF(17), 10, 10) - sage: A.minimal_polynomial() + sage: A.minimal_polynomial() # needs sage.libs.pari x :: - sage: A = random_matrix(GF(2535919), 0, 0) - sage: A.minimal_polynomial() + sage: A = random_matrix(GF(2535919), 0, 0) # needs sage.rings.finite_rings + sage: A.minimal_polynomial() # needs sage.rings.finite_rings 1 - sage: A = random_matrix(GF(2535919), 0, 1) - sage: A.minimal_polynomial() + sage: A = random_matrix(GF(2535919), 0, 1) # needs sage.rings.finite_rings + sage: A.minimal_polynomial() # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: matrix must be square - sage: A = random_matrix(GF(2535919), 1, 0) - sage: A.minimal_polynomial() + sage: A = random_matrix(GF(2535919), 1, 0) # needs sage.rings.finite_rings + sage: A.minimal_polynomial() # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: matrix must be square - sage: A = matrix(GF(2535919), 10, 10) - sage: A.minimal_polynomial() + sage: A = matrix(GF(2535919), 10, 10) # needs sage.rings.finite_rings + sage: A.minimal_polynomial() # needs sage.rings.finite_rings x EXAMPLES:: @@ -1634,6 +1645,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): :: + sage: # needs sage.rings.finite_rings sage: A = random_matrix(GF(16007), 10, 20) sage: E = A.echelon_form() sage: A.row_space() == E.row_space() @@ -1651,6 +1663,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): Parallel computation:: + sage: # needs sage.rings.finite_rings sage: A = random_matrix(GF(65521),100,200) sage: Parallelism().set('linbox', nproc=2) sage: E = A.echelon_form() @@ -1682,6 +1695,8 @@ cdef class Matrix_modn_dense_template(Matrix_dense): [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] + + sage: # needs sage.rings.finite_rings sage: A = random_matrix(GF(16007), 0, 10) sage: A.echelon_form() [] @@ -2121,6 +2136,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): :: + sage: # needs sage.rings.finite_rings sage: A = random_matrix(GF(16007), 100, 100) sage: B = copy(A) sage: A.rank() @@ -2142,6 +2158,8 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: A = random_matrix(GF(7), 0, 1) sage: A.rank() 0 + + sage: # needs sage.rings.finite_rings sage: A = random_matrix(GF(16007), 0, 0) sage: A.rank() 0 @@ -2188,26 +2206,26 @@ cdef class Matrix_modn_dense_template(Matrix_dense): :: + sage: # needs sage.rings.finite_rings sage: A = random_matrix(GF(16007), 10, 10) sage: A.determinant().parent() is GF(16007) True :: + sage: # needs sage.rings.finite_rings sage: A = random_matrix(GF(16007), 100, 100) sage: A.determinant().parent() is GF(16007) True - - sage: A.determinant() == A.transpose().determinant() True - sage: B = random_matrix(GF(16007), 100, 100) sage: (A*B).determinant() == A.determinant() * B.determinant() True Parallel computation:: + sage: # needs sage.rings.finite_rings sage: A = random_matrix(GF(65521),200) sage: B = copy(A) sage: Parallelism().set('linbox', nproc=2) @@ -2232,22 +2250,20 @@ cdef class Matrix_modn_dense_template(Matrix_dense): ... ValueError: self must be a square matrix - sage: A = matrix(GF(7), 5, 5); A.det() + sage: A = matrix(GF(7), 5, 5); A.det() # needs sage.libs.pari 0 + sage: # needs sage.rings.finite_rings sage: A = random_matrix(GF(16007), 0, 0); A.det() 1 - sage: A = random_matrix(GF(16007), 0, 1); A.det() Traceback (most recent call last): ... ValueError: self must be a square matrix - sage: A = random_matrix(GF(16007), 1, 0); A.det() Traceback (most recent call last): ... ValueError: self must be a square matrix - sage: A = matrix(GF(16007), 5, 5); A.det() 0 """ @@ -2733,6 +2749,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: A.lift().parent() Full MatrixSpace of 2 by 3 dense matrices over Integer Ring + sage: # needs sage.rings.finite_rings sage: A = matrix(GF(16007),2,3,[1..6]) sage: A.lift() [1 2 3] @@ -3007,14 +3024,21 @@ cdef class Matrix_modn_dense_template(Matrix_dense): if nrows == -1: nrows = self._nrows - row - if col != 0 or ncols != self._ncols: - return self.matrix_from_rows_and_columns(range(row, row+nrows), range(col, col+ncols)) - if nrows < 0 or row < 0 or row + nrows > self._nrows: raise IndexError("rows out of range") + if ncols < 0 or col < 0 or col + ncols > self._ncols: + raise IndexError("columns out of range") + + cdef Matrix_modn_dense_template M = self.new_matrix(nrows=nrows, ncols=ncols) + + if col == 0 and ncols == self._ncols: + memcpy(M._entries, self._matrix[row], sizeof(celement)*ncols*nrows) + return M + + cdef Py_ssize_t i,r + for i,r in enumerate(range(row, row+nrows)) : + memcpy(M._matrix[i], self._matrix[r]+col, sizeof(celement)*ncols) - cdef Matrix_modn_dense_template M = self.new_matrix(nrows=nrows, ncols=self._ncols) - memcpy(M._entries, self._entries+row*ncols, sizeof(celement)*ncols*nrows) return M def _matrices_from_rows(self, Py_ssize_t nrows, Py_ssize_t ncols): @@ -3060,6 +3084,122 @@ cdef class Matrix_modn_dense_template(Matrix_dense): ans.append(M) return ans + def matrix_from_columns(self, columns): + """ + Return the matrix constructed from self using columns with indices + in the columns list. + + EXAMPLES:: + + sage: M = MatrixSpace(Integers(8),3,3) + sage: A = M(range(9)); A + [0 1 2] + [3 4 5] + [6 7 0] + sage: A.matrix_from_columns([2,1]) + [2 1] + [5 4] + [0 7] + """ + cdef Py_ssize_t ncols = len(columns) + + # Construct new matrix + cdef Matrix_modn_dense_template A = self.new_matrix(ncols=ncols) + cdef Py_ssize_t i, j, col + for j, col in enumerate(columns): + if col < 0 or col >= self._ncols: + raise IndexError("column index out of range") + for i in range(self._nrows): + A._matrix[i][j] = self._matrix[i][col] + + return A + + def matrix_from_rows(self, rows): + """ + Return the matrix constructed from self using rows with indices in + the rows list. + + EXAMPLES:: + + sage: M = MatrixSpace(Integers(8),3,3) + sage: A = M(range(9)); A + [0 1 2] + [3 4 5] + [6 7 0] + sage: A.matrix_from_rows([2,1]) + [6 7 0] + [3 4 5] + """ + cdef Py_ssize_t nrows = len(rows) + + # Construct new matrix + cdef Matrix_modn_dense_template A = self.new_matrix(nrows=nrows) + + cdef Py_ssize_t i, row + for i, row in enumerate(rows): + if row < 0 or row >= self._nrows: + raise IndexError("row index out of range") + memcpy(A._matrix[i], self._matrix[row], sizeof(celement)*self._ncols) + + return A + + def matrix_from_rows_and_columns(self, rows, columns): + """ + Return the matrix constructed from self from the given rows and + columns. + + EXAMPLES:: + + sage: M = MatrixSpace(Integers(8),3,3) + sage: A = M(range(9)); A + [0 1 2] + [3 4 5] + [6 7 0] + sage: A.matrix_from_rows_and_columns([1], [0,2]) + [3 5] + sage: A.matrix_from_rows_and_columns([1,2], [1,2]) + [4 5] + [7 0] + + Note that row and column indices can be reordered or repeated:: + + sage: A.matrix_from_rows_and_columns([2,1], [2,1]) + [0 7] + [5 4] + + For example here we take from row 1 columns 2 then 0 twice, and do + this 3 times:: + + sage: A.matrix_from_rows_and_columns([1,1,1],[2,0,0]) + [5 3 3] + [5 3 3] + [5 3 3] + + AUTHORS: + + - Jaap Spies (2006-02-18) + + - Didier Deshommes: some Pyrex speedups implemented + """ + cdef Py_ssize_t ncols = len(columns) + cdef Py_ssize_t nrows = len(rows) + + # Check whether column indices are valid + cdef Py_ssize_t i, j, row, col + for col in columns: + if col < 0 or col >= self._ncols: + raise IndexError("column index out of range") + + # Construct new matrix + cdef Matrix_modn_dense_template A = self.new_matrix(nrows=nrows, ncols=ncols) + for i, row in enumerate(rows): + if row < 0 or row >= self._nrows: + raise IndexError("row index out of range") + for j, col in enumerate(columns): + A._matrix[i][j] = self._matrix[row][col] + + return A + def __bool__(self): """ Test whether this matrix is zero. @@ -3076,14 +3216,13 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: bool(A) False + sage: # needs sage.rings.finite_rings sage: A = matrix(GF(16007), 0, 0) sage: A.is_zero() True - sage: A = matrix(GF(16007), 1, 0) sage: A.is_zero() True - sage: A = matrix(GF(16007), 0, 1) sage: A.is_zero() True @@ -3104,8 +3243,8 @@ cdef class Matrix_modn_dense_template(Matrix_dense): EXAMPLES:: - sage: M = Matrix(GF(49), 2, [1,2,-2,0]) - sage: M.zero_pattern_matrix() # indirect doctest + sage: M = Matrix(GF(49), 2, [1,2,-2,0]) # needs sage.rings.finite_rings + sage: M.zero_pattern_matrix() # indirect doctest # needs sage.rings.finite_rings [0 0] [0 1] diff --git a/src/sage/matrix/matrix_modn_sparse.pxd b/src/sage/matrix/matrix_modn_sparse.pxd index 5c471a7082f..dded069b3d8 100644 --- a/src/sage/matrix/matrix_modn_sparse.pxd +++ b/src/sage/matrix/matrix_modn_sparse.pxd @@ -1,4 +1,4 @@ -from .matrix_sparse cimport Matrix_sparse +from sage.matrix.matrix_sparse cimport Matrix_sparse from sage.modules.vector_modn_sparse cimport * cdef class Matrix_modn_sparse(Matrix_sparse): diff --git a/src/sage/matrix/matrix_modn_sparse.pyx b/src/sage/matrix/matrix_modn_sparse.pyx index 1bf2255b8f3..80a74bf1761 100644 --- a/src/sage/matrix/matrix_modn_sparse.pyx +++ b/src/sage/matrix/matrix_modn_sparse.pyx @@ -83,54 +83,45 @@ TESTS:: from libc.stdint cimport uint64_t from libc.limits cimport UINT_MAX -from cysignals.memory cimport check_calloc, sig_malloc, sig_free +from cysignals.memory cimport check_calloc, sig_free from cysignals.signals cimport sig_on, sig_off -from sage.ext.stdsage cimport PY_NEW +cimport sage.libs.linbox.givaro as givaro +cimport sage.libs.linbox.linbox as linbox +from sage.arith.misc import is_prime +from sage.data_structures.binary_search cimport * +from sage.ext.stdsage cimport PY_NEW from sage.libs.flint.fmpz cimport fmpz_get_mpz, fmpz_set_mpz from sage.libs.flint.fmpz_mat cimport fmpz_mat_entry - -from sage.structure.element import is_Vector +from sage.libs.gmp.mpz cimport mpz_set +from sage.libs.linbox.conversion cimport (get_method, + METHOD_DEFAULT, + METHOD_DENSE_ELIMINATION, + METHOD_SPARSE_ELIMINATION, + METHOD_BLACKBOX, + METHOD_WIEDEMANN, + new_linbox_matrix_modn_sparse, + new_linbox_matrix_integer_sparse, + new_linbox_vector_integer_dense, + new_sage_vector_integer_dense) +from sage.matrix.args cimport SparseEntry, MatrixArgs_init +from sage.matrix.matrix2 import Matrix as Matrix2 +from sage.matrix.matrix_dense cimport Matrix_dense +from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense +from sage.misc.verbose import verbose, get_verbose +from sage.modules.vector_integer_dense cimport Vector_integer_dense +from sage.modules.vector_integer_sparse cimport * from sage.modules.vector_modn_sparse cimport * - -cimport sage.libs.linbox.givaro as givaro -cimport sage.libs.linbox.linbox as linbox - -from sage.libs.linbox.conversion cimport * - -from .matrix2 cimport Matrix -from sage.libs.gmp.mpz cimport mpz_init_set_si -cimport sage.matrix.matrix as matrix -cimport sage.matrix.matrix_sparse as matrix_sparse -cimport sage.matrix.matrix_dense as matrix_dense +from sage.rings.fast_arith cimport arith_int from sage.rings.finite_rings.integer_mod cimport IntegerMod_int, IntegerMod_abstract from sage.rings.integer cimport Integer -from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ - -from sage.misc.verbose import verbose, get_verbose - -from sage.matrix.matrix2 import Matrix as Matrix2 -from .args cimport SparseEntry, MatrixArgs_init -from sage.arith.all import is_prime - -from sage.structure.element import is_Vector - -cimport sage.structure.element - -from sage.data_structures.binary_search cimport * -from sage.modules.vector_integer_sparse cimport * - -from .matrix_integer_sparse cimport Matrix_integer_sparse -from .matrix_integer_dense cimport Matrix_integer_dense -from sage.modules.vector_integer_dense cimport Vector_integer_dense - -from sage.misc.decorators import rename_keyword +from sage.rings.rational_field import QQ +from sage.structure.element cimport Matrix ################ # TODO: change this to use extern cdef's methods. -from sage.rings.fast_arith cimport arith_int cdef arith_int ai ai = arith_int() ################ @@ -140,7 +131,7 @@ ai = arith_int() # Github Issue #12679. MAX_MODULUS = 46341 -cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): +cdef class Matrix_modn_sparse(Matrix_sparse): def __cinit__(self): nr = self._nrows nc = self._ncols @@ -234,7 +225,7 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): if d is not None: return d - cdef Py_ssize_t i, j, k + cdef Py_ssize_t i, j d = {} cdef IntegerMod_int n for i from 0 <= i < self._nrows: @@ -264,7 +255,7 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): else: raise ValueError("unknown matrix format") - cdef sage.structure.element.Matrix _matrix_times_matrix_(self, sage.structure.element.Matrix _right): + cdef Matrix _matrix_times_matrix_(self, Matrix _right): """ This code is implicitly called for multiplying self by another sparse matrix. @@ -319,10 +310,6 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): v = &(right.rows[i]) for j in range(v.num_nonzero): (<set> nonzero_positions_in_columns[v.positions[j]]).add(i) - # pre-computes the list of nonzero columns of right - cdef list right_indices - right_indices = [j for j in range(right._ncols) - if nonzero_positions_in_columns[j]] ans = self.new_matrix(self._nrows, right._ncols) @@ -343,7 +330,7 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): set_entry(&ans.rows[i], j, s) return ans - def _matrix_times_matrix_dense(self, sage.structure.element.Matrix _right): + def _matrix_times_matrix_dense(self, Matrix _right): """ Multiply self by the sparse matrix _right, and return the result as a dense matrix. @@ -368,7 +355,7 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): <class 'sage.matrix.matrix_mod2_dense.Matrix_mod2_dense'> """ cdef Matrix_modn_sparse right - cdef matrix_dense.Matrix_dense ans + cdef Matrix_dense ans right = _right cdef c_vector_modint* v @@ -432,7 +419,7 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): self.check_mutability() cdef Py_ssize_t i, r, c, min, min_row, start_row - cdef int a0, a_inverse, b, do_verb + cdef int a_inverse, b, do_verb cdef c_vector_modint tmp start_row = 0 pivots = [] @@ -878,7 +865,7 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): self.cache('det', d) return d elif algorithm == 'generic': - d = matrix_sparse.Matrix_sparse.determinant(self) + d = Matrix_sparse.determinant(self) self.cache('det', d) return d else: @@ -956,7 +943,7 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): if algorithm == "generic": return Matrix_sparse.solve_right(self, B) else: - if isinstance(B, sage.structure.element.Matrix): + if isinstance(B, Matrix): from sage.matrix.special import diagonal_matrix m, d = self._solve_matrix_linbox(B, algorithm) return m * diagonal_matrix([QQ((1,x)) for x in d]) @@ -1128,7 +1115,7 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): from sage.modules.free_module_element import vector cdef Matrix_integer_dense B - if not isinstance(mat, Matrix): + if not isinstance(mat, Matrix2): B = <Matrix_integer_dense?> matrix(ZZ, mat, sparse=False) else: B = <Matrix_integer_dense?> mat.change_ring(ZZ).dense_matrix() diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index 1fd54027d2d..e3de9bbdb57 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -15,20 +15,17 @@ AUTHOR: # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** - - -from sage.rings.polynomial.multi_polynomial_libsingular cimport new_MP - from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix -from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular -from sage.libs.singular.function import singular_function +from sage.libs.singular.function import singular_function, lib + +from cysignals.signals cimport sig_on, sig_off cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): @@ -106,7 +103,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): x = self.fetch('echelon_form_'+algorithm) if x is not None: return x - if algorithm == "frac": + if algorithm == "frac": E = self.matrix_over_field() E.echelonize(**kwds) else: @@ -270,13 +267,13 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): m = len(E) n = len(E[0]) - for r in xrange(m): + for r in range(m): for c in range(n): self.set_unsafe(r, c, E[r][c]) - for c in xrange(n, self.ncols()): + for c in range(n, self.ncols()): self.set_unsafe(r, c, R._zero_element) - for r in xrange(m, self.nrows()): - for c in xrange(self.ncols()): + for r in range(m, self.nrows()): + for c in range(self.ncols()): self.set_unsafe(r, c, R._zero_element) from sage.rings.integer_ring import ZZ @@ -456,6 +453,68 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): """ return self.fetch('swapped_columns') + def _fitting_ideal(self, i): + r""" + Return the `i`-th Fitting ideal of the matrix. This is the ideal generated + by the `n - i` minors, where `n` is the number of columns. + + INPUT: + + ``i`` -- an integer + + OUTPUT: + + An ideal on the base ring. + + EXAMPLES:: + + sage: R.<x,y,z> = QQ[] + sage: M = matrix(R, [[2*x-z, 0, y-z^2, 0], [0, z - y, z - x, 0],[z - y, x^2 - y, 0, z]]) + sage: M + [ 2*x - z 0 -z^2 + y 0] + [ 0 -y + z -x + z 0] + [ -y + z x^2 - y 0 z] + sage: M.fitting_ideal(0) + Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: M.fitting_ideal(1) + Ideal (2*x^4 - 3*x^3*z + x^2*z^2 + y^2*z^2 - 2*y*z^3 + z^4 - 2*x^2*y - y^3 + 3*x*y*z + 2*y^2*z - 2*y*z^2, y*z^3 - z^4 - y^2*z + y*z^2, -2*x*y*z + 2*x*z^2 + y*z^2 - z^3, -2*x^2*z + 3*x*z^2 - z^3) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: M.fitting_ideal(2) + Ideal (-x^3 + x^2*z + x*y - y*z, -y^2 + 2*y*z - z^2, -x^2*z^2 + x^2*y + y*z^2 - y^2, 2*x^3 - x^2*z - 2*x*y + y*z, -x*y + x*z + y*z - z^2, -y*z^2 + z^3 + y^2 - y*z, -2*x*y + 2*x*z + y*z - z^2, y*z^2 - z^3 - y^2 + y*z, 2*x^2 - 3*x*z + z^2, 2*x*z - z^2, -z^3 + y*z, -y*z + z^2, -x*z + z^2) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: M.fitting_ideal(3) + Ideal (2*x - z, -z^2 + y, -y + z, -x + z, -y + z, x^2 - y, z) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: M.fitting_ideal(4) + Ideal (1) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: [R.ideal(M.minors(i)) == M._fitting_ideal(4 - i) for i in range(5)] + [True, True, True, True, True] + + """ + minor = singular_function("minor") + R = self.base_ring() + for (nrow, row) in enumerate(self.rows()): + if not row: + N = self.delete_rows([nrow]) + return N._fitting_ideal(i) + for (ncoef, coef) in enumerate(row): + if all(coef.divides(f) for f in row): + N = self.__copy__() + for j in range(self.ncols()): + if j != ncoef: + N.add_multiple_of_column(j, ncoef, -R(self[nrow,j] / coef)) + return N.fitting_ideal(i) + for (ncolumn, column) in enumerate(self.columns()): + if not column: + N = self.delete_columns([ncolumn]) + return N._fitting_ideal(i-1) + for (ncoef, coef) in enumerate(column): + if all(coef.divides(f) for f in column): + N = self.__copy__() + for j in range(self.nrows()): + if j != ncoef: + N.add_multiple_of_row(j, ncoef, -R(self[j, ncolumn] / coef)) + return N.fitting_ideal(i) + rank = self.ncols() - i + return R.ideal(minor(self, rank)) + def determinant(self, algorithm=None): """ Return the determinant of this matrix diff --git a/src/sage/matrix/matrix_numpy_dense.pyx b/src/sage/matrix/matrix_numpy_dense.pyx index 6a3dafbb07a..31ffaa0a51c 100644 --- a/src/sage/matrix/matrix_numpy_dense.pyx +++ b/src/sage/matrix/matrix_numpy_dense.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - numpy """ Dense matrices using a NumPy backend @@ -39,7 +40,6 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from .matrix cimport Matrix from .args cimport MatrixArgs_init cimport sage.structure.element @@ -383,8 +383,9 @@ cdef class Matrix_numpy_dense(Matrix_dense): sage: m = matrix(RDF,[[1,2],[3,4]]) sage: n = m.numpy() sage: import numpy - sage: numpy.linalg.eig(n) - (array([-0.37228132, 5.37228132]), array([[-0.82456484, -0.41597356], + sage: tuple(numpy.linalg.eig(n)) + (array([-0.37228132, 5.37228132]), + array([[-0.82456484, -0.41597356], [ 0.56576746, -0.90937671]])) sage: m = matrix(RDF, 2, range(6)); m [0.0 1.0 2.0] diff --git a/src/sage/matrix/matrix_numpy_integer_dense.pyx b/src/sage/matrix/matrix_numpy_integer_dense.pyx index bc605df9b92..8c449a86abf 100644 --- a/src/sage/matrix/matrix_numpy_integer_dense.pyx +++ b/src/sage/matrix/matrix_numpy_integer_dense.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - numpy r""" Dense integer matrices using a NumPy backend diff --git a/src/sage/matrix/matrix_polynomial_dense.pyx b/src/sage/matrix/matrix_polynomial_dense.pyx index 92502d9632b..10d9a9248b6 100644 --- a/src/sage/matrix/matrix_polynomial_dense.pyx +++ b/src/sage/matrix/matrix_polynomial_dense.pyx @@ -39,7 +39,6 @@ AUTHORS: from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix -from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ @@ -115,7 +114,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix( pR, [[3*x+1, 0, 1], [x^3+3, 0, 0]]) + sage: M = Matrix(pR, [[3*x+1, 0, 1], [x^3+3, 0, 0]]) sage: M._check_shift_dimension(shifts=[1,3,2]) sage: M._check_shift_dimension(shifts=[1,3,2], row_wise=False) @@ -141,19 +140,19 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix( pR, [[3*x+1, 0, 1], [x^3+3, 0, 0]]) + sage: M = Matrix(pR, [[3*x+1, 0, 1], [x^3+3, 0, 0]]) sage: M.degree() 3 The zero matrix has degree ``-1``:: - sage: M = Matrix( pR, 2, 3 ) + sage: M = Matrix(pR, 2, 3) sage: M.degree() -1 For an empty matrix, the degree is not defined:: - sage: M = Matrix( pR, 3, 0 ) + sage: M = Matrix(pR, 3, 0) sage: M.degree() Traceback (most recent call last): ... @@ -195,7 +194,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix( pR, [[3*x+1, 0, 1], [x^3+3, 0, 0]]) + sage: M = Matrix(pR, [[3*x+1, 0, 1], [x^3+3, 0, 0]]) sage: M.degree_matrix() [ 1 -1 0] [ 3 -1 -1] @@ -224,7 +223,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): return self.apply_map(lambda x: x.degree()) from sage.matrix.constructor import matrix zero_degree = min(shifts) - 1 - if row_wise: + if row_wise: return matrix( ZZ, [[ self[i,j].degree() + shifts[j] if self[i,j] != 0 else zero_degree for j in range(self.ncols()) ] for i in range(self.nrows())] ) @@ -268,7 +267,6 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix([ ....: [ x^3+5*x^2+5*x+1, 5, 6*x+4, 0], ....: [ 6*x^2+3*x+1, 1, 2, 0], @@ -276,9 +274,9 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): ....: ]) sage: M.is_constant() False - sage: M = Matrix(pR,[[1,5,2],[3,1,5]]); M.is_constant() + sage: M = Matrix(pR, [[1,5,2], [3,1,5]]); M.is_constant() True - sage: M = Matrix.zero(pR,3,5); M.is_constant() + sage: M = Matrix.zero(pR, 3, 5); M.is_constant() True .. SEEALSO:: @@ -652,7 +650,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): [ 4*x + 6 x + 5 5*x + 5 6*x + 5] - sage: M.reverse(M.column_degrees(),row_wise=False) + sage: M.reverse(M.column_degrees(), row_wise=False) [ x^3 + 5*x^2 + 5*x + 1 5*x 4*x^2 + 6*x 0] [ x^3 + 3*x^2 + 6*x x @@ -744,10 +742,10 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: A = Matrix(pR, 3, 3, \ - [[4*x+5, 5*x^2 + x + 1, 4*x^2 + 4], \ - [6*x^2 + 6*x + 6, 4*x^2 + 5*x, 4*x^2 + x + 3], \ - [3*x^2 + 2, 4*x + 1, x^2 + 3*x]]) + sage: A = Matrix(pR, 3, 3, + ....: [[4*x+5, 5*x^2 + x + 1, 4*x^2 + 4], + ....: [6*x^2 + 6*x + 6, 4*x^2 + 5*x, 4*x^2 + x + 3], + ....: [3*x^2 + 2, 4*x + 1, x^2 + 3*x]]) sage: B = A.inverse_series_trunc(4); B [ x^3 + 5*x^2 + x + 4 x^3 + 5*x^2 + 6*x + 4 6*x^2 + 5*x + 3] [ 4*x^2 + 5*x + 6 6*x^3 + x^2 + x + 6 3*x^3 + 2*x^2 + 2] @@ -840,51 +838,52 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: + sage: pR.<x> = GF(7)[] - sage: A = Matrix(pR, 3, 3, \ - [[4*x+5, 5*x^2 + x + 1, 4*x^2 + 4], \ - [6*x^2 + 6*x + 6, 4*x^2 + 5*x, 4*x^2 + x + 3], \ - [3*x^2 + 2, 4*x + 1, x^2 + 3*x]]) + sage: A = Matrix(pR, 3, 3, + ....: [[4*x+5, 5*x^2 + x + 1, 4*x^2 + 4], + ....: [6*x^2 + 6*x + 6, 4*x^2 + 5*x, 4*x^2 + x + 3], + ....: [3*x^2 + 2, 4*x + 1, x^2 + 3*x]]) sage: A.is_square() and A.constant_matrix().is_invertible() True sage: B = vector([2*x^2 + 6*x + 6, 0, x + 6]) - sage: X = A.solve_left_series_trunc(B,4); X + sage: X = A.solve_left_series_trunc(B, 4); X (3*x^3 + 3*x^2 + 2*x + 4, 4*x^3 + x^2 + 2*x + 6, 6*x^3 + x + 3) sage: B == X*A % x**4 True - sage: B = Matrix(pR, 2, 3, \ - [[3*x, x^2 + x + 2, x^2 + 2*x + 3], \ - [ 0, 6*x^2 + 1, 1]]) - sage: A.solve_left_series_trunc(B,3) + sage: B = Matrix(pR, 2, 3, + ....: [[3*x, x^2 + x + 2, x^2 + 2*x + 3], + ....: [ 0, 6*x^2 + 1, 1]]) + sage: A.solve_left_series_trunc(B, 3) [6*x^2 + 2*x + 2 4*x + 3 2*x^2 + 3*x] [3*x^2 + 4*x + 5 4*x^2 + 3 x^2 + 6*x + 3] - sage: X = A.solve_left_series_trunc(B,37); B == X*A % x**37 + sage: X = A.solve_left_series_trunc(B, 37); B == X*A % x**37 True Dimensions of input are checked:: - sage: A.solve_left_series_trunc(B[:,:2],3) + sage: A.solve_left_series_trunc(B[:,:2], 3) Traceback (most recent call last): ... ValueError: number of columns of self must equal number of columns of right-hand side Raises an exception when no solution:: - sage: A[2:,:].solve_left_series_trunc(B,4) + sage: A[2:,:].solve_left_series_trunc(B, 4) Traceback (most recent call last): ... ValueError: matrix equation has no solutions sage: Ax = x*A; C = vector(pR, [1,1,1]) - sage: Ax.solve_left_series_trunc(C,5) + sage: Ax.solve_left_series_trunc(C, 5) Traceback (most recent call last): ... ValueError: matrix equation has no solutions Supports rectangular and rank-deficient cases:: - sage: A[:,:2].solve_left_series_trunc(B[:,:2],4) + sage: A[:,:2].solve_left_series_trunc(B[:,:2], 4) [5*x^2 + 2*x + 5 5*x + 5 2*x + 4] [5*x^3 + 2*x + 1 2*x^2 + 2*x + 5 4*x^2] @@ -988,45 +987,45 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: A = Matrix(pR, 3, 3, \ - [[4*x+5, 5*x^2 + x + 1, 4*x^2 + 4], \ - [6*x^2 + 6*x + 6, 4*x^2 + 5*x, 4*x^2 + x + 3], \ - [3*x^2 + 2, 4*x + 1, x^2 + 3*x]]) + sage: A = Matrix(pR, 3, 3, + ....: [[4*x+5, 5*x^2 + x + 1, 4*x^2 + 4], + ....: [6*x^2 + 6*x + 6, 4*x^2 + 5*x, 4*x^2 + x + 3], + ....: [3*x^2 + 2, 4*x + 1, x^2 + 3*x]]) sage: A.is_square() and A.constant_matrix().is_invertible() True sage: B = vector([2*x^2 + 6*x + 6, 0, x + 6]) - sage: X = A.solve_right_series_trunc(B,4); X + sage: X = A.solve_right_series_trunc(B, 4); X (2*x^3 + x^2, 5*x^3 + x^2 + 5*x + 6, 4*x^3 + 6*x^2 + 4*x) sage: B == A*X % x**4 True - sage: B = Matrix(pR, 3, 2, \ - [[5*x^2 + 6*x + 3, 4*x^2 + 6*x + 4], \ - [ x^2 + 4*x + 2, 5*x + 2], \ - [ 5*x + 3, 0]]) - sage: A.solve_right_series_trunc(B,3) + sage: B = Matrix(pR, 3, 2, + ....: [[5*x^2 + 6*x + 3, 4*x^2 + 6*x + 4], + ....: [ x^2 + 4*x + 2, 5*x + 2], + ....: [ 5*x + 3, 0]]) + sage: A.solve_right_series_trunc(B, 3) [ 3*x^2 + x + 1 5*x^2 + 4*x + 3] [6*x^2 + 3*x + 1 4*x + 1] [ 6*x^2 + 1 2*x^2 + x + 4] - sage: X = A.solve_right_series_trunc(B,37); B == A*X % x**37 + sage: X = A.solve_right_series_trunc(B, 37); B == A*X % x**37 True Dimensions of input are checked:: - sage: A.solve_right_series_trunc(B[:2,:],3) + sage: A.solve_right_series_trunc(B[:2,:], 3) Traceback (most recent call last): ... ValueError: number of rows of self must equal number of rows of right-hand side Raises an exception when no solution:: - sage: A[:,2:].solve_right_series_trunc(B,4) + sage: A[:,2:].solve_right_series_trunc(B, 4) Traceback (most recent call last): ... ValueError: matrix equation has no solutions sage: Ax = x*A; C = vector(pR, [1,1,1]) - sage: Ax.solve_right_series_trunc(C,5) + sage: Ax.solve_right_series_trunc(C, 5) Traceback (most recent call last): ... ValueError: matrix equation has no solutions @@ -1097,7 +1096,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix(pR, [ [3*x+1, 0, 1], [x^3+3, 0, 0] ]) + sage: M = Matrix(pR, [[3*x+1, 0, 1], [x^3+3, 0, 0]]) sage: M.row_degrees() [1, 3] @@ -1116,14 +1115,14 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): The row degrees of an empty matrix (`0\times n` or `m\times 0`) is not defined:: - - sage: M = Matrix( pR, 0, 3 ) + + sage: M = Matrix(pR, 0, 3) sage: M.row_degrees() Traceback (most recent call last): ... ValueError: empty matrix does not have row degrees - sage: M = Matrix( pR, 3, 0 ) + sage: M = Matrix(pR, 3, 0) sage: M.row_degrees() Traceback (most recent call last): ... @@ -1164,7 +1163,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix(pR, [ [3*x+1, 0, 1], [x^3+3, 0, 0] ]) + sage: M = Matrix(pR, [[3*x+1, 0, 1], [x^3+3, 0, 0]]) sage: M.column_degrees() [3, -1, 0] @@ -1180,13 +1179,13 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): The column degrees of an empty matrix (`0\times n` or `m\times 0`) is not defined:: - sage: M = Matrix( pR, 0, 3 ) + sage: M = Matrix(pR, 0, 3) sage: M.column_degrees() Traceback (most recent call last): ... ValueError: empty matrix does not have column degrees - sage: M = Matrix( pR, 3, 0 ) + sage: M = Matrix(pR, 3, 0) sage: M.column_degrees() Traceback (most recent call last): ... @@ -1215,7 +1214,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): n}`. Working row-wise and without shifts, its leading matrix is the matrix in `\Bold{K}^{m \times n}` formed by the leading coefficients of the entries of `M` which reach the degree of the corresponding row. - + More precisely, if working row-wise, let `s_1,\ldots,s_n \in \ZZ` be a shift, and let `(d_1,\ldots,d_m)` denote the shifted row degrees of `M`. Then, the shifted leading matrix of `M` is the matrix in @@ -1239,13 +1238,13 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): OUTPUT: a matrix over the base field. REFERENCES: - + [Wol1974]_ (Section 2.5, without shifts) and [VBB1992]_ (Section 3). EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix(pR, [ [3*x+1, 0, 1], [x^3+3, 0, 0] ]) + sage: M = Matrix(pR, [[3*x+1, 0, 1], [x^3+3, 0, 0]]) sage: M.leading_matrix() [3 0 0] [1 0 0] @@ -1335,7 +1334,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): False .. SEEALSO:: - + :meth:`is_popov` . """ if include_zero_vectors: @@ -1385,13 +1384,13 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): OUTPUT: a boolean value. REFERENCES: - + [Wol1974]_ (Section 2.5, without shifts) and [VBB1992]_ (Section 3). EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix(pR, [ [3*x+1, 0, 1], [x^3+3, 0, 0] ]) + sage: M = Matrix(pR, [[3*x+1, 0, 1], [x^3+3, 0, 0]]) sage: M.is_reduced() False @@ -1402,10 +1401,10 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): True sage: M.is_reduced(shifts=[2,0], row_wise=False, - ....: include_zero_vectors=False) + ....: include_zero_vectors=False) False - sage: M = Matrix(pR, [ [3*x+1, 0, 1], [x^3+3, 0, 0], [0, 1, 0] ]) + sage: M = Matrix(pR, [[3*x+1, 0, 1], [x^3+3, 0, 0], [0, 1, 0]]) sage: M.is_reduced(shifts=[2,0,0], row_wise=False) True @@ -1441,7 +1440,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): this vector is the index `j` of the rightmost nonzero entry `p_j` such that `\deg(p_j) + s_j` is equal to the shifted row degree of the vector. Then the pivot degree of the vector is the degree `\deg(p_j)`. - + For the zero row, both the leading positions and degree are `-1`. For a `m \times n` polynomial matrix, the leading positions and pivot degrees are the two lists containing the leading positions and the @@ -1465,13 +1464,13 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): of integers otherwise. REFERENCES: - + [Kai1980]_ (Section 6.7.2, without shifts). EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix(pR, [ [3*x+1, 0, 1], [x^3+3, 0, 0] ]) + sage: M = Matrix(pR, [[3*x+1, 0, 1], [x^3+3, 0, 0]]) sage: M.leading_positions() [0, 0] @@ -1485,23 +1484,24 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): ([1, -1, 0], [3, -1, 0]) sage: M.leading_positions(shifts=[1,2], row_wise=False, - ....: return_degree=True) + ....: return_degree=True) ([1, -1, 0], [3, -1, 0]) In case several entries in the row (resp. column) reach the shifted row (resp. column) degree, the leading position is chosen as the rightmost (resp. bottommost) such entry:: - sage: M.leading_positions(shifts=[0,5,1],return_degree=True) + sage: M.leading_positions(shifts=[0,5,1], return_degree=True) ([2, 0], [0, 3]) - sage: M.leading_positions(shifts=[2,0], row_wise=False,return_degree=True) + sage: M.leading_positions(shifts=[2,0], row_wise=False, + ....: return_degree=True) ([1, -1, 0], [3, -1, 0]) The leading positions and pivot degrees of an empty matrix (`0\times n` or `m\times 0`) is not defined:: - sage: M = Matrix( pR, 0, 3 ) + sage: M = Matrix(pR, 0, 3) sage: M.leading_positions() Traceback (most recent call last): ... @@ -1512,7 +1512,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): ... ValueError: empty matrix does not have leading positions - sage: M = Matrix( pR, 3, 0 ) + sage: M = Matrix(pR, 3, 0) sage: M.leading_positions(row_wise=False) Traceback (most recent call last): ... @@ -1541,7 +1541,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): self[i,pivot_index[i]].degree()) for i in range(self.nrows()) ] return (pivot_index,pivot_degree) if return_degree else pivot_index - + # now in the column-wise case column_degrees = self.column_degrees(shifts) if shifts is None: @@ -1595,7 +1595,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): OUTPUT: a boolean. REFERENCES: - + [Kai1980]_ (Section 6.7.2, square case without shifts), [MS2003]_ (without shifts), [BLV1999]_ . @@ -1614,7 +1614,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: M.is_weak_popov(ordered=True) True - sage: N = M.with_swapped_rows(1,2) + sage: N = M.with_swapped_rows(1, 2) sage: N.is_weak_popov() True sage: N.is_weak_popov(ordered=True) @@ -1625,7 +1625,8 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: M.is_weak_popov(shifts=[2,3,1]) False - sage: M.is_weak_popov(shifts=[0,2,0],row_wise=False,ordered=True) + sage: M.is_weak_popov(shifts=[0,2,0], row_wise=False, + ....: ordered=True) True Rectangular matrices are supported:: @@ -1638,7 +1639,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: M.is_weak_popov(shifts=[0,2,1,3]) True - sage: M.is_weak_popov(shifts=[0,2,1,3],ordered=True) + sage: M.is_weak_popov(shifts=[0,2,1,3], ordered=True) True Zero rows (resp. columns) can be forbidden:: @@ -1646,13 +1647,14 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: M = Matrix([ ....: [ 6*x+4, 0, 5*x+1, 0], ....: [ 2, 5*x + 1, 6*x^2+3*x+1, 0], - ....: [2*x^2+5*x+5, 1, 2*x^3+4*x^2+6*x+4, 0] + ....: [2*x^2+5*x+5, 1, 2*x^3+4*x^2+6*x+4, 0] ....: ]) - sage: M.is_weak_popov(shifts=[2,1,0], row_wise=False, ordered=True) + sage: M.is_weak_popov(shifts=[2,1,0], row_wise=False, + ....: ordered=True) True sage: M.is_weak_popov(shifts=[2,1,0], row_wise=False, - ....: include_zero_vectors=False) + ....: include_zero_vectors=False) False .. SEEALSO:: @@ -1663,20 +1665,29 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): if self.ncols() == 0 or self.nrows() == 0: return self._is_empty_popov(row_wise) leading_positions = self.leading_positions(shifts, row_wise) - # here, it will be convenient to have leading position - # larger than ncols for zero/empty rows - leading_positions = [pos if pos>=0 else self.ncols() + 1 for pos in leading_positions] + # here, because of the below sorting and of the convention that zero + # rows (resp. columns) are at the bottom (resp. right) of the matrix in + # the row-wise case (resp. column-wise case), it will be convenient to + # have leading position ncols (resp. nrows) for these zero vectors + pos_zero_vec = self.ncols() if row_wise else self.nrows() + leading_positions = [pos if pos >= 0 else pos_zero_vec + 1 + for pos in leading_positions] # leading positions should not have duplicates, which is equivalent to: # once sorted, it doesn't contain a pair of equal successive entries if not ordered: leading_positions.sort() # check that there is no zero vector, if it is forbidden - if leading_positions[-1] > self.ncols() and not include_zero_vectors: + # (in the ordered case, even though we have not sorted, this test of + # the last leading position is sufficient: in any case, if there is a + # zero vector followed by a nonzero one, the testing loop below will + # return False) + if leading_positions[-1] > pos_zero_vec and not include_zero_vectors: return False - # now leading_positions is nondecreasing: it remains to test whether - # it is strictly increasing (at least until the zero rows part) + # it remains to test whether leading_positions is strictly increasing + # until it reaches a zero vector (note this also checks that there is + # no zero vector encountered after a nonzero one) for index,next_leading_position in enumerate(leading_positions[1:]): - if next_leading_position <= self.ncols() and \ + if next_leading_position <= pos_zero_vec and \ next_leading_position <= leading_positions[index]: return False return True @@ -1724,16 +1735,16 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): OUTPUT: a boolean. REFERENCES: - + For the square case, without shifts: [Pop1972]_ and [Kai1980]_ (Section 6.7.2). For the general case: [BLV2006]_ . EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix(pR, [ [x^4+6*x^3+4*x+4, 3*x+6, 3 ], - ....: [x^2+6*x+6, x^2+5*x+5, 2 ], - ....: [3*x, 6*x+5, x+5] ]) + sage: M = Matrix(pR, [[x^4+6*x^3+4*x+4, 3*x+6, 3 ], + ....: [x^2+6*x+6, x^2+5*x+5, 2 ], + ....: [3*x, 6*x+5, x+5]]) sage: M.is_popov() True @@ -1746,9 +1757,9 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: M[:2,:].is_popov(shifts=[0,1,2]) True - sage: M = Matrix(pR, [ [x^4+3*x^3+x^2+2*x+6, x^3+5*x^2+5*x+1], - ....: [6*x+1, x^2+4*x+1 ], - ....: [6, 6 ] ]) + sage: M = Matrix(pR, [[x^4+3*x^3+x^2+2*x+6, x^3+5*x^2+5*x+1], + ....: [6*x+1, x^2+4*x+1 ], + ....: [6, 6 ]]) sage: M.is_popov(row_wise=False) False @@ -1757,9 +1768,9 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): One can forbid zero rows (or columns if not working row-wise):: - sage: N = Matrix(pR, [ [x^4+3*x^3+x^2+2*x+6, 6*x+1 ], - ....: [5*x^2+5*x+1, x^2+4*x+1 ], - ....: [0, 0 ] ]) + sage: N = Matrix(pR, [[x^4+3*x^3+x^2+2*x+6, 6*x+1 ], + ....: [5*x^2+5*x+1, x^2+4*x+1 ], + ....: [0, 0 ]]) sage: N.is_popov() True @@ -1770,15 +1781,15 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): One can verify Popov form up to row permutation (or column permutation if not working row-wise):: - sage: M.swap_columns(0,1) + sage: M.swap_columns(0, 1) sage: M.is_popov(shifts=[0,2,3], row_wise=False) False sage: M.is_popov(shifts=[0,2,3], row_wise=False, - ....: up_to_permutation=True) + ....: up_to_permutation=True) True - sage: N.swap_rows(0,2) + sage: N.swap_rows(0, 2) sage: N.is_popov() False @@ -1869,9 +1880,9 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix(pR, [ [x^4+6*x^3+4*x+4, 3*x+6, 3 ], - ....: [0, x^2+5*x+5, 2 ], - ....: [0, 0, x+5] ]) + sage: M = Matrix(pR, [[x^4+6*x^3+4*x+4, 3*x+6, 3 ], + ....: [0, x^2+5*x+5, 2 ], + ....: [0, 0, x+5]]) sage: M.is_hermite() True @@ -1880,9 +1891,9 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: M.is_hermite(row_wise=False, lower_echelon=True) False - sage: N = Matrix(pR, [ [x+5, 0, 0 ], - ....: [2, x^4+6*x^3+4*x+4, 0 ], - ....: [3, 3*x^3+6, x^2+5*x+5] ]) + sage: N = Matrix(pR, [[x+5, 0, 0 ], + ....: [2, x^4+6*x^3+4*x+4, 0 ], + ....: [3, 3*x^3+6, x^2+5*x+5]]) sage: N.is_hermite() False sage: N.is_hermite(lower_echelon=True) @@ -1908,7 +1919,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): False .. SEEALSO:: - + :meth:`hermite_form` . """ # shift for lower echelon @@ -1984,23 +1995,22 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix(pR, [ \ - [ 6*x+4, 5*x^3+5*x, 6*x^2+2*x+2], \ - [4*x^2+5*x+2, x^4+5*x^2+2*x+4, 4*x^3+6*x^2+6*x+5]]) - - sage: P,U = M.weak_popov_form(transformation=True) + sage: M = Matrix(pR, [ + ....: [ 6*x+4, 5*x^3+5*x, 6*x^2+2*x+2], + ....: [4*x^2+5*x+2, x^4+5*x^2+2*x+4, 4*x^3+6*x^2+6*x+5]]) + sage: P, U = M.weak_popov_form(transformation=True) sage: P [ 4 x^2 6*x^2 + x + 2] [ 2 4*x^2 + 2*x + 4 5] sage: U [2*x^2 + 1 4*x] [ 4*x 1] - sage: P.is_weak_popov() and U.is_invertible() and U*M==P + sage: P.is_weak_popov() and U.is_invertible() and U*M == P True Demonstrating the ``ordered`` option:: - sage: P.leading_positions() + sage: P.leading_positions() # needs sage.combinat [2, 1] sage: PP = M.weak_popov_form(ordered=True); PP [ 2 4*x^2 + 2*x + 4 5] @@ -2013,7 +2023,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: P = M.weak_popov_form(shifts=[0,2,4]); P [ 6*x^2 + 6*x + 4 5*x^4 + 4*x^3 + 5*x^2 + 5*x 2*x + 2] [ 2 4*x^2 + 2*x + 4 5] - sage: P==M.weak_popov_form(shifts=[-10,-8,-6]) + sage: P == M.weak_popov_form(shifts=[-10,-8,-6]) True Column-wise form is the row-wise form of the transpose:: @@ -2027,9 +2037,10 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): [x + 4 6 0] [ 5 1 0] - sage: P,U = M.weak_popov_form(transformation=True, \ - row_wise=False, \ - include_zero_vectors=False) + sage: # needs sage.combinat + sage: P, U = M.weak_popov_form(transformation=True, + ....: row_wise=False, + ....: include_zero_vectors=False) sage: P [x + 4 6] [ 5 1] @@ -2112,17 +2123,18 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: - sage: F.<a> = GF(2^4,'a') + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF(2^4, 'a') sage: PF.<x> = F[] sage: A = matrix(PF,[[1, a*x^17 + 1 ], ....: [0, a*x^11 + a^2*x^7 + 1 ]]) sage: M = A.__copy__() - sage: U = M._weak_popov_form(transformation=True) - sage: U * A == M + sage: U = M._weak_popov_form(transformation=True) # needs sage.combinat + sage: U * A == M # needs sage.combinat True - sage: M.is_weak_popov() + sage: M.is_weak_popov() # needs sage.combinat True - sage: U.is_invertible() + sage: U.is_invertible() # needs sage.combinat True sage: PF.<x> = QQ[] @@ -2268,30 +2280,32 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: M = Matrix(pR, [ \ - [ 6*x+4, 5*x^3+5*x, 6*x^2+2*x+2], \ - [4*x^2+5*x+2, x^4+5*x^2+2*x+4, 4*x^3+6*x^2+6*x+5]]) + sage: M = Matrix(pR, [ + ....: [ 6*x+4, 5*x^3+5*x, 6*x^2+2*x+2], + ....: [4*x^2+5*x+2, x^4+5*x^2+2*x+4, 4*x^3+6*x^2+6*x+5]]) - sage: P,U = M.popov_form(transformation=True) + sage: # needs sage.combinat + sage: P, U = M.popov_form(transformation=True) sage: P [ 4 x^2 + 4*x + 1 3] [ 0 4*x + 1 x^2 + 6*x + 1] sage: U [ x 2] [5*x^2 + x + 6 3*x + 2] - sage: P.is_popov() and U.is_invertible() and U*M==P + sage: P.is_popov() and U.is_invertible() and U*M == P True Demonstrating shifts and specific case of Hermite form:: + sage: # needs sage.combinat sage: P = M.popov_form(shifts=[0,2,4]); P [ 4*x^2 + 3*x + 4 x^4 + 3*x^3 + 5*x^2 + 5*x + 5 0] [ 6 5*x^2 + 6*x + 5 1] sage: P.is_popov(shifts=[0,2,4]) True - sage: P==M.popov_form(shifts=[-6,-4,-2]) + sage: P == M.popov_form(shifts=[-6,-4,-2]) True - sage: dd=sum(M.row_degrees())+1 + sage: dd = sum(M.row_degrees()) + 1 sage: M.popov_form(shifts=[2*dd,dd,0]) == M.hermite_form() True @@ -2306,9 +2320,10 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): [x + 2 6 0] [ 0 1 0] - sage: P,U = M.popov_form(transformation=True, \ - row_wise=False, \ - include_zero_vectors=False) + sage: # needs sage.combinat + sage: P, U = M.popov_form(transformation=True, + ....: row_wise=False, + ....: include_zero_vectors=False) sage: P [x + 2 6] [ 0 1] @@ -2459,9 +2474,9 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(3)[] - sage: A = matrix(pR,3,[x, x^2, x^3, - ....: x^2, x^1, 0, - ....: x^3, x^3, x^3]) + sage: A = matrix(pR, 3, [x, x^2, x^3, + ....: x^2, x^1, 0, + ....: x^3, x^3, x^3]) sage: R = A.reduced_form(); R [ x x^2 x^3] [ x^2 x 0] @@ -2481,7 +2496,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): `R` has a single non-zero entry and that entry is a scalar multiple of the greatest-common-divisor of the entries of the matrix:: - sage: A = matrix([[x*(x-1)*(x+1)],[x*(x-2)*(x+2)],[x]]) + sage: A = matrix([[x*(x-1)*(x+1)], [x*(x-2)*(x+2)], [x]]) sage: R = A.reduced_form() sage: R [x] @@ -2513,12 +2528,13 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): The last example shows the usage of the transformation parameter:: + sage: # needs sage.rings.finite_rings sage: Fq.<a> = GF(2^3) sage: pR.<x> = Fq[] sage: A = matrix(pR, [[x^2+a, x^4+a], - ....: [ x^3, a*x^4]]) - sage: W,U = A.reduced_form(transformation=True) - sage: W,U + ....: [ x^3, a*x^4]]) + sage: W, U = A.reduced_form(transformation=True) + sage: W, U ( [ x^2 + a x^4 + a] [1 0] [x^3 + a*x^2 + a^2 a^2], [a 1] @@ -2564,7 +2580,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): - the Hermite normal form `H` of this matrix `A` . - (optional) transformation matrix `U` such that `UA = H` . - + EXAMPLES:: sage: M.<x> = GF(7)[] @@ -2580,21 +2596,23 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: A = matrix(M, 2, 3, [x, 1, 2*x, 2*x, 2, 4*x]) sage: A.hermite_form(transformation=True, include_zero_rows=False) ([ x 1 2*x], [0 4]) - sage: H, U = A.hermite_form(transformation=True, include_zero_rows=True); H, U + sage: H, U = A.hermite_form(transformation=True, + ....: include_zero_rows=True); H, U ( [ x 1 2*x] [0 4] [ 0 0 0], [5 1] ) sage: U * A == H True - sage: H, U = A.hermite_form(transformation=True, include_zero_rows=False) + sage: H, U = A.hermite_form(transformation=True, + ....: include_zero_rows=False) sage: U * A [ x 1 2*x] sage: U * A == H True .. SEEALSO:: - + :meth:`is_hermite` , :meth:`popov_form` . """ @@ -2628,22 +2646,22 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: A = Matrix(pR, 3, 2, \ - [[ 3*x^3 + 3*x, 2*x^3 + 4], \ - [ 3*x^3 + 6*x + 5, 6*x^3 + 5*x^2 + 1], \ - [ 2*x^3 + 2*x + 6, 3*x^2 + 2*x + 2]]) - sage: B = Matrix(pR, 3, 3, \ - [[ 3, x + 3, 6], \ - [3*x^3 + 3*x + 1, 4*x^2 + 3*x, 6*x^3 + x + 4], \ - [ 4*x^2 + x + 4, 3*x^2 + 4*x, 3*x^2 + 3*x + 2]]) - sage: Q,R = A.left_quo_rem(B); (Q,R) + sage: A = Matrix(pR, 3, 2, + ....: [[ 3*x^3 + 3*x, 2*x^3 + 4], + ....: [ 3*x^3 + 6*x + 5, 6*x^3 + 5*x^2 + 1], + ....: [ 2*x^3 + 2*x + 6, 3*x^2 + 2*x + 2]]) + sage: B = Matrix(pR, 3, 3, + ....: [[ 3, x + 3, 6], + ....: [3*x^3 + 3*x + 1, 4*x^2 + 3*x, 6*x^3 + x + 4], + ....: [ 4*x^2 + x + 4, 3*x^2 + 4*x, 3*x^2 + 3*x + 2]]) + sage: Q, R = A.left_quo_rem(B); Q, R ( [2*x^2 + 4*x + 6 6*x^2 + 4*x + 1] [ 3 1] [ 3*x^2 + 5*x 2*x^2 + x + 5] [ 6 5*x^2 + 2*x + 3] [ 6*x^2 + 3*x 4*x^2 + 6*x + 1], [ 2*x + 3 6*x + 3] ) sage: rdegR = R.row_degrees(); rdegB = B.row_degrees() - sage: A == B*Q+R and all([rdegR[i] < rdegB[i] for i in range(3)]) + sage: A == B*Q+R and all(rdegR[i] < rdegB[i] for i in range(3)) True sage: A[:2,:].left_quo_rem(B) @@ -2656,7 +2674,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): no quotient and remainder (unless the matrix has full row rank, see :meth:`right_quo_rem`):: - sage: Q,R = A[:2,:].left_quo_rem(B[:2,:]); (Q,R) + sage: Q, R = A[:2,:].left_quo_rem(B[:2,:]); Q, R ( [ 3*x + 3 2*x + 1] [ 3*x^2 + 5*x 2*x^2 + x + 5] [ 5 0] @@ -2723,17 +2741,16 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): Case where `B` is a square, column reduced matrix:: sage: pR.<x> = GF(7)[] - sage: A = Matrix(pR, 2, 3, \ - [[3*x^3 + 3*x, 3*x^3 + 6*x + 5, 2*x^3 + 2*x + 6], \ - [2*x^3 + 4, 6*x^3 + 5*x^2 + 1, 3*x^2 + 2*x + 2]]) - - sage: B = Matrix(pR, 3, 3, \ - [[4*x^2 + 3*x + 3, 3*x^2 + 3*x + 1, 4*x^2 + x + 4], \ - [6*x^2 + 2*x + 3, 4*x^2 + 3*x, 3*x^2 + 4*x], \ - [5*x^2 + 3*x + 6, 6*x^2 + x + 4, 3*x^2 + 3*x + 2]]) + sage: A = Matrix(pR, 2, 3, + ....: [[3*x^3 + 3*x, 3*x^3 + 6*x + 5, 2*x^3 + 2*x + 6], + ....: [2*x^3 + 4, 6*x^3 + 5*x^2 + 1, 3*x^2 + 2*x + 2]]) + sage: B = Matrix(pR, 3, 3, + ....: [[4*x^2 + 3*x + 3, 3*x^2 + 3*x + 1, 4*x^2 + x + 4], + ....: [6*x^2 + 2*x + 3, 4*x^2 + 3*x, 3*x^2 + 4*x], + ....: [5*x^2 + 3*x + 6, 6*x^2 + x + 4, 3*x^2 + 3*x + 2]]) sage: B.is_reduced(row_wise=False) True - sage: Q,R = A.right_quo_rem(B); (Q,R) + sage: Q, R = A.right_quo_rem(B); Q, R ( [ 4*x x + 2 6*x + 1] [ x + 2 6*x + 1 5*x + 4] [4*x + 3 x + 6 3*x + 4], [4*x + 2 2*x + 3 4*x + 3] @@ -2746,13 +2763,13 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): ValueError: column dimension of self should be the column dimension of the input matrix - sage: B = Matrix(pR, 3, 3, \ - [[3, 3*x^3 + 3*x + 1, 4*x^2 + x + 4], \ - [x + 3, 4*x^2 + 3*x, 3*x^2 + 4*x], \ - [6, 6*x^3 + x + 4, 3*x^2 + 3*x + 2]]) + sage: B = Matrix(pR, 3, 3, + ....: [[3, 3*x^3 + 3*x + 1, 4*x^2 + x + 4], + ....: [x + 3, 4*x^2 + 3*x, 3*x^2 + 4*x], + ....: [6, 6*x^3 + x + 4, 3*x^2 + 3*x + 2]]) sage: B.is_reduced(row_wise=False) True - sage: Q,R = A.right_quo_rem(B); (Q,R) + sage: Q, R = A.right_quo_rem(B); Q, R ( [2*x^2 + 4*x + 6 3*x^2 + 5*x 6*x^2 + 3*x] [6*x^2 + 4*x + 1 2*x^2 + x + 5 4*x^2 + 6*x + 1], @@ -2767,13 +2784,13 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): With a nonsingular but also non-reduced matrix, there exists a solution, but it might not be unique:: - sage: B = Matrix(pR, 3, 3, \ - [[ 5, 0, 2*x + 6], \ - [ 4*x, 3*x^2 + 4*x + 5, x + 1], \ - [3*x^2 + 5*x + 2, 6*x^3 + 4*x + 6, 3]]) + sage: B = Matrix(pR, 3, 3, + ....: [[ 5, 0, 2*x + 6], + ....: [ 4*x, 3*x^2 + 4*x + 5, x + 1], + ....: [3*x^2 + 5*x + 2, 6*x^3 + 4*x + 6, 3]]) sage: B.det() != 0 and (not B.is_reduced(row_wise=False)) True - sage: Q,R = A.right_quo_rem(B); (Q,R) + sage: Q, R = A.right_quo_rem(B); Q, R ( [ 6*x^2 + 3*x 4*x^2 + 3*x + 1 5*x + 1] [ x^2 + 5*x + 5 5*x^2 + 3*x + 5 x + 2], @@ -2782,15 +2799,15 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): [ 6*x + 3 5*x^2 + 6 3] ) sage: cdegR = R.column_degrees(); cdegB = B.column_degrees() - sage: A == Q*B+R and all([cdegR[i] < cdegB[i] for i in range(3)]) + sage: A == Q*B+R and all(cdegR[i] < cdegB[i] for i in range(3)) True - sage: Q2 = Matrix(pR, 2, 3, \ - [[6*x^2 + 3*x + 1, 4*x^2 + 3*x + 6, 5*x + 1], \ - [ x^2 + 5*x + 3, 5*x^2 + 3*x + 2, x + 2]]) - sage: R2 = Matrix(pR, 2, 3, \ - [[ 5*x, 3*x + 4, 5], \ - [4*x + 6, 5*x, 4]]) + sage: Q2 = Matrix(pR, 2, 3, + ....: [[6*x^2 + 3*x + 1, 4*x^2 + 3*x + 6, 5*x + 1], + ....: [ x^2 + 5*x + 3, 5*x^2 + 3*x + 2, x + 2]]) + sage: R2 = Matrix(pR, 2, 3, + ....: [[ 5*x, 3*x + 4, 5], + ....: [4*x + 6, 5*x, 4]]) sage: A == Q2*B + R2 True @@ -2799,8 +2816,8 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): other cases (rank-deficient matrix `B` or matrix `B` having strictly fewer rows than columns) there may be no solution:: - sage: C = B.stack(B[1,:] + B[2,:]) # matrix 4 x 3, full column rank - sage: Q,R = A.right_quo_rem(C); (Q,R) + sage: C = B.stack(B[1,:] + B[2,:]) # 4 x 3, full column rank + sage: Q, R = A.right_quo_rem(C); Q, R ( [ 6*x^2 + 3*x 4*x^2 + 3*x + 1 5*x + 1 0] [ x^2 + 5*x + 5 5*x^2 + 3*x + 5 x + 2 0], @@ -2814,7 +2831,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): ... ValueError: division of these matrices does not admit a remainder with the required degree property - sage: D = copy(B); D[2,:] = B[0,:]+B[1,:] # square, singular + sage: D = copy(B); D[2,:] = B[0,:]+B[1,:] # square, singular sage: A.right_quo_rem(D) Traceback (most recent call last): ... @@ -2879,17 +2896,16 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: A = Matrix(pR, 2, 3, \ - [[3*x^3 + 3*x, 3*x^3 + 6*x + 5, 2*x^3 + 2*x + 6], \ - [2*x^3 + 4, 6*x^3 + 5*x^2 + 1, 3*x^2 + 2*x + 2]]) - - sage: B = Matrix(pR, 3, 3, \ - [[4*x^2 + 3*x + 3, 3*x^2 + 3*x + 1, 4*x^2 + x + 4], \ - [6*x^2 + 2*x + 3, 4*x^2 + 3*x, 3*x^2 + 4*x], \ - [5*x^2 + 3*x + 6, 6*x^2 + x + 4, 3*x^2 + 3*x + 2]]) + sage: A = Matrix(pR, 2, 3, + ....: [[3*x^3 + 3*x, 3*x^3 + 6*x + 5, 2*x^3 + 2*x + 6], + ....: [2*x^3 + 4, 6*x^3 + 5*x^2 + 1, 3*x^2 + 2*x + 2]]) + sage: B = Matrix(pR, 3, 3, + ....: [[4*x^2 + 3*x + 3, 3*x^2 + 3*x + 1, 4*x^2 + x + 4], + ....: [6*x^2 + 2*x + 3, 4*x^2 + 3*x, 3*x^2 + 4*x], + ....: [5*x^2 + 3*x + 6, 6*x^2 + x + 4, 3*x^2 + 3*x + 2]]) sage: B.is_reduced(row_wise=False) True - sage: Q,R = A._right_quo_rem_reduced(B); (Q,R) + sage: Q, R = A._right_quo_rem_reduced(B); Q, R ( [ 4*x x + 2 6*x + 1] [ x + 2 6*x + 1 5*x + 4] [4*x + 3 x + 6 3*x + 4], [4*x + 2 2*x + 3 4*x + 3] @@ -2897,13 +2913,13 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: A == Q*B+R and R.degree() < 2 True - sage: B = Matrix(pR, 3, 3, \ - [[4*x + 3*x + 3, 3*x^3 + 3*x + 1, 4*x^2 + x + 4], \ - [6*x + 2*x + 3, 4*x^2 + 3*x, 3*x^2 + 4*x], \ - [6, 6*x^3 + x + 4, 3*x^2 + 3*x + 2]]) + sage: B = Matrix(pR, 3, 3, + ....: [[4*x + 3*x + 3, 3*x^3 + 3*x + 1, 4*x^2 + x + 4], + ....: [6*x + 2*x + 3, 4*x^2 + 3*x, 3*x^2 + 4*x], + ....: [6, 6*x^3 + x + 4, 3*x^2 + 3*x + 2]]) sage: B.is_reduced(row_wise=False) True - sage: Q,R = A._right_quo_rem_reduced(B); (Q,R) + sage: Q, R = A._right_quo_rem_reduced(B); Q, R ( [2*x^2 + 4*x + 6 3*x^2 + 5*x 6*x^2 + 3*x] [6*x^2 + 4*x + 1 2*x^2 + x + 5 4*x^2 + 6*x + 1], @@ -2912,7 +2928,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): [ 1 5*x^2 + 2*x + 3 6*x + 3] ) sage: cdegR = R.column_degrees(); cdegB = B.column_degrees() - sage: A == Q*B+R and all([cdegR[i] < cdegB[i] for i in range(3)]) + sage: A == Q*B+R and all(cdegR[i] < cdegB[i] for i in range(3)) True """ # Step 0: find parameter d (delta in above reference) @@ -2923,7 +2939,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): return (self.parent().zero().__copy__(), self) # Step 1: reverse input matrices # Brev = B(1/x) diag(x^(cdeg[i])) - # Arev = A(1/x) diag(x^(d+cdeg[i]-1)) + # Arev = A(1/x) diag(x^(d+cdeg[i]-1)) Brev = B.reverse(degree=cdeg, row_wise=False) Arev = self.reverse(degree=[d+c-1 for c in cdeg], row_wise=False) # Step 2: compute quotient @@ -2953,20 +2969,19 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): and such a quotient and remainder is returned by the method. Or this matrix equation has no solution and this method fails: this raises ``ValueError``; however this is not a proof that there is no valid - division with remainder (see the last example below). + division with remainder (see the last example below). EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: A = Matrix(pR, 2, 3, \ - [[3*x^3 + 3*x, 3*x^3 + 6*x + 5, 2*x^3 + 2*x + 6], \ - [2*x^3 + 4, 6*x^3 + 5*x^2 + 1, 3*x^2 + 2*x + 2]]) - - sage: B = Matrix(pR, 3, 3, \ - [[4*x + 3*x + 3, 3*x^3 + 3*x + 1, 4*x^2 + x + 4], \ - [6*x + 2*x + 3, 4*x^2 + 3*x, 3*x^2 + 4*x], \ - [6, 6*x^3 + x + 4, 3*x^2 + 3*x + 2]]) - sage: Q,R = A._right_quo_rem_solve(B); (Q,R) + sage: A = Matrix(pR, 2, 3, + ....: [[3*x^3 + 3*x, 3*x^3 + 6*x + 5, 2*x^3 + 2*x + 6], + ....: [2*x^3 + 4, 6*x^3 + 5*x^2 + 1, 3*x^2 + 2*x + 2]]) + sage: B = Matrix(pR, 3, 3, + ....: [[4*x + 3*x + 3, 3*x^3 + 3*x + 1, 4*x^2 + x + 4], + ....: [6*x + 2*x + 3, 4*x^2 + 3*x, 3*x^2 + 4*x], + ....: [6, 6*x^3 + x + 4, 3*x^2 + 3*x + 2]]) + sage: Q, R = A._right_quo_rem_solve(B); Q, R ( [2*x^2 + 4*x + 6 3*x^2 + 5*x 6*x^2 + 3*x] [6*x^2 + 4*x + 1 2*x^2 + x + 5 4*x^2 + 6*x + 1], @@ -2983,13 +2998,13 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): With a nonsingular but also non-reduced matrix, there exists a solution and one is found by this method, but it might not be unique:: - sage: B = Matrix(pR, 3, 3, \ - [[ 5, 0, 2*x + 6], \ - [ 4*x, 3*x^2 + 4*x + 5, x + 1], \ - [3*x^2 + 5*x + 2, 6*x^3 + 4*x + 6, 3]]) - sage: B.det() != 0 and (not B.is_reduced(row_wise=False)) + sage: B = Matrix(pR, 3, 3, + ....: [[ 5, 0, 2*x + 6], + ....: [ 4*x, 3*x^2 + 4*x + 5, x + 1], + ....: [3*x^2 + 5*x + 2, 6*x^3 + 4*x + 6, 3]]) + sage: B.det() != 0 and not B.is_reduced(row_wise=False) True - sage: Q,R = A._right_quo_rem_solve(B); (Q,R) + sage: Q, R = A._right_quo_rem_solve(B); Q, R ( [ 6*x^2 + 3*x 4*x^2 + 3*x + 1 5*x + 1] [ x^2 + 5*x + 5 5*x^2 + 3*x + 5 x + 2], @@ -2998,15 +3013,15 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): [ 6*x + 3 5*x^2 + 6 3] ) sage: cdegR = R.column_degrees(); cdegB = B.column_degrees() - sage: A == Q*B+R and all([cdegR[i] < cdegB[i] for i in range(3)]) + sage: A == Q*B+R and all(cdegR[i] < cdegB[i] for i in range(3)) True - sage: Q2 = Matrix(pR, 2, 3, \ - [[6*x^2 + 3*x + 1, 4*x^2 + 3*x + 6, 5*x + 1], \ - [ x^2 + 5*x + 3, 5*x^2 + 3*x + 2, x + 2]]) - sage: R2 = Matrix(pR, 2, 3, \ - [[ 5*x, 3*x + 4, 5], \ - [4*x + 6, 5*x, 4]]) + sage: Q2 = Matrix(pR, 2, 3, + ....: [[6*x^2 + 3*x + 1, 4*x^2 + 3*x + 6, 5*x + 1], + ....: [ x^2 + 5*x + 3, 5*x^2 + 3*x + 2, x + 2]]) + sage: R2 = Matrix(pR, 2, 3, + ....: [[ 5*x, 3*x + 4, 5], + ....: [4*x + 6, 5*x, 4]]) sage: A == Q2*B + R2 True @@ -3015,8 +3030,8 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): other cases (rank-deficient or strictly fewer rows than columns) there might be no solution:: - sage: C = B.stack(B[1,:] + B[2,:]) # matrix 4 x 3, full column rank - sage: Q,R = A._right_quo_rem_solve(C); (Q,R) + sage: C = B.stack(B[1,:] + B[2,:]) # 4 x 3, full column rank + sage: Q, R = A._right_quo_rem_solve(C); Q, R ( [ 6*x^2 + 3*x 4*x^2 + 3*x + 1 5*x + 1 0] [ x^2 + 5*x + 5 5*x^2 + 3*x + 5 x + 2 0], @@ -3025,11 +3040,11 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): [ 6*x + 3 5*x^2 + 6 3] ) - sage: A._right_quo_rem_solve(B[:2,:]) # matrix 2 x 3, full row rank + sage: A._right_quo_rem_solve(B[:2,:]) # 2 x 3, full row rank Traceback (most recent call last): ... ValueError: dividing via system solving yields no solution - sage: D = copy(B); D[2,:] = B[0,:]+B[1,:] # square, singular + sage: D = copy(B); D[2,:] = B[0,:]+B[1,:] # square, singular sage: A._right_quo_rem_solve(D) Traceback (most recent call last): ... @@ -3125,13 +3140,13 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: B = Matrix(pR, [ \ - [ 6*x+4, 5*x^3+5*x, 6*x^2+2*x+2], \ - [4*x^2+5*x+2, x^4+5*x^2+2*x+4, 4*x^3+6*x^2+6*x+5]]) - sage: A = Matrix(pR, 1, 3, [ \ - [3*x^4+3*x^3+4*x^2+5*x+1, x^4+x^3+5*x^2+4*x+4, 4*x^4+2*x^3+x]]) + sage: B = Matrix(pR, [ + ....: [ 6*x+4, 5*x^3+5*x, 6*x^2+2*x+2], + ....: [4*x^2+5*x+2, x^4+5*x^2+2*x+4, 4*x^3+6*x^2+6*x+5]]) + sage: A = Matrix(pR, 1, 3, [ + ....: [3*x^4+3*x^3+4*x^2+5*x+1, x^4+x^3+5*x^2+4*x+4, 4*x^4+2*x^3+x]]) - sage: (Q,R) = A.reduce(B,return_quotient=True); R + sage: Q, R = A.reduce(B,return_quotient=True); R [3*x^4 + 3*x^3 + 4*x + 3 2*x + 2 2*x + 6] sage: A == Q*B + R True @@ -3149,12 +3164,12 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): Demonstrating shifts:: - sage: (Qs,Rs) = A.reduce(B,shifts=[0,2,4],return_quotient=True); Rs + sage: Qs, Rs = A.reduce(B, shifts=[0,2,4], return_quotient=True); Rs [3*x^4 + 3*x^3 + 6*x + 2 4*x^3 + 5*x 0] sage: A == Qs*B + Rs True sage: Ps = B.popov_form(shifts=[0,2,4]) - sage: Ps.leading_positions(shifts=[0,2,4],return_degree=True) + sage: Ps.leading_positions(shifts=[0,2,4], return_degree=True) ([1, 2], [4, 0]) sage: Rs.degree_matrix() [ 4 3 -1] @@ -3163,17 +3178,17 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): If ``return_quotient`` is ``False``, only the normal form is returned:: - sage: R == A.reduce(B) and Rs == A.reduce(B,shifts=[0,2,4]) + sage: R == A.reduce(B) and Rs == A.reduce(B, shifts=[0,2,4]) True Demonstrating column-wise normal forms, with a matrix `A` which has several columns, and a matrix `B` which does not have full column rank (its column-wise Popov form has a zero column):: - sage: A = Matrix(pR, 2, 2, \ - [[5*x^3 + 2*x^2 + 4*x + 1, x^3 + 4*x + 4], \ - [2*x^3 + 5*x^2 + 2*x + 4, 2*x^3 + 3*x + 2]]) - sage: (Q,R) = A.reduce(B,row_wise=False,return_quotient=True); R + sage: A = Matrix(pR, 2, 2, + ....: [[5*x^3 + 2*x^2 + 4*x + 1, x^3 + 4*x + 4], + ....: [2*x^3 + 5*x^2 + 2*x + 4, 2*x^3 + 3*x + 2]]) + sage: (Q,R) = A.reduce(B,row_wise=False, return_quotient=True); R [0 3] [0 0] sage: A == B*Q + R @@ -3245,12 +3260,12 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): Return ``True`` if and only if this matrix is an approximant basis in ``shifts``-ordered weak Popov form for the polynomial matrix ``pmat`` at order ``order``. - + If ``normal_form`` is ``True``, then the polynomial matrix must furthermore be in ``shifts``-Popov form. An error is raised if the input dimensions are not sound. If a single integer is provided for ``order``, then it is interpreted as a list of repeated integers with - this value. (See :meth:`minimal_approximant_basis` for definitions and + this value. (See :meth:`minimal_approximant_basis` for definitions and more details.) INPUT: @@ -3289,20 +3304,20 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): computing minimal approximant bases, 2006]:: sage: order = 8; shifts = [1,1,0,0,0] - sage: pmat = Matrix(pR, 5, 1, [ \ - pR([35, 0, 41, 87, 3, 42, 22, 90]), \ - pR([80, 15, 62, 87, 14, 93, 24, 0]), \ - pR([42, 57, 90, 87, 22, 80, 71, 53]), \ - pR([37, 72, 74, 6, 5, 75, 23, 47]), \ - pR([36, 10, 74, 1, 29, 44, 87, 74]) ]) - sage: appbas = Matrix(pR, [ \ - [x+47, 57, 58*x+44, 9*x+23, 93*x+76], \ - [ 15, x+18, 52*x+23, 15*x+58, 93*x+88], \ - [ 17, 86, x^2+77*x+16, 76*x+29, 90*x+78], \ - [ 44, 36, 3*x+42, x^2+50*x+26, 85*x+44], \ - [ 2, 22, 54*x+94, 73*x+24, x^2+2*x+25] ]) - sage: appbas.is_minimal_approximant_basis(pmat,\ - order, shifts, row_wise=True, normal_form=True) + sage: pmat = Matrix(pR, 5, 1, [ + ....: pR([35, 0, 41, 87, 3, 42, 22, 90]), + ....: pR([80, 15, 62, 87, 14, 93, 24, 0]), + ....: pR([42, 57, 90, 87, 22, 80, 71, 53]), + ....: pR([37, 72, 74, 6, 5, 75, 23, 47]), + ....: pR([36, 10, 74, 1, 29, 44, 87, 74])]) + sage: appbas = Matrix(pR, [ + ....: [x+47, 57, 58*x+44, 9*x+23, 93*x+76], + ....: [ 15, x+18, 52*x+23, 15*x+58, 93*x+88], + ....: [ 17, 86, x^2+77*x+16, 76*x+29, 90*x+78], + ....: [ 44, 36, 3*x+42, x^2+50*x+26, 85*x+44], + ....: [ 2, 22, 54*x+94, 73*x+24, x^2+2*x+25]]) + sage: appbas.is_minimal_approximant_basis( + ....: pmat, order, shifts, row_wise=True, normal_form=True) True The matrix `x^8 \mathrm{Id}_5` is square, nonsingular, in Popov form, @@ -3310,16 +3325,17 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): not an approximant basis since its rows generate a module strictly contained in the set of approximants for ``pmat`` at order 8:: - sage: (x^8*Matrix.identity(pR, 5)).is_minimal_approximant_basis(\ - pmat, 8) + sage: M = x^8 * Matrix.identity(pR, 5) + sage: M.is_minimal_approximant_basis(pmat, 8) False Since ``pmat`` is a single column, with nonzero constant coefficient, its column-wise approximant bases at order 8 are all `1\times 1` matrices `[c x^8]` for some nonzero field element `c`:: - sage: Matrix(pR, [x^8]).is_minimal_approximant_basis(pmat, \ - 8, row_wise=False, normal_form=True) + sage: M = Matrix(pR, [x^8]) + sage: M.is_minimal_approximant_basis( + ....: pmat, 8, row_wise=False, normal_form=True) True Exceptions are raised if input dimensions are not sound:: @@ -3327,14 +3343,14 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: appbas.is_minimal_approximant_basis(pmat, [8,8], shifts) Traceback (most recent call last): ... - ValueError: order length should be the column dimension + ValueError: order length should be the column dimension of the input matrix - sage: appbas.is_minimal_approximant_basis(pmat, \ - order, shifts, row_wise=False) + sage: appbas.is_minimal_approximant_basis( + ....: pmat, order, shifts, row_wise=False) Traceback (most recent call last): ... - ValueError: shifts length should be the column dimension + ValueError: shifts length should be the column dimension of the input matrix sage: Matrix(pR, [x^8]).is_minimal_approximant_basis(pmat, 8) @@ -3496,9 +3512,9 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: pR.<x> = GF(7)[] sage: order = [4, 3]; shifts = [-1, 2, 0] - sage: F = Matrix(pR, [[5*x^3 + 4*x^2 + 4*x + 6, 5*x^2 + 4*x + 1], \ - [ 2*x^2 + 2*x + 3, 6*x^2 + 6*x + 3], \ - [4*x^3 + x + 1, 4*x^2 + 2*x + 3] ]) + sage: F = Matrix(pR, [[5*x^3 + 4*x^2 + 4*x + 6, 5*x^2 + 4*x + 1], + ....: [ 2*x^2 + 2*x + 3, 6*x^2 + 6*x + 3], + ....: [4*x^3 + x + 1, 4*x^2 + 2*x + 3]]) sage: P = F.minimal_approximant_basis(order, shifts) sage: P.is_minimal_approximant_basis(F, order, shifts) True @@ -3506,30 +3522,33 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): By default, the computed basis is not required to be in normal form (and will not be except in rare special cases):: - sage: P.is_minimal_approximant_basis(F, order, shifts, \ - normal_form=True) + sage: P.is_minimal_approximant_basis(F, order, shifts, + ....: normal_form=True) False - sage: P = F.minimal_approximant_basis(order, shifts, normal_form=True) - sage: P.is_minimal_approximant_basis(F, order, shifts, \ - normal_form=True) + sage: P = F.minimal_approximant_basis(order, shifts, + ....: normal_form=True) + sage: P.is_minimal_approximant_basis(F, order, shifts, + ....: normal_form=True) True If shifts are not specified, they are chosen as uniform `[0,\ldots,0]` by default. Besides, if the orders are all the same, one can rather give a single integer:: - sage: F.minimal_approximant_basis(3) == \ - F.minimal_approximant_basis([3,3], shifts=None) + sage: (F.minimal_approximant_basis(3) == + ....: F.minimal_approximant_basis([3,3], shifts=None)) True One can work column-wise by specifying ``row_wise=False``:: - sage: P = F.minimal_approximant_basis([5,2,2], [0,1], row_wise=False) - sage: P.is_minimal_approximant_basis(F, [5,2,2], \ - shifts=[0,1], row_wise=False) + sage: P = F.minimal_approximant_basis([5,2,2], [0,1], + ....: row_wise=False) + sage: P.is_minimal_approximant_basis(F, [5,2,2], shifts=[0,1], + ....: row_wise=False) True - sage: F.minimal_approximant_basis(3, row_wise=True) == \ - F.transpose().minimal_approximant_basis(3, row_wise=False).transpose() + sage: (F.minimal_approximant_basis(3, row_wise=True) == + ....: F.transpose().minimal_approximant_basis( + ....: 3, row_wise=False).transpose()) True Errors are raised if the input dimensions are not sound:: @@ -3612,7 +3631,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): def _approximant_basis_iterative(self, order, shifts): r""" Return a ``shifts``-ordered weak Popov approximant basis for this - polynomial matrix at order ``order`` + polynomial matrix at order ``order`` (see :meth:`minimal_approximant_basis` for definitions). The output basis is considered row-wise, that is, its rows are @@ -3649,10 +3668,10 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): arbitrary shifts and orders:: sage: order = [4, 1, 2]; shifts = [-3, 4] - sage: pmat = Matrix(pR, [[5*x^3 + 4*x^2 + 4*x + 6, 5, 4], \ - [2*x^3 + 2*x^2 + 2*x + 3, 6, 6*x + 3]]) - sage: appbas,rdeg = pmat._approximant_basis_iterative(order, \ - shifts) + sage: pmat = Matrix(pR, [[5*x^3 + 4*x^2 + 4*x + 6, 5, 4], + ....: [2*x^3 + 2*x^2 + 2*x + 3, 6, 6*x + 3]]) + sage: appbas, rdeg = pmat._approximant_basis_iterative(order, + ....: shifts) sage: appbas.is_minimal_approximant_basis(pmat, order, shifts) True @@ -3665,8 +3684,8 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): matrices; in fact, this algorithm returns the identity:: sage: pmat = Matrix(pR, 3, 2) - sage: appbas,rdeg = pmat._approximant_basis_iterative([2,5], \ - [5,0,-4]) + sage: appbas,rdeg = pmat._approximant_basis_iterative([2,5], + ....: [5,0,-4]) sage: rdeg == [5,0,-4] and appbas == Matrix.identity(pR, 3) True """ @@ -3797,23 +3816,25 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(97)[] - sage: pmat = Matrix(pR, [[1],[x],[x**2]]) + sage: pmat = Matrix(pR, [[1], [x], [x**2]]) - sage: kerbas = Matrix(pR, [[x,-1,0],[0,x,-1]]) + sage: kerbas = Matrix(pR, [[x,-1,0], [0,x,-1]]) sage: kerbas.is_minimal_kernel_basis(pmat) True A matrix in Popov form which has the right rank, all rows in the kernel, but does not generate the kernel:: - sage: kerbas = Matrix(pR, [[x**2,0,-1],[0,x,-1]]) + sage: kerbas = Matrix(pR, [[x**2,0,-1], [0,x,-1]]) sage: kerbas.is_minimal_kernel_basis(pmat) False Shifts and right kernel bases are supported (with ``row_wise``), and one can test whether the kernel basis is normalized in shifted-Popov form (with ``normal_form``):: - sage: kerbas = Matrix(pR, [[-x,-x**2],[1,0],[0,1]]) - sage: kerbas.is_minimal_kernel_basis(pmat.transpose(),row_wise=False,normal_form=True,shifts=[0,1,2]) + sage: kerbas = Matrix(pR, [[-x,-x**2], [1,0], [0,1]]) + sage: kerbas.is_minimal_kernel_basis( + ....: pmat.transpose(), row_wise=False, + ....: normal_form=True, shifts=[0,1,2]) True """ m = pmat.nrows() @@ -3917,31 +3938,54 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): EXAMPLES:: sage: pR.<x> = GF(7)[] - sage: pmat = Matrix([[(x+1)*(x+3)],[(x+1)*(x+3)+1]]) + sage: pmat = Matrix([[(x+1)*(x+3)], [(x+1)*(x+3)+1]]) sage: pmat.minimal_kernel_basis() [6*x^2 + 3*x + 3 x^2 + 4*x + 3] - sage: pmat = Matrix([[(x+1)*(x+3)],[(x+1)*(x+4)]]) + sage: pmat = Matrix([[(x+1)*(x+3)], [(x+1)*(x+4)]]) sage: pmat.minimal_kernel_basis() [6*x + 3 x + 3] sage: pmat.minimal_kernel_basis(row_wise=False) [] - sage: pmat = Matrix(pR, [[1,x,x**2]]) - sage: pmat.minimal_kernel_basis(row_wise=False,normal_form=True) + sage: pmat = Matrix(pR, [[1, x, x**2]]) + sage: pmat.minimal_kernel_basis(row_wise=False, normal_form=True) [x 0] [6 x] [0 6] - sage: pmat.minimal_kernel_basis(row_wise=False,normal_form=True,shifts=[0,1,2]) + sage: pmat.minimal_kernel_basis(row_wise=False, normal_form=True, + ....: shifts=[0,1,2]) [ 6*x 6*x^2] [ 1 0] [ 0 1] + + Some particular cases (matrix is zero, dimension is zero, column is zero):: + + sage: Matrix(pR, 2, 1).minimal_kernel_basis() + [1 0] + [0 1] + + sage: Matrix(pR, 2, 0).minimal_kernel_basis() + [1 0] + [0 1] + + sage: Matrix(pR, 0, 2).minimal_kernel_basis() + [] + + sage: Matrix(pR, 3, 2, [[1,0],[1,0],[1,0]]).minimal_kernel_basis() + [6 1 0] + [6 0 1] + + sage: Matrix(pR, 3, 2, [[x,0],[1,0],[x+1,0]]).minimal_kernel_basis() + [6 x 0] + [6 6 1] """ + from sage.matrix.constructor import matrix + m = self.nrows() n = self.ncols() - d = self.degree() # set default shifts / check shifts dimension if shifts is None: @@ -3953,15 +3997,17 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): # compute kernel basis if row_wise: - if d is -1: # matrix is zero - from sage.matrix.constructor import matrix - return matrix.identity(self.base_ring(), m, m) - if m <= n and self.constant_matrix().rank() == m: - # early exit: kernel is empty - from sage.matrix.constructor import matrix + # early exit: kernel is empty; note: this covers the case m==0 return matrix(self.base_ring(), 0, m) + if n == 0: # early exit: kernel is identity + return matrix.identity(self.base_ring(), m, m) + + d = self.degree() # well defined since m > 0 and n > 0 + if d == -1: # matrix is zero: kernel is identity + return matrix.identity(self.base_ring(), m, m) + # degree bounds on the kernel basis degree_bound = min(m,n)*d+max(shifts) degree_bounds = [degree_bound - shifts[i] for i in range(m)] @@ -3970,24 +4016,37 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): orders = self.column_degrees(degree_bounds) for i in range(n): orders[i] = orders[i]+1 + # note: minimal_approximant_basis requires orders[i] > 0 + # -> if d>0, then degree_bounds > 0 entry-wise and this tuple + # `orders` already has all entries strictly positive + # -> if d==0, then `orders[i]` is zero exactly when the column i + # of self is zero; we may as well take orders[i] == 1 for such + # columns which do not influence the left kernel + if d == 0: + for i in range(n): + if orders[i] == 0: + orders[i] = 1 + # compute approximant basis and retrieve kernel rows P = self.minimal_approximant_basis(orders,shifts,True,normal_form) row_indices = [] for i in range(m): - if P[i,i].degree() + shifts[i] <= degree_bound: + if P[i, i].degree() + shifts[i] <= degree_bound: row_indices.append(i) return P[row_indices,:] else: - if d is -1: # matrix is zero - from sage.matrix.constructor import matrix - return matrix.identity(self.base_ring(), n, n) - if n <= m and self.constant_matrix().rank() == n: - # early exit: kernel is empty - from sage.matrix.constructor import matrix + # early exit: kernel is empty; this covers the case n==0 return matrix(self.base_ring(), n, 0) + if m == 0: # early exit: kernel is identity + return matrix.identity(self.base_ring(), n, n) + + d = self.degree() # well defined since m > 0 and n > 0 + if d == -1: # matrix is zero + return matrix.identity(self.base_ring(), n, n) + # degree bounds on the kernel basis degree_bound = min(m,n)*d+max(shifts) degree_bounds = [degree_bound - shifts[i] for i in range(n)] @@ -3996,10 +4055,21 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): orders = self.row_degrees(degree_bounds) for i in range(m): orders[i] = orders[i]+1 + # note: minimal_approximant_basis requires orders[i] > 0 + # -> if d>0, then degree_bounds > 0 entry-wise and this tuple + # `orders` already has all entries strictly positive + # -> if d==0, then `orders[i]` is zero exactly when the row i + # of self is zero; we may as well take orders[i] == 1 for such + # rows which do not influence the right kernel + if d == 0: + for i in range(m): + if orders[i] == 0: + orders[i] = 1 + # compute approximant basis and retrieve kernel columns P = self.minimal_approximant_basis(orders,shifts,False,normal_form) column_indices = [] for j in range(n): - if P[j,j].degree() + shifts[j] <= degree_bound: + if P[j, j].degree() + shifts[j] <= degree_bound: column_indices.append(j) return P[:,column_indices] diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index 93efb95781f..c9e1d87b049 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -59,7 +59,7 @@ Test hashing:: 1997752305 # 32-bit """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004,2005,2006 William Stein <wstein@gmail.com> # 2017 Vincent Delecroix <20100.delecroix@gmail.com> # @@ -67,8 +67,8 @@ Test hashing:: # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from libc.string cimport strcpy, strlen @@ -80,7 +80,7 @@ from sage.misc.randstate cimport randstate, current_randstate from sage.modules.vector_rational_dense cimport Vector_rational_dense -from cysignals.signals cimport sig_on, sig_off, sig_check +from cysignals.signals cimport sig_on, sig_off from cysignals.memory cimport sig_malloc, sig_free from sage.arith.rational_reconstruction cimport mpq_rational_reconstruction @@ -88,8 +88,12 @@ from sage.arith.rational_reconstruction cimport mpq_rational_reconstruction from sage.libs.gmp.types cimport mpz_t, mpq_t from sage.libs.gmp.mpz cimport mpz_init, mpz_clear, mpz_cmp_si from sage.libs.gmp.mpq cimport mpq_init, mpq_clear, mpq_set_si, mpq_mul, mpq_add, mpq_set -from sage.libs.gmp.randomize cimport (mpq_randomize_entry, mpq_randomize_entry_as_int, mpq_randomize_entry_recip_uniform, - mpq_randomize_entry_nonzero, mpq_randomize_entry_as_int_nonzero, mpq_randomize_entry_recip_uniform_nonzero) +from sage.libs.gmp.randomize cimport (mpq_randomize_entry, + mpq_randomize_entry_as_int, + mpq_randomize_entry_recip_uniform, + mpq_randomize_entry_nonzero, + mpq_randomize_entry_as_int_nonzero, + mpq_randomize_entry_recip_uniform_nonzero) from sage.libs.flint.fmpz cimport * from sage.libs.flint.fmpq cimport * @@ -98,36 +102,29 @@ from sage.libs.flint.fmpq_mat cimport * cimport sage.structure.element -from sage.structure.sequence import Sequence from sage.structure.richcmp cimport rich_to_bool from sage.rings.rational cimport Rational from .matrix cimport Matrix from .args cimport SparseEntry, MatrixArgs_init from .matrix_integer_dense cimport Matrix_integer_dense, _lift_crt -from sage.structure.element cimport ModuleElement, RingElement, Element, Vector +from sage.structure.element cimport Element, Vector from sage.rings.integer cimport Integer from sage.rings.ring import is_Ring from sage.rings.integer_ring import ZZ, is_IntegerRing -from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF import sage.rings.abc from sage.rings.rational_field import QQ -from sage.arith.all import gcd from .matrix2 import decomp_seq -from .matrix0 import Matrix as Matrix_base +from sage.misc.verbose import verbose -from sage.misc.misc_c import prod -from sage.misc.verbose import verbose, get_verbose - -######################################################### +# ######################################################## # PARI C library -from cypari2.gen cimport Gen from sage.libs.pari.all import PariError from sage.libs.pari.convert_gmp cimport INTFRAC_to_mpq from sage.libs.pari.convert_flint cimport rational_matrix, _new_GEN_from_fmpq_mat_t from cypari2.stack cimport clear_stack from cypari2.paridecl cimport * -######################################################### +# ######################################################## cdef class Matrix_rational_dense(Matrix_dense): def __cinit__(self): @@ -158,7 +155,7 @@ cdef class Matrix_rational_dense(Matrix_dense): return Matrix_rational_dense.__new__(Matrix_rational_dense, parent, None, None, None) - def __dealloc__(self): + def __dealloc__(self): fmpq_mat_clear(self._matrix) def __init__(self, parent, entries=None, copy=None, bint coerce=True): @@ -216,7 +213,7 @@ cdef class Matrix_rational_dense(Matrix_dense): [8 7 6 8] """ cdef Matrix_rational_dense A - cdef Py_ssize_t ncols, k, r, col + cdef Py_ssize_t k, r, col A = self._new_matrix(self._nrows, len(columns)) k = 0 @@ -299,7 +296,7 @@ cdef class Matrix_rational_dense(Matrix_dense): if version == 0: self._unpickle_version0(data) else: - raise RuntimeError("unknown matrix version (=%s)"%version) + raise RuntimeError("unknown matrix version (=%s)" % version) cdef _pickle_version0(self): return self._export_as_string(32) @@ -322,7 +319,6 @@ cdef class Matrix_rational_dense(Matrix_dense): '1 2/3 -3/4 1 -2/3 -2d/11' """ cdef Py_ssize_t i, j, len_so_far, m, n - cdef char *a cdef char *s cdef char *t cdef char *tmp @@ -388,7 +384,7 @@ cdef class Matrix_rational_dense(Matrix_dense): raise RuntimeError("invalid pickle data") fmpz_one(fmpq_mat_entry_den(self._matrix, i, j)) - ######################################################################## + # ####################################################################### # LEVEL 2 functionality # x * cdef _add_ # x * cdef _mul_ @@ -400,7 +396,7 @@ cdef class Matrix_rational_dense(Matrix_dense): # x * _multiply_classical # * _list -- list of underlying elements (need not be a copy) # * _dict -- sparse dictionary of underlying elements (need not be a copy) - ######################################################################## + # ####################################################################### cpdef _lmul_(self, Element right): """ @@ -547,7 +543,6 @@ cdef class Matrix_rational_dense(Matrix_dense): mpq_clear(z) return ans - def __neg__(self): """ Negate a matrix over QQ. @@ -595,7 +590,7 @@ cdef class Matrix_rational_dense(Matrix_dense): ans._subdivisions = self._subdivisions return ans - ######################################################################## + # ####################################################################### # LEVEL 3 functionality (Optional) # x * cdef _sub_ # * __deepcopy__ @@ -606,7 +601,7 @@ cdef class Matrix_rational_dense(Matrix_dense): # x * mpz_denom(self, mpz_t d): # x * _clear_denom(self): # o * echelon_modular(self, height_guess=None): - ######################################################################## + # ####################################################################### def __invert__(self): """ EXAMPLES:: @@ -755,7 +750,7 @@ cdef class Matrix_rational_dense(Matrix_dense): return (denom/d)*B else: - raise ValueError("unknown algorithm '%s'"%algorithm) + raise ValueError("unknown algorithm '%s'" % algorithm) def determinant(self, algorithm=None, proof=None): """ @@ -855,7 +850,7 @@ cdef class Matrix_rational_dense(Matrix_dense): elif algorithm == "generic": det = Matrix_dense.determinant(self) else: - raise ValueError("unknown algorithm '%s'"%algorithm) + raise ValueError("unknown algorithm '%s'" % algorithm) self.cache('det', det) return det @@ -954,7 +949,7 @@ cdef class Matrix_rational_dense(Matrix_dense): from sage.matrix.matrix_space import MatrixSpace MZ = MatrixSpace(ZZ, self._nrows, self._ncols, sparse=False) - A = Matrix_integer_dense.__new__(Matrix_integer_dense, MZ, None, None, None) + A = Matrix_integer_dense.__new__(Matrix_integer_dense, MZ, None, None, None) sig_on() for i in range(self._nrows): @@ -1050,7 +1045,7 @@ cdef class Matrix_rational_dense(Matrix_dense): elif algorithm == 'generic': g = Matrix_dense.charpoly(self, var) else: - raise ValueError("no algorithm '%s'"%algorithm) + raise ValueError("no algorithm '%s'" % algorithm) self.cache('charpoly', g) return g @@ -1127,7 +1122,7 @@ cdef class Matrix_rational_dense(Matrix_dense): elif algorithm == 'generic': g = Matrix_dense.minpoly(self, var) else: - raise ValueError("no algorithm '%s'"%algorithm) + raise ValueError("no algorithm '%s'" % algorithm) self.cache('minpoly', g) return g @@ -1228,7 +1223,7 @@ cdef class Matrix_rational_dense(Matrix_dense): AB = A*B else: sig_off() - raise ValueError("unknown algorithm '%s'"%algorithm) + raise ValueError("unknown algorithm '%s'" % algorithm) D = A_denom * B_denom if self._nrows == right._nrows: # self acts on the space of right @@ -1246,7 +1241,6 @@ cdef class Matrix_rational_dense(Matrix_dense): sig_off() return res - def height(self): """ Return the height of this matrix, which is the maximum of the @@ -1323,7 +1317,7 @@ cdef class Matrix_rational_dense(Matrix_dense): X, d = self._clear_denom() s = X._magma_init_(magma).replace('IntegerRing','RationalField') if d != 1: - s += '/%s'%d._magma_init_(magma) + s += '/%s' % d._magma_init_(magma) return s def prod_of_row_sums(self, cols): @@ -1420,9 +1414,9 @@ cdef class Matrix_rational_dense(Matrix_dense): verbose("done computing right kernel matrix over the rationals for %sx%s matrix" % (self.nrows(), self.ncols()),level=1, t=tm) return 'computed-iml-rational', K - ################################################ + # ############################################### # Change ring - ################################################ + # ############################################### def change_ring(self, R): """ Create the matrix over R with entries the entries of self coerced @@ -1494,11 +1488,9 @@ cdef class Matrix_rational_dense(Matrix_dense): # fallback to the generic version return Matrix_dense.change_ring(self, R) - - - ################################################ + # ############################################### # Echelon form - ################################################ + # ############################################### def echelonize(self, algorithm=None, height_guess=None, proof=None, **kwds): """ @@ -1565,8 +1557,8 @@ cdef class Matrix_rational_dense(Matrix_dense): ....: a.echelonize(algorithm=algo) ....: assert sorted(a._cache.keys()) == ['echelon_form', 'in_echelon_form', 'pivots', 'rank'], (algo, a._cache.keys()) """ - - if self.fetch('in_echelon_form'): return # already known to be in echelon form + if self.fetch('in_echelon_form'): + return # already known to be in echelon form self.check_mutability() if algorithm is None: @@ -1584,7 +1576,7 @@ cdef class Matrix_rational_dense(Matrix_dense): elif algorithm == 'padic': pivots = self._echelonize_padic() else: - raise ValueError("no algorithm '%s'"%algorithm) + raise ValueError("no algorithm '%s'" % algorithm) if type(pivots) is not tuple: raise RuntimeError("BUG: pivots must get set as a tuple. Got {} for algo {} with {}x{} matrix.".format( @@ -1752,7 +1744,6 @@ cdef class Matrix_rational_dense(Matrix_dense): # 1 at pivot fmpq_one(fmpq_mat_entry(self._matrix, i, pivots[i])) - # nonzero part for j in range(X.ncols()): entry = fmpq_mat_entry(self._matrix, i, nonpivots[j]) @@ -1818,7 +1809,6 @@ cdef class Matrix_rational_dense(Matrix_dense): fmpq_mat_swap(self._matrix, (<Matrix_rational_dense>E)._matrix) return pivots - cdef swap_rows_c(self, Py_ssize_t r1, Py_ssize_t r2): """ EXAMPLES:: @@ -1926,13 +1916,14 @@ cdef class Matrix_rational_dense(Matrix_dense): """ X = self._decomposition_rational(is_diagonalizable=is_diagonalizable, - echelon_algorithm = algorithm, - height_guess = height_guess, proof=proof) - if dual: - Y = self.transpose()._decomposition_rational(is_diagonalizable=is_diagonalizable, - echelon_algorithm = algorithm, height_guess = height_guess, proof=proof) - return X, Y - return X + echelon_algorithm=algorithm, + height_guess=height_guess, proof=proof) + if not dual: + return X + + Y = self.transpose()._decomposition_rational(is_diagonalizable=is_diagonalizable, + echelon_algorithm=algorithm, height_guess=height_guess, proof=proof) + return X, Y def _decomposition_rational(self, is_diagonalizable = False, echelon_algorithm=None, @@ -2003,7 +1994,7 @@ cdef class Matrix_rational_dense(Matrix_dense): v = V.random_element() num_iterates = max([0] + [f.degree() - g.degree() for g, _ in F if g.degree() > 1]) + 1 - S = [ ] + S = [] F.sort() for i in range(len(F)): @@ -2031,15 +2022,15 @@ cdef class Matrix_rational_dense(Matrix_dense): v = h.list() while len(S) < tries: - t = verbose('%s-spinning %s-th random vector'%(num_iterates, len(S)), + t = verbose('%s-spinning %s-th random vector' % (num_iterates, len(S)), level=2, caller_name='rational decomp') S.append(A.iterates(V.random_element(x=-10,y=10), num_iterates)) verbose('done spinning', level=2, t=t, caller_name='rational decomp') for j in range(0 if W is None else W.nrows() // g.degree(), len(S)): # Compute one element of the kernel of g(A)**m. - t = verbose('compute element of kernel of g(A), for g of degree %s'%g.degree(),level=2, - caller_name='rational decomp') + t = verbose('compute element of kernel of g(A), for g of degree %s' % g.degree(), level=2, + caller_name='rational decomp') w = S[j].linear_combination_of_rows(h.list()) t = verbose('done computing element of kernel of g(A)', t=t,level=2, caller_name='rational decomp') @@ -2059,141 +2050,137 @@ cdef class Matrix_rational_dense(Matrix_dense): verbose('computed row space', level=2,t=t, caller_name='rational decomp') break else: - verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)'%( - W.rank(), m*g.degree()), level=2, caller_name='rational decomp') + verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)' % (W.rank(), m*g.degree()), + level=2, caller_name='rational decomp') tries += 1 if tries > 5*m: raise RuntimeError("likely bug in decomposition") # end if - #end while - #end for + # end while + # end for return decomp_seq(E) - -## def simple_decomposition(self, echelon_algorithm='default', **kwds): -## """ -## Returns the decomposition of the free module on which this -## matrix A acts from the right (i.e., the action is x goes to x -## A), as a direct sum of simple modules. - -## NOTE: self *must* be diagonalizable. - -## INPUT: -## self -- a square matrix that is assumed to be diagonalizable -## echelon_algorithm -- 'default' -## 'multimodular' -- use this if the answers -## have small height -## **kwds -- passed on to echelon function. - -## IMPORTANT NOTE: -## If you expect that the subspaces in the answer are spanned by vectors -## with small height coordinates, use algorithm='multimodular' and -## height_guess=1; this is potentially much faster than the default. -## If you know for a fact the answer will be very small, use -## algorithm='multimodular', height_guess=bound on height, proof=False - -## OUTPUT: -## Sequence -- list of tuples (V,g), where V is a subspace -## and an irreducible polynomial g, which is the -## charpoly (=minpoly) of self acting on V. -## """ -## cdef Py_ssize_t k - -## if not self.is_square(): -## raise ArithmeticError("self must be a square matrix") - -## if self.nrows() == 0: -## return decomp_seq([]) - -## A, _ = self._clear_denom() - -## f = A.charpoly('x') -## E = decomp_seq([]) - -## t = verbose('factoring the characteristic polynomial', level=2, caller_name='simple decomp') -## F = f.factor() -## G = [g for g, _ in F] -## minpoly = prod(G) -## squarefree_degree = sum([g.degree() for g in G]) -## verbose('done factoring', t=t, level=2, caller_name='simple decomp') - -## V = ZZ**self.nrows() -## v = V.random_element() -## num_iterates = max([squarefree_degree - g.degree() for g in G]) + 1 - -## S = [ ] - -## F.sort() -## for i in range(len(F)): -## g, m = F[i] - -## if g.degree() == 1: -## # Just use kernel -- much easier. -## B = A.__copy__() -## for k from 0 <= k < A.nrows(): -## B[k,k] += g[0] -## if m > 1 and not is_diagonalizable: -## B = B**m -## W = B.change_ring(QQ).kernel() -## for b in W.basis(): -## E.append((W.span(b), g)) -## continue - -## # General case, i.e., deg(g) > 1: -## W = None -## while True: - -## # Compute the complementary factor of the charpoly. -## h = minpoly // g -## v = h.list() - -## while len(S) < m: -## t = verbose('%s-spinning %s-th random vector'%(num_iterates, len(S)), -## level=2, caller_name='simple decomp') -## S.append(A.iterates(V.random_element(x=-10,y=10), num_iterates)) -## verbose('done spinning', level=2, t=t, caller_name='simple decomp') - -## for j in range(len(S)): -## # Compute one element of the kernel of g(A). -## t = verbose('compute element of kernel of g(A), for g of degree %s'%g.degree(),level=2, -## caller_name='simple decomp') -## w = S[j].linear_combination_of_rows(h.list()) -## t = verbose('done computing element of kernel of g(A)', t=t,level=2, caller_name='simple decomp') - -## # Get the rest of the kernel. -## t = verbose('fill out rest of kernel',level=2, caller_name='simple decomp') -## if W is None: -## W = A.iterates(w, g.degree()) -## else: -## W = W.stack(A.iterates(w, g.degree())) -## t = verbose('finished filling out more of kernel',level=2, t=t, caller_name='simple decomp') - -## if W.rank() == m * g.degree(): -## W = W.change_ring(QQ) -## t = verbose('now computing row space', level=2, caller_name='simple decomp') -## W.echelonize(algorithm = echelon_algorithm, **kwds) -## E.append((W.row_space(), m==1)) -## verbose('computed row space', level=2,t=t, caller_name='simple decomp') -## break -## else: -## verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)'%( -## W.rank(), m*g.degree()), level=2, caller_name='simple decomp') -## j += 1 -## if j > 3*m: -## raise RuntimeError("likely bug in decomposition") -## # end if -## #end while -## #end for -## return E - +# def simple_decomposition(self, echelon_algorithm='default', **kwds): +# """ +# Returns the decomposition of the free module on which this +# matrix A acts from the right (i.e., the action is x goes to x +# A), as a direct sum of simple modules. + +# NOTE: self *must* be diagonalizable. + +# INPUT: +# self -- a square matrix that is assumed to be diagonalizable +# echelon_algorithm -- 'default' +# 'multimodular' -- use this if the answers +# have small height +# **kwds -- passed on to echelon function. + +# IMPORTANT NOTE: +# If you expect that the subspaces in the answer are spanned by vectors +# with small height coordinates, use algorithm='multimodular' and +# height_guess=1; this is potentially much faster than the default. +# If you know for a fact the answer will be very small, use +# algorithm='multimodular', height_guess=bound on height, proof=False + +# OUTPUT: +# Sequence -- list of tuples (V,g), where V is a subspace +# and an irreducible polynomial g, which is the +# charpoly (=minpoly) of self acting on V. +# """ +# cdef Py_ssize_t k + +# if not self.is_square(): +# raise ArithmeticError("self must be a square matrix") + +# if self.nrows() == 0: +# return decomp_seq([]) + +# A, _ = self._clear_denom() + +# f = A.charpoly('x') +# E = decomp_seq([]) + +# t = verbose('factoring the characteristic polynomial', level=2, caller_name='simple decomp') +# F = f.factor() +# G = [g for g, _ in F] +# minpoly = prod(G) +# squarefree_degree = sum([g.degree() for g in G]) +# verbose('done factoring', t=t, level=2, caller_name='simple decomp') + +# V = ZZ**self.nrows() +# v = V.random_element() +# num_iterates = max([squarefree_degree - g.degree() for g in G]) + 1 + +# S = [ ] + +# F.sort() +# for i in range(len(F)): +# g, m = F[i] + +# if g.degree() == 1: +# # Just use kernel -- much easier. +# B = A.__copy__() +# for k from 0 <= k < A.nrows(): +# B[k,k] += g[0] +# if m > 1 and not is_diagonalizable: +# B = B**m +# W = B.change_ring(QQ).kernel() +# for b in W.basis(): +# E.append((W.span(b), g)) +# continue + +# # General case, i.e., deg(g) > 1: +# W = None +# while True: + +# # Compute the complementary factor of the charpoly. +# h = minpoly // g +# v = h.list() + +# while len(S) < m: +# t = verbose('%s-spinning %s-th random vector'%(num_iterates, len(S)), +# level=2, caller_name='simple decomp') +# S.append(A.iterates(V.random_element(x=-10,y=10), num_iterates)) +# verbose('done spinning', level=2, t=t, caller_name='simple decomp') + +# for j in range(len(S)): +# # Compute one element of the kernel of g(A). +# t = verbose('compute element of kernel of g(A), for g of degree %s'%g.degree(),level=2, +# caller_name='simple decomp') +# w = S[j].linear_combination_of_rows(h.list()) +# t = verbose('done computing element of kernel of g(A)', t=t,level=2, caller_name='simple decomp') + +# # Get the rest of the kernel. +# t = verbose('fill out rest of kernel',level=2, caller_name='simple decomp') +# if W is None: +# W = A.iterates(w, g.degree()) +# else: +# W = W.stack(A.iterates(w, g.degree())) +# t = verbose('finished filling out more of kernel',level=2, t=t, caller_name='simple decomp') + +# if W.rank() == m * g.degree(): +# W = W.change_ring(QQ) +# t = verbose('now computing row space', level=2, caller_name='simple decomp') +# W.echelonize(algorithm = echelon_algorithm, **kwds) +# E.append((W.row_space(), m==1)) +# verbose('computed row space', level=2,t=t, caller_name='simple decomp') +# break +# else: +# verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)'%( +# W.rank(), m*g.degree()), level=2, caller_name='simple decomp') +# j += 1 +# if j > 3*m: +# raise RuntimeError("likely bug in decomposition") +# # end if +# #end while +# #end for +# return E def _lift_crt_rr(self, res, mm): cdef Integer m cdef Matrix_integer_dense ZA cdef Matrix_rational_dense QA cdef Py_ssize_t i, j - cdef mpz_t* Z_row - cdef mpq_t* Q_row cdef mpz_t tmp cdef mpq_t tmp2 mpz_init(tmp) @@ -2479,7 +2466,6 @@ cdef class Matrix_rational_dense(Matrix_dense): mpq_clear(tmp) - def rank(self, algorithm=None): """ Return the rank of this matrix. @@ -2627,12 +2613,12 @@ cdef class Matrix_rational_dense(Matrix_dense): ans = Matrix_rational_dense.__new__(Matrix_rational_dense, parent, None, None, None) cdef Py_ssize_t i,j - cdef Py_ssize_t ri,rj # reversed i and j + cdef Py_ssize_t ri,rj # reversed i and j sig_on() ri = self._nrows for i in range(self._nrows): rj = self._ncols - ri = ri - 1 + ri = ri - 1 for j in range(self._ncols): rj = rj - 1 fmpq_set(fmpq_mat_entry(ans._matrix, rj, ri), @@ -2642,7 +2628,7 @@ cdef class Matrix_rational_dense(Matrix_dense): if self._subdivisions is not None: row_divs, col_divs = self.subdivisions() ans.subdivide([self._ncols - t for t in reversed(col_divs)], - [self._nrows - t for t in reversed(row_divs)]) + [self._nrows - t for t in reversed(row_divs)]) return ans def set_row_to_multiple_of_row(self, Py_ssize_t i, Py_ssize_t j, s): @@ -2723,9 +2709,8 @@ cdef class Matrix_rational_dense(Matrix_dense): fmpq_neg(entry, entry) l += 1 - - def _add_col_j_of_A_to_col_i_of_self(self, - Py_ssize_t i, Matrix_rational_dense A, Py_ssize_t j): + def _add_col_j_of_A_to_col_i_of_self(self, Py_ssize_t i, + Matrix_rational_dense A, Py_ssize_t j): """ Unsafe technical function that very quickly adds the j-th column of A to the i-th column of self. @@ -2740,10 +2725,9 @@ cdef class Matrix_rational_dense(Matrix_dense): fmpq_mat_entry(self._matrix, r, i), fmpq_mat_entry(A._matrix, r, j)) - - ################################################# - # Methods using PARI library # - ################################################# + # ############################################### + # Methods using PARI library + # ############################################### def __pari__(self): """ @@ -2851,7 +2835,6 @@ cdef class Matrix_rational_dense(Matrix_dense): clear_stack() return A - def row(self, Py_ssize_t i, from_list=False): """ Return the i-th row of this matrix as a dense vector. @@ -2940,9 +2923,9 @@ cdef class Matrix_rational_dense(Matrix_dense): fmpq_get_mpq(v._entries[j], fmpq_mat_entry(self._matrix, j, i)) return v - ################################################ + # ############################################### # LLL - ################################################ + # ############################################### def LLL(self, *args, **kwargs): """ diff --git a/src/sage/matrix/matrix_rational_sparse.pyx b/src/sage/matrix/matrix_rational_sparse.pyx index c7cd866b578..06b9689e849 100644 --- a/src/sage/matrix/matrix_rational_sparse.pyx +++ b/src/sage/matrix/matrix_rational_sparse.pyx @@ -54,7 +54,6 @@ import sage.matrix.matrix_space from .matrix_integer_sparse cimport Matrix_integer_sparse from .matrix_rational_dense cimport Matrix_rational_dense -from sage.misc.verbose import verbose cdef class Matrix_rational_sparse(Matrix_sparse): def __cinit__(self): @@ -269,7 +268,6 @@ cdef class Matrix_rational_sparse(Matrix_sparse): mpq_clear(s) return ans - ######################################################################## # def _pickle(self): # def _unpickle(self, data, int version): # use version >= 0 @@ -282,20 +280,21 @@ cdef class Matrix_rational_sparse(Matrix_sparse): # def _multiply_classical(left, matrix.Matrix _right): # def _list(self): -# TODO -## cpdef _lmul_(self, Element right): -## """ -## EXAMPLES:: -## -## sage: a = matrix(QQ,2,range(6)) -## sage: (3/4) * a -## [ 0 3/4 3/2] -## [ 9/4 3 15/4] -## """ + # TODO + ## cpdef _lmul_(self, Element right): + ## """ + ## EXAMPLES:: + ## + ## sage: a = matrix(QQ,2,range(6)) + ## sage: (3/4) * a + ## [ 0 3/4 3/2] + ## [ 9/4 3 15/4] + ## """ def _dict(self): """ Unsafe version of the dict method, mainly for internal use. + This may return the dict of elements, but as an *unsafe* reference to the underlying dict of the object. It might be dangerous if you change entries of the returned dict. @@ -304,17 +303,16 @@ cdef class Matrix_rational_sparse(Matrix_sparse): if d is not None: return d - cdef Py_ssize_t i, j, k + cdef Py_ssize_t i, j d = {} - for i from 0 <= i < self._nrows: - for j from 0 <= j < self._matrix[i].num_nonzero: + for i in range(self._nrows): + for j in range(self._matrix[i].num_nonzero): x = Rational() mpq_set((<Rational>x).value, self._matrix[i].entries[j]) - d[(int(i),int(self._matrix[i].positions[j]))] = x + d[(int(i), int(self._matrix[i].positions[j]))] = x self.cache('dict', d) return d - ######################################################################## # LEVEL 3 functionality (Optional) # * cdef _sub_ @@ -326,7 +324,7 @@ cdef class Matrix_rational_sparse(Matrix_sparse): def _nonzero_positions_by_row(self, copy=True): """ - Returns the list of pairs (i,j) such that self[i,j] != 0. + Return the list of pairs (i,j) such that self[i,j] != 0. It is safe to change the resulting list (unless you give the option copy=False). @@ -398,25 +396,23 @@ cdef class Matrix_rational_sparse(Matrix_sparse): return 0 cdef int mpz_denom(self, mpz_t d) except -1: - mpz_set_si(d,1) + mpz_set_si(d, 1) cdef Py_ssize_t i, j - cdef mpq_vector *v sig_on() - for i from 0 <= i < self._nrows: - for j from 0 <= j < self._matrix[i].num_nonzero: + for i in range(self._nrows): + for j in range(self._matrix[i].num_nonzero): mpz_lcm(d, d, mpq_denref(self._matrix[i].entries[j])) sig_off() return 0 - def denominator(self): """ Return the denominator of this matrix. OUTPUT: - -- Sage Integer + - Sage Integer EXAMPLES:: diff --git a/src/sage/matrix/matrix_real_double_dense.pyx b/src/sage/matrix/matrix_real_double_dense.pyx index 39bb0fcdbab..eeff7658041 100644 --- a/src/sage/matrix/matrix_real_double_dense.pyx +++ b/src/sage/matrix/matrix_real_double_dense.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - numpy """ Dense matrices over the Real Double Field using NumPy diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 73c5b445de7..6aab58352be 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -19,7 +19,7 @@ sage: matrix(RR,2,2,sparse=True) [0.000000000000000 0.000000000000000] [0.000000000000000 0.000000000000000] - sage: matrix(GF(11),2,2,sparse=True) + sage: matrix(GF(11), 2, 2, sparse=True) [0 0] [0 0] """ @@ -39,11 +39,11 @@ # Sage matrix imports see :trac:`34283` # Sage imports -import sage.structure.coerce +import sage.structure.coerce_actions from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation import sage.rings.integer as integer -import sage.rings.finite_rings.finite_field_constructor +from sage.rings.finite_rings.finite_field_base import FiniteField import sage.misc.latex as latex import sage.modules.free_module @@ -114,16 +114,17 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): sage: get_matrix_class(ZZ, 3, 3, False, 'flint') <class 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'> - sage: get_matrix_class(ZZ, 3, 3, False, 'gap') + sage: get_matrix_class(ZZ, 3, 3, False, 'gap') # needs sage.modules <class 'sage.matrix.matrix_gap.Matrix_gap'> sage: get_matrix_class(ZZ, 3, 3, False, 'generic') <class 'sage.matrix.matrix_generic_dense.Matrix_generic_dense'> - sage: get_matrix_class(GF(2^15), 3, 3, False, None) + sage: get_matrix_class(GF(2^15), 3, 3, False, None) # needs sage.rings.finite_rings <class 'sage.matrix.matrix_gf2e_dense.Matrix_gf2e_dense'> - sage: get_matrix_class(GF(2^17), 3, 3, False, None) + sage: get_matrix_class(GF(2^17), 3, 3, False, None) # needs sage.rings.finite_rings <class 'sage.matrix.matrix_generic_dense.Matrix_generic_dense'> + sage: # needs sage.rings.finite_rings sage: get_matrix_class(GF(2), 2, 2, False, 'm4ri') <class 'sage.matrix.matrix_mod2_dense.Matrix_mod2_dense'> sage: get_matrix_class(GF(4), 2, 2, False, 'm4ri') @@ -133,12 +134,12 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): sage: get_matrix_class(GF(7), 2, 2, False, 'linbox-double') <class 'sage.matrix.matrix_modn_dense_double.Matrix_modn_dense_double'> - sage: get_matrix_class(RDF, 2, 2, False, 'numpy') + sage: get_matrix_class(RDF, 2, 2, False, 'numpy') # needs numpy <class 'sage.matrix.matrix_real_double_dense.Matrix_real_double_dense'> - sage: get_matrix_class(CDF, 2, 3, False, 'numpy') + sage: get_matrix_class(CDF, 2, 3, False, 'numpy') # needs numpy <class 'sage.matrix.matrix_complex_double_dense.Matrix_complex_double_dense'> - sage: get_matrix_class(GF(25,'x'), 4, 4, False, 'meataxe') # optional - meataxe + sage: get_matrix_class(GF(25,'x'), 4, 4, False, 'meataxe') # optional - meataxe, needs sage.rings.finite_rings <class 'sage.matrix.matrix_gfpn_dense.Matrix_gfpn_dense'> sage: get_matrix_class(IntegerModRing(3), 4, 4, False, 'meataxe') # optional - meataxe <class 'sage.matrix.matrix_gfpn_dense.Matrix_gfpn_dense'> @@ -146,7 +147,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): Traceback (most recent call last): ... ValueError: 'meataxe' matrix can only deal with finite fields of order < 256 - sage: get_matrix_class(GF(next_prime(255)), 4, 4, False, 'meataxe') + sage: get_matrix_class(GF(next_prime(255)), 4, 4, False, 'meataxe') # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: 'meataxe' matrix can only deal with finite fields of order < 256 @@ -166,21 +167,23 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): sage: get_matrix_class(Zmod(2**30), 2, 2, False, 'linbox-double') Traceback (most recent call last): ... - ValueError: 'linbox-double' matrices can only deal with order < 8388608 + ValueError: 'linbox-double' matrices can only deal with order < 94906266 - sage: type(matrix(SR, 2, 2, 0)) + sage: type(matrix(SR, 2, 2, 0)) # needs sage.symbolic <class 'sage.matrix.matrix_symbolic_dense.Matrix_symbolic_dense'> - sage: type(matrix(GF(7), 2, range(4))) + sage: type(matrix(SR, 2, 2, 0, sparse=True)) # needs sage.symbolic + <class 'sage.matrix.matrix_symbolic_sparse.Matrix_symbolic_sparse'> + sage: type(matrix(GF(7), 2, range(4))) # needs sage.rings.finite_rings <class 'sage.matrix.matrix_modn_dense_float.Matrix_modn_dense_float'> - sage: type(matrix(GF(16007), 2, range(4))) + sage: type(matrix(GF(16007), 2, range(4))) # needs sage.rings.finite_rings <class 'sage.matrix.matrix_modn_dense_double.Matrix_modn_dense_double'> - sage: type(matrix(CBF, 2, range(4))) + sage: type(matrix(CBF, 2, range(4))) # needs sage.libs.flint <class 'sage.matrix.matrix_complex_ball_dense.Matrix_complex_ball_dense'> - sage: type(matrix(GF(2), 2, range(4))) + sage: type(matrix(GF(2), 2, range(4))) # needs sage.rings.finite_rings <class 'sage.matrix.matrix_mod2_dense.Matrix_mod2_dense'> - sage: type(matrix(GF(64,'z'), 2, range(4))) + sage: type(matrix(GF(64, 'z'), 2, range(4))) # needs sage.rings.finite_rings <class 'sage.matrix.matrix_gf2e_dense.Matrix_gf2e_dense'> - sage: type(matrix(GF(125,'z'), 2, range(4))) # optional - meataxe + sage: type(matrix(GF(125, 'z'), 2, range(4))) # optional - meataxe # needs sage.rings.finite_rings <class 'sage.matrix.matrix_gfpn_dense.Matrix_gfpn_dense'> """ @@ -223,7 +226,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): else: return matrix_complex_double_dense.Matrix_complex_double_dense - elif sage.rings.finite_rings.finite_field_constructor.is_FiniteField(R): + elif isinstance(R, FiniteField): if R.order() == 2: try: from . import matrix_mod2_dense @@ -248,11 +251,15 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): pass if isinstance(R, sage.rings.abc.IntegerModRing): - from . import matrix_modn_dense_double, matrix_modn_dense_float - if R.order() < matrix_modn_dense_float.MAX_MODULUS: - return matrix_modn_dense_float.Matrix_modn_dense_float - if R.order() < matrix_modn_dense_double.MAX_MODULUS: - return matrix_modn_dense_double.Matrix_modn_dense_double + try: + from . import matrix_modn_dense_double, matrix_modn_dense_float + except ImportError: + pass + else: + if R.order() < matrix_modn_dense_float.MAX_MODULUS: + return matrix_modn_dense_float.Matrix_modn_dense_float + if R.order() < matrix_modn_dense_double.MAX_MODULUS: + return matrix_modn_dense_double.Matrix_modn_dense_double if isinstance(R, sage.rings.abc.NumberField_cyclotomic): from . import matrix_cyclo_dense @@ -397,9 +404,21 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): else: return matrix_integer_sparse.Matrix_integer_sparse - if R is sage.rings.real_double.RDF or R is sage.rings.complex_double.CDF: + if isinstance(R, (sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): from . import matrix_double_sparse return matrix_double_sparse.Matrix_double_sparse + try: + from sage.symbolic.ring import SR + except ImportError: + pass + else: + if R is SR: + try: + from . import matrix_symbolic_sparse + except ImportError: + pass + else: + return matrix_symbolic_sparse.Matrix_symbolic_sparse # the fallback from sage.matrix.matrix_generic_sparse import Matrix_generic_sparse @@ -477,28 +496,29 @@ class MatrixSpace(UniqueRepresentation, Parent): Check that different implementations play together as expected:: - sage: M1 = MatrixSpace(ZZ, 2, implementation='flint') + sage: M1 = MatrixSpace(ZZ, 2, implementation='flint') # needs sage.libs.flint sage: M2 = MatrixSpace(ZZ, 2, implementation='generic') - sage: type(M1(range(4))) + sage: type(M1(range(4))) # needs sage.libs.flint <class 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'> sage: type(M2(range(4))) <class 'sage.matrix.matrix_generic_dense.Matrix_generic_dense'> - sage: M1(M2.an_element()) + sage: M1(M2.an_element()) # needs sage.libs.flint [ 0 1] [-1 2] - sage: M2(M1.an_element()) + sage: M2(M1.an_element()) # needs sage.libs.flint [ 0 1] [-1 2] - sage: all(((A.get_action(B) is not None) == (A is B)) for A in [M1,M2] for B in [M1,M2]) + sage: all((A.get_action(B) is not None) == (A is B) # needs sage.libs.flint + ....: for A in [M1, M2] for B in [M1, M2]) True Check that libgap matrices over finite fields are working properly:: - sage: M2 = MatrixSpace(GF(2), 5, implementation='gap') - sage: M2.one() + sage: M2 = MatrixSpace(GF(2), 5, implementation='gap') # needs sage.libs.gap sage.rings.finite_rings + sage: M2.one() # needs sage.libs.gap sage.rings.finite_rings [1 0 0 0 0] [0 1 0 0 0] [0 0 1 0 0] @@ -506,7 +526,7 @@ class MatrixSpace(UniqueRepresentation, Parent): [0 0 0 0 1] sage: m = M2.random_element() sage: M1 = MatrixSpace(GF(2), 5) - sage: M1(m * m) == M1(m) * M1(m) + sage: M1(m * m) == M1(m) * M1(m) # needs sage.libs.gap sage.rings.finite_rings True """ @@ -521,16 +541,18 @@ def __classcall__(cls, base_ring, nrows, ncols=None, sparse=False, implementatio sage: M1 = MatrixSpace(QQ, 2) sage: M2 = MatrixSpace(QQ, 2) - sage: M3 = MatrixSpace(QQ, 2, implementation='flint') - sage: M1 is M2 and M1 is M3 + sage: M1 is M2 + True + sage: M3 = MatrixSpace(QQ, 2, implementation='flint') # needs sage.libs.flint + sage: M1 is M3 # needs sage.libs.flint True :: - sage: M = MatrixSpace(ZZ, 10, implementation="flint") - sage: M + sage: M = MatrixSpace(ZZ, 10, implementation="flint") # needs sage.libs.flint + sage: M # needs sage.libs.flint Full MatrixSpace of 10 by 10 dense matrices over Integer Ring - sage: loads(M.dumps()) is M + sage: loads(M.dumps()) is M # needs sage.libs.flint True sage: MatrixSpace(ZZ, 10, implementation="foobar") @@ -603,7 +625,8 @@ def __init__(self, base_ring, nrows, ncols, sparse, implementation): - ``linbox-float`` - for integer mod rings up to `2^8 = 256` - - ``linbox-double`` - for integer mod rings up to `2^23 = 8388608` + - ``linbox-double`` - for integer mod rings up to + `floor(2^26*sqrt(2) + 1/2) = 94906266` - ``numpy`` - for real and complex floating point numbers @@ -660,6 +683,8 @@ def __init__(self, base_ring, nrows, ncols, sparse, implementation): 200 x 1 dense matrix over Rational Field (use the '.str()' method to see the entries) sage: A = MatrixSpace(RDF,1000,1000).random_element() sage: B = MatrixSpace(RDF,1000,1000).random_element() + + sage: # needs numpy (otherwise timeout) sage: C = A * B We check that :trac:`18186` is fixed:: @@ -679,7 +704,8 @@ def __init__(self, base_ring, nrows, ncols, sparse, implementation): self.__ncols = ncols self.__is_sparse = sparse - from sage.categories.all import Modules, Algebras + from sage.categories.modules import Modules + from sage.categories.algebras import Algebras if nrows == ncols: category = Algebras(base_ring.category()) else: @@ -732,7 +758,7 @@ def characteristic(self): sage: MatrixSpace(ZZ, 2).characteristic() 0 - sage: MatrixSpace(GF(9), 0).characteristic() + sage: MatrixSpace(GF(9), 0).characteristic() # needs sage.rings.finite_rings 3 """ return self.base_ring().characteristic() @@ -779,15 +805,15 @@ def _copy_zero(self): EXAMPLES:: - sage: MS = MatrixSpace(GF(2),20,20) - sage: MS._copy_zero + sage: MS = MatrixSpace(GF(2), 20, 20) + sage: MS._copy_zero # needs sage.rings.finite_rings False - sage: MS = MatrixSpace(GF(3),20,20) - sage: MS._copy_zero + sage: MS = MatrixSpace(GF(3), 20, 20) + sage: MS._copy_zero # needs sage.rings.finite_rings True - sage: MS = MatrixSpace(GF(3),200,200) - sage: MS._copy_zero + sage: MS = MatrixSpace(GF(3), 200, 200) + sage: MS._copy_zero # needs sage.rings.finite_rings False sage: MS = MatrixSpace(ZZ,200,200) @@ -822,9 +848,10 @@ def _element_constructor_(self, entries, **kwds): EXAMPLES:: - sage: k = GF(7); G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]) + sage: k = GF(7) + sage: G = MatrixGroup([matrix(k, 2, [1,1,0,1]), matrix(k, 2, [1,0,0,2])]) sage: g = G.0 - sage: MatrixSpace(k,2)(g) + sage: MatrixSpace(k, 2)(g) [1 1] [0 1] @@ -854,7 +881,7 @@ def _element_constructor_(self, entries, **kwds): [3 4] sage: MS = MatrixSpace(ZZ, 2) - sage: g = Gamma0(5)([1,1,0,1]) + sage: g = Gamma0(5)([1,1,0,1]) # needs sage.modular sage: MS(g) [1 1] [0 1] @@ -874,14 +901,17 @@ def _element_constructor_(self, entries, **kwds): Ensure that :trac:`12020` is fixed:: + sage: rings = [ZZ, QQ, RealField(100), ComplexField(100), RDF, CDF] + sage: rings.append(PolynomialRing(QQ, 'x')) + sage: rings.append(PolynomialRing(CC, 2, 'x')) + sage: rings.append(SR) # needs sage.symbolic + sage: rings.extend([GF(2), GF(11), GF(2^8,'a'), GF(3^19,'a')]) # needs sage.rings.finite_rings sage: x = polygen(QQ) - sage: for R in [ZZ, QQ, RealField(100), ComplexField(100), RDF, CDF, - ....: SR, GF(2), GF(11), GF(2^8,'a'), GF(3^19,'a'), - ....: NumberField(x^3+2,'a'), CyclotomicField(4), - ....: PolynomialRing(QQ,'x'), PolynomialRing(CC,2,'x')]: - ....: A = MatrixSpace(R,60,30,sparse=False)(0) + sage: rings.extend([NumberField(x^3 + 2, 'a'), CyclotomicField(4)]) # needs sage.rings.number_field + sage: for R in rings: + ....: A = MatrixSpace(R, 60, 30, sparse=False)(0) ....: B = A.augment(A) - ....: A = MatrixSpace(R,60,30,sparse=True)(0) + ....: A = MatrixSpace(R, 60, 30, sparse=True)(0) ....: B = A.augment(A) Check that :trac:`13012` is fixed:: @@ -942,8 +972,9 @@ def change_ring(self, R): EXAMPLES:: - sage: Mat(QQ,3,5).change_ring(GF(7)) - Full MatrixSpace of 3 by 5 dense matrices over Finite Field of size 7 + sage: Mat(QQ, 3, 5).change_ring(GF(7)) + Full MatrixSpace of 3 by 5 dense matrices + over Finite Field of size 7 """ try: return self.__change_ring[R] @@ -967,9 +998,9 @@ def base_extend(self, R): EXAMPLES:: - sage: Mat(ZZ,3,5).base_extend(QQ) + sage: Mat(ZZ, 3, 5).base_extend(QQ) Full MatrixSpace of 3 by 5 dense matrices over Rational Field - sage: Mat(QQ,3,5).base_extend(GF(7)) + sage: Mat(QQ, 3, 5).base_extend(GF(7)) Traceback (most recent call last): ... TypeError: no base extension defined @@ -1053,7 +1084,7 @@ def _get_action_(self, S, op, self_on_left): return matrix_action.MatrixPolymapAction(self, S) else: # action of base ring - return sage.structure.coerce.RightModuleAction(S, self) + return sage.structure.coerce_actions.RightModuleAction(S, self) else: if is_MatrixSpace(S): # matrix multiplications @@ -1064,7 +1095,7 @@ def _get_action_(self, S, op, self_on_left): return matrix_action.PolymapMatrixAction(self, S) else: # action of base ring - return sage.structure.coerce.LeftModuleAction(S, self) + return sage.structure.coerce_actions.LeftModuleAction(S, self) except TypeError: return None @@ -1128,8 +1159,8 @@ def _coerce_map_from_(self, S): Coercion map: From: General Linear Group of degree 2 over Finite Field of size 3 To: Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 3 - sage: MS.coerce_map_from(GL(2, 2)) - sage: MS.coerce_map_from(Gamma1(5)) + sage: MS.coerce_map_from(GL(2, 2)) # needs sage.rings.finite_rings + sage: MS.coerce_map_from(Gamma1(5)) # needs sage.rings.finite_rings Coercion map: From: Congruence Subgroup Gamma1(5) To: Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 3 @@ -1153,7 +1184,7 @@ def _coerce_map_from_(self, S): sage: m = R([[1, 0], [0, 1]]) sage: m in G True - sage: m in list(G) + sage: m in list(G) # needs sage.libs.gap True sage: m == G(m) True @@ -1170,11 +1201,11 @@ def _coerce_map_from_(self, S): Verify which coercion maps are allowed (this should form a poset):: - sage: M1 = MatrixSpace(ZZ, 3, implementation='flint') - sage: M2 = MatrixSpace(ZZ, 3, implementation='generic') - sage: M3 = MatrixSpace(ZZ, 3, implementation='gap') - sage: M4 = MatrixSpace(ZZ, 3, sparse=True) - sage: S = [M1, M2, M3, M4] + sage: S = [] + sage: S += [MatrixSpace(ZZ, 3, implementation='flint')] # needs sage.libs.flint + sage: S += [MatrixSpace(ZZ, 3, implementation='generic')] + sage: S += [MatrixSpace(ZZ, 3, implementation='gap')] # needs sage.libs.gap + sage: S += [MatrixSpace(ZZ, 3, sparse=True)] sage: mult = '' sage: for A in S: ....: for B in S: @@ -1183,7 +1214,7 @@ def _coerce_map_from_(self, S): ....: else: ....: mult += ' ' ....: mult += '\n' - sage: print(mult) + sage: print(mult) # needs sage.libs.flint sage.libs.gap XXXX X X XX @@ -1229,12 +1260,24 @@ def _coerce_map_from_(self, S): pass else: MS = meth_matrix_space() - from sage.groups.matrix_gps.matrix_group import is_MatrixGroup - from sage.modular.arithgroup.arithgroup_generic import is_ArithmeticSubgroup - if is_MatrixGroup(S) or is_ArithmeticSubgroup(S): - return self.has_coerce_map_from(MS) + + try: + from sage.groups.matrix_gps.matrix_group import is_MatrixGroup + except ImportError: + pass else: - return False + if is_MatrixGroup(S): + return self.has_coerce_map_from(MS) + + try: + from sage.modular.arithgroup.arithgroup_generic import is_ArithmeticSubgroup + except ImportError: + pass + else: + if is_ArithmeticSubgroup(S): + return self.has_coerce_map_from(MS) + + return False # The parent is not matrix-like: coerce via base ring return (self.nrows() == self.ncols()) and self._coerce_map_via([B], S) @@ -1251,7 +1294,7 @@ def _repr_(self): sage: MS Full MatrixSpace of 2 by 4 sparse matrices over Integer Ring - sage: MatrixSpace(ZZ, 2, implementation='flint') + sage: MatrixSpace(ZZ, 2, implementation='flint') # needs sage.libs.flint Full MatrixSpace of 2 by 2 dense matrices over Integer Ring sage: MatrixSpace(ZZ, 2, implementation='generic') Full MatrixSpace of 2 by 2 dense matrices over Integer Ring (using Matrix_generic_dense) @@ -1300,20 +1343,20 @@ def _latex_(self): def __len__(self): """ Return number of elements of this matrix space if it fits in - an int; raise a TypeError if there are infinitely many - elements, and raise an OverflowError if there are finitely + an int; raise a :class:`TypeError` if there are infinitely many + elements, and raise an :class:`OverflowError` if there are finitely many but more than the size of an int. EXAMPLES:: - sage: len(MatrixSpace(GF(3),3,2)) + sage: len(MatrixSpace(GF(3), 3, 2)) 729 - sage: len(MatrixSpace(GF(3),2,3)) + sage: len(MatrixSpace(GF(3), 2, 3)) 729 sage: 3^(2*3) 729 - sage: len(MatrixSpace(GF(2003),3,2)) + sage: len(MatrixSpace(GF(2003), 3, 2)) # needs sage.rings.finite_rings Traceback (most recent call last): ... OverflowError: cannot fit 'int' into an index-sized integer @@ -1339,7 +1382,7 @@ def __iter__(self): :: - sage: list( GF(5) ) + sage: list(GF(5)) [0, 1, 2, 3, 4] sage: MS = MatrixSpace(GF(5), 2, 2) sage: l = list(MS) @@ -1400,7 +1443,7 @@ def __iter__(self): Some more examples:: - sage: MS = MatrixSpace(GF(2),2) + sage: MS = MatrixSpace(GF(2), 2) sage: a = list(MS) sage: len(a) 16 @@ -1458,7 +1501,7 @@ def __iter__(self): :: - sage: MS = MatrixSpace(GF(2),2, 3) + sage: MS = MatrixSpace(GF(2), 2, 3) sage: a = list(MS) sage: len(a) 64 @@ -1484,11 +1527,11 @@ def __iter__(self): :: - sage: list( MatrixSpace(GF(2), 2, 0) ) + sage: list(MatrixSpace(GF(2), 2, 0)) [[]] - sage: list( MatrixSpace(GF(2), 0, 2) ) + sage: list(MatrixSpace(GF(2), 0, 2)) [[]] - sage: list( MatrixSpace(GF(2), 0, 0) ) + sage: list(MatrixSpace(GF(2), 0, 0)) [[]] If the base ring does not support iteration (for example, with the @@ -1560,7 +1603,9 @@ def __getitem__(self, x): sage: MS = MatrixSpace(GF(3), 2, 2) sage: MS['x'] - Univariate Polynomial Ring in x over Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 3 + Univariate Polynomial Ring in x + over Full MatrixSpace of 2 by 2 dense matrices + over Finite Field of size 3 sage: MS[0] [0 0] [0 0] @@ -1765,10 +1810,10 @@ def identity_matrix(self): Check different implementations:: - sage: M1 = MatrixSpace(ZZ, 2, implementation='flint') + sage: M1 = MatrixSpace(ZZ, 2, implementation='flint') # needs sage.libs.flint sage: M2 = MatrixSpace(ZZ, 2, implementation='generic') - sage: type(M1.identity_matrix()) + sage: type(M1.identity_matrix()) # needs sage.libs.flint <class 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'> sage: type(M2.identity_matrix()) <class 'sage.matrix.matrix_generic_dense.Matrix_generic_dense'> @@ -1823,10 +1868,10 @@ def diagonal_matrix(self, entries): Check different implementations:: - sage: M1 = MatrixSpace(ZZ, 2, implementation='flint') + sage: M1 = MatrixSpace(ZZ, 2, implementation='flint') # needs sage.libs.flint sage: M2 = MatrixSpace(ZZ, 2, implementation='generic') - sage: type(M1.diagonal_matrix([1, 2])) + sage: type(M1.diagonal_matrix([1, 2])) # needs sage.libs.flint <class 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'> sage: type(M2.diagonal_matrix([1, 2])) <class 'sage.matrix.matrix_generic_dense.Matrix_generic_dense'> @@ -1859,9 +1904,9 @@ def is_sparse(self): EXAMPLES:: - sage: Mat(GF(2011),10000).is_sparse() + sage: Mat(GF(2011), 10000).is_sparse() # needs sage.rings.finite_rings False - sage: Mat(GF(2011),10000,sparse=True).is_sparse() + sage: Mat(GF(2011), 10000, sparse=True).is_sparse() # needs sage.rings.finite_rings True """ return self.__is_sparse @@ -1888,7 +1933,7 @@ def gen(self, n): EXAMPLES:: - sage: M = Mat(GF(7),10000,5); M.ngens() + sage: M = Mat(GF(7), 10000, 5); M.ngens() 50000 sage: a = M.10 sage: a[:4] @@ -1915,7 +1960,7 @@ def zero_matrix(self): EXAMPLES:: - sage: z = MatrixSpace(GF(7),2,4).zero_matrix(); z + sage: z = MatrixSpace(GF(7), 2, 4).zero_matrix(); z [0 0 0 0] [0 0 0 0] sage: z.is_mutable() @@ -1949,7 +1994,7 @@ def ngens(self): EXAMPLES:: - sage: M = Mat(GF(7),100,200); M.ngens() + sage: M = Mat(GF(7), 100, 200); M.ngens() 20000 """ return self.dimension() @@ -2018,9 +2063,10 @@ def matrix(self, x=None, **kwds): sage: MS([[1],[2]]) [1] [2] - sage: MS = MatrixSpace(CC,2,1) - sage: F = NumberField(x^2+1, name='x') - sage: MS([F(1),F(0)]) + sage: MS = MatrixSpace(CC, 2, 1) + sage: x = polygen(ZZ, 'x') + sage: F = NumberField(x^2 + 1, name='x') # needs sage.rings.number_field + sage: MS([F(1), F(0)]) # needs sage.rings.number_field [ 1.00000000000000] [0.000000000000000] @@ -2043,19 +2089,20 @@ def matrix(self, x=None, **kwds): Check that :trac:`13302` is fixed:: - sage: MatrixSpace(Qp(3),1,1)([Qp(3).zero()]) + sage: MatrixSpace(Qp(3), 1,1)([Qp(3).zero()]) # needs sage.rings.padics [0] - sage: MatrixSpace(Qp(3),1,1)([Qp(3)(4/3)]) + sage: MatrixSpace(Qp(3), 1,1)([Qp(3)(4/3)]) # needs sage.rings.padics [3^-1 + 1 + O(3^19)] One-rowed matrices over combinatorial free modules used to break the constructor (:trac:`17124`). Check that this is fixed:: + sage: # needs sage.combinat sage: Sym = SymmetricFunctions(ZZ) sage: h = Sym.h() - sage: MatrixSpace(h,1,1)([h[1]]) + sage: MatrixSpace(h, 1,1)([h[1]]) [h[1]] - sage: MatrixSpace(h,2,1)([h[1], h[2]]) + sage: MatrixSpace(h, 2,1)([h[1], h[2]]) [h[1]] [h[2]] @@ -2064,7 +2111,7 @@ def matrix(self, x=None, **kwds): sage: m = identity_matrix(GF(2), 2000, sparse=True) sage: MS = MatrixSpace(GF(2), 2000, sparse=False) - sage: md = MS(m) # used to be slow + sage: md = MS(m) sage: md.parent() is MS True """ @@ -2078,7 +2125,7 @@ def matrix_space(self, nrows=None, ncols=None, sparse=False): EXAMPLES:: - sage: M = Mat(GF(7),100,200) + sage: M = Mat(GF(7), 100, 200) sage: M.matrix_space(5000) Full MatrixSpace of 5000 by 200 dense matrices over Finite Field of size 7 sage: M.matrix_space(ncols=5000) @@ -2143,7 +2190,7 @@ def column_space(self): EXAMPLES:: - sage: M = Mat(GF(9,'a'),20,5,sparse=True); M.column_space() + sage: M = Mat(GF(9,'a'), 20, 5, sparse=True); M.column_space() # needs sage.rings.finite_rings Sparse vector space of dimension 20 over Finite Field in a of size 3^2 """ try: @@ -2200,10 +2247,10 @@ def random_element(self, density=None, *args, **kwds): sage: TestSuite(M).run() sage: M = Mat(QQ, 3, sparse=True).random_element() - sage: TestSuite(M).run() + sage: TestSuite(M).run() # needs sage.libs.pari - sage: M = Mat(GF(9,'a'), 3, sparse=True).random_element() - sage: TestSuite(M).run() + sage: M = Mat(GF(9,'a'), 3, sparse=True).random_element() # needs sage.rings.finite_rings + sage: TestSuite(M).run() # needs sage.rings.finite_rings """ Z = self.zero_matrix().__copy__() if density is None: @@ -2300,8 +2347,8 @@ def some_elements(self): [ 1/2 -1/2 2] [1 0 0] [0 1 0] [0 0 1] [0 0 0] [0 0 0] [0 0 0] [ -2 0 1], [0 0 0], [0 0 0], [0 0 0], [1 0 0], [0 1 0], [0 0 1] ) - sage: M = MatrixSpace(SR, 2, 2) - sage: tuple(M.some_elements()) + sage: M = MatrixSpace(SR, 2, 2) # needs sage.symbolic + sage: tuple(M.some_elements()) # needs sage.symbolic ( [some_variable some_variable] [1 0] [0 1] [0 0] [0 0] [some_variable some_variable], [0 0], [0 0], [1 0], [0 1] @@ -2336,9 +2383,9 @@ def _polymake_init_(self): EXAMPLES:: - sage: polymake(MatrixSpace(QQ,3)) # optional - jupymake + sage: polymake(MatrixSpace(QQ, 3)) # optional - jupymake Matrix<Rational> - sage: polymake(MatrixSpace(QuadraticField(5),3)) # optional - jupymake + sage: polymake(MatrixSpace(QuadraticField(5), 3)) # optional - jupymake, needs sage.rings.number_field Matrix<QuadraticExtension> """ from sage.interfaces.polymake import polymake @@ -2452,14 +2499,14 @@ def _test_trivial_matrices_inverse(ring, sparse=True, implementation=None, check sage: tinv(GF(11), sparse=False) sage: tinv(GF(2), sparse=True) sage: tinv(GF(2), sparse=False) - sage: tinv(SR, sparse=True) - sage: tinv(SR, sparse=False) + sage: tinv(SR, sparse=True) # needs sage.symbolic + sage: tinv(SR, sparse=False) # needs sage.symbolic sage: tinv(RDF, sparse=True) sage: tinv(RDF, sparse=False) sage: tinv(CDF, sparse=True) sage: tinv(CDF, sparse=False) - sage: tinv(CyclotomicField(7), sparse=True) - sage: tinv(CyclotomicField(7), sparse=False) + sage: tinv(CyclotomicField(7), sparse=True) # needs sage.rings.number_field + sage: tinv(CyclotomicField(7), sparse=False) # needs sage.rings.number_field sage: tinv(QQ['x,y'], sparse=True) sage: tinv(QQ['x,y'], sparse=False) diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index dcd9c2e1550..15f4cb093ee 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -1,7 +1,6 @@ r""" Base class for sparse matrices """ - # **************************************************************************** # 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 @@ -16,10 +15,9 @@ from cysignals.signals cimport sig_check cimport sage.matrix.matrix as matrix cimport sage.matrix.matrix0 as matrix0 -from sage.structure.element cimport Element, RingElement, ModuleElement, Vector +from sage.structure.element cimport Element, Vector from sage.structure.richcmp cimport richcmp_item, rich_to_bool from sage.rings.ring import is_Ring -from sage.misc.verbose import verbose from cpython cimport * from cpython.object cimport Py_EQ, Py_NE @@ -45,6 +43,7 @@ cdef class Matrix_sparse(matrix.Matrix): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: A = matrix(QQ['x,y'], 2, [0,-1,2*x,-2], sparse=True); A [ 0 -1] [2*x -2] @@ -364,10 +363,10 @@ cdef class Matrix_sparse(matrix.Matrix): return data, version def _unpickle_generic(self, data, int version): - cdef Py_ssize_t i, j, k + cdef Py_ssize_t i, j if version == -1: - for ij, x in data.iteritems(): - self.set_unsafe(ij[0], ij[1], x) + for (i, j), x in data.iteritems(): + self.set_unsafe(i, j, x) else: raise RuntimeError("unknown matrix version (=%s)" % version) @@ -642,7 +641,8 @@ cdef class Matrix_sparse(matrix.Matrix): [3 4 0] [1 2 3] sage: m.apply_morphism(phi).parent() - Full MatrixSpace of 3 by 3 sparse matrices over Finite Field of size 5 + Full MatrixSpace of 3 by 3 sparse matrices + over Finite Field of size 5 """ R = phi.codomain() M = sage.matrix.matrix_space.MatrixSpace(R, self._nrows, @@ -671,22 +671,26 @@ cdef class Matrix_sparse(matrix.Matrix): EXAMPLES:: sage: m = matrix(ZZ, 10000, {(1,2): 17}, sparse=True) + + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(9) sage: f = lambda x: k(x) sage: n = m.apply_map(f) sage: n.parent() - Full MatrixSpace of 10000 by 10000 sparse matrices over Finite Field in a of size 3^2 - sage: n[1,2] + Full MatrixSpace of 10000 by 10000 sparse matrices + over Finite Field in a of size 3^2 + sage: n[1, 2] 2 An example where the codomain is explicitly specified. :: - sage: n = m.apply_map(lambda x:x%3, GF(3)) + sage: n = m.apply_map(lambda x: x%3, GF(3)) sage: n.parent() - Full MatrixSpace of 10000 by 10000 sparse matrices over Finite Field of size 3 - sage: n[1,2] + Full MatrixSpace of 10000 by 10000 sparse matrices + over Finite Field of size 3 + sage: n[1, 2] 2 If we did not specify the codomain, the resulting matrix in the @@ -695,7 +699,7 @@ cdef class Matrix_sparse(matrix.Matrix): sage: n = m.apply_map(lambda x:x%3) sage: n.parent() Full MatrixSpace of 10000 by 10000 sparse matrices over Integer Ring - sage: n[1,2] + sage: n[1, 2] 2 If self is subdivided, the result will be as well:: @@ -806,8 +810,8 @@ cdef class Matrix_sparse(matrix.Matrix): EXAMPLES:: - sage: m = matrix(2, [x^i for i in range(4)], sparse=True) - sage: m._derivative(x) + sage: m = matrix(2, [x^i for i in range(4)], sparse=True) # needs sage.symbolic + sage: m._derivative(x) # needs sage.symbolic [ 0 1] [ 2*x 3*x^2] """ @@ -923,19 +927,18 @@ cdef class Matrix_sparse(matrix.Matrix): if not isinstance(columns, (list, tuple)): columns = list(columns) - cdef Py_ssize_t nrows, ncols,k,r,i,j + cdef Py_ssize_t nrows, ncols, k, i, j - r = 0 ncols = PyList_GET_SIZE(columns) nrows = PyList_GET_SIZE(rows) cdef Matrix_sparse A = self.new_matrix(nrows = nrows, ncols = ncols) - tmp = [el for el in columns if el >= 0 and el < self._ncols] + tmp = [el for el in columns if 0 <= el < self._ncols] columns = tmp if ncols != PyList_GET_SIZE(columns): raise IndexError("column index out of range") - tmp = [el for el in rows if el >= 0 and el < self._nrows] + tmp = [el for el in rows if 0 <= el < self._nrows] rows = tmp if nrows != PyList_GET_SIZE(rows): raise IndexError("row index out of range") @@ -959,7 +962,7 @@ cdef class Matrix_sparse(matrix.Matrix): i = get_ij(nz, k, 0) j = get_ij(nz, k, 1) if i in row_map and j in col_map: - entry = self.get_unsafe(i,j) + entry = self.get_unsafe(i, j) for new_row in row_map[i]: for new_col in col_map[j]: A.set_unsafe(new_row, new_col, entry) @@ -1175,8 +1178,9 @@ cdef class Matrix_sparse(matrix.Matrix): Check that the bug in :trac:`13854` has been fixed:: + sage: # needs sage.combinat sage: A.<x,y> = FreeAlgebra(QQ, 2) - sage: P.<x,y> = A.g_algebra(relations={y*x:-x*y}, order = 'lex') + sage: P.<x,y> = A.g_algebra(relations={y*x: -x*y}, order='lex') sage: M = Matrix([[x]], sparse=True) sage: w = vector([y]) doctest:...: UserWarning: You are constructing a free module diff --git a/src/sage/matrix/matrix_symbolic_dense.pyx b/src/sage/matrix/matrix_symbolic_dense.pyx index 8774848f2d7..b4f6f4f748f 100644 --- a/src/sage/matrix/matrix_symbolic_dense.pyx +++ b/src/sage/matrix/matrix_symbolic_dense.pyx @@ -1,5 +1,5 @@ """ -Symbolic matrices +Symbolic dense matrices EXAMPLES:: @@ -154,8 +154,7 @@ Check that :trac:`12778` is fixed:: Full MatrixSpace of 3 by 4 dense matrices over Symbolic Ring """ -from sage.rings.polynomial.all import PolynomialRing -from sage.structure.element cimport ModuleElement, RingElement, Element +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.factorization import Factorization from .matrix_generic_dense cimport Matrix_generic_dense @@ -163,7 +162,8 @@ from .constructor import matrix cdef maxima -from sage.calculus.calculus import symbolic_expression_from_maxima_string, maxima +from sage.calculus.calculus import maxima + cdef class Matrix_symbolic_dense(Matrix_generic_dense): def echelonize(self, **kwds): @@ -402,7 +402,8 @@ cdef class Matrix_symbolic_dense(Matrix_generic_dense): [1/2*(e^(2*x) + 1)*e^(-x) 1/2*(e^(2*x) - 1)*e^(-x)] [1/2*(e^(2*x) - 1)*e^(-x) 1/2*(e^(2*x) + 1)*e^(-x)] - Exp works on 0x0 and 1x1 matrices:: + Exponentiation works on 0x0 and 1x1 matrices, but the 1x1 example + requires a patched version of maxima (:trac:`32898`) for now:: sage: m = matrix(SR,0,[]); m [] @@ -410,7 +411,7 @@ cdef class Matrix_symbolic_dense(Matrix_generic_dense): [] sage: m = matrix(SR,1,[2]); m [2] - sage: m.exp() + sage: m.exp() # not tested, requires patched maxima [e^2] Commuting matrices `m, n` have the property that @@ -451,7 +452,6 @@ cdef class Matrix_symbolic_dense(Matrix_generic_dense): [ 0 1/2*(e^(2*x) + 1)*e^(-x) 1/2*(e^(2*x) - 1)*e^(-x) 0] [ 0 1/2*(e^(2*x) - 1)*e^(-x) 1/2*(e^(2*x) + 1)*e^(-x) 0] [1/2*(e^(2*x) - 1)*e^(-x) 0 0 1/2*(e^(2*x) + 1)*e^(-x)] - """ if not self.is_square(): raise ValueError("exp only defined on square matrices") @@ -575,7 +575,7 @@ cdef class Matrix_symbolic_dense(Matrix_generic_dense): if mp is None: mp = self._maxima_lib_().jordan().minimalPoly().expand() d = mp.hipow('x') - mp = [mp.coeff('x', i) for i in xrange(int(d) + 1)] + mp = [mp.coeff('x', i) for i in range(int(d) + 1)] mp = PolynomialRing(self.base_ring(), 'x')(mp) self.cache('minpoly', mp) return mp.change_variable_name(var) @@ -711,7 +711,7 @@ cdef class Matrix_symbolic_dense(Matrix_generic_dense): J = jordan_info.dispJordan()._sage_() if subdivide: v = [x[1] for x in jordan_info] - w = [sum(v[0:i]) for i in xrange(1, len(v))] + w = [sum(v[0:i]) for i in range(1, len(v))] J.subdivide(w, w) if transformation: P = A.diag_mode_matrix(jordan_info)._sage_() diff --git a/src/sage/matrix/matrix_symbolic_sparse.pxd b/src/sage/matrix/matrix_symbolic_sparse.pxd new file mode 100644 index 00000000000..897754c837d --- /dev/null +++ b/src/sage/matrix/matrix_symbolic_sparse.pxd @@ -0,0 +1,4 @@ +from .matrix_generic_sparse cimport Matrix_generic_sparse + +cdef class Matrix_symbolic_sparse(Matrix_generic_sparse): + pass diff --git a/src/sage/matrix/matrix_symbolic_sparse.pyx b/src/sage/matrix/matrix_symbolic_sparse.pyx new file mode 100644 index 00000000000..29f29a04dd1 --- /dev/null +++ b/src/sage/matrix/matrix_symbolic_sparse.pyx @@ -0,0 +1,1034 @@ +""" +Symbolic sparse matrices + +EXAMPLES:: + + sage: matrix(SR, 2, 2, range(4), sparse=True) + [0 1] + [2 3] + sage: matrix(SR, 2, 2, var('t'), sparse=True) + [t 0] + [0 t] + +Arithmetic:: + + sage: -matrix(SR, 2, range(4), sparse=True) + [ 0 -1] + [-2 -3] + sage: m = matrix(SR, 2, [1..4], sparse=True); sqrt(2)*m + [ sqrt(2) 2*sqrt(2)] + [3*sqrt(2) 4*sqrt(2)] + sage: m = matrix(SR, 4, [1..4^2], sparse=True) + sage: m * m + [ 90 100 110 120] + [202 228 254 280] + [314 356 398 440] + [426 484 542 600] + + sage: m = matrix(SR, 3, [1, 2, 3], sparse=True); m + [1] + [2] + [3] + sage: m.transpose() * m + [14] + +Computing inverses:: + + sage: M = matrix(SR, 2, var('a,b,c,d'), sparse=True) + sage: ~M + [1/a - b*c/(a^2*(b*c/a - d)) b/(a*(b*c/a - d))] + [ c/(a*(b*c/a - d)) -1/(b*c/a - d)] + sage: (~M*M).simplify_rational() + [1 0] + [0 1] + sage: M = matrix(SR, 3, 3, range(9), sparse=True) - var('t') + sage: (~M * M).simplify_rational() + [1 0 0] + [0 1 0] + [0 0 1] + + sage: matrix(SR, 1, 1, 1, sparse=True).inverse() + [1] + sage: matrix(SR, 0, 0, sparse=True).inverse() + [] + sage: matrix(SR, 3, 0, sparse=True).inverse() + Traceback (most recent call last): + ... + ArithmeticError: self must be a square matrix + +Transposition:: + + sage: m = matrix(SR, 2, [sqrt(2), -1, pi, e^2], sparse=True) + sage: m.transpose() + [sqrt(2) pi] + [ -1 e^2] + +``.T`` is a convenient shortcut for the transpose:: + + sage: m.T + [sqrt(2) pi] + [ -1 e^2] + +Test pickling:: + + sage: m = matrix(SR, 2, [sqrt(2), 3, pi, e], sparse=True); m + [sqrt(2) 3] + [ pi e] + sage: TestSuite(m).run() + +Comparison:: + + sage: m = matrix(SR, 2, [sqrt(2), 3, pi, e], sparse=True) + sage: m == m + True + sage: m != 3 + True + sage: m = matrix(SR,2,[1..4], sparse=True); n = m^2 + sage: (exp(m+n) - exp(m)*exp(n)).simplify_rational() == 0 # indirect test + True + + +Determinant:: + + sage: M = matrix(SR, 2, 2, [x,2,3,4], sparse=True) + sage: M.determinant() + 4*x - 6 + sage: M = matrix(SR, 3,3,range(9), sparse=True) + sage: M.det() + 0 + sage: t = var('t') + sage: M = matrix(SR, 2, 2, [cos(t), sin(t), -sin(t), cos(t)], sparse=True) + sage: M.det() + cos(t)^2 + sin(t)^2 + sage: M = matrix([[sqrt(x),0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]], sparse=True) + sage: det(M) + sqrt(x) + +Permanents:: + + sage: M = matrix(SR, 2, 2, [x,2,3,4], sparse=True) + sage: M.permanent() + 4*x + 6 + +Rank:: + + sage: M = matrix(SR, 5, 5, range(25), sparse=True) + sage: M.rank() + 2 + sage: M = matrix(SR, 5, 5, range(25), sparse=True) - var('t') + sage: M.rank() + 5 + + .. warning:: + + :meth:`rank` may return the wrong answer if it cannot determine that a + matrix element that is equivalent to zero is indeed so. + +Copying symbolic matrices:: + + sage: m = matrix(SR, 2, [sqrt(2), 3, pi, e], sparse=True) + sage: n = copy(m) + sage: n[0,0] = sin(1) + sage: m + [sqrt(2) 3] + [ pi e] + sage: n + [sin(1) 3] + [ pi e] + +Conversion to Maxima:: + + sage: m = matrix(SR, 2, [sqrt(2), 3, pi, e], sparse=True) + sage: m._maxima_() + matrix([sqrt(2),3],[%pi,%e]) + +TESTS: + +Check that :trac:`12778` is fixed:: + + sage: M = Matrix([[1, 0.9, 1/5, x^2], [2, 1.9, 2/5, x^3], [3, 2.9, 3/5, x^4]], sparse=True); M + [ 1 0.900000000000000 1/5 x^2] + [ 2 1.90000000000000 2/5 x^3] + [ 3 2.90000000000000 3/5 x^4] + sage: parent(M) + Full MatrixSpace of 3 by 4 sparse matrices over Symbolic Ring + +Check that :issue:`35653` is fixed:: + + sage: diagonal_matrix([x]).inverse() + [1/x] + sage: M = MatrixSpace(SR,2,2,sparse=True) + sage: M([[x,0],[0,x]]).inverse() + [1/x 0] + [ 0 1/x] +""" +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.structure.factorization import Factorization + +from .matrix_generic_sparse cimport Matrix_generic_sparse +from .constructor import matrix + +cdef maxima + +from sage.calculus.calculus import maxima + +cdef class Matrix_symbolic_sparse(Matrix_generic_sparse): + def echelonize(self, **kwds): + """ + Echelonize using the classical algorithm. + + + TESTS:: + + sage: m = matrix([[cos(pi/5), sin(pi/5)], [-sin(pi/5), cos(pi/5)]], sparse=True) + sage: m.echelonize(); m + [1 0] + [0 1] + """ + return super().echelonize(algorithm="classical", **kwds) + + def eigenvalues(self, extend=True): + """ + Compute the eigenvalues by solving the characteristic + polynomial in maxima. + + The argument ``extend`` is ignored but kept for compatibility with + other matrix classes. + + EXAMPLES:: + + sage: a=matrix(SR,[[1,2],[3,4]], sparse=True) + sage: a.eigenvalues() + [-1/2*sqrt(33) + 5/2, 1/2*sqrt(33) + 5/2] + + TESTS: + + Check for :trac:`31700`:: + + sage: m = matrix([[cos(pi/5), sin(pi/5)], [-sin(pi/5), cos(pi/5)]], sparse=True) + sage: t = linear_transformation(m) + sage: t.eigenvalues() + [1/4*sqrt(5) - 1/4*sqrt(2*sqrt(5) - 10) + 1/4, + 1/4*sqrt(5) + 1/4*sqrt(2*sqrt(5) - 10) + 1/4] + """ + maxima_evals = self._maxima_(maxima).eigenvalues()._sage_() + if not len(maxima_evals): + raise ArithmeticError("could not determine eigenvalues exactly using symbolic matrices; try using a different type of matrix via self.change_ring(), if possible") + return sum([[ev] * int(mult) for ev, mult in zip(*maxima_evals)], []) + + def eigenvectors_left(self, other=None): + r""" + Compute the left eigenvectors of a matrix. + + INPUT: + + - ``other`` -- a square matrix `B` (default: ``None``) in a generalized + eigenvalue problem; if ``None``, an ordinary eigenvalue problem is + solved (currently supported only if the base ring of ``self`` is + ``RDF`` or ``CDF``) + + OUTPUT: + + For each distinct eigenvalue, returns a list of the form (e,V,n) + where e is the eigenvalue, V is a list of eigenvectors forming a + basis for the corresponding left eigenspace, and n is the + algebraic multiplicity of the eigenvalue. + + EXAMPLES:: + + sage: A = matrix(SR,3,3,range(9), sparse=True); A + [0 1 2] + [3 4 5] + [6 7 8] + sage: es = A.eigenvectors_left(); es + [(-3*sqrt(6) + 6, [(1, -1/5*sqrt(6) + 4/5, -2/5*sqrt(6) + 3/5)], 1), + (3*sqrt(6) + 6, [(1, 1/5*sqrt(6) + 4/5, 2/5*sqrt(6) + 3/5)], 1), + (0, [(1, -2, 1)], 1)] + sage: eval, [evec], mult = es[0] + sage: delta = eval*evec - evec*A + sage: abs(abs(delta)) < 1e-10 + 3/5*sqrt(((2*sqrt(6) - 3)*(sqrt(6) - 2) + 7*sqrt(6) - 18)^2 + ((sqrt(6) - 2)*(sqrt(6) - 4) + 6*sqrt(6) - 14)^2) < (1.00000000000000e-10) + sage: abs(abs(delta)).n() < 1e-10 + True + + :: + + sage: A = matrix(SR, 2, 2, var('a,b,c,d'), sparse=True) + sage: A.eigenvectors_left() + [(1/2*a + 1/2*d - 1/2*sqrt(a^2 + 4*b*c - 2*a*d + d^2), [(1, -1/2*(a - d + sqrt(a^2 + 4*b*c - 2*a*d + d^2))/c)], 1), (1/2*a + 1/2*d + 1/2*sqrt(a^2 + 4*b*c - 2*a*d + d^2), [(1, -1/2*(a - d - sqrt(a^2 + 4*b*c - 2*a*d + d^2))/c)], 1)] + sage: es = A.eigenvectors_left(); es + [(1/2*a + 1/2*d - 1/2*sqrt(a^2 + 4*b*c - 2*a*d + d^2), [(1, -1/2*(a - d + sqrt(a^2 + 4*b*c - 2*a*d + d^2))/c)], 1), (1/2*a + 1/2*d + 1/2*sqrt(a^2 + 4*b*c - 2*a*d + d^2), [(1, -1/2*(a - d - sqrt(a^2 + 4*b*c - 2*a*d + d^2))/c)], 1)] + sage: eval, [evec], mult = es[0] + sage: delta = eval*evec - evec*A + sage: delta.apply_map(lambda x: x.full_simplify()) + (0, 0) + + This routine calls Maxima and can struggle with even small matrices + with a few variables, such as a `3\times 3` matrix with three variables. + However, if the entries are integers or rationals it can produce exact + values in a reasonable time. These examples create 0-1 matrices from + the adjacency matrices of graphs and illustrate how the format and type + of the results differ when the base ring changes. First for matrices + over the rational numbers, then the same matrix but viewed as a symbolic + matrix. :: + + sage: G=graphs.CycleGraph(5) + sage: am = G.adjacency_matrix(sparse=True) + sage: spectrum = am.eigenvectors_left() + sage: qqbar_evalue = spectrum[2][0] + sage: type(qqbar_evalue) + <class 'sage.rings.qqbar.AlgebraicNumber'> + sage: qqbar_evalue + 0.618033988749895? + + sage: am = G.adjacency_matrix(sparse=True).change_ring(SR) + sage: spectrum = am.eigenvectors_left() + sage: symbolic_evalue = spectrum[2][0] + sage: type(symbolic_evalue) + <class 'sage.symbolic.expression.Expression'> + sage: symbolic_evalue + 1/2*sqrt(5) - 1/2 + + sage: bool(qqbar_evalue == symbolic_evalue) + True + + A slightly larger matrix with a "nice" spectrum. :: + + sage: G = graphs.CycleGraph(6) + sage: am = G.adjacency_matrix(sparse=True).change_ring(SR) + sage: am.eigenvectors_left() + [(-1, [(1, 0, -1, 1, 0, -1), (0, 1, -1, 0, 1, -1)], 2), (1, [(1, 0, -1, -1, 0, 1), (0, 1, 1, 0, -1, -1)], 2), (-2, [(1, -1, 1, -1, 1, -1)], 1), (2, [(1, 1, 1, 1, 1, 1)], 1)] + + TESTS:: + + sage: A = matrix(SR, [[1, 2], [3, 4]], sparse=True) + sage: B = matrix(SR, [[1, 1], [0, 1]], sparse=True) + sage: A.eigenvectors_left(B) + Traceback (most recent call last): + ... + NotImplementedError: generalized eigenvector decomposition is + implemented for RDF and CDF, but not for Symbolic Ring + + Check that :trac:`23332` is fixed:: + + sage: matrix([[x, x^2], [1, 0]], sparse=True).eigenvectors_left() + [(-1/2*x*(sqrt(5) - 1), [(1, -1/2*x*(sqrt(5) + 1))], 1), + (1/2*x*(sqrt(5) + 1), [(1, 1/2*x*(sqrt(5) - 1))], 1)] + """ + if other is not None: + raise NotImplementedError('generalized eigenvector decomposition ' + 'is implemented for RDF and CDF, but ' + 'not for %s' % self.base_ring()) + + from sage.modules.free_module_element import vector + from sage.rings.integer_ring import ZZ + + [evals, mults], evecs = self.transpose()._maxima_(maxima).eigenvectors()._sage_() + result = [] + for e, evec, m in zip(evals, evecs, mults): + result.append((e, [vector(v) for v in evec], ZZ(m))) + + return result + + def eigenvectors_right(self, other=None): + r""" + Compute the right eigenvectors of a matrix. + + INPUT: + + - ``other`` -- a square matrix `B` (default: ``None``) in a generalized + eigenvalue problem; if ``None``, an ordinary eigenvalue problem is + solved (currently supported only if the base ring of ``self`` is + ``RDF`` or ``CDF``) + + OUTPUT: + + For each distinct eigenvalue, returns a list of the form (e,V,n) + where e is the eigenvalue, V is a list of eigenvectors forming a + basis for the corresponding right eigenspace, and n is the + algebraic multiplicity of the eigenvalue. + + EXAMPLES:: + + sage: A = matrix(SR,2,2,range(4), sparse=True); A + [0 1] + [2 3] + sage: right = A.eigenvectors_right(); right + [(-1/2*sqrt(17) + 3/2, [(1, -1/2*sqrt(17) + 3/2)], 1), (1/2*sqrt(17) + 3/2, [(1, 1/2*sqrt(17) + 3/2)], 1)] + + The right eigenvectors are nothing but the left eigenvectors of the + transpose matrix:: + + sage: left = A.transpose().eigenvectors_left(); left + [(-1/2*sqrt(17) + 3/2, [(1, -1/2*sqrt(17) + 3/2)], 1), (1/2*sqrt(17) + 3/2, [(1, 1/2*sqrt(17) + 3/2)], 1)] + sage: right[0][1] == left[0][1] + True + + TESTS:: + + sage: A = matrix(SR, [[1, 2], [3, 4]], sparse=True) + sage: B = matrix(SR, [[1, 1], [0, 1]], sparse=True) + sage: A.eigenvectors_right(B) + Traceback (most recent call last): + ... + NotImplementedError: generalized eigenvector decomposition is + implemented for RDF and CDF, but not for Symbolic Ring + + Check that :trac:`23332` is fixed:: + + sage: matrix([[x, x^2], [1, 0]], sparse=True).eigenvectors_right() + [(-1/2*x*(sqrt(5) - 1), [(1, -1/2*(sqrt(5) + 1)/x)], 1), + (1/2*x*(sqrt(5) + 1), [(1, 1/2*(sqrt(5) - 1)/x)], 1)] + """ + return self.transpose().eigenvectors_left(other=other) + + def exp(self): + r""" + Return the matrix exponential of this matrix `X`, which is the matrix + + .. MATH:: + + e^X = \sum_{k=0}^{\infty} \frac{X^k}{k!}. + + This function depends on maxima's matrix exponentiation + function, which does not deal well with floating point + numbers. If the matrix has floating point numbers, they will + be rounded automatically to rational numbers during the + computation. + + EXAMPLES:: + + sage: m = matrix(SR,2, [0,x,x,0], sparse=True); m + [0 x] + [x 0] + sage: m.exp() + [1/2*(e^(2*x) + 1)*e^(-x) 1/2*(e^(2*x) - 1)*e^(-x)] + [1/2*(e^(2*x) - 1)*e^(-x) 1/2*(e^(2*x) + 1)*e^(-x)] + sage: exp(m) + [1/2*(e^(2*x) + 1)*e^(-x) 1/2*(e^(2*x) - 1)*e^(-x)] + [1/2*(e^(2*x) - 1)*e^(-x) 1/2*(e^(2*x) + 1)*e^(-x)] + + Exponentiation works on 0x0 and 1x1 matrices, but the 1x1 example + requires a patched version of maxima (:trac:`32898`) for now:: + + sage: m = matrix(SR,0,[], sparse=True); m + [] + sage: m.exp() + [] + sage: m = matrix(SR,1,[2], sparse=True); m + [2] + sage: m.exp() # not tested, requires patched maxima + [e^2] + + Commuting matrices `m, n` have the property that + `e^{m+n} = e^m e^n` (but non-commuting matrices need not):: + + sage: m = matrix(SR,2,[1..4], sparse=True); n = m^2 + sage: m*n + [ 37 54] + [ 81 118] + sage: n*m + [ 37 54] + [ 81 118] + + sage: a = exp(m+n) - exp(m)*exp(n) + sage: a.simplify_rational() == 0 + True + + The input matrix must be square:: + + sage: m = matrix(SR,2,3,[1..6], sparse=True); exp(m) + Traceback (most recent call last): + ... + ValueError: exp only defined on square matrices + + In this example we take the symbolic answer and make it + numerical at the end:: + + sage: exp(matrix(SR, [[1.2, 5.6], [3,4]], sparse=True)).change_ring(RDF) # rel tol 1e-15 + [ 346.5574872980695 661.7345909344504] + [354.50067371488416 677.4247827652946] + + Another example involving the reversed identity matrix, which + we clumsily create:: + + sage: m = identity_matrix(SR,4, sparse=True) + sage: m = matrix(list(reversed(m.rows())), sparse=True) * x + sage: exp(m) + [1/2*(e^(2*x) + 1)*e^(-x) 0 0 1/2*(e^(2*x) - 1)*e^(-x)] + [ 0 1/2*(e^(2*x) + 1)*e^(-x) 1/2*(e^(2*x) - 1)*e^(-x) 0] + [ 0 1/2*(e^(2*x) - 1)*e^(-x) 1/2*(e^(2*x) + 1)*e^(-x) 0] + [1/2*(e^(2*x) - 1)*e^(-x) 0 0 1/2*(e^(2*x) + 1)*e^(-x)] + """ + if not self.is_square(): + raise ValueError("exp only defined on square matrices") + if self.nrows() == 0: + return self + # Maxima's matrixexp function chokes on floating point numbers + # so we automatically convert floats to rationals by passing + # keepfloat: false + m = self._maxima_(maxima) + z = maxima('matrixexp(%s), keepfloat: false' % m.name()) + if self.nrows() == 1: + # We do the following, because Maxima stupidly exp's 1x1 + # matrices into non-matrices! + z = maxima('matrix([%s])' % z.name()) + + return z._sage_() + + def charpoly(self, var='x', algorithm=None): + r""" + Compute the characteristic polynomial of ``self``, using maxima. + + .. NOTE:: + + The characteristic polynomial is defined as `\det(xI-A)`. + + INPUT: + + - ``var`` -- (default: 'x') name of variable of charpoly + + EXAMPLES:: + + sage: M = matrix(SR, 2, 2, var('a,b,c,d'), sparse=True) + sage: M.charpoly('t') + t^2 + (-a - d)*t - b*c + a*d + sage: matrix(SR, 5, [1..5^2], sparse=True).charpoly() + x^5 - 65*x^4 - 250*x^3 + + TESTS: + + The cached polynomial should be independent of the ``var`` + argument (:trac:`12292`). We check (indirectly) that the + second call uses the cached value by noting that its result is + not cached:: + + sage: M = MatrixSpace(SR, 2, sparse=True) + sage: A = M(range(0, 2^2)) + sage: type(A) + <class 'sage.matrix.matrix_symbolic_sparse.Matrix_symbolic_sparse'> + sage: A.charpoly('x') + x^2 - 3*x - 2 + sage: A.charpoly('y') + y^2 - 3*y - 2 + sage: A._cache['charpoly'] + x^2 - 3*x - 2 + + Ensure the variable name of the polynomial does not conflict + with variables used within the matrix (:trac:`14403`):: + + sage: Matrix(SR, [[sqrt(x), x],[1,x]], sparse=True).charpoly().list() + [x^(3/2) - x, -x - sqrt(x), 1] + + Test that :trac:`13711` is fixed:: + + sage: matrix([[sqrt(2), -1], [pi, e^2]], sparse=True).charpoly() + x^2 + (-sqrt(2) - e^2)*x + pi + sqrt(2)*e^2 + + Test that :trac:`26427` is fixed:: + + sage: M = matrix(SR, 7, 7, SR.var('a', 49), sparse=True) + sage: M.charpoly().degree() # long time + 7 + """ + cache_key = 'charpoly' + cp = self.fetch(cache_key) + if cp is not None: + return cp.change_variable_name(var) + from sage.symbolic.ring import SR + + # We must not use a variable name already present in the matrix + vname = 'do_not_use_this_name_in_a_matrix_youll_compute_a_charpoly_of' + vsym = SR(vname) + + cp = self._maxima_(maxima).charpoly(vname)._sage_().expand() + cp = [cp.coefficient(vsym, i) for i in range(self.nrows() + 1)] + cp = SR[var](cp) + + # Maxima has the definition det(matrix-xI) instead of + # det(xI-matrix), which is what Sage uses elsewhere. We + # correct for the discrepancy. + if self.nrows() % 2 == 1: + cp = -cp + + self.cache(cache_key, cp) + return cp + + def minpoly(self, var='x'): + """ + Return the minimal polynomial of ``self``. + + EXAMPLES:: + + sage: M = Matrix.identity(SR, 2, sparse=True) + sage: M.minpoly() + x - 1 + + sage: t = var('t') + sage: m = matrix(2, [1, 2, 4, t], sparse=True) + sage: m.minimal_polynomial() + x^2 + (-t - 1)*x + t - 8 + + TESTS: + + Check that the variable `x` can occur in the matrix:: + + sage: m = matrix([[x]], sparse=True) + sage: m.minimal_polynomial('y') + y - x + + """ + mp = self.fetch('minpoly') + if mp is None: + mp = self._maxima_lib_().jordan().minimalPoly().expand() + d = mp.hipow('x') + mp = [mp.coeff('x', i) for i in range(int(d) + 1)] + mp = PolynomialRing(self.base_ring(), 'x')(mp) + self.cache('minpoly', mp) + return mp.change_variable_name(var) + + def fcp(self, var='x'): + """ + Return the factorization of the characteristic polynomial of ``self``. + + INPUT: + + - ``var`` -- (default: 'x') name of variable of charpoly + + EXAMPLES:: + + sage: a = matrix(SR,[[1,2],[3,4]], sparse=True) + sage: a.fcp() + x^2 - 5*x - 2 + sage: [i for i in a.fcp()] + [(x^2 - 5*x - 2, 1)] + sage: a = matrix(SR,[[1,0],[0,2]], sparse=True) + sage: a.fcp() + (x - 2) * (x - 1) + sage: [i for i in a.fcp()] + [(x - 2, 1), (x - 1, 1)] + sage: a = matrix(SR, 5, [1..5^2], sparse=True) + sage: a.fcp() + (x^2 - 65*x - 250) * x^3 + sage: list(a.fcp()) + [(x^2 - 65*x - 250, 1), (x, 3)] + + """ + from sage.symbolic.ring import SR + sub_dict = {var: SR.var(var)} + return Factorization(self.charpoly(var).subs(**sub_dict).factor_list()) + + def jordan_form(self, subdivide=True, transformation=False): + """ + Return a Jordan normal form of ``self``. + + INPUT: + + - ``self`` -- a square matrix + + - ``subdivide`` -- boolean (default: ``True``) + + - ``transformation`` -- boolean (default: ``False``) + + OUTPUT: + + If ``transformation`` is ``False``, only a Jordan normal form + (unique up to the ordering of the Jordan blocks) is returned. + Otherwise, a pair ``(J, P)`` is returned, where ``J`` is a + Jordan normal form and ``P`` is an invertible matrix such that + ``self`` equals ``P * J * P^(-1)``. + + If ``subdivide`` is ``True``, the Jordan blocks in the + returned matrix ``J`` are indicated by a subdivision in + the sense of :meth:`~sage.matrix.matrix2.subdivide`. + + EXAMPLES: + + We start with some examples of diagonalisable matrices:: + + sage: a,b,c,d = var('a,b,c,d') + sage: matrix([a], sparse=True).jordan_form() + [a] + sage: matrix([[a, 0], [1, d]], sparse=True).jordan_form(subdivide=True) + [d|0] + [-+-] + [0|a] + sage: matrix([[a, 0], [1, d]], sparse=True).jordan_form(subdivide=False) + [d 0] + [0 a] + sage: matrix([[a, x, x], [0, b, x], [0, 0, c]], sparse=True).jordan_form() + [c|0|0] + [-+-+-] + [0|b|0] + [-+-+-] + [0|0|a] + + In the following examples, we compute Jordan forms of some + non-diagonalisable matrices:: + + sage: matrix([[a, a], [0, a]], sparse=True).jordan_form() + [a 1] + [0 a] + sage: matrix([[a, 0, b], [0, c, 0], [0, 0, a]], sparse=True).jordan_form() + [c|0 0] + [-+---] + [0|a 1] + [0|0 a] + + The following examples illustrate the ``transformation`` flag. + Note that symbolic expressions may need to be simplified to + make consistency checks succeed:: + + sage: A = matrix([[x - a*c, a^2], [-c^2, x + a*c]], sparse=True) + sage: J, P = A.jordan_form(transformation=True) + sage: J, P + ( + [x 1] [-a*c 1] + [0 x], [-c^2 0] + ) + sage: A1 = P * J * ~P; A1 + [ -a*c + x (a*c - x)*a/c + a*x/c] + [ -c^2 a*c + x] + sage: A1.simplify_rational() == A + True + + sage: B = matrix([[a, b, c], [0, a, d], [0, 0, a]], sparse=True) + sage: J, T = B.jordan_form(transformation=True) + sage: J, T + ( + [a 1 0] [b*d c 0] + [0 a 1] [ 0 d 0] + [0 0 a], [ 0 0 1] + ) + sage: (B * T).simplify_rational() == T * J + True + + Finally, some examples involving square roots:: + + sage: matrix([[a, -b], [b, a]], sparse=True).jordan_form() + [a - I*b| 0] + [-------+-------] + [ 0|a + I*b] + sage: matrix([[a, b], [c, d]], sparse=True).jordan_form(subdivide=False) + [1/2*a + 1/2*d - 1/2*sqrt(a^2 + 4*b*c - 2*a*d + d^2) 0] + [ 0 1/2*a + 1/2*d + 1/2*sqrt(a^2 + 4*b*c - 2*a*d + d^2)] + """ + A = self._maxima_lib_() + jordan_info = A.jordan() + J = matrix(jordan_info.dispJordan()._sage_(), sparse=True) + if subdivide: + v = [x[1] for x in jordan_info] + w = [sum(v[0:i]) for i in range(1, len(v))] + J.subdivide(w, w) + if transformation: + P = A.diag_mode_matrix(jordan_info)._sage_() + return J, matrix(P, sparse=True) + else: + return J + + def simplify(self): + """ + Simplify ``self``. + + EXAMPLES:: + + sage: var('x,y,z') + (x, y, z) + sage: m = matrix([[z, (x+y)/(x+y)], [x^2, y^2+2]], sparse=True); m + [ z 1] + [ x^2 y^2 + 2] + sage: m.simplify() + [ z 1] + [ x^2 y^2 + 2] + """ + return self.parent()([x.simplify() for x in self.list()]) + + def simplify_trig(self): + """ + EXAMPLES:: + + sage: theta = var('theta') + sage: M = matrix(SR, 2, 2, [cos(theta), sin(theta), -sin(theta), cos(theta)], sparse=True) + sage: ~M + [1/cos(theta) - sin(theta)^2/((sin(theta)^2/cos(theta) + cos(theta))*cos(theta)^2) -sin(theta)/((sin(theta)^2/cos(theta) + cos(theta))*cos(theta))] + [ sin(theta)/((sin(theta)^2/cos(theta) + cos(theta))*cos(theta)) 1/(sin(theta)^2/cos(theta) + cos(theta))] + sage: (~M).simplify_trig() + [ cos(theta) -sin(theta)] + [ sin(theta) cos(theta)] + """ + return self._maxima_(maxima).trigexpand().trigsimp()._sage_() + + def simplify_rational(self): + """ + EXAMPLES:: + + sage: M = matrix(SR, 3, 3, range(9), sparse=True) - var('t') + sage: (~M*M)[0,0] + t*(3*(2/t + (6/t + 7)/((t - 3/t - 4)*t))*(2/t + (6/t + 5)/((t - 3/t + - 4)*t))/(t - (6/t + 7)*(6/t + 5)/(t - 3/t - 4) - 12/t - 8) + 1/t + + 3/((t - 3/t - 4)*t^2)) - 6*(2/t + (6/t + 5)/((t - 3/t - 4)*t))/(t - + (6/t + 7)*(6/t + 5)/(t - 3/t - 4) - 12/t - 8) - 3*(6/t + 7)*(2/t + + (6/t + 5)/((t - 3/t - 4)*t))/((t - (6/t + 7)*(6/t + 5)/(t - 3/t - + 4) - 12/t - 8)*(t - 3/t - 4)) - 3/((t - 3/t - 4)*t) + sage: expand((~M*M)[0,0]) + 1 + sage: (~M * M).simplify_rational() + [1 0 0] + [0 1 0] + [0 0 1] + """ + return self._maxima_(maxima).fullratsimp()._sage_() + + def simplify_full(self): + """ + Simplify a symbolic matrix by calling + :meth:`Expression.simplify_full()` componentwise. + + INPUT: + + - ``self`` -- the matrix whose entries we should simplify. + + OUTPUT: + + A copy of ``self`` with all of its entries simplified. + + EXAMPLES: + + Symbolic matrices will have their entries simplified:: + + sage: a,n,k = SR.var('a,n,k') + sage: f1 = sin(x)^2 + cos(x)^2 + sage: f2 = sin(x/(x^2 + x)) + sage: f3 = binomial(n,k)*factorial(k)*factorial(n-k) + sage: f4 = x*sin(2)/(x^a) + sage: A = matrix(SR, [[f1,f2],[f3,f4]], sparse=True) + sage: A.simplify_full() + [ 1 sin(1/(x + 1))] + [ factorial(n) x^(-a + 1)*sin(2)] + + """ + M = self.parent() + return M([expr.simplify_full() for expr in self]) + + def canonicalize_radical(self): + r""" + Choose a canonical branch of each entry of ``self`` by calling + :meth:`Expression.canonicalize_radical()` componentwise. + + EXAMPLES:: + + sage: var('x','y') + (x, y) + sage: l1 = [sqrt(2)*sqrt(3)*sqrt(6) , log(x*y)] + sage: l2 = [sin(x/(x^2 + x)) , 1] + sage: m = matrix([l1, l2], sparse=True) + sage: m + [sqrt(6)*sqrt(3)*sqrt(2) log(x*y)] + [ sin(x/(x^2 + x)) 1] + sage: m.canonicalize_radical() + [ 6 log(x) + log(y)] + [ sin(1/(x + 1)) 1] + """ + M = self.parent() + return M([expr.canonicalize_radical() for expr in self]) + + def factor(self): + """ + Operate point-wise on each element. + + EXAMPLES:: + + sage: M = matrix(SR, 2, 2, x^2 - 2*x + 1, sparse=True); M + [x^2 - 2*x + 1 0] + [ 0 x^2 - 2*x + 1] + sage: M.factor() + [(x - 1)^2 0] + [ 0 (x - 1)^2] + """ + return matrix(self._maxima_(maxima).factor()._sage_(), sparse=True) + + def expand(self): + """ + Operate point-wise on each element. + + EXAMPLES:: + + sage: M = matrix(2, 2, range(4)) - var('x') + sage: M*M + [ x^2 + 2 -2*x + 3] + [ -4*x + 6 (x - 3)^2 + 2] + sage: (M*M).expand() + [ x^2 + 2 -2*x + 3] + [ -4*x + 6 x^2 - 6*x + 11] + """ + from sage.misc.call import attrcall + return self.apply_map(attrcall('expand')) + + def variables(self): + """ + Return the variables of ``self``. + + EXAMPLES:: + + sage: var('a,b,c,x,y') + (a, b, c, x, y) + sage: m = matrix([[x, x+2], [x^2, x^2+2]], sparse=True); m + [ x x + 2] + [ x^2 x^2 + 2] + sage: m.variables() + (x,) + sage: m = matrix([[a, b+c], [x^2, y^2+2]], sparse=True); m + [ a b + c] + [ x^2 y^2 + 2] + sage: m.variables() + (a, b, c, x, y) + """ + vars = set(sum([op.variables() for op in self.list()], ())) + return tuple(sorted(vars, key=repr)) + + def arguments(self): + """ + Return a tuple of the arguments that ``self`` can take. + + EXAMPLES:: + + sage: var('x,y,z') + (x, y, z) + sage: M = MatrixSpace(SR,2,2, sparse=True) + sage: M(x).arguments() + (x,) + sage: M(x+sin(x)).arguments() + (x,) + """ + return self.variables() + + def number_of_arguments(self): + """ + Return the number of arguments that ``self`` can take. + + EXAMPLES:: + + sage: var('a,b,c,x,y') + (a, b, c, x, y) + sage: m = matrix([[a, (x+y)/(x+y)], [x^2, y^2+2]], sparse=True); m + [ a 1] + [ x^2 y^2 + 2] + sage: m.number_of_arguments() + 3 + """ + return len(self.variables()) + + def __call__(self, *args, **kwargs): + """ + EXAMPLES:: + + sage: var('x,y,z') + (x, y, z) + sage: M = MatrixSpace(SR,2,2, sparse=True) + sage: h = M(sin(x)+cos(x)) + sage: h + [cos(x) + sin(x) 0] + [ 0 cos(x) + sin(x)] + sage: h(x=1) + [cos(1) + sin(1) 0] + [ 0 cos(1) + sin(1)] + sage: h(x=x) + [cos(x) + sin(x) 0] + [ 0 cos(x) + sin(x)] + + sage: h = M((sin(x)+cos(x)).function(x)) + sage: h + [cos(x) + sin(x) 0] + [ 0 cos(x) + sin(x)] + + sage: f = M([0,x,y,z]); f + [0 x] + [y z] + sage: f.arguments() + (x, y, z) + sage: f() + [0 x] + [y z] + sage: f(x=1) + [0 1] + [y z] + sage: f(x=1,y=2) + [0 1] + [2 z] + sage: f(x=1,y=2,z=3) + [0 1] + [2 3] + sage: f({x:1,y:2,z:3}) + [0 1] + [2 3] + + TESTS:: + + sage: f(1, x=2) + Traceback (most recent call last): + ... + ValueError: args and kwargs cannot both be specified + sage: f(x=1,y=2,z=3,t=4) + [0 1] + [2 3] + + sage: h(1) + Traceback (most recent call last): + ... + ValueError: use named arguments, like EXPR(x=..., y=...) + """ + if kwargs and args: + raise ValueError("args and kwargs cannot both be specified") + + if args: + if len(args) == 1 and isinstance(args[0], dict): + kwargs = {repr(x): vx for x, vx in args[0].iteritems()} + else: + raise ValueError('use named arguments, like EXPR(x=..., y=...)') + + new_entries = [] + for entry in self.list(): + try: + new_entries.append(entry(**kwargs)) + except ValueError: + new_entries.append(entry) + + return self.parent(new_entries) + + cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1: + r""" + Return 1 if the entry ``(i, j)`` is zero, otherwise 0. + + EXAMPLES:: + + sage: M = matrix(SR, [[0,1,0],[0,0,0]], sparse=True) + sage: M.zero_pattern_matrix() # indirect doctest + [1 0 1] + [1 1 1] + """ + entry = self.get_unsafe(i, j) + # See if we can avoid the full proof machinery that the entry is 0 + if entry.is_trivial_zero(): + return 1 + if entry: + return 0 + else: + return 1 + + def function(self, *args): + """ + Return a matrix over a callable symbolic expression ring. + + EXAMPLES:: + + sage: x, y = var('x,y') + sage: v = matrix([[x,y],[x*sin(y), 0]], sparse=True) + sage: w = v.function([x,y]); w + [ (x, y) |--> x (x, y) |--> y] + [(x, y) |--> x*sin(y) (x, y) |--> 0] + sage: w.parent() + Full MatrixSpace of 2 by 2 sparse matrices over Callable function ring with arguments (x, y) + """ + from sage.symbolic.callable import CallableSymbolicExpressionRing + return matrix(CallableSymbolicExpressionRing(args), + self.nrows(), self.ncols(), self.list(), sparse=True) diff --git a/src/sage/matrix/matrix_window.pyx b/src/sage/matrix/matrix_window.pyx index 38745fc25f1..e6046919191 100644 --- a/src/sage/matrix/matrix_window.pyx +++ b/src/sage/matrix/matrix_window.pyx @@ -104,7 +104,6 @@ cdef class MatrixWindow: def __getitem__(self, ij): cdef Py_ssize_t i, j - cdef object x if isinstance(ij, tuple): # ij is a tuple, so we get i and j efficiently, construct corresponding integer entry. @@ -112,7 +111,7 @@ cdef class MatrixWindow: raise IndexError("index must be an integer or pair of integers") i = <object> PyTuple_GET_ITEM(ij, 0) j = <object> PyTuple_GET_ITEM(ij, 1) - if i<0 or i >= self._nrows or j<0 or j >= self._ncols: + if i < 0 or i >= self._nrows or j < 0 or j >= self._ncols: raise IndexError("matrix index out of range") return self.get_unsafe(i, j) else: diff --git a/src/sage/matrix/misc.pyx b/src/sage/matrix/misc.pyx index 220f8866b0e..1819d45591e 100644 --- a/src/sage/matrix/misc.pyx +++ b/src/sage/matrix/misc.pyx @@ -1,150 +1,46 @@ """ Misc matrix algorithms - -Code goes here mainly when it needs access to the internal structure -of several classes, and we want to avoid circular cimports. - -NOTE: The whole problem of avoiding circular imports -- the reason for -existence of this file -- is now a non-issue, since some bugs in -Cython were fixed. Probably all this code should be moved into the -relevant classes and this file deleted. """ from cysignals.signals cimport sig_check -from sage.ext.mod_int cimport * -from sage.libs.gmp.mpz cimport * -from sage.libs.gmp.mpq cimport * -from sage.libs.mpfr cimport * - -from sage.libs.flint.fmpz cimport fmpz_set_mpz, fmpz_one -from sage.libs.flint.fmpq cimport fmpq_set_mpq, fmpq_canonicalise -from sage.libs.flint.fmpq_mat cimport fmpq_mat_entry_num, fmpq_mat_entry_den, fmpq_mat_entry - +from sage.arith.misc import CRT_basis, previous_prime from sage.arith.rational_reconstruction cimport mpq_rational_reconstruction - from sage.data_structures.binary_search cimport * +from sage.ext.mod_int cimport * +from sage.libs.gmp.mpq cimport * +from sage.libs.gmp.mpz cimport * +from sage.misc.lazy_import import LazyImport +from sage.misc.verbose import verbose from sage.modules.vector_integer_sparse cimport * -from sage.modules.vector_rational_sparse cimport * from sage.modules.vector_modn_sparse cimport * +from sage.modules.vector_rational_sparse cimport * +from sage.rings.integer cimport Integer +from sage.rings.rational_field import QQ from .matrix0 cimport Matrix -from .matrix_integer_dense cimport Matrix_integer_dense from .matrix_integer_sparse cimport Matrix_integer_sparse -from .matrix_rational_dense cimport Matrix_rational_dense from .matrix_rational_sparse cimport Matrix_rational_sparse -from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ - -from sage.rings.integer cimport Integer -from sage.arith.all import previous_prime, CRT_basis - -cimport sage.rings.abc -from sage.rings.real_mpfr cimport RealNumber - - -from sage.misc.verbose import verbose, get_verbose - -def matrix_integer_dense_rational_reconstruction(Matrix_integer_dense A, Integer N): - """ - Given a matrix over the integers and an integer modulus, do - rational reconstruction on all entries of the matrix, viewed as - numbers mod N. This is done efficiently by assuming there is a - large common factor dividing the denominators. - - INPUT: - - A -- matrix - N -- an integer - - EXAMPLES:: - - sage: B = ((matrix(ZZ, 3,4, [1,2,3,-4,7,2,18,3,4,3,4,5])/3)%500).change_ring(ZZ) - sage: sage.matrix.misc.matrix_integer_dense_rational_reconstruction(B, 500) - [ 1/3 2/3 1 -4/3] - [ 7/3 2/3 6 1] - [ 4/3 1 4/3 5/3] - - TESTS: - - Check that :trac:`9345` is fixed:: - - sage: A = random_matrix(ZZ, 3) - sage: sage.matrix.misc.matrix_integer_dense_rational_reconstruction(A, 0) - Traceback (most recent call last): - ... - ZeroDivisionError: The modulus cannot be zero - """ - if not N: - raise ZeroDivisionError("The modulus cannot be zero") - cdef Matrix_rational_dense R - R = Matrix_rational_dense.__new__(Matrix_rational_dense, - A.parent().change_ring(QQ), 0,0,0) - - cdef mpz_t a, bnd, other_bnd, denom, tmp - cdef mpq_t qtmp - cdef Integer _bnd - cdef Py_ssize_t i, j - cdef int do_it - - mpz_init_set_si(denom, 1) - mpz_init(a) - mpz_init(tmp) - mpz_init(other_bnd) - mpq_init(qtmp) - - _bnd = (N//2).isqrt() - mpz_init_set(bnd, _bnd.value) - mpz_sub(other_bnd, N.value, bnd) - - for i in range(A._nrows): - for j in range(A._ncols): - sig_check() - A.get_unsafe_mpz(i, j, a) - if mpz_cmp_ui(denom, 1) != 0: - mpz_mul(a, a, denom) - mpz_fdiv_r(a, a, N.value) - do_it = 0 - if mpz_cmp(a, bnd) <= 0: - do_it = 1 - elif mpz_cmp(a, other_bnd) >= 0: - mpz_sub(a, a, N.value) - do_it = 1 - if do_it: - fmpz_set_mpz(fmpq_mat_entry_num(R._matrix, i, j), a) - if mpz_cmp_ui(denom, 1) != 0: - fmpz_set_mpz(fmpq_mat_entry_den(R._matrix, i, j), denom) - fmpq_canonicalise(fmpq_mat_entry(R._matrix, i, j)) - else: - fmpz_one(fmpq_mat_entry_den(R._matrix, i, j)) - else: - # Otherwise have to do it the hard way - A.get_unsafe_mpz(i, j, tmp) - mpq_rational_reconstruction(qtmp, tmp, N.value) - mpz_lcm(denom, denom, mpq_denref(qtmp)) - fmpq_set_mpq(fmpq_mat_entry(R._matrix, i, j), qtmp) - - mpz_clear(denom) - mpz_clear(a) - mpz_clear(tmp) - mpz_clear(other_bnd) - mpz_clear(bnd) - mpq_clear(qtmp) - - return R +matrix_integer_dense_rational_reconstruction = \ + LazyImport('sage.matrix.misc_flint', 'matrix_integer_dense_rational_reconstruction', + deprecation=35758) +hadamard_row_bound_mpfr = \ + LazyImport('sage.matrix.misc_mpfr', 'hadamard_row_bound_mpfr', + deprecation=35758) def matrix_integer_sparse_rational_reconstruction(Matrix_integer_sparse A, Integer N): - """ + r""" Given a sparse matrix over the integers and an integer modulus, do rational reconstruction on all entries of the matrix, viewed as - numbers mod N. + numbers mod `N`. EXAMPLES:: sage: A = matrix(ZZ, 3, 4, [(1/3)%500, 2, 3, (-4)%500, 7, 2, 2, 3, 4, 3, 4, (5/7)%500], sparse=True) - sage: sage.matrix.misc.matrix_integer_sparse_rational_reconstruction(A, 500) + sage: from sage.matrix.misc import matrix_integer_sparse_rational_reconstruction + sage: matrix_integer_sparse_rational_reconstruction(A, 500) [1/3 2 3 -4] [ 7 2 2 3] [ 4 3 4 5/7] @@ -431,32 +327,33 @@ def matrix_rational_echelon_form_multimodular(Matrix self, height_guess=None, pr def cmp_pivots(x, y): - """ + r""" Compare two sequences of pivot columns. - If x is shorter than y, return -1, i.e., x < y, "not as good". - If x is longer than y, then x > y, so "better" and return +1. - If the length is the same, then x is better, i.e., x > y - if the entries of x are correspondingly <= those of y with + If `x` is shorter than `y`, return `-1`, i.e., `x < y`, "not as good". + If `x` is longer than `y`, then `x > y`, so "better" and return `+1`. + If the length is the same, then `x` is better, i.e., `x > y` + if the entries of `x` are correspondingly `\leq` those of `y` with one being strictly less. INPUT: - - x, y -- lists or tuples of integers + - ``x``, ``y`` -- lists or tuples of integers EXAMPLES: We illustrate each of the above comparisons. :: - sage: sage.matrix.misc.cmp_pivots([1,2,3], [4,5,6,7]) + sage: from sage.matrix.misc import cmp_pivots + sage: cmp_pivots([1,2,3], [4,5,6,7]) -1 - sage: sage.matrix.misc.cmp_pivots([1,2,3,5], [4,5,6]) + sage: cmp_pivots([1,2,3,5], [4,5,6]) 1 - sage: sage.matrix.misc.cmp_pivots([1,2,4], [1,2,3]) + sage: cmp_pivots([1,2,4], [1,2,3]) -1 - sage: sage.matrix.misc.cmp_pivots([1,2,3], [1,2,3]) + sage: cmp_pivots([1,2,3], [1,2,3]) 0 - sage: sage.matrix.misc.cmp_pivots([1,2,3], [1,2,4]) + sage: cmp_pivots([1,2,3], [1,2,4]) 1 """ x = tuple(x) @@ -471,70 +368,3 @@ def cmp_pivots(x, y): return 0 else: return -1 - - -def hadamard_row_bound_mpfr(Matrix A): - """ - Given a matrix A with entries that coerce to RR, compute the row - Hadamard bound on the determinant. - - INPUT: - - A -- a matrix over RR - - OUTPUT: - - integer -- an integer n such that the absolute value of the - determinant of this matrix is at most $10^n$. - - EXAMPLES: - - We create a very large matrix, compute the row Hadamard bound, - and also compute the row Hadamard bound of the transpose, which - happens to be sharp. :: - - sage: a = matrix(ZZ, 2, [2^10000,3^10000,2^50,3^19292]) - sage: import sage.matrix.misc - sage: sage.matrix.misc.hadamard_row_bound_mpfr(a.change_ring(RR)) - 13976 - sage: len(str(a.det())) - 12215 - sage: sage.matrix.misc.hadamard_row_bound_mpfr(a.transpose().change_ring(RR)) - 12215 - - Note that in the above example using RDF would overflow:: - - sage: b = a.change_ring(RDF) - sage: b._hadamard_row_bound() - Traceback (most recent call last): - ... - OverflowError: cannot convert float infinity to integer - """ - if not isinstance(A.base_ring(), sage.rings.abc.RealField): - raise TypeError("A must have base field an mpfr real field.") - - cdef RealNumber a, b - cdef mpfr_t s, d, pr - cdef Py_ssize_t i, j - - mpfr_init(s) - mpfr_init(d) - mpfr_init(pr) - mpfr_set_si(d, 0, MPFR_RNDU) - - for i in range(A._nrows): - mpfr_set_si(s, 0, MPFR_RNDU) - for j in range(A._ncols): - sig_check() - a = A.get_unsafe(i, j) - mpfr_mul(pr, a.value, a.value, MPFR_RNDU) - mpfr_add(s, s, pr, MPFR_RNDU) - mpfr_log10(s, s, MPFR_RNDU) - mpfr_add(d, d, s, MPFR_RNDU) - b = a._new() - mpfr_set(b.value, d, MPFR_RNDU) - b /= 2 - mpfr_clear(s) - mpfr_clear(d) - mpfr_clear(pr) - return b.ceil() diff --git a/src/sage/matrix/misc_flint.pyx b/src/sage/matrix/misc_flint.pyx new file mode 100644 index 00000000000..37d326c9a74 --- /dev/null +++ b/src/sage/matrix/misc_flint.pyx @@ -0,0 +1,107 @@ +r""" +Misc matrix algorithms using FLINT +""" + +from cysignals.signals cimport sig_check + +from sage.arith.rational_reconstruction cimport mpq_rational_reconstruction +from sage.libs.gmp.mpq cimport * +from sage.libs.gmp.mpz cimport * +from sage.libs.flint.fmpq cimport fmpq_set_mpq, fmpq_canonicalise +from sage.libs.flint.fmpq_mat cimport fmpq_mat_entry_num, fmpq_mat_entry_den, fmpq_mat_entry +from sage.libs.flint.fmpz cimport fmpz_set_mpz, fmpz_one +from sage.rings.integer cimport Integer +from sage.rings.rational_field import QQ + +from .matrix_integer_dense cimport Matrix_integer_dense +from .matrix_rational_dense cimport Matrix_rational_dense + + +def matrix_integer_dense_rational_reconstruction(Matrix_integer_dense A, Integer N): + r""" + Given a matrix over the integers and an integer modulus, do + rational reconstruction on all entries of the matrix, viewed as + numbers mod `N`. This is done efficiently by assuming there is a + large common factor dividing the denominators. + + INPUT: + + - ``A`` -- matrix + - ``N`` -- an integer + + EXAMPLES:: + + sage: B = ((matrix(ZZ, 3,4, [1,2,3,-4,7,2,18,3,4,3,4,5])/3)%500).change_ring(ZZ) + sage: from sage.matrix.misc_flint import matrix_integer_dense_rational_reconstruction + sage: matrix_integer_dense_rational_reconstruction(B, 500) + [ 1/3 2/3 1 -4/3] + [ 7/3 2/3 6 1] + [ 4/3 1 4/3 5/3] + + TESTS: + + Check that :trac:`9345` is fixed:: + + sage: A = random_matrix(ZZ, 3) + sage: matrix_integer_dense_rational_reconstruction(A, 0) + Traceback (most recent call last): + ... + ZeroDivisionError: The modulus cannot be zero + """ + if not N: + raise ZeroDivisionError("The modulus cannot be zero") + cdef Matrix_rational_dense R + R = Matrix_rational_dense.__new__(Matrix_rational_dense, + A.parent().change_ring(QQ), 0,0,0) + + cdef mpz_t a, bnd, other_bnd, denom, tmp + cdef mpq_t qtmp + cdef Integer _bnd + cdef Py_ssize_t i, j + cdef int do_it + + mpz_init_set_si(denom, 1) + mpz_init(a) + mpz_init(tmp) + mpz_init(other_bnd) + mpq_init(qtmp) + + _bnd = (N//2).isqrt() + mpz_init_set(bnd, _bnd.value) + mpz_sub(other_bnd, N.value, bnd) + + for i in range(A._nrows): + for j in range(A._ncols): + sig_check() + A.get_unsafe_mpz(i, j, a) + if mpz_cmp_ui(denom, 1) != 0: + mpz_mul(a, a, denom) + mpz_fdiv_r(a, a, N.value) + do_it = 0 + if mpz_cmp(a, bnd) <= 0: + do_it = 1 + elif mpz_cmp(a, other_bnd) >= 0: + mpz_sub(a, a, N.value) + do_it = 1 + if do_it: + fmpz_set_mpz(fmpq_mat_entry_num(R._matrix, i, j), a) + if mpz_cmp_ui(denom, 1) != 0: + fmpz_set_mpz(fmpq_mat_entry_den(R._matrix, i, j), denom) + fmpq_canonicalise(fmpq_mat_entry(R._matrix, i, j)) + else: + fmpz_one(fmpq_mat_entry_den(R._matrix, i, j)) + else: + # Otherwise have to do it the hard way + A.get_unsafe_mpz(i, j, tmp) + mpq_rational_reconstruction(qtmp, tmp, N.value) + mpz_lcm(denom, denom, mpq_denref(qtmp)) + fmpq_set_mpq(fmpq_mat_entry(R._matrix, i, j), qtmp) + + mpz_clear(denom) + mpz_clear(a) + mpz_clear(tmp) + mpz_clear(other_bnd) + mpz_clear(bnd) + mpq_clear(qtmp) + + return R diff --git a/src/sage/matrix/misc_mpfr.pyx b/src/sage/matrix/misc_mpfr.pyx new file mode 100644 index 00000000000..48b6ade6379 --- /dev/null +++ b/src/sage/matrix/misc_mpfr.pyx @@ -0,0 +1,79 @@ +r""" +Misc matrix algorithms using MPFR +""" + +from cysignals.signals cimport sig_check + +cimport sage.rings.abc + +from sage.libs.mpfr cimport * +from sage.rings.real_mpfr cimport RealNumber + +from .matrix0 cimport Matrix + + +def hadamard_row_bound_mpfr(Matrix A): + r""" + Given a matrix `A` with entries that coerce to ``RR``, compute the row + Hadamard bound on the determinant. + + INPUT: + + - ``A`` -- a matrix over ``RR`` + + OUTPUT: + + integer -- an integer n such that the absolute value of the + determinant of this matrix is at most `10^n`. + + EXAMPLES: + + We create a very large matrix, compute the row Hadamard bound, + and also compute the row Hadamard bound of the transpose, which + happens to be sharp. :: + + sage: a = matrix(ZZ, 2, [2^10000, 3^10000, 2^50, 3^19292]) + sage: from sage.matrix.misc_mpfr import hadamard_row_bound_mpfr + sage: hadamard_row_bound_mpfr(a.change_ring(RR)) + 13976 + sage: len(str(a.det())) + 12215 + sage: hadamard_row_bound_mpfr(a.transpose().change_ring(RR)) + 12215 + + Note that in the above example using RDF would overflow:: + + sage: b = a.change_ring(RDF) + sage: b._hadamard_row_bound() + Traceback (most recent call last): + ... + OverflowError: cannot convert float infinity to integer + """ + if not isinstance(A.base_ring(), sage.rings.abc.RealField): + raise TypeError("A must have base field an mpfr real field.") + + cdef RealNumber a, b + cdef mpfr_t s, d, pr + cdef Py_ssize_t i, j + + mpfr_init(s) + mpfr_init(d) + mpfr_init(pr) + mpfr_set_si(d, 0, MPFR_RNDU) + + for i in range(A._nrows): + mpfr_set_si(s, 0, MPFR_RNDU) + for j in range(A._ncols): + sig_check() + a = A.get_unsafe(i, j) + mpfr_mul(pr, a.value, a.value, MPFR_RNDU) + mpfr_add(s, s, pr, MPFR_RNDU) + mpfr_log10(s, s, MPFR_RNDU) + mpfr_add(d, d, s, MPFR_RNDU) + b = a._new() + mpfr_set(b.value, d, MPFR_RNDU) + b /= 2 + mpfr_clear(s) + mpfr_clear(d) + mpfr_clear(pr) + return b.ceil() diff --git a/src/sage/matrix/operation_table.py b/src/sage/matrix/operation_table.py index 9b59fa8dcee..69cc34d221e 100644 --- a/src/sage/matrix/operation_table.py +++ b/src/sage/matrix/operation_table.py @@ -14,12 +14,10 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from copy import copy + from sage.structure.sage_object import SageObject -from matplotlib.cm import gist_rainbow, Greys -from sage.plot.matrix_plot import matrix_plot from sage.matrix.constructor import Matrix -from sage.plot.text import text -from copy import copy class OperationTable(SageObject): @@ -83,8 +81,8 @@ class OperationTable(SageObject): In its most basic use, the table needs a structure and an operation:: sage: from sage.matrix.operation_table import OperationTable - sage: G=SymmetricGroup(3) - sage: OperationTable(G, operation=operator.mul) + sage: G = SymmetricGroup(3) # needs sage.groups + sage: OperationTable(G, operation=operator.mul) # needs sage.groups * a b c d e f +------------ a| a b c d e f @@ -98,7 +96,7 @@ class OperationTable(SageObject): want:: sage: from sage.matrix.operation_table import OperationTable - sage: R=Integers(6) + sage: R = Integers(6) sage: OperationTable(R, operation=operator.add) + a b c d e f +------------ @@ -114,8 +112,8 @@ class OperationTable(SageObject): 26 elements. :: sage: from sage.matrix.operation_table import OperationTable - sage: G=DihedralGroup(14) - sage: OperationTable(G, operator.mul, names='letters') + sage: G = DihedralGroup(14) # needs sage.groups + sage: OperationTable(G, operator.mul, names='letters') # needs sage.groups * aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az ba bb +------------------------------------------------------------------------------------ aa| aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az ba bb @@ -151,8 +149,8 @@ class OperationTable(SageObject): zeros to make a common width. :: sage: from sage.matrix.operation_table import OperationTable - sage: G=AlternatingGroup(4) - sage: OperationTable(G, operator.mul, names='digits') + sage: G = AlternatingGroup(4) # needs sage.groups + sage: OperationTable(G, operator.mul, names='digits') # needs sage.groups * 00 01 02 03 04 05 06 07 08 09 10 11 +------------------------------------ 00| 00 01 02 03 04 05 06 07 08 09 10 11 @@ -173,8 +171,8 @@ class OperationTable(SageObject): of the elements can be used. :: sage: from sage.matrix.operation_table import OperationTable - sage: G=AlternatingGroup(3) - sage: OperationTable(G, operator.mul, names='elements') + sage: G = AlternatingGroup(3) # needs sage.groups + sage: OperationTable(G, operator.mul, names='elements') # needs sage.groups * () (1,2,3) (1,3,2) +------------------------ ()| () (1,2,3) (1,3,2) @@ -186,6 +184,7 @@ class OperationTable(SageObject): :meth:`~sage.matrix.operation_table.OperationTable.column_keys` method. :: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable sage: G = QuaternionGroup() sage: T = OperationTable(G, operator.mul) @@ -280,10 +279,10 @@ class OperationTable(SageObject): odd. The LaTeX version works much better. :: sage: from sage.matrix.operation_table import OperationTable - sage: L=FiniteSemigroups().example(()) + sage: L = FiniteSemigroups().example(()) sage: L An example of a finite semigroup: the left regular band generated by () - sage: T=OperationTable(L, operation=operator.mul) + sage: T = OperationTable(L, operation=operator.mul) sage: T * + @@ -303,8 +302,9 @@ class OperationTable(SageObject): structure, in forms that can be coerced into the structure. Here we demonstrate the proper use first:: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable - sage: H=CyclicPermutationGroup(4) + sage: H = CyclicPermutationGroup(4) sage: H.list() [(), (1,2,3,4), (1,3)(2,4), (1,4,3,2)] sage: elts = ['()', '(1,3)(2,4)'] @@ -317,6 +317,7 @@ class OperationTable(SageObject): This can be rewritten so as to pass the actual elements of the group ``H``, using a simple ``for`` loop:: + sage: # needs sage.groups sage: L = H.list() #list of elements of the group H sage: elts = [L[i] for i in {0, 2}] sage: elts @@ -329,6 +330,7 @@ class OperationTable(SageObject): Here are a couple of improper uses:: + sage: # needs sage.groups sage: elts.append(5) sage: OperationTable(H, operator.mul, elements=elts) Traceback (most recent call last): @@ -347,13 +349,13 @@ class OperationTable(SageObject): Unusable functions should be recognized as such:: - sage: H=CyclicPermutationGroup(4) - sage: OperationTable(H, operator.add) + sage: H = CyclicPermutationGroup(4) # needs sage.groups + sage: OperationTable(H, operator.add) # needs sage.groups Traceback (most recent call last): ... TypeError: elements () and () of Cyclic group of order 4 as a permutation group are incompatible with operation: <built-in function add> sage: from operator import xor - sage: OperationTable(H, xor) + sage: OperationTable(H, xor) # needs sage.groups Traceback (most recent call last): ... TypeError: elements () and () of Cyclic group of order 4 as a permutation group are incompatible with operation: <built-in function xor> @@ -361,9 +363,9 @@ class OperationTable(SageObject): We construct the multiplication table for a finite finitely presented group, where there is no normalization done when computing the hash:: - sage: GU.<s,t> = FreeGroup() - sage: gr0 = GU / (s^(-2)*t*s*t, t^(-2)*s*t*s, s*t*s*t) - sage: gr0.multiplication_table() + sage: GU.<s,t> = FreeGroup() # needs sage.groups + sage: gr0 = GU / (s^(-2)*t*s*t, t^(-2)*s*t*s, s*t*s*t) # needs sage.groups + sage: gr0.multiplication_table() # needs sage.groups * a b c d e f g h i j k l +------------------------ a| a b c d e f g h i j k l @@ -390,9 +392,9 @@ def __init__(self, S, operation, names='letters', elements=None): TESTS:: sage: from sage.matrix.operation_table import OperationTable - sage: G=SymmetricGroup(3) - sage: T=OperationTable(G, operator.mul) - sage: TestSuite(T).run() + sage: G = SymmetricGroup(3) # needs sage.groups + sage: T = OperationTable(G, operator.mul) # needs sage.groups + sage: TestSuite(T).run() # needs sage.groups """ # Determine the elements of S, specified or not # If elements are given, we check if they are all in S @@ -511,9 +513,10 @@ def _name_maker(self, names): and :meth:`change_names` methods. So we just demonstrate the nature of the output here. :: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable - sage: G=SymmetricGroup(3) - sage: T=OperationTable(G, operator.mul) + sage: G = SymmetricGroup(3) + sage: T = OperationTable(G, operator.mul) sage: w, l, d = T._name_maker('letters') sage: w 1 @@ -528,9 +531,10 @@ def _name_maker(self, names): doctests for the :class:`OperationTable` and :meth:`change_names` methods that rely on this one. :: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable - sage: G=AlternatingGroup(3) - sage: T=OperationTable(G, operator.mul) + sage: G = AlternatingGroup(3) + sage: T = OperationTable(G, operator.mul) sage: T._name_maker(['x']) Traceback (most recent call last): ... @@ -609,9 +613,10 @@ def __getitem__(self, pair): EXAMPLES:: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable - sage: G=DiCyclicGroup(3) - sage: T=OperationTable(G, operator.mul) + sage: G = DiCyclicGroup(3) + sage: T = OperationTable(G, operator.mul) sage: T.column_keys() ((), (5,6,7), ..., (1,4,2,3)(5,7)) sage: T[G('(1,2)(3,4)(5,6,7)'), G('(1,3,2,4)(5,7)')] @@ -619,6 +624,7 @@ def __getitem__(self, pair): TESTS:: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable sage: G = DiCyclicGroup(3) sage: T = OperationTable(G, operator.mul) @@ -664,13 +670,14 @@ def __eq__(self, other): EXAMPLES:: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable - sage: G=CyclicPermutationGroup(6) - sage: H=CyclicPermutationGroup(3) - sage: P=OperationTable(G, operator.mul) - sage: Q=OperationTable(G, operator.mul) - sage: R=OperationTable(H, operator.mul) - sage: S=OperationTable(G, operator.truediv) + sage: G = CyclicPermutationGroup(6) + sage: H = CyclicPermutationGroup(3) + sage: P = OperationTable(G, operator.mul) + sage: Q = OperationTable(G, operator.mul) + sage: R = OperationTable(H, operator.mul) + sage: S = OperationTable(G, operator.truediv) sage: P == P, P == Q, P == R, P == S (True, True, False, False) """ @@ -682,13 +689,14 @@ def __ne__(self, other): EXAMPLES:: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable - sage: G=CyclicPermutationGroup(6) - sage: H=CyclicPermutationGroup(3) - sage: P=OperationTable(G, operator.mul) - sage: Q=OperationTable(G, operator.mul) - sage: R=OperationTable(H, operator.mul) - sage: S=OperationTable(G, operator.truediv) + sage: G = CyclicPermutationGroup(6) + sage: H = CyclicPermutationGroup(3) + sage: P = OperationTable(G, operator.mul) + sage: Q = OperationTable(G, operator.mul) + sage: R = OperationTable(H, operator.mul) + sage: S = OperationTable(G, operator.truediv) sage: P != P, P != Q, P != R, P != S (False, False, True, True) """ @@ -701,8 +709,8 @@ def _repr_(self): EXAMPLES:: sage: from sage.matrix.operation_table import OperationTable - sage: R=Integers(5) - sage: T=OperationTable(R, operation=operator.add) + sage: R = Integers(5) + sage: T = OperationTable(R, operation=operator.add) sage: print(T._repr_()) + a b c d e +---------- @@ -726,9 +734,10 @@ def set_print_symbols(self, ascii, latex): EXAMPLES:: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable - sage: G=AlternatingGroup(3) - sage: T=OperationTable(G, operator.mul) + sage: G = AlternatingGroup(3) + sage: T = OperationTable(G, operator.mul) sage: T.set_print_symbols('@', '\\times') sage: T @ a b c @@ -741,9 +750,10 @@ def set_print_symbols(self, ascii, latex): TESTS:: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable - sage: G=AlternatingGroup(3) - sage: T=OperationTable(G, operator.mul) + sage: G = AlternatingGroup(3) + sage: T = OperationTable(G, operator.mul) sage: T.set_print_symbols('@', 5) Traceback (most recent call last): ... @@ -783,9 +793,9 @@ def column_keys(self): EXAMPLES:: sage: from sage.matrix.operation_table import OperationTable - sage: G=AlternatingGroup(3) - sage: T=OperationTable(G, operator.mul) - sage: T.column_keys() + sage: G = AlternatingGroup(3) # needs sage.groups + sage: T = OperationTable(G, operator.mul) # needs sage.groups + sage: T.column_keys() # needs sage.groups ((), (1,2,3), (1,3,2)) """ return self._elts @@ -809,9 +819,9 @@ def translation(self): EXAMPLES:: sage: from sage.matrix.operation_table import OperationTable - sage: G=AlternatingGroup(3) - sage: T=OperationTable(G, operator.mul, names=['p','q','r']) - sage: T.translation() + sage: G = AlternatingGroup(3) # needs sage.groups + sage: T = OperationTable(G, operator.mul, names=['p','q','r']) # needs sage.groups + sage: T.translation() # needs sage.groups {'p': (), 'q': (1,2,3), 'r': (1,3,2)} """ return self._name_dict @@ -830,9 +840,9 @@ def table(self): EXAMPLES:: sage: from sage.matrix.operation_table import OperationTable - sage: C=CyclicPermutationGroup(3) - sage: T=OperationTable(C, operator.mul) - sage: T.table() + sage: C = CyclicPermutationGroup(3) # needs sage.groups + sage: T=OperationTable(C, operator.mul) # needs sage.groups + sage: T.table() # needs sage.groups [[0, 1, 2], [1, 2, 0], [2, 0, 1]] """ return self._table @@ -871,9 +881,10 @@ def change_names(self, names): :class:`OperationTable` since creating a new operation table uses the same routine. :: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable - sage: D=DihedralGroup(2) - sage: T=OperationTable(D, operator.mul) + sage: D = DihedralGroup(2) + sage: T = OperationTable(D, operator.mul) sage: T * a b c d +-------- @@ -928,6 +939,7 @@ def matrix_of_variables(self): The output here is from the doctests for the old ``cayley_table()`` method for permutation groups. :: + sage: # needs sage.groups sage: from sage.matrix.operation_table import OperationTable sage: G = PermutationGroup(['(1,2,3)', '(2,3)']) sage: T = OperationTable(G, operator.mul) @@ -950,41 +962,36 @@ def matrix_of_variables(self): for i in range(self._n) for j in range(self._n)] return MS(entries) - # documentation hack - # makes the cmap default argument look nice in the docs - # by copying the gist_rainbow object and overriding __repr__ - gist_rainbow_copy=copy(gist_rainbow) - class ReprOverrideLinearSegmentedColormap(gist_rainbow_copy.__class__): - def __repr__(self): - return "gist_rainbow" - gist_rainbow_copy.__class__=ReprOverrideLinearSegmentedColormap - - - def color_table(self, element_names=True, cmap=gist_rainbow_copy, **options): + def color_table(self, element_names=True, cmap=None, **options): r""" - Returns a graphic image as a square grid where entries are color coded. + Return a graphic image as a square grid where entries are color coded. INPUT: - ``element_names`` - (default : ``True``) Whether to display text with element names on the image - - ``cmap`` - (default : ``gist_rainbow``) colour map for plot, see matplotlib.cm + - ``cmap`` -- (default: :obj:`matplotlib.cm.gist_rainbow`) color map for plot, see :mod:`matplotlib.cm` - - ``**options`` - passed on to matrix_plot call + - ``**options`` -- passed on to :func:`~sage.plot.matrix_plot.matrix_plot` EXAMPLES:: sage: from sage.matrix.operation_table import OperationTable - sage: OTa = OperationTable(SymmetricGroup(3), operation=operator.mul) - sage: OTa.color_table() + sage: OTa = OperationTable(SymmetricGroup(3), operation=operator.mul) # needs sage.groups sage.plot + sage: OTa.color_table() # needs sage.groups sage.plot Graphics object consisting of 37 graphics primitives .. PLOT:: from sage.matrix.operation_table import OperationTable OTa = OperationTable(SymmetricGroup(3), operation=operator.mul) - sphinx_plot(OTa.color_table(), figsize=(3.0,3.0)) + sphinx_plot(OTa.color_table(), figsize=(3.0, 3.0)) """ + from sage.plot.matrix_plot import matrix_plot + from sage.plot.text import text + + if cmap is None: + from matplotlib.cm import gist_rainbow as cmap # Base matrix plot object, without text plot = matrix_plot(Matrix(self._table), cmap=cmap, @@ -1018,6 +1025,29 @@ def color_table(self, element_names=True, cmap=gist_rainbow_copy, **options): return plot def gray_table(self, **options): + r""" + Return a graphic image as a square grid where entries are displayed in grayscale. + + INPUT: + + - ``element_names`` -- (default: ``True``) whether to display text with element names on the image + + - ``**options`` -- passed on to :func:`~sage.plot.matrix_plot.matrix_plot` + + EXAMPLES:: + + sage: from sage.matrix.operation_table import OperationTable + sage: OTa = OperationTable(SymmetricGroup(3), operation=operator.mul) # needs sage.groups sage.plot + sage: OTa.gray_table() # needs sage.groups sage.plot + Graphics object consisting of 37 graphics primitives + + .. PLOT:: + + from sage.matrix.operation_table import OperationTable + OTa = OperationTable(SymmetricGroup(3), operation=operator.mul) + sphinx_plot(OTa.gray_table(), figsize=(3.0, 3.0)) + """ + from matplotlib.cm import Greys return self.color_table(cmap=Greys, **options) def _ascii_table(self): @@ -1027,8 +1057,8 @@ def _ascii_table(self): EXAMPLES:: sage: from sage.matrix.operation_table import OperationTable - sage: R=Integers(5) - sage: T=OperationTable(R, operator.add) + sage: R = Integers(5) + sage: T = OperationTable(R, operator.add) sage: print(T._ascii_table()) + a b c d e +---------- @@ -1042,8 +1072,8 @@ def _ascii_table(self): strings used to represent elements. :: sage: from sage.matrix.operation_table import OperationTable - sage: R=Integers(10) - sage: T=OperationTable(R, operator.mul, names='digits') + sage: R = Integers(10) + sage: T = OperationTable(R, operator.mul, names='digits') sage: print(T._ascii_table()) * 0 1 2 3 4 5 6 7 8 9 +-------------------- @@ -1061,8 +1091,8 @@ def _ascii_table(self): :: sage: from sage.matrix.operation_table import OperationTable - sage: R=Integers(11) - sage: T=OperationTable(R, operator.mul, names='digits') + sage: R = Integers(11) + sage: T = OperationTable(R, operator.mul, names='digits') sage: print(T._ascii_table()) * 00 01 02 03 04 05 06 07 08 09 10 +--------------------------------- @@ -1081,8 +1111,8 @@ def _ascii_table(self): :: sage: from sage.matrix.operation_table import OperationTable - sage: R=Integers(4) - sage: T=OperationTable(R, operator.mul, names=['x','y','wwww', 'z']) + sage: R = Integers(4) + sage: T = OperationTable(R, operator.mul, names=['x','y','wwww', 'z']) sage: print(T._ascii_table()) * x y wwww z +-------------------- @@ -1119,8 +1149,8 @@ def _latex_(self): EXAMPLES:: sage: from sage.matrix.operation_table import OperationTable - sage: R=Integers(2) - sage: T=OperationTable(R, operation=operator.mul) + sage: R = Integers(2) + sage: T = OperationTable(R, operation=operator.mul) sage: T._latex_() '{\\setlength{\\arraycolsep}{2ex}\n\\begin{array}{r|*{2}{r}}\n\\multicolumn{1}{c|}{\\ast}&a&b\\\\\\hline\n{}a&a&a\\\\\n{}b&a&b\\\\\n\\end{array}}' """ diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index 5d3bb13445b..41b64965ca3 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -7,7 +7,7 @@ For example, here is a circulant matrix of order five:: - sage: matrix.circulant(SR.var('a b c d e')) + sage: matrix.circulant(SR.var('a b c d e')) # needs sage.symbolic [a b c d e] [e a b c d] [d e a b c] @@ -66,7 +66,7 @@ from sage.rings.ring import is_Ring import sage.matrix.matrix_space as matrix_space from sage.modules.free_module_element import vector -from sage.structure.element import is_Matrix +from sage.structure.element import is_Matrix, parent from sage.structure.sequence import Sequence from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -266,7 +266,7 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation An upper bound on the absolute value of the entries may be set when the ``algorithm`` is ``echelonizable`` or ``unimodular``. In these cases it is possible for this constructor to fail with - a ``ValueError``. If you *must* have this routine return + a :class:`ValueError`. If you *must* have this routine return successfully, do not set ``upper_bound``. This behavior can be partially controlled by a ``max_tries`` keyword. @@ -356,6 +356,7 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation ....: A = random_matrix(*args, **kwds) ....: density_sum += float(A.density()) + sage: # needs sage.libs.flint (otherwise timeout) sage: density_sum = 0.0 sage: total_count = 0.0 sage: add_sample(ZZ, 5, x=-10, y=10, density=0.75) @@ -365,12 +366,14 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation sage: while abs(density_sum/total_count - expected_density) > 0.001: ....: add_sample(ZZ, 5, x=-10, y=10, density=0.75) + sage: # needs sage.libs.flint (otherwise timeout) sage: density_sum = 0.0 sage: total_count = 0.0 sage: add_sample(ZZ, 5, x=20, y=30, density=0.75) sage: while abs(density_sum/total_count - expected_density) > 0.001: ....: add_sample(ZZ, 5, x=20, y=30, density=0.75) + sage: # needs sage.libs.flint (otherwise timeout) sage: density_sum = 0.0 sage: total_count = 0.0 sage: add_sample(ZZ, 100, x=20, y=30, density=0.75) @@ -383,7 +386,7 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation For a matrix with low density it may be advisable to insist on a sparse representation, as this representation is not selected automatically. :: - sage: A=random_matrix(ZZ, 5, 5) + sage: A = random_matrix(ZZ, 5, 5) sage: A.is_sparse() False sage: A = random_matrix(ZZ, 5, 5, sparse=True) @@ -393,15 +396,16 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation For algorithm testing you might want to control the number of bits, say 10,000 entries, each limited to 16 bits. :: + sage: # needs sage.libs.flint (otherwise timeout) sage: A = random_matrix(ZZ, 100, 100, x=2^16); A 100 x 100 dense matrix over Integer Ring (use the '.str()' method to see the entries) One can prescribe a specific matrix implementation:: - sage: K.<a> = FiniteField(2^8) - sage: type(random_matrix(K, 2, 5)) + sage: K.<a> = FiniteField(2^8) # needs sage.rings.finite_rings + sage: type(random_matrix(K, 2, 5)) # needs sage.libs.m4ri sage.rings.finite_rings <class 'sage.matrix.matrix_gf2e_dense.Matrix_gf2e_dense'> - sage: type(random_matrix(K, 2, 5, implementation="generic")) + sage: type(random_matrix(K, 2, 5, implementation="generic")) # needs sage.rings.finite_rings <class 'sage.matrix.matrix_generic_dense.Matrix_generic_dense'> Random rational matrices. Now ``num_bound`` and ``den_bound`` control the @@ -421,7 +425,7 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation ....: for a in A.list()) True - sage: A = random_matrix(QQ, 4, density = 0.5, sparse=True) + sage: A = random_matrix(QQ, 4, density=0.5, sparse=True) sage: type(A) <class 'sage.matrix.matrix_rational_sparse.Matrix_rational_sparse'> sage: A.density() <= 0.5 @@ -460,11 +464,11 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation randomisation when using the optional meataxe package, we have to make sure that we use the default implementation in this test:: - sage: K.<a>=FiniteField(3^2) - sage: A = random_matrix(K, 2, 5, implementation='generic') + sage: K.<a> = FiniteField(3^2) # needs sage.rings.finite_rings + sage: A = random_matrix(K, 2, 5, implementation='generic') # needs sage.rings.finite_rings sage: type(A) <class 'sage.matrix.matrix_generic_dense.Matrix_generic_dense'> - sage: A.base_ring() is K + sage: A.base_ring() is K # needs sage.rings.finite_rings True sage: TestSuite(A).run() @@ -544,14 +548,15 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation When the eigenvalues and dimensions are not specified the result will have randomly generated values for both that fit with the designated size. :: - sage: A = random_matrix(QQ, 5, algorithm='diagonalizable', eigenvalues=[2,3,-1], dimensions=[1,2,2]); A # random - sage: all(x in ZZ for x in (A-(2*identity_matrix(5))).rref().list()) + sage: A = random_matrix(QQ, 5, algorithm='diagonalizable', # random + ....: eigenvalues=[2,3,-1], dimensions=[1,2,2]); A + sage: all(x in ZZ for x in (A - (2*identity_matrix(5))).rref().list()) True - sage: all(x in ZZ for x in (A-(3*identity_matrix(5))).rref().list()) + sage: all(x in ZZ for x in (A - 3*identity_matrix(5)).rref().list()) True - sage: all(x in ZZ for x in (A-(-1*identity_matrix(5))).rref().list()) + sage: all(x in ZZ for x in (A - (-1)*identity_matrix(5)).rref().list()) True - sage: A.jordan_form() + sage: A.jordan_form() # needs sage.combinat [ 2| 0| 0| 0| 0] [--+--+--+--+--] [ 0| 3| 0| 0| 0] @@ -575,14 +580,14 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation contain only integer entries. If ``rank``, is not set, the rank of the matrix will be generated randomly. :: - sage: B = random_matrix(QQ, 5, 6, algorithm='subspaces', rank=3); B #random - sage: B_expanded=B.augment(identity_matrix(5)).rref() + sage: B = random_matrix(QQ, 5, 6, algorithm='subspaces', rank=3); B # random + sage: B_expanded = B.augment(identity_matrix(5)).rref() sage: (B.nrows(), B.ncols()) (5, 6) sage: all(x in ZZ for x in B_expanded.list()) True - sage: C=B_expanded.submatrix(0,0,B.nrows()-B.nullity(),B.ncols()) - sage: L=B_expanded.submatrix(B.nrows()-B.nullity(),B.ncols()) + sage: C = B_expanded.submatrix(0, 0, B.nrows() - B.nullity(), B.ncols()) + sage: L = B_expanded.submatrix(B.nrows() - B.nullity(), B.ncols()) sage: B.right_kernel() == C.right_kernel() True sage: B.row_space() == C.row_space() @@ -604,7 +609,7 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation or ``QQ`` the result has integer entries, whose magnitudes can be limited by the value of ``upper_bound``. :: - sage: C=random_matrix(QQ, 5, algorithm='unimodular', upper_bound=70); C # random + sage: C = random_matrix(QQ, 5, algorithm='unimodular', upper_bound=70); C # random sage: det(C) 1 sage: C.base_ring() @@ -624,7 +629,7 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation We return an error for a bogus value of ``algorithm``:: - sage: random_matrix(ZZ, 5, algorithm = 'bogus') + sage: random_matrix(ZZ, 5, algorithm='bogus') Traceback (most recent call last): ... ValueError: random matrix algorithm "bogus" is not recognized @@ -748,6 +753,7 @@ def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True): NumPy arrays may be used as input. :: + sage: # needs numpy sage: import numpy sage: entries = numpy.array([1.2, 5.6]); entries array([1.2, 5.6]) @@ -758,6 +764,7 @@ def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True): sage: A.parent() Full MatrixSpace of 3 by 3 sparse matrices over Real Double Field + sage: # needs numpy sage: j = complex(0,1) sage: entries = numpy.array([2.0+j, 8.1, 3.4+2.6*j]); entries array([2. +1.j , 8.1+0.j , 3.4+2.6j]) @@ -768,6 +775,7 @@ def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True): sage: A.parent() Full MatrixSpace of 3 by 3 sparse matrices over Complex Double Field + sage: # needs numpy sage: entries = numpy.array([4, 5, 6]) sage: A = diagonal_matrix(entries); A [4 0 0] @@ -776,8 +784,8 @@ def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True): sage: A.parent() Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring - sage: entries = numpy.array([4.1, 5.2, 6.3]) - sage: A = diagonal_matrix(ZZ, entries); A + sage: entries = numpy.array([4.1, 5.2, 6.3]) # needs numpy + sage: A = diagonal_matrix(ZZ, entries); A # needs numpy Traceback (most recent call last): ... TypeError: unable to convert 4.1 to an element of Integer Ring @@ -819,7 +827,7 @@ def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True): Types for the entries need to be iterable (tuple, list, vector, NumPy array, etc):: - sage: diagonal_matrix(x^2) + sage: diagonal_matrix(x^2) # needs sage.symbolic Traceback (most recent call last): ... TypeError: 'sage.symbolic.expression.Expression' object is not iterable @@ -852,8 +860,14 @@ def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True): entries = arg0 # sanity check for entries - from numpy import ndarray - if not isinstance(entries, (list, tuple, ndarray)): + types = (list, tuple) + try: + from numpy import ndarray + except ImportError: + pass + else: + types += (ndarray,) + if not isinstance(entries, types): entries = list(entries) # Reconcile matrix size and number of entries @@ -1275,14 +1289,18 @@ def elementary_matrix(arg0, arg1=None, **kwds): sage: E.parent() Full MatrixSpace of 4 by 4 dense matrices over Rational Field + sage: # needs sage.symbolic sage: E = elementary_matrix(4, row1=1, scale=I) sage: E.parent() - Full MatrixSpace of 4 by 4 dense matrices over Number Field in I with defining polynomial x^2 + 1 with I = 1*I + Full MatrixSpace of 4 by 4 dense matrices over + Number Field in I with defining polynomial x^2 + 1 with I = 1*I + sage: # needs sage.rings.complex_double sage.symbolic sage: E = elementary_matrix(4, row1=1, scale=CDF(I)) sage: E.parent() Full MatrixSpace of 4 by 4 dense matrices over Complex Double Field + sage: # needs sage.rings.number_field sage.symbolic sage: E = elementary_matrix(4, row1=1, scale=QQbar(I)) sage: E.parent() Full MatrixSpace of 4 by 4 dense matrices over Algebraic Field @@ -1500,7 +1518,7 @@ def circulant(v, sparse=None): EXAMPLES:: - sage: v=[1,2,3,4,8] + sage: v = [1,2,3,4,8] sage: matrix.circulant(v) [1 2 3 4 8] [8 1 2 3 4] @@ -1546,7 +1564,7 @@ def _determine_block_matrix_grid(sub_matrices): Non-zero scalars are considered to be square matrices of any size, and zeroes are considered to be zero matrices of any size. - A ValueError is raised if there is insufficient or + A :class:`ValueError` is raised if there is insufficient or conflicting information. TESTS:: @@ -1905,6 +1923,12 @@ def block_matrix(*args, **kwds): sage: block_matrix(A) [ 3 5] [ 8 13] + sage: block_matrix([[A, 0r], [1r, A]]) + [ 3 5| 0 0] + [ 8 13| 0 0] + [-----+-----] + [ 1 0| 3 5] + [ 0 1| 8 13] """ args = list(args) sparse = kwds.get('sparse', None) @@ -2020,7 +2044,7 @@ def block_matrix(*args, **kwds): ring = ZZ for row in sub_matrices: for M in row: - R = M.base_ring() if is_Matrix(M) else M.parent() + R = M.base_ring() if is_Matrix(M) else parent(M) if R is not ZZ: ring = sage.categories.pushout.pushout(ring, R) @@ -2261,14 +2285,16 @@ def companion_matrix(poly, format='right'): [ 1 0 -8] [ 0 1 4] + sage: # needs sage.symbolic sage: y = var('y') - sage: q = y^3 -2*y + 1 + sage: q = y^3 - 2*y + 1 sage: companion_matrix(q) Traceback (most recent call last): ... - TypeError: input must be a polynomial (not a symbolic expression, see docstring), or other iterable, not y^3 - 2*y + 1 - - sage: coeff_list = [q(y=0)] + [q.coefficient(y^k) for k in range(1, q.degree(y)+1)] + TypeError: input must be a polynomial (not a symbolic expression, see docstring), + or other iterable, not y^3 - 2*y + 1 + sage: coeff_list = [q(y=0)] + [q.coefficient(y^k) + ....: for k in range(1, q.degree(y) + 1)] sage: coeff_list [1, -2, 0, 1] sage: companion_matrix(coeff_list) @@ -2284,9 +2310,9 @@ def companion_matrix(poly, format='right'): sage: t = polygen(QQ, 't') sage: p = t^12 - 7*t^4 + 28*t^2 - 456 sage: C = companion_matrix(p, format='top') - sage: q = C.minpoly(var='t'); q + sage: q = C.minpoly(var='t'); q # needs sage.libs.pari t^12 - 7*t^4 + 28*t^2 - 456 - sage: p == q + sage: p == q # needs sage.libs.pari True sage: p = t^3 + 3*t - 8 @@ -2295,9 +2321,9 @@ def companion_matrix(poly, format='right'): ....: companion_matrix(p^2), ....: companion_matrix(q), ....: companion_matrix(q) ) - sage: A.charpoly(var='t').factor() + sage: A.charpoly(var='t').factor() # needs sage.libs.pari (t^3 + 3*t - 8)^3 * (t^5 + t - 17)^2 - sage: A.minpoly(var='t').factor() + sage: A.minpoly(var='t').factor() # needs sage.libs.pari (t^3 + 3*t - 8)^2 * (t^5 + t - 17) TESTS:: @@ -2307,18 +2333,20 @@ def companion_matrix(poly, format='right'): ... ValueError: format must be 'right', 'left', 'top' or 'bottom', not junk - sage: companion_matrix(sin(x)) + sage: companion_matrix(sin(x)) # needs sage.symbolic Traceback (most recent call last): ... - TypeError: input must be a polynomial (not a symbolic expression, see docstring), or other iterable, not sin(x) + TypeError: input must be a polynomial (not a symbolic expression, see docstring), + or other iterable, not sin(x) sage: companion_matrix([2, 3, 896]) Traceback (most recent call last): ... - ValueError: polynomial (or the polynomial implied by coefficients) must be monic, not a leading coefficient of 896 + ValueError: polynomial (or the polynomial implied by coefficients) must be monic, + not a leading coefficient of 896 - sage: F.<a> = GF(2^2) - sage: companion_matrix([4/3, a+1, 1]) + sage: F.<a> = GF(2^2) # needs sage.rings.finite_rings + sage: companion_matrix([4/3, a+1, 1]) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: unable to find common ring for coefficients from polynomial @@ -2411,7 +2439,7 @@ def random_rref_matrix(parent, num_pivots): sage: from sage.matrix.constructor import random_rref_matrix sage: matrix_space = sage.matrix.matrix_space.MatrixSpace(QQ, 5, 6) - sage: A = random_rref_matrix(matrix_space, num_pivots=4); A # random + sage: A = random_rref_matrix(matrix_space, num_pivots=4); A # random [ 1 0 0 -6 0 -3] [ 0 1 0 2 0 3] [ 0 0 1 -4 0 -2] @@ -2430,10 +2458,11 @@ def random_rref_matrix(parent, num_pivots): Matrices can be generated over other exact rings. :: - sage: B = random_matrix(FiniteField(7), 4, 4, algorithm='echelon_form', num_pivots=3); B # random + sage: B = random_matrix(FiniteField(7), 4, 4, # random + ....: algorithm='echelon_form', num_pivots=3); B [1 0 0 0] [0 1 0 6] - [0 0 1 4] + [0 0 1 1] [0 0 0 0] sage: B.rank() == 3 True @@ -2596,14 +2625,14 @@ def random_echelonizable_matrix(parent, rank, upper_bound=None, max_tries=100): sage: A = random_echelonizable_matrix(matrix_space, rank=4, upper_bound=40) sage: A.rank() 4 - sage: max(map(abs,A.list()))<40 + sage: max(map(abs,A.list())) < 40 True sage: A.rref() == A.rref().change_ring(ZZ) True An example with default settings (i.e. no entry size control). :: - sage: C=random_matrix(QQ, 6, 7, algorithm='echelonizable', rank=5) + sage: C = random_matrix(QQ, 6, 7, algorithm='echelonizable', rank=5) sage: C.rank() 5 sage: C.rref() == C.rref().change_ring(ZZ) @@ -2611,7 +2640,7 @@ def random_echelonizable_matrix(parent, rank, upper_bound=None, max_tries=100): A matrix without size control may have very large entry sizes. :: - sage: D=random_matrix(ZZ, 7, 8, algorithm='echelonizable', rank=6); D # random + sage: D = random_matrix(ZZ, 7, 8, algorithm='echelonizable', rank=6); D # random [ 1 2 8 -35 -178 -239 -284 778] [ 4 9 37 -163 -827 -1111 -1324 3624] [ 5 6 21 -88 -454 -607 -708 1951] @@ -2622,8 +2651,10 @@ def random_echelonizable_matrix(parent, rank, upper_bound=None, max_tries=100): Matrices can be generated over any exact ring. :: - sage: F.<a>=GF(2^3) - sage: B = random_matrix(F, 4, 5, algorithm='echelonizable', rank=4, upper_bound=None) + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF(2^3) + sage: B = random_matrix(F, 4, 5, algorithm='echelonizable', rank=4, + ....: upper_bound=None) sage: B.rank() 4 sage: B.base_ring() is F @@ -2665,7 +2696,7 @@ def random_echelonizable_matrix(parent, rank, upper_bound=None, max_tries=100): Works for rank==1, too. :: - sage: random_matrix( QQ, 3, 3, algorithm='echelonizable', rank=1).ncols() + sage: random_matrix(QQ, 3, 3, algorithm='echelonizable', rank=1).ncols() 3 @@ -2835,11 +2866,11 @@ def random_subspaces_matrix(parent, rank=None): (5, 7) sage: all(x in ZZ for x in A.list()) True - sage: A_expanded=A.augment(identity_matrix(5)).rref() + sage: A_expanded = A.augment(identity_matrix(5)).rref() sage: all(x in ZZ for x in A_expanded.list()) True - sage: C = A_expanded.submatrix(0,0,A.nrows()-A.nullity(), A.ncols()) - sage: L = A_expanded.submatrix(A.nrows()-A.nullity(), A.ncols()) + sage: C = A_expanded.submatrix(0, 0, A.nrows() - A.nullity(), A.ncols()) + sage: L = A_expanded.submatrix(A.nrows() - A.nullity(), A.ncols()) sage: A.right_kernel() == C.right_kernel() True sage: A.row_space() == C.row_space() @@ -2966,8 +2997,9 @@ def random_unimodular_matrix(parent, upper_bound=None, max_tries=100): A matrix over the number Field in `y` with defining polynomial `y^2-2y-2`. :: - sage: y = var('y') - sage: K = NumberField(y^2-2*y-2, 'y') + sage: # needs sage.rings.number_field + sage: y = polygen(ZZ, 'y') + sage: K = NumberField(y^2 - 2*y - 2, 'y') sage: C = random_matrix(K, 3, algorithm='unimodular') sage: det(C) 1 @@ -2985,8 +3017,8 @@ def random_unimodular_matrix(parent, upper_bound=None, max_tries=100): Only matrices over ZZ and QQ can have size control. :: - sage: F.<a>=GF(5^7) - sage: random_matrix(F, 5, algorithm='unimodular', upper_bound=20) + sage: F.<a> = GF(5^7) # needs sage.rings.finite_rings + sage: random_matrix(F, 5, algorithm='unimodular', upper_bound=20) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: only matrices over ZZ or QQ can have size control. @@ -3022,11 +3054,11 @@ def random_diagonalizable_matrix(parent,eigenvalues=None,dimensions=None): If eigenvalues and dimensions are not specified in a list, they will be assigned randomly. - - ``parent`` - the desired size of the square matrix. + - ``parent`` -- the desired size of the square matrix. - - ``eigenvalues`` - the list of desired eigenvalues (default=None). + - ``eigenvalues`` -- the list of desired eigenvalues (default=None). - - ``dimensions`` - the list of dimensions corresponding to each + - ``dimensions`` -- the list of dimensions corresponding to each eigenspace (default=None). OUTPUT: @@ -3050,6 +3082,8 @@ def random_diagonalizable_matrix(parent,eigenvalues=None,dimensions=None): sage: from sage.matrix.constructor import random_diagonalizable_matrix sage: matrix_space = sage.matrix.matrix_space.MatrixSpace(QQ, 5) sage: A = random_diagonalizable_matrix(matrix_space) + + sage: # needs sage.rings.number_field sage: eigenvalues = A.eigenvalues() sage: S = A.right_eigenmatrix()[1] sage: eigenvalues2 = (S.inverse()*A*S).diagonal() @@ -3061,13 +3095,16 @@ def random_diagonalizable_matrix(parent,eigenvalues=None,dimensions=None): entries would all be integers. :: sage: eigenvalues = [ZZ.random_element() for _ in range(3)] - sage: B = random_matrix(QQ, 6, algorithm='diagonalizable', eigenvalues=eigenvalues, dimensions=[2,3,1]) + sage: B = random_matrix(QQ, 6, algorithm='diagonalizable', + ....: eigenvalues=eigenvalues, dimensions=[2,3,1]) sage: all(x in ZZ for x in (B-(-12*identity_matrix(6))).rref().list()) True sage: all(x in ZZ for x in (B-(4*identity_matrix(6))).rref().list()) True sage: all(x in ZZ for x in (B-(6*identity_matrix(6))).rref().list()) True + + sage: # needs sage.rings.number_field sage: S = B.right_eigenmatrix()[1] sage: eigenvalues2 = (S.inverse()*B*S).diagonal() sage: all(e in eigenvalues for e in eigenvalues2) @@ -3077,7 +3114,8 @@ def random_diagonalizable_matrix(parent,eigenvalues=None,dimensions=None): Eigenvalues must all be integers. :: - sage: random_matrix(QQ,3,algorithm='diagonalizable', eigenvalues=[2+I,2-I,2],dimensions=[1,1,1]) + sage: random_matrix(QQ, 3, algorithm='diagonalizable', # needs sage.symbolic + ....: eigenvalues=[2+I, 2-I, 2], dimensions=[1,1,1]) Traceback (most recent call last): ... TypeError: eigenvalues must be integers. @@ -3253,15 +3291,16 @@ def vector_on_axis_rotation_matrix(v, i, ring=None): sage: from sage.matrix.constructor import vector_on_axis_rotation_matrix sage: v = vector((1,2,3)) - sage: vector_on_axis_rotation_matrix(v, 2) * v + sage: vector_on_axis_rotation_matrix(v, 2) * v # needs sage.symbolic (0, 0, sqrt(14)) - sage: vector_on_axis_rotation_matrix(v, 1) * v + sage: vector_on_axis_rotation_matrix(v, 1) * v # needs sage.symbolic (0, sqrt(14), 0) - sage: vector_on_axis_rotation_matrix(v, 0) * v + sage: vector_on_axis_rotation_matrix(v, 0) * v # needs sage.symbolic (sqrt(14), 0, 0) :: + sage: # needs sage.symbolic sage: x,y = var('x,y') sage: v = vector((x,y)) sage: vector_on_axis_rotation_matrix(v, 1) @@ -3278,7 +3317,7 @@ def vector_on_axis_rotation_matrix(v, i, ring=None): :: sage: v = vector((1,2,3,4)) - sage: vector_on_axis_rotation_matrix(v, 0) * v + sage: vector_on_axis_rotation_matrix(v, 0) * v # needs sage.symbolic (sqrt(30), 0, 0, 0) sage: vector_on_axis_rotation_matrix(v, 0, ring=RealField(10)) [ 0.18 0.37 0.55 0.73] @@ -3323,35 +3362,35 @@ def ith_to_zero_rotation_matrix(v, i, ring=None): sage: from sage.matrix.constructor import ith_to_zero_rotation_matrix sage: v = vector((1,2,3)) - sage: ith_to_zero_rotation_matrix(v, 2) + sage: ith_to_zero_rotation_matrix(v, 2) # needs sage.symbolic [ 1 0 0] [ 0 2/13*sqrt(13) 3/13*sqrt(13)] [ 0 -3/13*sqrt(13) 2/13*sqrt(13)] - sage: ith_to_zero_rotation_matrix(v, 2) * v + sage: ith_to_zero_rotation_matrix(v, 2) * v # needs sage.symbolic (1, sqrt(13), 0) :: - sage: ith_to_zero_rotation_matrix(v, 0) + sage: ith_to_zero_rotation_matrix(v, 0) # needs sage.symbolic [ 3/10*sqrt(10) 0 -1/10*sqrt(10)] [ 0 1 0] [ 1/10*sqrt(10) 0 3/10*sqrt(10)] - sage: ith_to_zero_rotation_matrix(v, 1) + sage: ith_to_zero_rotation_matrix(v, 1) # needs sage.symbolic [ 1/5*sqrt(5) 2/5*sqrt(5) 0] [-2/5*sqrt(5) 1/5*sqrt(5) 0] [ 0 0 1] - sage: ith_to_zero_rotation_matrix(v, 2) + sage: ith_to_zero_rotation_matrix(v, 2) # needs sage.symbolic [ 1 0 0] [ 0 2/13*sqrt(13) 3/13*sqrt(13)] [ 0 -3/13*sqrt(13) 2/13*sqrt(13)] :: - sage: ith_to_zero_rotation_matrix(v, 0) * v + sage: ith_to_zero_rotation_matrix(v, 0) * v # needs sage.symbolic (0, 2, sqrt(10)) - sage: ith_to_zero_rotation_matrix(v, 1) * v + sage: ith_to_zero_rotation_matrix(v, 1) * v # needs sage.symbolic (sqrt(5), 0, 3) - sage: ith_to_zero_rotation_matrix(v, 2) * v + sage: ith_to_zero_rotation_matrix(v, 2) * v # needs sage.symbolic (1, sqrt(13), 0) Other ring:: @@ -3367,6 +3406,7 @@ def ith_to_zero_rotation_matrix(v, i, ring=None): On the symbolic ring:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: v = vector((x,y,z)) sage: ith_to_zero_rotation_matrix(v, 2) @@ -3472,7 +3512,7 @@ def vandermonde(v, ring=None): A Vandermonde matrix of order three over the symbolic ring:: - sage: matrix.vandermonde(SR.var(['x0', 'x1', 'x2'])) + sage: matrix.vandermonde(SR.var(['x0', 'x1', 'x2'])) # needs sage.symbolic [ 1 x0 x0^2] [ 1 x1 x1^2] [ 1 x2 x2^2] @@ -3559,7 +3599,7 @@ def hankel(c, r=None, ring=None): A Hankel matrix with symbolic entries:: - sage: matrix.hankel(SR.var('a, b, c, d, e')) + sage: matrix.hankel(SR.var('a, b, c, d, e')) # needs sage.symbolic [a b c d e] [b c d e 0] [c d e 0 0] @@ -3568,7 +3608,7 @@ def hankel(c, r=None, ring=None): We can also pass the elements of the last row, starting at the second column:: - sage: matrix.hankel(SR.var('a, b, c, d, e'), SR.var('f, g, h, i')) + sage: matrix.hankel(SR.var('a, b, c, d, e'), SR.var('f, g, h, i')) # needs sage.symbolic [a b c d e] [b c d e f] [c d e f g] diff --git a/src/sage/matrix/strassen.pyx b/src/sage/matrix/strassen.pyx index ab392d66cb1..13a8c152fd9 100644 --- a/src/sage/matrix/strassen.pyx +++ b/src/sage/matrix/strassen.pyx @@ -48,6 +48,7 @@ def strassen_window_multiply(C, A,B, cutoff): """ strassen_window_multiply_c(C, A, B, cutoff) + cdef strassen_window_multiply_c(MatrixWindow C, MatrixWindow A, MatrixWindow B, Py_ssize_t cutoff): # todo -- I'm not sure how to interpret "cutoff". Should it be... @@ -97,7 +98,6 @@ cdef strassen_window_multiply_c(MatrixWindow C, MatrixWindow A, cdef MatrixWindow S0, S1, S2, S3, T0, T1 ,T2, T3, P0, P1, P2, P3, P4, P5, P6, U0, U1, U2, U3, U4, U5, U6 cdef MatrixWindow X, Y - cdef Py_ssize_t tmp_cols, start_row X = A.new_empty_window(A_sub_nrows, max(A_sub_ncols,B_sub_ncols)) Y = B.new_empty_window(A_sub_ncols, B_sub_ncols) @@ -253,13 +253,11 @@ def strassen_echelon(MatrixWindow A, cutoff): INPUT: - - ``A`` - matrix window - ``cutoff`` - size at which algorithm reverts to naive Gaussian elimination and multiplication must be at least 1. - OUTPUT: The list of pivot columns EXAMPLES:: @@ -312,6 +310,7 @@ def strassen_echelon(MatrixWindow A, cutoff): strassen_echelon_c(A, cutoff, A._matrix._strassen_default_cutoff(A._matrix)) sig_off() + cdef strassen_echelon_c(MatrixWindow A, Py_ssize_t cutoff, Py_ssize_t mul_cutoff): # The following notation will be used in the comments below, which should be understood to give # the general idea of what's going on, as if there were no inconvenient non-pivot columns. diff --git a/src/sage/matrix/symplectic_basis.py b/src/sage/matrix/symplectic_basis.py index 4caee7a6da6..66dc1883a12 100644 --- a/src/sage/matrix/symplectic_basis.py +++ b/src/sage/matrix/symplectic_basis.py @@ -188,7 +188,12 @@ def symplectic_basis_over_field(M): An example over a finite field:: - sage: E = matrix(GF(7), 8, 8, [0, -1/2, -2, 1/2, 2, 0, -2, 1, 1/2, 0, -1, -3, 0, 2, 5/2, -3, 2, 1, 0, 3/2, -1, 0, -1, -2, -1/2, 3, -3/2, 0, 1, 3/2, -1/2, -1/2, -2, 0, 1, -1, 0, 0, 1, -1, 0, -2, 0, -3/2, 0, 0, 1/2, -2, 2, -5/2, 1, 1/2, -1, -1/2, 0, -1, -1, 3, 2, 1/2, 1, 2, 1, 0]); E + sage: E = matrix(GF(7), 8, 8, + ....: [0, -1/2, -2, 1/2, 2, 0, -2, 1, 1/2, 0, -1, -3, 0, 2, 5/2, + ....: -3, 2, 1, 0, 3/2, -1, 0, -1, -2, -1/2, 3, -3/2, 0, 1, 3/2, + ....: -1/2, -1/2, -2, 0, 1, -1, 0, 0, 1, -1, 0, -2, 0, -3/2, 0, + ....: 0, 1/2, -2, 2, -5/2, 1, 1/2, -1, -1/2, 0, -1, -1, 3, 2, + ....: 1/2, 1, 2, 1, 0]); E [0 3 5 4 2 0 5 1] [4 0 6 4 0 2 6 4] [2 1 0 5 6 0 6 5] @@ -211,7 +216,11 @@ def symplectic_basis_over_field(M): The tricky case of characteristic 2:: - sage: E = matrix(GF(2), 8, 8, [0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0]); E + sage: E = matrix(GF(2), 8, 8, + ....: [0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + ....: 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, + ....: 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, + ....: 0, 1, 0, 0]); E [0 0 1 1 0 1 0 1] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 1 1] diff --git a/src/sage/matrix/tests.py b/src/sage/matrix/tests.py index 21b7920307a..9208a5d4d72 100644 --- a/src/sage/matrix/tests.py +++ b/src/sage/matrix/tests.py @@ -11,7 +11,7 @@ Vector space of degree 1 and dimension 1 over Rational Field Basis matrix: [1] - sage: matrix(GF(7),1,0).kernel() + sage: matrix(GF(7), 1, 0).kernel() Vector space of degree 1 and dimension 1 over Finite Field of size 7 Basis matrix: [1] @@ -28,7 +28,7 @@ Vector space of degree 0 and dimension 0 over Rational Field Basis matrix: [] - sage: matrix(GF(7),0,1).kernel() + sage: matrix(GF(7), 0, 1).kernel() Vector space of degree 0 and dimension 0 over Finite Field of size 7 Basis matrix: [] @@ -45,7 +45,7 @@ sage: matrix(QQ, 2, 2, [1, 1, 1, 1]) / (1/2) [2 2] [2 2] - sage: matrix(QQ['x,y'], 2, 2, [1, 1, 1, 1]) / x + sage: matrix(QQ['x,y'], 2, 2, [1, 1, 1, 1]) / x # needs sage.symbolic [1/x 1/x] [1/x 1/x] sage: A = matrix(CC, 2, 2, [1, 1, 1, 1]) / I; A diff --git a/src/sage/matroids/__init__.py b/src/sage/matroids/__init__.py deleted file mode 100644 index 39cf60e3a53..00000000000 --- a/src/sage/matroids/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - -__all__ = ["all"] diff --git a/src/sage/matroids/advanced.py b/src/sage/matroids/advanced.py index 83cfb912a77..b38075bb39c 100644 --- a/src/sage/matroids/advanced.py +++ b/src/sage/matroids/advanced.py @@ -59,4 +59,6 @@ from . import lean_matrix from .extension import LinearSubclasses, MatroidExtensions from .union_matroid import MatroidUnion, MatroidSum, PartitionMatroid -from .graphic_matroid import GraphicMatroid + +from sage.misc.lazy_import import lazy_import +lazy_import('sage.matroids.graphic_matroid', 'GraphicMatroid') diff --git a/src/sage/matroids/basis_exchange_matroid.pxd b/src/sage/matroids/basis_exchange_matroid.pxd index aec3bb54c42..28cc7ad868c 100644 --- a/src/sage/matroids/basis_exchange_matroid.pxd +++ b/src/sage/matroids/basis_exchange_matroid.pxd @@ -15,13 +15,13 @@ cdef class BasisExchangeMatroid(Matroid): cdef _weak_invariant_var, _strong_invariant_var, _heuristic_invariant_var cdef SetSystem _weak_partition_var, _strong_partition_var, _heuristic_partition_var - cdef __relabel(self, l) + cdef _relabel(self, l) - cdef __pack(self, bitset_t, X) + cdef _pack(self, bitset_t, X) cdef __unpack(self, bitset_t) - cdef bint __is_exchange_pair(self, long x, long y) except -1 - cdef int __exchange(self, long x, long y) except -1 - cdef int __move(self, bitset_t X, bitset_t Y) except -1 + cdef bint _is_exchange_pair(self, long x, long y) except -1 + cdef int _exchange(self, long x, long y) except -1 + cdef int _move(self, bitset_t X, bitset_t Y) except -1 cdef __fundamental_cocircuit(self, bitset_t, long x) cdef __fundamental_circuit(self, bitset_t, long y) @@ -30,7 +30,7 @@ cdef class BasisExchangeMatroid(Matroid): cdef __closure(self, bitset_t, bitset_t) cdef __max_coindependent(self, bitset_t, bitset_t) cdef __cocircuit(self, bitset_t, bitset_t) - cdef __coclosure(self, bitset_t, bitset_t) + cdef _coclosure_internal(self, bitset_t, bitset_t) cdef __augment(self, bitset_t, bitset_t, bitset_t) cdef bint __is_independent(self, bitset_t F) except -1 diff --git a/src/sage/matroids/basis_exchange_matroid.pyx b/src/sage/matroids/basis_exchange_matroid.pyx index 5679814d32b..015fa8b8df3 100644 --- a/src/sage/matroids/basis_exchange_matroid.pyx +++ b/src/sage/matroids/basis_exchange_matroid.pyx @@ -41,9 +41,6 @@ Methods from .matroid cimport Matroid from .set_system cimport SetSystem -from copy import copy -from itertools import combinations, permutations - from sage.data_structures.bitset_base cimport * cdef class BasisExchangeMatroid(Matroid): @@ -60,10 +57,10 @@ cdef class BasisExchangeMatroid(Matroid): This base exchange graph is not stored as such, but should be provided implicitly by the child class in the form of two methods - ``__is_exchange_pair(x, y)`` and ``__exchange(x, y)``, as well as an + ``_is_exchange_pair(x, y)`` and ``_exchange(x, y)``, as well as an initial basis. At any moment, BasisExchangeMatroid keeps a current basis - `B`. The method ``__is_exchange_pair(x, y)`` should return a boolean - indicating whether `B - x + y` is a basis. The method ``__exchange(x, y)`` + `B`. The method ``_is_exchange_pair(x, y)`` should return a boolean + indicating whether `B - x + y` is a basis. The method ``_exchange(x, y)`` is called when the current basis `B` is replaced by said `B-x + y`. It is up to the child class to update its internal data structure to make information relative to the new basis more accessible. For instance, a @@ -84,16 +81,16 @@ cdef class BasisExchangeMatroid(Matroid): - :class:`BasisMatroid <sage.matroids.basis_matroid.BasisMatroid>`: keeps a list of all bases. - - ``__is_exchange_pair(x, y)`` reduces to a query whether `B - x + y` + - ``_is_exchange_pair(x, y)`` reduces to a query whether `B - x + y` is a basis. - - ``__exchange(x, y)`` has no work to do. + - ``_exchange(x, y)`` has no work to do. - :class:`LinearMatroid <sage.matroids.linear_matroid.LinearMatroid>`: keeps a matrix representation `A` of the matroid so that `A[B] = I`. - - ``__is_exchange_pair(x, y)`` reduces to testing whether `A[r, y]` + - ``_is_exchange_pair(x, y)`` reduces to testing whether `A[r, y]` is nonzero, where `A[r, x]=1`. - - ``__exchange(x, y)`` should modify the matrix so that `A[B - x + y]` + - ``_exchange(x, y)`` should modify the matrix so that `A[B - x + y]` becomes `I`, which means pivoting on `A[r, y]`. - ``TransversalMatroid`` (not yet implemented): If `A` is a set of subsets @@ -103,17 +100,17 @@ cdef class BasisExchangeMatroid(Matroid): edge `(A_i,e)` if `e` is in the subset `A_i`. At any time you keep a maximum matching `M` of `G` covering the current basis `B`. - - ``__is_exchange_pair(x, y)`` checks for the existence of an + - ``_is_exchange_pair(x, y)`` checks for the existence of an `M`-alternating path `P` from `y` to `x`. - - ``__exchange(x, y)`` replaces `M` by the symmetric difference of + - ``_exchange(x, y)`` replaces `M` by the symmetric difference of `M` and `E(P)`. - ``AlgebraicMatroid`` (not yet implemented): keeps a list of polynomials in variables `E - B + e` for each variable `e` in `B`. - - ``__is_exchange_pair(x, y)`` checks whether the polynomial that + - ``_is_exchange_pair(x, y)`` checks whether the polynomial that relates `y` to `E-B` uses `x`. - - ``__exchange(x, y)`` make new list of polynomials by computing + - ``_exchange(x, y)`` make new list of polynomials by computing resultants. All but the first of the above matroids are algebraic, and all @@ -142,7 +139,7 @@ cdef class BasisExchangeMatroid(Matroid): This initializer sets up a correspondence between elements of ``groundset`` and ``range(len(groundset))``. ``BasisExchangeMatroid`` uses this correspondence for encoding of subsets of the groundset as - bitpacked sets of integers --- see ``__pack()`` and ``__unpack()``. In + bitpacked sets of integers --- see ``_pack()`` and ``__unpack()``. In general, methods of ``BasisExchangeMatroid`` having a name starting with two underscores deal with such encoded subsets. @@ -179,11 +176,11 @@ cdef class BasisExchangeMatroid(Matroid): self._E = groundset self._idx = {} cdef long i - for i in xrange(self._groundset_size): + for i in range(self._groundset_size): self._idx[self._E[i]] = i if basis is not None: - self.__pack(self._current_basis, frozenset(basis)) + self._pack(self._current_basis, frozenset(basis)) def __dealloc__(self): bitset_free(self._current_basis) @@ -194,7 +191,7 @@ cdef class BasisExchangeMatroid(Matroid): bitset_free(self._output) bitset_free(self._temp) - cdef __relabel(self, l): + cdef _relabel(self, l): """ Relabel each element `e` as `l[e]`, where `l` is a given injective map. @@ -222,7 +219,7 @@ cdef class BasisExchangeMatroid(Matroid): self._groundset = frozenset(E) self._idx = {} - for i in xrange(self._groundset_size): + for i in range(self._groundset_size): self._idx[self._E[i]] = i if self._weak_partition_var: @@ -234,7 +231,7 @@ cdef class BasisExchangeMatroid(Matroid): self._heuristic_partition_var._relabel(l) # the engine - cdef __pack(self, bitset_t I, F): + cdef _pack(self, bitset_t I, F): """ Encode a subset F of the groundset into a bitpacked set of integers """ @@ -255,21 +252,21 @@ cdef class BasisExchangeMatroid(Matroid): return frozenset(F) # this method needs to be overridden by child class - cdef bint __is_exchange_pair(self, long x, long y) except -1: + cdef bint _is_exchange_pair(self, long x, long y) except -1: """ Test if current_basis-x + y is a basis """ raise NotImplementedError # if this method is overridden by a child class, the child class needs to call this method - cdef int __exchange(self, long x, long y) except -1: + cdef int _exchange(self, long x, long y) except -1: """ put current_basis <-- current_basis-x + y """ bitset_discard(self._current_basis, x) bitset_add(self._current_basis, y) - cdef int __move(self, bitset_t X, bitset_t Y) except -1: + cdef int _move(self, bitset_t X, bitset_t Y) except -1: """ Change current_basis to minimize intersection with ``X``, maximize intersection with ``Y``. """ @@ -278,8 +275,8 @@ cdef class BasisExchangeMatroid(Matroid): while x >= 0: y = bitset_first(Y) while y >= 0: - if self.__is_exchange_pair(x, y): - self.__exchange(x, y) + if self._is_exchange_pair(x, y): + self._exchange(x, y) bitset_discard(Y, y) bitset_discard(X, x) if bitset_isempty(Y): @@ -298,7 +295,7 @@ cdef class BasisExchangeMatroid(Matroid): bitset_complement(self._temp, self._current_basis) y = bitset_first(self._temp) while y >= 0: - if self.__is_exchange_pair(x, y): + if self._is_exchange_pair(x, y): bitset_add(C, y) y = bitset_next(self._temp, y + 1) bitset_add(C, x) @@ -311,7 +308,7 @@ cdef class BasisExchangeMatroid(Matroid): bitset_clear(C) x = bitset_first(self._current_basis) while x >= 0: - if self.__is_exchange_pair(x, y): + if self._is_exchange_pair(x, y): bitset_add(C, x) x = bitset_next(self._current_basis, x + 1) bitset_add(C, y) @@ -322,7 +319,7 @@ cdef class BasisExchangeMatroid(Matroid): """ bitset_difference(self._inside, self._current_basis, F) bitset_difference(self._outside, F, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) bitset_intersection(R, self._current_basis, F) cdef __circuit(self, bitset_t R, bitset_t F): @@ -338,8 +335,8 @@ cdef class BasisExchangeMatroid(Matroid): while y >= 0: x = bitset_first(self._inside) while x >= 0: - if self.__is_exchange_pair(x, y): - self.__exchange(x, y) + if self._is_exchange_pair(x, y): + self._exchange(x, y) bitset_discard(self._outside, y) bitset_discard(self._inside, x) if bitset_isempty(self._outside): @@ -358,7 +355,7 @@ cdef class BasisExchangeMatroid(Matroid): """ bitset_difference(self._inside, self._current_basis, F) bitset_difference(self._outside, F, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) bitset_set_first_n(R, self._groundset_size) cdef long x = bitset_first(self._inside) while x >= 0: @@ -373,7 +370,7 @@ cdef class BasisExchangeMatroid(Matroid): bitset_complement(R, F) bitset_difference(self._inside, self._current_basis, R) bitset_difference(self._outside, R, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) bitset_difference(R, F, self._current_basis) cdef __cocircuit(self, bitset_t R, bitset_t F): @@ -390,8 +387,8 @@ cdef class BasisExchangeMatroid(Matroid): while x >= 0: y = bitset_first(self._outside) while y >= 0: - if self.__is_exchange_pair(x, y): - self.__exchange(x, y) + if self._is_exchange_pair(x, y): + self._exchange(x, y) bitset_discard(self._outside, y) bitset_discard(self._inside, x) if bitset_isempty(self._inside): @@ -404,14 +401,14 @@ cdef class BasisExchangeMatroid(Matroid): return x = bitset_next(self._inside, x + 1) - cdef __coclosure(self, bitset_t R, bitset_t F): + cdef _coclosure_internal(self, bitset_t R, bitset_t F): """ Bitpacked version of ``closure``. """ bitset_complement(R, F) bitset_difference(self._inside, self._current_basis, R) bitset_difference(self._outside, R, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) bitset_set_first_n(R, self._groundset_size) cdef long y = bitset_first(self._outside) while y >= 0: @@ -425,10 +422,10 @@ cdef class BasisExchangeMatroid(Matroid): """ bitset_difference(self._inside, self._current_basis, X) bitset_difference(self._outside, X, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) bitset_difference(self._inside, self._inside, Y) bitset_difference(self._outside, Y, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) bitset_intersection(R, self._current_basis, Y) cdef bint __is_independent(self, bitset_t F) except -1: @@ -437,7 +434,7 @@ cdef class BasisExchangeMatroid(Matroid): """ bitset_difference(self._inside, self._current_basis, F) bitset_difference(self._outside, F, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) return bitset_isempty(self._outside) cdef __move_current_basis(self, bitset_t X, bitset_t Y): @@ -446,21 +443,21 @@ cdef class BasisExchangeMatroid(Matroid): """ bitset_difference(self._inside, self._current_basis, X) bitset_difference(self._outside, X, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) bitset_intersection(self._inside, self._current_basis, Y) bitset_complement(self._outside, self._current_basis) bitset_difference(self._outside, self._outside, Y) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) # functions for derived classes and for parent class cdef bint _set_current_basis(self, F): """ Set _current_basis to subset of the groundset ``F``. """ - self.__pack(self._input, F) + self._pack(self._input, F) bitset_difference(self._inside, self._current_basis, self._input) bitset_difference(self._outside, self._input, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) return bitset_isempty(self._outside) and bitset_isempty(self._inside) # groundset and full_rank @@ -633,8 +630,8 @@ cdef class BasisExchangeMatroid(Matroid): ['b', 'c', 'e', 'f'] """ - self.__pack(self._input, X) - self.__pack(self._input2, Y) + self._pack(self._input, X) + self._pack(self._input2, Y) self.__move_current_basis(self._input, self._input2) cpdef _max_independent(self, F): @@ -664,7 +661,7 @@ cdef class BasisExchangeMatroid(Matroid): see :meth:`<sage.matroids.matroid.Matroid.max_independent>`. """ - self.__pack(self._input, F) + self._pack(self._input, F) self.__max_independent(self._output, self._input) return self.__unpack(self._output) @@ -695,7 +692,7 @@ cdef class BasisExchangeMatroid(Matroid): see :meth:`<sage.matroids.matroid.Matroid.rank>`. """ - self.__pack(self._input, F) + self._pack(self._input, F) self.__max_independent(self._output, self._input) return bitset_len(self._output) @@ -732,7 +729,7 @@ cdef class BasisExchangeMatroid(Matroid): the input is indeed a subset of the ground set, see :meth:`<sage.matroids.matroid.Matroid.circuit>`. """ - self.__pack(self._input, F) + self._pack(self._input, F) self.__circuit(self._output, self._input) return self.__unpack(self._output) @@ -757,7 +754,7 @@ cdef class BasisExchangeMatroid(Matroid): sage: sorted(M._fundamental_circuit('abcd', 'e')) ['a', 'b', 'c', 'e'] """ - self.__pack(self._input, B) + self._pack(self._input, B) bitset_clear(self._input2) self.__move_current_basis(self._input, self._input2) self.__fundamental_circuit(self._output, self._idx[e]) @@ -790,7 +787,7 @@ cdef class BasisExchangeMatroid(Matroid): :meth:`<sage.matroids.matroid.Matroid.closure>`. """ - self.__pack(self._input, F) + self._pack(self._input, F) self.__closure(self._output, self._input) return self.__unpack(self._output) @@ -821,7 +818,7 @@ cdef class BasisExchangeMatroid(Matroid): see :meth:`<sage.matroids.matroid.Matroid.max_coindependent>`. """ - self.__pack(self._input, F) + self._pack(self._input, F) self.__max_coindependent(self._output, self._input) return self.__unpack(self._output) @@ -851,7 +848,7 @@ cdef class BasisExchangeMatroid(Matroid): input is indeed a subset of the ground set, see :meth:`<sage.matroids.matroid.Matroid.corank>`. """ - self.__pack(self._input, F) + self._pack(self._input, F) self.__max_coindependent(self._output, self._input) return bitset_len(self._output) @@ -888,7 +885,7 @@ cdef class BasisExchangeMatroid(Matroid): input is indeed a subset of the ground set, see :meth:`<sage.matroids.matroid.Matroid.cocircuit>`. """ - self.__pack(self._input, F) + self._pack(self._input, F) self.__cocircuit(self._output, self._input) return self.__unpack(self._output) @@ -913,7 +910,7 @@ cdef class BasisExchangeMatroid(Matroid): sage: sorted(M._fundamental_cocircuit('efgh', 'e')) ['b', 'c', 'd', 'e'] """ - self.__pack(self._input, B) + self._pack(self._input, B) bitset_clear(self._input2) self.__move_current_basis(self._input, self._input2) self.__fundamental_cocircuit(self._output, self._idx[e]) @@ -946,8 +943,8 @@ cdef class BasisExchangeMatroid(Matroid): see :meth:`<sage.matroids.matroid.Matroid.coclosure>`. """ - self.__pack(self._input, F) - self.__coclosure(self._output, self._input) + self._pack(self._input, F) + self._coclosure_internal(self._output, self._input) return self.__unpack(self._output) cpdef _augment(self, X, Y): @@ -976,8 +973,8 @@ cdef class BasisExchangeMatroid(Matroid): ['e', 'f', 'g'] """ - self.__pack(self._input, X) - self.__pack(self._input2, Y) + self._pack(self._input, X) + self._pack(self._input2, Y) self.__augment(self._output, self._input, self._input2) return self.__unpack(self._output) @@ -1009,7 +1006,7 @@ cdef class BasisExchangeMatroid(Matroid): the input is indeed a subset of the ground set, see :meth:`<sage.matroids.matroid.Matroid.is_independent>`. """ - self.__pack(self._input, F) + self._pack(self._input, F) return self.__is_independent(self._input) # connectivity @@ -1093,7 +1090,7 @@ cdef class BasisExchangeMatroid(Matroid): bitset_free(loops) bitset_free(loop) bitset_free(active_rows) - for i in xrange(self.full_rank()): + for i in range(self.full_rank()): bitset_free(comp[i]) sig_free(comp) return res @@ -1145,8 +1142,8 @@ cdef class BasisExchangeMatroid(Matroid): cdef bitset_t SS, TT bitset_init(SS, self._groundset_size) bitset_init(TT, self._groundset_size) - self.__pack(SS,S) - self.__pack(TT,T) + self._pack(SS,S) + self._pack(TT,T) #F = set(self.groundset()) - (S | T) cdef bitset_t F, I bitset_init(F, self._groundset_size) @@ -1270,16 +1267,16 @@ cdef class BasisExchangeMatroid(Matroid): flats = <bitset_t*>sig_malloc((self.full_rank() + 1) * sizeof(bitset_t)) todo = <bitset_t*>sig_malloc((self.full_rank() + 1) * sizeof(bitset_t)) - for i in xrange(self.full_rank() + 1): + for i in range(self.full_rank() + 1): bitset_init(flats[i], self._bitset_size) bitset_init(todo[i], self._bitset_size) - f_vec = [0 for i in xrange(self.full_rank() + 1)] + f_vec = [0 for i in range(self.full_rank() + 1)] i = 0 bitset_clear(todo[0]) self.__closure(flats[0], todo[0]) bitset_complement(todo[0], flats[0]) self._f_vector_rec(f_vec, flats, todo, 0, 0) - for i in xrange(self.full_rank() + 1): + for i in range(self.full_rank() + 1): bitset_free(flats[i]) bitset_free(todo[i]) sig_free(flats) @@ -1343,7 +1340,7 @@ cdef class BasisExchangeMatroid(Matroid): flats = <bitset_t*>sig_malloc((r + 1) * sizeof(bitset_t)) todo = <bitset_t*>sig_malloc((r + 1) * sizeof(bitset_t)) - for i in xrange(r + 1): + for i in range(r + 1): bitset_init(flats[i], self._bitset_size) bitset_init(todo[i], self._bitset_size) Rflats = SetSystem(self._E) @@ -1352,7 +1349,7 @@ cdef class BasisExchangeMatroid(Matroid): self.__closure(flats[0], todo[0]) bitset_complement(todo[0], flats[0]) self._flats_rec(Rflats, r, flats, todo, 0, 0) - for i in xrange(r + 1): + for i in range(r + 1): bitset_free(flats[i]) bitset_free(todo[i]) sig_free(flats) @@ -1418,16 +1415,16 @@ cdef class BasisExchangeMatroid(Matroid): coflats = <bitset_t*>sig_malloc((r + 1) * sizeof(bitset_t)) todo = <bitset_t*>sig_malloc((r + 1) * sizeof(bitset_t)) - for i in xrange(r + 1): + for i in range(r + 1): bitset_init(coflats[i], self._bitset_size) bitset_init(todo[i], self._bitset_size) Rcoflats = SetSystem(self._E) i = 0 bitset_clear(todo[0]) - self.__coclosure(coflats[0], todo[0]) + self._coclosure_internal(coflats[0], todo[0]) bitset_complement(todo[0], coflats[0]) self._coflats_rec(Rcoflats, r, coflats, todo, 0, 0) - for i in xrange(r + 1): + for i in range(r + 1): bitset_free(coflats[i]) bitset_free(todo[i]) sig_free(coflats) @@ -1446,7 +1443,7 @@ cdef class BasisExchangeMatroid(Matroid): while e >= 0: bitset_copy(self._input, coflats[i]) bitset_add(self._input, e) - self.__coclosure(coflats[i + 1], self._input) + self._coclosure_internal(coflats[i + 1], self._input) bitset_difference(todo[i], todo[i], coflats[i + 1]) bitset_difference(todo[i + 1], coflats[i + 1], coflats[i]) if bitset_first(todo[i + 1]) == e: @@ -1465,28 +1462,28 @@ cdef class BasisExchangeMatroid(Matroid): flats = <bitset_t*>sig_malloc((k + 1) * sizeof(bitset_t)) todo = <bitset_t*>sig_malloc((k + 1) * sizeof(bitset_t)) - for i in xrange(k + 1): + for i in range(k + 1): bitset_init(flats[i], self._bitset_size) bitset_init(todo[i], self._bitset_size) - f_inc = [[0 for e in range(self._groundset_size + 1)] for i in xrange(k + 1)] + f_inc = [[0 for e in range(self._groundset_size + 1)] for i in range(k + 1)] i = 0 bitset_clear(todo[0]) self.__closure(flats[0], todo[0]) bitset_complement(todo[0], flats[0]) self._flat_element_inv_rec(f_inc, k, flats, todo, 0, 0) - for i in xrange(k + 1): + for i in range(k + 1): bitset_free(flats[i]) bitset_free(todo[i]) sig_free(flats) sig_free(todo) fie = {} for e in range(self._groundset_size): - t = tuple([f_inc[i][e] for i in xrange(k + 1)]) + t = tuple([f_inc[i][e] for i in range(k + 1)]) if t in fie: fie[t].add(self._E[e]) else: fie[t] = set([self._E[e]]) - f_vec = tuple([f_inc[i][self._groundset_size] for i in xrange(k + 1)]) + f_vec = tuple([f_inc[i][self._groundset_size] for i in range(k + 1)]) return fie, f_vec cdef _flat_element_inv_rec(self, object f_inc, long R, bitset_t* flats, bitset_t* todo, long elt, long i): @@ -1718,7 +1715,7 @@ cdef class BasisExchangeMatroid(Matroid): EXAMPLES:: sage: M = matroids.named_matroids.N1() - sage: binomial(M.size(), M.full_rank())-M.bases_count() + sage: binomial(M.size(), M.full_rank())-M.bases_count() # needs sage.symbolic 68 sage: len([B for B in M.nonbases()]) 68 @@ -1809,7 +1806,7 @@ cdef class BasisExchangeMatroid(Matroid): if self.__is_independent(self._input): bitset_copy(self._input2, self._current_basis) e = bitset_first(self._current_basis) - for e in xrange(self._groundset_size): + for e in range(self._groundset_size): if not bitset_in(self._current_basis, e): self.__fundamental_circuit(self._output, e) if e > bitset_first(self._output): @@ -1851,14 +1848,13 @@ cdef class BasisExchangeMatroid(Matroid): return NSC bitset_clear(self._input) bitset_set_first_n(self._input, self._matroid_rank) - cdef long e, f, corank - corank = self._groundset_size - self._matroid_rank + cdef long e, f repeat = True while repeat: if self.__is_independent(self._input): bitset_copy(self._input2, self._current_basis) e = bitset_first(self._current_basis) - for e in xrange(self._groundset_size): + for e in range(self._groundset_size): if not bitset_in(self._current_basis, e): self.__fundamental_circuit(self._output, e) if e > bitset_first(self._output): @@ -2166,7 +2162,7 @@ cdef class BasisExchangeMatroid(Matroid): Bitpacked version of ``is_isomorphism``. """ cdef long i - morph = [other._idx[morphism[self._E[i]]] for i in xrange(len(self))] + morph = [other._idx[morphism[self._E[i]]] for i in range(len(self))] bitset_clear(self._input) bitset_set_first_n(self._input, self._matroid_rank) repeat = True @@ -2199,9 +2195,9 @@ cdef class BasisExchangeMatroid(Matroid): sage: from sage.matroids.advanced import * sage: M1 = matroids.Wheel(3) - sage: M2 = matroids.CompleteGraphic(4) - sage: morphism = M1._isomorphism(M2) - sage: M1._is_isomorphism(M2, morphism) + sage: M2 = matroids.CompleteGraphic(4) # needs sage.graphs + sage: morphism = M1._isomorphism(M2) # needs sage.graphs + sage: M1._is_isomorphism(M2, morphism) # needs sage.graphs True sage: M1 = matroids.named_matroids.Fano() sage: M2 = matroids.named_matroids.NonFano() @@ -2230,7 +2226,7 @@ cdef class BasisExchangeMatroid(Matroid): if self.full_rank() != other.full_rank(): return None if self.full_rank() == 0 or self.full_corank() == 0: - return {self.groundset_list()[i]: other.groundset_list()[i] for i in xrange(len(self))} + return {self.groundset_list()[i]: other.groundset_list()[i] for i in range(len(self))} if self._weak_invariant() != other._weak_invariant(): return None @@ -2238,7 +2234,7 @@ cdef class BasisExchangeMatroid(Matroid): PO = other._weak_partition() if len(PS) == len(self) and len(PO) == len(other): morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PS[i])] = min(PO[i]) if self.__is_isomorphism(other, morphism): return morphism @@ -2251,7 +2247,7 @@ cdef class BasisExchangeMatroid(Matroid): PO = other._strong_partition() if len(PS) == len(self) and len(PO) == len(other): morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PS[i])] = min(PO[i]) if self.__is_isomorphism(other, morphism): return morphism @@ -2262,7 +2258,7 @@ cdef class BasisExchangeMatroid(Matroid): PHS = self._heuristic_partition() PHO = other._heuristic_partition() morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PHS[i])] = min(PHO[i]) if self.__is_isomorphism(other, morphism): return morphism @@ -2293,10 +2289,10 @@ cdef class BasisExchangeMatroid(Matroid): sage: from sage.matroids.advanced import * sage: M1 = BasisMatroid(matroids.Wheel(3)) - sage: M2 = matroids.CompleteGraphic(4) - sage: M1._is_isomorphic(M2) + sage: M2 = matroids.CompleteGraphic(4) # needs sage.graphs + sage: M1._is_isomorphic(M2) # needs sage.graphs True - sage: M1._is_isomorphic(M2, certificate=True) + sage: M1._is_isomorphic(M2, certificate=True) # needs sage.graphs (True, {0: 0, 1: 1, 2: 2, 3: 3, 4: 5, 5: 4}) sage: M1 = BasisMatroid(matroids.named_matroids.Fano()) sage: M2 = matroids.named_matroids.NonFano() @@ -2331,7 +2327,7 @@ cdef class BasisExchangeMatroid(Matroid): PO = other._weak_partition() if len(PS) == len(self) and len(PO) == len(other): morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PS[i])] = min(PO[i]) return self.__is_isomorphism(other, morphism) @@ -2341,7 +2337,7 @@ cdef class BasisExchangeMatroid(Matroid): PO = other._strong_partition() if len(PS) == len(self) and len(PO) == len(other): morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PS[i])] = min(PO[i]) return self.__is_isomorphism(other, morphism) @@ -2349,7 +2345,7 @@ cdef class BasisExchangeMatroid(Matroid): PHS = self._heuristic_partition() PHO = other._heuristic_partition() morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PHS[i])] = min(PHO[i]) if self.__is_isomorphism(other, morphism): return True @@ -2385,7 +2381,7 @@ cdef class BasisExchangeMatroid(Matroid): Verify that :trac:`20172` was fixed:: - sage: M=Matroid(groundset='1234',bases=['12','13','23','34']) + sage: M = Matroid(groundset='1234', bases=['12','13','23','34']) sage: M.is_valid() False """ @@ -2401,7 +2397,7 @@ cdef class BasisExchangeMatroid(Matroid): # Set current basis to Y bitset_difference(self._inside, self._current_basis, BB._subsets[pointerY]) bitset_difference(self._outside, BB._subsets[pointerY], self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) if not bitset_eq(self._current_basis, BB._subsets[pointerY]): # We failed to set the current basis to Y through basis exchanges. # Therefore, the exchange axioms are violated! @@ -2413,7 +2409,7 @@ cdef class BasisExchangeMatroid(Matroid): foundpair = False y = bitset_first(self._input2) while y >= 0: # for y in Y-X - if self.__is_exchange_pair(y, x): + if self._is_exchange_pair(y, x): foundpair = True y = -1 else: diff --git a/src/sage/matroids/basis_matroid.pyx b/src/sage/matroids/basis_matroid.pyx index ff70add1ce2..6dff6506981 100644 --- a/src/sage/matroids/basis_matroid.pyx +++ b/src/sage/matroids/basis_matroid.pyx @@ -79,9 +79,7 @@ from .basis_exchange_matroid cimport BasisExchangeMatroid from .set_system cimport SetSystem from cpython.object cimport Py_EQ, Py_NE -from sage.arith.all import binomial - -from itertools import permutations, combinations +from itertools import combinations # class of general matroids, represented by their list of bases @@ -180,7 +178,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): bitset_init(self._bb, bc) bitset_set_first_n(self._bb, bc) NB = M.nonbases() - for i in xrange(len(NB)): + for i in range(len(NB)): bitset_discard(self._bb, set_to_index(NB._subsets[i])) bitset_init(self._b, (<BasisExchangeMatroid>M)._bitset_size) @@ -221,7 +219,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): raise ValueError("basis has wrong cardinality.") if not b.issubset(self._groundset): raise ValueError("basis is not a subset of the groundset") - self.__pack(self._b, b) + self._pack(self._b, b) i = set_to_index(self._b) if not bitset_in(self._bb, i): self._bcount += 1 @@ -236,7 +234,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): raise ValueError("nonbasis has wrong cardinality") if not b.issubset(self._groundset): raise ValueError("nonbasis is not a subset of the groundset") - self.__pack(self._b, b) + self._pack(self._b, b) i = set_to_index(self._b) if bitset_in(self._bb, i): self._bcount -= 1 @@ -265,7 +263,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): # support for parent BasisExchangeMatroid - cdef bint __is_exchange_pair(self, long x, long y) except -1: # test if current_basis-x + y is a basis + cdef bint _is_exchange_pair(self, long x, long y) except -1: # test if current_basis-x + y is a basis """ Test if `B-e + f` is a basis of the current matroid. @@ -328,7 +326,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): sage: M._is_basis(set(['a', 'b', 'c', 'd'])) False """ - self.__pack(self._b, X) + self._pack(self._b, X) return bitset_in(self._bb, set_to_index(self._b)) # dual and minors @@ -366,7 +364,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): cdef BasisMatroid D D = BasisMatroid(groundset=self._E, rank=self.full_corank()) N = binom[self._groundset_size][self._matroid_rank] - for i in xrange(N): + for i in range(N): if not bitset_in(self._bb, i): bitset_discard(D._bb, N - i - 1) D.reset_current_basis() @@ -559,7 +557,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): """ M = BasisMatroid(M=self) - M.__relabel(l) + M._relabel(l) return M # enumeration @@ -684,11 +682,10 @@ cdef class BasisMatroid(BasisExchangeMatroid): if self._bases_invariant_var is not None: return self._bases_invariant_var cdef long i, j - cdef bitset_t bb_comp cdef list bc cdef dict bi - bc = [0 for i in xrange(len(self))] - for i in xrange(binom[self._groundset_size][self._matroid_rank]): + bc = [0 for i in range(len(self))] + for i in range(binom[self._groundset_size][self._matroid_rank]): if not bitset_in(self._bb, i): index_to_set(self._b, i, self._matroid_rank, self._groundset_size) j = bitset_first(self._b) @@ -696,7 +693,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): bc[j] += 1 j = bitset_next(self._b, j + 1) bi = {} - for e in xrange(len(self)): + for e in range(len(self)): if bc[e] in bi: bi[bc[e]].append(e) else: @@ -871,8 +868,11 @@ cdef class BasisMatroid(BasisExchangeMatroid): Return if the application of a groundset morphism to this matroid yields a relaxation of the given matroid. - M is a relaxation of N if the set of bases of M is a subset of the - bases of N. + `M` is a relaxation of `N` if the set of bases of `M` is a superset of the + bases of `N`. + + This method assumes that ``self`` and ``other`` have the same rank + and does not check this condition. INPUT: @@ -905,7 +905,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): bitset_complement(bb_comp, self._bb) bitset_init(b2, max(len(self), 1)) - morph = [(<BasisMatroid>other)._idx[morphism[self._E[i]]] for i in xrange(len(self))] + morph = [(<BasisMatroid>other)._idx[morphism[self._E[i]]] for i in range(len(self))] i = bitset_first(bb_comp) while i != -1: index_to_set(self._b, i, self._matroid_rank, self._groundset_size) @@ -925,7 +925,10 @@ cdef class BasisMatroid(BasisExchangeMatroid): cpdef _is_isomorphism(self, other, morphism): """ - Version of is_isomorphism() that does no type checking. + Version of :meth:`is_isomorphism` that does no type checking. + + This method assumes that ``self`` and ``other`` have the same rank + and does not check this condition. INPUT: @@ -978,9 +981,9 @@ cdef class BasisMatroid(BasisExchangeMatroid): sage: from sage.matroids.advanced import * sage: M = BasisMatroid(matroids.Wheel(3)) - sage: N = BasisMatroid(matroids.CompleteGraphic(4)) - sage: morphism = M._isomorphism(N) - sage: M._is_isomorphism(N, morphism) + sage: N = BasisMatroid(matroids.CompleteGraphic(4)) # needs sage.graphs + sage: morphism = M._isomorphism(N) # needs sage.graphs + sage: M._is_isomorphism(N, morphism) # needs sage.graphs True sage: M = BasisMatroid(matroids.named_matroids.NonFano()) sage: N = BasisMatroid(matroids.named_matroids.Fano()) @@ -996,7 +999,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): if self.full_rank() != other.full_rank(): return None if self.full_rank() == 0: - return {self.groundset_list()[i]: other.groundset_list()[i] for i in xrange(len(self))} + return {self.groundset_list()[i]: other.groundset_list()[i] for i in range(len(self))} if self.bases_count() != other.bases_count(): return None @@ -1006,7 +1009,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): PO = other._bases_partition() if len(PS) == len(self) and len(PO) == len(other): morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PS[i])] = min(PO[i]) if self._is_relaxation(other, morphism): return morphism @@ -1019,7 +1022,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): PO = other._bases_partition2() if len(PS) == len(self) and len(PO) == len(other): morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PS[i])] = min(PO[i]) if self._is_relaxation(other, morphism): return morphism @@ -1030,7 +1033,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): PHS = self._bases_partition3() PHO = other._bases_partition3() morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PHS[i])] = min(PHO[i]) if self._is_relaxation(other, morphism): return morphism @@ -1088,7 +1091,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): PO = other._bases_partition() if len(PS) == len(self) and len(PO) == len(other): morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PS[i])] = min(PO[i]) return self._is_relaxation(other, morphism) @@ -1098,7 +1101,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): PO = other._bases_partition2() if len(PS) == len(self) and len(PO) == len(other): morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PS[i])] = min(PO[i]) return self._is_relaxation(other, morphism) @@ -1106,7 +1109,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): PHS = self._bases_partition3() PHO = other._bases_partition3() morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PHS[i])] = min(PHO[i]) if self._is_relaxation(other, morphism): return True @@ -1180,10 +1183,10 @@ cdef class BasisMatroid(BasisExchangeMatroid): """ N = BasisMatroid(M=self) - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N - def __deepcopy__(self, memo={}): + def __deepcopy__(self, memo=None): """ Create a deep copy. @@ -1201,8 +1204,10 @@ cdef class BasisMatroid(BasisExchangeMatroid): sage: M.groundset() is N.groundset() False """ + if memo is None: + memo = {} N = BasisMatroid(M=self) - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N def __reduce__(self): @@ -1231,7 +1236,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): """ import sage.matroids.unpickling BB = bitset_pickle(self._bb) - data = (self._E, self._matroid_rank, getattr(self, '__custom_name'), BB) + data = (self._E, self._matroid_rank, self.get_custom_name(), BB) version = 0 return sage.matroids.unpickling.unpickle_basis_matroid, (version, data) @@ -1247,7 +1252,7 @@ cdef binom_init(long N, long K): if binom[0][0] != 1: binom[0][0] = 1 binom[0][1] = 0 - for n in xrange(1, 2955): + for n in range(1, 2955): bin = 1 k = 0 while bin < 2 ** 32 and k <= 32 and k <= n: diff --git a/src/sage/matroids/catalog.py b/src/sage/matroids/catalog.py index 61071b0c757..4bc93a6b8a0 100644 --- a/src/sage/matroids/catalog.py +++ b/src/sage/matroids/catalog.py @@ -36,21 +36,19 @@ # **************************************************************************** from sage.matrix.constructor import Matrix -from sage.graphs.graph_generators import graphs - -from sage.rings.integer_ring import ZZ -from sage.rings.finite_rings.finite_field_constructor import GF -from sage.schemes.all import ProjectiveSpace - -import sage.matroids.matroid -import sage.matroids.basis_exchange_matroid from sage.matroids.basis_matroid import BasisMatroid from sage.matroids.circuit_closures_matroid import CircuitClosuresMatroid +from sage.matroids.constructor import Matroid from sage.matroids.linear_matroid import (LinearMatroid, RegularMatroid, BinaryMatroid, TernaryMatroid, QuaternaryMatroid) from sage.matroids.rank_matroid import RankMatroid -from sage.matroids.constructor import Matroid +from sage.misc.lazy_import import lazy_import +from sage.rings.integer_ring import ZZ + +lazy_import('sage.rings.finite_rings.finite_field_constructor', 'GF') +lazy_import('sage.schemes.projective.projective_space', 'ProjectiveSpace') + # The order is the same as in Oxley. @@ -67,13 +65,13 @@ def Q6(): EXAMPLES:: sage: from sage.matroids.advanced import setprint - sage: M = matroids.named_matroids.Q6(); M + sage: M = matroids.named_matroids.Q6(); M # needs sage.rings.finite_rings Q6: Quaternary matroid of rank 3 on 6 elements - sage: setprint(M.hyperplanes()) + sage: setprint(M.hyperplanes()) # needs sage.rings.finite_rings [{'a', 'b', 'd'}, {'a', 'c'}, {'a', 'e'}, {'a', 'f'}, {'b', 'c', 'e'}, {'b', 'f'}, {'c', 'd'}, {'c', 'f'}, {'d', 'e'}, {'d', 'f'}, {'e', 'f'}] - sage: M.nonspanning_circuits() == M.noncospanning_cocircuits() + sage: M.nonspanning_circuits() == M.noncospanning_cocircuits() # needs sage.rings.finite_rings False """ F = GF(4, 'x') @@ -106,7 +104,7 @@ def P6(): {2: {{'a', 'b', 'c'}}, 3: {{'a', 'b', 'c', 'd', 'e', 'f'}}} sage: len(set(M.nonspanning_circuits()).difference(M.nonbases())) == 0 True - sage: Matroid(matrix=random_matrix(GF(4, 'a'), ncols=5, + sage: Matroid(matrix=random_matrix(GF(4, 'a'), ncols=5, # needs sage.rings.finite_rings ....: nrows=5)).has_minor(M) False sage: M.is_valid() @@ -140,7 +138,7 @@ def R6(): True sage: M.is_connected() True - sage: M.is_3connected() + sage: M.is_3connected() # needs sage.graphs False """ A = Matrix(GF(3), [ @@ -172,7 +170,7 @@ def Fano(): sage: setprint(sorted(M.nonspanning_circuits())) [{'a', 'b', 'f'}, {'a', 'c', 'e'}, {'a', 'd', 'g'}, {'b', 'c', 'd'}, {'b', 'e', 'g'}, {'c', 'f', 'g'}, {'d', 'e', 'f'}] - sage: M.delete(M.groundset_list()[randrange(0, + sage: M.delete(M.groundset_list()[randrange(0, # needs sage.graphs ....: 7)]).is_isomorphic(matroids.CompleteGraphic(4)) True """ @@ -203,9 +201,9 @@ def NonFano(): sage: setprint(M.nonbases()) [{'a', 'b', 'f'}, {'a', 'c', 'e'}, {'a', 'd', 'g'}, {'b', 'c', 'd'}, {'b', 'e', 'g'}, {'c', 'f', 'g'}] - sage: M.delete('f').is_isomorphic(matroids.CompleteGraphic(4)) + sage: M.delete('f').is_isomorphic(matroids.CompleteGraphic(4)) # needs sage.graphs True - sage: M.delete('g').is_isomorphic(matroids.CompleteGraphic(4)) + sage: M.delete('g').is_isomorphic(matroids.CompleteGraphic(4)) # needs sage.graphs False """ A = Matrix(GF(3), [ @@ -232,7 +230,7 @@ def O7(): sage: M = matroids.named_matroids.O7(); M O7: Ternary matroid of rank 3 on 7 elements, type 0+ - sage: M.delete('e').is_isomorphic(matroids.CompleteGraphic(4)) + sage: M.delete('e').is_isomorphic(matroids.CompleteGraphic(4)) # needs sage.graphs True sage: M.tutte_polynomial() y^4 + x^3 + x*y^2 + 3*y^3 + 4*x^2 + 5*x*y + 5*y^2 + 4*x + 4*y @@ -263,7 +261,7 @@ def P7(): P7: Ternary matroid of rank 3 on 7 elements, type 1+ sage: M.f_vector() [1, 7, 11, 1] - sage: M.has_minor(matroids.CompleteGraphic(4)) + sage: M.has_minor(matroids.CompleteGraphic(4)) # needs sage.graphs False sage: M.is_valid() True @@ -307,7 +305,7 @@ def AG32prime(): {'b', 'c', 'd', 'g'}, {'b', 'c', 'e', 'f'}, {'b', 'd', 'f', 'h'}, {'b', 'e', 'g', 'h'}, {'c', 'd', 'e', 'h'}, {'c', 'f', 'g', 'h'}, {'d', 'e', 'f', 'g'}] - sage: M.is_valid() # long time + sage: M.is_valid() # long time, needs sage.rings.finite_rings True """ E = 'abcdefgh' @@ -378,7 +376,7 @@ def F8(): [...True...] sage: [N.is_isomorphic(matroids.named_matroids.NonFano()) for N in D] [...True...] - sage: M.is_valid() # long time + sage: M.is_valid() # long time, needs sage.rings.finite_rings True """ E = 'abcdefgh' @@ -591,7 +589,7 @@ def J(): [{'a', 'b', 'f'}, {'a', 'c', 'g'}, {'a', 'd', 'h'}] sage: M.is_isomorphic(M.dual()) True - sage: M.has_minor(matroids.CompleteGraphic(4)) + sage: M.has_minor(matroids.CompleteGraphic(4)) # needs sage.graphs False sage: M.is_valid() True @@ -623,7 +621,7 @@ def P8(): P8: Ternary matroid of rank 4 on 8 elements, type 2+ sage: M.is_isomorphic(M.dual()) True - sage: Matroid(matrix=random_matrix(GF(4, 'a'), ncols=5, + sage: Matroid(matrix=random_matrix(GF(4, 'a'), ncols=5, # needs sage.rings.finite_rings ....: nrows=5)).has_minor(M) False sage: M.bicycle_dimension() @@ -690,14 +688,16 @@ def K33dual(): EXAMPLES:: - sage: M = matroids.named_matroids.K33dual(); M + sage: M = matroids.named_matroids.K33dual(); M # needs sage.graphs M*(K3, 3): Regular matroid of rank 4 on 9 elements with 81 bases - sage: any(N.is_3connected() + sage: any(N.is_3connected() # needs sage.graphs ....: for N in M.linear_extensions(simple=True)) False - sage: M.is_valid() # long time + sage: M.is_valid() # long time, needs sage.graphs True """ + from sage.graphs.graph_generators import graphs + E = 'abcdefghi' G = graphs.CompleteBipartiteGraph(3, 3) M = Matroid(groundset=E, graph=G, regular=True) @@ -755,6 +755,7 @@ def CompleteGraphic(n): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.matroids.advanced import setprint sage: M = matroids.CompleteGraphic(5); M M(K5): Graphic matroid of rank 4 on 10 elements @@ -768,6 +769,8 @@ def CompleteGraphic(n): sage: M.is_valid() True """ + from sage.graphs.graph_generators import graphs + M = Matroid(groundset=list(range((n * (n - 1)) // 2)), graph=graphs.CompleteGraph(n)) M.rename('M(K' + str(n) + '): ' + repr(M)) @@ -802,11 +805,11 @@ def Wheel(n, field=None, ring=None): sage: M.is_valid() True sage: M = matroids.Wheel(3) - sage: M.is_isomorphic(matroids.CompleteGraphic(4)) + sage: M.is_isomorphic(matroids.CompleteGraphic(4)) # needs sage.graphs True - sage: M.is_isomorphic(matroids.Wheel(3,field=GF(3))) + sage: M.is_isomorphic(matroids.Wheel(3, field=GF(3))) True - sage: M = matroids.Wheel(3,field=GF(3)); M + sage: M = matroids.Wheel(3, field=GF(3)); M Wheel(3): Ternary matroid of rank 3 on 6 elements, type 0+ """ base_ring = ZZ @@ -863,7 +866,7 @@ def Whirl(n): sage: M.is_isomorphic(matroids.Wheel(5)) False sage: M = matroids.Whirl(3) - sage: M.is_isomorphic(matroids.CompleteGraphic(4)) + sage: M.is_isomorphic(matroids.CompleteGraphic(4)) # needs sage.graphs False .. TODO:: @@ -963,7 +966,7 @@ def PG(n, q, x=None): sage: M = matroids.PG(2, 2) sage: M.is_isomorphic(matroids.named_matroids.Fano()) True - sage: matroids.PG(5, 4, 'z').size() == (4^6 - 1) / (4 - 1) + sage: matroids.PG(5, 4, 'z').size() == (4^6 - 1) / (4 - 1) # needs sage.rings.finite_rings True sage: M = matroids.PG(4, 7); M PG(4, 7): Linear matroid of rank 5 on 2801 elements represented over @@ -1006,7 +1009,7 @@ def AG(n, q, x=None): sage: M = matroids.AG(2, 3) \ 8 sage: M.is_isomorphic(matroids.named_matroids.AG23minus()) True - sage: matroids.AG(5, 4, 'z').size() == ((4 ^ 6 - 1) / (4 - 1) - + sage: matroids.AG(5, 4, 'z').size() == ((4 ^ 6 - 1) / (4 - 1) - # needs sage.rings.finite_rings ....: (4 ^ 5 - 1)/(4 - 1)) True sage: M = matroids.AG(4, 2); M @@ -1045,7 +1048,7 @@ def R10(): {4, 6} sage: M.equals(M.dual()) False - sage: M.is_isomorphic(M.dual()) + sage: M.is_isomorphic(M.dual()) # needs sage.graphs True sage: M.is_valid() True @@ -1083,7 +1086,7 @@ def R12(): R12: Regular matroid of rank 6 on 12 elements with 441 bases sage: M.equals(M.dual()) False - sage: M.is_isomorphic(M.dual()) + sage: M.is_isomorphic(M.dual()) # needs sage.graphs True sage: M.is_valid() True @@ -1243,10 +1246,10 @@ def Q10(): EXAMPLES:: - sage: M = matroids.named_matroids.Q10() - sage: M.is_isomorphic(M.dual()) + sage: M = matroids.named_matroids.Q10() # needs sage.rings.finite_rings + sage: M.is_isomorphic(M.dual()) # needs sage.rings.finite_rings True - sage: M.is_valid() + sage: M.is_valid() # needs sage.rings.finite_rings True Check the splitter property. By Seymour's Theorem, and using self-duality, @@ -1255,8 +1258,8 @@ def Q10(): are quaternary are `U_{2, 5}, U_{3, 5}, F_7, F_7^*`. As it happens, it suffices to check for `U_{2, 5}`: - sage: S = matroids.named_matroids.Q10().linear_extensions(simple=True) - sage: [M for M in S if not M.has_line_minor(5)] # long time + sage: S = matroids.named_matroids.Q10().linear_extensions(simple=True) # needs sage.rings.finite_rings + sage: [M for M in S if not M.has_line_minor(5)] # long time, needs sage.rings.finite_rings [] """ F = GF(4, 'x') @@ -1366,8 +1369,8 @@ def Block_9_4(): sage: M = matroids.named_matroids.Block_9_4() sage: M.is_valid() # long time True - sage: BD = BlockDesign(M.groundset(), M.nonspanning_circuits()) - sage: BD.is_t_design(return_parameters=True) + sage: BD = BlockDesign(M.groundset(), M.nonspanning_circuits()) # needs sage.graphs + sage: BD.is_t_design(return_parameters=True) # needs sage.graphs (True, (2, 9, 4, 3)) """ E = 'abcdefghi' @@ -1392,8 +1395,8 @@ def Block_10_5(): sage: M = matroids.named_matroids.Block_10_5() sage: M.is_valid() # long time True - sage: BD = BlockDesign(M.groundset(), M.nonspanning_circuits()) - sage: BD.is_t_design(return_parameters=True) + sage: BD = BlockDesign(M.groundset(), M.nonspanning_circuits()) # needs sage.graphs + sage: BD.is_t_design(return_parameters=True) # needs sage.graphs (True, (3, 10, 5, 3)) """ @@ -1424,7 +1427,7 @@ def ExtendedBinaryGolayCode(): sage: M = matroids.named_matroids.ExtendedBinaryGolayCode() sage: C = LinearCode(M.representation()) - sage: C.is_permutation_equivalent(codes.GolayCode(GF(2))) # long time + sage: C.is_permutation_equivalent(codes.GolayCode(GF(2))) # long time, needs sage.rings.finite_rings True sage: M.is_valid() True @@ -1459,7 +1462,7 @@ def ExtendedTernaryGolayCode(): sage: M = matroids.named_matroids.ExtendedTernaryGolayCode() sage: C = LinearCode(M.representation()) - sage: C.is_permutation_equivalent(codes.GolayCode(GF(3))) # long time + sage: C.is_permutation_equivalent(codes.GolayCode(GF(3))) # long time, needs sage.rings.finite_rings True sage: M.is_valid() True diff --git a/src/sage/matroids/circuit_closures_matroid.pyx b/src/sage/matroids/circuit_closures_matroid.pyx index 2411e52fa81..4e79b0575e2 100644 --- a/src/sage/matroids/circuit_closures_matroid.pyx +++ b/src/sage/matroids/circuit_closures_matroid.pyx @@ -387,10 +387,10 @@ cdef class CircuitClosuresMatroid(Matroid): sage: from sage.matroids.advanced import * sage: M1 = CircuitClosuresMatroid(matroids.Wheel(3)) - sage: M2 = matroids.CompleteGraphic(4) - sage: M1._is_isomorphic(M2) + sage: M2 = matroids.CompleteGraphic(4) # needs sage.graphs + sage: M1._is_isomorphic(M2) # needs sage.graphs True - sage: M1._is_isomorphic(M2, certificate=True) + sage: M1._is_isomorphic(M2, certificate=True) # needs sage.graphs (True, {0: 0, 1: 1, 2: 2, 3: 3, 4: 5, 5: 4}) sage: M1 = CircuitClosuresMatroid(matroids.named_matroids.Fano()) sage: M2 = matroids.named_matroids.NonFano() @@ -513,11 +513,10 @@ cdef class CircuitClosuresMatroid(Matroid): N._groundset = self._groundset N._circuit_closures = self._circuit_closures N._matroid_rank = self._matroid_rank - if getattr(self, '__custom_name') is not None: # because of name wrangling, this is not caught by the default copy - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N - def __deepcopy__(self, memo={}): + def __deepcopy__(self, memo=None): """ Create a deep copy. @@ -534,11 +533,12 @@ cdef class CircuitClosuresMatroid(Matroid): sage: M.groundset() is N.groundset() False """ + if memo is None: + memo = {} from copy import deepcopy # Since matroids are immutable, N cannot reference itself in correct code, so no need to worry about the recursion. N = CircuitClosuresMatroid(groundset=deepcopy(self._groundset, memo), circuit_closures=deepcopy(self._circuit_closures, memo)) - if getattr(self, '__custom_name') is not None: # because of name wrangling, this is not caught by the default deepcopy - N.rename(deepcopy(getattr(self, '__custom_name'), memo)) + N.rename(deepcopy(self.get_custom_name(), memo)) return N def __reduce__(self): @@ -568,7 +568,7 @@ cdef class CircuitClosuresMatroid(Matroid): 4: {{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}}} """ import sage.matroids.unpickling - data = (self._groundset, self._circuit_closures, getattr(self, '__custom_name')) + data = (self._groundset, self._circuit_closures, self.get_custom_name()) version = 0 return sage.matroids.unpickling.unpickle_circuit_closures_matroid, (version, data) diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index 1fb2cd2b93e..acbc4c03d00 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -75,8 +75,8 @@ sage: M.is_isomorphic(matroids.named_matroids.Fano()) True - sage: M = Matroid(graphs.PetersenGraph()) - sage: M.rank() + sage: M = Matroid(graphs.PetersenGraph()) # needs sage.graphs + sage: M.rank() # needs sage.graphs 9 AUTHORS: @@ -103,11 +103,11 @@ from itertools import combinations from sage.matrix.constructor import Matrix -from sage.graphs.graph import Graph from sage.structure.element import is_Matrix from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.categories.all import Fields, Rings +from sage.categories.fields import Fields +from sage.categories.rings import Rings from sage.rings.finite_rings.finite_field_base import FiniteField import sage.matroids.matroid import sage.matroids.basis_exchange_matroid @@ -334,38 +334,40 @@ def Matroid(groundset=None, data=None, **kwds): :: - sage: G = graphs.PetersenGraph() - sage: Matroid(G) + sage: G = graphs.PetersenGraph() # needs sage.graphs + sage: Matroid(G) # needs sage.graphs Graphic matroid of rank 9 on 15 elements If each edge has a unique label, then those are used as the ground set labels:: - sage: G = Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'c')]) - sage: M = Matroid(G) - sage: sorted(M.groundset()) + sage: G = Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'c')]) # needs sage.graphs + sage: M = Matroid(G) # needs sage.graphs + sage: sorted(M.groundset()) # needs sage.graphs ['a', 'b', 'c'] If there are parallel edges, then integers are used for the ground set. If there are no edges in parallel, and is not a complete list of labels, or the labels are not unique, then vertex tuples are used:: + sage: # needs sage.graphs sage: G = Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'b')]) sage: M = Matroid(G) sage: sorted(M.groundset()) [(0, 1), (0, 2), (1, 2)] - sage: H = Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'b'), (1, 2, 'c')], multiedges=True) + sage: H = Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'b'), (1, 2, 'c')], + ....: multiedges=True) sage: N = Matroid(H) sage: sorted(N.groundset()) [0, 1, 2, 3] The GraphicMatroid object forces its graph to be connected. If a - disconnected graph is used as input, it will connect the components. + disconnected graph is used as input, it will connect the components:: + sage: # needs sage.graphs sage: G1 = graphs.CycleGraph(3); G2 = graphs.DiamondGraph() sage: G = G1.disjoint_union(G2) - sage: M = Matroid(G) - sage: M + sage: M = Matroid(G); M Graphic matroid of rank 5 on 8 elements sage: M.graph() Looped multi-graph on 6 vertices @@ -376,12 +378,12 @@ def Matroid(groundset=None, data=None, **kwds): If the keyword ``regular`` is set to ``True``, the output will instead - be an instance of ``RegularMatroid``. + be an instance of :class:`RegularMatroid`. :: - sage: G = Graph([(0, 1), (0, 2), (1, 2)]) - sage: M = Matroid(G, regular=True); M + sage: G = Graph([(0, 1), (0, 2), (1, 2)]) # needs sage.graphs + sage: M = Matroid(G, regular=True); M # needs sage.graphs Regular matroid of rank 2 on 3 elements with 3 bases Note: if a groundset is specified, we assume it is in the same order @@ -389,9 +391,9 @@ def Matroid(groundset=None, data=None, **kwds): :meth:`G.edge_iterator() <sage.graphs.generic_graph.GenericGraph.edge_iterator>` provides:: - sage: G = Graph([(0, 1), (0, 2), (0, 2), (1, 2)], multiedges=True) - sage: M = Matroid('abcd', G) - sage: M.rank(['b', 'c']) + sage: G = Graph([(0, 1), (0, 2), (0, 2), (1, 2)], multiedges=True) # needs sage.graphs + sage: M = Matroid('abcd', G) # needs sage.graphs + sage: M.rank(['b', 'c']) # needs sage.graphs 1 As before, @@ -399,14 +401,14 @@ def Matroid(groundset=None, data=None, **kwds): tuples ``(i, j)`` of endpoints. If that fails, we simply use a list ``[0..m-1]`` :: - sage: G = Graph([(0, 1), (0, 2), (1, 2)]) - sage: M = Matroid(G, regular=True) - sage: sorted(M.groundset()) + sage: G = Graph([(0, 1), (0, 2), (1, 2)]) # needs sage.graphs + sage: M = Matroid(G, regular=True) # needs sage.graphs + sage: sorted(M.groundset()) # needs sage.graphs [(0, 1), (0, 2), (1, 2)] - sage: G = Graph([(0, 1), (0, 2), (0, 2), (1, 2)], multiedges=True) - sage: M = Matroid(G, regular=True) - sage: sorted(M.groundset()) + sage: G = Graph([(0, 1), (0, 2), (0, 2), (1, 2)], multiedges=True) # needs sage.graphs + sage: M = Matroid(G, regular=True) # needs sage.graphs + sage: sorted(M.groundset()) # needs sage.graphs [0, 1, 2, 3] When the ``graph`` keyword is used, a variety of inputs can be @@ -414,12 +416,12 @@ def Matroid(groundset=None, data=None, **kwds): (see the :class:`Graph <sage.graphs.graph.Graph>` method's documentation):: - sage: Matroid(graph=':I`AKGsaOs`cI]Gb~') + sage: Matroid(graph=':I`AKGsaOs`cI]Gb~') # needs sage.graphs Graphic matroid of rank 9 on 17 elements However, this method is no more clever than ``Graph()``:: - sage: Matroid(graph=41/2) + sage: Matroid(graph=41/2) # needs sage.graphs Traceback (most recent call last): ... ValueError: This input cannot be turned into a graph @@ -433,7 +435,7 @@ def Matroid(groundset=None, data=None, **kwds): ....: [0, 1, 0, 1, 0, 1], ....: [0, 0, 1, 0, 1, 1]]) sage: M = Matroid(matrix=A) - sage: M.is_isomorphic(matroids.CompleteGraphic(4)) + sage: M.is_isomorphic(matroids.CompleteGraphic(4)) # needs sage.graphs True Various shortcuts are possible:: @@ -486,11 +488,11 @@ def Matroid(groundset=None, data=None, **kwds): ....: matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]], ....: field=GF(3)) Ternary matroid of rank 3 on 6 elements, type 0- - sage: Matroid([0, 1, 2, 3, 4, 5], + sage: Matroid([0, 1, 2, 3, 4, 5], # needs sage.rings.finite_rings ....: matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]], ....: field=GF(4, 'x')) Quaternary matroid of rank 3 on 6 elements - sage: Matroid([0, 1, 2, 3, 4, 5], + sage: Matroid([0, 1, 2, 3, 4, 5], # needs sage.graphs ....: matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]], ....: field=GF(2), regular=True) Regular matroid of rank 3 on 6 elements with 16 bases @@ -544,7 +546,7 @@ def Matroid(groundset=None, data=None, **kwds): sage: M = Matroid(circuit_closures=[(2, 'abd'), (3, 'abcdef'), ....: (2, 'bce')]) - sage: M.equals(matroids.named_matroids.Q6()) + sage: M.equals(matroids.named_matroids.Q6()) # needs sage.rings.finite_rings True #. RevLex-Index: @@ -600,53 +602,50 @@ def Matroid(groundset=None, data=None, **kwds): sage: M = Matroid(circuit_closures={2:['adb', 'bec', 'cfa', ....: 'def'], 3:['abcdef']}) - sage: N = Matroid(M, regular=True) - sage: N + sage: N = Matroid(M, regular=True); N # needs sage.graphs Regular matroid of rank 3 on 6 elements with 16 bases - sage: M == N + sage: M == N # needs sage.graphs False - sage: M.is_isomorphic(N) + sage: M.is_isomorphic(N) # needs sage.graphs True - sage: Matrix(N) # random + sage: Matrix(N) # random # needs sage.graphs [1 0 0 1 1 0] [0 1 0 1 1 1] [0 0 1 0 1 1] The ``regular`` option:: - sage: M = Matroid(reduced_matrix=[[1, 1, 0], + sage: M = Matroid(reduced_matrix=[[1, 1, 0], # needs sage.graphs ....: [1, 0, 1], - ....: [0, 1, 1]], regular=True) - sage: M + ....: [0, 1, 1]], regular=True); M Regular matroid of rank 3 on 6 elements with 16 bases - sage: M.is_isomorphic(matroids.CompleteGraphic(4)) + sage: M.is_isomorphic(matroids.CompleteGraphic(4)) # needs sage.graphs True By default we check if the resulting matroid is actually regular. To increase speed, this check can be skipped:: sage: M = matroids.named_matroids.Fano() - sage: N = Matroid(M, regular=True) + sage: N = Matroid(M, regular=True) # needs sage.graphs Traceback (most recent call last): ... ValueError: input is not a valid regular matroid - sage: N = Matroid(M, regular=True, check=False) - sage: N + sage: N = Matroid(M, regular=True, check=False); N # needs sage.graphs Regular matroid of rank 3 on 7 elements with 32 bases - sage: N.is_valid() + sage: N.is_valid() # needs sage.graphs False Sometimes the output is regular, but represents a different matroid from the one you intended:: sage: M = Matroid(Matrix(GF(3), [[1, 0, 1, 1], [0, 1, 1, 2]])) - sage: N = Matroid(Matrix(GF(3), [[1, 0, 1, 1], [0, 1, 1, 2]]), + sage: N = Matroid(Matrix(GF(3), [[1, 0, 1, 1], [0, 1, 1, 2]]), # needs sage.graphs ....: regular=True) - sage: N.is_valid() + sage: N.is_valid() # needs sage.graphs True - sage: N.is_isomorphic(M) + sage: N.is_isomorphic(M) # needs sage.graphs False TESTS:: @@ -711,7 +710,11 @@ def Matroid(groundset=None, data=None, **kwds): groundset = None if key is None: - if isinstance(data, sage.graphs.graph.Graph): + try: + from sage.graphs.graph import Graph + except ImportError: + Graph = () + if isinstance(data, Graph): key = 'graph' elif is_Matrix(data): key = 'matrix' @@ -772,6 +775,8 @@ def Matroid(groundset=None, data=None, **kwds): # Graphs: elif key == 'graph': + from sage.graphs.graph import Graph + if isinstance(data, sage.graphs.generic_graph.GenericGraph): G = data else: diff --git a/src/sage/matroids/dual_matroid.py b/src/sage/matroids/dual_matroid.py index 804e43f035b..da6639827e4 100644 --- a/src/sage/matroids/dual_matroid.py +++ b/src/sage/matroids/dual_matroid.py @@ -519,9 +519,7 @@ def __copy__(self): """ N = DualMatroid(self._matroid) - if getattr(self, '__custom_name') is not None: - # because of name wrangling, this is not caught by the default copy - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N def __deepcopy__(self, memo={}): @@ -543,10 +541,7 @@ def __deepcopy__(self, memo={}): """ from copy import deepcopy N = DualMatroid(deepcopy(self._matroid, memo)) - if getattr(self, '__custom_name') is not None: - # because of name wrangling, this is not caught by the - # default deepcopy - N.rename(deepcopy(getattr(self, '__custom_name'), memo)) + N.rename(deepcopy(self.get_custom_name(), memo)) return N def __reduce__(self): @@ -575,6 +570,6 @@ def __reduce__(self): 4: {{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}}}' """ import sage.matroids.unpickling - data = (self._matroid, getattr(self, '__custom_name')) + data = (self._matroid, self.get_custom_name()) version = 0 return sage.matroids.unpickling.unpickle_dual_matroid, (version, data) diff --git a/src/sage/matroids/extension.pyx b/src/sage/matroids/extension.pyx index 0408e60f86e..1f2cb38a65c 100644 --- a/src/sage/matroids/extension.pyx +++ b/src/sage/matroids/extension.pyx @@ -31,7 +31,6 @@ Methods from sage.data_structures.bitset_base cimport * from .basis_matroid cimport BasisMatroid -from sage.arith.all import binomial cdef class CutNode: @@ -341,8 +340,8 @@ cdef class LinearSubclasses: self._planes_on_line = [[] for l in range(self._hyperlines_count)] self._lines_on_plane = [[] for l in range(self._hyperplanes_count)] - for l in xrange(self._hyperlines_count): - for h in xrange(self._hyperplanes_count): + for l in range(self._hyperlines_count): + for h in range(self._hyperplanes_count): if self._hyperplanes[h] >= self._hyperlines[l]: self._lines_on_plane[h].append(l) self._planes_on_line[l].append(h) @@ -354,10 +353,10 @@ cdef class LinearSubclasses: if line_length is not None: self._line_length = line_length - self._mandatory_lines = [l for l in xrange(self._hyperlines_count) if len(self._planes_on_line[l]) >= line_length] + self._mandatory_lines = [l for l in range(self._hyperlines_count) if len(self._planes_on_line[l]) >= line_length] if subsets is not None: - for p in xrange(self._hyperplanes_count): + for p in range(self._hyperplanes_count): H = self._hyperplanes[p] for S in subsets: if frozenset(S).issubset(H): @@ -371,7 +370,7 @@ cdef class LinearSubclasses: if len(E) != len(E2) or len(F) != 1: raise ValueError("LinearSubclasses: the ground set of the splice matroid is not of the form E + e-f") - for p in xrange(self._hyperplanes_count): + for p in range(self._hyperplanes_count): X = self._hyperplanes[p] - F if splice._rank(X) == splice.full_rank() - 1: if splice._rank(X | F2) == splice.full_rank() - 1: @@ -485,13 +484,13 @@ cdef class MatroidExtensions(LinearSubclasses): """ if M.full_rank() == 0: pass - if type(M) == BasisMatroid: + if isinstance(M, BasisMatroid): BM = M else: BM = BasisMatroid(M) LinearSubclasses.__init__(self, BM, line_length=line_length, subsets=subsets, splice=splice) self._BX = BM._extension(e, []) - self._BH = [BM._extension(e, [self._hyperplanes[i]]) for i in xrange(len(self._hyperplanes))] + self._BH = [BM._extension(e, [self._hyperplanes[i]]) for i in range(len(self._hyperplanes))] if orderly: self._orderly = True diff --git a/src/sage/matroids/graphic_matroid.py b/src/sage/matroids/graphic_matroid.py index 9bafa6dc0c7..c841bc7d9d1 100644 --- a/src/sage/matroids/graphic_matroid.py +++ b/src/sage/matroids/graphic_matroid.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.graphs r""" Graphic Matroids @@ -88,12 +89,10 @@ # **************************************************************************** from .matroid import Matroid -from sage.graphs.graph import Graph from copy import copy, deepcopy from .utilities import newlabel, split_vertex, sanitize_contractions_deletions from itertools import combinations from sage.rings.integer import Integer -from sage.sets.disjoint_set import DisjointSet class GraphicMatroid(Matroid): @@ -185,6 +184,7 @@ def __init__(self, G, groundset=None): running ._test_not_implemented_methods() . . . pass running ._test_pickling() . . . pass """ + from sage.graphs.graph import Graph if groundset is None: # Try to construct a ground set based on the edge labels. @@ -283,6 +283,8 @@ def _rank(self, X): 1 """ + from sage.sets.disjoint_set import DisjointSet + edges = self.groundset_to_edges(X) vertices = set([u for (u, v, l) in edges]).union( [v for (u, v, l) in edges]) @@ -479,8 +481,7 @@ def __copy__(self): False """ N = GraphicMatroid(self._G) - if getattr(self, '__custom_name') is not None: # because of name wrangling, this is not caught by the default copy - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N def __deepcopy__(self, memo={}): @@ -500,8 +501,7 @@ def __deepcopy__(self, memo={}): """ # The only real difference between this and __copy__() is the memo N = GraphicMatroid(deepcopy(self._G, memo)) - if getattr(self, '__custom_name') is not None: # because of name wrangling, this is not caught by the default deepcopy - N.rename(deepcopy(getattr(self, '__custom_name'), memo)) + N.rename(deepcopy(self.get_custom_name(), memo)) return N def __reduce__(self): @@ -517,7 +517,7 @@ def __reduce__(self): Graphic matroid of rank 9 on 15 elements """ from .unpickling import unpickle_graphic_matroid - data = (self._G, getattr(self, '__custom_name')) + data = (self._G, self.get_custom_name()) version = 0 return unpickle_graphic_matroid, (version, data) @@ -712,6 +712,8 @@ def _corank(self, X): sage: M._corank([1,2,3]) 3 """ + from sage.sets.disjoint_set import DisjointSet + all_vertices = self._G.vertices(sort=False) not_our_edges = self.groundset_to_edges(self._groundset.difference(X)) DS_vertices = DisjointSet(all_vertices) @@ -825,6 +827,8 @@ def _max_independent(self, X): sage: sorted(N._max_independent(frozenset(['a']))) [] """ + from sage.sets.disjoint_set import DisjointSet + edges = self.groundset_to_edges(X) vertices = set([u for (u, v, l) in edges]) vertices.update([v for (u, v, l) in edges]) @@ -860,6 +864,8 @@ def _max_coindependent(self, X): sage: sorted(N.max_coindependent([0,1,2,5])) [1, 2, 5] """ + from sage.sets.disjoint_set import DisjointSet + edges = self.groundset_to_edges(X) all_vertices = self._G.vertices(sort=False) not_our_edges = self.groundset_to_edges(self._groundset.difference(X)) @@ -887,7 +893,7 @@ def _circuit(self, X): OUTPUT: ``frozenset`` instance containing a subset of ``X``. - A ``ValueError`` is raised if the set contains no circuit. + A :class:`ValueError` is raised if the set contains no circuit. EXAMPLES:: @@ -923,6 +929,8 @@ def _circuit(self, X): [4, 5] """ + from sage.sets.disjoint_set import DisjointSet + edges = self.groundset_to_edges(X) vertices = set([u for (u, v, l) in edges]).union( set([v for (u, v, l) in edges])) @@ -1334,6 +1342,8 @@ def _subgraph_from_set(self, X): sage: M._subgraph_from_set([0,1,2]) Looped multi-graph on 3 vertices """ + from sage.graphs.graph import Graph + edge_list = self._groundset_to_edges(X) return Graph(edge_list, loops=True, multiedges=True) diff --git a/src/sage/matroids/lean_matrix.pyx b/src/sage/matroids/lean_matrix.pyx index 6b3cf27bcf2..54c68e637c0 100644 --- a/src/sage/matroids/lean_matrix.pyx +++ b/src/sage/matroids/lean_matrix.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.rings.finite_rings # cython: profile=True """ Lean matrices @@ -37,7 +38,9 @@ from cysignals.signals cimport sig_on, sig_off from sage.data_structures.bitset_base cimport * from sage.matrix.matrix2 cimport Matrix -from sage.rings.all import ZZ, FiniteField, GF, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.rational_field import QQ from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational from sage.libs.gmp.mpq cimport * @@ -105,8 +108,8 @@ cdef class LeanMatrix: """ cdef long r, c M = sage.matrix.constructor.Matrix(self.base_ring(), self._nrows, self._ncols) - for r from 0 <= r < self._nrows: - for c from 0 <= c < self._ncols: + for r in range(self._nrows): + for c in range(self._ncols): M[r, c] = self.get_unsafe(r, c) return M @@ -132,11 +135,11 @@ cdef class LeanMatrix: cdef long i, j cdef long sr = self.nrows() A = type(self)(sr + M.nrows(), self.ncols()) - for i from 0 <= i < sr: - for j from 0 <= j < self.ncols(): + for i in range(sr): + for j in range(self.ncols()): A.set_unsafe(i, j, self.get_unsafe(i, j)) - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): A.set_unsafe(i + sr, j, M.get_unsafe(i, j)) return A @@ -150,10 +153,10 @@ cdef class LeanMatrix: cdef long i, j cdef long sc = self.ncols() A = type(self)(self.nrows(), sc + M.ncols()) - for i from 0 <= i < self.nrows(): - for j from 0 <= j < sc: + for i in range(self.nrows()): + for j in range(sc): A.set_unsafe(i, j, self.get_unsafe(i, j)) - for j from 0 <= j < M.ncols(): + for j in range(M.ncols()): A.set_unsafe(i, j + sc, M.get_unsafe(i, j)) return A @@ -164,9 +167,9 @@ cdef class LeanMatrix: """ cdef long i, j cdef LeanMatrix A = type(self)(self.nrows(), self.ncols() + self.nrows()) - for i from 0 <= i < self.nrows(): + for i in range(self.nrows()): A.set_unsafe(i, i, self.base_ring()(1)) - for j from 0 <= j < self.ncols(): + for j in range(self.ncols()): A.set_unsafe(i, self.nrows() + j, self.get_unsafe(i, j)) return A @@ -249,10 +252,10 @@ cdef class LeanMatrix: """ cdef long i if s is None: - for i from 0 <= i < self._ncols: + for i in range(self._ncols): self.set_unsafe(x, i, self.get_unsafe(x, i) + self.get_unsafe(y, i)) else: - for i from 0 <= i < self._ncols: + for i in range(self._ncols): self.set_unsafe(x, i, self.get_unsafe(x, i) + s * self.get_unsafe(y, i)) return 0 @@ -261,7 +264,7 @@ cdef class LeanMatrix: Swap rows ``x`` and ``y``. """ cdef long i - for i from 0 <= i < self._ncols: + for i in range(self._ncols): tmp = self.get_unsafe(x, i) self.set_unsafe(x, i, self.get_unsafe(y, i)) self.set_unsafe(y, i, tmp) @@ -273,7 +276,7 @@ cdef class LeanMatrix: compatibility, and is ignored. """ cdef long i - for i from 0 <= i < self._ncols: + for i in range(self._ncols): self.set_unsafe(x, i, s * self.get_unsafe(x, i)) return 0 @@ -283,7 +286,7 @@ cdef class LeanMatrix: compatibility, and ignored. """ cdef long j - for j from 0 <= j < self._nrows: + for j in range(self._nrows): self.set_unsafe(j, y, self.get_unsafe(j, y) * s) return 0 @@ -300,9 +303,9 @@ cdef class LeanMatrix: This is different from what matroid theorists tend to call a pivot, as it does not involve a column exchange! """ - cdef long i, j + cdef long i self.rescale_row_c(x, self.get_unsafe(x, y) ** (-1), 0) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): s = self.get_unsafe(i, y) if s and i != x: self.add_multiple_of_row_c(i, x, -s, 0) @@ -337,7 +340,7 @@ cdef class LeanMatrix: """ Get coordinates of nonzero entries of row ``r``. """ - return [i for i in xrange(self._ncols) if self.is_nonzero(r, i)] + return [i for i in range(self._ncols) if self.is_nonzero(r, i)] cdef LeanMatrix transpose(self): """ @@ -345,8 +348,8 @@ cdef class LeanMatrix: """ cdef LeanMatrix A = type(self)(self.ncols(), self.nrows()) cdef long i, j - for i from 0 <= i < self.nrows(): - for j from 0 <= j < self.ncols(): + for i in range(self.nrows()): + for j in range(self.ncols()): A.set_unsafe(j, i, self.get_unsafe(i, j)) return A @@ -357,9 +360,9 @@ cdef class LeanMatrix: """ cdef LeanMatrix A = type(self)(self.nrows(), other.ncols()) cdef i, j, k - for i from 0 <= i < self.nrows(): - for j from 0 <= j < other.ncols(): - for k from 0 <= k < self.ncols(): + for i in range(self.nrows()): + for j in range(other.ncols()): + for k in range(self.ncols()): A.set_unsafe(i, j, self.get_unsafe(i, k) * other.get_unsafe(k, j)) return A @@ -369,8 +372,8 @@ cdef class LeanMatrix: """ cdef long r, c cdef LeanMatrix A = type(self)(len(rows), len(columns), ring=self.base_ring()) - for r from 0 <= r < len(rows): - for c from 0 <= c < len(columns): + for r in range(len(rows)): + for c in range(len(columns)): A.set_unsafe(r, c, self.get_unsafe(rows[r], columns[c])) return A @@ -393,7 +396,7 @@ cdef class LeanMatrix: cdef long i cdef LeanMatrix A if isinstance(left, LeanMatrix): - if type(left) == type(right): + if type(left) is type(right): return (<LeanMatrix>left)._matrix_times_matrix_(right) else: return NotImplemented @@ -403,7 +406,7 @@ cdef class LeanMatrix: except (TypeError, NotImplemented, ValueError): return NotImplemented A = (<LeanMatrix>right).copy() - for i from 0 <= i < A.nrows(): + for i in range(A.nrows()): A.rescale_row_c(i, left, 0) return A @@ -424,7 +427,7 @@ cdef class LeanMatrix: cdef long i cdef LeanMatrix A = self.copy() x = self.base_ring()(-1) - for i from 0 <= i < A.nrows(): + for i in range(A.nrows()): A.rescale_row_c(i, x, 0) return A @@ -454,7 +457,7 @@ cdef class LeanMatrix: return NotImplemented if not isinstance(left, LeanMatrix) or not isinstance(right, LeanMatrix): return NotImplemented - if type(left) != type(right): + if type(left) is not type(right): return NotImplemented if op == Py_EQ: res = True @@ -465,8 +468,8 @@ cdef class LeanMatrix: return not res if left.ncols() != right.ncols(): return not res - for i from 0 <= i < left.nrows(): - for j from 0 <= j < left.ncols(): + for i in range(left.nrows()): + for j in range(left.ncols()): if (<LeanMatrix>left).get_unsafe(i, j) != (<LeanMatrix>right).get_unsafe(i, j): return not res return res @@ -488,7 +491,7 @@ cdef class LeanMatrix: """ return self.copy() - def __deepcopy__(self, memo={}): + def __deepcopy__(self, memo=None): """ Return a deep copy of ``self``. @@ -543,7 +546,7 @@ cdef class LeanMatrix: - `True, E` -- if there exist a ``m``-separator ``E``. """ - for z in xrange(self.ncols()): + for z in range(self.ncols()): if z in P_cols+Q_cols: continue sol,cert = self.shifting(P_rows,P_cols,Q_rows,Q_cols,z,None,m) @@ -608,22 +611,22 @@ cdef class LeanMatrix: if len(X_1) + len(Y_1) < m: return False, None - cdef set X=set(xrange(self.nrows())) - cdef set Y=set(xrange(self.ncols())) + cdef set X=set(range(self.nrows())) + cdef set Y=set(range(self.ncols())) cdef set X_3 = X-set(X_1+X_2) cdef set Y_3 = Y-set(Y_1+Y_2) cdef list lU_2 = sorted(list(U_2)) cdef list lV_2 = sorted(list(V_2)) - cdef dict rU = dict(zip(lU_2,xrange(len(U_2)))) - cdef dict rV = dict(zip(lV_2,xrange(len(V_2)))) + cdef dict rU = dict(zip(lU_2,range(len(U_2)))) + cdef dict rV = dict(zip(lV_2,range(len(V_2)))) # find a unique representation of every column in U_1xY_3 using columns in U_1xV_2 - B = self.matrix_from_rows_and_columns(list(U_1), xrange(len(Y))) + B = self.matrix_from_rows_and_columns(list(U_1), range(len(Y))) B.gauss_jordan_reduce(lV_2) # find a unique representation of every rows in X_3xV_1 using rows in U_2xV_1 - BT = self.matrix_from_rows_and_columns(xrange(len(X)),list(V_1)).transpose() + BT = self.matrix_from_rows_and_columns(range(len(X)),list(V_1)).transpose() BT.gauss_jordan_reduce(lU_2) cdef set X_p = set(X_1) @@ -724,25 +727,25 @@ cdef class GenericMatrix(LeanMatrix): if nrows == (<GenericMatrix>M)._nrows and ncols == (<GenericMatrix>M)._ncols: self._entries = (<GenericMatrix>M)._entries[:] # Slicing notation makes copy else: - for i from 0 <= i < (<GenericMatrix>M)._nrows: + for i in range((<GenericMatrix>M)._nrows): self._entries[i * self._ncols:i * self._ncols + (<GenericMatrix>M)._ncols] = (<GenericMatrix>M)._entries[i * (<GenericMatrix>M)._ncols:(i + 1) * (<GenericMatrix>M)._ncols] elif isinstance(M, LeanMatrix): if ring_override: - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): self._entries[i * self._ncols + j] = self._base_ring((<LeanMatrix>M).get_unsafe(i, j)) else: - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): self._entries[i * self._ncols + j] = (<LeanMatrix>M).get_unsafe(i, j) else: # Sage Matrix or otherwise if ring_override: - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): self._entries[i * self._ncols + j] = self._base_ring(M[i, j]) else: - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): self._entries[i * self._ncols + j] = M[i, j] def __repr__(self): @@ -779,7 +782,6 @@ cdef class GenericMatrix(LeanMatrix): Warning: assumes ``M`` is a GenericMatrix instance! """ cdef GenericMatrix A - cdef long i, j A = GenericMatrix(0, 0, ring=self._base_ring) A._entries = self._entries + ((<GenericMatrix>M)._entries) A._nrows = self._nrows + M.nrows() @@ -794,14 +796,14 @@ cdef class GenericMatrix(LeanMatrix): cdef long i cdef long Mn = M.ncols() A = GenericMatrix(self._nrows, self._ncols + Mn, ring=self._base_ring) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): A._entries[i * A._ncols:i * A._ncols + self._ncols] = self._entries[i * self._ncols:(i + 1) * self._ncols] A._entries[i * A._ncols + self._ncols:(i + 1) * A._ncols]=(<GenericMatrix>M)._entries[i * Mn:(i + 1) * Mn] return A cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation cdef GenericMatrix A = GenericMatrix(self._nrows, self._ncols + self._nrows, ring=self._base_ring) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): A._entries[i * A._ncols + i] = self._one A._entries[i * A._ncols + self._nrows:(i + 1) * A._ncols]=self._entries[i * self._ncols:(i + 1) * self._ncols] return A @@ -857,8 +859,8 @@ cdef class GenericMatrix(LeanMatrix): cdef GenericMatrix A cdef long i, j A = GenericMatrix(self._ncols, self._nrows, ring=self._base_ring) - for i from 0 <= i < self._nrows: - for j from 0 <= j < self._ncols: + for i in range(self._nrows): + for j in range(self._ncols): A.set_unsafe(j, i, self.get_unsafe(i, j)) return A @@ -868,7 +870,7 @@ cdef class GenericMatrix(LeanMatrix): """ cdef long k res = 0 - for k from 0 <= k < self._ncols: + for k in range(self._ncols): x = self.get_unsafe(i, k) y = self.get_unsafe(j, k) if y and y != self._one: @@ -884,10 +886,10 @@ cdef class GenericMatrix(LeanMatrix): cdef long i, j, t ot = <GenericMatrix > other A = GenericMatrix(self._nrows, ot._ncols, ring=self._base_ring) - for i from 0 <= i < A._nrows: - for j from 0 <= j < A._ncols: + for i in range(A._nrows): + for j in range(A._ncols): s = self._zero - for t from 0 <= t < self._ncols: + for t in range(self._ncols): s += self.get_unsafe(i, t) * ot.get_unsafe(t, j) A.set_unsafe(i, j, s) return A @@ -984,7 +986,7 @@ cdef class BinaryMatrix(LeanMatrix): EXAMPLES:: sage: from sage.matroids.lean_matrix import * - sage: A = BinaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest + sage: A = BinaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest sage: A.nrows() 2 """ @@ -996,7 +998,7 @@ cdef class BinaryMatrix(LeanMatrix): j = max(1, (<BinaryMatrix>M)._ncols) else: j = max(1, self._ncols) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_init(self._M[i], j) bitset_clear(self._M[i]) bitset_init(self._temp, j) @@ -1008,7 +1010,7 @@ cdef class BinaryMatrix(LeanMatrix): EXAMPLES:: sage: from sage.matroids.lean_matrix import * - sage: A = BinaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest + sage: A = BinaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest sage: A.nrows() 2 """ @@ -1021,16 +1023,16 @@ cdef class BinaryMatrix(LeanMatrix): GF2_not_defined = False if M is not None: if isinstance(M, BinaryMatrix): - for i from 0 <= i < M.nrows(): + for i in range(M.nrows()): bitset_copy(self._M[i], (<BinaryMatrix>M)._M[i]) elif isinstance(M, LeanMatrix): - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): if int((<LeanMatrix>M).get_unsafe(i, j)) & 1: self.set(i, j) elif isinstance(M, Matrix): - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): if int((<Matrix>M).get_unsafe(i, j)) & 1: self.set(i, j) else: @@ -1038,7 +1040,7 @@ cdef class BinaryMatrix(LeanMatrix): def __dealloc__(self): cdef long i - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_free(self._M[i]) sig_free(self._M) bitset_free(self._temp) @@ -1057,10 +1059,10 @@ cdef class BinaryMatrix(LeanMatrix): out = str(self._nrows) + ' x ' + str(self._ncols) + ' BinaryMatrix' cdef long i if self._ncols > 0: - for i from 0 <= i < self._nrows: + for i in range(self._nrows): out += '\n[' + bitset_string(self._M[i]) + ']' else: - for i from 0 <= i < self._nrows: + for i in range(self._nrows): out += '[]' return out @@ -1077,8 +1079,8 @@ cdef class BinaryMatrix(LeanMatrix): """ cdef long i, j M = sage.matrix.constructor.Matrix(GF(2), self._nrows, self._ncols) - for i from 0 <= i < self._nrows: - for j from 0 <= j < self._ncols: + for i in range(self._nrows): + for j in range(self._ncols): if bitset_in(self._M[i], j): M[i, j] = 1 return M @@ -1087,7 +1089,7 @@ cdef class BinaryMatrix(LeanMatrix): cdef BinaryMatrix B cdef long i B = BinaryMatrix(self.nrows(), self.ncols()) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_copy(B._M[i], self._M[i]) return B @@ -1097,14 +1099,14 @@ cdef class BinaryMatrix(LeanMatrix): """ cdef long i, c if k < self._nrows: - for i from k <= i < self._nrows: + for i in range(k, self._nrows): bitset_free(self._M[i]) self._nrows = k self._M = <bitset_t* > sig_realloc(self._M, k * sizeof(bitset_t)) if k > self._nrows: self._M = <bitset_t* > sig_realloc(self._M, k * sizeof(bitset_t)) c = max(1, self._ncols) - for i from self._nrows <= i < k: + for i in range(self._nrows, k): bitset_init(self._M[i], c) bitset_clear(self._M[i]) self._nrows = k @@ -1120,7 +1122,7 @@ cdef class BinaryMatrix(LeanMatrix): cdef BinaryMatrix M = <BinaryMatrix > MM cdef long i R = BinaryMatrix(self.nrows() + M.nrows(), self.ncols(), self) - for i from 0 <= i < M.nrows(): + for i in range(M.nrows()): bitset_copy(R._M[i + self.nrows()], M._M[i]) return R @@ -1133,8 +1135,8 @@ cdef class BinaryMatrix(LeanMatrix): cdef BinaryMatrix M = <BinaryMatrix > MM cdef long i, j R = BinaryMatrix(self.nrows(), self.ncols() + M.ncols(), self) - for i from 0 <= i < R.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(R.nrows()): + for j in range(M.ncols()): bitset_set_to(R._M[i], self.ncols() + j, bitset_in(M._M[i], j)) return R @@ -1142,9 +1144,9 @@ cdef class BinaryMatrix(LeanMatrix): """ Return the matrix obtained by prepending an identity matrix. Special case of ``augment``. """ - cdef long i, j + cdef long i cdef BinaryMatrix A = BinaryMatrix(self._nrows, self._ncols + self._nrows) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_lshift(A._M[i], self._M[i], self._nrows) A.set(i, i) return A @@ -1211,8 +1213,8 @@ cdef class BinaryMatrix(LeanMatrix): This is different from what matroid theorists tend to call a pivot, as it does not involve a column exchange! """ - cdef long i, j - for i from 0 <= i < self._nrows: + cdef long i + for i in range(self._nrows): if bitset_in(self._M[i], y) and i != x: bitset_symmetric_difference(self._M[i], self._M[i], self._M[x]) return 0 @@ -1275,7 +1277,7 @@ cdef class BinaryMatrix(LeanMatrix): cdef BinaryMatrix T cdef long i, j T = BinaryMatrix(self._ncols, self._nrows) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): j = bitset_first(self._M[i]) while j >= 0: T.set(j, i) @@ -1290,7 +1292,7 @@ cdef class BinaryMatrix(LeanMatrix): cdef BinaryMatrix ot = <BinaryMatrix > other M = BinaryMatrix(self._nrows, ot._ncols) cdef long i, j - for i from 0 <= i < self._nrows: + for i in range(self._nrows): j = bitset_first(self._M[i]) while j >= 0: bitset_symmetric_difference(M._M[i], M._M[i], ot._M[j]) @@ -1303,8 +1305,8 @@ cdef class BinaryMatrix(LeanMatrix): """ cdef long r, c cdef BinaryMatrix A = BinaryMatrix(len(rows), len(columns)) - for r from 0 <= r < len(rows): - for c from 0 <= c < len(columns): + for r in range(len(rows)): + for c in range(len(columns)): if bitset_in(self._M[rows[r]], <mp_bitcnt_t> columns[c]): bitset_add(A._M[r], c) return A @@ -1348,17 +1350,17 @@ cdef class BinaryMatrix(LeanMatrix): bitset_complement(mask, mask) # copy relevant part of this matrix into A cdef bitset_t row, row2 - for r in xrange(len(rows)): + for r in range(len(rows)): row = self._M[rows[r]] row2 = A._M[r] bitset_intersection(row2, row, mask) # yes, this is safe - for g in xrange(lg): + for g in range(lg): if bitset_in(row, cols[g]): bitset_add(row2, gaps[g]) # record order of the columns in list `order` - cdef list order = list(xrange(lc)) + cdef list order = list(range(lc)) g = 0 - for g in xrange(lg): + for g in range(lg): order[gaps[g]] = cols[g] # free up the two arrays and the bitset sig_free(gaps) @@ -1372,7 +1374,7 @@ cdef class BinaryMatrix(LeanMatrix): """ cdef long i I = [] - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_intersection(self._temp, self._M[i], x) I.append(bitset_len(self._temp)) return I @@ -1383,7 +1385,7 @@ cdef class BinaryMatrix(LeanMatrix): """ cdef BinaryMatrix Q d = {} - for i from 0 <= i < self._nrows: + for i in range(self._nrows): c = hash(tuple(P._character(self._M[i]))) if c in d: d[c].append(i) @@ -1406,8 +1408,8 @@ cdef class BinaryMatrix(LeanMatrix): cdef long i, j, r Q = BinaryMatrix(self._ncols, self._ncols) r = 0 - for i from 0 <= i < self._nrows: - for j from 0 <= j < P._nrows: + for i in range(self._nrows): + for j in range(P._nrows): bitset_intersection(self._temp, self._M[i], P._M[j]) if not bitset_isempty(self._temp): bitset_copy(Q._M[r], self._temp) @@ -1420,9 +1422,9 @@ cdef class BinaryMatrix(LeanMatrix): Helper method for isomorphism test. """ cdef BinaryMatrix Q - cdef long i, r + cdef long i Q = BinaryMatrix(self._nrows + 1, self._ncols) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_copy(Q._M[i], self._M[i]) bitset_discard(Q._M[i], j) bitset_add(Q._M[self._nrows], j) @@ -1454,19 +1456,19 @@ cdef class BinaryMatrix(LeanMatrix): if s_eq.nrows() != o_eq.nrows(): return False if s_eq.nrows() == s_eq.ncols(): # s_eq and o_eq partition into singletons - morph = [0 for i from 0 <= i < self._nrows] - for i from 0 <= i < self._nrows: + morph = [0 for i in range(self._nrows)] + for i in range(self._nrows): morph[bitset_first(s_eq._M[i])] = bitset_first(o_eq._M[i]) - for i from 0 <= i < self._nrows: - for j from 0 <= j < self._ncols: + for i in range(self._nrows): + for j in range(self._ncols): if self.get(i, j) != other.get(morph[i], morph[j]): return False return True - for i from 0 <= i < s_eq.nrows(): + for i in range(s_eq.nrows()): if s_eq.row_len(i) != o_eq.row_len(i): return False - for i from 0 <= i < s_eq.nrows(): + for i in range(s_eq.nrows()): if s_eq.row_len(i) > 1: break e = bitset_first(s_eq._M[i]) @@ -1529,7 +1531,7 @@ cdef class BinaryMatrix(LeanMatrix): return not res if left.ncols() != right.ncols(): return not res - for i from 0 <= i < left.nrows(): + for i in range(left.nrows()): if not bitset_eq((<BinaryMatrix>left)._M[i], (<BinaryMatrix>right)._M[i]): return not res return res @@ -1555,7 +1557,7 @@ cdef class BinaryMatrix(LeanMatrix): size = 0 limbs = 0 longsize = 0 - for i from 0 <= i < self.nrows(): + for i in range(self.nrows()): versionB, size, limbs, longsize, data = bitset_pickle(self._M[i]) M.append(data) data = (self.nrows(), self.ncols(), versionB, size, limbs, longsize, M) @@ -1593,7 +1595,7 @@ cdef class TernaryMatrix(LeanMatrix): EXAMPLES:: sage: from sage.matroids.lean_matrix import * - sage: A = TernaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest + sage: A = TernaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest sage: A.nrows() 2 """ @@ -1615,7 +1617,7 @@ cdef class TernaryMatrix(LeanMatrix): j = max(1, (<TernaryMatrix>M)._ncols) else: j = max(1, self._ncols) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_init(self._M0[i], j) bitset_clear(self._M0[i]) bitset_init(self._M1[i], j) @@ -1631,20 +1633,20 @@ cdef class TernaryMatrix(LeanMatrix): EXAMPLES:: sage: from sage.matroids.lean_matrix import * - sage: A = TernaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest + sage: A = TernaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest sage: A.nrows() 2 """ cdef long i, j if M is not None: if isinstance(M, TernaryMatrix): - for i from 0 <= i < (<TernaryMatrix>M)._nrows: + for i in range((<TernaryMatrix>M)._nrows): bitset_copy(self._M0[i], (<TernaryMatrix>M)._M0[i]) bitset_copy(self._M1[i], (<TernaryMatrix>M)._M1[i]) return if isinstance(M, LeanMatrix): - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): s = int((<LeanMatrix>M).get_unsafe(i, j)) % 3 if s: bitset_add(self._M0[i], j) @@ -1652,8 +1654,8 @@ cdef class TernaryMatrix(LeanMatrix): bitset_add(self._M1[i], j) return if isinstance(M, Matrix): - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): s = int((<Matrix>M).get_unsafe(i, j)) % 3 if s: bitset_add(self._M0[i], j) @@ -1662,7 +1664,7 @@ cdef class TernaryMatrix(LeanMatrix): def __dealloc__(self): cdef long i - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_free(self._M0[i]) bitset_free(self._M1[i]) sig_free(self._M0) @@ -1685,9 +1687,9 @@ cdef class TernaryMatrix(LeanMatrix): out = str(self._nrows) + ' x ' + str(self._ncols) + ' TernaryMatrix' cdef long i if self._ncols > 0: - for i from 0 <= i < self._nrows: + for i in range(self._nrows): out += '\n[' - for j from 0 <= j < self._ncols: + for j in range(self._ncols): x = self.get(i, j) if x == 0: out += '0' @@ -1697,7 +1699,7 @@ cdef class TernaryMatrix(LeanMatrix): out += '-' out += ']' else: - for i from 0 <= i < self._nrows: + for i in range(self._nrows): out += '[]' return out @@ -1735,7 +1737,7 @@ cdef class TernaryMatrix(LeanMatrix): cdef TernaryMatrix T cdef long i T = TernaryMatrix(self._nrows, self._ncols) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_copy(T._M0[i], self._M0[i]) bitset_copy(T._M1[i], self._M1[i]) return T @@ -1747,7 +1749,7 @@ cdef class TernaryMatrix(LeanMatrix): cdef long i cdef mp_bitcnt_t c if k < self._nrows: - for i from k <= i < self._nrows: + for i in range(k, self._nrows): bitset_free(self._M0[i]) bitset_free(self._M1[i]) self._nrows = k @@ -1757,7 +1759,7 @@ cdef class TernaryMatrix(LeanMatrix): self._M0 = <bitset_t* > sig_realloc(self._M0, k * sizeof(bitset_t)) self._M1 = <bitset_t* > sig_realloc(self._M1, k * sizeof(bitset_t)) c = max(1, self._ncols) - for i from self._nrows <= i < k: + for i in range(self._nrows, k): bitset_init(self._M0[i], c) bitset_clear(self._M0[i]) bitset_init(self._M1[i], c) @@ -1770,7 +1772,7 @@ cdef class TernaryMatrix(LeanMatrix): cdef TernaryMatrix M = <TernaryMatrix > MM cdef long i R = TernaryMatrix(self.nrows() + M.nrows(), self.ncols(), self) - for i from 0 <= i < M.nrows(): + for i in range(M.nrows()): bitset_copy(R._M0[i + self.nrows()], M._M0[i]) bitset_copy(R._M1[i + self.nrows()], M._M1[i]) return R @@ -1780,8 +1782,8 @@ cdef class TernaryMatrix(LeanMatrix): cdef TernaryMatrix M = <TernaryMatrix > MM cdef long i, j R = TernaryMatrix(self.nrows(), self.ncols() + M.ncols(), self) - for i from 0 <= i < R.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(R.nrows()): + for j in range(M.ncols()): bitset_set_to(R._M0[i], self.ncols() + j, bitset_in(M._M0[i], j)) bitset_set_to(R._M1[i], self.ncols() + j, bitset_in(M._M1[i], j)) return R @@ -1792,9 +1794,9 @@ cdef class TernaryMatrix(LeanMatrix): Special case of ``augment``. """ - cdef long i, j + cdef long i cdef TernaryMatrix A = TernaryMatrix(self._nrows, self._ncols + self._nrows) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_lshift(A._M0[i], self._M0[i], self._nrows) bitset_lshift(A._M1[i], self._M1[i], self._nrows) A.set(i, i, 1) @@ -1932,10 +1934,10 @@ cdef class TernaryMatrix(LeanMatrix): This is different from what matroid theorists tend to call a pivot, as it does not involve a column exchange! """ - cdef long i, j + cdef long i if self._is_negative(x, y): self._row_negate(x) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): if self.is_nonzero(i, y) and i != x: if self._is_negative(i, y): self.add_multiple_of_row_c(i, x, 1, 0) @@ -1956,7 +1958,7 @@ cdef class TernaryMatrix(LeanMatrix): cdef TernaryMatrix T cdef long i, j T = TernaryMatrix(self._ncols, self._nrows) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): j = bitset_first(self._M0[i]) while j >= 0: bitset_add(T._M0[j], i) @@ -1972,7 +1974,7 @@ cdef class TernaryMatrix(LeanMatrix): cdef TernaryMatrix M M = TernaryMatrix(self._nrows + 1, other.ncols()) cdef long i, j - for i from 0 <= i < self._nrows: + for i in range(self._nrows): j = bitset_first(self._M0[i]) while j >= 0: bitset_copy(M._M0[self._nrows], (<TernaryMatrix>other)._M0[j]) @@ -2025,14 +2027,14 @@ cdef class TernaryMatrix(LeanMatrix): # copy relevant part of this matrix into A cdef bitset_t row0, row1, row0_2, row1_2 cdef mp_bitcnt_t p, q - for r in xrange(len(rows)): + for r in range(len(rows)): row0 = self._M0[rows[r]] row1 = self._M1[rows[r]] row0_2 = A._M0[r] row1_2 = A._M1[r] bitset_intersection(row0_2, row0, mask) # yes, this is safe bitset_intersection(row1_2, row1, mask) # yes, this is safe - for g in xrange(lg): + for g in range(lg): p = cols[g] if bitset_in(row0, p): q = gaps[g] @@ -2040,9 +2042,9 @@ cdef class TernaryMatrix(LeanMatrix): if bitset_in(row1, p): bitset_add(row1_2, q) # record order of the columns in list `order` - cdef list order = list(xrange(lc)) + cdef list order = list(range(lc)) g = 0 - for g in xrange(lg): + for g in range(lg): order[gaps[g]] = cols[g] # free up the two arrays and the bitset sig_free(gaps) @@ -2085,7 +2087,7 @@ cdef class TernaryMatrix(LeanMatrix): return not res if left.ncols() != right.ncols(): return not res - for i from 0 <= i < left.nrows(): + for i in range(left.nrows()): if not bitset_eq((<TernaryMatrix>left)._M0[i], (<TernaryMatrix>right)._M0[i]): return not res if not bitset_eq((<TernaryMatrix>left)._M1[i], (<TernaryMatrix>right)._M1[i]): @@ -2114,7 +2116,7 @@ cdef class TernaryMatrix(LeanMatrix): size = 0 limbs = 0 longsize = 0 - for i from 0 <= i < self.nrows(): + for i in range(self.nrows()): versionB, size, limbs, longsize, data = bitset_pickle(self._M0[i]) M0.append(data) versionB, size, limbs, longsize, data = bitset_pickle(self._M1[i]) @@ -2152,7 +2154,7 @@ cdef class QuaternaryMatrix(LeanMatrix): EXAMPLES:: sage: from sage.matroids.lean_matrix import * - sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest + sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest sage: A.nrows() 2 """ @@ -2167,7 +2169,7 @@ cdef class QuaternaryMatrix(LeanMatrix): else: j = max(1, self._ncols) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_init(self._M0[i], j) bitset_clear(self._M0[i]) bitset_init(self._M1[i], j) @@ -2183,7 +2185,7 @@ cdef class QuaternaryMatrix(LeanMatrix): EXAMPLES:: sage: from sage.matroids.lean_matrix import * - sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest + sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest sage: A.nrows() 2 """ @@ -2195,7 +2197,7 @@ cdef class QuaternaryMatrix(LeanMatrix): self._one = self._gf4(1) self._x_zero = self._gf4.gens()[0] self._x_one = self._x_zero + self._one - for i from 0 <= i < (<QuaternaryMatrix>M)._nrows: + for i in range((<QuaternaryMatrix>M)._nrows): bitset_copy(self._M0[i], (<QuaternaryMatrix>M)._M0[i]) bitset_copy(self._M1[i], (<QuaternaryMatrix>M)._M1[i]) elif isinstance(M, LeanMatrix): @@ -2204,8 +2206,8 @@ cdef class QuaternaryMatrix(LeanMatrix): self._one = self._gf4(1) self._x_zero = self._gf4.gens()[0] self._x_one = self._x_zero + self._one - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): self.set(i, j, (<LeanMatrix>M).get_unsafe(i, j)) elif isinstance(M, Matrix): self._gf4 = (<Matrix>M).base_ring() @@ -2213,8 +2215,8 @@ cdef class QuaternaryMatrix(LeanMatrix): self._one = self._gf4(1) self._x_zero = self._gf4.gens()[0] self._x_one = self._x_zero + self._one - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): self.set(i, j, (<Matrix>M).get_unsafe(i, j)) else: raise TypeError("unrecognized input type.") @@ -2232,13 +2234,13 @@ cdef class QuaternaryMatrix(LeanMatrix): EXAMPLES:: sage: from sage.matroids.lean_matrix import * - sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest + sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest sage: A.nrows() 2 sage: A = None """ cdef long i - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_free(self._M0[i]) bitset_free(self._M1[i]) sig_free(self._M0) @@ -2261,9 +2263,9 @@ cdef class QuaternaryMatrix(LeanMatrix): out = str(self._nrows) + ' x ' + str(self._ncols) + ' QuaternaryMatrix' cdef long i if self._ncols > 0: - for i from 0 <= i < self._nrows: + for i in range(self._nrows): out += '\n[' - for j from 0 <= j < self._ncols: + for j in range(self._ncols): x = self.get(i, j) if x == self._zero: out += '0' @@ -2275,7 +2277,7 @@ cdef class QuaternaryMatrix(LeanMatrix): out += 'y' out += ']' else: - for i from 0 <= i < self._nrows: + for i in range(self._nrows): out += '[]' return out @@ -2292,8 +2294,8 @@ cdef class QuaternaryMatrix(LeanMatrix): [0 0 0] """ M = sage.matrix.constructor.Matrix(self._gf4, self._nrows, self._ncols) - for i from 0 <= i < self._nrows: - for j from 0 <= j < self._ncols: + for i in range(self._nrows): + for j in range(self._ncols): M[i, j] = self.get(i, j) return M @@ -2338,7 +2340,7 @@ cdef class QuaternaryMatrix(LeanMatrix): cdef QuaternaryMatrix T cdef long i T = QuaternaryMatrix(self._nrows, self._ncols, ring=self._gf4) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_copy(T._M0[i], self._M0[i]) bitset_copy(T._M1[i], self._M1[i]) return T @@ -2349,7 +2351,7 @@ cdef class QuaternaryMatrix(LeanMatrix): """ cdef mp_bitcnt_t c if k < self._nrows: - for i from k <= i < self._nrows: + for i in range(k, self._nrows): bitset_free(self._M0[i]) bitset_free(self._M1[i]) self._nrows = k @@ -2359,7 +2361,7 @@ cdef class QuaternaryMatrix(LeanMatrix): self._M0 = <bitset_t* > sig_realloc(self._M0, k * sizeof(bitset_t)) self._M1 = <bitset_t* > sig_realloc(self._M1, k * sizeof(bitset_t)) c = max(1, self._ncols) - for i from self._nrows <= i < k: + for i in range(self._nrows, k): bitset_init(self._M0[i], c) bitset_clear(self._M0[i]) bitset_init(self._M1[i], c) @@ -2372,7 +2374,7 @@ cdef class QuaternaryMatrix(LeanMatrix): cdef QuaternaryMatrix M = <QuaternaryMatrix > MM cdef long i R = QuaternaryMatrix(self.nrows() + M.nrows(), self.ncols(), self) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_copy(R._M0[i + self.nrows()], M._M0[i]) bitset_copy(R._M1[i + self.nrows()], M._M1[i]) return R @@ -2382,8 +2384,8 @@ cdef class QuaternaryMatrix(LeanMatrix): cdef QuaternaryMatrix M = <QuaternaryMatrix > MM cdef long i, j R = QuaternaryMatrix(self.nrows(), self.ncols() + M.ncols(), self) - for i from 0 <= i < R.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(R.nrows()): + for j in range(M.ncols()): bitset_set_to(R._M0[i], self.ncols() + j, bitset_in(M._M0[i], j)) bitset_set_to(R._M1[i], self.ncols() + j, bitset_in(M._M1[i], j)) return R @@ -2393,9 +2395,9 @@ cdef class QuaternaryMatrix(LeanMatrix): Return the matrix obtained by prepending an identity matrix. Special case of ``augment``. """ - cdef long i, j + cdef long i cdef QuaternaryMatrix A = QuaternaryMatrix(self._nrows, self._ncols + self._nrows, ring=self._gf4) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_lshift(A._M0[i], self._M0[i], self._nrows) bitset_lshift(A._M1[i], self._M1[i], self._nrows) A.set(i, i, 1) @@ -2519,9 +2521,9 @@ cdef class QuaternaryMatrix(LeanMatrix): This is different from what matroid theorists tend to call a pivot, as it does not involve a column exchange! """ - cdef long i, j + cdef long i self._row_div(x, self.get(x, y)) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): if self.is_nonzero(i, y) and i != x: self.add_multiple_of_row_c(i, x, self.get(i, y), 0) return 0 @@ -2540,8 +2542,8 @@ cdef class QuaternaryMatrix(LeanMatrix): cdef QuaternaryMatrix T cdef long i, j T = QuaternaryMatrix(self._ncols, self._nrows, ring=self._gf4) - for i from 0 <= i < self._ncols: - for j from 0 <= j < self._nrows: + for i in range(self._ncols): + for j in range(self._nrows): T.set(i, j, self.get(j, i)) return T @@ -2550,7 +2552,7 @@ cdef class QuaternaryMatrix(LeanMatrix): Apply the nontrivial GF(4)-automorphism to the entries. """ cdef long i - for i from 0 <= i < self._nrows: + for i in range(self._nrows): bitset_symmetric_difference(self._M0[i], self._M0[i], self._M1[i]) cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other): @@ -2561,8 +2563,8 @@ cdef class QuaternaryMatrix(LeanMatrix): ot = <QuaternaryMatrix > other M = QuaternaryMatrix(self._nrows + 1, ot._ncols, ring=self._gf4) cdef long i, j - for i from 0 <= i < self._nrows: - for j from 0 <= j < self._ncols: + for i in range(self._nrows): + for j in range(self._ncols): bitset_copy(M._M0[self._nrows], ot._M0[j]) bitset_copy(M._M1[self._nrows], ot._M1[j]) M.add_multiple_of_row_c(i, self._nrows, self.get(i, j), 0) @@ -2609,14 +2611,14 @@ cdef class QuaternaryMatrix(LeanMatrix): # copy relevant part of this matrix into A cdef bitset_t row0, row1, row0_2, row1_2 cdef mp_bitcnt_t p, q - for r in xrange(len(rows)): + for r in range(len(rows)): row0 = self._M0[rows[r]] row1 = self._M1[rows[r]] row0_2 = A._M0[r] row1_2 = A._M1[r] bitset_intersection(row0_2, row0, mask) # yes, this is safe bitset_intersection(row1_2, row1, mask) - for g in xrange(lg): + for g in range(lg): p = cols[g] q = gaps[g] if bitset_in(row0, p): @@ -2624,9 +2626,9 @@ cdef class QuaternaryMatrix(LeanMatrix): if bitset_in(row1, p): bitset_add(row1_2, q) # record order of the columns in list `order` - cdef list order = list(xrange(lc)) + cdef list order = list(range(lc)) g = 0 - for g in xrange(lg): + for g in range(lg): order[gaps[g]] = cols[g] # free up the two arrays and the bitset sig_free(gaps) @@ -2687,7 +2689,7 @@ cdef class QuaternaryMatrix(LeanMatrix): return not res if left.ncols() != right.ncols(): return not res - for i from 0 <= i < left.nrows(): + for i in range(left.nrows()): if not bitset_eq((<QuaternaryMatrix>left)._M0[i], (<QuaternaryMatrix>right)._M0[i]): return not res if not bitset_eq((<QuaternaryMatrix>left)._M1[i], (<QuaternaryMatrix>right)._M1[i]): @@ -2717,7 +2719,7 @@ cdef class QuaternaryMatrix(LeanMatrix): limbs = 0 longsize = 0 ring = self._gf4 - for i from 0 <= i < self.nrows(): + for i in range(self.nrows()): versionB, size, limbs, longsize, data = bitset_pickle(self._M0[i]) M0.append(data) versionB, size, limbs, longsize, data = bitset_pickle(self._M1[i]) @@ -2740,7 +2742,7 @@ cpdef GenericMatrix generic_identity(n, ring): """ cdef long i cdef GenericMatrix A = GenericMatrix(n, n, ring=ring) - for i from 0 <= i < n: + for i in range(n): A.set_unsafe(i, i, A._one) return A @@ -2773,8 +2775,8 @@ cdef class PlusMinusOneMatrix(LeanMatrix): EXAMPLES:: - sage: M = Matroid(graphs.CompleteGraph(4).incidence_matrix(oriented=True), - ....: regular=True) # indirect doctest + sage: M = Matroid(graphs.CompleteGraph(4).incidence_matrix(oriented=True), # indirect doctest + ....: regular=True) sage: M.is_isomorphic(matroids.Wheel(3)) True """ @@ -2785,7 +2787,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): EXAMPLES:: sage: from sage.matroids.lean_matrix import * - sage: A = PlusMinusOneMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest + sage: A = PlusMinusOneMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest sage: A.nrows() 2 """ @@ -2809,15 +2811,15 @@ cdef class PlusMinusOneMatrix(LeanMatrix): cdef long i, j if M is not None: if isinstance(M, PlusMinusOneMatrix): - for i from 0 <= i < M.nrows(): + for i in range(M.nrows()): memcpy(self._entries + i * self._ncols, (<PlusMinusOneMatrix>M)._entries + i * (<PlusMinusOneMatrix>M)._ncols, (<PlusMinusOneMatrix>M)._ncols * sizeof(int)) elif isinstance(M, LeanMatrix): - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): self._entries[i * self._ncols + j] = int((<LeanMatrix>M).get_unsafe(i, j)) else: # Sage Matrix or otherwise - for i from 0 <= i < M.nrows(): - for j from 0 <= j < M.ncols(): + for i in range(M.nrows()): + for j in range(M.ncols()): self._entries[i * self._ncols + j] = int(M[i, j]) def __dealloc__(self): @@ -2827,7 +2829,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): EXAMPLES:: sage: from sage.matroids.lean_matrix import * - sage: A = PlusMinusOneMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest + sage: A = PlusMinusOneMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest sage: A.nrows() 2 sage: A = None @@ -2919,7 +2921,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): cdef long i cdef long Mn = M.ncols() A = PlusMinusOneMatrix(self._nrows, self._ncols + Mn) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): memcpy(A._entries + i * A._ncols, self._entries + i * self._ncols, self._ncols * sizeof(int)) memcpy(A._entries + (i * A._ncols + self._ncols), (<PlusMinusOneMatrix>M)._entries + i * Mn, Mn * sizeof(int)) return A @@ -2927,7 +2929,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation cdef PlusMinusOneMatrix A = PlusMinusOneMatrix(self._nrows, self._ncols + self._nrows, ring=self._base_ring) cdef long i - for i from 0 <= i < self._nrows: + for i in range(self._nrows): A._entries[i * A._ncols + i] = 1 memcpy(A._entries + (i * A._ncols + self._nrows), self._entries + i * self._ncols, self._ncols * sizeof(int)) return A @@ -2964,7 +2966,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): """ cdef long k cdef long res = 0 - for k from 0 <= k < self._ncols: + for k in range(self._ncols): if self.get(i, k): res += 1 return res @@ -2975,7 +2977,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): """ cdef long k cdef int res = 0 - for k from 0 <= k < self._ncols: + for k in range(self._ncols): res += self.get(i, k) * self.get(j, k) return res @@ -2987,11 +2989,11 @@ cdef class PlusMinusOneMatrix(LeanMatrix): cdef long i cdef int sval if s is None: - for i from 0 <= i < self._ncols: + for i in range(self._ncols): self.set(x, i, self.get(x, i) + self.get(y, i)) else: sval = s - for i from 0 <= i < self._ncols: + for i in range(self._ncols): self.set(x, i, self.get(x, i) + sval * self.get(y, i)) return 0 @@ -3016,7 +3018,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): """ cdef long i cdef int sval = s - for i from 0 <= i < self._ncols: + for i in range(self._ncols): self.set(x, i, sval * self.get(x, i)) return 0 @@ -3027,7 +3029,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): """ cdef long j cdef int sval = s - for j from 0 <= j < self._nrows: + for j in range(self._nrows): self.set(j, y, self.get(j, y) * sval) return 0 @@ -3044,11 +3046,11 @@ cdef class PlusMinusOneMatrix(LeanMatrix): This is different from what matroid theorists tend to call a pivot, as it does not involve a column exchange! """ - cdef long i, j + cdef long i cdef int a, s a = self.get(x, y) # 1 or -1, so inverse is equal to itself self.rescale_row_c(x, a, 0) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): s = self.get(i, y) if s and i != x: self.add_multiple_of_row_c(i, x, -s, 0) @@ -3060,7 +3062,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): """ cdef long j cdef list res = [] - for j from r * self._ncols <= j < (r + 1) * self._ncols: + for j in range(r * self._ncols, (r + 1) * self._ncols): if self._entries[j]: res.append(j - r * self._ncols) return res @@ -3072,8 +3074,8 @@ cdef class PlusMinusOneMatrix(LeanMatrix): cdef PlusMinusOneMatrix A cdef long i, j A = PlusMinusOneMatrix(self._ncols, self._nrows) - for i from 0 <= i < self._nrows: - for j from 0 <= j < self._ncols: + for i in range(self._nrows): + for j in range(self._ncols): A.set(j, i, self.get(i, j)) return A @@ -3086,10 +3088,10 @@ cdef class PlusMinusOneMatrix(LeanMatrix): cdef int s ot = <PlusMinusOneMatrix> other A = PlusMinusOneMatrix(self._nrows, ot._ncols) - for i from 0 <= i < A._nrows: - for j from 0 <= j < A._ncols: + for i in range(A._nrows): + for j in range(A._ncols): s = 0 - for t from 0 <= t < self._ncols: + for t in range(self._ncols): s += self.get(i, t) * ot.get(t, j) A.set(i, j, s) return A @@ -3116,7 +3118,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): if is_pivot: self.swap_rows_c(p, r) self.rescale_row_c(r, self.get(r, c), 0) # Inverting not needed for integers -1, 1 - for row from 0 <= row < self._nrows: + for row in range(self._nrows): if row != r and self.is_nonzero(row, c): self.add_multiple_of_row_c(row, r, -self.get(row, c), 0) P.append(c) @@ -3160,7 +3162,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): return not res if left.ncols() != right.ncols(): return not res - for i from 0 <= i < left.nrows() * left.ncols(): + for i in range(left.nrows() * left.ncols()): if (<PlusMinusOneMatrix>left)._entries[i] != (<PlusMinusOneMatrix>right)._entries[i]: return not res return res @@ -3182,7 +3184,7 @@ cdef class PlusMinusOneMatrix(LeanMatrix): import sage.matroids.unpickling cdef list entries = [] cdef long i - for i from 0 <= i < self._nrows * self._ncols: + for i in range(self._nrows * self._ncols): entries.append(self._entries[i]) version = 0 data = (self.nrows(), self.ncols(), entries) @@ -3529,7 +3531,7 @@ cdef class RationalMatrix(LeanMatrix): This is different from what matroid theorists tend to call a pivot, as it does not involve a column exchange! """ - cdef long i, j + cdef long i cdef mpq_t t mpq_init(t) mpq_inv(t, self._entries[self.index(x, y)]) diff --git a/src/sage/matroids/linear_matroid.pxd b/src/sage/matroids/linear_matroid.pxd index 3f0c8d88095..9aebd446b68 100644 --- a/src/sage/matroids/linear_matroid.pxd +++ b/src/sage/matroids/linear_matroid.pxd @@ -15,15 +15,14 @@ cdef class LinearMatroid(BasisExchangeMatroid): cpdef characteristic(self) cdef list _setup_internal_representation(self, matrix, reduced_matrix, ring, keep_initial_representation) - cdef __exchange_value(self, long x, long y) + cdef _exchange_value_internal(self, long x, long y) cpdef representation(self, B=*, reduced=*, labels=*, order=*, lift_map=*) cpdef _current_rows_cols(self, B=*) cpdef representation_vectors(self) cpdef LeanMatrix _basic_representation(self, B=*) cpdef LeanMatrix _reduced_representation(self, B=*) - - + cpdef bint _is_field_isomorphism(self, LinearMatroid other, morphism) cpdef is_field_equivalent(self, other) cpdef is_field_isomorphism(self, other, morphism) diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 0c9b0a1baff..36f563aa433 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -111,27 +111,24 @@ Methods # https://www.gnu.org/licenses/ # **************************************************************************** +from copy import copy, deepcopy +from itertools import product + from cpython.object cimport Py_EQ, Py_NE from sage.data_structures.bitset_base cimport * -from sage.structure.richcmp cimport rich_to_bool -from sage.matroids.matroid cimport Matroid -from sage.matroids.basis_exchange_matroid cimport BasisExchangeMatroid -from .lean_matrix cimport (LeanMatrix, GenericMatrix, BinaryMatrix, - TernaryMatrix, QuaternaryMatrix, PlusMinusOneMatrix, - RationalMatrix, generic_identity) -from .set_system cimport SetSystem -from .utilities import newlabel, spanning_stars, spanning_forest, lift_cross_ratios -from sage.graphs.spanning_tree import kruskal -from sage.graphs.graph import Graph - -from sage.matrix.matrix2 cimport Matrix -import sage.matrix.constructor from sage.matrix.constructor import matrix -from copy import copy, deepcopy -from sage.rings.all import ZZ, QQ, FiniteField, GF -import itertools -from itertools import combinations, product +from sage.matrix.matrix2 cimport Matrix +from sage.matroids.basis_exchange_matroid cimport BasisExchangeMatroid +from sage.matroids.lean_matrix cimport (LeanMatrix, GenericMatrix, BinaryMatrix, + TernaryMatrix, QuaternaryMatrix, PlusMinusOneMatrix, + RationalMatrix) +from sage.matroids.matroid cimport Matroid +from sage.matroids.utilities import newlabel, spanning_stars, spanning_forest, lift_cross_ratios +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.structure.richcmp cimport rich_to_bool cdef bint GF2_not_defined = True cdef GF2, GF2_one, GF2_zero @@ -168,7 +165,7 @@ cdef inline characteristic(LeanMatrix A): # cdef long c, p, row # for c in columns: # is_pivot = False -# for row in xrange(r, A.nrows()): +# for row in range(r, A.nrows()): # if A.get_unsafe(row, c) != 0: # is_pivot = True # p = row @@ -176,7 +173,7 @@ cdef inline characteristic(LeanMatrix A): # if is_pivot: # A.swap_rows_c(p, r) # A.rescale_row_c(r, A.get_unsafe(r, c) ** (-1), 0) -# for row in xrange(A.nrows()): +# for row in range(A.nrows()): # if row != r and A.get_unsafe(row, c) != 0: # A.add_multiple_of_row_c(row, r, -A.get_unsafe(row, c), 0) # P.append(c) @@ -269,14 +266,14 @@ cdef class LinearMatroid(BasisExchangeMatroid): EXAMPLES:: sage: from sage.matroids.advanced import * - sage: LinearMatroid(matrix=Matrix(GF(5), [[1, 0, 1, 1, 1], - ....: [0, 1, 1, 2, 3]])) # indirect doctest + sage: LinearMatroid(matrix=Matrix(GF(5), [[1, 0, 1, 1, 1], # indirect doctest + ....: [0, 1, 1, 2, 3]])) Linear matroid of rank 2 on 5 elements represented over the Finite Field of size 5 """ basis = self._setup_internal_representation(matrix, reduced_matrix, ring, keep_initial_representation) if groundset is None: - groundset = list(xrange(self._A.nrows() + self._A.ncols())) + groundset = list(range(self._A.nrows() + self._A.ncols())) else: groundset = list(groundset) if len(groundset) != self._A.nrows() + self._A.ncols(): @@ -292,8 +289,8 @@ cdef class LinearMatroid(BasisExchangeMatroid): EXAMPLES:: sage: from sage.matroids.advanced import * - sage: M = LinearMatroid(matrix=Matrix(GF(5), [[1, 0, 1, 1, 1], - ....: [0, 1, 1, 2, 3]])) # indirect doctest + sage: M = LinearMatroid(matrix=Matrix(GF(5), [[1, 0, 1, 1, 1], # indirect doctest + ....: [0, 1, 1, 2, 3]])) sage: M = None """ if self._prow is not NULL: @@ -320,8 +317,8 @@ cdef class LinearMatroid(BasisExchangeMatroid): A = (<LeanMatrix>matrix).copy() # Deprecated Sage matrix operation if keep_initial_representation: self._representation = A.copy() # Deprecated Sage matrix operation - P = gauss_jordan_reduce(A, xrange(A.ncols())) - self._A = A.matrix_from_rows_and_columns(range(len(P)), [c for c in xrange(matrix.ncols()) if c not in P]) + P = gauss_jordan_reduce(A, range(A.ncols())) + self._A = A.matrix_from_rows_and_columns(range(len(P)), [c for c in range(matrix.ncols()) if c not in P]) else: reduced = True if not isinstance(reduced_matrix, LeanMatrix): @@ -331,20 +328,20 @@ cdef class LinearMatroid(BasisExchangeMatroid): self._A = GenericMatrix(reduced_matrix.nrows(), reduced_matrix.ncols(), M=reduced_matrix, ring=ring) else: self._A = (<LeanMatrix>reduced_matrix).copy() # Deprecated Sage matrix operation - P = list(xrange(self._A.nrows())) + P = list(range(self._A.nrows())) self._prow = <long* > sig_malloc((self._A.nrows() + self._A.ncols()) * sizeof(long)) if matrix is not None: - for r in xrange(len(P)): + for r in range(len(P)): self._prow[P[r]] = r r = 0 - for c in xrange(A.ncols()): + for c in range(A.ncols()): if c not in P: self._prow[c] = r r += 1 else: - for r from 0 <= r < self._A.nrows(): + for r in range(self._A.nrows()): self._prow[r] = r - for r from 0 <= r < self._A.ncols(): + for r in range(self._A.ncols()): self._prow[self._A.nrows() + r] = r return P @@ -394,13 +391,13 @@ cdef class LinearMatroid(BasisExchangeMatroid): """ return characteristic(self._A) - cdef bint __is_exchange_pair(self, long x, long y) except -1: + cdef bint _is_exchange_pair(self, long x, long y) except -1: r""" Check if ``self.basis() - x + y`` is again a basis. Internal method. """ return self._A.is_nonzero(self._prow[x], self._prow[y]) - cdef int __exchange(self, long x, long y) except -1: + cdef int _exchange(self, long x, long y) except -1: """ Put element indexed by ``x`` into basis, taking out element ``y``. Assumptions are that this is a valid basis exchange. @@ -416,16 +413,16 @@ cdef class LinearMatroid(BasisExchangeMatroid): pivi = piv ** (-1) self._A.rescale_row_c(px, pivi, 0) self._A.set_unsafe(px, py, pivi + self._one) # pivoting without column scaling. Add extra so column does not need adjusting - for r in xrange(self._A.nrows()): # if A and A' are the matrices before and after pivoting, then + for r in range(self._A.nrows()): # if A and A' are the matrices before and after pivoting, then a = self._A.get_unsafe(r, py) # ker[I A] equals ker[I A'] except for the labelling of the columns if a and r != px: self._A.add_multiple_of_row_c(r, px, -a, 0) self._A.set_unsafe(px, py, pivi) self._prow[y] = px self._prow[x] = py - BasisExchangeMatroid.__exchange(self, x, y) + BasisExchangeMatroid._exchange(self, x, y) - cdef __exchange_value(self, long x, long y): + cdef _exchange_value_internal(self, long x, long y): r""" Return the (x, y) entry of the current representation. """ @@ -577,11 +574,11 @@ cdef class LinearMatroid(BasisExchangeMatroid): sage: from sage.matroids.advanced import lift_cross_ratios, lift_map, LinearMatroid sage: R = GF(7) sage: A = Matrix(R, [[1, 0, 6, 1, 2],[6, 1, 0, 0, 1],[0, 6, 3, 6, 0]]) - sage: M = LinearMatroid(reduced_matrix = A) - sage: M.representation(lift_map=lift_map('sru')) + sage: M = LinearMatroid(reduced_matrix=A) + sage: M.representation(lift_map=lift_map('sru')) # needs sage.rings.finite_rings [ 1 0 0 1 0 1 1 1] [ 0 1 0 -z + 1 1 0 0 1] - [ 0 0 1 0 -z z 1 0] + [ 0 0 1 0 1 -1 z - 1 0] """ cdef LeanMatrix A if order is None: @@ -608,7 +605,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): self._representation = self._basic_representation(B) A = self._representation else: - B = self.__subset(B) + B = self._subset_internal(B) A = self._basic_representation(B) A = A.matrix_from_rows_and_columns(range(A.nrows()), order_idx) if lift_map is None: @@ -625,7 +622,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): if B is None: B = frozenset(self.basis()) else: - B = self.__subset(B) + B = self._subset_internal(B) A = self._reduced_representation(B) R, C = self._current_rows_cols() Ri = [] @@ -829,12 +826,6 @@ cdef class LinearMatroid(BasisExchangeMatroid): True """ # TODO: ensure this is safe for noncommutative rings - global GF2, GF2_zero, GF2_one, GF2_not_defined - if GF2_not_defined: - GF2 = GF(2) - GF2_zero = GF2(0) - GF2_one = GF2(1) - GF2_not_defined = False B = self.basis() N = self.groundset() - B Bo = frozenset([morphism[e] for e in B]) @@ -848,8 +839,18 @@ cdef class LinearMatroid(BasisExchangeMatroid): if other._cocircuit(No | set([morphism[e]])) != frozenset([morphism[f] for f in C[e]]): return False - if self.base_ring() == GF2: - return True + global GF2, GF2_zero, GF2_one, GF2_not_defined + try: + if GF2_not_defined: + GF2 = GF(2) + GF2_zero = GF2(0) + GF2_one = GF2(1) + GF2_not_defined = False + except ImportError: + pass + else: + if self.base_ring() == GF2: + return True self._set_current_basis(B) other._set_current_basis(Bo) @@ -1090,7 +1091,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): object has no attribute '_invariant' sage: M1._fast_isom_test(M3) is None True - sage: Matroid(graphs.WheelGraph(6), regular = True)._fast_isom_test( + sage: Matroid(graphs.WheelGraph(6), regular=True)._fast_isom_test( # needs sage.graphs ....: matroids.Wheel(5)) True """ @@ -1125,8 +1126,8 @@ cdef class LinearMatroid(BasisExchangeMatroid): EXAMPLES:: sage: M1 = matroids.Wheel(3) - sage: M2 = Matroid(graphs.CompleteGraph(4), regular = True) - sage: M1.is_field_isomorphic(M2) + sage: M2 = Matroid(graphs.CompleteGraph(4), regular=True) # needs sage.graphs + sage: M1.is_field_isomorphic(M2) # needs sage.graphs True sage: M3 = Matroid(bases=M1.bases()) sage: M1.is_field_isomorphic(M3) @@ -1178,7 +1179,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): return False if len(PS) == len(self): morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PS[i])] = min(PO[i]) return self._is_field_isomorphism(other, morphism) @@ -1190,7 +1191,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): return False if len(PS) == len(self): morphism = {} - for i in xrange(len(self)): + for i in range(len(self)): morphism[min(PS[i])] = min(PO[i]) return self._is_field_isomorphism(other, morphism) @@ -1492,7 +1493,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): sage: M._exchange_value(1, 3) 4 """ - return self.__exchange_value(self._idx[e], self._idx[f]) + return self._exchange_value_internal(self._idx[e], self._idx[f]) cpdef fundamental_cycle(self, B, e): """ @@ -1705,8 +1706,8 @@ cdef class LinearMatroid(BasisExchangeMatroid): ....: [0, 0, 1, 3, 2, 5]])) sage: sorted(M.cross_ratios()) [2, 3, 4, 5, 6] - sage: M = Matroid(graphs.CompleteGraph(5), regular = True) - sage: M.cross_ratios() + sage: M = Matroid(graphs.CompleteGraph(5), regular=True) # needs sage.graphs + sage: M.cross_ratios() # needs sage.graphs set() """ if hyperlines is None: @@ -2089,7 +2090,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): [0 1 1 0 0 1 1] [0 0 0 1 1 1 1] """ - cdef long i, j + cdef long i cdef LeanMatrix M ext = [] if self._representation is None: @@ -2097,11 +2098,9 @@ cdef class LinearMatroid(BasisExchangeMatroid): else: M = type(self._A)(self._representation.nrows(), self.size() + 1, self._representation) E = self._E + (element,) - D = {} - for i from 0 <= i < self.size(): - D[E[i]] = i + D = {E[i]: i for i in range(self.size())} for chain in chains: - for i from 0 <= i < M.nrows(): + for i in range(M.nrows()): a = self._zero for e in chain: a += M.get_unsafe(i, D[e]) * chain[e] @@ -2139,7 +2138,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): [0 0 0 1 1 1 0] [1 0 0 0 0 1 1] """ - cdef long i, j + cdef long i cdef LeanMatrix M coext = [] if self._representation is None: @@ -2148,11 +2147,9 @@ cdef class LinearMatroid(BasisExchangeMatroid): M = type(self._A)(self._representation.nrows() + 1, self.size() + 1, self._representation) M.set_unsafe(M.nrows() - 1, M.ncols() - 1, self._one) E = self._E + (element,) - D = {} - for i from 0 <= i < self.size(): - D[E[i]] = i + D = {E[i]: i for i in range(self.size())} for cochain in cochains: - for i from 0 <= i < M.ncols() - 1: + for i in range(M.ncols() - 1): M.set_unsafe(M.nrows() - 1, i, 0) for e in cochain: M.set_unsafe(M.nrows() - 1, D[e], -cochain[e]) @@ -2494,16 +2491,15 @@ cdef class LinearMatroid(BasisExchangeMatroid): EXAMPLES:: sage: M = Matroid(ring=GF(2), - ....: reduced_matrix=[[-1, 0, 1], [1, -1, 0], [0, 1, -1]]) + ....: reduced_matrix=[[-1, 0, 1], [1, -1, 0], [0, 1, -1]]) sage: len(M.linear_extensions()) 8 - sage: S = M.linear_extensions(simple=True) - sage: S + sage: S = M.linear_extensions(simple=True); S [Binary matroid of rank 3 on 7 elements, type (3, 0)] sage: S[0].is_field_isomorphic(matroids.named_matroids.Fano()) True sage: M = Matroid(ring=QQ, - ....: reduced_matrix=[[1, 0, 1], [1, 1, 0], [0, 1, 1]]) + ....: reduced_matrix=[[1, 0, 1], [1, 1, 0], [0, 1, 1]]) sage: S = M.linear_extensions(simple=True, ....: fundamentals=[1, -1, 1/2, 2]) sage: len(S) @@ -2512,7 +2508,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): ....: for N in S) True sage: len(M.linear_extensions(simple=True, - ....: fundamentals=[1, -1, 1/2, 2], F=[0, 1])) + ....: fundamentals=[1, -1, 1/2, 2], F=[0, 1])) 1 """ if element is None: @@ -2666,6 +2662,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): EXAMPLES:: + sage: # needs sage.graphs sage: matroids.Uniform(2, 3)._is_3connected_shifting() True sage: M = Matroid(ring=QQ, matrix=[[1, 0, 0, 1, 1, 0], @@ -2681,10 +2678,10 @@ cdef class LinearMatroid(BasisExchangeMatroid): sage: matroids.named_matroids.BetsyRoss()._is_3connected_shifting() True sage: M = matroids.named_matroids.R6() - sage: M._is_3connected_shifting() + sage: M._is_3connected_shifting() # needs sage.rings.finite_rings False - sage: B, X = M._is_3connected_shifting(True) - sage: M.connectivity(X)<3 + sage: B, X = M._is_3connected_shifting(True) # needs sage.rings.finite_rings + sage: M.connectivity(X) < 3 # needs sage.rings.finite_rings True """ if not self.is_connected(): @@ -2745,17 +2742,17 @@ cdef class LinearMatroid(BasisExchangeMatroid): EXAMPLES:: sage: M = matroids.Uniform(2, 6) - sage: B, X = M._is_4connected_shifting(True) - sage: (B, M.connectivity(X)<=3) + sage: B, X = M._is_4connected_shifting(True) # needs sage.graphs + sage: (B, M.connectivity(X)<=3) # needs sage.graphs (False, True) - sage: matroids.Uniform(4, 8)._is_4connected_shifting() + sage: matroids.Uniform(4, 8)._is_4connected_shifting() # needs sage.graphs True sage: M = Matroid(field=GF(2), matrix=[[1,0,0,1,0,1,1,0,0,1,1,1], ....: [0,1,0,1,0,1,0,1,0,0,0,1], ....: [0,0,1,1,0,0,1,1,0,1,0,1], ....: [0,0,0,0,1,1,1,1,0,0,1,1], ....: [0,0,0,0,0,0,0,0,1,1,1,1]]) - sage: M._is_4connected_shifting() + sage: M._is_4connected_shifting() # needs sage.graphs True """ if self.rank()>self.size()-self.rank(): @@ -2785,9 +2782,9 @@ cdef class LinearMatroid(BasisExchangeMatroid): B[x, y] = 0 # remove row x1 and y1 - Xp = list(xrange(n)) + Xp = list(range(n)) Xp.remove(x1) - Yp = list(xrange(m)) + Yp = list(range(m)) Yp.remove(y1) B = B.matrix_from_rows_and_columns(Xp,Yp) @@ -2847,8 +2844,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): EXAMPLES:: sage: M = matroids.Wheel(3) - sage: OS = M.orlik_terao_algebra() - sage: OS + sage: OS = M.orlik_terao_algebra(); OS Orlik-Terao algebra of Wheel(3): Regular matroid of rank 3 on 6 elements with 16 bases over Integer Ring @@ -2857,17 +2853,18 @@ cdef class LinearMatroid(BasisExchangeMatroid): sage: M.orlik_terao_algebra(QQ).base_ring() Rational Field - sage: G = SymmetricGroup(3); - sage: OTG = M.orlik_terao_algebra(QQ, invariant=G) + sage: G = SymmetricGroup(3); # needs sage.groups + sage: OTG = M.orlik_terao_algebra(QQ, invariant=G) # needs sage.groups + sage: # needs sage.groups sage: G = SymmetricGroup(4) - sage: action = lambda g,x: g(x+1)-1 + sage: action = lambda g, x: g(x + 1) - 1 sage: OTG1 = M.orlik_terao_algebra(QQ, invariant=(G,action)) sage: OTG2 = M.orlik_terao_algebra(QQ, invariant=(action,G)) sage: OTG1 is OTG2 True - """ + """ if R is None: R = self.base_ring() @@ -2882,7 +2879,6 @@ cdef class LinearMatroid(BasisExchangeMatroid): else: G, action = G_action, None # the None action is g.__call__ - from sage.algebras.orlik_terao import OrlikTeraoInvariantAlgebra return OrlikTeraoInvariantAlgebra(R, self, G, @@ -2913,7 +2909,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): else: rows, cols = self._current_rows_cols() N = LinearMatroid(groundset=rows + cols, reduced_matrix=self._A) - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N def __deepcopy__(self, memo): @@ -2934,7 +2930,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): else: rows, cols = self._current_rows_cols() N = LinearMatroid(groundset=deepcopy(rows + cols, memo), reduced_matrix=deepcopy(self._A, memo)) - N.rename(deepcopy(getattr(self, '__custom_name'), memo)) + N.rename(deepcopy(self.get_custom_name(), memo)) return N def __reduce__(self): @@ -2983,7 +2979,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): rows, cols = self._current_rows_cols() gs = rows + cols reduced = True - data = (A, gs, reduced, getattr(self, '__custom_name')) + data = (A, gs, reduced, self.get_custom_name()) return sage.matroids.unpickling.unpickle_linear_matroid, (version, data) # Binary matroid @@ -3071,8 +3067,8 @@ cdef class BinaryMatroid(LinearMatroid): EXAMPLES:: sage: from sage.matroids.advanced import * - sage: BinaryMatroid(matrix=Matrix(GF(5), [[1, 0, 1, 1, 1], - ....: [0, 1, 1, 2, 3]])) # indirect doctest + sage: BinaryMatroid(matrix=Matrix(GF(5), [[1, 0, 1, 1, 1], # indirect doctest + ....: [0, 1, 1, 2, 3]])) Binary matroid of rank 2 on 5 elements, type (1, 7) """ cdef BinaryMatrix A @@ -3091,17 +3087,17 @@ cdef class BinaryMatroid(LinearMatroid): if keep_initial_representation: self._representation = A.copy() # Deprecated Sage matrix operation if basis is None: - P = gauss_jordan_reduce(A, xrange(A.ncols())) + P = gauss_jordan_reduce(A, range(A.ncols())) A.resize(len(P)) # Not a Sage matrix operation self._A = A else: A = BinaryMatrix(reduced_matrix.nrows(), reduced_matrix.ncols(), M=reduced_matrix) - P = list(xrange(A.nrows())) + P = list(range(A.nrows())) self._A = A.prepend_identity() # Not a Sage matrix operation # Setup groundset, BasisExchangeMatroid data if groundset is None: - groundset = list(xrange(self._A.ncols())) + groundset = list(range(self._A.ncols())) else: if len(groundset) != self._A.ncols(): raise ValueError("size of groundset does not match size of matrix") @@ -3113,17 +3109,17 @@ cdef class BinaryMatroid(LinearMatroid): # Setup index of displayed basis self._prow = <long* > sig_malloc((self._A.ncols()) * sizeof(long)) - for c in xrange(self._A.ncols()): + for c in range(self._A.ncols()): self._prow[c] = -1 if matrix is not None: if basis is None: - for r in xrange(len(P)): + for r in range(len(P)): self._prow[P[r]] = r else: - for r in xrange(self._A.nrows()): + for r in range(self._A.nrows()): self._prow[self._idx[basis[r]]] = r else: - for r from 0 <= r < self._A.nrows(): + for r in range(self._A.nrows()): self._prow[r] = r self._zero = GF2_zero @@ -3156,20 +3152,20 @@ cdef class BinaryMatroid(LinearMatroid): """ return 2 - cdef bint __is_exchange_pair(self, long x, long y) except -1: + cdef bint _is_exchange_pair(self, long x, long y) except -1: r""" Check if ``self.basis() - x + y`` is again a basis. Internal method. """ return (<BinaryMatrix>self._A).is_nonzero(self._prow[x], y) - cdef int __exchange(self, long x, long y) except -1: + cdef int _exchange(self, long x, long y) except -1: r""" Replace ``self.basis() with ``self.basis() - x + y``. Internal method, does no checks. """ cdef long p = self._prow[x] self._A.pivot(p, y) # Not a Sage matrix operation self._prow[y] = p - BasisExchangeMatroid.__exchange(self, x, y) + BasisExchangeMatroid._exchange(self, x, y) cdef __fundamental_cocircuit(self, bitset_t C, long x): r""" @@ -3177,18 +3173,18 @@ cdef class BinaryMatroid(LinearMatroid): """ bitset_copy(C, (<BinaryMatrix>self._A)._M[self._prow[x]]) - cdef __coclosure(self, bitset_t R, bitset_t F): + cdef _coclosure_internal(self, bitset_t R, bitset_t F): """ Bitpacked version of ``coclosure``. - This function overrides the internal function BasisExchangeMatroid.__coclosure() of the parent class. + This function overrides the internal function BasisExchangeMatroid._coclosure_internal() of the parent class. The implementation should be more efficient for BinaryMatroid, due to the fact that in this class, __fundamental_cocircuit is much faster than __fundamental_circuit. """ bitset_complement(R, F) bitset_difference(self._inside, self._current_basis, R) bitset_difference(self._outside, R, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) bitset_copy(R, F) bitset_difference(self._inside, self._current_basis, F) @@ -3200,7 +3196,7 @@ cdef class BinaryMatroid(LinearMatroid): bitset_add(R, y) y = bitset_next(self._inside, y + 1) - cdef __exchange_value(self, long x, long y): + cdef _exchange_value_internal(self, long x, long y): r""" Return the (x, y) entry of the current representation. """ @@ -3344,7 +3340,7 @@ cdef class BinaryMatroid(LinearMatroid): """ if B is not None: self._move_current_basis(B, set()) - rows, cols = self._current_rows_cols() + _, cols = self._current_rows_cols() return self._A.matrix_from_rows_and_columns(range(self.full_rank()), [self._idx[e] for e in cols]) # isomorphism @@ -3452,12 +3448,12 @@ cdef class BinaryMatroid(LinearMatroid): i = 0 U = set() while i + d < r: - for j in xrange(i, r - d): + for j in range(i, r - d): if B.row_len(j) % 2 == 1: # Not a Sage matrix operation B.swap_rows_c(i, j) break if B.row_len(i) % 2 == 1: # Not a Sage matrix operation - for j in xrange(i + 1, r - d): + for j in range(i + 1, r - d): if B.row_inner_product(i, j): # Not a Sage matrix operation B.add_multiple_of_row_c(j, i, 1, 0) if B.row_len(i) % 4 == 1: # Not a Sage matrix operation @@ -3467,13 +3463,13 @@ cdef class BinaryMatroid(LinearMatroid): U.add(i) i += 1 else: - for j in xrange(i + 1, r - d): + for j in range(i + 1, r - d): if B.row_inner_product(i, j): # Not a Sage matrix operation B.swap_rows_c(i + 1, j) break if i + 1 < r - d: if B.row_inner_product(i, i + 1): # Not a Sage matrix operation - for j in xrange(i + 2, r): + for j in range(i + 2, r): if B.row_inner_product(i, j): # Not a Sage matrix operation B.add_multiple_of_row_c(j, i + 1, 1, 0) if B.row_inner_product(i + 1, j): # Not a Sage matrix operation @@ -3488,7 +3484,7 @@ cdef class BinaryMatroid(LinearMatroid): d += 1 doubly_even = True - for i in xrange(r - d, r): + for i in range(r - d, r): if B.row_len(i) % 4 == 2: # Not a Sage matrix operation doubly_even = False break @@ -3505,8 +3501,8 @@ cdef class BinaryMatroid(LinearMatroid): self._b_projection = BT._matrix_times_matrix_((B._matrix_times_matrix_(BT))._matrix_times_matrix_(B)) P = [F0, Fp] p = [] - for a in xrange(2): - for b in xrange(a + 1): + for a in range(2): + for b in range(a + 1): x = 0 for i in P[a]: for j in P[b]: @@ -3634,7 +3630,9 @@ cdef class BinaryMatroid(LinearMatroid): ['h'] sage: M.bicycle_dimension() 2 - sage: for i in [-1, 0, 1]: print(sorted([e for e in M.groundset() if (M\e).bicycle_dimension() == 2 + i])) + sage: for i in [-1, 0, 1]: + ....: print(sorted(e for e in M.groundset() + ....: if (M\e).bicycle_dimension() == 2 + i)) ['a', 'b', 'c', 'e', 'f', 'g'] ['d'] ['h'] @@ -3705,11 +3703,11 @@ cdef class BinaryMatroid(LinearMatroid): sage: M = matroids.named_matroids.R12() sage: N = BinaryMatroid(reduced_matrix=M.representation(reduced=True, ....: labels=False), groundset='abcdefghijkl') - sage: Npp = N._projection_partition(); Npp # random + sage: Npp = N._projection_partition(); Npp # random 2 x 12 BinaryMatrix [110011001100] [001100110011] - sage: sorted(Npp._matrix_().rows()) + sage: sorted(Npp._matrix_().rows()) # needs sage.rings.finite_rings [(1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0), (0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1)] """ if self._eq_part is None: @@ -3815,12 +3813,12 @@ cdef class BinaryMatroid(LinearMatroid): ....: reduced=True, labels=False)) sage: M.is_graphic() False - sage: K5 = Matroid(graphs.CompleteGraph(5), regular = True) - sage: M = Matroid(ring=GF(2), reduced_matrix=K5.representation( + sage: K5 = Matroid(graphs.CompleteGraph(5), regular=True) # needs sage.graphs + sage: M = Matroid(ring=GF(2), reduced_matrix=K5.representation( # needs sage.graphs sage.rings.finite_rings ....: reduced=True, labels=False)) - sage: M.is_graphic() + sage: M.is_graphic() # needs sage.graphs sage.rings.finite_rings True - sage: M.dual().is_graphic() + sage: M.dual().is_graphic() # needs sage.graphs False ALGORITHM: @@ -3837,16 +3835,16 @@ cdef class BinaryMatroid(LinearMatroid): c = 1 col = {} - for e in xrange(len(B)): + for e in range(len(B)): for f in range(len(B)): if e is not f: col[e, f] = c c += 1 M = [] r = 0 - for e in xrange(len(B)): - for f in xrange(e): - for g in xrange(f): + for e in range(len(B)): + for f in range(e): + for g in range(f): if not C[e].issuperset(C[f] & C[g]): M.append([col[e,f], col[e,g]]) r += 1 @@ -3966,7 +3964,7 @@ cdef class BinaryMatroid(LinearMatroid): for e in self.basis(): basis[self._prow[self._idx[e]]] = e N = BinaryMatroid(groundset=self._E, matrix=self._A, basis=basis) - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N def __deepcopy__(self, memo): @@ -3991,7 +3989,7 @@ cdef class BinaryMatroid(LinearMatroid): for e in self.basis(): basis[self._prow[self._idx[e]]] = e N = BinaryMatroid(groundset=deepcopy(self._E, memo), matrix=deepcopy(self._A, memo), basis=deepcopy(basis, memo)) - N.rename(deepcopy(getattr(self, '__custom_name'), memo)) + N.rename(deepcopy(self.get_custom_name(), memo)) return N def __reduce__(self): @@ -4049,7 +4047,7 @@ cdef class BinaryMatroid(LinearMatroid): A = self._A # current basis ordered so matrix cols form identity matrix: basis = self._current_rows_cols()[0] - data = (A, gs, basis, getattr(self, '__custom_name')) + data = (A, gs, basis, self.get_custom_name()) return sage.matroids.unpickling.unpickle_binary_matroid, (version, data) cdef class TernaryMatroid(LinearMatroid): @@ -4107,8 +4105,7 @@ cdef class TernaryMatroid(LinearMatroid): EXAMPLES:: sage: A = Matrix(GF(3), 2, 4, [[1, 0, 1, 1], [0, 1, 1, 1]]) - sage: M = Matroid(A) - sage: M + sage: M = Matroid(A); M Ternary matroid of rank 2 on 4 elements, type 0- sage: sorted(M.groundset()) [0, 1, 2, 3] @@ -4119,8 +4116,8 @@ cdef class TernaryMatroid(LinearMatroid): sage: sorted(M.groundset()) ['a', 'b', 'c', 'd'] sage: B = Matrix(GF(2), 2, 2, [[1, 1], [1, 1]]) - sage: N = Matroid(ring=GF(3), reduced_matrix=B, groundset='abcd') - sage: M == N + sage: N = Matroid(ring=GF(3), reduced_matrix=B, groundset='abcd') # needs sage.rings.finite_rings + sage: M == N # needs sage.rings.finite_rings True """ def __init__(self, matrix=None, groundset=None, reduced_matrix=None, ring=None, keep_initial_representation=True, basis=None): @@ -4136,8 +4133,8 @@ cdef class TernaryMatroid(LinearMatroid): EXAMPLES:: sage: from sage.matroids.advanced import * - sage: TernaryMatroid(matrix=Matrix(GF(5), [[1, 0, 1, 1, 1], - ....: [0, 1, 1, 2, 3]])) # indirect doctest + sage: TernaryMatroid(matrix=Matrix(GF(5), [[1, 0, 1, 1, 1], # indirect doctest + ....: [0, 1, 1, 2, 3]])) Ternary matroid of rank 2 on 5 elements, type 1+ """ cdef TernaryMatrix A @@ -4157,17 +4154,17 @@ cdef class TernaryMatroid(LinearMatroid): if keep_initial_representation: self._representation = A.copy() # Deprecated Sage matrix operation if basis is None: - P = gauss_jordan_reduce(A, xrange(A.ncols())) + P = gauss_jordan_reduce(A, range(A.ncols())) A.resize(len(P)) # Not a Sage matrix operation self._A = A else: A = TernaryMatrix(reduced_matrix.nrows(), reduced_matrix.ncols(), M=reduced_matrix) - P = list(xrange(A.nrows())) + P = list(range(A.nrows())) self._A = A.prepend_identity() # Not a Sage matrix operation # Setup groundset, BasisExchangeMatroid data if groundset is None: - groundset = list(xrange(self._A.ncols())) + groundset = list(range(self._A.ncols())) else: if len(groundset) != self._A.ncols(): raise ValueError("size of groundset does not match size of matrix") @@ -4179,17 +4176,17 @@ cdef class TernaryMatroid(LinearMatroid): # Setup index of displayed basis self._prow = <long* > sig_malloc((self._A.ncols()) * sizeof(long)) - for c in xrange(self._A.ncols()): + for c in range(self._A.ncols()): self._prow[c] = -1 if matrix is not None: if basis is None: - for r in xrange(len(P)): + for r in range(len(P)): self._prow[P[r]] = r else: - for r in xrange(self._A.nrows()): + for r in range(self._A.nrows()): self._prow[self._idx[basis[r]]] = r else: - for r from 0 <= r < self._A.nrows(): + for r in range(self._A.nrows()): self._prow[r] = r self._zero = GF3_zero @@ -4223,20 +4220,20 @@ cdef class TernaryMatroid(LinearMatroid): """ return 3 - cdef bint __is_exchange_pair(self, long x, long y) except -1: + cdef bint _is_exchange_pair(self, long x, long y) except -1: r""" Check if ``self.basis() - x + y`` is again a basis. Internal method. """ return (<TernaryMatrix>self._A).is_nonzero(self._prow[x], y) - cdef int __exchange(self, long x, long y) except -1: + cdef int _exchange(self, long x, long y) except -1: r""" Replace ``self.basis() with ``self.basis() - x + y``. Internal method, does no checks. """ cdef long p = self._prow[x] self._A.pivot(p, y) # Not a Sage matrix operation self._prow[y] = p - BasisExchangeMatroid.__exchange(self, x, y) + BasisExchangeMatroid._exchange(self, x, y) cdef __fundamental_cocircuit(self, bitset_t C, long x): r""" @@ -4244,18 +4241,18 @@ cdef class TernaryMatroid(LinearMatroid): """ bitset_copy(C, (<TernaryMatrix>self._A)._M0[self._prow[x]]) - cdef __coclosure(self, bitset_t R, bitset_t F): + cdef _coclosure_internal(self, bitset_t R, bitset_t F): """ Bitpacked version of ``coclosure``. - This function overrides the internal function BasisExchangeMatroid.__coclosure() of the parent class. + This function overrides the internal function BasisExchangeMatroid._coclosure_internal() of the parent class. The implementation should be more efficient for TernaryMatroid, due to the fact that in this class, __fundamental_cocircuit is much faster than __fundamental_circuit. """ bitset_complement(R, F) bitset_difference(self._inside, self._current_basis, R) bitset_difference(self._outside, R, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) bitset_copy(R, F) bitset_difference(self._inside, self._current_basis, F) @@ -4267,7 +4264,7 @@ cdef class TernaryMatroid(LinearMatroid): bitset_add(R, y) y = bitset_next(self._inside, y + 1) - cdef __exchange_value(self, long x, long y): + cdef _exchange_value_internal(self, long x, long y): r""" Return the (x, y) entry of the current representation. """ @@ -4417,7 +4414,7 @@ cdef class TernaryMatroid(LinearMatroid): """ if B is not None: self._move_current_basis(B, set()) - rows, cols = self._current_rows_cols() + _, cols = self._current_rows_cols() return self._A.matrix_from_rows_and_columns(range(self.full_rank()), [self._idx[e] for e in cols]) # isomorphism @@ -4454,7 +4451,7 @@ cdef class TernaryMatroid(LinearMatroid): """ if certificate: return self._is_isomorphic(other), self._isomorphism(other) - if type(other) == TernaryMatroid: + if isinstance(other, TernaryMatroid): return self.is_field_isomorphic(other) else: return LinearMatroid._is_isomorphic(self, other) @@ -4485,7 +4482,7 @@ cdef class TernaryMatroid(LinearMatroid): c = self._one i = 0 while i < r - d: - for j in xrange(i, r - d): + for j in range(i, r - d): if T.row_inner_product(j, j) != 0: # Not a Sage matrix operation if j > i: T.swap_rows_c(i, j) @@ -4500,7 +4497,7 @@ cdef class TernaryMatroid(LinearMatroid): T.swap_rows_c(i, r - d) else: c = c * GF3(x) - for j in xrange(i + 1, r - d): + for j in range(i + 1, r - d): y = T.row_inner_product(i, j) # Not a Sage matrix operation if y == 0: continue @@ -4513,16 +4510,16 @@ cdef class TernaryMatroid(LinearMatroid): TT = T.transpose() self._t_projection = TT._matrix_times_matrix_((T._matrix_times_matrix_(TT))._matrix_times_matrix_(T)) F = frozenset() - for i in xrange(r - d, r): + for i in range(r - d, r): F = F | frozenset(T.nonzero_positions_in_row(i)) - Fa = frozenset([j for j in xrange(len(self)) if self._t_projection.get(j, j) == 0]) - F # Not a Sage matrix operation - Fb = frozenset([j for j in xrange(len(self)) if self._t_projection.get(j, j) == 1]) - F # Not a Sage matrix operation - Fc = frozenset([j for j in xrange(len(self)) if self._t_projection.get(j, j) == -1]) - F # Not a Sage matrix operation + Fa = frozenset([j for j in range(len(self)) if self._t_projection.get(j, j) == 0]) - F # Not a Sage matrix operation + Fb = frozenset([j for j in range(len(self)) if self._t_projection.get(j, j) == 1]) - F # Not a Sage matrix operation + Fc = frozenset([j for j in range(len(self)) if self._t_projection.get(j, j) == -1]) - F # Not a Sage matrix operation P = [Fa, Fb, Fc] p = [] - for a in xrange(3): - for b in xrange(a + 1): + for a in range(3): + for b in range(a + 1): x = 0 for i in P[a]: for j in P[b]: @@ -4861,7 +4858,7 @@ cdef class TernaryMatroid(LinearMatroid): for e in self.basis(): basis[self._prow[self._idx[e]]] = e N = TernaryMatroid(groundset=self._E, matrix=self._A, basis=basis) - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N def __deepcopy__(self, memo): @@ -4886,7 +4883,7 @@ cdef class TernaryMatroid(LinearMatroid): for e in self.basis(): basis[self._prow[self._idx[e]]] = e N = TernaryMatroid(groundset=deepcopy(self._E, memo), matrix=deepcopy(self._A, memo), basis=deepcopy(basis, memo)) - N.rename(deepcopy(getattr(self, '__custom_name'), memo)) + N.rename(deepcopy(self.get_custom_name(), memo)) return N def __reduce__(self): @@ -4928,11 +4925,11 @@ cdef class TernaryMatroid(LinearMatroid): sage: from sage.matroids.advanced import * sage: X_bin = matroids.named_matroids.Fano().representation() - sage: X = Matrix(GF(3), X_bin) - sage: M = TernaryMatroid(matrix=X).dual() + sage: X = Matrix(GF(3), X_bin) # needs sage.rings.finite_rings + sage: M = TernaryMatroid(matrix=X).dual() # needs sage.rings.finite_rings sage: B = list(M.bases()) sage: N = loads(dumps(M)) - sage: N.closure(frozenset({3})) + sage: N.closure(frozenset({3})) # needs sage.rings.finite_rings frozenset({3}) sage: N.is_isomorphic(M) True @@ -4948,7 +4945,7 @@ cdef class TernaryMatroid(LinearMatroid): A = self._A # current basis ordered so matrix cols form identity matrix: basis = self._current_rows_cols()[0] - data = (A, gs, basis, getattr(self, '__custom_name')) + data = (A, gs, basis, self.get_custom_name()) return sage.matroids.unpickling.unpickle_ternary_matroid, (version, data) # Quaternary Matroids @@ -5007,6 +5004,7 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: GF4 = GF(4, 'x') sage: x = GF4.gens()[0] sage: A = Matrix(GF4, 2, 4, [[1, 0, 1, 1], [0, 1, 1, x]]) @@ -5041,8 +5039,9 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: sage: from sage.matroids.advanced import * - sage: QuaternaryMatroid(matrix=Matrix(GF(4, 'x'), - ....: [[1, 0, 1, 1, 1], [0, 1, 1, 1, 1]])) # indirect doctest + sage: QuaternaryMatroid(matrix=Matrix(GF(4, 'x'), # indirect doctest # needs sage.rings.finite_rings + ....: [[1, 0, 1, 1, 1], + ....: [0, 1, 1, 1, 1]])) Quaternary matroid of rank 2 on 5 elements """ cdef QuaternaryMatrix A @@ -5055,17 +5054,17 @@ cdef class QuaternaryMatroid(LinearMatroid): if keep_initial_representation: self._representation = A.copy() # Deprecated Sage matrix operation if basis is None: - P = gauss_jordan_reduce(A, xrange(A.ncols())) + P = gauss_jordan_reduce(A, range(A.ncols())) A.resize(len(P)) # Not a Sage matrix operation self._A = A else: A = QuaternaryMatrix(reduced_matrix.nrows(), reduced_matrix.ncols(), M=reduced_matrix, ring=ring) - P = list(xrange(A.nrows())) + P = list(range(A.nrows())) self._A = A.prepend_identity() # Not a Sage matrix operation # Setup groundset, BasisExchangeMatroid data if groundset is None: - groundset = list(xrange(self._A.ncols())) + groundset = list(range(self._A.ncols())) else: if len(groundset) != self._A.ncols(): raise ValueError("size of groundset does not match size of matrix") @@ -5077,17 +5076,17 @@ cdef class QuaternaryMatroid(LinearMatroid): # Setup index of displayed basis self._prow = <long* > sig_malloc((self._A.ncols()) * sizeof(long)) - for c in xrange(self._A.ncols()): + for c in range(self._A.ncols()): self._prow[c] = -1 if matrix is not None: if basis is None: - for r in xrange(len(P)): + for r in range(len(P)): self._prow[P[r]] = r else: - for r in xrange(self._A.nrows()): + for r in range(self._A.nrows()): self._prow[self._idx[basis[r]]] = r else: - for r from 0 <= r < self._A.nrows(): + for r in range(self._A.nrows()): self._prow[r] = r self._zero = (<QuaternaryMatrix>self._A)._zero @@ -5102,9 +5101,9 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = Matroid(ring=GF(4, 'y'), reduced_matrix=[[1, 0, 1], + sage: M = Matroid(ring=GF(4, 'y'), reduced_matrix=[[1, 0, 1], # needs sage.rings.finite_rings ....: [0, 1, 1]]) - sage: M.base_ring() + sage: M.base_ring() # needs sage.rings.finite_rings Finite Field in y of size 2^2 """ return (<QuaternaryMatrix>self._A).base_ring() @@ -5116,27 +5115,27 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = Matroid(ring=GF(4, 'y'), reduced_matrix=[[1, 0, 1], + sage: M = Matroid(ring=GF(4, 'y'), reduced_matrix=[[1, 0, 1], # needs sage.rings.finite_rings ....: [0, 1, 1]]) - sage: M.characteristic() + sage: M.characteristic() # needs sage.rings.finite_rings 2 """ return 2 - cdef bint __is_exchange_pair(self, long x, long y) except -1: + cdef bint _is_exchange_pair(self, long x, long y) except -1: r""" Check if ``self.basis() - x + y`` is again a basis. Internal method. """ return (<QuaternaryMatrix>self._A).is_nonzero(self._prow[x], y) - cdef int __exchange(self, long x, long y) except -1: + cdef int _exchange(self, long x, long y) except -1: r""" Replace ``self.basis() with ``self.basis() - x + y``. Internal method, does no checks. """ cdef long p = self._prow[x] self._A.pivot(p, y) # Not a Sage matrix operation self._prow[y] = p - BasisExchangeMatroid.__exchange(self, x, y) + BasisExchangeMatroid._exchange(self, x, y) cdef __fundamental_cocircuit(self, bitset_t C, long x): r""" @@ -5144,18 +5143,18 @@ cdef class QuaternaryMatroid(LinearMatroid): """ bitset_union(C, (<QuaternaryMatrix>self._A)._M0[self._prow[x]], (<QuaternaryMatrix>self._A)._M1[self._prow[x]]) - cdef __coclosure(self, bitset_t R, bitset_t F): + cdef _coclosure_internal(self, bitset_t R, bitset_t F): """ Bitpacked version of ``coclosure``. - This function overrides the internal function BasisExchangeMatroid.__coclosure() of the parent class. + This function overrides the internal function BasisExchangeMatroid._coclosure_internal() of the parent class. The implementation should be more efficient for QuaternaryMatroid, due to the fact that in this class, __fundamental_cocircuit is much faster than __fundamental_circuit. """ bitset_complement(R, F) bitset_difference(self._inside, self._current_basis, R) bitset_difference(self._outside, R, self._current_basis) - self.__move(self._inside, self._outside) + self._move(self._inside, self._outside) bitset_copy(R, F) bitset_difference(self._inside, self._current_basis, F) @@ -5167,7 +5166,7 @@ cdef class QuaternaryMatroid(LinearMatroid): bitset_add(R, y) y = bitset_next(self._inside, y + 1) - cdef __exchange_value(self, long x, long y): + cdef _exchange_value_internal(self, long x, long y): r""" Return the (x, y) entry of the current representation. """ @@ -5179,9 +5178,9 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = Matroid(ring=GF(4, 'x'), matrix=[[1, 0, 1], [0, 1, 1]]) - sage: M.rename() - sage: repr(M) # indirect doctest + sage: M = Matroid(ring=GF(4, 'x'), matrix=[[1, 0, 1], [0, 1, 1]]) # needs sage.rings.finite_rings + sage: M.rename() # needs sage.rings.finite_rings + sage: repr(M) # indirect doctest # needs sage.rings.finite_rings 'Quaternary matroid of rank 2 on 3 elements' """ S = "Quaternary matroid of rank " + str(self.rank()) + " on " + str(self.size()) + " elements" @@ -5205,6 +5204,7 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: M = matroids.named_matroids.Q10() sage: A = M._reduced_representation('efghi') sage: R, C = M._current_rows_cols() @@ -5253,15 +5253,15 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = matroids.named_matroids.Q10() - sage: M._basic_representation() + sage: M = matroids.named_matroids.Q10() # needs sage.rings.finite_rings + sage: M._basic_representation() # needs sage.rings.finite_rings 5 x 10 QuaternaryMatrix [100001x00y] [01000y1x00] [001000y1x0] [0001000y1x] [00001x00y1] - sage: matrix(M._basic_representation('efghi')) + sage: matrix(M._basic_representation('efghi')) # needs sage.rings.finite_rings [ 1 0 x + 1 1 0 1 0 0 0 1] [ x x + 1 0 0 0 0 0 1 0 1] [ 0 0 x x + 1 0 0 1 0 0 1] @@ -5296,15 +5296,15 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = matroids.named_matroids.Q10() - sage: M._reduced_representation() + sage: M = matroids.named_matroids.Q10() # needs sage.rings.finite_rings + sage: M._reduced_representation() # needs sage.rings.finite_rings 5 x 5 QuaternaryMatrix [1x00y] [y1x00] [0y1x0] [00y1x] [x00y1] - sage: matrix(M._reduced_representation('efghi')) + sage: matrix(M._reduced_representation('efghi')) # needs sage.rings.finite_rings [ 1 0 x + 1 1 1] [ x x + 1 0 0 1] [ 0 0 x x + 1 1] @@ -5313,7 +5313,7 @@ cdef class QuaternaryMatroid(LinearMatroid): """ if B is not None: self._move_current_basis(B, set()) - rows, cols = self._current_rows_cols() + _, cols = self._current_rows_cols() return self._A.matrix_from_rows_and_columns(range(self.full_rank()), [self._idx[e] for e in cols]) cpdef _make_invariant(self): @@ -5324,8 +5324,8 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = matroids.named_matroids.Q10() - sage: M._invariant() # indirect doctest + sage: M = matroids.named_matroids.Q10() # needs sage.rings.finite_rings + sage: M._invariant() # indirect doctest # needs sage.rings.finite_rings (0, 0, 5, 5, 20, 10, 25) """ cdef QuaternaryMatrix Q, QT @@ -5338,7 +5338,7 @@ cdef class QuaternaryMatroid(LinearMatroid): d = 0 i = 0 while i < r - d: - for j in xrange(i, r - d): + for j in range(i, r - d): if Q.row_inner_product(j, j) != 0: # Not a Sage matrix operation if j > i: Q.swap_rows_c(i, j) @@ -5353,7 +5353,7 @@ cdef class QuaternaryMatroid(LinearMatroid): d += 1 Q.swap_rows_c(i, r - d) else: - for j in xrange(i + 1, r - d): + for j in range(i + 1, r - d): y = Q.row_inner_product(j, i) # Not a Sage matrix operation if y == 0: continue @@ -5364,15 +5364,15 @@ cdef class QuaternaryMatroid(LinearMatroid): QT.conjugate() # Not a Sage matrix operation self._q_projection = QT._matrix_times_matrix_((Q._matrix_times_matrix_(QT))._matrix_times_matrix_(Q)) F = frozenset() - for i in xrange(r - d, r): + for i in range(r - d, r): F = F | frozenset(Q.nonzero_positions_in_row(i)) - Fa = frozenset([j for j in xrange(len(self)) if self._q_projection.get(j, j) == 0]) - F # Not a Sage matrix operation - Fb = frozenset([j for j in xrange(len(self)) if self._q_projection.get(j, j) == 1]) - F # Not a Sage matrix operation + Fa = frozenset([j for j in range(len(self)) if self._q_projection.get(j, j) == 0]) - F # Not a Sage matrix operation + Fb = frozenset([j for j in range(len(self)) if self._q_projection.get(j, j) == 1]) - F # Not a Sage matrix operation P = [Fa, Fb] p = [] - for a in xrange(2): - for b in xrange(a + 1): + for a in range(2): + for b in range(a + 1): x = 0 for i in P[a]: for j in P[b]: @@ -5403,8 +5403,8 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = matroids.named_matroids.Q10() - sage: M._invariant() + sage: M = matroids.named_matroids.Q10() # needs sage.rings.finite_rings + sage: M._invariant() # needs sage.rings.finite_rings (0, 0, 5, 5, 20, 10, 25) """ @@ -5431,8 +5431,8 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = matroids.named_matroids.Q10() - sage: M.bicycle_dimension() + sage: M = matroids.named_matroids.Q10() # needs sage.rings.finite_rings + sage: M.bicycle_dimension() # needs sage.rings.finite_rings 0 """ if self._q_invariant is None: @@ -5458,6 +5458,7 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: M = matroids.named_matroids.Q10()\'a' sage: for F in M._principal_tripartition(): print(sorted(F)) ['b', 'c', 'd', 'e', 'h', 'i'] @@ -5465,7 +5466,9 @@ cdef class QuaternaryMatroid(LinearMatroid): [] sage: M.bicycle_dimension() 1 - sage: for i in [-1, 0, 1]: print(sorted([e for e in M.groundset() if (M\e).bicycle_dimension() == 1 + i])) + sage: for i in [-1, 0, 1]: + ....: print(sorted(e for e in M.groundset() + ....: if (M\e).bicycle_dimension() == 1 + i)) ['b', 'c', 'd', 'e', 'h', 'i'] ['f', 'g', 'j'] [] @@ -5494,9 +5497,9 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = matroids.named_matroids.Q10()\'a' - sage: N = matroids.named_matroids.Q10()\'b' - sage: M._fast_isom_test(N) is None + sage: M = matroids.named_matroids.Q10()\'a' # needs sage.rings.finite_rings + sage: N = matroids.named_matroids.Q10()\'b' # needs sage.rings.finite_rings + sage: M._fast_isom_test(N) is None # needs sage.rings.finite_rings True """ if self._invariant() != other._invariant(): @@ -5530,9 +5533,9 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = matroids.named_matroids.Q10() - sage: N = M._minor(contractions=set(['a']), deletions=set([])) - sage: N._minor(contractions=set([]), deletions=set(['b', 'c'])) + sage: M = matroids.named_matroids.Q10() # needs sage.rings.finite_rings + sage: N = M._minor(contractions=set(['a']), deletions=set([])) # needs sage.rings.finite_rings + sage: N._minor(contractions=set([]), deletions=set(['b', 'c'])) # needs sage.rings.finite_rings Quaternary matroid of rank 4 on 7 elements """ self._move_current_basis(contractions, deletions) @@ -5559,8 +5562,8 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = Matroid(Matrix(GF(4, 'x'), [[]])) - sage: M.is_valid() + sage: M = Matroid(Matrix(GF(4, 'x'), [[]])) # needs sage.rings.finite_rings + sage: M.is_valid() # needs sage.rings.finite_rings True """ return True @@ -5571,10 +5574,10 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = Matroid(Matrix(GF(4, 'x'), [[1, 0, 0, 1, 1], + sage: M = Matroid(Matrix(GF(4, 'x'), [[1, 0, 0, 1, 1], # needs sage.rings.finite_rings ....: [0, 1, 0, 1, 2], [0, 0, 1, 1, 3]])) - sage: N = copy(M) # indirect doctest - sage: M == N + sage: N = copy(M) # indirect doctest # needs sage.rings.finite_rings + sage: M == N # needs sage.rings.finite_rings True """ cdef QuaternaryMatroid N @@ -5586,7 +5589,7 @@ cdef class QuaternaryMatroid(LinearMatroid): for e in self.basis(): basis[self._prow[self._idx[e]]] = e N = QuaternaryMatroid(groundset=self._E, matrix=self._A, basis=basis) - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N def __deepcopy__(self, memo): @@ -5595,10 +5598,10 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: - sage: M = Matroid(Matrix(GF(4, 'x'), [[1, 0, 0, 1, 1], + sage: M = Matroid(Matrix(GF(4, 'x'), [[1, 0, 0, 1, 1], # needs sage.rings.finite_rings ....: [0, 1, 0, 1, 2], [0, 0, 1, 1, -1]])) - sage: N = deepcopy(M) # indirect doctest - sage: M == N + sage: N = deepcopy(M) # indirect doctest # needs sage.rings.finite_rings + sage: M == N # needs sage.rings.finite_rings True """ from copy import deepcopy @@ -5611,7 +5614,7 @@ cdef class QuaternaryMatroid(LinearMatroid): for e in self.basis(): basis[self._prow[self._idx[e]]] = e N = QuaternaryMatroid(groundset=deepcopy(self._E, memo), matrix=deepcopy(self._A, memo), basis=deepcopy(basis, memo)) - N.rename(deepcopy(getattr(self, '__custom_name'), memo)) + N.rename(deepcopy(self.get_custom_name(), memo)) return N def __reduce__(self): @@ -5634,6 +5637,7 @@ cdef class QuaternaryMatroid(LinearMatroid): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: M = Matroid(Matrix(GF(4, 'x'), [[1, 0, 0, 1], [0, 1, 0, 1], ....: [0, 0, 1, 1]])) sage: M == loads(dumps(M)) # indirect doctest @@ -5648,13 +5652,13 @@ cdef class QuaternaryMatroid(LinearMatroid): sage: from sage.matroids.advanced import QuaternaryMatroid sage: X_bin = matroids.named_matroids.Fano().representation() - sage: X = Matrix(GF(4), X_bin) - sage: M = QuaternaryMatroid(matrix=X).dual() - sage: B = list(M.bases()) - sage: N = loads(dumps(M)) - sage: N.closure(frozenset({3})) + sage: X = Matrix(GF(4), X_bin) # needs sage.rings.finite_rings + sage: M = QuaternaryMatroid(matrix=X).dual() # needs sage.rings.finite_rings + sage: B = list(M.bases()) # needs sage.rings.finite_rings + sage: N = loads(dumps(M)) # needs sage.rings.finite_rings + sage: N.closure(frozenset({3})) # needs sage.rings.finite_rings frozenset({3}) - sage: N.is_isomorphic(M) + sage: N.is_isomorphic(M) # needs sage.rings.finite_rings True """ import sage.matroids.unpickling @@ -5668,7 +5672,7 @@ cdef class QuaternaryMatroid(LinearMatroid): A = self._A # current basis ordered so matrix cols form identity matrix: basis = self._current_rows_cols()[0] - data = (A, gs, basis, getattr(self, '__custom_name')) + data = (A, gs, basis, self.get_custom_name()) return sage.matroids.unpickling.unpickle_quaternary_matroid, (version, data) # Regular Matroids @@ -5735,16 +5739,15 @@ cdef class RegularMatroid(LinearMatroid): EXAMPLES:: sage: A = Matrix(ZZ, 2, 4, [[1, 0, 1, 1], [0, 1, 1, 1]]) - sage: M = Matroid(A, regular=True) - sage: M + sage: M = Matroid(A, regular=True); M # needs sage.graphs Regular matroid of rank 2 on 4 elements with 5 bases - sage: sorted(M.groundset()) + sage: sorted(M.groundset()) # needs sage.graphs [0, 1, 2, 3] - sage: Matrix(M) + sage: Matrix(M) # needs sage.graphs [1 0 1 1] [0 1 1 1] - sage: M = Matroid(matrix=A, groundset='abcd', regular=True) - sage: sorted(M.groundset()) + sage: M = Matroid(matrix=A, groundset='abcd', regular=True) # needs sage.graphs + sage: sorted(M.groundset()) # needs sage.graphs ['a', 'b', 'c', 'd'] """ def __init__(self, matrix=None, groundset=None, reduced_matrix=None, ring=None, keep_initial_representation=True): @@ -5760,8 +5763,8 @@ cdef class RegularMatroid(LinearMatroid): EXAMPLES:: sage: from sage.matroids.advanced import * - sage: RegularMatroid(matrix=Matrix(ZZ, [[1, 0, 1, 1, 1], - ....: [0, 1, 1, 1, 1]])) # indirect doctest + sage: RegularMatroid(matrix=Matrix(ZZ, [[1, 0, 1, 1, 1], # indirect doctest # needs sage.graphs + ....: [0, 1, 1, 1, 1]])) Regular matroid of rank 2 on 5 elements with 7 bases """ LinearMatroid.__init__(self, matrix, groundset, reduced_matrix, ring=ZZ, keep_initial_representation=keep_initial_representation) @@ -5784,28 +5787,28 @@ cdef class RegularMatroid(LinearMatroid): A = (<PlusMinusOneMatrix>matrix).copy() # Deprecated Sage matrix operation if keep_initial_representation: self._representation = A.copy() # Deprecated Sage matrix operation - P = gauss_jordan_reduce(A, xrange(A.ncols())) - self._A = A.matrix_from_rows_and_columns(range(len(P)), [c for c in xrange(matrix.ncols()) if c not in P]) + P = gauss_jordan_reduce(A, range(A.ncols())) + self._A = A.matrix_from_rows_and_columns(range(len(P)), [c for c in range(matrix.ncols()) if c not in P]) else: reduced = True if not isinstance(reduced_matrix, PlusMinusOneMatrix): self._A = PlusMinusOneMatrix(reduced_matrix.nrows(), reduced_matrix.ncols(), M=reduced_matrix) else: self._A = (<PlusMinusOneMatrix>reduced_matrix).copy() # Deprecated Sage matrix operation - P = list(xrange(self._A.nrows())) + P = list(range(self._A.nrows())) self._prow = <long* > sig_malloc((self._A.nrows() + self._A.ncols()) * sizeof(long)) if matrix is not None: - for r in xrange(len(P)): + for r in range(len(P)): self._prow[P[r]] = r r = 0 - for c in xrange(A.ncols()): + for c in range(A.ncols()): if c not in P: self._prow[c] = r r += 1 else: - for r from 0 <= r < self._A.nrows(): + for r in range(self._A.nrows()): self._prow[r] = r - for r from 0 <= r < self._A.ncols(): + for r in range(self._A.ncols()): self._prow[self._A.nrows() + r] = r return P @@ -5835,13 +5838,13 @@ cdef class RegularMatroid(LinearMatroid): """ return 0 - cdef bint __is_exchange_pair(self, long x, long y) except -1: + cdef bint _is_exchange_pair(self, long x, long y) except -1: r""" Check if ``self.basis() - x + y`` is again a basis. Internal method. """ return (<PlusMinusOneMatrix>self._A).is_nonzero(self._prow[x], self._prow[y]) - cdef int __exchange(self, long x, long y) except -1: + cdef int _exchange(self, long x, long y) except -1: """ Put element indexed by ``x`` into basis, taking out element ``y``. Assumptions are that this is a valid basis exchange. @@ -5857,16 +5860,16 @@ cdef class RegularMatroid(LinearMatroid): pivi = piv # NOTE: 1 and -1 are their own inverses. (<PlusMinusOneMatrix>self._A).rescale_row_c(px, pivi, 0) (<PlusMinusOneMatrix>self._A).set(px, py, pivi + 1) # pivoting without column scaling. Add extra so column does not need adjusting # Not a Sage matrix operation - for r in xrange(self._A.nrows()): # if A and A' are the matrices before and after pivoting, then + for r in range(self._A.nrows()): # if A and A' are the matrices before and after pivoting, then a = (<PlusMinusOneMatrix>self._A).get(r, py) # ker[I A] equals ker[I A'] except for the labelling of the columns # Not a Sage matrix operation if a and r != px: (<PlusMinusOneMatrix>self._A).add_multiple_of_row_c(r, px, -a, 0) (<PlusMinusOneMatrix>self._A).set(px, py, pivi) # Not a Sage matrix operation self._prow[y] = px self._prow[x] = py - BasisExchangeMatroid.__exchange(self, x, y) + BasisExchangeMatroid._exchange(self, x, y) - cdef __exchange_value(self, long x, long y): + cdef _exchange_value_internal(self, long x, long y): r""" Return the (x, y) entry of the current representation. @@ -5899,8 +5902,8 @@ cdef class RegularMatroid(LinearMatroid): EXAMPLES:: - sage: M = Matroid(graphs.CompleteGraph(5), regular = True) - sage: M.bases_count() + sage: M = Matroid(graphs.CompleteGraph(5), regular=True) # needs sage.graphs + sage: M.bases_count() # needs sage.graphs 125 ALGORITHM: @@ -5983,14 +5986,14 @@ cdef class RegularMatroid(LinearMatroid): A = {} B = {} N = 0 - for i in xrange(P.nrows()): + for i in range(P.nrows()): w = P.get_unsafe(i, i) if w != 0: if w in A: A[w] += 1 else: A[w] = 1 - for j in xrange(i): + for j in range(i): w = abs(P.get_unsafe(i, j)) if w != 0: if w in B: @@ -6027,12 +6030,11 @@ cdef class RegularMatroid(LinearMatroid): EXAMPLES:: sage: M = matroids.named_matroids.R10() - sage: PV, tups, G = M._hypergraph() - sage: G + sage: PV, tups, G = M._hypergraph() # needs sage.graphs + sage: G # needs sage.graphs Digraph on 55 vertices """ # NEW VERSION, Uses Sage'S Graph Isomorphism - from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph if self._r_hypergraph is not None: return (self._hypergraph_vertex_partition, self._hypergraph_tuples, self._r_hypergraph) @@ -6041,7 +6043,7 @@ cdef class RegularMatroid(LinearMatroid): B = {} V = [] E = [] - for i in xrange(P.nrows()): + for i in range(P.nrows()): e = self._E[i] w = P.get_unsafe(i, i) if w != 0: @@ -6050,7 +6052,7 @@ cdef class RegularMatroid(LinearMatroid): else: A[w] = [e] V.append(e) - for j in xrange(i): + for j in range(i): f = self._E[j] w = abs(P.get_unsafe(i, j)) if w != 0: @@ -6110,11 +6112,11 @@ cdef class RegularMatroid(LinearMatroid): EXAMPLES:: sage: M1 = matroids.Wheel(3) - sage: M2 = Matroid(groundset = list(range(6)), - ....: graph = graphs.CompleteGraph(4), regular = True) - sage: M1._is_isomorphic(M2) + sage: M2 = Matroid(groundset=list(range(6)), # needs sage.graphs + ....: graph=graphs.CompleteGraph(4), regular=True) + sage: M1._is_isomorphic(M2) # needs sage.graphs True - sage: M1._is_isomorphic(M2, certificate=True) + sage: M1._is_isomorphic(M2, certificate=True) # needs sage.graphs (True, {0: 0, 1: 1, 2: 2, 3: 3, 4: 5, 5: 4}) sage: M1 = matroids.Wheel(3) @@ -6150,7 +6152,7 @@ cdef class RegularMatroid(LinearMatroid): """ if certificate: return self._is_isomorphic(other), self._isomorphism(other) - if type(other) == RegularMatroid: + if isinstance(other, RegularMatroid): return self.is_field_isomorphic(other) else: return LinearMatroid._is_isomorphic(self, other) @@ -6182,7 +6184,7 @@ cdef class RegularMatroid(LinearMatroid): sage: M = matroids.named_matroids.R10()\'a' sage: N = matroids.named_matroids.R10()\'b' - sage: M._fast_isom_test(N) + sage: M._fast_isom_test(N) # needs sage.graphs True """ if self.bases_count() != other.bases_count(): @@ -6213,9 +6215,9 @@ cdef class RegularMatroid(LinearMatroid): Check that :trac:`22263` was fixed:: - sage: m1 = Matroid(graph='H?ABC~}') - sage: m2 = Matroid(graph='H?ACNr}') - sage: m1.is_isomorphic(m2) + sage: m1 = Matroid(graph='H?ABC~}') # needs sage.graphs + sage: m2 = Matroid(graph='H?ACNr}') # needs sage.graphs + sage: m1.is_isomorphic(m2) # needs sage.graphs False """ from sage.groups.perm_gps.partn_ref.refinement_graphs import isomorphic @@ -6337,10 +6339,10 @@ cdef class RegularMatroid(LinearMatroid): sage: M = matroids.named_matroids.R10() sage: M.is_graphic() False - sage: M = Matroid(graphs.CompleteGraph(5), regular = True) - sage: M.is_graphic() + sage: M = Matroid(graphs.CompleteGraph(5), regular=True) # needs sage.graphs + sage: M.is_graphic() # needs sage.graphs sage.rings.finite_rings True - sage: M.dual().is_graphic() + sage: M.dual().is_graphic() # needs sage.graphs False ALGORITHM: @@ -6366,6 +6368,7 @@ cdef class RegularMatroid(LinearMatroid): EXAMPLES:: + sage: # needs sage.graphs sage: M = Matroid(Matrix(ZZ, [[1, 0, 0, 1, 1, 0, 1], ....: [0, 1, 0, 1, 0, 1, 1], ....: [0, 0, 1, 0, 1, 1, 1]]), @@ -6521,7 +6524,7 @@ cdef class RegularMatroid(LinearMatroid): else: rows, cols = self._current_rows_cols() N = RegularMatroid(groundset=rows + cols, reduced_matrix=self._A) - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N def __deepcopy__(self, memo): @@ -6541,7 +6544,7 @@ cdef class RegularMatroid(LinearMatroid): else: rows, cols = self._current_rows_cols() N = RegularMatroid(groundset=deepcopy(rows + cols, memo), reduced_matrix=deepcopy(self._A, memo)) - N.rename(deepcopy(getattr(self, '__custom_name'), memo)) + N.rename(deepcopy(self.get_custom_name(), memo)) return N def __reduce__(self): @@ -6590,5 +6593,5 @@ cdef class RegularMatroid(LinearMatroid): rows, cols = self._current_rows_cols() gs = rows + cols reduced = True - data = (A, gs, reduced, getattr(self, '__custom_name')) + data = (A, gs, reduced, self.get_custom_name()) return sage.matroids.unpickling.unpickle_regular_matroid, (version, data) diff --git a/src/sage/matroids/matroid.pxd b/src/sage/matroids/matroid.pxd index fe6c07e3b71..e9ddfec96ae 100644 --- a/src/sage/matroids/matroid.pxd +++ b/src/sage/matroids/matroid.pxd @@ -1,8 +1,7 @@ from sage.structure.sage_object cimport SageObject cdef class Matroid(SageObject): - cdef public __custom_name - cdef public _custom_name + cdef public _SageObject__custom_name cdef public _cached_info cdef int _stored_full_rank cdef int _stored_size @@ -37,7 +36,7 @@ cdef class Matroid(SageObject): cpdef _line_length(self, F) cpdef _extension(self, element, hyperplanes) - cdef inline __subset(self, X): + cdef inline _subset_internal(self, X): """ Convert ``X`` to a ``frozenset`` and check that it is a subset of the groundset. diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 6c43b0d896d..4d19c589bdf 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -216,7 +216,7 @@ in which the partition is specified as a list of lists:: sage: M = PartitionMatroid([[1, 2], [3, 4, 5], [6, 7]]) sage: M.full_rank() 3 - sage: M.tutte_polynomial(var('x'), var('y')) + sage: M.tutte_polynomial(var('x'), var('y')) # needs sage.symbolic x^2*y^2 + 2*x*y^3 + y^4 + x^3 + 3*x^2*y + 3*x*y^2 + y^3 .. NOTE:: @@ -330,23 +330,23 @@ Methods # https://www.gnu.org/licenses/ # **************************************************************************** -from cpython.object cimport Py_EQ, Py_NE from collections.abc import Iterable +from cpython.object cimport Py_EQ, Py_NE +from itertools import combinations, product +from sage.matrix.constructor import matrix +from sage.misc.lazy_import import LazyImport +from sage.misc.prandom import shuffle +from sage.rings.integer_ring import ZZ from sage.structure.richcmp cimport rich_to_bool, richcmp from sage.structure.sage_object cimport SageObject -from itertools import combinations, permutations, product -from .set_system cimport SetSystem -from sage.graphs.spanning_tree import kruskal -from sage.graphs.graph import Graph -from sage.matrix.constructor import matrix +MixedIntegerLinearProgram = LazyImport('sage.numerical.mip', 'MixedIntegerLinearProgram') + +from .lean_matrix cimport BinaryMatrix, TernaryMatrix +from .set_system cimport SetSystem from .utilities import newlabel, sanitize_contractions_deletions, spanning_forest, spanning_stars -from sage.rings.integer_ring import ZZ -from sage.numerical.mip import MixedIntegerLinearProgram -from sage.matroids.lean_matrix cimport BinaryMatrix, TernaryMatrix -from sage.misc.prandom import shuffle # On some systems, macros "minor()" and "major()" are defined in system header # files. This will undefine those: @@ -395,7 +395,7 @@ cdef class Matroid(SageObject): sage: M = PartitionMatroid([[1, 2], [3, 4, 5], [6, 7]]) sage: M.full_rank() 3 - sage: M.tutte_polynomial(var('x'), var('y')) + sage: M.tutte_polynomial(var('x'), var('y')) # needs sage.symbolic x^2*y^2 + 2*x*y^3 + y^4 + x^3 + 3*x^2*y + 3*x*y^2 + y^3 .. NOTE:: @@ -563,7 +563,7 @@ cdef class Matroid(SageObject): OUTPUT: ``frozenset`` instance containing a subset of the groundset. - A ``ValueError`` is raised if the set contains no circuit. + A :class:`ValueError` is raised if the set contains no circuit. EXAMPLES:: @@ -708,7 +708,7 @@ cdef class Matroid(SageObject): OUTPUT: ``frozenset`` instance containing a subset of the groundset. - A ``ValueError`` is raised if the set contains no cocircuit. + A :class:`ValueError` is raised if the set contains no cocircuit. EXAMPLES:: @@ -1307,7 +1307,7 @@ cdef class Matroid(SageObject): TypeError: 'sage.rings.integer.Integer' object is not iterable """ # Call corresponding Cython method - return self.__subset(X) + return self._subset_internal(X) def _subset_all(self, X): """ @@ -1374,7 +1374,7 @@ cdef class Matroid(SageObject): """ if X is None: return self.full_rank() - return self._rank(self.__subset(X)) + return self._rank(self._subset_internal(X)) cpdef full_rank(self): r""" @@ -1453,7 +1453,7 @@ cdef class Matroid(SageObject): ... ValueError: ['x'] is not a subset of the groundset """ - return self._max_independent(self.__subset(X)) + return self._max_independent(self._subset_internal(X)) cpdef circuit(self, X=None): """ @@ -1490,7 +1490,7 @@ cdef class Matroid(SageObject): ... ValueError: ['x'] is not a subset of the groundset sage: C = M.circuit() - sage: sorted(C) # random + sage: sorted(C) # random ['a', 'b', 'c', 'd'] sage: M.is_circuit(C) True @@ -1558,7 +1558,7 @@ cdef class Matroid(SageObject): ... ValueError: ['x'] is not a subset of the groundset """ - return self._closure(self.__subset(X)) + return self._closure(self._subset_internal(X)) cpdef k_closure(self, X, k): r""" @@ -1597,7 +1597,7 @@ cdef class Matroid(SageObject): sage: sorted(M.k_closure({0,1}, 4)) [0, 1, 4] """ - X = self.__subset(X) + X = self._subset_internal(X) cdef int cur cdef frozenset S, cl cur = 0 @@ -1644,7 +1644,7 @@ cdef class Matroid(SageObject): ... ValueError: ['x'] is not a subset of the groundset """ - X = self.__subset(X) + X = self._subset_internal(X) Y = self.__subset_all(Y) return self._augment(X, Y.difference(X)) @@ -1770,7 +1770,7 @@ cdef class Matroid(SageObject): sage: M = matroids.named_matroids.Vamos() sage: X = M.max_coindependent(['a', 'c', 'd', 'e', 'f']) - sage: sorted(X) # random + sage: sorted(X) # random ['a', 'c', 'd', 'f'] sage: M.is_coindependent(X) True @@ -1781,7 +1781,7 @@ cdef class Matroid(SageObject): ... ValueError: ['x'] is not a subset of the groundset """ - return self._max_coindependent(self.__subset(X)) + return self._max_coindependent(self._subset_internal(X)) cpdef coclosure(self, X): """ @@ -1813,7 +1813,7 @@ cdef class Matroid(SageObject): ... ValueError: ['x'] is not a subset of the groundset """ - return self._coclosure(self.__subset(X)) + return self._coclosure(self._subset_internal(X)) cpdef cocircuit(self, X=None): """ @@ -1856,7 +1856,7 @@ cdef class Matroid(SageObject): ... ValueError: ['x'] is not a subset of the groundset sage: C = M.cocircuit() - sage: sorted(C) # random + sage: sorted(C) # random ['e', 'f', 'g', 'h'] sage: M.is_cocircuit(C) True @@ -1947,7 +1947,7 @@ cdef class Matroid(SageObject): ... ValueError: 'abcx' is not a subset of the groundset """ - return self._is_independent(self.__subset(X)) + return self._is_independent(self._subset_internal(X)) cpdef is_dependent(self, X): r""" @@ -1973,7 +1973,7 @@ cdef class Matroid(SageObject): ... ValueError: 'abcx' is not a subset of the groundset """ - return not self._is_independent(self.__subset(X)) + return not self._is_independent(self._subset_internal(X)) cpdef is_basis(self, X): r""" @@ -1999,7 +1999,7 @@ cdef class Matroid(SageObject): ... ValueError: 'abcx' is not a subset of the groundset """ - X = self.__subset(X) + X = self._subset_internal(X) if len(X) != self.full_rank(): return False return self._is_basis(X) @@ -2035,7 +2035,7 @@ cdef class Matroid(SageObject): ... ValueError: 'abcx' is not a subset of the groundset """ - return self._is_closed(self.__subset(X)) + return self._is_closed(self._subset_internal(X)) cpdef is_subset_k_closed(self, X, int k): r""" @@ -2118,7 +2118,7 @@ cdef class Matroid(SageObject): ... ValueError: 'abcx' is not a subset of the groundset """ - return self._is_circuit(self.__subset(X)) + return self._is_circuit(self._subset_internal(X)) cpdef coloops(self): r""" @@ -2178,7 +2178,7 @@ cdef class Matroid(SageObject): ... ValueError: 'abcx' is not a subset of the groundset """ - return self._is_coindependent(self.__subset(X)) + return self._is_coindependent(self._subset_internal(X)) cpdef is_codependent(self, X): r""" @@ -2211,7 +2211,7 @@ cdef class Matroid(SageObject): ... ValueError: 'abcx' is not a subset of the groundset """ - return not self._is_coindependent(self.__subset(X)) + return not self._is_coindependent(self._subset_internal(X)) cpdef is_cobasis(self, X): r""" @@ -2245,7 +2245,7 @@ cdef class Matroid(SageObject): ... ValueError: 'abcx' is not a subset of the groundset """ - X = self.__subset(X) + X = self._subset_internal(X) if len(X) != self.full_corank(): return False return self._is_cobasis(X) @@ -2282,7 +2282,7 @@ cdef class Matroid(SageObject): ... ValueError: 'abcx' is not a subset of the groundset """ - return self._is_cocircuit(self.__subset(X)) + return self._is_cocircuit(self._subset_internal(X)) cpdef is_coclosed(self, X): r""" @@ -2315,7 +2315,7 @@ cdef class Matroid(SageObject): ... ValueError: 'abcx' is not a subset of the groundset """ - return self._is_coclosed(self.__subset(X)) + return self._is_coclosed(self._subset_internal(X)) # verification @@ -2358,7 +2358,7 @@ cdef class Matroid(SageObject): rX = self._rank(XX) if rX > i: return False - for j in xrange(i, len(E) + 1): + for j in range(i, len(E) + 1): for Y in combinations(E, j): YY = frozenset(Y) rY = self._rank(YY) @@ -2511,10 +2511,10 @@ cdef class Matroid(SageObject): sage: [sorted(X) for X in CC[3]] [['a', 'b', 'c', 'd', 'e', 'f', 'g']] """ - CC = [set([]) for r in xrange(self.rank() + 1)] + CC = [set([]) for r in range(self.rank() + 1)] for C in self.circuits(): CC[len(C) - 1].add(self.closure(C)) - return {r: CC[r] for r in xrange(self.rank() + 1) if CC[r]} + return {r: CC[r] for r in range(self.rank() + 1) if CC[r]} cpdef nonspanning_circuit_closures(self): """ @@ -2544,10 +2544,10 @@ cdef class Matroid(SageObject): ... KeyError: 3 """ - CC = [set([]) for r in xrange(self.rank() + 1)] + CC = [set([]) for r in range(self.rank() + 1)] for C in self.nonspanning_circuits(): CC[len(C) - 1].add(self.closure(C)) - return {r: CC[r] for r in xrange(self.rank() + 1) if CC[r]} + return {r: CC[r] for r in range(self.rank() + 1) if CC[r]} cpdef nonbases(self): r""" @@ -2792,7 +2792,7 @@ cdef class Matroid(SageObject): return [] loops = self._closure(set()) flags = [[loops, set(), self.groundset() - loops]] - for r in xrange(r): + for r in range(r): flags = self._extend_flags(flags) return flags @@ -2845,8 +2845,8 @@ cdef class Matroid(SageObject): EXAMPLES:: - sage: M = matroids.named_matroids.Q6() - sage: sorted([sorted(F) for F in M.coflats(2)]) + sage: M = matroids.named_matroids.Q6() # needs sage.rings.finite_rings + sage: sorted([sorted(F) for F in M.coflats(2)]) # needs sage.rings.finite_rings [['a', 'b'], ['a', 'c'], ['a', 'd', 'f'], ['a', 'e'], ['b', 'c'], ['b', 'd'], ['b', 'e'], ['b', 'f'], ['c', 'd'], ['c', 'e', 'f'], ['d', 'e']] @@ -2860,7 +2860,7 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M = matroids.named_matroids.Fano() - sage: M.lattice_of_flats() + sage: M.lattice_of_flats() # needs sage.graphs Finite lattice containing 16 elements """ from sage.combinat.posets.lattices import LatticePoset @@ -2913,7 +2913,7 @@ cdef class Matroid(SageObject): loops = self._closure(set()) flags = [[loops, set(), self.groundset() - loops]] f_vec = [1] - for r in xrange(self.full_rank()): + for r in range(self.full_rank()): flags = self._extend_flags(flags) f_vec.append(len(flags)) return f_vec @@ -2974,17 +2974,17 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M = Matroid(circuits=[[1,2,3], [3,4,5], [1,2,4,5]]) - sage: SimplicialComplex(M.no_broken_circuits_sets()) + sage: SimplicialComplex(M.no_broken_circuits_sets()) # needs sage.graphs Simplicial complex with vertex set (1, 2, 3, 4, 5) and facets {(1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5)} - sage: SimplicialComplex(M.no_broken_circuits_sets([5,4,3,2,1])) + sage: SimplicialComplex(M.no_broken_circuits_sets([5,4,3,2,1])) # needs sage.graphs Simplicial complex with vertex set (1, 2, 3, 4, 5) and facets {(1, 3, 5), (1, 4, 5), (2, 3, 5), (2, 4, 5)} :: sage: M = Matroid(circuits=[[1,2,3], [1,4,5], [2,3,4,5]]) - sage: SimplicialComplex(M.no_broken_circuits_sets([5,4,3,2,1])) + sage: SimplicialComplex(M.no_broken_circuits_sets([5,4,3,2,1])) # needs sage.graphs Simplicial complex with vertex set (1, 2, 3, 4, 5) and facets {(1, 3, 5), (2, 3, 5), (2, 4, 5), (3, 4, 5)} @@ -3072,9 +3072,10 @@ cdef class Matroid(SageObject): with circuit-closures {3: {{0, 1, 2, 3}}} - sage: G = SymmetricGroup(3); - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) + sage: G = SymmetricGroup(3); # needs sage.groups + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) # needs sage.groups + sage: # needs sage.groups sage: G = SymmetricGroup(4) sage: action = lambda g,x: g(x+1)-1 sage: OSG1 = M.orlik_solomon_algebra(QQ, invariant=(G,action)) @@ -3127,12 +3128,12 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M = matroids.Whirl(4) - sage: P = M.matroid_polytope(); P + sage: P = M.matroid_polytope(); P # needs sage.geometry.polyhedron sage.rings.finite_rings A 7-dimensional polyhedron in ZZ^8 defined as the convex hull of 46 vertices sage: M = matroids.named_matroids.NonFano() - sage: M.matroid_polytope() + sage: M.matroid_polytope() # needs sage.geometry.polyhedron sage.rings.finite_rings A 6-dimensional polyhedron in ZZ^7 defined as the convex hull of 29 vertices @@ -3170,12 +3171,12 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M = matroids.Whirl(4) - sage: M.independence_matroid_polytope() + sage: M.independence_matroid_polytope() # needs sage.geometry.polyhedron sage.rings.finite_rings A 8-dimensional polyhedron in ZZ^8 defined as the convex hull of 135 vertices sage: M = matroids.named_matroids.NonFano() - sage: M.independence_matroid_polytope() + sage: M.independence_matroid_polytope() # needs sage.geometry.polyhedron sage.rings.finite_rings A 7-dimensional polyhedron in ZZ^7 defined as the convex hull of 58 vertices @@ -3216,13 +3217,13 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M1 = matroids.Wheel(3) - sage: M2 = matroids.CompleteGraphic(4) - sage: M1.is_isomorphic(M2) + sage: M2 = matroids.CompleteGraphic(4) # needs sage.graphs + sage: M1.is_isomorphic(M2) # needs sage.graphs True - sage: M1.is_isomorphic(M2, certificate=True) + sage: M1.is_isomorphic(M2, certificate=True) # needs sage.graphs (True, {0: 0, 1: 1, 2: 2, 3: 3, 4: 5, 5: 4}) - sage: G3 = graphs.CompleteGraph(4) - sage: M1.is_isomorphic(G3) + sage: G3 = graphs.CompleteGraph(4) # needs sage.graphs + sage: M1.is_isomorphic(G3) # needs sage.graphs Traceback (most recent call last): ... TypeError: can only test for isomorphism between matroids. @@ -3253,7 +3254,7 @@ cdef class Matroid(SageObject): OUTPUT: Boolean, - and, if certificate = True, a dictionary giving the isomorphism or None + and, if ``certificate=True``, a dictionary giving the isomorphism or ``None`` .. NOTE:: @@ -3262,10 +3263,10 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M1 = matroids.Wheel(3) - sage: M2 = matroids.CompleteGraphic(4) - sage: M1._is_isomorphic(M2) + sage: M2 = matroids.CompleteGraphic(4) # needs sage.graphs + sage: M1._is_isomorphic(M2) # needs sage.graphs True - sage: M1._is_isomorphic(M2, certificate=True) + sage: M1._is_isomorphic(M2, certificate=True) # needs sage.graphs (True, {0: 0, 1: 1, 2: 2, 3: 3, 4: 5, 5: 4}) sage: M1 = matroids.named_matroids.Fano() @@ -3300,12 +3301,12 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M1 = matroids.Wheel(3) - sage: M2 = matroids.CompleteGraphic(4) - sage: morphism=M1.isomorphism(M2) - sage: M1.is_isomorphism(M2, morphism) + sage: M2 = matroids.CompleteGraphic(4) # needs sage.graphs + sage: morphism = M1.isomorphism(M2) # needs sage.graphs + sage: M1.is_isomorphism(M2, morphism) # needs sage.graphs True - sage: G3 = graphs.CompleteGraph(4) - sage: M1.isomorphism(G3) + sage: G3 = graphs.CompleteGraph(4) # needs sage.graphs + sage: M1.isomorphism(G3) # needs sage.graphs Traceback (most recent call last): ... TypeError: can only give isomorphism between matroids. @@ -3336,9 +3337,9 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M1 = matroids.Wheel(3) - sage: M2 = matroids.CompleteGraphic(4) - sage: morphism=M1.isomorphism(M2) - sage: M1.is_isomorphism(M2, morphism) + sage: M2 = matroids.CompleteGraphic(4) # needs sage.graphs + sage: morphism = M1.isomorphism(M2) # needs sage.graphs + sage: M1.is_isomorphism(M2, morphism) # needs sage.graphs True sage: M1 = matroids.named_matroids.Fano() sage: M2 = matroids.named_matroids.NonFano() @@ -3386,8 +3387,7 @@ cdef class Matroid(SageObject): yields ``False``, even if the matroids are equal:: sage: from sage.matroids.advanced import * - sage: M = matroids.named_matroids.Fano() - sage: M + sage: M = matroids.named_matroids.Fano(); M Fano: Binary matroid of rank 3 on 7 elements, type (3, 0) sage: M1 = BasisMatroid(M) sage: M2 = Matroid(groundset='abcdefg', reduced_matrix=[ @@ -3419,6 +3419,15 @@ cdef class Matroid(SageObject): False sage: M1 == M3 True + + TESTS: + + Check that :issue:`35946` is fixed:: + + sage: M = matroids.Uniform(3,5) + sage: N = matroids.Uniform(2,5) + sage: M.equals(N) + False """ if self is other: return True @@ -3426,6 +3435,8 @@ cdef class Matroid(SageObject): raise TypeError("can only test for isomorphism between matroids.") if (self.size() != other.size() or other.groundset().difference(self.groundset())): return False + if self.full_rank() != other.full_rank(): + return False morphism = {e: e for e in self.groundset()} return self._is_isomorphism(other, morphism) @@ -3474,9 +3485,9 @@ cdef class Matroid(SageObject): a function, and many other types of maps:: sage: M = matroids.named_matroids.Fano() - sage: P = PermutationGroup([[('a', 'b', 'c'), + sage: P = PermutationGroup([[('a', 'b', 'c'), # needs sage.rings.finite_rings ....: ('d', 'e', 'f'), ('g')]]).gen() - sage: M.is_isomorphism(M, P) + sage: M.is_isomorphism(M, P) # needs sage.rings.finite_rings True sage: M = matroids.named_matroids.Pappus() @@ -3491,12 +3502,14 @@ cdef class Matroid(SageObject): There is extensive checking for inappropriate input:: + sage: # needs sage.graphs sage: M = matroids.CompleteGraphic(4) - sage: M.is_isomorphism(graphs.CompleteGraph(4), lambda x:x) + sage: M.is_isomorphism(graphs.CompleteGraph(4), lambda x: x) Traceback (most recent call last): ... TypeError: can only test for isomorphism between matroids. + sage: # needs sage.graphs sage: M = matroids.CompleteGraphic(4) sage: sorted(M.groundset()) [0, 1, 2, 3, 4, 5] @@ -3506,6 +3519,7 @@ cdef class Matroid(SageObject): ValueError: domain of morphism does not contain groundset of this matroid. + sage: # needs sage.graphs sage: M = matroids.CompleteGraphic(4) sage: sorted(M.groundset()) [0, 1, 2, 3, 4, 5] @@ -3515,6 +3529,7 @@ cdef class Matroid(SageObject): ValueError: range of morphism does not contain groundset of other matroid. + sage: # needs sage.graphs sage: M = matroids.CompleteGraphic(3) sage: N = Matroid(bases=['ab', 'ac', 'bc']) sage: f = [0, 1, 2] @@ -3525,8 +3540,18 @@ cdef class Matroid(SageObject): ValueError: the morphism argument does not seem to be an isomorphism. + sage: # needs sage.graphs sage: N.is_isomorphism(M, g) True + + TESTS: + + Check that :issue:`35946` is fixed:: + + sage: M = matroids.Uniform(3,5) + sage: N = matroids.Uniform(2,5) + sage: M.is_isomorphism(N, {e: e for e in M.groundset()}) + False """ from copy import copy if not isinstance(other, Matroid): @@ -3550,11 +3575,16 @@ cdef class Matroid(SageObject): raise ValueError("range of morphism does not contain groundset of other matroid.") if self is other: return self._is_isomorphism(copy(other), mf) + if self.full_rank() != other.full_rank(): + return False return self._is_isomorphism(other, mf) cpdef _is_isomorphism(self, other, morphism): r""" - Version of is_isomorphism() that does no type checking. + Version of :meth:`is_isomorphism` that does no type checking. + + This method assumes that ``self`` and ``other`` have the same rank + and does not check this condition. INPUT: @@ -3830,10 +3860,10 @@ cdef class Matroid(SageObject): One can use a single element, rather than a set:: - sage: M = matroids.CompleteGraphic(4) - sage: M.contract(1) == M.contract([1]) + sage: M = matroids.CompleteGraphic(4) # needs sage.graphs + sage: M.contract(1) == M.contract([1]) # needs sage.graphs True - sage: M / 1 + sage: M / 1 # needs sage.graphs Graphic matroid of rank 2 on 5 elements Note that one can iterate over strings:: @@ -3858,8 +3888,8 @@ cdef class Matroid(SageObject): EXAMPLES:: - sage: M = matroids.CompleteGraphic(4) - sage: M.contract(1) == M.__truediv__(1) + sage: M = matroids.CompleteGraphic(4) # needs sage.graphs + sage: M.contract(1) == M.__truediv__(1) # needs sage.graphs True """ return self.contract(X) @@ -3907,10 +3937,10 @@ cdef class Matroid(SageObject): One can use a single element, rather than a set:: - sage: M = matroids.CompleteGraphic(4) - sage: M.delete(1) == M.delete([1]) + sage: M = matroids.CompleteGraphic(4) # needs sage.graphs + sage: M.delete(1) == M.delete([1]) # needs sage.graphs True - sage: M \ 1 + sage: M \ 1 # needs sage.graphs Graphic matroid of rank 3 on 5 elements Note that one can iterate over strings:: @@ -3935,8 +3965,8 @@ cdef class Matroid(SageObject): EXAMPLES:: - sage: M = matroids.CompleteGraphic(4) - sage: M.delete(1) == M \ 1 # indirect doctest + sage: M = matroids.CompleteGraphic(4) # needs sage.graphs + sage: M.delete(1) == M \ 1 # indirect doctest # needs sage.graphs True """ return self.delete(X) @@ -4863,10 +4893,10 @@ cdef class Matroid(SageObject): sage: M.connectivity('ab', 'cd') 2 """ - S = self.__subset(S) + S = self._subset_internal(S) if T is None: return self._rank(S) + self._rank(self.groundset()-S) - self.full_rank() - T = self.__subset(T) + T = self._subset_internal(T) if S.intersection(T): raise ValueError("S and T are not disjoint") return len(self._link(S, T)[0]) - self.full_rank() + self._rank(S) + self._rank(T) @@ -4951,8 +4981,8 @@ cdef class Matroid(SageObject): sage: N.connectivity(S) 2 """ - S = self.__subset(S) - T = self.__subset(T) + S = self._subset_internal(S) + T = self._subset_internal(T) if not S.isdisjoint(T): raise ValueError("S and T are not disjoint") return self._link(S, T) @@ -5080,12 +5110,12 @@ cdef class Matroid(SageObject): ....: groundset='abcdef') sage: N.is_kconnected(3) False - sage: matroids.named_matroids.BetsyRoss().is_kconnected(3) + sage: matroids.named_matroids.BetsyRoss().is_kconnected(3) # needs sage.graphs True sage: matroids.AG(5,2).is_kconnected(4) True sage: M = matroids.named_matroids.R6() - sage: M.is_kconnected(3) + sage: M.is_kconnected(3) # needs sage.graphs False sage: B, X = M.is_kconnected(3,True) sage: M.connectivity(X)<3 @@ -5224,10 +5254,10 @@ cdef class Matroid(SageObject): ....: groundset='abcdef') sage: N.is_3connected() False - sage: matroids.named_matroids.BetsyRoss().is_3connected() + sage: matroids.named_matroids.BetsyRoss().is_3connected() # needs sage.graphs True sage: M = matroids.named_matroids.R6() - sage: M.is_3connected() + sage: M.is_3connected() # needs sage.graphs False sage: B, X = M.is_3connected(True) sage: M.connectivity(X) @@ -5287,7 +5317,7 @@ cdef class Matroid(SageObject): ....: [0,0,1,1,0,0,1,1,0,1,0,1], ....: [0,0,0,0,1,1,1,1,0,0,1,1], ....: [0,0,0,0,0,0,0,0,1,1,1,1]]) - sage: M.is_4connected() == M.is_4connected(algorithm="shifting") + sage: M.is_4connected() == M.is_4connected(algorithm="shifting") # needs sage.graphs True sage: M.is_4connected() == M.is_4connected(algorithm="intersection") True @@ -5447,25 +5477,25 @@ cdef class Matroid(SageObject): EXAMPLES:: - sage: matroids.Uniform(2, 3)._is_3connected_shifting() + sage: matroids.Uniform(2, 3)._is_3connected_shifting() # needs sage.graphs True sage: M = Matroid(ring=QQ, matrix=[[1, 0, 0, 1, 1, 0], ....: [0, 1, 0, 1, 2, 0], ....: [0, 0, 1, 0, 0, 1]]) - sage: M._is_3connected_shifting() + sage: M._is_3connected_shifting() # needs sage.graphs False sage: N = Matroid(circuit_closures={2: ['abc', 'cdef'], ....: 3: ['abcdef']}, ....: groundset='abcdef') - sage: N._is_3connected_shifting() + sage: N._is_3connected_shifting() # needs sage.graphs False - sage: matroids.named_matroids.BetsyRoss()._is_3connected_shifting() + sage: matroids.named_matroids.BetsyRoss()._is_3connected_shifting() # needs sage.graphs True sage: M = matroids.named_matroids.R6() - sage: M._is_3connected_shifting() + sage: M._is_3connected_shifting() # needs sage.graphs False - sage: B, X = M._is_3connected_shifting(True) - sage: M.connectivity(X) + sage: B, X = M._is_3connected_shifting(True) # needs sage.graphs + sage: M.connectivity(X) # needs sage.graphs 1 """ if not self.is_connected(): @@ -5526,17 +5556,17 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M = matroids.Uniform(2, 6) - sage: B, X = M._is_4connected_shifting(True) - sage: (B, M.connectivity(X)<=3) + sage: B, X = M._is_4connected_shifting(True) # needs sage.graphs + sage: (B, M.connectivity(X)<=3) # needs sage.graphs (False, True) - sage: matroids.Uniform(4, 8)._is_4connected_shifting() + sage: matroids.Uniform(4, 8)._is_4connected_shifting() # needs sage.graphs True sage: M = Matroid(field=GF(2), matrix=[[1,0,0,1,0,1,1,0,0,1,1,1], ....: [0,1,0,1,0,1,0,1,0,0,0,1], ....: [0,0,1,1,0,0,1,1,0,1,0,1], ....: [0,0,0,0,1,1,1,1,0,0,1,1], ....: [0,0,0,0,0,0,0,0,1,1,1,1]]) - sage: M._is_4connected_shifting() + sage: M._is_4connected_shifting() # needs sage.graphs True """ if self.rank()>self.size()-self.rank(): @@ -5572,9 +5602,9 @@ cdef class Matroid(SageObject): B[x, y] = 0 # remove row x1 and y1 - Xp = list(xrange(n)) + Xp = list(range(n)) Xp.remove(x1) - Yp = list(xrange(m)) + Yp = list(range(m)) Yp.remove(y1) B = B.matrix_from_rows_and_columns(Xp,Yp) @@ -5642,13 +5672,15 @@ cdef class Matroid(SageObject): ....: [0,0,1,1,0,0,1,1,0,1,0,1], ....: [0,0,0,0,1,1,1,1,0,0,1,1], ....: [0,0,0,0,0,0,0,0,1,1,1,1]]) - sage: M._shifting_all(M.basis(),set([0,1]),set([0,1]),set([]),set([]),3) + sage: M._shifting_all(M.basis(), + ....: set([0,1]), set([0,1]), set([]), set([]), 3) (False, None) sage: M = Matroid(field=GF(2), reduced_matrix=[[1,0,1,1,1], ....: [1,1,1,1,0], ....: [0,1,1,1,0], ....: [0,0,0,1,1]]) - sage: M._shifting_all(M.basis(), set([0,1]), set([5,8]), set([]), set([]), 3)[0] + sage: M._shifting_all(M.basis(), + ....: set([0,1]), set([5,8]), set([]), set([]), 3)[0] True """ @@ -5673,8 +5705,8 @@ cdef class Matroid(SageObject): Given a basis ``X``. If the submatrix of the partial matrix using rows `X_1` columns `Y_2` and submatrix using rows `X_2` columns `Y_1` can be extended to a ``m``-separator, then it returns - `True, E`, where `E` is a ``m``-separator. Otherwise it returns - `False, None` + ``True, E``, where `E` is a ``m``-separator. Otherwise it returns + ``False, None`` `X_1` and `X_2` must be disjoint subsets of `X`. `Y_1` and `Y_2` must be disjoint subsets of `Y`. @@ -5692,8 +5724,8 @@ cdef class Matroid(SageObject): OUTPUT: - - `False, None` -- if there is no ``m``-separator. - - `True, E` -- if there exist a ``m``-separator ``E``. + - ``False, None`` -- if there is no ``m``-separator. + - ``True, E`` -- if there exist a ``m``-separator ``E``. EXAMPLES:: @@ -5702,13 +5734,15 @@ cdef class Matroid(SageObject): ....: [0,0,1,1,0,0,1,1,0,1,0,1], ....: [0,0,0,0,1,1,1,1,0,0,1,1], ....: [0,0,0,0,0,0,0,0,1,1,1,1]]) - sage: M._shifting(M.basis(),set([0,1]),set([0,1]),set([]),set([]),3) + sage: M._shifting(M.basis(), + ....: set([0,1]), set([0,1]), set([]), set([]), 3) (False, None) sage: M = Matroid(field=GF(2), reduced_matrix=[[1,0,1,1,1], ....: [1,1,1,1,0], ....: [0,1,1,1,0], ....: [0,0,0,1,1]]) - sage: M._shifting(M.basis(), set([0,1]), set([5,8]), set([]), set([4]), 3)[0] + sage: M._shifting(M.basis(), + ....: set([0,1]), set([5,8]), set([]), set([4]), 3)[0] True """ @@ -5785,15 +5819,14 @@ cdef class Matroid(SageObject): ....: [0, 0, 1, 0, 0, 1]]) sage: M._is_3connected_BC() False - sage: N = Matroid(circuit_closures={2: ['abc', 'cdef'], - ....: 3: ['abcdef']}, + sage: N = Matroid(circuit_closures={2: ['abc', 'cdef'], 3: ['abcdef']}, ....: groundset='abcdef') sage: N._is_3connected_BC() False - sage: matroids.named_matroids.BetsyRoss()._is_3connected_BC() + sage: matroids.named_matroids.BetsyRoss()._is_3connected_BC() # needs sage.graphs True sage: M = matroids.named_matroids.R6() - sage: M._is_3connected_BC() + sage: M._is_3connected_BC() # needs sage.graphs False """ # The 5 stages of the algorithm @@ -5840,7 +5873,7 @@ cdef class Matroid(SageObject): True sage: M = matroids.named_matroids.R6() sage: B = M.basis() - sage: M._is_3connected_BC_recursion(B, + sage: M._is_3connected_BC_recursion(B, # needs sage.graphs ....: [M.fundamental_cocircuit(B, e) for e in B]) False @@ -5864,6 +5897,8 @@ cdef class Matroid(SageObject): return True # Step 3: Check the avoidance graph of Y + from sage.graphs.graph import Graph + Y_components = {} B_segments = [] for B in bridges: @@ -6082,14 +6117,16 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: N = matroids.named_matroids.Fano() - sage: M = N._local_ternary_matroid() - sage: N.is_isomorphism(M, {e:e for e in N.groundset()}) + sage: M = N._local_ternary_matroid() # needs sage.graphs + sage: N.is_isomorphism(M, {e:e for e in N.groundset()}) # needs sage.graphs False sage: N = matroids.named_matroids.NonFano() - sage: M = N._local_ternary_matroid() - sage: N.is_isomorphism(M, {e:e for e in N.groundset()}) + sage: M = N._local_ternary_matroid() # needs sage.graphs + sage: N.is_isomorphism(M, {e:e for e in N.groundset()}) # needs sage.graphs True """ + from sage.graphs.graph import Graph + if basis is None: basis = self.basis() basis = sorted(basis) @@ -6102,8 +6139,8 @@ cdef class Matroid(SageObject): entries = [(e, f, (e, f)) for e in basis for f in self._fundamental_cocircuit(basis, e).difference([e])] G = Graph(entries) T = set() - for C in G.connected_components(): - T.update(G.subgraph(C).min_spanning_tree()) + for C in G.connected_components_subgraphs(): + T.update(C.min_spanning_tree()) for edge in T: e,f = edge[2] A.set(bdx[e],idx[f], 1) @@ -6174,10 +6211,10 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M = matroids.named_matroids.Fano() - sage: M.ternary_matroid() is None + sage: M.ternary_matroid() is None # needs sage.graphs True sage: N = matroids.named_matroids.NonFano() - sage: N.ternary_matroid() + sage: N.ternary_matroid() # needs sage.graphs NonFano: Ternary matroid of rank 3 on 7 elements, type 0- """ @@ -6226,10 +6263,10 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: N = matroids.named_matroids.Fano() - sage: N.is_ternary() + sage: N.is_ternary() # needs sage.graphs False sage: N = matroids.named_matroids.NonFano() - sage: N.is_ternary() + sage: N.is_ternary() # needs sage.graphs True """ @@ -6246,6 +6283,7 @@ cdef class Matroid(SageObject): EXAMPLES:: + sage: # needs sage.combinat sage: PR = RootSystem(['A',4]).root_lattice().positive_roots() sage: m = matrix([x.to_vector() for x in PR]).transpose() sage: M = Matroid(m) @@ -6254,6 +6292,7 @@ cdef class Matroid(SageObject): sage: M.is_k_closed(4) True + sage: # needs sage.combinat sage: PR = RootSystem(['D',4]).root_lattice().positive_roots() sage: m = matrix([x.to_vector() for x in PR]).transpose() sage: M = Matroid(m) @@ -6305,7 +6344,7 @@ cdef class Matroid(SageObject): cdef frozenset Ax, Bx X = set(C) - e = X.pop() + _ = X.pop() # cl(X) = cl(C), and to be a chord x must be spanned by C for x in self._closure(X)-C: Ax = self._circuit(X.union([x])) @@ -6349,7 +6388,8 @@ cdef class Matroid(SageObject): (False, None) sage: M.is_circuit_chordal(['a','b','d','e']) True - sage: X = M.is_circuit_chordal(frozenset(['a','b','d','e']), certificate=True)[1] + sage: X = M.is_circuit_chordal(frozenset(['a','b','d','e']), + ....: certificate=True)[1] sage: X # random ('c', frozenset({'b', 'c', 'd'}), frozenset({'a', 'c', 'e'})) sage: M.is_circuit(X[1]) and M.is_circuit(X[2]) @@ -6567,12 +6607,10 @@ cdef class Matroid(SageObject): sage: M.is_cobasis(X) True - sage: wt = {'a': 1, 'b': 2, 'c': 2, 'd': 1/2, 'e': 1, 'f': 2, - ....: 'g': 2} + sage: wt = {'a': 1, 'b': 2, 'c': 2, 'd': 1/2, 'e': 1, 'f': 2, 'g': 2} sage: setprint(M.max_weight_coindependent(weights=wt)) {'b', 'c', 'f', 'g'} - sage: wt = {'a': 1, 'b': -10, 'c': 2, 'd': 1/2, 'e': 1, 'f': 2, - ....: 'g': 2} + sage: wt = {'a': 1, 'b': -10, 'c': 2, 'd': 1/2, 'e': 1, 'f': 2, 'g': 2} sage: setprint(M.max_weight_coindependent(weights=wt)) Traceback (most recent call last): ... @@ -6644,9 +6682,7 @@ cdef class Matroid(SageObject): - ``weights`` -- a dictionary or function mapping the elements of ``X`` to nonnegative weights. - OUTPUT: - - Boolean. + OUTPUT: Boolean. ALGORITHM: @@ -7567,7 +7603,7 @@ cdef class Matroid(SageObject): sage: from sage.matroids.advanced import setprint sage: M = matroids.named_matroids.Fano() - sage: setprint(M.flat_cover()) + sage: setprint(M.flat_cover()) # needs sage.rings.finite_rings [{'a', 'b', 'f'}, {'a', 'c', 'e'}, {'a', 'd', 'g'}, {'b', 'c', 'd'}, {'b', 'e', 'g'}, {'c', 'f', 'g'}, {'d', 'e', 'f'}] @@ -7585,7 +7621,7 @@ cdef class Matroid(SageObject): MIP.set_objective(sum([f[F] for F in FF])) for N in NB: MIP.add_constraint(sum([f[F] for F in FF if len(F.intersection(N)) > self.rank(F)]), min=1) - opt = MIP.solve(log=verbose) + _ = MIP.solve(log=verbose) fsol = MIP.get_values(f, convert=bool, tolerance=integrality_tolerance) @@ -7623,26 +7659,25 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M = matroids.Wheel(2) - sage: A = M.chow_ring() - sage: A + sage: A = M.chow_ring(); A Chow ring of Wheel(2): Regular matroid of rank 2 on 4 elements with 5 bases over Integer Ring - sage: A.gens() + sage: A.gens() # needs sage.libs.singular (A23, A23, A23) - sage: A23 = A.gen(0) - sage: A23*A23 + sage: A23 = A.gen(0) # needs sage.libs.singular + sage: A23*A23 # needs sage.libs.singular 0 We construct a more interesting example using the Fano matroid:: sage: M = matroids.named_matroids.Fano() - sage: A = M.chow_ring(QQ) - sage: A + sage: A = M.chow_ring(QQ); A Chow ring of Fano: Binary matroid of rank 3 on 7 elements, type (3, 0) over Rational Field Next we get the non-trivial generators and do some computations:: + sage: # needs sage.libs.singular sage.rings.finite_rings sage: G = A.gens()[6:] sage: Ag, Aabf, Aace, Aadg, Abcd, Abeg, Acfg, Adef = G sage: Ag * Ag @@ -7724,11 +7759,11 @@ cdef class Matroid(SageObject): EXAMPLES:: - sage: M=matroids.named_matroids.Fano() - sage: G=M.plot() - sage: type(G) + sage: M = matroids.named_matroids.Fano() + sage: G = M.plot() # needs sage.plot sage.rings.finite_rings + sage: type(G) # needs sage.plot sage.rings.finite_rings <class 'sage.plot.graphics.Graphics'> - sage: G.show() + sage: G.show() # needs sage.plot sage.rings.finite_rings """ from . import matroids_plot_helpers @@ -7781,11 +7816,12 @@ cdef class Matroid(SageObject): EXAMPLES:: - sage: M=matroids.named_matroids.TernaryDowling3() - sage: M.show(B=['a','b','c']) - sage: M.show(B=['a','b','c'],lineorders=[['f','e','i']]) - sage: pos = {'a':(0,0), 'b': (0,1), 'c':(1,0), 'd':(1,1), 'e':(1,-1), 'f':(-1,1), 'g':(-1,-1),'h':(2,0), 'i':(0,2)} - sage: M.show(pos_method=1, pos_dict=pos,lims=[-3,3,-3,3]) + sage: M = matroids.named_matroids.TernaryDowling3() + sage: M.show(B=['a','b','c']) # needs sage.plot sage.rings.finite_rings + sage: M.show(B=['a','b','c'], lineorders=[['f','e','i']]) # needs sage.plot sage.rings.finite_rings + sage: pos = {'a':(0,0), 'b': (0,1), 'c':(1,0), 'd':(1,1), # needs sage.plot + ....: 'e':(1,-1), 'f':(-1,1), 'g':(-1,-1),'h':(2,0), 'i':(0,2)} + sage: M.show(pos_method=1, pos_dict=pos, lims=[-3,3,-3,3]) # needs sage.plot sage.rings.finite_rings """ if self.rank() > 3: raise NotImplementedError @@ -7824,15 +7860,15 @@ cdef class Matroid(SageObject): sage: t="fghij" sage: x=1.61 sage: y=1/1.61 - sage: for i in range(5): + sage: for i in range(5): # needs sage.symbolic ....: pos[s[i]]=(RR(x*sin(2*pi*i/5)), RR(x*cos(2*pi*i/5))) ....: pos[t[i]]=(RR(y*sin(2*pi*(i+1/2)/5)), RR(y*cos(2*pi*(i+1/2)/5))) ....: sage: pos['k']=(0,0) - sage: M._fix_positions(pos_dict=pos) - sage: M._cached_info['lineorders'] is None + sage: M._fix_positions(pos_dict=pos) # needs sage.symbolic + sage: M._cached_info['lineorders'] is None # needs sage.symbolic True - sage: M._cached_info['plot_positions']['k'] + sage: M._cached_info['plot_positions']['k'] # needs sage.symbolic (0, 0) """ if self.rank() > 3: @@ -7863,10 +7899,10 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M = Matroid(circuits=[[1,2,3], [3,4,5], [1,2,4,5]]) - sage: M.broken_circuit_complex() + sage: M.broken_circuit_complex() # needs sage.graphs Simplicial complex with vertex set (1, 2, 3, 4, 5) and facets {(1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5)} - sage: M.broken_circuit_complex([5,4,3,2,1]) + sage: M.broken_circuit_complex([5,4,3,2,1]) # needs sage.graphs Simplicial complex with vertex set (1, 2, 3, 4, 5) and facets {(1, 3, 5), (1, 4, 5), (2, 3, 5), (2, 4, 5)} """ @@ -7888,7 +7924,7 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M = matroids.named_matroids.Fano() - sage: B = M.bergman_complex(); B + sage: B = M.bergman_complex(); B # needs sage.graphs Simplicial complex with 14 vertices and 21 facets .. SEEALSO:: @@ -7927,11 +7963,11 @@ cdef class Matroid(SageObject): EXAMPLES:: sage: M = matroids.named_matroids.Fano() - sage: A = M.augmented_bergman_complex(); A + sage: A = M.augmented_bergman_complex(); A # needs sage.graphs Simplicial complex with 22 vertices and 91 facets sage: M = matroids.Uniform(2,3) - sage: A = M.augmented_bergman_complex(); A + sage: A = M.augmented_bergman_complex(); A # needs sage.graphs Simplicial complex with 7 vertices and 9 facets Both the independent set complex of the matroid and the usual @@ -7940,9 +7976,9 @@ cdef class Matroid(SageObject): to the independent set complex and ``R`` when they belong to the (cone of) the Bergman complex. The cone point is ``'R[]'``:: - sage: sorted(A.faces()[0]) + sage: sorted(A.faces()[0]) # needs sage.graphs [('L0',), ('L1',), ('L2',), ('R[0]',), ('R[1]',), ('R[2]',), ('R[]',)] - sage: sorted(map(sorted, A.faces()[1])) + sage: sorted(map(sorted, A.faces()[1])) # needs sage.graphs [['L0', 'L1'], ['L0', 'L2'], ['L0', 'R[0]'], diff --git a/src/sage/matroids/matroids_plot_helpers.py b/src/sage/matroids/matroids_plot_helpers.py index 99ada7f3b3a..0740a938f11 100644 --- a/src/sage/matroids/matroids_plot_helpers.py +++ b/src/sage/matroids/matroids_plot_helpers.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - scipy r""" Helper functions for plotting the geometric representation of matroids @@ -50,13 +51,14 @@ EXAMPLES:: sage: from sage.matroids import matroids_plot_helpers - sage: M1=Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0,1,0,1], - ....: [0, 1, 0, 1, 0, 1, 1,0,0,1,0], [0, 0, 1, 1, 1, 0, 1,0,0,0,0]]) - sage: pos_dict= {0: (0, 0), 1: (2, 0), 2: (1, 2), 3: (1.5, 1.0), - ....: 4: (0.5, 1.0), 5: (1.0, 0.0), 6: (1.0, 0.666666666666667), - ....: 7: (3,3), 8: (4,0), 9: (-1,1), 10: (-2,-2)} - sage: M1._cached_info={'plot_positions': pos_dict, 'plot_lineorders': None} - sage: matroids_plot_helpers.geomrep(M1, sp=True) + sage: M1 = Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0,1,0,1], + ....: [0, 1, 0, 1, 0, 1, 1,0,0,1,0], + ....: [0, 0, 1, 1, 1, 0, 1,0,0,0,0]]) + sage: pos_dict = {0: (0, 0), 1: (2, 0), 2: (1, 2), 3: (1.5, 1.0), + ....: 4: (0.5, 1.0), 5: (1.0, 0.0), 6: (1.0, 0.666666666666667), + ....: 7: (3,3), 8: (4,0), 9: (-1,1), 10: (-2,-2)} + sage: M1._cached_info = {'plot_positions': pos_dict, 'plot_lineorders': None} + sage: matroids_plot_helpers.geomrep(M1, sp=True) # needs sage.plot sage.rings.finite_rings Graphics object consisting of 22 graphics primitives """ @@ -321,22 +323,22 @@ def createline(ptsdict, ll, lineorders2=None): EXAMPLES:: sage: from sage.matroids import matroids_plot_helpers - sage: ptsdict={'a':(1,3),'b':(2,1),'c':(4,5),'d':(5,2)} - sage: x,y,x_i,y_i=matroids_plot_helpers.createline(ptsdict, + sage: ptsdict = {'a':(1,3),'b':(2,1),'c':(4,5),'d':(5,2)} + sage: x,y,x_i,y_i = matroids_plot_helpers.createline(ptsdict, ....: ['a','b','c','d']) sage: [len(x), len(y), len(x_i), len(y_i)] [4, 4, 100, 100] - sage: G = line(zip(x_i, y_i),color='black',thickness=3,zorder=1) - sage: G+=points(zip(x, y), color='black', size=300,zorder=2) - sage: G.show() - sage: x,y,x_i,y_i=matroids_plot_helpers.createline(ptsdict, + sage: G = line(zip(x_i, y_i), color='black', thickness=3, zorder=1) # needs sage.plot + sage: G += points(zip(x, y), color='black', size=300, zorder=2) # needs sage.plot + sage: G.show() # needs sage.plot + sage: x,y,x_i,y_i = matroids_plot_helpers.createline(ptsdict, ....: ['a','b','c','d'],lineorders2=[['b','a','c','d'], ....: ['p','q','r','s']]) sage: [len(x), len(y), len(x_i), len(y_i)] [4, 4, 100, 100] - sage: G = line(zip(x_i, y_i),color='black',thickness=3,zorder=1) - sage: G+=points(zip(x, y), color='black', size=300,zorder=2) - sage: G.show() + sage: G = line(zip(x_i, y_i), color='black', thickness=3, zorder=1) # needs sage.plot + sage: G += points(zip(x, y), color='black', size=300, zorder=2) # needs sage.plot + sage: G.show() # needs sage.plot .. NOTE:: @@ -401,21 +403,23 @@ def slp(M1, pos_dict=None, B=None): sage: from sage.matroids import matroids_plot_helpers sage: from sage.matroids.advanced import setprint - sage: M1=Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0,1,0,1], - ....: [0, 1, 0, 1, 0, 1, 1,0,0,1,0],[0, 0, 1, 1, 1, 0, 1,0,0,0,0]]) - sage: [M,L,P]=matroids_plot_helpers.slp(M1) - sage: M.is_simple() + sage: M1 = Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0,1,0,1], + ....: [0, 1, 0, 1, 0, 1, 1,0,0,1,0], + ....: [0, 0, 1, 1, 1, 0, 1,0,0,0,0]]) + sage: [M,L,P] = matroids_plot_helpers.slp(M1) # needs sage.rings.finite_rings + sage: M.is_simple() # needs sage.rings.finite_rings True - sage: setprint([L,P]) + sage: setprint([L,P]) # needs sage.rings.finite_rings [{10, 8, 9}, {7}] - sage: M1=Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0,1,0,1], - ....: [0, 1, 0, 1, 0, 1, 1,0,0,1,0],[0, 0, 1, 1, 1, 0, 1,0,0,0,0]]) - sage: posdict= {8: (0, 0), 1: (2, 0), 2: (1, 2), 3: (1.5, 1.0), - ....: 4: (0.5, 1.0), 5: (1.0, 0.0), 6: (1.0, 0.6666666666666666)} - sage: [M,L,P]=matroids_plot_helpers.slp(M1,pos_dict=posdict) - sage: M.is_simple() + sage: M1 = Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0,1,0,1], + ....: [0, 1, 0, 1, 0, 1, 1,0,0,1,0], + ....: [0, 0, 1, 1, 1, 0, 1,0,0,0,0]]) + sage: posdict = {8: (0, 0), 1: (2, 0), 2: (1, 2), 3: (1.5, 1.0), + ....: 4: (0.5, 1.0), 5: (1.0, 0.0), 6: (1.0, 0.6666666666666666)} + sage: [M,L,P] = matroids_plot_helpers.slp(M1, pos_dict=posdict) # needs sage.rings.finite_rings + sage: M.is_simple() # needs sage.rings.finite_rings True - sage: setprint([L,P]) + sage: setprint([L,P]) # needs sage.rings.finite_rings [{0, 10, 9}, {7}] .. NOTE:: @@ -483,11 +487,12 @@ def addlp(M, M1, L, P, ptsdict, G=None, limits=None): EXAMPLES:: sage: from sage.matroids import matroids_plot_helpers - sage: M=Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0,1], - ....: [0, 1, 0, 1, 0, 1, 1,0,0],[0, 0, 1, 1, 1, 0, 1,0,0]]) - sage: [M1,L,P]=matroids_plot_helpers.slp(M) - sage: G,lims=matroids_plot_helpers.addlp(M,M1,L,P,{0:(0,0)}) - sage: G.show(axes=False) + sage: M = Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0,1], + ....: [0, 1, 0, 1, 0, 1, 1,0,0], + ....: [0, 0, 1, 1, 1, 0, 1,0,0]]) + sage: [M1,L,P] = matroids_plot_helpers.slp(M) # needs sage.rings.finite_rings + sage: G, lims = matroids_plot_helpers.addlp(M,M1,L,P,{0:(0,0)}) # needs sage.plot sage.rings.finite_rings + sage: G.show(axes=False) # needs sage.plot sage.rings.finite_rings .. NOTE:: @@ -664,15 +669,16 @@ def posdict_is_sane(M1, pos_dict): EXAMPLES:: sage: from sage.matroids import matroids_plot_helpers - sage: M1=Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0,1,0,1], - ....: [0, 1, 0, 1, 0, 1, 1,0,0,1,0],[0, 0, 1, 1, 1, 0, 1,0,0,0,0]]) - sage: pos_dict= {0: (0, 0), 1: (2, 0), 2: (1, 2), 3: (1.5, 1.0), + sage: M1 = Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0,1,0,1], + ....: [0, 1, 0, 1, 0, 1, 1,0,0,1,0], + ....: [0, 0, 1, 1, 1, 0, 1,0,0,0,0]]) + sage: pos_dict = {0: (0, 0), 1: (2, 0), 2: (1, 2), 3: (1.5, 1.0), ....: 4: (0.5, 1.0), 5: (1.0, 0.0), 6: (1.0, 0.6666666666666666)} - sage: matroids_plot_helpers.posdict_is_sane(M1,pos_dict) + sage: matroids_plot_helpers.posdict_is_sane(M1,pos_dict) # needs sage.rings.finite_rings True - sage: pos_dict= {1: (2, 0), 2: (1, 2), 3: (1.5, 1.0), - ....: 4: (0.5, 1.0), 5: (1.0, 0.0), 6: (1.0, 0.6666666666666666)} - sage: matroids_plot_helpers.posdict_is_sane(M1,pos_dict) + sage: pos_dict = {1: (2, 0), 2: (1, 2), 3: (1.5, 1.0), + ....: 4: (0.5, 1.0), 5: (1.0, 0.0), 6: (1.0, 0.6666666666666666)} + sage: matroids_plot_helpers.posdict_is_sane(M1,pos_dict) # needs sage.rings.finite_rings False .. NOTE:: @@ -757,12 +763,12 @@ def geomrep(M1, B1=None, lineorders1=None, pd=None, sp=False): EXAMPLES:: sage: from sage.matroids import matroids_plot_helpers - sage: M=matroids.named_matroids.P7() - sage: G=matroids_plot_helpers.geomrep(M) - sage: G.show(xmin=-2, xmax=3, ymin=-2, ymax=3) - sage: M=matroids.named_matroids.P7() - sage: G=matroids_plot_helpers.geomrep(M,lineorders1=[['f','e','d']]) - sage: G.show(xmin=-2, xmax=3, ymin=-2, ymax=3) + sage: M = matroids.named_matroids.P7() + sage: G = matroids_plot_helpers.geomrep(M) # needs sage.plot + sage: G.show(xmin=-2, xmax=3, ymin=-2, ymax=3) # needs sage.plot + sage: M = matroids.named_matroids.P7() + sage: G = matroids_plot_helpers.geomrep(M, lineorders1=[['f','e','d']]) # needs sage.plot + sage: G.show(xmin=-2, xmax=3, ymin=-2, ymax=3) # needs sage.plot .. NOTE:: diff --git a/src/sage/matroids/minor_matroid.py b/src/sage/matroids/minor_matroid.py index bc567d1d4ce..98856348ac1 100644 --- a/src/sage/matroids/minor_matroid.py +++ b/src/sage/matroids/minor_matroid.py @@ -132,8 +132,8 @@ def __init__(self, matroid, contractions=None, deletions=None): EXAMPLES:: sage: from sage.matroids.advanced import * - sage: M = MinorMatroid(matroids.named_matroids.Fano(), - ....: contractions=set(), deletions=set(['g'])) # indirect doctest + sage: M = MinorMatroid(matroids.named_matroids.Fano(), # indirect doctest + ....: contractions=set(), deletions=set(['g'])) sage: M.is_isomorphic(matroids.Wheel(3)) True """ @@ -486,8 +486,7 @@ def __copy__(self): True """ N = MinorMatroid(self._matroid, self._contractions, self._deletions) - if getattr(self, '__custom_name') is not None: # because of name wrangling, this is not caught by the default copy - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N def __deepcopy__(self, memo={}): @@ -512,8 +511,7 @@ def __deepcopy__(self, memo={}): from copy import deepcopy # Since matroids are immutable, N cannot reference itself in correct code, so no need to worry about the recursion. N = MinorMatroid(deepcopy(self._matroid, memo), deepcopy(self._contractions, memo), deepcopy(self._deletions, memo)) - if getattr(self, '__custom_name') is not None: # because of name wrangling, this is not caught by the default deepcopy - N.rename(deepcopy(getattr(self, '__custom_name'), memo)) + N.rename(deepcopy(self.get_custom_name(), memo)) return N def __reduce__(self): @@ -534,6 +532,6 @@ def __reduce__(self): 4: {{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}}} """ import sage.matroids.unpickling - data = (self._matroid, self._contractions, self._deletions, getattr(self, '__custom_name')) + data = (self._matroid, self._contractions, self._deletions, self.get_custom_name()) version = 0 return sage.matroids.unpickling.unpickle_minor_matroid, (version, data) diff --git a/src/sage/matroids/rank_matroid.py b/src/sage/matroids/rank_matroid.py index 4633ff0a792..6c4e9470ada 100644 --- a/src/sage/matroids/rank_matroid.py +++ b/src/sage/matroids/rank_matroid.py @@ -267,9 +267,7 @@ def __copy__(self): N = RankMatroid(groundset=[], rank_function=None) N._groundset = self._groundset N._rank_function = self._rank_function - if getattr(self, '__custom_name') is not None: - # because of name wrangling, this is not caught by the default copy - N.rename(getattr(self, '__custom_name')) + N.rename(self.get_custom_name()) return N def __deepcopy__(self, memo={}): @@ -293,8 +291,7 @@ def __deepcopy__(self, memo={}): from copy import deepcopy # Since matroids are immutable, N cannot reference itself in correct code, so no need to worry about the recursion. N = RankMatroid(groundset=deepcopy(self._groundset), rank_function=deepcopy(self._rank_function)) - if getattr(self, '__custom_name') is not None: # because of name wrangling, this is not caught by the default deepcopy - N.rename(deepcopy(getattr(self, '__custom_name'), memo)) + N.rename(deepcopy(self.get_custom_name(), memo)) return N def __reduce__(self): diff --git a/src/sage/matroids/set_system.pyx b/src/sage/matroids/set_system.pyx index 14a590c5d56..cb4daf4099a 100644 --- a/src/sage/matroids/set_system.pyx +++ b/src/sage/matroids/set_system.pyx @@ -83,7 +83,7 @@ cdef class SetSystem: else: self._groundset = groundset self._idx = {} - for i in xrange(len(groundset)): + for i in range(len(groundset)): self._idx[groundset[i]] = i self._groundset_size = len(groundset) @@ -125,7 +125,7 @@ cdef class SetSystem: def __dealloc__(self): cdef long i - for i in xrange(self._len): + for i in range(self._len): bitset_free(self._subsets[i]) sig_free(self._subsets) bitset_free(self._temp) @@ -205,7 +205,7 @@ cdef class SetSystem: cdef copy(self): cdef SetSystem S S = SetSystem(self._groundset, capacity=len(self)) - for i in xrange(len(self)): + for i in range(len(self)): S._append(self._subsets[i]) return S @@ -232,7 +232,7 @@ cdef class SetSystem: E.append(self._E[i]) self._groundset = E self._idx = {} - for i in xrange(self._groundset_size): + for i in range(self._groundset_size): self._idx[self._groundset[i]] = i cpdef _complements(self): @@ -255,7 +255,7 @@ cdef class SetSystem: if self._groundset_size == 0: return self S = SetSystem(self._groundset, capacity=len(self)) - for i in xrange(len(self)): + for i in range(len(self)): bitset_complement(self._temp, self._subsets[i]) S._append(self._temp) return S @@ -266,7 +266,7 @@ cdef class SetSystem: """ if k is None: k = self._len - for i in xrange(k, self._len): + for i in range(k, self._len): bitset_free(self._subsets[i]) self._len = min(self._len, k) k2 = max(k, 1) @@ -357,7 +357,7 @@ cdef class SetSystem: bitset_complement(active, active) # We compute the union of all sets containing 0, and deactivate them. - for i in xrange(self._len): + for i in range(self._len): if bitset_in(self._subsets[i], 0): bitset_union(self._temp, self._subsets[i], self._temp) bitset_discard(active, i) @@ -388,7 +388,7 @@ cdef class SetSystem: """ cdef long i, e cdef list cnt - cnt = [0 for v in xrange(self._groundset_size)] + cnt = [0 for v in range(self._groundset_size)] for e in E: i = bitset_first(self._subsets[e]) while i >= 0: @@ -401,11 +401,11 @@ cdef class SetSystem: Helper method for partition methods below. """ cdef dict C - cdef long i, j, v, t0, t + cdef long i, v, t0, t cdef bint split C = {} - for i in xrange(len(P)): + for i in range(len(P)): v = bitset_first(P._subsets[i]) if v < 0: continue @@ -443,7 +443,7 @@ cdef class SetSystem: """ cdef long c c = 0 - for p in xrange(len(P)): + for p in range(len(P)): c <<= bitset_len(P._subsets[p]) bitset_intersection(self._temp, P._subsets[p], self._subsets[e]) c += bitset_len(self._temp) @@ -453,11 +453,10 @@ cdef class SetSystem: """ Helper method for partition methods below. """ - S = {} if P is None: P = self.groundset_partition() if E is None: - E = xrange(self._len) + E = range(self._len) if len(E) == 0: return [E] @@ -487,7 +486,7 @@ cdef class SetSystem: S = SetSystem(self._groundset, capacity=len(self) + 1) bitset_clear(self._temp) bitset_add(self._temp, v) - for i in xrange(len(self)): + for i in range(len(self)): bitset_difference(S._temp, self._subsets[i], self._temp) S._append(S._temp) S._append(self._temp) @@ -499,7 +498,7 @@ cdef class SetSystem: Helper method for partition methods below. """ if E is None: - E = xrange(self._len) + E = range(self._len) if P is None: if self._groundset: P = SetSystem(self._groundset, [self._groundset], capacity=self._groundset_size) @@ -561,7 +560,7 @@ cdef class SetSystem: partition elements is an invariant of the isomorphism class of the hypergraph. """ - cdef long h, l + cdef long h cdef list EP2, H if P is None: @@ -633,7 +632,7 @@ cdef class SetSystem: [3] """ P, EP, h = self._equitable_partition(P, EP) - for i in xrange(len(P)): + for i in range(len(P)): if bitset_len(P._subsets[i]) > 1: return self._heuristic_partition(P._distinguish(bitset_first(P._subsets[i])), EP) return P, EP, h @@ -676,13 +675,13 @@ cdef class SetSystem: if len(SP) != len(OP): return None p = SP._groundset_size + 1 - for i in xrange(len(SP)): + for i in range(len(SP)): l = bitset_len(SP._subsets[i]) if l != bitset_len(OP._subsets[i]): return None if l != 1 and l < p: p = l - for i in xrange(len(SP)): + for i in range(len(SP)): if bitset_len(SP._subsets[i]) == p: SP2, SEP, sh = self._equitable_partition(SP._distinguish(bitset_first(SP._subsets[i]))) v = bitset_first(OP._subsets[i]) @@ -694,9 +693,9 @@ cdef class SetSystem: return m v = bitset_next(OP._subsets[i], v + 1) return None - if sorted([self.subset_characteristic(SP, i) for i in xrange(len(self))]) != sorted([other.subset_characteristic(OP, i) for i in xrange(len(other))]): + if sorted([self.subset_characteristic(SP, i) for i in range(len(self))]) != sorted([other.subset_characteristic(OP, i) for i in range(len(other))]): return None - return dict([(self._groundset[bitset_first(SP._subsets[i])], other._groundset[bitset_first(OP._subsets[i])]) for i in xrange(len(SP))]) + return dict([(self._groundset[bitset_first(SP._subsets[i])], other._groundset[bitset_first(OP._subsets[i])]) for i in range(len(SP))]) cpdef _equivalence(self, is_equiv, SetSystem other, SetSystem SP=None, SetSystem OP=None): """ @@ -734,7 +733,7 @@ cdef class SetSystem: sage: N = Matroid(ring=GF(5), reduced_matrix=[[1,0,1],[0,1,1],[1,1,0]]) sage: M.is_field_isomorphic(N) False - sage: any(M.is_field_isomorphism(N, p) for p in Permutations(range(6))) + sage: any(M.is_field_isomorphism(N, p) for p in Permutations(range(6))) # needs sage.combinat False """ cdef long v @@ -745,10 +744,10 @@ cdef class SetSystem: return None if len(SP) != len(OP): return None - for i in xrange(len(SP)): + for i in range(len(SP)): if bitset_len(SP._subsets[i]) != bitset_len(OP._subsets[i]): return None - for i in xrange(len(SP)): + for i in range(len(SP)): if bitset_len(SP._subsets[i]) > 1: SP2, SEP, sh = self._equitable_partition(SP._distinguish(bitset_first(SP._subsets[i]))) v = bitset_first(OP._subsets[i]) @@ -760,7 +759,7 @@ cdef class SetSystem: return m v = bitset_next(OP._subsets[i], v + 1) return None - morph = dict([(self._groundset[bitset_first(SP._subsets[i])], other._groundset[bitset_first(OP._subsets[i])]) for i in xrange(len(SP))]) + morph = dict([(self._groundset[bitset_first(SP._subsets[i])], other._groundset[bitset_first(OP._subsets[i])]) for i in range(len(SP))]) if is_equiv(self, other, morph): return morph diff --git a/src/sage/matroids/unpickling.pyx b/src/sage/matroids/unpickling.pyx index b37ae49a37f..94464ecb9f0 100644 --- a/src/sage/matroids/unpickling.pyx +++ b/src/sage/matroids/unpickling.pyx @@ -39,6 +39,7 @@ from .graphic_matroid import GraphicMatroid from sage.rings.rational cimport Rational from sage.libs.gmp.mpq cimport mpq_set + ############################################################################# # BasisMatroid ############################################################################# @@ -224,7 +225,7 @@ def unpickle_binary_matrix(version, data): raise TypeError("object was created with newer version of Sage. Please upgrade.") nrows, ncols, versionB, size, limbs, longsize, M = data A = BinaryMatrix(nrows, ncols) - for i from 0 <= i < nrows: + for i in range(nrows): bitset_unpickle(A._M[i], (versionB, size, limbs, longsize, M[i])) return A @@ -253,7 +254,7 @@ def unpickle_ternary_matrix(version, data): raise TypeError("object was created with newer version of Sage. Please upgrade.") nrows, ncols, versionB, size, limbs, longsize, M0, M1 = data A = TernaryMatrix(nrows, ncols) - for i from 0 <= i < nrows: + for i in range(nrows): bitset_unpickle(A._M0[i], (versionB, size, limbs, longsize, M0[i])) bitset_unpickle(A._M1[i], (versionB, size, limbs, longsize, M1[i])) return A @@ -269,6 +270,7 @@ def unpickle_quaternary_matrix(version, data): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(2, 5, ring=GF(4, 'x')) sage: A == loads(dumps(A)) # indirect doctest @@ -283,7 +285,7 @@ def unpickle_quaternary_matrix(version, data): raise TypeError("object was created with newer version of Sage. Please upgrade.") nrows, ncols, ring, versionB, size, limbs, longsize, M0, M1 = data A = QuaternaryMatrix(nrows, ncols, ring=ring) - for i from 0 <= i < nrows: + for i in range(nrows): bitset_unpickle(A._M0[i], (versionB, size, limbs, longsize, M0[i])) bitset_unpickle(A._M1[i], (versionB, size, limbs, longsize, M1[i])) return A @@ -324,7 +326,7 @@ def unpickle_plus_minus_one_matrix(version, data): raise TypeError("object was created with newer version of Sage. Please upgrade.") cdef PlusMinusOneMatrix A = PlusMinusOneMatrix(data[0], data[1]) cdef long i - for i from 0 <= i < A._nrows * A._ncols: + for i in range(A._nrows * A._ncols): A._entries[i] = data[2][i] return A @@ -332,6 +334,7 @@ def unpickle_plus_minus_one_matrix(version, data): from sage.misc.persist import register_unpickle_override register_unpickle_override("sage.matroids.unpickling", "unpickle_integer_matrix", unpickle_plus_minus_one_matrix) + def unpickle_rational_matrix(version, data): """ Reconstruct a :class:`sage.matroids.lean_matrix.RationalMatrix` object @@ -535,9 +538,9 @@ def unpickle_quaternary_matroid(version, data): sage: M.rename("U34") sage: loads(dumps(M)) U34 - sage: M = QuaternaryMatroid(Matrix(GF(4, 'x'), [[1, 0, 1], + sage: M = QuaternaryMatroid(Matrix(GF(4, 'x'), [[1, 0, 1], # needs sage.rings.finite_rings ....: [1, 0, 1]])) - sage: loads(dumps(M)).representation() + sage: loads(dumps(M)).representation() # needs sage.rings.finite_rings [1 0 1] [1 0 1] """ @@ -670,8 +673,8 @@ def unpickle_graphic_matroid(version, data): EXAMPLES:: - sage: M = Matroid(graphs.DiamondGraph()) - sage: M == loads(dumps(M)) + sage: M = Matroid(graphs.DiamondGraph()) # needs sage.graphs + sage: M == loads(dumps(M)) # needs sage.graphs True """ if version != 0: diff --git a/src/sage/matroids/utilities.py b/src/sage/matroids/utilities.py index eb2999ea07b..211c435c5ee 100644 --- a/src/sage/matroids/utilities.py +++ b/src/sage/matroids/utilities.py @@ -26,15 +26,10 @@ from collections.abc import Iterable from sage.matrix.constructor import Matrix -from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.graphs.graph import Graph -from sage.graphs.bipartite_graph import BipartiteGraph from sage.structure.all import SageObject -from sage.graphs.spanning_tree import kruskal from operator import itemgetter -from sage.rings.number_field.number_field import NumberField def setprint(X): @@ -83,10 +78,10 @@ def setprint(X): An exception was made for subclasses of SageObject:: sage: from sage.matroids.advanced import setprint - sage: G = graphs.PetersenGraph() - sage: list(G) + sage: G = graphs.PetersenGraph() # needs sage.graphs + sage: list(G) # needs sage.graphs [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - sage: setprint(G) + sage: setprint(G) # needs sage.graphs Petersen graph: Graph on 10 vertices """ print(setprint_s(X, toplevel=True)) @@ -270,7 +265,7 @@ def make_regular_matroid_from_matroid(matroid): EXAMPLES:: sage: from sage.matroids.utilities import make_regular_matroid_from_matroid - sage: make_regular_matroid_from_matroid( + sage: make_regular_matroid_from_matroid( # needs sage.graphs ....: matroids.CompleteGraphic(6)).is_isomorphic( ....: matroids.CompleteGraphic(6)) True @@ -279,6 +274,9 @@ def make_regular_matroid_from_matroid(matroid): M = matroid if isinstance(M, sage.matroids.linear_matroid.RegularMatroid): return M + + from sage.graphs.bipartite_graph import BipartiteGraph + rk = M.full_rank() # First create a reduced 0-1 matrix B = list(M.basis()) @@ -378,11 +376,15 @@ def spanning_forest(M): EXAMPLES:: - sage: len(sage.matroids.utilities.spanning_forest(matrix([[1,1,1],[1,1,1],[1,1,1]]))) + sage: from sage.matroids.utilities import spanning_forest + sage: len(spanning_forest(matrix([[1,1,1],[1,1,1],[1,1,1]]))) # needs sage.graphs 5 - sage: len(sage.matroids.utilities.spanning_forest(matrix([[0,0,1],[0,1,0],[0,1,0]]))) + sage: len(spanning_forest(matrix([[0,0,1],[0,1,0],[0,1,0]]))) # needs sage.graphs 3 """ + from sage.graphs.graph import Graph + from sage.graphs.spanning_tree import kruskal + # Given a matrix, produce a spanning tree G = Graph() m = M.ncols() @@ -390,8 +392,8 @@ def spanning_forest(M): G.add_edge(x + m, y) T = [] # find spanning tree in each component - for component in G.connected_components(): - spanning_tree = kruskal(G.subgraph(component)) + for component in G.connected_components_subgraphs(): + spanning_tree = kruskal(component) for (x, y, z) in spanning_tree: if x < m: t = x @@ -418,10 +420,12 @@ def spanning_stars(M): EXAMPLES:: - sage: edges = sage.matroids.utilities.spanning_stars(matrix([[1,1,1],[1,1,1],[1,1,1]])) - sage: Graph([(x+3, y) for x,y in edges]).is_connected() + sage: from sage.matroids.utilities import spanning_stars + sage: edges = spanning_stars(matrix([[1,1,1],[1,1,1],[1,1,1]])) # needs sage.graphs + sage: Graph([(x+3, y) for x,y in edges]).is_connected() # needs sage.graphs True """ + from sage.graphs.graph import Graph G = Graph() m = M.ncols() @@ -531,29 +535,32 @@ def lift_cross_ratios(A, lift_map=None): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.matroids.advanced import lift_cross_ratios, lift_map, LinearMatroid sage: R = GF(7) - sage: to_sixth_root_of_unity = lift_map('sru') + sage: to_sixth_root_of_unity = lift_map('sru') # needs sage.rings.number_field sage: A = Matrix(R, [[1, 0, 6, 1, 2],[6, 1, 0, 0, 1],[0, 6, 3, 6, 0]]) sage: A [1 0 6 1 2] [6 1 0 0 1] [0 6 3 6 0] - sage: Z = lift_cross_ratios(A, to_sixth_root_of_unity) - sage: Z - [ 1 0 1 1 1] - [ 1 1 0 0 z] - [ 0 -1 z 1 0] - sage: M = LinearMatroid(reduced_matrix = A) + sage: Z = lift_cross_ratios(A, to_sixth_root_of_unity) # needs sage.rings.finite_rings sage.rings.number_field + sage: Z # needs sage.rings.finite_rings sage.rings.number_field + [ 1 0 1 1 1] + [-z + 1 1 0 0 1] + [ 0 -1 1 -z + 1 0] + sage: M = LinearMatroid(reduced_matrix=A) sage: sorted(M.cross_ratios()) [3, 5] - sage: N = LinearMatroid(reduced_matrix = Z) - sage: sorted(N.cross_ratios()) + sage: N = LinearMatroid(reduced_matrix=Z) # needs sage.rings.finite_rings sage.rings.number_field + sage: sorted(N.cross_ratios()) # needs sage.rings.finite_rings sage.rings.number_field [-z + 1, z] - sage: M.is_isomorphism(N, {e:e for e in M.groundset()}) + sage: M.is_isomorphism(N, {e:e for e in M.groundset()}) # needs sage.rings.finite_rings sage.rings.number_field True """ + from sage.graphs.graph import Graph + for s, t in lift_map.items(): source_ring = s.parent() target_ring = t.parent() @@ -565,26 +572,28 @@ def lift_cross_ratios(A, lift_map=None): G = Graph([((r, 0), (c, 1), (r, c)) for r, c in A.nonzero_positions()]) # write the entries of (a scaled version of) A as products of cross ratios of A - T = set() - for C in G.connected_components(): - T.update(G.subgraph(C).min_spanning_tree()) + T = Graph() + for C in G.connected_components_subgraphs(): + T.add_edges(C.min_spanning_tree()) # - fix a tree of the support graph G to units (= empty dict, product of 0 terms) - F = {entry[2]: dict() for entry in T} - W = set(G.edge_iterator()) - set(T) - H = G.subgraph(edges=T) + F = {entry: dict() for entry in T.edge_labels()} + W = set(G.edge_iterator()) - set(T.edge_iterator()) + H = G.subgraph(edges=T.edge_iterator()) while W: # - find an edge in W to process, closing a circuit in H which is induced in G edge = W.pop() path = H.shortest_path(edge[0], edge[1]) + path_s = set(path) retry = True while retry: retry = False for edge2 in W: - if edge2[0] in path and edge2[1] in path: + if edge2[0] in path_s and edge2[1] in path_s: W.add(edge) edge = edge2 W.remove(edge) path = H.shortest_path(edge[0], edge[1]) + path_s = set(path) retry = True break entry = edge[2] @@ -690,8 +699,8 @@ def lift_map(target): EXAMPLES:: sage: from sage.matroids.utilities import lift_map - sage: lm = lift_map('gm') - sage: for x in lm: + sage: lm = lift_map('gm') # needs sage.rings.finite_rings sage.rings.number_field + sage: for x in lm: # needs sage.rings.finite_rings sage.rings.number_field ....: if (x == 1) is not (lm[x] == 1): ....: print('not a proper lift map') ....: for y in lm: @@ -704,11 +713,15 @@ def lift_map(target): ....: print('not a proper lift map') """ + from sage.rings.finite_rings.finite_field_constructor import GF + if target == "reg": R = GF(3) return {R(1): ZZ(1)} if target == "sru": + from sage.rings.number_field.number_field import NumberField + R = GF(7) z = ZZ['z'].gen() S = NumberField(z * z - z + 1, 'z') @@ -720,6 +733,8 @@ def lift_map(target): return {R(1): QQ(1), R(-1): QQ(-1), R(2): QQ(2), R(6): QQ((1, 2))} if target == "gm": + from sage.rings.number_field.number_field import NumberField + R = GF(19) t = QQ['t'].gen() G = NumberField(t * t - t - 1, 't') @@ -740,7 +755,7 @@ def split_vertex(G, u, v=None, edges=None): INPUT: - - ``G`` -- A SageMath Graph. + - ``G`` -- A SageMath :class:`Graph`. - ``u`` -- A vertex in ``G``. - ``v`` -- (optional) The name of the new vertex after the splitting. If ``v`` is specified and already in the graph, it must be an isolated vertex. @@ -750,6 +765,7 @@ def split_vertex(G, u, v=None, edges=None): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.matroids.utilities import split_vertex sage: G = graphs.BullGraph() sage: split_vertex(G, u=1, v=55, edges=[(1, 3)]) diff --git a/src/sage/media/__init__.py b/src/sage/media/__init__.py deleted file mode 100644 index 8b3785e6874..00000000000 --- a/src/sage/media/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from sage.misc.superseded import deprecation -deprecation(12673, "the package sage.media is deprecated") diff --git a/src/sage/media/all.py b/src/sage/media/all.py deleted file mode 100644 index 986d735f2c2..00000000000 --- a/src/sage/media/all.py +++ /dev/null @@ -1 +0,0 @@ -from .wav import Wave as wave diff --git a/src/sage/media/channels.pyx b/src/sage/media/channels.pyx deleted file mode 100644 index d2832abf8ef..00000000000 --- a/src/sage/media/channels.pyx +++ /dev/null @@ -1,33 +0,0 @@ -"_separate_channels" - -def _separate_channels(_data, _width, _nchannels): - """ - Separates the channels. This is an internal helper method for - precomputing some data while initializing the wav object. - """ - cdef int nchannels = _nchannels - cdef int width = _width - cdef char* data = _data - cdef int n - cdef short int x - - cdef int l = len(_data) / (width) - - channel_data = [[] for i in xrange(nchannels)] - if width == 1: - # handle the one byte case - - for n in range(l): - channel_data[n % nchannels].append(ord(data[n])-127) - - elif width == 2: - a = 32768 - for n in range(l): - # compute the value as an integer - x = <int> (data[2*n]) + 256 * <int>(data[2*n + 1]) - #x -= 65536*(x > a) - channel_data[n % nchannels].append(x) - else: - raise NotImplementedError("greater than 16-bit wavs not supported") - - return channel_data diff --git a/src/sage/media/wav.py b/src/sage/media/wav.py deleted file mode 100644 index c847754f2e5..00000000000 --- a/src/sage/media/wav.py +++ /dev/null @@ -1,403 +0,0 @@ -r""" -Work with WAV files - -A WAV file is a header specifying format information, followed by a -sequence of bytes, representing the state of some audio signal over a -length of time. - -A WAV file may have any number of channels. Typically, they have 1 -(mono) or 2 (for stereo). The data of a WAV file is given as a -sequence of frames. A frame consists of samples. There is one sample -per channel, per frame. Every wav file has a sample width, or, the -number of bytes per sample. Typically this is either 1 or 2 bytes. - -The wav module supplies more convenient access to this data. In -particular, see the docstring for ``Wave.channel_data()``. - -The header contains information necessary for playing the WAV file, -including the number of frames per second, the number of bytes per -sample, and the number of channels in the file. - -AUTHORS: - -- Bobby Moretti and Gonzalo Tornaria (2007-07-01): First version -- William Stein (2007-07-03): add more -- Bobby Moretti (2007-07-03): add doctests - -This module (and all of ``sage.media``) is deprecated. - -EXAMPLES:: - - sage: import sage.media - doctest:warning... - DeprecationWarning: the package sage.media is deprecated - See https://github.com/sagemath/sage/issues/12673 for details. -""" - -import math -import os -import wave - -from sage.misc.lazy_import import lazy_import -lazy_import("sage.plot.plot", "list_plot") -from sage.structure.sage_object import SageObject -from sage.arith.srange import srange -from sage.misc.html import html -from sage.rings.real_double import RDF - - -class Wave(SageObject): - """ - A class wrapping a wave audio file. - - INPUT: - - You must call Wave() with either data = filename, where - filename is the name of a wave file, or with each of the - following options: - - - channels -- the number of channels in the wave file (1 for mono, 2 for - stereo, etc... - - width -- the number of bytes per sample - - framerate -- the number of frames per second - - nframes -- the number of frames in the data stream - - bytes -- a string object containing the bytes of the data stream - - Slicing: - - Slicing a Wave object returns a new wave object that has been - trimmed to the bytes that you have given it. - - Indexing: - - Getting the `n`-th item in a Wave object will give you the value - of the `n`-th frame. - """ - def __init__(self, data=None, **kwds): - if data is not None: - self._filename = data - self._name = os.path.split(data)[1] - wv = wave.open(data, "rb") - self._nchannels = wv.getnchannels() - self._width = wv.getsampwidth() - self._framerate = wv.getframerate() - self._nframes = wv.getnframes() - self._bytes = wv.readframes(self._nframes) - from .channels import _separate_channels - self._channel_data = _separate_channels(self._bytes, - self._width, - self._nchannels) - wv.close() - elif kwds: - try: - self._name = kwds['name'] - self._nchannels = kwds['nchannels'] - self._width = kwds['width'] - self._framerate = kwds['framerate'] - self._nframes = kwds['nframes'] - self._bytes = kwds['bytes'] - self._channel_data = kwds['channel_data'] - except KeyError as msg: - raise KeyError(msg + " invalid input to Wave initializer") - else: - raise ValueError("Must give a filename") - - - def save(self, filename='sage.wav'): - r""" - Save this wave file to disk, either as a Sage sobj or as a .wav file. - - INPUT: - - filename -- the path of the file to save. If filename ends - with 'wav', then save as a wave file, - otherwise, save a Sage object. - - If no input is given, save the file as 'sage.wav'. - """ - if not filename.endswith('.wav'): - SageObject.save(self, filename) - return - wv = wave.open(filename, 'wb') - wv.setnchannels(self._nchannels) - wv.setsampwidth(self._width) - wv.setframerate(self._framerate) - wv.setnframes(self._nframes) - wv.writeframes(self._bytes) - wv.close() - - def listen(self): - """ - Listen to (or download) this wave file. - - Creates a link to this wave file in the notebook. - """ - i = 0 - fname = 'sage%s.wav'%i - while os.path.exists(fname): - i += 1 - fname = 'sage%s.wav'%i - - self.save(fname) - return html('<a href="cell://%s">Click to listen to %s</a>'%(fname, self._name)) - - def channel_data(self, n): - """ - Get the data from a given channel. - - INPUT: - - n -- the channel number to get - - OUTPUT: - - A list of signed ints, each containing the value of a frame. - """ - return self._channel_data[n] - - def getnchannels(self): - """ - Return the number of channels in this wave object. - - OUTPUT: - - The number of channels in this wave file. - """ - return self._nchannels - - def getsampwidth(self): - """ - Return the number of bytes per sample in this wave object. - - OUTPUT: - - The number of bytes in each sample. - """ - return self._width - - def getframerate(self): - """ - Return the number of frames per second in this wave object. - - OUTPUT: - - The frame rate of this sound file. - """ - return self._framerate - - def getnframes(self): - """ - Return the total number of frames in this wave object. - - OUTPUT: - - The number of frames in this WAV. - """ - return self._nframes - - def readframes(self, n): - """ - Read out the raw data for the first `n` frames of this wave object. - - INPUT: - - n -- the number of frames to return - - OUTPUT: - - A list of bytes (in string form) representing the raw wav data. - """ - return self._bytes[:self._nframes * self._width] - - def getlength(self): - """ - Return the length of this file (in seconds). - - OUTPUT: - - The running time of the entire WAV object. - """ - return float(self._nframes) / (self._nchannels * float(self._framerate)) - - def _repr_(self): - nc = self.getnchannels() - return "Wave file %s with %s channel%s of length %s seconds%s" % \ - (self._name, nc, "" if nc == 1 else "s", self.getlength(), "" if nc == 1 else " each") - - def _normalize_npoints(self, npoints): - """ - Used internally while plotting to normalize the number of - """ - return npoints if npoints else self._nframes - - def domain(self, npoints=None): - """ - Used internally for plotting. Get the x-values for the various points to plot. - """ - npoints = self._normalize_npoints(npoints) - # figure out on what intervals to sample the data - seconds = float(self._nframes) / float(self._width) - frame_duration = seconds / (float(npoints) * float(self._framerate)) - - domain = [n * frame_duration for n in range(npoints)] - return domain - - def values(self, npoints=None, channel=0): - """ - Used internally for plotting. Get the y-values for the various points to plot. - """ - npoints = self._normalize_npoints(npoints) - - # now, how many of the frames do we sample? - frame_skip = int(self._nframes / npoints) - # the values of the function at each point in the domain - cd = self.channel_data(channel) - - # now scale the values - scale = float(1 << (8*self._width -1)) - values = [cd[frame_skip*i]/scale for i in range(npoints)] - return values - - def set_values(self, values, channel=0): - """ - Used internally for plotting. Get the y-values for the various points to plot. - """ - c = self.channel_data(channel) - npoints = len(c) - if len(values) != npoints: - raise ValueError("values (of length %s) must have length %s"%(len(values), npoints)) - - # unscale the values - scale = float(1 << (8*self._width -1)) - values = [float(abs(s)) * scale for s in values] - - # the values of the function at each point in the domain - c = self.channel_data(channel) - for i in range(npoints): - c[i] = values[i] - - def vector(self, npoints=None, channel=0): - npoints = self._normalize_npoints(npoints) - - V = RDF**npoints - return V(self.values(npoints=npoints, channel=channel)) - - def plot(self, npoints=None, channel=0, plotjoined=True, **kwds): - """ - Plots the audio data. - - INPUT: - - - npoints -- number of sample points to take; if not given, draws all - known points. - - channel -- 0 or 1 (if stereo). default: 0 - - plotjoined -- whether to just draw dots or draw lines between sample points - - OUTPUT: - - a plot object that can be shown. - """ - domain = self.domain(npoints=npoints) - values = self.values(npoints=npoints, channel=channel) - points = zip(domain, values) - - L = list_plot(points, plotjoined=plotjoined, **kwds) - L.xmin(0) - L.xmax(domain[-1]) - return L - - def plot_fft(self, npoints=None, channel=0, half=True, **kwds): - v = self.vector(npoints=npoints) - w = v.fft() - if half: - w = w[:len(w)//2] - z = [abs(x) for x in w] - if half: - r = math.pi - else: - r = 2*math.pi - data = zip(srange(0, r, r/len(z)), z) - L = list_plot(data, plotjoined=True, **kwds) - L.xmin(0) - L.xmax(r) - return L - - def plot_raw(self, npoints=None, channel=0, plotjoined=True, **kwds): - npoints = self._normalize_npoints(npoints) - seconds = float(self._nframes) / float(self._width) - sample_step = seconds / float(npoints) - domain = [float(n*sample_step) / float(self._framerate) for n in range(npoints)] - frame_skip = self._nframes / npoints - values = [self.channel_data(channel)[frame_skip*i] for i in range(npoints)] - points = zip(domain, values) - - return list_plot(points, plotjoined=plotjoined, **kwds) - - def __getitem__(self, i): - """ - Return the `i`-th frame of data in the wave, in the form of a string, - if `i` is an integer. - - Return a slice of self if `i` is a slice. - """ - if isinstance(i, slice): - start, stop, step = i.indices(self._nframes) - return self._copy(start, stop) - else: - n = i*self._width - return self._bytes[n:n+self._width] - - def slice_seconds(self, start, stop): - """ - Slice the wave from start to stop. - - INPUT: - - start -- the time index from which to begin the slice (in seconds) - stop -- the time index from which to end the slice (in seconds) - - OUTPUT: - - A Wave object whose data is this object's data, - sliced between the given time indices - """ - start = int(start*self.getframerate()) - stop = int(stop*self.getframerate()) - return self[start:stop] - - # start and stop are frame numbers - def _copy(self, start, stop): - start = start * self._width - stop = stop * self._width - channels_sliced = [self._channel_data[i][start:stop] for i in range(self._nchannels)] - print(stop - start) - - return Wave(nchannels=self._nchannels, - width=self._width, - framerate=self._framerate, - bytes=self._bytes[start:stop], - nframes=stop - start, - channel_data=channels_sliced, - name=self._name) - - def __copy__(self): - return self._copy(0, self._nframes) - - def convolve(self, right, channel=0): - """ - NOT DONE! - - Convolution of self and other, i.e., add their fft's, then - inverse fft back. - """ - if not isinstance(right, Wave): - raise TypeError("right must be a wave") - npoints = self._nframes - v = self.vector(npoints, channel=channel).fft() - w = right.vector(npoints, channel=channel).fft() - k = v + w - i = k.inv_fft() - conv = self.__copy__() - conv.set_values(list(i)) - conv._name = "convolution of %s and %s" % (self._name, right._name) - return conv diff --git a/src/sage/misc/abstract_method.py b/src/sage/misc/abstract_method.py index 720f7f5a7f0..7d8ca8edb4c 100644 --- a/src/sage/misc/abstract_method.py +++ b/src/sage/misc/abstract_method.py @@ -127,10 +127,10 @@ def abstract_method(f=None, optional=False): sage: abstract_method(optional = True) <function abstract_method.<locals>.<lambda> at ...> - sage: abstract_method(optional = True)(banner) - <optional abstract method banner at ...> - sage: abstract_method(banner, optional = True) - <optional abstract method banner at ...> + sage: abstract_method(optional = True)(version) + <optional abstract method version at ...> + sage: abstract_method(version, optional = True) + <optional abstract method version at ...> """ if f is None: return lambda f: AbstractMethod(f, optional=optional) @@ -173,11 +173,11 @@ def __repr__(self): """ EXAMPLES:: - sage: abstract_method(banner) - <abstract method banner at ...> + sage: abstract_method(version) + <abstract method version at ...> - sage: abstract_method(banner, optional = True) - <optional abstract method banner at ...> + sage: abstract_method(version, optional = True) + <optional abstract method version at ...> """ return "<" + ("optional " if self._optional else "") + "abstract method %s at %s>" % (self.__name__, hex(id(self._f))) @@ -188,12 +188,12 @@ def _sage_src_lines_(self): EXAMPLES:: sage: from sage.misc.sageinspect import sage_getsourcelines - sage: g = abstract_method(banner) + sage: g = abstract_method(version) sage: (src, lines) = sage_getsourcelines(g) sage: src[0] - 'def banner():\n' + 'def version():\n' sage: lines - 89 + 19 """ from sage.misc.sageinspect import sage_getsourcelines return sage_getsourcelines(self._f) diff --git a/src/sage/misc/all.py b/src/sage/misc/all.py index 8fea19524eb..e5a6418043a 100644 --- a/src/sage/misc/all.py +++ b/src/sage/misc/all.py @@ -6,10 +6,8 @@ from .all__sagemath_repl import * from .misc import (BackslashOperator, - cputime, - union, uniq, powerset, subsets, exists, forall, is_iterator, - random_sublist, walltime, + random_sublist, pad_zeros, SAGE_DB, newton_method_sizes, compose, @@ -17,9 +15,9 @@ lazy_import('sage.misc.misc', 'union', deprecation=32096) -from .banner import version, banner +from .banner import version -from .dev_tools import runsnake, import_statements +from .dev_tools import import_statements from .html import html, pretty_print_default @@ -27,7 +25,7 @@ from .sage_timeit_class import timeit -from .edit_module import edit, set_edit_template +from .edit_module import edit from .map_threaded import map_threaded @@ -35,18 +33,10 @@ from .remote_file import get_remote_file -from .profiler import Profiler - from .mrange import xmrange, mrange, xmrange_iter, mrange_iter, cartesian_product_iterator from .fpickle import pickle_function, unpickle_function -from .dist import install_scripts - -lazy_import('sage.misc.package', ('installed_packages', 'is_package_installed', - 'standard_packages', 'optional_packages', - 'experimental_packages', 'package_versions')) - lazy_import('sage.misc.pager', 'pager') lazy_import('sage.misc.sagedoc', ['browse_sage_doc', @@ -130,46 +120,25 @@ from .latex import LatexExpr, latex, view -from .trace import trace - from .randstate import seed, set_random_seed, initial_seed, current_randstate from .prandom import * +from .timing import walltime, cputime + from .explain_pickle import explain_pickle, unpickle_newobj, unpickle_global, unpickle_build, unpickle_instantiate, unpickle_persistent, unpickle_extension, unpickle_appends lazy_import('sage.misc.inline_fortran', 'fortran') - -########################################################################## -def benchmark(n=-1): - """ - Run a well-chosen range of Sage commands and record the time it - takes for each to run. - - INPUT: - - - ``n`` -- int (default: -1); the benchmark number. The default - of -1 runs all the benchmarks. - - OUTPUT: - - - ``list`` -- summary of timings for each benchmark - """ - import sage.misc.benchmark - return sage.misc.benchmark.benchmark(n) - - -class logstr(str): - def __repr__(self): - return self - - def _latex_(self): - # return "\\begin{verbatim}%s\\end{verbatim}"%self - if '#' not in self: - delim = '#' - elif '@' not in self: - delim = '@' - elif '~' not in self: - delim = '~' - return r"""\verb%s%s%s""" % (delim, self.replace('\n\n', '\n').replace('\n', '; '), delim) +lazy_import('sage.misc.banner', 'banner', deprecation=34259) +lazy_import('sage.misc.dev_tools', 'runsnake', deprecation=34259) +lazy_import('sage.misc.edit_module', 'set_edit_template', deprecation=34259) +lazy_import('sage.misc.profiler', 'Profiler', deprecation=34259) +lazy_import('sage.misc.dist', 'install_scripts', deprecation=34259) +lazy_import('sage.misc.trace', 'trace', deprecation=34259) +lazy_import('sage.misc.package', ('installed_packages', 'is_package_installed', + 'standard_packages', 'optional_packages', + 'experimental_packages', 'package_versions'), + deprecation=34259) +lazy_import('sage.misc.benchmark', 'benchmark', deprecation=34259) +lazy_import('sage.repl.interpreter', 'logstr', deprecation=34259) diff --git a/src/sage/misc/all__sagemath_objects.py b/src/sage/misc/all__sagemath_objects.py index 3090b5a8913..43a9c1c06d5 100644 --- a/src/sage/misc/all__sagemath_objects.py +++ b/src/sage/misc/all__sagemath_objects.py @@ -32,3 +32,5 @@ from .cachefunc import CachedFunction, cached_function, cached_method, cached_in_parent_method, disk_cached_function from .abstract_method import abstract_method + +from .timing import walltime, cputime diff --git a/src/sage/misc/banner.py b/src/sage/misc/banner.py index bae5db95d29..a428de42005 100644 --- a/src/sage/misc/banner.py +++ b/src/sage/misc/banner.py @@ -100,7 +100,7 @@ def banner(): EXAMPLES:: sage: import sage.misc.banner; sage.misc.banner.SAGE_BANNER = '' - sage: banner() + sage: sage.misc.banner.banner() โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ SageMath version ..., Release Date: ... โ”‚ โ”‚ Using Python .... Type "help()" for help. โ”‚ diff --git a/src/sage/misc/binary_tree.pyx b/src/sage/misc/binary_tree.pyx index 8827cac9ef2..b23c9ee7266 100644 --- a/src/sage/misc/binary_tree.pyx +++ b/src/sage/misc/binary_tree.pyx @@ -1,13 +1,12 @@ """ Binary trees -Implements a binary tree in Cython. +This implements a binary tree in Cython. AUTHORS: - Tom Boothby (2007-02-15). Initial version free for any use (public domain). """ - from cysignals.memory cimport sig_malloc, sig_free from cpython.ref cimport PyObject, Py_INCREF, Py_XDECREF @@ -63,7 +62,6 @@ cdef object binary_tree_get(binary_tree_node *self, int key): cdef object binary_tree_delete(binary_tree_node *self, int key): cdef object t - cdef binary_tree_node *cur if self.key > key: if self.left == NULL: return None @@ -130,14 +128,14 @@ cdef binary_tree_node *binary_tree_head_excise(binary_tree_node *self): if self.left == NULL: return self.right if right: - #move right branch to left, return left + # move right branch to left, return left cur = self.left while cur.right != NULL: cur = cur.right cur.right = self.right cur = self.left else: - #move left branch to right, return right + # move left branch to right, return right cur = self.right while cur.left != NULL: cur = cur.left @@ -187,6 +185,7 @@ cdef class BinaryTree: """ def __cinit__(BinaryTree self): self.head = NULL + def __dealloc__(BinaryTree self): """ TESTS: @@ -207,14 +206,17 @@ cdef class BinaryTree: ....: return [(k,v) for (k,v) in post.items() if v>10] sage: test() # indirect doctest [] - """ binary_tree_dealloc(self.head) - def insert(BinaryTree self, object key, object value = None): + def insert(BinaryTree self, object key, object value=None): """ - Inserts a key-value pair into the BinaryTree. Duplicate keys are ignored. - The first parameter, key, should be an int, or coercible (one-to-one) into an int. + Insert a key-value pair into the BinaryTree. + + Duplicate keys are ignored. + + The first parameter, key, should be an int, or coercible (one-to-one) + into an int. EXAMPLES:: @@ -235,9 +237,10 @@ cdef class BinaryTree: self.head = BinaryTreeNode(ckey, value) else: binary_tree_insert(self.head, ckey, value) + def delete(BinaryTree self, int key): """ - Removes a the node corresponding to key, and returns the value + Remove a the node corresponding to key, and return the value associated with it. EXAMPLES:: @@ -278,28 +281,28 @@ cdef class BinaryTree: return r else: return binary_tree_delete(self.head, key) + def get(BinaryTree self, int key): """ - Returns the value associated with the key given. + Return the value associated with the key given. EXAMPLES:: sage: from sage.misc.binary_tree import BinaryTree sage: t = BinaryTree() - sage: t.insert(0,Matrix([[0,0],[1,1]])) - sage: t.insert(0,1) - sage: t.get(0) + sage: t.insert(0, Matrix([[0,0], [1,1]])) # needs sage.modules + sage: t.insert(0, 1) + sage: t.get(0) # needs sage.modules [0 0] [1 1] """ if self.head == NULL: return None - else: - return binary_tree_get(self.head, key) + return binary_tree_get(self.head, key) + def contains(BinaryTree self, int key): """ - Returns True if a node with the given key exists - in the tree, and False otherwise. + Return whether a node with the given key exists in the tree. EXAMPLES:: @@ -313,14 +316,11 @@ cdef class BinaryTree: """ if self.head == NULL: return False - else: - if binary_tree_get(self.head, key) is not None: - return True - else: - return False + return binary_tree_get(self.head, key) is not None + def get_max(BinaryTree self): """ - Returns the value of the node with the maximal key value. + Return the value of the node with the maximal key value. """ cdef binary_tree_node *cur if self.head == NULL: @@ -329,9 +329,10 @@ cdef class BinaryTree: while cur.right != NULL: cur = cur.right return <object>cur.value + def get_min(BinaryTree self): """ - Returns the value of the node with the minimal key value. + Return the value of the node with the minimal key value. """ cdef binary_tree_node *cur if self.head == NULL: @@ -340,10 +341,11 @@ cdef class BinaryTree: while cur.left != NULL: cur = cur.left return <object>cur.value + def pop_max(BinaryTree self): """ - Returns the value of the node with the maximal key value, - and removes that node from the tree. + Return the value of the node with the maximal key value, + and remove that node from the tree. EXAMPLES:: @@ -380,10 +382,11 @@ cdef class BinaryTree: max = <object>cur.right.value cur.right = binary_tree_right_excise(cur.right) return max + def pop_min(BinaryTree self): """ - Returns the value of the node with the minimal key value, - and removes that node from the tree. + Return the value of the node with the minimal key value, + and remove that node from the tree. EXAMPLES:: @@ -423,7 +426,7 @@ cdef class BinaryTree: def is_empty(BinaryTree self): """ - Returns True if the tree has no nodes. + Return whether the tree has no nodes. EXAMPLES:: @@ -439,7 +442,9 @@ cdef class BinaryTree: def keys(BinaryTree self, order="inorder"): """ - Returns the keys sorted according to "order" parameter, which can be one of + Return the keys sorted according to "order" parameter. + + The order can be one of "inorder", "preorder", or "postorder" """ if self.head == NULL: @@ -456,7 +461,9 @@ cdef class BinaryTree: def values(BinaryTree self, order="inorder"): """ - Returns the keys sorted according to "order" parameter, which can be one of + Return the keys sorted according to "order" parameter. + + The order can be one of "inorder", "preorder", or "postorder" """ if self.head == NULL: @@ -474,13 +481,12 @@ cdef class BinaryTree: def _headkey_(BinaryTree self): """ Used by the stress tester. Don't think a user would care. + Email tom if you care what the headkey is. """ if self.head == NULL: return 0 - else: - return self.head.key - + return self.head.key class Test: @@ -489,11 +495,13 @@ class Test: def binary_tree(self, values = 100, cycles = 100000): """ - Performs a sequence of random operations, given random inputs - to stress test the binary tree structure. This was useful during - development to find memory leaks / segfaults. Cycles should be - at least 100 times as large as values, or the delete, contains, - and get methods won't hit very often. + Perform a sequence of random operations, given random inputs + to stress test the binary tree structure. + + This was useful during development to find memory leaks / + segfaults. Cycles should be at least 100 times as large as + values, or the delete, contains, and get methods won't hit + very often. INPUT: @@ -507,10 +515,10 @@ class Test: """ from sage.misc.prandom import randint t = BinaryTree() - for i in xrange(cycles): - r = randint(0,8) - s = randint(0,values) - if r==1: + for i in range(cycles): + r = randint(0, 8) + s = randint(0, values) + if r == 1: t.insert(s) elif r == 2: t.delete(t._headkey_()) diff --git a/src/sage/misc/bindable_class.py b/src/sage/misc/bindable_class.py index 92f57ef48cb..86d04bc8770 100644 --- a/src/sage/misc/bindable_class.py +++ b/src/sage/misc/bindable_class.py @@ -160,7 +160,7 @@ class BoundClass(functools.partial): sage: c = x.Inner; c <bound class 'sage.misc.bindable_class.Outer.Inner' of <sage.misc.bindable_class.Outer object at ...>> - Introspection works, at least partially: + Introspection works, at least partially:: sage: sage_getdoc(c).strip() 'Some documentation for Outer.Inner' @@ -175,7 +175,7 @@ class BoundClass(functools.partial): .. warning:: - Since ``c`` is not a class (as tested by inspect.isclass), + Since ``c`` is not a class (as tested by :func:`inspect.isclass`), and has a ``__call__`` method, IPython's introspection (with ``c?``) insists on showing not only its documentation but also its class documentation and call @@ -183,14 +183,14 @@ class BoundClass(functools.partial): if available. Until a better approach is found, we reset the documentation - of ``BoundClass`` below, and make an exception for + of :class:`BoundClass` below, and make an exception for :meth:`__init__` to the strict rule that every method should be doctested:: sage: c.__class__.__doc__ sage: c.__class__.__init__.__doc__ - Make sure classes which inherit from functools.partial have the correct + Make sure classes which inherit from :class:`functools.partial` have the correct syntax, see :trac:`14748`:: sage: import warnings @@ -201,7 +201,7 @@ class BoundClass(functools.partial): sage: g() 8 - The following has correct syntax and no ``DeprecationWarning``:: + The following has correct syntax and no :class:`DeprecationWarning`:: sage: class mynewpartial(functools.partial): ....: def __init__(self, f, i, j): diff --git a/src/sage/misc/c3_controlled.pyx b/src/sage/misc/c3_controlled.pyx index ebadb070d1d..442dda7264f 100644 --- a/src/sage/misc/c3_controlled.pyx +++ b/src/sage/misc/c3_controlled.pyx @@ -196,21 +196,23 @@ key. We consider the smallest poset describing a class hierarchy admitting no MRO whatsoever:: - sage: P = Poset({10: [9,8,7], 9:[6,1], 8:[5,2], 7:[4,3], 6: [3,2], 5:[3,1], 4: [2,1] }, linear_extension=True, facade=True) + sage: P = Poset({10: [9,8,7], 9: [6,1], 8: [5,2], 7: [4,3], # needs sage.graphs + ....: 6: [3,2], 5: [3,1], 4: [2,1]}, + ....: linear_extension=True, facade=True) And build a :class:`HierarchyElement` from it:: sage: from sage.misc.c3_controlled import HierarchyElement - sage: x = HierarchyElement(10, P) + sage: x = HierarchyElement(10, P) # needs sage.graphs Here are its bases:: - sage: HierarchyElement(10, P)._bases + sage: HierarchyElement(10, P)._bases # needs sage.graphs [9, 8, 7] Using the standard ``C3`` algorithm fails:: - sage: x.mro_standard + sage: x.mro_standard # needs sage.graphs Traceback (most recent call last): ... ValueError: Cannot merge the items 3, 3, 2. @@ -219,16 +221,18 @@ We also get a failure when we relabel `P` according to another linear extension. For easy relabelling, we first need to set an appropriate default linear extension for `P`:: - sage: linear_extension = list(reversed(IntegerRange(1,11))) - sage: P = P.with_linear_extension(linear_extension) - sage: list(P) + sage: linear_extension = list(reversed(IntegerRange(1, 11))) + sage: P = P.with_linear_extension(linear_extension) # needs sage.graphs + sage: list(P) # needs sage.graphs [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] Now we play with a specific linear extension of `P`:: + sage: # needs sage.graphs sage: Q = P.linear_extension([10, 9, 8, 7, 6, 5, 4, 1, 2, 3]).to_poset() sage: Q.cover_relations() - [[10, 9], [10, 8], [10, 7], [9, 6], [9, 3], [8, 5], [8, 2], [7, 4], [7, 1], [6, 2], [6, 1], [5, 3], [5, 1], [4, 3], [4, 2]] + [[10, 9], [10, 8], [10, 7], [9, 6], [9, 3], [8, 5], [8, 2], [7, 4], + [7, 1], [6, 2], [6, 1], [5, 3], [5, 1], [4, 3], [4, 2]] sage: x = HierarchyElement(10, Q) sage: x.mro_standard Traceback (most recent call last): @@ -238,43 +242,43 @@ Now we play with a specific linear extension of `P`:: On the other hand, both the instrumented ``C3`` algorithm, and the controlled ``C3`` algorithm give the desired MRO:: - sage: x.mro + sage: x.mro # needs sage.graphs [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - sage: x.mro_controlled + sage: x.mro_controlled # needs sage.graphs [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] The above checks, and more, can be run with:: - sage: x._test_mro() + sage: x._test_mro() # needs sage.graphs In practice, the control was achieved by adding the following bases:: - sage: x._bases + sage: x._bases # needs sage.graphs [9, 8, 7] - sage: x._bases_controlled + sage: x._bases_controlled # needs sage.graphs [9, 8, 7, 6, 5] Altogether, four bases were added for control:: - sage: sum(len(HierarchyElement(q, Q)._bases) for q in Q) + sage: sum(len(HierarchyElement(q, Q)._bases) for q in Q) # needs sage.graphs 15 - sage: sum(len(HierarchyElement(q, Q)._bases_controlled) for q in Q) + sage: sum(len(HierarchyElement(q, Q)._bases_controlled) for q in Q) # needs sage.graphs 19 This information can also be recovered with:: - sage: x.all_bases_len() + sage: x.all_bases_len() # needs sage.graphs 15 - sage: x.all_bases_controlled_len() + sage: x.all_bases_controlled_len() # needs sage.graphs 19 We now check that the ``C3`` algorithm fails for all linear extensions `l` of this poset, whereas both the instrumented and controlled ``C3`` algorithms succeed; along the way, we collect some statistics:: - sage: L = P.linear_extensions() + sage: L = P.linear_extensions() # needs sage.graphs sage: stats = [] - sage: for l in L: + sage: for l in L: # needs sage.graphs sage.modules ....: x = HierarchyElement(10, l.to_poset()) ....: try: # Check that x.mro_standard always fails with a ValueError ....: x.mro_standard @@ -291,7 +295,7 @@ Depending on the linear extension `l` it was necessary to add between one and five bases for control; for example, `216` linear extensions required the addition of four bases:: - sage: sorted(Word(stats).evaluation_sparse()) + sage: sorted(Word(stats).evaluation_sparse()) # needs sage.graphs sage.modules [(1, 36), (2, 108), (3, 180), (4, 216), (5, 180)] We now consider a hierarchy of categories:: @@ -336,7 +340,7 @@ list below does not change radically, it's fine to just update this doctest:: sage: from sage.categories.category import category_sample - sage: sorted([C for C in category_sample() + sage: sorted([C for C in category_sample() # needs sage.combinat sage.graphs sage.modules sage.rings.number_field ....: if len(C._super_categories_for_classes) != len(C.super_categories())], ....: key=str) [Category of affine weyl groups, @@ -488,6 +492,7 @@ cdef class CmpKey: True """ cdef int count + def __init__(self): """ Sets the internal category counter to zero. @@ -951,6 +956,7 @@ cpdef tuple C3_sorted_merge(list lists, key=identity): #assert C3_merge(lists[:-1]+[suggestion_list]) == out return (out, suggestion_list) + class HierarchyElement(object, metaclass=ClasscallMetaclass): """ A class for elements in a hierarchy. @@ -988,7 +994,7 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): :class:`HopfAlgebrasWithBasis`:: sage: from sage.misc.c3_controlled import HierarchyElement - sage: G = DiGraph({ + sage: G = DiGraph({ # needs sage.graphs ....: 44 : [43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], ....: 43 : [42, 41, 40, 36, 35, 39, 38, 37, 33, 32, 31, 30, 29, 28, 27, 26, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], ....: 42 : [36, 35, 37, 30, 29, 28, 27, 26, 15, 14, 12, 11, 9, 8, 5, 3, 2, 1, 0], @@ -1036,6 +1042,7 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): ....: 0 : [], ....: }) + sage: # needs sage.combinat sage.graphs sage: x = HierarchyElement(44, G) sage: x.mro [44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] @@ -1049,8 +1056,9 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): """ EXAMPLES:: + sage: # needs sage.combinat sage.graphs sage: from sage.misc.c3_controlled import HierarchyElement - sage: P = Poset((divisors(30), lambda x,y: y.divides(x)), facade=True) + sage: P = Poset((divisors(30), lambda x, y: y.divides(x)), facade=True) sage: x = HierarchyElement(10, P) sage: x 10 @@ -1060,29 +1068,42 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): [10, 5, 2, 1] """ from sage.categories.sets_cat import Sets - from sage.combinat.posets.poset_examples import Posets - from sage.graphs.digraph import DiGraph - if succ in Posets(): - assert succ in Sets().Facade() - succ = succ.upper_covers - if isinstance(succ, DiGraph): - succ = succ.copy() - succ._immutable = True - succ = succ.neighbors_out + + try: + from sage.combinat.posets.poset_examples import Posets + except ImportError: + pass + else: + if succ in Posets(): + assert succ in Sets().Facade() + succ = succ.upper_covers + + try: + from sage.graphs.digraph import DiGraph + except ImportError: + pass + else: + if isinstance(succ, DiGraph): + succ = succ.copy() + succ._immutable = True + succ = succ.neighbors_out + if key is None: key = identity @cached_function def f(x): return typecall(cls, x, [f(y) for y in succ(x)], key, f) + return f(value) def __init__(self, value, bases, key, from_value): """ EXAMPLES:: + sage: # needs sage.graphs sage: from sage.misc.c3_controlled import HierarchyElement - sage: P = Poset((divisors(30), lambda x,y: y.divides(x)), facade=True) + sage: P = Poset((divisors(30), lambda x, y: y.divides(x)), facade=True) sage: x = HierarchyElement(10, P) sage: x 10 @@ -1098,9 +1119,9 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): The ``_from_value`` attribute is a function that can be used to reconstruct an element of the hierarchy from its value:: - sage: x._from_value + sage: x._from_value # needs sage.graphs Cached version of <cyfunction HierarchyElement.__classcall__.<locals>.f at ...> - sage: x._from_value(x.value) is x + sage: x._from_value(x.value) is x # needs sage.graphs True """ self.value = value @@ -1115,9 +1136,9 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): EXAMPLES:: sage: from sage.misc.c3_controlled import HierarchyElement - sage: P = Poset((divisors(30), lambda x,y: y.divides(x)), facade=True) - sage: x = HierarchyElement(10, P) - sage: x + sage: P = Poset((divisors(30), lambda x, y: y.divides(x)), facade=True) # needs sage.graphs + sage: x = HierarchyElement(10, P) # needs sage.graphs + sage: x # needs sage.graphs 10 """ return repr(self.value) @@ -1133,8 +1154,9 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): EXAMPLES:: + sage: # needs sage.combinat sage.graphs sage: from sage.misc.c3_controlled import HierarchyElement - sage: P = Poset((divisors(30), lambda x,y: y.divides(x)), facade=True) + sage: P = Poset((divisors(30), lambda x, y: y.divides(x)), facade=True) sage: x = HierarchyElement(10, P) sage: x.bases [5, 2] @@ -1154,8 +1176,9 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.misc.c3_controlled import HierarchyElement, C3_sorted_merge, identity - sage: P = Poset({7: [5,6], 5:[1,2], 6: [3,4]}, facade = True) + sage: P = Poset({7: [5, 6], 5: [1, 2], 6: [3, 4]}, facade=True) sage: x = HierarchyElement(5, P) sage: x.mro [5, 2, 1] @@ -1166,12 +1189,12 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): sage: x.mro [7, 6, 5, 4, 3, 2, 1] - sage: C3_sorted_merge([[6, 4, 3], [5, 2, 1], [6, 5]], identity) + sage: C3_sorted_merge([[6, 4, 3], [5, 2, 1], [6, 5]], identity) # needs sage.graphs ([6, 5, 4, 3, 2, 1], [6, 5, 4]) TESTS:: - sage: assert all(isinstance(v, Integer) for v in x.mro) + sage: assert all(isinstance(v, Integer) for v in x.mro) # needs sage.graphs """ bases = self._bases result, suggestion = C3_sorted_merge([base.mro for base in bases]+[[base.value for base in bases]], key=self._key) @@ -1190,8 +1213,9 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.misc.c3_controlled import HierarchyElement - sage: P = Poset({7: [5,6], 5:[1,2], 6: [3,4]}, facade = True) + sage: P = Poset({7: [5, 6], 5: [1, 2], 6: [3, 4]}, facade=True) sage: x = HierarchyElement(7, P) sage: x._bases [6, 5] @@ -1209,7 +1233,9 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): EXAMPLES:: sage: from sage.misc.c3_controlled import HierarchyElement, C3_merge - sage: P = Poset({7: [5,6], 5:[1,2], 6: [3,4]}, facade=True) + + sage: # needs sage.graphs + sage: P = Poset({7: [5, 6], 5: [1, 2], 6: [3, 4]}, facade=True) sage: x = HierarchyElement(5, P) sage: x.mro_standard [5, 2, 1] @@ -1219,12 +1245,13 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): sage: x = HierarchyElement(7, P) sage: x.mro_standard [7, 6, 4, 3, 5, 2, 1] + sage: C3_merge([[6, 4, 3], [5, 2, 1], [6, 5]]) [6, 4, 3, 5, 2, 1] TESTS:: - sage: assert all(isinstance(v, Integer) for v in x.mro_standard) + sage: assert all(isinstance(v, Integer) for v in x.mro_standard) # needs sage.graphs """ bases = self._bases return [self.value] + C3_merge([base.mro_standard for base in bases]+[[base.value for base in bases]]) @@ -1238,7 +1265,9 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): EXAMPLES:: sage: from sage.misc.c3_controlled import HierarchyElement, C3_merge - sage: P = Poset({7: [5,6], 5:[1,2], 6: [3,4]}, facade=True) + + sage: # needs sage.graphs + sage: P = Poset({7: [5, 6], 5: [1, 2], 6: [3, 4]}, facade=True) sage: x = HierarchyElement(5, P) sage: x.mro_controlled [5, 2, 1] @@ -1252,6 +1281,7 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): [6, 5] sage: x._bases_controlled [6, 5, 4] + sage: C3_merge([[6, 4, 3], [5, 2, 1], [6, 5]]) [6, 4, 3, 5, 2, 1] sage: C3_merge([[6, 4, 3], [5, 2, 1], [6, 5, 4]]) @@ -1259,14 +1289,14 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): TESTS:: - sage: assert all(isinstance(v, Integer) for v in x.mro_controlled) + sage: assert all(isinstance(v, Integer) for v in x.mro_controlled) # needs sage.graphs """ return [self.value] + C3_merge([base.mro_controlled for base in self._bases]+[self._bases_controlled]) @cached_method def _test_mro(self): r""" - Runs consistency tests. + Run consistency tests. This checks in particular that the instrumented ``C3`` and controlled ``C3`` algorithms give, as desired, the @@ -1281,9 +1311,9 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): EXAMPLES:: sage: from sage.misc.c3_controlled import HierarchyElement - sage: P = Poset({7: [5,6], 5:[1,2], 6: [3,4]}, facade=True) - sage: x = HierarchyElement(7, P) - sage: x._test_mro() + sage: P = Poset({7: [5, 6], 5: [1, 2], 6: [3, 4]}, facade=True) # needs sage.graphs + sage: x = HierarchyElement(7, P) # needs sage.graphs + sage: x._test_mro() # needs sage.graphs """ for b in self._bases: b._test_mro() @@ -1305,8 +1335,9 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.misc.c3_controlled import HierarchyElement - sage: P = Poset((divisors(30), lambda x,y: y.divides(x)), facade=True) + sage: P = Poset((divisors(30), lambda x, y: y.divides(x)), facade=True) sage: x = HierarchyElement(1, P) sage: x.cls <class '1.cls'> @@ -1332,8 +1363,9 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.misc.c3_controlled import HierarchyElement - sage: P = Poset((divisors(30), lambda x,y: y.divides(x)), facade=True) + sage: P = Poset((divisors(30), lambda x, y: y.divides(x)), facade=True) sage: HierarchyElement(1, P).all_bases() {1} sage: HierarchyElement(10, P).all_bases() # random output @@ -1350,8 +1382,8 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): EXAMPLES:: sage: from sage.misc.c3_controlled import HierarchyElement - sage: P = Poset((divisors(30), lambda x,y: y.divides(x)), facade=True) - sage: HierarchyElement(30, P).all_bases_len() + sage: P = Poset((divisors(30), lambda x, y: y.divides(x)), facade=True) # needs sage.graphs + sage: HierarchyElement(30, P).all_bases_len() # needs sage.graphs 12 """ return sum( len(x._bases) for x in self.all_bases()) @@ -1363,8 +1395,8 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): EXAMPLES:: sage: from sage.misc.c3_controlled import HierarchyElement - sage: P = Poset((divisors(30), lambda x,y: y.divides(x)), facade=True) - sage: HierarchyElement(30, P).all_bases_controlled_len() + sage: P = Poset((divisors(30), lambda x, y: y.divides(x)), facade=True) # needs sage.graphs + sage: HierarchyElement(30, P).all_bases_controlled_len() # needs sage.graphs 13 """ return sum( len(x._bases_controlled) for x in self.all_bases()) diff --git a/src/sage/misc/cachefunc.pxd b/src/sage/misc/cachefunc.pxd index d3cc677dece..8e5d9dfa42a 100644 --- a/src/sage/misc/cachefunc.pxd +++ b/src/sage/misc/cachefunc.pxd @@ -5,7 +5,7 @@ cpdef cache_key(o) cdef class CachedFunction(): cdef public str __name__ - cdef public str __module__ + cdef public str __cached_module__ cdef ArgumentFixer _argument_fixer cdef public f cdef public cache # not always of type <dict> @@ -20,7 +20,7 @@ cdef class CachedFunction(): cdef class CachedMethod(): cdef str _cache_name cdef public str __name__ - cdef public str __module__ + cdef public str __cached_module__ cdef CachedFunction _cachedfunc cdef Py_ssize_t nargs cpdef _get_instance_cache(self, inst) diff --git a/src/sage/misc/cachefunc.pyx b/src/sage/misc/cachefunc.pyx index 8ac07e65f49..2b1d38c12b9 100644 --- a/src/sage/misc/cachefunc.pyx +++ b/src/sage/misc/cachefunc.pyx @@ -46,26 +46,28 @@ the name that the wrapped method or function should have, since otherwise the name of the original function would be used:: - sage: cython('''cpdef test_funct(x): return -x''') # optional - sage.misc.cython - sage: wrapped_funct = cached_function(test_funct, name='wrapped_funct') # optional - sage.misc.cython - sage: wrapped_funct # optional - sage.misc.cython - Cached version of <built-in function test_funct> - sage: wrapped_funct.__name__ # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython('''cpdef test_funct(x): return -x''') + sage: wrapped_funct = cached_function(test_funct, name='wrapped_funct') + sage: wrapped_funct + Cached version of <cyfunction test_funct at ...> + sage: wrapped_funct.__name__ 'wrapped_funct' - sage: wrapped_funct(5) # optional - sage.misc.cython + sage: wrapped_funct(5) -5 - sage: wrapped_funct(5) is wrapped_funct(5) # optional - sage.misc.cython + sage: wrapped_funct(5) is wrapped_funct(5) True We can proceed similarly for cached methods of Cython classes, provided that they allow attribute assignment or have a public -attribute ``__cached_methods`` of type ``<dict>``. Since +attribute ``_cached_methods`` of type ``<dict>``. Since :trac:`11115`, this is the case for all classes inheriting from :class:`~sage.structure.parent.Parent`. See below for a more explicit example. By :trac:`12951`, cached methods of extension classes can be defined by simply using the decorator. However, an indirect approach is still needed for cpdef methods:: + sage: # needs sage.misc.cython sage: cython_code = ['cpdef test_meth(self,x):', ....: ' "some doc for a wrapped cython method"', ....: ' return -x', @@ -77,21 +79,21 @@ approach is still needed for cpdef methods:: ....: ' "Some doc for direct method"', ....: ' return 2*x', ....: ' wrapped_method = cached_method(test_meth,name="wrapped_method")'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython - sage: O = MyClass() # optional - sage.misc.cython - sage: O.direct_method # optional - sage.misc.cython - Cached version of <method 'direct_method' of '...MyClass' objects> - sage: O.wrapped_method # optional - sage.misc.cython - Cached version of <built-in function test_meth> - sage: O.wrapped_method.__name__ # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) + sage: O = MyClass() + sage: O.direct_method + Cached version of <cyfunction MyClass.direct_method at ...> + sage: O.wrapped_method + Cached version of <cyfunction test_meth at ...> + sage: O.wrapped_method.__name__ 'wrapped_method' - sage: O.wrapped_method(5) # optional - sage.misc.cython + sage: O.wrapped_method(5) -5 - sage: O.wrapped_method(5) is O.wrapped_method(5) # optional - sage.misc.cython + sage: O.wrapped_method(5) is O.wrapped_method(5) True - sage: O.direct_method(5) # optional - sage.misc.cython + sage: O.direct_method(5) 10 - sage: O.direct_method(5) is O.direct_method(5) # optional - sage.misc.cython + sage: O.direct_method(5) is O.direct_method(5) True In some cases, one would only want to keep the result in cache as long @@ -107,9 +109,9 @@ By :trac:`11115`, even if a parent does not allow attribute assignment, it can inherit a cached method from the parent class of a category (previously, the cache would have been broken):: - sage: cython_code = ["from sage.misc.cachefunc import cached_method", + sage: cython_code = ["from sage.misc.cachefunc import cached_method", ....: "from sage.misc.cachefunc import cached_in_parent_method", - ....: "from sage.categories.category import Category", + ....: "from sage.categories.category import Category", ....: "from sage.categories.objects import Objects", ....: "class MyCategory(Category):", ....: " @cached_method", @@ -129,8 +131,8 @@ category (previously, the cache would have been broken):: ....: " @cached_method", ....: " def invert(self, x):", ....: " return -x"] - sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython - sage: C = MyCategory() # optional - sage.misc.cython + sage: cython('\n'.join(cython_code)) # needs sage.misc.cython + sage: C = MyCategory() # needs sage.misc.cython In order to keep the memory footprint of elements small, it was decided to not support the same freedom of using cached methods @@ -147,6 +149,7 @@ cached methods. We remark, however, that cached methods are hardly by used. :: + sage: # needs sage.misc.cython sage: cython_code = ["from sage.structure.element cimport Element, ElementWithCachedMethod", "from cpython.object cimport PyObject_RichCompare", ....: "cdef class MyBrokenElement(Element):", ....: " cdef public object x", @@ -181,88 +184,93 @@ hardly by used. ....: "from sage.structure.parent cimport Parent", ....: "cdef class MyParent(Parent):", ....: " Element = MyElement"] - sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython - sage: P = MyParent(category=C) # optional - sage.misc.cython - sage: ebroken = MyBrokenElement(P, 5) # optional - sage.misc.cython - sage: e = MyElement(P, 5) # optional - sage.misc.cython + sage: cython('\n'.join(cython_code)) + sage: P = MyParent(category=C) + sage: ebroken = MyBrokenElement(P, 5) + sage: e = MyElement(P, 5) The cached methods inherited by the parent works:: - sage: P.one() # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: P.one() <1> - sage: P.one() is P.one() # optional - sage.misc.cython + sage: P.one() is P.one() True - sage: P.invert(e) # optional - sage.misc.cython + sage: P.invert(e) <-5> - sage: P.invert(e) is P.invert(e) # optional - sage.misc.cython + sage: P.invert(e) is P.invert(e) True The cached methods inherited by ``MyElement`` works:: - sage: e.element_cache_test() # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: e.element_cache_test() <-5> - sage: e.element_cache_test() is e.element_cache_test() # optional - sage.misc.cython + sage: e.element_cache_test() is e.element_cache_test() True - sage: e.element_via_parent_test() # optional - sage.misc.cython + sage: e.element_via_parent_test() <-5> - sage: e.element_via_parent_test() is e.element_via_parent_test() # optional - sage.misc.cython + sage: e.element_via_parent_test() is e.element_via_parent_test() True The other element class can only inherit a ``cached_in_parent_method``, since the cache is stored in the parent. In fact, equal elements share the cache, even if they are of different types:: - sage: e == ebroken # optional - sage.misc.cython + sage: e == ebroken # needs sage.misc.cython True - sage: type(e) == type(ebroken) # optional - sage.misc.cython + sage: type(e) == type(ebroken) # needs sage.misc.cython False - sage: ebroken.element_via_parent_test() is e.element_via_parent_test() # optional - sage.misc.cython + sage: ebroken.element_via_parent_test() is e.element_via_parent_test() # needs sage.misc.cython True However, the cache of the other inherited method breaks, although the method as such works:: - sage: ebroken.element_cache_test() # optional - sage.misc.cython + sage: ebroken.element_cache_test() # needs sage.misc.cython <-5> - sage: ebroken.element_cache_test() is ebroken.element_cache_test() # optional - sage.misc.cython + sage: ebroken.element_cache_test() is ebroken.element_cache_test() # needs sage.misc.cython False The cache can be emptied:: - sage: a = test_pfunc(5) # optional - sage.misc.cython - sage: test_pfunc.clear_cache() # optional - sage.misc.cython - sage: a is test_pfunc(5) # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: a = test_pfunc(5) + sage: test_pfunc.clear_cache() + sage: a is test_pfunc(5) False - sage: a = P.one() # optional - sage.misc.cython - sage: P.one.clear_cache() # optional - sage.misc.cython - sage: a is P.one() # optional - sage.misc.cython + sage: a = P.one() + sage: P.one.clear_cache() + sage: a is P.one() False Since ``e`` and ``ebroken`` share the cache, when we empty it for one element it is empty for the other as well:: - sage: b = ebroken.element_via_parent_test() # optional - sage.misc.cython - sage: e.element_via_parent_test.clear_cache() # optional - sage.misc.cython - sage: b is ebroken.element_via_parent_test() # optional - sage.misc.cython + sage: b = ebroken.element_via_parent_test() # needs sage.misc.cython + sage: e.element_via_parent_test.clear_cache() # needs sage.misc.cython + sage: b is ebroken.element_via_parent_test() # needs sage.misc.cython False Introspection works:: + sage: # needs sage.misc.cython sage: from sage.misc.edit_module import file_and_line sage: from sage.misc.sageinspect import sage_getdoc, sage_getfile, sage_getsource - sage: print(sage_getdoc(test_pfunc)) # optional - sage.misc.cython + sage: print(sage_getdoc(test_pfunc)) Some documentation - sage: print(sage_getdoc(O.wrapped_method)) # optional - sage.misc.cython + sage: print(sage_getdoc(O.wrapped_method)) some doc for a wrapped cython method <BLANKLINE> - sage: print(sage_getdoc(O.direct_method)) # optional - sage.misc.cython + sage: print(sage_getdoc(O.direct_method)) Some doc for direct method <BLANKLINE> - sage: print(sage_getsource(O.wrapped_method)) # optional - sage.misc.cython + sage: print(sage_getsource(O.wrapped_method)) cpdef test_meth(self,x): "some doc for a wrapped cython method" return -x - sage: print(sage_getsource(O.direct_method)) # optional - sage.misc.cython + sage: print(sage_getsource(O.direct_method)) + @cached_method def direct_method(self, x): "Some doc for direct method" return 2*x @@ -278,14 +286,14 @@ ought to be chosen. A typical example is (several arguments):: sage: P.<a,b,c,d> = QQ[] - sage: I = P*[a,b] + sage: I = P * [a, b] sage: I.gens() [a, b] sage: I.gens() is I.gens() True - sage: I.groebner_basis() + sage: I.groebner_basis() # needs sage.libs.singular [a, b] - sage: I.groebner_basis() is I.groebner_basis() + sage: I.groebner_basis() is I.groebner_basis() # needs sage.libs.singular True sage: type(I.gens) <class 'sage.misc.cachefunc.CachedMethodCallerNoArgs'> @@ -294,21 +302,22 @@ ought to be chosen. A typical example is By :trac:`12951`, the cached_method decorator is also supported on non-c(p)def methods of extension classes, as long as they either support attribute assignment -or have a public attribute of type ``<dict>`` called ``__cached_methods``. The +or have a public attribute of type ``<dict>`` called ``_cached_methods``. The latter is easy:: + sage: # needs sage.misc.cython sage: cython_code = [ ....: "from sage.misc.cachefunc import cached_method", ....: "cdef class MyClass:", - ....: " cdef public dict __cached_methods", + ....: " cdef public dict _cached_methods", ....: " @cached_method", ....: " def f(self, a,b):", ....: " return a*b"] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython - sage: P = MyClass() # optional - sage.misc.cython - sage: P.f(2, 3) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) + sage: P = MyClass() + sage: P.f(2, 3) 6 - sage: P.f(2, 3) is P.f(2, 3) # optional - sage.misc.cython + sage: P.f(2, 3) is P.f(2, 3) True Providing attribute access is a bit more tricky, since it is needed that @@ -316,6 +325,7 @@ an attribute inherited by the instance from its class can be overridden on the instance. That is why providing a ``__getattr__`` would not be enough in the following example:: + sage: # needs sage.misc.cython sage: cython_code = [ ....: "from sage.misc.cachefunc import cached_method", ....: "cdef class MyOtherClass:", @@ -333,19 +343,19 @@ enough in the following example:: ....: " @cached_method", ....: " def f(self, a,b):", ....: " return a+b"] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython - sage: Q = MyOtherClass() # optional - sage.misc.cython - sage: Q.f(2, 3) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) + sage: Q = MyOtherClass() + sage: Q.f(2, 3) 5 - sage: Q.f(2, 3) is Q.f(2, 3) # optional - sage.misc.cython + sage: Q.f(2, 3) is Q.f(2, 3) True Note that supporting attribute access is somehow faster than the easier method:: - sage: timeit("a = P.f(2,3)") # random # optional - sage.misc.cython + sage: timeit("a = P.f(2,3)") # random # needs sage.misc.cython 625 loops, best of 3: 1.3 ยตs per loop - sage: timeit("a = Q.f(2,3)") # random # optional - sage.misc.cython + sage: timeit("a = Q.f(2,3)") # random # needs sage.misc.cython 625 loops, best of 3: 931 ns per loop Some immutable objects (such as `p`-adic numbers) cannot implement a @@ -353,18 +363,19 @@ reasonable hash function because their ``==`` operator has been modified to return ``True`` for objects which might behave differently in some computations:: - sage: K.<a> = Qq(9) # optional - sage.rings.padics - sage: b = a.add_bigoh(1) # optional - sage.rings.padics - sage: c = a + 3 # optional - sage.rings.padics - sage: b # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K.<a> = Qq(9) + sage: b = a.add_bigoh(1) + sage: c = a + 3 + sage: b a + O(3) - sage: c # optional - sage.rings.padics + sage: c a + 3 + O(3^20) - sage: b == c # optional - sage.rings.padics + sage: b == c True - sage: b == a # optional - sage.rings.padics + sage: b == a True - sage: c == a # optional - sage.rings.padics + sage: c == a False If such objects defined a non-trivial hash function, this would break @@ -372,20 +383,21 @@ caching in many places. However, such objects should still be usable in caches. This can be achieved by defining an appropriate method ``_cache_key``:: - sage: hash(b) # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: hash(b) Traceback (most recent call last): ... TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement' + sage: from sage.misc.cachefunc import cached_method sage: @cached_method ....: def f(x): return x == a - sage: f(b) # optional - sage.rings.padics + sage: f(b) True - sage: f(c) # if b and c were hashable, this would return True # optional - sage.rings.padics + sage: f(c) # if b and c were hashable, this would return True False - - sage: b._cache_key() # optional - sage.rings.padics + sage: b._cache_key() (..., ((0, 1),), 0, 1) - sage: c._cache_key() # optional - sage.rings.padics + sage: c._cache_key() (..., ((0, 1), (1,)), 0, 20) .. NOTE:: @@ -398,9 +410,9 @@ if ``a != b``, then also ``a._cache_key() != b._cache_key()``. In practice this means that the ``_cache_key`` should always include the parent as its first argument:: - sage: S.<a> = Qq(4) # optional - sage.rings.padics - sage: d = a.add_bigoh(1) # optional - sage.rings.padics - sage: b._cache_key() == d._cache_key() # this would be True if the parents were not included # optional - sage.rings.padics + sage: S.<a> = Qq(4) # needs sage.rings.padics + sage: d = a.add_bigoh(1) # needs sage.rings.padics + sage: b._cache_key() == d._cache_key() # this would be True if the parents were not included False """ @@ -460,9 +472,9 @@ def _cached_function_unpickle(module, name, cache=None): TESTS:: - sage: type(hilbert_class_polynomial) + sage: type(hilbert_class_polynomial) # needs sage.schemes <class 'sage.misc.cachefunc.CachedFunction'> - sage: loads(dumps(hilbert_class_polynomial)) is hilbert_class_polynomial #indirect doctest + sage: loads(dumps(hilbert_class_polynomial)) is hilbert_class_polynomial #indirect doctest # needs sage.schemes True Verify that the ``cache`` parameter works:: @@ -537,8 +549,8 @@ cpdef inline dict_key(o): sage: from sage.misc.cachefunc import dict_key sage: dict_key(42) 42 - sage: K.<u> = Qq(9) # optional - sage.rings.padics - sage: dict_key(u) # optional - sage.rings.padics + sage: K.<u> = Qq(9) # needs sage.rings.padics + sage: dict_key(u) # needs sage.rings.padics (<object object at ...>, (..., 20)) """ try: @@ -561,24 +573,24 @@ cpdef inline cache_key(o): EXAMPLES:: sage: from sage.misc.cachefunc import cache_key - sage: K.<u> = Qq(9) # optional - sage.rings.padics - sage: a = K(1); a # optional - sage.rings.padics + sage: K.<u> = Qq(9) # needs sage.rings.padics + sage: a = K(1); a # needs sage.rings.padics 1 + O(3^20) - sage: cache_key(a) # optional - sage.rings.padics + sage: cache_key(a) # needs sage.rings.padics (..., ((1,),), 0, 20) This function works if ``o`` is a tuple. In this case it unpacks its entries recursively:: - sage: o = (1, 2, (3, a)) # optional - sage.rings.padics - sage: cache_key(o) # optional - sage.rings.padics + sage: o = (1, 2, (3, a)) # needs sage.rings.padics + sage: cache_key(o) # needs sage.rings.padics (1, 2, (3, (..., ((1,),), 0, 20))) Note that tuples are only partially unpacked if some of its entries are hashable:: - sage: o = (1/2, a) # optional - sage.rings.padics - sage: cache_key(o) # optional - sage.rings.padics + sage: o = (1/2, a) # needs sage.rings.padics + sage: cache_key(o) # needs sage.rings.padics (1/2, (..., ((1,),), 0, 20)) """ try: @@ -688,15 +700,17 @@ cdef class CachedFunction(): TESTS:: + sage: # needs sage.combinat sage: g = CachedFunction(number_of_partitions) sage: g.__name__ 'number_of_partitions' sage: 'partitions' in sage.misc.sageinspect.sage_getdoc(g) True - sage: g(5) + sage: g(5) # needs sage.libs.flint 7 - sage: g.cache + sage: g.cache # needs sage.libs.flint {((5, 'default'), ()): 7} + sage: def f(t=1): print(t) sage: h = CachedFunction(f) sage: w = walltime() @@ -761,13 +775,17 @@ cdef class CachedFunction(): else: self.__name__ = f.__name__ try: - self.__module__ = f.__module__ + self.__cached_module__ = f.__module__ except AttributeError: - self.__module__ = f.__objclass__.__module__ + self.__cached_module__ = f.__objclass__.__module__ if argument_fixer is not None: # it is None unless the argument fixer # was known previously. See #15038. self._argument_fixer = argument_fixer + @property + def __module__(self): + return self.__cached_module__ + cdef get_key_args_kwds(self, tuple args, dict kwds): """ Return the key in the cache to be used when ``args`` and @@ -823,12 +841,12 @@ cdef class CachedFunction(): TESTS:: - sage: type(hilbert_class_polynomial) + sage: type(hilbert_class_polynomial) # needs sage.schemes <class 'sage.misc.cachefunc.CachedFunction'> - sage: loads(dumps(hilbert_class_polynomial)) is hilbert_class_polynomial #indirect doctest + sage: loads(dumps(hilbert_class_polynomial)) is hilbert_class_polynomial #indirect doctest # needs sage.schemes True """ - return _cached_function_unpickle, (self.__module__, self.__name__, self.cache) + return _cached_function_unpickle, (self.__cached_module__, self.__name__, self.cache) ######### ## Introspection @@ -847,9 +865,10 @@ cdef class CachedFunction(): TESTS:: sage: P.<x,y> = QQ[] - sage: I = P*[x,y] + sage: I = P * [x,y] sage: from sage.misc.sageinspect import sage_getdoc - sage: print(sage_getdoc(I.groebner_basis)) # indirect doctest + sage: print(sage_getdoc(I.groebner_basis)) # indirect doctest + WARNING: the enclosing module is marked... Return the reduced Groebner basis of this ideal. ... @@ -896,8 +915,8 @@ cdef class CachedFunction(): TESTS:: sage: from sage.misc.sageinspect import sage_getsource - sage: g = CachedFunction(number_of_partitions) - sage: 'flint' in sage_getsource(g) # indirect doctest + sage: g = CachedFunction(number_of_partitions) # needs sage.combinat + sage: 'flint' in sage_getsource(g) # indirect doctest # needs sage.combinat True """ @@ -915,7 +934,7 @@ cdef class CachedFunction(): sage: I = P*[x,y] sage: from sage.misc.sageinspect import sage_getsourcelines sage: l = ' elif algorithm.startswith("macaulay2:"):\n' - sage: l in sage_getsourcelines(I.groebner_basis)[0] # indirect doctest + sage: l in sage_getsourcelines(I.groebner_basis)[0] # indirect doctest True """ @@ -948,6 +967,7 @@ cdef class CachedFunction(): TESTS:: + sage: # needs sage.combinat sage.libs.flint sage: g = CachedFunction(number_of_partitions) sage: a = g(5) sage: g.cache @@ -964,18 +984,19 @@ cdef class CachedFunction(): immutable unhashable objects which define :meth:`sage.structure.sage_object.SageObject._cache_key`:: + sage: # needs sage.rings.padics sage: @cached_function ....: def f(x): return x+x - sage: K.<u> = Qq(4) # optional - sage.rings.padics - sage: x = K(1,1); x # optional - sage.rings.padics + sage: K.<u> = Qq(4) + sage: x = K(1,1); x 1 + O(2) - sage: y = K(1,2); y # optional - sage.rings.padics + sage: y = K(1,2); y 1 + O(2^2) - sage: x == y # optional - sage.rings.padics + sage: x == y True - sage: f(x) is f(x) # optional - sage.rings.padics + sage: f(x) is f(x) True - sage: f(y) is not f(x) # optional - sage.rings.padics + sage: f(y) is not f(x) True """ @@ -1045,16 +1066,17 @@ cdef class CachedFunction(): immutable unhashable objects which define :meth:`sage.structure.sage_object.SageObject._cache_key`:: + sage: # needs sage.rings.padics sage: @cached_function ....: def f(x): return x - sage: K.<u> = Qq(4) # optional - sage.rings.padics - sage: x = K(1,1); x # optional - sage.rings.padics + sage: K.<u> = Qq(4) + sage: x = K(1,1); x 1 + O(2) - sage: f.is_in_cache(x) # optional - sage.rings.padics + sage: f.is_in_cache(x) False - sage: f(x) # optional - sage.rings.padics + sage: f(x) 1 + O(2) - sage: f.is_in_cache(x) # optional - sage.rings.padics + sage: f.is_in_cache(x) True """ @@ -1073,6 +1095,7 @@ cdef class CachedFunction(): EXAMPLES:: + sage: # needs sage.combinat sage.libs.flint sage: g = CachedFunction(number_of_partitions) sage: a = g(5) sage: g.cache @@ -1089,13 +1112,14 @@ cdef class CachedFunction(): immutable unhashable objects which define :meth:`sage.structure.sage_object.SageObject._cache_key`:: + sage: # needs sage.rings.padics sage: @cached_function ....: def f(x): return x - sage: K.<u> = Qq(4) # optional - sage.rings.padics - sage: x = K(1,1); x # optional - sage.rings.padics + sage: K.<u> = Qq(4) + sage: x = K(1,1); x 1 + O(2) - sage: f.set_cache(x, x) # optional - sage.rings.padics - sage: f.is_in_cache(x) # optional - sage.rings.padics + sage: f.set_cache(x, x) + sage: f.is_in_cache(x) True DEVELOPER NOTE: @@ -1174,8 +1198,8 @@ cdef class CachedFunction(): """ EXAMPLES:: - sage: g = CachedFunction(number_of_partitions) - sage: g # indirect doctest + sage: g = CachedFunction(number_of_partitions) # needs sage.combinat + sage: g # indirect doctest # needs sage.combinat Cached version of <function number_of_partitions at 0x...> """ try: @@ -1189,9 +1213,10 @@ cdef class CachedFunction(): EXAMPLES:: + sage: # needs sage.combinat sage: g = CachedFunction(number_of_partitions) - sage: a = g(5) - sage: g.cache + sage: a = g(5) # needs sage.libs.flint + sage: g.cache # needs sage.libs.flint {((5, 'default'), ()): 7} sage: g.clear_cache() sage: g.cache @@ -1314,20 +1339,21 @@ cdef class WeakCachedFunction(CachedFunction): immutable unhashable objects which define :meth:`sage.structure.sage_object.SageObject._cache_key`:: + sage: # needs sage.rings.padics sage: from sage.misc.cachefunc import weak_cached_function sage: @weak_cached_function ....: def f(x): return x+x - sage: K.<u> = Qq(4) # optional - sage.rings.padics - sage: R.<t> = K[] # optional - sage.rings.padics - sage: x = t + K(1,1); x # optional - sage.rings.padics + sage: K.<u> = Qq(4) + sage: R.<t> = K[] + sage: x = t + K(1,1); x (1 + O(2^20))*t + 1 + O(2) - sage: y = t + K(1,2); y # optional - sage.rings.padics + sage: y = t + K(1,2); y (1 + O(2^20))*t + 1 + O(2^2) - sage: x == y # optional - sage.rings.padics + sage: x == y True - sage: f(x) is f(x) # optional - sage.rings.padics + sage: f(x) is f(x) True - sage: f(y) is not f(x) # optional - sage.rings.padics + sage: f(y) is not f(x) True Examples and tests for ``is_in_cache``:: @@ -1358,16 +1384,17 @@ cdef class WeakCachedFunction(CachedFunction): immutable unhashable objects which define :meth:`sage.structure.sage_object.SageObject._cache_key`:: + sage: # needs sage.rings.padics sage: from sage.misc.cachefunc import weak_cached_function sage: @weak_cached_function ....: def f(x): return x - sage: K.<u> = Qq(4) # optional - sage.rings.padics - sage: R.<t> = K[] # optional - sage.rings.padics - sage: f.is_in_cache(t) # optional - sage.rings.padics + sage: K.<u> = Qq(4) + sage: R.<t> = K[] + sage: f.is_in_cache(t) False - sage: f(t) # optional - sage.rings.padics + sage: f(t) (1 + O(2^20))*t - sage: f.is_in_cache(t) # optional - sage.rings.padics + sage: f.is_in_cache(t) True Examples and tests for ``set_cache``:: @@ -1384,13 +1411,14 @@ cdef class WeakCachedFunction(CachedFunction): immutable unhashable objects which define :meth:`sage.structure.sage_object.SageObject._cache_key`:: + sage: # needs sage.rings.padics sage: from sage.misc.cachefunc import weak_cached_function sage: @weak_cached_function ....: def f(x): return x - sage: K.<u> = Qq(4) # optional - sage.rings.padics - sage: R.<t> = K[] # optional - sage.rings.padics - sage: f.set_cache(t,t) # optional - sage.rings.padics - sage: f.is_in_cache(t) # optional - sage.rings.padics + sage: K.<u> = Qq(4) + sage: R.<t> = K[] + sage: f.set_cache(t,t) + sage: f.is_in_cache(t) True """ def __init__(self, f, *, classmethod=False, name=None, key=None, **kwds): @@ -1444,8 +1472,8 @@ class CachedMethodPickle(): EXAMPLES:: sage: R.<x, y, z> = PolynomialRing(QQ, 3) - sage: I = R*(x^3 + y^3 + z^3,x^4-y^4) - sage: I.groebner_basis() + sage: I = R * (x^3 + y^3 + z^3, x^4 - y^4) + sage: I.groebner_basis() # needs sage.libs.singular [y^5*z^3 - 1/4*x^2*z^6 + 1/2*x*y*z^6 + 1/4*y^2*z^6, x^2*y*z^3 - x*y^2*z^3 + 2*y^3*z^3 + z^6, x*y^3 + y^4 + x*z^3, x^3 + y^3 + z^3] @@ -1463,11 +1491,11 @@ class CachedMethodPickle(): placeholder, it replaces itself by the cached method, and the entries of the cache are actually preserved:: - sage: J.groebner_basis.is_in_cache() + sage: J.groebner_basis.is_in_cache() # needs sage.libs.singular True sage: J.groebner_basis Cached version of <function ...groebner_basis at 0x...> - sage: J.groebner_basis() == I.groebner_basis() + sage: J.groebner_basis() == I.groebner_basis() # needs sage.libs.singular True TESTS: @@ -1546,10 +1574,10 @@ class CachedMethodPickle(): TESTS:: sage: R.<x, y, z> = PolynomialRing(QQ, 3) - sage: I = R*(x^3 + y^3 + z^3,x^4-y^4) - sage: G = I.groebner_basis() + sage: I = R * (x^3 + y^3 + z^3, x^4 - y^4) + sage: G = I.groebner_basis() # needs sage.libs.singular sage: J = loads(dumps(I)) - sage: J.groebner_basis #indirect doctest + sage: J.groebner_basis # indirect doctest Pickle of the cached method "groebner_basis" """ return 'Pickle of the cached method "{}"'.format(self._name) @@ -1562,8 +1590,8 @@ class CachedMethodPickle(): TESTS:: sage: R.<x, y, z> = PolynomialRing(QQ, 3) - sage: I = R*(x^3 + y^3 + z^3,x^4-y^4) - sage: I.groebner_basis() + sage: I = R * (x^3 + y^3 + z^3, x^4 - y^4) + sage: I.groebner_basis() # needs sage.libs.singular [y^5*z^3 - 1/4*x^2*z^6 + 1/2*x*y*z^6 + 1/4*y^2*z^6, x^2*y*z^3 - x*y^2*z^3 + 2*y^3*z^3 + z^6, x*y^3 + y^4 + x*z^3, x^3 + y^3 + z^3] @@ -1577,7 +1605,7 @@ class CachedMethodPickle(): sage: K = loads(dumps(J)) # indirect doctest sage: K.groebner_basis Pickle of the cached method "groebner_basis" - sage: K.groebner_basis.cache + sage: K.groebner_basis.cache # needs sage.libs.singular {(('', None, None, False), ()): [y^5*z^3 - 1/4*x^2*z^6 + 1/2*x*y*z^6 + 1/4*y^2*z^6, x^2*y*z^3 - x*y^2*z^3 + 2*y^3*z^3 + z^6, @@ -1622,8 +1650,8 @@ class CachedMethodPickle(): TESTS:: sage: R.<x, y, z> = PolynomialRing(QQ, 3) - sage: I = R*(x^3 + y^3 + z^3,x^4-y^4) - sage: G = I.groebner_basis() + sage: I = R * (x^3 + y^3 + z^3, x^4 - y^4) + sage: G = I.groebner_basis() # needs sage.libs.singular sage: J = loads(dumps(I)) sage: J.groebner_basis Pickle of the cached method "groebner_basis" @@ -1640,7 +1668,7 @@ class CachedMethodPickle(): In that way, the unpickling of the cached method is finally accomplished:: - sage: J.groebner_basis.is_in_cache() #indirect doctest + sage: J.groebner_basis.is_in_cache() # indirect doctest # needs sage.libs.singular True sage: J.groebner_basis Cached version of <function ...groebner_basis at 0x...> @@ -1756,12 +1784,12 @@ cdef class CachedMethodCaller(CachedFunction): TESTS:: sage: R.<x, y, z> = PolynomialRing(QQ, 3) - sage: I = R*(x^3 + y^3 + z^3,x^4-y^4) - sage: G = I.groebner_basis() - sage: J = loads(dumps(I)) #indirect doctest + sage: I = R * (x^3 + y^3 + z^3, x^4 - y^4) + sage: G = I.groebner_basis() # needs sage.libs.singular + sage: J = loads(dumps(I)) # indirect doctest sage: J.groebner_basis Pickle of the cached method "groebner_basis" - sage: J.groebner_basis.is_in_cache() + sage: J.groebner_basis.is_in_cache() # needs sage.libs.singular True sage: J.groebner_basis Cached version of <function ...groebner_basis at 0x...> @@ -1778,12 +1806,12 @@ cdef class CachedMethodCaller(CachedFunction): EXAMPLES:: sage: P.<a,b,c,d> = QQ[] - sage: I = P*[a,b] - sage: I.groebner_basis() + sage: I = P * [a, b] + sage: I.groebner_basis() # needs sage.libs.singular [a, b] - sage: I.groebner_basis._instance_call() is I.groebner_basis() + sage: I.groebner_basis._instance_call() is I.groebner_basis() # needs sage.libs.singular False - sage: I.groebner_basis._instance_call() == I.groebner_basis() + sage: I.groebner_basis._instance_call() == I.groebner_basis() # needs sage.libs.singular True :: @@ -1902,20 +1930,21 @@ cdef class CachedMethodCaller(CachedFunction): immutable unhashable objects which define :meth:`sage.structure.sage_object.SageObject._cache_key`:: - sage: K.<u> = Qq(4) # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K.<u> = Qq(4) sage: class A(): ....: @cached_method ....: def f(self, x): return x+x sage: a = A() - sage: x = K(1,1); x # optional - sage.rings.padics + sage: x = K(1,1); x 1 + O(2) - sage: y = K(1,2); y # optional - sage.rings.padics + sage: y = K(1,2); y 1 + O(2^2) - sage: x == y # optional - sage.rings.padics + sage: x == y True - sage: a.f(x) is a.f(x) # optional - sage.rings.padics + sage: a.f(x) is a.f(x) True - sage: a.f(y) is not a.f(x) # optional - sage.rings.padics + sage: a.f(y) is not a.f(x) True """ @@ -1995,7 +2024,7 @@ cdef class CachedMethodCaller(CachedFunction): This getter attempts to assign a bound method as an attribute to the given instance. If this is not possible (for example, for some extension classes), - it is attempted to find an attribute ``__cached_methods``, + it is attempted to find an attribute ``_cached_methods``, and store/retrieve the bound method there. In that way, cached methods can be implemented for extension classes deriving from :class:`~sage.structure.parent.Parent` @@ -2061,7 +2090,7 @@ cdef class CachedMethodCaller(CachedFunction): """ # This is for Parents or Elements that do not allow attribute assignment try: - return (<dict>inst.__cached_methods)[self._cachedmethod._cachedfunc.__name__] + return (<dict>inst._cached_methods)[self._cachedmethod._cachedfunc.__name__] except (AttributeError, TypeError, KeyError): pass @@ -2076,10 +2105,10 @@ cdef class CachedMethodCaller(CachedFunction): except AttributeError: pass try: - if inst.__cached_methods is None: - inst.__cached_methods = {self._cachedmethod._cachedfunc.__name__ : Caller} + if inst._cached_methods is None: + inst._cached_methods = {self._cachedmethod._cachedfunc.__name__ : Caller} else: - (<dict>inst.__cached_methods)[self._cachedmethod._cachedfunc.__name__] = Caller + (<dict>inst._cached_methods)[self._cachedmethod._cachedfunc.__name__] = Caller except AttributeError: pass return Caller @@ -2209,7 +2238,7 @@ cdef class CachedMethodCallerNoArgs(CachedFunction): """ # initialize CachedFunction - if isinstance(f,basestring): + if isinstance(f,str): try: F = getattr(inst.__class__,f) except AttributeError: @@ -2254,7 +2283,7 @@ cdef class CachedMethodCallerNoArgs(CachedFunction): sage: J = loads(dumps(I)) sage: J.gens Pickle of the cached method "gens" - sage: J.gens.cache # the cache is dropped because gens is not marked with do_pickle=True + sage: J.gens.cache # the cache is dropped because gens is not marked with do_pickle=True sage: J.gens Cached version of <function ...gens at 0x...> """ @@ -2397,7 +2426,7 @@ cdef class CachedMethodCallerNoArgs(CachedFunction): This getter attempts to assign a bound method as an attribute to the given instance. If this is not possible (for example, for some extension classes), - it is attempted to find an attribute ``__cached_methods``, + it is attempted to find an attribute ``_cached_methods``, and store/retrieve the bound method there. In that way, cached methods can be implemented for extension classes deriving from :class:`~sage.structure.parent.Parent` @@ -2448,7 +2477,7 @@ cdef class CachedMethodCallerNoArgs(CachedFunction): """ # This is for Parents or Elements that do not allow attribute assignment try: - return (<dict>inst.__cached_methods)[self.__name__] + return (<dict>inst._cached_methods)[self.__name__] except (AttributeError, TypeError, KeyError): pass Caller = CachedMethodCallerNoArgs(inst, self.f, name=self.__name__, do_pickle=self.do_pickle) @@ -2458,10 +2487,10 @@ cdef class CachedMethodCallerNoArgs(CachedFunction): except AttributeError: pass try: - if inst.__cached_methods is None: - inst.__cached_methods = {self.__name__ : Caller} + if inst._cached_methods is None: + inst._cached_methods = {self.__name__ : Caller} else: - (<dict>inst.__cached_methods)[self.__name__] = Caller + (<dict>inst._cached_methods)[self.__name__] = Caller except AttributeError: pass return Caller @@ -2485,12 +2514,12 @@ cdef class GloballyCachedMethodCaller(CachedMethodCaller): sage: class MyParent(Parent): ....: pass - sage: class MyElement(): + sage: class MyElement(): # indirect doctest ....: def __init__(self, x): ....: self.x = x ....: def parent(self): ....: return MyParent() - ....: @cached_in_parent_method #indirect doctest + ....: @cached_in_parent_method ....: def f(self): ....: return self.x^2 sage: a = MyElement(2) @@ -2674,7 +2703,11 @@ cdef class CachedMethod(): self._cache_name = '_cache__' + (name or f.__name__) self._cachedfunc = CachedFunction(f, classmethod=True, name=name, key=key, do_pickle=do_pickle) self.__name__ = self._cachedfunc.__name__ - self.__module__ = self._cachedfunc.__module__ + self.__cached_module__ = self._cachedfunc.__module__ + + @property + def __module__(self): + return self.__cached_module__ def __call__(self, inst, *args, **kwds): """ @@ -2804,7 +2837,7 @@ cdef class CachedMethod(): except AttributeError: name = self.__name__ try: - return (<dict>inst.__cached_methods)[name] + return (<dict>inst._cached_methods)[name] except (AttributeError, TypeError, KeyError): pass # Apparently we need to construct the caller. @@ -2816,8 +2849,6 @@ cdef class CachedMethod(): try: if METH_NOARGS&PyCFunction_GetFlags(f.__get__(inst,cls)): self.nargs = 1 - else: - self.nargs = 2 except Exception: pass if self.nargs == 0: @@ -2840,10 +2871,10 @@ cdef class CachedMethod(): except AttributeError: pass try: - if inst.__cached_methods is None: - inst.__cached_methods = {name : Caller} + if inst._cached_methods is None: + inst._cached_methods = {name : Caller} else: - (<dict>inst.__cached_methods)[name] = Caller + (<dict>inst._cached_methods)[name] = Caller except AttributeError: pass return Caller @@ -2941,12 +2972,12 @@ cdef class CachedSpecialMethod(CachedMethod): D = inst.__dict__ except (TypeError, AttributeError): try: - D = inst.__cached_methods + D = inst._cached_methods except (TypeError, AttributeError): - raise TypeError("For a cached special method, either attribute assignment or a public '__cached_methods' attribute of type <dict> is needed") + raise TypeError("For a cached special method, either attribute assignment or a public '_cached_methods' attribute of type <dict> is needed") if D is None: - # This can only happen in the case of __cached_methods - D = inst.__cached_methods = {} + # This can only happen in the case of _cached_methods + D = inst._cached_methods = {} else: try: return D[name] @@ -3057,7 +3088,7 @@ def cached_method(f, name=None, key=None, do_pickle=None): sage: import __main__ sage: __main__.C = C sage: c = C() - sage: hash(c) # random output + sage: hash(c) # random output sage: d = loads(dumps(c)) sage: hash(d) == hash(c) True @@ -3072,7 +3103,7 @@ def cached_method(f, name=None, key=None, do_pickle=None): sage: __main__.C = C sage: c = C() - sage: hash(c) # random output + sage: hash(c) # random output sage: d = loads(dumps(c)) sage: hash(d) == hash(c) False @@ -3124,13 +3155,13 @@ cdef class CachedInParentMethod(CachedMethod): sage: class MyParent(Parent): ....: pass - sage: class Foo: + sage: class Foo: # indirect doctest ....: def __init__(self, x): ....: self._x = x ....: self._parent = MyParent() ....: def parent(self): ....: return self._parent - ....: @cached_in_parent_method #indirect doctest + ....: @cached_in_parent_method ....: def f(self): ....: return self._x^2 sage: a = Foo(2) @@ -3255,7 +3286,7 @@ cdef class CachedInParentMethod(CachedMethod): sage: c = Foo(3) sage: c.f() 27 - sage: c.f.cache is a.f.cache #indirect doctest + sage: c.f.cache is a.f.cache #indirect doctest True Note that the cache is also available as an @@ -3274,13 +3305,13 @@ cdef class CachedInParentMethod(CachedMethod): return P.__dict__.setdefault(self._cache_name, default) except AttributeError: pass - if not hasattr(P,'__cached_methods'): + if not hasattr(P,'_cached_methods'): raise TypeError("The parent of this element does not allow attribute assignment\n" + " and does not descend from the Parent base class.\n" + " Cannot use CachedInParentMethod.") - if P.__cached_methods is None: - P.__cached_methods = {} - return (<dict>P.__cached_methods).setdefault(self._cache_name, default) + if P._cached_methods is None: + P._cached_methods = {} + return (<dict>P._cached_methods).setdefault(self._cache_name, default) def __get__(self, inst, cls): """ @@ -3670,11 +3701,11 @@ class disk_cached_function: sage: dir = tmp_dir() sage: @disk_cached_function(dir) ....: def foo(x): return next_prime(2^x)%x - sage: x = foo(200);x + sage: x = foo(200); x # needs sage.libs.pari 11 sage: @disk_cached_function(dir) ....: def foo(x): return 1/x - sage: foo(200) + sage: foo(200) # needs sage.libs.pari 11 sage: foo.clear_cache() sage: foo(200) @@ -3687,12 +3718,12 @@ class disk_cached_function: sage: dir = tmp_dir() sage: @disk_cached_function(dir, memory_cache=True) ....: def foo(x): return next_prime(2^x) - sage: x = foo(200) - sage: x is foo(200) + sage: x = foo(200) # needs sage.libs.pari + sage: x is foo(200) # needs sage.libs.pari True sage: @disk_cached_function(dir, memory_cache=False) ....: def foo(x): return next_prime(2^x) - sage: x is foo(200) + sage: x is foo(200) # needs sage.libs.pari False """ self._dir = dir @@ -3706,8 +3737,9 @@ class disk_cached_function: sage: dir = tmp_dir() sage: @disk_cached_function(dir) ....: def foo(x): return ModularSymbols(x) - sage: foo(389) - Modular Symbols space of dimension 65 for Gamma_0(389) of weight 2 with sign 0 over Rational Field + sage: foo(389) # needs sage.modular + Modular Symbols space of dimension 65 for Gamma_0(389) of weight 2 + with sign 0 over Rational Field """ return DiskCachedFunction(f, self._dir, memory_cache=self._memory_cache, key=self._key) diff --git a/src/sage/misc/call.py b/src/sage/misc/call.py index ddb48610e59..966ee34514b 100644 --- a/src/sage/misc/call.py +++ b/src/sage/misc/call.py @@ -40,11 +40,11 @@ def __call__(self, x, *args): EXAMPLES:: sage: core = attrcall('core', 3) - sage: core(Partition([4,2])) + sage: core(Partition([4,2])) # needs sage.combinat [4, 2] - sage: series = attrcall('series', x) - sage: series(sin(x), 4) + sage: series = attrcall('series', x) # needs sage.symbolic + sage: series(sin(x), 4) # needs sage.symbolic 1*x + (-1/6)*x^3 + Order(x^4) """ return getattr(x, self.name)(*(self.args + args), **self.kwds) @@ -159,7 +159,7 @@ def attrcall(name, *args, **kwds): sage: f = attrcall('core', 3); f *.core(3) - sage: [f(p) for p in Partitions(5)] + sage: [f(p) for p in Partitions(5)] # needs sage.combinat [[2], [1, 1], [1, 1], [3, 1, 1], [2], [2], [1, 1]] """ return AttrCallObject(name, args, kwds) @@ -181,5 +181,6 @@ def call_method(obj, name, *args, **kwds): """ return getattr(obj, name)(*args, **kwds) + from sage.misc.persist import register_unpickle_override register_unpickle_override("sage.misc.misc", "call_method", call_method) diff --git a/src/sage/misc/citation.pyx b/src/sage/misc/citation.pyx index 6bd24dd15b7..9377ce73636 100644 --- a/src/sage/misc/citation.pyx +++ b/src/sage/misc/citation.pyx @@ -23,7 +23,6 @@ systems['Mathematica'] = ['sage.interfaces.mathematica'] systems['MuPAD'] = ['sage.interfaces.mupad'] systems['Octave'] = ['sage.interfaces.octave'] systems['povray'] = ['sage.interfaces.povray'] -systems['qsieve'] = ['sage.interfaces.qsieve'] systems['Macaulay2'] = ['sage.interfaces.macaulay2'] systems['mwrank'] = ['sage.interfaces.mwrank', 'sage.libs.eclib'] systems['matlab'] = ['sage.interfaces.matlab'] @@ -72,9 +71,9 @@ def get_systems(cmd): sage: from sage.misc.citation import get_systems sage: get_systems('print("hello")') # random (may print warning) [] - sage: integrate(x^2, x) # Priming coercion model + sage: integrate(x^2, x) # Priming coercion model # needs sage.symbolic 1/3*x^3 - sage: get_systems('integrate(x^2, x)') + sage: get_systems('integrate(x^2, x)') # needs sage.symbolic ['Maxima', 'ginac'] sage: R.<x,y,z> = QQ[] sage: I = R.ideal(x^2+y^2, z^2+y) @@ -92,7 +91,7 @@ def get_systems(cmd): "Rebuild Sage with the environment variable 'SAGE_PROFILE=yes' " "to enable profiling.") - if not isinstance(cmd, basestring): + if not isinstance(cmd, str): raise TypeError("command must be a string") from sage.repl.preparse import preparse diff --git a/src/sage/misc/classcall_metaclass.pyx b/src/sage/misc/classcall_metaclass.pyx index 191534f76ee..65351cb2756 100644 --- a/src/sage/misc/classcall_metaclass.pyx +++ b/src/sage/misc/classcall_metaclass.pyx @@ -79,7 +79,7 @@ cdef class ClasscallMetaclass(NestedClassMetaclass): TESTS:: - sage: PerfectMatchings(2).list() + sage: PerfectMatchings(2).list() # needs sage.combinat [[(1, 2)]] .. NOTE:: @@ -271,12 +271,12 @@ cdef class ClasscallMetaclass(NestedClassMetaclass): The benefit, compared with using a wrapper function, is that the user interface has a single handle for the class:: - sage: x = Partition([3,2,2]) - sage: isinstance(x, Partition) # todo: not implemented + sage: x = Partition([3,2,2]) # needs sage.combinat + sage: isinstance(x, Partition) # not implemented # needs sage.combinat instead of:: - sage: isinstance(x, sage.combinat.partition.Partition) + sage: isinstance(x, sage.combinat.partition.Partition) # needs sage.combinat True Another difference is that ``__classcall__`` is inherited by diff --git a/src/sage/misc/compat.py b/src/sage/misc/compat.py index d6e5adb431b..4ad6d3fe5ef 100644 --- a/src/sage/misc/compat.py +++ b/src/sage/misc/compat.py @@ -93,7 +93,7 @@ def find_library(name): EXAMPLES:: sage: from sage.misc.compat import find_library - sage: find_library('giac') + sage: find_library('giac') # needs sage.libs.giac '...giac...' """ diff --git a/src/sage/misc/converting_dict.py b/src/sage/misc/converting_dict.py index 7476555e210..39f66c9295a 100644 --- a/src/sage/misc/converting_dict.py +++ b/src/sage/misc/converting_dict.py @@ -26,8 +26,9 @@ This is used e.g. in the result of a variety, to allow access to the result no matter how a generator is identified:: + sage: # needs sage.rings.number_field sage: K.<x,y> = QQ[] - sage: I = ideal([x^2+2*y-5,x+y+3]) + sage: I = ideal([x^2 + 2*y - 5, x + y + 3]) sage: V = sorted(I.variety(AA), key=str) sage: v = V[0] sage: v['x'], v['y'] diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 3f02e9e3a70..347b2e896d8 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.misc.cython +# sage.doctest: needs sage.misc.cython """ Cython support functions @@ -21,6 +21,7 @@ import builtins import os +import re import sys import shutil @@ -171,7 +172,7 @@ def cython(filename, verbose=0, compile_message=False, sage: os.chdir(d) sage: with open("helper.pxd", 'w') as f: ....: _ = f.write("cdef inline int the_answer(): return 42") - sage: cython(''' # optional - sage.misc.cython + sage: cython(''' ....: from helper cimport the_answer ....: print(the_answer()) ....: ''') @@ -208,9 +209,31 @@ def cython(filename, verbose=0, compile_message=False, As of :trac:`29139` the default is ``cdivision=True``:: - sage: cython(''' # optional - sage.misc.cython + sage: cython(''' ....: cdef size_t foo = 3/2 ....: ''') + + Check that Cython supports PEP 420 packages:: + + sage: cython(''' + ....: cimport sage.misc.cachefunc + ....: ''') + + sage: cython(''' + ....: from sage.misc.cachefunc cimport cache_key + ....: ''') + + In Cython 0.29.33 using `from PACKAGE cimport MODULE` is broken + when `PACKAGE` is a namespace package, see :trac:`35322`:: + + sage: cython(''' + ....: from sage.misc cimport cachefunc + ....: ''') + Traceback (most recent call last): + ... + RuntimeError: Error compiling Cython file: + ... + ...: 'sage/misc.pxd' not found """ if not filename.endswith('pyx'): print("Warning: file (={}) should have extension .pyx".format(filename), file=sys.stderr) @@ -374,6 +397,12 @@ def cython(filename, verbose=0, compile_message=False, raise RuntimeError(cython_messages.strip()) if verbose >= 0: + # triggered by Cython 3 with unpatched cysignals 1.11.2 + cython_messages = re.sub( + "^.*The keyword 'nogil' should appear at the end of the function signature line. " + "Placing it before 'except' or 'noexcept' will be disallowed in a future version of Cython.\n", + "", cython_messages, 0, re.MULTILINE) + sys.stderr.write(cython_messages) sys.stderr.flush() @@ -624,9 +653,9 @@ def compile_and_load(code, **kwds): ....: cdef Polynomial_rational_flint res = f._new() ....: cdef unsigned long k ....: cdef Rational z = Rational(0) - ....: for k in range(fmpq_poly_length(f.__poly)): - ....: fmpq_poly_get_coeff_mpq(z.value, f.__poly, k) - ....: fmpq_poly_set_coeff_mpq(res.__poly, n*k, z.value) + ....: for k in range(fmpq_poly_length(f._poly)): + ....: fmpq_poly_get_coeff_mpq(z.value, f._poly, k) + ....: fmpq_poly_set_coeff_mpq(res._poly, n*k, z.value) ....: return res ....: ''' sage: module = compile_and_load(code) # long time diff --git a/src/sage/misc/decorators.py b/src/sage/misc/decorators.py index ebfa844586b..a13f1523c74 100644 --- a/src/sage/misc/decorators.py +++ b/src/sage/misc/decorators.py @@ -67,7 +67,7 @@ def sage_wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES): ....: return x sage: g(2) 4 - sage: g(x) + sage: g(x) # needs sage.symbolic x^2 sage: g.__doc__ 'My little function' @@ -104,7 +104,7 @@ def sage_wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES): sage: I = P*[x,y] sage: sage_getfile(I.interreduced_basis) # known bug '.../sage/rings/polynomial/multi_polynomial_ideal.py' - sage: sage_getsourcelines(I.interreduced_basis) + sage: sage_getsourcelines(I.interreduced_basis) # needs sage.libs.singular ([' @handle_AA_and_QQbar\n', ' @singular_gb_standard_options\n', ' @libsingular_gb_standard_options\n', @@ -151,7 +151,7 @@ def sage_wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES): ....: return new_f sage: f = lambda x:x^2 sage: g = square(f) - sage: g(3) # this line used to fail for some people if these command were manually entered on the sage prompt + sage: g(3) # this line used to fail for some people if these command were manually entered on the sage prompt 81 """ @@ -192,13 +192,14 @@ class infix_operator(): ....: def dot(a, b): ....: '''Dot product.''' ....: return a.dot_product(b) - sage: u = vector([1, 2, 3]) - sage: v = vector([5, 4, 3]) - sage: u *dot* v + sage: u = vector([1, 2, 3]) # needs sage.modules + sage: v = vector([5, 4, 3]) # needs sage.modules + sage: u *dot* v # needs sage.modules 22 An infix element-wise addition operator:: + sage: # needs sage.modules sage: @infix_operator('add') ....: def eadd(a, b): ....: return a.parent([i + j for i, j in zip(a, b)]) @@ -214,7 +215,7 @@ class infix_operator(): sage: @infix_operator('or') ....: def thendo(a, b): ....: return b(a) - sage: x |thendo| cos |thendo| (lambda x: x^2) + sage: x |thendo| cos |thendo| (lambda x: x^2) # needs sage.symbolic cos(x)^2 """ @@ -389,7 +390,7 @@ def __call__(self, func): [('arrow_options', {'size': 5})] Demonstrate that the introspected argument specification of the - wrapped function is updated (see :trac:`9976`). + wrapped function is updated (see :trac:`9976`):: sage: from sage.misc.sageinspect import sage_getargspec sage: sage_getargspec(f) diff --git a/src/sage/misc/derivative.pyx b/src/sage/misc/derivative.pyx index 45ee7a918c5..9788e82e06e 100644 --- a/src/sage/misc/derivative.pyx +++ b/src/sage/misc/derivative.pyx @@ -91,20 +91,20 @@ def derivative_parse(args): EXAMPLES:: - sage: x = var("x") - sage: y = var("y") + sage: x = var("x") # needs sage.symbolic + sage: y = var("y") # needs sage.symbolic sage: from sage.misc.derivative import derivative_parse Differentiate twice with respect to x, then once with respect to y, then once with respect to x:: - sage: derivative_parse([x, 2, y, x]) + sage: derivative_parse([x, 2, y, x]) # needs sage.symbolic [x, x, y, x] Differentiate twice with respect to x, then twice with respect to the 'default variable':: - sage: derivative_parse([x, 2, 2]) + sage: derivative_parse([x, 2, 2]) # needs sage.symbolic [x, x, None, None] Special case with empty input list:: @@ -119,7 +119,7 @@ def derivative_parse(args): Special case with single list argument provided:: - sage: derivative_parse(([x, y], )) + sage: derivative_parse(([x, y], )) # needs sage.symbolic [x, y] If only the count is supplied:: @@ -135,6 +135,7 @@ def derivative_parse(args): Various other cases:: + sage: # needs sage.symbolic sage: derivative_parse([x]) [x] sage: derivative_parse([x, x]) @@ -186,8 +187,8 @@ def multi_derivative(F, args): INPUT: - F -- any object with a _derivative(var) method. - args -- any tuple that can be processed by derivative_parse(). + - ``F`` -- any object with a ``_derivative(var)`` method. + - ``args`` -- any tuple that can be processed by :func:`derivative_parse`. EXAMPLES:: diff --git a/src/sage/misc/dev_tools.py b/src/sage/misc/dev_tools.py index 9b2f8a504c9..e7bf176592c 100644 --- a/src/sage/misc/dev_tools.py +++ b/src/sage/misc/dev_tools.py @@ -31,6 +31,7 @@ def runsnake(command): EXAMPLES:: + sage: from sage.misc.dev_tools import runsnake sage: runsnake("list(SymmetricGroup(3))") # optional - runsnake ``command`` is first preparsed (see :func:`preparse`):: @@ -169,7 +170,7 @@ def load_submodules(module=None, exclude_pattern=None): load sage.geometry.polyhedron.palp_database... succeeded load sage.geometry.polyhedron.ppl_lattice_polygon... succeeded """ - import pkgutil + from .package_dir import walk_packages if module is None: import sage @@ -181,7 +182,7 @@ def load_submodules(module=None, exclude_pattern=None): else: exclude = None - for importer, module_name, ispkg in pkgutil.walk_packages(module.__path__, module.__name__ + '.'): + for importer, module_name, ispkg in walk_packages(module.__path__, module.__name__ + '.'): if ispkg or module_name in sys.modules: continue @@ -202,15 +203,25 @@ def load_submodules(module=None, exclude_pattern=None): sys.stdout.write("failed\n") -def find_objects_from_name(name, module_name=None): +def find_objects_from_name(name, module_name=None, include_lazy_imports=False): r""" Return the list of objects from ``module_name`` whose name is ``name``. - If ``module_name`` is ``None``, the function runs through all - loaded modules and returns the list of objects whose name matches ``name``. + INPUT: + + - ``name`` -- string + + - ``module_name`` -- string or ``None``: + + - If ``module_name`` is ``None``, the function runs through all + loaded modules and returns the list of objects whose name matches ``name``. - If ``module_name`` is not ``None``, then search only in submodules of - ``module_name``. + - If ``module_name`` is a string, then search only in submodules of + ``module_name``. + + - ``include_lazy_imports`` -- boolean (default: ``False``); whether to + include unresolved lazy imports (i.e., :class:`~sage.misc.lazy_import.LazyImport` + objects) in the output. In order to search through more modules you might use the function :func:`load_submodules`. @@ -218,9 +229,10 @@ def find_objects_from_name(name, module_name=None): EXAMPLES:: sage: import sage.misc.dev_tools as dt - sage: dt.find_objects_from_name('FareySymbol') + sage: dt.find_objects_from_name('FareySymbol') # needs sage.modular [<class 'sage.modular.arithgroup.farey_symbol.Farey'>] + sage: # needs sympy sage: import sympy sage: dt.find_objects_from_name('RR') [Real Field with 53 bits of precision, RR] @@ -239,11 +251,22 @@ def find_objects_from_name(name, module_name=None): sage: dt.find_objects_from_name is dt.find_objects_from_name True + When ``include_lazy_imports=True`` is used, several + :class:`~sage.misc.lazy_import.LazyImport` objects that are resolving to the + same object may be included in the output:: + + sage: dt.find_objects_from_name('RR', include_lazy_imports=True) + [Real Field with 53 bits of precision, + ... + Real Field with 53 bits of precision, + RR] + .. NOTE:: It might be a good idea to move this function into :mod:`sage.misc.sageinspect`. """ + from sage.misc.lazy_import import LazyImport obj = [] for smodule_name, smodule in sys.modules.items(): @@ -251,7 +274,7 @@ def find_objects_from_name(name, module_name=None): continue if hasattr(smodule, '__dict__') and name in smodule.__dict__: u = smodule.__dict__[name] - if all(v is not u for v in obj): + if (not isinstance(u, LazyImport) or include_lazy_imports) and all(v is not u for v in obj): obj.append(u) return obj @@ -269,7 +292,7 @@ def find_object_modules(obj): EXAMPLES:: sage: from sage.misc.dev_tools import find_object_modules - sage: find_object_modules(RR) + sage: find_object_modules(RR) # needs sage.rings.real_mpfr {'sage.rings.real_mpfr': ['RR']} sage: find_object_modules(ZZ) {'sage.rings.integer_ring': ['Z', 'ZZ']} @@ -352,7 +375,7 @@ def import_statements(*objects, **kwds): EXAMPLES:: - sage: import_statements(WeylGroup, lazy_attribute) + sage: import_statements(WeylGroup, lazy_attribute) # needs sage.libs.gap from sage.combinat.root_system.weyl_group import WeylGroup from sage.misc.lazy_attribute import lazy_attribute @@ -362,7 +385,7 @@ def import_statements(*objects, **kwds): If ``lazy`` is True, then :func:`lazy_import` statements are displayed instead:: - sage: import_statements(WeylGroup, lazy_attribute, lazy=True) + sage: import_statements(WeylGroup, lazy_attribute, lazy=True) # needs sage.libs.gap from sage.misc.lazy_import import lazy_import lazy_import('sage.combinat.root_system.weyl_group', 'WeylGroup') lazy_import('sage.misc.lazy_attribute', 'lazy_attribute') @@ -380,7 +403,7 @@ def import_statements(*objects, **kwds): sage: import_statements(euler_phi) from sage.arith.misc import euler_phi - sage: import_statements(x) + sage: import_statements(x) # needs sage.symbolic from sage.calculus.predefined import x If you don't like the warning you can disable them with the option ``verbose``:: @@ -388,13 +411,13 @@ def import_statements(*objects, **kwds): sage: import_statements(ZZ, verbose=False) from sage.rings.integer_ring import Z - sage: import_statements(x, verbose=False) + sage: import_statements(x, verbose=False) # needs sage.symbolic from sage.calculus.predefined import x If the object has several names, an other way to get the import statement you expect is to use a string instead of the object:: - sage: import_statements(matrix) + sage: import_statements(matrix) # needs sage.modules # ** Warning **: several names for that object: Matrix, matrix from sage.matrix.constructor import Matrix @@ -409,7 +432,7 @@ def import_statements(*objects, **kwds): The strings are allowed to be comma-separated names, and parenthesis are stripped for convenience:: - sage: import_statements('(floor, ceil)') + sage: import_statements('(floor, ceil)') # needs sage.symbolic from sage.functions.other import floor, ceil Specifying a string is also useful for objects that are not @@ -486,9 +509,9 @@ def import_statements(*objects, **kwds): from sage.combinat.partition_algebra import SetPartitionsAk sage: import_statements(CIF) from sage.rings.cif import CIF - sage: import_statements(NaN) + sage: import_statements(NaN) # needs sage.symbolic from sage.symbolic.constants import NaN - sage: import_statements(pi) + sage: import_statements(pi) # needs sage.symbolic from sage.symbolic.constants import pi sage: import_statements('SAGE_ENV') from sage.env import SAGE_ENV @@ -546,10 +569,10 @@ def expand_comma_separated_names(obj): obj = [G[name]] else: # 1.b. object inside a submodule of sage - obj = find_objects_from_name(name, 'sage') + obj = find_objects_from_name(name, 'sage', include_lazy_imports=True) if not obj: # 1.c. object from something already imported - obj = find_objects_from_name(name) + obj = find_objects_from_name(name, include_lazy_imports=True) # remove lazy imported objects from list obj i = 0 diff --git a/src/sage/misc/dist.py b/src/sage/misc/dist.py index b72f9c60919..5570bb5926b 100644 --- a/src/sage/misc/dist.py +++ b/src/sage/misc/dist.py @@ -70,6 +70,7 @@ def install_scripts(directory=None, ignore_existing=False): EXAMPLES:: sage: import tempfile + sage: from sage.misc.dist import install_scripts sage: with tempfile.TemporaryDirectory() as d: ....: install_scripts(d, ignore_existing=True) doctest:warning... diff --git a/src/sage/misc/edit_module.py b/src/sage/misc/edit_module.py index 5c1dfa6d7ae..9b03e7237a0 100644 --- a/src/sage/misc/edit_module.py +++ b/src/sage/misc/edit_module.py @@ -80,7 +80,7 @@ def file_and_line(obj): The following tests against a bug that was fixed in :trac:`11298`:: - sage: edit_module.file_and_line(x) + sage: edit_module.file_and_line(x) # needs sage.symbolic ('...sage/symbolic/expression...pyx', ...) """ # d = inspect.getdoc(obj) diff --git a/src/sage/misc/element_with_label.py b/src/sage/misc/element_with_label.py index 2410851c7de..831b012e31a 100644 --- a/src/sage/misc/element_with_label.py +++ b/src/sage/misc/element_with_label.py @@ -25,13 +25,15 @@ class ElementWithLabel(): EXAMPLES:: + sage: # needs sage.combinat sage.graphs sage: P = Poset({1: [2,3]}) sage: labs = {i: P.rank(i) for i in range(1, 4)} sage: print(labs) {1: 0, 2: 1, 3: 1} - sage: print(P.plot(element_labels=labs)) + sage: print(P.plot(element_labels=labs)) # needs sage.plot Graphics object consisting of 6 graphics primitives + sage: # needs sage.combinat sage.graphs sage.modules sage: from sage.misc.element_with_label import ElementWithLabel sage: W = WeylGroup("A1") sage: P = W.bruhat_poset(facade=True) @@ -65,11 +67,11 @@ def _latex_(self): TESTS:: - sage: var('a_1') + sage: var('a_1') # needs sage.symbolic a_1 sage: from sage.misc.element_with_label import ElementWithLabel - sage: e = ElementWithLabel(1, a_1) - sage: latex(e) + sage: e = ElementWithLabel(1, a_1) # needs sage.symbolic + sage: latex(e) # needs sage.symbolic a_{1} """ return latex(self.label) @@ -81,11 +83,11 @@ def __str__(self): TESTS:: - sage: var('a_1') + sage: var('a_1') # needs sage.symbolic a_1 sage: from sage.misc.element_with_label import ElementWithLabel - sage: e = ElementWithLabel(1, a_1) - sage: str(e) + sage: e = ElementWithLabel(1, a_1) # needs sage.symbolic + sage: str(e) # needs sage.symbolic 'a_1' """ return str(self.label) @@ -97,11 +99,11 @@ def __repr__(self): TESTS:: - sage: var('a_1') + sage: var('a_1') # needs sage.symbolic a_1 sage: from sage.misc.element_with_label import ElementWithLabel - sage: e = ElementWithLabel(1, a_1) - sage: repr(e) + sage: e = ElementWithLabel(1, a_1) # needs sage.symbolic + sage: repr(e) # needs sage.symbolic 'a_1' """ return repr(self.label) diff --git a/src/sage/misc/explain_pickle.py b/src/sage/misc/explain_pickle.py index c8d9e79c0d9..30c3988850b 100644 --- a/src/sage/misc/explain_pickle.py +++ b/src/sage/misc/explain_pickle.py @@ -213,7 +213,7 @@ def explain_pickle(pickle=None, file=None, compress=True, **kwargs): sage: explain_pickle(dumps({('a', 'b'): [1r, 2r]})) {('a', 'b'):[1r, 2r]} - sage: explain_pickle(dumps(RR(pi)), in_current_sage=True) + sage: explain_pickle(dumps(RR(pi)), in_current_sage=True) # needs sage.symbolic from sage.rings.real_mpfr import __create__RealNumber_version0 from sage.rings.real_mpfr import __create__RealField_version0 __create__RealNumber_version0(__create__RealField_version0(53r, False, 'RNDN'), '3.4gvml245kc0@0', 32r) @@ -294,6 +294,7 @@ def explain_pickle_string(pickle, in_current_sage=False, else: return ans + valid_name_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$') def name_is_valid(name): r""" @@ -313,6 +314,7 @@ def name_is_valid(name): # Technically, we also need to reject keywords... return bool(valid_name_re.match(name)) + # The pickle interpreter can push and pop "marks" on the stack. # This string is used as the representation of a mark. the_mark = 'mark' @@ -851,7 +853,7 @@ def BINFLOAT(self, f): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(float(pi)) + sage: test_pickle(float(pi)) # needs sage.symbolic 0: \x80 PROTO 2 2: G BINFLOAT 3.141592653589793 11: . STOP @@ -3051,6 +3053,7 @@ def __repr__(self): """ return "TestGlobalFunnyName" + TestGlobalFunnyName.__name__ = "funny$name" #This crashed Sphinx. Instead, we manually execute this just before the test. #globals()['funny$name'] = TestGlobalFunnyName diff --git a/src/sage/misc/fast_methods.pyx b/src/sage/misc/fast_methods.pyx index d3fd260f55f..370cefc46a0 100644 --- a/src/sage/misc/fast_methods.pyx +++ b/src/sage/misc/fast_methods.pyx @@ -169,7 +169,7 @@ cdef class WithEqualityById: Check that :trac:`19628` is fixed:: sage: from sage.misc.lazy_import import LazyImport - sage: lazyQQ = LazyImport('sage.all', 'QQ') + sage: lazyQQ = LazyImport('sage.rings.rational_field', 'QQ') sage: PolynomialRing(lazyQQ, 'ijk') is PolynomialRing(QQ, 'ijk') True sage: PolynomialRing(QQ, 'ijkl') is PolynomialRing(lazyQQ, 'ijkl') diff --git a/src/sage/misc/flatten.py b/src/sage/misc/flatten.py index 8b8a7ce54b2..5ebc8c2ceaa 100644 --- a/src/sage/misc/flatten.py +++ b/src/sage/misc/flatten.py @@ -35,13 +35,13 @@ def flatten(in_list, ltypes=(list, tuple), max_level=sys.maxsize): In the following example, the vector is not flattened because it is not given in the ``ltypes`` input. :: - sage: flatten((['Hi',2,vector(QQ,[1,2,3])],(4,5,6))) + sage: flatten((['Hi', 2, vector(QQ, [1,2,3])], (4,5,6))) # needs sage.modules ['Hi', 2, (1, 2, 3), 4, 5, 6] We give the vector type and then even the vector gets flattened:: - sage: tV = sage.modules.vector_rational_dense.Vector_rational_dense - sage: flatten((['Hi',2,vector(QQ,[1,2,3])], (4,5,6)), + sage: tV = sage.modules.vector_rational_dense.Vector_rational_dense # needs sage.modules + sage: flatten((['Hi', 2, vector(QQ, [1,2,3])], (4,5,6)), # needs sage.modules ....: ltypes=(list, tuple, tV)) ['Hi', 2, 1, 2, 3, 4, 5, 6] @@ -52,7 +52,7 @@ def flatten(in_list, ltypes=(list, tuple), max_level=sys.maxsize): sage: flatten([GF(5)]) [Finite Field of size 5] sage: tGF = type(GF(5)) - sage: flatten([GF(5)], ltypes = (list, tuple, tGF)) + sage: flatten([GF(5)], ltypes=(list, tuple, tGF)) [0, 1, 2, 3, 4] Degenerate cases:: diff --git a/src/sage/misc/fpickle.pyx b/src/sage/misc/fpickle.pyx index 793041d1422..37c26e431ba 100644 --- a/src/sage/misc/fpickle.pyx +++ b/src/sage/misc/fpickle.pyx @@ -5,7 +5,6 @@ Function pickling REFERENCE: The python cookbook. """ - import copyreg import pickle import sys @@ -91,6 +90,7 @@ def pickle_function(func): """ return pickle.dumps(func.__code__) + def unpickle_function(pickled): """ Unpickle a pickled function. @@ -106,40 +106,42 @@ def unpickle_function(pickled): return types.FunctionType(recovered, globals()) - def call_pickled_function(fpargs): - import sage.all - from sage.misc.fpickle import unpickle_function + try: + import sage.all as toplevel + except ImportError: + import sage.all__sagemath_categories as toplevel (fp, (args, kwds)) = fpargs - f = eval("unpickle_function(fp)", sage.all.__dict__, {'fp':fp}) - res = eval("f(*args, **kwds)",sage.all.__dict__, {'args':args, 'kwds':kwds, 'f':f}) + f = eval("unpickle_function(fp)", toplevel.__dict__, {'fp': fp}) + res = eval("f(*args, **kwds)", toplevel.__dict__, + {'args': args, 'kwds': kwds, 'f': f}) return ((args, kwds), res) + # The following four methods are taken from twisted.persisted.styles - the # import of twisted.persisted.styles takes a long time and we do not use # most functionality it provides def pickleMethod(method): 'support function for copyreg to pickle method refs' - # Note: On Python 3 there is no .im_class but we can get the instance's - # class through .__self__.__class__ - cls = getattr(method, 'im_class', method.__self__.__class__) - return (unpickleMethod, (method.__func__.__name__, method.__self__, cls)) + if isinstance(method.__self__, type): + # This is a class method, so get it from the type directly + return (getattr, (method.__self__, method.__func__.__name__)) + else: + cls = method.__self__.__class__ + return (unpickleMethod, (method.__func__.__name__, method.__self__, cls)) def unpickleMethod(im_name, - __self__, - im_class): + __self__, + im_class): 'support function for copyreg to unpickle method refs' try: - unbound = getattr(im_class,im_name) + unbound = getattr(im_class, im_name) if __self__ is None: return unbound - # Note: On Python 2 "unbound methods" are just functions, so they don't - # have a __func__ - bound = types.MethodType(getattr(unbound, '__func__', unbound), - __self__) + bound = types.MethodType(unbound, __self__) return bound except AttributeError: assert __self__ is not None, "No recourse: no instance to guess from." @@ -147,28 +149,29 @@ def unpickleMethod(im_name, # changed around since we pickled this method, we may still be # able to get it by looking on the instance's current class. unbound = getattr(__self__.__class__, im_name) - if __self__ is None: - return unbound - bound = types.MethodType(getattr(unbound, '__func__', unbound), - __self__) + bound = types.MethodType(unbound, __self__) return bound + copyreg.pickle(types.MethodType, - pickleMethod, - unpickleMethod) + pickleMethod, + unpickleMethod) oldModules = {} + def pickleModule(module): 'support function for copyreg to pickle module refs' return unpickleModule, (module.__name__,) + def unpickleModule(name): 'support function for copyreg to unpickle module refs' if name in oldModules: name = oldModules[name] - return __import__(name,{},{},'x') + return __import__(name, {}, {}, 'x') + copyreg.pickle(types.ModuleType, pickleModule, diff --git a/src/sage/misc/function_mangling.pyx b/src/sage/misc/function_mangling.pyx index e1bb7978953..1392fc4f2fd 100644 --- a/src/sage/misc/function_mangling.pyx +++ b/src/sage/misc/function_mangling.pyx @@ -157,8 +157,7 @@ cdef class ArgumentFixer: EXAMPLES:: sage: from sage.misc.function_mangling import ArgumentFixer - sage: g = ArgumentFixer(number_of_partitions) - sage: g + sage: g = ArgumentFixer(number_of_partitions); g # needs sage.combinat Argument Fixer of <function number_of_partitions at 0x...> """ return "Argument Fixer of %s"%self.f diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index 9419c145ad8..c922b8f6f12 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -2,7 +2,7 @@ """ Functional notation -These are functions so that you can write foo(x) instead of x.foo() +These are functions so that you can write ``foo(x)`` instead of ``x.foo()`` in certain common cases. AUTHORS: @@ -23,12 +23,14 @@ import builtins import math -from sage.rings.complex_double import CDF -from sage.rings.real_double import RDF, RealDoubleElement -from sage.rings.integer_ring import ZZ -from sage.rings.integer import Integer +from sage.misc.lazy_import import lazy_import from sage.misc.superseded import deprecation +lazy_import('sage.rings.complex_double', 'CDF') +lazy_import('sage.rings.real_double', ['RDF', 'RealDoubleElement']) +lazy_import('sage.rings.integer_ring', 'ZZ') +lazy_import('sage.rings.integer', 'Integer') + ############################################################################## # There are many functions on elements of a ring, which mathematicians # usually write f(x), e.g., it is weird to write x.log() and natural @@ -102,9 +104,9 @@ def basis(x): EXAMPLES:: - sage: V = VectorSpace(QQ,3) - sage: S = V.subspace([[1,2,0],[2,2,-1]]) - sage: basis(S) + sage: V = VectorSpace(QQ, 3) # needs sage.modules + sage: S = V.subspace([[1,2,0], [2,2,-1]]) # needs sage.modules + sage: basis(S) # needs sage.modules [ (1, 0, -1), (0, 1, 1/2) @@ -119,8 +121,8 @@ def category(x): EXAMPLES:: - sage: V = VectorSpace(QQ,3) - sage: category(V) + sage: V = VectorSpace(QQ, 3) # needs sage.modules + sage: category(V) # needs sage.modules Category of finite dimensional vector spaces with basis over (number fields and quotient fields and metric spaces) """ @@ -137,29 +139,31 @@ def characteristic_polynomial(x, var='x'): EXAMPLES:: - sage: M = MatrixSpace(QQ,3,3) + sage: # needs sage.libs.pari sage.modules + sage: M = MatrixSpace(QQ, 3, 3) sage: A = M([1,2,3,4,5,6,7,8,9]) sage: charpoly(A) x^3 - 15*x^2 - 18*x sage: charpoly(A, 't') t^3 - 15*t^2 - 18*t - sage: k.<alpha> = GF(7^10); k + sage: k.<alpha> = GF(7^10); k # needs sage.rings.finite_rings Finite Field in alpha of size 7^10 - sage: alpha.charpoly('T') + sage: alpha.charpoly('T') # needs sage.rings.finite_rings T^10 + T^6 + T^5 + 4*T^4 + T^3 + 2*T^2 + 3*T + 3 - sage: characteristic_polynomial(alpha, 'T') + sage: characteristic_polynomial(alpha, 'T') # needs sage.rings.finite_rings T^10 + T^6 + T^5 + 4*T^4 + T^3 + 2*T^2 + 3*T + 3 Ensure the variable name of the polynomial does not conflict with variables used within the matrix, and that non-integral powers of variables do not confuse the computation (:trac:`14403`):: + sage: # needs sage.libs.pari sage.symbolic sage: y = var('y') - sage: a = matrix([[x,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]) + sage: a = matrix([[x,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]]) sage: characteristic_polynomial(a).list() [x, -3*x - 1, 3*x + 3, -x - 3, 1] - sage: b = matrix([[y^(1/2),0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]) + sage: b = matrix([[y^(1/2),0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]]) sage: charpoly(b).list() [sqrt(y), -3*sqrt(y) - 1, 3*sqrt(y) + 3, -sqrt(y) - 3, 1] """ @@ -195,6 +199,7 @@ def cyclotomic_polynomial(n, var='x'): EXAMPLES:: + sage: # needs sage.libs.pari sage: cyclotomic_polynomial(3) x^2 + x + 1 sage: cyclotomic_polynomial(4) @@ -215,19 +220,21 @@ def decomposition(x): EXAMPLES:: - sage: M = matrix([[2, 3], [3, 4]]) - sage: M.decomposition() + sage: M = matrix([[2, 3], [3, 4]]) # needs sage.libs.pari sage.modules + sage: M.decomposition() # needs sage.libs.pari sage.modules [ (Ambient free module of rank 2 over the principal ideal domain Integer Ring, True) ] + sage: # needs sage.groups sage: G.<a,b> = DirichletGroup(20) - sage: c = a*b + sage: c = a * b sage: d = c.decomposition(); d [Dirichlet character modulo 4 of conductor 4 mapping 3 |--> -1, - Dirichlet character modulo 5 of conductor 5 mapping 2 |--> zeta4] + Dirichlet character modulo 5 of conductor 5 mapping 2 |--> zeta4] sage: d[0].parent() - Group of Dirichlet characters modulo 4 with values in Cyclotomic Field of order 4 and degree 2 + Group of Dirichlet characters modulo 4 + with values in Cyclotomic Field of order 4 and degree 2 """ return x.decomposition() @@ -257,9 +264,9 @@ def det(x): EXAMPLES:: - sage: M = MatrixSpace(QQ,3,3) - sage: A = M([1,2,3,4,5,6,7,8,9]) - sage: det(A) + sage: M = MatrixSpace(QQ, 3, 3) # needs sage.modules + sage: A = M([1,2,3, 4,5,6, 7,8,9]) # needs sage.modules + sage: det(A) # needs sage.modules 0 """ return x.det() @@ -271,9 +278,9 @@ def dimension(x): EXAMPLES:: - sage: V = VectorSpace(QQ,3) - sage: S = V.subspace([[1,2,0],[2,2,-1]]) - sage: dimension(S) + sage: V = VectorSpace(QQ, 3) # needs sage.modules + sage: S = V.subspace([[1,2,0], [2,2,-1]]) # needs sage.modules + sage: dimension(S) # needs sage.modules 2 """ return x.dimension() @@ -289,9 +296,9 @@ def discriminant(x): EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: S = R.quotient(x^29 - 17*x - 1, 'alpha') - sage: K = S.number_field() - sage: discriminant(K) + sage: S = R.quotient(x^29 - 17*x - 1, 'alpha') # needs sage.libs.pari + sage: K = S.number_field() # needs sage.libs.pari sage.rings.number_field + sage: discriminant(K) # needs sage.libs.pari sage.rings.number_field -15975100446626038280218213241591829458737190477345113376757479850566957249523 """ return x.discriminant() @@ -313,7 +320,7 @@ def eta(x): EXAMPLES:: - sage: eta(1+I) + sage: eta(1 + I) # needs sage.symbolic 0.7420487758365647 + 0.1988313702299107*I """ try: @@ -328,9 +335,9 @@ def fcp(x, var='x'): EXAMPLES:: - sage: M = MatrixSpace(QQ,3,3) - sage: A = M([1,2,3,4,5,6,7,8,9]) - sage: fcp(A, 'x') + sage: M = MatrixSpace(QQ, 3, 3) # needs sage.modules + sage: A = M([1,2,3, 4,5,6, 7,8,9]) # needs sage.modules + sage: fcp(A, 'x') # needs sage.libs.pari sage.modules x * (x^2 - 15*x - 18) """ try: @@ -351,8 +358,8 @@ def gen(x): x sage: gen(GF(7)) 1 - sage: A = AbelianGroup(1, [23]) - sage: gen(A) + sage: A = AbelianGroup(1, [23]) # needs sage.groups + sage: gen(A) # needs sage.groups f """ return x.gen() @@ -364,13 +371,14 @@ def gens(x): EXAMPLES:: - sage: R.<x,y> = SR[] - sage: R + sage: R.<x,y> = SR[] # needs sage.symbolic + sage: R # needs sage.symbolic Multivariate Polynomial Ring in x, y over Symbolic Ring - sage: gens(R) + sage: gens(R) # needs sage.symbolic (x, y) - sage: A = AbelianGroup(5, [5,5,7,8,9]) - sage: gens(A) + + sage: A = AbelianGroup(5, [5,5,7,8,9]) # needs sage.groups + sage: gens(A) # needs sage.groups (f0, f1, f2, f3, f4) """ return x.gens() @@ -382,9 +390,10 @@ def hecke_operator(x, n): EXAMPLES:: - sage: M = ModularSymbols(1,12) - sage: hecke_operator(M,5) - Hecke operator T_5 on Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field + sage: M = ModularSymbols(1,12) # needs sage.modular + sage: hecke_operator(M,5) # needs sage.modular + Hecke operator T_5 on Modular Symbols space of dimension 3 for Gamma_0(1) + of weight 12 with sign 0 over Rational Field """ return x.hecke_operator(n) @@ -395,9 +404,9 @@ def image(x): EXAMPLES:: - sage: M = MatrixSpace(QQ,3,3) - sage: A = M([1,2,3,4,5,6,7,8,9]) - sage: image(A) + sage: M = MatrixSpace(QQ, 3, 3) # needs sage.modules + sage: A = M([1,2,3, 4,5,6, 7,8,9]) # needs sage.modules + sage: image(A) # needs sage.modules Vector space of degree 3 and dimension 2 over Rational Field Basis matrix: [ 1 0 -1] @@ -435,18 +444,18 @@ def symbolic_sum(expression, *args, **kwds): EXAMPLES:: - sage: k, n = var('k,n') - sage: sum(k, k, 1, n).factor() + sage: k, n = var('k,n') # needs sage.symbolic + sage: sum(k, k, 1, n).factor() # needs sage.symbolic 1/2*(n + 1)*n :: - sage: sum(1/k^4, k, 1, oo) + sage: sum(1/k^4, k, 1, oo) # needs sage.symbolic 1/90*pi^4 :: - sage: sum(1/k^5, k, 1, oo) + sage: sum(1/k^5, k, 1, oo) # needs sage.symbolic zeta(5) .. WARNING:: @@ -458,9 +467,9 @@ def symbolic_sum(expression, *args, **kwds): In particular, this does not work:: - sage: n = var('n') + sage: n = var('n') # needs sage.symbolic sage: mylist = [1,2,3,4,5] - sage: sum(mylist[n], n, 0, 3) + sage: sum(mylist[n], n, 0, 3) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert n to an integer @@ -472,95 +481,95 @@ def symbolic_sum(expression, *args, **kwds): Also, only a limited number of functions are recognized in symbolic sums:: - sage: sum(valuation(n,2),n,1,5) + sage: sum(valuation(n, 2), n, 1, 5) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert n to an integer Again, use python ``sum()``:: - sage: sum(valuation(n+1,2) for n in range(5)) + sage: sum(valuation(n + 1, 2) for n in range(5)) 3 (now back to the Sage ``sum`` examples) A well known binomial identity:: - sage: sum(binomial(n,k), k, 0, n) + sage: sum(binomial(n, k), k, 0, n) # needs sage.symbolic 2^n The binomial theorem:: - sage: x, y = var('x, y') - sage: sum(binomial(n,k) * x^k * y^(n-k), k, 0, n) + sage: x, y = var('x, y') # needs sage.symbolic + sage: sum(binomial(n, k) * x^k * y^(n-k), k, 0, n) # needs sage.symbolic (x + y)^n :: - sage: sum(k * binomial(n, k), k, 1, n) + sage: sum(k * binomial(n, k), k, 1, n) # needs sage.symbolic 2^(n - 1)*n :: - sage: sum((-1)^k*binomial(n,k), k, 0, n) + sage: sum((-1)^k * binomial(n, k), k, 0, n) # needs sage.symbolic 0 :: - sage: sum(2^(-k)/(k*(k+1)), k, 1, oo) + sage: sum(2^(-k)/(k*(k+1)), k, 1, oo) # needs sage.symbolic -log(2) + 1 Another binomial identity (:trac:`7952`):: - sage: t,k,i = var('t,k,i') - sage: sum(binomial(i+t,t),i,0,k) + sage: t, k, i = var('t,k,i') # needs sage.symbolic + sage: sum(binomial(i + t, t), i, 0, k) # needs sage.symbolic binomial(k + t + 1, t + 1) Summing a hypergeometric term:: - sage: sum(binomial(n, k) * factorial(k) / factorial(n+1+k), k, 0, n) + sage: sum(binomial(n, k) * factorial(k) / factorial(n+1+k), k, 0, n) # needs sage.symbolic 1/2*sqrt(pi)/factorial(n + 1/2) We check a well known identity:: - sage: bool(sum(k^3, k, 1, n) == sum(k, k, 1, n)^2) + sage: bool(sum(k^3, k, 1, n) == sum(k, k, 1, n)^2) # needs sage.symbolic True A geometric sum:: - sage: a, q = var('a, q') - sage: sum(a*q^k, k, 0, n) + sage: a, q = var('a, q') # needs sage.symbolic + sage: sum(a*q^k, k, 0, n) # needs sage.symbolic (a*q^(n + 1) - a)/(q - 1) The geometric series:: - sage: assume(abs(q) < 1) - sage: sum(a*q^k, k, 0, oo) + sage: assume(abs(q) < 1) # needs sage.symbolic + sage: sum(a * q^k, k, 0, oo) # needs sage.symbolic -a/(q - 1) A divergent geometric series. Don't forget to forget your assumptions:: - sage: forget() - sage: assume(q > 1) - sage: sum(a*q^k, k, 0, oo) + sage: forget() # needs sage.symbolic + sage: assume(q > 1) # needs sage.symbolic + sage: sum(a * q^k, k, 0, oo) # needs sage.symbolic Traceback (most recent call last): ... ValueError: Sum is divergent. This summation only Mathematica can perform:: - sage: sum(1/(1+k^2), k, -oo, oo, algorithm = 'mathematica') # optional - mathematica + sage: sum(1/(1+k^2), k, -oo, oo, algorithm='mathematica') # optional - mathematica, needs sage.symbolic pi*coth(pi) Use Maple as a backend for summation:: - sage: sum(binomial(n,k)*x^k, k, 0, n, algorithm = 'maple') # optional - maple + sage: sum(binomial(n, k) * x^k, k, 0, n, algorithm='maple') # optional - maple, needs sage.symbolic (x + 1)^n Python ints should work as limits of summation (:trac:`9393`):: - sage: sum(x, x, 1r, 5r) + sage: sum(x, x, 1r, 5r) # needs sage.symbolic 15 .. note:: @@ -573,9 +582,9 @@ def symbolic_sum(expression, *args, **kwds): Check that :trac:`34007` is fixed:: - sage: sum([1,2], start=1) + sage: sum([1, 2], start=1) 4 - sage: sum([[1],[2]], start=[]) + sage: sum([[1], [2]], start=[]) [1, 2] """ @@ -615,8 +624,9 @@ def symbolic_prod(expression, *args, **kwds): EXAMPLES:: + sage: # needs sage.symbolic sage: i, k, n = var('i,k,n') - sage: product(k,k,1,n) + sage: product(k, k, 1, n) factorial(n) sage: product(x + i*(i+1)/2, i, 1, 4) x^4 + 20*x^3 + 127*x^2 + 288*x + 180 @@ -628,7 +638,7 @@ def symbolic_prod(expression, *args, **kwds): sage: product(f(i), i, 1, n) product(f(i), i, 1, n) sage: assume(k>0) - sage: product(integrate (x^k, x, 0, 1), k, 1, n) + sage: product(integrate(x^k, x, 0, 1), k, 1, n) 1/factorial(n + 1) sage: product(f(i), i, 1, n).log().log_expand() sum(log(f(i)), i, 1, n) @@ -663,38 +673,38 @@ def integral(x, *args, **kwds): :: - sage: integral(sin(x),x) + sage: integral(sin(x), x) # needs sage.symbolic -cos(x) :: - sage: y = var('y') - sage: integral(sin(x),y) + sage: y = var('y') # needs sage.symbolic + sage: integral(sin(x), y) # needs sage.symbolic y*sin(x) :: - sage: integral(sin(x), x, 0, pi/2) + sage: integral(sin(x), x, 0, pi/2) # needs sage.symbolic 1 - sage: sin(x).integral(x, 0,pi/2) + sage: sin(x).integral(x, 0, pi/2) # needs sage.symbolic 1 - sage: integral(exp(-x), (x, 1, oo)) + sage: integral(exp(-x), (x, 1, oo)) # needs sage.symbolic e^(-1) Numerical approximation:: - sage: h = integral(tan(x)/x, (x, 1, pi/3)) + sage: h = integral(tan(x)/x, (x, 1, pi/3)) # needs sage.symbolic ... - sage: h + sage: h # needs sage.symbolic integrate(tan(x)/x, x, 1, 1/3*pi) - sage: h.n() + sage: h.n() # needs sage.symbolic 0.07571599101... Specific algorithm can be used for integration:: - sage: integral(sin(x)^2, x, algorithm='maxima') + sage: integral(sin(x)^2, x, algorithm='maxima') # needs sage.symbolic 1/2*x - 1/4*sin(2*x) - sage: integral(sin(x)^2, x, algorithm='sympy') + sage: integral(sin(x)^2, x, algorithm='sympy') # needs sage.symbolic -1/2*cos(x)*sin(x) + 1/2*x TESTS: @@ -702,8 +712,8 @@ def integral(x, *args, **kwds): A symbolic integral from :trac:`11445` that was incorrect in earlier versions of Maxima:: - sage: f = abs(x - 1) + abs(x + 1) - 2*abs(x) - sage: integrate(f, (x, -Infinity, Infinity)) + sage: f = abs(x - 1) + abs(x + 1) - 2*abs(x) # needs sage.symbolic + sage: integrate(f, (x, -Infinity, Infinity)) # needs sage.symbolic 2 Another symbolic integral, from :trac:`11238`, that used to return @@ -714,58 +724,66 @@ def integral(x, *args, **kwds): with the default settings, so we temporarily use the Maxima setting ``domain: real``:: + sage: # needs sage.symbolic sage: sage.calculus.calculus.maxima('domain: real') real sage: f = exp(-x) * sinh(sqrt(x)) - sage: t = integrate(f, x, 0, Infinity); t # long time - 1/4*sqrt(pi)*(erf(1) - 1)*e^(1/4) - 1/4*(sqrt(pi)*(erf(1) - 1) - sqrt(pi) + 2*e^(-1) - 2)*e^(1/4) + 1/4*sqrt(pi)*e^(1/4) - 1/2*e^(1/4) + 1/2*e^(-3/4) - sage: t.canonicalize_radical() # long time + sage: t = integrate(f, x, 0, Infinity); t # long time + 1/4*sqrt(pi)*(erf(1) - 1)*e^(1/4) + - 1/4*(sqrt(pi)*(erf(1) - 1) - sqrt(pi) + 2*e^(-1) - 2)*e^(1/4) + + 1/4*sqrt(pi)*e^(1/4) - 1/2*e^(1/4) + 1/2*e^(-3/4) + sage: t.canonicalize_radical() # long time 1/2*sqrt(pi)*e^(1/4) sage: sage.calculus.calculus.maxima('domain: complex') complex An integral which used to return -1 before maxima 5.28. See :trac:`12842`:: - sage: f = e^(-2*x)/sqrt(1-e^(-2*x)) - sage: integrate(f, x, 0, infinity) + sage: f = e^(-2*x)/sqrt(1-e^(-2*x)) # needs sage.symbolic + sage: integrate(f, x, 0, infinity) # needs sage.symbolic 1 This integral would cause a stack overflow in earlier versions of Maxima, crashing sage. See :trac:`12377`. We don't care about the result here, just that the computation completes successfully:: - sage: y = (x^2)*exp(x) / (1 + exp(x))^2 - sage: _ = integrate(y, x, -1000, 1000) + sage: y = (x^2)*exp(x) / (1 + exp(x))^2 # needs sage.symbolic + sage: _ = integrate(y, x, -1000, 1000) # needs sage.symbolic When SymPy cannot solve an integral it gives it back, so we must be able to convert SymPy's ``Integral`` (:trac:`14723`):: + sage: # needs sage.symbolic sage: x, y, z = var('x,y,z') sage: f = function('f') sage: integrate(f(x), x, algorithm='sympy') integrate(f(x), x) - sage: integrate(f(x), x, 0, 1,algorithm='sympy') + sage: integrate(f(x), x, 0, 1, algorithm='sympy') integrate(f(x), x, 0, 1) - sage: integrate(integrate(integrate(f(x,y,z), x, algorithm='sympy'), y, algorithm='sympy'), z, algorithm='sympy') + sage: integrate(integrate(integrate(f(x,y,z), x, algorithm='sympy'), + ....: y, algorithm='sympy'), + ....: z, algorithm='sympy') integrate(integrate(integrate(f(x, y, z), x), y), z) sage: integrate(sin(x)*tan(x)/(1-cos(x)), x, algorithm='sympy') -integrate(sin(x)*tan(x)/(cos(x) - 1), x) sage: _ = var('a,b,x') sage: integrate(sin(x)*tan(x)/(1-cos(x)), x, a, b, algorithm='sympy') -integrate(sin(x)*tan(x)/(cos(x) - 1), x, a, b) + + sage: # needs sympy sage: import sympy sage: x, y, z = sympy.symbols('x y z') sage: f = sympy.Function('f') - sage: SR(sympy.Integral(f(x,y,z), x, y, z)) + sage: SR(sympy.Integral(f(x,y,z), x, y, z)) # needs sage.symbolic integrate(integrate(integrate(f(x, y, z), x), y), z) Ensure that the following integral containing a signum term from :trac:`11590` can be integrated:: - sage: x = SR.symbol('x', domain='real') - sage: result = integrate(x * sgn(x^2 - 1/4), x, -1, 0) + sage: x = SR.symbol('x', domain='real') # needs sage.symbolic + sage: result = integrate(x * sgn(x^2 - 1/4), x, -1, 0) # needs sage.symbolic ... - sage: result + sage: result # needs sage.symbolic -1/4 """ @@ -787,11 +805,13 @@ def integral_closure(x): sage: integral_closure(QQ) Rational Field - sage: K.<a> = QuadraticField(5) - sage: O2 = K.order(2*a); O2 - Order in Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? - sage: integral_closure(O2) - Maximal Order in Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? + sage: K.<a> = QuadraticField(5) # needs sage.rings.number_field + sage: O2 = K.order(2 * a); O2 # needs sage.rings.number_field + Order in Number Field in a + with defining polynomial x^2 - 5 with a = 2.236067977499790? + sage: integral_closure(O2) # needs sage.rings.number_field + Maximal Order in Number Field in a + with defining polynomial x^2 - 5 with a = 2.236067977499790? """ return x.integral_closure() @@ -874,9 +894,10 @@ def is_integrally_closed(x): doctest:...DeprecationWarning: use X.is_integrally_closed() See https://github.com/sagemath/sage/issues/32347 for details. True - sage: K.<a> = NumberField(x^2 + 189*x + 394) - sage: R = K.order(2*a) - sage: is_integrally_closed(R) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 189*x + 394) # needs sage.rings.number_field + sage: R = K.order(2*a) # needs sage.rings.number_field + sage: is_integrally_closed(R) # needs sage.rings.number_field False """ deprecation(32347, "use X.is_integrally_closed()") @@ -928,8 +949,9 @@ def kernel(x): EXAMPLES:: - sage: M = MatrixSpace(QQ,3,2) - sage: A = M([1,2,3,4,5,6]) + sage: # needs sage.modules + sage: M = MatrixSpace(QQ, 3, 2) + sage: A = M([1,2, 3,4, 5,6]) sage: kernel(A) Vector space of degree 3 and dimension 1 over Rational Field Basis matrix: @@ -941,7 +963,8 @@ def kernel(x): Here are two corner cases:: - sage: M = MatrixSpace(QQ,0,3) + sage: # needs sage.modules + sage: M = MatrixSpace(QQ, 0, 3) sage: A = M([]) sage: kernel(A) Vector space of degree 0 and dimension 0 over Rational Field @@ -967,7 +990,7 @@ def krull_dimension(x): 0 sage: krull_dimension(ZZ) 1 - sage: krull_dimension(ZZ[sqrt(5)]) + sage: krull_dimension(ZZ[sqrt(5)]) # needs sage.rings.number_field sage.symbolic 1 sage: U.<x,y,z> = PolynomialRing(ZZ,3); U Multivariate Polynomial Ring in x, y, z over Integer Ring @@ -991,8 +1014,8 @@ def lift(x): We lift an element of a quotient polynomial ring:: sage: R.<x> = QQ['x'] - sage: S.<xmod> = R.quo(x^2 + 1) - sage: lift(xmod-7) + sage: S.<xmod> = R.quo(x^2 + 1) # needs sage.libs.pari + sage: lift(xmod - 7) # needs sage.libs.pari x - 7 """ try: @@ -1019,7 +1042,7 @@ def log(*args, **kwds): EXAMPLES:: - sage: log(e^2) + sage: log(e^2) # needs sage.symbolic 2 To change the base of the logarithm, add a second parameter:: @@ -1029,6 +1052,7 @@ def log(*args, **kwds): The synonym ``ln`` can only take one argument:: + sage: # needs sage.symbolic sage: ln(RDF(10)) 2.302585092994046 sage: ln(2.718) @@ -1037,6 +1061,7 @@ def log(*args, **kwds): 0.693147180559945 sage: ln(float(-1)) 3.141592653589793j + sage: ln(complex(-1)) 3.141592653589793j @@ -1049,6 +1074,8 @@ def log(*args, **kwds): 10 sage: RDF(log(1024, 2)) 10.0 + + sage: # needs sage.symbolic sage: log(10, 4) 1/2*log(10)/log(2) sage: RDF(log(10, 4)) @@ -1066,15 +1093,16 @@ def log(*args, **kwds): numbers, and symbolic numbers too, picking the branch with angle between `-\\pi` and `\\pi`:: - sage: log(-1+0*I) + sage: log(-1+0*I) # needs sage.symbolic I*pi - sage: log(CC(-1)) + sage: log(CC(-1)) # needs sage.rings.real_mpfr 3.14159265358979*I - sage: log(-1.0) + sage: log(-1.0) # needs sage.symbolic 3.14159265358979*I Small integer powers are factored out immediately:: + sage: # needs sage.symbolic sage: log(4) 2*log(2) sage: log(1000000000) @@ -1086,7 +1114,8 @@ def log(*args, **kwds): The ``hold`` parameter can be used to prevent automatic evaluation:: - sage: log(-1,hold=True) + sage: # needs sage.symbolic + sage: log(-1, hold=True) log(-1) sage: log(-1) I*pi @@ -1097,23 +1126,24 @@ def log(*args, **kwds): For input zero, the following behavior occurs:: - sage: log(0) + sage: log(0) # needs sage.symbolic -Infinity - sage: log(CC(0)) + sage: log(CC(0)) # needs sage.rings.real_mpfr -infinity - sage: log(0.0) + sage: log(0.0) # needs sage.symbolic -infinity The log function also works in finite fields as long as the argument lies in the multiplicative group generated by the base:: + sage: # needs sage.libs.pari sage: F = GF(13); g = F.multiplicative_generator(); g 2 sage: a = F(8) - sage: log(a,g); g^log(a,g) + sage: log(a, g); g^log(a, g) 3 8 - sage: log(a,3) + sage: log(a, 3) Traceback (most recent call last): ... ValueError: no logarithm of 8 found to base 3 modulo 13 @@ -1123,11 +1153,11 @@ def log(*args, **kwds): The log function also works for p-adics (see documentation for p-adics for more information):: - sage: R = Zp(5); R + sage: R = Zp(5); R # needs sage.rings.padics 5-adic Ring with capped relative precision 20 - sage: a = R(16); a + sage: a = R(16); a # needs sage.rings.padics 1 + 3*5 + O(5^20) - sage: log(a) + sage: log(a) # needs sage.rings.padics 3*5 + 3*5^2 + 3*5^4 + 3*5^5 + 3*5^6 + 4*5^7 + 2*5^8 + 5^9 + 5^11 + 2*5^12 + 5^13 + 3*5^15 + 2*5^16 + 4*5^17 + 3*5^18 + 3*5^19 + O(5^20) @@ -1137,26 +1167,26 @@ def log(*args, **kwds): Check if :trac:`10136` is fixed:: - sage: ln(x).operator() is ln + sage: ln(x).operator() is ln # needs sage.symbolic True - sage: log(x).operator() is ln + sage: log(x).operator() is ln # needs sage.symbolic True sage: log(1000, 10) 3 - sage: log(3,-1) + sage: log(3, -1) # needs sage.symbolic -I*log(3)/pi - sage: log(int(8),2) + sage: log(int(8), 2) # needs sage.symbolic 3 - sage: log(8,int(2)) + sage: log(8, int(2)) 3 - sage: log(8,2) + sage: log(8, 2) 3 - sage: log(1/8,2) + sage: log(1/8, 2) -3 - sage: log(1/8,1/2) + sage: log(1/8, 1/2) 3 - sage: log(8,1/2) + sage: log(8, 1/2) -3 sage: log(1000, 10, base=5) @@ -1196,14 +1226,15 @@ def minimal_polynomial(x, var='x'): EXAMPLES:: + sage: # needs sage.libs.pari sage.modules sage: a = matrix(ZZ, 2, [1..4]) sage: minpoly(a) x^2 - 5*x - 2 - sage: minpoly(a,'t') + sage: minpoly(a, 't') t^2 - 5*t - 2 sage: minimal_polynomial(a) x^2 - 5*x - 2 - sage: minimal_polynomial(a,'theta') + sage: minimal_polynomial(a, 'theta') theta^2 - 5*theta - 2 """ try: @@ -1218,16 +1249,16 @@ def minimal_polynomial(x, var='x'): def multiplicative_order(x): r""" Return the multiplicative order of ``x``, if ``x`` is a unit, or - raise ``ArithmeticError`` otherwise. + raise :class:`ArithmeticError` otherwise. EXAMPLES:: - sage: a = mod(5,11) - sage: multiplicative_order(a) + sage: a = mod(5, 11) + sage: multiplicative_order(a) # needs sage.libs.pari 5 - sage: multiplicative_order(mod(2,11)) + sage: multiplicative_order(mod(2, 11)) # needs sage.libs.pari 10 - sage: multiplicative_order(mod(2,12)) + sage: multiplicative_order(mod(2, 12)) # needs sage.libs.pari Traceback (most recent call last): ... ArithmeticError: multiplicative order of 2 not defined since it is not a unit modulo 12 @@ -1241,12 +1272,12 @@ def ngens(x): EXAMPLES:: - sage: R.<x,y> = SR[]; R + sage: R.<x,y> = SR[]; R # needs sage.symbolic Multivariate Polynomial Ring in x, y over Symbolic Ring - sage: ngens(R) + sage: ngens(R) # needs sage.symbolic 2 - sage: A = AbelianGroup(5, [5,5,7,8,9]) - sage: ngens(A) + sage: A = AbelianGroup(5, [5,5,7,8,9]) # needs sage.groups + sage: ngens(A) # needs sage.groups 5 sage: ngens(ZZ) 1 @@ -1317,6 +1348,7 @@ def norm(x): The norm of vectors:: + sage: # needs sage.modules sage.symbolic sage: z = 1 + 2*I sage: norm(vector([z])) sqrt(5) @@ -1330,6 +1362,7 @@ def norm(x): The norm of matrices:: + sage: # needs sage.modules sage.symbolic sage: z = 1 + 2*I sage: norm(matrix([[z]])) 2.23606797749979 @@ -1343,6 +1376,7 @@ def norm(x): The norm of complex numbers:: + sage: # needs sage.symbolic sage: z = 2 - 3*I sage: norm(z) 13 @@ -1354,6 +1388,7 @@ def norm(x): The complex norm of symbolic expressions:: + sage: # needs sage.symbolic sage: a, b, c = var("a, b, c") sage: assume((a, 'real'), (b, 'real'), (c, 'real')) sage: z = a + b*I @@ -1415,6 +1450,7 @@ def numerical_approx(x, prec=None, digits=None, algorithm=None): EXAMPLES:: + sage: # needs sage.symbolic sage: numerical_approx(pi, 10) 3.1 sage: numerical_approx(pi, digits=10) @@ -1427,6 +1463,8 @@ def numerical_approx(x, prec=None, digits=None, algorithm=None): 12.5878862295484 sage: n(pi^2 + e, digits=50) 12.587886229548403854194778471228813633070946500941 + + sage: # needs sage.rings.real_mpfr sage: a = CC(-5).n(prec=40) sage: b = ComplexField(40)(-5) sage: a == b @@ -1438,17 +1476,18 @@ def numerical_approx(x, prec=None, digits=None, algorithm=None): You can also usually use method notation:: - sage: (pi^2 + e).n() + sage: (pi^2 + e).n() # needs sage.symbolic 12.5878862295484 - sage: (pi^2 + e).numerical_approx() + sage: (pi^2 + e).numerical_approx() # needs sage.symbolic 12.5878862295484 Vectors and matrices may also have their entries approximated:: - sage: v = vector(RDF, [1,2,3]) - sage: v.n() + sage: v = vector(RDF, [1,2,3]) # needs sage.modules + sage: v.n() # needs sage.modules (1.00000000000000, 2.00000000000000, 3.00000000000000) + sage: # needs sage.modules sage: v = vector(CDF, [1,2,3]) sage: v.n() (1.00000000000000, 2.00000000000000, 3.00000000000000) @@ -1457,12 +1496,13 @@ def numerical_approx(x, prec=None, digits=None, algorithm=None): sage: v.n(prec=20) (1.0000, 2.0000, 3.0000) - sage: u = vector(QQ, [1/2, 1/3, 1/4]) - sage: n(u, prec=15) + sage: u = vector(QQ, [1/2, 1/3, 1/4]) # needs sage.modules + sage: n(u, prec=15) # needs sage.modules (0.5000, 0.3333, 0.2500) - sage: n(u, digits=5) + sage: n(u, digits=5) # needs sage.modules (0.50000, 0.33333, 0.25000) + sage: # needs sage.modules sage: v = vector(QQ, [1/2, 0, 0, 1/3, 0, 0, 0, 1/4], sparse=True) sage: u = v.numerical_approx(digits=4) sage: u.is_sparse() @@ -1470,11 +1510,11 @@ def numerical_approx(x, prec=None, digits=None, algorithm=None): sage: u (0.5000, 0.0000, 0.0000, 0.3333, 0.0000, 0.0000, 0.0000, 0.2500) + sage: # needs sage.modules sage: A = matrix(QQ, 2, 3, range(6)) sage: A.n() [0.000000000000000 1.00000000000000 2.00000000000000] [ 3.00000000000000 4.00000000000000 5.00000000000000] - sage: B = matrix(Integers(12), 3, 8, srange(24)) sage: N(B, digits=2) [0.00 1.0 2.0 3.0 4.0 5.0 6.0 7.0] @@ -1485,28 +1525,28 @@ def numerical_approx(x, prec=None, digits=None, algorithm=None): Therefore, numbers which look the same in their decimal expansion might be different:: - sage: x=N(pi, digits=3); x + sage: x = N(pi, digits=3); x # needs sage.symbolic 3.14 - sage: y=N(3.14, digits=3); y + sage: y = N(3.14, digits=3); y # needs sage.rings.real_mpfr 3.14 - sage: x==y + sage: x == y # needs sage.rings.real_mpfr sage.symbolic False - sage: x.str(base=2) + sage: x.str(base=2) # needs sage.symbolic '11.001001000100' - sage: y.str(base=2) + sage: y.str(base=2) # needs sage.rings.real_mpfr '11.001000111101' Increasing the precision of a floating point number is not allowed:: - sage: CC(-5).n(prec=100) + sage: CC(-5).n(prec=100) # needs sage.rings.real_mpfr Traceback (most recent call last): ... TypeError: cannot approximate to a precision of 100 bits, use at most 53 bits - sage: n(1.3r, digits=20) + sage: n(1.3r, digits=20) # needs sage.rings.real_mpfr Traceback (most recent call last): ... TypeError: cannot approximate to a precision of 70 bits, use at most 53 bits - sage: RealField(24).pi().n() + sage: RealField(24).pi().n() # needs sage.rings.real_mpfr Traceback (most recent call last): ... TypeError: cannot approximate to a precision of 53 bits, use at most 24 bits @@ -1514,6 +1554,7 @@ def numerical_approx(x, prec=None, digits=None, algorithm=None): As an exceptional case, ``digits=1`` usually leads to 2 digits (one significant) in the decimal output (see :trac:`11647`):: + sage: # needs sage.symbolic sage: N(pi, digits=1) 3.2 sage: N(pi, digits=2) @@ -1526,33 +1567,33 @@ def numerical_approx(x, prec=None, digits=None, algorithm=None): In the following example, ``pi`` and ``3`` are both approximated to two bits of precision and then subtracted, which kills two bits of precision:: - sage: N(pi, prec=2) + sage: N(pi, prec=2) # needs sage.symbolic 3.0 - sage: N(3, prec=2) + sage: N(3, prec=2) # needs sage.rings.real_mpfr 3.0 - sage: N(pi - 3, prec=2) + sage: N(pi - 3, prec=2) # needs sage.symbolic 0.00 TESTS:: - sage: numerical_approx(I) + sage: numerical_approx(I) # needs sage.symbolic 1.00000000000000*I sage: x = QQ['x'].gen() - sage: F.<k> = NumberField(x^2+2, embedding=sqrt(CC(2))*CC.0) - sage: numerical_approx(k) + sage: F.<k> = NumberField(x^2 + 2, embedding=sqrt(CC(2))*CC.0) # needs sage.rings.number_field sage.symbolic + sage: numerical_approx(k) # needs sage.rings.number_field sage.symbolic 1.41421356237309*I - sage: type(numerical_approx(CC(1/2))) + sage: type(numerical_approx(CC(1/2))) # needs sage.rings.real_mpfr <class 'sage.rings.complex_mpfr.ComplexNumber'> The following tests :trac:`10761`, in which ``n()`` would break when called on complex-valued algebraic numbers. :: - sage: E = matrix(3, [3,1,6,5,2,9,7,3,13]).eigenvalues(); E + sage: E = matrix(3, [3,1,6,5,2,9,7,3,13]).eigenvalues(); E # needs sage.modules sage.rings.number_field [18.16815365088822?, -0.08407682544410650? - 0.2190261484802906?*I, -0.08407682544410650? + 0.2190261484802906?*I] - sage: E[1].parent() + sage: E[1].parent() # needs sage.modules sage.rings.number_field Algebraic Field - sage: [a.n() for a in E] + sage: [a.n() for a in E] # needs sage.modules sage.rings.number_field [18.1681536508882, -0.0840768254441065 - 0.219026148480291*I, -0.0840768254441065 + 0.219026148480291*I] Make sure we've rounded up log(10,2) enough to guarantee @@ -1561,20 +1602,20 @@ def numerical_approx(x, prec=None, digits=None, algorithm=None): sage: ks = 4*10**5, 10**6 sage: check_str_length = lambda k: len(str(numerical_approx(1+10**-k,digits=k+1)))-1 >= k+1 sage: check_precision = lambda k: numerical_approx(1+10**-k,digits=k+1)-1 > 0 - sage: all(check_str_length(k) and check_precision(k) for k in ks) + sage: all(check_str_length(k) and check_precision(k) for k in ks) # needs sage.rings.real_mpfr True Testing we have sufficient precision for the golden ratio (:trac:`12163`), note that the decimal point adds 1 to the string length:: - sage: len(str(n(golden_ratio, digits=5000))) + sage: len(str(n(golden_ratio, digits=5000))) # needs sage.symbolic 5001 - sage: len(str(n(golden_ratio, digits=5000000))) # long time (4s on sage.math, 2012) + sage: len(str(n(golden_ratio, digits=5000000))) # long time (4s on sage.math, 2012), needs sage.symbolic 5000001 Check that :trac:`14778` is fixed:: - sage: n(0, algorithm='foo') + sage: n(0, algorithm='foo') # needs sage.rings.real_mpfr 0.000000000000000 """ if prec is None: @@ -1628,8 +1669,8 @@ def order(x): EXAMPLES:: - sage: C = CyclicPermutationGroup(10) - sage: order(C) + sage: C = CyclicPermutationGroup(10) # needs sage.groups + sage: order(C) # needs sage.groups 10 sage: F = GF(7) sage: order(F) @@ -1646,15 +1687,15 @@ def rank(x): We compute the rank of a matrix:: - sage: M = MatrixSpace(QQ,3,3) - sage: A = M([1,2,3,4,5,6,7,8,9]) - sage: rank(A) + sage: M = MatrixSpace(QQ, 3, 3) # needs sage.modules + sage: A = M([1,2,3, 4,5,6, 7,8,9]) # needs sage.modules + sage: rank(A) # needs sage.modules 2 We compute the rank of an elliptic curve:: - sage: E = EllipticCurve([0,0,1,-1,0]) - sage: rank(E) + sage: E = EllipticCurve([0,0,1,-1,0]) # needs sage.schemes + sage: rank(E) # needs sage.schemes 1 """ return x.rank() @@ -1666,9 +1707,10 @@ def regulator(x): EXAMPLES:: - sage: regulator(NumberField(x^2-2, 'a')) + sage: x = polygen(ZZ, 'x') + sage: regulator(NumberField(x^2 - 2, 'a')) # needs sage.rings.number_field 0.881373587019543 - sage: regulator(EllipticCurve('11a')) + sage: regulator(EllipticCurve('11a')) # needs sage.schemes 1.00000000000000 """ return x.regulator() @@ -1684,9 +1726,10 @@ def round(x, ndigits=0): EXAMPLES:: - sage: round(sqrt(2),2) + sage: # needs sage.symbolic + sage: round(sqrt(2), 2) 1.41 - sage: q = round(sqrt(2),5); q + sage: q = round(sqrt(2), 5); q 1.41421 sage: type(q) <class 'sage.rings.real_double...RealDoubleElement...'> @@ -1696,6 +1739,7 @@ def round(x, ndigits=0): <class 'sage.rings.integer.Integer'> sage: round(pi) 3 + sage: b = 5.4999999999999999 sage: round(b) 5 @@ -1708,7 +1752,7 @@ def round(x, ndigits=0): Since we use floating-point with a limited range, some roundings can't be performed:: - sage: round(sqrt(Integer('1'*1000)),2) + sage: round(sqrt(Integer('1'*1000)), 2) # needs sage.symbolic +infinity IMPLEMENTATION: If ndigits is specified, it calls Python's builtin @@ -1752,8 +1796,8 @@ def quotient(x, y, *args, **kwds): 0.833333333333333 sage: R.<x> = ZZ[]; R Univariate Polynomial Ring in x over Integer Ring - sage: I = Ideal(R, x^2+1) - sage: quotient(R, I) + sage: I = Ideal(R, x^2 + 1) + sage: quotient(R, I) # needs sage.libs.pari Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1 """ try: @@ -1806,7 +1850,7 @@ def squarefree_part(x): sage: x = QQ['x'].0 sage: S = squarefree_part(-9*x*(x-6)^7*(x-3)^2); S -9*x^2 + 54*x - sage: S.factor() + sage: S.factor() # needs sage.libs.pari (-9) * (x - 6) * x :: @@ -1815,7 +1859,7 @@ def squarefree_part(x): x^10 - x^9 + 3*x^8 + 3*x^5 - 2*x^4 - x^3 - 2*x - 1 sage: g = squarefree_part(f); g x^4 - x^3 + x^2 - 1 - sage: g.factor() + sage: g.factor() # needs sage.libs.pari (x - 1) * (x^3 + x + 1) """ try: @@ -1834,43 +1878,42 @@ def squarefree_part(x): def _do_sqrt(x, prec=None, extend=True, all=False): r""" - Used internally to compute the square root of x. + Used internally to compute the square root of ``x``. INPUT: - - ``x`` - a number + - ``x`` -- a number - - ``prec`` - None (default) or a positive integer - (bits of precision) If not None, then compute the square root - numerically to prec bits of precision. + - ``prec`` -- a positive integer (default: ``None``); when specified, + compute the square root with ``prec`` bits of precision - - ``extend`` - bool (default: True); this is a place - holder, and is always ignored since in the symbolic ring everything + - ``extend`` -- bool (default: ``True``); this is a placeholder, and is + always ignored since in the symbolic ring everything has a square root. - - ``extend`` - bool (default: True); whether to extend + - ``extend`` -- bool (default: ``True``); whether to extend the base ring to find roots. The extend parameter is ignored if - prec is a positive integer. + ``prec`` is a positive integer. - - ``all`` - bool (default: False); whether to return - a list of all the square roots of x. + - ``all`` -- bool (default: ``False``); whether to return + a list of all the square roots of ``x``. EXAMPLES:: sage: from sage.misc.functional import _do_sqrt - sage: _do_sqrt(3) + sage: _do_sqrt(3) # needs sage.symbolic sqrt(3) - sage: _do_sqrt(3,prec=10) + sage: _do_sqrt(3, prec=10) # needs sage.rings.real_mpfr 1.7 - sage: _do_sqrt(3,prec=100) + sage: _do_sqrt(3, prec=100) # needs sage.rings.real_mpfr 1.7320508075688772935274463415 - sage: _do_sqrt(3,all=True) + sage: _do_sqrt(3, all=True) # needs sage.symbolic [sqrt(3), -sqrt(3)] Note that the extend parameter is ignored in the symbolic ring:: - sage: _do_sqrt(3,extend=False) + sage: _do_sqrt(3, extend=False) # needs sage.symbolic sqrt(3) """ if prec: @@ -1881,8 +1924,7 @@ def _do_sqrt(x, prec=None, extend=True, all=False): from sage.rings.complex_mpfr import ComplexField return ComplexField(prec)(x).sqrt(all=all) if x == -1: - from sage.symbolic.expression import I - z = I + from sage.symbolic.constants import I as z else: from sage.symbolic.ring import SR z = SR(x).sqrt() @@ -1899,43 +1941,45 @@ def sqrt(x, *args, **kwds): r""" INPUT: - - ``x`` - a number + - ``x`` -- a number - - ``prec`` - integer (default: None): if None, returns + - ``prec`` -- integer (default: ``None``): if ``None``, returns an exact square root; otherwise returns a numerical square root if necessary, to the given bits of precision. - - ``extend`` - bool (default: True); this is a place - holder, and is always ignored or passed to the sqrt function for x, + - ``extend`` -- bool (default: ``True``); this is a placeholder, and + is always ignored or passed to the ``sqrt`` method of ``x``, since in the symbolic ring everything has a square root. - - ``all`` - bool (default: False); if True, return all - square roots of self, instead of just one. + - ``all`` -- bool (default: ``False``); if ``True``, return all + square roots of ``self``, instead of just one. EXAMPLES:: + sage: sqrt(4) + 2 + sage: sqrt(4, all=True) + [2, -2] + + sage: # needs sage.symbolic sage: sqrt(-1) I sage: sqrt(2) sqrt(2) sage: sqrt(2)^2 2 - sage: sqrt(4) - 2 - sage: sqrt(4,all=True) - [2, -2] sage: sqrt(x^2) sqrt(x^2) For a non-symbolic square root, there are a few options. The best is to numerically approximate afterward:: - sage: sqrt(2).n() + sage: sqrt(2).n() # needs sage.symbolic 1.41421356237310 - sage: sqrt(2).n(prec=100) + sage: sqrt(2).n(prec=100) # needs sage.symbolic 1.4142135623730950488016887242 - Or one can input a numerical type. + Or one can input a numerical type:: sage: sqrt(2.) 1.41421356237310 @@ -1947,9 +1991,9 @@ def sqrt(x, *args, **kwds): To prevent automatic evaluation, one can use the ``hold`` parameter after coercing to the symbolic ring:: - sage: sqrt(SR(4),hold=True) + sage: sqrt(SR(4), hold=True) # needs sage.symbolic sqrt(4) - sage: sqrt(4,hold=True) + sage: sqrt(4, hold=True) Traceback (most recent call last): ... TypeError: ..._do_sqrt() got an unexpected keyword argument 'hold' @@ -1961,16 +2005,16 @@ def sqrt(x, *args, **kwds): Traceback (most recent call last): ... TypeError: ...sqrt() got an unexpected keyword argument 'prec' - sage: sqrt(a, prec=100) + sage: sqrt(a, prec=100) # needs sage.rings.real_mpfr 1.0488088481701515469914535137 - sage: sqrt(4.00, prec=250) + sage: sqrt(4.00, prec=250) # needs sage.rings.real_mpfr 2.0000000000000000000000000000000000000000000000000000000000000000000000000 One can use numpy input as well:: - sage: import numpy - sage: a = numpy.arange(2,5) - sage: sqrt(a) + sage: import numpy # needs numpy + sage: a = numpy.arange(2,5) # needs numpy + sage: sqrt(a) # needs numpy array([1.41421356, 1.73205081, 2. ]) """ if isinstance(x, float): @@ -1994,9 +2038,9 @@ def transpose(x): EXAMPLES:: - sage: M = MatrixSpace(QQ,3,3) - sage: A = M([1,2,3,4,5,6,7,8,9]) - sage: transpose(A) + sage: M = MatrixSpace(QQ, 3, 3) # needs sage.modules + sage: A = M([1,2,3, 4,5,6, 7,8,9]) # needs sage.modules + sage: transpose(A) # needs sage.modules [1 4 7] [2 5 8] [3 6 9] diff --git a/src/sage/misc/gperftools.py b/src/sage/misc/gperftools.py index 55ee572b8c4..b928ef18e08 100644 --- a/src/sage/misc/gperftools.py +++ b/src/sage/misc/gperftools.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ C Function Profiler Using Google Perftools @@ -47,7 +48,6 @@ libprofiler = None - class Profiler(SageObject): def __init__(self, filename=None): diff --git a/src/sage/misc/inherit_comparison.pyx b/src/sage/misc/inherit_comparison.pyx index 7582215291a..aa97f664496 100644 --- a/src/sage/misc/inherit_comparison.pyx +++ b/src/sage/misc/inherit_comparison.pyx @@ -51,8 +51,11 @@ cdef class InheritComparisonMetaclass(type): EXAMPLES:: - sage: cython( # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython( ....: ''' + ....: cimport cython + ....: ....: from sage.misc.inherit_comparison cimport InheritComparisonMetaclass ....: ....: cdef class Base(): @@ -65,17 +68,18 @@ cdef class InheritComparisonMetaclass(type): ....: return 1 ....: ....: cdef class DerivedWithRichcmp(Base): + ....: @cython.always_allow_keywords(False) ....: def __getmetaclass__(_): ....: from sage.misc.inherit_comparison import InheritComparisonMetaclass ....: return InheritComparisonMetaclass ....: def __hash__(self): ....: return 1 ....: ''') - sage: a = Derived() # optional - sage.misc.cython - sage: a == a # optional - sage.misc.cython + sage: a = Derived() + sage: a == a True - sage: b = DerivedWithRichcmp() # optional - sage.misc.cython - sage: b == b # optional - sage.misc.cython + sage: b = DerivedWithRichcmp() + sage: b == b Calling Base.__richcmp__ True """ diff --git a/src/sage/misc/inline_fortran.py b/src/sage/misc/inline_fortran.py index 6e71016c427..5d4fc7831bb 100644 --- a/src/sage/misc/inline_fortran.py +++ b/src/sage/misc/inline_fortran.py @@ -65,8 +65,8 @@ class InlineFortran: def __init__(self, globals=None): # globals=None means: use user globals from REPL self.globs = globals - self.library_paths=[] - self.libraries=[] + self.library_paths = [] + self.libraries = [] self.verbose = False def __repr__(self): @@ -91,6 +91,7 @@ def eval(self, x, globals=None, locals=None): EXAMPLES:: + sage: # needs numpy sage: code = ''' ....: C FILE: FIB1.F ....: SUBROUTINE FIB(A,N) diff --git a/src/sage/misc/instancedoc.pyx b/src/sage/misc/instancedoc.pyx index 360d3f768b3..d8e1e4ac536 100644 --- a/src/sage/misc/instancedoc.pyx +++ b/src/sage/misc/instancedoc.pyx @@ -36,7 +36,8 @@ EXAMPLES:: For a Cython ``cdef class``, a decorator cannot be used. Instead, call :func:`instancedoc` as a function after defining the class:: - sage: cython(''' + sage: cython( # needs sage.misc.cython + ....: ''' ....: from sage.misc.instancedoc import instancedoc ....: cdef class Y: ....: "Class docstring" @@ -44,9 +45,9 @@ For a Cython ``cdef class``, a decorator cannot be used. Instead, call ....: return "Instance docstring" ....: instancedoc(Y) ....: ''') - sage: Y.__doc__ + sage: Y.__doc__ # needs sage.misc.cython 'File:...\nClass docstring' - sage: Y().__doc__ + sage: Y().__doc__ # needs sage.misc.cython 'Instance docstring' One can still add a custom ``__doc__`` attribute on a particular @@ -59,7 +60,7 @@ instance:: This normally does not work on extension types:: - sage: Y().__doc__ = "Very special doc" + sage: Y().__doc__ = "Very special doc" # needs sage.misc.cython Traceback (most recent call last): ... AttributeError: attribute '__doc__' of 'Y' objects is not writable diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 5dc3fbe5ecd..25b1ff557be 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -184,7 +184,8 @@ def list_function(x): '\\left[1, 2, 3\\right]' sage: latex([1,2,3]) # indirect doctest \left[1, 2, 3\right] - sage: latex([Matrix(ZZ,3,range(9)), Matrix(ZZ,3,range(9))]) # indirect doctest + sage: latex([Matrix(ZZ, 3, range(9)), # indirect doctest # needs sage.modules + ....: Matrix(ZZ, 3, range(9))]) \left[\left(\begin{array}{rrr} 0 & 1 & 2 \\ 3 & 4 & 5 \\ @@ -366,6 +367,7 @@ def dict_function(x): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.misc.latex import dict_function sage: x,y,z = var('x,y,z') sage: print(dict_function({x/2: y^2})) @@ -450,9 +452,9 @@ class LatexExpr(str): EXAMPLES:: - sage: latex(x^20 + 1) + sage: latex(x^20 + 1) # needs sage.symbolic x^{20} + 1 - sage: LatexExpr(r"\frac{x^2 + 1}{x - 2}") + sage: LatexExpr(r"\frac{x^2 + 1}{x - 2}") # needs sage.symbolic \frac{x^2 + 1}{x - 2} ``LatexExpr`` simply converts to string without doing anything @@ -465,15 +467,15 @@ class LatexExpr(str): The result of :func:`latex` is of type ``LatexExpr``:: - sage: L = latex(x^20 + 1) - sage: L + sage: L = latex(x^20 + 1) # needs sage.symbolic + sage: L # needs sage.symbolic x^{20} + 1 - sage: type(L) + sage: type(L) # needs sage.symbolic <class 'sage.misc.latex.LatexExpr'> A ``LatexExpr`` can be converted to a plain string:: - sage: str(latex(x^20 + 1)) + sage: str(latex(x^20 + 1)) # needs sage.symbolic 'x^{20} + 1' """ def __add__(self, other): @@ -558,7 +560,7 @@ def has_latex_attr(x) -> bool: EXAMPLES:: sage: from sage.misc.latex import has_latex_attr - sage: has_latex_attr(identity_matrix(3)) + sage: has_latex_attr(identity_matrix(3)) # needs sage.modules True sage: has_latex_attr("abc") # strings have no _latex_ method False @@ -566,6 +568,7 @@ def has_latex_attr(x) -> bool: Types inherit the ``_latex_`` method of the class to which they refer, but calling it is broken:: + sage: # needs sage.modules sage: T = type(identity_matrix(3)); T <class 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'> sage: hasattr(T, '_latex_') @@ -647,6 +650,7 @@ def latex_extra_preamble(): \newcommand{\RLF}{\Bold{R}} \newcommand{\SL}{\mathrm{SL}} \newcommand{\PSL}{\mathrm{PSL}} + \newcommand{\lcm}{\mathop{\operatorname{lcm}}} \newcommand{\Bold}[1]{\mathbf{#1}} <BLANKLINE> """ @@ -917,12 +921,12 @@ def __call__(self, x, combine_all=False): 3 sage: latex(1==0) \mathrm{False} - sage: print(latex([x,2])) + sage: print(latex([x, 2])) # needs sage.symbolic \left[x, 2\right] Check that :trac:`11775` is fixed:: - sage: latex((x,2), combine_all=True) + sage: latex((x,2), combine_all=True) # needs sage.symbolic x 2 """ if has_latex_attr(x): @@ -961,9 +965,9 @@ class Latex(LatexCall): EXAMPLES:: - sage: latex(x^20 + 1) + sage: latex(x^20 + 1) # needs sage.symbolic x^{20} + 1 - sage: latex(FiniteField(25,'a')) + sage: latex(FiniteField(25,'a')) # needs sage.rings.finite_rings \Bold{F}_{5^{2}} sage: latex("hello") \text{\texttt{hello}} @@ -973,7 +977,7 @@ class Latex(LatexCall): LaTeX expressions can be added; note that a space is automatically inserted:: - sage: LatexExpr(r"y \neq") + latex(x^20 + 1) + sage: LatexExpr(r"y \neq") + latex(x^20 + 1) # needs sage.symbolic y \neq x^{20} + 1 """ def __init__(self, debug=False, slide=False, density=150, pdflatex=None, engine=None): @@ -1212,6 +1216,7 @@ def matrix_delimiters(self, left=None, right=None): EXAMPLES:: + sage: # needs sage.modules sage: a = matrix(1, 1, [17]) sage: latex(a) \left(\begin{array}{r} @@ -1273,6 +1278,7 @@ def vector_delimiters(self, left=None, right=None): EXAMPLES:: + sage: # needs sage.modules sage: a = vector(QQ, [1,2,3]) sage: latex(a) \left(1,\,2,\,3\right) @@ -1318,6 +1324,7 @@ def matrix_column_alignment(self, align=None): EXAMPLES:: + sage: # needs sage.modules sage: a = matrix(1, 1, [42]) sage: latex(a) \left(\begin{array}{r} @@ -1967,7 +1974,7 @@ def png(x, filename, density=150, debug=False, sage: from sage.misc.latex import png sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # random, optional - latex imagemagick + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # random # optional - imagemagick latex, needs sage.plot ....: png(ZZ[x], f.name) """ if not pdflatex: @@ -2019,7 +2026,7 @@ def coeff_repr(c): sage: from sage.misc.latex import coeff_repr sage: coeff_repr(QQ(1/2)) '\\frac{1}{2}' - sage: coeff_repr(-x^2) + sage: coeff_repr(-x^2) # needs sage.symbolic '\\left(-x^{2}\\right)' """ try: @@ -2067,9 +2074,9 @@ def repr_lincomb(symbols, coeffs): Verify that :trac:`17299` (latex representation of modular symbols) is fixed:: - sage: x = EllipticCurve('64a1').modular_symbol_space(sign=1).basis()[0] + sage: x = EllipticCurve('64a1').modular_symbol_space(sign=1).basis()[0] # needs sage.schemes sage: from sage.misc.latex import repr_lincomb - sage: latex(x.modular_symbol_rep()) + sage: latex(x.modular_symbol_rep()) # needs sage.schemes \left\{\frac{-3}{11}, \frac{-1}{4}\right\} - \left\{\frac{3}{13}, \frac{1}{4}\right\} Verify that it works when the symbols are numbers:: @@ -2198,8 +2205,8 @@ def latex_varify(a, is_fname=False): TESTS: - sage: abc = var('abc') - sage: latex((abc/(abc+1)+42)/(abc-1)) # trac #15870 + sage: abc = var('abc') # needs sage.symbolic + sage: latex((abc/(abc+1)+42)/(abc-1)) # trac #15870 # needs sage.symbolic \frac{\frac{\mathit{abc}}{\mathit{abc} + 1} + 42}{\mathit{abc} - 1} """ if a in common_varnames: @@ -2270,12 +2277,12 @@ def latex_variable_name(x, is_fname=False): TESTS:: - sage: latex_variable_name('_C') # trac #16007 + sage: latex_variable_name('_C') # trac #16007 # needs sage.symbolic 'C' - sage: latex_variable_name('_K1') + sage: latex_variable_name('_K1') # needs sage.symbolic 'K_{1}' - sage: latex_variable_name('5') + sage: latex_variable_name('5') # needs sage.symbolic '5' """ # if x is an integer (it might be the case for padics), we return x diff --git a/src/sage/misc/latex_macros.py b/src/sage/misc/latex_macros.py index 1605d8a22f5..238bd02c0e3 100644 --- a/src/sage/misc/latex_macros.py +++ b/src/sage/misc/latex_macros.py @@ -173,7 +173,8 @@ def convert_latex_macro_to_mathjax(macro): # Use this list to define additional latex macros for sage documentation latex_macros = [r"\newcommand{\SL}{\mathrm{SL}}", - r"\newcommand{\PSL}{\mathrm{PSL}}"] + r"\newcommand{\PSL}{\mathrm{PSL}}", + r"\newcommand{\lcm}{\mathop{\operatorname{lcm}}}"] # The following is to allow customization of typesetting of rings: # mathbf vs mathbb. See latex.py for more information. diff --git a/src/sage/misc/latex_standalone.py b/src/sage/misc/latex_standalone.py index 09339eddd1e..d1d9d77d864 100644 --- a/src/sage/misc/latex_standalone.py +++ b/src/sage/misc/latex_standalone.py @@ -156,35 +156,36 @@ tikzpicture code generated by Sage from some polyhedron:: sage: from sage.misc.latex_standalone import TikzPicture - sage: V = [[1,0,1],[1,0,0],[1,1,0],[0,0,-1],[0,1,0],[-1,0,0],[0,1,1],[0,0,1],[0,-1,0]] - sage: P = Polyhedron(vertices=V).polar() - sage: s = P.projection().tikz([674,108,-731],112, output_type='LatexExpr') - sage: t = TikzPicture(s) + sage: V = [[1,0,1], [1,0,0], [1,1,0], [0,0,-1], + ....: [0,1,0], [-1,0,0], [0,1,1], [0,0,1], [0,-1,0]] + sage: P = Polyhedron(vertices=V).polar() # needs sage.geometry.polyhedron + sage: s1 = P.projection().tikz([674,108,-731],112, output_type='LatexExpr') # needs sage.geometry.polyhedron sage.plot + sage: t1 = TikzPicture(s1) # needs sage.geometry.polyhedron sage.plot Open the image in a viewer (the returned value is a string giving the absolute path to the file in some temporary directory):: - sage: path_to_file = t.pdf() # not tested + sage: path_to_file = t1.pdf() # not tested # needs sage.geometry.polyhedron sage.plot Instead, you may save a pdf of the tikzpicture into a file of your choice (but this does not open the viewer):: - sage: _ = t.pdf('tikz_polytope.pdf') # not tested + sage: _ = t1.pdf('tikz_polytope.pdf') # not tested # needs sage.geometry.polyhedron sage.plot Opening the image in a viewer can be turned off:: - sage: _ = t.pdf(view=False) # long time (2s) # optional latex + sage: _ = t1.pdf(view=False) # long time (2s), optional - latex, needs sage.geometry.polyhedron sage.plot The same can be done with png format (translated from pdf with convert command which needs the installation of imagemagick):: - sage: _ = t.png(view=False) # long time (2s) # optional latex imagemagick + sage: _ = t1.png(view=False) # long time (2s), optional - imagemagick latex, needs sage.geometry.polyhedron sage.plot The string representation gives the header (5 lines) and tail (5 lines) of the tikzpicture. In Jupyter, it will instead use rich representation and show the image directly below the cell in png or svg format:: - sage: t + sage: t1 # needs sage.geometry.polyhedron sage.plot \documentclass[tikz]{standalone} \begin{document} \begin{tikzpicture}% @@ -201,21 +202,24 @@ Use ``print(t)`` to see the complete content of the file:: - sage: print(t) # not tested + sage: print(t1) # not tested # needs sage.geometry.polyhedron sage.plot Adding a border in the options avoids cropping the vertices of a graph:: - sage: g = graphs.PetersenGraph() # optional - sage.graphs - sage: s = latex(g) # takes 3s but the result is cached # optional latex sage.graphs - sage: t = TikzPicture(s, standalone_config=["border=4mm"], usepackage=['tkz-graph']) # optional latex sage.graphs - sage: _ = t.pdf() # not tested + sage: # needs sage.graphs + sage: g = graphs.PetersenGraph() + sage: s2 = latex(g) # takes 3s but the result is cached # optional - latex + sage: t2 = TikzPicture(s2, standalone_config=["border=4mm"], # optional - latex + ....: usepackage=['tkz-graph']) + sage: _ = t2.pdf() # not tested The current latex representation of a transducer is a tikzpicture using the tikz library automata. The string can be used as input:: - sage: s = latex(transducers.GrayCode()) # optional sage.combinat - sage: t = TikzPicture(s, usetikzlibrary=['automata']) # optional sage.combinat - sage: _ = t.pdf(view=False) # long time (2s) # optional sage.combinat latex + sage: # needs sage.graphs sage.modules + sage: s3 = latex(transducers.GrayCode()) + sage: t3 = TikzPicture(s3, usetikzlibrary=['automata']) + sage: _ = t3.pdf(view=False) # long time (2s) # optional - latex AUTHORS: @@ -274,7 +278,8 @@ class Standalone(SageObject): :: - sage: t = Standalone(content, standalone_config=["border=4mm"], usepackage=['amsmath']) + sage: t = Standalone(content, standalone_config=["border=4mm"], + ....: usepackage=['amsmath']) sage: t \documentclass{standalone} \standaloneconfig{border=4mm} @@ -622,7 +627,7 @@ def add_macro(self, macro): def pdf(self, filename=None, view=True, program=None): r""" - Compiles the latex code with pdflatex and create a pdf file. + Compile the latex code with pdflatex and create a pdf file. INPUT: @@ -639,34 +644,34 @@ def pdf(self, filename=None, view=True, program=None): OUTPUT: - string, path to pdf file + string, path to pdf file EXAMPLES:: sage: from sage.misc.latex_standalone import Standalone sage: t = Standalone('Hello World') - sage: _ = t.pdf(view=False) # long time (1s) # optional latex + sage: _ = t.pdf(view=False) # long time (1s) # optional - latex Same for instances of :class:`TikzPicture`:: sage: from sage.misc.latex_standalone import TikzPicture sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}" sage: t = TikzPicture(s) - sage: _ = t.pdf(view=False) # not tested + sage: _ = t.pdf(view=False) # not tested A filename may be provided where to save the file, in which case the viewer does not open the file:: sage: from sage.misc.temporary_file import tmp_filename sage: filename = tmp_filename('temp','.pdf') - sage: path_to_file = t.pdf(filename) # long time (1s) # optional latex - sage: path_to_file[-4:] # long time (fast) # optional latex + sage: path_to_file = t.pdf(filename) # long time (1s) # optional - latex + sage: path_to_file[-4:] # long time (fast) # optional - latex '.pdf' The filename may contain spaces:: sage: filename = tmp_filename('filename with spaces','.pdf') - sage: path_to_file = t.pdf(filename) # long time (1s) # optional latex + sage: path_to_file = t.pdf(filename) # long time (1s) # optional - latex TESTS: @@ -675,7 +680,7 @@ def pdf(self, filename=None, view=True, program=None): sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}" sage: s_missing_last_character = s[:-1] sage: t = TikzPicture(s_missing_last_character) - sage: _ = t.pdf() # optional latex + sage: _ = t.pdf() # optional - latex Traceback (most recent call last): ... CalledProcessError: Command '['...latex', '-interaction=nonstopmode', @@ -746,9 +751,136 @@ def pdf(self, filename=None, view=True, program=None): return temp_filename_pdf + def dvi(self, filename=None, view=True, program='latex'): + r""" + Compile the latex code with latex and create a dvi file. + + INPUT: + + - ``filename`` -- string (default: ``None``), the output filename. + If ``None``, it saves the file in a temporary directory. + + - ``view`` -- bool (default:``True``), whether to open the file in a + dvi viewer. This option is ignored and automatically set to + ``False`` if ``filename`` is not ``None``. + + - ``program`` -- string (default:``'latex'``), ``'latex'`` + + OUTPUT: + + string, path to dvi file + + EXAMPLES:: + + sage: from sage.misc.latex_standalone import Standalone + sage: t = Standalone('Hello World') + sage: _ = t.dvi(view=False) # long time (1s) # optional - latex + + Same for instances of :class:`TikzPicture`:: + + sage: from sage.misc.latex_standalone import TikzPicture + sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}" + sage: t = TikzPicture(s) + sage: _ = t.dvi(view=False) # not tested + + A filename may be provided where to save the file, in which case + the viewer does not open the file:: + + sage: from sage.misc.temporary_file import tmp_filename + sage: filename = tmp_filename('temp','.dvi') + sage: path_to_file = t.dvi(filename) # long time (1s) # optional - latex + sage: path_to_file[-4:] # long time (fast) # optional - latex + '.dvi' + + The filename may contain spaces:: + + sage: filename = tmp_filename('filename with spaces','.dvi') + sage: path_to_file = t.dvi(filename) # long time (1s) # optional - latex + + TESTS: + + We test the behavior when a wrong tex string is provided:: + + sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}" + sage: s_missing_last_character = s[:-1] + sage: t = TikzPicture(s_missing_last_character) + sage: _ = t.dvi() # optional - latex + Traceback (most recent call last): + ... + CalledProcessError: Command '['latex', '-interaction=nonstopmode', + 'tikz_...tex']' returned non-zero exit status 1. + + We test the behavior when a wrong value is provided:: + + sage: t = Standalone('Hello World') + sage: _ = t.dvi(program='lates') + Traceback (most recent call last): + ... + ValueError: program(=lates) should be latex + + """ + from sage.features.latex import latex + + # Set default program + if program is None: + program = 'latex' + + # Check availability of programs + if program == 'latex': + latex().require() + else: + raise ValueError("program(={}) should be latex".format(program)) + + # set up filenames + from sage.misc.temporary_file import tmp_filename + temp_filename_tex = tmp_filename('tikz_', '.tex') + with open(temp_filename_tex, 'w') as f: + f.write(str(self)) + base, temp_filename_tex = os.path.split(temp_filename_tex) + temp_filename, ext = os.path.splitext(temp_filename_tex) + + # running pdflatex or lualatex + cmd = [program, '-interaction=nonstopmode', temp_filename_tex] + result = run(cmd, cwd=base, capture_output=True, text=True) + + # If a problem with the tex source occurs, provide the log + if result.returncode != 0: + print("Command \n" + " '{}'\n" + "returned non-zero exit status {}.\n" + "Here is the content of the stderr:{}\n" + "Here is the content of the stdout:" + "{}\n".format(' '.join(result.args), + result.returncode, + result.stderr.strip(), + result.stdout.strip())) + result.check_returncode() + temp_filename_dvi = os.path.join(base, temp_filename + '.dvi') + + # move the pdf into the good location + if filename: + filename = os.path.abspath(filename) + import shutil + shutil.move(temp_filename_dvi, filename) + return filename + + # open the tmp dvi + elif view: + from sage.misc.viewer import dvi_viewer + cmd = dvi_viewer().split() + cmd.append(temp_filename_dvi) + # we use check_call as opposed to run, because + # it gives the sage prompt back to the user + # see https://stackoverflow.com/a/71342967 + # run(cmd, cwd=base, capture_output=True, check=True) + from subprocess import check_call, PIPE + check_call(cmd, cwd=base, stdout=PIPE, stderr=PIPE) + + return temp_filename_dvi + def png(self, filename=None, density=150, view=True): r""" - Compiles the latex code with pdflatex and converts to a png file. + Compile the latex code with pdflatex and converts to a png file. INPUT: @@ -764,27 +896,27 @@ def png(self, filename=None, density=150, view=True): OUTPUT: - string, path to png file + string, path to png file EXAMPLES:: sage: from sage.misc.latex_standalone import Standalone sage: t = Standalone('Hello World') - sage: _ = t.png(view=False) # long time (1s) # optional latex imagemagick + sage: _ = t.png(view=False) # long time (1s) # optional - latex imagemagick Same for instances of :class:`TikzPicture`:: sage: from sage.misc.latex_standalone import TikzPicture sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}" sage: t = TikzPicture(s) - sage: _ = t.png(view=False) # not tested + sage: _ = t.png(view=False) # not tested :: sage: from sage.misc.temporary_file import tmp_filename sage: filename = tmp_filename('temp','.png') - sage: path_to_file = t.png(filename) # long time (1s) # optional latex imagemagick - sage: path_to_file[-4:] # long time (fast) # optional latex imagemagick + sage: path_to_file = t.png(filename) # long time (1s) # optional - latex imagemagick + sage: path_to_file[-4:] # long time (fast) # optional - latex imagemagick '.png' """ @@ -837,7 +969,7 @@ def png(self, filename=None, density=150, view=True): def svg(self, filename=None, view=True, program='pdftocairo'): r""" - Compiles the latex code with pdflatex and converts to a svg file. + Compile the latex code with pdflatex and converts to a svg file. INPUT: @@ -853,7 +985,7 @@ def svg(self, filename=None, view=True, program='pdftocairo'): OUTPUT: - string, path to svg file + string, path to svg file EXAMPLES:: @@ -872,11 +1004,13 @@ def svg(self, filename=None, view=True, program='pdftocairo'): sage: from sage.misc.temporary_file import tmp_filename sage: filename = tmp_filename('temp', '.svg') - sage: path_to_file = t.svg(filename, program='pdf2svg') # long time (1s) # optional latex pdf2svg - sage: path_to_file[-4:] # long time (fast) # optional latex pdf2svg + sage: path_to_file = t.svg(filename, # long time (1s) # optional - latex pdf2svg + ....: program='pdf2svg') + sage: path_to_file[-4:] # long time (fast) # optional - latex pdf2svg '.svg' - sage: path_to_file = t.svg(filename, program='pdftocairo') # long time (1s) # optional latex pdftocairo - sage: path_to_file[-4:] # long time (fast) # optional latex pdftocairo + sage: path_to_file = t.svg(filename, # long time (1s) # optional - latex pdftocairo + ....: program='pdftocairo') + sage: path_to_file[-4:] # long time (fast) # optional - latex pdftocairo '.svg' """ @@ -935,6 +1069,123 @@ def svg(self, filename=None, view=True, program='pdftocairo'): return temp_filename_svg + def eps(self, filename=None, view=True, program='dvips'): + r""" + Compile the latex code with pdflatex and converts to a eps file. + + INPUT: + + - ``filename`` -- string (default:``None``), the output filename. + If ``None``, it saves the file in a temporary directory. + + - ``view`` -- bool (default:``True``), whether to open the file in + a browser. This option is ignored and automatically set to + ``False`` if ``filename`` is not ``None``. + + - ``program`` -- string (default:``'dvips'``), + ``'pdftocairo'`` or ``'dvips'`` + + OUTPUT: + + string, path to eps file + + EXAMPLES:: + + sage: from sage.misc.latex_standalone import Standalone + sage: t = Standalone('Hello World') + sage: _ = t.eps(view=False) # not tested + + Same for instances of :class:`TikzPicture`:: + + sage: from sage.misc.latex_standalone import TikzPicture + sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}" + sage: t = TikzPicture(s) + sage: _ = t.eps(view=False) # not tested + + We test the creation of the files:: + + sage: from sage.misc.temporary_file import tmp_filename + sage: filename = tmp_filename('temp', '.eps') + sage: path_to_file = t.eps(filename, # long time (1s) # optional - latex dvips + ....: program='dvips') + sage: path_to_file[-4:] # long time (fast) # optional - latex dvips + '.eps' + sage: path_to_file = t.eps(filename, # long time (1s) # optional - latex pdftocairo + ....: program='pdftocairo') + sage: path_to_file[-4:] # long time (fast) # optional - latex pdftocairo + '.eps' + + TESTS: + + We test the behavior when a wrong value is provided:: + + sage: t = Standalone('Hello World') + sage: _ = t.eps(program='convert') + Traceback (most recent call last): + ... + ValueError: program(=convert) should be 'pdftocairo' or 'dvips' + + """ + + if program == 'pdftocairo': + from sage.features.poppler import pdftocairo + pdftocairo().require() + # set the temporary filenames + temp_filename_pdf = self.pdf(filename=None, view=False) + temp_filename, ext = os.path.splitext(temp_filename_pdf) + temp_filename_eps = temp_filename + '.eps' + # set the command + cmd = ['pdftocairo', '-eps', temp_filename_pdf, temp_filename_eps] + elif program == 'dvips': + from sage.features.latex import dvips + dvips().require() + # set the temporary filenames + temp_filename_dvi = self.dvi(filename=None, view=False) + temp_filename, ext = os.path.splitext(temp_filename_dvi) + temp_filename_eps = temp_filename + '.eps' + # set the command + cmd = ['dvips', '-E', '-o', temp_filename_eps, temp_filename_dvi] + else: + raise ValueError("program(={}) should be 'pdftocairo' or" + " 'dvips'".format(program)) + + # convert to eps + result = run(cmd, capture_output=True, text=True) + + # If a problem occurs, provide the log + if result.returncode != 0: + print("Command \n" + " '{}'\n" + "returned non-zero exit status {}.\n" + "Here is the content of the stderr:{}\n" + "Here is the content of the stdout:" + "{}\n".format(' '.join(result.args), + result.returncode, + result.stderr.strip(), + result.stdout.strip())) + result.check_returncode() + + # move the eps into the good location + if filename: + filename = os.path.abspath(filename) + import shutil + shutil.move(temp_filename_eps, filename) + return filename + + # open the tmp eps + elif view: + from sage.misc.viewer import viewer + cmd = viewer().split() + cmd.append(temp_filename_eps) + # we use check_call as opposed to run, because + # it gives the sage prompt back to the user + # see https://stackoverflow.com/a/71342967 + # run(cmd, capture_output=True, check=True) + from subprocess import check_call, PIPE + check_call(cmd, stdout=PIPE, stderr=PIPE) + + return temp_filename_eps + def tex(self, filename=None, content_only=False, include_header=None): r""" Writes the latex code to a file. @@ -949,7 +1200,7 @@ def tex(self, filename=None, content_only=False, include_header=None): OUTPUT: - string, path to tex file + string, path to tex file EXAMPLES:: @@ -999,6 +1250,64 @@ def tex(self, filename=None, content_only=False, include_header=None): return filename + def save(self, filename, **kwds): + r""" + Save the graphics to an image file. + + INPUT: + + - ``filename`` -- string. The filename and the image format + given by the extension, which can be one of the following: + + * ``.pdf``, + * ``.png``, + * ``.svg``, + * ``.eps``, + * ``.dvi``, + * ``.sobj`` (for a Sage object you can load later), + * empty extension will be treated as ``.sobj``. + + All other keyword arguments will be passed to the plotter. + + OUTPUT: + + - ``None`` + + .. NOTE:: + + This method follows the signature of the method + :meth:`sage.plot.Graphics.save` in order to be compatible with + with sagetex. In particular so that ``\sageplot{t}`` written + in a ``tex`` file works when ``t`` is an instance of + :class:`Standalone` or :class:`TikzPicture`. + + EXAMPLES:: + + sage: from sage.misc.temporary_file import tmp_filename + sage: from sage.misc.latex_standalone import Standalone + sage: t = Standalone('Hello World') + sage: filename = tmp_filename('temp','.pdf') + sage: t.save(filename) # long time (1s) # optional - latex + sage: filename = tmp_filename('temp','.eps') + sage: t.save(filename) # long time (1s) # optional - latex dvips + + """ + ext = os.path.splitext(filename)[1].lower() + if ext == '' or ext == '.sobj': + raise NotImplementedError() + elif ext == '.pdf': + self.pdf(filename, **kwds) + elif ext == '.png': + self.png(filename, **kwds) + elif ext == '.svg': + self.svg(filename, **kwds) + elif ext == '.eps': + self.eps(filename, **kwds) + elif ext == '.dvi': + self.dvi(filename, **kwds) + else: + raise ValueError("allowed file extensions for images are " + ".pdf, .png, .svg, .eps, .dvi!") class TikzPicture(Standalone): r""" @@ -1044,19 +1353,22 @@ class TikzPicture(Standalone): below methods return a string providing the path to the filename, which is by default in a temporary folder:: - sage: _ = t.pdf() # not tested - sage: _ = t.png() # not tested - sage: _ = t.svg() # not tested - sage: _ = t.tex() # not tested - sage: _ = t.pdf(filename='abc.pdf') # not tested + sage: # not tested + sage: _ = t.pdf() + sage: _ = t.png() + sage: _ = t.svg() + sage: _ = t.tex() + sage: _ = t.pdf(filename='abc.pdf') Here we create a tikzpicture for the latex representation of a graph. This is using tkz-graph tex library:: - sage: g = graphs.PetersenGraph() # optional sage.graphs - sage: s = latex(g) # optional sage.graphs latex - sage: t = TikzPicture(s, standalone_config=["border=4mm"], usepackage=['tkz-graph']) # optional sage.graphs latex - sage: _ = t.pdf(view=False) # long time (2s) # optional - sage.graphs latex latex_package_tkz_graph + sage: # needs sage.graphs + sage: g = graphs.PetersenGraph() + sage: s = latex(g) # optional - latex + sage: t = TikzPicture(s, standalone_config=["border=4mm"], # optional - latex + ....: usepackage=['tkz-graph']) + sage: _ = t.pdf(view=False) # long time (2s), optional - latex latex_package_tkz_graph Here are standalone configurations, packages, tikz libraries and macros that can be set:: @@ -1071,7 +1383,7 @@ class TikzPicture(Standalone): sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}" sage: t = TikzPicture(s, standalone_config=options, usepackage=usepackage, ....: usetikzlibrary=tikzlib, macros=macros) - sage: _ = t.pdf(view=False) # long time (2s) # optional latex + sage: _ = t.pdf(view=False) # long time (2s), optional - latex """ def __init__(self, content, standalone_config=None, usepackage=None, usetikzlibrary=None, macros=None, use_sage_preamble=False): @@ -1153,30 +1465,34 @@ def from_dot_string(cls, dotdata, prog='dot'): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.misc.latex_standalone import TikzPicture - sage: G = graphs.PetersenGraph() # optional sage.graphs - sage: dotdata = G.graphviz_string() # optional sage.graphs - sage: tikz = TikzPicture.from_dot_string(dotdata) # optional sage.graphs dot2tex graphviz # long time (3s) + sage: G = graphs.PetersenGraph() + sage: dotdata = G.graphviz_string() + sage: tikz = TikzPicture.from_dot_string(dotdata) # long time (3s), optional - dot2tex graphviz sage: _ = tikz.pdf() # not tested :: - sage: dotdata = G.graphviz_string(labels='latex') # optional sage.graphs - sage: tikz = TikzPicture.from_dot_string(dotdata) # optional sage.graphs dot2tex graphviz # long time (3s) + sage: # needs sage.graphs + sage: dotdata = G.graphviz_string(labels='latex') + sage: tikz = TikzPicture.from_dot_string(dotdata) # long time (3s), optional - dot2tex graphviz sage: _ = tikz.pdf() # not tested :: + sage: # needs sage.combinat sage.graphs sage.groups sage: W = CoxeterGroup(["A",2]) - sage: G = W.cayley_graph() # optional sage.graphs - sage: dotdata = G.graphviz_string() # optional sage.graphs - sage: tikz = TikzPicture.from_dot_string(dotdata) # optional sage.graphs dot2tex graphviz # long time (3s) + sage: G = W.cayley_graph() + sage: dotdata = G.graphviz_string() + sage: tikz = TikzPicture.from_dot_string(dotdata) # long time (3s), optional - dot2tex graphviz sage: _ = tikz.pdf() # not tested :: - sage: dotdata = G.graphviz_string(labels='latex') # optional sage.graphs - sage: tikz = TikzPicture.from_dot_string(dotdata) # optional sage.graphs dot2tex graphviz # long time (3s) + sage: # needs sage.combinat sage.graphs sage.groups + sage: dotdata = G.graphviz_string(labels='latex') + sage: tikz = TikzPicture.from_dot_string(dotdata) # long time (3s), optional - dot2tex graphviz sage: _ = tikz.pdf() # not tested """ @@ -1238,9 +1554,10 @@ def from_graph(cls, graph, merge_multiedges=True, EXAMPLES:: + sage: # needs sage.graphs sage: from sage.misc.latex_standalone import TikzPicture - sage: g = graphs.PetersenGraph() # optional sage.graphs - sage: tikz = TikzPicture.from_graph(g) # optional sage.graphs dot2tex graphviz + sage: g = graphs.PetersenGraph() + sage: tikz = TikzPicture.from_graph(g) # optional - dot2tex graphviz doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. See https://github.com/sagemath/sage/issues/20343 for details. @@ -1248,28 +1565,33 @@ def from_graph(cls, graph, merge_multiedges=True, Using ``prog``:: - sage: tikz = TikzPicture.from_graph(g, prog='neato', color_by_label=True) # optional sage.graphs dot2tex graphviz # long time (3s) + sage: # needs sage.graphs + sage: tikz = TikzPicture.from_graph(g, prog='neato', # long time (3s), optional - dot2tex graphviz + ....: color_by_label=True) sage: _ = tikz.pdf() # not tested Using ``rankdir``:: - sage: tikz = TikzPicture.from_graph(g, rankdir='right') # optional sage.graphs dot2tex graphviz # long time (3s) + sage: tikz = TikzPicture.from_graph(g, rankdir='right') # long time (3s), optional - dot2tex graphviz, needs sage.graphs sage: _ = tikz.pdf() # not tested Using ``merge_multiedges``:: + sage: # needs sage.graphs sage.modules sage.symbolic sage: alpha = var('alpha') - sage: m = matrix(2,range(4)); m.set_immutable() - sage: G = DiGraph([(0,1,alpha), (0,1,0), (0,2,9), (0,2,m)], multiedges=True) # optional sage.graphs - sage: tikz = TikzPicture.from_graph(G, merge_multiedges=True) # optional sage.graphs dot2tex graphviz + sage: m = matrix(2, range(4)); m.set_immutable() + sage: G = DiGraph([(0,1,alpha), (0,1,0), (0,2,9), (0,2,m)], + ....: multiedges=True) + sage: tikz = TikzPicture.from_graph(G, merge_multiedges=True) # optional - dot2tex graphviz sage: _ = tikz.pdf() # not tested Using ``merge_multiedges`` with ``merge_label_function``:: + sage: # needs sage.graphs sage: fn = lambda L: LatexExpr(','.join(map(str, L))) sage: edges = [(0,1,'a'), (0,1,'b'), (0,2,'c'), (0,2,'d')] - sage: G = DiGraph(edges, multiedges=True) # optional sage.graphs - sage: tikz = TikzPicture.from_graph(G, # optional sage.graphs dot2tex graphviz + sage: G = DiGraph(edges, multiedges=True) + sage: tikz = TikzPicture.from_graph(G, # optional - dot2tex graphviz ....: merge_multiedges=True, merge_label_function=fn) sage: _ = tikz.pdf() # not tested @@ -1281,24 +1603,25 @@ def from_graph(cls, graph, merge_multiedges=True, sage: a = S((0,1,3,0,0)) sage: b = S((0,2,4,1,0)) sage: roots = [I] - sage: succ = lambda v:[v*a,v*b,a*v,b*v] + sage: succ = lambda v: [v*a,v*b,a*v,b*v] sage: R = RecursivelyEnumeratedSet(roots, succ) - sage: G = R.to_digraph() # optional sage.graphs - sage: G # optional sage.graphs + sage: G = R.to_digraph() # needs sage.graphs + sage: G # needs sage.graphs Looped multi-digraph on 27 vertices - sage: C = G.strongly_connected_components() # optional sage.graphs - sage: tikz = TikzPicture.from_graph(G, # optional sage.graphs dot2tex graphviz + sage: C = G.strongly_connected_components() # needs sage.graphs + sage: tikz = TikzPicture.from_graph(G, # optional - dot2tex graphviz, needs sage.graphs ....: merge_multiedges=False, subgraph_clusters=C) sage: _ = tikz.pdf() # not tested An example coming from ``graphviz_string`` documentation in SageMath:: - sage: f(x) = -1 / x # optional sage.symbolic - sage: g(x) = 1 / (x + 1) # optional sage.symbolic - sage: G = DiGraph() # optional sage.symbolic sage.graphs - sage: G.add_edges((i, f(i), f) for i in (1, 2, 1/2, 1/4)) # optional sage.symbolic sage.graphs - sage: G.add_edges((i, g(i), g) for i in (1, 2, 1/2, 1/4)) # optional sage.symbolic sage.graphs - sage: tikz = TikzPicture.from_graph(G) # optional sage.symbolic sage.graphs dot2tex graphviz + sage: # needs sage.graphs sage.symbolic + sage: f(x) = -1 / x + sage: g(x) = 1 / (x + 1) + sage: G = DiGraph() + sage: G.add_edges((i, f(i), f) for i in (1, 2, 1/2, 1/4)) + sage: G.add_edges((i, g(i), g) for i in (1, 2, 1/2, 1/4)) + sage: tikz = TikzPicture.from_graph(G) # optional - dot2tex graphviz sage: _ = tikz.pdf() # not tested sage: def edge_options(data): ....: u, v, label = data @@ -1308,7 +1631,7 @@ def from_graph(cls, graph, merge_multiedges=True, ....: if (u,v) == (1, -1): options["label_style"] = "latex" ....: if (u,v) == (1, 1/2): options["dir"] = "back" ....: return options - sage: tikz = TikzPicture.from_graph(G, edge_options=edge_options) # optional sage.symbolic sage.graphs dot2tex graphviz + sage: tikz = TikzPicture.from_graph(G, edge_options=edge_options) # optional - dot2tex graphviz sage: _ = tikz.pdf() # not tested """ @@ -1368,20 +1691,23 @@ def from_graph_with_pos(cls, graph, scale=1, merge_multiedges=True, EXAMPLES:: sage: from sage.misc.latex_standalone import TikzPicture - sage: g = graphs.PetersenGraph() # optional sage.graphs - sage: tikz = TikzPicture.from_graph_with_pos(g) # optional sage.graphs + + sage: # needs sage.graphs + sage: g = graphs.PetersenGraph() + sage: tikz = TikzPicture.from_graph_with_pos(g) doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. See https://github.com/sagemath/sage/issues/20343 for details. :: + sage: # needs sage.graphs sage: edges = [(0,0,'a'),(0,1,'b'),(0,1,'c')] sage: kwds = dict(format='list_of_edges', loops=True, multiedges=True) - sage: G = DiGraph(edges, **kwds) # optional sage.graphs - sage: G.set_pos({0:(0,0), 1:(1,0)}) # optional sage.graphs - sage: f = lambda label:','.join(label) # optional sage.graphs - sage: TikzPicture.from_graph_with_pos(G, merge_label_function=f) # optional sage.graphs + sage: G = DiGraph(edges, **kwds) + sage: G.set_pos({0:(0,0), 1:(1,0)}) + sage: f = lambda label:','.join(label) + sage: TikzPicture.from_graph_with_pos(G, merge_label_function=f) \documentclass[tikz]{standalone} \standaloneconfig{border=4mm} \begin{document} @@ -1399,10 +1725,11 @@ def from_graph_with_pos(cls, graph, scale=1, merge_multiedges=True, TESTS:: + sage: # needs sage.graphs sage: edges = [(0,0,'a'),(0,1,'b'),(0,1,'c')] sage: kwds = dict(format='list_of_edges', loops=True, multiedges=True) - sage: G = DiGraph(edges, **kwds) # optional sage.graphs - sage: TikzPicture.from_graph_with_pos(G) # optional sage.graphs + sage: G = DiGraph(edges, **kwds) + sage: TikzPicture.from_graph_with_pos(G) Traceback (most recent call last): ... ValueError: vertex positions need to be set first @@ -1496,21 +1823,25 @@ def from_poset(cls, poset, **kwds): EXAMPLES:: sage: from sage.misc.latex_standalone import TikzPicture - sage: P = posets.PentagonPoset() # optional sage.combinat - sage: tikz = TikzPicture.from_poset(P) # optional sage.combinat dot2tex graphviz + + sage: # needs sage.graphs sage.modules + sage: P = posets.PentagonPoset() + sage: tikz = TikzPicture.from_poset(P) # optional - dot2tex graphviz doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. See https://github.com/sagemath/sage/issues/20343 for details. :: - sage: tikz = TikzPicture.from_poset(P, prog='neato', color_by_label=True) # optional sage.combinat dot2tex # long time (3s) + sage: tikz = TikzPicture.from_poset(P, prog='neato', # long time (3s), optional - dot2tex, needs sage.graphs sage.modules + ....: color_by_label=True) :: - sage: P = posets.SymmetricGroupWeakOrderPoset(4) # optional sage.combinat - sage: tikz = TikzPicture.from_poset(P) # optional sage.combinat dot2tex graphviz # long time (4s) - sage: tikz = TikzPicture.from_poset(P, prog='neato') # optional sage.combinat dot2tex graphviz # long time (4s) + sage: # needs sage.graphs + sage: P = posets.SymmetricGroupWeakOrderPoset(4) + sage: tikz = TikzPicture.from_poset(P) # long time (4s), optional - dot2tex graphviz + sage: tikz = TikzPicture.from_poset(P, prog='neato') # long time (4s), optional - dot2tex graphviz """ graph = poset.hasse_diagram() return cls.from_graph(graph, **kwds) diff --git a/src/sage/misc/lazy_attribute.pyx b/src/sage/misc/lazy_attribute.pyx index 23a7098564b..bdbec3b3ba1 100644 --- a/src/sage/misc/lazy_attribute.pyx +++ b/src/sage/misc/lazy_attribute.pyx @@ -82,7 +82,7 @@ cdef class _lazy_attribute(): EXAMPLES:: sage: from sage.misc.sageinspect import sage_getsourcelines - sage: g = lazy_attribute(banner) + sage: g = lazy_attribute(sage.misc.banner.banner) sage: (src, lines) = sage_getsourcelines(g) sage: src[0] 'def banner():\n' @@ -111,12 +111,12 @@ cdef class _lazy_attribute(): if a is None: # when doing cls.x for cls a class and x a lazy attribute return self try: - # __cached_methods is supposed to be a public Cython attribute. + # _cached_methods is supposed to be a public Cython attribute. # Apparently, these are *not* subject to name mangling. - CM = getattr(a, '__cached_methods') + CM = getattr(a, '_cached_methods') if CM is None: CM = {} - setattr(a, '__cached_methods', CM) + setattr(a, '_cached_methods', CM) except AttributeError as msg: CM = None if CM is not None: @@ -354,9 +354,9 @@ class lazy_attribute(_lazy_attribute): ....: "cdef class MyElement(Element): pass", ....: "cdef class MyParent(Parent):", ....: " Element = MyElement"] - sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython - sage: P = MyParent(category=Rings()) # optional - sage.misc.cython - sage: P.element_class # indirect doctest # optional - sage.misc.cython + sage: cython('\n'.join(cython_code)) # needs sage.misc.cython + sage: P = MyParent(category=Rings()) # needs sage.misc.cython + sage: P.element_class # indirect doctest # needs sage.misc.cython <class '...MyElement'> .. rubric:: About descriptor specifications diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index d4a6c12ed5a..7fc73407ace 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -257,15 +257,20 @@ cdef class LazyImport(): if finish_startup_called: warn(f"Option ``at_startup=True`` for lazy import {self._name} not needed anymore") + feature = self._feature try: self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name) except ImportError as e: - if self._feature: + if feature: # Avoid warnings from static type checkers by explicitly importing FeatureNotPresentError. from sage.features import FeatureNotPresentError - raise FeatureNotPresentError(self._feature, reason=f'Importing {self._name} failed: {e}') + raise FeatureNotPresentError(feature, reason=f'Importing {self._name} failed: {e}') raise + if feature: + # for the case that the feature is hidden + feature.require() + if self._deprecation is not None: from sage.misc.superseded import deprecation_cython as deprecation try: @@ -350,7 +355,7 @@ cdef class LazyImport(): sage: from sage.misc.lazy_import import LazyImport sage: rm = LazyImport('sage.matrix.special', 'random_matrix') - sage: rm._sage_argspec_() + sage: rm._sage_argspec_() # needs sage.modules FullArgSpec(args=['ring', 'nrows', 'ncols', 'algorithm', 'implementation'], varargs='args', varkw='kwds', defaults=(None, 'randomize', None), kwonlyargs=[], kwonlydefaults=None, annotations={}) @@ -526,12 +531,12 @@ cdef class LazyImport(): We access the ``plot`` method:: - sage: Bar.plot + sage: Bar.plot # needs sage.plot <function plot at 0x...> Now ``plot`` has been replaced in the dictionary of ``Foo``:: - sage: type(Foo.__dict__['plot']) + sage: type(Foo.__dict__['plot']) # needs sage.plot <... 'function'> """ # Don't use the namespace of the class definition @@ -662,9 +667,10 @@ cdef class LazyImport(): """ TESTS:: + sage: # needs sympy sage: from sympy import Matrix sage: import sage.all__sagemath_objects - sage: sage.all__sagemath_objects.foo = Matrix([[1,1],[0,1]]) + sage: sage.all__sagemath_objects.foo = Matrix([[1,1], [0,1]]) sage: lazy_import('sage.all__sagemath_objects', 'foo') sage: foo.__matmul__(foo) Matrix([ @@ -1059,15 +1065,16 @@ def lazy_import(module, names, as_=None, *, ....: pass sage: type(Foo.__dict__['plot']) <class 'sage.misc.lazy_import.LazyImport'> - sage: 'EXAMPLES' in Bar.plot.__doc__ + sage: 'EXAMPLES' in Bar.plot.__doc__ # needs sage.plot True - sage: type(Foo.__dict__['plot']) + sage: type(Foo.__dict__['plot']) # needs sage.plot <... 'function'> If deprecated then a deprecation warning is issued:: - sage: lazy_import('sage.rings.padics.factory', 'Qp', 'my_Qp', deprecation=14275) - sage: my_Qp(5) + sage: lazy_import('sage.rings.padics.factory', 'Qp', 'my_Qp', + ....: deprecation=14275) + sage: my_Qp(5) # needs sage.rings.padics doctest:...: DeprecationWarning: Importing my_Qp from here is deprecated; please use "from sage.rings.padics.factory import Qp as my_Qp" instead. See https://github.com/sagemath/sage/issues/14275 for details. @@ -1075,8 +1082,9 @@ def lazy_import(module, names, as_=None, *, An example of deprecation with a message:: - sage: lazy_import('sage.rings.padics.factory', 'Qp', 'my_Qp_msg', deprecation=(14275, "This is an example.")) - sage: my_Qp_msg(5) + sage: lazy_import('sage.rings.padics.factory', 'Qp', 'my_Qp_msg', + ....: deprecation=(14275, "This is an example.")) + sage: my_Qp_msg(5) # needs sage.rings.padics doctest:...: DeprecationWarning: This is an example. See https://github.com/sagemath/sage/issues/14275 for details. 5-adic Field with capped relative precision 20 @@ -1084,9 +1092,10 @@ def lazy_import(module, names, as_=None, *, An example of an import relying on a feature:: sage: from sage.features import PythonModule - sage: lazy_import('ppl', 'equation', feature=PythonModule('ppl', spkg='pplpy')) - sage: equation - <built-in function equation> + sage: lazy_import('ppl', 'equation', + ....: feature=PythonModule('ppl', spkg='pplpy', type='standard')) + sage: equation # needs pplpy + <cyfunction equation at ...> sage: lazy_import('PyNormaliz', 'NmzListConeProperties', feature=PythonModule('PyNormaliz', spkg='pynormaliz')) # optional - pynormaliz sage: NmzListConeProperties # optional - pynormaliz <built-in function NmzListConeProperties> @@ -1099,7 +1108,7 @@ def lazy_import(module, names, as_=None, *, """ if as_ is None: as_ = names - if isinstance(names, basestring): + if isinstance(names, str): names = [names] as_ = [as_] else: @@ -1150,7 +1159,7 @@ def get_star_imports(module_name): sage: from sage.misc.lazy_import import get_star_imports sage: 'get_star_imports' in get_star_imports('sage.misc.lazy_import') True - sage: 'EllipticCurve' in get_star_imports('sage.schemes.all') + sage: 'EllipticCurve' in get_star_imports('sage.schemes.all') # needs sage.schemes True TESTS:: @@ -1164,7 +1173,7 @@ def get_star_imports(module_name): sage: import sage.misc.lazy_import_cache as cache sage: cache.get_cache_file = (lambda: cache_file) sage: lazy.star_imports = None - sage: lazy.get_star_imports('sage.schemes.all') + sage: lazy.get_star_imports('sage.schemes.all') # needs sage.schemes doctest:...: UserWarning: star_imports cache is corrupted [...] sage: os.remove(cache_file) @@ -1242,6 +1251,7 @@ def clean_namespace(namespace=None): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.misc.lazy_import import attributes, clean_namespace sage: from sage.calculus.calculus import maxima as C sage: attributes(C)['_as_name'] diff --git a/src/sage/misc/lazy_list.pyx b/src/sage/misc/lazy_list.pyx index 4e25ee39299..cd750933860 100644 --- a/src/sage/misc/lazy_list.pyx +++ b/src/sage/misc/lazy_list.pyx @@ -11,11 +11,11 @@ EXAMPLES:: sage: from sage.misc.lazy_list import lazy_list sage: P = lazy_list(Primes()) - sage: P[100] + sage: P[100] # needs sage.libs.pari 547 - sage: P[10:34] + sage: P[10:34] # needs sage.libs.pari lazy list [31, 37, 41, ...] - sage: P[12:23].list() + sage: P[12:23].list() # needs sage.libs.pari [41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83] sage: f = lazy_list((i**2 - 3*i for i in range(10))) @@ -305,6 +305,7 @@ def lazy_list_formatter(L, name='lazy list', :: + sage: # needs sage.libs.pari sage: from sage.misc.lazy_list import lazy_list sage: L = lazy_list(Primes()); L lazy list [2, 3, 5, ...] @@ -356,9 +357,9 @@ cdef class lazy_list_generic(): sage: from sage.misc.lazy_list import lazy_list sage: l = lazy_list(Primes()) - sage: l + sage: l # needs sage.libs.pari lazy list [2, 3, 5, ...] - sage: l[200] + sage: l[200] # needs sage.libs.pari 1229 """ @@ -415,8 +416,9 @@ cdef class lazy_list_generic(): sage: from sage.misc.lazy_list import lazy_list sage: P = lazy_list(Primes()) - sage: P[2:143:5].list() - [5, 19, 41, 61, 83, 107, 137, 163, 191, 223, 241, 271, 307, 337, 367, 397, 431, 457, 487, 521, 563, 593, 617, 647, 677, 719, 751, 787, 823] + sage: P[2:143:5].list() # needs sage.libs.pari + [5, 19, 41, 61, 83, 107, 137, 163, 191, 223, 241, 271, 307, 337, 367, + 397, 431, 457, 487, 521, 563, 593, 617, 647, 677, 719, 751, 787, 823] sage: P = lazy_list(iter([1,2,3])) sage: P.list() [1, 2, 3] @@ -430,11 +432,11 @@ cdef class lazy_list_generic(): Check that the cache is immutable:: sage: lazy = lazy_list(iter(Primes()))[:5] - sage: l = lazy.list(); l + sage: l = lazy.list(); l # needs sage.libs.pari [2, 3, 5, 7, 11] - sage: l[0] = -1; l + sage: l[0] = -1; l # needs sage.libs.pari [-1, 3, 5, 7, 11] - sage: lazy.list() + sage: lazy.list() # needs sage.libs.pari [2, 3, 5, 7, 11] """ self._fit(self.stop - self.step) @@ -453,9 +455,9 @@ cdef class lazy_list_generic(): start 10 stop 21474838 step 4 - sage: P[0] + sage: P[0] # needs sage.libs.pari 31 - sage: P._info() + sage: P._info() # needs sage.libs.pari cache length 11 start 10 stop 21474838 @@ -676,7 +678,7 @@ cdef class lazy_list_generic(): sage: from itertools import count sage: from sage.misc.lazy_list import lazy_list sage: iter(lazy_list(count())) - <generator object at 0x...> + <...generator object at 0x...> :: @@ -858,9 +860,9 @@ cdef class lazy_list_generic(): sage: from sage.misc.lazy_list import lazy_list sage: L = lazy_list(Primes())[2:] - sage: L._update_cache_up_to(4) + sage: L._update_cache_up_to(4) # needs sage.libs.pari 0 - sage: L._info() + sage: L._info() # needs sage.libs.pari cache length 5 start 2 stop 9223372036854775807 # 64-bit @@ -885,9 +887,9 @@ cdef class lazy_list_generic(): TESTS:: sage: from sage.misc.lazy_list import lazy_list - sage: L = lazy_list(Primes()); L + sage: L = lazy_list(Primes()); L # needs sage.libs.pari lazy list [2, 3, 5, ...] - sage: L._get_cache_() + sage: L._get_cache_() # needs sage.libs.pari [2, 3, 5, 7] """ return self.cache @@ -964,9 +966,9 @@ cdef class lazy_list_from_iterator(lazy_list_generic): sage: from sage.misc.lazy_list import lazy_list sage: L = lazy_list(iter(Primes()))[2:] - sage: L._update_cache_up_to(4) + sage: L._update_cache_up_to(4) # needs sage.libs.pari 0 - sage: L._info() + sage: L._info() # needs sage.libs.pari cache length 5 start 2 stop 9223372036854775807 # 64-bit @@ -1015,7 +1017,7 @@ cdef class lazy_list_from_function(lazy_list_generic): EXAMPLES:: sage: from sage.misc.lazy_list import lazy_list_from_function - sage: lazy_list_from_function(euler_phi) + sage: lazy_list_from_function(euler_phi) # needs sage.libs.pari lazy list [0, 1, 1, ...] sage: lazy_list_from_function(divisors, [None]) lazy list [None, [1], [1, 2], ...] @@ -1057,14 +1059,18 @@ cdef class lazy_list_from_function(lazy_list_generic): step 1 """ while len(self.cache) <= i: - self.cache.append(self.callable(len(self.cache))) + try: + value = self.callable(len(self.cache)) + except StopIteration: + return 1 + self.cache.append(value) def __reduce__(self): r""" TESTS:: sage: from sage.misc.lazy_list import lazy_list_from_function - sage: loads(dumps(lazy_list_from_function(euler_phi))) + sage: loads(dumps(lazy_list_from_function(euler_phi))) # needs sage.libs.pari lazy list [0, 1, 1, ...] sage: loads(dumps(lazy_list_from_function(divisors, [None]))) lazy list [None, [1], [1, 2], ...] diff --git a/src/sage/misc/lazy_string.pyx b/src/sage/misc/lazy_string.pyx index 5119775bad6..dd92fb38142 100644 --- a/src/sage/misc/lazy_string.pyx +++ b/src/sage/misc/lazy_string.pyx @@ -205,7 +205,7 @@ cdef class _LazyString(): cdef val(self): cdef f = self.func - if isinstance(f, basestring): + if isinstance(f, str): return f % self.args return PyObject_Call(f, self.args, self.kwargs) @@ -519,23 +519,24 @@ cdef class _LazyString(): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.misc.lazy_string import lazy_string - sage: f = lambda op,A,B:"unsupported operand parent(s) for %s: '%s' and '%s'"%(op,A,B) + sage: def f(op, A, B): + ....: return "unsupported operand parent(s) for %s: '%s' and '%s'" % (op, A, B) sage: R = GF(5) sage: S = GF(3) - sage: D = lazy_string(f, '+', R, S) - sage: D + sage: D = lazy_string(f, '+', R, S); D l"unsupported operand parent(s) for +: 'Finite Field of size 5' and 'Finite Field of size 3'" sage: D.update_lazy_string(('+', S, R), {}) Apparently, the lazy string got changed in-place:: - sage: D + sage: D # needs sage.rings.finite_rings l"unsupported operand parent(s) for +: 'Finite Field of size 3' and 'Finite Field of size 5'" TESTS:: - sage: D.update_lazy_string(None, None) + sage: D.update_lazy_string(None, None) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: Expected tuple, got NoneType diff --git a/src/sage/misc/map_threaded.py b/src/sage/misc/map_threaded.py index cc8f8f0a3dd..db525e0ef6f 100644 --- a/src/sage/misc/map_threaded.py +++ b/src/sage/misc/map_threaded.py @@ -2,6 +2,7 @@ Threaded map function """ + def map_threaded(function, sequence): """ Apply the function to the elements in the sequence by threading @@ -9,6 +10,7 @@ def map_threaded(function, sequence): EXAMPLES:: + sage: # needs sage.symbolic sage: map_threaded(log, [[1,2], [3,e]]) [[0, log(2)], [log(3), 1]] sage: map_threaded(log, [(1,2), (3,e)]) @@ -21,7 +23,7 @@ def map_threaded(function, sequence): map_threaded also works on any object with an apply_map method, e.g., on matrices:: - sage: map_threaded(lambda x: x^2, matrix([[1,2], [3,4]])) + sage: map_threaded(lambda x: x^2, matrix([[1,2], [3,4]])) # needs sage.modules [ 1 4] [ 9 16] @@ -31,5 +33,5 @@ def map_threaded(function, sequence): """ if hasattr(sequence, 'apply_map'): return sequence.apply_map(function) - return [map_threaded(function, x) if isinstance(x, (list, tuple)) \ - else function(x) for x in sequence] + return [map_threaded(function, x) if isinstance(x, (list, tuple)) + else function(x) for x in sequence] diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index 6bebd478e60..a4f8ebb826e 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -38,16 +38,20 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import contextlib +import functools import os -import time -import resource import pdb +import sys import warnings from .lazy_string import lazy_string from sage.env import DOT_SAGE, HOSTNAME from sage.misc.lazy_import import lazy_import +lazy_import("sage.combinat.subset", ["powerset", "subsets", "uniq"], + deprecation=35564) + lazy_import("sage.misc.call", ["AttrCallObject", "attrcall", "call_method"], deprecation=29869) @@ -58,6 +62,9 @@ lazy_import("sage.misc.repr", ["coeff_repr", "repr_lincomb"], deprecation=29892) +lazy_import("sage.misc.timing", ["cputime", "GlobalCputime", "walltime"], + deprecation=35816) + LOCAL_IDENTIFIER = '%s.%s' % (HOSTNAME, os.getpid()) ################################################################# @@ -291,233 +298,6 @@ def SPYX_TMP(): except KeyError: pass -################################################################# -# timing -################################################################# - - -def cputime(t=0, subprocesses=False): - """ - Return the time in CPU seconds since Sage started, or with - optional argument ``t``, return the time since ``t``. This is how - much time Sage has spent using the CPU. If ``subprocesses=False`` - this does not count time spent in subprocesses spawned by Sage - (e.g., Gap, Singular, etc.). If ``subprocesses=True`` this - function tries to take all subprocesses with a working - ``cputime()`` implementation into account. - - The measurement for the main Sage process is done via a call to - :func:`resource.getrusage()`, so it avoids the wraparound problems in - :func:`time.clock()` on Cygwin. - - INPUT: - - - ``t`` - (optional) time in CPU seconds, if ``t`` is a result - from an earlier call with ``subprocesses=True``, then - ``subprocesses=True`` is assumed. - - - subprocesses -- (optional), include subprocesses (default: - ``False``) - - OUTPUT: - - - ``float`` - time in CPU seconds if ``subprocesses=False`` - - - :class:`GlobalCputime` - object which holds CPU times of - subprocesses otherwise - - EXAMPLES:: - - sage: t = cputime() - sage: F = gp.factor(2^199-1) - sage: cputime(t) # somewhat random - 0.010999000000000092 - - sage: t = cputime(subprocesses=True) - sage: F = gp.factor(2^199-1) - sage: cputime(t) # somewhat random - 0.091999 - - sage: w = walltime() - sage: F = gp.factor(2^199-1) - sage: walltime(w) # somewhat random - 0.58425593376159668 - - .. NOTE:: - - Even with ``subprocesses=True`` there is no guarantee that the - CPU time is reported correctly because subprocesses can be - started and terminated at any given time. - """ - if isinstance(t, GlobalCputime): - subprocesses = True - - if not subprocesses: - try: - t = float(t) - except TypeError: - t = 0.0 - u, s = resource.getrusage(resource.RUSAGE_SELF)[:2] - return u + s - t - else: - from sage.interfaces.quit import expect_objects - if t == 0: - ret = GlobalCputime(cputime()) - for s in expect_objects: - S = s() - if S and S.is_running(): - try: - ct = S.cputime() - ret.total += ct - ret.interfaces[s] = ct - except NotImplementedError: - pass - return ret - else: - if not isinstance(t, GlobalCputime): - t = GlobalCputime(t) - ret = GlobalCputime(cputime() - t.local) - for s in expect_objects: - S = s() - if S and S.is_running(): - try: - ct = S.cputime() - t.interfaces.get(s, 0.0) - ret.total += ct - ret.interfaces[s] = ct - except NotImplementedError: - pass - return ret - - -class GlobalCputime: - """ - Container for CPU times of subprocesses. - - AUTHOR: - - - Martin Albrecht - (2008-12): initial version - - EXAMPLES: - - Objects of this type are returned if ``subprocesses=True`` is - passed to :func:`cputime`:: - - sage: cputime(subprocesses=True) # indirect doctest, output random - 0.2347431 - - We can use it to keep track of the CPU time spent in Singular for - example:: - - sage: t = cputime(subprocesses=True) - sage: P = PolynomialRing(QQ,7,'x') - sage: I = sage.rings.ideal.Katsura(P) - sage: gb = I.groebner_basis() # calls Singular - sage: cputime(subprocesses=True) - t # output random - 0.462987 - - For further processing we can then convert this container to a - float:: - - sage: t = cputime(subprocesses=True) - sage: float(t) #output somewhat random - 2.1088339999999999 - - .. SEEALSO:: - - :func:`cputime` - """ - def __init__(self, t): - """ - Create a new CPU time object which also keeps track of - subprocesses. - - EXAMPLES:: - - sage: from sage.misc.misc import GlobalCputime - sage: ct = GlobalCputime(0.0); ct - 0.0... - """ - self.total = t - self.local = t - self.interfaces = {} - - def __repr__(self): - """ - EXAMPLES:: - - sage: cputime(subprocesses=True) # indirect doctest, output random - 0.2347431 - """ - return str(self.total) - - def __add__(self, other): - """ - EXAMPLES:: - - sage: t = cputime(subprocesses=True) - sage: P = PolynomialRing(QQ,7,'x') - sage: I = sage.rings.ideal.Katsura(P) - sage: gb = I.groebner_basis() # calls Singular - sage: cputime(subprocesses=True) + t # output random - 2.798708 - """ - if not isinstance(other, GlobalCputime): - other = GlobalCputime(other) - ret = GlobalCputime(self.total + other.total) - return ret - - def __sub__(self, other): - """ - EXAMPLES:: - - sage: t = cputime(subprocesses=True) - sage: P = PolynomialRing(QQ,7,'x') - sage: I = sage.rings.ideal.Katsura(P) - sage: gb = I.groebner_basis() # calls Singular - sage: cputime(subprocesses=True) - t # output random - 0.462987 - """ - if not isinstance(other, GlobalCputime): - other = GlobalCputime(other) - ret = GlobalCputime(self.total - other.total) - return ret - - def __float__(self): - """ - EXAMPLES:: - - sage: t = cputime(subprocesses=True) - sage: float(t) #output somewhat random - 2.1088339999999999 - """ - return float(self.total) - - -def walltime(t=0): - """ - Return the wall time in second, or with optional argument t, return - the wall time since time t. "Wall time" means the time on a wall - clock, i.e., the actual time. - - INPUT: - - - - ``t`` - (optional) float, time in CPU seconds - - OUTPUT: - - - ``float`` - time in seconds - - - EXAMPLES:: - - sage: w = walltime() - sage: F = factor(2^199-1) - sage: walltime(w) # somewhat random - 0.8823847770690918 - """ - return time.time() - t - def union(x, y=None): """ @@ -554,53 +334,6 @@ def union(x, y=None): return list(set(x).union(y)) -def uniq(x): - """ - Return the sublist of all elements in the list x that is sorted and - is such that the entries in the sublist are unique. - - EXAMPLES:: - - sage: uniq([1, 1, 8, -5, 3, -5, -13, 13, -13]) - doctest:...: DeprecationWarning: the output of uniq(X) being sorted is deprecated; use sorted(set(X)) instead if you want sorted output - See https://github.com/sagemath/sage/issues/27014 for details. - [-13, -5, 1, 3, 8, 13] - """ - # After deprecation period, rename _stable_uniq -> uniq - from sage.misc.superseded import deprecation - deprecation(27014, "the output of uniq(X) being sorted is deprecated; use sorted(set(X)) instead if you want sorted output") - return sorted(set(x)) - - -def _stable_uniq(L): - """ - Iterate over the elements of ``L``, yielding every element at most - once: keep only the first occurrence of any item. - - The items must be hashable. - - INPUT: - - - ``L`` -- iterable - - EXAMPLES:: - - sage: from sage.misc.misc import _stable_uniq - sage: L = [1, 1, 8, -5, 3, -5, 'a', 'x', 'a'] - sage: it = _stable_uniq(L) - sage: it - <generator object _stable_uniq at ...> - sage: list(it) - [1, 8, -5, 3, 'a', 'x'] - """ - seen = set() - for x in L: - if x in seen: - continue - yield x - seen.add(x) - - def exactly_one_is_true(iterable): r""" Return whether exactly one element of ``iterable`` evaluates ``True``. @@ -723,19 +456,19 @@ def compose(f, g): sage: def g(x): return 3*x sage: def f(x): return x + 1 - sage: h1 = compose(f,g) - sage: h2 = compose(g,f) - sage: _ = var ('x') - sage: h1(x) + sage: h1 = compose(f, g) + sage: h2 = compose(g, f) + sage: _ = var('x') # needs sage.symbolic + sage: h1(x) # needs sage.symbolic 3*x + 1 - sage: h2(x) + sage: h2(x) # needs sage.symbolic 3*x + 3 :: - sage: _ = function('f g') - sage: _ = var ('x') - sage: compose(f,g)(x) + sage: _ = function('f g') # needs sage.symbolic + sage: _ = var('x') # needs sage.symbolic + sage: compose(f, g)(x) # needs sage.symbolic f(g(x)) """ @@ -759,22 +492,22 @@ def nest(f, n, x): EXAMPLES:: sage: def f(x): return x^2 + 1 - sage: x = var('x') - sage: nest(f, 3, x) + sage: x = var('x') # needs sage.symbolic + sage: nest(f, 3, x) # needs sage.symbolic ((x^2 + 1)^2 + 1)^2 + 1 :: - sage: _ = function('f') - sage: _ = var('x') - sage: nest(f, 10, x) + sage: _ = function('f') # needs sage.symbolic + sage: _ = var('x') # needs sage.symbolic + sage: nest(f, 10, x) # needs sage.symbolic f(f(f(f(f(f(f(f(f(f(x)))))))))) :: - sage: _ = function('f') - sage: _ = var('x') - sage: nest(f, 0, x) + sage: _ = function('f') # needs sage.symbolic + sage: _ = var('x') # needs sage.symbolic + sage: nest(f, 0, x) # needs sage.symbolic x """ @@ -821,6 +554,7 @@ def __rmul__(self, left): """ EXAMPLES:: + sage: # needs sage.modules sage: A = random_matrix(ZZ, 4) sage: while A.rank() != 4: ....: A = random_matrix(ZZ, 4) @@ -839,6 +573,7 @@ def __mul__(self, right): r""" EXAMPLES:: + sage: # needs sage.modules sage: A = matrix(RDF, 5, 5, 2) sage: b = vector(RDF, 5, range(5)) sage: v = A \ b @@ -893,10 +628,10 @@ def is_iterator(it) -> bool: sage: list(x) [4, 3, 2, 1] - sage: P = Partitions(3) - sage: is_iterator(P) + sage: P = Partitions(3) # needs sage.combinat + sage: is_iterator(P) # needs sage.combinat False - sage: is_iterator(iter(P)) + sage: is_iterator(iter(P)) # needs sage.combinat True """ # see trac #7398 for a discussion @@ -1056,69 +791,6 @@ def _some_tuples_sampling(elements, repeat, max_samples, n): yield tuple(elements[j] for j in Integer(a).digits(n, padto=repeat)) -def powerset(X): - r""" - Iterator over the *list* of all subsets of the iterable X, in no - particular order. Each list appears exactly once, up to order. - - INPUT: - - - ``X`` - an iterable - - OUTPUT: iterator of lists - - EXAMPLES:: - - sage: list(powerset([1,2,3])) - [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] - sage: [z for z in powerset([0,[1,2]])] - [[], [0], [[1, 2]], [0, [1, 2]]] - - Iterating over the power set of an infinite set is also allowed:: - - sage: i = 0 - sage: L = [] - sage: for x in powerset(ZZ): - ....: if i > 10: - ....: break - ....: else: - ....: i += 1 - ....: L.append(x) - sage: print(" ".join(str(x) for x in L)) - [] [0] [1] [0, 1] [-1] [0, -1] [1, -1] [0, 1, -1] [2] [0, 2] [1, 2] - - You may also use subsets as an alias for powerset:: - - sage: subsets([1,2,3]) - <generator object ...powerset at 0x...> - sage: list(subsets([1,2,3])) - [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] - - The reason we return lists instead of sets is that the elements of - sets must be hashable and many structures on which one wants the - powerset consist of non-hashable objects. - - AUTHORS: - - - William Stein - - - Nils Bruin (2006-12-19): rewrite to work for not-necessarily - finite objects X. - """ - yield [] - pairs = [] - power2 = 1 - for x in X: - pairs.append((power2, x)) - next_power2 = power2 << 1 - for w in range(power2, next_power2): - yield [x for m, x in pairs if m & w] - power2 = next_power2 - - -subsets = powerset - - ################################################################# # Misc. ################################################################# @@ -1413,7 +1085,7 @@ def inject_variable(name, value, warn=True): sage: a 272 - That's because warn seem to not reissue twice the same warning: + That's because warn seem to not reissue twice the same warning:: sage: from warnings import warn sage: warn("blah") @@ -1465,3 +1137,68 @@ def inject_variable_test(name, value, depth): inject_variable(name, value) else: inject_variable_test(name, value, depth - 1) + + +# from https://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop +def run_once(func): + """ + Runs a function (successfully) only once. + + The running can be reset by setting the ``has_run`` attribute to False + + TESTS:: + + sage: from sage.repl.ipython_extension import run_once + sage: @run_once + ....: def foo(work): + ....: if work: + ....: return 'foo worked' + ....: raise RuntimeError("foo didn't work") + sage: foo(False) + Traceback (most recent call last): + ... + RuntimeError: foo didn't work + sage: foo(True) + 'foo worked' + sage: foo(False) + sage: foo(True) + """ + @functools.wraps(func) + def wrapper(*args, **kwargs): + if not wrapper.has_run: + result = func(*args, **kwargs) + wrapper.has_run = True + return result + wrapper.has_run = False + return wrapper + + +@contextlib.contextmanager +def increase_recursion_limit(increment): + r""" + Context manager to temporarily change the Python maximum recursion depth. + + INPUT: + + - `increment`: increment to add to the current limit + + EXAMPLES:: + + sage: from sage.misc.misc import increase_recursion_limit + sage: def rec(n): None if n == 0 else rec(n-1) + sage: rec(10000) + Traceback (most recent call last): + ... + RecursionError: maximum recursion depth exceeded... + sage: with increase_recursion_limit(10000): rec(10000) + sage: rec(10000) + Traceback (most recent call last): + ... + RecursionError: maximum recursion depth exceeded... + """ + old_limit = sys.getrecursionlimit() + sys.setrecursionlimit(old_limit + increment) + try: + yield + finally: + sys.setrecursionlimit(old_limit) diff --git a/src/sage/misc/misc_c.pyx b/src/sage/misc/misc_c.pyx index 20a0fe0016c..1a856b4ea36 100644 --- a/src/sage/misc/misc_c.pyx +++ b/src/sage/misc/misc_c.pyx @@ -23,8 +23,6 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -import sys - from cpython.sequence cimport * from cpython.list cimport * from cpython.tuple cimport * @@ -587,7 +585,7 @@ cpdef list normalize_index(object key, int size): raise IndexError("index out of range") return [index] elif isinstance(key, slice): - return list(xrange(*key.indices(size))) + return list(range(*key.indices(size))) elif type(key) is tuple: index_tuple = key elif type(key) is list: @@ -745,7 +743,7 @@ def cyflush(): EXAMPLES:: sage: R.<t> = QQ[] - sage: t^(sys.maxsize//2) + sage: t^(sys.maxsize//2) # needs sage.libs.flint Traceback (most recent call last): ... RuntimeError: FLINT exception diff --git a/src/sage/misc/nested_class.pyx b/src/sage/misc/nested_class.pyx index b601d6f7276..4863fe45554 100644 --- a/src/sage/misc/nested_class.pyx +++ b/src/sage/misc/nested_class.pyx @@ -162,18 +162,19 @@ cpdef modify_for_nested_pickle(cls, str name_prefix, module, first_run=True): ....: " class B2:", ....: " class C2: pass"] sage: import os - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython Before :trac:`9107`, the name of ``A1.B1.C1`` would have been wrong:: - sage: A1.B1.C1.__name__ # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: A1.B1.C1.__name__ 'A1.B1.C1' - sage: A1.B2.C2.__name__ # optional - sage.misc.cython + sage: A1.B2.C2.__name__ 'A1.B2.C2' - sage: A_module = sys.modules[A1.__module__] # optional - sage.misc.cython - sage: getattr(A_module, 'A1.B1.C1', 'Not found').__name__ # optional - sage.misc.cython + sage: A_module = sys.modules[A1.__module__] + sage: getattr(A_module, 'A1.B1.C1', 'Not found').__name__ 'A1.B1.C1' - sage: getattr(A_module, 'A1.B2.C2', 'Not found').__name__ # optional - sage.misc.cython + sage: getattr(A_module, 'A1.B2.C2', 'Not found').__name__ 'A1.B2.C2' """ diff --git a/src/sage/misc/package.py b/src/sage/misc/package.py index 772007c6910..dcae7d0c0fc 100644 --- a/src/sage/misc/package.py +++ b/src/sage/misc/package.py @@ -125,6 +125,42 @@ def pip_remote_version(pkg, pypi_url=DEFAULT_PYPI, ignore_URLError=False): return max(stable_releases) +def spkg_type(name): + r""" + Return the type of the Sage package with the given name. + + INPUT: + + - ``name`` -- string giving the subdirectory name of the package under + ``SAGE_PKGS`` + + EXAMPLES:: + + sage: from sage.misc.package import spkg_type + sage: spkg_type('pip') # optional - sage_spkg + 'standard' + + OUTPUT: + + The type as a string in ``('base', 'standard', 'optional', 'experimental')``. + If no ``SPKG`` exists with the given name (or the directory ``SAGE_PKGS`` is + not avaialble), ``None`` is returned. + """ + spkg_type = None + from sage.env import SAGE_PKGS + if not SAGE_PKGS: + return None + try: + f = open(os.path.join(SAGE_PKGS, name, "type")) + except IOError: + # Probably an empty directory => ignore + return None + + with f: + spkg_type = f.read().strip() + return spkg_type + + def pip_installed_packages(normalization=None): r""" Return a dictionary `name->version` of installed pip packages. @@ -140,18 +176,19 @@ def pip_installed_packages(normalization=None): EXAMPLES:: + sage: # optional - sage_spkg sage: from sage.misc.package import pip_installed_packages - sage: d = pip_installed_packages() # optional - sage_spkg - sage: 'scipy' in d or 'SciPy' in d # optional - sage_spkg + sage: d = pip_installed_packages() + sage: 'scipy' in d or 'SciPy' in d True - sage: d['beautifulsoup4'] # optional - sage_spkg beautifulsoup4 + sage: d['beautifulsoup4'] # optional - beautifulsoup4 '...' - sage: d['prompt-toolkit'] # optional - sage_spkg + sage: d['prompt-toolkit'] '...' - sage: d = pip_installed_packages(normalization='spkg') # optional - sage_spkg - sage: d['prompt_toolkit'] # optional - sage_spkg + sage: d = pip_installed_packages(normalization='spkg') + sage: d['prompt_toolkit'] '...' - sage: d['scipy'] # optional - sage_spkg + sage: d['scipy'] '...' """ with open(os.devnull, 'w') as devnull: @@ -257,27 +294,29 @@ def list_packages(*pkg_types: str, pkg_sources: List[str] = ['normal', 'pip', 's EXAMPLES:: + sage: # optional - sage_spkg sage: from sage.misc.package import list_packages - sage: L = list_packages('standard') # optional - sage_spkg - sage: sorted(L.keys()) # optional - sage_spkg, random + sage: L = list_packages('standard') + sage: sorted(L.keys()) # random ['alabaster', 'arb', 'babel', ... 'zlib'] - sage: sage_conf_info = L['sage_conf'] # optional - sage_spkg - sage: sage_conf_info.type # optional - sage_spkg + sage: sage_conf_info = L['sage_conf'] + sage: sage_conf_info.type 'standard' - sage: sage_conf_info.is_installed() # optional - sage_spkg + sage: sage_conf_info.is_installed() True - sage: sage_conf_info.source # optional - sage_spkg + sage: sage_conf_info.source 'script' - sage: L = list_packages(pkg_sources=['pip'], local=True) # optional - sage_spkg internet - sage: bp_info = L['biopython'] # optional - sage_spkg internet - sage: bp_info.type # optional - sage_spkg internet + sage: # optional - sage_spkg internet + sage: L = list_packages(pkg_sources=['pip'], local=True) + sage: bp_info = L['biopython'] + sage: bp_info.type 'optional' - sage: bp_info.source # optional - sage_spkg internet + sage: bp_info.source 'pip' Check the option ``exclude_pip``:: @@ -310,15 +349,10 @@ def list_packages(*pkg_types: str, pkg_sources: List[str] = ['normal', 'pip', 's for p in lp: - try: - f = open(os.path.join(SAGE_PKGS, p, "type")) - except IOError: - # Probably an empty directory => ignore + typ = spkg_type(p) + if not typ: continue - with f: - typ = f.read().strip() - if os.path.isfile(os.path.join(SAGE_PKGS, p, "requirements.txt")): src = 'pip' elif os.path.isfile(os.path.join(SAGE_PKGS, p, "checksums.ini")): @@ -384,12 +418,21 @@ def installed_packages(exclude_pip=True): - ``exclude_pip`` -- (optional, default: ``True``) whether "pip" packages are excluded from the list - EXAMPLES:: + EXAMPLES: + + Below we test for a standard package without ``spkg-configure.m4`` script + that should be installed in ``SAGE_LOCAL``. When Sage is installed by + the Sage distribution (indicated by feature ``sage_spkg``), we should have + the installation record for this package. (We do not test for installation + records of Python packages. Our ``SAGE_VENV`` is not necessarily the + main Sage venv; it could be a user-created venv or a venv created by tox.):: - sage: sorted(installed_packages().keys()) # optional - sage_spkg - [...'gmpy2', ...'sage_conf', ...] - sage: installed_packages()['gmpy2'] # optional - sage_spkg, random - '2.1.0b5' + sage: # optional - sage_spkg + sage: from sage.misc.package import installed_packages + sage: sorted(installed_packages().keys()) + [...'conway_polynomials', ...] + sage: installed_packages()['conway_polynomials'] # random + '0.5' .. SEEALSO:: @@ -424,12 +467,13 @@ def is_package_installed(package, exclude_pip=True): EXAMPLES:: - sage: is_package_installed('gap') # optional - sage_spkg + sage: from sage.misc.package import is_package_installed + sage: is_package_installed('conway_polynomials') # optional - sage_spkg True Giving just the beginning of the package name is not good enough:: - sage: is_package_installed('matplotli') # optional - sage_spkg + sage: is_package_installed('conway_poly') # optional - sage_spkg False Otherwise, installing "pillow" would cause this function to think @@ -494,10 +538,12 @@ def package_versions(package_type, local=False): EXAMPLES:: - sage: std = package_versions('standard', local=True) # optional - sage_spkg - sage: 'gap' in std # optional - sage_spkg + sage: # optional - sage_spkg + sage: from sage.misc.package import package_versions + sage: std = package_versions('standard', local=True) + sage: 'gap' in std True - sage: std['zlib'] # optional - sage_spkg, random + sage: std['zlib'] # random ('1.2.11.p0', '1.2.11.p0') """ return {pkg.name: (pkg.installed_version, pkg.remote_version) for pkg in list_packages(package_type, local=local).values()} @@ -556,12 +602,13 @@ def optional_packages(): EXAMPLES:: + sage: # optional - sage_spkg sage: from sage.misc.package import optional_packages - sage: installed, not_installed = optional_packages() # optional - sage_spkg + sage: installed, not_installed = optional_packages() doctest:...: DeprecationWarning: ... - sage: 'biopython' in installed + not_installed # optional - sage_spkg + sage: 'biopython' in installed + not_installed True - sage: 'biopython' in installed # optional - sage_spkg biopython + sage: 'biopython' in installed # optional - biopython True """ from sage.misc.superseded import deprecation @@ -620,16 +667,17 @@ def package_manifest(package): EXAMPLES:: + sage: # optional - sage_spkg sage: from sage.misc.package import package_manifest - sage: sagetex_manifest = package_manifest('sagetex') # optional - sage_spkg - sage: sagetex_manifest['package_name'] == 'sagetex' # optional - sage_spkg + sage: manifest = package_manifest('conway_polynomials') + sage: manifest['package_name'] == 'conway_polynomials' True - sage: 'files' in sagetex_manifest # optional - sage_spkg + sage: 'files' in manifest True Test a nonexistent package:: - sage: package_manifest('dummy-package') # optional - sage_spkg + sage: package_manifest('dummy-package') # optional - sage_spkg Traceback (most recent call last): ... KeyError: 'dummy-package' diff --git a/src/sage/misc/package_dir.py b/src/sage/misc/package_dir.py index 17e0ce7b72c..218949ca11e 100644 --- a/src/sage/misc/package_dir.py +++ b/src/sage/misc/package_dir.py @@ -14,6 +14,7 @@ import os import glob +import sys from contextlib import contextmanager @@ -154,7 +155,7 @@ def is_package_or_sage_namespace_package_dir(path, *, distribution_filter=None): :mod:`sage.cpython` is an ordinary package:: sage: from sage.misc.package_dir import is_package_or_sage_namespace_package_dir - sage: directory = os.path.dirname(sage.cpython.__file__); directory + sage: directory = sage.cpython.__path__[0]; directory '.../sage/cpython' sage: is_package_or_sage_namespace_package_dir(directory) True @@ -162,23 +163,23 @@ def is_package_or_sage_namespace_package_dir(path, *, distribution_filter=None): :mod:`sage.libs.mpfr` only has an ``__init__.pxd`` file, but we consider it a package directory for consistency with Cython:: - sage: directory = os.path.join(os.path.dirname(sage.libs.all.__file__), 'mpfr'); directory + sage: directory = os.path.join(sage.libs.__path__[0], 'mpfr'); directory '.../sage/libs/mpfr' sage: is_package_or_sage_namespace_package_dir(directory) True :mod:`sage` is designated to become an implicit namespace package:: - sage: directory = os.path.dirname(sage.env.__file__); directory + sage: directory = sage.__path__[0]; directory '.../sage' sage: is_package_or_sage_namespace_package_dir(directory) True Not a package:: - sage: directory = os.path.join(os.path.dirname(sage.symbolic.__file__), 'ginac'); directory + sage: directory = os.path.join(sage.symbolic.__path__[0], 'ginac'); directory # needs sage.symbolic '.../sage/symbolic/ginac' - sage: is_package_or_sage_namespace_package_dir(directory) + sage: is_package_or_sage_namespace_package_dir(directory) # needs sage.symbolic False """ if os.path.exists(os.path.join(path, '__init__.py')): # ordinary package @@ -211,3 +212,124 @@ def cython_namespace_package_support(): yield finally: Cython.Utils.is_package_dir = Cython.Build.Cythonize.is_package_dir = Cython.Build.Dependencies.is_package_dir = orig_is_package_dir + + +def walk_packages(path=None, prefix='', onerror=None): + r""" + Yield :class:`pkgutil.ModuleInfo` for all modules recursively on ``path``. + + This version of the standard library function :func:`pkgutil.walk_packages` + addresses https://github.com/python/cpython/issues/73444 by handling + the implicit namespace packages in the package layout used by Sage; + see :func:`is_package_or_sage_namespace_package_dir`. + + INPUT: + + - ``path`` -- a list of paths to look for modules in or + ``None`` (all accessible modules). + + - ``prefix`` -- a string to output on the front of every module name + on output. + + - ``onerror`` -- a function which gets called with one argument (the + name of the package which was being imported) if any exception + occurs while trying to import a package. If ``None``, ignore + :class:`ImportError` but propagate all other exceptions. + + EXAMPLES:: + + sage: sorted(sage.misc.package_dir.walk_packages(sage.misc.__path__)) # a namespace package + [..., ModuleInfo(module_finder=FileFinder('.../sage/misc'), name='package_dir', ispkg=False), ...] + """ + # Adapted from https://github.com/python/cpython/blob/3.11/Lib/pkgutil.py + + def iter_modules(path=None, prefix=''): + """ + Yield :class:`ModuleInfo` for all submodules on ``path``. + """ + from pkgutil import get_importer, iter_importers, ModuleInfo + + if path is None: + importers = iter_importers() + elif isinstance(path, str): + raise ValueError("path must be None or list of paths to look for modules in") + else: + importers = map(get_importer, path) + + yielded = {} + for i in importers: + for name, ispkg in iter_importer_modules(i, prefix): + if name not in yielded: + yielded[name] = 1 + yield ModuleInfo(i, name, ispkg) + + def iter_importer_modules(importer, prefix=''): + r""" + Yield :class:`ModuleInfo` for all modules of ``importer``. + """ + from importlib.machinery import FileFinder + + if isinstance(importer, FileFinder): + if importer.path is None or not os.path.isdir(importer.path): + return + + yielded = {} + import inspect + try: + filenames = os.listdir(importer.path) + except OSError: + # ignore unreadable directories like import does + filenames = [] + filenames.sort() # handle packages before same-named modules + + for fn in filenames: + modname = inspect.getmodulename(fn) + if modname and (modname in ['__init__', 'all'] + or modname.startswith('all__') + or modname in yielded): + continue + + path = os.path.join(importer.path, fn) + ispkg = False + + if not modname and os.path.isdir(path) and '.' not in fn: + modname = fn + if not (ispkg := is_package_or_sage_namespace_package_dir(path)): + continue + + if modname and '.' not in modname: + yielded[modname] = 1 + yield prefix + modname, ispkg + + elif not hasattr(importer, 'iter_modules'): + yield from [] + + else: + yield from importer.iter_modules(prefix) + + def seen(p, m={}): + if p in m: + return True + m[p] = True + + for info in iter_modules(path, prefix): + yield info + + if info.ispkg: + try: + __import__(info.name) + except ImportError: + if onerror is not None: + onerror(info.name) + except Exception: + if onerror is not None: + onerror(info.name) + else: + raise + else: + path = getattr(sys.modules[info.name], '__path__', None) or [] + + # don't traverse path items we've seen before + path = [p for p in path if not seen(p)] + + yield from walk_packages(path, info.name + '.', onerror) diff --git a/src/sage/misc/parser.pyx b/src/sage/misc/parser.pyx index 29d7a9cd7a0..ee5b041383c 100644 --- a/src/sage/misc/parser.pyx +++ b/src/sage/misc/parser.pyx @@ -20,8 +20,6 @@ AUTHOR: # https://www.gnu.org/licenses/ # *************************************************************************** -from libc.string cimport strchr -from cpython.bytes cimport PyBytes_FromStringAndSize from cpython.list cimport PyList_Append import math @@ -480,21 +478,22 @@ cdef class Parser: sage: p.parse("1+2 == 3") True - sage: p = Parser(make_var=var) - sage: p.parse("a*b^c - 3a") + sage: p = Parser(make_var=var) # needs sage.symbolic + sage: p.parse("a*b^c - 3a") # needs sage.symbolic a*b^c - 3*a sage: R.<x> = QQ[] - sage: p = Parser(make_var = {'x': x }) + sage: p = Parser(make_var={'x': x}) sage: p.parse("(x+1)^5-x") x^5 + 5*x^4 + 10*x^3 + 10*x^2 + 4*x + 1 sage: p.parse("(x+1)^5-x").parent() is R True - sage: p = Parser(make_float=RR, make_var=var, make_function={'foo': (lambda x: x*x+x)}) - sage: p.parse("1.5 + foo(b)") + sage: p = Parser(make_float=RR, make_var=var, # needs sage.symbolic + ....: make_function={'foo': (lambda x: x*x+x)}) + sage: p.parse("1.5 + foo(b)") # needs sage.symbolic b^2 + b + 1.50000000000000 - sage: p.parse("1.9").parent() + sage: p.parse("1.9").parent() # needs sage.symbolic Real Field with 53 bits of precision """ self.integer_constructor = make_int @@ -513,8 +512,8 @@ cdef class Parser: EXAMPLES:: - sage: from sage.calculus.calculus import SR_parser - sage: SR_parser._variable_constructor() + sage: from sage.calculus.calculus import SR_parser # needs sage.symbolic + sage: SR_parser._variable_constructor() # needs sage.symbolic <sage.misc.parser.LookupNameMaker... """ return self.variable_constructor @@ -525,8 +524,8 @@ cdef class Parser: EXAMPLES:: - sage: from sage.calculus.calculus import SR_parser - sage: SR_parser._callable_constructor() + sage: from sage.calculus.calculus import SR_parser # needs sage.symbolic + sage: SR_parser._callable_constructor() # needs sage.symbolic <sage.misc.parser.LookupNameMaker... """ return self.callable_constructor @@ -538,8 +537,8 @@ cdef class Parser: EXAMPLES:: sage: from sage.misc.parser import Parser - sage: p = Parser(make_var=var) - sage: p.parse("E = m c^2") + sage: p = Parser(make_var=var) # needs sage.symbolic + sage: p.parse("E = m c^2") # needs sage.symbolic E == c^2*m """ cdef Tokenizer tokens = Tokenizer(s) @@ -560,8 +559,8 @@ cdef class Parser: EXAMPLES:: sage: from sage.misc.parser import Parser - sage: p = Parser(make_var=var) - sage: p.parse_expression('a-3b^2') + sage: p = Parser(make_var=var) # needs sage.symbolic + sage: p.parse_expression('a-3b^2') # needs sage.symbolic -3*b^2 + a """ cdef Tokenizer tokens = Tokenizer(s) @@ -576,6 +575,7 @@ cdef class Parser: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.misc.parser import Parser sage: p = Parser(make_var=var) sage: p.parse_sequence("1,2,3") @@ -600,8 +600,8 @@ cdef class Parser: EXAMPLES:: sage: from sage.misc.parser import Parser, Tokenizer - sage: p = Parser(make_var=var) - sage: p.p_matrix(Tokenizer("([a,0],[0,a])")) + sage: p = Parser(make_var=var) # needs sage.symbolic + sage: p.p_matrix(Tokenizer("([a,0],[0,a])")) # needs sage.symbolic [a 0] [0 a] """ @@ -628,10 +628,10 @@ cdef class Parser: EXAMPLES:: sage: from sage.misc.parser import Parser, Tokenizer - sage: p = Parser(make_var=var) - sage: p.p_sequence(Tokenizer("[1+2,0]")) + sage: p = Parser(make_var=var) # needs sage.symbolic + sage: p.p_sequence(Tokenizer("[1+2,0]")) # needs sage.symbolic [[3, 0]] - sage: p.p_sequence(Tokenizer("(1,2,3) , [1+a, 2+b, (3+c), (4+d,)]")) + sage: p.p_sequence(Tokenizer("(1,2,3) , [1+a, 2+b, (3+c), (4+d,)]")) # needs sage.symbolic [(1, 2, 3), [a + 1, b + 2, c + 3, (d + 4,)]] """ all = [] @@ -673,10 +673,10 @@ cdef class Parser: EXAMPLES:: sage: from sage.misc.parser import Parser, Tokenizer - sage: p = Parser(make_var=var) - sage: p.p_list(Tokenizer("[1+2, 1e3]")) + sage: p = Parser(make_var=var) # needs sage.symbolic + sage: p.p_list(Tokenizer("[1+2, 1e3]")) # needs sage.symbolic [3, 1000.0] - sage: p.p_list(Tokenizer("[]")) + sage: p.p_list(Tokenizer("[]")) # needs sage.symbolic [] """ cdef int token = tokens.next() @@ -695,8 +695,8 @@ cdef class Parser: EXAMPLES:: sage: from sage.misc.parser import Parser, Tokenizer - sage: p = Parser(make_var=var) - sage: p.p_tuple(Tokenizer("( (), (1), (1,), (1,2), (1,2,3), (1+2)^2, )")) + sage: p = Parser(make_var=var) # needs sage.symbolic + sage: p.p_tuple(Tokenizer("( (), (1), (1,), (1,2), (1,2,3), (1+2)^2, )")) # needs sage.symbolic ((), 1, (1,), (1, 2), (1, 2, 3), 9) """ cdef int start = tokens.pos @@ -732,10 +732,11 @@ cdef class Parser: EXAMPLES:: sage: from sage.misc.parser import Parser, Tokenizer - sage: p = Parser(make_var=var) - sage: p.p_eqn(Tokenizer("1+a")) + sage: p = Parser(make_var=var) # needs sage.symbolic + sage: p.p_eqn(Tokenizer("1+a")) # needs sage.symbolic a + 1 + sage: # needs sage.symbolic sage: p.p_eqn(Tokenizer("a == b")) a == b sage: p.p_eqn(Tokenizer("a < b")) @@ -774,6 +775,7 @@ cdef class Parser: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser(make_var=var) sage: p.p_expr(Tokenizer("a+b")) @@ -808,6 +810,7 @@ cdef class Parser: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser(make_var=var) sage: p.p_term(Tokenizer("a*b")) @@ -885,6 +888,7 @@ cdef class Parser: sage: p.p_power(Tokenizer("2^3^2")) == 2^9 True + sage: # needs sage.symbolic sage: p = Parser(make_var=var) sage: p.p_factor(Tokenizer('x!')) factorial(x) @@ -919,6 +923,7 @@ cdef class Parser: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser(make_var=var, make_function={'sin': sin}) sage: p.p_atom(Tokenizer("1")) @@ -933,7 +938,8 @@ cdef class Parser: a + 1 sage: p.p_atom(Tokenizer("sin(1+a)")) sin(a + 1) - sage: p = Parser(make_var=var, make_function={'foo': sage.misc.parser.foo}) + sage: p = Parser(make_var=var, + ....: make_function={'foo': sage.misc.parser.foo}) sage: p.p_atom(Tokenizer("foo(a, b, key=value)")) ((a, b), {'key': value}) sage: p.p_atom(Tokenizer("foo()")) @@ -1007,22 +1013,22 @@ cdef class Parser: Parsing a normal expression:: sage: from sage.misc.parser import Parser, Tokenizer - sage: p = Parser(make_var=var) - sage: p.p_arg(Tokenizer("a+b")) + sage: p = Parser(make_var=var) # needs sage.symbolic + sage: p.p_arg(Tokenizer("a+b")) # needs sage.symbolic a + b A keyword expression argument:: sage: from sage.misc.parser import Parser, Tokenizer - sage: p = Parser(make_var=var) - sage: p.p_arg(Tokenizer("val=a+b")) + sage: p = Parser(make_var=var) # needs sage.symbolic + sage: p.p_arg(Tokenizer("val=a+b")) # needs sage.symbolic ('val', a + b) A lone list:: sage: from sage.misc.parser import Parser, Tokenizer - sage: p = Parser(make_var=var) - sage: p.p_arg(Tokenizer("[x]")) + sage: p = Parser(make_var=var) # needs sage.symbolic + sage: p.p_arg(Tokenizer("[x]")) # needs sage.symbolic [x] """ @@ -1045,6 +1051,7 @@ cdef class Parser: cdef class LookupNameMaker: cdef object names cdef object fallback + def __init__(self, names, fallback=None): """ This class wraps a dictionary as a callable for use in creating names. @@ -1053,6 +1060,7 @@ cdef class LookupNameMaker: EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.misc.parser import LookupNameMaker sage: maker = LookupNameMaker({'pi': pi}, var) sage: maker('pi') @@ -1071,8 +1079,8 @@ cdef class LookupNameMaker: sage: from sage.misc.parser import LookupNameMaker sage: maker = LookupNameMaker({}, str) - sage: maker.set_names({'a': x}) - sage: maker('a') is x + sage: maker.set_names({'a': x}) # needs sage.symbolic + sage: maker('a') is x # needs sage.symbolic True """ self.names = new_names @@ -1081,6 +1089,7 @@ cdef class LookupNameMaker: """ TESTS:: + sage: # needs sage.symbolic sage: from sage.misc.parser import LookupNameMaker sage: maker = LookupNameMaker({'a': x}, str) sage: maker('a') @@ -1095,4 +1104,4 @@ cdef class LookupNameMaker: except KeyError: if self.fallback is not None: return self.fallback(name) - raise NameError("Unknown variable: '{}'".format(name)) + raise NameError(f"Unknown variable: '{name}'") diff --git a/src/sage/misc/persist.pyx b/src/sage/misc/persist.pyx index 5362ffa9c51..780fdd40847 100644 --- a/src/sage/misc/persist.pyx +++ b/src/sage/misc/persist.pyx @@ -155,9 +155,9 @@ def load(*filename, compress=True, verbose=True, **kwargs): sage: t = tmp_filename(ext=".F") sage: with open(t, 'w') as f: ....: _ = f.write(code) - sage: load(t) - sage: hello - <fortran object> + sage: load(t) # needs numpy + sage: hello # needs numpy + <fortran ...> """ import sage.repl.load if len(filename) != 1: @@ -239,13 +239,15 @@ def save(obj, filename, compress=True, **kwargs): sage: import tempfile sage: d = tempfile.TemporaryDirectory() - sage: a = matrix(2, [1,2,3,-5/2]) + sage: a = matrix(2, [1,2, 3,-5/2]) # needs sage.modules sage: objfile = os.path.join(d.name, 'test.sobj') sage: objfile_short = os.path.join(d.name, 'test') - sage: save(a, objfile) - sage: load(objfile_short) + sage: save(a, objfile) # needs sage.modules + sage: load(objfile_short) # needs sage.modules [ 1 2] [ 3 -5/2] + + sage: # needs sage.plot sage.schemes sage: E = EllipticCurve([-1,0]) sage: P = plot(E) sage: save(P, objfile_short) # saves the plot to "test.sobj" @@ -253,9 +255,11 @@ def save(obj, filename, compress=True, **kwargs): sage: save(P, os.path.join(d.name, "filename.with.some.wrong.ext")) Traceback (most recent call last): ... - ValueError: allowed file extensions for images are '.eps', '.pdf', '.pgf', '.png', '.ps', '.sobj', '.svg'! + ValueError: allowed file extensions for images are + '.eps', '.pdf', '.pgf', '.png', '.ps', '.sobj', '.svg'! sage: print(load(objfile)) Graphics object consisting of 2 graphics primitives + sage: save("A python string", os.path.join(d.name, 'test')) sage: load(objfile) 'A python string' @@ -435,7 +439,7 @@ def register_unpickle_override(module, name, callable, call_name=None): ....: self.__dict__ = D sage: __main__.SweeterPickle = SweeterPickle sage: register_unpickle_override('__main__', 'SourPickle', SweeterPickle) - sage: loads(gherkin) + sage: loads(gherkin) # needs sage.combinat [1, 2, 3] sage: loads(dumps(SweeterPickle([1, 2, 3]))) # check that pickles work for SweeterPickle [1, 2, 3] @@ -574,7 +578,7 @@ def unpickle_global(module, name): Test that :func:`register_unpickle_override` calls in lazily imported modules are respected:: - sage: unpickle_global('sage.combinat.root_system.type_A', 'ambient_space') + sage: unpickle_global('sage.combinat.root_system.type_A', 'ambient_space') # needs sage.modules <class 'sage.combinat.root_system.type_A.AmbientSpace'> """ unpickler = unpickle_override.get((module, name)) @@ -919,9 +923,9 @@ def loads(s, compress=True, **kwargs): EXAMPLES:: - sage: a = matrix(2, [1,2,3,-4/3]) - sage: s = dumps(a) - sage: loads(s) + sage: a = matrix(2, [1,2, 3,-4/3]) # needs sage.modules + sage: s = dumps(a) # needs sage.modules + sage: loads(s) # needs sage.modules [ 1 2] [ 3 -4/3] @@ -1158,7 +1162,7 @@ def make_None(*args, **kwds): EXAMPLES:: sage: from sage.misc.persist import make_None - sage: print(make_None(42, pi, foo='bar')) + sage: print(make_None(42, pi, foo='bar')) # needs sage.symbolic None """ return None diff --git a/src/sage/misc/prandom.py b/src/sage/misc/prandom.py index 751d5b35129..800ed60aedd 100644 --- a/src/sage/misc/prandom.py +++ b/src/sage/misc/prandom.py @@ -142,9 +142,9 @@ def choice(seq): EXAMPLES:: - sage: s = [choice(list(primes(10, 100))) for i in range(5)]; s # random + sage: s = [choice(list(primes(10, 100))) for i in range(5)]; s # random # needs sage.libs.pari [17, 47, 11, 31, 47] - sage: all(t in primes(10, 100) for t in s) + sage: all(t in primes(10, 100) for t in s) # needs sage.libs.pari True """ return _pyrand().choice(seq) @@ -227,9 +227,9 @@ def uniform(a, b): sage: 0.0 <= s <= 1.0 True - sage: s = uniform(e, pi); s # random + sage: s = uniform(e, pi); s # random # needs sage.symbolic 0.5143475134191677*pi + 0.48565248658083227*e - sage: bool(e <= s <= pi) + sage: bool(e <= s <= pi) # needs sage.symbolic True """ return _pyrand().uniform(a, b) diff --git a/src/sage/misc/profiler.py b/src/sage/misc/profiler.py index c442c67693b..a8e3592d935 100644 --- a/src/sage/misc/profiler.py +++ b/src/sage/misc/profiler.py @@ -15,7 +15,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.misc import cputime +from sage.misc.timing import cputime import inspect import sys @@ -28,8 +28,9 @@ class Profiler: EXAMPLES:: + from sage.misc.profiler import Profiler sage: def f(): # not tested - ....: p = Profiler() # not tested + ....: p = Profiler() Calling ``p(message)`` creates a checkpoint:: @@ -42,11 +43,12 @@ class Profiler: You can create a checkpoints without a string; ``Profiler`` will use the source code instead:: - sage: p() # not tested - sage: y = factor(25) # not tested - sage: p("last step") # not tested - sage: z = factor(35) # not tested - sage: p() # not tested + sage: # not tested + sage: p() + sage: y = factor(25) + sage: p("last step") + sage: z = factor(35) + sage: p() This will give a nice list of timings between checkpoints:: diff --git a/src/sage/misc/random_testing.py b/src/sage/misc/random_testing.py index 13ff9be3b57..917d8789b4d 100644 --- a/src/sage/misc/random_testing.py +++ b/src/sage/misc/random_testing.py @@ -54,9 +54,9 @@ def random_testing(fn): fails (raises an exception). If you want a very long-running test using this setup, you should do - something like (in Python 2):: + something like:: - for _ in xrange(10^10): test_foo(100) + for _ in range(10^10): test_foo(100) instead of:: diff --git a/src/sage/misc/randstate.pyx b/src/sage/misc/randstate.pyx index 4af9306cb63..06d6f8ce894 100644 --- a/src/sage/misc/randstate.pyx +++ b/src/sage/misc/randstate.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups sage.libs.gap sage.libs.ntl sage.libs.pari r""" Random Number States @@ -419,7 +420,6 @@ import os import time import weakref import random as _random -import sys use_urandom = False # Check whether os.urandom() works. @@ -713,7 +713,6 @@ cdef class randstate: if self._gap_saved_seed is not None: mersenne_seed, classic_seed = self._gap_saved_seed else: - import sage.rings.integer_ring as integer_ring from sage.rings.integer_ring import ZZ seed = ZZ.random_element(long(1)<<128) classic_seed = seed diff --git a/src/sage/misc/replace_dot_all.py b/src/sage/misc/replace_dot_all.py index 320a5a15c06..3415ea83058 100644 --- a/src/sage/misc/replace_dot_all.py +++ b/src/sage/misc/replace_dot_all.py @@ -72,7 +72,7 @@ # Keep in sync with SAGE_ROOT/src/.relint.yml (namespace_pkg_all_import) default_package_regex = (r"sage(" - r"|[.](arith|categories|combinat|ext|graphs(|[.]decompositions)|interfaces|libs|matrix|misc|numerical(|[.]backends)|rings|sets)" + r"|[.](arith|categories|combinat|crypto|databases|data_structures|dynamics|ext|game_theory|games|geometry|graphs|groups|interfaces|manifolds|matrix|matroids|misc|modules|monoids|numerical|probability|quadratic_forms|quivers|rings|sat|schemes|sets|stats|tensor)[a-z0-9_.]*|[.]libs" r")[.]all") @@ -298,7 +298,7 @@ def process_line(location, line, replacements, row_index, verbose=False): sage: from sage.misc.replace_dot_all import * sage: location = os.path.join(sage.env.SAGE_SRC, 'sage/plot/arc.py') sage: replacements = find_replacements(location, package_regex='sage[.]plot[.]all', verbose=True); replacements - [[471, 24, 'from sage.plot.graphics import Graphics']] + [[476, 24, 'from sage.plot.graphics import Graphics']] sage: with open(location, "r") as file: ....: lines = file.readlines() sage: row_index, col_number, *_ = replacements[0] @@ -385,7 +385,8 @@ def make_replacements_in_file(location, package_regex=None, verbose=False, outpu write_file.write(replaced_content) # overwriting the old file contents with the new/replaced content -def walkdir_replace_dot_all(dir, file_regex=r'.*[.](py|pyx|pxi)$', package_regex=None, verbose=False): +def walkdir_replace_dot_all(dir, file_regex=r'.*[.](py|pyx|pxi)$', package_regex=None, verbose=False, *, + excluded_file_regex=r'auto-methods|replace_dot_all'): r""" Replace ``import`` statements in the files in directory ``dir`` matching the regex pattern ``file_regex``. @@ -396,6 +397,7 @@ def walkdir_replace_dot_all(dir, file_regex=r'.*[.](py|pyx|pxi)$', package_regex - ``package_regex`` -- (default: :obj:`default_package_regex`) a regular expression matching the ``sage.PAC.KAGE.all`` package names from which we do not want to import. - ``verbose`` -- if True, print statements when interesting examples are found + - ``excluded_file_regex`` -- a regular expression matching the file names to exclude EXAMPLES:: @@ -404,14 +406,14 @@ def walkdir_replace_dot_all(dir, file_regex=r'.*[.](py|pyx|pxi)$', package_regex """ global numberFiles, numberFilesMatchingRegex file_regex = re.compile(file_regex) + excluded_file_regex = re.compile(excluded_file_regex) for root, dirs, files in os.walk(dir, topdown=False): for name in files: numberFiles += 1 - if file_regex.search(name): + if file_regex.search(name) and not excluded_file_regex.search(name): numberFilesMatchingRegex += 1 location = os.path.join(root, name) - if location.find('replace_dot_all') == -1: # to avoid changing anything in this file itself - make_replacements_in_file(location, package_regex, verbose) + make_replacements_in_file(location, package_regex, verbose) # ******************************************************** EXECUTES MAIN FUNCTION ********************************************************************** @@ -438,7 +440,9 @@ def walkdir_replace_dot_all(dir, file_regex=r'.*[.](py|pyx|pxi)$', package_regex package_regex = None # Execute the main function based on the specified location and verbosity if not args.location: - args.location = [os.path.join(sage.env.SAGE_SRC, 'sage')] + from sage.env import SAGE_SRC + + args.location = [os.path.join(SAGE_SRC, 'sage')] try: for location in args.location: if not (location.endswith('.py') or location.endswith('.pxi')): diff --git a/src/sage/misc/repr.py b/src/sage/misc/repr.py index 80265ac3cc3..ae873edea95 100644 --- a/src/sage/misc/repr.py +++ b/src/sage/misc/repr.py @@ -20,11 +20,11 @@ def coeff_repr(c, is_latex=False): sage: from sage.misc.repr import coeff_repr sage: coeff_repr(QQ(1/2)) '1/2' - sage: coeff_repr(-x^2) + sage: coeff_repr(-x^2) # needs sage.symbolic '(-x^2)' sage: coeff_repr(QQ(1/2), is_latex=True) '\\frac{1}{2}' - sage: coeff_repr(-x^2, is_latex=True) + sage: coeff_repr(-x^2, is_latex=True) # needs sage.symbolic '\\left(-x^{2}\\right)' """ if not is_latex: @@ -131,12 +131,13 @@ def repr_lincomb(terms, is_latex=False, scalar_mult="*", strip_one=False, Verify that :trac:`31672` is fixed:: + sage: # needs sage.symbolic sage: alpha = var("alpha") sage: repr_lincomb([(x, alpha)], is_latex=True) '\\alpha x' sage: A.<psi> = PolynomialRing(QQ) - sage: B.<t> = FreeAlgebra(A) - sage: (psi * t)._latex_() + sage: B.<t> = FreeAlgebra(A) # needs sage.combinat sage.modules + sage: (psi * t)._latex_() # needs sage.combinat sage.modules '\\psi t' """ # Setting scalar_mult: symbol used for scalar multiplication diff --git a/src/sage/misc/reset.pyx b/src/sage/misc/reset.pyx index 50893dfea17..23cad11fb77 100644 --- a/src/sage/misc/reset.pyx +++ b/src/sage/misc/reset.pyx @@ -20,22 +20,22 @@ def reset(vars=None, attached=False): If vars is specified, just restore the value of vars and leave all other variables alone (i.e., call restore). - Note that the variables in the set sage.misc.reset.EXCLUDE are + Note that the variables in the set :obj:`sage.misc.reset.EXCLUDE` are excluded from being reset. INPUT: - - ``vars`` - a list, or space or comma separated string (default: - None), variables to restore + - ``vars`` -- a list, or space or comma separated string (default: + ``None``), variables to restore - - ``attached`` - boolean (default: False), if ``vars`` is not None, + - ``attached`` -- boolean (default: ``False``), if ``vars`` is not None, whether to detach all attached files EXAMPLES:: sage: x = 5 sage: reset() - sage: x + sage: x # needs sage.symbolic x sage: fn = tmp_filename(ext='foo.py') @@ -57,6 +57,7 @@ def reset(vars=None, attached=False): Confirm that assumptions don't survive a reset (:trac:`10855`):: + sage: # needs sage.symbolic sage: assume(x > 3) sage: assumptions() [x > 3] @@ -95,7 +96,7 @@ def restore(vars=None): INPUT: - - ``vars`` - string or list (default: None), if not None, restores + - ``vars`` -- string or list (default: ``None``), if not ``None``, restores just the given variables to the default value. EXAMPLES:: @@ -108,9 +109,9 @@ def restore(vars=None): Rational Field sage: x 10 - sage: y = var('y') + sage: y = var('y') # needs sage.symbolic sage: restore('x y') - sage: x + sage: x # needs sage.symbolic x sage: y Traceback (most recent call last): @@ -119,7 +120,7 @@ def restore(vars=None): sage: x = 10; y = 15/3; QQ='red' sage: ww = 15 sage: restore() - sage: x, QQ, ww + sage: x, QQ, ww # needs sage.symbolic (x, Rational Field, 15) sage: restore('ww') sage: ww diff --git a/src/sage/misc/rest_index_of_methods.py b/src/sage/misc/rest_index_of_methods.py index 5efb863ead3..d1b102829c9 100644 --- a/src/sage/misc/rest_index_of_methods.py +++ b/src/sage/misc/rest_index_of_methods.py @@ -14,7 +14,7 @@ from sage.misc.sageinspect import is_function_or_cython_function as _isfunction -def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True): +def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True, root=None): r""" Return a ReST table describing a list of functions. @@ -35,13 +35,19 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True): precedence over the automatically computed name for the functions. Only used when ``list_of_entries`` is a list. - - ``sort`` (boolean; ``True``) -- whether to sort the list of methods - lexicographically. + - ``sort`` -- boolean (default: ``True``); whether to sort the list of + methods lexicographically. - - ``only_local_functions`` (boolean; ``True``) -- if ``list_of_entries`` is - a module, ``only_local_functions = True`` means that imported functions - will be filtered out. This can be useful to disable for making indexes of - e.g. catalog modules such as :mod:`sage.coding.codes_catalog`. + - ``only_local_functions`` -- boolean (default: ``True``); if + ``list_of_entries`` is a module, ``only_local_functions = True`` means + that imported functions will be filtered out. This can be useful to + disable for making indexes of e.g. catalog modules such as + :mod:`sage.coding.codes_catalog`. + + - ``root`` -- module or class (default: ``None``); the module, or class, + whose elements are to be listed. This is needed to recover the class when + this method is called from :meth:`gen_thematic_rest_table_index` (see + :issue:`36178`). .. WARNING:: @@ -52,7 +58,7 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True): EXAMPLES:: sage: from sage.misc.rest_index_of_methods import gen_rest_table_index - sage: print(gen_rest_table_index([graphs.PetersenGraph])) + sage: print(gen_rest_table_index([graphs.PetersenGraph])) # needs sage.graphs .. csv-table:: :class: contentstable :widths: 30, 70 @@ -70,14 +76,14 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True): <BLANKLINE> :func:`~sage.misc.rest_index_of_methods.doc_index` @ Attribute an index name to a function. :func:`~sage.misc.rest_index_of_methods.gen_rest_table_index` @ Return a ReST table describing a list of functions. - :func:`~sage.misc.rest_index_of_methods.gen_thematic_rest_table_index` @ Return a ReST string of thematically sorted function (or methods) of a module (or class). - :func:`~sage.misc.rest_index_of_methods.list_of_subfunctions` @ Returns the functions (resp. methods) of a given module (resp. class) with their names. + :func:`~sage.misc.rest_index_of_methods.gen_thematic_rest_table_index` @ Return a ReST string of thematically sorted functions (or methods) of a module (or class). + :func:`~sage.misc.rest_index_of_methods.list_of_subfunctions` @ Return the functions (resp. methods) of a given module (resp. class) with their names. <BLANKLINE> <BLANKLINE> The table of a class:: - sage: print(gen_rest_table_index(Graph)) + sage: print(gen_rest_table_index(Graph)) # needs sage.graphs .. csv-table:: :class: contentstable :widths: 30, 70 @@ -103,6 +109,7 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True): The inherited methods do not show up:: + sage: # needs sage.graphs sage: gen_rest_table_index(sage.combinat.posets.lattices.FiniteLatticePoset).count('\n') < 75 True sage: from sage.graphs.generic_graph import GenericGraph @@ -122,8 +129,8 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True): <BLANKLINE> :func:`~sage.misc.rest_index_of_methods.doc_index` @ Attribute an index name to a function. :func:`~sage.misc.rest_index_of_methods.gen_rest_table_index` @ Return a ReST table describing a list of functions. - :func:`~sage.misc.rest_index_of_methods.gen_thematic_rest_table_index` @ Return a ReST string of thematically sorted function (or methods) of a module (or class). - :func:`~sage.misc.rest_index_of_methods.list_of_subfunctions` @ Returns the functions (resp. methods) of a given module (resp. class) with their names. + :func:`~sage.misc.rest_index_of_methods.gen_thematic_rest_table_index` @ Return a ReST string of thematically sorted functions (or methods) of a module (or class). + :func:`~sage.misc.rest_index_of_methods.list_of_subfunctions` @ Return the functions (resp. methods) of a given module (resp. class) with their names. <BLANKLINE> <BLANKLINE> sage: print(gen_rest_table_index(sage.misc.rest_index_of_methods, only_local_functions=False)) @@ -133,18 +140,25 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True): :delim: @ <BLANKLINE> :func:`~sage.misc.rest_index_of_methods.doc_index` @ Attribute an index name to a function. - :func:`~sage.misc.rest_index_of_methods.gen_thematic_rest_table_index` @ Return a ReST string of thematically sorted function (or methods) of a module (or class). - :func:`~sage.misc.rest_index_of_methods.list_of_subfunctions` @ Returns the functions (resp. methods) of a given module (resp. class) with their names. + :func:`~sage.misc.rest_index_of_methods.gen_thematic_rest_table_index` @ Return a ReST string of thematically sorted functions (or methods) of a module (or class). + :func:`~sage.misc.rest_index_of_methods.list_of_subfunctions` @ Return the functions (resp. methods) of a given module (resp. class) with their names. <BLANKLINE> <BLANKLINE> A function that is imported into a class under a different name is listed under its 'new' name:: - sage: 'cliques_maximum' in gen_rest_table_index(Graph) + sage: 'cliques_maximum' in gen_rest_table_index(Graph) # needs sage.graphs True - sage: 'all_max_cliques`' in gen_rest_table_index(Graph) + sage: 'all_max_cliques`' in gen_rest_table_index(Graph) # needs sage.graphs False + + Check that :issue:`36178` is fixed:: + + sage: print(gen_rest_table_index(Graph)) # needs sage.graphs + ... + :meth:`~sage.graphs.graph.Graph.independent_set` @ Return a maximum independent set. + ... """ if names is None: names = {} @@ -168,14 +182,24 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True): if sort: list_of_entries.sort(key=fname) + obj_or_root_is_class = False + if inspect.isclass(root): + obj_or_root_is_class = True + class_name = root.__name__ + module_name = root.__module__ + elif inspect.isclass(obj): + obj_or_root_is_class = True + class_name = obj.__name__ + module_name = obj.__module__ + for e in list_of_entries: if inspect.ismethod(e): link = ":meth:`~{module}.{cls}.{func}`".format( module=e.im_class.__module__, cls=e.im_class.__name__, func=fname(e)) - elif _isfunction(e) and inspect.isclass(obj): + elif _isfunction(e) and obj_or_root_is_class: link = ":meth:`~{module}.{cls}.{func}`".format( - module=obj.__module__, cls=obj.__name__, func=fname(e)) + module=module_name, cls=class_name, func=fname(e)) elif _isfunction(e): link = ":func:`~{module}.{func}`".format( module=e.__module__, func=fname(e)) @@ -203,15 +227,15 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True): def list_of_subfunctions(root, only_local_functions=True): r""" - Returns the functions (resp. methods) of a given module (resp. class) with their names. + Return the functions (resp. methods) of a given module (resp. class) with their names. INPUT: - ``root`` -- the module, or class, whose elements are to be listed. - - ``only_local_functions`` (boolean; ``True``) -- if ``root`` is a module, - ``only_local_functions = True`` means that imported functions will be - filtered out. This can be useful to disable for making indexes of + - ``only_local_functions`` -- boolean (default: ``True``); if ``root`` is a + module, ``only_local_functions = True`` means that imported functions will + be filtered out. This can be useful to disable for making indexes of e.g. catalog modules such as :mod:`sage.coding.codes_catalog`. OUTPUT: @@ -223,17 +247,17 @@ def list_of_subfunctions(root, only_local_functions=True): EXAMPLES:: sage: from sage.misc.rest_index_of_methods import list_of_subfunctions - sage: l = list_of_subfunctions(Graph)[0] - sage: Graph.bipartite_color in l + sage: l = list_of_subfunctions(Graph)[0] # needs sage.graphs + sage: Graph.bipartite_color in l # needs sage.graphs True TESTS: A ``staticmethod`` is not callable. We must handle them correctly, however:: - sage: class A: + sage: class A: # needs sage.graphs ....: x = staticmethod(Graph.order) - sage: list_of_subfunctions(A) + sage: list_of_subfunctions(A) # needs sage.graphs ([<function GenericGraph.order at 0x...>], {<function GenericGraph.order at 0x...>: 'x'}) @@ -255,39 +279,49 @@ def local_filter(f,name): else: return inspect.isclass(root) or not (f is gen_rest_table_index) - functions = {getattr(root,name):name for name,f in root.__dict__.items() if - (not name.startswith('_') and # private functions - not hasattr(f,'issue_number') and # deprecated functions - not inspect.isclass(f) and # classes - callable(getattr(f,'__func__',f)) and # e.g. GenericGraph.graphics_array_defaults - local_filter(f,name)) # possibly filter imported functions + def can_import(f): + # poke it to provoke a lazy import to resolve + try: + hasattr(f, 'xyz') + except ImportError: + return False + return True + + functions = {getattr(root, name): name for name, f in root.__dict__.items() if + (not name.startswith('_') and # private functions + can_import(f) and # unresolved lazy imports + not hasattr(f, 'issue_number') and # deprecated functions + not inspect.isclass(f) and # classes + callable(getattr(f, '__func__', f)) and # e.g. GenericGraph.graphics_array_defaults + local_filter(f, name)) # possibly filter imported functions } return list(functions.keys()), functions -def gen_thematic_rest_table_index(root,additional_categories=None,only_local_functions=True): +def gen_thematic_rest_table_index(root, additional_categories=None, only_local_functions=True): r""" - Return a ReST string of thematically sorted function (or methods) of a module (or class). + Return a ReST string of thematically sorted functions (or methods) of a + module (or class). INPUT: - ``root`` -- the module, or class, whose elements are to be listed. - - ``additional_categories`` -- a dictionary associating a category (given as - a string) to a function's name. Can be used when the decorator - :func:`doc_index` does not work on a function. + - ``additional_categories`` -- dictionary (default: ``None``); a dictionary + associating a category (given as a string) to a function's name. Can be + used when the decorator :func:`doc_index` does not work on a function. - - ``only_local_functions`` (boolean; ``True``) -- if ``root`` is a module, - ``only_local_functions = True`` means that imported functions will be - filtered out. This can be useful to disable for making indexes of + - ``only_local_functions`` -- boolean (default: ``True``); if ``root`` is a + module, ``only_local_functions = True`` means that imported functions will + be filtered out. This can be useful to disable for making indexes of e.g. catalog modules such as :mod:`sage.coding.codes_catalog`. EXAMPLES:: sage: from sage.misc.rest_index_of_methods import gen_thematic_rest_table_index, list_of_subfunctions - sage: l = list_of_subfunctions(Graph)[0] - sage: Graph.bipartite_color in l + sage: l = list_of_subfunctions(Graph)[0] # needs sage.graphs + sage: Graph.bipartite_color in l # needs sage.graphs True """ from collections import defaultdict @@ -307,7 +341,7 @@ def gen_thematic_rest_table_index(root,additional_categories=None,only_local_fun except AttributeError: doc_ind = "Unsorted" theme_to_function[doc_ind].append(f) - s = ["**"+theme+"**\n\n"+gen_rest_table_index(list_of_functions,names=names) + s = ["**" + theme + "**\n\n" + gen_rest_table_index(list_of_functions, names=names, root=root) for theme, list_of_functions in sorted(theme_to_function.items())] return "\n\n".join(s) @@ -335,8 +369,10 @@ def doc_index(name): 'Wouhouuuuu' """ def hey(f): - setattr(f,"doc_index",name) + setattr(f, "doc_index", name) return f return hey -__doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index([gen_rest_table_index])) + +__doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index([gen_rest_table_index, + gen_thematic_rest_table_index])) diff --git a/src/sage/misc/sage_eval.py b/src/sage/misc/sage_eval.py index 4e2a9968f24..ec6d94543f9 100644 --- a/src/sage/misc/sage_eval.py +++ b/src/sage/misc/sage_eval.py @@ -71,7 +71,7 @@ def sage_eval(source, locals=None, cmds='', preparse=True): 36 sage: eval('bernoulli(6)') 36 - sage: sage_eval('bernoulli(6)') + sage: sage_eval('bernoulli(6)') # needs sage.libs.flint 1/42 :: @@ -117,7 +117,7 @@ def sage_eval(source, locals=None, cmds='', preparse=True): :: - sage: sage_eval(('f(x) = x^2', 'f(3)')) + sage: sage_eval(('f(x) = x^2', 'f(3)')) # needs sage.symbolic 9 sage: vars = {'rt2': sqrt(2.0)} sage: sage_eval(('rt2 += 1', 'rt2', vars)) @@ -131,6 +131,7 @@ def sage_eval(source, locals=None, cmds='', preparse=True): :: + sage: # needs sage.libs.gap sage: R.<x> = PolynomialRing(RationalField()) sage: gap.eval('R:=PolynomialRing(Rationals,["x"]);') 'Rationals[x]' @@ -198,7 +199,6 @@ def sage_eval(source, locals=None, cmds='', preparse=True): return eval(source, sage.all.__dict__, locals) - def sageobj(x, vars=None): """ Return a native Sage object associated to ``x``, if possible and @@ -213,8 +213,9 @@ def sageobj(x, vars=None): EXAMPLES:: - sage: type(sageobj(gp('34/56'))) + sage: type(sageobj(gp('34/56'))) # needs sage.libs.pari <class 'sage.rings.rational.Rational'> + sage: n = 5/2 sage: sageobj(n) is n True @@ -225,6 +226,7 @@ def sageobj(x, vars=None): This illustrates interfaces:: + sage: # needs sage.libs.pari sage: f = gp('2/3') sage: type(f) <class 'sage.interfaces.gp.GpElement'> @@ -232,6 +234,8 @@ def sageobj(x, vars=None): 2/3 sage: type(f._sage_()) <class 'sage.rings.rational.Rational'> + + sage: # needs sage.libs.gap sage: a = gap(939393/2433) sage: a._sage_() 313131/811 diff --git a/src/sage/misc/sage_input.py b/src/sage/misc/sage_input.py index a50bf15d708..66e78ecccbc 100644 --- a/src/sage/misc/sage_input.py +++ b/src/sage/misc/sage_input.py @@ -13,7 +13,7 @@ sage: sage_input(3) 3 - sage: sage_input((polygen(RR) + RR(pi))^2, verify=True) + sage: sage_input((polygen(RR) + RR(pi))^2, verify=True) # needs sage.symbolic # Verified R.<x> = RR[] x^2 + 6.2831853071795862*x + 9.869604401089358 @@ -172,6 +172,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.rings.real_mpfi', 'RealIntervalFieldElement') +lazy_import('sage.rings.complex_interval', 'ComplexIntervalFieldElement') + def sage_input(x, preparse=True, verify=False, allow_locals=False): r""" @@ -224,6 +229,7 @@ def sage_input(x, preparse=True, verify=False, allow_locals=False): The result of :func:`sage_input` is actually a pair of strings with a special ``__repr__`` method to print nicely.:: + sage: # needs sage.rings.real_mpfr sage.symbolic sage: r = sage_input(RealField(20)(pi), verify=True) sage: r # Verified @@ -373,9 +379,9 @@ def __call__(self, x, coerced=False): sage: sib = SageInputBuilder() sage: sib.result(sib(GF(17)(5), True)) 5 - sage: sib.result(sib(RealField(200)(1.5), True)) + sage: sib.result(sib(RealField(200)(1.5), True)) # needs sage.rings.real_mpfr 1.5000000000000000000000000000000000000000000000000000000000000 - sage: sib.result(sib(RealField(200)(1.5), 2)) + sage: sib.result(sib(RealField(200)(1.5), 2)) # needs sage.rings.real_mpfr 1.5 Since :func:`sage_input` directly calls this method, all @@ -395,13 +401,13 @@ def __call__(self, x, coerced=False): sage: sage_input(float(-infinity), preparse=True, verify=True) # Verified -float(infinity) - sage: sage_input(float(NaN), preparse=True, verify=True) + sage: sage_input(float(NaN), preparse=True, verify=True) # needs sage.symbolic # Verified float(NaN) - sage: sage_input(float(-pi), preparse=True, verify=True) + sage: sage_input(float(-pi), preparse=True, verify=True) # needs sage.symbolic # Verified float(-RR(3.1415926535897931)) - sage: sage_input(float(42), preparse=True, verify=True) + sage: sage_input(float(42), preparse=True, verify=True) # needs sage.rings.real_mpfr # Verified float(42) sage: sage_input("Hello, world\n", verify=True) @@ -422,7 +428,7 @@ def __call__(self, x, coerced=False): sage: sage_input('unicode with spectral: \u1234\U00012345', verify=True) # Verified 'unicode with spectral: \u1234\U00012345' - sage: sage_input((2, 3.5, 'Hi'), verify=True) + sage: sage_input((2, 3.5, 'Hi'), verify=True) # needs sage.rings.real_mpfr # Verified (2, 3.5, 'Hi') sage: sage_input(lambda x: x) @@ -581,7 +587,7 @@ def float_str(self, n): sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() - sage: sib.result(sib.float_str(repr(RR(e)))) + sage: sib.result(sib.float_str(repr(RR(e)))) # needs sage.symbolic 2.71828182845905 """ return SIE_literal_stringrep(self, n) @@ -1747,7 +1753,7 @@ class SIE_literal_stringrep(SIE_literal): sage: sib = SageInputBuilder() sage: isinstance(sib(3), SIE_literal_stringrep) True - sage: isinstance(sib(3.14159, True), SIE_literal_stringrep) + sage: isinstance(sib(3.14159, True), SIE_literal_stringrep) # needs sage.rings.real_mpfr True sage: isinstance(sib.name('pi'), SIE_literal_stringrep) True @@ -2153,7 +2159,7 @@ def __init__(self, sib, values, is_list): sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() - sage: sib((3.5, -2)) + sage: sib((3.5, -2)) # needs sage.rings.real_mpfr {tuple: ({atomic:3.5}, {unop:- {atomic:2}})} sage: sib(["Hello", "world"]) {list: ({atomic:'Hello'}, {atomic:'world'})} @@ -2238,10 +2244,12 @@ class SIE_dict(SageInputExpression): sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() - sage: sib.dict([('TeX', RR(pi)), ('Metafont', RR(e))]) - {dict: {{atomic:'TeX'}:{call: {atomic:RR}({atomic:3.1415926535897931})}, {atomic:'Metafont'}:{call: {atomic:RR}({atomic:2.7182818284590451})}}} + sage: sib.dict([('TeX', RR(pi)), ('Metafont', RR(e))]) # needs sage.symbolic + {dict: {{atomic:'TeX'}:{call: {atomic:RR}({atomic:3.1415926535897931})}, + {atomic:'Metafont'}:{call: {atomic:RR}({atomic:2.7182818284590451})}}} sage: sib.dict({-40:-40, 0:32, 100:212}) - {dict: {{unop:- {atomic:40}}:{unop:- {atomic:40}}, {atomic:0}:{atomic:32}, {atomic:100}:{atomic:212}}} + {dict: {{unop:- {atomic:40}}:{unop:- {atomic:40}}, + {atomic:0}:{atomic:32}, {atomic:100}:{atomic:212}}} """ def __init__(self, sib, entries): @@ -3470,9 +3478,7 @@ def verify_same(a, b): assert(a.parent() == b.parent()) else: assert(type(a) is type(b)) - from sage.rings.real_mpfi import is_RealIntervalFieldElement - from sage.rings.complex_interval import is_ComplexIntervalFieldElement - if is_RealIntervalFieldElement(a) or is_ComplexIntervalFieldElement(a): + if isinstance(a, (RealIntervalFieldElement, ComplexIntervalFieldElement)): assert(a.endpoints() == b.endpoints()), "Expected %s == %s" % (a, b) return diff --git a/src/sage/misc/sage_timeit.py b/src/sage/misc/sage_timeit.py index 8250b461dd4..2f9c255543b 100644 --- a/src/sage/misc/sage_timeit.py +++ b/src/sage/misc/sage_timeit.py @@ -37,7 +37,7 @@ class SageTimeitResult(): EXAMPLES:: sage: from sage.misc.sage_timeit import SageTimeitResult - sage: SageTimeitResult( (3, 5, int(8), pi, 'ms') ) + sage: SageTimeitResult( (3, 5, int(8), pi, 'ms') ) # needs sage.symbolic 3 loops, best of 5: 3.1415927 ms per loop :: @@ -47,10 +47,10 @@ class SageTimeitResult(): sage: number = 7 sage: repeat = 13 sage: precision = int(5) - sage: best = pi / 10 ^ 9 + sage: best = pi / 10 ^ 9 # needs sage.symbolic sage: order = 3 - sage: stats = (number, repeat, precision, best * scaling[order], units[order]) - sage: SageTimeitResult(stats) + sage: stats = (number, repeat, precision, best * scaling[order], units[order]) # needs sage.symbolic + sage: SageTimeitResult(stats) # needs sage.symbolic 7 loops, best of 13: 3.1416 ns per loop If the third argument is not a Python integer, a ``TypeError`` is raised:: @@ -69,10 +69,10 @@ def __init__(self, stats, series=None): EXAMPLES:: sage: from sage.misc.sage_timeit import SageTimeitResult - sage: SageTimeitResult( (3, 5, int(8), pi, 'ms') ) + sage: SageTimeitResult( (3, 5, int(8), pi, 'ms') ) # needs sage.symbolic 3 loops, best of 5: 3.1415927 ms per loop - sage: s = SageTimeitResult( (3, 5, int(8), pi, 'ms'), [1.0,1.1,0.5]) - sage: s.series + sage: s = SageTimeitResult( (3, 5, int(8), pi, 'ms'), [1.0,1.1,0.5]) # needs sage.symbolic + sage: s.series # needs sage.symbolic [1.00000000000000, 1.10000000000000, 0.500000000000000] """ self.stats = stats @@ -85,8 +85,8 @@ def __repr__(self): EXAMPLES:: sage: from sage.misc.sage_timeit import SageTimeitResult - sage: stats = (1, 2, int(3), pi, 'ns') - sage: SageTimeitResult(stats) #indirect doctest + sage: stats = (1, 2, int(3), pi, 'ns') # needs sage.symbolic + sage: SageTimeitResult(stats) #indirect doctest # needs sage.symbolic 1 loop, best of 2: 3.14 ns per loop """ if self.stats[0] > 1: @@ -153,12 +153,12 @@ def sage_timeit(stmt, globals_dict=None, preparse=None, number=0, repeat=3, prec sage: s = sage_timeit('10^2', globals(), repeat=1000) sage: len(s.series) 1000 - sage: mean(s.series) # random output + sage: mean(s.series) # random output # needs sage.modules 3.1298141479492283e-07 sage: min(s.series) # random output 2.9258728027343752e-07 - sage: t = stats.TimeSeries(s.series) - sage: t.scale(10^6).plot_histogram(bins=20,figsize=[12,6], ymax=2) + sage: t = stats.TimeSeries(s.series) # needs numpy sage.modules + sage: t.scale(10^6).plot_histogram(bins=20,figsize=[12,6], ymax=2) # needs numpy sage.modules sage.plot Graphics object consisting of 20 graphics primitives @@ -168,7 +168,7 @@ def sage_timeit(stmt, globals_dict=None, preparse=None, number=0, repeat=3, prec sage: from sage.misc.sage_timeit import sage_timeit sage: from os import linesep as CR sage: # sage_timeit(r'a = 2\\nb=131\\nfactor(a^b-1)') - sage: sage_timeit('a = 2' + CR + 'b=131' + CR + 'factor(a^b-1)', + sage: sage_timeit('a = 2' + CR + 'b=131' + CR + 'factor(a^b-1)', # needs sage.libs.pari ....: globals(), number=10) 10 loops, best of 3: ... per loop diff --git a/src/sage/misc/sage_timeit_class.pyx b/src/sage/misc/sage_timeit_class.pyx index d6b038c9de9..5537148e358 100644 --- a/src/sage/misc/sage_timeit_class.pyx +++ b/src/sage/misc/sage_timeit_class.pyx @@ -40,7 +40,7 @@ class SageTimeit: The input can contain newlines:: - sage: timeit("a = 2\nb=131\nfactor(a^b-1)", number=25) + sage: timeit("a = 2\nb=131\nfactor(a^b-1)", number=25) # needs sage.libs.pari 25 loops, best of 3: ... per loop .. SEEALSO:: :func:`runsnake` diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 2585c327a42..fb11088dac9 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -20,7 +20,7 @@ sage: from sage.env import SAGE_DOC sage: docfilename = os.path.join(SAGE_DOC, 'html', 'en', 'reference', 'calculus', 'sage', 'symbolic', 'expression.html') - sage: with open(docfilename) as fobj: # optional - sagemath_doc_html + sage: with open(docfilename) as fobj: # needs sagemath_doc_html ....: for line in fobj: ....: if "#sage.symbolic.expression.Expression.numerical_approx" in line: ....: print(line) @@ -41,6 +41,7 @@ # **************************************************************************** import os import re +import shutil import sys import pydoc from sage.misc.temporary_file import tmp_dir @@ -589,6 +590,35 @@ def process_mathtt(s): return s +def process_optional_doctest_tags(s): + r""" + Remove ``# optional/needs`` doctest tags for present features from docstring ``s``. + + EXAMPLES: + + sage: from sage.misc.sagedoc import process_optional_doctest_tags + sage: process_optional_doctest_tags("sage: # needs sage.rings.finite_rings\nsage: K.<x> = FunctionField(GF(5^2,'a')); K\nRational function field in x over Finite Field in a of size 5^2") # needs sage.rings.finite_rings + "sage: K.<x> = FunctionField(GF(5^2,'a')); K\nRational function field in x over Finite Field in a of size 5^2" + """ + import io + from sage.doctest.external import available_software + from sage.doctest.parsing import parse_optional_tags, update_optional_tags + + start = 0 + with io.StringIO() as output: + for m in re.finditer('( *sage: *.*#.*)\n', s): + output.write(s[start:m.start(0)]) + line = m.group(1) + tags = [tag for tag in parse_optional_tags(line) + if tag not in available_software] + line = update_optional_tags(line, tags=tags) + if not re.fullmatch(' *sage: *', line): + print(line, file=output) + start = m.end(0) + output.write(s[start:]) + return output.getvalue() + + def format(s, embedded=False): r"""noreplace Format Sage documentation ``s`` for viewing with IPython. @@ -623,10 +653,10 @@ def format(s, embedded=False): EXAMPLES:: sage: from sage.misc.sagedoc import format - sage: identity_matrix(2).rook_vector.__doc__[191:263] + sage: identity_matrix(2).rook_vector.__doc__[191:263] # needs sage.modules 'Let `A` be an `m` by `n` (0,1)-matrix. We identify `A` with a chessboard' - sage: format(identity_matrix(2).rook_vector.__doc__[191:263]) + sage: format(identity_matrix(2).rook_vector.__doc__[191:263]) # needs sage.modules 'Let A be an m by n (0,1)-matrix. We identify A with a chessboard\n' If the first line of the string is 'nodetex', remove 'nodetex' but @@ -641,16 +671,16 @@ def format(s, embedded=False): '<<<identity_matrix\n' sage: format('identity_matrix>>>') 'identity_matrix>>>\n' - sage: format('<<<identity_matrix>>>') + sage: format('<<<identity_matrix>>>') # needs sage.modules '...Definition: identity_matrix(...' - sage: format('<<<identity_matrix>>>')[:28] # optional - sphinx + sage: format('<<<identity_matrix>>>')[:28] # needs sphinx 'Definition: identity_matrix(' TESTS: We check that the todo Sphinx extension is correctly activated:: - sage: sage.misc.sagedoc.format(sage.combinat.ranker.on_fly.__doc__) # optional - sphinx + sage: sage.misc.sagedoc.format(sage.combinat.ranker.on_fly.__doc__) # needs sphinx " Returns ... Todo: add tests as in combinat::rankers\n" In the following use case, the ``nodetex`` directive would have been ignored prior @@ -664,9 +694,9 @@ def format(s, embedded=False): ....: " `x \\geq y`", ....: " '''", ....: " return -x"] - sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython + sage: cython('\n'.join(cython_code)) # needs sage.misc.cython sage: from sage.misc.sageinspect import sage_getdoc - sage: print(sage_getdoc(testfunc)) # optional - sage.misc.cython + sage: print(sage_getdoc(testfunc)) # needs sage.misc.cython <BLANKLINE> This is a doc string with raw latex <BLANKLINE> @@ -694,7 +724,7 @@ def format(s, embedded=False): Check that backslashes are preserved in code blocks (:trac:`29140`):: - sage: format('::\n' # optional - sphinx + sage: format('::\n' # needs sphinx ....: '\n' ....: r' sage: print(r"\\\\.")' '\n' ....: r' \\\\.') @@ -768,6 +798,10 @@ def format(s, embedded=False): s = process_mathtt(s) s = process_extlinks(s, embedded=embedded) s = detex(s, embedded=embedded) + + if not embedded: + s = process_optional_doctest_tags(s) + return s @@ -787,7 +821,7 @@ def format_src(s): sage: from sage.misc.sagedoc import format_src sage: format_src('unladen swallow') 'unladen swallow' - sage: format_src('<<<Sq>>>')[5:15] + sage: format_src('<<<Sq>>>')[5:15] # needs sage.combinat sage.modules 'Sq(*nums):' """ if not isinstance(s, str): @@ -873,7 +907,7 @@ def _search_src_or_doc(what, string, extra1='', extra2='', extra3='', sage: from sage.misc.sagedoc import _search_src_or_doc sage: len(_search_src_or_doc('src', r'matrix\(', 'incidence_structures', 'self', 'combinat', interact=False).splitlines()) > 1 True - sage: 'abvar/homology' in _search_src_or_doc('doc', 'homology', 'variety', interact=False) # optional - sagemath_doc_html, long time (4s on sage.math, 2012) + sage: 'abvar/homology' in _search_src_or_doc('doc', 'homology', 'variety', interact=False) # long time (4s on sage.math, 2012), needs sagemath_doc_html True sage: 'divisors' in _search_src_or_doc('src', '^ *def prime', interact=False) True @@ -885,8 +919,9 @@ def _search_src_or_doc(what, string, extra1='', extra2='', extra3='', results to stdout:: sage: from sage.misc.sagedoc import _search_src_or_doc - sage: _search_src_or_doc('src', r'def _search_src_or_doc\(', - ....: interact=True) # long time + sage: _search_src_or_doc('src', # long time + ....: r'def _search_src_or_doc\(', + ....: interact=True) misc/sagedoc.py:...: def _search_src_or_doc(what, string, extra1='', extra2='', extra3='', """ @@ -1063,20 +1098,21 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', You can search for "matrix" by typing ``search_src("matrix")``. This particular search will produce many results:: - sage: len(search_src("matrix", interact=False).splitlines()) # random # long time + sage: len(search_src("matrix", interact=False).splitlines()) # random # long time 9522 You can restrict to the Sage calculus code with ``search_src("matrix", module="sage.calculus")``, and this produces many fewer results:: - sage: len(search_src("matrix", module="sage.calculus", interact=False).splitlines()) # random + sage: len(search_src("matrix", module="sage.calculus", interact=False).splitlines()) # random 26 Note that you can do tab completion on the ``module`` string. Another way to accomplish a similar search:: - sage: len(search_src("matrix", path_re="calc", interact=False).splitlines()) > 15 + sage: len(search_src("matrix", path_re="calc", # needs sage.modules + ....: interact=False).splitlines()) > 15 True The following produces an error because the string 'fetch(' is a @@ -1089,11 +1125,11 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', To fix this, *escape* the parenthesis with a backslash:: - sage: print(search_src(r" fetch\(", "def", interact=False)) # random # long time + sage: print(search_src(r" fetch\(", "def", interact=False)) # random # long time matrix/matrix0.pyx: cdef fetch(self, key): matrix/matrix0.pxd: cdef fetch(self, key) - sage: print(search_src(r" fetch\(", "def", "pyx", interact=False)) # random # long time + sage: print(search_src(r" fetch\(", "def", "pyx", interact=False)) # random # long time matrix/matrix0.pyx: cdef fetch(self, key): As noted above, the search is case-insensitive, but you can make it @@ -1127,22 +1163,22 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', :: - sage: print(search_src(r'^ *sage[:] .*search_src\(', interact=False)) # long time - misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines()) # random # long time - misc/sagedoc.py:... len(search_src("matrix", module="sage.calculus", interact=False).splitlines()) # random - misc/sagedoc.py:... len(search_src("matrix", path_re="calc", interact=False).splitlines()) > 15 - misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False)) - misc/sagedoc.py:... print(search_src(r" fetch\(", "def", interact=False)) # random # long time - misc/sagedoc.py:... print(search_src(r" fetch\(", "def", "pyx", interact=False)) # random # long time - misc/sagedoc.py:... s = search_src('Matrix', path_re='matrix', interact=False); s.find('x') > 0 - misc/sagedoc.py:... s = search_src('MatRiX', path_re='matrix', interact=False); s.find('x') > 0 - misc/sagedoc.py:... s = search_src('MatRiX', path_re='matrix', interact=False, ignore_case=False); s.find('x') > 0 - misc/sagedoc.py:... len(search_src('log', 'derivative', interact=False).splitlines()) < 40 - misc/sagedoc.py:... len(search_src('log', 'derivative', interact=False, multiline=True).splitlines()) > 70 - misc/sagedoc.py:... print(search_src(r'^ *sage[:] .*search_src\(', interact=False)) # long time - misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines()) > 9000 # long time - misc/sagedoc.py:... print(search_src('matrix', 'column', 'row', 'sub', 'start', 'index', interact=False)) # random # long time - misc/sagedoc.py:... sage: results = search_src('format_search_as_html', # long time + sage: print(search_src(r'^ *sage[:] .*search_src\(', interact=False)) # long time + misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines())... + misc/sagedoc.py:... len(search_src("matrix", module="sage.calculus", interact=False).splitlines())... + misc/sagedoc.py:... len(search_src("matrix", path_re="calc"... + misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False))... + misc/sagedoc.py:... print(search_src(r" fetch\(", "def", interact=False))... + misc/sagedoc.py:... print(search_src(r" fetch\(", "def", "pyx", interact=False))... + misc/sagedoc.py:... s = search_src('Matrix', path_re='matrix', interact=False); s.find('x') > 0... + misc/sagedoc.py:... s = search_src('MatRiX', path_re='matrix', interact=False); s.find('x') > 0... + misc/sagedoc.py:... s = search_src('MatRiX', path_re='matrix',... + misc/sagedoc.py:... len(search_src('log', 'derivative', interact=False).splitlines()) < 40... + misc/sagedoc.py:... len(search_src('log', 'derivative'... + misc/sagedoc.py:... print(search_src(r'^ *sage[:] .*search_src\(', interact=False))... + misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines()) > 9000... + misc/sagedoc.py:... print(search_src('matrix', 'column', 'row', 'sub',... + misc/sagedoc.py:... sage: results = search_src('format_search_as_html',... TESTS: @@ -1195,13 +1231,14 @@ def search_doc(string, extra1='', extra2='', extra3='', extra4='', counting the length of ``search_doc('tree', interact=False).splitlines()`` gives the number of matches. :: - sage: N = len(search_doc('tree', interact=False).splitlines()) # optional - sagemath_doc_html, long time - sage: L = search_doc('tree', whole_word=True, interact=False).splitlines() # optional - sagemath_doc_html, long time - sage: len(L) < N # optional - sagemath_doc_html, long time + sage: # long time, needs sagemath_doc_html + sage: N = len(search_doc('tree', interact=False).splitlines()) + sage: L = search_doc('tree', whole_word=True, interact=False).splitlines() + sage: len(L) < N True sage: import re sage: tree_re = re.compile(r'(^|\W)tree(\W|$)', re.I) - sage: all(tree_re.search(l) for l in L) # optional - sagemath_doc_html, long time + sage: all(tree_re.search(l) for l in L) True """ return _search_src_or_doc('doc', string, extra1=extra1, extra2=extra2, @@ -1230,11 +1267,11 @@ def search_def(name, extra1='', extra2='', extra3='', extra4='', See the documentation for :func:`search_src` for more examples. :: - sage: print(search_def("fetch", interact=False)) # random # long time + sage: print(search_def("fetch", interact=False)) # random # long time matrix/matrix0.pyx: cdef fetch(self, key): matrix/matrix0.pxd: cdef fetch(self, key) - sage: print(search_def("fetch", path_re="pyx", interact=False)) # random # long time + sage: print(search_def("fetch", path_re="pyx", interact=False)) # random # long time matrix/matrix0.pyx: cdef fetch(self, key): """ # since we convert name to a regular expression, we need to do the @@ -1361,8 +1398,8 @@ def my_getsource(obj, oname=''): EXAMPLES:: sage: from sage.misc.sagedoc import my_getsource - sage: s = my_getsource(identity_matrix) - sage: s[15:34] + sage: s = my_getsource(identity_matrix) # needs sage.modules + sage: s[15:34] # needs sage.modules 'def identity_matrix' """ try: @@ -1398,9 +1435,9 @@ class _sage_doc: EXAMPLES:: - sage: browse_sage_doc._open("reference", testing=True)[0] # optional - sagemath_doc_html, indirect doctest + sage: browse_sage_doc._open("reference", testing=True)[0] # needs sagemath_doc_html 'http://localhost:8000/doc/live/reference/index.html' - sage: browse_sage_doc(identity_matrix, 'rst')[-107:-47] + sage: browse_sage_doc(identity_matrix, 'rst')[-107:-47] # needs sage.modules 'Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring' """ def __init__(self): @@ -1428,19 +1465,19 @@ def __call__(self, obj, output='html', view=True): EXAMPLES:: - sage: browse_sage_doc(identity_matrix, 'rst') + sage: browse_sage_doc(identity_matrix, 'rst') # needs sage.modules "...**File:**...**Type:**...**Definition:** identity_matrix..." - sage: identity_matrix.__doc__ in browse_sage_doc(identity_matrix, 'rst') + sage: identity_matrix.__doc__ in browse_sage_doc(identity_matrix, 'rst') # needs sage.modules True - sage: browse_sage_doc(identity_matrix, 'html', False) # optional - sphinx sagemath_doc_html + sage: browse_sage_doc(identity_matrix, 'html', False) # needs sagemath_doc_html sphinx '...div...File:...Type:...Definition:...identity_matrix...' In the 'text' version, double colons have been replaced with single ones (among other things):: - sage: '::' in browse_sage_doc(identity_matrix, 'rst') + sage: '::' in browse_sage_doc(identity_matrix, 'rst') # needs sage.modules True - sage: '::' in browse_sage_doc(identity_matrix, 'text') # optional - sphinx + sage: '::' in browse_sage_doc(identity_matrix, 'text') # needs sphinx False """ if output != 'html' and view: @@ -1570,9 +1607,9 @@ def _open(self, name, testing=False): EXAMPLES:: - sage: browse_sage_doc._open("reference", testing=True)[0] # optional - sagemath_doc_html + sage: browse_sage_doc._open("reference", testing=True)[0] # needs sagemath_doc_html 'http://localhost:8000/doc/live/reference/index.html' - sage: browse_sage_doc._open("tutorial", testing=True)[1] # optional - sagemath_doc_html + sage: browse_sage_doc._open("tutorial", testing=True)[1] # needs sagemath_doc_html '.../html/en/tutorial/index.html' """ url = self._base_url + os.path.join(name, "index.html") @@ -1602,8 +1639,8 @@ def reference(self): EXAMPLES:: - sage: reference() # indirect doctest, not tested - sage: manual() # indirect doctest, not tested + sage: reference() # indirect doctest, not tested + sage: manual() # indirect doctest, not tested """ self._open("reference") diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 83ad5d8d4c0..f0545be7d81 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -76,8 +76,8 @@ sage: sage_getdoc(sage.rings.rational.make_rational).lstrip() 'Make a rational number ...' - sage: sage_getsource(sage.rings.rational.make_rational)[4:] - 'make_rational(s):...' + sage: sage_getsource(sage.rings.rational.make_rational) + '@cython.binding(True)\ndef make_rational(s):...' Python functions:: @@ -105,10 +105,11 @@ By :trac:`9976` and :trac:`14017`, introspection also works for interactively defined Cython code, and with rather tricky argument lines:: - sage: cython('def foo(unsigned int x=1, a=\')"\', b={not (2+1==3):\'bar\'}, *args, **kwds): return') # optional - sage.misc.cython - sage: print(sage_getsource(foo)) # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython('def foo(unsigned int x=1, a=\')"\', b={not (2+1==3):\'bar\'}, *args, **kwds): return') + sage: print(sage_getsource(foo)) def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return - sage: sage_getargspec(foo) # optional - sage.misc.cython + sage: sage_getargspec(foo) FullArgSpec(args=['x', 'a', 'b'], varargs='args', varkw='kwds', defaults=(1, ')"', {False: 'bar'}), kwonlyargs=[], kwonlydefaults=None, annotations={}) """ @@ -162,8 +163,8 @@ def is_function_or_cython_function(obj): functions:: sage: from ipywidgets.widgets.interaction import signature - sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import fast_mandelbrot_plot - sage: signature(fast_mandelbrot_plot) # random + sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import fast_mandelbrot_plot # needs sage.symbolic + sage: signature(fast_mandelbrot_plot) # random # needs sage.symbolic <IPython.utils._signatures.Signature object at 0x7f3ec8274e10> """ # We use type(obj) instead of just obj to avoid __getattr__(). @@ -223,7 +224,11 @@ def isclassinstance(obj): return (not inspect.isclass(obj) and hasattr(obj, '__class__') and hasattr(obj.__class__, '__module__') and - obj.__class__.__module__ not in builtin_mods) + obj.__class__.__module__ not in builtin_mods and + # Starting with Cython 3, Cython's builtin types have __module__ set + # to the shared module names like _cython_3_0_0. + not (isinstance(obj.__class__.__module__, str) and + obj.__class__.__module__.startswith('_cython_'))) # Parse strings of form "File: sage/rings/rational.pyx (starting at line 1080)" @@ -252,16 +257,16 @@ def _extract_embedded_position(docstring): sage: from sage.misc.sageinspect import _extract_embedded_position sage: import inspect - sage: _extract_embedded_position(inspect.getdoc(var))[1][-21:] + sage: _extract_embedded_position(inspect.getdoc(var))[1][-21:] # needs sage.symbolic 'sage/calculus/var.pyx' TESTS: The following has been fixed in :trac:`13916`:: - sage: cython('''cpdef test_funct(x,y): return''') # optional - sage.misc.cython - sage: func_doc = inspect.getdoc(test_funct) # optional - sage.misc.cython - sage: with open(_extract_embedded_position(func_doc)[1]) as f: # optional - sage.misc.cython + sage: cython('''cpdef test_funct(x,y): return''') # needs sage.misc.cython + sage: func_doc = inspect.getdoc(test_funct) # needs sage.misc.cython + sage: with open(_extract_embedded_position(func_doc)[1]) as f: # needs sage.misc.cython ....: print(f.read()) cpdef test_funct(x,y): return @@ -272,10 +277,10 @@ def _extract_embedded_position(docstring): sage: from sage.env import DOT_SAGE sage: from sage.misc.sage_ostools import restore_cwd - sage: with restore_cwd(DOT_SAGE): # optional - sage.misc.cython + sage: with restore_cwd(DOT_SAGE): # needs sage.misc.cython ....: cython('''cpdef test_funct(x,y): return''') - sage: func_doc = inspect.getdoc(test_funct) # optional - sage.misc.cython - sage: with open(_extract_embedded_position(func_doc)[1]) as f: # optional - sage.misc.cython + sage: func_doc = inspect.getdoc(test_funct) # needs sage.misc.cython + sage: with open(_extract_embedded_position(func_doc)[1]) as f: # needs sage.misc.cython ....: print(f.read()) cpdef test_funct(x,y): return @@ -1081,12 +1086,12 @@ def split_string(s, quot): tmp_group, s = _split_syntactical_unit(s) out.append(tmp_group) s = s.strip() - if tmp_group==stop: + if tmp_group == stop: return ''.join(out), s elif s.startswith(stop): out.append(stop) return ''.join(out), s[1:].strip() - raise SyntaxError("Syntactical group starting with %s did not end with %s"%(repr(start),repr(stop))) + raise SyntaxError("Syntactical group starting with %s did not end with %s" % (repr(start),repr(stop))) def _sage_getargspec_from_ast(source): @@ -1118,7 +1123,7 @@ def _sage_getargspec_from_ast(source): FullArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, varkw=None, defaults=(2, {'a': [4, 5.5, False]}, (None, True)), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: from_ast(s) == inspect.getfullargspec(context['f']) True - sage: set(from_ast(sms.sage_getsource(x)) == inspect.getfullargspec(x) for x in [factor, identity_matrix, Graph.__init__]) + sage: set(from_ast(sms.sage_getsource(x)) == inspect.getfullargspec(x) for x in [factor, identity_matrix, Graph.__init__]) # needs sage.graphs sage.modules {True} """ ast_args = ast.parse(source.lstrip()).body[0].args @@ -1203,17 +1208,21 @@ def _sage_getargspec_cython(source): sage: def dummy_python(self, *args, x=1): pass sage: sgc("def dummy_python(self, *args, x=1): pass") - FullArgSpec(args=['self', 'x'], varargs='args', varkw=None, defaults=(1,), kwonlyargs=[], kwonlydefaults=None, annotations={}) - sage: cython("def dummy_cython(self, *args, x=1): pass") + FullArgSpec(args=['self', 'x'], varargs='args', varkw=None, defaults=(1,), + kwonlyargs=[], kwonlydefaults=None, annotations={}) + sage: cython("def dummy_cython(self, *args, x=1): pass") # needs sage.misc.cython sage: sgc("def dummy_cython(self, *args, x=1): pass") - FullArgSpec(args=['self', 'x'], varargs='args', varkw=None, defaults=(1,), kwonlyargs=[], kwonlydefaults=None, annotations={}) + FullArgSpec(args=['self', 'x'], varargs='args', varkw=None, defaults=(1,), + kwonlyargs=[], kwonlydefaults=None, annotations={}) In some examples above, a syntax error was raised when a type definition contains a pointer. An exception is made for ``char*``, since C strings are acceptable input in public Cython functions:: sage: sgc('def f(char *x = "a string", z = {(1,2,3): True}): pass') - FullArgSpec(args=['x', 'z'], varargs=None, varkw=None, defaults=('a string', {(1, 2, 3): True}), kwonlyargs=[], kwonlydefaults=None, annotations={}) + FullArgSpec(args=['x', 'z'], varargs=None, varkw=None, + defaults=('a string', {(1, 2, 3): True}), + kwonlyargs=[], kwonlydefaults=None, annotations={}) AUTHORS: @@ -1254,7 +1263,7 @@ def _sage_getargspec_cython(source): nb_stars = 0 varargs = None keywords = None - while (i<l): + while (i < l): unit = cy_units[i] if expect_default: if unit in ('=','*',','): @@ -1262,13 +1271,13 @@ def _sage_getargspec_cython(source): while unit != ',': py_units.append(unit) i += 1 - if i==l: + if i == l: break unit = cy_units[i] expect_default = False name = None if nb_stars: - raise SyntaxError("The %s argument has no default"%('varargs' if nb_stars==1 else 'keywords')) + raise SyntaxError("The %s argument has no default" % ('varargs' if nb_stars == 1 else 'keywords')) continue i += 1 if unit == '*': @@ -1291,14 +1300,14 @@ def _sage_getargspec_cython(source): expect_default = True name = None if nb_stars: - raise SyntaxError("The %s argument has no default"%('varargs' if nb_stars==1 else 'keywords')) + raise SyntaxError("The %s argument has no default" % ('varargs' if nb_stars == 1 else 'keywords')) else: name = unit if name is not None: # Is "name" part of a type definition? # If it is the last identifier before '=' or ',', # then it *is* a variable name, - if i==l or cy_units[i] in ('=',','): + if i == l or cy_units[i] in ('=',','): if nb_stars == 0: py_units.append(name) elif nb_stars == 1: @@ -1352,33 +1361,33 @@ def sage_getfile(obj): sage: from sage.misc.sageinspect import sage_getfile sage: sage_getfile(sage.rings.rational) '...sage/rings/rational.pyx' - sage: sage_getfile(Sq) + sage: sage_getfile(Sq) # needs sage.combinat sage.modules '...sage/algebras/steenrod/steenrod_algebra.py' - sage: sage_getfile(x) + sage: sage_getfile(x) # needs sage.symbolic '...sage/symbolic/expression.pyx' The following tests against some bugs fixed in :trac:`9976`:: - sage: obj = sage.combinat.partition_algebra.SetPartitionsAk - sage: obj = sage.combinat.partition_algebra.SetPartitionsAk - sage: sage_getfile(obj) + sage: obj = sage.combinat.partition_algebra.SetPartitionsAk # needs sage.combinat sage.modules + sage: sage_getfile(obj) # needs sage.combinat sage.modules '...sage/combinat/partition_algebra.py' And here is another bug, fixed in :trac:`11298`:: sage: P.<x,y> = QQ[] - sage: sage_getfile(P) + sage: sage_getfile(P) # needs sage.libs.singular '...sage/rings/polynomial/multi_polynomial_libsingular...' A problem fixed in :trac:`16309`:: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' ....: class Bar: pass ....: cdef class Foo: pass ....: ''') - sage: sage_getfile(Bar) + sage: sage_getfile(Bar) # needs sage.misc.cython '...pyx' - sage: sage_getfile(Foo) + sage: sage_getfile(Foo) # needs sage.misc.cython '...pyx' By :trac:`18249`, we return an empty string for Python builtins. In that @@ -1432,9 +1441,9 @@ def sage_getfile_relative(obj): sage: from sage.misc.sageinspect import sage_getfile_relative sage: sage_getfile_relative(sage.rings.rational) 'sage/rings/rational.pyx' - sage: sage_getfile_relative(Sq) + sage: sage_getfile_relative(Sq) # needs sage.combinat sage.modules 'sage/algebras/steenrod/steenrod_algebra.py' - sage: sage_getfile_relative(x) + sage: sage_getfile_relative(x) # needs sage.symbolic 'sage/symbolic/expression.pyx' sage: sage_getfile_relative(range) '' @@ -1469,27 +1478,20 @@ def sage_getargspec(obj): INPUT: - ``obj``, any callable object + - ``obj`` -- any callable object OUTPUT: - An ``ArgSpec`` is returned. This is a named tuple - ``(args, varargs, keywords, defaults)``. - - - ``args`` is a list of the argument names (it may contain nested lists). - - - ``varargs`` and ``keywords`` are the names of the ``*`` and ``**`` - arguments or ``None``. - - - ``defaults`` is an `n`-tuple of the default values of the last `n` arguments. + A named tuple :class:`FullArgSpec` is returned, as specified by the + Python library function :func:`inspect.getfullargspec`. NOTE: - If the object has a method ``_sage_argspec_`` then the output of + If the object has a method ``_sage_argspec_``, then the output of that method is transformed into a named tuple and then returned. - If a class instance has a method ``_sage_src_`` then its output - is studied to determine the argspec. This is because currently + If a class instance has a method ``_sage_src_``, then its output + is studied to determine the argspec. This is because currently the :class:`~sage.misc.cachefunc.CachedMethod` decorator has no ``_sage_argspec_`` method. @@ -1499,50 +1501,63 @@ def sage_getargspec(obj): sage: def f(x, y, z=1, t=2, *args, **keywords): ....: pass sage: sage_getargspec(f) - FullArgSpec(args=['x', 'y', 'z', 't'], varargs='args', varkw='keywords', defaults=(1, 2), kwonlyargs=[], kwonlydefaults=None, annotations={}) + FullArgSpec(args=['x', 'y', 'z', 't'], varargs='args', varkw='keywords', + defaults=(1, 2), kwonlyargs=[], kwonlydefaults=None, annotations={}) We now run sage_getargspec on some functions from the Sage library:: - sage: sage_getargspec(identity_matrix) - FullArgSpec(args=['ring', 'n', 'sparse'], varargs=None, varkw=None, defaults=(0, False), kwonlyargs=[], kwonlydefaults=None, annotations={}) + sage: sage_getargspec(identity_matrix) # needs sage.modules + FullArgSpec(args=['ring', 'n', 'sparse'], varargs=None, varkw=None, + defaults=(0, False), kwonlyargs=[], kwonlydefaults=None, + annotations={}) sage: sage_getargspec(factor) - FullArgSpec(args=['n', 'proof', 'int_', 'algorithm', 'verbose'], varargs=None, varkw='kwds', defaults=(None, False, 'pari', 0), kwonlyargs=[], kwonlydefaults=None, annotations={}) + FullArgSpec(args=['n', 'proof', 'int_', 'algorithm', 'verbose'], + varargs=None, varkw='kwds', defaults=(None, False, 'pari', 0), + kwonlyargs=[], kwonlydefaults=None, annotations={}) - In the case of a class or a class instance, the ``ArgSpec`` of the + In the case of a class or a class instance, the :class:`FullArgSpec` of the ``__new__``, ``__init__`` or ``__call__`` method is returned:: sage: P.<x,y> = QQ[] - sage: sage_getargspec(P) - FullArgSpec(args=['base_ring', 'n', 'names', 'order'], varargs=None, varkw=None, defaults=('degrevlex',), kwonlyargs=[], kwonlydefaults=None, annotations={}) - sage: sage_getargspec(P.__class__) - FullArgSpec(args=['self', 'x'], varargs='args', varkw='kwds', defaults=(0,), kwonlyargs=[], kwonlydefaults=None, annotations={}) + sage: sage_getargspec(P) # needs sage.libs.singular + FullArgSpec(args=['base_ring', 'n', 'names', 'order'], + varargs=None, varkw=None, defaults=('degrevlex',), + kwonlyargs=[], kwonlydefaults=None, annotations={}) + sage: sage_getargspec(P.__class__) # needs sage.libs.singular + FullArgSpec(args=['self', 'x'], varargs='args', varkw='kwds', defaults=(0,), + kwonlyargs=[], kwonlydefaults=None, annotations={}) The following tests against various bugs that were fixed in :trac:`9976`:: - sage: from sage.rings.polynomial.real_roots import bernstein_polynomial_factory_ratlist - sage: sage_getargspec(bernstein_polynomial_factory_ratlist.coeffs_bitsize) - FullArgSpec(args=['self'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) - sage: from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid - sage: sage_getargspec(BooleanMonomialMonoid.gen) - FullArgSpec(args=['self', 'i'], varargs=None, varkw=None, defaults=(0,), kwonlyargs=[], kwonlydefaults=None, annotations={}) + sage: from sage.rings.polynomial.real_roots import bernstein_polynomial_factory_ratlist # needs sage.modules + sage: sage_getargspec(bernstein_polynomial_factory_ratlist.coeffs_bitsize) # needs sage.modules + FullArgSpec(args=['self'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) + sage: from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid # needs sage.rings.polynomial.pbori + sage: sage_getargspec(BooleanMonomialMonoid.gen) # needs sage.rings.polynomial.pbori + FullArgSpec(args=['self', 'i'], varargs=None, varkw=None, defaults=(0,), + kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: I = P*[x,y] - sage: sage_getargspec(I.groebner_basis) + sage: sage_getargspec(I.groebner_basis) # needs sage.libs.singular FullArgSpec(args=['self', 'algorithm', 'deg_bound', 'mult_bound', 'prot'], - varargs='args', varkw='kwds', defaults=('', None, None, False), kwonlyargs=[], kwonlydefaults=None, annotations={}) - sage: cython("cpdef int foo(x,y) except -1: return 1") - sage: sage_getargspec(foo) - FullArgSpec(args=['x', 'y'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) - - If a ``functools.partial`` instance is involved, we see no other meaningful solution + varargs='args', varkw='kwds', defaults=('', None, None, False), + kwonlyargs=[], kwonlydefaults=None, annotations={}) + sage: cython("cpdef int foo(x,y) except -1: return 1") # needs sage.misc.cython + sage: sage_getargspec(foo) # needs sage.misc.cython + FullArgSpec(args=['x', 'y'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) + + If a :func:`functools.partial` instance is involved, we see no other meaningful solution than to return the argspec of the underlying function:: - sage: def f(a,b,c,d=1): - ....: return a+b+c+d + sage: def f(a, b, c, d=1): + ....: return a + b + c + d sage: import functools - sage: f1 = functools.partial(f, 1,c=2) + sage: f1 = functools.partial(f, 1, c=2) sage: sage_getargspec(f1) - FullArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, varkw=None, defaults=(1,), kwonlyargs=[], kwonlydefaults=None, annotations={}) + FullArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, varkw=None, defaults=(1,), + kwonlyargs=[], kwonlydefaults=None, annotations={}) TESTS: @@ -1553,11 +1568,12 @@ def sage_getargspec(obj): an instance of that class does not coincide with the argspec of its call method. That behaviour is intended, since a decorated method appears to have the generic signature - ``*args,**kwds``, but in fact it is only supposed to be called + ``*args, **kwds``, but in fact it is only supposed to be called with the arguments requested by the underlying undecorated method. We saw an easy example above, namely ``I.groebner_basis``. Here is a more difficult one:: + sage: # needs sage.misc.cython sage: cython_code = [ ....: 'cdef class MyClass:', ....: ' def _sage_src_(self):', @@ -1575,26 +1591,32 @@ def foo(x, a=')"', b={(2+1):'bar', not 1:3, 3<<4:5}): return sage: sorted(spec.defaults[1].items(), key=lambda x: str(x)) [(3, 'bar'), (48, 5), (False, 3)] sage: sage.misc.sageinspect.sage_getargspec(O.__call__) - FullArgSpec(args=['self', 'm', 'n'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) + FullArgSpec(args=['self', 'm', 'n'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) :: - sage: cython('def foo(x, a=\'\\\')"\', b={not (2+1==3):\'bar\'}): return') - sage: print(sage.misc.sageinspect.sage_getsource(foo)) + sage: cython('def foo(x, a=\'\\\')"\', b={not (2+1==3):\'bar\'}): return') # needs sage.misc.cython + sage: print(sage.misc.sageinspect.sage_getsource(foo)) # needs sage.misc.cython def foo(x, a='\')"', b={not (2+1==3):'bar'}): return <BLANKLINE> - sage: sage.misc.sageinspect.sage_getargspec(foo) - FullArgSpec(args=['x', 'a', 'b'], varargs=None, varkw=None, defaults=('\')"', {False: 'bar'}), kwonlyargs=[], kwonlydefaults=None, annotations={}) + sage: sage.misc.sageinspect.sage_getargspec(foo) # needs sage.misc.cython + FullArgSpec(args=['x', 'a', 'b'], varargs=None, varkw=None, + defaults=('\')"', {False: 'bar'}), + kwonlyargs=[], kwonlydefaults=None, annotations={}) The following produced a syntax error before the patch at :trac:`11913`, see also :trac:`26906`:: - sage: sage.misc.sageinspect.sage_getargspec(r.lm) # optional - rpy2 - FullArgSpec(args=['self'], varargs='args', varkw='kwds', defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) + sage: sage.misc.sageinspect.sage_getargspec(r.lm) # optional - rpy2 + FullArgSpec(args=['self'], varargs='args', varkw='kwds', defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) The following was fixed in :trac:`16309`:: - sage: cython(''' # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython( + ....: ''' ....: class Foo: ....: @staticmethod ....: def join(categories, bint as_list = False, tuple ignore_axioms=(), tuple axioms=()): pass @@ -1612,8 +1634,9 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return Test that :trac:`17009` is fixed:: - sage: sage_getargspec(gap) - FullArgSpec(args=['self', 'x', 'name'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={}) + sage: sage_getargspec(gap) # needs sage.libs.gap + FullArgSpec(args=['self', 'x', 'name'], varargs=None, varkw=None, + defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={}) By :trac:`17814`, the following gives the correct answer (previously, the defaults would have been found ``None``):: @@ -1866,9 +1889,9 @@ def sage_getdef(obj, obj_name=''): EXAMPLES:: sage: from sage.misc.sageinspect import sage_getdef - sage: sage_getdef(identity_matrix) + sage: sage_getdef(identity_matrix) # needs sage.modules '(ring, n=0, sparse=False)' - sage: sage_getdef(identity_matrix, 'identity_matrix') + sage: sage_getdef(identity_matrix, 'identity_matrix') # needs sage.modules 'identity_matrix(ring, n=0, sparse=False)' Check that :trac:`6848` has been fixed:: @@ -1897,7 +1920,7 @@ def sage_getdef(obj, obj_name=''): # change * to \*, and change ** to \**. return obj_name + '(' + s + ')' except (AttributeError, TypeError, ValueError): - return '%s( [noargspec] )'%obj_name + return '%s( [noargspec] )' % obj_name def _sage_getdoc_unformatted(obj): @@ -1919,8 +1942,8 @@ def _sage_getdoc_unformatted(obj): Integer(x=None, base=0) File: sage/rings/integer.pyx (starting at line ...) <BLANKLINE> - The ``Integer`` class represents arbitrary precision - integers. It derives from the ``Element`` class, so + The :class:`Integer` class represents arbitrary precision + integers. It derives from the :class:`Element` class, so integers can be used as ring elements anywhere in Sage. ... @@ -1994,8 +2017,8 @@ def sage_getdoc_original(obj): sage: print(sage_getdoc_original(sage.rings.integer.Integer)) <BLANKLINE> - The ``Integer`` class represents arbitrary precision - integers. It derives from the ``Element`` class, so + The :class:`Integer` class represents arbitrary precision + integers. It derives from the :class:`Element` class, so integers can be used as ring elements anywhere in Sage. ... @@ -2033,7 +2056,7 @@ def sage_getdoc_original(obj): If an instance of a class does not have its own docstring, the docstring of its class results:: - sage: sage_getdoc_original(sage.plot.colors.aliceblue) == sage_getdoc_original(sage.plot.colors.Color) + sage: sage_getdoc_original(sage.plot.colors.aliceblue) == sage_getdoc_original(sage.plot.colors.Color) # needs sage.plot True """ @@ -2076,7 +2099,7 @@ def sage_getdoc(obj, obj_name='', embedded=False): EXAMPLES:: sage: from sage.misc.sageinspect import sage_getdoc - sage: sage_getdoc(identity_matrix)[87:124] + sage: sage_getdoc(identity_matrix)[87:124] # needs sage.modules 'Return the n x n identity matrix over' sage: def f(a,b,c,d=1): return a+b+c+d ... @@ -2129,9 +2152,9 @@ def sage_getsource(obj): EXAMPLES:: sage: from sage.misc.sageinspect import sage_getsource - sage: sage_getsource(identity_matrix)[19:60] + sage: sage_getsource(identity_matrix)[19:60] # needs sage.modules 'identity_matrix(ring, n=0, sparse=False):' - sage: sage_getsource(identity_matrix)[19:60] + sage: sage_getsource(identity_matrix)[19:60] # needs sage.modules 'identity_matrix(ring, n=0, sparse=False):' AUTHORS: @@ -2176,7 +2199,9 @@ class ParentMethods: The following was fixed in :trac:`16309`:: - sage: cython(''' # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython( + ....: ''' ....: class A: ....: def __init__(self): ....: "some init doc" @@ -2308,25 +2333,25 @@ def sage_getsourcelines(obj): EXAMPLES:: sage: from sage.misc.sageinspect import sage_getsourcelines - sage: sage_getsourcelines(matrix)[1] + sage: sage_getsourcelines(matrix)[1] # needs sage.modules 21 - sage: sage_getsourcelines(matrix)[0][0] + sage: sage_getsourcelines(matrix)[0][0] # needs sage.modules 'def matrix(*args, **kwds):\n' Some classes customize this using a ``_sage_src_lines_`` method, which gives the source lines of a class instance, but not the class itself. We demonstrate this for :class:`CachedFunction`:: - sage: cachedfib = cached_function(fibonacci) - sage: sage_getsourcelines(cachedfib)[0][0] + sage: cachedfib = cached_function(fibonacci) # needs sage.combinat + sage: sage_getsourcelines(cachedfib)[0][0] # needs sage.combinat 'def fibonacci(n, algorithm="pari") -> Integer:\n' - sage: sage_getsourcelines(type(cachedfib))[0][0] + sage: sage_getsourcelines(type(cachedfib))[0][0] # needs sage.combinat 'cdef class CachedFunction():\n' TESTS:: - sage: cython('''cpdef test_funct(x,y): return''') # optional - sage.misc.cython - sage: sage_getsourcelines(test_funct) # optional - sage.misc.cython + sage: cython('''cpdef test_funct(x,y): return''') # needs sage.misc.cython + sage: sage_getsourcelines(test_funct) # needs sage.misc.cython (['cpdef test_funct(x,y): return\n'], 1) The following tests that an instance of ``functools.partial`` is correctly @@ -2344,22 +2369,22 @@ def sage_getsourcelines(obj): sage: P.<x,y> = QQ[] sage: I = P*[x,y] - sage: sage_getsourcelines(P) + sage: sage_getsourcelines(P) # needs sage.libs.singular (['cdef class MPolynomialRing_libsingular(MPolynomialRing_base):\n', '\n', ' def __cinit__(self):\n', ...) - sage: sage_getsourcelines(I) - ([...'class MPolynomialIdeal( MPolynomialIdeal_singular_repr, \\\n', + sage: sage_getsourcelines(I) # needs sage.libs.singular + ([...'class MPolynomialIdeal(MPolynomialIdeal_singular_repr,\n', ...) - sage: x = var('x') - sage: lines, lineno = sage_getsourcelines(x); lines[0:5] + sage: x = var('x') # needs sage.symbolic + sage: lines, lineno = sage_getsourcelines(x); lines[0:5] # needs sage.symbolic ['cdef class Expression(...):\n', '\n', ' cdef GEx _gobj\n', '\n', ' cpdef object pyobject(self):\n'] - sage: lines[-1] # last line + sage: lines[-1] # last line # needs sage.symbolic ' return S\n' We show some enhancements provided by :trac:`11768`. First, we @@ -2397,10 +2422,10 @@ class Element(): sage: P.<x,y> = QQ[] sage: I = P*[x,y] sage: sage_getsourcelines(I) - ([...'class MPolynomialIdeal( MPolynomialIdeal_singular_repr, \\\n', - ' MPolynomialIdeal_macaulay2_repr, \\\n', - ' MPolynomialIdeal_magma_repr, \\\n', - ' Ideal_generic ):\n', + ([...'class MPolynomialIdeal(MPolynomialIdeal_singular_repr,\n', + ' MPolynomialIdeal_macaulay2_repr,\n', + ' MPolynomialIdeal_magma_repr,\n', + ' Ideal_generic):\n', ' def __init__(self, ring, gens, coerce=True):\n', ...) @@ -2495,7 +2520,7 @@ class Element(): # definition. first_line = source_lines[lineno-1] leading_blanks = len(first_line)-len(first_line.lstrip()) - if first_line.lstrip().startswith('def ') and "__init__" in first_line and obj.__name__!='__init__': + if first_line.lstrip().startswith('def ') and "__init__" in first_line and obj.__name__ != '__init__': ignore = False double_quote = None for lnb in range(lineno, 0, -1): @@ -2503,17 +2528,17 @@ class Element(): nfl_strip = new_first_line.lstrip() if nfl_strip.startswith('"""'): if double_quote is None: - double_quote=True + double_quote = True if double_quote: ignore = not ignore elif nfl_strip.startswith("'''"): if double_quote is None: - double_quote=False + double_quote = False if double_quote is False: ignore = not ignore if ignore: continue - if len(new_first_line)-len(nfl_strip)<leading_blanks and nfl_strip: + if len(new_first_line)-len(nfl_strip) < leading_blanks and nfl_strip: # We are not inside a doc string. So, if the indentation # is less than the indentation of the __init__ method # then we must be at the class definition! @@ -2546,6 +2571,7 @@ def sage_getvariablename(self, omit_underscore_names=True): EXAMPLES:: + sage: # needs sage.modules sage: from sage.misc.sageinspect import sage_getvariablename sage: A = random_matrix(ZZ, 100) sage: sage_getvariablename(A) @@ -2556,7 +2582,7 @@ def sage_getvariablename(self, omit_underscore_names=True): If an object is not assigned to a variable, an empty list is returned:: - sage: sage_getvariablename(random_matrix(ZZ, 60)) + sage: sage_getvariablename(random_matrix(ZZ, 60)) # needs sage.modules [] """ result = [] diff --git a/src/sage/misc/session.pyx b/src/sage/misc/session.pyx index d1aa84b92af..31454dac993 100644 --- a/src/sage/misc/session.pyx +++ b/src/sage/misc/session.pyx @@ -61,12 +61,11 @@ AUTHOR: # Copyright (C) 2007,2010 William Stein <wstein@gmail.com> # Distributed under the terms of the GNU General Public License (GPL) # The full text of the GPL is available at: -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ############################################################################# # Standard python imports import builtins -import os import types # We want the caller's locals, but locals() is emulated in Cython @@ -81,6 +80,8 @@ from sage.misc.persist import load, save, loads, dumps state_at_init = None +CythonFunctionType = type(lambda: None) + def init(state=None): """ Initialize some dictionaries needed by the :func:`show_identifiers`, @@ -312,7 +313,7 @@ def save_session(name='sage_session', verbose=False): for k in show_identifiers(hidden = True): try: x = state[k] - if isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.BuiltinMethodType, type)): + if isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.BuiltinMethodType, CythonFunctionType, type)): raise TypeError('{} is a function, method, class or type'.format(k)) # We attempt to pickle *and* unpickle every variable to diff --git a/src/sage/misc/sh.py b/src/sage/misc/sh.py index a16c987731f..968cb48cb74 100644 --- a/src/sage/misc/sh.py +++ b/src/sage/misc/sh.py @@ -32,5 +32,6 @@ def eval(self, code, globals=None, locals=None): # gets printed when doing %sh in the notebook. return '' + # Create the sh object, so that %sh mode works in the notebook. sh = Sh() diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index 017b2ec2883..6e93d8e5a51 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -107,15 +107,17 @@ def deprecation_cython(issue_number, message, stacklevel=3): with the same callsite reference as `deprecation` in a python function, whereas `deprecation` in a cython function does not:: - sage: cython(''' # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython( + ....: ''' ....: from sage.misc.superseded import deprecation_cython, deprecation ....: def foo1(): - ....: deprecation_cython(100,"boo") + ....: deprecation_cython(100, "boo") ....: def foo2(): - ....: deprecation(100,"boo") + ....: deprecation(100, "boo") ....: ''') sage: def foo3(): - ....: deprecation(100,"boo") + ....: deprecation(100, "boo") sage: if True: # Execute the three "with" blocks as one doctest ....: with warnings.catch_warnings(record=True) as w1: ....: warnings.simplefilter("always") @@ -168,7 +170,7 @@ def warning(issue_number, message, warning_class=Warning, stacklevel=3): :class:`exceptions.Warning`. """ _check_issue_number(issue_number) - message += '\nSee https://github.com/sagemath/sage/issues/'+ str(issue_number) + ' for details.' + message += '\nSee https://github.com/sagemath/sage/issues/' + str(issue_number) + ' for details.' # Stack level 3 to get the line number of the code which called # the deprecated function which called this function. @@ -352,9 +354,9 @@ def __init__(self, issue_number, func, module, instance=None, unbound=None): TESTS:: sage: from sage.misc.superseded import deprecated_function_alias - sage: g = deprecated_function_alias(13109, number_of_partitions) + sage: g = deprecated_function_alias(13109, number_of_partitions) # needs sage.combinat sage: from sage.misc.superseded import deprecated_function_alias - sage: g.__doc__ + sage: g.__doc__ # needs sage.combinat 'Deprecated: Use :func:`number_of_partitions` instead.\nSee :trac:`13109` for details.\n\n' """ _check_issue_number(issue_number) @@ -382,8 +384,8 @@ def __name__(self): TESTS:: sage: from sage.misc.superseded import deprecated_function_alias - sage: g = deprecated_function_alias(13109, number_of_partitions) - sage: g.__name__ + sage: g = deprecated_function_alias(13109, number_of_partitions) # needs sage.combinat + sage: g.__name__ # needs sage.combinat 'g' sage: from sage.misc.superseded import deprecated_function_alias @@ -395,14 +397,14 @@ def __name__(self): sage: cls().old_meth.__name__ 'old_meth' - sage: cython('\n'.join([ # optional - sage.misc.cython + sage: cython('\n'.join([ # needs sage.misc.cython ....: r"from sage.misc.superseded import deprecated_function_alias", ....: r"cdef class cython_cls():", ....: r" def new_cython_meth(self):", ....: r" return 1", ....: r" old_cython_meth = deprecated_function_alias(13109, new_cython_meth)" ....: ])) - sage: cython_cls().old_cython_meth.__name__ # optional - sage.misc.cython + sage: cython_cls().old_cython_meth.__name__ # needs sage.misc.cython 'old_cython_meth' """ # first look through variables in stack frames @@ -514,9 +516,10 @@ def deprecated_function_alias(issue_number, func): EXAMPLES:: sage: from sage.misc.superseded import deprecated_function_alias - sage: g = deprecated_function_alias(13109, number_of_partitions) - sage: g(5) - doctest:...: DeprecationWarning: g is deprecated. Please use sage.combinat.partition.number_of_partitions instead. + sage: g = deprecated_function_alias(13109, number_of_partitions) # needs sage.combinat sage.libs.flint + sage: g(5) # needs sage.combinat sage.libs.flint + doctest:...: DeprecationWarning: g is deprecated. + Please use sage.combinat.partition.number_of_partitions instead. See https://github.com/sagemath/sage/issues/13109 for details. 7 diff --git a/src/sage/misc/table.py b/src/sage/misc/table.py index cbd8b083a6b..34410b103d2 100644 --- a/src/sage/misc/table.py +++ b/src/sage/misc/table.py @@ -106,7 +106,8 @@ class table(SageObject): information. The same goes for ``header_column``. Passing lists for both arguments simultaneously is not supported. :: - sage: table([(x,n(sin(x), digits=2)) for x in [0..3]], header_row=["$x$", r"$\sin(x)$"], frame=True) + sage: table([(x,n(sin(x), digits=2)) for x in [0..3]], # needs sage.symbolic + ....: header_row=["$x$", r"$\sin(x)$"], frame=True) +-----+-----------+ | $x$ | $\sin(x)$ | +=====+===========+ @@ -122,7 +123,9 @@ class table(SageObject): You can create the transpose of this table in several ways, for example, "by hand," that is, changing the data defining the table:: - sage: table(rows=[[x for x in [0..3]], [n(sin(x), digits=2) for x in [0..3]]], header_column=['$x$', r'$\sin(x)$'], frame=True) + sage: table(rows=[[x for x in [0..3]], # needs sage.symbolic + ....: [n(sin(x), digits=2) for x in [0..3]]], + ....: header_column=['$x$', r'$\sin(x)$'], frame=True) +-----------++------+------+------+------+ | $x$ || 0 | 1 | 2 | 3 | +-----------++------+------+------+------+ @@ -132,7 +135,8 @@ class table(SageObject): or by passing the original data as the ``columns`` of the table and using ``header_column`` instead of ``header_row``:: - sage: table(columns=[(x,n(sin(x), digits=2)) for x in [0..3]], header_column=['$x$', r'$\sin(x)$'], frame=True) + sage: table(columns=[(x, n(sin(x), digits=2)) for x in [0..3]], # needs sage.symbolic + ....: header_column=['$x$', r'$\sin(x)$'], frame=True) +-----------++------+------+------+------+ | $x$ || 0 | 1 | 2 | 3 | +-----------++------+------+------+------+ @@ -141,7 +145,8 @@ class table(SageObject): or by taking the :meth:`transpose` of the original table:: - sage: table(rows=[(x,n(sin(x), digits=2)) for x in [0..3]], header_row=['$x$', r'$\sin(x)$'], frame=True).transpose() + sage: table(rows=[(x, n(sin(x), digits=2)) for x in [0..3]], # needs sage.symbolic + ....: header_row=['$x$', r'$\sin(x)$'], frame=True).transpose() +-----------++------+------+------+------+ | $x$ || 0 | 1 | 2 | 3 | +-----------++------+------+------+------+ @@ -170,7 +175,9 @@ class table(SageObject): To generate HTML you should use ``html(table(...))``:: - sage: data = [["$x$", r"$\sin(x)$"]] + [(x,n(sin(x), digits=2)) for x in [0..3]] + sage: # needs sage.symbolic + sage: data = [["$x$", r"$\sin(x)$"]] + [(x, n(sin(x), digits=2)) + ....: for x in [0..3]] sage: output = html(table(data, header_row=True, frame=True)) sage: type(output) <class 'sage.misc.html.HtmlFragment'> @@ -233,8 +240,8 @@ class table(SageObject): TESTS:: - sage: TestSuite(table([["$x$", r"$\sin(x)$"]] + - ....: [(x,n(sin(x), digits=2)) for x in [0..3]], + sage: TestSuite(table([["$x$", r"$\sin(x)$"]] + # needs sage.symbolic + ....: [(x, n(sin(x), digits=2)) for x in [0..3]], ....: header_row=True, frame=True)).run() .. automethod:: _rich_repr_ @@ -286,6 +293,7 @@ def __eq__(self, other): EXAMPLES:: + sage: # needs sage.modules sage.plot sage: rows = [['a', 'b', 'c'], [1,plot(sin(x)),3], [4,5,identity_matrix(2)]] sage: T = table(rows, header_row=True) sage: T2 = table(rows, header_row=True) @@ -561,8 +569,9 @@ def _latex_(self): EXAMPLES:: sage: from sage.misc.table import table - sage: a = [[r'$\sin(x)$', '$x$', 'text'], [1,34342,3], [identity_matrix(2),5,6]] - sage: latex(table(a)) # indirect doctest + sage: a = [[r'$\sin(x)$', '$x$', 'text'], # needs sage.modules + ....: [1, 34342, 3], [identity_matrix(2), 5, 6]] + sage: latex(table(a)) # indirect doctest # needs sage.modules \begin{tabular}{lll} $\sin(x)$ & $x$ & text \\ $1$ & $34342$ & $3$ \\ @@ -571,7 +580,7 @@ def _latex_(self): 0 & 1 \end{array}\right)$ & $5$ & $6$ \\ \end{tabular} - sage: latex(table(a, frame=True, align='center')) + sage: latex(table(a, frame=True, align='center')) # needs sage.modules \begin{tabular}{|c|c|c|} \hline $\sin(x)$ & $x$ & text \\ \hline $1$ & $34342$ & $3$ \\ \hline @@ -640,10 +649,11 @@ def _html_(self): EXAMPLES:: - sage: T = table([[r'$\sin(x)$', '$x$', 'text'], [1,34342,3], [identity_matrix(2),5,6]]) - sage: T._html_() + sage: T = table([[r'$\sin(x)$', '$x$', 'text'], # needs sage.modules + ....: [1, 34342, 3], [identity_matrix(2), 5, 6]]) + sage: T._html_() # needs sage.modules '<div.../div>' - sage: print(T._html_()) + sage: print(T._html_()) # needs sage.modules <div class="notruncate"> <table class="table_form"> <tbody> @@ -672,8 +682,10 @@ def _html_(self): Note that calling ``html(table(...))`` has the same effect as calling ``table(...)._html_()``:: - sage: T = table([["$x$", r"$\sin(x)$"]] + [(x,n(sin(x), digits=2)) for x in [0..3]], header_row=True, frame=True) - sage: T + sage: T = table([["$x$", r"$\sin(x)$"]] # needs sage.symbolic + ....: + [(x,n(sin(x), digits=2)) for x in [0..3]], + ....: header_row=True, frame=True) + sage: T # needs sage.symbolic +-----+-----------+ | $x$ | $\sin(x)$ | +=====+===========+ @@ -685,7 +697,7 @@ def _html_(self): +-----+-----------+ | 3 | 0.14 | +-----+-----------+ - sage: print(html(T)) + sage: print(html(T)) # needs sage.symbolic <div class="notruncate"> <table border="1" class="table_form"> <tbody> @@ -780,11 +792,15 @@ def _html_table_row(self, file, row, header=False): <td style="text-align:left">\(2\)</td> <td style="text-align:left">\(x\)</td> """ - from sage.plot.all import Graphics from .latex import latex from .html import math_parse import types + try: + from sage.plot.all import Graphics + except ImportError: + Graphics = () + if isinstance(row, types.GeneratorType): row = list(row) elif not isinstance(row, (list, tuple)): diff --git a/src/sage/misc/temporary_file.py b/src/sage/misc/temporary_file.py index f75e98e980e..f356eb21c64 100644 --- a/src/sage/misc/temporary_file.py +++ b/src/sage/misc/temporary_file.py @@ -33,7 +33,7 @@ # as the parent for all temporary files & directories created by them. # This lets us clean up after those two functions when sage exits normally # using an atexit hook -TMP_DIR_FILENAME_BASE=tempfile.TemporaryDirectory() +TMP_DIR_FILENAME_BASE = tempfile.TemporaryDirectory() atexit.register(lambda: TMP_DIR_FILENAME_BASE.cleanup()) diff --git a/src/sage/misc/test_nested_class.py b/src/sage/misc/test_nested_class.py index 55973bd05b3..40712bfc9fb 100644 --- a/src/sage/misc/test_nested_class.py +++ b/src/sage/misc/test_nested_class.py @@ -63,7 +63,7 @@ def __init__(self): <sage.misc.test_nested_class.TestParent1_with_category object at ...> """ from sage.categories.sets_cat import Sets - Parent.__init__(self, category = Sets()) + Parent.__init__(self, category=Sets()) class Element(ElementWrapper): pass @@ -80,7 +80,7 @@ def __init__(self): TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases """ from sage.categories.sets_cat import Sets - Parent.__init__(self, category = Sets()) + Parent.__init__(self, category=Sets()) class Element(ElementWrapper): pass @@ -96,7 +96,7 @@ def __init__(self): <sage.misc.test_nested_class.TestParent3_with_category object at ...> """ from sage.categories.sets_cat import Sets - Parent.__init__(self, category = Sets()) + Parent.__init__(self, category=Sets()) class Element(ElementWrapper): pass @@ -186,6 +186,7 @@ class C(): """ pass + C = ALB.C diff --git a/src/sage/misc/timing.py b/src/sage/misc/timing.py new file mode 100644 index 00000000000..cc2753e50b8 --- /dev/null +++ b/src/sage/misc/timing.py @@ -0,0 +1,247 @@ +r""" +Timing functions +""" + +# **************************************************************************** +# Copyright (C) 2006 William Stein <wstein@gmail.com> +# 2006 Gonzalo Tornaria +# 2008 Martin Albrecht +# 2009 Mike Hansen +# 2018 Frรฉdรฉric Chapoton +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + + +import resource +import time + + +def cputime(t=0, subprocesses=False): + """ + Return the time in CPU seconds since Sage started, or with + optional argument ``t``, return the time since ``t``. This is how + much time Sage has spent using the CPU. If ``subprocesses=False`` + this does not count time spent in subprocesses spawned by Sage + (e.g., Gap, Singular, etc.). If ``subprocesses=True`` this + function tries to take all subprocesses with a working + ``cputime()`` implementation into account. + + The measurement for the main Sage process is done via a call to + :func:`resource.getrusage()`, so it avoids the wraparound problems in + :func:`time.clock()` on Cygwin. + + INPUT: + + - ``t`` -- (optional) time in CPU seconds, if ``t`` is a result + from an earlier call with ``subprocesses=True``, then + ``subprocesses=True`` is assumed. + + - subprocesses -- (optional), include subprocesses (default: + ``False``) + + OUTPUT: + + - ``float`` -- time in CPU seconds if ``subprocesses=False`` + + - :class:`GlobalCputime` -- object which holds CPU times of + subprocesses otherwise + + EXAMPLES:: + + sage: t = cputime() + sage: F = gp.factor(2^199-1) # needs sage.libs.pari + sage: cputime(t) # somewhat random + 0.010999000000000092 + + sage: t = cputime(subprocesses=True) + sage: F = gp.factor(2^199-1) # needs sage.libs.pari + sage: cputime(t) # somewhat random + 0.091999 + + sage: w = walltime() + sage: F = gp.factor(2^199-1) # needs sage.libs.pari + sage: walltime(w) # somewhat random + 0.58425593376159668 + + .. NOTE:: + + Even with ``subprocesses=True`` there is no guarantee that the + CPU time is reported correctly because subprocesses can be + started and terminated at any given time. + """ + if isinstance(t, GlobalCputime): + subprocesses = True + + if not subprocesses: + try: + t = float(t) + except TypeError: + t = 0.0 + u, s = resource.getrusage(resource.RUSAGE_SELF)[:2] + return u + s - t + else: + try: + from sage.interfaces.quit import expect_objects + except ImportError: + expect_objects = () + if t == 0: + ret = GlobalCputime(cputime()) + for s in expect_objects: + S = s() + if S and S.is_running(): + try: + ct = S.cputime() + ret.total += ct + ret.interfaces[s] = ct + except NotImplementedError: + pass + return ret + else: + if not isinstance(t, GlobalCputime): + t = GlobalCputime(t) + ret = GlobalCputime(cputime() - t.local) + for s in expect_objects: + S = s() + if S and S.is_running(): + try: + ct = S.cputime() - t.interfaces.get(s, 0.0) + ret.total += ct + ret.interfaces[s] = ct + except NotImplementedError: + pass + return ret + + +class GlobalCputime: + """ + Container for CPU times of subprocesses. + + AUTHOR: + + - Martin Albrecht - (2008-12): initial version + + EXAMPLES: + + Objects of this type are returned if ``subprocesses=True`` is + passed to :func:`cputime`:: + + sage: cputime(subprocesses=True) # indirect doctest, output random + 0.2347431 + + We can use it to keep track of the CPU time spent in Singular for + example:: + + sage: t = cputime(subprocesses=True) + sage: P = PolynomialRing(QQ,7,'x') + sage: I = sage.rings.ideal.Katsura(P) # needs sage.libs.singular + sage: gb = I.groebner_basis() # calls Singular # needs sage.libs.singular + sage: cputime(subprocesses=True) - t # output random + 0.462987 + + For further processing we can then convert this container to a + float:: + + sage: t = cputime(subprocesses=True) + sage: float(t) # output somewhat random + 2.1088339999999999 + + .. SEEALSO:: + + :func:`cputime` + """ + def __init__(self, t): + """ + Create a new CPU time object which also keeps track of + subprocesses. + + EXAMPLES:: + + sage: from sage.misc.timing import GlobalCputime + sage: ct = GlobalCputime(0.0); ct + 0.0... + """ + self.total = t + self.local = t + self.interfaces = {} + + def __repr__(self): + """ + EXAMPLES:: + + sage: cputime(subprocesses=True) # indirect doctest, output random + 0.2347431 + """ + return str(self.total) + + def __add__(self, other): + """ + EXAMPLES:: + + sage: t = cputime(subprocesses=True) + sage: P = PolynomialRing(QQ,7,'x') + sage: I = sage.rings.ideal.Katsura(P) # needs sage.libs.singular + sage: gb = I.groebner_basis() # calls Singular # needs sage.libs.singular + sage: cputime(subprocesses=True) + t # output random + 2.798708 + """ + if not isinstance(other, GlobalCputime): + other = GlobalCputime(other) + ret = GlobalCputime(self.total + other.total) + return ret + + def __sub__(self, other): + """ + EXAMPLES:: + + sage: t = cputime(subprocesses=True) + sage: P = PolynomialRing(QQ,7,'x') + sage: I = sage.rings.ideal.Katsura(P) # needs sage.libs.singular + sage: gb = I.groebner_basis() # calls Singular # needs sage.libs.singular + sage: cputime(subprocesses=True) - t # output random + 0.462987 + """ + if not isinstance(other, GlobalCputime): + other = GlobalCputime(other) + ret = GlobalCputime(self.total - other.total) + return ret + + def __float__(self): + """ + EXAMPLES:: + + sage: t = cputime(subprocesses=True) + sage: float(t) # output somewhat random + 2.1088339999999999 + """ + return float(self.total) + + +def walltime(t=0): + """ + Return the wall time in second, or with optional argument ``t``, return + the wall time since time ``t``. "Wall time" means the time on a wall + clock, i.e., the actual time. + + INPUT: + + + - ``t`` -- (optional) float, time in CPU seconds + + OUTPUT: + + - ``float`` -- time in seconds + + + EXAMPLES:: + + sage: w = walltime() + sage: F = factor(2^199-1) # needs sage.libs.pari + sage: walltime(w) # somewhat random + 0.8823847770690918 + """ + return time.time() - t diff --git a/src/sage/misc/trace.py b/src/sage/misc/trace.py index 2547426bc0a..6807cfb1940 100644 --- a/src/sage/misc/trace.py +++ b/src/sage/misc/trace.py @@ -26,6 +26,7 @@ def trace(code, preparse=True): :: + sage: from sage.misc.trace import trace sage: trace("factor(100)") # not tested then at the (Pdb) prompt type ``s`` (or ``step``), then press :kbd:`Return` @@ -53,9 +54,10 @@ def trace(code, preparse=True): The only real way to test this is via pexpect spawning a sage subprocess that uses IPython:: + sage: # needs pexpect sage.all sage: import pexpect sage: s = pexpect.spawn('sage') - sage: _ = s.sendline("trace('print(factor(10))'); print(3+97)") + sage: _ = s.sendline("from sage.misc.trace import trace; trace('print(factor(10))'); print(3+97)") sage: _ = s.expect('ipdb>', timeout=90) sage: _ = s.sendline("s"); _ = s.sendline("c") sage: _ = s.expect('100', timeout=90) @@ -63,7 +65,7 @@ def trace(code, preparse=True): Seeing the ipdb prompt and the 2 \* 5 in the output below is a strong indication that the trace command worked correctly:: - sage: print(s.before[s.before.find(b'--'):].decode()) + sage: print(s.before[s.before.find(b'--'):].decode()) # needs pexpect sage.all --... ...ipdb> c ...2 * 5... diff --git a/src/sage/misc/verbose.py b/src/sage/misc/verbose.py index b7016d08116..d29d7310758 100644 --- a/src/sage/misc/verbose.py +++ b/src/sage/misc/verbose.py @@ -145,7 +145,7 @@ def verbose(mesg="", t=0, level=1, caller_name=None): VERBOSE1 (william): This is Sage. (time = 0.0) sage: set_verbose(0) """ - from sage.misc.misc import cputime + from sage.misc.timing import cputime if level > LEVEL: return cputime() diff --git a/src/sage/misc/viewer.py b/src/sage/misc/viewer.py index de84f31ddf4..439dedc5e75 100644 --- a/src/sage/misc/viewer.py +++ b/src/sage/misc/viewer.py @@ -30,6 +30,7 @@ VIEWERS = ['browser', 'dvi_viewer', 'pdf_viewer', 'png_viewer'] + def default_viewer(viewer=None): """ Set up default programs for opening web pages, PDFs, PNGs, and DVI files. @@ -138,6 +139,7 @@ def default_viewer(viewer=None): # _viewer_prefs: a dictionary holding global preferences for viewers. _viewer_prefs = {} + class Viewer(SageObject): """ Set defaults for various viewing applications: a web browser, a @@ -301,8 +303,10 @@ def __call__(self, x=None): elif x.startswith('pdf'): return self.pdf_viewer() + viewer = Viewer() + def browser(): """ Return the program used to open a web page. By default, the @@ -319,6 +323,7 @@ def browser(): """ return viewer.browser() + def dvi_viewer(): """ Return the program used to display a dvi file. By default, the @@ -336,6 +341,7 @@ def dvi_viewer(): viewer() return viewer.dvi_viewer() + def pdf_viewer(): """ Return the program used to display a pdf file. By default, the @@ -356,6 +362,7 @@ def pdf_viewer(): viewer() return viewer.pdf_viewer() + def png_viewer(): """ Return the program used to display a png file. By default, the diff --git a/src/sage/misc/weak_dict.pyx b/src/sage/misc/weak_dict.pyx index 9202e96c99e..1d4e9f24093 100644 --- a/src/sage/misc/weak_dict.pyx +++ b/src/sage/misc/weak_dict.pyx @@ -118,15 +118,13 @@ See :trac:`13394` for a discussion of some of the design considerations. # https://www.gnu.org/licenses/ # **************************************************************************** -import weakref from weakref import KeyedRef from copy import deepcopy from cpython.dict cimport PyDict_SetItem, PyDict_Next from cpython.tuple cimport PyTuple_GET_SIZE, PyTuple_New from cpython.weakref cimport PyWeakref_NewRef -from cpython.object cimport PyObject_Hash -from cpython.ref cimport Py_INCREF, Py_XINCREF, Py_XDECREF +from cpython.ref cimport Py_INCREF from sage.cpython.dict_del_by_value cimport * from sage.misc.superseded import deprecation @@ -164,6 +162,7 @@ cdef class WeakValueDictEraser: - Nils Bruin (2013-11) """ cdef D + def __init__(self, D): """ INPUT: @@ -339,7 +338,8 @@ cdef class WeakValueDictionary(dict): EXAMPLES:: - sage: L = [(p,GF(p)) for p in prime_range(10)] + sage: # needs sage.rings.finite_rings + sage: L = [(p, GF(p)) for p in prime_range(10)] sage: import sage.misc.weak_dict sage: D = sage.misc.weak_dict.WeakValueDictionary() sage: len(D) @@ -365,7 +365,7 @@ cdef class WeakValueDictionary(dict): sage: D = sage.misc.weak_dict.WeakValueDictionary() sage: D[1] = QQ sage: D[2] = ZZ - sage: D[None] = CC + sage: D[None] = CC # needs sage.rings.real_mpfr sage: E = copy(D) # indirect doctest sage: set(E.items()) == set(D.items()) True @@ -429,13 +429,16 @@ cdef class WeakValueDictionary(dict): EXAMPLES:: sage: import sage.misc.weak_dict - sage: L = [(p,GF(p)) for p in prime_range(10)] + + sage: # needs sage.libs.pari + sage: L = [(p, GF(p)) for p in prime_range(10)] sage: D = sage.misc.weak_dict.WeakValueDictionary(L) sage: len(D) 4 The value for an existing key is returned and not overridden:: + sage: # needs sage.libs.pari sage: D.setdefault(5, ZZ) Finite Field of size 5 sage: D[5] @@ -443,6 +446,7 @@ cdef class WeakValueDictionary(dict): For a non-existing key, the default value is stored and returned:: + sage: # needs sage.libs.pari sage: 4 in D False sage: D.setdefault(4, ZZ) @@ -460,7 +464,7 @@ cdef class WeakValueDictionary(dict): raised for unhashable objects:: sage: D = sage.misc.weak_dict.WeakValueDictionary() - sage: D.setdefault(matrix([]),ZZ) + sage: D.setdefault(matrix([]), ZZ) # needs sage.modules Traceback (most recent call last): ... TypeError: mutable matrices are unhashable @@ -535,7 +539,7 @@ cdef class WeakValueDictionary(dict): raised for unhashable objects:: sage: D = sage.misc.weak_dict.WeakValueDictionary() - sage: D[matrix([])] = ZZ + sage: D[matrix([])] = ZZ # needs sage.modules Traceback (most recent call last): ... TypeError: mutable matrices are unhashable @@ -560,6 +564,8 @@ cdef class WeakValueDictionary(dict): EXAMPLES:: sage: import sage.misc.weak_dict + + sage: # needs sage.libs.pari sage: L = [GF(p) for p in prime_range(10^3)] sage: D = sage.misc.weak_dict.WeakValueDictionary(enumerate(L)) sage: 20 in D @@ -579,7 +585,7 @@ cdef class WeakValueDictionary(dict): raised for unhashable objects:: sage: D = sage.misc.weak_dict.WeakValueDictionary() - sage: D.pop(matrix([])) + sage: D.pop(matrix([])) # needs sage.modules Traceback (most recent call last): ... TypeError: mutable matrices are unhashable @@ -636,6 +642,8 @@ cdef class WeakValueDictionary(dict): EXAMPLES:: sage: import sage.misc.weak_dict + + sage: # needs sage.libs.pari sage: L = [GF(p) for p in prime_range(10^3)] sage: D = sage.misc.weak_dict.WeakValueDictionary(enumerate(L)) sage: 100 in D @@ -654,8 +662,9 @@ cdef class WeakValueDictionary(dict): Check that :trac:`15956` has been fixed, i.e., a ``TypeError`` is raised for unhashable objects:: + sage: # needs sage.libs.pari sage: D = sage.misc.weak_dict.WeakValueDictionary() - sage: D.get(matrix([])) + sage: D.get(matrix([])) # needs sage.modules Traceback (most recent call last): ... TypeError: mutable matrices are unhashable @@ -695,7 +704,7 @@ cdef class WeakValueDictionary(dict): raised for unhashable objects:: sage: D = sage.misc.weak_dict.WeakValueDictionary() - sage: D[matrix([])] + sage: D[matrix([])] # needs sage.modules Traceback (most recent call last): ... TypeError: mutable matrices are unhashable @@ -739,7 +748,7 @@ cdef class WeakValueDictionary(dict): raised for unhashable objects:: sage: D = sage.misc.weak_dict.WeakValueDictionary() - sage: matrix([]) in D + sage: matrix([]) in D # needs sage.modules Traceback (most recent call last): ... TypeError: mutable matrices are unhashable @@ -1193,13 +1202,13 @@ cdef class CachedWeakValueDictionary(WeakValueDictionary): EXAMPLES:: - sage: L = [(p,GF(p)) for p in prime_range(10)] + sage: L = [(p, GF(p)) for p in prime_range(10)] # needs sage.libs.pari sage: from sage.misc.weak_dict import CachedWeakValueDictionary sage: D = CachedWeakValueDictionary() sage: len(D) 0 - sage: D = CachedWeakValueDictionary(L) - sage: len(D) == len(L) + sage: D = CachedWeakValueDictionary(L) # needs sage.libs.pari + sage: len(D) == len(L) # needs sage.libs.pari True A :class:`CachedWeakValueDictionary` with a cache size of zero diff --git a/src/sage/modular/__init__.py b/src/sage/modular/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/abvar/__init__.py b/src/sage/modular/abvar/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index 05a9c16b9a1..54ef9cc41c5 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -33,6 +33,8 @@ from copy import copy from random import randrange +import sage.rings.abc + from sage.arith.functions import lcm as LCM from sage.arith.misc import divisors, next_prime, is_prime from sage.categories.modular_abelian_varieties import ModularAbelianVarieties @@ -55,7 +57,6 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.qqbar import QQbar from sage.rings.rational_field import QQ from sage.rings.ring import is_Ring from sage.schemes.elliptic_curves.constructor import EllipticCurve @@ -67,6 +68,7 @@ lazy_import('sage.databases.cremona', ['cremona_letter_code', 'CremonaDatabase']) + from . import homspace from . import lseries from .morphism import HeckeOperator, Morphism, DegeneracyMap @@ -609,16 +611,19 @@ def newform_label(self): def elliptic_curve(self): """ - Return an elliptic curve isogenous to self. If self is not dimension 1 - with rational base ring, raise a ValueError. + Return an elliptic curve isogenous to ``self``. + + If ``self`` is not dimension 1 + with rational base ring, this raises a :class:`ValueError`. - The elliptic curve is found by looking it up in the CremonaDatabase. - The CremonaDatabase contains all curves up to some large conductor. If - a curve is not found in the CremonaDatabase, a RuntimeError will be - raised. In practice, only the most committed users will see this - RuntimeError. + The elliptic curve is found by looking it up in the + CremonaDatabase. The CremonaDatabase contains all curves up + to some large conductor. If a curve is not found in the + CremonaDatabase, a :class:`RuntimeError` will be raised. In + practice, only the most committed users will see this + :class:`RuntimeError`. - OUTPUT: an elliptic curve isogenous to self. + OUTPUT: an elliptic curve isogenous to ``self``. EXAMPLES:: @@ -798,8 +803,8 @@ def _Hom_(self, B, cat=None): L = B.base_field() if K == L: F = K - elif K == QQbar or L == QQbar: - F = QQbar + elif isinstance(K, sage.rings.abc.AlgebraicField) or isinstance(L, sage.rings.abc.AlgebraicField): + from sage.rings.qqbar import QQbar as F else: # TODO -- improve this raise ValueError("please specify a category") @@ -997,7 +1002,7 @@ def intersection(self, other): for v in V.coordinate_module(S).basis()] if A.dimension() > 0: - finitegroup_base_field = QQbar + from sage.rings.qqbar import QQbar as finitegroup_base_field else: finitegroup_base_field = self.base_field() G = self.finite_subgroup(gens, field_of_definition=finitegroup_base_field) @@ -3126,7 +3131,7 @@ def finite_subgroup(self, X, field_of_definition=None, check=True): raise ValueError("X must be a subgroup of self.") if field_of_definition is None: - field_of_definition = QQbar + from sage.rings.qqbar import QQbar as field_of_definition return FiniteSubgroup_lattice( self, X, field_of_definition=field_of_definition, check=check) @@ -4181,7 +4186,8 @@ def modular_symbols(self, sign=0): """ Return space of modular symbols (with given sign) associated to this modular abelian variety, if it can be found by cutting down - using Hecke operators. Otherwise raise a RuntimeError exception. + using Hecke operators. Otherwise raise a :class:`RuntimeError` + exception. EXAMPLES:: diff --git a/src/sage/modular/abvar/cuspidal_subgroup.py b/src/sage/modular/abvar/cuspidal_subgroup.py index 136f6cf23e4..fe174e6631a 100644 --- a/src/sage/modular/abvar/cuspidal_subgroup.py +++ b/src/sage/modular/abvar/cuspidal_subgroup.py @@ -158,8 +158,8 @@ def _compute_lattice(self, rational_only=False, rational_subgroup=False): """ A = self.abelian_variety() Cusp = A.modular_symbols() - Amb = Cusp.ambient_module() - Eis = Amb.eisenstein_submodule() + Amb = Cusp.ambient_module() + Eis = Amb.eisenstein_submodule() C = Amb.cusps() N = Amb.level() @@ -211,7 +211,6 @@ def _repr_(self): """ return "Cuspidal subgroup %sover QQ of %s"%(self._invariants_repr(), self.abelian_variety()) - def lattice(self): """ Returned cached tuple of vectors that define elements of the @@ -219,10 +218,8 @@ def lattice(self): OUTPUT: - - ``tuple`` - cached - EXAMPLES:: sage: J = J0(27) @@ -265,8 +262,7 @@ def _repr_(self): sage: G._repr_() 'Finite subgroup with invariants [3] over QQ of Abelian variety J0(27) of dimension 1' """ - return "Subgroup generated by differences of rational cusps %sover QQ of %s"%(self._invariants_repr(), self.abelian_variety()) - + return "Subgroup generated by differences of rational cusps %sover QQ of %s" % (self._invariants_repr(), self.abelian_variety()) def lattice(self): """ diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 3f4f0ffbd8f..ec76a0f5e26 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -97,6 +97,9 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +import sage.rings.abc + +from sage.misc.lazy_import import lazy_import from sage.modular.abvar.torsion_point import TorsionPoint from sage.modules.module import Module from sage.modules.free_module import is_FreeModule @@ -105,7 +108,6 @@ from sage.structure.richcmp import richcmp_method, richcmp from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.qqbar import QQbar from sage.rings.rational_field import QQ from sage.arith.functions import lcm from sage.misc.misc_c import prod @@ -521,7 +523,7 @@ def _repr_(self): 'Finite subgroup with invariants [3, 3, 3, 3, 3, 3, 3, 3, 3, 3] over QQ of Abelian variety J0(42) of dimension 5' """ K = self.__field_of_definition - if K == QQbar: + if isinstance(K, sage.rings.abc.AlgebraicField): field = "QQbar" elif K == QQ: field = "QQ" @@ -750,6 +752,8 @@ def subgroup(self, gens): sage: H == G.subgroup([[1/11,0,0,0]]) True """ + from sage.rings.qqbar import QQbar + if not isinstance(gens, (tuple, list)): raise TypeError("gens must be a list or tuple") A = self.abelian_variety() @@ -815,7 +819,7 @@ def invariants(self): class FiniteSubgroup_lattice(FiniteSubgroup): - def __init__(self, abvar, lattice, field_of_definition=QQbar, check=True): + def __init__(self, abvar, lattice, field_of_definition=None, check=True): """ A finite subgroup of a modular abelian variety that is defined by a given lattice. @@ -841,6 +845,8 @@ def __init__(self, abvar, lattice, field_of_definition=QQbar, check=True): sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G Finite subgroup with invariants [15] over QQbar of Abelian variety J0(11) of dimension 1 """ + if field_of_definition is None: + from sage.rings.qqbar import QQbar as field_of_definition if check: from .abvar import is_ModularAbelianVariety if not is_FreeModule(lattice) or lattice.base_ring() != ZZ: diff --git a/src/sage/modular/abvar/homspace.py b/src/sage/modular/abvar/homspace.py index adf9889bebe..8e89399d611 100644 --- a/src/sage/modular/abvar/homspace.py +++ b/src/sage/modular/abvar/homspace.py @@ -148,14 +148,15 @@ :: - sage: T = E.image_of_hecke_algebra() # long time - sage: T.gens() # long time + sage: # long time + sage: T = E.image_of_hecke_algebra() + sage: T.gens() (Abelian variety endomorphism of Abelian variety J0(33) of dimension 3, Abelian variety endomorphism of Abelian variety J0(33) of dimension 3, Abelian variety endomorphism of Abelian variety J0(33) of dimension 3) - sage: T.index_in(E) # long time + sage: T.index_in(E) +Infinity - sage: T.index_in_saturation() # long time + sage: T.index_in_saturation() 1 AUTHORS: @@ -186,20 +187,22 @@ from . import morphism import sage.rings.integer_ring -import sage.rings.all +from sage.rings.infinity import Infinity from sage.rings.ring import Ring from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import Matrix, identity_matrix from sage.structure.element import is_Matrix -ZZ = sage.rings.integer_ring.ZZ +from sage.rings.integer_ring import ZZ + class Homspace(HomsetWithBase): """ A space of homomorphisms between two modular abelian varieties. """ Element = morphism.Morphism + def __init__(self, domain, codomain, cat): """ Create a homspace. @@ -880,7 +883,7 @@ def index_in(self, other, check=True): M = self.free_module() N = other.free_module() if M.rank() < N.rank(): - return sage.rings.all.Infinity + return Infinity return M.index_in(N) def index_in_saturation(self): diff --git a/src/sage/modular/abvar/morphism.py b/src/sage/modular/abvar/morphism.py index a57f4d0b66c..f0f3c065577 100644 --- a/src/sage/modular/abvar/morphism.py +++ b/src/sage/modular/abvar/morphism.py @@ -48,6 +48,7 @@ from .finite_subgroup import TorsionPoint + class Morphism_abstract(sage.modules.matrix_morphism.MatrixMorphism_abstract): """ A morphism between modular abelian varieties. @@ -184,7 +185,6 @@ def cokernel(self): self.__cokernel = C return C - def kernel(self): """ Return the kernel of this morphism. @@ -246,7 +246,6 @@ def kernel(self): return K, abvar - def factor_out_component_group(self): r""" View self as a morphism `f:A \to B`. Then `\ker(f)` @@ -286,7 +285,7 @@ def factor_out_component_group(self): L = A.image() # Saturate the image of the matrix corresponding to self. Lsat = L.saturation() - if L == Lsat: # easy case + if L == Lsat: # easy case self.__factor_out = self return self # Now find a matrix whose rows map exactly onto the @@ -308,9 +307,9 @@ def factor_out_component_group(self): # R/L' = (M+L')/L' = M/(L'/\M) = M/Lsat # which is torsion free! - Q = self.codomain() - M = Q.lattice() - one_over_n = ZZ(1)/n + Q = self.codomain() + M = Q.lattice() + one_over_n = ZZ.one() / n Lprime = (one_over_n * self.matrix() * M.basis_matrix()).row_module(ZZ) # This R is a lattice in the ambient space for B. @@ -546,7 +545,7 @@ def _image_of_finite_subgroup(self, G): B = G._relative_basis_matrix() * self.restrict_domain(G.abelian_variety()).matrix() * self.codomain().lattice().basis_matrix() lattice = B.row_module(ZZ) return self.codomain().finite_subgroup(lattice, - field_of_definition=G.field_of_definition()) + field_of_definition=G.field_of_definition()) def _image_of_abvar(self, A): """ @@ -654,11 +653,12 @@ def restrict_domain(self, sub): L = self.domain().lattice() B = sub.lattice().basis() - ims = sum([ (L(b)*self.matrix()).list() for b in B], []) + ims = sum(((L(b) * self.matrix()).list() for b in B), []) MS = matrix_space.MatrixSpace(self.base_ring(), len(B), self.codomain().rank()) H = sub.Hom(self.codomain(), self.category_for()) return H(MS(ims)) + class DegeneracyMap(Morphism): def __init__(self, parent, A, t, side="left"): """ @@ -714,7 +714,8 @@ def _repr_(self): sage: J0(22).degeneracy_map(44)._repr_() 'Degeneracy map from Abelian variety J0(22) of dimension 2 to Abelian variety J0(44) of dimension 4 defined by [1]' """ - return "Degeneracy map from %s to %s defined by %s"%(self.domain(), self.codomain(), self._t) + return "Degeneracy map from %s to %s defined by %s" % (self.domain(), self.codomain(), self._t) + class HeckeOperator(Morphism): """ @@ -761,7 +762,7 @@ def _repr_(self): sage: J.hecke_operator(2)._repr_() 'Hecke operator T_2 on Abelian variety J0(37) of dimension 2' """ - return "Hecke operator T_%s on %s"%(self.__n, self.__abvar) + return "Hecke operator T_%s on %s" % (self.__n, self.__abvar) def index(self): """ diff --git a/src/sage/modular/arithgroup/__init__.py b/src/sage/modular/arithgroup/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/arithgroup/all.py b/src/sage/modular/arithgroup/all.py index 9f312be37d0..d4fb241d1f9 100644 --- a/src/sage/modular/arithgroup/all.py +++ b/src/sage/modular/arithgroup/all.py @@ -9,7 +9,8 @@ from .congroup_gamma import Gamma_constructor as Gamma, is_Gamma from .congroup_sl2z import SL2Z, is_SL2Z -from .arithgroup_perm import ArithmeticSubgroup_Permutation +from sage.misc.lazy_import import lazy_import +lazy_import('sage.modular.arithgroup.arithgroup_perm', 'ArithmeticSubgroup_Permutation') from .congroup import (degeneracy_coset_representatives_gamma0, degeneracy_coset_representatives_gamma1) diff --git a/src/sage/modular/arithgroup/arithgroup_element.pyx b/src/sage/modular/arithgroup/arithgroup_element.pyx index 579cbc654cc..dee0b479c74 100644 --- a/src/sage/modular/arithgroup/arithgroup_element.pyx +++ b/src/sage/modular/arithgroup/arithgroup_element.pyx @@ -1,10 +1,9 @@ """ Elements of arithmetic subgroups """ - -################################################################################ +# ############################################################################## # -# Copyright (C) 2009, The Sage Group -- http://www.sagemath.org/ +# Copyright (C) 2009, The Sage Group -- https://www.sagemath.org/ # # Distributed under the terms of the GNU General Public License (GPL) # @@ -12,12 +11,11 @@ Elements of arithmetic subgroups # # https://www.gnu.org/licenses/ # -################################################################################ +# ############################################################################## -from sage.structure.element cimport MultiplicativeGroupElement, MonoidElement, Element +from sage.structure.element cimport MultiplicativeGroupElement from sage.structure.richcmp cimport richcmp from sage.rings.integer_ring import ZZ -from sage.modular.cusps import Cusp from sage.matrix.matrix_space import MatrixSpace from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense @@ -109,7 +107,7 @@ cdef class ArithmeticSubgroupElement(MultiplicativeGroupElement): sage: unpickle_build(si, (Gamma0(13), {'_ArithmeticSubgroupElement__x': x})) """ from .congroup_sl2z import SL2Z - oldparent, kwdict = state + _, kwdict = state self._parent = SL2Z if '_ArithmeticSubgroupElement__x' in kwdict: self.__x = M2Z(kwdict['_ArithmeticSubgroupElement__x']) @@ -342,6 +340,7 @@ cdef class ArithmeticSubgroupElement(MultiplicativeGroupElement): An example involving the Gaussian numbers:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: g.acton(i) 1/1186*i + 77/1186 diff --git a/src/sage/modular/arithgroup/arithgroup_generic.py b/src/sage/modular/arithgroup/arithgroup_generic.py index cbad28e64c6..844d8db7165 100644 --- a/src/sage/modular/arithgroup/arithgroup_generic.py +++ b/src/sage/modular/arithgroup/arithgroup_generic.py @@ -885,12 +885,12 @@ def index(self): def generalised_level(self): r""" - Return the generalised level of self, i.e. the least common multiple of + Return the generalised level of ``self``, i.e., the least common multiple of the widths of all cusps. - If self is *even*, Wohlfart's theorem tells us that this is equal to - the (conventional) level of self when self is a congruence subgroup. - This can fail if self is odd, but the actual level is at most twice the + If ``self`` is *even*, Wohlfart's theorem tells us that this is equal to + the (conventional) level of ``self`` when ``self`` is a congruence subgroup. + This can fail if ``self`` is odd, but the actual level is at most twice the generalised level. See the paper by Kiming, Schuett and Verrill for more examples. @@ -898,7 +898,8 @@ def generalised_level(self): sage: Gamma0(18).generalised_level() 18 - sage: sage.modular.arithgroup.arithgroup_perm.HsuExample18().generalised_level() + sage: from sage.modular.arithgroup.arithgroup_perm import HsuExample18 + sage: HsuExample18().generalised_level() 24 In the following example, the actual level is twice the generalised @@ -971,7 +972,7 @@ def genus(self): sage: [n for n in [1..200] if Gamma0(n).genus() == 1] [11, 14, 15, 17, 19, 20, 21, 24, 27, 32, 36, 49] """ - return ZZ(1 + (self.projective_index()) / ZZ(12) - (self.nu2())/ZZ(4) - (self.nu3())/ZZ(3) - self.ncusps()/ZZ(2)) + return ZZ(1 + (self.projective_index()) / ZZ(12) - (self.nu2())/ZZ(4) - (self.nu3())/ZZ(3) - self.ncusps()/ZZ(2)) def farey_symbol(self): r""" diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index 34a87cca043..c8536611724 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -395,7 +395,7 @@ def ArithmeticSubgroup_Permutation( S3 = L * ~R elif S2 is not None: # initialize from L,S2 if S3 is None: - S3 = ~S2 * ~L + S3 = ~S2 * ~L if R is None: R = ~S2 * ~L * S2 elif S3 is not None: # initialize from L,S3 @@ -1216,11 +1216,10 @@ def coset_graph(self, Looped multi-digraph on 2 vertices """ from sage.graphs.digraph import DiGraph - res = DiGraph(multiedges=True,loops=True) + res = DiGraph(multiedges=True, loops=True) res.add_vertices(list(range(self.index()))) - - if right_cosets: # invert the permutations + if right_cosets: # invert the permutations S2 = [None]*self.index() S3 = [None]*self.index() L = [None]*self.index() @@ -1552,14 +1551,15 @@ def surgroups(self): sage: l [6, 3, 4, 8, 4, 8, 4, 12, 4, 6, 6, 8, 8] """ - from sage.interfaces.gap import gap - P = self.perm_group()._gap_() + from sage.libs.gap.libgap import libgap + P = libgap(self.perm_group()) for b in P.AllBlocks(): - orbit = P.Orbit(b, gap.OnSets) - action = P.Action(orbit, gap.OnSets) - S2,S3,L,R = action.GeneratorsOfGroup() + orbit = P.Orbit(b, libgap.OnSets) + action = P.Action(orbit, libgap.OnSets) + S2, S3, L, R = action.GeneratorsOfGroup() yield ArithmeticSubgroup_Permutation(S2=S2, S3=S3, L=L, R=R, check=False) + class OddArithmeticSubgroup_Permutation(ArithmeticSubgroup_Permutation_class): r""" An arithmetic subgroup of `\SL(2, \ZZ)` not containing `-1`, @@ -2636,6 +2636,7 @@ def odd_subgroups(self): return res + def HsuExample10(): r""" An example of an index 10 arithmetic subgroup studied by Tim Hsu. @@ -2655,6 +2656,7 @@ def HsuExample10(): R="(1,7,9,10,6)(2,3)(4,5,8)", relabel=False) + def HsuExample18(): r""" An example of an index 18 arithmetic subgroup studied by Tim Hsu. diff --git a/src/sage/modular/arithgroup/congroup.pyx b/src/sage/modular/arithgroup/congroup.pyx index 86109c9b1eb..002e3bb02da 100644 --- a/src/sage/modular/arithgroup/congroup.pyx +++ b/src/sage/modular/arithgroup/congroup.pyx @@ -105,10 +105,10 @@ def degeneracy_coset_representatives_gamma0(int N, int M, int t): 14 """ if N % M != 0: - raise ArithmeticError("M (=%s) must be a divisor of N (=%s)" % (M,N)) + raise ArithmeticError(f"M (={M}) must be a divisor of N (={N})") - if (N/M) % t != 0: - raise ArithmeticError("t (=%s) must be a divisor of N/M (=%s)"%(t,N/M)) + if (N // M) % t != 0: + raise ArithmeticError(f"t (={t}) must be a divisor of N/M (={N//M})") cdef int n, i, j, k, aa, bb, cc, dd, g, Ndivt, halfmax, is_new cdef int* R @@ -122,7 +122,7 @@ def degeneracy_coset_representatives_gamma0(int N, int M, int t): while k < n: # try to find another coset representative. cc = M*random.randrange(-halfmax, halfmax+1) - dd = random.randrange(-halfmax, halfmax+1) + dd = random.randrange(-halfmax, halfmax+1) g = arith_int.c_xgcd_int(-cc,dd,&bb,&aa) if g == 0: continue @@ -132,10 +132,10 @@ def degeneracy_coset_representatives_gamma0(int N, int M, int t): dd = dd / g # Test if we've found a new coset representative. is_new = 1 - for i from 0 <= i < k: + for i in range(k): j = 4*i - if (R[j+1]*aa - R[j]*bb)%t == 0 and \ - (R[j+3]*cc - R[j+2]*dd)%Ndivt == 0: + if (R[j+1]*aa - R[j]*bb) % t == 0 and \ + (R[j+3]*cc - R[j+2]*dd) % Ndivt == 0: is_new = 0 break # If our matrix is new add it to the list. @@ -148,12 +148,13 @@ def degeneracy_coset_representatives_gamma0(int N, int M, int t): # Return the list left multiplied by T. S = [] - for i from 0 <= i < k: + for i in range(k): j = 4*i S.append([R[j], R[j+1], R[j+2]*t, R[j+3]*t]) sig_free(R) return S + def degeneracy_coset_representatives_gamma1(int N, int M, int t): r""" Let `N` be a positive integer and `M` a divisor of `N`. Let `t` be a @@ -204,29 +205,28 @@ def degeneracy_coset_representatives_gamma1(int N, int M, int t): sage: len(degeneracy_coset_representatives_gamma1(13, 1, 13)) 168 """ - if N % M != 0: - raise ArithmeticError("M (=%s) must be a divisor of N (=%s)" % (M,N)) + raise ArithmeticError(f"M (={M}) must be a divisor of N (={N})") - if (N/M) % t != 0: - raise ArithmeticError("t (=%s) must be a divisor of N/M (=%s)"%(t,N/M)) + if (N // M) % t != 0: + raise ArithmeticError(f"t (={t}) must be a divisor of N/M (={N//M})") cdef int d, g, i, j, k, n, aa, bb, cc, dd, Ndivt, halfmax, is_new cdef int* R # total number of coset representatives that we'll find n = Gamma1(N).index() / Gamma1(M).index() - d = arith_int.c_gcd_int(t, N/t) + d = arith_int.c_gcd_int(t, N // t) n = n / d k = 0 # number found so far - Ndivt = N / t + Ndivt = N // t R = <int*>check_allocarray(4 * n, sizeof(int)) halfmax = 2*(n+10) while k < n: # try to find another coset representative. - cc = M*random.randrange(-halfmax, halfmax+1) - dd = 1 + M*random.randrange(-halfmax, halfmax+1) - g = arith_int.c_xgcd_int(-cc,dd,&bb,&aa) + cc = M * random.randrange(-halfmax, halfmax + 1) + dd = 1 + M * random.randrange(-halfmax, halfmax + 1) + g = arith_int.c_xgcd_int(-cc, dd, &bb, &aa) if g == 0: continue cc = cc / g @@ -237,12 +237,12 @@ def degeneracy_coset_representatives_gamma1(int N, int M, int t): continue # Test if we've found a new coset representative. is_new = 1 - for i from 0 <= i < k: + for i in range(k): j = 4*i - if (R[j] - aa)%t == 0 and \ - (R[j+1] - bb)%t == 0 and \ - (R[j+2] - cc)%(Ndivt) == 0 and \ - (R[j+3] - dd)%(Ndivt) == 0: + if (R[j] - aa) % t == 0 and \ + (R[j+1] - bb) % t == 0 and \ + (R[j+2] - cc) % Ndivt == 0 and \ + (R[j+3] - dd) % Ndivt == 0: is_new = 0 break # If our matrix is new add it to the list. @@ -258,12 +258,13 @@ def degeneracy_coset_representatives_gamma1(int N, int M, int t): # Return the list left multiplied by T. S = [] - for i from 0 <= i < k: + for i in range(k): j = 4*i S.append([R[j], R[j+1], R[j+2]*t, R[j+3]*t]) sig_free(R) return S + def generators_helper(coset_reps, level): r""" Helper function for generators of Gamma0, Gamma1 and GammaH. diff --git a/src/sage/modular/arithgroup/congroup_gamma.py b/src/sage/modular/arithgroup/congroup_gamma.py index bc1cbb6afd6..bba5868dab6 100644 --- a/src/sage/modular/arithgroup/congroup_gamma.py +++ b/src/sage/modular/arithgroup/congroup_gamma.py @@ -240,6 +240,12 @@ def reduce_cusp(self, c): sage: G = Gamma(50) sage: all(c == G.reduce_cusp(c) for c in G.cusps()) True + + We test that :trac:`36163` is fixed:: + + sage: Gamma(7).reduce_cusp(Cusp(6,7)) + Infinity + """ N = self.level() c = Cusp(c) @@ -341,7 +347,7 @@ def _lift_pair(U,V,N): u = U % N v = V % N if v == 0: - if u == 1: + if u == 1 or u == N-1: return (1,0) else: v = N diff --git a/src/sage/modular/arithgroup/congroup_gamma0.py b/src/sage/modular/arithgroup/congroup_gamma0.py index 5a4b31bce86..e960ce477d3 100644 --- a/src/sage/modular/arithgroup/congroup_gamma0.py +++ b/src/sage/modular/arithgroup/congroup_gamma0.py @@ -39,6 +39,7 @@ def is_Gamma0(x): """ return isinstance(x, Gamma0_class) + _gamma0_cache = {} def Gamma0_constructor(N): """ @@ -104,7 +105,6 @@ class Gamma0_class(GammaH_class): """ - def __init__(self, level): r""" The congruence subgroup `\Gamma_0(N)`. @@ -482,13 +482,14 @@ def ncusps(self): [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] """ n = self.level() - return sum([euler_phi(gcd(d,n//d)) for d in n.divisors()]) - + return sum(euler_phi(gcd(d, n // d)) for d in n.divisors()) def nu2(self): r""" Return the number of elliptic points of order 2 for this congruence - subgroup `\Gamma_0(N)`. The number of these is given by a standard formula: + subgroup `\Gamma_0(N)`. + + The number of these is given by a standard formula: 0 if `N` is divisible by 4 or any prime congruent to -1 mod 4, and otherwise `2^d` where d is the number of odd primes dividing `N`. @@ -593,12 +594,10 @@ def dimension_new_cusp_forms(self, k=2, p=0): sage: all(Gamma0(N).dimension_new_cusp_forms(2)==100 for N in L) True """ - from sage.functions.other import floor - N = self.level() k = ZZ(k) - if not(p == 0 or N % p): + if not (p == 0 or N % p): return (self.dimension_cusp_forms(k) - 2 * self.restrict(N // p).dimension_new_cusp_forms(k)) @@ -669,8 +668,8 @@ def v3(q, a): res = (k - 1) / 12 * N * prod(s0(q, a) for q, a in factors) res -= prod(vinf(q, a) for q, a in factors) / ZZ(2) - res += ((1 - k)/4 + floor(k/4)) * prod(v2(q, a) for q, a in factors) - res += ((1 - k)/3 + floor(k/3)) * prod(v3(q, a) for q, a in factors) + res += ((1 - k)/4 + k//4) * prod(v2(q, a) for q, a in factors) + res += ((1 - k)/3 + k//3) * prod(v3(q, a) for q, a in factors) if k == 2: res += moebius(N) return res diff --git a/src/sage/modular/arithgroup/congroup_gamma1.py b/src/sage/modular/arithgroup/congroup_gamma1.py index ed84fd670b1..d32d3646256 100644 --- a/src/sage/modular/arithgroup/congroup_gamma1.py +++ b/src/sage/modular/arithgroup/congroup_gamma1.py @@ -370,6 +370,7 @@ def dimension_modular_forms(self, k=2, eps=None, algorithm="CohenOesterle"): Check that :trac:`18436` is fixed:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + x + 1) sage: G = DirichletGroup(13, base_ring=K) sage: Gamma1(13).dimension_modular_forms(2, G[1]) diff --git a/src/sage/modular/arithgroup/congroup_gammaH.py b/src/sage/modular/arithgroup/congroup_gammaH.py index cfe2da14117..20da4f05b3e 100644 --- a/src/sage/modular/arithgroup/congroup_gammaH.py +++ b/src/sage/modular/arithgroup/congroup_gammaH.py @@ -40,7 +40,7 @@ def GammaH_constructor(level, H): r""" Return the congruence subgroup `\Gamma_H(N)`, which is the subgroup of `SL_2(\ZZ)` consisting of matrices of the form `\begin{pmatrix} a & b \\ - c & d \end{pmatrix}` with `N | c` and `a, b \in H`, for `H` a specified + c & d \end{pmatrix}` with `N | c` and `a, d \in H`, for `H` a specified subgroup of `(\ZZ/N\ZZ)^\times`. INPUT: @@ -163,7 +163,7 @@ class GammaH_class(CongruenceSubgroup): The congruence subgroup `\Gamma_H(N)` for some subgroup `H \trianglelefteq (\ZZ / N\ZZ)^\times`, which is the subgroup of `\SL_2(\ZZ)` consisting of matrices of the form `\begin{pmatrix} a & - b \\ c & d \end{pmatrix}` with `N \mid c` and `a, b \in H`. + b \\ c & d \end{pmatrix}` with `N \mid c` and `a, d \in H`. TESTS: diff --git a/src/sage/modular/arithgroup/congroup_generic.py b/src/sage/modular/arithgroup/congroup_generic.py index 99dbc5036fb..e71426f9922 100644 --- a/src/sage/modular/arithgroup/congroup_generic.py +++ b/src/sage/modular/arithgroup/congroup_generic.py @@ -22,7 +22,6 @@ ################################################################################ from sage.arith.misc import gcd -from sage.groups.matrix_gps.all import MatrixGroup from sage.matrix.matrix_space import MatrixSpace from sage.misc.misc_c import prod from sage.rings.finite_rings.integer_mod_ring import Zmod @@ -88,7 +87,9 @@ def CongruenceSubgroup_constructor(*args): ... TypeError: Ring of definition must be Z / NZ for some N """ + from sage.groups.matrix_gps.finitely_generated import MatrixGroup from sage.groups.matrix_gps.matrix_group import is_MatrixGroup + if is_MatrixGroup(args[0]): G = args[0] @@ -377,6 +378,8 @@ def to_even_subgroup(self): if self.is_even(): return self else: + from sage.groups.matrix_gps.finitely_generated import MatrixGroup + G = self.image_mod_n() H = MatrixGroup([ g.matrix() for g in G.gens()] + [G.matrix_space()(-1)]) return CongruenceSubgroup_constructor(H) @@ -590,7 +593,9 @@ def _minimize_level(G): sage: sage.modular.arithgroup.congroup_generic._minimize_level(G) 3 """ + from sage.groups.matrix_gps.finitely_generated import MatrixGroup from .congroup_gamma import Gamma_constructor as Gamma + Glist = list(G) N = G.base_ring().characteristic() i = Gamma(N).index() diff --git a/src/sage/modular/arithgroup/farey.cpp b/src/sage/modular/arithgroup/farey.cpp index 34f5e5727db..209391676de 100644 --- a/src/sage/modular/arithgroup/farey.cpp +++ b/src/sage/modular/arithgroup/farey.cpp @@ -1010,7 +1010,7 @@ PyObject* FareySymbol::word_problem(const mpz_t a, const mpz_t b, LLT_algorithm(M, p, beta1); wd = PyList_New(p.size()); for(i=0; i<p.size(); i++) { - PyList_SetItem(wd, i, PyInt_FromLong(p[i])); + PyList_SetItem(wd, i, PyLong_FromLong(p[i])); } *beta = beta1; return wd; @@ -1085,7 +1085,7 @@ PyObject* FareySymbol::get_fractions() const { PyObject* FareySymbol::get_pairings() const { PyObject* pairing_list = PyList_New(pairing.size()); for(size_t i=0; i<pairing.size(); i++) { - PyObject* m = PyInt_FromLong(long(pairing[i])); + PyObject* m = PyLong_FromLong(long(pairing[i])); PyList_SetItem(pairing_list, i, m); } return pairing_list; @@ -1104,8 +1104,8 @@ PyObject* FareySymbol::get_paired_sides() const { for(vector<int>::const_iterator i=p.begin(); i!=p.end(); i++) { vector<int>::const_iterator j = find(pairing.begin(), pairing.end(), *i); vector<int>::const_iterator k = find(j+1, pairing.end(), *i); - PyObject* J = PyInt_FromLong(long(j-pairing.begin())); - PyObject* K = PyInt_FromLong(long(k-pairing.begin())); + PyObject* J = PyLong_FromLong(long(j-pairing.begin())); + PyObject* K = PyLong_FromLong(long(k-pairing.begin())); PyObject* tuple = PyTuple_New(2); PyTuple_SetItem(tuple, 0, J); PyTuple_SetItem(tuple, 1, K); diff --git a/src/sage/modular/arithgroup/farey.hpp b/src/sage/modular/arithgroup/farey.hpp index 076d5cd0504..03c03cf1434 100644 --- a/src/sage/modular/arithgroup/farey.hpp +++ b/src/sage/modular/arithgroup/farey.hpp @@ -29,9 +29,6 @@ #include <gmpxx.h> #include "sl2z.hpp" -#define PyInt_FromLong PyLong_FromLong -#define PyInt_AsLong PyLong_AsLong -#define PyInt_AS_LONG PyLong_AS_LONG //--- pure virtual base class for helper class for membership test -------- diff --git a/src/sage/modular/arithgroup/farey_symbol.pyx b/src/sage/modular/arithgroup/farey_symbol.pyx index 07d5c839dad..863c1d6b654 100644 --- a/src/sage/modular/arithgroup/farey_symbol.pyx +++ b/src/sage/modular/arithgroup/farey_symbol.pyx @@ -39,8 +39,6 @@ from .congroup_sl2z import SL2Z from sage.modular.cusps import Cusp from sage.misc.decorators import options, rename_keyword -from sage.misc.latex import latex -from sage.misc.lazy_attribute import lazy_attribute from sage.misc.cachefunc import cached_method from sage.structure.richcmp cimport richcmp_not_equal @@ -338,12 +336,12 @@ cdef class Farey: for i,g in enumerate(self.generators()): m = g.matrix() if (-m).is_one(): - return [i+1] + return [i + 1] t = m.trace() - if t == 0: # order = 4 - return 2 * [i+1] - elif t == 1: # order = 6 - return 3 * [i+1] + if t == 0: # order = 4 + return 2 * [i + 1] + elif t == 1: # order = 6 + return 3 * [i + 1] return [] def word_problem(self, M, output = 'standard', check = True): @@ -443,13 +441,12 @@ cdef class Farey: raise ValueError('Unrecognized output format') if check: if M not in self.group: - raise ValueError("Matrix ( %s ) is not in group ( %s )"%(M,self.group)) + raise ValueError("Matrix ( %s ) is not in group ( %s )" % (M, self.group)) cdef Integer a = M.d() cdef Integer b = -M.b() cdef Integer c = -M.c() cdef Integer d = M.a() - cdef cpp_SL2Z *cpp_beta = new cpp_SL2Z(1,0,0,1) - E = SL2Z([-1,0,0,-1]) + cdef cpp_SL2Z *cpp_beta = new cpp_SL2Z(1, 0, 0, 1) sig_on() result = self.this_ptr.word_problem(a.value, b.value, c.value, d.value, cpp_beta) sig_off() @@ -505,13 +502,13 @@ cdef class Farey: for i in range(len(tietze)): t = tietze[i] tmp = tmp * gens[t-1] if t > 0 else tmp * gens[-t-1]**-1 - assert tmp.matrix() == M.matrix(),'%s %s %s'%(tietze, tmp.matrix(),M.matrix()) + assert tmp.matrix() == M.matrix(),'%s %s %s' % (tietze, tmp.matrix(),M.matrix()) if output == 'standard': return tuple(tietze) if output == 'syllables': return tuple((a-1,len(list(g))) if a > 0 else (-a-1,-len(list(g))) for a,g in groupby(tietze)) - else: # output == 'gens' - return tuple((gens[a-1],len(list(g))) if a > 0 else (gens[-a-1],-len(list(g))) for a,g in groupby(tietze)) + else: # output == 'gens' + return tuple((gens[a-1],len(list(g))) if a > 0 else (gens[-a-1],-len(list(g))) for a, g in groupby(tietze)) def __contains__(self, M): r""" @@ -612,7 +609,7 @@ cdef class Farey: s = r'\left( -\infty' a = [x._latex_() for x in self.fractions()] + [r'\infty'] b = self.pairings() - for i in xrange(len(a)): + for i in range(len(a)): u = b[i] if u == -3: u = r'\bullet' @@ -957,17 +954,16 @@ cdef class Farey: sage: FareySymbol(Gamma0(23)).fundamental_domain(tesselation='coset', linestyle=':', thickness='2') Graphics object consisting of 58 graphics primitives - """ from sage.plot.all import Graphics - from sage.plot.colors import rainbow, to_mpl_color - from sage.plot.all import hyperbolic_arc, hyperbolic_triangle, text + from sage.plot.colors import rainbow + from sage.plot.all import hyperbolic_arc, hyperbolic_triangle I = CC(0, 1) w = RR(3).sqrt() L = 1000 g = Graphics() - ## show coset + # show coset for x in self.coset_reps(): a, b, c, d = x[1, 1], -x[0, 1], -x[1, 0], x[0, 0] A, B = CC(0, L), CC(0, L) diff --git a/src/sage/modular/arithgroup/tests.py b/src/sage/modular/arithgroup/tests.py index ef9818b39aa..be49c7d41d2 100644 --- a/src/sage/modular/arithgroup/tests.py +++ b/src/sage/modular/arithgroup/tests.py @@ -19,7 +19,7 @@ from sage.rings.finite_rings.integer_mod_ring import Zmod import sage.misc.prandom as prandom -from sage.misc.misc import cputime +from sage.misc.timing import cputime def random_even_arithgroup(index, nu2_max=None, nu3_max=None): diff --git a/src/sage/modular/btquotients/__init__.py b/src/sage/modular/btquotients/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index c7564695c8a..1bf60ecbefb 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -41,11 +41,7 @@ from copy import copy from collections import deque -from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra from sage.arith.misc import gcd, xgcd, kronecker_symbol, fundamental_discriminant -from sage.graphs.graph import Graph -from sage.interfaces.magma import magma -from sage.libs.pari.all import pari from sage.matrix.constructor import Matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method @@ -57,18 +53,23 @@ from sage.modular.arithgroup.all import Gamma0 from sage.modular.arithgroup.congroup_gammaH import GammaH_constructor from sage.modular.dirichlet import DirichletGroup -lazy_import("sage.plot.colors", "rainbow") from sage.quadratic_forms.quadratic_form import QuadraticForm from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import NumberField -from sage.rings.padics.factory import Qp, Zp from sage.rings.padics.precision_error import PrecisionError from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation +lazy_import("sage.plot.colors", "rainbow") + +lazy_import('sage.algebras.quatalg.quaternion_algebra', 'QuaternionAlgebra') +lazy_import('sage.graphs.graph', 'Graph') +lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.plot.colors', 'rainbow') +lazy_import('sage.rings.number_field.number_field', 'NumberField') +lazy_import('sage.rings.padics.factory', ['Qp', 'Zp']) class DoubleCosetReduction(SageObject): @@ -412,7 +413,7 @@ class BruhatTitsTree(SageObject, UniqueRepresentation): sage: T = BruhatTitsTree(4) Traceback (most recent call last): ... - ValueError: Input (4) must be prime + ValueError: input (4) must be prime AUTHORS: @@ -428,8 +429,8 @@ def __init__(self, p): sage: T = BruhatTitsTree(17) sage: TestSuite(T).run() """ - if not(ZZ(p).is_prime()): - raise ValueError('Input (%s) must be prime' % p) + if not ZZ(p).is_prime(): + raise ValueError(f'input ({p}) must be prime') self._p = ZZ(p) self._Mat_22 = MatrixSpace(ZZ, 2, 2) self._mat_p001 = self._Mat_22([self._p, 0, 0, 1]) @@ -1435,7 +1436,8 @@ def __classcall__(cls, p, Nminus, Nplus=1, character=None, True """ return super().__classcall__(cls, p, Nminus, Nplus, - character, use_magma, seed, magma_session) + character, use_magma, + seed, magma_session) def __init__(self, p, Nminus, Nplus=1, character=None, use_magma=False, seed=None, magma_session=None): @@ -2283,7 +2285,7 @@ def _local_splitting(self, prec): self._II = M([0, a, 1, 0]) z = 0 self._JJ = 0 - while(self._JJ == 0): + while self._JJ == 0: c = a * z * z + b if c.is_square(): x = c.sqrt() diff --git a/src/sage/modular/btquotients/pautomorphicform.py b/src/sage/modular/btquotients/pautomorphicform.py index 6ba6bb78bbe..6428c7357da 100644 --- a/src/sage/modular/btquotients/pautomorphicform.py +++ b/src/sage/modular/btquotients/pautomorphicform.py @@ -46,6 +46,7 @@ from sage.matrix.constructor import Matrix, zero_matrix from sage.matrix.matrix_space import MatrixSpace +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose from sage.modular.btquotients.btquotient import DoubleCosetReduction from sage.modular.hecke.all import AmbientHeckeModule, HeckeModuleElement @@ -56,7 +57,6 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.laurent_series_ring import LaurentSeriesRing -from sage.rings.padics.factory import Qp from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RR @@ -64,6 +64,9 @@ from sage.structure.richcmp import op_EQ, op_NE from sage.structure.unique_representation import UniqueRepresentation +lazy_import('sage.rings.padics.factory', 'Qp') + + # Need this to be pickleable @@ -1905,7 +1908,7 @@ def integrate(self, f, center=1, level=0, method='moments'): - Marc Masdeu (2012-02-20) """ E = self.parent()._source._BT.get_balls(center, level) - R1 = LaurentSeriesRing(f.base_ring(), 'r1', default_prec = self.parent()._U.base_ring().precision_cap() + 1) + R1 = LaurentSeriesRing(f.base_ring(), 'r1', default_prec=self.parent()._U.base_ring().precision_cap() + 1) R2 = PolynomialRing(f.base_ring(), 'x') x = R2.gen() value = 0 @@ -1913,16 +1916,14 @@ def integrate(self, f, center=1, level=0, method='moments'): if method == 'riemann_sum': for e in E: ii += 1 - #print(ii,"/",len(E)) exp = ((R1([e[1, 1], e[1, 0]])) ** (self.parent()._U.weight()) * e.determinant() ** (-(self.parent()._U.weight()) / 2)) * f(R1([e[0, 1], e[0, 0]]) / R1([e[1, 1], e[1, 0]])) - #exp = R2([tmp[jj] for jj in range(self.parent()._k-1)]) + # exp = R2([tmp[jj] for jj in range(self.parent()._k-1)]) new = eval_dist_at_powseries(self.evaluate(e), exp.truncate(self.parent()._U.weight() + 1)) value += new elif method == 'moments': n = self.parent()._U.weight() for e in E: ii += 1 - #print(ii,"/",len(E)) a, b, c, d = e.list() delta = e.determinant() verbose('%s' % (R2([e[0, 1], e[0, 0]]) @@ -2272,7 +2273,7 @@ def __init__(self, domain, U, prec=None, t=None, R=None, self._R = Qp(domain._p, prec) else: self._R = R - #U is a CoefficientModuleSpace + # U is a CoefficientModuleSpace if isinstance(U, Integer): if t is None: if overconvergent: @@ -2281,11 +2282,11 @@ def __init__(self, domain, U, prec=None, t=None, R=None, t = 0 if overconvergent: self._U = OverconvergentDistributions(U - 2, base=self._R, - prec_cap=U - 1 + t, - act_on_left=True, - adjuster=_btquot_adjuster(), - dettwist=-ZZ((U - 2) // 2), - act_padic=True) + prec_cap=U - 1 + t, + act_on_left=True, + adjuster=_btquot_adjuster(), + dettwist=-ZZ((U - 2) // 2), + act_padic=True) else: self._U = Symk(U - 2, base=self._R, act_on_left=True, adjuster=_btquot_adjuster(), @@ -2485,13 +2486,14 @@ def _element_constructor_(self, data): F = [] Uold = data.parent()._U for ii in range(len(data._F)): - newtmp = data.parent()._Sigma0(E[ii].rep.inverse(), check=False) * Uold(data._F[ii],normalize=False) + newtmp = data.parent()._Sigma0(E[ii].rep.inverse(), check=False) * Uold(data._F[ii], + normalize=False) tmp.append(newtmp) F.append(newtmp) - A = data.parent()._Sigma0(Matrix(QQ,2,2,[0,1/self.prime(),1,0]),check=False) + A = data.parent()._Sigma0(Matrix(QQ, 2, 2, [0, ~self.prime(), 1, 0]), check=False) for ii in range(len(data._F)): F.append(-(A * tmp[ii])) - vals = self._make_invariant([self._U(o,normalize=False) for o in F]) + vals = self._make_invariant([self._U(o, normalize=False) for o in F]) return self.element_class(self, vals) if data == 0: return self.zero() @@ -2605,11 +2607,12 @@ def _make_invariant(self, F): m = M[ii] for v in Si: s += 1 - g = self._Sigma0(m.adjugate() * self._source.embed_quaternion(v[0], prec=self._prec).adjugate() * m,check = False) + g = self._Sigma0(m.adjugate() * self._source.embed_quaternion(v[0], prec=self._prec).adjugate() * m, + check=False) newFi += g * x newF.append((QQ(1) / s) * newFi) else: - newF.append(self._U(x,normalize=False)) + newF.append(self._U(x, normalize=False)) return newF def _apply_Up_operator(self, f, scale=False, original_moments=None): @@ -2650,7 +2653,8 @@ def _apply_Up_operator(self, f, scale=False, original_moments=None): for gg, edge_list in HeckeData: u = edge_list[jj] tprec = 2 * (prec_cap + u.power) + 1 - r = S0(self._p ** -u.power * (u.t(tprec) * gg).adjugate(),check=False) + r = S0(self._p ** -u.power * (u.t(tprec) * gg).adjugate(), + check=False) tmp += r * f._value[u.label] tmp *= factor for ii in range(self._n + 1): diff --git a/src/sage/modular/cusps.py b/src/sage/modular/cusps.py index 27147942a6a..098c7e52a24 100644 --- a/src/sage/modular/cusps.py +++ b/src/sage/modular/cusps.py @@ -28,7 +28,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.libs.pari.all import pari, pari_gen from sage.misc.fast_methods import Singleton from sage.modular.modsym.p1list import lift_to_sl2z_llong from sage.rings.infinity import Infinity, InfinityRing @@ -41,6 +40,11 @@ from sage.structure.parent import Parent from sage.structure.richcmp import richcmp +try: + from sage.libs.pari.all import pari, pari_gen +except ImportError: + pari_gen = () + class Cusp(Element): """ @@ -621,7 +625,7 @@ def is_gamma0_equiv(self, other, N, transformation=None): if C % (M * v1 * v2) == 0: k = - C // (M * v1 * v2) else: - k = - (C / (M * v1 * v2)).round() + k = - (C / (M * v1 * v2)).round("away") s1pp = s1p + k * M * v1 # C += k*M*v1*v2 # is now the smallest in absolute value diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index 157ebabe291..8d8b580a74e 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.number_field r""" The set `\mathbb{P}^1(K)` of cusps of a number field `K` @@ -9,6 +10,7 @@ The space of cusps over a number field k:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5) sage: kCusps = NFCusps(k); kCusps Set of all cusps of Number Field in a with defining polynomial x^2 + 5 @@ -61,7 +63,7 @@ sage: Gamma0_NFCusps(N) [Cusp [0: 1] of Number Field in a with defining polynomial x^2 + 5, - Cusp [1: 3] of Number Field in a with defining polynomial x^2 + 5, + Cusp [1: 3] of Number Field in a with defining polynomial x^2 + 5, ...] """ # **************************************************************************** @@ -102,6 +104,7 @@ def list_of_representatives(N): EXAMPLES:: sage: from sage.modular.cusps_nf import list_of_representatives + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^4 + 13*x^3 - 11) sage: N = k.ideal(713, a + 208) sage: L = list_of_representatives(N); L @@ -127,6 +130,7 @@ def NFCusps(number_field): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5) sage: kCusps = NFCusps(k); kCusps Set of all cusps of Number Field in a with defining polynomial x^2 + 5 @@ -152,6 +156,7 @@ class NFCuspsSpace(UniqueRepresentation, Parent): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5) sage: kCusps = NFCusps(k); kCusps Set of all cusps of Number Field in a with defining polynomial x^2 + 5 @@ -162,6 +167,7 @@ def __init__(self, number_field): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^3 + x^2 + 13) sage: kCusps = NFCusps(k); kCusps Set of all cusps of Number Field in a with defining polynomial x^3 + x^2 + 13 @@ -175,6 +181,7 @@ def __eq__(self, right): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5) sage: L.<a> = NumberField(x^2 + 23) sage: kCusps = NFCusps(k); kCusps @@ -198,6 +205,7 @@ def __ne__(self, right): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5) sage: L.<a> = NumberField(x^2 + 23) sage: kCusps = NFCusps(k); kCusps @@ -219,6 +227,7 @@ def _repr_(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 2) sage: kCusps = NFCusps(k) sage: kCusps @@ -239,6 +248,7 @@ def _latex_(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5) sage: kCusps = NFCusps(k) sage: latex(kCusps) # indirect doctest @@ -252,6 +262,7 @@ def __call__(self, x): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5) sage: kCusps = NFCusps(k) sage: c = kCusps(a,2) @@ -283,10 +294,11 @@ def zero(self): EXAMPLES:: - sage: k.<a> = NumberField(x^2 + 5) - sage: kCusps = NFCusps(k) - sage: kCusps.zero() - Cusp [0: 1] of Number Field in a with defining polynomial x^2 + 5 + sage: x = polygen(ZZ, 'x') + sage: k.<a> = NumberField(x^2 + 5) + sage: kCusps = NFCusps(k) + sage: kCusps.zero() + Cusp [0: 1] of Number Field in a with defining polynomial x^2 + 5 """ return self(0) @@ -296,6 +308,7 @@ def number_field(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: kCusps = NFCusps(k) sage: kCusps.number_field() @@ -337,6 +350,7 @@ class NFCusp(Element): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5) sage: NFCusp(k, a, 2) Cusp [a: 2] of Number Field in a with defining polynomial x^2 + 5 @@ -416,6 +430,7 @@ def __init__(self, number_field, a, b=None, parent=None, lreps=None): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: c = NFCusp(k, 3, a+1); c Cusp [3: a + 1] of Number Field in a with defining polynomial x^2 + 1 @@ -554,6 +569,7 @@ def _repr_(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: c = NFCusp(k, a, 2); c Cusp [a: 2] of Number Field in a with defining polynomial x^2 + 1 @@ -576,6 +592,7 @@ def number_field(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 2) sage: alpha = NFCusp(k, 1, a + 1) sage: alpha.number_field() @@ -589,6 +606,7 @@ def is_infinity(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: NFCusp(k, a, 2).is_infinity() False @@ -605,6 +623,7 @@ def numerator(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: c = NFCusp(k, a, 2) sage: c.numerator() @@ -623,6 +642,7 @@ def denominator(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: c = NFCusp(k, a, 2) sage: c.denominator() @@ -642,6 +662,7 @@ def _number_field_element_(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 2) sage: NFCusp(k, a, 2)._number_field_element_() 1/2*a @@ -660,6 +681,7 @@ def _ring_of_integers_element_(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 2) sage: NFCusp(k, a+1)._ring_of_integers_element_() a + 1 @@ -684,6 +706,7 @@ def _latex_(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 11) sage: latex(NFCusp(k, 3*a, a + 1)) # indirect doctest \[3 a: a + 1\] @@ -709,6 +732,7 @@ def _richcmp_(self, right, op): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^3 + x + 1) sage: kCusps = NFCusps(k) @@ -746,6 +770,7 @@ def __neg__(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: c = NFCusp(k, a, a+1); c Cusp [a: a + 1] of Number Field in a with defining polynomial x^2 + 23 @@ -771,6 +796,7 @@ def apply(self, g): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: beta = NFCusp(k, 0, 1) sage: beta.apply([0, -1, 1, 0]) @@ -788,6 +814,7 @@ def ideal(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: alpha = NFCusp(k, 3, a-1) sage: alpha.ideal() @@ -812,6 +839,7 @@ def ABmatrix(self): :: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: alpha = NFCusp(k, oo) sage: alpha.ABmatrix() @@ -832,7 +860,7 @@ def ABmatrix(self): sage: M = alpha.ABmatrix() sage: M # random [-a^2 - a - 1, -3*a - 7, 8, -2*a^2 - 3*a + 4] - sage: M[0] == alpha.numerator() and M[2]==alpha.denominator() + sage: M[0] == alpha.numerator() and M[2] == alpha.denominator() True An AB-matrix associated to a cusp alpha will send Infinity to alpha: @@ -843,7 +871,7 @@ def ABmatrix(self): sage: M = alpha.ABmatrix() sage: (k.ideal(M[1], M[3])*alpha.ideal()).is_principal() True - sage: M[0] == alpha.numerator() and M[2]==alpha.denominator() + sage: M[0] == alpha.numerator() and M[2] == alpha.denominator() True sage: NFCusp(k, oo).apply(M) == alpha True @@ -901,8 +929,9 @@ def is_Gamma0_equivalent(self, other, N, Transformation=False): :: - sage: K.<a> = NumberField(x^3-10) - sage: N = K.ideal(a-1) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 10) + sage: N = K.ideal(a - 1) sage: alpha = NFCusp(K, 0) sage: beta = NFCusp(K, oo) sage: alpha.is_Gamma0_equivalent(beta, N) @@ -1008,6 +1037,7 @@ def Gamma0_NFCusps(N): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5) sage: N = k.ideal(3) sage: L = Gamma0_NFCusps(N) @@ -1026,6 +1056,7 @@ def Gamma0_NFCusps(N): Another example:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^4 - x^3 -21*x^2 + 17*x + 133) sage: N = k.ideal(5) sage: from sage.modular.cusps_nf import number_of_Gamma0_NFCusps @@ -1099,6 +1130,7 @@ def number_of_Gamma0_NFCusps(N): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(2, a+1) sage: from sage.modular.cusps_nf import number_of_Gamma0_NFCusps @@ -1144,6 +1176,7 @@ def NFCusps_ideal_reps_for_levelN(N, nlists=1): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(5, a + 1) sage: from sage.modular.cusps_nf import NFCusps_ideal_reps_for_levelN @@ -1203,6 +1236,7 @@ def units_mod_ideal(I): EXAMPLES:: sage: from sage.modular.cusps_nf import units_mod_ideal + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: I = k.ideal(a + 1) sage: units_mod_ideal(I) @@ -1216,7 +1250,8 @@ def units_mod_ideal(I): sage: from sage.modular.cusps_nf import units_mod_ideal sage: k.<a> = NumberField(x^3 + 11) sage: k.unit_group() - Unit group with structure C2 x Z of Number Field in a with defining polynomial x^3 + 11 + Unit group with structure C2 x Z of + Number Field in a with defining polynomial x^3 + 11 sage: I = k.ideal(5, a + 1) sage: units_mod_ideal(I) [1, @@ -1228,7 +1263,8 @@ def units_mod_ideal(I): sage: from sage.modular.cusps_nf import units_mod_ideal sage: k.<a> = NumberField(x^4 - x^3 -21*x^2 + 17*x + 133) sage: k.unit_group() - Unit group with structure C6 x Z of Number Field in a with defining polynomial x^4 - x^3 - 21*x^2 + 17*x + 133 + Unit group with structure C6 x Z of + Number Field in a with defining polynomial x^4 - x^3 - 21*x^2 + 17*x + 133 sage: I = k.ideal(3) sage: U = units_mod_ideal(I) sage: all(U[j].is_unit() and (U[j] not in I) for j in range(len(U))) diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 7efa9d8553f..9785c18963f 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -60,26 +60,23 @@ import sage.misc.prandom as random import sage.modules.free_module_element as free_module_element import sage.rings.abc -import sage.rings.number_field.number_field as number_field from sage.arith.functions import lcm -from sage.arith.misc import bernoulli, kronecker, factor, gcd, fundamental_discriminant, euler_phi, valuation +from sage.arith.misc import bernoulli, binomial, factorial, kronecker, factor, gcd, fundamental_discriminant, euler_phi, valuation from sage.categories.map import Map from sage.categories.objects import Objects -from sage.functions.other import binomial, factorial -from sage.libs.pari import pari from sage.misc.cachefunc import cached_method from sage.misc.fast_methods import WithEqualityById from sage.misc.functional import round +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modules.free_module import FreeModule from sage.rings.finite_rings.integer_mod import Mod from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import CyclotomicField from sage.rings.power_series_ring import PowerSeriesRing -from sage.rings.rational_field import RationalField, QQ, is_RationalField +from sage.rings.rational_field import QQ, is_RationalField from sage.rings.ring import is_Ring from sage.structure.element import MultiplicativeGroupElement from sage.structure.factory import UniqueFactory @@ -88,8 +85,11 @@ from sage.structure.richcmp import richcmp from sage.structure.sequence import Sequence +lazy_import('sage.libs.pari', 'pari') +lazy_import('sage.rings.number_field.number_field', ['CyclotomicField', 'NumberField', 'NumberField_generic']) -def trivial_character(N, base_ring=RationalField()): + +def trivial_character(N, base_ring=QQ): r""" Return the trivial character of the given modulus, with values in the given base ring. @@ -136,14 +136,14 @@ def kronecker_character(d): raise ValueError("d must be nonzero") D = fundamental_discriminant(d) - G = DirichletGroup(abs(D), RationalField()) + G = DirichletGroup(abs(D), QQ) return G([kronecker(D, u) for u in G.unit_gens()]) def kronecker_character_upside_down(d): """ Return the quadratic Dirichlet character (./d) of conductor d, for - d0. + d > 0. EXAMPLES:: @@ -158,11 +158,11 @@ def kronecker_character_upside_down(d): if d <= 0: raise ValueError("d must be positive") - G = DirichletGroup(d, RationalField()) + G = DirichletGroup(d, QQ) return G([kronecker(u.lift(), d) for u in G.unit_gens()]) -def is_DirichletCharacter(x): +def is_DirichletCharacter(x) -> bool: r""" Return ``True`` if ``x`` is of type ``DirichletCharacter``. @@ -640,7 +640,7 @@ def bernoulli(self, k, algorithm='recurrence', cache=True, **opts): .. MATH:: \sum_{a=1}^N \frac{\varepsilon(a) t e^{at}}{e^{Nt}-1} - = sum_{k=0}^{\infty} \frac{B_{k,\varepsilon}}{k!} t^k. + = \sum_{k=0}^{\infty} \frac{B_{k,\varepsilon}}{k!} t^k. ALGORITHM: @@ -708,8 +708,9 @@ def bernoulli(self, k, algorithm='recurrence', cache=True, **opts): def S(n): return sum(v[r] * r**n for r in range(1, N)) - ber = K(sum(binomial(k, j) * bernoulli(j, **opts) * - N**(j - 1) * S(k - j) for j in range(k + 1))) + + ber = sum(binomial(k, j) * bernoulli(j, **opts) * + N**(j - 1) * S(k - j) for j in range(k + 1)) elif algorithm == "definition": # This is better since it computes the same thing, but requires # no arith in a poly ring over a number field. @@ -722,7 +723,7 @@ def S(n): h = [0] + [g * ((n * t).exp(prec)) for n in range(1, N + 1)] ber = sum([self(a) * h[a][k] for a in range(1, N + 1)]) * factorial(k) else: - raise ValueError("algorithm = '%s' unknown" % algorithm) + raise ValueError(f"algorithm = '{algorithm}' unknown") if cache: self.__bernoulli[k] = ber @@ -914,9 +915,6 @@ def fixed_field_polynomial(self, algorithm="pari"): # this algorithm was written by Francis Clarke see issue #9407 - from sage.rings.finite_rings.integer_mod_ring import IntegerModRing - from sage.rings.integer_ring import IntegerRing - ZZ = IntegerRing() from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.matrix.constructor import matrix @@ -999,7 +997,7 @@ def fixed_field_polynomial(self, algorithm="pari"): G, chi = self._pari_init_() K = pari.charker(G, chi) H = pari.galoissubcyclo(G, K) - P = PolynomialRing(RationalField(), "x") + P = PolynomialRing(QQ, "x") x = P.gen() return H.sage({"x": x}) @@ -1039,7 +1037,7 @@ def fixed_field(self): sage: psi.fixed_field() Number Field in a with defining polynomial x^5 + x^4 - 12*x^3 - 21*x^2 + x + 5 """ - return number_field.NumberField(self.fixed_field_polynomial(), 'a') + return NumberField(self.fixed_field_polynomial(), 'a') @cached_method def decomposition(self): @@ -1203,7 +1201,12 @@ def conrey_number(self): sage: eps2 = DirichletGroup(5,QQ)([-1]) sage: eps1.conrey_number() == eps2.conrey_number() True + sage: chi = DirichletGroup(1)[0] + sage: chi.conrey_number() + 1 """ + if self.modulus() == 1: + return 1 G, v = self._pari_init_() return pari.znconreyexp(G, v).sage() @@ -1903,7 +1906,7 @@ def minimize_base_ring(self): K = IntegerModRing(p) elif self.order() <= 2: K = QQ - elif (isinstance(R, number_field.NumberField_generic) + elif (isinstance(R, NumberField_generic) and euler_phi(self.order()) < R.absolute_degree()): K = CyclotomicField(self.order()) else: @@ -2339,6 +2342,7 @@ class DirichletGroupFactory(UniqueFactory): sage: parent(val) Gaussian Integers in Cyclotomic Field of order 4 and degree 2 sage: r4.residue_field(r4.ideal(29).factor()[0][0])(val) + doctest:warning ... DeprecationWarning: ... 17 sage: r4.residue_field(r4.ideal(29).factor()[0][0])(val) * GF(29)(3) 22 @@ -2943,7 +2947,7 @@ def _automorphisms(self): if p == 0: Auts = [e for e in range(1, n) if gcd(e, n) == 1] else: - if not ZZ(p).is_prime(): + if not Integer(p).is_prime(): raise NotImplementedError("Automorphisms for finite non-field base rings not implemented") # The automorphisms in characteristic p are # k-th powering for diff --git a/src/sage/modular/hecke/__init__.py b/src/sage/modular/hecke/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/hecke/algebra.py b/src/sage/modular/hecke/algebra.py index 3699d2cb98e..0f6f5536a70 100644 --- a/src/sage/modular/hecke/algebra.py +++ b/src/sage/modular/hecke/algebra.py @@ -43,7 +43,7 @@ def is_HeckeAlgebra(x): r""" - Return True if x is of type HeckeAlgebra. + Return ``True`` if x is of type HeckeAlgebra. EXAMPLES:: @@ -210,7 +210,7 @@ def __call__(self, x, check=True): In the last case, the parameter ``check`` controls whether or not to check that this element really does lie in the appropriate algebra. At present, setting ``check=True`` raises - a NotImplementedError unless x is a scalar (or a diagonal + a :class:`NotImplementedError` unless x is a scalar (or a diagonal matrix). EXAMPLES:: @@ -320,7 +320,7 @@ def ngens(self): def is_noetherian(self): """ - Return True if this Hecke algebra is Noetherian as a ring. This is true + Return ``True`` if this Hecke algebra is Noetherian as a ring. This is true if and only if the base ring is Noetherian. EXAMPLES:: @@ -649,7 +649,6 @@ def __richcmp__(self, other, op): False sage: A == A True - """ if not isinstance(other, HeckeAlgebra_anemic): return NotImplemented @@ -675,9 +674,9 @@ def hecke_operator(self, n): raise IndexError("Hecke operator T_%s not defined in the anemic Hecke algebra" % n) return self.module()._hecke_operator_class()(self, n) - def is_anemic(self): + def is_anemic(self) -> bool: """ - Return True, since this is the anemic Hecke algebra. + Return ``True``, since this is the anemic Hecke algebra. EXAMPLES:: diff --git a/src/sage/modular/hecke/ambient_module.py b/src/sage/modular/hecke/ambient_module.py index 3e4ae52f00f..e5ed6158cb5 100644 --- a/src/sage/modular/hecke/ambient_module.py +++ b/src/sage/modular/hecke/ambient_module.py @@ -21,9 +21,8 @@ from . import module from . import submodule -import sage.modules.all - -import sage.rings.all +from sage.modules.free_module import FreeModule, is_FreeModule +from sage.rings.integer import Integer import sage.arith.all as arith @@ -70,7 +69,7 @@ def __init__(self, base_ring, rank, level, weight, category=None): sage: sage.modular.hecke.ambient_module.AmbientHeckeModule(QQ, 3, 2, 4) Generic ambient Hecke module of rank 3, level 2 and weight 4 over Rational Field """ - rank = sage.rings.all.Integer(rank) + rank = Integer(rank) if rank < 0: raise ValueError("rank (=%s) must be nonnegative" % rank) self.__rank = rank @@ -389,12 +388,12 @@ def degeneracy_map(self, codomain, t=1): err = True if err: raise ValueError(("the level of self (=%s) must be a divisor or multiple of " - "level (=%s) and t (=%s) must be a divisor of the quotient") % (self.level(), level, t)) + "level (=%s) and t (=%s) must be a divisor of the quotient") % (self.level(), level, t)) eps = self.character() if not (eps is None) and level % eps.conductor() != 0: raise ArithmeticError("the conductor of the character of this space " - "(=%s) must be divisible by the level (=%s)" % (eps.conductor(), level)) + "(=%s) must be divisible by the level (=%s)" % (eps.conductor(), level)) if M is None: M = self.hecke_module_of_level(level) @@ -491,7 +490,7 @@ def free_module(self): try: return self.__free_module except AttributeError: - M = sage.modules.all.FreeModule(self.base_ring(), self.rank()) + M = FreeModule(self.base_ring(), self.rank()) self.__free_module = M return M @@ -917,7 +916,7 @@ def old_submodule(self, p=None): def submodule(self, M, Mdual=None, check=True): """ - Return the Hecke submodule of self generated by M, which may be a + Return the Hecke submodule of ``self`` generated by `M`, which may be a submodule of the free module of self, or a list of elements of self. EXAMPLES:: @@ -927,7 +926,7 @@ def submodule(self, M, Mdual=None, check=True): Modular Forms subspace of dimension 2 of Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(37) of weight 2 over Rational Field """ if check: - if not sage.modules.free_module.is_FreeModule(M): + if not is_FreeModule(M): V = self.free_module() if isinstance(M, (list, tuple)): M = V.span([V(x.element()) for x in M]) diff --git a/src/sage/modular/hecke/degenmap.py b/src/sage/modular/hecke/degenmap.py index 7475244b569..fad128c0c3c 100644 --- a/src/sage/modular/hecke/degenmap.py +++ b/src/sage/modular/hecke/degenmap.py @@ -2,7 +2,7 @@ Degeneracy maps """ -#***************************************************************************** +# **************************************************************************** # Sage: Open Source Mathematical Software # # Copyright (C) 2005 William Stein <wstein@gmail.com> @@ -16,12 +16,11 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** - - +# https://www.gnu.org/licenses/ +# **************************************************************************** from . import morphism + class DegeneracyMap(morphism.HeckeModuleMorphism_matrix): """ A degeneracy map between Hecke modules of different levels. @@ -93,8 +92,8 @@ def __init__(self, matrix, domain, codomain, t): if t == 1: pow = "" else: - pow = "^%s"%t - name = "degeneracy map corresponding to f(q) |--> f(q%s)"%(pow) + pow = "^%s" % t + name = "degeneracy map corresponding to f(q) |--> f(q%s)" % (pow) morphism.HeckeModuleMorphism_matrix.__init__(self, H, matrix, name) def t(self): diff --git a/src/sage/modular/hecke/element.py b/src/sage/modular/hecke/element.py index fb8d267cf98..b91d33b6b8d 100644 --- a/src/sage/modular/hecke/element.py +++ b/src/sage/modular/hecke/element.py @@ -6,7 +6,7 @@ - William Stein """ -#***************************************************************************** +# **************************************************************************** # Sage: Open Source Mathematical Software # # Copyright (C) 2005 William Stein <wstein@gmail.com> @@ -20,15 +20,16 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.richcmp import richcmp, op_NE from sage.structure.element import ModuleElement + def is_HeckeModuleElement(x): """ - Return True if x is a Hecke module element, i.e., of type HeckeModuleElement. + Return ``True`` if x is a Hecke module element, i.e., of type HeckeModuleElement. EXAMPLES:: @@ -39,6 +40,7 @@ def is_HeckeModuleElement(x): """ return isinstance(x, HeckeModuleElement) + class HeckeModuleElement(ModuleElement): """ Element of a Hecke module. @@ -180,7 +182,7 @@ def _lmul_(self, x): sage: BrandtModule(37)([0,1,-1])._lmul_(3) (0, 3, -3) """ - return self.parent()(self.element()*x) + return self.parent()(self.element() * x) def _rmul_(self, x): """ @@ -218,9 +220,9 @@ def _sub_(self, right): """ return self.parent()(self.element() - right.element()) - def is_cuspidal(self): + def is_cuspidal(self) -> bool: r""" - Return True if this element is cuspidal. + Return ``True`` if this element is cuspidal. EXAMPLES:: @@ -247,14 +249,14 @@ def is_cuspidal(self): sage: N = next(S for S in M.decomposition(anemic=False) if S.hecke_matrix(3).trace()==-128844) sage: [g.is_cuspidal() for g in N.gens()] [True, True] - """ - return (self in self.parent().ambient().cuspidal_submodule()) + return self in self.parent().ambient().cuspidal_submodule() - def is_eisenstein(self): + def is_eisenstein(self) -> bool: r""" - Return True if this element is Eisenstein. This makes sense for both - modular forms and modular symbols. + Return ``True`` if this element is Eisenstein. + + This makes sense for both modular forms and modular symbols. EXAMPLES:: @@ -269,12 +271,13 @@ def is_eisenstein(self): sage: EllipticCurve('37a1').newform().element().is_eisenstein() False """ - return (self in self.parent().ambient().eisenstein_submodule()) + return self in self.parent().ambient().eisenstein_submodule() - def is_new(self, p=None): + def is_new(self, p=None) -> bool: r""" - Return True if this element is p-new. If p is None, return True if the - element is new. + Return ``True`` if this element is p-new. + + If p is ``None``, return ``True`` if the element is new. EXAMPLES:: @@ -285,12 +288,13 @@ def is_new(self, p=None): sage: CuspForms(22, 2).0.is_new() False """ - return (self in self.parent().new_submodule(p)) + return self in self.parent().new_submodule(p) - def is_old(self, p=None): + def is_old(self, p=None) -> bool: r""" - Return True if this element is p-old. If p is None, return True if the - element is old. + Return ``True`` if this element is p-old. + + If p is ``None``, return ``True`` if the element is old. EXAMPLES:: @@ -305,4 +309,4 @@ def is_old(self, p=None): sage: EisensteinForms(144, 2).1.is_old(2) # not implemented False """ - return (self in self.parent().old_submodule(p)) + return self in self.parent().old_submodule(p) diff --git a/src/sage/modular/hecke/hecke_operator.py b/src/sage/modular/hecke/hecke_operator.py index 0974629977d..e0401936daa 100644 --- a/src/sage/modular/hecke/hecke_operator.py +++ b/src/sage/modular/hecke/hecke_operator.py @@ -1,8 +1,7 @@ """ Hecke operators """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) @@ -14,15 +13,13 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** - - +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.element import AlgebraElement from sage.structure.richcmp import richcmp, rich_to_bool from sage.categories.homset import End import sage.arith.all as arith -from sage.rings.integer import Integer +from sage.rings.integer import Integer from . import algebra from . import morphism @@ -30,7 +27,7 @@ def is_HeckeOperator(x): r""" - Return True if x is of type HeckeOperator. + Return ``True`` if x is of type HeckeOperator. EXAMPLES:: @@ -43,9 +40,10 @@ def is_HeckeOperator(x): """ return isinstance(x, HeckeOperator) + def is_HeckeAlgebraElement(x): r""" - Return True if x is of type HeckeAlgebraElement. + Return ``True`` if x is of type HeckeAlgebraElement. EXAMPLES:: @@ -58,6 +56,7 @@ def is_HeckeAlgebraElement(x): """ return isinstance(x, HeckeAlgebraElement) + class HeckeAlgebraElement(AlgebraElement): r""" Base class for elements of Hecke algebras. @@ -73,7 +72,7 @@ def __init__(self, parent): Generic element of a structure """ if not algebra.is_HeckeAlgebra(parent): - raise TypeError("parent (=%s) must be a Hecke algebra"%parent) + raise TypeError("parent (=%s) must be a Hecke algebra" % parent) AlgebraElement.__init__(self, parent) def domain(self): @@ -141,7 +140,7 @@ def hecke_module_morphism(self): M = self.domain() H = End(M) if isinstance(self, HeckeOperator): - name = "T_%s"%self.index() + name = "T_%s" % self.index() else: name = "" self.__hecke_module_morphism = morphism.HeckeModuleMorphism_matrix(H, T, name) @@ -247,7 +246,7 @@ def apply_sparse(self, x): 24*(1,0) - 5*(1,9) """ if x not in self.domain(): - raise TypeError("x (=%s) must be in %s"%(x, self.domain())) + raise TypeError("x (=%s) must be in %s" % (x, self.domain())) # Generic implementation which doesn't actually do anything # special regarding sparseness. Override this for speed. T = self.hecke_module_morphism() @@ -303,7 +302,7 @@ def decomposition(self): except AttributeError: pass if isinstance(self, HeckeOperator) and \ - arith.gcd(self.index(), self.domain().level()) == 1: + arith.gcd(self.index(), self.domain().level()) == 1: D = self.hecke_module_morphism().decomposition(is_diagonalizable=True) else: # TODO: There are other weaker hypotheses that imply diagonalizability. @@ -466,7 +465,7 @@ def _richcmp_(self, other, op): if isinstance(other, HeckeOperator): return richcmp(self, other.matrix_form(), op) else: - raise RuntimeError("Bug in coercion code") # can't get here + raise RuntimeError("Bug in coercion code") # can't get here return richcmp(self.__matrix, other.__matrix, op) @@ -639,7 +638,7 @@ def _richcmp_(self, other, op): if isinstance(other, HeckeAlgebraElement_matrix): return richcmp(self.matrix_form(), other, op) else: - raise RuntimeError("Bug in coercion code") # can't get here + raise RuntimeError("Bug in coercion code") # can't get here if self.__n == other.__n: return rich_to_bool(op, 0) @@ -654,7 +653,7 @@ def _repr_(self): sage: ModularSymbols(Gamma0(7), 4).hecke_operator(6)._repr_() 'Hecke operator T_6 on Modular Symbols space of dimension 4 for Gamma_0(7) of weight 4 with sign 0 over Rational Field' """ - return "Hecke operator T_%s on %s"%(self.__n, self.domain()) + return "Hecke operator T_%s on %s" % (self.__n, self.domain()) def _latex_(self): r""" @@ -665,15 +664,17 @@ def _latex_(self): sage: ModularSymbols(Gamma0(7), 4).hecke_operator(6)._latex_() 'T_{6}' """ - return "T_{%s}"%self.__n + return "T_{%s}" % self.__n def _mul_(self, other): - """ - Multiply this Hecke operator by another element of the same algebra. If - the other element is of the form `T_m` for some m, we check whether the - product is equal to `T_{mn}` and return that; if the product is not - (easily seen to be) of the form `T_{mn}`, then we calculate the product - of the two matrices and return a Hecke algebra element defined by that. + r""" + Multiply this Hecke operator by another element of the same algebra. + + If the other element is of the form `T_m` for some m, we check + whether the product is equal to `T_{mn}` and return that; if + the product is not (easily seen to be) of the form `T_{mn}`, + then we calculate the product of the two matrices and return a + Hecke algebra element defined by that. EXAMPLES: We create the space of modular symbols of level `11` and weight `2`, then compute `T_2` diff --git a/src/sage/modular/hecke/homspace.py b/src/sage/modular/hecke/homspace.py index a42e40e3584..2245067bf99 100644 --- a/src/sage/modular/hecke/homspace.py +++ b/src/sage/modular/hecke/homspace.py @@ -1,7 +1,7 @@ r""" Hom spaces between Hecke modules """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) @@ -13,9 +13,8 @@ # See the GNU General Public License for more details; the full text # is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.matrix.constructor import matrix from sage.matrix.matrix_space import MatrixSpace from sage.categories.homset import HomsetWithBase @@ -25,7 +24,7 @@ def is_HeckeModuleHomspace(x): r""" - Return True if x is a space of homomorphisms in the category of Hecke modules. + Return ``True`` if x is a space of homomorphisms in the category of Hecke modules. EXAMPLES:: diff --git a/src/sage/modular/hecke/module.py b/src/sage/modular/hecke/module.py index f559b6f1d3a..8e1b699658c 100644 --- a/src/sage/modular/hecke/module.py +++ b/src/sage/modular/hecke/module.py @@ -1696,7 +1696,6 @@ def system_of_eigenvalues(self, n, name='alpha'): Next we define a function that does the above:: sage: def b(N,k=2): - ....: t=cputime() ....: S = ModularSymbols(N,k,sign=-1).cuspidal_submodule().new_submodule() ....: for A in S.decomposition(): ....: print("{} {}".format(N, A.system_of_eigenvalues(5))) diff --git a/src/sage/modular/hecke/morphism.py b/src/sage/modular/hecke/morphism.py index 92df8ca77dc..373d2b67298 100644 --- a/src/sage/modular/hecke/morphism.py +++ b/src/sage/modular/hecke/morphism.py @@ -6,7 +6,7 @@ - William Stein """ -#***************************************************************************** +# **************************************************************************** # Sage: Open Source Mathematical Software # # Copyright (C) 2005 William Stein <wstein@gmail.com> @@ -20,8 +20,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import sage.misc.misc as misc @@ -33,9 +33,10 @@ # modular abelian varieties (which are specified by matrices, but on # integral homology). All morphisms derive from HeckeModuleMorphism. + def is_HeckeModuleMorphism(x): r""" - Return True if x is of type HeckeModuleMorphism. + Return ``True`` if x is of type HeckeModuleMorphism. EXAMPLES:: @@ -44,6 +45,7 @@ def is_HeckeModuleMorphism(x): """ return isinstance(x, HeckeModuleMorphism) + def is_HeckeModuleMorphism_matrix(x): """ @@ -54,12 +56,14 @@ def is_HeckeModuleMorphism_matrix(x): """ return isinstance(x, HeckeModuleMorphism_matrix) + class HeckeModuleMorphism(Morphism): r""" Abstract base class for morphisms of Hecke modules. """ pass + class HeckeModuleMorphism_matrix(MatrixMorphism, HeckeModuleMorphism): """ Morphisms of Hecke modules when the morphism is given by a matrix. @@ -146,9 +150,8 @@ def _repr_(self): 'Hecke module morphism spam defined by the matrix\n[0 1 2]\n[3 4 5]\n[6 7 8]\nDomain: Modular Symbols space of dimension 3 for Gamma_0(6) of weight ...\nCodomain: Modular Symbols space of dimension 3 for Gamma_0(6) of weight ...' """ name = self.__name - if name != '': + if name: name += ' ' - return "Hecke module morphism %sdefined by the matrix\n%r\nDomain: %s\nCodomain: %s"%( - name, self.matrix(), misc.strunc(self.domain()), misc.strunc(self.codomain())) + return "Hecke module morphism %sdefined by the matrix\n%r\nDomain: %s\nCodomain: %s" % (name, self.matrix(), misc.strunc(self.domain()), misc.strunc(self.codomain())) # __mul__ method removed by David Loeffler 2009-04-14 as it is an exact duplicate of sage.modules.matrix_morphism.__mul__ diff --git a/src/sage/modular/hecke/submodule.py b/src/sage/modular/hecke/submodule.py index efcd8c9c848..c1112d685b6 100644 --- a/src/sage/modular/hecke/submodule.py +++ b/src/sage/modular/hecke/submodule.py @@ -21,15 +21,15 @@ import sage.arith.all as arith from sage.misc.verbose import verbose from sage.misc.cachefunc import cached_method +from sage.modules.free_module import is_FreeModule from sage.structure.richcmp import richcmp_method, richcmp_not_equal -import sage.modules.all from . import module def is_HeckeSubmodule(x): r""" - Return True if x is of type HeckeSubmodule. + Return ``True`` if x is of type HeckeSubmodule. EXAMPLES:: @@ -80,7 +80,7 @@ def __init__(self, ambient, submodule, dual_free_module=None, check=True): from . import ambient_module if not isinstance(ambient, ambient_module.AmbientHeckeModule): raise TypeError("ambient must be an ambient Hecke module") - if not sage.modules.free_module.is_FreeModule(submodule): + if not is_FreeModule(submodule): raise TypeError("submodule must be a free module") if not submodule.is_submodule(ambient.free_module()): raise ValueError("submodule must be a submodule of the ambient free module") @@ -91,10 +91,11 @@ def __init__(self, ambient, submodule, dual_free_module=None, check=True): self.__ambient = ambient self.__submodule = submodule - module.HeckeModule_free_module.__init__(self, - ambient.base_ring(), ambient.level(), ambient.weight()) + module.HeckeModule_free_module.__init__(self, ambient.base_ring(), + ambient.level(), + ambient.weight()) if not (dual_free_module is None): - if not sage.modules.free_module.is_FreeModule(dual_free_module): + if not is_FreeModule(dual_free_module): raise TypeError("dual_free_module must be a free module") if dual_free_module.rank() != submodule.rank(): raise ArithmeticError("dual_free_module must have the same rank as submodule") @@ -446,10 +447,12 @@ def degeneracy_map(self, level, t=1): @cached_method def dual_free_module(self, bound=None, anemic=True, use_star=True): r""" - Compute embedded dual free module if possible. In general this won't be - possible, e.g., if this space is not Hecke equivariant, possibly if it - is not cuspidal, or if the characteristic is not 0. In all these cases - we raise a RuntimeError exception. + Compute embedded dual free module if possible. + + In general this will not be possible, e.g., if this space is + not Hecke equivariant, possibly if it is not cuspidal, or if + the characteristic is not 0. In all these cases we raise a + :class:`RuntimeError` exception. If use_star is True (which is the default), we also use the +/- eigenspaces for the star operator to find the dual free module of self. @@ -587,7 +590,7 @@ def dual_free_module(self, bound=None, anemic=True, use_star=True): return V2 raise RuntimeError("Computation of embedded dual vector space failed " - "(cut down to rank %s, but should have cut down to rank %s)." % (V.rank(), self.rank())) + "(cut down to rank %s, but should have cut down to rank %s)." % (V.rank(), self.rank())) def free_module(self): """ @@ -908,7 +911,7 @@ def submodule(self, M, Mdual=None, check=True): sage: S.submodule(S[0].free_module()) Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_0(18) of weight 4 with sign 0 over Rational Field """ - if not sage.modules.free_module.is_FreeModule(M): + if not is_FreeModule(M): V = self.ambient_module().free_module() if isinstance(M, (list, tuple)): M = V.span([V(x.element()) for x in M]) diff --git a/src/sage/modular/hypergeometric_misc.pxd b/src/sage/modular/hypergeometric_misc.pxd index d031601666f..00bf9a97e9a 100644 --- a/src/sage/modular/hypergeometric_misc.pxd +++ b/src/sage/modular/hypergeometric_misc.pxd @@ -1,3 +1,2 @@ cpdef hgm_coeffs(long long p, int f, int prec, gamma, m, int D, gtable, int gtable_prec, bint use_longs) - diff --git a/src/sage/modular/hypergeometric_misc.pyx b/src/sage/modular/hypergeometric_misc.pyx index 7f3c8ee494d..af2c4f74e15 100644 --- a/src/sage/modular/hypergeometric_misc.pyx +++ b/src/sage/modular/hypergeometric_misc.pyx @@ -5,6 +5,7 @@ significantly from Cythonization. from cpython cimport array from cysignals.signals cimport sig_check + cpdef hgm_coeffs(long long p, int f, int prec, gamma, m, int D, gtable, int gtable_prec, bint use_longs): r""" @@ -24,20 +25,19 @@ cpdef hgm_coeffs(long long p, int f, int prec, gamma, m, int D, sage: D = 1 sage: hgm_coeffs(7, 1, 2, gamma, [0]*6, D, gtable, prec, False) [7, 2*7, 6*7, 7, 6, 4*7] - + Check issue from :trac:`28404`:: - + sage: H = Hyp(cyclotomic=[[10,2],[1,1,1,1,1]]) sage: u = H.euler_factor(2,79) # indirect doctest sage: u.reverse().is_weil_polynomial() - True - + True """ from sage.rings.padics.factory import Zp cdef int gl, j, k, l, v, gv cdef long long i, q1, w, w1, w2, q2, r, r1 - cdef bint flip, need_lift + cdef bint flip q1 = p ** f - 1 gl = len(gamma) @@ -116,8 +116,8 @@ cpdef hgm_coeffs(long long p, int f, int prec, gamma, m, int D, if flip: gv = -gv if use_longs: - w2 = gtab2[r1] # cast to long long to avoid overflow - if gv > 0: + w2 = gtab2[r1] # cast to long long to avoid overflow + if gv > 0: for j in range(gv): w = w * w2 % q2 else: diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index ad34fb3c92b..0db87ac9f66 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -688,11 +688,10 @@ def zigzag(self, x, flip_beta=False): alpha = self._alpha beta = self._beta if flip_beta: - return(sum(1 for a in alpha if a <= x) - - sum(1 for b in beta if 1 - b <= x)) - else: - return(sum(1 for a in alpha if a <= x) - - sum(1 for b in beta if b <= x)) + return (sum(1 for a in alpha if a <= x) - + sum(1 for b in beta if 1 - b <= x)) + return (sum(1 for a in alpha if a <= x) - + sum(1 for b in beta if b <= x)) def weight(self): """ diff --git a/src/sage/modular/local_comp/__init__.py b/src/sage/modular/local_comp/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/local_comp/local_comp.py b/src/sage/modular/local_comp/local_comp.py index 693843b1afe..765ce805ed9 100644 --- a/src/sage/modular/local_comp/local_comp.py +++ b/src/sage/modular/local_comp/local_comp.py @@ -23,14 +23,16 @@ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring import polygen from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.qqbar import QQbar from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose from sage.misc.flatten import flatten from sage.modular.modform.element import Newform from sage.structure.sequence import Sequence +lazy_import('sage.rings.qqbar', 'QQbar') + from .type_space import TypeSpace from .smoothchar import SmoothCharacterGroupQp, SmoothCharacterGroupUnramifiedQuadratic, SmoothCharacterGroupRamifiedQuadratic @@ -885,9 +887,8 @@ def characters(self): G = G.base_extend(F) c1q2, c2q2 = flatten([[x]*e for x,e in theta_poly.roots(G.base_ring())]) - - pairA = [ [c1q, c1q2], [c2q,c2q2] ] - pairB = [ [c1q, c2q2], [c2q, c1q2] ] + pairA = [[c1q, c1q2], [c2q, c2q2]] + pairB = [[c1q, c2q2], [c2q, c1q2]] A_fail = 0 B_fail = 0 diff --git a/src/sage/modular/local_comp/smoothchar.py b/src/sage/modular/local_comp/smoothchar.py index 0e878b99277..b56befe27cb 100644 --- a/src/sage/modular/local_comp/smoothchar.py +++ b/src/sage/modular/local_comp/smoothchar.py @@ -49,15 +49,14 @@ from sage.categories.rings import Rings from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.misc.mrange import xmrange from sage.misc.verbose import verbose from sage.modular.dirichlet import DirichletGroup -from sage.rings.finite_rings.conway_polynomials import conway_polynomial from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ from sage.structure.element import MultiplicativeGroupElement, parent @@ -65,6 +64,9 @@ from sage.structure.richcmp import richcmp_not_equal, richcmp from sage.structure.sequence import Sequence +lazy_import('sage.rings.finite_rings.conway_polynomials', 'conway_polynomial') +lazy_import('sage.rings.number_field.number_field', 'NumberField') + class SmoothCharacterGeneric(MultiplicativeGroupElement): r""" diff --git a/src/sage/modular/local_comp/type_space.py b/src/sage/modular/local_comp/type_space.py index 2549e5519b0..e27e4b27137 100644 --- a/src/sage/modular/local_comp/type_space.py +++ b/src/sage/modular/local_comp/type_space.py @@ -373,15 +373,15 @@ def minimal_twist(self): Test that :trac:`13158` is fixed:: sage: f = Newforms(256,names='a')[0] - sage: T = TypeSpace(f,2) - sage: g = T.minimal_twist() - sage: g[0:3] + sage: T = TypeSpace(f,2) # long time + sage: g = T.minimal_twist() # long time + sage: g[0:3] # long time [0, 1, 0] - sage: str(g[3]) in ('a', '-a', '-1/2*a', '1/2*a') + sage: str(g[3]) in ('a', '-a', '-1/2*a', '1/2*a') # long time True - sage: g[4:] + sage: g[4:] # long time [] - sage: g.level() + sage: g.level() # long time 64 """ if self.is_minimal(): @@ -497,7 +497,7 @@ def _rho_unramified(self, g): True """ f = self.prime() ** self.u() - from sage.groups.matrix_gps.all import SL + from sage.groups.matrix_gps.linear import SL G = SL(2, Zmod(f)) gg = G(g) s = G([1,1,0,1]) diff --git a/src/sage/modular/modform/__init__.py b/src/sage/modular/modform/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/modform/all.py b/src/sage/modular/modform/all.py index eefb8c3609f..feb1521d3ca 100644 --- a/src/sage/modular/modform/all.py +++ b/src/sage/modular/modform/all.py @@ -14,9 +14,10 @@ from .theta import theta_qexp, theta2_qexp -from .j_invariant import j_invariant_qexp +from sage.misc.lazy_import import lazy_import -from .vm_basis import victor_miller_basis, delta_qexp +lazy_import('sage.modular.modform.j_invariant', 'j_invariant_qexp') +lazy_import('sage.modular.modform.vm_basis', ['victor_miller_basis', 'delta_qexp']) from .hecke_operator_on_qexp import hecke_operator_on_qexp, hecke_operator_on_basis diff --git a/src/sage/modular/modform/ambient_R.py b/src/sage/modular/modform/ambient_R.py index 91e3f97b603..9601342faeb 100644 --- a/src/sage/modular/modform/ambient_R.py +++ b/src/sage/modular/modform/ambient_R.py @@ -91,12 +91,12 @@ def _compute_q_expansion_basis(self, prec=None): This checks that :trac:`13445` is fixed:: - sage: M = ModularForms(Gamma1(29), base_ring=GF(29)) + sage: M = ModularForms(Gamma0(11), base_ring=GF(11)) sage: S = M.cuspidal_subspace() sage: 0 in [f.valuation() for f in S.basis()] False sage: from sage.modular.dims import dimension_cusp_forms - sage: len(S.basis()) == dimension_cusp_forms(Gamma1(29), 2) + sage: len(S.basis()) == dimension_cusp_forms(Gamma0(11), 2) True """ if prec is None: @@ -147,7 +147,6 @@ def cuspidal_submodule(self): """ return CuspidalSubmodule_R(self) - def change_ring(self, R): r""" Return this modular forms space with the base ring changed to the ring R. diff --git a/src/sage/modular/modform/ambient_eps.py b/src/sage/modular/modform/ambient_eps.py index b5c3c543d67..8f14e22ce20 100644 --- a/src/sage/modular/modform/ambient_eps.py +++ b/src/sage/modular/modform/ambient_eps.py @@ -75,7 +75,7 @@ # http://www.gnu.org/licenses/ ######################################################################### -import sage.rings.all as rings +from sage.rings.integer import Integer import sage.modular.arithgroup.all as arithgroup import sage.modular.dirichlet as dirichlet @@ -200,7 +200,7 @@ def change_ring(self, base_ring): return self return ambient_R.ModularFormsAmbient_R(self, base_ring=base_ring) - @cached_method(key=lambda self, sign: rings.Integer(sign)) # convert sign to an Integer before looking this up in the cache + @cached_method(key=lambda self, sign: Integer(sign)) # convert sign to an Integer before looking this up in the cache def modular_symbols(self, sign=0): """ Return corresponding space of modular symbols with given sign. @@ -220,7 +220,7 @@ def modular_symbols(self, sign=0): ... ValueError: sign must be -1, 0, or 1 """ - sign = rings.Integer(sign) + sign = Integer(sign) return modsym.ModularSymbols(self.character(), weight=self.weight(), sign=sign, diff --git a/src/sage/modular/modform/ambient_g0.py b/src/sage/modular/modform/ambient_g0.py index a409a062984..114718b68b9 100644 --- a/src/sage/modular/modform/ambient_g0.py +++ b/src/sage/modular/modform/ambient_g0.py @@ -16,7 +16,7 @@ # http://www.gnu.org/licenses/ ######################################################################### -import sage.rings.all as rings +from sage.rings.rational_field import Q as QQ import sage.modular.arithgroup.all as arithgroup @@ -43,7 +43,7 @@ def __init__(self, level, weight): sage: type(m) <class 'sage.modular.modform.ambient_g0.ModularFormsAmbient_g0_Q_with_category'> """ - ambient.ModularFormsAmbient.__init__(self, arithgroup.Gamma0(level), weight, rings.QQ) + ambient.ModularFormsAmbient.__init__(self, arithgroup.Gamma0(level), weight, QQ) def _pari_init_(self): """ diff --git a/src/sage/modular/modform/ambient_g1.py b/src/sage/modular/modform/ambient_g1.py index 75f0de39e15..8c10c861cc0 100644 --- a/src/sage/modular/modform/ambient_g1.py +++ b/src/sage/modular/modform/ambient_g1.py @@ -50,7 +50,7 @@ # http://www.gnu.org/licenses/ ######################################################################### -import sage.rings.all as rings +from sage.rings.rational_field import Q as QQ import sage.modular.arithgroup.all as arithgroup @@ -77,7 +77,7 @@ def __init__(self, group, weight, eis_only): sage: type(m) <class 'sage.modular.modform.ambient_g1.ModularFormsAmbient_gH_Q_with_category'> """ - ambient.ModularFormsAmbient.__init__(self, group, weight, rings.QQ, eis_only=eis_only) + ambient.ModularFormsAmbient.__init__(self, group, weight, QQ, eis_only=eis_only) #################################################################### # Computation of Special Submodules @@ -170,7 +170,7 @@ def __init__(self, level, weight, eis_only): sage: type(m) <class 'sage.modular.modform.ambient_g1.ModularFormsAmbient_g1_Q_with_category'> """ - ambient.ModularFormsAmbient.__init__(self, arithgroup.Gamma1(level), weight, rings.QQ, eis_only=eis_only) + ambient.ModularFormsAmbient.__init__(self, arithgroup.Gamma1(level), weight, QQ, eis_only=eis_only) #################################################################### # Computation of Special Submodules diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index 6e9acf74e36..023f9a380d2 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -34,7 +34,9 @@ import sage.modular.arithgroup.all as arithgroup import sage.modular.dirichlet as dirichlet -import sage.rings.all as rings +from sage.rings.integer import Integer +from sage.rings.rational_field import Q as QQ +from sage.rings.ring import CommutativeRing from .ambient_eps import ModularFormsAmbient_eps from .ambient_g0 import ModularFormsAmbient_g0_Q @@ -92,38 +94,38 @@ def canonical_parameters(group, level, weight, base_ring): ... ValueError: group and level do not match. """ - weight = rings.Integer(weight) + weight = Integer(weight) if weight <= 0: raise NotImplementedError("weight must be at least 1") if isinstance(group, dirichlet.DirichletCharacter): - if ( group.level() != rings.Integer(level) ): + if ( group.level() != Integer(level) ): raise ValueError("group.level() and level do not match.") group = group.minimize_base_ring() - level = rings.Integer(level) + level = Integer(level) elif arithgroup.is_CongruenceSubgroup(group): - if ( rings.Integer(level) != group.level() ): + if ( Integer(level) != group.level() ): raise ValueError("group.level() and level do not match.") # normalize the case of SL2Z if arithgroup.is_SL2Z(group) or \ - arithgroup.is_Gamma1(group) and group.level() == rings.Integer(1): - group = arithgroup.Gamma0(rings.Integer(1)) + arithgroup.is_Gamma1(group) and group.level() == Integer(1): + group = arithgroup.Gamma0(Integer(1)) elif group is None: pass else: try: - m = rings.Integer(group) + m = Integer(group) except TypeError: raise TypeError("group of unknown type.") - level = rings.Integer(level) + level = Integer(level) if ( m != level ): raise ValueError("group and level do not match.") group = arithgroup.Gamma0(m) - if not isinstance(base_ring, rings.CommutativeRing): + if not isinstance(base_ring, CommutativeRing): raise TypeError("base_ring (=%s) must be a commutative ring"%base_ring) # it is *very* important to include the level as part of the data @@ -132,6 +134,7 @@ def canonical_parameters(group, level, weight, base_ring): # forms spaces. return level, group, weight, base_ring + _cache = {} def ModularForms_clear_cache(): @@ -299,7 +302,7 @@ def ModularForms(group=1, if base_ring is None: base_ring = group.minimize_base_ring().base_ring() if base_ring is None: - base_ring = rings.QQ + base_ring = QQ if isinstance(group, dirichlet.DirichletCharacter) \ or arithgroup.is_CongruenceSubgroup(group): @@ -324,17 +327,17 @@ def ModularForms(group=1, M = None if arithgroup.is_Gamma0(group): M = ModularFormsAmbient_g0_Q(group.level(), weight) - if base_ring != rings.QQ: + if base_ring != QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif arithgroup.is_Gamma1(group): M = ModularFormsAmbient_g1_Q(group.level(), weight, eis_only) - if base_ring != rings.QQ: + if base_ring != QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif arithgroup.is_GammaH(group): M = ModularFormsAmbient_gH_Q(group, weight, eis_only) - if base_ring != rings.QQ: + if base_ring != QQ: M = ambient_R.ModularFormsAmbient_R(M, base_ring) elif isinstance(group, dirichlet.DirichletCharacter): @@ -466,7 +469,7 @@ def Newforms(group, weight=2, base_ring=None, names=None): return CuspForms(group, weight, base_ring).newforms(names) -def Newform(identifier, group=None, weight=2, base_ring=rings.QQ, names=None): +def Newform(identifier, group=None, weight=2, base_ring=QQ, names=None): """ INPUT: @@ -497,7 +500,7 @@ def Newform(identifier, group=None, weight=2, base_ring=rings.QQ, names=None): group, identifier = parse_label(identifier) if weight != 2: raise ValueError("Canonical label not implemented for higher weight forms.") - elif base_ring != rings.QQ: + elif base_ring != QQ: raise ValueError("Canonical label not implemented except for over Q.") elif group is None: raise ValueError("Must specify a group or a label.") diff --git a/src/sage/modular/modform/cuspidal_submodule.py b/src/sage/modular/modform/cuspidal_submodule.py index 4b123ec8dc9..19a0b5661c0 100644 --- a/src/sage/modular/modform/cuspidal_submodule.py +++ b/src/sage/modular/modform/cuspidal_submodule.py @@ -41,12 +41,14 @@ from sage.matrix.constructor import Matrix from sage.matrix.special import identity_matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose from sage.rings.integer import Integer from sage.rings.rational_field import QQ +lazy_import('sage.modular.modform.vm_basis', 'victor_miller_basis') + from .submodule import ModularFormsSubmodule -from . import vm_basis from . import weight1 class CuspidalSubmodule(ModularFormsSubmodule): @@ -174,15 +176,16 @@ def modular_symbols(self, sign=0): A = self.ambient_module() return A.modular_symbols(sign).cuspidal_submodule() - def change_ring(self, R): r""" - Change the base ring of self to R, when this makes sense. This differs - from :meth:`~sage.modular.modform.space.ModularFormsSpace.base_extend` - in that there may not be a canonical map from self to the new space, as - in the first example below. If this space has a character then this may - fail when the character cannot be defined over R, as in the second - example. + Change the base ring of ``self`` to ``R``, when this makes sense. + + This differs from + :meth:`~sage.modular.modform.space.ModularFormsSpace.base_extend` + in that there may not be a canonical map from ``self`` to the new + space, as in the first example below. If this space has a + character then this may fail when the character cannot be + defined over ``R``, as in the second example. EXAMPLES:: @@ -315,8 +318,7 @@ def _compute_q_expansion_basis(self, prec=None): prec = self.prec() else: prec = Integer(prec) - return vm_basis.victor_miller_basis(self.weight(), prec, - cusp_only=True, var='q') + return victor_miller_basis(self.weight(), prec, cusp_only=True, var='q') def _pari_init_(self): """ @@ -378,7 +380,7 @@ def _compute_q_expansion_basis(self, prec=None): A more elaborate example (two Galois-conjugate characters each giving a 2-dimensional space):: - sage: CuspForms(GammaH(124, [85]), 1).q_expansion_basis() + sage: CuspForms(GammaH(124, [85]), 1).q_expansion_basis() # long time [ q - q^4 - q^6 + O(q^7), q^2 + O(q^7), diff --git a/src/sage/modular/modform/eis_series.py b/src/sage/modular/modform/eis_series.py index 351577db16e..be0f2557c73 100644 --- a/src/sage/modular/modform/eis_series.py +++ b/src/sage/modular/modform/eis_series.py @@ -14,16 +14,17 @@ from sage.arith.functions import lcm from sage.arith.misc import bernoulli, divisors, is_squarefree -from sage.misc.misc import cputime +from sage.misc.lazy_import import lazy_import +from sage.misc.timing import cputime from sage.modular.arithgroup.congroup_gammaH import GammaH_class from sage.modular.dirichlet import DirichletGroup from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import CyclotomicField from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ -from .eis_series_cython import eisenstein_series_poly, Ek_ZZ +lazy_import('sage.modular.modform.eis_series_cython', ['eisenstein_series_poly', 'Ek_ZZ']) +lazy_import('sage.rings.number_field.number_field', 'CyclotomicField') def eisenstein_series_qexp(k, prec=10, K=QQ, var='q', normalization='linear'): @@ -243,7 +244,6 @@ def __find_eisen_chars(character, k): V.insert(0, (chi, chi_inv, t)) return V - eps = character if eps(-1) != (-1)**k: return [] diff --git a/src/sage/modular/modform/eis_series_cython.pyx b/src/sage/modular/modform/eis_series_cython.pyx index c22f2296eed..c29fef9cef7 100644 --- a/src/sage/modular/modform/eis_series_cython.pyx +++ b/src/sage/modular/modform/eis_series_cython.pyx @@ -6,8 +6,6 @@ from cysignals.memory cimport check_allocarray, sig_free from cysignals.signals cimport sig_check from sage.arith.misc import primes, bernoulli -from sage.rings.rational_field import QQ -from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.integer cimport Integer from sage.rings.fast_arith cimport prime_range @@ -95,7 +93,7 @@ cpdef Ek_ZZ(int k, int prec=10): while True: continue_flag = 0 # do the first p-1 - for i from 0 < i < p: + for i in range(1, p): ind += p if (ind >= prec): continue_flag = 1 @@ -165,7 +163,7 @@ cpdef eisenstein_series_poly(int k, int prec = 10) : cdef int i cdef Fmpz_poly res = Fmpz_poly.__new__(Fmpz_poly) - if k%2 or k < 2: + if k % 2 or k < 2: raise ValueError("k (=%s) must be an even positive integer" % k) if prec < 0: raise ValueError("prec (=%s) must be an even nonnegative integer" % prec) @@ -217,7 +215,7 @@ cpdef eisenstein_series_poly(int k, int prec = 10) : mpz_clear(last_m1) fmpz_poly_set_coeff_mpz(res.poly, prec-1, val[prec-1]) - for i from 1 <= i < prec - 1 : + for i in range(1, prec - 1): fmpz_poly_set_coeff_mpz(res.poly, i, val[i]) fmpz_poly_scalar_mul_mpz(res.poly, res.poly, (<Integer>(a0.denominator())).value) diff --git a/src/sage/modular/modform/eisenstein_submodule.py b/src/sage/modular/modform/eisenstein_submodule.py index aced6a69aca..fd1731574fa 100644 --- a/src/sage/modular/modform/eisenstein_submodule.py +++ b/src/sage/modular/modform/eisenstein_submodule.py @@ -8,10 +8,12 @@ from sage.categories.objects import Objects from sage.matrix.constructor import Matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer -from sage.rings.number_field.number_field import CyclotomicField from sage.structure.sequence import Sequence +lazy_import('sage.rings.number_field.number_field', 'CyclotomicField') + from . import eis_series from . import element from . import submodule @@ -29,7 +31,8 @@ def __init__(self, ambient_space): sage: E = ModularForms(23,4).eisenstein_subspace() # indirect doctest sage: E - Eisenstein subspace of dimension 2 of Modular Forms space of dimension 7 for Congruence Subgroup Gamma0(23) of weight 4 over Rational Field + Eisenstein subspace of dimension 2 of Modular Forms space of dimension 7 + for Congruence Subgroup Gamma0(23) of weight 4 over Rational Field sage: E == loads(dumps(E)) True """ @@ -101,10 +104,13 @@ def modular_symbols(self, sign=0): sage: eps = DirichletGroup(13).0 sage: E = EisensteinForms(eps^2, 2) sage: E.modular_symbols() - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 and level 13, weight 2, character [zeta6], sign 0, over Cyclotomic Field of order 6 and degree 2 + Modular Symbols subspace of dimension 2 of Modular Symbols space of + dimension 4 and level 13, weight 2, character [zeta6], sign 0, + over Cyclotomic Field of order 6 and degree 2 sage: E = EisensteinForms(eps, 1); E - Eisenstein subspace of dimension 1 of Modular Forms space of character [zeta12] and weight 1 over Cyclotomic Field of order 12 and degree 4 + Eisenstein subspace of dimension 1 of Modular Forms space of character + [zeta12] and weight 1 over Cyclotomic Field of order 12 and degree 4 sage: E.modular_symbols() Traceback (most recent call last): ... @@ -127,11 +133,13 @@ def parameters(self): EXAMPLES:: sage: ModularForms(24,2).eisenstein_submodule().parameters() - [(Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, 2), - ... - Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, 24)] + [(Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, + Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, 2), + ... + Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, 24)] sage: EisensteinForms(12,6).parameters()[-1] - (Dirichlet character modulo 12 of conductor 1 mapping 7 |--> 1, 5 |--> 1, Dirichlet character modulo 12 of conductor 1 mapping 7 |--> 1, 5 |--> 1, 12) + (Dirichlet character modulo 12 of conductor 1 mapping 7 |--> 1, 5 |--> 1, + Dirichlet character modulo 12 of conductor 1 mapping 7 |--> 1, 5 |--> 1, 12) sage: pars = ModularForms(DirichletGroup(24).0,3).eisenstein_submodule().parameters() sage: [(x[0].values_on_gens(),x[1].values_on_gens(),x[2]) for x in pars] @@ -144,7 +152,14 @@ def parameters(self): ((-1, 1, 1), (1, 1, 1), 3), ((-1, 1, 1), (1, 1, 1), 6)] sage: EisensteinForms(DirichletGroup(24).0,1).parameters() - [(Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 1), (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 2), (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 3), (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 6)] + [(Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, + Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 1), + (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, + Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 2), + (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, + Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 3), + (Dirichlet character modulo 24 of conductor 1 mapping 7 |--> 1, 13 |--> 1, 17 |--> 1, + Dirichlet character modulo 24 of conductor 4 mapping 7 |--> -1, 13 |--> 1, 17 |--> 1, 6)] """ char = self._parameters_character() if char is None: @@ -159,7 +174,8 @@ def new_submodule(self, p=None): EXAMPLES:: sage: e = EisensteinForms(Gamma0(225), 2).new_submodule(); e - Modular Forms subspace of dimension 3 of Modular Forms space of dimension 42 for Congruence Subgroup Gamma0(225) of weight 2 over Rational Field + Modular Forms subspace of dimension 3 of Modular Forms space of dimension 42 + for Congruence Subgroup Gamma0(225) of weight 2 over Rational Field sage: e.basis() [ q + O(q^6), @@ -190,7 +206,8 @@ def change_ring(self, base_ring): EXAMPLES:: sage: E = EisensteinForms(12,2) ; E - Eisenstein subspace of dimension 5 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(12) of weight 2 over Rational Field + Eisenstein subspace of dimension 5 of Modular Forms space of dimension 5 + for Congruence Subgroup Gamma0(12) of weight 2 over Rational Field sage: E.basis() [ 1 + O(q^6), @@ -200,7 +217,8 @@ def change_ring(self, base_ring): q^4 + O(q^6) ] sage: E.change_ring(GF(5)) - Eisenstein subspace of dimension 5 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(12) of weight 2 over Finite Field of size 5 + Eisenstein subspace of dimension 5 of Modular Forms space of dimension 5 + for Congruence Subgroup Gamma0(12) of weight 2 over Finite Field of size 5 sage: E.change_ring(GF(5)).basis() [ 1 + O(q^6), @@ -233,7 +251,8 @@ def eisenstein_series(self): ] sage: EisensteinForms(1,24).eisenstein_series() [ - 236364091/131040 + q + 8388609*q^2 + 94143178828*q^3 + 70368752566273*q^4 + 11920928955078126*q^5 + O(q^6) + 236364091/131040 + q + 8388609*q^2 + 94143178828*q^3 + + 70368752566273*q^4 + 11920928955078126*q^5 + O(q^6) ] sage: EisensteinForms(5,4).eisenstein_series() [ @@ -259,7 +278,8 @@ def eisenstein_series(self): sage: eps = DirichletGroup(13).0^2 sage: ModularForms(eps,2).eisenstein_series() [ - -7/13*zeta6 - 11/13 + q + (2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 + (6*zeta6 - 3)*q^4 - 4*q^5 + O(q^6), + -7/13*zeta6 - 11/13 + q + (2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 + + (6*zeta6 - 3)*q^4 - 4*q^5 + O(q^6), q + (zeta6 + 2)*q^2 + (-zeta6 + 3)*q^3 + (3*zeta6 + 3)*q^4 + 4*q^5 + O(q^6) ] @@ -271,7 +291,8 @@ def eisenstein_series(self): sage: M = ModularForms(DirichletGroup(13).0, 1) sage: M.eisenstein_series() [ - -1/13*zeta12^3 + 6/13*zeta12^2 + 4/13*zeta12 + 2/13 + q + (zeta12 + 1)*q^2 + zeta12^2*q^3 + (zeta12^2 + zeta12 + 1)*q^4 + (-zeta12^3 + 1)*q^5 + O(q^6) + -1/13*zeta12^3 + 6/13*zeta12^2 + 4/13*zeta12 + 2/13 + q + (zeta12 + 1)*q^2 + + zeta12^2*q^3 + (zeta12^2 + zeta12 + 1)*q^4 + (-zeta12^3 + 1)*q^5 + O(q^6) ] sage: M = ModularForms(GammaH(15, [4]), 4) @@ -322,9 +343,9 @@ def _compute_q_expansion_basis(self, prec=None, new=False): O(q^6)] sage: EisensteinForms(22,4)._compute_q_expansion_basis(15) [1 + O(q^15), - q + 28*q^3 - 8*q^4 + 126*q^5 + 344*q^7 - 72*q^8 + 757*q^9 - 224*q^12 + 2198*q^13 + O(q^15), - q^2 + 9*q^4 + 28*q^6 + 73*q^8 + 126*q^10 + 252*q^12 + 344*q^14 + O(q^15), - q^11 + O(q^15)] + q + 28*q^3 - 8*q^4 + 126*q^5 + 344*q^7 - 72*q^8 + 757*q^9 - 224*q^12 + 2198*q^13 + O(q^15), + q^2 + 9*q^4 + 28*q^6 + 73*q^8 + 126*q^10 + 252*q^12 + 344*q^14 + O(q^15), + q^11 + O(q^15)] """ if prec is None: prec = self.prec() @@ -543,7 +564,8 @@ class EisensteinSubmodule_eps(EisensteinSubmodule_params): sage: M.eisenstein_series() [ - -1/3*zeta6 - 1/3 + q + (2*zeta6 - 1)*q^2 + q^3 + (-2*zeta6 - 1)*q^4 + (-5*zeta6 + 1)*q^5 + O(q^6), + -1/3*zeta6 - 1/3 + q + (2*zeta6 - 1)*q^2 + q^3 + + (-2*zeta6 - 1)*q^4 + (-5*zeta6 + 1)*q^5 + O(q^6), -1/3*zeta6 - 1/3 + q^3 + O(q^6), q + (-2*zeta6 + 1)*q^2 + (-2*zeta6 - 1)*q^4 + (5*zeta6 - 1)*q^5 + O(q^6), q + (zeta6 + 1)*q^2 + 3*q^3 + (zeta6 + 2)*q^4 + (-zeta6 + 5)*q^5 + O(q^6), @@ -590,8 +612,8 @@ def cyclotomic_restriction(L,K): EXAMPLES:: - sage: L = CyclotomicField(12) ; N = CyclotomicField(33) ; M = CyclotomicField(132) - sage: z, n = sage.modular.modform.eisenstein_submodule.cyclotomic_restriction(L,N) + sage: L = CyclotomicField(12); N = CyclotomicField(33); M = CyclotomicField(132) + sage: z, n = sage.modular.modform.eisenstein_submodule.cyclotomic_restriction(L, N) sage: n 2 @@ -600,11 +622,11 @@ def cyclotomic_restriction(L,K): sage: z(L.0)(M.0) zeta132^11 - sage: z(L.0^3-L.0+1) + sage: z(L.0^3 - L.0 + 1) (zeta33^19 + zeta33^8)*x + 1 - sage: z(L.0^3-L.0+1)(M.0) + sage: z(L.0^3 - L.0 + 1)(M.0) zeta132^33 - zeta132^11 + 1 - sage: z(L.0^3-L.0+1)(M.0) - M(L.0^3-L.0+1) + sage: z(L.0^3 - L.0 + 1)(M.0) - M(L.0^3 - L.0 + 1) 0 """ if not L.has_coerce_map_from(K): @@ -687,7 +709,7 @@ def z(a): EXAMPLES:: - sage: L = CyclotomicField(121) ; K = CyclotomicField(11) + sage: L = CyclotomicField(121); K = CyclotomicField(11) sage: z = sage.modular.modform.eisenstein_submodule.cyclotomic_restriction_tower(L,K) sage: z(L.0) x diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index a2ac0b1d1fa..6d10fdf47c3 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -35,10 +35,10 @@ from sage.arith.functions import lcm from sage.arith.misc import divisors, moebius, sigma, factor, crt from sage.arith.srange import xsrange -from sage.combinat.integer_vector_weighted import WeightedIntegerVectors from sage.matrix.constructor import Matrix from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.modular.dirichlet import DirichletGroup @@ -51,13 +51,15 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.morphism import RingHomomorphism -from sage.rings.number_field.number_field_morphisms import NumberFieldEmbedding from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RealField from sage.structure.element import coercion_model, ModuleElement, Element from sage.structure.richcmp import richcmp, op_NE, op_EQ +lazy_import('sage.combinat.integer_vector_weighted', 'WeightedIntegerVectors') +lazy_import('sage.rings.number_field.number_field_morphisms', 'NumberFieldEmbedding') + import sage.modular.hecke.element as element from . import defaults @@ -174,15 +176,17 @@ def level(self): """ return self.parent().level() - def is_homogeneous(self): + def is_homogeneous(self) -> bool: """ - Return true. For compatibility with elements of a graded modular forms ring. + Return ``True``. + + For compatibility with elements of a graded modular forms ring. An alias of this method is ``is_modular_form``. .. SEEALSO:: - :meth: `sage.modular.modform.element.GradedModularFormElement.is_homogeneous` + :meth:`sage.modular.modform.element.GradedModularFormElement.is_homogeneous` EXAMPLES:: @@ -190,11 +194,12 @@ def is_homogeneous(self): True """ return True + is_modular_form = is_homogeneous # alias def _repr_(self): """ - Return the string representation of self. + Return the string representation of ``self``. EXAMPLES:: @@ -1071,7 +1076,7 @@ def symsquare_lseries(self, chi=None, embedding=0, prec=53): sage: F = Newforms(1,12)[0] sage: chi = DirichletGroup(7).0 - sage: abs(F.symsquare_lseries(chi).check_functional_equation()) < 1e-5 + sage: abs(F.symsquare_lseries(chi).check_functional_equation()) < 1e-5 # long time True AUTHORS: @@ -2301,6 +2306,16 @@ def minimal_twist(self, p=None): EXAMPLES:: + sage: f = Newforms(121, 2)[3] + sage: g, chi = f.minimal_twist() + sage: g + q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6) + sage: chi + Dirichlet character modulo 11 of conductor 11 mapping 2 |--> -1 + sage: f.twist(chi, level=11) == g + True + + sage: # long time sage: f = Newforms(575, 2, names='a')[4] sage: g, chi = f.minimal_twist(5) sage: g @@ -2724,14 +2739,14 @@ def __init__(self, parent, E): EXAMPLES:: - sage: E = EllipticCurve('5077a') + sage: E = EllipticCurve('389a') sage: f = E.modular_form() sage: f - q - 2*q^2 - 3*q^3 + 2*q^4 - 4*q^5 + O(q^6) + q - 2*q^2 - 2*q^3 + 2*q^4 - 3*q^5 + O(q^6) sage: f.q_expansion(10) - q - 2*q^2 - 3*q^3 + 2*q^4 - 4*q^5 + 6*q^6 - 4*q^7 + 6*q^9 + O(q^10) + q - 2*q^2 - 2*q^3 + 2*q^4 - 3*q^5 + 4*q^6 - 5*q^7 + q^9 + O(q^10) sage: f.parent() - Modular Forms space of dimension 423 for Congruence Subgroup Gamma0(5077) of weight 2 over Rational Field + Modular Forms space of dimension 33 for Congruence Subgroup Gamma0(389) of weight 2 over Rational Field sage: E = EllipticCurve('37a') sage: f = E.modular_form() ; f diff --git a/src/sage/modular/modform/half_integral.py b/src/sage/modular/modform/half_integral.py index 432b4318046..eda22b15916 100644 --- a/src/sage/modular/modform/half_integral.py +++ b/src/sage/modular/modform/half_integral.py @@ -123,18 +123,18 @@ def half_integral_weight_modform_basis(chi, k, prec): psi = chi.parent()(DirichletGroup(4, chi.base_ring()).gen()) eps = chi*psi**((k+1) // 2) eps = eps.minimize_base_ring() - M = constructor.ModularForms(eps, (k+1)//2) - C = M.cuspidal_subspace() - B = C.basis() + M = constructor.ModularForms(eps, (k+1)//2) + C = M.cuspidal_subspace() + B = C.basis() # This computation of S below -- of course --dominates the whole function. S = [f.q_expansion(prec) for f in B] - T2 = theta2_qexp(prec) - T3 = theta_qexp(prec) - n = len(S) - MS = MatrixSpace(M.base_ring(), 2*n, prec) - A = copy(MS.zero_matrix()) + T2 = theta2_qexp(prec) + T3 = theta_qexp(prec) + n = len(S) + MS = MatrixSpace(M.base_ring(), 2*n, prec) + A = copy(MS.zero_matrix()) for i in range(n): T2f = T2*S[i] diff --git a/src/sage/modular/modform/hecke_operator_on_qexp.py b/src/sage/modular/modform/hecke_operator_on_qexp.py index 8601c9fd51e..36e092d8200 100644 --- a/src/sage/modular/modform/hecke_operator_on_qexp.py +++ b/src/sage/modular/modform/hecke_operator_on_qexp.py @@ -14,12 +14,14 @@ from sage.arith.misc import divisors, gcd from sage.matrix.constructor import matrix from sage.matrix.matrix_space import MatrixSpace +from sage.misc.lazy_import import lazy_import from sage.rings.infinity import Infinity from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import CyclotomicField from sage.rings.power_series_ring_element import is_PowerSeries +lazy_import('sage.rings.number_field.number_field', 'CyclotomicField') + from sage.modular.dirichlet import DirichletGroup, is_DirichletCharacter from .element import is_ModularFormElement diff --git a/src/sage/modular/modform/l_series_gross_zagier.py b/src/sage/modular/modform/l_series_gross_zagier.py index 1f3401c8506..28acdeeb978 100644 --- a/src/sage/modular/modform/l_series_gross_zagier.py +++ b/src/sage/modular/modform/l_series_gross_zagier.py @@ -48,7 +48,7 @@ def __init__(self, E, A, prec=53): ideal = A.ideal() K = A.gens()[0].parent() D = K.disc() - if not(K.degree() == 2 and D < 0): + if not (K.degree() == 2 and D < 0): raise ValueError("A is not an ideal class in an" " imaginary quadratic field") Q = ideal.quadratic_form().reduced_form() diff --git a/src/sage/modular/modform/l_series_gross_zagier_coeffs.pyx b/src/sage/modular/modform/l_series_gross_zagier_coeffs.pyx index 3246146c9a0..f91a3e256f0 100644 --- a/src/sage/modular/modform/l_series_gross_zagier_coeffs.pyx +++ b/src/sage/modular/modform/l_series_gross_zagier_coeffs.pyx @@ -68,13 +68,12 @@ def bqf_theta_series(Q, long bound, var=None): cdef long a, b, c a, b, c = Q cdef long* terms = bqf_theta_series_c(NULL, bound, a, b, c) - L = [terms[i] for i from 0 <= i <= bound] + L = [terms[i] for i in range(bound + 1)] sig_free(terms) return to_series(L, var) cdef long* bqf_theta_series_c(long* terms, long bound, long a, long b, long c) except NULL: - cdef long i cdef long x, y, yD cdef long xmax, ymin, ymax cdef double sqrt_yD @@ -86,13 +85,13 @@ cdef long* bqf_theta_series_c(long* terms, long bound, long a, long b, long c) e terms = <long*>check_calloc(1 + bound, sizeof(long)) sig_on() - for x from -xmax <= x <= xmax: + for x in range(-xmax, xmax + 1): yD = b * b * x * x - 4 * c * (a * x * x - bound) if yD > 0: sqrt_yD = sqrt(yD) ymin = <long>ceil((-b * x - sqrt_yD) / (2 * c)) ymax = <long>floor((-b * x + sqrt_yD) / (2 * c)) - for y from ymin <= y <= ymax: + for y in range(ymin, ymax + 1): terms[a * x * x + b * x * y + c * y * y] += 1 sig_off() return terms @@ -162,7 +161,7 @@ def gross_zagier_L_series(an_list, Q, long N, long u, var=None): i += 1 sig_on() memcpy(terms, con_terms, sizeof(long) * bound) # m = 1 - for m from 2 <= m <= <long>sqrt(bound): + for m in range(2, <long>sqrt(bound) + 1): if arith.c_gcd_longlong(D * N, m) == 1: me = m * kronecker_symbol(D, m) j = 0 diff --git a/src/sage/modular/modform/numerical.py b/src/sage/modular/modform/numerical.py index 1f7e8decd55..c13ebcbb77d 100644 --- a/src/sage/modular/modform/numerical.py +++ b/src/sage/modular/modform/numerical.py @@ -19,7 +19,7 @@ from sage.misc.prandom import randint from sage.modular.arithgroup.all import Gamma0 from sage.modular.modsym.all import ModularSymbols -from sage.modules.all import vector +from sage.modules.free_module_element import free_module_element as vector from sage.rings.complex_double import CDF from sage.rings.integer import Integer from sage.rings.rational_field import QQ @@ -104,7 +104,7 @@ def __init__(self, group, weight=2, eps=1e-20, """ if isinstance(group, (int, Integer)): group = Gamma0(Integer(group)) - self._group = group + self._group = group self._weight = Integer(weight) self._tp = tp if self._weight < 2: @@ -287,8 +287,6 @@ def _easy_vector(self): if E.nrows() == 0: return x - - def best_row(M): """ Find the best row among rows of M, i.e. the row diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index 3a56864da97..90e149340e4 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -803,7 +803,6 @@ def generators(self, maxweight=8, prec=10, start_gens=[], start_weight=2): return ret - def gen_forms(self, maxweight=8, start_gens=[], start_weight=2): r""" Return a list of modular forms generating this ring (as an algebra over @@ -1061,7 +1060,7 @@ def cuspidal_ideal_generators(self, maxweight=8, prec=None): # we may need to increase the precision of the cached cusp # generators - G = [] + G = [] for j,f,F in self.__cached_cusp_gens: if f.prec() >= working_prec: f = F.qexp(working_prec).change_ring(self.base_ring()) @@ -1070,9 +1069,8 @@ def cuspidal_ideal_generators(self, maxweight=8, prec=None): k = 2 G = [] - while k <= maxweight: - t = verbose("Looking for cusp generators in weight %s" % k) + t = verbose(f"Looking for cusp generators in weight {k}") kprec = self.modular_forms_of_weight(k).sturm_bound() diff --git a/src/sage/modular/modform/vm_basis.py b/src/sage/modular/modform/vm_basis.py index 4ac4f8c36a0..559c36828e9 100644 --- a/src/sage/modular/modform/vm_basis.py +++ b/src/sage/modular/modform/vm_basis.py @@ -200,21 +200,21 @@ def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): Fprod._unsafe_mutate_truncate(prec) Dprod._unsafe_mutate_truncate(prec) - - P = PowerSeriesRing(ZZ,var) - if cusp_only : + P = PowerSeriesRing(ZZ, var) + if cusp_only: for i in range(1,n+1) : for j in range(1, i) : ls[j] = ls[j] - ls[j][i]*ls[i] return Sequence([P(l.list()).add_bigoh(prec) for l in ls[1:]],cr=True) else : - for i in range(1,n+1) : - for j in range(i) : + for i in range(1,n+1): + for j in range(i): ls[j] = ls[j] - ls[j][i]*ls[i] return Sequence([P(l.list()).add_bigoh(prec) for l in ls], cr=True) + def _delta_poly(prec=10): """ Return the q-expansion of Delta as a FLINT polynomial. Used internally by diff --git a/src/sage/modular/modform_hecketriangle/__init__.py b/src/sage/modular/modform_hecketriangle/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/modform_hecketriangle/abstract_ring.py b/src/sage/modular/modform_hecketriangle/abstract_ring.py index 0ff086c0a60..f2b0e77d920 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_ring.py +++ b/src/sage/modular/modform_hecketriangle/abstract_ring.py @@ -7,14 +7,14 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann <jjermann2@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.algebras.free_algebra import FreeAlgebra from sage.misc.cachefunc import cached_method @@ -79,27 +79,27 @@ def __init__(self, group, base_ring, red_hom, n): False """ - #from graded_ring import canonical_parameters - #(group, base_ring, red_hom, n) = canonical_parameters(group, base_ring, red_hom, n) + # from graded_ring import canonical_parameters + # (group, base_ring, red_hom, n) = canonical_parameters(group, base_ring, red_hom, n) - #if (not group.is_arithmetic() and base_ring.characteristic()>0): + # if (not group.is_arithmetic() and base_ring.characteristic()>0): # raise NotImplementedError - #if (base_ring.characteristic().divides(2*group.n()*(group.n()-2))): + # if (base_ring.characteristic().divides(2*group.n()*(group.n()-2))): # raise NotImplementedError if (base_ring.characteristic() > 0): raise NotImplementedError("only characteristic 0 is supported") - self._group = group - self._red_hom = red_hom - self._base_ring = base_ring - self._coeff_ring = FractionField(PolynomialRing(base_ring,'d')) - self._pol_ring = PolynomialRing(base_ring,'x,y,z,d') - self._rat_field = FractionField(self._pol_ring) + self._group = group + self._red_hom = red_hom + self._base_ring = base_ring + self._coeff_ring = FractionField(PolynomialRing(base_ring,'d')) + self._pol_ring = PolynomialRing(base_ring,'x,y,z,d') + self._rat_field = FractionField(self._pol_ring) # default values - self._weight = None - self._ep = None - self._analytic_type = self.AT(["quasi", "mero"]) + self._weight = None + self._ep = None + self._analytic_type = self.AT(["quasi", "mero"]) self.default_prec(10) self.disp_prec(5) @@ -258,7 +258,7 @@ def _an_element_(self): return self(self.Delta()) - def default_prec(self, prec = None): + def default_prec(self, prec=None): r""" Set the default precision ``prec`` for the Fourier expansion. If ``prec=None`` (default) then the current default precision is returned instead. @@ -295,7 +295,7 @@ def default_prec(self, prec = None): else: return self._prec - def disp_prec(self, prec = None): + def disp_prec(self, prec=None): r""" Set the maximal display precision to ``prec``. If ``prec="max"`` the precision is set to the default precision. @@ -646,7 +646,7 @@ def rat_field(self): return self._rat_field - def get_d(self, fix_d = False, d_num_prec = None): + def get_d(self, fix_d=False, d_num_prec=None): r""" Return the parameter ``d`` of self either as a formal parameter or as a numerical approximation with the specified @@ -715,7 +715,7 @@ def get_d(self, fix_d = False, d_num_prec = None): return d - def get_q(self, prec = None, fix_d = False, d_num_prec = None): + def get_q(self, prec=None, fix_d=False, d_num_prec=None): r""" Return the generator of the power series of the Fourier expansion of ``self``. @@ -766,7 +766,7 @@ def get_q(self, prec = None, fix_d = False, d_num_prec = None): prec = self.default_prec() base_ring = d.parent() - return PowerSeriesRing(FractionField(base_ring), 'q', default_prec = prec).gen() + return PowerSeriesRing(FractionField(base_ring), 'q', default_prec=prec).gen() @cached_method def diff_alg(self): @@ -816,11 +816,11 @@ def _derivative_op(self): (X,Y,Z,dX,dY,dZ) = self.diff_alg().gens() if (self.hecke_n() == infinity): - return (X*Z-X*Y) * dX\ + return (X*Z-X*Y) * dX\ + ZZ(1)/ZZ(2) * (Y*Z-X) * dY\ + ZZ(1)/ZZ(4) * (Z**2-X) * dZ else: - return 1/self._group.n() * (X*Z-Y) * dX\ + return 1/self._group.n() * (X*Z-Y) * dX\ + ZZ(1)/ZZ(2) * (Y*Z-X**(self._group.n()-1)) * dY\ + (self._group.n()-2) / (4*self._group.n()) * (Z**2-X**(self._group.n()-2)) * dZ @@ -1039,7 +1039,7 @@ def homogeneous_part(self, k, ep): QuasiMeromorphicModularForms(n=7, k=2, ep=-1) over Integer Ring """ - return self.reduce_type(degree = (k,ep)) + return self.reduce_type(degree=(k,ep)) @cached_method def J_inv(self): @@ -1903,7 +1903,7 @@ def EisensteinSeries(self, k=None): if n == infinity: raise NotImplementedError("In the case n=infinity, the Eisenstein series is not unique and more parameters are required.") - if (k is None): + if k is None: try: if not self.is_homogeneous(): raise TypeError(None) @@ -1911,10 +1911,10 @@ def EisensteinSeries(self, k=None): if k < 0: raise TypeError(None) k = 2*ZZ(k/2) - #if self.ep() != ZZ(-1)**ZZ(k/2): + # if self.ep() != ZZ(-1)**ZZ(k/2): # raise TypeError except TypeError: - k = ZZ(0) + k = ZZ.zero() try: if k < 0: @@ -1926,33 +1926,33 @@ def EisensteinSeries(self, k=None): # The case n=infinity is special (there are 2 cusps) # Until we/I get confirmation what is what sort of Eisenstein series # this case is excluded... - if n == infinity: + if n == infinity: # We set the weight zero Eisenstein series to 1 pass - elif k == 0: + elif k == 0: return self.one() - elif k == 2: + elif k == 2: # This is a bit problematic, e.g. for n=infinity there is a # classical Eisenstein series of weight 2 return self.E2() - elif k == 4: + elif k == 4: return self.E4() - elif k == 6: + elif k == 6: return self.E6() # Basic variables ep = (-ZZ(1))**(k/2) extended_self = self.extend_type(["holo"], ring=True) # reduced_self is a classical ModularForms space - reduced_self = extended_self.reduce_type(["holo"], degree = (QQ(k), ep)) + reduced_self = extended_self.reduce_type(["holo"], degree=(QQ(k), ep)) if (n == infinity): - l2 = ZZ(0) - l1 = ZZ((k-(1-ep)) / ZZ(4)) + l2 = ZZ(0) + l1 = ZZ((k-(1-ep)) / ZZ(4)) else: num = ZZ((k-(1-ep)*n/(n-2)) * (n-2) / ZZ(4)) - l2 = num % n - l1 = ((num-l2)/n).numerator() + l2 = num % n + l1 = ((num-l2)/n).numerator() # If the space is one dimensional we return the normalized generator if l1 == 0: diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index efd12339000..110b0fe3be7 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -16,21 +16,23 @@ # **************************************************************************** from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.modules.free_module_element import is_FreeModuleElement from sage.modules.free_module_element import vector -from sage.rings.imaginary_unit import I from sage.rings.infinity import infinity from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.laurent_series_ring import is_LaurentSeriesRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.power_series_ring import is_PowerSeriesRing -from sage.rings.qqbar import AlgebraicField from sage.rings.rational_field import QQ from sage.structure.element import parent from .abstract_ring import FormsRing_abstract +lazy_import('sage.rings.imaginary_unit', 'I') +lazy_import('sage.rings.qqbar', 'QQbar') + class FormsSpace_abstract(FormsRing_abstract): r""" @@ -82,11 +84,11 @@ def __init__(self, group, base_ring, k, ep, n): sage: MF.is_homogeneous() True """ - #from space import canonical_parameters - #(group, base_ring, k, ep, n) = canonical_parameters(group, base_ring, k, ep, n) + # from space import canonical_parameters + # (group, base_ring, k, ep, n) = canonical_parameters(group, base_ring, k, ep, n) super().__init__(group=group, base_ring=base_ring, red_hom=True, n=n) - #self.register_embedding(self.hom(lambda f: f.parent().graded_ring()(f), codomain=self.graded_ring())) + # self.register_embedding(self.hom(lambda f: f.parent().graded_ring()(f), codomain=self.graded_ring())) self._weight = k self._ep = ep @@ -571,14 +573,13 @@ def element_from_coordinates(self, vec): sage: el.parent() == subspace True """ - if not self.module(): - raise ValueError("No free module defined for {}".format(self)) + raise ValueError(f"no free module defined for {self}") basis = self.gens() - assert(len(basis) == len(vec)) + assert len(basis) == len(vec) # vec = self.module()(self.module().linear_combination_of_basis(vec)) # this also handles the trivial case (dimension 0) - return self(sum([vec[k]*basis[k] for k in range(0, len(vec))])) + return self(sum([vec[k] * basis[k] for k in range(len(vec))])) def element_from_ambient_coordinates(self, vec): r""" @@ -757,7 +758,7 @@ def aut_factor(self, gamma, t): if (gamma.is_translation()): return ZZ(1) elif (gamma.is_reflection()): - return self._ep * (t/AlgebraicField()(I))**self._weight + return self._ep * (t/QQbar(I))**self._weight else: L = [v for v in gamma.word_S_T()[0]] aut_f = ZZ(1) @@ -835,7 +836,7 @@ def F_simple(self, order_1=ZZ(0)): return new_space(rat) - def Faber_pol(self, m, order_1=ZZ(0), fix_d = False, d_num_prec = None): + def Faber_pol(self, m, order_1=ZZ(0), fix_d=False, d_num_prec=None): r""" Return the ``m``'th Faber polynomial of ``self``. @@ -959,22 +960,22 @@ def Faber_pol(self, m, order_1=ZZ(0), fix_d = False, d_num_prec = None): if (m > order_inf): raise ValueError("Invalid basis index: m = {} > {} = order_inf!".format(m, order_inf)) - prec = 2*order_inf - m + 1 - d = self.get_d(fix_d=fix_d, d_num_prec=d_num_prec) - q = self.get_q(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec) + prec = 2*order_inf - m + 1 + d = self.get_d(fix_d=fix_d, d_num_prec=d_num_prec) + q = self.get_q(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec) - simple_qexp = self.F_simple(order_1=order_1).q_expansion(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec) - J_qexp = self.J_inv().q_expansion(prec=order_inf - m, fix_d=fix_d, d_num_prec=d_num_prec) + simple_qexp = self.F_simple(order_1=order_1).q_expansion(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec) + J_qexp = self.J_inv().q_expansion(prec=order_inf - m, fix_d=fix_d, d_num_prec=d_num_prec) # The precision could be infinity, otherwise we could do this: - #assert(temp_reminder.prec() == 1) + # assert temp_reminder.prec() == 1 temp_reminder = (1 / simple_qexp / q**(-m)).add_bigoh(1) - fab_pol = q.parent()([]) + fab_pol = q.parent()([]) while (len(temp_reminder.coefficients()) > 0): - temp_coeff = temp_reminder.coefficients()[0] - temp_exp = -temp_reminder.exponents()[0] - fab_pol += temp_coeff * (q/d)**temp_exp + temp_coeff = temp_reminder.coefficients()[0] + temp_exp = -temp_reminder.exponents()[0] + fab_pol += temp_coeff * (q/d)**temp_exp temp_reminder -= temp_coeff * (J_qexp/d)**temp_exp # The first term is zero only up to numerical errors, @@ -985,7 +986,7 @@ def Faber_pol(self, m, order_1=ZZ(0), fix_d = False, d_num_prec = None): return fab_pol.polynomial() # very similar to Faber_pol: faber_pol(q)=Faber_pol(d*q) - def faber_pol(self, m, order_1=ZZ(0), fix_d = False, d_num_prec = None): + def faber_pol(self, m, order_1=ZZ(0), fix_d=False, d_num_prec=None): r""" If ``n=infinity`` a non-trivial order of ``-1`` can be specified through the parameter ``order_1`` (default: 0). Otherwise it is ignored. @@ -1101,28 +1102,28 @@ def faber_pol(self, m, order_1=ZZ(0), fix_d = False, d_num_prec = None): if (m > order_inf): raise ValueError("Invalid basis index: m = {} > {} = order_inf!".format(m, order_inf)) - prec = 2*order_inf - m + 1 - d = self.get_d(fix_d=fix_d, d_num_prec=d_num_prec) - q = self.get_q(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec) + prec = 2*order_inf - m + 1 + d = self.get_d(fix_d=fix_d, d_num_prec=d_num_prec) + q = self.get_q(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec) - simple_qexp = self.F_simple(order_1=order_1).q_expansion(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec) - j_qexp = self.j_inv().q_expansion(prec=order_inf - m, fix_d=fix_d, d_num_prec=d_num_prec) + simple_qexp = self.F_simple(order_1=order_1).q_expansion(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec) + j_qexp = self.j_inv().q_expansion(prec=order_inf - m, fix_d=fix_d, d_num_prec=d_num_prec) # The precision could be infinity, otherwise we could do this: - #assert(temp_reminder.prec() == 1) + # assert temp_reminder.prec() == 1 temp_reminder = (1 / simple_qexp / q**(-m)).add_bigoh(1) - fab_pol = q.parent()([]) + fab_pol = q.parent()([]) while (len(temp_reminder.coefficients()) > 0): - temp_coeff = temp_reminder.coefficients()[0] - temp_exp = -temp_reminder.exponents()[0] - fab_pol += temp_coeff*q**temp_exp + temp_coeff = temp_reminder.coefficients()[0] + temp_exp = -temp_reminder.exponents()[0] + fab_pol += temp_coeff*q**temp_exp temp_reminder -= temp_coeff*j_qexp**temp_exp # The first term is zero only up to numerical errors, # so we manually have to remove it - if (not d.parent().is_exact()): - temp_reminder=temp_reminder.truncate_neg(-temp_exp+1) + if not d.parent().is_exact(): + temp_reminder = temp_reminder.truncate_neg(-temp_exp+1) return fab_pol.polynomial() @@ -1214,17 +1215,17 @@ def F_basis_pol(self, m, order_1=ZZ(0)): n = self._group.n() if (n ==infinity): - order_1 = ZZ(order_1) + order_1 = ZZ(order_1) order_inf = self._l1 - order_1 - finf_pol = d*(x-y**2) - jinv_pol = x/(x-y**2) - rat = finf_pol**order_inf * x**order_1 * y**(ZZ(1-self._ep)/ZZ(2)) * self.Faber_pol(m, order_1)(jinv_pol) + finf_pol = d*(x-y**2) + jinv_pol = x/(x-y**2) + rat = finf_pol**order_inf * x**order_1 * y**(ZZ(1-self._ep)/ZZ(2)) * self.Faber_pol(m, order_1)(jinv_pol) else: order_inf = self._l1 - order_1 = order_inf - finf_pol = d*(x**n-y**2) - jinv_pol = x**n/(x**n-y**2) - rat = finf_pol**order_inf * x**self._l2 * y**(ZZ(1-self._ep)/ZZ(2)) * self.Faber_pol(m)(jinv_pol) + order_1 = order_inf + finf_pol = d*(x**n-y**2) + jinv_pol = x**n/(x**n-y**2) + rat = finf_pol**order_inf * x**self._l2 * y**(ZZ(1-self._ep)/ZZ(2)) * self.Faber_pol(m)(jinv_pol) return rat @@ -1734,9 +1735,9 @@ def construct_form(self, laurent_series, order_1=ZZ(0), check=True, rationalize= if (laurent_series.prec() < order_inf + 1): raise ValueError("Insufficient precision: {} < {} = order_inf!".format(laurent_series.prec(), order_inf + 1)) - new_series = laurent_series.add_bigoh(order_inf + 1) - coefficients = new_series.coefficients() - exponents = new_series.exponents() + new_series = laurent_series.add_bigoh(order_inf + 1) + coefficients = new_series.coefficients() + exponents = new_series.exponents() if (len(coefficients) == 0): return self(0) @@ -1963,7 +1964,7 @@ def construct_quasi_form(self, laurent_series, order_1=ZZ(0), check=True, ration sage: el == constructed_el True - If a q_basis is available the construction uses a different algorithm which we also check:: + If a q_basis is available the construction uses a different algorithm which we also check:: sage: basis = QF.q_basis(min_exp=-1) sage: QF(qexp) == constructed_el @@ -2042,7 +2043,7 @@ def construct_quasi_form(self, laurent_series, order_1=ZZ(0), check=True, ration el = self(sum([b[k]*basis[k] for k in range(0, len(basis))])) else: - A = self._quasi_form_matrix(min_exp = min_exp, order_1=order_1) + A = self._quasi_form_matrix(min_exp=min_exp, order_1=order_1) row_size = A.dimensions()[0] if (prec < min_exp + row_size): @@ -2070,7 +2071,6 @@ def construct_quasi_form(self, laurent_series, order_1=ZZ(0), check=True, ration return el - @cached_method def q_basis(self, m=None, min_exp=0, order_1=ZZ(0)): r""" @@ -2165,7 +2165,7 @@ def q_basis(self, m=None, min_exp=0, order_1=ZZ(0)): if (m >= row_len + min_exp): raise ValueError("Index out of range: m={} >= {}=required_precision + min_exp".format(m, row_len + min_exp)) - A = self._quasi_form_matrix(min_exp = min_exp, order_1=order_1) + A = self._quasi_form_matrix(min_exp=min_exp, order_1=order_1) b = vector(self.coeff_ring(), row_len) b[m - min_exp] = 1 try: @@ -2181,7 +2181,7 @@ def q_basis(self, m=None, min_exp=0, order_1=ZZ(0)): return el - def rationalize_series(self, laurent_series, coeff_bound = 1e-10, denom_factor = ZZ(1)): + def rationalize_series(self, laurent_series, coeff_bound=1e-10, denom_factor=ZZ(1)): r""" Try to return a Laurent series with coefficients in ``self.coeff_ring()`` that matches the given Laurent series. @@ -2363,7 +2363,6 @@ def rationalize_coefficient(coeff, m): return laurent_series - # DEFAULT METHODS (should be overwritten in concrete classes) def _an_element_(self): diff --git a/src/sage/modular/modform_hecketriangle/analytic_type.py b/src/sage/modular/modform_hecketriangle/analytic_type.py index 3b3b691e181..0c809b3328c 100644 --- a/src/sage/modular/modform_hecketriangle/analytic_type.py +++ b/src/sage/modular/modform_hecketriangle/analytic_type.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Analytic types of modular forms @@ -11,14 +12,14 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann <jjermann2@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from sage.sets.set import Set from sage.combinat.posets.posets import Poset, FinitePoset @@ -68,7 +69,7 @@ class AnalyticTypeElement(LatticePosetElement): """ # We use the same constructor as LatticePosetElement - #def __init__(self, poset, element, vertex): + # def __init__(self, poset, element, vertex): # super().__init__(poset, element, vertex) def _repr_(self): @@ -170,6 +171,8 @@ def analytic_name(self): r""" Return a string representation of the analytic type. + EXAMPLES:: + sage: from sage.modular.modform_hecketriangle.analytic_type import AnalyticType sage: AT = AnalyticType() sage: AT(["quasi", "weak"]).analytic_name() @@ -328,9 +331,9 @@ class AnalyticType(FiniteLatticePoset): sage: el.analytic_type() quasi modular - Similarly the type of the ring element ``el2 = E4/Delta - E6/Delta`` is - ``weakly holomorphic`` despite the fact that the sum (``el2``) describes - a function which is holomorphic at infinity. + Similarly the type of the ring element ``el2 = E4/Delta - E6/Delta`` is + ``weakly holomorphic`` despite the fact that the sum (``el2``) describes + a function which is holomorphic at infinity:: sage: from sage.modular.modform_hecketriangle.graded_ring import WeakModularFormsRing sage: x,y,z,d = var("x,y,z,d") @@ -435,14 +438,14 @@ def __init__(self): zero """ # We (arbitrarily) choose to model by inclusion instead of restriction - P_elements = [ "cusp", "holo", "weak", "mero", "quasi"] + P_elements = ["cusp", "holo", "weak", "mero", "quasi"] P_relations = [["cusp", "holo"], ["holo", "weak"], ["weak", "mero"]] self._base_poset = Poset([P_elements, P_relations], cover_relations=True, linear_extension=True, facade=False) L = self._base_poset.order_ideals_lattice() - H = L._hasse_diagram.relabel({i:x for i,x in enumerate(L._elements)}, + H = L._hasse_diagram.relabel({i: x for i, x in enumerate(L._elements)}, inplace=False) FiniteLatticePoset.__init__(self, hasse_diagram=H, elements=L._elements, category=L.category(), @@ -525,19 +528,20 @@ def _element_constructor_(self, element): if isinstance(element, str): element = [element] if isinstance(element, (list, tuple)): - element = Set(self._base_poset.order_ideal([self._base_poset(s) for s in element])) + element = Set(self._base_poset.order_ideal([self._base_poset(s) + for s in element])) return super()._element_constructor_(element) - #res = self.first() - #for element in args: + # res = self.first() + # for element in args: # if type(element)==str: # element=[element] # if isinstance(element,list) or isinstance(element,tuple): # element = Set(self._base_poset.order_ideal([self._base_poset(s) for s in element])) # element = super()._element_constructor_(element) # res += element - #return res + # return res def base_poset(self): r""" diff --git a/src/sage/modular/modform_hecketriangle/constructor.py b/src/sage/modular/modform_hecketriangle/constructor.py index 7d182bb2147..9471394bea1 100644 --- a/src/sage/modular/modform_hecketriangle/constructor.py +++ b/src/sage/modular/modform_hecketriangle/constructor.py @@ -7,14 +7,14 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann <jjermann2@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -131,26 +131,26 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): analytic_type = AT(["quasi", "mero"]) - R = PolynomialRing(base_ring,'x,y,z,d') - F = FractionField(R) - (x,y,z,d) = R.gens() - R2 = PolynomialRing(PolynomialRing(base_ring, 'd'), 'x,y,z') - dhom = R.hom( R2.gens() + (R2.base().gen(),), R2) + R = PolynomialRing(base_ring,'x,y,z,d') + F = FractionField(R) + (x,y,z,d) = R.gens() + R2 = PolynomialRing(PolynomialRing(base_ring, 'd'), 'x,y,z') + dhom = R.hom( R2.gens() + (R2.base().gen(),), R2) - f = F(f) + f = F(f) - num = R(f.numerator()) - denom = R(f.denominator()) - ep_num = set([ZZ(1) - 2*(( sum([g.exponents()[0][m] for m in [1,2]]) )%2) for g in dhom(num).monomials()]) - ep_denom = set([ZZ(1) - 2*(( sum([g.exponents()[0][m] for m in [1,2]]) )%2) for g in dhom(denom).monomials()]) + num = R(f.numerator()) + denom = R(f.denominator()) + ep_num = set([ZZ.one() - 2*((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(num).monomials()]) + ep_denom = set([ZZ.one() - 2*((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(denom).monomials()]) if (n == infinity): - hom_num = R( num.subs(x=x**4, y=y**2, z=z**2) ) - hom_denom = R( denom.subs(x=x**4, y=y**2, z=z**2) ) + hom_num = R( num.subs(x=x**4, y=y**2, z=z**2) ) + hom_denom = R( denom.subs(x=x**4, y=y**2, z=z**2) ) else: - n = ZZ(n) - hom_num = R( num.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) ) - hom_denom = R( denom.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) ) + n = ZZ(n) + hom_num = R( num.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) ) + hom_denom = R( denom.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) ) # Determine whether the denominator of f is homogeneous if (len(ep_denom) == 1 and dhom(hom_denom).is_homogeneous()): @@ -159,20 +159,19 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): # elem, homo, k, ep, analytic_type return (False, False, None, None, None) - # Determine whether f is homogeneous if (len(ep_num) == 1 and dhom(hom_num).is_homogeneous()): - homo = True + homo = True if (n == infinity): weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) else: weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) / (n-2) - ep = ep_num.pop() / ep_denom.pop() + ep = ep_num.pop() / ep_denom.pop() # TODO: decompose f (resp. its degrees) into homogeneous parts else: - homo = False + homo = False weight = None - ep = None + ep = None # Note that we intentionally leave out the d-factor! if (n == infinity): diff --git a/src/sage/modular/modform_hecketriangle/element.py b/src/sage/modular/modform_hecketriangle/element.py index ae58a6ad08f..9cb02cb7cde 100644 --- a/src/sage/modular/modform_hecketriangle/element.py +++ b/src/sage/modular/modform_hecketriangle/element.py @@ -285,7 +285,7 @@ def lseries(self, num_prec=None, max_imaginary_part=0, max_asymp_coeffs=40): -23.9781792831... """ from sage.rings.integer_ring import ZZ - from sage.symbolic.all import pi + from sage.symbolic.constants import pi from sage.misc.functional import sqrt from sage.lfunctions.dokchitser import Dokchitser diff --git a/src/sage/modular/modform_hecketriangle/functors.py b/src/sage/modular/modform_hecketriangle/functors.py index 989f7b8e30e..f06615c823f 100644 --- a/src/sage/modular/modform_hecketriangle/functors.py +++ b/src/sage/modular/modform_hecketriangle/functors.py @@ -20,16 +20,17 @@ from sage.rings.rational_field import QQ from sage.rings.infinity import infinity -from sage.categories.functor import Functor -from sage.categories.pushout import ConstructionFunctor -from sage.categories.sets_cat import Sets -from sage.structure.parent import Parent +from sage.categories.functor import Functor +from sage.categories.pushout import ConstructionFunctor +from sage.categories.sets_cat import Sets +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups -from sage.categories.rings import Rings +from sage.categories.rings import Rings -from .constructor import FormsSpace, FormsRing -from .abstract_space import FormsSpace_abstract -from .subspace import SubSpaceForms +from .constructor import FormsSpace, FormsRing +from .abstract_space import FormsSpace_abstract +from .subspace import SubSpaceForms def _get_base_ring(ring, var_name="d"): @@ -77,16 +78,16 @@ def _get_base_ring(ring, var_name="d"): True """ - #from sage.rings.fraction_field import is_FractionField + # from sage.rings.fraction_field import is_FractionField from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.categories.pushout import FractionField as FractionFieldFunctor base_ring = ring - #if (is_FractionField(base_ring)): + # if (is_FractionField(base_ring)): # base_ring = base_ring.base() if (base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor()): base_ring = base_ring.construction()[1] - if (is_PolynomialRing(base_ring) and base_ring.ngens()==1 and base_ring.variable_name()==var_name): + if (is_PolynomialRing(base_ring) and base_ring.ngens() == 1 and base_ring.variable_name() == var_name): base_ring = base_ring.base() if (base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor()): base_ring = base_ring.construction()[1] @@ -325,13 +326,9 @@ def __eq__(self, other): sage: ss_functor1 == ss_functor2 False """ - - if (type(self) is type(other) and - self._ambient_space_functor == other._ambient_space_functor and - self._generators == other._generators): - return True - else: - return False + return (type(self) is type(other) and + self._ambient_space_functor == other._ambient_space_functor and + self._generators == other._generators) class FormsSpaceFunctor(ConstructionFunctor): @@ -514,15 +511,11 @@ def __eq__(self, other): sage: functor1 == functor2 False """ - - if (type(self) is type(other) and - self._group == other._group and - self._analytic_type == other._analytic_type and - self._k == other._k and - self._ep == other._ep): - return True - else: - return False + return (type(self) is type(other) and + self._group == other._group and + self._analytic_type == other._analytic_type and + self._k == other._k and + self._ep == other._ep) class FormsRingFunctor(ConstructionFunctor): @@ -703,17 +696,12 @@ def __eq__(self, other): sage: functor1 == functor2 False """ - - if (type(self) is type(other) and - self._group == other._group and - self._analytic_type == other._analytic_type and - self._red_hom == other._red_hom): - return True - else: - return False + return (type(self) is type(other) and + self._group == other._group and + self._analytic_type == other._analytic_type and + self._red_hom == other._red_hom) -from sage.structure.unique_representation import UniqueRepresentation class BaseFacade(Parent, UniqueRepresentation): r""" BaseFacade of a ring. @@ -754,11 +742,10 @@ def __init__(self, ring): sage: CC.has_coerce_map_from(BaseFacade(ZZ)) True """ - Parent.__init__(self, facade=ring, category=Rings()) self._ring = _get_base_ring(ring) # The BaseFacade(R) coerces/embeds into R, used in pushout - self.register_embedding(self.Hom(self._ring,Sets())(lambda x: x)) + self.register_embedding(self.Hom(self._ring, Sets())(lambda x: x)) def __repr__(self): r""" @@ -770,5 +757,4 @@ def __repr__(self): sage: BaseFacade(ZZ) BaseFacade(Integer Ring) """ - return "BaseFacade({})".format(self._ring) diff --git a/src/sage/modular/modform_hecketriangle/graded_ring.py b/src/sage/modular/modform_hecketriangle/graded_ring.py index 6da06db1b63..f7153493aac 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring.py @@ -6,15 +6,14 @@ - Jonas Jermann (2013): initial version """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann <jjermann2@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity @@ -64,7 +63,7 @@ class QuasiMeromorphicModularFormsRing(FormsRing_abstract, CommutativeAlgebra, U """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, red_hom = False, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, red_hom=False, n=None): r""" Return a (cached) instance with canonical parameters. @@ -119,6 +118,7 @@ def __init__(self, group, base_ring, red_hom, n): CommutativeAlgebra.__init__(self, base_ring=base_ring, category=CommutativeAlgebras(base_ring)) self._analytic_type = self.AT(["quasi", "mero"]) + class QuasiWeakModularFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRepresentation): r""" Graded ring of (Hecke) quasi weakly holomorphic modular forms @@ -126,7 +126,7 @@ class QuasiWeakModularFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRe """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, red_hom = False, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, red_hom=False, n=None): r""" Return a (cached) instance with canonical parameters. @@ -178,6 +178,7 @@ def __init__(self, group, base_ring, red_hom, n): CommutativeAlgebra.__init__(self, base_ring=base_ring, category=CommutativeAlgebras(base_ring)) self._analytic_type = self.AT(["quasi", "weak"]) + class QuasiModularFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRepresentation): r""" Graded ring of (Hecke) quasi modular forms @@ -185,7 +186,7 @@ class QuasiModularFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRepres """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, red_hom = False, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, red_hom=False, n=None): r""" Return a (cached) instance with canonical parameters. @@ -237,6 +238,7 @@ def __init__(self, group, base_ring, red_hom, n): CommutativeAlgebra.__init__(self, base_ring=base_ring, category=CommutativeAlgebras(base_ring)) self._analytic_type = self.AT(["quasi", "holo"]) + class QuasiCuspFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRepresentation): r""" Graded ring of (Hecke) quasi cusp forms @@ -244,7 +246,7 @@ class QuasiCuspFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRepresent """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, red_hom = False, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, red_hom=False, n=None): r""" Return a (cached) instance with canonical parameters. @@ -296,6 +298,7 @@ def __init__(self, group, base_ring, red_hom, n): CommutativeAlgebra.__init__(self, base_ring=base_ring, category=CommutativeAlgebras(base_ring)) self._analytic_type = self.AT(["quasi", "cusp"]) + class MeromorphicModularFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRepresentation): r""" Graded ring of (Hecke) meromorphic modular forms @@ -303,7 +306,7 @@ class MeromorphicModularFormsRing(FormsRing_abstract, CommutativeAlgebra, Unique """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, red_hom = False, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, red_hom=False, n=None): r""" Return a (cached) instance with canonical parameters. @@ -355,6 +358,7 @@ def __init__(self, group, base_ring, red_hom, n): CommutativeAlgebra.__init__(self, base_ring=base_ring, category=CommutativeAlgebras(base_ring)) self._analytic_type = self.AT(["mero"]) + class WeakModularFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRepresentation): r""" Graded ring of (Hecke) weakly holomorphic modular forms @@ -362,7 +366,7 @@ class WeakModularFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueReprese """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, red_hom = False, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, red_hom=False, n=None): r""" Return a (cached) instance with canonical parameters. @@ -414,6 +418,7 @@ def __init__(self, group, base_ring, red_hom, n): CommutativeAlgebra.__init__(self, base_ring=base_ring, category=CommutativeAlgebras(base_ring)) self._analytic_type = self.AT(["weak"]) + class ModularFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRepresentation): r""" Graded ring of (Hecke) modular forms @@ -421,7 +426,7 @@ class ModularFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRepresentat """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, red_hom = False, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, red_hom=False, n=None): r""" Return a (cached) instance with canonical parameters. @@ -472,6 +477,7 @@ def __init__(self, group, base_ring, red_hom, n): CommutativeAlgebra.__init__(self, base_ring=base_ring, category=CommutativeAlgebras(base_ring)) self._analytic_type = self.AT(["holo"]) + class CuspFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRepresentation): r""" Graded ring of (Hecke) cusp forms @@ -479,7 +485,7 @@ class CuspFormsRing(FormsRing_abstract, CommutativeAlgebra, UniqueRepresentation """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, red_hom = False, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, red_hom=False, n=None): r""" Return a (cached) instance with canonical parameters. diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index b6d01bf0c37..a2ef2a03b04 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -6,31 +6,33 @@ - Jonas Jermann (2013): initial version """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann <jjermann2@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.functions.log import exp from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane from sage.misc.cachefunc import cached_method from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.misc.lazy_import import lazy_import from sage.modules.free_module_element import vector from sage.rings.big_oh import O from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.laurent_series_ring_element import LaurentSeries -from sage.rings.number_field.number_field import QuadraticField from sage.structure.element import CommutativeAlgebraElement from sage.structure.parent_gens import localvars from sage.structure.richcmp import op_NE, op_EQ from sage.structure.unique_representation import UniqueRepresentation -from sage.symbolic.constants import pi + +lazy_import("sage.functions.log", "exp") +lazy_import("sage.rings.number_field.number_field", "QuadraticField") +lazy_import("sage.symbolic.constants", "pi") from .constructor import rational_type, FormsSpace, FormsRing from .series_constructor import MFSeriesConstructor @@ -194,15 +196,14 @@ def _rat_repr(self): sage: QuasiModularForms(n=infinity, k=10)(x*(x-y^2)*z)._rat_repr() '-E4*f_i^2*E2 + E4^2*E2' """ - - if (self.hecke_n() == infinity): + if self.hecke_n() == infinity: with localvars(self.parent()._pol_ring, "E4, f_i, E2, d"): pol_str = str(self._rat) else: with localvars(self.parent()._pol_ring, "f_rho, f_i, E2, d"): pol_str = str(self._rat) - return "{}".format(pol_str) + return pol_str def _qexp_repr(self): r""" @@ -426,10 +427,9 @@ def degree(self): sage: ModularForms(n=infinity).f_rho().degree() (0, 1) """ + return (self._weight, self._ep) - return (self._weight,self._ep) - - def is_modular(self): + def is_modular(self) -> bool: r""" Return whether ``self`` (resp. its homogeneous components) transform like modular forms. @@ -450,7 +450,6 @@ def is_modular(self): sage: QuasiModularForms(n=infinity).f_inf().is_modular() True """ - return not (self.AT("quasi") <= self._analytic_type) def is_weakly_holomorphic(self): @@ -642,7 +641,7 @@ def denominator(self): new_parent = self.parent().extend_type("holo", ring=True).reduce_type(["holo", "quasi"]) return new_parent(res).reduce() - def _add_(self,other): + def _add_(self, other): r""" Return the sum of ``self`` and ``other``. @@ -718,10 +717,9 @@ def _add_(self,other): sage: el.parent() ModularFormsRing(n=+Infinity) over Integer Ring """ + return self.parent()(self._rat + other._rat) - return self.parent()(self._rat+other._rat) - - def _sub_(self,other): + def _sub_(self, other): r""" Return the difference of ``self`` and ``other``. @@ -774,9 +772,8 @@ def _sub_(self,other): sage: el.parent() ModularFormsRing(n=+Infinity) over Integer Ring """ - - #reduce at the end? See example "sage: ((E4+E6)-E6).parent()" - return self.parent()(self._rat-other._rat) + # reduce at the end? See example "sage: ((E4+E6)-E6).parent()" + return self.parent()(self._rat - other._rat) def _neg_(self): r""" @@ -802,7 +799,7 @@ def _neg_(self): """ return self.parent()(-self._rat) - def _mul_(self,other): + def _mul_(self, other): r""" Return the product of ``self`` and ``other``. @@ -879,13 +876,12 @@ def _mul_(self,other): sage: el.parent() QuasiModularForms(n=+Infinity, k=8, ep=1) over Integer Ring """ - - res = self.parent().rat_field()(self._rat*other._rat) + res = self.parent().rat_field()(self._rat * other._rat) new_parent = self.parent().extend_type(ring=True) # The product of two homogeneous elements is homogeneous return new_parent(res).reduce() - def _div_(self,other): + def _div_(self, other): r""" Return the division of ``self`` by ``other``. @@ -965,8 +961,7 @@ def _div_(self,other): sage: el.parent() QuasiMeromorphicModularForms(n=+Infinity, k=0, ep=1) over Integer Ring """ - - res = self.parent().rat_field()(self._rat/other._rat) + res = self.parent().rat_field()(self._rat / other._rat) new_parent = self.parent().extend_type("mero", ring=True) # The division of two homogeneous elements is homogeneous return new_parent(res).reduce() @@ -1001,7 +996,7 @@ def sqrt(self): """ res = self._rat.sqrt() assert res.parent() is self.parent().rat_field() - #new_parent = self.parent().extend_type(ring=True) + # new_parent = self.parent().extend_type(ring=True) # The sqrt of a homogeneous element is homogeneous if it exists new_parent = self.parent().extend_type(ring=True) return new_parent(res).reduce() @@ -1094,20 +1089,19 @@ def diff_op(self, op, new_parent=None): sage: E2.diff_op(ran_op) E4*E2 + 1 """ - - (x,y,z,d) = self.parent().rat_field().gens() - (X,Y,Z,dX,dY,dZ) = self.parent().diff_alg().gens() + x, y, z, d = self.parent().rat_field().gens() + X, Y, Z, dX, dY, dZ = self.parent().diff_alg().gens() L = op.monomials() new_rat = 0 for mon in L: - mon_summand = self._rat - mon_summand = mon_summand.derivative(x,mon.degree(dX)) - mon_summand = mon_summand.derivative(y,mon.degree(dY)) - mon_summand = mon_summand.derivative(z,mon.degree(dZ)) + mon_summand = self._rat + mon_summand = mon_summand.derivative(x, mon.degree(dX)) + mon_summand = mon_summand.derivative(y, mon.degree(dY)) + mon_summand = mon_summand.derivative(z, mon.degree(dZ)) mon_summand *= x**(mon.degree(X)) mon_summand *= y**(mon.degree(Y)) mon_summand *= z**(mon.degree(Z)) - new_rat += op.monomial_coefficient(mon)*mon_summand + new_rat += op.monomial_coefficient(mon) * mon_summand res = self.parent().rat_field()(new_rat) if (new_parent is None): new_parent = self.parent().extend_type(["quasi", "mero"], ring=True) @@ -1346,12 +1340,12 @@ def order_at(self, tau=infinity): return infinity if (self.is_homogeneous() and self.is_modular()): - rat = self.parent().rat_field()(self._rat) - R = self.parent().pol_ring() + rat = self.parent().rat_field()(self._rat) + R = self.parent().pol_ring() numerator = R(rat.numerator()) - denom = R(rat.denominator()) - (x,y,z,d) = R.gens() - n = self.hecke_n() + denom = R(rat.denominator()) + x, y, z, d = R.gens() + n = self.hecke_n() if (tau == i): f_pol = y @@ -1378,37 +1372,37 @@ def order_at(self, tau=infinity): # Also numerator /= f_pol doesn't seem to return an element of R for non-exact rings... try: while (f_pol.divides(numerator)): - numerator = numerator.quo_rem(f_pol)[0] - #numerator /= f_pol - numerator = R(numerator) + numerator = numerator.quo_rem(f_pol)[0] + # numerator /= f_pol + numerator = R(numerator) order_f += 1 except TypeError: pass try: while (f_pol.divides(denom)): - denom = denom.quo_rem(f_pol)[0] - #denom /= f_pol - denom = R(denom) + denom = denom.quo_rem(f_pol)[0] + # denom /= f_pol + denom = R(denom) order_f -= 1 except TypeError: pass return order_f else: - if (tau != infinity): + if tau != infinity: raise NotImplementedError("Only the order at infinity is supported for non-homogeneous or quasi forms!") - num_val = prec_num_bound = 1 #(self.parent()._prec/ZZ(2)).ceil() - denom_val = prec_denom_bound = 1 #(self.parent()._prec/ZZ(2)).ceil() + num_val = prec_num_bound = 1 # (self.parent()._prec/ZZ(2)).ceil() + denom_val = prec_denom_bound = 1 # (self.parent()._prec/ZZ(2)).ceil() while (num_val >= prec_num_bound): - prec_num_bound *= 2 - num_val = self.numerator().q_expansion(prec=prec_num_bound, fix_prec=True).valuation() + prec_num_bound *= 2 + num_val = self.numerator().q_expansion(prec=prec_num_bound, fix_prec=True).valuation() while (denom_val >= prec_denom_bound): prec_denom_bound *= 2 denom_val = self.denominator().q_expansion(prec=prec_denom_bound, fix_prec=True).valuation() - return (num_val-denom_val) + return num_val - denom_val def as_ring_element(self): r""" @@ -1521,9 +1515,9 @@ def full_reduce(self): return self.reduced_parent()(self._rat) - #precision is actually accuracy, maybe add "real precision" meaning number of rel. coef + # precision is actually accuracy, maybe add "real precision" meaning number of rel. coef @cached_method - def _q_expansion_cached(self, prec, fix_d, subs_d, d_num_prec, fix_prec = False): + def _q_expansion_cached(self, prec, fix_d, subs_d, d_num_prec, fix_prec=False): """ Returns the Fourier expansion of self (cached). Don't call this function, instead use :meth:`q_expansion`. @@ -1563,16 +1557,18 @@ def _q_expansion_cached(self, prec, fix_d, subs_d, d_num_prec, fix_prec = False) X = SC.E4_ZZ().base_extend(formal_d.parent()) else: X = SC.f_rho_ZZ().base_extend(formal_d.parent()) - Y = SC.f_i_ZZ().base_extend(formal_d.parent()) + Y = SC.f_i_ZZ().base_extend(formal_d.parent()) if (self.parent().is_modular()): - qexp = self._rat.subs(x=X, y=Y, d=formal_d) + # z does not appear in self._rat but we need to specialize it for + # the evaluation to land in the correct parent + qexp = self._rat.subs(x=X, y=Y, z=0, d=formal_d) else: Z = SC.E2_ZZ().base_extend(formal_d.parent()) qexp = self._rat.subs(x=X, y=Y, z=Z, d=formal_d) qexp = (qexp + O(formal_q**prec)).parent()(qexp) - qexp = qexp(formal_q/formal_d) + qexp = qexp(formal_q / formal_d) cur_prec = qexp.prec() if (subs_d): @@ -1588,7 +1584,7 @@ def _q_expansion_cached(self, prec, fix_d, subs_d, d_num_prec, fix_prec = False) return qexp - def q_expansion(self, prec = None, fix_d = False, d_num_prec = None, fix_prec = False): + def q_expansion(self, prec=None, fix_d=False, d_num_prec=None, fix_prec=False): """ Returns the Fourier expansion of self. @@ -1692,7 +1688,7 @@ def q_expansion(self, prec = None, fix_d = False, d_num_prec = None, fix_prec = return self._q_expansion_cached(prec, fix_d, subs_d, d_num_prec, fix_prec) - def q_expansion_fixed_d(self, prec = None, d_num_prec = None, fix_prec = False): + def q_expansion_fixed_d(self, prec=None, d_num_prec=None, fix_prec=False): """ Returns the Fourier expansion of self. The numerical (or exact) value for ``d`` is substituted. @@ -1754,7 +1750,7 @@ def q_expansion_fixed_d(self, prec = None, d_num_prec = None, fix_prec = False): return self.q_expansion(prec, True, d_num_prec, fix_prec) - def q_expansion_vector(self, min_exp = None, max_exp = None, prec = None, **kwargs): + def q_expansion_vector(self, min_exp=None, max_exp=None, prec=None, **kwargs): r""" Return (part of) the Laurent series expansion of ``self`` as a vector. @@ -1818,14 +1814,14 @@ def q_expansion_vector(self, min_exp = None, max_exp = None, prec = None, **kwar qexp = self.q_expansion(prec=prec, **kwargs) - if (min_exp is None): + if min_exp is None: min_exp = qexp.valuation() else: min_exp = ZZ(min_exp) - return vector([qexp[m] for m in range(min_exp, max_exp +1)]) + return vector([qexp[m] for m in range(min_exp, max_exp + 1)]) - def evaluate(self, tau, prec = None, num_prec = None, check=False): + def evaluate(self, tau, prec=None, num_prec=None, check=False): r""" Try to return ``self`` evaluated at a point ``tau`` in the upper half plane, where ``self`` is interpreted @@ -2180,20 +2176,20 @@ def evaluate(self, tau, prec = None, num_prec = None, check=False): return q_exp.laurent_polynomial()(exp((2 * pi * i).n(num_prec) / self.group().lam() * w)) * aut_factor else: return q_exp.polynomial()(exp((2 * pi * i).n(num_prec) / self.group().lam() * w)) * aut_factor - elif (self._rat == z): + elif self._rat == z: E2 = self.parent().graded_ring().E2().reduce(force=True) (A, w) = self.group().get_FD(tau) aut_factor = E2.parent().aut_factor(A, w) E2_wvalue = E2.q_expansion_fixed_d(prec=prec, d_num_prec=num_prec).polynomial()(exp((2 * pi * i).n(num_prec) / self.group().lam() * w)) if (self.hecke_n() == infinity): - E2_cor_term = 4 * self.group().lam() / (2*pi*i).n(num_prec) * A.c() * (A.c()*w + A.d()) + E2_cor_term = 4 * self.group().lam() / (2 * pi * i).n(num_prec) * A.c() * (A.c() * w + A.d()) else: - E2_cor_term = 4 * self.group().lam() / (2*pi*i).n(num_prec) * self.hecke_n() / (self.hecke_n()-2) * A.c() * (A.c()*w + A.d()) - return E2_wvalue*aut_factor + E2_cor_term + E2_cor_term = 4 * self.group().lam() / (2 * pi * i).n(num_prec) * self.hecke_n() / (self.hecke_n() - 2) * A.c() * (A.c() * w + A.d()) + return E2_wvalue * aut_factor + E2_cor_term else: - f_i = self.parent().graded_ring().f_i() - E2 = self.parent().graded_ring().E2() - dval = self.parent().group().dvalue().n(num_prec) + f_i = self.parent().graded_ring().f_i() + E2 = self.parent().graded_ring().E2() + dval = self.parent().group().dvalue().n(num_prec) if (self.hecke_n() == infinity): E4 = self.parent().graded_ring().E4() return self._rat.subs(x=E4(tau), y=f_i(tau), z=E2(tau), d=dval) @@ -2201,7 +2197,7 @@ def evaluate(self, tau, prec = None, num_prec = None, check=False): f_rho = self.parent().graded_ring().f_rho() return self._rat.subs(x=f_rho(tau), y=f_i(tau), z=E2(tau), d=dval) - def __call__(self, tau, prec = None, num_prec = None, check=False): + def __call__(self, tau, prec=None, num_prec=None, check=False): r""" Try to return ``self`` evaluated at a point ``tau`` in the upper half plane, where ``self`` is interpreted diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index 090d1bfaf0f..7c3867923c9 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -17,13 +17,15 @@ # **************************************************************************** from sage.misc.latex import latex +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.rings.cc import CC -from sage.rings.qqbar import AA, QQbar + +lazy_import('sage.rings.qqbar', 'AA') from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane @@ -202,10 +204,10 @@ def _word_S_T_data(self): (((1, 1), (0, 1)), 1) """ res = [] - ID = self.parent().I()._matrix - T = self.parent().T()._matrix - S = self.parent().S()._matrix - M = self._matrix + ID = self.parent().I()._matrix + T = self.parent().T()._matrix + S = self.parent().S()._matrix + M = self._matrix lam = self.parent().lam() zero = ZZ.zero() one = ZZ.one() @@ -602,22 +604,22 @@ def continued_fraction(self): # emb = self.root_extension_embedding(QQbar) raise NotImplementedError - emb = self.root_extension_embedding(AA) - G = self.parent() - S = G.S() - TI = G.T().inverse() - lam = G.lam() + emb = self.root_extension_embedding(AA) + G = self.parent() + S = G.S() + TI = G.T().inverse() + lam = G.lam() - p = self.fixed_points()[0] + p = self.fixed_points()[0] - cf_dict = {} - L = [] + cf_dict = {} + L = [] cf_index = ZZ.zero() - one = ZZ.one() + one = ZZ.one() - while(p not in cf_dict): + while p not in cf_dict: cf_dict[p] = cf_index - if (p == infinity): + if p == infinity: # TODO: The choice of r doesn't matter? r = ZZ.zero() #elif self.is_elliptic(): @@ -765,22 +767,24 @@ def _primitive_block_decomposition_data(self): G = self.parent() zero = ZZ.zero() - one = ZZ.one() + one = ZZ.one() # The elliptic case (for this case we use a special notation): if self.is_elliptic(): if self.parent().n() == infinity: raise NotImplementedError - emb = self.root_extension_embedding(QQbar) - p = self.fixed_points()[0] - embp = emb(p) + from sage.rings.qqbar import QQbar + + emb = self.root_extension_embedding(QQbar) + p = self.fixed_points()[0] + embp = emb(p) embp.simplify() embp.exactify() (R, embw) = G.get_FD(embp) - w = R.inverse().acton(p) + w = R.inverse().acton(p) # we should have: embw == emb(w) - embw = emb(w) + embw = emb(w) embw.simplify() embw.exactify() @@ -807,7 +811,7 @@ def _primitive_block_decomposition_data(self): (preperiod, period) = self.continued_fraction() number_of_ones = [] - list_larger = [] + list_larger = [] ones = 0 for l in period: if l > 1: @@ -819,12 +823,12 @@ def _primitive_block_decomposition_data(self): number_of_ones.append(ones) initial_ones = number_of_ones.pop(0) - if len(list_larger) == 0: - list_v1 = [-ZZ(1)] - list_vlarger = [ initial_ones + 2 ] + if not list_larger: + list_v1 = [-ZZ(1)] + list_vlarger = [ initial_ones + 2 ] else: - list_v1 = [ v-2 for v in list_larger ] - list_vlarger = [ v+2 for v in number_of_ones ] + list_v1 = [ v-2 for v in list_larger ] + list_vlarger = [ v+2 for v in number_of_ones ] list_vlarger[-1] += initial_ones L = [] @@ -835,7 +839,7 @@ def _primitive_block_decomposition_data(self): L_len = len(L) k = 0 - while(k < L_len - 1): + while k < L_len - 1: if L[k][0] == L[k+1][0]: k_entry = L.pop(k+1) L[k][1] += k_entry[1] @@ -1331,8 +1335,8 @@ def primitive_power(self, method="cf"): warn("The case n=infinity here is not verified at all and probably wrong!") zero = ZZ.zero() - one = ZZ.one() - two = ZZ(2) + one = ZZ.one() + two = ZZ(2) if self.is_identity(): return zero @@ -1352,7 +1356,7 @@ def primitive_power(self, method="cf"): Uj = G.I() for j in range(1, G.n()): Uj *= U - if U_power == Uj: + if U_power == Uj: #L = [one, ZZ(j)] break elif U_power == -Uj: @@ -3223,26 +3227,26 @@ def slash(self, f, tau=None, k=None): INPUT: - ``f`` -- A function in ``tau`` (or an object for which - evaluation at ``self.acton(tau)`` makes sense. + evaluation at ``self.acton(tau)`` makes sense. - ``tau`` -- Where to evaluate the result. - This should be a valid argument for :meth:`acton`. + This should be a valid argument for :meth:`acton`. - If ``tau`` is a point of ``HyperbolicPlane()`` then - its coordinates in the upper half plane model are used. + If ``tau`` is a point of ``HyperbolicPlane()`` then + its coordinates in the upper half plane model are used. - Default: ``None`` in which case ``f`` has to be - a rational function / polynomial in one variable and - the generator of the polynomial ring is used for ``tau``. - That way ``slash`` acts on rational functions / polynomials. + Default: ``None`` in which case ``f`` has to be + a rational function / polynomial in one variable and + the generator of the polynomial ring is used for ``tau``. + That way ``slash`` acts on rational functions / polynomials. - ``k`` -- An even integer. - Default: ``None`` in which case ``f`` either - has to be a rational function / polynomial in one - variable (then -degree is used). - Or ``f`` needs to have a ``weight`` attribute which - is then used. + Default: ``None`` in which case ``f`` either + has to be a rational function / polynomial in one + variable (then -degree is used). + Or ``f`` needs to have a ``weight`` attribute which + is then used. EXAMPLES:: @@ -3321,4 +3325,5 @@ def as_hyperbolic_plane_isometry(self, model="UHP"): sage: el.as_hyperbolic_plane_isometry("KM").parent() Set of Morphisms from Hyperbolic plane in the Klein Disk Model to Hyperbolic plane in the Klein Disk Model in Category of hyperbolic models of Hyperbolic plane """ + from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane return HyperbolicPlane().UHP().get_isometry(self._matrix).to_model(model) diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index fdd7e38b552..917ebb0cf02 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -17,30 +17,33 @@ # **************************************************************************** from sage.arith.misc import divisors -from sage.functions.gamma import psi1 -from sage.functions.log import exp -from sage.functions.trig import cos, sec from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_generic from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method from sage.misc.latex import latex +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod -from sage.rings.imaginary_unit import I from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.qqbar import AA, AlgebraicField from sage.rings.rational_field import QQ from sage.structure.unique_representation import UniqueRepresentation -from sage.symbolic.constants import pi + +lazy_import("sage.functions.log", "exp") +lazy_import("sage.functions.gamma", "psi1") +lazy_import("sage.functions.trig", "sec") +lazy_import("sage.rings.number_field.number_field", "NumberField") +lazy_import("sage.rings.qqbar", ["AA", "AlgebraicField"]) +lazy_import("sage.rings.universal_cyclotomic_field", "E") +lazy_import("sage.symbolic.constants", "pi") from .hecke_triangle_group_element import HeckeTriangleGroupElement, cyclic_representative, coerce_AA + class HeckeTriangleGroup(FinitelyGeneratedMatrixGroup_generic, UniqueRepresentation): r""" - Hecke triangle group (2, n, infinity). + Hecke triangle group `(2, n, \infty)`. """ Element = HeckeTriangleGroupElement @@ -56,11 +59,11 @@ def __classcall__(cls, n=3): sage: HeckeTriangleGroup(QQ(3)) == HeckeTriangleGroup(int(3)) True """ - if (n == infinity): + if n == infinity: n = infinity else: n = ZZ(n) - if (n < 3): + if n < 3: raise AttributeError("n has to be infinity or an Integer >= 3.") return super().__classcall__(cls, n) @@ -95,12 +98,12 @@ def __init__(self, n): if n in [3, infinity]: self._base_ring = ZZ - self._lam = ZZ(1) if n == 3 else ZZ(2) + self._lam = ZZ.one() if n == 3 else ZZ(2) else: - lam_symbolic = 2 * cos(pi / n) + lam_symbolic = coerce_AA(E(2 * n) + ~E(2 * n)) K = NumberField(self.lam_minpoly(), 'lam', - embedding=coerce_AA(lam_symbolic)) - #self._base_ring = K.order(K.gens()) + embedding=lam_symbolic) + # self._base_ring = K.order(K.gens()) self._base_ring = K.maximal_order() self._lam = self._base_ring.gen(1) @@ -142,7 +145,7 @@ def element_repr_method(self, method=None): - ``method`` -- If ``method=None`` (default) the current default representation method is returned. Otherwise the default method is set to ``method``. - If ``method`` is not available a ValueError is raised. Possible methods are: + If ``method`` is not available a :class:`ValueError` is raised. Possible methods are: ``default``: Use the usual representation method for matrix group elements. @@ -167,9 +170,9 @@ def element_repr_method(self, method=None): if method is None: return self._element_repr_method elif method in ["default", "basic", "block", "conj"]: - self._element_repr_method=method + self._element_repr_method = method else: - raise ValueError("The specified method {} is not supported!").format(method) + raise ValueError(f"the specified method {method} is not supported") def one(self): r""" @@ -205,8 +208,12 @@ def lam_minpoly(self): x - 2 """ # TODO: Write an explicit (faster) implementation - lam_symbolic = 2 * cos(pi / self._n) - return coerce_AA(lam_symbolic).minpoly() + n = self._n + if n == infinity: + lam_symbolic = QQ(2) + else: + lam_symbolic = E(2 * n) + ~E(2 * n) + return lam_symbolic.minpoly() def base_ring(self): r""" @@ -256,7 +263,6 @@ def n(self): """ return self._n - # TODO: rename this to a more descriptive lambda in a later update/patch def lam(self): r""" Return the parameter ``lambda`` of ``self``, @@ -304,15 +310,16 @@ def rho(self): # TODO: maybe rho should be replaced by -rhobar # Also we could use NumberFields... if self._n == infinity: - return coerce_AA(1) + return AA.one() else: - rho = AlgebraicField()(exp(pi / self._n * I)) + rho = AlgebraicField()(E(2 * self._n)) rho.simplify() return rho def alpha(self): r""" Return the parameter ``alpha`` of ``self``. + This is the first parameter of the hypergeometric series used in the calculation of the Hauptmodul of ``self``. @@ -332,11 +339,12 @@ def alpha(self): sage: HeckeTriangleGroup(infinity).alpha() 1/4 """ - return ZZ(1) / ZZ(2) * (ZZ(1) / ZZ(2) - ZZ(1) / self._n) + return QQ((1, 2)) * (QQ((1, 2)) - ZZ.one() / self._n) def beta(self): r""" Return the parameter ``beta`` of ``self``. + This is the second parameter of the hypergeometric series used in the calculation of the Hauptmodul of ``self``. @@ -356,7 +364,7 @@ def beta(self): sage: HeckeTriangleGroup(infinity).beta() 1/4 """ - return ZZ(1)/ZZ(2) * (ZZ(1)/ZZ(2) + ZZ(1)/self._n) + return QQ((1, 2)) * (QQ((1, 2)) + ZZ.one() / self._n) # We use cached method here to create unique instances of basic matrices # (major performance gain) @@ -472,12 +480,13 @@ def V(self, j): INPUT: - ``j`` -- Any integer. To get the usual representatives - ``j`` should range from ``1`` to ``self.n()-1``. + ``j`` should range from ``1`` to ``self.n()-1``. OUTPUT: The corresponding matrix/element. - The matrix is parabolic if ``j`` is congruent to +-1 modulo ``self.n()``. + + The matrix is parabolic if ``j`` is congruent to `\pm 1` modulo ``self.n()``. It is elliptic if ``j`` is congruent to 0 modulo ``self.n()``. It is hyperbolic otherwise. @@ -540,19 +549,20 @@ def dvalue(self): """ n = self._n if n == 3: - return ZZ(1)/ZZ(2**6*3**3) - elif n == 4: - return ZZ(1)/ZZ(2**8) - elif n == 6: - return ZZ(1)/ZZ(2**2*3**3) - elif n == infinity: - return ZZ(1)/ZZ(2**6) - else: - return exp(-ZZ(2)*psi1(ZZ(1)) + psi1(ZZ(1)-self.alpha())+psi1(ZZ(1)-self.beta()) - pi*sec(pi/self._n)) - - def is_arithmetic(self): + return 1 / ZZ(2**6*3**3) + if n == 4: + return 1 / ZZ(2**8) + if n == 6: + return 1 / ZZ(2**2*3**3) + if n == infinity: + return 1 / ZZ(2**6) + # reference for this formula ? + return exp(-ZZ(2)*psi1(ZZ.one()) + psi1(ZZ.one()-self.alpha()) + + psi1(ZZ.one()-self.beta()) - pi*sec(pi/self._n)) + + def is_arithmetic(self) -> bool: r""" - Return True if ``self`` is an arithmetic subgroup. + Return ``True`` if ``self`` is an arithmetic subgroup. EXAMPLES:: @@ -619,26 +629,26 @@ def get_FD(self, z): 134.1200000... + 0.2200000000...*I """ ID = self.I() - T = self.T() - S = self.S() + T = self.T() + S = self.S() TI = self.T(-1) A = ID w = z - while (abs(w) < ZZ(1) or abs(w.real()) > self.lam()/ZZ(2)): - if (abs(w) < ZZ(1)): + while abs(w) < ZZ.one() or abs(w.real()) > self.lam() / ZZ(2): + if abs(w) < ZZ.one(): w = self.S().acton(w) A = S*A - while (w.real() >= self.lam()/ZZ(2)): + while w.real() >= self.lam() / ZZ(2): w = TI.acton(w) A = TI*A - while (w.real() < -self.lam()/ZZ(2)): + while w.real() < -self.lam() / ZZ(2): w = T.acton(w) A = T*A - if (w.real() == self.lam()/ZZ(2)): + if w.real() == self.lam() / ZZ(2): w = TI.acton(w) A = TI*A - if (abs(w) == ZZ(1) and w.real() > ZZ(0)): + if abs(w) == ZZ.one() and w.real() > ZZ.zero(): w = S.acton(w) A = S*A @@ -646,9 +656,9 @@ def get_FD(self, z): return (AI, A.acton(z)) - def in_FD(self, z): + def in_FD(self, z) -> bool: r""" - Returns ``True`` if ``z`` lies in the (strict) fundamental + Return ``True`` if ``z`` lies in the (strict) fundamental domain of ``self``. EXAMPLES:: @@ -669,7 +679,7 @@ def root_extension_field(self, D): INPUT: - ``D`` -- An element of the base ring of ``self`` - corresponding to a discriminant. + corresponding to a discriminant. OUTPUT: @@ -715,12 +725,12 @@ def root_extension_field(self, D): L = K.extension(x**2 - D, 'e') - #e = AA(D).sqrt() - #emb = L.hom([e]) - #L._unset_embedding() - #L.register_embedding(emb) + # e = AA(D).sqrt() + # emb = L.hom([e]) + # L._unset_embedding() + # L.register_embedding(emb) - #return NumberField(L.absolute_polynomial(), 'e', structure=AbsoluteFromRelative(L), embedding=(???)) + # return NumberField(L.absolute_polynomial(), 'e', structure=AbsoluteFromRelative(L), embedding=(???)) return L # We cache this method for performance reasons (it is repeatedly reused) @@ -736,17 +746,17 @@ def root_extension_embedding(self, D, K=None): INPUT: - ``D`` -- An element of the base ring of ``self`` - corresponding to a discriminant. + corresponding to a discriminant. - ``K`` -- A field to which we want the (correct) embedding. - If ``K=None`` (default) then ``AlgebraicField()`` is - used for positive ``D`` and ``AlgebraicRealField()`` - otherwise. + If ``K=None`` (default) then ``AlgebraicField()`` is + used for positive ``D`` and ``AlgebraicRealField()`` + otherwise. OUTPUT: The corresponding embedding if it was found. - Otherwise a ValueError is raised. + Otherwise a ``ValueError`` is raised. EXAMPLES:: @@ -869,7 +879,10 @@ def _elliptic_conj_reps(self): self._conj_prim[D] = [] self._conj_prim[D].append(self.S()) - other_reps = [self.U()**k for k in range(-((self.n()-1)/2).floor(), (self.n()/2).floor() + 1) if k not in [0,1]] + other_reps = [self.U()**k + for k in range(-((self.n() - 1) / 2).floor(), + self.n() // 2 + 1) + if k not in [0, 1]] for v in other_reps: D = v.discriminant() @@ -877,7 +890,7 @@ def _elliptic_conj_reps(self): self._conj_nonprim[D] = [] self._conj_nonprim[D].append(v) - def _conjugacy_representatives(self, max_block_length=ZZ(0), D=None): + def _conjugacy_representatives(self, max_block_length=0, D=None): r""" Store conjugacy representatives up to block length ``max_block_length`` (a non-negative integer, default: 0) @@ -944,12 +957,12 @@ def _conjugacy_representatives(self, max_block_length=ZZ(0), D=None): sage: G.element_repr_method("default") """ - from sage.combinat.partition import OrderedPartitions from sage.combinat.combinat import tuples if D is not None: - max_block_length = max(coerce_AA(0), coerce_AA((D + 4)/(self.lam()**2))).sqrt().floor() + max_block_length = max(AA.zero(), + coerce_AA((D + 4)/(self.lam()**2))).sqrt().floor() else: try: max_block_length = ZZ(max_block_length) @@ -959,10 +972,10 @@ def _conjugacy_representatives(self, max_block_length=ZZ(0), D=None): raise ValueError("max_block_length must be a non-negative integer!") if not hasattr(self, "_max_block_length"): - self._max_block_length = ZZ(0) - self._conj_block = {} - self._conj_nonprim = {} - self._conj_prim = {} + self._max_block_length = ZZ.zero() + self._conj_block = {} + self._conj_nonprim = {} + self._conj_prim = {} # It is not clear how to define the class number for D=0: # Conjugacy classes are V(n-1)^(+-k) for arbitrary k @@ -974,8 +987,8 @@ def _conjugacy_representatives(self, max_block_length=ZZ(0), D=None): # # We set it here to ensure that 0 is enlisted as a discriminant... # - self._conj_prim[ZZ(0)] = [] - self._conj_prim[ZZ(0)].append(self.V(self.n()-1)) + self._conj_prim[ZZ.zero()] = [] + self._conj_prim[ZZ.zero()].append(self.V(self.n()-1)) self._elliptic_conj_reps() @@ -1018,7 +1031,7 @@ def is_cycle_of_length(seq, n): keep = False # But: Do we maybe want powers of V(n-1)?? # For now we exclude the parabolic cases... - elif ex[0] == self.n()-1: + elif ex[0] == self.n() - 1: keep = False if keep: @@ -1028,18 +1041,11 @@ def is_cycle_of_length(seq, n): for el in self._conj_block[t_ZZ]: group_el = prod([self.V(el[k][0])**el[k][1] for k in range(len(el))]) - #if el != group_el.conjugacy_type(): - # raise AssertionError("This shouldn't happen!") - D = group_el.discriminant() - if coerce_AA(D) < 0: - raise AssertionError("This shouldn't happen!") - if coerce_AA(D) == 0: - raise AssertionError("This shouldn't happen!") - #continue + assert coerce_AA(D) > 0 # The primitive cases - #if group_el.is_primitive(): + # if group_el.is_primitive(): if not ((len(el) == 1 and el[0][1] > 1) or is_cycle(el)): if D not in self._conj_prim: self._conj_prim[D] = [] @@ -1063,10 +1069,10 @@ def class_representatives(self, D, primitive=True): INPUT: - ``D`` -- An element of the base ring corresponding - to a valid discriminant. + to a valid discriminant. - ``primitive`` -- If ``True`` (default) then only primitive - representatives are considered. + representatives are considered. EXAMPLES:: @@ -1129,7 +1135,7 @@ def class_representatives(self, D, primitive=True): if not primitive and D in self._conj_nonprim: L += self._conj_nonprim[D] - if len(L) == 0: + if not L: raise ValueError("D = {} is not a{} discriminant for {}".format(D, " primitive" if primitive else "", self)) else: return L @@ -1148,10 +1154,10 @@ def class_number(self, D, primitive=True): INPUT: - ``D`` -- An element of the base ring corresponding - to a valid discriminant. + to a valid discriminant. - ``primitive`` -- If ``True`` (default) then only primitive - elements are considered. + elements are considered. EXAMPLES:: @@ -1188,9 +1194,9 @@ def class_number(self, D, primitive=True): else: return num - def is_discriminant(self, D, primitive=True): + def is_discriminant(self, D, primitive=True) -> bool: r""" - Returns whether ``D`` is a discriminant of an element of ``self``. + Return whether ``D`` is a discriminant of an element of ``self``. Note: Checking that something isn't a discriminant takes much longer than checking for valid discriminants. @@ -1200,7 +1206,7 @@ def is_discriminant(self, D, primitive=True): - ``D`` -- An element of the base ring. - ``primitive`` -- If ``True`` (default) then only primitive - elements are considered. + elements are considered. OUTPUT: @@ -1220,9 +1226,9 @@ def is_discriminant(self, D, primitive=True): sage: G.is_discriminant(2) False """ - self._conjugacy_representatives(0) - t_bound = max(coerce_AA(0), coerce_AA((D + 4)/(self.lam()**2))).sqrt().floor() + t_bound = max(AA.zero(), + coerce_AA((D + 4) / (self.lam()**2))).sqrt().floor() for t in range(self._max_block_length + 1, t_bound + 1): self._conjugacy_representatives(t) @@ -1240,22 +1246,22 @@ def is_discriminant(self, D, primitive=True): def list_discriminants(self, D, primitive=True, hyperbolic=True, incomplete=False): r""" - Returns a list of all discriminants up to some upper bound ``D``. + Return a list of all discriminants up to some upper bound ``D``. INPUT: - ``D`` -- An element/discriminant of the base ring or - more generally an upper bound for the discriminant. + more generally an upper bound for the discriminant. - ``primitive`` -- If ``True`` (default) then only primitive - discriminants are listed. + discriminants are listed. - ``hyperbolic`` -- If ``True`` (default) then only positive - discriminants are listed. + discriminants are listed. - - ``incomplete`` -- If ``True`` (default: ``False``) then all (also higher) - discriminants which were gathered so far are listed - (however there might be missing discriminants inbetween). + - ``incomplete`` -- If ``True`` (default: ``False``) then all + (also higher) discriminants which were gathered so far are listed + (however there might be missing discriminants inbetween). OUTPUT: @@ -1284,17 +1290,18 @@ def list_discriminants(self, D, primitive=True, hyperbolic=True, incomplete=Fals else: max_D = coerce_AA(D) - L = [] if hyperbolic: - L += [key for key in self._conj_prim if coerce_AA(key) > 0 and coerce_AA(key) <= max_D] + L = [key for key in self._conj_prim if 0 < coerce_AA(key) <= max_D] else: - L += [key for key in self._conj_prim if coerce_AA(key) <= max_D] + L = [key for key in self._conj_prim if coerce_AA(key) <= max_D] if not primitive: if hyperbolic: - L += [key for key in self._conj_nonprim if coerce_AA(key) > 0 and coerce_AA(key) <= max_D and key not in L] + L += [key for key in self._conj_nonprim + if 0 < coerce_AA(key) <= max_D and key not in L] else: - L += [key for key in self._conj_nonprim if coerce_AA(key) <= max_D and key not in L] + L += [key for key in self._conj_nonprim + if coerce_AA(key) <= max_D and key not in L] return sorted(L, key=coerce_AA) @@ -1302,10 +1309,11 @@ def list_discriminants(self, D, primitive=True, hyperbolic=True, incomplete=Fals def reduced_elements(self, D): r""" Return all reduced (primitive) elements of discriminant ``D``. - Also see the element method ``is_reduced()`` for more information. + + Also see the element method :meth:`is_reduced` for more information. - ``D`` -- An element of the base ring corresponding - to a valid discriminant. + to a valid discriminant. EXAMPLES:: @@ -1338,6 +1346,7 @@ def reduced_elements(self, D): def simple_elements(self, D): r""" Return all simple elements of discriminant ``D``. + Also see the element method ``is_simple()`` for more information. - ``D`` -- An element of the base ring corresponding @@ -1368,16 +1377,19 @@ def simple_elements(self, D): def rational_period_functions(self, k, D): r""" Return a list of basic rational period functions of weight ``k`` for discriminant ``D``. - The list is expected to be a generating set for all rational period functions of the - given weight and discriminant (unknown). + + The list is expected to be a generating set for all rational + period functions of the given weight and discriminant (unknown). The method assumes that ``D > 0``. + Also see the element method `rational_period_function` for more information. - - ``k`` -- An even integer, the desired weight of the rational period functions. + - ``k`` -- An even integer, the desired weight + of the rational period functions. - ``D`` -- An element of the base ring corresponding - to a valid discriminant. + to a valid discriminant. EXAMPLES:: diff --git a/src/sage/modular/modform_hecketriangle/series_constructor.py b/src/sage/modular/modform_hecketriangle/series_constructor.py index 881270c5bfa..dc2cd792a6b 100644 --- a/src/sage/modular/modform_hecketriangle/series_constructor.py +++ b/src/sage/modular/modform_hecketriangle/series_constructor.py @@ -11,14 +11,14 @@ ``J_inv_ZZ`` is the main function used to determine all Fourier expansions. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann <jjermann2@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.arith.misc import bernoulli, sigma, rising_factorial from sage.misc.cachefunc import cached_method @@ -115,9 +115,9 @@ def __init__(self, group, prec): Power series constructor for Hecke modular forms for n=+Infinity with (basic series) precision 10 """ - self._group = group - self._prec = prec - self._series_ring = PowerSeriesRing(QQ,'q',default_prec=self._prec) + self._group = group + self._prec = prec + self._series_ring = PowerSeriesRing(QQ,'q',default_prec=self._prec) def _repr_(self): r""" @@ -210,7 +210,7 @@ def J_inv_ZZ(self): q^-1 + 3/8 + 69/1024*q + O(q^2) """ - F1 = lambda a,b: self._series_ring( + F1 = lambda a,b: self._series_ring( [ ZZ(0) ] + [ rising_factorial(a,k) * rising_factorial(b,k) / (ZZ(k).factorial())**2 @@ -222,23 +222,23 @@ def J_inv_ZZ(self): ZZ(self._prec+1) ) - F = lambda a,b,c: self._series_ring( + F = lambda a,b,c: self._series_ring( [ rising_factorial(a,k) * rising_factorial(b,k) / rising_factorial(c,k) / ZZ(k).factorial() for k in range(ZZ(0), ZZ(self._prec+1)) ], ZZ(self._prec+1) ) - a = self._group.alpha() - b = self._group.beta() - Phi = F1(a,b) / F(a,b,ZZ(1)) - q = self._series_ring.gen() + a = self._group.alpha() + b = self._group.beta() + Phi = F1(a,b) / F(a,b,ZZ(1)) + q = self._series_ring.gen() # the current implementation of power series reversion is slow # J_inv_ZZ = ZZ(1) / ((q*Phi.exp()).reverse()) - temp_f = (q*Phi.exp()).polynomial() - new_f = temp_f.revert_series(temp_f.degree()+1) + temp_f = (q*Phi.exp()).polynomial() + new_f = temp_f.revert_series(temp_f.degree()+1) J_inv_ZZ = ZZ(1) / (new_f + O(q**(temp_f.degree()+1))) return J_inv_ZZ @@ -341,7 +341,7 @@ def f_inf_ZZ(self): if (n == infinity): f_inf_ZZ = ((-q*self.J_inv_ZZ().derivative())**2/(self.J_inv_ZZ()**2*(self.J_inv_ZZ()-1))).power_series() else: - temp_expr = ((-q*self.J_inv_ZZ().derivative())**(2*n)/(self.J_inv_ZZ()**(2*n-2)*(self.J_inv_ZZ()-1)**n)/q**(n-2)).power_series() + temp_expr = ((-q*self.J_inv_ZZ().derivative())**(2*n)/(self.J_inv_ZZ()**(2*n-2)*(self.J_inv_ZZ()-1)**n)/q**(n-2)).power_series() f_inf_ZZ = (temp_expr.log()/(n-2)).exp()*q return f_inf_ZZ @@ -369,17 +369,15 @@ def G_inv_ZZ(self): sage: MFSeriesConstructor(group=infinity, prec=3).G_inv_ZZ() q^-1 - 1/8 - 59/1024*q + O(q^2) """ - n = self.hecke_n() # Note that G_inv is not a weakly holomorphic form (because of the behavior at -1) - if (n == infinity): + if n == infinity: q = self._series_ring.gen() temp_expr = (self.J_inv_ZZ()/self.f_inf_ZZ()*q**2).power_series() return 1/q*self.f_i_ZZ()*(temp_expr.log()/2).exp() elif (ZZ(2).divides(n)): return self.f_i_ZZ()*(self.f_rho_ZZ()**(ZZ(n/ZZ(2))))/self.f_inf_ZZ() else: - #return self._qseries_ring([]) raise ValueError("G_inv doesn't exist for n={}.".format(self.hecke_n())) @cached_method @@ -563,7 +561,7 @@ def EisensteinSeries_ZZ(self, k): if k == 0: return self._series_ring(1) - M = ZZ(self.group().lam()**2) + M = ZZ(self.group().lam()**2) lamk = M**(ZZ(k/2)) dval = self.group().dvalue() @@ -575,7 +573,7 @@ def coeff(m): return ZZ(1) factor = -2*k / QQ(bernoulli(k)) / lamk - sum1 = sigma(m, k-1) + sum1 = sigma(m, k-1) if M.divides(m): sum2 = (lamk-1) * sigma(ZZ(m/M), k-1) else: diff --git a/src/sage/modular/modform_hecketriangle/space.py b/src/sage/modular/modform_hecketriangle/space.py index beae939854d..662f1035794 100644 --- a/src/sage/modular/modform_hecketriangle/space.py +++ b/src/sage/modular/modform_hecketriangle/space.py @@ -6,15 +6,14 @@ - Jonas Jermann (2013): initial version """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann <jjermann2@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -29,6 +28,7 @@ from .hecke_triangle_groups import HeckeTriangleGroup from .abstract_space import FormsSpace_abstract + def canonical_parameters(group, base_ring, k, ep, n=None): r""" Return a canonical version of the parameters. @@ -42,11 +42,10 @@ def canonical_parameters(group, base_ring, k, ep, n=None): sage: canonical_parameters(infinity, ZZ, 2, int(-1)) (Hecke triangle group for n = +Infinity, Integer Ring, 2, -1, +Infinity) """ - - if not (n is None): + if n is not None: group = n - if (group == infinity): + if group == infinity: group = HeckeTriangleGroup(infinity) else: try: @@ -56,16 +55,16 @@ def canonical_parameters(group, base_ring, k, ep, n=None): n = group.n() k = QQ(k) - if (ep is None): - if (n == infinity): - ep = (-1)**(k/ZZ(2)) - elif (ZZ(2).divides(n)): + if ep is None: + if n == infinity: + ep = (-1)**(k / 2) + elif ZZ(2).divides(n): ep = (-1)**(k*ZZ(n-2)/ZZ(4)) else: ep = (-1)**(k*ZZ(n-2)/ZZ(2)) ep = ZZ(ep) - if (n == infinity): + if n == infinity: num = (k-(1-ep)) / ZZ(4) else: num = (k-(1-ep)*n/(n-2)) * (n-2) / ZZ(4) @@ -73,7 +72,7 @@ def canonical_parameters(group, base_ring, k, ep, n=None): try: num = ZZ(num) except TypeError: - raise ValueError("Invalid or non-occurring weight k={}, ep={}!".format(k,ep)) + raise ValueError(f"Invalid or non-occurring weight k={k}, ep={ep}!") return (group, base_ring, k, ep, n) @@ -85,7 +84,7 @@ class QuasiMeromorphicModularForms(FormsSpace_abstract, Module, UniqueRepresenta """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, k=QQ(0), ep=None, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, k=QQ(0), ep=None, n=None): r""" Return a (cached) instance with canonical parameters. @@ -119,10 +118,10 @@ def __init__(self, group, base_ring, k, ep, n): sage: MF.ambient_space() == MF True """ - FormsSpace_abstract.__init__(self, group=group, base_ring=base_ring, k=k, ep=ep, n=n) Module.__init__(self, base=base_ring) - self._analytic_type=self.AT(["quasi", "mero"]) + self._analytic_type = self.AT(["quasi", "mero"]) + class QuasiWeakModularForms(FormsSpace_abstract, Module, UniqueRepresentation): r""" @@ -131,7 +130,7 @@ class QuasiWeakModularForms(FormsSpace_abstract, Module, UniqueRepresentation): """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, k=QQ(0), ep=None, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, k=QQ(0), ep=None, n=None): r""" Return a (cached) instance with canonical parameters. @@ -166,10 +165,10 @@ def __init__(self, group, base_ring, k, ep, n): sage: MF.is_ambient() True """ - FormsSpace_abstract.__init__(self, group=group, base_ring=base_ring, k=k, ep=ep, n=n) Module.__init__(self, base=base_ring) - self._analytic_type=self.AT(["quasi", "weak"]) + self._analytic_type = self.AT(["quasi", "weak"]) + class QuasiModularForms(FormsSpace_abstract, Module, UniqueRepresentation): r""" @@ -178,7 +177,7 @@ class QuasiModularForms(FormsSpace_abstract, Module, UniqueRepresentation): """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, k=QQ(0), ep=None, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, k=QQ(0), ep=None, n=None): r""" Return a (cached) instance with canonical parameters. @@ -216,7 +215,7 @@ def __init__(self, group, base_ring, k, ep, n): FormsSpace_abstract.__init__(self, group=group, base_ring=base_ring, k=k, ep=ep, n=n) Module.__init__(self, base=base_ring) - self._analytic_type=self.AT(["quasi", "holo"]) + self._analytic_type = self.AT(["quasi", "holo"]) self._module = FreeModule(self.coeff_ring(), self.dimension()) @cached_method @@ -310,29 +309,29 @@ def coordinate_vector(self, v): sage: el2 == MF.element_from_coordinates(el2.coordinate_vector()) True """ - - (x,y,z,d) = self.pol_ring().gens() + x, y, z, d = self.pol_ring().gens() k = self._weight - rmax = QQ(k / ZZ(2)).floor() + rmax = (QQ(k) / 2).floor() partlist = v.rat().numerator().polynomial(z).list() denom = self.coeff_ring()(v.rat().denominator()) - partlist = [part/denom for part in partlist] - parts = partlist + [0]*(rmax + 1 - len(partlist)) + partlist = [part / denom for part in partlist] + parts = partlist + [0] * (rmax + 1 - len(partlist)) E2 = self.E2() coord_vector = [] - for r in range(ZZ(0), rmax + 1): - gens = [v/E2**r for v in self.quasi_part_gens(r)] + for r in range(rmax + 1): + gens = [v / E2**r for v in self.quasi_part_gens(r)] - if len(gens) > 0: + if gens: ambient_space = self.graded_ring().reduce_type("holo", degree=(gens[0].weight(), gens[0].ep())) subspace = ambient_space.subspace(gens) vector_part_in_subspace = subspace(parts[r]) - coord_part = [v for v in vector_part_in_subspace.coordinate_vector() ] + coord_part = [v for v in vector_part_in_subspace.coordinate_vector()] coord_vector += coord_part return self._module(vector(self.coeff_ring(), coord_vector)) + class QuasiCuspForms(FormsSpace_abstract, Module, UniqueRepresentation): r""" Module of (Hecke) quasi cusp forms @@ -340,7 +339,7 @@ class QuasiCuspForms(FormsSpace_abstract, Module, UniqueRepresentation): """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, k=QQ(0), ep=None, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, k=QQ(0), ep=None, n=None): r""" Return a (cached) instance with canonical parameters. @@ -381,7 +380,7 @@ def __init__(self, group, base_ring, k, ep, n): FormsSpace_abstract.__init__(self, group=group, base_ring=base_ring, k=k, ep=ep, n=n) Module.__init__(self, base=base_ring) - self._analytic_type=self.AT(["quasi", "cusp"]) + self._analytic_type = self.AT(["quasi", "cusp"]) self._module = FreeModule(self.coeff_ring(), self.dimension()) @cached_method @@ -482,29 +481,29 @@ def coordinate_vector(self, v): sage: el2 == MF.element_from_coordinates(el2.coordinate_vector()) True """ - - (x,y,z,d) = self.pol_ring().gens() + x, y, z, d = self.pol_ring().gens() k = self._weight - rmax = QQ(k / ZZ(2)).floor() + rmax = (QQ(k) / 2).floor() partlist = v.rat().numerator().polynomial(z).list() denom = self.coeff_ring()(v.rat().denominator()) - partlist = [part/denom for part in partlist] - parts = partlist + [0]*(rmax + 1 - len(partlist)) + partlist = [part / denom for part in partlist] + parts = partlist + [0] * (rmax + 1 - len(partlist)) E2 = self.E2() coord_vector = [] - for r in range(ZZ(0), rmax + 1): - gens = [v/E2**r for v in self.quasi_part_gens(r)] + for r in range(rmax + 1): + gens = [v / E2**r for v in self.quasi_part_gens(r)] - if len(gens) > 0: + if gens: ambient_space = self.graded_ring().reduce_type("cusp", degree=(gens[0].weight(), gens[0].ep())) subspace = ambient_space.subspace(gens) vector_part_in_subspace = subspace(parts[r]) - coord_part = [v for v in vector_part_in_subspace.coordinate_vector() ] + coord_part = [v for v in vector_part_in_subspace.coordinate_vector()] coord_vector += coord_part return self._module(vector(self.coeff_ring(), coord_vector)) + class MeromorphicModularForms(FormsSpace_abstract, Module, UniqueRepresentation): r""" Module of (Hecke) meromorphic modular forms @@ -512,7 +511,7 @@ class MeromorphicModularForms(FormsSpace_abstract, Module, UniqueRepresentation) """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, k=QQ(0), ep=None, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, k=QQ(0), ep=None, n=None): r""" Return a (cached) instance with canonical parameters. @@ -550,7 +549,8 @@ def __init__(self, group, base_ring, k, ep, n): FormsSpace_abstract.__init__(self, group=group, base_ring=base_ring, k=k, ep=ep, n=n) Module.__init__(self, base=base_ring) - self._analytic_type=self.AT(["mero"]) + self._analytic_type = self.AT(["mero"]) + class WeakModularForms(FormsSpace_abstract, Module, UniqueRepresentation): r""" @@ -559,7 +559,7 @@ class WeakModularForms(FormsSpace_abstract, Module, UniqueRepresentation): """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, k=QQ(0), ep=None, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, k=QQ(0), ep=None, n=None): r""" Return a (cached) instance with canonical parameters. @@ -592,10 +592,10 @@ def __init__(self, group, base_ring, k, ep, n): sage: MF in MF.category() True """ - FormsSpace_abstract.__init__(self, group=group, base_ring=base_ring, k=k, ep=ep, n=n) Module.__init__(self, base=base_ring) - self._analytic_type=self.AT(["weak"]) + self._analytic_type = self.AT(["weak"]) + class ModularForms(FormsSpace_abstract, Module, UniqueRepresentation): r""" @@ -604,7 +604,7 @@ class ModularForms(FormsSpace_abstract, Module, UniqueRepresentation): """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, k=QQ(0), ep=None, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, k=QQ(0), ep=None, n=None): r""" Return a (cached) instance with canonical parameters. @@ -679,8 +679,7 @@ def gens(self): sage: ModularForms(n=infinity, k=4).gens() [1 + 240*q^2 + 2160*q^4 + O(q^5), q - 8*q^2 + 28*q^3 - 64*q^4 + O(q^5)] """ - - return [ self.F_basis(m) for m in range(self.dimension()) ] + return [self.F_basis(m) for m in range(self.dimension())] @cached_method def dimension(self): @@ -699,8 +698,7 @@ def dimension(self): sage: ModularForms(n=infinity, k=8).dimension() 3 """ - - return max(self._l1+1, ZZ(0)) + return max(self._l1 + 1, ZZ.zero()) @cached_method def coordinate_vector(self, v): @@ -747,9 +745,10 @@ def coordinate_vector(self, v): (1, 1/(2*d), 15/(128*d^2)) """ - vec = v.q_expansion_vector(min_exp = 0, max_exp = self.degree() - 1) + vec = v.q_expansion_vector(min_exp=0, max_exp=self.degree() - 1) return self._module(vec) + class CuspForms(FormsSpace_abstract, Module, UniqueRepresentation): r""" Module of (Hecke) cusp forms @@ -757,7 +756,7 @@ class CuspForms(FormsSpace_abstract, Module, UniqueRepresentation): """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, k=QQ(0), ep=None, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, k=QQ(0), ep=None, n=None): r""" Return a (cached) instance with canonical parameters. @@ -795,10 +794,9 @@ def __init__(self, group, base_ring, k, ep, n): sage: MF.is_ambient() True """ - FormsSpace_abstract.__init__(self, group=group, base_ring=base_ring, k=k, ep=ep, n=n) Module.__init__(self, base=base_ring) - self._analytic_type=self.AT(["cusp"]) + self._analytic_type = self.AT(["cusp"]) self._module = FreeModule(self.coeff_ring(), self.dimension()) @cached_method @@ -822,9 +820,9 @@ def gens(self): sage: MF = CuspForms(n=infinity, k=8, ep=1) sage: MF.gen(0) == MF.E4()*MF.f_inf() True - """ - - return [ self.F_basis(m, order_1=ZZ(1)) for m in range(1, self.dimension() + 1) ] + """ + return [self.F_basis(m, order_1=ZZ.one()) + for m in range(1, self.dimension() + 1)] @cached_method def dimension(self): @@ -843,11 +841,9 @@ def dimension(self): sage: CuspForms(n=infinity, k=8).dimension() 1 """ - - if (self.hecke_n() == infinity): - return max(self._l1-1, ZZ(0)) - else: - return max(self._l1, ZZ(0)) + if self.hecke_n() == infinity: + return max(self._l1 - 1, ZZ.zero()) + return max(self._l1, ZZ.zero()) @cached_method def coordinate_vector(self, v): @@ -899,9 +895,10 @@ def coordinate_vector(self, v): True """ - vec = v.q_expansion_vector(min_exp = 1, max_exp = self.degree()) + vec = v.q_expansion_vector(min_exp=1, max_exp=self.degree()) return self._module(vec) + class ZeroForm(FormsSpace_abstract, Module, UniqueRepresentation): r""" Zero Module for the zero form for the given group, base ring @@ -909,7 +906,7 @@ class ZeroForm(FormsSpace_abstract, Module, UniqueRepresentation): """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), base_ring = ZZ, k=QQ(0), ep=None, n=None): + def __classcall__(cls, group=HeckeTriangleGroup(3), base_ring=ZZ, k=QQ(0), ep=None, n=None): r""" Return a (cached) instance with canonical parameters. @@ -952,7 +949,7 @@ def __init__(self, group, base_ring, k, ep, n): FormsSpace_abstract.__init__(self, group=group, base_ring=base_ring, k=k, ep=ep, n=n) Module.__init__(self, base=base_ring) - self._analytic_type=self.AT([]) + self._analytic_type = self.AT([]) self._module = FreeModule(self.coeff_ring(), self.dimension()) def _change_degree(self, k, ep): @@ -977,7 +974,8 @@ def _change_degree(self, k, ep): sage: MF._change_degree(14, -1) ZeroForms(n=3, k=14, ep=-1) over Integer Ring """ - return ZeroForm(group=self.group(), base_ring=self.base_ring(), k=k, ep=ep) + return ZeroForm(group=self.group(), base_ring=self.base_ring(), + k=k, ep=ep) @cached_method def gens(self): @@ -991,7 +989,6 @@ def gens(self): sage: ZeroForm(6, CC, 3, -1).gens() [] """ - return [] @cached_method @@ -1006,7 +1003,6 @@ def dimension(self): sage: ZeroForm(6, CC, 3, -1).dimension() 0 """ - return 0 @cached_method @@ -1038,6 +1034,4 @@ def coordinate_vector(self, v): sage: vec.parent() == MF.module() True """ - - vec = [] - return self._module(vector(self.coeff_ring(), vec)) + return self._module(vector(self.coeff_ring(), [])) diff --git a/src/sage/modular/modform_hecketriangle/subspace.py b/src/sage/modular/modform_hecketriangle/subspace.py index 332546aee15..f89d42affd8 100644 --- a/src/sage/modular/modform_hecketriangle/subspace.py +++ b/src/sage/modular/modform_hecketriangle/subspace.py @@ -43,7 +43,6 @@ def canonical_parameters(ambient_space, basis, check=True): (q + 30*q^2 + 333*q^3 + 1444*q^4 + O(q^5), 1 + 26208*q^3 + 530712*q^4 + O(q^5))) """ - if check: coord_matrix = matrix([ambient_space(v).ambient_coordinate_vector() for v in basis]) pivots = coord_matrix.transpose().pivots() @@ -55,6 +54,7 @@ def canonical_parameters(ambient_space, basis, check=True): return (ambient_space, basis) + def ModularFormsSubSpace(*args, **kwargs): r""" Create a modular forms subspace generated by the supplied arguments if possible. @@ -203,7 +203,6 @@ def __init__(self, ambient_space, basis, check): sage: subspace.gens() [q + 24*q^2 + O(q^3), q - 24*q^2 + O(q^3), q - 8*q^2 + O(q^3)] """ - FormsSpace_abstract.__init__(self, group=ambient_space.group(), base_ring=ambient_space.base_ring(), k=ambient_space.weight(), ep=ambient_space.ep(), n=ambient_space.hecke_n()) Module.__init__(self, base=ambient_space.base_ring()) @@ -213,7 +212,7 @@ def __init__(self, ambient_space, basis, check): self._gens = [self._element_constructor_(v) for v in basis] self._module = ambient_space._module.submodule([ambient_space.coordinate_vector(v) for v in basis]) # TODO: get the analytic type from the basis - #self._analytic_type=self.AT(["quasi", "mero"]) + # self._analytic_type=self.AT(["quasi", "mero"]) self._analytic_type = ambient_space._analytic_type def _repr_(self): diff --git a/src/sage/modular/modsym/__init__.py b/src/sage/modular/modsym/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/modsym/all.py b/src/sage/modular/modsym/all.py index e3bfa152ca7..798a4a7d55f 100644 --- a/src/sage/modular/modsym/all.py +++ b/src/sage/modular/modsym/all.py @@ -1,9 +1,10 @@ +from sage.misc.lazy_import import lazy_import from .element import set_modsym_print_mode from .modsym import ModularSymbols, ModularSymbols_clear_cache -from .heilbronn import HeilbronnCremona, HeilbronnMerel +lazy_import('sage.modular.modsym.heilbronn', ['HeilbronnCremona', 'HeilbronnMerel']) from .p1list import P1List, lift_to_sl2z diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index 627f1c567e7..9c1876493f1 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -25,8 +25,6 @@ class ``ModularSymbolsAmbient``, derived from - ``ModularSymbolsAmbient_wtk_eps``, for modular symbols of general weight `k` and character `\epsilon`. - - EXAMPLES: We compute a space of modular symbols modulo 2. The dimension is @@ -81,7 +79,6 @@ class ``ModularSymbolsAmbient``, derived from from sage.misc.latex import latex from sage.misc.verbose import verbose from sage.modular.arithgroup.arithgroup_element import M2Z -from sage.modular.arithgroup.congroup_generic import is_CongruenceSubgroup from sage.modular.dirichlet import TrivialCharacter, is_DirichletCharacter from sage.modular.hecke.ambient_module import AmbientHeckeModule from sage.modular.cusps import Cusp @@ -95,7 +92,7 @@ class ``ModularSymbolsAmbient``, derived from from sage.modules.free_module_element import FreeModuleElement from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.multi_polynomial import is_MPolynomial +from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.rings.rational_field import QQ from sage.rings.ring import Ring from sage.structure.factorization import Factorization @@ -166,7 +163,7 @@ def __init__(self, group, weight, sign, base_ring, """ weight = int(weight) if weight <= 1: - raise ValueError("Weight (=%s) Modular symbols of weight <= 1 not defined."%weight) + raise ValueError("Weight (=%s) Modular symbols of weight <= 1 not defined." % weight) if not arithgroup.is_CongruenceSubgroup(group): raise TypeError("group must be a congruence subgroup") @@ -178,8 +175,8 @@ def __init__(self, group, weight, sign, base_ring, character = TrivialCharacter(group.level(), base_ring) ModularSymbolsSpace.__init__(self, group, weight, - character, sign, base_ring, - category=category) + character, sign, base_ring, + category=category) if custom_init is not None: custom_init(self) @@ -192,9 +189,9 @@ def __init__(self, group, weight, sign, base_ring, rank = self.rank() if formula is not None: assert rank == formula, \ - "Computed dimension (=%s) of ambient space \"%s\" doesn't match dimension formula (=%s)!\n"%(rank, self, formula) + \ - "ModularSymbolsAmbient: group = %s, weight = %s, sign = %s, base_ring = %s, character = %s"%( - group, weight, sign, base_ring, character) + "Computed dimension (=%s) of ambient space \"%s\" doesn't match dimension formula (=%s)!\n" % (rank, self, formula) + \ + "ModularSymbolsAmbient: group = %s, weight = %s, sign = %s, base_ring = %s, character = %s" % ( + group, weight, sign, base_ring, character) AmbientHeckeModule.__init__(self, base_ring, rank, group.level(), weight, category=category) @@ -312,8 +309,8 @@ def compute_presentation(self): """ B, basis, mod = relation_matrix.compute_presentation( - self.manin_symbols(), self.sign(), - self.base_ring()) + self.manin_symbols(), self.sign(), + self.base_ring()) self._manin_generators = self.manin_symbols().manin_symbol_list() self._manin_basis = basis self._manin_gens_to_basis = B @@ -345,7 +342,6 @@ def manin_gens_to_basis(self): self.compute_presentation() return self._manin_gens_to_basis - ##################################################################### # Coercion ##################################################################### @@ -445,17 +441,12 @@ def _element_constructor_(self, x, computed_with_hecke=False): (1,35) sage: M([Cusp(1/2),Cusp(0)]) (1,35) - - """ if isinstance(x, FreeModuleElement): if x.degree() != self.dimension(): - raise TypeError("Incompatible degrees: x has degree %s\ - but modular symbols space has dimension %s"%( - x.degree(), self.dimension())) - #if x.parent().base_ring() != self.base_ring(): - # raise TypeError, "Vector x is over %s, but modular symbols space is over %s."%( - # x.parent().base_ring(), self.base_ring()) + raise TypeError("Incompatible degrees: x has degree " + f"{x.degree()} but modular symbols space has " + f"dimension {self.dimension()}") return self.element_class(self, x) elif isinstance(x, (ManinSymbol, element.ModularSymbolsElement)): @@ -464,23 +455,22 @@ def _element_constructor_(self, x, computed_with_hecke=False): elif isinstance(x, modular_symbols.ModularSymbol): return self(x.manin_symbol_rep()) - elif isinstance(x, (int, Integer)) and x==0: + elif isinstance(x, (int, Integer)) and x == 0: return self.element_class(self, self.free_module()(0)) elif isinstance(x, tuple): return self.manin_symbol(x) elif isinstance(x, FormalSum): - return sum([c*self(y) for c, y in x], self(0)) + return sum([c * self(y) for c, y in x], self(0)) elif isinstance(x, list): - if len(x) == 3 and is_MPolynomial(x[0]): + if len(x) == 3 and isinstance(x[0], MPolynomial): return self.modular_symbol_sum(x) else: return self.modular_symbol(x) - raise TypeError("No coercion of %s into %s defined."%(x, self)) - + raise TypeError("No coercion of %s into %s defined." % (x, self)) def change_ring(self, R): r""" @@ -540,7 +530,6 @@ def _action_on_modular_symbols(self, g): [0 0 0 1] [0 1 0 0] [0 1 0 0] - """ if not isinstance(g, list): raise TypeError("g must be a list") @@ -573,19 +562,19 @@ def manin_symbol(self, x, check=True): """ if check: if len(x) == 2: - x = (0,x[0],x[1]) + x = (0, x[0], x[1]) if len(x) == 3: # Manin symbol of the form (i, u, v), which corresponds to [X^i*Y^(k-2-i), (u,v)]. - if x[0] < 0 or x[0] > self.weight()-2: + if x[0] < 0 or x[0] > self.weight() - 2: raise ValueError("The first entry of the tuple (=%s)\ - must be an integer between 0 and k-2 (=%s)."%( - x, self.weight()-2)) + must be an integer between 0 and k-2 (=%s)." % ( + x, self.weight() - 2)) else: - raise ValueError("x (=%s) must be of length 2 or 3"%x) + raise ValueError("x (=%s) must be of length 2 or 3" % x) # end check N = self.level() - x = (x[0], x[1]%N, x[2]%N) + x = (x[0], x[1] % N, x[2] % N) try: return self.__manin_symbol[x] except AttributeError: @@ -605,7 +594,7 @@ def _modular_symbol_0_to_alpha(self, alpha, i=0): - ``alpha`` (rational or Infinity) -- a cusp - - ``i`` (int, default 0) -- the degree of the symbol. + - ``i`` (int, default 0) -- the degree of the symbol OUTPUT: @@ -624,11 +613,11 @@ def _modular_symbol_0_to_alpha(self, alpha, i=0): 0 """ if alpha.is_infinity(): - return self.manin_symbol((i,0,1), check=False) + return self.manin_symbol((i, 0, 1), check=False) # v, c = arith.continued_fraction_list(alpha._rational_(), partial_convergents=True) cf = alpha._rational_().continued_fraction() v = list(cf) - c = [(cf.p(k),cf.q(k)) for k in range(len(cf))] + c = [(cf.p(k), cf.q(k)) for k in range(len(cf))] a = self(0) one = ZZ.one() two = ZZ(2) @@ -639,8 +628,8 @@ def _modular_symbol_0_to_alpha(self, alpha, i=0): # zero in this case. we do the first here, and the # second in the k=0 case below, so as to avoid code # duplication - a += self.manin_symbol((i,0,1), check=False) - for k in range(0,len(c)): + a += self.manin_symbol((i, 0, 1), check=False) + for k in range(len(c)): # matrix entries associated to this partial sum if k == 0: x = c[0][0] @@ -652,7 +641,7 @@ def _modular_symbol_0_to_alpha(self, alpha, i=0): y = c[k-1][0] z = c[k][1] w = c[k-1][1] - if k%2 == 0: + if k % 2 == 0: y = -y w = -w @@ -665,7 +654,7 @@ def _modular_symbol_0_to_alpha(self, alpha, i=0): # method 1: write out solution. this is currently # incorrect, because it ends up doing 0^0 in the sum, # so I'll fix it and do timings soon. -# for s in range(0,self.weight()-two+1): +# for s in range(self.weight()-two+1): # coeff = sum([ binomial(i,t)*binomial(self.weight()-two-i,s-t)* # x**t * y**(i-t) * z**(s-t) * # w**(self.weight()-two-i-s+t) for t in range(0,s) ]) @@ -680,10 +669,10 @@ def _modular_symbol_0_to_alpha(self, alpha, i=0): if (self.weight()-2-i == 0): p2 = R(one) poly = (p1**i) * (p2**(self.weight()-2-i)) - for s in range(0,self.weight()-1): # k-2+1 = k-1 - a += poly[s] * self.manin_symbol((s,z,w), check=False) + for s in range(self.weight()-1): # k-2+1 = k-1 + a += poly[s] * self.manin_symbol((s, z, w), check=False) else: - for k in range(1,len(c)): + for k in range(1, len(c)): u = c[k][1] v = c[k-1][1] if k % 2 == 0: @@ -754,17 +743,16 @@ def modular_symbol(self, x, check=True): sage: set_modsym_print_mode() # return to default. """ - if check: if len(x) == 2: - x = [0,x[0],x[1]] + x = [0, x[0], x[1]] elif len(x) == 3: if x[0] < 0 or x[0] > self.weight()-2: raise ValueError("The first entry of the tuple (=%s)\ - must be an integer between 0 and k-2 (=%s)."%( + must be an integer between 0 and k-2 (=%s)." % ( x, self.weight()-2)) else: - raise ValueError("x (=%s) must be of length 2 or 3"%x) + raise ValueError("x (=%s) must be of length 2 or 3" % x) i = Integer(x[0]) alpha = Cusp(x[1]) beta = Cusp(x[2]) @@ -806,15 +794,15 @@ def modular_symbol_sum(self, x, check=True): """ if check: if len(x) != 3: - raise ValueError("%s must have length 3"%x) + raise ValueError("%s must have length 3" % x) f = x[0] - R = self.base_ring()['X','Y'] + R = self.base_ring()['X', 'Y'] X = R.gen(0) try: f = R(f) except TypeError: raise ValueError("f must be coercible to a polynomial \ - over %s"%self.base_ring()) + over %s" % self.base_ring()) if (not f.is_homogeneous()) or (f.degree() != self.weight()-2): raise ValueError("f must be a homogeneous polynomial of degree k-2") alpha = Cusp(x[1]) @@ -1002,26 +990,25 @@ def _compute_hecke_matrix_prime(self, p, rows=None): j = 0 for i in B: for h in H: - entries = syms.apply(i,h) + entries = syms.apply(i, h) for k, x in entries: f, s = mod2term[k] if s: # W[j,f] = W[j,f] + s*K(x) W.add_to_entry(j, f, s * K(x)) j += 1 - tm = verbose("start matrix multiply",tm) + tm = verbose("start matrix multiply", tm) if hasattr(W, '_matrix_times_matrix_dense'): Tp = W._matrix_times_matrix_dense(R) - verbose("done matrix multiply and computing Hecke operator",tm) + verbose("done matrix multiply and computing Hecke operator", tm) else: Tp = W * R - tm = verbose("done matrix multiply",tm) + tm = verbose("done matrix multiply", tm) Tp = Tp.dense_matrix() - verbose("done making Hecke operator matrix dense",tm) - self._hecke_matrices[(p,rows)] = Tp + verbose("done making Hecke operator matrix dense", tm) + self._hecke_matrices[(p, rows)] = Tp return Tp - def __heilbronn_operator(self, M, H, t=1): r""" Return the matrix function to the space `M` defined by `H`, `t`. @@ -1075,7 +1062,7 @@ def __heilbronn_operator(self, M, H, t=1): hom = self.Hom(M) if self.dimension() == 0 or M.dimension() == 0: A = MS(0) - phi = hom(A, "Heilbronn operator(%s,%s)"%(H,t)) + phi = hom(A, "Heilbronn operator(%s,%s)" % (H, t)) return phi rows = [] @@ -1089,17 +1076,17 @@ def __heilbronn_operator(self, M, H, t=1): # Manin symbol [X^i*Y^(k-2-i), (u,v)] for h in H: # Apply h to the polynomial part - (a,b,c,d) = tuple(h) + a, b, c, d = tuple(h) # P gives the ordered coefficients of (a*X+b*Y)^i*(c*X+d*Y)^(j-i) - P = apply_to_monomial(i, k-2, a,b,c,d) + P = apply_to_monomial(i, k-2, a, b, c, d) # Apply h to the (u,v) part of the Manin symbol - (uu,vv) = (u*a+v*c, u*b+v*d) + (uu, vv) = (u*a+v*c, u*b+v*d) # For the generalized Heilbronn operator, we through away any # symbols for which the (u,v) part of the symbol doesn't have # both entries divisible by t. if t != 1: - if uu%t != 0 or vv%t != 0: + if uu % t != 0 or vv % t != 0: continue uu = uu//t vv = vv//t @@ -1111,13 +1098,13 @@ def __heilbronn_operator(self, M, H, t=1): # into the image space M and add that to z. # Note that we coerce in Manin symbols as tuples. for m in range(len(P)): - x = M((m,uu,vv)) + x = M((m, uu, vv)) z += x*P[m] rows.append(z.element()) A = MS(rows) - return hom(A, "Heilbronn operator(%s,%s)"%(H,t)) + return hom(A, "Heilbronn operator(%s,%s)" % (H, t)) def _repr_(self): r""" @@ -1129,8 +1116,8 @@ def _repr_(self): sage: m # indirect doctest Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field """ - return "Modular Symbols space of dimension %s and weight %s for %s with sign %s and character %s over %s"%( - self.dimension(), self.weight(), self.group(), self.sign(), self.character()._repr_short_(), self.base_ring()) + return "Modular Symbols space of dimension %s and weight %s for %s with sign %s and character %s over %s" % ( + self.dimension(), self.weight(), self.group(), self.sign(), self.character()._repr_short_(), self.base_ring()) def _latex_(self): r""" @@ -1146,12 +1133,11 @@ def _latex_(self): sage: m = ModularSymbols(chi) sage: latex(m) \mathrm{ModSym}_{2}(\Gamma_1(7),\left[\zeta_{6}\right];\Bold{Q}(\zeta_{6})) - """ - return "\\mathrm{ModSym}_{%s}(%s,%s;%s)"%(self.weight(), - latex(self.group()), - latex(list(self.character().values_on_gens())), - latex(self.base_ring())) + return "\\mathrm{ModSym}_{%s}(%s,%s;%s)" % (self.weight(), + latex(self.group()), + latex(list(self.character().values_on_gens())), + latex(self.base_ring())) def _matrix_of_operator_on_modular_symbols(self, codomain, R): r""" @@ -1336,9 +1322,9 @@ def boundary_map(self): E = [x.element() for x in I] zero = self.base_ring()(0) n = int(B.dimension()) - E = sum([ list(x) + [zero]*(n - len(x)) for x in E ], []) + E = sum([list(x) + [zero]*(n - len(x)) for x in E], []) - A = W( E ) + A = W(E) H = Hom(self, B) self.__boundary_map = H(A, "boundary map") return self.__boundary_map @@ -1417,7 +1403,7 @@ def cuspidal_submodule(self): if self.base_ring().characteristic() == 0: d = self._cuspidal_submodule_dimension_formula() if d is not None: - assert d == S.dimension(), "According to dimension formulas the cuspidal subspace of \"%s\" has dimension %s; however, computing it using modular symbols we obtained %s, so there is a bug (please report!)."%(self, d, S.dimension()) + assert d == S.dimension(), "According to dimension formulas the cuspidal subspace of \"%s\" has dimension %s; however, computing it using modular symbols we obtained %s, so there is a bug (please report!)." % (self, d, S.dimension()) self.__cuspidal_submodule = S return self.__cuspidal_submodule @@ -1524,7 +1510,7 @@ def _degeneracy_lowering_matrix(self, M, t): # Use Proposition 2.6.15 in Merel's 1585 paper (or Prop 15 in # electronic version of that paper). H = heilbronn.HeilbronnMerel(t) - return self.__heilbronn_operator(M,H,t).matrix() + return self.__heilbronn_operator(M, H, t).matrix() def rank(self): """ @@ -1605,7 +1591,7 @@ def element(self, x): if isinstance(x, ManinSymbol): if not x.parent().weight() == self.weight(): raise ArithmeticError("incompatible weights: Manin symbol\ - has weight %s, but modular symbols space has weight %s"%( + has weight %s, but modular symbols space has weight %s" % ( x.parent().weight(), self.weight())) t = self.manin_symbols().index(x.tuple()) if isinstance(t, tuple): @@ -1619,11 +1605,11 @@ def element(self, x): M = x.parent() if M.ambient_hecke_module() != self: # TODO -- sometimes do something more sophisticated here. - raise TypeError("Modular symbol (%s) does not lie in this space."%x) + raise TypeError("Modular symbol (%s) does not lie in this space." % x) return self(x.element()) else: - raise ValueError("Cannot create element of %s from %s."%(x,self)) + raise ValueError("Cannot create element of %s from %s." % (x, self)) def dual_star_involution_matrix(self): """ @@ -1776,7 +1762,7 @@ def factorization(self): # We only run through spaces of level a multiple of the conductor of the character, which # we compute below, or set to 1 in case of Gamma_H or Gamma_1 chi = self.character() - cond = 1 if chi is None else chi.conductor() + cond = 1 if chi is None else chi.conductor() # Now actually run through the divisor levels, taking only the ones with that are # a multiple of the conductor. for d in reversed(divisors(self.level())): @@ -1789,18 +1775,18 @@ def factorization(self): if self.sign() == 0: V = A.plus_submodule() V._is_simple = True - D.append((V,n)) + D.append((V, n)) if skip_minus: continue V = A.minus_submodule() V._is_simple = True - D.append((V,n)) + D.append((V, n)) else: A._is_simple = True - D.append((A,n)) + D.append((A, n)) # The eisenstein part for E in self.eisenstein_submodule().decomposition(anemic=True): - D.append((E,1)) + D.append((E, 1)) r = self.dimension() s = sum(A.rank() * mult for A, mult in D) @@ -1855,7 +1841,7 @@ def is_eisenstein(self): return self.__is_eisenstein except AttributeError: S = self.ambient_hecke_module().eisenstein_submodule() - self.__is_eisenstein = self.dimension()==S.dimension() + self.__is_eisenstein = self.dimension() == S.dimension() return self.__is_eisenstein def manin_symbols_basis(self): @@ -1964,7 +1950,6 @@ def modular_symbols_of_sign(self, sign): return self return modsym.ModularSymbols(self.group(), self.weight(), sign=sign, base_ring=self.base_ring()) - def modular_symbols_of_weight(self, k): r""" Return a space of modular symbols with the same defining @@ -2100,7 +2085,7 @@ def _compute_diamond_matrix(self, d): sage: ModularSymbols(Gamma1(13), 5).diamond_bracket_operator(6).charpoly().factor() (x^2 + 1)^8 * (x^4 - x^2 + 1)^10 """ - return self.__heilbronn_operator(self, [[d,0, 0,d]], 1).matrix() * d**(2 - self.weight()) + return self.__heilbronn_operator(self, [[d, 0, 0, d]], 1).matrix() * d**(2 - self.weight()) def submodule(self, M, dual_free_module=None, check=True): r""" @@ -2150,7 +2135,7 @@ def submodule(self, M, dual_free_module=None, check=True): if check: if not is_FreeModule(M): V = self.free_module() - if not isinstance(M, (list,tuple)): + if not isinstance(M, (list, tuple)): M = M.gens() M = V.span([V(x.element()) for x in M]) return subspace.ModularSymbolsSubspace(self, M, dual_free_module=dual_free_module, check=check) @@ -2303,7 +2288,7 @@ def integral_structure(self, algorithm='default'): elif algorithm == 'padic': B = B.echelon_form(algorithm='padic', include_zero_rows=False) else: - raise ValueError("unknown algorithm '%s'"%algorithm) + raise ValueError("unknown algorithm '%s'" % algorithm) W = B.row_module() if d != 1: W = W.scale(1/d) @@ -2380,7 +2365,7 @@ class of cuspidal newforms in this ambient space. B = [A.dual_free_module().basis_matrix().transpose() for A in D] # Normalize the names strings. - names = ['%s%s'%(names,i) for i in range(len(B))] + names = ['%s%s' % (names, i) for i in range(len(B))] # Find an integer i such that the i-th columns of the basis for the # dual modules corresponding to the factors in D are all nonzero. @@ -2615,7 +2600,6 @@ def __init__(self, N, k, sign, F, custom_init=None, category=None): sign=sign, base_ring=F, custom_init=custom_init, category=category) - def _dimension_formula(self): r""" Return the dimension of this space using the formula. @@ -2635,7 +2619,7 @@ def _dimension_formula(self): if k % 2: return 0 elif k > 2: - return 2*self.group().dimension_cusp_forms(k) + self.group().ncusps() + return 2 * self.group().dimension_cusp_forms(k) + self.group().ncusps() else: return 2*self.group().dimension_cusp_forms(k) + self.group().ncusps() - 1 else: @@ -2652,7 +2636,7 @@ def _repr_(self): Modular Symbols space of dimension 32 for Gamma_0(37) of weight 6 with sign 0 over Rational Field """ return ("Modular Symbols space of dimension %s for Gamma_0(%s) of weight %s with sign %s " + - "over %s") % (self.dimension(), self.level(),self.weight(), self.sign(), + "over %s") % (self.dimension(), self.level(), self.weight(), self.sign(), self.base_ring()) def _cuspidal_submodule_dimension_formula(self): @@ -2677,7 +2661,6 @@ def _cuspidal_submodule_dimension_formula(self): else: raise NotImplementedError - def _degeneracy_raising_matrix_1(self, M): r""" Return the matrix of the degeneracy map (with t = 1) to level @@ -2733,13 +2716,12 @@ def _degeneracy_raising_matrix_1(self, M): # We apply each matrix in H according to the above formula for h in H: hg = h*g - z += M((i, hg[1,0], hg[1,1])) + z += M((i, hg[1, 0], hg[1, 1])) rows.append(z.element()) A = MS(rows) return A - def _cuspidal_new_submodule_dimension_formula(self): r""" Return the dimension of the new cuspidal subspace, via the formula. @@ -2845,7 +2827,7 @@ def _hecke_images(self, i, v): # the kernel of the dual space corresponding to self. c = self.manin_generators()[self.manin_basis()[i]] N = self.level() - return heilbronn.hecke_images_gamma0_weight_k(c.u,c.v, c.i, N, self.weight(), + return heilbronn.hecke_images_gamma0_weight_k(c.u, c.v, c.i, N, self.weight(), v, self.manin_gens_to_basis()) @cached_method @@ -2982,7 +2964,6 @@ def _cuspidal_new_submodule_dimension_formula(self): else: raise NotImplementedError - def _compute_hecke_matrix_prime(self, p, rows=None): r""" Compute and return the matrix of the `p`-th Hecke operator. @@ -3019,8 +3000,8 @@ def _compute_hecke_matrix_prime(self, p, rows=None): tm = verbose("Matrix non-reduced", tm) for i in B: # The following step is where most of the time is spent. - c,d = P1[i] - v = H.apply(c,d, N) + c, d = P1[i] + v = H.apply(c, d, N) # v is now a list of pairs ((c,d),m), where m is the # number of times that (c,d) appears in the image of x @@ -3033,25 +3014,25 @@ def _compute_hecke_matrix_prime(self, p, rows=None): # s, and the image of x under T_p is the product # of s with the matrix R defined above. for z, m in v: - k = P1.index_of_normalized_pair(z[0],z[1]) + k = P1.index_of_normalized_pair(z[0], z[1]) if k != -1: f, s = mod2term[k] if s != 0: - W[j,f] = W[j,f] + s*m + W[j, f] = W[j, f] + s*m j += 1 - tm = verbose("done making non-reduced matrix",tm) - verbose("start matrix-matrix (%s x %s) times (%s x %s) multiply to get Tp"%(W.nrows(), W.ncols(), - R.nrows(), R.ncols())) + tm = verbose("done making non-reduced matrix", tm) + verbose("start matrix-matrix (%s x %s) times (%s x %s) multiply to get Tp" % (W.nrows(), W.ncols(), + R.nrows(), R.ncols())) if hasattr(W, '_matrix_times_matrix_dense'): Tp = W._matrix_times_matrix_dense(R) - verbose("done matrix multiply and computing Hecke operator",tm) + verbose("done matrix multiply and computing Hecke operator", tm) else: Tp = W * R - tm = verbose("done multiplying",tm) + tm = verbose("done multiplying", tm) Tp = Tp.dense_matrix() verbose("done making Hecke operator dense", tm) if rows is None: - self._hecke_matrices[(p,rows)] = Tp + self._hecke_matrices[(p, rows)] = Tp return Tp def boundary_space(self): @@ -3099,7 +3080,8 @@ def _hecke_image_of_ith_basis_vector(self, n, i): """ c = self.manin_generators()[self.manin_basis()[i]] N = self.level() - I = heilbronn.hecke_images_gamma0_weight2(c.u,c.v,N,[n], self.manin_gens_to_basis()) + I = heilbronn.hecke_images_gamma0_weight2(c.u, c.v, N, [n], + self.manin_gens_to_basis()) return self(I[0]) def _hecke_images(self, i, v): @@ -3139,7 +3121,8 @@ def _hecke_images(self, i, v): # the kernel of the dual space corresponding to self. c = self.manin_generators()[self.manin_basis()[i]] N = self.level() - return heilbronn.hecke_images_gamma0_weight2(c.u,c.v,N, v, self.manin_gens_to_basis()) + return heilbronn.hecke_images_gamma0_weight2(c.u, c.v, N, v, + self.manin_gens_to_basis()) class ModularSymbolsAmbient_wtk_g1(ModularSymbolsAmbient): @@ -3282,7 +3265,6 @@ def _cuspidal_new_submodule_dimension_formula(self): m = 1 return m * self.group().dimension_new_cusp_forms(self.weight()) - def _compute_hecke_matrix_prime_power(self, p, r): r""" Compute and return the matrix of the Hecke operator `T(p^r)`. @@ -3342,7 +3324,7 @@ def _degeneracy_raising_matrix_1(self, M): # We apply each matrix in H according to the above formula for h in H: hg = h*g - z += M((i, hg[1,0], hg[1,1])) + z += M((i, hg[1, 0], hg[1, 1])) rows.append(z.element()) A = MS(rows) @@ -3746,8 +3728,10 @@ def _degeneracy_raising_matrix_1(self, M): syms = self.manin_symbols() G = MatrixSpace(ZZ, 2) H = [G(h) for h in H] - eps = self.character() # note: in my thesis I twisted by eps^(-1), which is definitely a mistake - # since twisting by eps gives the right answer and by eps^(-1) does not. + eps = self.character() + # note: in my thesis I twisted by eps^(-1), which is definitely a mistake + # since twisting by eps gives the right answer and by eps^(-1) does not. + for n in B: z = M(0) s = syms.manin_symbol(n) @@ -3755,8 +3739,8 @@ def _degeneracy_raising_matrix_1(self, M): i = s.i # We apply each matrix in H according to the above formula for h in H: - hg = h*g - z += eps(h[0,0])*M((i, hg[1,0], hg[1,1])) + hg = h * g + z += eps(h[0, 0]) * M((i, hg[1, 0], hg[1, 1])) rows.append(z.element()) A = MS(rows) return A @@ -3842,7 +3826,7 @@ def modular_symbols_of_level(self, N): elif N % self.level() == 0: eps = self.character().extend(N) else: - raise ValueError("The level N (=%s) must be a divisor or multiple of the modulus of the character (=%s)"%(N, self.level())) + raise ValueError("The level N (=%s) must be a divisor or multiple of the modulus of the character (=%s)" % (N, self.level())) return modsym.ModularSymbols(eps, self.weight(), self.sign(), self.base_ring()) def modular_symbols_of_sign(self, sign): @@ -3932,16 +3916,14 @@ def _hecke_images(self, i, v): [ 0 1 1 -1 -1 0 -1 1 1 0 1 2 0 -2 2] """ if self.weight() != 2: - raise NotImplementedError("hecke images only implemented when the weight is 2") + raise NotImplementedError("Hecke images only implemented when the weight is 2") chi = self.character() # Find basis vector for ambient space such that it is not in # the kernel of the dual space corresponding to self. c = self.manin_generators()[self.manin_basis()[i]] N = self.level() if chi.order() > 2: - return heilbronn.hecke_images_nonquad_character_weight2(c.u,c.v,N, - v, chi, self.manin_gens_to_basis()) - else: - return heilbronn.hecke_images_quad_character_weight2(c.u,c.v,N, - v, chi, self.manin_gens_to_basis()) - raise NotImplementedError + return heilbronn.hecke_images_nonquad_character_weight2(c.u, c.v, N, + v, chi, self.manin_gens_to_basis()) + return heilbronn.hecke_images_quad_character_weight2(c.u, c.v, N, + v, chi, self.manin_gens_to_basis()) diff --git a/src/sage/modular/modsym/apply.pyx b/src/sage/modular/modsym/apply.pyx index ff22f208c00..40488868b37 100644 --- a/src/sage/modular/modsym/apply.pyx +++ b/src/sage/modular/modsym/apply.pyx @@ -43,7 +43,7 @@ cdef class Apply: cdef int apply_to_monomial_flint(self, fmpz_poly_t ans, int i, int j, int a, int b, int c, int d) except -1: if i < 0 or j - i < 0: - raise ValueError("i (=%s) and j-i (=%s) must both be nonnegative."%(i,j-i)) + raise ValueError("i (=%s) and j-i (=%s) must both be nonnegative." % (i, j - i)) # f = b+a*x, g = d+c*x fmpz_poly_set_coeff_si(self.f, 0, b) @@ -61,6 +61,7 @@ cdef class Apply: cdef Apply A = Apply() + def apply_to_monomial(int i, int j, int a, int b, int c, int d): r""" Return a list of the coefficients of @@ -102,7 +103,7 @@ def apply_to_monomial(int i, int j, int a, int b, int c, int d): cdef Integer res v = [] - for k from 0 <= k <= j: + for k in range(j + 1): res = <Integer>PY_NEW(Integer) fmpz_poly_get_coeff_mpz(res.value, pr, k) v.append(int(res)) diff --git a/src/sage/modular/modsym/boundary.py b/src/sage/modular/modsym/boundary.py index ec41f8c36dd..208371b9deb 100644 --- a/src/sage/modular/modsym/boundary.py +++ b/src/sage/modular/modsym/boundary.py @@ -101,7 +101,8 @@ import sage.modular.hecke.all as hecke from sage.modular.modsym.manin_symbol import ManinSymbol -import sage.rings.all as rings +from sage.rings.rational_field import Q as QQ +from sage.rings.ring import Ring from . import element @@ -237,7 +238,7 @@ def _rmul_(self, other): """ x = {} for i, c in self.__x.items(): - x[i] = c*other + x[i] = c * other return BoundarySpaceElement(self.parent(), x) def _lmul_(self, other): @@ -258,7 +259,7 @@ def _lmul_(self, other): """ x = {} for i, c in self.__x.items(): - x[i] = other*c + x[i] = other * c return BoundarySpaceElement(self.parent(), x) def __neg__(self): @@ -283,7 +284,7 @@ def __init__(self, group=arithgroup.Gamma0(1), weight=2, sign=0, - base_ring=rings.QQ, + base_ring=QQ, character=None): """ Space of boundary symbols for a congruence subgroup of SL_2(Z). @@ -319,13 +320,13 @@ def __init__(self, if not arithgroup.is_CongruenceSubgroup(group): raise TypeError("group must be a congruence subgroup") sign = int(sign) - if not isinstance(base_ring, rings.Ring) and rings.is_CommutativeRing(base_ring): + if not isinstance(base_ring, Ring): raise TypeError("base_ring must be a commutative ring") if character is None and arithgroup.is_Gamma0(group): character = dirichlet.TrivialCharacter(group.level(), base_ring) (self.__group, self.__weight, self.__character, - self.__sign, self.__base_ring) = (group, weight, - character, sign, base_ring) + self.__sign, self.__base_ring) = (group, weight, + character, sign, base_ring) self._known_gens = [] self._zero_cusps = [] hecke.HeckeModule_generic.__init__(self, base_ring, group.level()) @@ -443,7 +444,7 @@ def gen(self, i=0): """ if i >= len(self._known_gens) or i < 0: raise ValueError("only %s generators known for %s" % (len(self._known_gens), self)) - return BoundarySpaceElement(self, {i:1}) + return BoundarySpaceElement(self, {i: 1}) def free_module(self): """ @@ -558,7 +559,7 @@ def __call__(self, x): if not isinstance(M, ModularSymbolsAmbient): raise TypeError("x (=%s) must be an element of a space of modular symbols of type ModularSymbolsAmbient" % x) if M.level() != self.level(): - raise TypeError("x (=%s) must have level %s but has level %s"%( + raise TypeError("x (=%s) must have level %s but has level %s" % ( x, self.level(), M.level())) S = x.manin_symbol_rep() if len(S) == 0: @@ -697,7 +698,7 @@ def _coerce_cusp(self, c): if i != -1: if i == -2: return self(0) - return BoundarySpaceElement(self, {i:1}) + return BoundarySpaceElement(self, {i: 1}) # see if we've already found -c sign = self.sign() @@ -707,7 +708,7 @@ def _coerce_cusp(self, c): if i2 == -2: return self(0) else: - return BoundarySpaceElement(self, {i2:sign}) + return BoundarySpaceElement(self, {i2: sign}) # found a new cusp class g = self._known_gens @@ -743,7 +744,7 @@ def _coerce_cusp(self, c): del self._known_gens[-1] return self(0) - return BoundarySpaceElement(self, {(len(g)-1):1}) + return BoundarySpaceElement(self, {(len(g) - 1): 1}) def _is_equiv(self, c1, c2): """ @@ -896,15 +897,15 @@ def _coerce_cusp(self, c): sage: [ B(Cusp(i,7)) for i in range(7) ] [0, [1/7], [2/7], [3/7], -[3/7], -[2/7], -[1/7]] """ - N = self.level() - k = self.weight() + N = self.level() + k = self.weight() sign = self.sign() i, eps = self._cusp_index(c) if i != -1: if i == -2: return self(0) else: - return BoundarySpaceElement(self, {i : eps**k}) + return BoundarySpaceElement(self, {i: eps**k}) if sign != 0: i2, eps = self._cusp_index(-c) @@ -912,7 +913,7 @@ def _coerce_cusp(self, c): if i2 == -2: return self(0) else: - return BoundarySpaceElement(self, {i2:sign*(eps**k)}) + return BoundarySpaceElement(self, {i2: sign * (eps**k)}) # found a new cusp class g = self._known_gens @@ -922,7 +923,7 @@ def _coerce_cusp(self, c): # this occurs if and only if N = 4 and c is equivalent to 1/2. if N == 4 and k % 2: - if self._is_equiv(c, (1,2))[0]: + if self._is_equiv(c, (1, 2))[0]: self._zero_cusps.append(c) del self._known_gens[-1] return self(0) @@ -946,10 +947,10 @@ def _coerce_cusp(self, c): # if sign: if (c.is_infinity() and sign != (-1)**self.weight()) or \ - (c.is_zero() and sign == -1): - self._zero_cusps.append(c) - del self._known_gens[-1] - return self(0) + (c.is_zero() and sign == -1): + self._zero_cusps.append(c) + del self._known_gens[-1] + return self(0) elif (not c.is_infinity() and not c.is_zero()): t, eps = self._is_equiv(c, -c) if t and ((eps == 1 and sign == -1) or @@ -958,7 +959,7 @@ def _coerce_cusp(self, c): del self._known_gens[-1] return self(0) - return BoundarySpaceElement(self, {(len(g)-1): 1}) + return BoundarySpaceElement(self, {(len(g) - 1): 1}) class BoundarySpace_wtk_gamma_h(BoundarySpace): @@ -1146,14 +1147,14 @@ def _coerce_cusp(self, c): sage: S.dimension() 8 """ - k = self.weight() + k = self.weight() sign = self.sign() i, eps = self._cusp_index(c) if i != -1: if i == -2: return self(0) else: - return BoundarySpaceElement(self, {i : eps**k}) + return BoundarySpaceElement(self, {i: eps**k}) if sign != 0: i2, eps = self._cusp_index(-c) @@ -1161,7 +1162,7 @@ def _coerce_cusp(self, c): if i2 == -2: return self(0) else: - return BoundarySpaceElement(self, {i2:sign*(eps**k)}) + return BoundarySpaceElement(self, {i2: sign * (eps**k)}) # found a new cusp class g = self._known_gens @@ -1211,7 +1212,7 @@ def _coerce_cusp(self, c): del self._known_gens[-1] return self(0) - return BoundarySpaceElement(self, {(len(g)-1): 1}) + return BoundarySpaceElement(self, {(len(g) - 1): 1}) class BoundarySpace_wtk_eps(BoundarySpace): @@ -1392,7 +1393,7 @@ def _coerce_cusp(self, c): # Does cusp vanish because of stabiliser? s = arithgroup.Gamma0(self.level()).cusp_data(c)[0] - if self.__eps(s[1,1]) != 1: + if self.__eps(s[1, 1]) != 1: self._zero_cusps.append(c) del self._known_gens[-1] return self(0) @@ -1430,4 +1431,4 @@ def _coerce_cusp(self, c): del self._known_gens[-1] return self(0) - return BoundarySpaceElement(self, {(len(g)-1):1}) + return BoundarySpaceElement(self, {(len(g) - 1): 1}) diff --git a/src/sage/modular/modsym/element.py b/src/sage/modular/modsym/element.py index cc81faad50d..df08763459d 100644 --- a/src/sage/modular/modsym/element.py +++ b/src/sage/modular/modsym/element.py @@ -1,8 +1,7 @@ """ A single element of an ambient space of modular symbols """ - -#***************************************************************************** +# **************************************************************************** # Sage: Open Source Mathematical Software # # Copyright (C) 2005 William Stein <wstein@gmail.com> @@ -16,9 +15,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** import sage.modules.free_module_element from sage.misc.repr import repr_lincomb @@ -26,9 +24,11 @@ import sage.modular.hecke.all as hecke import sage.misc.latex as latex + _print_mode = "manin" -def is_ModularSymbolsElement(x): + +def is_ModularSymbolsElement(x) -> bool: r""" Return True if x is an element of a modular symbols space. @@ -80,6 +80,7 @@ def set_modsym_print_mode(mode="manin"): global _print_mode _print_mode = mode + class ModularSymbolsElement(hecke.HeckeModuleElement): """ An element of a space of modular symbols. @@ -117,7 +118,7 @@ def __init__(self, parent, x, check=True): if not isinstance(x, sage.modules.free_module_element.FreeModuleElement): raise TypeError("x must be a free module element.") if x.degree() != parent.degree(): - raise TypeError("x (of degree %s) must be of degree the same as the degree of the parent (of degree %s)."%(x.degree(), parent.degree())) + raise TypeError("x (of degree %s) must be of degree the same as the degree of the parent (of degree %s)." % (x.degree(), parent.degree())) hecke.HeckeModuleElement.__init__(self, parent, x) def _repr_(self): @@ -143,7 +144,7 @@ def _repr_(self): m = self.manin_symbol_rep() elif _print_mode == "modular": m = self.modular_symbol_rep() - return repr_lincomb([(t,c) for c,t in m]) + return repr_lincomb([(t, c) for c, t in m]) def _latex_(self): r""" @@ -204,7 +205,8 @@ def _rmul_(self, other): ... TypeError: unsupported operand parent(s) for *: 'Modular Symbols space of dimension 8 for Gamma_0(3) of weight 12 with sign 0 over Rational Field' and 'Ring of integers modulo 17' """ - return ModularSymbolsElement(self.parent(), self.element()*other, check=False) + return ModularSymbolsElement(self.parent(), self.element() * other, + check=False) def _lmul_(self, left): r""" @@ -222,7 +224,8 @@ def _lmul_(self, left): ... TypeError: unsupported operand parent(s) for *: 'Ring of integers modulo 17' and 'Modular Symbols space of dimension 8 for Gamma_0(3) of weight 12 with sign 0 over Rational Field' """ - return ModularSymbolsElement(self.parent(), left*self.element(), check=False) + return ModularSymbolsElement(self.parent(), left * self.element(), + check=False) def _neg_(self): r""" diff --git a/src/sage/modular/modsym/g1list.py b/src/sage/modular/modsym/g1list.py index 87e86e94814..4485a52814a 100644 --- a/src/sage/modular/modsym/g1list.py +++ b/src/sage/modular/modsym/g1list.py @@ -2,7 +2,7 @@ List of coset representatives for `\Gamma_1(N)` in `\SL_2(\ZZ)` """ -#***************************************************************************** +# **************************************************************************** # Sage: Open Source Mathematical Software # # Copyright (C) 2005 William Stein <wstein@gmail.com> @@ -16,8 +16,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.arith.misc import GCD from sage.structure.richcmp import richcmp_method, richcmp @@ -96,12 +96,13 @@ def __repr__(self): sage: L = sage.modular.modsym.g1list.G1list(3); L.__repr__() 'List of coset representatives for Gamma_1(3) in SL_2(Z)' """ - return "List of coset representatives for Gamma_1(%s) in SL_2(Z)"%self.__N + return f"List of coset representatives for Gamma_1({self.__N}) in SL_2(Z)" def list(self): r""" - Return a list of vectors representing the cosets. Do not change the - returned list! + Return a list of vectors representing the cosets. + + Do not change the returned list! EXAMPLES:: @@ -169,7 +170,8 @@ def __setstate__(self, state): # We don't really want this class, but we want to handle new # pickles without creating a new class self.__class__ = G1list - self.__dict__ = state # Default pickling is ``state = self.__dict__`` + self.__dict__ = state # Default pickling is ``state = self.__dict__`` + register_unpickle_override('sage.modular.modsym.g1list', 'G1list', _G1list_old_pickle) diff --git a/src/sage/modular/modsym/ghlist.py b/src/sage/modular/modsym/ghlist.py index 38cdc8ff2b4..bd15cc505b5 100644 --- a/src/sage/modular/modsym/ghlist.py +++ b/src/sage/modular/modsym/ghlist.py @@ -173,7 +173,8 @@ def __setstate__(self, state): # We don't really want this class, but we want to handle new # pickles without creating a new class self.__class__ = GHlist - self.__dict__ = state # Default pickling is ``state = self.__dict__`` + self.__dict__ = state # Default pickling is ``state = self.__dict__`` + register_unpickle_override('sage.modular.modsym.ghlist', 'GHlist', _GHlist_old_pickle) diff --git a/src/sage/modular/modsym/heilbronn.pyx b/src/sage/modular/modsym/heilbronn.pyx index 2ba337dddc4..45f0921034d 100644 --- a/src/sage/modular/modsym/heilbronn.pyx +++ b/src/sage/modular/modsym/heilbronn.pyx @@ -34,14 +34,13 @@ cdef extern from "<math.h>": float roundf(float x) cimport sage.modular.modsym.p1list as p1list -from . import p1list +from . import p1list cdef p1list.export export export = p1list.export() from .apply cimport Apply cdef Apply PolyApply= Apply() -from sage.rings.integer cimport Integer from sage.matrix.matrix_rational_dense cimport Matrix_rational_dense from sage.matrix.matrix_cyclo_dense cimport Matrix_cyclo_dense @@ -49,7 +48,7 @@ ctypedef long long llong cdef int llong_prod_mod(int a, int b, int N): cdef int c - c = <int> ( ((<llong> a) * (<llong> b)) % (<llong> N) ) + c = <int> (((<llong> a) * (<llong> b)) % (<llong> N)) if c < 0: c = c + N return c @@ -112,7 +111,8 @@ cdef class Heilbronn: EXAMPLES:: - sage: H = sage.modular.modsym.heilbronn.Heilbronn() + sage: from sage.modular.modsym.heilbronn import Heilbronn + sage: H = Heilbronn() sage: H._initialize_list() Traceback (most recent call last): ... @@ -198,12 +198,12 @@ cdef class Heilbronn: a[i] = b[i] = 0 if N < 32768: # use ints with no reduction modulo N for i in range(self.length): - a[i] = u*self.list.v[4*i] + v*self.list.v[4*i+2] - b[i] = u*self.list.v[4*i+1] + v*self.list.v[4*i+3] + a[i] = u * self.list.v[4*i] + v * self.list.v[4*i+2] + b[i] = u * self.list.v[4*i+1] + v * self.list.v[4*i+3] elif N < 46340: # use ints but reduce mod N so can add two for i in range(self.length): - a[i] = (u * self.list.v[4*i])%N + (v * self.list.v[4*i+2])%N - b[i] = (u * self.list.v[4*i+1])%N + (v * self.list.v[4*i+3])%N + a[i] = (u * self.list.v[4*i]) % N + (v * self.list.v[4*i+2]) % N + b[i] = (u * self.list.v[4*i+1]) % N + (v * self.list.v[4*i+3]) % N else: for i in range(self.length): a[i] = llong_prod_mod(u,self.list.v[4*i],N) + llong_prod_mod(v,self.list.v[4*i+2], N) @@ -221,11 +221,13 @@ cdef class Heilbronn: OUTPUT: sets entries of ans """ - cdef int j, m = k-2 + cdef int j, m = k - 2 for j in range(self.length): PolyApply.apply_to_monomial_flint(ans[j], i, m, - self.list.v[4*j], self.list.v[4*j+1], - self.list.v[4*j+2], self.list.v[4*j+3]) + self.list.v[4 * j], + self.list.v[4 * j + 1], + self.list.v[4 * j + 2], + self.list.v[4 * j + 3]) def apply(self, int u, int v, int N): """ @@ -332,7 +334,7 @@ cdef class HeilbronnCremona(Heilbronn): sage: HeilbronnCremona(691).__repr__() 'The Cremona-Heilbronn matrices of determinant 691' """ - return "The Cremona-Heilbronn matrices of determinant %s"%self.p + return f"The Cremona-Heilbronn matrices of determinant {self.p}" def _initialize_list(self): """ @@ -342,6 +344,7 @@ cdef class HeilbronnCremona(Heilbronn): EXAMPLES:: + sage: from sage.modular.modsym.heilbronn import HeilbronnCremona sage: H = HeilbronnCremona.__new__(HeilbronnCremona) sage: H.p = 5 sage: H @@ -363,7 +366,7 @@ cdef class HeilbronnCremona(Heilbronn): [-2, 1, 1, -3], [1, 0, -3, 5]] """ - cdef int r, x1, x2, y1, y2, a, b, c, x3, y3, q, n, p + cdef int r, x1, x2, y1, y2, a, b, c, x3, y3, q, p cdef list *L list_init(&self.list) L = &self.list @@ -456,6 +459,7 @@ cdef class HeilbronnMerel(Heilbronn): EXAMPLES:: + sage: from sage.modular.modsym.heilbronn import HeilbronnMerel sage: H = HeilbronnMerel.__new__(HeilbronnMerel) sage: H.n = 5 sage: H @@ -799,8 +803,8 @@ def hecke_images_quad_character_weight2(int u, int v, int N, indices, chi, R): cdef int k, scalar cdef Heilbronn H - t = verbose("computing non-reduced images of symbol under Hecke operators", - level=1, caller_name='hecke_images_quad_character_weight2') + _ = verbose("computing non-reduced images of symbol under Hecke operators", + level=1, caller_name='hecke_images_quad_character_weight2') # Make a matrix over the rational numbers each of whose columns # are the values of the character chi. @@ -839,13 +843,11 @@ def hecke_images_quad_character_weight2(int u, int v, int N, indices, chi, R): return T * R - - -############################################################################ +# ########################################################################## # Fast application of Heilbronn operators to computation of # systems of Hecke eigenvalues. # Trivial character and weight > 2. -############################################################################ +# ########################################################################## def hecke_images_gamma0_weight_k(int u, int v, int i, int N, int k, indices, R): """ @@ -897,7 +899,6 @@ def hecke_images_gamma0_weight_k(int u, int v, int i, int N, int k, indices, R): cdef Heilbronn H cdef fmpz_poly_t* poly - cdef Integer coeff = Integer() for z, m in enumerate(indices): H = HeilbronnCremona(m) if is_prime(m) else HeilbronnMerel(m) diff --git a/src/sage/modular/modsym/manin_symbol.pyx b/src/sage/modular/modsym/manin_symbol.pyx index 5d6df57c47d..c02c1f26dbf 100644 --- a/src/sage/modular/modsym/manin_symbol.pyx +++ b/src/sage/modular/modsym/manin_symbol.pyx @@ -181,9 +181,8 @@ cdef class ManinSymbol(Element): """ if self.weight() > 2: polypart = _print_polypart(self.i, self.weight()-2-self.i) - return "[%s,(%s,%s)]"%\ - (polypart, self.u, self.v) - return "(%s,%s)"%(self.u, self.v) + return "[%s,(%s,%s)]" % (polypart, self.u, self.v) + return "(%s,%s)" % (self.u, self.v) def _latex_(self): """ diff --git a/src/sage/modular/modsym/manin_symbol_list.py b/src/sage/modular/modsym/manin_symbol_list.py index 182a35ffe32..858fa4a9feb 100644 --- a/src/sage/modular/modsym/manin_symbol_list.py +++ b/src/sage/modular/modsym/manin_symbol_list.py @@ -133,7 +133,7 @@ def symbol_list(self): sage: from sage.modular.modsym.manin_symbol_list import ManinSymbolList sage: m = ManinSymbolList(6, P1List(11)) """ - return list(self._symbol_list) # This makes a shallow copy + return list(self._symbol_list) # This makes a shallow copy def __len__(self): """ @@ -162,11 +162,10 @@ def apply(self, j, X): Traceback (most recent call last): ... NotImplementedError: Only implemented in derived classes - """ raise NotImplementedError("Only implemented in derived classes") - def _apply_S_only_0pm1(self): + def _apply_S_only_0pm1(self) -> bool: """ Return True if the coefficient when applying the S relation is always 0, 1, or -1. This is useful for optimizing code in @@ -183,7 +182,7 @@ def _apply_S_only_0pm1(self): sage: ManinSymbolList_character(eps,2)._apply_S_only_0pm1() False """ - return False # derived classes could overload and put True + return False # derived classes could overload and put True def apply_S(self, j): """ @@ -498,11 +497,8 @@ def apply_S(self, j): (2, 1)] """ i, u, v = self._symbol_list[j] - k = self.index((self._weight-2-i, v, -u)) - if i%2 == 0: - return k, 1 - else: - return k, -1 + k = self.index((self._weight - 2 - i, v, -u)) + return k, -1 if i % 2 else 1 def _apply_S_only_0pm1(self): """ @@ -552,7 +548,7 @@ def apply_I(self, j): """ i, u, v = self._symbol_list[j] k = self.index((i, -u, v)) - if i%2 == 0: + if i % 2 == 0: return k, 1 else: return k, -1 @@ -761,10 +757,9 @@ def __repr__(self): sage: M11 = ManinSymbolList_gamma0(11,2) sage: str(M11) 'Manin Symbol List of weight 2 for Gamma0(11)' - """ - return "Manin Symbol List of weight %s for Gamma0(%s)"%( - self.weight(), self.level()) + return "Manin Symbol List of weight %s for Gamma0(%s)" % ( + self.weight(), self.level()) class ManinSymbolList_gamma1(ManinSymbolList_group): @@ -820,8 +815,8 @@ def __repr__(self): sage: str(M11) 'Manin Symbol List of weight 4 for Gamma1(11)' """ - return "Manin Symbol List of weight %s for Gamma1(%s)"%( - self.weight(), self.level()) + return "Manin Symbol List of weight %s for Gamma1(%s)" % ( + self.weight(), self.level()) class ManinSymbolList_gamma_h(ManinSymbolList_group): @@ -890,8 +885,8 @@ def __repr__(self): sage: ModularSymbols(GammaH(12, [5]), 2).manin_symbols().__repr__() 'Manin Symbol List of weight 2 for Congruence Subgroup Gamma_H(12) with H generated by [5]' """ - return "Manin Symbol List of weight %s for %s"%( - self.weight(), self.group()) + return "Manin Symbol List of weight %s for %s" % ( + self.weight(), self.group()) class ManinSymbolList_character(ManinSymbolList): @@ -967,8 +962,8 @@ def __repr__(self): sage: str(m) # indirect doctest 'Manin Symbol List of weight 2 for Gamma1(4) with character [-1]' """ - return "Manin Symbol List of weight %s for Gamma1(%s) with character %s"%( - self.weight(), self.level(), self.character()._repr_short_()) + return "Manin Symbol List of weight %s for Gamma1(%s) with character %s" % ( + self.weight(), self.level(), self.character()._repr_short_()) def level(self): """ @@ -1028,7 +1023,7 @@ def apply(self, j, m): return [] r = len(self.__P1) return [(m + r*k, s*P[k]) for k in range(self._weight-2+1) - if P[k] != 0] + if P[k] != 0] def apply_S(self, j): """ @@ -1056,8 +1051,8 @@ def apply_S(self, j): [(1, 1), (0, -1), (4, 1), (5, -1), (2, -1), (3, 1)] """ i, u, v = self._symbol_list[j] - k, s = self.index((self._weight-2-i, v, -u)) - if i%2 == 0: + k, s = self.index((self._weight - 2 - i, v, -u)) + if i % 2 == 0: return k, s else: return k, -s @@ -1106,7 +1101,7 @@ def apply_I(self, j): """ i, u, v = self._symbol_list[j] k, s = self.index((i, -u, v)) - if i%2 == 0: + if i % 2 == 0: return k, s else: return k, -s diff --git a/src/sage/modular/modsym/modsym.py b/src/sage/modular/modsym/modsym.py index 0a87eece1d7..d33f61cd928 100644 --- a/src/sage/modular/modsym/modsym.py +++ b/src/sage/modular/modsym/modsym.py @@ -71,7 +71,7 @@ Modular Symbols space of dimension 20460 and level 184137, weight 2, character [2, 2], sign 1, over Finite Field of size 3 """ -#***************************************************************************** +# **************************************************************************** # Sage: Open Source Mathematical Software # # Copyright (C) 2005 William Stein <wstein@gmail.com> @@ -85,15 +85,16 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import weakref import sage.modular.arithgroup.all as arithgroup import sage.modular.dirichlet as dirichlet -import sage.rings.rational_field as rational_field -import sage.rings.all as rings +from sage.rings.integer import Integer +from sage.rings.ring import CommutativeRing +from sage.rings.rational_field import RationalField def canonical_parameters(group, weight, sign, base_ring): @@ -114,15 +115,15 @@ def canonical_parameters(group, weight, sign, base_ring): sage: type(p1[1]) <class 'sage.rings.integer.Integer'> """ - sign = rings.Integer(sign) - if not (sign in [-1,0,1]): + sign = Integer(sign) + if sign not in [-1, 0, 1]: raise ValueError("sign must be -1, 0, or 1") - weight = rings.Integer(weight) + weight = Integer(weight) if weight <= 1: raise ValueError("the weight must be at least 2") - if isinstance(group, (int, rings.Integer)): + if isinstance(group, (int, Integer)): group = arithgroup.Gamma0(group) elif isinstance(group, dirichlet.DirichletCharacter): if group.is_trivial(): @@ -134,18 +135,20 @@ def canonical_parameters(group, weight, sign, base_ring): base_ring = eps.base_ring() if base_ring is None: - base_ring = rational_field.RationalField() + base_ring = RationalField() - if not isinstance(base_ring, rings.CommutativeRing): - raise TypeError("base_ring (=%s) must be a commutative ring"%base_ring) + if not isinstance(base_ring, CommutativeRing): + raise TypeError(f"base_ring (={base_ring}) must be a commutative ring") if not base_ring.is_field(): - raise TypeError("(currently) base_ring (=%s) must be a field"%base_ring) + raise TypeError(f"(currently) base_ring (={base_ring}) must be a field") return group, weight, sign, base_ring + _cache = {} + def ModularSymbols_clear_cache(): """ Clear the global cache of modular symbols spaces. @@ -348,16 +351,16 @@ def ModularSymbols(group=1, if M is not None: return M - (group, weight, sign, base_ring) = key + group, weight, sign, base_ring = key M = None if arithgroup.is_Gamma0(group): - if weight == 2: - M = ambient.ModularSymbolsAmbient_wt2_g0( - group.level(),sign, base_ring, custom_init=custom_init) - else: - M = ambient.ModularSymbolsAmbient_wtk_g0( - group.level(), weight, sign, base_ring, custom_init=custom_init) + if weight == 2: + M = ambient.ModularSymbolsAmbient_wt2_g0( + group.level(), sign, base_ring, custom_init=custom_init) + else: + M = ambient.ModularSymbolsAmbient_wtk_g0( + group.level(), weight, sign, base_ring, custom_init=custom_init) elif arithgroup.is_Gamma1(group): diff --git a/src/sage/modular/modsym/modular_symbols.py b/src/sage/modular/modsym/modular_symbols.py index 504af3a4096..e76694d54e2 100644 --- a/src/sage/modular/modsym/modular_symbols.py +++ b/src/sage/modular/modsym/modular_symbols.py @@ -95,7 +95,7 @@ def _repr_(self): polypart = '' else: polypart = str(self.polynomial_part()) + '*' - return "%s{%s, %s}"%(polypart, self.__alpha, self.__beta) + return "%s{%s, %s}" % (polypart, self.__alpha, self.__beta) def __getitem__(self, j): r""" @@ -132,8 +132,9 @@ def _latex_(self): polypart = '' else: polypart = latex(self.polynomial_part()) - return "%s\\left\\{%s, %s\\right\\}"%(polypart, - latex(self.__alpha), latex(self.__beta)) + return "%s\\left\\{%s, %s\\right\\}" % (polypart, + latex(self.__alpha), + latex(self.__beta)) def __richcmp__(self, other, op): """ diff --git a/src/sage/modular/modsym/p1list.pxd b/src/sage/modular/modsym/p1list.pxd index 1a78ab5923c..b66f28b8ad6 100644 --- a/src/sage/modular/modsym/p1list.pxd +++ b/src/sage/modular/modsym/p1list.pxd @@ -21,9 +21,8 @@ cdef class P1List: # Here we use a pointer to a function, so the if logic # for normalizing an element does not need to be used # every time the user calls the normalize function. - cdef int (*__normalize)(int N, int u, int v,\ + cdef int (*_normalize)(int N, int u, int v, int* uu, int* vv, int* ss, int compute_s) except -1 cpdef index(self, int u, int v) cdef index_and_scalar(self, int u, int v, int* i, int* s) - diff --git a/src/sage/modular/modsym/p1list.pyx b/src/sage/modular/modsym/p1list.pyx index 4cdb7dec577..30a8f7471dd 100644 --- a/src/sage/modular/modsym/p1list.pyx +++ b/src/sage/modular/modsym/p1list.pyx @@ -15,7 +15,7 @@ cimport sage.rings.fast_arith import sage.rings.fast_arith cdef sage.rings.fast_arith.arith_int arith_int cdef sage.rings.fast_arith.arith_llong arith_llong -arith_int = sage.rings.fast_arith.arith_int() +arith_int = sage.rings.fast_arith.arith_int() arith_llong = sage.rings.fast_arith.arith_llong() ctypedef long long llong @@ -108,7 +108,7 @@ cdef int c_p1_normalize_int(int N, int u, int v, Ng = N/g vNg = (v*Ng) % N t = 1 - for k from 2 <= k <= g: + for k in range(2, g + 1): v = (v + vNg) % N t = (t + Ng) % N if v<min_v and arith_int.c_gcd_int(t,N)==1: @@ -166,8 +166,9 @@ def p1_normalize_int(N, u, v): 78 """ cdef int uu, vv, ss - c_p1_normalize_int(N, u%N, v%N, &uu, &vv, &ss, 1) - return (uu,vv,ss) + c_p1_normalize_int(N, u % N, v % N, &uu, &vv, &ss, 1) + return (uu, vv, ss) + def p1list_int(int N): r""" @@ -219,25 +220,25 @@ def p1list_int(int N): lst = [(0,1)] c = 1 - for d from 0 <= d < N: - lst.append((c,d)) + for d in range(N): + lst.append((c, d)) - cmax = N/2 - if N%2: # N odd, max divisor is <= N/3 - if N%3: # N not a multiple of 3 either, max is N/5 - cmax = N/5 + cmax = N // 2 + if N % 2: # N odd, max divisor is <= N/3 + if N % 3: # N not a multiple of 3 either, max is N/5 + cmax = N // 5 else: - cmax = N/3 + cmax = N // 3 - for c from 2 <= c <= cmax: - if N%c == 0: # c is a proper divisor - h = N/c - g = arith_int.c_gcd_int(c,h) - for d from 1 <= d <= h: + for c in range(2, cmax + 1): + if N % c == 0: # c is a proper divisor + h = N // c + g = arith_int.c_gcd_int(c, h) + for d in range(1, h + 1): sig_check() - if arith_int.c_gcd_int(d,g)==1: + if arith_int.c_gcd_int(d, g) == 1: d1 = d - while arith_int.c_gcd_int(d1,c)!=1: + while arith_int.c_gcd_int(d1, c) != 1: d1 += h c_p1_normalize_int(N, c, d1, &u, &v, &s, 0) lst.append((u,v)) @@ -364,7 +365,7 @@ cdef int c_p1_normalize_llong(int N, int u, int v, # Multiply [u,v] by s; then [s*u,s*v] = [g,s*v] (mod N) u = g # v = (s*v) % N - v = <int> ( ((<llong>s) * (<llong>v)) % ll_N ) + v = <int> (((<llong>s) * (<llong>v)) % ll_N) min_v = v min_t = 1 @@ -372,10 +373,10 @@ cdef int c_p1_normalize_llong(int N, int u, int v, Ng = N/g vNg = <int> ((<llong>v * <llong> Ng) % ll_N) t = 1 - for k from 2 <= k <= g: + for k in range(2, g + 1): v = (v + vNg) % N t = (t + Ng) % N - if v<min_v and arith_int.c_gcd_int(t,N)==1: + if v < min_v and arith_int.c_gcd_int(t, N) == 1: min_v = v min_t = t v = min_v @@ -430,8 +431,9 @@ def p1_normalize_llong(N, u, v): 78 """ cdef int uu, vv, ss - c_p1_normalize_llong(N, u%N, v%N, &uu, &vv, &ss, 1) - return (uu,vv,ss) + c_p1_normalize_llong(N, u % N, v % N, &uu, &vv, &ss, 1) + return (uu, vv, ss) + def p1list_llong(int N): r""" @@ -470,28 +472,28 @@ def p1list_llong(int N): lst = [(0,1)] c = 1 - for d from 0 <= d < N: - lst.append((c,d)) + for d in range(N): + lst.append((c, d)) - cmax = N/2 - if N%2: # N odd, max divisor is <= N/3 - if N%3: # N not a multiple of 3 either, max is N/5 - cmax = N/5 + cmax = N // 2 + if N % 2: # N odd, max divisor is <= N/3 + if N % 3: # N not a multiple of 3 either, max is N/5 + cmax = N // 5 else: - cmax = N/3 - - for c from 2 <= c <= cmax: - if N%c == 0: # c is a proper divisor - h = N/c - g = arith_int.c_gcd_int(c,h) - for d from 1 <= d <= h: - if arith_int.c_gcd_int(d,g)==1: + cmax = N // 3 + + for c in range(2, cmax + 1): + if N % c == 0: # c is a proper divisor + h = N // c + g = arith_int.c_gcd_int(c, h) + for d in range(1, h + 1): + if arith_int.c_gcd_int(d, g) == 1: sig_check() d1 = d - while arith_int.c_gcd_int(d1,c)!=1: + while arith_int.c_gcd_int(d1, c) != 1: d1 += h c_p1_normalize_llong(N, c, d1, &u, &v, &s, 0) - lst.append((u,v)) + lst.append((u, v)) lst.sort() return lst @@ -586,6 +588,7 @@ def p1_normalize(int N, int u, int v): else: raise OverflowError + cdef int p1_normalize_xgcdtable(int N, int u, int v, int compute_s, int *t_g, int *t_a, int *t_b, @@ -623,7 +626,7 @@ cdef int p1_normalize_xgcdtable(int N, int u, int v, v += N if u == 0: uu[0] = 0 - if t_g[v] == 1: # "if arith_int.c_gcd_int(v,N) == 1" + if t_g[v] == 1: # "if arith_int.c_gcd_int(v,N) == 1" vv[0] = 1 else: vv[0] = 0 @@ -660,10 +663,10 @@ cdef int p1_normalize_xgcdtable(int N, int u, int v, Ng = N/g vNg = (v*Ng) % N t = 1 - for k from 2 <= k <= g: + for k in range(2, g + 1): v = (v + vNg) % N t = (t + Ng) % N - if v<min_v and t_g[t] == 1: #arith_int.c_gcd_int(t,N)==1: + if v < min_v and t_g[t] == 1: # arith_int.c_gcd_int(t,N)==1: min_v = v min_t = t v = min_v @@ -674,8 +677,8 @@ cdef int p1_normalize_xgcdtable(int N, int u, int v, uu[0] = u vv[0] = v if compute_s: - #ss[0] = arith_int.c_inverse_mod_int(s*min_t, N); - ss[0] = t_a[(s*min_t)%N] + # ss[0] = arith_int.c_inverse_mod_int(s*min_t, N); + ss[0] = t_a[(s*min_t) % N] return 0 @@ -720,10 +723,10 @@ cdef class P1List(): self.__N = N if N <= 46340: self.__list = p1list_int(N) - self.__normalize = c_p1_normalize_int + self._normalize = c_p1_normalize_int elif N <= 2147483647: self.__list = p1list_llong(N) - self.__normalize = c_p1_normalize_llong + self._normalize = c_p1_normalize_llong else: raise OverflowError("p1list not defined for such large N.") self.__list.sort() @@ -741,15 +744,15 @@ cdef class P1List(): cdef llong ll_s, ll_t, ll_N = N if N <= 46340: - for i from 0 <= i < N: + for i in range(N): self.g[i] = arith_int.c_xgcd_int(i, N, &self.s[i], &self.t[i]) else: - for i from 0 <= i < N: + for i in range(N): self.g[i] = arith_llong.c_xgcd_longlong(i, N, &ll_s, &ll_t) self.s[i] = <int>(ll_s % ll_N) self.t[i] = <int>(ll_t % ll_N) - def __dealloc__(self): + def __dealloc__(self): """ Deallocates memory for an object of the class P1List. """ @@ -918,7 +921,7 @@ cdef class P1List(): """ cdef int u, v, uu, vv, ss u,v = self.__list[i] - self.__normalize(self.__N, -u, v, &uu, &vv, &ss, 0) + self._normalize(self.__N, -u, v, &uu, &vv, &ss, 0) _, j = search(self.__list, (uu,vv)) return j @@ -951,7 +954,7 @@ cdef class P1List(): """ cdef int u, v, uu, vv, ss u,v = self.__list[i] - self.__normalize(self.__N, -v, u, &uu, &vv, &ss, 0) + self._normalize(self.__N, -v, u, &uu, &vv, &ss, 0) _, j = search(self.__list, (uu,vv)) return j @@ -984,7 +987,7 @@ cdef class P1List(): """ cdef int u, v, uu, vv, ss u,v = self.__list[i] - self.__normalize(self.__N, v, -u-v, &uu, &vv, &ss, 0) + self._normalize(self.__N, v, -u-v, &uu, &vv, &ss, 0) _, j = search(self.__list, (uu,vv)) return j @@ -1057,7 +1060,7 @@ cdef class P1List(): s[0] = 1 return - cdef int uu, vv, ss + cdef int uu, vv p1_normalize_xgcdtable(self.__N, u, v, 1, self.g, self.s, self.t, &uu, &vv, s) if uu == 1: i[0] = vv + 1 @@ -1150,7 +1153,7 @@ cdef class P1List(): True """ cdef int uu, vv, ss - self.__normalize(self.__N, u, v, &uu, &vv, &ss, 0) + self._normalize(self.__N, u, v, &uu, &vv, &ss, 0) return (uu,vv) def normalize_with_scalar(self, int u, int v): @@ -1183,7 +1186,7 @@ cdef class P1List(): True """ cdef int uu, vv, ss - self.__normalize(self.__N, u, v, &uu, &vv, &ss, 1) + self._normalize(self.__N, u, v, &uu, &vv, &ss, 1) return (uu, vv, ss) def N(self): diff --git a/src/sage/modular/modsym/p1list_nf.py b/src/sage/modular/modsym/p1list_nf.py index 118d8d5e4fa..69986c1b8c8 100644 --- a/src/sage/modular/modsym/p1list_nf.py +++ b/src/sage/modular/modsym/p1list_nf.py @@ -14,6 +14,7 @@ :: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(5, a^2 - a + 1) sage: P = P1NFList(N); P @@ -75,19 +76,20 @@ sage: P.lift_to_sl2_Ok(3) [0, -1, 1, -2*a] """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009, Maite Aranes <M.T.Aranes@warwick.ac.uk> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.richcmp import richcmp_method, richcmp from sage.structure.sage_object import SageObject from sage.misc.search import search -_level_cache = {} # The info stored here is used in the normalization of MSymbols. +_level_cache = {} # The info stored here is used in the normalization of MSymbols. + def P1NFList_clear_level_cache(): """ @@ -95,6 +97,7 @@ def P1NFList_clear_level_cache(): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(a+1) sage: alpha = MSymbol(N, 2*a^2, 5) @@ -136,6 +139,7 @@ class MSymbol(SageObject): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(a + 1, 2) sage: MSymbol(N, 3, a^2 + 1) @@ -175,6 +179,7 @@ def __init__(self, N, c, d=None, check=True): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^4 + 13*x - 7) sage: N = k.ideal(5) sage: MSymbol(N, 0, 6*a) @@ -197,16 +202,16 @@ def __init__(self, N, c, d=None, check=True): c1 = R(c[0]) d1 = R(c[1]) except (ValueError, TypeError): - raise TypeError("Unable to create a Manin symbol from %s"%c) + raise TypeError("Unable to create a Manin symbol from %s" % c) else: try: c1 = R(c) d1 = R(d) except (ValueError, TypeError): - raise TypeError("Unable to create a Manin symbol from (%s, %s)"%(c, d)) + raise TypeError("Unable to create a Manin symbol from (%s, %s)" % (c, d)) if check: if (c1.is_zero() and d1.is_zero()) or not N.is_coprime(k.ideal(c1, d1)): - raise ValueError("(%s, %s) is not an element of P1(R/N)."%(c1, d1)) + raise ValueError("(%s, %s) is not an element of P1(R/N)." % (c1, d1)) self.__c, self.__d = (c1, d1) def __repr__(self): @@ -215,12 +220,13 @@ def __repr__(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3, a - 1) sage: MSymbol(N, 3, a) M-symbol (3: a) of level Fractional ideal (3, 1/2*a - 1/2) """ - return "M-symbol (%s: %s) of level %s"%(self.__c, self.__d, self.__N) + return "M-symbol (%s: %s) of level %s" % (self.__c, self.__d, self.__N) def _latex_(self): r""" @@ -228,6 +234,7 @@ def _latex_(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^4 + 13*x - 7) sage: N = k.ideal(a^3 - 1) sage: alpha = MSymbol(N, 3, 5*a^2 - 1) @@ -244,6 +251,7 @@ def __richcmp__(self, other, op): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3, a - 1) sage: alpha = MSymbol(N, 3, a) @@ -265,6 +273,7 @@ def N(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3, a - 1) sage: alpha = MSymbol(N, 3, a) @@ -279,6 +288,7 @@ def tuple(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3, a - 1) sage: alpha = MSymbol(N, 3, a); alpha @@ -299,6 +309,7 @@ def __getitem__(self, n): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3, a - 1) sage: alpha = MSymbol(N, 3, a); alpha @@ -316,6 +327,7 @@ def __get_c(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(a + 1, 2) sage: alpha = MSymbol(N, 3, a^2 + 1) @@ -331,6 +343,7 @@ def __get_d(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(a + 1, 2) sage: alpha = MSymbol(N, 3, a^2 + 1) @@ -353,6 +366,7 @@ def lift_to_sl2_Ok(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3, a - 1) sage: alpha = MSymbol(N, 3*a + 1, a) @@ -380,6 +394,7 @@ def normalize(self, with_scalar=False): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3, a - 1) sage: alpha1 = MSymbol(N, 3, a); alpha1 @@ -454,9 +469,9 @@ def normalize(self, with_scalar=False): return MSymbol(N, c, d) -#************************************************************************** -#* P1NFList class * -#************************************************************************** +# ************************************************************************ +# P1NFList class * +# ************************************************************************ @richcmp_method @@ -475,6 +490,7 @@ class P1NFList(SageObject): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(5, a + 1) sage: P = P1NFList(N); P @@ -494,6 +510,7 @@ def __init__(self, N): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 5) sage: N = k.ideal(3, a - 1) sage: P = P1NFList(N); P @@ -511,6 +528,7 @@ def __richcmp__(self, other, op): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N1 = k.ideal(3, a + 1) sage: P1 = P1NFList(N1) @@ -533,6 +551,7 @@ def __getitem__(self, n): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(a) sage: P = P1NFList(N) @@ -550,6 +569,7 @@ def __len__(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(5, a^2 - a + 1) sage: P = P1NFList(N) @@ -564,13 +584,13 @@ def __repr__(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(5, a+1) sage: P = P1NFList(N); P The projective line over the ring of integers modulo the Fractional ideal (5, a + 1) - """ - return "The projective line over the ring of integers modulo the %s"%self.__N + return "The projective line over the ring of integers modulo the %s" % self.__N def list(self): """ @@ -578,6 +598,7 @@ def list(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(5, a+1) sage: P = P1NFList(N) @@ -611,6 +632,7 @@ def normalize(self, c, d=None, with_scalar=False): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 31) sage: N = k.ideal(5, a + 3) sage: P = P1NFList(N) @@ -637,8 +659,8 @@ def normalize(self, c, d=None, with_scalar=False): """ if d is None: try: - c = MSymbol(self.__N, c) # check that c is an MSymbol - except ValueError: # catch special case of wrong level + c = MSymbol(self.__N, c) # check that c is an MSymbol + except ValueError: # catch special case of wrong level raise ValueError("The MSymbol is of a different level") return c.normalize(with_scalar) return MSymbol(self.N(), c, d).normalize(with_scalar) @@ -649,6 +671,7 @@ def N(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 31) sage: N = k.ideal(5, a + 3) sage: P = P1NFList(N) @@ -680,6 +703,7 @@ def index(self, c, d=None, with_scalar=False): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 31) sage: N = k.ideal(5, a + 3) sage: P = P1NFList(N) @@ -720,8 +744,8 @@ def index(self, c, d=None, with_scalar=False): """ if d is None: try: - c = MSymbol(self.__N, c) # check that c is an MSymbol - except ValueError: # catch special case of wrong level + c = MSymbol(self.__N, c) # check that c is an MSymbol + except ValueError: # catch special case of wrong level raise ValueError("The MSymbol is of a different level") if with_scalar: u, norm_c = c.normalize(with_scalar=True) @@ -760,6 +784,7 @@ def index_of_normalized_pair(self, c, d=None): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 31) sage: N = k.ideal(5, a + 3) sage: P = P1NFList(N) @@ -798,6 +823,7 @@ def lift_to_sl2_Ok(self, i): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3) sage: P = P1NFList(N) @@ -832,6 +858,7 @@ def apply_S(self, i): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(5, a + 1) sage: P = P1NFList(N) @@ -866,6 +893,7 @@ def apply_TS(self, i): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(5, a + 1) sage: P = P1NFList(N) @@ -902,6 +930,7 @@ def apply_T_alpha(self, i, alpha=1): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(5, a + 1) sage: P = P1NFList(N) @@ -941,6 +970,7 @@ def apply_J_epsilon(self, i, e1, e2=1): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 11) sage: N = k.ideal(5, a + 1) sage: P = P1NFList(N) @@ -966,13 +996,13 @@ def apply_J_epsilon(self, i, e1, e2=1): return j -#************************************************************************** +# ************************************************************************* # Global functions: # - p1NFList --compute list of M-symbols # - lift_to_sl2_Ok # - make_coprime -- need it for ``lift_to_sl2_Ok`` # - psi -- useful to check cardinality of the M-symbols list -#************************************************************************** +# ************************************************************************* def p1NFlist(N): """ @@ -985,6 +1015,7 @@ def p1NFlist(N): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3) sage: from sage.modular.modsym.p1list_nf import p1NFlist, psi @@ -993,14 +1024,14 @@ def p1NFlist(N): """ k = N.number_field() - L = [MSymbol(N, k(0),k(1), check=False)] - #N.residues() = iterator through the residues mod N - L = L+[MSymbol(N, k(1), r, check=False) for r in N.residues()] + L = [MSymbol(N, k(0), k(1), check=False)] + # N.residues() = iterator through the residues mod N + L = L + [MSymbol(N, k(1), r, check=False) for r in N.residues()] from sage.arith.misc import divisors for D in divisors(N): - if not D.is_trivial() and D!=N: - #we find Dp ideal coprime to N, in inverse class to D + if not D.is_trivial() and D != N: + # we find Dp ideal coprime to N, in inverse class to D if D.is_principal(): Dp = k.ideal(1) c = D.gens_reduced()[0] @@ -1010,7 +1041,7 @@ def p1NFlist(N): while not Dp.is_coprime(N) or not (Dp*D).is_principal(): Dp = next(it) c = (D*Dp).gens_reduced()[0] - #now we find all the (c,d)'s which have associated divisor D + # now we find all the (c,d)'s which have associated divisor D I = D + N/D for d in (N/D).residues(): if I.is_coprime(d): @@ -1020,6 +1051,7 @@ def p1NFlist(N): L.append(MSymbol(N, c, d1, check=False).normalize()) return L + def lift_to_sl2_Ok(N, c, d): """ Lift a pair (c, d) to an element of `SL(2, O_k)`, where `O_k` is the ring @@ -1043,6 +1075,7 @@ def lift_to_sl2_Ok(N, c, d): EXAMPLES:: sage: from sage.modular.modsym.p1list_nf import lift_to_sl2_Ok + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: Ok = k.ring_of_integers() sage: N = k.ideal(3) @@ -1091,17 +1124,17 @@ def lift_to_sl2_Ok(N, c, d): ValueError: <0> + <7> and the Fractional ideal (7, a) are not coprime. """ k = N.number_field() - #check the input + # check the input if c.is_zero() and d.is_zero(): - raise ValueError("Cannot lift (%s, %s) to an element of Sl2(Ok)."%(c, d)) + raise ValueError("Cannot lift (%s, %s) to an element of Sl2(Ok)." % (c, d)) if not N.is_coprime(k.ideal(c, d)): - raise ValueError("<%s> + <%s> and the %s are not coprime."%(c, d, N)) - #a few special cases + raise ValueError("<%s> + <%s> and the %s are not coprime." % (c, d, N)) + # a few special cases if c - 1 in N: return [k(0), k(-1), 1, d] if d - 1 in N: return [k(1), k(0), c, 1] - if c.is_zero(): # and d!=1, so won't happen for normalized M-symbols (c: d) + if c.is_zero(): # and d!=1, so won't happen for normalized M-symbols (c: d) it = k.primes_of_degree_one_iter() q = k.ideal(1) while not (q.is_coprime(d) and (q*N).is_principal()): @@ -1109,7 +1142,7 @@ def lift_to_sl2_Ok(N, c, d): m = (q*N).gens_reduced()[0] B = k.ideal(m).element_1_mod(k.ideal(d)) return [(1-B)/d, -B/m, m, d] - if d.is_zero(): # and c!=1, so won't happen for normalized M-symbols (c: d) + if d.is_zero(): # and c!=1, so won't happen for normalized M-symbols (c: d) it = k.primes_of_degree_one_iter() q = k.ideal(1) while not (q.is_coprime(c) and (q*N).is_principal()): @@ -1148,6 +1181,7 @@ def make_coprime(N, c, d): EXAMPLES:: sage: from sage.modular.modsym.p1list_nf import make_coprime + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3, a - 1) sage: c = 2*a; d = a + 1 @@ -1183,6 +1217,7 @@ def psi(N): EXAMPLES:: sage: from sage.modular.modsym.p1list_nf import psi + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3, a - 1) sage: psi(N) diff --git a/src/sage/modular/modsym/relation_matrix_pyx.pyx b/src/sage/modular/modsym/relation_matrix_pyx.pyx index f5a18c464eb..46d8d716e62 100644 --- a/src/sage/modular/modsym/relation_matrix_pyx.pyx +++ b/src/sage/modular/modsym/relation_matrix_pyx.pyx @@ -57,7 +57,7 @@ def sparse_2term_quotient_only_pm1(rels, n): tm = verbose("Starting optimized integer sparse 2-term quotient...") cdef int c0, c1, i, die - cdef list free = list(xrange(n)) + cdef list free = list(range(n)) cdef list coef = [1] * n cdef list related_to_me = [[] for i in range(n)] diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index 273ba7eed8d..9cf4bf0796f 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -27,6 +27,7 @@ from sage.categories.fields import Fields from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modules.free_module import EchelonMatrixKey, FreeModule, VectorSpace from sage.modules.free_module_element import FreeModuleElement @@ -35,7 +36,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer from sage.rings.infinity import infinity -from sage.rings.number_field.number_field_base import is_NumberField +from sage.rings.number_field.number_field_base import NumberField from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ from sage.structure.all import Sequence, SageObject @@ -46,7 +47,7 @@ from sage.modular.hecke.module import HeckeModule_free_module from sage.modular.modsym.element import ModularSymbolsElement -from . import hecke_operator +lazy_import('sage.modular.modsym', 'hecke_operator') def is_ModularSymbolsSpace(x): @@ -1046,7 +1047,7 @@ def _q_expansion_module_rational(self, prec): if not self.is_cuspidal(): raise ValueError("self must be cuspidal") K = self.base_ring() - if not is_NumberField(K): + if not isinstance(K, NumberField): raise TypeError("self must be over QQ or a number field.") n = K.degree() if n == 1: diff --git a/src/sage/modular/modsym/subspace.py b/src/sage/modular/modsym/subspace.py index c1f70471c0f..d1d2a393127 100644 --- a/src/sage/modular/modsym/subspace.py +++ b/src/sage/modular/modsym/subspace.py @@ -1,8 +1,7 @@ """ Subspace of ambient spaces of modular symbols """ - -#***************************************************************************** +# **************************************************************************** # Sage: Open Source Mathematical Software # # Copyright (C) 2005 William Stein <wstein@gmail.com> @@ -16,18 +15,14 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** import sage.modular.hecke.all as hecke - import sage.structure.factorization - import sage.modular.modsym.space - class ModularSymbolsSubspace(sage.modular.modsym.space.ModularSymbolsSpace, hecke.HeckeSubmodule): """ Subspace of ambient space of modular symbols @@ -86,8 +81,8 @@ def _repr_(self): sage: ModularSymbols(24,4).cuspidal_subspace()._repr_() 'Modular Symbols subspace of dimension 16 of Modular Symbols space of dimension 24 for Gamma_0(24) of weight 4 with sign 0 over Rational Field' """ - return "Modular Symbols subspace of dimension %s of %s"%( - self.rank(), self.ambient_module()) + return "Modular Symbols subspace of dimension %s of %s" % ( + self.rank(), self.ambient_module()) ################################ # Public functions @@ -175,10 +170,11 @@ def cuspidal_submodule(self): self.__cuspidal_submodule = S.intersection(self) return self.__cuspidal_submodule - def dual_star_involution_matrix(self): """ - Return the matrix of the dual star involution, which is induced by + Return the matrix of the dual star involution. + + This involution is induced by complex conjugation on the linear dual of modular symbols. EXAMPLES:: @@ -283,17 +279,17 @@ def factorization(self): if A.is_cuspidal(): V = A.plus_submodule() V._is_simple = True - D.append((V,1)) + D.append((V, 1)) V = A.minus_submodule() V._is_simple = True - D.append((V,1)) + D.append((V, 1)) else: A._is_simple = True D.append((A, 1)) else: for A in N: A._is_simple = True - D.append((A,1)) + D.append((A, 1)) else: # Compute factorization of the ambient space, then compute multiplicity # of each factor in this space. @@ -301,19 +297,19 @@ def factorization(self): for S in self.ambient_hecke_module().simple_factors(): n = self.multiplicity(S, check_simple=False) if n > 0: - D.append((S,n)) + D.append((S, n)) # endif # check that dimensions add up r = self.dimension() - s = sum([A.rank()*mult for A, mult in D]) + s = sum([A.rank() * mult for A, mult in D]) if r != s: - raise NotImplementedError("modular symbols factorization not fully implemented yet -- self has dimension %s, but sum of dimensions of factors is %s"%( - r, s)) + raise NotImplementedError("modular symbols factorization not fully implemented yet " + "-- self has dimension %s, but sum of dimensions of factors is %s" % (r, s)) self._factorization = sage.structure.factorization.Factorization(D, cr=True) return self._factorization - def is_cuspidal(self): + def is_cuspidal(self) -> bool: """ Return True if self is cuspidal. @@ -363,21 +359,18 @@ def is_eisenstein(self): self.__is_eisenstein = self.is_submodule(C) return self.__is_eisenstein - def _compute_sign_subspace(self, sign, compute_dual=True): """ - Return the subspace of self that is fixed under the star + Return the subspace of ``self`` that is fixed under the star involution. INPUT: - - ``sign`` - int (either -1 or +1) - ``compute_dual`` - bool (default: True) also compute dual subspace. This are useful for many algorithms. - OUTPUT: subspace of modular symbols EXAMPLES:: diff --git a/src/sage/modular/modsym/tests.py b/src/sage/modular/modsym/tests.py index 4fd47dda376..737bb66ba62 100644 --- a/src/sage/modular/modsym/tests.py +++ b/src/sage/modular/modsym/tests.py @@ -30,7 +30,7 @@ from . import modsym import sage.modular.dirichlet as dirichlet import sage.modular.arithgroup.all as arithgroup -from sage.misc.misc import cputime +from sage.misc.timing import cputime class Test: @@ -67,9 +67,9 @@ def __init__(self, levels=20, weights=4, onlyg0=False, onlyg1=False, weights = list(range(2, int(weights) + 1)) self.levels = levels self.weights = weights - if not(levels): + if not levels: raise RuntimeError("levels must have positive length") - if not(weights): + if not weights: raise RuntimeError("weights must have positive length") self.current_space = None self.onlyg0 = onlyg0 @@ -78,7 +78,7 @@ def __init__(self, levels=20, weights=4, onlyg0=False, onlyg1=False, def __repr__(self): """ - Return the string representation of self. + Return the string representation of ``self``. EXAMPLES:: @@ -111,7 +111,7 @@ def _modular_symbols_space(self): elif self.onlychar: which = 2 else: - which = random.randrange(0,3) + which = random.randrange(0, 3) if which == 0: print("gamma0") M = self._modular_symbols_space_gamma0() @@ -251,9 +251,9 @@ def test(self, name, seconds=0): total = cputime() n = 1 while seconds == 0 or cputime(total) < seconds: - s = "** test_dimension: number %s"%n + s = "** test_dimension: number %s" % n if seconds > 0: - s += " (will stop after about %s seconds)"%seconds + s += " (will stop after about %s seconds)" % seconds t = cputime() self._do(name) print("\ttime=%s\telapsed=%s" % (cputime(t), cputime(total))) @@ -292,7 +292,7 @@ def test_csnew_dimension(self): d = V.dimension() d2 = M._cuspidal_new_submodule_dimension_formula() assert d == d2, \ - "Test failed for M=\"%s\", where computed dimension is %s but formula dimension is %s."%(M, d, d2) + "Test failed for M=\"%s\", where computed dimension is %s but formula dimension is %s." % (M, d, d2) def test_csns_nscs(self): """ @@ -310,12 +310,11 @@ def test_csns_nscs(self): M = self._modular_symbols_space() V1 = M.cuspidal_submodule().new_submodule() V2 = M.new_submodule().cuspidal_submodule() - assert V1 == V2, "Test failed for M=\"%s\", where the new cuspidal and cuspidal new spaces are computed differently."%M + assert V1 == V2, "Test failed for M=\"%s\", where the new cuspidal and cuspidal new spaces are computed differently." % M d = M._cuspidal_new_submodule_dimension_formula() assert d == V1.dimension(), \ - "Test failed for M=\"%s\", where computed dimension is %s but formula dimension is %s."%( - M, V1.dimension(), d) - + "Test failed for M=\"%s\", where computed dimension is %s but formula dimension is %s." % ( + M, V1.dimension(), d) def test_decomposition(self): """ diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 6fd43f34560..22cabe23344 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -165,12 +165,14 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +from __future__ import annotations import numbers +from typing import Iterator +from itertools import product -from sage.structure.unique_representation import UniqueRepresentation +from sage.misc.fast_methods import Singleton from sage.structure.richcmp import op_EQ, op_NE from sage.structure.element import parent -from sage.categories.cartesian_product import cartesian_product from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis from sage.categories.rings import Rings from sage.categories.domains import Domains @@ -182,10 +184,10 @@ from sage.combinat.words.word import Word from sage.combinat.words.words import Words from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 as shuffle -from sage.libs.pari.all import pari from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_function, cached_method from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modular.multiple_zeta_F_algebra import F_algebra from sage.modules.free_module import VectorSpace @@ -193,6 +195,9 @@ from sage.rings.rational_field import QQ from sage.sets.positive_integers import PositiveIntegers +lazy_import('sage.libs.pari.all', 'pari') + + # multiplicative generators for weight <= 17 # using the following convention # (3, 5) <---> (sign) * [1,0,0,1,0,0,0,0] @@ -208,7 +213,7 @@ Words10 = Words((1, 0), infinite=False) -def coproduct_iterator(paire): +def coproduct_iterator(paire) -> Iterator[list]: """ Return an iterator for terms in the coproduct. @@ -248,7 +253,7 @@ def coproduct_iterator(paire): tail[step:])) -def composition_to_iterated(w, reverse=False): +def composition_to_iterated(w, reverse=False) -> tuple[int, ...]: """ Convert a composition to a word in 0 and 1. @@ -279,7 +284,7 @@ def composition_to_iterated(w, reverse=False): return word -def iterated_to_composition(w, reverse=False): +def iterated_to_composition(w, reverse=False) -> tuple[int, ...]: """ Convert a word in 0 and 1 to a composition. @@ -313,7 +318,7 @@ def iterated_to_composition(w, reverse=False): return tuple(b) if reverse else tuple(reversed(b)) -def dual_composition(c): +def dual_composition(c) -> tuple[int, ...]: """ Return the dual composition of ``c``. @@ -380,7 +385,7 @@ def minimize_term(w, cf): # numerical values -class MultizetaValues(UniqueRepresentation): +class MultizetaValues(Singleton): """ Custom cache for numerical values of multiple zetas. @@ -428,7 +433,7 @@ def __init__(self): self.prec = 0 self.reset() - def __repr__(self): + def __repr__(self) -> str: r""" TESTS:: @@ -545,7 +550,7 @@ def __call__(self, index, prec=None, reverse=True): Values = MultizetaValues() -def extend_multiplicative_basis(B, n): +def extend_multiplicative_basis(B, n) -> Iterator: """ Extend a multiplicative basis into a basis. @@ -573,8 +578,7 @@ def extend_multiplicative_basis(B, n): [((7,),), ((5,), (2,)), ((3,), (2,), (2,))] """ for pi in Partitions(n, min_part=2): - for liste in cartesian_product([B[i] for i in pi]): - yield liste + yield from product(*[B[i] for i in pi]) # several classes for the algebra of MZV @@ -663,7 +667,7 @@ def __init__(self, R): W = Words(PositiveIntegers(), infinite=False) CombinatorialFreeModule.__init__(self, R, W, prefix="Z", category=cat) - def _repr_(self): + def _repr_(self) -> str: r""" Return a string representation of the algebra. @@ -675,7 +679,7 @@ def _repr_(self): txt = "Algebra of motivic multiple zeta values indexed by compositions over {}" return txt.format(self.base_ring()) - def _repr_term(self, m): + def _repr_term(self, m) -> str: """ Return a custom string representation for the monomials. @@ -686,7 +690,7 @@ def _repr_term(self, m): """ return "ฮถ(" + ','.join(str(letter) for letter in m) + ")" - def _latex_term(self, m): + def _latex_term(self, m) -> str: r""" Return a custom latex representation for the monomials. @@ -712,7 +716,7 @@ def one_basis(self): """ return self.basis().keys()([], check=False) - def some_elements(self): + def some_elements(self) -> tuple: r""" Return some elements of the algebra. @@ -746,21 +750,22 @@ def product_on_basis(self, w1, w2): INPUT: - - ``w1``, ``w2`` -- compositions + - ``w1``, ``w2`` -- compositions as words EXAMPLES:: sage: M = Multizetas(QQ) - sage: M.product_on_basis([2],[2]) + sage: W = M.basis().keys() + sage: M.product_on_basis(W([2]),W([2])) 4*ฮถ(1,3) + 2*ฮถ(2,2) sage: x = M((2,)) sage: x*x 4*ฮถ(1,3) + 2*ฮถ(2,2) """ if not w1: - return self(w2) + return self._monomial(w2) if not w2: - return self(w1) + return self._monomial(w1) p1 = self.iterated_on_basis(w1) p2 = self.iterated_on_basis(w2) p1p2 = p1 * p2 @@ -938,7 +943,7 @@ def _element_constructor_(self, x): return x.composition() raise TypeError('invalid input for building a multizeta value') - def algebra_generators(self, n): + def algebra_generators(self, n) -> list: """ Return a set of multiplicative generators in weight ``n``. @@ -956,9 +961,10 @@ def algebra_generators(self, n): sage: M.algebra_generators(8) [ฮถ(3,5)] """ - return [self(b) for b in B_data[n]] + W = self.basis().keys() + return [self._monomial(W(b, check=False)) for b in B_data[n]] - def basis_data(self, basering, n): + def basis_data(self, basering, n) -> Iterator: """ Return an iterator for a basis in weight ``n``. @@ -975,9 +981,11 @@ def basis_data(self, basering, n): [4*ฮถ(1,3) + 2*ฮถ(2,2)] """ basis_MZV = extend_multiplicative_basis(B_data, n) - return (prod(self(compo) for compo in term) for term in basis_MZV) + W = self.basis().keys() + return (prod(self._monomial(W(compo, check=False)) + for compo in term) for term in basis_MZV) - def basis_brown(self, n): + def basis_brown(self, n) -> list: r""" Return a basis of the algebra of multiple zeta values in weight ``n``. @@ -1002,7 +1010,8 @@ def basis_brown(self, n): sage: M.basis_brown(6) [ฮถ(3,3), ฮถ(2,2,2)] """ - return [self(tuple(c)) + W = self.basis().keys() + return [self._monomial(W(tuple(c), check=False)) for c in IntegerVectors(n, min_part=2, max_part=3)] @cached_method @@ -1042,6 +1051,7 @@ def basis_filtration(self, d, reverse=False): if d == 1: return [] + W = self.basis().keys() Values.reset(max_weight=d) dim = len(self((d,)).phi_as_vector()) V = VectorSpace(QQ, dim) @@ -1057,14 +1067,15 @@ def basis_filtration(self, d, reverse=False): else: if c[0] == 1: continue - c = tuple(c[::-1]) - v = self(c).phi_as_vector() + c = c[::-1] + mon_c = self._monomial(W(c, check=False)) + v = mon_c.phi_as_vector() if v in U: continue U = V.subspace(U.basis() + [v]) - basis.append(c) + basis.append(mon_c) k += 1 - return [self(c) for c in basis] + return basis class Element(CombinatorialFreeModule.Element): def iterated(self): @@ -1083,9 +1094,15 @@ def iterated(self): return self.parent().iterated(self) def single_valued(self): - """ + r""" Return the single-valued version of ``self``. + This is the projection map onto the sub-algebra of + single-valued motivic multiple zeta values, as defined by + F. Brown in [Bro2013]_. + + This morphism of algebras sends in particular `\zeta(2)` to `0`. + EXAMPLES:: sage: M = Multizetas(QQ) @@ -1108,13 +1125,7 @@ def single_valued(self): sage: Z(5,3).single_valued() == 14*Z(3)*Z(5) True """ - phi_im = self.phi() - zin = phi_im.parent() - phi_no_f2 = phi_im.without_f2() - sv = zin.sum_of_terms(((0, w), cf) - for (a, b), cf in phi_no_f2.coproduct() - for w in shuffle(a[1], b[1].reversal(), False)) - return rho_inverse(sv) + return rho_inverse(self.phi().single_valued()) def simplify(self): """ @@ -1175,7 +1186,7 @@ def simplify_full(self, basis=None): result += sum(x * z for x, z in zip(P.solve_left(v), Bd)) return result - def __bool__(self): + def __bool__(self) -> bool: r""" EXAMPLES:: @@ -1186,7 +1197,7 @@ def __bool__(self): """ return bool(self.iterated()) - def is_zero(self): + def is_zero(self) -> bool: r""" Return whether this element is zero. @@ -1210,7 +1221,7 @@ def is_zero(self): """ return not self - def _richcmp_(self, other, op): + def _richcmp_(self, other, op) -> bool: """ Comparison. @@ -1414,7 +1425,7 @@ def __init__(self, R): CombinatorialFreeModule.__init__(self, R, Words10, prefix="I", category=cat) - def _repr_(self): + def _repr_(self) -> str: """ Return a string representation for the ring. @@ -1427,7 +1438,7 @@ def _repr_(self): """ return f"Algebra of motivic multiple zeta values as convergent iterated integrals over {self.base_ring()}" - def _repr_term(self, m): + def _repr_term(self, m) -> str: """ Return a custom string representation for the monomials. @@ -1650,7 +1661,7 @@ def dual_on_basis(self, w): -I(11010) """ rev = [1 - x for x in reversed(w)] - image = self(self.basis().keys()(rev, check=False)) + image = self._monomial(self.basis().keys()(rev, check=False)) return -image if len(w) % 2 else image def degree_on_basis(self, w): @@ -1967,7 +1978,7 @@ def phi(self): """ return self.parent().phi(self) - def __bool__(self): + def __bool__(self) -> bool: r""" TESTS:: @@ -1989,7 +2000,7 @@ def __bool__(self): return True return False - def is_zero(self): + def is_zero(self) -> bool: r""" Return whether this element is zero. @@ -2006,7 +2017,7 @@ def is_zero(self): """ return not self - def _richcmp_(self, other, op): + def _richcmp_(self, other, op) -> bool: """ Test for equality. @@ -2072,7 +2083,7 @@ def __init__(self, R): raise TypeError("argument R must be a ring") CombinatorialFreeModule.__init__(self, R, Words10, prefix="I") - def _repr_(self): + def _repr_(self) -> str: """ Return a string representation of the module. @@ -2085,7 +2096,7 @@ def _repr_(self): txt = "Space of motivic multiple zeta values as general iterated integrals over {}" return txt.format(self.base_ring()) - def _repr_term(self, m): + def _repr_term(self, m) -> str: """ Return a custom string representation for the monomials. @@ -2158,10 +2169,11 @@ def dual_on_basis(self, w): sage: M.dual_on_basis(x) -I(0;010;1) """ + W = self.basis().keys() if w[-2] == 0: - return self(w) + return self._monomial(w) rev = [1 - x for x in reversed(w)] - image = self(self.basis().keys()(rev, check=False)) + image = self._monomial(W(rev, check=False)) return -image if len(w) % 2 else image @lazy_attribute @@ -2204,7 +2216,7 @@ def reversal_on_basis(self, w): I(0;011;1) """ if w[0] == 0 and w[-1] == 1: - return self(w) + return self._monomial(w) W = self.basis().keys() image = self._monomial(W(list(reversed(w)), check=False)) return -image if len(w) % 2 else image @@ -2254,8 +2266,9 @@ def expand_on_basis(self, w): I(0;110;1) """ if w[1] == 1: - return self(w) + return self._monomial(w) + W = self.basis().keys() n_zeros = [] k = 0 for x in w[1:-1]: @@ -2276,7 +2289,8 @@ def expand_on_basis(self, w): indice = [0] for nj, ij in zip(n_zeros, idx): indice += [1] + [0] * (nj + ij - 1) - resu += coeff * self(indice + [1]) + resu += coeff * self._monomial(W(tuple(indice + [1]), + check=False)) return (-1)**k * resu # attention au signe @lazy_attribute diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index 39e7dcad4e7..f8875d4bc51 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -11,6 +11,10 @@ Here we provide a basic direct implementation, endowed with the motivic coproduct. +The similar algebra where the shuffle algebra has generators +`f_1, f_3, f_5, \ldots` is now also available. The implementation is even more +general, allowing any positive odd integer as start index. + AUTHORS: - Frรฉdรฉric Chapoton (2022-09): Initial version @@ -31,6 +35,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.words.words import Words from sage.combinat.words.finite_word import FiniteWord_class +from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 as shuffle from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.sets.integer_range import IntegerRange @@ -40,40 +45,65 @@ from sage.modules.free_module_element import vector -# the indexing set: (integer power of f_2, word in 3, 5, 7,...) -W_Odds = Words(IntegerRange(3, Infinity, 2), infinite=False) +def W_Odds(start=3): + r""" + Indexing set for the odd generators. + This is the set of pairs + (integer power of `f_2`, word in `s, s+2, s+4, \ldots`) + where `s` is the chosen odd start index. -def str_to_index(x: str) -> tuple: + INPUT: + + - ``start`` -- (default: ``3``) odd start index for odd generators + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import W_Odds + sage: W_Odds(3) + Finite words over {3, 5, ...} """ + return Words(IntegerRange(start, Infinity, 2), infinite=False) + + +def str_to_index(x: str) -> tuple: + r""" Convert a string to an index. - Every letter "2" contributes to the power of `f_2`. Other letters - define a word in `f_3`, `f_5`, ... + Every letter ``"2"`` contributes to the power of `f_2`. Other letters + are odd and define a word in `f_1, f_3, f_5, \ldots` - Usually the letters "2" form a prefix of the input. + Usually the letters ``"2"`` form a prefix of the input. EXAMPLES:: sage: from sage.modular.multiple_zeta_F_algebra import str_to_index sage: str_to_index("22357") (2, [3, 5, 7]) + + sage: str_to_index("22317") + (2, [3, 1, 7]) """ p = x.count("2") w = [int(i) for i in x if i != '2'] return (p, w) -def basis_f_odd_iterator(n) -> Iterator[tuple]: - """ - Return an iterator over compositions of ``n`` with parts in ``(3,5,7,...)`` +def basis_f_odd_iterator(n, start=3) -> Iterator[tuple]: + r""" + Return an iterator over compositions of ``n`` with odd parts. + + Let `s` be the chosen odd start index. The allowed parts are the + odd integers at least equal to `s`, in the set `s,s+2,s+4,s+6,\ldots`. - This is used to index a basis. + This set of compositions is used to index a basis. INPUT: - ``n`` -- an integer + - ``start`` -- (default: ``3``) odd integer, start index for odd generators + EXAMPLES:: sage: from sage.modular.multiple_zeta_F_algebra import basis_f_odd_iterator @@ -93,21 +123,22 @@ def basis_f_odd_iterator(n) -> Iterator[tuple]: if n == 0: yield tuple() return - if n == 1: - return - if n % 2: + if n % 2 and n >= start: yield (n,) - for k in range(3, n, 2): - for start in basis_f_odd_iterator(n - k): - yield start + (k, ) + for k in range(start, n, 2): + for word in basis_f_odd_iterator(n - k, start=start): + yield word + (k, ) -def basis_f_iterator(n) -> Iterator[tuple]: - """ - Return an iterator over decompositions of ``n`` using ``2,3,5,7,9,...``. +def basis_f_iterator(n, start=3) -> Iterator[tuple]: + r""" + Return an iterator for decompositions of ``n`` using ``2`` and odd integers. + + Let `s` be the chosen odd start index. The allowed odd parts are the + odd integers at least equal to `s`, in the set `s,s+2,s+4,s+6,\ldots`. The means that each term is made of a power of 2 and a composition - of the remaining integer with parts in ``(3,5,7,...)`` + of the remaining integer with parts in `(s,s+2,s+4,\ldots)`. This set is indexing a basis of the homogeneous component of weight ``n``. @@ -115,6 +146,8 @@ def basis_f_iterator(n) -> Iterator[tuple]: - ``n`` -- an integer + - ``start`` -- (default: ``3``) odd start index for odd generators + Each term is returned as a pair (integer, word) where the integer is the exponent of 2. @@ -144,21 +177,27 @@ def basis_f_iterator(n) -> Iterator[tuple]: sage: list(basis_f_iterator(0)) [(0, word: )] + sage: list(basis_f_iterator(3, start=1)) + [(0, word: 3), (0, word: 111), (1, word: 1)] """ - if n and n < 2: - return + wodds = W_Odds(start) for k in range(n // 2 + 1): - for start in basis_f_odd_iterator(n - 2 * k): - yield (k, W_Odds(start, check=False)) + for word in basis_f_odd_iterator(n - 2 * k, start): + yield (k, wodds(word, check=False)) -def morphism_constructor(data: dict): - """ +def morphism_constructor(data: dict, start=3): + r""" Build a morphism from the F-algebra to some codomain. + Let `s` be the chosen odd start index. + INPUT: - a dictionary containing the images of `f_2`, `f_3`, `f_5`, `f_7`, ... + - ``data`` -- a dictionary with integer keys containing the images of + `f_2, f_s, f_{s+2}, f_{s+4}, \ldots` + + - ``start`` -- (default: 3) start index for odd generators OUTPUT: @@ -171,10 +210,10 @@ def morphism_constructor(data: dict): EXAMPLES:: sage: from sage.modular.multiple_zeta_F_algebra import F_algebra, morphism_constructor - sage: F = F_algebra(QQ) sage: Z = Multizeta sage: D = {2: Z(2), 3: Z(3)} sage: rho = morphism_constructor(D) + sage: F = rho.domain() sage: rho(F("2")) ฮถ(2) sage: rho(F("3")) @@ -186,7 +225,7 @@ def morphism_constructor(data: dict): """ im_f2 = data[2] codomain = im_f2.parent() - domain = F_algebra(codomain.base_ring()) + domain = F_algebra(codomain.base_ring(), start=start) def morphism_on_basis(pw): p, w = pw @@ -210,6 +249,8 @@ class F_algebra(CombinatorialFreeModule): - ``R`` -- ring + - ``start`` -- (default: ``3``) odd start index for odd generators + EXAMPLES:: sage: from sage.modular.multiple_zeta_F_algebra import F_algebra @@ -228,10 +269,16 @@ class F_algebra(CombinatorialFreeModule): sage: s = f2*f3+f5; s f5 + f2*f3 """ - def __init__(self, R): + def __init__(self, R, start=3): r""" Initialize ``self``. + INPUT: + + - ``R`` -- base ring + + - ``start`` -- (default: ``3``) odd start index for odd generators + EXAMPLES:: sage: from sage.modular.multiple_zeta_F_algebra import F_algebra @@ -247,18 +294,21 @@ def __init__(self, R): """ if R not in Rings(): raise TypeError("argument R must be a ring") - Indices = NonNegativeIntegers().cartesian_product(W_Odds) + if not start % 2 and start > 0: + raise ValueError("argument start must be odd and positive") + self._start = start + Indices = NonNegativeIntegers().cartesian_product(W_Odds(start)) cat = BialgebrasWithBasis(R).Commutative().Graded() CombinatorialFreeModule.__init__(self, R, Indices, latex_prefix="", prefix='f', category=cat) def _repr_term(self, pw) -> str: - """ + r""" Return the custom representation of terms. Each monomial is written as a power of `f_2` times a word - in `f_3`, `f_5`, ... + in `f_1, f_3, f_5, \ldots`. EXAMPLES:: @@ -267,7 +317,7 @@ def _repr_term(self, pw) -> str: sage: f2 = F.gen(2) sage: f3 = F.gen(3) sage: f5 = F.gen(5) - sage: f2*f3+f5+f2**2 + sage: f2*f3+f5+f2**2 # indirect doctest f5 + f2*f3 + f2^2 """ p, w = pw @@ -323,7 +373,7 @@ def product_on_basis(self, pw1, pw2): sage: from sage.modular.multiple_zeta_F_algebra import F_algebra sage: A = F_algebra(QQ) sage: W = A.basis().keys() - sage: A.product(A("23"), A("25")) + sage: A.product(A("23"), A("25")) # indirect doctest f2^2*f3f5 + f2^2*f5f3 """ p1, w1 = pw1 @@ -346,7 +396,7 @@ def half_product_on_basis(self, pw1, pw2): sage: from sage.modular.multiple_zeta_F_algebra import F_algebra sage: A = F_algebra(QQ) sage: W = A.basis().keys() - sage: t = A.half_product(A("23"), A("25")); t + sage: t = A.half_product(A("23"), A("25")); t # indirect doctest f2^2*f3f5 TESTS:: @@ -404,7 +454,7 @@ def gen(self, i): f2 = self.monomial(self._indices((1, []))) if i == 2: return f2 - # now i odd >= 3 + # now i odd >= start if i % 2: return self.monomial(self._indices((0, [i]))) # now powers of f2 @@ -529,7 +579,7 @@ def homogeneous_from_vector(self, vec, N): if isinstance(vec, (list, tuple)): vec = vector(vec) return self.sum(cf * self.monomial(bi) - for cf, bi in zip(vec, basis_f_iterator(N))) + for cf, bi in zip(vec, basis_f_iterator(N, self._start))) def _element_constructor_(self, x): r""" @@ -705,7 +755,7 @@ def homogeneous_to_vector(self): a, b = next(iter(self))[0] N = 2 * a + sum(int(x) for x in b) return vector(BR, [self.coefficient(b) - for b in basis_f_iterator(N)]) + for b in basis_f_iterator(N, F._start)]) def without_f2(self): """ @@ -715,9 +765,30 @@ def without_f2(self): sage: from sage.modular.multiple_zeta_F_algebra import F_algebra sage: F = F_algebra(QQ) - sage: t = 4*F("35")+F("27") + sage: t = 4 * F("35") + F("27") sage: t.without_f2() 4*f3f5 """ F = self.parent() return F._from_dict({(0, w): cf for (p, w), cf in self if not p}) + + def single_valued(self): + """ + Return the single-valued version of ``self``. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ) + sage: t = 4 * F("2") + F("3") + sage: t.single_valued() + 2*f3 + sage: t = 4 * F("35") + F("27") + sage: t.single_valued() + 8*f3f5 + 8*f5f3 + """ + F = self.parent() + no_f2 = self.without_f2() + return F.sum_of_terms(((0, w), cf) + for (a, b), cf in no_f2.coproduct() + for w in shuffle(a[1], b[1].reversal(), False)) diff --git a/src/sage/modular/overconvergent/__init__.py b/src/sage/modular/overconvergent/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/overconvergent/all.py b/src/sage/modular/overconvergent/all.py index a6a3b8d158b..11e23071854 100644 --- a/src/sage/modular/overconvergent/all.py +++ b/src/sage/modular/overconvergent/all.py @@ -1,4 +1,4 @@ -from .weightspace import WeightSpace_constructor as pAdicWeightSpace +from .weightspace import WeightSpace_constructor as pAdicWeightSpace from .genus0 import OverconvergentModularForms diff --git a/src/sage/modular/overconvergent/genus0.py b/src/sage/modular/overconvergent/genus0.py index 972ef7eed45..04e86a0732e 100644 --- a/src/sage/modular/overconvergent/genus0.py +++ b/src/sage/modular/overconvergent/genus0.py @@ -177,25 +177,27 @@ from sage.matrix.matrix_space import MatrixSpace from sage.matrix.special import diagonal_matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose from sage.modular.arithgroup.all import is_Gamma0, is_Gamma1 from sage.modular.dirichlet import trivial_character from sage.modular.etaproducts import EtaProduct from sage.modular.modform.element import ModularFormElement from sage.modular.modform.hecke_operator_on_qexp import hecke_operator_on_qexp -from sage.modular.modform.j_invariant import j_invariant_qexp from sage.modules.free_module_element import vector from sage.modules.module import Module from sage.rings.big_oh import O from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ -from sage.rings.padics.factory import Qp as pAdicField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ from sage.structure.element import Vector, ModuleElement from sage.structure.richcmp import richcmp +lazy_import('sage.modular.modform.j_invariant', 'j_invariant_qexp') +lazy_import('sage.rings.padics.factory', 'Qp', as_='pAdicField') + from .weightspace import WeightSpace_constructor as WeightSpace, WeightCharacter @@ -283,7 +285,8 @@ class OverconvergentModularFormsSpace(Module): TESTS:: - sage: K.<w> = Qp(13).extension(x^2-13); M = OverconvergentModularForms(13, 20, radius=1/2, base_ring=K) + sage: x = polygen(ZZ, 'x') + sage: K.<w> = Qp(13).extension(x^2 - 13); M = OverconvergentModularForms(13, 20, radius=1/2, base_ring=K) sage: M is loads(dumps(M)) True """ @@ -357,6 +360,7 @@ def _set_radius(self, radius): sage: M._set_radius(1/3); M Space of 3-adic 1/3-overconvergent modular forms of weight-character 2 over Rational Field + sage: x = polygen(ZZ, 'x') sage: L.<w> = Qp(3).extension(x^5 - 3) sage: OverconvergentModularForms(3, 2, 1/30, base_ring=L).normalising_factor() # indirect doctest w + O(w^101) @@ -418,13 +422,15 @@ def change_ring(self, ring): def base_extend(self, ring): r""" - Return the base extension of self to the given base ring. There must be - a canonical map to this ring from the current base ring, otherwise a - TypeError will be raised. + Return the base extension of ``self`` to the given base ring. + + There must be a canonical map to this ring from the current + base ring, otherwise a :class:`TypeError` will be raised. EXAMPLES:: - sage: M = OverconvergentModularForms(2, 0, 1/2, base_ring = Qp(2)) + sage: M = OverconvergentModularForms(2, 0, 1/2, base_ring=Qp(2)) + sage: x = polygen(ZZ, 'x') sage: M.base_extend(Qp(2).extension(x^2 - 2, names="w")) Space of 2-adic 1/2-overconvergent modular forms of weight-character 0 over 2-adic Eisenstein Extension ... sage: M.base_extend(QQ) @@ -490,6 +496,7 @@ def normalising_factor(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<w> = Qp(7).extension(x^2 - 7) sage: OverconvergentModularForms(7, 0, 1/4, base_ring=L).normalising_factor() w + O(w^41) @@ -555,6 +562,7 @@ def _params(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<w> = Qp(7).extension(x^2 - 7) sage: OverconvergentModularForms(7, 0, 1/4, base_ring=L)._params() (7, @@ -573,6 +581,7 @@ def __reduce__(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<w> = Qp(7).extension(x^2 - 7) sage: OverconvergentModularForms(7, 0, 1/4, base_ring=L).__reduce__() (<function OverconvergentModularForms at ...>, @@ -778,7 +787,9 @@ def zero(self): EXAMPLES:: - sage: K.<w> = Qp(13).extension(x^2-13); M = OverconvergentModularForms(13, 20, radius=1/2, base_ring=K) + sage: x = polygen(ZZ, 'x') + sage: K.<w> = Qp(13).extension(x^2 - 13) + sage: M = OverconvergentModularForms(13, 20, radius=1/2, base_ring=K) sage: K.zero() 0 """ @@ -851,11 +862,10 @@ def coordinate_vector(self, x): return self.base_extend(x.base_ring()).coordinate_vector(x) if x.parent() != self: - x = self(x) + x = self(x) return vector(self.base_ring(), x.gexp().padded_list(x.gexp().prec())) - ########################################################## # Pointless routines required by parent class definition # ########################################################## @@ -926,13 +936,11 @@ def hecke_operator(self, f, m): else: return hecke_operator_on_qexp(f, m, self.weight().k(), eps=self.weight().chi()) - - def _convert_to_basis(self, qexp): r""" Given a `q`-expansion, converts it to a vector in the basis of this space, to the maximum possible precision (which is the minimum of the - `q`-adic precision of the `q`-expansion and the precision of self). + `q`-adic precision of the `q`-expansion and the precision of ``self``). EXAMPLES:: @@ -946,8 +954,8 @@ def _convert_to_basis(self, qexp): g = self._gsr.gen() answer = self._gsr(0) for i in range(n): - assert(x.valuation() >= i) - answer += (x[i] / self._basis_cache[i][i])*g**i + assert x.valuation() >= i + answer += (x[i] / self._basis_cache[i][i]) * g**i x = x - self._basis_cache[i] * answer[i] return answer + O(g**n) @@ -1014,7 +1022,6 @@ def hecke_matrix(self, m, n, use_recurrence=False, exact_arith=False): raise ValueError("n is too large computing initial conds: can't work out u[%s,%s]" % (i,j)) mat[i,j] = 0 - else: l = self._convert_to_basis(self.hecke_operator(self._basis_cache[j], m)) for i in range(self.prime()): @@ -1210,7 +1217,6 @@ def recurrence_matrix(self, use_smithline=True): self._cached_recurrence_matrix.set_immutable() return self._cached_recurrence_matrix - def _discover_recurrence_matrix(self, use_smithline=True): r""" Does hard work of calculating recurrence matrix, which is cached to avoid doing this every time. @@ -1296,7 +1302,9 @@ class OverconvergentModularFormElement(ModuleElement): EXAMPLES:: - sage: K.<w> = Qp(5).extension(x^7 - 5); s = OverconvergentModularForms(5, 6, 1/21, base_ring=K).0 + sage: x = polygen(ZZ, 'x') + sage: K.<w> = Qp(5).extension(x^7 - 5) + sage: s = OverconvergentModularForms(5, 6, 1/21, base_ring=K).0 sage: s == loads(dumps(s)) True """ @@ -1329,10 +1337,11 @@ def __init__(self, parent, gexp=None, qexp=None): self._eigenvalue = None self._slope = None - def _add_(self, other): r""" - Add self to other (where other has the same parent as self). + Add ``self`` to ``other``. + + Here ``other`` has the same parent as ``self``. EXAMPLES:: @@ -1663,7 +1672,9 @@ def weight(self): EXAMPLES:: - sage: M = OverconvergentModularForms(13, 10, 1/2, base_ring = Qp(13).extension(x^2 - 13,names='a')) + sage: x = polygen(ZZ, 'x') + sage: R = Qp(13).extension(x^2 - 13, names='a') + sage: M = OverconvergentModularForms(13, 10, 1/2, base_ring=R) sage: M.gen(0).weight() 10 """ @@ -1676,7 +1687,9 @@ def additive_order(self): EXAMPLES:: - sage: M = OverconvergentModularForms(13, 10, 1/2, base_ring = Qp(13).extension(x^2 - 13,names='a')) + sage: x = polygen(ZZ, 'x') + sage: R = Qp(13).extension(x^2 - 13, names='a') + sage: M = OverconvergentModularForms(13, 10, 1/2, base_ring=R) sage: M.gen(0).additive_order() +Infinity sage: M(0).additive_order() diff --git a/src/sage/modular/overconvergent/hecke_series.py b/src/sage/modular/overconvergent/hecke_series.py index 2da21b57b77..fa66f2aa0a3 100644 --- a/src/sage/modular/overconvergent/hecke_series.py +++ b/src/sage/modular/overconvergent/hecke_series.py @@ -74,7 +74,7 @@ from sage.matrix.constructor import matrix, random_matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.functional import dimension, transpose, charpoly -from sage.misc.misc import cputime +from sage.misc.timing import cputime from sage.misc.verbose import verbose from sage.modular.dims import dimension_modular_forms from sage.modular.modform.all import ModularForms, ModularFormsRing, delta_qexp, eisenstein_series_qexp @@ -925,8 +925,8 @@ def katz_expansions(k0, p, ellp, mdash, n): S = Zmod(p ** mdash) Ep1 = eisenstein_series_qexp(p - 1, ellp, K=S, normalization="constant") - E4 = eisenstein_series_qexp(4, ellp, K=S, normalization="constant") - E6 = eisenstein_series_qexp(6, ellp, K=S, normalization="constant") + E4 = eisenstein_series_qexp(4, ellp, K=S, normalization="constant") + E6 = eisenstein_series_qexp(6, ellp, K=S, normalization="constant") delta = delta_qexp(ellp, K=S) h = delta / E6 ** 2 diff --git a/src/sage/modular/overconvergent/weightspace.py b/src/sage/modular/overconvergent/weightspace.py index e7716b173a6..e9478c40a90 100644 --- a/src/sage/modular/overconvergent/weightspace.py +++ b/src/sage/modular/overconvergent/weightspace.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.rings.padics r""" The space of `p`-adic weights @@ -17,7 +17,8 @@ sage: W = pAdicWeightSpace(17) sage: W - Space of 17-adic weight-characters defined over 17-adic Field with capped relative precision 20 + Space of 17-adic weight-characters + defined over 17-adic Field with capped relative precision 20 sage: R.<x> = QQ[] sage: L = Qp(17).extension(x^2 - 17, names='a'); L.rename('L') sage: W.base_extend(L) @@ -68,18 +69,20 @@ from sage.arith.misc import divisors from sage.categories.sets_cat import Sets from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.modular.dirichlet import DirichletGroup, trivial_character from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ -from sage.rings.padics.factory import Qp -from sage.rings.padics.padic_generic_element import pAdicGenericElement from sage.rings.padics.precision_error import PrecisionError from sage.rings.rational_field import QQ from sage.structure.element import Element from sage.structure.parent import Parent from sage.structure.richcmp import richcmp +lazy_import('sage.rings.padics.factory', 'Qp') +lazy_import('sage.rings.padics.padic_generic_element', 'pAdicGenericElement') + _wscache = {} def WeightSpace_constructor(p, base_ring=None): @@ -99,7 +102,8 @@ def WeightSpace_constructor(p, base_ring=None): EXAMPLES:: sage: pAdicWeightSpace(3) # indirect doctest - Space of 3-adic weight-characters defined over 3-adic Field with capped relative precision 20 + Space of 3-adic weight-characters + defined over 3-adic Field with capped relative precision 20 sage: pAdicWeightSpace(3, QQ) Space of 3-adic weight-characters defined over Rational Field sage: pAdicWeightSpace(10) @@ -246,11 +250,13 @@ def base_extend(self, R): sage: W = pAdicWeightSpace(3, QQ) sage: W.base_extend(Qp(3)) - Space of 3-adic weight-characters defined over 3-adic Field with capped relative precision 20 + Space of 3-adic weight-characters + defined over 3-adic Field with capped relative precision 20 sage: W.base_extend(IntegerModRing(12)) Traceback (most recent call last): ... - TypeError: No coercion map from 'Rational Field' to 'Ring of integers modulo 12' is defined + TypeError: No coercion map from 'Rational Field' + to 'Ring of integers modulo 12' is defined """ if R.has_coerce_map_from(self.base_ring()): return WeightSpace_constructor(self.prime(), R) @@ -354,7 +360,9 @@ def pAdicEisensteinSeries(self, ring, prec=20): sage: kappa = pAdicWeightSpace(3)(3, DirichletGroup(3,QQ).0) sage: kappa.pAdicEisensteinSeries(QQ[['q']], 20) - 1 - 9*q + 27*q^2 - 9*q^3 - 117*q^4 + 216*q^5 + 27*q^6 - 450*q^7 + 459*q^8 - 9*q^9 - 648*q^10 + 1080*q^11 - 117*q^12 - 1530*q^13 + 1350*q^14 + 216*q^15 - 1845*q^16 + 2592*q^17 + 27*q^18 - 3258*q^19 + O(q^20) + 1 - 9*q + 27*q^2 - 9*q^3 - 117*q^4 + 216*q^5 + 27*q^6 - 450*q^7 + 459*q^8 + - 9*q^9 - 648*q^10 + 1080*q^11 - 117*q^12 - 1530*q^13 + 1350*q^14 + 216*q^15 + - 1845*q^16 + 2592*q^17 + 27*q^18 - 3258*q^19 + O(q^20) """ if not self.is_even(): raise ValueError("Eisenstein series not defined for odd weight-characters") @@ -568,7 +576,8 @@ def chi(self): sage: kappa = pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0^14) sage: kappa.chi() - Dirichlet character modulo 29 of conductor 29 mapping 2 |--> 28 + 28*29 + 28*29^2 + ... + O(29^20) + Dirichlet character modulo 29 of conductor 29 + mapping 2 |--> 28 + 28*29 + 28*29^2 + ... + O(29^20) """ return self._chi @@ -665,7 +674,8 @@ def Lvalue(self): sage: pAdicWeightSpace(7)(5, DirichletGroup(7, Qp(7)).0^4).Lvalue() 0 sage: pAdicWeightSpace(7)(6, DirichletGroup(7, Qp(7)).0^4).Lvalue() - 1 + 2*7 + 7^2 + 3*7^3 + 3*7^5 + 4*7^6 + 2*7^7 + 5*7^8 + 2*7^9 + 3*7^10 + 6*7^11 + 2*7^12 + 3*7^13 + 5*7^14 + 6*7^15 + 5*7^16 + 3*7^17 + 6*7^18 + O(7^19) + 1 + 2*7 + 7^2 + 3*7^3 + 3*7^5 + 4*7^6 + 2*7^7 + 5*7^8 + 2*7^9 + 3*7^10 + 6*7^11 + + 2*7^12 + 3*7^13 + 5*7^14 + 6*7^15 + 5*7^16 + 3*7^17 + 6*7^18 + O(7^19) """ if self._k > 0: return -self._chi.bernoulli(self._k) / self._k diff --git a/src/sage/modular/pollack_stevens/__init__.py b/src/sage/modular/pollack_stevens/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/pollack_stevens/dist.pxd b/src/sage/modular/pollack_stevens/dist.pxd index b922aefceea..95689892050 100644 --- a/src/sage/modular/pollack_stevens/dist.pxd +++ b/src/sage/modular/pollack_stevens/dist.pxd @@ -30,7 +30,6 @@ cdef class WeightKAction(Action): cdef public _dettwist cdef public _Sigma0 - cpdef acting_matrix(self, g, M) cpdef _compute_acting_matrix(self, g, M) diff --git a/src/sage/modular/pollack_stevens/dist.pyx b/src/sage/modular/pollack_stevens/dist.pyx index 3261d09d2c2..7a869a1c05a 100644 --- a/src/sage/modular/pollack_stevens/dist.pyx +++ b/src/sage/modular/pollack_stevens/dist.pyx @@ -18,46 +18,30 @@ REFERENCES: - [PS2011]_ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Robert Pollack <rpollack@math.bu.edu> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -from sage.structure.sage_object cimport SageObject from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.arith.misc import binomial, bernoulli -from sage.modules.free_module_element import vector, zero_vector from sage.matrix.matrix cimport Matrix -from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import matrix -from sage.misc.prandom import random -from sage.structure.element cimport RingElement, Element +from sage.structure.element cimport Element import operator from sage.rings.padics.padic_generic import pAdicGeneric -from sage.rings.padics.padic_capped_absolute_element cimport pAdicCappedAbsoluteElement -from sage.rings.padics.padic_capped_relative_element cimport pAdicCappedRelativeElement -from sage.rings.padics.padic_fixed_mod_element cimport pAdicFixedModElement from sage.rings.integer cimport Integer -from sage.rings.rational cimport Rational -from sage.misc.misc import cputime from sage.misc.verbose import verbose from sage.rings.infinity import Infinity -from sage.libs.flint.nmod_poly cimport (nmod_poly_init2_preinv, - nmod_poly_set_coeff_ui, - nmod_poly_inv_series, - nmod_poly_mullow, - nmod_poly_pow_trunc, - nmod_poly_get_coeff_ui, nmod_poly_t) - #from sage.libs.flint.ulong_extras cimport * from .sigma0 import Sigma0 @@ -293,7 +277,7 @@ cdef class Dist(ModuleElement): use_arg = False if not z: return False - for a in xrange(1, n): + for a in range(1, n): if usearg: try: z = self._unscaled_moment(a).is_zero(M - a) @@ -351,8 +335,8 @@ cdef class Dist(ModuleElement): other_pr = other.precision_relative() if n == 0: raise ValueError("self is zero") - verbose("n = %s" % n, level = 2) - verbose("moment 0", level = 2) + verbose("n = %s" % n, level=2) + verbose("moment 0", level=2) a = self._unscaled_moment(i) verbose("a = %s" % a, level = 2) padic = isinstance(a.parent(), pAdicGeneric) @@ -405,7 +389,7 @@ cdef class Dist(ModuleElement): verbose("comparing p moment %s" % i, level = 2) a = self._unscaled_moment(i) if check: -# verbose("self.moment=%s, other.moment=%s" % (a, other._unscaled_moment(i))) + # verbose("self.moment=%s, other.moment=%s" % (a, other._unscaled_moment(i))) if (padic and other._unscaled_moment(i) != alpha * a) or \ (not padic and other._unscaled_moment(i) % p ** (n - i) != alpha * a % p ** (n - i)): raise ValueError("not a scalar multiple") @@ -472,14 +456,12 @@ cdef class Dist(ModuleElement): """ cdef Dist other = _other n = self.precision_relative() - other_pr = other.precision_relative() if n == 0: raise ValueError("zeroth moment is zero") verbose("n = %s" % n, level = 2) a = self.moment(0) if a.is_zero(): raise ValueError("zeroth moment is zero") - padic = isinstance(a.parent(), pAdicGeneric) alpha = other.moment(0) / a if check: for i in range(1, n): @@ -527,7 +509,7 @@ cdef class Dist(ModuleElement): left.normalize() right.normalize() cdef long rprec = min(left._relprec(), right._relprec()) - cdef long i, c + cdef long i p = left.parent().prime() if left.ordp > right.ordp: shift = p ** (left.ordp - right.ordp) @@ -871,7 +853,7 @@ cdef class Dist_vector(Dist): sage: QQ(d) 4/3 - We get a TypeError if there is more than 1 moment:: + We get a :class:`TypeError` if there is more than 1 moment:: sage: D = Symk(1); d = D([1,2]); d (1, 2) @@ -1473,7 +1455,6 @@ cdef class WeightKAction_vector(WeightKAction): g.set_immutable() except AttributeError: pass - coeffmodule = v._moments.parent() v_moments = v._moments ans._moments = v_moments * self.acting_matrix(g, len(v_moments)) ans.ordp = v.ordp diff --git a/src/sage/modular/pollack_stevens/distributions.py b/src/sage/modular/pollack_stevens/distributions.py index 1bb73ceacc9..274cdfa87a4 100644 --- a/src/sage/modular/pollack_stevens/distributions.py +++ b/src/sage/modular/pollack_stevens/distributions.py @@ -40,19 +40,21 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.misc.lazy_import import lazy_import from sage.modules.module import Module from sage.structure.parent import Parent -from sage.rings.padics.factory import ZpCA, QpCR -from sage.rings.padics.padic_generic import pAdicGeneric from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method from sage.categories.modules import Modules -from sage.modular.pollack_stevens.dist import get_dist_classes # , Dist_long from sage.structure.factory import UniqueFactory import sage.rings.ring as ring +lazy_import('sage.modular.pollack_stevens.dist', 'get_dist_classes') +lazy_import('sage.rings.padics.factory', ['ZpCA', 'QpCR']) +lazy_import('sage.rings.padics.padic_generic', 'pAdicGeneric') + from .sigma0 import _default_adjuster @@ -222,6 +224,7 @@ def create_object(self, version, key): """ return Symk_class(*key) + OverconvergentDistributions = OverconvergentDistributions_factory('OverconvergentDistributions') Symk = Symk_factory('Symk') diff --git a/src/sage/modular/pollack_stevens/fund_domain.py b/src/sage/modular/pollack_stevens/fund_domain.py index 3e25c950b30..4bd2638d5a6 100644 --- a/src/sage/modular/pollack_stevens/fund_domain.py +++ b/src/sage/modular/pollack_stevens/fund_domain.py @@ -56,6 +56,7 @@ def M2Z(x): x.set_immutable() return x + Id = M2Z([1, 0, 0, 1]) sig = M2Z([0, 1, -1, 0]) tau = M2Z([0, -1, 1, -1]) diff --git a/src/sage/modular/pollack_stevens/modsym.py b/src/sage/modular/pollack_stevens/modsym.py index 0d0f064445c..78e601189a8 100644 --- a/src/sage/modular/pollack_stevens/modsym.py +++ b/src/sage/modular/pollack_stevens/modsym.py @@ -42,16 +42,18 @@ from sage.arith.misc import next_prime, gcd, kronecker from sage.categories.action import Action from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose from sage.rings.integer_ring import ZZ -from sage.rings.padics.factory import Qp -from sage.rings.padics.padic_generic import pAdicGeneric from sage.rings.padics.precision_error import PrecisionError from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ from sage.structure.element import ModuleElement from sage.structure.richcmp import op_EQ, op_NE +lazy_import('sage.rings.padics.factory', 'Qp') +lazy_import('sage.rings.padics.padic_generic', 'pAdicGeneric') + from .manin_map import ManinMap from .sigma0 import Sigma0 from .fund_domain import M2Z @@ -94,22 +96,22 @@ def _iterate_Up(Phi, p, M, ap, q, aq, check): raise ValueError("Lifting non-ordinary eigensymbols not implemented (issue #20)") # Act by Hecke to ensure values are in D and not D^dag after solving difference equation - verbose("Applying Hecke", level = 2) + verbose("Applying Hecke", level=2) apinv = ~ap Phi = apinv * Phi.hecke(p) # Killing eisenstein part - verbose("Killing eisenstein part with q = %s" % q, level = 2) + verbose("Killing eisenstein part with q = %s" % q, level=2) k = Phi.parent().weight() Phi = ((q ** (k + 1) + 1) * Phi - Phi.hecke(q)) # Iterating U_p - verbose("Iterating U_p", level = 2) + verbose("Iterating U_p", level=2) Psi = apinv * Phi.hecke(p) for attempts in range(M-1): - verbose("%s attempt (val = %s/%s)" % (attempts + 1,(Phi-Psi).valuation(),M), level = 2) + verbose("%s attempt (val = %s/%s)" % (attempts + 1,(Phi-Psi).valuation(),M), level=2) Phi = Psi Psi = apinv * Phi.hecke(p) Psi._normalize() @@ -654,7 +656,7 @@ def Tq_eigenvalue(self, q, p=None, M=None, check=True): i = 0 g = gens[i] - verbose("Computing eigenvalue", level = 2) + verbose("Computing eigenvalue", level=2) while self._map[g].moment(0).is_zero(): if not qhecke._map[g].moment(0).is_zero(): raise ValueError("not a scalar multiple") @@ -665,9 +667,9 @@ def Tq_eigenvalue(self, q, p=None, M=None, check=True): raise ValueError("self is zero") aq = self.parent().base_ring()(self._map[g].find_scalar_from_zeroth_moment(qhecke._map[g], p, M, check)) - verbose("Found eigenvalues of %s" % aq, level = 2) + verbose("Found eigenvalues of %s" % aq, level=2) if check: - verbose("Checking that this is actually an eigensymbol", level = 2) + verbose("Checking that this is actually an eigensymbol", level=2) if p is None or M is None or not ZZ(p).is_prime(): for g in gens[1:]: try: @@ -678,7 +680,7 @@ def Tq_eigenvalue(self, q, p=None, M=None, check=True): if qhecke._map[g] != aq * self._map[g]: raise ValueError("not a scalar multiple") else: - verbose('p = %s, M = %s' % (p, M), level = 2) + verbose('p = %s, M = %s' % (p, M), level=2) if qhecke != aq * self: raise ValueError("not a scalar multiple") # if not aq.parent().is_exact() and M is not None: @@ -830,8 +832,8 @@ def _consistency_check(self): # fundamental domain t = self.parent().coefficient_module().zero() for g in MR.gens()[1:]: - if not(g in MR.reps_with_two_torsion() - or g in MR.reps_with_three_torsion()): + if not (g in MR.reps_with_two_torsion() + or g in MR.reps_with_three_torsion()): t += f[g] * MR.gammas[g] - f[g] else: if g in MR.reps_with_two_torsion(): @@ -843,7 +845,7 @@ def _consistency_check(self): if f[id] * MR.gammas[id] - f[id] != -t: print(t) print(f[id] * MR.gammas[id] - f[id]) - raise ValueError("Does not add up correctly around loop") + raise ValueError("does not add up correctly around loop") print("This modular symbol satisfies the Manin relations") @@ -921,7 +923,7 @@ def _find_alpha(self, p, k, M=None, ap=None, new_base_ring=None, ordinary=True, else: set_padicbase = False try: - verbose("finding alpha: rooting %s in %s" % (poly, new_base_ring), level = 2) + verbose("finding alpha: rooting %s in %s" % (poly, new_base_ring), level=2) poly = poly.change_ring(new_base_ring) (v0, e0), (v1, e1) = poly.roots() except (TypeError, ValueError): @@ -1050,7 +1052,7 @@ def p_stabilize(self, p=None, M=20, alpha=None, ap=None, new_base_ring=None, ord raise ValueError("alpha must be a root of x^2 - a_p*x + p^(k+1)") if self.hecke(p) != ap * self: raise ValueError("alpha must be a root of x^2 - a_p*x + p^(k+1)") - verbose("found alpha = %s" % alpha, level = 2) + verbose("found alpha = %s" % alpha, level=2) V = self.parent()._p_stabilize_parent_space(p, new_base_ring) return self.__class__(self._map.p_stabilize(p, alpha, V), V, construct=True) @@ -1119,7 +1121,7 @@ def completions(self, p, M): return ans def lift(self, p=None, M=None, alpha=None, new_base_ring=None, - algorithm = None, eigensymbol=False, check=True): + algorithm=None, eigensymbol=False, check=True): r""" Return a (`p`-adic) overconvergent modular symbol with `M` moments which lifts self up to an Eisenstein error @@ -1250,17 +1252,17 @@ def lift(self, p=None, M=None, alpha=None, new_base_ring=None, # We need some extra precision due to the fact that solving # the difference equation can give denominators. if alpha is None: - verbose('Finding alpha with M = %s' % M, level = 2) + verbose('Finding alpha with M = %s' % M, level=2) alpha = self.Tq_eigenvalue(p, M=M + 1, check=check) newM, eisenloss, q, aq = self._find_extraprec(p, M + 1, alpha, check) Phi = self._lift_to_OMS(p, newM, new_base_ring, algorithm) Phi = _iterate_Up(Phi, p, newM, alpha, q, aq, check) Phi = Phi.reduce_precision(M) - return Phi._normalize(include_zeroth_moment = True) + return Phi._normalize(include_zeroth_moment=True) else: return self._lift_to_OMS(p, M, new_base_ring, algorithm) - def _lift_to_OMS(self, p, M, new_base_ring, algorithm = 'greenberg'): + def _lift_to_OMS(self, p, M, new_base_ring, algorithm='greenberg'): r""" Return a (`p`-adic) overconvergent modular symbol with `M` moments which lifts self up to an Eisenstein error @@ -1439,7 +1441,6 @@ def _find_extraprec(self, p, M, alpha, check): newM += -s return newM, eisenloss, q, aq - def p_stabilize_and_lift(self, p, M, alpha=None, ap=None, new_base_ring=None, ordinary=True, algorithm='greenberg', eigensymbol=False, @@ -1509,7 +1510,7 @@ def p_stabilize_and_lift(self, p, M, alpha=None, ap=None, Phi = self._lift_to_OMS(p, newM, new_base_ring, algorithm) Phi = _iterate_Up(Phi, p=p, M=newM, ap=alpha, q=q, aq=aq, check=check) Phi = Phi.reduce_precision(M) - return Phi._normalize(include_zeroth_moment = True) + return Phi._normalize(include_zeroth_moment=True) class PSModularSymbolElement_dist(PSModularSymbolElement): @@ -1531,7 +1532,7 @@ def reduce_precision(self, M): def precision_relative(self): r""" - Return the number of moments of each value of self + Return the number of moments of each value of ``self``. EXAMPLES:: @@ -1541,14 +1542,14 @@ def precision_relative(self): sage: f.precision_relative() 1 """ - return min([len(a._moments) for a in self._map]) - + return min(len(a._moments) for a in self._map) def specialize(self, new_base_ring=None): r""" - Return the underlying classical symbol of weight `k` - i.e., - applies the canonical map `D_k \to Sym^k` to all values of - self. + Return the underlying classical symbol of weight `k`. + + Namely, this applies the canonical map `D_k \to Sym^k` to all + values of ``self``. EXAMPLES:: diff --git a/src/sage/modular/pollack_stevens/padic_lseries.py b/src/sage/modular/pollack_stevens/padic_lseries.py index 0692e81aef3..748b5dc9993 100644 --- a/src/sage/modular/pollack_stevens/padic_lseries.py +++ b/src/sage/modular/pollack_stevens/padic_lseries.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.ring.padics r""" `p`-adic `L`-series attached to overconvergent eigensymbols @@ -21,13 +21,15 @@ # **************************************************************************** from sage.arith.misc import kronecker, binomial +from sage.misc.lazy_import import lazy_import from sage.rings.integer_ring import ZZ -from sage.rings.padics.factory import Qp as pAdicField from sage.rings.padics.precision_error import PrecisionError from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject +lazy_import('sage.rings.padics.factory', 'Qp', as_='pAdicField') + class pAdicLseries(SageObject): r""" diff --git a/src/sage/modular/pollack_stevens/sigma0.py b/src/sage/modular/pollack_stevens/sigma0.py index ab8e24959cd..bd203ec8600 100644 --- a/src/sage/modular/pollack_stevens/sigma0.py +++ b/src/sage/modular/pollack_stevens/sigma0.py @@ -162,6 +162,7 @@ def create_object(self, version, key): """ return Sigma0_class(*key) + Sigma0 = Sigma0_factory('sage.modular.pollack_stevens.sigma0.Sigma0') diff --git a/src/sage/modular/pollack_stevens/space.py b/src/sage/modular/pollack_stevens/space.py index 43e396b03c8..88b7be6d2cd 100644 --- a/src/sage/modular/pollack_stevens/space.py +++ b/src/sage/modular/pollack_stevens/space.py @@ -189,6 +189,7 @@ def create_object(self, version, key): """ return PollackStevensModularSymbolspace(*key) + PollackStevensModularSymbols = PollackStevensModularSymbols_factory('PollackStevensModularSymbols') diff --git a/src/sage/modular/quasimodform/__init__.py b/src/sage/modular/quasimodform/__init__.py deleted file mode 100644 index 6e633f48916..00000000000 --- a/src/sage/modular/quasimodform/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import all diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index 6821f3e97bf..b92c31722ac 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -24,7 +24,9 @@ from sage.structure.element import ModuleElement from sage.structure.richcmp import richcmp, op_NE, op_EQ +from sage.rings.integer import Integer from sage.rings.polynomial.polynomial_element import Polynomial +from sage.rings.integer_ring import ZZ class QuasiModularFormsElement(ModuleElement): r""" @@ -463,7 +465,7 @@ def weights_list(self): sage: (QM.0 + QM.1 + QM.2*QM.1 + QM.3*QM.4).weights_list() [2, 5, 7] """ - return sorted(list(self.to_polynomial().homogeneous_components())) + return sorted(self.homogeneous_components().keys()) def is_homogeneous(self): r""" @@ -474,34 +476,39 @@ def is_homogeneous(self): EXAMPLES:: sage: QM = QuasiModularForms(1) - sage: (QM.0).is_homogeneous() + sage: E2, E4, E6 = QM.gens() + sage: (E2).is_homogeneous() True - sage: (QM.0 + QM.1).is_homogeneous() + sage: (E2 + E4).is_homogeneous() False - sage: (QM.0 * QM.1 + QM.2).is_homogeneous() + sage: (E2 * E4 + E6).is_homogeneous() True sage: QM(1).is_homogeneous() True - sage: (1 + QM.0).is_homogeneous() + sage: (1 + E2).is_homogeneous() False - sage: QM = QuasiModularForms(Gamma0(4)) - sage: (QM.0).is_homogeneous() - True - sage: (QM.0 + QM.1).is_homogeneous() - True - sage: (QM.0 + QM.1 + QM.2).is_homogeneous() + sage: F = E6^3 + E4^4*E2 + (E4^2*E6)*E2^2 + (E4^3 + E6^2)*E2^3 + sage: F.is_homogeneous() True - sage: (QM.0 + QM.1^3).is_homogeneous() - False - """ - return len(self.weights_list()) == 1 + k = None + for i, c in enumerate(self._polynomial.coefficients(sparse=False)): + if c: + if not c.is_homogeneous(): + return False + if k is None: + k = c.weight() + 2*i + continue + if c.weight() + 2*i != k: + return False + return True def weight(self): r""" Return the weight of the given quasimodular form. - Note that the given form must be homogeneous. + Note that the given form must be homogeneous. An alias of this method is + ``degree``. EXAMPLES:: @@ -512,15 +519,21 @@ def weight(self): 6 sage: QM(1/2).weight() 0 + sage: (QM.0).degree() + 2 sage: (QM.0 + QM.1).weight() Traceback (most recent call last): ... ValueError: the given graded quasiform is not an homogeneous element """ if self.is_homogeneous(): - return self.to_polynomial().degree() + return (self._polynomial.leading_coefficient().weight() + + 2*self._polynomial.degree()) else: - raise ValueError("the given graded quasiform is not an homogeneous element") + raise ValueError("the given graded quasiform is not an homogeneous \ + element") + + degree = weight # alias def homogeneous_components(self): r""" @@ -538,17 +551,76 @@ def homogeneous_components(self): 6: 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)} sage: (1 + QM.0).homogeneous_components() {0: 1, 2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)} - sage: QM = QuasiModularForms(Gamma0(5)) - sage: F = QM.0 + QM.1 * QM.0 + QM.3^2*QM.0 + sage: QM5 = QuasiModularForms(Gamma1(3)) + sage: F = QM.1 + QM.1*QM.2 + QM.1*QM.0 + (QM.1 + QM.2^2)*QM.0^3 sage: F.homogeneous_components() - {2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6), - 4: 1 - 18*q - 198*q^2 - 936*q^3 - 2574*q^4 - 5610*q^5 + O(q^6), - 10: q^2 - 24*q^3 - 52*q^4 - 520*q^5 + O(q^6)} + {4: 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6), + 6: 1 + 216*q - 3672*q^2 - 62496*q^3 - 322488*q^4 - 1121904*q^5 + O(q^6), + 10: 2 - 96*q - 149040*q^2 - 4986240*q^3 - 67535952*q^4 - 538187328*q^5 + O(q^6), + 18: 1 - 1080*q + 294840*q^2 - 902880*q^3 - 452402280*q^4 + 105456816*q^5 + O(q^6)} + sage: F = QM.zero() + sage: F.homogeneous_components() + {0: 0} + sage: F = QM(42/13) + sage: F.homogeneous_components() + {0: 42/13} """ QM = self.parent() - poly_self = self.to_polynomial() - pol_hom_comp = poly_self.homogeneous_components() - return {k: QM.from_polynomial(pol) for k, pol in pol_hom_comp.items()} + if self.is_zero(): + return {ZZ(0): self} + components = {} + E2 = self.parent().weight_2_eisenstein_series() + for i, c in enumerate(self._polynomial.coefficients(sparse=False)): + if c: + forms = c._forms_dictionary + for k in forms.keys(): + try: + components[ZZ(k + 2*i)] += QM(forms[k]*(E2**i)) + except KeyError: + components[ZZ(k + 2*i)] = QM(forms[k]*(E2**i)) + return components + + def __getitem__(self, weight): + r""" + Return the homogeneous component of the given quasimodular form ring + element. + + An alias of this method is ``homogeneous_component``. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: E2, E4, E6 = QM.gens() + sage: F = E2 + E4*E6 + E2^3*E6 + sage: F[2] + 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6) + sage: F[10] + 1 - 264*q - 135432*q^2 - 5196576*q^3 - 69341448*q^4 - 515625264*q^5 + O(q^6) + sage: F[12] + 1 - 576*q + 21168*q^2 + 308736*q^3 - 15034608*q^4 - 39208320*q^5 + O(q^6) + sage: F[4] + 0 + sage: F.homogeneous_component(2) + 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6) + + TESTS:: + + sage: F[x] + Traceback (most recent call last): + ... + KeyError: 'the weight must be an integer' + sage: F[-1] + Traceback (most recent call last): + ... + ValueError: the weight must be nonnegative + """ + if not isinstance(weight, (int, Integer)): + raise KeyError("the weight must be an integer") + if weight < 0: + raise ValueError("the weight must be nonnegative") + return self.homogeneous_components().get(weight, self.parent().zero()) + + homogeneous_component = __getitem__ # alias def serre_derivative(self): r""" diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index 5579aa621d6..ee939a182df 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -216,6 +216,7 @@ class QuasiModularForms(Parent, UniqueRepresentation): NotImplementedError: base ring other than Q are not yet supported for quasimodular forms ring """ Element = QuasiModularFormsElement + def __init__(self, group=1, base_ring=QQ, name='E2'): r""" INPUT: diff --git a/src/sage/modular/quatalg/__init__.py b/src/sage/modular/quatalg/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index 9bbe2865b47..1c74d953f6d 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -202,12 +202,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra, basis_for_quaternion_lattice -from sage.algebras.quatalg.quaternion_algebra_cython import rational_matrix_from_rational_quaternions from sage.arith.misc import gcd, factor, prime_divisors, kronecker, next_prime from sage.matrix.constructor import matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.modular.dirichlet import TrivialCharacter @@ -223,6 +222,9 @@ from sage.rings.ring import CommutativeRing from sage.structure.richcmp import richcmp, richcmp_method +lazy_import('sage.algebras.quatalg.quaternion_algebra', ['QuaternionAlgebra', 'basis_for_quaternion_lattice']) +lazy_import('sage.algebras.quatalg.quaternion_algebra_cython', 'rational_matrix_from_rational_quaternions') + cache = {} @@ -399,7 +401,7 @@ def basis_for_left_ideal(R, gens): sage: sage.modular.quatalg.brandt.basis_for_left_ideal(B.maximal_order(), [3*(i+j),3*(i-j),6*k,A(3)]) [3/2 + 1/2*i + k, i + 2*k, 3/2*j + 3/2*k, 3*k] """ - return basis_for_quaternion_lattice([b * g for b in R.basis() for g in gens]) + return basis_for_quaternion_lattice([b * g for b in R.basis() for g in gens], reverse=False) def right_order(R, basis): @@ -876,7 +878,7 @@ def cyclic_submodules(self, I, p): """ if not Integer(p).is_prime(): raise ValueError("p must be a prime") - if not(self.level() % p): + if not self.level() % p: raise ValueError("p must be coprime to the level") R = self.order_of_level_N() @@ -922,7 +924,7 @@ def cyclic_submodules(self, I, p): v = [A(1), alpha, beta, alpha * beta] M = rational_matrix_from_rational_quaternions(v) e = M.determinant() - if e and not((d / e).valuation(p)): + if e and not (d / e).valuation(p): S = A.quaternion_order(v) break if S is not None: @@ -1177,7 +1179,7 @@ def _compute_hecke_matrix_directly(self, n, B=None, sparse=False): for r in range(len(C)): percent_done = 100 * r // len(C) if percent_done != last_percent: - if not(percent_done % 5): + if not percent_done % 5: verbose("percent done: %s" % percent_done) last_percent = percent_done if use_fast_alg: @@ -1296,7 +1298,7 @@ def _smallest_good_prime(self): """ level = self.level() p = ZZ(2) - while not(level % p): + while not level % p: p = next_prime(p) return p @@ -1555,7 +1557,7 @@ def eisenstein_subspace(self): p = Integer(2) N = self.level() while V.dimension() >= 2: - while not(N % p): + while not N % p: p = p.next_prime() A = V.T(p) - (p + 1) V = A.kernel() @@ -1690,7 +1692,7 @@ def benchmark_sage(levels, silent=False): ('sage', 43, 2, ...) ('sage', 97, 2, ...) """ - from sage.misc.misc import cputime + from sage.misc.timing import cputime ans = [] for p, M in levels: t = cputime() diff --git a/src/sage/modular/ssmod/__init__.py b/src/sage/modular/ssmod/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/ssmod/ssmod.py b/src/sage/modular/ssmod/ssmod.py index 089089995b8..a23320cecb0 100644 --- a/src/sage/modular/ssmod/ssmod.py +++ b/src/sage/modular/ssmod/ssmod.py @@ -68,8 +68,8 @@ # **************************************************************************** from sage.arith.misc import kronecker, next_prime -from sage.libs.pari.all import pari from sage.matrix.matrix_space import MatrixSpace +from sage.misc.lazy_import import lazy_import from sage.modular.arithgroup.all import Gamma0 from sage.modular.hecke.module import HeckeModule_free_module from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -78,6 +78,8 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.richcmp import richcmp_method, richcmp +lazy_import('sage.libs.pari.all', 'pari') + ZZy = PolynomialRing(ZZ, 'y') @@ -233,8 +235,8 @@ def dimension_supersingular_module(prime, level=1): - Iftikhar Burhanuddin - burhanud@usc.edu """ - if not(Integer(prime).is_prime()): - raise ValueError("%s is not a prime" % prime) + if not Integer(prime).is_prime(): + raise ValueError(f"{prime} is not a prime") if level == 1: return Gamma0(prime).dimension_modular_forms(2) @@ -243,8 +245,7 @@ def dimension_supersingular_module(prime, level=1): # elif (level in [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 16, 18, 25]): # compute basis - else: - raise NotImplementedError + raise NotImplementedError def supersingular_D(prime): @@ -331,12 +332,12 @@ def supersingular_j(FF): - Iftikhar Burhanuddin -- burhanud@usc.edu """ - if not(FF.is_field()) or not(FF.is_finite()): + if not FF.is_field() or not FF.is_finite(): raise ValueError("%s is not a finite field" % FF) prime = FF.characteristic() - if not(Integer(prime).is_prime()): + if not Integer(prime).is_prime(): raise ValueError("%s is not a prime" % prime) - if not(Integer(FF.cardinality())) == Integer(prime**2): + if FF.cardinality() != Integer(prime**2): raise ValueError("%s is not a quadratic extension" % FF) if kronecker(-1, prime) != 1: j_invss = 1728 # (2^2 * 3)^3 diff --git a/src/sage/modules/__init__.py b/src/sage/modules/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modules/all.py b/src/sage/modules/all.py index a90258d7ec8..87621e61b29 100644 --- a/src/sage/modules/all.py +++ b/src/sage/modules/all.py @@ -23,6 +23,8 @@ from .vector_space_morphism import linear_transformation +from .with_basis.all import * + from sage.misc.lazy_import import lazy_import lazy_import('sage.modules.filtered_vector_space', 'FilteredVectorSpace') diff --git a/src/sage/modules/complex_double_vector.py b/src/sage/modules/complex_double_vector.py index faf935694a6..88ad6bb6d67 100644 --- a/src/sage/modules/complex_double_vector.py +++ b/src/sage/modules/complex_double_vector.py @@ -7,10 +7,9 @@ TESTS:: - sage: v = vector(CDF,[(1,-1), (2,pi), (3,5)]) - sage: v + sage: v = vector(CDF,[(1,-1), (2,pi), (3,5)]); v # needs sage.symbolic (1.0 - 1.0*I, 2.0 + 3.141592653589793*I, 3.0 + 5.0*I) - sage: loads(dumps(v)) == v + sage: loads(dumps(v)) == v # needs sage.symbolic True """ diff --git a/src/sage/modules/diamond_cutting.py b/src/sage/modules/diamond_cutting.py index b18fc315754..786a783fabf 100644 --- a/src/sage/modules/diamond_cutting.py +++ b/src/sage/modules/diamond_cutting.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron """ Diamond cutting implementation diff --git a/src/sage/modules/fg_pid/__init__.py b/src/sage/modules/fg_pid/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/databases/__init__.py b/src/sage/modules/fg_pid/all.py similarity index 100% rename from src/sage/databases/__init__.py rename to src/sage/modules/fg_pid/all.py diff --git a/src/sage/modules/fg_pid/fgp_element.py b/src/sage/modules/fg_pid/fgp_element.py index faf255b2ded..dbb13dadbad 100644 --- a/src/sage/modules/fg_pid/fgp_element.py +++ b/src/sage/modules/fg_pid/fgp_element.py @@ -21,7 +21,7 @@ # This adds extra maybe-not-necessary checks in the code, but could # slow things down. It can impact what happens in more than just this # file. -DEBUG=True +DEBUG = True class FGP_Element(ModuleElement): @@ -120,7 +120,6 @@ def lift(self): """ return self._x - def __neg__(self): """ EXAMPLES:: @@ -135,7 +134,6 @@ def __neg__(self): P = self.parent() return P.element_class(P, -self._x) - def _add_(self, other): """ EXAMPLES:: @@ -156,7 +154,7 @@ def _add_(self, other): sage: 0 + x (1, 0) - We test canonical coercion from V and W. + We test canonical coercion from V and W:: sage: Q.0 + V.0 (1, 8) @@ -170,7 +168,6 @@ def _add_(self, other): P = self.parent() return P.element_class(P, self._x + other._x) - def _sub_(self, other): """ EXAMPLES:: @@ -190,7 +187,6 @@ def _sub_(self, other): P = self.parent() return P.element_class(P, self._x - other._x) - def _rmul_(self, c): """ Multiplication by a scalar from the left (``self`` is on the right). @@ -293,7 +289,6 @@ def _repr_(self): """ return repr(self.vector()) - def __getitem__(self, *args): """ EXAMPLES:: diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index 719c781ddc3..f2b1063ce64 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -2,7 +2,7 @@ Finitely generated modules over a PID You can use Sage to compute with finitely generated modules (FGM's) -over a principal ideal domain R presented as a quotient `V / W`, where `V` +over a principal ideal domain `R` presented as a quotient `V / W`, where `V` and `W` are free. .. NOTE:: @@ -13,44 +13,45 @@ obstruction to extending the implementation is only that one has to decide how elements print. -We represent ``M = V / W`` as a pair ``(V, W)`` with ``W`` contained in -``V``, and we internally represent elements of M non-canonically as elements -``x`` of ``V``. We also fix independent generators ``g[i]`` for ``M`` in -``V``, and when we print out elements of ``V`` we print their coordinates +We represent `M = V / W` as a pair `(V, W)` with `W` contained in +`V`, and we internally represent elements of `M` non-canonically as elements +`x` of `V`. We also fix independent generators ``g[i]`` for `M` in +`V`, and when we print out elements of `V` we print their coordinates with respect to the ``g[i]``; over `\ZZ` this is canonical, since each -coefficient is reduce modulo the additive order of ``g[i]``. To obtain -the vector in ``V`` corresponding to ``x`` in ``M``, use ``x.lift()``. +coefficient is reduced modulo the additive order of ``g[i]``. To obtain +the vector in `V` corresponding to `x` in `M`, use ``x.lift()``. -Morphisms between finitely generated R modules are well supported. +Morphisms between finitely generated `R`-modules are well supported. You create a homomorphism by simply giving the images of generators of -M0 in M1. Given a morphism phi:M0-->M1, you can compute the image of -phi, the kernel of phi, and using ``y = phi.lift(x)`` you can lift an -elements x in M1 to an element y in M0, if such a y exists. +`M_0` in `M_1`. Given a morphism `\phi: M_0 \to M_1`, you can compute the image of +`\phi`, the kernel of `\phi`, and using ``y = phi.lift(x)`` you can lift an +element `x` in `M_1` to an element `y` in `M_0`, if such a `y` exists. TECHNICAL NOTE: For efficiency, we introduce a notion of optimized representation for quotient modules. The optimized representation of -M=V/W is the quotient V'/W' where V' has as basis lifts of the -generators ``g[i]`` for M. We internally store a morphism from M0=V0/W0 -to M1=V1/W1 by giving a morphism from the optimized representation V0' -of M0 to V1 that sends W0 into W1. +`M=V/W` is the quotient `V'/W'` where `V'` has as basis lifts of the +generators ``g[i]`` for `M`. We internally store a morphism from `M_0=V_0/W_0` +to `M_1=V_1/W_1` by giving a morphism from the optimized representation `V_0'` +of `M_0` to `V_1` that sends `W_0` into `W_1`. The following TUTORIAL illustrates several of the above points. -First we create free modules V0 and W0 and the quotient module M0. -Notice that everything works fine even though V0 and W0 are not +First we create free modules `V_0` and `W_0` and the quotient module `M_0`. +Notice that everything works fine even though `V_0` and `W_0` are not contained inside `\ZZ^n`, which is extremely convenient. :: - sage: V0 = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W0 = V0.span([V0.0+2*V0.1, 9*V0.0+2*V0.1, 4*V0.2]) + sage: V0 = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ) + sage: W0 = V0.span([V0.0 + 2*V0.1, 9*V0.0 + 2*V0.1, 4*V0.2]) sage: M0 = V0/W0; M0 Finitely generated module V/W over Integer Ring with invariants (4, 16) The invariants are computed using the Smith normal form algorithm, and determine the structure of this finitely generated module. -You can get the V and W used in constructing the quotient module using -V() and W() methods:: +You can get the `V` and `W` used in constructing the quotient module using +the methods :meth:`V` and :meth:`W`:: sage: M0.V() Free module of degree 3 and rank 3 over Integer Ring @@ -65,8 +66,8 @@ [ 0 32 0] [ 0 0 4] -We note that the optimized representation of M0, mentioned above in -the technical note has a V that need not be equal to V0, in general. :: +We note that the optimized representation of `M_0`, mentioned above in +the technical note, has a `V` that need not be equal to `V_0`, in general. :: sage: M0.optimized()[0].V() Free module of degree 3 and rank 2 over Integer Ring @@ -74,9 +75,9 @@ [ 0 8 1] [ 0 -2 0] -Create elements of M0 either by coercing in elements of V0, getting generators, +Create elements of `M_0` either by coercing in elements of `V_0`, getting generators, or coercing in a list or tuple or coercing in 0. Finally, one can express an -element as a linear combination of the smith form generators :: +element as a linear combination of the Smith form generators :: sage: M0(V0.0) (0, 2) @@ -87,9 +88,9 @@ sage: 3*M0.0 + 20*M0.1 (3, 4) -We make an element of M0 by taking a difference of two generators, and +We make an element of `M_0` by taking a difference of two generators, and lift it. We also illustrate making an element from a list, which -coerces to V0, then take the equivalence class modulo W0. :: +coerces to `V_0`, then take the equivalence class modulo `W_0`. :: sage: x = M0.0 - M0.1; x (1, 15) @@ -100,23 +101,24 @@ sage: x.additive_order() 16 -Similarly, we construct V1 and W1, and the quotient M1, in a completely different -2-dimensional ambient space. :: +Similarly, we construct `V_1` and `W_1`, and the quotient `M_1`, +in a completely different 2-dimensional ambient space. :: - sage: V1 = span([[1/2,0],[3/2,2]],ZZ); W1 = V1.span([2*V1.0, 3*V1.1]) + sage: V1 = span([[1/2,0], [3/2,2]], ZZ); W1 = V1.span([2*V1.0, 3*V1.1]) sage: M1 = V1/W1; M1 Finitely generated module V/W over Integer Ring with invariants (6) -We create the homomorphism from M0 to M1 that sends both generators of -M0 to 3 times the generator of M1. This is well defined since 3 times +We create the homomorphism from `M_0` to `M_1` that sends both generators of +`M_0` to 3 times the generator of `M_1`. This is well-defined since 3 times the generator has order 2. :: sage: f = M0.hom([3*M1.0, 3*M1.0]); f - Morphism from module over Integer Ring with invariants (4, 16) to module with invariants (6,) that sends the generators to [(3), (3)] + Morphism from module over Integer Ring with invariants (4, 16) + to module with invariants (6,) that sends the generators to [(3), (3)] -We evaluate the homomorphism on our element x of the domain, and on the -first generator of the domain. We also evaluate at an element of V0, -which is coerced into M0. :: +We evaluate the homomorphism on our element `x` of the domain, and on the +first generator of the domain. We also evaluate at an element of `V_0`, +which is coerced into `M_0`. :: sage: f(x) (0) @@ -125,8 +127,8 @@ sage: f(V0.1) (3) -Here we illustrate lifting an element of the image of f, i.e., finding -an element of M0 that maps to a given element of M1:: +Here we illustrate lifting an element of the image of `f`, i.e., finding +an element of `M_0` that maps to a given element of `M_1`:: sage: y = f.lift(3*M1.0) sage: y # random @@ -134,10 +136,10 @@ sage: f(y) (3) -We compute the kernel of f, i.e., the submodule of elements of M0 that +We compute the kernel of `f`, i.e., the submodule of elements of `M_0` that map to 0. Note that the kernel is not explicitly represented as a -submodule, but as another quotient V/W where V is contained in V0. -You can explicitly coerce elements of the kernel into M0 though. :: +submodule, but as another quotient `V/W` where `V` is contained in `V_0`. +You can explicitly coerce elements of the kernel into `M_0` though. :: sage: K = f.kernel(); K Finitely generated module V/W over Integer Ring with invariants (2, 16) @@ -151,13 +153,13 @@ sage: f(M0(K.1)) (0) -We compute the image of f. :: +We compute the image of `f`. :: sage: f.image() Finitely generated module V/W over Integer Ring with invariants (2) Notice how the elements of the image are written as (0) and (1), -despite the image being naturally a submodule of M1, which has +despite the image being naturally a submodule of `M_1`, which has elements (0), (1), (2), (3), (4), (5). However, below we coerce the element (1) of the image into the codomain, and get (3):: @@ -174,8 +176,8 @@ TESTS:: sage: from sage.modules.fg_pid.fgp_module import FGP_Module - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = FGP_Module(V, W); Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.linear_combination_of_smith_form_gens([1,3]) @@ -185,7 +187,7 @@ sage: Q(W([1,16,0])) (0, 0) sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],QQ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1]) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1]) sage: Q = FGP_Module(V, W); Q Finitely generated module V/W over Rational Field with invariants (0) sage: q = Q.an_element(); q @@ -209,6 +211,7 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from itertools import product from sage.modules.module import Module from sage.modules.free_module import is_FreeModule @@ -232,22 +235,23 @@ def FGP_Module(V, W, check=True): """ INPUT: - - ``V`` -- a free R-module + - ``V`` -- a free `R`-module - - ``W`` -- a free R-submodule of ``V`` + - ``W`` -- a free `R`-submodule of `V` - ``check`` -- bool (default: ``True``); if ``True``, more checks on correctness are performed; in particular, we check the data - types of ``V`` and ``W``, and that ``W`` is a submodule of ``V`` + types of ``V`` and ``W``, and that `W` is a submodule of `V` with the same base ring. OUTPUT: - - the quotient ``V / W`` as a finitely generated R-module + - the quotient `V/W` as a finitely generated `R`-module EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: import sage.modules.fg_pid.fgp_module sage: Q = sage.modules.fg_pid.fgp_module.FGP_Module(V, W) sage: type(Q) @@ -273,7 +277,8 @@ def is_FGP_Module(x): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]); Q = V/W + sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]); Q = V/W sage: sage.modules.fg_pid.fgp_module.is_FGP_Module(V) False sage: sage.modules.fg_pid.fgp_module.is_FGP_Module(Q) @@ -284,13 +289,13 @@ def is_FGP_Module(x): class FGP_Module_class(Module): """ - A finitely generated module over a PID presented as a quotient ``V / W``. + A finitely generated module over a PID presented as a quotient `V/W`. INPUT: - - ``V`` -- an R-module + - ``V`` -- an `R`-module - - ``W`` -- an R-submodule of V + - ``W`` -- an `R`-submodule of `V` - ``check`` -- bool (default: ``True``) @@ -305,8 +310,8 @@ class FGP_Module_class(Module): Echelon basis matrix: [100] - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: type(Q) @@ -332,18 +337,19 @@ def __init__(self, V, W, check=True): """ INPUT: - - ``V`` -- an R-module + - ``V`` -- an `R`-module - - ``W`` -- an R-submodule of V + - ``W`` -- an `R`-submodule of `V` - ``check`` -- bool (default: ``True``); if ``True``, more checks on - correctness are performed; in particular, we check - the data types of V and W, and that W is a - submodule of V with the same base ring. + correctness are performed; in particular, we check the data types of + ``V`` and ``W``, and that `W` is a submodule of `V` with the same + base ring `R`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: type(Q) @@ -370,25 +376,26 @@ def __init__(self, V, W, check=True): def _module_constructor(self, V, W, check=True): r""" - Construct a quotient module ``V/W``. + Construct a quotient module `V/W`. This should be overridden in derived classes. INPUT: - - ``V`` -- an R-module. + - ``V`` -- an `R`-module - - ``W`` -- an R-submodule of ``V``. + - ``W`` -- an `R`-submodule of `V` - - ``check`` -- bool (default: ``True``). + - ``check`` -- bool (default: ``True``) OUTPUT: - The quotient ``V/W``. + The quotient `V/W`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q._module_constructor(V,W) @@ -402,7 +409,7 @@ def _coerce_map_from_(self, S): INPUT: - - ``S`` -- anything. + - ``S`` -- anything OUTPUT: @@ -410,7 +417,8 @@ def _coerce_map_from_(self, S): EXAMPLES:: - sage: V = span([[5, -1/2]],ZZ); W = span([[20,-2]],ZZ); Q = V/W; phi=Q.hom([2*Q.0]) + sage: V = span([[5, -1/2]], ZZ); W = span([[20,-2]], ZZ) + sage: Q = V/W; phi = Q.hom([2*Q.0]) sage: Q._coerce_map_from_(ZZ) False sage: Q._coerce_map_from_(phi.kernel()) @@ -448,10 +456,9 @@ def _mul_(self, other, switch_sides=False): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = span([2*V.0,4*V.1,3*V.2]) - sage: Q = V/W - sage: Q + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = span([2*V.0, 4*V.1, 3*V.2]) + sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (2, 12) sage: 2*Q Finitely generated module V/W over Integer Ring with invariants (6) @@ -469,7 +476,8 @@ def _repr_(self): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: (V/W)._repr_() 'Finitely generated module V/W over Integer Ring with invariants (4, 12)' """ @@ -478,12 +486,13 @@ def _repr_(self): def __truediv__(self, other): """ - Return the quotient self/other, where other must be a - submodule of self. + Return the quotient ``self`` / ``other``, where ``other`` must be a + submodule of ``self``. EXAMPLES:: - sage: V = span([[5, -1/2]],ZZ); W = span([[20,-2]],ZZ); Q = V/W; phi=Q.hom([2*Q.0]) + sage: V = span([[5, -1/2]], ZZ); W = span([[20,-2]] ,ZZ) + sage: Q = V/W; phi = Q.hom([2*Q.0]) sage: Q Finitely generated module V/W over Integer Ring with invariants (4) sage: Q/phi.kernel() @@ -504,7 +513,8 @@ def __eq__(self, other): """ EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q == Q True @@ -521,13 +531,13 @@ def __eq__(self, other): def __ne__(self, other): """ - True iff self is not equal to other. + True iff ``self`` is not equal to ``other``. This may not be needed for modules created using the function :func:`FGP_Module`, since those have uniqueness built into them, but if the modules are created directly using the ``__init__`` method for this class, then this may fail; in - particular, for modules M and N with ``M == N`` returning + particular, for modules ``M`` and ``N`` with ``M == N`` returning True, it may be the case that ``M != N`` may also return True. In particular, for derived classes whose ``__init__`` methods just call the ``__init__`` method for this class need this. See @@ -619,12 +629,12 @@ def _element_constructor_(self, x, check=True): - ``x`` -- a vector or an fgp module element: - - vector: coerce vector into V and define the - corresponding element of V/W + - vector: coerce vector into `V` and define the + corresponding element of `V/W` - - fgp module element: lift to element of ambient vector - space and try to put into V. If x is in ``self`` already, - just return x. + - fgp module element: lift to element of ambient vector + space and try to put into `V`. If ``x`` is in ``self`` already, + just return ``x``. - `check` -- bool (default: ``True``) @@ -632,10 +642,10 @@ def _element_constructor_(self, x, check=True): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W - sage: x = Q(V.0-V.1); x # indirect doctest + sage: x = Q(V.0 - V.1); x # indirect doctest (0, 9) sage: type(x) <class 'sage.modules.fg_pid.fgp_module.FGP_Module_class_with_category.element_class'> @@ -651,11 +661,11 @@ def _element_constructor_(self, x, check=True): def linear_combination_of_smith_form_gens(self, x): r""" Compute a linear combination of the optimised generators of this module - as returned by :meth:`.smith_form_gens`. + as returned by :meth:`smith_form_gens`. EXAMPLES:: - sage: X = ZZ**2 / span([[3,0],[0,2]], ZZ) + sage: X = ZZ**2 / span([[3,0], [0,2]], ZZ) sage: X.linear_combination_of_smith_form_gens([1]) (1) @@ -668,11 +678,12 @@ def linear_combination_of_smith_form_gens(self, x): def __contains__(self, x): """ - Return true if x is contained in ``self``. + Return true if ``x`` is contained in ``self``. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.0 in Q @@ -696,7 +707,7 @@ def __contains__(self, x): def submodule(self, x): """ - Return the submodule defined by x. + Return the submodule defined by ``x``. INPUT: @@ -704,7 +715,8 @@ def submodule(self, x): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.gens() @@ -767,7 +779,8 @@ def has_canonical_map_to(self, A): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: A = Q.submodule((Q.0, Q.0 + 3*Q.1)); A @@ -791,7 +804,7 @@ def is_submodule(self, A): More precisely, this returns ``True`` if ``self.V()`` is a submodule of ``A.V()``, with ``self.W()`` equal to ``A.W()``. - Compare :meth:`.has_canonical_map_to`. + Compare :meth:`has_canonical_map_to`. EXAMPLES:: @@ -829,7 +842,8 @@ def V(self): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.V() Free module of degree 3 and rank 3 over Integer Ring @@ -843,13 +857,14 @@ def V(self): def cover(self): """ - If this module was constructed as V/W, return the cover module V. + If this module was constructed as `V/W`, return the cover module `V`. This is the same as ``self.V()``. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.V() Free module of degree 3 and rank 3 over Integer Ring @@ -862,11 +877,12 @@ def cover(self): def W(self): """ - If this module was constructed as a quotient V/W, return W. + If this module was constructed as a quotient `V/W`, return `W`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.W() Free module of degree 3 and rank 3 over Integer Ring @@ -879,15 +895,15 @@ def W(self): def relations(self): """ - If ``self`` was constructed as ``V / W``, return the - relations module ``W``. + If ``self`` was constructed as `V / W`, return the + relations module `W`. This is the same as ``self.W()``. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V / W sage: Q.relations() Free module of degree 3 and rank 3 over Integer Ring @@ -901,16 +917,17 @@ def relations(self): @cached_method def _relative_matrix(self): """ - V has a fixed choice of basis, and W has a fixed choice of - basis, and both V and W are free R-modules. Since W is - contained in V, we can write each basis element of W as an - R-linear combination of the basis for V. This function - returns that matrix over R, where each row corresponds to a - basis element of W. + `V` has a fixed choice of basis, and `W` has a fixed choice of + basis, and both `V` and `W` are free `R`-modules. Since `W` is + contained in `V`, we can write each basis element of `W` as an + `R`-linear combination of the basis for `V`. This function + returns that matrix over `R`, where each row corresponds to a + basis element of `W`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q._relative_matrix() [ 1 8 0] @@ -925,15 +942,16 @@ def _relative_matrix(self): @cached_method def _smith_form(self): """ - Return matrices S, U, and V such that S = U*R*V, and S is in - Smith normal form, and R is the relative matrix that defines + Return matrices `S`, `U`, and `V` such that `S = U*R*V`, and `S` is in + Smith normal form, and `R` is the relative matrix that defines self. - See :meth:`._relative_matrix`. + See :meth:`_relative_matrix`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q._smith_form() ( @@ -946,11 +964,12 @@ def _smith_form(self): def base_ring(self): """ - Return the base ring of self. + Return the base ring of ``self``. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.base_ring() Integer Ring @@ -959,12 +978,12 @@ def base_ring(self): @cached_method def invariants(self, include_ones=False): - """ - Return the diagonal entries of the smith form of the relative + r""" + Return the diagonal entries of the Smith form of the relative matrix that defines ``self`` (see :meth:`._relative_matrix`) - padded with zeros, excluding 1's by default. Thus if v is the + padded with zeros, excluding 1's by default. Thus if ``v`` is the list of integers returned, then self is abstractly isomorphic to - the product of cyclic groups `Z/nZ` where `n` is in `v`. + the product of cyclic groups `\ZZ/n\ZZ` where `n` is in ``v``. INPUT: @@ -973,14 +992,15 @@ def invariants(self, include_ones=False): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.invariants() (4, 12) An example with 1 and 0 rows:: - sage: V = ZZ^3; W = V.span([[1,2,0],[0,1,0], [0,2,0]]); Q = V/W; Q + sage: V = ZZ^3; W = V.span([[1,2,0], [0,1,0], [0,2,0]]); Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (0) sage: Q.invariants() (0,) @@ -999,9 +1019,9 @@ def invariants(self, include_ones=False): def gens(self): """ - Returns tuple of elements `g_0,...,g_n` of self such that the module generated by - the gi is isomorphic to the direct sum of R/ei*R, where ei are the - invariants of self and R is the base ring. + Return tuple of elements `g_0,...,g_n` of ``self`` such that the module generated by + the `g_i` is isomorphic to the direct sum of `R/e_i R`, where `e_i` are the + invariants of ``self`` and `R` is the base ring. Note that these are not generally uniquely determined, and depending on how Smith normal form is implemented for the base ring, they may not @@ -1011,7 +1031,8 @@ def gens(self): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.gens() ((1, 0), (0, 1)) @@ -1023,11 +1044,12 @@ def gens(self): @cached_method def smith_form_gens(self): """ - Return a set of generators for self which are in Smith normal form. + Return a set of generators for ``self`` which are in Smith normal form. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.smith_form_gens() ((1, 0), (0, 1)) @@ -1054,7 +1076,7 @@ def gens_to_smith(self): r""" Return the transformation matrix from the user to Smith form generators. - To go in the other direction use :meth:`smith_to_gens`. + To go in the other direction, use :meth:`smith_to_gens`. OUTPUT: @@ -1062,9 +1084,8 @@ def gens_to_smith(self): EXAMPLES:: - sage: L2 = IntegralLattice(3 * matrix([[-2,0,0],[0,1,0],[0,0,-4]])) - sage: D = L2.discriminant_group().normal_form() - sage: D + sage: L2 = IntegralLattice(3 * matrix([[-2,0,0], [0,1,0], [0,0,-4]])) + sage: D = L2.discriminant_group().normal_form(); D # needs sage.libs.pari sage.rings.padics Finite quadratic module over Integer Ring with invariants (3, 6, 12) Gram matrix of the quadratic form with values in Q/Z: [1/2 0 0 0 0] @@ -1072,14 +1093,13 @@ def gens_to_smith(self): [ 0 0 1/3 0 0] [ 0 0 0 1/3 0] [ 0 0 0 0 2/3] - sage: D.gens_to_smith() + sage: D.gens_to_smith() # needs sage.libs.pari sage.rings.padics [0 3 0] [0 0 3] [0 4 0] [1 2 0] [0 0 4] - sage: T = D.gens_to_smith()*D.smith_to_gens() - sage: T + sage: T = D.gens_to_smith() * D.smith_to_gens(); T # needs sage.libs.pari sage.rings.padics [ 3 0 3 0 0] [ 0 33 0 0 3] [ 4 0 4 0 0] @@ -1088,9 +1108,9 @@ def gens_to_smith(self): The matrix `T` now satisfies a certain congruence:: - sage: for i in range(T.nrows()): + sage: for i in range(T.nrows()): # needs sage.libs.pari sage.rings.padics ....: T[:,i] = T[:,i] % D.gens()[i].order() - sage: T + sage: T # needs sage.libs.pari sage.rings.padics [1 0 0 0 0] [0 1 0 0 0] [0 0 1 0 0] @@ -1107,7 +1127,7 @@ def smith_to_gens(self): r""" Return the transformation matrix from Smith form to user generators. - To go in the other direction use :meth:`gens_to_smith`. + To go in the other direction, use :meth:`gens_to_smith`. OUTPUT: @@ -1115,9 +1135,8 @@ def smith_to_gens(self): EXAMPLES:: - sage: L2 = IntegralLattice(3 * matrix([[-2,0,0],[0,1,0],[0,0,-4]])) - sage: D = L2.discriminant_group().normal_form() - sage: D + sage: L2 = IntegralLattice(3 * matrix([[-2,0,0], [0,1,0], [0,0,-4]])) + sage: D = L2.discriminant_group().normal_form(); D # needs sage.libs.pari sage.rings.padics Finite quadratic module over Integer Ring with invariants (3, 6, 12) Gram matrix of the quadratic form with values in Q/Z: [1/2 0 0 0 0] @@ -1125,35 +1144,33 @@ def smith_to_gens(self): [ 0 0 1/3 0 0] [ 0 0 0 1/3 0] [ 0 0 0 0 2/3] - sage: D.smith_to_gens() + sage: D.smith_to_gens() # needs sage.libs.pari sage.rings.padics [ 0 0 1 1 0] [ 1 0 1 0 0] [ 0 11 0 0 1] - sage: T = D.smith_to_gens()*D.gens_to_smith() - sage: T + sage: T = D.smith_to_gens() * D.gens_to_smith(); T # needs sage.libs.pari sage.rings.padics [ 1 6 0] [ 0 7 0] [ 0 0 37] This matrix satisfies the congruence:: - sage: for i in range(T.ncols()): + sage: for i in range(T.ncols()): # needs sage.libs.pari sage.rings.padics ....: T[:, i] = T[:, i] % D.smith_form_gens()[i].order() - sage: T + sage: T # needs sage.libs.pari sage.rings.padics [1 0 0] [0 1 0] [0 0 1] We create some element of our FGP module:: - sage: x = D.linear_combination_of_smith_form_gens((1,2,3)) - sage: x + sage: x = D.linear_combination_of_smith_form_gens((1,2,3)); x # needs sage.libs.pari sage.rings.padics (1, 2, 3) and want to know some (it is not unique) linear combination - of the user defined generators that is x:: + of the user defined generators that is ``x``:: - sage: x.vector() * D.smith_to_gens() + sage: x.vector() * D.smith_to_gens() # needs sage.libs.pari sage.rings.padics (2, 33, 3, 1, 3) """ if self.base_ring() != ZZ: @@ -1175,7 +1192,7 @@ def smith_to_gens(self): def gens_vector(self, x, reduce=False): r""" - Return coordinates of x with respect to the generators. + Return coordinates of ``x`` with respect to the generators. INPUT: @@ -1191,7 +1208,7 @@ def gens_vector(self, x, reduce=False): sage: from sage.modules.fg_pid.fgp_module import FGP_Module_class sage: W = ZZ^3 - sage: V = W.span(matrix.diagonal([1/6,1/3,1/12])) + sage: V = W.span(matrix.diagonal([1/6, 1/3, 1/12])) sage: class FGP_with_gens(FGP_Module_class): ....: def __init__(self, V, W, gens): ....: FGP_Module_class.__init__(self, V, W) @@ -1205,26 +1222,24 @@ def gens_vector(self, x, reduce=False): ((0, 3, 0), (0, 0, 3), (0, 4, 0), (1, 2, 0), (0, 0, 8)) - We create some element of D:: + We create some element of ``D``:: - sage: x = D.linear_combination_of_smith_form_gens((1,2,3)) - sage: x + sage: x = D.linear_combination_of_smith_form_gens((1,2,3)); x (1, 2, 3) In our generators:: - sage: v = D.gens_vector(x) - sage: v + sage: v = D.gens_vector(x); v # needs sage.libs.pari (2, 9, 3, 1, 33) The output can be further reduced:: - sage: D.gens_vector(x, reduce=True) + sage: D.gens_vector(x, reduce=True) # needs sage.libs.pari (0, 1, 0, 1, 0) Let us check:: - sage: x == sum(v[i]*D.gen(i) for i in range(len(D.gens()))) + sage: x == sum(v[i]*D.gen(i) for i in range(len(D.gens()))) # needs sage.libs.pari True """ x = self(x) @@ -1239,12 +1254,12 @@ def gens_vector(self, x, reduce=False): def coordinate_vector(self, x, reduce=False): """ - Return coordinates of x with respect to the optimized - representation of self. + Return coordinates of ``x`` with respect to the optimized + representation of ``self``. INPUT: - - ``x`` -- element of self + - ``x`` -- element of ``self`` - ``reduce`` -- (default: False); if ``True``, reduce coefficients modulo invariants; this is @@ -1257,7 +1272,8 @@ def coordinate_vector(self, x, reduce=False): EXAMPLES:: - sage: V = span([[1/4,0,0],[3/4,4,2],[0,0,2]],ZZ); W = V.span([4*V.0+12*V.1]) + sage: V = span([[1/4,0,0], [3/4,4,2], [0,0,2]], ZZ) + sage: W = V.span([4*V.0 + 12*V.1]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 0, 0) sage: Q.coordinate_vector(-Q.0) @@ -1274,7 +1290,8 @@ def coordinate_vector(self, x, reduce=False): TESTS:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.coordinate_vector(Q.0 - Q.1, reduce=True) @@ -1345,7 +1362,8 @@ def gen(self, i): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.gen(0) @@ -1368,7 +1386,7 @@ def gen(self, i): def smith_form_gen(self, i): """ - Return the i-th generator of ``self``. + Return the ``i``-th generator of ``self``. This is a separate method so we can freely override :meth:`gen` in derived classes. @@ -1379,8 +1397,8 @@ def smith_form_gen(self, i): EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ) - sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.smith_form_gen(0) @@ -1394,27 +1412,28 @@ def smith_form_gen(self, i): return v[i] def optimized(self): - """ - Return a module isomorphic to this one, but with V replaced by - a submodule of V such that the generators of ``self`` all lift - trivially to generators of V. Replace W by the intersection - of V and W. This has the advantage that V has small dimension + r""" + Return a module isomorphic to this one, but with `V` replaced by + a submodule of `V` such that the generators of ``self`` all lift + trivially to generators of `V`. Replace `W` by the intersection + of `V` and `W`. This has the advantage that `V` has small dimension and any homomorphism from ``self`` trivially extends to a - homomorphism from V. + homomorphism from `V`. OUTPUT: - - ``Q`` -- an optimized quotient V0/W0 with V0 a submodule of V - such that phi: V0/W0 --> V/W is an isomorphism + - ``Q`` -- an optimized quotient `V_0/W_0` with `V_0` a submodule of `V` + such that `\phi: V_0/W_0 \to V/W` is an isomorphism - - ``Z`` -- matrix such that if x is in ``self.V()`` and - c gives the coordinates of x in terms of the - basis for ``self.V()``, then c*Z is in V0 - and c*Z maps to x via phi above. + - ``Z`` -- matrix such that if `x` is in ``self.V()`` and + ``c`` gives the coordinates of `x` in terms of the + basis for ``self.V()``, then ``c*Z`` is in `V_0` + and ``c*Z`` maps to `x` via `\phi` above. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: O, X = Q.optimized(); O Finitely generated module V/W over Integer Ring with invariants (4, 12) @@ -1469,7 +1488,7 @@ def optimized(self): def hom(self, im_gens, codomain=None, check=True): """ Homomorphism defined by giving the images of ``self.gens()`` in some - fixed fg R-module. + fixed finitely generated `R`-module. .. NOTE:: @@ -1480,16 +1499,19 @@ def hom(self, im_gens, codomain=None, check=True): INPUT: - ``im_gens`` -- a list of the images of ``self.gens()`` in some - R-module + `R`-module EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: phi = Q.hom([3*Q.1, Q.0]) sage: phi - Morphism from module over Integer Ring with invariants (4, 12) to module with invariants (4, 12) that sends the generators to [(0, 3), (1, 0)] + Morphism from module over Integer Ring with invariants (4, 12) + to module with invariants (4, 12) + that sends the generators to [(0, 3), (1, 0)] sage: phi(Q.0) (0, 3) sage: phi(Q.1) @@ -1499,13 +1521,16 @@ def hom(self, im_gens, codomain=None, check=True): This example illustrates creating a morphism to a free module. The free module is turned into an FGP module (i.e., quotient - V/W with W=0), and the morphism is constructed:: + `V/W` with `W=0`), and the morphism is constructed:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (2, 0, 0) - sage: phi = Q.hom([0,V.0,V.1]); phi - Morphism from module over Integer Ring with invariants (2, 0, 0) to module with invariants (0, 0, 0) that sends the generators to [(0, 0, 0), (1, 0, 0), (0, 1, 0)] + sage: phi = Q.hom([0, V.0, V.1]); phi + Morphism from module over Integer Ring with invariants (2, 0, 0) + to module with invariants (0, 0, 0) + that sends the generators to [(0, 0, 0), (1, 0, 0), (0, 1, 0)] sage: phi.domain() Finitely generated module V/W over Integer Ring with invariants (2, 0, 0) sage: phi.codomain() @@ -1522,25 +1547,28 @@ def hom(self, im_gens, codomain=None, check=True): sage: A = (ZZ^2)/(ZZ^2); A Finitely generated module V/W over Integer Ring with invariants () sage: A.hom([]) - Morphism from module over Integer Ring with invariants () to module with invariants () that sends the generators to [] + Morphism from module over Integer Ring with invariants () + to module with invariants () + that sends the generators to [] sage: A.hom([]).codomain() is A True sage: B = (ZZ^3)/(ZZ^3) - sage: A.hom([],codomain=B) - Morphism from module over Integer Ring with invariants () to module with invariants () that sends the generators to [] - sage: phi = A.hom([],codomain=B); phi - Morphism from module over Integer Ring with invariants () to module with invariants () that sends the generators to [] + sage: phi = A.hom([], codomain=B); phi + Morphism from module over Integer Ring with invariants () + to module with invariants () + that sends the generators to [] sage: phi(A(0)) () sage: phi(A(0)) == B(0) True - A degenerate case:: sage: A = (ZZ^2)/(ZZ^2) sage: phi = A.hom([]); phi - Morphism from module over Integer Ring with invariants () to module with invariants () that sends the generators to [] + Morphism from module over Integer Ring with invariants () + to module with invariants () + that sends the generators to [] sage: phi(A(0)) () @@ -1548,17 +1576,16 @@ def hom(self, im_gens, codomain=None, check=True): below we try to send a generator of order 2 to an element of order 14:: - sage: V = span([[1/14,3/14],[0,1/2]],ZZ); W = ZZ^2 + sage: V = span([[1/14,3/14], [0,1/2]], ZZ); W = ZZ^2 sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (2, 14) sage: Q.linear_combination_of_smith_form_gens([1,11]).additive_order() 14 - sage: f = Q.hom([Q.linear_combination_of_smith_form_gens([1,11]), Q.linear_combination_of_smith_form_gens([1,3])]); f + sage: f = Q.hom([Q.linear_combination_of_smith_form_gens([1,11]), + ....: Q.linear_combination_of_smith_form_gens([1,3])]); f Traceback (most recent call last): ... ValueError: phi must send optimized submodule of M.W() into N.W() - - """ if len(im_gens) == 0: # 0 map @@ -1590,14 +1617,14 @@ def hom(self, im_gens, codomain=None, check=True): def _hom_general(self, im_gens, check=True): """ Homomorphism defined by giving the images of ``self.gens()`` in some - fixed fg R-module. We do not assume that the generators given by + fixed finitely generated `R`-module. We do not assume that the generators given by ``self.gens()`` are the same as the Smith form generators, since this may not be true for a general derived class. INPUT: - ``im_gens`` - a Sequence object giving the images of ``self.gens()``, - whose universe is some fixed fg R-module + whose universe is some fixed finitely generated `R`-module EXAMPLES:: @@ -1615,7 +1642,9 @@ def _hom_general(self, im_gens, check=True): ... ValueError: Images do not determine a valid homomorphism sage: A.hom([B.0, B.0], B) # indirect doctest - Morphism from module over Integer Ring with invariants (3,) to module with invariants (3,) that sends the generators to [(1), (1)] + Morphism from module over Integer Ring with invariants (3,) + to module with invariants (3,) + that sends the generators to [(1), (1)] """ m = self.ngens() @@ -1633,12 +1662,12 @@ def _hom_general(self, im_gens, check=True): def _hom_from_smith(self, im_smith_gens, check=True): """ Homomorphism defined by giving the images of the Smith-form generators - of self in some fixed fg R-module. + of ``self`` in some fixed finitely generated `R`-module. INPUT: - ``im_gens`` -- a Sequence object giving the images of the Smith-form - generators of self, whose universe is some fixed fg R-module + generators of ``self``, whose universe is some fixed finitely generated `R`-module EXAMPLES:: @@ -1652,7 +1681,9 @@ def _hom_from_smith(self, im_smith_gens, check=True): (1) sage: B = ZZ**1 / span([[3]], ZZ) sage: A._hom_from_smith(Sequence([B.0])) - Morphism from module over Integer Ring with invariants (3,) to module with invariants (3,) that sends the generators to [(1), (1)] + Morphism from module over Integer Ring with invariants (3,) + to module with invariants (3,) + that sends the generators to [(1), (1)] """ if len(im_smith_gens) != len(self.smith_form_gens()): raise ValueError("im_gens must have length the same as self.smith_form_gens()") @@ -1670,16 +1701,22 @@ def _Hom_(self, N, category=None): """ EXAMPLES:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([V.0+2*V.1, 9*V.0+2*V.1, 4*V.2]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ); W = V.span([V.0 + 2*V.1, 9*V.0 + 2*V.1, 4*V.2]) sage: Q = V/W sage: Q.Hom(Q) # indirect doctest - Set of Morphisms from Finitely generated module V/W over Integer Ring with invariants (4, 16) to Finitely generated module V/W over Integer Ring with invariants (4, 16) in Category of modules over Integer Ring + Set of Morphisms + from Finitely generated module V/W over Integer Ring with invariants (4, 16) + to Finitely generated module V/W over Integer Ring with invariants (4, 16) + in Category of modules over Integer Ring sage: M = V/V.zero_submodule() sage: H = M.Hom(Q); H - Set of Morphisms from Finitely generated module V/W over Integer Ring with invariants (0, 0, 0) to Finitely generated module V/W over Integer Ring with invariants (4, 16) in Category of modules over Integer Ring - sage: Hom(M,Q) is H + Set of Morphisms + from Finitely generated module V/W over Integer Ring with invariants (0, 0, 0) + to Finitely generated module V/W over Integer Ring with invariants (4, 16) + in Category of modules over Integer Ring + sage: Hom(M, Q) is H True - sage: type(Hom(M,Q)) + sage: type(Hom(M, Q)) <class 'sage.modules.fg_pid.fgp_morphism.FGP_Homset_class_with_category'> sage: H.category() Category of homsets of modules over Integer Ring @@ -1692,7 +1729,10 @@ def _Hom_(self, N, category=None): sage: V = ZZ^2 sage: W = V.quotient(V.span([[1, 1]])) sage: H = W.Hom(QQ); H - Set of Morphisms from Finitely generated module V/W over Integer Ring with invariants (0) to Rational Field in Category of commutative additive groups + Set of Morphisms + from Finitely generated module V/W over Integer Ring with invariants (0) + to Rational Field + in Category of commutative additive groups sage: type(H) <class 'sage.categories.homset.Homset_with_category'> @@ -1703,14 +1743,15 @@ def _Hom_(self, N, category=None): def random_element(self, *args, **kwds): """ - Create a random element of ``self`` = V/W, by creating a random element of V and - reducing it modulo W. + Create a random element of ``self`` = `V/W`, by creating a random element of `V` and + reducing it modulo `W`. - All arguments are passed onto the method :meth:`random_element` of V. + All arguments are passed on to the method :meth:`random_element` of `V`. EXAMPLES:: - sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([2*V.0 + 4*V.1, 9*V.0 + 12*V.1, 4*V.2]) sage: Q = V/W sage: Q.random_element().parent() is Q True @@ -1728,7 +1769,7 @@ def cardinality(self): EXAMPLES:: - sage: V = ZZ^2; W = V.span([[1,2],[3,4]]); A = V/W; A + sage: V = ZZ^2; W = V.span([[1,2], [3,4]]); A = V/W; A Finitely generated module V/W over Integer Ring with invariants (2) sage: A.cardinality() 2 @@ -1738,10 +1779,10 @@ def cardinality(self): +Infinity sage: V = QQ^2; W = V.span([[1,2]]); A = V/W; A Vector space quotient V/W of dimension 1 over Rational Field where - V: Vector space of dimension 2 over Rational Field - W: Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 2] + V: Vector space of dimension 2 over Rational Field + W: Vector space of degree 2 and dimension 1 over Rational Field + Basis matrix: + [1 2] sage: A.cardinality() +Infinity """ @@ -1773,12 +1814,13 @@ def __iter__(self): EXAMPLES:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([V.0+2*V.1, 4*V.0+2*V.1, 4*V.2]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ); W = V.span([V.0 + 2*V.1, 4*V.0 + 2*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (2, 12) sage: z = list(V/W) sage: z - [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (0, 10), (0, 11), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (1, 11)] + [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (0, 10), (0, 11), + (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (1, 11)] sage: len(z) 24 @@ -1794,8 +1836,7 @@ def __iter__(self): raise NotImplementedError("currently self must be finite to iterate over") B = self.optimized()[0].V().basis_matrix() V = self.base_ring()**B.nrows() - from sage.misc.mrange import cartesian_product_iterator - for a in cartesian_product_iterator([range(k) for k in v]): + for a in product(*[range(k) for k in v]): b = V(a) * B yield self(b) @@ -1811,9 +1852,9 @@ def construction(self): sage: T1 = A1 / B1 sage: T1.construction() (QuotientModuleFunctor, - Free module of degree 2 and rank 1 over Integer Ring - Echelon basis matrix: - [1 0]) + Free module of degree 2 and rank 1 over Integer Ring + Echelon basis matrix: + [1 0]) TESTS:: @@ -1826,6 +1867,8 @@ def construction(self): sage: T2 = A2 / B2 sage: t1 = T1.an_element() sage: t2 = T2.an_element() + + sage: # needs sage.libs.flint (o/w infinite recursion) sage: t1 + t2 (1, 1) """ @@ -1838,12 +1881,13 @@ def is_finite(self): EXAMPLES:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([V.0+2*V.1, 9*V.0+2*V.1, 4*V.2]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([V.0 + 2*V.1, 9*V.0 + 2*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 16) sage: Q.is_finite() True - sage: Q = V/V.zero_submodule(); Q + sage: Q = V / V.zero_submodule(); Q Finitely generated module V/W over Integer Ring with invariants (0, 0, 0) sage: Q.is_finite() False @@ -1858,20 +1902,21 @@ def annihilator(self): EXAMPLES:: - sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([V.0+2*V.1, 9*V.0+2*V.1, 4*V.2]) + sage: V = span([[1/2,0,0], [3/2,2,1], [0,0,1]], ZZ) + sage: W = V.span([V.0 + 2*V.1, 9*V.0 + 2*V.1, 4*V.2]) sage: Q = V/W; Q.annihilator() Principal ideal (16) of Integer Ring sage: Q.annihilator().gen() 16 - sage: Q = V/V.span([V.0]); Q + sage: Q = V / V.span([V.0]); Q Finitely generated module V/W over Integer Ring with invariants (0, 0) sage: Q.annihilator() Principal ideal (0) of Integer Ring We check that :trac:`22720` is resolved:: - sage: H=AdditiveAbelianGroup([]) + sage: H = AdditiveAbelianGroup([]) sage: H.annihilator() Principal ideal (1) of Integer Ring """ @@ -1887,7 +1932,7 @@ def ngens(self): r""" Return the number of generators of ``self``. - (Note for developers: This is just the length of :meth:`.gens`, rather + (Note for developers: This is just the length of :meth:`gens`, rather than of the minimal set of generators as returned by :meth:`.smith_form_gens`; these are the same in the :class:`~sage.modules.fg_pid.fgp_module.FGP_Module_class`, but not @@ -1895,7 +1940,7 @@ def ngens(self): EXAMPLES:: - sage: A = (ZZ**2) / span([[4,0],[0,3]], ZZ) + sage: A = (ZZ**2) / span([[4,0], [0,3]], ZZ) sage: A.ngens() 1 @@ -1913,7 +1958,7 @@ def __hash__(self): EXAMPLES:: - sage: A = (ZZ**2) / span([[4,0],[0,3]], ZZ) + sage: A = (ZZ**2) / span([[4,0], [0,3]], ZZ) sage: hash(A) == hash(((2, ZZ), ((4, 0), (0, 3)))) True """ @@ -1950,7 +1995,7 @@ def random_fgp_module(n, R=ZZ, finite=False): - ``R`` -- base ring (default: ``ZZ``) - - ``finite`` -- bool (default: ``True``); if True, make the random module finite. + - ``finite`` -- bool (default: ``True``); if True, make the random module finite EXAMPLES:: @@ -2025,8 +2070,10 @@ def _test_morphism_0(*args, **kwds): sage: set_random_seed(s); v = [fgp._test_morphism_0(1) for _ in range(30)] sage: set_random_seed(s); v = [fgp._test_morphism_0(2) for _ in range(30)] sage: set_random_seed(s); v = [fgp._test_morphism_0(3) for _ in range(10)] + + sage: # needs sage.libs.flint (o/w timeout) sage: set_random_seed(s); v = [fgp._test_morphism_0(i) for i in range(1,20)] - sage: set_random_seed(s); v = [fgp._test_morphism_0(4) for _ in range(50)] # long time + sage: set_random_seed(s); v = [fgp._test_morphism_0(4) for _ in range(50)] # long time """ phi = random_fgp_morphism_0(*args, **kwds) K = phi.kernel() diff --git a/src/sage/modules/fg_pid/fgp_morphism.py b/src/sage/modules/fg_pid/fgp_morphism.py index 71b43dcdc1a..d1c8b221994 100644 --- a/src/sage/modules/fg_pid/fgp_morphism.py +++ b/src/sage/modules/fg_pid/fgp_morphism.py @@ -127,7 +127,7 @@ def _repr_(self): sage: phi._repr_() 'Morphism from module over Integer Ring with invariants (4, 12) to module with invariants (4, 12) that sends the generators to [(1, 3), (0, 11)]' """ - return "Morphism from module over %s with invariants %s to module with invariants %s that sends the generators to %s"%( + return "Morphism from module over %s with invariants %s to module with invariants %s that sends the generators to %s" % ( self.domain().base_ring(), self.domain().invariants(), self.codomain().invariants(), list(self.im_gens())) @@ -453,6 +453,7 @@ def lift(self, x): assert self(y) == x, "bug in phi.lift()" return y + from sage.categories.homset import Homset import sage.misc.weak_dict diff --git a/src/sage/modules/filtered_vector_space.py b/src/sage/modules/filtered_vector_space.py index a4a32815197..f34c0abfe71 100644 --- a/src/sage/modules/filtered_vector_space.py +++ b/src/sage/modules/filtered_vector_space.py @@ -83,17 +83,17 @@ Any field can be used as the vector space base. For example a finite field:: - sage: F.<a> = GF(5^3) - sage: r1 = (a, 0, F(5)); r1 + sage: F.<a> = GF(5^3) # needs sage.rings.finite_rings + sage: r1 = (a, 0, F(5)); r1 # needs sage.rings.finite_rings (a, 0, 0) - sage: FilteredVectorSpace([r1, r2, r3], {0:[0,1], oo:[1]}, base_ring=F) + sage: FilteredVectorSpace([r1, r2, r3], {0:[0,1], oo:[1]}, base_ring=F) # needs sage.rings.finite_rings GF(125)^2 >= GF(125)^1 in GF(125)^3 Or the algebraic field:: - sage: r1 = (1, 0, 1+QQbar(I)); r1 + sage: r1 = (1, 0, 1+QQbar(I)); r1 # needs sage.rings.number_field (1, 0, I + 1) - sage: FilteredVectorSpace([r1, r2, r3], {0:[0,1], oo:[1]}, base_ring=QQbar) + sage: FilteredVectorSpace([r1, r2, r3], {0:[0,1], oo:[1]}, base_ring=QQbar) # needs sage.rings.number_field Vector space of dimension 2 over Algebraic Field >= Vector space of dimension 1 over Algebraic Field in Vector space of dimension 3 over Algebraic Field @@ -107,11 +107,11 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # *************************************************************************** +from itertools import product from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ from sage.rings.real_double import RDF -from sage.rings.real_mpfr import RR from sage.rings.integer import Integer from sage.rings.infinity import InfinityRing, infinity, minus_infinity from sage.categories.fields import Fields @@ -119,6 +119,11 @@ from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method +try: + from sage.rings.real_mpfr import RR +except ImportError: + RR = None + def is_FilteredVectorSpace(X): """ @@ -784,11 +789,11 @@ def _repr_field_name(self): sage: FilteredVectorSpace(2, base_ring=QQ)._repr_field_name() 'QQ' - sage: F.<a> = GF(9) - sage: FilteredVectorSpace(2, base_ring=F)._repr_field_name() + sage: F.<a> = GF(9) # needs sage.rings.finite_rings + sage: FilteredVectorSpace(2, base_ring=F)._repr_field_name() # needs sage.rings.finite_rings 'GF(9)' - sage: FilteredVectorSpace(2, base_ring=AA)._repr_field_name() + sage: FilteredVectorSpace(2, base_ring=AA)._repr_field_name() # needs sage.rings.number_field Traceback (most recent call last): ... NotImplementedError @@ -825,8 +830,8 @@ def _repr_vector_space(self, dim): sage: F3 = FilteredVectorSpace(3, base_ring=GF(3)) sage: F3._repr_vector_space(1234) 'GF(3)^1234' - sage: F3 = FilteredVectorSpace(3, base_ring=AA) - sage: F3._repr_vector_space(1234) + sage: F3 = FilteredVectorSpace(3, base_ring=AA) # needs sage.rings.number_field + sage: F3._repr_vector_space(1234) # needs sage.rings.number_field 'Vector space of dimension 1234 over Algebraic Real Field' """ if dim == 0: @@ -882,7 +887,7 @@ def _repr_(self): QQ^1 >= 0 in QQ^2 sage: FilteredVectorSpace({1:[(1,0), (-1,1)], 3:[(1,0)]}, base_ring=GF(3)) GF(3)^2 >= GF(3)^1 >= GF(3)^1 >= 0 - sage: FilteredVectorSpace({1:[(1,0), (-1,1)], 3:[(1,0)]}, base_ring=AA) + sage: FilteredVectorSpace({1:[(1,0), (-1,1)], 3:[(1,0)]}, base_ring=AA) # needs sage.rings.number_field Vector space of dimension 2 over Algebraic Real Field >= Vector space of dimension 1 over Algebraic Real Field >= Vector space of dimension 1 over Algebraic Real Field >= 0 @@ -918,18 +923,19 @@ def __eq__(self, other): TESTS:: + sage: # needs sage.geometry.polyhedron sage.schemes sage: P = toric_varieties.P2() sage: T_P = P.sheaves.tangent_bundle() sage: O_P = P.sheaves.trivial_bundle(1) sage: S1 = T_P + O_P sage: S2 = O_P + T_P - sage: S1._filt[0].is_isomorphic(S2._filt[0]) # known bug + sage: S1._filt[0].is_isomorphic(S2._filt[0]) # known bug True sage: FilteredVectorSpace(2, base_ring=QQ) == FilteredVectorSpace(2, base_ring=GF(5)) False """ - if type(self) != type(other): + if type(self) is not type(other): return False if self.base_ring() != other.base_ring(): return False @@ -1107,7 +1113,7 @@ def _power_operation(self, n, operation): QQ^2 >= QQ^1 >= 0 sage: F._power_operation(2, 'symmetric') QQ^3 >= QQ^2 >= QQ^1 >= 0 - sage: F._power_operation(2, 'antisymmetric') + sage: F._power_operation(2, 'antisymmetric') # needs sage.groups QQ^1 >= 0 """ from sage.modules.tensor_operations import VectorCollection, TensorOperation @@ -1117,11 +1123,10 @@ def _power_operation(self, n, operation): iters = [self.support()] * n filtration = {} - from sage.categories.cartesian_product import cartesian_product - for degrees in cartesian_product(iters): + for degrees in product(*iters): deg = sum(degrees) filt_deg = filtration.get(deg, set()) - for i in cartesian_product([indices.get(d) for d in degrees]): + for i in product(*[indices.get(d) for d in degrees]): pow_i = T.index_map(*i) if pow_i is not None: filt_deg.add(pow_i) @@ -1145,6 +1150,7 @@ def exterior_power(self, n): EXAMPLES:: + sage: # needs sage.groups sage: F = FilteredVectorSpace(1, 1) + FilteredVectorSpace(1, 2); F QQ^2 >= QQ^1 >= 0 sage: F.exterior_power(1) diff --git a/src/sage/modules/finite_submodule_iter.pyx b/src/sage/modules/finite_submodule_iter.pyx index eb433546f23..bb4a730cad9 100644 --- a/src/sage/modules/finite_submodule_iter.pyx +++ b/src/sage/modules/finite_submodule_iter.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Iterators over finite submodules of a `\ZZ`-module diff --git a/src/sage/modules/fp_graded/__init__.py b/src/sage/modules/fp_graded/__init__.py deleted file mode 100755 index e69de29bb2d..00000000000 diff --git a/src/sage/docs/__init__.py b/src/sage/modules/fp_graded/all.py old mode 100644 new mode 100755 similarity index 100% rename from src/sage/docs/__init__.py rename to src/sage/modules/fp_graded/all.py diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index e4f288f3264..5e348276c33 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Elements of finitely presented graded modules diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 3f87d6b9c6f..f8f2fac3f72 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Finitely generated free graded left modules over connected graded algebras diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index 08e30a17dba..6edb4bb7dd6 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Homsets of finitely presented graded modules diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 79353e754a9..cb715523ad7 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Finitely presented graded modules @@ -551,7 +552,7 @@ def connectivity(self): # We must check that the generator(s) in the free generator module are # not hit by relations, since we are not guaranteed that the # presentation we have is minimal. - X = sorted(x for x in self.generator_degrees()) + X = sorted(self.generator_degrees()) previous = None for k in X: diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index fde00303230..47f74fd49e5 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Homomorphisms of finitely presented graded modules diff --git a/src/sage/modules/fp_graded/steenrod/__init__.py b/src/sage/modules/fp_graded/steenrod/__init__.py deleted file mode 100755 index e69de29bb2d..00000000000 diff --git a/src/sage/dynamics/__init__.py b/src/sage/modules/fp_graded/steenrod/all.py old mode 100644 new mode 100755 similarity index 100% rename from src/sage/dynamics/__init__.py rename to src/sage/modules/fp_graded/steenrod/all.py diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 743fc2fbbcc..8f584a211ef 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -183,7 +183,6 @@ import sage.misc.latex as latex from sage.modules.module import Module -import sage.rings.finite_rings.finite_field_constructor as finite_field import sage.rings.ring as ring import sage.rings.abc import sage.rings.integer_ring @@ -195,6 +194,7 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.misc.lazy_attribute import lazy_attribute from sage.misc.randstate import current_randstate +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.structure.factory import UniqueFactory from sage.structure.sequence import Sequence from sage.structure.richcmp import (richcmp_method, rich_to_bool, richcmp, @@ -243,11 +243,11 @@ def create_object(self, version, key): sage: R.<x,y> = QQ[] sage: Q = R.quo(R.ideal([x^2 - y^2 - 1])) - sage: Q.is_integral_domain() + sage: Q.is_integral_domain() # needs sage.libs.singular True - sage: Q2 = FreeModule(Q, 2) + sage: Q2 = FreeModule(Q, 2) # needs sage.libs.singular sage: from sage.modules.free_module import FreeModule_ambient_domain - sage: isinstance(Q2, FreeModule_ambient_domain) + sage: isinstance(Q2, FreeModule_ambient_domain) # needs sage.libs.singular True """ base_ring, rank, sparse, inner_product_matrix = key @@ -291,6 +291,7 @@ def create_object(self, version, key): return FreeModule_ambient(base_ring, rank, sparse=sparse) + FreeModuleFactory_with_standard_basis = FreeModuleFactory("FreeModule") def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_matrix=None, *, @@ -385,7 +386,7 @@ def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_m Vector space of dimension 10 over Rational Field sage: FreeModule(ZZ,10) Ambient free module of rank 10 over the principal ideal domain Integer Ring - sage: FreeModule(FiniteField(5),10) + sage: FreeModule(FiniteField(5), 10) Vector space of dimension 10 over Finite Field of size 5 sage: FreeModule(Integers(7),10) Vector space of dimension 10 over Ring of integers modulo 7 @@ -613,8 +614,9 @@ def span(gens, base_ring=None, check=True, already_echelonized=False): [ 1 0 -3] [ 0 1 4] - sage: span([V.gen(0)], QuadraticField(-7,'a')) - Vector space of degree 3 and dimension 1 over Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I + sage: span([V.gen(0)], QuadraticField(-7,'a')) # needs sage.rings.number_field + Vector space of degree 3 and dimension 1 over Number Field in a + with defining polynomial x^2 + 7 with a = 2.645751311064591?*I Basis matrix: [ 1 0 -3] @@ -1013,8 +1015,8 @@ def some_elements(self): ... (46/103823, -46/103823, 103823/46)) - sage: F = FreeModule(SR, 2) - sage: tuple(F.some_elements()) + sage: F = FreeModule(SR, 2) # needs sage.symbolic + sage: tuple(F.some_elements()) # needs sage.symbolic ((1, 0), (some_variable, some_variable)) """ yield self.an_element() @@ -1187,19 +1189,21 @@ def __richcmp__(self, other, op): More exotic comparisons:: + sage: # needs sage.symbolic sage: R1 = ZZ[sqrt(2)] sage: F1 = R1^3 - sage: V1 = F1.span([[sqrt(2),sqrt(2),0]]) + sage: V1 = F1.span([[sqrt(2), sqrt(2), 0]]) sage: F2 = ZZ^3 sage: V2 = F2.span([[2,2,0]]) sage: V2 <= V1 # Different ambient vector spaces False sage: V1 <= V2 False - sage: R2 = GF(5)[x] + + sage: R2.<x> = GF(5)[] sage: F3 = R2^3 - sage: V3 = F3.span([[x^5-1,1+x+x^2+x^3+x^4,0]]) - sage: W3 = F3.span([[1,1,0],[0,4,0]]) + sage: V3 = F3.span([[x^5 - 1, 1 + x + x^2 + x^3 + x^4, 0]]) + sage: W3 = F3.span([[1,1,0], [0,4,0]]) sage: V3 <= W3 True sage: W3 <= V3 @@ -1568,11 +1572,11 @@ def span(self, gens, base_ring=None, check=True, already_echelonized=False): EXAMPLES:: sage: V = VectorSpace(GF(7), 3) - sage: W = V.subspace([[2,3,4]]); W + sage: W = V.subspace([[2, 3, 4]]); W Vector space of degree 3 and dimension 1 over Finite Field of size 7 Basis matrix: [1 5 2] - sage: W.span([[1,1,1]]) + sage: W.span([[1, 1, 1]]) Vector space of degree 3 and dimension 1 over Finite Field of size 7 Basis matrix: [1 1 1] @@ -1636,19 +1640,19 @@ def span(self, gens, base_ring=None, check=True, already_echelonized=False): TESTS:: - sage: V = FreeModule(RDF,3) + sage: V = FreeModule(RDF, 3) sage: W = V.submodule([V.gen(0)]) sage: W.span([V.gen(1)], base_ring=GF(7)) Vector space of degree 3 and dimension 1 over Finite Field of size 7 Basis matrix: [0 1 0] - sage: v = V((1, pi, log(2))); v + sage: v = V((1, pi, log(2))); v # needs sage.symbolic (1.0, 3.141592653589793, 0.6931471805599453) - sage: W.span([v], base_ring=GF(7)) + sage: W.span([v], base_ring=GF(7)) # needs sage.rings.finite_rings sage.symbolic Traceback (most recent call last): ... ValueError: argument gens (= [(1.0, 3.141592653589793, 0.6931471805599453)]) is not compatible with base_ring (= Finite Field of size 7) - sage: W = V.submodule([v]) + sage: W = V.submodule([v]) # needs sage.symbolic sage: W.span([V.gen(2)], base_ring=GF(7)) Vector space of degree 3 and dimension 1 over Finite Field of size 7 Basis matrix: @@ -1810,10 +1814,9 @@ def free_resolution(self, *args, **kwds): sage: S.<x,y,z> = PolynomialRing(QQ) sage: M = S**2 sage: N = M.submodule([vector([x - y, z]), vector([y * z, x * z])]) - sage: res = N.free_resolution() - sage: res + sage: res = N.free_resolution(); res # needs sage.libs.singular S^2 <-- S^2 <-- 0 - sage: ascii_art(res.chain_complex()) + sage: ascii_art(res.chain_complex()) # needs sage.libs.singular [x - y y*z] [ z x*z] 0 <-- C_0 <-------------- C_1 <-- 0 @@ -1830,7 +1833,6 @@ def free_resolution(self, *args, **kwds): raise NotImplementedError("the module must be a free module or " "have the base ring be a polynomial ring using Singular") - def graded_free_resolution(self, *args, **kwds): r""" Return a graded free resolution of ``self``. @@ -1843,13 +1845,13 @@ def graded_free_resolution(self, *args, **kwds): sage: S.<x,y,z> = PolynomialRing(QQ) sage: M = S**2 sage: N = M.submodule([vector([x - y, z]), vector([y * z, x * z])]) - sage: N.graded_free_resolution(shifts=[1, -1]) + sage: N.graded_free_resolution(shifts=[1, -1]) # needs sage.libs.singular S(-1)โŠ•S(1) <-- S(-2)โŠ•S(-3) <-- 0 - sage: N.graded_free_resolution(shifts=[2, 3]) + sage: N.graded_free_resolution(shifts=[2, 3]) # needs sage.libs.singular S(-2)โŠ•S(-3) <-- S(-3)โŠ•S(-4) <-- 0 sage: N = M.submodule([vector([x^3 - y^6, z^2]), vector([y * z, x])]) - sage: N.graded_free_resolution(degrees=[2, 1, 3], shifts=[2, 3]) + sage: N.graded_free_resolution(degrees=[2, 1, 3], shifts=[2, 3]) # needs sage.libs.singular S(-2)โŠ•S(-3) <-- S(-6)โŠ•S(-8) <-- 0 """ from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular @@ -1894,16 +1896,18 @@ class FreeModule_generic(Module_free_ambient): EXAMPLES:: sage: PolynomialRing(QQ,3,'x')^3 - Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring in x0, x1, x2 over Rational Field + Ambient free module of rank 3 over the integral domain + Multivariate Polynomial Ring in x0, x1, x2 over Rational Field - sage: FreeModule(GF(7),3).category() + sage: FreeModule(GF(7), 3).category() Category of enumerated finite dimensional vector spaces with basis over (finite enumerated fields and subquotients of monoids and quotients of semigroups) sage: V = QQ^4; V.category() Category of finite dimensional vector spaces with basis over (number fields and quotient fields and metric spaces) sage: V = GF(5)**20; V.category() - Category of enumerated finite dimensional vector spaces with basis over (finite enumerated fields and subquotients of monoids and quotients of semigroups) + Category of enumerated finite dimensional vector spaces with basis over + (finite enumerated fields and subquotients of monoids and quotients of semigroups) sage: FreeModule(ZZ,3).category() Category of finite dimensional modules with basis over (euclidean domains and infinite enumerated sets @@ -1959,7 +1963,7 @@ def __init__(self, base_ring, rank, degree, sparse=False, rank = sage.rings.integer.Integer(rank) if rank < 0: - raise ValueError("rank (=%s) must be nonnegative"%rank) + raise ValueError("rank (=%s) must be nonnegative" % rank) Module_free_ambient.__init__(self, base_ring, degree=degree, sparse=sparse, category=category) self.__coordinate_ring = coordinate_ring @@ -2356,14 +2360,16 @@ def __iter__(self): EXAMPLES:: - sage: V = VectorSpace(GF(4,'a'),2) - sage: [x for x in V] - [(0, 0), (a, 0), (a + 1, 0), (1, 0), (0, a), (a, a), (a + 1, a), (1, a), (0, a + 1), (a, a + 1), (a + 1, a + 1), (1, a + 1), (0, 1), (a, 1), (a + 1, 1), (1, 1)] + sage: V = VectorSpace(GF(4, 'a'), 2) # needs sage.rings.finite_rings + sage: [x for x in V] # needs sage.rings.finite_rings + [(0, 0), (a, 0), (a + 1, 0), (1, 0), (0, a), (a, a), (a + 1, a), (1, a), + (0, a + 1), (a, a + 1), (a + 1, a + 1), (1, a + 1), (0, 1), (a, 1), + (a + 1, 1), (1, 1)] :: - sage: W = V.subspace([V([1,1])]) - sage: [x for x in W] + sage: W = V.subspace([V([1, 1])]) # needs sage.rings.finite_rings + sage: [x for x in W] # needs sage.rings.finite_rings [(0, 0), (a, a), (a + 1, a + 1), (1, 1)] Free modules over enumerated infinite rings (i.e., those in the @@ -2380,7 +2386,7 @@ def __iter__(self): TESTS:: - sage: V = VectorSpace(GF(2,'a'),2) + sage: V = VectorSpace(GF(2, 'a'), 2) sage: V.list() [(0, 0), (1, 0), (0, 1), (1, 1)] @@ -2463,17 +2469,20 @@ def cardinality(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = FiniteField(9) - sage: V = VectorSpace(k,3) + sage: V = VectorSpace(k, 3) sage: V.cardinality() 729 - sage: W = V.span([[1,2,1],[0,1,1]]) + sage: W = V.span([[1,2,1], [0,1,1]]) sage: W.cardinality() 81 + sage: R = IntegerModRing(12) - sage: M = FreeModule(R,2) + sage: M = FreeModule(R, 2) sage: M.cardinality() 144 + sage: (QQ^3).cardinality() +Infinity @@ -2534,7 +2543,7 @@ def basis_matrix(self, ring=None): :: - sage: M = FreeModule(GF(7),3).span([[2,3,4],[1,1,1]]); M + sage: M = FreeModule(GF(7), 3).span([[2,3,4], [1,1,1]]); M Vector space of degree 3 and dimension 2 over Finite Field of size 7 Basis matrix: [1 0 6] @@ -2545,7 +2554,7 @@ def basis_matrix(self, ring=None): :: - sage: M = FreeModule(GF(7),3).span_of_basis([[2,3,4],[1,1,1]]) + sage: M = FreeModule(GF(7), 3).span_of_basis([[2,3,4], [1,1,1]]) sage: M.basis_matrix() [2 3 4] [1 1 1] @@ -2593,7 +2602,7 @@ def basis_matrix(self, ring=None): except AttributeError: MAT = sage.matrix.matrix_space.MatrixSpace(self.coordinate_ring(), len(self.basis()), self.degree(), - sparse = self.is_sparse()) + sparse=self.is_sparse()) if self.is_ambient(): A = MAT.identity_matrix() else: @@ -2771,6 +2780,7 @@ def coordinate_module(self, V): function to write a submodule in terms of integral cuspidal modular symbols:: + sage: # needs sage.modular sage: M = ModularSymbols(54) sage: S = M.cuspidal_subspace() sage: K = S.integral_structure(); K @@ -2868,8 +2878,9 @@ def base_field(self): Finite Field of size 3 sage: FreeModule(ZZ, 2).base_field() Rational Field - sage: FreeModule(PolynomialRing(GF(7),'x'), 2).base_field() - Fraction Field of Univariate Polynomial Ring in x over Finite Field of size 7 + sage: FreeModule(PolynomialRing(GF(7), 'x'), 2).base_field() + Fraction Field of Univariate Polynomial Ring in x + over Finite Field of size 7 """ return self.base_ring().fraction_field() @@ -3347,91 +3358,95 @@ def _magma_init_(self, magma): :: + sage: # optional - magma sage: A = matrix([[1,0],[0,-1]]) sage: M = FreeModule(ZZ,2,inner_product_matrix=A); M Ambient free quadratic module of rank 2 over the principal ideal domain Integer Ring Inner product matrix: [ 1 0] [ 0 -1] - sage: M._magma_init_(magma) # optional - magma + sage: M._magma_init_(magma) 'RSpace(_sage_[...],2,_sage_ref...)' - sage: m = magma(M); m # optional - magma + sage: m = magma(M); m Full RSpace of degree 2 over Integer Ring Inner Product Matrix: [ 1 0] [ 0 -1] - sage: m.Type() # optional - magma + sage: m.Type() ModTupRng - sage: m.sage() # optional - magma + sage: m.sage() Ambient free quadratic module of rank 2 over the principal ideal domain Integer Ring Inner product matrix: [ 1 0] [ 0 -1] - sage: m.sage() is M # optional - magma + sage: m.sage() is M True Now over a field:: + sage: # optional - magma sage: N = FreeModule(QQ,2,inner_product_matrix=A); N Ambient quadratic space of dimension 2 over Rational Field Inner product matrix: [ 1 0] [ 0 -1] - sage: n = magma(N); n # optional - magma + sage: n = magma(N); n Full Vector space of degree 2 over Rational Field Inner Product Matrix: [ 1 0] [ 0 -1] - sage: n.Type() # optional - magma + sage: n.Type() ModTupFld - sage: n.sage() # optional - magma + sage: n.sage() Ambient quadratic space of dimension 2 over Rational Field Inner product matrix: [ 1 0] [ 0 -1] - sage: n.sage() is N # optional - magma + sage: n.sage() is N True How about some inexact fields:: + sage: # optional - magma, needs sage.symbolic sage: v = vector(RR, [1, pi, 5/6]) sage: F = v.parent() - sage: M = magma(F); M # optional - magma + sage: M = magma(F); M Full Vector space of degree 3 over Real field of precision 15 - sage: M.Type() # optional - magma + sage: M.Type() ModTupFld - sage: m = M.sage(); m # optional - magma + sage: m = M.sage(); m Vector space of dimension 3 over Real Field with 53 bits of precision - sage: m is F # optional - magma + sage: m is F True For interval fields, we can convert to Magma but there is no interval field in Magma so we cannot convert back:: + sage: # optional - magma, needs sage.symbolic sage: v = vector(RealIntervalField(100), [1, pi, 0.125]) sage: F = v.parent() - sage: M = magma(v.parent()); M # optional - magma + sage: M = magma(v.parent()); M Full Vector space of degree 3 over Real field of precision 30 - sage: M.Type() # optional - magma + sage: M.Type() ModTupFld - sage: m = M.sage(); m # optional - magma + sage: m = M.sage(); m Vector space of dimension 3 over Real Field with 100 bits of precision - sage: m is F # optional - magma + sage: m is F False """ K = magma(self.base_ring()) if not self._inner_product_is_dot_product(): M = magma(self.inner_product_matrix()) - return "RSpace(%s,%s,%s)"%(K.name(), self.rank(), M._ref()) + return "RSpace(%s,%s,%s)" % (K.name(), self.rank(), M._ref()) else: - return "RSpace(%s,%s)"%(K.name(), self.rank()) + return "RSpace(%s,%s)" % (K.name(), self.rank()) def _macaulay2_(self, macaulay2=None): r""" EXAMPLES:: sage: R = QQ^2 - sage: macaulay2(R) # optional - macaulay2 + sage: macaulay2(R) # optional - macaulay2 2 QQ """ @@ -3532,7 +3547,8 @@ def _mul_(self, other, switch_sides=False): sage: W = V.subspace([[1, 0]]) sage: x = matrix(GF(2), [[1, 1], [0, 1]]) sage: W*x - Vector space of degree 2 and dimension 1 over Finite Field of size 2 + Vector space of degree 2 and dimension 1 + over Finite Field of size 2 Basis matrix: [1 1] @@ -3572,9 +3588,12 @@ def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None, EXAMPLES:: sage: FreeModule(ZZ, 2) - Ambient free module of rank 2 over the principal ideal domain Integer Ring - sage: FreeModule(PolynomialRing(GF(7),'x'), 2) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Finite Field of size 7 + Ambient free module of rank 2 + over the principal ideal domain Integer Ring + sage: FreeModule(PolynomialRing(GF(7), 'x'), 2) + Ambient free module of rank 2 + over the principal ideal domain Univariate Polynomial Ring in x + over Finite Field of size 7 """ FreeModule_generic.__init__(self, base_ring, rank, degree, sparse, coordinate_ring, category=category) @@ -3649,7 +3668,7 @@ def __add__(self, other): if not isinstance(other, FreeModule_generic): if other == 0: return self - raise TypeError("other (=%s) must be a free module"%other) + raise TypeError("other (=%s) must be a free module" % other) if not (self.ambient_vector_space() == other.ambient_vector_space()): raise TypeError("ambient vector spaces must be equal") return self.span(self.basis() + other.basis()) @@ -3666,9 +3685,12 @@ def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None, EXAMPLES:: sage: FreeModule(ZZ, 2) - Ambient free module of rank 2 over the principal ideal domain Integer Ring - sage: FreeModule(PolynomialRing(GF(7),'x'), 2) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Finite Field of size 7 + Ambient free module of rank 2 + over the principal ideal domain Integer Ring + sage: FreeModule(PolynomialRing(GF(7), 'x'), 2) + Ambient free module of rank 2 + over the principal ideal domain Univariate Polynomial Ring in x + over Finite Field of size 7 """ super().__init__(base_ring, rank, degree, sparse, coordinate_ring, category=category) @@ -3797,6 +3819,8 @@ def intersection(self, other): We intersect two modules over the ring of integers of a number field:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: L.<w> = NumberField(x^2 - x + 2) sage: OL = L.ring_of_integers() sage: V = L**3 @@ -4080,7 +4104,7 @@ def span_of_basis(self, basis, base_ring=None, check=True, already_echelonized=F try: return M.span_of_basis(basis) except TypeError: - raise ValueError("Argument gens (= %s) is not compatible "%basis + + raise ValueError("Argument gens (= %s) is not compatible " % basis + "with base_ring (= %s)." % base_ring) def submodule_with_basis(self, basis, check=True, already_echelonized=False): @@ -4194,10 +4218,11 @@ def vector_space_span(self, gens, check=True): :: sage: R.<x> = QQ[] - sage: K = NumberField(x^2 + 1, 'a'); a = K.gen() - sage: V = VectorSpace(K, 3) - sage: V.vector_space_span([2*V.gen(0) + 3*V.gen(2)]) - Vector space of degree 3 and dimension 1 over Number Field in a with defining polynomial x^2 + 1 + sage: K = NumberField(x^2 + 1, 'a'); a = K.gen() # needs sage.rings.number_field + sage: V = VectorSpace(K, 3) # needs sage.rings.number_field + sage: V.vector_space_span([2*V.gen(0) + 3*V.gen(2)]) # needs sage.rings.number_field + Vector space of degree 3 and dimension 1 + over Number Field in a with defining polynomial x^2 + 1 Basis matrix: [ 1 0 3/2] @@ -4304,7 +4329,7 @@ def __init__(self, base_field, dimension, degree, sparse=False, category=None): <repr(<sage.modules.free_module.FreeModule_generic_field_with_category at 0x...>) failed: NotImplementedError> """ if not isinstance(base_field, ring.Field): - raise TypeError("The base_field (=%s) must be a field"%base_field) + raise TypeError("The base_field (=%s) must be a field" % base_field) super().__init__(base_field, dimension, degree, sparse=sparse, category=category) def _Hom_(self, Y, category): @@ -4689,7 +4714,7 @@ def subspaces(self, dim): :: sage: V = VectorSpace(GF(3), 5) - sage: V = V.subspace([V([1,1,0,0,0]),V([0,0,1,1,0])]) + sage: V = V.subspace([V([1,1,0,0,0]), V([0,0,1,1,0])]) sage: list(V.subspaces(1)) [Vector space of degree 5 and dimension 1 over Finite Field of size 3 Basis matrix: @@ -4797,10 +4822,9 @@ def complement(self): we can get complements which are only isomorphic to a vector space decomposition complement. :: - sage: F2 = GF(2,x) + sage: F2 = GF(2, 'x') sage: V = F2^6 - sage: W = V.span([[1,1,0,0,0,0]]) - sage: W + sage: W = V.span([[1,1,0,0,0,0]]); W Vector space of degree 6 and dimension 1 over Finite Field of size 2 Basis matrix: [1 1 0 0 0 0] @@ -5226,8 +5250,8 @@ def quotient_abstract(self, sub, check=True, **kwds): EXAMPLES:: sage: V = GF(19)^3 - sage: W = V.span_of_basis([ [1,2,3], [1,0,1] ]) - sage: U,pi,lift = V.quotient_abstract(W) + sage: W = V.span_of_basis([[1,2,3], [1,0,1]]) + sage: U, pi, lift = V.quotient_abstract(W) sage: pi(V.2) (18) sage: pi(V.0) @@ -5297,6 +5321,7 @@ def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None, category We check that the creation of a submodule does not trigger the construction of a basis of the ambient space. See :trac:`15953`:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) sage: V = VectorSpace(F, 1) sage: v = V.random_element() @@ -5378,7 +5403,7 @@ def _dense_module(self): sage: M is S._dense_module() True """ - return FreeModule(base_ring=self.base_ring(), rank = self.rank(), sparse=False) + return FreeModule(base_ring=self.base_ring(), rank=self.rank(), sparse=False) def _sparse_module(self): """ @@ -5394,7 +5419,7 @@ def _sparse_module(self): sage: M._sparse_module() is S True """ - return FreeModule(base_ring=self.base_ring(), rank = self.rank(), sparse=True) + return FreeModule(base_ring=self.base_ring(), rank=self.rank(), sparse=True) def echelonized_basis_matrix(self): """ @@ -5572,9 +5597,9 @@ def _repr_(self): Ambient free module of rank 12 over Ring of integers modulo 12 """ if self.is_sparse(): - return "Ambient sparse free module of rank %s over %s"%(self.rank(), self.base_ring()) + return "Ambient sparse free module of rank %s over %s" % (self.rank(), self.base_ring()) else: - return "Ambient free module of rank %s over %s"%(self.rank(), self.base_ring()) + return "Ambient free module of rank %s over %s" % (self.rank(), self.base_ring()) def _latex_(self): r""" @@ -5582,19 +5607,19 @@ def _latex_(self): EXAMPLES:: - sage: latex(QQ^3) # indirect doctest + sage: latex(QQ^3) # indirect doctest \Bold{Q}^{3} :: sage: A = GF(5)^20 - sage: latex(A) # indirect doctest + sage: latex(A) # indirect doctest \Bold{F}_{5}^{20} :: - sage: A = PolynomialRing(QQ,3,'x') ^ 20 - sage: latex(A) #indirect doctest + sage: A = PolynomialRing(QQ, 3, 'x')^20 + sage: latex(A) # indirect doctest (\Bold{Q}[x_{0}, x_{1}, x_{2}])^{20} """ t = "%s" % latex.latex(self.base_ring()) @@ -5959,9 +5984,9 @@ def _sympy_(self): EXAMPLES:: - sage: sZZ3 = (ZZ^3)._sympy_(); sZZ3 + sage: sZZ3 = (ZZ^3)._sympy_(); sZZ3 # needs sympy ProductSet(Integers, Integers, Integers) - sage: (1, 2, 3) in sZZ3 + sage: (1, 2, 3) in sZZ3 # needs sympy True """ from sympy import ProductSet @@ -5982,7 +6007,7 @@ class FreeModule_ambient_domain(FreeModule_generic_domain, FreeModule_ambient): EXAMPLES:: - sage: FreeModule(PolynomialRing(GF(5),'x'), 3) + sage: FreeModule(PolynomialRing(GF(5), 'x'), 3) Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in x over Finite Field of size 5 """ @@ -6038,10 +6063,10 @@ def _repr_(self): Ambient free module of rank 7 over the integral domain Univariate Polynomial Ring in x over Integer Ring """ if self.is_sparse(): - return "Ambient sparse free module of rank %s over the integral domain %s"%( + return "Ambient sparse free module of rank %s over the integral domain %s" % ( self.rank(), self.base_ring()) else: - return "Ambient free module of rank %s over the integral domain %s"%( + return "Ambient free module of rank %s over the integral domain %s" % ( self.rank(), self.base_ring()) def ambient_vector_space(self): @@ -6230,10 +6255,10 @@ def _repr_(self): Ambient free module of rank 7 over the principal ideal domain Integer Ring """ if self.is_sparse(): - return "Ambient sparse free module of rank %s over the principal ideal domain %s"%( + return "Ambient sparse free module of rank %s over the principal ideal domain %s" % ( self.rank(), self.base_ring()) else: - return "Ambient free module of rank %s over the principal ideal domain %s"%( + return "Ambient free module of rank %s over the principal ideal domain %s" % ( self.rank(), self.base_ring()) @@ -6307,9 +6332,9 @@ def _repr_(self): Vector space of dimension 7 over Rational Field """ if self.is_sparse(): - return "Sparse vector space of dimension %s over %s"%(self.dimension(), self.base_ring()) + return "Sparse vector space of dimension %s over %s" % (self.dimension(), self.base_ring()) else: - return "Vector space of dimension %s over %s"%(self.dimension(), self.base_ring()) + return "Vector space of dimension %s over %s" % (self.dimension(), self.base_ring()) def ambient_vector_space(self): """ @@ -6341,14 +6366,14 @@ def _element_constructor_(self, e, *args, **kwds): EXAMPLES:: - sage: k.<a> = GF(3^4) - sage: VS = k.vector_space(map=False) - sage: VS(a) + sage: k.<a> = GF(3^4) # needs sage.rings.finite_rings + sage: VS = k.vector_space(map=False) # needs sage.rings.finite_rings + sage: VS(a) # needs sage.rings.finite_rings (0, 1, 0, 0) """ try: k = e.parent() - if finite_field.is_FiniteField(k) and k.base_ring() == self.base_ring() and k.degree() == self.degree(): + if isinstance(k, FiniteField) and k.base_ring() == self.base_ring() and k.degree() == self.degree(): return self(e._vector_()) except AttributeError: pass @@ -6454,8 +6479,8 @@ def __init__(self, ambient, basis, check=True, :trac:`10250` is solved as well:: sage: V = (QQ^2).span_of_basis([[1,1]]) - sage: w = sqrt(2) * V([1,1]) - sage: 3 * w + sage: w = sqrt(2) * V([1,1]) # needs sage.symbolic + sage: 3 * w # needs sage.symbolic (3*sqrt(2), 3*sqrt(2)) TESTS: @@ -6675,15 +6700,15 @@ def _echelonized_basis(self, ambient, basis): sage: W = V.submodule_with_basis([[1,1,0],[0,2,1]]) sage: W._echelonized_basis(V,W.basis()) [(1, 0, -1/2), (0, 1, 1/2)] - sage: V = SR^3 + sage: V = SR^3 # needs sage.symbolic sage: W = V.submodule_with_basis([[1,0,1]]) - sage: W._echelonized_basis(V,W.basis()) + sage: W._echelonized_basis(V, W.basis()) [(1, 0, 1)] """ # Return the first rank rows (i.e., the nonzero rows). d = self._denominator(basis) MAT = sage.matrix.matrix_space.MatrixSpace( - ambient.base_ring(), len(basis), ambient.degree(), sparse = ambient.is_sparse()) + ambient.base_ring(), len(basis), ambient.degree(), sparse=ambient.is_sparse()) if d != 1: basis = [x*d for x in basis] A = MAT(basis) @@ -6758,11 +6783,11 @@ def _repr_(self): [-1 0 0 0 0 0 0 1] """ if self.is_sparse(): - s = "Sparse free module of degree %s and rank %s over %s\n"%( + s = "Sparse free module of degree %s and rank %s over %s\n" % ( self.degree(), self.rank(), self.base_ring()) + \ "User basis matrix:\n%r" % self.basis_matrix() else: - s = "Free module of degree %s and rank %s over %s\n"%( + s = "Free module of degree %s and rank %s over %s\n" % ( self.degree(), self.rank(), self.base_ring()) + \ "User basis matrix:\n%r" % self.basis_matrix() return s @@ -6778,7 +6803,7 @@ def _latex_(self): sage: M._latex_() '\\mathrm{RowSpan}_{\\Bold{Z}}\\left(\\begin{array}{rrr}\n1 & 2 & 3 \\\\\n4 & 5 & 6\n\\end{array}\\right)' """ - return "\\mathrm{RowSpan}_{%s}%s"%(latex.latex(self.base_ring()), latex.latex(self.basis_matrix())) + return "\\mathrm{RowSpan}_{%s}%s" % (latex.latex(self.base_ring()), latex.latex(self.basis_matrix())) def ambient_module(self): """ @@ -7051,7 +7076,7 @@ def user_to_echelon_matrix(self): rows = sum([self.echelon_coordinates(b,check=False) for b in self.basis()], []) M = sage.matrix.matrix_space.MatrixSpace(self.base_ring().fraction_field(), self.dimension(), - sparse = self.is_sparse()) + sparse=self.is_sparse()) self.__user_to_echelon_matrix = M(rows) return self.__user_to_echelon_matrix @@ -7580,13 +7605,13 @@ def _repr_(self): [ 0 0 0 0 0 0 1 -1] """ if self.is_sparse(): - s = "Sparse free module of degree %s and rank %s over %s\n"%( + s = "Sparse free module of degree %s and rank %s over %s\n" % ( self.degree(), self.rank(), self.base_ring()) + \ - "Echelon basis matrix:\n%s"%self.basis_matrix() + "Echelon basis matrix:\n%s" % self.basis_matrix() else: - s = "Free module of degree %s and rank %s over %s\n"%( + s = "Free module of degree %s and rank %s over %s\n" % ( self.degree(), self.rank(), self.base_ring()) + \ - "Echelon basis matrix:\n%s"%self.basis_matrix() + "Echelon basis matrix:\n%s" % self.basis_matrix() return s def coordinate_vector(self, v, check=True): @@ -7641,6 +7666,7 @@ def has_user_basis(self): """ return False + FreeModule_generic_pid._submodule_class = FreeModule_submodule_pid @@ -7783,11 +7809,11 @@ def _repr_(self): [ 0 0 0 1 -1] """ if self.is_sparse(): - return "Sparse vector space of degree %s and dimension %s over %s\n"%( + return "Sparse vector space of degree %s and dimension %s over %s\n" % ( self.degree(), self.dimension(), self.base_field()) + \ "User basis matrix:\n%r" % self.basis_matrix() else: - return "Vector space of degree %s and dimension %s over %s\n"%( + return "Vector space of degree %s and dimension %s over %s\n" % ( self.degree(), self.dimension(), self.base_field()) + \ "User basis matrix:\n%r" % self.basis_matrix() @@ -7982,11 +8008,11 @@ def _repr_(self): [ 0 0 0 1 -1] """ if self.is_sparse(): - return "Sparse vector space of degree %s and dimension %s over %s\n"%( + return "Sparse vector space of degree %s and dimension %s over %s\n" % ( self.degree(), self.dimension(), self.base_field()) + \ "Basis matrix:\n%r" % self.basis_matrix() else: - return "Vector space of degree %s and dimension %s over %s\n"%( + return "Vector space of degree %s and dimension %s over %s\n" % ( self.degree(), self.dimension(), self.base_field()) + \ "Basis matrix:\n%r" % self.basis_matrix() @@ -8033,7 +8059,7 @@ def echelon_coordinates(self, v, check=True): if not isinstance(v, free_module_element.FreeModuleElement): v = self.ambient_vector_space()(v) if v.degree() != self.degree(): - raise ArithmeticError("v (=%s) is not in self"%v) + raise ArithmeticError("v (=%s) is not in self" % v) E = self.echelonized_basis_matrix() P = E.pivots() if not P: @@ -8118,6 +8144,7 @@ def has_user_basis(self): """ return False + FreeModule_generic_field._submodule_class = FreeModule_submodule_field @@ -8142,7 +8169,7 @@ def element_class(R, is_sparse): <class 'sage.modules.vector_integer_dense.Vector_integer_dense'> sage: sage.modules.free_module.element_class(FF, is_sparse=True) <class 'sage.modules.free_module_element.FreeModuleElement_generic_sparse'> - sage: sage.modules.free_module.element_class(FF, is_sparse=False) + sage: sage.modules.free_module.element_class(FF, is_sparse=False) # needs sage.rings.finite_rings <class 'sage.modules.vector_mod2_dense.Vector_mod2_dense'> sage: sage.modules.free_module.element_class(GF(7), is_sparse=False) <class 'sage.modules.vector_modn_dense.Vector_modn_dense'> @@ -8159,14 +8186,21 @@ def element_class(R, is_sparse): from .vector_rational_dense import Vector_rational_dense return Vector_rational_dense elif isinstance(R, sage.rings.abc.IntegerModRing) and not is_sparse: - from .vector_mod2_dense import Vector_mod2_dense if R.order() == 2: - return Vector_mod2_dense - from .vector_modn_dense import Vector_modn_dense, MAX_MODULUS - if R.order() < MAX_MODULUS: - return Vector_modn_dense + try: + from .vector_mod2_dense import Vector_mod2_dense + except ImportError: + pass + else: + return Vector_mod2_dense + try: + from .vector_modn_dense import Vector_modn_dense, MAX_MODULUS + except ImportError: + pass else: - return free_module_element.FreeModuleElement_generic_dense + if R.order() < MAX_MODULUS: + return Vector_modn_dense + return free_module_element.FreeModuleElement_generic_dense elif isinstance(R, sage.rings.abc.RealDoubleField) and not is_sparse: try: from sage.modules.vector_real_double_dense import Vector_real_double_dense @@ -8184,9 +8218,13 @@ def element_class(R, is_sparse): elif isinstance(R, sage.rings.abc.CallableSymbolicExpressionRing) and not is_sparse: import sage.modules.vector_callable_symbolic_dense return sage.modules.vector_callable_symbolic_dense.Vector_callable_symbolic_dense - elif isinstance(R, sage.rings.abc.SymbolicRing) and not is_sparse: - import sage.modules.vector_symbolic_dense - return sage.modules.vector_symbolic_dense.Vector_symbolic_dense + elif isinstance(R, sage.rings.abc.SymbolicRing): + if not is_sparse: + import sage.modules.vector_symbolic_dense + return sage.modules.vector_symbolic_dense.Vector_symbolic_dense + else: + import sage.modules.vector_symbolic_sparse + return sage.modules.vector_symbolic_sparse.Vector_symbolic_sparse if is_sparse: return free_module_element.FreeModuleElement_generic_sparse diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index 6c1c5083682..c9af9bcbdf7 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -63,7 +63,9 @@ Since there is no canonical coercion map to the finite field from sage: V.0 + M.0 Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for +: 'Vector space of dimension 5 over Rational Field' and 'Vector space of dimension 5 over Finite Field of size 7' + TypeError: unsupported operand parent(s) for +: + 'Vector space of dimension 5 over Rational Field' and + 'Vector space of dimension 5 over Finite Field of size 7' However, there is a map from `\ZZ` to the finite field, so the following is defined, and the result is in the finite @@ -93,7 +95,7 @@ TESTS:: sage: u = 7 sage: R = Integers(D) sage: p = matrix(R,[[84, 97, 55, 58, 51]]) - sage: 2*p.row(0) + sage: 2*p.row(0) # needs sage.libs.pari (168, 194, 110, 116, 102) This is a test from :trac:`20211`:: @@ -114,7 +116,7 @@ cimport cython from cpython.slice cimport PySlice_GetIndicesEx from sage.structure.sequence import Sequence -from sage.structure.element cimport Element, ModuleElement, RingElement, Vector +from sage.structure.element cimport Element, RingElement, Vector from sage.structure.element import canonical_coercion from sage.structure.richcmp cimport richcmp_not_equal, richcmp, rich_to_bool @@ -124,7 +126,6 @@ from sage.rings.infinity import Infinity, AnInfinity from sage.rings.integer_ring import ZZ from sage.rings.abc import RealDoubleField, ComplexDoubleField -from sage.rings.ring cimport Ring from sage.rings.integer cimport Integer, smallInteger from sage.arith.numerical_approx cimport digits_to_bits @@ -346,6 +347,7 @@ def vector(arg0, arg1=None, arg2=None, sparse=None, immutable=False): must be contiguous, so column-wise slices of numpy matrices will raise an exception. :: + sage: # needs numpy sage: import numpy sage: x = numpy.random.randn(10) sage: y = vector(x) @@ -364,6 +366,7 @@ def vector(arg0, arg1=None, arg2=None, sparse=None, immutable=False): Multi-dimensional arrays are not supported:: + sage: # needs numpy sage: import numpy as np sage: a = np.array([[1, 2, 3], [4, 5, 6]], np.float64) sage: vector(a) @@ -383,27 +386,29 @@ def vector(arg0, arg1=None, arg2=None, sparse=None, immutable=False): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) sage: v[3].parent() Integer Ring - sage: v = vector([float(23.4), int(2), complex(2+7*I), 1]); v + sage: v = vector([float(23.4), int(2), complex(2+7*I), 1]); v # needs sage.symbolic (23.4, 2.0, 2.0 + 7.0*I, 1.0) - sage: v[1].parent() + sage: v[1].parent() # needs sage.symbolic Complex Double Field If the argument is a vector, it doesn't change the base ring. This fixes :trac:`6643`:: + sage: # needs sage.rings.number_field sage: K.<sqrt3> = QuadraticField(3) - sage: u = vector(K, (1/2, sqrt3/2) ) + sage: u = vector(K, (1/2, sqrt3/2)) sage: vector(u).base_ring() Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878? - sage: v = vector(K, (0, 1) ) + sage: v = vector(K, (0, 1)) sage: vector(v).base_ring() Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878? Constructing a vector from a numpy array behaves as expected:: + sage: # needs numpy sage: import numpy - sage: a=numpy.array([1,2,3]) - sage: v=vector(a); v + sage: a = numpy.array([1,2,3]) + sage: v = vector(a); v (1, 2, 3) sage: parent(v) Ambient free module of rank 3 over the principal ideal domain Integer Ring @@ -451,8 +456,10 @@ def vector(arg0, arg1=None, arg2=None, sparse=None, immutable=False): sage: v = vector(QQ, w, immutable=True) sage: v.is_immutable() True + + sage: # needs numpy sage: import numpy as np - sage: w = np.array([1, 2, pi], float) + sage: w = np.array([1, 2, pi], float) # needs sage.symbolic sage: v = vector(w, immutable=True) sage: v.is_immutable() True @@ -465,9 +472,9 @@ def vector(arg0, arg1=None, arg2=None, sparse=None, immutable=False): We check that :trac:`31470` is fixed:: - sage: k.<a> = GF(5^3) - sage: S.<x> = k['x', k.frobenius_endomorphism()] - sage: vector(S, 3) + sage: k.<a> = GF(5^3) # needs sage.rings.finite_rings + sage: S.<x> = k['x', k.frobenius_endomorphism()] # needs sage.rings.finite_rings + sage: vector(S, 3) # needs sage.rings.finite_rings ... (0, 0, 0) """ @@ -625,25 +632,27 @@ def prepare(v, R, degree=None): EXAMPLES:: sage: from sage.modules.free_module_element import prepare - sage: prepare([1,2/3,5],None) + sage: prepare([1, 2/3, 5], None) ([1, 2/3, 5], Rational Field) - sage: prepare([1,2/3,5],RR) - ([1.00000000000000, 0.666666666666667, 5.00000000000000], Real Field with 53 bits of precision) + sage: prepare([1, 2/3, 5], RR) + ([1.00000000000000, 0.666666666666667, 5.00000000000000], + Real Field with 53 bits of precision) - sage: prepare({1:4, 3:-2}, ZZ, 6) + sage: prepare({1: 4, 3: -2}, ZZ, 6) ([0, 4, 0, -2, 0, 0], Integer Ring) - sage: prepare({3:1, 5:3}, QQ, 6) + sage: prepare({3: 1, 5: 3}, QQ, 6) ([0, 0, 0, 1, 0, 3], Rational Field) - sage: prepare([1,2/3,'10',5],RR) - ([1.00000000000000, 0.666666666666667, 10.0000000000000, 5.00000000000000], Real Field with 53 bits of precision) + sage: prepare([1, 2/3, '10', 5], RR) + ([1.00000000000000, 0.666666666666667, 10.0000000000000, 5.00000000000000], + Real Field with 53 bits of precision) - sage: prepare({},QQ, 0) + sage: prepare({}, QQ, 0) ([], Rational Field) - sage: prepare([1,2/3,'10',5],None) + sage: prepare([1, 2/3, '10', 5], None) Traceback (most recent call last): ... TypeError: unable to find a common ring for all elements @@ -651,8 +660,8 @@ def prepare(v, R, degree=None): Some objects can be converted to sequences even if they are not always thought of as sequences. :: - sage: c = CDF(2+3*I) - sage: prepare(c, None) + sage: c = CDF(2 + 3*I) # needs sage.symbolic + sage: prepare(c, None) # needs sage.symbolic ([2.0, 3.0], Real Double Field) This checks a bug listed at :trac:`10595`. Without good evidence @@ -745,7 +754,7 @@ def zero_vector(arg0, arg1=None): Garbage instead of a ring will be recognized as such. :: - sage: zero_vector(x^2, 5) + sage: zero_vector(x^2, 5) # needs sage.symbolic Traceback (most recent call last): ... TypeError: first argument must be a ring @@ -876,9 +885,13 @@ def random_vector(ring, degree=None, *args, **kwds): sage: w1 = vector(ZZ.random_element(distribution="1/n") for _ in range(20)) sage: w2 = vector(ZZ.random_element(x=-1000, y=1000) for _ in range(15)) sage: w3 = vector(QQ.random_element() for _ in range(10)) + sage: [v1, v2, v3] == [w1, w2, w3] + True sage: w4 = vector(FiniteField(17).random_element() for _ in range(10)) + sage: v4 == w4 + True sage: w5 = vector(RR.random_element() for _ in range(10)) - sage: [v1, v2, v3, v4, v5] == [w1, w2, w3, w4, w5] + sage: v5 == w5 True Inputs get checked before constructing the vector. :: @@ -939,20 +952,20 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: sage: v = vector(ZZ, 4, range(4)) - sage: giac(v)+v + sage: giac(v) + v # needs sage.libs.giac [0,2,4,6] :: sage: v = vector(QQ, 3, [2/3, 0, 5/4]) - sage: giac(v) + sage: giac(v) # needs sage.libs.giac [2/3,0,5/4] :: sage: P.<x> = ZZ[] sage: v = vector(P, 3, [x^2 + 2, 2*x + 1, -2*x^2 + 4*x]) - sage: giac(v) + sage: giac(v) # needs sage.libs.giac [sageVARx^2+2,2*sageVARx+1,-2*sageVARx^2+4*sageVARx] """ return self.list() @@ -968,15 +981,15 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: sage: v = vector(range(4)) - sage: v.__pari__() + sage: v.__pari__() # needs sage.libs.pari [0, 1, 2, 3] - sage: v.__pari__().type() + sage: v.__pari__().type() # needs sage.libs.pari 't_VEC' A list of vectors:: sage: L = [vector(i^n for i in range(4)) for n in [1,3,5]] - sage: pari(L) + sage: pari(L) # needs sage.libs.pari [[0, 1, 2, 3], [0, 1, 8, 27], [0, 1, 32, 243]] """ from sage.libs.pari.all import pari @@ -994,11 +1007,12 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: sage: v = vector(range(4)) - sage: v._pari_init_() + sage: v._pari_init_() # needs sage.libs.pari '[0,1,2,3]' Create the multiplication table of `GF(4)` using GP:: + sage: # needs sage.libs.pari sage: k.<a> = GF(4, impl="pari_ffelt") sage: v = gp(vector(list(k))) sage: v @@ -1064,22 +1078,24 @@ cdef class FreeModuleElement(Vector): # abstract base class INPUT: - ``dtype`` -- the `numpy dtype <http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html>`_ - of the returned array + of the returned array EXAMPLES:: + sage: # needs numpy sage: v = vector([1,2,3]) sage: v.numpy() array([1, 2, 3], dtype=object) sage: v.numpy() * v.numpy() array([1, 4, 9], dtype=object) - sage: vector(QQ, [1, 2, 5/6]).numpy() + sage: vector(QQ, [1, 2, 5/6]).numpy() # needs numpy array([1, 2, 5/6], dtype=object) - By default the ``object`` `dtype <http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html>`_ is used. + By default, the ``object`` `dtype <http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html>`_ is used. Alternatively, the desired dtype can be passed in as a parameter:: + sage: # needs numpy sage: v = vector(QQ, [1, 2, 5/6]) sage: v.numpy() array([1, 2, 5/6], dtype=object) @@ -1094,26 +1110,29 @@ cdef class FreeModuleElement(Vector): # abstract base class Passing a dtype of None will let numpy choose a native type, which can be more efficient but may have unintended consequences:: + sage: # needs numpy sage: v.numpy(dtype=None) array([1. , 2. , 0.83333333]) sage: w = vector(ZZ, [0, 1, 2^63 -1]); w (0, 1, 9223372036854775807) - sage: wn = w.numpy(dtype=None); wn + sage: wn = w.numpy(dtype=None); wn # needs numpy array([ 0, 1, 9223372036854775807]...) - sage: wn.dtype + sage: wn.dtype # needs numpy dtype('int64') sage: w.dot_product(w) 85070591730234615847396907784232501250 - sage: wn.dot(wn) # overflow + sage: wn.dot(wn) # overflow # needs numpy 2 Numpy can give rather obscure errors; we wrap these to give a bit of context:: - sage: vector([1, 1/2, QQ['x'].0]).numpy(dtype=float) + sage: vector([1, 1/2, QQ['x'].0]).numpy(dtype=float) # needs numpy Traceback (most recent call last): ... - ValueError: Could not convert vector over Univariate Polynomial Ring in x over Rational Field to numpy array of type <... 'float'>: setting an array element with a sequence. + ValueError: Could not convert vector over Univariate Polynomial Ring in x + over Rational Field to numpy array of type <... 'float'>: + setting an array element with a sequence. """ from numpy import array try: @@ -1128,6 +1147,7 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: + sage: # needs sage.symbolic sage: v = vector([1,2/3,pi]) sage: v.__hash__() Traceback (most recent call last): @@ -1156,7 +1176,7 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: vector(vector((1, 6.8))) (1.00000000000000, 6.80000000000000) - sage: vector(vector(SR, (1, sqrt(2)) ) ) + sage: vector(vector(SR, (1, sqrt(2)) ) ) # needs sage.symbolic (1, sqrt(2)) """ if R is None: @@ -1169,7 +1189,7 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: sage_input(vector(RR, [pi, e, 0.5]), verify=True) + sage: sage_input(vector(RR, [pi, e, 0.5]), verify=True) # needs sage.symbolic # Verified vector(RR, [3.1415926535897931, 2.7182818284590451, 0.5]) sage: sage_input(vector(GF(5), [1, 2, 3, 4, 5]), verify=True) @@ -1187,7 +1207,7 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: from sage.misc.sage_input import SageInputBuilder sage: vector(ZZ, [42, 389])._sage_input_(SageInputBuilder(), False) {call: {atomic:vector}({atomic:ZZ}, {list: ({atomic:42}, {atomic:389})})} - sage: vector(RDF, {1:pi, 1000:e})._sage_input_(SageInputBuilder(), False) + sage: vector(RDF, {1:pi, 1000:e})._sage_input_(SageInputBuilder(), False) # needs sage.symbolic {call: {atomic:vector}({atomic:RDF}, {dict: {{atomic:1}:{atomic:3.1415926535897931}, {atomic:1000}:{atomic:2.718281828459045...}}})} """ # Not a lot of room for prettiness here. @@ -1376,7 +1396,7 @@ cdef class FreeModuleElement(Vector): # abstract base class then taking a transpose. Notice that supplying a vector to the matrix constructor demonstrates Sage's preference for rows. :: - sage: x = vector(RDF, [sin(i*pi/20) for i in range(10)]) + sage: x = vector(RDF, [sin(i*pi/20) for i in range(10)]) # needs sage.symbolic sage: x.row() == matrix(x) True sage: x.row() == x.column().transpose() @@ -1385,10 +1405,10 @@ cdef class FreeModuleElement(Vector): # abstract base class Sparse or dense implementations are preserved. :: sage: d = vector(RR, [1.0, 2.0, 3.0]) - sage: s = vector(CDF, {2:5.0+6.0*I}) + sage: s = vector(CDF, {2: 5.0+6.0*I}) # needs sage.symbolic sage: dm = d.row() - sage: sm = s.row() - sage: all([d.is_dense(), dm.is_dense(), s.is_sparse(), sm.is_sparse()]) + sage: sm = s.row() # needs sage.symbolic + sage: all([d.is_dense(), dm.is_dense(), s.is_sparse(), sm.is_sparse()]) # needs sage.symbolic True TESTS: @@ -1448,7 +1468,7 @@ cdef class FreeModuleElement(Vector): # abstract base class then taking a transpose. Notice that supplying a vector to the matrix constructor demonstrates Sage's preference for rows. :: - sage: x = vector(RDF, [sin(i*pi/20) for i in range(10)]) + sage: x = vector(RDF, [sin(i*pi/20) for i in range(10)]) # needs sage.libs.pari sage.symbolic sage: x.column() == matrix(x).transpose() True sage: x.column() == x.row().transpose() @@ -1457,10 +1477,10 @@ cdef class FreeModuleElement(Vector): # abstract base class Sparse or dense implementations are preserved. :: sage: d = vector(RR, [1.0, 2.0, 3.0]) - sage: s = vector(CDF, {2:5.0+6.0*I}) + sage: s = vector(CDF, {2: 5.0+6.0*I}) # needs sage.symbolic sage: dm = d.column() - sage: sm = s.column() - sage: all([d.is_dense(), dm.is_dense(), s.is_sparse(), sm.is_sparse()]) + sage: sm = s.column() # needs sage.symbolic + sage: all([d.is_dense(), dm.is_dense(), s.is_sparse(), sm.is_sparse()]) # needs sage.symbolic True TESTS: @@ -1518,6 +1538,7 @@ cdef class FreeModuleElement(Vector): # abstract base class """ EXAMPLES:: + sage: # needs sage.symbolic sage: var('a,b,d,e') (a, b, d, e) sage: v = vector([a, b, d, e]) @@ -1542,7 +1563,7 @@ cdef class FreeModuleElement(Vector): # abstract base class Check for :trac:`29630`:: sage: v = vector(QQ, 4, {0:1}, sparse=True) - sage: v.change_ring(AA).is_sparse() + sage: v.change_ring(AA).is_sparse() # needs sage.rings.number_field True """ if self.base_ring() is R: @@ -1611,17 +1632,17 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: v = vector([1,2/3,pi]) - sage: v.items() - <generator object at ...> - sage: list(v.items()) + sage: v = vector([1,2/3,pi]) # needs sage.symbolic + sage: v.items() # needs sage.symbolic + <...generator object at ...> + sage: list(v.items()) # needs sage.symbolic [(0, 1), (1, 2/3), (2, pi)] TESTS: Using iteritems as an alias:: - sage: list(v.iteritems()) + sage: list(v.iteritems()) # needs sage.symbolic [(0, 1), (1, 2/3), (2, pi)] """ cdef dict d = self.dict(copy=False) @@ -1636,7 +1657,7 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: v = vector([1..5]); abs(v) + sage: v = vector([1..5]); abs(v) # needs sage.symbolic sqrt(55) sage: v = vector(RDF, [1..5]); abs(v) 7.416198487095663 @@ -1649,12 +1670,12 @@ cdef class FreeModuleElement(Vector): # abstract base class INPUT: - - ``p`` - default: 2 - ``p`` can be a real number greater than 1, + - ``p`` - default: 2 -- ``p`` can be a real number greater than 1, infinity (``oo`` or ``Infinity``), or a symbolic expression. - - `p=1`: the taxicab (Manhattan) norm - - `p=2`: the usual Euclidean norm (the default) - - `p=\infty`: the maximum entry (in absolute value) + - `p=1`: the taxicab (Manhattan) norm + - `p=2`: the usual Euclidean norm (the default) + - `p=\infty`: the maximum entry (in absolute value) .. NOTE:: @@ -1663,14 +1684,14 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: sage: v = vector([1,2,-3]) - sage: v.norm(5) + sage: v.norm(5) # needs sage.symbolic 276^(1/5) The default is the usual Euclidean norm. :: - sage: v.norm() + sage: v.norm() # needs sage.symbolic sqrt(14) - sage: v.norm(2) + sage: v.norm(2) # needs sage.symbolic sqrt(14) The infinity norm is the maximum size (in absolute value) @@ -1686,9 +1707,11 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: v=vector(RDF,[1,2,3]) sage: v.norm(5) 3.077384885394063 - sage: v.norm(pi/2) #abs tol 1e-15 + + sage: # needs sage.symbolic + sage: v.norm(pi/2) # abs tol 1e-15 4.216595864704748 - sage: _=var('a b c d p'); v=vector([a, b, c, d]) + sage: _ = var('a b c d p'); v = vector([a, b, c, d]) sage: v.norm(p) (abs(a)^p + abs(b)^p + abs(c)^p + abs(d)^p)^(1/p) @@ -1702,6 +1725,7 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: nrm.parent() Rational Field + sage: # needs sage.symbolic sage: v = vector(QQ, [3, 5]) sage: nrm = v.norm(); nrm sqrt(34) @@ -1726,7 +1750,7 @@ cdef class FreeModuleElement(Vector): # abstract base class Norm works with Python integers (see :trac:`13502`). :: sage: v = vector(QQ, [1,2]) - sage: v.norm(int(2)) + sage: v.norm(int(2)) # needs sage.symbolic sqrt(5) """ abs_self = [abs(x) for x in self] @@ -1742,6 +1766,7 @@ cdef class FreeModuleElement(Vector): # abstract base class """ EXAMPLES:: + sage: # needs sage.symbolic sage: v = vector(SR, [0,0,0,0]) sage: v == 0 True @@ -1767,6 +1792,7 @@ cdef class FreeModuleElement(Vector): # abstract base class Verify that :trac:`33697` is fixed:: + sage: # needs sage.symbolic sage: v = vector(SR, [x]) sage: w = vector(SR, [1]) sage: v == w @@ -1831,7 +1857,7 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: vector(SR, [1/2,2/5,0]).get(0) + sage: vector(SR, [1/2,2/5,0]).get(0) # needs sage.symbolic 1/2 """ return self.get_unsafe(i) @@ -1894,9 +1920,9 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: v = vector(SR, [1/2,2/5,0]); v + sage: v = vector(SR, [1/2,2/5,0]); v # needs sage.symbolic (1/2, 2/5, 0) - sage: v.set(2, pi); v + sage: v.set(2, pi); v # needs sage.symbolic (1/2, 2/5, pi) """ assert value.parent() is self.coordinate_ring() @@ -1909,7 +1935,7 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: vector([1,2/3,pi]).__invert__() + sage: vector([1,2/3,pi]).__invert__() # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError @@ -1991,8 +2017,8 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: v = vector([1,2/3,pi]) - sage: v.list_from_positions([0,0,0,2,1]) + sage: v = vector([1, 2/3, pi]) # needs sage.symbolic + sage: v.list_from_positions([0,0,0,2,1]) # needs sage.symbolic [1, 1, 1, pi, 2/3] """ cdef Py_ssize_t i @@ -2106,10 +2132,10 @@ cdef class FreeModuleElement(Vector): # abstract base class :: - sage: x = var('x') - sage: v = vector([x/(2*x)+sqrt(2)+var('theta')^3,x/(2*x)]); v + sage: x = var('x') # needs sage.symbolic + sage: v = vector([x/(2*x)+sqrt(2)+var('theta')^3,x/(2*x)]); v # needs sage.symbolic (theta^3 + sqrt(2) + 1/2, 1/2) - sage: v._repr_() + sage: v._repr_() # needs sage.symbolic '(theta^3 + sqrt(2) + 1/2, 1/2)' """ cdef Py_ssize_t d = self._degree @@ -2117,9 +2143,9 @@ cdef class FreeModuleElement(Vector): # abstract base class return "()" # compute column widths S = [repr(x) for x in self.list(copy=False)] - #width = max([len(x) for x in S]) + # width = max([len(x) for x in S]) s = "(" - for i in xrange(d): + for i in range(d): if i == d-1: sep = "" else: @@ -2283,13 +2309,14 @@ cdef class FreeModuleElement(Vector): # abstract base class The following both plot the given vector:: sage: v = vector(RDF, (1,2)) - sage: A = plot(v) - sage: B = v.plot() - sage: A+B # should just show one vector + sage: A = plot(v) # needs sage.plot + sage: B = v.plot() # needs sage.plot + sage: A + B # should just show one vector # needs sage.plot Graphics object consisting of 2 graphics primitives Examples of the plot types:: + sage: # needs sage.plot sage: A = plot(v, plot_type='arrow') sage: B = plot(v, plot_type='point', color='green', size=20) sage: C = plot(v, plot_type='step') # calls v.plot_step() @@ -2299,68 +2326,69 @@ cdef class FreeModuleElement(Vector): # abstract base class You can use the optional arguments for :meth:`plot_step`:: sage: eps = 0.1 - sage: plot(v, plot_type='step', eps=eps, xmax=5, hue=0) + sage: plot(v, plot_type='step', eps=eps, xmax=5, hue=0) # needs sage.plot Graphics object consisting of 1 graphics primitive Three-dimensional examples:: sage: v = vector(RDF, (1,2,1)) - sage: plot(v) # defaults to an arrow plot + sage: plot(v) # defaults to an arrow plot # needs sage.plot Graphics3d Object :: - sage: plot(v, plot_type='arrow') + sage: plot(v, plot_type='arrow') # needs sage.plot Graphics3d Object :: - sage: from sage.plot.plot3d.shapes2 import frame3d - sage: plot(v, plot_type='point')+frame3d((0,0,0), v.list()) + sage: from sage.plot.plot3d.shapes2 import frame3d # needs sage.plot + sage: plot(v, plot_type='point')+frame3d((0,0,0), v.list()) # needs sage.plot Graphics3d Object :: - sage: plot(v, plot_type='step') # calls v.plot_step() + sage: plot(v, plot_type='step') # calls v.plot_step() # needs sage.plot Graphics object consisting of 1 graphics primitive :: - sage: plot(v, plot_type='step', eps=eps, xmax=5, hue=0) + sage: plot(v, plot_type='step', eps=eps, xmax=5, hue=0) # needs sage.plot Graphics object consisting of 1 graphics primitive With greater than three coordinates, it defaults to a step plot:: sage: v = vector(RDF, (1,2,3,4)) - sage: plot(v) + sage: plot(v) # needs sage.plot Graphics object consisting of 1 graphics primitive One dimensional vectors are plotted along the horizontal axis of the coordinate plane:: - sage: plot(vector([1])) + sage: plot(vector([1])) # needs sage.plot Graphics object consisting of 1 graphics primitive An optional start argument may also be specified by a tuple, list, or vector:: sage: u = vector([1,2]); v = vector([2,5]) - sage: plot(u, start=v) + sage: plot(u, start=v) # needs sage.plot Graphics object consisting of 1 graphics primitive TESTS:: sage: u = vector([1,1]); v = vector([2,2,2]); z=(3,3,3) - sage: plot(u) #test when start=None + sage: plot(u) #test when start=None # needs sage.plot Graphics object consisting of 1 graphics primitive :: + sage: # needs sage.plot sage: plot(u, start=v) #test when coordinate dimension mismatch exists Traceback (most recent call last): ... ValueError: vector coordinates are not of the same dimension - sage: P = plot(v, start=z) #test when start coordinates are passed as a tuple - sage: P = plot(v, start=list(z)) #test when start coordinates are passed as a list + sage: P = plot(v, start=z) # test when start coordinates are passed as a tuple + sage: P = plot(v, start=list(z)) # test when start coordinates are passed as a list """ # Give sensible defaults based on the vector length if plot_type is None: @@ -2431,9 +2459,9 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: eps=0.1 + sage: eps = 0.1 sage: v = vector(RDF, [sin(n*eps) for n in range(100)]) - sage: v.plot_step(eps=eps, xmax=5, hue=0) + sage: v.plot_step(eps=eps, xmax=5, hue=0) # needs sage.plot Graphics object consisting of 1 graphics primitive """ import math @@ -2559,7 +2587,7 @@ cdef class FreeModuleElement(Vector): # abstract base class The dot product of a vector with itself is the 2-norm, squared. :: sage: v = vector(QQ, [3, 4, 7]) - sage: v.dot_product(v) - v.norm()^2 + sage: v.dot_product(v) - v.norm()^2 # needs sage.symbolic 0 TESTS: @@ -2596,7 +2624,11 @@ cdef class FreeModuleElement(Vector): # abstract base class Check for :trac:`33814`:: - sage: for R in [ZZ, QQ, RDF, RR, GF(2), GF(3), GF(4), ZZ['x']]: + sage: rings = [ZZ, QQ, RDF, ZZ['x']] + sage: rings += [RR] # needs sage.rings.real_mpfr + sage: rings += [GF(2), GF(3)] + sage: rings += [GF(4)] # needs sage.rings.finite_rings + sage: for R in rings: ....: _ = (R**0)().dot_product((R**0)()) """ cdef FreeModuleElement r = <FreeModuleElement?>right @@ -2755,6 +2787,7 @@ cdef class FreeModuleElement(Vector): # abstract base class TESTS:: + sage: # needs sage.rings.finite_rings sage: F = GF(previous_prime(2^32)) sage: v = random_vector(F, 3) sage: w = random_vector(F, 3) @@ -2829,7 +2862,7 @@ cdef class FreeModuleElement(Vector): # abstract base class :: - sage: W = VectorSpace(GF(3),3) + sage: W = VectorSpace(GF(3), 3) sage: w = W([0,1,2]) sage: w.pairwise_product(v) (0, 2, 0) @@ -2846,8 +2879,6 @@ cdef class FreeModuleElement(Vector): # abstract base class TESTS:: - sage: x, y = var('x, y') - :: sage: parent(vector(ZZ,[1,2]).pairwise_product(vector(ZZ,[1,2]))) @@ -2869,42 +2900,56 @@ cdef class FreeModuleElement(Vector): # abstract base class :: sage: parent(vector(QQ,[1,2,3,4]).pairwise_product(vector(ZZ['x']['y'],[1,2,3,4]))) - Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + Ambient free module of rank 4 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field sage: parent(vector(ZZ['x']['y'],[1,2,3,4]).pairwise_product(vector(QQ,[1,2,3,4]))) - Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + Ambient free module of rank 4 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field :: sage: parent(vector(QQ['x'],[1,2,3,4]).pairwise_product(vector(ZZ['x']['y'],[1,2,3,4]))) - Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + Ambient free module of rank 4 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field sage: parent(vector(ZZ['x']['y'],[1,2,3,4]).pairwise_product(vector(QQ['x'],[1,2,3,4]))) - Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + Ambient free module of rank 4 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field :: sage: parent(vector(QQ['y'],[1,2,3,4]).pairwise_product(vector(ZZ['x']['y'],[1,2,3,4]))) - Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + Ambient free module of rank 4 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field sage: parent(vector(ZZ['x']['y'],[1,2,3,4]).pairwise_product(vector(QQ['y'],[1,2,3,4]))) - Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + Ambient free module of rank 4 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field :: sage: parent(vector(ZZ['x'],[1,2,3,4]).pairwise_product(vector(ZZ['y'],[1,2,3,4]))) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Integer Ring' + TypeError: no common canonical parent for objects with parents: + 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and + 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Integer Ring' sage: parent(vector(ZZ['x'],[1,2,3,4]).pairwise_product(vector(QQ['y'],[1,2,3,4]))) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' + TypeError: no common canonical parent for objects with parents: + 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and + 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' sage: parent(vector(QQ['x'],[1,2,3,4]).pairwise_product(vector(ZZ['y'],[1,2,3,4]))) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Integer Ring' + TypeError: no common canonical parent for objects with parents: + 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and + 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Integer Ring' sage: parent(vector(QQ['x'],[1,2,3,4]).pairwise_product(vector(QQ['y'],[1,2,3,4]))) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' + TypeError: no common canonical parent for objects with parents: + 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and + 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' sage: v = vector({1: 1, 3: 2}) # test sparse vectors sage: w = vector({0: 6, 3: -4}) sage: v.pairwise_product(w) @@ -2927,12 +2972,12 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: R.<x,y,z> = QQ[] sage: vector([x, y, 3])._variables() [x, y, z] - sage: vector(SR, [x, y, 3])._variables() + sage: vector(SR, [x, y, 3])._variables() # needs sage.symbolic Traceback (most recent call last): ... ValueError: Unable to determine ordered variable names for Symbolic Ring - sage: v(x, y, z) = (-y, x, 0) - sage: v._variables() + sage: v(x, y, z) = (-y, x, 0) # needs sage.symbolic + sage: v._variables() # needs sage.symbolic [(x, y, z) |--> x, (x, y, z) |--> y, (x, y, z) |--> z] """ R = self._parent.base_ring() @@ -2965,11 +3010,11 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: vector([x*y, y*z, z*x]).div([x, y, w]) y + z - sage: vector(SR, [x*y, y*z, z*x]).div() + sage: vector(SR, [x*y, y*z, z*x]).div() # needs sage.symbolic Traceback (most recent call last): ... ValueError: Unable to determine ordered variable names for Symbolic Ring - sage: vector(SR, [x*y, y*z, z*x]).div([x, y, z]) + sage: vector(SR, [x*y, y*z, z*x]).div([x, y, z]) # needs sage.symbolic x + y + z .. SEEALSO:: @@ -3006,21 +3051,21 @@ cdef class FreeModuleElement(Vector): # abstract base class For rings where the variable order is not well defined, it must be defined explicitly:: - sage: v = vector(SR, [-y, x, 0]) - sage: v.curl() + sage: v = vector(SR, [-y, x, 0]) # needs sage.symbolic + sage: v.curl() # needs sage.symbolic Traceback (most recent call last): ... ValueError: Unable to determine ordered variable names for Symbolic Ring - sage: v.curl([x, y, z]) + sage: v.curl([x, y, z]) # needs sage.symbolic (0, 0, 2) Note that callable vectors have well defined variable orderings:: - sage: v(x, y, z) = (-y, x, 0) - sage: v.curl() + sage: v(x, y, z) = (-y, x, 0) # needs sage.symbolic + sage: v.curl() # needs sage.symbolic (x, y, z) |--> (0, 0, 2) - In two-dimensions, this returns a scalar value:: + In two dimensions, this returns a scalar value:: sage: R.<x,y> = QQ[] sage: vector([-y, x]).curl() @@ -3102,14 +3147,14 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: sage: v = vector(QQ, [4, 1, 3, 2]) - sage: v.normalized() + sage: v.normalized() # needs sage.symbolic (2/15*sqrt(30), 1/30*sqrt(30), 1/10*sqrt(30), 1/15*sqrt(30)) sage: sum(v.normalized(1)) 1 Note that normalizing the vector may change the base ring:: - sage: v.base_ring() == v.normalized().base_ring() + sage: v.base_ring() == v.normalized().base_ring() # needs sage.symbolic False sage: u = vector(RDF, [-3, 4, 6, 9]) sage: u.base_ring() == u.normalized().base_ring() @@ -3130,10 +3175,10 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: v = vector(CDF, [2.3 - 5.4*I, -1.7 + 3.6*I]) - sage: w = v.conjugate(); w + sage: v = vector(CDF, [2.3 - 5.4*I, -1.7 + 3.6*I]) # needs sage.symbolic + sage: w = v.conjugate(); w # needs sage.symbolic (2.3 + 5.4*I, -1.7 - 3.6*I) - sage: w.parent() + sage: w.parent() # needs sage.symbolic Vector space of dimension 2 over Complex Double Field Even if conjugation seems nonsensical over a certain ring, this @@ -3147,6 +3192,7 @@ cdef class FreeModuleElement(Vector): # abstract base class such as the cyclotomic fields. This example uses such a field containing a primitive 7-th root of unity named ``a``. :: + sage: # needs sage.rings.number_field sage: F.<a> = CyclotomicField(7) sage: v = vector(F, [a^i for i in range(7)]) sage: v @@ -3156,6 +3202,7 @@ cdef class FreeModuleElement(Vector): # abstract base class Sparse vectors are returned as such. :: + sage: # needs sage.symbolic sage: v = vector(CC, {1: 5 - 6*I, 3: -7*I}); v (0.000000000000000, 5.00000000000000 - 6.00000000000000*I, 0.000000000000000, -7.00000000000000*I) sage: v.is_sparse() @@ -3168,17 +3215,17 @@ cdef class FreeModuleElement(Vector): # abstract base class TESTS:: sage: n = 15 - sage: x = vector(CDF, [sin(i*pi/n)+cos(i*pi/n)*I for i in range(n)]) - sage: x + x.conjugate() in RDF^n + sage: x = vector(CDF, [sin(i*pi/n)+cos(i*pi/n)*I for i in range(n)]) # needs sage.symbolic + sage: x + x.conjugate() in RDF^n # needs sage.symbolic True - sage: I*(x - x.conjugate()) in RDF^n + sage: I*(x - x.conjugate()) in RDF^n # needs sage.symbolic True The parent of the conjugate is the same as that of the original vector. We test this by building a specialized vector space with a non-standard inner product, and constructing a test vector in this space. :: - sage: V = VectorSpace(CDF, 2, inner_product_matrix = [[2,1],[1,5]]) + sage: V = VectorSpace(CDF, 2, inner_product_matrix=[[2,1],[1,5]]) sage: v = vector(CDF, [2-3*I, 4+5*I]) sage: w = V(v) sage: w.parent() @@ -3247,11 +3294,11 @@ cdef class FreeModuleElement(Vector): # abstract base class through to subspaces. :: sage: ipm = matrix(ZZ,[[2,0,-1], [0,2,0], [-1,0,6]]) - sage: M = FreeModule(ZZ, 3, inner_product_matrix = ipm) + sage: M = FreeModule(ZZ, 3, inner_product_matrix=ipm) sage: v = M([1,0,0]) sage: v.inner_product(v) 2 - sage: K = M.span_of_basis([[0/2,-1/2,-1/2], [0,1/2,-1/2],[2,0,0]]) + sage: K = M.span_of_basis([[0/2,-1/2,-1/2], [0,1/2,-1/2], [2,0,0]]) sage: (K.0).inner_product(K.0) 2 sage: w = M([1,3,-1]) @@ -3287,7 +3334,7 @@ cdef class FreeModuleElement(Vector): # abstract base class But with an inner product defined, this method will check that the input is a vector or free module element. :: - sage: W = VectorSpace(RDF, 2, inner_product_matrix = matrix(RDF, 2, [1.0,2.0,3.0,4.0])) + sage: W = VectorSpace(RDF, 2, inner_product_matrix=matrix(RDF, 2, [1.0,2.0,3.0,4.0])) sage: v = W([2.0, 4.0]) sage: v.inner_product(5) Traceback (most recent call last): @@ -3404,10 +3451,12 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: w = vector(GF(5), [1,2]) sage: v = vector(GF(7), [1,2,3,4]) - sage: z = w.outer_product(v) + sage: z = w.outer_product(v) # needs sage.rings.finite_rings Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 1 dense matrices over Finite Field of size 5' and 'Full MatrixSpace of 1 by 4 dense matrices over Finite Field of size 7' + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 1 dense matrices over Finite Field of size 5' and + 'Full MatrixSpace of 1 by 4 dense matrices over Finite Field of size 7' And some inputs don't make any sense at all. :: @@ -3415,7 +3464,8 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: z=w.outer_product(6) Traceback (most recent call last): ... - TypeError: right operand in an outer product must be a vector, not an element of Integer Ring + TypeError: right operand in an outer product must be a vector, + not an element of Integer Ring """ if not isinstance(right, FreeModuleElement): raise TypeError('right operand in an outer product must be a vector, not an element of %s' % right.parent()) @@ -3456,6 +3506,7 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: + sage: # needs sage.symbolic sage: v = vector(CDF, [2+3*I, 5-4*I]) sage: w = vector(CDF, [6-4*I, 2+3*I]) sage: v.hermitian_inner_product(w) @@ -3466,6 +3517,7 @@ cdef class FreeModuleElement(Vector): # abstract base class the base rings have a conjugate method, then the Hermitian inner product will be available. :: + sage: # needs sage.rings.number_field sage: Q.<a> = QuadraticField(-7) sage: a^2 -7 @@ -3479,6 +3531,7 @@ cdef class FreeModuleElement(Vector): # abstract base class in each argument (with conjugation on the first scalar), and anti-commutative. :: + sage: # needs sage.symbolic sage: alpha = CDF(5.0 + 3.0*I) sage: u = vector(CDF, [2+4*I, -3+5*I, 2-7*I]) sage: v = vector(CDF, [-1+3*I, 5+4*I, 9-2*I]) @@ -3518,15 +3571,15 @@ cdef class FreeModuleElement(Vector): # abstract base class def is_dense(self): """ - Return True if this is a dense vector, which is just a + Return ``True`` if this is a dense vector, which is just a statement about the data structure, not the number of nonzero entries. EXAMPLES:: - sage: vector([1/2,2/5,0]).is_dense() + sage: vector([1/2, 2/5, 0]).is_dense() True - sage: vector([1/2,2/5,0],sparse=True).is_dense() + sage: vector([1/2, 2/5, 0], sparse=True).is_dense() False """ return self.is_dense_c() @@ -3536,15 +3589,15 @@ cdef class FreeModuleElement(Vector): # abstract base class def is_sparse(self): """ - Return True if this is a sparse vector, which is just a + Return ``True`` if this is a sparse vector, which is just a statement about the data structure, not the number of nonzero entries. EXAMPLES:: - sage: vector([1/2,2/5,0]).is_sparse() + sage: vector([1/2, 2/5, 0]).is_sparse() False - sage: vector([1/2,2/5,0],sparse=True).is_sparse() + sage: vector([1/2, 2/5, 0], sparse=True).is_sparse() True """ return self.is_sparse_c() @@ -3554,11 +3607,11 @@ cdef class FreeModuleElement(Vector): # abstract base class def is_vector(self): """ - Return True, since this is a vector. + Return ``True``, since this is a vector. EXAMPLES:: - sage: vector([1/2,2/5,0]).is_vector() + sage: vector([1/2, 2/5, 0]).is_vector() True """ return True @@ -3569,17 +3622,17 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: vector(QQ, [1, 2, 3])._macaulay2_() # optional - macaulay2 + sage: vector(QQ, [1, 2, 3])._macaulay2_() # optional - macaulay2 | 1 | | 2 | | 3 | - sage: _.ring() # optional - macaulay2 + sage: _.ring() # optional - macaulay2 QQ :: sage: R.<x,y> = QQ[] - sage: macaulay2(vector(R, [1, x+y])) # optional - macaulay2 + sage: macaulay2(vector(R, [1, x+y])) # optional - macaulay2 | 1 | | x+y | @@ -3604,9 +3657,10 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: + sage: # optional - mathematica, needs sage.symbolic sage: vector((1,2,3), QQ)._mathematica_init_() '{1/1, 2/1, 3/1}' - sage: mathematica(vector((1,2,3), QQ)) # optional - mathematica + sage: mathematica(vector((1,2,3), QQ)) {1, 2, 3} sage: a = vector(SR, 5, [1, x, x^2, sin(x), pi]); a (1, x, x^2, sin(x), pi) @@ -3628,16 +3682,16 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: v = vector([1, 2, 3]); v (1, 2, 3) - sage: sv = v._sympy_(); sv + sage: sv = v._sympy_(); sv # needs sympy Matrix([ [1], [2], [3]]) - sage: type(sv) + sage: type(sv) # needs sympy <class 'sympy.matrices.immutable.ImmutableDenseMatrix'> sage: w = vector({1: 1, 5: -1}, sparse=True) - sage: sw = w._sympy_(); sw + sage: sw = w._sympy_(); sw # needs sympy Matrix([ [ 0], [ 1], @@ -3645,26 +3699,26 @@ cdef class FreeModuleElement(Vector): # abstract base class [ 0], [ 0], [-1]]) - sage: type(sw) + sage: type(sw) # needs sympy <class 'sympy.matrices.immutable.ImmutableSparseMatrix'> If ``self`` was immutable, then converting the result to Sage gives back ``self``:: sage: immv = vector([1, 2, 3], immutable=True) - sage: immv._sympy_()._sage_() is immv + sage: immv._sympy_()._sage_() is immv # needs sympy True If ``self`` was mutable, then converting back to Sage creates a new matrix (column vector):: - sage: sv._sage_() + sage: sv._sage_() # needs sympy [1] [2] [3] - sage: sv._sage_() is v + sage: sv._sage_() is v # needs sympy False - sage: sv._sage_() == v + sage: sv._sage_() == v # needs sympy False """ from sage.interfaces.sympy import sympy_init @@ -3817,17 +3871,17 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: m = vector([1,x,sin(x+1)]) - sage: m.apply_map(lambda x: x^2) + sage: m = vector([1,x,sin(x+1)]) # needs sage.symbolic + sage: m.apply_map(lambda x: x^2) # needs sage.symbolic (1, x^2, sin(x + 1)^2) - sage: m.apply_map(sin) + sage: m.apply_map(sin) # needs sage.symbolic (sin(1), sin(x), sin(sin(x + 1))) :: sage: m = vector(ZZ, 9, range(9)) - sage: k.<a> = GF(9) - sage: m.apply_map(k) + sage: k.<a> = GF(9) # needs sage.rings.finite_rings + sage: m.apply_map(k) # needs sage.rings.finite_rings (0, 1, 2, 0, 1, 2, 0, 1, 2) In this example, we explicitly specify the codomain. @@ -3836,9 +3890,9 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: s = GF(3) sage: f = lambda x: s(x) - sage: n = m.apply_map(f, k); n + sage: n = m.apply_map(f, k); n # needs sage.rings.finite_rings (0, 1, 2, 0, 1, 2, 0, 1, 2) - sage: n.parent() + sage: n.parent() # needs sage.rings.finite_rings Vector space of dimension 9 over Finite Field in a of size 3^2 If your map sends 0 to a non-zero value, then your resulting @@ -3873,8 +3927,8 @@ cdef class FreeModuleElement(Vector): # abstract base class TESTS:: - sage: m = vector(SR,[]) - sage: m.apply_map(lambda x: x*x) == m + sage: m = vector(SR,[]) # needs sage.symbolic + sage: m.apply_map(lambda x: x*x) == m # needs sage.symbolic True Check that we don't unnecessarily apply phi to 0 in the sparse case:: @@ -3894,8 +3948,9 @@ cdef class FreeModuleElement(Vector): # abstract base class Check that the bug in :trac:`14558` has been fixed:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(9) - sage: v = vector([a, 0,0,0], sparse=True) + sage: v = vector([a, 0, 0, 0], sparse=True) sage: f = F.hom([a**3]) sage: v.apply_map(f) (2*a + 1, 0, 0, 0) @@ -3951,6 +4006,7 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: + sage: # needs sage.symbolic sage: v = vector([1,x,x^2]) sage: v._derivative(x) (0, 1, 2*x) @@ -3966,7 +4022,8 @@ cdef class FreeModuleElement(Vector): # abstract base class symbolic expressions, then calculate the matrix derivative (i.e., the Jacobian matrix):: - sage: T(r,theta)=[r*cos(theta),r*sin(theta)] + sage: # needs sage.symbolic + sage: T(r,theta) = [r*cos(theta), r*sin(theta)] sage: T (r, theta) |--> (r*cos(theta), r*sin(theta)) sage: T.diff() # matrix derivative @@ -3999,6 +4056,7 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: + sage: # needs sage.symbolic sage: v = vector([1,x,x^2]) sage: v.derivative(x) (0, 1, 2*x) @@ -4025,13 +4083,14 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: t=var('t') - sage: r=vector([t,t^2,sin(t)]) + sage: # needs sage.symbolic + sage: t = var('t') + sage: r = vector([t,t^2,sin(t)]) sage: r.integral(t) (1/2*t^2, 1/3*t^3, -cos(t)) - sage: integrate(r,t) + sage: integrate(r, t) (1/2*t^2, 1/3*t^3, -cos(t)) - sage: r.integrate(t,0,1) + sage: r.integrate(t, 0, 1) (1/2, 1/3, -cos(1) + 1) """ @@ -4051,19 +4110,25 @@ cdef class FreeModuleElement(Vector): # abstract base class EXAMPLES:: - sage: t=var('t') - sage: r=vector([t,t^2,sin(t)]) - sage: vec,answers=r.nintegral(t,0,1) - sage: vec + sage: # needs sage.symbolic + sage: t = var('t') + sage: r = vector([t,t^2,sin(t)]) + sage: vec, answers = r.nintegral(t,0,1) + sage: vec # abs tol 1e-15 (0.5, 0.3333333333333334, 0.4596976941318602) sage: type(vec) <class 'sage.modules.vector_real_double_dense.Vector_real_double_dense'> sage: answers - [(0.5, 5.55111512312578...e-15, 21, 0), (0.3333333333333..., 3.70074341541719...e-15, 21, 0), (0.45969769413186..., 5.10366964392284...e-15, 21, 0)] + [(0.5, 5.55111512312578...e-15, 21, 0), + (0.3333333333333..., 3.70074341541719...e-15, 21, 0), + (0.45969769413186..., 5.10366964392284...e-15, 21, 0)] - sage: r=vector([t,0,1], sparse=True) - sage: r.nintegral(t,0,1) - ((0.5, 0.0, 1.0), {0: (0.5, 5.55111512312578...e-15, 21, 0), 2: (1.0, 1.11022302462515...e-14, 21, 0)}) + sage: # needs sage.symbolic + sage: r = vector([t,0,1], sparse=True) + sage: r.nintegral(t, 0, 1) + ((0.5, 0.0, 1.0), + {0: (0.5, 5.55111512312578...e-15, 21, 0), + 2: (1.0, 1.11022302462515...e-14, 21, 0)}) """ # If Cython supported lambda functions, we would just do @@ -4151,13 +4216,13 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): :: - sage: v = vector([1,2/3,pi]) + sage: v = vector([1,2/3,pi]) # needs sage.symbolic sage: v == v True :: - sage: v = vector(RR, [1,2/3,pi]) + sage: v = vector(RR, [1,2/3,pi]) # needs sage.symbolic sage: v.set_immutable() sage: isinstance(hash(v), int) True @@ -4192,6 +4257,7 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): EXAMPLES:: + sage: # needs sage.symbolic sage: v = vector([-1,0,3,pi]) sage: type(v) <class 'sage.modules.free_module.FreeModule_ambient_field_with_category.element_class'> @@ -4200,11 +4266,11 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): sage: v.__copy__() is v False - sage: copy(v) + sage: copy(v) # needs sage.symbolic (-1, 0, 3, pi) - sage: copy(v) == v + sage: copy(v) == v # needs sage.symbolic True - sage: copy(v) is v + sage: copy(v) is v # needs sage.symbolic False """ return self._new_c(list(self._entries)) @@ -4213,17 +4279,17 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): """ EXAMPLES:: - sage: type(vector(RR, [-1,0,2/3,pi,oo])) + sage: type(vector(RR, [-1,0,2/3,pi,oo])) # needs sage.symbolic <class 'sage.modules.free_module_element.FreeModuleElement_generic_dense'> We can initialize with lists, tuples and derived types:: sage: from sage.modules.free_module_element import FreeModuleElement_generic_dense - sage: FreeModuleElement_generic_dense(RR^5, [-1,0,2/3,pi,oo]) + sage: FreeModuleElement_generic_dense(RR^5, [-1,0,2/3,pi,oo]) # needs sage.symbolic (-1.00000000000000, 0.000000000000000, 0.666666666666667, 3.14159265358979, +infinity) - sage: FreeModuleElement_generic_dense(RR^5, (-1,0,2/3,pi,oo)) + sage: FreeModuleElement_generic_dense(RR^5, (-1,0,2/3,pi,oo)) # needs sage.symbolic (-1.00000000000000, 0.000000000000000, 0.666666666666667, 3.14159265358979, +infinity) - sage: FreeModuleElement_generic_dense(RR^5, Sequence([-1,0,2/3,pi,oo])) + sage: FreeModuleElement_generic_dense(RR^5, Sequence([-1,0,2/3,pi,oo])) # needs sage.symbolic (-1.00000000000000, 0.000000000000000, 0.666666666666667, 3.14159265358979, +infinity) sage: FreeModuleElement_generic_dense(RR^0, 0) () @@ -4232,11 +4298,12 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): Disabling coercion can lead to illegal objects:: - sage: FreeModuleElement_generic_dense(RR^5, [-1,0,2/3,pi,oo], coerce=False) + sage: FreeModuleElement_generic_dense(RR^5, [-1,0,2/3,pi,oo], coerce=False) # needs sage.symbolic (-1, 0, 2/3, pi, +Infinity) We test the ``copy`` flag:: + sage: # needs sage.symbolic sage: from sage.modules.free_module_element import FreeModuleElement_generic_dense sage: L = [RR(x) for x in (-1,0,2/3,pi,oo)] sage: FreeModuleElement_generic_dense(RR^5, tuple(L), coerce=False, copy=False) @@ -4248,6 +4315,7 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): :: + sage: # needs sage.symbolic sage: L = [RR(x) for x in (-1,0,2/3,pi,oo)] sage: v = FreeModuleElement_generic_dense(RR^5, L, coerce=False, copy=True) sage: L[4] = 42.0 @@ -4309,8 +4377,8 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): EXAMPLES:: - sage: v = vector([1,2/3,pi]); w = vector([-2/3,pi^2,1]) - sage: v._add_(w) + sage: v = vector([1,2/3,pi]); w = vector([-2/3,pi^2,1]) # needs sage.symbolic + sage: v._add_(w) # needs sage.symbolic (1/3, pi^2 + 2/3, pi + 1) """ cdef list a = left._entries @@ -4356,10 +4424,10 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): """ EXAMPLES:: - sage: v = vector([-1,0,3,pi]) - sage: v._lmul_(2/3) + sage: v = vector([-1,0,3,pi]) # needs sage.symbolic + sage: v._lmul_(2/3) # needs sage.symbolic (-2/3, 0, 2, 2/3*pi) - sage: v * (2/3) + sage: v * (2/3) # needs sage.symbolic (-2/3, 0, 2, 2/3*pi) """ if right._parent is self._parent._base: @@ -4392,9 +4460,10 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): """ EXAMPLES:: - sage: v = vector([-1,0,3,pi]) - sage: v.__reduce__() - (<cyfunction make_FreeModuleElement_generic_dense_v1 at ...>, (Vector space of dimension 4 over Symbolic Ring, [-1, 0, 3, pi], 4, True)) + sage: v = vector([-1,0,3,pi]) # needs sage.symbolic + sage: v.__reduce__() # needs sage.symbolic + (<cyfunction make_FreeModuleElement_generic_dense_v1 at ...>, + (Vector space of dimension 4 over Symbolic Ring, [-1, 0, 3, pi], 4, True)) """ return (make_FreeModuleElement_generic_dense_v1, (self._parent, self._entries, self._degree, not self._is_immutable)) @@ -4405,8 +4474,8 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): """ EXAMPLES:: - sage: v = vector(RR, [-1,0,2/3,pi]) - sage: v.get(3) + sage: v = vector(RR, [-1,0,2/3,pi]) # needs sage.symbolic + sage: v.get(3) # needs sage.symbolic 3.14159265358979 :: @@ -4442,9 +4511,9 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): """ EXAMPLES:: - sage: v = vector(RR, [-1,0,2/3,pi]) - sage: v.set(3, RR(1)) - sage: v + sage: v = vector(RR, [-1, 0, 2/3, pi]) # needs sage.symbolic + sage: v.set(3, RR(1)) # needs sage.symbolic + sage: v # needs sage.symbolic (-1.00000000000000, 0.000000000000000, 0.666666666666667, 1.00000000000000) """ self._entries[i] = value @@ -4485,6 +4554,7 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): EXAMPLES:: + sage: # needs sage.symbolic sage: x, y = var('x,y') sage: f = x^2 + y^2 sage: g = f.gradient() @@ -4509,9 +4579,10 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): EXAMPLES:: - sage: x,y=var('x,y') - sage: v=vector([x,y,x*sin(y)]) - sage: w=v.function([x,y]); w + sage: # needs sage.symbolic + sage: x, y = var('x,y') + sage: v = vector([x, y, x*sin(y)]) + sage: w = v.function([x,y]); w (x, y) |--> (x, y, x*sin(y)) sage: w.coordinate_ring() Callable function ring with arguments (x, y) @@ -4524,9 +4595,10 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): :: - sage: x,y=var('x,y') - sage: v=vector([x,y,x*sin(y)]) - sage: w=v.function([x]); w + sage: # needs sage.symbolic + sage: x,y = var('x,y') + sage: v = vector([x, y, x*sin(y)]) + sage: w = v.function([x]); w x |--> (x, y, x*sin(y)) sage: w.coordinate_ring() Callable function ring with argument x @@ -4582,9 +4654,9 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): TESTS:: - sage: v = vector([1,2/3,pi], sparse=True) - sage: v.set_immutable() - sage: isinstance(hash(v), int) + sage: v = vector([1,2/3,pi], sparse=True) # needs sage.symbolic + sage: v.set_immutable() # needs sage.symbolic + sage: isinstance(hash(v), int) # needs sage.symbolic True Pickling works:: @@ -4634,8 +4706,8 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): """ EXAMPLES:: - sage: v = vector([1,2/3,pi], sparse=True) - sage: v.__copy__() + sage: v = vector([1,2/3,pi], sparse=True) # needs sage.symbolic + sage: v.__copy__() # needs sage.symbolic (1, 2/3, pi) """ return self._new_c(dict(self._entries)) @@ -4654,6 +4726,8 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): sage: from sage.modules.free_module_element import FreeModuleElement_generic_sparse sage: def S(R,n): ....: return FreeModule(R, n, sparse=True) + + sage: # needs sage.symbolic sage: FreeModuleElement_generic_sparse(S(RR,5), {0:-1, 2:2/3, 3:pi, 4:oo}) (-1.00000000000000, 0.000000000000000, 0.666666666666667, 3.14159265358979, +infinity) sage: FreeModuleElement_generic_sparse(S(RR,5), [-1,0,2/3,pi,oo]) @@ -4662,8 +4736,10 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): (-1.00000000000000, 0.000000000000000, 0.666666666666667, 3.14159265358979, +infinity) sage: FreeModuleElement_generic_sparse(S(RR,5), Sequence([-1,0,2/3,pi,oo])) (-1.00000000000000, 0.000000000000000, 0.666666666666667, 3.14159265358979, +infinity) + sage: FreeModuleElement_generic_sparse(S(RR,0), 0) () + sage: from collections import defaultdict sage: D = defaultdict(RR) sage: D[0] = -1 @@ -4699,13 +4775,14 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): Test that :trac:`17101` is fixed:: + sage: # needs sage.rings.real_interval_field sage: v = vector([RIF(-1, 1)], sparse=True) sage: v.is_zero() False We correctly initialize values which become 0 only after coercion:: - sage: v = FreeModuleElement_generic_sparse(S(GF(3),6), [1,2,3,4,5,6]) + sage: v = FreeModuleElement_generic_sparse(S(GF(3), 6), [1,2,3,4,5,6]) sage: v.nonzero_positions() [0, 1, 3, 4] """ @@ -4758,8 +4835,8 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): EXAMPLES:: - sage: v = vector([1,2/3,pi], sparse=True) - sage: v._add_(v) + sage: v = vector([1,2/3,pi], sparse=True) # needs sage.symbolic + sage: v._add_(v) # needs sage.symbolic (2, 4/3, 2*pi) """ cdef dict v = dict((<FreeModuleElement_generic_sparse>right)._entries) @@ -4778,8 +4855,8 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): """ EXAMPLES:: - sage: v = vector([1,2/3,pi], sparse=True) - sage: v._sub_(v) + sage: v = vector([1,2/3,pi], sparse=True) # needs sage.symbolic + sage: v._sub_(v) # needs sage.symbolic (0, 0, 0) """ cdef dict v = dict(left._entries) # dict to make a copy @@ -4798,8 +4875,8 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): """ EXAMPLES:: - sage: v = vector([1,2/3,pi], sparse=True) - sage: v._lmul_(SR(3)) + sage: v = vector([1,2/3,pi], sparse=True) # needs sage.symbolic + sage: v._lmul_(SR(3)) # needs sage.symbolic (3, 2, 3*pi) """ cdef dict v = {} @@ -4814,8 +4891,8 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): """ EXAMPLES:: - sage: v = vector([1,2/3,pi], sparse=True) - sage: v._rmul_(SR(3)) + sage: v = vector([1,2/3,pi], sparse=True) # needs sage.symbolic + sage: v._rmul_(SR(3)) # needs sage.symbolic (3, 2, 3*pi) """ cdef dict v = {} @@ -4882,8 +4959,8 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): """ EXAMPLES:: - sage: v = vector([1,2/3,pi], sparse=True); w = vector([-2/3,pi^2,1],sparse=True) - sage: v._pairwise_product_(w) + sage: v = vector([1,2/3,pi], sparse=True); w = vector([-2/3,pi^2,1],sparse=True) # needs sage.symbolic + sage: v._pairwise_product_(w) # needs sage.symbolic (-2/3, 2/3*pi^2, pi) """ # Component wise vector * vector multiplication. @@ -4907,14 +4984,14 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): TESTS:: - sage: v = vector([1,2/3,pi], sparse=True) - sage: w = vector([1,2/3,pi], sparse=True) - sage: w == v + sage: v = vector([1,2/3,pi], sparse=True) # needs sage.symbolic + sage: w = vector([1,2/3,pi], sparse=True) # needs sage.symbolic + sage: w == v # needs sage.symbolic True Check that the bug in :trac:`13929` has been fixed:: - sage: V = FreeModule( GF(3), 2, sparse=True) + sage: V = FreeModule(GF(3), 2, sparse=True) sage: a = V([0,1]) sage: b = V([1,0]) sage: a < b @@ -4931,17 +5008,17 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): EXAMPLES:: - sage: v = vector([1,2/3,pi], sparse=True) - sage: next(v.items()) + sage: v = vector([1,2/3,pi], sparse=True) # needs sage.symbolic + sage: next(v.items()) # needs sage.symbolic (0, 1) - sage: list(v.items()) + sage: list(v.items()) # needs sage.symbolic [(0, 1), (1, 2/3), (2, pi)] TESTS: Using iteritems as an alias:: - sage: list(v.iteritems()) + sage: list(v.iteritems()) # needs sage.symbolic [(0, 1), (1, 2/3), (2, pi)] """ return iter(self._entries.iteritems()) @@ -4952,9 +5029,10 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): """ EXAMPLES:: - sage: v = vector([1,2/3,pi], sparse=True) - sage: v.__reduce__() - (<cyfunction make_FreeModuleElement_generic_sparse_v1 at ...>, (Sparse vector space of dimension 3 over Symbolic Ring, {0: 1, 1: 2/3, 2: pi}, 3, True)) + sage: v = vector([1,2/3,pi], sparse=True) # needs sage.symbolic + sage: v.__reduce__() # needs sage.symbolic + (<cyfunction make_FreeModuleElement_generic_sparse_v1 at ...>, + (Sparse vector space of dimension 3 over Symbolic Ring, {0: 1, 1: 2/3, 2: pi}, 3, True)) """ return (make_FreeModuleElement_generic_sparse_v1, (self._parent, self._entries, self._degree, not self._is_immutable)) @@ -5030,15 +5108,15 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): """ EXAMPLES:: - sage: v = vector([-1,0,2/3,pi], sparse=True) - sage: v.get(1) + sage: v = vector([-1,0,2/3,pi], sparse=True) # needs sage.symbolic + sage: v.get(1) # needs sage.symbolic 0 - sage: v.get(2) + sage: v.get(2) # needs sage.symbolic 2/3 For this class, 0 is returned if the access is out of bounds:: - sage: v.get(10) + sage: v.get(10) # needs sage.symbolic 0 """ try: @@ -5059,13 +5137,14 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): (4, 5, 6) sage: parent(w[39893]) Finite Field of size 17 - sage: w[39893] = sqrt(2) + sage: w[39893] = sqrt(2) # needs sage.rings.finite_rings sage.symbolic Traceback (most recent call last): ... TypeError: self must be a numeric expression :: + sage: # needs sage.symbolic sage: v = vector([1,2/3,pi], sparse=True) sage: v.set(1, pi^3) sage: v @@ -5076,12 +5155,13 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): This assignment is illegal:: - sage: v.set(10, pi) + sage: v.set(10, pi) # needs sage.symbolic This lack of bounds checking causes trouble later:: - sage: v - <repr(<sage.modules.free_module_element.FreeModuleElement_generic_sparse at 0x...>) failed: IndexError: list assignment index out of range> + sage: v # needs sage.symbolic + <repr(<sage.modules.free_module.FreeModule_ambient_field_with_category.element_class at 0x...>) failed: + IndexError: list assignment index out of range> """ if value: self._entries[i] = value diff --git a/src/sage/modules/free_module_homspace.py b/src/sage/modules/free_module_homspace.py index 4d99c5f4223..79c2b226436 100644 --- a/src/sage/modules/free_module_homspace.py +++ b/src/sage/modules/free_module_homspace.py @@ -54,7 +54,7 @@ See :trac:`13321`:: - sage: (GF(7)^2).hom([[20,0],[0,21]],ZZ^2) + sage: (GF(7)^2).hom([[20, 0], [0, 21]], ZZ^2) Traceback (most recent call last): ... TypeError: nontrivial morphisms require a coercion map from the base ring @@ -215,7 +215,7 @@ def __call__(self, A, **kwds): # Let us hope that FreeModuleMorphism knows to handle # that case pass - if not(self.codomain().base_ring().has_coerce_map_from(self.domain().base_ring())) and not(A.is_zero()): + if not self.codomain().base_ring().has_coerce_map_from(self.domain().base_ring()) and not A.is_zero(): raise TypeError("nontrivial morphisms require a coercion map from the base ring of the domain to the base ring of the codomain") return free_module_morphism.FreeModuleMorphism(self, A, side) diff --git a/src/sage/modules/free_module_integer.py b/src/sage/modules/free_module_integer.py index ddd8a25c92a..c16e747a53f 100644 --- a/src/sage/modules/free_module_integer.py +++ b/src/sage/modules/free_module_integer.py @@ -38,7 +38,11 @@ from sage.misc.cachefunc import cached_method from sage.modules.free_module import FreeModule_submodule_with_basis_pid, FreeModule_ambient_pid from sage.modules.free_module_element import vector -from sage.rings.number_field.number_field_element import OrderElement_absolute + +try: + from sage.rings.number_field.number_field_element import OrderElement_absolute +except ImportError: + OrderElement_absolute = () def IntegerLattice(basis, lll_reduce=True): @@ -107,9 +111,11 @@ def IntegerLattice(basis, lll_reduce=True): We construct an ideal lattice from an element of an absolute order:: + sage: # needs sage.rings.number_field sage: K.<a> = CyclotomicField(17) sage: O = K.ring_of_integers() - sage: f = O(-a^15 + a^13 + 4*a^12 - 12*a^11 - 256*a^10 + a^9 - a^7 - 4*a^6 + a^5 + 210*a^4 + 2*a^3 - 2*a^2 + 2*a - 2) + sage: f = O(-a^15 + a^13 + 4*a^12 - 12*a^11 - 256*a^10 + a^9 - a^7 + ....: - 4*a^6 + a^5 + 210*a^4 + 2*a^3 - 2*a^2 + 2*a - 2) sage: from sage.modules.free_module_integer import IntegerLattice sage: IntegerLattice(f) Free module of degree 16 and rank 16 over Integer Ring @@ -151,6 +157,7 @@ def IntegerLattice(basis, lll_reduce=True): Sage also interfaces with fpylll's lattice generator:: + sage: # needs fpylll sage: from sage.modules.free_module_integer import IntegerLattice sage: from fpylll import IntegerMatrix sage: A = IntegerMatrix.random(8, "simdioph", bits=20, bits2=10) @@ -197,7 +204,8 @@ class FreeModule_submodule_with_basis_integer(FreeModule_submodule_with_basis_pi EXAMPLES:: sage: from sage.modules.free_module_integer import IntegerLattice - sage: L = IntegerLattice(sage.crypto.gen_lattice(type='modular', m=10, seed=1337, dual=True)); L + sage: L = IntegerLattice(sage.crypto.gen_lattice(type='modular', m=10, + ....: seed=1337, dual=True)); L Free module of degree 10 and rank 10 over Integer Ring User basis matrix: [-1 1 2 -2 0 1 0 -1 2 1] @@ -259,7 +267,9 @@ def __init__(self, ambient, basis, check=True, echelonize=False, sage: M.row_space() == L.matrix().row_space() True - sage: K.<a> = NumberField(x^8+1) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^8 + 1) sage: O = K.ring_of_integers() sage: f = O(a^7 - a^6 + 4*a^5 - a^4 + a^3 + 1) sage: IntegerLattice(f) @@ -364,10 +374,10 @@ def LLL(self, *args, **kwds): ... sage: L.reduced_basis == A True - sage: old = L.reduced_basis[0].norm().n() + sage: old = L.reduced_basis[0].norm().n() # needs sage.symbolic sage: _ = L.LLL() - sage: new = L.reduced_basis[0].norm().n() - sage: new <= old + sage: new = L.reduced_basis[0].norm().n() # needs sage.symbolic + sage: new <= old # needs sage.symbolic True """ basis = self.reduced_basis @@ -397,21 +407,18 @@ def BKZ(self, *args, **kwds): EXAMPLES:: + sage: # needs sage.libs.flint (o/w timeout) sage: from sage.modules.free_module_integer import IntegerLattice sage: A = sage.crypto.gen_lattice(type='random', n=1, m=60, q=2^60, seed=42) sage: L = IntegerLattice(A, lll_reduce=False) sage: min(v.norm().n() for v in L.reduced_basis) 4.17330740711759e15 - sage: L.LLL() 60 x 60 dense matrix over Integer Ring (use the '.str()' method to see the entries) - sage: min(v.norm().n() for v in L.reduced_basis) 5.19615242270663 - sage: L.BKZ(block_size=10) 60 x 60 dense matrix over Integer Ring (use the '.str()' method to see the entries) - sage: min(v.norm().n() for v in L.reduced_basis) 4.12310562561766 @@ -557,21 +564,21 @@ def shortest_vector(self, update_reduced_basis=True, algorithm="fplll", *args, * sage: from sage.modules.free_module_integer import IntegerLattice sage: A = sage.crypto.gen_lattice(type='random', n=1, m=30, q=2^40, seed=42) sage: L = IntegerLattice(A, lll_reduce=False) - sage: min(v.norm().n() for v in L.reduced_basis) + sage: min(v.norm().n() for v in L.reduced_basis) # needs sage.symbolic 6.03890756700000e10 - sage: L.shortest_vector().norm().n() + sage: L.shortest_vector().norm().n() # needs sage.symbolic 3.74165738677394 sage: L = IntegerLattice(A, lll_reduce=False) - sage: min(v.norm().n() for v in L.reduced_basis) + sage: min(v.norm().n() for v in L.reduced_basis) # needs sage.symbolic 6.03890756700000e10 - sage: L.shortest_vector(algorithm="pari").norm().n() + sage: L.shortest_vector(algorithm="pari").norm().n() # needs sage.symbolic 3.74165738677394 sage: L = IntegerLattice(A, lll_reduce=True) - sage: L.shortest_vector(algorithm="pari").norm().n() + sage: L.shortest_vector(algorithm="pari").norm().n() # needs sage.symbolic 3.74165738677394 """ if algorithm == "pari": @@ -622,7 +629,7 @@ def update_reduced_basis(self, w): """ w = matrix(ZZ, w) L = w.stack(self.reduced_basis).LLL() - assert(L[0] == 0) + assert L[0] == 0 self._reduced_basis = L.matrix_from_rows(range(1, L.nrows())) @cached_method @@ -648,7 +655,10 @@ def voronoi_cell(self, radius=None): sage: L = IntegerLattice([[1, 0], [0, 1]]) sage: V = L.voronoi_cell() sage: V.Vrepresentation() - (A vertex at (1/2, -1/2), A vertex at (1/2, 1/2), A vertex at (-1/2, 1/2), A vertex at (-1/2, -1/2)) + (A vertex at (1/2, -1/2), + A vertex at (1/2, 1/2), + A vertex at (-1/2, 1/2), + A vertex at (-1/2, -1/2)) The volume of the Voronoi cell is the square root of the discriminant of the lattice:: @@ -660,8 +670,8 @@ def voronoi_cell(self, radius=None): [ 1 -1 2 1] [ -6 0 3 3] [ -6 -24 -6 -5] - sage: V = L.voronoi_cell() # long time - sage: V.volume() # long time + sage: V = L.voronoi_cell() # long time + sage: V.volume() # long time 678 sage: sqrt(L.discriminant()) 678 @@ -671,7 +681,10 @@ def voronoi_cell(self, radius=None): sage: L = IntegerLattice([[2, 0, 0], [0, 2, 0]]) sage: V = L.voronoi_cell() sage: V.Hrepresentation() - (An inequality (-1, 0, 0) x + 1 >= 0, An inequality (0, -1, 0) x + 1 >= 0, An inequality (1, 0, 0) x + 1 >= 0, An inequality (0, 1, 0) x + 1 >= 0) + (An inequality (-1, 0, 0) x + 1 >= 0, + An inequality (0, -1, 0) x + 1 >= 0, + An inequality (1, 0, 0) x + 1 >= 0, + An inequality (0, 1, 0) x + 1 >= 0) ALGORITHM: @@ -776,7 +789,7 @@ def projection(M, v): def CVPP_2V(t, V, voronoi_cell): t_new = t while not voronoi_cell.contains(t_new.list()): - v = max(V, key=lambda v: t_new * v / v.norm() ** 2) + v = max(V, key=lambda v: t_new * v / v.dot_product(v)) t_new = t_new - v return t - t_new diff --git a/src/sage/modules/free_module_morphism.py b/src/sage/modules/free_module_morphism.py index f7508ebeb97..cdc933f23d0 100644 --- a/src/sage/modules/free_module_morphism.py +++ b/src/sage/modules/free_module_morphism.py @@ -9,12 +9,12 @@ TESTS:: - sage: V = ZZ^2; f = V.hom([V.1,-2*V.0]) + sage: V = ZZ^2; f = V.hom([V.1, -2*V.0]) sage: loads(dumps(f)) Free module morphism defined by the matrix [ 0 1] [-2 0] - Domain: Ambient free module of rank 2 over the principal ideal domain ... + Domain: Ambient free module of rank 2 over the principal ideal domain ... Codomain: Ambient free module of rank 2 over the principal ideal domain ... sage: loads(dumps(f)) == f True @@ -53,7 +53,7 @@ def is_FreeModuleMorphism(x): """ EXAMPLES:: - sage: V = ZZ^2; f = V.hom([V.1,-2*V.0]) + sage: V = ZZ^2; f = V.hom([V.1, -2*V.0]) sage: sage.modules.free_module_morphism.is_FreeModuleMorphism(f) True sage: sage.modules.free_module_morphism.is_FreeModuleMorphism(0) @@ -158,7 +158,7 @@ def _repr_(self): sage: phi Vector space morphism represented by the matrix: 40 x 40 dense matrix over Rational Field - Domain: Vector space of dimension 40 over Rational Field + Domain: Vector space of dimension 40 over Rational Field Codomain: Vector space of dimension 40 over Rational Field The representation displays which side of the vectors the matrix is acting:: @@ -169,14 +169,14 @@ def _repr_(self): [0 1 0] [0 0 1] [1 0 0] - Domain: Ambient free module of rank 3 over the principal ideal domain Integer Ring + Domain: Ambient free module of rank 3 over the principal ideal domain Integer Ring Codomain: Ambient free module of rank 3 over the principal ideal domain Integer Ring sage: h2 = V.hom([V.1, V.2, V.0], side="right"); h2 Free module morphism defined as left-multiplication by the matrix [0 0 1] [1 0 0] [0 1 0] - Domain: Ambient free module of rank 3 over the principal ideal domain Integer Ring + Domain: Ambient free module of rank 3 over the principal ideal domain Integer Ring Codomain: Ambient free module of rank 3 over the principal ideal domain Integer Ring """ r = "Free module morphism defined {}by the matrix\n{!r}\nDomain: {}\nCodomain: {}" @@ -187,13 +187,15 @@ def _repr_(self): def change_ring(self, R): """ - Change the ring over which this morphism is defined. This changes the ring of the - domain, codomain, and underlying matrix. + Change the ring over which this morphism is defined. + + This changes the ring of the domain, codomain, and underlying matrix. EXAMPLES:: - sage: V0 = span([[0,0,1],[0,2,0]],ZZ); V1 = span([[1/2,0],[0,2]],ZZ); W = span([[1,0],[0,6]],ZZ) - sage: h = V0.hom([-3*V1.0-3*V1.1, -3*V1.0-3*V1.1]) + sage: V0 = span([[0,0,1],[0,2,0]], ZZ); V1 = span([[1/2,0],[0,2]], ZZ) + sage: W = span([[1,0],[0,6]], ZZ) + sage: h = V0.hom([-3*V1.0 - 3*V1.1, -3*V1.0 - 3*V1.1]) sage: h.base_ring() Integer Ring sage: h @@ -206,26 +208,26 @@ def change_ring(self, R): Vector space morphism represented by the matrix: [-3 -3] [-3 -3] - Domain: Vector space of degree 3 and dimension 2 over Rational Field - Basis matrix: - [0 1 0] - [0 0 1] + Domain: Vector space of degree 3 and dimension 2 over Rational Field + Basis matrix: + [0 1 0] + [0 0 1] Codomain: Vector space of degree 2 and dimension 2 over Rational Field - Basis matrix: - [1 0] - [0 1] + Basis matrix: + [1 0] + [0 1] sage: f = h.change_ring(GF(7)); f Vector space morphism represented by the matrix: [4 4] [4 4] - Domain: Vector space of degree 3 and dimension 2 over Finite Field of size 7 - Basis matrix: - [0 1 0] - [0 0 1] + Domain: Vector space of degree 3 and dimension 2 over Finite Field of size 7 + Basis matrix: + [0 1 0] + [0 0 1] Codomain: Vector space of degree 2 and dimension 2 over Finite Field of size 7 - Basis matrix: - [1 0] - [0 1] + Basis matrix: + [1 0] + [0 1] """ D = self.domain().change_ring(R) C = self.codomain().change_ring(R) @@ -262,8 +264,9 @@ def inverse_image(self, V): We test computing inverse images between two spaces embedded in different ambient spaces.:: - sage: V0 = span([[0,0,1],[0,2,0]],ZZ); V1 = span([[1/2,0],[0,2]],ZZ); W = span([[1,0],[0,6]],ZZ) - sage: h = V0.hom([-3*V1.0-3*V1.1, -3*V1.0-3*V1.1]) + sage: V0 = span([[0,0,1],[0,2,0]],ZZ); V1 = span([[1/2,0],[0,2]],ZZ) + sage: W = span([[1,0],[0,6]],ZZ) + sage: h = V0.hom([-3*V1.0 - 3*V1.1, -3*V1.0 - 3*V1.1]) sage: h.inverse_image(W) Free module of degree 3 and rank 2 over Integer Ring Echelon basis matrix: @@ -282,7 +285,7 @@ def inverse_image(self, V): We test computing inverse images over the integers:: sage: V = QQ^3; W = V.span_of_basis([[2,2,3],[-1,2,5/3]], ZZ) - sage: phi = W.hom([W.0, W.0-W.1]) + sage: phi = W.hom([W.0, W.0 - W.1]) sage: Z = W.span([2*W.1]); Z Free module of degree 3 and rank 1 over Integer Ring Echelon basis matrix: @@ -352,7 +355,7 @@ def inverse_image(self, V): else: if not hasattr(A, 'hermite_form'): - raise NotImplementedError("base ring (%s) must have hermite_form algorithm in order to compute inverse image"%R) + raise NotImplementedError("base ring (%s) must have hermite_form algorithm in order to compute inverse image" % R) # 1. Compute H such that U*A = H = hnf(A) without zero # rows. What this "does" is find a basis for the image of @@ -395,7 +398,7 @@ def lift(self, x): sage: V = X.span([[2, 0], [0, 8]], ZZ) sage: W = (QQ**1).span([[1/12]], ZZ) sage: f = V.hom([W([1/3]), W([1/2])], W) - sage: l=f.lift([1/3]); l # random + sage: l=f.lift([1/3]); l # random (8, -16) sage: f(l) (1/3) @@ -440,7 +443,7 @@ def lift(self, x): :: sage: V = QQ^2; m = matrix(2, [1, 1, 0, 1]) - sage: V.hom(m, side="right").lift(V.0+V.1) + sage: V.hom(m, side="right").lift(V.0 + V.1) (0, 1) sage: V.hom(m).lift(V.0+V.1) (1, 0) @@ -460,7 +463,7 @@ def lift(self, x): else: # see inverse_image for similar code but with comments if not hasattr(A, 'hermite_form'): - raise NotImplementedError("base ring (%s) must have hermite_form algorithm in order to compute inverse image"%R) + raise NotImplementedError("base ring (%s) must have hermite_form algorithm in order to compute inverse image" % R) H, U = A.hermite_form(transformation=True,include_zero_rows=False) Y = H.solve_left(vector(self.codomain().coordinates(x))) C = Y*U @@ -473,7 +476,7 @@ def lift(self, x): preimage_representative = lift - def eigenvalues(self,extend=True): + def eigenvalues(self, extend=True): r""" Returns a list with the eigenvalues of the endomorphism of vector spaces. @@ -486,18 +489,18 @@ def eigenvalues(self,extend=True): We compute the eigenvalues of an endomorphism of `\QQ^3`:: - sage: V=QQ^3 - sage: H=V.endomorphism_ring()([[1,-1,0],[-1,1,1],[0,3,1]]) - sage: H.eigenvalues() + sage: V = QQ^3 + sage: H = V.endomorphism_ring()([[1,-1,0], [-1,1,1], [0,3,1]]) + sage: H.eigenvalues() # needs sage.rings.number_field [3, 1, -1] Note the effect of the ``extend`` option:: - sage: V=QQ^2 - sage: H=V.endomorphism_ring()([[0,-1],[1,0]]) - sage: H.eigenvalues() + sage: V = QQ^2 + sage: H = V.endomorphism_ring()([[0,-1], [1,0]]) + sage: H.eigenvalues() # needs sage.rings.number_field [-1*I, 1*I] - sage: H.eigenvalues(extend=False) + sage: H.eigenvalues(extend=False) # needs sage.libs.pari [] """ if self.base_ring().is_field(): @@ -508,7 +511,7 @@ def eigenvalues(self,extend=True): else: raise NotImplementedError("module must be a vector space") - def eigenvectors(self,extend=True): + def eigenvectors(self, extend=True): """ Computes the subspace of eigenvectors of a given eigenvalue. @@ -525,61 +528,42 @@ def eigenvectors(self,extend=True): EXAMPLES:: - sage: V=(QQ^4).subspace([[0,2,1,4],[1,2,5,0],[1,1,1,1]]) - sage: H=(V.Hom(V))(matrix(QQ, [[0,1,0],[-1,0,0],[0,0,3]])) + sage: # needs sage.rings.number_field + sage: V = (QQ^4).subspace([[0,2,1,4], [1,2,5,0], [1,1,1,1]]) + sage: H = (V.Hom(V))(matrix(QQ, [[0,1,0], [-1,0,0], [0,0,3]])) sage: H.eigenvectors() - [(3, [ - (0, 0, 1, -6/7) - ], 1), (-1*I, [ - (1, 1*I, 0, -0.571428571428572? + 2.428571428571429?*I) - ], 1), (1*I, [ - (1, -1*I, 0, -0.571428571428572? - 2.428571428571429?*I) - ], 1)] + [(3, [ (0, 0, 1, -6/7) ], 1), + (-1*I, [ (1, 1*I, 0, -0.571428571428572? + 2.428571428571429?*I) ], 1), + (1*I, [ (1, -1*I, 0, -0.571428571428572? - 2.428571428571429?*I) ], 1)] sage: H.eigenvectors(extend=False) - [(3, [ - (0, 0, 1, -6/7) - ], 1)] - sage: H1=(V.Hom(V))(matrix(QQ, [[2,1,0],[0,2,0],[0,0,3]])) + [(3, [ (0, 0, 1, -6/7) ], 1)] + sage: H1 = (V.Hom(V))(matrix(QQ, [[2,1,0],[0,2,0],[0,0,3]])) sage: H1.eigenvectors() - [(3, [ - (0, 0, 1, -6/7) - ], 1), (2, [ - (0, 1, 0, 17/7) - ], 2)] + [(3, [ (0, 0, 1, -6/7) ], 1), + (2, [ (0, 1, 0, 17/7) ], 2)] sage: H1.eigenvectors(extend=False) - [(3, [ - (0, 0, 1, -6/7) - ], 1), (2, [ - (0, 1, 0, 17/7) - ], 2)] + [(3, [ (0, 0, 1, -6/7) ], 1), + (2, [ (0, 1, 0, 17/7) ], 2)] :: sage: V = QQ^2 sage: m = matrix(2, [1, 1, 0, 1]) - sage: V.hom(m, side="right").eigenvectors() - [(1, - [ - (1, 0) - ], - 2)] - sage: V.hom(m).eigenvectors() - [(1, - [ - (0, 1) - ], - 2)] + sage: V.hom(m, side="right").eigenvectors() # needs sage.rings.number_field + [(1, [ (1, 0) ], 2)] + sage: V.hom(m).eigenvectors() # needs sage.rings.number_field + [(1, [ (0, 1) ], 2)] """ if self.base_ring().is_field(): if self.is_endomorphism(): if self.side() == "right": - seigenvec=self.matrix().eigenvectors_right(extend=extend) + seigenvec = self.matrix().eigenvectors_right(extend=extend) else: - seigenvec=self.matrix().eigenvectors_left(extend=extend) - resu=[] + seigenvec = self.matrix().eigenvectors_left(extend=extend) + resu = [] for i in seigenvec: - V=self.domain().base_extend(i[0].parent()) - svectors=Sequence([V(j * V.basis_matrix()) for j in i[1]], cr=True) + V = self.domain().base_extend(i[0].parent()) + svectors = Sequence([V(j * V.basis_matrix()) for j in i[1]], cr=True) resu.append((i[0],svectors,i[2])) return resu else: @@ -587,7 +571,7 @@ def eigenvectors(self,extend=True): else: raise NotImplementedError("module must be a vector space") - def eigenspaces(self,extend=True): + def eigenspaces(self, extend=True): """ Compute a list of subspaces formed by eigenvectors of ``self``. @@ -603,56 +587,51 @@ def eigenspaces(self,extend=True): EXAMPLES:: sage: V = QQ^3 - sage: h = V.hom([[1,0,0],[0,0,1],[0,-1,0]], V) - sage: h.eigenspaces() - [(1, - Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [1 0 0]), - (-1*I, - Vector space of degree 3 and dimension 1 over Algebraic Field - Basis matrix: - [ 0 1 1*I]), - (1*I, - Vector space of degree 3 and dimension 1 over Algebraic Field - Basis matrix: - [ 0 1 -1*I])] - - sage: h.eigenspaces(extend=False) + sage: h = V.hom([[1,0,0], [0,0,1], [0,-1,0]], V) + sage: h.eigenspaces() # needs sage.rings.number_field + [(1, Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: + [1 0 0]), + (-1*I, Vector space of degree 3 and dimension 1 over Algebraic Field + Basis matrix: + [ 0 1 1*I]), + (1*I, Vector space of degree 3 and dimension 1 over Algebraic Field + Basis matrix: + [ 0 1 -1*I])] + + sage: h.eigenspaces(extend=False) # needs sage.rings.number_field [(1, Vector space of degree 3 and dimension 1 over Rational Field Basis matrix: [1 0 0])] sage: h = V.hom([[2,1,0], [0,2,0], [0,0,-1]], V) - sage: h.eigenspaces() + sage: h.eigenspaces() # needs sage.rings.number_field [(-1, Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [0 0 1]), + Basis matrix: + [0 0 1]), (2, Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [0 1 0])] + Basis matrix: + [0 1 0])] sage: h = V.hom([[2,1,0], [0,2,0], [0,0,2]], V) - sage: h.eigenspaces() + sage: h.eigenspaces() # needs sage.rings.number_field [(2, Vector space of degree 3 and dimension 2 over Rational Field - Basis matrix: - [0 1 0] - [0 0 1])] + Basis matrix: + [0 1 0] + [0 0 1])] :: sage: V = QQ^2; m = matrix(2, [1, 1, 0, 1]) - sage: V.hom(m, side="right").eigenspaces() - [(1, - Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 0])] - sage: V.hom(m).eigenspaces() - [(1, - Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [0 1])] + sage: V.hom(m, side="right").eigenspaces() # needs sage.rings.number_field + [(1, Vector space of degree 2 and dimension 1 over Rational Field + Basis matrix: + [1 0])] + sage: V.hom(m).eigenspaces() # needs sage.rings.number_field + [(1, Vector space of degree 2 and dimension 1 over Rational Field + Basis matrix: + [0 1])] """ ev = self.eigenvectors(extend) return [(vec[0], Sequence(vec[1]).universe().subspace(vec[1])) @@ -676,20 +655,20 @@ def minimal_polynomial(self,var='x'): Compute the minimal polynomial, and check it. :: - sage: V=GF(7)^3 - sage: H=V.Hom(V)([[0,1,2],[-1,0,3],[2,4,1]]) + sage: V = GF(7)^3 + sage: H = V.Hom(V)([[0,1,2], [-1,0,3], [2,4,1]]) sage: H Vector space morphism represented by the matrix: [0 1 2] [6 0 3] [2 4 1] - Domain: Vector space of dimension 3 over Finite Field of size 7 + Domain: Vector space of dimension 3 over Finite Field of size 7 Codomain: Vector space of dimension 3 over Finite Field of size 7 - sage: H.minpoly() + sage: H.minpoly() # needs sage.libs.pari x^3 + 6*x^2 + 6*x + 1 - sage: H.minimal_polynomial() + sage: H.minimal_polynomial() # needs sage.libs.pari x^3 + 6*x^2 + 6*x + 1 sage: H^3 + (H^2)*6 + H*6 + 1 @@ -697,7 +676,7 @@ def minimal_polynomial(self,var='x'): [0 0 0] [0 0 0] [0 0 0] - Domain: Vector space of dimension 3 over Finite Field of size 7 + Domain: Vector space of dimension 3 over Finite Field of size 7 Codomain: Vector space of dimension 3 over Finite Field of size 7 """ if self.is_endomorphism(): @@ -717,7 +696,8 @@ class BaseIsomorphism1D(Morphism): sage: V, from_V, to_V = R.free_module(R) sage: from_V Isomorphism morphism: - From: Ambient free module of rank 1 over the integral domain Multivariate Polynomial Ring in x, y over Rational Field + From: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y over Rational Field To: Multivariate Polynomial Ring in x, y over Rational Field """ def _repr_type(self): diff --git a/src/sage/modules/free_quadratic_module.py b/src/sage/modules/free_quadratic_module.py index b512db6ffbc..ff112b9a5c2 100644 --- a/src/sage/modules/free_quadratic_module.py +++ b/src/sage/modules/free_quadratic_module.py @@ -1141,8 +1141,8 @@ def __init__(self, base_field, dimension, inner_product_matrix, sparse=False): Check for :trac:`10606`:: sage: D = matrix.diagonal(ZZ, [1,1]) - sage: V = VectorSpace(GF(46349), 2, inner_product_matrix=D) - sage: deepcopy(V) + sage: V = VectorSpace(GF(46349), 2, inner_product_matrix=D) # needs sage.rings.finite_rings + sage: deepcopy(V) # needs sage.rings.finite_rings Ambient quadratic space of dimension 2 over Finite Field of size 46349 Inner product matrix: diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 0902a272f39..e4959cc7a55 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -59,9 +59,7 @@ from sage.matrix.constructor import matrix from sage.structure.element import is_Matrix from sage.arith.misc import gcd -from sage.combinat.root_system.cartan_matrix import CartanMatrix from sage.misc.cachefunc import cached_method -from sage.quadratic_forms.all import QuadraticForm ############################################################################### # @@ -157,6 +155,7 @@ def IntegralLattice(data, basis=None): (see :mod:`Cartan types <sage.combinat.root_system.cartan_type>` and :class:`CartanMatrix`):: + sage: # needs sage.graphs sage: IntegralLattice(["E", 7]) Lattice of degree 7 and rank 7 over Integer Ring Standard basis @@ -201,7 +200,7 @@ def IntegralLattice(data, basis=None): Inner product matrix: [0 1] [1 0] - sage: IntegralLattice(["A", 3], [[1,1,1]]) + sage: IntegralLattice(["A", 3], [[1,1,1]]) # needs sage.graphs Lattice of degree 3 and rank 1 over Integer Ring Basis matrix: [1 1 1] @@ -214,7 +213,7 @@ def IntegralLattice(data, basis=None): Basis matrix: [1 1 1 1] Standard scalar product - sage: IntegralLattice("A2", [[1,1]]) + sage: IntegralLattice("A2", [[1,1]]) # needs sage.graphs Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [1 1] @@ -224,11 +223,11 @@ def IntegralLattice(data, basis=None): TESTS:: - sage: IntegralLattice(["A", 1, 1]) + sage: IntegralLattice(["A", 1, 1]) # needs sage.graphs Traceback (most recent call last): ... ValueError: lattices must be nondegenerate; use FreeQuadraticModule instead - sage: IntegralLattice(["D", 3, 1]) + sage: IntegralLattice(["D", 3, 1]) # needs sage.graphs Traceback (most recent call last): ... ValueError: lattices must be nondegenerate; use FreeQuadraticModule instead @@ -240,6 +239,7 @@ def IntegralLattice(data, basis=None): elif data == "U" or data == "H": inner_product_matrix = matrix([[0,1],[1,0]]) else: + from sage.combinat.root_system.cartan_matrix import CartanMatrix inner_product_matrix = CartanMatrix(data) if basis is None: basis = matrix.identity(ZZ, inner_product_matrix.ncols()) @@ -272,6 +272,7 @@ def IntegralLatticeDirectSum(Lattices, return_embeddings=False): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLatticeDirectSum sage: L1 = IntegralLattice("D4") sage: L2 = IntegralLattice("A3", [[1, 1, 2]]) @@ -309,7 +310,7 @@ def IntegralLatticeDirectSum(Lattices, return_embeddings=False): TESTS:: - sage: IntegralLatticeDirectSum([IntegralLattice("D4")]) + sage: IntegralLatticeDirectSum([IntegralLattice("D4")]) # needs sage.graphs Lattice of degree 4 and rank 4 over Integer Ring Standard basis Inner product matrix: @@ -319,9 +320,9 @@ def IntegralLatticeDirectSum(Lattices, return_embeddings=False): [ 0 -1 0 2] sage: L1 = IntegralLattice(2 * matrix.identity(2), [[1/2, 1/2]]) - sage: L2 = IntegralLattice("A3", [[1, 1, 2]]) - sage: [L, phi] = IntegralLatticeDirectSum([L1, L2], True) - sage: L + sage: L2 = IntegralLattice("A3", [[1, 1, 2]]) # needs sage.graphs + sage: [L, phi] = IntegralLatticeDirectSum([L1, L2], True) # needs sage.graphs + sage: L # needs sage.graphs Lattice of degree 5 and rank 2 over Integer Ring Basis matrix: [1/2 1/2 0 0 0] @@ -417,6 +418,7 @@ def IntegralLatticeGluing(Lattices, glue, return_embeddings=False): Inner product matrix: [4]]] + sage: # needs sage.graphs sage: L1 = IntegralLattice([[2]]) sage: L2 = IntegralLattice([[2]]) sage: AL1 = L1.discriminant_group() @@ -437,6 +439,7 @@ def IntegralLatticeGluing(Lattices, glue, return_embeddings=False): [2 0] [0 2] + sage: # needs sage.graphs sage: L1 = IntegralLattice("A4") sage: L2 = IntegralLattice("A4") sage: g1 = L1.discriminant_group().gens()[0] @@ -482,6 +485,7 @@ def IntegralLatticeGluing(Lattices, glue, return_embeddings=False): Different gluings can be composed:: + sage: # needs sage.graphs sage: D4 = IntegralLattice("D4") sage: D4.discriminant_group() Finite quadratic module over Integer Ring with invariants (2, 2) @@ -508,7 +512,7 @@ def IntegralLatticeGluing(Lattices, glue, return_embeddings=False): sage: E8, psi = IntegralLatticeGluing([D6, L2], [[f1, f2], [g1, g2]], True) sage: D4embed = E8.sublattice(psi[0](phi[0].image()).basis_matrix()) sage: x = D4([1, 0, 0, 0]) - sage: psi[0](phi[0](x)).inner_product(psi[0](phi[0](x)))==x.inner_product(x) + sage: psi[0](phi[0](x)).inner_product(psi[0](phi[0](x))) == x.inner_product(x) True sage: D4embed Lattice of degree 8 and rank 4 over Integer Ring @@ -529,6 +533,7 @@ def IntegralLatticeGluing(Lattices, glue, return_embeddings=False): The input may be a list of three or more lattices:: + sage: # needs sage.graphs sage: A7 = IntegralLattice("A7") sage: D5 = IntegralLattice("D5") sage: gA7 = A7.discriminant_group().gens()[0] @@ -539,16 +544,18 @@ def IntegralLatticeGluing(Lattices, glue, return_embeddings=False): sage: L.determinant() 1 sage: B = phi[0].matrix() - sage: B*L.gram_matrix()*B.transpose()==A7.gram_matrix() + sage: B*L.gram_matrix()*B.transpose() == A7.gram_matrix() True The gluing takes place in the direct sum of the respective ambient spaces:: + sage: # needs sage.graphs sage: L1 = IntegralLattice("D4", [[1, 1, 0, 0], [0, 1, 1, 0]]) sage: L2 = IntegralLattice("E6", [[0, 2, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1]]) sage: [f1, f2] = L1.discriminant_group().gens() sage: [g1, g2] = L2.discriminant_group().gens() - sage: [L, phi] = IntegralLatticeGluing([L1, L2], [[f1, g1], [f2, 2 * g2]], True) + sage: [L, phi] = IntegralLatticeGluing([L1, L2], + ....: [[f1, g1], [f2, 2 * g2]], True) sage: phi[0] Free module morphism defined by the matrix [ 2 2 -2 -1] @@ -580,13 +587,13 @@ def IntegralLatticeGluing(Lattices, glue, return_embeddings=False): [ 0 0 0 0 0 0 0 -1 2 -1] [ 0 0 0 0 0 0 0 0 -1 2] sage: B = phi[0].matrix() - sage: B * L.gram_matrix() * B.transpose()==L1.gram_matrix() + sage: B * L.gram_matrix() * B.transpose() == L1.gram_matrix() True """ [direct_sum, phi] = IntegralLatticeDirectSum(Lattices, return_embeddings=True) N = len(Lattices) for g in glue: - if not len(g)==N: + if not len(g) == N: raise ValueError("the lengths of the lists do not match") for i in range(N): ALi = Lattices[i].discriminant_group() @@ -685,7 +692,7 @@ def _mul_(self, other, switch_sides=False): B = self.basis_matrix() B = other * B if switch_sides else B * other # check whether it is integral - if other in ZZ or other.denominator()==1: + if other in ZZ or other.denominator() == 1: return self.sublattice(B.rows()) else: return self.span(B.rows()) @@ -696,8 +703,8 @@ def _repr_(self): EXAMPLES:: - sage: A2 = IntegralLattice("A2") - sage: A2 + sage: A2 = IntegralLattice("A2") # needs sage.graphs + sage: A2 # needs sage.graphs Lattice of degree 2 and rank 2 over Integer Ring Standard basis Inner product matrix: @@ -728,12 +735,12 @@ def is_even(self): EXAMPLES:: - sage: G = Matrix(ZZ,2,2,[-1,1,1,2]) + sage: G = Matrix(ZZ, 2, 2, [-1,1,1,2]) sage: L = IntegralLattice(G) sage: L.is_even() False - sage: L = IntegralLattice("A2") - sage: L.is_even() + sage: L = IntegralLattice("A2") # needs sage.graphs + sage: L.is_even() # needs sage.graphs True """ return all(d % 2 == 0 for d in self.gram_matrix().diagonal()) @@ -751,9 +758,8 @@ def dual_lattice(self): EXAMPLES:: - sage: L = IntegralLattice("A2") - sage: Ldual=L.dual_lattice() - sage: Ldual + sage: L = IntegralLattice("A2") # needs sage.graphs + sage: Ldual = L.dual_lattice(); Ldual # needs sage.graphs Free module of degree 2 and rank 2 over Integer Ring Echelon basis matrix: [1/3 2/3] @@ -761,7 +767,7 @@ def dual_lattice(self): Since our lattices are always integral, a lattice is contained in its dual:: - sage: L.is_submodule(Ldual) + sage: L.is_submodule(Ldual) # needs sage.graphs True """ return self.span(self.gram_matrix().inverse()*self.basis_matrix()) @@ -781,7 +787,7 @@ def discriminant_group(self, s=0): EXAMPLES:: - sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])*2) + sage: L = IntegralLattice(Matrix(ZZ, 2, 2, [2,1,1,-2]) * 2) sage: L.discriminant_group() Finite quadratic module over Integer Ring with invariants (2, 10) Gram matrix of the quadratic form with values in Q/2Z: @@ -808,14 +814,16 @@ def discriminant_group(self, s=0): Test that the memory leak in :trac:`31625` is fixed:: sage: import gc - sage: L = IntegralLattice("A2") - sage: for k in range(1,500): + sage: gc.freeze() + sage: L = IntegralLattice("A2") # needs sage.graphs + sage: for k in range(1,500): # long time ....: G = L.twist(k) ....: D = G.discriminant_group() sage: tmp = gc.collect() sage: tmp = gc.collect() - sage: len([a for a in gc.get_objects() if type(a)==type(L)])<=300 + sage: len([a for a in gc.get_objects() if type(a) == type(L)]) <= 300 True + sage: gc.unfreeze() """ from sage.modules.torsion_quadratic_module import TorsionQuadraticModule D = TorsionQuadraticModule(self.dual_lattice(), self) @@ -849,9 +857,8 @@ def signature_pair(self): EXAMPLES:: - - sage: A2 = IntegralLattice("A2") - sage: A2.signature_pair() + sage: A2 = IntegralLattice("A2") # needs sage.graphs + sage: A2.signature_pair() # needs sage.graphs (2, 0) """ from sage.quadratic_forms.quadratic_form import QuadraticForm @@ -907,12 +914,12 @@ def is_primitive(self, M): True sage: U.is_primitive(L2) True - sage: U.is_primitive(L1+L2) + sage: U.is_primitive(L1 + L2) False We can also compute the index:: - sage: (L1+L2).index_in(U) + sage: (L1 + L2).index_in(U) 2 """ return (gcd((self/M).invariants()) == 0) @@ -928,7 +935,7 @@ def orthogonal_complement(self, M): EXAMPLES:: - sage: H5 = Matrix(ZZ,2,[2,1,1,-2]) + sage: H5 = Matrix(ZZ, 2, [2,1,1,-2]) sage: L = IntegralLattice(H5) sage: S = L.span([vector([1,1])]) sage: L.orthogonal_complement(S) @@ -940,7 +947,7 @@ def orthogonal_complement(self, M): [ 1 -2] sage: L = IntegralLattice(2) - sage: L.orthogonal_complement([vector(ZZ,[1,0])]) + sage: L.orthogonal_complement([vector(ZZ, [1,0])]) Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [0 1] @@ -969,8 +976,7 @@ def sublattice(self, basis): EXAMPLES:: sage: U = IntegralLattice("U") - sage: S = U.sublattice([vector([1,1])]) - sage: S + sage: S = U.sublattice([vector([1,1])]); S Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [1 1] @@ -1005,7 +1011,7 @@ def overlattice(self, gens): EXAMPLES:: - sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,0,0,2])) + sage: L = IntegralLattice(Matrix(ZZ, 2, 2, [2,0,0,2])) sage: M = L.overlattice([vector([1,1])/2]) sage: M.gram_matrix() [1 1] @@ -1031,6 +1037,7 @@ def maximal_overlattice(self, p=None): EXAMPLES:: + sage: # needs sage.graphs sage: L = IntegralLattice("A4").twist(25*89) sage: L.maximal_overlattice().determinant() 5 @@ -1041,6 +1048,7 @@ def maximal_overlattice(self, p=None): TESTS:: + sage: # needs sage.libs.flint (otherwise timeout) sage: L = IntegralLattice(matrix.diagonal([2,4,4,8])) sage: L.maximal_overlattice().is_even() True @@ -1050,7 +1058,7 @@ def maximal_overlattice(self, p=None): # it might speed up things to use the algorithms given in # https://arxiv.org/abs/1208.2481 # and trac:11940 - if not self.is_even() and (p is None or p==2): + if not self.is_even() and (p is None or p == 2): raise ValueError("this lattice must be even to admit an even overlattice") from sage.rings.finite_rings.finite_field_constructor import GF L = self @@ -1166,9 +1174,8 @@ def orthogonal_group(self, gens=None, is_finite=None): EXAMPLES:: - sage: A4 = IntegralLattice("A4") - sage: Aut = A4.orthogonal_group() - sage: Aut + sage: A4 = IntegralLattice("A4") # needs sage.graphs + sage: Aut = A4.orthogonal_group(); Aut # needs sage.graphs sage.libs.gap Group of isometries with 4 generators ( [0 0 0 1] [-1 -1 -1 0] [ 1 0 0 0] [ 1 0 0 0] [0 0 1 0] [ 0 0 0 -1] [-1 -1 -1 -1] [ 0 1 0 0] @@ -1178,16 +1185,16 @@ def orthogonal_group(self, gens=None, is_finite=None): The group acts from the right on the lattice and its discriminant group:: + sage: # needs sage.graphs sage.libs.gap sage: x = A4.an_element() - sage: g = Aut.an_element() - sage: g + sage: g = Aut.an_element(); g [-1 -1 -1 0] [ 0 0 1 0] [ 0 0 -1 -1] [ 0 1 1 1] sage: x*g (-1, -1, -1, 0) - sage: (x*g).parent()==A4 + sage: (x*g).parent() == A4 True sage: (g*x).parent() Vector space of dimension 4 over Rational Field @@ -1197,6 +1204,7 @@ def orthogonal_group(self, gens=None, is_finite=None): If the group is finite we can compute the usual things:: + sage: # needs sage.graphs sage.libs.gap sage: Aut.order() 240 sage: conj = Aut.conjugacy_classes_representatives() @@ -1207,8 +1215,9 @@ def orthogonal_group(self, gens=None, is_finite=None): The lattice can live in a larger ambient space:: - sage: A2 = IntegralLattice(matrix.identity(3),Matrix(ZZ,2,3,[1,-1,0,0,1,-1])) - sage: A2.orthogonal_group() + sage: A2 = IntegralLattice(matrix.identity(3), + ....: Matrix(ZZ, 2, 3, [1,-1,0,0,1,-1])) + sage: A2.orthogonal_group() # needs sage.libs.gap Group of isometries with 2 generators ( [ 2/3 2/3 -1/3] [1 0 0] [ 2/3 -1/3 2/3] [0 0 1] @@ -1217,25 +1226,26 @@ def orthogonal_group(self, gens=None, is_finite=None): It can be negative definite as well:: - sage: A2m = IntegralLattice(-Matrix(ZZ,2,[2,1,1,2])) - sage: G = A2m.orthogonal_group() - sage: G.order() + sage: A2m = IntegralLattice(-Matrix(ZZ, 2, [2,1,1,2])) + sage: G = A2m.orthogonal_group() # needs sage.libs.gap + sage: G.order() # needs sage.libs.gap 12 If the lattice is indefinite, sage does not know how to compute generators. Can you teach it?:: - sage: U = IntegralLattice(Matrix(ZZ,2,[0,1,1,0])) - sage: U.orthogonal_group() + sage: U = IntegralLattice(Matrix(ZZ, 2, [0,1,1,0])) + sage: U.orthogonal_group() # needs sage.libs.gap Traceback (most recent call last): ... - NotImplementedError: currently, we can only compute generators for orthogonal groups over definite lattices. + NotImplementedError: currently, we can only compute generators + for orthogonal groups over definite lattices. But we can define subgroups:: - sage: S = IntegralLattice(Matrix(ZZ,2,[2, 3, 3, 2])) - sage: f = Matrix(ZZ,2,[0,1,-1,3]) - sage: S.orthogonal_group([f]) + sage: S = IntegralLattice(Matrix(ZZ, 2, [2, 3, 3, 2])) + sage: f = Matrix(ZZ, 2, [0,1,-1,3]) + sage: S.orthogonal_group([f]) # needs sage.libs.gap Group of isometries with 1 generator ( [ 0 1] [-1 3] @@ -1245,8 +1255,8 @@ def orthogonal_group(self, gens=None, is_finite=None): We can handle the trivial group:: - sage: S = IntegralLattice(Matrix(ZZ,2,[2, 3, 3, 2])) - sage: S.orthogonal_group([]) + sage: S = IntegralLattice(Matrix(ZZ, 2, [2, 3, 3, 2])) + sage: S.orthogonal_group([]) # needs sage.libs.gap Group of isometries with 1 generator ( [1 0] [0 1] @@ -1296,7 +1306,7 @@ def orthogonal_group(self, gens=None, is_finite=None): invariant_quotient_module=D) return G - automorphisms=orthogonal_group + automorphisms = orthogonal_group def genus(self): r""" @@ -1305,7 +1315,7 @@ def genus(self): EXAMPLES:: sage: L = IntegralLattice("U") - sage: L.genus() + sage: L.genus() # needs sage.padics Genus of [0 1] [1 0] @@ -1323,14 +1333,13 @@ def tensor_product(self, other, discard_basis=False): - ``other`` -- an integral lattice - ``discard_basis`` -- a boolean (default: ``False``). If ``True``, then the lattice - returned is equipped with the standard basis. + returned is equipped with the standard basis. EXAMPLES:: + sage: # needs sage.graphs sage: L = IntegralLattice("D3", [[1,-1,0], [0,1,-1]]) - sage: L1 = L.tensor_product(L) - sage: L2 = L.tensor_product(L, True) - sage: L1 + sage: L1 = L.tensor_product(L); L1 Lattice of degree 9 and rank 4 over Integer Ring Basis matrix: [ 1 -1 0 -1 1 0 0 0 0] @@ -1352,7 +1361,7 @@ def tensor_product(self, other, discard_basis=False): [-12 24 4 -8] [-12 4 24 -8] [ 4 -8 -8 16] - sage: L2 + sage: L2 = L.tensor_product(L, True); L2 Lattice of degree 4 and rank 4 over Integer Ring Standard basis Inner product matrix: @@ -1383,13 +1392,13 @@ def quadratic_form(self): EXAMPLES:: - sage: L = IntegralLattice("A2") - sage: q = L.quadratic_form() - sage: q + sage: L = IntegralLattice("A2") # needs sage.graphs + sage: q = L.quadratic_form(); q # needs sage.graphs Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 -2 ] [ * 2 ] """ + from sage.quadratic_forms.quadratic_form import QuadraticForm return QuadraticForm(2 * self.gram_matrix()) @cached_method @@ -1403,10 +1412,10 @@ def minimum(self): EXAMPLES:: - sage: L = IntegralLattice('A2') - sage: L.minimum() + sage: L = IntegralLattice('A2') # needs sage.graphs + sage: L.minimum() # needs sage.graphs 2 - sage: L.twist(-1).minimum() + sage: L.twist(-1).minimum() # needs sage.graphs -Infinity """ p, n = self.signature_pair() @@ -1429,10 +1438,10 @@ def maximum(self): EXAMPLES:: - sage: L = IntegralLattice('A2') - sage: L.maximum() + sage: L = IntegralLattice('A2') # needs sage.graphs + sage: L.maximum() # needs sage.graphs +Infinity - sage: L.twist(-1).maximum() + sage: L.twist(-1).maximum() # needs sage.graphs -2 """ if self.rank() == 0: @@ -1453,13 +1462,14 @@ def LLL(self): EXAMPLES:: - sage: L = IntegralLattice('A2') - sage: L.lll() == L + sage: L = IntegralLattice('A2') # needs sage.graphs + sage: L.lll() == L # needs sage.graphs True - sage: G = matrix(ZZ,3,[0,1,0, 1,0,0, 0,0,7]) - sage: V = matrix(ZZ,3,[-14,-15,-15, -4,1,16, -5,-5,-4]) + + sage: G = matrix(ZZ, 3, [0,1,0, 1,0,0, 0,0,7]) + sage: V = matrix(ZZ, 3, [-14,-15,-15, -4,1,16, -5,-5,-4]) sage: L = IntegralLattice(V * G * V.T) - sage: L.lll().gram_matrix() + sage: L.lll().gram_matrix() # needs sage.libs.gap [0 0 1] [0 7 0] [1 0 0] @@ -1471,7 +1481,7 @@ def LLL(self): from sage.libs.pari import pari m = self.gram_matrix().__pari__() gp.read(SAGE_EXTCODE + "/pari/simon/qfsolve.gp") - m = gp.eval('qflllgram_indefgoon(%s)'%m) + m = gp.eval('qflllgram_indefgoon(%s)' % m) # convert the output string to sage G, U = pari(m).sage() U = U.T @@ -1491,7 +1501,7 @@ def short_vectors(self, n, **kwargs): INPUT: - ``n`` -- an integer - - further key word arguments are passed on to + - further keyword arguments are passed on to :meth:`sage.quadratic_forms.short_vector_list_up_to_length`. OUTPUT: @@ -1500,10 +1510,10 @@ def short_vectors(self, n, **kwargs): EXAMPLES:: - sage: A2 = IntegralLattice('A2') - sage: A2.short_vectors(3) + sage: A2 = IntegralLattice('A2') # needs sage.graphs + sage: A2.short_vectors(3) # needs sage.graphs [[(0, 0)], [], [(1, 1), (-1, -1), (0, 1), (0, -1), (1, 0), (-1, 0)]] - sage: A2.short_vectors(3,up_to_sign_flag=True) + sage: A2.short_vectors(3,up_to_sign_flag=True) # needs sage.graphs [[(0, 0)], [], [(1, 1), (0, 1), (1, 0)]] """ p, m = self.signature_pair() @@ -1512,6 +1522,7 @@ def short_vectors(self, n, **kwargs): e = 2 if m != 0: e = -2 + from sage.quadratic_forms.quadratic_form import QuadraticForm q = QuadraticForm(e * self.gram_matrix()) short = q.short_vector_list_up_to_length(n, *kwargs) return [[self(v * self.basis_matrix()) for v in L] for L in short] @@ -1529,8 +1540,8 @@ def twist(self, s, discard_basis=False): EXAMPLES:: - sage: L = IntegralLattice("A4") - sage: L.twist(3) + sage: L = IntegralLattice("A4") # needs sage.graphs + sage: L.twist(3) # needs sage.graphs Lattice of degree 4 and rank 4 over Integer Ring Standard basis Inner product matrix: @@ -1538,8 +1549,7 @@ def twist(self, s, discard_basis=False): [-3 6 -3 0] [ 0 -3 6 -3] [ 0 0 -3 6] - sage: L = IntegralLattice(3,[[2,1,0],[0,1,1]]) - sage: L + sage: L = IntegralLattice(3, [[2,1,0], [0,1,1]]); L Lattice of degree 3 and rank 2 over Integer Ring Basis matrix: [2 1 0] @@ -1562,7 +1572,7 @@ def twist(self, s, discard_basis=False): s = self.base_ring()(s) except TypeError: raise ValueError("the scaling factor must be an element of the base ring.") - if s==0: + if s == 0: raise ValueError("the scaling factor must be non zero") if discard_basis: return IntegralLattice(s * self.gram_matrix()) @@ -1581,8 +1591,7 @@ def local_modification(M, G, p, check=True): - ``M`` -- a `\ZZ_p`-maximal lattice - - ``G`` -- the gram matrix of a lattice - isomorphic to `M` over `\QQ_p` + - ``G`` -- the gram matrix of a lattice isomorphic to `M` over `\QQ_p` - ``p`` -- a prime number @@ -1593,6 +1602,7 @@ def local_modification(M, G, p, check=True): EXAMPLES:: + sage: # needs sage.graphs sage: from sage.modules.free_quadratic_module_integer_symmetric import local_modification sage: L = IntegralLattice("A3").twist(15) sage: M = L.maximal_overlattice() diff --git a/src/sage/modules/matrix_morphism.py b/src/sage/modules/matrix_morphism.py index 94069fcc603..b9d45e9755f 100644 --- a/src/sage/modules/matrix_morphism.py +++ b/src/sage/modules/matrix_morphism.py @@ -21,13 +21,13 @@ [0 0 1] sage: is_MatrixMorphism(m) True - sage: m.charpoly('x') + sage: m.charpoly('x') # needs sage.libs.pari x^3 - 3*x^2 + 3*x - 1 sage: m.base_ring() Rational Field sage: m.det() 1 - sage: m.fcp('x') + sage: m.fcp('x') # needs sage.libs.pari (x - 1)^3 sage: m.matrix() [1 0 0] @@ -188,7 +188,7 @@ def _call_(self, x): if parent(x) is not self.domain(): x = self.domain()(x) except TypeError: - raise TypeError("%s must be coercible into %s"%(x,self.domain())) + raise TypeError("%s must be coercible into %s" % (x,self.domain())) if self.domain().is_ambient(): x = x.element() else: @@ -523,6 +523,8 @@ def __mul__(self, right): Composite maps can be formed with matrix morphisms:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23) sage: V, VtoK, KtoV = K.vector_space() sage: f = V.hom([V.0 - V.1, V.0 + V.1])*KtoV; f @@ -835,7 +837,7 @@ def decomposition(self, *args, **kwds): EXAMPLES:: sage: V = ZZ^2; phi = V.hom([V.0+V.1, 2*V.1]) - sage: phi.decomposition() + sage: phi.decomposition() # needs sage.libs.pari [ Free module of degree 2 and rank 1 over Integer Ring Echelon basis matrix: @@ -845,7 +847,7 @@ def decomposition(self, *args, **kwds): [ 1 -1] ] sage: phi2 = V.hom(phi.matrix(), side="right") - sage: phi2.decomposition() + sage: phi2.decomposition() # needs sage.libs.pari [ Free module of degree 2 and rank 1 over Integer Ring Echelon basis matrix: @@ -904,10 +906,10 @@ def fcp(self, var='x'): EXAMPLES:: - sage: V = ZZ^2; phi = V.hom([V.0+V.1, 2*V.1]) - sage: phi.fcp() + sage: V = ZZ^2; phi = V.hom([V.0 + V.1, 2*V.1]) + sage: phi.fcp() # needs sage.libs.pari (x - 2) * (x - 1) - sage: phi.fcp('T') + sage: phi.fcp('T') # needs sage.libs.pari (T - 2) * (T - 1) """ return self.charpoly(var).factor() @@ -1740,7 +1742,7 @@ def is_surjective(self): An example over a PID that is not `\ZZ`. :: - sage: R = PolynomialRing(QQ, 'x') + sage: R.<x> = PolynomialRing(QQ) sage: A = R^2 sage: B = R^2 sage: H = A.hom([B([x^2-1, 1]), B([x^2, 1])]) diff --git a/src/sage/modules/module.pyx b/src/sage/modules/module.pyx index 180222b8b18..818d139c3ba 100644 --- a/src/sage/modules/module.pyx +++ b/src/sage/modules/module.pyx @@ -27,7 +27,8 @@ A minimal example of a module:: ....: def _repr_(self): ....: return repr(self.x) - sage: class MyModule(sage.modules.module.Module): + sage: from sage.modules.module import Module + sage: class MyModule(Module): ....: Element = MyElement ....: def _element_constructor_(self, x): ....: if isinstance(x, MyElement): x = x.x @@ -106,6 +107,7 @@ cdef class Module(Parent): We check that :trac:`8119` has been resolved:: + sage: # needs sage.modules sage: M = ZZ^3 sage: h = M.__hash__() sage: M.rename('toto') @@ -161,7 +163,7 @@ cdef class Module(Parent): Make sure :trac:`3638` is fixed:: - sage: vector(ZZ,[1,2,11])==vector(Zmod(8),[1,2,3]) + sage: vector(ZZ,[1,2,11]) == vector(Zmod(8),[1,2,3]) # needs sage.modules True AUTHORS: @@ -186,7 +188,9 @@ cdef class Module(Parent): EXAMPLES:: - sage: sage.modular.modform.space.ModularFormsSpace(Gamma0(11), 2, DirichletGroup(1)[0], QQ).change_ring(GF(7)) + sage: from sage.modular.modform.space import ModularFormsSpace # needs sage.modular + sage: ModularFormsSpace(Gamma0(11), 2, # needs sage.modular sage.rings.finite_rings + ....: DirichletGroup(1)[0], QQ).change_ring(GF(7)) Traceback (most recent call last): ... NotImplementedError: the method change_ring() has not yet been implemented @@ -210,32 +214,38 @@ cdef class Module(Parent): EXAMPLES:: - sage: V = ZZ^7 - sage: V.base_extend(QQ) + sage: V = ZZ^7 # needs sage.modules + sage: V.base_extend(QQ) # needs sage.modules Vector space of dimension 7 over Rational Field TESTS:: - sage: N = ModularForms(6, 4) - sage: N.base_extend(CyclotomicField(7)) - Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Cyclotomic Field of order 7 and degree 6 + sage: N = ModularForms(6, 4) # needs sage.modular + sage: N.base_extend(CyclotomicField(7)) # needs sage.modular sage.rings.number_field + Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) + of weight 4 over Cyclotomic Field of order 7 and degree 6 - sage: m = ModularForms(DirichletGroup(13).0^2,2); m - Modular Forms space of dimension 3, character [zeta6] and weight 2 over Cyclotomic Field of order 6 and degree 2 - sage: m.base_extend(CyclotomicField(12)) - Modular Forms space of dimension 3, character [zeta6] and weight 2 over Cyclotomic Field of order 12 and degree 4 + sage: m = ModularForms(DirichletGroup(13).0^2,2); m # needs sage.modular sage.rings.number_field + Modular Forms space of dimension 3, character [zeta6] and weight 2 + over Cyclotomic Field of order 6 and degree 2 + sage: m.base_extend(CyclotomicField(12)) # needs sage.modular sage.rings.number_field + Modular Forms space of dimension 3, character [zeta6] and weight 2 + over Cyclotomic Field of order 12 and degree 4 + sage: # needs sage.modular sage.rings.number_field sage: chi = DirichletGroup(109, CyclotomicField(3)).0 sage: S3 = CuspForms(chi, 2) - sage: S9 = S3.base_extend(CyclotomicField(9)) - sage: S9 - Cuspidal subspace of dimension 8 of Modular Forms space of dimension 10, character [zeta3 + 1] and weight 2 over Cyclotomic Field of order 9 and degree 6 - sage: S9.has_coerce_map_from(S3) # not implemented + sage: S9 = S3.base_extend(CyclotomicField(9)); S9 + Cuspidal subspace of dimension 8 of + Modular Forms space of dimension 10, character [zeta3 + 1] and weight 2 + over Cyclotomic Field of order 9 and degree 6 + sage: S9.has_coerce_map_from(S3) # not implemented True sage: S9.base_extend(CyclotomicField(3)) Traceback (most recent call last): ... - TypeError: Base extension of self (over 'Cyclotomic Field of order 9 and degree 6') to ring 'Cyclotomic Field of order 3 and degree 2' not defined. + TypeError: Base extension of self (over 'Cyclotomic Field of order 9 and degree 6') + to ring 'Cyclotomic Field of order 3 and degree 2' not defined. """ if R.has_coerce_map_from(self.base_ring()): @@ -252,7 +262,10 @@ cdef class Module(Parent): sage: from sage.modules.module import Module sage: M = Module(ZZ) sage: M.endomorphism_ring() - Set of Morphisms from <sage.modules.module.Module object at ...> to <sage.modules.module.Module object at ...> in Category of modules over Integer Ring + Set of Morphisms + from <sage.modules.module.Module object at ...> + to <sage.modules.module.Module object at ...> + in Category of modules over Integer Ring """ from sage.categories.homset import End return End(self) @@ -268,8 +281,8 @@ def is_Module(x): EXAMPLES:: sage: from sage.modules.module import is_Module - sage: M = FreeModule(RationalField(),30) - sage: is_Module(M) + sage: M = FreeModule(RationalField(),30) # needs sage.modules + sage: is_Module(M) # needs sage.modules True sage: is_Module(10) False @@ -287,6 +300,7 @@ def is_VectorSpace(x): EXAMPLES:: + sage: # needs sage.modules sage: from sage.modules.module import is_Module, is_VectorSpace sage: M = FreeModule(RationalField(),30) sage: is_VectorSpace(M) diff --git a/src/sage/modules/multi_filtered_vector_space.py b/src/sage/modules/multi_filtered_vector_space.py index e3f551b9e4b..beb46762361 100644 --- a/src/sage/modules/multi_filtered_vector_space.py +++ b/src/sage/modules/multi_filtered_vector_space.py @@ -490,7 +490,7 @@ def __eq__(self, other): sage: V == MultiFilteredVectorSpace({'a':F1, 'b':F2}) False """ - if type(self) != type(other): + if type(self) is not type(other): return False return self._filt == other._filt diff --git a/src/sage/modules/quotient_module.py b/src/sage/modules/quotient_module.py index 10db2189997..c50c1d044fc 100644 --- a/src/sage/modules/quotient_module.py +++ b/src/sage/modules/quotient_module.py @@ -163,12 +163,13 @@ def _coerce_map_from_(self, M): sage: Q.coerce_map_from(M) Coercion map: From: Ambient free module of rank 2 over the integral domain - Multivariate Polynomial Ring in x, y, z over Rational Field - To: Quotient module by Submodule of Ambient free module of rank 2 - over the integral domain Multivariate Polynomial Ring in x, y, z over Rational Field - Generated by the rows of the matrix: - [x - y z] - [ y*z x*z] + Multivariate Polynomial Ring in x, y, z over Rational Field + To: Quotient module by Submodule of + Ambient free module of rank 2 over the integral domain + Multivariate Polynomial Ring in x, y, z over Rational Field + Generated by the rows of the matrix: + [x - y z] + [ y*z x*z] """ if isinstance(M, FreeModule_ambient): return (self.base_ring().has_coerce_map_from(M.base_ring()) and @@ -277,7 +278,8 @@ def free_relations(self): sage: NQ = Q.submodule([Q([1, x])]) sage: QNQ = Q / NQ sage: QNQ.free_relations() - Submodule of Ambient free module of rank 2 over the integral domain Multivariate Polynomial Ring in x, y, z over Rational Field + Submodule of Ambient free module of rank 2 over the integral domain + Multivariate Polynomial Ring in x, y, z over Rational Field Generated by the rows of the matrix: [ 1 x] [x - y z] @@ -307,43 +309,53 @@ class FreeModule_ambient_field_quotient(FreeModule_ambient_field): EXAMPLES:: + sage: # needs sage.rings.number_field sage: k.<i> = QuadraticField(-1) sage: A = k^3; V = A.span([[1,0,i], [2,i,0]]) sage: W = A.span([[3,i,i]]) sage: U = V/W; U - Vector space quotient V/W of dimension 1 over Number Field in i with defining polynomial x^2 + 1 with i = 1*I where - V: Vector space of degree 3 and dimension 2 over Number Field in i with defining polynomial x^2 + 1 with i = 1*I - Basis matrix: - [ 1 0 i] - [ 0 1 -2] - W: Vector space of degree 3 and dimension 1 over Number Field in i with defining polynomial x^2 + 1 with i = 1*I - Basis matrix: - [ 1 1/3*i 1/3*i] + Vector space quotient V/W of dimension 1 over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I where + V: Vector space of degree 3 and dimension 2 over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I + Basis matrix: + [ 1 0 i] + [ 0 1 -2] + W: Vector space of degree 3 and dimension 1 over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I + Basis matrix: + [ 1 1/3*i 1/3*i] sage: U.V() - Vector space of degree 3 and dimension 2 over Number Field in i with defining polynomial x^2 + 1 with i = 1*I - Basis matrix: - [ 1 0 i] - [ 0 1 -2] + Vector space of degree 3 and dimension 2 over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I + Basis matrix: + [ 1 0 i] + [ 0 1 -2] sage: U.W() - Vector space of degree 3 and dimension 1 over Number Field in i with defining polynomial x^2 + 1 with i = 1*I - Basis matrix: - [ 1 1/3*i 1/3*i] + Vector space of degree 3 and dimension 1 over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I + Basis matrix: + [ 1 1/3*i 1/3*i] sage: U.quotient_map() Vector space morphism represented by the matrix: [ 1] [3*i] - Domain: Vector space of degree 3 and dimension 2 over Number Field in i with defining polynomial x^2 + 1 with i = 1*I - Basis matrix: - [ 1 0 i] - [ 0 1 -2] - Codomain: Vector space quotient V/W of dimension 1 over Number Field in i with defining polynomial x^2 + 1 with i = 1*I where - V: Vector space of degree 3 and dimension 2 over Number Field in i with defining polynomial x^2 + 1 with i = 1*I - Basis matrix: - [ 1 0 i] - [ 0 1 -2] - W: Vector space of degree 3 and dimension 1 over Number Field in i with defining polynomial x^2 + 1 with i = 1*I - Basis matrix: - [ 1 1/3*i 1/3*i] + Domain: Vector space of degree 3 and dimension 2 over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I + Basis matrix: + [ 1 0 i] + [ 0 1 -2] + Codomain: Vector space quotient V/W of dimension 1 over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I where + V: Vector space of degree 3 and dimension 2 over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I + Basis matrix: + [ 1 0 i] + [ 0 1 -2] + W: Vector space of degree 3 and dimension 1 over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I + Basis matrix: + [ 1 1/3*i 1/3*i] sage: Z = V.quotient(W) sage: Z == U True @@ -366,7 +378,7 @@ class FreeModule_ambient_field_quotient(FreeModule_ambient_field): TESTS:: - sage: A = QQ^0; V = A.span([]) # corner case + sage: A = QQ^0; V = A.span([]) # corner case sage: W = A.span([]) sage: U = V/W @@ -432,19 +444,20 @@ def _repr_(self): We create a quotient vector space over a finite field:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(9); A = k^3; V = A.span_of_basis([[1,0,a], [a,a,1]]); W = V.span([V.1]) sage: Q = V/W Note the type:: - sage: type(Q) + sage: type(Q) # needs sage.rings.finite_rings <class 'sage.modules.quotient_module.FreeModule_ambient_field_quotient_with_category'> The string representation mentions that this is a quotient `V/W`, that the quotient has dimension 1 and is over a finite field, and also describes `V` and `W`:: - sage: Q._repr_() + sage: Q._repr_() # needs sage.rings.finite_rings 'Vector space quotient V/W of dimension 1 over Finite Field in a of size 3^2 where\nV: Vector space of degree 3 and dimension 2 over Finite Field in a of size 3^2\nUser basis matrix:\n[1 0 a]\n[a a 1]\nW: Vector space of degree 3 and dimension 1 over Finite Field in a of size 3^2\nBasis matrix:\n[ 1 1 a + 2]' """ return "%s space quotient V/W of dimension %s over %s where\nV: %s\nW: %s" % ( @@ -539,23 +552,23 @@ def _coerce_map_from_(self, M): Composite map: From: Ambient free module of rank 2 over the principal ideal domain Integer Ring To: Vector space quotient V/W of dimension 1 over Rational Field where - V: Vector space of dimension 2 over Rational Field - W: Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 2] + V: Vector space of dimension 2 over Rational Field + W: Vector space of degree 2 and dimension 1 over Rational Field + Basis matrix: + [1 2] Defn: Coercion map: From: Ambient free module of rank 2 over the principal ideal domain Integer Ring To: Vector space of dimension 2 over Rational Field then Vector space morphism represented by the matrix: - [ 1] - [-1/2] - Domain: Vector space of dimension 2 over Rational Field - Codomain: Vector space quotient V/W of dimension 1 over Rational Field where - V: Vector space of dimension 2 over Rational Field - W: Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 2] + [ 1] + [-1/2] + Domain: Vector space of dimension 2 over Rational Field + Codomain: Vector space quotient V/W of dimension 1 over Rational Field where + V: Vector space of dimension 2 over Rational Field + W: Vector space of degree 2 and dimension 1 over Rational Field + Basis matrix: + [1 2] Make sure :trac:`10513` is fixed (no coercion from an abstract vector space to an isomorphic quotient vector space):: @@ -592,12 +605,12 @@ def quotient_map(self): [ 1 0] [ 0 1] [-1/3 -2/3] - Domain: Vector space of dimension 3 over Rational Field + Domain: Vector space of dimension 3 over Rational Field Codomain: Vector space quotient V/W of dimension 2 over Rational Field where - V: Vector space of dimension 3 over Rational Field - W: Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [1 2 3] + V: Vector space of dimension 3 over Rational Field + W: Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: + [1 2 3] sage: M.quotient_map()( (QQ^3)([1,2,3]) ) (0, 0) @@ -616,11 +629,11 @@ def lift_map(self): Vector space morphism represented by the matrix: [1 0 0] [0 1 0] - Domain: Vector space quotient V/W of dimension 2 over Rational Field where - V: Vector space of dimension 3 over Rational Field - W: Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [1 2 3] + Domain: Vector space quotient V/W of dimension 2 over Rational Field where + V: Vector space of dimension 3 over Rational Field + W: Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: + [1 2 3] Codomain: Vector space of dimension 3 over Rational Field """ return self.__lift_map diff --git a/src/sage/modules/submodule.py b/src/sage/modules/submodule.py index 4e0d6994f02..3ab5a195f49 100644 --- a/src/sage/modules/submodule.py +++ b/src/sage/modules/submodule.py @@ -165,7 +165,7 @@ def matrix(self): """ from sage.matrix.matrix_space import MatrixSpace MAT = MatrixSpace(self.base_ring(), len(self.gens()), self.degree(), - sparse = self.is_sparse()) + sparse=self.is_sparse()) A = MAT(self.gens()) A.set_immutable() return A diff --git a/src/sage/modules/tensor_operations.py b/src/sage/modules/tensor_operations.py index fafd5cc3a89..91ec0d83e07 100644 --- a/src/sage/modules/tensor_operations.py +++ b/src/sage/modules/tensor_operations.py @@ -60,7 +60,7 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - +from itertools import product from collections import defaultdict from sage.modules.free_module import FreeModule_ambient_field @@ -90,12 +90,11 @@ def symmetrized_coordinate_sums(dim, n): ((0, 0), (0, 1) + (1, 0), (1, 1)) """ from sage.structure.formal_sum import FormalSum - from sage.categories.cartesian_product import cartesian_product coordinates = [list(range(dim)) for i in range(n)] table = defaultdict(list) - for i in cartesian_product(coordinates): + for i in product(*coordinates): sort_i = tuple(sorted(i)) table[sort_i].append([1, tuple(i)]) @@ -119,7 +118,7 @@ def antisymmetrized_coordinate_sums(dim, n): EXAMPLES:: sage: from sage.modules.tensor_operations import antisymmetrized_coordinate_sums - sage: antisymmetrized_coordinate_sums(3, 2) + sage: antisymmetrized_coordinate_sums(3, 2) # needs sage.groups ((0, 1) - (1, 0), (0, 2) - (2, 0), (1, 2) - (2, 1)) """ from sage.structure.formal_sum import FormalSum @@ -344,11 +343,7 @@ def _init_product_vectors(self, i): """ # Pick out the i[j]-th vector rays = [list(self._V[j].vectors()[k]) for j, k in enumerate(i)] - v = [] - # Note: convert to list, as cartesian_product of vectors is unrelated - from sage.categories.cartesian_product import cartesian_product - for r in cartesian_product(rays): - v.append(prod(r)) # build up the tensor product + v = [prod(r) for r in product(*rays)] # build up the tensor product v = tuple(v) # Use index of pre-existing tensor product vector if there is one try: @@ -379,8 +374,8 @@ def _init_power_operation_vectors(self, i, linear_combinations): sage: Sym2_R = TensorOperation([R,R], operation='symmetric') sage: Sym2_R.vectors() # indirect doctest ((1, 0, 0), (1, 2, 0), (-1, -2, 0), (1, 4, 4), (-1, -4, -4)) - sage: Alt2_R = TensorOperation([R, R], operation='antisymmetric') - sage: Alt2_R.vectors() # indirect doctest + sage: Alt2_R = TensorOperation([R, R], operation='antisymmetric') # needs sage.groups + sage: Alt2_R.vectors() # indirect doctest # needs sage.groups ((2), (-2)) """ rays = [self._V[j].vectors()[k] for j, k in enumerate(i)] @@ -415,8 +410,7 @@ def _init_product(self): [((0, 0), 0), ((0, 1), 1), ((1, 0), 2), ((1, 1), 3), ((2, 0), 3), ((2, 1), 2)] """ V_list_indices = [list(range(V.n_vectors())) for V in self._V] - from sage.categories.cartesian_product import cartesian_product - for i in cartesian_product(V_list_indices): + for i in product(*V_list_indices): self._index_map[tuple(i)] = self._init_product_vectors(i) self._symmetrize_indices = False @@ -433,12 +427,11 @@ def _init_symmetric(self): sage: sorted(Sym2_R._index_map.items()) [((0, 0), 0), ((0, 1), 1), ((0, 2), 2), ((1, 1), 3), ((1, 2), 4), ((2, 2), 3)] """ - from sage.categories.cartesian_product import cartesian_product V_list_indices = [list(range(V.n_vectors())) for V in self._V] Sym = symmetrized_coordinate_sums(self._V[0].dimension(), len(self._V)) N = len(V_list_indices) - for i in cartesian_product(V_list_indices): + for i in product(*V_list_indices): if any(i[j - 1] > i[j] for j in range(1, N)): continue self._index_map[tuple(i)] = self._init_power_operation_vectors(i, Sym) @@ -453,8 +446,8 @@ def _init_antisymmetric(self): sage: from sage.modules.tensor_operations import \ ....: VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (1,2), (-1,-2)], QQ, 2) - sage: Alt2_R = TensorOperation([R, R], operation='antisymmetric') # indirect doctest - sage: sorted(Alt2_R._index_map.items()) + sage: Alt2_R = TensorOperation([R, R], operation='antisymmetric') # indirect doctest # needs sage.groups + sage: sorted(Alt2_R._index_map.items()) # needs sage.groups [((0, 1), 0), ((0, 2), 1)] """ n = len(self._V) @@ -517,17 +510,17 @@ def index_map(self, *i): sage: from sage.modules.tensor_operations import \ ....: VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (0,1), (-2,-3)], QQ, 2) - sage: detR = TensorOperation([R]*2, 'antisymmetric') - sage: detR.index_map(1, 0) + sage: detR = TensorOperation([R]*2, 'antisymmetric') # needs sage.groups + sage: detR.index_map(1, 0) # needs sage.groups 0 - sage: detR.index_map(0, 1) + sage: detR.index_map(0, 1) # needs sage.groups 0 TESTS:: - sage: sorted(detR._index_map.items()) + sage: sorted(detR._index_map.items()) # needs sage.groups [((0, 1), 0), ((0, 2), 1), ((1, 2), 2)] - sage: detR.vectors() + sage: detR.vectors() # needs sage.groups ((1), (-3), (2)) """ if len(i) == 1 and isinstance(i[0], (list, tuple)): @@ -553,10 +546,10 @@ def preimage(self): sage: from sage.modules.tensor_operations import \ ....: VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (0,1), (-2,-3)], QQ, 2) - sage: detR = TensorOperation([R]*2, 'antisymmetric') - sage: sorted(detR.preimage()) + sage: detR = TensorOperation([R]*2, 'antisymmetric') # needs sage.groups + sage: sorted(detR.preimage()) # needs sage.groups [(0, 1), (0, 2), (1, 2)] - sage: sorted(detR.codomain()) + sage: sorted(detR.codomain()) # needs sage.groups [0, 1, 2] """ return self._index_map.keys() @@ -574,10 +567,10 @@ def codomain(self): sage: from sage.modules.tensor_operations import \ ....: VectorCollection, TensorOperation sage: R = VectorCollection([(1,0), (0,1), (-2,-3)], QQ, 2) - sage: detR = TensorOperation([R]*2, 'antisymmetric') - sage: sorted(detR.preimage()) + sage: detR = TensorOperation([R]*2, 'antisymmetric') # needs sage.groups + sage: sorted(detR.preimage()) # needs sage.groups [(0, 1), (0, 2), (1, 2)] - sage: sorted(detR.codomain()) + sage: sorted(detR.codomain()) # needs sage.groups [0, 1, 2] """ return self._index_map.values() diff --git a/src/sage/modules/torsion_quadratic_module.py b/src/sage/modules/torsion_quadratic_module.py index 45a6699a0cc..b98e6f89c4b 100644 --- a/src/sage/modules/torsion_quadratic_module.py +++ b/src/sage/modules/torsion_quadratic_module.py @@ -21,7 +21,6 @@ from sage.modules.free_quadratic_module import FreeQuadraticModule from sage.arith.misc import gcd from sage.rings.integer_ring import ZZ -from sage.rings.padics.factory import Zp from sage.rings.rational_field import QQ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.groups.additive_abelian.qmodnz import QmodnZ @@ -47,7 +46,7 @@ def TorsionQuadraticForm(q): EXAMPLES:: - sage: q1 = Matrix(QQ,2,[1,1/2,1/2,1]) + sage: q1 = Matrix(QQ, 2, [1,1/2,1/2,1]) sage: TorsionQuadraticForm(q1) Finite quadratic module over Integer Ring with invariants (2, 2) Gram matrix of the quadratic form with values in Q/2Z: @@ -57,7 +56,7 @@ def TorsionQuadraticForm(q): In the following example the quadratic form is degenerate. But the bilinear form is still non-degenerate:: - sage: q2 = diagonal_matrix(QQ,[1/4,1/3]) + sage: q2 = diagonal_matrix(QQ, [1/4,1/3]) sage: TorsionQuadraticForm(q2) Finite quadratic module over Integer Ring with invariants (12,) Gram matrix of the quadratic form with values in Q/Z: @@ -112,7 +111,7 @@ class TorsionQuadraticModuleElement(FGP_Element): sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) sage: b = V.basis() - sage: W = V.span([2*b[0]+4*b[1], 9*b[0]+12*b[1], 4*b[2]]) + sage: W = V.span([2*b[0] + 4*b[1], 9*b[0] + 12*b[1], 4*b[2]]) sage: Q = TorsionQuadraticModule(V, W) sage: x = Q(b[0] - b[1]) sage: TestSuite(x).run() @@ -132,10 +131,9 @@ def _mul_(self, other): sage: V = (1/2)*ZZ^2; W = ZZ^2 sage: T = TorsionQuadraticModule(V, W) sage: g = T.gens() - sage: x = g[0] - sage: y = g[0] + g[1] - sage: x + sage: x = g[0]; x (1, 0) + sage: y = g[0] + g[1] sage: x*y 1/4 @@ -154,7 +152,7 @@ def _mul_(self, other): def quadratic_product(self): r""" - Compute the quadratic_product of ``self``. + Compute the quadratic product of ``self``. OUTPUT: @@ -190,7 +188,7 @@ class TorsionQuadraticModule(FGP_Module_class, CachedRepresentation): r""" Finite quotients with a bilinear and a quadratic form. - Let `V` be a symmetric FreeQuadraticModule and `W \subseteq V` a + Let `V` be a symmetric :class:`FreeQuadraticModule` and `W \subseteq V` a submodule of the same rank as `V`. The quotient `V / W` is a torsion quadratic module. It inherits a bilinear form `b` and a quadratic form `q`. @@ -218,8 +216,7 @@ class TorsionQuadraticModule(FGP_Module_class, CachedRepresentation): sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = FreeModule(ZZ, 3) - sage: T = TorsionQuadraticModule(V, 5*V) - sage: T + sage: T = TorsionQuadraticModule(V, 5*V); T Finite quadratic module over Integer Ring with invariants (5, 5, 5) Gram matrix of the quadratic form with values in Q/5Z: [1 0 0] @@ -306,8 +303,8 @@ def _repr_(self): EXAMPLES:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: V = FreeModule(ZZ,3) - sage: T = TorsionQuadraticModule(V, 5*V,modulus=1) + sage: V = FreeModule(ZZ, 3) + sage: T = TorsionQuadraticModule(V, 5*V, modulus=1) sage: T Finite quadratic module over Integer Ring with invariants (5, 5, 5) Gram matrix of the quadratic form with values in Q/Z: @@ -344,13 +341,13 @@ def _module_constructor(self, V, W, check=False): sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) sage: b = V.basis() - sage: W = V.span([2*b[0]+4*b[1], 9*b[0]+12*b[1], 4*b[2]]) + sage: W = V.span([2*b[0] + 4*b[1], 9*b[0] + 12*b[1], 4*b[2]]) sage: Q = TorsionQuadraticModule(V, W); Q Finite quadratic module over Integer Ring with invariants (4, 12) Gram matrix of the quadratic form with values in Q/(1/4)Z: [0 0] [0 0] - sage: Q._module_constructor(V,W) + sage: Q._module_constructor(V, W) Finite quadratic module over Integer Ring with invariants (4, 12) Gram matrix of the quadratic form with values in Q/(1/4)Z: [0 0] @@ -377,8 +374,8 @@ def all_submodules(self): EXAMPLES:: - sage: D = IntegralLattice("D4").discriminant_group() - sage: D.all_submodules() + sage: D = IntegralLattice("D4").discriminant_group() # needs sage.combinat + sage: D.all_submodules() # needs sage.combinat [Finite quadratic module over Integer Ring with invariants () Gram matrix of the quadratic form with values in Q/2Z: [], @@ -431,15 +428,15 @@ def brown_invariant(self): EXAMPLES:: - sage: L = IntegralLattice("D4") - sage: D = L.discriminant_group() - sage: D.brown_invariant() + sage: L = IntegralLattice("D4") # needs sage.combinat + sage: D = L.discriminant_group() # needs sage.combinat + sage: D.brown_invariant() # needs sage.combinat 4 We require the quadratic form to be defined modulo `2 \ZZ`:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: V = FreeQuadraticModule(ZZ,3,matrix.identity(3)) + sage: V = FreeQuadraticModule(ZZ, 3, matrix.identity(3)) sage: T = TorsionQuadraticModule((1/10)*V, V) sage: T.brown_invariant() Traceback (most recent call last): @@ -546,7 +543,7 @@ def genus(self, signature_pair): r""" Return the genus defined by ``self`` and the ``signature_pair``. - If no such genus exists, raise a ``ValueError``. + If no such genus exists, raise a :class:`ValueError`. REFERENCES: @@ -554,24 +551,25 @@ def genus(self, signature_pair): EXAMPLES:: + sage: # needs sage.combinat sage: L = IntegralLattice("D4").direct_sum(IntegralLattice("A2")) sage: D = L.discriminant_group() - sage: genus = D.genus(L.signature_pair()) - sage: genus + sage: genus = D.genus(L.signature_pair()) # needs sage.libs.pari + sage: genus # needs sage.libs.pari Genus of None Signature: (6, 0) Genus symbol at 2: 1^4:2^-2 Genus symbol at 3: 1^-5 3^-1 - sage: genus == L.genus() + sage: genus == L.genus() # needs sage.libs.pari True Let `H` be an even unimodular lattice of signature `(9, 1)`. Then `L = D_4 + A_2` is primitively embedded in `H`. We compute the discriminant form of the orthogonal complement of `L` in `H`:: - sage: DK = D.twist(-1) - sage: DK + sage: DK = D.twist(-1) # needs sage.combinat sage.libs.pari + sage: DK # needs sage.combinat sage.libs.pari Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] @@ -580,7 +578,7 @@ def genus(self, signature_pair): We know that `K` has signature `(5, 1)` and thus we can compute the genus of `K` as:: - sage: DK.genus((3,1)) + sage: DK.genus((3,1)) # needs sage.combinat sage.libs.pari Genus of None Signature: (3, 1) @@ -590,9 +588,9 @@ def genus(self, signature_pair): We can also compute the genus of an odd lattice from its discriminant form:: - sage: L = IntegralLattice(matrix.diagonal(range(1,5))) + sage: L = IntegralLattice(matrix.diagonal(range(1, 5))) sage: D = L.discriminant_group() - sage: D.genus((4,0)) + sage: D.genus((4,0)) # needs sage.libs.pari Genus of None Signature: (4, 0) @@ -601,19 +599,20 @@ def genus(self, signature_pair): TESTS:: - sage: L.genus() == D.genus((4,0)) + sage: L.genus() == D.genus((4,0)) # needs sage.libs.pari True - sage: D.genus((1,0)) + sage: D.genus((1,0)) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: this discriminant form and signature do not define a genus A systematic test of lattices of small ranks and determinants:: + sage: # needs sage.libs.pari sage: from sage.quadratic_forms.genera.genus import genera - sage: signatures = [(1,0),(1,1),(1,2),(3,0),(0,4)] - sage: dets = range(1,33) - sage: genera = flatten([genera(s, d, even=False) for d in dets for s in signatures]) # long time + sage: signatures = [(1,0), (1,1), (1,2), (3,0), (0,4)] + sage: dets = range(1, 33) + sage: genera = flatten([genera(s, d, even=False) for d in dets for s in signatures]) # long time sage: all(g == g.discriminant_form().genus(g.signature_pair()) for g in genera) # long time True """ @@ -752,22 +751,23 @@ def is_genus(self, signature_pair, even=True): INPUT: - - signature_pair -- a tuple of non negative integers ``(s_plus, s_minus)`` - - even -- bool (default: ``True``) + - ``signature_pair`` -- a tuple of non negative integers ``(s_plus, s_minus)`` + - ``even`` -- bool (default: ``True``) EXAMPLES:: - sage: L = IntegralLattice("D4").direct_sum(IntegralLattice(3 * Matrix(ZZ,2,[2,1,1,2]))) - sage: D = L.discriminant_group() - sage: D.is_genus((6,0)) + sage: L3 = IntegralLattice(3 * Matrix(ZZ, 2, [2,1,1,2])) + sage: L = IntegralLattice("D4").direct_sum(L3) # needs sage.combinat + sage: D = L.discriminant_group() # needs sage.combinat + sage: D.is_genus((6,0)) # needs sage.combinat True Let us see if there is a lattice in the genus defined by the same discriminant form but with a different signature:: - sage: D.is_genus((4,2)) + sage: D.is_genus((4,2)) # needs sage.combinat False - sage: D.is_genus((16,2)) + sage: D.is_genus((16,2)) # needs sage.combinat True """ s_plus = ZZ(signature_pair[0]) @@ -827,8 +827,8 @@ def orthogonal_group(self, gens=None, check=False): INPUT: - ``gens`` -- a list of generators, for instance square matrices, - something that acts on ``self``, or an automorphism - of the underlying abelian group + something that acts on ``self``, or an automorphism + of the underlying abelian group - ``check`` -- perform additional checks on the generators EXAMPLES: @@ -836,24 +836,25 @@ def orthogonal_group(self, gens=None, check=False): You can provide generators to obtain a subgroup of the full orthogonal group:: sage: D = TorsionQuadraticForm(matrix.identity(2)/2) - sage: f = matrix(2,[0,1,1,0]) - sage: D.orthogonal_group(gens=[f]).order() + sage: f = matrix(2, [0,1,1,0]) + sage: D.orthogonal_group(gens=[f]).order() # needs sage.groups 2 If no generators are given a slow brute force approach is used to calculate the full orthogonal group:: sage: D = TorsionQuadraticForm(matrix.identity(3)/2) - sage: OD = D.orthogonal_group() - sage: OD.order() + sage: OD = D.orthogonal_group() # needs sage.groups + sage: OD.order() # needs sage.groups 6 - sage: fd = D.hom([D.1,D.0,D.2]) - sage: OD(fd) + sage: fd = D.hom([D.1, D.0, D.2]) # needs sage.symbolic + sage: OD(fd) # needs sage.groups sage.symbolic [0 1 0] [1 0 0] [0 0 1] - We compute the kernel of the action of the orthogonal group of `L` on the discriminant group. + We compute the kernel of the action of the orthogonal group of `L` on the discriminant group:: + sage: # needs sage.combinat sage.groups sage: L = IntegralLattice('A4') sage: O = L.orthogonal_group() sage: D = L.discriminant_group() @@ -866,7 +867,7 @@ def orthogonal_group(self, gens=None, check=False): sage: phi.kernel().order() 120 """ - from sage.groups.fqf_orthogonal import FqfOrthogonalGroup,_isom_fqf + from sage.groups.fqf_orthogonal import FqfOrthogonalGroup, _isom_fqf from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap ambient = AbelianGroupGap(self.invariants()).aut() @@ -886,7 +887,7 @@ def orthogonal_group(self, gens=None, check=False): pass # the ambient knows what to do with the generators gens = tuple(ambient(g) for g in gens) - Oq = FqfOrthogonalGroup(ambient, gens, self, check=check) + Oq = FqfOrthogonalGroup(ambient, gens, self, check=check) return Oq def orthogonal_submodule_to(self, S): @@ -956,7 +957,7 @@ def normal_form(self, partial=False): or `u p^n`. If `p = 2` is even, then the normal form consists of - 1 x 1 blocks of the form + `1 \times 1` blocks of the form .. MATH:: @@ -981,7 +982,7 @@ def normal_form(self, partial=False): INPUT: - - partial - bool (default: ``False``) return only a partial normal form + - ``partial`` - bool (default: ``False``) return only a partial normal form; it is not unique but still useful to extract invariants OUTPUT: @@ -990,14 +991,14 @@ def normal_form(self, partial=False): EXAMPLES:: - sage: L1=IntegralLattice(matrix([[-2,0,0],[0,1,0],[0,0,4]])) - sage: L1.discriminant_group().normal_form() + sage: L1 = IntegralLattice(matrix([[-2,0,0], [0,1,0], [0,0,4]])) + sage: L1.discriminant_group().normal_form() # needs sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4) Gram matrix of the quadratic form with values in Q/Z: [1/2 0] [ 0 1/4] - sage: L2=IntegralLattice(matrix([[-2,0,0],[0,1,0],[0,0,-4]])) - sage: L2.discriminant_group().normal_form() + sage: L2 = IntegralLattice(matrix([[-2,0,0], [0,1,0], [0,0,-4]])) + sage: L2.discriminant_group().normal_form() # needs sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4) Gram matrix of the quadratic form with values in Q/Z: [1/2 0] @@ -1005,17 +1006,17 @@ def normal_form(self, partial=False): We check that :trac:`24864` is fixed:: - sage: L1=IntegralLattice(matrix([[-4,0,0],[0,4,0],[0,0,-2]])) - sage: AL1=L1.discriminant_group() - sage: L2=IntegralLattice(matrix([[-4,0,0],[0,-4,0],[0,0,2]])) - sage: AL2=L2.discriminant_group() - sage: AL1.normal_form() + sage: L1 = IntegralLattice(matrix([[-4,0,0], [0,4,0], [0,0,-2]])) + sage: AL1 = L1.discriminant_group() + sage: L2 = IntegralLattice(matrix([[-4,0,0], [0,-4,0], [0,0,2]])) + sage: AL2 = L2.discriminant_group() + sage: AL1.normal_form() # needs sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4, 4) Gram matrix of the quadratic form with values in Q/2Z: [1/2 0 0] [ 0 1/4 0] [ 0 0 5/4] - sage: AL2.normal_form() + sage: AL2.normal_form() # needs sage.libs.pari sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4, 4) Gram matrix of the quadratic form with values in Q/2Z: [1/2 0 0] @@ -1025,18 +1026,17 @@ def normal_form(self, partial=False): Some exotic cases:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: D4_gram = Matrix(ZZ,4,4,[2,0,0,-1,0,2,0,-1,0,0,2,-1,-1,-1,-1,2]) - sage: D4 = FreeQuadraticModule(ZZ,4,D4_gram) + sage: D4_gram = Matrix(ZZ, 4, 4,[2,0,0,-1, 0,2,0,-1, 0,0,2,-1, -1,-1,-1,2]) + sage: D4 = FreeQuadraticModule(ZZ, 4, D4_gram) sage: D4dual = D4.span(D4_gram.inverse()) - sage: T = TorsionQuadraticModule((1/6)*D4dual,D4) - sage: T + sage: T = TorsionQuadraticModule((1/6)*D4dual, D4); T Finite quadratic module over Integer Ring with invariants (6, 6, 12, 12) Gram matrix of the quadratic form with values in Q/(1/3)Z: [ 1/18 1/12 5/36 1/36] [ 1/12 1/6 1/36 1/9] [ 5/36 1/36 1/36 11/72] [ 1/36 1/9 11/72 1/36] - sage: T.normal_form() + sage: T.normal_form() # needs sage.libs.pari sage.rings.padics Finite quadratic module over Integer Ring with invariants (6, 6, 12, 12) Gram matrix of the quadratic form with values in Q/(1/3)Z: [ 1/6 1/12 0 0 0 0 0 0] @@ -1053,7 +1053,7 @@ def normal_form(self, partial=False): A degenerate case:: sage: T = TorsionQuadraticModule((1/6)*D4dual, D4, modulus=1/36) - sage: T.normal_form() + sage: T.normal_form() # needs sage.libs.pari sage.rings.padics Finite quadratic module over Integer Ring with invariants (6, 6, 12, 12) Gram matrix of the quadratic form with values in Q/(1/18)Z: [1/36 1/72 0 0 0 0 0 0] @@ -1065,8 +1065,10 @@ def normal_form(self, partial=False): [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] """ - gens = [] from sage.quadratic_forms.genera.normal_form import p_adic_normal_form, _normalize + from sage.rings.padics.factory import Zp + + gens = [] for p in self.annihilator().gen().prime_divisors(): D_p = self.primary_part(p) q_p = D_p.gram_matrix_quadratic() @@ -1129,8 +1131,7 @@ def primary_part(self, m): EXAMPLES:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: T = TorsionQuadraticModule((1/6)*ZZ^3,ZZ^3) - sage: T + sage: T = TorsionQuadraticModule((1/6)*ZZ^3, ZZ^3); T Finite quadratic module over Integer Ring with invariants (6, 6, 6) Gram matrix of the quadratic form with values in Q/(1/3)Z: [1/36 0 0] @@ -1167,7 +1168,7 @@ def submodule_with_gens(self, gens): EXAMPLES:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: V = FreeQuadraticModule(ZZ,3,matrix.identity(3)*10) + sage: V = FreeQuadraticModule(ZZ, 3, matrix.identity(3)*10) sage: T = TorsionQuadraticModule((1/10)*V, V) sage: g = T.gens() sage: new_gens = [2*g[0], 5*g[0]] @@ -1193,9 +1194,8 @@ def submodule_with_gens(self, gens): Test that things work without specified gens too:: sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule - sage: V = FreeQuadraticModule(ZZ,3,matrix.identity(3)*5) - sage: T = TorsionQuadraticModule((1/5)*V, V) - sage: T + sage: V = FreeQuadraticModule(ZZ, 3, matrix.identity(3)*5) + sage: T = TorsionQuadraticModule((1/5)*V, V); T Finite quadratic module over Integer Ring with invariants (5, 5, 5) Gram matrix of the quadratic form with values in Q/Z: [1/5 0 0] @@ -1267,8 +1267,7 @@ def value_module(self): sage: A2 = Matrix(ZZ, 2, 2, [2,-1,-1,2]) sage: L = IntegralLattice(2*A2) - sage: D = L.discriminant_group() - sage: D + sage: D = L.discriminant_group(); D Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] @@ -1287,9 +1286,8 @@ def value_module_qf(self): EXAMPLES:: sage: A2 = Matrix(ZZ, 2, 2, [2,-1,-1,2]) - sage: L = IntegralLattice(2*A2) - sage: D = L.discriminant_group() - sage: D + sage: L = IntegralLattice(2 * A2) + sage: D = L.discriminant_group(); D Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] diff --git a/src/sage/modules/tutorial_free_modules.py b/src/sage/modules/tutorial_free_modules.py index d58acd4ae9f..8fe8cd8c7df 100644 --- a/src/sage/modules/tutorial_free_modules.py +++ b/src/sage/modules/tutorial_free_modules.py @@ -40,7 +40,8 @@ sage: F = CombinatorialFreeModule(ZZ, CC); F.an_element() B[1.00000000000000*I] - sage: F = CombinatorialFreeModule(ZZ, Partitions(NonNegativeIntegers(), max_part=3)); F.an_element() + sage: F = CombinatorialFreeModule(ZZ, Partitions(NonNegativeIntegers(), # needs sage.combinat + ....: max_part=3)); F.an_element() 2*B[[]] + 2*B[[1]] + 3*B[[2]] sage: F = CombinatorialFreeModule(ZZ, ['spam', 'eggs', '42']); F.an_element() 3*B['42'] + 2*B['eggs'] + 2*B['spam'] @@ -89,7 +90,9 @@ module:: sage: a = F.basis(); a - Lazy family (Term map from Ring of integers modulo 5 to Free module generated by Ring of integers modulo 5 over Integer Ring(i))_{i in Ring of integers modulo 5} + Lazy family (Term map from Ring of integers modulo 5 + to Free module generated by Ring of integers modulo 5 + over Integer Ring(i))_{i in Ring of integers modulo 5} This gadget models the :class:`family <Family>` `(B_i)_{i \in \ZZ_5}`. In particular, one can run through its elements:: diff --git a/src/sage/modules/vector_callable_symbolic_dense.py b/src/sage/modules/vector_callable_symbolic_dense.py index 306982c2cc3..1929eabcf46 100644 --- a/src/sage/modules/vector_callable_symbolic_dense.py +++ b/src/sage/modules/vector_callable_symbolic_dense.py @@ -69,7 +69,7 @@ def _repr_(self): """ ring = self.coordinate_ring() args = ring.arguments() - repr_x=self.change_ring(SR)._repr_() + repr_x = self.change_ring(SR)._repr_() if len(args) == 1: return "%s |--> %s" % (args[0], repr_x) else: diff --git a/src/sage/modules/vector_complex_double_dense.pyx b/src/sage/modules/vector_complex_double_dense.pyx index 43f3322d627..d9715fbdc82 100644 --- a/src/sage/modules/vector_complex_double_dense.pyx +++ b/src/sage/modules/vector_complex_double_dense.pyx @@ -1,10 +1,11 @@ +# sage.doctest: optional - numpy r""" Dense complex double vectors using a NumPy backend EXAMPLES:: - sage: v = vector(CDF,[(1,-1), (2,pi), (3,5)]) - sage: v + sage: # needs sage.symbolic + sage: v = vector(CDF, [(1,-1), (2,pi), (3,5)]); v (1.0 - 1.0*I, 2.0 + 3.141592653589793*I, 3.0 + 5.0*I) sage: type(v) <class 'sage.modules.vector_complex_double_dense.Vector_complex_double_dense'> @@ -54,10 +55,9 @@ cdef class Vector_complex_double_dense(Vector_double_dense): EXAMPLES:: - sage: v = vector(CDF,[(1,-1), (2,pi), (3,5)]) - sage: v + sage: v = vector(CDF, [(1,-1), (2,pi), (3,5)]); v # needs sage.symbolic (1.0 - 1.0*I, 2.0 + 3.141592653589793*I, 3.0 + 5.0*I) - sage: v*v # rel tol 1e-15 + sage: v*v # rel tol 1e-15 # needs sage.symbolic -21.86960440108936 + 40.56637061435917*I """ def __cinit__(self, parent, entries, coerce=True, copy=True): diff --git a/src/sage/modules/vector_double_dense.pyx b/src/sage/modules/vector_double_dense.pyx index 2d581606980..551da99669e 100644 --- a/src/sage/modules/vector_double_dense.pyx +++ b/src/sage/modules/vector_double_dense.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - numpy r""" Dense vectors using a NumPy backend @@ -6,8 +7,8 @@ Complex Double Field EXAMPLES:: - sage: v = vector(CDF,[(1,-1), (2,pi), (3,5)]) - sage: v + sage: # needs sage.symbolic + sage: v = vector(CDF,[(1,-1), (2,pi), (3,5)]); v (1.0 - 1.0*I, 2.0 + 3.141592653589793*I, 3.0 + 5.0*I) sage: type(v) <class 'sage.modules.vector_complex_double_dense.Vector_complex_double_dense'> @@ -18,6 +19,7 @@ EXAMPLES:: (5.0, 2.0 + 3.141592653589793*I, 3.0 + 5.0*I) sage: loads(dumps(v)) == v True + sage: v = vector(RDF, [1,2,3,4]); v (1.0, 2.0, 3.0, 4.0) sage: loads(dumps(v)) == v @@ -471,10 +473,10 @@ cdef class Vector_double_dense(Vector_numpy_dense): # p = 0 returns integer *count* of non-zero entries return RDF(n) - ############################# # statistics ############################# + def mean(self): """ Calculate the arithmetic mean of the vector. diff --git a/src/sage/modules/vector_integer_dense.pyx b/src/sage/modules/vector_integer_dense.pyx index 9b24aecd965..177ada5dea1 100644 --- a/src/sage/modules/vector_integer_dense.pyx +++ b/src/sage/modules/vector_integer_dense.pyx @@ -43,27 +43,25 @@ TESTS:: True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 William Stein <wstein@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.memory cimport check_allocarray, sig_free from cysignals.signals cimport sig_on, sig_off -from sage.structure.element cimport Element, ModuleElement, RingElement, Vector +from sage.structure.element cimport Element, Vector from sage.structure.richcmp cimport rich_to_bool from sage.rings.integer cimport Integer, _Integer_from_mpz cimport sage.modules.free_module_element as free_module_element -from .free_module_element import vector - from sage.libs.gmp.mpz cimport * cdef class Vector_integer_dense(free_module_element.FreeModuleElement): @@ -210,8 +208,8 @@ cdef class Vector_integer_dense(free_module_element.FreeModuleElement): (1, 2, 3, 4) """ cdef int i - return [_Integer_from_mpz(self._entries[i]) for i in - xrange(self._degree)] + return [_Integer_from_mpz(self._entries[i]) + for i in range(self._degree)] def __reduce__(self): return (unpickle_v1, (self._parent, self.list(), self._degree, @@ -316,10 +314,10 @@ cdef class Vector_integer_dense(free_module_element.FreeModuleElement): sage: A = random_matrix(ZZ,1,3) sage: v = A.row(0) - sage: vs = singular(v) - sage: vs._repr_() == '{},\n{},\n{}'.format(*v) + sage: vs = singular(v) # needs sage.libs.singular + sage: vs._repr_() == '{},\n{},\n{}'.format(*v) # needs sage.libs.singular True - sage: vs.type() + sage: vs.type() # needs sage.libs.singular 'intvec' """ if singular is None: diff --git a/src/sage/modules/vector_mod2_dense.pyx b/src/sage/modules/vector_mod2_dense.pyx index 4583977dc0c..93fc3f32cd1 100644 --- a/src/sage/modules/vector_mod2_dense.pyx +++ b/src/sage/modules/vector_mod2_dense.pyx @@ -43,10 +43,9 @@ TESTS:: from sage.rings.finite_rings.integer_mod cimport IntegerMod_int, IntegerMod_abstract from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational -from sage.structure.element cimport Element, ModuleElement, RingElement, Vector +from sage.structure.element cimport Element, Vector from sage.structure.richcmp cimport rich_to_bool cimport sage.modules.free_module_element as free_module_element -from .free_module_element import vector from sage.libs.m4ri cimport * diff --git a/src/sage/modules/vector_modn_dense.pyx b/src/sage/modules/vector_modn_dense.pyx index 5a0e27912b9..8608672031d 100644 --- a/src/sage/modules/vector_modn_dense.pyx +++ b/src/sage/modules/vector_modn_dense.pyx @@ -46,7 +46,7 @@ We make a large zero vector:: We multiply a vector by a matrix:: sage: a = (GF(97)^5)(range(5)) - sage: m = matrix(GF(97),5,range(25)) + sage: m = matrix(GF(97), 5, range(25)) sage: a*m (53, 63, 73, 83, 93) @@ -58,20 +58,20 @@ TESTS:: sage: v = vector(Integers(389), [1,2,3,4,5]) sage: loads(dumps(v)) == v True - sage: v = vector(Integers(next_prime(10^20)), [1,2,3,4,5]) + sage: v = vector(Integers(next_prime(10^20)), [1,2,3,4,5]) # needs sage.libs.pari sage: loads(dumps(v)) == v True - sage: K = GF(previous_prime(2^31)) - sage: v = vector(K, [42]); type(v[0]) + sage: K = GF(previous_prime(2^31)) # needs sage.rings.finite_rings + sage: v = vector(K, [42]); type(v[0]) # needs sage.rings.finite_rings <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int64'> - sage: ~v[0] + sage: ~v[0] # needs sage.rings.finite_rings 2096353084 - sage: K = GF(next_prime(2^31)) - sage: v = vector(K, [42]); type(v[0]) + sage: K = GF(next_prime(2^31)) # needs sage.rings.finite_rings + sage: v = vector(K, [42]); type(v[0]) # needs sage.rings.finite_rings <class 'sage.rings.finite_rings.integer_mod.IntegerMod_gmp'> - sage: ~v[0] + sage: ~v[0] # needs sage.rings.finite_rings 1482786336 sage: w = vector(GF(11), [-1,0,0,0]) @@ -81,6 +81,7 @@ TESTS:: Test that :trac:`28042` is fixed:: + sage: # needs sage.rings.finite_rings sage: p = 193379 sage: K = GF(p) sage: a = K(1) @@ -88,7 +89,7 @@ Test that :trac:`28042` is fixed:: sage: c = K(109320) sage: d = K(167667) sage: e = 103937 - sage: a*c+b*d-e + sage: a*c + b*d - e 102041 sage: vector([a,b]) * vector([c,d]) - e 102041 @@ -128,10 +129,10 @@ cdef mod_int ivalue(IntegerMod_abstract x) except -1: else: raise TypeError("non-fixed size integer") -from sage.structure.element cimport Element, ModuleElement, RingElement, Vector +from sage.structure.element cimport Element, Vector cimport sage.modules.free_module_element as free_module_element -from .free_module_element import vector + cdef class Vector_modn_dense(free_module_element.FreeModuleElement): cdef _new_c(self): diff --git a/src/sage/modules/vector_modn_sparse.pyx b/src/sage/modules/vector_modn_sparse.pyx index 746f9897db2..e2dd1d7c1a6 100644 --- a/src/sage/modules/vector_modn_sparse.pyx +++ b/src/sage/modules/vector_modn_sparse.pyx @@ -7,8 +7,6 @@ from cysignals.memory cimport sig_malloc, sig_free -from sage.modules.vector_modn_sparse cimport c_vector_modint - cdef int allocate_c_vector_modint(c_vector_modint* v, Py_ssize_t num_nonzero) except -1: """ diff --git a/src/sage/modules/vector_numpy_dense.pyx b/src/sage/modules/vector_numpy_dense.pyx index 6c72c98c0c2..f0e2224b96d 100644 --- a/src/sage/modules/vector_numpy_dense.pyx +++ b/src/sage/modules/vector_numpy_dense.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - numpy r""" Dense vectors using a NumPy backend. diff --git a/src/sage/modules/vector_numpy_integer_dense.pyx b/src/sage/modules/vector_numpy_integer_dense.pyx index faeb8531771..ba3537436d5 100644 --- a/src/sage/modules/vector_numpy_integer_dense.pyx +++ b/src/sage/modules/vector_numpy_integer_dense.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - numpy r""" Dense integer vectors using a NumPy backend. @@ -26,8 +27,6 @@ EXAMPLES:: cimport numpy import numpy -from sage.structure.element cimport Element, Vector - from sage.rings.integer_ring import ZZ # This is for the NumPy C API (the PyArray... functions) to work diff --git a/src/sage/modules/vector_rational_dense.pyx b/src/sage/modules/vector_rational_dense.pyx index ff1b4914295..34b23515348 100644 --- a/src/sage/modules/vector_rational_dense.pyx +++ b/src/sage/modules/vector_rational_dense.pyx @@ -44,26 +44,25 @@ TESTS:: True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 William Stein <wstein@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.memory cimport check_allocarray, sig_free from cysignals.signals cimport sig_on, sig_off -from sage.structure.element cimport Element, ModuleElement, RingElement, Vector +from sage.structure.element cimport Element, Vector from sage.structure.richcmp cimport rich_to_bool from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational cimport sage.modules.free_module_element as free_module_element -from .free_module_element import vector from sage.libs.gmp.mpq cimport * @@ -146,7 +145,7 @@ cdef class Vector_rational_dense(free_module_element.FreeModuleElement): cdef Rational z if isinstance(x, (list, tuple)): if len(x) != self._degree: - raise TypeError("entries must be a list of length %s"%self._degree) + raise TypeError("entries must be a list of length %s" % self._degree) for i from 0 <= i < self._degree: z = Rational(x[i]) mpq_set(self._entries[i], z.value) @@ -229,8 +228,7 @@ cdef class Vector_rational_dense(free_module_element.FreeModuleElement): """ mpq_set(self._entries[i], (<Rational>value).value) - - def list(self,copy=True): + def list(self, copy=True): """ The list of entries of the vector. @@ -248,8 +246,8 @@ cdef class Vector_rational_dense(free_module_element.FreeModuleElement): (1, 2, 3, 4) """ cdef int i - return [_Rational_from_mpq(self._entries[i]) for i in - xrange(self._degree)] + return [_Rational_from_mpq(self._entries[i]) + for i in range(self._degree)] def __reduce__(self): return (unpickle_v1, (self._parent, self.list(), self._degree, @@ -264,7 +262,6 @@ cdef class Vector_rational_dense(free_module_element.FreeModuleElement): mpq_add(z._entries[i], self._entries[i], r._entries[i]) return z - cpdef _sub_(self, right): cdef Vector_rational_dense z, r r = right @@ -299,7 +296,6 @@ cdef class Vector_rational_dense(free_module_element.FreeModuleElement): mpq_clear(t) return z - cpdef _pairwise_product_(self, Vector right): """ EXAMPLES:: @@ -326,7 +322,8 @@ cdef class Vector_rational_dense(free_module_element.FreeModuleElement): mpq_set_z(a.value, (<Integer>left).value) else: # should not happen - raise TypeError("Cannot convert %s to %s" % (type(left).__name__, Rational.__name__)) + raise TypeError("cannot convert %s to %s" % (type(left).__name__, + Rational.__name__)) z = self._new_c() cdef Py_ssize_t i for i in range(self._degree): @@ -343,7 +340,8 @@ cdef class Vector_rational_dense(free_module_element.FreeModuleElement): mpq_set_z(a.value, (<Integer>right).value) else: # should not happen - raise TypeError("Cannot convert %s to %s" % (type(right).__name__, Rational.__name__)) + raise TypeError("cannot convert %s to %s" % (type(right).__name__, + Rational.__name__)) z = self._new_c() cdef Py_ssize_t i for i in range(self._degree): @@ -374,6 +372,7 @@ def unpickle_v0(parent, entries, degree): mpq_set(v._entries[i], z.value) return v + def unpickle_v1(parent, entries, degree, is_mutable): cdef Vector_rational_dense v v = Vector_rational_dense.__new__(Vector_rational_dense) diff --git a/src/sage/modules/vector_real_double_dense.pyx b/src/sage/modules/vector_real_double_dense.pyx index 7a3d674e1eb..bf7c75f1605 100644 --- a/src/sage/modules/vector_real_double_dense.pyx +++ b/src/sage/modules/vector_real_double_dense.pyx @@ -1,10 +1,11 @@ +# sage.doctest: optional - numpy r""" Dense real double vectors using a NumPy backend EXAMPLES:: - sage: v = vector(RDF,[1, pi, sqrt(2)]) - sage: v + sage: # needs sage.symbolic + sage: v = vector(RDF, [1, pi, sqrt(2)]); v (1.0, 3.141592653589793, 1.414213562373095) sage: type(v) <class 'sage.modules.vector_real_double_dense.Vector_real_double_dense'> diff --git a/src/sage/modules/vector_space_homspace.py b/src/sage/modules/vector_space_homspace.py index 13004ea14ce..b815051171a 100644 --- a/src/sage/modules/vector_space_homspace.py +++ b/src/sage/modules/vector_space_homspace.py @@ -191,7 +191,7 @@ # http://www.gnu.org/licenses/ #################################################################################### -import sage.matrix.all as matrix +from sage.matrix.constructor import matrix import sage.modules.free_module_homspace # This module initially overrides just the minimum functionality necessary @@ -365,7 +365,7 @@ def __call__(self, A, check=True, **kwds): sage: H.zero().is_zero() True - Previously the above code resulted in a TypeError because the + Previously the above code resulted in a :class:`TypeError` because the dimensions of the matrix were incorrect. """ from .vector_space_morphism import is_VectorSpaceMorphism, VectorSpaceMorphism @@ -384,7 +384,7 @@ def __call__(self, A, check=True, **kwds): msg = 'function cannot be applied properly to some basis element because\n' + e.args[0] raise ValueError(msg) try: - A = matrix.matrix(D.dimension(), C.dimension(), [C.coordinates(C(a)) for a in images]) + A = matrix(D.dimension(), C.dimension(), [C.coordinates(C(a)) for a in images]) except (ArithmeticError, TypeError) as e: msg = 'some image of the function is not in the codomain, because\n' + e.args[0] raise ArithmeticError(msg) @@ -396,7 +396,7 @@ def __call__(self, A, check=True, **kwds): raise ValueError(msg.format(len(D.basis()), len(A))) try: v = [C(a) for a in A] - A = matrix.matrix(D.dimension(), C.dimension(), [C.coordinates(a) for a in v]) + A = matrix(D.dimension(), C.dimension(), [C.coordinates(a) for a in v]) except (ArithmeticError, TypeError) as e: msg = 'some proposed image is not in the codomain, because\n' + e.args[0] raise ArithmeticError(msg) diff --git a/src/sage/modules/vector_space_morphism.py b/src/sage/modules/vector_space_morphism.py index b0e0846a163..2685462a74e 100644 --- a/src/sage/modules/vector_space_morphism.py +++ b/src/sage/modules/vector_space_morphism.py @@ -29,7 +29,7 @@ Vector space morphism represented by the matrix: [-1 2 3] [ 4 2 0] - Domain: Vector space of dimension 2 over Rational Field + Domain: Vector space of dimension 2 over Rational Field Codomain: Vector space of dimension 3 over Rational Field sage: phi([2, -3]) (-14, -2, 6) @@ -38,6 +38,7 @@ linear transformation, along with explicit descriptions of the domain and codomain. :: + sage: # needs sage.symbolic sage: F = Integers(13) sage: D = F^3 sage: C = F^2 @@ -65,11 +66,12 @@ [ 2 -1] [ 4 0] [ 3 7] - Domain: Vector space of dimension 4 over Rational Field + Domain: Vector space of dimension 4 over Rational Field Codomain: Vector space of dimension 2 over Rational Field A homomorphism may also be created via a method on the domain. :: + sage: # needs sage.rings.number_field sage.symbolic sage: F = QQ[sqrt(3)] sage: a = F.gen(0) sage: D = F^2 @@ -80,8 +82,10 @@ Vector space morphism represented by the matrix: [ sqrt3 1] [2*sqrt3 2] - Domain: Vector space of dimension 2 over Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878? - Codomain: Vector space of dimension 2 over Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878? + Domain: Vector space of dimension 2 over Number Field in sqrt3 + with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878? + Codomain: Vector space of dimension 2 over Number Field in sqrt3 + with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878? sage: psi([1, 4]) (9*sqrt3, 9) @@ -149,10 +153,10 @@ matrix representation used to represent linear transformations are relative to the bases of both the domain and codomain. :: - sage: A = graphs.PetersenGraph().adjacency_matrix() + sage: A = graphs.PetersenGraph().adjacency_matrix() # needs sage.graphs sage: V = QQ^10 - sage: phi = linear_transformation(V, V, A) - sage: phi + sage: phi = linear_transformation(V, V, A) # needs sage.graphs + sage: phi # needs sage.graphs Vector space morphism represented by the matrix: [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] @@ -164,9 +168,10 @@ [0 0 1 0 0 1 0 0 0 1] [0 0 0 1 0 1 1 0 0 0] [0 0 0 0 1 0 1 1 0 0] - Domain: Vector space of dimension 10 over Rational Field + Domain: Vector space of dimension 10 over Rational Field Codomain: Vector space of dimension 10 over Rational Field + sage: # needs sage.graphs sage: B1 = [V.gen(i) + V.gen(i+1) for i in range(9)] + [V.gen(9)] sage: B2 = [V.gen(0)] + [-V.gen(i-1) + V.gen(i) for i in range(1,10)] sage: D = V.subspace_with_basis(B1) @@ -185,42 +190,42 @@ [6 6 6 5 4 4 2 1 1 1] [6 6 6 6 5 4 3 1 0 0] [3 3 3 3 3 2 2 1 0 0] - Domain: Vector space of degree 10 and dimension 10 over Rational Field - User basis matrix: - [1 1 0 0 0 0 0 0 0 0] - [0 1 1 0 0 0 0 0 0 0] - [0 0 1 1 0 0 0 0 0 0] - [0 0 0 1 1 0 0 0 0 0] - [0 0 0 0 1 1 0 0 0 0] - [0 0 0 0 0 1 1 0 0 0] - [0 0 0 0 0 0 1 1 0 0] - [0 0 0 0 0 0 0 1 1 0] - [0 0 0 0 0 0 0 0 1 1] - [0 0 0 0 0 0 0 0 0 1] + Domain: Vector space of degree 10 and dimension 10 over Rational Field + User basis matrix: + [1 1 0 0 0 0 0 0 0 0] + [0 1 1 0 0 0 0 0 0 0] + [0 0 1 1 0 0 0 0 0 0] + [0 0 0 1 1 0 0 0 0 0] + [0 0 0 0 1 1 0 0 0 0] + [0 0 0 0 0 1 1 0 0 0] + [0 0 0 0 0 0 1 1 0 0] + [0 0 0 0 0 0 0 1 1 0] + [0 0 0 0 0 0 0 0 1 1] + [0 0 0 0 0 0 0 0 0 1] Codomain: Vector space of degree 10 and dimension 10 over Rational Field - User basis matrix: - [ 1 0 0 0 0 0 0 0 0 0] - [-1 1 0 0 0 0 0 0 0 0] - [ 0 -1 1 0 0 0 0 0 0 0] - [ 0 0 -1 1 0 0 0 0 0 0] - [ 0 0 0 -1 1 0 0 0 0 0] - [ 0 0 0 0 -1 1 0 0 0 0] - [ 0 0 0 0 0 -1 1 0 0 0] - [ 0 0 0 0 0 0 -1 1 0 0] - [ 0 0 0 0 0 0 0 -1 1 0] - [ 0 0 0 0 0 0 0 0 -1 1] + User basis matrix: + [ 1 0 0 0 0 0 0 0 0 0] + [-1 1 0 0 0 0 0 0 0 0] + [ 0 -1 1 0 0 0 0 0 0 0] + [ 0 0 -1 1 0 0 0 0 0 0] + [ 0 0 0 -1 1 0 0 0 0 0] + [ 0 0 0 0 -1 1 0 0 0 0] + [ 0 0 0 0 0 -1 1 0 0 0] + [ 0 0 0 0 0 0 -1 1 0 0] + [ 0 0 0 0 0 0 0 -1 1 0] + [ 0 0 0 0 0 0 0 0 -1 1] An endomorphism is a linear transformation with an equal domain and codomain, and here each needs to have the same basis. We are using a matrix that has well-behaved eigenvalues, as part of showing that these do not change as the representation changes. :: + sage: # needs sage.graphs sage: A = graphs.PetersenGraph().adjacency_matrix() sage: V = QQ^10 sage: phi = linear_transformation(V, V, A) sage: phi.eigenvalues() [3, -2, -2, -2, -2, 1, 1, 1, 1, 1] - sage: B1 = [V.gen(i) + V.gen(i+1) for i in range(9)] + [V.gen(9)] sage: C = V.subspace_with_basis(B1) sage: zeta = phi.restrict(C) @@ -236,31 +241,30 @@ [ 0 0 1 0 0 2 -1 1 -1 2] [ 0 0 0 1 0 1 1 0 0 0] [ 0 0 0 0 1 -1 2 -1 1 -1] - Domain: Vector space of degree 10 and dimension 10 over Rational Field - User basis matrix: - [1 1 0 0 0 0 0 0 0 0] - [0 1 1 0 0 0 0 0 0 0] - [0 0 1 1 0 0 0 0 0 0] - [0 0 0 1 1 0 0 0 0 0] - [0 0 0 0 1 1 0 0 0 0] - [0 0 0 0 0 1 1 0 0 0] - [0 0 0 0 0 0 1 1 0 0] - [0 0 0 0 0 0 0 1 1 0] - [0 0 0 0 0 0 0 0 1 1] - [0 0 0 0 0 0 0 0 0 1] + Domain: Vector space of degree 10 and dimension 10 over Rational Field + User basis matrix: + [1 1 0 0 0 0 0 0 0 0] + [0 1 1 0 0 0 0 0 0 0] + [0 0 1 1 0 0 0 0 0 0] + [0 0 0 1 1 0 0 0 0 0] + [0 0 0 0 1 1 0 0 0 0] + [0 0 0 0 0 1 1 0 0 0] + [0 0 0 0 0 0 1 1 0 0] + [0 0 0 0 0 0 0 1 1 0] + [0 0 0 0 0 0 0 0 1 1] + [0 0 0 0 0 0 0 0 0 1] Codomain: Vector space of degree 10 and dimension 10 over Rational Field - User basis matrix: - [1 1 0 0 0 0 0 0 0 0] - [0 1 1 0 0 0 0 0 0 0] - [0 0 1 1 0 0 0 0 0 0] - [0 0 0 1 1 0 0 0 0 0] - [0 0 0 0 1 1 0 0 0 0] - [0 0 0 0 0 1 1 0 0 0] - [0 0 0 0 0 0 1 1 0 0] - [0 0 0 0 0 0 0 1 1 0] - [0 0 0 0 0 0 0 0 1 1] - [0 0 0 0 0 0 0 0 0 1] - + User basis matrix: + [1 1 0 0 0 0 0 0 0 0] + [0 1 1 0 0 0 0 0 0 0] + [0 0 1 1 0 0 0 0 0 0] + [0 0 0 1 1 0 0 0 0 0] + [0 0 0 0 1 1 0 0 0 0] + [0 0 0 0 0 1 1 0 0 0] + [0 0 0 0 0 0 1 1 0 0] + [0 0 0 0 0 0 0 1 1 0] + [0 0 0 0 0 0 0 0 1 1] + [0 0 0 0 0 0 0 0 0 1] sage: zeta.eigenvalues() [3, -2, -2, -2, -2, 1, 1, 1, 1, 1] @@ -495,6 +499,7 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): Domain: Vector space of dimension 3 over Rational Field Codomain: Vector space of dimension 2 over Rational Field + sage: # needs sage.symbolic sage: x, y, z = var('x y z') sage: h(x, y, z) = [2*x + z, 5*y] sage: zeta = linear_transformation(QQ^3, QQ^2, h) @@ -503,12 +508,12 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): [2 0] [0 5] [1 0] - Domain: Vector space of dimension 3 over Rational Field + Domain: Vector space of dimension 3 over Rational Field Codomain: Vector space of dimension 2 over Rational Field sage: phi == rho True - sage: rho == zeta + sage: rho == zeta # needs sage.symbolic True @@ -536,6 +541,7 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): [2 5] [3 7] + sage: # needs sage.symbolic sage: s, t = var('s t') sage: h(s, t) = [(-4/5)*s + (1/5)*t, (97/5)*s + (-13/5)*t] sage: zeta = linear_transformation(D, C, h) @@ -546,8 +552,9 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): Finally, we can give an explicit list of images for the basis elements of the domain. :: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: F.<a> = NumberField(x^3+x+1) + sage: F.<a> = NumberField(x^3 + x + 1) sage: u = vector(F, [1, a, a^2]) sage: v = vector(F, [a, a^2, 2]) sage: w = u + v @@ -655,26 +662,27 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): A Sage symbolic function can come in a variety of forms that are not representative of a linear transformation. :: - sage: x, y = var('x, y') - sage: f(x, y) = [y, x, y] - sage: linear_transformation(QQ^3, QQ^3, f) + sage: x, y = var('x, y') # needs sage.symbolic + sage: f(x, y) = [y, x, y] # needs sage.symbolic + sage: linear_transformation(QQ^3, QQ^3, f) # needs sage.symbolic Traceback (most recent call last): ... ValueError: symbolic function has the wrong number of inputs for domain - sage: linear_transformation(QQ^2, QQ^2, f) + sage: linear_transformation(QQ^2, QQ^2, f) # needs sage.symbolic Traceback (most recent call last): ... ValueError: symbolic function has the wrong number of outputs for codomain - sage: x, y = var('x y') - sage: f(x, y) = [y, x*y] - sage: linear_transformation(QQ^2, QQ^2, f) + sage: x, y = var('x y') # needs sage.symbolic + sage: f(x, y) = [y, x*y] # needs sage.symbolic + sage: linear_transformation(QQ^2, QQ^2, f) # needs sage.symbolic Traceback (most recent call last): ... ValueError: symbolic function must be linear in all the inputs: unable to convert y to a rational + sage: # needs sage.symbolic sage: x, y = var('x y') sage: f(x, y) = [x, 2*y] sage: C = (QQ^2).span([vector(QQ, [1, 1])]) @@ -822,7 +830,7 @@ def __init__(self, homspace, A, side="left"): [0 1] [2 3] [4 5] - Domain: Vector space of dimension 3 over Rational Field + Domain: Vector space of dimension 3 over Rational Field Codomain: Vector space of dimension 2 over Rational Field See the constructor, @@ -866,7 +874,6 @@ def __init__(self, homspace, A, side="left"): if homspace.domain().dimension() != A.ncols(): raise TypeError('codomain dimension is incompatible with matrix size') - A = homspace._matrix_space(side)(A) free_module_morphism.FreeModuleMorphism.__init__(self, homspace, A, side) @@ -903,6 +910,7 @@ def is_invertible(self): A non-invertible linear transformation, an endomorphism of a vector space over a finite field. :: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(11^2) sage: A = matrix(F, [[6*a + 3, 8*a + 2, 10*a + 3], ....: [2*a + 7, 4*a + 3, 2*a + 3], diff --git a/src/sage/modules/vector_symbolic_dense.py b/src/sage/modules/vector_symbolic_dense.py index 12152d97fcb..ce134c0462e 100644 --- a/src/sage/modules/vector_symbolic_dense.py +++ b/src/sage/modules/vector_symbolic_dense.py @@ -1,7 +1,7 @@ """ -Vectors over the symbolic ring +Dense vectors over the symbolic ring -Implements vectors over the symbolic ring. +Implements dense vectors over the symbolic ring. AUTHORS: @@ -55,7 +55,7 @@ #***************************************************************************** from . import free_module_element -from sage.symbolic.all import Expression +from sage.symbolic.expression import Expression def apply_map(phi): @@ -108,6 +108,7 @@ def apply(self, *args, **kwds): class Vector_symbolic_dense(free_module_element.FreeModuleElement_generic_dense): pass + # Add elementwise methods. for method in ['simplify', 'simplify_factorial', 'simplify_log', 'simplify_rational', diff --git a/src/sage/modules/vector_symbolic_sparse.py b/src/sage/modules/vector_symbolic_sparse.py new file mode 100644 index 00000000000..73cb41ae611 --- /dev/null +++ b/src/sage/modules/vector_symbolic_sparse.py @@ -0,0 +1,119 @@ +""" +Sparse vectors over the symbolic ring + +Implements vectors over the symbolic ring. + +AUTHORS: + +- Robert Bradshaw (2011-05-25): Added more element-wise simplification methods + +- Joris Vankerschaver (2011-05-15): Initial version + +- Dima Pasechnik (2023-06-04): cloning from the dense case + +EXAMPLES:: + + sage: x, y = var('x, y') + sage: u = vector([sin(x)^2 + cos(x)^2, log(2*y) + log(3*y)], sparse=True); u + (cos(x)^2 + sin(x)^2, log(3*y) + log(2*y)) + sage: type(u) + <class 'sage.modules.free_module.FreeModule_ambient_field_with_category.element_class'> + sage: u.simplify_full() + (1, log(3*y) + log(2*y)) + +TESTS: + +Check that the outcome of arithmetic with symbolic vectors is again +a symbolic vector (:trac:`11549`):: + + sage: v = vector(SR, [1, 2], sparse=True) + sage: w = vector(SR, [sin(x), 0], sparse=True) + sage: type(v) + <class 'sage.modules.free_module.FreeModule_ambient_field_with_category.element_class'> + sage: type(w) + <class 'sage.modules.free_module.FreeModule_ambient_field_with_category.element_class'> + sage: type(v + w) + <class 'sage.modules.free_module.FreeModule_ambient_field_with_category.element_class'> + sage: type(-v) + <class 'sage.modules.free_module.FreeModule_ambient_field_with_category.element_class'> + sage: type(5*w) + <class 'sage.modules.free_module.FreeModule_ambient_field_with_category.element_class'> + +Test pickling/unpickling:: + + sage: u = vector(SR, [sin(x^2)], sparse=True) + sage: loads(dumps(u)) == u + True + +""" + +#***************************************************************************** +# Copyright (C) 2011 Joris Vankerschaver (jv@caltech.edu) +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from . import free_module_element +from sage.symbolic.expression import Expression + + +def apply_map(phi): + """ + Returns a function that applies phi to its argument. + + EXAMPLES:: + + sage: from sage.modules.vector_symbolic_sparse import apply_map + sage: v = vector([1,2,3], sparse=True) + sage: f = apply_map(lambda x: x+1) + sage: f(v) + (2, 3, 4) + + """ + def apply(self, *args, **kwds): + """ + Generic function used to implement common symbolic operations + elementwise as methods of a vector. + + EXAMPLES:: + + sage: var('x,y') + (x, y) + sage: v = vector([sin(x)^2 + cos(x)^2, log(x*y), sin(x/(x^2 + x)), factorial(x+1)/factorial(x)], sparse=True) + sage: v.simplify_trig() + (1, log(x*y), sin(1/(x + 1)), factorial(x + 1)/factorial(x)) + sage: v.canonicalize_radical() + (cos(x)^2 + sin(x)^2, log(x) + log(y), sin(1/(x + 1)), factorial(x + 1)/factorial(x)) + sage: v.simplify_rational() + (cos(x)^2 + sin(x)^2, log(x*y), sin(1/(x + 1)), factorial(x + 1)/factorial(x)) + sage: v.simplify_factorial() + (cos(x)^2 + sin(x)^2, log(x*y), sin(x/(x^2 + x)), x + 1) + sage: v.simplify_full() + (1, log(x*y), sin(1/(x + 1)), x + 1) + + sage: v = vector([sin(2*x), sin(3*x)], sparse=True) + sage: v.simplify_trig() + (2*cos(x)*sin(x), (4*cos(x)^2 - 1)*sin(x)) + sage: v.simplify_trig(False) + (sin(2*x), sin(3*x)) + sage: v.simplify_trig(expand=False) + (sin(2*x), sin(3*x)) + """ + return self.apply_map(lambda x: phi(x, *args, **kwds)) + apply.__doc__ += "\nSee Expression." + phi.__name__ + "() for optional arguments." + return apply + + +class Vector_symbolic_sparse(free_module_element.FreeModuleElement_generic_sparse): + pass + + +# Add elementwise methods. +for method in ['simplify', 'simplify_factorial', + 'simplify_log', 'simplify_rational', + 'simplify_trig', 'simplify_full', 'trig_expand', + 'canonicalize_radical', 'trig_reduce']: + setattr(Vector_symbolic_sparse, method, apply_map(getattr(Expression, method))) diff --git a/src/sage/modules/with_basis/__init__.py b/src/sage/modules/with_basis/__init__.py deleted file mode 100644 index 8cafbaa9b89..00000000000 --- a/src/sage/modules/with_basis/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -r""" -Concrete classes related to modules with a distinguished basis - -This module provides concrete classes for various constructions -related to modules with a distinguished basis: - -- :mod:`morphism` -- Concrete classes for morphisms of modules with basis - -.. SEEALSO:: The category :class:`ModulesWithBasis` -""" diff --git a/src/sage/modules/with_basis/all.py b/src/sage/modules/with_basis/all.py new file mode 100644 index 00000000000..1f352bcc768 --- /dev/null +++ b/src/sage/modules/with_basis/all.py @@ -0,0 +1,13 @@ +r""" +Concrete classes related to modules with a distinguished basis + +This module provides concrete classes for various constructions +related to modules with a distinguished basis: + +- :mod:`morphism` -- Concrete classes for morphisms of modules with basis + +.. SEEALSO:: The category :class:`ModulesWithBasis` +""" +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) diff --git a/src/sage/modules/with_basis/cell_module.py b/src/sage/modules/with_basis/cell_module.py index c51d43c32b6..66d72f648f8 100644 --- a/src/sage/modules/with_basis/cell_module.py +++ b/src/sage/modules/with_basis/cell_module.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Cell modules """ diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index 06947bfb3b0..90f7b8ec580 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -23,14 +23,9 @@ from sage.structure.richcmp cimport richcmp, rich_to_bool from cpython.object cimport Py_NE, Py_EQ from sage.misc.repr import repr_lincomb -from sage.misc.cachefunc import cached_method -from sage.misc.lazy_attribute import lazy_attribute from sage.misc.superseded import deprecation from sage.typeset.ascii_art import AsciiArt, empty_ascii_art, ascii_art from sage.typeset.unicode_art import UnicodeArt, empty_unicode_art, unicode_art -from sage.categories.category import Category -from sage.categories.sets_cat import Sets -from sage.categories.modules_with_basis import ModulesWithBasis from sage.data_structures.blas_dict cimport add, negate, scal, axpy @@ -82,9 +77,9 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: [i for i in sorted(f)] [('a', 1), ('c', 3)] - sage: s = SymmetricFunctions(QQ).schur() - sage: a = s([2,1]) + s([3]) - sage: [i for i in sorted(a)] + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat + sage: a = s([2,1]) + s([3]) # needs sage.combinat + sage: [i for i in sorted(a)] # needs sage.combinat [([2, 1], 1), ([3], 1)] """ return iter(self._monomial_coefficients.items()) @@ -107,6 +102,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: 'b' in f False + sage: # needs sage.combinat sage: s = SymmetricFunctions(QQ).schur() sage: a = s([2,1]) + s([3]) sage: Partition([2,1]) in a @@ -133,6 +129,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: hash(f) == hash(B['a'] + 4*B['c']) False + sage: # needs sage.combinat sage: F = RootSystem(['A',2]).ambient_space() sage: f = F.simple_root(0) sage: hash(f) == hash(F.simple_root(0)) @@ -264,6 +261,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): :: + sage: # needs sage.combinat sage: s = SymmetricFunctions(QQ).schur() sage: a = s([2,1])+2*s([3,2]) sage: d = a.monomial_coefficients() @@ -347,6 +345,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): """ TESTS:: + sage: # needs sage.combinat sage: M = QuasiSymmetricFunctions(QQ).M() sage: ascii_art(M[1,3]**2) # indirect doctest 4*M + 2*M + 2*M + 2*M + 2*M + M @@ -424,8 +423,8 @@ cdef class IndexedFreeModuleElement(ModuleElement): """ TESTS:: - sage: M = QuasiSymmetricFunctions(QQ).M() - sage: unicode_art(M[1,1]**2) # indirect doctest + sage: M = QuasiSymmetricFunctions(QQ).M() # needs sage.combinat + sage: unicode_art(M[1,1]**2) # indirect doctest # needs sage.combinat 6*M + 2*M + 2*M + 2*M + M โ”Œโ” โ”Œโ”ฌโ” โ”Œโ” โ”Œโ” โ”Œโ”ฌโ” โ”œโ”ค โ”œโ”ผโ”˜ โ”Œโ”ผโ”ค โ”œโ”ค โ”Œโ”ผโ”ผโ”˜ @@ -435,7 +434,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): The following test failed before :trac:`26850`:: - sage: unicode_art([M.zero()]) # indirect doctest + sage: unicode_art([M.zero()]) # indirect doctest # needs sage.combinat [ 0 ] """ from sage.misc.repr import coeff_repr @@ -506,9 +505,9 @@ cdef class IndexedFreeModuleElement(ModuleElement): :: - sage: QS3 = SymmetricGroupAlgebra(QQ,3) - sage: a = 2 + QS3([2,1,3]) - sage: latex(a) #indirect doctest + sage: QS3 = SymmetricGroupAlgebra(QQ, 3) # needs sage.combinat + sage: a = 2 + QS3([2,1,3]) # needs sage.combinat + sage: latex(a) #indirect doctest # needs sage.combinat 2 [1, 2, 3] + [2, 1, 3] :: @@ -568,6 +567,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): :: + sage: # needs sage.combinat sage: s = SymmetricFunctions(QQ).schur() sage: a = s([2,1]) sage: b = s([1,1,1]) @@ -595,6 +595,8 @@ cdef class IndexedFreeModuleElement(ModuleElement): Traceback (most recent call last): ... TypeError: do not know how to make x (= 0) an element of self (=Free module generated by {1, 2, 3} over Rational Field) + + sage: # needs sage.combinat sage: F = AlgebrasWithBasis(QQ).example() sage: F.one() == 1 True @@ -605,10 +607,10 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: int(2) == 2 * F.one() True - sage: S = SymmetricFunctions(QQ); s = S.s(); p = S.p() - sage: p[2] == s[2] - s[1, 1] + sage: S = SymmetricFunctions(QQ); s = S.s(); p = S.p() # needs sage.combinat + sage: p[2] == s[2] - s[1, 1] # needs sage.combinat True - sage: p[2] == s[2] + sage: p[2] == s[2] # needs sage.combinat False This feature is disputable, in particular since it can make @@ -618,6 +620,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): can vary because their indices are incomparable with ``cmp``. The following test did fail before :trac:`12489` :: + sage: # needs sage.combinat sage: F = CombinatorialFreeModule(QQ, Subsets([1,2,3])) sage: x = F.an_element() sage: (x+F.zero()).terms() # random @@ -630,7 +633,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): TESTS:: sage: TestSuite(F1).run() - sage: TestSuite(F).run() + sage: TestSuite(F).run() # needs sage.combinat """ cdef IndexedFreeModuleElement elt = <IndexedFreeModuleElement> other @@ -658,6 +661,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): :: + sage: # needs sage.combinat sage: s = SymmetricFunctions(QQ).schur() sage: s([2,1]) + s([5,4]) # indirect doctest s[2, 1] + s[5, 4] @@ -681,8 +685,8 @@ cdef class IndexedFreeModuleElement(ModuleElement): :: - sage: s = SymmetricFunctions(QQ).schur() - sage: -s([2,1]) # indirect doctest + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat + sage: -s([2,1]) # indirect doctest # needs sage.combinat -s[2, 1] """ return type(self)(self._parent, negate(self._monomial_coefficients)) @@ -698,8 +702,8 @@ cdef class IndexedFreeModuleElement(ModuleElement): :: - sage: s = SymmetricFunctions(QQ).schur() - sage: s([2,1]) - s([5,4]) # indirect doctest + sage: s = SymmetricFunctions(QQ).schur() # needs sage.combinat + sage: s([2,1]) - s([5,4]) # indirect doctest # needs sage.combinat s[2, 1] - s[5, 4] """ return type(self)(self._parent, @@ -713,6 +717,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): EXAMPLES:: + sage: # needs sage.combinat sage: p = Partition([2,1]) sage: q = Partition([1,1,1]) sage: s = SymmetricFunctions(QQ).schur() @@ -770,6 +775,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): More examples:: + sage: # needs sage.combinat sage: QS3 = SymmetricGroupAlgebra(QQ, 3) sage: a = 2*QS3([1,2,3]) + 4*QS3([3,2,1]) sage: a._vector_() @@ -786,7 +792,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): If ``new_base_ring`` is specified, then a vector over ``new_base_ring`` is returned:: - sage: a._vector_(RDF) + sage: a._vector_(RDF) # needs sage.combinat (2.0, 0.0, 0.0, 0.0, 0.0, 4.0) .. NOTE:: @@ -869,6 +875,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: (3/2)*el 3/2*B[[3, 1, 2]] + sage: # needs sage.combinat sage: P.<q> = QQ['q'] sage: F = FractionField(P) sage: V = CombinatorialFreeModule(F, Words()) diff --git a/src/sage/modules/with_basis/invariant.py b/src/sage/modules/with_basis/invariant.py index 12565a411e2..71a4c938424 100644 --- a/src/sage/modules/with_basis/invariant.py +++ b/src/sage/modules/with_basis/invariant.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups r""" Invariant modules """ diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index 6a43cab1461..b94629a8dfe 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -396,9 +396,9 @@ def __call__(self, *args): Add more tests for multi-parameter module morphisms. """ before = args[0:self._position] - after = args[self._position+1:len(args)] + after = args[self._position + 1:len(args)] x = args[self._position] - assert(x.parent() is self.domain()) + assert x.parent() is self.domain() mc = x.monomial_coefficients(copy=False) if self._is_module_with_basis_over_same_base_ring: @@ -690,11 +690,10 @@ def __init__(self, triangular="upper", unitriangular=False, self._inverse_on_support = inverse_on_support - if invertible is None and (domain.basis().keys() == codomain.basis().keys()) and \ - (self._inverse_on_support==identity or domain in Modules.FiniteDimensional): + (self._inverse_on_support == identity or domain in Modules.FiniteDimensional): invertible = True - self._invertible=invertible + self._invertible = invertible def _richcmp_(self, other, op): r""" @@ -773,10 +772,10 @@ def _test_triangular(self, **options): bs, co = self._dominant_item(on_basis(x)) if self._unitriangular: tester.assertEqual(co, self.domain().base_ring().one(), - LazyFormat("morphism is not unitriangular on %s")%(x)) + LazyFormat("morphism is not unitriangular on %s") % (x)) xback = self._inverse_on_support(bs) tester.assertEqual(x, xback, - LazyFormat("morphism is not triangular on %s")%(x)) + LazyFormat("morphism is not triangular on %s") % (x)) def __invert__(self): """ @@ -1128,7 +1127,7 @@ def cokernel_basis_indices(self): raise NotImplementedError("cokernel_basis_indices implemented only for morphisms with a finite dimensional codomain") return [i for i in self.codomain().basis().keys() if self._inverse_on_support(i) is None] - def cokernel_projection(self, category = None): + def cokernel_projection(self, category=None): """ Return a projection on the co-kernel of ``self``. @@ -1453,12 +1452,12 @@ def __init__(self, domain, diagonal, codomain=None, category=None): "and the same basis indexing") from collections.abc import Callable if not isinstance(diagonal, Callable): - raise ValueError("diagonal (=%s) should be a function"%diagonal) + raise ValueError("diagonal (=%s) should be a function" % diagonal) if category is None: category = ModulesWithBasis(domain.base_ring()) ModuleMorphismByLinearity.__init__( self, domain=domain, codomain=codomain, category=category) - self._diagonal=diagonal + self._diagonal = diagonal def _richcmp_(self, other, op): r""" @@ -1518,7 +1517,7 @@ def __invert__(self): """ return self.codomain().module_morphism( diagonal=pointwise_inverse_function(self._diagonal), - codomain=self.domain(), category = self.category_for()) + codomain=self.domain(), category=self.category_for()) def pointwise_inverse_function(f): diff --git a/src/sage/modules/with_basis/representation.py b/src/sage/modules/with_basis/representation.py index 815871e038d..a781fc39ec3 100644 --- a/src/sage/modules/with_basis/representation.py +++ b/src/sage/modules/with_basis/representation.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups """ Representations of a semigroup @@ -494,7 +495,6 @@ def side(self): """ return "left" if self._left_repr else "right" - class Element(CombinatorialFreeModule.Element): def _acted_upon_(self, scalar, self_on_left=False): """ diff --git a/src/sage/monoids/__init__.py b/src/sage/monoids/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/monoids/automatic_semigroup.py b/src/sage/monoids/automatic_semigroup.py index dd1a17bd575..2604f0f2533 100644 --- a/src/sage/monoids/automatic_semigroup.py +++ b/src/sage/monoids/automatic_semigroup.py @@ -557,7 +557,7 @@ def lift(self, x): sage: [m.lift() for m in M] [1, 3, 5, 9, 0, 10, 12, 6] """ - assert(x in self) + assert x in self return x.lift() def semigroup_generators(self): @@ -744,14 +744,14 @@ def product(self, x, y): sage: a*b [1] """ - assert(x in self) - assert(y in self) + assert x in self + assert y in self red = y._reduced_word if red is None: return self._retract(self._mul(x.lift(), y.lift())) - else: - for i in red: - x = x.transition(i) + + for i in red: + x = x.transition(i) return x def from_reduced_word(self, l): @@ -942,7 +942,7 @@ def transition(self, i): [1, 2] """ parent = self.parent() - assert(i in parent._generators.keys()) + assert i in parent._generators.keys() return parent._retract(parent._mul(self.lift(), parent._generators_in_ambient[i])) def _repr_(self): diff --git a/src/sage/monoids/free_abelian_monoid.py b/src/sage/monoids/free_abelian_monoid.py index 54771b247e4..6d1b69b59bb 100644 --- a/src/sage/monoids/free_abelian_monoid.py +++ b/src/sage/monoids/free_abelian_monoid.py @@ -103,9 +103,11 @@ def create_key(self, n, names): n = int(n) names = normalize_names(n, names) return (n, names) + def create_object(self, version, key): return FreeAbelianMonoid_class(*key) + FreeAbelianMonoid_factory = FreeAbelianMonoidFactory("sage.monoids.free_abelian_monoid.FreeAbelianMonoid_factory") @@ -202,7 +204,7 @@ def __init__(self, n, names): def __repr__(self): n = self.__ngens - return "Free abelian monoid on %s generators %s"%(n,self.gens()) + return "Free abelian monoid on %s generators %s" % (n,self.gens()) def __call__(self, x): """ @@ -220,7 +222,6 @@ def __call__(self, x): return x return self.element_class(self, x) - def __contains__(self, x): """ Return True if `x` is an element of this abelian monoid. diff --git a/src/sage/monoids/free_abelian_monoid_element.pxd b/src/sage/monoids/free_abelian_monoid_element.pxd index 74dd0f7b5ed..092cd343f05 100644 --- a/src/sage/monoids/free_abelian_monoid_element.pxd +++ b/src/sage/monoids/free_abelian_monoid_element.pxd @@ -13,4 +13,3 @@ cdef class FreeAbelianMonoidElement(MonoidElement): cdef FreeAbelianMonoidElement x = <FreeAbelianMonoidElement>(t.__new__(t)) x._init(self._n, self._parent) return x - diff --git a/src/sage/monoids/free_abelian_monoid_element.pyx b/src/sage/monoids/free_abelian_monoid_element.pyx index 87c9f91f445..65df8efe613 100644 --- a/src/sage/monoids/free_abelian_monoid_element.pyx +++ b/src/sage/monoids/free_abelian_monoid_element.pyx @@ -26,13 +26,13 @@ The list is a copy, so changing the list does not change the element:: a^7*b^2*d*e """ -#***************************************************************************** +# *************************************************************************** # Copyright (C) 2006 William Stein <wstein@gmail.com> # Copyright (C) 2005 David Kohel <kohel@maths.usyd.edu> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from cysignals.memory cimport check_allocarray, sig_free from cysignals.signals cimport sig_on, sig_off @@ -40,6 +40,7 @@ from sage.structure.richcmp cimport rich_to_bool from sage.rings.integer cimport Integer, _Integer_from_mpz from sage.libs.gmp.mpz cimport * + def is_FreeAbelianMonoidElement(x): r""" Queries whether ``x`` is an object of type ``FreeAbelianMonoidElement``. @@ -55,6 +56,7 @@ def is_FreeAbelianMonoidElement(x): """ return isinstance(x, FreeAbelianMonoidElement) + cdef class FreeAbelianMonoidElement(MonoidElement): cdef int _init(self, Py_ssize_t n, Parent parent) except -1: """ @@ -307,7 +309,7 @@ cdef class FreeAbelianMonoidElement(MonoidElement): a^2*b^4 """ if not isinstance(y, FreeAbelianMonoidElement): - raise TypeError("argument y (= %s) is of wrong type"%y) + raise TypeError("argument y (= %s) is of wrong type" % y) cdef FreeAbelianMonoidElement s, z, r s = self r = y diff --git a/src/sage/monoids/free_monoid_element.py b/src/sage/monoids/free_monoid_element.py index 23d2a8abc66..341a88a9ebe 100644 --- a/src/sage/monoids/free_monoid_element.py +++ b/src/sage/monoids/free_monoid_element.py @@ -121,9 +121,9 @@ def _repr_(self): g = x[int(v[i][0])] e = v[i][1] if e == 1: - s += "%s"%g + s += "%s" % g else: - s += "%s^%s"%(g,e) + s += "%s^%s" % (g,e) if len(s) == 0: s = "1" return s diff --git a/src/sage/monoids/hecke_monoid.py b/src/sage/monoids/hecke_monoid.py index 8db027b6d35..98f41dc4552 100644 --- a/src/sage/monoids/hecke_monoid.py +++ b/src/sage/monoids/hecke_monoid.py @@ -59,5 +59,5 @@ def HeckeMonoid(W): ambient_monoid = FiniteSetMaps(W, action="right") pi = W.simple_projections(length_increasing=True).map(ambient_monoid) H = ambient_monoid.submonoid(pi) - H.rename("0-Hecke monoid of the %s"%W) + H.rename("0-Hecke monoid of the %s" % W) return H diff --git a/src/sage/monoids/string_monoid.py b/src/sage/monoids/string_monoid.py index 5f4e3819b5e..55045fd7f14 100644 --- a/src/sage/monoids/string_monoid.py +++ b/src/sage/monoids/string_monoid.py @@ -226,7 +226,7 @@ def encoding(self, S, padic=False): n = ord(S[i]) bits = [] for i in range(8): - bits.append(n%2) + bits.append(n % 2) n = n >> 1 if not padic: bits.reverse() @@ -247,6 +247,7 @@ def encoding(self, S, padic=False): # """ # return 2 + BinaryStrings = BinaryStringMonoid @@ -309,6 +310,7 @@ def __call__(self, x, check=True): else: raise TypeError("Argument x (= %s) is of the wrong type." % x) + OctalStrings = OctalStringMonoid @@ -421,6 +423,7 @@ def encoding(self, S, padic=False): hex_string.extend(hex_chars) return self(hex_string) + HexadecimalStrings = HexadecimalStringMonoid @@ -487,6 +490,7 @@ def __call__(self, x, check=True): else: raise TypeError("Argument x (= %s) is of the wrong type." % x) + Radix64Strings = Radix64StringMonoid @@ -798,4 +802,5 @@ def encoding(self, S): """ return self(strip_encoding(S)) + AlphabeticStrings = AlphabeticStringMonoid diff --git a/src/sage/numerical/all__sagemath_polyhedra.py b/src/sage/numerical/all__sagemath_polyhedra.py new file mode 100644 index 00000000000..6de2a9af502 --- /dev/null +++ b/src/sage/numerical/all__sagemath_polyhedra.py @@ -0,0 +1,9 @@ +from sage.misc.lazy_import import lazy_import + +lazy_import("sage.numerical.mip", ["MixedIntegerLinearProgram"]) +lazy_import("sage.numerical.sdp", ["SemidefiniteProgram"]) +lazy_import("sage.numerical.backends.generic_backend", ["default_mip_solver"]) +lazy_import("sage.numerical.backends.generic_sdp_backend", ["default_sdp_solver"]) + +lazy_import("sage.numerical.interactive_simplex_method", + ["InteractiveLPProblem", "InteractiveLPProblemStandardForm"]) diff --git a/src/sage/dynamics/arithmetic_dynamics/__init__.py b/src/sage/numerical/backends/all__sagemath_polyhedra.py similarity index 100% rename from src/sage/dynamics/arithmetic_dynamics/__init__.py rename to src/sage/numerical/backends/all__sagemath_polyhedra.py diff --git a/src/sage/numerical/backends/cvxopt_backend.pyx b/src/sage/numerical/backends/cvxopt_backend.pyx index 10358c3a8f9..22bdfd20ea6 100644 --- a/src/sage/numerical/backends/cvxopt_backend.pyx +++ b/src/sage/numerical/backends/cvxopt_backend.pyx @@ -137,7 +137,7 @@ cdef class CVXOPTBackend(GenericBackend): This amounts to adding a new column to the matrix. By default, the variable is both positive and real. Variable types are always continuous, and thus the parameters - ``binary``, ``integer``, and ``continuous`` have no effect. + ``binary``, ``integer``, and ``continuous`` have no effect. INPUT: diff --git a/src/sage/numerical/backends/cvxopt_sdp_backend.pyx b/src/sage/numerical/backends/cvxopt_sdp_backend.pyx index c654f7f21a2..bb999559ee2 100644 --- a/src/sage/numerical/backends/cvxopt_sdp_backend.pyx +++ b/src/sage/numerical/backends/cvxopt_sdp_backend.pyx @@ -20,7 +20,7 @@ AUTHORS: #***************************************************************************** from sage.numerical.sdp import SDPSolverException -from sage.matrix.all import Matrix +from sage.matrix.constructor import Matrix from .matrix_sdp_backend cimport MatrixSDPBackend diff --git a/src/sage/numerical/backends/cvxpy_backend.pxd b/src/sage/numerical/backends/cvxpy_backend.pxd new file mode 100644 index 00000000000..ed4d63ccc63 --- /dev/null +++ b/src/sage/numerical/backends/cvxpy_backend.pxd @@ -0,0 +1,40 @@ +############################################################################## +# Copyright (C) 2010 Nathann Cohen <nathann.cohen@gmail.com> +# Copyright (C) 2022 Matthias Koeppe <mkoeppe@math.ucdavis.edu> +# Distributed under the terms of the GNU General Public License (GPL) +# The full text of the GPL is available at: +# http://www.gnu.org/licenses/ +############################################################################## + +from sage.numerical.backends.generic_backend cimport GenericBackend + +cdef class CVXPYBackend(GenericBackend): + + cdef object variables + cdef object problem + cdef object prob_name + cdef object constraint_names + + cdef object _cvxpy_solver + cdef object _cvxpy_solver_args + + cdef list objective_coefficients + cdef list Matrix + + cdef list row_lower_bound + cdef list row_upper_bound + cdef list col_lower_bound + cdef list col_upper_bound + + cpdef int add_variable(self, + lower_bound=*, + upper_bound=*, + binary=*, + continuous=*, + integer=*, + obj=*, + name=*, + coefficients=*) \ + except -1 + + cpdef cvxpy_problem(self) diff --git a/src/sage/numerical/backends/cvxpy_backend.pyx b/src/sage/numerical/backends/cvxpy_backend.pyx new file mode 100644 index 00000000000..4ffae61809a --- /dev/null +++ b/src/sage/numerical/backends/cvxpy_backend.pyx @@ -0,0 +1,932 @@ +# sage.doctest: optional - cvxpy +r""" +CVXPY Backend + +AUTHORS: + +- Nathann Cohen (2010-10) : generic_backend template +- Matthias Koeppe (2022-03) : this backend + +""" +# **************************************************************************** +# Copyright (C) 2010 Nathann Cohen <nathann.cohen@gmail.com> +# Copyright (C) 2022 Matthias Koeppe <mkoeppe@math.ucdavis.edu> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.numerical.mip import MIPSolverException +from sage.rings.real_double import RDF +from copy import copy +import cvxpy +from cvxpy.atoms.affine.add_expr import AddExpression +from cvxpy.expressions.constants import Constant +from cvxpy.constraints.zero import Equality + +cdef class CVXPYBackend: + """ + MIP Backend that delegates to CVXPY. + + CVXPY interfaces to various solvers, see + https://www.cvxpy.org/install/index.html#install and + https://www.cvxpy.org/tutorial/advanced/index.html#choosing-a-solver + + EXAMPLES:: + + sage: import cvxpy + sage: cvxpy.installed_solvers() # random + + Using the default solver determined by CVXPY:: + + sage: p = MixedIntegerLinearProgram(solver="CVXPY"); p.solve() + 0.0 + + Using a specific solver:: + + sage: p = MixedIntegerLinearProgram(solver="CVXPY/OSQP"); p.solve() + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/ECOS"); p.solve() + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/SCS"); p.solve() + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/SciPy/HiGHS"); p.solve() + 0.0 + + Open-source solvers provided by optional packages:: + + sage: p = MixedIntegerLinearProgram(solver="CVXPY/GLPK"); p.solve() # optional - cvxopt + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/GLPK_MI"); p.solve() # optional - cvxopt + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/CVXOPT"); p.solve() # optional - cvxopt + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/GLOP"); p.solve() # optional - ortools + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/PDLP"); p.solve() # optional - ortools + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/CBC"); p.solve() # optional - cylp + 0.0 + + Non-free solvers:: + + sage: p = MixedIntegerLinearProgram(solver="CVXPY/Gurobi"); p.solve() # optional - gurobi + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/CPLEX"); p.solve() # optional - cplex + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/MOSEK"); p.solve() # optional - mosek + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/SCIP"); p.solve() # optional - pyscipopt + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/XPRESS"); p.solve() # optional - xpress + 0.0 + sage: p = MixedIntegerLinearProgram(solver="CVXPY/NAG"); p.solve() # optional - naginterfaces + 0.0 + """ + + def __cinit__(self, maximization=True, base_ring=None, cvxpy_solver=None, cvxpy_solver_args=None): + """ + Cython constructor + + INPUT: + + - ``maximization`` (boolean, default: ``True``) -- Whether this is a + maximization or minimization problem. + + - ``base_ring`` (optional): Must be ``RDF`` if provided. + + - ``cvxpy_solver (optional): Passed to :meth:`cvxpy.Problem.solve` as the + parameter ``solver``. + + - ``cvxpy_solver_args`` (optional dict): Passed to :meth:`cvxpy.Problem.solve` + as additional keyword arguments. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + """ + if base_ring is None: + base_ring = RDF + elif base_ring != RDF: + raise ValueError('base_ring must be RDF') + + if cvxpy_solver_args is None: + cvxpy_solver_args = {} + + if isinstance(cvxpy_solver, str): + cvxpy_solver = cvxpy_solver.upper() + if cvxpy_solver.startswith("SCIPY/"): + cvxpy_solver_args['scipy_options'] = {"method": cvxpy_solver[len("SCIPY/"):]} + cvxpy_solver = "SCIPY" + cvxpy_solver = getattr(cvxpy, cvxpy_solver) + self._cvxpy_solver = cvxpy_solver + self._cvxpy_solver_args = cvxpy_solver_args + + self.set_verbosity(0) + self.variables = [] + self.constraint_names = [] + self.Matrix = [] + self.row_lower_bound = [] + self.row_upper_bound = [] + self.col_lower_bound = [] + self.col_upper_bound = [] + self.objective_coefficients = [] + self.obj_constant_term = 0.0 + if maximization: + objective = cvxpy.Maximize(0) + else: + objective = cvxpy.Minimize(0) + self.problem = cvxpy.Problem(objective, ()) + + cpdef __copy__(self): + """ + Returns a copy of self. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = MixedIntegerLinearProgram(solver="CVXPY") + sage: b = p.new_variable() + sage: p.add_constraint(b[1] + b[2] <= 6) + sage: p.set_objective(b[1] + b[2]) + sage: cp = copy(p.get_backend()) + sage: cp.solve() + 0 + sage: cp.get_objective_value() # abs tol 1e-7 + 6.0 + """ + cdef CVXPYBackend cp = type(self)(base_ring=self.base_ring()) + cp.problem = self.problem # it's considered immutable; so no need to copy. + cp.variables = copy(self.variables) + cp.constraint_names = copy(self.constraint_names) + cp.Matrix = [row[:] for row in self.Matrix] + cp.row_lower_bound = self.row_lower_bound[:] + cp.row_upper_bound = self.row_upper_bound[:] + cp.col_lower_bound = self.col_lower_bound[:] + cp.col_upper_bound = self.col_upper_bound[:] + cp.objective_coefficients = self.objective_coefficients[:] + cp.obj_constant_term = self.obj_constant_term + return cp + + cpdef cvxpy_problem(self): + return self.problem + + def cvxpy_variables(self): + return self.variables + + cpdef int add_variable(self, lower_bound=0, upper_bound=None, + binary=False, continuous=True, integer=False, + obj=None, name=None, coefficients=None) except -1: + ## coefficients is an extension in this backend, + ## and a proposed addition to the interface, to unify this with add_col. + """ + Add a variable. + + This amounts to adding a new column to the matrix. By default, + the variable is both nonnegative and real. + + INPUT: + + - ``lower_bound`` - the lower bound of the variable (default: 0) + + - ``upper_bound`` - the upper bound of the variable (default: ``None``) + + - ``binary`` - ``True`` if the variable is binary (default: ``False``). + + - ``continuous`` - ``True`` if the variable is continuous (default: ``True``). + + - ``integer`` - ``True`` if the variable is integral (default: ``False``). + + - ``obj`` - (optional) coefficient of this variable in the objective function (default: 0) + + - ``name`` - an optional name for the newly added variable (default: ``None``). + + - ``coefficients`` -- (optional) an iterable of pairs ``(i, v)``. In each + pair, ``i`` is a row index (integer) and ``v`` is a + value (element of :meth:`base_ring`). + + OUTPUT: The index of the newly created variable + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.ncols() + 0 + sage: p.add_variable() + 0 + sage: p.ncols() + 1 + sage: p.add_variable(continuous=True, integer=True) + Traceback (most recent call last): + ... + ValueError: ... + sage: p.add_variable(name='x',obj=1) + 1 + sage: p.col_name(1) + 'x' + sage: p.objective_coefficient(1) + 1.0 + """ + cdef int vtype = int(binary) + int(continuous) + int(integer) + if vtype == 0: + continuous = True + elif vtype != 1: + raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.") + + for i in range(len(self.Matrix)): + self.Matrix[i].append(0.0) + if lower_bound is not None: + lower_bound = float(lower_bound) + self.col_lower_bound.append(lower_bound) + if upper_bound is not None: + upper_bound = float(upper_bound) + self.col_upper_bound.append(upper_bound) + if obj is None: + obj = 0.0 + else: + obj = float(obj) + self.objective_coefficients.append(obj) + + if name is None: + name = f'x_{self.ncols()}' + + if binary: + variable = cvxpy.Variable(name=name, boolean=True) + elif integer: + variable = cvxpy.Variable(name=name, integer=True) + else: + variable = cvxpy.Variable(name=name) + + self.variables.append(variable) + index = self.ncols() - 1 + + if coefficients is not None: + constraints = list(self.problem.constraints) + for i, v in coefficients: + if not isinstance(constraints[i], Equality): + raise NotImplementedError('adding coefficients to inequalities is ambiguous ' + 'because cvxpy rewrites all inequalities as <=') + constraints[i] = type(constraints[i])(constraints[i].args[0] + float(v) * variable, + constraints[i].args[1]) + self.problem = cvxpy.Problem(self.problem.objective, constraints) + + self.add_linear_constraint([(index, 1)], lower_bound, upper_bound) + + if obj: + objective = type(self.problem.objective)(self.problem.objective.args[0] + + obj * variable) + self.problem = cvxpy.Problem(objective, self.problem.constraints) + + return index + + cpdef set_verbosity(self, int level): + """ + Set the log (verbosity) level + + This is currently ignored. + + INPUT: + + - ``level`` (integer) -- From 0 (no verbosity) to 3. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.set_verbosity(2) + """ + pass + + cpdef add_linear_constraint(self, coefficients, lower_bound, upper_bound, name=None): + """ + Add a linear constraint. + + INPUT: + + - ``coefficients`` -- an iterable of pairs ``(i, v)``. In each + pair, ``i`` is a variable index (integer) and ``v`` is a + value (element of :meth:`base_ring`). + + - ``lower_bound`` -- element of :meth:`base_ring` or + ``None``. The lower bound. + + - ``upper_bound`` -- element of :meth:`base_ring` or + ``None``. The upper bound. + + - ``name`` -- string or ``None``. Optional name for this row. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_variables(5) + 4 + sage: index = p.nrows() + sage: p.add_linear_constraint( zip(range(5), range(5)), 2, 2) + sage: p.row(index) + ([1, 2, 3, 4], [1, 2, 3, 4]) + sage: p.row_bounds(index) + (2, 2) + sage: p.add_linear_constraint( zip(range(5), range(5)), 1, 1, name='foo') + sage: p.row_name(1) + 'constraint_1' + """ + last = len(self.Matrix) + self.Matrix.append([]) + for i in range(len(self.objective_coefficients)): + self.Matrix[last].append(0.0) + for a in coefficients: + self.Matrix[last][a[0]] = a[1] + + self.row_lower_bound.append(lower_bound) + self.row_upper_bound.append(upper_bound) + + terms = [v * self.variables[i] for i, v in coefficients] + if terms: + expr = AddExpression(terms) + else: + expr = Constant(0) + constraints = list(self.problem.constraints) + if lower_bound is not None and lower_bound == upper_bound: + constraints.append(expr == upper_bound) + elif lower_bound is not None: + constraints.append(lower_bound <= expr) + elif upper_bound is not None: + constraints.append(expr <= upper_bound) + self.constraint_names.append(name) + self.problem = cvxpy.Problem(self.problem.objective, constraints) + + cpdef add_col(self, indices, coeffs): + """ + Add a column. + + INPUT: + + - ``indices`` (list of integers) -- this list contains the + indices of the constraints in which the variable's + coefficient is nonzero + + - ``coeffs`` (list of real values) -- associates a coefficient + to the variable in each of the constraints in which it + appears. Namely, the i-th entry of ``coeffs`` corresponds to + the coefficient of the variable in the constraint + represented by the i-th entry in ``indices``. + + .. NOTE:: + + ``indices`` and ``coeffs`` are expected to be of the same + length. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.ncols() + 0 + sage: p.nrows() + 0 + sage: p.add_linear_constraints(5, 0, None) + sage: p.add_col(list(range(5)), list(range(5))) + Traceback (most recent call last): + ... + NotImplementedError: adding coefficients to inequalities is ambiguous because cvxpy rewrites all inequalities as <= + sage: p.nrows() + 5 + """ + for i in range(len(self.Matrix)): + self.Matrix[i].append(0) + for i in range(len(indices)): + self.Matrix[indices[i]][len(self.Matrix[indices[i]]) - 1] = coeffs[i] + + self.col_lower_bound.append(None) + self.col_upper_bound.append(None) + #self.objective_coefficients.append(0) goes to "self.add_variable" + self.add_variable(coefficients=zip(indices, coeffs)) + + cpdef set_objective(self, list coeff, d=0.0): + """ + Set the objective function. + + INPUT: + + - ``coeff`` - a list of real values, whose ith element is the + coefficient of the ith variable in the objective function. + + - ``d`` (double) -- the constant term in the linear function (set to `0` by default) + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_variables(5) + 4 + sage: p.set_objective([1, 1, 2, 1, 3]) + sage: [p.objective_coefficient(x) for x in range(5)] + [1.0, 1.0, 2.0, 1.0, 3.0] + """ + if self.variables: + expr = AddExpression([c * x for c, x in zip(coeff, self.variables)]) + for i in range(len(coeff)): + self.objective_coefficients[i] = float(coeff[i]) + else: + expr = Constant(0) + objective = type(self.problem.objective)(expr) + constraints = list(self.problem.constraints) + self.problem = cvxpy.Problem(objective, constraints) + self.obj_constant_term = d + + cpdef set_sense(self, int sense): + """ + Set the direction (maximization/minimization). + + INPUT: + + - ``sense`` (integer) : + + * +1 => Maximization + * -1 => Minimization + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.is_maximization() + True + sage: p.set_sense(-1) + sage: p.is_maximization() + False + """ + expr = self.problem.objective.args[0] + if sense == 1: + objective = cvxpy.Maximize(expr) + else: + objective = cvxpy.Minimize(expr) + self.problem = cvxpy.Problem(objective, self.problem.constraints) + + cpdef objective_coefficient(self, int variable, coeff=None): + """ + Set or get the coefficient of a variable in the objective function + + INPUT: + + - ``variable`` (integer) -- the variable's id + + - ``coeff`` (double) -- its coefficient or ``None`` for + reading (default: ``None``) + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_variable() + 0 + sage: p.objective_coefficient(0) + 0.0 + sage: p.objective_coefficient(0, 2) + sage: p.objective_coefficient(0) + 2 + """ + if coeff is not None: + self.objective_coefficients[variable] = coeff + expr = self.problem.objective.args[0] + coeff * self.variables[variable] + objective = type(self.problem.objective)(expr) + constraints = list(self.problem.constraints) + self.problem = cvxpy.Problem(objective, constraints) + else: + if variable < len(self.objective_coefficients): + return self.objective_coefficients[variable] + else: + return 0 + + cpdef int solve(self) except -1: + """ + Solve the problem. + + .. NOTE:: + + This method raises ``MIPSolverException`` exceptions when + the solution cannot be computed for any reason (none + exists, or the LP solver was not able to find it, etc...) + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_linear_constraints(5, 0, None) + sage: p.add_col(list(range(5)), list(range(5))) + Traceback (most recent call last): + ... + NotImplementedError: adding coefficients to inequalities is ambiguous because cvxpy rewrites all inequalities as <= + sage: p.solve() + 0 + sage: p.objective_coefficient(0,1) + sage: p.solve() + Traceback (most recent call last): + ... + MIPSolverException: ... + """ + try: + self.problem.solve(solver=self._cvxpy_solver, **self._cvxpy_solver_args) + except Exception as e: + raise MIPSolverException(f"cvxpy.Problem.solve raised exception: {e}") + status = self.problem.status + if 'optimal' in status: + return 0 + if 'infeasible' in status: + raise MIPSolverException(f"cvxpy.Problem.solve: Problem has no feasible solution") + if 'unbounded' in status: + raise MIPSolverException(f"cvxpy.Problem.solve: Problem is unbounded") + raise MIPSolverException(f"cvxpy.Problem.solve reported an unknown problem status: {status}") + + cpdef get_objective_value(self): + """ + Return the value of the objective function. + + .. NOTE:: + + Behavior is undefined unless ``solve`` has been called before. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_variables(2) + 1 + sage: p.add_linear_constraint([(0,1), (1,2)], None, 3) + sage: p.set_objective([2, 5]) + sage: p.solve() + 0 + sage: p.get_objective_value() # abs tol 1e-7 + 7.5 + sage: p.get_variable_value(0) # abs tol 1e-7 + 0.0 + sage: p.get_variable_value(1) # abs tol 1e-7 + 1.5 + """ + return self.problem.value + self.obj_constant_term + + cpdef get_variable_value(self, int variable): + """ + Return the value of a variable given by the solver. + + .. NOTE:: + + Behavior is undefined unless ``solve`` has been called before. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_variables(2) + 1 + sage: p.add_linear_constraint([(0,1), (1, 2)], None, 3) + sage: p.set_objective([2, 5]) + sage: p.solve() + 0 + sage: p.get_objective_value() # abs tol 1e-7 + 7.5 + sage: p.get_variable_value(0) # abs tol 1e-7 + 0.0 + sage: p.get_variable_value(1) # abs tol 1e-7 + 1.5 + """ + return float(self.variables[variable].value) + + cpdef int ncols(self): + """ + Return the number of columns/variables. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.ncols() + 0 + sage: p.add_variables(2) + 1 + sage: p.ncols() + 2 + """ + return len(self.variables) + + cpdef int nrows(self): + """ + Return the number of rows/constraints. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.nrows() + 0 + sage: p.add_linear_constraints(2, 0, None) + sage: p.nrows() + 2 + """ + return len(self.problem.constraints) + + cpdef bint is_maximization(self): + """ + Test whether the problem is a maximization + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.is_maximization() + True + sage: p.set_sense(-1) + sage: p.is_maximization() + False + """ + return isinstance(self.problem.objective, cvxpy.Maximize) + + cpdef problem_name(self, name=None): + """ + Return or define the problem's name + + INPUT: + + - ``name`` (``str``) -- the problem's name. When set to + ``None`` (default), the method returns the problem's name. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.problem_name("There_once_was_a_french_fry") + sage: print(p.problem_name()) + There_once_was_a_french_fry + """ + if name is None: + if self.prob_name is not None: + return self.prob_name + else: + return "" + else: + self.prob_name = str(name) + + cpdef row(self, int i): + """ + Return a row + + INPUT: + + - ``index`` (integer) -- the constraint's id. + + OUTPUT: + + A pair ``(indices, coeffs)`` where ``indices`` lists the + entries whose coefficient is nonzero, and to which ``coeffs`` + associates their coefficient on the model of the + ``add_linear_constraint`` method. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_variables(5) + 4 + sage: index = p.nrows() + sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2) + sage: p.row(index) + ([1, 2, 3, 4], [1, 2, 3, 4]) + sage: p.row_bounds(index) + (2, 2) + """ + idx = [] + coef = [] + for j in range(len(self.Matrix[i])): + if self.Matrix[i][j] != 0: + idx.append(j) + coef.append(self.Matrix[i][j]) + return (idx, coef) + + cpdef row_bounds(self, int index): + """ + Return the bounds of a specific constraint. + + INPUT: + + - ``index`` (integer) -- the constraint's id. + + OUTPUT: + + A pair ``(lower_bound, upper_bound)``. Each of them can be set + to ``None`` if the constraint is not bounded in the + corresponding direction, and is a real value otherwise. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_variables(5) + 4 + sage: index = p.nrows() + sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2) + sage: p.row(index) + ([1, 2, 3, 4], [1, 2, 3, 4]) + sage: p.row_bounds(index) + (2, 2) + """ + return (self.row_lower_bound[index], self.row_upper_bound[index]) + + cpdef col_bounds(self, int index): + """ + Return the bounds of a specific variable. + + INPUT: + + - ``index`` (integer) -- the variable's id. + + OUTPUT: + + A pair ``(lower_bound, upper_bound)``. Each of them can be set + to ``None`` if the variable is not bounded in the + corresponding direction, and is a real value otherwise. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_variable() + 0 + sage: p.col_bounds(0) + (0.0, None) + sage: p.variable_upper_bound(0, 5) + sage: p.col_bounds(0) + (0.0, 5) + """ + return (self.col_lower_bound[index], self.col_upper_bound[index]) + + cpdef bint is_variable_binary(self, int index): + """ + Test whether the given variable is of binary type. + + INPUT: + + - ``index`` (integer) -- the variable's id + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.ncols() + 0 + sage: p.add_variable() + 0 + sage: p.is_variable_binary(0) + False + """ + return bool(self.variables[index].boolean_idx) + + cpdef bint is_variable_integer(self, int index): + """ + Test whether the given variable is of integer type. + + INPUT: + + - ``index`` (integer) -- the variable's id + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.ncols() + 0 + sage: p.add_variable() + 0 + sage: p.is_variable_integer(0) + False + """ + return bool(self.variables[index].integer_idx) + + cpdef bint is_variable_continuous(self, int index): + """ + Test whether the given variable is of continuous/real type. + + INPUT: + + - ``index`` (integer) -- the variable's id + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.ncols() + 0 + sage: p.add_variable() + 0 + sage: p.is_variable_continuous(0) + True + """ + return not self.is_variable_binary(index) and not self.is_variable_integer(index) + + cpdef row_name(self, int index): + """ + Return the ``index`` th row name + + INPUT: + + - ``index`` (integer) -- the row's id + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_linear_constraint([], 2, 2) + sage: p.row_name(0) + 'constraint_0' + """ + return self.constraint_names[index] or ("constraint_" + repr(index)) + + cpdef col_name(self, int index): + """ + Return the ``index`` th col name + + INPUT: + + - ``index`` (integer) -- the col's id + + - ``name`` (``char *``) -- its name. When set to ``NULL`` + (default), the method returns the current name. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_variable() + 0 + sage: p.col_name(0) + 'x_0' + """ + return self.variables[index].name() + + cpdef variable_upper_bound(self, int index, value = False): + """ + Return or define the upper bound on a variable + + INPUT: + + - ``index`` (integer) -- the variable's id + + - ``value`` -- real value, or ``None`` to mean that the + variable has not upper bound. When set to ``None`` + (default), the method returns the current value. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_variable() + 0 + sage: p.col_bounds(0) + (0.0, None) + sage: p.variable_upper_bound(0, 5) + sage: p.col_bounds(0) + (0.0, 5) + sage: p.variable_upper_bound(0, None) + sage: p.col_bounds(0) + (0.0, None) + """ + if value is not False: + self.col_upper_bound[index] = value + else: + return self.col_upper_bound[index] + + cpdef variable_lower_bound(self, int index, value = False): + """ + Return or define the lower bound on a variable + + INPUT: + + - ``index`` (integer) -- the variable's id + + - ``value`` -- real value, or ``None`` to mean that the + variable has not lower bound. When set to ``None`` + (default), the method returns the current value. + + EXAMPLES:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="CVXPY") + sage: p.add_variable() + 0 + sage: p.col_bounds(0) + (0.0, None) + sage: p.variable_lower_bound(0, 5) + sage: p.col_bounds(0) + (5, None) + sage: p.variable_lower_bound(0, None) + sage: p.col_bounds(0) + (None, None) + """ + if value is not False: + self.col_lower_bound[index] = value + else: + return self.col_lower_bound[index] diff --git a/src/sage/numerical/backends/cvxpy_backend_test.py b/src/sage/numerical/backends/cvxpy_backend_test.py new file mode 100644 index 00000000000..1f5f030248e --- /dev/null +++ b/src/sage/numerical/backends/cvxpy_backend_test.py @@ -0,0 +1,11 @@ +import pytest +from sage.numerical.backends.generic_backend_test import GenericBackendTests +from sage.numerical.backends.generic_backend import GenericBackend +from sage.numerical.mip import MixedIntegerLinearProgram + +@pytest.importorskip("cvxpy") +class TestCVXPYBackend(GenericBackendTests): + + @pytest.fixture + def backend(self) -> GenericBackend: + return MixedIntegerLinearProgram(solver="CVXPY").get_backend() diff --git a/src/sage/numerical/backends/generic_backend.pyx b/src/sage/numerical/backends/generic_backend.pyx index 4ba33af08b7..74cc99cb9e5 100644 --- a/src/sage/numerical/backends/generic_backend.pyx +++ b/src/sage/numerical/backends/generic_backend.pyx @@ -57,9 +57,9 @@ cdef class GenericBackend: - ``binary`` - ``True`` if the variable is binary (default: ``False``). - - ``continuous`` - ``True`` if the variable is binary (default: ``True``). + - ``continuous`` - ``True`` if the variable is continuous (default: ``True``). - - ``integer`` - ``True`` if the variable is binary (default: ``False``). + - ``integer`` - ``True`` if the variable is integral (default: ``False``). - ``obj`` - (optional) coefficient of this variable in the objective function (default: 0.0) @@ -423,7 +423,7 @@ cdef class GenericBackend: sage: p.add_linear_constraint([(0, 3), (1, 2)], None, 6) # optional - Nonexistent_LP_solver sage: p.remove_constraints([0, 1]) # optional - Nonexistent_LP_solver """ - if type(constraints) == int: self.remove_constraint(constraints) + if isinstance(constraints, int): self.remove_constraint(constraints) cdef int last = self.nrows() + 1 @@ -721,7 +721,7 @@ cdef class GenericBackend: tester = p._tester(**options) # From doctest of GenericBackend.solve: tester.assertIsNone(p.add_linear_constraints(5, 0, None)) - tester.assertIsNone(p.add_col(list(xrange(5)), list(xrange(5)))) + tester.assertIsNone(p.add_col(list(range(5)), list(range(5)))) tester.assertEqual(p.solve(), 0) tester.assertIsNone(p.objective_coefficient(0,1)) from sage.numerical.mip import MIPSolverException @@ -777,7 +777,7 @@ cdef class GenericBackend: sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver") # optional - Nonexistent_LP_solver sage: b = p.new_variable(binary=True) # optional - Nonexistent_LP_solver sage: for u,v in graphs.CycleGraph(5).edges(labels=False): # optional - Nonexistent_LP_solver - ....: p.add_constraint(b[u]+b[v]<=1) # optional - Nonexistent_LP_solver + ....: p.add_constraint(b[u]+b[v]<=1) sage: p.set_objective(p.sum(b[x] for x in range(5))) # optional - Nonexistent_LP_solver sage: p.solve() # optional - Nonexistent_LP_solver 2.0 @@ -812,7 +812,7 @@ cdef class GenericBackend: sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver") # optional - Nonexistent_LP_solver sage: b = p.new_variable(binary=True) # optional - Nonexistent_LP_solver sage: for u,v in graphs.CycleGraph(5).edges(labels=False): # optional - Nonexistent_LP_solver - ....: p.add_constraint(b[u]+b[v]<=1) # optional - Nonexistent_LP_solver + ....: p.add_constraint(b[u]+b[v]<=1) sage: p.set_objective(p.sum(b[x] for x in range(5))) # optional - Nonexistent_LP_solver sage: p.solve() # optional - Nonexistent_LP_solver 2.0 @@ -1288,8 +1288,8 @@ cdef class GenericBackend: del cp self._do_test_problem_data(tester, cpcp) - # TODO: We should have a more systematic way of generating MIPs for testing. + @classmethod def _test_copy_some_mips(cls, tester=None, **options): p = cls() # fresh instance of the backend @@ -1299,7 +1299,7 @@ cdef class GenericBackend: p.add_linear_constraints(5, 0, None) try: # p.add_col(range(5), range(5)) -- bad test because COIN sparsifies the 0s away on copy - p.add_col(list(xrange(5)), list(xrange(1, 6))) + p.add_col(list(range(5)), list(range(1, 6))) except NotImplementedError: # Gurobi does not implement add_col pass @@ -1555,7 +1555,7 @@ def default_mip_solver(solver=None): - a string indicating one of the available solvers (see :class:`MixedIntegerLinearProgram`); - - a callable (typically a subclass of + - a callable (typically a subclass of :class:`sage.numerical.backends.generic_backend.GenericBackend`); - ``None`` (default), in which case the current default solver @@ -1595,7 +1595,7 @@ def default_mip_solver(solver=None): return default_solver else: - for s in ["Cplex", "Gurobi", "Coin", "Glpk", "SCIP"]: + for s in ["Cplex", "Gurobi", "Cvxpy/cbc", "Coin", "Glpk", "SCIP"]: try: default_mip_solver(s) return s @@ -1649,6 +1649,24 @@ def default_mip_solver(solver=None): elif solver == "Interactivelp": default_solver = solver + elif solver == "Cvxpy": + try: + from sage.numerical.backends.cvxpy_backend import CVXPYBackend + except ImportError: + raise ValueError("CVXPY is not available. Please refer to the documentation to install it.") + else: + assert CVXPYBackend + default_solver = solver + + elif solver.startswith("Cvxpy"): + try: + s = get_solver(solver=solver) + s.solve() + except Exception as e: + raise ValueError(f"{solver} is not available: {e}. Please refer to the documentation to install it.") + else: + default_solver = solver + elif solver == "Scip": try: from sage.numerical.backends.scip_backend import SCIPBackend @@ -1657,7 +1675,7 @@ def default_mip_solver(solver=None): raise ValueError("SCIP is not available. Please refer to the documentation to install it.") else: - raise ValueError("'solver' should be set to 'GLPK', 'Coin', 'CPLEX', 'CVXOPT', 'Gurobi', 'PPL', 'SCIP', 'InteractiveLP', a callable, or None.") + raise ValueError("'solver' should be set to 'GLPK', 'Coin', 'CPLEX', 'CVXOPT', 'CVXPY', 'Gurobi', 'PPL', 'SCIP', 'InteractiveLP', a callable, or None.") cpdef GenericBackend get_solver(constraint_generation = False, solver = None, base_ring = None): """ @@ -1759,7 +1777,8 @@ cpdef GenericBackend get_solver(constraint_generation = False, solver = None, ba if base_ring is not None: base_ring = base_ring.fraction_field() - from sage.rings.all import QQ, RDF + from sage.rings.rational_field import QQ + from sage.rings.real_double import RDF if base_ring is QQ: solver = "Ppl" elif solver in ["Interactivelp", "Ppl"] and not base_ring.is_exact(): @@ -1813,10 +1832,16 @@ cpdef GenericBackend get_solver(constraint_generation = False, solver = None, ba from sage.numerical.backends.interactivelp_backend import InteractiveLPBackend return InteractiveLPBackend(base_ring=base_ring) + elif solver.startswith("Cvxpy"): + from sage.numerical.backends.cvxpy_backend import CVXPYBackend + if solver == "Cvxpy": + return CVXPYBackend() + if solver.startswith("Cvxpy/"): + return CVXPYBackend(cvxpy_solver=solver[len("Cvxpy/"):]) + elif solver == "Scip": from sage.numerical.backends.scip_backend import SCIPBackend return SCIPBackend() else: - raise ValueError("'solver' should be set to 'GLPK', 'GLPK/exact', 'Coin', 'CPLEX', 'CVXOPT', 'Gurobi', 'PPL', 'SCIP', 'InteractiveLP', None (in which case the default one is used), or a callable.") - + raise ValueError("'solver' should be set to 'GLPK', 'GLPK/exact', 'Coin', 'CPLEX', 'CVXOPT', 'CVXPY', 'Gurobi', 'PPL', 'SCIP', 'InteractiveLP', None (in which case the default one is used), or a callable.") diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index dcf732916c0..4b90438bc8c 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -80,9 +80,9 @@ cdef class GLPKBackend(GenericBackend): - ``binary`` - ``True`` if the variable is binary (default: ``False``). - - ``continuous`` - ``True`` if the variable is binary (default: ``True``). + - ``continuous`` - ``True`` if the variable is continuous (default: ``True``). - - ``integer`` - ``True`` if the variable is binary (default: ``False``). + - ``integer`` - ``True`` if the variable is integral (default: ``False``). - ``obj`` - (optional) coefficient of this variable in the objective function (default: 0.0) @@ -116,7 +116,7 @@ cdef class GLPKBackend(GenericBackend): 1.0 """ cdef int vtype = int(bool(binary)) + int(bool(continuous)) + int(bool(integer)) - if vtype == 0: + if vtype == 0: continuous = True elif vtype != 1: raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.") @@ -197,7 +197,7 @@ cdef class GLPKBackend(GenericBackend): 42.0 """ cdef int vtype = int(bool(binary)) + int(bool(continuous)) + int(bool(integer)) - if vtype == 0: + if vtype == 0: continuous = True elif vtype != 1: raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.") @@ -549,7 +549,7 @@ cdef class GLPKBackend(GenericBackend): cdef int * rows = <int *>sig_malloc((m + 1) * sizeof(int *)) cdef int nrows = glp_get_num_rows(self.lp) - for i in xrange(m): + for i in range(m): c = constraints[i] if c < 0 or c >= nrows: @@ -1012,10 +1012,14 @@ cdef class GLPKBackend(GenericBackend): (`get_col_dual` etc.) or tableau data (`get_row_stat` etc.), one needs to switch to "simplex_only" before solving. - GLPK also has an exact rational simplex solver. The only - access to data is via double-precision floats, however. It - reconstructs rationals from doubles and also provides results - as doubles. + GLPK also has an exact rational simplex solver. The only access + to data is via double-precision floats, which means that + rationals in the input data may be rounded before the exact + solver sees them. Thus, it is unreasonable to expect that + arbitrary LPs with rational coefficients are solved exactly. + Once the LP has been read into the backend, it reconstructs + rationals from doubles and does solve exactly over the rationals, + but results are returned as as doubles. EXAMPLES:: @@ -3129,7 +3133,7 @@ solver_parameter_names_dict = { 'obj_ll': obj_ll, 'obj_lower_limit': obj_ll, 'obj_ul': obj_ul, 'obj_upper_limit': obj_ul, 'it_lim': it_lim, 'iteration_limit': it_lim, - 'out_frq_simplex': out_frq_simplex, 'output_frequency_intopt': out_frq_simplex, + 'out_frq_simplex': out_frq_simplex, 'output_frequency_simplex': out_frq_simplex, 'out_dly_simplex': out_dly_simplex, 'output_delay_simplex': out_dly_simplex, 'presolve_simplex': presolve_simplex } diff --git a/src/sage/numerical/backends/glpk_exact_backend.pyx b/src/sage/numerical/backends/glpk_exact_backend.pyx index 0da98460382..3031748eb42 100644 --- a/src/sage/numerical/backends/glpk_exact_backend.pyx +++ b/src/sage/numerical/backends/glpk_exact_backend.pyx @@ -19,9 +19,13 @@ cdef class GLPKExactBackend(GLPKBackend): """ MIP Backend that runs the GLPK solver in exact rational simplex mode. - The only access to data is via double-precision floats, however. It - reconstructs rationals from doubles and also provides results - as doubles. + The only access to data is via double-precision floats, which + means that rationals in the input data may be rounded before + the exact solver sees them. Thus, it is unreasonable to expect + that arbitrary LPs with rational coefficients are solved exactly. + Once the LP has been read into the backend, it reconstructs + rationals from doubles and does solve exactly over the rationals, + but results are returned as as doubles. There is no support for integer variables. """ diff --git a/src/sage/numerical/backends/interactivelp_backend.pyx b/src/sage/numerical/backends/interactivelp_backend.pyx index 89b823f2491..773c13b781c 100644 --- a/src/sage/numerical/backends/interactivelp_backend.pyx +++ b/src/sage/numerical/backends/interactivelp_backend.pyx @@ -191,9 +191,9 @@ cdef class InteractiveLPBackend: - ``binary`` - ``True`` if the variable is binary (default: ``False``). - - ``continuous`` - ``True`` if the variable is binary (default: ``True``). + - ``continuous`` - ``True`` if the variable is continuous (default: ``True``). - - ``integer`` - ``True`` if the variable is binary (default: ``False``). + - ``integer`` - ``True`` if the variable is integral (default: ``False``). - ``obj`` - (optional) coefficient of this variable in the objective function (default: 0) @@ -228,7 +228,7 @@ cdef class InteractiveLPBackend: """ A, b, c, x, constraint_types, variable_types, problem_type, ring, d = self._AbcxCVPRd() cdef int vtype = int(binary) + int(continuous) + int(integer) - if vtype == 0: + if vtype == 0: continuous = True elif vtype != 1: raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.") diff --git a/src/sage/numerical/backends/matrix_sdp_backend.pyx b/src/sage/numerical/backends/matrix_sdp_backend.pyx index 52f5ae602e0..7668c64ecc1 100644 --- a/src/sage/numerical/backends/matrix_sdp_backend.pyx +++ b/src/sage/numerical/backends/matrix_sdp_backend.pyx @@ -20,7 +20,7 @@ other classes implementing solvers. # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.matrix.all import Matrix +from sage.matrix.constructor import Matrix from .generic_sdp_backend cimport GenericSDPBackend cdef class MatrixSDPBackend(GenericSDPBackend): diff --git a/src/sage/numerical/backends/ppl_backend.pyx b/src/sage/numerical/backends/ppl_backend.pyx index 9d59c226743..03b54b34359 100644 --- a/src/sage/numerical/backends/ppl_backend.pyx +++ b/src/sage/numerical/backends/ppl_backend.pyx @@ -9,23 +9,24 @@ AUTHORS: constraints and objective function (:trac:`16755`) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Risan <ptrrsn.1@gmail.com> # Copyright (C) 2014 Jeroen Demeyer <jdemeyer@cage.ugent.be> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.numerical.mip import MIPSolverException -from ppl import MIP_Problem, Variable, Variables_Set, Linear_Expression, Constraint, Generator +from ppl import MIP_Problem, Variable, Variables_Set, Linear_Expression from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational from .generic_backend cimport GenericBackend from copy import copy + cdef class PPLBackend(GenericBackend): """ @@ -257,9 +258,9 @@ cdef class PPLBackend(GenericBackend): - ``binary`` -- ``True`` if the variable is binary (default: ``False``). - - ``continuous`` -- ``True`` if the variable is binary (default: ``True``). + - ``continuous`` -- ``True`` if the variable is continuous (default: ``True``). - - ``integer`` -- ``True`` if the variable is binary (default: ``False``). + - ``integer`` -- ``True`` if the variable is integral (default: ``False``). - ``obj`` -- (optional) coefficient of this variable in the objective function (default: 0) @@ -289,7 +290,7 @@ cdef class PPLBackend(GenericBackend): 3 """ cdef int vtype = int(bool(binary)) + int(bool(continuous)) + int(bool(integer)) - if vtype == 0: + if vtype == 0: continuous = True elif vtype != 1: raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.") @@ -328,9 +329,9 @@ cdef class PPLBackend(GenericBackend): - ``binary`` -- ``True`` if the variable is binary (default: ``False``). - - ``continuous`` -- ``True`` if the variable is binary (default: ``True``). + - ``continuous`` -- ``True`` if the variable is continuous (default: ``True``). - - ``integer`` -- ``True`` if the variable is binary (default: ``False``). + - ``integer`` -- ``True`` if the variable is integral (default: ``False``). - ``obj`` -- (optional) coefficient of all variables in the objective function (default: 0) diff --git a/src/sage/numerical/backends/scip_backend.pyx b/src/sage/numerical/backends/scip_backend.pyx index b2ecf0f923b..fbec62ebcbf 100644 --- a/src/sage/numerical/backends/scip_backend.pyx +++ b/src/sage/numerical/backends/scip_backend.pyx @@ -9,7 +9,6 @@ AUTHORS: - Matthias Koeppe (2017): stubs - Moritz Firsching (2018-04): rest """ - # ***************************************************************************** # Copyright (C) 2010 Nathann Cohen <nathann.cohen@gmail.com> # 2017-2022 Matthias Koeppe @@ -19,15 +18,11 @@ AUTHORS: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # ***************************************************************************** -from os import sys from os.path import splitext -from sage.ext.memory_allocator cimport MemoryAllocator from sage.numerical.mip import MIPSolverException -from libc.float cimport DBL_MAX -from libc.limits cimport INT_MAX from pyscipopt import Model diff --git a/src/sage/numerical/backends/scip_backend_test.py b/src/sage/numerical/backends/scip_backend_test.py index 43648d0c3ce..136d3ce914b 100644 --- a/src/sage/numerical/backends/scip_backend_test.py +++ b/src/sage/numerical/backends/scip_backend_test.py @@ -3,6 +3,7 @@ from sage.numerical.backends.generic_backend import GenericBackend from sage.numerical.mip import MixedIntegerLinearProgram +@pytest.importorskip("pyscipopt") class TestSCIPBackend(GenericBackendTests): @pytest.fixture diff --git a/src/sage/numerical/gauss_legendre.pyx b/src/sage/numerical/gauss_legendre.pyx index 0b8dd4361e3..269727c1fdd 100644 --- a/src/sage/numerical/gauss_legendre.pyx +++ b/src/sage/numerical/gauss_legendre.pyx @@ -63,7 +63,7 @@ def nodes_uncached(degree, prec): - ``degree`` -- integer. The number of nodes. Must be 3 or even. - - ``prec`` -- integer (minimal value 53). Binary precision with which the + - ``prec`` -- integer (minimal value 53). Binary precision with which the nodes and weights are computed. OUTPUT: @@ -108,7 +108,7 @@ def nodes_uncached(degree, prec): performance. """ cdef long j,j1,n - cdef RealNumber r,t1,t2,t3,t4,a,w + cdef RealNumber r,t1,t2,t4,a,w cdef mpfr_t u,v cdef RealField_class R if prec < 53: @@ -117,8 +117,8 @@ def nodes_uncached(degree, prec): raise ValueError("degree=%s not supported (degree must be 3 or even)" % degree) R = RealField(int(prec*3/2)) Rout = RealField(prec) - mpfr_init2(u,R.__prec) - mpfr_init2(v,R.__prec) + mpfr_init2(u,R._prec) + mpfr_init2(v,R._prec) ZERO = R.zero() ONE = R.one() HALF = ONE/2 @@ -132,11 +132,11 @@ def nodes_uncached(degree, prec): else: nodes = [] n = degree - for j in xrange(1, n // 2 + 1): + for j in range(1, n // 2 + 1): r = R(math.cos(math.pi*(j-0.25)/(n+0.5))) while True: t1,t2=ONE,ZERO - for j1 in xrange(1,n+1): + for j1 in range(1,n+1): mpfr_mul(u,r.value,t1.value,rnd) mpfr_mul_si(u,u,2*j1-1,rnd) mpfr_mul_si(v,t2.value,j1-1,rnd) @@ -166,13 +166,13 @@ def nodes(degree, prec): Compute the integration nodes and weights for the Gauss-Legendre quadrature scheme, caching the output - Works by calling ``nodes_uncached``. + Works by calling ``nodes_uncached``. INPUT: - ``degree`` -- integer. The number of nodes. Must be 3 or even. - - ``prec`` -- integer (minimal value 53). Binary precision with which the + - ``prec`` -- integer (minimal value 53). Binary precision with which the nodes and weights are computed. OUTPUT: @@ -250,10 +250,11 @@ def estimate_error(results, prec, epsilon): 2.328235...e-10 """ if len(results)==2: - return max((results[0][i]-results[1][i]).abs() for i in xrange(len(results[0]))) + return max((results[0][i]-results[1][i]).abs() + for i in range(len(results[0]))) e = [] - ZERO = 0*epsilon - for i in xrange(len(results[0])): + ZERO = 0 * epsilon + for i in range(len(results[0])): try: if results[-1][i] == results[-2][i] == results[-3][i]: e.append(0*epsilon) @@ -271,10 +272,10 @@ def integrate_vector_N(f, prec, N=3): Integrate a one-argument vector-valued function numerically using Gauss-Legendre, setting the number of nodes. - This function uses the Gauss-Legendre quadrature scheme to approximate the + This function uses the Gauss-Legendre quadrature scheme to approximate the integral `\int_0^1 f(t) \, dt`. It is different from ``integrate_vector`` by using a specific number of nodes rather than targeting a specified error - bound on the result. + bound on the result. INPUT: @@ -284,9 +285,9 @@ def integrate_vector_N(f, prec, N=3): - ``N`` -- integer (default: 3). Number of nodes to use. - OUTPUT: + OUTPUT: - Vector approximating value of the integral. + Vector approximating value of the integral. EXAMPLES:: @@ -300,14 +301,14 @@ def integrate_vector_N(f, prec, N=3): .. NOTE:: - The nodes and weights are calculated in the real field with ``prec`` + The nodes and weights are calculated in the real field with ``prec`` bits of precision. If the vector space in which ``f`` takes values is over a field which is incompatible with this field (e.g. a finite - field) then a TypeError occurs. + field) then a :class:`TypeError` occurs. """ - # We use nodes_uncached, because caching takes up memory, and numerics in - # Bruin-DisneyHogg-Gao suggest that caching provides little benefit in the - # use in the Riemann surfaces module. + # We use nodes_uncached, because caching takes up memory, and numerics in + # Bruin-DisneyHogg-Gao suggest that caching provides little benefit in the + # use in the Riemann surfaces module. nodelist = nodes_uncached(N, prec) I = nodelist[0][1]*f(nodelist[0][0]) for i in range(1,len(nodelist)): diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index c61817f6a02..ae9e43383e4 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -64,7 +64,7 @@ Since it has only two variables, we can solve it graphically:: - sage: P.plot() + sage: P.plot() # optional - sage.plot Graphics object consisting of 19 graphics primitives @@ -182,20 +182,25 @@ from copy import copy from sage.misc.abstract_method import abstract_method -from sage.geometry.all import Polyhedron -from sage.matrix.all import (column_matrix, - identity_matrix, - matrix, - random_matrix) +from sage.geometry.polyhedron.constructor import Polyhedron +from sage.matrix.special import column_matrix +from sage.matrix.special import identity_matrix +from sage.matrix.constructor import matrix +from sage.matrix.special import random_matrix from sage.misc.latex import LatexExpr, latex from sage.misc.cachefunc import cached_function, cached_method from sage.misc.prandom import randint, random from sage.misc.html import HtmlFragment from sage.misc.misc import get_main_globals -from sage.modules.all import random_vector, vector +from sage.modules.free_module_element import random_vector +from sage.modules.free_module_element import free_module_element as vector from sage.misc.lazy_import import lazy_import lazy_import("sage.plot.all", ["Graphics", "arrow", "line", "point", "rainbow", "text"]) -from sage.rings.all import Infinity, PolynomialRing, QQ, RDF, ZZ +from sage.rings.infinity import Infinity +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ +from sage.rings.real_double import RDF +from sage.rings.integer_ring import ZZ from sage.structure.all import SageObject from sage.symbolic.ring import SR @@ -785,7 +790,7 @@ def _latex_(self): latex(xj), r"\geq" if vt == ">=" else r"\leq") for xj, vt in zip(x, self._variable_types) if vt)) lines.append(r"\end{array}") - return "\n".join(lines) + return "\n".join(lines) def _repr_(self): r""" @@ -1529,19 +1534,19 @@ def plot(self, *args, **kwds): sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") - sage: p = P.plot() - sage: p.show() + sage: p = P.plot() # optional - sage.plot + sage: p.show() # optional - sage.plot In this case the plot works better with the following axes ranges:: - sage: p = P.plot(0, 1000, 0, 1500) - sage: p.show() + sage: p = P.plot(0, 1000, 0, 1500) # optional - sage.plot + sage: p.show() # optional - sage.plot TESTS: We check that zero objective can be dealt with:: - sage: InteractiveLPProblem(A, b, (0, 0), ["C", "B"], variable_type=">=").plot() + sage: InteractiveLPProblem(A, b, (0, 0), ["C", "B"], variable_type=">=").plot() # optional - sage.plot Graphics object consisting of 8 graphics primitives """ FP = self.plot_feasible_set(*args, **kwds) @@ -1606,13 +1611,13 @@ def plot_feasible_set(self, xmin=None, xmax=None, ymin=None, ymax=None, sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") - sage: p = P.plot_feasible_set() - sage: p.show() + sage: p = P.plot_feasible_set() # optional - sage.plot + sage: p.show() # optional - sage.plot In this case the plot works better with the following axes ranges:: - sage: p = P.plot_feasible_set(0, 1000, 0, 1500) - sage: p.show() + sage: p = P.plot_feasible_set(0, 1000, 0, 1500) # optional - sage.plot + sage: p.show() # optional - sage.plot """ if self.n() != 2: raise ValueError("only problems with 2 variables can be plotted") @@ -4505,7 +4510,7 @@ def __init__(self, problem, basic_variables): "for auxiliary problems") super().__init__() self._problem = problem - R = problem.coordinate_ring() + R = problem.coordinate_ring() self._x_B = vector(R, [variable(R, v) for v in basic_variables]) def __eq__(self, other): @@ -4606,7 +4611,7 @@ def _latex_(self): headers.append("B^{-1} A_{%s}" % latex(entering)) if show_ratios: headers.append(r"\hbox{Ratio}") - lines.append(" & ".join(headers) + r" \\") + lines.append(" & ".join(headers) + r" \\") lines.append(r"\hline") Bi = self.B_inverse() c_B = self.c_B() diff --git a/src/sage/numerical/knapsack.py b/src/sage/numerical/knapsack.py index f334c24b94b..3a5c14474e8 100644 --- a/src/sage/numerical/knapsack.py +++ b/src/sage/numerical/knapsack.py @@ -648,9 +648,9 @@ def knapsack(seq, binary=True, max=1, value_only=False, solver=None, verbose=0, p = MixedIntegerLinearProgram(solver=solver, maximization=True) if binary: - present = p.new_variable(binary = True) + present = p.new_variable(binary=True) else: - present = p.new_variable(integer = True) + present = p.new_variable(integer=True) p.set_objective(p.sum([present[i] * seq[i][1] for i in range(len(seq))])) p.add_constraint(p.sum([present[i] * seq[i][0] for i in range(len(seq))]), max=max) diff --git a/src/sage/numerical/linear_functions.pyx b/src/sage/numerical/linear_functions.pyx index a5c0c0336d0..f3fc6fe419c 100644 --- a/src/sage/numerical/linear_functions.pyx +++ b/src/sage/numerical/linear_functions.pyx @@ -1064,7 +1064,7 @@ cdef class LinearFunction(LinearFunctionOrConstraint): sage: f._coeff_formatter(sqrt5) 'sqrt5*' - sage: from sage.rings.all import AA + sage: from sage.rings.qqbar import AA sage: sqrt5 = AA(5).sqrt() sage: p = MixedIntegerLinearProgram(solver='interactivelp', base_ring=AA) sage: LF = p.linear_functions_parent() @@ -1579,7 +1579,10 @@ cdef class LinearConstraint(LinearFunctionOrConstraint): while True: yield (lhs, rhs) lhs = rhs - rhs = next(term_iter) + try: + rhs = next(term_iter) + except StopIteration: + return def inequalities(self): """ @@ -1612,7 +1615,10 @@ cdef class LinearConstraint(LinearFunctionOrConstraint): while True: yield (lhs, rhs) lhs = rhs - rhs = next(term_iter) + try: + rhs = next(term_iter) + except StopIteration: + return def _repr_(self): r""" diff --git a/src/sage/numerical/linear_tensor.py b/src/sage/numerical/linear_tensor.py index 26d94b12cc6..2402845b896 100644 --- a/src/sage/numerical/linear_tensor.py +++ b/src/sage/numerical/linear_tensor.py @@ -181,12 +181,11 @@ def LinearTensorParent(free_module_parent, linear_functions_parent): return LinearTensorParent_class(free_module_parent, linear_functions_parent) - -#***************************************************************************** +# **************************************************************************** # # Parent of linear functions tensored with a free module # -#***************************************************************************** +# **************************************************************************** class LinearTensorParent_class(Parent): r""" @@ -389,7 +388,7 @@ def _element_constructor_(self, x): sage: type(_) <class 'sage.numerical.linear_tensor_element.LinearTensor'> - Construct from scalar: + Construct from scalar:: sage: LT(123) # indirect doctest (123.0, 123.0) diff --git a/src/sage/numerical/linear_tensor_element.pyx b/src/sage/numerical/linear_tensor_element.pyx index f04949d6c02..c77aa290e21 100644 --- a/src/sage/numerical/linear_tensor_element.pyx +++ b/src/sage/numerical/linear_tensor_element.pyx @@ -54,10 +54,10 @@ cdef class LinearTensor(ModuleElement): Constructor taking a dictionary as its argument. INPUT: - + - ``parent`` -- the parent :class:`~sage.numerical.linear_tensor.LinearTensorParent_class`. - + - ``f`` -- A linear function tensored by a free module is represented as a dictionary. The values are the coefficient (free module elements) of the variable represented by the @@ -70,7 +70,7 @@ cdef class LinearTensor(ModuleElement): sage: LT = MixedIntegerLinearProgram().linear_functions_parent().tensor(RDF^2) sage: LT({0: [1,2], 3: [-7,-8]}) (1.0, 2.0)*x_0 + (-7.0, -8.0)*x_3 - + sage: TestSuite(LT).run(skip=['_test_an_element', '_test_elements_eq_reflexive', ....: '_test_elements_eq_symmetric', '_test_elements_eq_transitive', ....: '_test_elements_neq', '_test_additive_associativity', @@ -191,7 +191,7 @@ cdef class LinearTensor(ModuleElement): OUTPUT: String. - + EXAMPLES:: sage: from sage.numerical.linear_functions import LinearFunctionsParent @@ -221,7 +221,7 @@ cdef class LinearTensor(ModuleElement): term = '{1}*x_{0}'.format(key, coeff) terms.append(term) return ' + '.join(terms) - + def _repr_matrix(self): """ Return a matrix-like string representation. @@ -266,7 +266,7 @@ cdef class LinearTensor(ModuleElement): Return sum. INPUT: - + - ``b`` -- a :class:`LinearTensor`. OUTPUT: @@ -310,7 +310,7 @@ cdef class LinearTensor(ModuleElement): Return difference. INPUT: - + - ``b`` -- a :class:`LinearTensor`. OUTPUT: @@ -402,7 +402,7 @@ cdef class LinearTensor(ModuleElement): Arithmetic performed after coercions. Result lives in Tensor product of Vector space of dimension 2 over Real Double Field and Linear functions over Real Double Field Tensor product of Vector space of dimension 2 over Real Double Field and Linear functions over Real Double Field - + sage: operator.le(10, lt) (10.0, 10.0) <= (1.0, 2.0)*x_0 sage: lt <= 1 diff --git a/src/sage/numerical/mip.pxd b/src/sage/numerical/mip.pxd index e041c6958eb..3046d8b4886 100644 --- a/src/sage/numerical/mip.pxd +++ b/src/sage/numerical/mip.pxd @@ -36,5 +36,3 @@ cdef class MIPVariable(SageObject): cdef object _upper_bound cdef _matrix_rmul_impl(self, m) cdef _matrix_lmul_impl(self, m) - - diff --git a/src/sage/numerical/mip.pyx b/src/sage/numerical/mip.pyx index bdbee5d974c..3711d9562cf 100644 --- a/src/sage/numerical/mip.pyx +++ b/src/sage/numerical/mip.pyx @@ -234,11 +234,7 @@ AUTHORS: # **************************************************************************** from copy import copy -from sage.structure.parent cimport Parent -from sage.structure.element cimport Element from sage.structure.element import is_Matrix -from sage.misc.cachefunc import cached_method -from sage.misc.superseded import deprecation_cython as deprecation from sage.rings.integer_ring import ZZ @@ -997,11 +993,11 @@ cdef class MixedIntegerLinearProgram(SageObject): cdef str s cdef GenericBackend b = self._backend - result = list() + result = [] # If indices is None, we actually want to return all constraints if indices is None: - indices = list(xrange(b.nrows())) + indices = list(range(b.nrows())) # Only one constraint if isinstance(indices, (int, Integer)): @@ -2134,11 +2130,10 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: p.remove_constraint(2) sage: p.solve() 6.0 - """ from sage.numerical.linear_functions import is_LinearFunction, is_LinearConstraint from sage.numerical.linear_tensor import is_LinearTensor - from sage.numerical.linear_tensor_constraints import is_LinearTensorConstraint + from sage.numerical.linear_tensor_constraints import is_LinearTensorConstraint if is_LinearFunction(linear_function) or is_LinearTensor(linear_function): # Find the parent for the coefficients if is_LinearFunction(linear_function): diff --git a/src/sage/numerical/optimize.py b/src/sage/numerical/optimize.py index 63d47674dbb..0f578f4e52b 100644 --- a/src/sage/numerical/optimize.py +++ b/src/sage/numerical/optimize.py @@ -155,7 +155,8 @@ def find_root(f, a, b, xtol=10e-13, rtol=2.0**-50, maxiter=100, full_output=Fals b = max(s_1, s_2) import scipy.optimize - brentqRes = scipy.optimize.brentq(f, a, b, + g = lambda x: float(f(x)) + brentqRes = scipy.optimize.brentq(g, a, b, full_output=full_output, xtol=xtol, rtol=rtol, maxiter=maxiter) # A check following :trac:`4942`, to ensure we actually found a root # Maybe should use a different tolerance here? @@ -675,7 +676,7 @@ def linear_program(c, G, h, A=None, b=None, solver=None): 'x': x, 's': s, 'y': y, 'z': z, 'status': status} -def find_fit(data, model, initial_guess = None, parameters = None, variables = None, solution_dict = False): +def find_fit(data, model, initial_guess=None, parameters=None, variables=None, solution_dict=False): r""" Finds numerical estimates for the parameters of the function model to give a best fit to data. @@ -754,7 +755,7 @@ def find_fit(data, model, initial_guess = None, parameters = None, variables = N if not isinstance(data, numpy.ndarray): try: - data = numpy.array(data, dtype = float) + data = numpy.array(data, dtype=float) except (ValueError, TypeError): raise TypeError("data has to be a list of lists, a matrix, or a numpy array") elif data.dtype == object: @@ -785,7 +786,7 @@ def find_fit(data, model, initial_guess = None, parameters = None, variables = N if not isinstance(initial_guess, numpy.ndarray): try: - initial_guess = numpy.array(initial_guess, dtype = float) + initial_guess = numpy.array(initial_guess, dtype=float) except (ValueError, TypeError): raise TypeError("initial_guess has to be a list, tuple, or numpy array") elif initial_guess.dtype == object: diff --git a/src/sage/numerical/sdp.pxd b/src/sage/numerical/sdp.pxd index 792c01e0703..e0351dde4f3 100644 --- a/src/sage/numerical/sdp.pxd +++ b/src/sage/numerical/sdp.pxd @@ -34,5 +34,5 @@ cdef class SDPVariable(Element): cdef class SDPVariableParent(Parent): pass -cdef SDPVariableParent sdp_variable_parent +cdef SDPVariableParent sdp_variable_parent diff --git a/src/sage/numerical/sdp.pyx b/src/sage/numerical/sdp.pyx index 207298d7ece..77f7fa5254c 100644 --- a/src/sage/numerical/sdp.pyx +++ b/src/sage/numerical/sdp.pyx @@ -217,21 +217,20 @@ AUTHORS: - Dima Pasechnik (2014-) : supervision, minor fixes, duality """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Ingolfur Edvardsson <ingolfured@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.parent cimport Parent from sage.structure.element cimport Element -from sage.misc.cachefunc import cached_method from sage.numerical.linear_functions import is_LinearFunction, is_LinearConstraint -from sage.matrix.all import Matrix +from sage.matrix.constructor import Matrix from sage.structure.element import is_Matrix diff --git a/src/sage/parallel/__init__.py b/src/sage/parallel/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/parallel/decorate.py b/src/sage/parallel/decorate.py index 8428b39b4fd..5b8572d3f60 100644 --- a/src/sage/parallel/decorate.py +++ b/src/sage/parallel/decorate.py @@ -107,8 +107,8 @@ def __call__(self, f): sage: from sage.parallel.decorate import Parallel sage: p = Parallel() - sage: f = x^2-1 - sage: p(f) + sage: f = x^2 - 1 # needs sage.symbolic + sage: p(f) # needs sage.symbolic <sage.parallel.decorate.ParallelFunction object at ...> sage: P = sage.parallel.decorate.Parallel() @@ -342,7 +342,7 @@ def parallel(p_iter='fork', ncpus=None, **kwds): sage: @parallel(ncpus=3, timeout=10) ....: def fac(n): return factor(2^n-1) - sage: for X, Y in sorted(list(fac([101,119,151,197,209]))): print((X,Y)) + sage: for X, Y in sorted(list(fac([101,119,151,197,209]))): print((X,Y)) # needs sage.libs.pari (((101,), {}), 7432339208719 * 341117531003194129) (((119,), {}), 127 * 239 * 20231 * 131071 * 62983048367 * 131105292137) (((151,), {}), 18121 * 55871 * 165799 * 2332951 * 7289088383388253664437433) @@ -517,10 +517,10 @@ def fork(f=None, timeout=0, verbose=False): sage: a 5 - We use ``fork`` to make sure that the function terminates after one - second, no matter what:: + We use ``fork`` to make sure that the function terminates after 100 ms, + no matter what:: - sage: @fork(timeout=1, verbose=True) + sage: @fork(timeout=0.1, verbose=True) ....: def g(n, m): return factorial(n).ndigits() + m sage: g(5, m=5) 8 @@ -531,6 +531,7 @@ def fork(f=None, timeout=0, verbose=False): We illustrate that the state of the pexpect interface is not altered by forked functions (they get their own new pexpect interfaces!):: + sage: # needs sage.libs.pari sage: gp.eval('a = 5') '5' sage: @fork() @@ -545,19 +546,21 @@ def fork(f=None, timeout=0, verbose=False): We illustrate that the forked function has its own pexpect interface:: - sage: gp.eval('a = 15') + sage: gp.eval('a = 15') # needs sage.libs.pari '15' sage: @fork() ....: def g(): return gp.eval('a') - sage: g() + sage: g() # needs sage.libs.pari 'a' We illustrate that segfaulting subprocesses are no trouble at all:: - sage: cython('def f(): print(<char*>0)') # optional - sage.misc.cython + sage: cython('def f(): print(<char*>0)') # needs sage.misc.cython sage: @fork - ....: def g(): f() - sage: print("this works"); g() # optional - sage.misc.cython + ....: def g(): + ....: os.environ["CYSIGNALS_CRASH_NDEBUG"]="yes" # skip enhanced backtrace (it is slow) + ....: f() + sage: print("this works"); g() # needs sage.misc.cython this works... <BLANKLINE> ------------------------------------------------------------------------ diff --git a/src/sage/parallel/map_reduce.py b/src/sage/parallel/map_reduce.py index d46ef531add..11e0673ee91 100644 --- a/src/sage/parallel/map_reduce.py +++ b/src/sage/parallel/map_reduce.py @@ -184,8 +184,8 @@ Compare:: - sage: from sage.combinat.q_analogues import q_factorial - sage: q_factorial(5) + sage: from sage.combinat.q_analogues import q_factorial # needs sage.combinat + sage: q_factorial(5) # needs sage.combinat q^10 + 4*q^9 + 9*q^8 + 15*q^7 + 20*q^6 + 22*q^5 + 20*q^4 + 15*q^3 + 9*q^2 + 4*q + 1 * **Listing the objects.** One can also compute the list of objects in a @@ -1653,14 +1653,14 @@ def steal(self): sage: EX = RESetMPExample(maxl=6) sage: EX.setup_workers(2) + sage: # known bug (Issue #27537) sage: w0, w1 = EX._workers sage: w0._todo.append(42) sage: thief0 = Thread(target = w0._thief, name="Thief") - sage: thief0.start() # known bug (Issue #27537) - - sage: w1.steal() # known bug (Issue #27537) + sage: thief0.start() + sage: w1.steal() 42 - sage: w0._todo # known bug (Issue #27537) + sage: w0._todo deque([]) """ self._mapred._signal_task_done() @@ -2010,8 +2010,7 @@ def __iter__(self): newres = self._results.get() if newres is not None: logger.debug("Got some results") - for r in newres: - yield r + yield from newres else: active_proc -= 1 if active_proc == 0: diff --git a/src/sage/parallel/multiprocessing_sage.py b/src/sage/parallel/multiprocessing_sage.py index be9b980aba9..2ccab49ac0f 100644 --- a/src/sage/parallel/multiprocessing_sage.py +++ b/src/sage/parallel/multiprocessing_sage.py @@ -74,7 +74,6 @@ def parallel_iter(processes, f, inputs): result = p.imap_unordered(call_pickled_function, [(fp, t) for t in inputs]) - for res in result: - yield res + yield from result p.close() p.join() diff --git a/src/sage/parallel/use_fork.py b/src/sage/parallel/use_fork.py index 69f2ede8420..ce240acf9d8 100644 --- a/src/sage/parallel/use_fork.py +++ b/src/sage/parallel/use_fork.py @@ -17,7 +17,7 @@ from cysignals.alarm import AlarmInterrupt, alarm, cancel_alarm from sage.interfaces.process import ContainChildren -from sage.misc.misc import walltime +from sage.misc.timing import walltime class WorkerData(): @@ -301,7 +301,12 @@ def _subprocess(self, f, dir, args, kwds={}): # The pexpect interfaces (and objects defined in them) are # not valid. if self.reset_interfaces: - sage.interfaces.quit.invalidate_all() + try: + from sage.interfaces.quit import invalidate_all + except ImportError: + pass + else: + invalidate_all() # Now evaluate the function f. value = f(*args, **kwds) diff --git a/src/sage/plot/__init__.py b/src/sage/plot/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/plot/animate.py b/src/sage/plot/animate.py index c835ab823a4..c917452e2be 100644 --- a/src/sage/plot/animate.py +++ b/src/sage/plot/animate.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic r""" Animated plots @@ -31,54 +31,66 @@ The sine function:: sage: x = SR.var("x") - sage: sines = [plot(c*sin(x), (-2*pi,2*pi), color=Color(c,0,0), ymin=-1, ymax=1) for c in sxrange(0,1,.2)] + sage: sines = [plot(c*sin(x), (-2*pi,2*pi), color=Color(c,0,0), ymin=-1, ymax=1) + ....: for c in sxrange(0,1,.2)] sage: a = animate(sines) - sage: a # optional -- ImageMagick + sage: print(a) Animation with 5 frames - sage: a.show() # optional -- ImageMagick + sage: a.show() # long time # optional -- ImageMagick Animate using FFmpeg_ instead of ImageMagick:: - sage: f = tmp_filename(ext='.gif') - sage: a.save(filename=f, use_ffmpeg=True) # optional -- ffmpeg + sage: a.show(use_ffmpeg=True) # long time # optional -- FFmpeg Animate as an APNG_:: - sage: a.apng() # long time + sage: a.apng(show_path=True) # long time + Animation saved to ....png. An animated :class:`sage.plot.multigraphics.GraphicsArray` of rotating ellipses:: - sage: E = animate((graphics_array([[ellipse((0,0),a,b,angle=t,xmin=-3,xmax=3)+circle((0,0),3,color='blue') for a in range(1,3)] for b in range(2,4)]) for t in sxrange(0,pi/4,.15))) + sage: E = animate((graphics_array([[ellipse((0,0), a, b, angle=t, xmin=-3, xmax=3) + ....: + circle((0,0), 3, color='blue') + ....: for a in range(1,3)] + ....: for b in range(2,4)]) + ....: for t in sxrange(0, pi/4, .15))) sage: str(E) # animations produced from a generator do not have a known length 'Animation with unknown number of frames' - sage: E.show() # optional -- ImageMagick # long time + sage: E.show() # long time # optional -- ImageMagick A simple animation of a circle shooting up to the right:: - sage: c = animate([circle((i,i), 1-1/(i+1), hue=i/10) for i in srange(0,2,0.2)], - ....: xmin=0,ymin=0,xmax=2,ymax=2,figsize=[2,2]) - sage: c.show() # optional -- ImageMagick + sage: c = animate([circle((i,i), 1 - 1/(i+1), hue=i/10) + ....: for i in srange(0, 2, 0.2)], + ....: xmin=0, ymin=0, xmax=2, ymax=2, figsize=[2,2]) + sage: c.show() # long time # optional -- ImageMagick Animations of 3d objects:: sage: s,t = SR.var("s,t") sage: def sphere_and_plane(x): - ....: return sphere((0,0,0),1,color='red',opacity=.5)+parametric_plot3d([t,x,s],(s,-1,1),(t,-1,1),color='green',opacity=.7) - sage: sp = animate([sphere_and_plane(x) for x in sxrange(-1,1,.3)]) + ....: return (sphere((0,0,0), 1, color='red', opacity=.5) + ....: + parametric_plot3d([t,x,s], (s,-1,1), (t,-1,1), + ....: color='green', opacity=.7)) + sage: sp = animate([sphere_and_plane(x) + ....: for x in sxrange(-1, 1, .3)]) sage: sp[0] # first frame Graphics3d Object sage: sp[-1] # last frame Graphics3d Object - sage: sp.show() # optional -- ImageMagick + sage: sp.show() # long time # optional -- ImageMagick sage: (x,y,z) = SR.var("x,y,z") sage: def frame(t): - ....: return implicit_plot3d((x^2 + y^2 + z^2), (x, -2, 2), (y, -2, 2), (z, -2, 2), plot_points=60, contour=[1,3,5], region=lambda x,y,z: x<=t or y>=t or z<=t) - sage: a = animate([frame(t) for t in srange(.01,1.5,.2)]) - sage: a[0] # long time + ....: return implicit_plot3d((x^2 + y^2 + z^2), + ....: (x, -2, 2), (y, -2, 2), (z, -2, 2), + ....: plot_points=60, contour=[1,3,5], + ....: region=lambda x,y,z: x<=t or y>=t or z<=t) + sage: a = animate([frame(t) for t in srange(.01, 1.5, .2)]) + sage: a[0] # long time Graphics3d Object - sage: a.show() # optional -- ImageMagick # long time + sage: a.show() # long time # optional -- ImageMagick If the input objects do not have a ``save_image`` method, then the animation object attempts to make an image by calling its internal @@ -86,8 +98,8 @@ illustrated by the following example:: sage: t = SR.var("t") - sage: a = animate((sin(c*pi*t) for c in sxrange(1,2,.2))) - sage: a.show() # optional -- ImageMagick + sage: a = animate((sin(c*pi*t) for c in sxrange(1, 2, .2))) + sage: a.show() # long time # optional -- ImageMagick AUTHORS: @@ -115,6 +127,7 @@ import builtins import os +import shlex import struct import zlib @@ -134,8 +147,8 @@ def animate(frames, **kwds): EXAMPLES:: sage: t = SR.var("t") - sage: a = animate((cos(c*pi*t) for c in sxrange(1,2,.2))) - sage: a.show() # optional -- ImageMagick + sage: a = animate((cos(c*pi*t) for c in sxrange(1, 2, .2))) + sage: a.show() # long time # optional -- ImageMagick See also :mod:`sage.plot.animate` for more examples. """ @@ -147,29 +160,28 @@ class Animation(WithEqualityById, SageObject): INPUT: - - - ``v`` - iterable of Sage objects. These should preferably be - graphics objects, but if they aren't then :meth:`make_image` is + - ``v`` -- iterable of Sage objects. These should preferably be + graphics objects, but if they aren't, then :meth:`make_image` is called on them. - - ``xmin, xmax, ymin, ymax`` - the ranges of the x and y axes. + - ``xmin, xmax, ymin, ymax`` -- the ranges of the x and y axes. - - ``**kwds`` - all additional inputs are passed onto the rendering - command. E.g., use figsize to adjust the resolution and aspect + - ``**kwds`` -- all additional inputs are passed onto the rendering + command. E.g., use ``figsize`` to adjust the resolution and aspect ratio. EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.3)], - ....: xmin=0, xmax=2*pi, figsize=[2,1]) - sage: a # optional -- ImageMagick # long time + sage: a = animate([sin(x + float(k)) for k in srange(0, 2*pi, 0.3)], + ....: xmin=0, xmax=2*pi, figsize=[2,1]) + sage: print(a) Animation with 21 frames - sage: a[:5] # optional -- ImageMagick + sage: print(a[:5]) Animation with 5 frames - sage: a.show() # optional -- ImageMagick # long time - sage: a[:5].show() # optional -- ImageMagick + sage: a.show() # long time # optional -- ImageMagick + sage: a[:5].show() # long time # optional -- ImageMagick The :meth:`show` method takes arguments to specify the delay between frames (measured in hundredths of a second, default @@ -177,18 +189,18 @@ class Animation(WithEqualityById, SageObject): means to iterate forever). To iterate 4 times with half a second between each frame:: - sage: a.show(delay=50, iterations=4) # optional -- ImageMagick # long time + sage: a.show(delay=50, iterations=4) # long time # optional -- ImageMagick An animation of drawing a parabola:: sage: step = 0.1 sage: L = Graphics() sage: v = [] - sage: for i in srange(0,1,step): - ....: L += line([(i,i^2),(i+step,(i+step)^2)], rgbcolor=(1,0,0), thickness=2) - ....: v.append(L) + sage: for i in srange(0, 1, step): + ....: L += line([(i,i^2),(i+step,(i+step)^2)], rgbcolor=(1,0,0), thickness=2) + ....: v.append(L) sage: a = animate(v, xmin=0, ymin=0) - sage: a.show() # optional -- ImageMagick + sage: a.show() # long time # optional -- ImageMagick sage: show(L) TESTS: @@ -204,7 +216,7 @@ class Animation(WithEqualityById, SageObject): sage: x = SR.var("x") sage: a = animate([plot(sin(x + float(k)), (0, 2*pi), ymin=-5, ymax=5) ....: for k in srange(0,2*pi,0.3)]) - sage: a.show() # optional -- ImageMagick # long time + sage: a.show() # long time # optional -- ImageMagick Do not convert input iterator to a list, but ensure that the frame count is known after rendering the frames:: @@ -221,7 +233,7 @@ class Animation(WithEqualityById, SageObject): <generator object ... sage: from sage.plot.animate import Animation - sage: hash(Animation()) # random + sage: hash(Animation()) # random 140658972348064 """ def __init__(self, v=None, **kwds): @@ -233,10 +245,11 @@ def __init__(self, v=None, **kwds): EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.3)], - ....: xmin=0, xmax=2*pi, figsize=[2,1]) # indirect doctest - sage: a # optional -- ImageMagick # long time + sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.3)], # indirect doctest + ....: xmin=0, xmax=2*pi, figsize=[2,1]) + sage: print(a) Animation with 21 frames + sage: a.show() # long time # optional -- ImageMagick """ self._frames = v self._kwds = kwds @@ -283,14 +296,14 @@ def __getitem__(self, i): sage: a = animate([circle((i,-i), 1-1/(i+1), hue=i/10) for i in srange(0,2,0.2)], ....: xmin=0,ymin=-2,xmax=2,ymax=0,figsize=[2,2]) - sage: a # optional -- ImageMagick + sage: print(a) Animation with 10 frames - sage: frame2 = a[2] # indirect doctest + sage: a.show() # long time # optional -- ImageMagick + sage: frame2 = a[2] # indirect doctest sage: frame2.show() - sage: a.show() # optional -- ImageMagick - sage: a[3:7] # optional -- ImageMagick # indirect doctest + sage: print(a[3:7]) # indirect doctest Animation with 4 frames - sage: a[3:7].show() # optional -- ImageMagick + sage: a[3:7].show() # long time # optional -- ImageMagick """ if isinstance(i, slice): return Animation(self._frames[i], **self._kwds) @@ -305,7 +318,7 @@ def _repr_(self): sage: a = animate([circle((i,-i), 1-1/(i+1), hue=i/10) for i in srange(0,2,0.2)], ....: xmin=0,ymin=-2,xmax=2,ymax=0,figsize=[2,2]) - sage: a # optional -- ImageMagick + sage: print(a) Animation with 10 frames sage: a._repr_() 'Animation with 10 frames' @@ -314,7 +327,7 @@ def _repr_(self): num = len(self) except TypeError: num = "unknown number of" - return "Animation with %s frames"%num + return "Animation with %s frames" % num def __add__(self, other): """ @@ -323,19 +336,25 @@ def __add__(self, other): EXAMPLES:: - sage: a = animate([circle((i,0),1) for i in srange(0,2,0.4)], - ....: xmin=0, ymin=-1, xmax=3, ymax=1, - ....: figsize=[3,1], ticks=[1,1]) + sage: a = animate([line([(0,0),(1,i)],hue=0/3) for i in range(2)], + ....: xmin=0, ymin=0, xmax=1, ymax=1, + ....: figsize=[1,1], axes=False) + sage: print(a) + Animation with 2 frames sage: a.show() # optional -- ImageMagick - sage: b = animate([circle((0,i),1,hue=0) for i in srange(0,2,0.4)], - ....: xmin=0, ymin=-1, xmax=2, ymax=3, - ....: figsize=[1,2], ticks=[1,1]) + sage: b = animate([line([(0,0),(i,1)],hue=2/3) for i in range(2)], + ....: xmin=0, ymin=0, xmax=1, ymax=1, + ....: figsize=[1,1], axes=False) + sage: print(b) + Animation with 2 frames sage: b.show() # optional -- ImageMagick sage: s = a+b # indirect doctest + sage: print(s) + Animation with 2 frames sage: len(a), len(b) - (5, 5) + (2, 2) sage: len(s) - 5 + 2 sage: s.show() # optional -- ImageMagick """ if not isinstance(other, Animation): @@ -357,18 +376,26 @@ def __mul__(self, other): EXAMPLES:: - sage: a = animate([circle((i,0),1,thickness=20*i) for i in srange(0,2,0.4)], - ....: xmin=0, ymin=-1, xmax=3, ymax=1, figsize=[2,1], axes=False) + sage: a = animate([line([(0,0),(1,i)],hue=0/3) for i in range(2)], + ....: xmin=0, ymin=0, xmax=1, ymax=1, + ....: figsize=[1,1], axes=False) + sage: print(a) + Animation with 2 frames sage: a.show() # optional -- ImageMagick - sage: b = animate([circle((0,i),1,hue=0,thickness=20*i) for i in srange(0,2,0.4)], - ....: xmin=0, ymin=-1, xmax=1, ymax=3, figsize=[1,2], axes=False) + sage: b = animate([line([(0,0),(i,1)],hue=2/3) for i in range(2)], + ....: xmin=0, ymin=0, xmax=1, ymax=1, + ....: figsize=[1,1], axes=False) + sage: print(b) + Animation with 2 frames sage: b.show() # optional -- ImageMagick sage: p = a*b # indirect doctest sage: len(a), len(b) - (5, 5) + (2, 2) sage: len(p) - 10 - sage: (a*b).show() # optional -- ImageMagick + 4 + sage: print(p) + Animation with 4 frames + sage: p.show() # optional -- ImageMagick """ if not isinstance(other, Animation): other = Animation(other) @@ -411,7 +438,9 @@ def make_image(self, frame, filename, **kwds): sage: t = SR.var("t") sage: x = lambda t: cos(t) sage: y = lambda n,t: sin(t)/n - sage: B = MyAnimation([([x(t), y(i+1,t)],(t,0,1), {'color':Color((1,0,i/4)), 'aspect_ratio':1, 'ymax':1}) for i in range(4)]) + sage: B = MyAnimation([([x(t), y(i+1,t)], (t,0,1), + ....: {'color':Color((1,0,i/4)), 'aspect_ratio':1, 'ymax':1}) + ....: for i in range(4)]) sage: d = B.png(); v = os.listdir(d); v.sort(); v # long time ['00000000.png', '00000001.png', '00000002.png', '00000003.png'] @@ -420,7 +449,8 @@ def make_image(self, frame, filename, **kwds): sage: class MyAnimation(Animation): ....: def make_image(self, frame, filename, **kwds): ....: G = frame.plot() - ....: G.set_axes_range(floor(G.xmin()),ceil(G.xmax()),floor(G.ymin()),ceil(G.ymax())) + ....: G.set_axes_range(floor(G.xmin()), ceil(G.xmax()), + ....: floor(G.ymin()), ceil(G.ymax())) ....: G.save_image(filename, **kwds) sage: B = MyAnimation([graphs.CompleteGraph(n) for n in range(7,11)], figsize=5) @@ -468,7 +498,7 @@ def png(self, dir=None): dir = tmp_dir() i = 0 for frame in self._frames: - filename = '%s/%08d.png'%(dir,i) + filename = '%s/%08d.png' % (dir,i) try: save_image = frame.save_image except AttributeError: @@ -490,32 +520,35 @@ def graphics_array(self, ncols=3): EXAMPLES:: + sage: # needs sage.schemes sage: E = EllipticCurve('37a') - sage: v = [E.change_ring(GF(p)).plot(pointsize=30) for p in [97, 101, 103, 107]] + sage: v = [E.change_ring(GF(p)).plot(pointsize=30) + ....: for p in [97, 101, 103]] sage: a = animate(v, xmin=0, ymin=0, axes=False) - sage: a # optional -- ImageMagick - Animation with 4 frames - sage: a.show() # optional -- ImageMagick + sage: print(a) + Animation with 3 frames + sage: a.show() # optional -- ImageMagick Modify the default arrangement of array:: - sage: g = a.graphics_array(); print(g) - Graphics Array of size 2 x 3 - sage: g.show(figsize=[6,3]) # not tested + sage: g = a.graphics_array(); print(g) # needs sage.schemes + Graphics Array of size 1 x 3 + sage: g.show(figsize=[6,3]) # needs sage.schemes Specify different arrangement of array and save it with a given file name:: - sage: g = a.graphics_array(ncols=2); print(g) + sage: g = a.graphics_array(ncols=2); print(g) # needs sage.schemes Graphics Array of size 2 x 2 - sage: f = tmp_filename(ext='.png') - sage: g.save(f) + sage: f = tmp_filename(ext='.png'); print(f) # needs sage.schemes + ...png + sage: g.save(f) # needs sage.schemes Frames can be specified as a generator too; it is internally converted to a list:: sage: t = SR.var("t") sage: b = animate((plot(sin(c*pi*t)) for c in sxrange(1,2,.2))) sage: g = b.graphics_array() - sage: g + sage: print(g) Graphics Array of size 2 x 3 """ ncols = int(ncols) @@ -563,16 +596,21 @@ def gif(self, delay=20, savefile=None, iterations=0, show_path=False, EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], + sage: a = animate([sin(x + float(k)) + ....: for k in srange(0,2*pi,0.7)], ....: xmin=0, xmax=2*pi, ymin=-1, ymax=1, figsize=[2,1]) sage: td = tmp_dir() sage: a.gif() # not tested - sage: a.gif(savefile=td + 'my_animation.gif', delay=35, iterations=3) # optional -- ImageMagick - sage: with open(td + 'my_animation.gif', 'rb') as f: print(b'GIF8' in f.read()) # optional -- ImageMagick + sage: a.gif(savefile=td + 'my_animation.gif', # long time # optional -- ImageMagick + ....: delay=35, iterations=3) + sage: with open(td + 'my_animation.gif', 'rb') as f: # long time # optional -- ImageMagick + ....: print(b'GIF8' in f.read()) True - sage: a.gif(savefile=td + 'my_animation.gif', show_path=True) # optional -- ImageMagick + sage: a.gif(savefile=td + 'my_animation.gif', # long time # optional -- ImageMagick + ....: show_path=True) Animation saved to .../my_animation.gif. - sage: a.gif(savefile=td + 'my_animation_2.gif', show_path=True, use_ffmpeg=True) # optional -- ffmpeg + sage: a.gif(savefile=td + 'my_animation_2.gif', # long time # optional -- FFmpeg + ....: show_path=True, use_ffmpeg=True) Animation saved to .../my_animation_2.gif. .. NOTE:: @@ -643,7 +681,7 @@ def _gif_from_imagemagick(self, savefile=None, show_path=False, sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], ....: xmin=0, xmax=2*pi, ymin=-1, ymax=1, figsize=[2,1]) sage: td = tmp_dir() - sage: a._gif_from_imagemagick(savefile=td + 'new.gif') # optional -- imagemagick + sage: a._gif_from_imagemagick(savefile=td + 'new.gif') # long time # optional -- ImageMagick .. NOTE:: @@ -700,7 +738,7 @@ def _rich_repr_(self, display_manager, **kwds): EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([plot(x^2 + n) for n in range(4)], ymin=0, ymax=4) + sage: a = animate([plot(x^2 + n) for n in range(2)], ymin=0, ymax=4) sage: from sage.repl.rich_output import get_display_manager sage: dm = get_display_manager() sage: a._rich_repr_(dm) # optional -- ImageMagick @@ -793,40 +831,43 @@ def show(self, delay=None, iterations=None, **kwds): EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], - ....: xmin=0, xmax=2*pi, figsize=[2,1]) - sage: a.show() # optional -- ImageMagick + sage: a = animate([sin(x + float(k)) + ....: for k in srange(0,2*pi,0.7)], + ....: xmin=0, xmax=2*pi, figsize=[2,1]) + sage: a.show() # long time # optional -- ImageMagick The preceding will loop the animation forever. If you want to show only three iterations instead:: - sage: a.show(iterations=3) # optional -- ImageMagick + sage: a.show(iterations=3) # long time # optional -- ImageMagick To put a half-second delay between frames:: - sage: a.show(delay=50) # optional -- ImageMagick + sage: a.show(delay=50) # long time # optional -- ImageMagick You can also make use of the HTML5 video element in the Sage Notebook:: - sage: a.show(format="ogg") # optional -- ffmpeg - sage: a.show(format="webm") # optional -- ffmpeg - sage: a.show(format="mp4") # optional -- ffmpeg - sage: a.show(format="webm", iterations=1) # optional -- ffmpeg + sage: # long time, optional -- FFmpeg + sage: a.show(format="ogg") + sage: a.show(format="webm") + sage: a.show(format="mp4") + sage: a.show(format="webm", iterations=1) Other backends may support other file formats as well:: - sage: a.show(format="flash") # optional -- ffmpeg - sage: a.show(format="matroska") # optional -- ffmpeg - sage: a.show(format="avi") # optional -- ffmpeg - sage: a.show(format="wmv") # optional -- ffmpeg - sage: a.show(format="quicktime") # optional -- ffmpeg + sage: # long time, optional -- FFmpeg + sage: a.show(format="flash") + sage: a.show(format="matroska") + sage: a.show(format="avi") + sage: a.show(format="wmv") + sage: a.show(format="quicktime") TESTS: Use of positional parameters is discouraged, will likely get deprecated, but should still work for the time being:: - sage: a.show(50, 3) # optional -- ImageMagick + sage: a.show(50, 3) # long time # optional -- ImageMagick .. NOTE:: @@ -850,7 +891,6 @@ def show(self, delay=None, iterations=None, **kwds): dm = get_display_manager() dm.display_immediately(self, **kwds) - def ffmpeg(self, savefile=None, show_path=False, output_format=None, ffmpeg_options='', delay=None, iterations=0, pix_fmt='rgb24'): r""" @@ -906,13 +946,14 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None, EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], + sage: a = animate([sin(x + float(k)) + ....: for k in srange(0, 2*pi, 0.7)], ....: xmin=0, xmax=2*pi, ymin=-1, ymax=1, figsize=[2,1]) sage: td = tmp_dir() - sage: a.ffmpeg(savefile=td + 'new.mpg') # optional -- ffmpeg - sage: a.ffmpeg(savefile=td + 'new.avi') # optional -- ffmpeg - sage: a.ffmpeg(savefile=td + 'new.gif') # optional -- ffmpeg - sage: a.ffmpeg(savefile=td + 'new.mpg', show_path=True) # optional -- ffmpeg + sage: a.ffmpeg(savefile=td + 'new.mpg') # long time # optional -- FFmpeg + sage: a.ffmpeg(savefile=td + 'new.avi') # long time # optional -- FFmpeg + sage: a.ffmpeg(savefile=td + 'new.gif') # long time # optional -- FFmpeg + sage: a.ffmpeg(savefile=td + 'new.mpg', show_path=True) # long time # optional -- FFmpeg Animation saved to .../new.mpg. .. NOTE:: @@ -926,7 +967,7 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None, TESTS:: - sage: a.ffmpeg(output_format='gif',delay=30,iterations=5) # optional -- ffmpeg + sage: a.ffmpeg(output_format='gif',delay=30,iterations=5) # long time # optional -- FFmpeg """ from sage.features.ffmpeg import FFmpeg FFmpeg().require() @@ -981,7 +1022,8 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None, # afterwards. Hence 'early_options' and 'ffmpeg_options' # The `-nostdin` is needed to avoid the command to hang, see # https://stackoverflow.com/questions/16523746/ffmpeg-hangs-when-run-in-background - cmd = 'cd "%s"; ffmpeg -nostdin -y -f image2 %s -i %s %s %s' % (pngdir, early_options, pngs, ffmpeg_options, savefile) + cmd = 'cd %s; ffmpeg -nostdin -y -f image2 %s -i %s %s %s' % ( + shlex.quote(pngdir), early_options, shlex.quote(pngs), ffmpeg_options, shlex.quote(savefile)) from subprocess import check_call, CalledProcessError, PIPE try: if sage.misc.verbose.get_verbose() > 0: @@ -1025,27 +1067,36 @@ def apng(self, savefile=None, show_path=False, delay=20, iterations=0): EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], - ....: xmin=0, xmax=2*pi, figsize=[2,1]) + sage: a = animate([sin(x + float(k)) + ....: for k in srange(0,2*pi,0.7)], + ....: xmin=0, xmax=2*pi, figsize=[2,1]) sage: dir = tmp_dir() - sage: a.apng() # long time + sage: a.apng(show_path=True) # long time + Animation saved to ....png. sage: a.apng(savefile=dir + 'my_animation.png', delay=35, iterations=3) # long time sage: a.apng(savefile=dir + 'my_animation.png', show_path=True) # long time Animation saved to .../my_animation.png. If the individual frames have different sizes, an error will be raised:: - sage: a = animate([plot(sin(x), (x, 0, k)) for k in range(1,4)], + sage: a = animate([plot(sin(x), (x, 0, k)) + ....: for k in range(1,4)], ....: ymin=-1, ymax=1, aspect_ratio=1, figsize=[2,1]) sage: a.apng() # long time Traceback (most recent call last): ... ValueError: Chunk IHDR mismatch + TESTS:: + + sage: a = animate([]) + sage: a.apng(show_path=True) + Animation saved to file ....png. + """ pngdir = self.png() if savefile is None: - savefile = tmp_filename('.png') + savefile = tmp_filename(ext='.png') with open(savefile, "wb") as out: apng = APngAssembler( out, len(self), @@ -1087,14 +1138,15 @@ def save(self, filename=None, show_path=False, use_ffmpeg=False, **kwds): EXAMPLES:: sage: x = SR.var("x") - sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], + sage: a = animate([sin(x + float(k)) + ....: for k in srange(0, 2*pi, 0.7)], ....: xmin=0, xmax=2*pi, ymin=-1, ymax=1, figsize=[2,1]) sage: td = tmp_dir() sage: a.save() # not tested - sage: a.save(td + 'wave.gif') # optional -- ImageMagick - sage: a.save(td + 'wave.gif', show_path=True) # optional -- ImageMagick + sage: a.save(td + 'wave.gif') # long time # optional -- ImageMagick + sage: a.save(td + 'wave.gif', show_path=True) # long time # optional -- ImageMagick Animation saved to file .../wave.gif. - sage: a.save(td + 'wave.avi', show_path=True) # optional -- ffmpeg + sage: a.save(td + 'wave.avi', show_path=True) # long time # optional -- FFmpeg Animation saved to file .../wave.avi. sage: a.save(td + 'wave0.sobj') sage: a.save(td + 'wave1.sobj', show_path=True) @@ -1108,18 +1160,23 @@ def save(self, filename=None, show_path=False, use_ffmpeg=False, **kwds): Ensure that we can pass delay and iteration count to the saved GIF image (see :trac:`18176`):: - sage: a.save(td + 'wave.gif') # optional -- ImageMagick - sage: with open(td + 'wave.gif', 'rb') as f: print(b'GIF8' in f.read()) # optional -- ImageMagick + sage: # long time, optional -- ImageMagick + sage: a.save(td + 'wave.gif') + sage: with open(td + 'wave.gif', 'rb') as f: + ....: print(b'GIF8' in f.read()) True - sage: with open(td + 'wave.gif', 'rb') as f: print(b'!\xff\x0bNETSCAPE2.0\x03\x01\x00\x00\x00' in f.read()) # optional -- ImageMagick + sage: with open(td + 'wave.gif', 'rb') as f: + ....: print(b'!\xff\x0bNETSCAPE2.0\x03\x01\x00\x00\x00' in f.read()) True - sage: a.save(td + 'wave.gif', delay=35) # optional -- ImageMagick - sage: with open(td + 'wave.gif', 'rb') as f: print(b'GIF8' in f.read()) # optional -- ImageMagick + sage: a.save(td + 'wave.gif', delay=35) + sage: with open(td + 'wave.gif', 'rb') as f: + ....: print(b'GIF8' in f.read()) True - sage: a.save(td + 'wave.gif', iterations=3) # optional -- ImageMagick - sage: with open(td + 'wave.gif', 'rb') as f: print(b'!\xff\x0bNETSCAPE2.0\x03\x01\x00\x00\x00' in f.read()) # optional -- ImageMagick + sage: a.save(td + 'wave.gif', iterations=3) + sage: with open(td + 'wave.gif', 'rb') as f: + ....: print(b'!\xff\x0bNETSCAPE2.0\x03\x01\x00\x00\x00' in f.read()) False - sage: with open(td + 'wave.gif', 'rb') as f: # optional -- ImageMagick + sage: with open(td + 'wave.gif', 'rb') as f: ....: check1 = b'!\xff\x0bNETSCAPE2.0\x03\x01\x02\x00\x00' ....: check2 = b'!\xff\x0bNETSCAPE2.0\x03\x01\x03\x00\x00' ....: data = f.read() @@ -1166,7 +1223,8 @@ def interactive(self, **kwds): EXAMPLES:: sage: x = SR.var("x") - sage: frames = [point3d((sin(x), cos(x), x)) for x in (0, pi/16, .., 2*pi)] + sage: frames = [point3d((sin(x), cos(x), x)) + ....: for x in (0, pi/16, .., 2*pi)] sage: animate(frames).interactive(online=True) Graphics3d Object @@ -1217,16 +1275,16 @@ class APngAssembler(): INPUT: - - ``out`` -- a file opened for binary writing to which the data - will be written + - ``out`` -- a file opened for binary writing to which the data + will be written - - ``num_frames`` -- the number of frames in the animation + - ``num_frames`` -- the number of frames in the animation - - ``num_plays`` -- how often to iterate, 0 means infinitely + - ``num_plays`` -- how often to iterate, 0 means infinitely - - ``delay`` -- numerator of the delay fraction in seconds + - ``delay`` -- numerator of the delay fraction in seconds - - ``delay_denominator`` -- denominator of the delay in seconds + - ``delay_denominator`` -- denominator of the delay in seconds EXAMPLES:: diff --git a/src/sage/plot/arc.py b/src/sage/plot/arc.py index f65973bcbd5..84a62554118 100644 --- a/src/sage/plot/arc.py +++ b/src/sage/plot/arc.py @@ -45,6 +45,7 @@ class Arc(GraphicPrimitive): Note that the construction should be done using ``arc``:: + sage: from math import pi sage: from sage.plot.arc import Arc sage: print(Arc(0,0,1,1,pi/4,pi/4,pi/2,{})) Arc with center (0.0,0.0) radii (1.0,1.0) angle 0.78539816339... inside the sector (0.78539816339...,1.5707963267...) @@ -115,6 +116,7 @@ def get_minmax_data(self): The same example with a rotation of angle `\pi/2`:: + sage: from math import pi sage: p = arc((-2, 3), 1, 2, pi/2) sage: d = p.get_minmax_data() sage: d['xmin'] @@ -293,6 +295,7 @@ def bezier_path(self): sage: Arc(2,3,2.2,2.2,0,2,3,op).bezier_path() Graphics object consisting of 1 graphics primitive + sage: from math import pi sage: a = arc((0,0),2,1,0,(pi/5,pi/2+pi/12), linestyle="--", color="red") sage: b = a[0].bezier_path() sage: b[0] @@ -348,6 +351,7 @@ def _render_on_subplot(self, subplot): """ TESTS:: + sage: from math import pi sage: A = arc((1,1),3,4,pi/4,(pi,4*pi/3)); A Graphics object consisting of 1 graphics primitive """ @@ -421,6 +425,7 @@ def arc(center, r1, r2=None, angle=0.0, sector=(0.0, 2 * pi), **options): Plot an arc of circle centered at (0,0) with radius 1 in the sector `(\pi/4,3*\pi/4)`:: + sage: from math import pi sage: arc((0,0), 1, sector=(pi/4,3*pi/4)) Graphics object consisting of 1 graphics primitive diff --git a/src/sage/plot/arrow.py b/src/sage/plot/arrow.py index 13b3b07d241..179e026d2e4 100644 --- a/src/sage/plot/arrow.py +++ b/src/sage/plot/arrow.py @@ -413,7 +413,10 @@ def get_paths(self, renderer): return paths def __call__(self, renderer, gc, tpath, affine, rgbFace): - path = self.get_paths(renderer)[self._n] + paths = self.get_paths(renderer) + if self._n >= len(paths): + return False + path = paths[self._n] vert1, code1 = path.vertices, path.codes import numpy as np @@ -470,6 +473,13 @@ def arrow(tailpoint=None, headpoint=None, **kwds): sphinx_plot(arrow((0,0,1), (1,1,1))) + TESTS: + + Check that :trac:`35031` is fixed:: + + sage: arrow((0,0), (0,0), linestyle='dashed') + Graphics object consisting of 1 graphics primitive + """ try: return arrow2d(tailpoint, headpoint, **kwds) @@ -576,7 +586,8 @@ def arrow2d(tailpoint=None, headpoint=None, path=None, **options): A pretty circle of arrows:: - sage: sum([arrow2d((0,0), (cos(x),sin(x)), hue=x/(2*pi)) for x in [0..2*pi,step=0.1]]) + sage: sum(arrow2d((0,0), (cos(x),sin(x)), hue=x/(2*pi)) # needs sage.symbolic + ....: for x in [0..2*pi, step=0.1]) Graphics object consisting of 63 graphics primitives .. PLOT:: diff --git a/src/sage/plot/bezier_path.py b/src/sage/plot/bezier_path.py index 27c95f10c0c..a8bffed51ba 100644 --- a/src/sage/plot/bezier_path.py +++ b/src/sage/plot/bezier_path.py @@ -168,9 +168,9 @@ def plot3d(self, z=0, **kwds): EXAMPLES:: sage: b = bezier_path([[(0,0),(0,1),(1,0)]]) - sage: A = b.plot3d() - sage: B = b.plot3d(z=2) - sage: A + B + sage: A = b.plot3d() # needs sage.symbolic + sage: B = b.plot3d(z=2) # needs sage.symbolic + sage: A + B # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -182,7 +182,7 @@ def plot3d(self, z=0, **kwds): :: - sage: bezier3d([[(0,0,0),(1,0,0),(0,1,0),(0,1,1)]]) + sage: bezier3d([[(0,0,0),(1,0,0),(0,1,0),(0,1,1)]]) # needs sage.symbolic Graphics3d Object .. PLOT:: diff --git a/src/sage/plot/circle.py b/src/sage/plot/circle.py index 1dc58e02e39..41281b66735 100644 --- a/src/sage/plot/circle.py +++ b/src/sage/plot/circle.py @@ -25,18 +25,18 @@ class Circle(GraphicPrimitive): """ - Primitive class for the Circle graphics type. See circle? for information + Primitive class for the :class:`Circle` graphics type. See ``circle?`` for information about actually plotting circles. INPUT: - - x -- `x`-coordinate of center of Circle + - ``x`` -- `x`-coordinate of center of Circle - - y -- `y`-coordinate of center of Circle + - ``y`` -- `y`-coordinate of center of Circle - - r -- radius of Circle object + - ``r`` -- radius of Circle object - - options -- dict of valid plot options to pass to constructor + - ``options`` -- dict of valid plot options to pass to constructor EXAMPLES: @@ -80,7 +80,7 @@ def __init__(self, x, y, r, options): def get_minmax_data(self): """ - Returns a dictionary with the bounding box data. + Return a dictionary with the bounding box data. EXAMPLES:: @@ -133,12 +133,13 @@ def _repr_(self): sage: c = C[0]; c Circle defined by (2.0,3.0) with r=5.0 """ - return "Circle defined by (%s,%s) with r=%s"%(self.x, self.y, self.r) + return "Circle defined by (%s,%s) with r=%s" % (self.x, self.y, self.r) def _render_on_subplot(self, subplot): """ TESTS:: + sage: from math import pi sage: C = circle((2,pi), 2, edgecolor='black', facecolor='green', fill=True) """ import matplotlib.patches as patches @@ -147,7 +148,7 @@ def _render_on_subplot(self, subplot): options = self.options() p = patches.Circle((float(self.x), float(self.y)), float(self.r), clip_on=options['clip']) if not options['clip']: - self._bbox_extra_artists=[p] + self._bbox_extra_artists = [p] p.set_linewidth(float(options['thickness'])) p.set_fill(options['fill']) a = float(options['alpha']) @@ -182,7 +183,8 @@ def plot3d(self, z=0, **kwds): This example uses this method implicitly, but does not pass the optional parameter z to this method:: - sage: sum([circle((random(),random()), random()).plot3d(z=random()) for _ in range(20)]) + sage: sum(circle((random(),random()), random()).plot3d(z=random()) + ....: for _ in range(20)) Graphics3d Object .. PLOT:: @@ -192,6 +194,7 @@ def plot3d(self, z=0, **kwds): These examples are explicit, and pass z to this method:: + sage: from math import pi sage: C = circle((2,pi), 2, hue=.8, alpha=.3, fill=True) sage: c = C[0] sage: d = c.plot3d(z=2) @@ -304,14 +307,16 @@ def circle(center, radius, **options): Here we make a more complicated plot, with many circles of different colors:: sage: g = Graphics() - sage: step=6; ocur=1/5; paths=16 + sage: step = 6; ocur = 1/5; paths = 16 sage: PI = math.pi # numerical for speed -- fine for graphics sage: for r in range(1,paths+1): - ....: for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) for n in srange(0, 2*PI+PI/step, PI/step)]: + ....: for x,y in [((r+ocur)*math.cos(n), (r+ocur)*math.sin(n)) + ....: for n in srange(0, 2*PI+PI/step, PI/step)]: ....: g += circle((x,y), ocur, rgbcolor=hue(r/paths)) ....: rnext = (r+1)^2 ....: ocur = (rnext-r)-ocur - sage: g.show(xmin=-(paths+1)^2, xmax=(paths+1)^2, ymin=-(paths+1)^2, ymax=(paths+1)^2, figsize=[6,6]) + sage: g.show(xmin=-(paths+1)^2, xmax=(paths+1)^2, + ....: ymin=-(paths+1)^2, ymax=(paths+1)^2, figsize=[6,6]) .. PLOT:: @@ -358,7 +363,8 @@ def circle(center, radius, **options): And circles with legends:: - sage: circle((4,5), 1, rgbcolor='yellow', fill=True, legend_label='the sun').show(xmin=0, ymin=0) + sage: circle((4,5), 1, rgbcolor='yellow', fill=True, + ....: legend_label='the sun').show(xmin=0, ymin=0) .. PLOT:: @@ -368,7 +374,8 @@ def circle(center, radius, **options): :: - sage: circle((4,5), 1, legend_label='the sun', legend_color='yellow').show(xmin=0, ymin=0) + sage: circle((4,5), 1, + ....: legend_label='the sun', legend_color='yellow').show(xmin=0, ymin=0) .. PLOT:: @@ -378,12 +385,12 @@ def circle(center, radius, **options): Extra options will get passed on to show(), as long as they are valid:: - sage: circle((0, 0), 2, figsize=[10,10]) # That circle is huge! + sage: circle((0, 0), 2, figsize=[10,10]) # That circle is huge! Graphics object consisting of 1 graphics primitive :: - sage: circle((0, 0), 2).show(figsize=[10,10]) # These are equivalent + sage: circle((0, 0), 2).show(figsize=[10,10]) # These are equivalent TESTS: diff --git a/src/sage/plot/colors.py b/src/sage/plot/colors.py index bc89be406ea..8c0db2b3c34 100644 --- a/src/sage/plot/colors.py +++ b/src/sage/plot/colors.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.plot r""" Colors diff --git a/src/sage/plot/complex_plot.pyx b/src/sage/plot/complex_plot.pyx index 6f0aeab87ae..cb6a9cf8ca0 100644 --- a/src/sage/plot/complex_plot.pyx +++ b/src/sage/plot/complex_plot.pyx @@ -461,6 +461,8 @@ def complex_to_rgb(z_values, contoured=False, tiled=False, rgb[i, j, 2] = b sig_off() + nan_indices = np.isnan(rgb).any(-1) # Mask for undefined points + rgb[nan_indices] = 1 # Make nan_indices white return rgb @@ -561,7 +563,7 @@ def complex_to_cmap_rgb(z_values, cmap='turbo', contoured=False, tiled=False, import matplotlib as mpl if isinstance(cmap, str): - cmap = mpl.cm.get_cmap(cmap) + cmap = mpl.colormaps[cmap] if contour_base is None: if contour_type == "linear": @@ -576,7 +578,6 @@ def complex_to_cmap_rgb(z_values, cmap='turbo', contoured=False, tiled=False, cdef unsigned int i, j, imax, jmax cdef double x, y, mag, arg cdef double lightness_delta - cdef double r, g, b cdef ComplexDoubleElement z from sage.rings.complex_double import CDF @@ -668,11 +669,14 @@ def add_lightness_smoothing_to_rgb(rgb, delta): We can call this on grids of values:: + sage: # needs numpy sage: import numpy as np sage: from sage.plot.complex_plot import add_lightness_smoothing_to_rgb - sage: add_lightness_smoothing_to_rgb(np.array([[[0, 0.25, 0.5]]]), np.array([[0.75]])) # abs tol 1e-4 + sage: add_lightness_smoothing_to_rgb( # abs tol 1e-4 + ....: np.array([[[0, 0.25, 0.5]]]), np.array([[0.75]])) array([[[0.75 , 0.8125, 0.875 ]]]) - sage: add_lightness_smoothing_to_rgb(np.array([[[0, 0.25, 0.5]]]), np.array([[0.75]])) # abs tol 1e-4 + sage: add_lightness_smoothing_to_rgb( # abs tol 1e-4 + ....: np.array([[[0, 0.25, 0.5]]]), np.array([[0.75]])) array([[[0.75 , 0.8125, 0.875 ]]]) """ import numpy as np @@ -730,21 +734,25 @@ def add_contours_to_rgb(rgb, delta, dark_rate=0.5): EXAMPLES:: + sage: # needs numpy sage: import numpy as np sage: from sage.plot.complex_plot import add_contours_to_rgb - sage: add_contours_to_rgb(np.array([[[0, 0.25, 0.5]]]), np.array([[0.75]])) # abs tol 1e-4 + sage: add_contours_to_rgb(np.array([[[0, 0.25, 0.5]]]), # abs tol 1e-4 + ....: np.array([[0.75]])) array([[[0.25 , 0.625, 1. ]]]) - sage: add_contours_to_rgb(np.array([[[0, 0, 0]]]), np.array([[1]])) # abs tol 1e-4 + sage: add_contours_to_rgb(np.array([[[0, 0, 0]]]), # abs tol 1e-4 + ....: np.array([[1]])) array([[[0.5, 0.5, 0.5]]]) - sage: add_contours_to_rgb(np.array([[[1, 1, 1]]]), np.array([[-0.5]])) # abs tol 1e-4 + sage: add_contours_to_rgb(np.array([[[1, 1, 1]]]), # abs tol 1e-4 + ....: np.array([[-0.5]])) array([[[0.75, 0.75, 0.75]]]) Raising ``dark_rate`` leads to bigger adjustments:: - sage: add_contours_to_rgb(np.array([[[0.5, 0.5, 0.5]]]), # abs tol 1e-4 + sage: add_contours_to_rgb(np.array([[[0.5, 0.5, 0.5]]]), # abs tol 1e-4 # needs numpy ....: np.array([[0.5]]), dark_rate=0.1) array([[[0.55, 0.55, 0.55]]]) - sage: add_contours_to_rgb(np.array([[[0.5, 0.5, 0.5]]]), # abs tol 1e-4 + sage: add_contours_to_rgb(np.array([[[0.5, 0.5, 0.5]]]), # abs tol 1e-4 # needs numpy ....: np.array([[0.5]]), dark_rate=0.5) array([[[0.75, 0.75, 0.75]]]) """ @@ -926,7 +934,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Here we plot a couple of simple functions:: - sage: complex_plot(sqrt(x), (-5, 5), (-5, 5)) + sage: complex_plot(sqrt(x), (-5, 5), (-5, 5)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -935,7 +943,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, :: - sage: complex_plot(sin(x), (-5, 5), (-5, 5)) + sage: complex_plot(sin(x), (-5, 5), (-5, 5)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -944,7 +952,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, :: - sage: complex_plot(log(x), (-10, 10), (-10, 10)) + sage: complex_plot(log(x), (-10, 10), (-10, 10)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -953,7 +961,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, :: - sage: complex_plot(exp(x), (-10, 10), (-10, 10)) + sage: complex_plot(exp(x), (-10, 10), (-10, 10)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -962,7 +970,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, A plot with a different choice of colormap:: - sage: complex_plot(exp(x), (-10, 10), (-10, 10), cmap='viridis') + sage: complex_plot(exp(x), (-10, 10), (-10, 10), cmap='viridis') # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -971,8 +979,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, A function with some nice zeros and a pole:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3)) + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -983,8 +991,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, The same function as above, but with contours. Contours render poorly with few plot points, so we use 300 here:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, contoured=True) + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, contoured=True) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -994,8 +1002,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, The same function as above, but tiled and with the *plasma* colormap:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), # needs sage.symbolic ....: plot_points=300, tiled=True, cmap='plasma') Graphics object consisting of 1 graphics primitive @@ -1008,8 +1016,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, controlled by adjusting ``nphases``. We make the same plot with fewer tilings:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, # needs sage.symbolic ....: tiled=True, nphases=5, cmap='plasma') Graphics object consisting of 1 graphics primitive @@ -1021,8 +1029,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, It is also possible to use *linear* contours. We plot the same function above on an inset, setting contours to appear `1` apart:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (0, 1), (0, 1), plot_points=300, + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (0, 1), (0, 1), plot_points=300, # needs sage.symbolic ....: contoured=True, contour_type='linear', contour_base=1) Graphics object consisting of 1 graphics primitive @@ -1034,8 +1042,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Note that tightly spaced contours can lead to Moirรฉ patterns and aliasing problems. For example:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, # needs sage.symbolic ....: contoured=True, contour_type='linear', contour_base=1) Graphics object consisting of 1 graphics primitive @@ -1048,8 +1056,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, be considered more appropriate for showing changes in phase without sharp color contrasts:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, cmap='twilight') + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), plot_points=300, cmap='twilight') # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1060,8 +1068,8 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Passing *matplotlib* as the colormap gives a special colormap that is similar to the default:: - sage: f(z) = z^5 + z - 1 + 1/z - sage: complex_plot(f, (-3, 3), (-3, 3), + sage: f(z) = z^5 + z - 1 + 1/z # needs sage.symbolic + sage: complex_plot(f, (-3, 3), (-3, 3), # needs sage.symbolic ....: plot_points=300, contoured=True, cmap='matplotlib') Graphics object consisting of 1 graphics primitive @@ -1072,7 +1080,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Here is the identity, useful for seeing what values map to what colors:: - sage: complex_plot(lambda z: z, (-3, 3), (-3, 3)) + sage: complex_plot(lambda z: z, (-3, 3), (-3, 3)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1081,7 +1089,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, The Riemann Zeta function:: - sage: complex_plot(zeta, (-30,30), (-30,30)) + sage: complex_plot(zeta, (-30,30), (-30,30)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1092,7 +1100,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, ``dark_rate`` will make regions become darker/lighter faster when there are no contours:: - sage: complex_plot(zeta, (-30, 30), (-30, 30), dark_rate=1.0) + sage: complex_plot(zeta, (-30, 30), (-30, 30), dark_rate=1.0) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1102,7 +1110,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Decreasing ``dark_rate`` has the opposite effect. When there are contours, adjust ``dark_rate`` affects how visible contours are. Compare:: - sage: complex_plot(zeta, (-1, 9), (10, 20), plot_points=200, # long time + sage: complex_plot(zeta, (-1, 9), (10, 20), plot_points=200, # long time, needs sage.symbolic ....: contoured=True, cmap='twilight', dark_rate=0.2) Graphics object consisting of 1 graphics primitive @@ -1112,7 +1120,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, and:: - sage: complex_plot(zeta, (-1, 9), (10, 20), plot_points=200, # long time + sage: complex_plot(zeta, (-1, 9), (10, 20), plot_points=200, # long time, needs sage.symbolic ....: contoured=True, cmap='twilight', dark_rate=0.75) Graphics object consisting of 1 graphics primitive @@ -1125,12 +1133,12 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Extra options will get passed on to show(), as long as they are valid:: - sage: complex_plot(lambda z: z, (-3, 3), (-3, 3), figsize=[1,1]) + sage: complex_plot(lambda z: z, (-3, 3), (-3, 3), figsize=[1,1]) # needs sage.symbolic Graphics object consisting of 1 graphics primitive :: - sage: complex_plot(lambda z: z, (-3, 3), (-3, 3)).show(figsize=[1,1]) # These are equivalent + sage: complex_plot(lambda z: z, (-3, 3), (-3, 3)).show(figsize=[1,1]) # These are equivalent # needs sage.symbolic REFERENCES: @@ -1142,6 +1150,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, Test to make sure that using fast_callable functions works:: + sage: # needs sage.symbolic sage: f(x) = x^2 sage: g = fast_callable(f, domain=CC, vars='x') sage: h = fast_callable(f, domain=CDF, vars='x') @@ -1161,7 +1170,7 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, :: - sage: complex_plot(sqrt, (-5, 5), (-5, 5)) + sage: complex_plot(sqrt, (-5, 5), (-5, 5)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ import matplotlib as mpl @@ -1204,11 +1213,11 @@ def complex_plot(f, x_range, y_range, contoured=False, tiled=False, cmap=None, domain = np.linspace(0, 1, 256) shifted_domain = np.roll(domain, 128) default_cmap = mpl.colors.LinearSegmentedColormap.from_list( - "sage_default", mpl.cm.get_cmap('hsv')(shifted_domain) + "sage_default", mpl.colormaps['hsv'](shifted_domain) ) cmap = default_cmap else: - cmap = mpl.cm.get_cmap(cmap) + cmap = mpl.colormaps[cmap] rgbs = complex_to_cmap_rgb( z_values, cmap=cmap, contoured=contoured, tiled=tiled, contour_type=contour_type, contour_base=contour_base, diff --git a/src/sage/plot/contour_plot.py b/src/sage/plot/contour_plot.py index c0cab456686..9c70ebd3e49 100644 --- a/src/sage/plot/contour_plot.py +++ b/src/sage/plot/contour_plot.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Contour plots """ @@ -848,9 +849,7 @@ def f(x,y): return cos(x) + sin(y) sage: contour_plot(lambda x,y: 0, (-1,1), (-1,1), ....: contours=[0], fill=False, cmap=['blue']) - ... - UserWarning: No contour levels were found within the data range. - Graphics object consisting of 1 graphics primitive + ...Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -874,8 +873,7 @@ def f(x,y): return cos(x) + sin(y) Check that :trac:`18074` is fixed:: sage: contour_plot(0, (0,1), (0,1)) - ... UserWarning: No contour levels were found within the data range. - Graphics object consisting of 1 graphics primitive + ...Graphics object consisting of 1 graphics primitive Domain points in :trac:`11648` with complex output are now skipped:: @@ -1164,8 +1162,9 @@ def f(x,y): return x**2 + y**2 - 2 The same circle with different line and fill colors:: - sage: implicit_plot(f, (-3,3), (-3,3), color='red', fill=True, fillcolor='green', - ....: plot_points=500) # long time + sage: implicit_plot(f, (-3,3), (-3,3), color='red', # long time + ....: fill=True, fillcolor='green', + ....: plot_points=500) Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1310,8 +1309,8 @@ def f(x,y): symbolic expression the user should increase the number of plot points to avoid artifacts:: - sage: implicit_plot(lambda x, y: x^2 + y^2 - 2, (x,-3,3), (y,-3,3), - ....: fill=True, plot_points=500) # long time + sage: implicit_plot(lambda x, y: x^2 + y^2 - 2, (x,-3,3), # long time + ....: (y,-3,3), fill=True, plot_points=500) Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1395,8 +1394,7 @@ def f(x,y): @options(plot_points=100, incol='blue', outcol=None, bordercol=None, borderstyle=None, borderwidth=None, frame=False, axes=True, legend_label=None, aspect_ratio=1, alpha=1) -def region_plot(f, xrange, yrange, plot_points, incol, outcol, bordercol, - borderstyle, borderwidth, alpha, **options): +def region_plot(f, xrange, yrange, **options): r""" ``region_plot`` takes a boolean function of two variables, `f(x, y)` and plots the region where f is True over the specified @@ -1660,6 +1658,14 @@ def region_plot(f, xrange, yrange, plot_points, incol, outcol, bordercol, from warnings import warn import numpy + plot_points = options['plot_points'] + incol = options.pop('incol') + outcol = options.pop('outcol') + bordercol = options.pop('bordercol') + borderstyle = options.pop('borderstyle') + borderwidth = options.pop('borderwidth') + alpha = options.pop('alpha') + if not isinstance(f, (list, tuple)): f = [f] @@ -1678,9 +1684,9 @@ def region_plot(f, xrange, yrange, plot_points, incol, outcol, bordercol, if neqs and not bordercol: bordercol = incol if not f: - return implicit_plot(feqs[0], xrange, yrange, plot_points=plot_points, - fill=False, linewidth=borderwidth, - linestyle=borderstyle, color=bordercol, **options) + return implicit_plot(feqs[0], xrange, yrange, fill=False, + linewidth=borderwidth, linestyle=borderstyle, + color=bordercol, **options) f_all, ranges = setup_for_eval_on_grid(feqs + f, [xrange, yrange], plot_points) diff --git a/src/sage/plot/density_plot.py b/src/sage/plot/density_plot.py index 155ac8d7a8e..8d6123ff226 100644 --- a/src/sage/plot/density_plot.py +++ b/src/sage/plot/density_plot.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Density plots """ @@ -126,7 +127,7 @@ def _repr_(self): sage: d = D[0]; d DensityPlot defined by a 25 x 25 data grid """ - return "DensityPlot defined by a %s x %s data grid"%(self.xy_array_row, self.xy_array_col) + return "DensityPlot defined by a %s x %s data grid" % (self.xy_array_row, self.xy_array_col) def _render_on_subplot(self, subplot): """ diff --git a/src/sage/plot/disk.py b/src/sage/plot/disk.py index d84b883d6e2..91891b84550 100644 --- a/src/sage/plot/disk.py +++ b/src/sage/plot/disk.py @@ -46,10 +46,12 @@ class Disk(GraphicPrimitive): Note this should normally be used indirectly via ``disk``:: + sage: from math import pi sage: from sage.plot.disk import Disk sage: D = Disk((1,2), 2, (pi/2,pi), {'zorder':3}) sage: D - Disk defined by (1.0,2.0) with r=2.0 spanning (1.5707963267..., 3.1415926535...) radians + Disk defined by (1.0,2.0) with r=2.0 + spanning (1.5707963267..., 3.1415926535...) radians sage: D.options()['zorder'] 3 sage: D.x @@ -68,6 +70,7 @@ def __init__(self, point, r, angle, options): EXAMPLES:: + sage: from math import pi sage: D = disk((2,3), 1, (pi/2, pi), fill=False, color='red', thickness=1, alpha=.5) sage: D[0].x 2.0 @@ -95,6 +98,7 @@ def get_minmax_data(self): EXAMPLES:: + sage: from math import pi sage: D = disk((5,4), 1, (pi/2, pi)) sage: d = D.get_minmax_data() sage: d['xmin'] @@ -118,6 +122,7 @@ def _allowed_options(self): EXAMPLES:: + sage: from math import pi sage: p = disk((3, 3), 1, (0, pi/2)) sage: p[0]._allowed_options()['alpha'] 'How transparent the figure is.' @@ -139,6 +144,7 @@ def _repr_(self): EXAMPLES:: + sage: from math import pi sage: P = disk((3, 3), 1, (0, pi/2)) sage: p = P[0]; p Disk defined by (3.0,3.0) with r=1.0 spanning (0.0, 1.5707963267...) radians @@ -149,6 +155,7 @@ def _render_on_subplot(self, subplot): """ TESTS:: + sage: from math import pi sage: D = disk((2,-1), 2, (0, pi), color='black', thickness=3, fill=False); D Graphics object consisting of 1 graphics primitive @@ -192,6 +199,7 @@ def plot3d(self, z=0, **kwds): EXAMPLES:: + sage: from math import pi sage: disk((0,0), 1, (0, pi/2)).plot3d() Graphics3d Object sage: disk((0,0), 1, (0, pi/2)).plot3d(z=2) @@ -253,12 +261,13 @@ def disk(point, radius, angle, **options): Make some dangerous disks:: + sage: from math import pi sage: bl = disk((0.0,0.0), 1, (pi, 3*pi/2), color='yellow') sage: tr = disk((0.0,0.0), 1, (0, pi/2), color='yellow') sage: tl = disk((0.0,0.0), 1, (pi/2, pi), color='black') sage: br = disk((0.0,0.0), 1, (3*pi/2, 2*pi), color='black') - sage: P = tl+tr+bl+br - sage: P.show(xmin=-2,xmax=2,ymin=-2,ymax=2) + sage: P = tl + tr + bl + br + sage: P.show(xmin=-2, xmax=2, ymin=-2, ymax=2) .. PLOT:: @@ -318,9 +327,11 @@ def disk(point, radius, angle, **options): Extra options will get passed on to ``show()``, as long as they are valid:: - sage: disk((0, 0), 5, (0, pi/2), xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2), rgbcolor=(1, 0, 1)) + sage: disk((0, 0), 5, (0, pi/2), rgbcolor=(1, 0, 1), + ....: xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2)) Graphics object consisting of 1 graphics primitive - sage: disk((0, 0), 5, (0, pi/2), rgbcolor=(1, 0, 1)).show(xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2)) # These are equivalent + sage: disk((0, 0), 5, (0, pi/2), rgbcolor=(1, 0, 1)).show( # These are equivalent + ....: xmin=0, xmax=5, ymin=0, ymax=5, figsize=(2,2)) TESTS: diff --git a/src/sage/plot/ellipse.py b/src/sage/plot/ellipse.py index c35bed574ef..791b719fe68 100644 --- a/src/sage/plot/ellipse.py +++ b/src/sage/plot/ellipse.py @@ -41,6 +41,7 @@ class Ellipse(GraphicPrimitive): Note that this construction should be done using ``ellipse``:: + sage: from math import pi sage: from sage.plot.ellipse import Ellipse sage: Ellipse(0, 0, 2, 1, pi/4, {}) Ellipse centered at (0.0, 0.0) with radii (2.0, 1.0) and angle 0.78539816339... @@ -94,6 +95,7 @@ def get_minmax_data(self): The same example with a rotation of angle `\pi/2`:: + sage: from math import pi sage: p = ellipse((-2, 3), 1, 2, pi/2) sage: d = p.get_minmax_data() sage: d['xmin'] @@ -168,7 +170,7 @@ def _repr_(self): sage: Ellipse(0,0,2,1,0,{})._repr_() 'Ellipse centered at (0.0, 0.0) with radii (2.0, 1.0) and angle 0.0' """ - return "Ellipse centered at (%s, %s) with radii (%s, %s) and angle %s"%(self.x, self.y, self.r1, self.r2, self.angle) + return "Ellipse centered at (%s, %s) with radii (%s, %s) and angle %s" % (self.x, self.y, self.r1, self.r2, self.angle) def _render_on_subplot(self, subplot): """ @@ -178,6 +180,7 @@ def _render_on_subplot(self, subplot): TESTS:: + sage: from math import pi sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3) Graphics object consisting of 1 graphics primitive @@ -280,7 +283,8 @@ def ellipse(center, r1, r2, angle=0, **options): More complicated examples with tilted axes and drawing options:: - sage: ellipse((0,0),3,1,pi/6,fill=True,alpha=0.3,linestyle="dashed") + sage: from math import pi + sage: ellipse((0,0), 3, 1, pi/6, fill=True, alpha=0.3, linestyle="dashed") Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -358,7 +362,7 @@ def ellipse(center, r1, r2, angle=0, **options): if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] - if len(center)==2: + if len(center) == 2: return g - elif len(center)==3: + elif len(center) == 3: raise NotImplementedError("plotting ellipse in 3D is not implemented") diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 64ea1a7e10f..adcccff059b 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -36,6 +36,7 @@ # **************************************************************************** import os +from numbers import Integral from collections.abc import Iterable from math import isnan import sage.misc.verbose @@ -130,23 +131,23 @@ class Graphics(WithEqualityById, SageObject): sage: G = Graphics(); print(G) Graphics object consisting of 0 graphics primitives sage: c = circle((1,1), 1) - sage: G+=c; print(G) + sage: G += c; print(G) Graphics object consisting of 1 graphics primitive Here we make a graphic of embedded isosceles triangles, coloring each one with a different color as we go:: - sage: h=10; c=0.4; p=0.5 + sage: h = 10; c = 0.4; p = 0.5 sage: G = Graphics() - sage: for x in srange(1,h+1): + sage: for x in srange(1, h+1): # needs sage.symbolic ....: l = [[0,x*sqrt(3)],[-x/2,-x*sqrt(3)/2],[x/2,-x*sqrt(3)/2],[0,x*sqrt(3)]] - ....: G+=line(l,color=hue(c + p*(x/h))) - sage: G.show(figsize=[5,5]) + ....: G += line(l, color=hue(c + p*(x/h))) + sage: G.show(figsize=[5,5]) # needs sage.symbolic We can change the scale of the axes in the graphics before displaying.:: - sage: G = plot(exp, 1, 10) # long time - sage: G.show(scale='semilogy') # long time + sage: G = plot(exp, 1, 10) # long time # needs sage.symbolic + sage: G.show(scale='semilogy') # long time # needs sage.symbolic TESTS: @@ -212,32 +213,32 @@ def set_aspect_ratio(self, ratio): EXAMPLES: We create a plot of the upper half of a circle, but it doesn't look round because the aspect ratio is off:: - sage: P = plot(sqrt(1-x^2),(x,-1,1)); P + sage: P = plot(sqrt(1-x^2),(x,-1,1)); P # needs sage.symbolic Graphics object consisting of 1 graphics primitive So we set the aspect ratio and now it is round:: - sage: P.set_aspect_ratio(1) - sage: P.aspect_ratio() + sage: P.set_aspect_ratio(1) # needs sage.symbolic + sage: P.aspect_ratio() # needs sage.symbolic 1.0 - sage: P + sage: P # needs sage.symbolic Graphics object consisting of 1 graphics primitive Note that the aspect ratio is inherited upon addition (which takes the max of aspect ratios of objects whose aspect ratio has been set):: - sage: P + plot(sqrt(4-x^2),(x,-2,2)) + sage: P + plot(sqrt(4-x^2),(x,-2,2)) # needs sage.symbolic Graphics object consisting of 2 graphics primitives In the following example, both plots produce a circle that looks twice as tall as wide:: sage: Q = circle((0,0), 0.5); Q.set_aspect_ratio(2) - sage: (P + Q).aspect_ratio(); P+Q + sage: (P + Q).aspect_ratio(); P + Q # needs sage.symbolic 2.0 Graphics object consisting of 2 graphics primitives - sage: (Q + P).aspect_ratio(); Q+P + sage: (Q + P).aspect_ratio(); Q + P # needs sage.symbolic 2.0 Graphics object consisting of 2 graphics primitives """ @@ -252,20 +253,20 @@ def set_aspect_ratio(self, ratio): def aspect_ratio(self): """ Get the current aspect ratio, which is the ratio of height to - width of a unit square, or 'automatic'. + width of a unit square, or ``'automatic'``. - OUTPUT: a positive float (height/width of a unit square), or 'automatic' + OUTPUT: a positive float (height/width of a unit square), or ``'automatic'`` (expand to fill the figure). EXAMPLES: - The default aspect ratio for a new blank Graphics object is 'automatic':: + The default aspect ratio for a new blank :class:`Graphics` object is ``'automatic'``:: sage: P = Graphics() sage: P.aspect_ratio() 'automatic' - The aspect ratio can be explicitly set different than the object's default:: + The aspect ratio can be explicitly set different from the object's default:: sage: P = circle((1,1), 1) sage: P.aspect_ratio() @@ -285,7 +286,7 @@ def legend(self, show=None): INPUT: - - ``show`` - (default: None) a boolean + - ``show`` -- (default: ``None``) a boolean If called with no input, return the current legend setting. @@ -293,23 +294,24 @@ def legend(self, show=None): By default no legend is displayed:: - sage: P = plot(sin) - sage: P.legend() + sage: P = plot(sin) # needs sage.symbolic + sage: P.legend() # needs sage.symbolic False But if we put a label then the legend is shown:: - sage: P = plot(sin, legend_label='sin') - sage: P.legend() + sage: P = plot(sin, legend_label='sin') # needs sage.symbolic + sage: P.legend() # needs sage.symbolic True We can turn it on or off:: + sage: # needs sage.symbolic sage: P.legend(False) sage: P.legend() False sage: P.legend(True) - sage: P # show with the legend + sage: P # show with the legend Graphics object consisting of 1 graphics primitive """ if show is None: @@ -405,30 +407,30 @@ def set_legend_options(self, **kwds): By default, no options are set:: - sage: p = plot(tan, legend_label='tan') - sage: p.set_legend_options() + sage: p = plot(tan, legend_label='tan') # needs sage.symbolic + sage: p.set_legend_options() # needs sage.symbolic {} We build a legend without a shadow:: - sage: p.set_legend_options(shadow=False) - sage: p.set_legend_options()['shadow'] + sage: p.set_legend_options(shadow=False) # needs sage.symbolic + sage: p.set_legend_options()['shadow'] # needs sage.symbolic False To set the legend position to the center of the plot, all these methods are roughly equivalent:: - sage: p.set_legend_options(loc='center'); p + sage: p.set_legend_options(loc='center'); p # needs sage.symbolic Graphics object consisting of 1 graphics primitive :: - sage: p.set_legend_options(loc=10); p + sage: p.set_legend_options(loc=10); p # needs sage.symbolic Graphics object consisting of 1 graphics primitive :: - sage: p.set_legend_options(loc=(0.5,0.5)); p # aligns the bottom of the box to the center + sage: p.set_legend_options(loc=(0.5,0.5)); p # aligns the bottom of the box to the center # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ if len(kwds) == 0: @@ -623,8 +625,9 @@ def axes_labels_size(self, s=None): EXAMPLES:: + sage: # needs sage.symbolic sage: p = plot(sin(x^2), (x, -3, 3), axes_labels=['$x$','$y$']) - sage: p.axes_labels_size() # default value + sage: p.axes_labels_size() # default value 1.6 sage: p.axes_labels_size(2.5) sage: p.axes_labels_size() @@ -632,7 +635,7 @@ def axes_labels_size(self, s=None): Now the axes labels are large w.r.t. the tick marks:: - sage: p + sage: p # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ @@ -759,20 +762,20 @@ def axes_labels(self, l=None): :: - sage: p = plot(sin(x), (x, 0, 10)) - sage: p.axes_labels(['$x$','$y$']) - sage: p.axes_labels() + sage: p = plot(sin(x), (x, 0, 10)) # needs sage.symbolic + sage: p.axes_labels(['$x$','$y$']) # needs sage.symbolic + sage: p.axes_labels() # needs sage.symbolic ('$x$', '$y$') Now when you plot p, you see x and y axes labels:: - sage: p + sage: p # needs sage.symbolic Graphics object consisting of 1 graphics primitive Notice that some may prefer axes labels which are not typeset:: - sage: plot(sin(x), (x, 0, 10), axes_labels=['x','y']) + sage: plot(sin(x), (x, 0, 10), axes_labels=['x','y']) # needs sage.symbolic Graphics object consisting of 1 graphics primitive TESTS: @@ -805,7 +808,7 @@ def axes_label_color(self, c=None): Set the color of the axes labels. The axes labels are placed at the edge of the x and y axes, and are - not on by default (use the ``axes_labels`` command to + not on by default (use the :meth:`axes_labels` command to set them; see the example below). This function just changes their color. @@ -823,25 +826,25 @@ def axes_label_color(self, c=None): :: - sage: p = plot(sin, (-1,1)) - sage: p.axes_label_color() + sage: p = plot(sin, (-1,1)) # needs sage.symbolic + sage: p.axes_label_color() # needs sage.symbolic (0, 0, 0) We change the labels to be red, and confirm this:: - sage: p.axes_label_color((1,0,0)) - sage: p.axes_label_color() + sage: p.axes_label_color((1,0,0)) # needs sage.symbolic + sage: p.axes_label_color() # needs sage.symbolic (1.0, 0.0, 0.0) We set labels, since otherwise we won't see anything. :: - sage: p.axes_labels(['$x$ axis', '$y$ axis']) + sage: p.axes_labels(['$x$ axis', '$y$ axis']) # needs sage.symbolic In the plot below, notice that the labels are red:: - sage: p + sage: p # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ if c is None: @@ -860,7 +863,7 @@ def axes_width(self, w=None): INPUT: - - ``w`` - a float + - ``w`` -- a float If called with no input, return the current @@ -871,6 +874,7 @@ def axes_width(self, w=None): :: + sage: # needs sage.symbolic sage: p = plot(cos, (-3,3)) sage: p.axes_width() 0.8 @@ -882,7 +886,7 @@ def axes_width(self, w=None): :: - sage: p + sage: p # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ if w is None: @@ -908,6 +912,7 @@ def tick_label_color(self, c=None): EXAMPLES:: + sage: # needs sage.symbolic sage: p = plot(cos, (-3,3)) sage: p.tick_label_color() (0, 0, 0) @@ -938,27 +943,27 @@ def _repr_(self): We create a plot and call :meth:`show` on it, which causes it to be displayed as a plot:: - sage: P = plot(cos, (-1,1)) - sage: P.show() + sage: P = plot(cos, (-1,1)) # needs sage.symbolic + sage: P.show() # needs sage.symbolic Just doing this also displays the plot:: - sage: P + sage: P # needs sage.symbolic Graphics object consisting of 1 graphics primitive Using the Python `repr` or `str` commands do not display the plot:: - sage: repr(P) + sage: repr(P) # needs sage.symbolic 'Graphics object consisting of 1 graphics primitive' - sage: str(P) + sage: str(P) # needs sage.symbolic 'Graphics object consisting of 1 graphics primitive' - sage: print(P) + sage: print(P) # needs sage.symbolic Graphics object consisting of 1 graphics primitive TESTS:: - sage: P._repr_() + sage: P._repr_() # needs sage.symbolic 'Graphics object consisting of 1 graphics primitive' """ return str(self) @@ -1071,8 +1076,8 @@ def __delitem__(self, i): def __setitem__(self, i, x): """ - You can replace a GraphicPrimitive (point, line, circle, etc...) in - a Graphics object G with any other GraphicPrimitive + You can replace a :class:`GraphicPrimitive` (point, line, circle, etc...) in + a :class:`Graphics` object G with any other :class:`GraphicPrimitive` EXAMPLES:: @@ -1100,8 +1105,8 @@ def __radd__(self, other): Compute and return other + this graphics object. This only works when other is a Python int equal to 0. In all other - cases a TypeError is raised. The main reason for this function is - to make summing a list of graphics objects easier. + cases a :class:`TypeError` is raised. The main reason for this + function is to make summing a list of graphics objects easier. EXAMPLES:: @@ -1125,7 +1130,7 @@ def __add__(self, other): """ If you have any Graphics object G1, you can always add any other amount of Graphics objects G2,G3,... to form a new Graphics object: - G4 = G1 + G2 + G3. + ``G4 = G1 + G2 + G3``. The xmin, xmax, ymin, and ymax properties of the graphics objects are expanded to include all objects in both scenes. If the aspect @@ -1140,15 +1145,16 @@ def __add__(self, other): EXAMPLES:: - sage: g1 = plot(abs(sqrt(x^3-1)), (x,1,5), frame=True) - sage: g2 = plot(-abs(sqrt(x^3-1)), (x,1,5), color='red') - sage: g1 + g2 # displays the plot + sage: g1 = plot(abs(sqrt(x^3-1)), (x,1,5), frame=True) # needs sage.symbolic + sage: g2 = plot(-abs(sqrt(x^3-1)), (x,1,5), color='red') # needs sage.symbolic + sage: g1 + g2 # displays the plot # needs sage.symbolic Graphics object consisting of 2 graphics primitives TESTS: Extra keywords to show are propagated:: + sage: # needs sage.symbolic sage: (g1 + g2)._extra_kwds=={'aspect_ratio': 'automatic', 'frame': True} True sage: g1.set_aspect_ratio(2) @@ -1160,10 +1166,11 @@ def __add__(self, other): As are legend options, :trac:`12936`:: + sage: # needs sage.symbolic sage: p1 = plot(x, x, 0, 1) sage: p2 = p1 - sage: p1.set_legend_options(back_color = 'black') - sage: p2.set_legend_options(shadow = False) + sage: p1.set_legend_options(back_color='black') + sage: p2.set_legend_options(shadow=False) sage: p3 = p1 + p2 sage: p3._legend_opts {'back_color': 'black', 'shadow': False} @@ -1171,19 +1178,21 @@ def __add__(self, other): If the same legend option is specified more than once, the latter takes precedence:: + sage: # needs sage.symbolic sage: p1 = plot(x, x, 0, 1) sage: p2 = p1 - sage: p1.set_legend_options(shadow = True) - sage: p2.set_legend_options(shadow = False) + sage: p1.set_legend_options(shadow=True) + sage: p2.set_legend_options(shadow=False) sage: p3 = p1 + p2 sage: p3._legend_opts {'shadow': False} Flipped axes take precedence over non-flipped axes:: - sage: p1 = plot(x, x, 0, 1, flip_x=True, flip_y=True) - sage: p2 = plot(x^2, x, 0, 1) - sage: [p._extra_kwds[k] for p in [p1 + p2, p2 + p1] for k in ['flip_x', 'flip_y']] + sage: p1 = plot(x, x, 0, 1, flip_x=True, flip_y=True) # needs sage.symbolic + sage: p2 = plot(x^2, x, 0, 1) # needs sage.symbolic + sage: [p._extra_kwds[k] for p in [p1 + p2, p2 + p1] # needs sage.symbolic + ....: for k in ['flip_x', 'flip_y']] [True, True, True, True] """ if isinstance(other, int) and other == 0: @@ -1224,10 +1233,15 @@ def add_primitive(self, primitive): We give a very explicit example:: sage: G = Graphics() + sage: from math import e sage: from sage.plot.line import Line sage: from sage.plot.arrow import Arrow - sage: L = Line([3,4,2,7,-2],[1,2,e,4,5.],{'alpha':1,'thickness':2,'rgbcolor':(0,1,1),'legend_label':''}) - sage: A = Arrow(2,-5,.1,.2,{'width':3,'head':0,'rgbcolor':(1,0,0),'linestyle':'dashed','zorder':8,'legend_label':''}) + sage: L = Line([3,4,2,7,-2], [1,2,e,4,5.], + ....: {'alpha': 1, 'thickness': 2, 'rgbcolor': (0,1,1), + ....: 'legend_label': ''}) + sage: A = Arrow(2, -5, .1, .2, + ....: {'width': 3, 'head': 0, 'rgbcolor': (1,0,0), + ....: 'linestyle': 'dashed', 'zorder': 8, 'legend_label': ''}) sage: G.add_primitive(L) sage: G.add_primitive(A) sage: G @@ -1262,13 +1276,14 @@ def plot(self): def plot3d(self, z=0, **kwds): """ - Returns an embedding of this 2D plot into the xy-plane of 3D space, - as a 3D plot object. An optional parameter z can be given to + Return an embedding of this 2D plot into the xy-plane of 3D space, + as a 3D plot object. An optional parameter ``z`` can be given to specify the z-coordinate. EXAMPLES:: - sage: sum([plot(z*sin(x), 0, 10).plot3d(z) for z in range(6)]) # long time + sage: sum(plot(z*sin(x), 0, 10).plot3d(z) # long time # needs sage.symbolic + ....: for z in range(6)) Graphics3d Object """ from sage.plot.plot3d.base import Graphics3dGroup @@ -1286,7 +1301,7 @@ def _extract_kwds_for_show(cls, kwds, ignore=[]): sage: kwds = {'f': lambda x: x, 'xmin': 0, 'figsize': [1,1], 'plot_points': (40, 40)} sage: G_kwds = Graphics._extract_kwds_for_show(kwds, ignore='xmin') - sage: kwds # Note how this action modifies the passed dictionary + sage: kwds # Note how this action modifies the passed dictionary {'f': <function <lambda> at 0x...>, 'plot_points': (40, 40), 'xmin': 0} @@ -1296,7 +1311,7 @@ def _extract_kwds_for_show(cls, kwds, ignore=[]): This method is intended to be used with _set_extra_kwds(). Here is an idiom to ensure the correct keywords will get passed on to show():: - sage: options = {} # Usually this will come from an argument + sage: options = {} # Usually this will come from an argument sage: g = Graphics() sage: g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) """ @@ -1321,7 +1336,7 @@ def _set_extra_kwds(self, kwds): sage: g._set_extra_kwds({'figsize': [10,10]}) sage: g._extra_kwds {'figsize': [10, 10]} - sage: g.show() # Now the (blank) plot will be extra large + sage: g.show() # Now the (blank) plot will be extra large """ self._extra_kwds = kwds @@ -1714,117 +1729,117 @@ def show(self, **kwds): height each having a maximum value of 327 inches at default dpi:: sage: p = ellipse((0,0),4,1) - sage: p.show(figsize=[327,10],dpi=100) - sage: p.show(figsize=[328,10],dpi=80) + sage: p.show(figsize=[327,10], dpi=100) + sage: p.show(figsize=[328,10], dpi=80) You can turn off the drawing of the axes:: - sage: show(plot(sin,-4,4), axes=False) + sage: show(plot(sin,-4,4), axes=False) # needs sage.symbolic You can also label the axes. Putting something in dollar signs formats it as a mathematical expression:: - sage: show(plot(sin,-4,4), axes_labels=('$x$','$y$')) + sage: show(plot(sin,-4,4), axes_labels=('$x$','$y$')) # needs sage.symbolic You can add a title to a plot:: - sage: show(plot(sin,-4,4), title=r'A plot of $\sin(x)$') + sage: show(plot(sin,-4,4), title=r'A plot of $\sin(x)$') # needs sage.symbolic You can also provide the position for the title to the plot. In the plot below the title is placed on the bottom left of the figure.:: - sage: plot(sin, -4, 4, title='Plot sin(x)', title_pos=(0.05,-0.05)) + sage: plot(sin, -4, 4, title='Plot sin(x)', title_pos=(0.05,-0.05)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive If you want all the text to be rendered by using an external LaTeX installation then set the ``typeset`` to ``"latex"``. This requires that LaTeX, dvipng and Ghostscript be installed:: - sage: plot(x, typeset='latex') # optional - latex + sage: plot(x, typeset='latex') # optional - latex, needs sage.symbolic Graphics object consisting of 1 graphics primitive If you want all the text in your plot to use Type 1 fonts, then set the ``typeset`` option to ``"type1"``. This requires that LaTeX, dvipng and Ghostscript be installed:: - sage: plot(x, typeset='type1') # optional - latex + sage: plot(x, typeset='type1') # optional - latex, needs sage.symbolic Graphics object consisting of 1 graphics primitive You can turn on the drawing of a frame around the plots:: - sage: show(plot(sin,-4,4), frame=True) + sage: show(plot(sin,-4,4), frame=True) # needs sage.symbolic You can make the background transparent:: - sage: plot(sin(x), (x, -4, 4), transparent=True) + sage: plot(sin(x), (x, -4, 4), transparent=True) # needs sage.symbolic Graphics object consisting of 1 graphics primitive Prior to :trac:`19485`, legends by default had a shadowless gray background. This behavior can be recovered by passing in certain ``legend_options``:: - sage: p = plot(sin(x), legend_label=r'$\sin(x)$') - sage: p.show(legend_options={'back_color': (0.9,0.9,0.9), + sage: p = plot(sin(x), legend_label=r'$\sin(x)$') # needs sage.symbolic + sage: p.show(legend_options={'back_color': (0.9,0.9,0.9), # needs sage.symbolic ....: 'shadow': False}) We can change the scale of the axes in the graphics before displaying:: - sage: G = plot(exp, 1, 10) - sage: G.show(scale='semilogy') + sage: G = plot(exp, 1, 10) # needs sage.symbolic + sage: G.show(scale='semilogy') # needs sage.symbolic We can change the base of the logarithm too. The following changes the vertical axis to be on log scale, and with base 2. Note that the ``base`` argument will ignore any changes to the axis which is in linear scale.:: - sage: G.show(scale='semilogy', base=2) # long time # y axis as powers of 2 + sage: G.show(scale='semilogy', base=2) # y axis as powers of 2 # long time, needs sage.symbolic :: - sage: G.show(scale='semilogy', base=(3,2)) # base ignored for x-axis + sage: G.show(scale='semilogy', base=(3,2)) # base ignored for x-axis # needs sage.symbolic The scale can be also given as a 2-tuple or a 3-tuple.:: - sage: G.show(scale=('loglog', 2.1)) # long time # both x and y axes in base 2.1 + sage: G.show(scale=('loglog', 2.1)) # both x and y axes in base 2.1 # long time, needs sage.symbolic :: - sage: G.show(scale=('loglog', 2, 3)) # long time # x in base 2, y in base 3 + sage: G.show(scale=('loglog', 2, 3)) # x in base 2, y in base 3 # long time, needs sage.symbolic The base need not be an integer, though it does have to be made a float.:: - sage: G.show(scale='semilogx', base=float(e)) # base is e + sage: G.show(scale='semilogx', base=float(e)) # base is e # needs sage.symbolic Logarithmic scale can be used for various kinds of plots. Here are some examples.:: - sage: G = list_plot([10**i for i in range(10)]) # long time - sage: G.show(scale='semilogy') # long time + sage: G = list_plot([10**i for i in range(10)]) # long time, needs sage.symbolic + sage: G.show(scale='semilogy') # long time :: - sage: G = parametric_plot((x, x**2), (x, 1, 10)) - sage: G.show(scale='loglog') + sage: G = parametric_plot((x, x**2), (x, 1, 10)) # needs sage.symbolic + sage: G.show(scale='loglog') # needs sage.symbolic :: - sage: disk((5,5), 4, (0, 3*pi/2)).show(scale='loglog',base=2) + sage: disk((5,5), 4, (0, 3*pi/2)).show(scale='loglog',base=2) # needs sage.symbolic :: - sage: x, y = var('x, y') - sage: G = plot_vector_field((2^x,y^2),(x,1,10),(y,1,100)) - sage: G.show(scale='semilogx',base=2) + sage: x, y = var('x, y') # needs sage.symbolic + sage: G = plot_vector_field((2^x,y^2), (x,1,10), (y,1,100)) # needs sage.symbolic + sage: G.show(scale='semilogx',base=2) # needs sage.symbolic Flip the horizontal or vertical axis. :: - sage: G = plot(x^3, -2, 3) - sage: G.show(flip_x=True) - sage: G.show(flip_y=True) + sage: G = plot(x^3, -2, 3) # needs sage.symbolic + sage: G.show(flip_x=True) # needs sage.symbolic + sage: G.show(flip_y=True) # needs sage.symbolic Add grid lines at the major ticks of the axes. @@ -1839,6 +1854,7 @@ def show(self, **kwds): :: + sage: # needs sage.symbolic sage: u,v = var('u v') sage: f = exp(-(u^2+v^2)) sage: p = plot_vector_field(f.gradient(), (u,-2,2), (v,-2,2)) @@ -1848,18 +1864,18 @@ def show(self, **kwds): :: - sage: p = plot(sin,-10,20) - sage: p.show(gridlines=[None, "automatic"]) - sage: p.show(gridlines=["minor", False]) + sage: p = plot(sin, -10, 20) # needs sage.symbolic + sage: p.show(gridlines=[None, "automatic"]) # needs sage.symbolic + sage: p.show(gridlines=["minor", False]) # needs sage.symbolic Add grid lines at specific positions (using lists/tuples). :: - sage: x, y = var('x, y') - sage: p = implicit_plot((y^2-x^2)*(x-1)*(2*x-3)-4*(x^2+y^2-2*x)^2, \ - ....: (x,-2,2), (y,-2,2), plot_points=1000) - sage: p.show(gridlines=[[1,0],[-1,0,1]]) + sage: x, y = var('x, y') # needs sage.symbolic + sage: p = implicit_plot((y^2-x^2)*(x-1)*(2*x-3) - 4*(x^2+y^2-2*x)^2, # needs sage.symbolic + ....: (x,-2,2), (y,-2,2), plot_points=1000) + sage: p.show(gridlines=[[1,0],[-1,0,1]]) # needs sage.symbolic Add grid lines at specific positions (using iterators). @@ -1867,16 +1883,18 @@ def show(self, **kwds): sage: def maple_leaf(t): ....: return (100/(100+(t-pi/2)^8))*(2-sin(7*t)-cos(30*t)/2) - sage: p = polar_plot(maple_leaf, -pi/4, 3*pi/2, color="red",plot_points=1000) # long time - sage: p.show(gridlines=([-3,-2.75,..,3], range(-1,5,2))) # long time + sage: p = polar_plot(maple_leaf, -pi/4, 3*pi/2, # long time, needs sage.symbolic + ....: color="red",plot_points=1000) + sage: p.show(gridlines=([-3,-2.75,..,3], range(-1,5,2))) # long time, needs sage.symbolic Add grid lines at specific positions (using functions). :: + sage: # needs sage.symbolic sage: y = x^5 + 4*x^4 - 10*x^3 - 40*x^2 + 9*x + 36 sage: p = plot(y, -4.1, 1.1) - sage: xlines = lambda a,b: [z for z,m in y.roots()] + sage: xlines = lambda a, b: [z for z, m in y.roots()] sage: p.show(gridlines=[xlines, [0]], frame=True, axes=False) Change the style of all the grid lines. @@ -1884,27 +1902,27 @@ def show(self, **kwds): :: sage: b = bar_chart([-3,5,-6,11], color='red') - sage: b.show(gridlines=([-1,-0.5,..,4],True), - ....: gridlinesstyle=dict(color="blue", linestyle=":")) + sage: b.show(gridlines=([-1,-0.5,..,4], True), + ....: gridlinesstyle=dict(color="blue", linestyle=":")) Change the style of the horizontal or vertical grid lines separately. :: - sage: p = polar_plot(2 + 2*cos(x), 0, 2*pi, color=hue(0.3)) - sage: p.show(gridlines=True, - ....: hgridlinesstyle=dict(color="orange", linewidth=1.0), - ....: vgridlinesstyle=dict(color="blue", linestyle=":")) + sage: p = polar_plot(2 + 2*cos(x), 0, 2*pi, color=hue(0.3)) # needs sage.symbolic + sage: p.show(gridlines=True, # needs sage.symbolic + ....: hgridlinesstyle=dict(color="orange", linewidth=1.0), + ....: vgridlinesstyle=dict(color="blue", linestyle=":")) Change the style of each grid line individually. :: - sage: x, y = var('x, y') - sage: p = implicit_plot((y^2-x^2)*(x-1)*(2*x-3)-4*(x^2+y^2-2*x)^2, - ....: (x,-2,2), (y,-2,2), plot_points=1000) - sage: p.show(gridlines=( + sage: x, y = var('x, y') # needs sage.symbolic + sage: p = implicit_plot((y^2-x^2)*(x-1)*(2*x-3) - 4*(x^2+y^2-2*x)^2, # needs sage.symbolic + ....: (x,-2,2), (y,-2,2), plot_points=1000) + sage: p.show(gridlines=( # needs sage.symbolic ....: [ ....: (1,{"color":"red","linestyle":":"}), ....: (0,{"color":"blue","linestyle":"--"}) @@ -1921,9 +1939,10 @@ def show(self, **kwds): :: - sage: f = sin(x^2 + y^2)*cos(x)*sin(y) - sage: c = contour_plot(f, (x, -4, 4), (y, -4, 4), plot_points=100) - sage: c.show(gridlines=True, gridlinesstyle={'linestyle':':','linewidth':1, 'color':'red'}) + sage: f = sin(x^2 + y^2)*cos(x)*sin(y) # needs sage.symbolic + sage: c = contour_plot(f, (x, -4, 4), (y, -4, 4), plot_points=100) # needs sage.symbolic + sage: c.show(gridlines=True, # needs sage.symbolic + ....: gridlinesstyle={'linestyle': ':', 'linewidth': 1, 'color': 'red'}) Grid lines can be added to matrix plots. @@ -1942,9 +1961,11 @@ def show(self, **kwds): :: - sage: plot(sin(x), (x, -pi, pi),thickness=2)+point((pi, -1), pointsize=15) + sage: (plot(sin(x), (x, -pi, pi), thickness=2) # needs sage.symbolic + ....: + point((pi, -1), pointsize=15)) Graphics object consisting of 2 graphics primitives - sage: plot(sin(x), (x, -pi, pi),thickness=2,axes_pad=0)+point((pi, -1), pointsize=15) + sage: (plot(sin(x), (x, -pi, pi), thickness=2, axes_pad=0) # needs sage.symbolic + ....: + point((pi, -1), pointsize=15)) Graphics object consisting of 2 graphics primitives The behavior of the ``axes_pad`` parameter is different if the axis @@ -1956,10 +1977,10 @@ def show(self, **kwds): :: - sage: plot_loglog(x, (1.1*10**-2, 9990)) + sage: plot_loglog(x, (1.1*10**-2, 9990)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive - sage: plot_loglog(x, (1.1*10**-2, 9990), axes_pad=0) + sage: plot_loglog(x, (1.1*10**-2, 9990), axes_pad=0) # needs sage.symbolic Graphics object consisting of 1 graphics primitive Via matplotlib, Sage allows setting of custom ticks. See above @@ -1967,38 +1988,39 @@ def show(self, **kwds): Here the labels are not so useful:: - sage: plot(sin(pi*x), (x, -8, 8)) + sage: plot(sin(pi*x), (x, -8, 8)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive Now put ticks at multiples of 2:: - sage: plot(sin(pi*x), (x, -8, 8), ticks=2) + sage: plot(sin(pi*x), (x, -8, 8), ticks=2) # needs sage.symbolic Graphics object consisting of 1 graphics primitive Or just choose where you want the ticks:: - sage: plot(sin(pi*x), (x, -8, 8), ticks=[[-7,-3,0,3,7],[-1/2,0,1/2]]) + sage: plot(sin(pi*x), (x, -8, 8), ticks=[[-7,-3,0,3,7], [-1/2,0,1/2]]) # needs sage.symbolic Graphics object consisting of 1 graphics primitive Or no ticks at all:: - sage: plot(sin(pi*x), (x, -8, 8), ticks=[[],[]]) + sage: plot(sin(pi*x), (x, -8, 8), ticks=[[], []]) # needs sage.symbolic Graphics object consisting of 1 graphics primitive This can be very helpful in showing certain features of plots. :: - sage: plot(1.5/(1+e^(-x)), (x, -10, 10)) # doesn't quite show value of inflection point + sage: plot(1.5/(1+e^(-x)), (x, -10, 10)) # doesn't quite show value of inflection point # needs sage.symbolic Graphics object consisting of 1 graphics primitive :: - sage: plot(1.5/(1+e^(-x)), (x, -10, 10), ticks=[None, 1.5/4]) # It's right at f(x)=0.75! + sage: plot(1.5/(1+e^(-x)), (x, -10, 10), # It's right at f(x)=0.75! # needs sage.symbolic + ....: ticks=[None, 1.5/4]) Graphics object consisting of 1 graphics primitive But be careful to leave enough room for at least two major ticks, so that the user can tell what the scale is:: - sage: plot(x^2,(x,1,8),ticks=6).show() + sage: plot(x^2, (x,1,8), ticks=6).show() # needs sage.symbolic Traceback (most recent call last): ... ValueError: Expand the range of the independent variable to @@ -2007,7 +2029,9 @@ def show(self, **kwds): We can also do custom formatting if you need it. See above for full details:: - sage: plot(2*x+1,(x,0,5),ticks=[[0,1,e,pi,sqrt(20)],2],tick_formatter="latex") # not tested (broken with matplotlib 3.6) + sage: plot(2*x + 1, (x,0,5), # not tested (broken with matplotlib 3.6), needs sage.symbolic + ....: ticks=[[0,1,e,pi,sqrt(20)], 2], + ....: tick_formatter="latex") Graphics object consisting of 1 graphics primitive This is particularly useful when setting custom ticks in multiples @@ -2015,41 +2039,47 @@ def show(self, **kwds): :: - sage: plot(sin(x),(x,0,2*pi),ticks=pi/3,tick_formatter=pi) + sage: plot(sin(x), (x,0,2*pi), ticks=pi/3, tick_formatter=pi) # needs sage.symbolic Graphics object consisting of 1 graphics primitive But keep in mind that you will get exactly the formatting you asked for if you specify both formatters. The first syntax is recommended for best style in that case. :: - sage: plot(arcsin(x),(x,-1,1),ticks=[None,pi/6],tick_formatter=["latex",pi]) # Nice-looking! + sage: plot(arcsin(x), (x,-1,1), ticks=[None, pi/6], # Nice-looking! # needs sage.symbolic + ....: tick_formatter=["latex", pi]) Graphics object consisting of 1 graphics primitive :: - sage: plot(arcsin(x),(x,-1,1),ticks=[None,pi/6],tick_formatter=[None,pi]) # Not so nice-looking + sage: plot(arcsin(x), (x,-1,1), ticks=[None, pi/6], # Not so nice-looking # needs sage.symbolic + ....: tick_formatter=[None, pi]) Graphics object consisting of 1 graphics primitive Custom tick labels can be provided by providing the keyword ``tick_formatter`` with the list of labels, and simultaneously providing the keyword ``ticks`` with the positions of the labels. :: - sage: plot(x, (x,0,3), ticks=[[1,2.5],[0.5,1,2]], tick_formatter=[["$x_1$","$x_2$"],["$y_1$","$y_2$","$y_3$"]]) + sage: plot(x, (x,0,3), ticks=[[1,2.5], [0.5,1,2]], # needs sage.symbolic + ....: tick_formatter=[["$x_1$","$x_2$"], ["$y_1$","$y_2$","$y_3$"]]) Graphics object consisting of 1 graphics primitive The following sets the custom tick labels only along the horizontal axis. :: - sage: plot(x**2, (x,0,2), ticks=[[1,2], None], tick_formatter=[["$x_1$","$x_2$"], None]) + sage: plot(x**2, (x,0,2), ticks=[[1,2], None], # needs sage.symbolic + ....: tick_formatter=[["$x_1$","$x_2$"], None]) Graphics object consisting of 1 graphics primitive If the number of tick labels do not match the number of positions of tick labels, then it results in an error.:: - sage: plot(x**2, (x,0,2), ticks=[[2], None], tick_formatter=[["$x_1$","$x_2$"], None]).show() + sage: plot(x**2, (x,0,2), ticks=[[2], None], # needs sage.symbolic + ....: tick_formatter=[["$x_1$","$x_2$"], None]).show() Traceback (most recent call last): ... - ValueError: If the first component of the list `tick_formatter` is a list then the first component of `ticks` must also be a list of equal length. + ValueError: If the first component of the list `tick_formatter` is a list + then the first component of `ticks` must also be a list of equal length. When using logarithmic scale along the axis, make sure to have enough room for two ticks so that the user can tell what the scale @@ -2083,8 +2113,9 @@ def show(self, **kwds): When using ``title_pos``, it must be ensured that a list or a tuple of length two is used. Otherwise, a warning is raised:: - sage: plot(x, -4, 4, title='Plot x', title_pos=0.05) - doctest:...: ...RichReprWarning: Exception in _rich_repr_ while displaying object: 'title_pos' must be a list or tuple of two real numbers. + sage: plot(x, -4, 4, title='Plot x', title_pos=0.05) # needs sage.symbolic + doctest:...: ...RichReprWarning: Exception in _rich_repr_ while displaying + object: 'title_pos' must be a list or tuple of two real numbers. Graphics object consisting of 1 graphics primitive TESTS: @@ -2111,6 +2142,7 @@ def show(self, **kwds): The following tests ensure we give a good error message for negative figsizes:: + sage: # needs sage.symbolic sage: P = plot(x^2,(x,0,1)) sage: P.show(figsize=[-1,1]) Traceback (most recent call last): @@ -2127,7 +2159,8 @@ def show(self, **kwds): sage: P.show(figsize=[2,3,4]) Traceback (most recent call last): ... - ValueError: figsize should be a positive number or a list of two positive numbers, not [2, 3, 4] + ValueError: figsize should be a positive number or + a list of two positive numbers, not [2, 3, 4] sage: P.show(figsize=[sqrt(2),sqrt(3)]) """ from sage.repl.rich_output import get_display_manager @@ -2240,7 +2273,8 @@ def get_minmax_data(self): 'ymin': -1.0} sage: l = line([(0,0), (1,1)], aspect_ratio=1e19) sage: l.get_minmax_data() - {'xmax': 5000.50000000000, 'xmin': -4999.50000000000, 'ymax': 1.0, 'ymin': 0.0} + {'xmax': 5000.50000000000, 'xmin': -4999.50000000000, + 'ymax': 1.0, 'ymin': 0.0} """ objects = self._objects if objects: @@ -2332,16 +2366,18 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), the ticks formatting. This function is only for internal use. INPUT: + - ``subplot`` -- the subplot instance. EXAMPLES:: + sage: # needs sage.symbolic sage: from matplotlib.figure import Figure sage: p = plot(x); d = p.get_minmax_data() sage: subplot = Figure().add_subplot(111) sage: p._objects[0]._render_on_subplot(subplot) sage: p._matplotlib_tick_formatter(subplot, **d) - (<AxesSubplot:...>, + (<Axes...>, <matplotlib.ticker.MaxNLocator object at ...>, <matplotlib.ticker.MaxNLocator object at ...>, <matplotlib.ticker.ScalarFormatter object at ...>, @@ -2649,14 +2685,15 @@ def matplotlib(self, filename=None, :: - sage: p = plot(sin(x), (x, -2*pi, 2*pi)) - sage: figure = p.matplotlib() - sage: axes = figure.axes[0] + sage: p = plot(sin(x), (x, -2*pi, 2*pi)) # needs sage.symbolic + sage: figure = p.matplotlib() # needs sage.symbolic + sage: axes = figure.axes[0] # needs sage.symbolic TESTS: We verify that :trac:`10291` is fixed:: + sage: # needs sage.symbolic sage: p = plot(sin(x), (x, -2*pi, 2*pi)) sage: figure = p.matplotlib() sage: axes_range = p.get_axes_range() @@ -2669,20 +2706,22 @@ def matplotlib(self, filename=None, First, we test with no options, and next with an incomplete set of options.:: + sage: # needs sage.symbolic sage: p = plot(x, legend_label='aha') sage: p.legend(True) sage: pm = p.matplotlib() - sage: pm = p.matplotlib(legend_options={'font_size':'small'}) + sage: pm = p.matplotlib(legend_options={'font_size': 'small'}) The title should not overlap with the axes labels nor the frame in the following plot (see :trac:`10512`):: - sage: plot(sin(x^2), (x, -3, 3), title='Plot of sin(x^2)', axes_labels=['x','y'],frame=True) + sage: plot(sin(x^2), (x, -3, 3), title='Plot of sin(x^2)', # needs sage.symbolic + ....: axes_labels=['x','y'], frame=True) Graphics object consisting of 1 graphics primitive ``typeset`` must not be set to an arbitrary string:: - sage: plot(x, typeset='garbage') + sage: plot(x, typeset='garbage') # needs sage.symbolic doctest:...: ...RichReprWarning: Exception in _rich_repr_ while displaying object: typeset must be set to one of 'default', 'latex', or 'type1'; got 'garbage'. @@ -2692,12 +2731,14 @@ def matplotlib(self, filename=None, By default, Sage 5.10 changes float objects to the `RealLiteral` type. The patch changes them to float before creating `matplotlib` objects.:: - sage: f = lambda x, y : (abs(cos((x + I * y) ** 4)) - 1) # long time - sage: g = implicit_plot(f,(-4, 4),(-3, 3),linewidth=0.6) # long time - sage: gm = g.matplotlib() # long time # without the patch, this goes BOOM -- er, TypeError + sage: # long time, needs sage.symbolic + sage: f = lambda x, y: abs(cos((x + I * y) ** 4)) - 1 + sage: g = implicit_plot(f, (-4, 4), (-3, 3), linewidth=0.6) + sage: gm = g.matplotlib() If the axes are flipped, the limits of the axes get swapped:: + sage: # needs sage.symbolic sage: p = plot(2*x, 1, 2) sage: sub, = p.matplotlib(flip_y=True, flip_x=True).axes sage: xmin, xmax = sub.get_xlim() @@ -2834,6 +2875,11 @@ def matplotlib(self, filename=None, weight=lopts.pop('font_weight', 'medium'), variant=lopts.pop('font_variant', 'normal')) color = lopts.pop('back_color', 'white') + if 'loc' in lopts: + loc = lopts['loc'] + if isinstance(loc, Integral): + # matplotlib 3.8 doesn't support sage integers + lopts['loc'] = int(loc) leg = subplot.legend(prop=prop, **lopts) if leg is None: from warnings import warn @@ -3251,16 +3297,16 @@ def save(self, filename, **kwds): ``fig_tight=False``:: sage: c.save(f.name, figsize=[8,4], fig_tight=False, - ....: xmin=-1, xmax=3, ymin=-1, ymax=3) + ....: xmin=-1, xmax=3, ymin=-1, ymax=3) You can also pass extra options to the plot command instead of this method, e.g. :: - sage: plot(x^2 - 5, (x, 0, 5), ymin=0).save(tmp_filename(ext='.png')) + sage: plot(x^2 - 5, (x, 0, 5), ymin=0).save(tmp_filename(ext='.png')) # needs sage.symbolic will save the same plot as the one shown by this command:: - sage: plot(x^2 - 5, (x, 0, 5), ymin=0) + sage: plot(x^2 - 5, (x, 0, 5), ymin=0) # needs sage.symbolic Graphics object consisting of 1 graphics primitive (This test verifies that :trac:`8632` is fixed.) @@ -3269,6 +3315,7 @@ def save(self, filename, **kwds): Legend labels should save correctly:: + sage: # needs sage.symbolic sage: P = plot(x,(x,0,1),legend_label='$xyz$') sage: P.set_legend_options(back_color=(1,0,0)) sage: P.set_legend_options(loc=7) @@ -3279,16 +3326,16 @@ def save(self, filename, **kwds): This plot should save with the frame shown, showing :trac:`7524` is fixed (same issue as :trac:`7981` and :trac:`8632`):: - sage: var('x,y') + sage: var('x,y') # needs sage.symbolic (x, y) - sage: a = plot_vector_field((x,-y),(x,-1,1),(y,-1,1)) + sage: a = plot_vector_field((x,-y),(x,-1,1),(y,-1,1)) # needs sage.symbolic sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.symbolic ....: a.save(f.name) The following plot should show the axes; fixes :trac:`14782` :: - sage: plot(x^2, (x, 1, 2), ticks=[[], []]) + sage: plot(x^2, (x, 1, 2), ticks=[[], []]) # needs sage.symbolic Graphics object consisting of 1 graphics primitive """ @@ -3403,7 +3450,7 @@ def description(self): EXAMPLES:: - sage: print(polytopes.hypercube(2).plot().description()) + sage: print(polytopes.hypercube(2).plot().description()) # needs sage.geometry.polyhedron Polygon defined by 4 points: [(-1.0, -1.0), (1.0, -1.0), (1.0, 1.0), (-1.0, 1.0)] Line defined by 2 points: [(-1.0, 1.0), (-1.0, -1.0)] Line defined by 2 points: [(1.0, -1.0), (-1.0, -1.0)] @@ -3448,6 +3495,7 @@ def inset(self, graphics, pos=None, fontsize=None): EXAMPLES:: + sage: # needs sage.symbolic sage: f(x) = x^2*sin(1/x) sage: g1 = plot(f(x), (x, -2, 2), axes_labels=['$x$', '$y$']) sage: g2 = plot(f(x), (x, -0.3, 0.3), axes_labels=['$x$', '$y$'], @@ -3465,7 +3513,7 @@ def inset(self, graphics, pos=None, fontsize=None): Using non-default values for the position/size and the font size:: - sage: g1.inset(g2, pos=(0.15, 0.7, 0.25, 0.25), fontsize=8) + sage: g1.inset(g2, pos=(0.15, 0.7, 0.25, 0.25), fontsize=8) # needs sage.symbolic Multigraphics with 2 elements .. PLOT:: @@ -3478,10 +3526,10 @@ def inset(self, graphics, pos=None, fontsize=None): We can add another inset by invoking ``inset`` on the last output:: - sage: g1g2 = _ - sage: g3 = plot(f(x), (x, -0.05, 0.05), axes_labels=['$x$', '$y$'], + sage: g1g2 = _ # needs sage.symbolic + sage: g3 = plot(f(x), (x, -0.05, 0.05), axes_labels=['$x$', '$y$'], # needs sage.symbolic ....: frame=True) - sage: g1g2.inset(g3, pos=(0.65, 0.12, 0.25, 0.25)) + sage: g1g2.inset(g3, pos=(0.65, 0.12, 0.25, 0.25)) # needs sage.symbolic Multigraphics with 3 elements .. PLOT:: @@ -3518,7 +3566,8 @@ def GraphicsArray(*args, **kwargs): sage: from sage.plot.graphics import GraphicsArray sage: c = circle((0,0), 1) sage: G = GraphicsArray([c, c]) - doctest:...: DeprecationWarning: GraphicsArray must be imported from sage.plot.multigraphics and no longer from sage.plot.graphics. + doctest:...: DeprecationWarning: GraphicsArray must be imported from + sage.plot.multigraphics and no longer from sage.plot.graphics. See https://github.com/sagemath/sage/issues/28675 for details. sage: G Graphics Array of size 1 x 2 diff --git a/src/sage/plot/histogram.py b/src/sage/plot/histogram.py index 295f3036eba..388c2d1391d 100644 --- a/src/sage/plot/histogram.py +++ b/src/sage/plot/histogram.py @@ -87,13 +87,8 @@ def get_minmax_data(self): TESTS:: - sage: h = histogram([10,3,5], normed=True)[0] - doctest:warning...: - DeprecationWarning: the 'normed' option is deprecated. Use 'density' instead. - See https://github.com/sagemath/sage/issues/25260 for details. + sage: h = histogram([10,3,5], density=True)[0] sage: h.get_minmax_data() - doctest:warning ... - ...VisibleDeprecationWarning: Passing `normed=True` on non-uniform bins has always been broken, and computes neither the probability density function nor the probability mass function. The result is only correct if the bins are uniform, when density=True will produce the same result anyway. The argument will be removed in a future version of numpy. {'xmax': 10.0, 'xmin': 3.0, 'ymax': 0.476190476190..., 'ymin': 0} """ import numpy diff --git a/src/sage/plot/hyperbolic_arc.py b/src/sage/plot/hyperbolic_arc.py index 0ab3f2744c8..4e7fda8350d 100644 --- a/src/sage/plot/hyperbolic_arc.py +++ b/src/sage/plot/hyperbolic_arc.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic r""" Arcs in hyperbolic geometry diff --git a/src/sage/plot/hyperbolic_polygon.py b/src/sage/plot/hyperbolic_polygon.py index 1726525ff43..efe39697829 100644 --- a/src/sage/plot/hyperbolic_polygon.py +++ b/src/sage/plot/hyperbolic_polygon.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Polygons and triangles in hyperbolic geometry diff --git a/src/sage/plot/hyperbolic_regular_polygon.py b/src/sage/plot/hyperbolic_regular_polygon.py index 5874073b549..9be2169ab63 100644 --- a/src/sage/plot/hyperbolic_regular_polygon.py +++ b/src/sage/plot/hyperbolic_regular_polygon.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Regular polygons in the upper half model for hyperbolic plane @@ -109,14 +110,14 @@ def __init__(self, sides, i_angle, center, options): """ self.center = CC(center) if self.center.imag() <= 0: - raise ValueError("center: %s is not a valid point in the upper half plane model of the hyperbolic plane"%(self.center)) + raise ValueError("center: %s is not a valid point in the upper half plane model of the hyperbolic plane" % (self.center)) if sides < 3: raise ValueError("degenerated polygons (sides<=2) are not supported") if i_angle <= 0 or i_angle >= pi: - raise ValueError("interior angle %s must be in (0, pi) interval"%(i_angle)) + raise ValueError("interior angle %s must be in (0, pi) interval" % (i_angle)) if pi*(sides-2) - sides*i_angle <= 0: raise ValueError("there exists no hyperbolic regular compact polygon," - " for sides=%s the interior angle must be less than %s"%(sides, pi * (sides-2) / sides)) + " for sides=%s the interior angle must be less than %s" % (sides, pi * (sides-2) / sides)) self.sides = sides self.i_angle = i_angle beta = 2 * pi / self.sides # compute the rotation angle to be used ahead @@ -150,7 +151,7 @@ def __init__(self, sides, i_angle, center, options): new_z_k = self._i_rotation(z_k[-1], beta).n(digits=8) z_k = z_k + [new_z_k] d_z_k = d_z_k + [new_z_k * scale + h_disp] - r_z_k=[-(new_z_k).conjugate() * scale + h_disp] + r_z_k + r_z_k = [-(new_z_k).conjugate() * scale + h_disp] + r_z_k if is_odd(self.sides): HyperbolicPolygon.__init__(self, d_z_k + r_z_k, "UHP", options) else: diff --git a/src/sage/plot/line.py b/src/sage/plot/line.py index 691e3c31307..c945946484a 100644 --- a/src/sage/plot/line.py +++ b/src/sage/plot/line.py @@ -131,9 +131,9 @@ def plot3d(self, z=0, **kwds): EXAMPLES:: - sage: E = EllipticCurve('37a').plot(thickness=5).plot3d() - sage: F = EllipticCurve('37a').plot(thickness=5).plot3d(z=2) - sage: E + F # long time (5s on sage.math, 2012) + sage: E = EllipticCurve('37a').plot(thickness=5).plot3d() # needs sage.schemes + sage: F = EllipticCurve('37a').plot(thickness=5).plot3d(z=2) # needs sage.schemes + sage: E + F # long time (5s on sage.math, 2012), needs sage.schemes Graphics3d Object .. PLOT:: @@ -389,16 +389,16 @@ def line2d(points, **options): A line with no points or one point:: - sage: line([]) #returns an empty plot + sage: line([]) # returns an empty plot Graphics object consisting of 0 graphics primitives - sage: import numpy; line(numpy.array([])) + sage: import numpy; line(numpy.array([])) # needs numpy Graphics object consisting of 0 graphics primitives sage: line([(1,1)]) Graphics object consisting of 1 graphics primitive A line with numpy arrays:: - sage: line(numpy.array([[1,2], [3,4]])) + sage: line(numpy.array([[1,2], [3,4]])) # needs numpy Graphics object consisting of 1 graphics primitive A line with a legend:: @@ -442,7 +442,9 @@ def line2d(points, **options): A blue conchoid of Nicomedes:: - sage: L = [[1+5*cos(pi/2+pi*i/100), tan(pi/2+pi*i/100)*(1+5*cos(pi/2+pi*i/100))] for i in range(1,100)] + sage: from math import pi + sage: L = [[1 + 5*cos(pi/2+pi*i/100), + ....: tan(pi/2+pi*i/100) * (1+5*cos(pi/2+pi*i/100))] for i in range(1,100)] sage: line(L, rgbcolor=(1/4,1/8,3/4)) Graphics object consisting of 1 graphics primitive @@ -454,7 +456,7 @@ def line2d(points, **options): A line with 2 complex points:: sage: i = CC(0,1) - sage: line([1+i, 2+3*i]) + sage: line([1 + i, 2 + 3*i]) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -466,7 +468,8 @@ def line2d(points, **options): A blue hypotrochoid (3 leaves):: sage: n = 4; h = 3; b = 2 - sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] + sage: L = [[n*cos(pi*i/100) + h*cos((n/b)*pi*i/100), + ....: n*sin(pi*i/100) - h*sin((n/b)*pi*i/100)] for i in range(200)] sage: line(L, rgbcolor=(1/4,1/4,3/4)) Graphics object consisting of 1 graphics primitive @@ -482,7 +485,8 @@ def line2d(points, **options): A blue hypotrochoid (4 leaves):: sage: n = 6; h = 5; b = 2 - sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] + sage: L = [[n*cos(pi*i/100) + h*cos((n/b)*pi*i/100), + ....: n*sin(pi*i/100) - h*sin((n/b)*pi*i/100)] for i in range(200)] sage: line(L, rgbcolor=(1/4,1/4,3/4)) Graphics object consisting of 1 graphics primitive @@ -493,7 +497,8 @@ def line2d(points, **options): A red limacon of Pascal:: - sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,101)] + sage: L = [[sin(pi*i/100) + sin(pi*i/50), + ....: -(1 + cos(pi*i/100) + cos(pi*i/50))] for i in range(-100,101)] sage: line(L, rgbcolor=(1,1/4,1/2)) Graphics object consisting of 1 graphics primitive @@ -504,7 +509,8 @@ def line2d(points, **options): A light green trisectrix of Maclaurin:: - sage: L = [[2*(1-4*cos(-pi/2+pi*i/100)^2),10*tan(-pi/2+pi*i/100)*(1-4*cos(-pi/2+pi*i/100)^2)] for i in range(1,100)] + sage: L = [[2 * (1-4*cos(-pi/2+pi*i/100)^2), + ....: 10 * tan(-pi/2+pi*i/100) * (1-4*cos(-pi/2+pi*i/100)^2)] for i in range(1,100)] sage: line(L, rgbcolor=(1/4,1,1/8)) Graphics object consisting of 1 graphics primitive @@ -530,8 +536,8 @@ def line2d(points, **options): A red plot of the Jacobi elliptic function `\text{sn}(x,2)`, `-3 < x < 3`:: - sage: L = [(i/100.0, real_part(jacobi('sn', i/100.0, 2.0))) for i in - ....: range(-300, 300, 30)] + sage: L = [(i/100.0, real_part(jacobi('sn', i/100.0, 2.0))) + ....: for i in range(-300, 300, 30)] sage: line(L, rgbcolor=(3/4, 1/4, 1/8)) Graphics object consisting of 1 graphics primitive @@ -543,7 +549,7 @@ def line2d(points, **options): A red plot of `J`-Bessel function `J_2(x)`, `0 < x < 10`:: sage: L = [(i/10.0, bessel_J(2,i/10.0)) for i in range(100)] - sage: line(L, rgbcolor=(3/4,1/4,5/8)) + sage: line(L, rgbcolor=(3/4, 1/4, 5/8)) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -556,7 +562,7 @@ def line2d(points, **options): sage: i = CDF.gen() sage: v = [zeta(0.5 + n/10 * i) for n in range(300)] sage: L = [(z.real(), z.imag()) for z in v] - sage: line(L, rgbcolor=(3/4,1/2,5/8)) + sage: line(L, rgbcolor=(3/4, 1/2, 5/8)) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -568,8 +574,9 @@ def line2d(points, **options): A purple plot of the Hasse-Weil `L`-function `L(E, 1 + it)`, `-1 < t < 10`:: + sage: # needs sage.schemes sage: E = EllipticCurve('37a') - sage: vals = E.lseries().values_along_line(1-I, 1+10*I, 100) # critical line + sage: vals = E.lseries().values_along_line(1-I, 1+10*I, 100) # critical line sage: L = [(z[1].real(), z[1].imag()) for z in vals] sage: line(L, rgbcolor=(3/4,1/2,5/8)) Graphics object consisting of 1 graphics primitive diff --git a/src/sage/plot/matrix_plot.py b/src/sage/plot/matrix_plot.py index ddee2b8925e..f113f5aaa62 100644 --- a/src/sage/plot/matrix_plot.py +++ b/src/sage/plot/matrix_plot.py @@ -121,9 +121,9 @@ def get_minmax_data(self): # for example, the square representing the (0,0) entry is centered on # the origin. if not xrange: - xrange = (-.5, self.xy_array_col -.5) + xrange = (-.5, self.xy_array_col - .5) if not yrange: - yrange = (-.5, self.xy_array_row -.5) + yrange = (-.5, self.xy_array_row - .5) return minmax_data(xrange, yrange, dict=True) def _allowed_options(self): @@ -132,8 +132,8 @@ def _allowed_options(self): EXAMPLES:: - sage: M = matrix_plot([[sin(i*j) for i in range(5)] for j in range(5)]) - sage: isinstance(M[0]._allowed_options(),dict) + sage: M = matrix_plot([[sin(i*j) for i in range(5)] for j in range(5)]) # needs sage.symbolic + sage: isinstance(M[0]._allowed_options(), dict) # needs sage.symbolic True """ return {'cmap':"""the name of a predefined colormap, @@ -158,11 +158,11 @@ def _repr_(self): EXAMPLES:: - sage: M = matrix_plot([[sin(i*j) for i in range(5)] for j in range(5)]) - sage: m = M[0]; m + sage: M = matrix_plot([[sin(i*j) for i in range(5)] for j in range(5)]) # needs sage.symbolic + sage: m = M[0]; m # needs sage.symbolic MatrixPlot defined by a 5 x 5 data grid """ - return "MatrixPlot defined by a %s x %s data grid"%(self.xy_array_row, self.xy_array_col) + return "MatrixPlot defined by a %s x %s data grid" % (self.xy_array_row, self.xy_array_col) def _render_on_subplot(self, subplot): """ @@ -175,29 +175,29 @@ def _render_on_subplot(self, subplot): cmap = get_cmap(options.pop('cmap',None)) flip_y = options['flip_y'] - norm=options['norm'] + norm = options['norm'] - if norm=='value': + if norm == 'value': import matplotlib - norm=matplotlib.colors.NoNorm() + norm = matplotlib.colors.NoNorm() - lim=self.get_minmax_data() + lim = self.get_minmax_data() if options['subdivisions']: - subdiv_options=options['subdivision_options'] + subdiv_options = options['subdivision_options'] if isinstance(subdiv_options['boundaries'], (list, tuple)): - rowsub,colsub=subdiv_options['boundaries'] + rowsub,colsub = subdiv_options['boundaries'] else: - rowsub=subdiv_options['boundaries'] - colsub=subdiv_options['boundaries'] + rowsub = subdiv_options['boundaries'] + colsub = subdiv_options['boundaries'] if isinstance(subdiv_options['style'], (list, tuple)): - rowstyle,colstyle=subdiv_options['style'] + rowstyle,colstyle = subdiv_options['style'] else: - rowstyle=subdiv_options['style'] - colstyle=subdiv_options['style'] + rowstyle = subdiv_options['style'] + colstyle = subdiv_options['style'] if rowstyle is None: - rowstyle=dict() + rowstyle = dict() if colstyle is None: - colstyle=dict() + colstyle = dict() # Make line objects for subdivisions from .line import line2d @@ -215,7 +215,7 @@ def _render_on_subplot(self, subplot): if hasattr(self.xy_data_array, 'tocoo'): # Sparse matrix -- use spy - opts=options.copy() + opts = options.copy() for opt in ['vmin', 'vmax', 'norm', 'flip_y', 'subdivisions', 'subdivision_options', 'colorbar', 'colorbar_options']: del opts[opt] @@ -233,7 +233,7 @@ def _render_on_subplot(self, subplot): if options.get('colorbar', False): colorbar_options = options['colorbar_options'] from matplotlib import colorbar - cax,kwds=colorbar.make_axes_gridspec(subplot,**colorbar_options) + cax,kwds = colorbar.make_axes_gridspec(subplot,**colorbar_options) colorbar.Colorbar(cax, image, **kwds) if flip_y: @@ -243,7 +243,6 @@ def _render_on_subplot(self, subplot): subplot.xaxis.set_ticks_position('both') #only tick marks, not tick labels - @suboptions('colorbar', orientation='vertical', format=None) @suboptions('subdivision',boundaries=None, style=None) @options(aspect_ratio=1, axes=False, cmap='Greys', colorbar=False, @@ -389,14 +388,17 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): sage: m=random_matrix(RR,10) sage: m.subdivide([2,4],[6,8]) - sage: matrix_plot(m, subdivisions=True, subdivision_style=dict(color='red',thickness=3)) + sage: matrix_plot(m, subdivisions=True, + ....: subdivision_style=dict(color='red',thickness=3)) Graphics object consisting of 1 graphics primitive You can also specify your own subdivisions and separate styles for row or column subdivisions:: sage: m=random_matrix(RR,10) - sage: matrix_plot(m, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]], subdivision_style=[dict(color='red',thickness=3),dict(linestyle='--',thickness=6)]) + sage: matrix_plot(m, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]], + ....: subdivision_style=[dict(color='red',thickness=3), + ....: dict(linestyle='--',thickness=6)]) Graphics object consisting of 1 graphics primitive Generally matrices are plotted with the (0,0) entry in the upper @@ -410,10 +412,9 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): A custom bounding box in which to draw the matrix can be specified using the ``xrange`` and ``yrange`` arguments:: - sage: P = matrix_plot(identity_matrix(10), xrange=(0, pi), yrange=(-pi, 0)) - sage: P + sage: P = matrix_plot(identity_matrix(10), xrange=(0, pi), yrange=(-pi, 0)); P # needs sage.symbolic Graphics object consisting of 1 graphics primitive - sage: P.get_minmax_data() + sage: P.get_minmax_data() # needs sage.symbolic {'xmax': 3.14159..., 'xmin': 0.0, 'ymax': 0.0, 'ymin': -3.14159...} If the horizontal and vertical dimension of the image are very different, @@ -426,18 +427,19 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): Another random plot, but over `\GF{389}`:: - sage: m = random_matrix(GF(389), 10) - sage: matrix_plot(m, cmap='Oranges') + sage: m = random_matrix(GF(389), 10) # needs sage.rings.finite_rings + sage: matrix_plot(m, cmap='Oranges') # needs sage.rings.finite_rings Graphics object consisting of 1 graphics primitive It also works if you lift it to the polynomial ring:: - sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges') + sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges') # needs sage.rings.finite_rings Graphics object consisting of 1 graphics primitive We have several options for colorbars:: - sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_orientation='horizontal') + sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, + ....: colorbar_orientation='horizontal') Graphics object consisting of 1 graphics primitive :: @@ -457,27 +459,28 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): Here we plot a random sparse matrix:: - sage: sparse = matrix(dict([((randint(0, 10), randint(0, 10)), 1) for i in range(100)])) + sage: sparse = matrix(dict(((randint(0, 10), randint(0, 10)), 1) + ....: for i in range(100))) sage: matrix_plot(sparse) Graphics object consisting of 1 graphics primitive :: - sage: A=random_matrix(ZZ,100000,density=.00001,sparse=True) - sage: matrix_plot(A,marker=',') + sage: A = random_matrix(ZZ, 100000, density=.00001, sparse=True) + sage: matrix_plot(A, marker=',') Graphics object consisting of 1 graphics primitive As with dense matrices, sparse matrix entries are automatically converted to floating point numbers before plotting. Thus the following works:: - sage: b=random_matrix(GF(2),200,sparse=True,density=0.01) - sage: matrix_plot(b) + sage: b = random_matrix(GF(2), 200, sparse=True, density=0.01) # needs sage.rings.finite_rings + sage: matrix_plot(b) # needs sage.rings.finite_rings Graphics object consisting of 1 graphics primitive While this returns an error:: - sage: b=random_matrix(CDF,200,sparse=True,density=0.01) + sage: b = random_matrix(CDF, 200, sparse=True, density=0.01) sage: matrix_plot(b) Traceback (most recent call last): ... @@ -486,7 +489,7 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): To plot the absolute value of a complex matrix, use the ``apply_map`` method:: - sage: b=random_matrix(CDF,200,sparse=True,density=0.01) + sage: b = random_matrix(CDF, 200, sparse=True, density=0.01) sage: matrix_plot(b.apply_map(abs)) Graphics object consisting of 1 graphics primitive @@ -497,8 +500,8 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): As does plotting of NumPy arrays:: - sage: import numpy - sage: matrix_plot(numpy.random.rand(10, 10)) + sage: import numpy # needs numpy + sage: matrix_plot(numpy.random.rand(10, 10)) # needs numpy Graphics object consisting of 1 graphics primitive A plot title can be added to the matrix plot.:: @@ -566,7 +569,7 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): from sage.plot.all import Graphics from sage.structure.element import is_Matrix from sage.rings.real_double import RDF - orig_mat=mat + orig_mat = mat if is_Matrix(mat): sparse = mat.is_sparse() if sparse: @@ -585,12 +588,11 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): else: sparse = False - try: if sparse: xy_data_array = mat else: - xy_data_array = np.asarray(mat, dtype = float) + xy_data_array = np.asarray(mat, dtype=float) except TypeError: raise TypeError("mat must be a Matrix or a two dimensional array") except ValueError: @@ -610,7 +612,7 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): yrange = tuple(float(v) for v in yrange) if options['subdivisions'] and options['subdivision_options']['boundaries'] is None: - options['subdivision_options']['boundaries']=orig_mat.get_subdivisions() + options['subdivision_options']['boundaries'] = orig_mat.get_subdivisions() # Custom position the title. Otherwise it overlaps with tick labels if options['flip_y'] and 'title_pos' not in options: diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index 37a8000f9aa..fa06484c4cf 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Plotting utilities """ @@ -96,7 +97,7 @@ def setup_for_eval_on_grid(funcs, ValueError: At least one variable range has more than 3 entries: each should either have 2 or 3 entries, with one of the forms (xmin, xmax) or (x, xmin, xmax) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(y,1,-1),(x,-1,1)], plot_points=5) - (<sage...>, [(1.0, -1.0, 0.5), (-1.0, 1.0, 0.5)]) + (<sage...>, [(-1.0, 1.0, 0.5), (-1.0, 1.0, 0.5)]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,1,-1),(x,-1,1)], plot_points=5) Traceback (most recent call last): ... @@ -106,9 +107,9 @@ def setup_for_eval_on_grid(funcs, ... ValueError: plot start point and end point must be different sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,1,-1),(y,-1,1)], return_vars=True) - (<sage...>, [(1.0, -1.0, 2.0), (-1.0, 1.0, 2.0)], [x, y]) + (<sage...>, [(-1.0, 1.0, 2.0), (-1.0, 1.0, 2.0)], [x, y]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(y,1,-1),(x,-1,1)], return_vars=True) - (<sage...>, [(1.0, -1.0, 2.0), (-1.0, 1.0, 2.0)], [y, x]) + (<sage...>, [(-1.0, 1.0, 2.0), (-1.0, 1.0, 2.0)], [y, x]) TESTS: @@ -139,6 +140,14 @@ def setup_for_eval_on_grid(funcs, else: vars, free_vars = unify_arguments(funcs) + # check for invalid range (xmin > xmax or ymin > ymax) and swap + if len(ranges) > 1: + for i in range(len(ranges)): + if ranges[i][-2] > ranges[i][-1]: + ranges[i] = list(ranges[i]) + ranges[i][-1], ranges[i][-2] = ranges[i][-2], ranges[i][-1] + ranges[i] = tuple(ranges[i]) + # pad the variables if we don't have enough nargs = len(ranges) if len(vars) < nargs: @@ -250,8 +259,8 @@ def unify_arguments(funcs): sage: sage.plot.misc.unify_arguments((x+y,x-y)) ((x, y), (x, y)) """ - vars=set() - free_variables=set() + vars = set() + free_variables = set() if not isinstance(funcs, (list, tuple)): funcs = [funcs] @@ -308,7 +317,7 @@ def _multiple_of_constant(n, pos, const): k = 1 while cf.quotient(k) != Infinity and cf.denominator(k) < 12: k += 1 - return '$%s$'%latex(cf.convergent(k-1)*const) + return '$%s$' % latex(cf.convergent(k-1)*const) def get_matplotlib_linestyle(linestyle, return_type): @@ -395,9 +404,9 @@ def get_matplotlib_linestyle(linestyle, return_type): '--', ':', '-.', ''} """ - long_to_short_dict={'solid' : '-','dashed' : '--', 'dotted' : ':', + long_to_short_dict = {'solid' : '-','dashed' : '--', 'dotted' : ':', 'dashdot':'-.'} - short_to_long_dict={'-' : 'solid','--' : 'dashed', ':' : 'dotted', + short_to_long_dict = {'-' : 'solid','--' : 'dashed', ':' : 'dotted', '-.':'dashdot'} # We need this to take care of region plot. Essentially, if None is @@ -432,7 +441,7 @@ def get_matplotlib_linestyle(linestyle, return_type): raise ValueError("WARNING: Unrecognized linestyle '%s'. " "Possible linestyle options are:\n{'solid', " "'dashed', 'dotted', dashdot', 'None'}, " - "respectively {'-', '--', ':', '-.', ''}"% + "respectively {'-', '--', ':', '-.', ''}" % (linestyle)) elif return_type == 'long': @@ -446,7 +455,7 @@ def get_matplotlib_linestyle(linestyle, return_type): raise ValueError("WARNING: Unrecognized linestyle '%s'. " "Possible linestyle options are:\n{'solid', " "'dashed', 'dotted', dashdot', 'None'}, " - "respectively {'-', '--', ':', '-.', ''}"% + "respectively {'-', '--', ':', '-.', ''}" % (linestyle)) diff --git a/src/sage/plot/multigraphics.py b/src/sage/plot/multigraphics.py index 99c817f03a6..f22febca152 100644 --- a/src/sage/plot/multigraphics.py +++ b/src/sage/plot/multigraphics.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic r""" Graphics arrays and insets @@ -1207,7 +1207,7 @@ def _add_subplot(self, figure, index, **options): sage: fig = Figure() sage: ax1 = G._add_subplot(fig, 0) sage: type(ax1) - <class 'matplotlib.axes._subplots.AxesSubplot'> + <class 'matplotlib.axes...'> sage: ax2 = G._add_subplot(fig, 1) sage: fig.get_axes() == [ax1, ax2] True diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index a36ff9efc53..b614b2ef3db 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic r""" 2D plotting @@ -186,7 +187,7 @@ You can even have custom tick labels along with custom positioning. :: - sage: plot(x^2, (x,0,3), ticks=[[1,2.5],pi/2], tick_formatter=[["$x_1$","$x_2$"],pi]) # long time + sage: plot(x^2, (x,0,3), ticks=[[1,2.5],pi/2], tick_formatter=[["$x_1$","$x_2$"],pi]) # long time Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -339,7 +340,7 @@ Many concentric circles shrinking toward the origin:: - sage: show(sum(circle((i,0), i, hue=sin(i/10)) for i in [10,9.9,..,0])) # long time + sage: show(sum(circle((i,0), i, hue=sin(i/10)) for i in [10,9.9,..,0])) # long time .. PLOT:: @@ -419,7 +420,8 @@ def y(x): return x*sin(x**2) sage: g1 = plot(sin(x), 0, 2*pi) sage: g2 = plot(cos(x), 0, 2*pi, linestyle="--") - sage: (g1+g2).show(ticks=pi/6, tick_formatter=pi) # long time # show their sum, nicely formatted + sage: (g1 + g2).show(ticks=pi/6, # show their sum, nicely formatted # long time + ....: tick_formatter=pi) .. PLOT:: @@ -432,7 +434,8 @@ def y(x): return x*sin(x**2) sage: f(x) = (x-3)*(x-5)*(x-7)+40 sage: P = line([(2,0),(2,f(2))], color='black') sage: P += line([(8,0),(8,f(8))], color='black') - sage: P += polygon([(2,0),(2,f(2))] + [(x, f(x)) for x in [2,2.1,..,8]] + [(8,0),(2,0)], rgbcolor=(0.8,0.8,0.8),aspect_ratio='automatic') + sage: P += polygon([(2,0),(2,f(2))] + [(x, f(x)) for x in [2,2.1,..,8]] + [(8,0),(2,0)], + ....: rgbcolor=(0.8,0.8,0.8), aspect_ratio='automatic') sage: P += text("$\\int_{a}^b f(x) dx$", (5, 20), fontsize=16, color='black') sage: P += plot(f, (1, 8.5), thickness=3) sage: P # show the result @@ -515,7 +518,7 @@ def f(x): return (x-3)*(x-5)*(x-7)+40 Verify that a clean sage startup does *not* import matplotlib:: - sage: os.system("sage -c \"if 'matplotlib' in sys.modules: sys.exit(1)\"") # long time + sage: os.system("sage -c \"if 'matplotlib' in sys.modules: sys.exit(1)\"") # long time 0 Verify that :trac:`10980` is fixed:: @@ -681,15 +684,17 @@ def SelectiveFormatter(formatter, skip_values): :: + sage: # needs numpy sage: from sage.plot.plot import SelectiveFormatter sage: import matplotlib.pyplot as plt sage: import numpy - sage: fig=plt.figure() - sage: ax=fig.add_subplot(111) + sage: fig = plt.figure() + sage: ax = fig.add_subplot(111) sage: t = numpy.arange(0.0, 2.0, 0.01) sage: s = numpy.sin(2*numpy.pi*t) sage: p = ax.plot(t, s) - sage: formatter=SelectiveFormatter(ax.xaxis.get_major_formatter(),skip_values=[0,1]) + sage: formatter = SelectiveFormatter(ax.xaxis.get_major_formatter(), + ....: skip_values=[0,1]) sage: ax.xaxis.set_major_formatter(formatter) sage: import tempfile sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: @@ -715,22 +720,24 @@ def __init__(self, formatter, skip_values): EXAMPLES:: + sage: # needs numpy sage: from sage.plot.plot import SelectiveFormatter sage: import matplotlib.pyplot as plt sage: import numpy - sage: fig=plt.figure() - sage: ax=fig.add_subplot(111) + sage: fig = plt.figure() + sage: ax = fig.add_subplot(111) sage: t = numpy.arange(0.0, 2.0, 0.01) sage: s = numpy.sin(2*numpy.pi*t) - sage: line=ax.plot(t, s) - sage: formatter=SelectiveFormatter(ax.xaxis.get_major_formatter(),skip_values=[0,1]) + sage: line = ax.plot(t, s) + sage: formatter = SelectiveFormatter(ax.xaxis.get_major_formatter(), + ....: skip_values=[0,1]) sage: ax.xaxis.set_major_formatter(formatter) sage: from tempfile import NamedTemporaryFile sage: with NamedTemporaryFile(suffix=".png") as f: ....: fig.savefig(f.name) """ - self.formatter=formatter - self.skip_values=skip_values + self.formatter = formatter + self.skip_values = skip_values def set_locs(self, locs): """ @@ -740,7 +747,8 @@ def set_locs(self, locs): sage: from sage.plot.plot import SelectiveFormatter sage: import matplotlib.ticker - sage: formatter=SelectiveFormatter(matplotlib.ticker.Formatter(),skip_values=[0,200]) + sage: formatter = SelectiveFormatter(matplotlib.ticker.Formatter(), + ....: skip_values=[0,200]) sage: formatter.set_locs([i*100 for i in range(10)]) """ self.formatter.set_locs([l for l in locs if l not in self.skip_values]) @@ -753,7 +761,8 @@ def __call__(self, x, *args, **kwds): sage: from sage.plot.plot import SelectiveFormatter sage: import matplotlib.ticker - sage: formatter=SelectiveFormatter(matplotlib.ticker.FixedFormatter(['a','b']),skip_values=[0,2]) + sage: formatter = SelectiveFormatter(matplotlib.ticker.FixedFormatter(['a','b']), + ....: skip_values=[0,2]) sage: [formatter(i,1) for i in range(10)] ['', 'b', '', 'b', 'b', 'b', 'b', 'b', 'b', 'b'] """ @@ -1101,7 +1110,7 @@ def plot(funcs, *args, **kwds): :: - sage: p=plot(1, (x,0,3), plot_points=4, randomize=False, adaptive_recursion=0) + sage: p = plot(1, (x,0,3), plot_points=4, randomize=False, adaptive_recursion=0) sage: list(p[0]) [(0.0, 1.0), (1.0, 1.0), (2.0, 1.0), (3.0, 1.0)] @@ -1139,9 +1148,12 @@ def plot(funcs, *args, **kwds): By default, color will change from one primitive to the next. This may be controlled by modifying ``color`` option:: - sage: g1 = plot([x*exp(-n*x^2)/.4 for n in [1..3]], (0, 2), color='blue', aspect_ratio=.8); g1 + sage: g1 = plot([x*exp(-n*x^2)/.4 for n in [1..3]], (0, 2), + ....: color='blue', aspect_ratio=.8); g1 Graphics object consisting of 3 graphics primitives - sage: g2 = plot([x*exp(-n*x^2)/.4 for n in [1..3]], (0, 2), color=['red','red','green'], linestyle=['-','--','-.'], aspect_ratio=.8); g2 + sage: g2 = plot([x*exp(-n*x^2)/.4 for n in [1..3]], (0, 2), + ....: color=['red','red','green'], linestyle=['-','--','-.'], + ....: aspect_ratio=.8); g2 Graphics object consisting of 3 graphics primitives .. PLOT:: @@ -1210,7 +1222,7 @@ def plot(funcs, *args, **kwds): a graph is on both sides of both axes, as the axes only cross if the origin is actually part of the viewing area:: - sage: plot(x^3,(x,0,2)) # this one has the origin + sage: plot(x^3, (x,0,2)) # this one has the origin Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1220,7 +1232,7 @@ def plot(funcs, *args, **kwds): :: - sage: plot(x^3,(x,1,2)) # this one does not + sage: plot(x^3, (x,1,2)) # this one does not Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1232,7 +1244,7 @@ def plot(funcs, *args, **kwds): the labels have quite different orders of magnitude or are very large, scientific notation (the `e` notation for powers of ten) is used:: - sage: plot(x^2,(x,480,500)) # this one has no scientific notation + sage: plot(x^2, (x,480,500)) # this one has no scientific notation Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1242,7 +1254,7 @@ def plot(funcs, *args, **kwds): :: - sage: plot(x^2,(x,300,500)) # this one has scientific notation on y-axis + sage: plot(x^2, (x,300,500)) # this one has scientific notation on y-axis Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1322,7 +1334,7 @@ def plot(funcs, *args, **kwds): If `X` is a list of Sage objects and ``legend_label`` is 'automatic', then Sage will create labels for each function according to their internal representation:: - sage: plot([sin(x), tan(x), 1-x^2], legend_label='automatic') + sage: plot([sin(x), tan(x), 1 - x^2], legend_label='automatic') Graphics object consisting of 3 graphics primitives .. PLOT:: @@ -1365,7 +1377,7 @@ def plot(funcs, *args, **kwds): :: - sage: plot_semilogy(exp, (1, 10)) # same thing + sage: plot_semilogy(exp, (1, 10)) # same thing Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1385,7 +1397,7 @@ def plot(funcs, *args, **kwds): :: - sage: plot(exp, (1, 10), scale='loglog', base=2) # long time # base of log is 2 + sage: plot(exp, (1, 10), scale='loglog', base=2) # base of log is 2 # long time Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1396,15 +1408,16 @@ def plot(funcs, *args, **kwds): We can also change the scale of the axes in the graphics just before displaying:: - sage: G = plot(exp, 1, 10) # long time - sage: G.show(scale=('semilogy', 2)) # long time + sage: G = plot(exp, 1, 10) # long time + sage: G.show(scale=('semilogy', 2)) # long time The algorithm used to insert extra points is actually pretty simple. On the picture drawn by the lines below:: sage: p = plot(x^2, (-0.5, 1.4)) + line([(0,0), (1,1)], color='green') sage: p += line([(0.5, 0.5), (0.5, 0.5^2)], color='purple') - sage: p += point(((0, 0), (0.5, 0.5), (0.5, 0.5^2), (1, 1)), color='red', pointsize=20) + sage: p += point(((0, 0), (0.5, 0.5), (0.5, 0.5^2), (1, 1)), + ....: color='red', pointsize=20) sage: p += text('A', (-0.05, 0.1), color='red') sage: p += text('B', (1.01, 1.1), color='red') sage: p += text('C', (0.48, 0.57), color='red') @@ -1444,8 +1457,8 @@ def plot(funcs, *args, **kwds): :: - sage: def h1(x): return abs(sqrt(x^3 - 1)) - sage: def h2(x): return -abs(sqrt(x^3 - 1)) + sage: def h1(x): return abs(sqrt(x^3 - 1)) + sage: def h2(x): return -abs(sqrt(x^3 - 1)) sage: P = plot([h1, h2], 1,4) sage: P # show the result Graphics object consisting of 2 graphics primitives @@ -1467,14 +1480,16 @@ def h2(x): return -abs(sqrt(x**3 - 1)) As a workaround, we can perform the trick:: - sage: p1 = line([(a,b) for a,b in zip(p[0].xdata,p[0].ydata) if (b>=-1 and b<=1)]) - sage: q1 = line([(a,b) for a,b in zip(q[0].xdata,q[0].ydata) if (b>=0 and b<=4)]) - sage: (p1+q1).show() + sage: p1 = line([(a,b) for a, b in zip(p[0].xdata, p[0].ydata) + ....: if b>=-1 and b<=1]) + sage: q1 = line([(a,b) for a, b in zip(q[0].xdata, q[0].ydata) + ....: if b>=0 and b<=4]) + sage: (p1 + q1).show() We can also directly plot the elliptic curve:: - sage: E = EllipticCurve([0,-1]) - sage: plot(E, (1, 4), color=hue(0.6)) + sage: E = EllipticCurve([0,-1]) # needs sage.schemes + sage: plot(E, (1, 4), color=hue(0.6)) # needs sage.schemes Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1600,8 +1615,10 @@ def h2(x): return -abs(sqrt(x**3 - 1)) sage: p1 = plot(sin(x), -pi, pi, fill='axis') sage: p2 = plot(sin(x), -pi, pi, fill='min', fillalpha=1) sage: p3 = plot(sin(x), -pi, pi, fill='max') - sage: p4 = plot(sin(x), -pi, pi, fill=(1-x)/3, fillcolor='blue', fillalpha=.2) - sage: graphics_array([[p1, p2], [p3, p4]]).show(frame=True, axes=False) # long time + sage: p4 = plot(sin(x), -pi, pi, fill=(1-x)/3, + ....: fillcolor='blue', fillalpha=.2) + sage: graphics_array([[p1, p2], # long time + ....: [p3, p4]]).show(frame=True, axes=False) .. PLOT:: @@ -1615,11 +1632,15 @@ def h2(x): return -abs(sqrt(x**3 - 1)) The basic options for filling a list of plots:: sage: (f1, f2) = x*exp(-1*x^2)/.35, x*exp(-2*x^2)/.35 - sage: p1 = plot([f1, f2], -pi, pi, fill={1: [0]}, fillcolor='blue', fillalpha=.25, color='blue') + sage: p1 = plot([f1, f2], -pi, pi, fill={1: [0]}, + ....: fillcolor='blue', fillalpha=.25, color='blue') sage: p2 = plot([f1, f2], -pi, pi, fill={0: x/3, 1:[0]}, color=['blue']) - sage: p3 = plot([f1, f2], -pi, pi, fill=[0, [0]], fillcolor=['orange','red'], fillalpha=1, color={1: 'blue'}) - sage: p4 = plot([f1, f2], (x,-pi, pi), fill=[x/3, 0], fillcolor=['grey'], color=['red', 'blue']) - sage: graphics_array([[p1, p2], [p3, p4]]).show(frame=True, axes=False) # long time + sage: p3 = plot([f1, f2], -pi, pi, fill=[0, [0]], + ....: fillcolor=['orange','red'], fillalpha=1, color={1: 'blue'}) + sage: p4 = plot([f1, f2], (x,-pi, pi), fill=[x/3, 0], + ....: fillcolor=['grey'], color=['red', 'blue']) + sage: graphics_array([[p1, p2], # long time + ....: [p3, p4]]).show(frame=True, axes=False) .. PLOT:: @@ -1633,7 +1654,8 @@ def h2(x): return -abs(sqrt(x**3 - 1)) A example about the growth of prime numbers:: - sage: plot(1.13*log(x), 1, 100, fill=lambda x: nth_prime(x)/floor(x), fillcolor='red') + sage: plot(1.13*log(x), 1, 100, + ....: fill=lambda x: nth_prime(x)/floor(x), fillcolor='red') Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1643,7 +1665,7 @@ def h2(x): return -abs(sqrt(x**3 - 1)) Fill the area between a function and its asymptote:: sage: f = (2*x^3+2*x-1)/((x-2)*(x+1)) - sage: plot([f, 2*x+2], -7,7, fill={0: [1]}, fillcolor='#ccc').show(ymin=-20, ymax=20) + sage: plot([f, 2*x+2], -7, 7, fill={0: [1]}, fillcolor='#ccc').show(ymin=-20, ymax=20) .. PLOT:: @@ -1670,16 +1692,18 @@ def b(n): return lambda x: bessel_J(n, x) like ``i:j`` will fill between the ith function and the line y=j:: sage: def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) - sage: plot([b(c) for c in [1..5]], 0, 20, fill={i:[i-1] for i in [1..4]}, color={i:'blue' for i in [1..5]}, aspect_ratio=3, ymax=3) + sage: plot([b(c) for c in [1..5]], 0, 20, fill={i: [i-1] for i in [1..4]}, + ....: color={i: 'blue' for i in [1..5]}, aspect_ratio=3, ymax=3) Graphics object consisting of 9 graphics primitives - sage: plot([b(c) for c in [1..5]], 0, 20, fill={i:i-1 for i in [1..4]}, color='blue', aspect_ratio=3) # long time + sage: plot([b(c) for c in [1..5]], 0, 20, fill={i: i-1 for i in [1..4]}, # long time + ....: color='blue', aspect_ratio=3) Graphics object consisting of 9 graphics primitives .. PLOT:: def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) g1 = plot([b(n) for n in range(1,6)], 0, 20, fill={i:[i-1] for i in range(1,5)}, color={i:'blue' for i in range(1,6)}, aspect_ratio=3) - g2 = plot([b(n) for n in range(1,6)], 0, 20, fill={i:i-1 for i in range(1,5)}, color='blue', aspect_ratio=3) # long time + g2 = plot([b(n) for n in range(1,6)], 0, 20, fill={i:i-1 for i in range(1,5)}, color='blue', aspect_ratio=3) g1.ymax(3) g = graphics_array([[g1], [g2]]) sphinx_plot(g) @@ -1687,39 +1711,42 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) Extra options will get passed on to :meth:`~sage.plot.graphics.Graphics.show`, as long as they are valid:: - sage: plot(sin(x^2), (x, -3, 3), title=r'Plot of $\sin(x^2)$', axes_labels=['$x$','$y$']) # These labels will be nicely typeset + sage: plot(sin(x^2), (x, -3, 3), # These labels will be nicely typeset + ....: title=r'Plot of $\sin(x^2)$', axes_labels=['$x$','$y$']) Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot(sin(x**2), (x, -3, 3), title=r'Plot of $\sin(x^2)$', axes_labels=['$x$','$y$']) # These labels will be nicely typeset + g = plot(sin(x**2), (x, -3, 3), title=r'Plot of $\sin(x^2)$', axes_labels=['$x$','$y$']) sphinx_plot(g) :: - sage: plot(sin(x^2), (x, -3, 3), title='Plot of sin(x^2)', axes_labels=['x','y']) # These will not + sage: plot(sin(x^2), (x, -3, 3), # These will not + ....: title='Plot of sin(x^2)', axes_labels=['x','y']) Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot(sin(x**2), (x, -3, 3), title='Plot of sin(x^2)', axes_labels=['x','y']) # These will not + g = plot(sin(x**2), (x, -3, 3), title='Plot of sin(x^2)', axes_labels=['x','y']) sphinx_plot(g) :: - sage: plot(sin(x^2), (x, -3, 3), axes_labels=['x','y'], axes_labels_size=2.5) # Large axes labels (w.r.t. the tick marks) + sage: plot(sin(x^2), (x, -3, 3), # Large axes labels (w.r.t. the tick marks) + ....: axes_labels=['x','y'], axes_labels_size=2.5) Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot(sin(x**2), (x, -3, 3), axes_labels=['x','y'], axes_labels_size=2.5) # Large axes labels (w.r.t. the tick marks) + g = plot(sin(x**2), (x, -3, 3), axes_labels=['x','y'], axes_labels_size=2.5) sphinx_plot(g) :: sage: plot(sin(x^2), (x, -3, 3), figsize=[8,2]) Graphics object consisting of 1 graphics primitive - sage: plot(sin(x^2), (x, -3, 3)).show(figsize=[8,2]) # These are equivalent + sage: plot(sin(x^2), (x, -3, 3)).show(figsize=[8,2]) # These are equivalent .. PLOT:: @@ -1731,7 +1758,7 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) :: - sage: plot(sin(pi*x), (x, -8, 8), ticks=[[-7,-3,0,3,7],[-1/2,0,1/2]]) + sage: plot(sin(pi*x), (x, -8, 8), ticks=[[-7,-3,0,3,7], [-1/2,0,1/2]]) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1741,7 +1768,10 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) :: - sage: plot(2*x + 1, (x, 0, 5), ticks=[[0, 1, e, pi, sqrt(20)], [1, 3, 2*e + 1, 2*pi + 1, 2*sqrt(20) + 1]], tick_formatter="latex") + sage: plot(2*x + 1, (x, 0, 5), + ....: ticks=[[0, 1, e, pi, sqrt(20)], + ....: [1, 3, 2*e + 1, 2*pi + 1, 2*sqrt(20) + 1]], + ....: tick_formatter="latex") Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1753,7 +1783,7 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) :: - sage: plot(sin(x),(x,0,2*pi),ticks=pi/3,tick_formatter=pi) + sage: plot(sin(x), (x,0,2*pi), ticks=pi/3, tick_formatter=pi) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1763,7 +1793,8 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) You can even have custom tick labels along with custom positioning. :: - sage: plot(x**2, (x,0,3), ticks=[[1,2.5],[0.5,1,2]], tick_formatter=[["$x_1$","$x_2$"],["$y_1$","$y_2$","$y_3$"]]) + sage: plot(x**2, (x,0,3), ticks=[[1,2.5], [0.5,1,2]], + ....: tick_formatter=[["$x_1$","$x_2$"],["$y_1$","$y_2$","$y_3$"]]) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -1775,7 +1806,7 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) option as shown below. This also requires that LaTeX, dvipng and Ghostscript be installed:: - sage: plot(x, typeset='type1') # optional - latex + sage: plot(x, typeset='type1') # optional - latex Graphics object consisting of 1 graphics primitive A example with excluded values:: @@ -1808,8 +1839,8 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) Excluded points can also be given by an equation:: - sage: g(x) = x^2-2*x-2 - sage: plot(1/g(x), (x, -3, 4), exclude=g(x)==0, ymin=-5, ymax=5) # long time + sage: g(x) = x^2 - 2*x - 2 + sage: plot(1/g(x), (x, -3, 4), exclude=g(x)==0, ymin=-5, ymax=5) # long time Graphics object consisting of 3 graphics primitives .. PLOT:: @@ -1821,7 +1852,8 @@ def g(x): return x**2-2*x-2 ``exclude`` and ``detect_poles`` can be used together:: sage: f(x) = (floor(x)+0.5) / (1-(x-0.5)^2) - sage: plot(f, (x, -3.5, 3.5), detect_poles='show', exclude=[-3..3], ymin=-5, ymax=5) + sage: plot(f, (x, -3.5, 3.5), detect_poles='show', exclude=[-3..3], + ....: ymin=-5, ymax=5) Graphics object consisting of 12 graphics primitives .. PLOT:: @@ -1841,7 +1873,7 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) .. PLOT:: set_verbose(-1) - g = plot(arcsec, (x, -2, 2)) # [-1, 1] is excluded automatically + g = plot(arcsec, (x, -2, 2)) sphinx_plot(g) :: @@ -1852,7 +1884,7 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) .. PLOT:: set_verbose(-1) - g = plot(arcsec, (x, -2, 2), exclude=[1.5]) # x=1.5 is also excluded + g = plot(arcsec, (x, -2, 2), exclude=[1.5]) sphinx_plot(g) :: @@ -1865,7 +1897,7 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) .. PLOT:: set_verbose(-1) - g = plot(sqrt(x**2-1), -2, 2) # [-1, 1] is excluded automatically + g = plot(sqrt(x**2-1), -2, 2) sphinx_plot(g) :: @@ -1877,7 +1909,7 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) .. PLOT:: set_verbose(-1) - g = plot(arccsc, -2, 2) # [-1, 1] is excluded automatically + g = plot(arccsc, -2, 2) sphinx_plot(g) TESTS: @@ -2143,7 +2175,7 @@ def _plot(funcs, xrange, parametric=False, options['plot_points'], imaginary_tolerance=imag_tol) xmin, xmax, delta = ranges[0] - xrange=ranges[0][:2] + xrange = ranges[0][:2] # parametric_plot will be a list or tuple of two functions (f,g) # and will plotted as (f(x), g(x)) for all x in the given range if parametric: @@ -2282,7 +2314,7 @@ def golden_rainbow(i,lightness=0.4): if i < len(legend_color_temp): legend_color_entry = legend_color_temp[i] elif legend_color_temp == 'automatic': - if len(funcs)>1: + if len(funcs) > 1: legend_color_entry = golden_rainbow(i) elif legend_color_temp is not None: legend_color_entry = legend_color_temp @@ -2513,8 +2545,6 @@ def golden_rainbow(i,lightness=0.4): return G - - ########## misc functions ################### @options(aspect_ratio=1.0) @@ -2554,7 +2584,7 @@ def parametric_plot(funcs, *args, **kwargs): :: - sage: parametric_plot( (sin(t), sin(2*t)), (t, 0, 2*pi), color=hue(0.6) ) + sage: parametric_plot((sin(t), sin(2*t)), (t, 0, 2*pi), color=hue(0.6)) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -2610,27 +2640,27 @@ def parametric_plot(funcs, *args, **kwargs): :: - sage: y=var('y') - sage: parametric_plot( (5*cos(x), x*y, cos(x*y)), (x, -4,4), (y,-4,4)) # long time` + sage: y = var('y') + sage: parametric_plot((5*cos(x), x*y, cos(x*y)), (x, -4, 4), (y, -4, 4)) # long time Graphics3d Object .. PLOT:: #AttributeError: 'sage.plot.plot3d.parametric_surface.ParametricSurf' object has no attribute 'plot' #y = var('y') - #g = parametric_plot( (5*cos(x), x*y, cos(x*y)), (x, -4,4), (y,-4,4)) # long time` + #g = parametric_plot( (5*cos(x), x*y, cos(x*y)), (x, -4,4), (y,-4,4)) # long time #sphinx_plot(g) :: - sage: t=var('t') - sage: parametric_plot( vector((sin(t), sin(2*t))), (t, 0, 2*pi), color='green') # long time + sage: t = var('t') + sage: parametric_plot(vector((sin(t), sin(2*t))), (t, 0, 2*pi), color='green') # long time Graphics object consisting of 1 graphics primitive .. PLOT:: t = var('t') - g = parametric_plot( vector((sin(t), sin(2*t))), (t, 0, 2*pi), color='green') # long time + g = parametric_plot( vector((sin(t), sin(2*t))), (t, 0, 2*pi), color='green') # long time sphinx_plot(g) :: @@ -2696,7 +2726,7 @@ def parametric_plot(funcs, *args, **kwargs): One test for :trac:`7165`:: sage: m = SR.var('m') - sage: parametric_plot([real(exp(i*m)),imaginary(exp(i*m))], (m,0,7)) + sage: parametric_plot([real(exp(i*m)), imaginary(exp(i*m))], (m, 0, 7)) Graphics object consisting of 1 graphics primitive """ num_ranges = 0 @@ -2828,7 +2858,7 @@ def polar_plot(funcs, *args, **kwds): sphinx_plot(g) """ - kwds['polar']=True + kwds['polar'] = True return plot(funcs, *args, **kwds) @options(aspect_ratio='automatic') @@ -2898,8 +2928,8 @@ def list_plot(data, plotjoined=False, **kwargs): You can provide a numpy array.:: - sage: import numpy - sage: list_plot(numpy.arange(10)) + sage: import numpy # needs numpy + sage: list_plot(numpy.arange(10)) # needs numpy Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -2910,7 +2940,7 @@ def list_plot(data, plotjoined=False, **kwargs): :: - sage: list_plot(numpy.array([[1,2], [2,3], [3,4]])) + sage: list_plot(numpy.array([[1,2], [2,3], [3,4]])) # needs numpy Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -3095,7 +3125,7 @@ def list_plot(data, plotjoined=False, **kwargs): # a tuple. # So, the only other check we need to do is whether data[0] is an # element of the Symbolic Ring. - if data[0] in sage.symbolic.ring.SR: + if isinstance(data[0], Expression): data = list(enumerate(data)) try: @@ -3137,7 +3167,7 @@ def plot_loglog(funcs, *args, **kwds): EXAMPLES:: - sage: plot_loglog(exp, (1,10)) # plot in loglog scale with base 10 + sage: plot_loglog(exp, (1,10)) # plot in loglog scale with base 10 Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -3147,12 +3177,12 @@ def plot_loglog(funcs, *args, **kwds): :: - sage: plot_loglog(exp, (1,10), base=2.1) # long time # with base 2.1 on both axes + sage: plot_loglog(exp, (1,10), base=2.1) # with base 2.1 on both axes # long time Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot_loglog(exp, (1,10), base=2.1) # long time # with base 2.1 on both axes + g = plot_loglog(exp, (1,10), base=2.1) sphinx_plot(g) :: @@ -3185,27 +3215,27 @@ def plot_semilogx(funcs, *args, **kwds): EXAMPLES:: - sage: plot_semilogx(exp, (1,10)) # long time # plot in semilogx scale, base 10 + sage: plot_semilogx(exp, (1,10)) # plot in semilogx scale, base 10 # long time Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot_semilogx(exp, (1,10)) # long time # plot in semilogx scale, base 10 + g = plot_semilogx(exp, (1,10)) sphinx_plot(g) :: - sage: plot_semilogx(exp, (1,10), base=2) # with base 2 + sage: plot_semilogx(exp, (1,10), base=2) # with base 2 Graphics object consisting of 1 graphics primitive .. PLOT:: - g = plot_semilogx(exp, (1,10), base=2) # with base 2 + g = plot_semilogx(exp, (1,10), base=2) sphinx_plot(g) :: - sage: s = var('s') # Samples points logarithmically so graph is smooth + sage: s = var('s') # Samples points logarithmically so graph is smooth sage: f = 4000000/(4000000 + 4000*s*i - s*s) sage: plot_semilogx(20*log(abs(f), 10), (s, 1, 1e6)) Graphics object consisting of 1 graphics primitive @@ -3276,31 +3306,32 @@ def list_plot_loglog(data, plotjoined=False, **kwds): EXAMPLES:: sage: yl = [5**k for k in range(10)]; xl = [2**k for k in range(10)] - sage: list_plot_loglog(list(zip(xl, yl))) # long time # plot in loglog scale with base 10 + sage: list_plot_loglog(list(zip(xl, yl))) # use loglog scale with base 10 # long time Graphics object consisting of 1 graphics primitive .. PLOT:: yl = [5**k for k in range(10)] xl = [2**k for k in range(10)] - g = list_plot_loglog(list(zip(xl, yl))) # long time # plot in loglog scale with base 10 + g = list_plot_loglog(list(zip(xl, yl))) sphinx_plot(g) :: - sage: list_plot_loglog(list(zip(xl, yl)), base=2.1) # long time # with base 2.1 on both axes + sage: list_plot_loglog(list(zip(xl, yl)), # with base 2.1 on both axes # long time + ....: base=2.1) Graphics object consisting of 1 graphics primitive .. PLOT:: yl = [5**k for k in range(10)] xl = [2**k for k in range(10)] - g = list_plot_loglog(list(zip(xl, yl)), base=2.1) # long time # with base 2.1 on both axes + g = list_plot_loglog(list(zip(xl, yl)), base=2.1) sphinx_plot(g) :: - sage: list_plot_loglog(list(zip(xl, yl)), base=(2,5)) # long time + sage: list_plot_loglog(list(zip(xl, yl)), base=(2,5)) # long time Graphics object consisting of 1 graphics primitive .. warning:: @@ -3358,7 +3389,7 @@ def list_plot_semilogx(data, plotjoined=False, **kwds): :: sage: yl = [2**k for k in range(12)] - sage: list_plot_semilogx(yl) # plot empty due to (0,1) + sage: list_plot_semilogx(yl) # plot empty due to (0,1) Graphics object consisting of 1 graphics primitive We remove `(0,1)` to fix this.:: @@ -3368,12 +3399,12 @@ def list_plot_semilogx(data, plotjoined=False, **kwds): :: - sage: list_plot_semilogx([(1,2),(3,4),(3,-1),(25,3)], base=2) # with base 2 + sage: list_plot_semilogx([(1,2),(3,4),(3,-1),(25,3)], base=2) # with base 2 Graphics object consisting of 1 graphics primitive .. PLOT:: - g = list_plot_semilogx([(1,2),(3,4),(3,-1),(25,3)], base=2) # with base 2 + g = list_plot_semilogx([(1,2),(3,4),(3,-1),(25,3)], base=2) sphinx_plot(g) """ @@ -3395,13 +3426,13 @@ def list_plot_semilogy(data, plotjoined=False, **kwds): EXAMPLES:: sage: yl = [2**k for k in range(12)] - sage: list_plot_semilogy(yl) # plot in semilogy scale, base 10 + sage: list_plot_semilogy(yl) # plot in semilogy scale, base 10 Graphics object consisting of 1 graphics primitive .. PLOT:: yl = [2**k for k in range(12)] - g = list_plot_semilogy(yl) # plot in semilogy scale, base 10 + g = list_plot_semilogy(yl) # plot in semilogy scale, base 10 sphinx_plot(g) .. warning:: @@ -3414,7 +3445,7 @@ def list_plot_semilogy(data, plotjoined=False, **kwds): :: sage: xl = [2**k for k in range(12)]; yl = range(len(xl)) - sage: list_plot_semilogy(list(zip(xl,yl))) # plot empty due to (1,0) + sage: list_plot_semilogy(list(zip(xl, yl))) # plot empty due to (1,0) doctest:warning ... Graphics object consisting of 1 graphics primitive @@ -3426,12 +3457,12 @@ def list_plot_semilogy(data, plotjoined=False, **kwds): :: - sage: list_plot_semilogy([2, 4, 6, 8, 16, 31], base=2) # with base 2 + sage: list_plot_semilogy([2, 4, 6, 8, 16, 31], base=2) # with base 2 Graphics object consisting of 1 graphics primitive .. PLOT:: - g = list_plot_semilogy([2, 4, 6, 8, 16, 31], base=2) # with base 2 + g = list_plot_semilogy([2, 4, 6, 8, 16, 31], base=2) sphinx_plot(g) """ @@ -3468,7 +3499,7 @@ def reshape(v, n, m): EXAMPLES:: - sage: L = [plot(sin(k*x),(x,-pi,pi)) for k in range(10)] + sage: L = [plot(sin(k*x), (x,-pi,pi)) for k in range(10)] sage: graphics_array(L,3,4) # long time (up to 4s on sage.math, 2012) Graphics Array of size 3 x 4 @@ -3538,17 +3569,18 @@ def graphics_array(array, nrows=None, ncols=None): Make some plots of `\sin` functions:: + sage: # long time sage: f(x) = sin(x) sage: g(x) = sin(2*x) sage: h(x) = sin(4*x) - sage: p1 = plot(f, (-2*pi,2*pi), color=hue(0.5)) # long time - sage: p2 = plot(g, (-2*pi,2*pi), color=hue(0.9)) # long time - sage: p3 = parametric_plot((f,g), (0,2*pi), color=hue(0.6)) # long time - sage: p4 = parametric_plot((f,h), (0,2*pi), color=hue(1.0)) # long time + sage: p1 = plot(f, (-2*pi,2*pi), color=hue(0.5)) + sage: p2 = plot(g, (-2*pi,2*pi), color=hue(0.9)) + sage: p3 = parametric_plot((f,g), (0,2*pi), color=hue(0.6)) + sage: p4 = parametric_plot((f,h), (0,2*pi), color=hue(1.0)) Now make a graphics array out of the plots:: - sage: graphics_array(((p1,p2), (p3,p4))) # long time + sage: graphics_array(((p1,p2), (p3,p4))) # long time Graphics Array of size 2 x 2 .. PLOT:: @@ -3556,26 +3588,25 @@ def graphics_array(array, nrows=None, ncols=None): def f(x): return sin(x) def g(x): return sin(2*x) def h(x): return sin(4*x) - p1 = plot(f, (-2*pi,2*pi), color=hue(0.5)) # long time - p2 = plot(g, (-2*pi,2*pi), color=hue(0.9)) # long time - p3 = parametric_plot((f,g), (0,2*pi), color=hue(0.6)) # long time - p4 = parametric_plot((f,h), (0,2*pi), color=hue(1.0)) # long time - g = graphics_array(((p1, p2), (p3, p4))) # long time + p1 = plot(f, (-2*pi,2*pi), color=hue(0.5)) + p2 = plot(g, (-2*pi,2*pi), color=hue(0.9)) + p3 = parametric_plot((f,g), (0,2*pi), color=hue(0.6)) + p4 = parametric_plot((f,h), (0,2*pi), color=hue(1.0)) + g = graphics_array(((p1, p2), (p3, p4))) sphinx_plot(g) One can also name the array, and then use :meth:`~sage.plot.multigraphics.MultiGraphics.show` or :meth:`~sage.plot.multigraphics.MultiGraphics.save`:: - sage: ga = graphics_array(((p1,p2), (p3,p4))) # long time + sage: ga = graphics_array(((p1,p2), (p3,p4))) # long time sage: ga.show() # long time; same output as above Here we give only one row:: - sage: p1 = plot(sin,(-4,4)) - sage: p2 = plot(cos,(-4,4)) - sage: ga = graphics_array([p1, p2]) - sage: ga + sage: p1 = plot(sin, (-4,4)) + sage: p2 = plot(cos, (-4,4)) + sage: ga = graphics_array([p1, p2]); ga Graphics Array of size 1 x 2 sage: ga.show() @@ -3832,7 +3863,12 @@ def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, sage: adaptive_refinement(sin, (0,0), (pi,0), adaptive_tolerance=0.01, adaptive_recursion=0) [] sage: adaptive_refinement(sin, (0,0), (pi,0), adaptive_tolerance=0.01) - [(0.125*pi, 0.3826834323650898), (0.1875*pi, 0.5555702330196022), (0.25*pi, 0.7071067811865475), (0.3125*pi, 0.8314696123025452), (0.375*pi, 0.9238795325112867), (0.4375*pi, 0.9807852804032304), (0.5*pi, 1.0), (0.5625*pi, 0.9807852804032304), (0.625*pi, 0.9238795325112867), (0.6875*pi, 0.8314696123025455), (0.75*pi, 0.7071067811865476), (0.8125*pi, 0.5555702330196022), (0.875*pi, 0.3826834323650899)] + [(0.125*pi, 0.3826834323650898), (0.1875*pi, 0.5555702330196022), + (0.25*pi, 0.7071067811865475), (0.3125*pi, 0.8314696123025452), + (0.375*pi, 0.9238795325112867), (0.4375*pi, 0.9807852804032304), + (0.5*pi, 1.0), (0.5625*pi, 0.9807852804032304), (0.625*pi, 0.9238795325112867), + (0.6875*pi, 0.8314696123025455), (0.75*pi, 0.7071067811865476), + (0.8125*pi, 0.5555702330196022), (0.875*pi, 0.3826834323650899)] This shows that lowering ``adaptive_tolerance`` and raising ``adaptive_recursion`` both increase the number of subdivision @@ -3867,14 +3903,14 @@ def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, try: y = float(f(x)) if str(y) in ['nan', 'NaN', 'inf', '-inf']: - sage.misc.verbose.verbose("%s\nUnable to compute f(%s)"%(msg, x),1) + sage.misc.verbose.verbose("%s\nUnable to compute f(%s)" % (msg, x),1) # give up for this branch if excluded: return [(x, 'NaN')] return [] except (ZeroDivisionError, TypeError, ValueError, OverflowError) as msg: - sage.misc.verbose.verbose("%s\nUnable to compute f(%s)"%(msg, x), 1) + sage.misc.verbose.verbose("%s\nUnable to compute f(%s)" % (msg, x), 1) # give up for this branch if excluded: return [(x, 'NaN')] diff --git a/src/sage/plot/plot3d/__init__.py b/src/sage/plot/plot3d/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 77dabadc78e..85510d0c33a 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -50,7 +50,6 @@ AUTHORS: # **************************************************************************** from cpython.list cimport * -from cpython.object cimport PyObject import os import sys @@ -842,6 +841,7 @@ cdef class Graphics3d(SageObject): EXAMPLES:: + sage: from math import pi sage: from sage.plot.plot3d.shapes import Cone sage: v = (1,2,3) sage: G = arrow3d((0, 0, 0), v) @@ -862,6 +862,7 @@ cdef class Graphics3d(SageObject): EXAMPLES:: + sage: from math import pi sage: from sage.plot.plot3d.shapes import Cone sage: G = Cone(1/5, 1) + Cone(1/5, 1, opacity=.25).rotateX(pi/2) sage: G.show(aspect_ratio=1) @@ -874,6 +875,7 @@ cdef class Graphics3d(SageObject): EXAMPLES:: + sage: from math import pi sage: from sage.plot.plot3d.shapes import Cone sage: G = Cone(1/5, 1) + Cone(1/5, 1, opacity=.25).rotateY(pi/3) sage: G.show(aspect_ratio=1) @@ -886,6 +888,7 @@ cdef class Graphics3d(SageObject): EXAMPLES:: + sage: from math import pi sage: from sage.plot.plot3d.shapes import Box sage: G = Box(1/2, 1/3, 1/5) + Box(1/2, 1/3, 1/5, opacity=.25).rotateZ(pi/5) sage: G.show(aspect_ratio=1) @@ -1762,17 +1765,17 @@ end_scene""".format( EXAMPLES: We illustrate use of the ``aspect_ratio`` option:: - sage: x, y = var('x,y') - sage: p = plot3d(2*sin(x*y), (x, -pi, pi), (y, -pi, pi)) - sage: p.show(aspect_ratio=[1,1,1]) + sage: x, y = var('x,y') # needs sage.symbolic + sage: p = plot3d(2*sin(x*y), (x, -pi, pi), (y, -pi, pi)) # needs sage.symbolic + sage: p.show(aspect_ratio=[1,1,1]) # needs sage.symbolic This looks flattened, but filled with the plot:: - sage: p.show(frame_aspect_ratio=[1,1,1/16]) + sage: p.show(frame_aspect_ratio=[1,1,1/16]) # needs sage.symbolic This looks flattened, but the plot is square and smaller:: - sage: p.show(aspect_ratio=[1,1,1], frame_aspect_ratio=[1,1,1/8]) + sage: p.show(aspect_ratio=[1,1,1], frame_aspect_ratio=[1,1,1/8]) # needs sage.symbolic This example shows indirectly that the defaults from :func:`~sage.plot.plot.plot` are dealt with properly:: @@ -1783,17 +1786,17 @@ end_scene""".format( We use the 'canvas3d' backend from inside the notebook to get a view of the plot rendered inline using HTML canvas:: - sage: p.show(viewer='canvas3d') + sage: p.show(viewer='canvas3d') # needs sage.symbolic Sometimes shadows in Tachyon-produced images can lead to confusing plots. To remove them:: - sage: p.show(viewer="tachyon", shade="medium") + sage: p.show(viewer="tachyon", shade="medium") # needs sage.symbolic One can also pass Tachyon command line flags directly. For example, the following line produces the same result as the previous one:: - sage: p.show(viewer="tachyon", extra_opts="-mediumshade") + sage: p.show(viewer="tachyon", extra_opts="-mediumshade") # needs sage.symbolic """ from sage.repl.rich_output import get_display_manager dm = get_display_manager() @@ -1987,6 +1990,7 @@ end_scene""".format( EXAMPLES:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: a = implicit_plot3d(x^2+y^2+z^2-9,[x,-5,5],[y,-5,5],[z,-5,5]) sage: astl = a.stl_binary() @@ -1999,9 +2003,9 @@ end_scene""".format( This works when faces have more then 3 sides:: - sage: P = polytopes.dodecahedron() - sage: Q = P.plot().all[-1] - sage: print(Q.stl_binary()[:40].decode('ascii')) + sage: P = polytopes.dodecahedron() # needs sage.geometry.polyhedron + sage: Q = P.plot().all[-1] # needs sage.geometry.polyhedron + sage: print(Q.stl_binary()[:40].decode('ascii')) # needs sage.geometry.polyhedron STL binary file / made by SageMath / ### """ import struct @@ -2034,6 +2038,7 @@ end_scene""".format( EXAMPLES:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: a = implicit_plot3d(x^2+y^2+z^2-9,[x,-5,5],[y,-5,5],[z,-5,5]) sage: astl = a.stl_ascii_string() @@ -2060,9 +2065,9 @@ end_scene""".format( Now works when faces have more then 3 sides:: - sage: P = polytopes.dodecahedron() - sage: Q = P.plot().all[-1] - sage: print(Q.stl_ascii_string().splitlines()[:7]) + sage: P = polytopes.dodecahedron() # needs sage.geometry.polyhedron + sage: Q = P.plot().all[-1] # needs sage.geometry.polyhedron + sage: print(Q.stl_ascii_string().splitlines()[:7]) # needs sage.geometry.polyhedron ['solid surface', 'facet normal 0.0 0.5257311121191338 0.8506508083520399', ' outer loop', @@ -2129,6 +2134,7 @@ end_scene""".format( EXAMPLES:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: a = implicit_plot3d(x^2+y^2+z^2-9,[x,-5,5],[y,-5,5],[z,-5,5]) sage: astl = a.ply_ascii_string() @@ -2203,6 +2209,7 @@ end_scene""".format( EXAMPLES:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: a = implicit_plot3d(x^2+y^2+z^2-9,[x,-5,5],[y,-5,5],[z,-5,5]) sage: a_amf = a.amf_ascii_string() @@ -2602,6 +2609,7 @@ class TransformGroup(Graphics3dGroup): EXAMPLES:: + sage: from math import pi sage: G = cube() sage: G.bounding_box() ((-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)) diff --git a/src/sage/plot/plot3d/implicit_plot3d.py b/src/sage/plot/plot3d/implicit_plot3d.py index aa05059878d..60a51a3dcbe 100644 --- a/src/sage/plot/plot3d/implicit_plot3d.py +++ b/src/sage/plot/plot3d/implicit_plot3d.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Implicit plots """ @@ -23,13 +24,13 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): marching cubes algorithm will be one less than this). Can be a triple of integers, to specify a different resolution in each of x,y,z. - - ``contour`` -- (default: 0) plot the isosurface f(x,y,z)==contour. Can be a - list, in which case multiple contours are plotted. + - ``contour`` -- (default: 0) plot the isosurface ``f(x,y,z) == contour``. + Can be a list, in which case multiple contours are plotted. - ``region`` -- (default: None) If region is given, it must be a Python - callable. Only segments of the surface where region(x,y,z) returns a - number >0 will be included in the plot. (Note that returning a Python - boolean is acceptable, since True == 1 and False == 0). + callable. Only segments of the surface where ``region(x,y,z)`` returns a + number `>0` will be included in the plot. (Note that returning a Python + boolean is acceptable, since ``True == 1`` and ``False == 0``). EXAMPLES:: @@ -50,8 +51,11 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): A nested set of spheres with a hole cut out:: - sage: implicit_plot3d((x^2 + y^2 + z^2), (x,-2,2), (y,-2,2), (z,-2,2), plot_points=60, contour=[1,3,5], - ....: region=lambda x,y,z: x<=0.2 or y>=0.2 or z<=0.2, color='aquamarine').show(viewer='tachyon') + sage: F = x^2 + y^2 + z^2 + sage: P = implicit_plot3d(F, (x,-2,2), (y,-2,2), (z,-2,2), plot_points=60, + ....: contour=[1,3,5], color='aquamarine', + ....: region=lambda x,y,z: x<=0.2 or y>=0.2 or z<=0.2) + sage: P.show(viewer='tachyon') # long time .. PLOT:: @@ -65,9 +69,11 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): <http://web.archive.org/web/20080529033738/http://iat.ubalt.edu/summers/math/platsol.htm>`_):: sage: T = RDF(golden_ratio) - sage: F = 2 - (cos(x+T*y) + cos(x-T*y) + cos(y+T*z) + cos(y-T*z) + cos(z-T*x) + cos(z+T*x)) + sage: F = 2 - (cos(x+T*y) + cos(x-T*y) + cos(y+T*z) + ....: + cos(y-T*z) + cos(z-T*x) + cos(z+T*x)) sage: r = 4.77 - sage: implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), plot_points=40, color='darkkhaki').show(viewer='tachyon') + sage: implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), + ....: plot_points=40, color='darkkhaki').show(viewer='tachyon') .. PLOT:: @@ -85,7 +91,9 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): sage: F = (x^2+9/4*y^2+z^2-1)^3 - x^2*z^3 - 9/(80)*y^2*z^3 sage: r = 1.5 - sage: implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), plot_points=80, color='red', smooth=False).show(viewer='tachyon') + sage: V = implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), + ....: plot_points=80, color='red', smooth=False) + sage: V.show(viewer='tachyon') # long time .. PLOT:: @@ -98,13 +106,16 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): The same examples also work with the default Jmol viewer; for example:: sage: T = RDF(golden_ratio) - sage: F = 2 - (cos(x + T*y) + cos(x - T*y) + cos(y + T*z) + cos(y - T*z) + cos(z - T*x) + cos(z + T*x)) + sage: F = 2 - (cos(x + T*y) + cos(x - T*y) + cos(y + T*z) + ....: + cos(y - T*z) + cos(z - T*x) + cos(z + T*x)) sage: r = 4.77 - sage: implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), plot_points=40, color='deepskyblue').show() + sage: implicit_plot3d(F, (x,-r,r), (y,-r,r), (z,-r,r), + ....: plot_points=40, color='deepskyblue').show() - Here we use smooth=True with a Tachyon graph:: + Here we use ``smooth=True`` with a Tachyon graph:: - sage: implicit_plot3d(x^2 + y^2 + z^2, (x,-2,2), (y,-2,2), (z,-2,2), contour=4, color='deepskyblue', smooth=True) + sage: implicit_plot3d(x^2 + y^2 + z^2, (x,-2,2), (y,-2,2), (z,-2,2), + ....: contour=4, color='deepskyblue', smooth=True) Graphics3d Object .. PLOT:: @@ -114,14 +125,15 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): P = implicit_plot3d(F, (x,-2,2), (y,-2,2), (z,-2,2), contour=4, color='deepskyblue', smooth=True) sphinx_plot(P) - We explicitly specify a gradient function (in conjunction with smooth=True) + We explicitly specify a gradient function (in conjunction with ``smooth=True``) and invert the normals:: sage: gx = lambda x, y, z: -(2*x + y^2 + z^2) sage: gy = lambda x, y, z: -(x^2 + 2*y + z^2) sage: gz = lambda x, y, z: -(x^2 + y^2 + 2*z) - sage: implicit_plot3d(x^2+y^2+z^2, (x,-2,2), (y,-2,2), (z,-2,2), contour=4, - ....: plot_points=40, smooth=True, gradient=(gx, gy, gz)).show(viewer='tachyon') + sage: implicit_plot3d(x^2+y^2+z^2, (x,-2,2), (y,-2,2), (z,-2,2), + ....: contour=4, plot_points=40, smooth=True, + ....: gradient=(gx, gy, gz)).show(viewer='tachyon') .. PLOT:: @@ -135,8 +147,11 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): A graph of two metaballs interacting with each other:: - sage: def metaball(x0, y0, z0): return 1 / ((x-x0)^2+(y-y0)^2+(z-z0)^2) - sage: implicit_plot3d(metaball(-0.6,0,0) + metaball(0.6,0,0), (x,-2,2), (y,-2,2), (z,-2,2), plot_points=60, contour=2, color='seagreen') + sage: def metaball(x0, y0, z0): + ....: return 1 / ((x-x0)^2+(y-y0)^2+(z-z0)^2) + sage: implicit_plot3d(metaball(-0.6,0,0) + metaball(0.6,0,0), + ....: (x,-2,2), (y,-2,2), (z,-2,2), + ....: plot_points=60, contour=2, color='seagreen') Graphics3d Object .. PLOT:: @@ -148,13 +163,13 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) One can also color the surface using a coloring function and a colormap as follows. Note that the coloring function must take - values in the interval [0,1]. :: + values in the interval `[0,1]`. :: sage: t = (sin(3*z)**2).function(x,y,z) sage: cm = colormaps.gist_rainbow sage: G = implicit_plot3d(x^2 + y^2 + z^2, (x,-2,2), (y,-2,2), (z,-2, 2), ....: contour=4, color=(t,cm), plot_points=100) - sage: G.show(viewer='tachyon') + sage: G.show(viewer='tachyon') # long time .. PLOT:: @@ -170,8 +185,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) sage: x, y, z = var('x,y,z') sage: t = (x).function(x,y,z) sage: cm = colormaps.PiYG - sage: G = implicit_plot3d(x^4 + y^2 + z^2, (x,-2,2), - ....: (y,-2,2),(z,-2,2), contour=4, color=(t,cm), plot_points=40) + sage: G = implicit_plot3d(x^4 + y^2 + z^2, (x,-2,2), (y,-2,2),(z,-2,2), + ....: contour=4, color=(t,cm), plot_points=40) sage: G Graphics3d Object @@ -188,7 +203,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A kind of saddle:: - sage: implicit_plot3d(x^3 + y^2 - z^2, (x,-2,2), (y,-2,2), (z,-2,2), plot_points=60, contour=0, color='lightcoral') + sage: implicit_plot3d(x^3 + y^2 - z^2, (x,-2,2), (y,-2,2), (z,-2,2), + ....: plot_points=60, contour=0, color='lightcoral') Graphics3d Object .. PLOT:: @@ -199,7 +215,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A smooth surface with six radial openings:: - sage: implicit_plot3d(-(cos(x) + cos(y) + cos(z)), (x,-4,4), (y,-4,4), (z,-4,4), color='orchid') + sage: implicit_plot3d(-(cos(x) + cos(y) + cos(z)), + ....: (x,-4,4), (y,-4,4), (z,-4,4), color='orchid') Graphics3d Object .. PLOT:: @@ -264,7 +281,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Drope:: - sage: implicit_plot3d(z - 4*x*exp(-x^2-y^2), (x,-2,2), (y,-2,2), (z,-1.7,1.7), color='darkcyan') + sage: implicit_plot3d(z - 4*x*exp(-x^2-y^2), (x,-2,2), (y,-2,2), (z,-1.7,1.7), + ....: color='darkcyan') Graphics3d Object .. PLOT:: @@ -288,7 +306,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A simple hyperbolic surface:: - sage: implicit_plot3d(x^2 + y - z^2, (x,-1,1), (y,-1,1), (z,-1,1), color='darkslategray') + sage: implicit_plot3d(x^2 + y - z^2, (x,-1,1), (y,-1,1), (z,-1,1), + ....: color='darkslategray') Graphics3d Object .. PLOT:: @@ -299,7 +318,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A hyperboloid:: - sage: implicit_plot3d(x^2 + y^2 - z^2 -0.3, (x,-2,2), (y,-2,2), (z,-1.8,1.8), color='honeydew') + sage: implicit_plot3d(x^2 + y^2 - z^2 -0.3, (x,-2,2), (y,-2,2), (z,-1.8,1.8), + ....: color='honeydew') Graphics3d Object .. PLOT:: @@ -310,7 +330,7 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Dupin cyclide (:wikipedia:`Dupin_cyclide`) :: - sage: x, y, z , a, b, c, d = var('x,y,z,a,b,c,d') + sage: x, y, z, a, b, c, d = var('x,y,z,a,b,c,d') sage: a = 3.5 sage: b = 3 sage: c = sqrt(a^2 - b^2) @@ -332,7 +352,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Sinus:: - sage: implicit_plot3d(sin(pi*((x)^2+(y)^2))/2 + z, (x,-1,1), (y,-1,1), (z,-1,1), color='rosybrown') + sage: implicit_plot3d(sin(pi*((x)^2+(y)^2))/2 + z, (x,-1,1), (y,-1,1), (z,-1,1), + ....: color='rosybrown') Graphics3d Object .. PLOT:: @@ -343,7 +364,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A torus:: - sage: implicit_plot3d((sqrt(x*x+y*y)-3)^2 + z*z - 1, (x,-4,4), (y,-4,4), (z,-1,1), color='indigo') + sage: implicit_plot3d((sqrt(x*x+y*y)-3)^2 + z*z - 1, (x,-4,4), (y,-4,4), (z,-1,1), + ....: color='indigo') Graphics3d Object .. PLOT:: @@ -354,7 +376,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) An octahedron:: - sage: implicit_plot3d(abs(x) + abs(y) + abs(z) - 1, (x,-1,1), (y,-1,1), (z,-1,1), color='olive') + sage: implicit_plot3d(abs(x) + abs(y) + abs(z) - 1, (x,-1,1), (y,-1,1), (z,-1,1), + ....: color='olive') Graphics3d Object .. PLOT:: @@ -365,7 +388,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A cube:: - sage: implicit_plot3d(x^100 + y^100 + z^100 - 1, (x,-2,2), (y,-2,2), (z,-2,2), color='lightseagreen') + sage: implicit_plot3d(x^100 + y^100 + z^100 - 1, (x,-2,2), (y,-2,2), (z,-2,2), + ....: color='lightseagreen') Graphics3d Object .. PLOT:: @@ -376,7 +400,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Toupie:: - sage: implicit_plot3d((sqrt(x*x+y*y)-3)^3 + z*z - 1, (x,-4,4), (y,-4,4), (z,-6,6), color='mintcream') + sage: implicit_plot3d((sqrt(x*x+y*y)-3)^3 + z*z - 1, (x,-4,4), (y,-4,4), (z,-6,6), + ....: color='mintcream') Graphics3d Object .. PLOT:: @@ -401,7 +426,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Chmutov:: sage: F = x^4 + y^4 + z^4 - (x^2 + y^2 + z^2 - 0.3) - sage: implicit_plot3d(F, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1.5,1.5), color='lightskyblue') + sage: implicit_plot3d(F, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1.5,1.5), + ....: color='lightskyblue') Graphics3d Object .. PLOT:: @@ -414,7 +440,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Further Chmutov:: sage: F = 2*(x^2*(3-4*x^2)^2+y^2*(3-4*y^2)^2+z^2*(3-4*z^2)^2) - 3 - sage: implicit_plot3d(F, (x,-1.3,1.3), (y,-1.3,1.3), (z,-1.3,1.3), color='darksalmon') + sage: implicit_plot3d(F, (x,-1.3,1.3), (y,-1.3,1.3), (z,-1.3,1.3), + ....: color='darksalmon') Graphics3d Object .. PLOT:: @@ -451,7 +478,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Looks like a water droplet:: - sage: implicit_plot3d(x^2 +y^2 -(1-z)*z^2, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1,1), color='bisque') + sage: implicit_plot3d(x^2 + y^2 - (1-z)*z^2, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1,1), + ....: color='bisque') Graphics3d Object .. PLOT:: @@ -463,7 +491,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Sphere in a cage:: sage: F = (x^8+z^30+y^8-(x^4 + z^50 + y^4 -0.3)) * (x^2+y^2+z^2-0.5) - sage: implicit_plot3d(F, (x,-1.2,1.2), (y,-1.3,1.3), (z,-1.5,1.5), color='firebrick') + sage: implicit_plot3d(F, (x,-1.2,1.2), (y,-1.3,1.3), (z,-1.5,1.5), + ....: color='firebrick') Graphics3d Object .. PLOT:: @@ -475,8 +504,10 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Ortho circle:: - sage: F = ((x^2+y^2-1)^2+z^2) * ((y^2+z^2-1)^2+x^2) * ((z^2+x^2-1)^2+y^2)-0.075^2 * (1+3*(x^2+y^2+z^2)) - sage: implicit_plot3d(F, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1.5,1.5), color='lemonchiffon') + sage: F = (((x^2+y^2-1)^2+z^2) * ((y^2+z^2-1)^2+x^2) * ((z^2+x^2-1)^2+y^2) + ....: - 0.075^2 * (1+3*(x^2+y^2+z^2))) + sage: implicit_plot3d(F, (x,-1.5,1.5), (y,-1.5,1.5), (z,-1.5,1.5), + ....: color='lemonchiffon') Graphics3d Object .. PLOT:: @@ -501,7 +532,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Two cylinders intersect to make a cross:: - sage: implicit_plot3d((x^2+y^2-1) * (x^2+z^2-1) - 1, (x,-3,3), (y,-3,3), (z,-3,3), color='burlywood') + sage: implicit_plot3d((x^2+y^2-1) * (x^2+z^2-1) - 1, (x,-3,3), (y,-3,3), (z,-3,3), + ....: color='burlywood') Graphics3d Object .. PLOT:: @@ -512,7 +544,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Three cylinders intersect in a similar fashion:: - sage: implicit_plot3d((x^2+y^2-1) * (x^2+z^2-1) * (y^2+z^2-1)-1, (x,-3,3), (y,-3,3), (z,-3,3), color='aqua') + sage: implicit_plot3d((x^2+y^2-1) * (x^2+z^2-1) * (y^2+z^2-1) - 1, + ....: (x,-3,3), (y,-3,3), (z,-3,3), color='aqua') Graphics3d Object .. PLOT:: @@ -523,7 +556,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A sphere-ish object with twelve holes, four on each XYZ plane:: - sage: implicit_plot3d(3*(cos(x)+cos(y)+cos(z)) + 4*cos(x)*cos(y)*cos(z), (x,-3,3), (y,-3,3), (z,-3,3), color='orangered') + sage: implicit_plot3d(3*(cos(x)+cos(y)+cos(z)) + 4*cos(x)*cos(y)*cos(z), + ....: (x,-3,3), (y,-3,3), (z,-3,3), color='orangered') Graphics3d Object .. PLOT:: @@ -534,7 +568,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) A gyroid:: - sage: implicit_plot3d(cos(x)*sin(y) + cos(y)*sin(z) + cos(z)*sin(x), (x,-4,4), (y,-4,4), (z,-4,4), color='sandybrown') + sage: implicit_plot3d(cos(x)*sin(y) + cos(y)*sin(z) + cos(z)*sin(x), + ....: (x,-4,4), (y,-4,4), (z,-4,4), color='sandybrown') Graphics3d Object .. PLOT:: @@ -545,7 +580,8 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) Tetrahedra:: - sage: implicit_plot3d((x^2+y^2+z^2)^2 + 8*x*y*z - 10*(x^2+y^2+z^2) + 25, (x,-4,4), (y,-4,4), (z,-4,4), color='plum') + sage: implicit_plot3d((x^2+y^2+z^2)^2 + 8*x*y*z - 10*(x^2+y^2+z^2) + 25, + ....: (x,-4,4), (y,-4,4), (z,-4,4), color='plum') Graphics3d Object .. PLOT:: diff --git a/src/sage/plot/plot3d/implicit_surface.pyx b/src/sage/plot/plot3d/implicit_surface.pyx index 1726f8f95a5..db8a3f226f3 100644 --- a/src/sage/plot/plot3d/implicit_surface.pyx +++ b/src/sage/plot/plot3d/implicit_surface.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic r""" Graphics 3D object for representing and triangulating isosurfaces @@ -81,8 +82,6 @@ cimport numpy as np import numpy as np from sage.plot.plot3d.transform cimport point_c, face_c, color_c, Transformation -from sage.plot.plot3d.base cimport PrimitiveObject -from sage.plot.plot3d.base import RenderParams, default_texture from sage.plot.plot3d.index_face_set cimport IndexFaceSet from sage.rings.real_double import RDF from sage.plot.misc import setup_for_eval_on_grid @@ -495,8 +494,8 @@ cdef class MarchingCubesTriangles(MarchingCubes): cdef bint has_nan cdef point_c gradients[2] cdef int i - for y from 0 <= y < ny - 1: - for z from 0 <= z < nz: + for y in range(ny - 1): + for z in range(nz): if marching_has_edge(cur[y,z], cur[y+1,z], self.contour, &frac, &has_nan): v = mk_VertexInfo(x, y+frac, z, &self.eval_min, &self.eval_scale) if self.region is not None: @@ -509,7 +508,7 @@ cdef class MarchingCubesTriangles(MarchingCubes): self.apply_point_func(&v.gradient, self.gradient, v) else: # Use central differencing. - for i from 0 <= i < 2: + for i in range(2): self.get_gradient(&gradients[i], x, y+i, z, cur[y+i,z], @@ -529,8 +528,8 @@ cdef class MarchingCubesTriangles(MarchingCubes): # OK, that updated the Y vertices. Now we do almost exactly # the same thing to update Z vertices. - for y from 0 <= y < ny: - for z from 0 <= z < nz - 1: + for y in range(ny): + for z in range(nz - 1): if marching_has_edge(cur[y,z], cur[y,z+1], self.contour, &frac, &has_nan): v = mk_VertexInfo(x, y, z+frac, &self.eval_min, &self.eval_scale) if self.region is not None: @@ -543,7 +542,7 @@ cdef class MarchingCubesTriangles(MarchingCubes): self.apply_point_func(&v.gradient, self.gradient, v) else: # Use central differencing. - for i from 0 <= i < 2: + for i in range(2): self.get_gradient(&gradients[i], x, y, z+i, cur[y,z+i], @@ -596,8 +595,8 @@ cdef class MarchingCubesTriangles(MarchingCubes): cdef double frac cdef bint has_nan cdef point_c gradients[2] - for y from 0 <= y < ny: - for z from 0 <= z < nz: + for y in range(ny): + for z in range(nz): if marching_has_edge(left[y,z], right[y,z], self.contour, &frac, &has_nan): v = mk_VertexInfo(x+frac, y, z, &self.eval_min, &self.eval_scale) if self.region is not None: @@ -746,8 +745,8 @@ cdef class MarchingCubesTriangles(MarchingCubes): cdef int i - for y from 0 <= y < ny-1: - for z from 0 <= z < nz-1: + for y in range(ny - 1): + for z in range(nz - 1): # For each vertex (0 to 7), set the corresponding bit # of insideMask iff the vertex is inside the surface. insideMask = 0 @@ -910,13 +909,13 @@ cpdef render_implicit(f, xrange, yrange, zrange, plot_points, cube_marchers): cdef MarchingCubes marcher - for n from 0 <= n < nx: + for n in range(nx): x = nx-1-n eval_x = eval_min.x + eval_scale.x * x slice = data[n % 4, :, :] - for y from 0 <= y < ny: + for y in range(ny): eval_y = eval_min.y + eval_scale.y * y - for z from 0 <= z < nz: + for z in range(nz): eval_z = eval_min.z + eval_scale.z * z slice[y, z] = f(eval_x, eval_y, eval_z) @@ -1219,7 +1218,7 @@ cdef class ImplicitSurface(IndexFaceSet): int fcount = len(results) self.realloc(fcount * 3, fcount, fcount * 3) - for i from 0 <= i < fcount: + for i in range(fcount): dest_face = &self._faces[i] src_face = results[i] @@ -1235,7 +1234,7 @@ cdef class ImplicitSurface(IndexFaceSet): # ct is the mean of the colors of vertices dest_face.color.r, dest_face.color.g, dest_face.color.b = ct - for j from 0 <= j < 3: + for j in range(3): dest_face.vertices[j] = (3 * i) + j dest_vertex = &self.vs[(3 * i) + j] dest_vertex.x = src_face[j]['x'] diff --git a/src/sage/plot/plot3d/index_face_set.pyx b/src/sage/plot/plot3d/index_face_set.pyx index 642397e9ecf..3968db3ab51 100644 --- a/src/sage/plot/plot3d/index_face_set.pyx +++ b/src/sage/plot/plot3d/index_face_set.pyx @@ -32,9 +32,8 @@ AUTHORS: # **************************************************************************** from textwrap import dedent -from sage.misc.superseded import deprecation_cython as deprecation -from libc.math cimport isfinite, INFINITY +from libc.math cimport INFINITY from libc.string cimport memset, memcpy from cysignals.memory cimport check_calloc, check_allocarray, check_reallocarray, sig_free from cysignals.signals cimport sig_check, sig_on, sig_off @@ -53,15 +52,10 @@ from cpython.bytes cimport * include "point_c.pxi" - -from math import sin, cos, sqrt -from random import randint - from sage.cpython.string cimport bytes_to_str from sage.rings.real_double import RDF -from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector from sage.plot.colors import Color, float_to_integer @@ -184,7 +178,7 @@ cdef inline format_pmesh_face(face_c face, int has_color): # Naive triangulation all = [] if has_color == 1: - for i from 1 <= i < face.n - 1: + for i in range(1, face.n - 1): r = sprintf_5i(ss, "%d\n%d\n%d\n%d\n%d", has_color * 4, face.vertices[0], face.vertices[i], @@ -192,7 +186,7 @@ cdef inline format_pmesh_face(face_c face, int has_color): face.vertices[0]) PyList_Append(all, PyBytes_FromStringAndSize(ss, r)) else: - for i from 1 <= i < face.n - 1: + for i in range(1, face.n - 1): r = sprintf_6i(ss, "%d\n%d\n%d\n%d\n%d\n%d", has_color * 4, face.vertices[0], face.vertices[i], @@ -254,7 +248,8 @@ def cut_edge_by_bisection(pointa, pointb, condition, eps=1.0e-6, N=100): EXAMPLES:: sage: from sage.plot.plot3d.index_face_set import cut_edge_by_bisection - sage: cut_edge_by_bisection((0.0,0.0,0.0),(1.0,1.0,0.0),( (lambda x,y,z: x**2+y**2+z**2<1) ),eps=1.0E-12) + sage: cut_edge_by_bisection((0.0,0.0,0.0), (1.0,1.0,0.0), + ....: lambda x,y,z: x**2+y**2+z**2 < 1, eps=1.0E-12) (0.7071067811864395, 0.7071067811864395, 0.0) """ cdef point_c a, b @@ -284,7 +279,7 @@ def cut_edge_by_bisection(pointa, pointb, condition, eps=1.0e-6, N=100): point_c_middle(&midp, b, a, half) - return midp.x, midp.y, midp.z + return midp.x, midp.y, midp.z cdef class IndexFaceSet(PrimitiveObject): @@ -308,9 +303,10 @@ cdef class IndexFaceSet(PrimitiveObject): EXAMPLES:: sage: from sage.plot.plot3d.index_face_set import IndexFaceSet - sage: S = IndexFaceSet([[(1,0,0),(0,1,0),(0,0,1)],[(1,0,0),(0,1,0),(0,0,0)]]) + sage: S = IndexFaceSet([[(1,0,0),(0,1,0),(0,0,1)], [(1,0,0),(0,1,0),(0,0,0)]]) sage: S.face_list() - [[(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)], [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 0.0)]] + [[(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 0.0)]] sage: S.vertex_list() [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0), (0.0, 0.0, 0.0)] @@ -323,13 +319,13 @@ cdef class IndexFaceSet(PrimitiveObject): sage: S = IndexFaceSet(face_list, point_list, color='red') sage: S.face_list() [[(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 0.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 2.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 3.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 4.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 5.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 6.0)], - [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 7.0)]] + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 2.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 3.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 4.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 5.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 6.0)], + [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 7.0)]] sage: S.show() A simple example of colored IndexFaceSet (:trac:`12212`):: @@ -375,16 +371,16 @@ cdef class IndexFaceSet(PrimitiveObject): cdef Py_ssize_t i cdef Py_ssize_t index_len = 0 - for i from 0 <= i < len(faces): + for i in range(len(faces)): index_len += len(faces[i]) self.realloc(len(point_list), len(faces), index_len) - for i from 0 <= i < self.vcount: + for i in range(self.vcount): self.vs[i].x, self.vs[i].y, self.vs[i].z = point_list[i] cdef int cur_pt = 0 - for i from 0 <= i < self.fcount: + for i in range(self.fcount): self._faces[i].n = len(faces[i]) self._faces[i].vertices = &self.face_indices[cur_pt] if self.global_texture: @@ -402,15 +398,18 @@ cdef class IndexFaceSet(PrimitiveObject): EXAMPLES:: + sage: # needs sage.symbolic sage: var('x,y,z') (x, y, z) - sage: G = implicit_plot3d(x^2+y^2+z^2 - 1, (x, -2, 2), (y, -2, 2), (z, -2, 2), plot_points=6) + sage: G = implicit_plot3d(x^2+y^2+z^2 - 1, + ....: (x, -2, 2), (y, -2, 2), (z, -2, 2), plot_points=6) sage: G.triangulate() # indirect doctest sage: len(G.face_list()) 44 sage: len(G.vertex_list()) 132 - sage: G = implicit_plot3d(x^2+y^2+z^2 - 100, (x, -2, 2), (y, -2, 2), (z, -2, 2), plot_points=6) + sage: G = implicit_plot3d(x^2+y^2+z^2 - 100, + ....: (x, -2, 2), (y, -2, 2), (z, -2, 2), plot_points=6) sage: G.triangulate() # indirect doctest sage: len(G.face_list()) 0 @@ -523,15 +522,15 @@ cdef class IndexFaceSet(PrimitiveObject): cdef int* point_counts = <int *>check_calloc(self.vcount * 2 + 1, sizeof(int)) # For each vertex, get number of faces cdef int* running_point_counts = &point_counts[self.vcount] - for i from 0 <= i < self.fcount: + for i in range(self.fcount): face = &self._faces[i] total += face.n - for j from 0 <= j < face.n: + for j in range(face.n): point_counts[face.vertices[j]] += 1 # Running used as index into face list cdef int running = 0 cdef int max = 0 - for i from 0 <= i < self.vcount: + for i in range(self.vcount): running_point_counts[i] = running running += point_counts[i] if point_counts[i] > max: @@ -546,9 +545,9 @@ cdef class IndexFaceSet(PrimitiveObject): raise sig_on() memset(point_counts, 0, sizeof(int) * self.vcount) - for i from 0 <= i < self.fcount: + for i in range(self.fcount): face = &self._faces[i] - for j from 0 <= j < face.n: + for j in range(face.n): v = face.vertices[j] point_faces[running_point_counts[v]+point_counts[v]] = face point_counts[v] += 1 @@ -563,7 +562,7 @@ cdef class IndexFaceSet(PrimitiveObject): while start < self.vcount: ix = self.vcount # Find creases - for i from 0 <= i < self.vcount - start: + for i in range(self.vcount - start): faces = &point_faces[running_point_counts[i]] any = 0 for j from point_counts[i] > j >= 1: @@ -588,17 +587,17 @@ cdef class IndexFaceSet(PrimitiveObject): raise ix = self.vcount running = 0 - for i from 0 <= i < self.vcount - start: + for i in range(self.vcount - start): if point_counts[i] != running_point_counts[i+1] - running_point_counts[i]: # We have a new vertex self.vs[ix] = self.vs[i+start] # Update the point_counts and point_faces arrays for the next time around. count = running_point_counts[i+1] - running_point_counts[i] - point_counts[i] faces = &point_faces[running] - for j from 0 <= j < count: + for j in range(count): faces[j] = point_faces[running_point_counts[i] + point_counts[i] + j] face = faces[j] - for k from 0 <= k < face.n: + for k in range(face.n): if face.vertices[k] == i + start: face.vertices[k] = ix point_counts[ix-self.vcount] = count @@ -659,8 +658,8 @@ cdef class IndexFaceSet(PrimitiveObject): """ cdef Py_ssize_t i, j return [[self._faces[i].vertices[j] - for j from 0 <= j < self._faces[i].n] - for i from 0 <= i < self.fcount] + for j in range(self._faces[i].n)] + for i in range(self.fcount)] def has_local_colors(self): """ @@ -704,13 +703,13 @@ cdef class IndexFaceSet(PrimitiveObject): sage: point_list = [(2,0,0),(0,2,0),(0,0,2),(0,1,1),(1,0,1),(1,1,0)] sage: face_list = [[0,4,5],[3,4,5],[2,3,4],[1,3,5]] sage: col = rainbow(10, 'rgbtuple') - sage: t_list=[Texture(col[i]) for i in range(10)] + sage: t_list = [Texture(col[i]) for i in range(10)] sage: S = IndexFaceSet(face_list, point_list, texture_list=t_list) sage: S.index_faces_with_colors() [([0, 4, 5], '#ff0000'), - ([3, 4, 5], '#ff9900'), - ([2, 3, 4], '#cbff00'), - ([1, 3, 5], '#33ff00')] + ([3, 4, 5], '#ff9900'), + ([2, 3, 4], '#cbff00'), + ([1, 3, 5], '#33ff00')] When the texture is global, an error is raised:: @@ -725,11 +724,11 @@ cdef class IndexFaceSet(PrimitiveObject): if self.global_texture: raise ValueError('the texture is global') return [([self._faces[i].vertices[j] - for j from 0 <= j < self._faces[i].n], + for j in range(self._faces[i].n)], Color(self._faces[i].color.r, self._faces[i].color.g, self._faces[i].color.b).html_color()) - for i from 0 <= i < self.fcount] + for i in range(self.fcount)] def faces(self): """ @@ -853,7 +852,7 @@ cdef class IndexFaceSet(PrimitiveObject): sage: point_list = [(2,0,0),(0,2,0),(0,0,2),(0,1,1),(1,0,1),(1,1,0)] sage: face_list = [[0,4,5],[3,4,5],[2,3,4],[1,3,5]] sage: col = rainbow(10, 'rgbtuple') - sage: t_list=[Texture(col[i]) for i in range(10)] + sage: t_list = [Texture(col[i]) for i in range(10)] sage: S = IndexFaceSet(face_list, point_list, texture_list=t_list) sage: print(S.x3d_geometry()) <BLANKLINE> @@ -902,9 +901,9 @@ cdef class IndexFaceSet(PrimitiveObject): EXAMPLES:: - sage: x,y = var('x,y') - sage: p = plot3d(sqrt(sin(x)*sin(y)), (x,0,2*pi),(y,0,2*pi)) - sage: p.bounding_box() + sage: x,y = var('x,y') # needs sage.symbolic + sage: p = plot3d(sqrt(sin(x)*sin(y)), (x,0,2*pi), (y,0,2*pi)) # needs sage.symbolic + sage: p.bounding_box() # needs sage.symbolic ((0.0, 0.0, 0.0), (6.283185307179586, 6.283185307179586, 0.9991889981715697)) """ if self.vcount == 0: @@ -937,7 +936,7 @@ cdef class IndexFaceSet(PrimitiveObject): sage: from sage.plot.plot3d.shapes import * sage: S = Box(1,2,3) - sage: len(S.partition(lambda x,y,z : floor(x+y+z))) + sage: len(S.partition(lambda x,y,z: floor(x+y+z))) 6 """ cdef Py_ssize_t i, j, ix, face_ix @@ -950,10 +949,10 @@ cdef class IndexFaceSet(PrimitiveObject): cdef int *partition = <int *>check_allocarray(self.fcount, sizeof(int)) part_counts = {} - for i from 0 <= i < self.fcount: + for i in range(self.fcount): face = &self._faces[i] P = self.vs[face.vertices[0]] - for j from 1 <= j < face.n: + for j in range(1, face.n): point_c_add(&P, P, self.vs[face.vertices[j]]) point_c_mul(&P, P, 1.0/face.n) partition[i] = part = f(P.x, P.y, P.z) @@ -970,13 +969,13 @@ cdef class IndexFaceSet(PrimitiveObject): memcpy(face_set.vs, self.vs, sizeof(point_c) * self.vcount) face_ix = 0 ix = 0 - for i from 0 <= i < self.fcount: + for i in range(self.fcount): if partition[i] == part: face = &self._faces[i] new_face = &face_set._faces[face_ix] new_face.n = face.n new_face.vertices = &face_set.face_indices[ix] - for j from 0 <= j < face.n: + for j in range(face.n): new_face.vertices[j] = face.vertices[j] face_ix += 1 ix += face.n @@ -1012,12 +1011,12 @@ cdef class IndexFaceSet(PrimitiveObject): EXAMPLES:: - sage: var('x,y,z') + sage: var('x,y,z') # needs sage.symbolic (x, y, z) - sage: P = implicit_plot3d(z-x*y,(-2,2),(-2,2),(-2,2)) + sage: P = implicit_plot3d(z-x*y,(-2,2),(-2,2),(-2,2)) # needs sage.symbolic sage: def condi(x,y,z): ....: return bool(x*x+y*y+z*z <= Integer(1)) - sage: R = P.add_condition(condi,20);R + sage: R = P.add_condition(condi, 20); R # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -1034,8 +1033,9 @@ cdef class IndexFaceSet(PrimitiveObject): ....: return bool(x*x+y*y <= 1.1) sage: cm = colormaps.hsv sage: cf = lambda x,y,z: float(x+y) % 1 - sage: P = implicit_plot3d(x**2+y**2+z**2-1-x**2*z+y**2*z,(-2,2),(-2,2),(-2,2),color=(cm,cf)) - sage: R = P.add_condition(condi,40); R + sage: P = implicit_plot3d(x**2+y**2+z**2-1-x**2*z+y**2*z, # needs sage.symbolic + ....: (-2,2),(-2,2),(-2,2),color=(cm,cf)) + sage: R = P.add_condition(condi,40); R # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -1050,10 +1050,11 @@ cdef class IndexFaceSet(PrimitiveObject): An example with transparency:: - sage: P = implicit_plot3d(x**4+y**4+z**2-4,(x,-2,2),(y,-2,2),(z,-2,2),alpha=0.3) + sage: P = implicit_plot3d(x**4+y**4+z**2-4, (x,-2,2), (y,-2,2), (z,-2,2), # needs sage.symbolic + ....: alpha=0.3) sage: def cut(a,b,c): ....: return a*a+c*c > 2 - sage: Q = P.add_condition(cut,40); Q + sage: Q = P.add_condition(cut,40); Q # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -1066,11 +1067,11 @@ cdef class IndexFaceSet(PrimitiveObject): A sombrero with quadrilaterals:: - sage: P = plot3d(-sin(2*x*x+2*y*y)*exp(-x*x-y*y),(x,-2,2),(y,-2,2), - ....: color='gold') + sage: P = plot3d(-sin(2*x*x+2*y*y)*exp(-x*x-y*y), (x,-2,2), (y,-2,2), # needs sage.symbolic + ....: color='gold') sage: def cut(x,y,z): ....: return x*x+y*y < 1 - sage: Q = P.add_condition(cut);Q + sage: Q = P.add_condition(cut);Q # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -1085,6 +1086,7 @@ cdef class IndexFaceSet(PrimitiveObject): One test for preservation of transparency :trac:`28783`:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: P = plot3d(cos(x*y),(x,-2,2),(y,-2,2),color='red',opacity=0.1) sage: def condi(x,y,z): @@ -1099,7 +1101,7 @@ cdef class IndexFaceSet(PrimitiveObject): sage: p = polygon3d([[2,0,0], [0,2,0], [0,0,3]]) sage: def f(x,y,z): ....: return bool(x*x+y*y+z*z<=5) - sage: cut = p.add_condition(f,60,1.0e-12); cut.face_list() + sage: cut = p.add_condition(f,60,1.0e-12); cut.face_list() # needs sage.symbolic [[(0.556128491210302, 0.0, 2.165807263184547), (2.0, 0.0, 0.0), (0.0, 2.0, 0.0), @@ -1220,7 +1222,7 @@ cdef class IndexFaceSet(PrimitiveObject): sage: point_list = [(2,0,0),(0,2,0),(0,0,2),(0,1,1),(1,0,1),(1,1,0)] sage: face_list = [[0,4,5],[3,4,5],[2,3,4],[1,3,5]] sage: col = rainbow(10, 'rgbtuple') - sage: t_list=[Texture(col[i]) for i in range(10)] + sage: t_list = [Texture(col[i]) for i in range(10)] sage: S = IndexFaceSet(face_list, point_list, texture_list=t_list) sage: S.tachyon_repr(S.default_render_params()) ['TRI V0 2 0 0 V1 1 0 1 V2 1 1 0', @@ -1232,7 +1234,7 @@ cdef class IndexFaceSet(PrimitiveObject): cdef face_c face cdef Py_ssize_t i, k sig_on() - for i from 0 <= i < self.fcount: + for i in range(self.fcount): face = self._faces[i] if transform is not None: transform.transform_point_c(&P, self.vs[face.vertices[0]]) @@ -1248,7 +1250,7 @@ cdef class IndexFaceSet(PrimitiveObject): else: PyList_Append(lines, format_tachyon_texture(face.color)) if face.n > 3: - for k from 3 <= k < face.n: + for k in range(3, face.n): Q = R if transform is not None: transform.transform_point_c(&R, self.vs[face.vertices[k]]) @@ -1296,7 +1298,7 @@ cdef class IndexFaceSet(PrimitiveObject): for i in range(self.vcount))) else: vertices_str = "[" - for i from 0 <= i < self.vcount: + for i in range(self.vcount): transform.transform_point_c(&res, self.vs[i]) if i > 0: vertices_str += "," @@ -1414,7 +1416,7 @@ cdef class IndexFaceSet(PrimitiveObject): vertices = [] cdef Transformation transform = render_params.transform cdef point_c res - for i from 0 <= i < self.vcount: + for i in range(self.vcount): if transform is None: res = self.vs[i] else: @@ -1424,16 +1426,16 @@ cdef class IndexFaceSet(PrimitiveObject): faces = [] cdef face_c face - for i from 0 <= i < self.fcount: + for i in range(self.fcount): face = self._faces[i] - faces.append([int(face.vertices[j]) for j from 0 <= j < face.n]) + faces.append([int(face.vertices[j]) for j in range(face.n)]) surface['faces'] = faces if self.global_texture: surface['color'] = '#' + str(self.texture.hex_rgb()) else: face_colors = [] - for i from 0 <= i < self.fcount: + for i in range(self.fcount): face = self._faces[i] color = Color(face.color.r, face.color.g, face.color.b) face_colors.append(str(color.html_color())) @@ -1478,16 +1480,16 @@ cdef class IndexFaceSet(PrimitiveObject): sig_on() if transform is None: - points = [format_obj_vertex(self.vs[i]) for i from 0 <= i < self.vcount] + points = [format_obj_vertex(self.vs[i]) for i in range(self.vcount)] else: points = [] - for i from 0 <= i < self.vcount: + for i in range(self.vcount): transform.transform_point_c(&res, self.vs[i]) PyList_Append(points, format_obj_vertex(res)) - faces = [format_obj_face(self._faces[i], off) for i from 0 <= i < self.fcount] + faces = [format_obj_face(self._faces[i], off) for i in range(self.fcount)] if not self.enclosed: - back_faces = [format_obj_face_back(self._faces[i], off) for i from 0 <= i < self.fcount] + back_faces = [format_obj_face_back(self._faces[i], off) for i in range(self.fcount)] else: back_faces = [] @@ -1519,25 +1521,25 @@ cdef class IndexFaceSet(PrimitiveObject): sig_on() if transform is None: points = [format_pmesh_vertex(self.vs[i]) - for i from 0 <= i < self.vcount] + for i in range(self.vcount)] else: points = [] - for i from 0 <= i < self.vcount: + for i in range(self.vcount): transform.transform_point_c(&res, self.vs[i]) PyList_Append(points, format_pmesh_vertex(res)) # activation of coloring in jmol if self.global_texture: faces = [format_pmesh_face(self._faces[i], 1) - for i from 0 <= i < self.fcount] + for i in range(self.fcount)] else: faces = [format_pmesh_face(self._faces[i], -1) - for i from 0 <= i < self.fcount] + for i in range(self.fcount)] # If a face has more than 4 vertices, it gets chopped up in # format_pmesh_face cdef Py_ssize_t extra_faces = 0 - for i from 0 <= i < self.fcount: + for i in range(self.fcount): if self._faces[i].n >= 5: extra_faces += self._faces[i].n-3 @@ -1637,9 +1639,7 @@ cdef class IndexFaceSet(PrimitiveObject): sage: T = S.dual() sage: len(T.vertex_list()) 6 - """ - cdef point_c P cdef face_c *face cdef Py_ssize_t i, j, ix, ff cdef IndexFaceSet dual = IndexFaceSet([], **kwds) @@ -1649,14 +1649,14 @@ cdef class IndexFaceSet(PrimitiveObject): dual.realloc(self.fcount, self.vcount, self.icount) # is using dicts overly-heavy? - dual_faces = [{} for i from 0 <= i < self.vcount] + dual_faces = [{} for i in range(self.vcount)] - for i from 0 <= i < self.fcount: + for i in range(self.fcount): sig_check() # Let the vertex be centered on the face according to a simple average face = &self._faces[i] dual.vs[i] = self.vs[face.vertices[0]] - for j from 1 <= j < face.n: + for j in range(1, face.n): point_c_add(&dual.vs[i], dual.vs[i], self.vs[face.vertices[j]]) point_c_mul(&dual.vs[i], dual.vs[i], 1.0/face.n) @@ -1684,7 +1684,7 @@ cdef class IndexFaceSet(PrimitiveObject): face.vertices = &dual.face_indices[ix] ff, next_ = next(iter(dd.itervalues())) face.vertices[0] = ff - for j from 1 <= j < face.n: + for j in range(1, face.n): ff, next_ = dd[next_] face.vertices[j] = ff i += 1 @@ -1722,14 +1722,13 @@ cdef class IndexFaceSet(PrimitiveObject): sage: S = B.stickers(['red','yellow','blue'], 0.1, 0.05) sage: S.show() sage: (S+B).show() - """ all = [] n = self.fcount ct = len(colors) for k in range(len(colors)): if colors[k]: - all.append(self.sticker(list(xrange(k, n, ct)), width, hover, + all.append(self.sticker(list(range(k, n, ct)), width, hover, texture=colors[k])) return Graphics3dGroup(all) @@ -1772,7 +1771,7 @@ cdef class FaceIter: raise StopIteration else: face = [] - for j from 0 <= j < self.set._faces[self.i].n: + for j in range(self.set._faces[self.i].n): P = self.set.vs[self.set._faces[self.i].vertices[j]] PyList_Append(face, (P.x, P.y, P.z)) self.i += 1 diff --git a/src/sage/plot/plot3d/list_plot3d.py b/src/sage/plot/plot3d/list_plot3d.py index d64b766001e..b8e4ddffce6 100644 --- a/src/sage/plot/plot3d/list_plot3d.py +++ b/src/sage/plot/plot3d/list_plot3d.py @@ -72,8 +72,9 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): We plot a matrix of values of ``sin``:: - sage: pi = float(pi) - sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) + sage: from math import pi + sage: m = matrix(RDF, 6, [sin(i^2 + j^2) + ....: for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) sage: list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object @@ -85,9 +86,10 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): sphinx_plot(list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3])) Though it does not change the shape of the graph, increasing - num_points can increase the clarity of the graph:: + ``num_points`` can increase the clarity of the graph:: - sage: list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3], num_points=40) + sage: list_plot3d(m, color='yellow', num_points=40, + ....: frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object .. PLOT:: @@ -101,7 +103,8 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): sage: import warnings sage: warnings.simplefilter('ignore', UserWarning) - sage: list_plot3d(m, color='yellow', interpolation_type='clough', frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='clough', + ....: frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object .. PLOT:: @@ -115,7 +118,8 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): We can make this look better by increasing the number of samples:: - sage: list_plot3d(m, color='yellow', interpolation_type='clough', frame_aspect_ratio=[1, 1, 1/3], num_points=40) + sage: list_plot3d(m, color='yellow', interpolation_type='clough', + ....: frame_aspect_ratio=[1, 1, 1/3], num_points=40) Graphics3d Object .. PLOT:: @@ -127,7 +131,8 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): Let us try a spline:: - sage: list_plot3d(m, color='yellow', interpolation_type='spline', frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='spline', + ....: frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object .. PLOT:: @@ -140,7 +145,8 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): That spline does not capture the oscillation very well; let's try a higher degree spline:: - sage: list_plot3d(m, color='yellow', interpolation_type='spline', degree=5, frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='spline', degree=5, + ....: frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object .. PLOT:: @@ -185,8 +191,11 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): sage: l = [] sage: for i in range(-5, 5): ....: for j in range(-5, 5): - ....: l.append((normalvariate(0, 1), normalvariate(0, 1), normalvariate(0, 1))) - sage: L = list_plot3d(l, interpolation_type='clough', color='orange', num_points=100) + ....: l.append((normalvariate(0, 1), + ....: normalvariate(0, 1), + ....: normalvariate(0, 1))) + sage: L = list_plot3d(l, interpolation_type='clough', + ....: color='orange', num_points=100) sage: L Graphics3d Object @@ -308,7 +317,8 @@ def list_plot3d_matrix(m, **kwds): We plot a matrix that illustrates summation modulo `n`:: sage: n = 5 - sage: list_plot3d(matrix(RDF, n, [(i+j)%n for i in [1..n] for j in [1..n]])) # indirect doctest + sage: list_plot3d(matrix(RDF, n, [(i+j) % n # indirect doctest + ....: for i in [1..n] for j in [1..n]])) Graphics3d Object .. PLOT:: @@ -320,9 +330,10 @@ def list_plot3d_matrix(m, **kwds): We plot a matrix of values of `sin`:: - sage: pi = float(pi) - sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) - sage: list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3]) # indirect doctest + sage: from math import pi + sage: m = matrix(RDF, 6, [sin(i^2 + j^2) + ....: for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) + sage: list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3]) # indirect doctest Graphics3d Object .. PLOT:: @@ -333,7 +344,7 @@ def list_plot3d_matrix(m, **kwds): sphinx_plot(list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3])) :: - sage: list_plot3d(m, color='yellow', interpolation_type='linear') # indirect doctest + sage: list_plot3d(m, color='yellow', interpolation_type='linear') # indirect doctest Graphics3d Object .. PLOT:: @@ -350,7 +361,7 @@ def list_plot3d_matrix(m, **kwds): sage: n = 20 sage: cf = lambda x, y: ((2*(x-y)/n)**2) % 1 sage: list_plot3d(matrix(RDF, n, [cos(pi*(i+j)/n) for i in [1..n] - ....: for j in [1..n]]), color=(cf,cm)) + ....: for j in [1..n]]), color=(cf,cm)) Graphics3d Object .. PLOT:: @@ -412,7 +423,8 @@ def list_plot3d_array_of_arrays(v, interpolation_type, **kwds): With certain extra keywords (see :func:`list_plot3d_matrix`), this function will end up using :func:`list_plot3d_tuples`:: - sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]], interpolation_type='spline')) + sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]], + ....: interpolation_type='spline')) .. PLOT:: @@ -431,14 +443,14 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): INPUT: - - ``v`` - something that defines a set of points in 3 + - ``v`` -- something that defines a set of points in 3 space, for example: - a matrix - This will be if using an interpolation type other than - 'linear', or if using ``num_points`` with 'linear'; otherwise - see :func:`list_plot3d_matrix`. + This will be if using an ``interpolation_type`` other than + ``'linear'``, or if using ``num_points`` with ``'linear'``; + otherwise see :func:`list_plot3d_matrix`. - a list of 3-tuples @@ -447,33 +459,34 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): OPTIONAL KEYWORDS: - - ``interpolation_type`` - 'linear', 'clough' (CloughTocher2D), 'spline' + - ``interpolation_type`` -- one of ``'linear'``, ``'clough'`` + (CloughTocher2D), ``'spline'`` - 'linear' will perform linear interpolation + ``'linear'`` will perform linear interpolation The option 'clough' will interpolate by using a piecewise cubic interpolating Bezier polynomial on each triangle, using a Clough-Tocher scheme. The interpolant is guaranteed to be continuously differentiable. - The option 'spline' interpolates using a bivariate B-spline. + The option ``'spline'`` interpolates using a bivariate B-spline. - When v is a matrix the default is to use linear interpolation, when - v is a list of points the default is 'clough'. + When ``v`` is a matrix the default is to use linear interpolation, when + ``v`` is a list of points the default is ``'clough'``. - - ``degree`` - an integer between 1 and 5, controls the degree of spline + - ``degree`` -- an integer between 1 and 5, controls the degree of spline used for spline interpolation. For data that is highly oscillatory use higher values - - ``point_list`` - If point_list=True is passed, then if the array + - ``point_list`` -- If ``point_list=True`` is passed, then if the array is a list of lists of length three, it will be treated as an array of points rather than a `3\times n` array. - - ``num_points`` - Number of points to sample interpolating + - ``num_points`` -- Number of points to sample interpolating function in each direction. By default for an `n\times n` array this is `n`. - - ``**kwds`` - all other arguments are passed to the + - ``**kwds`` -- all other arguments are passed to the surface function OUTPUT: a 3d plot @@ -483,9 +496,11 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): All of these use this function; see :func:`list_plot3d` for other list plots:: - sage: pi = float(pi) - sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) - sage: list_plot3d(m, color='yellow', interpolation_type='linear', num_points=5) # indirect doctest + sage: from math import pi + sage: m = matrix(RDF, 6, [sin(i^2 + j^2) + ....: for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) + sage: list_plot3d(m, color='yellow', interpolation_type='linear', # indirect doctest + ....: num_points=5) Graphics3d Object .. PLOT:: @@ -497,7 +512,8 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): :: - sage: list_plot3d(m, color='yellow', interpolation_type='spline', frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='spline', + ....: frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object .. PLOT:: @@ -509,7 +525,8 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): :: - sage: show(list_plot3d([[1, 1, 1], [1, 2, 1], [0, 1, 3], [1, 0, 4]], point_list=True)) + sage: show(list_plot3d([[1, 1, 1], [1, 2, 1], [0, 1, 3], [1, 0, 4]], + ....: point_list=True)) .. PLOT:: @@ -517,7 +534,8 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): :: - sage: list_plot3d([(1, 2, 3), (0, 1, 3), (2, 1, 4), (1, 0, -2)], color='yellow', num_points=50) # long time + sage: list_plot3d([(1, 2, 3), (0, 1, 3), (2, 1, 4), (1, 0, -2)], # long time + ....: color='yellow', num_points=50) Graphics3d Object .. PLOT:: @@ -602,7 +620,7 @@ def g(x, y): from .parametric_surface import ParametricSurface def g(x, y): - z = f([x, y]) + z = f([x, y]).item() return (x, y, z) G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points * j]), list(numpy.r_[ymin:ymax:num_points * j])), diff --git a/src/sage/plot/plot3d/parametric_plot3d.py b/src/sage/plot/plot3d/parametric_plot3d.py index e16df517fb8..afb2d6fa129 100644 --- a/src/sage/plot/plot3d/parametric_plot3d.py +++ b/src/sage/plot/plot3d/parametric_plot3d.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic """ Parametric plots """ @@ -415,8 +415,12 @@ def g(x,y): return x, y+sin(y), x**2 + y**2 sage: f_x = K * (cos(u)*cos(2*v)+sqrt(2)*sin(u)*cos(v)) sage: f_y = K * (cos(u)*sin(2*v)-sqrt(2)*sin(u)*sin(v)) sage: f_z = 3 * K * cos(u) - sage: parametric_plot3d([f_x, f_y, f_z], (u,-2*pi,2*pi), (v,0,pi), - ....: plot_points=[90,90], frame=False, color="orange") # long time -- about 30 seconds + sage: parametric_plot3d([f_x, f_y, f_z], # long time + ....: (u,-2*pi,2*pi), + ....: (v,0,pi), + ....: plot_points=[90,90], + ....: frame=False, + ....: color="orange") Graphics3d Object .. PLOT:: diff --git a/src/sage/plot/plot3d/parametric_surface.pxd b/src/sage/plot/plot3d/parametric_surface.pxd index 9f5affa0cae..47265921622 100644 --- a/src/sage/plot/plot3d/parametric_surface.pxd +++ b/src/sage/plot/plot3d/parametric_surface.pxd @@ -8,4 +8,3 @@ cdef class ParametricSurface(IndexFaceSet): cdef object colormap cdef int eval_grid(self, urange, vrange) except -1 cdef int eval_c(self, point_c *res, double u, double v) except -1 - diff --git a/src/sage/plot/plot3d/parametric_surface.pyx b/src/sage/plot/plot3d/parametric_surface.pyx index 68b388b587e..11676df7dfe 100644 --- a/src/sage/plot/plot3d/parametric_surface.pyx +++ b/src/sage/plot/plot3d/parametric_surface.pyx @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic r""" Parametric surface @@ -468,7 +468,8 @@ cdef class ParametricSurface(IndexFaceSet): sage: from sage.plot.plot3d.parametric_surface import MoebiusStrip sage: M = MoebiusStrip(7,3,2) sage: M.bounding_box() - ((-10.0, -7.53907349250478..., -2.9940801852848145), (10.0, 7.53907349250478..., 2.9940801852848145)) + ((-10.0, -7.53907349250478..., -2.9940801852848145), + (10.0, 7.53907349250478..., 2.9940801852848145)) """ # We must triangulate before computing the bounding box; otherwise # we'll get an empty bounding box, as the bounding box is computed @@ -493,7 +494,7 @@ cdef class ParametricSurface(IndexFaceSet): sage: def f(x,y): return x+y, sin(x)*sin(y), x*y # indirect doctests sage: P = ParametricSurface(f, (srange(0,10,0.1), srange(-5,5.0,0.1))) # indirect doctests sage: P.show() # indirect doctests - sage: S = MoebiusStrip(1,.2) # indirect doctests + sage: S = MoebiusStrip(1, .2) # indirect doctests sage: S.show() # indirect doctests """ cdef double u, v @@ -710,9 +711,9 @@ cdef class ParametricSurface(IndexFaceSet): res = self.vs if fast_y: # must be Wrapper_rdf - for i from 0 <= i < m: + for i in range(m): uv[0] = ulist[i] - for j from 0 <= j < n: + for j in range(n): sig_check() uv[1] = vlist[j] (<Wrapper_rdf>fy).call_c(uv, &res.y) diff --git a/src/sage/plot/plot3d/platonic.py b/src/sage/plot/plot3d/platonic.py index eee95d3290f..be590739c3e 100644 --- a/src/sage/plot/plot3d/platonic.py +++ b/src/sage/plot/plot3d/platonic.py @@ -226,13 +226,14 @@ def tetrahedron(center=(0, 0, 0), size=1, **kwds): A Dodecahedral complex of 5 tetrahedra (a more elaborate example from Peter Jipsen):: - sage: v=(sqrt(5.)/2-5/6, 5/6*sqrt(3.)-sqrt(15.)/2, sqrt(5.)/3) - sage: t=acos(sqrt(5.)/3)/2 - sage: t1=tetrahedron(aspect_ratio=(1,1,1), opacity=0.5).rotateZ(t) - sage: t2=tetrahedron(color='red', opacity=0.5).rotateZ(t).rotate(v,2*pi/5) - sage: t3=tetrahedron(color='green', opacity=0.5).rotateZ(t).rotate(v,4*pi/5) - sage: t4=tetrahedron(color='yellow', opacity=0.5).rotateZ(t).rotate(v,6*pi/5) - sage: t5=tetrahedron(color='orange', opacity=0.5).rotateZ(t).rotate(v,8*pi/5) + sage: from math import pi + sage: v = (sqrt(5.)/2-5/6, 5/6*sqrt(3.)-sqrt(15.)/2, sqrt(5.)/3) + sage: t = acos(sqrt(5.)/3)/2 + sage: t1 = tetrahedron(aspect_ratio=(1,1,1), opacity=0.5).rotateZ(t) + sage: t2 = tetrahedron(color='red', opacity=0.5).rotateZ(t).rotate(v,2*pi/5) + sage: t3 = tetrahedron(color='green', opacity=0.5).rotateZ(t).rotate(v,4*pi/5) + sage: t4 = tetrahedron(color='yellow', opacity=0.5).rotateZ(t).rotate(v,6*pi/5) + sage: t5 = tetrahedron(color='orange', opacity=0.5).rotateZ(t).rotate(v,8*pi/5) sage: show(t1+t2+t3+t4+t5, frame=False, zoom=1.3) .. PLOT:: diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index 174765980f7..5687c6f9c8c 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -1,10 +1,12 @@ +# sage.doctest: needs sage.symbolic r""" Plotting functions EXAMPLES:: sage: x, y = var('x y') - sage: W = plot3d(sin(pi*((x)^2 + (y)^2))/2, (x, -1, 1), (y, -1, 1), frame=False, color='purple', opacity=0.8) + sage: W = plot3d(sin(pi*((x)^2 + (y)^2))/2, (x, -1, 1), (y, -1, 1), + ....: frame=False, color='purple', opacity=0.8) sage: S = sphere((0, 0, 0), size=0.3, color='red', aspect_ratio=[1,1,1]) sage: show(W + S, figsize=8) @@ -30,7 +32,8 @@ sage: def f(x,y): ....: return math.sin(y^2 + x^2)/math.sqrt(x^2 + y^2 + 0.0001) - sage: P = plot3d(f, (-3, 3),(-3, 3), adaptive=True, color=rainbow(60, 'rgbtuple'), max_bend=.1, max_depth=15) + sage: P = plot3d(f, (-3, 3),(-3, 3), adaptive=True, + ....: color=rainbow(60, 'rgbtuple'), max_bend=.1, max_depth=15) sage: P.show() .. ONLY:: html @@ -121,11 +124,14 @@ def c(x, y): return float((x + y + x*y)/15) % 1 :: - sage: S += sphere((.45, -.1, .15), size=.1, color='white') + sphere((.51,-.1,.17), size=.05, color='black') - sage: S += sphere((.45, .1, .15), size=.1, color='white') + sphere((.51, .1,.17), size=.05, color='black') + sage: S += sphere((.45, -.1, .15), size=.1, color='white') + sage: S += sphere((.51,-.1,.17), size=.05, color='black') + sage: S += sphere((.45, .1, .15), size=.1, color='white') + sage: S += sphere((.51, .1,.17), size=.05, color='black') sage: S += sphere((.5, 0, -.2), size=.1, color='yellow') sage: def f(x,y): return math.exp(x/5)*math.cos(y) - sage: P = plot3d(f, (-5, 5), (-5, 5), adaptive=True, color=['red','yellow'], max_depth=10) + sage: P = plot3d(f, (-5, 5), (-5, 5), adaptive=True, + ....: color=['red','yellow'], max_depth=10) sage: cape_man = P.scale(.2) + S.translate(1, 0, 0) sage: cape_man.show(aspect_ratio=[1, 1, 1]) @@ -248,7 +254,7 @@ def __init__(self, dep_var, indep_vars): Because the base :class:`_Coordinates` class automatically checks the initializing variables with the transform method, :class:`_Coordinates` - cannot be instantiated by itself. We test a subclass. + cannot be instantiated by itself. We test a subclass:: sage: from sage.plot.plot3d.plot3d import _ArbitraryCoordinates as arb sage: x,y,z=var('x,y,z') @@ -257,7 +263,7 @@ def __init__(self, dep_var, indep_vars): """ all_vars = sage_getargspec(self.transform).args[1:] if set(all_vars) != set(indep_vars + [dep_var]): - raise ValueError('variables were specified incorrectly for this coordinate system; incorrect variables were %s'%list(set(all_vars).symmetric_difference(set(indep_vars+[dep_var])))) + raise ValueError('variables were specified incorrectly for this coordinate system; incorrect variables were %s' % list(set(all_vars).symmetric_difference(set(indep_vars+[dep_var])))) self.dep_var = dep_var self.indep_vars = indep_vars @@ -378,7 +384,7 @@ def to_cartesian(self, func, params=None): ....: [ 0.16763356, 0.19993708, 0.31403568, 0.47359696, 0.55282422], ....: [ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422]]) sage: import scipy.interpolate - sage: f=scipy.interpolate.RectBivariateSpline(v_phi,v_theta,m_r) + sage: f=scipy.interpolate.RectBivariateSpline(v_phi,v_theta,m_r).ev sage: spherical_plot3d(f,(0,2*pi),(0,pi)) Graphics3d Object @@ -703,7 +709,8 @@ class SphericalElevation(_Coordinates): Plot a sin curve wrapped around the equator:: - sage: P1 = plot3d( (pi/12)*sin(8*theta), (r,0.99,1), (theta, 0, 2*pi), transformation=SE, plot_points=(10,200)) + sage: P1 = plot3d((pi/12)*sin(8*theta), (r,0.99,1), (theta, 0, 2*pi), + ....: transformation=SE, plot_points=(10,200)) sage: P2 = sphere(center=(0,0,0), size=1, color='red', opacity=0.3) sage: P1 + P2 Graphics3d Object @@ -736,10 +743,14 @@ class SphericalElevation(_Coordinates): sage: r, phi, theta = var('r phi theta') sage: SE = SphericalElevation('elevation', ['radius', 'azimuth']) sage: angles = [pi/18, pi/12, pi/6] - sage: P1 = [plot3d( a, (r,0,3), (theta, 0, 2*pi), transformation=SE, opacity=0.85, color='blue') for a in angles] + sage: P1 = [plot3d(a, (r,0,3), (theta, 0, 2*pi), transformation=SE, + ....: opacity=0.85, color='blue') + ....: for a in angles] sage: S = Spherical('inclination', ['radius', 'azimuth']) - sage: P2 = [plot3d( a, (r,0,3), (theta, 0, 2*pi), transformation=S, opacity=0.85, color='red') for a in angles] + sage: P2 = [plot3d(a, (r,0,3), (theta, 0, 2*pi), transformation=S, + ....: opacity=0.85, color='red') + ....: for a in angles] sage: show(sum(P1+P2), aspect_ratio=1) .. ONLY:: html @@ -886,7 +897,7 @@ class TrivialTriangleFactory: but simply returning a list of vertices for both regular and smooth triangles. """ - def triangle(self, a, b, c, color = None): + def triangle(self, a, b, c, color=None): """ Function emulating behavior of :meth:`~sage.plot.plot3d.tri_plot.TriangleFactory.triangle` @@ -911,8 +922,9 @@ def triangle(self, a, b, c, color = None): sage: tri [[0, 0, 0], [0, 0, 1], [1, 1, 0]] """ - return [a,b,c] - def smooth_triangle(self, a, b, c, da, db, dc, color = None): + return [a, b, c] + + def smooth_triangle(self, a, b, c, da, db, dc, color=None): """ Function emulating behavior of :meth:`~sage.plot.plot3d.tri_plot.TriangleFactory.smooth_triangle` @@ -941,6 +953,7 @@ def smooth_triangle(self, a, b, c, da, db, dc, color = None): """ return [a,b,c] + from . import parametric_plot3d def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): """ @@ -1083,7 +1096,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): sage: var('x,y') (x, y) - sage: plot3d(sin(x^2 + y^2),(x,-5,5),(y,-5,5), plot_points=200) + sage: plot3d(sin(x^2 + y^2), (x,-5,5), (y,-5,5), plot_points=200) Graphics3d Object .. ONLY:: html @@ -1151,8 +1164,10 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): Two wobby translucent planes:: sage: x,y = var('x,y') - sage: P = plot3d(x + y + sin(x*y), (x, -10, 10), (y, -10, 10), opacity=0.87, color='blue') - sage: Q = plot3d(x - 2*y - cos(x*y),(x, -10, 10), (y, -10, 10), opacity=0.3, color='red') + sage: P = plot3d(x + y + sin(x*y), (x, -10, 10), (y, -10, 10), + ....: opacity=0.87, color='blue') + sage: Q = plot3d(x - 2*y - cos(x*y),(x, -10, 10), (y, -10, 10), + ....: opacity=0.3, color='red') sage: P + Q Graphics3d Object @@ -1357,11 +1372,11 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense if isinstance(transformation, (tuple, list,Vector_callable_symbolic_dense)): - if len(transformation)==3: + if len(transformation) == 3: if params is None: raise ValueError("must specify independent variable names in the ranges when using generic transformation") indep_vars = params - elif len(transformation)==4: + elif len(transformation) == 4: indep_vars = transformation[3] transformation = transformation[0:3] else: @@ -1369,8 +1384,8 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): # find out which variable is the function variable by # eliminating the parameter variables. all_vars = set(sum([list(s.variables()) for s in transformation],[])) - dep_var=all_vars - set(indep_vars) - if len(dep_var)==1: + dep_var = all_vars - set(indep_vars) + if len(dep_var) == 1: dep_var = dep_var.pop() transformation = _ArbitraryCoordinates(transformation, dep_var, indep_vars) else: @@ -1476,9 +1491,9 @@ def plot3d_adaptive(f, x_range, y_range, color="automatic", texture = Texture(kwds) factory = TrivialTriangleFactory() - plot = TrianglePlot(factory, g, (xmin, xmax), (ymin, ymax), g = grad_f, + plot = TrianglePlot(factory, g, (xmin, xmax), (ymin, ymax), g=grad_f, min_depth=initial_depth, max_depth=max_depth, - max_bend=max_bend, num_colors = None) + max_bend=max_bend, num_colors=None) P = IndexFaceSet(plot._objects) if isinstance(texture, (list, tuple)): diff --git a/src/sage/plot/plot3d/plot_field3d.py b/src/sage/plot/plot3d/plot_field3d.py index bdf39391d3e..d93d95cba57 100644 --- a/src/sage/plot/plot3d/plot_field3d.py +++ b/src/sage/plot/plot3d/plot_field3d.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Plotting 3D fields """ @@ -29,32 +30,33 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, INPUT: - - ``functions`` - a list of three functions, representing the x-, + - ``functions`` -- a list of three functions, representing the x-, y-, and z-coordinates of a vector - - ``xrange``, ``yrange``, and ``zrange`` - three tuples of the + - ``xrange``, ``yrange``, and ``zrange`` -- three tuples of the form (var, start, stop), giving the variables and ranges for each axis - - ``plot_points`` (default 5) - either a number or list of three + - ``plot_points`` -- (default 5) either a number or list of three numbers, specifying how many points to plot for each axis - - ``colors`` (default 'jet') - a color, list of colors (which are + - ``colors`` -- (default ``'jet'``) a color, list of colors (which are interpolated between), or matplotlib colormap name, giving the coloring of the arrows. If a list of colors or a colormap is given, coloring is done as a function of length of the vector - - ``center_arrows`` (default False) - If True, draw the arrows + - ``center_arrows`` -- (default ``False``) If ``True``, draw the arrows centered on the points; otherwise, draw the arrows with the tail at the point - - any other keywords are passed on to the plot command for each arrow + - any other keywords are passed on to the :func:`plot` command for each arrow EXAMPLES: A 3d vector field:: - sage: x,y,z=var('x y z') - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi)) + sage: x,y,z = var('x y z') + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi)) Graphics3d Object .. PLOT:: @@ -64,7 +66,9 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, same example with only a list of colors:: - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),colors=['red','green','blue']) + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi), + ....: colors=['red','green','blue']) Graphics3d Object .. PLOT:: @@ -74,7 +78,8 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, same example with only one color:: - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),colors='red') + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi), colors='red') Graphics3d Object .. PLOT:: @@ -84,7 +89,8 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, same example with the same plot points for the three axes:: - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),plot_points=4) + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi), plot_points=4) Graphics3d Object .. PLOT:: @@ -94,7 +100,8 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, same example with different number of plot points for each axis:: - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),plot_points=[3,5,7]) + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi), plot_points=[3,5,7]) Graphics3d Object .. PLOT:: @@ -104,7 +111,8 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, same example with the arrows centered on the points:: - sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),center_arrows=True) + sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)), + ....: (x,0,pi), (y,0,pi), (z,0,pi), center_arrows=True) Graphics3d Object .. PLOT:: @@ -126,9 +134,9 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, vectors = [vector((ff(*point), gg(*point), hh(*point))) for point in points] try: - from matplotlib.cm import get_cmap - cm = get_cmap(colors) - except (TypeError, ValueError): + import matplotlib as mpl + cm = mpl.colormaps[colors] + except (TypeError, KeyError): cm = None if cm is None: if isinstance(colors, (list, tuple)): diff --git a/src/sage/plot/plot3d/point_c.pxi b/src/sage/plot/plot3d/point_c.pxi index c2763154fc8..aa6699d368e 100644 --- a/src/sage/plot/plot3d/point_c.pxi +++ b/src/sage/plot/plot3d/point_c.pxi @@ -145,4 +145,3 @@ cdef inline double sin_face_angle(face_c F, face_c E, point_c* vlist): face_c_normal(&nE, E, vlist) cdef double dot = point_c_dot(nF, nE) return math.sqrt(1-(dot*dot)/(point_c_dot(nF, nF)*point_c_dot(nE, nE))) - diff --git a/src/sage/plot/plot3d/revolution_plot3d.py b/src/sage/plot/plot3d/revolution_plot3d.py index 7c570b985f3..b140c463c29 100644 --- a/src/sage/plot/plot3d/revolution_plot3d.py +++ b/src/sage/plot/plot3d/revolution_plot3d.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.plot """ Surfaces of revolution @@ -39,25 +40,25 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr INPUT: - - ``curve`` - A curve to be revolved, specified as a function, a 2-tuple or a 3-tuple. + - ``curve`` -- A curve to be revolved, specified as a function, a 2-tuple or a 3-tuple. - - ``trange`` - A 3-tuple `(t,t_{\min},t_{\max})` where t is the independent variable of the curve. + - ``trange`` -- A 3-tuple `(t,t_{\min},t_{\max})` where t is the independent variable of the curve. - - ``phirange`` - A 2-tuple of the form `(\phi_{\min},\phi_{\max})`, (default `(0,\pi)`) that specifies the angle in which the curve is to be revolved. + - ``phirange`` -- A 2-tuple of the form `(\phi_{\min},\phi_{\max})`, (default `(0,\pi)`) that specifies the angle in which the curve is to be revolved. - - ``parallel_axis`` - A string (Either 'x', 'y', or 'z') that specifies the coordinate axis parallel to the revolution axis. + - ``parallel_axis`` -- A string (one of ``'x'``, ``'y'``, ``'z'``) that specifies the coordinate axis parallel to the revolution axis. - - ``axis`` - A 2-tuple that specifies the position of the revolution axis. If parallel is: + - ``axis`` -- A 2-tuple that specifies the position of the revolution axis. If ``parallel_axis`` is: - - 'z' - then axis is the point in which the revolution axis intersects the `x y` plane. + - ``'z'`` -- then ``axis`` is the point in which the revolution axis intersects the `x` `y` plane. - - 'x' - then axis is the point in which the revolution axis intersects the `y z` plane. + - ``'x'`` -- then ``axis`` is the point in which the revolution axis intersects the `y` `z` plane. - - 'y' - then axis is the point in which the revolution axis intersects the `x z` plane. + - ``'y'`` -- then ``axis`` is the point in which the revolution axis intersects the `x` `z` plane. - - ``print_vector`` - If True, the parametrization of the surface of revolution will be printed. + - ``print_vector`` -- If ``True``, the parametrization of the surface of revolution will be printed. - - ``show_curve`` - If True, the curve will be displayed. + - ``show_curve`` -- If ``True``, the curve will be displayed. EXAMPLES: @@ -66,7 +67,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr sage: u = var('u') sage: f = u^2 - sage: revolution_plot3d(f, (u,0,2), show_curve=True, opacity=0.7).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(f, (u,0,2), + ....: show_curve=True, opacity=0.7).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -77,7 +79,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr If we move slightly the axis, we get a goblet-like surface:: - sage: revolution_plot3d(f, (u,0,2), axis=(1,0.2), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(f, (u,0,2), axis=(1,0.2), + ....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -90,9 +93,11 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr sage: line = u sage: parabola = u^2 - sage: sur1 = revolution_plot3d(line, (u,0,1), opacity=0.5, rgbcolor=(1,0.5,0), show_curve=True, parallel_axis='x') - sage: sur2 = revolution_plot3d(parabola, (u,0,1), opacity=0.5, rgbcolor=(0,1,0), show_curve=True, parallel_axis='x') - sage: (sur1+sur2).show() + sage: sur1 = revolution_plot3d(line, (u,0,1), opacity=0.5, rgbcolor=(1,0.5,0), + ....: show_curve=True, parallel_axis='x') + sage: sur2 = revolution_plot3d(parabola, (u,0,1), opacity=0.5, rgbcolor=(0,1,0), + ....: show_curve=True, parallel_axis='x') + sage: (sur1 + sur2).show() .. PLOT:: @@ -109,7 +114,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr sage: u = var('u') sage: circle = (cos(u), sin(u)) - sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,0), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,0), + ....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -120,7 +126,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr An axis on `(0,y)` will produce a cylinder-like surface:: - sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,2), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,2), + ....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -131,7 +138,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr And any other axis will produce a torus-like surface:: - sage: revolution_plot3d(circle, (u,0,2*pi), axis=(2,0), show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(circle, (u,0,2*pi), axis=(2,0), + ....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -144,7 +152,8 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr sage: u = var('u') sage: curve = (u, cos(4*u), u^2) - sage: P = revolution_plot3d(curve, (u,0,2), show_curve=True, parallel_axis='z',axis=(1,.2), opacity=0.5) + sage: P = revolution_plot3d(curve, (u,0,2), parallel_axis='z', axis=(1,.2), + ....: show_curve=True, opacity=0.5) sage: P.show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -158,7 +167,9 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr sage: u = var('u') sage: curve = (sin(3*u), .8*cos(4*u), cos(u)) - sage: revolution_plot3d(curve, (u,0,pi), (0,pi/2), show_curve=True, parallel_axis='z', opacity=0.5).show(aspect_ratio=(1,1,1),frame=False) + sage: revolution_plot3d(curve, (u,0,pi), (0,pi/2), parallel_axis='z', + ....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1), + ....: frame=False) .. PLOT:: @@ -169,12 +180,13 @@ def revolution_plot3d(curve,trange,phirange=None,parallel_axis='z',axis=(0,0),pr One can also color the surface using a coloring function of two parameters and a colormap as follows. Note that the coloring - function must take values in the interval [0,1]. :: + function must take values in the interval `[0,1]`. :: sage: u, phi = var('u,phi') sage: def cf(u,phi): return sin(phi+u) ^ 2 sage: curve = (1+u^2/4, 0, u) - sage: revolution_plot3d(curve, (u,-2,2), (0,2*pi), parallel_axis='z', color=(cf, colormaps.PiYG)).show(aspect_ratio=(1,1,1)) + sage: revolution_plot3d(curve, (u,-2,2), (0,2*pi), parallel_axis='z', + ....: color=(cf, colormaps.PiYG)).show(aspect_ratio=(1,1,1)) .. PLOT:: @@ -192,8 +204,8 @@ def cf(u, phi): return sin(phi+u) ** 2 sage: u, phi = var('u,phi') sage: def cf(u, phi): return float(2 * u / pi) % 1 sage: curve = (sin(u), 0, u) - sage: revolution_plot3d(curve, (u,0,pi), (0,2*pi), parallel_axis - ....: ='z', color=(colormaps.brg, cf)).show(aspect_ratio=1) + sage: revolution_plot3d(curve, (u,0,pi), (0,2*pi), parallel_axis='z', + ....: color=(colormaps.brg, cf)).show(aspect_ratio=1) .. PLOT:: diff --git a/src/sage/plot/plot3d/shapes.pyx b/src/sage/plot/plot3d/shapes.pyx index 340f034c235..f5c98fe3929 100644 --- a/src/sage/plot/plot3d/shapes.pyx +++ b/src/sage/plot/plot3d/shapes.pyx @@ -12,8 +12,10 @@ EXAMPLES:: sage: from sage.plot.plot3d.shapes import * sage: S = Sphere(.5, color='yellow') sage: S += Cone(.5, .5, color='red').translate(0,0,.3) - sage: S += Sphere(.1, color='white').translate(.45,-.1,.15) + Sphere(.05, color='black').translate(.51,-.1,.17) - sage: S += Sphere(.1, color='white').translate(.45, .1,.15) + Sphere(.05, color='black').translate(.51, .1,.17) + sage: S += Sphere(.1, color='white').translate(.45,-.1,.15) + sage: S += Sphere(.05, color='black').translate(.51,-.1,.17) + sage: S += Sphere(.1, color='white').translate(.45, .1,.15) + sage: S += Sphere(.05, color='black').translate(.51, .1,.17) sage: S += Sphere(.1, color='yellow').translate(.5, 0, -.2) sage: S.show() sage: S.scale(1,1,2).show() @@ -50,11 +52,11 @@ EXAMPLES:: # https://www.gnu.org/licenses/ # **************************************************************************** -from libc.math cimport sqrt, sin, cos, tan, asin, acos, atan, M_PI +from libc.math cimport sqrt, sin, cos, acos, M_PI from sage.rings.real_double import RDF from sage.modules.free_module_element import vector from sage.misc.decorators import rename_keyword -from .base import Graphics3dGroup, Graphics3d +from .base import Graphics3dGroup from .index_face_set cimport IndexFaceSet, PrimitiveObject from .transform cimport point_c @@ -78,7 +80,7 @@ def validate_frame_size(size): Traceback (most recent call last): ... ValueError: each box dimension must be nonnegative - sage: validate_frame_size([sqrt(-1),3,2]) + sage: validate_frame_size([sqrt(-1),3,2]) # needs sage.symbolic Traceback (most recent call last): ... TypeError: each box dimension must coerce to a float @@ -125,7 +127,8 @@ class Box(IndexFaceSet): A stack of boxes:: - sage: show(sum([Box([2,3,1], color="red").translate((0,0,6*i)) for i in [0..3]])) + sage: show(sum(Box([2,3,1], color="red").translate((0,0,6*i)) + ....: for i in [0..3])) .. PLOT:: @@ -135,8 +138,10 @@ class Box(IndexFaceSet): A sinusoidal stack of multicolored boxes:: - sage: B = sum([Box([2,4,1/4], color=(i/4,i/5,1)).translate((sin(i),0,5-i)) for i in [0..20]]) - sage: show(B, figsize=6) + sage: B = sum(Box([2,4,1/4], # needs sage.symbolic + ....: color=(i/4,i/5,1)).translate((sin(i),0,5-i)) + ....: for i in [0..20]) + sage: show(B, figsize=6) # needs sage.symbolic .. PLOT:: @@ -265,7 +270,8 @@ cdef class Cone(ParametricSurface): EXAMPLES:: sage: from sage.plot.plot3d.shapes import Cone - sage: c = Cone(3/2, 1, color='red') + Cone(1, 2, color='yellow').translate(3, 0, 0) + sage: c = Cone(3/2, 1, color='red') + sage: c += Cone(1, 2, color='yellow').translate(3, 0, 0) sage: c.show(aspect_ratio=1) .. PLOT:: @@ -286,7 +292,8 @@ cdef class Cone(ParametricSurface): A spiky plot of the sine function:: - sage: sum(Cone(.1, sin(n), color='yellow').translate(n, sin(n), 0) for n in [0..10, step=.1]) + sage: sum(Cone(.1, sin(n), color='yellow').translate(n, sin(n), 0) # needs sage.symbolic + ....: for n in [0..10, step=.1]) Graphics3d Object .. PLOT:: @@ -296,9 +303,11 @@ cdef class Cone(ParametricSurface): A Christmas tree:: - sage: T = sum(Cone(exp(-n/5), 4/3*exp(-n/5), color=(0, .5, 0)).translate(0, 0, -3*exp(-n/5)) for n in [1..7]) - sage: T += Cone(1/8, 1, color='brown').translate(0, 0, -3) - sage: T.show(aspect_ratio=1, frame=False) + sage: T = sum(Cone(exp(-n/5), 4/3*exp(-n/5), # needs sage.symbolic + ....: color=(0, .5, 0)).translate(0, 0, -3*exp(-n/5)) + ....: for n in [1..7]) + sage: T += Cone(1/8, 1, color='brown').translate(0, 0, -3) # needs sage.symbolic + sage: T.show(aspect_ratio=1, frame=False) # needs sage.symbolic .. PLOT:: @@ -350,7 +359,7 @@ cdef class Cone(ParametricSurface): urange = [1,0,-1] else: urange = [1,0] - vrange = [2*M_PI*k/t_res for k from 0 <= k < t_res] + [0.0] + vrange = [2*M_PI*k/t_res for k in range(t_res)] + [0.0] return urange, vrange cdef int eval_c(self, point_c *res, double u, double v) except -1: @@ -376,12 +385,13 @@ cdef class Cylinder(ParametricSurface): - ``closed`` -- whether or not to include the ends (default ``True``) - - ``**kwds`` -- passed to the ParametricSurface constructor + - ``**kwds`` -- passed to the :class:`ParametricSurface` constructor EXAMPLES:: sage: from sage.plot.plot3d.shapes import Cylinder - sage: c = Cylinder(3/2, 1, color='red') + Cylinder(1, 2, color='yellow').translate(3, 0, 0) + sage: c = Cylinder(3/2, 1, color='red') + sage: c += Cylinder(1, 2, color='yellow').translate(3, 0, 0) sage: c.show(aspect_ratio=1) .. PLOT:: @@ -402,8 +412,10 @@ cdef class Cylinder(ParametricSurface): Some gears:: + sage: # needs sage.symbolic sage: G = Cylinder(1, .5) + Cylinder(.25, 3).translate(0, 0, -3) - sage: G += sum(Cylinder(.2, 1).translate(cos(2*pi*n/9), sin(2*pi*n/9), 0) for n in [1..9]) + sage: G += sum(Cylinder(.2, 1).translate(cos(2*pi*n/9), sin(2*pi*n/9), 0) + ....: for n in [1..9]) sage: G += G.translate(2.3, 0, -.5) sage: G += G.translate(3.5, 2, -1) sage: G.show(aspect_ratio=1, frame=False) @@ -523,11 +535,10 @@ cdef class Cylinder(ParametricSurface): name = render_params.unique_name('line') return [""" draw %s width %s {%s %s %s} {%s %s %s}\n%s -""" % (name, - rad, +""" % (name, rad, base[0], base[1], base[2], - top [0], top [1], top [2], - self.texture.jmol_str("$" + name)) ] + top[0], top[1], top[2], + self.texture.jmol_str("$" + name))] def get_endpoints(self, transform=None): """ @@ -537,7 +548,8 @@ draw %s width %s {%s %s %s} {%s %s %s}\n%s sage: from sage.plot.plot3d.transform import Transformation sage: Cylinder(1, 5).get_endpoints() ((0, 0, 0), (0, 0, 5.0)) - sage: Cylinder(1, 5).get_endpoints(Transformation(trans=(1,2,3), scale=(2,2,2))) + sage: Cylinder(1, 5).get_endpoints(Transformation(trans=(1,2,3), + ....: scale=(2,2,2))) ((1.0, 2.0, 3.0), (1.0, 2.0, 13.0)) """ if transform is None: @@ -553,7 +565,8 @@ draw %s width %s {%s %s %s} {%s %s %s}\n%s sage: from sage.plot.plot3d.transform import Transformation sage: Cylinder(3, 1).get_radius() 3.0 - sage: Cylinder(3, 1).get_radius(Transformation(trans=(1,2,3), scale=(2,2,2))) + sage: Cylinder(3, 1).get_radius(Transformation(trans=(1,2,3), + ....: scale=(2,2,2))) 6.0 """ if transform is None: @@ -580,7 +593,7 @@ draw %s width %s {%s %s %s} {%s %s %s}\n%s urange = [2,1,-1,-2] else: urange = [1,-1] - vrange = [2*M_PI*k/v_res for k from 0 <= k < v_res] + [0.0] + vrange = [2*M_PI*k/v_res for k in range(v_res)] + [0.0] return urange, vrange cdef int eval_c(self, point_c *res, double u, double v) except -1: @@ -670,12 +683,12 @@ def arrow3d(start, end, width=1, radius=None, head_radius=None, head_len=None, * INPUT: - - start -- (x,y,z) point; the starting point of the arrow - - end -- (x,y,z) point; the end point - - width -- (default: 1); how wide the arrow is - - radius -- (default: width/50.0) the radius of the arrow - - head_radius -- (default: 3*radius); radius of arrow head - - head_len -- (default: 3*head_radius); len of arrow head + - ``start`` -- (x,y,z) point; the starting point of the arrow + - ``end`` -- (x,y,z) point; the end point + - ``width`` -- (default: 1); how wide the arrow is + - ``radius`` -- (default: ``width/50.0``) the radius of the arrow + - ``head_radius`` -- (default: ``3*radius``); radius of arrow head + - ``head_len`` -- (default: ``3*head_radius``); len of arrow head EXAMPLES: @@ -708,7 +721,8 @@ def arrow3d(start, end, width=1, radius=None, head_radius=None, head_len=None, * A fat arrow head:: - sage: arrow3d((2,1,0), (1,1,1), color='green', head_radius=0.3, aspect_ratio=[1,1,1]) + sage: arrow3d((2,1,0), (1,1,1), color='green', head_radius=0.3, + ....: aspect_ratio=[1,1,1]) Graphics3d Object .. PLOT:: @@ -717,7 +731,8 @@ def arrow3d(start, end, width=1, radius=None, head_radius=None, head_len=None, * Many arrows arranged in a circle (flying spears?):: - sage: sum([arrow3d((cos(t),sin(t),0),(cos(t),sin(t),1)) for t in [0,0.3,..,2*pi]]) + sage: sum(arrow3d((cos(t),sin(t),0), (cos(t),sin(t),1)) # needs sage.symbolic + ....: for t in [0,0.3,..,2*pi]) Graphics3d Object .. PLOT:: @@ -730,7 +745,7 @@ def arrow3d(start, end, width=1, radius=None, head_radius=None, head_len=None, * sphinx_plot(G) Change the width of the arrow. (Note: for an arrow that scales with zoom, please consider - the ``line3d`` function with the option ``arrow_head=True``):: + the :func:`line3d` function with the option ``arrow_head=True``):: sage: arrow3d((0,0,0), (1,1,1), width=1) Graphics3d Object @@ -804,7 +819,7 @@ cdef class Sphere(ParametricSurface): from sage.plot.plot3d.shapes import Sphere sphinx_plot(Sphere(3)) - Plot with aspect_ratio=1 to see it unsquashed:: + Plot with ``aspect_ratio=1`` to see it unsquashed:: sage: S = Sphere(3, color='blue') + Sphere(2, color='red').translate(0,3,0) sage: S.show(aspect_ratio=1) @@ -948,7 +963,7 @@ cdef class Sphere(ParametricSurface): ([-10.0, ..., 10.0], [0.0, ..., 3.141592653589793, ..., 0.0]) """ - cdef int K, u_res, v_res + cdef int u_res, v_res u_res = min(max(int(M_PI*self.radius/ds), 6), 20) v_res = min(max(int(2*M_PI * self.radius/ds), 6), 36) urange = [-10.0] + [M_PI * k/u_res - M_PI/2 for k in range(1, u_res)] + [10.0] @@ -961,8 +976,8 @@ cdef class Sphere(ParametricSurface): elif u == 10: res.x, res.y, res.z = 0, 0, self.radius else: - res.x = self.radius*cos(v) * cos(u) - res.y = self.radius*sin(v) * cos(u) + res.x = self.radius * cos(v) * cos(u) + res.y = self.radius * sin(v) * cos(u) res.z = self.radius * sin(u) @@ -970,8 +985,8 @@ cdef class Torus(ParametricSurface): """ INPUT: - - R -- (default: 1) outer radius - - r -- (default: .3) inner radius + - ``R`` -- (default: ``1``) outer radius + - ``r`` -- (default: ``.3``) inner radius OUTPUT: @@ -998,7 +1013,8 @@ cdef class Torus(ParametricSurface): A rubberband ball:: - sage: show(sum([Torus(1, .03, color=(1, t/30.0, 0)).rotate((1,1,1),t) for t in range(30)])) + sage: show(sum(Torus(1, .03, color=(1, t/30.0, 0)).rotate((1,1,1), t) + ....: for t in range(30))) .. PLOT:: @@ -1007,8 +1023,12 @@ cdef class Torus(ParametricSurface): Mmm... doughnuts:: - sage: D = Torus(1, .4, color=(.5, .3, .2)) + Torus(1, .3, color='yellow').translate(0, 0, .15) - sage: G = sum(D.translate(RDF.random_element(-.2, .2), RDF.random_element(-.2, .2), .8*t) for t in range(10)) + sage: D = Torus(1, .4, color=(.5, .3, .2)) + sage: D += Torus(1, .3, color='yellow').translate(0, 0, .15) + sage: G = sum(D.translate(RDF.random_element(-.2, .2), + ....: RDF.random_element(-.2, .2), + ....: .8*t) + ....: for t in range(10)) sage: G.show(aspect_ratio=1, frame=False) .. PLOT:: diff --git a/src/sage/plot/plot3d/shapes2.py b/src/sage/plot/plot3d/shapes2.py index e771763955e..18e37bbfefe 100644 --- a/src/sage/plot/plot3d/shapes2.py +++ b/src/sage/plot/plot3d/shapes2.py @@ -64,8 +64,8 @@ def line3d(points, thickness=1, radius=None, arrow_head=False, **kwds): - ``color`` -- a string (``"red"``, ``"green"`` etc) or a tuple (r, g, b) with r, g, b numbers between 0 and 1 - - ``opacity`` -- (default: 1) if less than 1 then is - transparent + - ``opacity`` -- (default: 1) if less than 1 then is + transparent EXAMPLES: @@ -117,6 +117,7 @@ def line3d(points, thickness=1, radius=None, arrow_head=False, **kwds): ....: (-sqrt(2.)/3,-sqrt(6.)/3,-1./3), (2*sqrt(2.)/3,0,-1./3)],\ ....: color=col, thickness=10, aspect_ratio=[1,1,1]) + sage: from math import pi sage: v = (sqrt(5.)/2-5/6, 5/6*sqrt(3.)-sqrt(15.)/2, sqrt(5.)/3) sage: t = acos(sqrt(5.)/3)/2 sage: t1 = tetra('blue').rotateZ(t) @@ -160,7 +161,7 @@ def tetra(col): This function should work for anything than can be turned into a list, such as iterators and such (see :trac:`10478`):: - sage: line3d(iter([(0,0,0), (sqrt(3), 2, 4)])) + sage: line3d(iter([(0,0,0), (sqrt(3), 2, 4)])) # needs sage.symbolic Graphics3d Object sage: line3d((x, x^2, x^3) for x in range(5)) Graphics3d Object @@ -210,13 +211,13 @@ def bezier3d(path, **options): - ``thickness`` -- (default: 2) - - ``color`` -- a string (``"red"``, ``"green"`` etc) - or a tuple (r, g, b) with r, g, b numbers between 0 and 1 + - ``color`` -- a string (``"red"``, ``"green"`` etc) + or a tuple (r, g, b) with r, g, b numbers between 0 and 1 - ``opacity`` -- (default: 1) if less than 1 then is transparent - - ``aspect_ratio`` -- (default:[1,1,1]) + - ``aspect_ratio`` -- (default: [1,1,1]) The path is a list of curves, and each curve is a list of points. Each point is a tuple (x,y,z). @@ -248,9 +249,9 @@ def bezier3d(path, **options): EXAMPLES:: - sage: path = [[(0,0,0),(.5,.1,.2),(.75,3,-1),(1,1,0)],[(.5,1,.2),(1,.5,0)],[(.7,.2,.5)]] - sage: b = bezier3d(path, color='green') - sage: b + sage: path = [[(0,0,0),(.5,.1,.2),(.75,3,-1),(1,1,0)], + ....: [(.5,1,.2),(1,.5,0)], [(.7,.2,.5)]] + sage: b = bezier3d(path, color='green'); b # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -261,8 +262,7 @@ def bezier3d(path, **options): To construct a simple curve, create a list containing a single list:: sage: path = [[(0,0,0),(1,0,0),(0,1,0),(0,1,1)]] - sage: curve = bezier3d(path, thickness=5, color='blue') - sage: curve + sage: curve = bezier3d(path, thickness=5, color='blue'); curve # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -274,13 +274,16 @@ def bezier3d(path, **options): Check for :trac:`31640`:: - sage: p2d = [[(3,0.0),(3,0.13),(2,0.2),(2,0.3)], [(2.7,0.4),(2.6,0.5),(2.5,0.5)], [(2.3,0.5),(2.2,0.4),(2.1,0.3)]] - sage: bp = bezier_path(p2d) - sage: bp.plot3d() + sage: p2d = [[(3,0.0),(3,0.13),(2,0.2),(2,0.3)], + ....: [(2.7,0.4),(2.6,0.5),(2.5,0.5)], [(2.3,0.5),(2.2,0.4),(2.1,0.3)]] + sage: bp = bezier_path(p2d) # needs sage.symbolic + sage: bp.plot3d() # needs sage.symbolic Graphics3d Object - sage: p3d = p3d = [[(3,0,0),(3,0.1,0),(2.9,0.2,0),(2.8,0.3,0)], [(2.7,0.4,0),(2,0.5,0),(2.5,0.5,0)], [(2.3,0.5,0),(2.2,0.4,0),(2.1,0.3,0)]] - sage: bezier3d(p3d) + sage: p3d = [[(3,0,0),(3,0.1,0),(2.9,0.2,0),(2.8,0.3,0)], + ....: [(2.7,0.4,0),(2,0.5,0),(2.5,0.5,0)], + ....: [(2.3,0.5,0),(2.2,0.4,0),(2.1,0.3,0)]] + sage: bezier3d(p3d) # needs sage.symbolic Graphics3d Object """ from . import parametric_plot3d as P3D @@ -336,7 +339,8 @@ def polygon3d(points, **options): Some modern art -- a random polygon:: - sage: v = [(randrange(-5,5), randrange(-5,5), randrange(-5, 5)) for _ in range(10)] + sage: v = [(randrange(-5,5), randrange(-5,5), randrange(-5, 5)) + ....: for _ in range(10)] sage: polygon3d(v) Graphics3d Object @@ -347,7 +351,8 @@ def polygon3d(points, **options): A bent transparent green triangle:: - sage: polygon3d([[1, 2, 3], [0,1,0], [1,0,1], [3,0,0]], color=(0,1,0), opacity=0.7) + sage: polygon3d([[1, 2, 3], [0,1,0], [1,0,1], [3,0,0]], + ....: color=(0,1,0), opacity=0.7) Graphics3d Object .. PLOT:: @@ -356,7 +361,8 @@ def polygon3d(points, **options): This is the same as using ``alpha=0.7``:: - sage: polygon3d([[1, 2, 3], [0,1,0], [1,0,1], [3,0,0]], color=(0,1,0), alpha=0.7) + sage: polygon3d([[1, 2, 3], [0,1,0], [1,0,1], [3,0,0]], + ....: color=(0,1,0), alpha=0.7) Graphics3d Object .. PLOT:: @@ -373,7 +379,7 @@ def polygons3d(faces, points, **options): """ Draw the union of several polygons in 3d. - Useful to plot a polyhedron as just one ``IndexFaceSet``. + Useful to plot a polyhedron as just one :class:`IndexFaceSet`. INPUT: @@ -426,8 +432,8 @@ def frame3d(lower_left, upper_right, **kwds): This is usually used for making an actual plot:: - sage: y = var('y') - sage: plot3d(sin(x^2+y^2),(x,0,pi),(y,0,pi)) + sage: y = var('y') # needs sage.symbolic + sage: plot3d(sin(x^2+y^2), (x,0,pi), (y,0,pi)) # needs sage.symbolic Graphics3d Object """ x0, y0, z0 = lower_left @@ -483,10 +489,11 @@ def frame_labels(lower_left, upper_right, This is usually used for making an actual plot:: + sage: # needs sage.symbolic sage: y = var('y') - sage: P = plot3d(sin(x^2+y^2),(x,0,pi),(y,0,pi)) + sage: P = plot3d(sin(x^2+y^2), (x,0,pi), (y,0,pi)) sage: a,b = P._rescale_for_frame_aspect_ratio_and_zoom(1.0,[1,1,1],1) - sage: F = frame_labels(a,b,*P._box_for_aspect_ratio("automatic",a,b)) + sage: F = frame_labels(a, b, *P._box_for_aspect_ratio("automatic",a,b)) sage: F.jmol_repr(F.default_render_params())[0] [['select atomno = 1', 'color atom [76,76,76]', 'label "0.0"']] @@ -749,7 +756,7 @@ def sphere(center=(0, 0, 0), size=1, **kwds): Spheres of radii 1 and 2 one stuck into the other:: sage: sphere(color='orange') + sphere(color=(0,0,0.3), - ....: center=(0,0,-2),size=2,opacity=0.9) + ....: center=(0,0,-2), size=2, opacity=0.9) Graphics3d Object .. PLOT:: @@ -758,9 +765,9 @@ def sphere(center=(0, 0, 0), size=1, **kwds): We draw a transparent sphere on a saddle. :: - sage: u,v = var('u v') - sage: saddle = plot3d(u^2 - v^2, (u,-2,2), (v,-2,2)) - sage: sphere((0,0,1), color='red', opacity=0.5, aspect_ratio=[1,1,1]) + saddle + sage: u,v = var('u v') # needs sage.symbolic + sage: saddle = plot3d(u^2 - v^2, (u,-2,2), (v,-2,2)) # needs sage.symbolic + sage: sphere((0,0,1), color='red', opacity=0.5, aspect_ratio=[1,1,1]) + saddle # needs sage.symbolic Graphics3d Object .. PLOT:: @@ -1048,7 +1055,8 @@ class Line(PrimitiveObject): EXAMPLES:: sage: from sage.plot.plot3d.shapes2 import Line - sage: Line([(i*math.sin(i), i*math.cos(i), i/3) for i in range(30)], arrow_head=True) + sage: Line([(i*math.sin(i), i*math.cos(i), i/3) for i in range(30)], + ....: arrow_head=True) Graphics3d Object Smooth angles less than 90 degrees:: @@ -1060,10 +1068,10 @@ class Line(PrimitiveObject): sage: N = 11 sage: c = 0.4 - sage: sum([Line([(i,1,0), (i,0,0), (i,cos(2*pi*i/N), sin(2*pi*i/N))], - ....: corner_cutoff=c, - ....: color='red' if -cos(2*pi*i/N)<=c else 'blue') - ....: for i in range(N+1)]) + sage: sum(Line([(i,1,0), (i,0,0), (i,cos(2*pi*i/N), sin(2*pi*i/N))], # needs sage.symbolic + ....: corner_cutoff=c, + ....: color='red' if -cos(2*pi*i/N)<=c else 'blue') + ....: for i in range(N+1)) Graphics3d Object """ def __init__(self, points, thickness=5, corner_cutoff=0.5, @@ -1099,10 +1107,10 @@ def bounding_box(self): TESTS:: sage: from sage.plot.plot3d.shapes2 import Line - sage: L = Line([(i,i^2-1,-2*ln(i)) for i in [10,20,30]]) - sage: L.bounding_box() + sage: L = Line([(i, i^2 - 1, -2*ln(i)) for i in [10,20,30]]) # needs sage.symbolic + sage: L.bounding_box() # needs sage.symbolic ((10.0, 99.0, -6.802394763324311), - (30.0, 899.0, -4.605170185988092)) + (30.0, 899.0, -4.605170185988092)) """ try: return self.__bounding_box @@ -1117,8 +1125,9 @@ def tachyon_repr(self, render_params): TESTS:: - sage: L = line3d([(cos(i),sin(i),i^2) for i in srange(0,10,.01)],color='red') - sage: L.tachyon_repr(L.default_render_params())[0] + sage: L = line3d([(cos(i),sin(i),i^2) for i in srange(0,10,.01)], # needs sage.symbolic + ....: color='red') + sage: L.tachyon_repr(L.default_render_params())[0] # needs sage.symbolic 'FCylinder base 1.0 0.0 0.0 apex 0.9999500004166653 0.009999833334166664 0.0001 rad 0.005 texture...' """ T = render_params.transform @@ -1149,8 +1158,9 @@ def obj_repr(self, render_params): TESTS:: sage: from sage.plot.plot3d.shapes2 import Line - sage: L = Line([(cos(i),sin(i),i^2) for i in srange(0,10,.01)],color='red') - sage: L.obj_repr(L.default_render_params())[0][0][0][2][:3] + sage: L = Line([(cos(i),sin(i),i^2) for i in srange(0,10,.01)], # needs sage.symbolic + ....: color='red') + sage: L.obj_repr(L.default_render_params())[0][0][0][2][:3] # needs sage.symbolic ['v 0.99995 0.00999983 0.0001', 'v 1.02376 0.010195 -0.00750607', 'v 1.00007 0.0102504 -0.0248984'] @@ -1172,8 +1182,9 @@ def jmol_repr(self, render_params): TESTS:: - sage: L = line3d([(cos(i),sin(i),i^2) for i in srange(0,10,.01)],color='red') - sage: L.jmol_repr(L.default_render_params())[0][:42] + sage: L = line3d([(cos(i),sin(i),i^2) for i in srange(0,10,.01)], # needs sage.symbolic + ....: color='red') + sage: L.jmol_repr(L.default_render_params())[0][:42] # needs sage.symbolic 'draw line_1 diameter 1 curve {1.0 0.0 0.0}' """ T = render_params.transform @@ -1255,7 +1266,7 @@ def corners(self, corner_cutoff=None, max_len=None): elif corner_cutoff <= -1: # no corners - if not(max_len is None): + if max_len is not None: # forced by the maximal number of consecutive smooth points return self.points[:-1][::max_len - 1] else: @@ -1410,15 +1421,15 @@ def point3d(v, size=5, **kwds): - ``size`` -- (default: 5) size of the point (or points) - - ``color`` -- a string (``"red"``, ``"green"`` etc) - or a tuple (r, g, b) with r, g, b numbers between 0 and 1 + - ``color`` -- a string (``"red"``, ``"green"`` etc) + or a tuple (r, g, b) with r, g, b numbers between 0 and 1 - ``opacity`` -- (default: 1) if less than 1 then is transparent EXAMPLES:: - sage: sum([point3d((i,i^2,i^3), size=5) for i in range(10)]) + sage: sum(point3d((i,i^2,i^3), size=5) for i in range(10)) Graphics3d Object .. PLOT:: @@ -1431,15 +1442,15 @@ def point3d(v, size=5, **kwds): sage: print(point(vector((2,3,4)))) Graphics3d Object - sage: c = polytopes.hypercube(3) - sage: v = c.vertices()[0]; v + sage: c = polytopes.hypercube(3) # needs sage.geometry.polyhedron + sage: v = c.vertices()[0]; v # needs sage.geometry.polyhedron A vertex at (1, -1, -1) - sage: print(point(v)) + sage: print(point(v)) # needs sage.geometry.polyhedron Graphics3d Object We check to make sure the options work:: - sage: point3d((4,3,2),size=20,color='red',opacity=.5) + sage: point3d((4,3,2), size=20, color='red', opacity=.5) Graphics3d Object .. PLOT:: @@ -1469,7 +1480,7 @@ def point3d(v, size=5, **kwds): We check that iterators of points are accepted (:trac:`13890`):: - sage: point3d(iter([(1,1,2),(2,3,4),(3,5,8)]),size=20,color='red') + sage: point3d(iter([(1,1,2),(2,3,4),(3,5,8)]), size=20, color='red') Graphics3d Object TESTS:: diff --git a/src/sage/plot/plot3d/tachyon.py b/src/sage/plot/plot3d/tachyon.py index 88c8eba2d51..9c5719f894e 100644 --- a/src/sage/plot/plot3d/tachyon.py +++ b/src/sage/plot/plot3d/tachyon.py @@ -34,7 +34,7 @@ flexibility. For example, here we directly use Tachyon to draw 3 spheres on the coordinate axes:: - sage: t = Tachyon(xres=500,yres=500, camera_position=(2,0,0)) + sage: t = Tachyon(xres=500, yres=500, camera_position=(2,0,0)) sage: t.light((4,3,2), 0.2, (1,1,1)) sage: t.texture('t2', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1,0,0)) sage: t.texture('t3', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(0,1,0)) @@ -46,11 +46,12 @@ For scenes with many reflections it is helpful to increase the raydepth option, and turn on antialiasing. The following scene is an extreme case with many reflections between four cotangent spheres:: - sage: t = Tachyon(camera_position=(0,-4,1), xres = 800, yres = 600, raydepth = 12, aspectratio=.75, antialiasing = 4) + sage: t = Tachyon(camera_position=(0,-4,1), xres=800, yres=600, raydepth=12, + ....: aspectratio=.75, antialiasing=4) sage: t.light((0.02,0.012,0.001), 0.01, (1,0,0)) sage: t.light((0,0,10), 0.01, (0,0,1)) - sage: t.texture('s', color = (.8,1,1), opacity = .9, specular = .95, diffuse = .3, ambient = 0.05) - sage: t.texture('p', color = (0,0,1), opacity = 1, specular = .2) + sage: t.texture('s', color=(.8,1,1), opacity=.9, specular=.95, diffuse=.3, ambient=0.05) + sage: t.texture('p', color=(0,0,1), opacity=1, specular=.2) sage: t.sphere((-1,-.57735,-0.7071),1,'s') sage: t.sphere((1,-.57735,-0.7071),1,'s') sage: t.sphere((0,1.15465,-0.7071),1,'s') @@ -92,7 +93,7 @@ Finally there is the ``projection='perspective_dof'`` option. :: sage: T = Tachyon(xres=800, antialiasing=4, raydepth=10, - ....: projection='perspective_dof', focallength='1.0', aperture='.0025') + ....: projection='perspective_dof', focallength='1.0', aperture='.0025') sage: T.light((0,5,7), 1.0, (1,1,1)) sage: T.texture('t1', opacity=1, specular=.3) sage: T.texture('t2', opacity=1, specular=.3, color=(0,0,1)) @@ -113,7 +114,8 @@ cylinders or spheres. In this example an image is created and then used to tile the plane:: - sage: T = Tachyon(xres=800, yres=600, camera_position=(-2.0,-.1,.3), projection='fisheye', frustum=(-1.0, 1.0, -1.0, 1.0)) + sage: T = Tachyon(xres=800, yres=600, camera_position=(-2.0,-.1,.3), + ....: projection='fisheye', frustum=(-1.0, 1.0, -1.0, 1.0)) sage: T.texture('t1',color=(0,0,1)) sage: for ed in cedges: ....: T.fcylinder(ed[0], ed[1], .05, 't1') @@ -121,15 +123,20 @@ sage: fname_png = tmp_filename(ext='.png') sage: fname_ppm = tmp_filename(ext='.ppm') sage: T.save(fname_png) - sage: r2 = os.system('convert '+fname_png+' '+fname_ppm) # optional -- ImageMagick - - sage: T = Tachyon(xres=800, yres=600, camera_position=(-2.0,-.1,.3), projection='fisheye', frustum=(-1.0, 1.0, -1.0, 1.0)) # optional -- ImageMagick - sage: T.texture('t1', color=(1,0,0), specular=.9) # optional -- ImageMagick - sage: T.texture('p1', color=(1,1,1), opacity=.1, imagefile=fname_ppm, texfunc=9) # optional -- ImageMagick - sage: T.sphere((0,0,0), .5, 't1') # optional -- ImageMagick - sage: T.plane((0,0,-1), (0,0,1), 'p1') # optional -- ImageMagick - sage: T.light((-4,-4,4), .1, (1,1,1)) # optional -- ImageMagick - sage: T.show() # optional -- ImageMagick + sage: r2 = os.system('convert '+fname_png+' '+fname_ppm) # optional -- ImageMagick + + sage: # optional - imagemagick + sage: T = Tachyon(xres=800, yres=600, + ....: camera_position=(-2.0,-.1,.3), + ....: projection='fisheye', + ....: frustum=(-1.0, 1.0, -1.0, 1.0)) + sage: T.texture('t1', color=(1,0,0), specular=.9) + sage: T.texture('p1', color=(1,1,1), opacity=.1, + ....: imagefile=fname_ppm, texfunc=9) + sage: T.sphere((0,0,0), .5, 't1') + sage: T.plane((0,0,-1), (0,0,1), 'p1') + sage: T.light((-4,-4,4), .1, (1,1,1)) + sage: T.show() AUTHOR: @@ -172,24 +179,24 @@ class Tachyon(WithEqualityById, SageObject): INPUT: - - ``xres`` - (default 350) - - ``yres`` - (default 350) - - ``zoom`` - (default 1.0) - - ``antialiasing`` - (default ``False``) - - ``aspectratio`` - (default 1.0) - - ``raydepth`` - (default 8) - - ``camera_position`` - (default (-3, 0, 0)) - - ``updir`` - (default (0, 0, 1)) - - ``look_at`` - (default (0,0,0)) - - ``viewdir`` - (default ``None``), otherwise list of three numbers - - ``projection`` - ``'PERSPECTIVE'`` (default), ``'perspective_dof'`` + - ``xres`` -- (default 350) + - ``yres`` -- (default 350) + - ``zoom`` -- (default 1.0) + - ``antialiasing`` -- (default ``False``) + - ``aspectratio`` -- (default 1.0) + - ``raydepth`` -- (default 8) + - ``camera_position`` -- (default (-3, 0, 0)) + - ``updir`` -- (default (0, 0, 1)) + - ``look_at`` -- (default (0,0,0)) + - ``viewdir`` -- (default ``None``), otherwise list of three numbers + - ``projection`` -- ``'PERSPECTIVE'`` (default), ``'perspective_dof'`` or ``'fisheye'``. - - ``frustum`` - (default ''), otherwise list of four numbers. Only - used with projection='fisheye'. - - ``focallength`` - (default ''), otherwise a number. Only used - with projection='perspective_dof'. - - ``aperture`` - (default ''), otherwise a number. Only used - with projection='perspective_dof'. + - ``frustum`` -- (default ``''``), otherwise list of four numbers. Only + used with ``projection='fisheye'``. + - ``focallength`` -- (default ''), otherwise a number. Only used + with ``projection='perspective_dof'``. + - ``aperture`` -- (default ''), otherwise a number. Only used + with ``projection='perspective_dof'``. OUTPUT: A Tachyon 3d scene. @@ -205,7 +212,7 @@ class Tachyon(WithEqualityById, SageObject): sage: t.light((4,3,2), 0.2, (1,1,1)) sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1.0,0,0)) sage: t.texture('t1', ambient=0.1, diffuse=0.9, specular=0.3, opacity=1.0, color=(0,1.0,0)) - sage: t.texture('t2', ambient=0.2,diffuse=0.7, specular=0.5, opacity=0.7, color=(0,0,1.0)) + sage: t.texture('t2', ambient=0.2, diffuse=0.7, specular=0.5, opacity=0.7, color=(0,0,1.0)) sage: k=0 sage: for i in srange(-1,1,0.05): ....: k += 1 @@ -252,25 +259,28 @@ class Tachyon(WithEqualityById, SageObject): Points on an elliptic curve, their height indicated by their height above the axis:: + sage: # needs sage.schemes sage: t = Tachyon(camera_position=(5,2,2), look_at=(0,1,0)) sage: t.light((10,3,2), 0.2, (1,1,1)) sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1,0,0)) sage: t.texture('t1', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(0,1,0)) sage: t.texture('t2', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(0,0,1)) - sage: E = EllipticCurve('37a') - sage: P = E([0,0]) - sage: Q = P + sage: E = EllipticCurve('37a') # needs sage.schemes + sage: P = E([0,0]) # needs sage.schemes + sage: Q = P # needs sage.schemes sage: n = 100 - sage: for i in range(n): # increase 20 for a better plot + sage: for i in range(n): # increase 20 for a better plot # needs sage.schemes ....: Q = Q + P ....: t.sphere((Q[1], Q[0], ZZ(i)/n), 0.1, 't%s'%(i%3)) - sage: t.show() + sage: t.show() # needs sage.schemes A beautiful picture of rational points on a rank 1 elliptic curve. :: - sage: t = Tachyon(xres=1000, yres=800, camera_position=(2,7,4), look_at=(2,0,0), raydepth=4) + sage: # needs sage.schemes + sage: t = Tachyon(xres=1000, yres=800, camera_position=(2,7,4), + ....: look_at=(2,0,0), raydepth=4) sage: t.light((10,3,2), 1, (1,1,1)) sage: t.light((10,-3,2), 1, (1,1,1)) sage: t.texture('black', color=(0,0,0)) @@ -279,26 +289,27 @@ class Tachyon(WithEqualityById, SageObject): sage: t.plane((0,0,0),(0,0,1),'grey') sage: t.cylinder((0,0,0),(1,0,0),.01,'black') sage: t.cylinder((0,0,0),(0,1,0),.01,'black') - sage: E = EllipticCurve('37a') - sage: P = E([0,0]) - sage: Q = P + sage: E = EllipticCurve('37a') # needs sage.schemes + sage: P = E([0,0]) # needs sage.schemes + sage: Q = P # needs sage.schemes sage: n = 100 - sage: for i in range(n): + sage: for i in range(n): # needs sage.schemes ....: Q = Q + P ....: c = i/n + .1 ....: t.texture('r%s'%i,color=(float(i/n),0,0)) ....: t.sphere((Q[0], -Q[1], .01), .04, 'r%s'%i) - sage: t.show() # long time, e.g., 10-20 seconds + sage: t.show() # long time # needs sage.schemes A beautiful spiral. :: - sage: t = Tachyon(xres=800,yres=800, camera_position=(2,5,2), look_at=(2.5,0,0)) + sage: t = Tachyon(xres=800, yres=800, camera_position=(2,5,2), look_at=(2.5,0,0)) sage: t.light((0,0,100), 1, (1,1,1)) - sage: t.texture('r', ambient=0.1, diffuse=0.9, specular=0.5, opacity=1.0, color=(1,0,0)) + sage: t.texture('r', ambient=0.1, diffuse=0.9, specular=0.5, + ....: opacity=1.0, color=(1,0,0)) sage: for i in srange(0,50,0.1): - ....: t.sphere((i/10,sin(i),cos(i)), 0.05, 'r') + ....: t.sphere((i/10.0,sin(i),cos(i)), 0.05, 'r') sage: t.texture('white', color=(1,1,1), opacity=1, specular=1, diffuse=1) sage: t.plane((0,0,-100), (0,0,-100), 'white') sage: t.show() @@ -314,15 +325,15 @@ class Tachyon(WithEqualityById, SageObject): Use of a fisheye lens perspective. :: - sage: T = Tachyon(xres=800, yres=600, camera_position=(-1.5,-1.5,.3), projection='fisheye', frustum=(-1.0, 1.0, -1.0, 1.0)) + sage: T = Tachyon(xres=800, yres=600, camera_position=(-1.5,-1.5,.3), + ....: projection='fisheye', frustum=(-1.0, 1.0, -1.0, 1.0)) sage: T.texture('t1', color=(0,0,1)) sage: cedges = [[[1, 1, 1], [-1, 1, 1]], [[1, 1, 1], [1, -1, 1]], - ....: [[1, 1, 1], [1, 1, -1]], [[-1, 1, 1], [-1, -1, 1]], [[-1, 1, 1], - ....: [-1, 1, -1]], [[1, -1, 1], [-1, -1, 1]], [[1, -1, 1], - ....: [1, -1, -1]], - ....: [[-1, -1, 1], [-1, -1, -1]], [[1, 1, -1], [-1, 1, -1]], - ....: [[1, 1, -1], [1, -1, -1]], [[-1, 1, -1], [-1, -1, -1]], - ....: [[1, -1, -1], [-1, -1, -1]]] + ....: [[1, 1, 1], [1, 1, -1]], [[-1, 1, 1], [-1, -1, 1]], + ....: [[-1, 1, 1], [-1, 1, -1]], [[1, -1, 1], [-1, -1, 1]], + ....: [[1, -1, 1], [1, -1, -1]], [[-1, -1, 1], [-1, -1, -1]], + ....: [[1, 1, -1], [-1, 1, -1]], [[1, 1, -1], [1, -1, -1]], + ....: [[-1, 1, -1], [-1, -1, -1]], [[1, -1, -1], [-1, -1, -1]]] sage: for ed in cedges: ....: T.fcylinder(ed[0], ed[1], .05, 't1') sage: T.light((-4,-4,4), .1, (1,1,1)) @@ -331,7 +342,8 @@ class Tachyon(WithEqualityById, SageObject): Use of the ``projection='perspective_dof'`` option. This may not be implemented correctly. :: - sage: T = Tachyon(xres=800,antialiasing=4, raydepth=10, projection='perspective_dof', focallength='1.0', aperture='.0025') + sage: T = Tachyon(xres=800, antialiasing=4, raydepth=10, + ....: projection='perspective_dof', focallength='1.0', aperture='.0025') sage: T.light((0,5,7), 1.0, (1,1,1)) sage: T.texture('t1', opacity=1, specular=.3) sage: T.texture('t2', opacity=1, specular=.3, color=(0,0,1)) @@ -544,14 +556,17 @@ def show(self, **kwds): :: - sage: h = Tachyon(xres=512,yres=512, camera_position=(4,-4,3),viewdir=(-4,4,-3), raydepth=4) + sage: h = Tachyon(xres=512, yres=512, camera_position=(4,-4,3), + ....: viewdir=(-4,4,-3), raydepth=4) sage: h.light((4.4,-4.4,4.4), 0.2, (1,1,1)) sage: def f(x,y): return float(sin(x*y)) - sage: h.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, opacity=1.0, color=(1.0,0,0)) - sage: h.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, num_colors=60) # increase min_depth for better picture + sage: h.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, + ....: opacity=1.0, color=(1.0,0,0)) + sage: h.plot(f, (-4,4), (-4,4), "t0", max_depth=5, initial_depth=3, # needs sage.symbolic + ....: num_colors=60) # increase min_depth for better picture sage: from sage.misc.verbose import set_verbose, get_verbose sage: set_verbose(0) - sage: h.show() + sage: h.show() # needs sage.symbolic This second example, using a "medium" global verbosity setting of 1, displays some extra technical information then @@ -559,13 +574,16 @@ def show(self, **kwds): :: - sage: s = Tachyon(xres=512,yres=512, camera_position=(4,-4,3),viewdir=(-4,4,-3), raydepth=4) + sage: s = Tachyon(xres=512, yres=512, camera_position=(4,-4,3), + ....: viewdir=(-4,4,-3), raydepth=4) sage: s.light((4.4,-4.4,4.4), 0.2, (1,1,1)) sage: def f(x,y): return float(sin(x*y)) - sage: s.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, opacity=1.0, color=(1.0,0,0)) - sage: s.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, num_colors=60) # increase min_depth for better picture + sage: s.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, + ....: opacity=1.0, color=(1.0,0,0)) + sage: s.plot(f, (-4,4), (-4,4), "t0", max_depth=5, initial_depth=3, # needs sage.symbolic + ....: num_colors=60) # increase min_depth for better picture sage: set_verbose(1) - sage: s.show() + sage: s.show() # needs sage.symbolic tachyon ... Scene contains 2713 objects. ... @@ -579,14 +597,17 @@ def show(self, **kwds): :: sage: set_verbose(0) - sage: d = Tachyon(xres=512,yres=512, camera_position=(4,-4,3),viewdir=(-4,4,-3), raydepth=4) + sage: d = Tachyon(xres=512, yres=512, camera_position=(4,-4,3), + ....: viewdir=(-4,4,-3), raydepth=4) sage: d.light((4.4,-4.4,4.4), 0.2, (1,1,1)) sage: def f(x,y): return float(sin(x*y)) - sage: d.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, opacity=1.0, color=(1.0,0,0)) - sage: d.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, num_colors=60) # increase min_depth for better picture + sage: d.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, + ....: opacity=1.0, color=(1.0,0,0)) + sage: d.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, # needs sage.symbolic + ....: num_colors=60) # increase min_depth for better picture sage: get_verbose() 0 - sage: d.show(verbose=2) + sage: d.show(verbose=2) # needs sage.symbolic tachyon ... Scene contains 2713 objects. ... @@ -604,7 +625,7 @@ def _res(self): EXAMPLES:: - sage: t = Tachyon(xres = 300, yres = 700) + sage: t = Tachyon(xres=300, yres=700) sage: t._res() '\nresolution 300 700\n' """ @@ -617,7 +638,7 @@ def _camera(self): EXAMPLES:: - sage: t = Tachyon(raydepth = 16, zoom = 2, antialiasing = True) + sage: t = Tachyon(raydepth=16, zoom=2, antialiasing=True) sage: t._camera().split()[3:10] ['zoom', '2.0', 'aspectratio', '1.0', 'antialiasing', '1', 'raydepth'] """ @@ -764,7 +785,8 @@ def texture(self, name, ambient=0.2, diffuse=0.8, sage: t = Tachyon(camera_position=(2,5,4), look_at=(2,0,0), raydepth=6) sage: t.light((10,3,4), 1, (1,1,1)) - sage: t.texture('mirror', ambient=0.05, diffuse=0.05, specular=.9, opacity=0.9, color=(.8,.8,.8)) + sage: t.texture('mirror', ambient=0.05, diffuse=0.05, specular=.9, + ....: opacity=0.9, color=(.8,.8,.8)) sage: t.texture('grey', color=(.8,.8,.8), texfunc=3) sage: t.plane((0,0,0),(0,0,1),'grey') sage: t.sphere((4,-1,1), 1, 'mirror') @@ -987,12 +1009,15 @@ def plot(self, f, xmin_xmax, ymin_ymax, texture, grad_f=None, Flat Triangles:: - sage: t = Tachyon(xres=512,yres=512, camera_position=(4,-4,3),viewdir=(-4,4,-3), raydepth=4) + sage: t = Tachyon(xres=512, yres=512, camera_position=(4,-4,3), + ....: viewdir=(-4,4,-3), raydepth=4) sage: t.light((4.4,-4.4,4.4), 0.2, (1,1,1)) sage: def f(x,y): return float(sin(x*y)) - sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, opacity=1.0, color=(1.0,0,0)) - sage: t.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, num_colors=60) # increase min_depth for better picture - sage: t.show(verbose=1) + sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, + ....: opacity=1.0, color=(1.0,0,0)) + sage: t.plot(f, (-4,4), (-4,4), "t0", max_depth=5, initial_depth=3, # needs sage.symbolic + ....: num_colors=60) # increase min_depth for better picture + sage: t.show(verbose=1) # needs sage.symbolic tachyon ... Scene contains 2713 objects. ... @@ -1000,13 +1025,16 @@ def plot(self, f, xmin_xmax, ymin_ymax, texture, grad_f=None, Plotting with Smooth Triangles (requires explicit gradient function):: - sage: t = Tachyon(xres=512,yres=512, camera_position=(4,-4,3),viewdir=(-4,4,-3), raydepth=4) + sage: t = Tachyon(xres=512, yres=512, camera_position=(4,-4,3), + ....: viewdir=(-4,4,-3), raydepth=4) sage: t.light((4.4,-4.4,4.4), 0.2, (1,1,1)) sage: def f(x,y): return float(sin(x*y)) - sage: def g(x,y): return ( float(y*cos(x*y)), float(x*cos(x*y)), 1 ) - sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, opacity=1.0, color=(1.0,0,0)) - sage: t.plot(f,(-4,4),(-4,4),"t0",max_depth=5,initial_depth=3, grad_f = g) # increase min_depth for better picture - sage: t.show(verbose=1) + sage: def g(x,y): return (float(y*cos(x*y)), float(x*cos(x*y)), 1) + sage: t.texture('t0', ambient=0.1, diffuse=0.9, specular=0.1, + ....: opacity=1.0, color=(1.0,0,0)) + sage: t.plot(f, (-4,4), (-4,4), "t0", max_depth=5, initial_depth=3, # needs sage.symbolic + ....: grad_f=g) # increase min_depth for better picture + sage: t.show(verbose=1) # needs sage.symbolic tachyon ... Scene contains 2713 objects. ... @@ -1646,7 +1674,6 @@ def str(self): EXAMPLES:: sage: from sage.plot.plot3d.tachyon import ParametricPlot - sage: t = var('t') sage: f = lambda t: (t,t^2,t^3) sage: q = ParametricPlot(f,0,1,'s') sage: q.str()[9:69] @@ -1662,7 +1689,6 @@ def __init__(self, f, t_0, t_f, tex, r=.1, cylinders=True, EXAMPLES:: sage: from sage.plot.plot3d.tachyon import ParametricPlot - sage: t = var('t') sage: f = lambda t: (t,t^2,t^3) sage: q = ParametricPlot(f,0,1,'s') sage: q._e_rel @@ -1690,7 +1716,6 @@ def _plot_step(self, depth, t_0, t_f, f_0, f_f): EXAMPLES:: sage: from sage.plot.plot3d.tachyon import ParametricPlot - sage: t = var('t') sage: f = lambda t: (t,t^2,t^3) sage: q = ParametricPlot(f,0,1,'s') sage: q._plot_step(8,0,1,[0,0,0],[1,1,1]) @@ -1724,7 +1749,6 @@ def tol(self, est, val): EXAMPLES:: sage: from sage.plot.plot3d.tachyon import ParametricPlot - sage: t = var('t') sage: f = lambda t: (t,t^2,t^3) sage: q = ParametricPlot(f,0,1,'s') sage: q.tol([0,0,0],[1,0,0]) diff --git a/src/sage/plot/plot3d/transform.pyx b/src/sage/plot/plot3d/transform.pyx index 299ea0ee25c..5bff0d71ddc 100644 --- a/src/sage/plot/plot3d/transform.pyx +++ b/src/sage/plot/plot3d/transform.pyx @@ -54,7 +54,7 @@ cdef class Transformation: # this raw data is used for optimized transformations m_data = self.matrix.list() cdef int i - for i from 0 <= i < 12: + for i in range(12): self._matrix_data[i] = m_data[i] def get_matrix(self): @@ -95,7 +95,7 @@ cdef class Transformation: point_c_transform(&lower, self._matrix_data, bounds[0]) point_c_transform(&upper, self._matrix_data, bounds[0]) cdef int i - for i from 1 <= i < 8: + for i in range(1, 8): temp.x = bounds[ i & 1 ].x temp.y = bounds[(i & 2) >> 1].y temp.z = bounds[(i & 4) >> 2].z diff --git a/src/sage/plot/plot3d/tri_plot.py b/src/sage/plot/plot3d/tri_plot.py index dfe525409bb..da719020117 100644 --- a/src/sage/plot/plot3d/tri_plot.py +++ b/src/sage/plot/plot3d/tri_plot.py @@ -64,7 +64,7 @@ class of the form sage: print(tri.str()) [0, 0, 0] [-1, 2, 3] [0, 2, 0] 0 """ - return "%s %s %s %s"%(self._a, self._b, self._c, self._color) + return "%s %s %s %s" % (self._a, self._b, self._c, self._color) def set_color(self, color): """ @@ -135,7 +135,7 @@ def str(self): sage: print(t.str()) [1, 2, 3] [2, 3, 4] [0, 0, 0] 0 [0, 0, 1] [0, 1, 0] [1, 0, 0] """ - return "%s %s %s %s %s %s %s"%(self._a, self._b, self._c, self._color, self._da, self._db, self._dc) + return "%s %s %s %s %s %s %s" % (self._a, self._b, self._c, self._color, self._da, self._db, self._dc) def get_normals(self): """ @@ -152,7 +152,7 @@ def get_normals(self): class TriangleFactory: - def triangle(self, a, b, c, color = None): + def triangle(self, a, b, c, color=None): """ Parameters: a, b, c : triples (x,y,z) representing corners on a triangle in 3-space @@ -173,7 +173,7 @@ def triangle(self, a, b, c, color = None): else: return Triangle(a,b,c,color) - def smooth_triangle(self, a, b, c, da, db, dc, color = None): + def smooth_triangle(self, a, b, c, da, db, dc, color=None): """ Parameters: @@ -217,7 +217,6 @@ def get_colors(self, list): return list - class TrianglePlot: """ Recursively plots a function of two variables by building squares of 4 triangles, checking at @@ -239,8 +238,8 @@ def str(self): """ return "".join(o.str() for o in self._objects) - def __init__(self, triangle_factory, f, min_x__max_x, min_y__max_y, g = None, - min_depth=4, max_depth=8, num_colors = None, max_bend=.3): + def __init__(self, triangle_factory, f, min_x__max_x, min_y__max_y, g=None, + min_depth=4, max_depth=8, num_colors=None, max_bend=.3): """ TESTS:: @@ -302,7 +301,6 @@ def fcn(x,y): avg_z = (vertices[0][2] + vertices[1][2] + vertices[2][2])/3 o.set_color(colors[int(num_colors * (avg_z - self._min) / zrange)]) - def plot_block(self, min_x, mid_x, max_x, min_y, mid_y, max_y, sw_z, nw_z, se_z, ne_z, mid_z, depth): """ Recursive triangulation function for plotting. @@ -400,7 +398,6 @@ def plot_block(self, min_x, mid_x, max_x, min_y, mid_y, max_y, sw_z, nw_z, se_z, mid_se_z = self._fcn(qtr3_x,qtr1_y) mid_ne_z = self._fcn(qtr3_x,qtr3_y) - self.extrema([mid_w_z[0], mid_n_z[0], mid_e_z[0], mid_s_z[0], mid_sw_z[0], mid_se_z[0], mid_nw_z[0], mid_sw_z[0]]) # recurse into the sub-squares @@ -440,7 +437,6 @@ def plot_block(self, min_x, mid_x, max_x, min_y, mid_y, max_y, sw_z, nw_z, se_z, ne = [(max_x,max_y,ne_z[0]),ne_z[1]] c = [[(mid_x,mid_y,mid_z[0]),mid_z[1]]] - left = [sw,nw] left_c = c top = [nw,ne] @@ -499,7 +495,6 @@ def interface(self, n, p, p_c, q, q_c): self.triangulate(m, mpc) self.triangulate(m, mqc) - def triangulate(self, p, c): """ Pass in a list of edge points (p) and center points (c). @@ -523,7 +518,6 @@ def triangulate(self, p, c): for i in range(0,len(p)-1): self._objects.append(self._triangle_factory.smooth_triangle(p[i][0], p[i+1][0], c[i][0],p[i][1], p[i+1][1], c[i][1])) - def extrema(self, list): """ If the num_colors option has been set, this expands the TrianglePlot's _min and _max diff --git a/src/sage/plot/plot_field.py b/src/sage/plot/plot_field.py index b57af986b59..9b2746c5a27 100644 --- a/src/sage/plot/plot_field.py +++ b/src/sage/plot/plot_field.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Plotting fields """ @@ -138,7 +139,7 @@ def _repr_(self): 20 """ - return "PlotField defined by a %s x %s vector grid"%( + return "PlotField defined by a %s x %s vector grid" % ( self._options['plot_points'], self._options['plot_points']) def _render_on_subplot(self, subplot): diff --git a/src/sage/plot/point.py b/src/sage/plot/point.py index 10a19a5b5e4..2bbe8cef07a 100644 --- a/src/sage/plot/point.py +++ b/src/sage/plot/point.py @@ -4,10 +4,12 @@ TESTS:: - sage: E = EllipticCurve('37a') - sage: P = E(0,0) - sage: def get_points(n): return sum([point(list(i*P)[:2], size=3) for i in range(-n,n) if i != 0 and (i*P)[0] < 3]) - sage: sum([get_points(15*n).plot3d(z=n) for n in range(1,10)]) + sage: E = EllipticCurve('37a') # needs sage.schemes + sage: P = E(0,0) # needs sage.schemes + sage: def get_points(n): + ....: return sum(point(list(i*P)[:2], size=3) + ....: for i in range(-n,n) if i != 0 and (i*P)[0] < 3) + sage: sum(get_points(15*n).plot3d(z=n) for n in range(1,10)) # needs sage.schemes Graphics3d Object """ @@ -40,15 +42,15 @@ class Point(GraphicPrimitive_xydata): INPUT: - - xdata -- list of x values for points in Point object + - ``xdata`` -- list of x values for points in Point object - - ydata -- list of y values for points in Point object + - ``ydata`` -- list of y values for points in Point object - - options -- dict of valid plot options to pass to constructor + - ``options`` -- dict of valid plot options to pass to constructor EXAMPLES: - Note this should normally be used indirectly via ``point`` and friends:: + Note this should normally be used indirectly via :func:`point` and friends:: sage: from sage.plot.point import Point sage: P = Point([1,2],[2,3],{'alpha':.5}) @@ -369,9 +371,11 @@ def point(points, **kwds): Extra options will get passed on to show(), as long as they are valid:: - sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)], frame=True) + sage: point([(cos(theta), sin(theta)) # needs sage.symbolic + ....: for theta in srange(0, 2*pi, pi/8)], frame=True) Graphics object consisting of 1 graphics primitive - sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)]).show(frame=True) # These are equivalent + sage: point([(cos(theta), sin(theta)) # These are equivalent # needs sage.symbolic + ....: for theta in srange(0, 2*pi, pi/8)]).show(frame=True) TESTS: @@ -502,8 +506,9 @@ def point2d(points, **options): The legend can be colored:: - sage: P = points([(0, 0), (1, 0)], pointsize=40, legend_label='origin', legend_color='red') - sage: P + plot(x^2, (x, 0, 1), legend_label='plot', legend_color='green') + sage: P = points([(0, 0), (1, 0)], pointsize=40, + ....: legend_label='origin', legend_color='red') + sage: P + plot(x^2, (x, 0, 1), legend_label='plot', legend_color='green') # needs sage.symbolic Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -514,9 +519,11 @@ def point2d(points, **options): Extra options will get passed on to show(), as long as they are valid:: - sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)], frame=True) + sage: point([(cos(theta), sin(theta)) # needs sage.symbolic + ....: for theta in srange(0, 2*pi, pi/8)], frame=True) Graphics object consisting of 1 graphics primitive - sage: point([(cos(theta), sin(theta)) for theta in srange(0, 2*pi, pi/8)]).show(frame=True) # These are equivalent + sage: point([(cos(theta), sin(theta)) # These are equivalent # needs sage.symbolic + ....: for theta in srange(0, 2*pi, pi/8)]).show(frame=True) .. PLOT:: @@ -546,9 +553,9 @@ def point2d(points, **options): We can plot a single complex number:: - sage: point(1 + I, pointsize=100) + sage: point(1 + I, pointsize=100) # needs sage.symbolic Graphics object consisting of 1 graphics primitive - sage: point(sqrt(2) + I, pointsize=100) + sage: point(sqrt(2) + I, pointsize=100) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -561,7 +568,7 @@ def point2d(points, **options): We can also plot a list of complex numbers:: - sage: point([I, 1 + I, 2 + 2*I], pointsize=100) + sage: point([I, 1 + I, 2 + 2*I], pointsize=100) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: diff --git a/src/sage/plot/polygon.py b/src/sage/plot/polygon.py index 916957643d7..6f2c2b3f78b 100644 --- a/src/sage/plot/polygon.py +++ b/src/sage/plot/polygon.py @@ -31,11 +31,11 @@ class Polygon(GraphicPrimitive_xydata): INPUT: - - xdata -- list of `x`-coordinates of points defining Polygon + - ``xdata`` -- list of `x`-coordinates of points defining Polygon - - ydata -- list of `y`-coordinates of points defining Polygon + - ``ydata`` -- list of `y`-coordinates of points defining Polygon - - options -- dict of valid plot options to pass to constructor + - ``options`` -- dict of valid plot options to pass to constructor EXAMPLES: @@ -198,7 +198,8 @@ def plot3d(self, z=0, **kwds): A pentagon:: - sage: polygon([(cos(t), sin(t)) for t in srange(0, 2*pi, 2*pi/5)]).plot3d() + sage: polygon([(cos(t), sin(t)) # needs sage.symbolic + ....: for t in srange(0, 2*pi, 2*pi/5)]).plot3d() Graphics3d Object .. PLOT:: @@ -364,8 +365,8 @@ def polygon2d(points, **options): For filled polygons, one can use different colors for the border and the interior as follows:: - sage: L = [[0,0]]+[[i/100, 1.1+cos(i/20)] for i in range(100)]+[[1,0]] - sage: polygon2d(L, color="limegreen", edgecolor="black", axes=False) + sage: L = [[0,0]]+[[i/100, 1.1+cos(i/20)] for i in range(100)]+[[1,0]] # needs sage.symbolic + sage: polygon2d(L, color="limegreen", edgecolor="black", axes=False) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -386,10 +387,25 @@ def polygon2d(points, **options): P = polygon2d(v, legend_label='some form') sphinx_plot(P) + An aperiodic monotile, [Smi2023]_:: + + sage: s = sqrt(3) # needs sage.symbolic + sage: polygon2d([[0, 0], [0, s], [1, s], [3/2, 3/2*s], [3, s], [3, 0], [4, 0], # needs sage.symbolic + ....: [9/2, -1/2*s], [3, -s], [3/2, -1/2*s], [1, -s], [-1, -s], + ....: [-3/2, -1/2*s]], axes=False) + Graphics object consisting of 1 graphics primitive + + .. PLOT:: + + s = sqrt(3) + P = polygon2d([[0, 0], [0, s], [1, s], [3/2, 3/2*s], [3, s], [3, 0], [4, 0], [9/2, -1/2*s], [3, -s], \ + [3/2, -1/2*s], [1, -s], [-1, -s], [-3/2, -1/2*s]], axes=False) + sphinx_plot(P) + A purple hexagon:: - sage: L = [[cos(pi*i/3),sin(pi*i/3)] for i in range(6)] - sage: polygon2d(L, rgbcolor=(1,0,1)) + sage: L = [[cos(pi*i/3),sin(pi*i/3)] for i in range(6)] # needs sage.symbolic + sage: polygon2d(L, rgbcolor=(1,0,1)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -400,8 +416,9 @@ def polygon2d(points, **options): A green deltoid:: - sage: L = [[-1+cos(pi*i/100)*(1+cos(pi*i/100)),2*sin(pi*i/100)*(1-cos(pi*i/100))] for i in range(200)] - sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2)) + sage: L = [[-1+cos(pi*i/100)*(1+cos(pi*i/100)), # needs sage.symbolic + ....: 2*sin(pi*i/100)*(1-cos(pi*i/100))] for i in range(200)] + sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -412,8 +429,9 @@ def polygon2d(points, **options): A blue hypotrochoid:: - sage: L = [[6*cos(pi*i/100)+5*cos((6/2)*pi*i/100),6*sin(pi*i/100)-5*sin((6/2)*pi*i/100)] for i in range(200)] - sage: polygon2d(L, rgbcolor=(1/8,1/4,1/2)) + sage: L = [[6*cos(pi*i/100)+5*cos((6/2)*pi*i/100), # needs sage.symbolic + ....: 6*sin(pi*i/100)-5*sin((6/2)*pi*i/100)] for i in range(200)] + sage: polygon2d(L, rgbcolor=(1/8,1/4,1/2)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -425,8 +443,9 @@ def polygon2d(points, **options): Another one:: sage: n = 4; h = 5; b = 2 - sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] - sage: polygon2d(L, rgbcolor=(1/8,1/4,3/4)) + sage: L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100), # needs sage.symbolic + ....: n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] + sage: polygon2d(L, rgbcolor=(1/8,1/4,3/4)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -439,8 +458,9 @@ def polygon2d(points, **options): A purple epicycloid:: sage: m = 9; b = 1 - sage: L = [[m*cos(pi*i/100)+b*cos((m/b)*pi*i/100),m*sin(pi*i/100)-b*sin((m/b)*pi*i/100)] for i in range(200)] - sage: polygon2d(L, rgbcolor=(7/8,1/4,3/4)) + sage: L = [[m*cos(pi*i/100)+b*cos((m/b)*pi*i/100), # needs sage.symbolic + ....: m*sin(pi*i/100)-b*sin((m/b)*pi*i/100)] for i in range(200)] + sage: polygon2d(L, rgbcolor=(7/8,1/4,3/4)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -452,8 +472,8 @@ def polygon2d(points, **options): A brown astroid:: - sage: L = [[cos(pi*i/100)^3,sin(pi*i/100)^3] for i in range(200)] - sage: polygon2d(L, rgbcolor=(3/4,1/4,1/4)) + sage: L = [[cos(pi*i/100)^3, sin(pi*i/100)^3] for i in range(200)] # needs sage.symbolic + sage: polygon2d(L, rgbcolor=(3/4,1/4,1/4)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -464,8 +484,9 @@ def polygon2d(points, **options): And, my favorite, a greenish blob:: - sage: L = [[cos(pi*i/100)*(1+cos(pi*i/50)), sin(pi*i/100)*(1+sin(pi*i/50))] for i in range(200)] - sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2)) + sage: L = [[cos(pi*i/100)*(1+cos(pi*i/50)), # needs sage.symbolic + ....: sin(pi*i/100)*(1+sin(pi*i/50))] for i in range(200)] + sage: polygon2d(L, rgbcolor=(1/8,3/4,1/2)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -476,8 +497,9 @@ def polygon2d(points, **options): This one is for my wife:: - sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,100)] - sage: polygon2d(L, rgbcolor=(1,1/4,1/2)) + sage: L = [[sin(pi*i/100)+sin(pi*i/50), # needs sage.symbolic + ....: -(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,100)] + sage: polygon2d(L, rgbcolor=(1,1/4,1/2)) # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -488,7 +510,7 @@ def polygon2d(points, **options): One can do the same one with a colored legend label:: - sage: polygon2d(L, color='red', legend_label='For you!', legend_color='red') + sage: polygon2d(L, color='red', legend_label='For you!', legend_color='red') # needs sage.symbolic Graphics object consisting of 1 graphics primitive .. PLOT:: diff --git a/src/sage/plot/primitive.py b/src/sage/plot/primitive.py index 4510a571399..20c2987142f 100644 --- a/src/sage/plot/primitive.py +++ b/src/sage/plot/primitive.py @@ -56,7 +56,6 @@ def __init__(self, options): """ self._options = options - def _allowed_options(self): """ Return the allowed options for a graphics primitive. @@ -216,7 +215,6 @@ def _repr_(self): return "Graphics primitive" - class GraphicPrimitive_xydata(GraphicPrimitive): def get_minmax_data(self): """ diff --git a/src/sage/plot/step.py b/src/sage/plot/step.py index 461ab53d411..4023686f9bd 100644 --- a/src/sage/plot/step.py +++ b/src/sage/plot/step.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Step function plots """ @@ -30,10 +31,10 @@ def plot_step_function(v, vertical_lines=True, **kwds): - ``v`` -- list of pairs (a,b) - - ``vertical_lines`` -- bool (default: True) if True, draw + - ``vertical_lines`` -- bool (default: ``True``) if ``True``, draw vertical risers at each step of this step function. Technically these vertical lines are not part of the graph - of this function, but they look very nice in the plot so we + of this function, but they look very nice in the plot, so we include them by default EXAMPLES: @@ -59,7 +60,8 @@ def plot_step_function(v, vertical_lines=True, **kwds): We pass in many options and get something that looks like "Space Invaders":: sage: v = [(i, sin(i)) for i in range(5, 20)] - sage: plot_step_function(v, vertical_lines=False, thickness=30, rgbcolor='purple', axes=False) + sage: plot_step_function(v, vertical_lines=False, thickness=30, + ....: rgbcolor='purple', axes=False) Graphics object consisting of 14 graphics primitives .. PLOT:: diff --git a/src/sage/plot/streamline_plot.py b/src/sage/plot/streamline_plot.py index bd9156bf000..663d3aee70b 100644 --- a/src/sage/plot/streamline_plot.py +++ b/src/sage/plot/streamline_plot.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.symbolic """ Streamline plots """ @@ -199,7 +200,8 @@ def streamline_plot(f_g, xrange, yrange, **options): We increase the density of the plot:: - sage: streamline_plot((y, (cos(x)-2) * sin(x)), (x,-pi,pi), (y,-pi,pi), density=2) + sage: streamline_plot((y, (cos(x)-2) * sin(x)), + ....: (x,-pi,pi), (y,-pi,pi), density=2) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -211,7 +213,8 @@ def streamline_plot(f_g, xrange, yrange, **options): We ignore function values that are infinite or NaN:: sage: x, y = var('x y') - sage: streamline_plot((-x/sqrt(x^2+y^2), -y/sqrt(x^2+y^2)), (x,-10,10), (y,-10,10)) + sage: streamline_plot((-x/sqrt(x^2+y^2), -y/sqrt(x^2+y^2)), + ....: (x,-10,10), (y,-10,10)) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -225,7 +228,7 @@ def streamline_plot(f_g, xrange, yrange, **options): sage: streamline_plot((x, y), (x,-2,2), (y,-2,2), xmax=10) Graphics object consisting of 1 graphics primitive - sage: streamline_plot((x, y), (x,-2,2), (y,-2,2)).show(xmax=10) # These are equivalent + sage: streamline_plot((x, y), (x,-2,2), (y,-2,2)).show(xmax=10) # These are equivalent .. PLOT:: @@ -248,7 +251,8 @@ def streamline_plot(f_g, xrange, yrange, **options): We choose some particular points the streamlines pass through:: sage: pts = [[1, 1], [-2, 2], [1, -3/2]] - sage: g = streamline_plot((x + y) / sqrt(x^2 + y^2), (x,-3,3), (y,-3,3), start_points=pts) + sage: g = streamline_plot((x + y) / sqrt(x^2 + y^2), + ....: (x,-3,3), (y,-3,3), start_points=pts) sage: g += point(pts, color='red') sage: g Graphics object consisting of 2 graphics primitives diff --git a/src/sage/plot/text.py b/src/sage/plot/text.py index 0795cf5debb..602cdfebddf 100644 --- a/src/sage/plot/text.py +++ b/src/sage/plot/text.py @@ -81,8 +81,8 @@ def _repr_(self): EXAMPLES:: - sage: T = text("I like cool constants", (pi,e)) - sage: t=T[0];t + sage: T = text("I like cool constants", (pi,e)) # needs sage.symbolic + sage: t = T[0];t # needs sage.symbolic Text 'I like cool constants' at the point (3.1415926535...,2.7182818284...) """ return "Text '%s' at the point (%s,%s)" % (self.string, self.x, self.y) @@ -273,7 +273,8 @@ def text(string, xy, **options): Larger font, bold, colored red and transparent text:: - sage: text("I had a dream!", (2,12), alpha=0.3, fontsize='large', fontweight='bold', color='red') + sage: text("I had a dream!", (2,12), alpha=0.3, + ....: fontsize='large', fontweight='bold', color='red') Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -283,7 +284,8 @@ def text(string, xy, **options): By setting ``horizontal_alignment`` to 'left' the text is guaranteed to be in the lower left no matter what:: - sage: text("I got a horse and he lives in a tree", (0,0), axis_coords=True, horizontal_alignment='left') + sage: text("I got a horse and he lives in a tree", (0,0), + ....: axis_coords=True, horizontal_alignment='left') Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -293,7 +295,8 @@ def text(string, xy, **options): Various rotations:: - sage: text("noitator", (0,0), rotation=45.0, horizontal_alignment='left', vertical_alignment='bottom') + sage: text("noitator", (0,0), rotation=45.0, + ....: horizontal_alignment='left', vertical_alignment='bottom') Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -311,7 +314,7 @@ def text(string, xy, **options): You can also align text differently:: - sage: t1 = text("Hello",(1,1), vertical_alignment="top") + sage: t1 = text("Hello", (1,1), vertical_alignment="top") sage: t2 = text("World", (1,0.5), horizontal_alignment="left") sage: t1 + t2 # render the sum Graphics object consisting of 2 graphics primitives @@ -330,7 +333,7 @@ def text(string, xy, **options): Some examples of bounding box:: - sage: bbox = {'boxstyle':"rarrow,pad=0.3", 'fc':"cyan", 'ec':"b", 'lw':2} + sage: bbox = {'boxstyle': "rarrow,pad=0.3", 'fc': "cyan", 'ec': "b", 'lw': 2} sage: text("I feel good", (1,2), bounding_box=bbox) Graphics object consisting of 1 graphics primitive @@ -341,7 +344,7 @@ def text(string, xy, **options): :: - sage: text("So good", (0,0), bounding_box={'boxstyle':'round', 'fc':'w'}) + sage: text("So good", (0,0), bounding_box={'boxstyle': 'round', 'fc': 'w'}) Graphics object consisting of 1 graphics primitive .. PLOT:: @@ -371,8 +374,10 @@ def text(string, xy, **options): sage: PQ = point2d([(-a, a), (a, a)]) sage: botleft = dict(horizontal_alignment='left', vertical_alignment='bottom') sage: botright = dict(horizontal_alignment='right', vertical_alignment='bottom') - sage: tp = text(r'$z_P = e^{3i\pi/4}$', (-a, a), **botright) - sage: tq = text(r'$Q = (\frac{\sqrt{2}}{2}, \frac{\sqrt{2}}{2})$', (a, a), **botleft) + sage: tp = text(r'$z_P = e^{3i\pi/4}$', + ....: (-a, a), **botright) + sage: tq = text(r'$Q = (\frac{\sqrt{2}}{2}, \frac{\sqrt{2}}{2})$', + ....: (a, a), **botleft) sage: A + PQ + tp + tq Graphics object consisting of 4 graphics primitives diff --git a/src/sage/probability/__init__.py b/src/sage/probability/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/probability/probability_distribution.pyx b/src/sage/probability/probability_distribution.pyx index e90b20fb7ab..1f120cd6089 100644 --- a/src/sage/probability/probability_distribution.pyx +++ b/src/sage/probability/probability_distribution.pyx @@ -1,14 +1,14 @@ -""" +r""" Probability Distributions This module provides three types of probability distributions: -- ``RealDistribution``: various real-valued probability distributions. +- :class:`RealDistribution`: various real-valued probability distributions. -- ``SphericalDistribution``: uniformly distributed points on the +- :class:`SphericalDistribution`: uniformly distributed points on the surface of an `n-1` sphere in `n` dimensional euclidean space. -- ``GeneralDiscreteDistribution``: user-defined discrete distributions. +- :class:`GeneralDiscreteDistribution`: user-defined discrete distributions. AUTHORS: @@ -29,18 +29,15 @@ REFERENCES: GNU gsl library, Random number distributions http://www.gnu.org/software/gsl/manual/html_node/Random-Number-Distributions.html """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004, 2005, 2006 Joshua Kantor <kantor.jm@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** - -import sys +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.memory cimport sig_malloc, sig_free from sage.libs.gsl.all cimport * @@ -48,9 +45,8 @@ import sage.misc.prandom as random import sage.rings.real_double from sage.modules.free_module_element import vector -#TODO: Add more distributions available in gsl -#available but not currently wrapped are exponential, laplace, cauchy, landau, gamma, -#gamma, beta logistic. +# TODO: Add more distributions available in gsl +# available but not currently wrapped are laplace, cauchy, landau, logistic. cdef enum: uniform @@ -64,15 +60,17 @@ cdef enum: exppow weibull beta + exponential + gamma cdef class ProbabilityDistribution: - """ + r""" Concrete probability distributions should be derived from this abstract class. """ def __init__(self): - """ + r""" To be implemented by a derived class:: sage: P = sage.probability.probability_distribution.ProbabilityDistribution() @@ -81,7 +79,7 @@ cdef class ProbabilityDistribution: pass def get_random_element(self): - """ + r""" To be implemented by a derived class:: sage: P = sage.probability.probability_distribution.ProbabilityDistribution() @@ -94,15 +92,15 @@ cdef class ProbabilityDistribution: raise NotImplementedError("implement in derived class") def generate_histogram_data(self, num_samples=1000, bins=50): - """ + r""" Compute a histogram of the probability distribution. INPUT: - - ``num_samples`` - (optional) number of times to sample from + - ``num_samples`` -- (optional) number of times to sample from the probability distribution - - ``bins`` - (optional) number of bins to divide the samples + - ``bins`` -- (optional) number of bins to divide the samples into. OUTPUT: @@ -117,8 +115,8 @@ cdef class ProbabilityDistribution: sage: from sage.probability.probability_distribution import GeneralDiscreteDistribution sage: P = [0.3, 0.4, 0.3] sage: X = GeneralDiscreteDistribution(P) - sage: h, b = X.generate_histogram_data(bins = 10) - sage: h # rel tol 1e-08 + sage: h, b = X.generate_histogram_data(bins=10) # needs sage.plot + sage: h # rel tol 1e-08 # needs sage.plot [1.6299999999999999, 0.0, 0.0, @@ -129,7 +127,7 @@ cdef class ProbabilityDistribution: 0.0, 0.0, 1.4650000000000003] - sage: b + sage: b # needs sage.plot [0.0, 0.2, 0.4, @@ -143,23 +141,23 @@ cdef class ProbabilityDistribution: 2.0] """ import pylab - l = [float(self.get_random_element()) for _ in range(num_samples)] - S = pylab.hist(l, bins, density=True) + ell = [float(self.get_random_element()) for _ in range(num_samples)] + S = pylab.hist(ell, bins, density=True) return [list(S[0]), list(S[1])] - def generate_histogram_plot(self, name, num_samples = 1000, bins = 50): - """ + def generate_histogram_plot(self, name, num_samples=1000, bins=50): + r""" Save the histogram from :func:`generate_histogram_data() <sage.libs.gsl.ProbabilityDistribution.generate_histogram_data>` to a file. INPUT: - - ``name`` - file to save the histogram plot (as a PNG). + - ``name`` -- file to save the histogram plot (as a PNG). - - ``num_samples`` - (optional) number of times to sample from + - ``num_samples`` -- (optional) number of times to sample from the probability distribution - - ``bins`` - (optional) number of bins to divide the samples + - ``bins`` -- (optional) number of bins to divide the samples into. EXAMPLES: @@ -170,23 +168,23 @@ cdef class ProbabilityDistribution: sage: import tempfile sage: P = [0.3, 0.4, 0.3] sage: X = GeneralDiscreteDistribution(P) - sage: with tempfile.NamedTemporaryFile() as f: + sage: with tempfile.NamedTemporaryFile() as f: # needs sage.plot ....: X.generate_histogram_plot(f.name) """ import pylab - l = [float(self.get_random_element()) for _ in range(num_samples)] - pylab.hist(l, bins, density=True) + ell = [float(self.get_random_element()) for _ in range(num_samples)] + pylab.hist(ell, bins, density=True) pylab.savefig(name) cdef class SphericalDistribution(ProbabilityDistribution): - """ + r""" This class is capable of producing random points uniformly distributed - on the surface of an ``n-1`` sphere in ``n`` dimensional euclidean space. The - dimension, ``n`` is selected via the keyword ``dimension``. The random + on the surface of an `(n-1)`-sphere in `n`-dimensional euclidean space. The + dimension `n` is selected via the keyword ``dimension``. The random number generator which drives it can be selected using the keyword - ``rng``. Valid choices are ``default`` which uses the Mersenne-Twister, - ``luxury`` which uses RANDLXS, and ``taus`` which uses the tausworth + ``rng``. Valid choices are ``'default'`` which uses the Mersenne-Twister, + ``'luxury'`` which uses RANDLXS, and ``'taus'`` which uses the tausworth generator. The default dimension is ``3``. EXAMPLES:: @@ -255,19 +253,19 @@ cdef class SphericalDistribution(ProbabilityDistribution): self.vec = <double *>sig_malloc(self.dimension*(sizeof(double))) def set_seed(self, seed): - """ + r""" Set the seed for the underlying random number generator. EXAMPLES:: - sage: T = SphericalDistribution(seed = 0) + sage: T = SphericalDistribution(seed=0) sage: T.set_seed(100) """ gsl_rng_set(self.r, seed) self.seed = seed def set_random_number_generator(self, rng='default'): - """ + r""" Set the gsl random number generator to be one of ``default``, ``luxury``, or ``taus``. @@ -298,12 +296,12 @@ cdef class SphericalDistribution(ProbabilityDistribution): sig_free(self.vec) def get_random_element(self): - """ + r""" Get a random sample from the probability distribution. EXAMPLES:: - sage: T = SphericalDistribution(seed = 0) + sage: T = SphericalDistribution(seed=0) sage: T.get_random_element() # rel tol 4e-16 (0.07961564104639995, -0.05237671627581255, 0.9954486572862178) """ @@ -312,20 +310,26 @@ cdef class SphericalDistribution(ProbabilityDistribution): gsl_ran_dir_nd(self.r, self.dimension, self.vec) for i in range(self.dimension): v[i] = self.vec[i] - return vector(sage.rings.real_double.RDF, v) #This could be made more efficient by directly constructing the vector, TODO. + return vector(sage.rings.real_double.RDF, v) # This could be made more efficient by directly constructing the vector, TODO. def reset_distribution(self): - """ + r""" This method resets the distribution. EXAMPLES:: - sage: T = SphericalDistribution(seed = 0) + sage: T = SphericalDistribution(seed=0) sage: [T.get_random_element() for _ in range(4)] # rel tol 4e-16 - [(0.07961564104639995, -0.05237671627581255, 0.9954486572862178), (0.4123599490593727, 0.5606817859360097, -0.7180495855658982), (-0.9619860891623148, -0.2726473494040498, -0.015690351211529927), (0.5674297579435619, -0.011206783800420301, -0.8233455397322326)] + [(0.07961564104639995, -0.05237671627581255, 0.9954486572862178), + (0.4123599490593727, 0.5606817859360097, -0.7180495855658982), + (-0.9619860891623148, -0.2726473494040498, -0.015690351211529927), + (0.5674297579435619, -0.011206783800420301, -0.8233455397322326)] sage: T.reset_distribution() sage: [T.get_random_element() for _ in range(4)] # rel tol 4e-16 - [(0.07961564104639995, -0.05237671627581255, 0.9954486572862178), (0.4123599490593727, 0.5606817859360097, -0.7180495855658982), (-0.9619860891623148, -0.2726473494040498, -0.015690351211529927), (0.5674297579435619, -0.011206783800420301, -0.8233455397322326)] + [(0.07961564104639995, -0.05237671627581255, 0.9954486572862178), + (0.4123599490593727, 0.5606817859360097, -0.7180495855658982), + (-0.9619860891623148, -0.2726473494040498, -0.015690351211529927), + (0.5674297579435619, -0.011206783800420301, -0.8233455397322326)] """ if self.r != NULL: gsl_rng_free(self.r) @@ -334,8 +338,8 @@ cdef class SphericalDistribution(ProbabilityDistribution): # gsl_rng_env_setup() cdef class RealDistribution(ProbabilityDistribution): - """ - The ``RealDistribution`` class provides a number of routines for sampling + r""" + The :class:`RealDistribution` class provides a number of routines for sampling from and analyzing and visualizing probability distributions. For precise definitions of the distributions and their parameters see the gsl reference manuals chapter on random number generators @@ -498,6 +502,31 @@ cdef class RealDistribution(ProbabilityDistribution): sage: T.cum_distribution_function(1) 1.0 + The exponential distribution has one parameter ``mu``:: + + sage: mu = 2 + sage: T = RealDistribution('exponential', mu) + sage: s = T.get_random_element() + sage: 0 <= s + True + sage: s.parent() + Real Double Field + sage: T.distribution_function(0) + 0.5 + + The gamma distribution has two parameters ``a`` and ``b``:: + + sage: a = 2 + sage: b = 2 + sage: T = RealDistribution('gamma', [a, b]) + sage: s = T.get_random_element() + sage: 0 <= s + True + sage: s.parent() + Real Double Field + sage: T.distribution_function(0) + 0.0 + The weibull distribution has two parameters ``a`` and ``b``:: sage: a = 1 @@ -520,10 +549,10 @@ cdef class RealDistribution(ProbabilityDistribution): twister. Also available are the RANDLXS algorithm and the Tausworthe generator (see the gsl reference manual for more details). These are all supposed to be simulation quality - generators. For RANDLXS use ``rng = 'luxury'`` and for - tausworth use ``rng = 'taus'``:: + generators. For RANDLXS use ``rng='luxury'`` and for + tausworth use ``rng='taus'``:: - sage: T = RealDistribution('gaussian', 1, rng = 'luxury', seed = 10) + sage: T = RealDistribution('gaussian', 1, rng='luxury', seed=10) To change the seed at a later time use ``set_seed``:: @@ -545,15 +574,16 @@ cdef class RealDistribution(ProbabilityDistribution): cdef double* parameters cdef long int seed cdef object name - #cdef double (*generator_1)(gsl_rng*) - #cdef double (*generator_2)(gsl_rng*, double) - #cdef _get_random_element_c(self) + # cdef double (*generator_1)(gsl_rng*) + # cdef double (*generator_2)(gsl_rng*, double) + # cdef _get_random_element_c(self) - def __init__(self, type = 'uniform', parameters = [], rng = 'default', seed = None): + def __init__(self, type='uniform', parameters=None, + rng='default', seed=None): r""" EXAMPLES:: - sage: T = RealDistribution('gaussian', 1, seed = 0) + sage: T = RealDistribution('gaussian', 1, seed=0) sage: T.get_random_element() # rel tol 4e-16 0.13391860811867587 @@ -574,7 +604,6 @@ cdef class RealDistribution(ProbabilityDistribution): sage: one == three False """ - gsl_rng_env_setup() self.parameters = NULL self.set_random_number_generator(rng) @@ -586,22 +615,22 @@ cdef class RealDistribution(ProbabilityDistribution): self.set_distribution(type, parameters) def set_seed(self, seed): - """ + r""" Set the seed for the underlying random number generator. EXAMPLES:: - sage: T = RealDistribution('gaussian', 1, rng = 'luxury', seed = 10) + sage: T = RealDistribution('gaussian', 1, rng='luxury', seed=10) sage: T.set_seed(100) """ gsl_rng_set(self.r, seed) self.seed = seed - def set_random_number_generator(self, rng = 'default'): - """ - Set the gsl random number generator to be one of ``default``, - ``luxury``, or ``taus``. + def set_random_number_generator(self, rng='default'): + r""" + Set the gsl random number generator to be one of ``'default'``, + ``'luxury'``, or ``'taus'``. EXAMPLES:: @@ -630,7 +659,7 @@ cdef class RealDistribution(ProbabilityDistribution): sig_free(self.parameters) def __str__(self): - """ + r""" Return the name of the current distribution. EXAMPLES:: @@ -645,12 +674,12 @@ cdef class RealDistribution(ProbabilityDistribution): return self.name def get_random_element(self): - """ + r""" Get a random sample from the probability distribution. EXAMPLES:: - sage: T = RealDistribution('gaussian', 1, seed = 0) + sage: T = RealDistribution('gaussian', 1, seed=0) sage: T.get_random_element() # rel tol 4e-16 0.13391860811867587 @@ -679,13 +708,17 @@ cdef class RealDistribution(ProbabilityDistribution): result = gsl_ran_weibull(self.r, self.parameters[0], self.parameters[1]) elif self.distribution_type == beta: result = gsl_ran_beta(self.r, self.parameters[0], self.parameters[1]) + elif self.distribution_type == exponential: + result = gsl_ran_exponential(self.r, self.parameters[0]) + elif self.distribution_type == gamma: + result = gsl_ran_gamma(self.r, self.parameters[0], self.parameters[1]) else: raise TypeError("Not a supported probability distribution") return sage.rings.real_double.RDF(result) - def set_distribution(self, name = 'uniform', parameters = []): - """ + def set_distribution(self, name='uniform', parameters=None): + r""" This method can be called to change the current probability distribution. EXAMPLES:: @@ -696,6 +729,9 @@ cdef class RealDistribution(ProbabilityDistribution): """ sig_free(self.parameters) + if parameters is None: + parameters = [] + if name == 'uniform': self.distribution_type = uniform for x in parameters: @@ -726,7 +762,6 @@ cdef class RealDistribution(ProbabilityDistribution): self.parameters[1] = float(parameters[1]) self.distribution_type = pareto elif name == 'rayleigh': - self.distribution_type = rayleigh try: float(parameters) except Exception: @@ -807,20 +842,39 @@ cdef class RealDistribution(ProbabilityDistribution): self.parameters[0] = float(parameters[0]) self.parameters[1] = float(parameters[1]) self.distribution_type = beta + elif name == 'exponential': + try: + float(parameters) + except Exception: + raise TypeError("exponential distribution requires parameter mu coercible to float") + self.parameters = <double*>sig_malloc(sizeof(double)) + self.parameters[0] = float(parameters) + self.distribution_type = exponential + elif name == 'gamma': + if len(parameters) != 2: + raise TypeError("gamma distribution requires two real parameters") + try: + map(float, parameters) + except Exception: + raise TypeError("gamma distribution requires real parameters") + self.parameters = <double *>sig_malloc(sizeof(double)*2) + self.parameters[0] = float(parameters[0]) + self.parameters[1] = float(parameters[1]) + self.distribution_type = gamma else: raise TypeError("Not a supported probability distribution") self.name = name - #def _get_random_element_c(): + # def _get_random_element_c(): def reset_distribution(self): - """ - This method resets the distribution. + r""" + Reset the distribution. EXAMPLES:: - sage: T = RealDistribution('gaussian', 1, seed = 10) + sage: T = RealDistribution('gaussian', 1, seed=10) sage: [T.get_random_element() for _ in range(10)] # rel tol 4e-16 [-0.7460999595745819, -0.004644606626413462, -0.8720538317207641, 0.6916259921666037, 2.67668674666043, 0.6325002813661014, -0.7974263521959355, -0.5284976893366636, 1.1353119849528792, 0.9912505673230749] sage: T.reset_distribution() @@ -834,7 +888,7 @@ cdef class RealDistribution(ProbabilityDistribution): # gsl_rng_env_setup() def distribution_function(self, x): - """ + r""" Evaluate the distribution function of the probability distribution at ``x``. @@ -872,11 +926,15 @@ cdef class RealDistribution(ProbabilityDistribution): return sage.rings.real_double.RDF(gsl_ran_weibull_pdf(x, self.parameters[0], self.parameters[1])) elif self.distribution_type == beta: return sage.rings.real_double.RDF(gsl_ran_beta_pdf(x, self.parameters[0], self.parameters[1])) + elif self.distribution_type == exponential: + return sage.rings.real_double.RDF(gsl_ran_exponential_pdf(x, self.parameters[0])) + elif self.distribution_type == gamma: + return sage.rings.real_double.RDF(gsl_ran_gamma_pdf(x, self.parameters[0], self.parameters[1])) else: raise TypeError("Not a supported probability distribution") def cum_distribution_function(self, x): - """ + r""" Evaluate the cumulative distribution function of the probability distribution at ``x``. @@ -908,11 +966,15 @@ cdef class RealDistribution(ProbabilityDistribution): return sage.rings.real_double.RDF(gsl_cdf_weibull_P(x, self.parameters[0], self.parameters[1])) elif self.distribution_type == beta: return sage.rings.real_double.RDF(gsl_cdf_beta_P(x, self.parameters[0], self.parameters[1])) + elif self.distribution_type == exponential: + return sage.rings.real_double.RDF(gsl_cdf_exponential_P(x, self.parameters[0])) + elif self.distribution_type == gamma: + return sage.rings.real_double.RDF(gsl_cdf_gamma_P(x, self.parameters[0], self.parameters[1])) else: raise TypeError("Not a supported probability distribution") def cum_distribution_function_inv(self, x): - """ + r""" Evaluate the inverse of the cumulative distribution distribution function of the probability distribution at ``x``. @@ -945,11 +1007,15 @@ cdef class RealDistribution(ProbabilityDistribution): return sage.rings.real_double.RDF(gsl_cdf_weibull_Pinv(x, self.parameters[0], self.parameters[1])) elif self.distribution_type == beta: return sage.rings.real_double.RDF(gsl_cdf_beta_Pinv(x, self.parameters[0], self.parameters[1])) + elif self.distribution_type == exponential: + return sage.rings.real_double.RDF(gsl_cdf_exponential_Pinv(x, self.parameters[0])) + elif self.distribution_type == gamma: + return sage.rings.real_double.RDF(gsl_cdf_gamma_Pinv(x, self.parameters[0], self.parameters[1])) else: raise TypeError("Not a supported probability distribution") def plot(self, *args, **kwds): - """ + r""" Plot the distribution function for the probability distribution. Parameters to :func:`sage.plot.plot.plot` can be passed through ``*args`` and ``**kwds``. @@ -957,25 +1023,25 @@ cdef class RealDistribution(ProbabilityDistribution): EXAMPLES:: sage: T = RealDistribution('uniform', [0, 2]) - sage: P = T.plot() + sage: P = T.plot() # needs sage.plot """ from sage.plot.plot import plot return plot(self.distribution_function, *args, **kwds) cdef class GeneralDiscreteDistribution(ProbabilityDistribution): - """ + r""" Create a discrete probability distribution. INPUT: - - ``P`` - list of probabilities. The list will automatically be + - ``P`` -- list of probabilities. The list will automatically be normalised if ``sum(P)`` is not equal to 1. - - ``rng`` - (optional) random number generator to use. May be + - ``rng`` -- (optional) random number generator to use. May be one of ``'default'``, ``'luxury'``, or ``'taus'``. - - ``seed`` - (optional) seed to use with the random number + - ``seed`` -- (optional) seed to use with the random number generator. OUTPUT: @@ -985,7 +1051,7 @@ cdef class GeneralDiscreteDistribution(ProbabilityDistribution): EXAMPLES: - Constructs a ``GeneralDiscreteDistribution`` with the probability + Construct a ``GeneralDiscreteDistribution`` with the probability distribution `P` where `P(0) = 0.3`, `P(1) = 0.4`, `P(2) = 0.3`:: sage: P = [0.3, 0.4, 0.3] @@ -1007,7 +1073,7 @@ cdef class GeneralDiscreteDistribution(ProbabilityDistribution): The distribution probabilities will automatically be normalised:: sage: P = [0.1, 0.3] - sage: X = GeneralDiscreteDistribution(P, seed = 0) + sage: X = GeneralDiscreteDistribution(P, seed=0) sage: counts = [0, 0] sage: for _ in range(10000): ....: counts[X.get_random_element()] += 1 @@ -1031,13 +1097,12 @@ cdef class GeneralDiscreteDistribution(ProbabilityDistribution): ... ValueError: The distribution probabilities must be non-negative """ - cdef gsl_rng_type * T cdef gsl_rng * r cdef gsl_ran_discrete_t *dist cdef long seed - def __init__(self, P, rng = 'default', seed = None): + def __init__(self, P, rng='default', seed=None): r""" Given a list of probabilities P construct an instance of a gsl discrete random variable generator. @@ -1073,7 +1138,6 @@ cdef class GeneralDiscreteDistribution(ProbabilityDistribution): sage: X = GeneralDiscreteDistribution([1,2,2^1024]) sage: Counter(X.get_random_element() for _ in range(100)) Counter({2: 100}) - """ gsl_rng_env_setup() self.set_random_number_generator(rng) @@ -1096,7 +1160,7 @@ cdef class GeneralDiscreteDistribution(ProbabilityDistribution): for i in range(n): if P[i] < 0: raise ValueError("The distribution probabilities must " - "be non-negative") + "be non-negative") P_vec[i] = P[i] self.dist = gsl_ran_discrete_preproc(n, P_vec) @@ -1104,7 +1168,7 @@ cdef class GeneralDiscreteDistribution(ProbabilityDistribution): sig_free(P_vec) def set_seed(self, seed): - """ + r""" Set the seed to be used by the random number generator. EXAMPLES:: @@ -1114,12 +1178,11 @@ cdef class GeneralDiscreteDistribution(ProbabilityDistribution): sage: X.get_random_element() 1 """ - gsl_rng_set(self.r, seed) self.seed = seed - def set_random_number_generator(self, rng = 'default'): - """ + def set_random_number_generator(self, rng='default'): + r""" Set the random number generator to be used by gsl. EXAMPLES:: @@ -1127,7 +1190,6 @@ cdef class GeneralDiscreteDistribution(ProbabilityDistribution): sage: X = GeneralDiscreteDistribution([0.3, 0.4, 0.3]) sage: X.set_random_number_generator('taus') """ - if rng == 'default': self.T = gsl_rng_default elif rng == 'luxury': @@ -1145,7 +1207,7 @@ cdef class GeneralDiscreteDistribution(ProbabilityDistribution): gsl_ran_discrete_free(self.dist) def get_random_element(self): - """ + r""" Get a random sample from the probability distribution. EXAMPLES:: @@ -1160,7 +1222,7 @@ cdef class GeneralDiscreteDistribution(ProbabilityDistribution): return sage.rings.integer.Integer(gsl_ran_discrete(self.r, self.dist)) def reset_distribution(self): - """ + r""" This method resets the distribution. EXAMPLES:: diff --git a/src/sage/probability/random_variable.py b/src/sage/probability/random_variable.py index 11dc4ca3cf7..4a385e55150 100644 --- a/src/sage/probability/random_variable.py +++ b/src/sage/probability/random_variable.py @@ -326,7 +326,7 @@ def __init__(self, X, P, codomain=None, check=False): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) sage: X.set() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - sage: X.entropy().n() + sage: X.entropy().n() # needs sage.libs.pari 1.99993896484375 A probability space can be defined on any list of elements:: @@ -337,7 +337,7 @@ def __init__(self, X, P, codomain=None, check=False): sage: X = DiscreteProbabilitySpace(S,P) sage: X Discrete probability space defined by {'A': 1/2, 'B': 1/4, 'C': 1/4} - sage: X.entropy().n() + sage: X.entropy().n() # needs sage.libs.pari 1.50000000000000 """ if codomain is None: diff --git a/src/sage/quadratic_forms/__init__.py b/src/sage/quadratic_forms/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index e7cd7086f09..c82a343a04e 100755 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -11,7 +11,7 @@ x^2 + 2*x*y + 3*y^2 sage: Q.discriminant() -8 - sage: Q.reduced_form() + sage: Q.reduced_form() # needs sage.libs.pari x^2 + 2*y^2 sage: Q(1, 1) 6 @@ -51,15 +51,20 @@ # **************************************************************************** from functools import total_ordering -from sage.libs.pari.all import pari_gen -from sage.rings.all import ZZ, is_fundamental_discriminant -from sage.arith.all import gcd +from sage.rings.integer_ring import ZZ +from sage.arith.misc import gcd from sage.structure.sage_object import SageObject from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import Matrix from sage.misc.cachefunc import cached_method +try: + from sage.libs.pari.all import pari_gen, pari +except ImportError: + pari_gen = () + + @total_ordering class BinaryQF(SageObject): r""" @@ -130,14 +135,13 @@ def __init__(self, a, b=None, c=None): sage: BinaryQF(0) 0 """ - from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial + from sage.rings.polynomial.multi_polynomial import MPolynomial if b is None and c is None: - if (isinstance(a, (list, tuple)) - and len(a) == 3): + if isinstance(a, (list, tuple)) and len(a) == 3: a, b, c = a elif a == 0: a = b = c = 0 - elif (is_MPolynomial(a) and a.is_homogeneous() and a.base_ring() == ZZ + elif (isinstance(a, MPolynomial) and a.is_homogeneous() and a.base_ring() == ZZ and a.degree() == 2 and a.parent().ngens() == 2): x, y = a.parent().gens() a, b, c = [a.monomial_coefficient(mon) for mon in [x**2, x*y, y**2]] @@ -162,6 +166,8 @@ def _pari_init_(self): 2*x^2 + 3*x*y + 4*y^2 sage: f._pari_init_() 'Qfb(2,3,4)' + + sage: # needs sage.libs.pari sage: pari(f) Qfb(2, 3, 4) sage: type(pari(f)) @@ -184,6 +190,7 @@ def __mul__(self, right): We explicitly compute in the group of classes of positive definite binary quadratic forms of discriminant -23:: + sage: # needs sage.libs.pari sage: R = BinaryQF_reduced_representatives(-23, primitive_only=False); R [x^2 + x*y + 6*y^2, 2*x^2 - x*y + 3*y^2, 2*x^2 + x*y + 3*y^2] sage: R[0] * R[0] @@ -194,6 +201,7 @@ def __mul__(self, right): 2*x^2 + x*y + 3*y^2 sage: (R[1] * R[1] * R[1]).reduced_form() x^2 + x*y + 6*y^2 + sage: q1 = BinaryQF(1, 1, 4) sage: M = Matrix(ZZ, [[1, 3], [0, 1]]) sage: q1*M @@ -210,8 +218,8 @@ def __mul__(self, right): return BinaryQF(self.__pari__().qfbcompraw(right)) # ...or a 2x2 matrix... if (isinstance(right.parent(), MatrixSpace) - and right.nrows() == right.ncols() == 2): - aa,bb,cc,dd = right.list() + and right.nrows() == right.ncols() == 2): + aa, bb, cc, dd = right.list() A = self.polynomial()(aa, cc) C = self.polynomial()(bb, dd) B = self.polynomial()(aa + bb, cc + dd) - A - C @@ -531,10 +539,10 @@ def from_polynomial(poly): if not isinstance(R, MPolynomialRing_base) or R.ngens() != 2: raise TypeError(f'not a bivariate polynomial ring: {R}') if not all(mon.degree() == 2 for mon in poly.monomials()): - raise ValueError(f'polynomial has monomials of degree != 2') - x,y = R.gens() + raise ValueError('polynomial has monomials of degree != 2') + x, y = R.gens() coeffs = (poly.monomial_coefficient(mon) for mon in (x**2, x*y, y**2)) - a,b,c = map(ZZ, coeffs) + a, b, c = map(ZZ, coeffs) return BinaryQF(a, b, c) @cached_method @@ -597,16 +605,16 @@ def has_fundamental_discriminant(self): sage: Q = BinaryQF([1, 0, 1]) sage: Q.discriminant() -4 - sage: Q.has_fundamental_discriminant() + sage: Q.has_fundamental_discriminant() # needs sage.libs.pari True sage: Q = BinaryQF([2, 0, 2]) sage: Q.discriminant() -16 - sage: Q.has_fundamental_discriminant() + sage: Q.has_fundamental_discriminant() # needs sage.libs.pari False """ - return is_fundamental_discriminant(self.discriminant()) + return self.discriminant().is_fundamental_discriminant() def is_primitive(self): r""" @@ -812,17 +820,17 @@ def reduced_form(self, transformation=False, algorithm="default"): sage: a = BinaryQF([33, 11, 5]) sage: a.is_reduced() False - sage: b = a.reduced_form(); b + sage: b = a.reduced_form(); b # needs sage.libs.pari 5*x^2 - x*y + 27*y^2 - sage: b.is_reduced() + sage: b.is_reduced() # needs sage.libs.pari True sage: a = BinaryQF([15, 0, 15]) sage: a.is_reduced() True - sage: b = a.reduced_form(); b + sage: b = a.reduced_form(); b # needs sage.libs.pari 15*x^2 + 15*y^2 - sage: b.is_reduced() + sage: b.is_reduced() # needs sage.libs.pari True Examples of reducing indefinite forms:: @@ -830,26 +838,26 @@ def reduced_form(self, transformation=False, algorithm="default"): sage: f = BinaryQF(1, 0, -3) sage: f.is_reduced() False - sage: g = f.reduced_form(); g + sage: g = f.reduced_form(); g # needs sage.libs.pari x^2 + 2*x*y - 2*y^2 - sage: g.is_reduced() + sage: g.is_reduced() # needs sage.libs.pari True sage: q = BinaryQF(1, 0, -1) - sage: q.reduced_form() + sage: q.reduced_form() # needs sage.libs.pari x^2 + 2*x*y - sage: BinaryQF(1, 9, 4).reduced_form(transformation=True) + sage: BinaryQF(1, 9, 4).reduced_form(transformation=True) # needs sage.libs.pari ( [ 0 -1] 4*x^2 + 7*x*y - y^2, [ 1 2] ) - sage: BinaryQF(3, 7, -2).reduced_form(transformation=True) + sage: BinaryQF(3, 7, -2).reduced_form(transformation=True) # needs sage.libs.pari ( [1 0] 3*x^2 + 7*x*y - 2*y^2, [0 1] ) - sage: BinaryQF(-6, 6, -1).reduced_form(transformation=True) + sage: BinaryQF(-6, 6, -1).reduced_form(transformation=True) # needs sage.libs.pari ( [ 0 -1] -x^2 + 2*x*y + 2*y^2, [ 1 -4] @@ -859,12 +867,12 @@ def reduced_form(self, transformation=False, algorithm="default"): Check for :trac:`34229`:: - sage: BinaryQF([1,2,3]).reduced_form(transformation=True) + sage: BinaryQF([1,2,3]).reduced_form(transformation=True) # needs sage.libs.pari ( [ 1 -1] x^2 + 2*y^2, [ 0 1] ) - sage: BinaryQF([-225, -743, -743]).reduced_form().is_reduced() + sage: BinaryQF([-225, -743, -743]).reduced_form().is_reduced() # needs sage.libs.pari True Some randomized testing:: @@ -873,7 +881,8 @@ def reduced_form(self, transformation=False, algorithm="default"): ....: f = BinaryQF([randrange(-10^3, 10^3) for _ in 'abc']) ....: if not f.discriminant().is_square(): ....: break - sage: algos = ['default', 'pari'] + sage: algos = ['default'] + sage: assert pari; algos.append('pari') # needs sage.libs.pari sage: if f.discriminant() > 0: ....: algos.append('sage') sage: a = choice(algos) @@ -919,7 +928,7 @@ def reduced_form(self, transformation=False, algorithm="default"): 'supported using PARI') if transformation: - y,g = self.__pari__().qfbredsl2() + y, g = self.__pari__().qfbredsl2() return BinaryQF(y), Matrix(ZZ, g) return BinaryQF(self.__pari__().qfbred()) @@ -1038,30 +1047,30 @@ def cycle(self, proper=False): sage: Q = BinaryQF(1, 8, -3) sage: Q.cycle() [x^2 + 8*x*y - 3*y^2, - 3*x^2 + 4*x*y - 5*y^2, - 5*x^2 + 6*x*y - 2*y^2, - 2*x^2 + 6*x*y - 5*y^2, - 5*x^2 + 4*x*y - 3*y^2, - 3*x^2 + 8*x*y - y^2] - sage: Q.cycle(proper=True) - [x^2 + 8*x*y - 3*y^2, - -3*x^2 + 4*x*y + 5*y^2, + 3*x^2 + 4*x*y - 5*y^2, 5*x^2 + 6*x*y - 2*y^2, - -2*x^2 + 6*x*y + 5*y^2, + 2*x^2 + 6*x*y - 5*y^2, 5*x^2 + 4*x*y - 3*y^2, - -3*x^2 + 8*x*y + y^2] + 3*x^2 + 8*x*y - y^2] + sage: Q.cycle(proper=True) + [x^2 + 8*x*y - 3*y^2, + -3*x^2 + 4*x*y + 5*y^2, + 5*x^2 + 6*x*y - 2*y^2, + -2*x^2 + 6*x*y + 5*y^2, + 5*x^2 + 4*x*y - 3*y^2, + -3*x^2 + 8*x*y + y^2] sage: Q = BinaryQF(1, 7, -6) sage: Q.cycle() [x^2 + 7*x*y - 6*y^2, - 6*x^2 + 5*x*y - 2*y^2, - 2*x^2 + 7*x*y - 3*y^2, - 3*x^2 + 5*x*y - 4*y^2, - 4*x^2 + 3*x*y - 4*y^2, - 4*x^2 + 5*x*y - 3*y^2, - 3*x^2 + 7*x*y - 2*y^2, - 2*x^2 + 5*x*y - 6*y^2, - 6*x^2 + 7*x*y - y^2] + 6*x^2 + 5*x*y - 2*y^2, + 2*x^2 + 7*x*y - 3*y^2, + 3*x^2 + 5*x*y - 4*y^2, + 4*x^2 + 3*x*y - 4*y^2, + 4*x^2 + 5*x*y - 3*y^2, + 3*x^2 + 7*x*y - 2*y^2, + 2*x^2 + 5*x*y - 6*y^2, + 6*x^2 + 7*x*y - y^2] TESTS: @@ -1148,7 +1157,7 @@ def cycle(self, proper=False): 'implemented for non-square discriminants') if proper: # Prop 6.10.5 in Buchmann Vollmer - C = list(self.cycle(proper=False)) # make a copy so we can modify it + C = list(self.cycle(proper=False)) # make a copy that we can modify if len(C) % 2: C += C for i in range(len(C)//2): @@ -1254,6 +1263,7 @@ def is_equivalent(self, other, proper=True): EXAMPLES:: + sage: # needs sage.libs.pari sage: Q3 = BinaryQF(4, 4, 15) sage: Q2 = BinaryQF(4, -4, 15) sage: Q2.is_equivalent(Q3) @@ -1270,15 +1280,16 @@ def is_equivalent(self, other, proper=True): sage: Q1 = BinaryQF(9, 8, -7) sage: Q2 = BinaryQF(9, -8, -7) - sage: Q1.is_equivalent(Q2, proper=True) + sage: Q1.is_equivalent(Q2, proper=True) # needs sage.libs.pari False - sage: Q1.is_equivalent(Q2, proper=False) + sage: Q1.is_equivalent(Q2, proper=False) # needs sage.libs.pari True TESTS: We check that :trac:`25888` is fixed:: + sage: # needs sage.libs.pari sage: Q1 = BinaryQF(3, 4, -2) sage: Q2 = BinaryQF(-2, 4, 3) sage: Q1.is_equivalent(Q2) == Q2.is_equivalent(Q1) @@ -1293,25 +1304,25 @@ def is_equivalent(self, other, proper=True): sage: Q = BinaryQF(0, 2, 0) sage: Q.discriminant() 4 - sage: Q.is_equivalent(Q, proper=True) + sage: Q.is_equivalent(Q, proper=True) # needs sage.libs.pari True - sage: Q.is_equivalent(Q, proper=False) + sage: Q.is_equivalent(Q, proper=False) # needs sage.libs.pari True A test for rational forms:: sage: Q1 = BinaryQF(0, 4, 2) sage: Q2 = BinaryQF(2, 4, 0) - sage: Q1.is_equivalent(Q2, proper=False) + sage: Q1.is_equivalent(Q2, proper=False) # needs sage.libs.pari True Test another part of :trac:`28989`:: sage: Q1, Q2 = BinaryQF(1, 1, -1), BinaryQF(-1, 1, 1) - sage: Q1.is_equivalent(Q2, proper=True) + sage: Q1.is_equivalent(Q2, proper=True) # needs sage.libs.pari True """ - if type(other) != type(self): + if not isinstance(other, BinaryQF): raise TypeError("%s is not a BinaryQF" % other) if self.discriminant() != other.discriminant(): return False @@ -1337,7 +1348,7 @@ def is_equivalent(self, other, proper=True): return is_properly_equiv else: g = gcd(a, b) - return is_properly_equiv or ((gcd(ao,b) == g) and ((a*ao - g**2) % (b*g) == 0)) + return is_properly_equiv or ((gcd(ao, b) == g) and ((a*ao - g**2) % (b*g) == 0)) proper_cycle = otherred.cycle(proper=True) @@ -1450,7 +1461,7 @@ def complex_point(self): EXAMPLES:: sage: Q = BinaryQF([1, 0, 1]) - sage: Q.complex_point() + sage: Q.complex_point() # needs sage.libs.pari 1.00000000000000*I """ if self.discriminant() >= 0: @@ -1506,15 +1517,13 @@ def matrix_action_right(self, M): def small_prime_value(self, Bmax=1000): r""" - Returns a prime represented by this (primitive positive definite) binary form. + Return a prime represented by this (primitive positive definite) binary form. INPUT: - - ``Bmax`` -- a positive bound on the representing integers. - - OUTPUT: + - ``Bmax`` -- a positive bound on the representing integers - A prime number represented by the form. + OUTPUT: a prime number represented by the form .. NOTE:: @@ -1523,12 +1532,14 @@ def small_prime_value(self, Bmax=1000): EXAMPLES:: - sage: [Q.small_prime_value() for Q in BinaryQF_reduced_representatives(-23, primitive_only=True)] + sage: [Q.small_prime_value() # needs sage.libs.pari + ....: for Q in BinaryQF_reduced_representatives(-23, primitive_only=True)] [23, 2, 2] - sage: [Q.small_prime_value() for Q in BinaryQF_reduced_representatives(-47, primitive_only=True)] + sage: [Q.small_prime_value() # needs sage.libs.pari + ....: for Q in BinaryQF_reduced_representatives(-47, primitive_only=True)] [47, 2, 2, 3, 3] """ - from sage.sets.all import Set + from sage.sets.set import Set from sage.arith.srange import xsrange B = 10 while True: @@ -1540,7 +1551,7 @@ def small_prime_value(self, Bmax=1000): raise ValueError("Unable to find a prime value of %s" % self) B += 10 - def solve_integer(self, n): + def solve_integer(self, n, *, algorithm="general"): r""" Solve `Q(x, y) = n` in integers `x` and `y` where `Q` is this quadratic form. @@ -1549,21 +1560,43 @@ def solve_integer(self, n): - ``n`` -- a positive integer + - ``algorithm`` -- ``"general"`` (default) or ``"cornacchia"`` + + To use the Cornacchia algorithm, the quadratic form must have + `a=1` and `b=0` and `c>0`, and ``n`` must be a prime or four + times a prime (but this is not checked). + OUTPUT: A tuple `(x, y)` of integers satisfying `Q(x, y) = n`, or ``None`` if no solution exists. - ALGORITHM: :pari:`qfbsolve` + ALGORITHM: :pari:`qfbsolve` or :pari:`qfbcornacchia` EXAMPLES:: sage: Q = BinaryQF([1, 0, 419]) - sage: Q.solve_integer(773187972) + sage: Q.solve_integer(773187972) # needs sage.libs.pari (4919, 1337) + If `Q` is of the form `[1,0,c]` as above and `n` is a prime or + four times a prime, Cornacchia's algorithm can be used, which is + typically much faster than the general method:: + + sage: Q = BinaryQF([1, 0, 12345]) + sage: n = 2^99 + 5273 + sage: Q.solve_integer(n) # needs sage.libs.pari + (-67446480057659, 7139620553488) + sage: Q.solve_integer(n, algorithm='cornacchia') # needs sage.libs.pari + (67446480057659, 7139620553488) + sage: timeit('Q.solve_integer(n)') # not tested + 125 loops, best of 3: 3.13 ms per loop + sage: timeit('Q.solve_integer(n, algorithm="cornacchia")') # not tested + 625 loops, best of 3: 18.6 ฮผs per loop + :: + sage: # needs sage.libs.pari sage: Qs = BinaryQF_reduced_representatives(-23, primitive_only=True) sage: Qs [x^2 + x*y + 6*y^2, 2*x^2 - x*y + 3*y^2, 2*x^2 + x*y + 3*y^2] @@ -1580,8 +1613,23 @@ def solve_integer(self, n): sage: Q = BinaryQF([randrange(-10^3, 10^3) for _ in 'abc']) sage: n = randrange(-10^9, 10^9) - sage: xy = Q.solve_integer(n) - sage: xy is None or Q(*xy) == n + sage: xy = Q.solve_integer(n) # needs sage.libs.pari + sage: xy is None or Q(*xy) == n # needs sage.libs.pari + True + + Also when using the ``"cornacchia"`` algorithm:: + + sage: # needs sage.libs.pari + sage: abc = [1, 0, randrange(1,10^3)] + sage: Q = BinaryQF(abc) + sage: n = random_prime(10^9) + sage: if randrange(2): + ....: n *= 4 + sage: xy1 = Q.solve_integer(n, algorithm='cornacchia') + sage: xy1 is None or Q(*xy1) == n + True + sage: xy2 = Q.solve_integer(n) + sage: (xy1 is None) == (xy2 is None) True Test for square discriminants specifically (:trac:`33026`):: @@ -1594,14 +1642,14 @@ def solve_integer(self, n): sage: Q = Q.matrix_action_right(U) sage: Q.discriminant().is_square() True - sage: xy = Q.solve_integer(n) - sage: Q(*xy) == n + sage: xy = Q.solve_integer(n) # needs sage.libs.pari + sage: Q(*xy) == n # needs sage.libs.pari True Also test the `n=0` special case separately:: - sage: xy = Q.solve_integer(0) - sage: Q(*xy) + sage: xy = Q.solve_integer(0) # needs sage.libs.pari + sage: Q(*xy) # needs sage.libs.pari 0 """ n = ZZ(n) @@ -1614,17 +1662,24 @@ def solve_integer(self, n): # https://math.stackexchange.com/a/980075 w = self.discriminant().sqrt() r = (-self._b + (w if w != self._b else -w)) / (2*self._a) - p,q = r.as_integer_ratio() - g,u,v = p.xgcd(q) - M = Matrix(ZZ, [[v,p],[-u,q]]) + p, q = r.as_integer_ratio() + _, u, v = p.xgcd(q) + M = Matrix(ZZ, [[v, p], [-u, q]]) elif self._c: - M = Matrix(ZZ, [[0,1],[1,0]]) + M = Matrix(ZZ, [[0, 1], [1, 0]]) else: - M = Matrix(ZZ, [[1,0],[0,1]]) + M = Matrix(ZZ, [[1, 0], [0, 1]]) assert M.is_unit() Q = self.matrix_action_right(M) assert not Q._c + if not Q._b: + # at this point, Q = a*x^2 + if Q._a.divides(n) and (n // Q._a).is_square(): + x = (n // Q._a).isqrt() + return tuple(row[0] * x for row in M.rows()) + return None + # at this point, Q = a*x^2 + b*x*y if not n: return tuple(M.columns()[1]) @@ -1632,10 +1687,19 @@ def solve_integer(self, n): y_num = n // x - Q._a * x if Q._b.divides(y_num): y = y_num // Q._b - return tuple(row[0]*x + row[1]*y for row in M.rows()) + return tuple([row[0]*x + row[1]*y for row in M.rows()]) return None + if algorithm == 'cornacchia': + if not (self._a.is_one() and self._b.is_zero() and self._c > 0): + raise ValueError("Cornacchia's algorithm requires a=1 and b=0 and c>0") + sol = pari.qfbcornacchia(self._c, n) + return tuple(map(ZZ, sol)) if sol else None + + if algorithm != 'general': + raise ValueError(f'algorithm {algorithm!r} is not a valid algorithm') + flag = 2 # single solution, possibly imprimitive sol = self.__pari__().qfbsolve(n, flag) return tuple(map(ZZ, sol)) if sol else None @@ -1678,23 +1742,25 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): [x^2 + 4*y^2, 2*x^2 + 2*y^2] sage: BinaryQF_reduced_representatives(-63) - [x^2 + x*y + 16*y^2, 2*x^2 - x*y + 8*y^2, 2*x^2 + x*y + 8*y^2, 3*x^2 + 3*x*y + 6*y^2, 4*x^2 + x*y + 4*y^2] + [x^2 + x*y + 16*y^2, 2*x^2 - x*y + 8*y^2, 2*x^2 + x*y + 8*y^2, + 3*x^2 + 3*x*y + 6*y^2, 4*x^2 + x*y + 4*y^2] The number of inequivalent reduced binary forms with a fixed negative - fundamental discriminant D is the class number of the quadratic field + fundamental discriminant `D` is the class number of the quadratic field `\QQ(\sqrt{D})`:: sage: len(BinaryQF_reduced_representatives(-13*4)) 2 - sage: QuadraticField(-13*4, 'a').class_number() + sage: QuadraticField(-13*4, 'a').class_number() # needs sage.rings.number_field 2 + + sage: # needs sage.libs.pari sage: p = next_prime(2^20); p 1048583 sage: len(BinaryQF_reduced_representatives(-p)) 689 - sage: QuadraticField(-p, 'a').class_number() + sage: QuadraticField(-p, 'a').class_number() # needs sage.rings.number_field 689 - sage: BinaryQF_reduced_representatives(-23*9) [x^2 + x*y + 52*y^2, 2*x^2 - x*y + 26*y^2, @@ -1717,7 +1783,7 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): sage: BinaryQF_reduced_representatives(73) [4*x^2 + 3*x*y - 4*y^2] - sage: BinaryQF_reduced_representatives(76, primitive_only=True) + sage: BinaryQF_reduced_representatives(76, primitive_only=True) # needs sage.libs.pari [-3*x^2 + 4*x*y + 5*y^2, 3*x^2 + 4*x*y - 5*y^2] sage: BinaryQF_reduced_representatives(136) @@ -1732,9 +1798,9 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): sage: BinaryQF_reduced_representatives(148, proper=False, primitive_only=False) [x^2 + 12*x*y - y^2, 4*x^2 + 6*x*y - 7*y^2, 6*x^2 + 2*x*y - 6*y^2] - sage: BinaryQF_reduced_representatives(148, proper=False, primitive_only=True) + sage: BinaryQF_reduced_representatives(148, proper=False, primitive_only=True) # needs sage.libs.pari [x^2 + 12*x*y - y^2, 4*x^2 + 6*x*y - 7*y^2] - sage: BinaryQF_reduced_representatives(148, proper=True, primitive_only=True) + sage: BinaryQF_reduced_representatives(148, proper=True, primitive_only=True) # needs sage.libs.pari [-7*x^2 + 6*x*y + 4*y^2, x^2 + 12*x*y - y^2, 4*x^2 + 6*x*y - 7*y^2] sage: BinaryQF_reduced_representatives(148, proper=True, primitive_only=False) [-7*x^2 + 6*x*y + 4*y^2, @@ -1753,9 +1819,9 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): x^2 + 10*x*y, 2*x^2 + 10*x*y, 5*x^2 + 10*x*y] - sage: BinaryQF_reduced_representatives(10^2, proper=False, primitive_only=True) + sage: BinaryQF_reduced_representatives(10^2, proper=False, primitive_only=True) # needs sage.libs.pari [-3*x^2 + 10*x*y, -x^2 + 10*x*y, x^2 + 10*x*y] - sage: BinaryQF_reduced_representatives(10^2, proper=True, primitive_only=True) + sage: BinaryQF_reduced_representatives(10^2, proper=True, primitive_only=True) # needs sage.libs.pari [-3*x^2 + 10*x*y, -x^2 + 10*x*y, x^2 + 10*x*y, 3*x^2 + 10*x*y] sage: BinaryQF_reduced_representatives(10^2, proper=True, primitive_only=False) [-4*x^2 + 10*x*y, @@ -1773,7 +1839,7 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): # For a fundamental discriminant all forms are primitive so we need not check: if primitive_only: - primitive_only = not is_fundamental_discriminant(D) + primitive_only = not D.is_fundamental_discriminant() form_list = [] @@ -1788,7 +1854,7 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): c = ZZ(0) # -b/2 < a <= b/2 for a in xsrange((-b/2).floor() + 1, (b/2).floor() + 1): - if (not primitive_only) or (gcd([a,b,c]) == 1): + if not primitive_only or (gcd([a, b, c]) == 1): form_list.append(BinaryQF(a, b, c)) # We follow the description of Buchmann/Vollmer 6.7.1. They # enumerate all reduced forms. We only want representatives. @@ -1822,14 +1888,14 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): a4 = 4*a s = D + a*a4 w = 1+(s-1).isqrt() if s > 0 else 0 - if w%2 != D%2: + if w % 2 != D % 2: w += 1 for b in xsrange(w, a+1, 2): t = b*b-D if t % a4 == 0: c = t // a4 - if (not primitive_only) or gcd([a, b, c]) == 1: - if b>0 and a>b and c>a: + if not primitive_only or gcd([a, b, c]) == 1: + if c > a > b > 0: form_list.append(BinaryQF([a, -b, c])) form_list.append(BinaryQF([a, b, c])) if not proper or D > 0: diff --git a/src/sage/quadratic_forms/constructions.py b/src/sage/quadratic_forms/constructions.py index dd9f83216d3..2fe117d2e29 100644 --- a/src/sage/quadratic_forms/constructions.py +++ b/src/sage/quadratic_forms/constructions.py @@ -6,12 +6,11 @@ ## from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.quadratic_forms.quadratic_form import QuadraticForm - def BezoutianQuadraticForm(f, g): r""" Compute the Bezoutian of two polynomials defined over a common base ring. This is defined by @@ -24,18 +23,16 @@ def BezoutianQuadraticForm(f, g): INPUT: - - `f`, `g` -- polynomials in `R[x]`, for some ring `R` - - OUTPUT: + - ``f``, ``g`` -- polynomials in `R[x]`, for some ring `R` - a quadratic form over `R` + OUTPUT: a quadratic form over `R` EXAMPLES:: sage: R = PolynomialRing(ZZ, 'x') sage: f = R([1,2,3]) sage: g = R([2,5]) - sage: Q = BezoutianQuadraticForm(f, g) ; Q + sage: Q = BezoutianQuadraticForm(f, g); Q # needs sage.libs.singular Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 -12 ] [ * -15 ] @@ -46,7 +43,7 @@ def BezoutianQuadraticForm(f, g): """ # Check that f and g are polynomials with a common base ring - if not is_Polynomial(f) or not is_Polynomial(g): + if not isinstance(f, Polynomial) or not isinstance(g, Polynomial): raise TypeError("one of your inputs is not a polynomial") if f.base_ring() != g.base_ring(): # TO DO: Change this to allow coercion! raise TypeError("these polynomials are not defined over the same coefficient ring") @@ -77,8 +74,8 @@ def HyperbolicPlane_quadratic_form(R, r=1): INPUT: - - `R`: a ring - - `n` (integer, default 1) number of copies + - ``R``: a ring + - ``n`` (integer, default 1) number of copies EXAMPLES:: @@ -93,4 +90,4 @@ def HyperbolicPlane_quadratic_form(R, r=1): raise TypeError("the multiplicity r must be a natural number") H = QuadraticForm(R, 2, [0, 1, 0]) - return sum([H for i in range(r - 1)], H) + return sum([H for i in range(r - 1)], H) diff --git a/src/sage/quadratic_forms/count_local_2.pyx b/src/sage/quadratic_forms/count_local_2.pyx index 36b6b9d593c..3ce05a3a413 100644 --- a/src/sage/quadratic_forms/count_local_2.pyx +++ b/src/sage/quadratic_forms/count_local_2.pyx @@ -1,36 +1,29 @@ r""" Optimized counting of congruence solutions """ - -from sage.arith.all import valuation, kronecker_symbol, is_prime +from sage.arith.misc import is_prime, kronecker as kronecker_symbol, valuation from sage.rings.finite_rings.integer_mod import Mod from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from sage.rings.integer_ring import ZZ - -from sage.rings.finite_rings.integer_mod cimport IntegerMod_gmp -from sage.sets.set import Set - def count_modp__by_gauss_sum(n, p, m, Qdet): - """ - Returns the number of solutions of Q(x) = m over the finite field - Z/pZ, where p is a prime number > 2 and Q is a non-degenerate - quadratic form of dimension n >= 1 and has Gram determinant Qdet. + r""" + Return the number of solutions of `Q(x) = m` over the finite field + `\ZZ/p\ZZ`, where `p` is a prime number > 2 and `Q` is a non-degenerate + quadratic form of dimension `n \geq 1` and has Gram determinant ``Qdet``. REFERENCE: - These are defined in Table 1 on p363 of Hanke's "Local - Densities..." paper. + + These are defined in Table 1 on p363 of Hanke's "Local Densities..." paper. INPUT: - - n -- an integer >= 1 - - p -- a prime number > 2 - - m -- an integer - - Qdet -- a integer which is non-zero mod p + - ``n`` -- an integer `\geq 1` + - ``p`` -- a prime number > 2 + - ``m`` -- an integer + - ``Qdet`` -- a integer which is non-zero mod `p` - OUTPUT: - an integer >= 0 + OUTPUT: an integer `\geq 0` EXAMPLES:: @@ -44,7 +37,9 @@ def count_modp__by_gauss_sum(n, p, m, Qdet): 12 sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: [Q.count_congruence_solutions(3, 1, m, None, None) == count_modp__by_gauss_sum(3, 3, m, 1) for m in range(3)] + sage: [Q.count_congruence_solutions(3, 1, m, None, None) + ....: == count_modp__by_gauss_sum(3, 3, m, 1) + ....: for m in range(3)] [True, True, True] @@ -56,7 +51,9 @@ def count_modp__by_gauss_sum(n, p, m, Qdet): 6 sage: Q = DiagonalQuadraticForm(ZZ, [1,1,2]) - sage: [Q.count_congruence_solutions(3, 1, m, None, None) == count_modp__by_gauss_sum(3, 3, m, 2) for m in range(3)] + sage: [Q.count_congruence_solutions(3, 1, m, None, None) + ....: == count_modp__by_gauss_sum(3, 3, m, 2) + ....: for m in range(3)] [True, True, True] @@ -75,25 +72,21 @@ def count_modp__by_gauss_sum(n, p, m, Qdet): # Compute the Gauss sum neg1 = -1 - if not (m % p): + if not m % p: if n % 2: - count = (p**(n-1)) + count = p**(n-1) else: - count = (p**(n-1)) + (p-1) * (p**((n-2)/2)) * kronecker_symbol(((neg1**(n/2)) * Qdet) % p, p) + count = p**(n-1) + (p-1) * (p**((n-2)//2)) * kronecker_symbol(((neg1**(n//2)) * Qdet) % p, p) else: if n % 2: - count = (p**(n-1)) + (p**((n-1)/2)) * kronecker_symbol(((neg1**((n-1)/2)) * Qdet * m) % p, p) + count = p**(n-1) + p**((n-1)//2) * kronecker_symbol(((neg1**((n-1)//2)) * Qdet * m) % p, p) else: - count = (p**(n-1)) - (p**((n-2)/2)) * kronecker_symbol(((neg1**(n/2)) * Qdet) % p, p) + count = p**(n-1) - p**((n-2)//2) * kronecker_symbol(((neg1**(n//2)) * Qdet) % p, p) # Return the result return count - - - - cdef CountAllLocalTypesNaive_cdef(Q, p, k, m, zvec, nzvec): """ This Cython routine is documented in its Python wrapper method @@ -104,33 +97,23 @@ cdef CountAllLocalTypesNaive_cdef(Q, p, k, m, zvec, nzvec): cdef long ptr # Used to increment the vector cdef long solntype # Used to store the kind of solution we find - # Some shortcuts and definitions n = Q.dim() R = p ** k - Q1 = Q.base_change_to(IntegerModRing(R)) - - - # Cython Variables - cdef IntegerMod_gmp zero, one - zero = IntegerMod_gmp(IntegerModRing(R), 0) - one = IntegerMod_gmp(IntegerModRing(R), 1) - - + Q1 = Q.change_ring(IntegerModRing(R)) # Initialize the counting vector - count_vector = [0 for i in range(6)] + count_vector = [0 for i in range(6)] # Initialize v = (0, ... , 0) - v = [Mod(0, R) for i in range(n)] - + v = [Mod(0, R) for i in range(n)] # Some declarations to speed up the loop R_n = R ** n m1 = Mod(m, R) # Count the local solutions - for i from 0 <= i < R_n: + for i in range(R_n): # Perform a carry (when value = R-1) until we can increment freely ptr = len(v) @@ -139,24 +122,22 @@ cdef CountAllLocalTypesNaive_cdef(Q, p, k, m, zvec, nzvec): ptr += -1 # Only increment if we're not already at the zero vector =) - if (ptr > 0): + if ptr > 0: v[ptr-1] += 1 - # Evaluate Q(v) quickly tmp_val = Mod(0, R) for a from 0 <= a < n: for b from a <= b < n: - tmp_val += Q1[a,b] * v[a] * v[b] + tmp_val += Q1[a, b] * v[a] * v[b] # Sort the solution by it's type - #if (Q1(v) == m1): - if (tmp_val == m1): + # if Q1(v) == m1: + if tmp_val == m1: solntype = local_solution_type_cdef(Q1, p, v, zvec, nzvec) - if (solntype != 0): + if solntype != 0: count_vector[solntype] += 1 - # Generate the Bad-type and Total counts count_vector[3] = count_vector[4] + count_vector[5] count_vector[0] = count_vector[1] + count_vector[2] + count_vector[3] @@ -174,10 +155,10 @@ def CountAllLocalTypesNaive(Q, p, k, m, zvec, nzvec): INPUT: - - `Q` -- quadratic form over `\ZZ` - - `p` -- prime number > 0 - - `k` -- an integer > 0 - - `m` -- an integer (depending only on mod `p^k`) + - ``Q`` -- quadratic form over `\ZZ` + - ``p`` -- prime number > 0 + - ``k`` -- an integer > 0 + - ``m`` -- an integer (depending only on mod `p^k`) - ``zvec``, ``nzvec`` -- a list of integers in ``range(Q.dim())``, or ``None`` OUTPUT: @@ -200,19 +181,14 @@ def CountAllLocalTypesNaive(Q, p, k, m, zvec, nzvec): return CountAllLocalTypesNaive_cdef(Q, p, k, m, zvec, nzvec) - - - - - cdef local_solution_type_cdef(Q, p, w, zvec, nzvec): """ - Internal routine to check if a given solution vector w (of Q(w) = - m mod p^k) is of a certain local type and satisfies certain - congruence conditions mod p. + Internal routine to check if a given solution vector `w` (of `Q(w) = + m` mod `p^k`) is of a certain local type and satisfies certain + congruence conditions mod `p`. - NOTE: No internal checking is done to test if p is a prime >=2, or - that Q has the same size as w. + NOTE: No internal checking is done to test if `p` is a prime >=2, or + that Q has the same size as `w`. """ cdef long i @@ -222,91 +198,87 @@ cdef local_solution_type_cdef(Q, p, w, zvec, nzvec): # Check if the solution satisfies the zvec "zero" congruence conditions # (either zvec is empty or its components index the zero vector mod p) - if (zvec is None) or (not zvec): + if zvec is None or not zvec: zero_flag = True else: zero_flag = False i = 0 - while ( (i < len(zvec)) and ((w[zvec[i]] % p) == 0) ): # Increment so long as our entry is zero (mod p) + while i < len(zvec) and not w[zvec[i]] % p: # Increment so long as our entry is zero (mod p) i += 1 - if (i == len(zvec)): # If we make it through all entries then the solution is zero (mod p) + if i == len(zvec): # If we make it through all entries then the solution is zero (mod p) zero_flag = True - # DIAGNOSTIC - #print("IsLocalSolutionType: Finished the Zero congruence condition test \n") + # print("IsLocalSolutionType: Finished the Zero congruence condition test \n") if not zero_flag: return <long> 0 # DIAGNOSTIC - #print("IsLocalSolutionType: Passed the Zero congruence condition test \n") + # print("IsLocalSolutionType: Passed the Zero congruence condition test \n") # Check if the solution satisfies the nzvec "nonzero" congruence conditions # (nzvec is non-empty and its components index a non-zero vector mod p) - if (nzvec is None): + if nzvec is None: nonzero_flag = True - elif (len(nzvec) == 0): + elif len(nzvec) == 0: nonzero_flag = False # Trivially no solutions in this case! else: nonzero_flag = False i = 0 - while ((not nonzero_flag) and (i < len(nzvec))): - if ((w[nzvec[i]] % p) != 0): + while not nonzero_flag and i < len(nzvec): + if w[nzvec[i]] % p: nonzero_flag = True # The non-zero condition is satisfied when we find one non-zero entry i += 1 if not nonzero_flag: return <long> 0 - # Check if the solution has the appropriate (local) type: # ------------------------------------------------------- # 1: Check Good-type - for i from 0 <= i < n: - if (((w[i] % p) != 0) and ((Q[i,i] % p) != 0)): + for i in range(n): + if w[i] % p and Q[i, i] % p: return <long> 1 - if (p == 2): - for i from 0 <= i < (n - 1): - if (((Q[i,i+1] % p) != 0) and (((w[i] % p) != 0) or ((w[i+1] % p) != 0))): + if p == 2: + for i in range(n - 1): + if Q[i, i+1] % p and (w[i] % p or w[i+1] % p): return <long> 1 - # 2: Check Zero-type Zero_flag = True - for i from 0 <= i < n: - if ((w[i] % p) != 0): + for i in range(n): + if w[i] % p: Zero_flag = False if Zero_flag: return <long> 2 - # Check if wS1 is zero or not wS1_nonzero_flag = False for i from 0 <= i < n: # Compute the valuation of each index, allowing for off-diagonal terms - if (Q[i,i] == 0): - if (i == 0): - val = valuation(Q[i,i+1], p) # Look at the term to the right - elif (i == n - 1): - val = valuation(Q[i-1,i], p) # Look at the term above + if Q[i, i] == 0: + if i == 0: + val = valuation(Q[i, i+1], p) # Look at the term to the right + elif i == n - 1: + val = valuation(Q[i-1, i], p) # Look at the term above else: - val = valuation(Q[i,i+1] + Q[i-1,i], p) # Finds the valuation of the off-diagonal term since only one isn't zero + val = valuation(Q[i, i+1] + Q[i-1, i], p) # Finds the valuation of the off-diagonal term since only one isn't zero else: - val = valuation(Q[i,i], p) + val = valuation(Q[i, i], p) # Test each index - if ((val == 1) and ((w[i] % p) != 0)): + if val == 1 and w[i] % p: wS1_nonzero_flag = True # 4: Check Bad-type I - if (wS1_nonzero_flag is True): + if wS1_nonzero_flag: return <long> 4 # 5: Check Bad-type II - if (wS1_nonzero_flag is False): + if not wS1_nonzero_flag: return <long> 5 # Error if we get here! =o diff --git a/src/sage/quadratic_forms/extras.py b/src/sage/quadratic_forms/extras.py index be7f05b0439..7bdba23c32e 100644 --- a/src/sage/quadratic_forms/extras.py +++ b/src/sage/quadratic_forms/extras.py @@ -4,7 +4,7 @@ from sage.matrix.constructor import matrix from sage.structure.element import is_Matrix -from sage.arith.all import legendre_symbol +from sage.arith.misc import legendre_symbol from sage.rings.integer_ring import ZZ @@ -25,7 +25,7 @@ def is_triangular_number(n, return_value=False): - ``n`` - an integer - ``return_value`` - a boolean set to ``False`` by default. If set to - ``True`` the function returns a pair made of a boolean and the value ``v`` + ``True`` the function returns a pair made of a boolean and the value `v` such that `v(v+1)/2 = n`. EXAMPLES:: @@ -75,11 +75,11 @@ def is_triangular_number(n, return_value=False): def extend_to_primitive(A_input): - """ + r""" Given a matrix (resp. list of vectors), extend it to a square matrix (resp. list of vectors), such that its determinant is the gcd of its minors (i.e. extend the basis of a lattice to a - "maximal" one in Z^n). + "maximal" one in `\ZZ^n`). Author(s): Gonzalo Tornaria and Jonathan Hanke. @@ -101,7 +101,6 @@ def extend_to_primitive(A_input): sage: extend_to_primitive([vector([1,2,3])]) [(1, 2, 3), (0, 1, 1), (-1, 0, 0)] - """ # Deal with a list of vectors if not is_Matrix(A_input): @@ -145,14 +144,14 @@ def extend_to_primitive(A_input): def least_quadratic_nonresidue(p): - """ - Return the smallest positive integer quadratic non-residue in Z/pZ for primes p>2. + r""" + Return the smallest positive integer quadratic non-residue in `\ZZ/p\ZZ` for primes `p>2`. EXAMPLES:: sage: least_quadratic_nonresidue(5) 2 - sage: [least_quadratic_nonresidue(p) for p in prime_range(3,100)] + sage: [least_quadratic_nonresidue(p) for p in prime_range(3, 100)] # needs sage.libs.pari [2, 2, 3, 2, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 2, 2, 2, 7, 5, 3, 2, 3, 5] TESTS: diff --git a/src/sage/quadratic_forms/genera/__init__.py b/src/sage/quadratic_forms/genera/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index 0fc43f33c62..d9c298f5f0a 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -1,7 +1,7 @@ +# sage.doctest: needs sage.libs.pari r""" Genus - AUTHORS: - David Kohel & Gabriele Nebe (2007): First created @@ -19,24 +19,19 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from copy import copy, deepcopy + from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method -from sage.arith.all import LCM, fundamental_discriminant +from sage.arith.functions import lcm as LCM +from sage.arith.misc import fundamental_discriminant from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import matrix -from sage.rings.integer_ring import IntegerRing, ZZ -from sage.rings.rational_field import RationalField, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.rings.integer import Integer -from sage.interfaces.gp import gp -from sage.libs.pari import pari -from sage.rings.finite_rings.finite_field_constructor import FiniteField -from copy import copy, deepcopy from sage.misc.verbose import verbose -from sage.functions.gamma import gamma -from sage.functions.transcendental import zeta -from sage.symbolic.constants import pi -from sage.symbolic.ring import SR from sage.quadratic_forms.special_values import quadratic_L_function__exact lazy_import('sage.quadratic_forms.genera.normal_form', '_min_nonsquare') lazy_import('sage.interfaces.magma', 'magma') @@ -86,7 +81,6 @@ def genera(sig_pair, determinant, max_scale=None, even=False): """ from sage.misc.mrange import mrange_iter # input checks - ZZ = IntegerRing() determinant = ZZ(determinant) sig_pair = (ZZ(sig_pair[0]), ZZ(sig_pair[1])) even = bool(even) @@ -126,6 +120,10 @@ def genera(sig_pair, determinant, max_scale=None, even=False): return genera +# #35557: In Python < 3.10, a staticmethod cannot be called directly +_genera_staticmethod = staticmethod(genera) + + def _local_genera(p, rank, det_val, max_scale, even): r""" Return all `p`-adic genera with the given conditions. @@ -139,7 +137,7 @@ def _local_genera(p, rank, det_val, max_scale, even): - ``rank`` -- the rank of this genus - - ``det_val`` -- valuation of the determinant at p + - ``det_val`` -- valuation of the determinant at `p` - ``max_scale`` -- an integer the maximal scale of a jordan block @@ -176,8 +174,8 @@ def _local_genera(p, rank, det_val, max_scale, even): """ from sage.misc.mrange import cantor_product from sage.combinat.integer_lists.invlex import IntegerListsLex - scales_rks = [] # contains possibilities for scales and ranks - for rkseq in IntegerListsLex(rank, length=max_scale+1): # rank sequences + scales_rks = [] # contains possibilities for scales and ranks + for rkseq in IntegerListsLex(rank, length=max_scale + 1): # rank sequences # sum(rkseq) = rank # len(rkseq) = max_scale + 1 # now assure that we get the right determinant @@ -280,7 +278,7 @@ def _blocks(b, even_only=False): # odd case if not even_only: # format (det, oddity) - for s in [(1,2), (5,6), (1,6), (5,2), (7,0), (3,4)]: + for s in [(1, 2), (5, 6), (1, 6), (5, 2), (7, 0), (3, 4)]: b1 = copy(b) b1[2] = s[0] b1[3] = 1 @@ -291,22 +289,22 @@ def _blocks(b, even_only=False): b1 = copy(b) b1[3] = 0 b1[4] = 0 - d = (-1)**(rk//2) % 8 + d = (-1)**(rk // 2) % 8 for det in [d, d * (-3) % 8]: b1 = copy(b1) b1[2] = det blocks.append(b1) # odd case if not even_only: - for s in [(1,2), (5,6), (1,6), (5,2), (7,0), (3,4)]: + for s in [(1, 2), (5, 6), (1, 6), (5, 2), (7, 0), (3, 4)]: b1 = copy(b) - b1[2] = s[0]*(-1)**(rk//2 -1) % 8 + b1[2] = s[0]*(-1)**(rk // 2 - 1) % 8 b1[3] = 1 b1[4] = s[1] blocks.append(b1) - for s in [(1,4), (5,0)]: + for s in [(1, 4), (5, 0)]: b1 = copy(b) - b1[2] = s[0]*(-1)**(rk//2 - 2) % 8 + b1[2] = s[0]*(-1)**(rk // 2 - 2) % 8 b1[3] = 1 b1[4] = s[1] blocks.append(b1) @@ -332,7 +330,7 @@ def Genus(A, factored_determinant=None): - ``A`` -- a symmetric matrix with integer coefficients - - ``factored_determinant`` -- (default: ``None``) a factorization object + - ``factored_determinant`` -- (default: ``None``) a :class:`Factorization` object, the factored determinant of ``A`` OUTPUT: @@ -370,7 +368,7 @@ def Genus(A, factored_determinant=None): for f in D: p = f[0] val = f[1] - symbol = p_adic_symbol(A, p, val = val) + symbol = p_adic_symbol(A, p, val=val) G = Genus_Symbol_p_adic_ring(p, symbol) local_symbols.append(G) return GenusSymbol_global_ring(sig_pair, local_symbols, representative=A) @@ -406,11 +404,10 @@ def LocalGenusSymbol(A, p): Genus symbol at 3: 1^-2 """ val = A.determinant().valuation(p) - symbol = p_adic_symbol(A, p, val = val) + symbol = p_adic_symbol(A, p, val=val) return Genus_Symbol_p_adic_ring(p, symbol) - def is_GlobalGenus(G): r""" Return if `G` represents the genus of a global quadratic form or lattice. @@ -419,9 +416,7 @@ def is_GlobalGenus(G): - ``G`` -- :class:`GenusSymbol_global_ring` object - OUTPUT: - - - boolean + OUTPUT: boolean EXAMPLES:: @@ -430,12 +425,11 @@ def is_GlobalGenus(G): sage: G = Genus(A) sage: is_GlobalGenus(G) True - sage: G=Genus(matrix.diagonal([2, 2, 2, 2])) - sage: G._local_symbols[0]._symbol=[[0,2,3,0,0], [1,2,5,1,0]] + sage: G = Genus(matrix.diagonal([2, 2, 2, 2])) + sage: G._local_symbols[0]._symbol = [[0,2,3,0,0], [1,2,5,1,0]] sage: G._representative=None sage: is_GlobalGenus(G) False - """ D = G.determinant() r, s = G.signature_pair() @@ -445,18 +439,20 @@ def is_GlobalGenus(G): sym = loc._symbol v = sum([ss[0] * ss[1] for ss in sym]) a = D // (p**v) - b = Integer(prod([ss[2] for ss in sym])) + b = ZZ.prod(ss[2] for ss in sym) if p == 2: if not is_2_adic_genus(sym): verbose(mesg="False in is_2_adic_genus(sym)", level=2) return False if (a*b).kronecker(p) != 1: - verbose(mesg="False in (%s*%s).kronecker(%s)"%(a,b,p), level=2) + verbose(mesg="False in (%s*%s).kronecker(%s)" % (a, b, p), + level=2) return False oddity -= loc.excess() else: if a.kronecker(p) != b: - verbose(mesg="False in %s.kronecker(%s) != *%s"%(a,p,b), level=2) + verbose(mesg="False in %s.kronecker(%s) != *%s" % (a, p, b), + level=2) return False oddity += loc.excess() if oddity % 8 != 0: @@ -465,7 +461,6 @@ def is_GlobalGenus(G): return True - def is_2_adic_genus(genus_symbol_quintuple_list): r""" Given a `2`-adic local symbol (as the underlying list of quintuples) @@ -476,9 +471,7 @@ def is_2_adic_genus(genus_symbol_quintuple_list): - ``genus_symbol_quintuple_list`` -- a quintuple of integers (with certain restrictions). - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -494,7 +487,8 @@ def is_2_adic_genus(genus_symbol_quintuple_list): sage: is_2_adic_genus(G3.symbol_tuple_list()) # This raises an error Traceback (most recent call last): ... - TypeError: The genus symbols are not quintuples, so it's not a genus symbol for the prime p=2. + TypeError: The genus symbols are not quintuples, + so it's not a genus symbol for the prime p=2. sage: A = Matrix(ZZ, 2, 2, [1,0,0,2]) sage: G2 = LocalGenusSymbol(A, 2) @@ -520,30 +514,27 @@ def is_2_adic_genus(genus_symbol_quintuple_list): if s[2] % 8 in (3, 5): if not s[4] in (2, 4, 6): return False - if (s[1] - s[4])% 2 == 1: + if (s[1] - s[4]) % 2 == 1: return False if s[3] == 0 and s[4] != 0: return False return True - def canonical_2_adic_compartments(genus_symbol_quintuple_list): r""" Given a `2`-adic local symbol (as the underlying list of quintuples) this returns a list of lists of indices of the - genus_symbol_quintuple_list which are in the same compartment. A + ``genus_symbol_quintuple_list`` which are in the same compartment. A compartment is defined to be a maximal interval of Jordan components all (scaled) of type I (i.e. odd). INPUT: - ``genus_symbol_quintuple_list`` -- a quintuple of integers (with certain - restrictions). - - OUTPUT: + restrictions) - a list of lists of integers. + OUTPUT: a list of lists of integers EXAMPLES:: @@ -597,11 +588,12 @@ def canonical_2_adic_compartments(genus_symbol_quintuple_list): i += 1 return compartments + def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): r""" Given a `2`-adic local symbol (as the underlying list of quintuples) this returns a list of lists of indices of the - genus_symbol_quintuple_list which are in the same train. A train + ``genus_symbol_quintuple_list`` which are in the same train. A train is defined to be a maximal interval of Jordan components so that at least one of each adjacent pair (allowing zero-dimensional Jordan components) is (scaled) of type I (i.e. odd). @@ -615,9 +607,7 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): restrictions). - ``compartments`` -- this argument is deprecated - OUTPUT: - - a list of lists of distinct integers. + OUTPUT: a list of lists of distinct integers EXAMPLES:: @@ -648,7 +638,9 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): [[0, 2, 3, 0, 0]] sage: canonical_2_adic_trains(G2.symbol_tuple_list()) [[0]] - sage: symbol = [[0, 1, 1, 1, 1], [1, 2, -1, 0, 0], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1], [4, 1, 1, 1, 1], [5, 2, -1, 0, 0], [7, 1, 1, 1, 1], [10, 1, 1, 1, 1], [11, 1, 1, 1, 1], [12, 1, 1, 1, 1]] + sage: symbol = [[0, 1, 1, 1, 1], [1, 2, -1, 0, 0], [2, 1, 1, 1, 1], + ....: [3, 1, 1, 1, 1], [4, 1, 1, 1, 1], [5, 2, -1, 0, 0], + ....: [7, 1, 1, 1, 1], [10, 1, 1, 1, 1], [11, 1, 1, 1, 1], [12, 1, 1, 1, 1]] sage: canonical_2_adic_trains(symbol) [[0, 1, 2, 3, 4, 5], [6], [7, 8, 9]] @@ -661,7 +653,6 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): .. NOTE:: See [CS1999]_, pp. 381-382 for definitions and examples. - """ if compartments is not None: from sage.misc.superseded import deprecation @@ -670,16 +661,16 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): # avoid a special case for the end of symbol # if a jordan component has rank zero it is considered even. symbol = genus_symbol_quintuple_list - symbol.append([symbol[-1][0]+1, 0, 1, 0, 0]) #We have just modified the input globally! + symbol.append([symbol[-1][0]+1, 0, 1, 0, 0]) # We have just modified the input globally! # Hence, we have to remove the last entry of symbol at the end. try: trains = [] new_train = [0] - for i in range(1,len(symbol)-1): + for i in range(1, len(symbol) - 1): # start a new train if there are two adjacent even symbols prev, cur = symbol[i-1:i+1] - if cur[0] - prev[0] > 2: + if cur[0] - prev[0] > 2: trains.append(new_train) new_train = [i] # create a new train starting at elif (cur[0] - prev[0] == 2) and cur[3]*prev[3] == 0: @@ -696,9 +687,10 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): trains.append(new_train) return trains finally: - #revert the input list to its original state + # revert the input list to its original state symbol.pop() + def canonical_2_adic_reduction(genus_symbol_quintuple_list): r""" Given a `2`-adic local symbol (as the underlying list of quintuples) @@ -715,9 +707,7 @@ def canonical_2_adic_reduction(genus_symbol_quintuple_list): - ``compartments`` -- a list of lists of distinct integers (optional) - OUTPUT: - - a list of lists of distinct integers. + OUTPUT: a list of lists of distinct integers. EXAMPLES:: @@ -763,18 +753,18 @@ def canonical_2_adic_reduction(genus_symbol_quintuple_list): # Canonical determinants: for i in range(len(genus_symbol_quintuple_list)): d = genus_symbol_quintuple_list[i][2] - if d in (1,7): + if d in (1, 7): canonical_symbol[i][2] = 1 else: canonical_symbol[i][2] = -1 # Oddity fusion: compartments = canonical_2_adic_compartments(genus_symbol_quintuple_list) for compart in compartments: - oddity = sum([ genus_symbol_quintuple_list[i][4] for i in compart ]) % 8 + oddity = sum([genus_symbol_quintuple_list[i][4] for i in compart]) % 8 for i in compart: genus_symbol_quintuple_list[i][4] = 0 genus_symbol_quintuple_list[compart[0]][4] = oddity - verbose(mesg="End oddity fusion: %s" %canonical_symbol, level=2) + verbose(mesg="End oddity fusion: %s" % canonical_symbol, level=2) # Sign walking: trains = canonical_2_adic_trains(genus_symbol_quintuple_list) for train in trains: @@ -788,7 +778,7 @@ def canonical_2_adic_reduction(genus_symbol_quintuple_list): if t1-1 in compart or t1 in compart: o = canonical_symbol[compart[0]][4] canonical_symbol[compart[0]][4] = (o+4) % 8 - verbose(mesg="End sign walking: %s" %canonical_symbol, level=2) + verbose(mesg="End sign walking: %s" % canonical_symbol, level=2) return canonical_symbol @@ -801,9 +791,7 @@ def basis_complement(B): - ``B`` -- matrix over a field in row echelon form - OUTPUT: - - a rectangular matrix over a field + OUTPUT: a rectangular matrix over a field EXAMPLES:: @@ -846,9 +834,7 @@ def signature_pair_of_matrix(A): - ``A`` -- symmetric matrix (assumed to be non-degenerate) - OUTPUT: - - - `(p, n)` -- a pair (tuple) of integers. + OUTPUT: `(p, n)` -- a pair (tuple) of integers. EXAMPLES:: @@ -904,9 +890,7 @@ def p_adic_symbol(A, p, val): divisor of `A` needed to obtain enough precision. Calculation is modulo `p` to the ``val+3``. - OUTPUT: - - a list of lists of integers + OUTPUT: a list of lists of integers EXAMPLES:: @@ -922,39 +906,41 @@ def p_adic_symbol(A, p, val): """ if p % 2 == 0: return two_adic_symbol(A, val) - m0 = min([ c.valuation(p) for c in A.list() ]) + + from sage.rings.finite_rings.finite_field_constructor import FiniteField + + m0 = min(c.valuation(p) for c in A.list()) q = p**m0 n = A.nrows() - A = MatrixSpace(IntegerRing(), n, n)([ c // q for c in A.list() ]) + A = MatrixSpace(ZZ, n, n)([c // q for c in A.list()]) A_p = MatrixSpace(FiniteField(p), n, n)(A) B_p = A_p.kernel().echelonized_basis_matrix() if B_p.nrows() == 0: e0 = Integer(A_p.det()).kronecker(p) n0 = A.nrows() - return [ [m0, n0, e0] ] + return [[m0, n0, e0]] else: C_p = basis_complement(B_p) e0 = Integer((C_p * A_p * C_p.transpose()).det()).kronecker(p) n0 = C_p.nrows() - sym = [ [0, n0, e0] ] + sym = [[0, n0, e0]] r = B_p.nrows() - B = MatrixSpace(IntegerRing(), r, n)(B_p) - C = MatrixSpace(IntegerRing(), n - r, n)(C_p) + B = MatrixSpace(ZZ, r, n)(B_p) + C = MatrixSpace(ZZ, n - r, n)(C_p) # Construct the blocks for the Jordan decomposition [F,X;X,A_new] - F = MatrixSpace(RationalField(), n - r, n - r)(C * A * C.transpose()) + F = MatrixSpace(QQ, n - r, n - r)(C * A * C.transpose()) U = F**-1 - d = LCM([ c.denominator() for c in U.list() ]) - R = IntegerRing().quotient_ring(Integer(p)**(val + 3)) + d = LCM([c.denominator() for c in U.list()]) + R = ZZ.quotient_ring(Integer(p)**(val + 3)) u = R(d)**-1 - MatR = MatrixSpace(R, n - r , n - r) - MatZ = MatrixSpace(IntegerRing(), n - r, n - r) + MatR = MatrixSpace(R, n - r, n - r) + MatZ = MatrixSpace(ZZ, n - r, n - r) U = MatZ(MatR(MatZ(U * d)) * u) # X = C*A*B.transpose() # A = B*A*B.transpose() - X.transpose()*U*X X = C * A - A = B * (A - X.transpose()*U*X) * B.transpose() - return [ [s[0]+m0] + s[1:] for s in sym + p_adic_symbol(A, p, val) ] - + A = B * (A - X.transpose() * U * X) * B.transpose() + return [[s[0]+m0] + s[1:] for s in sym + p_adic_symbol(A, p, val)] def is_even_matrix(A): @@ -962,15 +948,13 @@ def is_even_matrix(A): Determines if the integral symmetric matrix `A` is even (i.e. represents only even numbers). If not, then it returns the index of an odd diagonal entry. If it is even, then we return the - index -1. + index `-1`. INPUT: - ``A`` -- symmetric integer matrix - OUTPUT: - - a pair of the form (boolean, integer) + OUTPUT: a pair of the form (boolean, integer) EXAMPLES:: @@ -985,12 +969,11 @@ def is_even_matrix(A): (True, -1) """ for i in range(A.nrows()): - if A[i,i] % 2 == 1: + if A[i, i] % 2: return False, i return True, -1 - def split_odd(A): r""" Given a non-degenerate Gram matrix `A (\mod 8)`, return a splitting @@ -1034,43 +1017,42 @@ def split_odd(A): Traceback (most recent call last): ... RuntimeError: The matrix A does not admit a non-even splitting. - """ n0 = A.nrows() if n0 == 1: - return A[0, 0], MatrixSpace(IntegerRing(), 0, A.ncols())([]) + return A[0, 0], MatrixSpace(ZZ, 0, A.ncols())([]) even, i = is_even_matrix(A) R = A.parent().base_ring() C = MatrixSpace(R, n0 - 1, n0)(0) - u = A[i,i] + u = A[i, i] for j in range(n0-1): if j < i: - C[j,j] = 1 - C[j,i] = -A[j,i] * u + C[j, j] = 1 + C[j, i] = -A[j, i] * u else: - C[j,j+1] = 1 - C[j,i] = -A[j+1,i] * u + C[j, j+1] = 1 + C[j, i] = -A[j+1, i] * u B = C*A*C.transpose() even, j = is_even_matrix(B) if even: I = A.parent()(1) # TODO: we could manually (re)construct the kernel here... if i == 0: - I[1,0] = 1 - A[1,0]*u + I[1, 0] = 1 - A[1, 0]*u i = 1 else: - I[0,i] = 1 - A[0,i]*u + I[0, i] = 1 - A[0, i]*u i = 0 A = I*A*I.transpose() - u = A[i,i] - C = MatrixSpace(R,n0-1,n0)(0) + u = A[i, i] + C = MatrixSpace(R, n0-1, n0)(0) for j in range(n0-1): if j < i: - C[j,j] = 1 - C[j,i] = -A[j,i] * u + C[j, j] = 1 + C[j, i] = -A[j, i] * u else: - C[j,j+1] = 1 - C[j,i] = -A[j+1,i] * u + C[j, j+1] = 1 + C[j, i] = -A[j+1, i] * u B = C * A * C.transpose() even, j = is_even_matrix(B) if even: @@ -1080,12 +1062,11 @@ def split_odd(A): return u, B - def trace_diag_mod_8(A): r""" Return the trace of the diagonalised form of `A` of an integral - symmetric matrix which is diagonalizable `\mod 8`. (Note that since - the Jordan decomposition into blocks of size `<=` 2 is not unique + symmetric matrix which is diagonalizable mod `8`. (Note that since + the Jordan decomposition into blocks of size `\leq 2` is not unique here, this is not the same as saying that `A` is always diagonal in any `2`-adic Jordan decomposition!) @@ -1094,9 +1075,7 @@ def trace_diag_mod_8(A): - ``A`` -- symmetric matrix with coefficients in `\ZZ` which is odd in `\ZZ/2\ZZ` and has determinant not divisible by `8`. - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -1122,7 +1101,7 @@ def trace_diag_mod_8(A): while A.nrows(): u, A = split_odd(A) tr += u - return IntegerRing()(tr) + return ZZ(tr) def two_adic_symbol(A, val): @@ -1132,11 +1111,11 @@ def two_adic_symbol(A, val): The genus symbol of a component `2^m f` is of the form ``(m,n,s,d[,o])``, where - - m = valuation of the component - - n = dimension of f - - d = det(f) in {1,3,5,7} - - s = 0 (or 1) if even (or odd) - - o = oddity of f (= 0 if s = 0) in `Z/8Z` + - ``m`` = valuation of the component + - ``n`` = dimension of `f` + - ``d`` = det(`f`) in {1,3,5,7} + - ``s`` = 0 (or 1) if even (or odd) + - ``o`` = oddity of `f` (= 0 if s = 0) in `\ZZ/8\ZZ` INPUT: @@ -1156,14 +1135,15 @@ def two_adic_symbol(A, val): [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]] """ + from sage.rings.finite_rings.finite_field_constructor import FiniteField + n = A.nrows() # deal with the empty matrix if n == 0: return [[0, 0, 1, 0, 0]] - m0 = min([ c.valuation(2) for c in A.list() ]) + m0 = min([c.valuation(2) for c in A.list()]) q = 2**m0 - A = A.parent()([ c // q for c in A.list() ]) - ZZ = IntegerRing() + A = A.parent()([c // q for c in A.list()]) A_2 = MatrixSpace(FiniteField(2), n, n)(A) K_2 = A_2.kernel() R_8 = ZZ.quotient_ring(Integer(8)) @@ -1178,7 +1158,7 @@ def two_adic_symbol(A, val): print("A:") print(A) assert False - even, i = is_even_matrix(A_2) # Determine whether the matrix is even or odd. + even, _ = is_even_matrix(A_2) # Determine whether the matrix is even or odd. if even: return [[m0, n0, d0, 0, 0]] else: @@ -1190,47 +1170,47 @@ def two_adic_symbol(A, val): B_2 = K_2.echelonized_basis_matrix() C_2 = basis_complement(B_2) n0 = C_2.nrows() - C = MatrixSpace(ZZ,n0,n)(C_2) + C = MatrixSpace(ZZ, n0, n)(C_2) A_new = C * A * C.transpose() # compute oddity modulo 8: A_8 = MatrixSpace(R_8, n0, n0)(A_new) # d0 = A_8.det() # no determinant over Z/8Z - d0 = ZZ(R_8(MatrixSpace(ZZ,n0,n0)(A_8).determinant())) + d0 = ZZ(R_8(MatrixSpace(ZZ, n0, n0)(A_8).determinant())) if d0 == 0: print("A:") print(A_new) assert False - even, i = is_even_matrix(A_new) + even, _ = is_even_matrix(A_new) if even: sym = [[0, n0, d0, 0, 0]] else: tr8 = trace_diag_mod_8(A_8) sym = [[0, n0, d0, 1, tr8]] r = B_2.nrows() - B = MatrixSpace(ZZ,r,n)(B_2) - C = MatrixSpace(IntegerRing(), n - r, n)(C_2) - F = MatrixSpace(RationalField(), n - r, n - r)(C * A * C.transpose()) + B = MatrixSpace(ZZ, r, n)(B_2) + C = MatrixSpace(ZZ, n - r, n)(C_2) + F = MatrixSpace(QQ, n - r, n - r)(C * A * C.transpose()) U = F**-1 - d = LCM([ c.denominator() for c in U.list() ]) - R = IntegerRing().quotient_ring(Integer(2)**(val + 3)) + d = LCM([c.denominator() for c in U.list()]) + R = ZZ.quotient_ring(Integer(2)**(val + 3)) u = R(d)**-1 MatR = MatrixSpace(R, n - r, n - r) - MatZ = MatrixSpace(IntegerRing(), n - r, n - r) + MatZ = MatrixSpace(ZZ, n - r, n - r) U = MatZ(MatR(MatZ(U * d)) * u) X = C * A A = B * (A - X.transpose()*U*X) * B.transpose() - return [ [s[0]+m0] + s[1:] for s in sym + two_adic_symbol(A, val) ] + return [[s[0]+m0] + s[1:] for s in sym + two_adic_symbol(A, val)] class Genus_Symbol_p_adic_ring(): r""" - Local genus symbol over a p-adic ring. + Local genus symbol over a `p`-adic ring. The genus symbol of a component `p^m A` for odd prime `= p` is of the form `(m,n,d)`, where - `m` = valuation of the component - - `n` = rank of A + - `n` = rank of `A` - `d = det(A) \in \{1,u\}` for a normalized quadratic non-residue `u`. The genus symbol of a component `2^m A` is of the form `(m, n, s, d, o)`, @@ -1240,13 +1220,14 @@ class Genus_Symbol_p_adic_ring(): - `n` = rank of `A` - `d` = det(A) in `\{1,3,5,7\}` - `s` = 0 (or 1) if even (or odd) - - `o` = oddity of `A` (= 0 if s = 0) in `Z/8Z` - = the trace of the diagonalization of `A` + - `o` = oddity of `A` (= 0 if s = 0) in `Z/8Z` = the trace of the diagonalization of `A` The genus symbol is a list of such symbols (ordered by `m`) for each of the Jordan blocks `A_1,...,A_t`. - Reference: [CS1999]_ Conway and Sloane 3rd edition, Chapter 15, Section 7. + REFERENCE: + + [CS1999]_ Conway and Sloane 3rd edition, Chapter 15, Section 7. .. WARNING:: @@ -1271,17 +1252,17 @@ class Genus_Symbol_p_adic_ring(): sage: p = 2 sage: s2 = p_adic_symbol(A, p, 2); s2 [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]] - sage: G2 = Genus_Symbol_p_adic_ring(p,s2);G2 + sage: G2 = Genus_Symbol_p_adic_ring(p,s2); G2 Genus symbol at 2: [1^-2 2^1 4^1]_6 sage: A = diagonal_matrix(ZZ, [1, 2, 3, 4]) sage: p = 3 sage: s3 = p_adic_symbol(A, p, 1); s3 [[0, 3, -1], [1, 1, 1]] - sage: G3 = Genus_Symbol_p_adic_ring(p,s3);G3 + sage: G3 = Genus_Symbol_p_adic_ring(p,s3); G3 Genus symbol at 3: 1^-3 3^1 """ - def __init__(self, prime, symbol, check = True): + def __init__(self, prime, symbol, check=True): r""" Create the local genus symbol of given prime and local invariants. @@ -1318,9 +1299,7 @@ def __repr__(self): r""" String representation for the `p`-adic genus symbol - OUTPUT: - - a string + OUTPUT: a string EXAMPLES:: @@ -1357,14 +1336,14 @@ def __repr__(self): Genus symbol at 2: [1^2]_0 2^2 Genus symbol at 3: 1^2 3^2 """ - p=self._prime + p = self._prime CS_string = "" if p == 2: CS = self.canonical_symbol() for train in self.trains(): - #mark the beginning of a train with a colon + # mark the beginning of a train with a colon CS_string += " :" - #collect the indices where compartments begin and end + # collect the indices where compartments begin and end compartment_begins = [] compartment_ends = [] for comp in self.compartments(): @@ -1373,24 +1352,24 @@ def __repr__(self): for block_index in train: if block_index in compartment_begins: - #mark the beginning of this compartment with [ + # mark the beginning of this compartment with [ CS_string += "[" block = CS[block_index] block_string = "%s^%s " % (p**block[0], block[2] * block[1]) CS_string += block_string if block_index in compartment_ends: - #close this compartment with ] and remove a space + # close this compartment with ] and remove a space CS_string = CS_string[:-1] + "]" # the oddity belongs to the compartment # and is saved in its first block i = compartment_ends.index(block_index) compartment_start = compartment_begins[i] oddity = CS[compartment_start][4] - CS_string +="_%s " % oddity + CS_string += "_%s " % oddity # remove the first colon CS_string = CS_string[2:] # remove some unnecessary whitespace - CS_string = CS_string.replace(" :",":") + CS_string = CS_string.replace(" :", ":") else: for s in self._symbol: @@ -1411,7 +1390,7 @@ def _latex_(self): sage: latex(g) \mbox{Genus symbol at } 2\mbox{: }1^{4} [2^{2} 4^{1}]_{3} :16^{4} [32^{1}]_{1} """ - p=self._prime + p = self._prime CS_string = "" if p == 2: CS = self.canonical_symbol() @@ -1440,14 +1419,14 @@ def _latex_(self): i = compartment_ends.index(block_index) compartment_start = compartment_begins[i] oddity = CS[compartment_start][4] - CS_string +="_{%s}" % oddity - #remove the first colon + CS_string += "_{%s}" % oddity + # remove the first colon CS_string = CS_string[2:] else: for s in self._symbol: CS_string += " {%s}^{%s}" % (p**s[0], s[2]*s[1]) - return r"\mbox{Genus symbol at } %s\mbox{: }%s" % (p,CS_string) + return r"\mbox{Genus symbol at } %s\mbox{: }%s" % (p, CS_string) def __eq__(self, other): r""" @@ -1455,11 +1434,9 @@ def __eq__(self, other): INPUT: - - other -- a :class:`Genus_Symbol_p_adic_ring` object + - ``other`` -- a :class:`Genus_Symbol_p_adic_ring` object - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -1487,18 +1464,15 @@ def __eq__(self, other): return False return self.canonical_symbol() == other.canonical_symbol() - def __ne__(self, other): r""" Determines if two genus symbols are unequal (not just inequivalent!). INPUT: - - other -- a :class:`Genus_Symbol_p_adic_ring` object - - OUTPUT: + - ``other`` -- a :class:`Genus_Symbol_p_adic_ring` object - boolean + OUTPUT: boolean EXAMPLES:: @@ -1519,17 +1493,15 @@ def __ne__(self, other): False sage: G3 != G3 False - """ return not self == other - # Added these two methods to make this class iterable... - #def __getitem__(self, i): - # return self._symbol[i] + # def __getitem__(self, i): + # return self._symbol[i] # - #def len(self): - # return len(self._symbol) + # def len(self): + # return len(self._symbol) # ------------------------------------------------------ def automorphous_numbers(self): @@ -1542,8 +1514,8 @@ def automorphous_numbers(self): OUTPUT: - - a list of integers representing the square classes of generators of - the automorphous numbers + a list of integers representing the square classes of generators of + the automorphous numbers EXAMPLES: @@ -1552,13 +1524,12 @@ def automorphous_numbers(self): sage: A = matrix.diagonal([3, 16]) sage: G = Genus(A) - sage: sym2 = G.local_symbols()[0] - sage: sym2 + sage: sym2 = G.local_symbols()[0]; sym2 Genus symbol at 2: [1^-1]_3:[16^1]_1 sage: sym2.automorphous_numbers() [3, 5] - sage: A = matrix(ZZ,3,[2,1,0, 1,2,0, 0,0,18]) + sage: A = matrix(ZZ, 3, [2,1,0, 1,2,0, 0,0,18]) sage: G = Genus(A) sage: sym = G.local_symbols() sage: sym[0] @@ -1640,11 +1611,11 @@ def automorphous_numbers(self): II = [] for block in collect_small_blocks(G): if block.ncols() == 1: - u = block[0,0] + u = block[0, 0] if I.count(u) < 2: - I.append(block[0,0]) - else: # rank2 - q = block[0,1] + I.append(block[0, 0]) + else: # rank2 + q = block[0, 1] II += [2*q, 3*2*q, 5*2*q, 7*2*q] L = I + II @@ -1676,9 +1647,9 @@ def automorphous_numbers(self): v, u = r.val_unit(ZZ(2)) u = u % 8 assert v >= 0 - if v==0 and u==1: + if v == 0 and u == 1: automorphs.append(ZZ(2)) - if v==0 and u==5: + if v == 0 and u == 5: automorphs.append(ZZ(6)) if v in [0, 2, 4]: # this overlaps with the first two cases! automorphs.append(ZZ(5)) @@ -1765,14 +1736,13 @@ def canonical_symbol(self): else: return self._symbol - def gram_matrix(self, check=True): r""" - Return a gram matrix of a representative of this local genus. + Return a Gram matrix of a representative of this local genus. INPUT: - - check (default: ``True``) -- double check the result + - ``check`` (default: ``True``) -- double check the result EXAMPLES:: @@ -1826,7 +1796,7 @@ def mass(self): p = self.prime() sym = self._symbol ############## - #diagonal product + # diagonal product ############## # diagonal factors @@ -1910,14 +1880,14 @@ def _species_list(self): for k in range(sym[-1][0] + 1): if sym[s][0] == k: symbols.append(sym[s]) - s +=1 + s += 1 else: symbols.append([k, 0, 1, 0, 0]) # avoid a case distinction - sym = [[-2, 0, 1, 0, 0],[-1, 0, 1, 0, 0]] + symbols + [[sym[-1][0]+1, 0, 1, 0, 0],[sym[-1][0] + 2, 0, 1, 0, 0]] + sym = [[-2, 0, 1, 0, 0], [-1, 0, 1, 0, 0]] + symbols + [[sym[-1][0]+1, 0, 1, 0, 0], [sym[-1][0] + 2, 0, 1, 0, 0]] for k in range(1, len(sym)-1): free = True - if sym[k-1][3]==1 or sym[k+1][3]==1: + if sym[k-1][3] == 1 or sym[k+1][3] == 1: free = False n = sym[k][1] o = sym[k][4] @@ -1940,9 +1910,7 @@ def prime(self): r""" Return the prime number `p` of this `p`-adic local symbol. - OUTPUT: - - - an integer + OUTPUT: an integer EXAMPLES:: @@ -1986,9 +1954,7 @@ def symbol_tuple_list(self): Return a copy of the underlying list of lists of integers defining the genus symbol. - OUTPUT: - - a list of lists of integers + OUTPUT: a list of lists of integers EXAMPLES:: @@ -2019,9 +1985,7 @@ def number_of_blocks(self): r""" Return the number of positive dimensional symbols/Jordan blocks. - OUTPUT: - - A non-negative integer + OUTPUT: a non-negative integer EXAMPLES:: @@ -2030,21 +1994,22 @@ def number_of_blocks(self): sage: A = DiagonalQuadraticForm(ZZ, [1, 2, 3, 4]).Hessian_matrix() sage: p = 2 - sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2.symbol_tuple_list() + sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)) + sage: G2.symbol_tuple_list() [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]] sage: G2.number_of_blocks() 3 sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 3 - sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3.symbol_tuple_list() + sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)) + sage: G3.symbol_tuple_list() [[0, 3, 1], [1, 1, -1]] sage: G3.number_of_blocks() 2 """ return len(self._symbol) - def determinant(self): r""" Returns the (`p`-part of the) determinant (square-class) of the @@ -2052,9 +2017,7 @@ def determinant(self): integral symmetric matrix which generated this genus symbol as the Gram matrix of `Q`) associated to this local genus symbol. - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -2076,7 +2039,7 @@ def determinant(self): 3 """ p = self._prime - return prod([ p**(s[0]*s[1]) for s in self._symbol ]) + return prod([p**(s[0] * s[1]) for s in self._symbol]) det = determinant @@ -2084,9 +2047,7 @@ def dimension(self): r""" Return the dimension of a quadratic form associated to this genus symbol. - OUTPUT: - - an non-negative integer + OUTPUT: a non-negative integer EXAMPLES:: @@ -2106,9 +2067,8 @@ def dimension(self): Genus symbol at 3: 1^3 3^-1 sage: G3.dimension() 4 - """ - return sum([ s[1] for s in self._symbol ]) + return sum([s[1] for s in self._symbol]) dim = dimension rank = dimension @@ -2172,8 +2132,8 @@ def direct_sum(self, other): def excess(self): r""" - Returns the p-excess of the quadratic form whose Hessian - matrix is the symmetric matrix A. When p = 2 the p-excess is + Returns the `p`-excess of the quadratic form whose Hessian + matrix is the symmetric matrix `A`. When `p = 2`, the `p`-excess is called the oddity. .. WARNING:: @@ -2186,9 +2146,7 @@ def excess(self): [CS1999]_ Conway and Sloane Book, 3rd edition, pp 370-371. - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -2238,13 +2196,13 @@ def excess(self): for s in self._symbol: if s[0] % 2 == 1 and s[2] in (3, 5): k += 1 - return Integer(sum([ s[4] for s in self._symbol ]) + 4*k).mod(8) + return Integer(sum([s[4] for s in self._symbol]) + 4*k).mod(8) else: k = 0 for s in self._symbol: if s[0] % 2 == 1 and s[2] == -1: k += 1 - return Integer(sum([ s[1] * (p**s[0]-1) for s in self._symbol]) + 4*k).mod(8) + return Integer(sum([s[1] * (p**s[0]-1) for s in self._symbol]) + 4*k).mod(8) def scale(self): r""" @@ -2254,9 +2212,7 @@ def scale(self): The scale of `(L,b)` is defined as the ideal `b(L,L)`. - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -2298,7 +2254,7 @@ def norm(self): def level(self): r""" - Return the maximal scale of a jordan component. + Return the maximal scale of a Jordan component. EXAMPLES:: @@ -2313,12 +2269,10 @@ def level(self): def trains(self): r""" Compute the indices for each of the trains in this local genus - symbol if it is associated to the prime p=2 (and raise an + symbol if it is associated to the prime `p=2` (and raise an error for all other primes). - OUTPUT: - - a list of non-negative integers + OUTPUT: a list of non-negative integers EXAMPLES:: @@ -2339,16 +2293,13 @@ def trains(self): symbol = self._symbol return canonical_2_adic_trains(symbol) - def compartments(self): r""" Compute the indices for each of the compartments in this local genus - symbol if it is associated to the prime p=2 (and raise an + symbol if it is associated to the prime `p=2` (and raise an error for all other primes). - OUTPUT: - - a list of non-negative integers + OUTPUT: a list of non-negative integers EXAMPLES:: @@ -2380,11 +2331,11 @@ class GenusSymbol_global_ring(): - ``signature_pair`` -- a tuple of two non-negative integers - - ``local_symbols`` -- a list of :class:`Genus_Symbol_p_adic_ring`` instances + - ``local_symbols`` -- a list of :class:`Genus_Symbol_p_adic_ring` instances sorted by their primes - ``representative`` -- (default: ``None``) integer symmetric matrix; - the gram matrix of a representative of this genus + the Gram matrix of a representative of this genus - ``check`` -- (default: ``True``) a boolean; checks the input @@ -2405,7 +2356,7 @@ class GenusSymbol_global_ring(): .. SEEALSO:: - :func:`Genus` to create a :class:`GenusSymbol_global_ring` from the gram matrix directly. + :func:`Genus` to create a :class:`GenusSymbol_global_ring` from the Gram matrix directly. """ def __init__(self, signature_pair, local_symbols, representative=None, check=True): @@ -2423,7 +2374,7 @@ def __init__(self, signature_pair, local_symbols, representative=None, check=Tru if not all(isinstance(sym, Genus_Symbol_p_adic_ring) for sym in local_symbols): raise TypeError("local symbols must be a list of local genus symbols") n = signature_pair[0] + signature_pair[1] - if not all(sym.dimension()==n for sym in local_symbols): + if not all(sym.dimension() == n for sym in local_symbols): raise TypeError("all local symbols must be of the same dimension") if representative is not None: if not representative.is_symmetric(): @@ -2436,20 +2387,17 @@ def __init__(self, signature_pair, local_symbols, representative=None, check=Tru raise ValueError("the first symbol must be 2-adic") if representative is not None: if representative.base_ring() != ZZ: - representative = matrix(ZZ,representative) + representative = matrix(ZZ, representative) representative.set_immutable() self._representative = representative self._signature = signature_pair self._local_symbols = local_symbols - def __repr__(self): r""" Return a string representing the global genus symbol. - OUTPUT: - - a string + OUTPUT: a string EXAMPLES:: @@ -2477,8 +2425,8 @@ def __repr__(self): """ rep = "Genus" if self.dimension() <= 20: - rep += " of\n%s" %self._representative - rep += "\nSignature: %s"%(self._signature,) + rep += " of\n%s" % self._representative + rep += "\nSignature: %s" % (self._signature,) for s in self._local_symbols: rep += "\n" + s.__repr__() return rep @@ -2501,15 +2449,14 @@ def _latex_(self): """ rep = r"\mbox{Genus" if self.dimension() <= 20: - rep += r" of}\\ %s" %self._representative._latex_() + rep += r" of}\\ %s" % self._representative._latex_() else: - rep +=r"}" - rep += r"\\ \mbox{Signature: } %s"%(self._signature,) + rep += r"}" + rep += r"\\ \mbox{Signature: } %s" % (self._signature,) for s in self._local_symbols: rep += r"\\ " + s._latex_() return rep - def __eq__(self, other): r""" Determines if two global genus symbols are equal (not just equivalent!). @@ -2518,9 +2465,7 @@ def __eq__(self, other): a :class:`GenusSymbol_global_ring` object - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -2562,8 +2507,6 @@ def __eq__(self, other): return False return True - - def __ne__(self, other): r""" Determine if two global genus symbols are unequal (not just inequivalent!). @@ -2572,9 +2515,7 @@ def __ne__(self, other): a ``GenusSymbol_global_ring`` object - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -2615,12 +2556,10 @@ def is_even(self): def signature_pair(self): r""" Return the signature pair `(p, n)` of the (non-degenerate) - global genus symbol, where p is the number of positive - eigenvalues and n is the number of negative eigenvalues. - - OUTPUT: + global genus symbol, where `p` is the number of positive + eigenvalues and `n` is the number of negative eigenvalues. - a pair of integers `(p, n)` each `>= 0` + OUTPUT: a pair of integers `(p, n)`, each `\geq 0` EXAMPLES:: @@ -2637,9 +2576,7 @@ def _proper_spinor_kernel(self): r""" Return the proper spinor kernel. - OUTPUT: - - A pair ``(A, K)`` where + OUTPUT: a pair `(A, K)` where .. MATH:: @@ -2679,9 +2616,7 @@ def _improper_spinor_kernel(self): r""" Return the improper spinor kernel. - OUTPUT: - - A pair ``(A, K)`` where + OUTPUT: a pair ``(A, K)`` where .. MATH:: @@ -2716,7 +2651,6 @@ def _improper_spinor_kernel(self): K = A.subgroup(K.gens() + (j,)) return A, K - def spinor_generators(self, proper): r""" Return the spinor generators. @@ -2725,9 +2659,7 @@ def spinor_generators(self, proper): - ``proper`` -- boolean - OUTPUT: - - a list of primes not dividing the determinant + OUTPUT: a list of primes not dividing the determinant EXAMPLES:: @@ -2753,7 +2685,7 @@ def spinor_generators(self, proper): if p.divides(self.determinant()): continue g = Q(A.delta(p)) - if g.gap() in U.gap(): # containment in sage is broken + if g.gap() in U.gap(): # containment in sage is broken continue else: spinor_gens.append(p) @@ -2796,18 +2728,17 @@ def _proper_is_improper(self): P = [s.prime() for s in self._local_symbols] while True: x = V.random_element() - q = x * G* x + q = x * G * x if q != 0 and all(q.valuation(p) == norm.valuation(p) for p in P): break - Q = [p for p in q.prime_factors() if (norm.valuation(p) + q.valuation(p)) % 2 != 0] + Q = [p for p in q.prime_factors() if (norm.valuation(p) + q.valuation(p)) % 2] r = ZZ.prod(Q) # M = \tau_x(L) # q = [L: L & M] A, K = self._proper_spinor_kernel() - j = A.delta(r) # diagonal embedding of r + j = A.delta(r) # diagonal embedding of r return j in K, j - def signature(self): r""" Return the signature of this genus. @@ -2827,14 +2758,13 @@ def signature(self): def determinant(self): r""" - Return the determinant of this genus, where the determinant - is the Hessian determinant of the quadratic form whose Gram - matrix is the Gram matrix giving rise to this global genus - symbol. + Return the determinant of this genus. - OUTPUT: + The determinant is the Hessian determinant of the quadratic + form whose Gram matrix is the Gram matrix giving rise to this + global genus symbol. - an integer + OUTPUT: an integer EXAMPLES:: @@ -2843,8 +2773,8 @@ def determinant(self): sage: GS.determinant() -24 """ - p, n = self.signature_pair() - return (-1)**n*prod([ G.determinant() for G in self._local_symbols ]) + _, n = self.signature_pair() + return (-1)**n * ZZ.prod(G.determinant() for G in self._local_symbols) det = determinant @@ -2933,9 +2863,7 @@ def rational_representative(self): Return a representative of the rational bilinear form defined by this genus. - OUTPUT: - - A diagonal_matrix. + OUTPUT: a diagonal_matrix EXAMPLES:: @@ -2956,7 +2884,8 @@ def rational_representative(self): [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 2] """ - from sage.quadratic_forms.all import QuadraticForm, quadratic_form_from_invariants + from sage.quadratic_forms.quadratic_form import QuadraticForm + from sage.quadratic_forms.quadratic_form import quadratic_form_from_invariants sminus = self.signature_pair_of_matrix()[1] det = self.determinant() m = self.rank() @@ -2964,7 +2893,7 @@ def rational_representative(self): for sym in self._local_symbols: p = sym._prime # it is important to use the definition of Cassels here! - if QuadraticForm(QQ,2*sym.gram_matrix()).hasse_invariant(p) == -1: + if QuadraticForm(QQ, 2*sym.gram_matrix()).hasse_invariant(p) == -1: P.append(p) q = quadratic_form_from_invariants(F=QQ, rk=m, det=det, P=P, sminus=sminus) @@ -2988,8 +2917,8 @@ def _compute_representative(self, LLL=True): ....: G = genera((1,2), det, even=False) ....: assert all(g==Genus(g.representative()) for g in G) sage: for det in range(1, 9): # long time (8s, 2020) - ....: G = genera((2,2), det, even=False) # long time - ....: assert all(g==Genus(g.representative()) for g in G) # long time + ....: G = genera((2,2), det, even=False) + ....: assert all(g==Genus(g.representative()) for g in G) """ from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice, local_modification q = self.rational_representative() @@ -3010,12 +2939,16 @@ def _compute_representative(self, LLL=True): L = local_modification(L, sym.gram_matrix(), p) L = L.gram_matrix().change_ring(ZZ) if LLL: + from sage.libs.pari import pari + sig = self.signature_pair_of_matrix() if sig[0] * sig[1] != 0: from sage.env import SAGE_EXTCODE + from sage.interfaces.gp import gp + m = pari(L) gp.read(SAGE_EXTCODE + "/pari/simon/qfsolve.gp") - m = gp.eval('qflllgram_indefgoon(%s)'%m) + m = gp.eval('qflllgram_indefgoon(%s)' % m) # convert the output string to sage L = pari(m).sage()[0] elif sig[1] != 0: @@ -3045,7 +2978,7 @@ def representative(self): Genus symbol at 3: 1^3 3^1 A representative of ``g`` is not known yet. - Let us trigger its computation: + Let us trigger its computation:: sage: g.representative() [ 0 0 0 2] @@ -3065,12 +2998,10 @@ def representatives(self, backend=None, algorithm=None): INPUT: - - ``backend`` -- (default:``None``) - - ``algorithm`` -- (default:``None``) + - ``backend`` -- (default: ``None``) + - ``algorithm`` -- (default: ``None``) - OUTPUT: - - - a list of gram matrices + OUTPUT: a list of Gram matrices EXAMPLES:: @@ -3157,7 +3088,7 @@ def representatives(self, backend=None, algorithm=None): e = ZZ(2) if self.signature_pair()[0] == 0: e *= ZZ(-1) - Q = QuadraticForm(ZZ,e*self.representative()) + Q = QuadraticForm(ZZ, e * self.representative()) seeds = [Q] for p in self.spinor_generators(proper=False): v = Q.find_primitive_p_divisible_vector__next(p) @@ -3233,10 +3164,14 @@ def _standard_mass(self): sage: A = matrix.diagonal(ZZ, [1, 1, 1, 1]) sage: GS = Genus(A) - sage: GS._standard_mass() + sage: GS._standard_mass() # needs sage.symbolic 1/48 """ + from sage.symbolic.constants import pi + from sage.symbolic.ring import SR + from sage.functions.transcendental import zeta + from sage.functions.gamma import gamma n = self.dimension() if n % 2 == 0: s = n // 2 @@ -3276,15 +3211,13 @@ def mass(self, backend='sage'): - ``backend`` -- default: ``'sage'``, or ``'magma'`` - OUTPUT: - - a rational number + OUTPUT: a rational number EXAMPLES:: sage: from sage.quadratic_forms.genera.genus import genera sage: G = genera((8,0), 1, even=True)[0] - sage: G.mass() + sage: G.mass() # needs sage.symbolic 1/696729600 sage: G.mass(backend='magma') # optional - magma 1/696729600 @@ -3323,28 +3256,28 @@ def mass(self, backend='sage'): if pos * neg != 0: raise ValueError("the genus must be definite.") if pos + neg == 1: - return QQ(1)/QQ(2) + return QQ(1) / QQ(2) if backend == 'sage': mass = self._standard_mass() for sym in self._local_symbols: - mass *= sym.mass()/sym._standard_mass() + mass *= sym.mass() / sym._standard_mass() return QQ(mass.canonicalize_radical()) elif backend == 'magma': - e = 1 # lattices in magma are positive definite - if neg !=0: + e = 1 # lattices in magma are positive definite + if neg != 0: e = -1 # for some reason LatticeWithGram wants a dense matrix - L = magma(e*self.representative().dense_matrix()) + L = magma(e * self.representative().dense_matrix()) L = L.LatticeWithGram() return QQ(L.Mass()) else: - raise ValueError("unknown backend: %s"%backend) + raise ValueError("unknown backend: %s" % backend) def level(self): r""" Return the level of this genus. - This is the denominator of the inverse gram matrix + This is the denominator of the inverse Gram matrix of a representative. EXAMPLES:: @@ -3363,9 +3296,7 @@ def scale(self): The scale of `(L,b)` is defined as the ideal `b(L,L)`. - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -3397,7 +3328,7 @@ def norm(self): def _gram_from_jordan_block(p, block, discr_form=False): r""" - Return the gram matrix of this jordan block. + Return the Gram matrix of this jordan block. This is a helper for :meth:`discriminant_form` and :meth:`gram_matrix`. No input checks. @@ -3409,7 +3340,7 @@ def _gram_from_jordan_block(p, block, discr_form=False): - ``block`` -- a list of 3 integers or 5 integers if `p` is `2` - ``discr_form`` -- bool (default: ``False``); if ``True`` invert the scales - to obtain a gram matrix for the discriminant form instead. + to obtain a Gram matrix for the discriminant form instead. EXAMPLES:: @@ -3446,18 +3377,18 @@ def _gram_from_jordan_block(p, block, discr_form=False): if p == 2: o = ZZ(block[3]) t = ZZ(block[4]) - U = matrix(QQ, 2, [0,1, 1,0]) - V = matrix(QQ, 2, [2,1, 1,2]) + U = matrix(QQ, 2, [0, 1, 1, 0]) + V = matrix(QQ, 2, [2, 1, 1, 2]) W = matrix(QQ, 1, [1]) if o == 0: if det in [1, 7]: qL = (rk // 2) * [U] else: - qL = (rk//2 - 1)*[U] + [V] + qL = (rk // 2 - 1) * [U] + [V] if o == 1: if rk % 2 == 1: qL = max(0, (rk - 3) // 2) * [U] - if t*det % 8 in [3, 5]: + if t * det % 8 in [3, 5]: qL += [V] elif rk >= 3: qL += [U] @@ -3468,21 +3399,21 @@ def _gram_from_jordan_block(p, block, discr_form=False): else: det = 1 qL = max(0, (rk - 4) // 2) * [U] - if (det , t) == (1, 0): + if (det, t) == (1, 0): qL += [U, 1 * W, 7 * W] - if (det , t) == (1, 2): + if (det, t) == (1, 2): qL += [U, 1 * W, 1 * W] - if (det , t) == (1, 4): + if (det, t) == (1, 4): qL += [V, 1 * W, 3 * W] - if (det , t) == (1, 6): + if (det, t) == (1, 6): qL += [U, 7 * W, 7 * W] - if (det , t) == (-1, 0): + if (det, t) == (-1, 0): qL += [V, 1 * W, 7 * W] - if (det , t) == (-1, 2): + if (det, t) == (-1, 2): qL += [U, 3 * W, 7 * W] - if (det , t) == (-1, 4): + if (det, t) == (-1, 4): qL += [U, 1 * W, 3 * W] - if (det , t) == (-1, 6): + if (det, t) == (-1, 6): qL += [U, 1 * W, 5 * W] # if the rank is 2 there is a U too much if rk == 2: @@ -3497,16 +3428,17 @@ def _gram_from_jordan_block(p, block, discr_form=False): d = 2**(rk % 2) if Integer(d).kronecker(p) != det: u = ZZ(_min_nonsquare(p)) - q[0,0] = u + q[0, 0] = u q = q * (2 / p**level) if p != 2 and not discr_form: q = matrix.identity(QQ, rk) if det != 1: u = ZZ(_min_nonsquare(p)) - q[0,0] = u + q[0, 0] = u q = q * p**level return q + # Helper functions for mass computations def M_p(species, p): @@ -3575,7 +3507,7 @@ def M_p(species, p): return QQ(1) n = species.abs() s = (n + 1) // ZZ(2) - mp = ZZ(2) * ZZ.prod(ZZ(1) - p**(-2*k) for k in range(1, s)) + mp = ZZ(2) * ZZ.prod(ZZ(1) - p**(-2 * k) for k in range(1, s)) if n % 2 == 0: - mp *= ZZ(1) - species.sign() * p**(-s) - return QQ(1) / mp + mp *= ZZ.one() - species.sign() * p**(-s) + return QQ.one() / mp diff --git a/src/sage/quadratic_forms/genera/normal_form.py b/src/sage/quadratic_forms/genera/normal_form.py index bebd2478ec4..829b4783226 100644 --- a/src/sage/quadratic_forms/genera/normal_form.py +++ b/src/sage/quadratic_forms/genera/normal_form.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari sage.rings.padics r""" Normal forms for `p`-adic quadratic and bilinear forms @@ -87,7 +88,8 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import Zp, ZZ, GF +from sage.rings.integer_ring import ZZ +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.matrix.constructor import Matrix from copy import copy from sage.rings.finite_rings.integer_mod import mod @@ -178,7 +180,7 @@ def p_adic_normal_form(G, p, precision=None, partial=False, debug=False): - ``D`` -- the jordan matrix over `\QQ_p` - ``B`` -- invertible transformation matrix over `\ZZ_p`, - i.e, ``D = B * G * B^T`` + i.e., `D = B * G * B^T` EXAMPLES:: @@ -233,13 +235,15 @@ def p_adic_normal_form(G, p, precision=None, partial=False, debug=False): TESTS:: - sage: Z = Matrix(ZZ,0,[]) + sage: Z = Matrix(ZZ, 0, []) sage: p_adic_normal_form(Z, 3) ([], []) sage: Z = matrix.zero(10) sage: p_adic_normal_form(Z, 3)[0] == 0 True """ + from sage.rings.padics.factory import Zp + p = ZZ(p) # input checks!! G0, denom = G._clear_denom() @@ -359,9 +363,7 @@ def _get_small_block_indices(G): - ``G`` -- a block_diagonal matrix consisting of `1` by `1` and `2` by `2` blocks - OUTPUT: - - - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -395,12 +397,10 @@ def _get_homogeneous_block_indices(G): INPUT: - - ``G`` -- a block diagonal matrix over the p-adics + - ``G`` -- a block diagonal matrix over the `p`-adics with blocks of size at most `2`. - OUTPUT: - - - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -457,7 +457,7 @@ def _homogeneous_normal_form(G, w): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _homogeneous_normal_form - sage: R = Zp(2, type = 'fixed-mod', print_mode='terse', show_prec=False) + sage: R = Zp(2, type='fixed-mod', print_mode='terse', show_prec=False) sage: U = Matrix(R, 2, [0,1,1,0]) sage: V = Matrix(R, 2, [2,1,1,2]) sage: W1 = Matrix(R, 1, [1]) @@ -655,7 +655,7 @@ def _jordan_2_adic(G): sage: from sage.quadratic_forms.genera.normal_form import _jordan_2_adic sage: R = Zp(2, prec=3, print_mode='terse', show_prec=False) - sage: A4 = Matrix(R,4,[2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2]) + sage: A4 = Matrix(R, 4, [2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2]) sage: A4 [2 7 0 0] [7 2 7 0] @@ -784,7 +784,7 @@ def _normalize(G, normal_odd=True): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _normalize - sage: R = Zp(3, prec = 5, type = 'fixed-mod', print_mode='series', show_prec=False) + sage: R = Zp(3, prec=5, type='fixed-mod', print_mode='series', show_prec=False) sage: G = matrix.diagonal(R, [1,7,3,3*5,3,9,-9,27*13]) sage: D, B =_normalize(G) sage: D @@ -861,7 +861,7 @@ def _normalize_2x2(G): INPUT: ``G`` - a `2` by `2` matrix over `\ZZ_p` - with ``type = 'fixed-mod'`` of the form:: + with ``type='fixed-mod'`` of the form:: [2a b] [ b 2c] * 2^n @@ -880,14 +880,14 @@ def _normalize_2x2(G): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _normalize_2x2 - sage: R = Zp(2, prec = 15, type = 'fixed-mod', print_mode='series', show_prec=False) + sage: R = Zp(2, prec=15, type='fixed-mod', print_mode='series', show_prec=False) sage: G = Matrix(R, 2, [-17*2,3,3,23*2]) sage: B =_normalize_2x2(G) sage: B * G * B.T [2 1] [1 2] - sage: G = Matrix(R,2,[-17*4,3,3,23*2]) + sage: G = Matrix(R, 2, [-17*4,3,3,23*2]) sage: B = _normalize_2x2(G) sage: B*G*B.T [0 1] @@ -1038,7 +1038,7 @@ def _partial_normal_form_of_block(G): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _partial_normal_form_of_block - sage: R = Zp(2,prec=4, type = 'fixed-mod',print_mode='terse', show_prec=False) + sage: R = Zp(2, prec=4, type='fixed-mod', print_mode='terse', show_prec=False) sage: U = Matrix(R, 2, [0,1,1,0]) sage: V = Matrix(R, 2, [2,1,1,2]) sage: W1 = Matrix(R, 1, [1]) @@ -1134,13 +1134,13 @@ def _relations(G, n): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _relations - sage: R = Zp(2, type = 'fixed-mod',print_mode='terse', show_prec=False) - sage: U = Matrix(R,2,[0,1,1,0]) - sage: V = Matrix(R,2,[2,1,1,2]) - sage: W1 = Matrix(R,1,[1]) - sage: W3 = Matrix(R,1,[3]) - sage: W5 = Matrix(R,1,[5]) - sage: W7 = Matrix(R,1,[7]) + sage: R = Zp(2, type='fixed-mod', print_mode='terse', show_prec=False) + sage: U = Matrix(R, 2, [0,1,1,0]) + sage: V = Matrix(R, 2, [2,1,1,2]) + sage: W1 = Matrix(R, 1, [1]) + sage: W3 = Matrix(R, 1, [3]) + sage: W5 = Matrix(R, 1, [5]) + sage: W7 = Matrix(R, 1, [7]) sage: G = Matrix.block_diagonal(W1,W1) sage: b = _relations(G,1) sage: b * G * b.T @@ -1374,7 +1374,7 @@ def _relations(G, n): e1 = G[0, 0].unit_part() e2 = G[1, 1].unit_part() B = Matrix(R, 2, 2, [1, 1, -4 * e2, e1]) - D, B1 = _normalize(B * G * B.T) + _, B1 = _normalize(B * G * B.T) return B1 * B @@ -1394,13 +1394,13 @@ def _two_adic_normal_forms(G, partial=False): EXAMPLES:: sage: from sage.quadratic_forms.genera.normal_form import _two_adic_normal_forms - sage: R = Zp(2, type = 'fixed-mod', print_mode='terse', show_prec=False) - sage: U = Matrix(R,2,[0,1,1,0]) - sage: V = Matrix(R,2,[2,1,1,2]) - sage: W1 = Matrix(R,1,[1]) - sage: W3 = Matrix(R,1,[3]) - sage: W5 = Matrix(R,1,[5]) - sage: W7 = Matrix(R,1,[7]) + sage: R = Zp(2, type='fixed-mod', print_mode='terse', show_prec=False) + sage: U = Matrix(R, 2, [0,1,1,0]) + sage: V = Matrix(R, 2, [2,1,1,2]) + sage: W1 = Matrix(R, 1, [1]) + sage: W3 = Matrix(R, 1, [3]) + sage: W5 = Matrix(R, 1, [5]) + sage: W7 = Matrix(R, 1, [7]) sage: G = Matrix.block_diagonal([2*W1,2*W1,4*V]) sage: B = _two_adic_normal_forms(G)[1] sage: B * G * B.T diff --git a/src/sage/quadratic_forms/genera/spinor_genus.py b/src/sage/quadratic_forms/genera/spinor_genus.py index e42e4b6e361..f049496965d 100644 --- a/src/sage/quadratic_forms/genera/spinor_genus.py +++ b/src/sage/quadratic_forms/genera/spinor_genus.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups r""" Spinor genus computations. @@ -27,7 +28,8 @@ from sage.groups.abelian_gps.abelian_group_gap import (AbelianGroupGap, AbelianGroupElement_gap) -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ class SpinorOperator(AbelianGroupElement_gap): @@ -200,7 +202,7 @@ def delta(self, r, prime=None): OUTPUT: - If a prime `p` is given the method returns + If a prime `p` is given, the method returns `\Delta_p(r)` otherwise returns `\Delta(r)` where both are as defined by Conway-Sloane in diff --git a/src/sage/quadratic_forms/qfsolve.py b/src/sage/quadratic_forms/qfsolve.py index d5e15d9f83e..85116e43f9e 100644 --- a/src/sage/quadratic_forms/qfsolve.py +++ b/src/sage/quadratic_forms/qfsolve.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari """ Solving quadratic equations @@ -15,7 +16,7 @@ - Tyler Gaona (2015-11-14): added the `solve` method """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Nick Alexander # Copyright (C) 2014 Jeroen Demeyer # @@ -23,10 +24,12 @@ # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -from sage.rings.all import ZZ, QQ, Integer +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.integer import Integer from sage.modules.free_module_element import vector from sage.matrix.constructor import Matrix @@ -44,7 +47,7 @@ def qfsolve(G): ALGORITHM: - Uses PARI/GP function ``qfsolve``. + Uses PARI/GP function :pari:`qfsolve`. EXAMPLES:: @@ -77,25 +80,26 @@ def qfsolve(G): return vector(QQ, ret) return ZZ(ret) + def qfparam(G, sol): r""" - Parametrizes the conic defined by the matrix ``G``. + Parametrize the conic defined by the matrix `G`. INPUT: - - ``G`` -- a `3 \times 3`-matrix over `\QQ`. + - ``G`` -- a `3 \times 3`-matrix over `\QQ` - - ``sol`` -- a triple of rational numbers providing a solution - to sol*G*sol^t = 0. + - ``sol`` -- a triple of rational numbers providing a solution + to `x\cdot G\cdot x^t = 0` OUTPUT: A triple of polynomials that parametrizes all solutions of - x*G*x^t = 0 up to scaling. + `x\cdot G\cdot x^t = 0` up to scaling. ALGORITHM: - Uses PARI/GP function ``qfparam``. + Uses PARI/GP function :pari:`qfparam`. EXAMPLES:: @@ -108,7 +112,8 @@ def qfparam(G, sol): sage: ret = qfparam(M, sol); ret (-12*t^2 - 1, 24*t, 24) sage: ret.parent() - Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in t over Rational Field + Ambient free module of rank 3 over the principal ideal domain + Univariate Polynomial Ring in t over Rational Field """ R = QQ['t'] mat = G.__pari__().qfparam(sol) @@ -122,15 +127,13 @@ def solve(self, c=0): INPUT: - - ``c`` -- (default: 0) a rational number. - - OUTPUT: + - ``c`` -- (default: 0) a rational number - - A non-zero vector `x` satisfying ``self(x) == c``. + OUTPUT: A non-zero vector `x` satisfying ``self(x) == c``. ALGORITHM: - Uses PARI's qfsolve(). Algorithm described by Jeroen Demeyer; see comments on :trac:`19112` + Uses PARI's :pari:`qfsolve`. Algorithm described by Jeroen Demeyer; see comments on :trac:`19112` EXAMPLES:: @@ -218,8 +221,8 @@ def solve(self, c=0): N = Matrix(self.base_ring(), d+1, d+1) for i in range(d): for j in range(d): - N[i,j] = M[i,j] - N[d,d] = -c + N[i, j] = M[i, j] + N[d, d] = -c # Find a solution x to Q(x) = 0, using qfsolve() x = qfsolve(N) diff --git a/src/sage/quadratic_forms/quadratic_form.py b/src/sage/quadratic_forms/quadratic_form.py index c4e97d97c50..3db01b9fe2f 100644 --- a/src/sage/quadratic_forms/quadratic_form.py +++ b/src/sage/quadratic_forms/quadratic_form.py @@ -23,53 +23,46 @@ from sage.matrix.constructor import matrix from sage.matrix.matrix_space import MatrixSpace +from sage.misc.lazy_import import lazy_import from sage.structure.element import is_Matrix from sage.rings.integer_ring import IntegerRing, ZZ from sage.rings.ring import Ring from sage.misc.functional import denominator, is_even -from sage.arith.all import GCD, LCM -from sage.rings.all import Ideal, QQ +from sage.arith.misc import GCD +from sage.arith.functions import lcm as LCM +from sage.rings.ideal import Ideal +from sage.rings.rational_field import QQ from sage.rings.ring import is_Ring, PrincipalIdealDomain -from sage.structure.sage_object import SageObject from sage.structure.element import is_Vector from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.polynomial.polynomial_element import Polynomial +from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.modules.free_module_element import vector -from sage.quadratic_forms.genera.genus import genera from sage.quadratic_forms.quadratic_form__evaluate import QFEvaluateVector, QFEvaluateMatrix - - -def QuadraticForm__constructor(R, n=None, entries=None): - """ - Wrapper for the QuadraticForm class constructor. This is meant - for internal use within the QuadraticForm class code only. You - should instead directly call QuadraticForm(). - - EXAMPLES:: - - sage: from sage.quadratic_forms.quadratic_form import QuadraticForm__constructor - sage: QuadraticForm__constructor(ZZ, 3) # Makes a generic quadratic form over the integers - Quadratic form in 3 variables over Integer Ring with coefficients: - [ 0 0 0 ] - [ * 0 0 ] - [ * * 0 ] - - """ - return QuadraticForm(R, n, entries) +from sage.structure.sage_object import SageObject +from sage.misc.superseded import deprecation, deprecated_function_alias def is_QuadraticForm(Q): """ - Determine if the object Q is an element of the QuadraticForm class. + Determine if the object ``Q`` is an element of the :class:`QuadraticForm` class. + + This function is deprecated. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: from sage.quadratic_forms.quadratic_form import is_QuadraticForm - sage: is_QuadraticForm(Q) ##random + sage: is_QuadraticForm(Q) + doctest:...: DeprecationWarning: the function is_QuadraticForm is deprecated; + use isinstance(x, sage.quadratic_forms.quadratic_form.QuadraticForm) instead... True - sage: is_QuadraticForm(2) ##random + sage: is_QuadraticForm(2) False """ + deprecation(35305, + "the function is_QuadraticForm is deprecated; use " + "isinstance(x, sage.quadratic_forms.quadratic_form.QuadraticForm) instead") return isinstance(Q, QuadraticForm) @@ -107,32 +100,31 @@ def quadratic_form_from_invariants(F, rk, det, P, sminus): EXAMPLES:: sage: P = [3,5] - sage: q = quadratic_form_from_invariants(QQ,2,-15,P,1) - sage: q + sage: q = quadratic_form_from_invariants(QQ,2,-15,P,1); q # needs sage.rings.padics Quadratic form in 2 variables over Rational Field with coefficients: [ 5 0 ] [ * -3 ] - sage: all(q.hasse_invariant(p)==-1 for p in P) + sage: all(q.hasse_invariant(p) == -1 for p in P) # needs sage.rings.padics True TESTS: This shows that :trac:`28955` is fixed:: - sage: quadratic_form_from_invariants(QQ,3,2,[2],2) + sage: quadratic_form_from_invariants(QQ,3,2,[2],2) # needs sage.rings.padics Quadratic form in 3 variables over Rational Field with coefficients: [ -1 0 0 ] [ * 1 0 ] [ * * -2 ] - sage: quadratic_form_from_invariants(QQ,4,2,[2],4) + sage: quadratic_form_from_invariants(QQ,4,2,[2],4) # needs sage.rings.padics Traceback (most recent call last): ... ValueError: invariants do not define a rational quadratic form """ from sage.arith.misc import hilbert_symbol # normalize input - if F!=QQ: + if F != QQ: raise NotImplementedError('base field must be QQ. If you want this over any field, implement weak approximation.') P = [ZZ(p) for p in P] rk = ZZ(rk) @@ -160,9 +152,9 @@ def quadratic_form_from_invariants(F, rk, det, P, sminus): else: a = ZZ(1) elif rk == 3: - Pprime = [p for p in P if hilbert_symbol(-1, -d, p)==1] - Pprime += [p for p in (2*d).prime_divisors() - if hilbert_symbol(-1, -d, p)==-1 and p not in P] + Pprime = [p for p in P if hilbert_symbol(-1, -d, p) == 1] + Pprime += [p for p in (2 * d).prime_divisors() + if hilbert_symbol(-1, -d, p) == -1 and p not in P] if sminus > 0: a = ZZ(-1) else: @@ -170,29 +162,29 @@ def quadratic_form_from_invariants(F, rk, det, P, sminus): for p in Pprime: if d.valuation(p) % 2 == 0: a *= p - assert all((a*d).valuation(p)%2==1 for p in Pprime) + assert all((a * d).valuation(p) % 2 == 1 for p in Pprime) elif rk == 2: S = P if sminus == 2: S += [-1] - a = QQ.hilbert_symbol_negative_at_S(S,-d) + a = QQ.hilbert_symbol_negative_at_S(S, -d) a = ZZ(a) P = ([p for p in P if hilbert_symbol(a, -d, p) == 1] - +[p for p in (2*a*d).prime_divisors() - if hilbert_symbol(a, -d, p)==-1 and p not in P]) - sminus = max(0, sminus-1) + + [p for p in (2 * a * d).prime_divisors() + if hilbert_symbol(a, -d, p) == -1 and p not in P]) + sminus = max(0, sminus - 1) rk = rk - 1 - d = a*d + d = a * d D.append(a.squarefree_part()) d = d.squarefree_part() D.append(d) - return DiagonalQuadraticForm(QQ,D) + return DiagonalQuadraticForm(QQ, D) class QuadraticForm(SageObject): r""" - The ``QuadraticForm`` class represents a quadratic form in n variables with - coefficients in the ring R. + The ``QuadraticForm`` class represents a quadratic form in `n` variables with + coefficients in the ring `R`. INPUT: @@ -200,21 +192,25 @@ class QuadraticForm(SageObject): #. ``QuadraticForm(R, n, entries)``, where - - `R` -- ring for which the quadratic form is defined - - `n` -- an integer >= 0 + - ``R`` -- ring for which the quadratic form is defined + - ``n`` -- an integer `\geq 0` - ``entries`` -- a list of `n(n+1)/2` coefficients of the quadratic form in `R` (given lexicographically, or equivalently, by rows of the matrix) + #. ``QuadraticForm(p)``, where + + - ``p`` -- a homogeneous polynomial of degree `2` + #. ``QuadraticForm(R, n)``, where - - `R` -- a ring - - `n` -- a symmetric `n \times n` matrix with even diagonal (relative to + - ``R`` -- a ring + - ``n`` -- a symmetric `n \times n` matrix with even diagonal (relative to `R`) #. ``QuadraticForm(R)``, where - - `R` -- a symmetric `n \times n` matrix with even diagonal (relative to + - ``R`` -- a symmetric `n \times n` matrix with even diagonal (relative to its base ring) If the keyword argument ``unsafe_initialize`` is True, then the subsequent @@ -225,14 +221,11 @@ class QuadraticForm(SageObject): - ``determinant`` - OUTPUT: - - quadratic form + OUTPUT: quadratic form EXAMPLES:: - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Q + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]); Q Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] @@ -240,8 +233,7 @@ class QuadraticForm(SageObject): :: - sage: Q = QuadraticForm(QQ, 3, [1,2,3,4/3 ,5,6]) - sage: Q + sage: Q = QuadraticForm(QQ, 3, [1,2,3,4/3,5,6]); Q Quadratic form in 3 variables over Rational Field with coefficients: [ 1 2 3 ] [ * 4/3 5 ] @@ -253,8 +245,7 @@ class QuadraticForm(SageObject): :: - sage: Q = QuadraticForm(QQ, 7, range(28)) - sage: Q + sage: Q = QuadraticForm(QQ, 7, range(28)); Q Quadratic form in 7 variables over Rational Field with coefficients: [ 0 1 2 3 4 5 6 ] [ * 7 8 9 10 11 12 ] @@ -267,7 +258,7 @@ class QuadraticForm(SageObject): :: sage: Q = QuadraticForm(QQ, 2, range(1,4)) - sage: A = Matrix(ZZ,2,2,[-1,0,0,1]) + sage: A = Matrix(ZZ, 2, 2, [-1,0,0,1]) sage: Q(A) Quadratic form in 2 variables over Rational Field with coefficients: [ 1 -2 ] @@ -275,7 +266,7 @@ class QuadraticForm(SageObject): :: - sage: m = matrix(2,2,[1,2,3,4]) + sage: m = matrix(2, 2, [1,2,3,4]) sage: m + m.transpose() [2 5] [5 8] @@ -284,6 +275,16 @@ class QuadraticForm(SageObject): [ 1 5 ] [ * 4 ] + :: + + sage: P.<x,y,z> = QQ[] + sage: p = x^2 + 2*x*y + x*z/2 + y^2 + y*z/3 + sage: QuadraticForm(p) + Quadratic form in 3 variables over Rational Field with coefficients: + [ 1 2 1/2 ] + [ * 1 1/3 ] + [ * * 0 ] + :: sage: QuadraticForm(ZZ, m + m.transpose()) @@ -303,11 +304,12 @@ class QuadraticForm(SageObject): # --------------------------- # Routines to compute the p-adic local normal form - from sage.quadratic_forms.quadratic_form__local_normal_form import \ - find_entry_with_minimal_scale_at_prime, \ - local_normal_form, \ - jordan_blocks_by_scale_and_unimodular, \ - jordan_blocks_in_unimodular_list_by_scale_power + lazy_import("sage.quadratic_forms.quadratic_form__local_normal_form", [ + "find_entry_with_minimal_scale_at_prime", + "local_normal_form", + "jordan_blocks_by_scale_and_unimodular", + "jordan_blocks_in_unimodular_list_by_scale_power" + ]) # Routines to perform elementary variable substitutions from sage.quadratic_forms.quadratic_form__variable_substitutions import \ @@ -362,9 +364,10 @@ class QuadraticForm(SageObject): count_congruence_solutions__bad_type_II # Routines to be called by the user to compute local densities - from sage.quadratic_forms.quadratic_form__local_density_interfaces import \ - local_density, \ - local_primitive_density + lazy_import("sage.quadratic_forms.quadratic_form__local_density_interfaces", [ + "local_density", + "local_primitive_density" + ]) # Routines for computing with ternary forms from sage.quadratic_forms.quadratic_form__ternary_Tornaria import \ @@ -400,8 +403,9 @@ class QuadraticForm(SageObject): theta_by_cholesky # Routines to compute the product of all local densities - from sage.quadratic_forms.quadratic_form__siegel_product import \ - siegel_product + lazy_import("sage.quadratic_forms.quadratic_form__siegel_product", [ + "siegel_product" + ]) # Routines to compute p-neighbors from sage.quadratic_forms.quadratic_form__neighbors import \ @@ -419,47 +423,51 @@ class QuadraticForm(SageObject): minkowski_reduction, \ minkowski_reduction_for_4vars__SP # Wrappers for Conway-Sloane genus routines (in ./genera/) - from sage.quadratic_forms.quadratic_form__genus import \ - global_genus_symbol, \ - local_genus_symbol, \ - CS_genus_symbol_list - + lazy_import("sage.quadratic_forms.quadratic_form__genus", [ + "global_genus_symbol", + "local_genus_symbol", + "CS_genus_symbol_list" + ]) # Routines to compute local masses for ZZ. - from sage.quadratic_forms.quadratic_form__mass import \ - shimura_mass__maximal, \ - GHY_mass__maximal - from sage.quadratic_forms.quadratic_form__mass__Siegel_densities import \ - mass__by_Siegel_densities, \ - Pall_mass_density_at_odd_prime, \ - Watson_mass_at_2, \ - Kitaoka_mass_at_2, \ - mass_at_two_by_counting_mod_power - from sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses import \ - parity, \ - is_even, \ - is_odd, \ - conway_species_list_at_odd_prime, \ - conway_species_list_at_2, \ - conway_octane_of_this_unimodular_Jordan_block_at_2, \ - conway_diagonal_factor, \ - conway_cross_product_doubled_power, \ - conway_type_factor, \ - conway_p_mass, \ - conway_standard_p_mass, \ - conway_standard_mass, \ - conway_mass + lazy_import("sage.quadratic_forms.quadratic_form__mass", [ + "shimura_mass__maximal", + "GHY_mass__maximal" + ]) + lazy_import("sage.quadratic_forms.quadratic_form__mass__Siegel_densities", [ + "mass__by_Siegel_densities", + "Pall_mass_density_at_odd_prime", + "Watson_mass_at_2", + "Kitaoka_mass_at_2", + "mass_at_two_by_counting_mod_power" + ]) + lazy_import("sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses", [ + "parity", + "is_even", + "is_odd", + "conway_species_list_at_odd_prime", + "conway_species_list_at_2", + "conway_octane_of_this_unimodular_Jordan_block_at_2", + "conway_diagonal_factor", + "conway_cross_product_doubled_power", + "conway_type_factor", + "conway_p_mass", + "conway_standard_p_mass", + "conway_standard_mass", + "conway_mass" # conway_generic_mass, \ # conway_p_mass_adjustment + ]) # Routines to check local representability of numbers - from sage.quadratic_forms.quadratic_form__local_representation_conditions import \ - local_representation_conditions, \ - is_locally_universal_at_prime, \ - is_locally_universal_at_all_primes, \ - is_locally_universal_at_all_places, \ - is_locally_represented_number_at_place, \ - is_locally_represented_number + lazy_import("sage.quadratic_forms.quadratic_form__local_representation_conditions", [ + "local_representation_conditions", + "is_locally_universal_at_prime", + "is_locally_universal_at_all_primes", + "is_locally_universal_at_all_places", + "is_locally_represented_number_at_place", + "is_locally_represented_number" + ]) # Routines to make a split local covering of the given quadratic form. from sage.quadratic_forms.quadratic_form__split_local_covering import \ @@ -469,15 +477,16 @@ class QuadraticForm(SageObject): split_local_cover # Routines to make automorphisms of the given quadratic form. - from sage.quadratic_forms.quadratic_form__automorphisms import \ - basis_of_short_vectors, \ - short_vector_list_up_to_length, \ - short_primitive_vector_list_up_to_length, \ - _compute_automorphisms, \ - automorphism_group, \ - automorphisms, \ - number_of_automorphisms, \ - set_number_of_automorphisms + lazy_import("sage.quadratic_forms.quadratic_form__automorphisms", [ + "basis_of_short_vectors", + "short_vector_list_up_to_length", + "short_primitive_vector_list_up_to_length", + "_compute_automorphisms", + "automorphism_group", + "automorphisms", + "number_of_automorphisms", + "set_number_of_automorphisms" + ]) # Routines to test the local and global equivalence/isometry of two quadratic forms. from sage.quadratic_forms.quadratic_form__equivalence_testing import \ @@ -487,9 +496,13 @@ class QuadraticForm(SageObject): is_rationally_isometric # Routines for solving equations of the form Q(x) = c. - from sage.quadratic_forms.qfsolve import solve - + lazy_import("sage.quadratic_forms.qfsolve", [ + "solve" + ]) + # Genus + lazy_import("sage.quadratic_forms.genera.genus", + "_genera_staticmethod", as_="genera") def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_of_automorphisms=None, determinant=None): """ @@ -499,6 +512,25 @@ def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_ sage: s.dim() 4 + sage: P.<x,y,z> = QQ[] + sage: p = x^2 + y^2 + 2*x*z + sage: QuadraticForm(p) + Quadratic form in 3 variables over Rational Field with coefficients: + [ 1 0 2 ] + [ * 1 0 ] + [ * * 0 ] + sage: z = P.zero() + sage: QuadraticForm(z) + Quadratic form in 3 variables over Rational Field with coefficients: + [ 0 0 0 ] + [ * 0 0 ] + [ * * 0 ] + sage: q = x^2 + 3*y - z + sage: QuadraticForm(q) + Traceback (most recent call last): + ... + ValueError: polynomial is neither zero nor homogeneous of degree 2 + TESTS:: sage: s == loads(dumps(s)) @@ -510,6 +542,10 @@ def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_ sage: x = polygen(ZZ, 'x') sage: QuadraticForm(x**2) + Quadratic form in 1 variables over Integer Ring with coefficients: + [ 1 ] + + sage: QuadraticForm(1) Traceback (most recent call last): .... TypeError: wrong input for QuadraticForm @@ -527,20 +563,41 @@ def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_ M_ring = R matrix_init_flag = True - elif not is_Matrix(R): - # first argument, if not a ring, must be a matrix - raise TypeError('wrong input for QuadraticForm') - else: - # Deal with: QuadraticForm(matrix) + elif is_Matrix(R): + M = R + # Test if R is symmetric and has even diagonal - if not self._is_even_symmetric_matrix_(R): + if not self._is_even_symmetric_matrix_(M): raise TypeError("the matrix is not a symmetric with even diagonal") - # Rename the matrix and ring - M = R - M_ring = R.base_ring() + M_ring = M.base_ring() matrix_init_flag = True + elif isinstance(R, (Polynomial, MPolynomial)): + p = R + + if not p.is_zero() and not (p.is_homogeneous() and p.degree() == 2): + raise ValueError("polynomial is neither zero nor homogeneous of degree 2") + + P = p.parent() + R, n = P.base_ring(), P.ngens() + + # Extract quadratic form coefficients + entries = [] + if n == 0: + exponents = [] + elif n == 1: + exponents = [2] + else: + from sage.combinat.integer_lists.invlex import IntegerListsLex + + exponents = IntegerListsLex(2, length=n) + for alpha in exponents: + entries.append(p[alpha]) + + else: + raise TypeError('wrong input for QuadraticForm') + # Perform the quadratic form initialization if matrix_init_flag: self.__n = ZZ(M.nrows()) @@ -548,10 +605,10 @@ def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_ self.__coeffs = [] for i in range(M.nrows()): for j in range(i, M.nrows()): - if (i == j): - self.__coeffs += [ M_ring(M[i,j] / 2) ] + if i == j: + self.__coeffs += [M_ring(M[i, j] / 2)] else: - self.__coeffs += [ M_ring(M[i,j]) ] + self.__coeffs += [M_ring(M[i, j])] return @@ -591,8 +648,8 @@ def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_ # Set the number of automorphisms if number_of_automorphisms is not None: self.set_number_of_automorphisms(number_of_automorphisms) - #self.__number_of_automorphisms = number_of_automorphisms - #self.__external_initialization_list.append('number_of_automorphisms') + # self.__number_of_automorphisms = number_of_automorphisms + # self.__external_initialization_list.append('number_of_automorphisms') # Set the determinant if determinant is not None: @@ -602,7 +659,7 @@ def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_ def list_external_initializations(self): """ Return a list of the fields which were set externally at - creation, and not created through the usual QuadraticForm + creation, and not created through the usual :class:`QuadraticForm` methods. These fields are as good as the external process that made them, and are thus not guaranteed to be correct. @@ -611,25 +668,30 @@ def list_external_initializations(self): sage: Q = QuadraticForm(ZZ, 2, [1,0,5]) sage: Q.list_external_initializations() [] + + sage: # needs sage.libs.pari sage: T = Q.theta_series() sage: Q.list_external_initializations() [] - sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, number_of_automorphisms=3, determinant=0) + sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, + ....: number_of_automorphisms=3, determinant=0) sage: Q.list_external_initializations() [] :: - sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, number_of_automorphisms=3, determinant=0) + sage: # needs sage.libs.pari + sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=False, + ....: number_of_automorphisms=3, determinant=0) sage: Q.list_external_initializations() [] - sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=True, number_of_automorphisms=3, determinant=0) + sage: Q = QuadraticForm(ZZ, 2, [1,0,5], unsafe_initialization=True, + ....: number_of_automorphisms=3, determinant=0) sage: Q.list_external_initializations() ['number_of_automorphisms', 'determinant'] """ return deepcopy(self._external_initialization_list) - def __pari__(self): """ Return a PARI-formatted Hessian matrix for Q. @@ -637,7 +699,7 @@ def __pari__(self): EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,0,5]) - sage: Q.__pari__() + sage: Q.__pari__() # needs sage.libs.pari [2, 0; 0, 10] """ @@ -650,7 +712,7 @@ def _pari_init_(self): EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,0,5]) - sage: Q._pari_init_() + sage: Q._pari_init_() # needs sage.libs.pari 'Mat([2,0;0,10])' """ return self.matrix()._pari_init_() @@ -665,7 +727,6 @@ def _repr_(self): Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 3 ] [ * 5 ] - """ n = self.dim() out_str = "Quadratic form in " + str(n) + " variables over " + str(self.base_ring()) + " with coefficients: \n" @@ -681,7 +742,6 @@ def _repr_(self): out_str += "]" return out_str - def _latex_(self): """ Give a LaTeX representation for the quadratic form given as an upper-triangular matrix of coefficients. @@ -691,7 +751,6 @@ def _latex_(self): sage: Q = QuadraticForm(ZZ, 2, [2,3,5]) sage: Q._latex_() 'Quadratic form in 2 variables over Integer Ring with coefficients: \\newline\\left[ \\begin{array}{cc}2 & 3 & * & 5 & \\end{array} \\right]' - """ n = self.dim() out_str = "" @@ -710,8 +769,8 @@ def _latex_(self): return out_str def __getitem__(self, ij): - """ - Return the coefficient `a_{ij}` of `x_i * x_j`. + r""" + Return the coefficient `a_{ij}` of `x_i\cdot x_j`. EXAMPLES:: @@ -723,7 +782,7 @@ def __getitem__(self, ij): """ # Unpack the list of indices - i, j = ij + i, j = ij i = int(i) j = int(j) @@ -736,8 +795,8 @@ def __getitem__(self, ij): return self.__coeffs[i*self.__n - i*(i-1)//2 + j - i] def __setitem__(self, ij, coeff): - """ - Set the coefficient `a_{ij}` in front of `x_i * x_j`. + r""" + Set the coefficient `a_{ij}` in front of `x_i\cdot x_j`. EXAMPLES:: @@ -756,7 +815,7 @@ def __setitem__(self, ij, coeff): """ # Unpack the list of indices - i, j = ij + i, j = ij i = int(i) j = int(j) @@ -770,7 +829,7 @@ def __setitem__(self, ij, coeff): # Set the entry try: - self.__coeffs[i*self.__n - i*(i-1)//2 + j -i] = self.__base_ring(coeff) + self.__coeffs[i*self.__n - i*(i-1)//2 + j - i] = self.__base_ring(coeff) except Exception: raise RuntimeError("this coefficient cannot be coerced to an element of the base ring for the quadratic form") @@ -780,10 +839,10 @@ def __hash__(self): sage: Q1 = QuadraticForm(QQ, 2, [1,1,1]) sage: Q2 = QuadraticForm(QQ, 2, [1,1,1]) - sage: Q3 = QuadraticForm(QuadraticField(2), 2, [1,1,1]) + sage: Q3 = QuadraticForm(QuadraticField(2), 2, [1,1,1]) # needs sage.rings.number_field sage: hash(Q1) == hash(Q2) True - sage: hash(Q1) == hash(Q3) + sage: hash(Q1) == hash(Q3) # needs sage.rings.number_field False """ return hash(self.__base_ring) ^ hash(tuple(self.__coeffs)) @@ -821,8 +880,7 @@ def __add__(self, right): EXAMPLES:: - sage: Q = QuadraticForm(ZZ, 2, [1,4,10]) - sage: Q + sage: Q = QuadraticForm(ZZ, 2, [1,4,10]); Q Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 4 ] [ * 10 ] @@ -859,12 +917,11 @@ def sum_by_coefficients_with(self, right): EXAMPLES:: - sage: Q = QuadraticForm(ZZ, 2, [1,4,10]) - sage: Q + sage: Q = QuadraticForm(ZZ, 2, [1,4,10]); Q Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 4 ] [ * 10 ] - sage: Q+Q + sage: Q + Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 4 0 0 ] [ * 10 0 0 ] @@ -879,51 +936,46 @@ def sum_by_coefficients_with(self, right): """ if not isinstance(right, QuadraticForm): raise TypeError("cannot add these objects since they are not both quadratic forms") - elif (self.__n != right.__n): + elif self.__n != right.__n: raise TypeError("cannot add these since the quadratic forms do not have the same sizes") - elif (self.__base_ring != right.__base_ring): + elif self.__base_ring != right.__base_ring: raise TypeError("cannot add these since the quadratic forms do not have the same base rings") - return QuadraticForm(self.__base_ring, self.__n, [self.__coeffs[i] + right.__coeffs[i] for i in range(len(self.__coeffs))]) - - -# ======================== CHANGE THIS TO A TENSOR PRODUCT?!? Even in Characteristic 2?!? ======================= -# def __mul__(self, right): -# """ -# Multiply (on the right) the quadratic form Q by an element of the ring that Q is defined over. -# -# EXAMPLES:: -# -# sage: Q = QuadraticForm(ZZ, 2, [1,4,10]) -# sage: Q*2 -# Quadratic form in 2 variables over Integer Ring with coefficients: -# [ 2 8 ] -# [ * 20 ] -# -# sage: Q+Q == Q*2 -# True -# -# """ -# try: -# c = self.base_ring()(right) -# except Exception: -# raise TypeError, "Oh no! The multiplier cannot be coerced into the base ring of the quadratic form. =(" -# -# return QuadraticForm(self.base_ring(), self.dim(), [c * self.__coeffs[i] for i in range(len(self.__coeffs))]) -# ========================================================================================================================= - - + return QuadraticForm(self.__base_ring, self.__n, [self.__coeffs[i] + right.__coeffs[i] for i in range(len(self.__coeffs))]) + + # ======================== CHANGE THIS TO A TENSOR PRODUCT?!? Even in Characteristic 2?!? ======================= + # def __mul__(self, right): + # """ + # Multiply (on the right) the quadratic form Q by an element of the ring that Q is defined over. + # + # EXAMPLES:: + # + # sage: Q = QuadraticForm(ZZ, 2, [1,4,10]) + # sage: Q*2 + # Quadratic form in 2 variables over Integer Ring with coefficients: + # [ 2 8 ] + # [ * 20 ] + # + # sage: Q+Q == Q*2 + # True + # """ + # try: + # c = self.base_ring()(right) + # except Exception: + # raise TypeError("the multiplier cannot be coerced into the base ring of the quadratic form") + # return QuadraticForm(self.base_ring(), self.dim(), [c * self.__coeffs[i] for i in range(len(self.__coeffs))]) def __call__(self, v): - """ - Evaluate this quadratic form Q on a vector or matrix of elements - coercible to the base ring of the quadratic form. If a vector - is given then the output will be the ring element Q(`v`), but if a - matrix is given then the output will be the quadratic form Q' - which in matrix notation is given by: + r""" + Evaluate this quadratic form `Q` on a vector or matrix of elements + coercible to the base ring of the quadratic form. + + If a vector is given then the output will be the ring element + `Q(v)`, but if a matrix is given then the output will be the + quadratic form `Q'` which in matrix notation is given by: .. MATH:: - Q' = v^t * Q * v. + Q' = v^t\cdot Q\cdot v. EXAMPLES: @@ -1024,19 +1076,17 @@ def __call__(self, v): else: raise TypeError - - - -# ===================================================================================================== + # =============================================== def _is_even_symmetric_matrix_(self, A, R=None): """ - Tests if a matrix is symmetric, defined over R, and has even diagonal in R. + Tests if a matrix is symmetric, defined over `R`, and has even diagonal in `R`. INPUT: - A -- matrix - R -- ring + - ``A`` -- matrix + + - ``R`` -- ring EXAMPLES:: @@ -1063,39 +1113,32 @@ def _is_even_symmetric_matrix_(self, A, R=None): if not isinstance(R, Ring): raise TypeError("R is not a ring.") - if not A.is_square(): + if not (A.is_square() and A.is_symmetric()): return False - # Test that the matrix is symmetric - n = A.nrows() - for i in range(n): - for j in range(i+1, n): - if A[i,j] != A[j,i]: - return False - # Test that all entries coerce to R + n = A.nrows() if not ((A.base_ring() == R) or ring_coerce_test): try: for i in range(n): for j in range(i, n): - R(A[i,j]) - except Exception: + R(A[i, j]) + except (TypeError, ValueError): return False # Test that the diagonal is even (if 1/2 isn't in R) if not R(2).is_unit(): for i in range(n): - if not is_even(R(A[i,i])): + if not is_even(R(A[i, i])): return False return True - -# ===================================================================================================== + # ===================================================================== def matrix(self): - """ - Return the Hessian matrix A for which Q(X) = `(1/2) * X^t * A * X`. + r""" + Return the Hessian matrix `A` for which `Q(X) = (1/2) X^t\cdot A\cdot X`. EXAMPLES:: @@ -1109,13 +1152,12 @@ def matrix(self): return self.Hessian_matrix() def Hessian_matrix(self): - """ - Return the Hessian matrix A for which Q(X) = `(1/2) * X^t * A * X`. + r""" + Return the Hessian matrix `A` for which `Q(X) = (1/2) X^t\cdot A\cdot X`. EXAMPLES:: - sage: Q = QuadraticForm(QQ, 2, range(1,4)) - sage: Q + sage: Q = QuadraticForm(QQ, 2, range(1,4)); Q Quadratic form in 2 variables over Rational Field with coefficients: [ 1 2 ] [ * 3 ] @@ -1129,21 +1171,21 @@ def Hessian_matrix(self): mat_entries = [] for i in range(self.dim()): for j in range(self.dim()): - if (i == j): - mat_entries += [ 2 * self[i,j] ] + if i == j: + mat_entries += [2 * self[i, j]] else: - mat_entries += [ self[i,j] ] + mat_entries += [self[i, j]] return matrix(self.base_ring(), self.dim(), self.dim(), mat_entries) def Gram_matrix_rational(self): - """ - Return a (symmetric) Gram matrix A for the quadratic form Q, + r""" + Return a (symmetric) Gram matrix `A` for the quadratic form `Q`, meaning that .. MATH:: - Q(x) = x^t * A * x, + Q(x) = x^t\cdot A\cdot x, defined over the fraction field of the base ring. @@ -1162,16 +1204,16 @@ def Gram_matrix_rational(self): return (ZZ(1) / ZZ(2)) * self.matrix() def Gram_matrix(self): - """ - Return a (symmetric) Gram matrix A for the quadratic form Q, + r""" + Return a (symmetric) Gram matrix `A` for the quadratic form `Q`, meaning that .. MATH:: - Q(x) = x^t * A * x, + Q(x) = x^t\cdot A\cdot x, - defined over the base ring of Q. If this is not possible, - then a TypeError is raised. + defined over the base ring of `Q`. If this is not possible, + then a :class:`TypeError` is raised. EXAMPLES:: @@ -1199,7 +1241,7 @@ def Gram_matrix(self): raise TypeError("this form does not have an integral Gram matrix") def has_integral_Gram_matrix(self): - """ + r""" Return whether the quadratic form has an integral Gram matrix (with respect to its base ring). A warning is issued if the form is defined over a field, since in that case the return is trivially true. @@ -1251,17 +1293,15 @@ def gcd(self): def polynomial(self,names='x'): r""" - Return the polynomial in 'n' variables of the quadratic form in the ring 'R[names].' + Return the quadratic form as a polynomial in `n` variables. INPUT: - -'self' - a quadratic form over a commutative ring. - -'names' - the name of the variables. Digits will be appended to the name for each different canonical - variable e.g x1, x2, x3 etc. + - ``self`` - a quadratic form over a commutative ring - OUTPUT: + - ``names`` - specification of the names of the variables; see :func:`PolynomialRing` - The polynomial form of the quadratic form. + OUTPUT: The polynomial form of the quadratic form. EXAMPLES:: @@ -1271,14 +1311,18 @@ def polynomial(self,names='x'): :: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: F.<a> = NumberField(x^2 - 5) sage: Z = F.ring_of_integers() - sage: Q = QuadraticForm(Z,3,[2*a, 3*a, 0 , 1 - a, 0, 2*a + 4]) + sage: Q = QuadraticForm(Z, 3, [2*a, 3*a, 0, 1 - a, 0, 2*a + 4]) sage: P = Q.polynomial(names='y'); P 2*a*y0^2 + 3*a*y0*y1 + (-a + 1)*y1^2 + (2*a + 4)*y2^2 - sage: Q = QuadraticForm(F,4,[a, 3*a, 0, 1 - a, a - 3, 0, 2*a + 4, 4 + a, 0, 1]) + sage: Q = QuadraticForm(F, 4, + ....: [a, 3*a, 0, 1 - a, a - 3, 0, 2*a + 4, 4 + a, 0, 1]) sage: Q.polynomial(names='z') - a*z0^2 + (3*a)*z0*z1 + (a - 3)*z1^2 + (a + 4)*z2^2 + (-a + 1)*z0*z3 + (2*a + 4)*z1*z3 + z3^2 + a*z0^2 + (3*a)*z0*z1 + (a - 3)*z1^2 + (a + 4)*z2^2 + + (-a + 1)*z0*z3 + (2*a + 4)*z1*z3 + z3^2 sage: B.<i,j,k> = QuaternionAlgebra(F,-1,-1) sage: Q = QuadraticForm(B, 3, [2*a, 3*a, i, 1 - a, 0, 2*a + 4]) sage: Q.polynomial() @@ -1332,21 +1376,19 @@ def from_polynomial(poly): if not isinstance(R, MPolynomialRing_base): raise TypeError(f'not a multivariate polynomial ring: {R}') if not all(mon.degree() == 2 for mon in poly.monomials()): - raise ValueError(f'polynomial has monomials of degree != 2') + raise ValueError('polynomial has monomials of degree != 2') base = R.base_ring() vs = R.gens() coeffs = [] - for i,v in enumerate(vs): + for i, v in enumerate(vs): for w in vs[i:]: coeffs.append(poly.monomial_coefficient(v*w)) return QuadraticForm(base, len(vs), coeffs) - - def is_primitive(self): """ Determines if the given integer-valued form is primitive - (i.e. not an integer (>1) multiple of another integer-valued + (i.e. not an integer (`> 1`) multiple of another integer-valued quadratic form). EXAMPLES:: @@ -1362,8 +1404,8 @@ def is_primitive(self): return (self.gcd() == 1) def primitive(self): - """ - Return a primitive version of an integer-valued quadratic form, defined over `ZZ`. + r""" + Return a primitive version of an integer-valued quadratic form, defined over `\ZZ`. EXAMPLES:: @@ -1404,7 +1446,7 @@ def adjoint_primitive(self): def dim(self): """ - Gives the number of variables of the quadratic form. + Return the number of variables of the quadratic form. EXAMPLES:: @@ -1423,21 +1465,19 @@ def dim(self): def base_ring(self): """ - Gives the ring over which the quadratic form is defined. + Return the ring over which the quadratic form is defined. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.base_ring() Integer Ring - """ return self.__base_ring - def coefficients(self): - """ - Gives the matrix of upper triangular coefficients, + r""" + Return the matrix of upper triangular coefficients, by reading across the rows from the main diagonal. EXAMPLES:: @@ -1445,25 +1485,23 @@ def coefficients(self): sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.coefficients() [1, 2, 3] - """ return self.__coeffs - def det(self): - """ - Gives the determinant of the Gram matrix of 2*Q, or - equivalently the determinant of the Hessian matrix of Q. + r""" + Return the determinant of the Gram matrix of `2\cdot Q`, or + equivalently the determinant of the Hessian matrix of `Q`. + + .. NOTE: - (Note: This is always defined over the same ring as the - quadratic form.) + This is always defined over the same ring as the quadratic form. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.det() 8 - """ try: return self.__det @@ -1478,60 +1516,58 @@ def det(self): self.__det = new_det return new_det - def Gram_det(self): - """ - Gives the determinant of the Gram matrix of Q. + r""" + Return the determinant of the Gram matrix of `Q`. - (Note: This is defined over the fraction field of the ring of - the quadratic form, but is often not defined over the same - ring as the quadratic form.) + .. NOTE:: + + This is defined over the fraction field of the ring of + the quadratic form, but is often not defined over the same + ring as the quadratic form. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: Q.Gram_det() 2 - """ return self.det() / ZZ(2**self.dim()) - - def base_change_to(self, R): + def change_ring(self, R): """ Alters the quadratic form to have all coefficients - defined over the new base_ring R. Here R must be + defined over the new base ring `R`. Here `R` must be coercible to from the current base ring. - Note: This is preferable to performing an explicit - coercion through the base_ring() method, which does - not affect the individual coefficients. This is - particularly useful for performing fast modular - arithmetic evaluations. + .. NOTE:: + + This is preferable to performing an explicit + coercion through the :meth:`base_ring` method, which does + not affect the individual coefficients. This is + particularly useful for performing fast modular + arithmetic evaluations. INPUT: - R -- a ring - OUTPUT: - quadratic form + - ``R`` -- a ring + + OUTPUT: quadratic form EXAMPLES:: - sage: Q = DiagonalQuadraticForm(ZZ,[1,1]); Q + sage: Q = DiagonalQuadraticForm(ZZ, [1,1]); Q Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 0 ] [ * 1 ] - :: - - sage: Q1 = Q.base_change_to(IntegerModRing(5)); Q1 + sage: Q1 = Q.change_ring(IntegerModRing(5)); Q1 Quadratic form in 2 variables over Ring of integers modulo 5 with coefficients: [ 1 0 ] [ * 1 ] sage: Q1([35,11]) 1 - """ # Check that a canonical coercion is possible if not is_Ring(R): @@ -1541,11 +1577,13 @@ def base_change_to(self, R): # Return the coerced form return QuadraticForm(R, self.dim(), [R(x) for x in self.coefficients()]) + base_change_to = deprecated_function_alias(35248, change_ring) + def level(self): r""" Determines the level of the quadratic form over a PID, which is a - generator for the smallest ideal `N` of `R` such that N * (the matrix of - 2*Q)^(-1) is in R with diagonal in 2*R. + generator for the smallest ideal `N` of `R` such that `N\cdot (` the matrix of + `2*Q` `)^{(-1)}` is in `R` with diagonal in `2R`. Over `\ZZ` this returns a non-negative number. @@ -1559,13 +1597,13 @@ def level(self): sage: Q1 = QuadraticForm(QQ, 2, range(1,4)) sage: Q1.level() # random - UserWarning: Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!? + UserWarning: Warning -- The level of a quadratic form over a field is always 1. + Do you really want to do this?!? 1 sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.level() 420 - """ # Try to return the cached level try: @@ -1579,8 +1617,7 @@ def level(self): # Warn the user if the form is defined over a field! if self.base_ring().is_field(): warn("Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!?") - #raise RuntimeError, "Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!?" - + # raise RuntimeError("Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!?") # Check invertibility and find the inverse try: @@ -1613,14 +1650,16 @@ def level(self): return lvl def level_ideal(self): - """ - Determines the level of the quadratic form (over R), which is the - smallest ideal N of R such that N * (the matrix of 2*Q)^(-1) is - in R with diagonal in 2*R. + r""" + Determine the level of the quadratic form (over `R`), which is the + smallest ideal `N` of `R` such that `N \cdot (` the matrix of `2Q` `)^{(-1)}` is + in `R` with diagonal in `2R`. (Caveat: This always returns the principal ideal when working over a field!) - WARNING: THIS ONLY WORKS OVER A PID RING OF INTEGERS FOR NOW! - (Waiting for Sage fractional ideal support.) + .. WARNING:: + + This only works over a PID ring of integers for now! + (Waiting for Sage fractional ideal support.) EXAMPLES:: @@ -1654,46 +1693,45 @@ def bilinear_map(self, v, w): INPUT: - `v, w` -- two vectors + - ``v``, ``w`` -- two vectors - OUTPUT: - - an element of the base ring `R`. + OUTPUT: an element of the base ring `R`. EXAMPLES: First, an example over `\ZZ`:: - sage: Q = QuadraticForm(ZZ,3,[1,4,0,1,4,1]) - sage: v = vector(ZZ,(1,2,0)) - sage: w = vector(ZZ,(0,1,1)) - sage: Q.bilinear_map(v,w) + sage: Q = QuadraticForm(ZZ, 3, [1,4,0,1,4,1]) + sage: v = vector(ZZ, (1,2,0)) + sage: w = vector(ZZ, (0,1,1)) + sage: Q.bilinear_map(v, w) 8 This also works over `\QQ`:: - sage: Q = QuadraticForm(QQ,2,[1/2,2,1]) - sage: v = vector(QQ,(1,1)) - sage: w = vector(QQ,(1/2,2)) - sage: Q.bilinear_map(v,w) + sage: Q = QuadraticForm(QQ, 2, [1/2,2,1]) + sage: v = vector(QQ, (1,1)) + sage: w = vector(QQ, (1/2,2)) + sage: Q.bilinear_map(v, w) 19/4 The vectors must have the correct length:: - sage: Q = DiagonalQuadraticForm(ZZ,[1,7,7]) + sage: Q = DiagonalQuadraticForm(ZZ, [1,7,7]) sage: v = vector((1,2)) sage: w = vector((1,1,1)) - sage: Q.bilinear_map(v,w) + sage: Q.bilinear_map(v, w) Traceback (most recent call last): ... TypeError: vectors must have length 3 This does not work if the characteristic is 2:: - sage: Q = DiagonalQuadraticForm(GF(2),[1,1,1]) + sage: # needs sage.rings.finite_rings + sage: Q = DiagonalQuadraticForm(GF(2), [1,1,1]) sage: v = vector((1,1,1)) sage: w = vector((1,1,1)) - sage: Q.bilinear_map(v,w) + sage: Q.bilinear_map(v, w) Traceback (most recent call last): ... TypeError: not defined for rings of characteristic 2 @@ -1702,9 +1740,7 @@ def bilinear_map(self, v, w): raise TypeError("vectors must have length " + str(self.dim())) if self.base_ring().characteristic() == 2: raise TypeError("not defined for rings of characteristic 2") - return (self(v+w) - self(v) - self(w))/2 - - genera = staticmethod(genera) + return (self(v + w) - self(v) - self(w)) / 2 def DiagonalQuadraticForm(R, diag): @@ -1713,17 +1749,14 @@ def DiagonalQuadraticForm(R, diag): INPUT: - - `R` -- ring - - ``diag`` -- list/tuple of elements coercible to R - - OUTPUT: + - ``R`` -- ring + - ``diag`` -- list/tuple of elements coercible to `R` - quadratic form + OUTPUT: quadratic form EXAMPLES:: - sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) - sage: Q + sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]); Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 0 0 ] [ * 3 0 0 ] diff --git a/src/sage/quadratic_forms/quadratic_form__automorphisms.py b/src/sage/quadratic_forms/quadratic_form__automorphisms.py index 3d72cf3be11..d0bf38f71a5 100644 --- a/src/sage/quadratic_forms/quadratic_form__automorphisms.py +++ b/src/sage/quadratic_forms/quadratic_form__automorphisms.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari """ Automorphisms of Quadratic Forms """ @@ -8,19 +9,18 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from sage.misc.cachefunc import cached_method -from sage.libs.pari.all import pari from sage.matrix.constructor import Matrix from sage.rings.integer_ring import ZZ -from sage.modules.all import FreeModule +from sage.modules.free_module import FreeModule from sage.modules.free_module_element import vector -from sage.arith.all import GCD +from sage.arith.misc import GCD @cached_method def basis_of_short_vectors(self, show_lengths=False): r""" - Return a basis for `\ZZ^n` made of vectors with minimal lengths Q(`v`). + Return a basis for `\ZZ^n` made of vectors with minimal lengths `Q(v)`. OUTPUT: @@ -101,11 +101,11 @@ def basis_of_short_vectors(self, show_lengths=False): def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): """ Return a list of lists of short vectors `v`, sorted by length, with - Q(`v`) < len_bound. + `Q(v) <` ``len_bound``. INPUT: - - ``len_bound`` -- bound for the length of the vectors. + - ``len_bound`` -- bound for the length of the vectors - ``up_to_sign_flag`` -- (default: ``False``) if set to True, then only one of the vectors of the pair `[v, -v]` is listed. @@ -186,6 +186,8 @@ def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): raise ValueError("Quadratic form must be positive definite " "in order to enumerate short vectors") + from sage.libs.pari.all import pari + if len_bound <= 0: return [] @@ -224,8 +226,8 @@ def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): def short_primitive_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): r""" Return a list of lists of short primitive vectors `v`, sorted by length, with - Q(`v`) < len_bound. The list in output `[i]` indexes all vectors of - length `i`. If the up_to_sign_flag is set to ``True``, then only one of + `Q(v) <` ``len_bound``. The list in output `[i]` indexes all vectors of + length `i`. If the ``up_to_sign_flag`` is set to ``True``, then only one of the vectors of the pair `[v, -v]` is listed. .. NOTE:: @@ -374,13 +376,11 @@ def automorphisms(self): def number_of_automorphisms(self): - """ - Return the number of automorphisms (of det 1 and -1) of + r""" + Return the number of automorphisms (of det `1` and `-1`) of the quadratic form. - OUTPUT: - - an integer >= 2. + OUTPUT: an integer `\geq 2`. EXAMPLES:: @@ -404,13 +404,13 @@ def number_of_automorphisms(self): def set_number_of_automorphisms(self, num_autos): - """ + r""" Set the number of automorphisms to be the value given. No error checking is performed, to this may lead to erroneous results. The fact that this result was set externally is recorded in the internal list of external initializations, accessible by the - method list_external_initializations(). + method :meth:`list_external_initializations`. OUTPUT: None diff --git a/src/sage/quadratic_forms/quadratic_form__count_local_2.py b/src/sage/quadratic_forms/quadratic_form__count_local_2.py index 54b072109f3..999da6428de 100644 --- a/src/sage/quadratic_forms/quadratic_form__count_local_2.py +++ b/src/sage/quadratic_forms/quadratic_form__count_local_2.py @@ -13,21 +13,21 @@ def count_congruence_solutions_as_vector(self, p, k, m, zvec, nzvec): - """ - Gives the number of integer solution vectors `x` satisfying the - congruence Q(`x`) `= m (mod p^k)` of each solution type (i.e. All, + r""" + Return the number of integer solution vectors `x` satisfying the + congruence `Q(x) = m` (mod `p^k`) of each solution type (i.e. All, Good, Zero, Bad, BadI, BadII) which satisfy the additional congruence conditions of having certain coefficients = 0 (mod `p`) and certain collections of coefficients not congruent to the zero vector (mod `p`). A solution vector `x` satisfies the additional congruence conditions - specified by zvec and nzvec (and therefore is counted) iff both of + specified by ``zvec`` and ``nzvec`` (and therefore is counted) iff both of the following conditions hold: - 1) `x[i] == 0 (mod p)` for all `i` in zvec + 1. `x_i = 0` (mod `p`) for all `i` in ``zvec`` - 2) `x[i] != 0 (mod p) for all i` in nzvec + 2. `x_i \neq 0` (mod `p`) for all `i` in ``nzvec`` REFERENCES: @@ -37,14 +37,14 @@ def count_congruence_solutions_as_vector(self, p, k, m, zvec, nzvec): INPUT: - - `p` -- prime number > 0 - - `k` -- an integer > 0 - - `m` -- an integer (depending only on mod `p^k`) - - zvec, nzvec -- a list of integers in range(self.dim()), or None + - ``p`` -- prime number > 0 + - ``k`` -- an integer > 0 + - ``m`` -- an integer (depending only on mod `p^k`) + - ``zvec``, ``nzvec`` -- lists of integers in ``range(self.dim())``, or ``None`` OUTPUT: - a list of six integers >= 0 representing the solution types: + a list of six integers `\geq 0` representing the solution types: [All, Good, Zero, Bad, BadI, BadII] @@ -68,166 +68,155 @@ def count_congruence_solutions_as_vector(self, p, k, m, zvec, nzvec): return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec) - - - - ##/////////////////////////////////////////// ##/// Front-ends for our counting routines // ##/////////////////////////////////////////// def count_congruence_solutions(self, p, k, m, zvec, nzvec): - """ - Counts all solutions of Q(`x`) `= m (mod p^k)` satisfying the + r""" + Count all solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers in range(self.dim()), or None + - ``zvec``, ``nzvec`` -- lists of integers in ``range(self.dim())``, or ``None`` EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions(3, 1, 0, None, None) 15 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[0] - def count_congruence_solutions__good_type(self, p, k, m, zvec, nzvec): - """ - Counts the good-type solutions of Q(x) = m (mod p^k) satisfying the + r""" + Count the good-type solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers up to dim(Q) + - ``zvec``, ``nzvec`` -- lists of integers up to dim(`Q`) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__good_type(3, 1, 0, None, None) 12 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[1] def count_congruence_solutions__zero_type(self, p, k, m, zvec, nzvec): """ - Counts the zero-type solutions of Q(`x`) = `m (mod p^k)` satisfying the + Count the zero-type solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers up to dim(Q) + - ``zvec``, ``nzvec`` -- lists of integers up to dim(`Q`) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__zero_type(3, 1, 0, None, None) 1 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[2] def count_congruence_solutions__bad_type(self, p, k, m, zvec, nzvec): """ - Counts the bad-type solutions of Q(`x`) `= m (mod p^k)` satisfying the + Count the bad-type solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers up to dim(Q) + - ``zvec``, ``nzvec`` -- lists of integers up to dim(`Q`) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__bad_type(3, 1, 0, None, None) 2 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[3] def count_congruence_solutions__bad_type_I(self, p, k, m, zvec, nzvec): """ - Counts the bad-typeI solutions of Q(`x`) = `m (mod p^k)` satisfying + Count the bad-typeI solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers up to dim(Q) + - ``zvec``, ``nzvec`` -- lists of integers up to dim(`Q`) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__bad_type_I(3, 1, 0, None, None) 0 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[4] def count_congruence_solutions__bad_type_II(self, p, k, m, zvec, nzvec): """ - Counts the bad-typeII solutions of Q(`x`) `= m (mod p^k)` satisfying + Count the bad-typeII solutions of `Q(x) = m` (mod `p^k`) satisfying the additional congruence conditions described in - QuadraticForm.count_congruence_solutions_as_vector(). + :meth:`QuadraticForm.count_congruence_solutions_as_vector`. INPUT: - `p` -- prime number > 0 + - ``p`` -- prime number > 0 - `k` -- an integer > 0 + - ``k`` -- an integer > 0 - `m` -- an integer (depending only on mod `p^k`) + - ``m`` -- an integer (depending only on mod `p^k`) - zvec, nzvec -- a list of integers up to dim(Q) + - ``zvec``, ``nzvec`` -- lists of integers up to dim(`Q`) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3]) sage: Q.count_congruence_solutions__bad_type_II(3, 1, 0, None, None) 2 - """ return CountAllLocalTypesNaive(self, p, k, m, zvec, nzvec)[5] diff --git a/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py b/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py index b69bb6abf9d..7b109b3dc01 100644 --- a/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py +++ b/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py @@ -5,12 +5,15 @@ - Anna Haensch (2014-12-01): added test for rational isometry """ -from sage.arith.all import hilbert_symbol, prime_divisors, is_prime, valuation, GCD, legendre_symbol +from sage.arith.misc import (hilbert_symbol, + GCD, + is_prime, + legendre_symbol, + prime_divisors, + valuation) from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.quadratic_forms.quadratic_form import is_QuadraticForm - ############################################################################## # Routines to test if two quadratic forms over ZZ are globally equivalent. # @@ -18,9 +21,9 @@ ############################################################################## def is_globally_equivalent_to(self, other, return_matrix=False): - """ + r""" Determine if the current quadratic form is equivalent to the - given form over ZZ. + given form over `\ZZ`. If ``return_matrix`` is True, then we return the transformation matrix `M` so that ``self(M) == other``. @@ -44,14 +47,15 @@ def is_globally_equivalent_to(self, other, return_matrix=False): sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: M = Matrix(ZZ, 4, 4, [1,2,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) sage: Q1 = Q(M) - sage: Q.is_globally_equivalent_to(Q1) + sage: Q.is_globally_equivalent_to(Q1) # needs sage.libs.pari True - sage: MM = Q.is_globally_equivalent_to(Q1, return_matrix=True) - sage: Q(MM) == Q1 + sage: MM = Q.is_globally_equivalent_to(Q1, return_matrix=True) # needs sage.libs.pari + sage: Q(MM) == Q1 # needs sage.libs.pari True :: + sage: # needs sage.libs.pari sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q2 = QuadraticForm(ZZ, 3, [2, 1, 2, 2, 1, 3]) sage: Q3 = QuadraticForm(ZZ, 3, [8, 6, 5, 3, 4, 2]) @@ -71,7 +75,7 @@ def is_globally_equivalent_to(self, other, return_matrix=False): :: sage: Q = DiagonalQuadraticForm(ZZ, [1, -1]) - sage: Q.is_globally_equivalent_to(Q) + sage: Q.is_globally_equivalent_to(Q) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: not a definite form in QuadraticForm.is_globally_equivalent_to() @@ -85,13 +89,15 @@ def is_globally_equivalent_to(self, other, return_matrix=False): sage: Q = QuadraticForm(ZZ, 2, [2, 3, 5]) sage: P = QuadraticForm(ZZ, 2, [8, 6, 5]) - sage: Q.is_globally_equivalent_to(P) + sage: Q.is_globally_equivalent_to(P) # needs sage.libs.pari False - sage: P.is_globally_equivalent_to(Q) + sage: P.is_globally_equivalent_to(Q) # needs sage.libs.pari False """ + from sage.quadratic_forms.quadratic_form import QuadraticForm + # Check that other is a QuadraticForm - if not is_QuadraticForm(other): + if not isinstance(other, QuadraticForm): raise TypeError("you must compare two quadratic forms, but the argument is not a quadratic form") # only for definite forms @@ -109,31 +115,28 @@ def is_globally_equivalent_to(self, other, return_matrix=False): def is_locally_equivalent_to(self, other, check_primes_only=False, force_jordan_equivalence_test=False): - """ - Determine if the current quadratic form (defined over ZZ) is + r""" + Determine if the current quadratic form (defined over `\ZZ`) is locally equivalent to the given form over the real numbers and the - `p`-adic integers for every prime p. + `p`-adic integers for every prime `p`. This works by comparing the local Jordan decompositions at every prime, and the dimension and signature at the real place. INPUT: - a QuadraticForm + - ``other`` -- a :class:`QuadraticForm` - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q2 = QuadraticForm(ZZ, 3, [2, 1, 2, 2, 1, 3]) - sage: Q1.is_globally_equivalent_to(Q2) + sage: Q1.is_globally_equivalent_to(Q2) # needs sage.libs.pari False - sage: Q1.is_locally_equivalent_to(Q2) + sage: Q1.is_locally_equivalent_to(Q2) # needs sage.libs.pari True - """ # TO IMPLEMENT: if self.det() == 0: @@ -171,16 +174,14 @@ def is_locally_equivalent_to(self, other, check_primes_only=False, force_jordan_ def has_equivalent_Jordan_decomposition_at_prime(self, other, p): """ - Determines if the given quadratic form has a Jordan decomposition - equivalent to that of self. + Determine if the given quadratic form has a Jordan decomposition + equivalent to that of ``self``. INPUT: - a QuadraticForm + - ``other`` -- a :class:`QuadraticForm` - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -189,36 +190,36 @@ def has_equivalent_Jordan_decomposition_at_prime(self, other, p): sage: Q3 = QuadraticForm(ZZ, 3, [1, 0, 0, 1, 0, 11]) sage: [Q1.level(), Q2.level(), Q3.level()] [44, 44, 44] - sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,2) + + sage: # needs sage.libs.pari + sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2, 2) False - sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,11) + sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2, 11) False - sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,2) + sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3, 2) False - sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,11) + sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3, 11) True - sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,2) + sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3, 2) True - sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,11) + sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3, 11) False - """ # Sanity Checks - #if not isinstance(other, QuadraticForm): + # if not isinstance(other, QuadraticForm): if not isinstance(other, type(self)): raise TypeError("the first argument must be of type QuadraticForm") if not is_prime(p): raise TypeError("the second argument must be a prime number") # Get the relevant local normal forms quickly - self_jordan = self.jordan_blocks_by_scale_and_unimodular(p, safe_flag= False) + self_jordan = self.jordan_blocks_by_scale_and_unimodular(p, safe_flag=False) other_jordan = other.jordan_blocks_by_scale_and_unimodular(p, safe_flag=False) # Check for the same number of Jordan components if len(self_jordan) != len(other_jordan): return False - # Deal with odd primes: Check that the Jordan component scales, dimensions, and discriminants are the same if p != 2: for i in range(len(self_jordan)): @@ -230,14 +231,12 @@ def has_equivalent_Jordan_decomposition_at_prime(self, other, p): # All tests passed for an odd prime. return True - # For p = 2: Check that all Jordan Invariants are the same. elif p == 2: # Useful definition t = len(self_jordan) # Define t = Number of Jordan components - # Check that all Jordan Invariants are the same (scale, dim, and norm) for i in range(t): if (self_jordan[i][0] != other_jordan[i][0]) \ @@ -249,27 +248,27 @@ def has_equivalent_Jordan_decomposition_at_prime(self, other, p): # ------------------------------------------ # List of norms, scales, and dimensions for each i - scale_list = [ZZ(2)**self_jordan[i][0] for i in range(t)] - norm_list = [ZZ(2)**(self_jordan[i][0] + valuation(GCD(self_jordan[i][1].coefficients()), 2)) for i in range(t)] - dim_list = [(self_jordan[i][1].dim()) for i in range(t)] + scale_list = [ZZ(2)**self_jordan[i][0] for i in range(t)] + norm_list = [ZZ(2)**(self_jordan[i][0] + valuation(GCD(self_jordan[i][1].coefficients()), 2)) for i in range(t)] + dim_list = [(self_jordan[i][1].dim()) for i in range(t)] # List of Hessian determinants and Hasse invariants for each Jordan (sub)chain # (Note: This is not the same as O'Meara's Gram determinants, but ratios are the same!) -- NOT SO GOOD... # But it matters in condition (ii), so we multiply all by 2 (instead of dividing by 2 since only square-factors matter, and it's easier.) j = 0 - self_chain_det_list = [ self_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])] - other_chain_det_list = [ other_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])] - self_hasse_chain_list = [ self_jordan[j][1].scale_by_factor(ZZ(2)**self_jordan[j][0]).hasse_invariant__OMeara(2) ] - other_hasse_chain_list = [ other_jordan[j][1].scale_by_factor(ZZ(2)**other_jordan[j][0]).hasse_invariant__OMeara(2) ] + self_chain_det_list = [self_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])] + other_chain_det_list = [other_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])] + self_hasse_chain_list = [self_jordan[j][1].scale_by_factor(ZZ(2)**self_jordan[j][0]).hasse_invariant__OMeara(2)] + other_hasse_chain_list = [other_jordan[j][1].scale_by_factor(ZZ(2)**other_jordan[j][0]).hasse_invariant__OMeara(2)] for j in range(1, t): self_chain_det_list.append(self_chain_det_list[j-1] * self_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])) other_chain_det_list.append(other_chain_det_list[j-1] * other_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])) - self_hasse_chain_list.append(self_hasse_chain_list[j-1] \ - * hilbert_symbol(self_chain_det_list[j-1], self_jordan[j][1].Gram_det(), 2) \ + self_hasse_chain_list.append(self_hasse_chain_list[j-1] + * hilbert_symbol(self_chain_det_list[j-1], self_jordan[j][1].Gram_det(), 2) * self_jordan[j][1].hasse_invariant__OMeara(2)) - other_hasse_chain_list.append(other_hasse_chain_list[j-1] \ - * hilbert_symbol(other_chain_det_list[j-1], other_jordan[j][1].Gram_det(), 2) \ + other_hasse_chain_list.append(other_hasse_chain_list[j-1] + * hilbert_symbol(other_chain_det_list[j-1], other_jordan[j][1].Gram_det(), 2) * other_jordan[j][1].hasse_invariant__OMeara(2)) # SANITY CHECK -- check that the scale powers are strictly increasing @@ -288,7 +287,7 @@ def has_equivalent_Jordan_decomposition_at_prime(self, other, p): return False # Check O'Meara's condition (ii) when appropriate - if norm_list[i+1] % (4 * norm_list[i]) == 0: + if norm_list[i + 1] % (4 * norm_list[i]) == 0: if self_hasse_chain_list[i] * hilbert_symbol(norm_list[i] * other_chain_det_list[i], -self_chain_det_list[i], 2) \ != other_hasse_chain_list[i] * hilbert_symbol(norm_list[i], -other_chain_det_list[i], 2): # Nipp conditions return False @@ -322,20 +321,24 @@ def is_rationally_isometric(self, other, return_matrix=False): sage: V = DiagonalQuadraticForm(QQ, [1, 1, 2]) sage: W = DiagonalQuadraticForm(QQ, [2, 2, 2]) - sage: V.is_rationally_isometric(W) + sage: V.is_rationally_isometric(W) # needs sage.libs.pari True :: - sage: K.<a> = NumberField(x^2-3) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 3) sage: V = QuadraticForm(K, 4, [1, 0, 0, 0, 2*a, 0, 0, a, 0, 2]); V - Quadratic form in 4 variables over Number Field in a with defining polynomial x^2 - 3 with coefficients: + Quadratic form in 4 variables over Number Field in a + with defining polynomial x^2 - 3 with coefficients: [ 1 0 0 0 ] [ * 2*a 0 0 ] [ * * a 0 ] [ * * * 2 ] sage: W = QuadraticForm(K, 4, [1, 2*a, 4, 6, 3, 10, 2, 1, 2, 5]); W - Quadratic form in 4 variables over Number Field in a with defining polynomial x^2 - 3 with coefficients: + Quadratic form in 4 variables over Number Field in a + with defining polynomial x^2 - 3 with coefficients: [ 1 2*a 4 6 ] [ * 3 10 2 ] [ * * 1 2 ] @@ -345,16 +348,19 @@ def is_rationally_isometric(self, other, return_matrix=False): :: + sage: # needs sage.rings.number_field sage: K.<a> = NumberField(x^4 + 2*x + 6) sage: V = DiagonalQuadraticForm(K, [a, 2, 3, 2, 1]); V - Quadratic form in 5 variables over Number Field in a with defining polynomial x^4 + 2*x + 6 with coefficients: + Quadratic form in 5 variables over Number Field in a + with defining polynomial x^4 + 2*x + 6 with coefficients: [ a 0 0 0 0 ] [ * 2 0 0 0 ] [ * * 3 0 0 ] [ * * * 2 0 ] [ * * * * 1 ] sage: W = DiagonalQuadraticForm(K, [a, a, a, 2, 1]); W - Quadratic form in 5 variables over Number Field in a with defining polynomial x^4 + 2*x + 6 with coefficients: + Quadratic form in 5 variables over Number Field in a + with defining polynomial x^4 + 2*x + 6 with coefficients: [ a 0 0 0 0 ] [ * a 0 0 0 ] [ * * a 0 0 ] @@ -365,12 +371,14 @@ def is_rationally_isometric(self, other, return_matrix=False): :: + sage: # needs sage.rings.number_field sage: K.<a> = NumberField(x^2 - 3) sage: V = DiagonalQuadraticForm(K, [-1, a, -2*a]) sage: W = DiagonalQuadraticForm(K, [-1, -a, 2*a]) sage: V.is_rationally_isometric(W) True + sage: # needs sage.rings.number_field sage: V = DiagonalQuadraticForm(QQ, [1, 1, 2]) sage: W = DiagonalQuadraticForm(QQ, [2, 2, 2]) sage: T = V.is_rationally_isometric(W, True); T @@ -380,53 +388,54 @@ def is_rationally_isometric(self, other, return_matrix=False): sage: V.Gram_matrix() == T.transpose() * W.Gram_matrix() * T True - sage: T = W.is_rationally_isometric(V, True); T + sage: T = W.is_rationally_isometric(V, True); T # needs sage.rings.number_field [ 0 -1 1] [ 0 -1 -1] [ 1 0 0] - sage: W.Gram_matrix() == T.T * V.Gram_matrix() * T + sage: W.Gram_matrix() == T.T * V.Gram_matrix() * T # needs sage.rings.number_field True :: sage: L = QuadraticForm(QQ, 3, [2, 2, 0, 2, 2, 5]) sage: M = QuadraticForm(QQ, 3, [2, 2, 0, 3, 2, 3]) - sage: L.is_rationally_isometric(M, True) + sage: L.is_rationally_isometric(M, True) # needs sage.libs.pari False :: sage: A = DiagonalQuadraticForm(QQ, [1, 5]) sage: B = QuadraticForm(QQ, 2, [1, 12, 81]) - sage: T = A.is_rationally_isometric(B, True); T + sage: T = A.is_rationally_isometric(B, True); T # needs sage.libs.pari [ 1 -2] [ 0 1/3] - sage: A.Gram_matrix() == T.T * B.Gram_matrix() * T + sage: A.Gram_matrix() == T.T * B.Gram_matrix() * T # needs sage.libs.pari True :: sage: C = DiagonalQuadraticForm(QQ, [1, 5, 9]) sage: D = DiagonalQuadraticForm(QQ, [6, 30, 1]) - sage: T = C.is_rationally_isometric(D, True); T + sage: T = C.is_rationally_isometric(D, True); T # needs sage.libs.pari [ 0 -5/6 1/2] [ 0 1/6 1/2] [ -1 0 0] - sage: C.Gram_matrix() == T.T * D.Gram_matrix() * T + sage: C.Gram_matrix() == T.T * D.Gram_matrix() * T # needs sage.libs.pari True :: sage: E = DiagonalQuadraticForm(QQ, [1, 1]) sage: F = QuadraticForm(QQ, 2, [17, 94, 130]) - sage: T = F.is_rationally_isometric(E, True); T + sage: T = F.is_rationally_isometric(E, True); T # needs sage.libs.pari [ -4 -189/17] [ -1 -43/17] - sage: F.Gram_matrix() == T.T * E.Gram_matrix() * T + sage: F.Gram_matrix() == T.T * E.Gram_matrix() * T # needs sage.libs.pari True TESTS:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(3) sage: V = DiagonalQuadraticForm(K, [1, 2]) sage: W = DiagonalQuadraticForm(K, [1, 0]) @@ -437,6 +446,7 @@ def is_rationally_isometric(self, other, return_matrix=False): Forms must have the same base ring otherwise a `TypeError` is raised:: + sage: # needs sage.rings.number_field sage: K1.<a> = QuadraticField(5) sage: K2.<b> = QuadraticField(7) sage: V = DiagonalQuadraticForm(K1, [1, a]) @@ -455,7 +465,8 @@ def is_rationally_isometric(self, other, return_matrix=False): Forms whose determinants do not differ by a square in the base field are not isometric:: - sage: K.<a> = NumberField(x^2-3) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^2 - 3) sage: V = DiagonalQuadraticForm(K, [-1, a, -2*a]) sage: W = DiagonalQuadraticForm(K, [-1, a, 2*a]) sage: V.is_rationally_isometric(W) @@ -463,6 +474,7 @@ def is_rationally_isometric(self, other, return_matrix=False): :: + sage: # needs sage.rings.number_field sage: K.<a> = NumberField(x^5 - x + 2, 'a') sage: Q = QuadraticForm(K, 3, [a, 1, 0, -a**2, -a**3, -1]) sage: m = Q.matrix() @@ -487,13 +499,13 @@ def is_rationally_isometric(self, other, return_matrix=False): if self.dim() != other.dim(): return False - if not (self.Gram_det()*other.Gram_det()).is_square(): + if not (self.Gram_det() * other.Gram_det()).is_square(): return False - L1=self.Gram_det().support() - L2=other.Gram_det().support() + L1 = self.Gram_det().support() + L2 = other.Gram_det().support() - for p in set().union(L1,L2): + for p in set().union(L1, L2): if self.hasse_invariant(p) != other.hasse_invariant(p): return False @@ -511,13 +523,13 @@ def is_rationally_isometric(self, other, return_matrix=False): for emb in K.real_embeddings(): - Mpos=0 + Mpos = 0 for x in Mentries: - Mpos+= emb(x) >= 0 + Mpos += emb(x) >= 0 - Npos=0 + Npos = 0 for x in Nentries: - Npos+= emb(x) >= 0 + Npos += emb(x) >= 0 if Npos != Mpos: return False @@ -564,18 +576,18 @@ def _diagonal_isometry(V, W): sage: Q = DiagonalQuadraticForm(QQ, [1, 2, 4]) sage: F = DiagonalQuadraticForm(QQ, [2, 2, 2]) - sage: T = _diagonal_isometry(Q, F); T + sage: T = _diagonal_isometry(Q, F); T # needs sage.libs.pari [ 0 1 0] [-1/2 0 1] [ 1/2 0 1] - sage: Q.Gram_matrix() == T.T * F.Gram_matrix() * T + sage: Q.Gram_matrix() == T.T * F.Gram_matrix() * T # needs sage.libs.pari True - sage: T = _diagonal_isometry(F, Q); T + sage: T = _diagonal_isometry(F, Q); T # needs sage.libs.pari [ 0 -1 -1] [ 1 0 0] [ 0 -1/2 1/2] - sage: F.Gram_matrix() == T.T * Q.Gram_matrix() * T + sage: F.Gram_matrix() == T.T * Q.Gram_matrix() * T # needs sage.libs.pari True """ import copy @@ -601,7 +613,7 @@ def _diagonal_isometry(V, W): if Q.Gram_matrix()[0][0] != F.Gram_matrix()[0][0]: # Find a vector w in F such that F(w) equals the first term of Q. w = F.solve(Q.Gram_matrix()[0][0]) - w = vector(QQ, i*[0] + w.list()) + w = vector(QQ, i * [0] + w.list()) # We want to extend the basis of W to include the vector w. # Find a non-fixed vector in the current basis to replace by w. @@ -609,10 +621,10 @@ def _diagonal_isometry(V, W): # The new set of vectors must still be linearly independent (i.e. the matrix is non-singular). while True: temp_matrix = Matrix(change_of_basis_matrix) - temp_matrix.set_column(j, change_of_basis_matrix*w) + temp_matrix.set_column(j, change_of_basis_matrix * w) if not temp_matrix.is_singular(): break - j = j + 1 + j += 1 change_of_basis_matrix = temp_matrix @@ -685,12 +697,10 @@ def _gram_schmidt(m, fixed_vector_index, inner_product): from sage.matrix.constructor import column_matrix n = m.dimensions()[0] - vectors = [0] * n + vectors = [m.column(i) for i in range(n)] - for i in range(n): - vectors[i] = m.column(i) for i in range(fixed_vector_index, n): - for j in range(i+1, n): + for j in range(i + 1, n): vectors[j] = vectors[j] - (inner_product(vectors[j], vectors[i]) / inner_product(vectors[i], vectors[i])) * vectors[i] return column_matrix(vectors) diff --git a/src/sage/quadratic_forms/quadratic_form__evaluate.pyx b/src/sage/quadratic_forms/quadratic_form__evaluate.pyx index 1505e7bd115..95e82e669dc 100644 --- a/src/sage/quadratic_forms/quadratic_form__evaluate.pyx +++ b/src/sage/quadratic_forms/quadratic_form__evaluate.pyx @@ -2,29 +2,30 @@ def QFEvaluateVector(Q, v): - """ - Evaluate this quadratic form Q on a vector or matrix of elements - coercible to the base ring of the quadratic form. If a vector - is given then the output will be the ring element Q(v), but if a - matrix is given then the output will be the quadratic form Q' - which in matrix notation is given by: + r""" + Evaluate this quadratic form `Q` on a vector or matrix of elements + coercible to the base ring of the quadratic form. + + If a vector is given, then the output will be the ring element + `Q(v)`, but if a matrix is given, then the output will be the + quadratic form `Q'` which in matrix notation is given by: .. MATH:: - Q' = v^t * Q * v. + Q' = v^t\cdot Q\cdot v. - Note: This is a Python wrapper for the fast evaluation routine - QFEvaluateVector_cdef(). This routine is for internal use and is - called more conveniently as Q(M). + .. NOTE:: - INPUT: + This is a Python wrapper for the fast evaluation routine + :func:`QFEvaluateVector_cdef`. This routine is for internal use and is + called more conveniently as ``Q(M)``. - - Q -- QuadraticForm over a base ring R - - v -- a tuple or list (or column matrix) of Q.dim() elements of R + INPUT: - OUTPUT: + - ``Q`` -- :class:`QuadraticForm` over a base ring `R` + - ``v`` -- a tuple or list (or column matrix) of ``Q.dim()`` elements of `R` - an element of R + OUTPUT: an element of `R` EXAMPLES:: @@ -39,54 +40,53 @@ def QFEvaluateVector(Q, v): 0 sage: QFEvaluateVector(Q, (1,0,1,0)) 9 - """ return QFEvaluateVector_cdef(Q, v) - cdef QFEvaluateVector_cdef(Q, v): - """ - Routine to quickly evaluate a quadratic form Q on a vector v. See - the Python wrapper function QFEvaluate() above for details. + r""" + Routine to quickly evaluate a quadratic form `Q` on a vector `v`. See + the Python wrapper function :meth:`QFEvaluate` above for details. """ # If we are passed a matrix A, return the quadratic form Q(A(x)) # (In matrix notation: A^t * Q * A) n = Q.dim() - tmp_val = Q.base_ring()(0) - for i from 0 <= i < n: - for j from i <= j < n: - tmp_val += Q[i,j] * v[i] * v[j] + tmp_val = Q.base_ring().zero() + for i in range(n): + for j in range(i, n): + tmp_val += Q[i, j] * v[i] * v[j] # Return the value (over R) return Q.base_ring().coerce(tmp_val) - def QFEvaluateMatrix(Q, M, Q2): - """ - Evaluate this quadratic form Q on a matrix M of elements coercible + r""" + Evaluate this quadratic form `Q` on a matrix `M` of elements coercible to the base ring of the quadratic form, which in matrix notation is given by: - Q2 = M^t * Q * M. + .. MATH:: - Note: This is a Python wrapper for the fast evaluation routine - QFEvaluateMatrix_cdef(). This routine is for internal use and is - called more conveniently as Q(M). The inclusion of Q2 as an - argument is to avoid having to create a QuadraticForm here, which - for now creates circular imports. + Q_2 = M^t\cdot Q\cdot M. - INPUT: + .. NOTE:: - - Q -- QuadraticForm over a base ring R - - M -- a Q.dim() x Q2.dim() matrix of elements of R + This is a Python wrapper for the fast evaluation routine + :func:`QFEvaluateMatrix_cdef`. This routine is for internal use and is + called more conveniently as ``Q(M)``. The inclusion of ``Q2`` as an + argument is to avoid having to create a :func:`QuadraticForm` here, which + for now creates circular imports. - OUTPUT: + INPUT: - - Q2 -- a QuadraticForm over R + - ``Q`` -- :class:`QuadraticForm` over a base ring `R` + - ``M`` -- a ``Q.dim()`` `\times` ``Q2.dim()`` matrix of elements of `R` + + OUTPUT: a :class:`QuadraticForm` over `R` EXAMPLES:: @@ -107,15 +107,14 @@ def QFEvaluateMatrix(Q, M, Q2): Quadratic form in 2 variables over Integer Ring with coefficients: [ 0 2 ] [ * 7 ] - """ return QFEvaluateMatrix_cdef(Q, M, Q2) cdef QFEvaluateMatrix_cdef(Q, M, Q2): - """ - Routine to quickly evaluate a quadratic form Q on a matrix M. See - the Python wrapper function QFEvaluateMatrix() above for details. + r""" + Routine to quickly evaluate a quadratic form `Q` on a matrix `M`. See + the Python wrapper function :func:`QFEvaluateMatrix` above for details. """ # Create the new quadratic form @@ -125,14 +124,17 @@ cdef QFEvaluateMatrix_cdef(Q, M, Q2): # TODO: Check the dimensions of M are compatible with those of Q and Q2 # Evaluate Q(M) into Q2 - for k from 0 <= k < m: - for l from k <= l < m: - tmp_sum = Q2.base_ring()(0) - for i from 0 <= i < n: - for j from i <= j < n: - if (k == l): - tmp_sum += Q[i,j] * (M[i,k] * M[j,l]) - else: - tmp_sum += Q[i,j] * (M[i,k] * M[j,l] + M[i,l] * M[j,k]) - Q2[k,l] = tmp_sum + for k in range(m): + for l in range(k, m): + tmp_sum = Q2.base_ring().zero() + if k == l: + for i in range(n): + for j in range(i, n): + tmp_sum += Q[i, j] * (M[i, k] * M[j, l]) + else: + for i in range(n): + for j in range(i, n): + tmp_sum += Q[i, j] * (M[i, k] * M[j, l] + + M[i, l] * M[j, k]) + Q2[k, l] = tmp_sum return Q2 diff --git a/src/sage/quadratic_forms/quadratic_form__genus.py b/src/sage/quadratic_forms/quadratic_form__genus.py index 18a02061029..8727645b453 100644 --- a/src/sage/quadratic_forms/quadratic_form__genus.py +++ b/src/sage/quadratic_forms/quadratic_form__genus.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari """ Local and Global Genus Symbols """ @@ -7,9 +8,9 @@ # # ############################################################# +from sage.arith.misc import is_prime, prime_divisors from sage.quadratic_forms.genera.genus import Genus, LocalGenusSymbol from sage.rings.integer_ring import ZZ -from sage.arith.all import is_prime, prime_divisors def global_genus_symbol(self): @@ -55,48 +56,47 @@ def local_genus_symbol(self, p): Return the Conway-Sloane genus symbol of 2 times a quadratic form defined over `\ZZ` at a prime number `p`. - This is defined (in the - Genus_Symbol_p_adic_ring() class in the quadratic_forms/genera - subfolder) to be a list of tuples (one for each Jordan component - p^m*A at p, where A is a unimodular symmetric matrix with - coefficients the p-adic integers) of the following form: + This is defined (in the class + :class:`~sage.quadratic_forms.genera.genus.Genus_Symbol_p_adic_ring`) + to be a list of tuples (one for each Jordan component + `p^m\cdot A` at `p`, where `A` is a unimodular symmetric matrix with + coefficients the `p`-adic integers) of the following form: - 1. If p>2 then return triples of the form [`m`, `n`, `d`] where + - If `p>2`, then return triples of the form [`m`, `n`, `d`] where - `m` = valuation of the component + - `m` = valuation of the component - `n` = rank of A + - `n` = rank of `A` - `d` = det(A) in {1,u} for normalized quadratic non-residue u. + - `d` = det(`A`) in {1, `u`} for normalized quadratic non-residue `u`. - 2. If p=2 then return quintuples of the form [`m`,`n`,`s`, `d`, `o`] where + - If `p=2`, then return quintuples of the form [`m`, `n`, `s`, `d`, `o`] where - `m` = valuation of the component + - `m` = valuation of the component - `n` = rank of A + - `n` = rank of `A` - `d` = det(A) in {1,3,5,7} + - `d` = det(`A`) in {1, 3, 5, 7} - `s` = 0 (or 1) if A is even (or odd) + - `s` = 0 (or 1) if `A` is even (or odd) - `o` = oddity of A (= 0 if s = 0) in Z/8Z - = the trace of the diagonalization of A + - `o` = oddity of `A` (= 0 if `s` = 0) in `\ZZ/8\ZZ` = the trace of the diagonalization of `A` .. NOTE:: - The Conway-Sloane convention for describing the prime 'p = -1' + The Conway-Sloane convention for describing the prime `p = -1` is not supported here, and neither is the convention for including the 'prime' Infinity. See note on p370 of Conway-Sloane (3rd ed) [CS1999]_ for a discussion of this convention. INPUT: - - `p` -- a prime number > 0 + - ``p`` -- a prime number > 0 OUTPUT: a Conway-Sloane genus symbol at `p`, which is an - instance of the Genus_Symbol_p_adic_ring class. + instance of the class :class:`~sage.quadratic_forms.genera.genus.Genus_Symbol_p_adic_ring`. EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py index 71872a37b8e..a39637df8f0 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py +++ b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py @@ -10,16 +10,16 @@ from sage.sets.set import Set from sage.rings.rational_field import QQ -from sage.arith.all import valuation +from sage.arith.misc import valuation from sage.misc.verbose import verbose from sage.quadratic_forms.count_local_2 import count_modp__by_gauss_sum def count_modp_solutions__by_Gauss_sum(self, p, m): - """ - Return the number of solutions of `Q(x) = m (mod p)` of a - non-degenerate quadratic form over the finite field `Z/pZ`, + r""" + Return the number of solutions of `Q(x) = m` (mod `p`) of a + non-degenerate quadratic form over the finite field `\ZZ/p\ZZ`, where `p` is a prime number > 2. .. NOTE:: @@ -32,11 +32,11 @@ def count_modp_solutions__by_Gauss_sum(self, p, m): INPUT: - - `p` -- a prime number > 2 + - ``p`` -- a prime number > 2 - - `m` -- an integer + - ``m`` -- an integer - OUTPUT: an integer >= 0 + OUTPUT: an integer `\geq 0` EXAMPLES:: @@ -55,29 +55,29 @@ def count_modp_solutions__by_Gauss_sum(self, p, m): def local_good_density_congruence_odd(self, p, m, Zvec, NZvec): """ - Find the Good-type local density of Q representing `m` at `p`. - (Assuming that `p` > 2 and Q is given in local diagonal form.) + Find the Good-type local density of `Q` representing `m` at `p`. + (Assuming that `p > 2` and `Q` is given in local diagonal form.) - The additional congruence condition arguments Zvec and NZvec can - be either a list of indices or None. Zvec = [] is equivalent to - Zvec = None which both impose no additional conditions, but NZvec - = [] returns no solutions always while NZvec = None imposes no + The additional congruence condition arguments ``Zvec`` and ``NZvec`` can + be either a list of indices or None. ``Zvec=[]`` is equivalent to + ``Zvec=None``, which both impose no additional conditions, but + ``NZvec=[]`` returns no solutions always while ``NZvec=None`` imposes no additional condition. .. TODO:: - Add type checking for Zvec, NZvec, and that Q is in local + Add type checking for ``Zvec``, ``NZvec``, and that `Q` is in local normal form. INPUT: - - Q -- quadratic form assumed to be diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -92,7 +92,6 @@ def local_good_density_congruence_odd(self, p, m, Zvec, NZvec): sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.local_good_density_congruence_odd(3, 1, None, None) 8/9 - """ n = self.dim() @@ -141,38 +140,40 @@ def local_good_density_congruence_odd(self, p, m, Zvec, NZvec): def local_good_density_congruence_even(self, m, Zvec, NZvec): - """ - Find the Good-type local density of Q representing `m` at `p=2`. - (Assuming Q is given in local diagonal form.) - - The additional congruence condition arguments Zvec and NZvec can - be either a list of indices or None. Zvec = [] is equivalent to - Zvec = None which both impose no additional conditions, but NZvec - = [] returns no solutions always while NZvec = None imposes no + r""" + Find the Good-type local density of `Q` representing `m` at `p=2`. + (Assuming `Q` is given in local diagonal form.) + + The additional congruence condition arguments ``Zvec`` and ``NZvec`` can + be either a list of indices or None. ``Zvec=[]`` is equivalent to + ``Zvec=None`` which both impose no additional conditions, but + ``NZvec=[]`` returns no solutions always while ``NZvec=None`` imposes no additional condition. - WARNING: Here the indices passed in Zvec and NZvec represent - indices of the solution vector `x` of Q(`x`) = `m (mod p^k)`, and *not* - the Jordan components of Q. They therefore are required (and - assumed) to include either all or none of the indices of a given - Jordan component of Q. This is only important when `p=2` since - otherwise all Jordan blocks are 1x1, and so there the indices and - Jordan blocks coincide. + .. WARNING:: + + Here the indices passed in ``Zvec`` and ``NZvec`` represent + indices of the solution vector `x` of `Q(x) = m` (mod `p^k`), and *not* + the Jordan components of `Q`. They therefore are required (and + assumed) to include either all or none of the indices of a given + Jordan component of `Q`. This is only important when `p=2` since + otherwise all Jordan blocks are `1 \times 1`, and so there the indices and + Jordan blocks coincide. .. TODO:: - Add type checking for Zvec, NZvec, and that Q is in local + Add type checking for ``Zvec`` and ``NZvec``, and that `Q` is in local normal form. INPUT: - - Q -- quadratic form assumed to be block diagonal and 2-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and 2-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -207,9 +208,9 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): [ * 10 5 6 ] [ * * 15 8 ] [ * * * 20 ] - sage: Q.theta_series(20) + sage: Q.theta_series(20) # needs sage.libs.pari 1 + 2*q^5 + 2*q^10 + 2*q^14 + 2*q^15 + 2*q^16 + 2*q^18 + O(q^20) - sage: Q.local_normal_form(2) + sage: Q.local_normal_form(2) # needs sage.libs.pari sage.rings.padics Quadratic form in 4 variables over Integer Ring with coefficients: [ 0 1 0 0 ] [ * 0 0 0 ] @@ -221,7 +222,6 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): 1 sage: Q.local_good_density_congruence_even(5, None, None) 3/4 - """ n = self.dim() @@ -323,23 +323,23 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): def local_good_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the Good-type local density of Q representing `m` at `p`. - (Front end routine for parity specific routines for p.) + Find the Good-type local density of `Q` representing `m` at `p`. + (Front end routine for parity specific routines for `p`.) .. TODO:: - Add Documentation about the additional congruence - conditions Zvec and NZvec. + Add documentation about the additional congruence + conditions ``Zvec`` and ``NZvec``. INPUT: - - Q -- quadratic form assumed to be block diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -399,18 +399,18 @@ def local_good_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_zero_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the Zero-type local density of Q representing `m` at `p`, - allowing certain congruence conditions mod p. + Find the Zero-type local density of `Q` representing `m` at `p`, + allowing certain congruence conditions mod `p`. INPUT: - - Q -- quadratic form assumed to be block diagonal and `p`-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -437,7 +437,6 @@ def local_zero_density_congruence(self, p, m, Zvec=None, NZvec=None): 0 sage: Q.local_zero_density_congruence(3, 9, None, None) 8/81 - """ # DIAGNOSTIC verbose(" In local_zero_density_congruence with ") @@ -473,18 +472,18 @@ def local_zero_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_badI_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the Bad-type I local density of Q representing `m` at `p`. - (Assuming that p > 2 and Q is given in local diagonal form.) + Find the Bad-type I local density of `Q` representing `m` at `p`. + (Assuming that `p > 2` and `Q` is given in local diagonal form.) INPUT: - - Q -- quadratic form assumed to be block diagonal and `p`-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -533,8 +532,6 @@ def local_badI_density_congruence(self, p, m, Zvec=None, NZvec=None): 0 sage: Q.local_badI_density_congruence(3, 18, None, None) 0 - - """ # DIAGNOSTIC verbose(" In local_badI_density_congruence with ") @@ -638,18 +635,18 @@ def local_badI_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_badII_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the Bad-type II local density of Q representing `m` at `p`. - (Assuming that `p` > 2 and Q is given in local diagonal form.) + Find the Bad-type II local density of `Q` representing `m` at `p`. + (Assuming that `p > 2` and `Q` is given in local diagonal form.) INPUT: - - Q -- quadratic form assumed to be block diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -684,7 +681,6 @@ def local_badII_density_congruence(self, p, m, Zvec=None, NZvec=None): 4/27 sage: Q.local_badII_density_congruence(3, 18, None, None) 4/9 - """ # DIAGNOSTIC verbose(" In local_badII_density_congruence with ") @@ -785,18 +781,18 @@ def local_badII_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_bad_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the Bad-type local density of Q representing + Find the Bad-type local density of `Q` representing `m` at `p`, allowing certain congruence conditions mod `p`. INPUT: - - Q -- quadratic form assumed to be block diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -833,7 +829,6 @@ def local_bad_density_congruence(self, p, m, Zvec=None, NZvec=None): 4/9 sage: Q.local_bad_density_congruence(3, 27, None, None) 8/27 - """ return self.local_badI_density_congruence(p, m, Zvec, NZvec) + self.local_badII_density_congruence(p, m, Zvec, NZvec) @@ -844,18 +839,18 @@ def local_bad_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the local density of Q representing `m` at `p`, + Find the local density of `Q` representing `m` at `p`, allowing certain congruence conditions mod `p`. INPUT: - - Q -- quadratic form assumed to be block diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number @@ -912,7 +907,7 @@ def local_density_congruence(self, p, m, Zvec=None, NZvec=None): def local_primitive_density_congruence(self, p, m, Zvec=None, NZvec=None): """ - Find the primitive local density of Q representing + Find the primitive local density of `Q` representing `m` at `p`, allowing certain congruence conditions mod `p`. .. NOTE:: @@ -921,13 +916,13 @@ def local_primitive_density_congruence(self, p, m, Zvec=None, NZvec=None): INPUT: - - Q -- quadratic form assumed to be block diagonal and p-integral + - ``self`` -- quadratic form `Q`, assumed to be block diagonal and `p`-integral - - `p` -- a prime number + - ``p`` -- a prime number - - `m` -- an integer + - ``m`` -- an integer - - Zvec, NZvec -- non-repeating lists of integers in range(self.dim()) or None + - ``Zvec``, ``NZvec`` -- non-repeating lists of integers in ``range(self.dim())`` or ``None`` OUTPUT: a rational number diff --git a/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py b/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py index aa4fb04ad63..ec39e489494 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py +++ b/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py @@ -4,7 +4,7 @@ # // This is needed in the filter for primitivity... # #include "../max-min.h" -from sage.arith.all import valuation +from sage.arith.misc import valuation from sage.rings.rational_field import QQ @@ -20,12 +20,10 @@ def local_density(self, p, m): INPUT: - - `p` -- a prime number > 0 - - `m` -- an integer + - ``p`` -- a prime number > 0 + - ``m`` -- an integer - OUTPUT: - - a rational number + OUTPUT: a rational number EXAMPLES:: @@ -57,7 +55,6 @@ def local_density(self, p, m): if ((m != 0) and (valuation(m,p) < p_valuation)): # Note: The (m != 0) condition protects taking the valuation of zero. return QQ(0) - # If the form is imprimitive, rescale it and call the local density routine p_adjustment = QQ(1) / p**p_valuation m_prim = QQ(m) / p**p_valuation @@ -69,7 +66,7 @@ def local_density(self, p, m): def local_primitive_density(self, p, m): """ - Gives the local primitive density -- should be called by the user. =) + Return the local primitive density -- should be called by the user. =) NOTE: This screens for imprimitive forms, and puts the quadratic form in local normal form, which is a *requirement* of @@ -77,12 +74,10 @@ def local_primitive_density(self, p, m): INPUT: - `p` -- a prime number > 0 - `m` -- an integer - - OUTPUT: + - ``p`` -- a prime number > 0 + - ``m`` -- an integer - a rational number + OUTPUT: a rational number EXAMPLES:: @@ -97,7 +92,7 @@ def local_primitive_density(self, p, m): [ * 10 5 6 ] [ * * 15 8 ] [ * * * 20 ] - sage: Q.theta_series(20) + sage: Q.theta_series(20) # needs sage.libs.pari 1 + 2*q^5 + 2*q^10 + 2*q^14 + 2*q^15 + 2*q^16 + 2*q^18 + O(q^20) sage: Q.local_normal_form(2) Quadratic form in 4 variables over Integer Ring with coefficients: @@ -115,7 +110,6 @@ def local_primitive_density(self, p, m): 3/4 sage: Q.local_density(2, 5) 3/4 - """ n = self.dim() if n == 0: @@ -133,7 +127,6 @@ def local_primitive_density(self, p, m): if ((m != 0) and (valuation(m,p) < p_valuation)): # Note: The (m != 0) condition protects taking the valuation of zero. return QQ(0) - # If the form is imprimitive, rescale it and call the local density routine p_adjustment = QQ(1) / p**p_valuation m_prim = QQ(m) / p**p_valuation diff --git a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py index 3556c101705..35f64198113 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py +++ b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py @@ -21,15 +21,13 @@ # places, is_semi_definite, and support for number fields. ########################################################################### - from copy import deepcopy -from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ -from sage.rings.real_mpfr import RR -from sage.arith.all import prime_divisors, hilbert_symbol -from sage.functions.all import sgn + +from sage.arith.misc import hilbert_symbol, prime_divisors from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ def rational_diagonal_form(self, return_matrix=False): @@ -42,15 +40,15 @@ def rational_diagonal_form(self, return_matrix=False): - ``return_matrix`` -- (boolean, default: False) also return the transformation matrix - OUTPUT: either ``D`` (if ``return_matrix`` is false) or ``(D,T)`` - (if ``return_matrix`` is true) where + OUTPUT: either the diagonal quadratic form `D` (if ``return_matrix`` is false) + or the pair `(D, T)` (if ``return_matrix`` is true) where - - ``D`` -- the diagonalized form of this quadratic form. + - `D` -- the diagonalized form of this quadratic form - - ``T`` -- transformation matrix. This is such that + - `T` -- transformation matrix. This is such that ``T.transpose() * self.matrix() * T`` gives ``D.matrix()``. - Both ``D`` and ``T`` are defined over the fraction field of the + Both `D` and `T` are defined over the fraction field of the base ring of the given form. EXAMPLES:: @@ -142,7 +140,8 @@ def rational_diagonal_form(self, return_matrix=False): ... TypeError sage: Q.rational_diagonal_form() - Quadratic form in 4 variables over Real Interval Field with 53 bits of precision with coefficients: + Quadratic form in 4 variables over Real Interval Field with 53 bits of precision + with coefficients: [ 5 0.?e-14 0.?e-13 0.?e-13 ] [ * -0.05000000000000? 0.?e-12 0.?e-12 ] [ * * 13.00000000000? 0.?e-10 ] @@ -188,14 +187,14 @@ def _rational_diagonal_form_and_transformation(self): the corresponding transformation matrix. This is over the fraction field of the base ring of the given quadratic form. - OUTPUT: a tuple ``(D,T)`` where + OUTPUT: a tuple `(D,T)` where - - ``D`` -- the diagonalized form of this quadratic form. + - `D` -- the diagonalized form of this quadratic form - - ``T`` -- transformation matrix. This is such that + - `T` -- transformation matrix. This is such that ``T.transpose() * self.matrix() * T`` gives ``D.matrix()``. - Both ``D`` and ``T`` are defined over the fraction field of the + Both `D` and `T` are defined over the fraction field of the base ring of the given form. EXAMPLES:: @@ -223,7 +222,7 @@ def _rational_diagonal_form_and_transformation(self): """ n = self.dim() K = self.base_ring().fraction_field() - Q = self.base_change_to(K) + Q = self.change_ring(K) MS = MatrixSpace(K, n, n) try: @@ -286,22 +285,16 @@ def _rational_diagonal_form_and_transformation(self): def signature_vector(self): - """ - Returns the triple `(p, n, z)` of integers where + r""" + Return the triple `(p, n, z)` of integers where - `p` = number of positive eigenvalues - `n` = number of negative eigenvalues - `z` = number of zero eigenvalues - for the symmetric matrix associated to Q. - - INPUT: - - (none) - - OUTPUT: + for the symmetric matrix associated to `Q`. - a triple of integers >= 0 + OUTPUT: a triple of integers `\geq 0` EXAMPLES:: @@ -342,22 +335,15 @@ def signature_vector(self): return (p, n, z) - def signature(self): """ - Returns the signature of the quadratic form, defined as: + Return the signature of the quadratic form, defined as: - number of positive eigenvalues - number of negative eigenvalues + number of positive eigenvalues `-` number of negative eigenvalues of the matrix of the quadratic form. - INPUT: - - None - - OUTPUT: - - an integer + OUTPUT: an integer EXAMPLES:: @@ -381,16 +367,15 @@ def signature(self): [ * * * 9 ] sage: Q.signature() 2 - """ - (p, n, z) = self.signature_vector() + p, n, _ = self.signature_vector() return p - n def hasse_invariant(self, p): r""" - Computes the Hasse invariant at a prime `p` or at infinity, as given on p55 of - Cassels's book. If Q is diagonal with coefficients `a_i`, then the + Compute the Hasse invariant at a prime `p` or at infinity, as given on p55 of + Cassels's book. If `Q` is diagonal with coefficients `a_i`, then the (Cassels) Hasse invariant is given by .. MATH:: @@ -398,27 +383,25 @@ def hasse_invariant(self, p): c_p = \prod_{i < j} (a_i, a_j)_p where `(a,b)_p` is the Hilbert symbol at `p`. The underlying - quadratic form must be non-degenerate over `Q_p` for this to make + quadratic form must be non-degenerate over `\QQ_p` for this to make sense. .. WARNING:: This is different from the O'Meara Hasse invariant, which - allows `i <= j` in the product. That is given by the method - hasse_invariant__OMeara(p). + allows `i \leq j` in the product. That is given by the method + :meth:`hasse_invariant__OMeara`. .. NOTE:: - We should really rename this hasse_invariant__Cassels(), and - set hasse_invariant() as a front-end to it. + We should really rename this ``hasse_invariant__Cassels``, and + set :meth:`hasse_invariant` as a front-end to it. INPUT: - - `p` -- a prime number > 0 or `-1` for the infinite place + - ``p`` -- a prime number > 0 or `-1` for the infinite place - OUTPUT: - - 1 or -1 + OUTPUT: `1` or `-1` EXAMPLES:: @@ -427,32 +410,33 @@ def hasse_invariant(self, p): Quadratic form in 2 variables over Rational Field with coefficients: [ 1 0 ] [ * 2 ] - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # needs sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # needs sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] :: sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # needs sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # needs sage.libs.pari [-1, 1, 1, 1, 1, 1, 1, 1] :: sage: Q = DiagonalQuadraticForm(ZZ, [1,-1,5]) - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # needs sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # needs sage.libs.pari [-1, 1, 1, 1, 1, 1, 1, 1] :: - sage: K.<a>=NumberField(x^2-23) - sage: Q=DiagonalQuadraticForm(K,[-a,a+2]) - sage: [Q.hasse_invariant(p) for p in K.primes_above(19)] + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 23) # needs sage.rings.number_field + sage: Q = DiagonalQuadraticForm(K, [-a, a + 2]) # needs sage.rings.number_field + sage: [Q.hasse_invariant(p) for p in K.primes_above(19)] # needs sage.rings.number_field [-1, 1] """ # TO DO: Need to deal with the case n=1 separately somewhere! @@ -481,12 +465,12 @@ def hasse_invariant__OMeara(self, p): Compute the O'Meara Hasse invariant at a prime `p`. This is defined on - p167 of O'Meara's book. If Q is diagonal with coefficients `a_i`, + p167 of O'Meara's book. If `Q` is diagonal with coefficients `a_i`, then the (Cassels) Hasse invariant is given by .. MATH:: - c_p = \prod_{i <= j} (a_i, a_j)_p + c_p = \prod_{i \leq j} (a_i, a_j)_p where `(a,b)_p` is the Hilbert symbol at `p`. @@ -498,11 +482,9 @@ def hasse_invariant__OMeara(self, p): INPUT: - - `p` -- a prime number > 0 or `-1` for the infinite place - - OUTPUT: + - ``p`` -- a prime number > 0 or `-1` for the infinite place - 1 or -1 + OUTPUT: `1` or `-1` EXAMPLES:: @@ -511,32 +493,33 @@ def hasse_invariant__OMeara(self, p): Quadratic form in 2 variables over Rational Field with coefficients: [ 1 0 ] [ * 2 ] - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # needs sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # needs sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] :: sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # needs sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # needs sage.libs.pari [-1, 1, 1, 1, 1, 1, 1, 1] :: sage: Q = DiagonalQuadraticForm(ZZ,[1,-1,-1]) - sage: [Q.hasse_invariant(p) for p in prime_range(20)] + sage: [Q.hasse_invariant(p) for p in prime_range(20)] # needs sage.libs.pari [-1, 1, 1, 1, 1, 1, 1, 1] - sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] + sage: [Q.hasse_invariant__OMeara(p) for p in prime_range(20)] # needs sage.libs.pari [-1, 1, 1, 1, 1, 1, 1, 1] :: - sage: K.<a>=NumberField(x^2-23) - sage: Q = DiagonalQuadraticForm(K,[-a,a+2]) - sage: [Q.hasse_invariant__OMeara(p) for p in K.primes_above(19)] + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 23) # needs sage.rings.number_field + sage: Q = DiagonalQuadraticForm(K, [-a, a + 2]) # needs sage.rings.number_field + sage: [Q.hasse_invariant__OMeara(p) for p in K.primes_above(19)] # needs sage.rings.number_field [1, 1] """ # TO DO: Need to deal with the case n=1 separately somewhere! @@ -566,21 +549,20 @@ def is_hyperbolic(self, p): REFERENCES: - This criteria follows from Cassels's "Rational Quadratic Forms": + This criterion follows from Cassels's "Rational Quadratic Forms": - local invariants for hyperbolic plane (Lemma 2.4, p58) - direct sum formulas (Lemma 2.3, p58) INPUT: - - `p` -- a prime number > 0 or `-1` for the infinite place - - OUTPUT: + - ``p`` -- a prime number > 0 or `-1` for the infinite place - boolean + OUTPUT: boolean EXAMPLES:: + sage: # needs sage.libs.pari sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) sage: Q.is_hyperbolic(-1) False @@ -621,44 +603,46 @@ def is_hyperbolic(self, p): def is_anisotropic(self, p): r""" - Check if the quadratic form is anisotropic over the p-adic numbers `\QQ_p` or `\RR`. + Check if the quadratic form is anisotropic over the `p`-adic numbers `\QQ_p` or `\RR`. INPUT: - - `p` -- a prime number > 0 or `-1` for the infinite place + - ``p`` -- a prime number > 0 or `-1` for the infinite place - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) - sage: Q.is_anisotropic(2) + sage: Q.is_anisotropic(2) # needs sage.libs.pari True - sage: Q.is_anisotropic(3) + sage: Q.is_anisotropic(3) # needs sage.libs.pari True - sage: Q.is_anisotropic(5) + sage: Q.is_anisotropic(5) # needs sage.libs.pari False :: sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) - sage: Q.is_anisotropic(2) + sage: Q.is_anisotropic(2) # needs sage.libs.pari False - sage: Q.is_anisotropic(3) + sage: Q.is_anisotropic(3) # needs sage.libs.pari False - sage: Q.is_anisotropic(5) + sage: Q.is_anisotropic(5) # needs sage.libs.pari False :: - sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p)]).is_anisotropic(p) for p in prime_range(3, 30)] + sage: [DiagonalQuadraticForm(ZZ, # needs sage.libs.pari + ....: [1, -least_quadratic_nonresidue(p)]).is_anisotropic(p) + ....: for p in prime_range(3, 30)] [True, True, True, True, True, True, True, True, True] :: - sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p), p, -p*least_quadratic_nonresidue(p)]).is_anisotropic(p) for p in prime_range(3, 30)] + sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p), # needs sage.libs.pari + ....: p, -p*least_quadratic_nonresidue(p)]).is_anisotropic(p) + ....: for p in prime_range(3, 30)] [True, True, True, True, True, True, True, True, True] """ # TO DO: Should check that p is prime @@ -688,45 +672,47 @@ def is_anisotropic(self, p): def is_isotropic(self, p): - """ - Checks if Q is isotropic over the p-adic numbers `Q_p` or `RR`. + r""" + Checks if `Q` is isotropic over the `p`-adic numbers `\QQ_p` or `\RR`. INPUT: - - `p` -- a prime number > 0 or `-1` for the infinite place + - ``p`` -- a prime number > 0 or `-1` for the infinite place - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) - sage: Q.is_isotropic(2) + sage: Q.is_isotropic(2) # needs sage.libs.pari False - sage: Q.is_isotropic(3) + sage: Q.is_isotropic(3) # needs sage.libs.pari False - sage: Q.is_isotropic(5) + sage: Q.is_isotropic(5) # needs sage.libs.pari True :: sage: Q = DiagonalQuadraticForm(ZZ, [1,-1]) - sage: Q.is_isotropic(2) + sage: Q.is_isotropic(2) # needs sage.libs.pari True - sage: Q.is_isotropic(3) + sage: Q.is_isotropic(3) # needs sage.libs.pari True - sage: Q.is_isotropic(5) + sage: Q.is_isotropic(5) # needs sage.libs.pari True :: - sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p)]).is_isotropic(p) for p in prime_range(3, 30)] + sage: [DiagonalQuadraticForm(ZZ, # needs sage.libs.pari + ....: [1, -least_quadratic_nonresidue(p)]).is_isotropic(p) + ....: for p in prime_range(3, 30)] [False, False, False, False, False, False, False, False, False] :: - sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p), p, -p*least_quadratic_nonresidue(p)]).is_isotropic(p) for p in prime_range(3, 30)] + sage: [DiagonalQuadraticForm(ZZ, [1, -least_quadratic_nonresidue(p), # needs sage.libs.pari + ....: p, -p*least_quadratic_nonresidue(p)]).is_isotropic(p) + ....: for p in prime_range(3, 30)] [False, False, False, False, False, False, False, False, False] """ @@ -742,15 +728,15 @@ def anisotropic_primes(self): EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: Q.anisotropic_primes() + sage: Q.anisotropic_primes() # needs sage.libs.pari [2, -1] sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) - sage: Q.anisotropic_primes() + sage: Q.anisotropic_primes() # needs sage.libs.pari [2, -1] sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,1]) - sage: Q.anisotropic_primes() + sage: Q.anisotropic_primes() # needs sage.libs.pari [-1] """ # Look at all prime divisors of 2 * Det(Q) to find the @@ -761,25 +747,23 @@ def anisotropic_primes(self): def compute_definiteness(self): """ - Computes whether the given quadratic form is positive-definite, + Compute whether the given quadratic form is positive-definite, negative-definite, indefinite, degenerate, or the zero form. - This caches one of the following strings in self.__definiteness_string: + This caches one of the following strings in ``self.__definiteness_string``: "pos_def", "neg_def", "indef", "zero", "degenerate". It is called - from all routines like: - - is_positive_definite(), is_negative_definite(), is_indefinite(), etc. + from all routines like: :meth:`is_positive_definite`, :meth:`is_negative_definite`, + :meth:`is_indefinite`, etc. - Note: A degenerate form is considered neither definite nor indefinite. - Note: The zero-dim'l form is considered both positive definite and negative definite. + .. NOTE:: - INPUT: + A degenerate form is considered neither definite nor indefinite. - QuadraticForm + .. NOTE: - OUTPUT: + The zero-dimensional form is considered both positive definite and negative definite. - boolean + OUTPUT: boolean EXAMPLES:: @@ -822,6 +806,8 @@ def compute_definiteness(self): """ # Sanity Check + from sage.rings.real_mpfr import RR + if not ((self.base_ring() == ZZ) or (self.base_ring() == QQ) or (self.base_ring() == RR)): raise NotImplementedError("we can only check definiteness over ZZ, QQ, and RR for now") @@ -854,15 +840,9 @@ def compute_definiteness_string_by_determinants(self): """ Compute the (positive) definiteness of a quadratic form by looking at the signs of all of its upper-left subdeterminants. See also - self.compute_definiteness() for more documentation. - - INPUT: - - None - - OUTPUT: + :meth:`compute_definiteness` for more documentation. - string describing the definiteness + OUTPUT: string describing the definiteness EXAMPLES:: @@ -895,9 +875,13 @@ def compute_definiteness_string_by_determinants(self): 'neg_def' """ # Sanity Check + from sage.rings.real_mpfr import RR + if not ((self.base_ring() == ZZ) or (self.base_ring() == QQ) or (self.base_ring() == RR)): raise NotImplementedError("we can only check definiteness over ZZ, QQ, and RR for now") + from sage.functions.all import sgn + # Some useful variables n = self.dim() M = self.matrix() @@ -932,16 +916,15 @@ def is_positive_definite(self): """ Determines if the given quadratic form is positive-definite. - Note: A degenerate form is considered neither definite nor indefinite. - Note: The zero-dim'l form is considered both positive definite and negative definite. + .. NOTE:: - INPUT: + A degenerate form is considered neither definite nor indefinite. - None + .. NOTE:: - OUTPUT: + The zero-dimensional form is considered both positive definite and negative definite. - boolean -- True or False + OUTPUT: boolean -- True or False EXAMPLES:: @@ -970,16 +953,15 @@ def is_negative_definite(self): """ Determines if the given quadratic form is negative-definite. - Note: A degenerate form is considered neither definite nor indefinite. - Note: The zero-dim'l form is considered both positive definite and negative definite. + .. NOTE:: - INPUT: + A degenerate form is considered neither definite nor indefinite. - None + .. NOTE:: - OUTPUT: + The zero-dimensional form is considered both positive definite and negative definite. - boolean -- True or False + OUTPUT: boolean -- True or False EXAMPLES:: @@ -1008,16 +990,15 @@ def is_indefinite(self): """ Determines if the given quadratic form is indefinite. - Note: A degenerate form is considered neither definite nor indefinite. - Note: The zero-dim'l form is not considered indefinite. + .. NOTE:: - INPUT: + A degenerate form is considered neither definite nor indefinite. - None + .. NOTE:: - OUTPUT: + The zero-dimensional form is not considered indefinite. - boolean -- True or False + OUTPUT: boolean -- True or False EXAMPLES:: @@ -1047,16 +1028,15 @@ def is_definite(self): """ Determines if the given quadratic form is (positive or negative) definite. - Note: A degenerate form is considered neither definite nor indefinite. - Note: The zero-dim'l form is considered indefinite. + .. NOTE:: - INPUT: + A degenerate form is considered neither definite nor indefinite. - None + .. NOTE:: - OUTPUT: + The zero-dimensional form is considered indefinite. - boolean -- True or False + OUTPUT: boolean -- True or False EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form__local_normal_form.py b/src/sage/quadratic_forms/quadratic_form__local_normal_form.py index 429c7c68896..5770a3c22f0 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_normal_form.py +++ b/src/sage/quadratic_forms/quadratic_form__local_normal_form.py @@ -1,7 +1,6 @@ """ Local Normal Form """ - # **************************************************************************** # Copyright (C) 2007 William Stein and Jonathan Hanke # @@ -18,50 +17,52 @@ # **************************************************************************** import copy + from sage.rings.infinity import Infinity -from sage.rings.integer_ring import IntegerRing, ZZ +from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.arith.all import GCD, valuation, is_prime +from sage.arith.misc import GCD, valuation, is_prime def find_entry_with_minimal_scale_at_prime(self, p): - """ - Finds the entry of the quadratic form with minimal scale at the - prime p, preferring diagonal entries in case of a tie. (I.e. If - we write the quadratic form as a symmetric matrix M, then this - entry M[i,j] has the minimal valuation at the prime p.) + r""" + Find the entry of the quadratic form with minimal scale at the + prime `p`, preferring diagonal entries in case of a tie. - Note: This answer is independent of the kind of matrix (Gram or - Hessian) associated to the form. + (I.e. If + we write the quadratic form as a symmetric matrix `M`, then this + entry ``M[i,j]`` has the minimal valuation at the prime `p`.) - INPUT: + .. NOTE:: - `p` -- a prime number > 0 + This answer is independent of the kind of matrix (Gram or + Hessian) associated to the form. - OUTPUT: + INPUT: + + - ``p`` -- a prime number > 0 - a pair of integers >= 0 + OUTPUT: a pair of integers `\geq 0` EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [6, 2, 20]); Q Quadratic form in 2 variables over Integer Ring with coefficients: - [ 6 2 ] - [ * 20 ] + [ 6 2 ] + [ * 20 ] sage: Q.find_entry_with_minimal_scale_at_prime(2) (0, 1) sage: Q.find_entry_with_minimal_scale_at_prime(3) (1, 1) sage: Q.find_entry_with_minimal_scale_at_prime(5) (0, 0) - """ n = self.dim() min_val = Infinity ij_index = None val_2 = valuation(2, p) for d in range(n): # d = difference j-i - for e in range(n - d): # e is the length of the diagonal with value d. + for e in range(n - d): # e is the length of the diagonal with value d. # Compute the valuation of the entry if d == 0: @@ -83,18 +84,16 @@ def local_normal_form(self, p): Return a locally integrally equivalent quadratic form over the `p`-adic integers `\ZZ_p` which gives the Jordan decomposition. - The Jordan components are written as sums of blocks of size <= 2 + The Jordan components are written as sums of blocks of size `\leq 2` and are arranged by increasing scale, and then by increasing norm. - This is equivalent to saying that we put the 1x1 blocks before - the 2x2 blocks in each Jordan component. + This is equivalent to saying that we put the `1 \times 1` blocks before + the `2 \times 2` blocks in each Jordan component. INPUT: - - `p` -- a positive prime number. - - OUTPUT: + - ``p`` -- a positive prime number - a quadratic form over `\ZZ` + OUTPUT: a quadratic form over `\ZZ` .. WARNING:: @@ -105,25 +104,25 @@ def local_normal_form(self, p): sage: Q = QuadraticForm(ZZ, 2, [10,4,1]) sage: Q.local_normal_form(5) Quadratic form in 2 variables over Integer Ring with coefficients: - [ 1 0 ] - [ * 6 ] + [ 1 0 ] + [ * 6 ] :: sage: Q.local_normal_form(3) Quadratic form in 2 variables over Integer Ring with coefficients: - [ 10 0 ] - [ * 15 ] + [ 10 0 ] + [ * 15 ] sage: Q.local_normal_form(2) Quadratic form in 2 variables over Integer Ring with coefficients: - [ 1 0 ] - [ * 6 ] + [ 1 0 ] + [ * 6 ] """ # Sanity Checks - if (self.base_ring() != IntegerRing()): + if self.base_ring() != ZZ: raise NotImplementedError("this currently only works for quadratic forms defined over ZZ") - if not ((p>=2) and is_prime(p)): + if not (p >= 2 and is_prime(p)): raise TypeError("p is not a positive prime number") # Some useful local variables @@ -145,21 +144,21 @@ def local_normal_form(self, p): min_val = valuation(Q[min_i, min_j], p) # Error if we still haven't seen non-zero coefficients! - if (min_val == Infinity): + if min_val == Infinity: raise RuntimeError("the original matrix is degenerate") # Step 2: Arrange for the upper leftmost entry to have minimal valuation # ---------------------------------------------------------------------- - if (min_i == min_j): + if min_i == min_j: block_size = 1 - Q.swap_variables(0, min_i, in_place = True) + Q.swap_variables(0, min_i, in_place=True) else: # Work in the upper-left 2x2 block, and replace it by its 2-adic equivalent form - Q.swap_variables(0, min_i, in_place = True) - Q.swap_variables(1, min_j, in_place = True) + Q.swap_variables(0, min_i, in_place=True) + Q.swap_variables(1, min_j, in_place=True) # 1x1 => make upper left the smallest - if (p != 2): + if p != 2: block_size = 1 Q.add_symmetric(1, 0, 1, in_place=True) # 2x2 => replace it with the appropriate 2x2 matrix @@ -171,8 +170,8 @@ def local_normal_form(self, p): min_scale = p ** min_val # This is the minimal valuation of the Hessian matrix entries. # Perform cancellation over Z by ensuring divisibility - if (block_size == 1): - a = 2 * Q[0,0] + if block_size == 1: + a = 2 * Q[0, 0] for j in range(block_size, n): b = Q[0, j] g = GCD(a, b) @@ -181,16 +180,16 @@ def local_normal_form(self, p): if valuation(g, p) != valuation(a, p): raise RuntimeError("we have a problem with our rescaling not preserving p-integrality") - Q.multiply_variable(ZZ(a/g), j, in_place = True) # Ensures that the new b entry is divisible by a - Q.add_symmetric(ZZ(-b/g), j, 0, in_place = True) # Performs the cancellation + Q.multiply_variable(ZZ(a / g), j, in_place=True) # Ensures that the new b entry is divisible by a + Q.add_symmetric(ZZ(-b / g), j, 0, in_place=True) # Performs the cancellation - elif (block_size == 2): - a1 = 2 * Q[0,0] + elif block_size == 2: + a1 = 2 * Q[0, 0] a2 = Q[0, 1] b1 = Q[1, 0] # This is the same as a2 b2 = 2 * Q[1, 1] - big_det = (a1*b2 - a2*b1) + big_det = a1 * b2 - a2 * b1 small_det = big_det / (min_scale * min_scale) # Cancels out the rows/columns of the 2x2 block @@ -199,21 +198,21 @@ def local_normal_form(self, p): b = Q[1, j] # Ensures an integral result (scale jth row/column by big_det) - Q.multiply_variable(big_det, j, in_place = True) + Q.multiply_variable(big_det, j, in_place=True) # Performs the cancellation (by producing -big_det * jth row/column) - Q.add_symmetric(ZZ(-(a*b2 - b*a2)), j, 0, in_place = True) - Q.add_symmetric(ZZ(-(-a*b1 + b*a1)), j, 1, in_place = True) + Q.add_symmetric(ZZ(-(a * b2 - b * a2)), j, 0, in_place=True) + Q.add_symmetric(ZZ(-(-a * b1 + b * a1)), j, 1, in_place=True) # Now remove the extra factor (non p-unit factor) in big_det we introduced above - Q.divide_variable(ZZ(min_scale * min_scale), j, in_place = True) + Q.divide_variable(ZZ(min_scale * min_scale), j, in_place=True) # Uses Cassels's proof to replace the remaining 2 x 2 block - if (((1 + small_det) % 8) == 0): + if (1 + small_det) % 8 == 0: Q[0, 0] = 0 Q[1, 1] = 0 Q[0, 1] = min_scale - elif (((5 + small_det) % 8) == 0): + elif (5 + small_det) % 8 == 0: Q[0, 0] = min_scale Q[1, 1] = min_scale Q[0, 1] = min_scale @@ -223,7 +222,7 @@ def local_normal_form(self, p): # Check that the cancellation worked, extract the upper-left block, and trim Q to handle the next block. for i in range(block_size): for j in range(block_size, n): - if Q[i,j] != 0: + if Q[i, j] != 0: raise RuntimeError(f"the cancellation did not work properly at entry ({i},{j})") Q_Jordan = Q_Jordan + Q.extract_variables(range(block_size)) Q = Q.extract_variables(range(block_size, n)) @@ -237,7 +236,7 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): `p^{s_i}`-unimodular Jordan component which is further decomposed into block diagonals of block size `\le 2`. - For each `L_i` the 2x2 blocks are listed after the 1x1 blocks + For each `L_i` the `2 \times 2` blocks are listed after the `1 \times 1` blocks (which follows from the convention of the :meth:`local_normal_form` method). @@ -253,7 +252,7 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): INPUT: - - `p` -- a prime number > 0. + - ``p`` -- a prime number > 0 OUTPUT: @@ -272,25 +271,27 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7]) sage: Q.jordan_blocks_by_scale_and_unimodular(3) [(0, Quadratic form in 3 variables over Integer Ring with coefficients: - [ 1 0 0 ] - [ * 5 0 ] - [ * * 7 ]), (2, Quadratic form in 1 variables over Integer Ring with coefficients: - [ 1 ])] + [ 1 0 0 ] + [ * 5 0 ] + [ * * 7 ]), + (2, Quadratic form in 1 variables over Integer Ring with coefficients: + [ 1 ])] :: sage: Q2 = QuadraticForm(ZZ, 2, [1,1,1]) sage: Q2.jordan_blocks_by_scale_and_unimodular(2) [(-1, Quadratic form in 2 variables over Integer Ring with coefficients: - [ 2 2 ] - [ * 2 ])] + [ 2 2 ] + [ * 2 ])] sage: Q = Q2 + Q2.scale_by_factor(2) sage: Q.jordan_blocks_by_scale_and_unimodular(2) [(-1, Quadratic form in 2 variables over Integer Ring with coefficients: - [ 2 2 ] - [ * 2 ]), (0, Quadratic form in 2 variables over Integer Ring with coefficients: - [ 2 2 ] - [ * 2 ])] + [ 2 2 ] + [ * 2 ]), + (0, Quadratic form in 2 variables over Integer Ring with coefficients: + [ 2 2 ] + [ * 2 ])] """ # Try to use the cached result try: @@ -298,48 +299,45 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): return copy.deepcopy(self.__jordan_blocks_by_scale_and_unimodular_dict[p]) else: return self.__jordan_blocks_by_scale_and_unimodular_dict[p] - except Exception: + except (KeyError, AttributeError): # Initialize the global dictionary if it doesn't exist if not hasattr(self, '__jordan_blocks_by_scale_and_unimodular_dict'): self.__jordan_blocks_by_scale_and_unimodular_dict = {} - # Deal with zero dim'l forms if self.dim() == 0: return [] - # Find the Local Normal form of Q at p Q1 = self.local_normal_form(p) - # Parse this into Jordan Blocks n = Q1.dim() tmp_Jordan_list = [] i = 0 start_ind = 0 - if (n >= 2) and (Q1[0,1] != 0): - start_scale = valuation(Q1[0,1], p) - 1 + if n >= 2 and Q1[0, 1] != 0: + start_scale = valuation(Q1[0, 1], p) - 1 else: - start_scale = valuation(Q1[0,0], p) + start_scale = valuation(Q1[0, 0], p) - while (i < n): + while i < n: # Determine the size of the current block - if (i == n-1) or (Q1[i,i+1] == 0): + if i == n - 1 or Q1[i, i + 1] == 0: block_size = 1 else: block_size = 2 # Determine the valuation of the current block if block_size == 1: - block_scale = valuation(Q1[i,i], p) + block_scale = valuation(Q1[i, i], p) else: - block_scale = valuation(Q1[i,i+1], p) - 1 + block_scale = valuation(Q1[i, i + 1], p) - 1 # Process the previous block if the valuation increased if block_scale > start_scale: - tmp_Jordan_list += [(start_scale, Q1.extract_variables(range(start_ind, i)).scale_by_factor(ZZ(1) / (QQ(p)**(start_scale))))] + tmp_Jordan_list += [(start_scale, Q1.extract_variables(range(start_ind, i)).scale_by_factor(ZZ.one() / QQ(p)**start_scale))] start_ind = i start_scale = block_scale @@ -347,8 +345,7 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): i += block_size # Add the last block - tmp_Jordan_list += [(start_scale, Q1.extract_variables(range(start_ind, n)).scale_by_factor(ZZ(1) / QQ(p)**(start_scale)))] - + tmp_Jordan_list += [(start_scale, Q1.extract_variables(range(start_ind, n)).scale_by_factor(ZZ.one() / QQ(p)**start_scale))] # Cache the result self.__jordan_blocks_by_scale_and_unimodular_dict[p] = tmp_Jordan_list @@ -358,22 +355,20 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): def jordan_blocks_in_unimodular_list_by_scale_power(self, p): - """ - Returns a list of Jordan components, whose component at index i - should be scaled by the factor p^i. + r""" + Return a list of Jordan components, whose component at index `i` + should be scaled by the factor `p^i`. This is only defined for integer-valued quadratic forms - (i.e. forms with base_ring ZZ), and the indexing only works - correctly for p=2 when the form has an integer Gram matrix. + (i.e., forms with base ring `\ZZ`), and the indexing only works + correctly for `p=2` when the form has an integer Gram matrix. INPUT: - self -- a quadratic form over ZZ, which has integer Gram matrix if p == 2 - `p` -- a prime number > 0 - - OUTPUT: + - ``self`` -- a quadratic form over `\ZZ`, which has integer Gram matrix if `p = 2` + - ``p`` -- a prime number > 0 - a list of p-unimodular quadratic forms + OUTPUT: a list of `p`-unimodular quadratic forms EXAMPLES:: @@ -385,16 +380,19 @@ def jordan_blocks_in_unimodular_list_by_scale_power(self, p): sage: Q.scale_by_factor(2).jordan_blocks_in_unimodular_list_by_scale_power(2) [Quadratic form in 2 variables over Integer Ring with coefficients: - [ 0 2 ] - [ * 0 ], Quadratic form in 0 variables over Integer Ring with coefficients: - , Quadratic form in 1 variables over Integer Ring with coefficients: - [ 345 ]] + [ 0 2 ] + [ * 0 ], + Quadratic form in 0 variables over Integer Ring with coefficients: + , + Quadratic form in 1 variables over Integer Ring with coefficients: + [ 345 ]] sage: Q.jordan_blocks_in_unimodular_list_by_scale_power(3) [Quadratic form in 2 variables over Integer Ring with coefficients: - [ 2 0 ] - [ * 10 ], Quadratic form in 1 variables over Integer Ring with coefficients: - [ 2 ]] + [ 2 0 ] + [ * 10 ], + Quadratic form in 1 variables over Integer Ring with coefficients: + [ 2 ]] """ # Sanity Check if self.base_ring() != ZZ: diff --git a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py index 5d39650ecb4..888f4ae2832 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py +++ b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari sage.rings.number_field """ Local Representation Conditions """ @@ -8,7 +9,7 @@ from __future__ import annotations from copy import deepcopy -from sage.arith.all import prime_divisors, valuation, is_square +from sage.arith.misc import is_square, prime_divisors, valuation from sage.misc.functional import numerator, denominator from sage.quadratic_forms.extras import least_quadratic_nonresidue from sage.rings.infinity import infinity @@ -67,8 +68,9 @@ class QuadraticFormLocalRepresentationConditions(): sage: Q2.is_locally_universal_at_all_primes() False sage: L = [m for m in range(-5, 25) if Q2.is_locally_represented_number(m)] - sage: L1 = [0] + [m for m in range(1,25) \ - if len([p for p in prime_factors(squarefree_part(ZZ(m))) if (p % 4) == 3]) % 2 == 0] + sage: L1 = [0] + [m for m in range(1, 25) + ....: if len([p for p in prime_factors(squarefree_part(ZZ(m))) + ....: if (p % 4) == 3]) % 2 == 0] sage: L == L1 True sage: L @@ -93,19 +95,19 @@ class QuadraticFormLocalRepresentationConditions(): [0] """ def __init__(self, Q): - """ - Takes a QuadraticForm and computes its local conditions (if - they do not already exist). The recompute_flag overrides the + r""" + Takes a :class:`QuadraticForm` and computes its local conditions (if + they do not already exist). The ``recompute_flag`` overrides the previously computed conditions if they exist, and stores the new conditions. INPUT: - - Q -- Quadratic form over ZZ + - ``Q`` -- Quadratic form over `\ZZ` OUTPUT: - a QuadraticFormLocalRepresentationConditions object + a :class:`QuadraticFormLocalRepresentationConditions` object EXAMPLES:: @@ -201,9 +203,7 @@ def __repr__(self) -> str: r""" Print the local conditions. - OUTPUT: - - string + OUTPUT: string .. TODO:: @@ -246,11 +246,9 @@ def __eq__(self, right) -> bool: INPUT: - - right -- a QuadraticFormLocalRepresentationConditions object - - OUTPUT: + - ``right`` -- a QuadraticFormLocalRepresentationConditions object - boolean + OUTPUT: boolean EXAMPLES:: @@ -293,11 +291,9 @@ def squareclass_vector(self, p) -> list: INPUT: - - `p` -- a positive prime number or "infinity" + - ``p`` -- a positive prime number or "infinity" - OUTPUT: - - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -320,11 +316,9 @@ def local_conditions_vector_for_prime(self, p) -> list: INPUT: - - `p` -- a positive prime number. (Is 'infinity' allowed here?) - - OUTPUT: + - ``p`` -- a positive prime number. (Is 'infinity' allowed here?) - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -371,16 +365,14 @@ def local_conditions_vector_for_prime(self, p) -> list: raise RuntimeError("the stored dimension should be a non-negative integer") def is_universal_at_prime(self, p) -> bool: - """ - Determine if the (integer-valued/rational) quadratic form represents all of `Z_p`. + r""" + Determine if the (integer-valued/rational) quadratic form represents all of `\ZZ_p`. INPUT: - - `p` -- a positive prime number or "infinity". + - ``p`` -- a positive prime number or "infinity" - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -418,12 +410,10 @@ def is_universal_at_prime(self, p) -> bool: return Zp_univ_flag def is_universal_at_all_finite_primes(self) -> bool: - """ - Determine if the quadratic form represents `Z_p` for all finite/non-archimedean primes. - - OUTPUT: + r""" + Determine if the quadratic form represents `\ZZ_p` for all finite/non-archimedean primes. - boolean + OUTPUT: boolean EXAMPLES:: @@ -451,13 +441,11 @@ def is_universal_at_all_finite_primes(self) -> bool: for p in self.exceptional_primes[1:]) def is_universal_at_all_places(self) -> bool: - """ - Determine if the quadratic form represents `Z_p` for all + r""" + Determine if the quadratic form represents `\ZZ_p` for all finite/non-archimedean primes, and represents all real numbers. - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -499,13 +487,11 @@ def is_locally_represented_at_place(self, m, p) -> bool: INPUT: - - `m` -- an integer - - - `p` -- a positive prime number or "infinity". + - ``m`` -- an integer - OUTPUT: + - ``p`` -- a positive prime number or "infinity" - boolean + OUTPUT: boolean EXAMPLES:: @@ -563,18 +549,16 @@ def is_locally_represented_at_place(self, m, p) -> bool: return local_vec[sqclass.index(s) + 1] <= (nu / 2) def is_locally_represented(self, m) -> bool: - """ + r""" Determine if the rational number `m` is locally represented by - the quadratic form (allowing vectors with coefficients in `Z_p` at all + the quadratic form (allowing vectors with coefficients in `\ZZ_p` at all places). INPUT: - - `m` -- an integer + - ``m`` -- an integer - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -624,51 +608,45 @@ def is_locally_represented(self, m) -> bool: def local_representation_conditions(self, recompute_flag=False, silent_flag=False): - """ + r""" .. WARNING:: - THIS ONLY WORKS CORRECTLY FOR FORMS IN >=3 VARIABLES, - WHICH ARE LOCALLY UNIVERSAL AT ALMOST ALL PRIMES! + This only works correctly for forms in >=3 variables, + which are locally universal at almost all primes! This class finds the local conditions for a number to be integrally represented by an integer-valued quadratic form. These conditions - are stored in "self.__local_representability_conditions" and + are stored in ``self.__local_representability_conditions`` and consist of a list of 9 element vectors, with one for each prime with a local obstruction (though only the first 5 are meaningful - unless `p=2` ). The first element is always the prime `p` where the + unless `p=2`). The first element is always the prime `p` where the local obstruction occurs, and the next 8 (or 4) entries represent - square-classes in the `p`-adic integers `Z_p`, and are labeled by the - `Q_p` square-classes `t*(Q_p)^2` with `t` given as follows: + square-classes in the `p`-adic integers `\ZZ_p`, and are labeled by the + `\QQ_p` square-classes `t\cdot (\QQ_p)^2` with `t` given as follows: - `p > 2` ==> [ * 1 u p u p * * * * ] + - for `p > 2`, ``[ * 1 u p u p * * * * ]``, - `p = 2` ==> [ * 1 3 5 7 2 6 10 14 ] + - for `p = 2`, ``[ * 1 3 5 7 2 6 10 14 ]``. The integer appearing in each place tells us how `p`-divisible a number needs to be in that square-class in order to be locally - represented by Q. A negative number indicates that the entire `Q_p` + represented by `Q`. A negative number indicates that the entire `\QQ_p` square-class is not represented, while a positive number `x` indicates - that `t*p^{(2*x)} (Z_p)^2` is locally represented but `t*p^{(2*(x-1))}` - `(Z_p)^2` is not. + that `t\cdot p^{(2\cdot x)} (\ZZ_p)^2` is locally represented but `t\cdot p^{(2\cdot (x-1))}` + `(\ZZ_p)^2` is not. - As an example, the vector - - [2 3 0 0 0 0 2 0 infinity] - - tells us that all positive integers are locally represented at p=2 + As an example, the vector ``[2 3 0 0 0 0 2 0 infinity]`` + tells us that all positive integers are locally represented at `p=2` except those of the forms: - `2^6 * u * r^2` with `u = 1 (mod 8)` - - `2^5 * u * r^2` with `u = 3 (mod 8)` + - `2^6\cdot u\cdot r^2` with `u = 1` (mod 8) - `2 * u * r^2` with `u = 7 (mod 8)` + - `2^5\cdot u\cdot r^2` with `u = 3` (mod 8) - At the real numbers, the vector which looks like + - `2\cdot u\cdot r^2` with `u = 7` (mod 8) - [infinity, 0, infinity, None, None, None, None, None, None] - - means that Q is negative definite (i.e. the 0 tells us all + At the real numbers, the vector which looks like ``[infinity, 0, infinity, None, None, None, None, None, None]`` + means that `Q` is negative definite (i.e., the 0 tells us all positive reals are represented). The real vector always appears, and is listed before the other ones. @@ -738,16 +716,14 @@ def local_representation_conditions(self, recompute_flag=False, silent_flag=Fals def is_locally_universal_at_prime(self, p) -> bool: - """ - Determine if the (integer-valued/rational) quadratic form represents all of `Z_p`. + r""" + Determine if the (integer-valued/rational) quadratic form represents all of `\ZZ_p`. INPUT: - - `p` -- a positive prime number or "infinity". + - ``p`` -- a positive prime number or "infinity" - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -784,12 +760,10 @@ def is_locally_universal_at_prime(self, p) -> bool: def is_locally_universal_at_all_primes(self) -> bool: - """ - Determine if the quadratic form represents `Z_p` for all finite/non-archimedean primes. - - OUTPUT: + r""" + Determine if the quadratic form represents `\ZZ_p` for all finite/non-archimedean primes. - boolean + OUTPUT: boolean EXAMPLES:: @@ -814,13 +788,11 @@ def is_locally_universal_at_all_primes(self) -> bool: def is_locally_universal_at_all_places(self) -> bool: - """ - Determine if the quadratic form represents `Z_p` for all + r""" + Determine if the quadratic form represents `\ZZ_p` for all finite/non-archimedean primes, and represents all real numbers. - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -851,13 +823,11 @@ def is_locally_represented_number_at_place(self, m, p) -> bool: INPUT: - - `m` -- an integer - - - `p` -- a prime number > 0 or 'infinity' + - ``m`` -- an integer - OUTPUT: + - ``p`` -- a prime number > 0 or 'infinity' - boolean + OUTPUT: boolean EXAMPLES:: @@ -898,11 +868,9 @@ def is_locally_represented_number(self, m) -> bool: INPUT: - - `m` -- an integer - - OUTPUT: + - ``m`` -- an integer - boolean + OUTPUT: boolean EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form__mass.py b/src/sage/quadratic_forms/quadratic_form__mass.py index 9f7de214b6a..11b581b1dd7 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass.py +++ b/src/sage/quadratic_forms/quadratic_form__mass.py @@ -50,13 +50,14 @@ def shimura_mass__maximal(self): pass - def GHY_mass__maximal(self): """ Use the GHY formula to compute the mass of a (maximal?) quadratic lattice. This works for any number field. - Reference: See [GHY, Prop 7.4 and 7.5, p121] and [GY, Thrm 10.20, p25]. + REFERENCES: + + See [GHY, Prop 7.4 and 7.5, p121] and [GY, Thrm 10.20, p25]. OUTPUT: diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py index 65c524db39a..894ee68cec9 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py @@ -1,35 +1,37 @@ """ Conway-Sloane masses """ +from sage.arith.misc import (fundamental_discriminant, + is_prime, + kronecker as kronecker_symbol, + legendre_symbol, + prime_divisors) +from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.arith.all import kronecker_symbol, legendre_symbol, prime_divisors, is_prime, fundamental_discriminant -from sage.symbolic.constants import pi -from sage.misc.misc_c import prod -from sage.quadratic_forms.special_values import gamma__exact, zeta__exact, quadratic_L_function__exact def parity(self, allow_rescaling_flag=True): - """ + r""" Return the parity ("even" or "odd") of an integer-valued quadratic - form over `ZZ`, defined up to similitude/rescaling of the form so that + form over `\ZZ`, defined up to similitude/rescaling of the form so that its Jordan component of smallest scale is unimodular. After this rescaling, we say a form is even if it only represents even numbers, and odd if it represents some odd number. - If the 'allow_rescaling_flag' is set to False, then we require that - the quadratic form have a Gram matrix with coefficients in `ZZ`, and + If the ``allow_rescaling_flag`` is set to False, then we require that + the quadratic form have a Gram matrix with coefficients in `\ZZ`, and look at the unimodular Jordan block to determine its parity. This returns an error if the form is not integer-matrix, meaning that it has Jordan components at `p=2` which do not have an integer scale. - We determine the parity by looking for a 1x1 block in the 0-th + We determine the parity by looking for a `1 \times 1` block in the 0-th Jordan component, after a possible rescaling. INPUT: - self -- a quadratic form with base_ring `ZZ`, which we may - require to have integer Gram matrix. + - ``self`` -- a quadratic form with base ring `\ZZ`, which we may + require to have integer Gram matrix. OUTPUT: @@ -74,7 +76,6 @@ def parity(self, allow_rescaling_flag=True): [ * * 1 ] sage: Q.parity() 'odd' - """ # Deal with 0-dim'l forms if self.dim() == 0: @@ -82,7 +83,7 @@ def parity(self, allow_rescaling_flag=True): # Identify the correct Jordan component to use. Jordan_list = self.jordan_blocks_by_scale_and_unimodular(2) - scale_pow_list = [J[0] for J in Jordan_list] + scale_pow_list = [J[0] for J in Jordan_list] min_scale_pow = min(scale_pow_list) if allow_rescaling_flag: ind = scale_pow_list.index(min_scale_pow) @@ -103,19 +104,17 @@ def parity(self, allow_rescaling_flag=True): # convention of the local_normal_form routine will appear first). if Q0.dim() == 1: return "odd" - elif Q0[0,1] == 0: + if Q0[0, 1] == 0: return "odd" - else: - return "even" - + return "even" -def is_even(self, allow_rescaling_flag=True): - """ - Returns true iff after rescaling by some appropriate factor, the - form represents no odd integers. For more details, see parity(). +def is_even(self, allow_rescaling_flag=True) -> bool: + r""" + Return true iff after rescaling by some appropriate factor, the + form represents no odd integers. For more details, see :meth:`parity`. - Requires that Q is defined over `ZZ`. + Requires that `Q` is defined over `\ZZ`. EXAMPLES:: @@ -125,17 +124,16 @@ def is_even(self, allow_rescaling_flag=True): sage: Q = QuadraticForm(ZZ, 2, [1, 1, 1]) sage: Q.is_even() True - """ return self.parity(allow_rescaling_flag) == "even" def is_odd(self, allow_rescaling_flag=True): - """ - Returns true iff after rescaling by some appropriate factor, the - form represents some odd integers. For more details, see parity(). + r""" + Return true iff after rescaling by some appropriate factor, the + form represents some odd integers. For more details, see :meth:`parity`. - Requires that Q is defined over `ZZ`. + Requires that `Q` is defined over `\ZZ`. EXAMPLES:: @@ -150,27 +148,26 @@ def is_odd(self, allow_rescaling_flag=True): return self.parity(allow_rescaling_flag) == "odd" - def conway_species_list_at_odd_prime(self, p): - """ - Returns an integer called the 'species' which determines the type - of the orthogonal group over the finite field `F_p`. + r""" + Return an integer called the 'species' which determines the type + of the orthogonal group over the finite field `\GF{p}`. This assumes that the given quadratic form is a unimodular Jordan block at an odd prime `p`. When the dimension is odd then this number is always positive, otherwise it may be positive or negative (or zero, but that is considered positive by convention). - Note: The species of a zero dim'l form is always 0+, so we - interpret the return value of zero as positive here! =) + .. NOTE: - INPUT: + The species of a zero dimensional form is always 0+, so we + interpret the return value of zero as positive here! =) - a positive prime number + INPUT: - OUTPUT: + - ``p`` -- a positive prime number - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -207,9 +204,9 @@ def conway_species_list_at_odd_prime(self, p): d = tmp_Q.det() # Determine the species - if (n % 2 != 0): # Deal with odd dim'l forms + if n % 2 != 0: # Deal with odd dim'l forms species = n - elif (n % 4 == 2) and (p % 4 == 3): # Deal with even dim'l forms + elif n % 4 == 2 and p % 4 == 3: # Deal with even dim'l forms species = (-1) * legendre_symbol(d, p) * n else: species = legendre_symbol(d, p) * n @@ -221,23 +218,22 @@ def conway_species_list_at_odd_prime(self, p): return species_list - def conway_species_list_at_2(self): - """ - Returns an integer called the 'species' which determines the type - of the orthogonal group over the finite field `F_p`. + r""" + Return an integer called the 'species' which determines the type + of the orthogonal group over the finite field `\GF{p}`. This assumes that the given quadratic form is a unimodular Jordan block at an odd prime `p`. When the dimension is odd then this number is always positive, otherwise it may be positive or negative. - Note: The species of a zero dim'l form is always 0+, so we - interpret the return value of zero as positive here! =) + .. NOTE:: - OUTPUT: + The species of a zero dimensional form is always 0+, so we + interpret the return value of zero as positive here! =) - a list of integers + OUTPUT: a list of integers EXAMPLES:: @@ -276,17 +272,17 @@ def conway_species_list_at_2(self): if jordan_list[i].is_even(): two_t = d else: - two_t = ZZ(2) * ((d-1) // 2) + two_t = ZZ(2) * ((d - 1) // 2) # Determine if the form is bound if len(jordan_list) == 1: is_bound = False elif i == 0: - is_bound = jordan_list[i+1].is_odd() + is_bound = jordan_list[i + 1].is_odd() elif i == len(jordan_list) - 1: - is_bound = jordan_list[i-1].is_odd() + is_bound = jordan_list[i - 1].is_odd() else: - is_bound = jordan_list[i-1].is_odd() or jordan_list[i+1].is_odd() + is_bound = jordan_list[i - 1].is_odd() or jordan_list[i + 1].is_odd() # Determine the species octane = jordan_list[i].conway_octane_of_this_unimodular_Jordan_block_at_2() @@ -300,7 +296,6 @@ def conway_species_list_at_2(self): # Append the species to the list species_list.append(species) - if jordan_list[-1].is_odd(): # Add an entry for the unlisted "s_max + 1" Jordan component as well. species_list.append(1) @@ -308,24 +303,16 @@ def conway_species_list_at_2(self): return species_list - - def conway_octane_of_this_unimodular_Jordan_block_at_2(self): - """ + r""" Determines the 'octane' of this full unimodular Jordan block at - the prime `p=2`. This is an invariant defined `(mod 8)`, ad. + the prime `p=2`. This is an invariant defined (mod 8), ad. This assumes that the form is given as a block diagonal form with - unimodular blocks of size <= 2 and the 1x1 blocks are all in the upper + unimodular blocks of size `\leq 2` and the `1 \times 1` blocks are all in the upper leftmost position. - INPUT: - - none - - OUTPUT: - - an integer 0 <= x <= 7 + OUTPUT: an integer `0 \leq x \leq 7` EXAMPLES:: @@ -338,52 +325,50 @@ def conway_octane_of_this_unimodular_Jordan_block_at_2(self): sage: Q = DiagonalQuadraticForm(ZZ, [3,7,13]) sage: Q.conway_octane_of_this_unimodular_Jordan_block_at_2() 7 - """ # Deal with 'even' forms if self.parity() == "even": d = self.Gram_matrix().det() - if (d % 8 == 1) or (d % 8 == 7): + if d % 8 == 1 or d % 8 == 7: return 0 else: return 4 # Deal with 'odd' forms by diagonalizing, and then computing the octane. n = self.dim() - u = self[0,0] - tmp_diag_vec = [None for i in range(n)] + u = self[0, 0] + tmp_diag_vec = [None] * n tmp_diag_vec[0] = u # This should be an odd integer! - ind = 1 # The next index to diagonalize - + ind = 1 # The next index to diagonalize # Use u to diagonalize the form -- WHAT ARE THE POSSIBLE LOCAL NORMAL FORMS? while ind < n: # Check for a 1x1 block and diagonalize it - if (ind == (n-1)) or (self[ind, ind+1] == 0): + if ind == n - 1 or self[ind, ind + 1] == 0: tmp_diag_vec[ind] = self[ind, ind] ind += 1 # Diagonalize the 2x2 block else: - B = self[ind, ind+1] - if (B % 2 != 0): + B = self[ind, ind + 1] + if B % 2: raise RuntimeError("we expected the mixed term to be even") a = self[ind, ind] - b = ZZ(B / ZZ(2)) - c = self[ind+1, ind+1] + b = B // ZZ(2) + c = self[ind + 1, ind + 1] tmp_disc = b * b - a * c # Perform the diagonalization - if (tmp_disc % 8 == 1): # 2xy + if tmp_disc % 8 == 1: # 2xy tmp_diag_vec[ind] = 1 - tmp_diag_vec[ind+1] = -1 + tmp_diag_vec[ind + 1] = -1 ind += 2 - elif(tmp_disc % 8 == 5): # 2x^2 + 2xy + 2y^2 - tmp_diag_vec[0] = 3*u + elif tmp_disc % 8 == 5: # 2x^2 + 2xy + 2y^2 + tmp_diag_vec[0] = 3 * u tmp_diag_vec[ind] = -u - tmp_diag_vec[ind+1] = -u + tmp_diag_vec[ind + 1] = -u ind += 2 u = tmp_diag_vec[0] else: @@ -404,25 +389,22 @@ def conway_octane_of_this_unimodular_Jordan_block_at_2(self): def conway_diagonal_factor(self, p): - """ - Computes the diagonal factor of Conway's `p`-mass. + r""" + Compute the diagonal factor of Conway's `p`-mass. INPUT: - `p` -- a prime number > 0 + - ``p`` -- a prime number > 0 - OUTPUT: - - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, range(1,6)) sage: Q.conway_diagonal_factor(3) 81/256 - """ - # Get the species list at p + # Get the species list at p if p == 2: species_list = self.conway_species_list_at_2() else: @@ -434,9 +416,11 @@ def conway_diagonal_factor(self, p): if s == 0: pass elif s % 2 == 1: # Note: Here always s > 0. - diag_factor = diag_factor / (2 * prod([1 - QQ(p)**(-i) for i in range(2, s, 2)])) + diag_factor = diag_factor / (2 * prod([1 - QQ(p)**(-i) + for i in range(2, s, 2)])) else: - diag_factor = diag_factor / (2 * prod([1 - QQ(p)**(-i) for i in range(2, abs(s), 2)])) + diag_factor = diag_factor / (2 * prod([1 - QQ(p)**(-i) + for i in range(2, abs(s), 2)])) s_sign = ZZ(s / abs(s)) diag_factor = diag_factor / (ZZ(1) - s_sign * QQ(p) ** ZZ(-abs(s) / ZZ(2))) @@ -445,17 +429,15 @@ def conway_diagonal_factor(self, p): def conway_cross_product_doubled_power(self, p): - """ - Computes twice the power of p which evaluates the 'cross product' + r""" + Compute twice the power of `p` which evaluates the 'cross product' term in Conway's mass formula. INPUT: - `p` -- a prime number > 0 + - ``p`` -- a prime number > 0 - OUTPUT: - - a rational number + OUTPUT: a rational number EXAMPLES:: @@ -473,52 +455,41 @@ def conway_cross_product_doubled_power(self, p): sage: Q.conway_cross_product_doubled_power(13) 0 """ - doubled_power = 0 - dim_list = [J.dim() for J in self.jordan_blocks_in_unimodular_list_by_scale_power(p)] - for i in range(len(dim_list)): - for j in range(i): - doubled_power += (i-j) * dim_list[i] * dim_list[j] - - return doubled_power + dim_list = [J.dim() for J in self.jordan_blocks_in_unimodular_list_by_scale_power(p)] + return sum((i - j) * dimi * dim_list[j] + for i, dimi in enumerate(dim_list) + for j in range(i)) def conway_type_factor(self): - """ + r""" This is a special factor only present in the mass formula when `p=2`. - INPUT: - - none - - OUTPUT: - - a rational number + OUTPUT: a rational number EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, range(1,8)) sage: Q.conway_type_factor() 4 - """ jordan_list = self.jordan_blocks_in_unimodular_list_by_scale_power(2) - n2 = sum([J.dim() for J in jordan_list if J.is_even()]) - n11 = sum([1 for i in range(len(jordan_list) - 1) if jordan_list[i].is_odd() and jordan_list[i+1].is_odd()]) + n2 = sum([J.dim() for J in jordan_list if J.is_even()]) + n11 = sum([1 for i in range(len(jordan_list) - 1) + if jordan_list[i].is_odd() and jordan_list[i + 1].is_odd()]) return ZZ(2)**(n11 - n2) def conway_p_mass(self, p): - """ - Computes Conway's `p`-mass. + r""" + Compute Conway's `p`-mass. INPUT: - `p` -- a prime number > 0 - - OUTPUT: + - ``p`` -- a prime number > 0 - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: @@ -527,7 +498,6 @@ def conway_p_mass(self, p): 16/3 sage: Q.conway_p_mass(3) 729/256 - """ # Compute the first two factors of the p-mass p_mass = self.conway_diagonal_factor(p) * (p ** (self.conway_cross_product_doubled_power(p) / ZZ(2))) @@ -541,109 +511,103 @@ def conway_p_mass(self, p): def conway_standard_p_mass(self, p): - """ - Computes the standard (generic) Conway-Sloane `p`-mass. + r""" + Compute the standard (generic) Conway-Sloane `p`-mass. INPUT: - `p` -- a prime number > 0 - - OUTPUT: + - ``p`` -- a prime number > 0 - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.conway_standard_p_mass(2) 2/3 - """ # Some useful variables n = self.dim() if n % 2 == 0: s = n // 2 else: - s = (n+1) // 2 + s = (n + 1) // 2 # Compute the inverse of the generic p-mass - p_mass_inv = 2 * prod([1-p**(-i) for i in range(2, 2*s, 2)]) + p_mass_inv = 2 * prod([1 - p**(-i) for i in range(2, 2 * s, 2)]) if n % 2 == 0: - D = (-1)**s * self.det() * (2**n) # We should have something like D = (-1)**s * self.det() / (2**n), but that's not an integer and here we only care about the square-class. - #d = self.det() # Note: No normalizing power of 2 is needed since the power is even. - #if not ((p == 2) or (d % p == 0)): + D = (-1)**s * self.det() * (2**n) + # We should have something like D = (-1)**s * self.det() / (2**n), but that's not an integer and here we only care about the square-class. + # d = self.det() # Note: No normalizing power of 2 is needed since the power is even. + # if not ((p == 2) or (d % p == 0)): p_mass_inv *= (1 - kronecker_symbol(fundamental_discriminant(D), p) * p**(-s)) # Return the standard p-mass - return ZZ(1) / p_mass_inv + return ZZ.one() / p_mass_inv def conway_standard_mass(self): - """ - Returns the infinite product of the standard mass factors. - - INPUT: + r""" + Return the infinite product of the standard mass factors. - none - - OUTPUT: - - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [2, -2, 0, 3, -5, 4]) - sage: Q.conway_standard_mass() + sage: Q.conway_standard_mass() # needs sage.symbolic 1/6 :: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: Q.conway_standard_mass() + sage: Q.conway_standard_mass() # needs sage.symbolic 1/6 - """ + from sage.quadratic_forms.special_values import gamma__exact, zeta__exact, quadratic_L_function__exact + from sage.symbolic.constants import pi + n = self.dim() if n % 2 == 0: s = n // 2 else: - s = (n+1) // 2 + s = (n + 1) // 2 - generic_mass = 2 * pi**((-1) * n * (n+1) / ZZ(4)) \ - * prod([gamma__exact(j / ZZ(2)) for j in range(1, n+1)]) \ - * prod([zeta__exact(2*k) for k in range(1, s)]) + generic_mass = 2 * pi**((-1) * n * (n + 1) / ZZ(4)) \ + * prod([gamma__exact(j / ZZ(2)) for j in range(1, n + 1)]) \ + * prod([zeta__exact(2 * k) for k in range(1, s)]) if n % 2 == 0: - D = (-1)**s * self.det() * (2**n) # We should have something like D = (-1)**s * self.det() / (2**n), but that's not an integer and here we only care about the square-class. + D = (-1)**s * self.det() * (2**n) + # We should have something like D = (-1)**s * self.det() / (2**n), but + # that's not an integer and here we only care about the square-class. generic_mass *= quadratic_L_function__exact(s, D) return generic_mass def conway_mass(self): - """ + r""" Compute the mass by using the Conway-Sloane mass formula. - OUTPUT: - - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: Q.conway_mass() + sage: Q.conway_mass() # needs sage.symbolic 1/48 sage: Q = DiagonalQuadraticForm(ZZ, [7,1,1]) - sage: Q.conway_mass() + sage: Q.conway_mass() # needs sage.symbolic 3/16 sage: Q = QuadraticForm(ZZ, 3, [7, 2, 2, 2, 0, 2]) + DiagonalQuadraticForm(ZZ, [1]) - sage: Q.conway_mass() + sage: Q.conway_mass() # needs sage.symbolic 3/32 - sage: Q = QuadraticForm(Matrix(ZZ,2,[2,1,1,2])) - sage: Q.conway_mass() + sage: Q = QuadraticForm(Matrix(ZZ, 2, [2,1,1,2])) + sage: Q.conway_mass() # needs sage.symbolic 1/12 """ # Try to use the cached result @@ -658,7 +622,7 @@ def conway_mass(self): # Adjust the p-masses when p|2d d = self.det() - for p in prime_divisors(2*d): + for p in prime_divisors(2 * d): mass *= (Q.conway_p_mass(p) / Q.conway_standard_p_mass(p)) # Cache and return the (simplified) result @@ -666,7 +630,7 @@ def conway_mass(self): return self.__conway_mass -#def conway_generic_mass(self): +# def conway_generic_mass(self): # """ # Computes the generic mass given as # 2 \pi^{-n(n+1)/4} \prod_{j=1}^{n} \Gamma\(\tfrac{j}{2}\) @@ -701,10 +665,3 @@ def conway_mass(self): # # # Return the answer # return ans - - -#def conway_p_mass_adjustment(self, p): -# """ -# Computes the adjustment to give the p-mass from the generic mass. -# """ -# pass diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py index 97b07023060..a99eb439e0f 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py @@ -2,7 +2,7 @@ Local Masses and Siegel Densities """ ######################################################################## -# Computes the local masses (rep'n densities of a form by itself) for a quadratic forms over ZZ +# Computes the local masses (rep'n densities of a form by itself) for a quadratic form over ZZ # using the papers of Pall [PSPUM VIII (1965), pp95--105] for p>2, and Watson [Mathematika # 23, no. 1, (1976), pp 94--106] for p=2. These formulas will also work for any local field # which is unramified at p=2. @@ -10,79 +10,82 @@ # Copyright by Jonathan Hanke 2007 <jonhanke@gmail.com> ######################################################################## -import copy +from copy import deepcopy +from sage.arith.misc import kronecker, legendre_symbol, prime_divisors +from sage.matrix.matrix_space import MatrixSpace +from sage.misc.functional import squarefree_part from sage.misc.misc_c import prod from sage.misc.mrange import mrange -from sage.rings.integer_ring import ZZ +from sage.quadratic_forms.special_values import gamma__exact, zeta__exact, quadratic_L_function__exact from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.arith.all import legendre_symbol, kronecker, prime_divisors -from sage.functions.all import sgn -from sage.quadratic_forms.special_values import gamma__exact, zeta__exact, quadratic_L_function__exact -from sage.misc.functional import squarefree_part -from sage.symbolic.constants import pi -from sage.matrix.matrix_space import MatrixSpace def mass__by_Siegel_densities(self, odd_algorithm="Pall", even_algorithm="Watson"): """ - Gives the mass of transformations (det 1 and -1). + Return the mass of transformations (det 1 and -1). + + .. WARNING:: - WARNING: THIS IS BROKEN RIGHT NOW... =( + This is broken right now... - Optional Arguments: + INPUT: - - When p > 2 -- odd_algorithm = "Pall" (only one choice for now) - - When p = 2 -- even_algorithm = "Kitaoka" or "Watson" + - ``odd_algorithm`` -- algorithm to be used when `p>2`; ``"Pall"`` (only one choice for now) + - ``even_algorithm`` -- algorithm to be used when `p=2`; + either ``"Kitaoka"`` or ``"Watson"`` (the default) REFERENCES: - Nipp's Book "Tables of Quaternary Quadratic Forms". - - Papers of Pall (only for p>2) and Watson (for `p=2` -- tricky!). + - Papers of Pall (only for `p>2`) and Watson (for `p=2` -- tricky!). - Siegel, Milnor-Hussemoller, Conway-Sloane Paper IV, Kitoaka (all of which have problems...) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) - sage: m = Q.mass__by_Siegel_densities(); m + sage: m = Q.mass__by_Siegel_densities(); m # needs sage.symbolic 1/384 - sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1) + sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1) # needs sage.symbolic 0 :: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: m = Q.mass__by_Siegel_densities(); m + sage: m = Q.mass__by_Siegel_densities(); m # needs sage.symbolic 1/48 - sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1) + sage: m - (2^Q.dim() * factorial(Q.dim()))^(-1) # needs sage.symbolic 0 """ + from sage.symbolic.constants import pi + # Setup n = self.dim() - s = (n-1) // 2 + s = (n - 1) // 2 if n % 2 != 0: - char_d = squarefree_part(2*self.det()) # Accounts for the det as a QF + char_d = squarefree_part(2 * self.det()) # Accounts for the det as a QF else: char_d = squarefree_part(self.det()) # Form the generic zeta product - generic_prod = ZZ(2) * (pi)**(-ZZ(n) * (n+1) / 4) + generic_prod = ZZ(2) * (pi)**(-ZZ(n) * (n + 1) / 4) ########################################## - generic_prod *= (self.det())**(ZZ(n+1)/2) # ***** This uses the Hessian Determinant ******** + generic_prod *= self.det()**(ZZ(n + 1) / 2) # ***** This uses the Hessian Determinant ******** ########################################## - generic_prod *= prod([gamma__exact(ZZ(j)/2) for j in range(1,n+1)]) - generic_prod *= prod([zeta__exact(ZZ(j)) for j in range(2, 2*s+1, 2)]) - if (n % 2 == 0): - generic_prod *= quadratic_L_function__exact(n//2, ZZ(-1)**(n//2) * char_d) + generic_prod *= prod([gamma__exact(ZZ(j) / 2) for j in range(1, n + 1)]) + generic_prod *= prod([zeta__exact(ZZ(j)) for j in range(2, 2 * s + 1, 2)]) + if n % 2 == 0: + generic_prod *= quadratic_L_function__exact(n // 2, ZZ(-1)**(n // 2) * char_d) # Determine the adjustment factors adj_prod = ZZ.one() for p in prime_divisors(2 * self.det()): # Cancel out the generic factors - p_adjustment = prod([1 - ZZ(p)**(-j) for j in range(2, 2*s+1, 2)]) - if (n % 2 == 0): - p_adjustment *= (1 - kronecker((-1)**(n//2) * char_d, p) * ZZ(p)**(-n//2)) + p_adjustment = prod([1 - ZZ(p)**(-j) for j in range(2, 2 * s + 1, 2)]) + if n % 2 == 0: + p_adjustment *= (1 - kronecker((-1)**(n // 2) * char_d, p) * ZZ(p)**(-n // 2)) # Insert the new mass factors if p == 2: if even_algorithm == "Kitaoka": @@ -101,7 +104,7 @@ def mass__by_Siegel_densities(self, odd_algorithm="Pall", even_algorithm="Watson adj_prod *= p_adjustment # Extra adjustment for the case of a 2-dimensional form. - #if (n == 2): + # if (n == 2): # generic_prod *= 2 # Return the mass @@ -110,22 +113,20 @@ def mass__by_Siegel_densities(self, odd_algorithm="Pall", even_algorithm="Watson def Pall_mass_density_at_odd_prime(self, p): - """ - Returns the local representation density of a form (for - representing itself) defined over `ZZ`, at some prime `p>2`. + r""" + Return the local representation density of a form (for + representing itself) defined over `\ZZ`, at some prime `p>2`. REFERENCES: - Pall's article "The Weight of a Genus of Positive n-ary Quadratic Forms" - appearing in Proc. Symp. Pure Math. VIII (1965), pp95--105. + Pall's article "The Weight of a Genus of Positive n-ary Quadratic Forms" + appearing in Proc. Symp. Pure Math. VIII (1965), pp95--105. INPUT: - `p` -- a prime number > 2. - - OUTPUT: + - ``p`` -- a prime number > 2 - a rational number. + OUTPUT: a rational number. EXAMPLES:: @@ -144,25 +145,24 @@ def Pall_mass_density_at_odd_prime(self, p): # Step 1: Obtain a p-adic (diagonal) local normal form, and # compute the invariants for each Jordan block. jordan_list = self.jordan_blocks_by_scale_and_unimodular(p) - modified_jordan_list = [(a, Q.dim(), Q.det()) for (a,Q) in jordan_list] # List of pairs (scale, det) + modified_jordan_list = [(a, Q.dim(), Q.det()) for a, Q in jordan_list] # List of pairs (scale, det) # Step 2: Compute the list of local masses for each Jordan block jordan_mass_list = [] - for (s,n,d) in modified_jordan_list: - generic_factor = prod([1 - p**(-2*j) for j in range(1, (n-1)//2+1)]) - if (n % 2 == 0): - m = n/2 + for (s, n, d) in modified_jordan_list: + generic_factor = prod([1 - p**(-2 * j) for j in range(1, (n - 1) // 2 + 1)]) + if n % 2 == 0: + m = n // 2 generic_factor *= (1 + legendre_symbol(((-1)**m) * d, p) * p**(-m)) jordan_mass_list = jordan_mass_list + [generic_factor] - # Step 3: Compute the local mass $\al_p$ at p. MJL = modified_jordan_list s = len(modified_jordan_list) - M = [sum([MJL[j][1] for j in range(i, s)]) for i in range(s-1)] # Note: It's s-1 since we don't need the last M. - nu = sum([M[i] * MJL[i][0] * MJL[i][1] for i in range(s-1)]) - ZZ(sum([J[0] * J[1] * (J[1]-1) for J in MJL]))/ZZ(2) + M = [sum([MJL[j][1] for j in range(i, s)]) for i in range(s - 1)] # Note: It's s-1 since we don't need the last M. + nu = sum([M[i] * MJL[i][0] * MJL[i][1] for i in range(s - 1)]) - ZZ(sum([J[0] * J[1] * (J[1] - 1) for J in MJL])) / ZZ(2) p_mass = prod(jordan_mass_list) - p_mass *= 2**(s-1) * p**nu + p_mass *= 2**(s - 1) * p**nu print(jordan_list, MJL, jordan_mass_list, p_mass) @@ -172,73 +172,69 @@ def Pall_mass_density_at_odd_prime(self, p): def Watson_mass_at_2(self): """ - Returns the local mass of the quadratic form when `p=2`, according + Return the local mass of the quadratic form when `p=2`, according to Watson's Theorem 1 of "The 2-adic density of a quadratic form" in Mathematika 23 (1976), pp 94--106. - INPUT: - - none - - OUTPUT: - - a rational number + OUTPUT: a rational number EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) - sage: Q.Watson_mass_at_2() # WARNING: WE NEED TO CHECK THIS CAREFULLY! + sage: Q.Watson_mass_at_2() # WARNING: WE NEED TO CHECK THIS CAREFULLY! # needs sage.symbolic 384 - """ + from sage.functions.all import sgn + # Make a 0-dim'l quadratic form (for initialization purposes) - Null_Form = copy.deepcopy(self) + Null_Form = deepcopy(self) Null_Form.__init__(ZZ, 0) # Step 0: Compute Jordan blocks and bounds of the scales to keep track of Jordan_Blocks = self.jordan_blocks_by_scale_and_unimodular(2) - scale_list = [B[0] for B in Jordan_Blocks] + scale_list = [B[0] for B in Jordan_Blocks] s_min = min(scale_list) s_max = max(scale_list) # Step 1: Compute dictionaries of the diagonal block and 2x2 block for each scale - diag_dict = dict((i, Null_Form) for i in range(s_min-2, s_max + 4)) # Initialize with the zero form - dim2_dict = dict((i, Null_Form) for i in range(s_min, s_max + 4)) # Initialize with the zero form - for (s,L) in Jordan_Blocks: + diag_dict = dict((i, Null_Form) for i in range(s_min - 2, s_max + 4)) # Initialize with the zero form + dim2_dict = dict((i, Null_Form) for i in range(s_min, s_max + 4)) # Initialize with the zero form + for s, L in Jordan_Blocks: i = 0 - while (i < L.dim()-1) and (L[i,i+1] == 0): # Find where the 2x2 blocks start - i = i + 1 - if i < (L.dim() - 1): + while i < L.dim() - 1 and L[i, i + 1] == 0: # Find where the 2x2 blocks start + i += 1 + if i < L.dim() - 1: diag_dict[s] = L.extract_variables(range(i)) # Diagonal Form - dim2_dict[s+1] = L.extract_variables(range(i, L.dim())) # Non-diagonal Form + dim2_dict[s + 1] = L.extract_variables(range(i, L.dim())) # Non-diagonal Form else: diag_dict[s] = L # Step 2: Compute three dictionaries of invariants (for n_j, m_j, nu_j) - n_dict = dict((j,0) for j in range(s_min+1, s_max+2)) - m_dict = dict((j,0) for j in range(s_min, s_max+4)) - for (s,L) in Jordan_Blocks: - n_dict[s+1] = L.dim() + n_dict = dict((j, 0) for j in range(s_min + 1, s_max + 2)) + m_dict = dict((j, 0) for j in range(s_min, s_max + 4)) + for s, L in Jordan_Blocks: + n_dict[s + 1] = L.dim() if diag_dict[s].dim() == 0: - m_dict[s+1] = ZZ.one()/ZZ(2) * L.dim() + m_dict[s + 1] = ZZ.one() / ZZ(2) * L.dim() else: - m_dict[s+1] = ZZ(L.dim() - 1) // ZZ(2) + m_dict[s + 1] = ZZ(L.dim() - 1) // ZZ(2) - nu_dict = dict((j,n_dict[j+1] - 2*m_dict[j+1]) for j in range(s_min, s_max+1)) - nu_dict[s_max+1] = 0 + nu_dict = dict((j, n_dict[j + 1] - 2 * m_dict[j + 1]) + for j in range(s_min, s_max + 1)) + nu_dict[s_max + 1] = 0 # Step 3: Compute the e_j dictionary eps_dict = {} - for j in range(s_min, s_max+3): - two_form = (diag_dict[j-2] + diag_dict[j] + dim2_dict[j]).scale_by_factor(2) - j_form = (two_form + diag_dict[j-1]).base_change_to(IntegerModRing(4)) + for j in range(s_min, s_max + 3): + two_form = (diag_dict[j - 2] + diag_dict[j] + dim2_dict[j]).scale_by_factor(2) + j_form = (two_form + diag_dict[j - 1]).change_ring(IntegerModRing(4)) if j_form.dim() == 0: eps_dict[j] = 1 else: iter_vec = [4] * j_form.dim() - alpha = sum([True for x in mrange(iter_vec) if j_form(x) == 0]) - beta = sum([True for x in mrange(iter_vec) if j_form(x) == 2]) + alpha = sum(1 for x in mrange(iter_vec) if j_form(x) == 0) + beta = sum(1 for x in mrange(iter_vec) if j_form(x) == 2) if alpha > beta: eps_dict[j] = 1 elif alpha == beta: @@ -248,10 +244,10 @@ def Watson_mass_at_2(self): # Step 4: Compute the quantities nu, q, P, E for the local mass at 2 nu = sum([j * n_dict[j] * (ZZ(n_dict[j] + 1) / ZZ(2) + - sum([n_dict[r] for r in range(j+1, s_max+2)])) for j in range(s_min+1, s_max+2)]) - q = sum([sgn(nu_dict[j-1] * (n_dict[j] + sgn(nu_dict[j]))) for j in range(s_min+1, s_max+2)]) - P = prod([prod([1 - QQ(4)**(-k) for k in range(1, m_dict[j]+1)]) for j in range(s_min+1, s_max+2)]) - E = prod([ZZ(1)/ZZ(2) * (1 + eps_dict[j] * QQ(2)**(-m_dict[j])) for j in range(s_min, s_max+3)]) + sum([n_dict[r] for r in range(j + 1, s_max + 2)])) for j in range(s_min + 1, s_max + 2)]) + q = sum([sgn(nu_dict[j - 1] * (n_dict[j] + sgn(nu_dict[j]))) for j in range(s_min + 1, s_max + 2)]) + P = prod([prod([1 - QQ(4)**(-k) for k in range(1, m_dict[j] + 1)]) for j in range(s_min + 1, s_max + 2)]) + E = prod([ZZ(1) / ZZ(2) * (1 + eps_dict[j] * QQ(2)**(-m_dict[j])) for j in range(s_min, s_max + 3)]) # Step 5: Compute the local mass for the prime 2. mass_at_2 = QQ(2)**(nu - q) * P / E @@ -260,17 +256,11 @@ def Watson_mass_at_2(self): def Kitaoka_mass_at_2(self): """ - Returns the local mass of the quadratic form when `p=2`, according + Return the local mass of the quadratic form when `p=2`, according to Theorem 5.6.3 on pp108--9 of Kitaoka's Book "The Arithmetic of Quadratic Forms". - INPUT: - - none - - OUTPUT: - - a rational number > 0 + OUTPUT: a rational number > 0 EXAMPLES:: @@ -280,35 +270,35 @@ def Kitaoka_mass_at_2(self): """ # Make a 0-dim'l quadratic form (for initialization purposes) - Null_Form = copy.deepcopy(self) + Null_Form = deepcopy(self) Null_Form.__init__(ZZ, 0) # Step 0: Compute Jordan blocks and bounds of the scales to keep track of Jordan_Blocks = self.jordan_blocks_by_scale_and_unimodular(2) - scale_list = [B[0] for B in Jordan_Blocks] + scale_list = [B[0] for B in Jordan_Blocks] s_min = min(scale_list) s_max = max(scale_list) # Step 1: Compute dictionaries of the diagonal block and 2x2 block for each scale - diag_dict = dict((i, Null_Form) for i in range(s_min-2, s_max + 4)) # Initialize with the zero form - dim2_dict = dict((i, Null_Form) for i in range(s_min, s_max + 4)) # Initialize with the zero form - for (s,L) in Jordan_Blocks: + diag_dict = dict((i, Null_Form) for i in range(s_min - 2, s_max + 4)) # Initialize with the zero form + dim2_dict = dict((i, Null_Form) for i in range(s_min, s_max + 4)) # Initialize with the zero form + for s, L in Jordan_Blocks: i = 0 - while (i < L.dim()-1) and (L[i,i+1] == 0): # Find where the 2x2 blocks start - i = i + 1 - if i < (L.dim() - 1): + while i < L.dim() - 1 and L[i, i + 1] == 0: # Find where the 2x2 blocks start + i += 1 + if i < L.dim() - 1: diag_dict[s] = L.extract_variables(range(i)) # Diagonal Form - dim2_dict[s+1] = L.extract_variables(range(i, L.dim())) # Non-diagonal Form + dim2_dict[s + 1] = L.extract_variables(range(i, L.dim())) # Non-diagonal Form else: diag_dict[s] = L - ################# START EDITING HERE ################## + # ################ START EDITING HERE ################## # Compute q := sum of the q_j q = 0 for j in range(s_min, s_max + 1): if diag_dict[j].dim() > 0: # Check that N_j is odd (i.e. rep'ns an odd #) - if diag_dict[j+1].dim() == 0: + if diag_dict[j + 1].dim() == 0: q += Jordan_Blocks[j][1].dim() # When N_{j+1} is "even", add n_j else: q += Jordan_Blocks[j][1].dim() + 1 # When N_{j+1} is "odd", add n_j + 1 @@ -322,8 +312,8 @@ def Kitaoka_mass_at_2(self): # Compute the product E := prod_j (1 / E_j) E = QQ.one() for j in range(s_min - 1, s_max + 2): - if (diag_dict[j-1].dim() == 0) and (diag_dict[j+1].dim() == 0) and \ - ((diag_dict[j].dim() != 2) or (((diag_dict[j][0,0] - diag_dict[j][1,1]) % 4) != 0)): + if (diag_dict[j - 1].dim() == 0) and (diag_dict[j + 1].dim() == 0) and \ + ((diag_dict[j].dim() != 2) or (((diag_dict[j][0, 0] - diag_dict[j][1, 1]) % 4) != 0)): # Deal with the complicated case: tmp_m = dim2_dict[j].dim() // 2 @@ -337,9 +327,9 @@ def Kitaoka_mass_at_2(self): # Compute the exponent w w = QQ.zero() - for j in range(s_min, s_max+1): + for j in range(s_min, s_max + 1): n_j = Jordan_Blocks[j][1].dim() - for k in range(j+1, s_max+1): + for k in range(j + 1, s_max + 1): n_k = Jordan_Blocks[k][1].dim() w += j * n_j * (n_k + QQ(n_j + 1) / 2) @@ -349,10 +339,12 @@ def Kitaoka_mass_at_2(self): def mass_at_two_by_counting_mod_power(self, k): - """ - Computes the local mass at `p=2` assuming that it's stable `(mod 2^k)`. + r""" + Compute the local mass at `p=2` assuming that it's stable (mod `2^k`). + + .. NOTE:: - Note: This is **way** too slow to be useful, even when k=1!!! + This is **way** too slow to be useful, even when `k=1`. .. TODO:: @@ -360,11 +352,9 @@ def mass_at_two_by_counting_mod_power(self, k): INPUT: - - k -- an integer >= 1 - - OUTPUT: + - ``k`` -- an integer `\geq 1` - a rational number + OUTPUT: a rational number EXAMPLES:: @@ -373,10 +363,9 @@ def mass_at_two_by_counting_mod_power(self, k): 4 """ R = IntegerModRing(2**k) - Q1 = self.base_change_to(R) + Q1 = self.change_ring(R) n = self.dim() MS = MatrixSpace(R, n) - ct = sum([1 for x in mrange([2**k] * (n**2)) if Q1(MS(x)) == Q1]) # Count the solutions mod 2^k - two_mass = ZZ(1)/2 * (ZZ(ct) / ZZ(2)**(k*n*(n-1)/2)) - return two_mass + ct = sum(1 for x in mrange([2**k] * (n**2)) if Q1(MS(x)) == Q1) # Count the solutions mod 2^k + return ZZ.one() / 2 * (ZZ(ct) / ZZ(2)**(k * n * (n - 1) / 2)) diff --git a/src/sage/quadratic_forms/quadratic_form__neighbors.py b/src/sage/quadratic_forms/quadratic_form__neighbors.py index 96a5203101d..94f6559d51a 100644 --- a/src/sage/quadratic_forms/quadratic_form__neighbors.py +++ b/src/sage/quadratic_forms/quadratic_form__neighbors.py @@ -4,7 +4,7 @@ from sage.modules.free_module_element import vector from sage.rings.integer_ring import ZZ -from sage.rings.all import GF, QQ +from sage.rings.rational_field import QQ from copy import deepcopy from sage.matrix.constructor import matrix @@ -31,7 +31,7 @@ def find_primitive_p_divisible_vector__random(self, p): True sage: 5.divides(Q(v)) True - sage: Q = QuadraticForm(QQ,matrix.diagonal([1,1,1,1])) + sage: Q = QuadraticForm(QQ, matrix.diagonal([1,1,1,1])) sage: v = Q.find_primitive_p_divisible_vector__random(2) sage: Q(v) 2 @@ -59,14 +59,12 @@ def find_primitive_p_divisible_vector__next(self, p, v=None): value is `p`-divisible, where the last vector returned was `v`. For an initial call, no `v` needs to be passed. - Returns vectors whose last non-zero entry is normalized to 0 or 1 (so no + Return vectors whose last non-zero entry is normalized to 0 or 1 (so no lines are counted repeatedly). The ordering is by increasing the first non-normalized entry. If we have tested all (lines of) vectors, then return None. - OUTPUT: - - vector or None + OUTPUT: vector or None EXAMPLES:: @@ -76,7 +74,7 @@ def find_primitive_p_divisible_vector__next(self, p, v=None): sage: v = Q.find_primitive_p_divisible_vector__next(5, v); v (1, 0) sage: v = Q.find_primitive_p_divisible_vector__next(5, v); v - sage: Q = QuadraticForm(QQ,matrix.diagonal([1,1,1,1])) + sage: Q = QuadraticForm(QQ, matrix.diagonal([1,1,1,1])) sage: v = Q.find_primitive_p_divisible_vector__next(2) sage: Q(v) 2 @@ -133,6 +131,7 @@ def find_primitive_p_divisible_vector__next(self, p, v=None): if a in ZZ and (a % p == 0): return w + def find_p_neighbor_from_vec(self, p, y): r""" Return the `p`-neighbor of ``self`` defined by ``y``. @@ -146,14 +145,14 @@ def find_p_neighbor_from_vec(self, p, y): INPUT: - ``p`` -- a prime number - - ``y`` -- a vector with `q(y) \in p \ZZ`. - - ``odd`` -- (default=``False``) if `p=2` return also odd neighbors + - ``y`` -- a vector with `q(y) \in p \ZZ` + - ``odd`` -- (default: ``False``) if `p=2`, return also odd neighbors EXAMPLES:: - sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1]) + sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: v = vector([0,2,1,1]) - sage: X = Q.find_p_neighbor_from_vec(3,v); X + sage: X = Q.find_p_neighbor_from_vec(3, v); X # needs sage.libs.pari Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 0 0 ] [ * 1 4 4 ] @@ -162,11 +161,11 @@ def find_p_neighbor_from_vec(self, p, y): Since the base ring and the domain are not yet separate, for rational, half integral forms we just pretend - the base ring is `ZZ`:: + the base ring is `\ZZ`:: - sage: Q = QuadraticForm(QQ,matrix.diagonal([1,1,1,1])) + sage: Q = QuadraticForm(QQ, matrix.diagonal([1,1,1,1])) sage: v = vector([1,1,1,1]) - sage: Q.find_p_neighbor_from_vec(2,v) + sage: Q.find_p_neighbor_from_vec(2, v) # needs sage.libs.pari Quadratic form in 4 variables over Rational Field with coefficients: [ 1/2 1 1 1 ] [ * 1 1 2 ] @@ -175,9 +174,12 @@ def find_p_neighbor_from_vec(self, p, y): """ p = ZZ(p) if not p.divides(self(y)): - raise ValueError("y=%s must be of square divisible by p=%s"%(y,p)) + raise ValueError("y=%s must be of square divisible by p=%s" % (y, p)) if self.base_ring() not in [ZZ, QQ]: raise NotImplementedError("the base ring of this form must be the integers or the rationals") + + from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + n = self.dim() G = self.Hessian_matrix() R = self.base_ring() @@ -196,14 +198,14 @@ def find_p_neighbor_from_vec(self, p, y): z = (ZZ**n).gen(k) break else: - raise ValueError("either y is not primitive or self is not maximal at %s"%p) + raise ValueError("either y is not primitive or self is not maximal at %s" % p) z *= (2*y*G*z).inverse_mod(p) y = y - b*z # assert y*G*y % p^2 == 0 if p == 2: val = b.valuation(p) if val <= 1: - raise ValueError("y=%s must be of square divisible by 2"%y) + raise ValueError("y=%s must be of square divisible by 2" % y) if val == 2 and not odd: # modify it to have square 4 for k in range(n): @@ -236,7 +238,7 @@ def neighbor_iteration(seeds, p, mass=None, max_classes=ZZ(10)**3, Return all classes in the `p`-neighbor graph of ``self``. Starting from the given seeds, this function successively - finds p-neighbors until no new quadratic form (class) is obtained. + finds `p`-neighbors until no new quadratic form (class) is obtained. INPUT: @@ -248,14 +250,12 @@ def neighbor_iteration(seeds, p, mass=None, max_classes=ZZ(10)**3, - ``max_classes`` -- (default: ``1000``) break the computation when ``max_classes`` are found - - ``algorithm`` -- (optional) one of 'orbits', 'random', 'exhaustion' + - ``algorithm`` -- (optional) one of ``'orbits'``, ``'random'``, ``'exhaustion'`` - ``max_random_trys`` -- (default: ``1000``) the maximum number of neighbors - computed for a single lattice - - OUTPUT: + computed for a single lattice - - a list of quadratic forms + OUTPUT: a list of quadratic forms EXAMPLES:: @@ -263,26 +263,31 @@ def neighbor_iteration(seeds, p, mass=None, max_classes=ZZ(10)**3, sage: Q = QuadraticForm(ZZ, 3, [1, 0, 0, 2, 1, 3]) sage: Q.det() 46 + + sage: # needs sage.symbolic sage: mass = Q.conway_mass() - sage: g1 = neighbor_iteration([Q],3, mass=mass, algorithm = 'random') # long time - sage: g2 = neighbor_iteration([Q],3, algorithm = 'exhaustion') # long time - sage: g3 = neighbor_iteration([Q],3, algorithm = 'orbits') - sage: mass == sum(1/q.number_of_automorphisms() for q in g1) # long time + sage: g1 = neighbor_iteration([Q], 3, # long time + ....: mass=mass, algorithm='random') + sage: g2 = neighbor_iteration([Q], 3, algorithm='exhaustion') # long time + sage: g3 = neighbor_iteration([Q], 3, algorithm='orbits') # needs sage.libs.gap + sage: mass == sum(1/q.number_of_automorphisms() for q in g1) # long time True - sage: mass == sum(1/q.number_of_automorphisms() for q in g2) # long time + sage: mass == sum(1/q.number_of_automorphisms() for q in g2) # long time True - sage: mass == sum(1/q.number_of_automorphisms() for q in g3) + sage: mass == sum(1/q.number_of_automorphisms() for q in g3) # needs sage.libs.gap True TESTS:: sage: from sage.quadratic_forms.quadratic_form__neighbors import neighbor_iteration sage: Q = QuadraticForm(ZZ, 3, [1, 0, 0, 2, 1, 3]) - sage: g = neighbor_iteration([Q],3,mass=Q.conway_mass(),max_classes=2) + sage: g = neighbor_iteration([Q], 3, mass=Q.conway_mass(), max_classes=2) # needs sage.symbolic ... - UserWarning: reached the maximum number of isometry classes=2. Increase the optional argument max_classes to obtain more. + UserWarning: reached the maximum number of isometry classes=2. + Increase the optional argument max_classes to obtain more. Warning: not all classes in the genus were found - sage: neighbor_iteration([Q], 3, mass=Q.conway_mass(), max_neighbors=0, algorithm='random') + sage: neighbor_iteration([Q], 3, # needs sage.symbolic + ....: mass=Q.conway_mass(), max_neighbors=0, algorithm='random') Warning: not all classes in the genus were found [] """ @@ -344,7 +349,7 @@ def p_divisible_vectors(Q, max_neighbors): break if len(isom_classes) >= max_classes: - warn("reached the maximum number of isometry classes=%s. Increase the optional argument max_classes to obtain more." %max_classes) + warn("reached the maximum number of isometry classes=%s. Increase the optional argument max_classes to obtain more." % max_classes) if mass is not None: assert mass_count <= mass @@ -352,6 +357,7 @@ def p_divisible_vectors(Q, max_neighbors): print("Warning: not all classes in the genus were found") return isom_classes + def orbits_lines_mod_p(self, p): r""" Let `(L, q)` be a lattice. This returns representatives of the @@ -361,24 +367,24 @@ def orbits_lines_mod_p(self, p): - ``p`` -- a prime number - OUTPUT: - - - a list of vectors over ``GF(p)`` + OUTPUT: a list of vectors over ``GF(p)`` EXAMPLES:: sage: from sage.quadratic_forms.quadratic_form__neighbors import orbits_lines_mod_p sage: Q = QuadraticForm(ZZ, 3, [1, 0, 0, 2, 1, 3]) - sage: Q.orbits_lines_mod_p(2) + sage: Q.orbits_lines_mod_p(2) # needs sage.libs.gap sage.libs.pari [(0, 0, 1), - (0, 1, 0), - (0, 1, 1), - (1, 0, 0), - (1, 0, 1), - (1, 1, 0), - (1, 1, 1)] + (0, 1, 0), + (0, 1, 1), + (1, 0, 0), + (1, 0, 1), + (1, 1, 0), + (1, 1, 1)] """ from sage.libs.gap.libgap import libgap + from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + # careful the self.automorphism_group() acts from the left # but in gap we act from the right!! --> transpose gens = self.automorphism_group().gens() diff --git a/src/sage/quadratic_forms/quadratic_form__reduction_theory.py b/src/sage/quadratic_forms/quadratic_form__reduction_theory.py index 16c89f6edf2..87323962097 100644 --- a/src/sage/quadratic_forms/quadratic_form__reduction_theory.py +++ b/src/sage/quadratic_forms/quadratic_form__reduction_theory.py @@ -3,10 +3,11 @@ """ from copy import deepcopy from sage.matrix.constructor import matrix -from sage.functions.all import floor +from sage.misc.lazy_import import lazy_import from sage.misc.mrange import mrange from sage.modules.free_module_element import vector from sage.rings.integer_ring import ZZ +lazy_import("sage.functions.all", "floor") def reduced_binary_form1(self): @@ -17,7 +18,7 @@ def reduced_binary_form1(self): EXAMPLES:: - sage: QuadraticForm(ZZ,2,[5,5,2]).reduced_binary_form1() + sage: QuadraticForm(ZZ, 2, [5,5,2]).reduced_binary_form1() # needs sage.symbolic ( Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 -1 ] @@ -26,29 +27,41 @@ def reduced_binary_form1(self): [ 0 -1] [ 1 1] ) + + TESTS:: + + sage: QuadraticForm(ZZ, 2, [4,-7,6]).reduced_binary_form1()[0] # needs sage.symbolic + Quadratic form in 2 variables over Integer Ring with coefficients: + [ 3 -1 ] + [ * 4 ] + + sage: QuadraticForm(ZZ, 3, [1,2,3,4,5,6]).reduced_binary_form1() # needs sage.symbolic + Traceback (most recent call last): + ... + TypeError: only available for binary forms """ if self.dim() != 2: - raise TypeError("This must be a binary form for now...") + raise TypeError("only available for binary forms") R = self.base_ring() interior_reduced_flag = False Q = deepcopy(self) - M = matrix(R, 2, 2, [1,0,0,1]) + M = matrix(R, 2, 2, [1, 0, 0, 1]) while not interior_reduced_flag: interior_reduced_flag = True # Arrange for a <= c - if Q[0,0] > Q[1,1]: - M_new = matrix(R,2,2,[0, -1, 1, 0]) + if Q[0, 0] > Q[1, 1]: + M_new = matrix(R, 2, 2, [0, -1, 1, 0]) Q = Q(M_new) M = M * M_new interior_reduced_flag = False # Arrange for |b| <= a - if abs(Q[0,1]) > Q[0,0]: - r = R(floor(round(Q[0,1]/(2*Q[0,0])))) - M_new = matrix(R,2,2,[1, -r, 0, 1]) + if abs(Q[0, 1]) > Q[0, 0]: + r = R(floor(round(Q[0, 1] / (2 * Q[0, 0])))) + M_new = matrix(R, 2, 2, [1, -r, 0, 1]) Q = Q(M_new) M = M * M_new interior_reduced_flag = False @@ -79,7 +92,7 @@ def reduced_binary_form(self): EXAMPLES:: - sage: QuadraticForm(ZZ,2,[5,5,2]).reduced_binary_form() + sage: QuadraticForm(ZZ, 2, [5,5,2]).reduced_binary_form() # needs sage.symbolic ( Quadratic form in 2 variables over Integer Ring with coefficients: [ 2 -1 ] @@ -93,37 +106,31 @@ def reduced_binary_form(self): n = self.dim() interior_reduced_flag = False Q = deepcopy(self) - M = matrix(R, n, n) - for i in range(n): - M[i,i] = 1 + M = matrix(R, n, n, 1) while not interior_reduced_flag: interior_reduced_flag = True # Arrange for (weakly) increasing diagonal entries for i in range(n): - for j in range(i+1,n): - if Q[i,i] > Q[j,j]: - M_new = matrix(R,n,n) - for k in range(n): - M_new[k,k] = 1 - M_new[i,j] = -1 - M_new[j,i] = 1 - M_new[i,i] = 0 - M_new[j,j] = 1 + for j in range(i + 1, n): + if Q[i, i] > Q[j, j]: + M_new = matrix(R, n, n, 1) + M_new[i, j] = -1 + M_new[j, i] = 1 + M_new[i, i] = 0 + M_new[j, j] = 1 Q = Q(M_new) M = M * M_new interior_reduced_flag = False # Arrange for |b| <= a - if abs(Q[i,j]) > Q[i,i]: - r = R(floor(round(Q[i,j]/(2*Q[i,i])))) + if abs(Q[i, j]) > Q[i, i]: + r = R(floor(round(Q[i, j] / (2 * Q[i, i])))) - M_new = matrix(R,n,n) - for k in range(n): - M_new[k,k] = 1 - M_new[i,j] = -r + M_new = matrix(R, n, n, 1) + M_new[i, j] = -r Q = Q(M_new) M = M * M_new @@ -133,28 +140,30 @@ def reduced_binary_form(self): def minkowski_reduction(self): - """ + r""" Find a Minkowski-reduced form equivalent to the given one. + This means that .. MATH:: - Q(v_k) <= Q(s_1 * v_1 + ... + s_n * v_n) + Q(v_k) \leq Q(s_1\cdot v_1 + ... + s_n\cdot v_n) - for all `s_i` where GCD`(s_k, ... s_n) = 1`. + for all `s_i` where `\gcd(s_k, ... s_n) = 1`. - Note: When Q has dim <= 4 we can take all `s_i` in {1, 0, -1}. + .. NOTE:: - References: + When `Q` has dim `\leq 4` we can take all `s_i` in `\{1, 0, -1\}`. - Schulze-Pillot's paper on "An algorithm for computing genera - of ternary and quaternary quadratic forms", p138. - Donaldson's 1979 paper "Minkowski Reduction of Integral - Matrices", p203. + REFERENCES: + + - Schulze-Pillot's paper on "An algorithm for computing genera + of ternary and quaternary quadratic forms", p138. + - Donaldson's 1979 paper "Minkowski Reduction of Integral Matrices", p203. EXAMPLES:: - sage: Q = QuadraticForm(ZZ,4,[30, 17, 11, 12, 29, 25, 62, 64, 25, 110]) + sage: Q = QuadraticForm(ZZ, 4, [30, 17, 11, 12, 29, 25, 62, 64, 25, 110]) sage: Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 30 17 11 12 ] @@ -198,6 +207,8 @@ def minkowski_reduction(self): [0 0 0 1] ) + TESTS:: + sage: Q = QuadraticForm(ZZ,5,[2,2,0,0,0,2,2,0,0,2,2,0,2,2,2]) sage: Q.Gram_matrix() [2 1 0 0 0] @@ -209,6 +220,12 @@ def minkowski_reduction(self): Traceback (most recent call last): ... NotImplementedError: this algorithm is only for dimensions less than 5 + + sage: Q = QuadraticForm(ZZ,2,[4,-11,6]) + sage: Q.minkowski_reduction() + Traceback (most recent call last): + ... + TypeError: Minkowski reduction only works for positive definite forms """ from sage.quadratic_forms.quadratic_form import QuadraticForm from sage.quadratic_forms.quadratic_form import matrix @@ -220,9 +237,7 @@ def minkowski_reduction(self): R = self.base_ring() n = self.dim() Q = deepcopy(self) - M = matrix(R, n, n) - for i in range(n): - M[i, i] = 1 + M = matrix(R, n, n, 1) # Begin the reduction done_flag = False @@ -230,24 +245,22 @@ def minkowski_reduction(self): # Loop through possible shorted vectors until done_flag = True - for j in range(n-1, -1, -1): - for a_first in mrange([3 for i in range(j)]): - y = [x-1 for x in a_first] + [1] + [0 for k in range(n-1-j)] - e_j = [0 for k in range(n)] + for j in range(n - 1, -1, -1): + for a_first in mrange([3 for i in range(j)]): + y = [x - 1 for x in a_first] + [1] + [0] * (n - 1 - j) + e_j = [0] * n e_j[j] = 1 # Reduce if a shorter vector is found if Q(y) < Q(e_j): # Create the transformation matrix - M_new = matrix(R, n, n) - for k in range(n): - M_new[k,k] = 1 + M_new = matrix(R, n, n, 1) for k in range(n): - M_new[k,j] = y[k] + M_new[k, j] = y[k] # Perform the reduction and restart the loop - Q = QuadraticForm(M_new.transpose()*Q.matrix()*M_new) + Q = QuadraticForm(M_new.transpose() * Q.matrix() * M_new) M = M * M_new done_flag = False @@ -262,26 +275,29 @@ def minkowski_reduction(self): def minkowski_reduction_for_4vars__SP(self): - """ + r""" Find a Minkowski-reduced form equivalent to the given one. This means that - Q(`v_k`) <= Q(`s_1 * v_1 + ... + s_n * v_n`) + .. MATH:: + + Q(v_k) \leq Q(s_1\cdot v_1 + ... + s_n\cdot v_n) for all `s_i` where GCD(`s_k, ... s_n`) = 1. - Note: When Q has dim <= 4 we can take all `s_i` in {1, 0, -1}. + .. NOTE:: + + When `Q` has dim `\leq 4`, we can take all `s_i` in `\{1, 0, -1\}`. + + REFERENCES: - References: - Schulze-Pillot's paper on "An algorithm for computing genera - of ternary and quaternary quadratic forms", p138. - Donaldson's 1979 paper "Minkowski Reduction of Integral - Matrices", p203. + - Schulze-Pillot's paper on "An algorithm for computing genera + of ternary and quaternary quadratic forms", p138. + - Donaldson's 1979 paper "Minkowski Reduction of Integral Matrices", p203. EXAMPLES:: - sage: Q = QuadraticForm(ZZ,4,[30,17,11,12,29,25,62,64,25,110]) - sage: Q + sage: Q = QuadraticForm(ZZ, 4, [30,17,11,12,29,25,62,64,25,110]); Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 30 17 11 12 ] [ * 29 25 62 ] @@ -300,13 +316,19 @@ def minkowski_reduction_for_4vars__SP(self): [ 0 0 1 0] [ 0 0 0 1] ) + + TESTS:: + + sage: Q = QuadraticForm(ZZ, 2, [3,4,5]) + sage: Q.minkowski_reduction_for_4vars__SP() + Traceback (most recent call last): + ... + TypeError: the given quadratic form has 2 != 4 variables """ R = self.base_ring() n = self.dim() Q = deepcopy(self) - M = matrix(R, n, n) - for i in range(n): - M[i, i] = 1 + M = matrix(R, n, n, 1) # Only allow 4-variable forms if n != 4: @@ -318,10 +340,10 @@ def minkowski_reduction_for_4vars__SP(self): # Loop through possible shorter vectors done_flag = True - for j in range(n-1, -1, -1): - for a_first in mrange([2 for i in range(j)]): - y = [x-1 for x in a_first] + [1] + [0 for k in range(n-1-j)] - e_j = [0 for k in range(n)] + for j in range(n - 1, -1, -1): + for a_first in mrange([2 for i in range(j)]): + y = [x - 1 for x in a_first] + [1] + [0] * (n - 1 - j) + e_j = [0] * n e_j[j] = 1 # Reduce if a shorter vector is found @@ -329,22 +351,20 @@ def minkowski_reduction_for_4vars__SP(self): # Further n=4 computations B_y_vec = Q.matrix() * vector(ZZ, y) - # SP's B = our self.matrix()/2 - # SP's A = coeff matrix of his B - # Here we compute the double of both and compare. - B_sum = sum([abs(B_y_vec[i]) for i in range(4) if i != j]) - A_sum = sum([abs(Q[i,j]) for i in range(4) if i != j]) - B_max = max([abs(B_y_vec[i]) for i in range(4) if i != j]) - A_max = max([abs(Q[i,j]) for i in range(4) if i != j]) + # SP's B = our self.matrix()/2 + # SP's A = coeff matrix of his B + # Here we compute the double of both and compare. + B_sum = sum([abs(B_y_vec[i]) for i in range(4) if i != j]) + A_sum = sum([abs(Q[i, j]) for i in range(4) if i != j]) + B_max = max(abs(B_y_vec[i]) for i in range(4) if i != j) + A_max = max(abs(Q[i, j]) for i in range(4) if i != j) - if (B_sum < A_sum) or ((B_sum == A_sum) and (B_max < A_max)): + if B_sum < A_sum or (B_sum == A_sum and B_max < A_max): # Create the transformation matrix - M_new = matrix(R, n, n) + M_new = matrix(R, n, n, 1) for k in range(n): - M_new[k,k] = 1 - for k in range(n): - M_new[k,j] = y[k] + M_new[k, j] = y[k] # Perform the reduction and restart the loop Q = Q(M_new) @@ -359,109 +379,108 @@ def minkowski_reduction_for_4vars__SP(self): # Step 2: Order A by certain criteria for i in range(4): - for j in range(i+1,4): + for j in range(i + 1, 4): # Condition (a) - if (Q[i,i] > Q[j,j]): - Q.swap_variables(i,j,in_place=True) - M_new = matrix(R,n,n) - M_new[i,j] = -1 - M_new[j,i] = 1 + if Q[i, i] > Q[j, j]: + Q.swap_variables(i, j, in_place=True) + M_new = matrix(R, n, n) + M_new[i, j] = -1 + M_new[j, i] = 1 for r in range(4): - if (r == i) or (r == j): - M_new[r,r] = 0 + if r == i or r == j: + M_new[r, r] = 0 else: - M_new[r,r] = 1 + M_new[r, r] = 1 M = M * M_new - elif (Q[i,i] == Q[j,j]): - i_sum = sum([abs(Q[i,k]) for k in range(4) if k != i]) - j_sum = sum([abs(Q[j,k]) for k in range(4) if k != j]) + elif Q[i, i] == Q[j, j]: + i_sum = sum([abs(Q[i, k]) for k in range(4) if k != i]) + j_sum = sum([abs(Q[j, k]) for k in range(4) if k != j]) # Condition (b) - if (i_sum > j_sum): - Q.swap_variables(i,j,in_place=True) - M_new = matrix(R,n,n) - M_new[i,j] = -1 - M_new[j,i] = 1 + if i_sum > j_sum: + Q.swap_variables(i, j, in_place=True) + M_new = matrix(R, n, n) + M_new[i, j] = -1 + M_new[j, i] = 1 for r in range(4): - if (r == i) or (r == j): - M_new[r,r] = 0 + if r == i or r == j: + M_new[r, r] = 0 else: - M_new[r,r] = 1 + M_new[r, r] = 1 M = M * M_new - elif (i_sum == j_sum): - for k in [2,1,0]: # TO DO: These steps are a little redundant... + elif i_sum == j_sum: + for k in [2, 1, 0]: # TO DO: These steps are a little redundant... Q1 = Q.matrix() - c_flag = True - for l in range(k+1,4): - c_flag = c_flag and (abs(Q1[i,l]) == abs(Q1[j,l])) + c_flag = all(abs(Q1[i, l]) == abs(Q1[j, l]) + for l in range(k + 1, 4)) # Condition (c) - if c_flag and (abs(Q1[i,k]) > abs(Q1[j,k])): - Q.swap_variables(i,j,in_place=True) - M_new = matrix(R,n,n) - M_new[i,j] = -1 - M_new[j,i] = 1 + if c_flag and abs(Q1[i, k]) > abs(Q1[j, k]): + Q.swap_variables(i, j, in_place=True) + M_new = matrix(R, n, n) + M_new[i, j] = -1 + M_new[j, i] = 1 for r in range(4): - if (r == i) or (r == j): - M_new[r,r] = 0 + if r == i or r == j: + M_new[r, r] = 0 else: - M_new[r,r] = 1 + M_new[r, r] = 1 M = M * M_new # Step 3: Order the signs for i in range(4): - if Q[i,3] < 0: + if Q[i, 3] < 0: Q.multiply_variable(-1, i, in_place=True) - M_new = matrix(R,n,n) + M_new = matrix(R, n, n) for r in range(4): if r == i: - M_new[r,r] = -1 + M_new[r, r] = -1 else: - M_new[r,r] = 1 + M_new[r, r] = 1 M = M * M_new for i in range(4): j = 3 - while (Q[i,j] == 0): + while Q[i, j] == 0: j += -1 - if (Q[i,j] < 0): + if Q[i, j] < 0: Q.multiply_variable(-1, i, in_place=True) - M_new = matrix(R,n,n) + M_new = matrix(R, n, n) for r in range(4): if r == i: - M_new[r,r] = -1 + M_new[r, r] = -1 else: - M_new[r,r] = 1 + M_new[r, r] = 1 M = M * M_new - if Q[1,2] < 0: + if Q[1, 2] < 0: # Test a row 1 sign change - if (Q[1,3] <= 0 and \ - ((Q[1,3] < 0) or (Q[1,3] == 0 and Q[1,2] < 0) \ - or (Q[1,3] == 0 and Q[1,2] == 0 and Q[1,1] < 0))): + if (Q[1, 3] <= 0 and (Q[1, 3] < 0 + or Q[1, 2] < 0 + or (Q[1, 2] == 0 and Q[1, 1] < 0))): Q.multiply_variable(-1, i, in_place=True) - M_new = matrix(R,n,n) + M_new = matrix(R, n, n) for r in range(4): if r == i: - M_new[r,r] = -1 + M_new[r, r] = -1 else: - M_new[r,r] = 1 + M_new[r, r] = 1 M = M * M_new - elif (Q[2,3] <= 0 and \ - ((Q[2,3] < 0) or (Q[2,3] == 0 and Q[2,2] < 0) \ - or (Q[2,3] == 0 and Q[2,2] == 0 and Q[2,1] < 0))): + elif (Q[2, 3] <= 0 and ((Q[2, 3] < 0) + or Q[2, 2] < 0 + or (Q[2, 2] == 0 and Q[2, 1] < 0))): Q.multiply_variable(-1, i, in_place=True) - M_new = matrix(R,n,n) + M_new = matrix(R, n, n) for r in range(4): if r == i: - M_new[r,r] = -1 + M_new[r, r] = -1 else: - M_new[r,r] = 1 + M_new[r, r] = 1 M = M * M_new # Return the results diff --git a/src/sage/quadratic_forms/quadratic_form__siegel_product.py b/src/sage/quadratic_forms/quadratic_form__siegel_product.py index 1cf72a23745..c439a93f33b 100644 --- a/src/sage/quadratic_forms/quadratic_form__siegel_product.py +++ b/src/sage/quadratic_forms/quadratic_form__siegel_product.py @@ -1,40 +1,41 @@ +# sage.doctest: needs sage.libs.pari """ Siegel Products """ -#***************************************************************************** +# **************************************************************************** # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ -from sage.arith.all import kronecker_symbol, bernoulli, prime_divisors, fundamental_discriminant +from sage.arith.misc import (bernoulli, + fundamental_discriminant, + kronecker as kronecker_symbol, + prime_divisors) from sage.misc.functional import sqrt -from sage.quadratic_forms.special_values import QuadraticBernoulliNumber - - from sage.misc.verbose import verbose +from sage.quadratic_forms.special_values import QuadraticBernoulliNumber +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ - - -#/*! \brief Computes the product of all local densities for comparison with independently computed Eisenstein coefficients. +# /*! \brief Computes the product of all local densities for comparison with independently computed Eisenstein coefficients. # * # * \todo We fixed the generic factors to compensate for using the matrix of 2Q, but we need to document this better! =) # */ -#///////////////////////////////////////////////////////////////// -#/// -#///////////////////////////////////////////////////////////////// +# ///////////////////////////////////////////////////////////////// +# /// +# ///////////////////////////////////////////////////////////////// + +# mpq_class Matrix_mpz::siegel_product(mpz_class u) const { -#mpq_class Matrix_mpz::siegel_product(mpz_class u) const { def siegel_product(self, u): """ - Computes the infinite product of local densities of the quadratic + Compute the infinite product of local densities of the quadratic form for the number `u`. EXAMPLES:: @@ -95,7 +96,6 @@ def siegel_product(self, u): verbose("siegel_product Break 1. \n") verbose(" u = " + str(u) + "\n") - # Make the odd generic factors if ((n % 2) == 1): m = (n-1) // 2 @@ -112,15 +112,12 @@ def siegel_product(self, u): factor1 *= i genericfactor = factor1 * ((u / f) ** m) \ - * QQ(sqrt((2 ** n) * f) / (u * d)) \ + * QQ(sqrt((2 ** n) * f) / (u * d)) \ * abs(QuadraticBernoulliNumber(m, d1) / bernoulli(2*m)) - - # DIAGNOSTIC verbose("siegel_product Break 2. \n") - # Make the even generic factor if ((n % 2) == 0): m = n // 2 @@ -128,18 +125,15 @@ def siegel_product(self, u): f = abs(d1) # DIAGNOSTIC - #cout << " mpz_class(-1)^m = " << (mpz_class(-1)^m) << " and d = " << d << endl; - #cout << " f = " << f << " and d1 = " << d1 << endl; - + # cout << " mpz_class(-1)^m = " << (mpz_class(-1)^m) << " and d = " << d << endl; + # cout << " f = " << f << " and d1 = " << d1 << endl; genericfactor = m / QQ(sqrt(f*d)) \ * ((u/2) ** (m-1)) * (f ** m) \ / abs(QuadraticBernoulliNumber(m, d1)) \ * (2 ** m) # This last factor compensates for using the matrix of 2*Q - - ##return genericfactor - + # return genericfactor # Omit the generic factors in S and compute them separately omit = 1 @@ -148,55 +142,53 @@ def siegel_product(self, u): S_divisors = prime_divisors(S) # DIAGNOSTIC - #cout << "\n S is " << S << endl; - #cout << " The Prime divisors of S are :"; - #PrintV(S_divisors); + # cout << "\n S is " << S << endl; + # cout << " The Prime divisors of S are :"; + # PrintV(S_divisors); for p in S_divisors: Q_normal = self.local_normal_form(p) - # DIAGNOSTIC verbose(" p = " + str(p) + " and its Kronecker symbol (d1/p) = (" + str(d1) + "/" + str(p) + ") is " + str(kronecker_symbol(d1, p)) + "\n") omit *= 1 / (1 - (kronecker_symbol(d1, p) / (p**m))) - # DIAGNOSTIC verbose(" omit = " + str(omit) + "\n") verbose(" Q_normal is \n" + str(Q_normal) + "\n") verbose(" Q_normal = \n" + str(Q_normal)) verbose(" p = " + str(p) + "\n") - verbose(" u = " +str(u) + "\n") + verbose(" u = " + str(u) + "\n") verbose(" include = " + str(include) + "\n") include *= Q_normal.local_density(p, u) # DIAGNOSTIC - #cout << " Including the p = " << p << " factor: " << local_density(Q_normal, p, u) << endl; + # cout << " Including the p = " << p << " factor: " << local_density(Q_normal, p, u) << endl; # DIAGNOSTIC verbose(" --- Exiting loop \n") - #// **************** Important ******************* - #// Additional fix (only included for n=4) to deal - #// with the power of 2 introduced at the real place - #// by working with Q instead of 2*Q. This needs to - #// be done for all other n as well... - #/* - #if (n==4) + # // **************** Important ******************* + # // Additional fix (only included for n=4) to deal + # // with the power of 2 introduced at the real place + # // by working with Q instead of 2*Q. This needs to + # // be done for all other n as well... + # /* + # if (n==4) # genericfactor = 4 * genericfactor; - #*/ + # */ # DIAGNOSTIC - #cout << endl; - #cout << " generic factor = " << genericfactor << endl; - #cout << " omit = " << omit << endl; - #cout << " include = " << include << endl; - #cout << endl; + # cout << endl; + # cout << " generic factor = " << genericfactor << endl; + # cout << " omit = " << omit << endl; + # cout << " include = " << include << endl; + # cout << endl; # DIAGNOSTIC - #// cout << "siegel_product Break 3. " << endl; + # // cout << "siegel_product Break 3. " << endl; # Return the final factor (and divide by 2 if n=2) if n == 2: diff --git a/src/sage/quadratic_forms/quadratic_form__split_local_covering.py b/src/sage/quadratic_forms/quadratic_form__split_local_covering.py index 2fc02f60e56..61f8c1a027f 100644 --- a/src/sage/quadratic_forms/quadratic_form__split_local_covering.py +++ b/src/sage/quadratic_forms/quadratic_form__split_local_covering.py @@ -9,47 +9,44 @@ from copy import deepcopy from sage.quadratic_forms.extras import extend_to_primitive -from sage.quadratic_forms.quadratic_form import QuadraticForm__constructor, is_QuadraticForm import sage.rings.abc -from sage.rings.real_mpfr import RealField from sage.rings.real_double import RDF from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import matrix -from sage.functions.all import floor +from sage.misc.lazy_import import lazy_import +lazy_import("sage.functions.all", "floor") from sage.rings.integer_ring import ZZ -from sage.arith.all import GCD +from sage.arith.misc import GCD -def cholesky_decomposition(self, bit_prec = 53): +def cholesky_decomposition(self, bit_prec=53): r""" Give the Cholesky decomposition of this quadratic form `Q` as a real matrix of precision ``bit_prec``. RESTRICTIONS: - Q must be given as a QuadraticForm defined over `\ZZ`, `\QQ`, or some + `Q` must be given as a :class:`QuadraticForm` defined over `\ZZ`, `\QQ`, or some real field. If it is over some real field, then an error is raised if the precision given is not less than the defined precision of the real field defining the quadratic form! REFERENCE: - From Cohen's "A Course in Computational Algebraic Number Theory" book, - p 103. + - Cohen's "A Course in Computational Algebraic Number Theory" book, p 103. INPUT: - ``bit_prec`` -- a natural number (default 53). + - ``bit_prec`` -- a natural number (default 53) - OUTPUT: + OUTPUT: an upper triangular real matrix of precision ``bit_prec``. - an upper triangular real matrix of precision ``bit_prec``. + .. TODO:: - TO DO: - If we only care about working over the real double field (RDF), then we - can use the ``cholesky()`` method present for square matrices over that. + If we only care about working over the real double field (``RDF``), then we + can use the method :meth:`cholesky` present for square matrices over that. .. note:: @@ -57,10 +54,8 @@ def cholesky_decomposition(self, bit_prec = 53): :: - ##///////////////////////////////////////////////////////////////////////////////////////////////// - ##/// Finds the Cholesky decomposition of a quadratic form -- as an upper-triangular matrix! - ##/// (It's assumed to be global, hence twice the form it refers to.) <-- Python revision asks: Is this true?!? =| - ##///////////////////////////////////////////////////////////////////////////////////////////////// + Finds the Cholesky decomposition of a quadratic form -- as an upper-triangular matrix! + (It's assumed to be global, hence twice the form it refers to.) <-- Python revision asks: Is this true?!? =| EXAMPLES:: @@ -87,6 +82,8 @@ def cholesky_decomposition(self, bit_prec = 53): if isinstance(self.base_ring(), sage.rings.abc.RealField) and (self.base_ring().prec() < bit_prec): raise RuntimeError("the precision requested is greater than that of the given quadratic form") + from sage.rings.real_mpfr import RealField + # 1. Initialization n = self.dim() R = RealField(bit_prec) @@ -115,27 +112,29 @@ def cholesky_decomposition(self, bit_prec = 53): def vectors_by_length(self, bound): - """ - Returns a list of short vectors together with their values. + r""" + Return a list of short vectors together with their values. This is a naive algorithm which uses the Cholesky decomposition, but does not use the LLL-reduction algorithm. INPUT: - bound -- an integer >= 0 + - ``bound`` -- an integer `\geq 0` OUTPUT: - A list L of length (bound + 1) whose entry L `[i]` is a list of - all vectors of length `i`. + - a list ``L`` of length (``bound`` + 1) whose entry ``L[i]`` is a list of + all vectors of length `i`. + + REFERENCES: - Reference: This is a slightly modified version of Cohn's Algorithm + This is a slightly modified version of Cohn's Algorithm 2.7.5 in "A Course in Computational Number Theory", with the increment step moved around and slightly re-indexed to allow clean looping. - .. NOTE:: + .. NOTE:: We could speed this up for very skew matrices by using LLL first, and then changing coordinates back, but for our purposes @@ -144,7 +143,7 @@ def vectors_by_length(self, bound): EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) - sage: Q.vectors_by_length(5) + sage: Q.vectors_by_length(5) # needs sage.symbolic [[[0, 0]], [[0, -1], [-1, 0]], [[-1, -1], [1, -1]], @@ -155,7 +154,7 @@ def vectors_by_length(self, bound): :: sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,5,7]) - sage: Q1.vectors_by_length(5) + sage: Q1.vectors_by_length(5) # needs sage.symbolic [[[0, 0, 0, 0]], [[-1, 0, 0, 0]], [], @@ -166,13 +165,13 @@ def vectors_by_length(self, bound): :: sage: Q = QuadraticForm(ZZ, 4, [1,1,1,1, 1,0,0, 1,0, 1]) - sage: list(map(len, Q.vectors_by_length(2))) + sage: list(map(len, Q.vectors_by_length(2))) # needs sage.symbolic [1, 12, 12] :: sage: Q = QuadraticForm(ZZ, 4, [1,-1,-1,-1, 1,0,0, 4,-3, 4]) - sage: list(map(len, Q.vectors_by_length(3))) + sage: list(map(len, Q.vectors_by_length(3))) # needs sage.symbolic [1, 3, 0, 3] """ # pari uses eps = 1e-6 ; nothing bad should happen if eps is too big @@ -190,7 +189,6 @@ def vectors_by_length(self, bound): # Initialize Q with zeros and Copy the Cholesky array into Q Q = self.cholesky_decomposition() - # 1. Initialize T = n * [RDF(0)] # Note: We index the entries as 0 --> n-1 U = n * [RDF(0)] @@ -238,7 +236,7 @@ def vectors_by_length(self, bound): Q_val = Q_val_double.round() # SANITY CHECK: Roundoff Error is < 0.001 - if abs(Q_val_double - Q_val) > 0.001: + if abs(Q_val_double - Q_val) > 0.001: print(" x = ", x) print(" Float = ", Q_val_double, " Long = ", Q_val) raise RuntimeError("The roundoff error is bigger than 0.001, so we should use more precision somewhere...") @@ -264,25 +262,27 @@ def vectors_by_length(self, bound): def complementary_subform_to_vector(self, v): - """ - Finds the `(n-1)`-dim'l quadratic form orthogonal to the vector `v`. + r""" + Find the `(n-1)`-dimensional quadratic form orthogonal to the vector `v`. - Note: This is usually not a direct summand! + .. NOTE:: - Technical Notes: There is a minor difference in the cancellation - code here (form the C++ version) since the notation Q `[i,j]` indexes - coefficients of the quadratic polynomial here, not the symmetric - matrix. Also, it produces a better splitting now, for the full - lattice (as opposed to a sublattice in the C++ code) since we - now extend `v` to a unimodular matrix. + This is usually not a direct summand! - INPUT: + .. NOTE:: - `v` -- a list of self.dim() integers + There is a minor difference in the cancellation + code here (form the C++ version) since the notation ``Q[i,j]`` indexes + coefficients of the quadratic polynomial here, not the symmetric + matrix. Also, it produces a better splitting now, for the full + lattice (as opposed to a sublattice in the C++ code) since we + now extend `v` to a unimodular matrix. - OUTPUT: + INPUT: + + - ``v`` -- a list of ``self.dim()`` integers - a QuadraticForm over `ZZ` + OUTPUT: a :class:`QuadraticForm` over `\ZZ` EXAMPLES:: @@ -309,7 +309,6 @@ def complementary_subform_to_vector(self, v): [ 880 -480 -160 ] [ * 624 -96 ] [ * * 240 ] - """ n = self.dim() @@ -354,47 +353,41 @@ def complementary_subform_to_vector(self, v): if not done_flag: raise RuntimeError("There is a problem cancelling out the matrix entries! =O") - # Return the complementary matrix return Q1.extract_variables(range(1,n)) def split_local_cover(self): - """ + r""" Tries to find subform of the given (positive definite quaternary) - quadratic form Q of the form + quadratic form `Q` of the form .. MATH:: - d*x^2 + T(y,z,w) + d\cdot x^2 + T(y,z,w) where `d > 0` is as small as possible. This is done by exhaustive search on small vectors, and then - comparing the local conditions of its sum with it's complementary - lattice and the original quadratic form Q. - - INPUT: + comparing the local conditions of its sum with its complementary + lattice and the original quadratic form `Q`. - none - - OUTPUT: - - a QuadraticForm over ZZ + OUTPUT: a :class:`QuadraticForm` over `\ZZ` EXAMPLES:: sage: Q1 = DiagonalQuadraticForm(ZZ, [7,5,3]) - sage: Q1.split_local_cover() + sage: Q1.split_local_cover() # needs sage.symbolic Quadratic form in 3 variables over Integer Ring with coefficients: [ 3 0 0 ] [ * 5 0 ] [ * * 7 ] - """ + from sage.quadratic_forms.quadratic_form import QuadraticForm + # 0. If a split local cover already exists, then return it. if hasattr(self, "__split_local_cover"): - if is_QuadraticForm(self.__split_local_cover): # Here the computation has been done. + if isinstance(self.__split_local_cover, QuadraticForm): # Here the computation has been done. return self.__split_local_cover elif self.__split_local_cover in ZZ: # Here it indexes the values already tried! current_length = self.__split_local_cover + 1 @@ -412,7 +405,7 @@ def split_local_cover(self): # 2. Check if any of the primitive ones produce a split local cover for v in current_vectors: - Q = QuadraticForm__constructor(ZZ, 1, [current_length]) + self.complementary_subform_to_vector(v) + Q = QuadraticForm(ZZ, 1, [current_length]) + self.complementary_subform_to_vector(v) if Q.local_representation_conditions() == self.local_representation_conditions(): self.__split_local_cover = Q return Q diff --git a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py index 22334a8e857..6ec8bd8022f 100644 --- a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +++ b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py @@ -11,17 +11,17 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.integer_ring import ZZ +from sage.arith.misc import (CRT_vectors, + factor, + gcd, + hilbert_symbol, + kronecker as kronecker_symbol, + prime_to_m_part) from sage.misc.functional import is_odd - -from sage.libs.pari.all import pari from sage.misc.misc_c import prod -from sage.arith.all import (factor, gcd, prime_to_m_part, CRT_vectors, - hilbert_symbol, kronecker_symbol) - -from sage.quadratic_forms.quadratic_form import QuadraticForm__constructor as QuadraticForm from sage.modules.free_module import FreeModule from sage.modules.free_module_element import vector +from sage.rings.integer_ring import ZZ # TO DO -- Add second argument @@ -131,6 +131,8 @@ def adjoint(self): [ * * 8 ] """ + from sage.quadratic_forms.quadratic_form import QuadraticForm as QuadraticForm + if is_odd(self.dim()): return QuadraticForm(self.matrix().adjoint_classical() * 2) return QuadraticForm(self.matrix().adjoint_classical()) @@ -148,7 +150,7 @@ def antiadjoint(self): [ 1 0 -1 ] [ * 2 -1 ] [ * * 5 ] - sage: Q.antiadjoint() + sage: Q.antiadjoint() # needs sage.symbolic Traceback (most recent call last): ... ValueError: not an adjoint @@ -172,7 +174,7 @@ def is_adjoint(self) -> bool: EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) - sage: Q.is_adjoint() + sage: Q.is_adjoint() # needs sage.symbolic False sage: Q.adjoint().is_adjoint() True @@ -185,7 +187,7 @@ def is_adjoint(self) -> bool: def reciprocal(self): - """ + r""" This gives the reciprocal quadratic form associated to the given form. This is defined as the multiple of the primitive adjoint with the same content as the given form. @@ -211,7 +213,7 @@ def reciprocal(self): def omega(self): - """ + r""" This is the content of the adjoint of the primitive associated quadratic form. Ref: See Dickson's "Studies in Number Theory". @@ -227,7 +229,7 @@ def omega(self): def delta(self): - """ + r""" This is the omega of the adjoint form, which is the same as the omega of the reciprocal form. @@ -241,14 +243,14 @@ def delta(self): def level__Tornaria(self): - """ + r""" Return the level of the quadratic form, defined as - level(B) for even dimension - level(B)/4 for odd dimension + - level(`B`) for even dimension, + - level(`B`)/4 for odd dimension, - where 2Q(`x`) `= x^t * B * x`. + where `2Q(x) = x^t\cdot B\cdot x`. This agrees with the usual level for even dimension... @@ -267,7 +269,7 @@ def level__Tornaria(self): def discrec(self): - """ + r""" Return the discriminant of the reciprocal form. EXAMPLES:: @@ -287,10 +289,11 @@ def discrec(self): def hasse_conductor(self): """ - This is the product of all primes where the Hasse invariant equals -1 + This is the product of all primes where the Hasse invariant equals `-1` EXAMPLES:: + sage: # needs sage.libs.pari sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.hasse_invariant(2) -1 @@ -299,9 +302,9 @@ def hasse_conductor(self): sage: Q.hasse_conductor() 74 - sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).hasse_conductor() + sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).hasse_conductor() # needs sage.libs.pari 1 - sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).hasse_conductor() + sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).hasse_conductor() # needs sage.libs.pari 10 """ return prod([x[0] for x in factor(2 * self.level()) @@ -318,8 +321,9 @@ def clifford_invariant(self, p): EXAMPLES: - For hyperbolic spaces, the clifford invariant is +1:: + For hyperbolic spaces, the Clifford invariant is +1:: + sage: # needs sage.libs.pari sage: H = QuadraticForm(ZZ, 2, [0, 1, 0]) sage: H.clifford_invariant(2) 1 @@ -331,7 +335,7 @@ def clifford_invariant(self, p): 1 """ n = self.dim() % 8 - if n == 1 or n == 2: + if n == 1 or n == 2: s = 1 elif n == 3 or n == 4: s = hilbert_symbol(-1, -self.disc(), p) @@ -344,9 +348,9 @@ def clifford_invariant(self, p): def clifford_conductor(self): """ - This is the product of all primes where the Clifford invariant is -1 + This is the product of all primes where the Clifford invariant is `-1` - ..NOTE:: + .. NOTE:: For ternary forms, this is the discriminant of the quaternion algebra associated to the quadratic space @@ -354,6 +358,7 @@ def clifford_conductor(self): EXAMPLES:: + sage: # needs sage.libs.pari sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.clifford_invariant(2) 1 @@ -362,13 +367,14 @@ def clifford_conductor(self): sage: Q.clifford_conductor() 37 - sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).clifford_conductor() + sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).clifford_conductor() # needs sage.libs.pari 2 - sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).clifford_conductor() + sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).clifford_conductor() # needs sage.libs.pari 30 - For hyperbolic spaces, the clifford conductor is 1:: + For hyperbolic spaces, the Clifford conductor is 1:: + sage: # needs sage.libs.pari sage: H = QuadraticForm(ZZ, 2, [0, 1, 0]) sage: H.clifford_conductor() 1 @@ -387,7 +393,7 @@ def clifford_conductor(self): def basiclemma(self, M): """ - Find a number represented by self and coprime to M. + Find a number represented by self and coprime to `M`. EXAMPLES:: @@ -402,7 +408,7 @@ def basiclemma(self, M): def basiclemmavec(self, M): """ - Find a vector where the value of the quadratic form is coprime to M. + Find a vector where the value of the quadratic form is coprime to `M`. EXAMPLES:: @@ -448,7 +454,9 @@ def xi(self, p): Return the value of the genus characters Xi_p... which may be missing one character. We allow -1 as a prime. - Reference: Dickson's "Studies in the Theory of Numbers" + REFERENCES: + + Dickson's "Studies in the Theory of Numbers" EXAMPLES:: @@ -456,9 +464,10 @@ def xi(self, p): sage: Q2 = QuadraticForm(ZZ, 3, [2, -1, 0, 2, 0, 50]) sage: [Q1.omega(), Q2.omega()] [5, 5] - sage: [Q1.hasse_invariant(5), Q2.hasse_invariant(5)] # equivalent over Q_5 + sage: [Q1.hasse_invariant(5), # equivalent over Q_5 # needs sage.libs.pari + ....: Q2.hasse_invariant(5)] [1, 1] - sage: [Q1.xi(5), Q2.xi(5)] # not equivalent over Z_5 + sage: [Q1.xi(5), Q2.xi(5)] # not equivalent over Z_5 # needs sage.libs.pari [1, -1] """ if self.dim() == 2 and self.disc() % p: @@ -476,11 +485,13 @@ def xi_rec(self,p): EXAMPLES:: + sage: # needs sage.libs.pari sage: Q1 = QuadraticForm(ZZ, 3, [1, 1, 1, 14, 3, 14]) sage: Q2 = QuadraticForm(ZZ, 3, [2, -1, 0, 2, 0, 50]) - sage: [Q1.clifford_conductor(), Q2.clifford_conductor()] # equivalent over Q + sage: [Q1.clifford_conductor(), # equivalent over Q + ....: Q2.clifford_conductor()] [3, 3] - sage: Q1.is_locally_equivalent_to(Q2) # not in the same genus + sage: Q1.is_locally_equivalent_to(Q2) # not in the same genus False sage: [Q1.delta(), Q2.delta()] [480, 480] @@ -496,14 +507,14 @@ def xi_rec(self,p): def lll(self): """ - Return an LLL-reduced form of Q (using Pari). + Return an LLL-reduced form of `Q` (using PARI). EXAMPLES:: sage: Q = QuadraticForm(ZZ, 4, range(1,11)) sage: Q.is_definite() True - sage: Q.lll() + sage: Q.lll() # needs sage.libs.pari Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 1 0 ] [ * 4 3 3 ] @@ -519,10 +530,12 @@ def representation_number_list(self, B): EXAMPLES:: - sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1,1,1,1,1]) - sage: Q.representation_number_list(10) + sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,1,1,1,1]) + sage: Q.representation_number_list(10) # needs sage.libs.pari [1, 16, 112, 448, 1136, 2016, 3136, 5504, 9328, 12112] """ + from sage.libs.pari.all import pari + ans = pari(1).concat(self.__pari__().qfrep(B - 1, 1) * 2) return ans.sage() @@ -535,6 +548,7 @@ def representation_vector_list(self, B, maxvectors=10**8): EXAMPLES:: + sage: # needs sage.libs.pari sage: Q = DiagonalQuadraticForm(ZZ, [1, 1]) sage: Q.representation_vector_list(10) [[(0, 0)], @@ -554,13 +568,13 @@ def representation_vector_list(self, B, maxvectors=10**8): TESTS:: - sage: R = QuadraticForm(ZZ,2,[-4,-3,0]) - sage: R.representation_vector_list(10) + sage: R = QuadraticForm(ZZ, 2, [-4,-3,0]) + sage: R.representation_vector_list(10) # needs sage.libs.pari Traceback (most recent call last): ... PariError: domain error in minim0: form is not positive definite """ - n, m, vs = self.__pari__().qfminim(2 * (B - 1), maxvectors) + n, _, vs = self.__pari__().qfminim(2 * (B - 1), maxvectors) if n != 2 * len(vs): raise RuntimeError("insufficient number of vectors") @@ -574,8 +588,8 @@ def representation_vector_list(self, B, maxvectors=10**8): # zeros def is_zero(self, v, p=0) -> bool: - """ - Determine if the vector v is on the conic Q(x) = 0 (mod p). + r""" + Determine if the vector `v` is on the conic `Q(x) = 0` (mod `p`). EXAMPLES:: @@ -586,17 +600,16 @@ def is_zero(self, v, p=0) -> bool: True sage: Q1.is_zero([1,1,0], 2) False - """ norm = self(v) if p != 0: norm = norm % p - return norm == 0 + return norm == 0 def is_zero_nonsingular(self, v, p=0) -> bool: """ - Determine if the vector `v` is on the conic Q(`x`) = 0 (mod `p`), + Determine if the vector `v` is on the conic `Q(x) = 0` (mod `p`), and that this point is non-singular point of the conic. EXAMPLES:: @@ -619,7 +632,7 @@ def is_zero_nonsingular(self, v, p=0) -> bool: def is_zero_singular(self, v, p=0) -> bool: """ - Determine if the vector `v` is on the conic Q(`x`) = 0 (mod `p`), + Determine if the vector `v` is on the conic `Q(x) = 0` (mod `p`), and that this point is singular point of the conic. EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form__theta.py b/src/sage/quadratic_forms/quadratic_form__theta.py index 7763c61a194..7aa257d5e71 100644 --- a/src/sage/quadratic_forms/quadratic_form__theta.py +++ b/src/sage/quadratic_forms/quadratic_form__theta.py @@ -11,35 +11,31 @@ """ from copy import deepcopy -from sage.rings.real_mpfr import RealField from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.integer_ring import ZZ -from sage.functions.all import floor, ceil -from sage.misc.functional import sqrt -from sage.misc.misc import cputime def theta_series(self, Max=10, var_str='q', safe_flag=True): - """ + r""" Compute the theta series as a power series in the variable given - in var_str (which defaults to '`q`'), up to the specified precision - `O(q^max)`. + in ``var_str`` (which defaults to ``'q'``), up to the specified precision + `O(q^{Max})`. This uses the PARI/GP function :pari:`qfrep`, wrapped by the theta_by_pari() method. This caches the result for future computations. - The safe_flag allows us to select whether we want a copy of the + The ``safe_flag`` allows us to select whether we want a copy of the output, or the original output. It is only meaningful when a vector is returned, otherwise a copy is automatically made in - creating the power series. By default safe_flag = True, so we + creating the power series. By default ``safe_flag`` = True, so we return a copy of the cached information. If this is set to False, then the routine is much faster but the return values are vulnerable to being corrupted by the user. .. TODO:: - Allow the option Max='mod_form' to give enough coefficients + Allow the option ``Max='mod_form'`` to give enough coefficients to ensure we determine the theta series as a modular form. This is related to the Sturm bound, but we will need to be careful about this (particularly for half-integral weights!). @@ -47,11 +43,13 @@ def theta_series(self, Max=10, var_str='q', safe_flag=True): EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) - sage: Q.theta_series() + sage: Q.theta_series() # needs sage.libs.pari 1 + 2*q + 2*q^3 + 6*q^4 + 2*q^5 + 4*q^6 + 6*q^7 + 8*q^8 + 14*q^9 + O(q^10) - sage: Q.theta_series(25) - 1 + 2*q + 2*q^3 + 6*q^4 + 2*q^5 + 4*q^6 + 6*q^7 + 8*q^8 + 14*q^9 + 4*q^10 + 12*q^11 + 18*q^12 + 12*q^13 + 12*q^14 + 8*q^15 + 34*q^16 + 12*q^17 + 8*q^18 + 32*q^19 + 10*q^20 + 28*q^21 + 16*q^23 + 44*q^24 + O(q^25) + sage: Q.theta_series(25) # needs sage.libs.pari + 1 + 2*q + 2*q^3 + 6*q^4 + 2*q^5 + 4*q^6 + 6*q^7 + 8*q^8 + 14*q^9 + 4*q^10 + + 12*q^11 + 18*q^12 + 12*q^13 + 12*q^14 + 8*q^15 + 34*q^16 + 12*q^17 + 8*q^18 + + 32*q^19 + 10*q^20 + 28*q^21 + 16*q^23 + 44*q^24 + O(q^25) """ # Sanity Check: Max is an integer or an allowed string: @@ -73,38 +71,37 @@ def theta_series(self, Max=10, var_str='q', safe_flag=True): # ------------- Compute the theta function by using the PARI/GP routine qfrep ------------ def theta_by_pari(self, Max, var_str='q', safe_flag=True): - """ + r""" Use PARI/GP to compute the theta function as a power series (or - vector) up to the precision `O(q^Max)`. This also caches the result + vector) up to the precision `O(q^{Max})`. This also caches the result for future computations. - If var_str = '', then we return a vector `v` where `v[i]` counts the + If ``var_str`` = ``''``, then we return a vector `v` where ``v[i]`` counts the number of vectors of length `i`. - The safe_flag allows us to select whether we want a copy of the + The ``safe_flag`` allows us to select whether we want a copy of the output, or the original output. It is only meaningful when a vector is returned, otherwise a copy is automatically made in - creating the power series. By default safe_flag = True, so we + creating the power series. By default ``safe_flag=True``, so we return a copy of the cached information. If this is set to False, then the routine is much faster but the return values are vulnerable to being corrupted by the user. INPUT: - Max -- an integer >=0 - var_str -- a string - - OUTPUT: + - ``Max`` -- an integer `\geq 0` + - ``var_str`` -- a string - a power series or a vector + OUTPUT: a power series or a vector EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Prec = 100 - sage: compute = Q.theta_by_pari(Prec, '') - sage: exact = [1] + [8 * sum([d for d in divisors(i) if d % 4 != 0]) for i in range(1, Prec)] - sage: compute == exact + sage: compute = Q.theta_by_pari(Prec, '') # needs sage.libs.pari + sage: exact = [1] + [8 * sum([d for d in divisors(i) if d % 4 != 0]) # needs sage.libs.pari + ....: for i in range(1, Prec)] + sage: compute == exact # needs sage.libs.pari True """ @@ -126,7 +123,6 @@ def theta_by_pari(self, Max, var_str='q', safe_flag=True): return PowerSeriesRing(ZZ, var_str)(theta_vec, Max) - # ------------- Compute the theta function by using an explicit Cholesky decomposition ------------ @@ -148,8 +144,7 @@ def theta_by_cholesky(self, q_prec): REFERENCE: - From Cohen's "A Course in Computational Algebraic Number Theory" book, - p 102. + Cohen's "A Course in Computational Algebraic Number Theory" book, p 102. EXAMPLES:: @@ -157,8 +152,10 @@ def theta_by_cholesky(self, q_prec): sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Theta = Q.theta_by_cholesky(10) sage: Theta - 1 + 8*q + 24*q^2 + 32*q^3 + 24*q^4 + 48*q^5 + 96*q^6 + 64*q^7 + 24*q^8 + 104*q^9 + 144*q^10 - sage: Expected = [1] + [8*sum([d for d in divisors(n) if d%4 != 0]) for n in range(1,11)] + 1 + 8*q + 24*q^2 + 32*q^3 + 24*q^4 + 48*q^5 + 96*q^6 + + 64*q^7 + 24*q^8 + 104*q^9 + 144*q^10 + sage: Expected = [1] + [8*sum([d for d in divisors(n) if d%4 != 0]) + ....: for n in range(1, 11)] sage: Expected [1, 8, 24, 32, 24, 48, 96, 64, 24, 104, 144] sage: Theta.list() == Expected @@ -177,6 +174,10 @@ def theta_by_cholesky(self, q_prec): # RAISE AN ERROR -- This routine is deprecated! #raise NotImplementedError, "This routine is deprecated. Try theta_series(), which uses theta_by_pari()." + from sage.arith.misc import integer_ceil as ceil, integer_floor as floor + from sage.misc.functional import sqrt + from sage.rings.real_mpfr import RealField + n = self.dim() theta = [0 for i in range(q_prec+1)] PS = PowerSeriesRing(ZZ, 'q') @@ -224,8 +225,6 @@ def theta_by_cholesky(self, q_prec): L[i] = floor(Z - U[i]) x[i] = ceil(-Z - U[i]) - 1 - - # 3a. Main loop x[i] += 1 while (x[i] > L[i]): @@ -235,32 +234,32 @@ def theta_by_cholesky(self, q_prec): # 3b. Main loop if (i > 0): from_step3_flag = True - T[i-1] = T[i] - Q[i,i] * (x[i] + U[i]) * (x[i] + U[i]) - i += - 1 + T[i - 1] = T[i] - Q[i, i] * (x[i] + U[i]) * (x[i] + U[i]) + i += -1 U[i] = 0 - for j in range(i+1, n): - U[i] += Q[i,j] * x[j] + for j in range(i + 1, n): + U[i] += Q[i, j] * x[j] # 4. Solution found (This happens when i=0) from_step4_flag = True - Q_val_double = q_prec - T[0] + Q[0,0] * (x[0] + U[0]) * (x[0] + U[0]) + Q_val_double = q_prec - T[0] + Q[0, 0] * (x[0] + U[0]) * (x[0] + U[0]) Q_val = floor(Q_val_double + half) # Note: This rounds the value up, since the "round" function returns a float, but floor returns integer. # OPTIONAL SAFETY CHECK: eps = 0.000000001 - if (abs(Q_val_double - Q_val) > eps): - raise RuntimeError("Oh No! We have a problem with the floating point precision... \n" \ - + " Q_val_double = " + str(Q_val_double) + "\n" \ - + " Q_val = " + str(Q_val) + "\n" \ + if abs(Q_val_double - Q_val) > eps: + raise RuntimeError("Oh No! We have a problem with the floating point precision... \n" + + " Q_val_double = " + str(Q_val_double) + "\n" + + " Q_val = " + str(Q_val) + "\n" + " x = " + str(x) + "\n") - if (Q_val <= q_prec): + if Q_val <= q_prec: theta[Q_val] += 2 # 5. Check if x = 0, for exit condition. =) done_flag = True for j in range(n): - if (x[j] != 0): + if x[j] != 0: done_flag = False # Set the value: theta[0] = 1 @@ -272,11 +271,11 @@ def theta_by_cholesky(self, q_prec): def theta_series_degree_2(Q, prec): r""" - Compute the theta series of degree 2 for the quadratic form Q. + Compute the theta series of degree 2 for the quadratic form `Q`. INPUT: - - ``prec`` -- an integer. + - ``prec`` -- an integer OUTPUT: @@ -288,6 +287,7 @@ def theta_series_degree_2(Q, prec): EXAMPLES:: + sage: # needs sage.symbolic sage: Q2 = QuadraticForm(ZZ, 4, [1,1,1,1, 1,0,0, 1,0, 1]) sage: S = Q2.theta_series_degree_2(10) sage: S[(0,0,2)] @@ -306,6 +306,9 @@ def theta_series_degree_2(Q, prec): - Raum, Ryan, Skoruppa, Tornaria, 'On Formal Siegel Modular Forms' (preprint) """ + from sage.arith.misc import integer_floor as floor + from sage.misc.functional import sqrt + from sage.misc.timing import cputime from sage.misc.verbose import verbose if Q.base_ring() != ZZ: diff --git a/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py b/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py index f84dc007c7f..cbcae91d9de 100644 --- a/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py +++ b/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py @@ -19,17 +19,17 @@ def swap_variables(self, r, s, in_place=False): - """ + r""" Switch the variables `x_r` and `x_s` in the quadratic form - (replacing the original form if the in_place flag is True). + (replacing the original form if the ``in_place`` flag is True). INPUT: - - `r`, `s` -- integers >= 0 + - ``r``, ``s`` -- integers `\geq 0` OUTPUT: - a QuadraticForm (by default, otherwise none) + a :class:`QuadraticForm` (by default, otherwise none) EXAMPLES:: @@ -41,7 +41,6 @@ def swap_variables(self, r, s, in_place=False): [ * * 8 9 ] [ * * * 10 ] - sage: Q.swap_variables(0,2) Quadratic form in 4 variables over Integer Ring with coefficients: [ 8 6 3 9 ] @@ -49,14 +48,12 @@ def swap_variables(self, r, s, in_place=False): [ * * 1 4 ] [ * * * 10 ] - sage: Q.swap_variables(0,2).swap_variables(0,2) Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 4 ] [ * 5 6 7 ] [ * * 8 9 ] [ * * * 10 ] - """ if not in_place: Q = self.parent()(self.base_ring(), self.dim(), self.coefficients()) @@ -77,33 +74,30 @@ def swap_variables(self, r, s, in_place=False): def multiply_variable(self, c, i, in_place=False): - """ - Replace the variables `x_i` by `c*x_i` in the quadratic form - (replacing the original form if the in_place flag is True). + r""" + Replace the variables `x_i` by `c\cdot x_i` in the quadratic form + (replacing the original form if the ``in_place`` flag is True). - Here `c` must be an element of the base_ring defining the + Here `c` must be an element of the base ring defining the quadratic form. INPUT: - - `c` -- an element of Q.base_ring() + - ``c`` -- an element of ``self.base_ring()`` - - `i` -- an integer >= 0 + - ``i`` -- an integer `\geq 0` - OUTPUT: - - a QuadraticForm (by default, otherwise none) + OUTPUT: a :class:`QuadraticForm` (by default, otherwise none) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7]) - sage: Q.multiply_variable(5,0) + sage: Q.multiply_variable(5, 0) Quadratic form in 4 variables over Integer Ring with coefficients: [ 25 0 0 0 ] [ * 9 0 0 ] [ * * 5 0 ] [ * * * 7 ] - """ if not in_place: Q = self.parent()(self.base_ring(), self.dim(), self.coefficients()) @@ -122,34 +116,33 @@ def multiply_variable(self, c, i, in_place=False): def divide_variable(self, c, i, in_place=False): - """ + r""" Replace the variables `x_i` by `(x_i)/c` in the quadratic form - (replacing the original form if the in_place flag is True). + (replacing the original form if the ``in_place`` flag is True). - Here `c` must be an element of the base_ring defining the + Here `c` must be an element of the base ring defining the quadratic form, and the division must be defined in the base ring. INPUT: - - `c` -- an element of Q.base_ring() + - ``c`` -- an element of ``self.base_ring()`` - - `i` -- an integer >= 0 + - ``i`` -- an integer `\geq 0` OUTPUT: - a QuadraticForm (by default, otherwise none) + a :class:`QuadraticForm` (by default, otherwise none) EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7]) - sage: Q.divide_variable(3,1) + sage: Q.divide_variable(3, 1) Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 0 0 ] [ * 1 0 0 ] [ * * 5 0 ] [ * * * 7 ] - """ if not in_place: Q = self.parent()(self.base_ring(), self.dim(), self.coefficients()) @@ -177,11 +170,9 @@ def scale_by_factor(self, c, change_value_ring_flag=False): INPUT: - `c` -- a scalar in the fraction field of the value ring of the form. + - ``c`` -- a scalar in the fraction field of the value ring of the form - OUTPUT: - - A quadratic form of the same dimension + OUTPUT: a quadratic form of the same dimension EXAMPLES:: @@ -222,17 +213,15 @@ def scale_by_factor(self, c, change_value_ring_flag=False): def extract_variables(QF, var_indices): - """ + r""" Extract the variables (in order) whose indices are listed in ``var_indices``, to give a new quadratic form. INPUT: - ``var_indices`` -- a list of integers >= 0 + - ``var_indices`` -- a list of integers `\geq 0` - OUTPUT: - - a QuadraticForm + OUTPUT: a :class:`QuadraticForm` EXAMPLES:: @@ -255,24 +244,23 @@ def extract_variables(QF, var_indices): def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! - """ - Perform the substitution `x_i --> x_i + c*x_j` (replacing the - original form if the in_place flag is True). + r""" + Perform the substitution `x_i \longmapsto x_i + c\cdot x_j` (replacing the + original form if the ``in_place`` flag is True). INPUT: - - `c` -- an element of Q.base_ring() + - ``c`` -- an element of ``self.base_ring()`` - - `i`, `j` -- integers >= 0 + - ``i``, ``j`` -- integers `\geq 0` OUTPUT: - a QuadraticForm (by default, otherwise none) + a :class:`QuadraticForm` (by default, otherwise none) EXAMPLES:: - sage: Q = QuadraticForm(ZZ, 4, range(1,11)) - sage: Q + sage: Q = QuadraticForm(ZZ, 4, range(1,11)); Q Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 4 ] [ * 5 6 7 ] @@ -288,8 +276,7 @@ def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! :: - sage: R = QuadraticForm(ZZ, 4, range(1,11)) - sage: R + sage: R = QuadraticForm(ZZ, 4, range(1,11)); R Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 2 3 4 ] [ * 5 6 7 ] @@ -298,8 +285,7 @@ def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! :: - sage: M = Matrix(ZZ, 4, 4, [1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1]) - sage: M + sage: M = Matrix(ZZ, 4, 4, [1,0,0,1, 0,1,0,0, 0,0,1,0, 0,0,0,1]); M [1 0 0 1] [0 1 0 0] [0 0 1 0] @@ -310,7 +296,6 @@ def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! [ * 5 6 9 ] [ * * 8 12 ] [ * * * 15 ] - """ if not in_place: Q = self.parent()(self.base_ring(), self.dim(), self.coefficients()) @@ -332,25 +317,24 @@ def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! def add_symmetric(self, c, i, j, in_place=False): - """ - Performs the substitution `x_j --> x_j + c*x_i`, which has the + r""" + Perform the substitution `x_j \longmapsto x_j + c\cdot x_i`, which has the effect (on associated matrices) of symmetrically adding - `c * j`-th row/column to the `i`-th row/column. + `c` times the `j`-th row/column to the `i`-th row/column. NOTE: This is meant for compatibility with previous code, which implemented a matrix model for this class. It is used - in the local_normal_form() method. - + in the method :meth:`local_normal_form`. INPUT: - - `c` -- an element of Q.base_ring() + - ``c`` -- an element of ``self.base_ring()`` - - `i`, `j` -- integers >= 0 + - ``i``, ``j`` -- integers `\geq 0` OUTPUT: - a QuadraticForm (by default, otherwise none) + a :class:`QuadraticForm` (by default, otherwise none) EXAMPLES:: @@ -367,7 +351,8 @@ def add_symmetric(self, c, i, j, in_place=False): sage: Q.add_symmetric(-3/2, 2, 0) # ERROR: -3/2 isn't in the base ring ZZ Traceback (most recent call last): ... - RuntimeError: this coefficient cannot be coerced to an element of the base ring for the quadratic form + RuntimeError: this coefficient cannot be coerced + to an element of the base ring for the quadratic form :: diff --git a/src/sage/quadratic_forms/random_quadraticform.py b/src/sage/quadratic_forms/random_quadraticform.py index 368de819740..aa6a069a8b5 100644 --- a/src/sage/quadratic_forms/random_quadraticform.py +++ b/src/sage/quadratic_forms/random_quadraticform.py @@ -23,14 +23,12 @@ def random_quadraticform(R, n, rand_arg_list=[]): INPUT: - - `R` -- a ring. - - `n` -- an integer `\ge 0` + - ``R`` -- a ring + - ``n`` -- an integer `\ge 0` - ``rand_arg_list`` -- a list of at most 3 arguments which can be taken by ``R.random_element()``. - OUTPUT: - - A quadratic form over the ring `R`. + OUTPUT: A quadratic form over the ring `R`. EXAMPLES:: @@ -134,9 +132,7 @@ def random_ternaryqf(rand_arg_list=[]): - ``rand_arg_list`` -- a list of at most 3 arguments which can be taken by ``R.random_element()``. - OUTPUT: - - A ternary quadratic form. + OUTPUT: A ternary quadratic form. EXAMPLES:: diff --git a/src/sage/quadratic_forms/special_values.py b/src/sage/quadratic_forms/special_values.py index af80989032e..2ee775e053d 100644 --- a/src/sage/quadratic_forms/special_values.py +++ b/src/sage/quadratic_forms/special_values.py @@ -7,15 +7,18 @@ - :func:`quadratic_L_function__numerical` -- Numerical values of the Dirichlet L-functions of quadratic characters in the domain of convergence """ -from sage.combinat.combinat import bernoulli_polynomial +import sage.rings.abc + +from sage.arith.misc import (bernoulli, + factorial, + fundamental_discriminant, + kronecker as kronecker_symbol) from sage.misc.functional import denominator -from sage.arith.all import kronecker_symbol, bernoulli, factorial, fundamental_discriminant from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ -import sage.rings.abc -from sage.symbolic.constants import pi, I + # ---------------- The Gamma Function ------------------ @@ -35,6 +38,7 @@ def gamma__exact(n): sage: gamma__exact(1) 1 + sage: # needs sage.symbolic sage: gamma__exact(1/2) sqrt(pi) sage: gamma__exact(3/2) @@ -44,6 +48,7 @@ def gamma__exact(n): sage: gamma__exact(7/2) 15/8*sqrt(pi) + sage: # needs sage.symbolic sage: gamma__exact(-1/2) -2*sqrt(pi) sage: gamma__exact(-3/2) @@ -60,15 +65,18 @@ def gamma__exact(n): ... TypeError: you must give an integer or half-integer argument """ - from sage.all import sqrt n = QQ(n) if denominator(n) == 1: if n <= 0: return infinity return factorial(n - 1) - elif denominator(n) == 2: + + if denominator(n) == 2: # now n = 1/2 + an integer + from sage.misc.functional import sqrt + from sage.symbolic.constants import pi + ans = QQ.one() while n != QQ((1, 2)): if n < 0: @@ -80,14 +88,15 @@ def gamma__exact(n): ans *= sqrt(pi) return ans - else: - raise TypeError("you must give an integer or half-integer argument") + + raise TypeError("you must give an integer or half-integer argument") + # ------------- The Riemann Zeta Function -------------- def zeta__exact(n): r""" - Returns the exact value of the Riemann Zeta function + Return the exact value of the Riemann Zeta function The argument must be a critical value, namely either positive even or negative odd. @@ -99,8 +108,9 @@ def zeta__exact(n): Let us test the accuracy for negative special values:: sage: RR = RealField(100) - sage: for i in range(1,10): - ....: print("zeta({}): {}".format(1-2*i, RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i)))) + sage: for i in range(1,10): # needs sage.symbolic + ....: print("zeta({}): {}".format(1 - 2*i, + ....: RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i)))) zeta(-1): 0.00000000000000000000000000000 zeta(-3): 0.00000000000000000000000000000 zeta(-5): 0.00000000000000000000000000000 @@ -113,12 +123,13 @@ def zeta__exact(n): Let us test the accuracy for positive special values:: - sage: all(abs(RR(zeta__exact(2*i))-zeta(RR(2*i))) < 10**(-28) for i in range(1,10)) + sage: all(abs(RR(zeta__exact(2*i)) - zeta(RR(2*i))) < 10**(-28) # needs sage.symbolic + ....: for i in range(1,10)) True TESTS:: - sage: zeta__exact(4) + sage: zeta__exact(4) # needs sage.symbolic 1/90*pi^4 sage: zeta__exact(-3) 1/120 @@ -139,6 +150,8 @@ def zeta__exact(n): return bernoulli(1-n)/(n-1) elif n > 1: if (n % 2 == 0): + from sage.symbolic.constants import pi + return ZZ(-1)**(n//2 + 1) * ZZ(2)**(n-1) * pi**n * bernoulli(n) / factorial(n) else: raise TypeError("n must be a critical value (i.e. even > 0 or odd < 0)") @@ -147,6 +160,7 @@ def zeta__exact(n): elif n == 0: return QQ((-1, 2)) + # ---------- Dirichlet L-functions with quadratic characters ---------- def QuadraticBernoulliNumber(k, d): @@ -158,51 +172,57 @@ def QuadraticBernoulliNumber(k, d): Let us create a list of some odd negative fundamental discriminants:: - sage: test_set = [d for d in range(-163, -3, 4) if is_fundamental_discriminant(d)] + sage: test_set = [d for d in srange(-163, -3, 4) # needs sage.libs.pari + ....: if d.is_fundamental_discriminant()] In general, we have `B_{1, \chi_d} = -2 h/w` for odd negative fundamental discriminants:: - sage: all(QuadraticBernoulliNumber(1, d) == -len(BinaryQF_reduced_representatives(d)) for d in test_set) + sage: all(QuadraticBernoulliNumber(1, d) # needs sage.libs.pari + ....: == -len(BinaryQF_reduced_representatives(d)) + ....: for d in test_set) True REFERENCES: - [Iwa1972]_, pp 7-16. """ + from sage.combinat.combinat import bernoulli_polynomial + # Ensure the character is primitive d1 = fundamental_discriminant(d) f = abs(d1) # Make the (usual) k-th Bernoulli polynomial - x = PolynomialRing(QQ, 'x').gen() + x = PolynomialRing(QQ, 'x').gen() bp = bernoulli_polynomial(x, k) # Make the k-th quadratic Bernoulli number - total = sum([kronecker_symbol(d1, i) * bp(i/f) for i in range(f)]) - total *= (f ** (k-1)) + total = sum([kronecker_symbol(d1, i) * bp(i / f) for i in range(f)]) + total *= f**(k - 1) return total + def quadratic_L_function__exact(n, d): r""" - Returns the exact value of a quadratic twist of the Riemann Zeta function + Return the exact value of a quadratic twist of the Riemann Zeta function by `\chi_d(x) = \left(\frac{d}{x}\right)`. The input `n` must be a critical value. EXAMPLES:: - sage: quadratic_L_function__exact(1, -4) + sage: quadratic_L_function__exact(1, -4) # needs sage.libs.pari sage.symbolic 1/4*pi - sage: quadratic_L_function__exact(-4, -4) + sage: quadratic_L_function__exact(-4, -4) # needs sage.libs.pari 5/2 - sage: quadratic_L_function__exact(2, 1) + sage: quadratic_L_function__exact(2, 1) # needs sage.libs.pari sage.symbolic 1/6*pi^2 TESTS:: - sage: quadratic_L_function__exact(2, -4) + sage: quadratic_L_function__exact(2, -4) # needs sage.libs.pari Traceback (most recent call last): ... TypeError: n must be a critical value (i.e. odd > 0 or even <= 0) @@ -213,9 +233,8 @@ def quadratic_L_function__exact(n, d): - [IR1990]_ - [Was1997]_ """ - from sage.all import SR, sqrt if n <= 0: - return QuadraticBernoulliNumber(1-n,d)/(n-1) + return QuadraticBernoulliNumber(1-n, d)/(n-1) elif n >= 1: # Compute the kind of critical values (p10) if kronecker_symbol(fundamental_discriminant(d), -1) == 1: @@ -225,6 +244,10 @@ def quadratic_L_function__exact(n, d): # Compute the positive special values (p17) if ((n - delta) % 2 == 0): + from sage.misc.functional import sqrt + from sage.symbolic.constants import I, pi + from sage.symbolic.ring import SR + f = abs(fundamental_discriminant(d)) if delta == 0: GS = sqrt(f) @@ -234,7 +257,7 @@ def quadratic_L_function__exact(n, d): ans *= (2*pi/f)**n ans *= GS # Evaluate the Gauss sum here! =0 ans *= QQ.one()/(2 * I**delta) - ans *= QuadraticBernoulliNumber(n,d)/factorial(n) + ans *= QuadraticBernoulliNumber(n, d)/factorial(n) return ans else: if delta == 0: @@ -253,8 +276,10 @@ def quadratic_L_function__numerical(n, d, num_terms=1000): First, let us test several values for a given character:: sage: RR = RealField(100) - sage: for i in range(5): - ....: print("L({}, (-4/.)): {}".format(1+2*i, RR(quadratic_L_function__exact(1+2*i, -4)) - quadratic_L_function__numerical(RR(1+2*i),-4, 10000))) + sage: for i in range(5): # needs sage.symbolic + ....: print("L({}, (-4/.)): {}".format(1+2*i, + ....: RR(quadratic_L_function__exact(1+2*i, -4)) + ....: - quadratic_L_function__numerical(RR(1+2*i), -4, 10000))) L(1, (-4/.)): 0.000049999999500000024999996962707 L(3, (-4/.)): 4.99999970000003...e-13 L(5, (-4/.)): 4.99999922759382...e-21 @@ -264,7 +289,7 @@ def quadratic_L_function__numerical(n, d, num_terms=1000): This procedure fails for negative special values, as the Dirichlet series does not converge here:: - sage: quadratic_L_function__numerical(-3,-4, 10000) + sage: quadratic_L_function__numerical(-3, -4, 10000) Traceback (most recent call last): ... ValueError: the Dirichlet series does not converge here @@ -272,9 +297,12 @@ def quadratic_L_function__numerical(n, d, num_terms=1000): Test for several characters that the result agrees with the exact value, to a given accuracy :: - sage: for d in range(-20,0): # long time (2s on sage.math 2014) - ....: if abs(RR(quadratic_L_function__numerical(1, d, 10000) - quadratic_L_function__exact(1, d))) > 0.001: - ....: print("We have a problem at d = {}: exact = {}, numerical = {}".format(d, RR(quadratic_L_function__exact(1, d)), RR(quadratic_L_function__numerical(1, d)))) + sage: for d in range(-20,0): # long time (2s on sage.math 2014), needs sage.symbolic + ....: if abs(RR(quadratic_L_function__numerical(1, d, 10000) + ....: - quadratic_L_function__exact(1, d))) > 0.001: + ....: print("We have a problem at d = {}: exact = {}, numerical = {}".format(d, + ....: RR(quadratic_L_function__exact(1, d)), + ....: RR(quadratic_L_function__numerical(1, d)))) """ # Set the correct precision if it is given (for n). if isinstance(n.parent(), sage.rings.abc.RealField): @@ -288,6 +316,6 @@ def quadratic_L_function__numerical(n, d, num_terms=1000): d1 = fundamental_discriminant(d) ans = R.zero() - for i in range(1,num_terms): - ans += R(kronecker_symbol(d1,i) / R(i)**n) + for i in range(1, num_terms): + ans += R(kronecker_symbol(d1, i) / R(i)**n) return ans diff --git a/src/sage/quadratic_forms/ternary.pyx b/src/sage/quadratic_forms/ternary.pyx index 168ef3392bb..ddcfbfdb6a9 100644 --- a/src/sage/quadratic_forms/ternary.pyx +++ b/src/sage/quadratic_forms/ternary.pyx @@ -2,36 +2,32 @@ Helper code for ternary quadratic forms """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Gustavo Rama # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -from sage.rings.integer_ring import ZZ +from sage.arith.misc import gcd, inverse_mod, xgcd from sage.matrix.constructor import matrix, identity_matrix, diagonal_matrix -from sage.modules.free_module_element import vector -from sage.arith.all import inverse_mod, xgcd, gcd -from sage.quadratic_forms.extras import extend_to_primitive -from sage.rings.finite_rings.integer_mod import mod from sage.misc.prandom import randint +from sage.rings.finite_rings.integer_mod import mod +from sage.rings.integer_ring import ZZ -def red_mfact(a,b): +def red_mfact(a, b): """ - Auxiliary function for reduction that finds the reduction factor of a, b integers. + Auxiliary function for reduction that finds the reduction factor of integers `a`, `b`. INPUT: - - a, b integers - - OUTPUT: + - ``a``, ``b`` -- integers - Integer + OUTPUT: Integer EXAMPLES:: @@ -40,7 +36,6 @@ def red_mfact(a,b): 0 sage: red_mfact(-5, 100) 9 - """ if a: @@ -71,182 +66,172 @@ def _reduced_ternary_form_eisenstein_with_matrix(a1, a2, a3, a23, a13, a12): True sage: Q(M) == Qr True - - """ - M = identity_matrix(3) - loop=1 + loop = True while loop: - # adjust - v=a1+a2+a23+a13+a12 - if (v<0): - M*=matrix(ZZ,3,[1,0,1,0,1,1,0,0,1]) - a3+=v - a23+=a12+2*a2 - a13+=a12+2*a1 + v = a1+a2+a23+a13+a12 + if v < 0: + M *= matrix(ZZ, 3, [1, 0, 1, 0, 1, 1, 0, 0, 1]) + a3 += v + a23 += a12+2*a2 + a13 += a12+2*a1 # cuadred 12 - m=red_mfact(a1,a12) - M*=matrix(ZZ,3,[1,m,0,0,1,0,0,0,1]) - t=a1*m - a12+=t - a2+=a12*m - a12+=t - a23+=a13*m + m = red_mfact(a1, a12) + M *= matrix(ZZ, 3, [1, m, 0, 0, 1, 0, 0, 0, 1]) + t = a1*m + a12 += t + a2 += a12*m + a12 += t + a23 += a13*m # cuadred 23 - m=red_mfact(a2,a23) - M*=matrix(ZZ,3,[1,0,0,0,1,m,0,0,1]) - t=a2*m - a23+=t - a3+=a23*m - a23+=t - a13+=a12*m + m = red_mfact(a2, a23) + M *= matrix(ZZ, 3, [1, 0, 0, 0, 1, m, 0, 0, 1]) + t = a2*m + a23 += t + a3 += a23*m + a23 += t + a13 += a12*m # cuadred 13 - m=red_mfact(a1,a13) - M*=matrix(ZZ,3,[1,0,m,0,1,0,0,0,1]) - t=a1*m - a13+=t - a3+=a13*m - a13+=t - a23+=a12*m + m = red_mfact(a1, a13) + M *= matrix(ZZ, 3, [1, 0, m, 0, 1, 0, 0, 0, 1]) + t = a1*m + a13 += t + a3 += a13*m + a13 += t + a23 += a12*m # order 12 if a1 > a2 or (a1 == a2 and abs(a23) > abs(a13)): - M*=matrix(ZZ,3,[0,-1,0,-1,0,0,0,0,-1]) - [a1,a2]=[a2,a1] - [a13,a23]=[a23,a13] + M *= matrix(ZZ, 3, [0, -1, 0, -1, 0, 0, 0, 0, -1]) + [a1, a2] = [a2, a1] + [a13, a23] = [a23, a13] # order 23 if a2 > a3 or (a2 == a3 and abs(a13) > abs(a12)): - M*=matrix(ZZ,3,[-1,0,0,0,0,-1,0,-1,0]) - [a2,a3]=[a3,a2] - [a13,a12]=[a12,a13] + M *= matrix(ZZ, 3, [-1, 0, 0, 0, 0, -1, 0, -1, 0]) + [a2, a3] = [a3, a2] + [a13, a12] = [a12, a13] # order 12 if a1 > a2 or (a1 == a2 and abs(a23) > abs(a13)): - M*=matrix(ZZ,3,[0,-1,0,-1,0,0,0,0,-1]) - [a1,a2]=[a2,a1] - [a13,a23]=[a23,a13] + M *= matrix(ZZ, 3, [0, -1, 0, -1, 0, 0, 0, 0, -1]) + [a1, a2] = [a2, a1] + [a13, a23] = [a23, a13] # signs - if (a23*a13*a12>0): + if a23*a13*a12 > 0: # a23, a13, a12 positive - if (a23<0): - M*=diagonal_matrix([-1,1,1]) - a23=-a23 - if (a13<0): - M*=diagonal_matrix([1,-1,1]) - a13=-a13 - if (a12<0): - M*=diagonal_matrix([1,1,-1]) - a12=-a12 + if a23 < 0: + M *= diagonal_matrix([-1, 1, 1]) + a23 = -a23 + if a13 < 0: + M *= diagonal_matrix([1, -1, 1]) + a13 = -a13 + if a12 < 0: + M *= diagonal_matrix([1, 1, -1]) + a12 = -a12 else: # a23, a13, a12 nonpositive - [s1,s2,s3]=[(a23>0),(a13>0),(a12>0)] - if ((s1+s2+s3)%2): - if (a23==0): - s1=1 + [s1, s2, s3] = [a23 > 0, a13 > 0, a12 > 0] + if (s1+s2+s3) % 2: + if a23 == 0: + s1 = 1 else: - if (a13==0): - s2=1 + if a13 == 0: + s2 = 1 else: - if (a12==0): - s3=1 + if a12 == 0: + s3 = 1 if s1: - M*=diagonal_matrix([-1,1,1]) - a23=-a23 + M *= diagonal_matrix([-1, 1, 1]) + a23 = -a23 if s2: - M*=diagonal_matrix([1,-1,1]) - a13=-a13 + M *= diagonal_matrix([1, -1, 1]) + a13 = -a13 if s3: - M*=diagonal_matrix([1,1,-1]) - a12=-a12 - - loop = not (abs(a23) <= a2 and abs(a13) <= a1 and abs(a12) <= a1 and a1+a2+a23+a13+a12>=0) - - -################ -################ - + M *= diagonal_matrix([1, 1, -1]) + a12 = -a12 + loop = not (abs(a23) <= a2 and abs(a13) <= a1 and abs(a12) <= a1 and a1+a2+a23+a13+a12 >= 0) # adj 3 if a1+a2+a23+a13+a12 == 0 and 2*a1+2*a13+a12 > 0: - M*=matrix(ZZ,3,[-1,0,1,0,-1,1,0,0,1]) + M *= matrix(ZZ, 3, [-1, 0, 1, 0, -1, 1, 0, 0, 1]) # a3 += a1+a2+a23+a13+a12 - a23=-2*a2-a23-a12 - a13=-2*a1-a13-a12 + a23 = -2*a2-a23-a12 + a13 = -2*a1-a13-a12 # adj 5.12 if a1 == -a12 and a13 != 0: - M*=matrix(ZZ,3,[-1,-1,0,0,-1,0,0,0,1]) - #a2 += a1+a12 - a23=-a23-a13 - a13=-a13 - a12=-a12 # = 2*a1+a12 + M *= matrix(ZZ, 3, [-1, -1, 0, 0, -1, 0, 0, 0, 1]) + # a2 += a1+a12 + a23 = -a23-a13 + a13 = -a13 + a12 = -a12 # = 2*a1+a12 # adj 5.13 if a1 == -a13 and a12 != 0: - M*=matrix(ZZ,3,[-1,0,-1,0,1,0,0,0,-1]) + M *= matrix(ZZ, 3, [-1, 0, -1, 0, 1, 0, 0, 0, -1]) # a3 += a1+a13 - a23=-a23-a12 - a13=-a13 # = 2*a1+a13 - a12=-a12 + a23 = -a23-a12 + a13 = -a13 # = 2*a1+a13 + a12 = -a12 # adj 5.23 if a2 == -a23 and a12 != 0: - M*=matrix(ZZ,3,[1,0,0,0,-1,-1,0,0,-1]) + M *= matrix(ZZ, 3, [1, 0, 0, 0, -1, -1, 0, 0, -1]) # a3 += a2+a23 - a23=-a23 # = 2*a2+a23 - a13=-a13-a12 - a12=-a12 + a23 = -a23 # = 2*a2+a23 + a13 = -a13-a12 + a12 = -a12 # adj 4.12 if a1 == a12 and a13 > 2*a23: - M*=matrix(ZZ,3,[-1,-1,0,0,1,0,0,0,-1]) + M *= matrix(ZZ, 3, [-1, -1, 0, 0, 1, 0, 0, 0, -1]) # a 2 += a1-a12 a23 = -a23 + a13 # a12 = 2*a1 - a12 # adj 4.13 if a1 == a13 and a12 > 2*a23: - M*=matrix(ZZ,3,[-1,0,-1,0,-1,0,0,0,1]) + M *= matrix(ZZ, 3, [-1, 0, -1, 0, -1, 0, 0, 0, 1]) # a3 += a1-a13 a23 = -a23 + a12 # a13 = 2*a1 - a13 # adj 4.23 if a2 == a23 and a12 > 2*a13: - M*=matrix(ZZ,3,[-1,0,0,0,-1,-1,0,0,1]) + M *= matrix(ZZ, 3, [-1, 0, 0, 0, -1, -1, 0, 0, 1]) # a3 += a2-a23 # a23 = 2*a2 - a23 a13 = -a13 + a12 # order 12 if a1 == a2 and abs(a23) > abs(a13): - M*=matrix(ZZ,3,[0,-1,0,-1,0,0,0,0,-1]) - [a1,a2]=[a2,a1] - [a13,a23]=[a23,a13] + M *= matrix(ZZ, 3, [0, -1, 0, -1, 0, 0, 0, 0, -1]) + [a1, a2] = [a2, a1] + [a13, a23] = [a23, a13] # order 23 if a2 == a3 and abs(a13) > abs(a12): - M*=matrix(ZZ,3,[-1,0,0,0,0,-1,0,-1,0]) - [a13,a12]=[a12,a13] + M *= matrix(ZZ, 3, [-1, 0, 0, 0, 0, -1, 0, -1, 0]) + [a13, a12] = [a12, a13] # order 12 if a1 == a2 and abs(a23) > abs(a13): - M*=matrix(ZZ,3,[0,-1,0,-1,0,0,0,0,-1]) - [a13,a23]=[a23,a13] + M *= matrix(ZZ, 3, [0, -1, 0, -1, 0, 0, 0, 0, -1]) + [a13, a23] = [a23, a13] return (a1, a2, a3, a23, a13, a12), M @@ -267,124 +252,114 @@ def _reduced_ternary_form_eisenstein_without_matrix(a1, a2, a3, a23, a13, a12): sage: Qr = TernaryQF(qr) sage: Qr.is_eisenstein_reduced() True - """ - - loop=1 + loop = True while loop: # adjust - v=a1+a2+a23+a13+a12 - if (v<0): - a3+=v - a23+=a12+2*a2 - a13+=a12+2*a1 + v = a1+a2+a23+a13+a12 + if v < 0: + a3 += v + a23 += a12+2*a2 + a13 += a12+2*a1 # cuadred 12 - m=red_mfact(a1,a12) - t=a1*m - a12+=t - a2+=a12*m - a12+=t - a23+=a13*m + m = red_mfact(a1, a12) + t = a1*m + a12 += t + a2 += a12*m + a12 += t + a23 += a13*m # cuadred 23 - m=red_mfact(a2,a23) - t=a2*m - a23+=t - a3+=a23*m - a23+=t - a13+=a12*m + m = red_mfact(a2, a23) + t = a2*m + a23 += t + a3 += a23*m + a23 += t + a13 += a12*m # cuadred 13 - m=red_mfact(a1,a13) - t=a1*m - a13+=t - a3+=a13*m - a13+=t - a23+=a12*m + m = red_mfact(a1, a13) + t = a1*m + a13 += t + a3 += a13*m + a13 += t + a23 += a12*m # order 12 if a1 > a2 or (a1 == a2 and abs(a23) > abs(a13)): - [a1,a2]=[a2,a1] - [a13,a23]=[a23,a13] + [a1, a2] = [a2, a1] + [a13, a23] = [a23, a13] # order 23 if a2 > a3 or (a2 == a3 and abs(a13) > abs(a12)): - [a2,a3]=[a3,a2] - [a13,a12]=[a12,a13] + [a2, a3] = [a3, a2] + [a13, a12] = [a12, a13] # order 12 if a1 > a2 or (a1 == a2 and abs(a23) > abs(a13)): - [a1,a2]=[a2,a1] - [a13,a23]=[a23,a13] + [a1, a2] = [a2, a1] + [a13, a23] = [a23, a13] # signs if a23*a13*a12 > 0: # a23, a13, a12 positive - if (a23<0): - a23=-a23 - if (a13<0): - a13=-a13 - if (a12<0): - a12=-a12 + if a23 < 0: + a23 = -a23 + if a13 < 0: + a13 = -a13 + if a12 < 0: + a12 = -a12 else: # a23, a13, a12 nonpositive - [s1,s2,s3]=[(a23>0),(a13>0),(a12>0)] - if ((s1+s2+s3)%2): - if (a23==0): - s1=1 - else: - if (a13==0): - s2=1 - else: - if (a12==0): - s3=1 + [s1, s2, s3] = [a23 > 0, a13 > 0, a12 > 0] + if (s1+s2+s3) % 2: + if a23 == 0: + s1 = 1 + elif a13 == 0: + s2 = 1 + elif a12 == 0: + s3 = 1 if s1: - a23=-a23 + a23 = -a23 if s2: - a13=-a13 + a13 = -a13 if s3: - a12=-a12 + a12 = -a12 loop = not (abs(a23) <= a2 and abs(a13) <= a1 and abs(a12) <= a1 and a1+a2+a23+a13+a12 >= 0) - -################ -################ - - - # adj 3 if a1+a2+a23+a13+a12 == 0 and 2*a1+2*a13+a12 > 0: # a3 += a1+a2+a23+a13+a12 - a23=-2*a2-a23-a12 - a13=-2*a1-a13-a12 + a23 = -2*a2-a23-a12 + a13 = -2*a1-a13-a12 # adj 5.12 if a1 == -a12 and a13 != 0: - #a2 += a1+a12 - a23=-a23-a13 - a13=-a13 - a12=-a12 # = 2*a1+a12 + # a2 += a1+a12 + a23 = -a23-a13 + a13 = -a13 + a12 = -a12 # = 2*a1+a12 # adj 5.13 if a1 == -a13 and a12 != 0: # a3 += a1+a13 - a23=-a23-a12 - a13=-a13 # = 2*a1+a13 - a12=-a12 + a23 = -a23-a12 + a13 = -a13 # = 2*a1+a13 + a12 = -a12 # adj 5.23 if a2 == -a23 and a12 != 0: # a3 += a2+a23 - a23=-a23 # = 2*a2+a23 - a13=-a13-a12 - a12=-a12 + a23 = -a23 # = 2*a2+a23 + a13 = -a13-a12 + a12 = -a12 # adj 4.12 if a1 == a12 and a13 > 2*a23: @@ -406,23 +381,23 @@ def _reduced_ternary_form_eisenstein_without_matrix(a1, a2, a3, a23, a13, a12): # order 12 if a1 == a2 and abs(a23) > abs(a13): - [a1,a2]=[a2,a1] - [a13,a23]=[a23,a13] + [a1, a2] = [a2, a1] + [a13, a23] = [a23, a13] # order 23 if a2 == a3 and abs(a13) > abs(a12): - [a13,a12]=[a12,a13] + [a13, a12] = [a12, a13] # order 12 if a1 == a2 and abs(a23) > abs(a13): - [a13,a23]=[a23,a13] + [a13, a23] = [a23, a13] return a1, a2, a3, a23, a13, a12 def primitivize(long long v0, long long v1, long long v2, p): """ - Given a 3-tuple v not singular mod p, it returns a primitive 3-tuple version of v mod p. + Given a 3-tuple `v` not singular mod `p`, return a primitive 3-tuple version of `v` mod `p`. EXAMPLES:: @@ -431,20 +406,19 @@ def primitivize(long long v0, long long v1, long long v2, p): (3, 2, 1) sage: primitivize(12, 13, 15, 5) (4, 1, 0) - """ - - if v2%p != 0: + if v2 % p: v2_inv = inverse_mod(v2, p) - return v2_inv*v0%p, v2_inv*v1%p, 1 - elif v1%p != 0: - return inverse_mod(v1, p)*v0%p, 1, 0 + return v2_inv*v0 % p, v2_inv*v1 % p, 1 + elif v1 % p: + return inverse_mod(v1, p)*v0 % p, 1, 0 else: return 1, 0, 0 + def evaluate(a, b, c, r, s, t, v): """ - Function to evaluate the ternary quadratic form (a, b, c, r, s, t) in a 3-tuple v. + Function to evaluate the ternary quadratic form `(a, b, c, r, s, t)` in a 3-tuple `v`. EXAMPLES:: @@ -455,11 +429,10 @@ def evaluate(a, b, c, r, s, t, v): 1105 sage: evaluate(1, 2, 3, -1, 0, 0, v) 1105 - """ - return a*v[0]**2+b*v[1]**2+c*v[2]**2+r*v[2]*v[1]+s*v[2]*v[0]+t*v[1]*v[0] + def _find_zeros_mod_p_2(a, b, c, r, s, t): """ Function to find the zeros mod 2 of a ternary quadratic form. @@ -477,64 +450,61 @@ def _find_zeros_mod_p_2(a, b, c, r, s, t): 2 sage: Q((1, 1, 1)) 4 - """ - - zeros=[] - v=(1,0,0) - if evaluate(a,b,c,r,s,t,v)%2==0: + zeros = [] + v = (1, 0, 0) + if evaluate(a, b, c, r, s, t, v) % 2 == 0: zeros.append(v) for i in range(2): - v=(i,1,0) - if evaluate(a,b,c,r,s,t,v)%2==0: + v = (i, 1, 0) + if evaluate(a, b, c, r, s, t, v) % 2 == 0: zeros.append(v) for i in range(2): for j in range(2): - v=(i,j,1) - if evaluate(a,b,c,r,s,t,v)%2==0: + v = (i, j, 1) + if evaluate(a, b, c, r, s, t, v) % 2 == 0: zeros.append(v) return zeros + def pseudorandom_primitive_zero_mod_p(a, b, c, r, s, t, p): """ - Find a zero of the form (a, b, 1) of the ternary quadratic form given by the coefficients (a, b, c, r, s, t) - mod p, where p is a odd prime that doesn't divide the discriminant. + Find a zero of the form `(a, b, 1)` of the ternary quadratic form given by the coefficients `(a, b, c, r, s, t)` + mod `p`, where `p` is a odd prime that doesn't divide the discriminant. EXAMPLES:: sage: Q = TernaryQF([1, 2, 2, -1, 0, 0]) sage: p = 1009 sage: from sage.quadratic_forms.ternary import pseudorandom_primitive_zero_mod_p - sage: v = pseudorandom_primitive_zero_mod_p(1, 2, 2, -1, 0, 0, p) - sage: v[2] + sage: v = pseudorandom_primitive_zero_mod_p(1, 2, 2, -1, 0, 0, p) # needs sage.libs.pari + sage: v[2] # needs sage.libs.pari 1 - sage: Q(v)%p + sage: Q(v)%p # needs sage.libs.pari 0 - """ - - #[a,b,c,r,s,t] = Q.coefficients() + # [a, b, c, r, s, t] = Q.coefficients() while True: - r1 = randint(0,p-1) - r2 = randint(0,p-1) - alpha = (b*r1**2+t*r1+a)%p + r1 = randint(0, p-1) + r2 = randint(0, p-1) + alpha = (b*r1**2+t*r1+a) % p if alpha != 0: - beta = (2*b*r1*r2+t*r2+r*r1+s)%p - gamma = (b*r2**2+r*r2+c)%p + beta = (2*b*r1*r2+t*r2+r*r1+s) % p + gamma = (b*r2**2+r*r2+c) % p disc = beta**2-4*alpha*gamma - if mod(disc,p).is_square(): + if mod(disc, p).is_square(): + + z = (-beta+mod(disc, p).sqrt().lift())*(2*alpha).inverse_mod(p) + return z % p, (r1*z+r2) % p, 1 - z = (-beta+mod(disc,p).sqrt().lift())*(2*alpha).inverse_mod(p) - #return vector((z,r1*z+r2,1))%p - return z%p, (r1*z+r2)%p, 1 def _find_zeros_mod_p_odd(long long a, long long b, long long c, long long r, long long s, long long t, long long p, v): """ - Find the zeros mod p, where p is an odd prime, of a ternary quadratic form given by its coefficients and a given zero of the form v. + Find the zeros mod `p`, where `p` is an odd prime, of a ternary quadratic form given by its coefficients and a given zero of the form `v`. - The prime p does not divide the discriminant of the form. + The prime `p` does not divide the discriminant of the form. EXAMPLES:: @@ -564,52 +534,52 @@ def _find_zeros_mod_p_odd(long long a, long long b, long long c, long long r, lo cdef long long x0 cdef long long y0 - zeros=[v] - x0=v[0] - y0=v[1] - more=False - for i in xrange(p): - a_i=(a*x0**2+b*i**2-2*b*i*y0+b*y0**2-t*i*x0+t*x0*y0-2*a*x0+t*i-t*y0+s*x0-r*i+r*y0+a+c-s)%p - #b_i=(-2*b*i**2+2*b*i*y0+t*i*x0+2*a*x0-2*t*i+t*y0+r*i-2*a+s)%p - if a_i==0: - w=((x0-1)%p,(y0-i)%p,1) - if w==v: - more=True + zeros = [v] + x0 = v[0] + y0 = v[1] + more = False + for i in range(p): + a_i = (a*x0**2+b*i**2-2*b*i*y0+b*y0**2-t*i*x0+t*x0*y0-2*a*x0+t*i-t*y0+s*x0-r*i+r*y0+a+c-s) % p + # b_i=(-2*b*i**2+2*b*i*y0+t*i*x0+2*a*x0-2*t*i+t*y0+r*i-2*a+s)%p + if a_i == 0: + w = ((x0-1) % p, (y0-i) % p, 1) + if w == v: + more = True else: zeros.append(w) else: - c_i=(b*i**2+t*i+a)%p - l=c_i*ZZ(a_i).inverse_mod(p) - w = primitivize(l*(x0-1)+1, l*(y0-i)+i, l , p) - if (w[0]==v[0] and w[1]==v[1] and w[2]==v[2]): - more=True + c_i = (b*i**2+t*i+a) % p + l = c_i*ZZ(a_i).inverse_mod(p) + w = primitivize(l*(x0-1)+1, l*(y0-i)+i, l, p) + if w[0] == v[0] and w[1] == v[1] and w[2] == v[2]: + more = True else: zeros.append(w) if more: - a_inf=(a*x0**2+b*y0**2+t*x0*y0-2*b*y0-t*x0+s*x0+r*y0+b+c-r)%p - #b_inf=(2*b*y0+t*x0-2*b+r)%p - if a_inf==0: - w=(x0%p,(y0-1)%p,1) + a_inf = (a*x0**2+b*y0**2+t*x0*y0-2*b*y0-t*x0+s*x0+r*y0+b+c-r) % p + # b_inf=(2*b*y0+t*x0-2*b+r)%p + if a_inf == 0: + w = (x0 % p, (y0-1) % p, 1) zeros.append(w) else: - c_inf=b%p - l=c_inf*ZZ(a_inf).inverse_mod(p) + c_inf = b % p + l = c_inf*ZZ(a_inf).inverse_mod(p) w = primitivize(l*x0, l*(y0-1)+1, l, p) zeros.append(w) return zeros - def _find_zeros_mod_p(a, b, c, r, s, t, p): """ Find the zeros mod `p` of the ternary quadratic form. - The quadratic form is given by the coefficients (a, b, c, r, s, t), + The quadratic form is given by the coefficients `(a, b, c, r, s, t)`, and `p` is a prime that does not divide the discriminant of the form. EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.quadratic_forms.ternary import _find_zeros_mod_p sage: Q = TernaryQF([1, 2, 2, -1, 0, 0]) sage: p = 1009 @@ -624,14 +594,11 @@ def _find_zeros_mod_p(a, b, c, r, s, t, p): sage: zeros_2 = _find_zeros_mod_p(1, 2, 2, -1, 0, 0, 2) sage: zeros_2 [(0, 1, 0), (0, 0, 1), (1, 1, 1)] - """ - - if p==2: + if p == 2: return _find_zeros_mod_p_2(a, b, c, r, s, t) - else: - v = pseudorandom_primitive_zero_mod_p(a, b, c, r, s, t, p) - return _find_zeros_mod_p_odd(a, b, c, r, s, t, p, v) + v = pseudorandom_primitive_zero_mod_p(a, b, c, r, s, t, p) + return _find_zeros_mod_p_odd(a, b, c, r, s, t, p, v) def _find_all_ternary_qf_by_level_disc(long long N, long long d): @@ -659,10 +626,7 @@ def _find_all_ternary_qf_by_level_disc(long long N, long long d): Traceback (most recent call last): ... ValueError: There are no ternary forms of this level and discriminant - - """ - cdef long long a cdef long long b cdef long long c @@ -670,7 +634,6 @@ def _find_all_ternary_qf_by_level_disc(long long N, long long d): cdef long long s cdef long long t cdef long long m - cdef long long mu cdef long long g cdef long long u cdef long long v @@ -679,54 +642,45 @@ def _find_all_ternary_qf_by_level_disc(long long N, long long d): cdef double a_max cdef double r_max cdef double b_max - cdef long long stu2 - cdef long long mg + l = [] - - l=[] - - if (4*d)%N!=0: + if (4*d) % N: raise ValueError("There are no ternary forms of this level and discriminant") else: - m=4*d//N + m = 4*d//N - if (N**2)%d!=0: + if (N**2) % d: raise ValueError("There are no ternary forms of this level and discriminant") - else: - mu=N*N//d - - m_2=m%2 - mu_2=mu%2 - a=1 - a_max=(d/2.)**(1/3.) - while a<=a_max: + a = 1 + a_max = (d/2.)**(1/3.) + while a <= a_max: - [g,u,v]=xgcd(4*a,m) - g1=(ZZ(g).squarefree_part()*g).sqrtrem()[0] - t=0 - while t<=a: + [g, u, v] = xgcd(4*a, m) + g1 = (ZZ(g).squarefree_part()*g).sqrtrem()[0] + t = 0 + while t <= a: - alpha=max(a,m/4/a) - b=alpha+((((u*t*t//g)-alpha))%(m//g)) - b_max=(d/2.0/a)**(1/2.) - while b<=b_max: + alpha = max(a, m/4/a) + b = alpha+((((u*t*t//g)-alpha)) % (m//g)) + b_max = (d/2.0/a)**(1/2.) + while b <= b_max: - s=0 - beta=g//gcd(g,2*t) - while s<=a: + s = 0 + beta = g//gcd(g, 2*t) + while s <= a: - r = -b+((((2*s*t*u//g)+b))%(m//g)) - if s*t==0: - r_max=0 + r = -b+((((2*s*t*u//g)+b)) % (m//g)) + if s*t == 0: + r_max = 0 else: - r_max=b - while r<=r_max: + r_max = b + while r <= r_max: - if (d-r*s*t+a*r*r+b*s*s)%(4*a*b-t**2)==0: + if (d-r*s*t+a*r*r+b*s*s) % (4*a*b-t**2) == 0: - c=(d-r*s*t+a*r*r+b*s*s)//(4*a*b-t**2) + c = (d-r*s*t+a*r*r+b*s*s)//(4*a*b-t**2) if r <= 0: is_reduced = True if r < -b: @@ -746,11 +700,11 @@ def _find_all_ternary_qf_by_level_disc(long long N, long long d): elif b == -r and t != 0: is_reduced = False if is_reduced: - m_q=gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, -2*r*t+4*b*s, -2*r*s+4*c*t)) - if m_q==m: + m_q = gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, -2*r*t+4*b*s, -2*r*s+4*c*t)) + if m_q == m: l.append((ZZ(a), ZZ(b), ZZ(c), ZZ(r), ZZ(-s), ZZ(-t))) else: - is_reduced=True + is_reduced = True if not (b <= c and 0 <= a+b+r+s+t): is_reduced = False elif a == b and abs(r) > abs(s): @@ -766,19 +720,18 @@ def _find_all_ternary_qf_by_level_disc(long long N, long long d): elif b == r and t > 2*s: is_reduced = False if is_reduced: - m_q=gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, 2*r*t-4*b*s, 2*r*s-4*c*t)) - if m_q==m: + m_q = gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, 2*r*t-4*b*s, 2*r*s-4*c*t)) + if m_q == m: l.append((ZZ(a), ZZ(b), ZZ(c), ZZ(r), ZZ(s), ZZ(t))) - r+=(m//g) - s+=beta - b+=m//g - t+=g1 + r += (m//g) + s += beta + b += m//g + t += g1 - a+=1 + a += 1 return l - def _find_a_ternary_qf_by_level_disc(long long N, long long d): """ Find the coefficients of a reduced ternary quadratic form given its discriminant d and level N. @@ -803,9 +756,7 @@ def _find_a_ternary_qf_by_level_disc(long long N, long long d): Traceback (most recent call last): ... ValueError: There are no ternary forms of this level and discriminant - """ - cdef long long a cdef long long b cdef long long c @@ -813,7 +764,6 @@ def _find_a_ternary_qf_by_level_disc(long long N, long long d): cdef long long s cdef long long t cdef long long m - cdef long long mu cdef long long g cdef long long u cdef long long v @@ -822,50 +772,43 @@ def _find_a_ternary_qf_by_level_disc(long long N, long long d): cdef double a_max cdef double r_max cdef double b_max - cdef long long stu2 - cdef long long mg - if (4*d)%N: + if (4*d) % N: raise ValueError("There are no ternary forms of this level and discriminant") else: - m=4*d//N + m = 4*d//N - if (N**2)%d: + if (N**2) % d: raise ValueError("There are no ternary forms of this level and discriminant") - else: - mu=N*N//d - - m_2=m%2 - mu_2=mu%2 - a=1 - a_max=(d/2.)**(1/3.) - while a<=a_max: + a = 1 + a_max = (d/2.)**(1/3.) + while a <= a_max: - [g,u,v]=xgcd(4*a,m) - g1=(ZZ(g).squarefree_part()*g).sqrtrem()[0] - t=0 - while t<=a: + [g, u, v] = xgcd(4*a, m) + g1 = (ZZ(g).squarefree_part()*g).sqrtrem()[0] + t = 0 + while t <= a: - alpha=max(a,m/4/a) - b=alpha+((((u*t*t//g)-alpha))%(m//g)) - b_max=(d/2.0/a)**(1/2.) - while b<=b_max: + alpha = max(a, m/4/a) + b = alpha+((((u*t*t//g)-alpha)) % (m//g)) + b_max = (d/2.0/a)**(1/2.) + while b <= b_max: - s=0 - beta=g//gcd(g,2*t) - while s<=a: + s = 0 + beta = g//gcd(g, 2*t) + while s <= a: - r = -b+((((2*s*t*u//g)+b))%(m//g)) - if s*t==0: - r_max=0 + r = -b+((((2*s*t*u//g)+b)) % (m//g)) + if s*t == 0: + r_max = 0 else: - r_max=b - while r<=r_max: + r_max = b + while r <= r_max: - if (d-r*s*t+a*r*r+b*s*s)%(4*a*b-t**2)==0: + if (d-r*s*t+a*r*r+b*s*s) % (4*a*b-t**2) == 0: - c=(d-r*s*t+a*r*r+b*s*s)//(4*a*b-t**2) + c = (d-r*s*t+a*r*r+b*s*s)//(4*a*b-t**2) if r <= 0: is_reduced = True if r < -b: @@ -885,8 +828,8 @@ def _find_a_ternary_qf_by_level_disc(long long N, long long d): elif b == -r and t != 0: is_reduced = False if is_reduced: - m_q=gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, -2*r*t+4*b*s, -2*r*s+4*c*t)) - if m_q==m: + m_q = gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, -2*r*t+4*b*s, -2*r*s+4*c*t)) + if m_q == m: return ZZ(a), ZZ(b), ZZ(c), ZZ(r), ZZ(-s), ZZ(-t) else: is_reduced = True @@ -898,36 +841,34 @@ def _find_a_ternary_qf_by_level_disc(long long N, long long d): is_reduced = False elif a+b+r+s+t == 0 and 2*a+2*s+t > 0: is_reduced = False - elif a==t and s > 2*r: + elif a == t and s > 2*r: is_reduced = False - elif a == s and t>2*r: + elif a == s and t > 2*r: is_reduced = False elif b == r and t > 2*s: is_reduced = False if is_reduced: - m_q=gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, 2*r*t-4*b*s, 2*r*s-4*c*t)) - if m_q==m: + m_q = gcd((4*b*c-r**2, 4*a*c-s**2, 4*a*b-t**2, 2*s*t-4*a*r, 2*r*t-4*b*s, 2*r*s-4*c*t)) + if m_q == m: return ZZ(a), ZZ(b), ZZ(c), ZZ(r), ZZ(s), ZZ(t) - r+=(m//g) - s+=beta - b+=m//g - t+=g1 - - a+=1 + r += (m//g) + s += beta + b += m//g + t += g1 + a += 1 def extend(v): """ - Return the coefficients of a matrix M such that M has determinant gcd(v) and the first column is v. + Return the coefficients of a matrix `M` such that `M` has determinant gcd(`v`) and the first column is `v`. EXAMPLES:: sage: from sage.quadratic_forms.ternary import extend sage: v = (6, 4, 12) sage: m = extend(v) - sage: M = matrix(3, m) - sage: M + sage: M = matrix(3, m); M [ 6 1 0] [ 4 1 0] [12 0 1] @@ -942,9 +883,7 @@ def extend(v): [ 30 0 -7] sage: M.det() 2 - """ - b1 = xgcd(v[0], v[1]) b2 = xgcd(b1[1], b1[2]) b3 = xgcd(b1[0], v[2]) @@ -952,9 +891,9 @@ def extend(v): return v[0], -b1[2], -b2[1]*b3[2], v[1], b1[1], -b2[2]*b3[2], v[2], 0, b3[1] -def _find_p_neighbor_from_vec(a, b, c, r, s, t, p, v, mat = False): +def _find_p_neighbor_from_vec(a, b, c, r, s, t, p, v, mat=False): """ - Finds the coefficients of the reduced equivalent of the p-neighbor + Find the coefficients of the reduced equivalent of the p-neighbor of the ternary quadratic given by Q = (a, b, c, r, s, t) form associated to a given vector v satisfying: @@ -975,9 +914,9 @@ def _find_p_neighbor_from_vec(a, b, c, r, s, t, p, v, mat = False): sage: Q.disc() 29 sage: v = (9, 7, 1) - sage: v in Q.find_zeros_mod_p(11) + sage: v in Q.find_zeros_mod_p(11) # needs sage.libs.pari True - sage: q11, M = _find_p_neighbor_from_vec(1, 3, 3, -2, 0, -1, 11, v, mat = True) + sage: q11, M = _find_p_neighbor_from_vec(1, 3, 3, -2, 0, -1, 11, v, mat=True) sage: Q11 = TernaryQF(q11) sage: Q11 Ternary quadratic form with integer coefficients: @@ -990,9 +929,7 @@ def _find_p_neighbor_from_vec(a, b, c, r, s, t, p, v, mat = False): [ 0 -3/11 13/11] sage: Q(M) == Q11 True - """ - v0, w0, u0, v1, w1, u1, v2, w2, u2 = extend(v) m00 = 2*a*v0**2 + 2*b*v1**2 + 2*c*v2**2 + 2*r*v1*v2 + 2*s*v0*v2 + 2*t*v0*v1 @@ -1002,8 +939,7 @@ def _find_p_neighbor_from_vec(a, b, c, r, s, t, p, v, mat = False): m02 = 2*a*u0*v0 + 2*b*u1*v1 + 2*c*u2*v2 + r*u1*v2 + r*u2*v1 + s*u0*v2 + s*u2*v0 + t*u0*v1 + t*u1*v0 m12 = 2*a*u0*w0 + 2*b*u1*w1 + r*u2*w1 + s*u2*w0 + t*u0*w1 + t*u1*w0 - - if m02%p!=0: + if m02 % p: m0 = (-m00/m02/2) % p**2 m1 = (-m01/m02) % p @@ -1031,7 +967,7 @@ def _find_p_neighbor_from_vec(a, b, c, r, s, t, p, v, mat = False): else: return _reduced_ternary_form_eisenstein_without_matrix(ZZ(b00/2), ZZ(b11/2), ZZ(b22/2), ZZ(b12), ZZ(b02), ZZ(b01)) - if m01%p!=0: + if m01 % p: m0 = (-m00/m01/2) % p**2 m1 = (-m02/m01) % p @@ -1074,31 +1010,30 @@ def _basic_lemma_vec(a, b, c, r, s, t, n): (0, 1, 0) sage: Q(v) 2 - """ - if n == 1: return 0, 0, 0 - if a%n != 0: + if a % n: return 1, 0, 0 - elif b%n != 0: + elif b % n: return 0, 1, 0 - elif c%n != 0: + elif c % n: return 0, 0, 1 - if r%n != 0: + if r % n: return 0, 1, 1 - elif s%n != 0: + elif s % n: return 1, 0, 1 - elif t%n != 0: + elif t % n: return 1, 1, 0 raise ValueError("not primitive form") + def _basic_lemma(a, b, c, r, s, t, n): """ - Finds a number represented by the ternary quadratic form given by the coefficients (a, b, c, r, s, t) + Find a number represented by the ternary quadratic form given by the coefficients (a, b, c, r, s, t) and coprime to the prime n. EXAMPLES:: @@ -1107,24 +1042,22 @@ def _basic_lemma(a, b, c, r, s, t, n): sage: Q = TernaryQF([5, 2, 3, -1, 0, 0]) sage: _basic_lemma(5, 2, 3, -1, 0, 0, 5) 2 - """ - if n == 1: return 0 - if a%n != 0: + if a % n: return a - elif b%n != 0: + elif b % n: return b - elif c%n != 0: + elif c % n: return c - if r%n != 0: + if r % n: return b + c + r - elif s%n != 0: + elif s % n: return a + c + s - elif t%n != 0: + elif t % n: return a + b + t raise ValueError("not primitive form") diff --git a/src/sage/quadratic_forms/ternary_qf.py b/src/sage/quadratic_forms/ternary_qf.py index 7932c432779..6a08d00f26c 100644 --- a/src/sage/quadratic_forms/ternary_qf.py +++ b/src/sage/quadratic_forms/ternary_qf.py @@ -1,4 +1,4 @@ -""" +r""" Ternary quadratic form with integer coefficients AUTHOR: @@ -7,7 +7,7 @@ Based in code of Gonzalo Tornaria -The form `a*x^2 + b*y^2 + c*z^2 + r*yz + s*xz + t*xy` is stored as a tuple (a, b, c, r, s, t) of integers. +The form `a\cdot x^2 + b\cdot y^2 + c\cdot z^2 + r\cdot yz + s\cdot xz + t\cdot xy` is stored as a tuple ``(a, b, c, r, s, t)`` of integers. """ @@ -26,37 +26,42 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.sage_object import SageObject -from sage.rings.integer_ring import ZZ -from sage.arith.all import gcd, kronecker_symbol -from sage.quadratic_forms.quadratic_form import QuadraticForm +from sage.arith.misc import gcd, kronecker as kronecker_symbol from sage.matrix.constructor import matrix, identity_matrix -from sage.structure.element import is_Vector, is_Matrix -from sage.quadratic_forms.ternary import _reduced_ternary_form_eisenstein_with_matrix -from sage.quadratic_forms.ternary import _reduced_ternary_form_eisenstein_without_matrix, _find_zeros_mod_p_odd, _find_zeros_mod_p_2, _find_p_neighbor_from_vec, _basic_lemma -from sage.quadratic_forms.ternary import _find_all_ternary_qf_by_level_disc, _find_a_ternary_qf_by_level_disc from sage.misc.prandom import randint +from sage.quadratic_forms.quadratic_form import QuadraticForm +from sage.quadratic_forms.ternary import (_basic_lemma, + _find_a_ternary_qf_by_level_disc, + _find_all_ternary_qf_by_level_disc, + _find_p_neighbor_from_vec, + _find_zeros_mod_p_2, + _find_zeros_mod_p_odd, + _reduced_ternary_form_eisenstein_with_matrix, + _reduced_ternary_form_eisenstein_without_matrix) + from sage.rings.finite_rings.integer_mod import mod -from sage.rings.ring import is_Ring +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring import polygens +from sage.rings.ring import is_Ring +from sage.structure.element import is_Vector, is_Matrix +from sage.structure.sage_object import SageObject class TernaryQF(SageObject): - """ - The ``TernaryQF`` class represents a quadratic form in 3 variables with coefficients in Z. + r""" + The ``TernaryQF`` class represents a quadratic form in 3 variables with coefficients in `\ZZ`. INPUT: - - `v` -- a list or tuple of 6 entries: [a,b,c,r,s,t] + - ``v`` -- a list or tuple of 6 entries: ``[a,b,c,r,s,t]`` OUTPUT: - - the ternary quadratic form a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y. + - the ternary quadratic form `a\cdot x^2 + b\cdot y^2 + c\cdot z^2 + r\cdot y\cdot z + s\cdot x\cdot z + t\cdot x\cdot y`. EXAMPLES:: - sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]) - sage: Q + sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]); Q Ternary quadratic form with integer coefficients: [1 2 3] [4 5 6] @@ -66,8 +71,6 @@ class TernaryQF(SageObject): [1 187 9] [-85 8 -31] sage: TestSuite(TernaryQF).run() - - """ __slots__ = ['_a', '_b', '_c', '_r', '_s', '_t', '_automorphisms', '_number_of_automorphisms'] @@ -76,17 +79,16 @@ class TernaryQF(SageObject): def __init__(self, v): r""" - Creates the ternary quadratic form `a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y.` from the - tuple v=[a,b,c,r,s,t] over `\ZZ`. + Create the ternary quadratic form `a\cdot x^2 + b\cdot y^2 + c\cdot z^2 + r\cdot y\cdot z + s\cdot x\cdot z + t\cdot x\cdot y` from the + tuple ``v=[a,b,c,r,s,t]`` over `\ZZ`. INPUT: - - ``v`` -- 6-tuple of integers + - ``v`` -- 6-tuple of integers EXAMPLES:: - sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]) - sage: Q + sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]); Q Ternary quadratic form with integer coefficients: [1 2 3] [4 5 6] @@ -100,30 +102,31 @@ def __init__(self, v): self._number_of_automorphisms = None def coefficients(self): - """ - Return the list coefficients of the ternary quadratic form. + r""" + Return the list of coefficients of the ternary quadratic form. EXAMPLES:: - sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]) - sage: Q + sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]); Q Ternary quadratic form with integer coefficients: [1 2 3] [4 5 6] sage: Q.coefficients() (1, 2, 3, 4, 5, 6) - """ return self._a, self._b, self._c, self._r, self._s, self._t def coefficient(self, n): - """ - Return the n-th coefficient of the ternary quadratic form, with 0<=n<=5. + r""" + Return the `n`-th coefficient of the ternary quadratic form. + + INPUT: + + - ``n`` -- integer with `0 \leq n \leq 5`. EXAMPLES:: - sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]) - sage: Q + sage: Q = TernaryQF([1, 2, 3, 4, 5, 6]); Q Ternary quadratic form with integer coefficients: [1 2 3] [4 5 6] @@ -135,28 +138,25 @@ def coefficient(self, n): return self.coefficients()[n] def polynomial(self, names='x,y,z'): - """ + r""" Return the polynomial associated to the ternary quadratic form. EXAMPLES:: - sage: Q = TernaryQF([1, 1, 0, 2, -3, -1]) - sage: Q + sage: Q = TernaryQF([1, 1, 0, 2, -3, -1]); Q Ternary quadratic form with integer coefficients: [1 1 0] [2 -3 -1] - sage: p = Q.polynomial() - sage: p + sage: p = Q.polynomial(); p x^2 - x*y + y^2 - 3*x*z + 2*y*z sage: p.parent() Multivariate Polynomial Ring in x, y, z over Integer Ring - """ (x,y,z) = polygens(ZZ,names) - return self._a * x**2 + self._b* y**2 + self._c * z**2 + self._t * x*y + self._s * x*z + self._r * y*z + return self._a * x**2 + self._b * y**2 + self._c * z**2 + self._t * x*y + self._s * x*z + self._r * y*z def _repr_(self): - """ + r""" Display the quadratic form. EXAMPLES:: @@ -172,17 +172,25 @@ def _repr_(self): [0 0 0] """ rep = 'Ternary quadratic form with integer coefficients:\n' - rep+= '[' + str(self._a) + ' ' + str(self._b) + ' ' + str(self._c) + ']\n' - rep+= '[' + str(self._r) + ' ' + str(self._s) + ' ' + str(self._t) + ']' + rep += '[' + str(self._a) + ' ' + str(self._b) + ' ' + str(self._c) + ']\n' + rep += '[' + str(self._r) + ' ' + str(self._s) + ' ' + str(self._t) + ']' return rep def __call__(self, v): - """ - Evaluate this ternary quadratic form Q on a vector of 3 elements, or matrix of elements in Z, with 3 rows. If a vector is given then the output will be an integer Q(`v`), but if a matrix is given the output will be a ternary quadratic form if the matrix has 3 columns, or a quadratic form if not. The quadratic form in matrix notation will be: + r""" + Evaluate this ternary quadratic form `Q` on a vector of 3 elements, + or matrix of elements in Z, with 3 rows. + + OUTPUT: + + If a vector is given, then the output will be an integer `Q(v)`, + but if a matrix is given, the output will be a ternary quadratic form + if the matrix has 3 columns, or a quadratic form if not. + The quadratic form in matrix notation will be: .. MATH:: - Q' = v^t * Q * v. + Q' = v^t\cdot Q\cdot v. EXAMPLES:: @@ -225,14 +233,13 @@ def __call__(self, v): raise TypeError("presently we can only evaluate a quadratic form on a list, tuple, vector or matrix") def quadratic_form(self): - """ - Return the object QuadraticForm with the same coefficients as Q over ZZ. + r""" + Return a :class:`QuadraticForm` with the same coefficients as ``self`` over `\ZZ`. EXAMPLES:: sage: Q = TernaryQF([1, 2, 3, 1, 1, 1]) - sage: QF1 = Q.quadratic_form() - sage: QF1 + sage: QF1 = Q.quadratic_form(); QF1 Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 1 1 ] [ * 2 1 ] @@ -244,25 +251,23 @@ def quadratic_form(self): return QuadraticForm(ZZ, 3, [self._a, self._t, self._s, self._b, self._r, self._c]) def matrix(self): - """ + r""" Return the Hessian matrix associated to the ternary quadratic form. - That is, if Q is a ternary quadratic form, Q(x,y,z) = a*x^2 + b*y^2 + c*z^2 + r*y*z + s*x*z + t*x*y, - then the Hessian matrix associated to Q is + That is, if `Q` is a ternary quadratic form, `Q(x,y,z) = a\cdot x^2 + b\cdot y^2 + c\cdot z^2 + r\cdot y\cdot z + s\cdot x\cdot z + t\cdot x\cdot y`, + then the Hessian matrix associated to `Q` is :: - [2*a t s] - [t 2*b r] - [s r 2*c] + [2\cdot a t s] + [t 2\cdot b r] + [s r 2\cdot c] EXAMPLES:: - sage: Q = TernaryQF([1,1,2,0,-1,4]) - sage: Q + sage: Q = TernaryQF([1,1,2,0,-1,4]); Q Ternary quadratic form with integer coefficients: [1 1 2] [0 -1 4] - sage: M = Q.matrix() - sage: M + sage: M = Q.matrix(); M [ 2 4 -1] [ 4 2 0] [-1 0 4] @@ -276,7 +281,7 @@ def matrix(self): return M def disc(self): - """ + r""" Return the discriminant of the ternary quadratic form, this is the determinant of the matrix divided by 2. EXAMPLES:: @@ -411,8 +416,7 @@ def __neg__(self): EXAMPLES:: - sage: Q = TernaryQF([1, 1, 2, -2, 0, -1]) - sage: Q + sage: Q = TernaryQF([1, 1, 2, -2, 0, -1]); Q Ternary quadratic form with integer coefficients: [1 1 2] [-2 0 -1] @@ -421,7 +425,7 @@ def __neg__(self): [-1 -1 -2] [2 0 1] sage: Q = TernaryQF([0, 0, 0, 0, 0, 0]) - sage: Q==-Q + sage: Q == -Q True """ return TernaryQF([-a for a in self.coefficients()]) @@ -475,7 +479,12 @@ def primitive(self): def scale_by_factor(self, k): """ - Scale the values of the ternary quadratic form by the number c, if c times the content of the ternary quadratic form is an integer it returns a ternary quadratic form, otherwise returns a quadratic form of dimension 3. + Scale the values of the ternary quadratic form by the number ``k``. + + OUTPUT: + + If ``k`` times the content of the ternary quadratic form is an integer, return a ternary quadratic form; + otherwise, return a quadratic form of dimension 3. EXAMPLES:: @@ -542,15 +551,14 @@ def reciprocal_reduced(self): EXAMPLES:: sage: Q = TernaryQF([1, 1, 3, 0, -1, 0]) - sage: Qrr = Q.reciprocal_reduced() - sage: Qrr + sage: Qrr = Q.reciprocal_reduced(); Qrr Ternary quadratic form with integer coefficients: [4 11 12] [0 -4 0] sage: Q.is_eisenstein_reduced() True sage: Qr = Q.reciprocal() - sage: Qr.reduced_form_eisenstein(matrix = False) == Qrr + sage: Qr.reduced_form_eisenstein(matrix=False) == Qrr True """ return self.reciprocal().reduced_form_eisenstein(matrix=False) @@ -684,7 +692,7 @@ def level(self): return 4 * self.disc() // self.divisor() def is_eisenstein_reduced(self) -> bool: - """ + r""" Determine if the ternary quadratic form is Eisenstein reduced. That is, if we have a ternary quadratic form: @@ -695,16 +703,14 @@ def is_eisenstein_reduced(self) -> bool: then - :: - - 1- a<=b<=c; - 2- r, s, and t are all positive or all nonpositive; - 3- a>=|t|; a>=|s|; b>=|r|; - 4- a+b+r+s+t>=0; - 5- a=t implies s<=2*r; a=s implies t<=2*r; b=r implies t<=2*s; - 6- a=-t implies s=0; a=-s implies t=0; b=-r implies t=0; - 7- a+b+r+s+t=0 implies 2*a+2*s+t<=0; - 8- a=b implies |r|<=|s|; b=c implies |s|<=|t|. + 1. `a \leq b \leq c`; + 2. `r`, `s`, and `t` are all positive or all nonpositive; + 3. `a \geq |t|`; `a \geq |s|`; `b \geq |r|`; + 4. `a+b+r+s+t \geq 0`; + 5. `a=t` implies `s \leq 2\cdot r`; `a=s` implies `t \leq 2\cdot r`; `b=r` implies `t \leq 2\cdot s`; + 6. `a=-t` implies `s=0`; `a=-s` implies `t=0`; `b=-r` implies `t=0`; + 7. `a+b+r+s+t = 0` implies `2\cdot a+2\cdot s+t \leq 0`; + 8. `a=b` implies `|r| \leq |s|`; `b=c` implies `|s| \leq |t|`. EXAMPLES:: @@ -715,7 +721,7 @@ def is_eisenstein_reduced(self) -> bool: sage: Q.is_eisenstein_reduced() False """ - [a,b,c,r,s,t]=[self._a,self._b,self._c,self._r,self._s,self._t] + [a,b,c,r,s,t] = [self._a,self._b,self._c,self._r,self._s,self._t] # cond 2 if not (r > 0 and t > 0 and s > 0): @@ -740,7 +746,7 @@ def is_eisenstein_reduced(self) -> bool: # cond 6 # r, s, t <= 0 - if r<=0: + if r <= 0: if a == -t and s != 0: return False if a == -s and t != 0: @@ -760,7 +766,7 @@ def is_eisenstein_reduced(self) -> bool: return True def reduced_form_eisenstein(self, matrix=True): - """ + r""" Return the Eisenstein reduced form equivalent to the given positive ternary quadratic form, which is unique. @@ -797,8 +803,8 @@ def reduced_form_eisenstein(self, matrix=True): def pseudorandom_primitive_zero_mod_p(self, p): """ - Return a tuple of the form v = (a, b, 1) such that is a zero of the given ternary quadratic - positive definite form modulo an odd prime p, where p doesn't divides the discriminant of the form. + Return a tuple of the form `v = (a, b, 1)` such that is a zero of the given ternary quadratic + positive definite form modulo an odd prime `p`, where `p` doesn't divides the discriminant of the form. EXAMPLES:: @@ -809,32 +815,32 @@ def pseudorandom_primitive_zero_mod_p(self, p): (1, 2, 1) sage: Q((1, 2, 1)) 15 - sage: v = Q.pseudorandom_primitive_zero_mod_p(1009) - sage: Q(v) % 1009 + sage: v = Q.pseudorandom_primitive_zero_mod_p(1009) # needs sage.libs.pari + sage: Q(v) % 1009 # needs sage.libs.pari 0 - sage: v[2] + sage: v[2] # needs sage.libs.pari 1 """ [a,b,c,r,s,t] = self.coefficients() while True: - r1=randint(0,p-1) - r2=randint(0,p-1) - alpha=(b*r1**2+t*r1+a) % p + r1 = randint(0,p-1) + r2 = randint(0,p-1) + alpha = (b*r1**2+t*r1+a) % p if alpha != 0: - beta=(2*b*r1*r2+t*r2+r*r1+s) % p - gamma=(b*r2**2+r*r2+c) % p - disc=beta**2-4*alpha*gamma + beta = (2*b*r1*r2+t*r2+r*r1+s) % p + gamma = (b*r2**2+r*r2+c) % p + disc = beta**2-4*alpha*gamma if mod(disc, p).is_square(): - z=(-beta+mod(disc,p).sqrt().lift())*(2*alpha).inverse_mod(p) + z = (-beta+mod(disc,p).sqrt().lift())*(2*alpha).inverse_mod(p) # return vector((z,r1*z+r2,1))%p return z % p, (r1*z+r2) % p, 1 def find_zeros_mod_p(self, p): """ - Find the zeros of the given ternary quadratic positive definite form modulo a prime p, where p doesn't divides the discriminant of the form. + Find the zeros of the given ternary quadratic positive definite form modulo a prime `p`, where `p` doesn't divide the discriminant of the form. EXAMPLES:: @@ -845,16 +851,14 @@ def find_zeros_mod_p(self, p): 3 * 13 * 19 sage: Q.find_zeros_mod_p(2) [(1, 0, 0), (1, 1, 0), (0, 0, 1)] - sage: zeros_17 = Q.find_zeros_mod_p(17) - sage: len(zeros_17) + sage: zeros_17 = Q.find_zeros_mod_p(17) # needs sage.libs.pari + sage: len(zeros_17) # needs sage.libs.pari 18 - sage: [Q(v)%17 for v in zeros_17] + sage: [Q(v)%17 for v in zeros_17] # needs sage.libs.pari [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - - """ - if p==2: + if p == 2: return _find_zeros_mod_p_2(self._a, self._b, self._c, self._r, self._s, self._t) @@ -865,20 +869,22 @@ def find_zeros_mod_p(self, p): return _find_zeros_mod_p_odd(a, b, c, r, s, t, p, v) def find_p_neighbor_from_vec(self, p, v, mat=False): - """ - Finds the reduced equivalent of the p-neighbor of this ternary quadratic form associated to a given - vector v satisfying: + r""" + Finds the reduced equivalent of the `p`-neighbor of this ternary quadratic form associated to a given + vector `v` satisfying: - 1. Q(v) = 0 mod p + 1. `Q(v) = 0` (mod `p`) - 2. v is a non-singular point of the conic Q(v) = 0 mod p. + 2. `v` is a non-singular point of the conic `Q(v) = 0` (mod `p`). - Reference: Gonzalo Tornaria's Thesis, Thrm 3.5, p34. + REFERENCES: + + Gonzalo Tornaria's Thesis, Thrm 3.5, p34. EXAMPLES:: - sage: Q = TernaryQF([1, 3, 3, -2, 0, -1]) - sage: Q + sage: # needs sage.libs.pari + sage: Q = TernaryQF([1, 3, 3, -2, 0, -1]); Q Ternary quadratic form with integer coefficients: [1 3 3] [-2 0 -1] @@ -887,7 +893,7 @@ def find_p_neighbor_from_vec(self, p, v, mat=False): sage: v = (9, 7, 1) sage: v in Q.find_zeros_mod_p(11) True - sage: Q11, M = Q.find_p_neighbor_from_vec(11, v, mat = True) + sage: Q11, M = Q.find_p_neighbor_from_vec(11, v, mat=True) sage: Q11 Ternary quadratic form with integer coefficients: [1 2 4] @@ -908,13 +914,13 @@ def find_p_neighbor_from_vec(self, p, v, mat=False): def find_p_neighbors(self, p, mat=False): """ - Find a list with all the reduced equivalent of the p-neighbors of this ternary quadratic form, given by the zeros mod p of the form. - See find_p_neighbor_from_vec for more information. + Find a list with all the reduced equivalent of the `p`-neighbors of this ternary quadratic form, given by the zeros mod `p` of the form. + See :meth:`find_p_neighbor_from_vec` for more information. EXAMPLES:: - sage: Q0 = TernaryQF([1, 3, 3, -2, 0, -1]) - sage: Q0 + sage: # needs sage.libs.pari + sage: Q0 = TernaryQF([1, 3, 3, -2, 0, -1]); Q0 Ternary quadratic form with integer coefficients: [1 3 3] [-2 0 -1] @@ -937,7 +943,7 @@ def find_p_neighbors(self, p, mat=False): def basic_lemma(self, p): """ - Finds a number represented by self and coprime to the prime p. + Find a number represented by ``self`` and coprime to the prime `p`. EXAMPLES:: @@ -951,9 +957,11 @@ def basic_lemma(self, p): def xi(self, p): """ Return the value of the genus characters Xi_p... which may be - missing one character. We allow -1 as a prime. + missing one character. We allow `-1` as a prime. - Reference: Dickson's "Studies in the Theory of Numbers" + REFERENCES: + + Dickson's "Studies in the Theory of Numbers" EXAMPLES:: @@ -1000,12 +1008,12 @@ def xi_rec(self, p): def symmetry(self, v): """ - Return A the automorphism of the ternary quadratic form such that: + Return `A`, the automorphism of the ternary quadratic form such that: - - A*v = -v. - - A*u = 0, if u is orthogonal to v. + - `Av = -v`, + - `Au = 0`, if `u` is orthogonal to `v`, - where v is a given vector. + where `v` is a given vector. EXAMPLES:: @@ -1030,15 +1038,15 @@ def symmetry(self, v): True sage: M*v2 == v2 True - - """ return identity_matrix(3) - v.column()*matrix(v)*self.matrix()/self(v) def automorphism_symmetries(self, A): """ - Given the automorphism A, returns two vectors v1, v2 if A is not the identity. Such that the product of the symmetries of the ternary quadratic form given by the two vectors is A. + Given the automorphism `A`, if `A` is the identity, return the empty list. + Otherwise, return a list of two vectors `v_1`, `v_2` such that the product of + the symmetries of the ternary quadratic form given by the two vectors is `A`. EXAMPLES:: @@ -1063,7 +1071,6 @@ def automorphism_symmetries(self, A): True sage: Q.automorphism_symmetries(identity_matrix(ZZ,3)) [] - """ if A == identity_matrix(3): @@ -1082,7 +1089,7 @@ def automorphism_symmetries(self, A): def automorphism_spin_norm(self, A): """ - Return the spin norm of the automorphism A. + Return the spin norm of the automorphism `A`. EXAMPLES:: @@ -1663,14 +1670,16 @@ def _automorphisms_reduced_slow(self): sage: Q = TernaryQF([1, 1, 7, 0, 0, 0]) sage: Q.is_eisenstein_reduced() True - sage: auts = Q._automorphisms_reduced_slow() # long time (3s on sage.math, 2014) - sage: len(auts) # long time + + sage: # long time + sage: auts = Q._automorphisms_reduced_slow() # 3s on sage.math, 2014 + sage: len(auts) 8 - sage: A = auts[randint(0,7)] # long time - sage: Q(A) == Q # long time + sage: A = auts[randint(0,7)] + sage: Q(A) == Q True sage: Q = TernaryQF([3, 4, 5, 3, 3, 2]) - sage: Q._automorphisms_reduced_slow() # long time + sage: Q._automorphisms_reduced_slow() [ [1 0 0] [0 1 0] @@ -1694,8 +1703,7 @@ def automorphisms(self, slow=True): EXAMPLES:: sage: Q = TernaryQF([1, 1, 7, 0, 0, 0]) - sage: auts = Q.automorphisms() - sage: auts + sage: auts = Q.automorphisms(); auts [ [-1 0 0] [-1 0 0] [ 0 -1 0] [ 0 -1 0] [ 0 1 0] [ 0 1 0] [ 0 -1 0] [ 0 1 0] [-1 0 0] [ 1 0 0] [-1 0 0] [ 1 0 0] @@ -1707,14 +1715,14 @@ def automorphisms(self, slow=True): sage: all(Q == Q(A) for A in auts) True sage: Q = TernaryQF([3, 4, 5, 3, 3, 2]) - sage: Q.automorphisms(slow = False) + sage: Q.automorphisms(slow=False) [ [1 0 0] [0 1 0] [0 0 1] ] sage: Q = TernaryQF([4, 2, 4, 3, -4, -5]) - sage: auts = Q.automorphisms(slow = False) + sage: auts = Q.automorphisms(slow=False) sage: auts [ [1 0 0] [ 2 -1 -1] @@ -1763,7 +1771,7 @@ def _number_of_automorphisms_reduced(self): sage: Q = TernaryQF([1, 1, 7, 0, 0, 0]) sage: Q._number_of_automorphisms_reduced() 8 - sage: len(Q.automorphisms(slow = False)) + sage: len(Q.automorphisms(slow=False)) 8 sage: Q = TernaryQF([3, 4, 5, 3, 3, 2]) sage: Q._number_of_automorphisms_reduced() @@ -1941,8 +1949,7 @@ def number_of_automorphisms(self, slow=True): sage: A = matrix(ZZ, 3, [0, 1, 0, -1, 5, 0, -8, -1, 1]) sage: A.det() 1 - sage: Q1 = Q(A) - sage: Q1 + sage: Q1 = Q(A); Q1 Ternary quadratic form with integer coefficients: [449 33 7] [-14 -112 102] @@ -1951,7 +1958,7 @@ def number_of_automorphisms(self, slow=True): sage: Q = TernaryQF([-19, -7, -6, -12, 20, 23]) sage: Q.is_negative_definite() True - sage: Q.number_of_automorphisms(slow = False) + sage: Q.number_of_automorphisms(slow=False) 24 """ if not self.is_definite(): @@ -1973,9 +1980,9 @@ def number_of_automorphisms(self, slow=True): def find_all_ternary_qf_by_level_disc(N, d): """ - Find the coefficients of all the reduced ternary quadratic forms given its discriminant d and level N. + Find the coefficients of all the reduced ternary quadratic forms given its discriminant `d` and level `N`. - If N|4d and d|N^2, then it may be some forms with that discriminant and level. + If `N|4d` and `d|N^2`, then it may be some forms with that discriminant and level. EXAMPLES:: @@ -2010,13 +2017,12 @@ def find_all_ternary_qf_by_level_disc(N, d): def find_a_ternary_qf_by_level_disc(N, d): """ - Find a reduced ternary quadratic form given its discriminant d and level N. - If N|4d and d|N^2, then it may be a form with that discriminant and level. + Find a reduced ternary quadratic form given its discriminant `d` and level `N`. + If `N|4d` and `d|N^2`, then it may be a form with that discriminant and level. EXAMPLES:: - sage: Q1 = find_a_ternary_qf_by_level_disc(44, 11) - sage: Q1 + sage: Q1 = find_a_ternary_qf_by_level_disc(44, 11); Q1 Ternary quadratic form with integer coefficients: [1 1 3] [0 -1 0] diff --git a/src/sage/quivers/__init__.py b/src/sage/quivers/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/quivers/algebra_elements.pyx b/src/sage/quivers/algebra_elements.pyx index c21251df4d3..3d05ba7e270 100644 --- a/src/sage/quivers/algebra_elements.pyx +++ b/src/sage/quivers/algebra_elements.pyx @@ -17,7 +17,6 @@ AUTHORS: # **************************************************************************** include "algebra_elements.pxi" -from sage.misc.cachefunc import cached_method from sage.misc.repr import repr_lincomb from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool @@ -90,15 +89,16 @@ cdef class PathAlgebraElement(RingElement): faster, but the timing for path algebra elements has improved by about 20%:: - sage: timeit('pF^5+3*pF^3') # not tested + sage: # not tested + sage: timeit('pF^5+3*pF^3') 1 loops, best of 3: 338 ms per loop - sage: timeit('pP^5+3*pP^3') # not tested + sage: timeit('pP^5+3*pP^3') 100 loops, best of 3: 2.55 ms per loop - sage: timeit('pF2^7') # not tested + sage: timeit('pF2^7') 10000 loops, best of 3: 513 ms per loop - sage: timeit('pL2^7') # not tested + sage: timeit('pL2^7') 125 loops, best of 3: 1.99 ms per loop - sage: timeit('pP2^7') # not tested + sage: timeit('pP2^7') 10000 loops, best of 3: 1.54 ms per loop So, if one is merely interested in basic arithmetic operations for @@ -477,9 +477,9 @@ cdef class PathAlgebraElement(RingElement): cdef path_homog_poly_t *H = self.data cdef path_term_t *T cdef list L = [] - while H!=NULL: + while H != NULL: T = H.poly.lead - while T!=NULL: + while T != NULL: L.append(<object>T.coef) T = T.nxt H = H.nxt @@ -534,9 +534,9 @@ cdef class PathAlgebraElement(RingElement): cdef path_term_t *T cdef object one = self.base_ring().one() cdef list L = [] - while H!=NULL: + while H != NULL: T = H.poly.lead - while T!=NULL: + while T != NULL: out = homog_poly_create(H.start, H.end) out.poly.lead = term_create_blank(one) mon_copy(out.poly.lead.mon, T.mon) @@ -587,11 +587,10 @@ cdef class PathAlgebraElement(RingElement): cdef path_homog_poly_t *H = self.data cdef path_homog_poly_t *out cdef path_term_t *T - cdef object one = self.base_ring().one() cdef list L = [] - while H!=NULL: + while H != NULL: T = H.poly.lead - while T!=NULL: + while T != NULL: out = homog_poly_create(H.start, H.end) out.poly.lead = term_copy(T) out.poly.lead.nxt = NULL @@ -647,9 +646,9 @@ cdef class PathAlgebraElement(RingElement): cdef QuiverPath sample = self._parent.semigroup().gen(0) cdef QuiverPath tmp cdef list L = [] - while H!=NULL: + while H != NULL: T = H.poly.lead - while T!=NULL: + while T != NULL: tmp = sample._new_(H.start, H.end) biseq_init_copy(tmp._path, T.mon.path) L.append(tmp) @@ -766,9 +765,9 @@ cdef class PathAlgebraElement(RingElement): cdef path_term_t *T cdef QuiverPath sample = self._parent.semigroup().gen(0) cdef QuiverPath tmp - while H!=NULL: + while H != NULL: T = H.poly.lead - while T!=NULL: + while T != NULL: sig_check() tmp = sample._new_(H.start, H.end) biseq_init_copy(tmp._path, T.mon.path) @@ -975,7 +974,6 @@ cdef class PathAlgebraElement(RingElement): cdef PathAlgebraElement self = left cdef path_homog_poly_t *H1 = self.data cdef path_homog_poly_t *H2 = other.data - cdef int c while H1 != NULL and H2 != NULL: v1 = H1.start v2 = H2.start @@ -1318,12 +1316,10 @@ cdef class PathAlgebraElement(RingElement): cdef path_homog_poly_t *H1 = self.data cdef path_homog_poly_t *H2 cdef path_term_t *T2 - cdef path_poly_t *P cdef path_homog_poly_t *out_orig = NULL cdef path_homog_poly_t *out = NULL cdef path_homog_poly_t *nxt cdef path_term_t *P1start - cdef int c while H1 != NULL: H2 = right.data while H2 != NULL: diff --git a/src/sage/dynamics/complex_dynamics/__init__.py b/src/sage/quivers/all.py similarity index 100% rename from src/sage/dynamics/complex_dynamics/__init__.py rename to src/sage/quivers/all.py diff --git a/src/sage/quivers/morphism.py b/src/sage/quivers/morphism.py index b8bb25657eb..fc08e35ba60 100644 --- a/src/sage/quivers/morphism.py +++ b/src/sage/quivers/morphism.py @@ -1108,7 +1108,7 @@ def algebraic_dual(self): Representation with dimension vector (5, 2, 1, 1, 4) The algebraic dual of an indecomposable projective is the indecomposable - projective of the same vertex in the opposite quiver. + projective of the same vertex in the opposite quiver. :: sage: Q.reverse().P(QQ, 4) Representation with dimension vector (5, 2, 1, 1, 4) diff --git a/src/sage/quivers/paths.pyx b/src/sage/quivers/paths.pyx index 6fb990f8821..f2642ada119 100644 --- a/src/sage/quivers/paths.pyx +++ b/src/sage/quivers/paths.pyx @@ -409,7 +409,6 @@ cdef class QuiverPath(MonoidElement): cdef tuple E cdef Py_ssize_t start, stop, step, slicelength cdef int init, end - cdef size_t i,ind cdef QuiverPath OUT if isinstance(index, slice): PySlice_GetIndicesEx(index, self._path.length, @@ -599,7 +598,7 @@ cdef class QuiverPath(MonoidElement): """ if self._parent is not P._parent: return (None, None, None) - cdef size_t i, start + cdef size_t i sig_on() i = biseq_startswith_tail(P._path, self._path, 0) sig_off() @@ -665,8 +664,6 @@ cdef class QuiverPath(MonoidElement): raise ValueError("the two paths belong to different quivers") if subpath._path.length == 0: raise ValueError("we only consider sub-paths of positive length") - cdef size_t i - cdef size_t max_i, bitsize if self._path.length < subpath._path.length: return 0 if biseq_contains(self._path, subpath._path, 0) == -1: diff --git a/src/sage/quivers/representation.py b/src/sage/quivers/representation.py index 9c11eb8ad0e..db82cbd7c86 100644 --- a/src/sage/quivers/representation.py +++ b/src/sage/quivers/representation.py @@ -1297,10 +1297,7 @@ def copy(self): sage: v.get_element(1) (1, 0) """ - if hasattr(self, '__custom_name'): - name = self.__custom_name - else: - name = None + name = self.get_custom_name() return self.parent()(self._elems.copy(), name) #################################################################### diff --git a/src/sage/repl/configuration.py b/src/sage/repl/configuration.py index 1890dc207d4..cb255ef65b3 100644 --- a/src/sage/repl/configuration.py +++ b/src/sage/repl/configuration.py @@ -7,11 +7,11 @@ the IPython simple prompt is being used:: sage: cmd = 'print([sys.stdin.isatty(), sys.stdout.isatty()])' - sage: import pexpect - sage: output = pexpect.run( + sage: import pexpect # needs pexpect + sage: output = pexpect.run( # needs pexpect ....: 'bash -c \'echo "{0}" | sage\''.format(cmd), ....: ).decode('utf-8', 'surrogateescape') - sage: 'sage: [False, True]' in output + sage: 'sage: [False, True]' in output # needs pexpect True """ diff --git a/src/sage/repl/display/fancy_repr.py b/src/sage/repl/display/fancy_repr.py index 5c1191dc4f1..77949a4b578 100644 --- a/src/sage/repl/display/fancy_repr.py +++ b/src/sage/repl/display/fancy_repr.py @@ -181,19 +181,20 @@ def __call__(self, obj, p, cycle): EXAMPLES:: + sage: # needs sage.modules sage: from sage.repl.display.fancy_repr import LargeMatrixHelpRepr sage: M = identity_matrix(40) sage: pp = LargeMatrixHelpRepr() sage: pp.format_string(M) - "40 x 40 dense matrix over Integer Ring (use the '.str()' method to see the entries)" + "40 x 40 dense matrix over Integer Ring (use the '.str()' method...)" sage: pp.format_string([M, M]) '--- object not handled by representer ---' Leads to:: - sage: M - 40 x 40 dense matrix over Integer Ring (use the '.str()' method to see the entries) - sage: [M, M] + sage: M # needs sage.modules + 40 x 40 dense matrix over Integer Ring (use the '.str()' method...) + sage: [M, M] # needs sage.modules [40 x 40 dense matrix over Integer Ring, 40 x 40 dense matrix over Integer Ring] """ @@ -312,7 +313,7 @@ def __call__(self, obj, p, cycle): sage: from sage.repl.display.fancy_repr import TallListRepr sage: format_list = TallListRepr().format_string - sage: format_list([1, 2, identity_matrix(2)]) + sage: format_list([1, 2, identity_matrix(2)]) # needs sage.modules '[\n [1 0]\n1, 2, [0 1]\n]' Check that :trac:`18743` is fixed:: diff --git a/src/sage/repl/display/formatter.py b/src/sage/repl/display/formatter.py index 7e06656d880..822a9edfaba 100644 --- a/src/sage/repl/display/formatter.py +++ b/src/sage/repl/display/formatter.py @@ -24,17 +24,17 @@ sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() sage: shell.run_cell('%display ascii_art') - sage: shell.run_cell('integral(x^2/pi^x, x)') + sage: shell.run_cell('integral(x^2/pi^x, x)') # needs sage.symbolic -x / 2 2 \ -pi *\x *log (pi) + 2*x*log(pi) + 2/ -------------------------------------- 3 log (pi) - sage: shell.run_cell("i = var('i')") - sage: shell.run_cell('sum(i*x^i, i, 0, 10)') + sage: shell.run_cell("i = var('i')") # needs sage.symbolic + sage: shell.run_cell('sum(i*x^i, i, 0, 10)') # needs sage.symbolic 10 9 8 7 6 5 4 3 2 10*x + 9*x + 8*x + 7*x + 6*x + 5*x + 4*x + 3*x + 2*x + x - sage: shell.run_cell('StandardTableaux(4).list()') + sage: shell.run_cell('StandardTableaux(4).list()') # needs sage.combinat [ [ 1 4 1 3 [ 1 3 4 1 2 4 1 2 3 1 3 1 2 2 2 @@ -79,6 +79,7 @@ lazy_import('matplotlib.figure', 'Figure') + class SageDisplayFormatter(DisplayFormatter): def __init__(self, *args, **kwds): @@ -120,7 +121,7 @@ def format(self, obj, include=None, exclude=None): EXAMPLES:: - sage: [identity_matrix(i) for i in range(3,7)] + sage: [identity_matrix(i) for i in range(3,7)] # needs sage.modules [ [1 0 0 0 0 0] [1 0 0 0 0] [0 1 0 0 0 0] @@ -132,8 +133,8 @@ def format(self, obj, include=None, exclude=None): sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() sage: shell.run_cell('%display ascii_art') # indirect doctest - sage: shell.run_cell("i = var('i')") - sage: shell.run_cell('sum(i*x^i, i, 0, 10)') + sage: shell.run_cell("i = var('i')") # needs sage.symbolic + sage: shell.run_cell('sum(i*x^i, i, 0, 10)') # needs sage.symbolic 10 9 8 7 6 5 4 3 2 10*x + 9*x + 8*x + 7*x + 6*x + 5*x + 4*x + 3*x + 2*x + x sage: shell.run_cell('%display default') @@ -194,7 +195,7 @@ def format(self, obj, include=None, exclude=None): # if it is not plain and dull if (not isinstance(obj, IPYTHON_NATIVE_TYPES) and not set(sage_format.keys()).issubset([PLAIN_TEXT]) and - not isinstance(obj, Figure)): + not isinstance(obj, Figure)): return sage_format, sage_metadata if self.ipython_display_formatter(obj): @@ -228,11 +229,11 @@ def _ipython_float_precision_changed(change): sage: shell = get_test_shell() sage: shell.run_cell('%precision 4') '%.4f' - sage: shell.run_cell('matrix.options.precision') # indirect doctest + sage: shell.run_cell('matrix.options.precision') # indirect doctest # needs sage.modules 4 sage: shell.run_cell('%precision') '%r' - sage: shell.run_cell('matrix.options.precision') # indirect doctest + sage: shell.run_cell('matrix.options.precision') # indirect doctest # needs sage.modules None """ from sage.matrix.constructor import options @@ -304,8 +305,8 @@ def __call__(self, obj): sage: fmt(2) ---- calling ipython formatter ---- '2' - sage: a = identity_matrix(ZZ, 2) - sage: fmt([a, a]) + sage: a = identity_matrix(ZZ, 2) # needs sage.modules + sage: fmt([a, a]) # needs sage.modules ---- calling ipython formatter ---- '[\n[1 0] [1 0]\n[0 1], [0 1]\n]' """ diff --git a/src/sage/repl/display/jsmol_iframe.py b/src/sage/repl/display/jsmol_iframe.py index 4775d2a02e7..f8e69cfcb59 100644 --- a/src/sage/repl/display/jsmol_iframe.py +++ b/src/sage/repl/display/jsmol_iframe.py @@ -112,7 +112,7 @@ def __init__(self, jmol, path_to_jsmol=None, width='100%', height='100%'): EXAMPLES:: sage: from sage.repl.display.jsmol_iframe import JSMolHtml - sage: JSMolHtml(sphere(), width=500, height=300) + sage: JSMolHtml(sphere(), width=500, height=300) # needs sage.plot JSmol Window 500x300 """ from sage.repl.rich_output.output_graphics3d import OutputSceneJmol diff --git a/src/sage/repl/display/util.py b/src/sage/repl/display/util.py index ee99782b6fa..a2033c69f4f 100644 --- a/src/sage/repl/display/util.py +++ b/src/sage/repl/display/util.py @@ -6,14 +6,14 @@ methods elsewhere. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Volker Braun <vbraun.name@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** class TallListFormatter(): @@ -39,7 +39,7 @@ def _tall_list_row(self, running_lines, last_row=False): sage: format_list._tall_list_row(['a b', 'b c', 'c']) ['a b', 'b c', 'c,', ''] """ - s=[] + s = [] for i, line in enumerate(running_lines): if i + 1 != len(running_lines): sep, tail = ' ', '' @@ -74,7 +74,7 @@ def try_format(self, the_list): TESTS:: sage: from sage.repl.display.util import format_list - sage: print(format_list.try_format( + sage: print(format_list.try_format( # needs sage.modules ....: [matrix([[1, 2, 3, 4], [5, 6, 7, 8]]) for i in range(7)])) [ [1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4] diff --git a/src/sage/repl/inputhook.py b/src/sage/repl/inputhook.py index da5df0268c0..7f7894f6dcf 100644 --- a/src/sage/repl/inputhook.py +++ b/src/sage/repl/inputhook.py @@ -17,6 +17,8 @@ import select import errno +import contextlib +import io from IPython import get_ipython from IPython.terminal.pt_inputhooks import register @@ -47,15 +49,27 @@ def install(): """ Install the Sage input hook - EXAMPLES:: + EXAMPLES: + + Make sure ipython is running so we really test this function:: + + sage: from sage.repl.interpreter import get_test_shell + sage: get_test_shell() + <sage.repl.interpreter.SageTestShell object at ...> + + Run the function twice, to check it is idempotent (see :trac:`35235`):: sage: from sage.repl.inputhook import install sage: install() + sage: install() """ ip = get_ipython() if not ip: return # Not running in ipython, e.g. doctests - ip.enable_gui('sage') + if ip._inputhook != sage_inputhook: + # silence `ip.enable_gui()` useless output + with contextlib.redirect_stdout(io.StringIO()): + ip.enable_gui('sage') def uninstall(): @@ -71,4 +85,6 @@ def uninstall(): if not ip: return if ip._inputhook == sage_inputhook: - ip.enable_gui(None) + # silence `ip.enable_gui()` useless output + with contextlib.redirect_stdout(io.StringIO()): + ip.enable_gui(None) diff --git a/src/sage/repl/interface_magic.py b/src/sage/repl/interface_magic.py index 856bdcd120d..b77bc09e972 100644 --- a/src/sage/repl/interface_magic.py +++ b/src/sage/repl/interface_magic.py @@ -97,7 +97,7 @@ def all_iter(cls): except ImportError: return for name, obj in sage.interfaces.all.__dict__.items(): - if isinstance(obj, sage.interfaces.interface.Interface): + if isinstance(obj, (sage.interfaces.interface.Interface, sage.misc.lazy_import.LazyImport)): yield cls(name, obj) @classmethod @@ -121,9 +121,9 @@ def register_all(cls, shell=None): ... ('maxima', 'line') ('maxima', 'cell') - sage: 'gap' in MockShell.magics + sage: 'gap' in MockShell.magics # needs sage.libs.gap True - sage: 'maxima' in MockShell.magics + sage: 'maxima' in MockShell.magics # needs sage.symbolic True """ if shell is None: @@ -159,7 +159,7 @@ def find(cls, name): EXAMPLES:: sage: from sage.repl.interface_magic import InterfaceMagic - sage: InterfaceMagic.find('gap') + sage: InterfaceMagic.find('gap') # needs sage.libs.gap <sage.repl.interface_magic.InterfaceMagic object at 0x...> """ for magic in cls.all_iter(): @@ -183,7 +183,7 @@ def __init__(self, name, interface): EXAMPLES:: sage: from sage.repl.interface_magic import InterfaceMagic - sage: InterfaceMagic.find('gap') + sage: InterfaceMagic.find('gap') # needs sage.libs.gap <sage.repl.interface_magic.InterfaceMagic object at 0x...> """ self._name = name @@ -199,6 +199,7 @@ def line_magic_factory(self): EXAMPLES:: + sage: # needs sage.libs.gap sage: from sage.repl.interface_magic import InterfaceMagic sage: line_magic = InterfaceMagic.find('gap').line_magic_factory() sage: output = line_magic('1+1') @@ -211,9 +212,9 @@ def line_magic_factory(self): sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() - sage: shell.run_cell('%gap 1+1') + sage: shell.run_cell('%gap 1+1') # needs sage.libs.gap 2 - sage: shell.run_cell('%gap?') + sage: shell.run_cell('%gap?') # needs sage.libs.gap Docstring: Interact with gap <BLANKLINE> @@ -243,6 +244,7 @@ def cell_magic_factory(self): EXAMPLES:: + sage: # needs sage.libs.gap sage: from sage.repl.interface_magic import InterfaceMagic sage: cell_magic = InterfaceMagic.find('gap').cell_magic_factory() sage: output = cell_magic('', '1+1;') @@ -258,15 +260,15 @@ def cell_magic_factory(self): sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() - sage: shell.run_cell('%%gap\nG:=SymmetricGroup(5);\n1+1;Order(G);') + sage: shell.run_cell('%%gap\nG:=SymmetricGroup(5);\n1+1;Order(G);') # needs sage.libs.gap Sym( [ 1 .. 5 ] ) 2 120 - sage: shell.run_cell('%%gap foo\n1+1;\n') + sage: shell.run_cell('%%gap foo\n1+1;\n') # needs sage.libs.gap ...File...<string>... SyntaxError: Interface magics have no options, got "foo" <BLANKLINE> - sage: shell.run_cell('%%gap?') + sage: shell.run_cell('%%gap?') # needs sage.libs.gap Docstring: Interact with gap <BLANKLINE> diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index fe4cff3add5..c8fd27b35fa 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -455,6 +455,42 @@ def SagePreparseTransformer(lines): # Interface shell # ################### +class logstr(str): + """ + For use by :meth`~InterfaceShellTransformer.transform`. + This provides a ``_latex_`` method which is just the string + wrapped in a ``\\verb`` environment. + """ + def __repr__(self): + """ + EXAMPLES:: + sage: from sage.repl.interpreter import logstr + sage: logstr("ABC") + ABC + """ + return self + + def _latex_(self): + r""" + EXAMPLES:: + sage: from sage.repl.interpreter import logstr + sage: logstr("A") + A + sage: latex(logstr("A")) + \verb#A# + sage: latex(logstr("A#B")) + \verb@A#B@ + """ + # return "\\begin{verbatim}%s\\end{verbatim}"%self + if '#' not in self: + delim = '#' + elif '@' not in self: + delim = '@' + elif '~' not in self: + delim = '~' + return r"""\verb%s%s%s""" % (delim, self.replace('\n\n', '\n').replace('\n', '; '), delim) + + class InterfaceShellTransformer(PrefilterTransformer): priority = 50 @@ -472,6 +508,7 @@ def __init__(self, *args, **kwds): TESTS:: + sage: # needs sage.symbolic sage: from sage.repl.interpreter import interface_shell_embed sage: shell = interface_shell_embed(maxima) sage: ift = shell.prefilter_manager.transformers[0] @@ -499,9 +536,11 @@ def preparse_imports_from_sage(self, line): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.repl.interpreter import interface_shell_embed, InterfaceShellTransformer sage: shell = interface_shell_embed(maxima) - sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, prefilter_manager=shell.prefilter_manager) + sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, + ....: prefilter_manager=shell.prefilter_manager) sage: ift.shell.ex('a = 3') sage: ift.preparse_imports_from_sage('2 + sage(a)') '2 + sage0 ' @@ -515,9 +554,11 @@ def preparse_imports_from_sage(self, line): Since :trac:`28439`, this also works with more complicated expressions containing nested parentheses:: + sage: # needs sage.libs.gap sage.symbolic sage: shell = interface_shell_embed(gap) sage: shell.user_ns = locals() - sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, prefilter_manager=shell.prefilter_manager) + sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, + ....: prefilter_manager=shell.prefilter_manager) sage: line = '2 + sage((1+2)*gap(-(5-3)^2).sage()) - gap(1+(2-1))' sage: line = ift.preparse_imports_from_sage(line) sage: gap.eval(line) @@ -551,35 +592,41 @@ def transform(self, line, continue_prompt): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.repl.interpreter import interface_shell_embed, InterfaceShellTransformer sage: shell = interface_shell_embed(maxima) - sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, prefilter_manager=shell.prefilter_manager) + sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, + ....: prefilter_manager=shell.prefilter_manager) sage: ift.transform('2+2', False) # note: output contains triple quotation marks - 'sage.misc.all.logstr(r"""4""")' + 'sage.repl.interpreter.logstr(r"""4""")' sage: ift.shell.ex('a = 4') sage: ift.transform(r'sage(a)+4', False) - 'sage.misc.all.logstr(r"""8""")' + 'sage.repl.interpreter.logstr(r"""8""")' sage: ift.temporary_objects set() - sage: shell = interface_shell_embed(gap) - sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, prefilter_manager=shell.prefilter_manager) + sage: shell = interface_shell_embed(gap) # needs sage.libs.gap + sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, # needs sage.libs.gap + ....: prefilter_manager=shell.prefilter_manager) sage: ift.transform('2+2', False) - 'sage.misc.all.logstr(r"""4""")' + 'sage.repl.interpreter.logstr(r"""4""")' TESTS: Check that whitespace is not stripped and that special characters are escaped (:trac:`28439`):: - sage: shell = interface_shell_embed(gap) - sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, prefilter_manager=shell.prefilter_manager) - sage: ift.transform(r'Print(" -\n\\\\- ");', False) - 'sage.misc.all.logstr(r""" -\n\\\\-""")' - - sage: shell = interface_shell_embed(macaulay2) # optional - macaulay2 - sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, prefilter_manager=shell.prefilter_manager) # optional - macaulay2 - sage: ift.transform('net(ZZ^2)', False) # optional - macaulay2 - 'sage.misc.all.logstr(r""" 2\nZZ""")' + sage: shell = interface_shell_embed(gap) # needs sage.libs.gap sage.symbolic + sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, # needs sage.libs.gap sage.symbolic + ....: prefilter_manager=shell.prefilter_manager) + sage: ift.transform(r'Print(" -\n\\\\- ");', False) # needs sage.symbolic + 'sage.repl.interpreter.logstr(r""" -\n\\\\-""")' + + sage: # optional - macaulay2 + sage: shell = interface_shell_embed(macaulay2) + sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, + ....: prefilter_manager=shell.prefilter_manager) + sage: ift.transform('net(ZZ^2)', False) + 'sage.repl.interpreter.logstr(r""" 2\nZZ""")' ''' line = self.preparse_imports_from_sage(line) @@ -591,7 +638,7 @@ def transform(self, line, continue_prompt): self.temporary_objects = set() # We do not strip whitespace from t here as the individual interface is # responsible for that - return 'sage.misc.all.logstr(r"""%s""")' % t + return 'sage.repl.interpreter.logstr(r"""%s""")' % t def interface_shell_embed(interface): @@ -608,8 +655,8 @@ def interface_shell_embed(interface): EXAMPLES:: sage: from sage.repl.interpreter import interface_shell_embed - sage: shell = interface_shell_embed(gap) - sage: shell.run_cell('List( [1..10], IsPrime )') + sage: shell = interface_shell_embed(gap) # needs sage.libs.gap + sage: shell.run_cell('List( [1..10], IsPrime )') # needs sage.libs.gap [ false, true, true, false, true, false, true, false, false, false ] <ExecutionResult object at ..., execution_count=None error_before_exec=None error_in_exec=None ...result=[ false, true, true, false, true, false, true, false, false, false ]> """ @@ -696,14 +743,14 @@ def __init__(self, app): <sage.repl.interpreter.SageCrashHandler object at 0x...> sage: sorted(sch.info.items()) [('app_name', 'Sage'), - ('bug_tracker', 'http://trac.sagemath.org'), + ('bug_tracker', 'https://github.com/sagemath/sage/issues'), ('contact_email', 'sage-support@googlegroups.com'), ('contact_name', 'sage-support'), ('crash_report_fname', 'Crash_report_Sage.txt')] """ contact_name = 'sage-support' contact_email = 'sage-support@googlegroups.com' - bug_tracker = 'http://trac.sagemath.org' + bug_tracker = 'https://github.com/sagemath/sage/issues' CrashHandler.__init__(self, app, contact_name, contact_email, bug_tracker, show_crash_traceback=True) self.crash_report_fname = 'Sage_crash_report.txt' diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index 798671aab42..14c945a8517 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -68,6 +68,7 @@ from sage.repl.load import load_wrap from sage.env import SAGE_IMPORTALL, SAGE_STARTUP_FILE from sage.misc.lazy_import import LazyImport +from sage.misc.misc import run_once @magics_class class SageMagics(Magics): @@ -197,9 +198,10 @@ def pre_readline(): self.shell.readline_startup_hook(pre_readline) self.shell.pre_readline = pre_readline - print('Interactively loading "%s"'%args) + print('Interactively loading "%s"' % args) _magic_display_status = 'simple' + @line_magic def display(self, args): r""" @@ -219,8 +221,8 @@ def display(self, args): That means you do not have to use :func:`ascii_art` to get an ASCII art output:: - sage: shell.run_cell("i = var('i')") - sage: shell.run_cell('sum(i^2*x^i, i, 0, 10)') + sage: shell.run_cell("i = var('i')") # needs sage.symbolic + sage: shell.run_cell('sum(i^2*x^i, i, 0, 10)') # needs sage.symbolic 10 9 8 7 6 5 4 3 2 100*x + 81*x + 64*x + 49*x + 36*x + 25*x + 16*x + 9*x + 4*x + x @@ -228,14 +230,14 @@ def display(self, args): sage: shell.run_cell('%display text plain') sage: shell.run_cell('%display plain') # shortcut for "text plain" - sage: shell.run_cell('sum(i^2*x^i, i, 0, 10)') + sage: shell.run_cell('sum(i^2*x^i, i, 0, 10)') # needs sage.symbolic 100*x^10 + 81*x^9 + 64*x^8 + 49*x^7 + 36*x^6 + 25*x^5 + 16*x^4 + 9*x^3 + 4*x^2 + x Sometime you could have to use a special output width and you could specify it:: sage: shell.run_cell('%display ascii_art') - sage: shell.run_cell('StandardTableaux(4).list()') + sage: shell.run_cell('StandardTableaux(4).list()') # needs sage.combinat [ [ 1 4 1 3 [ 1 3 4 1 2 4 1 2 3 1 3 1 2 2 2 @@ -246,7 +248,7 @@ def display(self, args): 3 3 ] 4 , 4 ] sage: shell.run_cell('%display ascii_art 50') - sage: shell.run_cell('StandardTableaux(4).list()') + sage: shell.run_cell('StandardTableaux(4).list()') # needs sage.combinat [ [ [ 1 3 4 1 2 4 1 2 3 @@ -350,12 +352,13 @@ def cython(self, line, cell): sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() - sage: shell.run_cell(''' + sage: shell.run_cell( # needs sage.misc.cython + ....: ''' ....: %%cython ....: def f(): ....: print('test') ....: ''') - sage: f() + sage: f() # needs sage.misc.cython test """ from sage.misc.cython import cython_compile @@ -381,6 +384,7 @@ def fortran(self, line, cell): EXAMPLES:: + sage: # needs numpy sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() sage: shell.run_cell(''' @@ -405,7 +409,7 @@ def fortran(self, line, cell): ....: C END FILE FIB1.F ....: ''') sage: fib - <fortran object> + <fortran ...> sage: from numpy import array sage: a = array(range(10), dtype=float) sage: fib(a, 10) @@ -582,41 +586,6 @@ def all_globals(): return all_jupyter -# from https://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop -from functools import wraps -def run_once(func): - """ - Runs a function (successfully) only once. - - The running can be reset by setting the ``has_run`` attribute to False - - TESTS:: - - sage: from sage.repl.ipython_extension import run_once - sage: @run_once - ....: def foo(work): - ....: if work: - ....: return 'foo worked' - ....: raise RuntimeError("foo didn't work") - sage: foo(False) - Traceback (most recent call last): - ... - RuntimeError: foo didn't work - sage: foo(True) - 'foo worked' - sage: foo(False) - sage: foo(True) - """ - @wraps(func) - def wrapper(*args, **kwargs): - if not wrapper.has_run: - result = func(*args, **kwargs) - wrapper.has_run = True - return result - wrapper.has_run = False - return wrapper - - @run_once def load_ipython_extension(ip): """ diff --git a/src/sage/repl/ipython_kernel/install.py b/src/sage/repl/ipython_kernel/install.py index cfb11b51bcf..081599b3452 100644 --- a/src/sage/repl/ipython_kernel/install.py +++ b/src/sage/repl/ipython_kernel/install.py @@ -263,14 +263,14 @@ def check(cls): spec = get_kernel_spec(ident) except NoSuchKernel: warnings.warn(f'no kernel named {ident} is accessible; ' - 'check your Jupyter configuration ' - '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html)') + 'check your Jupyter configuration ' + '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html)') else: from pathlib import Path if Path(spec.argv[0]).resolve() != Path(os.path.join(SAGE_VENV, 'bin', 'sage')).resolve(): warnings.warn(f'the kernel named {ident} does not seem to correspond to this ' - 'installation of SageMath; check your Jupyter configuration ' - '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html)') + 'installation of SageMath; check your Jupyter configuration ' + '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html)') def have_prerequisites(debug=True): diff --git a/src/sage/repl/ipython_kernel/interact.py b/src/sage/repl/ipython_kernel/interact.py index 4f96a212ab7..0551c83480e 100644 --- a/src/sage/repl/ipython_kernel/interact.py +++ b/src/sage/repl/ipython_kernel/interact.py @@ -51,12 +51,11 @@ def f(x=(0, 10)): from collections import OrderedDict from collections.abc import Iterable, Iterator from .widgets import EvalText, SageColorPicker -from .widgets_sagenb import input_grid from sage.structure.element import parent import sage.rings.abc from sage.misc.lazy_import import lazy_import -lazy_import("sage.plot.colors", "Color") from sage.structure.element import Matrix +lazy_import("sage.plot.colors", "Color") class sage_interactive(interactive): @@ -182,16 +181,18 @@ def widget_from_single_value(cls, abbrev, *args, **kwds): sage: from sage.repl.ipython_kernel.interact import sage_interactive sage: sage_interactive.widget_from_single_value("sin(x)") ...Text(value='sin(x)') - sage: sage_interactive.widget_from_single_value(sin(x)) + sage: sage_interactive.widget_from_single_value(sin(x)) # needs sage.symbolic ...EvalText(value='sin(x)') - sage: from sage.plot.colors import Color - sage: sage_interactive.widget_from_single_value(matrix([[1, 2], [3, 4]])) + sage: sage_interactive.widget_from_single_value(matrix([[1, 2], [3, 4]])) # needs sage.modules ...Grid(value=[[1, 2], [3, 4]], children=(Label(value=''), VBox(children=(EvalText(value='1', layout=Layout(max_width='5em')), EvalText(value='3', layout=Layout(max_width='5em')))), VBox(children=(EvalText(value='2', layout=Layout(max_width='5em')), EvalText(value='4', layout=Layout(max_width='5em')))))) - sage: sage_interactive.widget_from_single_value(Color('cornflowerblue')) + sage: from sage.plot.colors import Color # needs sage.plot + sage: sage_interactive.widget_from_single_value(Color('cornflowerblue')) # needs sage.plot ...SageColorPicker(value='#6495ed') """ # Support Sage matrices and colors if isinstance(abbrev, Matrix): + from .widgets_sagenb import input_grid + return input_grid(abbrev.nrows(), abbrev.ncols(), default=abbrev.list(), to_value=abbrev.parent()) if isinstance(abbrev, Color): @@ -226,15 +227,15 @@ def widget_from_tuple(cls, abbrev, *args, **kwds): ...IntSlider(value=3, max=10) sage: sage_interactive.widget_from_tuple((2, [('one', 1), ('two', 2), ('three', 3)])) ...Dropdown(index=1, options=(('one', 1), ('two', 2), ('three', 3)), value=2) - sage: sage_interactive.widget_from_tuple( (sqrt(2), pi) ) + sage: sage_interactive.widget_from_tuple( (sqrt(2), pi) ) # needs sage.symbolic ...FloatSlider(value=2.277903107981444, max=3.141592653589793, min=1.4142135623730951) TESTS: Symbolic subrings:: - sage: SCR = SR.subring(no_variables=True) - sage: sage_interactive.widget_from_tuple( (SCR(sqrt(2)), SCR(pi)) ) + sage: SCR = SR.subring(no_variables=True) # needs sage.symbolic + sage: sage_interactive.widget_from_tuple( (SCR(sqrt(2)), SCR(pi)) ) # needs sage.symbolic ...FloatSlider(value=2.277903107981444, max=3.141592653589793, min=1.4142135623730951) """ # Support (description, abbrev) diff --git a/src/sage/repl/ipython_kernel/kernel.py b/src/sage/repl/ipython_kernel/kernel.py index a4642014e90..73681716aa2 100644 --- a/src/sage/repl/ipython_kernel/kernel.py +++ b/src/sage/repl/ipython_kernel/kernel.py @@ -6,14 +6,14 @@ notebook or remote Jupyter sessions. """ -#***************************************************************************** +# *************************************************************************** # Copyright (C) 2015 Volker Braun <vbraun.name@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** import sys from ipykernel.ipkernel import IPythonKernel @@ -24,6 +24,7 @@ from sage.repl.interpreter import SageNotebookInteractiveShell from sage.repl.ipython_extension import SageJupyterCustomizations + class SageZMQInteractiveShell(SageNotebookInteractiveShell, ZMQInteractiveShell): pass @@ -98,7 +99,10 @@ def help_links(self): """ from sage.repl.ipython_kernel.install import SageKernelSpec identifier = SageKernelSpec.identifier() - kernel_url = lambda x: 'kernelspecs/{0}/{1}'.format(identifier, x) + + def kernel_url(x): + return 'kernelspecs/{0}/{1}'.format(identifier, x) + return [ { 'text': 'Sage Documentation', diff --git a/src/sage/repl/ipython_kernel/widgets.py b/src/sage/repl/ipython_kernel/widgets.py index 3ba45df9b04..14c879373a5 100644 --- a/src/sage/repl/ipython_kernel/widgets.py +++ b/src/sage/repl/ipython_kernel/widgets.py @@ -173,7 +173,7 @@ class EvalWidget(TransformWidget): sage: w = EvalToggleButtons(options=["pi", "e"], transform=lambda x: x+x) sage: w EvalToggleButtons(options=('pi', 'e'), value='pi') - sage: w.get_interact_value() + sage: w.get_interact_value() # needs sage.symbolic 2*pi """ def get_value(self): @@ -225,7 +225,7 @@ class TransformFloatSlider(TransformWidget, FloatSlider): sage: w = TransformFloatSlider(min=0, max=100, value=7, transform=lambda x: sqrt(x)) sage: w TransformFloatSlider(value=7.0) - sage: w.get_interact_value() + sage: w.get_interact_value() # needs sage.symbolic 2.6457513110645907 """ pass @@ -310,7 +310,7 @@ class EvalText(EvalWidget, Text): sage: w = EvalText(value="pi", transform=lambda x: x^2) sage: w EvalText(value='pi') - sage: w.get_interact_value() + sage: w.get_interact_value() # needs sage.symbolic pi^2 """ pass @@ -327,7 +327,7 @@ class EvalTextarea(EvalWidget, Textarea): sage: w = EvalTextarea(value="pi", transform=lambda x: x^2) sage: w EvalTextarea(value='pi') - sage: w.get_interact_value() + sage: w.get_interact_value() # needs sage.symbolic pi^2 """ pass @@ -351,7 +351,7 @@ def get_interact_value(self): EXAMPLES:: sage: from sage.repl.ipython_kernel.widgets import SageColorPicker - sage: SageColorPicker().get_interact_value() + sage: SageColorPicker().get_interact_value() # needs sage.plot RGB color (0.0, 0.0, 0.0) """ return Color(self.value) @@ -395,11 +395,13 @@ def __init__(self, nrows, ncols, make_widget, description=u"", transform=None): EXAMPLES:: sage: from sage.repl.ipython_kernel.widgets import Grid, EvalText - sage: w = Grid(2, 2, lambda i,j: EvalText(str(j+4*i)), - ....: description="2x2 matrix", transform=matrix) - sage: w - Grid(value=[[0, 1], [4, 5]], children=(Label(value='2x2 matrix'), VBox(children=(EvalText(value='0'), EvalText(value='4'))), VBox(children=(EvalText(value='1'), EvalText(value='5'))))) - sage: w.get_interact_value() + sage: w = Grid(2, 2, lambda i,j: EvalText(str(j+4*i)), # needs sage.modules + ....: description="2x2 matrix", transform=matrix); w + Grid(value=[[0, 1], [4, 5]], + children=(Label(value='2x2 matrix'), + VBox(children=(EvalText(value='0'), EvalText(value='4'))), + VBox(children=(EvalText(value='1'), EvalText(value='5'))))) + sage: w.get_interact_value() # needs sage.modules [0 1] [4 5] diff --git a/src/sage/repl/ipython_kernel/widgets_sagenb.py b/src/sage/repl/ipython_kernel/widgets_sagenb.py index 76f4f52ac4a..cedf713248a 100644 --- a/src/sage/repl/ipython_kernel/widgets_sagenb.py +++ b/src/sage/repl/ipython_kernel/widgets_sagenb.py @@ -29,12 +29,12 @@ # **************************************************************************** from ipywidgets.widgets import (IntSlider, IntRangeSlider, FloatSlider, - FloatRangeSlider, SelectionSlider, - Checkbox, ToggleButtons, Dropdown) + FloatRangeSlider, SelectionSlider, + Checkbox, ToggleButtons, Dropdown) from .widgets import (TransformText, TransformTextarea, - TransformIntSlider, TransformIntRangeSlider, - TransformFloatSlider, TransformFloatRangeSlider, - EvalText, EvalTextarea, SageColorPicker, Grid) + TransformIntSlider, TransformIntRangeSlider, + TransformFloatSlider, TransformFloatRangeSlider, + EvalText, EvalTextarea, SageColorPicker, Grid) from ipywidgets.widgets.interaction import _get_min_max_value from collections.abc import Iterable, Sequence from numbers import Integral, Rational, Real @@ -43,10 +43,10 @@ from sage.arith.srange import srange import sage.rings.abc -Color = None - from .widgets import HTMLText as text_control +Color = None + def input_box(default=None, label=None, type=None, width=80, height=1): """ @@ -91,7 +91,7 @@ def input_box(default=None, label=None, type=None, width=80, height=1): 9 With a different ``type``, the text is evaluated and ``type`` is - called on it: + called on it:: sage: w = input_box("4+5", type=float) sage: w @@ -153,7 +153,7 @@ def input_box(default=None, label=None, type=None, width=80, height=1): if label is not None: kwds["description"] = label w = cls(**kwds) - w.layout.max_width = str(width+1) + "em" + w.layout.max_width = str(width + 1) + "em" return w @@ -470,7 +470,7 @@ def selector(values, label=None, default=None, nrows=None, ncols=None, width=Non sage: selector([(1,"one"), (2,"two"), (3,"three")], buttons=True) ToggleButtons(options=(('one', 1), ('two', 2), ('three', 3)), value=1) - The values can be any kind of object: + The values can be any kind of object:: sage: selector([sin(x^2), GF(29), EllipticCurve('37a1')]) Dropdown(options=(sin(x^2), Finite Field of size 29, Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field), value=sin(x^2)) diff --git a/src/sage/repl/load.py b/src/sage/repl/load.py index d43363682b0..4b82e3d021e 100644 --- a/src/sage/repl/load.py +++ b/src/sage/repl/load.py @@ -132,7 +132,7 @@ def load(filename, globals, attach=False): sage: with open(t, 'w') as f: ....: _ = f.write("print(('hi', 2^3)); z = -2^7") sage: z = 1 - sage: sage.repl.load.load(t, globals()) + sage: sage.repl.load.load(t, globals()) # needs sage.misc.cython Compiling ... ('hi', 1) sage: z @@ -177,16 +177,17 @@ def load(filename, globals, attach=False): current working directory, i.e., ``'.'``. But you can modify the path with :func:`load_attach_path`:: + sage: import tempfile sage: sage.repl.attach.reset(); reset_load_attach_path() sage: load_attach_path() ['.'] - sage: t_dir = tmp_dir() - sage: fname = 'test.py' - sage: fullpath = os.path.join(t_dir, fname) - sage: with open(fullpath, 'w') as f: - ....: _ = f.write("print(37 * 3)") - sage: load_attach_path(t_dir, replace=True) - sage: attach(fname) + sage: with tempfile.TemporaryDirectory() as t_dir: + ....: fname = 'test.py' + ....: fullpath = os.path.join(t_dir, fname) + ....: with open(fullpath, 'w') as f: + ....: _ = f.write("print(37 * 3)") + ....: load_attach_path(t_dir, replace=True) + ....: attach(fname) 111 sage: sage.repl.attach.reset(); reset_load_attach_path() # clean up diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index 6c5e15042fb..18ab18fdeaa 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -82,18 +82,19 @@ Symbolic functional notation:: - sage: a=10; f(theta, beta) = theta + beta; b = x^2 + theta # optional - sage.symbolic - sage: f # optional - sage.symbolic + sage: # needs sage.symbolic + sage: a=10; f(theta, beta) = theta + beta; b = x^2 + theta + sage: f (theta, beta) |--> beta + theta - sage: a # optional - sage.symbolic + sage: a 10 - sage: b # optional - sage.symbolic + sage: b x^2 + theta - sage: f(theta,theta) # optional - sage.symbolic + sage: f(theta,theta) 2*theta - sage: a = 5; f(x,y) = x*y*sqrt(a) # optional - sage.symbolic - sage: f # optional - sage.symbolic + sage: a = 5; f(x,y) = x*y*sqrt(a) # needs sage.symbolic + sage: f # needs sage.symbolic (x, y) |--> sqrt(5)*x*y This involves an =-, but should still be turned into a symbolic @@ -101,8 +102,8 @@ sage: preparse('a(x) =- 5') '__tmp__=var("x"); a = symbolic_expression(- Integer(5)).function(x)' - sage: f(x)=-x # optional - sage.symbolic - sage: f(10) # optional - sage.symbolic + sage: f(x)=-x # needs sage.symbolic + sage: f(10) # needs sage.symbolic -10 This involves -=, which should not be turned into a symbolic @@ -297,12 +298,13 @@ def implicit_multiplication(level=None): global implicit_mul_level if level is None: return implicit_mul_level - elif level is True: + if level is True: implicit_mul_level = 5 else: implicit_mul_level = level -def isalphadigit_(s): + +def isalphadigit_(s) -> bool: """ Return ``True`` if ``s`` is a non-empty string of alphabetic characters or a non-empty string of digits or just a single ``_`` @@ -321,13 +323,16 @@ def isalphadigit_(s): """ return s.isalpha() or s.isdigit() or s == "_" + in_single_quote = False in_double_quote = False in_triple_quote = False -def in_quote(): + +def in_quote() -> bool: return in_single_quote or in_double_quote or in_triple_quote + class QuoteStack: """The preserved state of parsing in :func:`strip_string_literals`.""" @@ -340,9 +345,8 @@ def __init__(self): sage: qs = sage.repl.preparse.QuoteStack() sage: len(qs) 0 - """ - self._stack = [] # list of QuoteStackFrame + self._stack = [] # list of QuoteStackFrame self._single_quote_safe = True self._double_quote_safe = True @@ -360,7 +364,6 @@ def __len__(self): QuoteStackFrame(...) sage: len(qs) 0 - """ return len(self._stack) @@ -376,7 +379,6 @@ def __repr__(self): [QuoteStackFrame(...delim='"'...)] sage: qs.push(sage.repl.preparse.QuoteStackFrame("'")); qs [QuoteStackFrame(...delim='"'...), QuoteStackFrame(...delim="'"...)] - """ return repr(self._stack) @@ -391,7 +393,6 @@ def peek(self): sage: qs.push(sage.repl.preparse.QuoteStackFrame('"')) sage: qs.peek() QuoteStackFrame(...delim='"'...) - """ return self._stack[-1] if self._stack else None @@ -411,7 +412,6 @@ def pop(self): sage: qs.push(sage.repl.preparse.QuoteStackFrame('"')) sage: qs.pop() QuoteStackFrame(...delim='"'...) - """ return self._stack.pop() @@ -428,7 +428,6 @@ def push(self, frame): sage: qs.push(sage.repl.preparse.QuoteStackFrame("'")) sage: len(qs) 1 - """ self._stack.append(frame) if frame.f_string: @@ -469,14 +468,12 @@ def safe_delimiter(self): sage: s.push(QuoteStackFrame('"', f_string=True)) sage: s.safe_delimiter() is None True - """ if self._single_quote_safe: return "'" - elif self._double_quote_safe: + if self._double_quote_safe: return '"' - else: - return None + return None class QuoteStackFrame(SimpleNamespace): @@ -484,7 +481,6 @@ class QuoteStackFrame(SimpleNamespace): The state of a single level of a string literal being parsed. Only F-strings have more than one level. - """ def __init__(self, delim, raw=False, f_string=False, braces=0, parens=0, brackets=0, @@ -538,7 +534,7 @@ def strip_string_literals(code, state=None): - ``code`` - a string; the input - - ``state`` - a :class:`QuoteStack` (default: None); state with which to + - ``state`` - a :class:`QuoteStack` (default: ``None``); state with which to continue processing, e.g., across multiple calls to this function OUTPUT: @@ -722,13 +718,12 @@ def strip_string_literals(code, state=None): ' f\'{r"abc".upper()[1:]:{width:10}}\' ' sage: s_broken_up == s_one_time True - """ new_code = [] literals = {} - counter = 0 # to assign unique label numbers - start = 0 # characters before this point have been added to new_code or literals - q = 0 # current search position in code string + counter = 0 # to assign unique label numbers + start = 0 # characters before this point have been added to new_code or literals + q = 0 # current search position in code string state = state or QuoteStack() quote = state.peek() @@ -736,10 +731,9 @@ def in_literal(): """In the literal portion of a string?""" if not quote: return False - elif not quote.f_string or not quote.braces or quote.nested_fmt_spec: + if not quote.f_string or not quote.braces or quote.nested_fmt_spec: return True - else: - return quote.fmt_spec and quote.braces == 1 + return quote.fmt_spec and quote.braces == 1 match = ssl_search_chars.search(code) while match: @@ -765,17 +759,17 @@ def in_literal(): if in_literal(): # Deal with escaped quotes (odd number of backslashes preceding). escaped = False - if q>0 and code[q-1] == '\\': + if q > 0 and code[q - 1] == '\\': k = 2 - while q >= k and code[q-k] == '\\': + while q >= k and code[q - k] == '\\': k += 1 - if k % 2 == 0: + if not k % 2: escaped = True # Check for end of quote. - if not escaped and code[q:q+len(quote.delim)] == quote.delim: + if not escaped and code[q:q + len(quote.delim)] == quote.delim: counter += 1 label = "L%s" % counter - literals[label] = code[start:q+len(quote.delim)] + literals[label] = code[start:q + len(quote.delim)] new_code.append("%%(%s)s" % label) q += len(quote.delim) start = q @@ -783,17 +777,17 @@ def in_literal(): quote = state.peek() else: # Check prefixes for raw or F-string. - if q>0 and code[q-1] in 'rR': + if q > 0 and code[q - 1] in 'rR': raw = True - f_string = q>1 and code[q-2] in 'fF' - elif q>0 and code[q-1] in 'fF': + f_string = q > 1 and code[q - 2] in 'fF' + elif q > 0 and code[q - 1] in 'fF': f_string = True - raw = q>1 and code[q-2] in 'rR' + raw = q > 1 and code[q - 2] in 'rR' else: raw = f_string = False # Short or long string? - if len(code) >= q+3 and (code[q+1] == ch == code[q+2]): - delim = ch*3 + if len(code) >= q + 3 and (code[q + 1] == ch == code[q + 2]): + delim = ch * 3 else: delim = ch # Now inside quotes. @@ -812,7 +806,7 @@ def in_literal(): newline = len(code) counter += 1 label = "L%s" % counter - literals[label] = code[q+1:newline] + literals[label] = code[q + 1:newline] new_code.append(code[start:q].replace('%', '%%')) new_code.append("#%%(%s)s" % label) start = q = newline @@ -831,13 +825,13 @@ def in_literal(): handle_colon = True if handle_colon: # Treat the preceding substring and the colon itself as code. - new_code.append(code[start:q+1].replace('%', '%%')) - start = q+1 + new_code.append(code[start:q + 1].replace('%', '%%')) + start = q + 1 elif ch == '{' or ch == '}': if quote and quote.f_string: # Skip over {{ and }} escape sequences outside of replacement sections. - if not quote.braces and q+1 < len(code) and code[q+1] == ch: + if not quote.braces and q + 1 < len(code) and code[q + 1] == ch: q += 2 else: # Handle the substring preceding the brace. @@ -857,7 +851,7 @@ def in_literal(): quote.braces -= 1 # We can no longer be in a nested format specifier following a }. quote.nested_fmt_spec = False - start = q+1 + start = q + 1 # Move to the next character if we have not already moved elsewhere. if q == orig_q: @@ -878,7 +872,7 @@ def in_literal(): return "".join(new_code), literals, state -def containing_block(code, idx, delimiters=['()','[]','{}'], require_delim=True): +def containing_block(code, idx, delimiters=['()', '[]', '{}'], require_delim=True): """ Find the code block given by balanced delimiters that contains the position ``idx``. @@ -893,8 +887,8 @@ def containing_block(code, idx, delimiters=['()','[]','{}'], require_delim=True) character and no character can at the same time be opening and closing delimiter. - - ``require_delim`` - a boolean (default: True); whether to raise - a SyntaxError if delimiters are present. If the delimiters are + - ``require_delim`` - a boolean (default: ``True``); whether to raise + a ``SyntaxError`` if delimiters are present. If the delimiters are unbalanced, an error will be raised in any case. OUTPUT: @@ -969,7 +963,6 @@ def containing_block(code, idx, delimiters=['()','[]','{}'], require_delim=True) (0, 6) sage: containing_block('abc',1, require_delim=False) (0, 3) - """ openings = "".join(d[0] for d in delimiters) closings = "".join(d[-1] for d in delimiters) @@ -1005,7 +998,7 @@ def containing_block(code, idx, delimiters=['()','[]','{}'], require_delim=True) if code[end] in closings: p = closings.index(code[end]) levels[p] += 1 - if p==p0 and levels[p] == 0: + if p == p0 and levels[p] == 0: break elif code[end] in openings and end > idx: p = openings.index(code[end]) @@ -1028,7 +1021,7 @@ def parse_ellipsis(code, preparse_step=True): - ``code`` - a string - - ``preparse_step`` - a boolean (default: True) + - ``preparse_step`` - a boolean (default: ``True``) OUTPUT: @@ -1056,33 +1049,33 @@ def parse_ellipsis(code, preparse_step=True): while ix != -1: if ix == 0: raise SyntaxError("cannot start line with ellipsis") - elif code[ix-1]=='.': + elif code[ix - 1] == '.': # '...' be valid Python in index slices - code = code[:ix-1] + "Ellipsis" + code[ix+2:] - elif len(code) >= ix+3 and code[ix+2]=='.': + code = code[:ix - 1] + "Ellipsis" + code[ix + 2:] + elif len(code) >= ix + 3 and code[ix + 2] == '.': # '...' be valid Python in index slices - code = code[:ix] + "Ellipsis" + code[ix+3:] + code = code[:ix] + "Ellipsis" + code[ix + 3:] else: - start_list, end_list = containing_block(code, ix, ['()','[]']) + start_list, end_list = containing_block(code, ix, ['()', '[]']) - #search the current containing block for other '..' occurrences that may - #be contained in proper subblocks. Those need to be processed before - #we can deal with the present level of ellipses. - ix = code.find('..',ix+2,end_list) + # search the current containing block for other '..' occurrences that may + # be contained in proper subblocks. Those need to be processed before + # we can deal with the present level of ellipses. + ix = code.find('..', ix + 2, end_list) while ix != -1: - if code[ix-1]!='.' and code[ix+2]!='.': - start_list,end_list = containing_block(code,ix,['()','[]']) - ix = code.find('..',ix+2,end_list) + if code[ix - 1] != '.' and code[ix + 2] != '.': + start_list, end_list = containing_block(code, ix, ['()', '[]']) + ix = code.find('..', ix + 2, end_list) - arguments = code[start_list+1:end_list-1].replace('...', ',Ellipsis,').replace('..', ',Ellipsis,') + arguments = code[start_list + 1:end_list - 1].replace('...', ',Ellipsis,').replace('..', ',Ellipsis,') arguments = re.sub(r',\s*,', ',', arguments) if preparse_step: arguments = arguments.replace(';', ', step=') - range_or_iter = 'range' if code[start_list]=='[' else 'iter' - code = "%s(ellipsis_%s(%s))%s" % (code[:start_list], - range_or_iter, - arguments, - code[end_list:]) + range_or_iter = 'range' if code[start_list] == '[' else 'iter' + code = "%s(ellipsis_%s(%s))%s" % (code[:start_list], + range_or_iter, + arguments, + code[end_list:]) ix = code.find('..') return code @@ -1120,8 +1113,10 @@ def extract_numeric_literals(code): """ return preparse_numeric_literals(code, True) + all_num_regex = None + def preparse_numeric_literals(code, extract=False, quotes="'"): """ Preparse numerical literals into their Sage counterparts, @@ -1297,11 +1292,11 @@ def preparse_numeric_literals(code, extract=False, quotes="'"): # The Sage preparser does extra things with numbers, which we need to handle here. if '.' in num: if start > 0 and num[0] == '.': - if code[start-1] == '.': + if code[start - 1] == '.': # handle Ellipsis start += 1 num = num[1:] - elif re.match(r'[\w\])]', code[start-1]): + elif re.match(r'[\w\])]', code[start - 1]): # handle R.0 continue elif end < len(code) and num[-1] == '.': @@ -1312,7 +1307,7 @@ def preparse_numeric_literals(code, extract=False, quotes="'"): elif end < len(code) and code[end] == '.' and not postfix and re.match(r'\d+(_\d+)*$', num): # \b does not match after the . for floating point # two dots in a row would be an ellipsis - if end+1 == len(code) or code[end+1] != '.': + if end + 1 == len(code) or code[end + 1] != '.': end += 1 num += '.' @@ -1343,7 +1338,7 @@ def preparse_numeric_literals(code, extract=False, quotes="'"): new_code.append(code[last:start]) if extract: - new_code.append(num_name+' ') + new_code.append(num_name + ' ') else: new_code.append(num_make) last = end @@ -1358,7 +1353,7 @@ def preparse_numeric_literals(code, extract=False, quotes="'"): def strip_prompts(line): r""" - Removes leading sage: and >>> prompts so that pasting of examples + Remove leading sage: and >>> prompts so that pasting of examples from the documentation works. INPUT: @@ -1379,10 +1374,9 @@ def strip_prompts(line): sage: strip_prompts(" 2 + 4") ' 2 + 4' """ - for prompt in ['sage:', '>>>']: + for prompt, length in [('sage:', 5), ('>>>', 3)]: if line.startswith(prompt): - line = line[len(prompt):].lstrip() - break + return line[length:].lstrip() return line @@ -1504,14 +1498,14 @@ def preparse_calculus(code): if last_end == 0: return code - else: - new_code.append(code[m.end():]) - return ''.join(new_code) + + new_code.append(code[m.end():]) + return ''.join(new_code) def preparse_generators(code): r""" - Parses generator syntax, converting:: + Parse generator syntax, converting:: obj.<gen0,gen1,...,genN> = objConstructor(...) @@ -1663,7 +1657,7 @@ def preparse_generators(code): raise SyntaxError("mismatched ')'") opening = constructor.rindex('(') # Only use comma if there are already arguments to the constructor - comma = ', ' if constructor[opening+1:-1].strip() != '' else '' + comma = ', ' if constructor[opening + 1:-1].strip() else '' names = "('%s',)" % "', '".join(gens) constructor = constructor[:-1] + comma + "names=%s)" % names elif constructor[-1] == ']': @@ -1672,9 +1666,9 @@ def preparse_generators(code): raise SyntaxError("mismatched ']'") opening = constructor.rindex('[') closing = constructor.index(']', opening) - if constructor[opening+1:closing].strip() == '': + if not constructor[opening + 1:closing].strip(): names = "'" + ', '.join(gens) + "'" - constructor = constructor[:opening+1] + names + constructor[closing:] + constructor = constructor[:opening + 1] + names + constructor[closing:] else: pass gens_tuple = "(%s,)" % ', '.join(gens) @@ -1685,9 +1679,9 @@ def preparse_generators(code): if last_end == 0: return code - else: - new_code.append(code[m.end():]) - return ''.join(new_code) + + new_code.append(code[m.end():]) + return ''.join(new_code) quote_state = None @@ -1696,19 +1690,19 @@ def preparse_generators(code): def preparse(line, reset=True, do_time=False, ignore_prompts=False, numeric_literals=True): r""" - Preparses a line of input. + Preparse a line of input. INPUT: - ``line`` - a string - - ``reset`` - a boolean (default: True) + - ``reset`` - a boolean (default: ``True``) - - ``do_time`` - a boolean (default: False) + - ``do_time`` - a boolean (default: ``False``) - - ``ignore_prompts`` - a boolean (default: False) + - ``ignore_prompts`` - a boolean (default: ``False``) - - ``numeric_literals`` - a boolean (default: True) + - ``numeric_literals`` - a boolean (default: ``True``) OUTPUT: @@ -1726,7 +1720,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, "ZZ = ZZ['u,v']; (x, y,) = ZZ._first_ngens(2)" sage: preparse("ZZ.<x> = QQ[2^(1/3)]") 'ZZ = QQ[Integer(2)**(Integer(1)/Integer(3))]; (x,) = ZZ._first_ngens(1)' - sage: QQ[2^(1/3)] + sage: QQ[2^(1/3)] # needs sage.rings.number_field sage.symbolic Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873? sage: preparse("a^b") @@ -1786,7 +1780,8 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, if L.startswith('...'): i = line.find('...') - return line[:i+3] + preparse(line[i+3:], reset=reset, do_time=do_time, ignore_prompts=ignore_prompts) + return line[:i + 3] + preparse(line[i + 3:], reset=reset, + do_time=do_time, ignore_prompts=ignore_prompts) if ignore_prompts: # Get rid of leading sage: and >>> so that pasting of examples from @@ -1808,7 +1803,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, if implicit_mul_level: # Implicit Multiplication # 2x -> 2*x - L = implicit_mul(L, level = implicit_mul_level) + L = implicit_mul(L, level=implicit_mul_level) if numeric_literals: # Wrapping @@ -1840,7 +1835,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, ends.append(i) while ends: i = ends.pop() - L = L[:i] + ';%s;' % L[i] + L[i+1:] + L = L[:i] + ';%s;' % L[i] + L[i + 1:] L = ';' + L + ';' if do_time: @@ -1870,13 +1865,11 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, L = L.replace(';#;', '#') L = L.replace(';\n;', '\n')[1:-1] - line = L % literals - - return line + return L % literals ###################################################### -## Apply the preparser to an entire file +# Apply the preparser to an entire file ###################################################### def preparse_file(contents, globals=None, numeric_literals=True): @@ -1893,11 +1886,11 @@ def preparse_file(contents, globals=None, numeric_literals=True): - ``contents`` - a string - - ``globals`` - dict or None (default: None); if given, then + - ``globals`` - dict or None (default: ``None``); if given, then arguments to load/attach are evaluated in the namespace of this dict. - - ``numeric_literals`` - bool (default: True), whether to factor + - ``numeric_literals`` - bool (default: ``True``), whether to factor out wrapping of integers and floats, so they do not get created repeatedly inside loops @@ -1918,19 +1911,17 @@ def preparse_file(contents, globals=None, numeric_literals=True): sage: file_contents = ''' ....: @parallel(8) - ....: def f(p): + ....: def func(p): ....: t = cputime() ....: M = ModularSymbols(p^2,sign=1) ....: w = M.atkin_lehner_operator(p) - ....: K = (w-1).kernel() - ....: N = K.new_subspace() - ....: D = N.decomposition()''' + ....: K = (w-1).kernel()''' sage: t = tmp_filename(ext=".sage") - sage: with open(t, 'w') as f: - ....: f.write(file_contents) - 185 + sage: with open(t, 'w') as file: + ....: file.write(file_contents) + 137 sage: load(t) - sage: sorted(list(f([11,17]))) + sage: sorted(list(func([11,17]))) # needs sage.modular [(((11,), {}), None), (((17,), {}), None)] """ if not isinstance(contents, str): @@ -1950,7 +1941,7 @@ def preparse_file(contents, globals=None, numeric_literals=True): if ix == -1: ix = len(contents) if not re.match(r"^ *(#.*)?$", contents[:ix]): - contents = "\n"+contents + contents = "\n" + contents assignments = ["%s = %s" % x for x in nums.items()] # the preparser recurses on semicolons, so we only attempt # to preserve line numbers if there are a few @@ -1966,7 +1957,7 @@ def preparse_file(contents, globals=None, numeric_literals=True): # Preparse contents prior to the load/attach. lines_out += preparse(contents[start:m.start()], **preparse_opts).splitlines() # Wrap the load/attach itself. - lines_out.append(m.group(1) + load_wrap(m.group(3), m.group(2)=='attach')) + lines_out.append(m.group(1) + load_wrap(m.group(3), m.group(2) == 'attach')) # Further preparsing should start after this load/attach line. start = m.end() # Preparse the remaining contents. @@ -2034,7 +2025,7 @@ def implicit_mul(code, level=5): keywords_py2 = ['print', 'exec'] def re_no_keyword(pattern, code): - for _ in range(2): # do it twice in because matches do not overlap + for _ in range(2): # do it twice in because matches do not overlap for m in reversed(list(re.finditer(pattern, code))): left, right = m.groups() if not iskeyword(left) and not iskeyword(right) \ @@ -2054,7 +2045,7 @@ def re_no_keyword(pattern, code): code = re.sub(r'\b(\d+(?:\.\d+)?)e([-\d])', r'\1%se%s\2' % (no_mul_token, no_mul_token), code, flags=re.I) # exclude such things as 1e5 code = re_no_keyword(r'\b((?:\d+(?:\.\d+)?)|(?:%s[0-9eEpn]*\b)) *([^\W\d(]\w*)\b' % numeric_literal_prefix, code) if level >= 2: - code = re.sub(r'(\%\(L\d+\))s', r'\1%ss%s' % (no_mul_token, no_mul_token), code) # literal strings + code = re.sub(r'(\%\(L\d+\))s', r'\1%ss%s' % (no_mul_token, no_mul_token), code) # literal strings code = re_no_keyword(r'(\)) *(\w+)', code) if level >= 3: code = re_no_keyword(r'(\w+) +(\w+)', code) @@ -2066,7 +2057,7 @@ def re_no_keyword(pattern, code): def _strip_quotes(s): """ - Strips one set of outer quotes. + Strip one set of outer quotes. INPUT: @@ -2092,7 +2083,7 @@ def _strip_quotes(s): sage: sage.repl.preparse._strip_quotes('""foo".sage""') '"foo".sage"' """ - if len(s) == 0: + if not s: return s if s[0] in ["'", '"']: s = s[1:] @@ -2179,7 +2170,6 @@ def handle_encoding_declaration(contents, out): # -*- coding: utf-42 -*- '#!/usr/local/bin/python\nimport os, sys' - .. NOTE:: - :pep:`263` says that Python will interpret a UTF-8 @@ -2201,7 +2191,7 @@ def handle_encoding_declaration(contents, out): for num, line in enumerate(lines[:2]): if re.search(r"coding[:=]\s*([-\w.]+)", line): out.write(line + '\n') - return '\n'.join(lines[:num] + lines[(num+1):]) + return '\n'.join(lines[:num] + lines[(num + 1):]) # If we did not find any encoding hints, use utf-8. This is not in # conformance with PEP 263, which says that Python files default to @@ -2209,6 +2199,7 @@ def handle_encoding_declaration(contents, out): out.write("# -*- coding: utf-8 -*-\n") return contents + def preparse_file_named_to_stream(name, out): r""" Preparse file named \code{name} (presumably a .sage file), outputting to @@ -2219,11 +2210,12 @@ def preparse_file_named_to_stream(name, out): contents = f.read() contents = handle_encoding_declaration(contents, out) parsed = preparse_file(contents) - out.write('#'*70+'\n') - out.write('# This file was *autogenerated* from the file %s.\n' % name) - out.write('#'*70+'\n') + out.write('#' * 70 + '\n') + out.write(f'# This file was *autogenerated* from the file {name}.\n') + out.write('#' * 70 + '\n') out.write(parsed) + def preparse_file_named(name): r""" Preparse file named \code{name} (presumably a .sage file), outputting to a diff --git a/src/sage/repl/rich_output/backend_base.py b/src/sage/repl/rich_output/backend_base.py index e9ca0b4d3ba..9d76fc1ed76 100644 --- a/src/sage/repl/rich_output/backend_base.py +++ b/src/sage/repl/rich_output/backend_base.py @@ -39,14 +39,14 @@ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Volker Braun <vbraun.name@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import builtins from io import StringIO @@ -459,6 +459,7 @@ def latex_formatter(self, obj, **kwds): sage: out.html.get_str() '<html>\\(\\displaystyle \\frac{1}{2}\\)</html>' + sage: # needs sage.symbolic sage: out = backend.latex_formatter([1/2, x, 3/4, ZZ], concatenate=False) sage: out.html.get_str() '<html>\\(\\displaystyle \\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left[\\frac{1}{2}, x, \\frac{3}{4}, \\Bold{Z}\\right]\\)</html>' diff --git a/src/sage/repl/rich_output/backend_doctest.py b/src/sage/repl/rich_output/backend_doctest.py index da9cb737a2a..69905f7b067 100644 --- a/src/sage/repl/rich_output/backend_doctest.py +++ b/src/sage/repl/rich_output/backend_doctest.py @@ -164,14 +164,14 @@ def displayhook(self, plain_text, rich_output): This ends up calling the displayhook:: - sage: plt = plot(sin) - sage: plt + sage: plt = plot(sin) # needs sage.plot sage.symbolic + sage: plt # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive - sage: plt.show() + sage: plt.show() # needs sage.plot sage.symbolic sage: from sage.repl.rich_output import get_display_manager sage: dm = get_display_manager() - sage: dm.displayhook(plt) # indirect doctest + sage: dm.displayhook(plt) # indirect doctest # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive """ self.validate(rich_output) @@ -198,14 +198,14 @@ def display_immediately(self, plain_text, rich_output): displayhook, the plot is still shown. Nothing is shown during doctests:: - sage: plt = plot(sin) - sage: plt + sage: plt = plot(sin) # needs sage.plot sage.symbolic + sage: plt # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive - sage: plt.show() + sage: plt.show() # needs sage.plot sage.symbolic sage: from sage.repl.rich_output import get_display_manager sage: dm = get_display_manager() - sage: dm.display_immediately(plt) # indirect doctest + sage: dm.display_immediately(plt) # indirect doctest # needs sage.plot sage.symbolic """ self.validate(rich_output) types_to_print = [OutputPlainText, OutputAsciiArt, OutputUnicodeArt, OutputHtml] diff --git a/src/sage/repl/rich_output/backend_emacs.py b/src/sage/repl/rich_output/backend_emacs.py index c1c54a27ea6..112650270dd 100644 --- a/src/sage/repl/rich_output/backend_emacs.py +++ b/src/sage/repl/rich_output/backend_emacs.py @@ -7,14 +7,14 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Ivan Andrus <darthandrus@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from sage.repl.rich_output.backend_ipython import BackendIPythonCommandline from sage.repl.rich_output.output_catalog import * diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index 981ecdf2cb1..86bdf342e3e 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -6,14 +6,14 @@ :mod:`sage.repl.rich_output`. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Volker Braun <vbraun.name@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import os import sys @@ -362,7 +362,7 @@ def launch_jmol(self, output_jmol, plain_text): sage: from sage.repl.rich_output.backend_ipython import BackendIPythonCommandline sage: backend = BackendIPythonCommandline() sage: from sage.repl.rich_output.output_graphics3d import OutputSceneJmol - sage: backend.launch_jmol(OutputSceneJmol.example(), 'Graphics3d object') + sage: backend.launch_jmol(OutputSceneJmol.example(), 'Graphics3d object') # needs sage.plot 'Launched jmol viewer for Graphics3d object' """ from sage.doctest import DOCTEST_MODE @@ -410,7 +410,7 @@ def threejs_offline_scripts(self): sage: from sage.repl.rich_output.backend_ipython import BackendIPythonCommandline sage: backend = BackendIPythonCommandline() - sage: backend.threejs_offline_scripts() + sage: backend.threejs_offline_scripts() # needs sage.plot '...<script ...</script>...' """ from sage.env import THREEJS_DIR @@ -428,8 +428,7 @@ def normpath(p): return '\n<script src="{0}"></script>'.format(script) -IFRAME_TEMPLATE = \ -""" +IFRAME_TEMPLATE = """ <iframe srcdoc="{escaped_html}" width="{width}" height="{height}" @@ -543,35 +542,35 @@ def displayhook(self, plain_text, rich_output): 'text/plain': plain_text.text.get_str(), }, {}) elif isinstance(rich_output, OutputHtml): - data = {'text/html': rich_output.html.get_str(), + data = {'text/html': rich_output.html.get_str(), 'text/plain': plain_text.text.get_str()} if rich_output.latex: data['text/latex'] = rich_output.latex.get_str() return (data, {}) elif isinstance(rich_output, OutputImagePng): - return ({'image/png': rich_output.png.get(), + return ({'image/png': rich_output.png.get(), 'text/plain': plain_text.text.get_str(), }, {}) elif isinstance(rich_output, OutputImageGif): - return ({'text/html': rich_output.html_fragment(), + return ({'text/html': rich_output.html_fragment(), 'text/plain': plain_text.text.get_str(), }, {}) elif isinstance(rich_output, OutputImageJpg): - return ({'image/jpeg': rich_output.jpg.get(), - 'text/plain': plain_text.text.get_str(), + return ({'image/jpeg': rich_output.jpg.get(), + 'text/plain': plain_text.text.get_str(), }, {}) elif isinstance(rich_output, OutputImageSvg): return ({'image/svg+xml': rich_output.svg.get(), - 'text/plain': plain_text.text.get_str(), + 'text/plain': plain_text.text.get_str(), }, {}) elif isinstance(rich_output, OutputImagePdf): - return ({'image/png': rich_output.png.get(), + return ({'image/png': rich_output.png.get(), 'text/plain': plain_text.text.get_str(), }, {}) elif isinstance(rich_output, OutputSceneJmol): from sage.repl.display.jsmol_iframe import JSMolHtml jsmol = JSMolHtml(rich_output, height=500) - return ({'text/html': jsmol.iframe(), + return ({'text/html': jsmol.iframe(), 'text/plain': plain_text.text.get_str(), }, {}) elif isinstance(rich_output, OutputSceneThreejs): @@ -581,7 +580,7 @@ def displayhook(self, plain_text, rich_output): width='100%', height=400, ) - return ({'text/html': iframe, + return ({'text/html': iframe, 'text/plain': plain_text.text.get_str(), }, {}) else: @@ -599,7 +598,7 @@ def threejs_offline_scripts(self): sage: from sage.repl.rich_output.backend_ipython import BackendIPythonNotebook sage: backend = BackendIPythonNotebook() - sage: backend.threejs_offline_scripts() + sage: backend.threejs_offline_scripts() # needs sage.plot '...<script src="/nbextensions/threejs-sage/r.../three.min.js...<\\/script>...' """ from sage.repl.rich_output import get_display_manager diff --git a/src/sage/repl/rich_output/display_manager.py b/src/sage/repl/rich_output/display_manager.py index f022335f8e6..f6bec0209e1 100644 --- a/src/sage/repl/rich_output/display_manager.py +++ b/src/sage/repl/rich_output/display_manager.py @@ -30,7 +30,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** @@ -45,6 +45,7 @@ ) from sage.repl.rich_output.preferences import DisplayPreferences + def _required_threejs_version(): """ Return the version of threejs that Sage requires. @@ -52,7 +53,7 @@ def _required_threejs_version(): EXAMPLES:: sage: from sage.repl.rich_output.display_manager import _required_threejs_version - sage: _required_threejs_version() + sage: _required_threejs_version() # needs sage.plot 'r...' """ import os @@ -60,6 +61,7 @@ def _required_threejs_version(): with open(os.path.join(sage.env.SAGE_EXTCODE, 'threejs', 'threejs-version.txt')) as f: return f.read().strip() + class DisplayException(Exception): """ Base exception for all rich output-related exceptions. @@ -706,10 +708,12 @@ def graphics_from_save(self, save_function, save_kwds, EXAMPLES:: + sage: # needs sage.plot sage.symbolic sage: from sage.repl.rich_output import get_display_manager sage: dm = get_display_manager() sage: plt = plot(sin) - sage: out = dm.graphics_from_save(plt.save, dict(), '.png', dm.types.OutputImagePng) + sage: out = dm.graphics_from_save(plt.save, dict(), '.png', + ....: dm.types.OutputImagePng) sage: out OutputImagePng container sage: out.png.get().startswith(b'\x89PNG') @@ -756,9 +760,9 @@ def threejs_scripts(self, online): EXAMPLES:: sage: from sage.repl.rich_output import get_display_manager - sage: get_display_manager().threejs_scripts(online=True) + sage: get_display_manager().threejs_scripts(online=True) # needs sage.plot '...<script src="https://cdn.jsdelivr.net/gh/sagemath/threejs-sage@...' - sage: get_display_manager().threejs_scripts(online=False) + sage: get_display_manager().threejs_scripts(online=False) # needs sage.plot Traceback (most recent call last): ... ValueError: current backend does not support diff --git a/src/sage/repl/rich_output/output_basic.py b/src/sage/repl/rich_output/output_basic.py index 2166715d364..03f267896e6 100644 --- a/src/sage/repl/rich_output/output_basic.py +++ b/src/sage/repl/rich_output/output_basic.py @@ -320,7 +320,7 @@ def __init__(self, latex): EXAMPLES:: sage: from sage.repl.rich_output.output_catalog import OutputLatex - sage: OutputLatex(latex(sqrt(x))) + sage: OutputLatex(latex(sqrt(x))) # needs sage.symbolic OutputLatex container """ self.latex = OutputBuffer(latex) diff --git a/src/sage/repl/rich_output/output_graphics3d.py b/src/sage/repl/rich_output/output_graphics3d.py index 959412570f0..46ff6d67ad1 100644 --- a/src/sage/repl/rich_output/output_graphics3d.py +++ b/src/sage/repl/rich_output/output_graphics3d.py @@ -4,17 +4,14 @@ This module defines the rich output types for 3-d scenes. """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Volker Braun <vbraun.name@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** - - +# https://www.gnu.org/licenses/ +# **************************************************************************** import os import importlib.resources @@ -23,7 +20,6 @@ from sage.repl.rich_output.buffer import OutputBuffer - class OutputSceneJmol(OutputBase): def __init__(self, scene_zip, preview_png): diff --git a/src/sage/repl/rich_output/pretty_print.py b/src/sage/repl/rich_output/pretty_print.py index 4fcbfe4d5af..65d72068588 100644 --- a/src/sage/repl/rich_output/pretty_print.py +++ b/src/sage/repl/rich_output/pretty_print.py @@ -12,7 +12,7 @@ sage: pretty_print(1, 2, 3) 1 2 3 - sage: pretty_print(x^2 / (x + 1)) # optional - sage.symbolic + sage: pretty_print(x^2 / (x + 1)) # needs sage.symbolic x^2/(x + 1) TESTS:: @@ -23,7 +23,7 @@ EXAMPLES:: sage: %display ascii_art # not tested - sage: pretty_print(x^2 / (x + 1)) # optional - sage.symbolic + sage: pretty_print(x^2 / (x + 1)) # needs sage.symbolic 2 x ----- @@ -41,9 +41,9 @@ :func:`pretty_print` does not print anything and just shows the graphics instead:: - sage: print(plot(sin)) # optional - sage.symbolic # optional - sage.plot + sage: print(plot(sin)) # needs sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive - sage: pretty_print(plot(sin)) # optional - sage.symbolic # optional - sage.plot + sage: pretty_print(plot(sin)) # needs sage.plot sage.symbolic """ # **************************************************************************** @@ -117,10 +117,10 @@ def _concatenate_graphs(self): EXAMPLES:: sage: from sage.repl.rich_output.pretty_print import SequencePrettyPrinter - sage: plt = SequencePrettyPrinter(*list(graphs(3)))._concatenate_graphs() # optional - sage.graphs # optional - sage.plot - sage: type(plt) # optional - sage.graphs # optional - sage.plot + sage: plt = SequencePrettyPrinter(*list(graphs(3)))._concatenate_graphs() # needs sage.graphs sage.plot + sage: type(plt) # needs sage.graphs sage.plot <class 'sage.plot.multigraphics.GraphicsArray'> - sage: plt # optional - sage.graphs # optional - sage.plot + sage: plt # needs sage.graphs sage.plot Graphics Array of size 1 x 4 """ import sage.graphs.graph_list as graphs_list @@ -137,10 +137,10 @@ def _concatenate_graphics(self): EXAMPLES:: sage: from sage.repl.rich_output.pretty_print import SequencePrettyPrinter - sage: ga = SequencePrettyPrinter(*[Graphics()]*5)._concatenate_graphics() # optional - sage.plot - sage: type(ga) # optional - sage.plot + sage: ga = SequencePrettyPrinter(*[Graphics()]*5)._concatenate_graphics() # needs sage.plot + sage: type(ga) # needs sage.plot <class 'sage.plot.multigraphics.GraphicsArray'> - sage: ga.nrows(), ga.ncols() # optional - sage.plot + sage: ga.nrows(), ga.ncols() # needs sage.plot (2, 4) """ from sage.plot.plot import graphics_array @@ -159,9 +159,9 @@ def pretty_print(self): The keyword arguments are only used the first time graphics output is generated:: - sage: seq = SequencePrettyPrinter(Graph(), Graph(), edge_labels=True) # optional - sage.plot - sage: seq.pretty_print() # does not pass edge_labels to graphics object # optional - sage.plot - sage: seq._concatenate_graphs().show(edge_labels=True) # optional - sage.plot + sage: seq = SequencePrettyPrinter(Graph(), Graph(), edge_labels=True) # needs sage.graphs sage.plot + sage: seq.pretty_print() # does not pass edge_labels to graphics object # needs sage.graphs sage.plot + sage: seq._concatenate_graphs().show(edge_labels=True) # needs sage.graphs sage.plot Traceback (most recent call last): ... TypeError: ...matplotlib() got an unexpected keyword argument 'edge_labels' @@ -243,13 +243,13 @@ def pretty_print(*args, **kwds): For text-based backends, the default text display preference is to output plain text which is usually the same as using ``print()``:: - sage: pretty_print(x^2 / (x + 1)) # optional - sage.symbolic + sage: pretty_print(x^2 / (x + 1)) # needs sage.symbolic x^2/(x + 1) - sage: t = BinaryTrees(3).first() # optional - sage.combinat - sage: pretty_print(t) # optional - sage.combinat + sage: t = BinaryTrees(3).first() # needs sage.graphs + sage: pretty_print(t) # needs sage.graphs [., [., [., .]]] - sage: print(t) # optional - sage.combinat + sage: print(t) # needs sage.graphs [., [., [., .]]] TESTS:: @@ -263,7 +263,7 @@ def pretty_print(*args, **kwds): The following illustrates a possible use-case:: sage: %display ascii_art # not tested - sage: for t in BinaryTrees(3)[:3]: # optional - sage.combinat + sage: for t in BinaryTrees(3)[:3]: # needs sage.graphs ....: pretty_print(t) o \ @@ -279,7 +279,7 @@ def pretty_print(*args, **kwds): / \ o o - sage: pretty_print(x^2 / (x + 1)) # optional - sage.symbolic + sage: pretty_print(x^2 / (x + 1)) # needs sage.symbolic 2 x ----- @@ -293,10 +293,11 @@ def pretty_print(*args, **kwds): :: - sage: plt = plot(sin) # optional - sage.symbolic # optional - sage.plot - sage: pretty_print(plt) # graphics output # optional - sage.symbolic # optional - sage.plot - sage: pretty_print(plt, plt) # graphics output # optional - sage.symbolic # optional - sage.plot - sage: pretty_print(ZZ, 123, plt) # optional - sage.symbolic # optional - sage.plot + sage: # needs sage.plot sage.symbolic + sage: plt = plot(sin) + sage: pretty_print(plt) # graphics output + sage: pretty_print(plt, plt) # graphics output + sage: pretty_print(ZZ, 123, plt) Integer Ring 123 Graphics object consisting of 1 graphics primitive """ dm = get_display_manager() diff --git a/src/sage/repl/user_globals.py b/src/sage/repl/user_globals.py index 92de7d87e0c..73c13c44690 100644 --- a/src/sage/repl/user_globals.py +++ b/src/sage/repl/user_globals.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules r""" User-interface globals diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index 4d4e9bfd104..6ad9dd8d6f0 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -14,13 +14,13 @@ class NumberField_quadratic(Field): EXAMPLES:: sage: import sage.rings.abc - sage: K.<sqrt2> = QuadraticField(2) # optional - sage.rings.number_field - sage: isinstance(K, sage.rings.abc.NumberField_quadratic) # optional - sage.rings.number_field + sage: K.<sqrt2> = QuadraticField(2) # needs sage.rings.number_field + sage: isinstance(K, sage.rings.abc.NumberField_quadratic) # needs sage.rings.number_field True By design, there is a unique direct subclass:: - sage: sage.rings.abc.NumberField_quadratic.__subclasses__() # optional - sage.rings.number_field + sage: sage.rings.abc.NumberField_quadratic.__subclasses__() # needs sage.rings.number_field [<class 'sage.rings.number_field.number_field.NumberField_quadratic'>] sage: len(sage.rings.abc.NumberField_quadratic.__subclasses__()) <= 1 @@ -40,13 +40,13 @@ class NumberField_cyclotomic(Field): EXAMPLES:: sage: import sage.rings.abc - sage: K.<zeta> = CyclotomicField(15) # optional - sage.rings.number_field - sage: isinstance(K, sage.rings.abc.NumberField_cyclotomic) # optional - sage.rings.number_field + sage: K.<zeta> = CyclotomicField(15) # needs sage.rings.number_field + sage: isinstance(K, sage.rings.abc.NumberField_cyclotomic) # needs sage.rings.number_field True By design, there is a unique direct subclass:: - sage: sage.rings.abc.NumberField_cyclotomic.__subclasses__() # optional - sage.rings.number_field + sage: sage.rings.abc.NumberField_cyclotomic.__subclasses__() # needs sage.rings.number_field [<class 'sage.rings.number_field.number_field.NumberField_cyclotomic'>] sage: len(sage.rings.abc.NumberField_cyclotomic.__subclasses__()) <= 1 @@ -56,6 +56,32 @@ class NumberField_cyclotomic(Field): pass +class UniversalCyclotomicField(Field): + r""" + Abstract base class for :class:`~sage.rings.universal_cyclotomic_field.UniversalCyclotomicField`. + + This class is defined for the purpose of :func:`isinstance` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: K = UniversalCyclotomicField() # needs sage.rings.number_field + sage: isinstance(K, sage.rings.abc.UniversalCyclotomicField) # needs sage.rings.number_field + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.UniversalCyclotomicField.__subclasses__() # needs sage.rings.number_field + [<class 'sage.rings.universal_cyclotomic_field.UniversalCyclotomicField'>] + + sage: len(sage.rings.abc.NumberField_cyclotomic.__subclasses__()) <= 1 + True + """ + + pass + + class AlgebraicField_common(Field): r""" Abstract base class for :class:`~sage.rings.qqbar.AlgebraicField_common`. @@ -66,16 +92,16 @@ class AlgebraicField_common(Field): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(QQbar, sage.rings.abc.AlgebraicField_common) # optional - sage.rings.number_field + sage: isinstance(QQbar, sage.rings.abc.AlgebraicField_common) # needs sage.rings.number_field True - sage: isinstance(AA, sage.rings.abc.AlgebraicField_common) # optional - sage.rings.number_field + sage: isinstance(AA, sage.rings.abc.AlgebraicField_common) # needs sage.rings.number_field True By design, other than the abstract subclasses :class:`~sage.rings.abc.AlgebraicField` and :class:`~sage.rings.abc.AlgebraicRealField`, there is only one direct implementation subclass:: - sage: sage.rings.abc.AlgebraicField_common.__subclasses__() # optional - sage.rings.number_field + sage: sage.rings.abc.AlgebraicField_common.__subclasses__() # needs sage.rings.number_field [<class 'sage.rings.abc.AlgebraicField'>, <class 'sage.rings.abc.AlgebraicRealField'>, <class 'sage.rings.qqbar.AlgebraicField_common'>] @@ -97,14 +123,14 @@ class AlgebraicField(AlgebraicField_common): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(QQbar, sage.rings.abc.AlgebraicField) # optional - sage.rings.number_field + sage: isinstance(QQbar, sage.rings.abc.AlgebraicField) # needs sage.rings.number_field True - sage: isinstance(AA, sage.rings.abc.AlgebraicField) # optional - sage.rings.number_field + sage: isinstance(AA, sage.rings.abc.AlgebraicField) # needs sage.rings.number_field False By design, there is a unique direct subclass:: - sage: sage.rings.abc.AlgebraicField.__subclasses__() # optional - sage.rings.number_field + sage: sage.rings.abc.AlgebraicField.__subclasses__() # needs sage.rings.number_field [<class 'sage.rings.qqbar.AlgebraicField'>] sage: len(sage.rings.abc.AlgebraicField.__subclasses__()) <= 1 @@ -124,14 +150,14 @@ class AlgebraicRealField(AlgebraicField_common): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(QQbar, sage.rings.abc.AlgebraicRealField) # optional - sage.rings.number_field + sage: isinstance(QQbar, sage.rings.abc.AlgebraicRealField) # needs sage.rings.number_field False - sage: isinstance(AA, sage.rings.abc.AlgebraicRealField) # optional - sage.rings.number_field + sage: isinstance(AA, sage.rings.abc.AlgebraicRealField) # needs sage.rings.number_field True By design, there is a unique direct subclass:: - sage: sage.rings.abc.AlgebraicRealField.__subclasses__() # optional - sage.rings.number_field + sage: sage.rings.abc.AlgebraicRealField.__subclasses__() # needs sage.rings.number_field [<class 'sage.rings.qqbar.AlgebraicRealField'>] sage: len(sage.rings.abc.AlgebraicRealField.__subclasses__()) <= 1 @@ -151,12 +177,12 @@ cdef class RealField(Field): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(RR, sage.rings.abc.RealField) + sage: isinstance(RR, sage.rings.abc.RealField) # needs sage.rings.real_mpfr True By design, there is a unique direct subclass:: - sage: sage.rings.abc.RealField.__subclasses__() + sage: sage.rings.abc.RealField.__subclasses__() # needs sage.rings.real_mpfr [<class 'sage.rings.real_mpfr.RealField_class'>] sage: len(sage.rings.abc.RealField.__subclasses__()) <= 1 @@ -176,12 +202,12 @@ class RealBallField(Field): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(RBF, sage.rings.abc.RealBallField) + sage: isinstance(RBF, sage.rings.abc.RealBallField) # needs sage.libs.flint True By design, there is a unique direct subclass:: - sage: sage.rings.abc.RealBallField.__subclasses__() + sage: sage.rings.abc.RealBallField.__subclasses__() # needs sage.libs.flint [<class 'sage.rings.real_arb.RealBallField'>] sage: len(sage.rings.abc.RealBallField.__subclasses__()) <= 1 @@ -201,12 +227,12 @@ cdef class RealIntervalField(Field): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(RIF, sage.rings.abc.RealIntervalField) + sage: isinstance(RIF, sage.rings.abc.RealIntervalField) # needs sage.rings.real_interval_field True By design, there is a unique direct subclass:: - sage: sage.rings.abc.RealIntervalField.__subclasses__() + sage: sage.rings.abc.RealIntervalField.__subclasses__() # needs sage.rings.real_interval_field [<class 'sage.rings.real_mpfi.RealIntervalField_class'>] sage: len(sage.rings.abc.RealIntervalField.__subclasses__()) <= 1 @@ -251,12 +277,12 @@ cdef class ComplexField(Field): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(CC, sage.rings.abc.ComplexField) + sage: isinstance(CC, sage.rings.abc.ComplexField) # needs sage.rings.real_mpfr True By design, there is a unique direct subclass:: - sage: sage.rings.abc.ComplexField.__subclasses__() + sage: sage.rings.abc.ComplexField.__subclasses__() # needs sage.rings.real_mpfr [<class 'sage.rings.complex_mpfr.ComplexField_class'>] sage: len(sage.rings.abc.ComplexField.__subclasses__()) <= 1 @@ -276,12 +302,12 @@ class ComplexBallField(Field): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(CBF, sage.rings.abc.ComplexBallField) + sage: isinstance(CBF, sage.rings.abc.ComplexBallField) # needs sage.libs.flint True By design, there is a unique direct subclass:: - sage: sage.rings.abc.ComplexBallField.__subclasses__() + sage: sage.rings.abc.ComplexBallField.__subclasses__() # needs sage.libs.flint [<class 'sage.rings.complex_arb.ComplexBallField'>] sage: len(sage.rings.abc.ComplexBallField.__subclasses__()) <= 1 @@ -301,12 +327,12 @@ class ComplexIntervalField(Field): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(CIF, sage.rings.abc.ComplexIntervalField) + sage: isinstance(CIF, sage.rings.abc.ComplexIntervalField) # needs sage.rings.complex_interval_field True By design, there is a unique direct subclass:: - sage: sage.rings.abc.ComplexIntervalField.__subclasses__() + sage: sage.rings.abc.ComplexIntervalField.__subclasses__() # needs sage.rings.complex_interval_field [<class 'sage.rings.complex_interval_field.ComplexIntervalField_class'>] sage: len(sage.rings.abc.ComplexIntervalField.__subclasses__()) <= 1 @@ -326,12 +352,12 @@ cdef class ComplexDoubleField(Field): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(CDF, sage.rings.abc.ComplexDoubleField) + sage: isinstance(CDF, sage.rings.abc.ComplexDoubleField) # needs sage.rings.complex_double True By design, there is a unique direct subclass:: - sage: sage.rings.abc.ComplexDoubleField.__subclasses__() + sage: sage.rings.abc.ComplexDoubleField.__subclasses__() # needs sage.rings.complex_double [<class 'sage.rings.complex_double.ComplexDoubleField_class'>] sage: len(sage.rings.abc.ComplexDoubleField.__subclasses__()) <= 1 @@ -376,13 +402,14 @@ class Order: EXAMPLES:: sage: import sage.rings.abc - sage: K.<a> = NumberField(x^2 + 1); O = K.order(2*a) # optional - sage.rings.number_field - sage: isinstance(O, sage.rings.abc.Order) # optional - sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 1); O = K.order(2*a) # needs sage.rings.number_field + sage: isinstance(O, sage.rings.abc.Order) # needs sage.rings.number_field True By design, there is a unique direct subclass:: - sage: sage.rings.abc.Order.__subclasses__() # optional - sage.rings.number_field + sage: sage.rings.abc.Order.__subclasses__() # needs sage.rings.number_field [<class 'sage.rings.number_field.order.Order'>] sage: len(sage.rings.abc.Order.__subclasses__()) <= 1 @@ -402,14 +429,14 @@ class pAdicRing(EuclideanDomain): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(Zp(5), sage.rings.abc.pAdicRing) + sage: isinstance(Zp(5), sage.rings.abc.pAdicRing) # needs sage.rings.padics True - sage: isinstance(Qp(5), sage.rings.abc.pAdicRing) + sage: isinstance(Qp(5), sage.rings.abc.pAdicRing) # needs sage.rings.padics False By design, there is a unique direct subclass:: - sage: sage.rings.abc.pAdicRing.__subclasses__() + sage: sage.rings.abc.pAdicRing.__subclasses__() # needs sage.rings.padics [<class 'sage.rings.padics.generic_nodes.pAdicRingGeneric'>] sage: len(sage.rings.abc.pAdicRing.__subclasses__()) <= 1 @@ -429,14 +456,14 @@ class pAdicField(Field): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(Zp(5), sage.rings.abc.pAdicField) + sage: isinstance(Zp(5), sage.rings.abc.pAdicField) # needs sage.rings.padics False - sage: isinstance(Qp(5), sage.rings.abc.pAdicField) + sage: isinstance(Qp(5), sage.rings.abc.pAdicField) # needs sage.rings.padics True By design, there is a unique direct subclass:: - sage: sage.rings.abc.pAdicField.__subclasses__() + sage: sage.rings.abc.pAdicField.__subclasses__() # needs sage.rings.padics [<class 'sage.rings.padics.generic_nodes.pAdicFieldGeneric'>] sage: len(sage.rings.abc.pAdicField.__subclasses__()) <= 1 @@ -456,13 +483,13 @@ cdef class SymbolicRing(CommutativeRing): EXAMPLES:: sage: import sage.rings.abc - sage: isinstance(SR, sage.rings.abc.SymbolicRing) # optional - sage.symbolic + sage: isinstance(SR, sage.rings.abc.SymbolicRing) # needs sage.symbolic True By design, other than the abstract subclass :class:`~sage.rings.abc.CallableSymbolicExpressionRing`, there is only one direct implementation subclass:: - sage: sage.rings.abc.SymbolicRing.__subclasses__() # optional - sage.symbolic + sage: sage.rings.abc.SymbolicRing.__subclasses__() # needs sage.symbolic [<class 'sage.rings.abc.CallableSymbolicExpressionRing'>, <class 'sage.symbolic.ring.SymbolicRing'>] @@ -483,13 +510,13 @@ class CallableSymbolicExpressionRing(SymbolicRing): EXAMPLES:: sage: import sage.rings.abc - sage: f = x.function(x).parent() # optional - sage.symbolic - sage: isinstance(f, sage.rings.abc.CallableSymbolicExpressionRing) # optional - sage.symbolic + sage: f = x.function(x).parent() # needs sage.symbolic + sage: isinstance(f, sage.rings.abc.CallableSymbolicExpressionRing) # needs sage.symbolic True By design, there is a unique direct subclass:: - sage: sage.rings.abc.CallableSymbolicExpressionRing.__subclasses__() # optional - sage.symbolic + sage: sage.rings.abc.CallableSymbolicExpressionRing.__subclasses__() # needs sage.symbolic [<class 'sage.symbolic.callable.CallableSymbolicExpressionRing_class'>] sage: len(sage.rings.abc.CallableSymbolicExpressionRing.__subclasses__()) <= 1 diff --git a/src/sage/rings/algebraic_closure_finite_field.py b/src/sage/rings/algebraic_closure_finite_field.py index d45c3ec2cb0..d7ad457f88c 100644 --- a/src/sage/rings/algebraic_closure_finite_field.py +++ b/src/sage/rings/algebraic_closure_finite_field.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Algebraic closures of finite fields @@ -57,10 +58,9 @@ from sage.misc.abstract_method import abstract_method from sage.misc.fast_methods import WithEqualityById -from sage.rings.finite_rings.element_base import is_FiniteFieldElement -from sage.rings.finite_rings.finite_field_base import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.ring import Field -from sage.structure.element import FieldElement +from sage.structure.element import Element, FieldElement from sage.structure.richcmp import richcmp @@ -91,7 +91,7 @@ def __init__(self, parent, value): and ``loads(dumps(x))``. """ - if is_FiniteFieldElement(value): + if isinstance(value, Element) and isinstance(value.parent(), FiniteField): n = value.parent().degree() else: from sage.rings.integer import Integer @@ -340,25 +340,34 @@ def is_square(self): """ return True - def sqrt(self): + def sqrt(self, all=False): """ Return a square root of ``self``. + If the optional keyword argument ``all`` is set to ``True``, + return a list of all square roots of ``self`` instead. + EXAMPLES:: sage: F = GF(3).algebraic_closure() sage: F.gen(2).sqrt() z4^3 + z4 + 1 - + sage: F.gen(2).sqrt(all=True) + [z4^3 + z4 + 1, 2*z4^3 + 2*z4 + 2] + sage: (F.gen(2)^2).sqrt() + z2 + sage: (F.gen(2)^2).sqrt(all=True) + [z2, 2*z2] """ F = self.parent() x = self._value - if x.is_square(): - return self.__class__(F, x.sqrt(extend=False)) - else: + if not x.is_square(): l = self._level x = F.inclusion(l, 2*l)(x) - return self.__class__(F, x.sqrt(extend=False)) + sqrt = x.sqrt(extend=False, all=all) + if all: + return [self.__class__(F, y) for y in sqrt] + return self.__class__(F, sqrt) def nth_root(self, n): """ @@ -582,7 +591,7 @@ def __eq__(self, other): """ if self is other: return True - if type(self) != type(other): + if type(self) is not type(other): return False return ((self.base_ring(), self.variable_name(), self.category()) == (other.base_ring(), other.variable_name(), other.category())) @@ -659,7 +668,7 @@ def _coerce_map_from_(self, other): """ if other is self: return True - elif is_FiniteField(other) and self._subfield(other.degree()) is other: + elif isinstance(other, FiniteField) and self._subfield(other.degree()) is other: return True elif self._subfield(1).has_coerce_map_from(other): return True @@ -1092,7 +1101,7 @@ def __init__(self, base_ring, name, category=None, lattice=None, use_database=Tr :meth:`AlgebraicClosureFiniteFieldElement.__init__`. """ - if not (is_FiniteField(base_ring) and base_ring.is_prime_field()): + if not (isinstance(base_ring, FiniteField) and base_ring.is_prime_field()): raise NotImplementedError('algebraic closures of finite fields are only implemented for prime fields') from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice p = base_ring.characteristic() diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 17dd9896212..1d7b89601f5 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -1,29 +1,5 @@ """ Rings - -Tests for deprecations of imports in global namespace from :trac:`33602`:: - - sage: PowerSeries - doctest:warning...: - DeprecationWarning: - Importing PowerSeries from here is deprecated; - please use "from sage.rings.power_series_ring_element import PowerSeries" instead. - See https://github.com/sagemath/sage/issues/33602 for details. - ... - sage: PuiseuxSeries - doctest:warning...: - DeprecationWarning: - Importing PuiseuxSeries from here is deprecated; - please use "from sage.rings.puiseux_series_ring_element import PuiseuxSeries" instead. - See https://github.com/sagemath/sage/issues/33602 for details. - ... - sage: LaurentSeries - doctest:warning...: - DeprecationWarning: - Importing LaurentSeries from here is deprecated; - please use "from sage.rings.laurent_series_ring_element import LaurentSeries" instead. - See https://github.com/sagemath/sage/issues/33602 for details. - ... """ # **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> @@ -139,11 +115,9 @@ # Power series rings from .power_series_ring import PowerSeriesRing -lazy_import('sage.rings.power_series_ring_element', 'PowerSeries', deprecation=33602) # Laurent series ring in one variable from .laurent_series_ring import LaurentSeriesRing -lazy_import('sage.rings.laurent_series_ring_element', 'LaurentSeries', deprecation=33602) # Lazy Laurent series ring lazy_import('sage.rings.lazy_series_ring', ['LazyLaurentSeriesRing', 'LazyPowerSeriesRing', @@ -154,7 +128,6 @@ # Puiseux series ring from .puiseux_series_ring import PuiseuxSeriesRing -lazy_import('sage.rings.puiseux_series_ring_element', 'PuiseuxSeries', deprecation=33602) # Pseudo-ring of PARI objects. from .pari_ring import PariRing, Pari diff --git a/src/sage/rings/asymptotic/__init__.py b/src/sage/rings/asymptotic/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 38d486541d1..9a27c9d61eb 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -197,7 +197,6 @@ def Stirling(var, precision=None, skip_constant_factor=False): return result - @staticmethod def log_Stirling(var, precision=None, skip_constant_summand=False): r""" @@ -321,7 +320,6 @@ def log_Stirling(var, precision=None, skip_constant_summand=False): return result - @staticmethod def _log_StirlingNegativePowers_(var, precision): r""" @@ -371,7 +369,6 @@ def _log_StirlingNegativePowers_(var, precision): A.zero()) return result + (1 / n**(2*precision + 1)).O() - @staticmethod def HarmonicNumber(var, precision=None, skip_constant_summand=False): r""" @@ -477,7 +474,6 @@ def HarmonicNumber(var, precision=None, skip_constant_summand=False): return result - @staticmethod def Binomial_kn_over_n(var, k, precision=None, skip_constant_factor=False): r""" @@ -603,7 +599,6 @@ def Binomial_kn_over_n(var, k, precision=None, skip_constant_factor=False): return result - @staticmethod def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, precision=None, normalized=True): @@ -961,7 +956,6 @@ def inverse_gamma_derivative(shift, r): if precision is None: precision = series_precision() - if not normalized and not (beta in ZZ and delta in ZZ): raise ValueError("beta and delta must be integers") if delta != 0: @@ -1040,7 +1034,6 @@ def inverse_gamma_derivative(shift, r): return result - @staticmethod @experimental(20050) def ImplicitExpansion(var, phi, tau=None, precision=None): @@ -1208,7 +1201,6 @@ def ansatz(prec=precision): return A(tau) + ansatz(prec=precision-1).map_coefficients(lambda term: term.subs(solution_dict).simplify_rational()) - @staticmethod @experimental(20050) def ImplicitExpansionPeriodicPart(var, phi, period, tau=None, precision=None): @@ -1298,7 +1290,6 @@ def ImplicitExpansionPeriodicPart(var, phi, period, tau=None, precision=None): Z = aperiodic_expansion.parent().gen() return 1/rho * (aperiodic_expansion/(1 - 1/Z))**(1/period) - @staticmethod def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): r""" diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 1423513a993..b07319382d3 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1209,7 +1209,6 @@ def _mul_term_(self, term): return self.parent()(self.summands.mapped(lambda element: term * element), simplify=simplify, convert=False) - def _mul_(self, other): r""" Multiply this asymptotic expansion by another asymptotic expansion ``other``. @@ -1309,7 +1308,6 @@ def _div_(self, other): """ return self * ~other - def __invert__(self, precision=None): r""" Return the multiplicative inverse of this element. @@ -1485,7 +1483,6 @@ def exact_part(self): return self.parent(exact_terms) - def error_part(self): r""" Return the expansion consisting of all error terms of this @@ -1511,7 +1508,6 @@ def error_part(self): if not term.is_exact()), parent.zero()) - def __pow__(self, exponent, precision=None): r""" Calculate the power of this asymptotic expansion to the given ``exponent``. @@ -1717,10 +1713,8 @@ def __pow__(self, exponent, precision=None): raise combine_exceptions( ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) - pow = __pow__ - def __pow_number__(self, exponent, precision=None, check_convergence=False): r""" Return the power of this asymptotic expansion to some @@ -1873,7 +1867,6 @@ def binomials(a): return result * pmax - def sqrt(self, precision=None): r""" Return the square root of this asymptotic expansion. @@ -2244,7 +2237,6 @@ def rpow(self, base, precision=None, locals=None): if not expr_o: return large_result - if base == 'e': geom = expr_o else: @@ -3911,7 +3903,6 @@ def _create_empty_summands_(): can_merge=can_absorb, merge=absorption) - def _create_element_in_extension_(self, term, old_term_parent=None): r""" Create an element in an extension of this asymptotic ring which @@ -4084,7 +4075,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): if isinstance(data, MutablePoset): return self.element_class(self, data, simplify=simplify, convert=convert) - if type(data) == self.element_class and data.parent() == self: + if type(data) is self.element_class and data.parent() == self: return data if isinstance(data, AsymptoticExpansion): @@ -4158,9 +4149,9 @@ def _element_constructor_(self, data, simplify=True, convert=True): elif is_PowerSeriesRing(P): raise NotImplementedError( - 'Cannot convert %s from the %s to an asymptotic expansion ' + 'cannot convert %s from the %s to an asymptotic expansion ' 'in %s, since growths at other points than +oo are not yet ' - 'supported.' % (data, P, self)) + 'supported' % (data, P, self)) # Delete lines above as soon as we can deal with growths # other than the that at going to +oo. from sage.rings.infinity import PlusInfinity @@ -4993,7 +4984,7 @@ def __eq__(self, other): sage: F_X == F_Y False """ - return (type(self) == type(other) + return (type(self) is type(other) and self.growth_group == other.growth_group and self._default_prec_ == other._default_prec_ and self._category_ == other._category_ diff --git a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py index 771d23c7b90..8a6002af635 100644 --- a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +++ b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py @@ -823,7 +823,7 @@ def univariate_decomposition(self): for a, m in df: am = a**m q, r = denominator.quo_rem(am) - assert r==0 + assert r == 0 numer = p * q.inverse_mod(am) % am # The inverse exists because the product and a**m # are relatively prime. @@ -1251,7 +1251,7 @@ def leinartas_decomposition(self): sage: H = R(f.denominator()) sage: ff = FFPD(G, H.factor()) sage: decomp = ff.leinartas_decomposition() - sage: decomp + sage: decomp # random - non canonical depends on singular version (0, []) + (-(x*y^2*sin(x) + x^2*y + x*y + y*sin(x) + x)*y, [(y, 1)]) + ((x*y^2*sin(x) + x^2*y + x*y + y*sin(x) + x)*x*y, [(x*y + 1, 1)]) + @@ -1592,7 +1592,7 @@ def asymptotics(self, p, alpha, N, asy_var=None, numerical=0, 432, 3/5*sqrt(5)*sqrt(3)*sqrt(2)*sqrt(r)/sqrt(pi) + 463/6000*sqrt(5)*sqrt(3)*sqrt(2)/(sqrt(pi)*sqrt(r))) - sage: F.relative_error(asy[0], alpha, [1, 2, 4, 8, 16], asy[1]) # abs tol 1e-10 + sage: F.relative_error(asy[0], alpha, [1, 2, 4, 8, 16], asy[1]) # abs tol 1e-10 # long time [((4, 3), 2.083333333, [2.092576110], [-0.004436533009]), ((8, 6), 2.787374614, [2.790732875], [-0.001204811281]), ((16, 12), 3.826259447, [3.827462310], [-0.0003143703383]), @@ -1611,9 +1611,7 @@ def asymptotics(self, p, alpha, N, asy_var=None, numerical=0, (-16, [(x + 2*y + z - 4, 1), (2*x + y + z - 4, 2)]) sage: alpha = [3, 3, 2] sage: decomp = F.asymptotic_decomposition(alpha); decomp - (0, []) + - (16*r*(3/x - 2/z) + 16/x - 16/z, - [(x + 2*y + z - 4, 1), (2*x + y + z - 4, 1)]) + (0, []) + (..., [(x + 2*y + z - 4, 1), (2*x + y + z - 4, 1)]) sage: F1 = decomp[1] sage: p = {x: 1, y: 1, z: 1} sage: asy = F1.asymptotics(p, alpha, 2, verbose=True) # long time @@ -1874,7 +1872,7 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, Uderivs = diff_prod(Hderivs, U, Hcheck, X, range(1, k + 1), end, Uderivs, atP) # Check for a nonzero U derivative. - if any(u for u in Uderivs.values()): + if any(Uderivs.values()): all_zero = False if all_zero: # Then, using a proposition at the end of [RW2012], we can @@ -1932,7 +1930,7 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, if v.mod(2) == 0: At_derivs = diff_all(At, T, 2 * N - 2, sub=hderivs1, sub_final=[Tstar, atP], rekey=AA) - Phitu_derivs = diff_all(Phitu, T, 2 * N - 2 +v, + Phitu_derivs = diff_all(Phitu, T, 2 * N - 2 + v, sub=hderivs1, sub_final=[Tstar, atP], zero_order=v + 1, rekey=BB) else: @@ -2265,7 +2263,7 @@ def asymptotics_multiple(self, p, alpha, N, asy_var, coordinate=None, Uderivs = diff_prod(Hprodderivs, U, Hcheck, X, range(1, k + 1), end, Uderivs, atP) # Check for a nonzero U derivative. - if any(u for u in Uderivs.values()): + if any(Uderivs.values()): all_zero = False if all_zero: # Then all higher derivatives of U are zero. @@ -2821,7 +2819,7 @@ def maclaurin_coefficients(self, multi_indices, numerical=0): sage: alpha = vector([3, 3, 2]) sage: interval = [1, 2, 4] sage: S = [r*alpha for r in interval] - sage: F.maclaurin_coefficients(S, numerical=10) + sage: F.maclaurin_coefficients(S, numerical=10) # long time {(3, 3, 2): 0.7849731445, (6, 6, 4): 0.7005249476, (12, 12, 8): 0.5847732654} @@ -3324,7 +3322,6 @@ def _an_element_(self): from sage.rings.semirings.non_negative_integer_semiring import NN return self(NN.an_element(), [(self.base().an_element(), NN(3))]) - Element = FractionWithFactoredDenominator @@ -4029,10 +4026,10 @@ def diff_op(A, B, AB_derivs, V, M, r, N): sage: B = function('B')(*tuple(T)) sage: AB_derivs = {} sage: M = matrix([[1, 2],[2, 1]]) - sage: DD = diff_op(A, B, AB_derivs, T, M, 1, 2) - sage: sorted(DD) + sage: DD = diff_op(A, B, AB_derivs, T, M, 1, 2) # long time (see :trac:`35207`) + sage: sorted(DD) # long time [(0, 0, 0), (0, 1, 0), (0, 1, 1), (0, 1, 2)] - sage: DD[(0, 1, 2)].number_of_operands() + sage: DD[(0, 1, 2)].number_of_operands() # long time 246 """ from itertools import product diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 98f40457f07..27c14592bca 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -381,7 +381,6 @@ def __init__(self, var, repr=None, latex_name=None, ignore=None): raise ValueError('Variable names %s are not pairwise distinct.' % (var_bases,)) - self.var_bases = var_bases self.var_repr = var_repr @@ -1679,7 +1678,6 @@ class GenericGrowthGroup(UniqueRepresentation, Parent, WithLocals): # enable the category framework for elements Element = GenericGrowthElement - # set everything up to determine category from sage.categories.sets_cat import Sets from sage.categories.posets import Posets @@ -2777,7 +2775,7 @@ def __eq__(self, other): sage: F == G False """ - return type(self) == type(other) and self.var == other.var + return type(self) is type(other) and self.var == other.var def __ne__(self, other): r""" diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 645d9723e68..f93535e8d8e 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -196,7 +196,6 @@ def create_key_and_extra_args(self, growth_groups, category, **kwds): return (tuple(growth_groups), category), kwds - def create_object(self, version, args, **kwds): r""" Create an object from the given arguments. @@ -287,7 +286,6 @@ class GenericProduct(CartesianProductPoset, GenericGrowthGroup): __classcall__ = CartesianProductPoset.__classcall__ - def __init__(self, sets, category, **kwds): r""" See :class:`GenericProduct` for details. @@ -319,10 +317,8 @@ def __init__(self, sets, category, **kwds): GenericGrowthGroup.__init__(self, sets[0], Vars, self.category(), **kwds) - __hash__ = CartesianProductPoset.__hash__ - def some_elements(self): r""" Return some elements of this Cartesian product of growth groups. @@ -399,7 +395,6 @@ def _create_element_in_extension_(self, element): category=self.category()) return parent(element) - def _element_constructor_(self, data): r""" Converts the given object to an element of this Cartesian @@ -491,7 +486,7 @@ def convert_factors(data, raw_data): elif data is None: raise ValueError('%s cannot be converted.' % (data,)) - elif type(data) == self.element_class and data.parent() == self: + elif type(data) is self.element_class and data.parent() == self: return data elif isinstance(data, str): @@ -520,10 +515,8 @@ def convert_factors(data, raw_data): return convert_factors((data,), data) - _repr_ = GenericGrowthGroup._repr_ - def _repr_short_(self): r""" A short (shorter than :meth:`._repr_`) representation string @@ -547,7 +540,6 @@ def _repr_short_(self): """ return ' * '.join(S._repr_short_() for S in self.cartesian_factors()) - def _convert_factors_(self, factors): r""" Helper method. Try to convert some ``factors`` to an @@ -617,7 +609,6 @@ def get_factors(data): return prod(self.cartesian_injection(*fs) for f in factors for fs in get_factors(f)) - def cartesian_injection(self, factor, element): r""" Inject the given element into this Cartesian product at the given factor. @@ -642,7 +633,6 @@ def cartesian_injection(self, factor, element): return self(tuple((f.one() if f != factor else element) for f in self.cartesian_factors())) - def _coerce_map_from_(self, S): r""" Return whether ``S`` coerces into this growth group. @@ -677,7 +667,6 @@ def _coerce_map_from_(self, S): for f in factors): return True - def _pushout_(self, other): r""" Construct the pushout of this and the other growth group. This is called by @@ -786,8 +775,7 @@ def pushout_univariate_factors(self, other, var, Sfactors, Ofactors): def subfactors(F): for f in F: if isinstance(f, GenericProduct): - for g in subfactors(f.cartesian_factors()): - yield g + yield from subfactors(f.cartesian_factors()) else: yield f @@ -864,7 +852,6 @@ def next_custom(self): from sage.categories.cartesian_product import cartesian_product return pushout(cartesian_product(newS), cartesian_product(newO)) - def gens_monomial(self): r""" Return a tuple containing monomial generators of this growth group. @@ -900,7 +887,6 @@ def gens_monomial(self): for factor in self.cartesian_factors()), tuple()) - def variable_names(self): r""" Return the names of the variables. @@ -921,13 +907,11 @@ def variable_names(self): from itertools import groupby return tuple(v for v, _ in groupby(vars)) - class Element(CartesianProductPoset.Element): from .growth_group import _is_lt_one_ is_lt_one = _is_lt_one_ - def _repr_(self, latex=False): r""" A representation string for this Cartesian product element. @@ -961,7 +945,6 @@ def _repr_(self, latex=False): return '1' return s - def _latex_(self): r""" A representation string for this Cartesian product element. @@ -982,7 +965,6 @@ def _latex_(self): """ return self._repr_(latex=True) - def __pow__(self, exponent): r""" Calculate the power of this growth element to the given @@ -1013,7 +995,6 @@ def __pow__(self, exponent): return self.parent()._create_element_in_extension_( tuple(x ** exponent for x in self.cartesian_factors())) - def factors(self): r""" Return the atomic factors of this growth element. An atomic factor @@ -1062,12 +1043,10 @@ def factors(self): if not f.is_one()), tuple()) - from .growth_group import _log_factor_, _log_ log = _log_ log_factor = _log_factor_ - def _log_factor_(self, base=None, locals=None): r""" Helper method for calculating the logarithm of the factorization @@ -1120,11 +1099,9 @@ def try_create_growth(g): ArithmeticError('Cannot build log(%s) in %s.' % (self, self.parent())), e) - from .growth_group import _rpow_ rpow = _rpow_ - def _rpow_element_(self, base): r""" Return an element which is the power of ``base`` to this @@ -1166,7 +1143,6 @@ def _rpow_element_(self, base): raise ValueError # calling method has to deal with it... return factor._rpow_element_(base) - def exp(self): r""" The exponential of this element. @@ -1211,7 +1187,6 @@ def exp(self): """ return self.rpow('e') - def __invert__(self): r""" Return the multiplicative inverse of this Cartesian product. @@ -1235,7 +1210,6 @@ def __invert__(self): return self.parent()._create_element_in_extension_( tuple(~x for x in self.cartesian_factors())) - def _substitute_(self, rules): r""" Substitute the given ``rules`` in this @@ -1378,7 +1352,6 @@ def _singularity_analysis_(self, var, zeta, precision): 'singularity analysis of {} not yet implemented ' 'since it has more than two factors'.format(self)) - def variable_names(self): r""" Return the names of the variables of this growth element. @@ -1408,7 +1381,6 @@ def variable_names(self): from itertools import groupby return tuple(v for v, _ in groupby(vars)) - CartesianProduct = CartesianProductGrowthGroups diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index f8a009b6282..fdfb8365f1a 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -4640,7 +4640,6 @@ def __init__(self, parent, growth, valid_from, **kwds): raise ValueError('B-Term has not defined all variables which occur in the term in valid_from.') self.valid_from = valid_from - def construction(self): r""" Return a construction of this term. @@ -4968,13 +4967,13 @@ def _default_kwds_construction_(self): sage: T = TermMonoid('B', G, ZZ) sage: T._default_kwds_construction_() {'coefficient': 1, 'valid_from': {'x': 0}} - sage: T.from_construction((None, {'growth': G.gen()})) # indirect doctest + sage: T.from_construction((None, {'growth': G.gen()})) # indirect doctest B(x, x >= 0) - sage: T.from_construction( - ....: (None, {'growth': G.gen(), 'coefficient': 2})) # indirect doctest + sage: T.from_construction( # indirect doctest + ....: (None, {'growth': G.gen(), 'coefficient': 2})) B(2*x, x >= 0) - sage: T.from_construction( - ....: (None, {'growth': G.gen(), 'valid_from': {'x': 5}})) # indirect doctest + sage: T.from_construction( # indirect doctest + ....: (None, {'growth': G.gen(), 'valid_from': {'x': 5}})) B(x, x >= 5) """ defaults = {} diff --git a/src/sage/rings/bernmm.pyx b/src/sage/rings/bernmm.pyx index 00a3da0d1ff..fb633e2d6f1 100644 --- a/src/sage/rings/bernmm.pyx +++ b/src/sage/rings/bernmm.pyx @@ -13,7 +13,7 @@ Cython wrapper for bernmm library AUTHOR: - - David Harvey (2008-06): initial version +- David Harvey (2008-06): initial version """ #***************************************************************************** @@ -42,18 +42,18 @@ from sage.rings.rational cimport Rational def bernmm_bern_rat(long k, int num_threads = 1): r""" - Computes k-th Bernoulli number using a multimodular algorithm. + Compute `k`-th Bernoulli number using a multimodular algorithm. (Wrapper for bernmm library.) INPUT: - - k -- non-negative integer - - num_threads -- integer >= 1, number of threads to use + - ``k`` -- non-negative integer + - ``num_threads`` -- integer `\geq 1`, number of threads to use COMPLEXITY: - Pretty much quadratic in `k`. See the paper "A multimodular algorithm - for computing Bernoulli numbers", David Harvey, 2008, for more details. + Pretty much quadratic in `k`. See the paper "A multimodular algorithm + for computing Bernoulli numbers", David Harvey, 2008, for more details. EXAMPLES:: @@ -98,18 +98,18 @@ def bernmm_bern_rat(long k, int num_threads = 1): def bernmm_bern_modp(long p, long k): r""" - Computes `B_k \mod p`, where `B_k` is the k-th Bernoulli number. + Compute `B_k \mod p`, where `B_k` is the `k`-th Bernoulli number. - If `B_k` is not `p`-integral, returns -1. + If `B_k` is not `p`-integral, return `-1`. INPUT: - p -- a prime - k -- non-negative integer + - ``p`` -- a prime + - ``k`` -- non-negative integer COMPLEXITY: - Pretty much linear in `p`. + Pretty much linear in `p`. EXAMPLES:: diff --git a/src/sage/rings/bernoulli_mod_p.pyx b/src/sage/rings/bernoulli_mod_p.pyx index b46c6b41da1..e9bf4fbf358 100644 --- a/src/sage/rings/bernoulli_mod_p.pyx +++ b/src/sage/rings/bernoulli_mod_p.pyx @@ -15,19 +15,18 @@ AUTHOR: - David Harvey (2007-08-31): algorithm for a single Bernoulli number mod p - David Harvey (2008-06): added interface to bernmm, removed old code """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein <wstein@gmail.com> # 2006 David Harvey <dmharvey@math.harvard.edu> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** cimport sage.rings.fast_arith import sage.rings.fast_arith cdef sage.rings.fast_arith.arith_int arith_int -arith_int = sage.rings.fast_arith.arith_int() +arith_int = sage.rings.fast_arith.arith_int() ctypedef long long llong @@ -35,7 +34,6 @@ import sage.arith.all from sage.libs.ntl import all as ntl from sage.libs.ntl.ntl_ZZ_pX cimport ntl_ZZ_pX -from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.bernmm import bernmm_bern_modp @@ -53,11 +51,9 @@ def verify_bernoulli_mod_p(data): INPUT: - data -- list, same format as output of bernoulli_mod_p function - - OUTPUT: + - ``data`` -- list, same format as output of :func:`bernoulli_mod_p` function - bool -- True if checksum passed + OUTPUT: bool -- True if checksum passed EXAMPLES:: @@ -102,7 +98,7 @@ def bernoulli_mod_p(int p): INPUT: - p -- integer, a prime + - ``p`` -- integer, a prime OUTPUT: @@ -134,10 +130,8 @@ def bernoulli_mod_p(int p): AUTHOR: - -- David Harvey (2006-08-06) - + - David Harvey (2006-08-06) """ - if p <= 2: raise ValueError("p (=%s) must be a prime >= 3" % p) @@ -233,12 +227,12 @@ def bernoulli_mod_p_single(long p, long k): r""" Return the Bernoulli number `B_k` mod `p`. - If `B_k` is not `p`-integral, an ArithmeticError is raised. + If `B_k` is not `p`-integral, an :class:`ArithmeticError` is raised. INPUT: - - p -- integer, a prime - - k -- non-negative integer + - ``p`` -- integer, a prime + - ``k`` -- non-negative integer OUTPUT: @@ -274,7 +268,7 @@ def bernoulli_mod_p_single(long p, long k): ... ValueError: k must be non-negative - Check results against bernoulli_mod_p:: + Check results against :class:`bernoulli_mod_p`:: sage: bernoulli_mod_p(37) [1, 31, 16, 15, 16, 4, 17, 32, 22, 31, 15, 15, 17, 12, 29, 2, 0, 2] @@ -303,9 +297,8 @@ def bernoulli_mod_p_single(long p, long k): AUTHOR: - -- David Harvey (2007-08-31) - -- David Harvey (2008-06): rewrote to use bernmm library - + - David Harvey (2007-08-31) + - David Harvey (2008-06): rewrote to use bernmm library """ if p <= 2: raise ValueError("p (=%s) must be a prime >= 3" % p) @@ -313,8 +306,6 @@ def bernoulli_mod_p_single(long p, long k): if not sage.arith.all.is_prime(p): raise ValueError("p (=%s) must be a prime" % p) - R = Integers(p) - cdef long x = bernmm_bern_modp(p, k) if x == -1: raise ArithmeticError("B_k is not integral at p") diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index 64ce5562f2c..e9b22e77b37 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -9,15 +9,25 @@ - `polynomials <../../../polynomial_rings/index.html>`_ """ -import sage.arith.all as arith -from . import laurent_series_ring_element -from sage.rings.puiseux_series_ring_element import PuiseuxSeries -import sage.rings.padics.factory as padics_factory -import sage.rings.padics.padic_generic_element as padic_generic_element +from sage.arith.misc import factor +from sage.misc.lazy_import import lazy_import +lazy_import('sage.rings.padics.factory', ['Qp', 'Zp']) +lazy_import('sage.rings.padics.padic_generic_element', 'pAdicGenericElement') +from sage.rings.polynomial.polynomial_element import Polynomial + +try: + from .laurent_series_ring_element import LaurentSeries +except ImportError: + LaurentSeries = () + +try: + from .puiseux_series_ring_element import PuiseuxSeries +except ImportError: + PuiseuxSeries = () + from . import power_series_ring_element from . import integer from . import rational -from sage.rings.polynomial.polynomial_element import Polynomial from . import multi_power_series_ring_element @@ -47,43 +57,45 @@ def O(*x, **kwds): This is also useful to create `p`-adic numbers:: - sage: O(7^6) + sage: O(7^6) # needs sage.rings.padics O(7^6) - sage: 1/3 + O(7^6) + sage: 1/3 + O(7^6) # needs sage.rings.padics 5 + 4*7 + 4*7^2 + 4*7^3 + 4*7^4 + 4*7^5 + O(7^6) It behaves well with respect to adding negative powers of `p`:: - sage: a = O(11^-32); a + sage: a = O(11^-32); a # needs sage.rings.padics O(11^-32) - sage: a.parent() + sage: a.parent() # needs sage.rings.padics 11-adic Field with capped relative precision 20 There are problems if you add a rational with very negative valuation to an `O`-Term:: - sage: 11^-12 + O(11^15) + sage: 11^-12 + O(11^15) # needs sage.rings.padics 11^-12 + O(11^8) The reason that this fails is that the constructor doesn't know the right precision cap to use. If you cast explicitly or use other means of element creation, you can get around this issue:: + sage: # needs sage.rings.padics sage: K = Qp(11, 30) sage: K(11^-12) + O(11^15) 11^-12 + O(11^15) sage: 11^-12 + K(O(11^15)) 11^-12 + O(11^15) - sage: K(11^-12, absprec = 15) + sage: K(11^-12, absprec=15) 11^-12 + O(11^15) sage: K(11^-12, 15) 11^-12 + O(11^15) We can also work with `asymptotic expansions`_:: - sage: A.<n> = AsymptoticRing(growth_group='QQ^n * n^QQ * log(n)^QQ', coefficient_ring=QQ); A + sage: A.<n> = AsymptoticRing(growth_group='QQ^n * n^QQ * log(n)^QQ', # needs sage.symbolic + ....: coefficient_ring=QQ); A Asymptotic Ring <QQ^n * n^QQ * log(n)^QQ * Signs^n> over Rational Field - sage: O(n) + sage: O(n) # needs sage.symbolic O(n) Application with Puiseux series:: @@ -97,13 +109,13 @@ def O(*x, **kwds): TESTS:: - sage: var('x, y') + sage: var('x, y') # needs sage.symbolic (x, y) - sage: O(x) + sage: O(x) # needs sage.symbolic Traceback (most recent call last): ... ArithmeticError: O(x) not defined - sage: O(y) + sage: O(y) # needs sage.symbolic Traceback (most recent call last): ... ArithmeticError: O(y) not defined @@ -137,9 +149,8 @@ def O(*x, **kwds): "for the maximal ideal (x)") return x.parent().completion(x.parent().gen())(0, x.degree(), **kwds) - elif isinstance(x, laurent_series_ring_element.LaurentSeries): - return laurent_series_ring_element.LaurentSeries(x.parent(), 0).\ - add_bigoh(x.valuation(), **kwds) + elif isinstance(x, LaurentSeries): + return LaurentSeries(x.parent(), 0).add_bigoh(x.valuation(), **kwds) elif isinstance(x, PuiseuxSeries): return x.add_bigoh(x.valuation(), **kwds) @@ -148,18 +159,18 @@ def O(*x, **kwds): # p-adic number if x <= 0: raise ArithmeticError("x must be a prime power >= 2") - F = arith.factor(x) + F = factor(x) if len(F) != 1: raise ArithmeticError("x must be prime power") p, r = F[0] if r >= 0: - return padics_factory.Zp(p, prec=max(r, 20), - type='capped-rel')(0, absprec=r, **kwds) + return Zp(p, prec=max(r, 20), + type='capped-rel')(0, absprec=r, **kwds) else: - return padics_factory.Qp(p, prec=max(r, 20), - type='capped-rel')(0, absprec=r, **kwds) + return Qp(p, prec=max(r, 20), + type='capped-rel')(0, absprec=r, **kwds) - elif isinstance(x, padic_generic_element.pAdicGenericElement): + elif isinstance(x, pAdicGenericElement): return x.parent()(0, absprec=x.valuation(), **kwds) elif hasattr(x, 'O'): return x.O(**kwds) diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index 8681fc3f263..7229dab646a 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic r""" C-Finite Sequences @@ -1038,7 +1038,7 @@ def an_element(self): def __contains__(self, x): """ - Return True if x is an element of ``CFiniteSequences`` or + Return ``True`` if x is an element of ``CFiniteSequences`` or canonically coerces to this ring. EXAMPLES:: @@ -1233,7 +1233,7 @@ def guess(self, sequence, algorithm='sage'): return CFiniteSequence(num / den) else: from sage.matrix.constructor import matrix - from sage.functions.other import ceil + from sage.arith.misc import integer_ceil as ceil from numpy import trim_zeros seq = sequence[:] while seq and sequence[-1] == 0: @@ -1265,10 +1265,11 @@ def guess(self, sequence, algorithm='sage'): r""" .. TODO:: - sage: CFiniteSequence(x+x^2+x^3+x^4+x^5+O(x^6)) # not implemented - sage: latex(r) # not implemented + sage: # not implemented + sage: CFiniteSequence(x+x^2+x^3+x^4+x^5+O(x^6)) + sage: latex(r) \big\{a_{n\ge0}\big|a_{n+2}=\sum_{i=0}^{1}c_ia_{n+i}, c=\{1,1\}, a_{n<2}=\{0,0,0,1\}\big\} - sage: r.egf() # not implemented + sage: r.egf() exp(2*x) - sage: r = CFiniteSequence(1/(1-y-x*y), x) # not implemented + sage: r = CFiniteSequence(1/(1-y-x*y), x) """ diff --git a/src/sage/rings/commutative_algebra.py b/src/sage/rings/commutative_algebra.py index 26ab115e52b..92d734cce77 100644 --- a/src/sage/rings/commutative_algebra.py +++ b/src/sage/rings/commutative_algebra.py @@ -28,6 +28,11 @@ def is_CommutativeAlgebra(x): sage: from sage.rings.commutative_algebra import is_CommutativeAlgebra sage: from sage.rings.ring import CommutativeAlgebra sage: is_CommutativeAlgebra(CommutativeAlgebra(ZZ)) + doctest:warning... + DeprecationWarning: the function is_CommutativeAlgebra is deprecated; use '... in Algebras(base_ring).Commutative()' instead + See https://github.com/sagemath/sage/issues/35253 for details. True """ + from sage.misc.superseded import deprecation + deprecation(35253, "the function is_CommutativeAlgebra is deprecated; use '... in Algebras(base_ring).Commutative()' instead") return isinstance(x, CommutativeAlgebra) diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index 797f5122d40..a22ce3c5e53 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -101,7 +101,9 @@ Coercion Automatic coercions work as expected:: - sage: bpol = 1/3*CBF(i) + AA(sqrt(2)) + (polygen(RealBallField(20), 'x') + QQbar(i)) + sage: # needs sage.symbolic + sage: bpol = 1/3*CBF(i) + AA(sqrt(2)) + sage: bpol += polygen(RealBallField(20), 'x') + QQbar(i) sage: bpol x + [1.41421 +/- ...e-6] + [1.33333 +/- ...e-6]*I sage: bpol.parent() @@ -116,12 +118,12 @@ TESTS:: :: - sage: SR.coerce(CBF(0.42 + 3.33*I)) + sage: SR.coerce(CBF(0.42 + 3.33*I)) # needs sage.symbolic [0.4200000000000000 +/- ...e-17] + [3.330000000000000 +/- ...e-17]*I Check that :trac:`19839` is fixed:: - sage: log(SR(CBF(0.42))).pyobject().parent() + sage: log(SR(CBF(0.42))).pyobject().parent() # needs sage.symbolic Complex ball field with 53 bits of precision :trac:`24621`:: @@ -145,16 +147,15 @@ Classes and Methods import operator import sys import warnings -from cysignals.signals cimport sig_on, sig_str, sig_off, sig_error +from cysignals.signals cimport sig_on, sig_str, sig_off, sig_error, sig_block, sig_unblock import sage.categories.fields cimport sage.rings.abc cimport sage.rings.rational -from cpython.float cimport PyFloat_AS_DOUBLE -from cpython.int cimport PyInt_AS_LONG -from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE +from cpython.long cimport PyLong_AsLong +from cpython.object cimport Py_EQ, Py_NE from cpython.complex cimport PyComplex_FromDoubles from sage.ext.stdsage cimport PY_NEW @@ -168,13 +169,13 @@ from sage.libs.arb.acb_hypgeom cimport * from sage.libs.arb.acb_elliptic cimport * from sage.libs.arb.acb_modular cimport * from sage.libs.arb.acb_poly cimport * -from sage.libs.arb.arf cimport arf_init, arf_get_d, arf_get_mpfr, arf_set_mpfr, arf_clear, arf_set_mag, arf_set, arf_is_nan -from sage.libs.arb.mag cimport (mag_init, mag_clear, mag_add, mag_set_d, - MAG_BITS, mag_is_inf, mag_is_finite, mag_zero, mag_set_ui_2exp_si, +from sage.libs.arb.arf cimport arf_init, arf_get_d, arf_get_mpfr, arf_clear, arf_set, arf_is_nan +from sage.libs.arb.mag cimport (mag_init, mag_clear, mag_set_d, + MAG_BITS, mag_zero, mag_set_ui_2exp_si, mag_mul_2exp_si) -from sage.libs.flint.fmpz cimport fmpz_t, fmpz_init, fmpz_get_mpz, fmpz_set_mpz, fmpz_clear, fmpz_abs +from sage.libs.flint.fmpz cimport fmpz_t, fmpz_init, fmpz_get_mpz, fmpz_set_mpz, fmpz_clear from sage.libs.flint.fmpq cimport fmpq_t, fmpq_init, fmpq_set_mpq, fmpq_clear -from sage.libs.gmp.mpz cimport mpz_fits_ulong_p, mpz_fits_slong_p, mpz_get_ui, mpz_get_si, mpz_sgn +from sage.libs.gmp.mpz cimport mpz_fits_slong_p, mpz_get_si from sage.libs.gsl.complex cimport gsl_complex_rect from sage.rings.real_double cimport RealDoubleElement from sage.rings.complex_double cimport ComplexDoubleElement @@ -185,17 +186,15 @@ from sage.rings.real_arb import RealBallField from sage.rings.real_mpfi cimport RealIntervalField_class from sage.rings.real_mpfr cimport RealField_class, RealField, RealNumber from sage.rings.ring import Field -from sage.structure.element cimport Element, ModuleElement -from sage.structure.parent cimport Parent +from sage.structure.element cimport Element from sage.structure.unique_representation import UniqueRepresentation from sage.arith.long cimport is_small_python_int from sage.misc.lazy_string import lazy_string -from sage.misc.superseded import deprecated_function_alias -from sage.rings.complex_mpfr import ComplexField from sage.rings.complex_interval_field import ComplexIntervalField, ComplexIntervalField_class from sage.rings.integer_ring import ZZ + cdef void ComplexIntervalFieldElement_to_acb( acb_t target, ComplexIntervalFieldElement source): @@ -284,27 +283,27 @@ cdef int acb_calc_func_callback(acb_ptr out, const acb_t inp, void * param, """ cdef IntegrationContext ctx cdef ComplexBall x - sig_off() + sig_block() try: ctx = <IntegrationContext>param if ctx.exn_type is not None or order >= 2: acb_indeterminate(out) return 0 - x = ComplexBall.__new__(ComplexBall) - assert prec == ctx.parent._prec - x._parent = ctx.parent - acb_set(x.value, inp) try: + x = ComplexBall.__new__(ComplexBall) + assert prec == ctx.parent._prec + x._parent = ctx.parent + acb_set(x.value, inp) y = ctx.f(x, (order == 1)) if not isinstance(y, ComplexBall): y = ctx.parent.coerce(y) acb_set(out, (<ComplexBall> y).value) - except Exception: + except BaseException: ctx.exn_type, ctx.exn_obj, ctx.exn_tb = sys.exc_info() acb_indeterminate(out) return 0 finally: - sig_on() + sig_unblock() class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): @@ -549,6 +548,7 @@ class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): sage: CBF.convert_map_from(QuadraticField(-2)) Conversion via _acb_ method map: ... + sage: x = polygen(ZZ, 'x') sage: CBF.coerce_map_from(NumberField(x^7 + 2, 'a', ....: embedding=QQbar(-2)^(1/7))) Conversion via _acb_ method map: @@ -592,15 +592,15 @@ class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): 1.000000000000000 sage: CBF(1, 1) 1.000000000000000 + 1.000000000000000*I - sage: CBF(pi, sqrt(2)) + sage: CBF(pi, sqrt(2)) # needs sage.symbolic [3.141592653589793 +/- ...e-16] + [1.414213562373095 +/- ...e-16]*I sage: CBF(I) 1.000000000000000*I - sage: CBF(pi+I/3) + sage: CBF(pi + I/3) # needs sage.symbolic [3.141592653589793 +/- ...e-16] + [0.3333333333333333 +/- ...e-17]*I sage: CBF(QQbar(i/7)) # abs tol 1e-16 [0.1428571428571429 +/- 4.29e-17]*I - sage: CBF(AA(sqrt(2))) + sage: CBF(AA(sqrt(2))) # needs sage.symbolic [1.414213562373095 +/- ...e-16] sage: CBF(CIF(0, 1)) 1.000000000000000*I @@ -617,9 +617,9 @@ class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): sage: NF.<a> = QuadraticField(-2) sage: CBF(1/5 + a/2) [0.2000000000000000 +/- ...e-17] + [0.707106781186547 +/- ...e-16]*I - sage: CBF(infinity, NaN) + sage: CBF(infinity, NaN) # needs sage.symbolic [+/- inf] + nan*I - sage: CBF(x) + sage: CBF(x) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert x to a ComplexBall @@ -637,6 +637,7 @@ class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): The following conversions used to yield incorrect enclosures:: + sage: # needs sage.symbolic sage: a = CBF(airy_ai(1)); a [0.1352924163128814 +/- 6.95e-17] sage: a.overlaps(ComplexBallField(100).one().airy_ai()) @@ -875,7 +876,7 @@ class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): cdef RealBall rb cdef ComplexBall cb acb_poly_init(rounded_poly) - cdef long deg = acb_poly_degree(poly.__poly) + cdef long deg = acb_poly_degree(poly._poly) if deg < 0: raise ArithmeticError("taking the roots of the zero polynomial") cdef acb_ptr roots = _acb_vec_init(deg) @@ -884,7 +885,7 @@ class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): while ((isolated < deg or any(acb_rel_accuracy_bits(&roots[i]) < tgtprec for i in range(deg))) and prec < maxprec): - acb_poly_set_round(rounded_poly, poly.__poly, prec) + acb_poly_set_round(rounded_poly, poly._poly, prec) maxiter = min(max(deg, 32), prec) if (prec == initial_prec): isolated = acb_poly_find_roots(roots, rounded_poly, NULL, maxiter, prec) @@ -1078,7 +1079,7 @@ class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): ....: return CBF(NaN) ....: else: ....: return z.sqrt() - sage: CBF.integral(my_sqrt, -1 + CBF(i), -1 - CBF(i)) + sage: CBF.integral(my_sqrt, -1 + CBF(i), -1 - CBF(i)) # needs sage.symbolic [+/- ...e-14] + [-0.4752076627926 +/- 5...e-14]*I Note, though, that proper handling of the ``analytic`` flag is required @@ -1086,7 +1087,7 @@ class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): sage: correct = CBF.integral(my_sqrt, 1, 2); correct [1.21895141649746 +/- ...e-15] - sage: RBF(integral(sqrt(x), x, 1, 2)) # long time + sage: RBF(integral(sqrt(x), x, 1, 2)) # long time # needs sage.symbolic [1.21895141649746 +/- ...e-15] sage: wrong = CBF.integral(lambda z, _: z.sqrt(), 1, 2) # WRONG! sage: correct - wrong @@ -1175,6 +1176,14 @@ class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): sage: ComplexBallField(100).integral(lambda x, _: sin(x), RBF(0), RBF(1)) [0.4596976941318602825990633926 +/- ...e-29] + + sage: from cysignals.alarm import alarm + sage: alarm(0.1r) + sage: C = ComplexBallField(1000000) + sage: C.integral(lambda x, _: x.cos() * x.sin(), 0, 1) + Traceback (most recent call last): + ... + AlarmInterrupt """ cdef IntegrationContext ctx = IntegrationContext() cdef acb_calc_integrate_opt_t arb_opts @@ -1341,7 +1350,7 @@ cdef class ComplexBall(RingElement): 0 sage: ComplexBall(CBF100, ComplexBall(CBF53, ComplexBall(CBF100, 1/3))) [0.333333333333333333333333333333 +/- ...e-31] - sage: ComplexBall(CBF100, RBF(pi)) + sage: ComplexBall(CBF100, RBF(pi)) # needs sage.symbolic [3.141592653589793 +/- ...e-16] sage: ComplexBall(CBF100, -3r) @@ -1395,7 +1404,6 @@ cdef class ComplexBall(RingElement): """ cdef fmpz_t tmpz cdef fmpq_t tmpq - cdef long myprec cdef bint cplx = False Element.__init__(self, parent) @@ -1506,7 +1514,7 @@ cdef class ComplexBall(RingElement): TESTS:: - sage: [loads(dumps(b)).identical(b) for b in + sage: [loads(dumps(b)).identical(b) for b in # needs sage.symbolic ....: [ComplexBallField(60)(1/3 + i*pi), CBF(NaN)]] [True, True] """ @@ -2098,9 +2106,9 @@ cdef class ComplexBall(RingElement): sage: CBF(17, 1023).nbits() 10 - sage: CBF(1/3, NaN).nbits() + sage: CBF(1/3, NaN).nbits() # needs sage.symbolic 53 - sage: CBF(NaN).nbits() + sage: CBF(NaN).nbits() # needs sage.symbolic 0 """ return acb_bits(self.value) @@ -2115,13 +2123,13 @@ cdef class ComplexBall(RingElement): their parent's nominal precision (see :mod:`~sage.rings.real_arb` for more information):: - sage: b = CBF(exp(I*pi/3).n(100)) - sage: b.mid() + sage: b = CBF(exp(I*pi/3).n(100)) # needs sage.symbolic + sage: b.mid() # needs sage.symbolic 0.50000000000000000000000000000 + 0.86602540378443864676372317075*I The ``round()`` method rounds such a ball to its parent's precision:: - sage: b.round().mid() + sage: b.round().mid() # needs sage.symbolic 0.500000000000000 + 0.866025403784439*I .. SEEALSO:: :meth:`trim` @@ -2144,7 +2152,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(exp(I*pi/3)).accuracy() + sage: CBF(exp(I*pi/3)).accuracy() # needs sage.symbolic 51 sage: CBF(I/2).accuracy() == CBF.base().maximal_accuracy() True @@ -2212,7 +2220,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(NaN).is_NaN() + sage: CBF(NaN).is_NaN() # needs sage.symbolic True sage: CBF(-5).gamma().is_NaN() True @@ -2255,7 +2263,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(pi, 1/3).is_nonzero() + sage: CBF(pi, 1/3).is_nonzero() # needs sage.symbolic True sage: CBF(RIF(-0.5, 0.5), 1/3).is_nonzero() True @@ -2419,17 +2427,15 @@ cdef class ComplexBall(RingElement): False """ cdef ComplexBall lt, rt - cdef acb_t difference lt = left rt = right if op == Py_EQ: return acb_eq(lt.value, rt.value) - elif op == Py_NE: + if op == Py_NE: return acb_ne(lt.value, rt.value) - elif op == Py_GT or op == Py_GE or op == Py_LT or op == Py_LE: - raise TypeError("No order is defined for ComplexBalls.") + raise TypeError("No order is defined for ComplexBalls.") def identical(self, ComplexBall other): """ @@ -2441,7 +2447,7 @@ cdef class ComplexBall(RingElement): OUTPUT: - Return True iff ``self`` and ``other`` are equal as sets, i.e. if their + Return ``True`` iff ``self`` and ``other`` are equal as sets, i.e. if their real and imaginary parts each have the same midpoint and radius. Note that this is not the same thing as testing whether both ``self`` @@ -2462,7 +2468,7 @@ cdef class ComplexBall(RingElement): def overlaps(self, ComplexBall other): """ - Return True iff ``self`` and ``other`` have some point in common. + Return ``True`` iff ``self`` and ``other`` have some point in common. INPUT: @@ -2501,7 +2507,7 @@ cdef class ComplexBall(RingElement): sage: CBF(1).contains_exact(CBF(1)) True - sage: CBF(sqrt(2)).contains_exact(sqrt(2)) + sage: CBF(sqrt(2)).contains_exact(sqrt(2)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unsupported type: <class 'sage.symbolic.expression.Expression'> @@ -2530,7 +2536,7 @@ cdef class ComplexBall(RingElement): def __contains__(self, other): """ - Return True if ``other`` can be verified to be contained in ``self``. + Return ``True`` if ``other`` can be verified to be contained in ``self``. Depending on the type of ``other``, the test may use interval arithmetic with a precision determined by the parent of ``self`` and @@ -2728,7 +2734,7 @@ cdef class ComplexBall(RingElement): cdef ComplexBall self = val cdef ComplexBall res = self._new() if is_small_python_int(shift): - acb_mul_2exp_si(res.value, self.value, PyInt_AS_LONG(shift)) + acb_mul_2exp_si(res.value, self.value, PyLong_AsLong(shift)) elif isinstance(shift, Integer): sig_on() fmpz_init(tmpz) @@ -2801,7 +2807,7 @@ cdef class ComplexBall(RingElement): sage: CBF(-1)**(1/2) 1.000000000000000*I - sage: CBF(e)**CBF(i*pi) + sage: CBF(e)**CBF(i*pi) # needs sage.symbolic [-1.00000000000000 +/- ...e-16] + [+/- ...e-15]*I sage: CBF(0, 1)**AA(2)**(1/2) [-0.60569986707881 +/- ...e-15] + [0.79569320156748 +/- ...e-15]*I @@ -2820,13 +2826,13 @@ cdef class ComplexBall(RingElement): TESTS:: - sage: (CBF(e)**CBF(i))**RBF(pi) + sage: (CBF(e)**CBF(i))**RBF(pi) # needs sage.symbolic [-1.0000000000000 +/- ...e-15] + [+/- ...e-15]*I sage: CBF(2*i)**10r -1024.000000000000 sage: CBF(1,1) ^ -1r 0.5000000000000000 - 0.5000000000000000*I - sage: CBF(2)**SR.var('x') + sage: CBF(2)**SR.var('x') # needs sage.symbolic 2.000000000000000^x """ if (isinstance(base, ComplexBall) @@ -2860,7 +2866,7 @@ cdef class ComplexBall(RingElement): TESTS:: - sage: CBF(2).pow(SR.var('x')) + sage: CBF(2).pow(SR.var('x')) # needs sage.symbolic Traceback (most recent call last): ... TypeError: no canonical coercion from Symbolic Ring to Complex ball @@ -2870,7 +2876,7 @@ cdef class ComplexBall(RingElement): cdef ComplexBall res = self._new() if is_small_python_int(expo): if _do_sig(prec(self)): sig_on() - acb_pow_si(res.value, self.value, PyInt_AS_LONG(expo), prec(self)) + acb_pow_si(res.value, self.value, PyLong_AsLong(expo), prec(self)) if _do_sig(prec(self)): sig_off() elif isinstance(expo, Integer): if _do_sig(prec(self)): sig_on() @@ -3115,7 +3121,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(i*pi).exp() + sage: CBF(i*pi).exp() # needs sage.symbolic [-1.00000000000000 +/- ...e-16] + [+/- ...e-16]*I """ cdef ComplexBall res = self._new() @@ -3132,7 +3138,7 @@ cdef class ComplexBall(RingElement): sage: CBF(1/2).exppii() 1.000000000000000*I - sage: CBF(0, -1/pi).exppii() + sage: CBF(0, -1/pi).exppii() # needs sage.symbolic [2.71828182845904 +/- ...e-15] """ cdef ComplexBall res = self._new() @@ -3147,7 +3153,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(i*pi).sin() + sage: CBF(i*pi).sin() # needs sage.symbolic [11.54873935725775 +/- ...e-15]*I """ cdef ComplexBall res = self._new() @@ -3162,7 +3168,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(i*pi).cos() + sage: CBF(i*pi).cos() # needs sage.symbolic [11.59195327552152 +/- ...e-15] """ cdef ComplexBall res = self._new() @@ -3177,9 +3183,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(pi/2, 1/10).tan() + sage: CBF(pi/2, 1/10).tan() # needs sage.symbolic [+/- ...e-14] + [10.03331113225399 +/- ...e-15]*I - sage: CBF(pi/2).tan() + sage: CBF(pi/2).tan() # needs sage.symbolic nan """ cdef ComplexBall res = self._new() @@ -3194,9 +3200,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(pi, 1/10).cot() + sage: CBF(pi, 1/10).cot() # needs sage.symbolic [+/- ...e-14] + [-10.03331113225399 +/- ...e-15]*I - sage: CBF(pi).cot() + sage: CBF(pi).cot() # needs sage.symbolic nan """ cdef ComplexBall res = self._new() @@ -3273,7 +3279,7 @@ cdef class ComplexBall(RingElement): sage: CBF(1, 1).tanh() [1.083923327338694 +/- ...e-16] + [0.2717525853195117 +/- ...e-17]*I - sage: CBF(0, pi/2).tanh() + sage: CBF(0, pi/2).tanh() # needs sage.symbolic nan*I """ cdef ComplexBall res = self._new() @@ -3290,7 +3296,7 @@ cdef class ComplexBall(RingElement): sage: CBF(1, 1).coth() [0.868014142895925 +/- ...e-16] + [-0.2176215618544027 +/- ...e-17]*I - sage: CBF(0, pi).coth() + sage: CBF(0, pi).coth() # needs sage.symbolic nan*I """ cdef ComplexBall res = self._new() @@ -3305,7 +3311,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(pi/2, 1/10).sech() + sage: CBF(pi/2, 1/10).sech() # needs sage.symbolic [0.397174529918189 +/- ...e-16] + [-0.0365488656274242 +/- ...e-17]*I """ cdef ComplexBall res = self._new() @@ -3322,7 +3328,7 @@ cdef class ComplexBall(RingElement): sage: CBF(1, 1).csch() [0.303931001628426 +/- ...e-16] + [-0.621518017170428 +/- ...e-16]*I - sage: CBF(i*pi).csch() + sage: CBF(i*pi).csch() # needs sage.symbolic nan*I """ cdef ComplexBall res = self._new() @@ -3833,15 +3839,15 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(1, pi/2).hypergeometric([], []) + sage: CBF(1, pi/2).hypergeometric([], []) # needs sage.symbolic [+/- ...e-16] + [2.71828182845904 +/- ...e-15]*I - sage: CBF(1, pi).hypergeometric([1/4], [1/4]) + sage: CBF(1, pi).hypergeometric([1/4], [1/4]) # needs sage.symbolic [-2.7182818284590 +/- ...e-14] + [+/- ...e-14]*I - sage: CBF(1000, 1000).hypergeometric([10], [AA(sqrt(2))]) + sage: CBF(1000, 1000).hypergeometric([10], [AA(sqrt(2))]) # needs sage.symbolic [9.79300951360e+454 +/- ...e+442] + [5.522579106816e+455 +/- ...e+442]*I - sage: CBF(1000, 1000).hypergeometric([100], [AA(sqrt(2))]) + sage: CBF(1000, 1000).hypergeometric([100], [AA(sqrt(2))]) # needs sage.symbolic [1.27967355557e+590 +/- ...e+578] + [-9.32333491987e+590 +/- ...e+578]*I sage: CBF(0, 1).hypergeometric([], [1/2, 1/3, 1/4]) @@ -3875,7 +3881,7 @@ cdef class ComplexBall(RingElement): TESTS:: - sage: CBF(0, 1).hypergeometric([QQbar(sqrt(2)), RLF(pi)], [1r, 1/2]) + sage: CBF(0, 1).hypergeometric([QQbar(sqrt(2)), RLF(pi)], [1r, 1/2]) # needs sage.symbolic [-8.7029449215408 +/- ...e-14] + [-0.8499070546106 +/- ...e-14]*I """ @@ -3924,7 +3930,7 @@ cdef class ComplexBall(RingElement): cdef acb_ptr vec_a = _acb_vec_init(p - s) cdef acb_ptr vec_b = _acb_vec_init(q + 1 - s) cdef long j = 0 - for i in xrange(p): + for i in range(p): if i != i1: tmp = self._parent.coerce(a[i]) acb_set(&(vec_a[j]), tmp.value) @@ -3949,7 +3955,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(1000, 1000).hypergeometric_U(RLF(pi), -100) + sage: CBF(1000, 1000).hypergeometric_U(RLF(pi), -100) # needs sage.symbolic [-7.261605907166e-11 +/- ...e-24] + [-7.928136216391e-11 +/- ...e-24]*I sage: CBF(1000, 1000).hypergeometric_U(0, -100) 1.000000000000000 @@ -4002,7 +4008,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(10*pi).airy() + sage: CBF(10*pi).airy() # needs sage.symbolic ([1.2408955946101e-52 +/- ...e-66], [-6.965048886977e-52 +/- ...e-65], [2.2882956833435e+50 +/- ...e+36], @@ -4214,7 +4220,7 @@ cdef class ComplexBall(RingElement): TESTS: - sage: CBF(Ei(I)) # abs tol 1e-16 + sage: CBF(Ei(I)) # abs tol 1e-16 # needs sage.symbolic [0.337403922900968 +/- 3.76e-16] + [2.51687939716208 +/- 2.01e-15]*I """ cdef ComplexBall result = self._new() @@ -4223,8 +4229,6 @@ cdef class ComplexBall(RingElement): if _do_sig(prec(self)): sig_off() return result - ei = deprecated_function_alias(32869, Ei) - def Si(self): """ Return the sine integral with argument ``self``. @@ -4238,7 +4242,7 @@ cdef class ComplexBall(RingElement): TESTS: - sage: CBF(Si(I)) + sage: CBF(Si(I)) # needs sage.symbolic [1.05725087537573 +/- 2.77e-15]*I """ cdef ComplexBall result = self._new() @@ -4249,8 +4253,6 @@ cdef class ComplexBall(RingElement): sin_integral = Si # as for the symbolic function - si = deprecated_function_alias(32869, Si) - def Ci(self): """ Return the cosine integral with argument ``self``. @@ -4264,7 +4266,7 @@ cdef class ComplexBall(RingElement): TESTS: - sage: CBF(Ci(I)) # abs tol 1e-17 + sage: CBF(Ci(I)) # abs tol 1e-17 # needs sage.symbolic [0.837866940980208 +/- 4.72e-16] + [1.570796326794897 +/- 5.54e-16]*I """ cdef ComplexBall result = self._new() @@ -4275,8 +4277,6 @@ cdef class ComplexBall(RingElement): cos_integral = Ci # as for the symbolic function - ci = deprecated_function_alias(32869, Ci) - def Shi(self): """ Return the hyperbolic sine integral with argument ``self``. @@ -4290,7 +4290,7 @@ cdef class ComplexBall(RingElement): TESTS: - sage: CBF(Shi(I)) # abs tol 1e-15 + sage: CBF(Shi(I)) # abs tol 1e-15 # needs sage.symbolic [0.946083070367183 +/- 9.22e-16]*I """ cdef ComplexBall result = self._new() @@ -4301,8 +4301,6 @@ cdef class ComplexBall(RingElement): sinh_integral = Shi - shi = deprecated_function_alias(32869, Shi) - def Chi(self): """ Return the hyperbolic cosine integral with argument ``self``. @@ -4316,7 +4314,7 @@ cdef class ComplexBall(RingElement): TESTS: - sage: CBF(Chi(I)) # abs tol 1e-16 + sage: CBF(Chi(I)) # abs tol 1e-16 # needs sage.symbolic [0.337403922900968 +/- 3.25e-16] + [1.570796326794897 +/- 5.54e-16]*I """ cdef ComplexBall result = self._new() @@ -4327,8 +4325,6 @@ cdef class ComplexBall(RingElement): cosh_integral = Chi - chi = deprecated_function_alias(32869, Chi) - def li(self, bint offset=False): """ Return the logarithmic integral with argument ``self``. @@ -4343,16 +4339,16 @@ cdef class ComplexBall(RingElement): 0 sage: CBF(0).li(offset=True) [-1.045163780117493 +/- ...e-16] - sage: li(0).n() + sage: li(0).n() # needs sage.symbolic 0.000000000000000 - sage: Li(0).n() + sage: Li(0).n() # needs sage.symbolic -1.04516378011749 TESTS:: - sage: CBF(li(0)) + sage: CBF(li(0)) # needs sage.symbolic 0 - sage: CBF(Li(0)) + sage: CBF(Li(0)) # needs sage.symbolic [-1.04516378011749...] """ cdef ComplexBall result = self._new() @@ -4371,9 +4367,9 @@ cdef class ComplexBall(RingElement): sage: CBF(0).Li() [-1.045163780117493 +/- ...e-16] - sage: li(0).n() + sage: li(0).n() # needs sage.symbolic 0.000000000000000 - sage: Li(0).n() + sage: Li(0).n() # needs sage.symbolic -1.04516378011749 """ cdef ComplexBall result = self._new() @@ -4475,6 +4471,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: + sage: # needs sage.symbolic sage: tau = CBF(sqrt(2),pi) sage: tau.modular_lambda() [-0.00022005123884157 +/- ...e-18] + [-0.00079787346459944 +/- ...e-18]*I @@ -4560,19 +4557,19 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: tau = CBF(1,4) - sage: z = CBF(sqrt(2), sqrt(3)) - sage: z.elliptic_p(tau) + sage: z = CBF(sqrt(2), sqrt(3)) # needs sage.symbolic + sage: z.elliptic_p(tau) # needs sage.symbolic [-3.28920996772709 +/- ...e-15] + [-0.0003673767302933 +/- ...e-17]*I - sage: (z + tau).elliptic_p(tau) + sage: (z + tau).elliptic_p(tau) # needs sage.symbolic [-3.28920996772709 +/- ...e-15] + [-0.000367376730293 +/- ...e-16]*I - sage: (z + 1).elliptic_p(tau) + sage: (z + 1).elliptic_p(tau) # needs sage.symbolic [-3.28920996772709 +/- ...e-15] + [-0.0003673767302933 +/- ...e-17]*I - sage: z.elliptic_p(tau, 3) + sage: z.elliptic_p(tau, 3) # needs sage.symbolic [[-3.28920996772709 +/- ...e-15] + [-0.0003673767302933 +/- ...e-17]*I, [0.002473055794309 +/- ...e-16] + [0.003859554040267 +/- ...e-16]*I, [-0.01299087561709 +/- ...e-15] + [0.00725027521915 +/- ...e-15]*I] - sage: (z + 3 + 4*tau).elliptic_p(tau, 3) + sage: (z + 3 + 4*tau).elliptic_p(tau, 3) # needs sage.symbolic [[-3.28920996772709 +/- ...e-15] + [-0.00036737673029 +/- ...e-15]*I, [0.0024730557943 +/- ...e-14] + [0.0038595540403 +/- ...e-14]*I, [-0.01299087562 +/- ...e-12] + [0.00725027522 +/- ...e-12]*I] @@ -4611,7 +4608,7 @@ cdef class ComplexBall(RingElement): sage: CBF(0,1).elliptic_invariants() ([189.07272012923 +/- ...e-12], [+/- ...e-12]) - sage: CBF(sqrt(2)/2, sqrt(2)/2).elliptic_invariants() + sage: CBF(sqrt(2)/2, sqrt(2)/2).elliptic_invariants() # needs sage.symbolic ([+/- ...e-12] + [-332.5338031465...]*I, [1254.46842157...] + [1254.46842157...]*I) """ diff --git a/src/sage/rings/complex_conversion.pyx b/src/sage/rings/complex_conversion.pyx index a11f86a7735..abf179064c6 100644 --- a/src/sage/rings/complex_conversion.pyx +++ b/src/sage/rings/complex_conversion.pyx @@ -12,7 +12,7 @@ cdef class CCtoCDF(Map): sage: f = CCtoCDF(CC, CDF) # indirect doctest sage: f(CC.0) 1.0*I - sage: f(exp(pi*CC.0/4)) + sage: f(exp(pi*CC.0/4)) # needs sage.symbolic 0.7071067811865476 + 0.7071067811865475*I """ z = <ComplexDoubleElement>ComplexDoubleElement.__new__(ComplexDoubleElement) diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 332977164f4..8b9883d1279 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -24,7 +24,7 @@ EXAMPLES:: Complex Double Field sage: type(CDF.0) <class 'sage.rings.complex_double.ComplexDoubleElement'> - sage: ComplexDoubleElement(sqrt(2),3) + sage: ComplexDoubleElement(sqrt(2), 3) # needs sage.symbolic 1.4142135623730951 + 3.0*I sage: parent(CDF(-2)) Complex Double Field @@ -68,7 +68,6 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -import operator from cpython.object cimport Py_NE from sage.misc.randstate cimport randstate, current_randstate @@ -83,7 +82,7 @@ import sage.rings.abc cimport sage.rings.ring cimport sage.rings.integer -from sage.structure.element cimport RingElement, Element, ModuleElement, FieldElement +from sage.structure.element cimport Element, FieldElement from sage.structure.parent cimport Parent from sage.structure.parent_gens import ParentWithGens from sage.structure.richcmp cimport rich_to_bool @@ -117,30 +116,6 @@ cimport gmpy2 gmpy2.import_gmpy2() -def is_ComplexDoubleField(x): - """ - Return ``True`` if ``x`` is the complex double field. - - This function is deprecated. Use :func:`isinstance` with - :class:`~sage.rings.abc.ComplexDoubleField` instead. - - EXAMPLES:: - - sage: from sage.rings.complex_double import is_ComplexDoubleField - sage: is_ComplexDoubleField(CDF) - doctest:warning... - DeprecationWarning: is_ComplexDoubleField is deprecated; - use isinstance(..., sage.rings.abc.ComplexDoubleField) instead - See https://github.com/sagemath/sage/issues/32610 for details. - True - sage: is_ComplexDoubleField(ComplexField(53)) - False - """ - from sage.misc.superseded import deprecation - deprecation(32610, 'is_ComplexDoubleField is deprecated; use isinstance(..., sage.rings.abc.ComplexDoubleField) instead') - return isinstance(x, ComplexDoubleField_class) - - cdef class ComplexDoubleField_class(sage.rings.abc.ComplexDoubleField): """ An approximation to the field of complex numbers using double @@ -316,13 +291,13 @@ cdef class ComplexDoubleField_class(sage.rings.abc.ComplexDoubleField): 2.0 - 3.0*I sage: CDF(4.5) # indirect doctest 4.5 - sage: CDF(1+I) # indirect doctest + sage: CDF(1+I) # indirect doctest # needs sage.symbolic 1.0 + 1.0*I - sage: CDF(pari(1)) + sage: CDF(pari(1)) # needs sage.libs.pari 1.0 - sage: CDF(pari("I")) + sage: CDF(pari("I")) # needs sage.libs.pari 1.0*I - sage: CDF(pari("x^2 + x + 1").polroots()[0]) + sage: CDF(pari("x^2 + x + 1").polroots()[0]) # needs sage.libs.pari -0.5 - 0.8660254037844386*I sage: from gmpy2 import mpc sage: CDF(mpc('2.0+1.0j')) @@ -339,6 +314,7 @@ cdef class ComplexDoubleField_class(sage.rings.abc.ComplexDoubleField): numbers and higher-precision ones, though of course there may be loss of precision:: + sage: # needs sage.rings.real_mpfr sage: a = ComplexField(200)(-2).sqrt(); a 1.4142135623730950488016887242096980785696718753769480731767*I sage: b = CDF(a); b @@ -354,7 +330,7 @@ cdef class ComplexDoubleField_class(sage.rings.abc.ComplexDoubleField): Check that :trac:`31836` is fixed:: - sage: a = CDF() ; a + sage: a = CDF(); a 0.0 sage: a.parent() Complex Double Field @@ -422,16 +398,17 @@ cdef class ComplexDoubleField_class(sage.rings.abc.ComplexDoubleField): Thus the sum of a CDF and a symbolic object is symbolic:: - sage: a = pi + CDF.0; a + sage: a = pi + CDF.0; a # needs sage.symbolic pi + 1.0*I - sage: parent(a) + sage: parent(a) # needs sage.symbolic Symbolic Ring TESTS:: + sage: # needs sage.rings.real_mpfr sage: CDF(1) + RR(1) 2.0 - sage: CDF.0 - CC(1) - int(1) - RR(1) - QQbar(1) + sage: CDF.0 - CC(1) - int(1) - RR(1) - QQbar(1) # needs sage.rings.number_field -4.0 + 1.0*I sage: CDF.has_coerce_map_from(ComplexField(20)) False @@ -473,13 +450,13 @@ cdef class ComplexDoubleField_class(sage.rings.abc.ComplexDoubleField): EXAMPLES:: - sage: CDF._magma_init_(magma) # optional - magma + sage: CDF._magma_init_(magma) # optional - magma 'ComplexField(53 : Bits := true)' - sage: magma(CDF) # optional - magma + sage: magma(CDF) # optional - magma Complex field of precision 15 - sage: floor(RR(log(2**53, 10))) + sage: floor(RR(log(2**53, 10))) # needs sage.symbolic 15 - sage: magma(CDF).sage() # optional - magma + sage: magma(CDF).sage() # optional - magma Complex Field with 53 bits of precision """ return "ComplexField(%s : Bits := true)" % self.prec() @@ -891,13 +868,14 @@ cdef class ComplexDoubleElement(FieldElement): EXAMPLES:: - sage: CDF((1.2, 0.3))._magma_init_(magma) # optional - magma + sage: # optional - magma + sage: CDF((1.2, 0.3))._magma_init_(magma) 'ComplexField(53 : Bits := true)![1.2, 0.3]' - sage: magma(CDF(1.2, 0.3)) # optional - magma # indirect doctest + sage: magma(CDF(1.2, 0.3)) # indirect doctest 1.20000000000000 + 0.300000000000000*$.1 - sage: s = magma(CDF(1.2, 0.3)).sage(); s # optional - magma # indirect doctest + sage: s = magma(CDF(1.2, 0.3)).sage(); s # indirect doctest 1.20000000000000 + 0.300000000000000*I - sage: s.parent() # optional - magma + sage: s.parent() Complex Field with 53 bits of precision """ return "%s![%s, %s]" % (self.parent()._magma_init_(magma), self.real(), self.imag()) @@ -982,11 +960,11 @@ cdef class ComplexDoubleElement(FieldElement): EXAMPLES:: - sage: s1 = CDF(exp(I)); s1 + sage: s1 = CDF(exp(I)); s1 # needs sage.symbolic 0.5403023058681398 + 0.8414709848078965*I - sage: s1._interface_init_() + sage: s1._interface_init_() # needs sage.symbolic '0.54030230586813977 + 0.84147098480789650*I' - sage: s1 == CDF(gp(s1)) + sage: s1 == CDF(gp(s1)) # needs sage.symbolic True """ # Sending to another computer algebra system is slow anyway, right? @@ -1014,7 +992,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: CDF.0._maxima_init_() '1.0000000000000000*%i' - sage: CDF(.5 + I)._maxima_init_() + sage: CDF(.5 + I)._maxima_init_() # needs sage.symbolic '0.50000000000000000 + 1.0000000000000000*%i' """ from .complex_mpfr import ComplexField @@ -1026,11 +1004,11 @@ cdef class ComplexDoubleElement(FieldElement): EXAMPLES:: - sage: CDF(1, 0)._sympy_() + sage: CDF(1, 0)._sympy_() # needs sympy 1.00000000000000 - sage: CDF(1/3, 1)._sympy_() + sage: CDF(1/3, 1)._sympy_() # needs sympy 0.333333333333333 + 1.0*I - sage: type(_) + sage: type(_) # needs sympy <class 'sympy.core.add.Add'> """ x = GSL_REAL(self._complex) @@ -1146,6 +1124,7 @@ cdef class ComplexDoubleElement(FieldElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: CDF(1,2).__pari__() 1.00000000000000 + 2.00000000000000*I sage: pari(CDF(1,2)) @@ -1355,11 +1334,11 @@ cdef class ComplexDoubleElement(FieldElement): sage: CDF(6).argument() 0.0 - sage: CDF(i).argument() + sage: CDF(i).argument() # needs sage.symbolic 1.5707963267948966 sage: CDF(-1).argument() 3.141592653589793 - sage: CDF(-1 - 0.000001*i).argument() + sage: CDF(-1 - 0.000001*i).argument() # needs sage.symbolic -3.1415916535897934 """ return RealDoubleElement(gsl_complex_arg(self._complex)) @@ -1565,13 +1544,13 @@ cdef class ComplexDoubleElement(FieldElement): def is_integer(self): """ - Returns True if this number is a integer + Return ``True`` if this number is a integer EXAMPLES:: sage: CDF(0.5).is_integer() False - sage: CDF(I).is_integer() + sage: CDF(I).is_integer() # needs sage.symbolic False sage: CDF(2).is_integer() True @@ -1629,7 +1608,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: CDF(1, 2).is_NaN() False - sage: CDF(NaN).is_NaN() + sage: CDF(NaN).is_NaN() # needs sage.symbolic True sage: (1/CDF(0, 0)).is_NaN() True @@ -1664,11 +1643,11 @@ cdef class ComplexDoubleElement(FieldElement): We raise to symbolic powers:: - sage: var('x, n') + sage: var('x, n') # needs sage.symbolic (x, n) - sage: CDF(1.2)^x + sage: CDF(1.2)^x # needs sage.symbolic 1.2^x - sage: CDF(1.2)^(x^n + n^x) + sage: CDF(1.2)^(x^n + n^x) # needs sage.symbolic 1.2^(n^x + x^n) A real number powered to an exact integer always yields a real @@ -1740,9 +1719,9 @@ cdef class ComplexDoubleElement(FieldElement): We numerically verify a famous identity to the precision of a double:: - sage: z = CDF(0, 2*pi); z + sage: z = CDF(0, 2*pi); z # needs sage.symbolic 6.283185307179586*I - sage: exp(z) # rel tol 1e-4 + sage: exp(z) # rel tol 1e-4 # needs sage.symbolic 1.0 - 2.4492935982947064e-16*I """ return self._new_c(gsl_complex_exp(self._complex)) @@ -1987,10 +1966,10 @@ cdef class ComplexDoubleElement(FieldElement): """ return self._new_c(gsl_complex_arcsec(self._complex)) - ####################################################################### # Complex Hyperbolic Functions ####################################################################### + def sinh(self): r""" This function returns the complex hyperbolic sine of the complex @@ -2195,41 +2174,42 @@ cdef class ComplexDoubleElement(FieldElement): We compute a few values of :meth:`eta()`:: - sage: CDF(0,1).eta() + sage: CDF(0,1).eta() # needs sage.libs.pari 0.7682254223260566 - sage: CDF(1,1).eta() + sage: CDF(1,1).eta() # needs sage.libs.pari 0.7420487758365647 + 0.1988313702299107*I - sage: CDF(25,1).eta() + sage: CDF(25,1).eta() # needs sage.libs.pari 0.7420487758365647 + 0.1988313702299107*I :meth:`eta()` works even if the inputs are large:: sage: CDF(0, 10^15).eta() 0.0 - sage: CDF(10^15, 0.1).eta() # abs tol 1e-10 + sage: CDF(10^15, 0.1).eta() # abs tol 1e-10 # needs sage.libs.pari -0.115342592727 - 0.19977923088*I We compute a few values of :meth:`eta()`, but with the fractional power of `e` omitted:: - sage: CDF(0,1).eta(True) + sage: CDF(0,1).eta(True) # needs sage.libs.pari 0.9981290699259585 We compute :meth:`eta()` to low precision directly from the definition:: - sage: z = CDF(1,1); z.eta() + sage: z = CDF(1,1); z.eta() # needs sage.libs.pari 0.7420487758365647 + 0.1988313702299107*I - sage: i = CDF(0,1); pi = CDF(pi) - sage: exp(pi * i * z / 12) * prod([1-exp(2*pi*i*n*z) for n in range(1,10)]) + sage: i = CDF(0,1); pi = CDF(pi) # needs sage.symbolic + sage: exp(pi * i * z / 12) * prod(1 - exp(2*pi*i*n*z) # needs sage.libs.pari sage.symbolic + ....: for n in range(1, 10)) 0.7420487758365647 + 0.19883137022991068*I The optional argument allows us to omit the fractional part:: - sage: z.eta(omit_frac=True) + sage: z.eta(omit_frac=True) # needs sage.libs.pari 0.9981290699259585 - sage: pi = CDF(pi) - sage: prod([1-exp(2*pi*i*n*z) for n in range(1,10)]) # abs tol 1e-12 + sage: pi = CDF(pi) # needs sage.symbolic + sage: prod(1 - exp(2*pi*i*n*z) for n in range(1,10)) # abs tol 1e-12 # needs sage.libs.pari sage.symbolic 0.998129069926 + 4.59084695545e-19*I We illustrate what happens when `z` is not in the upper half plane:: @@ -2243,7 +2223,7 @@ cdef class ComplexDoubleElement(FieldElement): You can also use functional notation:: sage: z = CDF(1,1) - sage: eta(z) + sage: eta(z) # needs sage.libs.pari 0.7420487758365647 + 0.1988313702299107*I """ if GSL_IMAG(self._complex) <= 0: @@ -2296,8 +2276,8 @@ cdef class ComplexDoubleElement(FieldElement): EXAMPLES:: - sage: i = CDF(I) - sage: (1+i).agm(2-i) # rel tol 1e-15 + sage: i = CDF(I) # needs sage.symbolic + sage: (1+i).agm(2-i) # rel tol 1e-15 # needs sage.symbolic 1.6278054848727064 + 0.1368275483973686*I An example to show that the returned value depends on the algorithm @@ -2373,9 +2353,9 @@ cdef class ComplexDoubleElement(FieldElement): EXAMPLES:: - sage: CDF(1,2).dilog() + sage: CDF(1,2).dilog() # needs sage.libs.pari -0.059474798673809476 + 2.0726479717747566*I - sage: CDF(10000000,10000000).dilog() + sage: CDF(10000000,10000000).dilog() # needs sage.libs.pari -134.411774490731 + 38.79396299904504*I """ global complex_double_element_dilog @@ -2390,6 +2370,7 @@ cdef class ComplexDoubleElement(FieldElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: CDF(5,0).gamma() 24.0 sage: CDF(1,1).gamma() @@ -2421,11 +2402,11 @@ cdef class ComplexDoubleElement(FieldElement): EXAMPLES:: - sage: CDF(1,1).gamma_inc(CDF(2,3)) + sage: CDF(1,1).gamma_inc(CDF(2,3)) # needs sage.libs.pari 0.0020969148636468277 - 0.059981913655449706*I - sage: CDF(1,1).gamma_inc(5) + sage: CDF(1,1).gamma_inc(5) # needs sage.libs.pari -0.001378130936215849 + 0.006519820023119819*I - sage: CDF(2,0).gamma_inc(CDF(1,1)) + sage: CDF(2,0).gamma_inc(CDF(1,1)) # needs sage.libs.pari 0.7070920963459381 - 0.4203536409598115*I """ global complex_double_element_gamma_inc @@ -2440,11 +2421,11 @@ cdef class ComplexDoubleElement(FieldElement): EXAMPLES:: sage: z = CDF(1, 1) - sage: z.zeta() + sage: z.zeta() # needs sage.libs.pari 0.5821580597520036 - 0.9268485643308071*I - sage: zeta(z) + sage: zeta(z) # needs sage.libs.pari 0.5821580597520036 - 0.9268485643308071*I - sage: zeta(CDF(1)) + sage: zeta(CDF(1)) # needs sage.libs.pari Infinity """ if GSL_REAL(self._complex) == 1 and GSL_IMAG(self._complex) == 0: @@ -2468,18 +2449,18 @@ cdef class ComplexDoubleElement(FieldElement): EXAMPLES:: - sage: z = (1/2)*(1 + RDF(sqrt(3)) *CDF.0); z # abs tol 1e-16 + sage: z = (1/2)*(1 + RDF(sqrt(3)) * CDF.0); z # abs tol 1e-16 # needs sage.symbolic 0.5 + 0.8660254037844387*I - sage: p = z.algdep(5); p + sage: p = z.algdep(5); p # needs sage.libs.pari sage.symbolic x^2 - x + 1 - sage: abs(z^2 - z + 1) < 1e-14 + sage: abs(z^2 - z + 1) < 1e-14 # needs sage.symbolic True :: - sage: CDF(0,2).algdep(10) + sage: CDF(0,2).algdep(10) # needs sage.libs.pari x^2 + 4 - sage: CDF(1,5).algdep(2) + sage: CDF(1,5).algdep(2) # needs sage.libs.pari x^2 - 2*x + 26 """ from sage.arith.misc import algdep @@ -2544,7 +2525,7 @@ cdef class FloatToCDF(Morphism): 1.0 + 2.0*I sage: CDF('i') # indirect doctest 1.0*I - sage: CDF(2+i) # indirect doctest + sage: CDF(2+i) # indirect doctest # needs sage.symbolic 2.0 + 1.0*I """ cdef ComplexDoubleElement z = <ComplexDoubleElement>ComplexDoubleElement.__new__(ComplexDoubleElement) @@ -2570,11 +2551,11 @@ cdef class ComplexToCDF(Morphism): EXAMPLES:: - sage: import numpy - sage: f = CDF.coerce_map_from(numpy.complex_) - sage: f(numpy.complex_(I)) + sage: import numpy # needs numpy + sage: f = CDF.coerce_map_from(numpy.complex_) # needs numpy + sage: f(numpy.complex_(I)) # needs numpy 1.0*I - sage: f(numpy.complex_(I)).parent() + sage: f(numpy.complex_(I)).parent() # needs numpy Complex Double Field """ def __init__(self, R): @@ -2590,8 +2571,8 @@ cdef class ComplexToCDF(Morphism): EXAMPLES:: - sage: import numpy - sage: CDF(numpy.complex_(I)) # indirect doctest + sage: import numpy # needs numpy + sage: CDF(numpy.complex_(I)) # indirect doctest # needs numpy 1.0*I """ cdef ComplexDoubleElement z = <ComplexDoubleElement>ComplexDoubleElement.__new__(ComplexDoubleElement) @@ -2604,9 +2585,9 @@ cdef class ComplexToCDF(Morphism): EXAMPLES:: - sage: import numpy - sage: f = sage.rings.complex_double.ComplexToCDF(numpy.complex_) - sage: f._repr_type() + sage: import numpy # needs numpy + sage: f = sage.rings.complex_double.ComplexToCDF(numpy.complex_) # needs numpy + sage: f._repr_type() # needs numpy 'Native' """ return "Native" diff --git a/src/sage/rings/complex_field.py b/src/sage/rings/complex_field.py deleted file mode 100644 index c410c069409..00000000000 --- a/src/sage/rings/complex_field.py +++ /dev/null @@ -1,17 +0,0 @@ -r""" -Deprecated in favor of :mod:`sage.rings.complex_mpfr` - -TESTS:: - - sage: from sage.rings.complex_field import ComplexField - doctest:warning - ... - DeprecationWarning: the complex_field module is deprecated, please use sage.rings.complex_mpfr - See https://github.com/sagemath/sage/issues/24483 for details. - sage: ComplexField() - Complex Field with 53 bits of precision -""" - -from sage.misc.superseded import deprecation -from sage.rings.complex_mpfr import * -deprecation(24483, "the complex_field module is deprecated, please use sage.rings.complex_mpfr") diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index c993ac687b2..7fe25fd8114 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -64,13 +64,12 @@ from sage.libs.flint.fmpz cimport * from sage.libs.mpfr cimport MPFR_RNDU, MPFR_RNDD from sage.arith.constants cimport LOG_TEN_TWO_PLUS_EPSILON -from sage.structure.element cimport FieldElement, RingElement, Element, ModuleElement +from sage.structure.element cimport FieldElement from sage.structure.parent cimport Parent from .complex_mpfr cimport ComplexNumber -from .complex_mpfr import ComplexField from sage.rings.integer cimport Integer cimport sage.rings.real_mpfi as real_mpfi -from .real_mpfr cimport RealNumber, RealField +from .real_mpfr cimport RealNumber from .convert.mpfi cimport mpfi_set_sage from .infinity import infinity @@ -90,7 +89,7 @@ def is_ComplexIntervalFieldElement(x): return isinstance(x, ComplexIntervalFieldElement) -cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): +cdef class ComplexIntervalFieldElement(FieldElement): """ A complex interval. @@ -143,7 +142,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): mpfi_set_sage(self.__re, NULL, real, parent, base) mpfi_set_sage(self.__im, NULL, imag, parent, base) - def __dealloc__(self): + def __dealloc__(self): if self._parent is not None: mpfi_clear(self.__re) mpfi_clear(self.__im) @@ -231,7 +230,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): '-2.5000000000000000?*I' sage: CIF(1.5).str(base=3) '1.1111111111111111111111111111111112?' - sage: CIF(1, pi).str(style='brackets') + sage: CIF(1, pi).str(style='brackets') # needs sage.symbolic '[1.0000000000000000 .. 1.0000000000000000] + [3.1415926535897931 .. 3.1415926535897936]*I' .. SEEALSO:: @@ -286,16 +285,18 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): EXAMPLES:: - sage: sum(plot(CIF(RIF(1/k, 1/k), RIF(-k, k))) for k in [1..10]) + sage: sum(plot(CIF(RIF(1/k, 1/k), RIF(-k, k))) for k in [1..10]) # needs sage.plot Graphics object consisting of 20 graphics primitives Exact and nearly exact points are still visible:: + sage: # needs sage.plot sage: plot(CIF(pi, 1), color='red') + plot(CIF(1, e), color='purple') + plot(CIF(-1, -1)) Graphics object consisting of 6 graphics primitives A demonstration that `z \mapsto z^2` acts chaotically on `|z|=1`:: + sage: # needs sage.plot sage.symbolic sage: z = CIF(0, 2*pi/1000).exp() sage: g = Graphics() sage: for i in range(40): @@ -352,11 +353,11 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): (2.50000000000000, 3.00000000000000) (-4.50000000000000, -4.00000000000000) + sage: # needs sage.symbolic sage: z = CIF(RIF(sqrt(2), sqrt(3)), RIF(e, pi)) sage: a, b, c, d = z.bisection() sage: a.intersection(b).intersection(c).intersection(d) == CIF(z.center()) True - sage: zz = a.union(b).union(c).union(c) sage: zz.real().endpoints() == z.real().endpoints() True @@ -400,9 +401,9 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): True sage: CIF(-5, 0).sqrt().is_exact() False - sage: CIF(0, 2*pi).is_exact() + sage: CIF(0, 2*pi).is_exact() # needs sage.symbolic False - sage: CIF(e).is_exact() + sage: CIF(e).is_exact() # needs sage.symbolic False sage: CIF(1e100).is_exact() True @@ -986,7 +987,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): Here a conversion to Maxima happens, which results in a ``TypeError``:: sage: a = CIF(2.3) - sage: maxima(a) + sage: maxima(a) # needs sage.symbolic Traceback (most recent call last): ... TypeError @@ -1000,7 +1001,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): EXAMPLES:: - sage: sage_input(CIF(RIF(e, pi), RIF(sqrt(2), sqrt(3))), verify=True) + sage: sage_input(CIF(RIF(e, pi), RIF(sqrt(2), sqrt(3))), verify=True) # needs sage.symbolic # Verified CIF(RIF(RR(2.7182818284590451), RR(3.1415926535897936)), RIF(RR(1.4142135623730949), RR(1.7320508075688774))) sage: sage_input(ComplexIntervalField(64)(2)^I, preparse=False, verify=True) @@ -1998,7 +1999,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): sage: CIF(2, 1).is_NaN() False - sage: CIF(NaN).is_NaN() + sage: CIF(NaN).is_NaN() # needs sage.symbolic True sage: (1 / CIF(0, 0)).is_NaN() True @@ -2020,7 +2021,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): Check that :trac:`17285` is fixed:: - sage: CIF(cos(2/3)) + sage: CIF(cos(2/3)) # needs sage.symbolic 0.7858872607769480? ALGORITHM: @@ -2062,7 +2063,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): Check that :trac:`17825` is fixed:: - sage: CIF(sin(2/3)) + sage: CIF(sin(2/3)) # needs sage.symbolic 0.618369803069737? ALGORITHM: diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index 81385cc7bfb..5c5e6bbb906 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -49,27 +49,6 @@ from sage.misc.cachefunc import cached_method -def is_ComplexIntervalField(x): - """ - Check if ``x`` is a :class:`ComplexIntervalField`. - - EXAMPLES:: - - sage: from sage.rings.complex_interval_field import is_ComplexIntervalField as is_CIF - sage: is_CIF(CIF) - doctest:warning... - DeprecationWarning: is_ComplexIntervalField is deprecated; - use isinstance(..., sage.rings.abc.ComplexIntervalField) instead - See https://github.com/sagemath/sage/issues/32612 for details. - True - sage: is_CIF(CC) - False - """ - from sage.misc.superseded import deprecation - deprecation(32612, 'is_ComplexIntervalField is deprecated; use isinstance(..., sage.rings.abc.ComplexIntervalField) instead') - return isinstance(x, ComplexIntervalField_class) - - cache = {} def ComplexIntervalField(prec=53, names=None): """ @@ -304,7 +283,7 @@ def _magma_init_(self, magma): sage: magma(ComplexIntervalField(100)) # optional - magma # indirect doctest Complex field of precision 30 - sage: floor(RR(log(2**100, 10))) + sage: floor(RR(log(2**100, 10))) # needs sage.symbolic 30 """ return "ComplexField(%s : Bits := true)" % self.prec() @@ -445,7 +424,7 @@ def __call__(self, x=None, im=None, **kwds): TypeError: unable to convert '1+I' to real interval sage: CIF(2,3) 2 + 3*I - sage: CIF(pi, e) + sage: CIF(pi, e) # needs sage.symbolic 3.141592653589794? + 2.718281828459046?*I sage: ComplexIntervalField(100)(CIF(RIF(2,3))) 3.? @@ -558,7 +537,7 @@ def _repr_(self): sage: ComplexIntervalField(100) # indirect doctest Complex Interval Field with 100 bits of precision """ - return "Complex Interval Field with %s bits of precision"%self._prec + return "Complex Interval Field with %s bits of precision" % self._prec def _latex_(self): r""" @@ -627,7 +606,7 @@ def random_element(self, *args, **kwds): im = rand(*args, **kwds) return self.element_class(self, re, im) - def is_field(self, proof = True): + def is_field(self, proof=True): """ Return ``True``, since the complex numbers are a field. diff --git a/src/sage/rings/complex_mpc.pxd b/src/sage/rings/complex_mpc.pxd index 762c38afbdc..f7d8cb9492c 100644 --- a/src/sage/rings/complex_mpc.pxd +++ b/src/sage/rings/complex_mpc.pxd @@ -11,7 +11,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): cpdef _mul_(self, other) cdef class MPComplexField_class(sage.rings.ring.Field): - cdef readonly int __prec + cdef readonly int _prec cdef mpc_rnd_t __rnd cdef object __rnd_str cdef object __real_field diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index 456883bb17a..ae2bd50c735 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -69,7 +69,7 @@ from sage.libs.mpfr cimport * from sage.libs.mpc cimport * from sage.structure.parent cimport Parent from sage.structure.parent_gens cimport ParentWithGens -from sage.structure.element cimport RingElement, Element, ModuleElement +from sage.structure.element cimport Element from sage.structure.richcmp cimport rich_to_bool from sage.categories.map cimport Map from sage.libs.pari.all import pari @@ -84,8 +84,6 @@ from .real_mpfr import mpfr_prec_min, mpfr_prec_max from sage.structure.richcmp cimport rich_to_bool, richcmp from sage.categories.fields import Fields -from sage.misc.superseded import deprecated_function_alias - cimport gmpy2 gmpy2.import_gmpy2() @@ -206,7 +204,7 @@ cpdef inline split_complex_string(string, int base=10): else: return None - if z.group(prefix + '_re_abs') is not None: + if z.group(prefix + '_re_abs') is not None: x = z.expand(r'\g<' + prefix + '_re_abs>') if z.group(prefix + '_re_sign') is not None: x = z.expand(r'\g<' + prefix + '_re_sign>') + x @@ -307,14 +305,14 @@ cdef class MPComplexField_class(sage.rings.ring.Field): if prec < mpfr_prec_min() or prec > mpfr_prec_max(): raise ValueError("prec (=%s) must be >= %s and <= %s." % ( prec, mpfr_prec_min(), mpfr_prec_max())) - self.__prec = prec + self._prec = prec if not isinstance(rnd, str): raise TypeError("rnd must be a string") try: n = _mpc_rounding_modes.index(rnd) except ValueError: - raise ValueError("rnd (=%s) must be of the form RNDxy"\ - "where x and y are one of N, Z, U, D" % rnd) + raise ValueError("rnd (=%s) must be of the form RNDxy" + "where x and y are one of N, Z, U, D" % rnd) self.__rnd = n self.__rnd_str = rnd @@ -331,7 +329,7 @@ cdef class MPComplexField_class(sage.rings.ring.Field): cdef MPComplexNumber z z = MPComplexNumber.__new__(MPComplexNumber) z._parent = self - mpc_init2(z.value, self.__prec) + mpc_init2(z.value, self._prec) z.init = 1 return z @@ -344,7 +342,7 @@ cdef class MPComplexField_class(sage.rings.ring.Field): sage: MPComplexField(200, 'RNDDU') # indirect doctest Complex Field with 200 bits of precision and rounding RNDDU """ - s = "Complex Field with %s bits of precision"%self.__prec + s = "Complex Field with %s bits of precision"%self._prec if self.__rnd != MPC_RNDNN: s = s + " and rounding %s"%(self.__rnd_str) return s @@ -465,13 +463,13 @@ cdef class MPComplexField_class(sage.rings.ring.Field): if RR.has_coerce_map_from(S): return self._coerce_map_via([RR], S) - if isinstance(S, MPComplexField_class) and S.prec() >= self.__prec: + if isinstance(S, MPComplexField_class) and S.prec() >= self._prec: #FIXME: What map when rounding modes differ but prec is the same ? # How to provide commutativity of morphisms ? # Change _cmp_ when done return MPCtoMPC(S, self) - if isinstance(S, ComplexField_class) and S.prec() >= self.__prec: + if isinstance(S, ComplexField_class) and S.prec() >= self._prec: return CCtoMPC(S, self) late_import() @@ -490,7 +488,7 @@ cdef class MPComplexField_class(sage.rings.ring.Field): sage: loads(dumps(C)) == C True """ - return __create__MPComplexField_version0, (self.__prec, self.__rnd_str) + return __create__MPComplexField_version0, (self._prec, self.__rnd_str) def __richcmp__(left, right, int op): """ @@ -513,7 +511,7 @@ cdef class MPComplexField_class(sage.rings.ring.Field): cdef MPComplexField_class s = <MPComplexField_class>left cdef MPComplexField_class o = <MPComplexField_class>right - return richcmp(s.__prec, o.__prec, op) + return richcmp(s._prec, o._prec, op) def gen(self, n=0): """ @@ -604,7 +602,7 @@ cdef class MPComplexField_class(sage.rings.ring.Field): sage: C = MPComplexField(10, 'RNDNZ'); C.name() 'MPComplexField10_RNDNZ' """ - return "MPComplexField%s_%s"%(self.__prec, self.__rnd_str) + return "MPComplexField%s_%s"%(self._prec, self.__rnd_str) def __hash__(self): """ @@ -629,7 +627,7 @@ cdef class MPComplexField_class(sage.rings.ring.Field): sage: MPComplexField(22).prec() 22 """ - return self.__prec + return self._prec def rounding_mode(self): """ @@ -707,7 +705,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): cdef MPComplexNumber z z = MPComplexNumber.__new__(MPComplexNumber) z._parent = self._parent - mpc_init2(z.value, (<MPComplexField_class>self._parent).__prec) + mpc_init2(z.value, (<MPComplexField_class>self._parent)._prec) z.init = 1 return z @@ -760,7 +758,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): if parent is None: raise TypeError self._parent = parent - mpc_init2(self.value, parent.__prec) + mpc_init2(self.value, parent._prec) self.init = 1 if x is None: return self._set(x, y, base) @@ -816,7 +814,6 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): """ # This should not be called except when the number is being created. # Complex Numbers are supposed to be immutable. - cdef RealNumber x cdef mpc_rnd_t rnd rnd =(<MPComplexField_class>self._parent).__rnd if y is None: @@ -1011,7 +1008,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): sage: i.prec() 2000 """ - return <MPComplexField_class>(self._parent).__prec + return <MPComplexField_class>(self._parent)._prec def real(self): """ @@ -1158,8 +1155,8 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): TypeError: can...t convert complex to float; use abs(z) """ if mpfr_zero_p(self.value.im): - return mpfr_get_d(self.value.re,\ - rnd_re((<MPComplexField_class>self._parent).__rnd)) + return mpfr_get_d(self.value.re, + rnd_re((<MPComplexField_class>self._parent).__rnd)) else: raise TypeError("can't convert complex to float; use abs(z)") @@ -1196,27 +1193,27 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): sage: MPC = MPComplexField() sage: a = MPC(2,1) - sage: a.__pari__() + sage: a.__pari__() # needs sage.libs.pari 2.00000000000000 + 1.00000000000000*I - sage: pari(a) + sage: pari(a) # needs sage.libs.pari 2.00000000000000 + 1.00000000000000*I - sage: pari(a).type() + sage: pari(a).type() # needs sage.libs.pari 't_COMPLEX' - sage: a = MPC(pi) - sage: pari(a) + sage: a = MPC(pi) # needs sage.libs.pari sage.symbolic + sage: pari(a) # needs sage.libs.pari sage.symbolic 3.14159265358979 - sage: pari(a).type() + sage: pari(a).type() # needs sage.libs.pari sage.symbolic 't_REAL' sage: a = MPC(-2).sqrt() - sage: pari(a) + sage: pari(a) # needs sage.libs.pari 1.41421356237310*I The precision is preserved, rounded up to the wordsize:: sage: MPC = MPComplexField(250) - sage: MPC(1,2).__pari__().bitprecision() + sage: MPC(1,2).__pari__().bitprecision() # needs sage.libs.pari 256 - sage: MPC(pi).__pari__().bitprecision() + sage: MPC(pi).__pari__().bitprecision() # needs sage.libs.pari 256 """ if mpfr_zero_p(self.value.re): @@ -1521,7 +1518,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): 2.23606797749979 sage: a.__abs__() 2.23606797749979 - sage: float(sqrt(2^2 + 1^1)) + sage: float(sqrt(2^2 + 1^1)) # needs sage.symbolic 2.23606797749979 sage: b = MPC(42,0) @@ -1572,26 +1569,6 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): mpc_norm(x.value, self.value, (<RealField_class>x._parent).rnd) return x - def __rtruediv__(self, left): - r""" - Returns the quotient of ``left`` with ``self``, that is: ``left/self`` - as a complex number. - - INPUT: - - - ``left`` -- a complex number - - EXAMPLES:: - - sage: MPC = MPComplexField() - sage: a = MPC(2, 2) - sage: a.__rtruediv__(MPC(1)) - 0.250000000000000 - 0.250000000000000*I - sage: MPC(1)/a - 0.250000000000000 - 0.250000000000000*I - """ - return MPComplexNumber(self._parent, left)/self - def __pow__(self, right, modulus): """ Compute ``self`` raised to the power of exponent, rounded in @@ -1970,8 +1947,6 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): """ return ~(self.tan()) - cotan = deprecated_function_alias(29412, cot) - ################################ # Other functions ################################ @@ -2184,7 +2159,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): tt= RealNumber(R) cdef list zlist = [z] - for i in xrange(1,n): + for i in range(1,n): z = self._new() mpfr_mul_ui(tt.value, t.value, i, rrnd) mpfr_add(tt.value, tt.value, a.value, rrnd) @@ -2213,7 +2188,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): sage: a = MPC(1,0) sage: a.dilog() 1.64493406684823 - sage: float(pi^2/6) + sage: float(pi^2/6) # needs sage.symbolic 1.6449340668482262 :: @@ -2338,18 +2313,17 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): sage: u.agm(v, algorithm="optimal") -0.410522769709397 + 4.60061063922097*I """ - if algorithm=="pari": + if algorithm == "pari": t = self._parent(right).__pari__() return self._parent(self.__pari__().agm(t)) cdef MPComplexNumber a, b, d, s, res - cdef mpfr_t sn,dn cdef mp_exp_t rel_prec cdef bint optimal = algorithm == "optimal" cdef mpc_rnd_t rnd = (<MPComplexField_class>(self._parent)).__rnd - cdef int prec = self._parent.__prec + cdef int prec = self._parent._prec if optimal or algorithm == "principal": if not isinstance(right, MPComplexNumber) or (<MPComplexNumber>right)._parent is not self._parent: @@ -2578,5 +2552,4 @@ cdef class CCtoMPC(Map): # Support Python's numbers abstract base class -import numbers -from sage.rings.complex_mpc import MPComplexNumber +# import numbers diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index 0b12280d6e5..1862cea7bbf 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -30,15 +30,13 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -import math -import operator import weakref import sage.misc.misc from sage.libs.mpfr cimport * -from sage.structure.element cimport FieldElement, RingElement, Element, ModuleElement +from sage.structure.element cimport RingElement, Element from sage.structure.richcmp cimport rich_to_bool from sage.categories.map cimport Map from sage.structure.parent import Parent @@ -48,7 +46,7 @@ from sage.misc.sage_eval import sage_eval import sage.rings.abc from sage.arith.constants cimport LOG_TEN_TWO_PLUS_EPSILON -from . import ring, infinity +from . import infinity from .integer cimport Integer from .complex_double cimport ComplexDoubleElement @@ -58,8 +56,6 @@ from sage.libs.gsl.complex cimport * from sage.libs.mpmath.utils cimport mpfr_to_mpfval from sage.rings.integer_ring import ZZ -from sage.misc.superseded import deprecated_function_alias - cimport gmpy2 gmpy2.import_gmpy2() @@ -148,6 +144,7 @@ def is_ComplexNumber(x): while elements of the class :class:`ComplexField_class` are of type :class:`ComplexNumber`:: + sage: # needs sage.symbolic sage: c = 1 + 2*I sage: is_ComplexNumber(c) False @@ -158,32 +155,6 @@ def is_ComplexNumber(x): return isinstance(x, ComplexNumber) -def is_ComplexField(x): - """ - Check if ``x`` is a :class:`complex field <ComplexField_class>`. - - This function is deprecated. Use :func:`isinstance` with - :class:`~sage.rings.abc.ComplexField` instead. - - EXAMPLES:: - - sage: from sage.rings.complex_mpfr import is_ComplexField as is_CF - sage: is_CF(ComplexField()) - doctest:warning... - DeprecationWarning: is_ComplexField is deprecated; - use isinstance(..., sage.rings.abc.ComplexField) instead - See https://github.com/sagemath/sage/issues/32610 for details. - True - sage: is_CF(ComplexField(12)) - True - sage: is_CF(CC) - True - """ - from sage.misc.superseded import deprecation - deprecation(32610, 'is_ComplexField is deprecated; use isinstance(..., sage.rings.abc.ComplexField) instead') - return isinstance(x, ComplexField_class) - - cache = {} def ComplexField(prec=53, names=None): """ @@ -381,7 +352,6 @@ class ComplexField_class(sage.rings.abc.ComplexField): """ return ComplexField(prec) - # very useful to cache this. def _real_field(self): """ @@ -460,11 +430,12 @@ class ComplexField_class(sage.rings.abc.ComplexField): 1.00000000000000 + 1.00000000000000*I sage: CC(2,3) 2.00000000000000 + 3.00000000000000*I - sage: CC(QQ[I].gen()) + sage: CC(QQ[I].gen()) # needs sage.symbolic 1.00000000000000*I - sage: CC.gen() + QQ[I].gen() + sage: CC.gen() + QQ[I].gen() # needs sage.symbolic 2.00000000000000*I - sage: CC.gen() + QQ.extension(x^2 + 1, 'I', embedding=None).gen() + sage: x = polygen(ZZ, 'x') + sage: CC.gen() + QQ.extension(x^2 + 1, 'I', embedding=None).gen() # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for +: 'Complex Field with 53 bits of precision' and 'Number Field in I with defining polynomial x^2 + 1' @@ -494,9 +465,10 @@ class ComplexField_class(sage.rings.abc.ComplexField): Check that :trac:`14989` is fixed:: - sage: QQi = NumberField(x^2+1, 'i', embedding=CC(0,1)) - sage: i = QQi.order(QQi.gen()).gen(1) - sage: CC(i) + sage: x = polygen(ZZ, 'x') + sage: QQi = NumberField(x^2 + 1, 'i', embedding=CC(0,1)) # needs sage.rings.number_field + sage: i = QQi.order(QQi.gen()).gen(1) # needs sage.rings.number_field + sage: CC(i) # needs sage.rings.number_field 1.00000000000000*I TESTS:: @@ -517,7 +489,7 @@ class ComplexField_class(sage.rings.abc.ComplexField): x = x.replace('j', 'I') x = x.replace('E', 'e') allowed = '+-.*0123456789Ie' - if not all(letter in allowed for letter in x): + if len(x) == 0 or not all(letter in allowed for letter in x): raise ValueError(f'given string {x!r} is not a complex number') # This should rather use a proper parser to validate input. # TODO: this is probably not the best and most @@ -716,8 +688,8 @@ class ComplexField_class(sage.rings.abc.ComplexField): sage: re, im = CC6.random_element(2^-20) sage: -2^-20 <= re <= 2^-20, -2^-20 <= im <= 2^-20 (True, True) - sage: re, im = CC6.random_element(pi^20) - sage: bool(-pi^20 <= re <= pi^20), bool(-pi^20 <= im <= pi^20) + sage: re, im = CC6.random_element(pi^20) # needs sage.symbolic + sage: bool(-pi^20 <= re <= pi^20), bool(-pi^20 <= im <= pi^20) # needs sage.symbolic (True, True) Passes extra positional or keyword arguments through:: @@ -762,7 +734,7 @@ class ComplexField_class(sage.rings.abc.ComplexField): INPUT: - - ``n`` - an integer (default: 2) + - ``n`` -- an integer (default: 2) OUTPUT: a complex `n`-th root of unity. @@ -848,19 +820,20 @@ class ComplexField_class(sage.rings.abc.ComplexField): TESTS:: + sage: # needs sage.libs.pari sage: k = ComplexField(100) sage: R.<x> = k[] - sage: k._factor_univariate_polynomial( x ) + sage: k._factor_univariate_polynomial(x) x - sage: k._factor_univariate_polynomial( 2*x ) + sage: k._factor_univariate_polynomial(2*x) (2.0000000000000000000000000000) * x - sage: k._factor_univariate_polynomial( x^2 ) + sage: k._factor_univariate_polynomial(x^2) x^2 - sage: k._factor_univariate_polynomial( x^2 + 3 ) + sage: k._factor_univariate_polynomial(x^2 + 3) (x - 1.7320508075688772935274463415*I) * (x + 1.7320508075688772935274463415*I) - sage: k._factor_univariate_polynomial( x^2 + 1 ) + sage: k._factor_univariate_polynomial(x^2 + 1) (x - I) * (x + I) - sage: k._factor_univariate_polynomial( k(I) * (x^2 + 1) ) + sage: k._factor_univariate_polynomial(k(I) * (x^2 + 1)) (1.0000000000000000000000000000*I) * (x - I) * (x + I) """ @@ -976,15 +949,14 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): except TypeError: raise TypeError("unable to coerce to a ComplexNumber: %s" % type(real)) - - def __dealloc__(self): + def __dealloc__(self): """ TESTS: Check that :trac:`12038` is resolved:: sage: from sage.rings.complex_mpfr import ComplexNumber as CN - sage: coerce(CN, 1+I) + sage: coerce(CN, 1+I) # needs sage.symbolic Traceback (most recent call last): ... TypeError: ...__init__() takes at least 2 positional arguments (1 given) @@ -1001,11 +973,11 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: s1 = CC(exp(I)); s1 + sage: s1 = CC(exp(I)); s1 # needs sage.symbolic 0.540302305868140 + 0.841470984807897*I - sage: s1._interface_init_() + sage: s1._interface_init_() # needs sage.symbolic '0.54030230586813977 + 0.84147098480789650*I' - sage: s1 == CC(gp(s1)) + sage: s1 == CC(gp(s1)) # needs sage.libs.pari sage.symbolic True """ return self.str() @@ -1028,7 +1000,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): sage: CC.0._maxima_init_() '1.0000000000000000*%i' - sage: CC(.5 + I)._maxima_init_() + sage: CC(.5 + I)._maxima_init_() # needs sage.symbolic '0.50000000000000000 + 1.0000000000000000*%i' """ return self.str(istr='%i') @@ -1040,10 +1012,10 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: import numpy - sage: numpy.array([1.0, 2.5j]).dtype + sage: import numpy # needs numpy + sage: numpy.array([1.0, 2.5j]).dtype # needs numpy dtype('complex128') - sage: numpy.array([1.000000000000000000000000000000000000j]).dtype + sage: numpy.array([1.000000000000000000000000000000000000j]).dtype # needs numpy dtype('O') """ if self._prec <= 53: @@ -1184,7 +1156,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): INPUT: - - ``i`` - 0 or 1 + - ``i`` -- 0 or 1 - ``0`` -- will return the real component of ``self`` - ``1`` -- will return the imaginary component of ``self`` @@ -1267,8 +1239,8 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: a = CC(pi + I*e) - sage: a + sage: # needs sage.symbolic + sage: a = CC(pi + I*e); a 3.14159265358979 + 2.71828182845905*I sage: a.str(truncate=True) '3.14159265358979 + 2.71828182845905*I' @@ -1282,6 +1254,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): '3.243f6a8885a30 + 2.b7e151628aed2*I' sage: a.str(base=36) '3.53i5ab8p5fc + 2.puw5nggjf8f*I' + sage: CC(0) 0.000000000000000 sage: CC.0.str(istr='%i') @@ -1392,6 +1365,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): Coerce the object using the ``pari`` function:: + sage: # needs sage.libs.pari sage: a = ComplexNumber(2,1) sage: pari(a) 2.00000000000000 + 1.00000000000000*I @@ -1403,10 +1377,10 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): 2.00000000000000 + 1.00000000000000*I sage: type(a.__pari__()) <class 'cypari2.gen.Gen'> - sage: a = CC(pi) - sage: pari(a) + sage: a = CC(pi) # needs sage.symbolic + sage: pari(a) # needs sage.symbolic 3.14159265358979 - sage: pari(a).type() + sage: pari(a).type() # needs sage.symbolic 't_REAL' sage: a = CC(-2).sqrt() sage: pari(a) @@ -1476,11 +1450,11 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: CC(1, 0)._sympy_() + sage: CC(1, 0)._sympy_() # needs sympy 1.00000000000000 - sage: CC(1/3, 1)._sympy_() + sage: CC(1/3, 1)._sympy_() # needs sympy 0.333333333333333 + 1.0*I - sage: type(_) + sage: type(_) # needs sympy <class 'sympy.core.add.Add'> """ import sympy @@ -1661,28 +1635,6 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): mpfr_clear(right_nm) return x - def __rtruediv__(self, left): - r""" - Return the quotient of left with ``self``, that is: - - ``left/self`` - - as a complex number. - - INPUT: - - - ``left`` - a complex number to divide by ``self`` - - EXAMPLES:: - - sage: a = ComplexNumber(2,0) - sage: a.__rtruediv__(CC(1)) - 0.500000000000000 - sage: CC(1)/a - 0.500000000000000 - """ - return ComplexNumber(self._parent, left)/self - def __pow__(self, right, modulus): r""" Raise ``self`` to the ``right`` exponent. @@ -1760,7 +1712,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): def __bool__(self): """ Return ``True`` if ``self`` is not zero. This is an internal function; - use :meth:`is_zero()` instead. + use :meth:`is_zero` instead. EXAMPLES:: @@ -1882,7 +1834,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): 2.23606797749979 sage: a.__abs__() 2.23606797749979 - sage: float(sqrt(2^2 + 1^1)) + sage: float(sqrt(2^2 + 1^1)) # needs sage.symbolic 2.23606797749979 :: @@ -2032,7 +1984,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): def multiplicative_order(self): """ Return the multiplicative order of this complex number, if known, - or raise a ``NotImplementedError``. + or raise a :class:`NotImplementedError`. EXAMPLES:: @@ -2072,7 +2024,6 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): return infinity.infinity raise NotImplementedError("order of element not known") - ######################################################################## # Plotting ######################################################################## @@ -2093,13 +2044,13 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): You can either use the indirect:: sage: z = CC(0,1) - sage: plot(z) + sage: plot(z) # needs sage.plot Graphics object consisting of 1 graphics primitive or the more direct:: sage: z = CC(0,1) - sage: z.plot() + sage: z.plot() # needs sage.plot Graphics object consisting of 1 graphics primitive """ return sage.plot.point.point2d((self.real(), self.imag()), **kargs) @@ -2115,7 +2066,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: (1+CC(I)).arccos() + sage: (1+CC(I)).arccos() # needs sage.libs.pari 0.904556894302381 - 1.06127506190504*I """ return self._parent(self.__pari__().acos()) @@ -2126,7 +2077,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: (1+CC(I)).arccosh() + sage: (1+CC(I)).arccosh() # needs sage.libs.pari 1.06127506190504 + 0.904556894302381*I """ return self._parent(self.__pari__().acosh()) @@ -2137,7 +2088,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: (1+CC(I)).arcsin() + sage: (1+CC(I)).arcsin() # needs sage.libs.pari 0.666239432492515 + 1.06127506190504*I """ return self._parent(self.__pari__().asin()) @@ -2148,7 +2099,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: (1+CC(I)).arcsinh() + sage: (1+CC(I)).arcsinh() # needs sage.libs.pari 1.06127506190504 + 0.666239432492515*I """ return self._parent(self.__pari__().asinh()) @@ -2159,7 +2110,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: (1+CC(I)).arctan() + sage: (1+CC(I)).arctan() # needs sage.libs.pari 1.01722196789785 + 0.402359478108525*I """ return self._parent(self.__pari__().atan()) @@ -2170,7 +2121,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: (1+CC(I)).arctanh() + sage: (1+CC(I)).arctanh() # needs sage.libs.pari 0.402359478108525 + 1.01722196789785*I """ return self._parent(self.__pari__().atanh()) @@ -2181,7 +2132,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: ComplexField(100)(1,1).coth() + sage: ComplexField(100)(1,1).coth() # needs sage.libs.pari 0.86801414289592494863584920892 - 0.21762156185440268136513424361*I """ return ~(self.tanh()) @@ -2192,7 +2143,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: ComplexField(100)(1,1).arccoth() + sage: ComplexField(100)(1,1).arccoth() # needs sage.libs.pari 0.40235947810852509365018983331 - 0.55357435889704525150853273009*I """ return (~self).arctanh() @@ -2203,7 +2154,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: ComplexField(100)(1,1).csc() + sage: ComplexField(100)(1,1).csc() # needs sage.libs.pari 0.62151801717042842123490780586 - 0.30393100162842645033448560451*I """ return ~(self.sin()) @@ -2214,7 +2165,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: ComplexField(100)(1,1).csch() + sage: ComplexField(100)(1,1).csch() # needs sage.libs.pari 0.30393100162842645033448560451 - 0.62151801717042842123490780586*I """ return ~(self.sinh()) @@ -2225,7 +2176,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: ComplexField(100)(1,1).arccsch() + sage: ComplexField(100)(1,1).arccsch() # needs sage.libs.pari 0.53063753095251782601650945811 - 0.45227844715119068206365839783*I """ return (~self).arcsinh() @@ -2236,7 +2187,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: ComplexField(100)(1,1).sec() + sage: ComplexField(100)(1,1).sec() # needs sage.libs.pari 0.49833703055518678521380589177 + 0.59108384172104504805039169297*I """ return ~(self.cos()) @@ -2247,7 +2198,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: ComplexField(100)(1,1).sech() + sage: ComplexField(100)(1,1).sech() # needs sage.libs.pari 0.49833703055518678521380589177 - 0.59108384172104504805039169297*I """ return ~(self.cosh()) @@ -2258,7 +2209,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: - sage: ComplexField(100)(1,1).arcsech() + sage: ComplexField(100)(1,1).arcsech() # needs sage.libs.pari 0.53063753095251782601650945811 - 1.1185178796437059371676632938*I """ return (~self).arccosh() @@ -2269,6 +2220,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: (1+CC(I)).cot() 0.217621561854403 - 0.868014142895925*I sage: i = ComplexField(200).0 @@ -2287,8 +2239,6 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): """ return ~(self.tan()) - cotan = deprecated_function_alias(29412, cot) - def cos(self): """ Return the cosine of ``self``. @@ -2361,7 +2311,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): INPUT: - ``self`` -- element of the upper half plane (if not, - raises a ``ValueError``). + raises a :class:`ValueError`). - ``omit_frac`` -- (bool, default: ``False``), if ``True``, omit the `e^{\pi i z / 12}` factor. @@ -2375,37 +2325,35 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): First we compute `\eta(1+i)`:: sage: i = CC.0 - sage: z = 1+i; z.eta() + sage: z = 1 + i; z.eta() # needs sage.libs.pari 0.742048775836565 + 0.198831370229911*I We compute eta to low precision directly from the definition:: - sage: z = 1 + i; z.eta() - 0.742048775836565 + 0.198831370229911*I - sage: pi = CC(pi) # otherwise we will get a symbolic result. - sage: exp(pi * i * z / 12) * prod([1-exp(2*pi*i*n*z) for n in range(1,10)]) + sage: pi = CC(pi) # otherwise we will get a symbolic result. # needs sage.symbolic + sage: exp(pi * i * z / 12) * prod(1 - exp(2*pi*i*n*z) # needs sage.libs.pari sage.symbolic + ....: for n in range(1,10)) 0.742048775836565 + 0.198831370229911*I The optional argument allows us to omit the fractional part:: - sage: z = 1 + i - sage: z.eta(omit_frac=True) + sage: z.eta(omit_frac=True) # needs sage.libs.pari 0.998129069925959 - sage: prod([1-exp(2*pi*i*n*z) for n in range(1,10)]) + sage: prod(1 - exp(2*pi*i*n*z) for n in range(1,10)) # needs sage.libs.pari sage.symbolic 0.998129069925958 + 4.59099857829247e-19*I We illustrate what happens when `z` is not in the upper half plane:: sage: z = CC(1) - sage: z.eta() + sage: z.eta() # needs sage.libs.pari Traceback (most recent call last): ... ValueError: value must be in the upper half plane You can also use functional notation:: - sage: eta(1+CC(I)) + sage: eta(1 + CC(I)) # needs sage.libs.pari 0.742048775836565 + 0.198831370229911*I """ try: @@ -2556,7 +2504,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): - ``right`` (complex) -- another complex number - - ``algorithm`` (string, default "optimal") -- the algorithm to use + - ``algorithm`` (string, default ``"optimal"``) -- the algorithm to use (see below). OUTPUT: @@ -2565,18 +2513,18 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): this is a multi-valued function, and the algorithm used affects the value returned, as follows: - - "pari": Call the :pari:`agm` function from the pari library. + - ``"pari"``: Call the :pari:`agm` function from the PARI library. - - "optimal": Use the AGM sequence such that at each stage - `(a,b)` is replaced by `(a_1,b_1)=((a+b)/2,\pm\sqrt{ab})` - where the sign is chosen so that `|a_1-b_1|\le|a_1+b_1|`, or - equivalently `\Re(b_1/a_1)\ge 0`. The resulting limit is - maximal among all possible values. + - ``"optimal"``: Use the AGM sequence such that at each stage + `(a,b)` is replaced by `(a_1,b_1)=((a+b)/2,\pm\sqrt{ab})` + where the sign is chosen so that `|a_1-b_1|\le|a_1+b_1|`, or + equivalently `\Re(b_1/a_1)\ge 0`. The resulting limit is + maximal among all possible values. - - "principal": Use the AGM sequence such that at each stage - `(a,b)` is replaced by `(a_1,b_1)=((a+b)/2,\pm\sqrt{ab})` - where the sign is chosen so that `\Re(b_1)\ge 0` (the - so-called principal branch of the square root). + - ``"principal"``: Use the AGM sequence such that at each stage + `(a,b)` is replaced by `(a_1,b_1)=((a+b)/2,\pm\sqrt{ab})` + where the sign is chosen so that `\Re(b_1)\ge 0` (the + so-called principal branch of the square root). The values `AGM(a,0)`, `AGM(0,a)`, and `AGM(a,-a)` are all taken to be 0. @@ -2590,7 +2538,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): 1.62780548487271 + 0.136827548397369*I sage: a.agm(b, algorithm="principal") 1.62780548487271 + 0.136827548397369*I - sage: a.agm(b, algorithm="pari") + sage: a.agm(b, algorithm="pari") # needs sage.libs.pari 1.62780548487271 + 0.136827548397369*I An example to show that the returned value depends on the algorithm @@ -2602,13 +2550,13 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): -0.371591652351761 + 0.319894660206830*I sage: a.agm(b, algorithm="principal") 0.338175462986180 - 0.0135326969565405*I - sage: a.agm(b, algorithm="pari") + sage: a.agm(b, algorithm="pari") # needs sage.libs.pari -0.371591652351761 + 0.319894660206830*I sage: a.agm(b, algorithm="optimal").abs() 0.490319232466314 sage: a.agm(b, algorithm="principal").abs() 0.338446122230459 - sage: a.agm(b, algorithm="pari").abs() + sage: a.agm(b, algorithm="pari").abs() # needs sage.libs.pari 0.490319232466314 TESTS: @@ -2778,7 +2726,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): def arg(self): """ - See :meth:`argument()`. + See :meth:`argument`. EXAMPLES:: @@ -2825,21 +2773,21 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: sage: a = ComplexNumber(1,0) - sage: a.dilog() + sage: a.dilog() # needs sage.libs.pari 1.64493406684823 - sage: float(pi^2/6) + sage: float(pi^2/6) # needs sage.symbolic 1.6449340668482262 :: sage: b = ComplexNumber(0,1) - sage: b.dilog() + sage: b.dilog() # needs sage.libs.pari -0.205616758356028 + 0.915965594177219*I :: sage: c = ComplexNumber(0,0) - sage: c.dilog() + sage: c.dilog() # needs sage.libs.pari 0.000000000000000 """ return self._parent(self.__pari__().dilog()) @@ -2875,17 +2823,17 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: sage: i = ComplexField(30).0 - sage: (1+i).gamma() + sage: (1 + i).gamma() # needs sage.libs.pari 0.49801567 - 0.15494983*I TESTS:: - sage: CC(0).gamma() + sage: CC(0).gamma() # needs sage.libs.pari Infinity :: - sage: CC(-1).gamma() + sage: CC(-1).gamma() # needs sage.libs.pari Infinity """ try: @@ -2901,6 +2849,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: C, i = ComplexField(30).objgen() sage: (1+i).gamma_inc(2 + 3*i) # abs tol 2e-10 0.0020969149 - 0.059981914*I @@ -2916,7 +2865,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): Check that :trac:`7099` is fixed:: sage: C = ComplexField(400) - sage: C(2 + I).gamma_inc(C(3 + I)) # abs tol 1e-120 + sage: C(2 + I).gamma_inc(C(3 + I)) # abs tol 1e-120 # needs sage.libs.pari 0.121515644664508695525971545977439666159749344176962379708992904126499444842886620664991650378432544392118359044438541515 + 0.101533909079826033296475736021224621546966200987295663190553587086145836461236284668967411665020429964946098113930918850*I """ @@ -2925,8 +2874,8 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): def log(self, base=None): r""" Complex logarithm of `z` with branch chosen as follows: Write - `z = \rho e^{i \theta}` with `-\pi < \theta <= pi`. Then - `\mathrm{log}(z) = \mathrm{log}(\rho) + i \theta`. + `z = \rho e^{i \theta}` with `-\pi < \theta \leq \pi`. Then + `\log(z) = \log(\rho) + i \theta`. .. WARNING:: @@ -3003,7 +2952,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): INPUT: - - ``all`` - bool (default: ``False``); if ``True``, return a + - ``all`` -- bool (default: ``False``); if ``True``, return a list of all square roots. EXAMPLES:: @@ -3072,7 +3021,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): INPUT: - - ``all`` - bool (default: ``False``); if ``True``, return a + - ``all`` -- bool (default: ``False``); if ``True``, return a list of all `n`-th roots. EXAMPLES:: @@ -3081,10 +3030,13 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): sage: a.nth_root(3) 3.00000000000000 sage: a.nth_root(3, all=True) - [3.00000000000000, -1.50000000000000 + 2.59807621135332*I, -1.50000000000000 - 2.59807621135332*I] + [3.00000000000000, + -1.50000000000000 + 2.59807621135332*I, + -1.50000000000000 - 2.59807621135332*I] sage: a = ComplexField(20)(2,1) sage: [r^7 for r in a.nth_root(7, all=True)] - [2.0000 + 1.0000*I, 2.0000 + 1.0000*I, 2.0000 + 1.0000*I, 2.0000 + 1.0000*I, 2.0000 + 1.0000*I, 2.0000 + 1.0001*I, 2.0000 + 1.0001*I] + [2.0000 + 1.0000*I, 2.0000 + 1.0000*I, 2.0000 + 1.0000*I, 2.0000 + 1.0000*I, + 2.0000 + 1.0000*I, 2.0000 + 1.0001*I, 2.0000 + 1.0001*I] """ if self.is_zero(): return [self] if all else self @@ -3144,7 +3096,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): def is_real(self): """ - Return ``True`` if ``self`` is real, i.e. has imaginary part zero. + Return ``True`` if ``self`` is real, i.e., has imaginary part zero. EXAMPLES:: @@ -3157,7 +3109,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): def is_imaginary(self): """ - Return ``True`` if ``self`` is imaginary, i.e. has real part zero. + Return ``True`` if ``self`` is imaginary, i.e., has real part zero. EXAMPLES:: @@ -3170,7 +3122,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): def is_integer(self): """ - Return ``True`` if ``self`` is a integer + Return ``True`` if ``self`` is an integer. EXAMPLES:: @@ -3247,9 +3199,9 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): sage: i = ComplexField(30).gen() sage: z = 1 + i - sage: z.zeta() + sage: z.zeta() # needs sage.libs.pari 0.58215806 - 0.92684856*I - sage: zeta(z) + sage: zeta(z) # needs sage.libs.pari 0.58215806 - 0.92684856*I sage: CC(1).zeta() @@ -3266,8 +3218,8 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): ALGORITHM: Uses the PARI C-library :pari:`algdep` command. - INPUT: Type algdep? at the top level prompt. All additional - parameters are passed onto the top-level algdep command. + INPUT: Type ``algdep?`` at the top level prompt. All additional + parameters are passed onto the top-level :func:`algdep` command. EXAMPLES:: @@ -3466,7 +3418,7 @@ cdef inline mp_exp_t max_exp(ComplexNumber z): cpdef int cmp_abs(ComplexNumber a, ComplexNumber b): """ - Return -1, 0, or 1 according to whether `|a|` is less than, equal to, or + Return `-1`, `0`, or `1` according to whether `|a|` is less than, equal to, or greater than `|b|`. Optimized for non-close numbers, where the ordering can be determined by diff --git a/src/sage/rings/complex_number.pyx b/src/sage/rings/complex_number.pyx deleted file mode 100644 index f2c91d5aaee..00000000000 --- a/src/sage/rings/complex_number.pyx +++ /dev/null @@ -1,14 +0,0 @@ -r""" -Deprecated in favor of :mod:`sage.rings.complex_mpfr` - -TESTS:: - - sage: from sage.rings.complex_number import ComplexNumber - doctest:warning - ... - DeprecationWarning: the complex_number module is deprecated, please use sage.rings.complex_mpfr - See https://github.com/sagemath/sage/issues/24483 for details. -""" -from sage.misc.superseded import deprecation -from sage.rings.complex_mpfr import * -deprecation(24483, "the complex_number module is deprecated, please use sage.rings.complex_mpfr") diff --git a/src/sage/rings/continued_fraction.py b/src/sage/rings/continued_fraction.py index a16137ff609..a3f877e423d 100644 --- a/src/sage/rings/continued_fraction.py +++ b/src/sage/rings/continued_fraction.py @@ -67,13 +67,14 @@ sage: 0 + 1/(2 + 1/22) 22/45 - sage: continued_fraction(pi) + sage: continued_fraction(pi) # needs sage.symbolic [3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, ...] - sage: continued_fraction_list(pi, nterms=5) + sage: continued_fraction_list(pi, nterms=5) # needs sage.symbolic [3, 7, 15, 1, 292] - sage: K.<cbrt5> = NumberField(x^3 - 5, embedding=1.709) - sage: continued_fraction(cbrt5) + sage: x = polygen(ZZ, 'x') + sage: K.<cbrt5> = NumberField(x^3 - 5, embedding=1.709) # needs sage.rings.number_field + sage: continued_fraction(cbrt5) # needs sage.rings.number_field [1; 1, 2, 2, 4, 3, 3, 1, 5, 1, 1, 4, 10, 17, 1, 14, 1, 1, 3052, 1, ...] It is also possible to create a continued fraction from a list of partial @@ -84,10 +85,9 @@ Even infinite:: - sage: w = words.ThueMorseWord([1,2]) - sage: w + sage: w = words.ThueMorseWord([1,2]); w # needs sage.combinat word: 1221211221121221211212211221211221121221... - sage: continued_fraction(w) + sage: continued_fraction(w) # needs sage.combinat [1; 2, 2, 1, 2, 1, 1, 2, 2, 1...] To go back and forth between the value (as a real number) and the partial @@ -100,18 +100,18 @@ sage: cf.value() 13/27 - sage: cf = continued_fraction(pi) - sage: cf.quotients() + sage: cf = continued_fraction(pi) # needs sage.symbolic + sage: cf.quotients() # needs sage.symbolic lazy list [3, 7, 15, ...] - sage: cf.value() + sage: cf.value() # needs sage.symbolic pi + sage: # needs sage.combinat sage: w = words.FibonacciWord([1,2]) sage: cf = continued_fraction(w) sage: cf.quotients() word: 1211212112112121121211211212112112121121... - sage: v = cf.value() - sage: v + sage: v = cf.value(); v 1.387954587967143? sage: v.n(digits=100) 1.387954587967142336919313859873185477878152452498532271894917289826418577622648932169885237034242967 @@ -121,6 +121,7 @@ Recall that quadratic numbers correspond to ultimately periodic continued fractions. For them special methods give access to preperiod and period:: + sage: # needs sage.rings.number_field sage: K.<sqrt2> = QuadraticField(2) sage: cf = continued_fraction(sqrt2); cf [1; (2)*] @@ -131,18 +132,18 @@ sage: cf.period() (2,) - sage: cf = (3*sqrt2 + 1/2).continued_fraction(); cf + sage: cf = (3*sqrt2 + 1/2).continued_fraction(); cf # needs sage.rings.number_field [4; (1, 2, 1, 7)*] sage: cf = continued_fraction([(1,2,3),(1,4)]); cf [1; 2, 3, (1, 4)*] - sage: cf.value() + sage: cf.value() # needs sage.rings.number_field -2/23*sqrt2 + 36/23 On the following we can remark how the tail may change even in the same quadratic field:: - sage: for i in range(20): print(continued_fraction(i*sqrt2)) + sage: for i in range(20): print(continued_fraction(i*sqrt2)) # needs sage.rings.number_field [0] [1; (2)*] [2; (1, 4)*] @@ -156,6 +157,7 @@ Nevertheless, the tail is preserved under invertible integer homographies:: + sage: # needs sage.rings.number_field sage: apply_homography = lambda m,z: (m[0,0]*z + m[0,1]) / (m[1,0]*z + m[1,1]) sage: m1 = SL2Z([60,13,83,18]) sage: m2 = SL2Z([27,80,28,83]) @@ -263,7 +265,7 @@ def rat_interval_cf_list(r1, r2): sage: from sage.rings.continued_fraction import rat_interval_cf_list sage: rat_interval_cf_list(257/113, 5224/2297) [2, 3, 1, 1, 1, 4] - sage: for prec in range(10,54): + sage: for prec in range(10,54): # needs sage.rings.real_interval_field ....: R = RealIntervalField(prec) ....: for _ in range(100): ....: x = R.random_element() * R.random_element() + R.random_element() / 100 @@ -360,7 +362,7 @@ def str(self, nterms=10, unicode=False, join=True): EXAMPLES:: - sage: print(continued_fraction(pi).str()) + sage: print(continued_fraction(pi).str()) # needs sage.symbolic 1 3 + ---------------------------------------------------- 1 @@ -380,9 +382,9 @@ def str(self, nterms=10, unicode=False, join=True): 1 2 + --------- 1 + ... - sage: print(continued_fraction(pi).str(nterms=1)) + sage: print(continued_fraction(pi).str(nterms=1)) # needs sage.symbolic 3 + ... - sage: print(continued_fraction(pi).str(nterms=2)) + sage: print(continued_fraction(pi).str(nterms=2)) # needs sage.symbolic 1 3 + --------- 7 + ... @@ -504,8 +506,8 @@ def _latex_(self, nterms=10): r""" EXAMPLES:: - sage: cf_pi = continued_fraction(pi) - sage: latex(cf_pi) + sage: cf_pi = continued_fraction(pi) # needs sage.symbolic + sage: latex(cf_pi) # needs sage.symbolic 3 + \frac{\displaystyle 1}{\displaystyle 7 + \frac{\displaystyle 1}{\displaystyle 15 @@ -517,7 +519,7 @@ def _latex_(self, nterms=10): + \frac{\displaystyle 1}{\displaystyle 2 + \frac{\displaystyle 1}{\displaystyle 1 + \frac{\displaystyle 1}{\displaystyle \dots}}}}}}}}}} - sage: print(cf_pi._latex_(nterms=3)) + sage: print(cf_pi._latex_(nterms=3)) # needs sage.symbolic 3 + \frac{\displaystyle 1}{\displaystyle 7 + \frac{\displaystyle 1}{\displaystyle 15 @@ -593,18 +595,19 @@ def _mpfr_(self, R): EXAMPLES:: - sage: continued_fraction(1/2).n() + sage: continued_fraction(1/2).n() # needs sage.rings.real_mpfr 0.500000000000000 - sage: continued_fraction([0,4]).n() + sage: continued_fraction([0,4]).n() # needs sage.rings.real_mpfr 0.250000000000000 - sage: continued_fraction([12,1,3,4,2,2,3,1,2]).n(digits=4) + sage: continued_fraction([12,1,3,4,2,2,3,1,2]).n(digits=4) # needs sage.rings.real_mpfr 12.76 - sage: continued_fraction(12/7).n(digits=13) == (12/7).n(digits=13) + sage: continued_fraction(12/7).n(digits=13) == (12/7).n(digits=13) # needs sage.rings.real_mpfr True - sage: continued_fraction(-14/333).n(digits=21) == (-14/333).n(digits=21) + sage: continued_fraction(-14/333).n(digits=21) == (-14/333).n(digits=21) # needs sage.rings.real_mpfr True + sage: # needs sage.symbolic sage: a = (106*pi - 333) / (355 - 113*pi) - 292 sage: cf = continued_fraction(a); cf [0; 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, 1, 84, 2, 1, ...] @@ -621,7 +624,9 @@ def _mpfr_(self, R): sage: cf.n(digits=8) 0.63459101 - sage: K.<a> = NumberField(x^3-2, 'a', embedding=1.25) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2, 'a', embedding=1.25) sage: b = 504/253*a^2 + 635/253*a + 661/253 sage: cf = continued_fraction(b); cf [8; 1, 14, 1, 10, 2, 1, 4, 12, 2, 3, 2, 1, 3, 4, 1, 1, 2, 14, 3, ...] @@ -646,7 +651,7 @@ def _mpfr_(self, R): rational case):: sage: fields = [] - sage: for prec in [17, 24, 53, 128, 256]: + sage: for prec in [17, 24, 53, 128, 256]: # needs sage.rings.real_mpfr ....: for rnd in ['RNDN', 'RNDD', 'RNDU', 'RNDZ', 'RNDA']: ....: fields.append(RealField(prec=prec, rnd=rnd)) sage: for n in range(3000): # long time, not tested, known bug (see :trac:`29957`) @@ -743,7 +748,7 @@ def __float__(self): sage: a = continued_fraction(-17/389); a [-1; 1, 21, 1, 7, 2] - sage: float(a) + sage: float(a) # needs sage.rings.real_mpfr -0.043701799485861184 sage: float(-17/389) -0.043701799485861184 @@ -757,6 +762,7 @@ def numerator(self, n): EXAMPLES:: + sage: # needs sage.symbolic sage: c = continued_fraction(pi); c [3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, ...] sage: c.numerator(0) @@ -791,6 +797,7 @@ def denominator(self, n): EXAMPLES:: + sage: # needs sage.symbolic sage: c = continued_fraction(pi); c [3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, ...] sage: c.denominator(0) @@ -813,11 +820,11 @@ def convergent(self, n): EXAMPLES:: - sage: a = continued_fraction(pi); a + sage: a = continued_fraction(pi); a # needs sage.symbolic [3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, ...] - sage: a.convergent(3) + sage: a.convergent(3) # needs sage.symbolic 355/113 - sage: a.convergent(15) + sage: a.convergent(15) # needs sage.symbolic 411557987/131002976 """ return self.numerator(n) / self.denominator(n) @@ -881,15 +888,15 @@ def __getitem__(self, n): TESTS:: - sage: cf1 = continued_fraction(pi); cf1 + sage: cf1 = continued_fraction(pi); cf1 # needs sage.symbolic [3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, ...] - sage: cf2 = continued_fraction(QuadraticField(2).gen()); cf2 + sage: cf2 = continued_fraction(QuadraticField(2).gen()); cf2 # needs sage.rings.number_field [1; (2)*] sage: cf3 = continued_fraction(4/17); cf3 [0; 4, 4] - sage: cf1[3:17] + sage: cf1[3:17] # needs sage.symbolic [1; 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2] - sage: cf2[:10] + sage: cf2[:10] # needs sage.rings.number_field [1; 2, 2, 2, 2, 2, 2, 2, 2, 2] sage: cf3[1:16] [4; 4] @@ -897,7 +904,7 @@ def __getitem__(self, n): Be careful that the truncation of an infinite continued fraction might be shorter by one:: - sage: len(continued_fraction(golden_ratio)[:8]) + sage: len(continued_fraction(golden_ratio)[:8]) # needs sage.symbolic 7 """ if isinstance(n, slice): @@ -924,6 +931,7 @@ def __iter__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: cf = continued_fraction(pi) sage: i = iter(cf) sage: [next(i) for _ in range(10)] @@ -962,7 +970,7 @@ def sign(self): EXAMPLES:: - sage: continued_fraction(tan(pi/7)).sign() + sage: continued_fraction(tan(pi/7)).sign() # needs sage.symbolic 1 sage: continued_fraction(-34/2115).sign() -1 @@ -1018,8 +1026,6 @@ def __bool__(self): """ return bool(self.quotient(0)) or self.quotient(1) is not Infinity - - def is_zero(self): r""" Test whether ``self`` is zero. @@ -1032,7 +1038,7 @@ def is_zero(self): False sage: continued_fraction(-1/2).is_zero() False - sage: continued_fraction(pi).is_zero() + sage: continued_fraction(pi).is_zero() # needs sage.symbolic False """ return self.quotient(0) == ZZ_0 and self.quotient(1) is Infinity @@ -1049,7 +1055,7 @@ def is_one(self): False sage: continued_fraction(0).is_one() False - sage: continued_fraction(pi).is_one() + sage: continued_fraction(pi).is_one() # needs sage.symbolic False """ return self.quotient(0) == ZZ_1 and self.quotient(1) is Infinity @@ -1098,7 +1104,7 @@ def multiplicative_order(self): 2 sage: continued_fraction(1).multiplicative_order() 1 - sage: continued_fraction(pi).multiplicative_order() + sage: continued_fraction(pi).multiplicative_order() # needs sage.symbolic +Infinity """ if self.is_zero(): @@ -1128,18 +1134,17 @@ def numerical_approx(self, prec=None, digits=None, algorithm=None): EXAMPLES:: - sage: w = words.FibonacciWord([1,3]) - sage: cf = continued_fraction(w) - sage: cf + sage: w = words.FibonacciWord([1,3]) # needs sage.combinat + sage: cf = continued_fraction(w); cf # needs sage.combinat [1; 3, 1, 1, 3, 1, 3, 1, 1, 3, 1, 1, 3, 1, 3, 1, 1, 3, 1, 3...] - sage: cf.numerical_approx(prec=53) + sage: cf.numerical_approx(prec=53) # needs sage.combinat 1.28102513329557 The method `n` is a shortcut to this one:: - sage: cf.n(digits=25) + sage: cf.n(digits=25) # needs sage.combinat 1.281025133295569815552930 - sage: cf.n(digits=33) + sage: cf.n(digits=33) # needs sage.combinat 1.28102513329556981555293038097590 """ from sage.arith.numerical_approx import (digits_to_bits, @@ -1174,22 +1179,20 @@ def apply_homography(self, a, b, c, d, forward_value=False): We demonstrate now the effect of the optional argument ``forward_value``:: - sage: cf = continued_fraction(pi) - sage: h1 = cf.apply_homography(35, -27, 12, -5) - sage: h1 + sage: cf = continued_fraction(pi) # needs sage.symbolic + sage: h1 = cf.apply_homography(35, -27, 12, -5); h1 # needs sage.symbolic [2; 1, 1, 6, 3, 1, 2, 1, 5, 3, 1, 1, 1, 1, 9, 12, 1, 1, 1, 3...] - sage: h1.value() + sage: h1.value() # needs sage.symbolic 2.536941776086946? - sage: h2 = cf.apply_homography(35, -27, 12, -5, forward_value=True) - sage: h2 + sage: h2 = cf.apply_homography(35, -27, 12, -5, forward_value=True); h2 # needs sage.symbolic [2; 1, 1, 6, 3, 1, 2, 1, 5, 3, 1, 1, 1, 1, 9, 12, 1, 1, 1, 3...] - sage: h2.value() + sage: h2.value() # needs sage.symbolic (35*pi - 27)/(12*pi - 5) TESTS:: - sage: CF = [continued_fraction(x) for x in [sqrt(2), AA(3).sqrt(), + sage: CF = [continued_fraction(x) for x in [sqrt(2), AA(3).sqrt(), # needs sage.rings.number_field sage.symbolic ....: AA(3)**(1/3), QuadraticField(37).gen(), pi, 113/27, ....: [3,1,2,2], words.FibonacciWord([1,3])]] sage: for _ in range(100): # not tested, known bug (see :trac:`32086`) @@ -1211,7 +1214,7 @@ def apply_homography(self, a, b, c, d, forward_value=False): ... ValueError: continued fraction can not represent infinity - sage: continued_fraction(pi).apply_homography(0, 1, 0, 0) + sage: continued_fraction(pi).apply_homography(0, 1, 0, 0) # needs sage.symbolic Traceback (most recent call last): ... ZeroDivisionError: division by zero @@ -1262,9 +1265,9 @@ def __neg__(self): EXAMPLES:: - sage: -continued_fraction(e) + sage: -continued_fraction(e) # needs sage.symbolic [-3; 3, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10, 1, 1, 12, 1, 1, 14...] - sage: -continued_fraction(sqrt(7)) + sage: -continued_fraction(sqrt(7)) # needs sage.symbolic [-3; 2, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4...] """ return self.apply_homography(-1, 0, 0, 1) @@ -1275,9 +1278,9 @@ def __invert__(self): EXAMPLES:: - sage: ~continued_fraction(e) + sage: ~continued_fraction(e) # needs sage.symbolic [0; 2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10, 1, 1, 12, 1...] - sage: ~continued_fraction(sqrt(7)) + sage: ~continued_fraction(sqrt(7)) # needs sage.symbolic [0; 2, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1...] """ return self.apply_homography(0, 1, 1, 0) @@ -1327,12 +1330,12 @@ def period(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<sqrt3> = QuadraticField(3) sage: cf = continued_fraction(sqrt3); cf [1; (1, 2)*] sage: cf.period() (1, 2) - sage: for k in xsrange(2,40): ....: if not k.is_square(): ....: s = QuadraticField(k).gen() @@ -1365,12 +1368,12 @@ def preperiod(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<sqrt3> = QuadraticField(3) sage: cf = continued_fraction(sqrt3); cf [1; (1, 2)*] sage: cf.preperiod() (1,) - sage: cf = continued_fraction(sqrt3/7); cf [0; 4, (24, 8)*] sage: cf.preperiod() @@ -1448,6 +1451,7 @@ def __richcmp__(self, other, op): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: a = continued_fraction([(0,),(1,2,3,1,2,3,1)]); a.n() 0.694249167819459 sage: b = continued_fraction([(0,),(1,2,3)]); b.n() @@ -1492,49 +1496,49 @@ def value(self): sage: cf = continued_fraction([(),(2,)]); cf [(2)*] - sage: v = cf.value(); v + sage: v = cf.value(); v # needs sage.rings.number_field sqrt2 + 1 - sage: v.continued_fraction() + sage: v.continued_fraction() # needs sage.rings.number_field [(2)*] sage: cf = continued_fraction([(),(1,2)]); cf [(1, 2)*] - sage: v = cf.value(); v + sage: v = cf.value(); v # needs sage.rings.number_field 1/2*sqrt3 + 1/2 - sage: v.continued_fraction() + sage: v.continued_fraction() # needs sage.rings.number_field [(1, 2)*] The number ``sqrt3`` that appear above is actually internal to the continued fraction. In order to be access it from the console:: - sage: cf.value().parent().inject_variables() + sage: cf.value().parent().inject_variables() # needs sage.rings.number_field Defining sqrt3 - sage: sqrt3 + sage: sqrt3 # needs sage.rings.number_field sqrt3 - sage: ((sqrt3+1)/2).continued_fraction() + sage: ((sqrt3+1)/2).continued_fraction() # needs sage.rings.number_field [(1, 2)*] Some ultimately periodic but non periodic examples:: sage: cf = continued_fraction([(1,),(2,)]); cf [1; (2)*] - sage: v = cf.value(); v + sage: v = cf.value(); v # needs sage.rings.number_field sqrt2 - sage: v.continued_fraction() + sage: v.continued_fraction() # needs sage.rings.number_field [1; (2)*] sage: cf = continued_fraction([(1,3),(1,2)]); cf [1; 3, (1, 2)*] - sage: v = cf.value(); v + sage: v = cf.value(); v # needs sage.rings.number_field -sqrt3 + 3 - sage: v.continued_fraction() + sage: v.continued_fraction() # needs sage.rings.number_field [1; 3, (1, 2)*] sage: cf = continued_fraction([(-5,18), (1,3,1,5)]) - sage: cf.value().continued_fraction() == cf + sage: cf.value().continued_fraction() == cf # needs sage.rings.number_field True sage: cf = continued_fraction([(-1,),(1,)]) - sage: cf.value().continued_fraction() == cf + sage: cf.value().continued_fraction() == cf # needs sage.rings.number_field True TESTS:: @@ -1544,7 +1548,7 @@ def value(self): sage: a3 = ((1,),(1,2)) sage: a4 = ((-2,2),(1,124,13)) sage: a5 = ((0,),(1,)) - sage: for a in a1,a2,a3,a4,a5: + sage: for a in a1,a2,a3,a4,a5: # needs sage.rings.number_field ....: cf = continued_fraction(a) ....: assert cf.value().continued_fraction() == cf """ @@ -1575,10 +1579,10 @@ def _repr_(self): r""" TESTS:: - sage: a = continued_fraction(pi.n()); a + sage: a = continued_fraction(pi.n()); a # needs sage.symbolic [3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 3] - sage: a.rename('continued fraction of pi') - sage: a + sage: a.rename('continued fraction of pi') # needs sage.symbolic + sage: a # needs sage.symbolic continued fraction of pi sage: continued_fraction([(0,1),(2,)]) @@ -1656,10 +1660,10 @@ def _latex_(self): + \frac{\displaystyle 1}{\displaystyle 7 + \frac{\displaystyle 1}{\displaystyle 2 }}}}} - sage: K.<a> = QuadraticField(1234) - sage: cf=continued_fraction(a); cf + sage: K.<a> = QuadraticField(1234) # needs sage.rings.number_field + sage: cf = continued_fraction(a); cf # needs sage.rings.number_field [35; (7, 1, 3, 1, 4, 4, 2, 9, 1, 1, 2, 3, 1, 1, 34, 1, 1, 3, 2, 1, 1, 9, 2, 4, 4, 1, 3, 1, 7, 70)*] - sage: latex(cf) + sage: latex(cf) # needs sage.rings.number_field 35 + \frac{\displaystyle 1}{\displaystyle 7 + \frac{\displaystyle 1}{\displaystyle 1 @@ -1701,6 +1705,7 @@ def __invert__(self): sage: a.value() * (~a).value() 1 + sage: # needs sage.rings.number_field sage: K.<sqrt5> = QuadraticField(5) sage: a1 = (sqrt5+1)/2 sage: c1 = a1.continued_fraction(); c1 @@ -1710,9 +1715,9 @@ def __invert__(self): sage: c1.value() * (~c1).value() 1 - sage: c2 = (sqrt5/3 + 1/7).continued_fraction(); c2 + sage: c2 = (sqrt5/3 + 1/7).continued_fraction(); c2 # needs sage.rings.number_field [0; 1, (7, 1, 17, ..., 1, 2)*] - sage: c2.value() * (~c2).value() + sage: c2.value() * (~c2).value() # needs sage.rings.number_field 1 """ if not self: @@ -1744,7 +1749,7 @@ def __neg__(self): sage: quots2 = [((),(1,)), ((), (1,2)), ((0,),(1,)), ....: ((),(2,1)), ((3,),(2,1))] - sage: for q in quots2: + sage: for q in quots2: # needs sage.rings.number_field ....: cf = continued_fraction(q) ....: ncf = -cf ....: nncf = -ncf @@ -1795,16 +1800,14 @@ class ContinuedFraction_real(ContinuedFraction_base): EXAMPLES:: - sage: cf = continued_fraction(pi) - sage: cf + sage: cf = continued_fraction(pi); cf # needs sage.symbolic [3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, ...] - sage: cf.value() + sage: cf.value() # needs sage.symbolic pi - sage: cf = continued_fraction(e) - sage: cf + sage: cf = continued_fraction(e); cf # needs sage.symbolic [2; 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10, 1, 1, 12, 1, 1, ...] - sage: cf.value() + sage: cf.value() # needs sage.symbolic e """ def __init__(self, x): @@ -1815,7 +1818,7 @@ def __init__(self, x): TESTS:: - sage: TestSuite(continued_fraction(pi)).run() + sage: TestSuite(continued_fraction(pi)).run() # needs sage.symbolic """ ContinuedFraction_base.__init__(self) self._x0 = x @@ -1833,7 +1836,7 @@ def length(self): EXAMPLES:: - sage: continued_fraction(pi).length() + sage: continued_fraction(pi).length() # needs sage.symbolic +Infinity """ return Infinity @@ -1842,7 +1845,7 @@ def __len__(self): r""" TESTS:: - sage: len(continued_fraction(pi)) + sage: len(continued_fraction(pi)) # needs sage.symbolic Traceback (most recent call last): ... ValueError: the length is infinite! @@ -1855,9 +1858,9 @@ def __richcmp__(self, other, op): EXAMPLES:: - sage: continued_fraction(pi) > continued_fraction(e) + sage: continued_fraction(pi) > continued_fraction(e) # needs sage.symbolic True - sage: continued_fraction(pi) > continued_fraction(e+4) + sage: continued_fraction(pi) > continued_fraction(e+4) # needs sage.symbolic False """ try: @@ -1875,7 +1878,7 @@ def _repr_(self): EXAMPLES:: - sage: continued_fraction(pi) # indirect doctest + sage: continued_fraction(pi) # indirect doctest # needs sage.symbolic [3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, ...] """ return '[%d; ' % self.quotient(0) + ', '.join(str(self.quotient(i)) for i in range(1, 20)) + ", ...]" @@ -1886,12 +1889,13 @@ def quotient(self, n): EXAMPLES:: + sage: # needs sage.symbolic sage: cf = continued_fraction(pi) sage: cf.quotient(27) 13 sage: cf.quotient(2552) 152 - sage: cf.quotient(10000) # long time + sage: cf.quotient(10000) # long time 5 The algorithm is not efficient with element of the symbolic ring and, @@ -1900,6 +1904,7 @@ def quotient(self, n): evaluate in ``RIF`` an expression of the form ``(a*x+b)/(c*x+d)`` where both the numerator and the denominator are extremely small:: + sage: # needs sage.symbolic sage: a1 = pi sage: c1 = continued_fraction(a1) sage: p0 = c1.numerator(12); q0 = c1.denominator(12) @@ -1915,6 +1920,8 @@ def quotient(self, n): The same computation with an element of a number field instead of ``pi`` gives a very satisfactory answer:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a2> = NumberField(x^3 - 2, embedding=1.25) sage: c2 = continued_fraction(a2) sage: p0 = c2.numerator(111); q0 = c2.denominator(111) @@ -1932,6 +1939,7 @@ def quotient(self, n): The consequence is that the precision needed with ``c1`` grows when we compute larger and larger partial quotients:: + sage: # needs sage.symbolic sage: c1.quotient(100) 2 sage: c1._xa.parent() @@ -1945,6 +1953,7 @@ def quotient(self, n): sage: c1._xa.parent() Real Interval Field with 1053 bits of precision + sage: # needs sage.rings.number_field sage: c2.quotient(200) 6 sage: c2._xa.parent() @@ -1994,8 +2003,8 @@ def value(self): EXAMPLES:: - sage: cf = continued_fraction(e) - sage: cf.value() + sage: cf = continued_fraction(e) # needs sage.symbolic + sage: cf.value() # needs sage.symbolic e """ return self._x0 @@ -2007,16 +2016,16 @@ class ContinuedFraction_infinite(ContinuedFraction_base): EXAMPLES:: - sage: t = continued_fraction(words.ThueMorseWord([1,2])); t + sage: t = continued_fraction(words.ThueMorseWord([1,2])); t # needs sage.combinat [1; 2, 2, 1, 2, 1, 1, 2, 2, 1...] - sage: t.n(digits=100) + sage: t.n(digits=100) # needs sage.combinat 1.422388736882785488341547116024565825306879108991711829311892452916456747272565883312455412962072042 We check that comparisons work well:: - sage: t > continued_fraction(1) and t < continued_fraction(3/2) + sage: t > continued_fraction(1) and t < continued_fraction(3/2) # needs sage.combinat True - sage: t < continued_fraction(1) or t > continued_fraction(2) + sage: t < continued_fraction(1) or t > continued_fraction(2) # needs sage.combinat False Can also be called with a ``value`` option:: @@ -2024,16 +2033,14 @@ class ContinuedFraction_infinite(ContinuedFraction_base): sage: def f(n): ....: if n % 3 == 2: return 2*(n+1)//3 ....: return 1 - sage: w = Word(f, alphabet=NN) - sage: w + sage: w = Word(f, alphabet=NN); w # needs sage.combinat word: 1,1,2,1,1,4,1,1,6,1,1,8,1,1,10,1,1,12,1,1,14,1,1,16,1,1,18,1,1,20,1,1,22,1,1,24,1,1,26,1,... - sage: cf = continued_fraction(w, value=e-1) - sage: cf + sage: cf = continued_fraction(w, value=e-1); cf # needs sage.combinat sage.symbolic [1; 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10, 1, 1, 12, 1, 1...] In that case a small check is done on the input:: - sage: cf = continued_fraction(w, value=pi) + sage: cf = continued_fraction(w, value=pi) # needs sage.combinat sage.symbolic Traceback (most recent call last): ... ValueError: value evaluates to 3.141592653589794? while the continued @@ -2055,32 +2062,32 @@ def __init__(self, w, value=None, check=True): TESTS:: - sage: w = words.FibonacciWord(['a','b']) - sage: continued_fraction(w) + sage: w = words.FibonacciWord(['a','b']) # needs sage.combinat + sage: continued_fraction(w) # needs sage.combinat Traceback (most recent call last): ... ValueError: the sequence must consist of integers sage: from itertools import count - sage: w = Word(count(), length="infinite") - sage: continued_fraction(w) + sage: w = Word(count(), length="infinite") # needs sage.combinat + sage: continued_fraction(w) # needs sage.combinat [0; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19...] - sage: w = Word(count(), length="unknown") - sage: continued_fraction(w) + sage: w = Word(count(), length="unknown") # needs sage.combinat + sage: continued_fraction(w) # needs sage.combinat Traceback (most recent call last): ... ValueError: word with unknown length cannot be converted to continued fractions - sage: continued_fraction(words.FibonacciWord([0,1])) + sage: continued_fraction(words.FibonacciWord([0,1])) # needs sage.combinat Traceback (most recent call last): ... ValueError: only the first partial quotient can be null - sage: w = words.ThueMorseWord([int(1), int(2)]) - sage: t = continued_fraction(w) - sage: type(t.quotient(1)) + sage: w = words.ThueMorseWord([int(1), int(2)]) # needs sage.combinat + sage: t = continued_fraction(w) # needs sage.combinat + sage: type(t.quotient(1)) # needs sage.combinat <class 'sage.rings.integer.Integer'> """ ContinuedFraction_base.__init__(self) @@ -2117,8 +2124,8 @@ def _repr_(self): EXAMPLES:: - sage: w = words.FibonacciWord([3,13]) - sage: cf = continued_fraction(w); cf + sage: w = words.FibonacciWord([3,13]) # needs sage.combinat + sage: cf = continued_fraction(w); cf # needs sage.combinat [3; 13, 3, 3, 13, 3, 13, 3, 3, 13, 3, 3, 13, 3, 13, 3, 3, 13, 3, 13...] """ return "[" + str(self._w[0]) + "; " + ", ".join(map(str, self._w[1:20])) + "...]" @@ -2129,9 +2136,9 @@ def length(self): EXAMPLES:: - sage: w = words.FibonacciWord([3,13]) - sage: cf = continued_fraction(w) - sage: cf.length() + sage: w = words.FibonacciWord([3,13]) # needs sage.combinat + sage: cf = continued_fraction(w) # needs sage.combinat + sage: cf.length() # needs sage.combinat +Infinity """ return Infinity @@ -2146,6 +2153,7 @@ def quotient(self, n): EXAMPLES:: + sage: # needs sage.combinat sage: w = words.FibonacciWord([1,3]) sage: cf = continued_fraction(w) sage: cf.quotient(0) @@ -2163,9 +2171,9 @@ def quotients(self): EXAMPLES:: - sage: w = words.FibonacciWord([1,5]) - sage: cf = continued_fraction(w) - sage: cf.quotients() + sage: w = words.FibonacciWord([1,5]) # needs sage.combinat + sage: cf = continued_fraction(w) # needs sage.combinat + sage: cf.quotients() # needs sage.combinat word: 1511515115115151151511511515115115151151... """ return self._w @@ -2180,6 +2188,7 @@ def _Integer_quotient(self, n): EXAMPLES:: + sage: # needs sage.combinat sage: w = words.ThueMorseWord([int(1), int(2)]) sage: t = continued_fraction(w) sage: t.quotient(0) @@ -2203,20 +2212,17 @@ def value(self): sage: def f(n): ....: if n % 3 == 2: return 2*(n+1)//3 ....: return 1 - sage: w = Word(f, alphabet=NN) - sage: w + sage: w = Word(f, alphabet=NN); w # needs sage.combinat word: 1,1,2,1,1,4,1,1,6,1,1,8,1,1,10,1,1,12,1,1,14,1,1,16,1,1,18,1,1,20,1,1,22,1,1,24,1,1,26,1,... - sage: cf = continued_fraction(w, value=e-1) - sage: cf + sage: cf = continued_fraction(w, value=e-1); cf # needs sage.combinat sage.symbolic [1; 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10, 1, 1, 12, 1, 1...] - sage: cf.value() + sage: cf.value() # needs sage.combinat sage.symbolic e - 1 - sage: w = words.FibonacciWord([2,5]) - sage: cf = continued_fraction(w) - sage: cf + sage: w = words.FibonacciWord([2,5]) # needs sage.combinat + sage: cf = continued_fraction(w); cf # needs sage.combinat [2; 5, 2, 2, 5, 2, 5, 2, 2, 5, 2, 2, 5, 2, 5, 2, 2, 5, 2, 5...] - sage: cf.value() + sage: cf.value() # needs sage.combinat 2.184951302409338? """ if self._value is not None: @@ -2233,12 +2239,12 @@ def __neg__(self): EXAMPLES:: - sage: -continued_fraction(words.FibonacciWord([2,5])) + sage: -continued_fraction(words.FibonacciWord([2,5])) # needs sage.combinat [-3; 1, 4, 2, 2, 5, 2, 5, 2, 2, 5, 2, 2, 5, 2, 5, 2, 2, 5, 2...] sage: from sage.misc.lazy_list import lazy_list sage: l = lazy_list(lambda n: (n**2)%17) - sage: -continued_fraction(l) + sage: -continued_fraction(l) # needs sage.combinat [-1; 5, 9, 16, 8, 2, 15, 13, 13, 15, 2, 8, 16, 9, 4, 1, 0, 1, 4, 9...] """ from sage.combinat.words.word import Word @@ -2373,20 +2379,20 @@ def continued_fraction_list(x, type="std", partial_convergents=False, sage: 2 + 1/(2 + 1/(1 + 1/(2 + 1/2))) 45/19 - sage: continued_fraction_list(45/19,type="hj") + sage: continued_fraction_list(45/19, type="hj") [3, 2, 3, 2, 3] sage: 3 - 1/(2 - 1/(3 - 1/(2 - 1/3))) 45/19 Specifying ``bits`` or ``nterms`` modify the length of the output:: + sage: # needs sage.symbolic sage: continued_fraction_list(e, bits=20) [2, 1, 2, 1, 1, 4, 2] - sage: continued_fraction_list(sqrt(2)+sqrt(3), bits=30) + sage: continued_fraction_list(sqrt(2) + sqrt(3), bits=30) [3, 6, 1, 5, 7, 2] sage: continued_fraction_list(pi, bits=53) [3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14] - sage: continued_fraction_list(log(3/2), nterms=15) [0, 2, 2, 6, 1, 11, 2, 1, 2, 2, 1, 4, 3, 1, 1] sage: continued_fraction_list(tan(sqrt(pi)), nterms=20) @@ -2396,16 +2402,18 @@ def continued_fraction_list(x, type="std", partial_convergents=False, and the parameters ``bits`` and ``nterms`` are not specified then a warning is raised:: - sage: continued_fraction_list(sqrt(2)) - doctest:...: UserWarning: the continued fraction of sqrt(2) seems infinite, return only the first 20 terms + sage: continued_fraction_list(sqrt(2)) # needs sage.symbolic + doctest:...: UserWarning: the continued fraction of sqrt(2) seems infinite, + return only the first 20 terms [1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] - sage: continued_fraction_list(sqrt(4/19)) - doctest:...: UserWarning: the continued fraction of 2*sqrt(1/19) seems infinite, return only the first 20 terms + sage: continued_fraction_list(sqrt(4/19)) # needs sage.symbolic + doctest:...: UserWarning: the continued fraction of 2*sqrt(1/19) seems infinite, + return only the first 20 terms [0, 2, 5, 1, 1, 2, 1, 16, 1, 2, 1, 1, 5, 4, 5, 1, 1, 2, 1, 16] An examples with the list of partial convergents:: - sage: continued_fraction_list(RR(pi), partial_convergents=True) + sage: continued_fraction_list(RR(pi), partial_convergents=True) # needs sage.symbolic ([3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 3], [(3, 1), (22, 7), @@ -2426,24 +2434,24 @@ def continued_fraction_list(x, type="std", partial_convergents=False, sage: continued_fraction_list(1 + 10^-10, nterms=3) [1, 10000000000] - sage: continued_fraction_list(1 + 10^-20 - e^-100, nterms=3) + sage: continued_fraction_list(1 + 10^-20 - e^-100, nterms=3) # needs sage.symbolic [1, 100000000000000000000, 2688] - sage: continued_fraction_list(1 + 10^-20 - e^-100, nterms=5) + sage: continued_fraction_list(1 + 10^-20 - e^-100, nterms=5) # needs sage.symbolic [1, 100000000000000000000, 2688, 8, 1] - sage: continued_fraction_list(1 + 10^-20 - e^-100, nterms=5) + sage: continued_fraction_list(1 + 10^-20 - e^-100, nterms=5) # needs sage.symbolic [1, 100000000000000000000, 2688, 8, 1] Fixed :trac:`18901`:: sage: a = 1.575709393346379 - sage: type(a) + sage: type(a) # needs sage.rings.real_mpfr <class 'sage.rings.real_mpfr.RealLiteral'> sage: continued_fraction_list(a) [1, 1, 1, 2, 1, 4, 18, 1, 5, 2, 25037802, 7, 1, 3, 1, 28, 1, 8, 2] Check that this works for arb elements (:trac:`20069`):: - sage: continued_fraction(RBF(e)) + sage: continued_fraction(RBF(e)) # needs sage.symbolic [2; 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10, 1, 1, 12] """ from .rational_field import QQ @@ -2515,13 +2523,13 @@ def continued_fraction_list(x, type="std", partial_convergents=False, def continued_fraction(x, value=None): r""" - Return the continued fraction of ``x``. + Return the continued fraction of `x`. INPUT: - - `x` -- a number or a list of partial quotients (for finite - development) or two list of partial quotients (preperiod and period - for ultimately periodic development) + - ``x`` -- a number or a list of partial quotients (for finite + development) or two list of partial quotients (preperiod and period + for ultimately periodic development) EXAMPLES: @@ -2536,13 +2544,14 @@ def continued_fraction(x, value=None): It can be called with elements defined from symbolic values, in which case the partial quotients are evaluated in a lazy way:: - sage: c = continued_fraction(golden_ratio); c + sage: c = continued_fraction(golden_ratio); c # needs sage.symbolic [1; 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...] - sage: c.convergent(12) + sage: c.convergent(12) # needs sage.symbolic 377/233 - sage: fibonacci(14)/fibonacci(13) + sage: fibonacci(14)/fibonacci(13) # needs sage.libs.pari 377/233 + sage: # needs sage.symbolic sage: continued_fraction(pi) [3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, ...] sage: c = continued_fraction(pi); c @@ -2554,6 +2563,7 @@ def continued_fraction(x, value=None): sage: pi.n() 3.14159265358979 + sage: # needs sage.symbolic sage: continued_fraction(sqrt(2)) [1; 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ...] sage: continued_fraction(tan(1)) @@ -2567,7 +2577,9 @@ def continued_fraction(x, value=None): ``sqrt(2)`` above), it is much more convenient to use number fields as follows since preperiods and periods are computed:: - sage: K.<sqrt5> = NumberField(x^2-5, embedding=2.23) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<sqrt5> = NumberField(x^2 - 5, embedding=2.23) sage: my_golden_ratio = (1 + sqrt5)/2 sage: cf = continued_fraction((1+sqrt5)/2); cf [(1)*] @@ -2582,7 +2594,8 @@ def continued_fraction(x, value=None): sage: cf.period() (1, 3, 1, 1, 3, 9) - sage: L.<sqrt2> = NumberField(x^2-2, embedding=1.41) + sage: # needs sage.rings.number_field + sage: L.<sqrt2> = NumberField(x^2 - 2, embedding=1.41) sage: cf = continued_fraction(sqrt2); cf [1; (2)*] sage: cf.period() @@ -2596,22 +2609,22 @@ def continued_fraction(x, value=None): continued fraction from its preperiod and its period and get its value back:: - sage: cf = continued_fraction([(1,1),(2,8)]); cf + sage: cf = continued_fraction([(1,1), (2,8)]); cf [1; 1, (2, 8)*] - sage: cf.value() + sage: cf.value() # needs sage.rings.number_field 2/11*sqrt5 + 14/11 It is possible to deal with higher degree number fields but in that case the continued fraction expansion is known to be aperiodic:: - sage: K.<a> = NumberField(x^3-2, embedding=1.25) - sage: cf = continued_fraction(a); cf + sage: K.<a> = NumberField(x^3 - 2, embedding=1.25) # needs sage.rings.number_field + sage: cf = continued_fraction(a); cf # needs sage.rings.number_field [1; 3, 1, 5, 1, 1, 4, 1, 1, 8, 1, 14, 1, 10, 2, 1, 4, 12, 2, 3, ...] Note that initial rounding can result in incorrect trailing partial quotients:: - sage: continued_fraction(RealField(39)(e)) + sage: continued_fraction(RealField(39)(e)) # needs sage.symbolic [2; 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10, 2] Note the value returned for floating point number is the continued fraction @@ -2633,8 +2646,8 @@ def continued_fraction(x, value=None): Constants in symbolic subrings work like constants in ``SR``:: - sage: SCR = SR.subring(no_variables=True) - sage: continued_fraction(SCR(pi)) + sage: SCR = SR.subring(no_variables=True) # needs sage.symbolic + sage: continued_fraction(SCR(pi)) # needs sage.symbolic [3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, ...] """ diff --git a/src/sage/rings/continued_fraction_gosper.py b/src/sage/rings/continued_fraction_gosper.py index 08d5dd34658..4f86b3d9da6 100644 --- a/src/sage/rings/continued_fraction_gosper.py +++ b/src/sage/rings/continued_fraction_gosper.py @@ -4,12 +4,13 @@ EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.rings.continued_fraction_gosper import gosper_iterator sage: x = continued_fraction(pi) sage: it = iter(gosper_iterator(3,2,3,1,x)) - sage: Word(it, length='infinite') + sage: Word(it, length='infinite') # needs sage.combinat word: 1,10,2,2,1,4,1,1,1,97,4,1,2,1,2,45,6,4,9,1,27,2,6,1,4,2,3,1,3,1,15,2,1,1,2,1,1,2,32,1,... - sage: continued_fraction((3*pi + 2) / (3*pi + 1)) + sage: continued_fraction((3*pi + 2) / (3*pi + 1)) # needs sage.combinat [1; 10, 2, 2, 1, 4, 1, 1, 1, 97, 4, 1, 2, 1, 2, 45, 6, 4, 9, 1, ...] REFERENCES: @@ -104,9 +105,9 @@ def __iter__(self): sage: from sage.rings.continued_fraction_gosper import gosper_iterator sage: a, b, c, d = (Integer(randint(-100,100)) for _ in range(4)) - sage: ig = iter(gosper_iterator(a, b, c, d, continued_fraction(pi))) - sage: icf = iter(continued_fraction((a*pi + b) / (c*pi + d))); - sage: for i in range(10): + sage: ig = iter(gosper_iterator(a, b, c, d, continued_fraction(pi))) # needs sage.symbolic + sage: icf = iter(continued_fraction((a*pi + b) / (c*pi + d))); # needs sage.symbolic + sage: for i in range(10): # needs sage.symbolic ....: try: ....: assert next(ig) == next(icf) ....: except StopIteration: @@ -121,8 +122,8 @@ def __next__(self): TESTS:: sage: from sage.rings.continued_fraction_gosper import gosper_iterator - sage: it = gosper_iterator(1, 0, 0, 1, continued_fraction(pi)) - sage: list(next(it) for _ in range(10)) + sage: it = gosper_iterator(1, 0, 0, 1, continued_fraction(pi)) # needs sage.symbolic + sage: list(next(it) for _ in range(10)) # needs sage.symbolic [3, 7, 15, 1, 292, 1, 1, 1, 2, 1] """ while True: @@ -156,10 +157,10 @@ def emit(self, q): sage: a = Integer(randint(-100,100)); b = Integer(randint(-100,100)); sage: c = Integer(randint(-100,100)); d = Integer(randint(-100,100)); sage: from sage.rings.continued_fraction_gosper import gosper_iterator - sage: gi = gosper_iterator(a,b,c,d,continued_fraction(pi)) - sage: for i in range(10): + sage: gi = gosper_iterator(a, b, c, d, continued_fraction(pi)) # needs sage.symbolic + sage: for i in range(10): # needs sage.symbolic ....: gi.emit(i) - sage: gi.currently_emitted + sage: gi.currently_emitted # needs sage.symbolic 10 """ self.currently_emitted += 1 @@ -182,10 +183,10 @@ def ingest(self): sage: a = Integer(randint(-100,100)); b = Integer(randint(-100,100)); sage: c = Integer(randint(-100,100)); d = Integer(randint(-100,100)); sage: from sage.rings.continued_fraction_gosper import gosper_iterator - sage: gi = gosper_iterator(a,b,c,d,continued_fraction(pi)) - sage: for i in range(10): + sage: gi = gosper_iterator(a, b, c, d, continued_fraction(pi)) # needs sage.symbolic + sage: for i in range(10): # needs sage.symbolic ....: gi.ingest() - sage: gi.currently_read + sage: gi.currently_read # needs sage.symbolic 10 """ try: diff --git a/src/sage/rings/convert/__init__.py b/src/sage/rings/convert/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/functions/__init__.py b/src/sage/rings/convert/all.py similarity index 100% rename from src/sage/functions/__init__.py rename to src/sage/rings/convert/all.py diff --git a/src/sage/rings/convert/mpfi.pyx b/src/sage/rings/convert/mpfi.pyx index 3dbe12da224..3ca01ac276f 100644 --- a/src/sage/rings/convert/mpfi.pyx +++ b/src/sage/rings/convert/mpfi.pyx @@ -20,7 +20,7 @@ from sage.libs.gsl.complex cimport * from sage.arith.long cimport integer_check_long from sage.cpython.string cimport bytes_to_str -from sage.structure.element cimport Element, parent +from sage.structure.element cimport Element import sage.rings.abc from ..integer cimport Integer diff --git a/src/sage/rings/derivation.py b/src/sage/rings/derivation.py index 29f3a18d662..26b6f2d5905 100644 --- a/src/sage/rings/derivation.py +++ b/src/sage/rings/derivation.py @@ -35,7 +35,8 @@ sage: A.<x,y,z> = QQ[] sage: M = A.derivation_module() sage: M - Module of derivations over Multivariate Polynomial Ring in x, y, z over Rational Field + Module of derivations over + Multivariate Polynomial Ring in x, y, z over Rational Field The method :meth:`~sage.rings.derivation.RingDerivationModule.gens` returns the generators of this module:: @@ -76,8 +77,10 @@ Sage knows moreover that `M` is a Lie algebra:: sage: M.category() - Join of Category of lie algebras with basis over Rational Field - and Category of modules with basis over Multivariate Polynomial Ring in x, y, z over Rational Field + Join of + Category of lie algebras with basis over Rational Field and + Category of modules with basis over + Multivariate Polynomial Ring in x, y, z over Rational Field Computations of Lie brackets are implemented as well:: @@ -116,7 +119,9 @@ sage: M = A.derivation_module(ev) sage: M - Module of derivations from Multivariate Polynomial Ring in x, y, z over Rational Field to Rational Field + Module of derivations + from Multivariate Polynomial Ring in x, y, z over Rational Field + to Rational Field sage: M.gens() (d/dx, d/dy, d/dz) @@ -138,7 +143,8 @@ sage: theta = B.hom([B(y),B(z),B(x)]) sage: theta - Ring endomorphism of Fraction Field of Multivariate Polynomial Ring in x, y, z over Rational Field + Ring endomorphism of Fraction Field of + Multivariate Polynomial Ring in x, y, z over Rational Field Defn: x |--> y y |--> z z |--> x @@ -196,7 +202,8 @@ from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic from sage.rings.padics.padic_generic import pAdicGeneric -from sage.rings.function_field.function_field import FunctionField, RationalFunctionField +from sage.rings.function_field.function_field import FunctionField +from sage.rings.function_field.function_field_rational import RationalFunctionField from sage.categories.number_fields import NumberFields from sage.categories.finite_fields import FiniteFields from sage.categories.modules import Modules @@ -225,24 +232,31 @@ def __init__(self, domain, codomain, twist=None): sage: from sage.rings.derivation import RingDerivationModule sage: R5.<x> = GF(5)[] - sage: R25.<x> = GF(25)[] + sage: R25.<x> = GF(25)[] # needs sage.rings.finite_rings sage: R7.<x> = GF(7)[] - sage: RingDerivationModule(R5, R25) - Module of derivations from Univariate Polynomial Ring in x over Finite Field of size 5 to Univariate Polynomial Ring in x over Finite Field in z2 of size 5^2 + sage: RingDerivationModule(R5, R25) # needs sage.rings.finite_rings + Module of derivations + from Univariate Polynomial Ring in x over Finite Field of size 5 + to Univariate Polynomial Ring in x over Finite Field in z2 of size 5^2 sage: RingDerivationModule(R5, R5^2) Traceback (most recent call last): ... - TypeError: the codomain must be an algebra over the domain or a morphism with the correct domain - sage: RingDerivationModule(R5, R7) + TypeError: the codomain must be an algebra over the domain + or a morphism with the correct domain + sage: RingDerivationModule(R5, R7) # needs sage.rings.finite_rings Traceback (most recent call last): ... - TypeError: the codomain must be an algebra over the domain or a morphism with the correct domain + TypeError: the codomain must be an algebra over the domain + or a morphism with the correct domain sage: theta = R5.hom([R5.gen()^2]) - sage: RingDerivationModule(R5, R25, twist=theta) - Module of twisted derivations from Univariate Polynomial Ring in x over Finite Field of size 5 to Univariate Polynomial Ring in x over Finite Field in z2 of size 5^2 (twisting morphism: x |--> x^2) - sage: RingDerivationModule(R7, R7, twist=theta) + sage: RingDerivationModule(R5, R25, twist=theta) # needs sage.rings.finite_rings + Module of twisted derivations + from Univariate Polynomial Ring in x over Finite Field of size 5 + to Univariate Polynomial Ring in x over Finite Field in z2 of size 5^2 + (twisting morphism: x |--> x^2) + sage: RingDerivationModule(R7, R7, twist=theta) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: the domain of the derivation must coerce to the domain of the twisting homomorphism @@ -391,13 +405,13 @@ def __init__(self, domain, codomain, twist=None): constants, sharp = self._base_derivation._constants self._constants = (constants, False) # can we do better? elif isinstance(domain, RationalFunctionField): - from sage.rings.function_field.maps import FunctionFieldDerivation_rational + from sage.rings.function_field.derivations_rational import FunctionFieldDerivation_rational self.Element = FunctionFieldDerivation_rational self._gens = self._basis = [ None ] self._dual_basis = [ domain.gen() ] elif isinstance(domain, FunctionField): if domain.is_separable(): - from sage.rings.function_field.maps import FunctionFieldDerivation_separable + from sage.rings.function_field.derivations_polymod import FunctionFieldDerivation_separable self._base_derivation = RingDerivationModule(domain.base_ring(), defining_morphism) self.Element = FunctionFieldDerivation_separable try: @@ -410,7 +424,7 @@ def __init__(self, domain, codomain, twist=None): except NotImplementedError: pass else: - from sage.rings.function_field.maps import FunctionFieldDerivation_inseparable + from sage.rings.function_field.derivations_polymod import FunctionFieldDerivation_inseparable M, f, self._t = domain.separable_model() self._base_derivation = RingDerivationModule(M, defining_morphism * f) self._d = self._base_derivation(None) @@ -459,8 +473,10 @@ def _coerce_map_from_(self, R): sage: M1 = A.derivation_module(); M1 Module of derivations over Univariate Polynomial Ring in x over Rational Field sage: M2 = A.derivation_module(B); M2 - Module of derivations from Univariate Polynomial Ring in x over Rational Field - to Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + Module of derivations + from Univariate Polynomial Ring in x over Rational Field + to Univariate Polynomial Ring in y over + Univariate Polynomial Ring in x over Rational Field sage: M1._coerce_map_from_(M2) is None True sage: M1.has_coerce_map_from(M2) @@ -566,7 +582,8 @@ def defining_morphism(self): sage: M.defining_morphism() Polynomial base injection morphism: From: Univariate Polynomial Ring in x over Rational Field - To: Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + To: Univariate Polynomial Ring in y over + Univariate Polynomial Ring in x over Rational Field sage: ev = R.hom([QQ(0)]) sage: M = R.derivation_module(ev) @@ -856,7 +873,8 @@ def codomain(self): sage: S.<y> = R[] sage: M = R.derivation_module(S) sage: M.random_element().codomain() - Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + Univariate Polynomial Ring in y over + Univariate Polynomial Ring in x over Rational Field sage: M.random_element().codomain() is S True @@ -1131,6 +1149,7 @@ def pth_power(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<x,y> = GF(5)[] sage: Dx = R.derivation(x) sage: Dx.pth_power() @@ -1140,8 +1159,8 @@ def pth_power(self): sage: (x^6*Dx).pth_power() x^26*d/dx - sage: Dy = R.derivation(y) - sage: (x*Dx + y*Dy).pth_power() + sage: Dy = R.derivation(y) # needs sage.rings.finite_rings + sage: (x*Dx + y*Dy).pth_power() # needs sage.rings.finite_rings x*d/dx + y*d/dy An error is raised if the domain has characteristic zero:: @@ -1164,6 +1183,7 @@ def pth_power(self): TESTS:: + sage: # needs sage.rings.finite_rings sage: R.<x,y> = GF(3)[] sage: D = R.derivation_module().random_element() sage: Dp = D.pth_power() @@ -1171,7 +1191,7 @@ def pth_power(self): sage: Dp(f) == D(D(D(f))) True - sage: D.bracket(Dp) + sage: D.bracket(Dp) # needs sage.rings.finite_rings 0 """ @@ -1560,6 +1580,7 @@ def __init__(self, parent, arg=None): TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.derivation import RingDerivationWithoutTwist_wrapper sage: R.<x,y> = GF(5)[] sage: S = R.quo([x^5, y^5]) @@ -1568,7 +1589,7 @@ def __init__(self, parent, arg=None): sage: isinstance(der, RingDerivationWithoutTwist_wrapper) True - sage: TestSuite(der).run() + sage: TestSuite(der).run() # needs sage.rings.finite_rings """ if isinstance(arg, list) and len(arg) == 1 and isinstance(arg[0], RingDerivation): @@ -1599,6 +1620,7 @@ def _add_(self, other): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<X,Y> = GF(5)[] sage: S.<x,y> = R.quo([X^5, Y^5]) sage: Dx = S.derivation(x) @@ -1615,6 +1637,7 @@ def _sub_(self, other): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<X,Y> = GF(5)[] sage: S.<x,y> = R.quo([X^5, Y^5]) sage: Dx = S.derivation(x) @@ -1631,6 +1654,7 @@ def _neg_(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<X,Y> = GF(5)[] sage: S.<x,y> = R.quo([X^5, Y^5]) sage: Dx = S.derivation(x) @@ -1646,6 +1670,7 @@ def _lmul_(self, factor): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<X,Y> = GF(5)[] sage: S.<x,y> = R.quo([X^5, Y^5]) sage: Dx = S.derivation(x) @@ -1663,6 +1688,7 @@ def _rmul_(self, factor): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<X,Y> = GF(5)[] sage: S.<x,y> = R.quo([X^5, Y^5]) sage: Dx = S.derivation(x) @@ -1681,20 +1707,21 @@ def list(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<X,Y> = GF(5)[] sage: S.<x,y> = R.quo([X^5, Y^5]) sage: M = S.derivation_module() sage: M.basis() Family (d/dx, d/dy) - sage: S.derivation(x).list() + sage: S.derivation(x).list() # needs sage.rings.finite_rings [1, 0] - sage: S.derivation(y).list() + sage: S.derivation(y).list() # needs sage.rings.finite_rings [0, 1] - sage: f = x*S.derivation(x) + y*S.derivation(y); f + sage: f = x*S.derivation(x) + y*S.derivation(y); f # needs sage.rings.finite_rings x*d/dx + y*d/dy - sage: f.list() + sage: f.list() # needs sage.rings.finite_rings [x, y] """ @@ -1973,6 +2000,7 @@ def _call_(self, x): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<X,Y> = GF(5)[] sage: S.<x,y> = R.quo([X^5, Y^5]) sage: f = x^3*S.derivation(); f @@ -2073,9 +2101,10 @@ def _latex_(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: Frob = k.frobenius_endomorphism() - sage: der = k.derivation(a+1, twist=Frob) + sage: der = k.derivation(a + 1, twist=Frob) sage: latex(der) \left(a + 1\right) \left(\left[a \mapsto a^{5}\right] - \text{id}\right) """ @@ -2352,13 +2381,12 @@ def extend_to_fraction_field(self): sage: d x*([x |--> y, y |--> x] - id) - sage: D = d.extend_to_fraction_field() - sage: D + sage: D = d.extend_to_fraction_field(); D # needs sage.libs.singular x*([x |--> y, y |--> x] - id) - sage: D.domain() + sage: D.domain() # needs sage.libs.singular Fraction Field of Multivariate Polynomial Ring in x, y over Integer Ring - sage: D(1/x) + sage: D(1/x) # needs sage.libs.singular (x - y)/y """ parent = self.parent() diff --git a/src/sage/rings/factorint.pyx b/src/sage/rings/factorint.pyx index 3a7e4a3648b..d4df0e5ea05 100644 --- a/src/sage/rings/factorint.pyx +++ b/src/sage/rings/factorint.pyx @@ -8,22 +8,23 @@ AUTHORS: """ -#***************************************************************************** -# Copyright (C) 2010 Andrรฉ Apitzsch <andre.apitzsch@st.ovgu.de> +# **************************************************************************** +# Copyright (C) 2010-2011 Andrรฉ Apitzsch <andre.apitzsch@st.ovgu.de> +# 2012 Nils Bruin +# 2014 David Roe +# 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.ext.stdsage cimport PY_NEW from sage.libs.gmp.mpz cimport * from sage.rings.integer cimport Integer -from sage.rings.fast_arith import prime_range from sage.structure.factorization_integer import IntegerFactorization -from math import floor from sage.misc.misc_c import prod cdef extern from "limits.h": @@ -49,23 +50,23 @@ cpdef aurifeuillian(n, m, F=None, bint check=True): EXAMPLES:: sage: from sage.rings.factorint import aurifeuillian - sage: aurifeuillian(2,2) + sage: aurifeuillian(2, 2) [5, 13] - sage: aurifeuillian(2,2^5) + sage: aurifeuillian(2, 2^5) [1985, 2113] - sage: aurifeuillian(5,3) + sage: aurifeuillian(5, 3) [1471, 2851] - sage: aurifeuillian(15,1) + sage: aurifeuillian(15, 1) [19231, 142111] - sage: aurifeuillian(12,3) + sage: aurifeuillian(12, 3) Traceback (most recent call last): ... ValueError: n has to be square-free - sage: aurifeuillian(1,2) + sage: aurifeuillian(1, 2) Traceback (most recent call last): ... ValueError: n has to be greater than 1 - sage: aurifeuillian(2,0) + sage: aurifeuillian(2, 0) Traceback (most recent call last): ... ValueError: m has to be positive @@ -128,25 +129,26 @@ cpdef factor_aurifeuillian(n, check=True): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.rings.factorint import factor_aurifeuillian as fa - sage: fa(2^6+1) + sage: fa(2^6 + 1) [5, 13] - sage: fa(2^58+1) + sage: fa(2^58 + 1) [536838145, 536903681] - sage: fa(3^3+1) + sage: fa(3^3 + 1) [4, 1, 7] - sage: fa(5^5-1) + sage: fa(5^5 - 1) [4, 11, 71] - sage: prod(_) == 5^5-1 + sage: prod(_) == 5^5 - 1 True - sage: fa(2^4+1) + sage: fa(2^4 + 1) [17] - sage: fa((6^2*3)^3+1) + sage: fa((6^2*3)^3 + 1) [109, 91, 127] TESTS:: - sage: for n in [2,3,5,6,30,31,33]: + sage: for n in [2,3,5,6,30,31,33]: # needs sage.libs.pari ....: for m in [8,96,109201283]: ....: s = -1 if n % 4 == 1 else 1 ....: y = (m^2*n)^n + s @@ -202,9 +204,9 @@ cpdef factor_aurifeuillian(n, check=True): def factor_cunningham(m, proof=None): r""" - Return factorization of self obtained using trial division + Return factorization of ``self`` obtained using trial division for all primes in the so called Cunningham table. This is - efficient if self has some factors of type `b^n+1` or `b^n-1`, + efficient if ``self`` has some factors of type `b^n+1` or `b^n-1`, with `b` in `\{2,3,5,6,7,10,11,12\}`. You need to install an optional package to use this method, @@ -222,7 +224,7 @@ def factor_cunningham(m, proof=None): sage: from sage.rings.factorint import factor_cunningham sage: factor_cunningham(2^257-1) # optional - cunningham_tables 535006138814359 * 1155685395246619182673033 * 374550598501810936581776630096313181393 - sage: factor_cunningham((3^101+1)*(2^60).next_prime(),proof=False) # optional - cunningham_tables + sage: factor_cunningham((3^101+1)*(2^60).next_prime(), proof=False) # optional - cunningham_tables 2^2 * 379963 * 1152921504606847009 * 1017291527198723292208309354658785077827527 """ @@ -245,12 +247,12 @@ def factor_cunningham(m, proof=None): cpdef factor_trial_division(m, long limit=LONG_MAX): r""" - Return partial factorization of self obtained using trial division - for all primes up to limit, where limit must fit in a C signed long. + Return partial factorization of ``self`` obtained using trial division + for all primes up to ``limit``, where ``limit`` must fit in a C ``signed long``. INPUT: - - ``limit`` -- integer (default: ``LONG_MAX``) that fits in a C signed long + - ``limit`` -- integer (default: ``LONG_MAX``) that fits in a C ``signed long`` EXAMPLES:: @@ -288,65 +290,3 @@ cpdef factor_trial_division(m, long limit=LONG_MAX): return IntegerFactorization(F, unit=unit, unsafe=True, sort=False, simplify=False) - - -def factor_using_pari(n, int_=False, debug_level=0, proof=None): - r""" - Factor this integer using PARI. - - This function returns a list of pairs, not a ``Factorization`` - object. The first element of each pair is the factor, of type - ``Integer`` if ``int_`` is ``False`` or ``int`` otherwise, - the second element is the positive exponent, of type ``int``. - - INPUT: - - - ``int_`` -- (default: ``False``), whether the factors are - of type ``int`` instead of ``Integer`` - - - ``debug_level`` -- (default: 0), debug level of the call - to PARI - - - ``proof`` -- (default: ``None``), whether the factors are - required to be proven prime; if ``None``, the global default - is used - - OUTPUT: - - A list of pairs. - - EXAMPLES:: - - sage: factor(-2**72 + 3, algorithm='pari') # indirect doctest - -1 * 83 * 131 * 294971519 * 1472414939 - - Check that PARI's debug level is properly reset (:trac:`18792`):: - - sage: alarm(0.5); factor(2^1000 - 1, verbose=5) - Traceback (most recent call last): - ... - AlarmInterrupt - sage: pari.get_debug_level() - 0 - """ - from sage.libs.pari.all import pari - - if proof is None: - from sage.structure.proof.proof import get_flag - proof = get_flag(proof, "arithmetic") - - prev = pari.get_debug_level() - - cdef Py_ssize_t i - try: - if prev != debug_level: - pari.set_debug_level(debug_level) - - p, e = n.__pari__().factor(proof=proof) - if int_: - return [(int(p[i]), int(e[i])) for i in range(len(p))] - else: - return [(Integer(p[i]), int(e[i])) for i in range(len(p))] - finally: - if prev != debug_level: - pari.set_debug_level(prev) diff --git a/src/sage/rings/factorint_flint.pyx b/src/sage/rings/factorint_flint.pyx new file mode 100644 index 00000000000..7e08edafa97 --- /dev/null +++ b/src/sage/rings/factorint_flint.pyx @@ -0,0 +1,97 @@ +# sage.doctest: needs sage.libs.flint +r""" +Integer factorization using FLINT + +AUTHORS: + +- Michael Orlitzky (2023) +""" + +#***************************************************************************** +# Copyright (C) 2023 Michael Orlitzky +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from cysignals.signals cimport sig_on, sig_off + +from sage.libs.flint.fmpz cimport fmpz_t, fmpz_init, fmpz_set_mpz +from sage.libs.flint.fmpz_factor cimport * +from sage.rings.integer cimport Integer + + +def factor_using_flint(Integer n): + r""" + Factor the nonzero integer ``n`` using FLINT. + + This function returns a list of (factor, exponent) pairs. The + factors will be of type ``Integer``, and the exponents will be of + type ``int``. + + INPUT: + + - ``n`` -- a nonzero sage Integer; the number to factor. + + OUTPUT: + + A list of ``(Integer, int)`` pairs representing the factors and + their exponents. + + EXAMPLES:: + + sage: from sage.rings.factorint_flint import factor_using_flint + sage: n = ZZ(9962572652930382) + sage: factors = factor_using_flint(n) + sage: factors + [(2, 1), (3, 1), (1660428775488397, 1)] + sage: prod( f^e for (f,e) in factors ) == n + True + + Negative numbers will have a leading factor of ``(-1)^1``:: + + sage: n = ZZ(-1 * 2 * 3) + sage: factor_using_flint(n) + [(-1, 1), (2, 1), (3, 1)] + + The factorization of unity is empty:: + + sage: factor_using_flint(ZZ.one()) + [] + + While zero has a single factor, of... zero:: + + sage: factor_using_flint(ZZ.zero()) + [(0, 1)] + + TESTS: + + Check that the integers [-10,000, 10,000] are factored correctly:: + + sage: all( + ....: prod( f^e for (f,e) in factor_using_flint(ZZ(c*k)) ) == c*k + ....: for k in range(10000) + ....: for c in [-1, 1] + ....: ) + True + """ + if n.is_zero(): + return [(n, int(1))] + + cdef fmpz_t p + fmpz_init(p) + fmpz_set_mpz(p, (<Integer>n).value) + + cdef fmpz_factor_t factors + fmpz_factor_init(factors) + + sig_on() + fmpz_factor(factors, p) + sig_off() + + pairs = fmpz_factor_to_pairlist(factors) + + fmpz_factor_clear(factors) + return pairs diff --git a/src/sage/rings/factorint_pari.pyx b/src/sage/rings/factorint_pari.pyx new file mode 100644 index 00000000000..8e5ed7c619e --- /dev/null +++ b/src/sage/rings/factorint_pari.pyx @@ -0,0 +1,80 @@ +# sage.doctest: needs sage.libs.pari +r""" +Integer factorization using PARI + +AUTHORS: + +- Jeroen Demeyer (2015) +""" + +#***************************************************************************** +# Copyright (C) 2015 Jeroen Demeyer +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.libs.pari.all import pari +from sage.rings.integer cimport Integer + + +def factor_using_pari(n, int_=False, debug_level=0, proof=None): + r""" + Factor this integer using PARI. + + This function returns a list of pairs, not a :class:`Factorization` + object. The first element of each pair is the factor, of type + ``Integer`` if ``int_`` is ``False`` or ``int`` otherwise, + the second element is the positive exponent, of type ``int``. + + INPUT: + + - ``int_`` -- (default: ``False``), whether the factors are + of type ``int`` instead of ``Integer`` + + - ``debug_level`` -- (default: 0), debug level of the call + to PARI + + - ``proof`` -- (default: ``None``), whether the factors are + required to be proven prime; if ``None``, the global default + is used + + OUTPUT: + + A list of pairs. + + EXAMPLES:: + + sage: factor(-2**72 + 3, algorithm='pari') # indirect doctest + -1 * 83 * 131 * 294971519 * 1472414939 + + Check that PARI's debug level is properly reset (:trac:`18792`):: + + sage: alarm(0.5); factor(2^1000 - 1, verbose=5) + Traceback (most recent call last): + ... + AlarmInterrupt + sage: pari.get_debug_level() + 0 + """ + if proof is None: + from sage.structure.proof.proof import get_flag + proof = get_flag(proof, "arithmetic") + + prev = pari.get_debug_level() + + cdef Py_ssize_t i + try: + if prev != debug_level: + pari.set_debug_level(debug_level) + + p, e = n.__pari__().factor(proof=proof) + if int_: + return [(int(p[i]), int(e[i])) for i in range(len(p))] + else: + return [(Integer(p[i]), int(e[i])) for i in range(len(p))] + finally: + if prev != debug_level: + pari.set_debug_level(prev) diff --git a/src/sage/rings/fast_arith.pyx b/src/sage/rings/fast_arith.pyx index df9b592cf97..bdb5884668e 100644 --- a/src/sage/rings/fast_arith.pyx +++ b/src/sage/rings/fast_arith.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari """ Basic arithmetic with C integers """ @@ -58,16 +59,16 @@ cpdef prime_range(start, stop=None, algorithm=None, bint py_ints=False): - ``algorithm`` -- optional string (default: ``None``), one of: - - ``None``: Use algorithm ``"pari_primes"`` if ``stop`` <= 436273009 - (approximately 4.36E8). Otherwise use algorithm ``"pari_isprime"``. + - ``None``: Use algorithm ``"pari_primes"`` if ``stop`` <= 436273009 + (approximately 4.36E8). Otherwise use algorithm ``"pari_isprime"``. - - ``"pari_primes"``: Use PARI's :pari:`primes` function to generate all - primes from 2 to stop. This is fast but may crash if there is - insufficient memory. Raises an error if ``stop`` > 436273009. + - ``"pari_primes"``: Use PARI's :pari:`primes` function to generate all + primes from 2 to stop. This is fast but may crash if there is + insufficient memory. Raises an error if ``stop`` > 436273009. - - ``"pari_isprime"``: Wrapper for ``list(primes(start, stop))``. Each (odd) - integer in the specified range is tested for primality by applying PARI's - :pari:`isprime` function. This is slower but will work for much larger input. + - ``"pari_isprime"``: Wrapper for ``list(primes(start, stop))``. Each (odd) + integer in the specified range is tested for primality by applying PARI's + :pari:`isprime` function. This is slower but will work for much larger input. - ``py_ints`` -- optional boolean (default ``False``), return Python ints rather than Sage Integers (faster). Ignored unless algorithm ``"pari_primes"`` is being @@ -145,7 +146,6 @@ cpdef prime_range(start, stop=None, algorithm=None, bint py_ints=False): - Kevin Stueve (added primes iterator option) 2010-10-16 - Robert Bradshaw (speedup using Pari prime table, py_ints option) """ - cdef Integer z # input to pari.init_primes cannot be greater than 436273290 (hardcoded bound) DEF init_primes_max = 436273290 DEF small_prime_max = 436273009 # a prime < init_primes_max (preferably the largest) diff --git a/src/sage/rings/finite_rings/__init__.py b/src/sage/rings/finite_rings/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/rings/finite_rings/conway_polynomials.py b/src/sage/rings/finite_rings/conway_polynomials.py index d4a08e1fb4d..02779f49bca 100644 --- a/src/sage/rings/finite_rings/conway_polynomials.py +++ b/src/sage/rings/finite_rings/conway_polynomials.py @@ -11,10 +11,13 @@ """ from sage.misc.fast_methods import WithEqualityById +from sage.misc.lazy_import import lazy_import from sage.structure.sage_object import SageObject from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.rings.integer import Integer -import sage.databases.conway + +lazy_import('sage.databases.conway', 'ConwayPolynomials') + def conway_polynomial(p, n): """ @@ -45,11 +48,11 @@ def conway_polynomial(p, n): EXAMPLES:: - sage: conway_polynomial(2,5) + sage: conway_polynomial(2,5) # needs conway_polynomials x^5 + x^2 + 1 - sage: conway_polynomial(101,5) + sage: conway_polynomial(101,5) # needs conway_polynomials x^5 + 2*x + 99 - sage: conway_polynomial(97,101) + sage: conway_polynomial(97,101) # needs conway_polynomials Traceback (most recent call last): ... RuntimeError: requested Conway polynomial not in database. @@ -57,7 +60,7 @@ def conway_polynomial(p, n): (p, n) = (int(p), int(n)) R = FiniteField(p)['x'] try: - return R(sage.databases.conway.ConwayPolynomials()[p][n]) + return R(ConwayPolynomials()[p][n]) except KeyError: raise RuntimeError("requested Conway polynomial not in database.") @@ -82,7 +85,7 @@ def exists_conway_polynomial(p, n): EXAMPLES:: - sage: exists_conway_polynomial(2,3) + sage: exists_conway_polynomial(2,3) # needs conway_polynomials True sage: exists_conway_polynomial(2,-1) False @@ -91,7 +94,10 @@ def exists_conway_polynomial(p, n): sage: exists_conway_polynomial(6,6) False """ - return sage.databases.conway.ConwayPolynomials().has_polynomial(p,n) + try: + return ConwayPolynomials().has_polynomial(p,n) + except ImportError: + return False class PseudoConwayLattice(WithEqualityById, SageObject): r""" @@ -127,6 +133,7 @@ class PseudoConwayLattice(WithEqualityById, SageObject): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.polynomial(3) @@ -154,11 +161,13 @@ def __init__(self, p, use_database=True): """ TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(3) sage: PCL.polynomial(3) x^3 + 2*x + 1 + sage: # needs sage.rings.finite_rings sage: PCL = PseudoConwayLattice(5, use_database=False) sage: PCL.polynomial(12) x^12 + 4*x^11 + 2*x^10 + 4*x^9 + 2*x^8 + 2*x^7 + 4*x^6 + x^5 + 2*x^4 + 2*x^2 + x + 2 @@ -171,9 +180,13 @@ def __init__(self, p, use_database=True): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing self.ring = PolynomialRing(FiniteField(p), 'x') if use_database: - C = sage.databases.conway.ConwayPolynomials() - self.nodes = {n: self.ring(C.polynomial(p, n)) - for n in C.degrees(p)} + try: + C = ConwayPolynomials() + except ImportError: + self.nodes = {} + else: + self.nodes = {n: self.ring(C.polynomial(p, n)) + for n in C.degrees(p)} else: self.nodes = {} @@ -199,6 +212,7 @@ def polynomial(self, n): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.polynomial(3) @@ -267,13 +281,14 @@ def check_consistency(self, n): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.check_consistency(6) sage: PCL.check_consistency(60) # long time """ p = self.p - K = FiniteField(p**n, modulus = self.polynomial(n), names='a') + K = FiniteField(p**n, modulus=self.polynomial(n), names='a') a = K.gen() for m in n.divisors(): assert (a**((p**n-1)//(p**m-1))).minimal_polynomial() == self.polynomial(m) @@ -301,6 +316,7 @@ def _find_pow_of_frobenius(p, n, x, y): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.conway_polynomials import _find_pow_of_frobenius sage: K.<a> = GF(3^14) sage: x = K.multiplicative_generator() @@ -380,6 +396,7 @@ def _frobenius_shift(K, generators, check_only=False): EXAMPLES:: + sage: # needs sage.libs.ntl sage.rings.finite_rings sage: R.<x> = GF(2)[] sage: f30 = x^30 + x^28 + x^27 + x^25 + x^24 + x^20 + x^19 + x^18 + x^16 + x^15 + x^12 + x^10 + x^7 + x^2 + 1 sage: f20 = x^20 + x^19 + x^15 + x^13 + x^12 + x^11 + x^9 + x^8 + x^7 + x^4 + x^2 + x + 1 @@ -454,7 +471,7 @@ def find_leveller(qindex, level, x, xleveled, searched, i): searched[i] = True crt_possibles = [] for j in range(1,len(qlist)): - if i==j: + if i == j: continue if crt[(i,j)][qindex][1] >= level: if xleveled[j]: @@ -470,7 +487,7 @@ def find_leveller(qindex, level, x, xleveled, searched, i): def propagate_levelling(qindex, level, x, xleveled, i): for j in range(1, len(qlist)): - if i==j: + if i == j: continue if not xleveled[j] and crt[(i,j)][qindex][1] >= level: newxj = x[i][0] + crt[(i,j)][qindex][0] diff --git a/src/sage/rings/finite_rings/element_base.pyx b/src/sage/rings/finite_rings/element_base.pyx index 29ab05dd8ba..e9ab5b5d4ab 100755 --- a/src/sage/rings/finite_rings/element_base.pyx +++ b/src/sage/rings/finite_rings/element_base.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings """ Base class for finite field elements @@ -25,58 +26,79 @@ from sage.misc.superseded import deprecated_function_alias def is_FiniteFieldElement(x): """ - Returns if x is a finite field element. + Return ``True`` if ``x`` is a finite field element. + + This function is deprecated. EXAMPLES:: sage: from sage.rings.finite_rings.element_base import is_FiniteFieldElement sage: is_FiniteFieldElement(1) + doctest:...: DeprecationWarning: the function is_FiniteFieldElement is deprecated; use isinstance(x, sage.structure.element.FieldElement) and x.parent().is_finite() instead + See https://github.com/sagemath/sage/issues/32664 for details. False sage: is_FiniteFieldElement(IntegerRing()) False sage: is_FiniteFieldElement(GF(5)(2)) True """ - from sage.rings.finite_rings.finite_field_base import is_FiniteField - return isinstance(x, Element) and is_FiniteField(x.parent()) + from sage.misc.superseded import deprecation + deprecation(32664, "the function is_FiniteFieldElement is deprecated; use isinstance(x, sage.structure.element.FieldElement) and x.parent().is_finite() instead") + + from sage.rings.finite_rings.finite_field_base import FiniteField + return isinstance(x, Element) and isinstance(x.parent(), FiniteField) cdef class FiniteRingElement(CommutativeRingElement): def _nth_root_common(self, n, all, algorithm, cunningham): """ This function exists to reduce code duplication between finite field - nth roots and integer_mod nth roots. + nth roots and integer_mod nth roots. It assumes that `self` is a field + element. The inputs are described there. TESTS:: sage: a = Zmod(17)(13) - sage: a._nth_root_common(4, True, "Johnston", False) - [3, 5, 14, 12] - sage: a._nth_root_common(4, True, "Johnston", cunningham=True) # optional - cunningham_tables - [3, 5, 14, 12] + sage: sorted(a._nth_root_common(4, True, "Johnston", False)) + [3, 5, 12, 14] + sage: sorted(a._nth_root_common(4, True, "Johnston", cunningham=True)) # optional - cunningham_tables + [3, 5, 12, 14] + + Test various prime powers:: + + sage: p = 5^5*10000000100 + 1 + sage: a = GF(p)(3)**(5^7) + sage: for e in range(20): + ....: r = a._nth_root_common(5^e, False, "Johnston", False) + ....: assert r**(5^e) == a + + Test very large modulus (assumed impossible to factor in reasonable time):: + + sage: p = 2^1024 + 643 + sage: a = GF(p, proof=False)(3)**(29*283*3539) + sage: r = a._nth_root_common(29*283*3539*12345, False, "Johnston", False) + sage: r**(29*283*3539*12345) == a + True """ K = self.parent() q = K.order() + gcd = n.gcd(q-1) if self.is_one(): - gcd = n.gcd(q-1) if gcd == 1: if all: return [self] else: return self else: - # the following may eventually be improved to not need a multiplicative generator. - g = K.multiplicative_generator() - q1overn = (q-1)//gcd - nthroot = g**q1overn + nthroot = K.zeta(gcd) return [nthroot**a for a in range(gcd)] if all else nthroot - n = n % (q-1) - if n == 0: + if gcd == q-1: if all: return [] else: raise ValueError("no nth root") - gcd, alpha, beta = n.xgcd(q-1) # gcd = alpha*n + beta*(q-1), so 1/n = alpha/gcd (mod q-1) + gcd, alpha, _ = n.xgcd(q-1) # gcd = alpha*n + beta*(q-1), so 1/n = alpha/gcd (mod q-1) if gcd == 1: return [self**alpha] if all else self**alpha + n = gcd q1overn = (q-1)//n if self**q1overn != 1: @@ -90,18 +112,26 @@ cdef class FiniteRingElement(CommutativeRingElement): F = n.factor() from sage.groups.generic import discrete_log if algorithm is None or algorithm == 'Johnston': - g = K.multiplicative_generator() + # In the style of the Adleman-Manders-Miller algorithm, + # we will use small order elements instead of a multiplicative + # generator, which can be expensive to compute. for r, v in F: + # 0 < v <= k k, h = (q-1).val_unit(r) - z = h * (-h).inverse_mod(r**v) + hinv = (-h).inverse_mod(r**v) + z = h * hinv x = (1 + z) // r**v - if k == 1: + if k == v: self = self**x else: - t = discrete_log(self**h, g**(r**v*h), r**(k-v), operation='*') - self = self**x * g**(-z*t) + # We need an element of order r^k (g^h in Johnston's article) + # self^x differs from the actual nth root by an element of + # order dividing r^(k-v) + gh = K.zeta(r**k) + t = discrete_log(self**h, gh**(r**v), r**(k-v), operation='*') + self = self**x * gh**(-hinv*t) if all: - nthroot = g**q1overn + nthroot = K.zeta(n) L = [self] for i in range(1,n): self *= nthroot @@ -375,12 +405,11 @@ cdef class FinitePolyExtElement(FiniteRingElement): sage: e._vector_(reverse=True) (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1) """ - #vector(foo) might pass in ZZ + # vector(foo) might pass in ZZ if isinstance(reverse, Parent): raise TypeError("Base field is fixed to prime subfield.") k = self.parent() - p = self.polynomial() ret = self.polynomial().padded_list(k.degree()) if reverse: @@ -391,7 +420,9 @@ cdef class FinitePolyExtElement(FiniteRingElement): r""" Return the matrix of left multiplication by the element on the power basis `1, x, x^2, \ldots, x^{d-1}` for the field - extension. Thus the \emph{columns} of this matrix give the images + extension. + + Thus the \emph{columns} of this matrix give the images of each of the `x^i`. INPUT: @@ -414,7 +445,7 @@ cdef class FinitePolyExtElement(FiniteRingElement): columns = [] - for i in xrange(d): + for i in range(d): columns.append( (self * x)._vector_(reverse=reverse) ) x *= a @@ -474,7 +505,6 @@ cdef class FinitePolyExtElement(FiniteRingElement): """ if var is None: var = self.parent().variable_name() - from sage.libs.pari.all import pari ffgen = self._parent.modulus()._pari_with_name(var).ffgen() polypari = self.polynomial()._pari_with_name() # Add ffgen - ffgen to ensure that we really get an FFELT @@ -681,23 +711,23 @@ cdef class FinitePolyExtElement(FiniteRingElement): EXAMPLES:: - sage: k.<a> = FiniteField(9, impl='givaro', modulus='primitive') - sage: a.is_square() + sage: k.<a> = FiniteField(9, impl='givaro', modulus='primitive') # needs sage.libs.linbox + sage: a.is_square() # needs sage.libs.linbox False - sage: (a**2).is_square() + sage: (a**2).is_square() # needs sage.libs.linbox True - sage: k.<a> = FiniteField(4, impl='ntl', modulus='primitive') - sage: (a**2).is_square() + sage: k.<a> = FiniteField(4, impl='ntl', modulus='primitive') # needs sage.libs.ntl + sage: (a**2).is_square() # needs sage.libs.ntl True - sage: k.<a> = FiniteField(17^5, impl='pari_ffelt', modulus='primitive') - sage: a.is_square() + sage: k.<a> = FiniteField(17^5, impl='pari_ffelt', modulus='primitive') # needs sage.libs.pari + sage: a.is_square() # needs sage.libs.pari False - sage: (a**2).is_square() + sage: (a**2).is_square() # needs sage.libs.pari True :: - sage: k(0).is_square() + sage: k(0).is_square() # needs sage.libs.linbox True """ K = self.parent() @@ -976,7 +1006,7 @@ cdef class FinitePolyExtElement(FiniteRingElement): sage: G32(m1) == g1 True """ - [(p, k2)] = list(self.parent().cardinality().factor()) + k2 = self.parent().degree() if k2 % 2: raise TypeError("cardinality of the field must be a square number") k = k2 / 2 @@ -1019,6 +1049,7 @@ cdef class FinitePolyExtElement(FiniteRingElement): TESTS:: + sage: # needs sage.modules sage: p = random_prime(2^99) sage: k = randrange(2,10) sage: F.<t> = GF((p, k)) @@ -1056,7 +1087,7 @@ cdef class Cache_base(SageObject): EXAMPLES:: sage: k.<a> = GF(2^48) - sage: k._cache.fetch_int(2^33 + 2 + 1) + sage: k._cache.fetch_int(2^33 + 2 + 1) # needs sage.libs.ntl a^33 + a + 1 """ raise NotImplementedError("this must be implemented by subclasses") diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index bdb42614592..ead2551ded5 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -56,33 +56,25 @@ from cysignals.signals cimport sig_on, sig_off from cypari2.paridecl cimport * -from sage.misc.randstate cimport randstate, current_randstate -from sage.rings.finite_rings.finite_field_base cimport FiniteField -from sage.rings.ring cimport Ring +from sage.misc.randstate cimport current_randstate from .element_pari_ffelt cimport FiniteFieldElement_pari_ffelt from sage.structure.richcmp cimport richcmp -from sage.structure.element cimport Element, ModuleElement, RingElement -import operator import sage.arith.all -import sage.rings.finite_rings.finite_field_constructor as finite_field -from sage.libs.pari.all import pari from cypari2.gen cimport Gen from cypari2.stack cimport clear_stack from sage.structure.parent cimport Parent - +from sage.structure.element cimport Vector from sage.interfaces.abc import GapElement cdef object is_IntegerMod cdef object Integer cdef object Rational -cdef object ConwayPolynomials -cdef object conway_polynomial cdef object MPolynomial cdef object Polynomial -cdef object FreeModuleElement + cdef void late_import(): """ @@ -91,11 +83,8 @@ cdef void late_import(): global is_IntegerMod, \ Integer, \ Rational, \ - ConwayPolynomials, \ - conway_polynomial, \ MPolynomial, \ - Polynomial, \ - FreeModuleElement + Polynomial if is_IntegerMod is not None: return @@ -109,20 +98,12 @@ cdef void late_import(): import sage.rings.rational Rational = sage.rings.rational.Rational - import sage.databases.conway - ConwayPolynomials = sage.databases.conway.ConwayPolynomials - - import sage.rings.finite_rings.finite_field_constructor - conway_polynomial = sage.rings.finite_rings.conway_polynomials.conway_polynomial - import sage.rings.polynomial.multi_polynomial_element MPolynomial = sage.rings.polynomial.multi_polynomial_element.MPolynomial import sage.rings.polynomial.polynomial_element Polynomial = sage.rings.polynomial.polynomial_element.Polynomial - import sage.modules.free_module_element - FreeModuleElement = sage.modules.free_module_element.FreeModuleElement cdef class Cache_givaro(Cache_base): def __init__(self, parent, unsigned int p, unsigned int k, modulus, repr="poly", cache=False): @@ -398,7 +379,7 @@ cdef class Cache_givaro(Cache_base): return self.parent(eval(e.replace("^", "**"), self.parent.gens_dict())) - elif isinstance(e, FreeModuleElement): + elif isinstance(e, Vector): if self.parent.vector_space(map=False) != e.parent(): raise TypeError("e.parent must match self.vector_space") ret = self._zero_element @@ -1579,7 +1560,6 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): """ # TODO -- I'm sure this can be made vastly faster # using how elements are represented as a power of the generator ?? - import sage.arith.all if self._multiplicative_order is not None: return self._multiplicative_order diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index 109ce513b61..7c5ab521b7a 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -15,18 +15,18 @@ AUTHORS: - Martin Albrecht <malb@informatik.uni-bremen.de> (2007-10) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Martin Albrecht <malb@informatik.uni-bremen.de> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.memory cimport check_malloc, sig_free -from cysignals.signals cimport sig_on, sig_off +from cysignals.signals cimport sig_on from sage.ext.cplusplus cimport ccrepr, ccreadstr include "sage/libs/ntl/decl.pxi" @@ -34,11 +34,9 @@ from cypari2.paridecl cimport * from sage.structure.richcmp cimport (richcmp, richcmp_not_equal, rich_to_bool) -from sage.structure.element cimport Element, ModuleElement, RingElement from sage.structure.parent cimport Parent - -from sage.rings.ring cimport Ring +from sage.structure.element cimport Vector from sage.rings.finite_rings.finite_field_base cimport FiniteField @@ -46,27 +44,17 @@ from sage.libs.pari.all import pari from cypari2.gen cimport Gen from cypari2.stack cimport clear_stack -from sage.misc.randstate import current_randstate -from sage.arith.long cimport pyobject_to_long - from .element_pari_ffelt import FiniteFieldElement_pari_ffelt from .finite_field_ntl_gf2e import FiniteField_ntl_gf2e -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - from sage.interfaces.abc import GapElement cdef object is_IntegerMod -cdef object IntegerModRing_generic cdef object Integer cdef object Rational -cdef object is_Polynomial -cdef object ConwayPolynomials -cdef object conway_polynomial cdef object MPolynomial cdef object Polynomial -cdef object FreeModuleElement cdef object GF cdef object GF2, GF2_0, GF2_1 @@ -77,15 +65,10 @@ cdef int late_import() except -1: imports. """ global is_IntegerMod, \ - IntegerModRing_generic, \ Integer, \ Rational, \ - is_Polynomial, \ - ConwayPolynomials, \ - conway_polynomial, \ MPolynomial, \ Polynomial, \ - FreeModuleElement, \ GF, \ GF2, GF2_0, GF2_1 @@ -95,30 +78,15 @@ cdef int late_import() except -1: import sage.rings.finite_rings.integer_mod is_IntegerMod = sage.rings.finite_rings.integer_mod.is_IntegerMod - import sage.rings.finite_rings.integer_mod_ring - IntegerModRing_generic = sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic - import sage.rings.rational Rational = sage.rings.rational.Rational - import sage.rings.polynomial.polynomial_element - is_Polynomial = sage.rings.polynomial.polynomial_element.is_Polynomial - - import sage.databases.conway - ConwayPolynomials = sage.databases.conway.ConwayPolynomials - - import sage.rings.finite_rings.conway_polynomials - conway_polynomial = sage.rings.finite_rings.conway_polynomials.conway_polynomial - import sage.rings.polynomial.multi_polynomial_element MPolynomial = sage.rings.polynomial.multi_polynomial_element.MPolynomial import sage.rings.polynomial.polynomial_element Polynomial = sage.rings.polynomial.polynomial_element.Polynomial - import sage.modules.free_module_element - FreeModuleElement = sage.modules.free_module_element.FreeModuleElement - import sage.rings.finite_rings.finite_field_constructor GF = sage.rings.finite_rings.finite_field_constructor.FiniteField GF2 = GF(2) @@ -321,7 +289,7 @@ cdef class Cache_ntl_gf2e(Cache_base): elif isinstance(e, str): return self._parent(eval(e.replace("^","**"),self._parent.gens_dict())) - elif isinstance(e, FreeModuleElement): + elif isinstance(e, Vector): if self._parent.vector_space(map=False) != e.parent(): raise TypeError("e.parent must match self.vector_space") ztmp = Integer(e.list(),2) @@ -1004,8 +972,8 @@ cdef class FiniteField_ntl_gf2eElement(FinitePolyExtElement): sage: e.polynomial() a^15 + a^13 + a^11 + a^10 + a^9 + a^8 + a^7 + a^6 + a^4 + a + 1 - sage: from sage.rings.polynomial.polynomial_element import is_Polynomial - sage: is_Polynomial(e.polynomial()) + sage: from sage.rings.polynomial.polynomial_element import Polynomial + sage: isinstance(e.polynomial(), Polynomial) True sage: e.polynomial('x') diff --git a/src/sage/rings/finite_rings/element_pari_ffelt.pyx b/src/sage/rings/finite_rings/element_pari_ffelt.pyx index be70aa56d39..2d29f424e3b 100644 --- a/src/sage/rings/finite_rings/element_pari_ffelt.pyx +++ b/src/sage/rings/finite_rings/element_pari_ffelt.pyx @@ -16,7 +16,6 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from cysignals.memory cimport sig_free from cysignals.signals cimport sig_on, sig_off from cypari2.paridecl cimport * @@ -29,17 +28,16 @@ from .element_base cimport FinitePolyExtElement from .integer_mod import IntegerMod_abstract import sage.rings.integer -from sage.modules.free_module_element import FreeModuleElement from sage.rings.integer cimport Integer from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.multi_polynomial_element import MPolynomial from sage.rings.rational import Rational -from sage.structure.element cimport Element, ModuleElement, RingElement +from sage.structure.element cimport Vector from sage.structure.richcmp cimport rich_to_bool - from sage.interfaces.abc import GapElement + cdef GEN _INT_to_FFELT(GEN g, GEN x) except NULL: """ Convert the t_INT `x` to an element of the field of definition of @@ -270,13 +268,19 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): sage: k = FiniteField(3^11, 't', impl='pari_ffelt') sage: k([ 0, 1/2 ]) 2*t + sage: k([ 0, 1/2, 0, 0, 0, 0, 0, 0, 0, -1, 0 ]) + 2*t^9 + 2*t sage: k([ k(0), k(1) ]) t sage: k([ GF(3)(2), GF(3^5,'u')(1) ]) t + 2 sage: R.<x> = PolynomialRing(k) + sage: k([ x/x ]) + 1 sage: k([ R(-1), x/x ]) t + 2 + sage: k([ R(-1), R(0), 0 ]) + 2 Check that zeros are created correctly (:trac:`11685`):: @@ -450,7 +454,7 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): sig_off() raise TypeError(f"unable to convert PARI {x.type()} to finite field element") - elif (isinstance(x, FreeModuleElement) + elif (isinstance(x, Vector) and x.parent() is self._parent.vector_space(map=False)): g = (<pari_gen>self._parent._gen_pari).g t = g[1] # codeword: t_FF_FpXQ, t_FF_Flxq, t_FF_F2xq @@ -464,13 +468,13 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): if t == t_FF_FpXQ: f = cgetg(n + 2, t_POL) set_gel(f, 1, gmael(g, 2, 1)) - for i in xrange(n): + for i in range(n): xi = Integer(x[i]) set_gel(f, i + 2, _new_GEN_from_mpz_t(xi.value)) elif t == t_FF_Flxq or t == t_FF_F2xq: f = cgetg(n + 2, t_VECSMALL) set_gel(f, 1, gmael(g, 2, 1)) - for i in xrange(n): + for i in range(n): set_uel(f, i + 2, x[i]) if t == t_FF_F2xq: f = Flx_to_F2x(f) @@ -496,7 +500,13 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): self.construct_from(x.constant_coefficient()) elif isinstance(x, list): - if len(x) == self._parent.degree(): + n = len(x) + if n == 0: + self.construct_from(None) + elif n == 1: + Fp = self._parent.base_ring() + self.construct_from(Fp(x[0])) + elif n == self._parent.degree(): self.construct_from(self._parent.vector_space(map=False)(x)) else: Fp = self._parent.base_ring() @@ -850,6 +860,61 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): x.construct(FF_pow(self.val, (<pari_gen>exp).g)) return x + def pth_power(FiniteFieldElement_pari_ffelt self, int k=1): + r""" + Return the `(p^k)^{th}` power of ``self``, where `p` is the + characteristic of the field. + + INPUT: + + - ``k`` -- integer (default: 1); must fit in a C ``int`` + + Note that if `k` is negative, then this computes the appropriate root. + + TESTS:: + + sage: F.<a> = GF(13^64, impl='pari_ffelt'); F + Finite Field in a of size 13^64 + sage: x = F.random_element() + sage: x.pth_power(0) == x + True + sage: x.pth_power(1) == x**13 + True + sage: x.pth_power(2) == x**(13**2) + True + sage: x.pth_power(-1)**13 == x + True + + sage: F.<a> = GF(127^16, impl='pari_ffelt'); F + Finite Field in a of size 127^16 + sage: x = F.random_element() + sage: x.pth_power(0) == x + True + sage: x.pth_power(1) == x**127 + True + sage: x.pth_power(2) == x**(127**2) + True + sage: x.pth_power(-1)**127 == x + True + """ + cdef int n = int(self._parent.degree()) + if k % n == 0: + return self + cdef Integer p = self._parent.characteristic() + if k == 1 and (p < 100 or p.bit_length()**2 < n): + # For extremely small primes or very large extension degrees, + # exponentiation is faster. + return self**p + # Otherwise use PARI field morphism (evaluation of a Fp polynomial + # at the image of the generator). + f = self._parent._pari_frobenius(k) + cdef FiniteFieldElement_pari_ffelt x = self._new() + sig_on() + x.construct(ffmap((<pari_gen>f).g, self.val)) + return x + + frobenius = pth_power + def polynomial(self, name=None): """ Return the unique representative of ``self`` as a polynomial @@ -977,7 +1042,7 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): If ``extend`` is ``True``, a square root is chosen in an extension field if necessary. If ``extend`` is ``False``, a - ValueError is raised if the element is not a square in the + :class:`ValueError` is raised if the element is not a square in the base field. .. WARNING:: @@ -1265,9 +1330,10 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): EXAMPLES:: + sage: # needs sage.libs.gap sage: F = FiniteField(2^3, 'aa', impl='pari_ffelt') sage: aa = F.multiplicative_generator() - sage: gap(aa) # indirect doctest + sage: gap(aa) # indirect doctest Z(2^3) sage: b = F.multiplicative_generator() sage: a = b^3 @@ -1282,6 +1348,7 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): You can specify the instance of the Gap interpreter that is used:: + sage: # needs sage.libs.gap sage: F = FiniteField(next_prime(200)^2, 'a', impl='pari_ffelt') sage: a = F.multiplicative_generator() sage: a._gap_ (gap) @@ -1291,6 +1358,7 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): Gap only supports relatively small finite fields:: + sage: # needs sage.libs.gap sage: F = FiniteField(next_prime(1000)^2, 'a', impl='pari_ffelt') sage: a = F.multiplicative_generator() sage: a._gap_init_() diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index 285412aa5bd..4e799ad57e8 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -1,11 +1,12 @@ +# sage.doctest: needs sage.rings.finite_rings """ Base class for finite fields TESTS:: - sage: K.<a> = NumberField(x^2 + 1) - sage: F = K.factor(3)[0][0].residue_field() - sage: loads(dumps(F)) == F + sage: K.<a> = NumberField(x^2 + 1) # needs sage.rings.number_field + sage: F = K.factor(3)[0][0].residue_field() # needs sage.rings.number_field + sage: loads(dumps(F)) == F # needs sage.rings.number_field True AUTHORS: @@ -27,7 +28,7 @@ AUTHORS: # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** cimport cython @@ -35,7 +36,6 @@ from cysignals.signals cimport sig_check from cpython.array cimport array from sage.categories.finite_fields import FiniteFields -from sage.structure.parent cimport Parent from sage.misc.persist import register_unpickle_override from sage.misc.cachefunc import cached_method from sage.misc.prandom import randrange @@ -226,13 +226,14 @@ cdef class FiniteField(Field): EXAMPLES:: - sage: GF(97,'a')._magma_init_(magma) # optional - magma + sage: # optional - magma + sage: GF(97,'a')._magma_init_(magma) 'GF(97)' - sage: GF(9,'a')._magma_init_(magma) # optional - magma + sage: GF(9,'a')._magma_init_(magma) 'SageCreateWithNames(ext<GF(3)|_sage_[...]![GF(3)!2,GF(3)!2,GF(3)!1]>,["a"])' - sage: magma(GF(9,'a')) # optional - magma + sage: magma(GF(9,'a')) Finite field of size 3^2 - sage: magma(GF(9,'a')).1 # optional - magma + sage: magma(GF(9,'a')).1 a """ if self.degree() == 1: @@ -327,7 +328,7 @@ cdef class FiniteField(Field): sage: p = next_prime(2^64) sage: k.<a> = FiniteField(p^2, impl="pari") sage: it = iter(k); it - <generator object at ...> + <...generator object at ...> sage: [next(it) for i in range(10)] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] @@ -337,11 +338,11 @@ cdef class FiniteField(Field): sage: L = [] sage: from sage.rings.finite_rings.finite_field_base import FiniteField - sage: for impl in ("givaro", "pari", "ntl"): - ....: k = GF(8, impl=impl, names="z") - ....: print(list(FiniteField.__iter__(k))) + sage: print(list(FiniteField.__iter__(GF(8, impl="givaro", names="z")))) # needs sage.libs.linbox [0, 1, z, z + 1, z^2, z^2 + 1, z^2 + z, z^2 + z + 1] + sage: print(list(FiniteField.__iter__(GF(8, impl="pari", names="z")))) [0, 1, z, z + 1, z^2, z^2 + 1, z^2 + z, z^2 + z + 1] + sage: print(list(FiniteField.__iter__(GF(8, impl="ntl", names="z")))) # needs sage.libs.ntl [0, 1, z, z + 1, z^2, z^2 + 1, z^2 + z, z^2 + z + 1] """ cdef Py_ssize_t n = self.degree() @@ -537,8 +538,9 @@ cdef class FiniteField(Field): def _squarefree_decomposition_univariate_polynomial(self, f): """ - Return the square-free decomposition of this polynomial. This is a - partial factorization into square-free, coprime polynomials. + Return the square-free decomposition of this polynomial. + + This is a partial factorization into square-free, coprime polynomials. This is a helper method for :meth:`sage.rings.polynomial.squarefree_decomposition`. @@ -547,8 +549,8 @@ cdef class FiniteField(Field): - ``f`` -- a univariate non-zero polynomial over this field - ALGORITHM; [Coh1993]_, algorithm 3.4.2 which is basically the algorithm in - [Yun1976]_ with special treatment for powers divisible by `p`. + ALGORITHM: [Coh1993]_, Algorithm 3.4.2 which is basically the algorithm + in [Yun1976]_ with special treatment for powers divisible by `p`. EXAMPLES:: @@ -576,53 +578,70 @@ cdef class FiniteField(Field): ....: for j in range(len(F)): ....: if i == j: continue ....: assert gcd(F[i][0], F[j][0]) == 1 + + Check that :trac:`35323` is fixed:: + + sage: R.<x> = GF(2)[] + sage: (x^2 + 1).squarefree_decomposition() + (x + 1)^2 + sage: R.<x> = PolynomialRing(GF(65537), sparse=True) + sage: (x^65537 + 2).squarefree_decomposition() + (x + 2)^65537 + """ from sage.structure.factorization import Factorization if f.degree() == 0: return Factorization([], unit=f[0]) - factors = [] - p = self.characteristic() + cdef Py_ssize_t i, k + cdef list factors = [] + cdef Integer p = Integer(self.characteristic()) unit = f.leading_coefficient() T0 = f.monic() - e = 1 - if T0.degree() > 0: + cdef Integer e = Integer(1) + cdef Integer T0_deg = T0.degree() + if T0_deg > 0: + P = T0.parent() der = T0.derivative() + pth_root = self.frobenius_endomorphism(-1) while der.is_zero(): - T0 = T0.parent()([T0[p*i].pth_root() for i in range(T0.degree()//p + 1)]) + T0 = P([pth_root(T0[p*i]) for i in range(T0_deg//p + 1)]) + T0_deg //= p if T0 == 1: raise RuntimeError der = T0.derivative() - e = e*p + e *= p T = T0.gcd(der) V = T0 // T k = 0 - while T0.degree() > 0: + while T0_deg > 0: k += 1 if p.divides(k): T = T // V k += 1 W = V.gcd(T) if W.degree() < V.degree(): - factors.append((V // W, e*k)) + factors.append((V // W, e * k)) V = W T = T // V if V.degree() == 0: if T.degree() == 0: break # T is of the form sum_{i=0}^n t_i X^{pi} - T0 = T0.parent()([T[p*i].pth_root() for i in range(T.degree()//p + 1)]) + T0 = P([pth_root(T[p*i]) for i in range(T.degree()//p + 1)]) + T0_deg //= p der = T0.derivative() - e = p*e + e *= p while der.is_zero(): - T0 = T0.parent()([T0[p*i].pth_root() for i in range(T0.degree()//p + 1)]) + T0 = P([pth_root(T0[p*i]) for i in range(T0_deg//p + 1)]) + T0_deg //= p der = T0.derivative() - e = p*e + e *= p T = T0.gcd(der) V = T0 // T k = 0 else: - T = T//V + T = T // V return Factorization(factors, unit=unit, sort=False) @@ -930,7 +949,7 @@ cdef class FiniteField(Field): sage: GF(3, 'a').is_prime_field() True """ - return self.degree()==1 + return self.degree() == 1 def modulus(self): r""" @@ -993,7 +1012,7 @@ cdef class FiniteField(Field): The given modulus is always made monic:: - sage: k.<a> = GF(7^2, modulus=2*x^2-3, impl="pari_ffelt") + sage: k.<a> = GF(7^2, modulus=2*x^2 - 3, impl="pari_ffelt") sage: k.modulus() x^2 + 2 @@ -1003,19 +1022,19 @@ cdef class FiniteField(Field): sage: GF(2, impl="modn").modulus() x + 1 - sage: GF(2, impl="givaro").modulus() + sage: GF(2, impl="givaro").modulus() # needs sage.libs.linbox x + 1 - sage: GF(2, impl="ntl").modulus() + sage: GF(2, impl="ntl").modulus() # needs sage.libs.ntl x + 1 sage: GF(2, impl="modn", modulus=x).modulus() x - sage: GF(2, impl="givaro", modulus=x).modulus() + sage: GF(2, impl="givaro", modulus=x).modulus() # needs sage.libs.linbox x - sage: GF(2, impl="ntl", modulus=x).modulus() + sage: GF(2, impl="ntl", modulus=x).modulus() # needs sage.libs.ntl x - sage: GF(13^2, 'a', impl="givaro", modulus=x^2+2).modulus() + sage: GF(13^2, 'a', impl="givaro", modulus=x^2 + 2).modulus() # needs sage.libs.linbox x^2 + 2 - sage: GF(13^2, 'a', impl="pari_ffelt", modulus=x^2+2).modulus() + sage: GF(13^2, 'a', impl="pari_ffelt", modulus=x^2 + 2).modulus() # needs sage.libs.pari x^2 + 2 """ # Normally, this is set by the constructor of the implementation @@ -1067,6 +1086,7 @@ cdef class FiniteField(Field): sage: f(F.gen()) 0 + sage: # needs sage.libs.ntl sage: k.<a> = GF(2^20, impl='ntl') sage: k.polynomial() a^20 + a^10 + a^9 + a^7 + a^6 + a^5 + a^4 + a + 1 @@ -1103,12 +1123,12 @@ cdef class FiniteField(Field): EXAMPLES:: sage: k = GF(19^4, 'a') - sage: k.random_element().parent() is k + sage: k.random_element().parent() is k # needs sage.modules True Passes extra positional or keyword arguments through:: - sage: k.random_element(prob=0) + sage: k.random_element(prob=0) # needs sage.modules 0 """ @@ -1125,7 +1145,7 @@ cdef class FiniteField(Field): EXAMPLES:: sage: k = GF(2^8,'a') - sage: k.some_elements() # random output + sage: k.some_elements() # random output # needs sage.modules [a^4 + a^3 + 1, a^6 + a^4 + a^3, a^5 + a^4 + a, a^2 + a] """ return [self.random_element() for i in range(4)] @@ -1153,7 +1173,7 @@ cdef class FiniteField(Field): else: return PolynomialRing(GF(self.characteristic()), variable_name) - def free_module(self, base=None, basis=None, map=None, subfield=None): + def free_module(self, base=None, basis=None, map=True): """ Return the vector space over the subfield isomorphic to this finite field as a vector space, along with the isomorphisms. @@ -1186,9 +1206,10 @@ cdef class FiniteField(Field): EXAMPLES:: - sage: GF(27,'a').vector_space(map=False) + sage: GF(27,'a').vector_space(map=False) # needs sage.modules Vector space of dimension 3 over Finite Field of size 3 + sage: # needs sage.modules sage: F = GF(8) sage: E = GF(64) sage: V, from_V, to_V = E.vector_space(F, map=True) @@ -1203,6 +1224,7 @@ cdef class FiniteField(Field): sage: all(to_V(c * e) == c * to_V(e) for e in E for c in F) True + sage: # needs sage.modules sage: basis = [E.gen(), E.gen() + 1] sage: W, from_W, to_W = E.vector_space(F, basis, map=True) sage: all(from_W(to_W(e)) == e for e in E) @@ -1215,7 +1237,8 @@ cdef class FiniteField(Field): (1, 0) (0, 1) - sage: F = GF(9, 't', modulus=(x^2+x-1)) + sage: # needs sage.modules + sage: F = GF(9, 't', modulus=x^2 + x - 1) sage: E = GF(81) sage: h = Hom(F,E).an_element() sage: V, from_V, to_V = E.vector_space(h, map=True) @@ -1230,16 +1253,12 @@ cdef class FiniteField(Field): sage: all(to_V(h(c) * e) == c * to_V(e) for e in E for c in F) True """ - from sage.modules.all import VectorSpace + if base is None and self.__vector_space is not None and not map: + # A very common case: return as early as possible. + return self.__vector_space + + from sage.modules.free_module import VectorSpace from sage.categories.morphism import is_Morphism - if subfield is not None: - if base is not None: - raise ValueError - deprecation(28481, "The subfield keyword argument has been renamed to base") - base = subfield - if map is None: - deprecation(28481, "The default value for map will be changing to True. To keep the current behavior, explicitly pass map=False.") - map = False if base is None: base = self.prime_subfield() @@ -1260,13 +1279,12 @@ cdef class FiniteField(Field): else: raise ValueError("{} is not a subfield".format(base)) - if map is False: # shortcut + if map is False: # shortcut return V if inclusion_map is None: inclusion_map = self.coerce_map_from(base) - from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix from .maps_finite_field import ( MorphismVectorSpaceToFiniteField, MorphismFiniteFieldToVectorSpace) @@ -1356,7 +1374,7 @@ cdef class FiniteField(Field): return True if isinstance(R, sage.rings.abc.IntegerModRing) and self.characteristic().divides(R.characteristic()): return R.hom((self.one(),), check=False) - if is_FiniteField(R): + if isinstance(R, FiniteField): if R is self: return True from .residue_field import ResidueField_generic @@ -1375,16 +1393,16 @@ cdef class FiniteField(Field): EXAMPLES:: - sage: K.<a> = Qq(49); k = K.residue_field() - sage: k.convert_map_from(K) + sage: K.<a> = Qq(49); k = K.residue_field() # needs sage.rings.padics + sage: k.convert_map_from(K) # needs sage.rings.padics Reduction morphism: From: 7-adic Unramified Extension Field in a defined by x^2 + 6*x + 3 To: Finite Field in a0 of size 7^2 Check that :trac:`8240 is resolved:: - sage: R.<a> = Zq(81); k = R.residue_field() - sage: k.convert_map_from(R) + sage: R.<a> = Zq(81); k = R.residue_field() # needs sage.rings.padics + sage: k.convert_map_from(R) # needs sage.rings.padics Reduction morphism: From: 3-adic Unramified Extension Ring in a defined by x^4 + 2*x^3 + 2 To: Finite Field in a0 of size 3^4 @@ -1491,13 +1509,16 @@ cdef class FiniteField(Field): To: Finite Field in b of size 5^2 Defn: 1 |--> 1 sage: f.parent() - Set of field embeddings from Finite Field of size 5 to Finite Field in b of size 5^2 + Set of field embeddings + from Finite Field of size 5 + to Finite Field in b of size 5^2 Extensions of non-prime finite fields by polynomials are not yet supported: we fall back to generic code:: sage: k.extension(x^5 + x^2 + x - 1) - Univariate Quotient Polynomial Ring in x over Finite Field in z4 of size 3^4 with modulus x^5 + x^2 + x + 2 + Univariate Quotient Polynomial Ring in x over Finite Field in z4 of size 3^4 + with modulus x^5 + x^2 + x + 2 TESTS: @@ -1521,7 +1542,7 @@ cdef class FiniteField(Field): True """ from .finite_field_constructor import GF - from sage.rings.polynomial.polynomial_element import is_Polynomial + from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.integer import Integer if name is None and names is not None: name = names @@ -1532,7 +1553,7 @@ cdef class FiniteField(Field): E = GF((self.characteristic(), modulus), name=name, **kwds) elif isinstance(modulus, (list, tuple)): E = GF((self.characteristic(), len(modulus) - 1), name=name, modulus=modulus, **kwds) - elif is_Polynomial(modulus): + elif isinstance(modulus, Polynomial): if modulus.change_ring(self).is_irreducible(): E = GF((self.characteristic(), modulus.degree()), name=name, modulus=modulus, **kwds) else: @@ -1776,12 +1797,14 @@ cdef class FiniteField(Field): Ring morphism: From: Finite Field in z3 of size 2^3 To: Finite Field in z21 of size 2^21 - Defn: z3 |--> z21^20 + z21^19 + z21^17 + z21^15 + z21^11 + z21^9 + z21^8 + z21^6 + z21^2), + Defn: z3 |--> z21^20 + z21^19 + z21^17 + z21^15 + z21^11 + + z21^9 + z21^8 + z21^6 + z21^2), (Finite Field in z7 of size 2^7, Ring morphism: From: Finite Field in z7 of size 2^7 To: Finite Field in z21 of size 2^21 - Defn: z7 |--> z21^20 + z21^19 + z21^17 + z21^15 + z21^14 + z21^6 + z21^4 + z21^3 + z21), + Defn: z7 |--> z21^20 + z21^19 + z21^17 + z21^15 + z21^14 + + z21^6 + z21^4 + z21^3 + z21), (Finite Field in z21 of size 2^21, Identity endomorphism of Finite Field in z21 of size 2^21)] """ @@ -1924,8 +1947,8 @@ cdef class FiniteField(Field): sage: Frob = k.frobenius_endomorphism(); Frob Frobenius endomorphism t |--> t^3 on Finite Field in t of size 3^5 - sage: a = k.random_element() - sage: Frob(a) == a^3 + sage: a = k.random_element() # needs sage.modules + sage: Frob(a) == a^3 # needs sage.modules True We can specify a power:: @@ -1961,8 +1984,8 @@ cdef class FiniteField(Field): EXAMPLES:: - sage: G = GF(3^6).galois_group() - sage: G + sage: # needs sage.groups + sage: G = GF(3^6).galois_group(); G Galois group C6 of GF(3^6) sage: F = G.gen() sage: F^2 @@ -2018,13 +2041,14 @@ cdef class FiniteField(Field): EXAMPLES:: sage: F.<a> = GF(2^4) - sage: F.dual_basis(basis=None, check=False) + sage: F.dual_basis(basis=None, check=False) # needs sage.modules [a^3 + 1, a^2, a, 1] We can test that the dual basis returned satisfies the defining property of a dual basis: `\mathrm{Tr}(e_i d_j) = \delta_{i,j}, 0 \leq i,j \leq n-1` :: + sage: # needs sage.modules sage: F.<a> = GF(7^4) sage: e = [4*a^3, 2*a^3 + a^2 + 3*a + 5, ....: 3*a^3 + 5*a^2 + 4*a + 2, 2*a^3 + 2*a^2 + 2] @@ -2038,17 +2062,18 @@ cdef class FiniteField(Field): We can test that if `d` is the dual basis of `e`, then `e` is the dual basis of `d`:: + sage: # needs sage.modules sage: F.<a> = GF(7^8) sage: e = [a^0, a^1, a^2, a^3, a^4, a^5, a^6, a^7] sage: d = F.dual_basis(e, check=False); d [6*a^6 + 4*a^5 + 4*a^4 + a^3 + 6*a^2 + 3, - 6*a^7 + 4*a^6 + 4*a^5 + 2*a^4 + a^2, - 4*a^6 + 5*a^5 + 5*a^4 + 4*a^3 + 5*a^2 + a + 6, - 5*a^7 + a^6 + a^4 + 4*a^3 + 4*a^2 + 1, - 2*a^7 + 5*a^6 + a^5 + a^3 + 5*a^2 + 2*a + 4, - a^7 + 2*a^6 + 5*a^5 + a^4 + 5*a^2 + 4*a + 4, - a^7 + a^6 + 2*a^5 + 5*a^4 + a^3 + 4*a^2 + 4*a + 6, - 5*a^7 + a^6 + a^5 + 2*a^4 + 5*a^3 + 6*a] + 6*a^7 + 4*a^6 + 4*a^5 + 2*a^4 + a^2, + 4*a^6 + 5*a^5 + 5*a^4 + 4*a^3 + 5*a^2 + a + 6, + 5*a^7 + a^6 + a^4 + 4*a^3 + 4*a^2 + 1, + 2*a^7 + 5*a^6 + a^5 + a^3 + 5*a^2 + 2*a + 4, + a^7 + 2*a^6 + 5*a^5 + a^4 + 5*a^2 + 4*a + 4, + a^7 + a^6 + 2*a^5 + 5*a^4 + a^3 + 4*a^2 + 4*a + 6, + 5*a^7 + a^6 + a^5 + 2*a^4 + 5*a^3 + 6*a] sage: F.dual_basis(d) [1, a, a^2, a^3, a^4, a^5, a^6, a^7] @@ -2056,12 +2081,12 @@ cdef class FiniteField(Field): :: sage: F.<a> = GF(2^3) - sage: F.dual_basis([a], check=True) + sage: F.dual_basis([a], check=True) # needs sage.modules Traceback (most recent call last): ... ValueError: basis length should be 3, not 1 - sage: F.dual_basis([a^0, a, a^0 + a], check=True) + sage: F.dual_basis([a^0, a, a^0 + a], check=True) # needs sage.modules Traceback (most recent call last): ... ValueError: value of 'basis' keyword is not a basis @@ -2115,10 +2140,14 @@ def is_FiniteField(R): Return whether the implementation of ``R`` has the interface provided by the standard finite field implementation. + This function is deprecated. + EXAMPLES:: sage: from sage.rings.finite_rings.finite_field_base import is_FiniteField sage: is_FiniteField(GF(9,'a')) + doctest:...: DeprecationWarning: the function is_FiniteField is deprecated; use isinstance(x, sage.rings.finite_rings.finite_field_base.FiniteField) instead + See https://github.com/sagemath/sage/issues/32664 for details. True sage: is_FiniteField(GF(next_prime(10^10))) True @@ -2128,4 +2157,6 @@ def is_FiniteField(R): sage: is_FiniteField(Integers(7)) False """ + from sage.misc.superseded import deprecation + deprecation(32664, "the function is_FiniteField is deprecated; use isinstance(x, sage.rings.finite_rings.finite_field_base.FiniteField) instead") return isinstance(R, FiniteField) diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index e42b2bed2dd..2c5dfbc664f 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Finite fields @@ -72,7 +73,7 @@ :: - sage: k = GF(5^2,'c'); type(k) + sage: k = GF(5^2,'c'); type(k) # needs sage.libs.linbox <class 'sage.rings.finite_rings.finite_field_givaro.FiniteField_givaro_with_category'> One can also give the cardinality `q=p^n` as the tuple `(p,n)`:: @@ -82,7 +83,7 @@ :: - sage: k = GF(2^16,'c'); type(k) + sage: k = GF(2^16,'c'); type(k) # needs sage.libs.ntl <class 'sage.rings.finite_rings.finite_field_ntl_gf2e.FiniteField_ntl_gf2e_with_category'> :: @@ -124,6 +125,7 @@ :: + sage: # needs sage.libs.linbox sage: k = GF(9,'alpha'); type(k) <class 'sage.rings.finite_rings.finite_field_givaro.FiniteField_givaro_with_category'> sage: k.base_ring() @@ -173,7 +175,7 @@ from collections import defaultdict from sage.structure.category_object import normalize_names - +from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.integer import Integer # the import below is just a redirection @@ -188,6 +190,12 @@ except ImportError: FiniteField_givaro = None +try: + from .finite_field_ntl_gf2e import FiniteField_ntl_gf2e +except ImportError: + FiniteField_ntl_gf2e = None + + from sage.structure.factory import UniqueFactory @@ -436,8 +444,8 @@ class FiniteFieldFactory(UniqueFactory): Using pseudo-Conway polynomials is slow for highly composite extension degrees:: - sage: k = GF(3^120) # long time -- about 3 seconds - sage: GF(3^40).gen().minimal_polynomial()(k.gen()^((3^120-1)/(3^40-1))) # long time because of previous line + sage: k = GF(3^120) # long time (about 3 seconds) + sage: GF(3^40).gen().minimal_polynomial()(k.gen()^((3^120-1)/(3^40-1))) # long time (because of previous line) 0 Before :trac:`17569`, the boolean keyword argument ``conway`` @@ -501,12 +509,12 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, """ EXAMPLES:: - sage: GF.create_key_and_extra_args(9, 'a') + sage: GF.create_key_and_extra_args(9, 'a') # needs sage.libs.linbox ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True, True, True), {}) The order `q` can also be given as a pair `(p,n)`:: - sage: GF.create_key_and_extra_args((3, 2), 'a') + sage: GF.create_key_and_extra_args((3, 2), 'a') # needs sage.libs.linbox ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True, True, True), {}) We do not take invalid keyword arguments and raise a value error @@ -520,28 +528,28 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, Moreover, ``repr`` and ``elem_cache`` are ignored when not using givaro:: - sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', repr='poly') + sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', repr='poly') # needs sage.libs.ntl ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None, True, True), {}) - sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', elem_cache=False) + sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', elem_cache=False) # needs sage.libs.ntl ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None, True, True), {}) - sage: GF(16, impl='ntl') is GF(16, impl='ntl', repr='foo') + sage: GF(16, impl='ntl') is GF(16, impl='ntl', repr='foo') # needs sage.libs.ntl True We handle extra arguments for the givaro finite field and create unique objects for their defaults:: - sage: GF(25, impl='givaro') is GF(25, impl='givaro', repr='poly') + sage: GF(25, impl='givaro') is GF(25, impl='givaro', repr='poly') # needs sage.libs.linbox True - sage: GF(25, impl='givaro') is GF(25, impl='givaro', elem_cache=True) + sage: GF(25, impl='givaro') is GF(25, impl='givaro', elem_cache=True) # needs sage.libs.linbox True - sage: GF(625, impl='givaro') is GF(625, impl='givaro', elem_cache=False) + sage: GF(625, impl='givaro') is GF(625, impl='givaro', elem_cache=False) # needs sage.libs.linbox True We explicitly take ``structure``, ``implementation`` and ``prec`` attributes for compatibility with :class:`~sage.categories.pushout.AlgebraicExtensionFunctor` but we ignore them as they are not used, see :trac:`21433`:: - sage: GF.create_key_and_extra_args(9, 'a', structure=None) + sage: GF.create_key_and_extra_args(9, 'a', structure=None) # needs sage.libs.linbox ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True, True, True), {}) TESTS:: @@ -618,9 +626,9 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, name = normalize_names(1, name) if impl is None: - if order < zech_log_bound: + if order < zech_log_bound and FiniteField_givaro is not None: impl = 'givaro' - elif p == 2: + elif p == 2 and FiniteField_ntl_gf2e is not None: impl = 'ntl' else: impl = 'pari_ffelt' @@ -641,7 +649,7 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, else: self._modulus_cache[order][modulus] = modulus = R.irreducible_element(n, algorithm=modulus) else: - if sage.rings.polynomial.polynomial_element.is_Polynomial(modulus): + if isinstance(modulus, Polynomial): modulus = modulus.change_variable_name('x') modulus = R(modulus).monic() @@ -677,8 +685,8 @@ def create_object(self, version, key, **kwds): We try to create finite fields with various implementations:: sage: k = GF(2, impl='modn') - sage: k = GF(2, impl='givaro') - sage: k = GF(2, impl='ntl') + sage: k = GF(2, impl='givaro') # needs sage.libs.linbox + sage: k = GF(2, impl='ntl') # needs sage.libs.ntl sage: k = GF(2, impl='pari') Traceback (most recent call last): ... @@ -691,18 +699,18 @@ def create_object(self, version, key, **kwds): Traceback (most recent call last): ... ValueError: the 'modn' implementation requires a prime order - sage: k.<a> = GF(2^15, impl='givaro') - sage: k.<a> = GF(2^15, impl='ntl') + sage: k.<a> = GF(2^15, impl='givaro') # needs sage.libs.linbox + sage: k.<a> = GF(2^15, impl='ntl') # needs sage.libs.ntl sage: k.<a> = GF(2^15, impl='pari') sage: k.<a> = GF(3^60, impl='modn') Traceback (most recent call last): ... ValueError: the 'modn' implementation requires a prime order - sage: k.<a> = GF(3^60, impl='givaro') + sage: k.<a> = GF(3^60, impl='givaro') # needs sage.libs.linbox Traceback (most recent call last): ... ValueError: q must be < 2^16 - sage: k.<a> = GF(3^60, impl='ntl') + sage: k.<a> = GF(3^60, impl='ntl') # needs sage.libs.ntl Traceback (most recent call last): ... ValueError: q must be a 2-power @@ -771,7 +779,6 @@ def create_object(self, version, key, **kwds): if impl == 'givaro': K = FiniteField_givaro(order, name, modulus, repr, elem_cache) elif impl == 'ntl': - from .finite_field_ntl_gf2e import FiniteField_ntl_gf2e K = FiniteField_ntl_gf2e(order, name, modulus) elif impl == 'pari_ffelt' or impl == 'pari': from .finite_field_pari_ffelt import FiniteField_pari_ffelt @@ -791,24 +798,32 @@ def create_object(self, version, key, **kwds): def is_PrimeFiniteField(x): """ - Returns True if x is a prime finite field. + Return ``True`` if ``x`` is a prime finite field. + + This function is deprecated. EXAMPLES:: sage: from sage.rings.finite_rings.finite_field_constructor import is_PrimeFiniteField sage: is_PrimeFiniteField(QQ) + doctest:...: DeprecationWarning: the function is_PrimeFiniteField is deprecated; use isinstance(x, sage.rings.finite_rings.finite_field_base.FiniteField) and x.is_prime_field() instead + See https://github.com/sagemath/sage/issues/32664 for details. False sage: is_PrimeFiniteField(GF(7)) True - sage: is_PrimeFiniteField(GF(7^2,'a')) + sage: is_PrimeFiniteField(GF(7^2, 'a')) False - sage: is_PrimeFiniteField(GF(next_prime(10^90,proof=False))) + sage: is_PrimeFiniteField(GF(next_prime(10^90, proof=False))) True """ + from sage.misc.superseded import deprecation + deprecation(32664, "the function is_PrimeFiniteField is deprecated; use isinstance(x, sage.rings.finite_rings.finite_field_base.FiniteField) and x.is_prime_field() instead") + from .finite_field_prime_modn import FiniteField_prime_modn from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_generic return isinstance(x, FiniteField_prime_modn) or \ (isinstance(x, FiniteField_generic) and x.degree() == 1) + zech_log_bound = 2**16 diff --git a/src/sage/rings/finite_rings/finite_field_givaro.py b/src/sage/rings/finite_rings/finite_field_givaro.py index b67df86bb30..2dd96beeb34 100644 --- a/src/sage/rings/finite_rings/finite_field_givaro.py +++ b/src/sage/rings/finite_rings/finite_field_givaro.py @@ -137,8 +137,8 @@ def __init__(self, q, name="a", modulus=None, repr="poly", cache=False): from .finite_field_constructor import GF FiniteField.__init__(self, GF(p), name, normalize=False) - from sage.rings.polynomial.polynomial_element import is_Polynomial - if not is_Polynomial(modulus): + from sage.rings.polynomial.polynomial_element import Polynomial + if not isinstance(modulus, Polynomial): raise TypeError("modulus must be a polynomial") self._cache = Cache_givaro(self, p, k, modulus, repr, cache) @@ -510,7 +510,7 @@ def _pari_modulus(self): Mod(1, 3)*a^4 + Mod(2, 3)*a^3 + Mod(2, 3) """ f = pari(str(self.modulus())) - return f.subst('x', 'a') * pari("Mod(1,%s)"%self.characteristic()) + return f.subst('x', 'a') * pari("Mod(1,%s)" % self.characteristic()) def __iter__(self): """ diff --git a/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py b/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py index 82004502674..654f7a2b54b 100644 --- a/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py +++ b/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py @@ -33,14 +33,7 @@ def late_import(): """ if "GF2" in globals(): return - global is_FiniteField, exists_conway_polynomial, conway_polynomial, Cache_ntl_gf2e, GF, GF2, is_Polynomial - - import sage.rings.finite_rings.finite_field_base - is_FiniteField = sage.rings.finite_rings.finite_field_base.is_FiniteField - - import sage.rings.finite_rings.conway_polynomials - exists_conway_polynomial = sage.rings.finite_rings.conway_polynomials.exists_conway_polynomial - conway_polynomial = sage.rings.finite_rings.conway_polynomials.conway_polynomial + global Cache_ntl_gf2e, GF, GF2 import sage.rings.finite_rings.element_ntl_gf2e Cache_ntl_gf2e = sage.rings.finite_rings.element_ntl_gf2e.Cache_ntl_gf2e @@ -49,8 +42,6 @@ def late_import(): GF = sage.rings.finite_rings.finite_field_constructor.GF GF2 = GF(2) - import sage.rings.polynomial.polynomial_element - is_Polynomial = sage.rings.polynomial.polynomial_element.is_Polynomial class FiniteField_ntl_gf2e(FiniteField): """ @@ -138,8 +129,8 @@ def __init__(self, q, names="a", modulus=None, repr="poly"): raise ValueError("q must be a 2-power") FiniteField.__init__(self, GF2, names, normalize=True) - from sage.rings.polynomial.polynomial_element import is_Polynomial - if not is_Polynomial(modulus): + from sage.rings.polynomial.polynomial_element import Polynomial + if not isinstance(modulus, Polynomial): raise TypeError("modulus must be a polynomial") self._cache = Cache_ntl_gf2e(self, k, modulus) @@ -314,4 +305,4 @@ def _pari_modulus(self): Mod(1, 2)*a^16 + Mod(1, 2)*a^5 + Mod(1, 2)*a^3 + Mod(1, 2)*a^2 + Mod(1, 2) """ f = pari(str(self.modulus())) - return f.subst('x', 'a') * pari("Mod(1,%s)"%self.characteristic()) + return f.subst('x', 'a') * pari("Mod(1,%s)" % self.characteristic()) diff --git a/src/sage/rings/finite_rings/finite_field_pari_ffelt.py b/src/sage/rings/finite_rings/finite_field_pari_ffelt.py index 906c91d6ba8..c60a7a563a7 100644 --- a/src/sage/rings/finite_rings/finite_field_pari_ffelt.py +++ b/src/sage/rings/finite_rings/finite_field_pari_ffelt.py @@ -124,6 +124,9 @@ def __init__(self, p, modulus, name=None): self._one_element = self.element_class(self, 1) self._gen = self.element_class(self, self._gen_pari) + # Cache for Frobenius endomorphisms (O(n) field elements) + self.__pari_frobenius_powers = [] + Element = FiniteFieldElement_pari_ffelt def __reduce__(self): @@ -201,3 +204,33 @@ def degree(self): 20 """ return self._degree + + def _pari_frobenius(self, k=1): + """ + Return a cached PARI Frobenius endomorphism (internally defined + by the image of the generator). + + TESTS:: + + sage: F = FiniteField(37^10, 'a', impl='pari_ffelt') + sage: x = F.random_element() # needs sage.modules + sage: all(x**(37**k) == F(F._pari_frobenius(k).ffmap(x)) # needs sage.modules + ....: for k in range(1, 30) if k % 10 != 0) + True + sage: F(F._pari_frobenius(-1).ffmap(x))**37 == x # needs sage.modules + True + """ + k = k % self.degree() + if k == 0: + raise ValueError("_pari_frobenius requires a non-zero exponent") + g = self.gen() + i = len(self.__pari_frobenius_powers) + if i == 0: + self.__pari_frobenius_powers.append(g.__pari__().fffrobenius(1)) + i = 1 + f1 = self.__pari_frobenius_powers[0] + while i < k: + i += 1 + fi = self.__pari_frobenius_powers[-1].ffcompomap(f1) + self.__pari_frobenius_powers.append(fi) + return self.__pari_frobenius_powers[k-1] diff --git a/src/sage/rings/finite_rings/finite_field_prime_modn.py b/src/sage/rings/finite_rings/finite_field_prime_modn.py index afd18b7d64d..95c1803abf4 100644 --- a/src/sage/rings/finite_rings/finite_field_prime_modn.py +++ b/src/sage/rings/finite_rings/finite_field_prime_modn.py @@ -47,7 +47,7 @@ class FiniteField_prime_modn(FiniteField_generic, integer_mod_ring.IntegerModRin sage: FiniteField(3) Finite Field of size 3 - sage: FiniteField(next_prime(1000)) + sage: FiniteField(next_prime(1000)) # needs sage.rings.finite_rings Finite Field of size 1009 """ def __init__(self, p, check=True, modulus=None): @@ -104,8 +104,11 @@ def _coerce_map_from_(self, S): 5 sage: 12 % 7 5 - sage: ZZ.residue_field(7).hom(GF(7))(1) # See trac 11319 + + sage: ZZ.residue_field(7).hom(GF(7))(1) # See trac 11319 # needs sage.rings.finite_rings 1 + + sage: # needs sage.rings.finite_rings sage.rings.number_field sage: K.<w> = QuadraticField(337) # See trac 11319 sage: pp = K.ideal(13).factor()[0][0] sage: RF13 = K.residue_field(pp) @@ -117,19 +120,19 @@ def _coerce_map_from_(self, S): Check that :trac:`19573` is resolved:: - sage: Integers(9).hom(GF(3)) + sage: Integers(9).hom(GF(3)) # needs sage.rings.finite_rings Natural morphism: From: Ring of integers modulo 9 To: Finite Field of size 3 - sage: Integers(9).hom(GF(5)) + sage: Integers(9).hom(GF(5)) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: natural coercion morphism from Ring of integers modulo 9 to Finite Field of size 5 not defined There is no coercion from a `p`-adic ring to its residue field:: - sage: GF(3).has_coerce_map_from(Zp(3)) + sage: GF(3).has_coerce_map_from(Zp(3)) # needs sage.rings.padics False """ if S is int: @@ -155,6 +158,7 @@ def _convert_map_from_(self, R): EXAMPLES:: + sage: # needs sage.rings.padics sage: GF(3).convert_map_from(Qp(3)) Reduction morphism: From: 3-adic Field with capped relative precision 20 @@ -201,6 +205,7 @@ def is_prime_field(self): sage: k.is_prime_field() True + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(3^2) sage: k.is_prime_field() False @@ -271,6 +276,8 @@ def gen(self, n=0): sage: k = GF(13) sage: k.gen() 1 + + sage: # needs sage.rings.finite_rings sage: k = GF(1009, modulus="primitive") sage: k.gen() # this gives a primitive element 11 @@ -304,6 +311,7 @@ def __iter__(self): We can even start iterating over something that would be too big to actually enumerate:: + sage: # needs sage.rings.finite_rings sage: K = GF(next_prime(2^256)) sage: all = iter(K) sage: next(all) @@ -332,6 +340,7 @@ def degree(self): """ return Integer(1) + register_unpickle_override( 'sage.rings.finite_field_prime_modn', 'FiniteField_prime_modn', FiniteField_prime_modn) diff --git a/src/sage/rings/finite_rings/hom_finite_field.pyx b/src/sage/rings/finite_rings/hom_finite_field.pyx index 86d2401ceec..fa38753d79f 100644 --- a/src/sage/rings/finite_rings/hom_finite_field.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings """ Finite field morphisms @@ -106,7 +107,7 @@ from sage.rings.integer cimport Integer from sage.categories.homset import Hom from sage.structure.element cimport Element -from sage.rings.finite_rings.finite_field_base import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_base from sage.rings.morphism cimport RingHomomorphism, RingHomomorphism_im_gens, FrobeniusEndomorphism_generic from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -227,9 +228,9 @@ cdef class FiniteFieldHomomorphism_generic(RingHomomorphism_im_gens): """ domain = parent.domain() codomain = parent.codomain() - if not is_FiniteField(domain): + if not isinstance(domain, FiniteField_base): raise TypeError("The domain is not a finite field or does not provide the required interface for finite fields") - if not is_FiniteField(codomain): + if not isinstance(codomain, FiniteField_base): raise TypeError("The codomain is not a finite field or does not provide the required interface for finite fields") if domain.characteristic() != codomain.characteristic() or codomain.degree() % domain.degree() != 0: raise ValueError("No embedding of %s into %s" % (domain, codomain)) @@ -317,7 +318,7 @@ cdef class FiniteFieldHomomorphism_generic(RingHomomorphism_im_gens): def is_injective(self): """ - Return True since a embedding between finite fields is + Return ``True`` since a embedding between finite fields is always injective. EXAMPLES:: @@ -334,7 +335,7 @@ cdef class FiniteFieldHomomorphism_generic(RingHomomorphism_im_gens): def is_surjective(self): """ - Return true if this embedding is surjective (and hence an + Return ``True`` if this embedding is surjective (and hence an isomorphism. EXAMPLES:: @@ -522,7 +523,7 @@ cdef class FrobeniusEndomorphism_finite_field(FrobeniusEndomorphism_generic): ... TypeError: The domain is not a finite field or does not provide the required interface for finite fields """ - if not is_FiniteField(domain): + if not isinstance(domain, FiniteField_base): raise TypeError("The domain is not a finite field or does not provide the required interface for finite fields") try: n = Integer(n) @@ -619,7 +620,10 @@ cdef class FrobeniusEndomorphism_finite_field(FrobeniusEndomorphism_generic): sage: Frob(t) == t^5 True """ - return x ** self._q + if self.is_identity(): + return x + else: + return x.pth_power(self._power) def order(self): @@ -770,7 +774,7 @@ cdef class FrobeniusEndomorphism_finite_field(FrobeniusEndomorphism_generic): def is_injective(self): """ - Return true since any power of the Frobenius endomorphism + Return ``True`` since any power of the Frobenius endomorphism over a finite field is always injective. EXAMPLES:: @@ -785,7 +789,7 @@ cdef class FrobeniusEndomorphism_finite_field(FrobeniusEndomorphism_generic): def is_surjective(self): """ - Return true since any power of the Frobenius endomorphism + Return ``True`` since any power of the Frobenius endomorphism over a finite field is always surjective. EXAMPLES:: @@ -800,7 +804,7 @@ cdef class FrobeniusEndomorphism_finite_field(FrobeniusEndomorphism_generic): def is_identity(self): """ - Return true if this morphism is the identity morphism. + Return ``True`` if this morphism is the identity morphism. EXAMPLES:: diff --git a/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx b/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx index ad88a240355..aae6c84ab25 100644 --- a/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx @@ -22,13 +22,13 @@ AUTHOR: - Xavier Caruso (2012-06-29) """ -############################################################################# +# ########################################################################### # Copyright (C) 2012 Xavier Caruso <xavier.caruso@normalesup.org> # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ -#**************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -41,7 +41,6 @@ from .hom_prime_finite_field cimport FiniteFieldHomomorphism_prime from sage.categories.homset import Hom from sage.structure.element cimport Element -from sage.rings.morphism cimport RingHomomorphism_im_gens from sage.rings.finite_rings.finite_field_givaro import FiniteField_givaro from .element_givaro cimport FiniteField_givaroElement diff --git a/src/sage/rings/finite_rings/hom_prime_finite_field.pyx b/src/sage/rings/finite_rings/hom_prime_finite_field.pyx index b24c8bbfb3e..e141120d918 100644 --- a/src/sage/rings/finite_rings/hom_prime_finite_field.pyx +++ b/src/sage/rings/finite_rings/hom_prime_finite_field.pyx @@ -24,8 +24,6 @@ AUTHOR: # http://www.gnu.org/licenses/ #**************************************************************************** -from sage.rings.integer cimport Integer - from sage.categories.homset import Hom from sage.structure.element cimport Element @@ -33,8 +31,7 @@ from .hom_finite_field cimport SectionFiniteFieldHomomorphism_generic from .hom_finite_field cimport FiniteFieldHomomorphism_generic from .hom_finite_field cimport FrobeniusEndomorphism_finite_field -from sage.rings.finite_rings.finite_field_base import FiniteField, is_FiniteField -from sage.rings.morphism cimport RingHomomorphism_im_gens +from sage.rings.finite_rings.finite_field_base import FiniteField cdef class SectionFiniteFieldHomomorphism_prime(SectionFiniteFieldHomomorphism_generic): @@ -56,22 +53,22 @@ cdef class FiniteFieldHomomorphism_prime(FiniteFieldHomomorphism_generic): sage: from sage.rings.finite_rings.hom_prime_finite_field import FiniteFieldHomomorphism_prime sage: k = GF(3) - sage: K.<T> = GF(3^4) - sage: f = FiniteFieldHomomorphism_prime(Hom(k, K)); f + sage: K.<T> = GF(3^4) # needs sage.rings.finite_rings + sage: f = FiniteFieldHomomorphism_prime(Hom(k, K)); f # needs sage.rings.finite_rings Ring morphism: From: Finite Field of size 3 To: Finite Field in T of size 3^4 Defn: 1 |--> 1 - sage: k.<t> = GF(3^2) - sage: K.<T> = GF(3^4) - sage: f = FiniteFieldHomomorphism_prime(Hom(k, K)); f + sage: k.<t> = GF(3^2) # needs sage.rings.finite_rings + sage: K.<T> = GF(3^4) # needs sage.rings.finite_rings + sage: f = FiniteFieldHomomorphism_prime(Hom(k, K)); f # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: The domain is not a finite prime field """ domain = parent.domain() - if not is_FiniteField(domain) or not domain.is_prime_field(): + if not isinstance(domain, FiniteField) or not domain.is_prime_field(): raise TypeError("The domain is not a finite prime field") if section_class is None: section_class = SectionFiniteFieldHomomorphism_prime @@ -82,6 +79,7 @@ cdef class FiniteFieldHomomorphism_prime(FiniteFieldHomomorphism_generic): """ TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.finite_rings.hom_prime_finite_field import FiniteFieldHomomorphism_prime sage: k = GF(3) sage: K.<t> = GF(3^5) @@ -100,7 +98,7 @@ cdef class FrobeniusEndomorphism_prime(FrobeniusEndomorphism_finite_field): fields (i.e. identity map :-). """ def __init__(self, domain, power=1): - if not is_FiniteField(domain) or not domain.is_prime_field(): + if not isinstance(domain, FiniteField) or not domain.is_prime_field(): raise TypeError("The domain is not a finite prime field") FrobeniusEndomorphism_finite_field.__init__(self, Hom(domain, domain)) self._order = 1 diff --git a/src/sage/rings/finite_rings/homset.py b/src/sage/rings/finite_rings/homset.py index 0a7578a092e..f9d523199ec 100644 --- a/src/sage/rings/finite_rings/homset.py +++ b/src/sage/rings/finite_rings/homset.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings """ Homset for finite fields @@ -37,7 +38,7 @@ from sage.rings.homset import RingHomset_generic from sage.rings.finite_rings.hom_finite_field import FiniteFieldHomomorphism_generic -from sage.rings.finite_rings.finite_field_base import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.integer import Integer from sage.rings.morphism import RingHomomorphism_im_gens from sage.structure.sequence import Sequence @@ -96,7 +97,7 @@ def __call__(self, im_gens, base_map=None, check=True): if self.domain().degree() == 1: from sage.rings.finite_rings.hom_prime_finite_field import FiniteFieldHomomorphism_prime return FiniteFieldHomomorphism_prime(self, im_gens, base_map=base_map, check=check) - if is_FiniteField(self.codomain()): + if isinstance(self.codomain(), FiniteField): return FiniteFieldHomomorphism_generic(self, im_gens, base_map=base_map, check=check) # Currently, FiniteFieldHomomorphism_generic does not work if # the codomain is not derived from the finite field base class; @@ -152,9 +153,9 @@ def _repr_(self): D = self.domain() C = self.codomain() if C == D: - return "Automorphism group of %s"%D + return "Automorphism group of %s" % D else: - return "Set of field embeddings from %s to %s"%(D, C) + return "Set of field embeddings from %s to %s" % (D, C) def is_aut(self): """ diff --git a/src/sage/rings/finite_rings/integer_mod.pxd b/src/sage/rings/finite_rings/integer_mod.pxd index 1e3cb81c148..351ffa25e1b 100644 --- a/src/sage/rings/finite_rings/integer_mod.pxd +++ b/src/sage/rings/finite_rings/integer_mod.pxd @@ -20,7 +20,7 @@ cdef class NativeIntStruct: cdef class IntegerMod_abstract(FiniteRingElement): - cdef NativeIntStruct __modulus + cdef NativeIntStruct _modulus cdef _new_c_from_long(self, long value) cdef IntegerMod_abstract _new_c_fast(self, unsigned long value) cdef void set_from_mpz(self, mpz_t value) diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 97ae92d867b..046b737a833 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -70,7 +70,7 @@ TESTS:: from cysignals.signals cimport sig_on, sig_off, sig_check -from cpython.int cimport * +from cpython.long cimport * from cpython.list cimport * from cpython.ref cimport * @@ -78,16 +78,20 @@ from libc.math cimport log2, ceil from sage.libs.gmp.all cimport * -import operator - cdef bint use_32bit_type(int_fast64_t modulus): return modulus <= INTEGER_MOD_INT32_LIMIT from sage.arith.long cimport ( - integer_check_long, integer_check_long_py, is_small_python_int, ERR_OVERFLOW) + integer_check_long, integer_check_long_py, is_small_python_int) import sage.rings.rational as rational -from sage.libs.pari.all import pari, PariError + +try: + from sage.libs.pari.all import pari, PariError +except ImportError: + class PariError(Exception): + pass + import sage.rings.integer_ring as integer_ring import sage.rings.rational_field @@ -100,7 +104,7 @@ from sage.structure.richcmp cimport rich_to_bool_sgn, rich_to_bool import sage.structure.element cimport sage.structure.element coerce_binop = sage.structure.element.coerce_binop -from sage.structure.element cimport RingElement, ModuleElement, Element +from sage.structure.element cimport Element from sage.categories.morphism cimport Morphism from sage.categories.map cimport Map @@ -110,7 +114,6 @@ from sage.structure.parent cimport Parent from sage.arith.misc import CRT as crt from sage.arith.functions import lcm -from sage.groups.generic import discrete_log cdef Integer one_Z = Integer(1) @@ -149,7 +152,6 @@ def Mod(n, m, parent=None): return n # m is non-zero, so return n mod m - cdef IntegerMod_abstract x if parent is None: from .integer_mod_ring import IntegerModRing parent = IntegerModRing(m) @@ -349,17 +351,17 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: TestSuite(Zmod(2^10 * 3^5)).run() sage: TestSuite(Zmod(2^30 * 3^50 * 5^20)).run() - sage: GF(29)(SR(1/3)) + sage: GF(29)(SR(1/3)) # needs sage.rings.finite_rings sage.symbolic 10 sage: Integers(30)(QQ['x'](1/7)) 13 - sage: Integers(30)(SR(1/4)) + sage: Integers(30)(SR(1/4)) # needs sage.symbolic Traceback (most recent call last): ... ZeroDivisionError: inverse of Mod(4, 30) does not exist """ self._parent = parent - self.__modulus = parent._pyx_order + self._modulus = parent._pyx_order if value is None: return @@ -371,7 +373,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): if isinstance(value, Integer): z = <Integer>value elif isinstance(value, rational.Rational): - z = value % self.__modulus.sageInteger + z = value % self._modulus.sageInteger elif integer_check_long_py(value, &longval, &err) and not err: self.set_from_long(longval) return @@ -386,7 +388,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): value = py_scalar_to_element(value) if isinstance(value, Element) and value.parent().is_exact(): value = sage.rings.rational_field.QQ(value) - z = value % self.__modulus.sageInteger + z = value % self._modulus.sageInteger else: raise self.set_from_mpz(z.value) @@ -395,7 +397,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): cdef type t = type(self) x = <IntegerMod_abstract>t.__new__(t) x._parent = self._parent - x.__modulus = self.__modulus + x._modulus = self._modulus x.set_from_ulong_fast(value) return x @@ -403,7 +405,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): cdef type t = type(self) cdef IntegerMod_abstract x = <IntegerMod_abstract>t.__new__(t) x._parent = self._parent - x.__modulus = self.__modulus + x._modulus = self._modulus x.set_from_long(value) return x @@ -505,7 +507,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: sage: a = Integers(90384098234^3) - sage: factor(a.order()) + sage: factor(a.order()) # needs sage.libs.pari 2^3 * 191^3 * 236607587^3 sage: b = a(2*191) sage: b.is_nilpotent() @@ -527,17 +529,17 @@ cdef class IntegerMod_abstract(FiniteRingElement): """ if self.is_zero(): return True - m = self.__modulus.sageInteger.exact_log(2) + 1 + m = self._modulus.sageInteger.exact_log(2) + 1 return (self**m).is_zero() ################################################################# # Interfaces ################################################################# def _pari_init_(self): - return 'Mod(%s,%s)'%(str(self), self.__modulus.sageInteger) + return 'Mod(%s,%s)'%(str(self), self._modulus.sageInteger) def __pari__(self): - return self.lift().__pari__().Mod(self.__modulus.sageInteger) + return self.lift().__pari__().Mod(self._modulus.sageInteger) def _gap_init_(self): r""" @@ -545,6 +547,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: + sage: # needs sage.libs.gap sage: a = Mod(2,19) sage: gap(a) Z(19) @@ -555,7 +558,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: gap(Mod(4, 48)) ZmodnZObj( 4, 48 ) """ - return '%s*One(ZmodnZ(%s))' % (self, self.__modulus.sageInteger) + return '%s*One(ZmodnZ(%s))' % (self, self._modulus.sageInteger) def _magma_init_(self, magma): """ @@ -563,11 +566,12 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: + sage: # optional - magma sage: a = Integers(15)(4) - sage: b = magma(a) # optional - magma - sage: b.Type() # optional - magma + sage: b = magma(a) + sage: b.Type() RngIntResElt - sage: b^2 # optional - magma + sage: b^2 1 """ return '%s!%s'%(self.parent()._magma_init_(magma), self) @@ -583,14 +587,14 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: a._axiom_init_() '4 :: IntegerMod(15)' - sage: aa = axiom(a); aa #optional - axiom + sage: aa = axiom(a); aa # optional - axiom 4 - sage: aa.type() #optional - axiom + sage: aa.type() # optional - axiom IntegerMod 15 - sage: aa = fricas(a); aa #optional - fricas + sage: aa = fricas(a); aa # optional - fricas 4 - sage: aa.typeOf() #optional - fricas + sage: aa.typeOf() # optional - fricas IntegerMod(15) """ @@ -625,7 +629,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): else: return sib(self.parent())(v) - def log(self, b=None, logarithm_exists=None): + def log(self, b=None): r""" Compute the discrete logarithm of this element to base `b`, that is, @@ -652,6 +656,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: r = Integers(125) sage: b = r.multiplicative_generator()^3 sage: a = b^17 @@ -662,7 +667,8 @@ cdef class IntegerMod_abstract(FiniteRingElement): A bigger example:: - sage: FF = FiniteField(2^32+61) + sage: # needs sage.rings.finite_rings + sage: FF = FiniteField(2^32 + 61) sage: c = FF(4294967356) sage: x = FF(2) sage: a = c.log(x) @@ -674,17 +680,17 @@ cdef class IntegerMod_abstract(FiniteRingElement): An example with a highly composite modulus:: sage: m = 2^99 * 77^7 * 123456789 * 13712923537615486607^2 - sage: (Mod(5,m)^5735816763073854953388147237921).log(5) + sage: (Mod(5,m)^5735816763073854953388147237921).log(5) # needs sage.libs.pari 5735816763073854953388147237921 Errors are generated if the logarithm doesn't exist or the inputs are not units:: - sage: Mod(3, 7).log(Mod(2, 7)) + sage: Mod(3, 7).log(Mod(2, 7)) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: no logarithm of 3 found to base 2 modulo 7 - sage: a = Mod(16, 100); b = Mod(4,100) + sage: a = Mod(16, 100); b = Mod(4, 100) sage: a.log(b) Traceback (most recent call last): ... @@ -694,11 +700,12 @@ cdef class IntegerMod_abstract(FiniteRingElement): We check that :trac:`9205` is fixed:: - sage: Mod(5,9).log(Mod(2, 9)) + sage: Mod(5, 9).log(Mod(2, 9)) # needs sage.libs.pari 5 We test against a bug (side effect on PARI) fixed in :trac:`9438`:: + sage: # needs sage.libs.pari sage: R.<a, b> = QQ[] sage: pari(b) b @@ -711,26 +718,26 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: x = mod(48475563673907791151, 10^20 + 763)^2 sage: e = 25248843418589594761 - sage: (x^e).log(x)==e + sage: (x^e).log(x) == e # needs sage.libs.pari True Examples like this took extremely long before :trac:`32375`:: - sage: (Mod(5, 123337052926643**4) ^ (10^50-1)).log(5) + sage: (Mod(5, 123337052926643**4) ^ (10^50-1)).log(5) # needs sage.libs.pari 99999999999999999999999999999999999999999999999999 We check that non-existence of solutions is detected: No local solutions:: - sage: Mod(1111, 1234567).log(1111**3) + sage: Mod(1111, 1234567).log(1111**3) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: no logarithm of 1111 found to base 961261 modulo 1234567 (no solution modulo 9721) Incompatible local solutions:: - sage: Mod(230, 323).log(173) + sage: Mod(230, 323).log(173) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: no logarithm of 230 found to base 173 modulo 323 (incompatible local solutions) @@ -752,11 +759,6 @@ cdef class IntegerMod_abstract(FiniteRingElement): - Lorenz Panny (2021): speedups for composite moduli """ - - if logarithm_exists is not None: - from sage.misc.superseded import deprecation - deprecation(32375, 'The "logarithm_exists" argument to .log() is no longer necessary and will be removed at some point.') - if not self.is_unit(): raise ValueError(f"logarithm of {self} is not defined since it is not a unit modulo {self.modulus()}") @@ -779,14 +781,15 @@ cdef class IntegerMod_abstract(FiniteRingElement): na = a_red.multiplicative_order() nb = b_red.multiplicative_order() if not na.divides(nb): # cannot be a power - raise ValueError(f"no logarithm of {self} found to base {b} modulo {self.modulus()}" \ + raise ValueError(f"no logarithm of {self} found to base {b} modulo {self.modulus()}" + (f" (no solution modulo {q})" if q != self.modulus() else "")) if p == 2 and e >= 3: # (ZZ/2^e)* is not cyclic; must not give unsolvable DLPs to Pari try: + from sage.groups.generic import discrete_log v = discrete_log(a_red, b_red, nb) except ValueError: - raise ValueError(f"no logarithm of {self} found to base {b} modulo {self.modulus()}" \ + raise ValueError(f"no logarithm of {self} found to base {b} modulo {self.modulus()}" + (f" (no solution modulo {q})" if q != self.modulus() else "")) else: try: @@ -818,9 +821,9 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: sage: m = Mod(3, 1568) - sage: v = m.generalised_log(); v + sage: v = m.generalised_log(); v # needs sage.libs.pari [1, 3, 1] - sage: prod([Zmod(1568).unit_gens()[i] ** v[i] for i in [0..2]]) + sage: prod([Zmod(1568).unit_gens()[i] ** v[i] for i in [0..2]]) # needs sage.libs.pari 3 .. SEEALSO:: @@ -861,7 +864,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: Mod(3,17).modulus() 17 """ - return self.__modulus.sageInteger + return self._modulus.sageInteger def charpoly(self, var='x'): """ @@ -916,7 +919,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): 1 sage: a.polynomial() 1 - sage: type(a.polynomial()) + sage: type(a.polynomial()) # needs sage.rings.finite_rings <class 'sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint'> """ R = self.parent()[var] @@ -1002,7 +1005,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): @coerce_binop def divides(self, other): r""" - Test wheter ``self`` divides ``other``. + Test whether ``self`` divides ``other``. EXAMPLES:: @@ -1028,13 +1031,15 @@ cdef class IntegerMod_abstract(FiniteRingElement): r""" EXAMPLES:: - sage: Mod(3,17).is_square() + sage: Mod(3, 17).is_square() False - sage: Mod(9,17).is_square() + + sage: # needs sage.libs.pari + sage: Mod(9, 17).is_square() True - sage: Mod(9,17*19^2).is_square() + sage: Mod(9, 17*19^2).is_square() True - sage: Mod(-1,17^30).is_square() + sage: Mod(-1, 17^30).is_square() True sage: Mod(1/9, next_prime(2^40)).is_square() True @@ -1043,12 +1048,12 @@ cdef class IntegerMod_abstract(FiniteRingElement): TESTS:: - sage: Mod(1/25, 2^8).is_square() + sage: Mod(1/25, 2^8).is_square() # needs sage.libs.pari True - sage: Mod(1/25, 2^40).is_square() + sage: Mod(1/25, 2^40).is_square() # needs sage.libs.pari True - sage: for p,q,r in cartesian_product_iterator([[3,5],[11,13],[17,19]]): # long time + sage: for p,q,r in cartesian_product_iterator([[3,5],[11,13],[17,19]]): # long time, needs sage.libs.pari ....: for ep,eq,er in cartesian_product_iterator([[0,1,2,3],[0,1,2,3],[0,1,2,3]]): ....: for e2 in [0, 1, 2, 3, 4]: ....: n = p^ep * q^eq * r^er * 2^e2 @@ -1126,6 +1131,8 @@ cdef class IntegerMod_abstract(FiniteRingElement): 86 sage: mod(7, 18).sqrt() 5 + + sage: # needs sage.libs.pari sage: a = mod(14, 5^60).sqrt() sage: a*a 14 @@ -1140,7 +1147,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): :: - sage: a = Mod(3,5); a + sage: a = Mod(3, 5); a 3 sage: x = Mod(-1, 360) sage: x.sqrt(extend=False) @@ -1150,7 +1157,8 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: y = x.sqrt(); y sqrt359 sage: y.parent() - Univariate Quotient Polynomial Ring in sqrt359 over Ring of integers modulo 360 with modulus x^2 + 1 + Univariate Quotient Polynomial Ring in sqrt359 over + Ring of integers modulo 360 with modulus x^2 + 1 sage: y^2 359 @@ -1169,6 +1177,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): :: + sage: # needs sage.libs.pari sage: R = Integers(5*13^3*37); R Ring of integers modulo 406445 sage: v = R(-1).sqrt(all=True); v @@ -1182,11 +1191,12 @@ cdef class IntegerMod_abstract(FiniteRingElement): :: + sage: # needs sage.rings.finite_rings sage: t = FiniteField(next_prime(2^100))(4) - sage: t.sqrt(extend = False, all = True) + sage: t.sqrt(extend=False, all=True) [2, 1267650600228229401496703205651] sage: t = FiniteField(next_prime(2^100))(2) - sage: t.sqrt(extend = False, all = True) + sage: t.sqrt(extend=False, all=True) [] Modulo a power of 2:: @@ -1214,7 +1224,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): modulus = R.gen()**2 - R(self) if self._parent.is_field(): from .finite_field_constructor import FiniteField - Q = FiniteField(self.__modulus.sageInteger**2, y, modulus) + Q = FiniteField(self._modulus.sageInteger**2, y, modulus) else: R = self.parent()['x'] Q = R.quotient(modulus, names=(y,)) @@ -1235,7 +1245,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): if all and e > 1 and not self.is_unit(): if self.is_zero(): # All multiples of p^ciel(e/2) vanish - return [self._parent(x) for x in xrange(0, self.__modulus.sageInteger, p**((e+1)/2))] + return [self._parent(x) for x in range(0, self._modulus.sageInteger, p**((e+1)/2))] else: z = self.lift() val = z.valuation(p)/2 # square => valuation is even @@ -1257,7 +1267,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): p_exp = p**exp w = [self._parent(a.lift() * p_val + b) for a in u.sqrt(all=True) - for b in xrange(0, self.__modulus.sageInteger, p_exp)] + for b in range(0, self._modulus.sageInteger, p_exp)] if p == 2: w = list(set(w)) w.sort() @@ -1386,30 +1396,34 @@ cdef class IntegerMod_abstract(FiniteRingElement): 5 sage: K(23).nth_root(3) 29 - sage: mod(225,2^5*3^2).nth_root(4, all=True) - [225, 129, 33, 63, 255, 159, 9, 201, 105, 279, 183, 87, 81, 273, 177, 207, 111, 15, 153, 57, 249, 135, 39, 231] - sage: mod(275,2^5*7^4).nth_root(7, all=True) + + sage: # needs sage.rings.padics + sage: mod(225, 2^5*3^2).nth_root(4, all=True) + [225, 129, 33, 63, 255, 159, 9, 201, 105, 279, 183, 87, 81, + 273, 177, 207, 111, 15, 153, 57, 249, 135, 39, 231] + sage: mod(275, 2^5*7^4).nth_root(7, all=True) [58235, 25307, 69211, 36283, 3355, 47259, 14331] - sage: mod(1,8).nth_root(2,all=True) + sage: mod(1,8).nth_root(2, all=True) [1, 7, 5, 3] - sage: mod(4,8).nth_root(2,all=True) + sage: mod(4,8).nth_root(2, all=True) [2, 6] - sage: mod(1,16).nth_root(4,all=True) + sage: mod(1,16).nth_root(4, all=True) [1, 15, 13, 3, 9, 7, 5, 11] + sage: (mod(22,31)^200).nth_root(200) 5 - sage: mod(3,6).nth_root(0,all=True) + sage: mod(3,6).nth_root(0, all=True) [] sage: mod(3,6).nth_root(0) Traceback (most recent call last): ... ValueError - sage: mod(1,6).nth_root(0,all=True) + sage: mod(1,6).nth_root(0, all=True) [1, 2, 3, 4, 5] TESTS:: - sage: for p in [1009,2003,10007,100003]: + sage: for p in [1009,2003,10007,100003]: # needs sage.rings.finite_rings ....: K = GF(p) ....: for r in (p-1).divisors(): ....: if r == 1: continue @@ -1419,7 +1433,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): ....: if (y^41).nth_root(41*r)**(41*r) != y^41: raise RuntimeError ....: if (y^307).nth_root(307*r)**(307*r) != y^307: raise RuntimeError - sage: for t in range(200): + sage: for t in range(200): # needs sage.libs.pari ....: n = randint(1,2^63) ....: K = Integers(n) ....: b = K.random_element() @@ -1434,18 +1448,18 @@ cdef class IntegerMod_abstract(FiniteRingElement): We check that :trac:`13172` is resolved:: - sage: mod(-1, 4489).nth_root(2, all=True) + sage: mod(-1, 4489).nth_root(2, all=True) # needs sage.rings.padics [] We check that :trac:`32084` is fixed:: - sage: mod(24, 25).nth_root(50)^50 + sage: mod(24, 25).nth_root(50)^50 # needs sage.rings.padics 24 Check that the code path cunningham might be used:: sage: a = Mod(9,11) - sage: a.nth_root(2, False, True, 'Johnston', cunningham = True) # optional - cunningham_tables + sage: a.nth_root(2, False, True, 'Johnston', cunningham=True) # optional - cunningham_tables [3, 8] ALGORITHM: @@ -1523,9 +1537,8 @@ cdef class IntegerMod_abstract(FiniteRingElement): return [K(a.lift()*p**(pval // n) + p**(k - (pval - pval//n)) * b) for a in mod(upart, p**(k-pval)).nth_root(n, all=True, algorithm=algorithm) for b in range(p**(pval - pval//n))] else: return K(p**(pval // n) * mod(upart, p**(k-pval)).nth_root(n, algorithm=algorithm).lift()) - from sage.rings.padics.all import ZpFM + from sage.rings.padics.factory import ZpFM R = ZpFM(p,k) - self_orig = self if p == 2: sign = [1] if self % 4 == 3: @@ -1577,7 +1590,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): TESTS:: - sage: for n in range(2,100): # long time + sage: for n in range(2,100): # long time ....: K = Integers(n) ....: elist = list(range(1,min(2*n+2,100))) ....: for e in random_sublist(elist, 5/len(elist)): @@ -1606,7 +1619,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): despite the possibly probabilistic nature of the underlying algorithm. """ - if self.lift() > self.__modulus.sageInteger >> 1: + if self.lift() > self._modulus.sageInteger >> 1: return -self return self @@ -1645,21 +1658,21 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: a = mod(3,5) - sage: b = mod(2,7) + sage: a = mod(3, 5) + sage: b = mod(2, 7) sage: a.crt(b) 23 :: - sage: a = mod(37,10^8) - sage: b = mod(9,3^8) + sage: a = mod(37, 10^8) + sage: b = mod(9, 3^8) sage: a.crt(b) 125900000037 :: - sage: b = mod(0,1) + sage: b = mod(0, 1) sage: a.crt(b) == a True sage: a.crt(b).modulus() @@ -1667,17 +1680,17 @@ cdef class IntegerMod_abstract(FiniteRingElement): TESTS:: - sage: mod(0,1).crt(mod(4,2^127)) + sage: mod(0, 1).crt(mod(4, 2^127)) 4 - sage: mod(4,2^127).crt(mod(0,1)) + sage: mod(4, 2^127).crt(mod(0, 1)) 4 - sage: mod(4,2^30).crt(mod(0,1)) + sage: mod(4, 2^30).crt(mod(0, 1)) 4 - sage: mod(0,1).crt(mod(4,2^30)) + sage: mod(0, 1).crt(mod(4, 2^30)) 4 - sage: mod(0,1).crt(mod(4,2^15)) + sage: mod(0, 1).crt(mod(4, 2^15)) 4 - sage: mod(4,2^15).crt(mod(0,1)) + sage: mod(4, 2^15).crt(mod(0, 1)) 4 AUTHORS: @@ -1687,27 +1700,27 @@ cdef class IntegerMod_abstract(FiniteRingElement): cdef int_fast64_t new_modulus if not isinstance(self, IntegerMod_gmp) and not isinstance(other, IntegerMod_gmp): - if other.__modulus.int64 == 1: return self - new_modulus = self.__modulus.int64 * other.__modulus.int64 + if other._modulus.int64 == 1: return self + new_modulus = self._modulus.int64 * other._modulus.int64 if new_modulus < INTEGER_MOD_INT32_LIMIT: - return self.__crt(other) + return self._crt(other) elif new_modulus < INTEGER_MOD_INT64_LIMIT: if not isinstance(self, IntegerMod_int64): self = IntegerMod_int64(self._parent, self.lift()) if not isinstance(other, IntegerMod_int64): other = IntegerMod_int64(other._parent, other.lift()) - return self.__crt(other) + return self._crt(other) if not isinstance(self, IntegerMod_gmp): - if self.__modulus.int64 == 1: return other + if self._modulus.int64 == 1: return other self = IntegerMod_gmp(self._parent, self.lift()) if not isinstance(other, IntegerMod_gmp): - if other.__modulus.int64 == 1: return self + if other._modulus.int64 == 1: return self other = IntegerMod_gmp(other._parent, other.lift()) - return self.__crt(other) + return self._crt(other) def additive_order(self): r""" @@ -1724,7 +1737,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: Integers(90308402384902)(2).additive_order() 45154201192451 """ - n = self.__modulus.sageInteger + n = self._modulus.sageInteger return sage.rings.integer.Integer(n // self.lift().gcd(n)) def is_primitive_root(self): @@ -1736,20 +1749,20 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: mod(1,2).is_primitive_root() + sage: mod(1, 2).is_primitive_root() True - sage: mod(3,4).is_primitive_root() + sage: mod(3, 4).is_primitive_root() True - sage: mod(2,7).is_primitive_root() + sage: mod(2, 7).is_primitive_root() False - sage: mod(3,98).is_primitive_root() + sage: mod(3, 98).is_primitive_root() # needs sage.libs.pari True - sage: mod(11,1009^2).is_primitive_root() + sage: mod(11, 1009^2).is_primitive_root() # needs sage.libs.pari True TESTS:: - sage: for p in prime_range(3,12): + sage: for p in prime_range(3,12): # needs sage.libs.pari ....: for k in range(1,4): ....: for even in [1,2]: ....: n = even*p^k @@ -1764,12 +1777,12 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: mod(0, 17).is_primitive_root() False - sage: all(not mod(0, n).is_primitive_root() for n in srange(2, 20)) + sage: all(not mod(0, n).is_primitive_root() for n in srange(2, 20)) # needs sage.libs.pari True sage: mod(0, 1).is_primitive_root() True - sage: all(not mod(p^j, p^k).is_primitive_root() + sage: all(not mod(p^j, p^k).is_primitive_root() # needs sage.libs.pari ....: for p in prime_range(3, 12) ....: for k in srange(1, 4) ....: for j in srange(0, k)) @@ -1824,24 +1837,25 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: - sage: Mod(-1,5).multiplicative_order() + sage: Mod(-1, 5).multiplicative_order() # needs sage.libs.pari 2 - sage: Mod(1,5).multiplicative_order() + sage: Mod(1, 5).multiplicative_order() # needs sage.libs.pari 1 - sage: Mod(0,5).multiplicative_order() + sage: Mod(0, 5).multiplicative_order() # needs sage.libs.pari Traceback (most recent call last): ... - ArithmeticError: multiplicative order of 0 not defined since it is not a unit modulo 5 + ArithmeticError: multiplicative order of 0 not defined + since it is not a unit modulo 5 """ try: return sage.rings.integer.Integer(self.__pari__().znorder()) except PariError: raise ArithmeticError("multiplicative order of %s not defined since it is not a unit modulo %s"%( - self, self.__modulus.sageInteger)) + self, self._modulus.sageInteger)) def valuation(self, p): """ - The largest power r such that m is in the ideal generated by p^r or infinity if there is not a largest such power. + The largest power `r` such that `m` is in the ideal generated by `p^r` or infinity if there is not a largest such power. However it is an error to take the valuation with respect to a unit. .. NOTE:: @@ -1850,13 +1864,13 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES: - This example shows that the (a*b).valuation(n) is not always the same as a.valuation(n) + b.valuation(n) + This example shows that ``(a*b).valuation(n)`` is not always the same as ``a.valuation(n) + b.valuation(n)`` :: - sage: R=ZZ.quo(9) - sage: a=R(3) - sage: b=R(6) + sage: R = ZZ.quo(9) + sage: a = R(3) + sage: b = R(6) sage: a.valuation(3) 1 sage: a.valuation(3) + b.valuation(3) @@ -1875,9 +1889,9 @@ cdef class IntegerMod_abstract(FiniteRingElement): TESTS:: - sage: R=ZZ.quo(12) - sage: a=R(2) - sage: b=R(4) + sage: R = ZZ.quo(12) + sage: a = R(2) + sage: b = R(4) sage: a.valuation(2) 1 sage: b.valuation(2) @@ -1886,7 +1900,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): 2 """ - p=self.__modulus.sageInteger.gcd(p) + p=self._modulus.sageInteger.gcd(p) if p==1: raise ValueError("Valuation with respect to a unit is not defined.") r = 0 @@ -1894,7 +1908,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): while not (self % power): # self % power == 0 r += 1 power *= p - if not power.divides(self.__modulus.sageInteger): + if not power.divides(self._modulus.sageInteger): from sage.rings.infinity import infinity return infinity return r @@ -1933,8 +1947,8 @@ cdef class IntegerMod_abstract(FiniteRingElement): EXAMPLES:: sage: F.<a> = GF(13) - sage: V = F.vector_space(map=False) - sage: V(a) + sage: V = F.vector_space(map=False) # needs sage.modules + sage: V(a) # needs sage.modules (1) """ return self.parent().vector_space(map=False)([self]) @@ -1961,7 +1975,7 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): cdef IntegerMod_gmp _new_c(self): cdef IntegerMod_gmp x x = IntegerMod_gmp.__new__(IntegerMod_gmp) - x.__modulus = self.__modulus + x._modulus = self._modulus x._parent = self._parent return x @@ -1970,19 +1984,19 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): cdef void set_from_mpz(self, mpz_t value): cdef sage.rings.integer.Integer modulus - modulus = self.__modulus.sageInteger + modulus = self._modulus.sageInteger mpz_mod(self.value, value, modulus.value) cdef void set_from_long(self, long value): r""" EXAMPLES:: - sage: p = next_prime(2^32) - sage: GF(p)(int(p+1)) + sage: p = next_prime(2^32) # needs sage.libs.pari + sage: GF(p)(int(p + 1)) # needs sage.libs.pari sage.rings.finite_rings 1 """ mpz_set_si(self.value, value) - mpz_mod(self.value, self.value, self.__modulus.sageInteger.value) + mpz_mod(self.value, self.value, self._modulus.sageInteger.value) cdef void set_from_ulong_fast(self, unsigned long value): mpz_set_ui(self.value, value) @@ -2052,7 +2066,7 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): x = self._new_c() if k > 0: mpz_mul_2exp(x.value, self.value, k) - mpz_fdiv_r(x.value, x.value, self.__modulus.sageInteger.value) + mpz_fdiv_r(x.value, x.value, self._modulus.sageInteger.value) else: mpz_fdiv_q_2exp(x.value, self.value, -k) return x @@ -2102,7 +2116,7 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): cpdef bint is_unit(self): """ - Return True iff this element is a unit. + Return ``True`` iff this element is a unit. EXAMPLES:: @@ -2113,12 +2127,12 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): """ return self.lift().gcd(self.modulus()) == 1 - def __crt(IntegerMod_gmp self, IntegerMod_gmp other): + def _crt(IntegerMod_gmp self, IntegerMod_gmp other): cdef IntegerMod_gmp lift, x cdef sage.rings.integer.Integer modulus, other_modulus - modulus = self.__modulus.sageInteger - other_modulus = other.__modulus.sageInteger + modulus = self._modulus.sageInteger + other_modulus = other._modulus.sageInteger from .integer_mod_ring import IntegerModRing lift = IntegerMod_gmp(IntegerModRing(modulus*other_modulus)) try: @@ -2169,8 +2183,8 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): cdef IntegerMod_gmp x x = self._new_c() mpz_add(x.value, self.value, (<IntegerMod_gmp>right).value) - if mpz_cmp(x.value, self.__modulus.sageInteger.value) >= 0: - mpz_sub(x.value, x.value, self.__modulus.sageInteger.value) + if mpz_cmp(x.value, self._modulus.sageInteger.value) >= 0: + mpz_sub(x.value, x.value, self._modulus.sageInteger.value) return x cpdef _sub_(self, right): @@ -2185,7 +2199,7 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): x = self._new_c() mpz_sub(x.value, self.value, (<IntegerMod_gmp>right).value) if mpz_sgn(x.value) == -1: - mpz_add(x.value, x.value, self.__modulus.sageInteger.value) + mpz_add(x.value, x.value, self._modulus.sageInteger.value) return x cpdef _neg_(self): @@ -2201,7 +2215,7 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): return self cdef IntegerMod_gmp x x = self._new_c() - mpz_sub(x.value, self.__modulus.sageInteger.value, self.value) + mpz_sub(x.value, self._modulus.sageInteger.value, self.value) return x cpdef _mul_(self, right): @@ -2215,7 +2229,7 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): cdef IntegerMod_gmp x x = self._new_c() mpz_mul(x.value, self.value, (<IntegerMod_gmp>right).value) - mpz_fdiv_r(x.value, x.value, self.__modulus.sageInteger.value) + mpz_fdiv_r(x.value, x.value, self._modulus.sageInteger.value) return x cpdef _div_(self, right): @@ -2250,9 +2264,9 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): sage: R = Integers(10^10) sage: R(2)^1000 5668069376 - sage: p = next_prime(11^10) - sage: R = Integers(p) - sage: R(9876)^(p-1) + sage: p = next_prime(11^10) # needs sage.libs.pari + sage: R = Integers(p) # needs sage.libs.pari + sage: R(9876)^(p-1) # needs sage.libs.pari 1 sage: mod(3, 10^100)^-2 8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888889 @@ -2265,8 +2279,8 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): We define ``0^0`` to be unity, :trac:`13894`:: - sage: p = next_prime(11^10) - sage: R = Integers(p) + sage: p = next_prime(11^10) # needs sage.libs.pari + sage: R = Integers(p) # needs sage.libs.pari sage: R(0)^0 1 @@ -2291,7 +2305,7 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): cdef IntegerMod_gmp x = self._new_c() sig_on() try: - mpz_pow_helper(x.value, self.value, exp, self.__modulus.sageInteger.value) + mpz_pow_helper(x.value, self.value, exp, self._modulus.sageInteger.value) finally: sig_off() return x @@ -2312,12 +2326,12 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): ZeroDivisionError: inverse of Mod(2, 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) does not exist """ if self.is_zero(): - raise ZeroDivisionError(f"inverse of Mod(0, {self.__modulus.sageInteger}) does not exist") + raise ZeroDivisionError(f"inverse of Mod(0, {self._modulus.sageInteger}) does not exist") cdef IntegerMod_gmp x x = self._new_c() - if not mpz_invert(x.value, self.value, self.__modulus.sageInteger.value): - raise ZeroDivisionError(f"inverse of Mod({self}, {self.__modulus.sageInteger}) does not exist") + if not mpz_invert(x.value, self.value, self._modulus.sageInteger.value): + raise ZeroDivisionError(f"inverse of Mod({self}, {self._modulus.sageInteger}) does not exist") return x def lift(IntegerMod_gmp self): @@ -2372,10 +2386,10 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): """ cdef IntegerMod_gmp ans = self._new_c() sig_on() - mpz_gcd(ans.value, self.value, self.__modulus.sageInteger.value) + mpz_gcd(ans.value, self.value, self._modulus.sageInteger.value) mpz_gcd(ans.value, ans.value, other.value) sig_off() - if mpz_cmp(ans.value, self.__modulus.sageInteger.value) == 0: + if mpz_cmp(ans.value, self._modulus.sageInteger.value) == 0: # self = other = 0 mpz_set_ui(ans.value, 0) return ans @@ -2403,30 +2417,30 @@ cdef class IntegerMod_int(IntegerMod_abstract): """ cdef IntegerMod_int _new_c(self, int_fast32_t value): - if self.__modulus.table is not None: - return self.__modulus.table[value] + if self._modulus.table is not None: + return self._modulus.table[value] cdef IntegerMod_int x = IntegerMod_int.__new__(IntegerMod_int) x._parent = self._parent - x.__modulus = self.__modulus + x._modulus = self._modulus x.ivalue = value return x cdef void set_from_mpz(self, mpz_t value): - self.ivalue = mpz_fdiv_ui(value, self.__modulus.int32) + self.ivalue = mpz_fdiv_ui(value, self._modulus.int32) cdef void set_from_long(self, long value): - self.ivalue = value % self.__modulus.int32 + self.ivalue = value % self._modulus.int32 if self.ivalue < 0: - self.ivalue += self.__modulus.int32 + self.ivalue += self._modulus.int32 cdef void set_from_ulong_fast(self, unsigned long value): self.ivalue = value cdef void set_from_int(IntegerMod_int self, int_fast32_t ivalue): if ivalue < 0: - self.ivalue = self.__modulus.int32 + (ivalue % self.__modulus.int32) - elif ivalue >= self.__modulus.int32: - self.ivalue = ivalue % self.__modulus.int32 + self.ivalue = self._modulus.int32 + (ivalue % self._modulus.int32) + elif ivalue >= self._modulus.int32: + self.ivalue = ivalue % self._modulus.int32 else: self.ivalue = ivalue @@ -2471,7 +2485,7 @@ cdef class IntegerMod_int(IntegerMod_abstract): sage: Zmod(1).one().is_one() True """ - return self.ivalue == 1 or self.__modulus.int32 == 1 + return self.ivalue == 1 or self._modulus.int32 == 1 def __bool__(IntegerMod_int self): """ @@ -2489,7 +2503,7 @@ cdef class IntegerMod_int(IntegerMod_abstract): cpdef bint is_unit(IntegerMod_int self): """ - Return True iff this element is a unit + Return ``True`` iff this element is a unit EXAMPLES:: @@ -2500,9 +2514,9 @@ cdef class IntegerMod_int(IntegerMod_abstract): sage: a.is_unit() False """ - return gcd_int(self.ivalue, self.__modulus.int32) == 1 + return gcd_int(self.ivalue, self._modulus.int32) == 1 - def __crt(IntegerMod_int self, IntegerMod_int other): + def _crt(IntegerMod_int self, IntegerMod_int other): """ Use the Chinese Remainder Theorem to find an element of the integers modulo the product of the moduli that reduces to self and @@ -2524,11 +2538,11 @@ cdef class IntegerMod_int(IntegerMod_abstract): cdef int_fast32_t x from .integer_mod_ring import IntegerModRing - lift = IntegerMod_int(IntegerModRing(self.__modulus.int32 * other.__modulus.int32)) + lift = IntegerMod_int(IntegerModRing(self._modulus.int32 * other._modulus.int32)) try: - x = (other.ivalue - self.ivalue % other.__modulus.int32) * mod_inverse_int(self.__modulus.int32, other.__modulus.int32) - lift.set_from_int( x * self.__modulus.int32 + self.ivalue ) + x = (other.ivalue - self.ivalue % other._modulus.int32) * mod_inverse_int(self._modulus.int32, other._modulus.int32) + lift.set_from_int( x * self._modulus.int32 + self.ivalue ) return lift except ZeroDivisionError: raise ZeroDivisionError("moduli must be coprime") @@ -2567,8 +2581,8 @@ cdef class IntegerMod_int(IntegerMod_abstract): """ cdef int_fast32_t x x = self.ivalue + (<IntegerMod_int>right).ivalue - if x >= self.__modulus.int32: - x = x - self.__modulus.int32 + if x >= self._modulus.int32: + x = x - self._modulus.int32 return self._new_c(x) cpdef _sub_(self, right): @@ -2582,7 +2596,7 @@ cdef class IntegerMod_int(IntegerMod_abstract): cdef int_fast32_t x x = self.ivalue - (<IntegerMod_int>right).ivalue if x < 0: - x = x + self.__modulus.int32 + x = x + self._modulus.int32 return self._new_c(x) cpdef _neg_(self): @@ -2596,7 +2610,7 @@ cdef class IntegerMod_int(IntegerMod_abstract): """ if self.ivalue == 0: return self - return self._new_c(self.__modulus.int32 - self.ivalue) + return self._new_c(self._modulus.int32 - self.ivalue) cpdef _mul_(self, right): """ @@ -2606,7 +2620,7 @@ cdef class IntegerMod_int(IntegerMod_abstract): sage: R(7) * R(8) 6 """ - return self._new_c((self.ivalue * (<IntegerMod_int>right).ivalue) % self.__modulus.int32) + return self._new_c((self.ivalue * (<IntegerMod_int>right).ivalue) % self._modulus.int32) cpdef _div_(self, right): """ @@ -2616,16 +2630,16 @@ cdef class IntegerMod_int(IntegerMod_abstract): sage: R(2)/3 4 """ - if self.__modulus.inverses is not None: - right_inverse = self.__modulus.inverses[(<IntegerMod_int>right).ivalue] + if self._modulus.inverses is not None: + right_inverse = self._modulus.inverses[(<IntegerMod_int>right).ivalue] if right_inverse is None: - raise ZeroDivisionError(f"inverse of Mod({right}, {self.__modulus.sageInteger}) does not exist") + raise ZeroDivisionError(f"inverse of Mod({right}, {self._modulus.sageInteger}) does not exist") else: - return self._new_c((self.ivalue * (<IntegerMod_int>right_inverse).ivalue) % self.__modulus.int32) + return self._new_c((self.ivalue * (<IntegerMod_int>right_inverse).ivalue) % self._modulus.int32) cdef int_fast32_t x - x = self.ivalue * mod_inverse_int((<IntegerMod_int>right).ivalue, self.__modulus.int32) - return self._new_c(x% self.__modulus.int32) + x = self.ivalue * mod_inverse_int((<IntegerMod_int>right).ivalue, self._modulus.int32) + return self._new_c(x% self._modulus.int32) def __int__(IntegerMod_int self): """ @@ -2720,7 +2734,7 @@ cdef class IntegerMod_int(IntegerMod_abstract): if k == 0: return self elif k > 0: - return self._new_c((self.ivalue << k) % self.__modulus.int32) + return self._new_c((self.ivalue << k) % self._modulus.int32) else: return self._new_c(self.ivalue >> (-k)) @@ -2774,8 +2788,8 @@ cdef class IntegerMod_int(IntegerMod_abstract): cdef long long_exp cdef int_fast32_t res cdef mpz_t res_mpz - if type(exp) is int and -100000 < PyInt_AS_LONG(exp) < 100000: - long_exp = PyInt_AS_LONG(exp) + if type(exp) is int and -100000 < PyLong_AsLong(exp) < 100000: + long_exp = PyLong_AsLong(exp) elif type(exp) is Integer and mpz_cmpabs_ui((<Integer>exp).value, 100000) == -1: long_exp = mpz_get_si((<Integer>exp).value) else: @@ -2783,7 +2797,7 @@ cdef class IntegerMod_int(IntegerMod_abstract): sig_on() try: mpz_init(res_mpz) - mpz_pow_helper(res_mpz, (<Integer>base).value, exp, self.__modulus.sageInteger.value) + mpz_pow_helper(res_mpz, (<Integer>base).value, exp, self._modulus.sageInteger.value) res = mpz_get_ui(res_mpz) mpz_clear(res_mpz) finally: @@ -2792,12 +2806,12 @@ cdef class IntegerMod_int(IntegerMod_abstract): if long_exp == 0 and self.ivalue == 0: # Return 0 if the modulus is 1, otherwise return 1. - return self._new_c(self.__modulus.int32 != 1) + return self._new_c(self._modulus.int32 != 1) cdef bint invert = False if long_exp < 0: invert = True long_exp = -long_exp - res = mod_pow_int(self.ivalue, long_exp, self.__modulus.int32) + res = mod_pow_int(self.ivalue, long_exp, self._modulus.int32) if invert: return ~self._new_c(res) else: @@ -2814,14 +2828,14 @@ cdef class IntegerMod_int(IntegerMod_abstract): sage: Mod(0,1)^-1 0 """ - if self.__modulus.inverses is not None: - x = self.__modulus.inverses[self.ivalue] + if self._modulus.inverses is not None: + x = self._modulus.inverses[self.ivalue] if x is None: - raise ZeroDivisionError(f"inverse of Mod({self}, {self.__modulus.sageInteger}) does not exist") + raise ZeroDivisionError(f"inverse of Mod({self}, {self._modulus.sageInteger}) does not exist") else: return x else: - return self._new_c(mod_inverse_int(self.ivalue, self.__modulus.int32)) + return self._new_c(mod_inverse_int(self.ivalue, self._modulus.int32)) def lift(IntegerMod_int self): """ @@ -2908,6 +2922,8 @@ cdef class IntegerMod_int(IntegerMod_abstract): 86 sage: mod(7, 18).sqrt() 5 + + sage: # needs sage.libs.pari sage: a = mod(14, 5^60).sqrt() sage: a*a 14 @@ -2932,7 +2948,8 @@ cdef class IntegerMod_int(IntegerMod_abstract): sage: y = x.sqrt(); y sqrt359 sage: y.parent() - Univariate Quotient Polynomial Ring in sqrt359 over Ring of integers modulo 360 with modulus x^2 + 1 + Univariate Quotient Polynomial Ring in sqrt359 + over Ring of integers modulo 360 with modulus x^2 + 1 sage: y^2 359 @@ -2953,6 +2970,7 @@ cdef class IntegerMod_int(IntegerMod_abstract): :: + sage: # needs sage.libs.pari sage: R = Integers(5*13^3*37); R Ring of integers modulo 406445 sage: v = R(-1).sqrt(all=True); v @@ -2983,15 +3001,15 @@ cdef class IntegerMod_int(IntegerMod_abstract): sage: GF(103)(-1).sqrt(extend=False, all=True) [] """ - cdef int_fast32_t i, n = self.__modulus.int32 + cdef int_fast32_t i, n = self._modulus.int32 if n > 100: moduli = self._parent.factored_order() # Unless the modulus is tiny, test to see if we're in the really # easy case of n prime, n = 3 mod 4. if n > 100 and n % 4 == 3 and len(moduli) == 1 and moduli[0][1] == 1: - if jacobi_int(self.ivalue, self.__modulus.int32) == 1: + if jacobi_int(self.ivalue, self._modulus.int32) == 1: # it's a non-zero square, sqrt(a) = a^(p+1)/4 - i = mod_pow_int(self.ivalue, (self.__modulus.int32+1)/4, n) + i = mod_pow_int(self.ivalue, (self._modulus.int32+1)/4, n) if i > n / 2: i = n - i if all: @@ -3026,7 +3044,7 @@ cdef class IntegerMod_int(IntegerMod_abstract): This function returns `x` or `-x`, whichever has a positive representative in `-n/2 < x \leq n/2`. """ - if self.ivalue > self.__modulus.int32 / 2: + if self.ivalue > self._modulus.int32 / 2: return -self return self @@ -3059,9 +3077,9 @@ cdef class IntegerMod_int(IntegerMod_abstract): sage: mod(0,1).gcd(mod(0,1)) 0 """ - cdef int_fast32_t g = gcd_int(self.ivalue, self.__modulus.int32) + cdef int_fast32_t g = gcd_int(self.ivalue, self._modulus.int32) g = gcd_int(g, other.ivalue) - if g == self.__modulus.int32: # self = other = 0 + if g == self._modulus.int32: # self = other = 0 g = 0 return self._new_c(g) @@ -3233,27 +3251,27 @@ cdef class IntegerMod_int64(IntegerMod_abstract): cdef IntegerMod_int64 _new_c(self, int_fast64_t value): cdef IntegerMod_int64 x x = IntegerMod_int64.__new__(IntegerMod_int64) - x.__modulus = self.__modulus + x._modulus = self._modulus x._parent = self._parent x.ivalue = value return x cdef void set_from_mpz(self, mpz_t value): - self.ivalue = mpz_fdiv_ui(value, self.__modulus.int64) + self.ivalue = mpz_fdiv_ui(value, self._modulus.int64) cdef void set_from_long(self, long value): - self.ivalue = value % self.__modulus.int64 + self.ivalue = value % self._modulus.int64 if self.ivalue < 0: - self.ivalue += self.__modulus.int64 + self.ivalue += self._modulus.int64 cdef void set_from_ulong_fast(self, unsigned long value): self.ivalue = value cdef void set_from_int(IntegerMod_int64 self, int_fast64_t ivalue): if ivalue < 0: - self.ivalue = self.__modulus.int64 + (ivalue % self.__modulus.int64) # Is ivalue % self.__modulus.int64 actually negative? - elif ivalue >= self.__modulus.int64: - self.ivalue = ivalue % self.__modulus.int64 + self.ivalue = self._modulus.int64 + (ivalue % self._modulus.int64) # Is ivalue % self._modulus.int64 actually negative? + elif ivalue >= self._modulus.int64: + self.ivalue = ivalue % self._modulus.int64 else: self.ivalue = ivalue @@ -3312,7 +3330,7 @@ cdef class IntegerMod_int64(IntegerMod_abstract): cpdef bint is_unit(IntegerMod_int64 self): """ - Return True iff this element is a unit. + Return ``True`` iff this element is a unit. EXAMPLES:: @@ -3321,9 +3339,9 @@ cdef class IntegerMod_int64(IntegerMod_abstract): sage: mod(25, 5^10).is_unit() False """ - return gcd_int64(self.ivalue, self.__modulus.int64) == 1 + return gcd_int64(self.ivalue, self._modulus.int64) == 1 - def __crt(IntegerMod_int64 self, IntegerMod_int64 other): + def _crt(IntegerMod_int64 self, IntegerMod_int64 other): """ Use the Chinese Remainder Theorem to find an element of the integers modulo the product of the moduli that reduces to self and @@ -3356,11 +3374,11 @@ cdef class IntegerMod_int64(IntegerMod_abstract): cdef int_fast64_t x from .integer_mod_ring import IntegerModRing - lift = IntegerMod_int64(IntegerModRing(self.__modulus.int64 * other.__modulus.int64)) + lift = IntegerMod_int64(IntegerModRing(self._modulus.int64 * other._modulus.int64)) try: - x = (other.ivalue - self.ivalue % other.__modulus.int64) * mod_inverse_int64(self.__modulus.int64, other.__modulus.int64) - lift.set_from_int( x * self.__modulus.int64 + self.ivalue ) + x = (other.ivalue - self.ivalue % other._modulus.int64) * mod_inverse_int64(self._modulus.int64, other._modulus.int64) + lift.set_from_int( x * self._modulus.int64 + self.ivalue ) return lift except ZeroDivisionError: raise ZeroDivisionError("moduli must be coprime") @@ -3399,8 +3417,8 @@ cdef class IntegerMod_int64(IntegerMod_abstract): """ cdef int_fast64_t x x = self.ivalue + (<IntegerMod_int64>right).ivalue - if x >= self.__modulus.int64: - x = x - self.__modulus.int64 + if x >= self._modulus.int64: + x = x - self._modulus.int64 return self._new_c(x) cpdef _sub_(self, right): @@ -3414,7 +3432,7 @@ cdef class IntegerMod_int64(IntegerMod_abstract): cdef int_fast64_t x x = self.ivalue - (<IntegerMod_int64>right).ivalue if x < 0: - x = x + self.__modulus.int64 + x = x + self._modulus.int64 return self._new_c(x) cpdef _neg_(self): @@ -3428,7 +3446,7 @@ cdef class IntegerMod_int64(IntegerMod_abstract): """ if self.ivalue == 0: return self - return self._new_c(self.__modulus.int64 - self.ivalue) + return self._new_c(self._modulus.int64 - self.ivalue) cpdef _mul_(self, right): """ @@ -3438,7 +3456,7 @@ cdef class IntegerMod_int64(IntegerMod_abstract): sage: R(700) * R(800) 60000 """ - return self._new_c((self.ivalue * (<IntegerMod_int64>right).ivalue) % self.__modulus.int64) + return self._new_c((self.ivalue * (<IntegerMod_int64>right).ivalue) % self._modulus.int64) cpdef _div_(self, right): @@ -3450,7 +3468,7 @@ cdef class IntegerMod_int64(IntegerMod_abstract): 33334 """ return self._new_c((self.ivalue * mod_inverse_int64((<IntegerMod_int64>right).ivalue, - self.__modulus.int64) ) % self.__modulus.int64) + self._modulus.int64) ) % self._modulus.int64) def __int__(IntegerMod_int64 self): return self.ivalue @@ -3536,7 +3554,7 @@ cdef class IntegerMod_int64(IntegerMod_abstract): if k == 0: return self elif k > 0: - return self._new_c((self.ivalue << k) % self.__modulus.int64) + return self._new_c((self.ivalue << k) % self._modulus.int64) else: return self._new_c(self.ivalue >> (-k)) @@ -3547,9 +3565,9 @@ cdef class IntegerMod_int64(IntegerMod_abstract): sage: R = Integers(10) sage: R(2)^10 4 - sage: p = next_prime(10^5) - sage: R = Integers(p) - sage: R(1234)^(p-1) + sage: p = next_prime(10^5) # needs sage.libs.pari + sage: R = Integers(p) # needs sage.libs.pari + sage: R(1234)^(p - 1) # needs sage.libs.pari 1 sage: R = Integers(17^5) sage: R(17)^5 @@ -3575,8 +3593,8 @@ cdef class IntegerMod_int64(IntegerMod_abstract): We define ``0^0`` to be unity, :trac:`13894`:: - sage: p = next_prime(10^5) - sage: R = Integers(p) + sage: p = next_prime(10^5) # needs sage.libs.pari + sage: R = Integers(p) # needs sage.libs.pari sage: R(0)^0 1 @@ -3601,8 +3619,8 @@ cdef class IntegerMod_int64(IntegerMod_abstract): cdef long long_exp cdef int_fast64_t res cdef mpz_t res_mpz - if type(exp) is int and -100000 < PyInt_AS_LONG(exp) < 100000: - long_exp = PyInt_AS_LONG(exp) + if type(exp) is int and -100000 < PyLong_AsLong(exp) < 100000: + long_exp = PyLong_AsLong(exp) elif type(exp) is Integer and mpz_cmpabs_ui((<Integer>exp).value, 100000) == -1: long_exp = mpz_get_si((<Integer>exp).value) else: @@ -3610,7 +3628,7 @@ cdef class IntegerMod_int64(IntegerMod_abstract): sig_on() try: mpz_init(res_mpz) - mpz_pow_helper(res_mpz, (<Integer>base).value, exp, self.__modulus.sageInteger.value) + mpz_pow_helper(res_mpz, (<Integer>base).value, exp, self._modulus.sageInteger.value) res = mpz_get_ui(res_mpz) mpz_clear(res_mpz) finally: @@ -3619,14 +3637,14 @@ cdef class IntegerMod_int64(IntegerMod_abstract): if long_exp == 0 and self.ivalue == 0: # Return 0 if the modulus is 1, otherwise return 1. - return self._new_c(self.__modulus.int64 != 1) + return self._new_c(self._modulus.int64 != 1) cdef bint invert = False if long_exp < 0: invert = True long_exp = -long_exp - res = mod_pow_int64(self.ivalue, long_exp, self.__modulus.int64) + res = mod_pow_int64(self.ivalue, long_exp, self._modulus.int64) if invert: - return self._new_c(mod_inverse_int64(res, self.__modulus.int64)) + return self._new_c(mod_inverse_int64(res, self._modulus.int64)) else: return self._new_c(res) @@ -3643,7 +3661,7 @@ cdef class IntegerMod_int64(IntegerMod_abstract): sage: a 7 """ - return self._new_c(mod_inverse_int64(self.ivalue, self.__modulus.int64)) + return self._new_c(mod_inverse_int64(self.ivalue, self._modulus.int64)) def lift(IntegerMod_int64 self): """ @@ -3692,7 +3710,7 @@ cdef class IntegerMod_int64(IntegerMod_abstract): This function returns `x` or `-x`, whichever has a positive representative in `-n/2 < x \leq n/2`. """ - if self.ivalue > self.__modulus.int64 / 2: + if self.ivalue > self._modulus.int64 / 2: return -self return self @@ -3715,9 +3733,9 @@ cdef class IntegerMod_int64(IntegerMod_abstract): sage: mod(0,17^5).gcd(mod(0,17^5)) 0 """ - cdef int_fast64_t g = gcd_int64(self.ivalue, self.__modulus.int64) + cdef int_fast64_t g = gcd_int64(self.ivalue, self._modulus.int64) g = gcd_int64(g, other.ivalue) - if g == self.__modulus.int64: # self = other = 0 + if g == self._modulus.int64: # self = other = 0 g = 0 return self._new_c(g) @@ -3902,11 +3920,11 @@ def square_root_mod_prime_power(IntegerMod_abstract a, p, e): :: - sage: a = Mod(72,97^10) - sage: b = square_root_mod_prime_power(a,97,10) - sage: b^2 == a + sage: a = Mod(72, 97^10) + sage: b = square_root_mod_prime_power(a, 97, 10) # needs sage.libs.pari + sage: b^2 == a # needs sage.libs.pari True - sage: mod(100, 5^7).sqrt()^2 + sage: mod(100, 5^7).sqrt()^2 # needs sage.libs.pari 100 TESTS: @@ -3914,7 +3932,7 @@ def square_root_mod_prime_power(IntegerMod_abstract a, p, e): A big example for the binary case (:trac:`33961`):: sage: y = Mod(-7, 2^777) - sage: hex(y.sqrt()^2 - y) + sage: hex(y.sqrt()^2 - y) # needs sage.libs.pari '0x0' Testing with random squares in random rings:: @@ -3922,7 +3940,7 @@ def square_root_mod_prime_power(IntegerMod_abstract a, p, e): sage: p = random_prime(999) sage: e = randrange(1, 999) sage: x = Zmod(p^e).random_element() - sage: (x^2).sqrt()^2 == x^2 + sage: (x^2).sqrt()^2 == x^2 # needs sage.libs.pari True """ if a.is_zero() or a.is_one(): @@ -4017,7 +4035,7 @@ cpdef square_root_mod_prime(IntegerMod_abstract a, p=None): :: sage: from sage.rings.finite_rings.integer_mod import square_root_mod_prime # sqrt() uses brute force for small p - sage: all(square_root_mod_prime(a*a)^2 == a*a + sage: all(square_root_mod_prime(a*a)^2 == a*a # needs sage.libs.pari ....: for p in prime_range(100) ....: for a in Integers(p)) True @@ -4033,9 +4051,6 @@ cpdef square_root_mod_prime(IntegerMod_abstract a, p=None): cdef double bits = log2(float(p)) cdef long r, m - cdef Integer resZ - - if p_mod_16 % 2 == 0: # p == 2 return a @@ -4103,7 +4118,7 @@ def lucas_q1(mm, IntegerMod_abstract P): TESTS:: sage: from sage.rings.finite_rings.integer_mod import lucas_q1 - sage: all(lucas_q1(k, a) == BinaryRecurrenceSequence(a, -1, 2, a)(k) + sage: all(lucas_q1(k, a) == BinaryRecurrenceSequence(a, -1, 2, a)(k) # needs sage.combinat sage.modules ....: for a in Integers(23) ....: for k in range(13)) True @@ -4171,7 +4186,7 @@ def lucas(k, P, Q=1, n=None): sage: p = randint(0,100000) sage: q = randint(0,100000) sage: n = randint(1,100) - sage: all(lucas(k,p,q,n)[0] == Mod(lucas_number2(k,p,q),n) + sage: all(lucas(k, p, q, n)[0] == Mod(lucas_number2(k, p, q), n) # needs sage.combinat sage.libs.gap ....: for k in Integers(20)) True sage: from sage.rings.finite_rings.integer_mod import lucas @@ -4179,7 +4194,8 @@ def lucas(k, P, Q=1, n=None): sage: q = randint(0,100000) sage: n = randint(1,100) sage: k = randint(0,100) - sage: lucas(k,p,q,n) == [Mod(lucas_number2(k,p,q),n),Mod(q^(int(k/2)),n)] + sage: lucas(k, p, q, n) == [Mod(lucas_number2(k, p, q), n), # needs sage.combinat sage.libs.gap + ....: Mod(q^(int(k/2)), n)] True EXAMPLES:: @@ -4317,8 +4333,14 @@ cdef class IntegerMod_to_IntegerMod(IntegerMod_hom): sage: from sage.rings.finite_rings.integer_mod import IntegerMod_to_IntegerMod sage: Rs = [Integers(3**k) for k in range(1,30,5)] sage: [type(R(0)) for R in Rs] - [<class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>, <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>, <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int64'>, <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int64'>, <class 'sage.rings.finite_rings.integer_mod.IntegerMod_gmp'>, <class 'sage.rings.finite_rings.integer_mod.IntegerMod_gmp'>] - sage: fs = [IntegerMod_to_IntegerMod(S, R) for R in Rs for S in Rs if S is not R and S.order() > R.order()] + [<class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>, + <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>, + <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int64'>, + <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int64'>, + <class 'sage.rings.finite_rings.integer_mod.IntegerMod_gmp'>, + <class 'sage.rings.finite_rings.integer_mod.IntegerMod_gmp'>] + sage: fs = [IntegerMod_to_IntegerMod(S, R) + ....: for R in Rs for S in Rs if S is not R and S.order() > R.order()] sage: all(f(-1) == f.codomain()(-1) for f in fs) True sage: [f(-1) for f in fs] @@ -4387,7 +4409,9 @@ cdef class Integer_to_IntegerMod(IntegerMod_hom): sage: from sage.rings.finite_rings.integer_mod import Integer_to_IntegerMod sage: Rs = [Integers(10), Integers(10^5), Integers(10^10)] sage: [type(R(0)) for R in Rs] - [<class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>, <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int64'>, <class 'sage.rings.finite_rings.integer_mod.IntegerMod_gmp'>] + [<class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>, + <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int64'>, + <class 'sage.rings.finite_rings.integer_mod.IntegerMod_gmp'>] sage: fs = [Integer_to_IntegerMod(R) for R in Rs] sage: [f(-1) for f in fs] [9, 99999, 9999999999] @@ -4493,7 +4517,11 @@ cdef class Int_to_IntegerMod(IntegerMod_hom): sage: from sage.rings.finite_rings.integer_mod import Int_to_IntegerMod sage: Rs = [Integers(2**k) for k in range(1,50,10)] sage: [type(R(0)) for R in Rs] - [<class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>, <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>, <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int64'>, <class 'sage.rings.finite_rings.integer_mod.IntegerMod_gmp'>, <class 'sage.rings.finite_rings.integer_mod.IntegerMod_gmp'>] + [<class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>, + <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>, + <class 'sage.rings.finite_rings.integer_mod.IntegerMod_int64'>, + <class 'sage.rings.finite_rings.integer_mod.IntegerMod_gmp'>, + <class 'sage.rings.finite_rings.integer_mod.IntegerMod_gmp'>] sage: fs = [Int_to_IntegerMod(R) for R in Rs] sage: [f(-1) for f in fs] [1, 2047, 2097151, 2147483647, 2199023255551] diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index a10d84aade9..92b99d050ba 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -19,13 +19,13 @@ sage: s = GF(7) sage: r.has_coerce_map_from(s) False - sage: s.has_coerce_map_from(r) + sage: s.has_coerce_map_from(r) # needs sage.rings.finite_rings True - sage: s(1) + r(1) + sage: s(1) + r(1) # needs sage.rings.finite_rings 2 - sage: parent(s(1) + r(1)) + sage: parent(s(1) + r(1)) # needs sage.rings.finite_rings Finite Field of size 7 - sage: parent(r(1) + s(1)) + sage: parent(r(1) + s(1)) # needs sage.rings.finite_rings Finite Field of size 7 We list the elements of `\ZZ/3\ZZ`:: @@ -72,7 +72,11 @@ import sage.rings.integer_ring as integer_ring import sage.rings.quotient_ring as quotient_ring -from sage.libs.pari.all import pari, PariError +try: + from sage.libs.pari.all import pari, PariError +except ImportError: + class PariError(Exception): + pass from sage.misc.cachefunc import cached_method @@ -242,38 +246,6 @@ def create_object(self, version, order, **kwds): Zmod = Integers = IntegerModRing = IntegerModFactory("IntegerModRing") -def is_IntegerModRing(x): - """ - Return ``True`` if ``x`` is an integer modulo ring. - - This function is deprecated. Use :func:`isinstance` with - :class:`sage.rings.abc.IntegerModRing` instead. - - EXAMPLES:: - - sage: from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing - sage: R = IntegerModRing(17) - sage: is_IntegerModRing(R) - doctest:warning... - DeprecationWarning: the function is_IntegerModRing is deprecated. - Use isinstance(..., sage.rings.abc.IntegerModRing) instead. - See https://github.com/sagemath/sage/issues/32606 for details. - True - sage: is_IntegerModRing(GF(13)) - True - sage: is_IntegerModRing(GF(4, 'a')) - False - sage: is_IntegerModRing(10) - False - sage: is_IntegerModRing(ZZ) - False - """ - from sage.misc.superseded import deprecation - deprecation(32606, "the function is_IntegerModRing is deprecated. " - "Use isinstance(..., sage.rings.abc.IntegerModRing) instead.") - return isinstance(x, IntegerModRing_generic) - - from sage.categories.commutative_rings import CommutativeRings from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.category import JoinCategory @@ -290,9 +262,9 @@ def _unit_gens_primepowercase(p, r): sage: from sage.rings.finite_rings.integer_mod_ring import _unit_gens_primepowercase sage: _unit_gens_primepowercase(2, 3) [(7, 2), (5, 2)] - sage: _unit_gens_primepowercase(17, 1) + sage: _unit_gens_primepowercase(17, 1) # needs sage.libs.pari [(3, 16)] - sage: _unit_gens_primepowercase(3, 3) + sage: _unit_gens_primepowercase(3, 3) # needs sage.libs.pari [(2, 18)] """ pr = p**r @@ -344,6 +316,8 @@ class IntegerModRing_generic(quotient_ring.QuotientRing_generic, sage.rings.abc. 29 sage: FF.order() 29 + + sage: # needs sage.groups sage: gens = FF.unit_gens() sage: a = gens[0] sage: a @@ -404,6 +378,8 @@ class IntegerModRing_generic(quotient_ring.QuotientRing_generic, sage.rings.abc. 16 sage: Z16.characteristic() 16 + + sage: # needs sage.groups sage: gens = Z16.unit_gens() sage: gens (15, 5) @@ -422,6 +398,7 @@ class IntegerModRing_generic(quotient_ring.QuotientRing_generic, sage.rings.abc. 2 sage: b.multiplicative_order() 4 + sage: TestSuite(Z16).run() Saving and loading:: @@ -572,7 +549,8 @@ def extension(self, poly, name=None, names=None, **kwds): sage: R.<t> = QQ[] sage: Integers(8).extension(t^2 - 3) - Univariate Quotient Polynomial Ring in t over Ring of integers modulo 8 with modulus t^2 + 5 + Univariate Quotient Polynomial Ring in t + over Ring of integers modulo 8 with modulus t^2 + 5 """ if self.modulus() == 1: return self @@ -638,6 +616,7 @@ def multiplicative_subgroups(self): EXAMPLES:: + sage: # needs sage.groups sage: Integers(5).multiplicative_subgroups() ((2,), (4,), ()) sage: Integers(15).multiplicative_subgroups() @@ -649,11 +628,11 @@ def multiplicative_subgroups(self): TESTS:: - sage: IntegerModRing(1).multiplicative_subgroups() + sage: IntegerModRing(1).multiplicative_subgroups() # needs sage.groups ((),) - sage: IntegerModRing(2).multiplicative_subgroups() + sage: IntegerModRing(2).multiplicative_subgroups() # needs sage.groups ((),) - sage: IntegerModRing(3).multiplicative_subgroups() + sage: IntegerModRing(3).multiplicative_subgroups() # needs sage.groups ((2,), ()) """ return tuple(tuple(g.value() for g in H.gens()) @@ -667,7 +646,7 @@ def is_integral_domain(self, proof=None): sage: Integers(389).is_integral_domain() True - sage: Integers(389^2).is_integral_domain() + sage: Integers(389^2).is_integral_domain() # needs sage.libs.pari False TESTS: @@ -688,7 +667,7 @@ def is_unique_factorization_domain(self, proof=None): sage: Integers(389).is_unique_factorization_domain() True - sage: Integers(389^2).is_unique_factorization_domain() + sage: Integers(389^2).is_unique_factorization_domain() # needs sage.libs.pari False """ return self.is_field(proof) @@ -696,7 +675,7 @@ def is_unique_factorization_domain(self, proof=None): @cached_method def is_field(self, proof=None): r""" - Return True precisely if the order is prime. + Return ``True`` precisely if the order is prime. INPUT: @@ -827,8 +806,8 @@ def _pseudo_fraction_field(self): This should be very fast:: - sage: R.<x> = Integers(next_prime(10^101)*next_prime(10^100))[] - sage: x / R.base_ring()(2) + sage: R.<x> = Integers(next_prime(10^101)*next_prime(10^100))[] # needs sage.libs.pari + sage: x / R.base_ring()(2) # needs sage.libs.pari 500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000401*x """ return self @@ -847,18 +826,18 @@ def multiplicative_group_is_cyclic(self): sage: R.multiplicative_group_is_cyclic() True sage: R = Integers(9) - sage: R.multiplicative_group_is_cyclic() + sage: R.multiplicative_group_is_cyclic() # needs sage.libs.pari True sage: Integers(8).multiplicative_group_is_cyclic() False sage: Integers(4).multiplicative_group_is_cyclic() True - sage: Integers(25*3).multiplicative_group_is_cyclic() + sage: Integers(25*3).multiplicative_group_is_cyclic() # needs sage.libs.pari False We test that :trac:`5250` is fixed:: - sage: Integers(162).multiplicative_group_is_cyclic() + sage: Integers(162).multiplicative_group_is_cyclic() # needs sage.libs.pari True """ n = self.order() @@ -883,6 +862,7 @@ def multiplicative_generator(self): EXAMPLES:: + sage: # needs sage.groups sage.libs.pari sage: R = Integers(7); R Ring of integers modulo 7 sage: R.multiplicative_generator() @@ -927,7 +907,7 @@ def quadratic_nonresidue(self): EXAMPLES:: sage: R = Integers(17) - sage: R.quadratic_nonresidue() + sage: R.quadratic_nonresidue() # needs sage.libs.pari 3 sage: R(3).is_square() False @@ -959,6 +939,7 @@ def square_roots_of_one(self): :: + sage: # needs sage.libs.pari sage: v = Integers(9*5).square_roots_of_one(); v (1, 19, 26, 44) sage: [x^2 for x in v] @@ -1132,7 +1113,7 @@ def _pari_order(self): EXAMPLES:: - sage: Zmod(87)._pari_order() + sage: Zmod(87)._pari_order() # needs sage.libs.pari 87 """ try: @@ -1145,10 +1126,11 @@ def _element_constructor_(self, x): """ TESTS:: + sage: # needs sage.rings.finite_rings sage: K2 = GF(2) sage: K3 = GF(3) - sage: K8 = GF(8,'a') - sage: K8(5) # indirect doctest + sage: K8 = GF(8, 'a') + sage: K8(5) # indirect doctest 1 sage: K8('a+1') a + 1 @@ -1172,21 +1154,21 @@ def _element_constructor_(self, x): The following test refers to :trac:`8970`:: sage: R = Zmod(13); a = R(2) - sage: a == R(gap(a)) + sage: a == R(gap(a)) # needs sage.libs.gap True libgap interface (:trac:`23714`):: - sage: a = libgap.eval("Z(13)^2") - sage: a.sage() + sage: a = libgap.eval("Z(13)^2") # needs sage.libs.gap + sage: a.sage() # needs sage.libs.gap 4 - sage: libgap(a.sage()) == a + sage: libgap(a.sage()) == a # needs sage.libs.gap True better syntax for libgap interface:: - sage: a = libgap.Z(13)^2 - sage: libgap(a.sage()) == a + sage: a = libgap.Z(13)^2 # needs sage.libs.gap + sage: libgap(a.sage()) == a # needs sage.libs.gap True """ try: @@ -1224,7 +1206,7 @@ def _coerce_map_from_(self, S): EXAMPLES:: sage: R = Integers(15) - sage: f = R.coerce_map_from(Integers(450)); f # indirect doctest + sage: f = R.coerce_map_from(Integers(450)); f # indirect doctest Natural morphism: From: Ring of integers modulo 450 To: Ring of integers modulo 15 @@ -1295,7 +1277,7 @@ def _convert_map_from_(self, other): EXAMPLES:: - sage: Zmod(81).convert_map_from(Qp(3)) + sage: Zmod(81).convert_map_from(Qp(3)) # needs sage.rings.padics Reduction morphism: From: 3-adic Field with capped relative precision 20 To: Ring of integers modulo 81 @@ -1318,10 +1300,12 @@ def __richcmp__(self, other, op): Ring of integers modulo 12 sage: Z13 = IntegerModRing(13); Z13 Ring of integers modulo 13 + sage: Z11 == Z11, Z11 == Z12, Z11 == Z13 + (True, False, False) sage: F = GF(11); F Finite Field of size 11 - sage: Z11 == Z11, Z11 == Z12, Z11 == Z13, Z11 == F - (True, False, False, False) + sage: Z11 == F + False In :trac:`15229`, the following was implemented:: @@ -1341,7 +1325,7 @@ def __richcmp__(self, other, op): try: c = bool(other.__class__.__base__ != self.__class__.__base__) except AttributeError: # __base__ does not always exists - c = bool(type(other) != type(self)) + c = bool(type(other) is not type(self)) if c: return NotImplemented return richcmp(self.__order, other.__order, op) @@ -1363,12 +1347,12 @@ def unit_gens(self, **kwds): EXAMPLES:: sage: R = IntegerModRing(18) - sage: R.unit_gens() + sage: R.unit_gens() # needs sage.groups (11,) sage: R = IntegerModRing(17) - sage: R.unit_gens() + sage: R.unit_gens() # needs sage.groups (3,) - sage: IntegerModRing(next_prime(10^30)).unit_gens() + sage: IntegerModRing(next_prime(10^30)).unit_gens() # needs sage.groups (5,) The choice of generators is affected by the optional keyword @@ -1376,18 +1360,18 @@ def unit_gens(self, **kwds): See :meth:`unit_group` for details. :: sage: A = Zmod(55) - sage: A.unit_gens(algorithm='sage') + sage: A.unit_gens(algorithm='sage') # needs sage.groups (12, 46) - sage: A.unit_gens(algorithm='pari') + sage: A.unit_gens(algorithm='pari') # needs sage.groups sage.libs.pari (2, 21) TESTS:: - sage: IntegerModRing(2).unit_gens() + sage: IntegerModRing(2).unit_gens() # needs sage.groups () - sage: IntegerModRing(4).unit_gens() + sage: IntegerModRing(4).unit_gens() # needs sage.groups (3,) - sage: IntegerModRing(8).unit_gens() + sage: IntegerModRing(8).unit_gens() # needs sage.groups (7, 5) """ @@ -1398,10 +1382,10 @@ def unit_group_exponent(self): EXAMPLES:: sage: R = IntegerModRing(17) - sage: R.unit_group_exponent() + sage: R.unit_group_exponent() # needs sage.groups 16 sage: R = IntegerModRing(18) - sage: R.unit_group_exponent() + sage: R.unit_group_exponent() # needs sage.groups 6 """ return self.unit_group().exponent() @@ -1413,7 +1397,7 @@ def unit_group_order(self): EXAMPLES:: sage: R = Integers(500) - sage: R.unit_group_order() + sage: R.unit_group_order() # needs sage.groups 200 """ return self.unit_group().order() @@ -1451,70 +1435,76 @@ def unit_group(self, algorithm='sage'): differ in various ways. In the following example, the same cyclic factors are computed, but in a different order:: + sage: # needs sage.groups sage: A = Zmod(15) sage: G = A.unit_group(); G Multiplicative Abelian group isomorphic to C2 x C4 sage: G.gens_values() (11, 7) - sage: H = A.unit_group(algorithm='pari'); H + sage: H = A.unit_group(algorithm='pari'); H # needs sage.libs.pari Multiplicative Abelian group isomorphic to C4 x C2 - sage: H.gens_values() + sage: H.gens_values() # needs sage.libs.pari (7, 11) Here are two examples where the cyclic factors are isomorphic, but are ordered differently and have different generators:: + sage: # needs sage.groups sage: A = Zmod(40) sage: G = A.unit_group(); G Multiplicative Abelian group isomorphic to C2 x C2 x C4 sage: G.gens_values() (31, 21, 17) - sage: H = A.unit_group(algorithm='pari'); H + sage: H = A.unit_group(algorithm='pari'); H # needs sage.libs.pari Multiplicative Abelian group isomorphic to C4 x C2 x C2 - sage: H.gens_values() + sage: H.gens_values() # needs sage.libs.pari (17, 31, 21) + sage: # needs sage.groups sage: A = Zmod(192) sage: G = A.unit_group(); G Multiplicative Abelian group isomorphic to C2 x C16 x C2 sage: G.gens_values() (127, 133, 65) - sage: H = A.unit_group(algorithm='pari'); H + sage: H = A.unit_group(algorithm='pari'); H # needs sage.libs.pari Multiplicative Abelian group isomorphic to C16 x C2 x C2 - sage: H.gens_values() + sage: H.gens_values() # needs sage.libs.pari (133, 127, 65) In the following examples, the cyclic factors are not even isomorphic:: sage: A = Zmod(319) - sage: A.unit_group() + sage: A.unit_group() # needs sage.groups Multiplicative Abelian group isomorphic to C10 x C28 - sage: A.unit_group(algorithm='pari') + sage: A.unit_group(algorithm='pari') # needs sage.groups sage.libs.pari Multiplicative Abelian group isomorphic to C140 x C2 sage: A = Zmod(30.factorial()) - sage: A.unit_group() - Multiplicative Abelian group isomorphic to C2 x C16777216 x C3188646 x C62500 x C2058 x C110 x C156 x C16 x C18 x C22 x C28 - sage: A.unit_group(algorithm='pari') - Multiplicative Abelian group isomorphic to C20499647385305088000000 x C55440 x C12 x C12 x C4 x C2 x C2 x C2 x C2 x C2 x C2 + sage: A.unit_group() # needs sage.groups + Multiplicative Abelian group isomorphic to + C2 x C16777216 x C3188646 x C62500 x C2058 x C110 x C156 x C16 x C18 x C22 x C28 + sage: A.unit_group(algorithm='pari') # needs sage.groups sage.libs.pari + Multiplicative Abelian group isomorphic to + C20499647385305088000000 x C55440 x C12 x C12 x C4 x C2 x C2 x C2 x C2 x C2 x C2 TESTS: We test the cases where the unit group is trivial:: + sage: # needs sage.groups sage: A = Zmod(1) sage: A.unit_group() Trivial Abelian group - sage: A.unit_group(algorithm='pari') + sage: A.unit_group(algorithm='pari') # needs sage.libs.pari Trivial Abelian group sage: A = Zmod(2) sage: A.unit_group() Trivial Abelian group - sage: A.unit_group(algorithm='pari') + sage: A.unit_group(algorithm='pari') # needs sage.libs.pari Trivial Abelian group - sage: Zmod(3).unit_group(algorithm='bogus') + sage: Zmod(3).unit_group(algorithm='bogus') # needs sage.groups Traceback (most recent call last): ... ValueError: unknown algorithm 'bogus' for computing the unit group @@ -1578,7 +1568,7 @@ def _gap_init_(self): sage: R = Integers(12345678900) sage: R Ring of integers modulo 12345678900 - sage: gap(R) # indirect doctest + sage: gap(R) # indirect doctest # needs sage.libs.gap (Integers mod 12345678900) """ return 'ZmodnZ({})'.format(self.order()) @@ -1590,7 +1580,7 @@ def _magma_init_(self, magma): sage: R = Integers(12345678900) sage: R Ring of integers modulo 12345678900 - sage: magma(R) # indirect doctest, optional - magma + sage: magma(R) # indirect doctest, optional - magma Residue class ring of integers modulo 12345678900 """ return 'Integers({})'.format(self.order()) @@ -1624,7 +1614,7 @@ def crt(v): EXAMPLES:: sage: from sage.rings.finite_rings.integer_mod_ring import crt - sage: crt([mod(3, 8),mod(1,19),mod(7, 15)]) + sage: crt([mod(3, 8), mod(1,19), mod(7, 15)]) 1027 """ if len(v) == 0: diff --git a/src/sage/rings/finite_rings/maps_finite_field.py b/src/sage/rings/finite_rings/maps_finite_field.py index 07d351c165a..0ae08a3d25d 100644 --- a/src/sage/rings/finite_rings/maps_finite_field.py +++ b/src/sage/rings/finite_rings/maps_finite_field.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings """ Structure maps for finite fields diff --git a/src/sage/rings/finite_rings/residue_field.pyx b/src/sage/rings/finite_rings/residue_field.pyx index 83436bd6582..b466ee5e2c1 100644 --- a/src/sage/rings/finite_rings/residue_field.pyx +++ b/src/sage/rings/finite_rings/residue_field.pyx @@ -3,14 +3,15 @@ Finite residue fields We can take the residue field of maximal ideals in the ring of integers of number fields. We can also take the residue field of irreducible -polynomials over `GF(p)`. +polynomials over `\GF{p}`. EXAMPLES:: - sage: K.<a> = NumberField(x^3-7) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 7) sage: P = K.ideal(29).factor()[0][0] - sage: k = K.residue_field(P) - sage: k + sage: k = K.residue_field(P); k Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) sage: k.order() 841 @@ -18,9 +19,11 @@ EXAMPLES:: We reduce mod a prime for which the ring of integers is not monogenic (i.e., 2 is an essential discriminant divisor):: + sage: # needs sage.rings.number_field sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8) sage: F = K.factor(2); F - (Fractional ideal (-1/2*a^2 + 1/2*a - 1)) * (Fractional ideal (-a^2 + 2*a - 3)) * (Fractional ideal (3/2*a^2 - 5/2*a + 4)) + (Fractional ideal (-1/2*a^2 + 1/2*a - 1)) * (Fractional ideal (-a^2 + 2*a - 3)) + * (Fractional ideal (3/2*a^2 - 5/2*a + 4)) sage: F[0][0].residue_field() Residue field of Fractional ideal (-1/2*a^2 + 1/2*a - 1) sage: F[1][0].residue_field() @@ -35,10 +38,12 @@ We can also form residue fields from `\ZZ`:: And for polynomial rings over finite fields:: + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(5)[] sage: I = R.ideal(t^2 + 2) sage: k = ResidueField(I); k - Residue field in tbar of Principal ideal (t^2 + 2) of Univariate Polynomial Ring in t over Finite Field of size 5 + Residue field in tbar of Principal ideal (t^2 + 2) of + Univariate Polynomial Ring in t over Finite Field of size 5 AUTHORS: @@ -51,6 +56,7 @@ AUTHORS: TESTS:: + sage: # needs sage.rings.number_field sage: K.<z> = CyclotomicField(7) sage: P = K.factor(17)[0][0] sage: ff = K.residue_field(P) @@ -63,15 +69,17 @@ TESTS:: Verify that :trac:`15192` has been resolved:: - sage: a.is_unit() + sage: a.is_unit() # needs sage.rings.number_field True + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(11)[]; P = R.ideal(t^3 + t + 4) sage: ff.<a> = ResidueField(P) sage: a == ff(t) True sage: parent(a*a) - Residue field in a of Principal ideal (t^3 + t + 4) of Univariate Polynomial Ring in t over Finite Field of size 11 + Residue field in a of Principal ideal (t^3 + t + 4) of + Univariate Polynomial Ring in t over Finite Field of size 11 Verify that :trac:`7475` is fixed:: @@ -81,40 +89,51 @@ Verify that :trac:`7475` is fixed:: Reducing a curve modulo a prime:: - sage: K.<s> = NumberField(x^2+23) + sage: # needs sage.rings.number_field + sage: K.<s> = NumberField(x^2 + 23) sage: OK = K.ring_of_integers() sage: E = EllipticCurve([0,0,0,K(1),K(5)]) sage: pp = K.factor(13)[0][0] sage: Fpp = OK.residue_field(pp) sage: E.base_extend(Fpp) - Elliptic Curve defined by y^2 = x^3 + x + 5 over Residue field of Fractional ideal (13, 1/2*s + 9/2) + Elliptic Curve defined by y^2 = x^3 + x + 5 over + Residue field of Fractional ideal (13, 1/2*s + 9/2) + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(11)[] sage: P = R.ideal(t^3 + t + 4) sage: ff.<a> = R.residue_field(P) - sage: E = EllipticCurve([0,0,0,R(1),R(t)]) - sage: E.base_extend(ff) - Elliptic Curve defined by y^2 = x^3 + x + a over Residue field in a of Principal ideal (t^3 + t + 4) of Univariate Polynomial Ring in t over Finite Field of size 11 + sage: E = EllipticCurve([0,0,0,R(1),R(t)]) # needs sage.schemes + sage: E.base_extend(ff) # needs sage.schemes + Elliptic Curve defined by y^2 = x^3 + x + a over + Residue field in a of Principal ideal (t^3 + t + 4) of + Univariate Polynomial Ring in t over Finite Field of size 11 Calculating Groebner bases over various residue fields. First over a small non-prime field:: - sage: F1.<u> = NumberField(x^6 + 6*x^5 + 124*x^4 + 452*x^3 + 4336*x^2 + 8200*x + 42316) + sage: # needs sage.rings.number_field + sage: F1.<u> = NumberField(x^6 + 6*x^5 + 124*x^4 + ....: + 452*x^3 + 4336*x^2 + 8200*x + 42316) sage: reduct_id = F1.factor(47)[0][0] sage: Rf = F1.residue_field(reduct_id) sage: type(Rf) - <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_pari_ffelt_with_category'> + <class 'sage.rings.finite_rings.residue_field_pari_ffelt.ResidueFiniteField_pari_ffelt_with_category'> sage: Rf.cardinality().factor() 47^3 sage: R.<X, Y> = PolynomialRing(Rf) sage: ubar = Rf(u) sage: I = ideal([ubar*X + Y]); I - Ideal (ubar*X + Y) of Multivariate Polynomial Ring in X, Y over Residue field in ubar of Fractional ideal (47, 517/55860*u^5 + 235/3724*u^4 + 9829/13965*u^3 + 54106/13965*u^2 + 64517/27930*u + 755696/13965) + Ideal (ubar*X + Y) of Multivariate Polynomial Ring in X, Y over + Residue field in ubar of Fractional ideal + (47, 517/55860*u^5 + 235/3724*u^4 + 9829/13965*u^3 + + 54106/13965*u^2 + 64517/27930*u + 755696/13965) sage: I.groebner_basis() [X + (-19*ubar^2 - 5*ubar - 17)*Y] And now over a large prime field:: + sage: # needs sage.rings.number_field sage: x = ZZ['x'].0 sage: F1.<u> = NumberField(x^2 + 6*x + 324) sage: reduct_id = F1.prime_above(next_prime(2^42)) @@ -133,47 +152,48 @@ And now over a large prime field:: [Z^2 + 4398046511117*X, Y + Z] """ -#***************************************************************************** -# Copyright (C) 2007 David Roe <roed@math.harvard.edu> -# William Stein <wstein@gmail.com> +# ***************************************************************************** +# Copyright (C) 2007-2019 David Roe <roed@math.harvard.edu> +# 2007 William Stein <wstein@gmail.com> +# 2008 John Cremona +# 2008 Robert Bradshaw +# 2009 Nick Alexander +# 2010 Robert L. Miller +# 2010-2013 Simon King +# 2010-2017 Jeroen Demeyer +# 2012 Travis Scrimshaw +# 2016-2021 Frรฉdรฉric Chapoton +# 2021-2022 Antonio Rojas # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.rings.ring cimport Field from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational from sage.categories.homset import Hom -from sage.categories.basic import Fields, Rings from sage.categories.pushout import AlgebraicExtensionFunctor -from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.finite_rings.finite_field_constructor import zech_log_bound, FiniteField as GF -from sage.rings.finite_rings.finite_field_givaro import FiniteField_givaro -from sage.rings.finite_rings.finite_field_ntl_gf2e import FiniteField_ntl_gf2e from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn -from sage.rings.finite_rings.finite_field_pari_ffelt import FiniteField_pari_ffelt from sage.rings.ideal import is_Ideal -from sage.structure.element cimport Element - -from sage.rings.number_field.number_field_element import is_NumberFieldElement +from sage.rings.number_field.number_field_element_base import NumberFieldElement_base from sage.rings.number_field.number_field_ideal import is_NumberFieldIdeal -from sage.modules.free_module_element import FreeModuleElement from sage.rings.fraction_field import is_FractionField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_element import Polynomial +from sage.structure.element cimport Element, parent, Vector from sage.structure.factory import UniqueFactory -from sage.structure.element cimport parent from sage.structure.richcmp cimport richcmp, richcmp_not_equal @@ -185,50 +205,53 @@ class ResidueFieldFactory(UniqueFactory): INPUT: - - ``p`` -- a prime ideal of an order in a number field. + - ``p`` -- a prime ideal of an order in a number field. - - ``names`` -- the variable name for the finite field created. - Defaults to the name of the number field variable but with - bar placed after it. + - ``names`` -- the variable name for the finite field created. + Defaults to the name of the number field variable but with + bar placed after it. - - ``check`` -- whether or not to check if `p` is prime. + - ``check`` -- whether or not to check if `p` is prime. OUTPUT: - - The residue field at the prime `p`. + The residue field at the prime `p`. EXAMPLES:: - sage: K.<a> = NumberField(x^3-7) - sage: P = K.ideal(29).factor()[0][0] - sage: ResidueField(P) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 7) # needs sage.rings.number_field + sage: P = K.ideal(29).factor()[0][0] # needs sage.rings.number_field + sage: ResidueField(P) # needs sage.rings.number_field Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) The result is cached:: - sage: ResidueField(P) is ResidueField(P) + sage: ResidueField(P) is ResidueField(P) # needs sage.rings.number_field True - sage: k = K.residue_field(P); k + sage: k = K.residue_field(P); k # needs sage.rings.number_field Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) - sage: k.order() + sage: k.order() # needs sage.rings.number_field 841 It also works for polynomial rings:: sage: R.<t> = GF(31)[] sage: P = R.ideal(t^5 + 2*t + 11) - sage: ResidueField(P) - Residue field in tbar of Principal ideal (t^5 + 2*t + 11) of Univariate Polynomial Ring in t over Finite Field of size 31 + sage: ResidueField(P) # needs sage.rings.finite_rings + Residue field in tbar of Principal ideal (t^5 + 2*t + 11) of + Univariate Polynomial Ring in t over Finite Field of size 31 - sage: ResidueField(P) is ResidueField(P) + sage: ResidueField(P) is ResidueField(P) # needs sage.rings.finite_rings True - sage: k = ResidueField(P); k.order() + sage: k = ResidueField(P); k.order() # needs sage.rings.finite_rings 28629151 An example where the generator of the number field doesn't generate the residue class field:: - sage: K.<a> = NumberField(x^3-875) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^3 - 875) sage: P = K.ideal(5).factor()[0][0]; k = K.residue_field(P); k Residue field in abar of Fractional ideal (5, 1/25*a^2 - 2/5*a - 1) sage: k.polynomial() @@ -238,7 +261,9 @@ class ResidueFieldFactory(UniqueFactory): An example where the residue class field is large but of degree 1:: - sage: K.<a> = NumberField(x^3-875); P = K.ideal(2007).factor()[2][0]; k = K.residue_field(P); k + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^3 - 875) + sage: P = K.ideal(2007).factor()[2][0]; k = K.residue_field(P); k Residue field of Fractional ideal (223, 1/5*a + 11) sage: k(a) 168 @@ -247,17 +272,21 @@ class ResidueFieldFactory(UniqueFactory): And for polynomial rings:: + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(next_prime(2^18))[] sage: P = R.ideal(t - 5) sage: k = ResidueField(P); k - Residue field of Principal ideal (t + 262142) of Univariate Polynomial Ring in t over Finite Field of size 262147 + Residue field of Principal ideal (t + 262142) of + Univariate Polynomial Ring in t over Finite Field of size 262147 sage: k(t) 5 In this example, 2 is an inessential discriminant divisor, so divides the index of ``ZZ[a]`` in the maximal order for all ``a``:: - sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8); P = K.ideal(2).factor()[0][0]; P + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8) + sage: P = K.ideal(2).factor()[0][0]; P Fractional ideal (-1/2*a^2 + 1/2*a - 1) sage: F = K.residue_field(P); F Residue field of Fractional ideal (-1/2*a^2 + 1/2*a - 1) @@ -276,8 +305,8 @@ class ResidueFieldFactory(UniqueFactory): TESTS:: - sage: K.<a> = NumberField(polygen(QQ)) - sage: K.residue_field(K.ideal(3)) + sage: K.<a> = NumberField(polygen(QQ)) # needs sage.rings.number_field + sage: K.residue_field(K.ideal(3)) # needs sage.rings.number_field Residue field of Fractional ideal (3) """ def create_key_and_extra_args(self, p, names = None, check=True, impl=None, **kwds): @@ -287,20 +316,21 @@ class ResidueFieldFactory(UniqueFactory): EXAMPLES:: - sage: K.<a> = NumberField(x^3-7) - sage: ResidueField(K.ideal(29).factor()[0][0]) # indirect doctest + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 7) # needs sage.rings.number_field + sage: ResidueField(K.ideal(29).factor()[0][0]) # indirect doctest # needs sage.rings.number_field Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) """ if check: if not is_Ideal(p): if isinstance(p, (int, Integer, Rational)): p = ZZ.ideal(p) - elif is_NumberFieldElement(p): + elif isinstance(p, NumberFieldElement_base): if p.parent().is_field(): p = p.parent().ring_of_integers().ideal(p) else: p = p.parent().ideal(p) - elif is_Polynomial(p): + elif isinstance(p, Polynomial): p = p.parent().ideal(p) #elif isinstance(p.parent(), FractionField_1poly_field): # p = p.parent().ring_of_integers().ideal(p) @@ -334,9 +364,10 @@ class ResidueFieldFactory(UniqueFactory): EXAMPLES:: - sage: K.<a> = NumberField(x^3-7) - sage: P = K.ideal(29).factor()[0][0] - sage: ResidueField(P) is ResidueField(P) # indirect doctest + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 7) # needs sage.rings.number_field + sage: P = K.ideal(29).factor()[0][0] # needs sage.rings.number_field + sage: ResidueField(P) is ResidueField(P) # indirect doctest # needs sage.rings.number_field True """ p, names, impl = key @@ -354,13 +385,30 @@ class ResidueFieldFactory(UniqueFactory): else: q = characteristic**(f.degree()) if q < zech_log_bound and (impl is None or impl == 'givaro'): - return ResidueFiniteField_givaro(p, q, names, f, None, None, None) - elif (q % 2 == 0) and (impl is None or impl == 'ntl'): - return ResidueFiniteField_ntl_gf2e(q, names, f, "poly", p, None, None, None) - elif impl is None or impl == 'pari': - return ResidueFiniteField_pari_ffelt(p, characteristic, names, f, None, None, None) - else: - raise ValueError("unrecognized finite field type") + try: + from .residue_field_givaro import ResidueFiniteField_givaro + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_givaro(p, q, names, f, None, None, None) + if q % 2 == 0 and (impl is None or impl == 'ntl'): + try: + from .residue_field_ntl_gf2e import ResidueFiniteField_ntl_gf2e + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_ntl_gf2e(q, names, f, "poly", p, None, None, None) + if impl is None or impl == 'pari': + try: + from .residue_field_pari_ffelt import ResidueFiniteField_pari_ffelt + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_pari_ffelt(p, characteristic, names, f, None, None, None) + raise ValueError("unrecognized finite field type") # Should generalize to allowing residue fields of relative extensions to be extensions of finite fields. if is_NumberFieldIdeal(p): @@ -413,22 +461,42 @@ class ResidueFieldFactory(UniqueFactory): else: q = characteristic**(f.degree()) if q < zech_log_bound and (impl is None or impl == 'givaro'): - return ResidueFiniteField_givaro(p, q, names, f, to_vs, to_order, PB) - elif (q % 2 == 0) and (impl is None or impl == 'ntl'): - return ResidueFiniteField_ntl_gf2e(q, names, f, "poly", p, to_vs, to_order, PB) - elif impl is None or impl == 'pari': - return ResidueFiniteField_pari_ffelt(p, characteristic, names, f, to_vs, to_order, PB) - else: - raise ValueError("unrecognized finite field type") + try: + from .residue_field_givaro import ResidueFiniteField_givaro + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_givaro(p, q, names, f, to_vs, to_order, PB) + elif q % 2 == 0 and (impl is None or impl == 'ntl'): + try: + from .residue_field_ntl_gf2e import ResidueFiniteField_ntl_gf2e + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_ntl_gf2e(q, names, f, "poly", p, to_vs, to_order, PB) + if impl is None or impl == 'pari': + try: + from .residue_field_pari_ffelt import ResidueFiniteField_pari_ffelt + except ImportError: + if impl is not None: + raise + else: + return ResidueFiniteField_pari_ffelt(p, characteristic, names, f, to_vs, to_order, PB) + raise ValueError("unrecognized finite field type") + ResidueField = ResidueFieldFactory("ResidueField") + class ResidueField_generic(Field): """ The class representing a generic residue field. EXAMPLES:: + sage: # needs sage.rings.number_field sage: I = QQ[i].factor(2)[0][0]; I Fractional ideal (I + 1) sage: k = I.residue_field(); k @@ -436,10 +504,12 @@ class ResidueField_generic(Field): sage: type(k) <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_prime_modn_with_category'> + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(29)[]; P = R.ideal(t^2 + 2); k.<a> = ResidueField(P); k - Residue field in a of Principal ideal (t^2 + 2) of Univariate Polynomial Ring in t over Finite Field of size 29 - sage: type(k) - <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_givaro_with_category'> + Residue field in a of Principal ideal (t^2 + 2) of + Univariate Polynomial Ring in t over Finite Field of size 29 + sage: type(k) # needs sage.libs.linbox + <class 'sage.rings.finite_rings.residue_field_givaro.ResidueFiniteField_givaro_with_category'> """ def __init__(self, p): """ @@ -458,25 +528,30 @@ class ResidueField_generic(Field): EXAMPLES:: - sage: K.<a> = NumberField(x^3-17) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 17) sage: P = K.ideal(29).factor()[0][0] - sage: k = K.residue_field(P) # indirect doctest - sage: F = ZZ.residue_field(17) # indirect doctest - - sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) - sage: k.<a> = P.residue_field() # indirect doctest + sage: k = K.residue_field(P) # indirect doctest - sage: k.category() - Category of finite enumerated fields + sage: F = ZZ.residue_field(17) # indirect doctest sage: F.category() Join of Category of finite enumerated fields and Category of subquotients of monoids and Category of quotients of semigroups + sage: # needs sage.rings.finite_rings + sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) + sage: k.<a> = P.residue_field() # indirect doctest + sage: k.category() + Category of finite enumerated fields + TESTS:: - sage: TestSuite(k).run() sage: TestSuite(F).run() + + sage: # needs sage.modules sage.rings.finite_rings + sage: TestSuite(k).run() """ self.p = p # Note: we don't call Parent.__init__ since many residue fields use multiple inheritance and will be calling __init__ via their other superclass. @@ -497,10 +572,10 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<z> = CyclotomicField(7) sage: P = K.factor(17)[0][0] - sage: k = K.residue_field(P) - sage: k + sage: k = K.residue_field(P); k Residue field in zbar of Fractional ideal (17) sage: F, R = k.construction() sage: F @@ -523,9 +598,11 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + x + 1) sage: P = K.ideal(29).factor()[0][0] - sage: k = K.residue_field(P) # indirect doctest + sage: k = K.residue_field(P) # indirect doctest sage: k.ideal() is P True sage: p = next_prime(2^40); p @@ -534,10 +611,12 @@ class ResidueField_generic(Field): sage: k.ideal().norm() == p True + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k.<a> = R.residue_field(P) sage: k.ideal() - Principal ideal (t^3 + t^2 + 7) of Univariate Polynomial Ring in t over Finite Field of size 17 + Principal ideal (t^3 + t^2 + 7) of + Univariate Polynomial Ring in t over Finite Field of size 17 """ return self.p @@ -559,9 +638,11 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.rings.finite_rings.residue_field import ResidueField_generic - sage: K.<i> = NumberField(x^2+1) - sage: P = K.ideal(-3*i-2) + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) + sage: P = K.ideal(-3*i - 2) sage: OK = K.maximal_order() sage: F = OK.residue_field(P) sage: ResidueField_generic._element_constructor_(F, i) @@ -569,12 +650,13 @@ class ResidueField_generic(Field): With :trac:`8800`, we also have:: - sage: ResidueField_generic._element_constructor_(F, GF(13)(8)) + sage: ResidueField_generic._element_constructor_(F, GF(13)(8)) # needs sage.rings.number_field 8 Here is a test that was temporarily removed, but newly introduced in :trac:`8800`:: + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k.<a> = P.residue_field() sage: k(t) @@ -605,23 +687,26 @@ class ResidueField_generic(Field): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) - sage: P = K.ideal(-3*i-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) + sage: P = K.ideal(-3*i - 2) sage: OK = K.maximal_order() sage: F = OK.residue_field(P) - sage: F.has_coerce_map_from(GF(13)) # indirect doctest + sage: F.has_coerce_map_from(GF(13)) # indirect doctest True TESTS: Check that :trac:`11319` is fixed:: - sage: GF(13).has_coerce_map_from(F) + sage: GF(13).has_coerce_map_from(F) # needs sage.rings.number_field True + sage: # needs sage.rings.number_field sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k.<a> = P.residue_field() - sage: k.has_coerce_map_from(Qp(17)) # indirect doctest + sage: k.has_coerce_map_from(Qp(17)) # indirect doctest # needs sage.rings.padics False """ OK = self.p.ring() @@ -635,18 +720,21 @@ class ResidueField_generic(Field): EXAMPLES:: - sage: K.<a> = NumberField(x^3-7) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 7) sage: P = K.ideal(29).factor()[0][0] - sage: k = K.residue_field(P) - sage: k + sage: k = K.residue_field(P); k Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) sage: F = ZZ.residue_field(17); F Residue field of Integers modulo 17 + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) - sage: k.<a> = P.residue_field(); k # indirect doctest - Residue field in a of Principal ideal (t^3 + t^2 + 7) of Univariate Polynomial Ring in t over Finite Field of size 17 + sage: k.<a> = P.residue_field(); k # indirect doctest + Residue field in a of Principal ideal (t^3 + t^2 + 7) of + Univariate Polynomial Ring in t over Finite Field of size 17 """ if self.p.ring() is ZZ: return "Residue field of Integers modulo %s"%self.p.gen() @@ -659,17 +747,20 @@ class ResidueField_generic(Field): EXAMPLES:: - sage: K.<a> = NumberField(x^3-7) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 7) sage: P = K.ideal(29).factor()[0][0] - sage: k =K.residue_field(P) + sage: k = K.residue_field(P) sage: OK = K.maximal_order() sage: c = OK(a) sage: b = k(a) sage: k.lift(13*b + 5) 13*a + 5 - sage: k.lift(12821*b+918) + sage: k.lift(12821*b + 918) 3*a + 19 + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k.<a> = P.residue_field() sage: k.lift(a^2 + 5) @@ -690,19 +781,23 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage.symbolic sage: I = QQ[2^(1/3)].factor(2)[0][0]; I Fractional ideal (a) sage: k = I.residue_field(); k Residue field of Fractional ideal (a) sage: pi = k.reduction_map(); pi Partially defined reduction map: - From: Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873? + From: Number Field in a with defining polynomial x^3 - 2 + with a = 1.259921049894873? To: Residue field of Fractional ideal (a) sage: pi.domain() Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873? sage: pi.codomain() Residue field of Fractional ideal (a) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 32) sage: F = K.factor(2)[0][0].residue_field() sage: F.reduction_map().domain() @@ -712,11 +807,14 @@ class ResidueField_generic(Field): sage: F.reduction_map().codomain() Residue field of Fractional ideal (1/4*a) + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k.<a> = P.residue_field(); f = k.reduction_map(); f Partially defined reduction map: - From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 17 - To: Residue field in a of Principal ideal (t^3 + t^2 + 7) of Univariate Polynomial Ring in t over Finite Field of size 17 + From: Fraction Field of Univariate Polynomial Ring in t + over Finite Field of size 17 + To: Residue field in a of Principal ideal (t^3 + t^2 + 7) of + Univariate Polynomial Ring in t over Finite Field of size 17 sage: f(1/t) 12*a^2 + 12*a """ @@ -729,6 +827,7 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field sage.symbolic sage: I = QQ[3^(1/3)].factor(5)[1][0]; I Fractional ideal (a - 2) sage: k = I.residue_field(); k @@ -736,20 +835,24 @@ class ResidueField_generic(Field): sage: f = k.lift_map(); f Lifting map: From: Residue field of Fractional ideal (a - 2) - To: Maximal Order in Number Field in a with defining polynomial x^3 - 3 with a = 1.442249570307409? + To: Maximal Order in Number Field in a with defining polynomial x^3 - 3 + with a = 1.442249570307409? sage: f.domain() Residue field of Fractional ideal (a - 2) sage: f.codomain() - Maximal Order in Number Field in a with defining polynomial x^3 - 3 with a = 1.442249570307409? + Maximal Order in Number Field in a with defining polynomial x^3 - 3 + with a = 1.442249570307409? sage: f(k.0) 1 + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k.<a> = P.residue_field() sage: f = k.lift_map(); f (map internal to coercion system -- copy before use) Lifting map: - From: Residue field in a of Principal ideal (t^3 + t^2 + 7) of Univariate Polynomial Ring in t over Finite Field of size 17 + From: Residue field in a of Principal ideal (t^3 + t^2 + 7) of + Univariate Polynomial Ring in t over Finite Field of size 17 To: Univariate Polynomial Ring in t over Finite Field of size 17 sage: f(a^2 + 5) t^2 + 5 @@ -766,7 +869,9 @@ class ResidueField_generic(Field): EXAMPLES:: - sage: K.<a> = NumberField(x^3-11) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 11) sage: F = K.ideal(37).factor(); F (Fractional ideal (37, a + 9)) * (Fractional ideal (37, a + 12)) * (Fractional ideal (-2*a + 5)) sage: k = K.residue_field(F[0][0]) @@ -774,6 +879,7 @@ class ResidueField_generic(Field): sage: k == l False + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k.<a> = P.residue_field() sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 11) @@ -798,11 +904,15 @@ class ResidueField_generic(Field): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + x + 1) - sage: hash(K.residue_field(K.prime_above(17))) # random + sage: hash(K.residue_field(K.prime_above(17))) # random -6463132282686559142 - sage: hash(K.residue_field(K.prime_above(2^60))) # random + sage: hash(K.residue_field(K.prime_above(2^60))) # random -6939519969600666586 + + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(13)[] sage: hash(R.residue_field(t + 2)) # random 3521289879659800254 @@ -819,21 +929,26 @@ cdef class ReductionMap(Map): EXAMPLES:: + sage: # needs sage.rings.number_field sage.symbolic sage: I = QQ[sqrt(17)].factor(5)[0][0]; I Fractional ideal (5) sage: k = I.residue_field(); k Residue field in sqrt17bar of Fractional ideal (5) sage: R = k.reduction_map(); R Partially defined reduction map: - From: Number Field in sqrt17 with defining polynomial x^2 - 17 with sqrt17 = 4.123105625617660? + From: Number Field in sqrt17 with defining polynomial x^2 - 17 + with sqrt17 = 4.123105625617660? To: Residue field in sqrt17bar of Fractional ideal (5) + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(next_prime(2^20))[]; P = R.ideal(t^2 + t + 1) sage: k = P.residue_field() sage: k.reduction_map() Partially defined reduction map: - From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 1048583 - To: Residue field in tbar of Principal ideal (t^2 + t + 1) of Univariate Polynomial Ring in t over Finite Field of size 1048583 + From: Fraction Field of + Univariate Polynomial Ring in t over Finite Field of size 1048583 + To: Residue field in tbar of Principal ideal (t^2 + t + 1) of + Univariate Polynomial Ring in t over Finite Field of size 1048583 """ def __init__(self, K, F, to_vs, to_order, PB, PBinv): """ @@ -841,6 +956,8 @@ cdef class ReductionMap(Map): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8) sage: F = K.factor(2)[0][0].residue_field() sage: F.reduction_map() @@ -848,6 +965,7 @@ cdef class ReductionMap(Map): From: Number Field in a with defining polynomial x^3 + x^2 - 2*x + 8 To: Residue field of Fractional ideal (-1/2*a^2 + 1/2*a - 1) + sage: # needs sage.rings.number_field sage: K.<theta_5> = CyclotomicField(5) sage: F = K.factor(7)[0][0].residue_field() sage: F.reduction_map() @@ -855,14 +973,17 @@ cdef class ReductionMap(Map): From: Cyclotomic Field of order 5 and degree 4 To: Residue field in theta_5bar of Fractional ideal (7) + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(2)[]; P = R.ideal(t^7 + t^6 + t^5 + t^4 + 1) sage: k = P.residue_field() - sage: k.reduction_map() + sage: k.reduction_map() # needs sage.libs.ntl Partially defined reduction map: - From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) - To: Residue field in tbar of Principal ideal (t^7 + t^6 + t^5 + t^4 + 1) of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) - sage: type(k) - <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_givaro_with_category'> + From: Fraction Field of + Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + To: Residue field in tbar of Principal ideal (t^7 + t^6 + t^5 + t^4 + 1) of + Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + sage: type(k) # needs sage.libs.linbox + <class 'sage.rings.finite_rings.residue_field_givaro.ResidueFiniteField_givaro_with_category'> """ self._K = K self._F = F # finite field @@ -880,15 +1001,17 @@ cdef class ReductionMap(Map): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 1) sage: F = K.factor(2)[0][0].residue_field() sage: r = F.reduction_map() - sage: cr = copy(r) # indirect doctest + sage: cr = copy(r) # indirect doctest sage: cr Partially defined reduction map: From: Number Field in a with defining polynomial x^2 + 1 To: Residue field of Fractional ideal (a + 1) - sage: cr == r # todo: comparison not implemented + sage: cr == r # not implemented True sage: r(2 + a) == cr(2 + a) True @@ -909,15 +1032,17 @@ cdef class ReductionMap(Map): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 1) sage: F = K.factor(2)[0][0].residue_field() sage: r = F.reduction_map() - sage: cr = copy(r) # indirect doctest + sage: cr = copy(r) # indirect doctest sage: cr Partially defined reduction map: From: Number Field in a with defining polynomial x^2 + 1 To: Residue field of Fractional ideal (a + 1) - sage: cr == r # todo: comparison not implemented + sage: cr == r # not implemented True sage: r(2 + a) == cr(2 + a) True @@ -941,6 +1066,8 @@ cdef class ReductionMap(Map): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 1) sage: F = K.factor(2)[0][0].residue_field() sage: r = F.reduction_map(); r @@ -950,14 +1077,17 @@ cdef class ReductionMap(Map): We test that calling the function also works after copying:: + sage: # needs sage.rings.number_field sage: r = copy(r) - sage: r(2 + a) # indirect doctest + sage: r(2 + a) # indirect doctest 1 sage: r(a/2) Traceback (most recent call last): ... - ZeroDivisionError: Cannot reduce field element 1/2*a modulo Fractional ideal (a + 1): it has negative valuation + ZeroDivisionError: Cannot reduce field element 1/2*a + modulo Fractional ideal (a + 1): it has negative valuation + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(2)[]; h = t^5 + t^2 + 1 sage: k.<a> = R.residue_field(h) sage: K = R.fraction_field() @@ -969,17 +1099,19 @@ cdef class ReductionMap(Map): sage: f(1/h) Traceback (most recent call last): ... - ZeroDivisionError: division by zero in finite field + ZeroDivisionError... An example to show that the issue raised in :trac:`1951` has been fixed:: + sage: # needs sage.rings.number_field sage: K.<i> = NumberField(x^2 + 1) - sage: P1, P2 = [g[0] for g in K.factor(5)]; (P1,P2) + sage: P1, P2 = [g[0] for g in K.factor(5)]; P1, P2 (Fractional ideal (-i - 2), Fractional ideal (2*i + 1)) sage: a = 1/(1+2*i) - sage: F1, F2 = [g.residue_field() for g in [P1,P2]]; (F1,F2) - (Residue field of Fractional ideal (-i - 2), Residue field of Fractional ideal (2*i + 1)) + sage: F1, F2 = [g.residue_field() for g in [P1,P2]]; F1, F2 + (Residue field of Fractional ideal (-i - 2), + Residue field of Fractional ideal (2*i + 1)) sage: a.valuation(P1) 0 sage: F1(i/7) @@ -991,7 +1123,8 @@ cdef class ReductionMap(Map): sage: F2(a) Traceback (most recent call last): ... - ZeroDivisionError: Cannot reduce field element -2/5*i + 1/5 modulo Fractional ideal (2*i + 1): it has negative valuation + ZeroDivisionError: Cannot reduce field element -2/5*i + 1/5 + modulo Fractional ideal (2*i + 1): it has negative valuation """ # The reduction map is just x |--> F(to_vs(x) * (PB**(-1))) if # either x is integral or the denominator of x is coprime to @@ -1049,13 +1182,16 @@ cdef class ReductionMap(Map): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^5 - 5*x + 2) sage: P = K.ideal(47).factor()[0][0] sage: k = K.residue_field(P) sage: f = k.convert_map_from(K) sage: s = f.section(); s Lifting map: - From: Residue field in abar of Fractional ideal (-14*a^4 + 24*a^3 + 26*a^2 - 58*a + 15) + From: Residue field in abar of + Fractional ideal (-14*a^4 + 24*a^3 + 26*a^2 - 58*a + 15) To: Number Field in a with defining polynomial x^5 - 5*x + 2 sage: s(k.gen()) a @@ -1070,14 +1206,17 @@ cdef class ReductionMap(Map): sage: s(l.gen()).parent() Number Field in b with defining polynomial x^5 + 17*x + 1 + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(2)[]; h = t^5 + t^2 + 1 sage: k.<a> = R.residue_field(h) sage: K = R.fraction_field() sage: f = k.convert_map_from(K) - sage: f.section() + sage: f.section() # needs sage.libs.ntl Lifting map: - From: Residue field in a of Principal ideal (t^5 + t^2 + 1) of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) - To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + From: Residue field in a of Principal ideal (t^5 + t^2 + 1) of + Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + To: Fraction Field of + Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) """ if self._section is None: self._section = LiftingMap(self, self._to_order, self._PB) @@ -1091,7 +1230,9 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: - sage: K.<a> = NumberField(x^3-7) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 7) sage: P = K.ideal(29).factor()[0][0] sage: k = K.residue_field(P) sage: OK = K.maximal_order() @@ -1100,6 +1241,7 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): sage: (1+abar)^179 24*abar + 12 + sage: # needs sage.rings.number_field sage: phi = k.coerce_map_from(OK); phi Ring morphism: From: Maximal Order in Number Field in a with defining polynomial x^3 - 7 @@ -1109,12 +1251,14 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): sage: phi(OK.1) abar + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(19)[]; P = R.ideal(t^2 + 5) sage: k.<a> = R.residue_field(P) sage: f = k.coerce_map_from(R); f Ring morphism: From: Univariate Polynomial Ring in t over Finite Field of size 19 - To: Residue field in a of Principal ideal (t^2 + 5) of Univariate Polynomial Ring in t over Finite Field of size 19 + To: Residue field in a of Principal ideal (t^2 + 5) of + Univariate Polynomial Ring in t over Finite Field of size 19 """ def __init__(self, K, F, to_vs, to_order, PB, PBinv): """ @@ -1132,6 +1276,7 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): We create a residue field homomorphism:: + sage: # needs sage.rings.number_field sage: K.<theta> = CyclotomicField(5) sage: P = K.factor(7)[0][0] sage: P.residue_class_degree() @@ -1145,6 +1290,7 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): sage: type(phi) <class 'sage.rings.finite_rings.residue_field.ResidueFieldHomomorphism_global'> + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(2)[]; P = R.ideal(t^7 + t^6 + t^5 + t^4 + 1) sage: k = P.residue_field(); f = k.coerce_map_from(R) sage: f(t^10) @@ -1165,7 +1311,9 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: - sage: K.<a> = NumberField(x^3-x+8) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - x + 8) sage: P = K.ideal(29).factor()[0][0] sage: k = K.residue_field(P) sage: OK = K.maximal_order() @@ -1174,7 +1322,7 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): Ring morphism: From: Maximal Order in Number Field in a with defining polynomial x^3 - x + 8 To: Residue field in abar of Fractional ideal (29) - sage: psi == phi # todo: comparison not implemented + sage: psi == phi # not implemented True sage: psi(OK.an_element()) == phi(OK.an_element()) True @@ -1195,7 +1343,9 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: - sage: K.<a> = NumberField(x^3-x+8) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - x + 8) sage: P = K.ideal(29).factor()[0][0] sage: k = K.residue_field(P) sage: OK = K.maximal_order() @@ -1204,7 +1354,7 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): Ring morphism: From: Maximal Order in Number Field in a with defining polynomial x^3 - x + 8 To: Residue field in abar of Fractional ideal (29) - sage: psi == phi # todo: comparison not implemented + sage: psi == phi # not implemented True sage: psi(OK.an_element()) == phi(OK.an_element()) True @@ -1224,18 +1374,22 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: - sage: K.<a> = NumberField(x^3-x+8) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - x + 8) sage: P = K.ideal(29).factor()[0][0] - sage: k =K.residue_field(P) + sage: k = K.residue_field(P) sage: OK = K.maximal_order() - sage: k.coerce_map_from(OK)(OK(a)^7) # indirect doctest + sage: k.coerce_map_from(OK)(OK(a)^7) # indirect doctest 13*abar^2 + 7*abar + 21 + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(next_prime(2^18))[]; P = R.ideal(t - 71) sage: k = ResidueField(P); f = k.coerce_map_from(R); f Ring morphism: From: Univariate Polynomial Ring in t over Finite Field of size 262147 - To: Residue field of Principal ideal (t + 262076) of Univariate Polynomial Ring in t over Finite Field of size 262147 + To: Residue field of Principal ideal (t + 262076) of + Univariate Polynomial Ring in t over Finite Field of size 262147 sage: f(t^2) 5041 """ @@ -1262,13 +1416,16 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^5 - 5*x + 2) sage: P = K.ideal(47).factor()[0][0] sage: k = K.residue_field(P) sage: f = k.coerce_map_from(K.ring_of_integers()) sage: s = f.section(); s Lifting map: - From: Residue field in abar of Fractional ideal (-14*a^4 + 24*a^3 + 26*a^2 - 58*a + 15) + From: Residue field in abar of + Fractional ideal (-14*a^4 + 24*a^3 + 26*a^2 - 58*a + 15) To: Maximal Order in Number Field in a with defining polynomial x^5 - 5*x + 2 sage: s(k.gen()) a @@ -1279,17 +1436,20 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): sage: s = g.section(); s Lifting map: From: Residue field in bbar of Fractional ideal (53, b^2 + 23*b + 8) - To: Maximal Order in Number Field in b with defining polynomial x^5 + 17*x + 1 + To: Maximal Order in Number Field in b + with defining polynomial x^5 + 17*x + 1 sage: s(l.gen()).parent() Maximal Order in Number Field in b with defining polynomial x^5 + 17*x + 1 + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k.<a> = P.residue_field() sage: f = k.coerce_map_from(R) sage: f.section() (map internal to coercion system -- copy before use) Lifting map: - From: Residue field in a of Principal ideal (t^3 + t^2 + 7) of Univariate Polynomial Ring in t over Finite Field of size 17 + From: Residue field in a of Principal ideal (t^3 + t^2 + 7) of + Univariate Polynomial Ring in t over Finite Field of size 17 To: Univariate Polynomial Ring in t over Finite Field of size 17 """ if self._section is None: @@ -1303,7 +1463,9 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): EXAMPLES:: - sage: K.<a> = NumberField(x^3-7) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 7) sage: P = K.ideal(29).factor()[0][0] sage: k = K.residue_field(P) sage: OK = K.maximal_order() @@ -1312,9 +1474,10 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): sage: b = k(a) sage: f.lift(13*b + 5) 13*a + 5 - sage: f.lift(12821*b+918) + sage: f.lift(12821*b + 918) 3*a + 19 + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7) sage: k.<a> = P.residue_field(); f = k.coerce_map_from(R) sage: f.lift(a^2 + 5*a + 1) @@ -1333,6 +1496,8 @@ cdef class LiftingMap(Section): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: F = K.factor(5)[0][0].residue_field() sage: F.degree() @@ -1346,12 +1511,16 @@ cdef class LiftingMap(Section): sage: L(3*a + 1) == F.0^2 True + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(13)[] - sage: P = R.ideal(8*t^12 + 9*t^11 + 11*t^10 + 2*t^9 + 11*t^8 + 3*t^7 + 12*t^6 + t^4 + 7*t^3 + 5*t^2 + 12*t + 1) + sage: P = R.ideal(8*t^12 + 9*t^11 + 11*t^10 + 2*t^9 + 11*t^8 + ....: + 3*t^7 + 12*t^6 + t^4 + 7*t^3 + 5*t^2 + 12*t + 1) sage: k.<a> = P.residue_field() sage: k.lift_map() Lifting map: - From: Residue field in a of Principal ideal (t^12 + 6*t^11 + 3*t^10 + 10*t^9 + 3*t^8 + 2*t^7 + 8*t^6 + 5*t^4 + 9*t^3 + 12*t^2 + 8*t + 5) of Univariate Polynomial Ring in t over Finite Field of size 13 + From: Residue field in a of Principal ideal (t^12 + 6*t^11 + 3*t^10 + + 10*t^9 + 3*t^8 + 2*t^7 + 8*t^6 + 5*t^4 + 9*t^3 + 12*t^2 + 8*t + 5) of + Univariate Polynomial Ring in t over Finite Field of size 13 To: Univariate Polynomial Ring in t over Finite Field of size 13 """ def __init__(self, reduction, to_order, PB): @@ -1360,6 +1529,7 @@ cdef class LiftingMap(Section): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<theta_5> = CyclotomicField(5) sage: F = K.factor(7)[0][0].residue_field() sage: F.lift_map() @@ -1367,15 +1537,19 @@ cdef class LiftingMap(Section): From: Residue field in theta_5bar of Fractional ideal (7) To: Maximal Order in Cyclotomic Field of order 5 and degree 4 + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^5 + 2) sage: F = K.factor(7)[0][0].residue_field() sage: L = F.lift_map(); L Lifting map: From: Residue field in abar of Fractional ideal (2*a^4 - a^3 + 4*a^2 - 2*a + 1) - To: Maximal Order in Number Field in a with defining polynomial x^5 + 2 + To: Maximal Order in Number Field in a + with defining polynomial x^5 + 2 sage: L.domain() Residue field in abar of Fractional ideal (2*a^4 - a^3 + 4*a^2 - 2*a + 1) + sage: # needs sage.rings.number_field sage: K.<a> = CyclotomicField(7) sage: F = K.factor(5)[0][0].residue_field() sage: L = F.lift_map(); L @@ -1385,11 +1559,12 @@ cdef class LiftingMap(Section): sage: L.codomain() Maximal Order in Cyclotomic Field of order 7 and degree 6 + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(2)[]; h = t^5 + t^2 + 1 sage: k.<a> = R.residue_field(h) sage: K = R.fraction_field() sage: L = k.lift_map(); L.codomain() - Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + Univariate Polynomial Ring in t over Finite Field of size 2... """ self._K = reduction._K self._F = reduction._F # finite field @@ -1403,6 +1578,7 @@ cdef class LiftingMap(Section): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<a> = CyclotomicField(7) sage: F = K.factor(5)[0][0].residue_field() sage: phi = F.lift_map() @@ -1410,7 +1586,7 @@ cdef class LiftingMap(Section): Lifting map: From: Residue field in abar of Fractional ideal (5) To: Maximal Order in Cyclotomic Field of order 7 and degree 6 - sage: psi == phi # todo: comparison not implemented + sage: psi == phi # not implemented False sage: phi(F.0) == psi(F.0) True @@ -1428,6 +1604,7 @@ cdef class LiftingMap(Section): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<a> = CyclotomicField(7) sage: F = K.factor(5)[0][0].residue_field() sage: phi = F.lift_map() @@ -1435,7 +1612,7 @@ cdef class LiftingMap(Section): Lifting map: From: Residue field in abar of Fractional ideal (5) To: Maximal Order in Cyclotomic Field of order 7 and degree 6 - sage: psi == phi # todo: comparison not implemented + sage: psi == phi # not implemented False sage: phi(F.0) == psi(F.0) True @@ -1452,17 +1629,19 @@ cdef class LiftingMap(Section): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<a> = CyclotomicField(7) sage: F = K.factor(5)[0][0].residue_field() sage: L = F.lift_map(); L Lifting map: From: Residue field in abar of Fractional ideal (5) To: Maximal Order in Cyclotomic Field of order 7 and degree 6 - sage: L(F.0) # indirect doctest + sage: L(F.0) # indirect doctest a sage: F(a) abar + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(2)[]; h = t^5 + t^2 + 1 sage: k.<a> = R.residue_field(h) sage: K = R.fraction_field() @@ -1494,6 +1673,7 @@ cdef class LiftingMap(Section): """ EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<theta_12> = CyclotomicField(12) sage: F.<tmod> = K.factor(7)[0][0].residue_field() sage: F.lift_map() #indirect doctest @@ -1510,11 +1690,11 @@ class ResidueFiniteField_prime_modn(ResidueField_generic, FiniteField_prime_modn EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^3-7) + sage: K.<a> = NumberField(x^3 - 7) sage: P = K.ideal(29).factor()[1][0] - sage: k = ResidueField(P) - sage: k + sage: k = ResidueField(P); k Residue field of Fractional ideal (-a^2 - 2*a - 2) sage: k.order() 29 @@ -1530,9 +1710,11 @@ class ResidueFiniteField_prime_modn(ResidueField_generic, FiniteField_prime_modn sage: b + c 3 + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(7)[]; P = R.ideal(2*t + 3) sage: k = P.residue_field(); k - Residue field of Principal ideal (t + 5) of Univariate Polynomial Ring in t over Finite Field of size 7 + Residue field of Principal ideal (t + 5) of + Univariate Polynomial Ring in t over Finite Field of size 7 sage: k(t^2) 4 sage: k.order() @@ -1552,11 +1734,13 @@ class ResidueFiniteField_prime_modn(ResidueField_generic, FiniteField_prime_modn EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: kk = ResidueField(K.factor(5)[0][0]) sage: type(kk) <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_prime_modn_with_category'> + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(7)[]; P = R.ideal(2*t + 3) sage: k = P.residue_field(); type(k) <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_prime_modn_with_category'> @@ -1576,11 +1760,15 @@ class ResidueFiniteField_prime_modn(ResidueField_generic, FiniteField_prime_modn else: # polynomial ring case. coerce_list = [ResidueFieldHomomorphism_global(OK, self, None, None, None, None), OK.base_ring()] - self._populate_coercion_lists_(coerce_list=coerce_list, convert_list=[ReductionMap(K, self, None, None, None, None)]) # could be special-cased a bit more. + self._populate_coercion_lists_(coerce_list=coerce_list, + convert_list=[ReductionMap(K, self, None, None, None, None)]) # could be special-cased a bit more. else: PBinv = PB**(-1) - self._populate_coercion_lists_(coerce_list=[IntegerMod_to_IntegerMod(GF(intp), self), Integer_to_IntegerMod(self), Int_to_IntegerMod(self), ResidueFieldHomomorphism_global(OK, self, to_vs, to_order, PB, PBinv)], \ - convert_list=[ReductionMap(K, self, to_vs, to_order, PB, PBinv)]) + self._populate_coercion_lists_(coerce_list=[IntegerMod_to_IntegerMod(GF(intp), self), + Integer_to_IntegerMod(self), + Int_to_IntegerMod(self), + ResidueFieldHomomorphism_global(OK, self, to_vs, to_order, PB, PBinv)], + convert_list=[ReductionMap(K, self, to_vs, to_order, PB, PBinv)]) def _element_constructor_(self, x): """ @@ -1592,8 +1780,9 @@ class ResidueFiniteField_prime_modn(ResidueField_generic, FiniteField_prime_modn EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^3-7) + sage: K.<a> = NumberField(x^3 - 7) sage: P = K.ideal(29).factor()[1][0] sage: k = ResidueField(P) sage: k @@ -1607,315 +1796,18 @@ class ResidueFiniteField_prime_modn(ResidueField_generic, FiniteField_prime_modn sage: V = k.vector_space(map=False); v = V([3]) sage: type(k.convert_map_from(V)) <class 'sage.structure.coerce_maps.DefaultConvertMap_unique'> - sage: k(v) # indirect doctest + sage: k(v) # indirect doctest 3 - sage: R.<t> = GF(2)[]; P = R.ideal(t+1); k.<a> = P.residue_field() + sage: # needs sage.rings.finite_rings + sage: R.<t> = GF(2)[]; P = R.ideal(t + 1); k.<a> = P.residue_field() sage: V = k.vector_space(map=False); v = V([1]) sage: k(v) 1 """ - if isinstance(x, FreeModuleElement) and len(x) == 1: + if isinstance(x, Vector) and len(x) == 1: x = x[0] try: return FiniteField_prime_modn._element_constructor_(self, x) except TypeError: return ResidueField_generic._element_constructor_(self, x) - -class ResidueFiniteField_pari_ffelt(ResidueField_generic, FiniteField_pari_ffelt): - """ - The class representing residue fields of number fields that have non-prime - order at least `2^16`. - - EXAMPLES:: - - sage: K.<a> = NumberField(x^3-7) - sage: P = K.ideal(923478923).factor()[0][0] - sage: k = K.residue_field(P) - sage: k.degree() - 2 - sage: OK = K.maximal_order() - sage: c = OK(a) - sage: b = k(c) - sage: b+c - 2*abar - sage: b*c - 664346875*abar + 535606347 - sage: k.base_ring() - Finite Field of size 923478923 - - sage: R.<t> = GF(5)[]; P = R.ideal(4*t^12 + 3*t^11 + 4*t^10 + t^9 + t^8 + 3*t^7 + 2*t^6 + 3*t^4 + t^3 + 3*t^2 + 2) - sage: k.<a> = P.residue_field() - sage: type(k) - <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_pari_ffelt_with_category'> - sage: k(1/t) - 3*a^11 + a^10 + 3*a^9 + 2*a^8 + 2*a^7 + a^6 + 4*a^5 + a^3 + 2*a^2 + a - """ - - def __init__(self, p, characteristic, name, modulus, to_vs, to_order, PB): - """ - Initialize ``self``. - - EXAMPLES: - - We create a residue field with implementation ``pari_ffelt``:: - - sage: K.<a> = NumberField(x^3-7) - sage: P = K.ideal(923478923).factor()[0][0] - sage: type(P.residue_field()) - <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_pari_ffelt_with_category'> - """ - ResidueField_generic.__init__(self, p) - FiniteField_pari_ffelt.__init__(self, characteristic, modulus, name) - K = OK = p.ring() - if OK.is_field(): - OK = OK.ring_of_integers() - else: - K = K.fraction_field() - if PB is None: - PBinv = None - else: - PBinv = PB**(-1) - self._populate_coercion_lists_(coerce_list=[self.base_ring(), ResidueFieldHomomorphism_global(OK, self, to_vs, to_order, PB, PBinv)], convert_list = [ReductionMap(K, self, to_vs, to_order, PB, PBinv)]) - - def _element_constructor_(self, x): - """ - Coerce ``x`` into ``self``. - - EXAMPLES:: - - sage: K.<aa> = NumberField(x^3 - 2) - sage: P = K.factor(10007)[0][0] - sage: P.residue_class_degree() - 2 - sage: ff.<alpha> = P.residue_field(); ff - Residue field in alpha of Fractional ideal (-12*aa^2 + 189*aa - 475) - sage: type(ff) - <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_pari_ffelt_with_category'> - sage: ff(alpha^2 + 1) - 7521*alpha + 4131 - sage: ff(17/3) - 6677 - sage: V = ff.vector_space(map=False); v = V([3,-2]) - sage: type(ff.convert_map_from(V)) - <class 'sage.structure.coerce_maps.DefaultConvertMap_unique'> - sage: ff(v) # indirect doctest - 10005*alpha + 3 - - sage: R.<t> = GF(5)[]; P = R.ideal(4*t^12 + 3*t^11 + 4*t^10 + t^9 + t^8 + 3*t^7 + 2*t^6 + 3*t^4 + t^3 + 3*t^2 + 2) - sage: k.<a> = P.residue_field() - sage: V = k.vector_space(map=False); v = V([1,2,3,4,5,6,7,8,9,0,1,2]); k(v) # indirect doctest - 2*a^11 + a^10 + 4*a^8 + 3*a^7 + 2*a^6 + a^5 + 4*a^3 + 3*a^2 + 2*a + 1 - """ - try: - return self.element_class(self, x) - except TypeError: - return ResidueField_generic._element_constructor_(self, x) - - -class ResidueFiniteField_givaro(ResidueField_generic, FiniteField_givaro): - """ - The class representing residue fields of number fields that have non-prime - order strictly less than `2^16`. - - EXAMPLES:: - - sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^3-7) - sage: P = K.ideal(29).factor()[0][0] - sage: k =K.residue_field(P) - sage: k.degree() - 2 - sage: OK = K.maximal_order() - sage: c = OK(a) - sage: b = k(c) - sage: b*c^2 - 7 - sage: b*c - 13*abar + 5 - - sage: R.<t> = GF(7)[]; P = R.ideal(t^2 + 4) - sage: k.<a> = R.residue_field(P); type(k) - <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_givaro_with_category'> - sage: k(1/t) - 5*a - """ - def __init__(self, p, q, name, modulus, to_vs, to_order, PB): - r""" - INPUT: - - - ``p`` -- the prime ideal defining this residue field - - - ``q`` -- the order of this residue field (a power of intp) - - - ``name`` -- the name of the generator of this extension - - - ``modulus`` -- the polynomial modulus for this extension - - - ``to_vs`` -- the map from the number field (or function field) to - the appropriate vector space (over `\QQ` or `F_p(t)`) - - - ``to_order`` -- the map from a lattice in that vector space to the maximal order - - - ``PB`` -- a matrix used in defining the reduction and lifting maps. - - EXAMPLES:: - - sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) - sage: P = K.ideal(61).factor()[0][0] - sage: k = K.residue_field(P) - - sage: R.<t> = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k.<a> = P.residue_field(); type(k) - <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_givaro_with_category'> - sage: a^5 - a^3 + 2*a^2 + a + 2 - """ - ResidueField_generic.__init__(self, p) - FiniteField_givaro.__init__(self, q, name, modulus) - K = OK = p.ring() - if OK.is_field(): - OK = OK.ring_of_integers() - else: - K = K.fraction_field() - if PB is None: - PBinv = None - else: - PBinv = PB**(-1) - self._populate_coercion_lists_(coerce_list=[self.base_ring(), ResidueFieldHomomorphism_global(OK, self, to_vs, to_order, PB, PBinv)], convert_list = [ReductionMap(K, self, to_vs, to_order, PB, PBinv)]) - - def _element_constructor_(self, x): - """ - INPUT: - - - ``x`` -- Something to cast into ``self``. - - EXAMPLES:: - - sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) - sage: P = K.ideal(61).factor()[0][0] - sage: k =K.residue_field(P) - sage: k(77*a^7+4) - 2*abar + 4 - sage: V = k.vector_space(map=False); v = V([3,-2]) - sage: type(k.convert_map_from(V)) - <class 'sage.structure.coerce_maps.DefaultConvertMap_unique'> - sage: k(v) # indirect doctest - 59*abar + 3 - - sage: R.<t> = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k.<a> = P.residue_field() - sage: V = k.vector_space(map=False); v = V([0,1,2,3]) - sage: k(v) # indirect doctest - 2*a^2 + a - """ - try: - return FiniteField_givaro._element_constructor_(self, x) - except TypeError: - return ResidueField_generic._element_constructor_(self, x) - -class ResidueFiniteField_ntl_gf2e(ResidueField_generic, FiniteField_ntl_gf2e): - """ - The class representing residue fields with order a power of 2. - - When the order is less than `2^16`, givaro is used by default instead. - - EXAMPLES:: - - sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^3-7) - sage: P = K.ideal(29).factor()[0][0] - sage: k =K.residue_field(P) - sage: k.degree() - 2 - sage: OK = K.maximal_order() - sage: c = OK(a) - sage: b = k(c) - sage: b*c^2 - 7 - sage: b*c - 13*abar + 5 - - sage: R.<t> = GF(2)[]; P = R.ideal(t^19 + t^5 + t^2 + t + 1) - sage: k.<a> = R.residue_field(P); type(k) - <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_ntl_gf2e_with_category'> - sage: k(1/t) - a^18 + a^4 + a + 1 - sage: k(1/t)*t - 1 - """ - # we change the order for consistency with FiniteField_ntl_gf2e's __cinit__ - def __init__(self, q, name, modulus, repr, p, to_vs, to_order, PB): - r""" - INPUT: - - - ``p`` -- the prime ideal defining this residue field - - - ``q`` -- the order of this residue field - - - ``name`` -- the name of the generator of this extension - - - ``modulus`` -- the polynomial modulus for this extension - - - ``to_vs`` -- the map from the number field (or function field) to - the appropriate vector space (over `\QQ` or `F_p(t)`) - - - ``to_order`` -- the map from a lattice in that vector space to the - maximal order - - - ``PB`` -- a matrix used in defining the reduction and lifting maps - - EXAMPLES:: - - sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) - sage: P = K.ideal(61).factor()[0][0] - sage: k = K.residue_field(P) - - sage: R.<t> = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k.<a> = P.residue_field(); type(k) - <class 'sage.rings.finite_rings.residue_field.ResidueFiniteField_givaro_with_category'> - sage: a^5 - a^3 + 2*a^2 + a + 2 - """ - ResidueField_generic.__init__(self, p) - FiniteField_ntl_gf2e.__init__(self, q, name, modulus, repr) - K = OK = p.ring() - if OK.is_field(): - OK = OK.ring_of_integers() - else: - K = K.fraction_field() - if PB is None: - PBinv = None - else: - PBinv = PB**(-1) - self._populate_coercion_lists_(coerce_list=[self.base_ring(), ResidueFieldHomomorphism_global(OK, self, to_vs, to_order, PB, PBinv)], convert_list = [ReductionMap(K, self, to_vs, to_order, PB, PBinv)]) - - def _element_constructor_(self, x): - """ - INPUT: - - - ``x`` -- Something to cast into ``self``. - - EXAMPLES:: - - sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) - sage: P = K.ideal(61).factor()[0][0] - sage: k =K.residue_field(P) - sage: k(77*a^7+4) - 2*abar + 4 - sage: V = k.vector_space(map=False); v = V([3,-2]) - sage: type(k.convert_map_from(V)) - <class 'sage.structure.coerce_maps.DefaultConvertMap_unique'> - sage: k(v) # indirect doctest - 59*abar + 3 - - sage: R.<t> = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k.<a> = P.residue_field() - sage: V = k.vector_space(map=False); v = V([0,1,2,3]) - sage: k(v) # indirect doctest - 2*a^2 + a - """ - try: - return FiniteField_ntl_gf2e._element_constructor_(self, x) - except TypeError: - return ResidueField_generic._element_constructor_(self, x) diff --git a/src/sage/rings/finite_rings/residue_field_givaro.pyx b/src/sage/rings/finite_rings/residue_field_givaro.pyx new file mode 100644 index 00000000000..07fd740c044 --- /dev/null +++ b/src/sage/rings/finite_rings/residue_field_givaro.pyx @@ -0,0 +1,132 @@ +r""" +Finite residue fields (Givaro implementation) +""" + +# ***************************************************************************** +# Copyright (C) 2007-2019 David Roe <roed@math.harvard.edu> +# 2007 William Stein <wstein@gmail.com> +# 2008 John Cremona +# 2008 Robert Bradshaw +# 2009 Nick Alexander +# 2010 Robert L. Miller +# 2010-2013 Simon King +# 2010-2017 Jeroen Demeyer +# 2012 Travis Scrimshaw +# 2016-2021 Frรฉdรฉric Chapoton +# 2021-2022 Antonio Rojas +# +# 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. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.rings.finite_rings.finite_field_givaro import FiniteField_givaro +from sage.rings.finite_rings.residue_field import ResidueField_generic, ResidueFieldHomomorphism_global, ReductionMap + + +class ResidueFiniteField_givaro(ResidueField_generic, FiniteField_givaro): + """ + The class representing residue fields of number fields that have non-prime + order strictly less than `2^16`. + + EXAMPLES:: + + sage: # needs sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(x^3 - 7) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) + sage: k.degree() + 2 + sage: OK = K.maximal_order() + sage: c = OK(a) + sage: b = k(c) + sage: b*c^2 + 7 + sage: b*c + 13*abar + 5 + + sage: R.<t> = GF(7)[]; P = R.ideal(t^2 + 4) + sage: k.<a> = R.residue_field(P); type(k) + <class 'sage.rings.finite_rings.residue_field_givaro.ResidueFiniteField_givaro_with_category'> + sage: k(1/t) + 5*a + """ + def __init__(self, p, q, name, modulus, to_vs, to_order, PB): + r""" + INPUT: + + - ``p`` -- the prime ideal defining this residue field + + - ``q`` -- the order of this residue field (a power of intp) + + - ``name`` -- the name of the generator of this extension + + - ``modulus`` -- the polynomial modulus for this extension + + - ``to_vs`` -- the map from the number field (or function field) to + the appropriate vector space (over `\QQ` or `F_p(t)`) + + - ``to_order`` -- the map from a lattice in that vector space to the maximal order + + - ``PB`` -- a matrix used in defining the reduction and lifting maps. + + EXAMPLES:: + + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) # needs sage.rings.number_field + sage: P = K.ideal(61).factor()[0][0] # needs sage.rings.number_field + sage: k = K.residue_field(P) # needs sage.rings.number_field + + sage: R.<t> = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k.<a> = P.residue_field(); type(k) + <class 'sage.rings.finite_rings.residue_field_givaro.ResidueFiniteField_givaro_with_category'> + sage: a^5 + a^3 + 2*a^2 + a + 2 + """ + ResidueField_generic.__init__(self, p) + FiniteField_givaro.__init__(self, q, name, modulus) + K = OK = p.ring() + if OK.is_field(): + OK = OK.ring_of_integers() + else: + K = K.fraction_field() + if PB is None: + PBinv = None + else: + PBinv = PB**(-1) + self._populate_coercion_lists_(coerce_list=[self.base_ring(), + ResidueFieldHomomorphism_global(OK, self, to_vs, to_order, PB, PBinv)], + convert_list=[ReductionMap(K, self, to_vs, to_order, PB, PBinv)]) + + def _element_constructor_(self, x): + """ + INPUT: + + - ``x`` -- Something to cast into ``self``. + + EXAMPLES:: + + sage: # needs sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) + sage: P = K.ideal(61).factor()[0][0] + sage: k = K.residue_field(P) + sage: k(77*a^7 + 4) + 2*abar + 4 + sage: V = k.vector_space(map=False); v = V([3,-2]) + sage: type(k.convert_map_from(V)) + <class 'sage.structure.coerce_maps.DefaultConvertMap_unique'> + sage: k(v) # indirect doctest + 59*abar + 3 + + sage: R.<t> = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k.<a> = P.residue_field() + sage: V = k.vector_space(map=False); v = V([0,1,2,3]) + sage: k(v) # indirect doctest + 2*a^2 + a + """ + try: + return FiniteField_givaro._element_constructor_(self, x) + except TypeError: + return ResidueField_generic._element_constructor_(self, x) diff --git a/src/sage/rings/finite_rings/residue_field_ntl_gf2e.pyx b/src/sage/rings/finite_rings/residue_field_ntl_gf2e.pyx new file mode 100644 index 00000000000..ed6af655258 --- /dev/null +++ b/src/sage/rings/finite_rings/residue_field_ntl_gf2e.pyx @@ -0,0 +1,137 @@ +r""" +Finite residue fields (NTL implementation) +""" + +# ***************************************************************************** +# Copyright (C) 2007-2019 David Roe <roed@math.harvard.edu> +# 2007 William Stein <wstein@gmail.com> +# 2008 John Cremona +# 2008 Robert Bradshaw +# 2009 Nick Alexander +# 2010 Robert L. Miller +# 2010-2013 Simon King +# 2010-2017 Jeroen Demeyer +# 2012 Travis Scrimshaw +# 2016-2021 Frรฉdรฉric Chapoton +# 2021-2022 Antonio Rojas +# +# 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. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.rings.finite_rings.finite_field_ntl_gf2e import FiniteField_ntl_gf2e +from sage.rings.finite_rings.residue_field import ResidueField_generic, ResidueFieldHomomorphism_global, ReductionMap + + +class ResidueFiniteField_ntl_gf2e(ResidueField_generic, FiniteField_ntl_gf2e): + """ + The class representing residue fields with order a power of 2. + + When the order is less than `2^16`, givaro is used by default instead. + + EXAMPLES:: + + sage: # needs sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(x^3 - 7) + sage: P = K.ideal(29).factor()[0][0] + sage: k = K.residue_field(P) + sage: k.degree() + 2 + sage: OK = K.maximal_order() + sage: c = OK(a) + sage: b = k(c) + sage: b*c^2 + 7 + sage: b*c + 13*abar + 5 + + sage: R.<t> = GF(2)[]; P = R.ideal(t^19 + t^5 + t^2 + t + 1) + sage: k.<a> = R.residue_field(P); type(k) + <class 'sage.rings.finite_rings.residue_field_ntl_gf2e.ResidueFiniteField_ntl_gf2e_with_category'> + sage: k(1/t) + a^18 + a^4 + a + 1 + sage: k(1/t)*t + 1 + """ + # we change the order for consistency with FiniteField_ntl_gf2e's __cinit__ + def __init__(self, q, name, modulus, repr, p, to_vs, to_order, PB): + r""" + INPUT: + + - ``p`` -- the prime ideal defining this residue field + + - ``q`` -- the order of this residue field + + - ``name`` -- the name of the generator of this extension + + - ``modulus`` -- the polynomial modulus for this extension + + - ``to_vs`` -- the map from the number field (or function field) to + the appropriate vector space (over `\QQ` or `F_p(t)`) + + - ``to_order`` -- the map from a lattice in that vector space to the + maximal order + + - ``PB`` -- a matrix used in defining the reduction and lifting maps + + EXAMPLES:: + + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) # needs sage.rings.number_field + sage: P = K.ideal(61).factor()[0][0] # needs sage.rings.number_field + sage: k = K.residue_field(P) # needs sage.rings.number_field + + sage: R.<t> = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k.<a> = P.residue_field(); type(k) + <class 'sage.rings.finite_rings.residue_field_givaro.ResidueFiniteField_givaro_with_category'> + sage: a^5 + a^3 + 2*a^2 + a + 2 + """ + ResidueField_generic.__init__(self, p) + FiniteField_ntl_gf2e.__init__(self, q, name, modulus, repr) + K = OK = p.ring() + if OK.is_field(): + OK = OK.ring_of_integers() + else: + K = K.fraction_field() + if PB is None: + PBinv = None + else: + PBinv = PB**(-1) + self._populate_coercion_lists_(coerce_list=[self.base_ring(), + ResidueFieldHomomorphism_global(OK, self, to_vs, to_order, PB, PBinv)], + convert_list=[ReductionMap(K, self, to_vs, to_order, PB, PBinv)]) + + def _element_constructor_(self, x): + """ + INPUT: + + - ``x`` -- Something to cast into ``self``. + + EXAMPLES:: + + sage: # needs sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) + sage: P = K.ideal(61).factor()[0][0] + sage: k = K.residue_field(P) + sage: k(77*a^7 + 4) + 2*abar + 4 + sage: V = k.vector_space(map=False); v = V([3,-2]) + sage: type(k.convert_map_from(V)) + <class 'sage.structure.coerce_maps.DefaultConvertMap_unique'> + sage: k(v) # indirect doctest + 59*abar + 3 + + sage: R.<t> = GF(3)[]; P = R.ideal(t^4 - t^3 + t + 1); k.<a> = P.residue_field() + sage: V = k.vector_space(map=False); v = V([0,1,2,3]) + sage: k(v) # indirect doctest + 2*a^2 + a + """ + try: + return FiniteField_ntl_gf2e._element_constructor_(self, x) + except TypeError: + return ResidueField_generic._element_constructor_(self, x) diff --git a/src/sage/rings/finite_rings/residue_field_pari_ffelt.pyx b/src/sage/rings/finite_rings/residue_field_pari_ffelt.pyx new file mode 100644 index 00000000000..375b3b4cdfc --- /dev/null +++ b/src/sage/rings/finite_rings/residue_field_pari_ffelt.pyx @@ -0,0 +1,127 @@ +r""" +Finite residue fields (PARI implementation) +""" + +# ***************************************************************************** +# Copyright (C) 2007-2019 David Roe <roed@math.harvard.edu> +# 2007 William Stein <wstein@gmail.com> +# 2008 John Cremona +# 2008 Robert Bradshaw +# 2009 Nick Alexander +# 2010 Robert L. Miller +# 2010-2013 Simon King +# 2010-2017 Jeroen Demeyer +# 2012 Travis Scrimshaw +# 2016-2021 Frรฉdรฉric Chapoton +# 2021-2022 Antonio Rojas +# +# 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. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.rings.finite_rings.finite_field_pari_ffelt import FiniteField_pari_ffelt +from sage.rings.finite_rings.residue_field import ResidueField_generic, ResidueFieldHomomorphism_global, ReductionMap + + +class ResidueFiniteField_pari_ffelt(ResidueField_generic, FiniteField_pari_ffelt): + """ + The class representing residue fields of number fields that have non-prime + order at least `2^16`. + + EXAMPLES:: + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 7) + sage: P = K.ideal(923478923).factor()[0][0] + sage: k = K.residue_field(P) + sage: k.degree() + 2 + sage: OK = K.maximal_order() + sage: c = OK(a) + sage: b = k(c) + sage: b + c + 2*abar + sage: b*c + 664346875*abar + 535606347 + sage: k.base_ring() + Finite Field of size 923478923 + + sage: R.<t> = GF(5)[] + sage: P = R.ideal(4*t^12 + 3*t^11 + 4*t^10 + t^9 + t^8 + ....: + 3*t^7 + 2*t^6 + 3*t^4 + t^3 + 3*t^2 + 2) + sage: k.<a> = P.residue_field() + sage: type(k) + <class 'sage.rings.finite_rings.residue_field_pari_ffelt.ResidueFiniteField_pari_ffelt_with_category'> + sage: k(1/t) + 3*a^11 + a^10 + 3*a^9 + 2*a^8 + 2*a^7 + a^6 + 4*a^5 + a^3 + 2*a^2 + a + """ + + def __init__(self, p, characteristic, name, modulus, to_vs, to_order, PB): + """ + Initialize ``self``. + + EXAMPLES: + + We create a residue field with implementation ``pari_ffelt``:: + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 7) + sage: P = K.ideal(923478923).factor()[0][0] + sage: type(P.residue_field()) + <class 'sage.rings.finite_rings.residue_field_pari_ffelt.ResidueFiniteField_pari_ffelt_with_category'> + """ + ResidueField_generic.__init__(self, p) + FiniteField_pari_ffelt.__init__(self, characteristic, modulus, name) + K = OK = p.ring() + if OK.is_field(): + OK = OK.ring_of_integers() + else: + K = K.fraction_field() + if PB is None: + PBinv = None + else: + PBinv = PB**(-1) + self._populate_coercion_lists_(coerce_list=[self.base_ring(), + ResidueFieldHomomorphism_global(OK, self, to_vs, to_order, PB, PBinv)], + convert_list=[ReductionMap(K, self, to_vs, to_order, PB, PBinv)]) + + def _element_constructor_(self, x): + """ + Coerce ``x`` into ``self``. + + EXAMPLES:: + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<aa> = NumberField(x^3 - 2) + sage: P = K.factor(10007)[0][0] + sage: P.residue_class_degree() + 2 + sage: ff.<alpha> = P.residue_field(); ff + Residue field in alpha of Fractional ideal (-12*aa^2 + 189*aa - 475) + sage: type(ff) + <class 'sage.rings.finite_rings.residue_field_pari_ffelt.ResidueFiniteField_pari_ffelt_with_category'> + sage: ff(alpha^2 + 1) + 7521*alpha + 4131 + sage: ff(17/3) + 6677 + sage: V = ff.vector_space(map=False); v = V([3,-2]) + sage: type(ff.convert_map_from(V)) + <class 'sage.structure.coerce_maps.DefaultConvertMap_unique'> + sage: ff(v) # indirect doctest + 10005*alpha + 3 + + sage: R.<t> = GF(5)[]; P = R.ideal(4*t^12 + 3*t^11 + 4*t^10 + t^9 + t^8 + 3*t^7 + 2*t^6 + 3*t^4 + t^3 + 3*t^2 + 2) + sage: k.<a> = P.residue_field() + sage: V = k.vector_space(map=False); v = V([1,2,3,4,5,6,7,8,9,0,1,2]); k(v) # indirect doctest + 2*a^11 + a^10 + 4*a^8 + 3*a^7 + 2*a^6 + a^5 + 4*a^3 + 3*a^2 + 2*a + 1 + """ + try: + return self.element_class(self, x) + except TypeError: + return ResidueField_generic._element_constructor_(self, x) diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index 3f1964b13d2..5d298720a90 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -25,6 +25,7 @@ The GCD is not taken (since it doesn't converge sometimes) in the inexact case:: + sage: # needs sage.rings.real_mpfr sage: Z.<z> = CC[] sage: I = CC.gen() sage: (1+I+z)/(z+0.1*I) @@ -55,6 +56,18 @@ sage: F = FractionField(PolynomialRing(RationalField(),2,'x')) sage: F == loads(dumps(F)) True + +Test that :trac:`15971` is fixed:: + + sage: for B in [QQ['t'], QQ['s, t'], ZZ['t'], ZZ['s, t']]: + ....: F = B.fraction_field() + ....: R = F['x, y'] + ....: x = R.gen(0) + ....: print(x / x) + 1 + 1 + 1 + 1 """ # **************************************************************************** # @@ -251,8 +264,9 @@ def _coerce_map_from_(self, S): We demonstrate that :trac:`7958` is resolved in the case of number fields:: + sage: # needs sage.rings.number_field sage: _.<x> = ZZ[] - sage: K.<a> = NumberField(x^5-3*x^4+2424*x^3+2*x-232) + sage: K.<a> = NumberField(x^5 - 3*x^4 + 2424*x^3 + 2*x - 232) sage: R = K.ring_of_integers() sage: S.<y> = R[] sage: F = FractionField(S) @@ -284,6 +298,7 @@ def _coerce_map_from_(self, S): sage: 1/(R.gen() + 1) 1/(x + 1) + sage: # needs sage.modules sage: R = LaurentPolynomialRing(ZZ, 'x,y') sage: FF = FractionField(PolynomialRing(ZZ, 'x,y')) sage: prod(R.gens()) + prod(FF.gens()) @@ -294,13 +309,14 @@ def _coerce_map_from_(self, S): Test for :trac:`31320`:: sage: FQt = Frac(QQ['t']) - sage: LCt = LaurentPolynomialRing(CC,'t') - sage: coercion_model.common_parent(FQt, LCt) + sage: LCt = LaurentPolynomialRing(CC,'t') # needs sage.rings.real_mpfr + sage: coercion_model.common_parent(FQt, LCt) # needs sage.rings.real_mpfr Fraction Field of Univariate Polynomial Ring in t over Complex Field with 53 bits of precision Coercion from a localization:: + sage: # needs sage.libs.pari sage: R.<x> = ZZ[] sage: L = Localization(R, (x**2 + 1,7)) sage: F = L.fraction_field() @@ -313,7 +329,7 @@ def _coerce_map_from_(self, S): """ from sage.rings.rational_field import QQ from sage.rings.number_field.number_field_base import NumberField - from sage.rings.polynomial.laurent_polynomial_ring import \ + from sage.rings.polynomial.laurent_polynomial_ring_base import \ LaurentPolynomialRing_generic if S is self._R: @@ -381,11 +397,12 @@ def _number_field_to_frac_of_ring_of_integers(self, x): We demonstrate that :trac:`7958` is resolved in the case of number fields:: + sage: # needs sage.rings.number_field sage: _.<x> = ZZ[] - sage: K.<a> = NumberField(x^5-3*x^4+2424*x^3+2*x-232) + sage: K.<a> = NumberField(x^5 - 3*x^4 + 2424*x^3 + 2*x - 232) sage: R = K.ring_of_integers() sage: S.<y> = R[] - sage: F = FractionField(S) # indirect doctest + sage: F = FractionField(S) # indirect doctest sage: F(1/a) (a^4 - 3*a^3 + 2424*a^2 + 2)/232 """ @@ -482,7 +499,7 @@ def _magma_init_(self, magma): sage: QQ['x'].fraction_field()._magma_init_(magma) # optional - magma 'SageCreateWithNames(FieldOfFractions(SageCreateWithNames(PolynomialRing(_sage_ref...),["x"])),["x"])' - sage: GF(9,'a')['x,y,z'].fraction_field()._magma_init_(magma) # optional - magma + sage: GF(9,'a')['x,y,z'].fraction_field()._magma_init_(magma) # optional - magma, needs sage.rings.finite_rings 'SageCreateWithNames(FieldOfFractions(SageCreateWithNames(PolynomialRing(_sage_ref...,3,"grevlex"),["x","y","z"])),["x","y","z"])' ``_magma_init_`` gets called implicitly below:: @@ -526,7 +543,7 @@ def is_exact(self): sage: Frac(ZZ['x']).is_exact() True - sage: Frac(CDF['x']).is_exact() + sage: Frac(CDF['x']).is_exact() # needs sage.rings.complex_double False """ return self.ring().is_exact() @@ -559,17 +576,17 @@ def _element_constructor_(self, x, y=None, coerce=True): The next example failed before :trac:`4376`:: - sage: K(pari((x + 1)/(x^2 + x + 1))) + sage: K(pari((x + 1)/(x^2 + x + 1))) # needs sage.libs.pari (x + 1)/(x^2 + x + 1) These examples failed before :trac:`11368`:: sage: R.<x, y, z> = PolynomialRing(QQ) sage: S = R.fraction_field() - sage: S(pari((x + y)/y)) + sage: S(pari((x + y)/y)) # needs sage.libs.pari (x + y)/y - sage: S(pari(x + y + 1/z)) + sage: S(pari(x + y + 1/z)) # needs sage.libs.pari (x*z + y*z + 1)/z This example failed before :trac:`23664`:: @@ -595,19 +612,19 @@ def _element_constructor_(self, x, y=None, coerce=True): sage: A.<a,c> = Frac(PolynomialRing(QQ,'a,c')) sage: B.<d,e> = PolynomialRing(A,'d,e') sage: R.<x> = PolynomialRing(B,'x') - sage: (a*d*x^2+a+e+1).resultant(-4*c^2*x+1) + sage: (a*d*x^2+a+e+1).resultant(-4*c^2*x+1) # needs sage.libs.pari a*d + (16*c^4)*e + (16*a*c^4 + 16*c^4) Check that :trac:`24539` is fixed:: sage: tau = polygen(QQ, 'tau') - sage: PolynomialRing(CyclotomicField(2), 'z').fraction_field()(tau/(1+tau)) + sage: PolynomialRing(CyclotomicField(2), 'z').fraction_field()(tau/(1+tau)) # needs sage.rings.number_field z/(z + 1) Check that :trac:`26150` is fixed:: - sage: z = SR.var('z') - sage: CyclotomicField(2)['z'].fraction_field()(2*(4*z + 5)/((z + 1)*(z - 1)^4)) + sage: z = SR.var('z') # needs sage.symbolic + sage: CyclotomicField(2)['z'].fraction_field()(2*(4*z + 5)/((z + 1)*(z - 1)^4)) # needs sage.rings.number_field sage.symbolic (8*z + 10)/(z^5 - 3*z^4 + 2*z^3 + 2*z^2 - 3*z + 1) :: @@ -722,7 +739,8 @@ def construction(self): sage: K = Frac(GF(3)['t']) sage: f, R = K.construction() sage: f(R) - Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 3 + Fraction Field of Univariate Polynomial Ring in t + over Finite Field of size 3 sage: f(R) == K True """ @@ -789,7 +807,8 @@ def ngens(self): EXAMPLES:: sage: R = Frac(PolynomialRing(QQ,'z',10)); R - Fraction Field of Multivariate Polynomial Ring in z0, z1, z2, z3, z4, z5, z6, z7, z8, z9 over Rational Field + Fraction Field of Multivariate Polynomial Ring + in z0, z1, z2, z3, z4, z5, z6, z7, z8, z9 over Rational Field sage: R.ngens() 10 """ @@ -802,7 +821,8 @@ def gen(self, i=0): EXAMPLES:: sage: R = Frac(PolynomialRing(QQ,'z',10)); R - Fraction Field of Multivariate Polynomial Ring in z0, z1, z2, z3, z4, z5, z6, z7, z8, z9 over Rational Field + Fraction Field of Multivariate Polynomial Ring + in z0, z1, z2, z3, z4, z5, z6, z7, z8, z9 over Rational Field sage: R.0 z0 sage: R.gen(3) @@ -1007,6 +1027,7 @@ def _factor_univariate_polynomial(self, f): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(9) sage: K = k['t'].fraction_field() sage: R.<x> = K[] @@ -1045,18 +1066,20 @@ def _coerce_map_from_(self, R): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(5)[] sage: K = R.fraction_field() sage: L = K.function_field() sage: f = K.coerce_map_from(L); f # indirect doctest Isomorphism: From: Rational function field in t over Finite Field of size 5 - To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 + To: Fraction Field of Univariate Polynomial Ring in t + over Finite Field of size 5 sage: f(~L.gen()) 1/t """ - from sage.rings.function_field.function_field import RationalFunctionField + from sage.rings.function_field.function_field_rational import RationalFunctionField if isinstance(R, RationalFunctionField) and self.variable_name() == R.variable_name() and self.base_ring() is R.constant_base_field(): from sage.categories.homset import Hom parent = Hom(R, self) @@ -1159,7 +1182,7 @@ def _richcmp_(self, other, op): True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self.domain(), self.codomain()), (other.domain(), other.codomain()), op) @@ -1220,19 +1243,20 @@ def _call_(self, x, check=True): Over inexact rings, we have to take the precision of the denominators into account:: - sage: R=ZpCR(2) + sage: # needs sage.rings.padics + sage: R = ZpCR(2) sage: S.<x> = R[] - sage: f = x/S(R(3,absprec=2)) + sage: f = x/S(R(3, absprec=2)) sage: S(f) (1 + 2 + O(2^2))*x Test for Localization:: sage: R.<x> = ZZ[] - sage: L = Localization(R, x**2+2*x+ 1) - sage: 1/(x+1) in L # indirect doctest + sage: L = Localization(R, x**2 + 2*x + 1) # needs sage.libs.pari + sage: 1/(x + 1) in L # indirect doctest # needs sage.libs.pari True - sage: 1/(x+2) in L # indirect doctest + sage: 1/(x + 2) in L # indirect doctest # needs sage.libs.pari False """ codom = self.codomain() @@ -1291,7 +1315,7 @@ def _richcmp_(self, other, op): True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self.domain(), self.codomain()), (other.domain(), other.codomain()), op) diff --git a/src/sage/rings/fraction_field_FpT.pyx b/src/sage/rings/fraction_field_FpT.pyx index 8351963a195..c9bb5d5a384 100644 --- a/src/sage/rings/fraction_field_FpT.pyx +++ b/src/sage/rings/fraction_field_FpT.pyx @@ -6,23 +6,19 @@ # distutils: language = c++ "Univariate rational functions over prime fields" -import sys - from cysignals.signals cimport sig_on, sig_off from sage.rings.finite_rings.stdint cimport INTEGER_MOD_INT32_LIMIT from sage.libs.gmp.mpz cimport * -from sage.rings.finite_rings.finite_field_constructor import GF from sage.libs.flint.nmod_poly cimport * from sage.libs.flint.ulong_extras cimport n_jacobi -from sage.structure.element cimport Element, ModuleElement, FieldElement +from sage.structure.element cimport Element, FieldElement from sage.rings.integer_ring import ZZ -from sage.rings.fraction_field import FractionField_generic, FractionField_1poly_field +from sage.rings.fraction_field import FractionField_1poly_field from sage.rings.finite_rings.integer_mod cimport IntegerMod_int from sage.rings.integer cimport Integer from sage.rings.polynomial.polynomial_zmod_flint cimport Polynomial_zmod_flint, get_cparent -import sage.algebras.algebra from sage.structure.richcmp cimport rich_to_bool from sage.rings.finite_rings.integer_mod cimport mod_inverse_int @@ -30,7 +26,7 @@ from sage.rings.finite_rings.integer_mod cimport mod_inverse_int class FpT(FractionField_1poly_field): r""" - This class represents the fraction field GF(p)(T) for `2 < p < \sqrt{2^31-1}`. + This class represents the fraction field `\GF{p}(T)` for `2 < p < \sqrt{2^31-1}`. EXAMPLES:: @@ -93,7 +89,7 @@ class FpT(FractionField_1poly_field): cdef class FpTElement(FieldElement): """ - An element of an FpT fraction field. + An element of an :class:`FpT` fraction field. TESTS:: @@ -563,7 +559,7 @@ cdef class FpTElement(FieldElement): cpdef FpTElement next(self): """ - This function iterates through all polynomials, returning the "next" polynomial after this one. + Iterate through all polynomials, returning the "next" polynomial after this one. The strategy is as follows: @@ -572,7 +568,7 @@ cdef class FpTElement(FieldElement): - We progress through the elements with both numerator and denominator monic, and with the denominator less than the numerator. For each such, we output all the scalar multiples of it, then all of the scalar multiples of its inverse. - - So if the leading coefficient of the numerator is less than p-1, we scale the numerator to increase it by 1. + - So if the leading coefficient of the numerator is less than `p-1`, we scale the numerator to increase it by 1. - Otherwise, we consider the multiple with numerator and denominator monic. @@ -741,7 +737,7 @@ cdef class FpTElement(FieldElement): cpdef bint is_square(self): """ - Return True if this element is the square of another element of the fraction field. + Return ``True`` if this element is the square of another element of the fraction field. EXAMPLES:: @@ -1654,7 +1650,7 @@ cdef class FpT_Fp_section(Section): raise ValueError("not constant") ans = IntegerMod_int.__new__(IntegerMod_int) ans._parent = self.codomain() - ans.__modulus = ans._parent._pyx_order + ans._modulus = ans._parent._pyx_order if nmod_poly_get_coeff_ui(x._denom, 0) != 1: normalize(x._numer, x._denom, self.p) ans.ivalue = nmod_poly_get_coeff_ui(x._numer, 0) @@ -1848,11 +1844,11 @@ cdef class ZZ_FpT_coerce(RingHomomorphism): cdef inline bint normalize(nmod_poly_t numer, nmod_poly_t denom, long p): """ - Put numer/denom into a normal form: denominator monic and sharing no common factor with the numerator. + Put ``numer`` / ``denom`` into a normal form: denominator monic and sharing no common factor with the numerator. The normalized form of 0 is 0/1. - Return True if numer and denom were changed. + Return ``True`` if ``numer`` and ``denom`` were changed. """ cdef long a cdef bint changed @@ -1923,9 +1919,9 @@ cdef inline long nmod_poly_cmp(nmod_poly_t a, nmod_poly_t b): """ Compare `a` and `b`, returning 0 if they are equal. - - If the degree of `a` is less than that of `b`, returns -1. + - If the degree of `a` is less than that of `b`, returns `-1`. - - If the degree of `b` is less than that of `a`, returns 1. + - If the degree of `b` is less than that of `a`, returns `1`. - Otherwise, compares `a` and `b` lexicographically, starting at the leading terms. """ @@ -1949,7 +1945,7 @@ cdef inline long nmod_poly_cmp(nmod_poly_t a, nmod_poly_t b): cdef bint nmod_poly_sqrt_check(nmod_poly_t poly): """ - Quick check to see if poly could possibly be a square. + Quick check to see if ``poly`` could possibly be a square. """ # We could use Sage's jacobi_int which is for 32 bits integers rather # than FLINT's n_jacobi which is for longs as the FpT class is crafted @@ -1977,8 +1973,8 @@ def unpickle_FpT_element(K, numer, denom): # elsewhere at some point. cdef int sage_cmp_nmod_poly_t(nmod_poly_t L, nmod_poly_t R): """ - Compare two nmod_poly_t in a Pythonic way, so this returns -1, 0, - or 1, and is consistent. + Compare two ``nmod_poly_t`` in a Pythonic way, so this returns `-1`, `0`, + or `1`, and is consistent. """ cdef int j cdef Py_ssize_t i diff --git a/src/sage/rings/fraction_field_element.pyx b/src/sage/rings/fraction_field_element.pyx index 122c07c091f..2134c2fa07b 100644 --- a/src/sage/rings/fraction_field_element.pyx +++ b/src/sage/rings/fraction_field_element.pyx @@ -9,22 +9,19 @@ AUTHORS: derivative to use Henrici's algorithms [Hor1972]_ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.element cimport FieldElement, parent from sage.structure.richcmp cimport richcmp -# from sage.rings.polynomial.flatten import SpecializationMorphism -from . import integer_ring -from .integer_ring import ZZ from .rational_field import QQ import sage.misc.latex as latex @@ -67,9 +64,9 @@ cdef class FractionFieldElement(FieldElement): Test if :trac:`5451` is fixed:: - sage: A = FiniteField(9,'theta')['t'] - sage: K.<t> = FractionField(A) - sage: f= 2/(t^2+2*t); g =t^9/(t^18 + t^10 + t^2);f+g + sage: A = FiniteField(9,'theta')['t'] # needs sage.rings.finite_rings + sage: K.<t> = FractionField(A) # needs sage.rings.finite_rings + sage: f = 2/(t^2 + 2*t); g = t^9/(t^18 + t^10 + t^2); f + g # needs sage.rings.finite_rings (2*t^15 + 2*t^14 + 2*t^13 + 2*t^12 + 2*t^11 + 2*t^10 + 2*t^9 + t^7 + t^6 + t^5 + t^4 + t^3 + t^2 + t + 1)/(t^17 + t^9 + t) Test if :trac:`8671` is fixed:: @@ -81,8 +78,8 @@ cdef class FractionFieldElement(FieldElement): sage: F.one().quo_rem(F.one()) (1, 0) """ - cdef object __numerator - cdef object __denominator + cdef object _numerator + cdef object _denominator cdef bint _is_reduced def __init__(self, parent, numerator, denominator=1, @@ -102,7 +99,7 @@ cdef class FractionFieldElement(FieldElement): sage: f.numerator() 'hi' - sage: x = var('x') + sage: x = var('x') # needs sage.symbolic sage: K((x + 1)/(x^2 + x + 1)) (x + 1)/(x^2 + x + 1) sage: K(355/113) @@ -111,17 +108,17 @@ cdef class FractionFieldElement(FieldElement): """ FieldElement.__init__(self, parent) if coerce: - self.__numerator = parent.ring()(numerator) - self.__denominator = parent.ring()(denominator) + self._numerator = parent.ring()(numerator) + self._denominator = parent.ring()(denominator) else: - self.__numerator = numerator - self.__denominator = denominator + self._numerator = numerator + self._denominator = denominator if reduce and parent.is_exact(): try: self.reduce() except ArithmeticError: pass - if self.__denominator.is_zero(): + if self._denominator.is_zero(): raise ZeroDivisionError("fraction field element division by zero") def _im_gens_(self, codomain, im_gens, base_map=None): @@ -135,30 +132,31 @@ cdef class FractionFieldElement(FieldElement): :: - sage: phi = F.hom([a+b, a*b], K) + sage: phi = F.hom([a + b, a*b], K) sage: phi(x+y) # indirect doctest a*b + a + b :: - sage: (x^2/y)._im_gens_(K, [a+b, a*b]) + sage: (x^2/y)._im_gens_(K, [a + b, a*b]) (a^2 + 2*a*b + b^2)/(a*b) sage: (x^2/y)._im_gens_(K, [a, a*b]) a/b :: + sage: # needs sage.rings.number_field sage: Zx.<x> = ZZ[] sage: K.<i> = NumberField(x^2 + 1) sage: cc = K.hom([-i]) sage: R.<a,b> = K[] sage: F = R.fraction_field() - sage: phi = F.hom([F(b),F(a)], base_map=cc) + sage: phi = F.hom([F(b), F(a)], base_map=cc) sage: phi(i/a) ((-i))/b """ - nnum = codomain.coerce(self.__numerator._im_gens_(codomain, im_gens, base_map=base_map)) - nden = codomain.coerce(self.__denominator._im_gens_(codomain, im_gens, base_map=base_map)) + nnum = codomain.coerce(self._numerator._im_gens_(codomain, im_gens, base_map=base_map)) + nden = codomain.coerce(self._denominator._im_gens_(codomain, im_gens, base_map=base_map)) return codomain.coerce(nnum/nden) cpdef reduce(self): @@ -176,10 +174,10 @@ cdef class FractionFieldElement(FieldElement): EXAMPLES:: - sage: R.<x> = RealField(10)[] - sage: f = (x^2+2*x+1)/(x+1); f + sage: R.<x> = RealField(10)[] # needs sage.rings.real_mpfr + sage: f = (x^2+2*x+1)/(x+1); f # needs sage.rings.real_mpfr (x^2 + 2.0*x + 1.0)/(x + 1.0) - sage: f.reduce(); f + sage: f.reduce(); f # needs sage.rings.real_mpfr x + 1.0 TESTS: @@ -194,10 +192,10 @@ cdef class FractionFieldElement(FieldElement): if self._is_reduced: return try: - g = self.__numerator.gcd(self.__denominator) + g = self._numerator.gcd(self._denominator) if not g.is_unit(): - self.__numerator //= g - self.__denominator //= g + self._numerator //= g + self._denominator //= g self._is_reduced = True except AttributeError: raise ArithmeticError("unable to reduce because lack of gcd or quo_rem algorithm") @@ -205,14 +203,14 @@ cdef class FractionFieldElement(FieldElement): raise ArithmeticError("unable to reduce because gcd algorithm doesn't work on input") except NotImplementedError: raise ArithmeticError("unable to reduce because gcd algorithm not implemented on input") - if not self.__denominator.is_one() and self.__denominator.is_unit(): + if not self._denominator.is_one() and self._denominator.is_unit(): try: - inv = self.__denominator.inverse_of_unit() + inv = self._denominator.inverse_of_unit() except Exception: pass else: - self.__numerator *= inv - self.__denominator = self.__denominator.parent().one() + self._numerator *= inv + self._denominator = self._denominator.parent().one() def __copy__(self): """ @@ -221,13 +219,13 @@ cdef class FractionFieldElement(FieldElement): EXAMPLES:: sage: R.<x,y> = ZZ[] - sage: f = x/y+1; f + sage: f = x/y + 1; f (x + y)/y sage: copy(f) (x + y)/y """ - return self.__class__(self._parent, self.__numerator, - self.__denominator, coerce=False, reduce=False) + return self.__class__(self._parent, self._numerator, + self._denominator, coerce=False, reduce=False) def numerator(self): """ @@ -236,12 +234,12 @@ cdef class FractionFieldElement(FieldElement): EXAMPLES:: sage: R.<x,y> = ZZ[] - sage: f = x/y+1; f + sage: f = x/y + 1; f (x + y)/y sage: f.numerator() x + y """ - return self.__numerator + return self._numerator def denominator(self): """ @@ -250,12 +248,12 @@ cdef class FractionFieldElement(FieldElement): EXAMPLES:: sage: R.<x,y> = ZZ[] - sage: f = x/y+1; f + sage: f = x/y + 1; f (x + y)/y sage: f.denominator() y """ - return self.__denominator + return self._denominator def is_square(self,root=False): @@ -310,10 +308,10 @@ cdef class FractionFieldElement(FieldElement): a = self.numerator() b = self.denominator() if not root: - return (a*b).is_square( root = False ) - is_sqr, sq_rt = (a*b).is_square( root = True ) + return (a * b).is_square(root=False) + is_sqr, sq_rt = (a * b).is_square(root=True) if is_sqr: - return True, self._parent( sq_rt/b ) + return True, self._parent(sq_rt / b) return False, None def nth_root(self, n): @@ -396,16 +394,16 @@ cdef class FractionFieldElement(FieldElement): Check that :trac:`25199` is fixed:: - sage: R.<x,y,z>=QQbar[] - sage: hash(R.0)==hash(FractionField(R).0) + sage: R.<x,y,z> = QQbar[] # needs sage.rings.number_field + sage: hash(R.0) == hash(FractionField(R).0) True - sage: ((x+1)/(x^2+1)).subs({x:1}) + sage: ((x+1)/(x^2+1)).subs({x: 1}) 1 """ - if self.__denominator.is_one(): + if self._denominator.is_one(): # Handle this case even over rings that don't support reduction, to # avoid breaking existing code that carelessly mixes p and p/1 - return hash(self.__numerator) + return hash(self._numerator) if self._parent.is_exact(): # May fail; let the exception propagate then. # (In contrast, over inexact rings, we hash unreduced fractions @@ -416,8 +414,8 @@ cdef class FractionFieldElement(FieldElement): # issues even if we didn't...) self.reduce() # Same algorithm as for elements of QQ - n = hash(self.__numerator) - d = hash(self.__denominator) + n = hash(self._numerator) + d = hash(self._denominator) if d == 1: return n else: @@ -438,7 +436,7 @@ cdef class FractionFieldElement(FieldElement): -2*x1*x2 + x0 + x1 sage: f(1,2,5) -17 - sage: h = f /(x[1] + x[2]) + sage: h = f / (x[1] + x[2]) sage: h (-2*x1*x2 + x0 + x1)/(x1 + x2) sage: h(1,2,5) @@ -446,7 +444,7 @@ cdef class FractionFieldElement(FieldElement): sage: h(x0=1) (-2*x1*x2 + x1 + 1)/(x1 + x2) """ - return self.__numerator(*x, **kwds) / self.__denominator(*x, **kwds) + return self._numerator(*x, **kwds) / self._denominator(*x, **kwds) def _is_atomic(self): """ @@ -459,7 +457,7 @@ cdef class FractionFieldElement(FieldElement): sage: f._is_atomic() False """ - return self.__numerator._is_atomic() and self.__denominator._is_atomic() + return self._numerator._is_atomic() and self._denominator._is_atomic() def _repr_(self): """ @@ -479,13 +477,13 @@ cdef class FractionFieldElement(FieldElement): """ if self.is_zero(): return "0" - s = "%s" % self.__numerator - if self.__denominator != 1: - denom_string = str( self.__denominator ) - if self.__denominator._is_atomic() and not ('*' in denom_string or '/' in denom_string): - s = "%s/%s"%(self.__numerator._coeff_repr(no_space=False),denom_string) + s = "%s" % self._numerator + if self._denominator != 1: + denom_string = str( self._denominator ) + if self._denominator._is_atomic() and not ('*' in denom_string or '/' in denom_string): + s = "%s/%s"%(self._numerator._coeff_repr(no_space=False),denom_string) else: - s = "%s/(%s)"%(self.__numerator._coeff_repr(no_space=False),denom_string) + s = "%s/(%s)"%(self._numerator._coeff_repr(no_space=False),denom_string) return s def _latex_(self): @@ -521,10 +519,10 @@ cdef class FractionFieldElement(FieldElement): """ if self.is_zero(): return "0" - if self.__denominator == 1: - return latex.latex(self.__numerator) - return "\\frac{%s}{%s}"%(latex.latex(self.__numerator), - latex.latex(self.__denominator)) + if self._denominator == 1: + return latex.latex(self._numerator) + return "\\frac{%s}{%s}"%(latex.latex(self._numerator), + latex.latex(self._denominator)) def _magma_init_(self, magma): """ @@ -533,7 +531,7 @@ cdef class FractionFieldElement(FieldElement): EXAMPLES:: sage: R.<x> = ZZ[] - sage: magma((x^2 + x + 1)/(x + 1)) # optional - magma # indirect doctest + sage: magma((x^2 + x + 1)/(x + 1)) # optional - magma # indirect doctest (x^2 + x + 1)/(x + 1) :: @@ -571,7 +569,7 @@ cdef class FractionFieldElement(FieldElement): (x + y)/(x*y) sage: 1/x + 1/(x*y) (y + 1)/(x*y) - sage: Frac(CDF['x']).gen() + 3 + sage: Frac(CDF['x']).gen() + 3 # needs sage.rings.complex_double x + 3.0 Subtraction is implemented by adding the negative:: @@ -580,10 +578,10 @@ cdef class FractionFieldElement(FieldElement): sage: t - 1/t # indirect doctest (t^2 + 6)/t """ - rnum = self.__numerator - rden = self.__denominator - snum = (<FractionFieldElement> right).__numerator - sden = (<FractionFieldElement> right).__denominator + rnum = self._numerator + rden = self._denominator + snum = (<FractionFieldElement> right)._numerator + sden = (<FractionFieldElement> right)._denominator if (rnum.is_zero()): return <FractionFieldElement> right @@ -605,7 +603,7 @@ cdef class FractionFieldElement(FieldElement): self._parent.ring().one(), coerce=False, reduce=False) else: - tden = self.__denominator * sden + tden = self._denominator * sden e = tnum.gcd(d) if not e.is_unit(): tnum = tnum // e @@ -627,10 +625,10 @@ cdef class FractionFieldElement(FieldElement): except TypeError: pass - rnum = self.__numerator - rden = self.__denominator - snum = (<FractionFieldElement> right).__numerator - sden = (<FractionFieldElement> right).__denominator + rnum = self._numerator + rden = self._denominator + snum = (<FractionFieldElement> right)._numerator + sden = (<FractionFieldElement> right)._denominator return self.__class__(self._parent, rnum*sden + rden*snum, rden*sden, coerce=False, reduce=False) @@ -649,16 +647,17 @@ cdef class FractionFieldElement(FieldElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<t> = Frac(GF(7)['t']) sage: a = t/(1+t) sage: b = 3/t - sage: a*b # indirect doctest + sage: a * b # indirect doctest 3/(t + 1) """ - rnum = self.__numerator - rden = self.__denominator - snum = (<FractionFieldElement> right).__numerator - sden = (<FractionFieldElement> right).__denominator + rnum = self._numerator + rden = self._denominator + snum = (<FractionFieldElement> right)._numerator + sden = (<FractionFieldElement> right)._denominator if (rnum.is_zero() or snum.is_zero()): return self._parent.zero() @@ -692,10 +691,10 @@ cdef class FractionFieldElement(FieldElement): except TypeError: pass - rnum = self.__numerator - rden = self.__denominator - snum = (<FractionFieldElement> right).__numerator - sden = (<FractionFieldElement> right).__denominator + rnum = self._numerator + rden = self._denominator + snum = (<FractionFieldElement> right)._numerator + sden = (<FractionFieldElement> right)._denominator return self.__class__(self._parent, rnum * snum, rden * sden, coerce=False, reduce=False) @@ -720,8 +719,8 @@ cdef class FractionFieldElement(FieldElement): sage: a/b (x*z - x + z - 1)/(z - 3) """ - snum = (<FractionFieldElement> right).__numerator - sden = (<FractionFieldElement> right).__denominator + snum = (<FractionFieldElement> right)._numerator + sden = (<FractionFieldElement> right)._denominator if snum.is_zero(): raise ZeroDivisionError("fraction field element division by zero") @@ -746,10 +745,10 @@ cdef class FractionFieldElement(FieldElement): sage: int(K(.5)) 0 """ - if self.__denominator != 1: + if self._denominator != 1: self.reduce() - if self.__denominator == 1: - return int(self.__numerator) + if self._denominator == 1: + return int(self._numerator) else: raise TypeError("denominator must equal 1") @@ -761,24 +760,24 @@ cdef class FractionFieldElement(FieldElement): sage: float(x/x + y/y) 2.0 """ - return float(self.__numerator) / float(self.__denominator) + return float(self._numerator) / float(self._denominator) def __complex__(self): """ EXAMPLES:: - sage: K.<x,y> = Frac(I.parent()['x,y']) - sage: complex(x/(I*x) + (I*y)/y) + sage: K.<x,y> = Frac(I.parent()['x,y']) # needs sage.symbolic + sage: complex(x/(I*x) + (I*y)/y) # needs sage.symbolic 0j """ - return complex(self.__numerator) / complex(self.__denominator) + return complex(self._numerator) / complex(self._denominator) def _rational_(self): r""" TESTS:: sage: K = Frac(ZZ['x']) - sage: QQ(K(x) / K(2*x)) + sage: QQ(K(x) / K(2*x)) # needs sage.symbolic 1/2 """ return self._conversion(QQ) @@ -814,10 +813,11 @@ cdef class FractionFieldElement(FieldElement): 3/2 sage: x = polygen(QQ) - sage: A.<u> = NumberField(x^3 - 2) - sage: A((x+3) / (2*x - 1)) + sage: A.<u> = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: A((x+3) / (2*x - 1)) # needs sage.rings.number_field 14/15*u^2 + 7/15*u + 11/15 + sage: # needs sage.rings.number_field sage: B = A['y'].fraction_field() sage: A(B(u)) u @@ -825,12 +825,12 @@ cdef class FractionFieldElement(FieldElement): sage: A(C(u)) u """ - if self.__denominator.is_one(): - return R(self.__numerator) + if self._denominator.is_one(): + return R(self._numerator) else: self.reduce() - num = R(self.__numerator) - inv_den = R(self.__denominator).inverse_of_unit() + num = R(self._numerator) + inv_den = R(self._denominator).inverse_of_unit() return num * inv_den _real_double_ = _conversion @@ -850,7 +850,7 @@ cdef class FractionFieldElement(FieldElement): Returns self raised to the `right^{th}` power. Note that we need to check whether or not right is negative so we - don't set ``__numerator`` or ``__denominator`` to an element of the + don't set ``_numerator`` or ``_denominator`` to an element of the fraction field instead of the underlying ring. EXAMPLES:: @@ -860,15 +860,15 @@ cdef class FractionFieldElement(FieldElement): sage: x,y = FR.gens() sage: a = x^2; a x^2 - sage: type(a.numerator()) + sage: type(a.numerator()) # needs sage.libs.singular <class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'> - sage: type(a.denominator()) + sage: type(a.denominator()) # needs sage.libs.singular <class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'> sage: a = x^(-2); a 1/x^2 - sage: type(a.numerator()) + sage: type(a.numerator()) # needs sage.libs.singular <class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'> - sage: type(a.denominator()) + sage: type(a.denominator()) # needs sage.libs.singular <class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'> sage: x^0 1 @@ -879,8 +879,8 @@ cdef class FractionFieldElement(FieldElement): sage: ((x+y)/(x-y))^0 1 """ - snum = (<FractionFieldElement> self).__numerator - sden = (<FractionFieldElement> self).__denominator + snum = (<FractionFieldElement> self)._numerator + sden = (<FractionFieldElement> self)._denominator if right == 0: R = self.parent().ring() return self.__class__(self.parent(), @@ -907,7 +907,7 @@ cdef class FractionFieldElement(FieldElement): (4*t^2 + 4*t)/(t + 2) """ return self.__class__(self._parent, - -self.__numerator, self.__denominator, + -self._numerator, self._denominator, coerce=False, reduce=False) def __abs__(self): @@ -918,7 +918,7 @@ cdef class FractionFieldElement(FieldElement): sage: abs(FractionFieldElement(QQ, -2, 3, coerce=False)) 2/3 """ - return abs(self.__numerator) / abs(self.__denominator) + return abs(self._numerator) / abs(self._denominator) def __invert__(self): """ @@ -932,16 +932,17 @@ cdef class FractionFieldElement(FieldElement): if self.is_zero(): raise ZeroDivisionError("Cannot invert 0") return self.__class__(self._parent, - self.__denominator, self.__numerator, coerce=False, reduce=False) + self._denominator, self._numerator, coerce=False, reduce=False) cpdef _richcmp_(self, other, int op): """ EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<t> = Frac(GF(7)['t']) sage: t/t == 1 True - sage: t+1/t == (t^2+1)/t + sage: t + 1/t == (t^2+1)/t True sage: t == t/5 False @@ -954,10 +955,10 @@ cdef class FractionFieldElement(FieldElement): sage: 1 > y False """ - return richcmp(self.__numerator * - (<FractionFieldElement>other).__denominator, - self.__denominator * - (<FractionFieldElement>other).__numerator, op) + return richcmp(self._numerator * + (<FractionFieldElement>other)._denominator, + self._denominator * + (<FractionFieldElement>other)._numerator, op) def valuation(self, v=None): """ @@ -972,10 +973,10 @@ cdef class FractionFieldElement(FieldElement): (-1/2*x^2 - 1/2)/(x^2 - 1/2*x) sage: f.valuation() -1 - sage: f.valuation(x^2+1) + sage: f.valuation(x^2 + 1) 1 """ - return self.__numerator.valuation(v) - self.__denominator.valuation(v) + return self._numerator.valuation(v) - self._denominator.valuation(v) def __bool__(self): """ @@ -994,7 +995,7 @@ cdef class FractionFieldElement(FieldElement): sage: bool(1/x) True """ - return not self.__numerator.is_zero() + return not self._numerator.is_zero() def is_zero(self): """ @@ -1013,7 +1014,7 @@ cdef class FractionFieldElement(FieldElement): sage: u.parent() is F True """ - return self.__numerator.is_zero() + return self._numerator.is_zero() def is_one(self): """ @@ -1028,7 +1029,7 @@ cdef class FractionFieldElement(FieldElement): sage: (x/y).is_one() False """ - return self.__numerator == self.__denominator + return self._numerator == self._denominator def _symbolic_(self, ring): """ @@ -1042,12 +1043,12 @@ cdef class FractionFieldElement(FieldElement): sage: x,y = F.gens() sage: elt = (2*x + 2*y) / (3*x - 3*y); elt (2*x + 2*y)/(3*x - 3*y) - sage: elt._symbolic_(SR) + sage: elt._symbolic_(SR) # needs sage.symbolic 2/3*(x + y)/(x - y) - sage: symbolic_expression(elt) + sage: symbolic_expression(elt) # needs sage.symbolic 2/3*(x + y)/(x - y) """ - return ring(self.__numerator)/ring(self.__denominator) + return ring(self._numerator)/ring(self._denominator) def __reduce__(self): """ @@ -1061,7 +1062,7 @@ cdef class FractionFieldElement(FieldElement): True """ return (make_element, - (self._parent, self.__numerator, self.__denominator)) + (self._parent, self._numerator, self._denominator)) def _evaluate_polynomial(self, pol): """ @@ -1108,7 +1109,8 @@ cdef class FractionFieldElement(FieldElement): Check that inexact elements are treated correctly:: - sage: K=Qp(2,5) + sage: # needs sage.rings.padics + sage: K = Qp(2, 5) sage: R.<x> = K[] sage: L = R.fraction_field() sage: S.<y> = L[] @@ -1173,9 +1175,9 @@ cdef class FractionFieldElement_1poly_field(FractionFieldElement): """ See :meth:`reduce`. """ - invlc = ~self.__denominator.leading_coefficient() - self.__denominator = self.__denominator.monic() - self.__numerator *= invlc + invlc = ~self._denominator.leading_coefficient() + self._denominator = self._denominator.monic() + self._numerator *= invlc def is_integral(self): """ @@ -1205,8 +1207,9 @@ cdef class FractionFieldElement_1poly_field(FractionFieldElement): EXAMPLES:: sage: R.<t> = QQ[] - sage: h = (t^14 + 2*t^12 - 4*t^11 - 8*t^9 + 6*t^8 + 12*t^6 - 4*t^5 - 8*t^3 + t^2 + 2)/(t^6 + 6*t^5 + 9*t^4 - 2*t^2 - 12*t - 18) - sage: h.support() + sage: h = (t^14 + 2*t^12 - 4*t^11 - 8*t^9 + 6*t^8 + 12*t^6 - 4*t^5 + ....: - 8*t^3 + t^2 + 2)/(t^6 + 6*t^5 + 9*t^4 - 2*t^2 - 12*t - 18) + sage: h.support() # needs sage.libs.pari [t - 1, t + 3, t^2 + 2, t^2 + t + 1, t^4 - 2] """ L = [fac[0] for fac in self.numerator().factor()] + [fac[0] for fac in self.denominator().factor()] @@ -1249,7 +1252,7 @@ def make_element(parent, numerator, denominator): sage: R = ZZ['x,y'] sage: x,y = R.gens() sage: F = R.fraction_field() - sage: make_element(F, 1+x, 1+y) + sage: make_element(F, 1 + x, 1 + y) (x + 1)/(y + 1) """ @@ -1265,7 +1268,8 @@ def make_element_old(parent, cdict): sage: from sage.rings.fraction_field_element import make_element_old sage: R.<x,y> = ZZ[] sage: F = R.fraction_field() - sage: make_element_old(F, {'_FractionFieldElement__numerator':x+y,'_FractionFieldElement__denominator':x-y}) + sage: make_element_old(F, {'_FractionFieldElement__numerator': x + y, + ....: '_FractionFieldElement__denominator': x - y}) (x + y)/(x - y) """ return FractionFieldElement(parent, diff --git a/src/sage/rings/function_field/__init__.py b/src/sage/rings/function_field/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/rings/function_field/all.py b/src/sage/rings/function_field/all.py index b6bba3369c3..455fa9fe19e 100644 --- a/src/sage/rings/function_field/all.py +++ b/src/sage/rings/function_field/all.py @@ -1 +1,5 @@ from .constructor import FunctionField + +from sage.misc.lazy_import import lazy_import + +lazy_import("sage.rings.function_field.drinfeld_modules.drinfeld_module", "DrinfeldModule") diff --git a/src/sage/rings/function_field/constructor.py b/src/sage/rings/function_field/constructor.py index a459b9e51ac..071f66ec163 100644 --- a/src/sage/rings/function_field/constructor.py +++ b/src/sage/rings/function_field/constructor.py @@ -24,16 +24,19 @@ ``UniqueFactory`` """ -#***************************************************************************** -# Copyright (C) 2010 William Stein <wstein@gmail.com> -# Copyright (C) 2011 Maarten Derickx <m.derickx.student@gmail.com> -# Copyright (C) 2011 Julian Rueth <julian.rueth@gmail.com> + +# **************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2011-2014 Julian Rueth <julian.rueth@gmail.com> +# 2012 Travis Scrimshaw +# 2017-2019 Kwankyu Lee # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from sage.structure.factory import UniqueFactory @@ -57,7 +60,7 @@ class FunctionFieldFactory(UniqueFactory): sage: L.<y> = FunctionField(GF(7)); L Rational function field in y over Finite Field of size 7 sage: R.<z> = L[] - sage: M.<z> = L.extension(z^7-z-y); M + sage: M.<z> = L.extension(z^7 - z - y); M # needs sage.rings.finite_rings sage.rings.function_field Function field in z defined by z^7 + 6*z + 6*y TESTS:: @@ -83,7 +86,7 @@ def create_key(self, F, names): sage: K.<x> = FunctionField(QQ) # indirect doctest """ if not isinstance(names, tuple): - names=(names,) + names = (names,) return (F, names) def create_object(self, version, key,**extra_args): @@ -99,16 +102,18 @@ def create_object(self, version, key,**extra_args): True """ if key[0].is_finite(): - from .function_field import RationalFunctionField_global + from .function_field_rational import RationalFunctionField_global return RationalFunctionField_global(key[0], names=key[1]) elif key[0].characteristic() == 0: - from .function_field import RationalFunctionField_char_zero + from .function_field_rational import RationalFunctionField_char_zero return RationalFunctionField_char_zero(key[0], names=key[1]) else: - from .function_field import RationalFunctionField + from .function_field_rational import RationalFunctionField return RationalFunctionField(key[0], names=key[1]) -FunctionField=FunctionFieldFactory("sage.rings.function_field.constructor.FunctionField") + +FunctionField = FunctionFieldFactory("sage.rings.function_field.constructor.FunctionField") + class FunctionFieldExtensionFactory(UniqueFactory): """ @@ -129,13 +134,13 @@ class FunctionFieldExtensionFactory(UniqueFactory): EXAMPLES:: sage: K.<x> = FunctionField(QQ) - sage: R.<y>=K[] + sage: R.<y> = K[] sage: y2 = y*1 sage: y2 is y False - sage: L.<w>=K.extension(x - y^2) - sage: M.<w>=K.extension(x - y2^2) - sage: L is M + sage: L.<w> = K.extension(x - y^2) # needs sage.rings.function_field + sage: M.<w> = K.extension(x - y2^2) # needs sage.rings.function_field + sage: L is M # needs sage.rings.function_field True """ def create_key(self,polynomial,names): @@ -147,12 +152,13 @@ def create_key(self,polynomial,names): sage: K.<x> = FunctionField(QQ) sage: R.<y> = K[] - sage: L.<w> = K.extension(x - y^2) # indirect doctest + sage: L.<w> = K.extension(x - y^2) # indirect doctest # needs sage.rings.function_field TESTS: Verify that :trac:`16530` has been resolved:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ) sage: R.<y> = K[] sage: L.<y> = K.extension(y^2 - x) @@ -165,9 +171,9 @@ def create_key(self,polynomial,names): """ if names is None: - names=polynomial.variable_name() + names = polynomial.variable_name() if not isinstance(names,tuple): - names=(names,) + names = (names,) return (polynomial,names,polynomial.base_ring()) def create_object(self,version,key,**extra_args): @@ -179,32 +185,34 @@ def create_object(self,version,key,**extra_args): sage: K.<x> = FunctionField(QQ) sage: R.<y> = K[] - sage: L.<w> = K.extension(x - y^2) # indirect doctest + sage: L.<w> = K.extension(x - y^2) # indirect doctest # needs sage.rings.function_field sage: y2 = y*1 - sage: M.<w> = K.extension(x - y2^2) # indirect doctest - sage: L is M + sage: M.<w> = K.extension(x - y2^2) # indirect doctest # needs sage.rings.function_field + sage: L is M # needs sage.rings.function_field True """ - from . import function_field + from . import function_field_polymod, function_field_rational + f = key[0] names = key[1] base_field = f.base_ring() - if isinstance(base_field, function_field.RationalFunctionField): + if isinstance(base_field, function_field_rational.RationalFunctionField): k = base_field.constant_field() if k.is_finite(): # then we are in positive characteristic # irreducible and separable if f.is_irreducible() and not all(e % k.characteristic() == 0 for e in f.exponents()): # monic and integral if f.is_monic() and all(e in base_field.maximal_order() for e in f.coefficients()): - return function_field.FunctionField_global_integral(f, names) + return function_field_polymod.FunctionField_global_integral(f, names) else: - return function_field.FunctionField_global(f, names) + return function_field_polymod.FunctionField_global(f, names) elif k.characteristic() == 0: if f.is_irreducible() and f.is_monic() and all(e in base_field.maximal_order() for e in f.coefficients()): - return function_field.FunctionField_char_zero_integral(f, names) + return function_field_polymod.FunctionField_char_zero_integral(f, names) else: - return function_field.FunctionField_char_zero(f, names) - return function_field.FunctionField_polymod(f, names) + return function_field_polymod.FunctionField_char_zero(f, names) + return function_field_polymod.FunctionField_polymod(f, names) + -FunctionFieldExtension=FunctionFieldExtensionFactory( +FunctionFieldExtension = FunctionFieldExtensionFactory( "sage.rings.function_field.constructor.FunctionFieldExtension") diff --git a/src/sage/rings/function_field/derivations.py b/src/sage/rings/function_field/derivations.py new file mode 100644 index 00000000000..9a6f0f613a9 --- /dev/null +++ b/src/sage/rings/function_field/derivations.py @@ -0,0 +1,102 @@ +r""" +Derivations of function fields + +For global function fields, which have positive characteristics, the higher +derivation is available:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field + sage: h = L.higher_derivation() # needs sage.rings.function_field + sage: h(y^2, 2) # needs sage.rings.function_field + ((x^7 + 1)/x^2)*y^2 + x^3*y + +AUTHORS: + +- William Stein (2010): initial version + +- Julian Rรผth (2011-09-14, 2014-06-23, 2017-08-21): refactored class hierarchy; added + derivation classes; morphisms to/from fraction fields + +- Kwankyu Lee (2017-04-30): added higher derivations and completions + +""" + +# **************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011-2017 Julian Rรผth <julian.rueth@gmail.com> +# 2017 Alyson Deines +# 2017-2019 Kwankyu Lee +# 2018-2019 Travis Scrimshaw +# 2019 Brent Baccala +# 2022 Xavier Caruso +# 2022 Frรฉdรฉric Chapoton +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.rings.derivation import RingDerivationWithoutTwist + + +class FunctionFieldDerivation(RingDerivationWithoutTwist): + r""" + Base class for derivations on function fields. + + A derivation on `R` is a map `R \to R` with + `D(\alpha+\beta)=D(\alpha)+D(\beta)` and `D(\alpha\beta)=\beta + D(\alpha)+\alpha D(\beta)` for all `\alpha,\beta\in R`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: d = K.derivation() + sage: d + d/dx + """ + def __init__(self, parent): + r""" + Initialize a derivation. + + INPUT: + + - ``parent`` -- the differential module in which this + derivation lives + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: d = K.derivation() + sage: TestSuite(d).run() + """ + RingDerivationWithoutTwist.__init__(self, parent) + self.__field = parent.domain() + + def is_injective(self) -> bool: + r""" + Return ``False`` since a derivation is never injective. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: d = K.derivation() + sage: d.is_injective() + False + """ + return False + + def _rmul_(self, factor): + """ + Return the product of this derivation by the scalar ``factor``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: d = K.derivation() + sage: d + d/dx + sage: x * d + x*d/dx + """ + return self._lmul_(factor) diff --git a/src/sage/rings/function_field/derivations_polymod.py b/src/sage/rings/function_field/derivations_polymod.py new file mode 100644 index 00000000000..2e0fe91a968 --- /dev/null +++ b/src/sage/rings/function_field/derivations_polymod.py @@ -0,0 +1,911 @@ +r""" +Derivations of function fields: extension +""" + +# **************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011-2017 Julian Rรผth <julian.rueth@gmail.com> +# 2017 Alyson Deines +# 2017-2019 Kwankyu Lee +# 2018-2019 Travis Scrimshaw +# 2019 Brent Baccala +# 2022 Xavier Caruso +# 2022 Frรฉdรฉric Chapoton +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.arith.misc import binomial +from sage.categories.homset import Hom +from sage.categories.map import Map +from sage.categories.sets_cat import Sets +from sage.rings.derivation import RingDerivationWithoutTwist + +from .derivations import FunctionFieldDerivation + + +class FunctionFieldDerivation_separable(FunctionFieldDerivation): + """ + Derivations of separable extensions. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: L.derivation() + d/dx + """ + def __init__(self, parent, d): + """ + Initialize a derivation. + + INPUT: + + - ``parent`` -- the parent of this derivation + + - ``d`` -- a variable name or a derivation over + the base field (or something capable to create + such a derivation) + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: d = L.derivation() + sage: TestSuite(d).run() + + sage: L.derivation(y) # d/dy + 2*y*d/dx + + sage: dK = K.derivation([x]); dK + x*d/dx + sage: L.derivation(dK) + x*d/dx + """ + FunctionFieldDerivation.__init__(self, parent) + L = parent.domain() + C = parent.codomain() + dm = parent._defining_morphism + u = L.gen() + if d == L.gen(): + d = parent._base_derivation(None) + f = L.polynomial().change_ring(L) + coeff = -f.derivative()(u) / f.map_coefficients(d)(u) + if dm is not None: + coeff = dm(coeff) + self._d = parent._base_derivation([coeff]) + self._gen_image = C.one() + else: + if isinstance(d, RingDerivationWithoutTwist) and d.domain() is L.base_ring(): + self._d = d + else: + self._d = d = parent._base_derivation(d) + f = L.polynomial() + if dm is None: + denom = f.derivative()(u) + else: + u = dm(u) + denom = f.derivative().map_coefficients(dm, new_base_ring=C)(u) + num = f.map_coefficients(d, new_base_ring=C)(u) + self._gen_image = -num / denom + + def _call_(self, x): + r""" + Evaluate the derivation on ``x``. + + INPUT: + + - ``x`` -- element of the function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: d = L.derivation() + sage: d(x) # indirect doctest + 1 + sage: d(y) + 1/2/x*y + sage: d(y^2) + 1 + """ + parent = self.parent() + if x.is_zero(): + return parent.codomain().zero() + x = x._x + y = parent.domain().gen() + dm = parent._defining_morphism + tmp1 = x.map_coefficients(self._d, new_base_ring=parent.codomain()) + tmp2 = x.derivative()(y) + if dm is not None: + tmp2 = dm(tmp2) + y = dm(y) + return tmp1(y) + tmp2 * self._gen_image + + def _add_(self, other): + """ + Return the sum of this derivation and ``other``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: d = L.derivation() + sage: d + d/dx + sage: d + d + 2*d/dx + """ + return type(self)(self.parent(), self._d + other._d) + + def _lmul_(self, factor): + """ + Return the product of this derivation by the scalar ``factor``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: d = L.derivation() + sage: d + d/dx + sage: y * d + y*d/dx + """ + return type(self)(self.parent(), factor * self._d) + + +class FunctionFieldDerivation_inseparable(FunctionFieldDerivation): + def __init__(self, parent, u=None): + r""" + Initialize this derivation. + + INPUT: + + - ``parent`` -- the parent of this derivation + + - ``u`` -- a parameter describing the derivation + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: d = L.derivation() + + This also works for iterated non-monic extensions:: + + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - 1/x) + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^2*y - x^3) + sage: M.derivation() + d/dz + + We can also create a multiple of the canonical derivation:: + + sage: M.derivation([x]) + x*d/dz + """ + FunctionFieldDerivation.__init__(self, parent) + if u is None: + self._u = parent.codomain().one() + elif u == 0 or isinstance(u, (list, tuple)): + if u == 0 or len(u) == 0: + self._u = parent.codomain().zero() + elif len(u) == 1: + self._u = parent.codomain()(u[0]) + else: + raise ValueError("the length does not match") + else: + raise ValueError("you must pass in either a name of a variable or a list of coefficients") + + def _call_(self, x): + r""" + Evaluate the derivation on ``x``. + + INPUT: + + - ``x`` -- an element of the function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: d = L.derivation() + sage: d(x) # indirect doctest + 0 + sage: d(y) + 1 + sage: d(y^2) + 0 + + """ + if x.is_zero(): + return self.codomain().zero() + parent = self.parent() + return self._u * parent._d(parent._t(x)) + + def _add_(self, other): + """ + Return the sum of this derivation and ``other``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(3)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^3 - x) + sage: d = L.derivation() + sage: d + d/dy + sage: d + d + 2*d/dy + """ + return type(self)(self.parent(), [self._u + other._u]) + + def _lmul_(self, factor): + """ + Return the product of this derivation by the scalar ``factor``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: d = L.derivation() + sage: d + d/dy + sage: y * d + y*d/dy + """ + return type(self)(self.parent(), [factor * self._u]) + + +class FunctionFieldHigherDerivation(Map): + """ + Base class of higher derivations on function fields. + + INPUT: + + - ``field`` -- function field on which the derivation operates + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: F.higher_derivation() + Higher derivation map: + From: Rational function field in x over Finite Field of size 2 + To: Rational function field in x over Finite Field of size 2 + """ + def __init__(self, field): + """ + Initialize. + + TESTS:: + + sage: F.<x> = FunctionField(GF(4)) # needs sage.rings.finite_rings + sage: h = F.higher_derivation() # needs sage.rings.finite_rings + sage: TestSuite(h).run(skip='_test_category') # needs sage.rings.finite_rings + """ + Map.__init__(self, Hom(field, field, Sets())) + self._field = field + # elements of a prime finite field do not have pth_root method + if field.constant_base_field().is_prime_field(): + self._pth_root_func = _pth_root_in_prime_field + else: + self._pth_root_func = _pth_root_in_finite_field + + def _repr_type(self) -> str: + """ + Return a string containing the type of the map. + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h # indirect doctest + Higher derivation map: + From: Rational function field in x over Finite Field of size 2 + To: Rational function field in x over Finite Field of size 2 + """ + return 'Higher derivation' + + def __eq__(self, other) -> bool: + """ + Test if ``self`` equals ``other``. + + TESTS:: + + sage: F.<x> = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: loads(dumps(h)) == h + True + """ + if isinstance(other, FunctionFieldHigherDerivation): + return self._field == other._field + return False + + +def _pth_root_in_prime_field(e): + """ + Return the `p`-th root of element ``e`` in a prime finite field. + + TESTS:: + + sage: from sage.rings.function_field.derivations_polymod import _pth_root_in_prime_field + sage: p = 5 + sage: F.<a> = GF(p) + sage: e = F.random_element() + sage: _pth_root_in_prime_field(e)^p == e + True + """ + return e + + +def _pth_root_in_finite_field(e): + """ + Return the `p`-th root of element ``e`` in a finite field. + + TESTS:: + + sage: from sage.rings.function_field.derivations_polymod import _pth_root_in_finite_field + sage: p = 3 + sage: F.<a> = GF(p^2) # needs sage.rings.finite_rings + sage: e = F.random_element() # needs sage.rings.finite_rings + sage: _pth_root_in_finite_field(e)^p == e # needs sage.rings.finite_rings + True + """ + return e.pth_root() + + +class RationalFunctionFieldHigherDerivation_global(FunctionFieldHigherDerivation): + """ + Higher derivations of rational function fields over finite fields. + + INPUT: + + - ``field`` -- function field on which the derivation operates + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h + Higher derivation map: + From: Rational function field in x over Finite Field of size 2 + To: Rational function field in x over Finite Field of size 2 + sage: h(x^2, 2) + 1 + """ + def __init__(self, field): + """ + Initialize. + + TESTS:: + + sage: F.<x> = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: TestSuite(h).run(skip='_test_category') + """ + FunctionFieldHigherDerivation.__init__(self, field) + + self._p = field.characteristic() + self._separating_element = field.gen() + + def _call_with_args(self, f, args=(), kwds={}): + """ + Call the derivation with args and kwds. + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h(x^2, 2) # indirect doctest + 1 + """ + return self._derive(f, *args, **kwds) + + def _derive(self, f, i, separating_element=None): + """ + Return the `i`-th derivative of ``f`` with respect to the + separating element. + + This implements Hess' Algorithm 26 in [Hes2002b]_. + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h._derive(x^3, 0) + x^3 + sage: h._derive(x^3, 1) + x^2 + sage: h._derive(x^3, 2) + x + sage: h._derive(x^3, 3) + 1 + sage: h._derive(x^3, 4) + 0 + """ + F = self._field + p = self._p + + if separating_element is None: + x = self._separating_element + + def derivative(f): + return f.derivative() + else: + x = separating_element + xderinv = ~(x.derivative()) + + def derivative(f): + return xderinv * f.derivative() + + prime_power_representation = self._prime_power_representation + + def derive(f, i): + # Step 1: zero-th derivative + if i == 0: + return f + # Step 2: + s = i % p + r = i // p + # Step 3: + e = f + while s > 0: + e = derivative(e) / F(s) + s -= 1 + # Step 4: + if r == 0: + return e + else: + # Step 5: + lambdas = prime_power_representation(e, x) + # Step 6 and 7: + der = 0 + for i in range(p): + mu = derive(lambdas[i], r) + der += mu**p * x**i + return der + + return derive(f, i) + + def _prime_power_representation(self, f, separating_element=None): + """ + Return `p`-th power representation of the element ``f``. + + Here `p` is the characteristic of the function field. + + This implements Hess' Algorithm 25. + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h._prime_power_representation(x^2 + x + 1) + [x + 1, 1] + sage: x^2 + x + 1 == _[0]^2 + _[1]^2 * x + True + """ + F = self._field + p = self._p + + if separating_element is None: + x = self._separating_element + + def derivative(f): + return f.derivative() + else: + x = separating_element + xderinv = ~(x.derivative()) + + def derivative(f): + return xderinv * f.derivative() + + # Step 1: + a = [f] + aprev = f + j = 1 + while j < p: + aprev = derivative(aprev) / F(j) + a.append(aprev) + j += 1 + # Step 2: + b = a + j = p - 2 + while j >= 0: + b[j] -= sum(binomial(i, j) * b[i] * x**(i - j) + for i in range(j + 1, p)) + j -= 1 + # Step 3 + return [self._pth_root(c) for c in b] + + def _pth_root(self, c): + """ + Return the `p`-th root of the rational function ``c``. + + INPUT: + + - ``c`` -- rational function + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h._pth_root((x^2+1)^2) + x^2 + 1 + """ + K = self._field + p = self._p + + R = K._field.ring() + + poly = c.numerator() + num = R([self._pth_root_func(poly[i]) + for i in range(0, poly.degree() + 1, p)]) + poly = c.denominator() + den = R([self._pth_root_func(poly[i]) + for i in range(0, poly.degree() + 1, p)]) + return K.element_class(K, num / den) + + +class FunctionFieldHigherDerivation_global(FunctionFieldHigherDerivation): + """ + Higher derivations of global function fields. + + INPUT: + + - ``field`` -- function field on which the derivation operates + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: h + Higher derivation map: + From: Function field in y defined by y^3 + x^3*y + x + To: Function field in y defined by y^3 + x^3*y + x + sage: h(y^2, 2) + ((x^7 + 1)/x^2)*y^2 + x^3*y + """ + + def __init__(self, field): + """ + Initialize. + + TESTS:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: TestSuite(h).run(skip=['_test_category']) + """ + from sage.matrix.constructor import matrix + + FunctionFieldHigherDerivation.__init__(self, field) + + self._p = field.characteristic() + self._separating_element = field(field.base_field().gen()) + + p = field.characteristic() + y = field.gen() + + # matrix for pth power map; used in _prime_power_representation method + self.__pth_root_matrix = matrix([(y**(i * p)).list() + for i in range(field.degree())]).transpose() + + # cache computed higher derivatives to speed up later computations + self._cache = {} + + def _call_with_args(self, f, args, kwds): + """ + Call the derivation with ``args`` and ``kwds``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: h(y^2, 2) # indirect doctest + ((x^7 + 1)/x^2)*y^2 + x^3*y + """ + return self._derive(f, *args, **kwds) + + def _derive(self, f, i, separating_element=None): + """ + Return ``i``-th derivative of ``f`` with respect to the separating + element. + + This implements Hess' Algorithm 26 in [Hes2002b]_. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: y^3 + x^3*y + x + sage: h._derive(y^3, 0) + x^3*y + x + sage: h._derive(y^3, 1) + x^4*y^2 + 1 + sage: h._derive(y^3, 2) + x^10*y^2 + (x^8 + x)*y + sage: h._derive(y^3, 3) + (x^9 + x^2)*y^2 + x^7*y + sage: h._derive(y^3, 4) + (x^22 + x)*y^2 + ((x^21 + x^14 + x^7 + 1)/x)*y + """ + F = self._field + p = self._p + frob = F.frobenius_endomorphism() # p-th power map + + if separating_element is None: + x = self._separating_element + + def derivative(f): + return f.derivative() + else: + x = separating_element + xderinv = ~(x.derivative()) + + def derivative(f): + return xderinv * f.derivative() + + try: + cache = self._cache[separating_element] + except KeyError: + cache = self._cache[separating_element] = {} + + def derive(f, i): + # Step 1: zero-th derivative + if i == 0: + return f + + # Step 1.5: use cached result if available + try: + return cache[f, i] + except KeyError: + pass + + # Step 2: + s = i % p + r = i // p + # Step 3: + e = f + while s > 0: + e = derivative(e) / F(s) + s -= 1 + # Step 4: + if r == 0: + der = e + else: + # Step 5: inlined self._prime_power_representation + a = [e] + aprev = e + j = 1 + while j < p: + aprev = derivative(aprev) / F(j) + a.append(aprev) + j += 1 + b = a + j = p - 2 + while j >= 0: + b[j] -= sum(binomial(k, j) * b[k] * x**(k - j) + for k in range(j + 1, p)) + j -= 1 + lambdas = [self._pth_root(c) for c in b] + + # Step 6 and 7: + der = 0 + xpow = 1 + for k in range(p): + mu = derive(lambdas[k], r) + der += frob(mu) * xpow + xpow *= x + + cache[f, i] = der + return der + + return derive(f, i) + + def _prime_power_representation(self, f, separating_element=None): + """ + Return `p`-th power representation of the element ``f``. + + Here `p` is the characteristic of the function field. + + This implements Hess' Algorithm 25 in [Hes2002b]_. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: b = h._prime_power_representation(y) + sage: y == b[0]^2 + b[1]^2 * x + True + """ + F = self._field + p = self._p + + if separating_element is None: + x = self._separating_element + + def derivative(f): + return f.derivative() + else: + x = separating_element + xderinv = ~(x.derivative()) + + def derivative(f): + return xderinv * f.derivative() + + # Step 1: + a = [f] + aprev = f + j = 1 + while j < p: + aprev = derivative(aprev) / F(j) + a.append(aprev) + j += 1 + # Step 2: + b = a + j = p - 2 + while j >= 0: + b[j] -= sum(binomial(i, j) * b[i] * x**(i - j) + for i in range(j + 1, p)) + j -= 1 + # Step 3 + return [self._pth_root(c) for c in b] + + def _pth_root(self, c): + """ + Return the `p`-th root of function field element ``c``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: h._pth_root((x^2 + y^2)^2) + y^2 + x^2 + """ + from sage.modules.free_module_element import vector + + K = self._field.base_field() # rational function field + p = self._p + + coeffs = [] + for d in self.__pth_root_matrix.solve_right(vector(c.list())): + poly = d.numerator() + num = K([self._pth_root_func(poly[i]) + for i in range(0, poly.degree() + 1, p)]) + poly = d.denominator() + den = K([self._pth_root_func(poly[i]) + for i in range(0, poly.degree() + 1, p)]) + coeffs.append(num / den) + return self._field(coeffs) + + +class FunctionFieldHigherDerivation_char_zero(FunctionFieldHigherDerivation): + """ + Higher derivations of function fields of characteristic zero. + + INPUT: + + - ``field`` -- function field on which the derivation operates + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: h + Higher derivation map: + From: Function field in y defined by y^3 + x^3*y + x + To: Function field in y defined by y^3 + x^3*y + x + sage: h(y,1) == -(3*x^2*y+1)/(3*y^2+x^3) + True + sage: h(y^2,1) == -2*y*(3*x^2*y+1)/(3*y^2+x^3) + True + sage: e = L.random_element() + sage: h(h(e,1),1) == 2*h(e,2) + True + sage: h(h(h(e,1),1),1) == 3*2*h(e,3) + True + """ + def __init__(self, field): + """ + Initialize. + + TESTS:: + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: TestSuite(h).run(skip=['_test_category']) + """ + FunctionFieldHigherDerivation.__init__(self, field) + + self._separating_element = field(field.base_field().gen()) + + # cache computed higher derivatives to speed up later computations + self._cache = {} + + def _call_with_args(self, f, args, kwds): + """ + Call the derivation with ``args`` and ``kwds``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: e = L.random_element() + sage: h(h(e,1),1) == 2*h(e,2) # indirect doctest + True + """ + return self._derive(f, *args, **kwds) + + def _derive(self, f, i, separating_element=None): + """ + Return ``i``-th derivative of ``f`` with respect to the separating + element. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: y^3 + -x^3*y - x + sage: h._derive(y^3, 0) + -x^3*y - x + sage: h._derive(y^3, 1) + (-21/4*x^4/(x^7 + 27/4))*y^2 + ((-9/2*x^9 - 45/2*x^2)/(x^7 + 27/4))*y + (-9/2*x^7 - 27/4)/(x^7 + 27/4) + """ + F = self._field + + if separating_element is None: + x = self._separating_element + xderinv = 1 + else: + x = separating_element + xderinv = ~(x.derivative()) + + try: + cache = self._cache[separating_element] + except KeyError: + cache = self._cache[separating_element] = {} + + if i == 0: + return f + + try: + return cache[f, i] + except KeyError: + pass + + s = i + e = f + while s > 0: + e = xderinv * e.derivative() / F(s) + s -= 1 + + der = e + + cache[f, i] = der + return der diff --git a/src/sage/rings/function_field/derivations_rational.py b/src/sage/rings/function_field/derivations_rational.py new file mode 100644 index 00000000000..777f16d3e08 --- /dev/null +++ b/src/sage/rings/function_field/derivations_rational.py @@ -0,0 +1,131 @@ +r""" +Derivations of function fields: rational +""" + +# **************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011-2017 Julian Rรผth <julian.rueth@gmail.com> +# 2017 Alyson Deines +# 2017-2019 Kwankyu Lee +# 2018-2019 Travis Scrimshaw +# 2019 Brent Baccala +# 2022 Xavier Caruso +# 2022 Frรฉdรฉric Chapoton +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from .derivations import FunctionFieldDerivation + + +class FunctionFieldDerivation_rational(FunctionFieldDerivation): + """ + Derivations on rational function fields. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K.derivation() + d/dx + """ + def __init__(self, parent, u=None): + """ + Initialize a derivation. + + INPUT: + + - ``parent`` -- the parent of this derivation + + - ``u`` -- a parameter describing the derivation + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: d = K.derivation() + sage: TestSuite(d).run() + + The parameter ``u`` can be the name of the variable:: + + sage: K.derivation(x) + d/dx + + or a list of length one whose unique element is the image + of the generator of the underlying function field:: + + sage: K.derivation([x^2]) + x^2*d/dx + """ + FunctionFieldDerivation.__init__(self, parent) + if u is None or u == parent.domain().gen(): + self._u = parent.codomain().one() + elif u == 0 or isinstance(u, (list, tuple)): + if u == 0 or len(u) == 0: + self._u = parent.codomain().zero() + elif len(u) == 1: + self._u = parent.codomain()(u[0]) + else: + raise ValueError("the length does not match") + else: + raise ValueError("you must pass in either a name of a variable or a list of coefficients") + + def _call_(self, x): + """ + Compute the derivation of ``x``. + + INPUT: + + - ``x`` -- element of the rational function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: d = K.derivation() + sage: d(x) # indirect doctest + 1 + sage: d(x^3) + 3*x^2 + sage: d(1/x) + -1/x^2 + """ + f = x.numerator() + g = x.denominator() + numerator = f.derivative() * g - f * g.derivative() + if numerator.is_zero(): + return self.codomain().zero() + else: + v = numerator / g**2 + defining_morphism = self.parent()._defining_morphism + if defining_morphism is not None: + v = defining_morphism(v) + return self._u * v + + def _add_(self, other): + """ + Return the sum of this derivation and ``other``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: d = K.derivation() + sage: d + d + 2*d/dx + """ + return type(self)(self.parent(), [self._u + other._u]) + + def _lmul_(self, factor): + """ + Return the product of this derivation by the scalar ``factor``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: d = K.derivation() + sage: d + d/dx + sage: x * d + x*d/dx + """ + return type(self)(self.parent(), [factor * self._u]) diff --git a/src/sage/rings/function_field/differential.py b/src/sage/rings/function_field/differential.py index e7d5f5a5c68..9b6fec9a72d 100644 --- a/src/sage/rings/function_field/differential.py +++ b/src/sage/rings/function_field/differential.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules """ Differentials of function fields @@ -8,6 +9,7 @@ The module of differentials on a function field forms an one-dimensional vector space over the function field:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: f = x + y @@ -24,6 +26,7 @@ We can compute a canonical divisor:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: k = df.divisor() sage: k.degree() 4 @@ -33,6 +36,7 @@ Exact differentials vanish and logarithmic differentials are stable under the Cartier operation:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: df.cartier() 0 sage: w = 1/f * df @@ -44,14 +48,17 @@ - Kwankyu Lee (2017-04-30): initial version """ -#***************************************************************************** -# Copyright (C) 2016 Kwankyu Lee <ekwankyu@gmail.com> + +# **************************************************************************** +# Copyright (C) 2016-2019 Kwankyu Lee <ekwankyu@gmail.com> +# 2019 Brent Baccala +# 2019 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from sage.misc.latex import latex @@ -78,7 +85,7 @@ class FunctionFieldDifferential(ModuleElement): EXAMPLES:: - sage: F.<x>=FunctionField(QQ) + sage: F.<x> = FunctionField(QQ) sage: f = x/(x^2 + x + 1) sage: f.differential() ((-x^2 + 1)/(x^4 + 2*x^3 + 3*x^2 + 2*x + 1)) d(x) @@ -86,10 +93,10 @@ class FunctionFieldDifferential(ModuleElement): :: sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: L(x).differential() + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field + sage: L(x).differential() # needs sage.rings.function_field d(x) - sage: y.differential() + sage: y.differential() # needs sage.rings.function_field ((21/4*x/(x^7 + 27/4))*y^2 + ((3/2*x^7 + 9/4)/(x^8 + 27/4*x))*y + 7/2*x^4/(x^7 + 27/4)) d(x) """ def __init__(self, parent, f, t=None): @@ -116,12 +123,12 @@ def _repr_(self): EXAMPLES:: - sage: K.<x> = FunctionField(GF(4)); _.<Y>=K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) - sage: y.differential() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3+x+x^3*Y) # needs sage.rings.finite_rings sage.rings.function_field + sage: y.differential() # needs sage.rings.finite_rings sage.rings.function_field (x*y^2 + 1/x*y) d(x) - sage: F.<x>=FunctionField(QQ) + sage: F.<x> = FunctionField(QQ) sage: f = 1/x sage: f.differential() (-1/x^2) d(x) @@ -129,7 +136,7 @@ def _repr_(self): if self._f.is_zero(): # zero differential return '0' - r = 'd({})'.format(self.parent()._gen_base_differential) + r = 'd({})'.format(self.parent()._gen_base_differential) if self._f.is_one(): return r @@ -142,16 +149,17 @@ def _latex_(self): EXAMPLES:: - sage: K.<x> = FunctionField(GF(4)); _.<Y>=K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) - sage: w = y.differential() - sage: latex(w) + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field + sage: w = y.differential() # needs sage.rings.function_field + sage: latex(w) # needs sage.rings.function_field \left( x y^{2} + \frac{1}{x} y \right)\, dx """ if self._f.is_zero(): # zero differential return '0' - r = 'd{}'.format(self.parent()._gen_base_differential) + r = 'd{}'.format(self.parent()._gen_base_differential) if self._f.is_one(): return r @@ -164,11 +172,11 @@ def __hash__(self): EXAMPLES:: - sage: K.<x>=FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y>=K.extension(Y^3 + x + x^3*Y) + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field sage: {x.differential(): 1} {d(x): 1} - sage: {y.differential(): 1} + sage: {y.differential(): 1} # needs sage.rings.function_field {(x*y^2 + 1/x*y) d(x): 1} """ return hash((self.parent(), self._f)) @@ -186,8 +194,9 @@ def _richcmp_(self, other, op): EXAMPLES:: - sage: K.<x> = FunctionField(GF(4)); _.<Y>=K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) + sage: # needs sage.rings.finite_rings sage.rings.function_field + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: w1 = y.differential() sage: w2 = L(x).differential() sage: w3 = (x*y).differential() @@ -198,7 +207,7 @@ def _richcmp_(self, other, op): sage: w3 == x * w1 + y * w2 True - sage: F.<x>=FunctionField(QQ) + sage: F.<x> = FunctionField(QQ) sage: w1 = ((x^2+x+1)^10).differential() sage: w2 = (x^2+x+1).differential() sage: w1 < w2 @@ -220,8 +229,9 @@ def _add_(self, other): EXAMPLES:: - sage: K.<x> = FunctionField(GF(4)); _.<Y>=K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) + sage: # needs sage.rings.finite_rings sage.rings.function_field + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: w1 = y.differential() sage: w2 = (1/y).differential() sage: w1 + w2 @@ -248,8 +258,9 @@ def _div_(self, other): EXAMPLES:: - sage: K.<x> = FunctionField(GF(4)); _.<Y>=K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) + sage: # needs sage.rings.finite_rings sage.rings.function_field + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: w1 = y.differential() sage: w2 = (1/y).differential() sage: w1 / w2 @@ -272,8 +283,9 @@ def _neg_(self): EXAMPLES:: - sage: K.<x> = FunctionField(GF(5)); _.<Y>=K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: w1 = y.differential() sage: w2 = (-y).differential() sage: -w1 == w2 @@ -299,14 +311,15 @@ def _rmul_(self, f): EXAMPLES:: - sage: K.<x> = FunctionField(GF(5)); _.<Y>=K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: w1 = (1/y).differential() sage: w2 = (-1/y^2) * y.differential() sage: w1 == w2 True - sage: F.<x>=FunctionField(QQ) + sage: F.<x> = FunctionField(QQ) sage: w1 = (x^2*(x^2+x+1)).differential() sage: w2 = (x^2).differential() sage: w3 = (x^2+x+1).differential() @@ -328,6 +341,7 @@ def _acted_upon_(self, f, self_on_left): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(31)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 - x); _.<Z> = L[] sage: M.<z> = L.extension(Z^2 - y) @@ -336,6 +350,7 @@ def _acted_upon_(self, f, self_on_left): sage: 1/(2*z) * y.differential() (8/x*z) d(x) + sage: # needs sage.rings.function_field sage: z * x.differential() (z) d(x) sage: z * (y^2).differential() @@ -345,9 +360,9 @@ def _acted_upon_(self, f, self_on_left): :: - sage: K.<x>=FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y>=K.extension(Y^3 + x + x^3*Y) - sage: y * x.differential() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.finite_rings sage.rings.function_field + sage: y * x.differential() # needs sage.rings.finite_rings sage.rings.function_field (y) d(x) """ F = f.parent() @@ -363,10 +378,10 @@ def divisor(self): EXAMPLES:: - sage: K.<x> = FunctionField(GF(5)); _.<Y>=K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) - sage: w = (1/y) * y.differential() - sage: w.divisor() + sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field + sage: w = (1/y) * y.differential() # needs sage.rings.function_field + sage: w.divisor() # needs sage.rings.function_field - Place (1/x, 1/x^3*y^2 + 1/x) - Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1) - Place (x, y) @@ -377,7 +392,7 @@ def divisor(self): sage: F.<x> = FunctionField(QQ) sage: w = (1/x).differential() - sage: w.divisor() + sage: w.divisor() # needs sage.libs.pari -2*Place (x) """ F = self.parent().function_field() @@ -394,10 +409,10 @@ def valuation(self, place): EXAMPLES:: - sage: K.<x> = FunctionField(GF(5)); _.<Y>=K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) - sage: w = (1/y) * y.differential() - sage: [w.valuation(p) for p in L.places()] + sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field + sage: w = (1/y) * y.differential() # needs sage.rings.function_field + sage: [w.valuation(p) for p in L.places()] # needs sage.rings.function_field [-1, -1, -1, 0, 1, 0] """ F = self.parent().function_field() @@ -421,6 +436,7 @@ def residue(self, place): We verify the residue theorem in a rational function field:: + sage: # needs sage.rings.finite_rings sage: F.<x> = FunctionField(GF(4)) sage: f = 0 sage: while f == 0: @@ -428,11 +444,12 @@ def residue(self, place): sage: w = 1/f * f.differential() sage: d = f.divisor() sage: s = d.support() - sage: sum([w.residue(p).trace() for p in s]) + sage: sum([w.residue(p).trace() for p in s]) # needs sage.rings.function_field 0 and in an extension field:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(7)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: f = 0 @@ -446,11 +463,12 @@ def residue(self, place): and also in a function field of characteristic zero:: + sage: # needs sage.rings.function_field sage: R.<x> = FunctionField(QQ) sage: L.<Y> = R[] sage: F.<y> = R.extension(Y^2 - x^4 - 4*x^3 - 2*x^2 - 1) sage: a = 6*x^2 + 5*x + 7 - sage: b = 2*x^6 + 8*x^5 + 3*x^4 - 4*x^3 -1 + sage: b = 2*x^6 + 8*x^5 + 3*x^4 - 4*x^3 - 1 sage: w = y*a/b*x.differential() sage: d = w.divisor() sage: sum([QQ(w.residue(p)) for p in d.support()]) @@ -482,11 +500,11 @@ def monomial_coefficients(self, copy=True): EXAMPLES:: sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) - sage: d = y.differential() - sage: d + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field + sage: d = y.differential() # needs sage.rings.function_field + sage: d # needs sage.rings.function_field ((4*x/(x^7 + 3))*y^2 + ((4*x^7 + 1)/(x^8 + 3*x))*y + x^4/(x^7 + 3)) d(x) - sage: d.monomial_coefficients() + sage: d.monomial_coefficients() # needs sage.rings.function_field {0: (4*x/(x^7 + 3))*y^2 + ((4*x^7 + 1)/(x^8 + 3*x))*y + x^4/(x^7 + 3)} """ return {0: self._f} @@ -498,16 +516,16 @@ class FunctionFieldDifferential_global(FunctionFieldDifferential): EXAMPLES:: - sage: F.<x>=FunctionField(GF(7)) + sage: F.<x> = FunctionField(GF(7)) sage: f = x/(x^2 + x + 1) sage: f.differential() ((6*x^2 + 1)/(x^4 + 2*x^3 + 3*x^2 + 2*x + 1)) d(x) :: - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: y.differential() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.finite_rings sage.rings.function_field + sage: y.differential() # needs sage.rings.finite_rings sage.rings.function_field (x*y^2 + 1/x*y) d(x) """ def cartier(self): @@ -527,6 +545,7 @@ def cartier(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: f = x/y @@ -536,10 +555,11 @@ def cartier(self): :: + sage: # needs sage.rings.finite_rings sage: F.<x> = FunctionField(GF(4)) sage: f = x/(x^2 + x + 1) sage: w = 1/f*f.differential() - sage: w.cartier() == w + sage: w.cartier() == w # needs sage.rings.function_field True """ W = self.parent() @@ -559,9 +579,9 @@ class DifferentialsSpace(UniqueRepresentation, Parent): EXAMPLES:: - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: L.space_of_differentials() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) # needs sage.rings.finite_rings sage.rings.function_field + sage: L.space_of_differentials() # needs sage.rings.finite_rings sage.rings.function_field Space of differentials of Function field in y defined by y^3 + x^3*y + x The space of differentials is a one-dimensional module over the function @@ -571,6 +591,7 @@ class DifferentialsSpace(UniqueRepresentation, Parent): element is automatically found and used to generate the base differential relative to which other differentials are denoted:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(5)) sage: R.<y> = K[] sage: L.<y> = K.extension(y^5 - 1/x) @@ -589,8 +610,9 @@ def __init__(self, field, category=None): TESTS:: - sage: K.<x>=FunctionField(GF(4)); _.<Y>=K[] - sage: L.<y>=K.extension(Y^3+x+x^3*Y) + sage: # needs sage.rings.finite_rings sage.rings.function_field + sage: K.<x> = FunctionField(GF(4)); _.<Y>=K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: W = L.space_of_differentials() sage: TestSuite(W).run() """ @@ -615,8 +637,9 @@ def _repr_(self): EXAMPLES:: - sage: K.<x>=FunctionField(GF(4)); _.<Y>=K[] - sage: L.<y>=K.extension(Y^3+x+x^3*Y) + sage: # needs sage.rings.finite_rings sage.rings.function_field + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: w = y.differential() sage: w.parent() Space of differentials of Function field in y defined by y^3 + x^3*y + x @@ -633,8 +656,9 @@ def _element_constructor_(self, f): EXAMPLES:: - sage: K.<x>=FunctionField(GF(4)); _.<Y>=K[] - sage: L.<y>=K.extension(Y^3+x+x^3*Y) + sage: # needs sage.rings.finite_rings sage.rings.function_field + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: S = L.space_of_differentials() sage: S(y) (x*y^2 + 1/x*y) d(x) @@ -658,8 +682,8 @@ def _coerce_map_from_(self, S): EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: L.space_of_differentials().coerce_map_from(K.space_of_differentials()) + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) # needs sage.rings.function_field + sage: L.space_of_differentials().coerce_map_from(K.space_of_differentials()) # needs sage.rings.function_field Inclusion morphism: From: Space of differentials of Rational function field in x over Rational Field To: Space of differentials of Function field in y defined by y^2 - x*y + 4*x^3 @@ -675,6 +699,7 @@ def function_field(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x^3*Y + x) sage: S = L.space_of_differentials() @@ -689,8 +714,9 @@ def _an_element_(self): EXAMPLES:: - sage: K.<x>=FunctionField(GF(4)); _.<Y>=K[] - sage: L.<y>=K.extension(Y^3+x+x^3*Y) + sage: # needs sage.rings.finite_rings sage.rings.function_field + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: S = L.space_of_differentials() sage: S.an_element() # random (x*y^2 + 1/x*y) d(x) @@ -704,6 +730,7 @@ def basis(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x^3*Y + x) sage: S = L.space_of_differentials() @@ -723,9 +750,9 @@ class DifferentialsSpace_global(DifferentialsSpace): EXAMPLES:: - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: L.space_of_differentials() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) # needs sage.rings.finite_rings sage.rings.function_field + sage: L.space_of_differentials() # needs sage.rings.finite_rings sage.rings.function_field Space of differentials of Function field in y defined by y^3 + x^3*y + x """ Element = FunctionFieldDifferential_global @@ -738,10 +765,10 @@ class DifferentialsSpaceInclusion(Morphism): EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) # needs sage.rings.function_field sage: OK = K.space_of_differentials() - sage: OL = L.space_of_differentials() - sage: OL.coerce_map_from(OK) + sage: OL = L.space_of_differentials() # needs sage.rings.function_field + sage: OL.coerce_map_from(OK) # needs sage.rings.function_field Inclusion morphism: From: Space of differentials of Rational function field in x over Rational Field To: Space of differentials of Function field in y defined by y^2 - x*y + 4*x^3 @@ -754,10 +781,10 @@ def _repr_(self): EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) # needs sage.rings.function_field sage: OK = K.space_of_differentials() - sage: OL = L.space_of_differentials() - sage: OL.coerce_map_from(OK) + sage: OL = L.space_of_differentials() # needs sage.rings.function_field + sage: OL.coerce_map_from(OK) # needs sage.rings.function_field Inclusion morphism: From: Space of differentials of Rational function field in x over Rational Field To: Space of differentials of Function field in y defined by y^2 - x*y + 4*x^3 @@ -774,10 +801,10 @@ def is_injective(self): EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) # needs sage.rings.function_field sage: OK = K.space_of_differentials() - sage: OL = L.space_of_differentials() - sage: OL.coerce_map_from(OK).is_injective() + sage: OL = L.space_of_differentials() # needs sage.rings.function_field + sage: OL.coerce_map_from(OK).is_injective() # needs sage.rings.function_field True """ return True @@ -788,6 +815,7 @@ def is_surjective(self): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: OK = K.space_of_differentials() @@ -814,6 +842,7 @@ def _call_(self, v): EXAMPLES:: + sage: # needs sage.rings.function_field sage.rings.number_field sage: K.<x> = FunctionField(QQbar); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 - x*Y + 4*x^3) sage: OK = K.space_of_differentials() diff --git a/src/sage/rings/function_field/divisor.py b/src/sage/rings/function_field/divisor.py index 10e06c248cd..84c837ffb09 100644 --- a/src/sage/rings/function_field/divisor.py +++ b/src/sage/rings/function_field/divisor.py @@ -1,3 +1,5 @@ +# sage.doctest: optional - sage.rings.finite_rings (because all doctests use finite fields) +# sage.doctest: optional - sage.rings.function_field (because almost all doctests use function field extensions) """ Divisors of function fields @@ -37,14 +39,16 @@ - Kwankyu Lee (2017-04-30): initial version """ -#***************************************************************************** -# Copyright (C) 2016 Kwankyu Lee <ekwankyu@gmail.com> + +# **************************************************************************** +# Copyright (C) 2016-2022 Kwankyu Lee <ekwankyu@gmail.com> +# 2019 Brent Baccala # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** import random @@ -1019,7 +1023,7 @@ def _repr_(self): sage: F.divisor_group() Divisor group of Function field in y defined by y^2 + 4*x^3 + 4 """ - return "Divisor group of %s"%(self._field,) + return "Divisor group of %s" % (self._field,) def _element_constructor_(self, x): """ diff --git a/src/sage/rings/function_field/drinfeld_modules/action.py b/src/sage/rings/function_field/drinfeld_modules/action.py new file mode 100644 index 00000000000..cfa9774058a --- /dev/null +++ b/src/sage/rings/function_field/drinfeld_modules/action.py @@ -0,0 +1,196 @@ +# sage.doctest: optional - sage.rings.finite_rings +r""" +The module action induced by a Drinfeld module + +This module provides the class +:class:`sage.rings.function_field.drinfeld_module.action.DrinfeldModuleAction`. + +AUTHORS: + +- Antoine Leudiรจre (2022-04) +""" + +# ***************************************************************************** +# Copyright (C) 2022 Antoine Leudiรจre <antoine.leudiere@inria.fr> +# +# 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. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.categories.action import Action +from sage.misc.latex import latex +from sage.rings.function_field.drinfeld_modules.drinfeld_module import DrinfeldModule + + +class DrinfeldModuleAction(Action): + r""" + This class implements the module action induced by a Drinfeld + `\mathbb{F}_q[T]`-module. + + Let `\phi` be a Drinfeld `\mathbb{F}_q[T]`-module over a field `K` + and let `L/K` be a field extension. Let `x \in L` and let `a` be a + function ring element; the action is defined as `(a, x) \mapsto + \phi_a(x)`. + + .. NOTE:: + + In this implementation, `L` is `K`. + + .. NOTE:: + + The user should never explicitly instantiate the class + `DrinfeldModuleAction`. + + .. WARNING:: + + This class may be replaced later on. See issues #34833 and + #34834. + + INPUT: the Drinfeld module + + EXAMPLES:: + + sage: Fq.<z2> = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z, 0, 0, 1]) + sage: action = phi.action() + sage: action + Action on Finite Field in z of size 11^2 over its base + induced by Drinfeld module defined by T |--> t^3 + z + + The action on elements is computed as follows:: + + sage: P = T + 1 + sage: a = z + sage: action(P, a) + ... + 4*z + 2 + sage: action(0, K.random_element()) + 0 + sage: action(A.random_element(), 0) + 0 + + Finally, given a Drinfeld module action, it is easy to recover the + corresponding Drinfeld module:: + + sage: action.drinfeld_module() is phi + True + """ + + def __init__(self, drinfeld_module): + """ + Initialize ``self``. + + INPUT: the Drinfeld module + + TESTS:: + + sage: Fq.<z2> = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z, 0, 0, 1]) + sage: action = phi.action() + sage: action._drinfeld_module is phi + True + sage: action._base is phi.base() + True + """ + if not isinstance(drinfeld_module, DrinfeldModule): + raise TypeError('input must be a DrinfeldModule') + self._drinfeld_module = drinfeld_module + self._base = drinfeld_module.base() + super().__init__(drinfeld_module.function_ring(), self._base) + + def _act_(self, pol, x): + r""" + Return the action of ``pol`` on ``x``. + + INPUT: + + - ``pol`` -- a function ring element + - ``x`` -- an element in the field acted upon + + OUTPUT: an element in the base codomain + + EXAMPLES:: + + sage: Fq.<z2> = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z, 0, 0, 1]) + sage: action = phi.action() + sage: P = T + 1 + sage: a = z + sage: action(P, a) + 4*z + 2 + sage: action(0, K.random_element()) + 0 + sage: action(A.random_element(), 0) + 0 + """ + if pol not in self._drinfeld_module.function_ring(): + raise TypeError('first input must be in the function ring') + if x not in self._base: + raise TypeError('second input must be in the field acted upon') + return self._drinfeld_module(pol)(x) + + def _latex_(self): + r""" + Return a LaTeX representation of the action. + + OUTPUT: a string + + EXAMPLES:: + + sage: Fq.<z2> = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z, 0, 0, 1]) + sage: action = phi.action() + sage: latex(action) + \text{Action{ }on{ }}\Bold{F}_{11^{2}}\text{{ }induced{ }by{ }}\phi: T \mapsto t^{3} + z + """ + return f'\\text{{Action{{ }}on{{ }}}}' \ + f'{latex(self._base)}\\text{{{{ }}' \ + f'induced{{ }}by{{ }}}}{latex(self._drinfeld_module)}' + + def _repr_(self): + r""" + Return a string representation of the action. + + OUTPUT: a string + + EXAMPLES:: + + sage: Fq.<z2> = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z, 0, 0, 1]) + sage: action = phi.action() + sage: action + Action on Finite Field in z of size 11^2 over its base induced by Drinfeld module defined by T |--> t^3 + z + """ + return f'Action on {self._base} induced by ' \ + f'{self._drinfeld_module}' + + def drinfeld_module(self): + r""" + Return the Drinfeld module defining the action. + + OUTPUT: a Drinfeld module + + EXAMPLES:: + + sage: Fq.<z2> = GF(11) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z, 0, 0, 1]) + sage: action = phi.action() + sage: action.drinfeld_module() is phi + True + """ + return self._drinfeld_module diff --git a/src/sage/game_theory/__init__.py b/src/sage/rings/function_field/drinfeld_modules/all.py similarity index 100% rename from src/sage/game_theory/__init__.py rename to src/sage/rings/function_field/drinfeld_modules/all.py diff --git a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py new file mode 100644 index 00000000000..74ef125fb6a --- /dev/null +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -0,0 +1,2404 @@ +# sage.doctest: optional - sage.rings.finite_rings +r""" +Drinfeld modules + +This module provides the class +:class:`sage.rings.function_field.drinfeld_module.drinfeld_module.DrinfeldModule`. + +For finite Drinfeld modules and their theory of complex multiplication, see +class +:class:`sage.rings.function_field.drinfeld_module.finite_drinfeld_module.DrinfeldModule`. + +AUTHORS: + +- Antoine Leudiรจre (2022-04): initial version +- Xavier Caruso (2022-06): initial version +- David Ayotte (2023-03): added basic `j`-invariants +""" + +# ***************************************************************************** +# Copyright (C) 2022 Antoine Leudiรจre <antoine.leudiere@inria.fr> +# +# 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. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.arith.misc import gcd +from sage.categories.drinfeld_modules import DrinfeldModules +from sage.categories.homset import Hom +from sage.geometry.polyhedron.constructor import Polyhedron +from sage.misc.cachefunc import cached_method +from sage.misc.latex import latex +from sage.misc.latex import latex_variable_name +from sage.misc.lazy_import import lazy_import +from sage.misc.lazy_string import _LazyString +from sage.misc.misc_c import prod +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.ore_polynomial_element import OrePolynomial +from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.structure.parent import Parent +from sage.structure.sage_object import SageObject +from sage.structure.sequence import Sequence +from sage.structure.unique_representation import UniqueRepresentation + +lazy_import('sage.rings.ring_extension', 'RingExtension_generic') +lazy_import('sage.rings.lazy_series_ring', 'LazyPowerSeriesRing') + + +class DrinfeldModule(Parent, UniqueRepresentation): + r""" + This class implements Drinfeld `\mathbb{F}_q[T]`-modules. + + Let `\mathbb{F}_q[T]` be a polynomial ring with coefficients in a + finite field `\mathbb{F}_q` and let `K` be a field. Fix a ring + morphism `\gamma: \mathbb{F}_q[T] \to K`; we say that `K` is an + `\mathbb{F}_q[T]`-*field*. Let `K\{\tau\}` be the ring of Ore + polynomials with coefficients in `K`, whose multiplication is given + by the rule `\tau \lambda = \lambda^q \tau` for any `\lambda \in K`. + + A Drinfeld `\mathbb{F}_q[T]`-module over the base + `\mathbb{F}_q[T]`-field `K` is an `\mathbb{F}_q`-algebra morphism + `\phi: \mathbb{F}_q[T] \to K\{\tau\}` such that `\mathrm{Im}(\phi) + \not\subset K` and `\phi` agrees with `\gamma` on `\mathbb{F}_q`. + + For `a` in `\mathbb{F}_q[T]`, `\phi(a)` is denoted `\phi_a`. + + The Drinfeld `\mathbb{F}_q[T]`-module `\phi` is uniquely determined + by the image `\phi_T` of `T`; this serves as input of the class. + + .. NOTE:: + + See also :class:`sage.categories.drinfeld_modules`. + + The *base morphism* is the morphism `\gamma: \mathbb{F}_q[T] \to K`. + The monic polynomial that generates the kernel of `\gamma` is called + the `\mathbb{F}_q[T]`-*characteristic*, or *function-field + characteristic*, of the base field. We say that `\mathbb{F}_q[T]` is + the *function ring* of `\phi`; `K\{\tau\}` is the *Ore polynomial + ring*. Further, the *generator* is `\phi_T` and the *constant + coefficient* is the constant coefficient of `\phi_T`. + + A Drinfeld module is said to be *finite* if the field `K` is. + Despite an emphasis on this case, the base field can be any + extension of `\mathbb{F}_q`:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z, 4, 1]) + sage: phi + Drinfeld module defined by T |--> t^2 + 4*t + z + + :: + + sage: Fq = GF(49) + sage: A.<T> = Fq[] + sage: K = Frac(A) + sage: psi = DrinfeldModule(A, [K(T), T+1]) + sage: psi + Drinfeld module defined by T |--> (T + 1)*t + T + + .. NOTE:: + + Finite Drinfeld modules are implemented in the class + :class:`sage.rings.function_field.drinfeld_modules.finite_drinfeld_module`. + + Classical references on Drinfeld modules include [Gos1998]_, + [Rosen2002]_, [VS06]_ and [Gek1991]_. + + .. NOTE:: + + Drinfeld modules are defined in a larger setting, in which the + polynomial ring `\mathbb{F}_q[T]` is replaced by a more general + function ring: the ring of functions in `k` that are regular + outside `\infty`, where `k` is a function field over + `\mathbb{F}_q` with transcendence degree `1` and `\infty` is a + fixed place of `k`. This is out of the scope of this + implementation. + + INPUT: + + - ``function_ring`` -- a univariate polynomial ring whose base field + is a finite field + + - ``gen`` -- the generator of the Drinfeld module; as a list of + coefficients or an Ore polynomial + + - ``name`` (default: ``'t'``) -- the name of the Ore polynomial ring + generator + + .. RUBRIC:: Construction + + A Drinfeld module object is constructed by giving the function ring + and the generator:: + + sage: Fq.<z2> = GF(3^2) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z, 1, 1]) + sage: phi + Drinfeld module defined by T |--> t^2 + t + z + + .. NOTE:: + + Note that the definition of the base field is implicit; it is + automatically defined as the compositum of all the parents of + the coefficients. + + The above Drinfeld module is finite; it can also be infinite:: + + sage: L = Frac(A) + sage: psi = DrinfeldModule(A, [L(T), 1, T^3 + T + 1]) + sage: psi + Drinfeld module defined by T |--> (T^3 + T + 1)*t^2 + t + T + + :: + + sage: phi.is_finite() + True + sage: psi.is_finite() + False + + In those examples, we used a list of coefficients (``[z, 1, 1]``) to + represent the generator `\phi_T = z + t + t^2`. One can also use + regular Ore polynomials:: + + sage: ore_polring = phi.ore_polring() + sage: t = ore_polring.gen() + sage: rho_T = z + t^3 + sage: rho = DrinfeldModule(A, rho_T) + sage: rho + Drinfeld module defined by T |--> t^3 + z + sage: rho(T) == rho_T + True + + Images under the Drinfeld module are computed by calling the + object:: + + sage: phi(T) # phi_T, the generator of the Drinfeld module + t^2 + t + z + sage: phi(T^3 + T + 1) # phi_(T^3 + T + 1) + t^6 + (z^11 + z^9 + 2*z^6 + 2*z^4 + 2*z + 1)*t^4 + + (2*z^11 + 2*z^10 + z^9 + z^8 + 2*z^7 + 2*z^6 + z^5 + 2*z^3)*t^3 + + (2*z^11 + z^10 + z^9 + 2*z^7 + 2*z^6 + z^5 + z^4 + 2*z^3 + 2*z + 2)*t^2 + + (2*z^11 + 2*z^8 + 2*z^6 + z^5 + z^4 + 2*z^2)*t + z^3 + z + 1 + sage: phi(1) # phi_1 + 1 + + .. RUBRIC:: The category of Drinfeld modules + + Drinfeld modules have their own category (see class + :class:`sage.categories.drinfeld_modules.DrinfeldModules`):: + + sage: phi.category() + Category of Drinfeld modules over Finite Field in z of size 3^12 over its base + sage: phi.category() is psi.category() + False + sage: phi.category() is rho.category() + True + + One can use the category to directly create new objects:: + + sage: cat = phi.category() + sage: cat.object([z, 0, 0, 1]) + Drinfeld module defined by T |--> t^3 + z + + .. RUBRIC:: The base field of a Drinfeld module + + The base field of the Drinfeld module is retrieved using + :meth:`base`:: + + sage: phi.base() + Finite Field in z of size 3^12 over its base + + The base morphism is retrieved using :meth:`base_morphism`:: + + sage: phi.base_morphism() + Ring morphism: + From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 + To: Finite Field in z of size 3^12 over its base + Defn: T |--> z + + Note that the base field is *not* the field `K`. Rather, it is a + ring extension + (see :class:`sage.rings.ring_extension.RingExtension`) whose + underlying ring is `K` and whose base is the base morphism:: + + sage: phi.base() is K + False + + .. RUBRIC:: Getters + + One can retrieve basic properties:: + + sage: phi.base_morphism() + Ring morphism: + From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 + To: Finite Field in z of size 3^12 over its base + Defn: T |--> z + + :: + + sage: phi.ore_polring() # K{t} + Ore Polynomial Ring in t over Finite Field in z of size 3^12 over its base + twisted by Frob^2 + + :: + + sage: phi.function_ring() # Fq[T] + Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 + + :: + + sage: phi.gen() # phi_T + t^2 + t + z + sage: phi.gen() == phi(T) + True + + :: + + sage: phi.constant_coefficient() # Constant coefficient of phi_T + z + + :: + + sage: phi.morphism() # The Drinfeld module as a morphism + Ring morphism: + From: Univariate Polynomial Ring in T over Finite Field in z2 of size 3^2 + To: Ore Polynomial Ring in t + over Finite Field in z of size 3^12 over its base + twisted by Frob^2 + Defn: T |--> t^2 + t + z + + One can compute the rank and height:: + + sage: phi.rank() + 2 + sage: phi.height() + 1 + + As well as the j-invariant:: + + sage: phi.j_invariant() # j-invariant + 1 + + A Drinfeld `\mathbb{F}_q[T]`-module can be seen as an Ore polynomial + with positive degree and constant coefficient `\gamma(T)`, where + `\gamma` is the base morphism. This analogy is the motivation for + the following methods:: + + sage: phi.coefficients() + [z, 1, 1] + + :: + + sage: phi.coefficient(1) + 1 + + + .. RUBRIC:: Morphisms and isogenies + + A *morphism* of Drinfeld modules `\phi \to \psi` is an Ore + polynomial `f \in K\{\tau\}` such that `f \phi_a = \psi_a f` for + every `a` in the function ring. In our case, this is equivalent to + `f \phi_T = \psi_T f`. An *isogeny* is a nonzero morphism. + + Use the ``in`` syntax to test if an Ore polynomial defines a + morphism:: + + sage: phi(T) in Hom(phi, phi) + True + sage: t^6 in Hom(phi, phi) + True + sage: t^5 + 2*t^3 + 1 in Hom(phi, phi) + False + sage: 1 in Hom(phi, rho) + False + sage: 1 in Hom(phi, phi) + True + sage: 0 in Hom(phi, rho) + True + + To create a SageMath object representing the morphism, call the + homset (``hom``):: + + sage: hom = Hom(phi, phi) + sage: frobenius_endomorphism = hom(t^6) + sage: identity_morphism = hom(1) + sage: zero_morphism = hom(0) + sage: frobenius_endomorphism + Endomorphism of Drinfeld module defined by T |--> t^2 + t + z + Defn: t^6 + sage: identity_morphism + Identity morphism of Drinfeld module defined by T |--> t^2 + t + z + sage: zero_morphism + Endomorphism of Drinfeld module defined by T |--> t^2 + t + z + Defn: 0 + + The underlying Ore polynomial is retrieved with the method + :meth:`ore_polynomial`:: + + sage: frobenius_endomorphism.ore_polynomial() + t^6 + sage: identity_morphism.ore_polynomial() + 1 + + One checks if a morphism is an isogeny, endomorphism or + isomorphism:: + + sage: frobenius_endomorphism.is_isogeny() + True + sage: identity_morphism.is_isogeny() + True + sage: zero_morphism.is_isogeny() + False + sage: frobenius_endomorphism.is_isomorphism() + False + sage: identity_morphism.is_isomorphism() + True + sage: zero_morphism.is_isomorphism() + False + + .. RUBRIC:: The Vรฉlu formula + + Let ``P`` be a nonzero Ore polynomial. We can decide if ``P`` + defines an isogeny with a given domain and, if it does, find + the codomain:: + + sage: P = (2*z^6 + z^3 + 2*z^2 + z + 2)*t + z^11 + 2*z^10 + 2*z^9 + 2*z^8 + z^7 + 2*z^6 + z^5 + z^3 + z^2 + z + sage: psi = phi.velu(P) + sage: psi + Drinfeld module defined by T |--> (2*z^11 + 2*z^9 + z^6 + 2*z^5 + 2*z^4 + 2*z^2 + 1)*t^2 + + (2*z^11 + 2*z^10 + 2*z^9 + z^8 + 2*z^7 + 2*z^6 + z^5 + 2*z^4 + 2*z^2 + 2*z)*t + z + sage: P in Hom(phi, psi) + True + sage: P * phi(T) == psi(T) * P + True + + If the input does not define an isogeny, an exception is raised:: + + sage: phi.velu(0) + Traceback (most recent call last): + ... + ValueError: the input does not define an isogeny + sage: phi.velu(t) + Traceback (most recent call last): + ... + ValueError: the input does not define an isogeny + + .. RUBRIC:: The action of a Drinfeld module + + The `\mathbb{F}_q[T]`-Drinfeld module `\phi` induces a special left + `\mathbb{F}_q[T]`-module structure on any field extension `L/K`. Let + `x \in L` and `a` be in the function ring; the action is defined as + `(a, x) \mapsto \phi_a(x)`. The method :meth:`action` returns a + :class:`sage.rings.function_field.drinfeld_modules.action.Action` + object representing the Drinfeld module action. + + .. NOTE:: + + In this implementation, `L` is `K`:: + + sage: action = phi.action() + sage: action + Action on Finite Field in z of size 3^12 over its base + induced by Drinfeld module defined by T |--> t^2 + t + z + + The action on elements is computed by calling the action object:: + + sage: P = T + 1 + sage: a = z + sage: action(P, a) + ... + z^9 + 2*z^8 + 2*z^7 + 2*z^6 + 2*z^3 + z^2 + sage: action(0, K.random_element()) + 0 + sage: action(A.random_element(), 0) + 0 + + .. WARNING:: + + The class ``DrinfeldModuleAction`` may be replaced later on. See + issues #34833 and #34834. + + TESTS: + + The generator must have positive degree:: + + sage: Fq = GF(2) + sage: K.<z> = Fq.extension(2) + sage: A.<T> = Fq[] + sage: DrinfeldModule(A, [K(1)]) + Traceback (most recent call last): + ... + ValueError: generator must have positive degree + + The constant coefficient must be nonzero:: + + sage: Fq = GF(2) + sage: K.<z> = Fq.extension(2) + sage: A.<T> = Fq[] + sage: DrinfeldModule(A, [K(0), K(1)]) + Traceback (most recent call last): + ... + ValueError: constant coefficient must be nonzero + + The coefficients of the generator must lie in an + `\mathbb{F}_q[T]`-field, where `\mathbb{F}_q[T]` is the function + ring of the Drinfeld module:: + + sage: Fq = GF(2) + sage: K.<z> = Fq.extension(2) + sage: A.<T> = Fq[] + sage: DrinfeldModule(A, [z, QQ(1)]) + Traceback (most recent call last): + ... + ValueError: function ring base must coerce into base field + + :: + + sage: Fq = GF(2) + sage: K.<z> = Fq.extension(2) + sage: A.<T> = Fq[] + sage: DrinfeldModule(A, [1, QQ(1)]) + Traceback (most recent call last): + ... + ValueError: function ring base must coerce into base field + + The function ring must be an univariate polynomial ring whose + base is a finite field:: + + sage: Fq = GF(2) + sage: K.<z> = Fq.extension(2) + sage: A.<T> = Fq[] + sage: DrinfeldModule(K, [z, 1, 1]) + Traceback (most recent call last): + ... + NotImplementedError: function ring must be a polynomial ring + + :: + + sage: Fq = GF(2) + sage: K.<z> = Fq.extension(2) + sage: A.<T> = Fq[] + sage: AY.<Y> = A[] + sage: DrinfeldModule(AY, [z, 1, 1]) + Traceback (most recent call last): + ... + TypeError: function ring base must be a finite field + + If you already defined a category of Drinfeld modules, and you + create a Drinfeld module through this category, you must ensure that + the constant coefficient is that of the category:: + + sage: Fq = GF(2) + sage: K.<z> = Fq.extension(2) + sage: A.<T> = Fq[] + sage: phi = DrinfeldModule(A, [z, 1]) + sage: phi.category().object([1, 1, K(1)]) + Traceback (most recent call last): + ... + ValueError: constant coefficient must equal that of the category + + :: + + sage: Fq = K = GF(2) + sage: A.<T> = Fq[] + sage: phi = DrinfeldModule(A, [1, 1]) + Traceback (most recent call last): + ... + ValueError: function ring base must coerce into base field + + :: + + sage: Fq = K = GF(2) + sage: A.<T> = Fq[] + sage: phi = DrinfeldModule(A, [K(1), 1]) + sage: isinstance(phi.ore_polring(), OrePolynomialRing) + True + """ + + @staticmethod + def __classcall_private__(cls, function_ring, gen, name='t'): + """ + Check input validity and return a ``DrinfeldModule`` or + ``FiniteDrinfeldModule`` object accordingly. + + INPUT: + + - ``function_ring`` -- a univariate polynomial ring whose base + is a finite field + + - ``gen`` -- the generator of the Drinfeld module; as a list of + coefficients or an Ore polynomial + + - ``name`` (default: ``'t'``) -- the name of the Ore polynomial + ring gen + + OUTPUT: + + A DrinfeldModule or FiniteDrinfeldModule. + + TESTS:: + + sage: from sage.rings.function_field.drinfeld_modules.finite_drinfeld_module import FiniteDrinfeldModule + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: isinstance(phi, FiniteDrinfeldModule) + True + + :: + + sage: K = Frac(A) + sage: phi = DrinfeldModule(A, [K(T), 1]) + sage: isinstance(psi, FiniteDrinfeldModule) + False + """ + + # FIXME: function_ring must be checked before calling base_ring + # on it. But then it is checked twice: firstly here, secondly in + # the category. Another problem is that those lines are + # duplicate. As a general comment, there are sanity checks both + # here and in the category constructor, which is not ideal. + # Check domain is Fq[T] + if not isinstance(function_ring, PolynomialRing_general): + raise NotImplementedError('function ring must be a polynomial ' + 'ring') + function_ring_base = function_ring.base_ring() + if not function_ring_base.is_field() \ + or not function_ring_base.is_finite(): + raise TypeError('function ring base must be a finite field') + + # Check all possible input types for gen + # `gen` is an Ore polynomial: + if isinstance(gen, OrePolynomial): + ore_polring = gen.parent() + # Base ring without morphism structure: + base_field_noext = ore_polring.base() + name = ore_polring.variable_name() + # `gen` is a list of coefficients (function_ring = Fq[T]): + elif isinstance(gen, (list, tuple)): + ore_polring = None + # Base ring without morphism structure: + base_field_noext = Sequence(gen).universe() + else: + raise TypeError('generator must be list of coefficients or Ore ' + 'polynomial') + # Constant coefficient must be nonzero: + if gen[0].is_zero(): + raise ValueError('constant coefficient must be nonzero') + # The coefficients are in a base field that has coercion from Fq: + if not (hasattr(base_field_noext, 'has_coerce_map_from') and + base_field_noext.has_coerce_map_from(function_ring.base_ring())): + raise ValueError('function ring base must coerce into base field') + + # Build the category + T = function_ring.gen() + if isinstance(base_field_noext, RingExtension_generic): + base_field = base_field_noext + elif base_field_noext.has_coerce_map_from(function_ring) \ + and T == gen[0]: + base_morphism = base_field_noext.coerce_map_from(function_ring) + base_field = base_field_noext.over(base_morphism) + else: + base_morphism = Hom(function_ring, base_field_noext)(gen[0]) + base_field = base_field_noext.over(base_morphism) + + # This test is also done in the category. We put it here also + # to have a friendlier error message + if not base_field.is_field(): + raise ValueError('generator coefficients must live in a field') + + category = DrinfeldModules(base_field, name=name) + + # Check gen as Ore polynomial + ore_polring = category.ore_polring() # Sanity cast + gen = ore_polring(gen) + if gen.degree() <= 0: + raise ValueError('generator must have positive degree') + + # Instantiate the appropriate class + if base_field.is_finite(): + from sage.rings.function_field.drinfeld_modules.finite_drinfeld_module import FiniteDrinfeldModule + return FiniteDrinfeldModule(gen, category) + return cls.__classcall__(cls, gen, category) + + def __init__(self, gen, category): + """ + Initialize ``self``. + + Validity of the input is checked in meth:`__classcall_private__`. + The meth:`__init__` just saves attributes. + + INPUT: + + - ``function_ring`` -- a univariate polynomial ring whose base + is a finite field + + - ``gen`` -- the generator of the Drinfeld module; as a list of + coefficients or an Ore polynomial + + - ``name`` (default: ``'t'``) -- the name of the Ore polynomial + ring gen + + TESTS:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: gen = [p_root, z12^3, z12^5] + sage: phi = DrinfeldModule(A, gen) + sage: ore_polring = phi.ore_polring() + sage: phi._base == phi.category().base() + True + sage: phi._function_ring == A + True + sage: phi._gen == ore_polring(gen) + True + sage: phi._ore_polring == ore_polring + True + sage: phi._morphism == Hom(A, ore_polring)(phi._gen) + True + + :: + + sage: TestSuite(phi).run() + """ + self._base = category.base() + self._function_ring = category.function_ring() + self._gen = gen + self._morphism = category._function_ring.hom([gen]) + self._ore_polring = gen.parent() + self._Fq = self._function_ring.base_ring() # Must be last + super().__init__(base=self._base, category=category) + + def __call__(self, a): + r""" + Return the image of input ``a`` by the morphism that defines the + Drinfeld module; i.e. `\phi_a` if the Drinfeld module is denoted + `phi`. + + INPUT: + + - ``a`` -- a function ring element + + OUTPUT: an element in the base codomain + + TESTS:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + + :: + sage: a = T^3 + 4*T + 2 + sage: phi(a) == phi(T)^3 + 4*phi(T) + 2 + True + sage: phi(a)[0] == p_root^3 + 4*p_root + 2 + True + + :: + + sage: phi(0) + 0 + sage: phi(1) + 1 + sage: phi(T) == phi._gen + True + + :: + + sage: a = A.random_element(5) + sage: phi(a)[0] == phi.category().base()(a) + True + """ + return self._morphism(a) + + def _Hom_(self, other, category): + r""" + Return the set of morphisms from ``self`` to ``other``. + + Validity of the input is checked at the instantiation of + ``DrinfeldModuleHomset``; ``self`` and ``other`` only need be in + the same category. + + INPUT: + + - ``other`` -- the codomain of the homset + + - ``category`` -- the category in which we consider the + morphisms, usually ``self.category()`` + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: t = phi.ore_polring().gen() + sage: isog = t + 2*z12^11 + 4*z12^9 + 2*z12^8 + 2*z12^6 + 3*z12^5 + z12^4 + 2*z12^3 + 4*z12^2 + 4*z12 + 4 + sage: psi = phi.velu(isog) + sage: hom = phi._Hom_(psi, category=phi.category()) + sage: hom is Hom(phi, psi) # known bug + True + sage: from sage.rings.function_field.drinfeld_modules.homset import DrinfeldModuleHomset + sage: isinstance(hom, DrinfeldModuleHomset) + True + """ + from sage.rings.function_field.drinfeld_modules.homset import DrinfeldModuleHomset + return DrinfeldModuleHomset(self, other, category) + + def _check_rank_two(self): + r""" + Raise ``NotImplementedError`` if the rank is not two. + + TESTS:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi._check_rank_two() + sage: phi = DrinfeldModule(A, [p_root, 1]) + sage: phi._check_rank_two() + Traceback (most recent call last): + ... + NotImplementedError: rank must be 2 + """ + if self.rank() != 2: + raise NotImplementedError('rank must be 2') + + def _latex_(self): + r""" + Return a LaTeX representation of the Drinfeld module. + + If a representation name is given with meth:`rename`, it is + taken into account for LaTeX representation. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: latex(phi) + \phi: T \mapsto z_{12}^{5} t^{2} + z_{12}^{3} t + 2 z_{12}^{11} + 2 z_{12}^{10} + z_{12}^{9} + 3 z_{12}^{8} + z_{12}^{7} + 2 z_{12}^{5} + 2 z_{12}^{4} + 3 z_{12}^{3} + z_{12}^{2} + 2 z_{12} + + :: + + sage: phi.rename('phi') + sage: latex(phi) + \phi + sage: phi.reset_name() + """ + if self.get_custom_name() is not None: + return latex_variable_name(self.get_custom_name()) + else: + return f'\\phi: {latex(self._function_ring.gen())} \\mapsto ' \ + f'{latex(self._gen)}' + + def _repr_(self): + r""" + Return a string representation of this Drinfeld module. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi + Drinfeld module defined by T |--> z12^5*t^2 + z12^3*t + 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + """ + return f'Drinfeld module defined by {self._function_ring.gen()} ' \ + f'|--> {self._gen}' + + def _test_category(self, **options): + """ + Run generic tests on the method :meth:`.category`. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi._test_category() + + .. NOTE:: + + We reimplemented this method because Drinfeld modules are + parents, and + meth:`sage.structure.parent.Parent._test_category` requires + parents' categories to be subcategories of ``Sets()``. + """ + tester = self._tester(**options) + SageObject._test_category(self, tester=tester) + category = self.category() + # Tests that self inherits methods from the categories + tester.assertTrue(isinstance(self, category.parent_class), + _LazyString("category of %s improperly initialized", (self,), {})) + + def __hash__(self): + r""" + Return a hash of ``self``. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: hash(phi) # random + -6894299335185957188 + """ + return hash((self.base(), self._gen)) + + def action(self): + r""" + Return the action object + (:class:`sage.rings.function_field.drinfeld_modules.action.Action`) + that represents the module action, on the base codomain, that is + induced by the Drinfeld module. + + OUTPUT: a Drinfeld module action object + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: action = phi.action() + sage: action + Action on Finite Field in z12 of size 5^12 over its base + induced by Drinfeld module defined by T |--> z12^5*t^2 + z12^3*t + 2*z12^11 + + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + + The action on elements is computed as follows:: + + sage: P = T^2 + T + 1 + sage: a = z12 + 1 + sage: action(P, a) + 3*z12^11 + 2*z12^10 + 3*z12^9 + 3*z12^7 + 4*z12^5 + z12^4 + z12^3 + 2*z12 + 1 + sage: action(0, a) + 0 + sage: action(P, 0) + 0 + """ + from sage.rings.function_field.drinfeld_modules.action import DrinfeldModuleAction + return DrinfeldModuleAction(self) + + def basic_j_invariant_parameters(self, coeff_indices=None, nonzero=False): + r""" + Return the list of basic `j`-invariant parameters. + + See the method :meth:`j_invariant` for definitions. + + INPUT: + + - ``coeff_indices`` (list or tuple, or NoneType; default: + ``None``) -- indices of the Drinfeld module generator + coefficients to be considered in the computation. If the + parameter is ``None`` (default), all the coefficients are + involved. + + - ``nonzero`` (boolean, default: ``False``) -- if this flag + is set to ``True``, then only the parameters for which the + corresponding basic `j`-invariant is nonzero are returned. + + .. WARNING:: + + The usage of this method can be computationally + expensive e.g. if the rank is greater than four, + or if `q` is large. Setting the ``nonzero`` flag to ``True`` + can speed up the computation considerably if the Drinfeld + module generator possesses multiple zero coefficients. + + EXAMPLES:: + + sage: A = GF(5)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, 0, T+1, T^2 + 1]) + sage: phi.basic_j_invariant_parameters() + [((1,), (31, 1)), + ((1, 2), (1, 5, 1)), + ((1, 2), (7, 4, 1)), + ((1, 2), (8, 9, 2)), + ((1, 2), (9, 14, 3)), + ((1, 2), (10, 19, 4)), + ((1, 2), (11, 24, 5)), + ((1, 2), (12, 29, 6)), + ((1, 2), (13, 3, 1)), + ((1, 2), (15, 13, 3)), + ((1, 2), (17, 23, 5)), + ((1, 2), (19, 2, 1)), + ((1, 2), (20, 7, 2)), + ((1, 2), (22, 17, 4)), + ((1, 2), (23, 22, 5)), + ((1, 2), (25, 1, 1)), + ((1, 2), (27, 11, 3)), + ((1, 2), (29, 21, 5)), + ((1, 2), (31, 31, 7)), + ((2,), (31, 6))] + + Use the ``nonzero=True`` flag to display only the parameters + whose `j`-invariant value is nonzero:: + + sage: phi.basic_j_invariant_parameters(nonzero=True) + [((2,), (31, 6))] + + + One can specify the list of coefficients indices to be + considered in the computation:: + + sage: A = GF(2)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, T, 1, T]) + sage: phi.basic_j_invariant_parameters([1, 2]) + [((1,), (7, 1)), + ((1, 2), (1, 2, 1)), + ((1, 2), (4, 1, 1)), + ((1, 2), (5, 3, 2)), + ((1, 2), (6, 5, 3)), + ((1, 2), (7, 7, 4)), + ((2,), (7, 3))] + + TESTS:: + + sage: A = GF(5)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, 0, T+1, T^2 + 1]) + sage: phi.basic_j_invariant_parameters([1, 'x']) + Traceback (most recent call last): + ... + TypeError: coefficients indices must be integers + + :: + + sage: phi.basic_j_invariant_parameters([1, 10]) + Traceback (most recent call last): + ... + ValueError: indices must be > 0 and < 3 + + :: + + sage: phi.basic_j_invariant_parameters([1, 1]) + Traceback (most recent call last): + ... + ValueError: indices must be distinct and sorted + + :: + + sage: phi.basic_j_invariant_parameters([2, 1]) + Traceback (most recent call last): + ... + ValueError: indices must be distinct and sorted + + :: + + sage: phi.basic_j_invariant_parameters('x') + Traceback (most recent call last): + ... + TypeError: indices must be None, a tuple or a list + """ + r = self._gen.degree() + if coeff_indices is None: + if nonzero: + coeff_indices = [k for k, g in enumerate( + self.coefficients(sparse=False)[1:-1], start=1) if g] + else: + coeff_indices = list(range(1, r)) + # Check if coeff_indices is valid: + elif isinstance(coeff_indices, (tuple, list)): + coeff_indices = list(coeff_indices) + if not all(isinstance(k, (int, Integer)) for k in coeff_indices): + raise TypeError('coefficients indices must be integers') + if max(coeff_indices) >= r or min(coeff_indices) <= 0: + raise ValueError(f'indices must be > 0 and < {r}') + if not all(coeff_indices[i] < coeff_indices[i+1] for i in + range(len(coeff_indices) - 1)): + raise ValueError('indices must be distinct and sorted') + if nonzero: + coeff_indices = [k for k in coeff_indices if self._gen[k]] + else: + raise TypeError('indices must be None, a tuple or a list') + # Create the equation and inequalities for the polyhedron: + q = self._Fq.order() + equation = [0] + inequalities = [] + # Create the equation: + # d_1 (q - 1) + ... + d_{r-1} (q^{r-1} - 1) + # = d_r (q^r - 1) + for idx, i in enumerate(coeff_indices): + equation.append(q**i - 1) + # Create inequalities of the form 0 <= delta_i + lower_bounds = [0] * (len(coeff_indices) + 2) + lower_bounds[idx + 1] = 1 + # Create inequalities of the form + # delta_i <= (q^r - 1)/(q^{gcd(i,r)} - 1) + upper_bounds = [Integer((q**r - 1) / (q**(gcd(i, r)) - 1))]\ + + [0]*(len(coeff_indices) + 1) + upper_bounds[idx + 1] = -1 + inequalities.extend((lower_bounds, upper_bounds)) + equation.append(1 - q**r) + # Create the polyhedron defined by the equation and the + # inequalities. + polyhedron = Polyhedron(ieqs=inequalities, eqns=[equation]) + # Compute its integral points + integral_points = polyhedron.integral_points() + # Format the result + parameters = [] + for p in integral_points: + if gcd(p) != 1: + continue + ks = list(coeff_indices) + ds = p.list() + i = 0 + while i < len(ks): + if ds[i] == 0: + del ds[i] + del ks[i] + else: + i += 1 + parameters.append((tuple(ks), tuple(ds))) + parameters.sort() + return parameters + + def basic_j_invariants(self, nonzero=False): + r""" + Return a dictionary whose keys are all the basic `j`-invariants + parameters and values are the corresponding `j`-invariant. + + See the method :meth:`j_invariant` for definitions. + + INPUT: + + - ``nonzero`` (boolean, default: ``False``) -- if this flag + is set to ``True``, then only the parameters for which the + corresponding basic `j`-invariant is nonzero are returned. + + .. WARNING:: + + The usage of this method can be computationally + expensive e.g. if the rank is greater than four, + or if `q` is large. Setting the ``nonzero`` flag to ``True`` + can speed up the computation considerably if the Drinfeld + module generator possesses multiple zero coefficients. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.basic_j_invariants() + {((1,), (26, 1)): z12^10 + 4*z12^9 + 3*z12^8 + 2*z12^7 + 3*z12^6 + z12^5 + z12^3 + 4*z12^2 + z12 + 2} + + :: + + sage: phi = DrinfeldModule(A, [p_root, 0, 1, z12]) + sage: phi.basic_j_invariants(nonzero=True) + {((2,), (651, 26)): z12^11 + 3*z12^10 + 4*z12^9 + 3*z12^8 + z12^7 + 2*z12^6 + 3*z12^4 + 2*z12^3 + z12^2 + 4*z12} + + :: + + sage: A = GF(5)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, T + 2, T+1, 1]) + sage: J_phi = phi.basic_j_invariants(); J_phi + {((1,), (31, 1)): T^31 + 2*T^30 + 2*T^26 + 4*T^25 + 2*T^6 + 4*T^5 + 4*T + 3, + ((1, 2), (1, 5, 1)): T^6 + 2*T^5 + T + 2, + ((1, 2), (7, 4, 1)): T^11 + 3*T^10 + T^9 + 4*T^8 + T^7 + 2*T^6 + 2*T^4 + 3*T^3 + 2*T^2 + 3, + ((1, 2), (8, 9, 2)): T^17 + 2*T^15 + T^14 + 4*T^13 + 4*T^11 + 4*T^10 + 3*T^9 + 2*T^8 + 3*T^7 + 2*T^6 + 3*T^5 + 2*T^4 + 3*T^3 + 4*T^2 + 3*T + 1, + ((1, 2), (9, 14, 3)): T^23 + 2*T^22 + 2*T^21 + T^19 + 4*T^18 + T^17 + 4*T^16 + T^15 + 4*T^14 + 2*T^12 + 4*T^11 + 4*T^10 + 2*T^8 + 4*T^7 + 4*T^6 + 2*T^4 + T^2 + 2*T + 2, + ((1, 2), (10, 19, 4)): T^29 + 4*T^28 + T^27 + 4*T^26 + T^25 + 2*T^24 + 3*T^23 + 2*T^22 + 3*T^21 + 2*T^20 + 4*T^19 + T^18 + 4*T^17 + T^16 + 4*T^15 + T^9 + 4*T^8 + T^7 + 4*T^6 + T^5 + 4*T^4 + T^3 + 4*T^2 + T + 4, + ... + ((2,), (31, 6)): T^31 + T^30 + T^26 + T^25 + T^6 + T^5 + T + 1} + sage: J_phi[((1, 2), (7, 4, 1))] + T^11 + 3*T^10 + T^9 + 4*T^8 + T^7 + 2*T^6 + 2*T^4 + 3*T^3 + 2*T^2 + 3 + """ + return {parameter: self.j_invariant(parameter, check=False) + for parameter in self.basic_j_invariant_parameters(nonzero=nonzero)} + + def coefficient(self, n): + r""" + Return the `n`-th coefficient of the generator. + + INPUT: + + - ``n`` -- a nonnegative integer + + OUTPUT: an element in the base codomain + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.coefficient(0) + 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi.coefficient(0) == p_root + True + sage: phi.coefficient(1) + z12^3 + sage: phi.coefficient(2) + z12^5 + sage: phi.coefficient(5) + Traceback (most recent call last): + ... + ValueError: input must be >= 0 and <= rank + """ + n = Integer(n) + if not 0 <= n <= self.rank(): + raise ValueError('input must be >= 0 and <= rank') + return self.coefficients(sparse=False)[n] + + def coefficients(self, sparse=True): + r""" + Return the coefficients of the generator, as a list. + + If the flag ``sparse`` is ``True`` (default), only return the + nonzero coefficients; otherwise, return all of them. + + INPUT: + + - ``sparse`` -- a boolean + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.coefficients() + [2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12, + z12^3, + z12^5] + + Careful, the method only returns the nonzero coefficients, + unless otherwise specified:: + + sage: rho = DrinfeldModule(A, [p_root, 0, 0, 0, 1]) + sage: rho.coefficients() + [2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12, + 1] + sage: rho.coefficients(sparse=False) + [2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12, + 0, + 0, + 0, + 1] + """ + return self._gen.coefficients(sparse=sparse) + + @cached_method + def _compute_coefficient_exp(self, k): + r""" + Return the `q^k`-th coefficient of the exponential of this Drinfeld module. + + INPUT: + + - ``k`` (integer) -- the index of the coefficient + + TESTS:: + + sage: A = GF(2)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: q = A.base_ring().cardinality() + sage: phi._compute_coefficient_exp(0) + 1 + sage: phi._compute_coefficient_exp(1) + 1/(T^2 + T) + sage: phi._compute_coefficient_exp(2) + 1/(T^8 + T^6 + T^5 + T^3) + sage: phi._compute_coefficient_exp(3) + 1/(T^24 + T^20 + T^18 + T^17 + T^14 + T^13 + T^11 + T^7) + """ + k = ZZ(k) + if k.is_zero(): + return self._base.one() + q = self._Fq.cardinality() + c = self._base.zero() + for i in range(k): + j = k - i + c += self._compute_coefficient_exp(i)*self._compute_coefficient_log(j)**(q**i) + return -c + + def exponential(self, name='z'): + r""" + Return the exponential of this Drinfeld module. + + Note that the exponential is only defined when the + `\mathbb{F}_q[T]`-characteristic is zero. + + INPUT: + + - ``name`` (string, default: ``'z'``) -- the name of the + generator of the lazy power series ring. + + OUTPUT: + + A lazy power series over the base field. + + EXAMPLES:: + + sage: A = GF(2)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: q = A.base_ring().cardinality() + sage: exp = phi.exponential(); exp + z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8) + + The exponential is returned as a lazy power series, meaning that + any of its coefficients can be computed on demands:: + + sage: exp[2^4] + 1/(T^64 + T^56 + T^52 + ... + T^27 + T^23 + T^15) + sage: exp[2^5] + 1/(T^160 + T^144 + T^136 + ... + T^55 + T^47 + T^31) + + Example in higher rank:: + + sage: A = GF(5)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, T^2, T + T^2 + T^4, 1]) + sage: exp = phi.exponential(); exp + z + ((T/(T^4+4))*z^5) + O(z^8) + + The exponential is the compositional inverse of the logarithm + (see :meth:`logarithm`):: + + sage: log = phi.logarithm(); log + z + ((4*T/(T^4+4))*z^5) + O(z^8) + sage: exp.compose(log) + z + O(z^8) + sage: log.compose(exp) + z + O(z^8) + + :: + + sage: Fq.<w> = GF(3) + sage: A = Fq['T'] + sage: phi = DrinfeldModule(A, [w, 1]) + sage: phi.exponential() + Traceback (most recent call last): + ... + ValueError: characteristic must be zero (=T + 2) + + TESTS:: + + sage: A = GF(2)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: exp = phi.exponential() + sage: exp[2] == 1/(T**q - T) # expected value + True + sage: exp[2^2] == 1/((T**(q**2) - T)*(T**q - T)**q) # expected value + True + sage: exp[2^3] == 1/((T**(q**3) - T)*(T**(q**2) - T)**q*(T**q - T)**(q**2)) # expected value + True + + REFERENCE: + + See section 4.6 of [Gos1998]_ for the definition of the + exponential. + """ + if self.category()._characteristic: + raise ValueError(f"characteristic must be zero (={self.characteristic()})") + L = LazyPowerSeriesRing(self._base, name) + zero = self._base.zero() + q = self._Fq.cardinality() + + def coeff_exp(k): + # Return the k-th coefficient of the exponential. + k = ZZ(k) + if k.is_power_of(q): + return self._compute_coefficient_exp(k.log(q)) + else: + return zero + return L(coeff_exp, valuation=1) + + def gen(self): + r""" + Return the generator of the Drinfeld module. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.gen() == phi(T) + True + """ + return self._gen + + @cached_method + def _compute_goss_polynomial(self, n, q, poly_ring, X): + r""" + Utility function for computing the n-th Goss polynomial. + + The user should not call this method directly, but + :meth:`goss_polynomial` instead. + + TESTS:: + + sage: A = GF(2^2)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, T+1, T^2, 1]) + sage: poly_ring = phi.base()['X'] + sage: X = poly_ring.gen() + sage: phi._compute_goss_polynomial(0, 2^2, poly_ring, X) + 0 + sage: phi._compute_goss_polynomial(3, 2^2, poly_ring, X) + X^3 + sage: phi._compute_goss_polynomial(4*3, 2^2, poly_ring, X) + X^12 + sage: phi._compute_goss_polynomial(9, 2^2, poly_ring, X) + X^9 + (1/(T^3 + T^2 + T))*X^6 + (1/(T^6 + T^4 + T^2))*X^3 + + """ + # Trivial cases + if n.is_zero(): + return poly_ring.zero() + if n <= q - 1: + return X**n + if n % q == 0: + return self.goss_polynomial(n // q)**q + # General case + pol = sum(self._compute_coefficient_exp(i+1) + *self._compute_goss_polynomial(n - q**(i+1), q, poly_ring, X) + for i in range(0, (n.log(q).n()).floor())) + return X*(self._compute_goss_polynomial(n - 1, q, poly_ring, X) + pol) + + def goss_polynomial(self, n, var='X'): + r""" + Return the `n`-th Goss polynomial of the Drinfeld module. + + Note that Goss polynomials are only defined for Drinfeld modules + of characteristic zero. + + INPUT: + + - ``n`` (integer) -- the index of the Goss polynomial + + - ``var`` (str, default: ``'X'``) -- the name of polynomial + variable. + + OUTPUT: + + - a univariate polynomial in ``var`` over the base `A`-field. + + EXAMPLES:: + + sage: A = GF(3)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) # Carlitz module + sage: phi.goss_polynomial(1) + X + sage: phi.goss_polynomial(2) + X^2 + sage: phi.goss_polynomial(4) + X^4 + (1/(T^3 + 2*T))*X^2 + sage: phi.goss_polynomial(5) + X^5 + (2/(T^3 + 2*T))*X^3 + sage: phi.goss_polynomial(10) + X^10 + (1/(T^3 + 2*T))*X^8 + (1/(T^6 + T^4 + T^2))*X^6 + (1/(T^9 + 2*T^3))*X^4 + (1/(T^18 + 2*T^12 + 2*T^10 + T^4))*X^2 + + TESTS:: + + sage: Fq.<z> = GF(25) + sage: A.<T> = Fq[] + sage: phi = DrinfeldModule(A, [z, 1]) + sage: phi.goss_polynomial(1) + Traceback (most recent call last): + ... + ValueError: characteristic must be zero (=T^2 + 4*T + 2) + + REFERENCE: + + Section 3 of [Gek1988]_ provides an exposition of Goss + polynomials. + """ + if self.category()._characteristic: + raise ValueError(f"characteristic must be zero (={self.characteristic()})") + n = ZZ(n) + K = self.base() + poly_ring = K[var] + X = poly_ring.gen() + q = self._Fq.cardinality() + return self._compute_goss_polynomial(n, q, poly_ring, X) + + def height(self): + r""" + Return the height of the Drinfeld module if the function field + characteristic is a prime ideal; raise ValueError otherwise. + + The height of a Drinfeld module is defined when the function + field characteristic is a prime ideal. In our case, this ideal + is even generated by a monic polynomial `\mathfrak{p}` in the + function field. Write `\phi_\mathfrak{p} = a_s \tau^s + \dots + + \tau^{r*\deg(\mathfrak{p})}`. The height of the Drinfeld module + is the well-defined positive integer `h = + \frac{s}{\deg(\mathfrak{p})}`. + + .. NOTE:: + + See [Gos1998]_, Definition 4.5.8 for the general definition. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.height() == 1 + True + sage: phi.is_ordinary() + True + + :: + + sage: Fq = GF(343) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [1, 0, z6]) + sage: phi.height() + 2 + sage: phi.is_supersingular() + True + + In characteristic zero, height is not defined:: + + sage: L = A.fraction_field() + sage: phi = DrinfeldModule(A, [L(T), L(1)]) + sage: phi.height() + Traceback (most recent call last): + ... + ValueError: height is only defined for prime function field characteristic + + TESTS: + + In the following case, sage is unable to determine the + characteristic; that is why an error is raised:: + + sage: B.<Y> = Fq[] + sage: L = Frac(B) + sage: phi = DrinfeldModule(A, [L(2), L(1)]) + sage: phi.height() + Traceback (most recent call last): + ... + NotImplementedError: height not implemented in this case + + """ + try: + if self.characteristic().is_zero(): + raise ValueError('height is only defined for prime ' + 'function field characteristic') + else: + p = self.characteristic() + return Integer(self(p).valuation() // p.degree()) + except NotImplementedError: + raise NotImplementedError('height not implemented in this case') + + def is_isomorphic(self, other, absolutely=False): + r""" + Return ``True`` if this Drinfeld module is isomorphic to ``other``; + return ``False`` otherwise. + + INPUT: + + - ``absolutely`` -- a boolean (default: ``False``); if ``True``, + check the existence of an isomorphism defined on the base + field; if ``False``, check over an algebraic closure. + + EXAMPLES:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 0, 1, z]) + sage: t = phi.ore_variable() + + We create a second Drinfeld module, which is isomorphic to `\phi` + and then check that they are indeed isomorphic:: + + sage: psi = phi.velu(z) + sage: phi.is_isomorphic(psi) + True + + In the example below, `\phi` and `\psi` are isogenous but not + isomorphic:: + + sage: psi = phi.velu(t + 1) + sage: phi.is_isomorphic(psi) + False + + Here is an example of two Drinfeld modules which are isomorphic + on an algebraic closure but not on the base field:: + + sage: phi = DrinfeldModule(A, [z, 1]) + sage: psi = DrinfeldModule(A, [z, z]) + sage: phi.is_isomorphic(psi) + False + sage: phi.is_isomorphic(psi, absolutely=True) + True + + On certain fields, testing isomorphisms over the base field may + fail:: + + sage: L = A.fraction_field() + sage: T = L.gen() + sage: phi = DrinfeldModule(A, [T, 0, 1]) + sage: psi = DrinfeldModule(A, [T, 0, T]) + sage: psi.is_isomorphic(phi) + Traceback (most recent call last): + ... + NotImplementedError: cannot solve the equation u^24 == T + + However, it never fails over the algebraic closure:: + + sage: psi.is_isomorphic(phi, absolutely=True) + True + + Note finally that when the constant coefficients of `\phi_T` and + `\psi_T` differ, `\phi` and `\psi` do not belong to the same category + and checking whether they are isomorphic does not make sense; in this + case, an error is raised:: + + sage: phi = DrinfeldModule(A, [z, 0, 1]) + sage: psi = DrinfeldModule(A, [z^2, 0, 1]) + sage: phi.is_isomorphic(psi) + Traceback (most recent call last): + ... + ValueError: Drinfeld modules are not in the same category + + TESTS: + + A Drinfeld module is always isomorphic to itself:: + + sage: phi = DrinfeldModule(A, [z] + [K.random_element() for _ in range(3)] + [1]) + sage: phi.is_isomorphic(phi) + True + + Two Drinfeld modules of different ranks are never isomorphic:: + + sage: psi = DrinfeldModule(A, [z] + [K.random_element() for _ in range(5)] + [1]) + sage: phi.is_isomorphic(psi) + False + + Two Drinfeld modules which are not patterned-alike are also not + isomorphic:: + + sage: phi = DrinfeldModule(A, [T, 1, 0, 1]) + sage: psi = DrinfeldModule(A, [T, 1, 1, 1]) + sage: phi.is_isomorphic(psi) + False + """ + # Trivial cases + if self.category() is not other.category(): + raise ValueError("Drinfeld modules are not in the same category") + if self is other: + return True + r = self.rank() + if other.rank() != r: + return False + # Check if there exists u such that u*self_X = other_X*u: + # if self_X = a_0 + a_1*t + ... + a_r*t^r + # and other_x = b_0 + b_1*t + ... + b_r*t^r + # this reduces to find a solution of the system: + # b_i * u^(q^i - 1) = a_i (0 <= i <= r) + # which, using gcds, can be reduced to a unique equation + # of the form u^e = ue. + q = self._Fq.cardinality() + A = self.gen() + B = other.gen() + e = Integer(0) + ue = self._base(1) + for i in range(1, r+1): + ai = A[i] + bi = B[i] + if ai == 0 and bi == 0: + continue + if ai == 0 or bi == 0: + return False + if e != q - 1: + # u^e = ue + # u^(q^i - 1) = ai/bi + e, s, t = e.xgcd(q**i - 1) + ue = ue**s * (ai/bi)**t + for i in range(1, r+1): + if A[i]: + f = (q**i - 1) // e + if A[i] != B[i] * ue**f: + return False + # Solve the equation u^e = ue + # - when absolutely=True, over the algebraic closure (then a + # solution always exists) + # - when absolutely=False, over the ground field. + if absolutely: + return True + else: + ue = ue.backend(force=True) + try: + _ = ue.nth_root(e) + except ValueError: + return False + except (AttributeError, NotImplementedError): + raise NotImplementedError(f"cannot solve the equation u^{e} == {ue}") + return True + + def is_finite(self) -> bool: + r""" + Return ``True`` if this Drinfeld module is finite, + ``False`` otherwise. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.is_finite() + True + sage: B.<Y> = Fq[] + sage: L = Frac(B) + sage: psi = DrinfeldModule(A, [L(2), L(1)]) + sage: psi.is_finite() + False + """ + from sage.rings.function_field.drinfeld_modules.finite_drinfeld_module import FiniteDrinfeldModule + return isinstance(self, FiniteDrinfeldModule) + + def j_invariant(self, parameter=None, check=True): + r""" + Return the `j`-invariant of the Drinfeld + `\mathbb{F}_q[T]`-module for the given parameter. + + Suppose that `\phi_T = g_0 + g_1\tau + \cdots + g_r \tau^r` with + `g_r \neq 0`. Then the + `((k_1, \ldots, k_n), (d_1, \ldots, d_n, d_r))`-`j`-*invariant* + of `\phi` is defined by + + .. MATH:: + + j_{k_1, \ldots, k_n}^{d_1, \ldots, d_n, d_r}(\phi) + := \frac{1}{g_r^{d_q}}\prod_{i = 1}^n g_{k_i}^{d_i} + + where `1\leqslant k_1 < k_2 < \ldots < k_n \leqslant r - 1` and + the integers `d_i` satisfy the *weight-0 condition*: + + .. MATH:: + + d_1 (q^{k_1} - 1) + d_2 (q^{k_2} - 1) + + \cdots + d_{n} (q^{k_n} - 1) = d_r (q^r - 1). + + Furthermore, if `\gcd(d_1,\ldots, d_n, d_r) = 1` and + + .. MATH:: + + 0 \leq d_i \leq (q^r - 1)/(q^{\gcd(i, r)} - 1), + \quad 1 \leq i \leq n, + + then the `j`-invariant is called *basic*. See the method + :meth:`basic_j_invariant_parameters` for computing the list of + all basic `j`-invariant parameters. + + INPUT: + + - ``parameter`` (tuple or list, integer or NoneType; default: + ``None``) -- the `j`-invariant parameter: + + - If ``parameter`` is a list or a tuple, then it must be of + the form: + `((k_1, k_2, \ldots, k_n), (d_1, d_2, \ldots, d_n, d_r))`, + where the `k_i` and `d_i` are integers satisfying the + weight-0 condition described above. + + - If ``parameter`` is an integer `k` then the method returns + the ``j``-invariant associated to the parameter + `((k,), (d_k, d_r))`; + + - If ``parameter`` is ``None`` and the rank of the Drinfeld + module is 2, then the method returns its usual + `j`-invariant, that is the `j`-invariant for the parameter + `((1,), (q+1, 1))`. + + - ``check`` (bool, default: ``True``) -- if this flag is set to + ``False`` then the code will not check if the given parameter + is valid and satisfy the weight-0 condition. + + OUTPUT: the `j`-invariant of ``self`` for the given parameter. + + REFERENCE: + + The notion of basic `j`-invariant was introduced by Potemine in + [Pot1998]_. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.j_invariant() + z12^10 + 4*z12^9 + 3*z12^8 + 2*z12^7 + 3*z12^6 + z12^5 + z12^3 + 4*z12^2 + z12 + 2 + sage: psi = DrinfeldModule(A, [p_root, 1, 1]) + sage: psi.j_invariant() + 1 + sage: rho = DrinfeldModule(A, [p_root, 0, 1]) + sage: rho.j_invariant() + 0 + + :: + + sage: A = GF(5)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, T^2, 1, T + 1, T^3]) + sage: phi.j_invariant(1) + T^309 + sage: phi.j_invariant(2) + 1/T^3 + sage: phi.j_invariant(3) + (T^156 + T^155 + T^151 + T^150 + T^131 + T^130 + T^126 + T^125 + T^31 + T^30 + T^26 + T^25 + T^6 + T^5 + T + 1)/T^93 + + The parameter can either be a tuple or a list:: + + sage: Fq.<a> = GF(7) + sage: A.<T> = Fq[] + sage: phi = DrinfeldModule(A, [a, a^2 + a, 0, 3*a, a^2+1]) + sage: J = phi.j_invariant(((1, 3), (267, 269, 39))); J + 5 + sage: J == (phi.coefficient(1)**267)*(phi.coefficient(3)**269)/(phi.coefficient(4)**39) + True + sage: phi.j_invariant([[3], [400, 57]]) + 4 + sage: phi.j_invariant([[3], [400, 57]]) == phi.j_invariant(3) + True + + The list of all basic `j`-invariant parameters can be retrieved + using the method :meth:`basic_j_invariant_parameters`:: + + sage: A = GF(3)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, T^2 + T + 1, 0, T^4 + 1, T - 1]) + sage: param = phi.basic_j_invariant_parameters(nonzero=True) + sage: phi.j_invariant(param[1]) + T^13 + 2*T^12 + T + 2 + sage: phi.j_invariant(param[2]) + T^35 + 2*T^31 + T^27 + 2*T^8 + T^4 + 2 + + TESTS:: + + sage: A = GF(5)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, T^2, 1, T + 1, T^3]) + sage: phi.j_invariant() + Traceback (most recent call last): + ... + TypeError: parameter must not be None if the rank is greater than 2 + + :: + + sage: phi.j_invariant(-1) + Traceback (most recent call last): + ... + ValueError: integer parameter must be >= 1 and < the rank (=4) + + :: + + sage: phi.j_invariant('x') + Traceback (most recent call last): + ... + TypeError: parameter must be a tuple or a list of length 2 or an integer + + :: + + sage: phi.j_invariant((1, 2, 3)) + Traceback (most recent call last): + ... + ValueError: list or tuple parameter must be of length 2 + + :: + + sage: phi.j_invariant(('x', (1, 2, 3))) + Traceback (most recent call last): + ... + TypeError: list or tuple parameter must contain tuples or lists + + :: + + sage: phi.j_invariant(((1, 2), 'x')) + Traceback (most recent call last): + ... + TypeError: list or tuple parameter must contain tuples or lists + + :: + + sage: phi.j_invariant(((1, 2, 3, 4, 5), (2, 1))) + Traceback (most recent call last): + ... + ValueError: components of tuple or list parameter have incorrect length + + :: + + sage: phi.j_invariant(((1, 'x'), (2, 3, 8))) + Traceback (most recent call last): + ... + TypeError: components of tuple or list parameter must contain only integers + + :: + + sage: phi.j_invariant(((1, 2), (2, 3, 'x'))) + Traceback (most recent call last): + ... + TypeError: components of tuple or list parameter must contain only integers + + :: + + sage: phi.j_invariant(((1, 2), (4, 3, 7))) + Traceback (most recent call last): + ... + ValueError: parameter does not satisfy the weight-0 condition + + :: + + sage: phi.j_invariant(((1, 2), (4, 3, 7)), check=False) + 1/T^13 + """ + r = self._gen.degree() + q = self._Fq.order() + if parameter is None: + if r != 2: + raise TypeError("parameter must not be None " + "if the rank is greater than 2") + return self._gen[1]**(q+1)/self._gen[2] + if parameter in ZZ: + parameter = ZZ(parameter) + if parameter <= 0 or parameter >= r: + raise ValueError("integer parameter must be >= 1 and < the " + f"rank (={r})") + dk = Integer((q**r - 1)/(q**gcd(parameter, r) - 1)) + dr = Integer((q**parameter - 1)/(q**gcd(parameter, r) - 1)) + return self._gen[parameter]**dk / self._gen[-1]**dr + elif isinstance(parameter, (tuple, list)): + if len(parameter) != 2: + raise ValueError("list or tuple parameter must be of length 2") + if not isinstance(parameter[0], (tuple, list)) \ + or not isinstance(parameter[1], (tuple, list)): + raise TypeError("list or tuple parameter must contain tuples " + "or lists") + if not len(parameter[0]) < r or\ + not len(parameter[1]) == len(parameter[0]) + 1: + raise ValueError("components of tuple or list parameter have " + "incorrect length") + try: # Check parameter's type + parameter_0 = [ZZ(p) for p in parameter[0]] + parameter_1 = [ZZ(p) for p in parameter[1]] + except TypeError: + raise TypeError("components of tuple or list parameter must " + "contain only integers") + # Check that the weight-0 condition is satisfied: + # d_1 (q - 1) + ... + d_{r-1} (q^{r-1} - 1) + # = d_r (q^r - 1) + if check: + right = parameter_1[-1]*(q**r - 1) + left = sum(parameter_1[i]*(q**(parameter_0[i]) - 1) for i in + range(len(parameter_0))) + if left != right: + raise ValueError("parameter does not satisfy the " + "weight-0 condition") + else: + raise TypeError("parameter must be a tuple or a list of " + "length 2 or an integer") + num = prod(self._gen[k]**d + for k, d in zip(parameter_0, parameter_1[:-1])) + return num / (self._gen[-1]**parameter_1[-1]) + + def jk_invariants(self): + r""" + Return a dictionary whose keys are all the integers + `1 \leqslant k \leqslant r-1` and the values are the + corresponding `j_k`-invariants + + Recall that the `j_k`-invariant of self is defined by: + + .. MATH:: + + j_k := \frac{g_k^{(q^r - 1)/(\mathrm{gcd}(k, r) - 1)}}{g_r^{(q^k - 1)/(\mathrm{gcd}(k, r) - 1)}} + + where `g_i` is the `i`-th coefficient of the generator of self. + + EXAMPLES:: + + sage: A = GF(3)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1, T+1, T^3, T^6]) + sage: jk_inv = phi.jk_invariants(); jk_inv + {1: 1/T^6, 2: (T^10 + T^9 + T + 1)/T^6, 3: T^42} + sage: jk_inv[2] + (T^10 + T^9 + T + 1)/T^6 + + :: + + sage: F = GF(7**2) + sage: A = F['T'] + sage: E.<z> = F.extension(4) + sage: phi = DrinfeldModule(A, [z^2, 1, z+1, z^2, z, z+1]) + sage: phi.jk_invariants() + {1: 5*z^7 + 2*z^6 + 5*z^5 + 2*z^4 + 5*z^3 + z^2 + z + 2, + 2: 3*z^7 + 4*z^6 + 5*z^5 + 6*z^4 + 4*z, + 3: 5*z^7 + 6*z^6 + 6*z^5 + 4*z^3 + z^2 + 2*z + 1, + 4: 3*z^6 + 2*z^5 + 4*z^4 + 2*z^3 + 4*z^2 + 6*z + 2} + """ + r = self._gen.degree() # rank of self + return {k: self.j_invariant(k) for k in range(1, r)} + + @cached_method + def _compute_coefficient_log(self, k): + r""" + Return the `q^k`-th coefficient of the logarithm of this Drinfeld module. + + TESTS:: + + sage: A = GF(2)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: q = A.base_ring().cardinality() + sage: phi._compute_coefficient_log(0) + 1 + sage: phi._compute_coefficient_log(1) + 1/(T^2 + T) + sage: phi._compute_coefficient_log(2) + 1/(T^6 + T^5 + T^3 + T^2) + sage: phi._compute_coefficient_log(3) + 1/(T^14 + T^13 + T^11 + T^10 + T^7 + T^6 + T^4 + T^3) + """ + k = ZZ(k) + if k.is_zero(): + return self._base.one() + r = self._gen.degree() + T = self._gen[0] + q = self._Fq.cardinality() + c = self._base.zero() + for i in range(k): + j = k - i + if j < r + 1: + c += self._compute_coefficient_log(i)*self._gen[j]**(q**i) + return c/(T - T**(q**k)) + + def logarithm(self, name='z'): + r""" + Return the logarithm of the given Drinfeld module. + + By definition, the logarithm is the compositional inverse of the + exponential (see :meth:`exponential`). Note that the logarithm + is only defined when the `\mathbb{F}_q[T]`-characteristic is + zero. + + INPUT: + + - ``name`` (string, default: ``'z'``) -- the name of the + generator of the lazy power series ring. + + OUTPUT: + + A lazy power series over the base field. + + EXAMPLES:: + + sage: A = GF(2)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: log = phi.logarithm(); log + z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8) + + The logarithm is returned as a lazy power series, meaning that + any of its coefficients can be computed on demands:: + + sage: log[2^4] + 1/(T^30 + T^29 + T^27 + ... + T^7 + T^5 + T^4) + sage: log[2^5] + 1/(T^62 + T^61 + T^59 + ... + T^8 + T^6 + T^5) + + Example in higher rank:: + + sage: A = GF(5)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, T^2, T + T^2 + T^4, 1]) + sage: phi.logarithm() + z + ((4*T/(T^4+4))*z^5) + O(z^8) + + TESTS:: + + sage: A = GF(2)['T'] + sage: K.<T> = Frac(A) + sage: phi = DrinfeldModule(A, [T, 1]) + sage: q = 2 + sage: log[2] == -1/((T**q - T)) # expected value + True + sage: log[2**2] == 1/((T**q - T)*(T**(q**2) - T)) # expected value + True + sage: log[2**3] == -1/((T**q - T)*(T**(q**2) - T)*(T**(q**3) - T)) # expected value + True + + :: + + sage: Fq.<w> = GF(3) + sage: A = Fq['T'] + sage: phi = DrinfeldModule(A, [w, 1]) + sage: phi.logarithm() + Traceback (most recent call last): + ... + ValueError: characteristic must be zero (=T + 2) + """ + if self.category()._characteristic: + raise ValueError(f"characteristic must be zero (={self.characteristic()})") + L = LazyPowerSeriesRing(self._base, name) + zero = self._base.zero() + q = self._Fq.cardinality() + + def coeff_log(k): + # Return the k-th coefficient of the logarithm + k = ZZ(k) + if k.is_power_of(q): + return self._compute_coefficient_log(k.log(q)) + else: + return self._base.zero() + return L(coeff_log, valuation=1) + + def morphism(self): + r""" + Return the morphism object that defines the Drinfeld module. + + OUTPUT: a ring morphism from the function ring to the Ore + polynomial ring + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.morphism() + Ring morphism: + From: Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 + To: Ore Polynomial Ring in t over Finite Field in z12 of size 5^12 + over its base twisted by Frob^2 + Defn: T |--> z12^5*t^2 + z12^3*t + 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: from sage.rings.morphism import RingHomomorphism + sage: isinstance(phi.morphism(), RingHomomorphism) + True + + Actually, the ``DrinfeldModule`` method :meth:`__call__` simply + class the ``__call__`` method of this morphism:: + + sage: phi.morphism()(T) == phi(T) + True + sage: a = A.random_element() + sage: phi.morphism()(a) == phi(a) + True + + And many methods of the Drinfeld module have a counterpart in + the morphism object:: + + sage: m = phi.morphism() + sage: m.domain() is phi.function_ring() + True + sage: m.codomain() is phi.ore_polring() + True + sage: m.im_gens() + [z12^5*t^2 + z12^3*t + 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12] + sage: phi(T) == m.im_gens()[0] + True + """ + return self._morphism + + def rank(self): + r""" + Return the rank of the Drinfeld module. + + In our case, the rank is the degree of the generator. + + OUTPUT: an integer + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: phi.rank() + 2 + sage: psi = DrinfeldModule(A, [p_root, 2]) + sage: psi.rank() + 1 + sage: rho = DrinfeldModule(A, [p_root, 0, 0, 0, 1]) + sage: rho.rank() + 4 + + TESTS: + + The rank must be an ``Integer`` (see PR #35519):: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: isinstance(phi.rank(), Integer) + True + """ + return self._gen.degree() + + def velu(self, isog): + r""" + Return a new Drinfeld module such that input is an + isogeny to this module with domain ``self``; if no such isogeny + exists, raise an exception. + + INPUT: + + - ``isog`` -- the Ore polynomial that defines the isogeny + + OUTPUT: a Drinfeld module + + ALGORITHM: + + The input defines an isogeny if only if: + + 1. The degree of the characteristic divides the height of + the input. (The height of an Ore polynomial `P(\tau)` is the + maximum `n` such that `\tau^n` right-divides `P(\tau)`.) + + 2. The input right-divides the generator, which can + be tested with Euclidean division. + + We test if the input is an isogeny, and, if it is, we + return the quotient of the Euclidean division. + + Height and Euclidean division of Ore polynomials are + implemented as methods of class + :class:`sage.rings.polynomial.ore_polynomial_element.OrePolynomial`. + + Another possible algorithm is to recursively solve a system, + see :arxiv:`2203.06970`, Eq. 1.1. + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: t = phi.ore_polring().gen() + sage: isog = t + 2*z12^11 + 4*z12^9 + 2*z12^8 + 2*z12^6 + 3*z12^5 + z12^4 + 2*z12^3 + 4*z12^2 + 4*z12 + 4 + sage: psi = phi.velu(isog) + sage: psi + Drinfeld module defined by T |--> + (z12^11 + 3*z12^10 + z12^9 + z12^7 + z12^5 + 4*z12^4 + 4*z12^3 + z12^2 + 1)*t^2 + + (2*z12^11 + 4*z12^10 + 2*z12^8 + z12^6 + 3*z12^5 + z12^4 + 2*z12^3 + z12^2 + z12 + 4)*t + + 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: isog in Hom(phi, psi) + True + + This method works for endomorphisms as well:: + + sage: phi.velu(phi(T)) is phi + True + sage: phi.velu(t^6) is phi + True + + The following inputs do not define isogenies, and the method + returns ``None``:: + + sage: phi.velu(0) + Traceback (most recent call last): + ... + ValueError: the input does not define an isogeny + sage: phi.velu(t) + Traceback (most recent call last): + ... + ValueError: the input does not define an isogeny + sage: phi.velu(t^3 + t + 2) + Traceback (most recent call last): + ... + ValueError: the input does not define an isogeny + """ + if isog not in self.ore_polring(): + raise TypeError('input must be an Ore polynomial') + e = ValueError('the input does not define an isogeny') + if isog == 0: + raise e + quo, rem = (isog * self.gen()).right_quo_rem(isog) + if rem.is_zero() and quo[0] == self.gen()[0]: + return self.category().object(quo) + else: + raise e + + def hom(self, x, codomain=None): + r""" + Return the homomorphism defined by ``x`` having this Drinfeld + module as domain. + + We recall that a homomorphism `f : \phi \to \psi` between + two Drinfeld modules is defined by an Ore polynomial `u`, + which is subject to the relation `phi_T u = u \psi_T`. + + INPUT: + + - ``x`` -- an element of the ring of functions, or an + Ore polynomial + + - ``codomain`` -- a Drinfeld module or ``None`` (default: + ``None``) + + EXAMPLES:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 0, 1, z]) + sage: phi + Drinfeld module defined by T |--> z*t^3 + t^2 + z + + An important class of endomorphisms of a Drinfeld module + `\phi` is given by scalar multiplications, that are endomorphisms + corresponding to the Ore polynomials `\phi_a` with `a` in the function + ring `A`. We construct them as follows:: + + sage: phi.hom(T) + Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z + Defn: z*t^3 + t^2 + z + + :: + + sage: phi.hom(T^2 + 1) + Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z + Defn: z^2*t^6 + (3*z^2 + z + 1)*t^5 + t^4 + 2*z^2*t^3 + (3*z^2 + z + 1)*t^2 + z^2 + 1 + + We can also define a morphism by passing in the Ore polynomial + defining it. + For example, below, we construct the Frobenius endomorphism + of `\phi`:: + + sage: t = phi.ore_variable() + sage: phi.hom(t^3) + Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z + Defn: t^3 + + If the input Ore polynomial defines a morphism to another + Drinfeld module, the latter is determined automatically:: + + sage: phi.hom(t + 1) + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> z*t^3 + t^2 + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*t^3 + (3*z^2 + 2*z + 2)*t^2 + (2*z^2 + 3*z + 4)*t + z + Defn: t + 1 + + TESTS:: + + sage: phi.hom(t) + Traceback (most recent call last): + ... + ValueError: the input does not define an isogeny + + :: + + sage: phi.hom(T + z) + Traceback (most recent call last): + ... + ValueError: the input does not define an isogeny + + :: + + sage: phi.hom(t + 1, codomain=phi) + Traceback (most recent call last): + ... + ValueError: Ore polynomial does not define a morphism + + """ + # When `x` is in the function ring (or something that coerces to it): + if self.function_ring().has_coerce_map_from(x.parent()): + return self.Hom(self)(x) + if codomain is None: + try: + codomain = self.velu(x) + except TypeError: + raise ValueError("the input does not define an isogeny") + H = self.Hom(codomain) + return H(x) + + # TODO: implement the method `moh`, the analogue of `hom` + # with fixed codomain. + # It's not straightforward because `left_divides` does not + # work currently because Sage does not know how to invert the + # Frobenius endomorphism; this is due to the RingExtension stuff. + + def scalar_multiplication(self, x): + r""" + Return the endomorphism of this Drinfeld module, which is + the multiplication by `x`, i.e. the isogeny defined by the + Ore polynomial `\phi_x`. + + INPUT: + + - ``x`` -- an element in the ring of functions + + EXAMPLES:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 0, 1, z]) + sage: phi + Drinfeld module defined by T |--> z*t^3 + t^2 + z + sage: phi.hom(T) + Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z + Defn: z*t^3 + t^2 + z + + :: + + sage: phi.hom(T^2 + 1) + Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z + Defn: z^2*t^6 + (3*z^2 + z + 1)*t^5 + t^4 + 2*z^2*t^3 + (3*z^2 + z + 1)*t^2 + z^2 + 1 + + """ + if not self.function_ring().has_coerce_map_from(x.parent()): + raise ValueError("%s is not element of the function ring" % x) + return self.Hom(self)(x) diff --git a/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py new file mode 100644 index 00000000000..e2115323fb8 --- /dev/null +++ b/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py @@ -0,0 +1,544 @@ +# sage.doctest: optional - sage.rings.finite_rings +r""" +Finite Drinfeld modules + +This module provides the class +:class:`sage.rings.function_fields.drinfeld_module.finite_drinfeld_module.FiniteDrinfeldModule`, +which inherits +:class:`sage.rings.function_fields.drinfeld_module.drinfeld_module.DrinfeldModule`. + +AUTHORS: + +- Antoine Leudiรจre (2022-04) +""" + +# ***************************************************************************** +# Copyright (C) 2022 Antoine Leudiรจre <antoine.leudiere@inria.fr> +# +# 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. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.matrix.constructor import Matrix +from sage.modules.free_module_element import vector +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.function_field.drinfeld_modules.drinfeld_module import DrinfeldModule + + +class FiniteDrinfeldModule(DrinfeldModule): + r""" + This class implements finite Drinfeld `\mathbb{F}_q[T]`-modules. + + A *finite Drinfeld module* is a Drinfeld module whose base field is + finite. In this case, the function field characteristic is a prime + ideal. + + For general definitions and help on Drinfeld modules, see class + :class:`sage.rings.function_fields.drinfeld_module.drinfeld_module.DrinfeldModule`. + + .. RUBRIC:: Construction: + + The user does not ever need to directly call + ``FiniteDrinfeldModule`` --- the metaclass ``DrinfeldModule`` is + responsible for instantiating ``DrinfeldModule`` or + ``FiniteDrinfeldModule`` depending on the input:: + + sage: Fq = GF(343) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z6, 0, 5]) + sage: phi + Drinfeld module defined by T |--> 5*t^2 + z6 + + :: + + sage: isinstance(phi, DrinfeldModule) + True + sage: from sage.rings.function_field.drinfeld_modules.finite_drinfeld_module import FiniteDrinfeldModule + sage: isinstance(phi, FiniteDrinfeldModule) + True + + The user should never use ``FiniteDrinfeldModule`` to test if a + Drinfeld module is finite, but rather the ``is_finite`` method:: + + sage: phi.is_finite() + True + + .. RUBRIC:: Complex multiplication of rank two finite Drinfeld modules + + We can handle some aspects of the theory of complex multiplication + of finite Drinfeld modules. Apart from the method + ``frobenius_endomorphism``, we only handle rank two Drinfeld + modules. + + First of all, it is easy to create the Frobenius endomorphism:: + + sage: frobenius_endomorphism = phi.frobenius_endomorphism() + sage: frobenius_endomorphism + Endomorphism of Drinfeld module defined by T |--> 5*t^2 + z6 + Defn: t^2 + + Its characteristic polynomial can be computed:: + + sage: chi = phi.frobenius_charpoly() + sage: chi + X^2 + (T + 2*z3^2 + 2*z3 + 1)*X + 2*T^2 + (z3^2 + z3 + 4)*T + 2*z3 + sage: frob_pol = frobenius_endomorphism.ore_polynomial() + sage: chi(frob_pol, phi(T)) + 0 + + as well as its trace and norm:: + + sage: phi.frobenius_trace() + 6*T + 5*z3^2 + 5*z3 + 6 + sage: phi.frobenius_trace() == -chi[1] + True + sage: phi.frobenius_norm() + 2*T^2 + (z3^2 + z3 + 4)*T + 2*z3 + + We can decide if a Drinfeld module is ordinary or supersingular:: + + sage: phi.is_ordinary() + True + sage: phi.is_supersingular() + False + + .. RUBRIC:: Inverting the Drinfeld module + + The morphism that defines a Drinfeld module is injective (see + [Gos1998]_, cor. 4.5.2). If the Drinfeld module is finite, one can + retrieve preimages:: + + sage: a = A.random_element() + sage: phi.invert(phi(a)) == a + True + """ + + def __init__(self, gen, category): + """ + Initialize `self`. + + Validity of the input is checked in `__classcall_private__`. The + `__init__` just saves attributes. + + INPUT: + + - ``function_ring`` -- a univariate polynomial ring whose base + is a finite field + + - ``gen`` -- the generator of the Drinfeld module as a list of + coefficients or an Ore polynomial + + - ``name`` (default: `'t'`) -- the name of the Ore polynomial + ring gen + + TESTS:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: gen = [p_root, z12^3, z12^5] + sage: phi = DrinfeldModule(A, gen) + sage: ore_polring = phi.ore_polring() + sage: phi._gen == ore_polring(gen) + True + """ + # NOTE: There used to be no __init__ here (which was fine). I + # added one to ensure that FiniteDrinfeldModule would always + # have _frobenius_norm and _frobenius_trace attributes. + super().__init__(gen, category) + self._frobenius_norm = None + self._frobenius_trace = None + + def frobenius_endomorphism(self): + r""" + Return the Frobenius endomorphism of the Drinfeld module as a + morphism object. + + Let `q` be the order of the base field of the function ring. The + *Frobenius endomorphism* is defined as the endomorphism whose + defining Ore polynomial is `t^q`. + + EXAMPLES:: + + sage: Fq = GF(343) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [1, 0, z6]) + sage: phi.frobenius_endomorphism() + Endomorphism of Drinfeld module defined by T |--> z6*t^2 + 1 + Defn: t^2 + + TESTS:: + + sage: from sage.rings.function_field.drinfeld_modules.morphism import DrinfeldModuleMorphism + sage: isinstance(phi.frobenius_endomorphism(), DrinfeldModuleMorphism) + True + """ + t = self.ore_polring().gen() + deg = self.base_over_constants_field().degree_over() + return self._Hom_(self, category=self.category())(t**deg) + + def frobenius_charpoly(self, var='X'): + r""" + Return the characteristic polynomial of the Frobenius + endomorphism if the rank is two. Raise a NotImplementedError + otherwise. + + Let `\mathbb{F}_q` be the base field of the function ring. The + *characteristic polynomial `\chi` of the Frobenius endomorphism* + is defined in [Gek1991]_. An important feature of this + polynomial is that it is a monic univariate polynomial with + coefficients in the function ring. As in our case the function + ring is a univariate polynomial ring, it is customary to see the + characteristic polynomial of the Frobenius endomorphism as a + bivariate polynomial. + + Let `\chi = X^2 - A(T)X + B(T)` be the characteristic polynomial + of the Frobenius endomorphism, and let `t^n` be the Ore polynomial + that defines the Frobenius endomorphism of `\phi`; by + definition, `n` is the degree over of the base field over + `\mathbb{F}_q`. We have `\chi(t^n)(\phi(T)) = t^{2n} - \phi_A + t^n + \phi_B = 0`, with `\deg(A) \leq \frac{n}{2}` and `\deg(B) + = n`. + + Note that the *Frobenius trace* is defined as `A(T)` and the + *Frobenius norm* is defined as `B(T)`. + + INPUT: + + - ``var`` (default: ``'X'``) -- the name of the second variable + + EXAMPLES:: + + sage: Fq = GF(343) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [1, 0, z6]) + sage: chi = phi.frobenius_charpoly() + sage: chi + X^2 + ((3*z3^2 + z3 + 4)*T + 4*z3^2 + 6*z3 + 3)*X + + (5*z3^2 + 2*z3)*T^2 + (4*z3^2 + 3*z3)*T + 5*z3^2 + 2*z3 + + :: + + sage: frob_pol = phi.frobenius_endomorphism().ore_polynomial() + sage: chi(frob_pol, phi(T)) + 0 + + :: + + sage: trace = phi.frobenius_trace() + sage: trace + (4*z3^2 + 6*z3 + 3)*T + 3*z3^2 + z3 + 4 + sage: norm = phi.frobenius_norm() + sage: norm + (5*z3^2 + 2*z3)*T^2 + (4*z3^2 + 3*z3)*T + 5*z3^2 + 2*z3 + + :: + + sage: n = 2 # Degree of the base field over Fq + sage: trace.degree() <= n/2 + True + sage: norm.degree() == n + True + + ALGORITHM: + + We compute the Frobenius norm, and with it the Frobenius + trace. This gives the Frobenius characteristic polynomial. + See [MS2019]_, Section 4. + + See docstrings of methods :meth:`frobenius_norm` and + :meth:`frobenius_trace` for further details on the + computation of the norm and of the trace. + """ + self._check_rank_two() + A = self._function_ring # Fq[T] + S = PolynomialRing(A, name=var) # Fq[T][X] + # Does not work when Fq is not a prime field... + # chi = self._gen.reduced_charpoly() + # return -chi(A.gen(), S.gen()) + return S([self.frobenius_norm(), -self.frobenius_trace(), 1]) + + def frobenius_norm(self): + r""" + Return Frobenius norm of the Drinfeld module, if the rank is + two, raise a NotImplementedError otherwise. + + Let `\mathbb{F}_q[T]` be the function ring, write `\chi = X^2 - + A(T)X + B(T) \in \mathbb{F}_q[T][X]` for the characteristic + polynomial of the Frobenius endomorphism. The *Frobenius norm* + is defined as the polynomial `B(T) \in \mathbb{F}_q[T]`. + + Let `n` be the degree of the base field over `\mathbb{F}_q` Then the + Frobenius norm has degree `n`. + + EXAMPLES:: + + sage: Fq = GF(343) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [1, 0, z6]) + sage: B = phi.frobenius_norm() + sage: B + (5*z3^2 + 2*z3)*T^2 + (4*z3^2 + 3*z3)*T + 5*z3^2 + 2*z3 + + :: + + sage: n = 2 # Degree of the base field over Fq + sage: B.degree() == n + True + + :: + + sage: B == phi.frobenius_charpoly()[0] + True + + ALGORITHM: + + The Frobenius norm is computed using the formula, by + Gekeler, given in [MS2019]_, Section 4, Proposition 3. + """ + self._check_rank_two() + L = self._base.over(self._Fq) + # Notations from Schost-Musleh: + if self._frobenius_norm is None: + n = L.degree_over(self._Fq) + d = self.characteristic().degree() + m = n // d + delta = self._gen[2] + norm = L(delta).norm() + char = self.characteristic() + self._frobenius_norm = ((-1)**n) * (char**m) / norm + return self._frobenius_norm + + def frobenius_trace(self): + r""" + Return Frobenius norm of the Drinfeld module, if the rank is + two; raise a NotImplementedError otherwise. + + Let `\mathbb{F}_q[T]` be the function ring, write `\chi = T^2 - + A(X)T + B(X) \in \mathbb{F}_q[T][X]` for the characteristic + polynomial of the Frobenius endomorphism. The *Frobenius trace* + is defined as the polynomial `A(T) \in \mathbb{F}_q[T]`. + + Let `n` be the degree over `\mathbb{F}_q` of the base codomain. + Then the Frobenius trace has degree at most `\frac{n}{2}`. + + EXAMPLES:: + + sage: Fq = GF(343) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [1, 0, z6]) + sage: A = phi.frobenius_trace() + sage: A + (4*z3^2 + 6*z3 + 3)*T + 3*z3^2 + z3 + 4 + + :: + + sage: n = 2 # Degree over Fq of the base codomain + sage: A.degree() <= n/2 + True + + :: + + sage: A == -phi.frobenius_charpoly()[1] + True + + ALGORITHM: + + Let `A(T)` denote the Frobenius trace and `B(T)` denote the + Frobenius norm. We begin by computing `B(T)`, see docstring + of method :meth:`frobenius_norm` for details. The + characteristic polynomial of the Frobenius yields `t^{2n} - + \phi_A t^n + \phi_B = 0`, where `t^n` is the Frobenius + endomorphism. As `\phi_B` is now known, we can compute + `\phi_A = (t^{2n} + \phi_B) / t^n`. We get `A(T)` by + inverting this quantity, using the method + :meth:`sage.rings.function_fields.drinfeld_module.drinfeld_module.DrinfeldModule.invert`, + see its docstring for details. + """ + self._check_rank_two() + # Notations from Schost-Musleh: + if self._frobenius_trace is None: + n = self._base.over(self._Fq).degree_over(self._Fq) + B = self.frobenius_norm() + t = self.ore_polring().gen() + self._frobenius_trace = self.invert(t**n + (self(B) // t**n)) + return self._frobenius_trace + + def invert(self, ore_pol): + r""" + Return the preimage of the input under the Drinfeld module, if it + exists. + + INPUT: + + - ``ore_pol`` -- the Ore polynomial whose preimage we want to + compute + + EXAMPLES:: + + sage: Fq = GF(25) + sage: A.<T> = Fq[] + sage: K.<z12> = Fq.extension(6) + sage: p_root = 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 + sage: phi = DrinfeldModule(A, [p_root, z12^3, z12^5]) + sage: a = A.random_element() + sage: phi.invert(phi(a)) == a + True + sage: phi.invert(phi(T)) == T + True + sage: phi.invert(phi(Fq.gen())) == Fq.gen() + True + + When the input is not in the image of the Drinfeld module, an + exception is raised:: + + sage: t = phi.ore_polring().gen() + sage: phi.invert(t + 1) + Traceback (most recent call last): + ... + ValueError: input must be in the image of the Drinfeld module + + :: + + sage: phi.invert(t^4 + t^2 + 1) + Traceback (most recent call last): + ... + ValueError: input must be in the image of the Drinfeld module + + ALGORITHM: + + The algorithm relies on the inversion of a linear algebra + system. See [MS2019]_, 3.2.5 for details. + + TESTS:: + + sage: a = A.random_element() + sage: cat = phi.category() + sage: phi_r1 = cat.random_object(1) + sage: phi_r1.invert(phi_r1(a)) == a + True + sage: phi_r2 = cat.random_object(2) + sage: phi_r2.invert(phi_r2(a)) == a + True + sage: phi_r3 = cat.random_object(3) + sage: phi_r3.invert(phi_r3(a)) == a + True + sage: phi_r4 = cat.random_object(4) + sage: phi_r4.invert(phi_r4(a)) == a + True + sage: phi_r5 = cat.random_object(5) + sage: phi_r5.invert(phi_r5(a)) == a + True + + :: + + sage: B.<X> = Fq[] + sage: phi_r5.invert(X) + Traceback (most recent call last): + ... + TypeError: input must be an Ore polynomial + + """ + deg = ore_pol.degree() + r = self.rank() + E = self.base() + K = self.base_over_constants_field() + if ore_pol in self._ore_polring: + ore_pol = self._ore_polring(ore_pol) + else: + raise TypeError('input must be an Ore polynomial') + + # Trivial cases + if deg <= 0: + return K(ore_pol[0]).in_base() + if deg % r != 0: + raise ValueError('input must be in the image of the Drinfeld module') + # Write the system and solve it + k = deg // r + A = self._function_ring + T = A.gen() + mat_rows = [[E.zero() for _ in range(k+1)] for _ in range(k+1)] + mat_rows[0][0] = E.one() + phiT = self.gen() + phiTi = self.ore_polring().one() + for i in range(1, k+1): + phiTi *= phiT + for j in range(i+1): + mat_rows[j][i] = phiTi[r*j] + mat = Matrix(mat_rows) + vec = vector([ore_pol[r*j] for j in range(k+1)]) + coeffs_K = list(mat.inverse() * vec) + # Cast the coefficients to Fq + try: + coeffs_Fq = [K(c).in_base() for c in coeffs_K] + pre_image = A(coeffs_Fq) + if self(pre_image) == ore_pol: + return pre_image + except ValueError: + pass + raise ValueError('input must be in the image of the Drinfeld module') + + def is_supersingular(self): + r""" + Return ``True`` if this Drinfeld module is supersingular. + + A Drinfeld module is supersingular if and only if its + height equals its rank. + + EXAMPLES:: + + sage: Fq = GF(343) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [1, 0, z6]) + sage: phi.is_supersingular() + True + sage: phi(phi.characteristic()) # Purely inseparable + z6*t^2 + + In rank two, a Drinfeld module is either ordinary or + supersinguler. In higher ranks, it could be neither of + the two:: + + sage: psi = DrinfeldModule(A, [1, 0, z6, z6]) + sage: psi.is_ordinary() + False + sage: psi.is_supersingular() + False + + """ + return self.height() == self.rank() + + def is_ordinary(self): + r""" + Return ``True`` if this Drinfeld module is ordinary. + + A Drinfeld module is ordinary if and only if its + height is one. + + EXAMPLES:: + + sage: Fq = GF(343) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [1, 0, z6]) + sage: phi.is_ordinary() + False + + :: + + sage: phi = DrinfeldModule(A, [1, z6, 0, z6]) + sage: phi.is_ordinary() + True + + """ + return self.height() == 1 diff --git a/src/sage/rings/function_field/drinfeld_modules/homset.py b/src/sage/rings/function_field/drinfeld_modules/homset.py new file mode 100644 index 00000000000..9ca53442cf5 --- /dev/null +++ b/src/sage/rings/function_field/drinfeld_modules/homset.py @@ -0,0 +1,423 @@ +# sage.doctest: optional - sage.rings.finite_rings +r""" +Set of morphisms between two Drinfeld modules + +This module provides the class +:class:`sage.rings.function_field.drinfeld_module.homset.DrinfeldModuleHomset`. + +AUTHORS: + +- Antoine Leudiรจre (2022-04) +""" + +# ***************************************************************************** +# Copyright (C) 2022 Antoine Leudiรจre <antoine.leudiere@inria.fr> +# +# 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. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +import operator + +from sage.categories.drinfeld_modules import DrinfeldModules +from sage.categories.homset import Homset +from sage.categories.action import Action +from sage.misc.latex import latex +from sage.rings.function_field.drinfeld_modules.morphism import DrinfeldModuleMorphism +from sage.structure.parent import Parent + + +class DrinfeldModuleMorphismAction(Action): + r""" + Action of the function ring on the homset of a Drinfeld module. + + EXAMPLES:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 1, z]) + sage: psi = DrinfeldModule(A, [z, z^2 + 4*z + 3, 2*z^2 + 4*z + 4]) + sage: H = Hom(phi, psi) + sage: t = phi.ore_variable() + sage: f = H(t + 2) + + Left action:: + + sage: (T + 1) * f + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> z*t^2 + t + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*t^2 + (z^2 + 4*z + 3)*t + z + Defn: (2*z^2 + 4*z + 4)*t^3 + (2*z + 1)*t^2 + (2*z^2 + 4*z + 2)*t + 2*z + 2 + + Right action currently does not work (it is a known bug, due to an + incompatibility between multiplication of morphisms and the coercion + system):: + + sage: f * (T + 1) + Traceback (most recent call last): + ... + TypeError: right (=T + 1) must be a map to multiply it by Drinfeld Module morphism: + From: Drinfeld module defined by T |--> z*t^2 + t + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*t^2 + (z^2 + 4*z + 3)*t + z + Defn: t + 2 + + """ + def __init__(self, A, H, is_left, op): + r""" + Initialize this action. + + INPUT: + + - ``A`` -- the function ring of the underlying Drinfeld module + + - ``H`` -- a homset between Drinfeld modules + + - ``is_left`` -- a boolean + + - ``op`` -- an operator + + TESTS:: + + sage: Fq = GF(27) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z6, z6, 2]) + sage: psi = DrinfeldModule(A, [z6, 2*z6^5 + 2*z6^4 + 2*z6 + 1, 2]) + sage: H = Hom(phi, psi) + + sage: from sage.rings.function_field.drinfeld_modules.homset import DrinfeldModuleMorphismAction + sage: left_action = DrinfeldModuleMorphismAction(A, H, True, operator.mul) + sage: TestSuite(left_action).run(skip='_test_pickling') + + sage: right_action = DrinfeldModuleMorphismAction(A, H, False, operator.mul) + sage: TestSuite(right_action).run(skip='_test_pickling') + + """ + Action.__init__(self, A, H, is_left, op) + if is_left: + self._phi = H.codomain() + else: + self._phi = H.domain() + + def _act_(self, a, f): + r""" + Return the action of `a` on `f`. + + EXAMPLES:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 0, 1, z]) + sage: t = phi.ore_variable() + sage: f = phi.hom(t + 1) + sage: T*f # indirect doctest + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> z*t^3 + t^2 + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*t^3 + (3*z^2 + 2*z + 2)*t^2 + (2*z^2 + 3*z + 4)*t + z + Defn: (2*z^2 + 4*z + 4)*t^4 + (z + 1)*t^3 + t^2 + (2*z^2 + 4*z + 4)*t + z + + """ + u = f.ore_polynomial() + if self._is_left: + u = self._phi(a) * u + else: + u = u * self._phi(a) + return f.parent()(u) + + +class DrinfeldModuleHomset(Homset): + r""" + This class implements the set of morphisms between two Drinfeld + `\mathbb{F}_q[T]`-modules. + + INPUT: + + - ``X`` -- the domain + + - ``Y`` -- the codomain + + EXAMPLES:: + + sage: Fq = GF(27) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z6, z6, 2]) + sage: psi = DrinfeldModule(A, [z6, 2*z6^5 + 2*z6^4 + 2*z6 + 1, 2]) + sage: H = Hom(phi, psi) + sage: H + Set of Drinfeld module morphisms + from (gen) 2*t^2 + z6*t + z6 + to (gen) 2*t^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*t + z6 + + :: + + sage: from sage.rings.function_field.drinfeld_modules.homset import DrinfeldModuleHomset + sage: isinstance(H, DrinfeldModuleHomset) + True + + There is a simpler syntax for endomorphisms sets:: + + sage: E = End(phi) + sage: E + Set of Drinfeld module morphisms from (gen) 2*t^2 + z6*t + z6 to (gen) 2*t^2 + z6*t + z6 + sage: E is Hom(phi, phi) + True + + The domain and codomain must have the same Drinfeld modules + category:: + + sage: rho = DrinfeldModule(A, [Frac(A)(T), 1]) + sage: Hom(phi, rho) + Traceback (most recent call last): + ... + ValueError: Drinfeld modules must be in the same category + + :: + + sage: sigma = DrinfeldModule(A, [1, z6, 2]) + sage: Hom(phi, sigma) + Traceback (most recent call last): + ... + ValueError: Drinfeld modules must be in the same category + + One can create morphism objects by calling the homset:: + + sage: identity_morphism = E(1) + sage: identity_morphism + Identity morphism of Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 + + :: + + sage: t = phi.ore_polring().gen() + sage: frobenius_endomorphism = E(t^6) + sage: frobenius_endomorphism + Endomorphism of Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 + Defn: t^6 + + :: + + sage: isogeny = H(t + 1) + sage: isogeny + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 + To: Drinfeld module defined by T |--> 2*t^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*t + z6 + Defn: t + 1 + + And one can test if an Ore polynomial defines a morphism using the + ``in`` syntax:: + + sage: 1 in H + False + sage: t^6 in H + False + sage: t + 1 in H + True + sage: 1 in E + True + sage: t^6 in E + True + sage: t + 1 in E + False + + This also works if the candidate is a morphism object:: + + sage: isogeny in H + True + sage: E(0) in E + True + sage: identity_morphism in H + False + sage: frobenius_endomorphism in H + False + + """ + Element = DrinfeldModuleMorphism + + def __init__(self, X, Y, category=None, check=True): + """ + Initialize ``self``. + + INPUT: + + - ``X`` -- the domain of the homset + + - ``Y`` -- the codomain of the homset + + - ``category`` (default: ``None``) -- the Drinfeld modules category of + the domain and codomain + + - ``check`` (default: ``True``) -- check the validity of the category + + TESTS:: + + sage: Fq = GF(27) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z6, z6, 2]) + sage: psi = DrinfeldModule(A, [z6, 2*z6^5 + 2*z6^4 + 2*z6 + 1, 2]) + sage: H = Hom(phi, psi) + sage: H.domain() is phi + True + sage: H.codomain() is psi + True + """ + if category is None: + category = X.category() + if check: + if X.category() != Y.category() \ + or not isinstance(X.category(), DrinfeldModules): + raise ValueError('Drinfeld modules must be in the same category') + if category != X.category(): + raise ValueError('category should be DrinfeldModules') + base = category.base() + super().__init__(X, Y, category=category, base=base, check=check) + A = X.function_ring() + self.register_action(DrinfeldModuleMorphismAction(A, self, True, operator.mul)) + # ARGH: the next line does not work + # because Map.__mul__ does not call the coercion system + self.register_action(DrinfeldModuleMorphismAction(A, self, False, operator.mul)) + if X is Y: + self.register_coercion(A) + + def _latex_(self): + r""" + Return a LaTeX representation of the homset. + + EXAMPLES:: + + sage: Fq = GF(27) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z6, z6, 2]) + sage: psi = DrinfeldModule(A, [z6, 2*z6^5 + 2*z6^4 + 2*z6 + 1, 2]) + sage: H = Hom(phi, psi) + sage: latex(H) + \text{Set{ }of{ }Drinfeld{ }module{ }morphisms{ }from{ }(gen){ }}2 t^{2} + z_{6} t + z_{6}\text{{ }to{ }(gen){ }}2 t^{2} + \left(2 z_{6}^{5} + 2 z_{6}^{4} + 2 z_{6} + 1\right) t + z_{6} + """ + return f'\\text{{Set{{ }}of{{ }}Drinfeld{{ }}module{{ }}morphisms' \ + f'{{ }}from{{ }}(gen){{ }}}}{latex(self.domain().gen())}' \ + f'\\text{{{{ }}to{{ }}(gen){{ }}}}'\ + f'{latex(self.codomain().gen())}' + + def _repr_(self): + r""" + Return a string representation of the homset. + + EXAMPLES:: + + sage: Fq = GF(27) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z6, z6, 2]) + sage: psi = DrinfeldModule(A, [z6, 2*z6^5 + 2*z6^4 + 2*z6 + 1, 2]) + sage: H = Hom(phi, psi) + sage: H + Set of Drinfeld module morphisms from (gen) 2*t^2 + z6*t + z6 to (gen) 2*t^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*t + z6 + """ + return f'Set of Drinfeld module morphisms from (gen) '\ + f'{self.domain().gen()} to (gen) {self.codomain().gen()}' + + def __contains__(self, x): + r""" + Return ``True`` if the input defines a morphism in the homset. + + INPUT: + + - ``x`` -- an Ore polynomial or a Drinfeld module morphism + + EXAMPLES: + + In the next examples, the input is an Ore polynomial:: + + sage: Fq = GF(27) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z6, z6, 2]) + sage: psi = DrinfeldModule(A, [z6, 2*z6^5 + 2*z6^4 + 2*z6 + 1, 2]) + sage: H = Hom(phi, psi) + sage: E = End(phi) + sage: t = phi.ore_polring().gen() + sage: 1 in H + False + sage: t^6 in H + False + sage: t + 1 in H + True + sage: 1 in E + True + sage: t^6 in E + True + sage: t + 1 in E + False + + Whereas the input is now a Drinfeld module morphism:: + + sage: isogeny = H(t + 1) + sage: isogeny in H + True + sage: E(0) in E + True + sage: identity_morphism = E(1) + sage: identity_morphism in H + False + sage: frobenius_endomorphism = phi.frobenius_endomorphism() + sage: frobenius_endomorphism in H + False + """ + try: + x = self(x) + return True + except (AttributeError, ValueError, TypeError): + return False + + def _element_constructor_(self, *args, **kwds): + r""" + Return the Drinfeld module morphism defined by the given Ore + polynomial. + + EXAMPLES:: + + sage: Fq = GF(27) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(2) + sage: phi = DrinfeldModule(A, [z6, z6, 2]) + sage: psi = DrinfeldModule(A, [z6, 2*z6^5 + 2*z6^4 + 2*z6 + 1, 2]) + sage: H = Hom(phi, psi) + sage: E = End(phi) + sage: t = phi.ore_polring().gen() + sage: identity_morphism = E(1) + sage: identity_morphism + Identity morphism of Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 + + :: + + sage: scalar_multiplication = E(T) + sage: scalar_multiplication + Endomorphism of Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 + Defn: 2*t^2 + z6*t + z6 + + :: + + sage: frobenius_endomorphism = E(t^6) + sage: frobenius_endomorphism + Endomorphism of Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 + Defn: t^6 + + :: + + sage: isogeny = H(t + 1) + sage: isogeny + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> 2*t^2 + z6*t + z6 + To: Drinfeld module defined by T |--> 2*t^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*t + z6 + Defn: t + 1 + """ + # NOTE: This used to be self.element_class(self, ...), but this + # would call __init__ instead of __classcall_private__. This + # seems to work, but I don't know what I'm doing. + return DrinfeldModuleMorphism(self, *args, **kwds) diff --git a/src/sage/rings/function_field/drinfeld_modules/morphism.py b/src/sage/rings/function_field/drinfeld_modules/morphism.py new file mode 100644 index 00000000000..dfed15f778c --- /dev/null +++ b/src/sage/rings/function_field/drinfeld_modules/morphism.py @@ -0,0 +1,827 @@ +# sage.doctest: optional - sage.rings.finite_rings +r""" +Drinfeld module morphisms + +This module provides the class +:class:`sage.rings.function_fields.drinfeld_module.morphism.DrinfeldModuleMorphism`. + +AUTHORS: +- Antoine Leudiรจre (2022-04) +""" + +# ***************************************************************************** +# Copyright (C) 2022 Antoine Leudiรจre <antoine.leudiere@inria.fr> +# +# 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. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.misc.latex import latex +from sage.categories.morphism import Morphism +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element import coerce_binop + +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.matrix.constructor import matrix + + +class DrinfeldModuleMorphism(Morphism, UniqueRepresentation, + metaclass=InheritComparisonClasscallMetaclass): + r""" + This class represents Drinfeld `\mathbb{F}_q[T]`-module morphisms. + + Let `\phi` and `\psi` be two Drinfeld `\mathbb{F}_q[T]`-modules over + a field `K`. A *morphism of Drinfeld modules* `\phi \to \psi` is an + Ore polynomial `f \in K\{\tau\}` such that `f \phi_a = \psi_a f` for + every `a \in \mathbb{F}_q[T]`. In our case, this is equivalent to `f + \phi_T = \psi_T f`. An *isogeny* is a nonzero morphism. + + To create a morphism object, the user should never explicitly + instantiate :class:`DrinfeldModuleMorphism`, but rather call the + parent homset with the defining Ore polynomial:: + + sage: Fq = GF(4) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, z^2 + z, z^2 + z]) + sage: t = phi.ore_polring().gen() + sage: ore_pol = t + z^5 + z^3 + z + 1 + sage: psi = phi.velu(ore_pol) + sage: morphism = Hom(phi, psi)(ore_pol) + sage: morphism + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> (z^2 + z)*t^2 + (z^2 + z)*t + z + To: Drinfeld module defined by T |--> (z^5 + z^2 + z + 1)*t^2 + (z^4 + z + 1)*t + z + Defn: t + z^5 + z^3 + z + 1 + + + The given Ore polynomial must indeed define a morphism:: + + sage: morphism = Hom(phi, psi)(1) + Traceback (most recent call last): + ... + ValueError: Ore polynomial does not define a morphism + + One can get basic data on the morphism:: + + sage: morphism.domain() + Drinfeld module defined by T |--> (z^2 + z)*t^2 + (z^2 + z)*t + z + sage: morphism.domain() is phi + True + + sage: morphism.codomain() + Drinfeld module defined by T |--> (z^5 + z^2 + z + 1)*t^2 + (z^4 + z + 1)*t + z + sage: morphism.codomain() is psi + True + + :: + + sage: morphism.ore_polynomial() + t + z^5 + z^3 + z + 1 + sage: morphism.ore_polynomial() is ore_pol + True + + One can check various properties:: + + sage: morphism.is_zero() + False + sage: morphism.is_isogeny() + True + sage: morphism.is_endomorphism() + False + sage: morphism.is_isomorphism() + False + + TESTS:: + + sage: morphism.parent() is Hom(phi, psi) + True + sage: Hom(phi, psi)(morphism) == morphism + True + + :: + + sage: phi.frobenius_endomorphism().parent() == End(phi) + True + sage: End(phi)(0).parent() == End(phi) + True + + For the sake of completeness, we explain how the user can directly + instantiate the class, even though this should never be explicitly + done:: + + sage: from sage.rings.function_field.drinfeld_modules.morphism import DrinfeldModuleMorphism + sage: DrinfeldModuleMorphism(Hom(phi, psi), ore_pol) + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> (z^2 + z)*t^2 + (z^2 + z)*t + z + To: Drinfeld module defined by T |--> (z^5 + z^2 + z + 1)*t^2 + (z^4 + z + 1)*t + z + Defn: t + z^5 + z^3 + z + 1 + sage: DrinfeldModuleMorphism(Hom(phi, psi), ore_pol) is morphism + True + + """ + @staticmethod + def __classcall_private__(cls, parent, x): + """ + Create the morphism. + + INPUT: + + - ``cls`` -- the class ``DrinfeldModuleMorphism`` + + - ``parent`` -- the Drinfeld module homset + + - ``x`` -- a morphism of Drinfeld modules or an element + (either an Ore polynomial or an element in the base + ring) defining it + + TESTS:: + + sage: Fq = GF(2) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z6, 1, 1]) + sage: End(phi)(T + 1) + Endomorphism of Drinfeld module defined by T |--> t^2 + t + z6 + Defn: t^2 + t + z6 + 1 + + :: + + sage: t = phi.ore_polring().gen() + sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) + sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: morphism is Hom(phi, psi)(morphism) + True + + :: + + sage: from sage.rings.function_field.drinfeld_modules.morphism import DrinfeldModuleMorphism + sage: morphism = DrinfeldModuleMorphism(Sets(), t + 1) + Traceback (most recent call last): + ... + TypeError: parent should be a DrinfeldModuleHomset + """ + from sage.rings.function_field.drinfeld_modules.homset import DrinfeldModuleHomset + if not isinstance(parent, DrinfeldModuleHomset): + raise TypeError('parent should be a DrinfeldModuleHomset') + domain = parent.domain() + codomain = parent.codomain() + A = domain.category().function_ring() + # NOTE: it used to be x.parent() is parent, but this was False. + # DrinfeldModuleHomset inherits Homset, which does NOT inherit + # UniqueRepresentation + if x.parent() == parent: + # x is a DrinfeldModuleMorphism + ore_pol = x.ore_polynomial() + elif domain is codomain and A.has_coerce_map_from(x.parent()): + # x is in the function field; we return the endomorphism phi_x + ore_pol = domain(A(x)) + else: + # x is an Ore polynomial + ore_pol = domain.ore_polring()(x) + if ore_pol * domain.gen() != codomain.gen() * ore_pol: + raise ValueError('Ore polynomial does not define a morphism') + return cls.__classcall__(cls, parent, ore_pol) + + def __init__(self, parent, ore_pol): + r""" + Initialize ``self``. + + INPUT: + + - ``parent`` -- the Drinfeld module homset + + - ``ore_pol`` -- the Ore polynomial that defines the morphism + + TESTS:: + + sage: Fq = GF(2) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z6, 1, 1]) + sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) + sage: t = phi.ore_polring().gen() + sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: morphism._domain is phi + True + sage: morphism._codomain is psi + True + sage: morphism._ore_polynomial == t + z6^5 + z6^2 + 1 + True + """ + super().__init__(parent) + self._domain = parent.domain() + self._codomain = parent.codomain() + self._ore_polynomial = ore_pol + + def _latex_(self): + r""" + Return a LaTeX representation of the morphism. + + EXAMPLES:: + + sage: Fq = GF(2) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z6, 1, 1]) + sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) + sage: t = phi.ore_polring().gen() + sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: latex(morphism) + t + z_{6}^{5} + z_{6}^{2} + 1 + """ + return f'{latex(self._ore_polynomial)}' + + def _repr_(self): + r""" + Return a string representation of the morphism. + + EXAMPLES:: + + sage: Fq = GF(2) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z6, 1, 1]) + sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) + sage: t = phi.ore_polring().gen() + sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: morphism + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> t^2 + t + z6 + To: Drinfeld module defined by T |--> t^2 + (z6^4 + z6^2 + 1)*t + z6 + Defn: t + z6^5 + z6^2 + 1 + """ + if self.is_identity(): + return f'Identity morphism of {self._domain}' + elif self.is_endomorphism(): + return f'Endomorphism of {self._domain}\n' \ + f' Defn: {self._ore_polynomial}' + else: + return f'Drinfeld Module morphism:\n' \ + f' From: {self._domain}\n' \ + f' To: {self._codomain}\n' \ + f' Defn: {self._ore_polynomial}' + + def __hash__(self): + r""" + Return a hash of ``self``. + + EXAMPLES:: + + sage: Fq = GF(2) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z6, 1, 1]) + sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) + sage: t = phi.ore_polring().gen() + sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: hash(morphism) # random + -4214883752078138009 + """ + return hash((self._domain, self._codomain, self._ore_polynomial)) + + def is_zero(self): + r""" + Return ``True`` whether the morphism is the zero morphism. + + EXAMPLES:: + + sage: Fq = GF(2) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z6, 1, 1]) + sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) + sage: t = phi.ore_polring().gen() + sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: morphism.is_zero() + False + + :: + + sage: zero_morphism = End(phi)(0) + sage: zero_morphism.is_zero() + True + """ + return self._ore_polynomial.is_zero() + + def is_identity(self): + r""" + Return ``True`` whether the morphism is the identity morphism. + + EXAMPLES:: + + sage: Fq = GF(2) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z6, 1, 1]) + sage: morphism = End(phi)(1) + sage: morphism.is_identity() + True + + :: + + sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) + sage: t = phi.ore_polring().gen() + sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: morphism.is_identity() + False + """ + return self._ore_polynomial == 1 + + def is_isogeny(self): + r""" + Return ``True`` whether the morphism is an isogeny. + + EXAMPLES:: + + sage: Fq = GF(2) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z6, 1, 1]) + sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) + sage: t = phi.ore_polring().gen() + sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: morphism.is_isogeny() + True + + :: + + sage: zero_morphism = End(phi)(0) + sage: zero_morphism.is_isogeny() + False + + :: + + sage: identity_morphism = End(phi)(1) + sage: identity_morphism.is_isogeny() + True + + :: + + sage: frobenius_endomorphism = phi.frobenius_endomorphism() + sage: frobenius_endomorphism.is_isogeny() + True + """ + return not self.is_zero() + + def is_isomorphism(self): + r""" + Return ``True`` whether the morphism is an isomorphism. + + EXAMPLES:: + + sage: Fq = GF(2) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z6, 1, 1]) + sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) + sage: t = phi.ore_polring().gen() + sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: morphism.is_isomorphism() + False + + :: + + sage: zero_morphism = End(phi)(0) + sage: zero_morphism.is_isomorphism() + False + + :: + + sage: identity_morphism = End(phi)(1) + sage: identity_morphism.is_isomorphism() + True + + :: + + sage: frobenius_endomorphism = phi.frobenius_endomorphism() + sage: frobenius_endomorphism.is_isomorphism() + False + """ + return self.is_isogeny() and self._ore_polynomial.degree() == 0 + + def ore_polynomial(self): + r""" + Return the Ore polynomial that defines the morphism. + + EXAMPLES:: + + sage: Fq = GF(2) + sage: A.<T> = Fq[] + sage: K.<z6> = Fq.extension(6) + sage: phi = DrinfeldModule(A, [z6, 1, 1]) + sage: psi = DrinfeldModule(A, [z6, z6^4 + z6^2 + 1, 1]) + sage: t = phi.ore_polring().gen() + sage: morphism = Hom(phi, psi)(t + z6^5 + z6^2 + 1) + sage: ore_pol = morphism.ore_polynomial() + sage: ore_pol + t + z6^5 + z6^2 + 1 + + :: + + sage: ore_pol * phi(T) == psi(T) * ore_pol + True + """ + return self._ore_polynomial + + @coerce_binop + def __add__(self, other): + r""" + Return the sum of this morphism and ``other``. + + INPUT: + + - ``other`` -- a morphism of Drinfeld modules in the + same category + + TESTS:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 0, 1, z]) + sage: t = phi.ore_variable() + sage: f = phi.hom(t + 1) + sage: g = T * f + sage: f + g # indirect doctest + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> z*t^3 + t^2 + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*t^3 + (3*z^2 + 2*z + 2)*t^2 + (2*z^2 + 3*z + 4)*t + z + Defn: (2*z^2 + 4*z + 4)*t^4 + (z + 1)*t^3 + t^2 + (2*z^2 + 4*z)*t + z + 1 + + We check that coercion from the function ring works:: + + sage: F = phi.frobenius_endomorphism() + sage: F + T + Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z + Defn: (z + 1)*t^3 + t^2 + z + + """ + return self.parent()(self.ore_polynomial() + other.ore_polynomial()) + + def _composition_(self, other, H): + r""" + Return the composite of this morphism and ``other``. + + EXAMPLES:: + + sage: Fq = GF(2) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 1, z, z^2]) + sage: f = phi.frobenius_endomorphism() + sage: f + Endomorphism of Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z + Defn: t^3 + sage: f * f # indirect doctest + Endomorphism of Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z + Defn: t^6 + + """ + return H(self.ore_polynomial() * other.ore_polynomial()) + + def inverse(self): + r""" + Return the inverse of this morphism. + + Only morphisms defined by constant nonzero Ore + polynomials are invertible. + + EXAMPLES:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 1, z, z^2]) + sage: f = phi.hom(2); f + Endomorphism of Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z + Defn: 2 + sage: f.inverse() + Endomorphism of Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z + Defn: 3 + + Inversion of general isomorphisms between different Drinfeld modules + also works:: + + sage: g = phi.hom(z); g + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z + To: Drinfeld module defined by T |--> z^2*t^3 + (z^2 + 2*z + 3)*t^2 + (z^2 + 3*z)*t + z + Defn: z + sage: g.inverse() + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> z^2*t^3 + (z^2 + 2*z + 3)*t^2 + (z^2 + 3*z)*t + z + To: Drinfeld module defined by T |--> z^2*t^3 + z*t^2 + t + z + Defn: 3*z^2 + 4 + + When the morphism is not invertible, an error is raised:: + + sage: F = phi.frobenius_endomorphism() + sage: F.inverse() + Traceback (most recent call last): + ... + ZeroDivisionError: this morphism is not invertible + + """ + return self.__invert__() + + def __invert__(self): + r""" + Return the inverse of this morphism. + + TESTS:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: coeffs = [z] + [K.random_element() for _ in range(10)] + sage: phi = DrinfeldModule(A, coeffs) + sage: f = phi.hom(K.random_element()) + sage: g = ~f + + sage: (f*g).is_identity() + True + sage: (g*f).is_identity() + True + + """ + if not self.is_isomorphism(): + raise ZeroDivisionError("this morphism is not invertible") + H = self.codomain().Hom(self.domain()) + return H(~(self.ore_polynomial()[0])) + + def _motive_matrix(self): + r""" + Return the matrix giving the action of this morphism + on the motives of the underlying Drinfeld modules. + + For internal use. Do not call this method directly. + + EXAMPLES:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 0, 1]) + sage: t = phi.ore_variable() + sage: u = t^2 + (2*z^2 + 3*z + 3)*t + (2*z + 3) + sage: f = phi.hom(u) + sage: f._motive_matrix() + [ T + 3 + z 3 + 3*z + 2*z^2] + [(1 + z + z^2)*T + 3 + 2*z - z^2 T + 2 - z + 2*z^2] + + """ + phi = self.domain() + phiT = phi.gen() + r = phiT.degree() + K = phi.base_over_constants_field() + S = phi.ore_polring() + Frob = S.twisting_morphism() + KT = PolynomialRing(K, name='T') + + # The first row: + # we write u = u0 + u1*phiT + u2*phiT^2 + ... + u = self.ore_polynomial() + us = [ ] + while not u.is_zero(): + u, ui = u.right_quo_rem(phiT) + us.append(ui) + l = len(us) + row = [KT([us[i][j] for i in range(l)]) for j in range(r)] + rows = [row] + + # The next rows: + # each row is obtained from the previous one by + # applying the semi-linear transformation f |-> t*f + inv = K(phiT[r]).inverse() + B = inv * phiT + T = KT.gen() + for i in range(1, r): + twist = [c.map_coefficients(Frob) for c in row] + row = [(inv*T - B[0]) * twist[-1]] + row += [twist[j-1] - B[j]*twist[-1] for j in range(1, r)] + rows.append(row) + + return matrix(KT, rows) + + def norm(self, ideal=True): + r""" + Return the norm of this isogeny. + + INPUT: + + - ``ideal`` -- a boolean (default: ``True``); if ``True``, + return the norm as an ideal in the function ring of the Drinfeld + modules; if ``False``, return the norm as an element in this + function ring (only relevant for endomorphisms) + + EXAMPLES:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 0, 1, z]) + sage: t = phi.ore_variable() + sage: f = phi.hom(t + 1) + sage: f.norm() + Principal ideal (T + 4) of Univariate Polynomial Ring in T over Finite Field of size 5 + + The norm of the Frobenius endomorphism is equal to the characteristic:: + + sage: F = phi.frobenius_endomorphism() + sage: F.norm() + Principal ideal (T^3 + 3*T + 3) of Univariate Polynomial Ring in T over Finite Field of size 5 + sage: phi.characteristic() + T^3 + 3*T + 3 + + For `a` in the underlying function ring, the norm of the + endomorphism given by `\phi_a` is `a^r` where `r` is the rank:: + + sage: g = phi.hom(T) + sage: g.norm() + Principal ideal (T^3) of Univariate Polynomial Ring in T over Finite Field of size 5 + + sage: h = phi.hom(T+1) + sage: h.norm() + Principal ideal (T^3 + 3*T^2 + 3*T + 1) of Univariate Polynomial Ring in T over Finite Field of size 5 + + For endomorphisms, the norm is not an ideal of `A` but it makes + sense as an actual element of `A`. We can get this element by passing + in the argument ``ideal=False``:: + + sage: phi.hom(2*T).norm(ideal=False) + 3*T^3 + + sage: f.norm(ideal=False) + Traceback (most recent call last): + ... + ValueError: norm is defined as an actual element only for endomorphisms + + """ + nu = self._motive_matrix().det() + # We cast to A + A = self.domain().function_ring() + if ideal: + nu = A([c.in_base() for c in nu.monic().list()]) + return A.ideal(nu) + elif self.domain() is self.codomain(): + return A([c.in_base() for c in nu.list()]) + else: + raise ValueError("norm is defined as an actual element only for endomorphisms") + + def dual_isogeny(self): + r""" + Return a dual isogeny to this morphism. + + By definition, a dual isogeny of `f : \phi \to \psi` is an + isogeny `g : \psi \to \phi` such that the composite `g \circ f` + is the multiplication by a generator of the norm of `f`. + + EXAMPLES:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 0, 1, z]) + sage: t = phi.ore_variable() + sage: f = phi.hom(t + 1) + sage: f + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> z*t^3 + t^2 + z + To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*t^3 + (3*z^2 + 2*z + 2)*t^2 + (2*z^2 + 3*z + 4)*t + z + Defn: t + 1 + sage: g = f.dual_isogeny() + sage: g + Drinfeld Module morphism: + From: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*t^3 + (3*z^2 + 2*z + 2)*t^2 + (2*z^2 + 3*z + 4)*t + z + To: Drinfeld module defined by T |--> z*t^3 + t^2 + z + Defn: z*t^2 + (4*z + 1)*t + z + 4 + + We check that `f \circ g` (resp. `g \circ f`) is the multiplication + by the norm of `f`:: + + sage: a = f.norm().gen(); a + T + 4 + sage: g * f == phi.hom(a) + True + + sage: psi = f.codomain() + sage: f * g == psi.hom(a) + True + + TESTS:: + + sage: zero = phi.hom(0) + sage: zero.dual_isogeny() + Traceback (most recent call last): + ... + ValueError: the dual isogeny of the zero morphism is not defined + + """ + if not self.is_isogeny(): + raise ValueError("the dual isogeny of the zero morphism is not defined") + nu = self._motive_matrix().det().monic() + A = self.domain().function_ring() + nu = A([c.in_base() for c in nu.list()]) + dual = self.domain()(nu) // self.ore_polynomial() + return self.codomain().hom(dual, codomain=self.domain()) + + def characteristic_polynomial(self, var='X'): + r""" + Return the characteristic polynomial of this endomorphism. + + INPUT: + + - ``var`` -- a string (default: ``X``), the name of the + variable of the characteristic polynomial + + EXAMPLES:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 0, 1, z]) + + sage: f = phi.frobenius_endomorphism() + sage: f.characteristic_polynomial() + X^3 + (T + 1)*X^2 + (2*T + 3)*X + 2*T^3 + T + 1 + + We verify, on an example, that the caracteristic polynomial + of a morphism corresponding to `\phi_a` is `(X-a)^r` where `r` + is the rank:: + + sage: g = phi.hom(T^2 + 1) + sage: chi = g.characteristic_polynomial() + sage: chi.factor() + (X + 4*T^2 + 4)^3 + + An example with another variable name:: + + sage: f.characteristic_polynomial(var='Y') + Y^3 + (T + 1)*Y^2 + (2*T + 3)*Y + 2*T^3 + T + 1 + + TESTS:: + + sage: t = phi.ore_variable() + sage: isog = phi.hom(t + 1) + sage: isog.characteristic_polynomial() + Traceback (most recent call last): + ... + ValueError: characteristic polynomial is only defined for endomorphisms + + """ + if self.domain() is not self.codomain(): + raise ValueError("characteristic polynomial is only defined for endomorphisms") + P = self._motive_matrix().charpoly() + # We cast to the correct parent + A = self.domain().function_ring() + parent = PolynomialRing(A, name=var) + return parent([A([c.in_base() for c in co.list()]) for co in P.list()]) + + def charpoly(self, var='X'): + r""" + Return the characteristic polynomial of this endomorphism. + + INPUT: + + - ``var`` -- a string (default: ``X``), the name of the + variable of the characteristic polynomial + + EXAMPLES:: + + sage: Fq = GF(5) + sage: A.<T> = Fq[] + sage: K.<z> = Fq.extension(3) + sage: phi = DrinfeldModule(A, [z, 0, 1, z]) + + sage: f = phi.frobenius_endomorphism() + sage: chi = f.charpoly() + sage: chi + X^3 + (T + 1)*X^2 + (2*T + 3)*X + 2*T^3 + T + 1 + + We check that the characteristic polynomial annihilates the + morphism (Cayley-Hamilton's theorem):: + + sage: chi(f) + Endomorphism of Drinfeld module defined by T |--> z*t^3 + t^2 + z + Defn: 0 + + We verify, on an example, that the caracteristic polynomial + of the morphism corresponding to `\phi_a` is `(X-a)^r` where `r` + is the rank:: + + sage: g = phi.hom(T^2 + 1) + sage: g.charpoly().factor() + (X + 4*T^2 + 4)^3 + + An example with another variable name:: + + sage: f.charpoly(var='Y') + Y^3 + (T + 1)*Y^2 + (2*T + 3)*Y + 2*T^3 + T + 1 + + """ + return self.characteristic_polynomial(var) diff --git a/src/sage/rings/function_field/element.pxd b/src/sage/rings/function_field/element.pxd new file mode 100644 index 00000000000..f0418634f82 --- /dev/null +++ b/src/sage/rings/function_field/element.pxd @@ -0,0 +1,10 @@ +from sage.structure.element cimport FieldElement + + +cdef class FunctionFieldElement(FieldElement): + cdef readonly object _x + cdef readonly object _matrix + + cdef FunctionFieldElement _new_c(self) + cpdef bint is_nth_power(self, n) + cpdef FunctionFieldElement nth_root(self, n) diff --git a/src/sage/rings/function_field/element.pyx b/src/sage/rings/function_field/element.pyx index 6de39e743b2..9a82b611d18 100644 --- a/src/sage/rings/function_field/element.pyx +++ b/src/sage/rings/function_field/element.pyx @@ -20,16 +20,16 @@ Arithmetic with rational functions:: Derivatives of elements in separable extensions:: - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: (y^3 + x).derivative() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.finite_rings sage.rings.function_field + sage: (y^3 + x).derivative() # needs sage.rings.finite_rings sage.rings.function_field ((x^2 + 1)/x^2)*y + (x^4 + x^3 + 1)/x^3 The divisor of an element of a global function field:: sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: y.divisor() + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.function_field + sage: y.divisor() # needs sage.rings.function_field - Place (1/x, 1/x*y) - Place (x, x*y) + 2*Place (x + 1, x*y) @@ -47,21 +47,27 @@ AUTHORS: - Kwankyu Lee (2017-04-30): added elements for global function fields """ -# **************************************************************************** -# Copyright (C) 2010 William Stein <wstein@gmail.com> -# Copyright (C) 2010 Robert Bradshaw <robertwb@math.washington.edu> -# Copyright (C) 2011-2020 Julian Rueth <julian.rueth@gmail.com> -# Copyright (C) 2011 Maarten Derickx <m.derickx.student@gmail.com> +# ***************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2010 Robert Bradshaw <robertwb@math.washington.edu> +# 2011-2020 Julian Rueth <julian.rueth@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2015 Nils Bruin +# 2016 Frรฉdรฉric Chapoton +# 2017-2019 Kwankyu Lee +# 2018-2020 Travis Scrimshaw +# 2019 Brent Baccala +# 2021 Saher Amasha # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -# **************************************************************************** +# ***************************************************************************** -from sage.structure.element cimport FieldElement, RingElement, ModuleElement, Element +from sage.structure.element cimport FieldElement from sage.misc.cachefunc import cached_method -from sage.structure.richcmp cimport richcmp, richcmp_not_equal + def is_FunctionFieldElement(x): """ @@ -104,9 +110,6 @@ cdef class FunctionFieldElement(FieldElement): sage: isinstance(t, sage.rings.function_field.element.FunctionFieldElement) True """ - cdef readonly object _x - cdef readonly object _matrix - def __reduce__(self): """ EXAMPLES:: @@ -138,8 +141,8 @@ cdef class FunctionFieldElement(FieldElement): sage: K.<a> = FunctionField(QQ) sage: R.<b> = K[] - sage: L.<b> = K.extension(b^2-a) - sage: b.__pari__() + sage: L.<b> = K.extension(b^2 - a) # needs sage.rings.function_field + sage: b.__pari__() # needs sage.rings.function_field Traceback (most recent call last): ... NotImplementedError: PARI does not support general function field elements. @@ -177,13 +180,14 @@ cdef class FunctionFieldElement(FieldElement): A rational function field:: sage: K.<t> = FunctionField(QQ) - sage: t.matrix() + sage: t.matrix() # needs sage.modules [t] - sage: (1/(t+1)).matrix() + sage: (1/(t+1)).matrix() # needs sage.modules [1/(t + 1)] Now an example in a nontrivial extension of a rational function field:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: y.matrix() @@ -195,6 +199,7 @@ cdef class FunctionFieldElement(FieldElement): An example in a relative extension, where neither function field is rational:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ) sage: R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) @@ -217,6 +222,7 @@ cdef class FunctionFieldElement(FieldElement): We show that this matrix does indeed work as expected when making a vector space from a function field:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ) sage: R.<y> = K[] sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) @@ -247,8 +253,8 @@ cdef class FunctionFieldElement(FieldElement): EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: y.trace() + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) # needs sage.rings.function_field + sage: y.trace() # needs sage.modules sage.rings.function_field x """ return self.matrix().trace() @@ -260,18 +266,18 @@ cdef class FunctionFieldElement(FieldElement): EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: y.norm() + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) # needs sage.rings.function_field + sage: y.norm() # needs sage.modules sage.rings.function_field 4*x^3 The norm is relative:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3); R.<z> = L[] - sage: M.<z> = L.extension(z^3 - y^2*z + x) - sage: z.norm() + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3); R.<z> = L[] # needs sage.rings.function_field + sage: M.<z> = L.extension(z^3 - y^2*z + x) # needs sage.rings.function_field + sage: z.norm() # needs sage.modules sage.rings.function_field -x - sage: z.norm().parent() + sage: z.norm().parent() # needs sage.modules sage.rings.function_field Function field in y defined by y^2 - x*y + 4*x^3 """ return self.matrix().determinant() @@ -320,13 +326,13 @@ cdef class FunctionFieldElement(FieldElement): EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3); R.<z> = L[] - sage: M.<z> = L.extension(z^3 - y^2*z + x) - sage: x.characteristic_polynomial('W') + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3); R.<z> = L[] # needs sage.rings.function_field + sage: M.<z> = L.extension(z^3 - y^2*z + x) # needs sage.rings.function_field + sage: x.characteristic_polynomial('W') # needs sage.modules W - x - sage: y.characteristic_polynomial('W') + sage: y.characteristic_polynomial('W') # needs sage.modules sage.rings.function_field W^2 - x*W + 4*x^3 - sage: z.characteristic_polynomial('W') + sage: z.characteristic_polynomial('W') # needs sage.modules sage.rings.function_field W^3 + (-x*y + 4*x^3)*W + x """ return self.matrix().characteristic_polynomial(*args, **kwds) @@ -341,13 +347,13 @@ cdef class FunctionFieldElement(FieldElement): EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3); R.<z> = L[] - sage: M.<z> = L.extension(z^3 - y^2*z + x) - sage: x.minimal_polynomial('W') + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3); R.<z> = L[] # needs sage.rings.function_field + sage: M.<z> = L.extension(z^3 - y^2*z + x) # needs sage.rings.function_field + sage: x.minimal_polynomial('W') # needs sage.modules W - x - sage: y.minimal_polynomial('W') + sage: y.minimal_polynomial('W') # needs sage.modules sage.rings.function_field W^2 - x*W + 4*x^3 - sage: z.minimal_polynomial('W') + sage: z.minimal_polynomial('W') # needs sage.modules sage.rings.function_field W^3 + (-x*y + 4*x^3)*W + x """ return self.matrix().minimal_polynomial(*args, **kwds) @@ -360,6 +366,7 @@ cdef class FunctionFieldElement(FieldElement): EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: y.is_integral() @@ -384,12 +391,12 @@ cdef class FunctionFieldElement(FieldElement): sage: K.<t> = FunctionField(QQ) sage: f = 1 / t - sage: f.differential() + sage: f.differential() # needs sage.modules (-1/t^2) d(t) - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x +1/x) - sage: (y^3 + x).differential() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x +1/x) # needs sage.rings.finite_rings sage.rings.function_field + sage: (y^3 + x).differential() # needs sage.modules sage.rings.finite_rings sage.rings.function_field (((x^2 + 1)/x^2)*y + (x^4 + x^3 + 1)/x^3) d(x) TESTS: @@ -398,15 +405,15 @@ cdef class FunctionFieldElement(FieldElement): sage: K.<x> = FunctionField(GF(31)) sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2 - y) + sage: L.<y> = K.extension(y^2 - x) # needs sage.rings.function_field + sage: R.<z> = L[] # needs sage.rings.function_field + sage: M.<z> = L.extension(z^2 - y) # needs sage.rings.function_field - sage: x.differential() + sage: x.differential() # needs sage.modules d(x) - sage: y.differential() + sage: y.differential() # needs sage.modules sage.rings.function_field (16/x*y) d(x) - sage: z.differential() + sage: z.differential() # needs sage.modules sage.rings.function_field (8/x*z) d(x) """ F = self.parent() @@ -424,12 +431,12 @@ cdef class FunctionFieldElement(FieldElement): sage: K.<t> = FunctionField(QQ) sage: f = (t + 1) / (t^2 - 1/3) - sage: f.derivative() + sage: f.derivative() # needs sage.modules (-t^2 - 2*t - 1/3)/(t^4 - 2/3*t^2 + 1/9) - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: (y^3 + x).derivative() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.finite_rings sage.rings.function_field + sage: (y^3 + x).derivative() # needs sage.modules sage.rings.finite_rings sage.rings.function_field ((x^2 + 1)/x^2)*y + (x^4 + x^3 + 1)/x^3 """ D = self.parent().derivation() @@ -451,14 +458,14 @@ cdef class FunctionFieldElement(FieldElement): sage: K.<t> = FunctionField(GF(2)) sage: f = t^2 - sage: f.higher_derivative(2) + sage: f.higher_derivative(2) # needs sage.modules sage.rings.function_field 1 :: - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: (y^3 + x).higher_derivative(2) + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.finite_rings sage.rings.function_field + sage: (y^3 + x).higher_derivative(2) # needs sage.modules sage.rings.finite_rings sage.rings.function_field 1/x^3*y + (x^6 + x^4 + x^3 + x^2 + x + 1)/x^5 """ D = self.parent().higher_derivation() @@ -473,7 +480,7 @@ cdef class FunctionFieldElement(FieldElement): sage: K.<x> = FunctionField(GF(2)) sage: f = 1/(x^3 + x^2 + x) - sage: f.divisor() + sage: f.divisor() # needs sage.libs.pari sage.modules 3*Place (1/x) - Place (x) - Place (x^2 + x + 1) @@ -481,8 +488,8 @@ cdef class FunctionFieldElement(FieldElement): :: sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: y.divisor() + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.function_field + sage: y.divisor() # needs sage.modules sage.rings.function_field - Place (1/x, 1/x*y) - Place (x, x*y) + 2*Place (x + 1, x*y) @@ -503,14 +510,14 @@ cdef class FunctionFieldElement(FieldElement): sage: K.<x> = FunctionField(GF(2)) sage: f = 1/(x^3 + x^2 + x) - sage: f.divisor_of_zeros() + sage: f.divisor_of_zeros() # needs sage.libs.pari sage.modules 3*Place (1/x) :: - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: (x/y).divisor_of_zeros() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.finite_rings sage.rings.function_field + sage: (x/y).divisor_of_zeros() # needs sage.modules sage.rings.finite_rings sage.rings.function_field 3*Place (x, x*y) """ if self.is_zero(): @@ -529,15 +536,15 @@ cdef class FunctionFieldElement(FieldElement): sage: K.<x> = FunctionField(GF(2)) sage: f = 1/(x^3 + x^2 + x) - sage: f.divisor_of_poles() + sage: f.divisor_of_poles() # needs sage.libs.pari sage.modules Place (x) + Place (x^2 + x + 1) :: - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: (x/y).divisor_of_poles() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.finite_rings sage.rings.function_field + sage: (x/y).divisor_of_poles() # needs sage.modules sage.rings.finite_rings sage.rings.function_field Place (1/x, 1/x*y) + 2*Place (x + 1, x*y) """ if self.is_zero(): @@ -556,14 +563,14 @@ cdef class FunctionFieldElement(FieldElement): sage: K.<x> = FunctionField(GF(2)) sage: f = 1/(x^3 + x^2 + x) - sage: f.zeros() + sage: f.zeros() # needs sage.libs.pari sage.modules [Place (1/x)] :: - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: (x/y).zeros() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.finite_rings sage.rings.function_field + sage: (x/y).zeros() # needs sage.modules sage.rings.finite_rings sage.rings.function_field [Place (x, x*y)] """ return self.divisor_of_zeros().support() @@ -576,14 +583,14 @@ cdef class FunctionFieldElement(FieldElement): sage: K.<x> = FunctionField(GF(2)) sage: f = 1/(x^3 + x^2 + x) - sage: f.poles() + sage: f.poles() # needs sage.libs.pari sage.modules [Place (x), Place (x^2 + x + 1)] :: - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: (x/y).poles() + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.finite_rings sage.rings.function_field + sage: (x/y).poles() # needs sage.modules sage.rings.finite_rings sage.rings.function_field [Place (1/x, 1/x*y), Place (x + 1, x*y)] """ return self.divisor_of_poles().support() @@ -599,17 +606,18 @@ cdef class FunctionFieldElement(FieldElement): EXAMPLES:: sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: p = L.places_infinite()[0] - sage: y.valuation(p) + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.function_field + sage: p = L.places_infinite()[0] # needs sage.modules sage.rings.function_field + sage: y.valuation(p) # needs sage.modules sage.rings.function_field -1 :: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() - sage: p = O.ideal(x-1).place() + sage: p = O.ideal(x - 1).place() sage: y.valuation(p) 0 """ @@ -641,6 +649,7 @@ cdef class FunctionFieldElement(FieldElement): :: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p, = L.places_infinite() @@ -652,15 +661,15 @@ cdef class FunctionFieldElement(FieldElement): sage: (y/x + 1).evaluate(p) 1 """ - R, fr_R, to_R = place._residue_field() + R, _, to_R = place._residue_field() v = self.valuation(place) if v > 0: return R.zero() - elif v == 0: + if v == 0: return to_R(self) - else: # v < 0 - raise ValueError('has a pole at the place') + # v < 0 + raise ValueError('has a pole at the place') cpdef bint is_nth_power(self, n): r""" @@ -710,871 +719,8 @@ cdef class FunctionFieldElement(FieldElement): sage: K.<x> = FunctionField(GF(3)) sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: L(y^27).nth_root(27) + sage: L.<y> = K.extension(y^2 - x) # needs sage.rings.function_field + sage: L(y^27).nth_root(27) # needs sage.rings.function_field y """ raise NotImplementedError("nth_root() not implemented for generic elements") - -cdef class FunctionFieldElement_polymod(FunctionFieldElement): - """ - Elements of a finite extension of a function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: x*y + 1/x^3 - x*y + 1/x^3 - """ - def __init__(self, parent, x, reduce=True): - """ - Initialize. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: TestSuite(x*y + 1/x^3).run() - """ - FieldElement.__init__(self, parent) - if reduce: - self._x = x % self._parent.polynomial() - else: - self._x = x - - def element(self): - """ - Return the underlying polynomial that represents the element. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<T> = K[] - sage: L.<y> = K.extension(T^2 - x*T + 4*x^3) - sage: f = y/x^2 + x/(x^2+1); f - 1/x^2*y + x/(x^2 + 1) - sage: f.element() - 1/x^2*y + x/(x^2 + 1) - """ - return self._x - - def _repr_(self): - """ - Return the string representation of the element. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: y._repr_() - 'y' - """ - return self._x._repr(name=self.parent().variable_name()) - - def __bool__(self): - """ - Return True if the element is not zero. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: bool(y) - True - sage: bool(L(0)) - False - sage: bool(L.coerce(L.polynomial())) - False - """ - return not not self._x - - def __hash__(self): - """ - Return the hash of the element. - - TESTS:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: len({hash(y^i+x^j) for i in [-2..2] for j in [-2..2]}) >= 24 - True - """ - return hash(self._x) - - cpdef _richcmp_(self, other, int op): - """ - Do rich comparison with the other element with respect to ``op`` - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: L(0) == 0 - True - sage: y != L(2) - True - """ - cdef FunctionFieldElement left = <FunctionFieldElement>self - cdef FunctionFieldElement right = <FunctionFieldElement>other - return richcmp(left._x, right._x, op) - - cpdef _add_(self, right): - """ - Add the element with the other element. - - INPUT: - - - ``right`` -- element - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: (2*y + x/(1+x^3)) + (3*y + 5*x*y) # indirect doctest - (5*x + 5)*y + x/(x^3 + 1) - sage: (y^2 - x*y + 4*x^3)==0 # indirect doctest - True - sage: -y+y - 0 - """ - cdef FunctionFieldElement res = self._new_c() - res._x = self._x + (<FunctionFieldElement>right)._x - return res - - cpdef _sub_(self, right): - """ - Subtract the other element from the element. - - INPUT: - - - ``right`` -- element - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: (2*y + x/(1+x^3)) - (3*y + 5*x*y) # indirect doctest - (-5*x - 1)*y + x/(x^3 + 1) - sage: y-y - 0 - """ - cdef FunctionFieldElement res = self._new_c() - res._x = self._x - (<FunctionFieldElement>right)._x - return res - - cpdef _mul_(self, right): - """ - Multiply the element with the other element. - - INPUT: - - - ``right`` -- element - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: y * (3*y + 5*x*y) # indirect doctest - (5*x^2 + 3*x)*y - 20*x^4 - 12*x^3 - """ - cdef FunctionFieldElement res = self._new_c() - res._x = (self._x * (<FunctionFieldElement>right)._x) % self._parent.polynomial() - return res - - cpdef _div_(self, right): - """ - Divide the element with the other element. - - INPUT: - - - ``right`` -- element - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: (2*y + x/(1+x^3)) / (2*y + x/(1+x^3)) # indirect doctest - 1 - sage: 1 / (y^2 - x*y + 4*x^3) # indirect doctest - Traceback (most recent call last): - ... - ZeroDivisionError: Cannot invert 0 - """ - return self * ~right - - def __invert__(self): - """ - Return the multiplicative inverse of the element. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: a = ~(2*y + 1/x); a # indirect doctest - (-1/8*x^2/(x^5 + 1/8*x^2 + 1/16))*y + (1/8*x^3 + 1/16*x)/(x^5 + 1/8*x^2 + 1/16) - sage: a*(2*y + 1/x) - 1 - """ - if self.is_zero(): - raise ZeroDivisionError("Cannot invert 0") - P = self._parent - return P(self._x.xgcd(P._polynomial)[1]) - - cpdef list list(self): - """ - Return the list of the coefficients representing the element. - - If the function field is `K[y]/(f(y))`, then return the coefficients of - the reduced presentation of the element as a polynomial in `K[y]`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) - sage: a = ~(2*y + 1/x); a - (-1/8*x^2/(x^5 + 1/8*x^2 + 1/16))*y + (1/8*x^3 + 1/16*x)/(x^5 + 1/8*x^2 + 1/16) - sage: a.list() - [(1/8*x^3 + 1/16*x)/(x^5 + 1/8*x^2 + 1/16), -1/8*x^2/(x^5 + 1/8*x^2 + 1/16)] - sage: (x*y).list() - [0, x] - """ - return self._x.padded_list(self._parent.degree()) - - cpdef FunctionFieldElement nth_root(self, n): - r""" - Return an ``n``-th root of this element in the function field. - - INPUT: - - - ``n`` -- an integer - - OUTPUT: - - Returns an element ``a`` in the function field such that this element - equals `a^n`. Raises an error if no such element exists. - - ALGORITHM: - - If ``n`` is a power of the characteristic of the field and the constant - base field is perfect, then this uses the algorithm described in - Proposition 12 of [GiTr1996]_. - - .. SEEALSO:: - - :meth:`is_nth_power` - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: L(y^3).nth_root(3) - y - sage: L(y^9).nth_root(-9) - 1/x*y - - This also works for inseparable extensions:: - - sage: K.<x> = FunctionField(GF(3)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^3 - x^2) - sage: L(x).nth_root(3)^3 - x - sage: L(x^9).nth_root(-27)^-27 - x^9 - - """ - if n == 1: - return self - if n < 0: - return (~self).nth_root(-n) - if n == 0: - if not self.is_one(): - raise ValueError("element is not a 0-th power") - return self - - # reduce to the separable case - poly = self._parent._polynomial - if not poly.gcd(poly.derivative()).is_one(): - L, from_L, to_L = self._parent.separable_model(('t', 'w')) - return from_L(to_L(self).nth_root(n)) - - constant_base_field = self._parent.constant_base_field() - p = constant_base_field.characteristic() - if p.divides(n) and constant_base_field.is_perfect(): - return self._pth_root().nth_root(n//p) - - raise NotImplementedError("nth_root() not implemented for this n") - - cpdef bint is_nth_power(self, n): - r""" - Return whether this element is an ``n``-th power in the function field. - - INPUT: - - - ``n`` -- an integer - - ALGORITHM: - - If ``n`` is a power of the characteristic of the field and the constant - base field is perfect, then this uses the algorithm described in - Proposition 12 of [GiTr1996]_. - - .. SEEALSO:: - - :meth:`nth_root` - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(4)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: y.is_nth_power(2) - False - sage: L(x).is_nth_power(2) - True - - """ - if n == 0: - return self.is_one() - if n == 1: - return True - if n < 0: - return self.is_unit() and (~self).is_nth_power(-n) - - # reduce to the separable case - poly = self._parent._polynomial - if not poly.gcd(poly.derivative()).is_one(): - L, from_L, to_L = self._parent.separable_model(('t', 'w')) - return to_L(self).is_nth_power(n) - - constant_base_field = self._parent.constant_base_field() - p = constant_base_field.characteristic() - if p.divides(n) and constant_base_field.is_perfect(): - return self._parent.derivation()(self).is_zero() and self._pth_root().is_nth_power(n//p) - - raise NotImplementedError("is_nth_power() not implemented for this n") - - cdef FunctionFieldElement _pth_root(self): - r""" - Helper method for :meth:`nth_root` and :meth:`is_nth_power` which - computes a `p`-th root if the characteristic is `p` and the constant - base field is perfect. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: (y^3).nth_root(3) # indirect doctest - y - """ - cdef Py_ssize_t deg = self._parent.degree() - if deg == 1: - return self._parent(self._x[0].nth_root(self._parent.characteristic())) - - from .function_field import RationalFunctionField - if not isinstance(self.base_ring(), RationalFunctionField): - raise NotImplementedError("only implemented for simple extensions of function fields") - # compute a representation of the generator y of the field in terms of powers of y^p - cdef Py_ssize_t i - cdef list v = [] - char = self._parent.characteristic() - cdef FunctionFieldElement_polymod yp = self._parent.gen() ** char - val = self._parent.one()._x - poly = self._parent.polynomial() - for i in range(deg): - v += val.padded_list(deg) - val = (val * yp._x) % poly - from sage.matrix.matrix_space import MatrixSpace - MS = MatrixSpace(self._parent._base, deg) - M = MS(v) - y = self._parent._base.polynomial_ring()(M.solve_left(MS.column_space()([0,1]+[0]*(deg-2))).list()) - - f = self._x(y).map_coefficients(lambda c: c.nth_root(char)) - return self._parent(f) - - -cdef class FunctionFieldElement_rational(FunctionFieldElement): - """ - Elements of a rational function field. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ); K - Rational function field in t over Rational Field - sage: t^2 + 3/2*t - t^2 + 3/2*t - sage: FunctionField(QQ,'t').gen()^3 - t^3 - """ - def __init__(self, parent, x, reduce=True): - """ - Initialize. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: x = t^3 - sage: TestSuite(x).run() - """ - FieldElement.__init__(self, parent) - self._x = x - - def __pari__(self): - r""" - Coerce the element to PARI. - - EXAMPLES:: - - sage: K.<a> = FunctionField(QQ) - sage: ((a+1)/(a-1)).__pari__() - (a + 1)/(a - 1) - - """ - return self.element().__pari__() - - def element(self): - """ - Return the underlying fraction field element that represents the element. - - EXAMPLES:: - - sage: K.<t> = FunctionField(GF(7)) - sage: t.element() - t - sage: type(t.element()) - <... 'sage.rings.fraction_field_FpT.FpTElement'> - - sage: K.<t> = FunctionField(GF(131101)) - sage: t.element() - t - sage: type(t.element()) - <... 'sage.rings.fraction_field_element.FractionFieldElement_1poly_field'> - """ - return self._x - - cpdef list list(self): - """ - Return a list with just the element. - - The list represents the element when the rational function field is - viewed as a (one-dimensional) vector space over itself. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: t.list() - [t] - """ - return [self] - - def _repr_(self): - """ - Return the string representation of the element. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: t._repr_() - 't' - """ - return repr(self._x) - - def __bool__(self): - """ - Return True if the element is not zero. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: bool(t) - True - sage: bool(K(0)) - False - sage: bool(K(1)) - True - """ - return not not self._x - - def __hash__(self): - """ - Return the hash of the element. - - TESTS: - - It would be nice if the following would produce a list of - 15 distinct hashes:: - - sage: K.<t> = FunctionField(QQ) - sage: len({hash(t^i+t^j) for i in [-2..2] for j in [i..2]}) >= 10 - True - """ - return hash(self._x) - - cpdef _richcmp_(self, other, int op): - """ - Compare the element with the other element with respect to ``op`` - - INPUT: - - - ``other`` -- element - - - ``op`` -- comparison operator - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: t > 0 - True - sage: t < t^2 - True - """ - cdef FunctionFieldElement left - cdef FunctionFieldElement right - try: - left = <FunctionFieldElement?>self - right = <FunctionFieldElement?>other - lp = left._parent - rp = right._parent - if lp != rp: - return richcmp_not_equal(lp, rp, op) - return richcmp(left._x, right._x, op) - except TypeError: - return NotImplemented - - cpdef _add_(self, right): - """ - Add the element with the other element. - - INPUT: - - - ``right`` -- element - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: t + (3*t^3) # indirect doctest - 3*t^3 + t - """ - cdef FunctionFieldElement res = self._new_c() - res._x = self._x + (<FunctionFieldElement>right)._x - return res - - cpdef _sub_(self, right): - """ - Subtract the other element from the element. - - INPUT: - - - ``right`` -- element - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: t - (3*t^3) # indirect doctest - -3*t^3 + t - """ - cdef FunctionFieldElement res = self._new_c() - res._x = self._x - (<FunctionFieldElement>right)._x - return res - - cpdef _mul_(self, right): - """ - Multiply the element with the other element - - INPUT: - - - ``right`` -- element - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: (t+1) * (t^2-1) # indirect doctest - t^3 + t^2 - t - 1 - """ - cdef FunctionFieldElement res = self._new_c() - res._x = self._x * (<FunctionFieldElement>right)._x - return res - - cpdef _div_(self, right): - """ - Divide the element with the other element - - INPUT: - - - ``right`` -- element - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: (t+1) / (t^2 - 1) # indirect doctest - 1/(t - 1) - """ - cdef FunctionFieldElement res = self._new_c() - res._parent = self._parent.fraction_field() - res._x = self._x / (<FunctionFieldElement>right)._x - return res - - def numerator(self): - """ - Return the numerator of the rational function. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: f = (t+1) / (t^2 - 1/3); f - (t + 1)/(t^2 - 1/3) - sage: f.numerator() - t + 1 - """ - return self._x.numerator() - - def denominator(self): - """ - Return the denominator of the rational function. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: f = (t+1) / (t^2 - 1/3); f - (t + 1)/(t^2 - 1/3) - sage: f.denominator() - t^2 - 1/3 - """ - return self._x.denominator() - - def valuation(self, place): - """ - Return the valuation of the rational function at the place. - - Rational function field places are associated with irreducible - polynomials. - - INPUT: - - - ``place`` -- a place or an irreducible polynomial - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: f = (t - 1)^2*(t + 1)/(t^2 - 1/3)^3 - sage: f.valuation(t - 1) - 2 - sage: f.valuation(t) - 0 - sage: f.valuation(t^2 - 1/3) - -3 - - sage: K.<x> = FunctionField(GF(2)) - sage: p = K.places_finite()[0] - sage: (1/x^2).valuation(p) - -2 - """ - from .place import FunctionFieldPlace - - if not isinstance(place, FunctionFieldPlace): - # place is an irreducible polynomial - R = self._parent._ring - return self._x.valuation(R(self._parent(place)._x)) - - prime = place.prime_ideal() - ideal = prime.ring().ideal(self) - return prime.valuation(ideal) - - def is_square(self): - """ - Return whether the element is a square. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: t.is_square() - False - sage: (t^2/4).is_square() - True - sage: f = 9 * (t+1)^6 / (t^2 - 2*t + 1); f.is_square() - True - - sage: K.<t> = FunctionField(GF(5)) - sage: (-t^2).is_square() - True - sage: (-t^2).sqrt() - 2*t - """ - return self._x.is_square() - - def sqrt(self, all=False): - """ - Return the square root of the rational function. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: f = t^2 - 2 + 1/t^2; f.sqrt() - (t^2 - 1)/t - sage: f = t^2; f.sqrt(all=True) - [t, -t] - - TESTS:: - - sage: K(4/9).sqrt() - 2/3 - sage: K(0).sqrt(all=True) - [0] - """ - if all: - return [self._parent(r) for r in self._x.sqrt(all=True)] - else: - return self._parent(self._x.sqrt()) - - cpdef bint is_nth_power(self, n): - r""" - Return whether this element is an ``n``-th power in the rational - function field. - - INPUT: - - - ``n`` -- an integer - - OUTPUT: - - Returns ``True`` if there is an element `a` in the function field such - that this element equals `a^n`. - - ALGORITHM: - - If ``n`` is a power of the characteristic of the field and the constant - base field is perfect, then this uses the algorithm described in Lemma - 3 of [GiTr1996]_. - - .. SEEALSO:: - - :meth:`nth_root` - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3)) - sage: f = (x+1)/(x-1) - sage: f.is_nth_power(1) - True - sage: f.is_nth_power(3) - False - sage: (f^3).is_nth_power(3) - True - sage: (f^9).is_nth_power(-9) - True - """ - if n == 1: - return True - if n < 0: - return (~self).is_nth_power(-n) - - p = self._parent.characteristic() - if n == p: - return self._parent.derivation()(self).is_zero() - if p.divides(n): - return self.is_nth_power(p) and self.nth_root(p).is_nth_power(n//p) - if n == 2: - return self.is_square() - - raise NotImplementedError("is_nth_power() not implemented for the given n") - - cpdef FunctionFieldElement nth_root(self, n): - r""" - Return an ``n``-th root of this element in the function field. - - INPUT: - - - ``n`` -- an integer - - OUTPUT: - - Returns an element ``a`` in the rational function field such that this - element equals `a^n`. Raises an error if no such element exists. - - ALGORITHM: - - If ``n`` is a power of the characteristic of the field and the constant - base field is perfect, then this uses the algorithm described in - Corollary 3 of [GiTr1996]_. - - .. SEEALSO:: - - :meth:`is_nth_power` - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3)) - sage: f = (x+1)/(x+2) - sage: f.nth_root(1) - (x + 1)/(x + 2) - sage: f.nth_root(3) - Traceback (most recent call last): - ... - ValueError: element is not an n-th power - sage: (f^3).nth_root(3) - (x + 1)/(x + 2) - sage: (f^9).nth_root(-9) - (x + 2)/(x + 1) - """ - if n == 0: - if not self.is_one(): - raise ValueError("element is not a 0-th power") - return self - if n == 1: - return self - if n < 0: - return (~self).nth_root(-n) - p = self._parent.characteristic() - if p.divides(n): - if not self.is_nth_power(p): - raise ValueError("element is not an n-th power") - return self._parent(self.numerator().nth_root(p) / self.denominator().nth_root(p)).nth_root(n//p) - if n == 2: - return self.sqrt() - - raise NotImplementedError("nth_root() not implemented for {}".format(n)) - - def factor(self): - """ - Factor the rational function. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: f = (t+1) / (t^2 - 1/3) - sage: f.factor() - (t + 1) * (t^2 - 1/3)^-1 - sage: (7*f).factor() - (7) * (t + 1) * (t^2 - 1/3)^-1 - sage: ((7*f).factor()).unit() - 7 - sage: (f^3).factor() - (t + 1)^3 * (t^2 - 1/3)^-3 - """ - P = self.parent() - F = self._x.factor() - from sage.structure.factorization import Factorization - return Factorization([(P(a),e) for a,e in F], unit=F.unit()) - - def inverse_mod(self, I): - """ - Return an inverse of the element modulo the integral ideal `I`, if `I` - and the element together generate the unit ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order(); I = O.ideal(x^2+1) - sage: t = O(x+1).inverse_mod(I); t - -1/2*x + 1/2 - sage: (t*(x+1) - 1) in I - True - - """ - assert len(I.gens()) == 1 - f = I.gens()[0]._x - assert f.denominator() == 1 - assert self._x.denominator() == 1 - return self.parent()(self._x.numerator().inverse_mod(f.numerator())) diff --git a/src/sage/rings/function_field/element_polymod.pyx b/src/sage/rings/function_field/element_polymod.pyx new file mode 100644 index 00000000000..9e198d0b042 --- /dev/null +++ b/src/sage/rings/function_field/element_polymod.pyx @@ -0,0 +1,407 @@ +# sage.doctest: optional - sage.rings.function_field +r""" +Elements of function fields: extension +""" + +# ***************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2010 Robert Bradshaw <robertwb@math.washington.edu> +# 2011-2020 Julian Rueth <julian.rueth@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2015 Nils Bruin +# 2016 Frรฉdรฉric Chapoton +# 2017-2019 Kwankyu Lee +# 2018-2020 Travis Scrimshaw +# 2019 Brent Baccala +# 2021 Saher Amasha +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.structure.richcmp cimport richcmp +from sage.structure.element cimport FieldElement + +from sage.rings.function_field.element cimport FunctionFieldElement + + +cdef class FunctionFieldElement_polymod(FunctionFieldElement): + """ + Elements of a finite extension of a function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: x*y + 1/x^3 + x*y + 1/x^3 + """ + def __init__(self, parent, x, reduce=True): + """ + Initialize. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: TestSuite(x*y + 1/x^3).run() + """ + FieldElement.__init__(self, parent) + if reduce: + self._x = x % self._parent.polynomial() + else: + self._x = x + + def element(self): + """ + Return the underlying polynomial that represents the element. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<T> = K[] + sage: L.<y> = K.extension(T^2 - x*T + 4*x^3) + sage: f = y/x^2 + x/(x^2+1); f + 1/x^2*y + x/(x^2 + 1) + sage: f.element() + 1/x^2*y + x/(x^2 + 1) + """ + return self._x + + def _repr_(self): + """ + Return the string representation of the element. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: y._repr_() + 'y' + """ + return self._x._repr(name=self.parent().variable_name()) + + def __bool__(self): + """ + Return ``True`` if the element is not zero. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: bool(y) + True + sage: bool(L(0)) + False + sage: bool(L.coerce(L.polynomial())) + False + """ + return not not self._x + + def __hash__(self): + """ + Return the hash of the element. + + TESTS:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: len({hash(y^i+x^j) for i in [-2..2] for j in [-2..2]}) >= 24 + True + """ + return hash(self._x) + + cpdef _richcmp_(self, other, int op): + """ + Do rich comparison with the other element with respect to ``op`` + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: L(0) == 0 + True + sage: y != L(2) + True + """ + cdef FunctionFieldElement left = <FunctionFieldElement>self + cdef FunctionFieldElement right = <FunctionFieldElement>other + return richcmp(left._x, right._x, op) + + cpdef _add_(self, right): + """ + Add the element with the other element. + + INPUT: + + - ``right`` -- element + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: (2*y + x/(1+x^3)) + (3*y + 5*x*y) # indirect doctest + (5*x + 5)*y + x/(x^3 + 1) + sage: (y^2 - x*y + 4*x^3)==0 # indirect doctest + True + sage: -y + y + 0 + """ + cdef FunctionFieldElement res = self._new_c() + res._x = self._x + (<FunctionFieldElement>right)._x + return res + + cpdef _sub_(self, right): + """ + Subtract the other element from the element. + + INPUT: + + - ``right`` -- element + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: (2*y + x/(1+x^3)) - (3*y + 5*x*y) # indirect doctest + (-5*x - 1)*y + x/(x^3 + 1) + sage: y - y + 0 + """ + cdef FunctionFieldElement res = self._new_c() + res._x = self._x - (<FunctionFieldElement>right)._x + return res + + cpdef _mul_(self, right): + """ + Multiply the element with the other element. + + INPUT: + + - ``right`` -- element + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: y * (3*y + 5*x*y) # indirect doctest + (5*x^2 + 3*x)*y - 20*x^4 - 12*x^3 + """ + cdef FunctionFieldElement res = self._new_c() + res._x = (self._x * (<FunctionFieldElement>right)._x) % self._parent.polynomial() + return res + + cpdef _div_(self, right): + """ + Divide the element with the other element. + + INPUT: + + - ``right`` -- element + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: (2*y + x/(1+x^3)) / (2*y + x/(1+x^3)) # indirect doctest + 1 + sage: 1 / (y^2 - x*y + 4*x^3) # indirect doctest + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot invert 0 + """ + return self * ~right + + def __invert__(self): + """ + Return the multiplicative inverse of the element. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: a = ~(2*y + 1/x); a # indirect doctest + (-1/8*x^2/(x^5 + 1/8*x^2 + 1/16))*y + (1/8*x^3 + 1/16*x)/(x^5 + 1/8*x^2 + 1/16) + sage: a*(2*y + 1/x) + 1 + """ + if self.is_zero(): + raise ZeroDivisionError("Cannot invert 0") + P = self._parent + return P(self._x.xgcd(P._polynomial)[1]) + + cpdef list list(self): + """ + Return the list of the coefficients representing the element. + + If the function field is `K[y]/(f(y))`, then return the coefficients of + the reduced presentation of the element as a polynomial in `K[y]`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) + sage: a = ~(2*y + 1/x); a + (-1/8*x^2/(x^5 + 1/8*x^2 + 1/16))*y + (1/8*x^3 + 1/16*x)/(x^5 + 1/8*x^2 + 1/16) + sage: a.list() + [(1/8*x^3 + 1/16*x)/(x^5 + 1/8*x^2 + 1/16), -1/8*x^2/(x^5 + 1/8*x^2 + 1/16)] + sage: (x*y).list() + [0, x] + """ + return self._x.padded_list(self._parent.degree()) + + cpdef FunctionFieldElement nth_root(self, n): + r""" + Return an ``n``-th root of this element in the function field. + + INPUT: + + - ``n`` -- an integer + + OUTPUT: + + Returns an element ``a`` in the function field such that this element + equals `a^n`. Raises an error if no such element exists. + + ALGORITHM: + + If ``n`` is a power of the characteristic of the field and the constant + base field is perfect, then this uses the algorithm described in + Proposition 12 of [GiTr1996]_. + + .. SEEALSO:: + + :meth:`is_nth_power` + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(3)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: L(y^3).nth_root(3) + y + sage: L(y^9).nth_root(-9) + 1/x*y + + This also works for inseparable extensions:: + + sage: K.<x> = FunctionField(GF(3)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^3 - x^2) + sage: L(x).nth_root(3)^3 + x + sage: L(x^9).nth_root(-27)^-27 + x^9 + + """ + if n == 1: + return self + if n < 0: + return (~self).nth_root(-n) + if n == 0: + if not self.is_one(): + raise ValueError("element is not a 0-th power") + return self + + # reduce to the separable case + poly = self._parent._polynomial + if not poly.gcd(poly.derivative()).is_one(): + _, from_L, to_L = self._parent.separable_model(('t', 'w')) + return from_L(to_L(self).nth_root(n)) + + constant_base_field = self._parent.constant_base_field() + p = constant_base_field.characteristic() + if p.divides(n) and constant_base_field.is_perfect(): + return self._pth_root().nth_root(n//p) + + raise NotImplementedError("nth_root() not implemented for this n") + + cpdef bint is_nth_power(self, n): + r""" + Return whether this element is an ``n``-th power in the function field. + + INPUT: + + - ``n`` -- an integer + + ALGORITHM: + + If ``n`` is a power of the characteristic of the field and the constant + base field is perfect, then this uses the algorithm described in + Proposition 12 of [GiTr1996]_. + + .. SEEALSO:: + + :meth:`nth_root` + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: y.is_nth_power(2) + False + sage: L(x).is_nth_power(2) + True + + """ + if n == 0: + return self.is_one() + if n == 1: + return True + if n < 0: + return self.is_unit() and (~self).is_nth_power(-n) + + # reduce to the separable case + poly = self._parent._polynomial + if not poly.gcd(poly.derivative()).is_one(): + _, _, to_L = self._parent.separable_model(('t', 'w')) + return to_L(self).is_nth_power(n) + + constant_base_field = self._parent.constant_base_field() + p = constant_base_field.characteristic() + if p.divides(n) and constant_base_field.is_perfect(): + return self._parent.derivation()(self).is_zero() and self._pth_root().is_nth_power(n//p) + + raise NotImplementedError("is_nth_power() not implemented for this n") + + cdef FunctionFieldElement _pth_root(self): + r""" + Helper method for :meth:`nth_root` and :meth:`is_nth_power` which + computes a `p`-th root if the characteristic is `p` and the constant + base field is perfect. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(3)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: (y^3).nth_root(3) # indirect doctest + y + """ + cdef Py_ssize_t deg = self._parent.degree() + if deg == 1: + return self._parent(self._x[0].nth_root(self._parent.characteristic())) + + from .function_field_rational import RationalFunctionField + if not isinstance(self.base_ring(), RationalFunctionField): + raise NotImplementedError("only implemented for simple extensions of function fields") + # compute a representation of the generator y of the field in terms of powers of y^p + cdef Py_ssize_t i + cdef list v = [] + char = self._parent.characteristic() + cdef FunctionFieldElement_polymod yp = self._parent.gen() ** char + val = self._parent.one()._x + poly = self._parent.polynomial() + for i in range(deg): + v += val.padded_list(deg) + val = (val * yp._x) % poly + from sage.matrix.matrix_space import MatrixSpace + MS = MatrixSpace(self._parent._base, deg) + M = MS(v) + y = self._parent._base.polynomial_ring()(M.solve_left(MS.column_space()([0,1]+[0]*(deg-2))).list()) + + f = self._x(y).map_coefficients(lambda c: c.nth_root(char)) + return self._parent(f) diff --git a/src/sage/rings/function_field/element_rational.pyx b/src/sage/rings/function_field/element_rational.pyx new file mode 100644 index 00000000000..0d306d6826e --- /dev/null +++ b/src/sage/rings/function_field/element_rational.pyx @@ -0,0 +1,513 @@ +r""" +Elements of function fields: rational +""" + +# ***************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2010 Robert Bradshaw <robertwb@math.washington.edu> +# 2011-2020 Julian Rueth <julian.rueth@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2015 Nils Bruin +# 2016 Frรฉdรฉric Chapoton +# 2017-2019 Kwankyu Lee +# 2018-2020 Travis Scrimshaw +# 2019 Brent Baccala +# 2021 Saher Amasha +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.structure.richcmp cimport richcmp, richcmp_not_equal +from sage.structure.element cimport FieldElement + +from sage.rings.function_field.element cimport FunctionFieldElement + + +cdef class FunctionFieldElement_rational(FunctionFieldElement): + """ + Elements of a rational function field. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ); K + Rational function field in t over Rational Field + sage: t^2 + 3/2*t + t^2 + 3/2*t + sage: FunctionField(QQ,'t').gen()^3 + t^3 + """ + def __init__(self, parent, x, reduce=True): + """ + Initialize. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: x = t^3 + sage: TestSuite(x).run() + """ + FieldElement.__init__(self, parent) + self._x = x + + def __pari__(self): + r""" + Coerce the element to PARI. + + EXAMPLES:: + + sage: K.<a> = FunctionField(QQ) + sage: ((a+1)/(a-1)).__pari__() # needs sage.libs.pari + (a + 1)/(a - 1) + + """ + return self.element().__pari__() + + def element(self): + """ + Return the underlying fraction field element that represents the element. + + EXAMPLES:: + + sage: K.<t> = FunctionField(GF(7)) + sage: t.element() + t + sage: type(t.element()) # needs sage.rings.finite_rings + <... 'sage.rings.fraction_field_FpT.FpTElement'> + + sage: K.<t> = FunctionField(GF(131101)) # needs sage.libs.pari + sage: t.element() + t + sage: type(t.element()) + <... 'sage.rings.fraction_field_element.FractionFieldElement_1poly_field'> + """ + return self._x + + cpdef list list(self): + """ + Return a list with just the element. + + The list represents the element when the rational function field is + viewed as a (one-dimensional) vector space over itself. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: t.list() + [t] + """ + return [self] + + def _repr_(self): + """ + Return the string representation of the element. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: t._repr_() + 't' + """ + return repr(self._x) + + def __bool__(self): + """ + Return ``True`` if the element is not zero. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: bool(t) + True + sage: bool(K(0)) + False + sage: bool(K(1)) + True + """ + return not not self._x + + def __hash__(self): + """ + Return the hash of the element. + + TESTS: + + It would be nice if the following would produce a list of + 15 distinct hashes:: + + sage: K.<t> = FunctionField(QQ) + sage: len({hash(t^i+t^j) for i in [-2..2] for j in [i..2]}) >= 10 + True + """ + return hash(self._x) + + cpdef _richcmp_(self, other, int op): + """ + Compare the element with the other element with respect to ``op`` + + INPUT: + + - ``other`` -- element + + - ``op`` -- comparison operator + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: t > 0 + True + sage: t < t^2 + True + """ + cdef FunctionFieldElement left + cdef FunctionFieldElement right + try: + left = <FunctionFieldElement?>self + right = <FunctionFieldElement?>other + lp = left._parent + rp = right._parent + if lp != rp: + return richcmp_not_equal(lp, rp, op) + return richcmp(left._x, right._x, op) + except TypeError: + return NotImplemented + + cpdef _add_(self, right): + """ + Add the element with the other element. + + INPUT: + + - ``right`` -- element + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: t + (3*t^3) # indirect doctest + 3*t^3 + t + """ + cdef FunctionFieldElement res = self._new_c() + res._x = self._x + (<FunctionFieldElement>right)._x + return res + + cpdef _sub_(self, right): + """ + Subtract the other element from the element. + + INPUT: + + - ``right`` -- element + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: t - (3*t^3) # indirect doctest + -3*t^3 + t + """ + cdef FunctionFieldElement res = self._new_c() + res._x = self._x - (<FunctionFieldElement>right)._x + return res + + cpdef _mul_(self, right): + """ + Multiply the element with the other element + + INPUT: + + - ``right`` -- element + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: (t+1) * (t^2-1) # indirect doctest + t^3 + t^2 - t - 1 + """ + cdef FunctionFieldElement res = self._new_c() + res._x = self._x * (<FunctionFieldElement>right)._x + return res + + cpdef _div_(self, right): + """ + Divide the element with the other element + + INPUT: + + - ``right`` -- element + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: (t+1) / (t^2 - 1) # indirect doctest + 1/(t - 1) + """ + cdef FunctionFieldElement res = self._new_c() + res._parent = self._parent.fraction_field() + res._x = self._x / (<FunctionFieldElement>right)._x + return res + + def numerator(self): + """ + Return the numerator of the rational function. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: f = (t+1) / (t^2 - 1/3); f + (t + 1)/(t^2 - 1/3) + sage: f.numerator() + t + 1 + """ + return self._x.numerator() + + def denominator(self): + """ + Return the denominator of the rational function. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: f = (t+1) / (t^2 - 1/3); f + (t + 1)/(t^2 - 1/3) + sage: f.denominator() + t^2 - 1/3 + """ + return self._x.denominator() + + def valuation(self, place): + """ + Return the valuation of the rational function at the place. + + Rational function field places are associated with irreducible + polynomials. + + INPUT: + + - ``place`` -- a place or an irreducible polynomial + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: f = (t - 1)^2*(t + 1)/(t^2 - 1/3)^3 + sage: f.valuation(t - 1) + 2 + sage: f.valuation(t) + 0 + sage: f.valuation(t^2 - 1/3) + -3 + + sage: K.<x> = FunctionField(GF(2)) + sage: p = K.places_finite()[0] # needs sage.libs.pari + sage: (1/x^2).valuation(p) # needs sage.libs.pari + -2 + """ + from .place import FunctionFieldPlace + + if not isinstance(place, FunctionFieldPlace): + # place is an irreducible polynomial + R = self._parent._ring + return self._x.valuation(R(self._parent(place)._x)) + + prime = place.prime_ideal() + ideal = prime.ring().ideal(self) + return prime.valuation(ideal) + + def is_square(self): + """ + Return whether the element is a square. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: t.is_square() + False + sage: (t^2/4).is_square() + True + sage: f = 9 * (t+1)^6 / (t^2 - 2*t + 1); f.is_square() + True + + sage: K.<t> = FunctionField(GF(5)) + sage: (-t^2).is_square() # needs sage.libs.pari + True + sage: (-t^2).sqrt() # needs sage.libs.pari + 2*t + """ + return self._x.is_square() + + def sqrt(self, all=False): + """ + Return the square root of the rational function. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: f = t^2 - 2 + 1/t^2; f.sqrt() + (t^2 - 1)/t + sage: f = t^2; f.sqrt(all=True) + [t, -t] + + TESTS:: + + sage: K(4/9).sqrt() + 2/3 + sage: K(0).sqrt(all=True) + [0] + """ + if all: + return [self._parent(r) for r in self._x.sqrt(all=True)] + else: + return self._parent(self._x.sqrt()) + + cpdef bint is_nth_power(self, n): + r""" + Return whether this element is an ``n``-th power in the rational + function field. + + INPUT: + + - ``n`` -- an integer + + OUTPUT: + + Returns ``True`` if there is an element `a` in the function field such + that this element equals `a^n`. + + ALGORITHM: + + If ``n`` is a power of the characteristic of the field and the constant + base field is perfect, then this uses the algorithm described in Lemma + 3 of [GiTr1996]_. + + .. SEEALSO:: + + :meth:`nth_root` + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3)) + sage: f = (x+1)/(x-1) + sage: f.is_nth_power(1) + True + sage: f.is_nth_power(3) + False + sage: (f^3).is_nth_power(3) + True + sage: (f^9).is_nth_power(-9) + True + """ + if n == 1: + return True + if n < 0: + return (~self).is_nth_power(-n) + + p = self._parent.characteristic() + if n == p: + return self._parent.derivation()(self).is_zero() + if p.divides(n): + return self.is_nth_power(p) and self.nth_root(p).is_nth_power(n//p) + if n == 2: + return self.is_square() + + raise NotImplementedError("is_nth_power() not implemented for the given n") + + cpdef FunctionFieldElement nth_root(self, n): + r""" + Return an ``n``-th root of this element in the function field. + + INPUT: + + - ``n`` -- an integer + + OUTPUT: + + Returns an element ``a`` in the rational function field such that this + element equals `a^n`. Raises an error if no such element exists. + + ALGORITHM: + + If ``n`` is a power of the characteristic of the field and the constant + base field is perfect, then this uses the algorithm described in + Corollary 3 of [GiTr1996]_. + + .. SEEALSO:: + + :meth:`is_nth_power` + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3)) + sage: f = (x+1)/(x+2) + sage: f.nth_root(1) + (x + 1)/(x + 2) + sage: f.nth_root(3) + Traceback (most recent call last): + ... + ValueError: element is not an n-th power + sage: (f^3).nth_root(3) + (x + 1)/(x + 2) + sage: (f^9).nth_root(-9) + (x + 2)/(x + 1) + """ + if n == 0: + if not self.is_one(): + raise ValueError("element is not a 0-th power") + return self + if n == 1: + return self + if n < 0: + return (~self).nth_root(-n) + p = self._parent.characteristic() + if p.divides(n): + if not self.is_nth_power(p): + raise ValueError("element is not an n-th power") + return self._parent(self.numerator().nth_root(p) / self.denominator().nth_root(p)).nth_root(n//p) + if n == 2: + return self.sqrt() + + raise NotImplementedError("nth_root() not implemented for {}".format(n)) + + def factor(self): + """ + Factor the rational function. + + EXAMPLES:: + + sage: # needs sage.libs.pari + sage: K.<t> = FunctionField(QQ) + sage: f = (t+1) / (t^2 - 1/3) + sage: f.factor() + (t + 1) * (t^2 - 1/3)^-1 + sage: (7*f).factor() + (7) * (t + 1) * (t^2 - 1/3)^-1 + sage: ((7*f).factor()).unit() + 7 + sage: (f^3).factor() + (t + 1)^3 * (t^2 - 1/3)^-3 + """ + P = self.parent() + F = self._x.factor() + from sage.structure.factorization import Factorization + return Factorization([(P(a),e) for a,e in F], unit=F.unit()) + + def inverse_mod(self, I): + """ + Return an inverse of the element modulo the integral ideal `I`, if `I` + and the element together generate the unit ideal. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order(); I = O.ideal(x^2 + 1) + sage: t = O(x + 1).inverse_mod(I); t + -1/2*x + 1/2 + sage: (t*(x+1) - 1) in I + True + """ + assert len(I.gens()) == 1 + f = I.gens()[0]._x + assert f.denominator() == 1 + assert self._x.denominator() == 1 + return self.parent()(self._x.numerator().inverse_mod(f.numerator())) diff --git a/src/sage/rings/function_field/extensions.py b/src/sage/rings/function_field/extensions.py index 0abe0346f72..9e42e5bff6b 100644 --- a/src/sage/rings/function_field/extensions.py +++ b/src/sage/rings/function_field/extensions.py @@ -11,22 +11,23 @@ Constant field extension of the rational function field over rational numbers:: sage: K.<x> = FunctionField(QQ) - sage: N.<a> = QuadraticField(2) - sage: L = K.extension_constant_field(N) - sage: L + sage: N.<a> = QuadraticField(2) # needs sage.rings.number_field + sage: L = K.extension_constant_field(N) # needs sage.rings.number_field + sage: L # needs sage.rings.number_field Rational function field in x over Number Field in a with defining polynomial x^2 - 2 with a = 1.4142... over its base - sage: d = (x^2 - 2).divisor() - sage: d + sage: d = (x^2 - 2).divisor() # needs sage.libs.pari sage.modules + sage: d # needs sage.libs.pari sage.modules -2*Place (1/x) + Place (x^2 - 2) - sage: L.conorm_divisor(d) + sage: L.conorm_divisor(d) # needs sage.libs.pari sage.modules sage.rings.number_field -2*Place (1/x) + Place (x - a) + Place (x + a) Constant field extension of a function field over a finite field:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[] sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) sage: E = F.extension_constant_field(GF(2^3)) @@ -52,6 +53,15 @@ """ +# **************************************************************************** +# Copyright (C) 2021-2022 Kwankyu Lee +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from sage.rings.ring_extension import RingExtension_generic from .constructor import FunctionField @@ -81,6 +91,7 @@ def __init__(self, F, k_ext): TESTS:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[] sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) sage: E = F.extension_constant_field(GF(2^3)) @@ -120,6 +131,7 @@ def top(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[] sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) sage: E = F.extension_constant_field(GF(2^3)) @@ -136,6 +148,7 @@ def defining_morphism(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[] sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) sage: E = F.extension_constant_field(GF(2^3)) @@ -161,6 +174,7 @@ def conorm_place(self, p): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[] sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) sage: E = F.extension_constant_field(GF(2^3)) @@ -197,12 +211,13 @@ def conorm_divisor(self, d): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[] sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) sage: E = F.extension_constant_field(GF(2^3)) sage: p1 = F.get_place(3) sage: p2 = F.get_place(2) - sage: c = E.conorm_divisor(2*p1+ 3*p2) + sage: c = E.conorm_divisor(2*p1 + 3*p2) sage: c1 = E.conorm_place(p1) sage: c2 = E.conorm_place(p2) sage: c == 2*c1 + 3*c2 diff --git a/src/sage/rings/function_field/function_field.py b/src/sage/rings/function_field/function_field.py index 782aa99cc42..26975773a88 100644 --- a/src/sage/rings/function_field/function_field.py +++ b/src/sage/rings/function_field/function_field.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Function Fields @@ -10,6 +9,7 @@ We create a rational function field:: + sage: # needs sage.rings.finite_rings sage: K.<x> = FunctionField(GF(5^2,'a')); K Rational function field in x over Finite Field in a of size 5^2 sage: K.genus() @@ -23,6 +23,7 @@ Then we create an extension of the rational function field, and do some simple arithmetic in it:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: R.<y> = K[] sage: L.<y> = K.extension(y^3 - (x^3 + 2*x*y + 1/x)); L Function field in y defined by y^3 + 3*x*y + (4*x^4 + 4)/x @@ -38,6 +39,7 @@ We next make an extension of the above function field, illustrating that arithmetic with a tower of three fields is fully supported:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: S.<t> = L[] sage: M.<t> = L.extension(t^2 - x*y) sage: M @@ -53,18 +55,19 @@ It is also possible to construct function fields over an imperfect base field:: - sage: N.<u> = FunctionField(K) + sage: N.<u> = FunctionField(K) # needs sage.rings.finite_rings and inseparable extension function fields:: sage: J.<x> = FunctionField(GF(5)); J Rational function field in x over Finite Field of size 5 sage: T.<v> = J[] - sage: O.<v> = J.extension(v^5 - x); O + sage: O.<v> = J.extension(v^5 - x); O # needs sage.rings.function_field Function field in v defined by v^5 + 4*x Function fields over the rational field are supported:: + sage: # needs sage.rings.function_field sage: F.<x> = FunctionField(QQ) sage: R.<Y> = F[] sage: L.<y> = F.extension(Y^2 - x^8 - 1) @@ -81,6 +84,7 @@ sage: (4*D).basis_function_space() [1, 1/x^4*y + 1/x^4] + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); _.<Y> = K[] sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) sage: O = F.maximal_order() @@ -89,6 +93,7 @@ 2*Place (x, y, (1/(x^3 + x^2 + x))*y^2) + 2*Place (x^2 + x + 1, y, (1/(x^3 + x^2 + x))*y^2) + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() @@ -99,6 +104,7 @@ Function fields over the algebraic field are supported:: + sage: # needs sage.rings.function_field sage.rings.number_field sage: K.<x> = FunctionField(QQbar); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() @@ -111,21 +117,21 @@ sage: m = L.completion(pl, prec=5) sage: m(x) I + s + O(s^5) - sage: m(y) # long time (4s) + sage: m(y) # long time (4s) -2*s + (-4 - I)*s^2 + (-15 - 4*I)*s^3 + (-75 - 23*I)*s^4 + (-413 - 154*I)*s^5 + O(s^6) - sage: m(y)^2 + m(y) + m(x) + 1/m(x) # long time (8s) + sage: m(y)^2 + m(y) + m(x) + 1/m(x) # long time (8s) O(s^5) TESTS:: sage: TestSuite(J).run() - sage: TestSuite(K).run(max_runs=256) # long time (10s) - sage: TestSuite(L).run(max_runs=8) # long time (25s) - sage: TestSuite(M).run(max_runs=8) # long time (35s) - sage: TestSuite(N).run(max_runs=8, skip = '_test_derivation') # long time (15s) - sage: TestSuite(O).run() - sage: TestSuite(R).run() - sage: TestSuite(S).run() # long time (4s) + sage: TestSuite(K).run(max_runs=256) # long time (10s) # needs sage.rings.number_field + sage: TestSuite(L).run(max_runs=8) # long time (25s) # needs sage.rings.function_field sage.rings.number_field + sage: TestSuite(M).run(max_runs=8) # long time (35s) # needs sage.rings.finite_rings sage.rings.function_field + sage: TestSuite(N).run(max_runs=8, skip='_test_derivation') # long time (15s), needs sage.rings.finite_rings + sage: TestSuite(O).run() # needs sage.rings.function_field + sage: TestSuite(R).run() # needs sage.rings.finite_rings sage.rings.function_field + sage: TestSuite(S).run() # long time (4s) # needs sage.rings.finite_rings sage.rings.function_field Global function fields ---------------------- @@ -140,6 +146,7 @@ of its maximal order and maximal infinite order, and then do arithmetic with ideals of those maximal orders:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(3)); _.<t> = K[] sage: L.<y> = K.extension(t^4 + t - x^5) sage: O = L.maximal_order() @@ -160,11 +167,12 @@ global function field, we compute all the Weierstrass places of the Klein quartic over `\GF{2}` and gap numbers for ordinary places:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x^3*Y + x) sage: L.genus() 3 - sage: L.weierstrass_places() + sage: L.weierstrass_places() # needs sage.modules [Place (1/x, 1/x^3*y^2 + 1/x), Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1), Place (x, y), @@ -175,11 +183,12 @@ Place (x^3 + x^2 + 1, y + x), Place (x^3 + x^2 + 1, y + x^2 + 1), Place (x^3 + x^2 + 1, y + x^2 + x + 1)] - sage: L.gaps() + sage: L.gaps() # needs sage.modules [1, 2, 3] The gap numbers for Weierstrass places are of course not ordinary:: + sage: # needs sage.modules sage.rings.function_field sage: p1,p2,p3 = L.weierstrass_places()[:3] sage: p1.gaps() [1, 2, 4] @@ -210,40 +219,37 @@ - Brent Baccala (2019-12-20): added function fields over number fields and QQbar """ -# **************************************************************************** -# Copyright (C) 2010 William Stein <wstein@gmail.com> -# Copyright (C) 2010 Robert Bradshaw <robertwb@math.washington.edu> -# Copyright (C) 2011-2018 Julian Rรผth <julian.rueth@gmail.com> -# Copyright (C) 2011 Maarten Derickx <m.derickx.student@gmail.com> + +# ***************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2010 Robert Bradshaw <robertwb@math.washington.edu> +# 2011-2018 Julian Rรผth <julian.rueth@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2011 Syed Ahmad Lavasani +# 2013-2014 Simon King +# 2017 Dean Bisogno +# 2017 Alyson Deines +# 2017-2019 David Roe +# 2017-2022 Kwankyu Lee +# 2018 Marc Mezzarobba +# 2018 Wilfried Luebbe +# 2019 Brent Baccala +# 2022 Frรฉdรฉric Chapoton +# 2022 Gonzalo Tornarรญa # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -# **************************************************************************** -from sage.misc.cachefunc import cached_method - -from sage.interfaces.singular import singular - -from sage.arith.functions import lcm +# ***************************************************************************** -from sage.rings.integer import Integer +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import LazyImport from sage.rings.ring import Field -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.qqbar_decorators import handle_AA_and_QQbar - -from sage.modules.free_module_element import vector - from sage.categories.homset import Hom from sage.categories.function_fields import FunctionFields from sage.structure.category_object import CategoryObject -from .differential import DifferentialsSpace, DifferentialsSpace_global - -from .element import ( - FunctionFieldElement, - FunctionFieldElement_rational, - FunctionFieldElement_polymod) def is_FunctionField(x): """ @@ -278,7 +284,7 @@ class FunctionField(Field): sage: K Rational function field in x over Rational Field """ - _differentials_space = DifferentialsSpace + _differentials_space = LazyImport('sage.rings.function_field.differential', 'DifferentialsSpace') def __init__(self, base_field, names, category=FunctionFields()): """ @@ -335,8 +341,8 @@ def some_elements(self): :: sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: L.some_elements() + sage: L.<y> = K.extension(y^2 - x) # needs sage.rings.function_field + sage: L.some_elements() # needs sage.rings.function_field [1, y, 1/x*y, @@ -370,15 +376,15 @@ def characteristic(self): sage: K.<x> = FunctionField(QQ) sage: K.characteristic() 0 - sage: K.<x> = FunctionField(QQbar) + sage: K.<x> = FunctionField(QQbar) # needs sage.rings.number_field sage: K.characteristic() 0 sage: K.<x> = FunctionField(GF(7)) sage: K.characteristic() 7 sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: L.characteristic() + sage: L.<y> = K.extension(y^2 - x) # needs sage.rings.function_field + sage: L.characteristic() # needs sage.rings.function_field 7 """ return self.constant_base_field().characteristic() @@ -408,7 +414,7 @@ def is_global(self): sage: R.<t> = FunctionField(QQ) sage: R.is_global() False - sage: R.<t> = FunctionField(QQbar) + sage: R.<t> = FunctionField(QQbar) # needs sage.rings.number_field sage: R.is_global() False sage: R.<t> = FunctionField(GF(7)) @@ -435,18 +441,18 @@ def extension(self, f, names=None): EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: K.extension(y^5 - x^3 - 3*x + x*y) + sage: K.extension(y^5 - x^3 - 3*x + x*y) # needs sage.rings.function_field Function field in y defined by y^5 + x*y - x^3 - 3*x A nonintegral defining polynomial:: sage: K.<t> = FunctionField(QQ); R.<y> = K[] - sage: K.extension(y^3 + (1/t)*y + t^3/(t+1), 'z') + sage: K.extension(y^3 + (1/t)*y + t^3/(t+1), 'z') # needs sage.rings.function_field Function field in z defined by z^3 + 1/t*z + t^3/(t + 1) The defining polynomial need not be monic or integral:: - sage: K.extension(t*y^3 + (1/t)*y + t^3/(t+1)) + sage: K.extension(t*y^3 + (1/t)*y + t^3/(t+1)) # needs sage.rings.function_field Function field in y defined by t*y^3 + 1/t*y + t^3/(t + 1) """ from . import constructor @@ -471,34 +477,35 @@ def order_with_basis(self, basis, check=True): EXAMPLES:: - sage: K.<x> = FunctionField(QQ); R.<y> = K[]; L.<y> = K.extension(y^3 + x^3 + 4*x + 1) - sage: O = L.order_with_basis([1, y, y^2]); O + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^3 + x^3 + 4*x + 1) # needs sage.rings.function_field + sage: O = L.order_with_basis([1, y, y^2]); O # needs sage.rings.function_field Order in Function field in y defined by y^3 + x^3 + 4*x + 1 - sage: O.basis() + sage: O.basis() # needs sage.rings.function_field (1, y, y^2) Note that 1 does not need to be an element of the basis, as long it is in the module spanned by it:: - sage: O = L.order_with_basis([1+y, y, y^2]); O + sage: O = L.order_with_basis([1+y, y, y^2]); O # needs sage.rings.function_field Order in Function field in y defined by y^3 + x^3 + 4*x + 1 - sage: O.basis() + sage: O.basis() # needs sage.rings.function_field (y + 1, y, y^2) The following error is raised when the module spanned by the basis is not closed under multiplication:: - sage: O = L.order_with_basis([1, x^2 + x*y, (2/3)*y^2]); O + sage: O = L.order_with_basis([1, x^2 + x*y, (2/3)*y^2]); O # needs sage.rings.function_field Traceback (most recent call last): ... ValueError: the module generated by basis (1, x*y + x^2, 2/3*y^2) must be closed under multiplication and this happens when the identity is not in the module spanned by the basis:: - sage: O = L.order_with_basis([x, x^2 + x*y, (2/3)*y^2]) + sage: O = L.order_with_basis([x, x^2 + x*y, (2/3)*y^2]) # needs sage.rings.function_field Traceback (most recent call last): ... ValueError: the identity element must be in the module spanned by basis (x, x*y + x^2, 2/3*y^2) """ - from .order import FunctionFieldOrder_basis + from .order_basis import FunctionFieldOrder_basis return FunctionFieldOrder_basis(tuple([self(a) for a in basis]), check=check) def order(self, x, check=True): @@ -513,21 +520,22 @@ def order(self, x, check=True): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^3 + x^3 + 4*x + 1) - sage: O = L.order(y); O + sage: O = L.order(y); O # needs sage.modules Order in Function field in y defined by y^3 + x^3 + 4*x + 1 - sage: O.basis() + sage: O.basis() # needs sage.modules (1, y, y^2) - sage: Z = K.order(x); Z + sage: Z = K.order(x); Z # needs sage.modules sage.rings.function_field Order in Rational function field in x over Rational Field - sage: Z.basis() + sage: Z.basis() # needs sage.modules sage.rings.function_field (1,) Orders with multiple generators are not yet supported:: - sage: Z = K.order([x,x^2]); Z + sage: Z = K.order([x, x^2]); Z # needs sage.rings.function_field Traceback (most recent call last): ... NotImplementedError @@ -558,6 +566,7 @@ def order_infinite_with_basis(self, basis, check=True): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^3 + x^3 + 4*x + 1) sage: O = L.order_infinite_with_basis([1, 1/x*y, 1/x^2*y^2]); O @@ -568,15 +577,15 @@ def order_infinite_with_basis(self, basis, check=True): Note that 1 does not need to be an element of the basis, as long it is in the module spanned by it:: - sage: O = L.order_infinite_with_basis([1+1/x*y,1/x*y, 1/x^2*y^2]); O + sage: O = L.order_infinite_with_basis([1+1/x*y,1/x*y, 1/x^2*y^2]); O # needs sage.rings.function_field Infinite order in Function field in y defined by y^3 + x^3 + 4*x + 1 - sage: O.basis() + sage: O.basis() # needs sage.rings.function_field (1/x*y + 1, 1/x*y, 1/x^2*y^2) The following error is raised when the module spanned by the basis is not closed under multiplication:: - sage: O = L.order_infinite_with_basis([1,y, 1/x^2*y^2]); O + sage: O = L.order_infinite_with_basis([1,y, 1/x^2*y^2]); O # needs sage.rings.function_field Traceback (most recent call last): ... ValueError: the module generated by basis (1, y, 1/x^2*y^2) must be closed under multiplication @@ -584,12 +593,12 @@ def order_infinite_with_basis(self, basis, check=True): and this happens when the identity is not in the module spanned by the basis:: - sage: O = L.order_infinite_with_basis([1/x,1/x*y, 1/x^2*y^2]) + sage: O = L.order_infinite_with_basis([1/x,1/x*y, 1/x^2*y^2]) # needs sage.rings.function_field Traceback (most recent call last): ... ValueError: the identity element must be in the module spanned by basis (1/x, 1/x*y, 1/x^2*y^2) """ - from .order import FunctionFieldOrderInfinite_basis + from .order_basis import FunctionFieldOrderInfinite_basis return FunctionFieldOrderInfinite_basis(tuple([self(g) for g in basis]), check=check) def order_infinite(self, x, check=True): @@ -605,17 +614,17 @@ def order_infinite(self, x, check=True): EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^3 + x^3 + 4*x + 1) - sage: L.order_infinite(y) # todo: not implemented + sage: L.<y> = K.extension(y^3 + x^3 + 4*x + 1) # needs sage.rings.function_field + sage: L.order_infinite(y) # not implemented # needs sage.modules sage.rings.function_field - sage: Z = K.order(x); Z + sage: Z = K.order(x); Z # needs sage.modules Order in Rational function field in x over Rational Field - sage: Z.basis() + sage: Z.basis() # needs sage.modules (1,) Orders with multiple generators, not yet supported:: - sage: Z = K.order_infinite([x,x^2]); Z + sage: Z = K.order_infinite([x, x^2]); Z Traceback (most recent call last): ... NotImplementedError @@ -641,7 +650,9 @@ def _coerce_map_from_(self, source): EXAMPLES:: - sage: K.<x> = FunctionField(QQ); R.<y> = K[]; L.<y> = K.extension(y^3 + x^3 + 4*x + 1) + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^3 + x^3 + 4*x + 1) sage: L.equation_order() Order in Function field in y defined by y^3 + x^3 + 4*x + 1 sage: L._coerce_map_from_(L.equation_order()) @@ -651,24 +662,24 @@ def _coerce_map_from_(self, source): sage: L._coerce_map_from_(GF(7)) sage: K.<x> = FunctionField(QQ) - sage: L.<x> = FunctionField(GaussianIntegers().fraction_field()) - sage: L.has_coerce_map_from(K) + sage: L.<x> = FunctionField(GaussianIntegers().fraction_field()) # needs sage.rings.number_field + sage: L.has_coerce_map_from(K) # needs sage.rings.number_field True sage: K.<x> = FunctionField(QQ) sage: R.<y> = K[] - sage: L.<y> = K.extension(y^3 + 1) - sage: K.<x> = FunctionField(GaussianIntegers().fraction_field()) + sage: L.<y> = K.extension(y^3 + 1) # needs sage.rings.function_field + sage: K.<x> = FunctionField(GaussianIntegers().fraction_field()) # needs sage.rings.number_field sage: R.<y> = K[] - sage: M.<y> = K.extension(y^3 + 1) - sage: M.has_coerce_map_from(L) # not tested (the constant field including into a function field is not yet known to be injective) + sage: M.<y> = K.extension(y^3 + 1) # needs sage.rings.function_field + sage: M.has_coerce_map_from(L) # not tested (the constant field including into a function field is not yet known to be injective), needs sage.rings.function_field True sage: K.<x> = FunctionField(QQ) sage: R.<I> = K[] - sage: L.<I> = K.extension(I^2 + 1) - sage: M.<x> = FunctionField(GaussianIntegers().fraction_field()) - sage: M.has_coerce_map_from(L) + sage: L.<I> = K.extension(I^2 + 1) # needs sage.rings.function_field + sage: M.<x> = FunctionField(GaussianIntegers().fraction_field()) # needs sage.rings.number_field + sage: M.has_coerce_map_from(L) # needs sage.rings.function_field sage.rings.number_field True Check that :trac:`31072` is fixed:: @@ -734,7 +745,10 @@ def _test_derivation(self, **options): tester = self._tester(**options) S = tester.some_elements() K = self.constant_base_field().some_elements() - d = self.derivation() + try: + d = self.derivation() + except ImportError: + return from itertools import product # Non-zero tester.assertFalse(d.is_zero()) @@ -766,10 +780,14 @@ def _convert_map_from_(self, R): sage: K.<x> = FunctionField(QQ) sage: R.<y> = K[] - sage: L.<y> = K.extension(y^3 + x^3 + 4*x + 1) - sage: K(L(x)) # indirect doctest + sage: L.<y> = K.extension(y^3 + x^3 + 4*x + 1) # needs sage.rings.function_field + sage: K(L(x)) # indirect doctest # needs sage.rings.function_field x """ + try: + from .function_field_polymod import FunctionField_polymod + except ImportError: + FunctionField_polymod = () if isinstance(R, FunctionField_polymod): base_conversion = self.convert_map_from(R.base_field()) if base_conversion is not None: @@ -797,21 +815,25 @@ def _intermediate_fields(self, base): [Rational function field in x over Rational Field] sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2-x) - sage: L._intermediate_fields(K) - [Function field in y defined by y^2 - x, Rational function field in x over Rational Field] + sage: L.<y> = K.extension(y^2 - x) # needs sage.rings.function_field + sage: L._intermediate_fields(K) # needs sage.rings.function_field + [Function field in y defined by y^2 - x, + Rational function field in x over Rational Field] + sage: # needs sage.rings.function_field sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2-y) + sage: M.<z> = L.extension(z^2 - y) sage: M._intermediate_fields(L) - [Function field in z defined by z^2 - y, Function field in y defined by y^2 - x] + [Function field in z defined by z^2 - y, + Function field in y defined by y^2 - x] sage: M._intermediate_fields(K) - [Function field in z defined by z^2 - y, Function field in y defined by y^2 - x, + [Function field in z defined by z^2 - y, + Function field in y defined by y^2 - x, Rational function field in x over Rational Field] TESTS:: - sage: K._intermediate_fields(M) + sage: K._intermediate_fields(M) # needs sage.rings.function_field Traceback (most recent call last): ... ValueError: field has not been constructed as a finite extension of base @@ -842,15 +864,17 @@ def rational_function_field(self): Rational function field in x over Rational Field sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2-x) - sage: L.rational_function_field() + sage: L.<y> = K.extension(y^2 - x) # needs sage.rings.function_field + sage: L.rational_function_field() # needs sage.rings.function_field Rational function field in x over Rational Field - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2-y) - sage: M.rational_function_field() + sage: R.<z> = L[] # needs sage.rings.function_field + sage: M.<z> = L.extension(z^2 - y) # needs sage.rings.function_field + sage: M.rational_function_field() # needs sage.rings.function_field Rational function field in x over Rational Field """ + from .function_field_rational import RationalFunctionField + return self if isinstance(self, RationalFunctionField) else self.base_field().rational_function_field() def valuation(self, prime): @@ -870,48 +894,50 @@ def valuation(self, prime): function field:: sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(1); v + sage: v = K.valuation(1); v # needs sage.rings.function_field (x - 1)-adic valuation - sage: v(x) + sage: v(x) # needs sage.rings.function_field 0 - sage: v(x - 1) + sage: v(x - 1) # needs sage.rings.function_field 1 A place can also be specified with an irreducible polynomial:: - sage: v = K.valuation(x - 1); v + sage: v = K.valuation(x - 1); v # needs sage.rings.function_field (x - 1)-adic valuation Similarly, for a finite non-rational place:: - sage: v = K.valuation(x^2 + 1); v + sage: v = K.valuation(x^2 + 1); v # needs sage.rings.function_field (x^2 + 1)-adic valuation - sage: v(x^2 + 1) + sage: v(x^2 + 1) # needs sage.rings.function_field 1 - sage: v(x) + sage: v(x) # needs sage.rings.function_field 0 Or for the infinite place:: - sage: v = K.valuation(1/x); v + sage: v = K.valuation(1/x); v # needs sage.rings.function_field Valuation at the infinite place - sage: v(x) + sage: v(x) # needs sage.rings.function_field -1 Instead of specifying a generator of a place, we can define a valuation on a rational function field by giving a discrete valuation on the underlying polynomial ring:: + sage: # needs sage.rings.function_field sage: R.<x> = QQ[] - sage: w = valuations.GaussValuation(R, valuations.TrivialValuation(QQ)).augmentation(x - 1, 1) + sage: u = valuations.GaussValuation(R, valuations.TrivialValuation(QQ)) + sage: w = u.augmentation(x - 1, 1) sage: v = K.valuation(w); v (x - 1)-adic valuation Note that this allows us to specify valuations which do not correspond to a place of the function field:: - sage: w = valuations.GaussValuation(R, QQ.valuation(2)) - sage: v = K.valuation(w); v + sage: w = valuations.GaussValuation(R, QQ.valuation(2)) # needs sage.rings.function_field + sage: v = K.valuation(w); v # needs sage.rings.function_field 2-adic valuation The same is possible for valuations with `v(1/x) > 0` by passing in an @@ -921,14 +947,18 @@ def valuation(self, prime): applying the substitution `x \mapsto 1/x` (here, the inverse map is also `x \mapsto 1/x`):: + sage: # needs sage.rings.function_field sage: w = valuations.GaussValuation(R, QQ.valuation(2)).augmentation(x, 1) sage: w = K.valuation(w) sage: v = K.valuation((w, K.hom([~K.gen()]), K.hom([~K.gen()]))); v - Valuation on rational function field induced by [ Gauss valuation induced by 2-adic valuation, v(x) = 1 ] (in Rational function field in x over Rational Field after x |--> 1/x) + Valuation on rational function field + induced by [ Gauss valuation induced by 2-adic valuation, v(x) = 1 ] + (in Rational function field in x over Rational Field after x |--> 1/x) Note that classical valuations at finite places or the infinite place are always normalized such that the uniformizing element has valuation 1:: + sage: # needs sage.rings.function_field sage: K.<t> = FunctionField(GF(3)) sage: M.<x> = FunctionField(K) sage: v = M.valuation(x^3 - t) @@ -940,16 +970,17 @@ def valuation(self, prime): extension of ``v`` to ``L`` still has valuation 1 on `x^3 - t` but it has valuation ``1/3`` on its uniformizing element `x - w`:: + sage: # needs sage.rings.function_field sage: R.<w> = K[] sage: L.<w> = K.extension(w^3 - t) sage: N.<x> = FunctionField(L) - sage: w = v.extension(N) # missing factorization, :trac:`16572` + sage: w = v.extension(N) # missing factorization, :trac:`16572` Traceback (most recent call last): ... NotImplementedError - sage: w(x^3 - t) # not tested + sage: w(x^3 - t) # not tested 1 - sage: w(x - w) # not tested + sage: w(x - w) # not tested 1/3 There are several ways to create valuations on extensions of rational @@ -957,16 +988,16 @@ def valuation(self, prime): sage: K.<x> = FunctionField(QQ) sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x); L + sage: L.<y> = K.extension(y^2 - x); L # needs sage.rings.function_field Function field in y defined by y^2 - x A place that has a unique extension can just be defined downstairs:: - sage: v = L.valuation(x); v + sage: v = L.valuation(x); v # needs sage.rings.function_field (x)-adic valuation """ - from sage.rings.function_field.function_field_valuation import FunctionFieldValuation + from sage.rings.function_field.valuation import FunctionFieldValuation return FunctionFieldValuation(self, prime) def space_of_differentials(self): @@ -976,13 +1007,14 @@ def space_of_differentials(self): EXAMPLES:: sage: K.<t> = FunctionField(QQ) - sage: K.space_of_differentials() + sage: K.space_of_differentials() # needs sage.modules Space of differentials of Rational function field in t over Rational Field sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) - sage: L.space_of_differentials() - Space of differentials of Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) + sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) # needs sage.rings.function_field + sage: L.space_of_differentials() # needs sage.modules sage.rings.function_field + Space of differentials of Function field in y + defined by y^3 + (4*x^3 + 1)/(x^3 + 3) """ return self._differentials_space(self) @@ -993,7 +1025,7 @@ def space_of_holomorphic_differentials(self): EXAMPLES:: sage: K.<t> = FunctionField(QQ) - sage: K.space_of_holomorphic_differentials() + sage: K.space_of_holomorphic_differentials() # needs sage.libs.pari sage.modules (Vector space of dimension 0 over Rational Field, Linear map: From: Vector space of dimension 0 over Rational Field @@ -1003,14 +1035,16 @@ def space_of_holomorphic_differentials(self): To: Vector space of dimension 0 over Rational Field) sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) - sage: L.space_of_holomorphic_differentials() + sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) # needs sage.rings.function_field + sage: L.space_of_holomorphic_differentials() # needs sage.modules sage.rings.function_field (Vector space of dimension 4 over Finite Field of size 5, Linear map: From: Vector space of dimension 4 over Finite Field of size 5 - To: Space of differentials of Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3), + To: Space of differentials of Function field in y + defined by y^3 + (4*x^3 + 1)/(x^3 + 3), Section of linear map: - From: Space of differentials of Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) + From: Space of differentials of Function field in y + defined by y^3 + (4*x^3 + 1)/(x^3 + 3) To: Vector space of dimension 4 over Finite Field of size 5) """ return self.divisor_group().zero().differential_space() @@ -1024,12 +1058,12 @@ def basis_of_holomorphic_differentials(self): EXAMPLES:: sage: K.<t> = FunctionField(QQ) - sage: K.basis_of_holomorphic_differentials() + sage: K.basis_of_holomorphic_differentials() # needs sage.libs.pari sage.modules [] sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) - sage: L.basis_of_holomorphic_differentials() + sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) # needs sage.rings.function_field + sage: L.basis_of_holomorphic_differentials() # needs sage.modules sage.rings.function_field [((x/(x^3 + 4))*y) d(x), ((1/(x^3 + 4))*y) d(x), ((x/(x^3 + 4))*y^2) d(x), @@ -1046,17 +1080,17 @@ def divisor_group(self): EXAMPLES:: sage: K.<t> = FunctionField(QQ) - sage: K.divisor_group() + sage: K.divisor_group() # needs sage.modules Divisor group of Rational function field in t over Rational Field sage: _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 - (t^3 - 1)/(t^3 - 2)) - sage: L.divisor_group() + sage: L.<y> = K.extension(Y^3 - (t^3 - 1)/(t^3 - 2)) # needs sage.rings.function_field + sage: L.divisor_group() # needs sage.modules sage.rings.function_field Divisor group of Function field in y defined by y^3 + (-t^3 + 1)/(t^3 - 2) sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) - sage: L.divisor_group() + sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) # needs sage.rings.function_field + sage: L.divisor_group() # needs sage.modules sage.rings.function_field Divisor group of Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) """ from .divisor import DivisorGroup @@ -1077,8 +1111,8 @@ def place_set(self): Set of places of Rational function field in t over Rational Field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: L.place_set() + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.function_field + sage: L.place_set() # needs sage.rings.function_field Set of places of Function field in y defined by y^2 + y + (x^2 + 1)/x """ from .place import PlaceSet @@ -1102,6 +1136,7 @@ def completion(self, place, name=None, prec=None, gen_name=None): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p = L.places_finite()[0] @@ -1109,11 +1144,12 @@ def completion(self, place, name=None, prec=None, gen_name=None): Completion map: From: Function field in y defined by y^2 + y + (x^2 + 1)/x To: Laurent Series Ring in s over Finite Field of size 2 - sage: m(x,10) + sage: m(x, 10) s^2 + s^3 + s^4 + s^5 + s^7 + s^8 + s^9 + s^10 + O(s^12) - sage: m(y,10) + sage: m(y, 10) s^-1 + 1 + s^3 + s^5 + s^7 + O(s^9) + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p = L.places_finite()[0] @@ -1121,40 +1157,41 @@ def completion(self, place, name=None, prec=None, gen_name=None): Completion map: From: Function field in y defined by y^2 + y + (x^2 + 1)/x To: Laurent Series Ring in s over Finite Field of size 2 - sage: m(x,10) + sage: m(x, 10) s^2 + s^3 + s^4 + s^5 + s^7 + s^8 + s^9 + s^10 + O(s^12) - sage: m(y,10) + sage: m(y, 10) s^-1 + 1 + s^3 + s^5 + s^7 + O(s^9) sage: K.<x> = FunctionField(GF(2)) - sage: p = K.places_finite()[0]; p + sage: p = K.places_finite()[0]; p # needs sage.libs.pari Place (x) - sage: m = K.completion(p); m + sage: m = K.completion(p); m # needs sage.rings.function_field Completion map: From: Rational function field in x over Finite Field of size 2 To: Laurent Series Ring in s over Finite Field of size 2 - sage: m(1/(x+1)) + sage: m(1/(x+1)) # needs sage.rings.function_field 1 + s + s^2 + s^3 + s^4 + s^5 + s^6 + s^7 + s^8 + s^9 + s^10 + s^11 + s^12 + s^13 + s^14 + s^15 + s^16 + s^17 + s^18 + s^19 + O(s^20) sage: p = K.place_infinite(); p Place (1/x) - sage: m = K.completion(p); m + sage: m = K.completion(p); m # needs sage.rings.function_field Completion map: From: Rational function field in x over Finite Field of size 2 To: Laurent Series Ring in s over Finite Field of size 2 - sage: m(x) + sage: m(x) # needs sage.rings.function_field s^-1 + O(s^19) - sage: m = K.completion(p, prec=infinity); m + sage: m = K.completion(p, prec=infinity); m # needs sage.rings.function_field Completion map: From: Rational function field in x over Finite Field of size 2 To: Lazy Laurent Series Ring in s over Finite Field of size 2 - sage: f = m(x); f + sage: f = m(x); f # needs sage.rings.function_field s^-1 + ... - sage: f.coefficient(100) + sage: f.coefficient(100) # needs sage.rings.function_field 0 + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 - x) sage: O = L.maximal_order() @@ -1169,12 +1206,14 @@ def completion(self, place, name=None, prec=None, gen_name=None): sage: ye^2 - xe == 0 True + sage: # needs sage.rings.function_field sage: decomp2 = O.decomposition(K.maximal_order().ideal(x^2 + 1)) sage: pls2 = decomp2[0][0].place() sage: m = L.completion(pls2); m Completion map: From: Function field in y defined by y^2 - x - To: Laurent Series Ring in s over Number Field in a with defining polynomial x^4 + 2*x^2 + 4*x + 2 + To: Laurent Series Ring in s over + Number Field in a with defining polynomial x^4 + 2*x^2 + 4*x + 2 sage: xe = m(x) sage: ye = m(y) sage: ye^2 - xe == 0 @@ -1193,6 +1232,7 @@ def extension_constant_field(self, k): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: F.<y> = K.extension(Y^2 + Y + x + 1/x) sage: E = F.extension_constant_field(GF(2^4)) @@ -1203,3478 +1243,3 @@ def extension_constant_field(self, k): """ from .extensions import ConstantFieldExtension return ConstantFieldExtension(self, k) - - -class FunctionField_polymod(FunctionField): - """ - Function fields defined by a univariate polynomial, as an extension of the - base field. - - INPUT: - - - ``polynomial`` -- univariate polynomial over a function field - - - ``names`` -- tuple of length 1 or string; variable names - - - ``category`` -- category (default: category of function fields) - - EXAMPLES: - - We make a function field defined by a degree 5 polynomial over the - rational function field over the rational numbers:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L - Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x - - We next make a function field over the above nontrivial function - field L:: - - sage: S.<z> = L[] - sage: M.<z> = L.extension(z^2 + y*z + y); M - Function field in z defined by z^2 + y*z + y - sage: 1/z - ((-x/(x^4 + 1))*y^4 + 2*x^2/(x^4 + 1))*z - 1 - sage: z * (1/z) - 1 - - We drill down the tower of function fields:: - - sage: M.base_field() - Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x - sage: M.base_field().base_field() - Rational function field in x over Rational Field - sage: M.base_field().base_field().constant_field() - Rational Field - sage: M.constant_base_field() - Rational Field - - .. WARNING:: - - It is not checked if the polynomial used to define the function field is irreducible - Hence it is not guaranteed that this object really is a field! - This is illustrated below. - - :: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(x^2 - y^2) - sage: (y - x)*(y + x) - 0 - sage: 1/(y - x) - 1 - sage: y - x == 0; y + x == 0 - False - False - """ - Element = FunctionFieldElement_polymod - - def __init__(self, polynomial, names, category=None): - """ - Create a function field defined as an extension of another function - field by adjoining a root of a univariate polynomial. - - EXAMPLES: - - We create an extension of a function field:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L = K.extension(y^5 - x^3 - 3*x + x*y); L - Function field in y defined by y^5 + x*y - x^3 - 3*x - sage: TestSuite(L).run(max_runs=512) # long time (15s) - - We can set the variable name, which doesn't have to be y:: - - sage: L.<w> = K.extension(y^5 - x^3 - 3*x + x*y); L - Function field in w defined by w^5 + x*w - x^3 - 3*x - - TESTS: - - Test that :trac:`17033` is fixed:: - - sage: K.<t> = FunctionField(QQ) - sage: R.<x> = QQ[] - sage: M.<z> = K.extension(x^7-x-t) - sage: M(x) - z - sage: M('z') - z - sage: M('x') - Traceback (most recent call last): - ... - TypeError: unable to evaluate 'x' in Fraction Field of Univariate - Polynomial Ring in t over Rational Field - """ - from sage.rings.polynomial.polynomial_element import is_Polynomial - if polynomial.parent().ngens()>1 or not is_Polynomial(polynomial): - raise TypeError("polynomial must be univariate a polynomial") - if names is None: - names = (polynomial.variable_name(), ) - elif names != polynomial.variable_name(): - polynomial = polynomial.change_variable_name(names) - if polynomial.degree() <= 0: - raise ValueError("polynomial must have positive degree") - base_field = polynomial.base_ring() - if not isinstance(base_field, FunctionField): - raise TypeError("polynomial must be over a FunctionField") - - self._base_field = base_field - self._polynomial = polynomial - - FunctionField.__init__(self, base_field, names=names, - category=FunctionFields().or_subcategory(category)) - - from .place import FunctionFieldPlace_polymod - self._place_class = FunctionFieldPlace_polymod - - self._hash = hash(polynomial) - self._ring = self._polynomial.parent() - - self._populate_coercion_lists_(coerce_list=[base_field, self._ring]) - self._gen = self(self._ring.gen()) - - def __hash__(self): - """ - Return hash of the function field. - - The hash value is equal to the hash of the defining polynomial. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L = K.extension(y^5 - x^3 - 3*x + x*y) - sage: hash(L) == hash(L.polynomial()) - True - """ - return self._hash - - def _element_constructor_(self, x): - r""" - Make ``x`` into an element of the function field, possibly not canonically. - - INPUT: - - - ``x`` -- element - - TESTS:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: L._element_constructor_(L.polynomial_ring().gen()) - y - """ - if isinstance(x, FunctionFieldElement): - return self.element_class(self, self._ring(x.element())) - return self.element_class(self, self._ring(x)) - - def gen(self, n=0): - """ - Return the `n`-th generator of the function field. By default, `n` is 0; any other - value of `n` leads to an error. The generator is the class of `y`, if we view - the function field as being presented as `K[y]/(f(y))`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: L.gen() - y - sage: L.gen(1) - Traceback (most recent call last): - ... - IndexError: there is only one generator - """ - if n != 0: - raise IndexError("there is only one generator") - return self._gen - - def ngens(self): - """ - Return the number of generators of the function field over its base - field. This is by definition 1. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: L.ngens() - 1 - """ - return 1 - - def _to_base_field(self, f): - r""" - Return ``f`` as an element of the :meth:`base_field`. - - INPUT: - - - ``f`` -- element of the function field which lies in the base - field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: L._to_base_field(L(x)) - x - sage: L._to_base_field(y) - Traceback (most recent call last): - ... - ValueError: y is not an element of the base field - - TESTS: - - Verify that :trac:`21872` has been resolved:: - - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2 - y) - - sage: M(1) in QQ - True - sage: M(y) in L - True - sage: M(x) in K - True - sage: z in K - False - """ - K = self.base_field() - if f.element().is_constant(): - return K(f.element()) - raise ValueError("%r is not an element of the base field"%(f,)) - - def _to_constant_base_field(self, f): - """ - Return ``f`` as an element of the :meth:`constant_base_field`. - - INPUT: - - - ``f`` -- element of the rational function field which is a - constant - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: L._to_constant_base_field(L(1)) - 1 - sage: L._to_constant_base_field(y) - Traceback (most recent call last): - ... - ValueError: y is not an element of the base field - - TESTS: - - Verify that :trac:`21872` has been resolved:: - - sage: L(1) in QQ - True - sage: y in QQ - False - """ - return self.base_field()._to_constant_base_field(self._to_base_field(f)) - - def monic_integral_model(self, names=None): - """ - Return a function field isomorphic to this field but which is an - extension of a rational function field with defining polynomial that is - monic and integral over the constant base field. - - INPUT: - - - ``names`` -- a string or a tuple of up to two strings (default: - ``None``), the name of the generator of the field, and the name of - the generator of the underlying rational function field (if a tuple); - if not given, then the names are chosen automatically. - - OUTPUT: - - A triple ``(F,f,t)`` where ``F`` is a function field, ``f`` is an - isomorphism from ``F`` to this field, and ``t`` is the inverse of - ``f``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(x^2*y^5 - 1/x); L - Function field in y defined by x^2*y^5 - 1/x - sage: A, from_A, to_A = L.monic_integral_model('z') - sage: A - Function field in z defined by z^5 - x^12 - sage: from_A - Function Field morphism: - From: Function field in z defined by z^5 - x^12 - To: Function field in y defined by x^2*y^5 - 1/x - Defn: z |--> x^3*y - x |--> x - sage: to_A - Function Field morphism: - From: Function field in y defined by x^2*y^5 - 1/x - To: Function field in z defined by z^5 - x^12 - Defn: y |--> 1/x^3*z - x |--> x - sage: to_A(y) - 1/x^3*z - sage: from_A(to_A(y)) - y - sage: from_A(to_A(1/y)) - x^3*y^4 - sage: from_A(to_A(1/y)) == 1/y - True - - This also works for towers of function fields:: - - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2*y - 1/x) - sage: M.monic_integral_model() - (Function field in z_ defined by z_^10 - x^18, Function Field morphism: - From: Function field in z_ defined by z_^10 - x^18 - To: Function field in z defined by y*z^2 - 1/x - Defn: z_ |--> x^2*z - x |--> x, Function Field morphism: - From: Function field in z defined by y*z^2 - 1/x - To: Function field in z_ defined by z_^10 - x^18 - Defn: z |--> 1/x^2*z_ - y |--> 1/x^15*z_^8 - x |--> x) - - TESTS: - - If the field is already a monic integral extension, then it is returned - unchanged:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2-x) - sage: L.monic_integral_model() - (Function field in y defined by y^2 - x, Function Field endomorphism of Function field in y defined by y^2 - x - Defn: y |--> y - x |--> x, Function Field endomorphism of Function field in y defined by y^2 - x - Defn: y |--> y - x |--> x) - - unless ``names`` does not match with the current names:: - - sage: L.monic_integral_model(names=('yy','xx')) - (Function field in yy defined by yy^2 - xx, Function Field morphism: - From: Function field in yy defined by yy^2 - xx - To: Function field in y defined by y^2 - x - Defn: yy |--> y - xx |--> x, Function Field morphism: - From: Function field in y defined by y^2 - x - To: Function field in yy defined by yy^2 - xx - Defn: y |--> yy - x |--> xx) - - """ - if names: - if not isinstance(names, tuple): - names = (names,) - if len(names) > 2: - raise ValueError("names must contain at most 2 entries") - - if self.base_field() is not self.rational_function_field(): - L,from_L,to_L = self.simple_model() - ret,ret_to_L,L_to_ret = L.monic_integral_model(names) - from_ret = ret.hom( [from_L(ret_to_L(ret.gen())), from_L(ret_to_L(ret.base_field().gen()))] ) - to_ret = self.hom( [L_to_ret(to_L(k.gen())) for k in self._intermediate_fields(self.rational_function_field())] ) - return ret, from_ret, to_ret - else: - if self.polynomial().is_monic() and all(c.denominator().is_one() for c in self.polynomial()): - # self is already monic and integral - if names is None or names == (): - names = (self.variable_name(),) - return self.change_variable_name(names) - else: - if not names: - names = (self.variable_name()+"_",) - if len(names) == 1: - names = (names[0], self.rational_function_field().variable_name()) - - g, d = self._make_monic_integral(self.polynomial()) - K,from_K,to_K = self.base_field().change_variable_name(names[1]) - g = g.map_coefficients(to_K) - ret = K.extension(g, names=names[0]) - from_ret = ret.hom([self.gen() * d, self.base_field().gen()]) - to_ret = self.hom([ret.gen() / d, ret.base_field().gen()]) - return ret, from_ret, to_ret - - def _make_monic_integral(self, f): - """ - Return a monic integral polynomial `g` and an element `d` of the base - field such that `g(y*d)=0` where `y` is a root of `f`. - - INPUT: - - - ``f`` -- polynomial - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(x^2*y^5 - 1/x) - sage: g, d = L._make_monic_integral(L.polynomial()); g,d - (y^5 - x^12, x^3) - sage: (y*d).is_integral() - True - sage: g.is_monic() - True - sage: g(y*d) - 0 - """ - R = f.base_ring() - if not isinstance(R, RationalFunctionField): - raise NotImplementedError - - # make f monic - n = f.degree() - c = f.leading_coefficient() - if c != 1: - f = f / c - - # find lcm of denominators - # would be good to replace this by minimal... - d = lcm([b.denominator() for b in f.list() if b]) - if d != 1: - x = f.parent().gen() - g = (d**n) * f(x/d) - else: - g = f - return g, d - - def constant_field(self): - """ - Return the algebraic closure of the constant field of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^5 - x) - sage: L.constant_field() - Traceback (most recent call last): - ... - NotImplementedError - """ - raise NotImplementedError - - def constant_base_field(self): - """ - Return the base constant field of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L - Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x - sage: L.constant_base_field() - Rational Field - sage: S.<z> = L[] - sage: M.<z> = L.extension(z^2 - y) - sage: M.constant_base_field() - Rational Field - """ - return self.base_field().constant_base_field() - - @cached_method(key=lambda self, base: self.base_field() if base is None else base) - def degree(self, base=None): - """ - Return the degree of the function field over the function field ``base``. - - INPUT: - - - ``base`` -- a function field (default: ``None``), a function field - from which this field has been constructed as a finite extension. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L - Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x - sage: L.degree() - 5 - sage: L.degree(L) - 1 - - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2 - y) - sage: M.degree(L) - 2 - sage: M.degree(K) - 10 - - TESTS:: - - sage: L.degree(M) - Traceback (most recent call last): - ... - ValueError: base must be the rational function field itself - - """ - if base is None: - base = self.base_field() - if base is self: - from sage.rings.integer_ring import ZZ - return ZZ(1) - return self._polynomial.degree() * self.base_field().degree(base) - - def _repr_(self): - """ - Return the string representation of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: L._repr_() - 'Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x' - """ - return "Function field in %s defined by %s"%(self.variable_name(), self._polynomial) - - def base_field(self): - """ - Return the base field of the function field. This function field is - presented as `L = K[y]/(f(y))`, and the base field is by definition the - field `K`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: L.base_field() - Rational function field in x over Rational Field - """ - return self._base_field - - def random_element(self, *args, **kwds): - """ - Create a random element of the function field. Parameters are passed - onto the random_element method of the base_field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - (x^2 + x)) - sage: L.random_element() # random - ((x^2 - x + 2/3)/(x^2 + 1/3*x - 1))*y^2 + ((-1/4*x^2 + 1/2*x - 1)/(-5/2*x + 2/3))*y - + (-1/2*x^2 - 4)/(-12*x^2 + 1/2*x - 1/95) - """ - return self(self._ring.random_element(degree=self.degree(), *args, **kwds)) - - def polynomial(self): - """ - Return the univariate polynomial that defines the function field, that - is, the polynomial `f(y)` so that the function field is of the form - `K[y]/(f(y))`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: L.polynomial() - y^5 - 2*x*y + (-x^4 - 1)/x - """ - return self._polynomial - - def is_separable(self, base=None): - r""" - Return whether this is a separable extension of ``base``. - - INPUT: - - - ``base`` -- a function field from which this field has been created - as an extension or ``None`` (default: ``None``); if ``None``, then - return whether this is a separable extension over its base field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: L.is_separable() - False - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^3 - y) - sage: M.is_separable() - True - sage: M.is_separable(K) - False - - sage: K.<x> = FunctionField(GF(5)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: L.is_separable() - True - - sage: K.<x> = FunctionField(GF(5)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^5 - 1) - sage: L.is_separable() - False - - """ - if base is None: - base = self.base_field() - for k in self._intermediate_fields(base)[:-1]: - f = k.polynomial() - g = f.derivative() - if f.gcd(g).degree() != 0: - return False - return True - - def polynomial_ring(self): - """ - Return the polynomial ring used to represent elements of the - function field. If we view the function field as being presented - as `K[y]/(f(y))`, then this function returns the ring `K[y]`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: L.polynomial_ring() - Univariate Polynomial Ring in y over Rational function field in x over Rational Field - """ - return self._ring - - @cached_method(key=lambda self, base, basis, map: (self.base_field() if base is None else base, basis, map)) - def free_module(self, base=None, basis=None, map=True): - """ - Return a vector space and isomorphisms from the field to and from the - vector space. - - This function allows us to identify the elements of this field with - elements of a vector space over the base field, which is useful for - representation and arithmetic with orders, ideals, etc. - - INPUT: - - - ``base`` -- a function field (default: ``None``), the returned vector - space is over this subfield `R`, which defaults to the base field of this - function field. - - - ``basis`` -- a basis for this field over the base. - - - ``maps`` -- boolean (default ``True``), whether to return - `R`-linear maps to and from `V`. - - OUTPUT: - - - a vector space over the base function field - - - an isomorphism from the vector space to the field (if requested) - - - an isomorphism from the field to the vector space (if requested) - - EXAMPLES: - - We define a function field:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L - Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x - - We get the vector spaces, and maps back and forth:: - - sage: V, from_V, to_V = L.free_module() - sage: V - Vector space of dimension 5 over Rational function field in x over Rational Field - sage: from_V - Isomorphism: - From: Vector space of dimension 5 over Rational function field in x over Rational Field - To: Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x - sage: to_V - Isomorphism: - From: Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x - To: Vector space of dimension 5 over Rational function field in x over Rational Field - - We convert an element of the vector space back to the function field:: - - sage: from_V(V.1) - y - - We define an interesting element of the function field:: - - sage: a = 1/L.0; a - (x/(x^4 + 1))*y^4 - 2*x^2/(x^4 + 1) - - We convert it to the vector space, and get a vector over the base field:: - - sage: to_V(a) - (-2*x^2/(x^4 + 1), 0, 0, 0, x/(x^4 + 1)) - - We convert to and back, and get the same element:: - - sage: from_V(to_V(a)) == a - True - - In the other direction:: - - sage: v = x*V.0 + (1/x)*V.1 - sage: to_V(from_V(v)) == v - True - - And we show how it works over an extension of an extension field:: - - sage: R2.<z> = L[]; M.<z> = L.extension(z^2 -y) - sage: M.free_module() - (Vector space of dimension 2 over Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x, Isomorphism: - From: Vector space of dimension 2 over Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x - To: Function field in z defined by z^2 - y, Isomorphism: - From: Function field in z defined by z^2 - y - To: Vector space of dimension 2 over Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x) - - We can also get the vector space of ``M`` over ``K``:: - - sage: M.free_module(K) - (Vector space of dimension 10 over Rational function field in x over Rational Field, Isomorphism: - From: Vector space of dimension 10 over Rational function field in x over Rational Field - To: Function field in z defined by z^2 - y, Isomorphism: - From: Function field in z defined by z^2 - y - To: Vector space of dimension 10 over Rational function field in x over Rational Field) - - """ - if basis is not None: - raise NotImplementedError - from .maps import MapVectorSpaceToFunctionField, MapFunctionFieldToVectorSpace - if base is None: - base = self.base_field() - degree = self.degree(base) - V = base**degree - if not map: - return V - from_V = MapVectorSpaceToFunctionField(V, self) - to_V = MapFunctionFieldToVectorSpace(self, V) - return (V, from_V, to_V) - - def maximal_order(self): - """ - Return the maximal order of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: L.maximal_order() - Maximal order of Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x - """ - from .order import FunctionFieldMaximalOrder_polymod - return FunctionFieldMaximalOrder_polymod(self) - - def maximal_order_infinite(self): - """ - Return the maximal infinite order of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: L.maximal_order_infinite() - Maximal infinite order of Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: F.maximal_order_infinite() - Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2 - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: L.maximal_order_infinite() - Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x - """ - from .order import FunctionFieldMaximalOrderInfinite_polymod - return FunctionFieldMaximalOrderInfinite_polymod(self) - - def different(self): - """ - Return the different of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) - sage: F.different() - 2*Place (x, (1/(x^3 + x^2 + x))*y^2) - + 2*Place (x^2 + x + 1, (1/(x^3 + x^2 + x))*y^2) - """ - O = self.maximal_order() - Oinf = self.maximal_order_infinite() - return O.different().divisor() + Oinf.different().divisor() - - def equation_order(self): - """ - Return the equation order of the function field. - - If we view the function field as being presented as `K[y]/(f(y))`, then - the order generated by the class of `y` is returned. If `f` - is not monic, then :meth:`_make_monic_integral` is called, and instead - we get the order generated by some integral multiple of a root of `f`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: O = L.equation_order() - sage: O.basis() - (1, x*y, x^2*y^2, x^3*y^3, x^4*y^4) - - We try an example, in which the defining polynomial is not - monic and is not integral:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(x^2*y^5 - 1/x); L - Function field in y defined by x^2*y^5 - 1/x - sage: O = L.equation_order() - sage: O.basis() - (1, x^3*y, x^6*y^2, x^9*y^3, x^12*y^4) - """ - d = self._make_monic_integral(self.polynomial())[1] - return self.order(d*self.gen(), check=False) - - def hom(self, im_gens, base_morphism=None): - """ - Create a homomorphism from the function field to another function field. - - INPUT: - - - ``im_gens`` -- list of images of the generators of the function field - and of successive base rings. - - - ``base_morphism`` -- homomorphism of the base ring, after the - ``im_gens`` are used. Thus if ``im_gens`` has length 2, then - ``base_morphism`` should be a morphism from the base ring of the base - ring of the function field. - - EXAMPLES: - - We create a rational function field, and a quadratic extension of it:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - - We make the field automorphism that sends y to -y:: - - sage: f = L.hom(-y); f - Function Field endomorphism of Function field in y defined by y^2 - x^3 - 1 - Defn: y |--> -y - - Evaluation works:: - - sage: f(y*x - 1/x) - -x*y - 1/x - - We try to define an invalid morphism:: - - sage: f = L.hom(y+1) - Traceback (most recent call last): - ... - ValueError: invalid morphism - - We make a morphism of the base rational function field:: - - sage: phi = K.hom(x+1); phi - Function Field endomorphism of Rational function field in x over Rational Field - Defn: x |--> x + 1 - sage: phi(x^3 - 3) - x^3 + 3*x^2 + 3*x - 2 - sage: (x+1)^3-3 - x^3 + 3*x^2 + 3*x - 2 - - We make a morphism by specifying where the generators and the - base generators go:: - - sage: L.hom([-y, x]) - Function Field endomorphism of Function field in y defined by y^2 - x^3 - 1 - Defn: y |--> -y - x |--> x - - You can also specify a morphism on the base:: - - sage: R1.<q> = K[] - sage: L1.<q> = K.extension(q^2 - (x+1)^3 - 1) - sage: L.hom(q, base_morphism=phi) - Function Field morphism: - From: Function field in y defined by y^2 - x^3 - 1 - To: Function field in q defined by q^2 - x^3 - 3*x^2 - 3*x - 2 - Defn: y |--> q - x |--> x + 1 - - We make another extension of a rational function field:: - - sage: K2.<t> = FunctionField(QQ); R2.<w> = K2[] - sage: L2.<w> = K2.extension((4*w)^2 - (t+1)^3 - 1) - - We define a morphism, by giving the images of generators:: - - sage: f = L.hom([4*w, t+1]); f - Function Field morphism: - From: Function field in y defined by y^2 - x^3 - 1 - To: Function field in w defined by 16*w^2 - t^3 - 3*t^2 - 3*t - 2 - Defn: y |--> 4*w - x |--> t + 1 - - Evaluation works, as expected:: - - sage: f(y+x) - 4*w + t + 1 - sage: f(x*y + x/(x^2+1)) - (4*t + 4)*w + (t + 1)/(t^2 + 2*t + 2) - - We make another extension of a rational function field:: - - sage: K3.<yy> = FunctionField(QQ); R3.<xx> = K3[] - sage: L3.<xx> = K3.extension(yy^2 - xx^3 - 1) - - This is the function field L with the generators exchanged. We define a morphism to L:: - - sage: g = L3.hom([x,y]); g - Function Field morphism: - From: Function field in xx defined by -xx^3 + yy^2 - 1 - To: Function field in y defined by y^2 - x^3 - 1 - Defn: xx |--> x - yy |--> y - - """ - if not isinstance(im_gens, (list,tuple)): - im_gens = [im_gens] - if len(im_gens) == 0: - raise ValueError("no images specified") - - if len(im_gens) > 1: - base_morphism = self.base_field().hom(im_gens[1:], base_morphism) - - # the codomain of this morphism is the field containing all the im_gens - codomain = im_gens[0].parent() - if base_morphism is not None: - from sage.categories.pushout import pushout - codomain = pushout(codomain, base_morphism.codomain()) - - from .maps import FunctionFieldMorphism_polymod - return FunctionFieldMorphism_polymod(self.Hom(codomain), im_gens[0], base_morphism) - - @cached_method - def genus(self): - """ - Return the genus of the function field. - - For now, the genus is computed using Singular. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) - sage: L.genus() - 3 - """ - # Unfortunately Singular can not compute the genus with the - # polynomial_ring()._singular_ object because genus method only accepts - # a ring of transcendental degree 2 over a prime field not a ring of - # transcendental degree 1 over a rational function field of one variable - - if (isinstance(self._base_field, RationalFunctionField) and - self._base_field.constant_field().is_prime_field()): - - # making the auxiliary ring which only has polynomials - # with integral coefficients. - tmpAuxRing = PolynomialRing(self._base_field.constant_field(), - str(self._base_field.gen())+','+str(self._ring.gen())) - intMinPoly, d = self._make_monic_integral(self._polynomial) - curveIdeal = tmpAuxRing.ideal(intMinPoly) - - singular.lib('normal.lib') #loading genus method in Singular - return int(curveIdeal._singular_().genus()) - - else: - raise NotImplementedError("computation of genus over non-prime " - "constant fields not implemented yet") - - def _simple_model(self, name='v'): - r""" - Return a finite extension `N/K(x)` isomorphic to the tower of - extensions `M/L/K(x)` with `K` perfect. - - Helper method for :meth:`simple_model`. - - INPUT: - - - ``name`` -- a string, the name of the generator of `N` - - ALGORITHM: - - Since `K` is perfect, the extension `M/K(x)` is simple, i.e., generated - by a single element [BM1940]_. Therefore, there are only finitely many - intermediate fields (Exercise 3.6.7 in [Bo2009]_). - Let `a` be a generator of `M/L` and let `b` be a generator of `L/K(x)`. - For some `i` the field `N_i=K(x)(a+x^ib)` is isomorphic to `M` and so - it is enough to test for all terms of the form `a+x^ib` whether they - generate a field of the right degree. - Indeed, suppose for contradiction that for all `i` we had `N_i\neq M`. - Then `N_i=N_j` for some `i,j`. Thus `(a+x^ib)-(a+x^jb)=b(x^i-x^j)\in - N_j` and so `b\in N_j`. Similarly, - `a+x^ib-x^{i-j}(a+x^jb)=a(1+x^{i-j})\in N_j` and so `a\in N_j`. - Therefore, `N_j=M`. - - TESTS:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2-x) - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2-y) - sage: M._simple_model() - (Function field in v defined by v^4 - x, - Function Field morphism: - From: Function field in v defined by v^4 - x - To: Function field in z defined by z^2 - y - Defn: v |--> z, - Function Field morphism: - From: Function field in z defined by z^2 - y - To: Function field in v defined by v^4 - x - Defn: z |--> v - y |--> v^2) - - Check that this also works for inseparable extensions:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2-x) - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2-y) - sage: M._simple_model() - (Function field in v defined by v^4 + x, - Function Field morphism: - From: Function field in v defined by v^4 + x - To: Function field in z defined by z^2 + y - Defn: v |--> z, - Function Field morphism: - From: Function field in z defined by z^2 + y - To: Function field in v defined by v^4 + x - Defn: z |--> v - y |--> v^2) - - An example where the generator of the last extension does not generate - the extension of the rational function field:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2-x) - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^3-1) - sage: M._simple_model() - (Function field in v defined by v^6 + x*v^4 + x^2*v^2 + x^3 + 1, - Function Field morphism: - From: Function field in v defined by v^6 + x*v^4 + x^2*v^2 + x^3 + 1 - To: Function field in z defined by z^3 + 1 - Defn: v |--> z + y, - Function Field morphism: - From: Function field in z defined by z^3 + 1 - To: Function field in v defined by v^6 + x*v^4 + x^2*v^2 + x^3 + 1 - Defn: z |--> v^4 + x^2 - y |--> v^4 + v + x^2) - - """ - M = self - L = M.base_field() - K = L.base_field() - - assert(isinstance(K, RationalFunctionField)) - assert(K is not L) - assert(L is not M) - - if not K.constant_field().is_perfect(): - raise NotImplementedError("simple_model() only implemented over perfect constant fields") - - x = K.gen() - b = L.gen() - a = M.gen() - - # using a+x^i*b tends to lead to huge powers of x in the minimal - # polynomial of the resulting field; it is better to try terms of - # the form a+i*b first (but in characteristic p>0 there are only - # finitely many of these) - # We systematically try elements of the form a+b*factor*x^exponent - factor = self.constant_base_field().zero() - exponent = 0 - while True: - v = M(a+b*factor*x**exponent) - minpoly = v.matrix(K).minpoly() - if minpoly.degree() == M.degree()*L.degree(): - break - factor += 1 - if factor == 0: - factor = self.constant_base_field().one() - exponent += 1 - - N = K.extension(minpoly, names=(name,)) - - # the morphism N -> M, v |-> v - N_to_M = N.hom(v) - - # the morphism M -> N, b |-> M_b, a |-> M_a - V, V_to_M, M_to_V = M.free_module(K) - V, V_to_N, N_to_V = N.free_module(K) - from sage.matrix.matrix_space import MatrixSpace - MS = MatrixSpace(V.base_field(), V.dimension()) - # the power basis of v over K - B = [M_to_V(v**i) for i in range(V.dimension())] - B = MS(B) - M_b = V_to_N(B.solve_left(M_to_V(b))) - M_a = V_to_N(B.solve_left(M_to_V(a))) - M_to_N = M.hom([M_a,M_b]) - - return N, N_to_M, M_to_N - - @cached_method - def simple_model(self, name=None): - """ - Return a function field isomorphic to this field which is a simple - extension of a rational function field. - - INPUT: - - - ``name`` -- a string (default: ``None``), the name of generator of - the simple extension. If ``None``, then the name of the generator - will be the same as the name of the generator of this function field. - - OUTPUT: - - A triple ``(F,f,t)`` where ``F`` is a field isomorphic to this field, - ``f`` is an isomorphism from ``F`` to this function field and ``t`` is - the inverse of ``f``. - - EXAMPLES: - - A tower of four function fields:: - - sage: K.<x> = FunctionField(QQ); R.<z> = K[] - sage: L.<z> = K.extension(z^2-x); R.<u> = L[] - sage: M.<u> = L.extension(u^2-z); R.<v> = M[] - sage: N.<v> = M.extension(v^2-u) - - The fields N and M as simple extensions of K:: - - sage: N.simple_model() - (Function field in v defined by v^8 - x, - Function Field morphism: - From: Function field in v defined by v^8 - x - To: Function field in v defined by v^2 - u - Defn: v |--> v, - Function Field morphism: - From: Function field in v defined by v^2 - u - To: Function field in v defined by v^8 - x - Defn: v |--> v - u |--> v^2 - z |--> v^4 - x |--> x) - sage: M.simple_model() - (Function field in u defined by u^4 - x, - Function Field morphism: - From: Function field in u defined by u^4 - x - To: Function field in u defined by u^2 - z - Defn: u |--> u, - Function Field morphism: - From: Function field in u defined by u^2 - z - To: Function field in u defined by u^4 - x - Defn: u |--> u - z |--> u^2 - x |--> x) - - An optional parameter ``name`` can be used to set the name of the - generator of the simple extension:: - - sage: M.simple_model(name='t') - (Function field in t defined by t^4 - x, Function Field morphism: - From: Function field in t defined by t^4 - x - To: Function field in u defined by u^2 - z - Defn: t |--> u, Function Field morphism: - From: Function field in u defined by u^2 - z - To: Function field in t defined by t^4 - x - Defn: u |--> t - z |--> t^2 - x |--> x) - - An example with higher degrees:: - - sage: K.<x> = FunctionField(GF(3)); R.<y> = K[] - sage: L.<y> = K.extension(y^5-x); R.<z> = L[] - sage: M.<z> = L.extension(z^3-x) - sage: M.simple_model() - (Function field in z defined by z^15 + x*z^12 + x^2*z^9 + 2*x^3*z^6 + 2*x^4*z^3 + 2*x^5 + 2*x^3, - Function Field morphism: - From: Function field in z defined by z^15 + x*z^12 + x^2*z^9 + 2*x^3*z^6 + 2*x^4*z^3 + 2*x^5 + 2*x^3 - To: Function field in z defined by z^3 + 2*x - Defn: z |--> z + y, - Function Field morphism: - From: Function field in z defined by z^3 + 2*x - To: Function field in z defined by z^15 + x*z^12 + x^2*z^9 + 2*x^3*z^6 + 2*x^4*z^3 + 2*x^5 + 2*x^3 - Defn: z |--> 2/x*z^6 + 2*z^3 + z + 2*x - y |--> 1/x*z^6 + z^3 + x - x |--> x) - - This also works for inseparable extensions:: - - sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] - sage: L.<y> = K.extension(y^2-x); R.<z> = L[] - sage: M.<z> = L.extension(z^2-y) - sage: M.simple_model() - (Function field in z defined by z^4 + x, Function Field morphism: - From: Function field in z defined by z^4 + x - To: Function field in z defined by z^2 + y - Defn: z |--> z, Function Field morphism: - From: Function field in z defined by z^2 + y - To: Function field in z defined by z^4 + x - Defn: z |--> z - y |--> z^2 - x |--> x) - """ - if name is None: - name = self.variable_name() - - if isinstance(self.base_field(), RationalFunctionField): - # the extension is simple already - if name == self.variable_name(): - id = Hom(self,self).identity() - return self, id, id - else: - ret = self.base_field().extension(self.polynomial(), names=(name,)) - f = ret.hom(self.gen()) - t = self.hom(ret.gen()) - return ret, f, t - else: - # recursively collapse the tower of fields - base = self.base_field() - base_, from_base_, to_base_ = base.simple_model() - self_ = base_.extension(self.polynomial().map_coefficients(to_base_), names=(name,)) - gens_in_base_ = [to_base_(k.gen()) - for k in base._intermediate_fields(base.rational_function_field())] - to_self_ = self.hom([self_.gen()]+gens_in_base_) - from_self_ = self_.hom([self.gen(),from_base_(base_.gen())]) - - # now collapse self_/base_/K(x) - ret, ret_to_self_, self__to_ret = self_._simple_model(name) - ret_to_self = ret.hom(from_self_(ret_to_self_(ret.gen()))) - gens_in_ret = [self__to_ret(to_self_(k.gen())) - for k in self._intermediate_fields(self.rational_function_field())] - self_to_ret = self.hom(gens_in_ret) - return ret, ret_to_self, self_to_ret - - @cached_method - def primitive_element(self): - r""" - Return a primitive element over the underlying rational function field. - - If this is a finite extension of a rational function field `K(x)` with - `K` perfect, then this is a simple extension of `K(x)`, i.e., there is - a primitive element `y` which generates this field over `K(x)`. This - method returns such an element `y`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2-x) - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2-y) - sage: R.<z> = L[] - sage: N.<u> = L.extension(z^2-x-1) - sage: N.primitive_element() - u + y - sage: M.primitive_element() - z - sage: L.primitive_element() - y - - This also works for inseparable extensions:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<Y> = K[] - sage: L.<y> = K.extension(Y^2-x) - sage: R.<Z> = L[] - sage: M.<z> = L.extension(Z^2-y) - sage: M.primitive_element() - z - """ - N, f, t = self.simple_model() - return f(N.gen()) - - @cached_method - def separable_model(self, names=None): - r""" - Return a function field isomorphic to this field which is a separable - extension of a rational function field. - - INPUT: - - - ``names`` -- a tuple of two strings or ``None`` (default: ``None``); - the second entry will be used as the variable name of the rational - function field, the first entry will be used as the variable name of - its separable extension. If ``None``, then the variable names will be - chosen automatically. - - OUTPUT: - - A triple ``(F,f,t)`` where ``F`` is a function field, ``f`` is an - isomorphism from ``F`` to this function field, and ``t`` is the inverse - of ``f``. - - ALGORITHM: - - Suppose that the constant base field is perfect. If this is a monic - integral inseparable extension of a rational function field, then the - defining polynomial is separable if we swap the variables (Proposition - 4.8 in Chapter VIII of [Lan2002]_.) - The algorithm reduces to this case with :meth:`monic_integral_model`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3) - sage: L.separable_model(('t','w')) - (Function field in t defined by t^3 + w^2, - Function Field morphism: - From: Function field in t defined by t^3 + w^2 - To: Function field in y defined by y^2 + x^3 - Defn: t |--> x - w |--> y, - Function Field morphism: - From: Function field in y defined by y^2 + x^3 - To: Function field in t defined by t^3 + w^2 - Defn: y |--> w - x |--> t) - - This also works for non-integral polynomials:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2/x - x^2) - sage: L.separable_model() - (Function field in y_ defined by y_^3 + x_^2, - Function Field morphism: - From: Function field in y_ defined by y_^3 + x_^2 - To: Function field in y defined by 1/x*y^2 + x^2 - Defn: y_ |--> x - x_ |--> y, - Function Field morphism: - From: Function field in y defined by 1/x*y^2 + x^2 - To: Function field in y_ defined by y_^3 + x_^2 - Defn: y |--> x_ - x |--> y_) - - If the base field is not perfect this is only implemented in trivial cases:: - - sage: k.<t> = FunctionField(GF(2)) - sage: k.is_perfect() - False - sage: K.<x> = FunctionField(k) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^3 - t) - sage: L.separable_model() - (Function field in y defined by y^3 + t, - Function Field endomorphism of Function field in y defined by y^3 + t - Defn: y |--> y - x |--> x, - Function Field endomorphism of Function field in y defined by y^3 + t - Defn: y |--> y - x |--> x) - - Some other cases for which a separable model could be constructed are - not supported yet:: - - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - t) - sage: L.separable_model() - Traceback (most recent call last): - ... - NotImplementedError: constructing a separable model is only implemented for function fields over a perfect constant base field - - TESTS: - - Check that this also works in characteristic zero:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3) - sage: L.separable_model() - (Function field in y defined by y^2 - x^3, - Function Field endomorphism of Function field in y defined by y^2 - x^3 - Defn: y |--> y - x |--> x, - Function Field endomorphism of Function field in y defined by y^2 - x^3 - Defn: y |--> y - x |--> x) - - Check that this works for towers of inseparable extensions:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2 - y) - sage: M.separable_model() - (Function field in z_ defined by z_ + x_^4, - Function Field morphism: - From: Function field in z_ defined by z_ + x_^4 - To: Function field in z defined by z^2 + y - Defn: z_ |--> x - x_ |--> z, - Function Field morphism: - From: Function field in z defined by z^2 + y - To: Function field in z_ defined by z_ + x_^4 - Defn: z |--> x_ - y |--> x_^2 - x |--> x_^4) - - Check that this also works if only the first extension is inseparable:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^3 - y) - sage: M.separable_model() - (Function field in z_ defined by z_ + x_^6, Function Field morphism: - From: Function field in z_ defined by z_ + x_^6 - To: Function field in z defined by z^3 + y - Defn: z_ |--> x - x_ |--> z, Function Field morphism: - From: Function field in z defined by z^3 + y - To: Function field in z_ defined by z_ + x_^6 - Defn: z |--> x_ - y |--> x_^3 - x |--> x_^6) - - """ - if names is None: - pass - elif not isinstance(names, tuple): - raise TypeError("names must be a tuple consisting of two strings") - elif len(names) != 2: - raise ValueError("must provide exactly two variable names") - - if self.base_ring() is not self.rational_function_field(): - L, from_L, to_L = self.simple_model() - K, from_K, to_K = L.separable_model(names=names) - f = K.hom([from_L(from_K(K.gen())), from_L(from_K(K.base_field().gen()))]) - t = self.hom([to_K(to_L(k.gen())) for k in self._intermediate_fields(self.rational_function_field())]) - return K, f, t - - if self.polynomial().gcd(self.polynomial().derivative()).is_one(): - # the model is already separable - if names is None: - names = self.variable_name(), self.base_field().variable_name() - return self.change_variable_name(names) - - if not self.constant_base_field().is_perfect(): - raise NotImplementedError("constructing a separable model is only implemented for function fields over a perfect constant base field") - - if names is None: - names = (self.variable_name()+"_", self.rational_function_field().variable_name()+"_") - - L, from_L, to_L = self.monic_integral_model() - - if L.polynomial().gcd(L.polynomial().derivative()).is_one(): - # L is separable - ret, ret_to_L, L_to_ret = L.change_variable_name(names) - f = ret.hom([from_L(ret_to_L(ret.gen())), from_L(ret_to_L(ret.base_field().gen()))]) - t = self.hom([L_to_ret(to_L(self.gen())), L_to_ret(to_L(self.base_field().gen()))]) - return ret, f, t - else: - # otherwise, the polynomial of L must be separable in the other variable - from .constructor import FunctionField - K = FunctionField(self.constant_base_field(), names=(names[1],)) - # construct a field isomorphic to L on top of K - - # turn the minpoly of K into a bivariate polynomial - if names[0] == names[1]: - raise ValueError("names of generators must be distinct") - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(self.constant_base_field(), names=names) - S = R.remove_var(names[1]) - f = R( L.polynomial().change_variable_name(names[1]).map_coefficients( - lambda c:c.numerator().change_variable_name(names[0]), S)) - f = f.polynomial(R.gen(0)).change_ring(K) - f /= f.leading_coefficient() - # f must be separable in the other variable (otherwise it would factor) - assert f.gcd(f.derivative()).is_one() - - ret = K.extension(f, names=(names[0],)) - # isomorphisms between L and ret are given by swapping generators - ret_to_L = ret.hom( [L(L.base_field().gen()), L.gen()] ) - L_to_ret = L.hom( [ret(K.gen()), ret.gen()] ) - # compose with from_L and to_L to get the desired isomorphisms between self and ret - f = ret.hom( [from_L(ret_to_L(ret.gen())), from_L(ret_to_L(ret.base_field().gen()))] ) - t = self.hom( [L_to_ret(to_L(self.gen())), L_to_ret(to_L(self.base_field().gen()))] ) - return ret, f, t - - def change_variable_name(self, name): - r""" - Return a field isomorphic to this field with variable(s) ``name``. - - INPUT: - - - ``name`` -- a string or a tuple consisting of a strings, the names of - the new variables starting with a generator of this field and going - down to the rational function field. - - OUTPUT: - - A triple ``F,f,t`` where ``F`` is a function field, ``f`` is an - isomorphism from ``F`` to this field, and ``t`` is the inverse of - ``f``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2 - y) - - sage: M.change_variable_name('zz') - (Function field in zz defined by zz^2 - y, - Function Field morphism: - From: Function field in zz defined by zz^2 - y - To: Function field in z defined by z^2 - y - Defn: zz |--> z - y |--> y - x |--> x, - Function Field morphism: - From: Function field in z defined by z^2 - y - To: Function field in zz defined by zz^2 - y - Defn: z |--> zz - y |--> y - x |--> x) - sage: M.change_variable_name(('zz','yy')) - (Function field in zz defined by zz^2 - yy, Function Field morphism: - From: Function field in zz defined by zz^2 - yy - To: Function field in z defined by z^2 - y - Defn: zz |--> z - yy |--> y - x |--> x, Function Field morphism: - From: Function field in z defined by z^2 - y - To: Function field in zz defined by zz^2 - yy - Defn: z |--> zz - y |--> yy - x |--> x) - sage: M.change_variable_name(('zz','yy','xx')) - (Function field in zz defined by zz^2 - yy, - Function Field morphism: - From: Function field in zz defined by zz^2 - yy - To: Function field in z defined by z^2 - y - Defn: zz |--> z - yy |--> y - xx |--> x, - Function Field morphism: - From: Function field in z defined by z^2 - y - To: Function field in zz defined by zz^2 - yy - Defn: z |--> zz - y |--> yy - x |--> xx) - - """ - if not isinstance(name, tuple): - name = (name,) - if len(name) == 0: - raise ValueError("name must contain at least one string") - elif len(name) == 1: - base = self.base_field() - from_base = to_base = Hom(base,base).identity() - else: - base, from_base, to_base = self.base_field().change_variable_name(name[1:]) - - ret = base.extension(self.polynomial().map_coefficients(to_base), names=(name[0],)) - f = ret.hom( [k.gen() for k in self._intermediate_fields(self.rational_function_field())] ) - t = self.hom( [k.gen() for k in ret._intermediate_fields(ret.rational_function_field())] ) - return ret, f, t - - -class FunctionField_simple(FunctionField_polymod): - """ - Function fields defined by irreducible and separable polynomials - over rational function fields. - """ - @cached_method - def _inversion_isomorphism(self): - r""" - Return an inverted function field isomorphic to ``self`` and isomorphisms - between them. - - An *inverted* function field `M` is an extension of the base rational - function field `k(x)` of ``self``, and isomorphic to ``self`` by an - isomorphism sending `x` to `1/x`, which we call an *inversion* - isomorphism. Also the defining polynomial of the function field `M` is - required to be monic and integral. - - The inversion isomorphism is for internal use to reposition infinite - places to finite places. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: F._inversion_isomorphism() - (Function field in s defined by s^3 + x^16 + x^14 + x^12, Composite map: - From: Function field in s defined by s^3 + x^16 + x^14 + x^12 - To: Function field in y defined by y^3 + x^6 + x^4 + x^2 - Defn: Function Field morphism: - From: Function field in s defined by s^3 + x^16 + x^14 + x^12 - To: Function field in T defined by T^3 + (x^4 + x^2 + 1)/x^6 - Defn: s |--> x^6*T - x |--> x - then - Function Field morphism: - From: Function field in T defined by T^3 + (x^4 + x^2 + 1)/x^6 - To: Function field in y defined by y^3 + x^6 + x^4 + x^2 - Defn: T |--> y - x |--> 1/x, Composite map: - From: Function field in y defined by y^3 + x^6 + x^4 + x^2 - To: Function field in s defined by s^3 + x^16 + x^14 + x^12 - Defn: Function Field morphism: - From: Function field in y defined by y^3 + x^6 + x^4 + x^2 - To: Function field in T defined by T^3 + (x^4 + x^2 + 1)/x^6 - Defn: y |--> T - x |--> 1/x - then - Function Field morphism: - From: Function field in T defined by T^3 + (x^4 + x^2 + 1)/x^6 - To: Function field in s defined by s^3 + x^16 + x^14 + x^12 - Defn: T |--> 1/x^6*s - x |--> x) - """ - K = self.base_field() - R = PolynomialRing(K,'T') - x = K.gen() - xinv = 1/x - - h = K.hom(xinv) - F_poly = R([h(c) for c in self.polynomial().list()]) - F = K.extension(F_poly) - - self2F = self.hom([F.gen(),xinv]) - F2self = F.hom([self.gen(),xinv]) - - M, M2F, F2M = F.monic_integral_model('s') - - return M, F2self*M2F, F2M*self2F - - def places_above(self, p): - """ - Return places lying above ``p``. - - INPUT: - - - ``p`` -- place of the base rational function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) - sage: all(q.place_below() == p for p in K.places() for q in F.places_above(p)) - True - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) - sage: O = K.maximal_order() - sage: pls = [O.ideal(x-c).place() for c in [-2, -1, 0, 1, 2]] - sage: all(q.place_below() == p for p in pls for q in F.places_above(p)) - True - - sage: K.<x> = FunctionField(QQbar); _.<Y> = K[] - sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) - sage: O = K.maximal_order() - sage: pls = [O.ideal(x-QQbar(sqrt(c))).place() for c in [-2, -1, 0, 1, 2]] - sage: all(q.place_below() == p # long time (4s) - ....: for p in pls for q in F.places_above(p)) - True - """ - R = self.base_field() - - if p not in R.place_set(): - raise TypeError("not a place of the base rational function field") - - if p.is_infinite_place(): - dec = self.maximal_order_infinite().decomposition() - else: - dec = self.maximal_order().decomposition(p.prime_ideal()) - - return tuple([q.place() for q, deg, exp in dec]) - - def constant_field(self): - """ - Return the algebraic closure of the base constant field in the function - field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3)); _.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: L.constant_field() - Finite Field of size 3 - """ - return self.exact_constant_field()[0] - - def exact_constant_field(self, name='t'): - """ - Return the exact constant field and its embedding into the function field. - - INPUT: - - - ``name`` -- name (default: `t`) of the generator of the exact constant field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3)); _.<Y> = K[] - sage: f = Y^2 - x*Y + x^2 + 1 # irreducible but not absolutely irreducible - sage: L.<y> = K.extension(f) - sage: L.genus() - 0 - sage: L.exact_constant_field() - (Finite Field in t of size 3^2, Ring morphism: - From: Finite Field in t of size 3^2 - To: Function field in y defined by y^2 + 2*x*y + x^2 + 1 - Defn: t |--> y + x) - sage: (y+x).divisor() - 0 - """ - # A basis of the full constant field is obtained from - # computing a Riemann-Roch basis of zero divisor. - basis = self.divisor_group().zero().basis_function_space() - - dim = len(basis) - - for e in basis: - _min_poly = e.minimal_polynomial(name) - if _min_poly.degree() == dim: - break - k = self.constant_base_field() - R = k[name] - min_poly = R([k(c) for c in _min_poly.list()]) - - k_ext = k.extension(min_poly, name) - - if k_ext.is_prime_field(): - # The cover of the quotient ring k_ext is the integer ring - # whose generator is 1. This is different from the generator - # of k_ext. - embedding = k_ext.hom([self(1)], self) - else: - embedding = k_ext.hom([e], self) - - return k_ext, embedding - - def genus(self): - """ - Return the genus of the function field. - - EXAMPLES:: - - sage: F.<a> = GF(16) - sage: K.<x> = FunctionField(F); K - Rational function field in x over Finite Field in a of size 2^4 - sage: R.<t> = PolynomialRing(K) - sage: L.<y> = K.extension(t^4+t-x^5) - sage: L.genus() - 6 - - The genus is computed by the Hurwitz genus formula. - """ - k, _ = self.exact_constant_field() - different_degree = self.different().degree() # must be even - return Integer(different_degree // 2 - self.degree() / k.degree()) + 1 - - def residue_field(self, place, name=None): - """ - Return the residue field associated with the place along with the maps - from and to the residue field. - - INPUT: - - - ``place`` -- place of the function field - - - ``name`` -- string; name of the generator of the residue field - - The domain of the map to the residue field is the discrete valuation - ring associated with the place. - - The discrete valuation ring is defined as the ring of all elements of - the function field with nonnegative valuation at the place. The maximal - ideal is the set of elements of positive valuation. The residue field - is then the quotient of the discrete valuation ring by its maximal - ideal. - - If an element not in the valuation ring is applied to the map, an - exception ``TypeError`` is raised. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: p = L.places_finite()[0] - sage: R, fr_R, to_R = L.residue_field(p) - sage: R - Finite Field of size 2 - sage: f = 1 + y - sage: f.valuation(p) - -1 - sage: to_R(f) - Traceback (most recent call last): - ... - TypeError: ... - sage: (1+1/f).valuation(p) - 0 - sage: to_R(1 + 1/f) - 1 - sage: [fr_R(e) for e in R] - [0, 1] - """ - return place.residue_field(name=name) - - -class FunctionField_char_zero(FunctionField_simple): - """ - Function fields of characteristic zero. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) - sage: L - Function field in y defined by y^3 + (-x^3 + 1)/(x^3 - 2) - sage: L.characteristic() - 0 - """ - @cached_method - def higher_derivation(self): - """ - Return the higher derivation (also called the Hasse-Schmidt derivation) - for the function field. - - The higher derivation of the function field is uniquely determined with - respect to the separating element `x` of the base rational function - field `k(x)`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) - sage: L.higher_derivation() - Higher derivation map: - From: Function field in y defined by y^3 + (-x^3 + 1)/(x^3 - 2) - To: Function field in y defined by y^3 + (-x^3 + 1)/(x^3 - 2) - """ - from .maps import FunctionFieldHigherDerivation_char_zero - return FunctionFieldHigherDerivation_char_zero(self) - - -class FunctionField_global(FunctionField_simple): - """ - Global function fields. - - INPUT: - - - ``polynomial`` -- monic irreducible and separable polynomial - - - ``names`` -- name of the generator of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) - sage: L - Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) - - The defining equation needs not be monic:: - - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension((1 - x)*Y^7 - x^3) - sage: L.gaps() # long time (6s) - [1, 2, 3] - - or may define a trivial extension:: - - sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] - sage: L.<y> = K.extension(Y-1) - sage: L.genus() - 0 - """ - _differentials_space = DifferentialsSpace_global - - def __init__(self, polynomial, names): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) - sage: TestSuite(L).run() # long time (7s) - """ - FunctionField_polymod.__init__(self, polynomial, names) - - def maximal_order(self): - """ - Return the maximal order of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); - sage: R.<t> = PolynomialRing(K); - sage: F.<y> = K.extension(t^4 + x^12*t^2 + x^18*t + x^21 + x^18); - sage: O = F.maximal_order() - sage: O.basis() - (1, 1/x^4*y, 1/x^11*y^2 + 1/x^2, 1/x^15*y^3 + 1/x^6*y) - """ - from .order import FunctionFieldMaximalOrder_global - return FunctionFieldMaximalOrder_global(self) - - @cached_method - def higher_derivation(self): - """ - Return the higher derivation (also called the Hasse-Schmidt derivation) - for the function field. - - The higher derivation of the function field is uniquely determined with - respect to the separating element `x` of the base rational function - field `k(x)`. - - EXAMPLES:: - - sage: K.<x>=FunctionField(GF(5)); _.<Y>=K[] - sage: L.<y>=K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) - sage: L.higher_derivation() - Higher derivation map: - From: Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) - To: Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) - """ - from .maps import FunctionFieldHigherDerivation_global - return FunctionFieldHigherDerivation_global(self) - - def get_place(self, degree): - """ - Return a place of ``degree``. - - INPUT: - - - ``degree`` -- a positive integer - - OUTPUT: a place of ``degree`` if any exists; otherwise ``None`` - - EXAMPLES:: - - sage: F.<a> = GF(2) - sage: K.<x> = FunctionField(F) - sage: R.<Y> = PolynomialRing(K) - sage: L.<y> = K.extension(Y^4 + Y - x^5) - sage: L.get_place(1) - Place (x, y) - sage: L.get_place(2) - Place (x, y^2 + y + 1) - sage: L.get_place(3) - Place (x^3 + x^2 + 1, y + x^2 + x) - sage: L.get_place(4) - Place (x + 1, x^5 + 1) - sage: L.get_place(5) - Place (x^5 + x^3 + x^2 + x + 1, y + x^4 + 1) - sage: L.get_place(6) - Place (x^3 + x^2 + 1, y^2 + y + x^2) - sage: L.get_place(7) - Place (x^7 + x + 1, y + x^6 + x^5 + x^4 + x^3 + x) - sage: L.get_place(8) - - """ - for p in self._places_finite(degree): - return p - - for p in self._places_infinite(degree): - return p - - return None - - def places(self, degree=1): - """ - Return a list of the places with ``degree``. - - INPUT: - - - ``degree`` -- positive integer (default: `1`) - - EXAMPLES:: - - sage: F.<a> = GF(2) - sage: K.<x> = FunctionField(F) - sage: R.<t> = PolynomialRing(K) - sage: L.<y> = K.extension(t^4 + t - x^5) - sage: L.places(1) - [Place (1/x, 1/x^4*y^3), Place (x, y), Place (x, y + 1)] - """ - return self.places_infinite(degree) + self.places_finite(degree) - - def places_finite(self, degree=1): - """ - Return a list of the finite places with ``degree``. - - INPUT: - - - ``degree`` -- positive integer (default: `1`) - - EXAMPLES:: - - sage: F.<a> = GF(2) - sage: K.<x> = FunctionField(F) - sage: R.<t> = PolynomialRing(K) - sage: L.<y> = K.extension(t^4+t-x^5) - sage: L.places_finite(1) - [Place (x, y), Place (x, y + 1)] - """ - return list(self._places_finite(degree)) - - def _places_finite(self, degree): - """ - Return a generator of finite places with ``degree``. - - INPUT: - - - ``degree`` -- positive integer - - EXAMPLES:: - - sage: F.<a> = GF(2) - sage: K.<x> = FunctionField(F) - sage: R.<t> = PolynomialRing(K) - sage: L.<y> = K.extension(t^4+t-x^5) - sage: L._places_finite(1) - <generator object ...> - """ - O = self.maximal_order() - K = self.base_field() - - degree = Integer(degree) - - for d in degree.divisors(): - for p in K._places_finite(degree=d): - for prime,_,_ in O.decomposition(p.prime_ideal()): - place = prime.place() - if place.degree() == degree: - yield place - - def places_infinite(self, degree=1): - """ - Return a list of the infinite places with ``degree``. - - INPUT: - - - ``degree`` -- positive integer (default: `1`) - - EXAMPLES:: - - sage: F.<a> = GF(2) - sage: K.<x> = FunctionField(F) - sage: R.<t> = PolynomialRing(K) - sage: L.<y> = K.extension(t^4+t-x^5) - sage: L.places_infinite(1) - [Place (1/x, 1/x^4*y^3)] - """ - return list(self._places_infinite(degree)) - - def _places_infinite(self, degree): - """ - Return a generator of *infinite* places with ``degree``. - - INPUT: - - - ``degree`` -- positive integer - - EXAMPLES:: - - sage: F.<a> = GF(2) - sage: K.<x> = FunctionField(F) - sage: R.<t> = PolynomialRing(K) - sage: L.<y> = K.extension(t^4+t-x^5) - sage: L._places_infinite(1) - <generator object ...> - """ - Oinf = self.maximal_order_infinite() - for prime,_,_ in Oinf.decomposition(): - place = prime.place() - if place.degree() == degree: - yield place - - def gaps(self): - """ - Return the gaps of the function field. - - These are the gaps at the ordinary places, that is, places which are - not Weierstrass places. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3 * Y + x) - sage: L.gaps() - [1, 2, 3] - """ - return self._weierstrass_places()[1] - - def weierstrass_places(self): - """ - Return all Weierstrass places of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3 * Y + x) - sage: L.weierstrass_places() - [Place (1/x, 1/x^3*y^2 + 1/x), - Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1), - Place (x, y), - Place (x + 1, (x^3 + 1)*y + x + 1), - Place (x^3 + x + 1, y + 1), - Place (x^3 + x + 1, y + x^2), - Place (x^3 + x + 1, y + x^2 + 1), - Place (x^3 + x^2 + 1, y + x), - Place (x^3 + x^2 + 1, y + x^2 + 1), - Place (x^3 + x^2 + 1, y + x^2 + x + 1)] - """ - return self._weierstrass_places()[0].support() - - @cached_method - def _weierstrass_places(self): - """ - Return the Weierstrass places together with the gap sequence for - ordinary places. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3 * Y + x) - sage: len(L.weierstrass_places()) # indirect doctest - 10 - - This method implements Algorithm 30 in [Hes2002b]_. - """ - from sage.matrix.constructor import matrix - - W = self(self.base_field().gen()).differential().divisor() - basis = W._basis() - - if not basis: - return [], [] - d = len(basis) - - der = self.higher_derivation() - M = matrix([basis]) - e = 1 - gaps = [1] - while M.nrows() < d: - row = vector([der._derive(basis[i], e) for i in range(d)]) - if row not in M.row_space(): - M = matrix(M.rows() + [row]) - gaps.append(e + 1) - e += 1 - - # This is faster than M.determinant(). Note that Mx - # is a matrix over univariate polynomial ring. - Mx = matrix(M.nrows(), [c._x for c in M.list()]) - detM = self(Mx.determinant() % self._polynomial) - - R = detM.divisor() + sum(gaps)*W # ramification divisor - - return R, gaps - - @cached_method - def L_polynomial(self, name='t'): - """ - Return the L-polynomial of the function field. - - INPUT: - - - ``name`` -- (default: ``t``) name of the variable of the polynomial - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: F.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: F.L_polynomial() - 2*t^2 + t + 1 - """ - from sage.rings.integer_ring import ZZ - q = self.constant_field().order() - g = self.genus() - - B = [len(self.places(i+1)) for i in range(g)] - N = [sum(d * B[d-1] for d in ZZ(i+1).divisors()) for i in range(g)] - S = [N[i] - q**(i+1) - 1 for i in range(g)] - - a = [1] - for i in range(1, g+1): - a.append(sum(S[j] * a[i-j-1] for j in range(i)) / i) - for j in range(1, g+1): - a.append(q**j * a[g-j]) - - return ZZ[name](a) - - def number_of_rational_places(self, r=1): - """ - Return the number of rational places of the function field whose - constant field extended by degree ``r``. - - INPUT: - - - ``r`` -- positive integer (default: `1`) - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: F.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: F.number_of_rational_places() - 4 - sage: [F.number_of_rational_places(r) for r in [1..10]] - [4, 8, 4, 16, 44, 56, 116, 288, 508, 968] - """ - from sage.rings.integer_ring import IntegerRing - - q = self.constant_field().order() - L = self.L_polynomial() - Lp = L.derivative() - - R = IntegerRing()[[L.parent().gen()]] # power series ring - - f = R(Lp / L, prec=r) - n = f[r-1] + q**r + 1 - - return n - - -@handle_AA_and_QQbar -def _singular_normal(ideal): - r""" - Compute the normalization of the affine algebra defined by ``ideal`` using - Singular. - - The affine algebra is the quotient algebra of a multivariate polynomial - ring `R` by the ideal. The normalization is by definition the integral - closure of the algebra in its total ring of fractions. - - INPUT: - - - ``ideal`` -- a radical ideal in a multivariate polynomial ring - - OUTPUT: - - a list of lists, one list for each ideal in the equidimensional - decomposition of the ``ideal``, each list giving a set of generators of the - normalization of each ideal as an R-module by dividing all elements of the - list by the final element. Thus the list ``[x, y]`` means that `\{x/y, 1\}` - is the set of generators of the normalization of `R/(x,y)`. - - ALGORITHM: - - Singular's implementation of the normalization algorithm described in G.-M. - Greuel, S. Laplagne, F. Seelisch: Normalization of Rings (2009). - - EXAMPLES:: - - sage: from sage.rings.function_field.function_field import _singular_normal - sage: R.<x,y> = QQ[] - - sage: f = (x^2-y^3) * x - sage: _singular_normal(ideal(f)) - [[x, y], [1]] - - sage: f = (y^2-x) - sage: _singular_normal(ideal(f)) - [[1]] - """ - from sage.libs.singular.function import singular_function, lib - lib('normal.lib') - normal = singular_function('normal') - execute = singular_function('execute') - - try: - get_printlevel = singular_function('get_printlevel') - except NameError: - execute('proc get_printlevel {return (printlevel);}') - get_printlevel = singular_function('get_printlevel') - - # It's fairly verbose unless printlevel is -1. - saved_printlevel = get_printlevel() - execute('printlevel=-1') - nor = normal(ideal) - execute('printlevel={}'.format(saved_printlevel)) - - return nor[1] - - -class FunctionField_integral(FunctionField_simple): - """ - Integral function fields. - - A function field is integral if it is defined by an irreducible separable - polynomial, which is integral over the maximal order of the base rational - function field. - """ - def _maximal_order_basis(self): - """ - Return a basis of the maximal order of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^4 + x^12*t^2 + x^18*t + x^21 + x^18) - sage: F._maximal_order_basis() - [1, 1/x^4*y, 1/x^11*y^2 + 1/x^2, 1/x^15*y^3 + 1/x^6*y] - - The basis of the maximal order *always* starts with 1. This is assumed - in some algorithms. - """ - from sage.matrix.constructor import matrix - from .hermite_form_polynomial import reversed_hermite_form - - k = self.constant_base_field() - K = self.base_field() # rational function field - n = self.degree() - - # Construct the defining polynomial of the function field as a - # two-variate polynomial g in the ring k[y,x] where k is the constant - # base field. - S,(y,x) = PolynomialRing(k, names='y,x', order='lex').objgens() - v = self.polynomial().list() - g = sum([v[i].numerator().subs(x) * y**i for i in range(len(v))]) - - if self.is_global(): - from sage.libs.singular.function import singular_function, lib - from sage.env import SAGE_EXTCODE - lib(SAGE_EXTCODE + '/singular/function_field/core.lib') - normalize = singular_function('core_normalize') - - # Singular "normalP" algorithm assumes affine domain over - # a prime field. So we construct gflat lifting g as in - # k_prime[yy,xx,zz]/(k_poly) where k = k_prime[zz]/(k_poly) - R = PolynomialRing(k.prime_subfield(), names='yy,xx,zz') - gflat = R.zero() - for m in g.monomials(): - c = g.monomial_coefficient(m).polynomial('zz') - gflat += R(c) * R(m) # R(m) is a monomial in yy and xx - - k_poly = R(k.polynomial('zz')) - - # invoke Singular - pols_in_R = normalize(R.ideal([k_poly, gflat])) - - # reconstruct polynomials in S - h = R.hom([y,x,k.gen()],S) - pols_in_S = [h(f) for f in pols_in_R] - else: - # Call Singular. Singular's "normal" function returns a basis - # of the integral closure of k(x,y)/(g) as a k[x,y]-module. - pols_in_S = _singular_normal(S.ideal(g))[0] - - # reconstruct the polynomials in the function field - x = K.gen() - y = self.gen() - pols = [] - for f in pols_in_S: - p = f.polynomial(S.gen(0)) - s = 0 - for i in range(p.degree()+1): - s += p[i].subs(x) * y**i - pols.append(s) - - # Now if pols = [g1,g2,...gn,g0], then the g1/g0,g2/g0,...,gn/g0, - # and g0/g0=1 are the module generators of the integral closure - # of the equation order Sb = k[xb,yb] in its fraction field, - # that is, the function field. The integral closure of k[x] - # is then obtained by multiplying these generators with powers of y - # as the equation order itself is an integral extension of k[x]. - d = ~ pols[-1] - _basis = [] - for f in pols: - b = d * f - for i in range(n): - _basis.append(b) - b *= y - - # Finally we reduce _basis to get a basis over k[x]. This is done of - # course by Hermite normal form computation. Here we apply a trick to - # get a basis that starts with 1 and is ordered in increasing - # y-degrees. The trick is to use the reversed Hermite normal form. - # Note that it is important that the overall denominator l lies in k[x]. - V, fr_V, to_V = self.free_module() - basis_V = [to_V(bvec) for bvec in _basis] - l = lcm([vvec.denominator() for vvec in basis_V]) - - _mat = matrix([[coeff.numerator() for coeff in l*v] for v in basis_V]) - reversed_hermite_form(_mat) - - basis = [fr_V(v) / l for v in _mat if not v.is_zero()] - return basis - - @cached_method - def equation_order(self): - """ - Return the equation order of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: F.equation_order() - Order in Function field in y defined by y^3 + x^6 + x^4 + x^2 - - sage: K.<x> = FunctionField(QQ); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: F.equation_order() - Order in Function field in y defined by y^3 - x^6 - 2*x^5 - 3*x^4 - 2*x^3 - x^2 - """ - from .order import FunctionFieldOrder_basis - a = self.gen() - basis = [a**i for i in range(self.degree())] - return FunctionFieldOrder_basis(tuple(basis)) - - @cached_method - def primitive_integal_element_infinite(self): - """ - Return a primitive integral element over the base maximal infinite order. - - This element is integral over the maximal infinite order of the base - rational function field and the function field is a simple extension by - this element over the base order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: b = F.primitive_integal_element_infinite(); b - 1/x^2*y - sage: b.minimal_polynomial('t') - t^3 + (x^4 + x^2 + 1)/x^4 - """ - f = self.polynomial() - n = f.degree() - y = self.gen() - x = self.base_field().gen() - - cf = max([(f[i].numerator().degree()/(n-i)).ceil() for i in range(n) - if f[i] != 0]) - return y*x**(-cf) - - @cached_method - def equation_order_infinite(self): - """ - Return the infinite equation order of the function field. - - This is by definition `o[b]` where `b` is the primitive integral - element from :meth:`primitive_integal_element_infinite()` and `o` is - the maximal infinite order of the base rational function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: F.equation_order_infinite() - Infinite order in Function field in y defined by y^3 + x^6 + x^4 + x^2 - - sage: K.<x> = FunctionField(QQ); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: F.equation_order_infinite() - Infinite order in Function field in y defined by y^3 - x^6 - 2*x^5 - 3*x^4 - 2*x^3 - x^2 - """ - from .order import FunctionFieldOrderInfinite_basis - b = self.primitive_integal_element_infinite() - basis = [b**i for i in range(self.degree())] - return FunctionFieldOrderInfinite_basis(tuple(basis)) - - -class FunctionField_char_zero_integral(FunctionField_char_zero, FunctionField_integral): - """ - Function fields of characteristic zero, defined by an irreducible and - separable polynomial, integral over the maximal order of the base rational - function field with a finite constant field. - """ - pass - - -class FunctionField_global_integral(FunctionField_global, FunctionField_integral): - """ - Global function fields, defined by an irreducible and separable polynomial, - integral over the maximal order of the base rational function field with a - finite constant field. - """ - pass - - -class RationalFunctionField(FunctionField): - """ - Rational function field in one variable, over an arbitrary base field. - - INPUT: - - - ``constant_field`` -- arbitrary field - - - ``names`` -- string or tuple of length 1 - - EXAMPLES:: - - sage: K.<t> = FunctionField(GF(3)); K - Rational function field in t over Finite Field of size 3 - sage: K.gen() - t - sage: 1/t + t^3 + 5 - (t^4 + 2*t + 1)/t - - sage: K.<t> = FunctionField(QQ); K - Rational function field in t over Rational Field - sage: K.gen() - t - sage: 1/t + t^3 + 5 - (t^4 + 5*t + 1)/t - - There are various ways to get at the underlying fields and rings - associated to a rational function field:: - - sage: K.<t> = FunctionField(GF(7)) - sage: K.base_field() - Rational function field in t over Finite Field of size 7 - sage: K.field() - Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 - sage: K.constant_field() - Finite Field of size 7 - sage: K.maximal_order() - Maximal order of Rational function field in t over Finite Field of size 7 - - sage: K.<t> = FunctionField(QQ) - sage: K.base_field() - Rational function field in t over Rational Field - sage: K.field() - Fraction Field of Univariate Polynomial Ring in t over Rational Field - sage: K.constant_field() - Rational Field - sage: K.maximal_order() - Maximal order of Rational function field in t over Rational Field - - We define a morphism:: - - sage: K.<t> = FunctionField(QQ) - sage: L = FunctionField(QQ, 'tbar') # give variable name as second input - sage: K.hom(L.gen()) - Function Field morphism: - From: Rational function field in t over Rational Field - To: Rational function field in tbar over Rational Field - Defn: t |--> tbar - - Here are some calculations over a number field:: - - sage: R.<x> = FunctionField(QQ) - sage: L.<y> = R[] - sage: F.<y> = R.extension(y^2 - (x^2+1)) - sage: (y/x).divisor() - - Place (x, y - 1) - - Place (x, y + 1) - + Place (x^2 + 1, y) - - sage: A.<z> = QQ[] - sage: NF.<i> = NumberField(z^2+1) - sage: R.<x> = FunctionField(NF) - sage: L.<y> = R[] - sage: F.<y> = R.extension(y^2 - (x^2+1)) - - sage: (x/y*x.differential()).divisor() - -2*Place (1/x, 1/x*y - 1) - - 2*Place (1/x, 1/x*y + 1) - + Place (x, y - 1) - + Place (x, y + 1) - - sage: (x/y).divisor() - - Place (x - i, y) - + Place (x, y - 1) - + Place (x, y + 1) - - Place (x + i, y) - - """ - Element = FunctionFieldElement_rational - - def __init__(self, constant_field, names, category=None): - """ - Initialize. - - EXAMPLES:: - - sage: K.<t> = FunctionField(CC); K - Rational function field in t over Complex Field with 53 bits of precision - sage: TestSuite(K).run() # long time (5s) - - sage: FunctionField(QQ[I], 'alpha') - Rational function field in alpha over Number Field in I with defining polynomial x^2 + 1 with I = 1*I - - Must be over a field:: - - sage: FunctionField(ZZ, 't') - Traceback (most recent call last): - ... - TypeError: constant_field must be a field - """ - if names is None: - raise ValueError("variable name must be specified") - elif not isinstance(names, tuple): - names = (names, ) - if not constant_field.is_field(): - raise TypeError("constant_field must be a field") - - self._constant_field = constant_field - - FunctionField.__init__(self, self, names=names, category=FunctionFields().or_subcategory(category)) - - from .place import FunctionFieldPlace_rational - self._place_class = FunctionFieldPlace_rational - - R = constant_field[names[0]] - self._hash = hash((constant_field, names)) - self._ring = R - self._field = R.fraction_field() - - hom = Hom(self._field, self) - from .maps import FractionFieldToFunctionField - self.register_coercion(hom.__make_element_class__(FractionFieldToFunctionField)(hom.domain(), hom.codomain())) - - from sage.categories.sets_with_partial_maps import SetsWithPartialMaps - from sage.categories.morphism import SetMorphism - R.register_conversion(SetMorphism(self.Hom(R, SetsWithPartialMaps()), self._to_polynomial)) - - self._gen = self(R.gen()) - - def __reduce__(self): - """ - Return the arguments which were used to create this instance. The - rationale for this is explained in the documentation of - :class:`UniqueRepresentation`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: clazz,args = K.__reduce__() - sage: clazz(*args) - Rational function field in x over Rational Field - """ - from .constructor import FunctionField - return FunctionField, (self._constant_field, self._names) - - def __hash__(self): - """ - Return hash of the function field. - - The hash is formed from the constant field and the variable names. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: hash(K) == hash((K.constant_base_field(), K.variable_names())) - True - - """ - return self._hash - - def _repr_(self): - """ - Return string representation of the function field. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: K._repr_() - 'Rational function field in t over Rational Field' - """ - return "Rational function field in %s over %s"%( - self.variable_name(), self._constant_field) - - def _element_constructor_(self, x): - r""" - Coerce ``x`` into an element of the function field, possibly not canonically. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: a = K._element_constructor_(K.maximal_order().gen()); a - t - sage: a.parent() - Rational function field in t over Rational Field - - TESTS: - - Conversion of a string:: - - sage: K('t') - t - sage: K('1/t') - 1/t - - Conversion of a constant polynomial over the function field:: - - sage: K(K.polynomial_ring().one()) - 1 - - Some indirect test of conversion:: - - sage: S.<x, y> = K[] - sage: I = S*[x^2 - y^2, y-t] - sage: I.groebner_basis() - [x^2 - t^2, y - t] - - """ - if isinstance(x, FunctionFieldElement): - return self.element_class(self, self._field(x._x)) - try: - x = self._field(x) - except TypeError as Err: - try: - if x.parent() is self.polynomial_ring(): - return x[0] - except AttributeError: - pass - raise Err - return self.element_class(self, x) - - def _to_constant_base_field(self, f): - r""" - Return ``f`` as an element of the constant base field. - - INPUT: - - - ``f`` -- element of the rational function field which is a - constant of the underlying rational function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K._to_constant_base_field(K(1)) - 1 - sage: K._to_constant_base_field(K(x)) - Traceback (most recent call last): - ... - ValueError: only constants can be converted into the constant base field but x is not a constant - - TESTS: - - Verify that :trac:`21872` has been resolved:: - - sage: K(1) in QQ - True - sage: x in QQ - False - - """ - K = self.constant_base_field() - if f.denominator() in K and f.numerator() in K: - # When K is not exact, f.denominator() might not be an exact 1, so - # we need to divide explicitly to get the correct precision - return K(f.numerator()) / K(f.denominator()) - raise ValueError("only constants can be converted into the constant base field but %r is not a constant"%(f,)) - - def _to_polynomial(self, f): - """ - If ``f`` is integral, return it as a polynomial. - - INPUT: - - - ``f`` -- an element of this rational function field whose denominator is a constant. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K._ring(x) # indirect doctest - x - """ - K = f.parent().constant_base_field() - if f.denominator() in K: - return f.numerator()/K(f.denominator()) - raise ValueError("only polynomials can be converted to the underlying polynomial ring") - - def _to_bivariate_polynomial(self, f): - """ - Convert ``f`` from a univariate polynomial over the rational function - field into a bivariate polynomial and a denominator. - - INPUT: - - - ``f`` -- univariate polynomial over the function field - - OUTPUT: - - - bivariate polynomial, denominator - - EXAMPLES:: - - sage: R.<t> = FunctionField(GF(7)) - sage: S.<X> = R[] - sage: f = (1/t)*(X^4 - 1/t^2)*(X^3 - t^3) - sage: R._to_bivariate_polynomial(f) - (X^7*t^2 - X^4*t^5 - X^3 + t^3, t^3) - """ - v = f.list() - denom = lcm([a.denominator() for a in v]) - S = denom.parent() - x,t = S.base_ring()['%s,%s'%(f.parent().variable_name(),self.variable_name())].gens() - phi = S.hom([t]) - return sum([phi((denom * v[i]).numerator()) * x**i for i in range(len(v))]), denom - - def _factor_univariate_polynomial(self, f, proof=None): - """ - Factor the univariate polynomial f over the function field. - - INPUT: - - - ``f`` -- univariate polynomial over the function field - - EXAMPLES: - - We do a factorization over the function field over the rationals:: - - sage: R.<t> = FunctionField(QQ) - sage: S.<X> = R[] - sage: f = (1/t)*(X^4 - 1/t^2)*(X^3 - t^3) - sage: f.factor() # indirect doctest - (1/t) * (X - t) * (X^2 - 1/t) * (X^2 + 1/t) * (X^2 + t*X + t^2) - sage: f.factor().prod() == f - True - - We do a factorization over a finite prime field:: - - sage: R.<t> = FunctionField(GF(7)) - sage: S.<X> = R[] - sage: f = (1/t)*(X^4 - 1/t^2)*(X^3 - t^3) - sage: f.factor() - (1/t) * (X + 3*t) * (X + 5*t) * (X + 6*t) * (X^2 + 1/t) * (X^2 + 6/t) - sage: f.factor().prod() == f - True - - Factoring over a function field over a non-prime finite field:: - - sage: k.<a> = GF(9) - sage: R.<t> = FunctionField(k) - sage: S.<X> = R[] - sage: f = (1/t)*(X^3 - a*t^3) - sage: f.factor() - (1/t) * (X + (a + 2)*t)^3 - sage: f.factor().prod() == f - True - - Factoring over a function field over a tower of finite fields:: - - sage: k.<a> = GF(4) - sage: R.<b> = k[] - sage: l.<b> = k.extension(b^2 + b + a) - sage: K.<x> = FunctionField(l) - sage: R.<t> = K[] - sage: F = t*x - sage: F.factor(proof=False) - (x) * t - - """ - old_variable_name = f.variable_name() - # the variables of the bivariate polynomial must be distinct - if self.variable_name() == f.variable_name(): - # replace x with xx to make the variable names distinct - f = f.change_variable_name(old_variable_name + old_variable_name) - - F, d = self._to_bivariate_polynomial(f) - fac = F.factor(proof=proof) - x = f.parent().gen() - t = f.parent().base_ring().gen() - phi = F.parent().hom([x, t]) - v = [(phi(P),e) for P, e in fac] - unit = phi(fac.unit())/d - w = [] - for a, e in v: - c = a.leading_coefficient() - a = a/c - # undo any variable substitution that we introduced for the bivariate polynomial - if old_variable_name != a.variable_name(): - a = a.change_variable_name(old_variable_name) - unit *= (c**e) - if a.is_unit(): - unit *= a**e - else: - w.append((a,e)) - from sage.structure.factorization import Factorization - return Factorization(w, unit=unit) - - def extension(self, f, names=None): - """ - Create an extension `L = K[y]/(f(y))` of the rational function field. - - INPUT: - - - ``f`` -- univariate polynomial over self - - - ``names`` -- string or length-1 tuple - - OUTPUT: - - - a function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: K.extension(y^5 - x^3 - 3*x + x*y) - Function field in y defined by y^5 + x*y - x^3 - 3*x - - A nonintegral defining polynomial:: - - sage: K.<t> = FunctionField(QQ); R.<y> = K[] - sage: K.extension(y^3 + (1/t)*y + t^3/(t+1)) - Function field in y defined by y^3 + 1/t*y + t^3/(t + 1) - - The defining polynomial need not be monic or integral:: - - sage: K.extension(t*y^3 + (1/t)*y + t^3/(t+1)) - Function field in y defined by t*y^3 + 1/t*y + t^3/(t + 1) - """ - from . import constructor - return constructor.FunctionFieldExtension(f, names) - - @cached_method - def polynomial_ring(self, var='x'): - """ - Return a polynomial ring in one variable over the rational function field. - - INPUT: - - - ``var`` -- string; name of the variable - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K.polynomial_ring() - Univariate Polynomial Ring in x over Rational function field in x over Rational Field - sage: K.polynomial_ring('T') - Univariate Polynomial Ring in T over Rational function field in x over Rational Field - """ - return self[var] - - @cached_method(key=lambda self, base, basis, map: map) - def free_module(self, base=None, basis=None, map=True): - """ - Return a vector space `V` and isomorphisms from the field to `V` and - from `V` to the field. - - This function allows us to identify the elements of this field with - elements of a one-dimensional vector space over the field itself. This - method exists so that all function fields (rational or not) have the - same interface. - - INPUT: - - - ``base`` -- the base field of the vector space; must be the function - field itself (the default) - - - ``basis`` -- (ignored) a basis for the vector space - - - ``map`` -- (default ``True``), whether to return maps to and from the vector space - - OUTPUT: - - - a vector space `V` over base field - - - an isomorphism from `V` to the field - - - the inverse isomorphism from the field to `V` - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K.free_module() - (Vector space of dimension 1 over Rational function field in x over Rational Field, Isomorphism: - From: Vector space of dimension 1 over Rational function field in x over Rational Field - To: Rational function field in x over Rational Field, Isomorphism: - From: Rational function field in x over Rational Field - To: Vector space of dimension 1 over Rational function field in x over Rational Field) - - TESTS:: - - sage: K.free_module() - (Vector space of dimension 1 over Rational function field in x over Rational Field, Isomorphism: - From: Vector space of dimension 1 over Rational function field in x over Rational Field - To: Rational function field in x over Rational Field, Isomorphism: - From: Rational function field in x over Rational Field - To: Vector space of dimension 1 over Rational function field in x over Rational Field) - - """ - if basis is not None: - raise NotImplementedError - from .maps import MapVectorSpaceToFunctionField, MapFunctionFieldToVectorSpace - if base is None: - base = self - elif base is not self: - raise ValueError("base must be the rational function field itself") - V = base**1 - if not map: - return V - from_V = MapVectorSpaceToFunctionField(V, self) - to_V = MapFunctionFieldToVectorSpace(self, V) - return (V, from_V, to_V) - - def random_element(self, *args, **kwds): - """ - Create a random element of the rational function field. - - Parameters are passed to the random_element method of the - underlying fraction field. - - EXAMPLES:: - - sage: FunctionField(QQ,'alpha').random_element() # random - (-1/2*alpha^2 - 4)/(-12*alpha^2 + 1/2*alpha - 1/95) - """ - return self(self._field.random_element(*args, **kwds)) - - def degree(self, base=None): - """ - Return the degree over the base field of the rational function - field. Since the base field is the rational function field itself, the - degree is 1. - - INPUT: - - - ``base`` -- the base field of the vector space; must be the function - field itself (the default) - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: K.degree() - 1 - """ - if base is None: - base = self - elif base is not self: - raise ValueError("base must be the rational function field itself") - from sage.rings.integer_ring import ZZ - return ZZ(1) - - def gen(self, n=0): - """ - Return the ``n``-th generator of the function field. If ``n`` is not - 0, then an IndexError is raised. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ); K.gen() - t - sage: K.gen().parent() - Rational function field in t over Rational Field - sage: K.gen(1) - Traceback (most recent call last): - ... - IndexError: Only one generator. - """ - if n != 0: - raise IndexError("Only one generator.") - return self._gen - - def ngens(self): - """ - Return the number of generators, which is 1. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: K.ngens() - 1 - """ - return 1 - - def base_field(self): - """ - Return the base field of the rational function field, which is just - the function field itself. - - EXAMPLES:: - - sage: K.<t> = FunctionField(GF(7)) - sage: K.base_field() - Rational function field in t over Finite Field of size 7 - """ - return self - - def hom(self, im_gens, base_morphism=None): - """ - Create a homomorphism from ``self`` to another ring. - - INPUT: - - - ``im_gens`` -- exactly one element of some ring. It must be - invertible and transcendental over the image of - ``base_morphism``; this is not checked. - - - ``base_morphism`` -- a homomorphism from the base field into the - other ring. If ``None``, try to use a coercion map. - - OUTPUT: - - - a map between function fields - - EXAMPLES: - - We make a map from a rational function field to itself:: - - sage: K.<x> = FunctionField(GF(7)) - sage: K.hom( (x^4 + 2)/x) - Function Field endomorphism of Rational function field in x over Finite Field of size 7 - Defn: x |--> (x^4 + 2)/x - - We construct a map from a rational function field into a - non-rational extension field:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^3 + 6*x^3 + x) - sage: f = K.hom(y^2 + y + 2); f - Function Field morphism: - From: Rational function field in x over Finite Field of size 7 - To: Function field in y defined by y^3 + 6*x^3 + x - Defn: x |--> y^2 + y + 2 - sage: f(x) - y^2 + y + 2 - sage: f(x^2) - 5*y^2 + (x^3 + 6*x + 4)*y + 2*x^3 + 5*x + 4 - """ - if isinstance(im_gens, CategoryObject): - return self.Hom(im_gens).natural_map() - if not isinstance(im_gens, (list,tuple)): - im_gens = [im_gens] - if len(im_gens) != 1: - raise ValueError("there must be exactly one generator") - x = im_gens[0] - R = x.parent() - if base_morphism is None and not R.has_coerce_map_from(self.constant_field()): - raise ValueError("you must specify a morphism on the base field") - from .maps import FunctionFieldMorphism_rational - return FunctionFieldMorphism_rational(self.Hom(R), x, base_morphism) - - def field(self): - """ - Return the underlying field, forgetting the function field - structure. - - EXAMPLES:: - - sage: K.<t> = FunctionField(GF(7)) - sage: K.field() - Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 - - .. SEEALSO:: - - :meth:`sage.rings.fraction_field.FractionField_1poly_field.function_field` - - """ - return self._field - - @cached_method - def maximal_order(self): - """ - Return the maximal order of the function field. - - Since this is a rational function field it is of the form `K(t)`, and the - maximal order is by definition `K[t]`, where `K` is the constant field. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: K.maximal_order() - Maximal order of Rational function field in t over Rational Field - sage: K.equation_order() - Maximal order of Rational function field in t over Rational Field - """ - from .order import FunctionFieldMaximalOrder_rational - return FunctionFieldMaximalOrder_rational(self) - - equation_order = maximal_order - - @cached_method - def maximal_order_infinite(self): - """ - Return the maximal infinite order of the function field. - - By definition, this is the valuation ring of the degree valuation of - the rational function field. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: K.maximal_order_infinite() - Maximal infinite order of Rational function field in t over Rational Field - sage: K.equation_order_infinite() - Maximal infinite order of Rational function field in t over Rational Field - """ - from .order import FunctionFieldMaximalOrderInfinite_rational - return FunctionFieldMaximalOrderInfinite_rational(self) - - equation_order_infinite = maximal_order_infinite - - def constant_base_field(self): - """ - Return the field of which the rational function field is a - transcendental extension. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: K.constant_base_field() - Rational Field - """ - return self._constant_field - - constant_field = constant_base_field - - def different(self): - """ - Return the different of the rational function field. - - For a rational function field, the different is simply the zero - divisor. - - EXAMPLES:: - - sage: K.<t> = FunctionField(QQ) - sage: K.different() - 0 - """ - return self.divisor_group().zero() - - def genus(self): - """ - Return the genus of the function field, namely 0. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K.genus() - 0 - """ - return Integer(0) - - def change_variable_name(self, name): - r""" - Return a field isomorphic to this field with variable ``name``. - - INPUT: - - - ``name`` -- a string or a tuple consisting of a single string, the - name of the new variable - - OUTPUT: - - A triple ``F,f,t`` where ``F`` is a rational function field, ``f`` is - an isomorphism from ``F`` to this field, and ``t`` is the inverse of - ``f``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: L,f,t = K.change_variable_name('y') - sage: L,f,t - (Rational function field in y over Rational Field, - Function Field morphism: - From: Rational function field in y over Rational Field - To: Rational function field in x over Rational Field - Defn: y |--> x, - Function Field morphism: - From: Rational function field in x over Rational Field - To: Rational function field in y over Rational Field - Defn: x |--> y) - sage: L.change_variable_name('x')[0] is K - True - - """ - if isinstance(name, tuple): - if len(name) != 1: - raise ValueError("names must be a tuple with a single string") - name = name[0] - if name == self.variable_name(): - id = Hom(self,self).identity() - return self,id,id - else: - from .constructor import FunctionField - ret = FunctionField(self.constant_base_field(), name) - return ret, ret.hom(self.gen()), self.hom(ret.gen()) - - def residue_field(self, place, name=None): - """ - Return the residue field of the place along with the maps from - and to it. - - INPUT: - - - ``place`` -- place of the function field - - - ``name`` -- string; name of the generator of the residue field - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(5)) - sage: p = F.places_finite(2)[0] - sage: R, fr_R, to_R = F.residue_field(p) - sage: R - Finite Field in z2 of size 5^2 - sage: to_R(x) in R - True - """ - return place.residue_field(name=name) - - -class RationalFunctionField_char_zero(RationalFunctionField): - """ - Rational function fields of characteristic zero. - """ - @cached_method - def higher_derivation(self): - """ - Return the higher derivation for the function field. - - This is also called the Hasse-Schmidt derivation. - - EXAMPLES:: - - sage: F.<x> = FunctionField(QQ) - sage: d = F.higher_derivation() - sage: [d(x^5,i) for i in range(10)] - [x^5, 5*x^4, 10*x^3, 10*x^2, 5*x, 1, 0, 0, 0, 0] - sage: [d(x^9,i) for i in range(10)] - [x^9, 9*x^8, 36*x^7, 84*x^6, 126*x^5, 126*x^4, 84*x^3, 36*x^2, 9*x, 1] - """ - from .maps import FunctionFieldHigherDerivation_char_zero - return FunctionFieldHigherDerivation_char_zero(self) - - -class RationalFunctionField_global(RationalFunctionField): - """ - Rational function field over finite fields. - """ - _differentials_space = DifferentialsSpace_global - - def places(self, degree=1): - """ - Return all places of the degree. - - INPUT: - - - ``degree`` -- (default: 1) a positive integer - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(5)) - sage: F.places() - [Place (1/x), - Place (x), - Place (x + 1), - Place (x + 2), - Place (x + 3), - Place (x + 4)] - """ - if degree == 1: - return [self.place_infinite()] + self.places_finite(degree) - else: - return self.places_finite(degree) - - def places_finite(self, degree=1): - """ - Return the finite places of the degree. - - INPUT: - - - ``degree`` -- (default: 1) a positive integer - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(5)) - sage: F.places_finite() - [Place (x), Place (x + 1), Place (x + 2), Place (x + 3), Place (x + 4)] - """ - return list(self._places_finite(degree)) - - def _places_finite(self, degree=1): - """ - Return a generator for all monic irreducible polynomials of the degree. - - INPUT: - - - ``degree`` -- (default: 1) a positive integer - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(5)) - sage: F._places_finite() - <generator object ...> - """ - O = self.maximal_order() - R = O._ring - G = R.polynomials(max_degree=degree - 1) - lm = R.monomial(degree) - for g in G: - h = lm + g - if h.is_irreducible(): - yield O.ideal(h).place() - - def place_infinite(self): - """ - Return the unique place at infinity. - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(5)) - sage: F.place_infinite() - Place (1/x) - """ - return self.maximal_order_infinite().prime_ideal().place() - - def get_place(self, degree): - """ - Return a place of ``degree``. - - INPUT: - - - ``degree`` -- a positive integer - - EXAMPLES:: - - sage: F.<a> = GF(2) - sage: K.<x> = FunctionField(F) - sage: K.get_place(1) - Place (x) - sage: K.get_place(2) - Place (x^2 + x + 1) - sage: K.get_place(3) - Place (x^3 + x + 1) - sage: K.get_place(4) - Place (x^4 + x + 1) - sage: K.get_place(5) - Place (x^5 + x^2 + 1) - - """ - for p in self._places_finite(degree): - return p - - assert False, "there is a bug around" - - @cached_method - def higher_derivation(self): - """ - Return the higher derivation for the function field. - - This is also called the Hasse-Schmidt derivation. - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(5)) - sage: d = F.higher_derivation() - sage: [d(x^5,i) for i in range(10)] - [x^5, 0, 0, 0, 0, 1, 0, 0, 0, 0] - sage: [d(x^7,i) for i in range(10)] - [x^7, 2*x^6, x^5, 0, 0, x^2, 2*x, 1, 0, 0] - """ - from .maps import RationalFunctionFieldHigherDerivation_global - return RationalFunctionFieldHigherDerivation_global(self) diff --git a/src/sage/rings/function_field/function_field_polymod.py b/src/sage/rings/function_field/function_field_polymod.py new file mode 100644 index 00000000000..460096c94a1 --- /dev/null +++ b/src/sage/rings/function_field/function_field_polymod.py @@ -0,0 +1,2581 @@ +# sage.doctest: optional - sage.rings.function_field +r""" +Function Fields: extension +""" + +# ***************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2010 Robert Bradshaw <robertwb@math.washington.edu> +# 2011-2018 Julian Rรผth <julian.rueth@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2011 Syed Ahmad Lavasani +# 2013-2014 Simon King +# 2017 Dean Bisogno +# 2017 Alyson Deines +# 2017-2019 David Roe +# 2017-2022 Kwankyu Lee +# 2018 Marc Mezzarobba +# 2018 Wilfried Luebbe +# 2019 Brent Baccala +# 2022 Frรฉdรฉric Chapoton +# 2022 Gonzalo Tornarรญa +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.arith.functions import lcm +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import LazyImport +from sage.rings.qqbar_decorators import handle_AA_and_QQbar +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.integer import Integer +from sage.categories.homset import Hom +from sage.categories.function_fields import FunctionFields + +from .element import FunctionFieldElement +from .element_polymod import FunctionFieldElement_polymod +from .function_field import FunctionField +from .function_field_rational import RationalFunctionField + + +class FunctionField_polymod(FunctionField): + """ + Function fields defined by a univariate polynomial, as an extension of the + base field. + + INPUT: + + - ``polynomial`` -- univariate polynomial over a function field + + - ``names`` -- tuple of length 1 or string; variable names + + - ``category`` -- category (default: category of function fields) + + EXAMPLES: + + We make a function field defined by a degree 5 polynomial over the + rational function field over the rational numbers:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L + Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x + + We next make a function field over the above nontrivial function + field L:: + + sage: S.<z> = L[] + sage: M.<z> = L.extension(z^2 + y*z + y); M + Function field in z defined by z^2 + y*z + y + sage: 1/z + ((-x/(x^4 + 1))*y^4 + 2*x^2/(x^4 + 1))*z - 1 + sage: z * (1/z) + 1 + + We drill down the tower of function fields:: + + sage: M.base_field() + Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x + sage: M.base_field().base_field() + Rational function field in x over Rational Field + sage: M.base_field().base_field().constant_field() + Rational Field + sage: M.constant_base_field() + Rational Field + + .. WARNING:: + + It is not checked if the polynomial used to define the function field is irreducible + Hence it is not guaranteed that this object really is a field! + This is illustrated below. + + :: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(x^2 - y^2) + sage: (y - x)*(y + x) + 0 + sage: 1/(y - x) + 1 + sage: y - x == 0; y + x == 0 + False + False + """ + Element = FunctionFieldElement_polymod + + def __init__(self, polynomial, names, category=None): + """ + Create a function field defined as an extension of another function + field by adjoining a root of a univariate polynomial. + + EXAMPLES: + + We create an extension of a function field:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L = K.extension(y^5 - x^3 - 3*x + x*y); L + Function field in y defined by y^5 + x*y - x^3 - 3*x + sage: TestSuite(L).run(max_runs=512) # long time (15s) + + We can set the variable name, which doesn't have to be y:: + + sage: L.<w> = K.extension(y^5 - x^3 - 3*x + x*y); L + Function field in w defined by w^5 + x*w - x^3 - 3*x + + TESTS: + + Test that :trac:`17033` is fixed:: + + sage: K.<t> = FunctionField(QQ) + sage: R.<x> = QQ[] + sage: M.<z> = K.extension(x^7 - x - t) + sage: M(x) + z + sage: M('z') + z + sage: M('x') + Traceback (most recent call last): + ... + TypeError: unable to evaluate 'x' in Fraction Field of Univariate + Polynomial Ring in t over Rational Field + """ + from sage.rings.polynomial.polynomial_element import Polynomial + if polynomial.parent().ngens() > 1 or not isinstance(polynomial, Polynomial): + raise TypeError("polynomial must be univariate a polynomial") + if names is None: + names = (polynomial.variable_name(), ) + elif names != polynomial.variable_name(): + polynomial = polynomial.change_variable_name(names) + if polynomial.degree() <= 0: + raise ValueError("polynomial must have positive degree") + base_field = polynomial.base_ring() + if not isinstance(base_field, FunctionField): + raise TypeError("polynomial must be over a FunctionField") + + self._base_field = base_field + self._polynomial = polynomial + + FunctionField.__init__(self, base_field, names=names, + category=FunctionFields().or_subcategory(category)) + + from .place_polymod import FunctionFieldPlace_polymod + self._place_class = FunctionFieldPlace_polymod + + self._hash = hash(polynomial) + self._ring = self._polynomial.parent() + + self._populate_coercion_lists_(coerce_list=[base_field, self._ring]) + self._gen = self(self._ring.gen()) + + def __hash__(self): + """ + Return hash of the function field. + + The hash value is equal to the hash of the defining polynomial. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L = K.extension(y^5 - x^3 - 3*x + x*y) + sage: hash(L) == hash(L.polynomial()) + True + """ + return self._hash + + def _element_constructor_(self, x): + r""" + Make ``x`` into an element of the function field, possibly not canonically. + + INPUT: + + - ``x`` -- element + + TESTS:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: L._element_constructor_(L.polynomial_ring().gen()) + y + """ + if isinstance(x, FunctionFieldElement): + return self.element_class(self, self._ring(x.element())) + return self.element_class(self, self._ring(x)) + + def gen(self, n=0): + """ + Return the `n`-th generator of the function field. By default, `n` is 0; any other + value of `n` leads to an error. The generator is the class of `y`, if we view + the function field as being presented as `K[y]/(f(y))`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: L.gen() + y + sage: L.gen(1) + Traceback (most recent call last): + ... + IndexError: there is only one generator + """ + if n != 0: + raise IndexError("there is only one generator") + return self._gen + + def ngens(self): + """ + Return the number of generators of the function field over its base + field. This is by definition 1. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: L.ngens() + 1 + """ + return 1 + + def _to_base_field(self, f): + r""" + Return ``f`` as an element of the :meth:`base_field`. + + INPUT: + + - ``f`` -- element of the function field which lies in the base + field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: L._to_base_field(L(x)) + x + sage: L._to_base_field(y) + Traceback (most recent call last): + ... + ValueError: y is not an element of the base field + + TESTS: + + Verify that :trac:`21872` has been resolved:: + + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^2 - y) + + sage: M(1) in QQ + True + sage: M(y) in L + True + sage: M(x) in K + True + sage: z in K + False + """ + K = self.base_field() + if f.element().is_constant(): + return K(f.element()) + raise ValueError("%r is not an element of the base field" % (f,)) + + def _to_constant_base_field(self, f): + """ + Return ``f`` as an element of the :meth:`constant_base_field`. + + INPUT: + + - ``f`` -- element of the rational function field which is a + constant + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: L._to_constant_base_field(L(1)) + 1 + sage: L._to_constant_base_field(y) + Traceback (most recent call last): + ... + ValueError: y is not an element of the base field + + TESTS: + + Verify that :trac:`21872` has been resolved:: + + sage: L(1) in QQ + True + sage: y in QQ + False + """ + return self.base_field()._to_constant_base_field(self._to_base_field(f)) + + def monic_integral_model(self, names=None): + """ + Return a function field isomorphic to this field but which is an + extension of a rational function field with defining polynomial that is + monic and integral over the constant base field. + + INPUT: + + - ``names`` -- a string or a tuple of up to two strings (default: + ``None``), the name of the generator of the field, and the name of + the generator of the underlying rational function field (if a tuple); + if not given, then the names are chosen automatically. + + OUTPUT: + + A triple ``(F,f,t)`` where ``F`` is a function field, ``f`` is an + isomorphism from ``F`` to this field, and ``t`` is the inverse of + ``f``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(x^2*y^5 - 1/x); L + Function field in y defined by x^2*y^5 - 1/x + sage: A, from_A, to_A = L.monic_integral_model('z') + sage: A + Function field in z defined by z^5 - x^12 + sage: from_A + Function Field morphism: + From: Function field in z defined by z^5 - x^12 + To: Function field in y defined by x^2*y^5 - 1/x + Defn: z |--> x^3*y + x |--> x + sage: to_A + Function Field morphism: + From: Function field in y defined by x^2*y^5 - 1/x + To: Function field in z defined by z^5 - x^12 + Defn: y |--> 1/x^3*z + x |--> x + sage: to_A(y) + 1/x^3*z + sage: from_A(to_A(y)) + y + sage: from_A(to_A(1/y)) + x^3*y^4 + sage: from_A(to_A(1/y)) == 1/y + True + + This also works for towers of function fields:: + + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^2*y - 1/x) + sage: M.monic_integral_model() + (Function field in z_ defined by z_^10 - x^18, + Function Field morphism: + From: Function field in z_ defined by z_^10 - x^18 + To: Function field in z defined by y*z^2 - 1/x + Defn: z_ |--> x^2*z + x |--> x, Function Field morphism: + From: Function field in z defined by y*z^2 - 1/x + To: Function field in z_ defined by z_^10 - x^18 + Defn: z |--> 1/x^2*z_ + y |--> 1/x^15*z_^8 + x |--> x) + + TESTS: + + If the field is already a monic integral extension, then it is returned + unchanged:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: L.monic_integral_model() + (Function field in y defined by y^2 - x, + Function Field endomorphism of Function field in y defined by y^2 - x + Defn: y |--> y + x |--> x, Function Field endomorphism of Function field in y defined by y^2 - x + Defn: y |--> y + x |--> x) + + unless ``names`` does not match with the current names:: + + sage: L.monic_integral_model(names=('yy','xx')) + (Function field in yy defined by yy^2 - xx, + Function Field morphism: + From: Function field in yy defined by yy^2 - xx + To: Function field in y defined by y^2 - x + Defn: yy |--> y + xx |--> x, Function Field morphism: + From: Function field in y defined by y^2 - x + To: Function field in yy defined by yy^2 - xx + Defn: y |--> yy + x |--> xx) + + """ + if names: + if not isinstance(names, tuple): + names = (names,) + if len(names) > 2: + raise ValueError("names must contain at most 2 entries") + + if self.base_field() is not self.rational_function_field(): + L,from_L,to_L = self.simple_model() + ret,ret_to_L,L_to_ret = L.monic_integral_model(names) + from_ret = ret.hom( [from_L(ret_to_L(ret.gen())), from_L(ret_to_L(ret.base_field().gen()))] ) + to_ret = self.hom( [L_to_ret(to_L(k.gen())) for k in self._intermediate_fields(self.rational_function_field())] ) + return ret, from_ret, to_ret + else: + if self.polynomial().is_monic() and all(c.denominator().is_one() for c in self.polynomial()): + # self is already monic and integral + if names is None or names == (): + names = (self.variable_name(),) + return self.change_variable_name(names) + else: + if not names: + names = (self.variable_name()+"_",) + if len(names) == 1: + names = (names[0], self.rational_function_field().variable_name()) + + g, d = self._make_monic_integral(self.polynomial()) + K,from_K,to_K = self.base_field().change_variable_name(names[1]) + g = g.map_coefficients(to_K) + ret = K.extension(g, names=names[0]) + from_ret = ret.hom([self.gen() * d, self.base_field().gen()]) + to_ret = self.hom([ret.gen() / d, ret.base_field().gen()]) + return ret, from_ret, to_ret + + def _make_monic_integral(self, f): + """ + Return a monic integral polynomial `g` and an element `d` of the base + field such that `g(y*d)=0` where `y` is a root of `f`. + + INPUT: + + - ``f`` -- polynomial + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(x^2*y^5 - 1/x) + sage: g, d = L._make_monic_integral(L.polynomial()); g,d + (y^5 - x^12, x^3) + sage: (y*d).is_integral() + True + sage: g.is_monic() + True + sage: g(y*d) + 0 + """ + R = f.base_ring() + if not isinstance(R, RationalFunctionField): + raise NotImplementedError + + # make f monic + n = f.degree() + c = f.leading_coefficient() + if c != 1: + f = f / c + + # find lcm of denominators + # would be good to replace this by minimal... + d = lcm([b.denominator() for b in f.list() if b]) + if d != 1: + x = f.parent().gen() + g = (d**n) * f(x/d) + else: + g = f + return g, d + + def constant_field(self): + """ + Return the algebraic closure of the constant field of the function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^5 - x) # needs sage.rings.finite_rings + sage: L.constant_field() # needs sage.rings.finite_rings + Traceback (most recent call last): + ... + NotImplementedError + """ + raise NotImplementedError + + def constant_base_field(self): + """ + Return the base constant field of the function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L + Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x + sage: L.constant_base_field() + Rational Field + sage: S.<z> = L[] + sage: M.<z> = L.extension(z^2 - y) + sage: M.constant_base_field() + Rational Field + """ + return self.base_field().constant_base_field() + + @cached_method(key=lambda self, base: self.base_field() if base is None else base) + def degree(self, base=None): + """ + Return the degree of the function field over the function field ``base``. + + INPUT: + + - ``base`` -- a function field (default: ``None``), a function field + from which this field has been constructed as a finite extension. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L + Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x + sage: L.degree() + 5 + sage: L.degree(L) + 1 + + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^2 - y) + sage: M.degree(L) + 2 + sage: M.degree(K) + 10 + + TESTS:: + + sage: L.degree(M) + Traceback (most recent call last): + ... + ValueError: base must be the rational function field itself + + """ + if base is None: + base = self.base_field() + if base is self: + from sage.rings.integer_ring import ZZ + return ZZ(1) + return self._polynomial.degree() * self.base_field().degree(base) + + def _repr_(self): + """ + Return the string representation of the function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: L._repr_() + 'Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x' + """ + return "Function field in %s defined by %s" % (self.variable_name(), self._polynomial) + + def base_field(self): + """ + Return the base field of the function field. This function field is + presented as `L = K[y]/(f(y))`, and the base field is by definition the + field `K`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: L.base_field() + Rational function field in x over Rational Field + """ + return self._base_field + + def random_element(self, *args, **kwds): + """ + Create a random element of the function field. Parameters are passed + onto the random_element method of the base_field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - (x^2 + x)) + sage: L.random_element() # random + ((x^2 - x + 2/3)/(x^2 + 1/3*x - 1))*y^2 + ((-1/4*x^2 + 1/2*x - 1)/(-5/2*x + 2/3))*y + + (-1/2*x^2 - 4)/(-12*x^2 + 1/2*x - 1/95) + """ + return self(self._ring.random_element(degree=self.degree(), *args, **kwds)) + + def polynomial(self): + """ + Return the univariate polynomial that defines the function field, that + is, the polynomial `f(y)` so that the function field is of the form + `K[y]/(f(y))`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: L.polynomial() + y^5 - 2*x*y + (-x^4 - 1)/x + """ + return self._polynomial + + def is_separable(self, base=None): + r""" + Return whether this is a separable extension of ``base``. + + INPUT: + + - ``base`` -- a function field from which this field has been created + as an extension or ``None`` (default: ``None``); if ``None``, then + return whether this is a separable extension over its base field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: L.is_separable() + False + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^3 - y) + sage: M.is_separable() + True + sage: M.is_separable(K) + False + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(5)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: L.is_separable() + True + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(5)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^5 - 1) + sage: L.is_separable() + False + + """ + if base is None: + base = self.base_field() + for k in self._intermediate_fields(base)[:-1]: + f = k.polynomial() + g = f.derivative() + if f.gcd(g).degree() != 0: + return False + return True + + def polynomial_ring(self): + """ + Return the polynomial ring used to represent elements of the + function field. If we view the function field as being presented + as `K[y]/(f(y))`, then this function returns the ring `K[y]`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: L.polynomial_ring() + Univariate Polynomial Ring in y over Rational function field in x over Rational Field + """ + return self._ring + + @cached_method(key=lambda self, base, basis, map: (self.base_field() if base is None else base, basis, map)) + def free_module(self, base=None, basis=None, map=True): + """ + Return a vector space and isomorphisms from the field to and from the + vector space. + + This function allows us to identify the elements of this field with + elements of a vector space over the base field, which is useful for + representation and arithmetic with orders, ideals, etc. + + INPUT: + + - ``base`` -- a function field (default: ``None``), the returned vector + space is over this subfield `R`, which defaults to the base field of this + function field. + + - ``basis`` -- a basis for this field over the base. + + - ``maps`` -- boolean (default ``True``), whether to return + `R`-linear maps to and from `V`. + + OUTPUT: + + - a vector space over the base function field + + - an isomorphism from the vector space to the field (if requested) + + - an isomorphism from the field to the vector space (if requested) + + EXAMPLES: + + We define a function field:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L + Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x + + We get the vector spaces, and maps back and forth:: + + sage: # needs sage.modules + sage: V, from_V, to_V = L.free_module() + sage: V + Vector space of dimension 5 over Rational function field in x over Rational Field + sage: from_V + Isomorphism: + From: Vector space of dimension 5 over Rational function field in x over Rational Field + To: Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x + sage: to_V + Isomorphism: + From: Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x + To: Vector space of dimension 5 over Rational function field in x over Rational Field + + We convert an element of the vector space back to the function field:: + + sage: from_V(V.1) # needs sage.modules + y + + We define an interesting element of the function field:: + + sage: a = 1/L.0; a # needs sage.modules + (x/(x^4 + 1))*y^4 - 2*x^2/(x^4 + 1) + + We convert it to the vector space, and get a vector over the base field:: + + sage: to_V(a) # needs sage.modules + (-2*x^2/(x^4 + 1), 0, 0, 0, x/(x^4 + 1)) + + We convert to and back, and get the same element:: + + sage: from_V(to_V(a)) == a # needs sage.modules + True + + In the other direction:: + + sage: v = x*V.0 + (1/x)*V.1 # needs sage.modules + sage: to_V(from_V(v)) == v # needs sage.modules + True + + And we show how it works over an extension of an extension field:: + + sage: R2.<z> = L[]; M.<z> = L.extension(z^2 - y) + sage: M.free_module() # needs sage.modules + (Vector space of dimension 2 over Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x, Isomorphism: + From: Vector space of dimension 2 over Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x + To: Function field in z defined by z^2 - y, Isomorphism: + From: Function field in z defined by z^2 - y + To: Vector space of dimension 2 over Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x) + + We can also get the vector space of ``M`` over ``K``:: + + sage: M.free_module(K) # needs sage.modules + (Vector space of dimension 10 over Rational function field in x over Rational Field, Isomorphism: + From: Vector space of dimension 10 over Rational function field in x over Rational Field + To: Function field in z defined by z^2 - y, Isomorphism: + From: Function field in z defined by z^2 - y + To: Vector space of dimension 10 over Rational function field in x over Rational Field) + + """ + if basis is not None: + raise NotImplementedError + from .maps import MapVectorSpaceToFunctionField, MapFunctionFieldToVectorSpace + if base is None: + base = self.base_field() + degree = self.degree(base) + V = base**degree + if not map: + return V + from_V = MapVectorSpaceToFunctionField(V, self) + to_V = MapFunctionFieldToVectorSpace(self, V) + return (V, from_V, to_V) + + def maximal_order(self): + """ + Return the maximal order of the function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: L.maximal_order() + Maximal order of Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x + """ + from .order_polymod import FunctionFieldMaximalOrder_polymod + return FunctionFieldMaximalOrder_polymod(self) + + def maximal_order_infinite(self): + """ + Return the maximal infinite order of the function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: L.maximal_order_infinite() + Maximal infinite order of Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x + + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] # needs sage.rings.finite_rings + sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) # needs sage.rings.finite_rings + sage: F.maximal_order_infinite() # needs sage.rings.finite_rings + Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2 + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.finite_rings + sage: L.maximal_order_infinite() # needs sage.rings.finite_rings + Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x + """ + from .order_polymod import FunctionFieldMaximalOrderInfinite_polymod + return FunctionFieldMaximalOrderInfinite_polymod(self) + + def different(self): + """ + Return the different of the function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) # needs sage.rings.finite_rings + sage: F.different() # needs sage.rings.finite_rings + 2*Place (x, (1/(x^3 + x^2 + x))*y^2) + + 2*Place (x^2 + x + 1, (1/(x^3 + x^2 + x))*y^2) + """ + O = self.maximal_order() + Oinf = self.maximal_order_infinite() + return O.different().divisor() + Oinf.different().divisor() + + def equation_order(self): + """ + Return the equation order of the function field. + + If we view the function field as being presented as `K[y]/(f(y))`, then + the order generated by the class of `y` is returned. If `f` + is not monic, then :meth:`_make_monic_integral` is called, and instead + we get the order generated by some integral multiple of a root of `f`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: O = L.equation_order() + sage: O.basis() + (1, x*y, x^2*y^2, x^3*y^3, x^4*y^4) + + We try an example, in which the defining polynomial is not + monic and is not integral:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(x^2*y^5 - 1/x); L + Function field in y defined by x^2*y^5 - 1/x + sage: O = L.equation_order() + sage: O.basis() + (1, x^3*y, x^6*y^2, x^9*y^3, x^12*y^4) + """ + d = self._make_monic_integral(self.polynomial())[1] + return self.order(d*self.gen(), check=False) + + def hom(self, im_gens, base_morphism=None): + """ + Create a homomorphism from the function field to another function field. + + INPUT: + + - ``im_gens`` -- list of images of the generators of the function field + and of successive base rings. + + - ``base_morphism`` -- homomorphism of the base ring, after the + ``im_gens`` are used. Thus if ``im_gens`` has length 2, then + ``base_morphism`` should be a morphism from the base ring of the base + ring of the function field. + + EXAMPLES: + + We create a rational function field, and a quadratic extension of it:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + + We make the field automorphism that sends y to -y:: + + sage: f = L.hom(-y); f + Function Field endomorphism of Function field in y defined by y^2 - x^3 - 1 + Defn: y |--> -y + + Evaluation works:: + + sage: f(y*x - 1/x) + -x*y - 1/x + + We try to define an invalid morphism:: + + sage: f = L.hom(y + 1) + Traceback (most recent call last): + ... + ValueError: invalid morphism + + We make a morphism of the base rational function field:: + + sage: phi = K.hom(x + 1); phi + Function Field endomorphism of Rational function field in x over Rational Field + Defn: x |--> x + 1 + sage: phi(x^3 - 3) + x^3 + 3*x^2 + 3*x - 2 + sage: (x+1)^3 - 3 + x^3 + 3*x^2 + 3*x - 2 + + We make a morphism by specifying where the generators and the + base generators go:: + + sage: L.hom([-y, x]) + Function Field endomorphism of Function field in y defined by y^2 - x^3 - 1 + Defn: y |--> -y + x |--> x + + You can also specify a morphism on the base:: + + sage: R1.<q> = K[] + sage: L1.<q> = K.extension(q^2 - (x+1)^3 - 1) + sage: L.hom(q, base_morphism=phi) + Function Field morphism: + From: Function field in y defined by y^2 - x^3 - 1 + To: Function field in q defined by q^2 - x^3 - 3*x^2 - 3*x - 2 + Defn: y |--> q + x |--> x + 1 + + We make another extension of a rational function field:: + + sage: K2.<t> = FunctionField(QQ); R2.<w> = K2[] + sage: L2.<w> = K2.extension((4*w)^2 - (t+1)^3 - 1) + + We define a morphism, by giving the images of generators:: + + sage: f = L.hom([4*w, t + 1]); f + Function Field morphism: + From: Function field in y defined by y^2 - x^3 - 1 + To: Function field in w defined by 16*w^2 - t^3 - 3*t^2 - 3*t - 2 + Defn: y |--> 4*w + x |--> t + 1 + + Evaluation works, as expected:: + + sage: f(y+x) + 4*w + t + 1 + sage: f(x*y + x/(x^2+1)) + (4*t + 4)*w + (t + 1)/(t^2 + 2*t + 2) + + We make another extension of a rational function field:: + + sage: K3.<yy> = FunctionField(QQ); R3.<xx> = K3[] + sage: L3.<xx> = K3.extension(yy^2 - xx^3 - 1) + + This is the function field L with the generators exchanged. We define a morphism to L:: + + sage: g = L3.hom([x,y]); g + Function Field morphism: + From: Function field in xx defined by -xx^3 + yy^2 - 1 + To: Function field in y defined by y^2 - x^3 - 1 + Defn: xx |--> x + yy |--> y + + """ + if not isinstance(im_gens, (list,tuple)): + im_gens = [im_gens] + if len(im_gens) == 0: + raise ValueError("no images specified") + + if len(im_gens) > 1: + base_morphism = self.base_field().hom(im_gens[1:], base_morphism) + + # the codomain of this morphism is the field containing all the im_gens + codomain = im_gens[0].parent() + if base_morphism is not None: + from sage.categories.pushout import pushout + codomain = pushout(codomain, base_morphism.codomain()) + + from .maps import FunctionFieldMorphism_polymod + return FunctionFieldMorphism_polymod(self.Hom(codomain), im_gens[0], base_morphism) + + @cached_method + def genus(self): + """ + Return the genus of the function field. + + For now, the genus is computed using Singular. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) + sage: L.genus() + 3 + """ + # Unfortunately Singular can not compute the genus with the + # polynomial_ring()._singular_ object because genus method only accepts + # a ring of transcendental degree 2 over a prime field not a ring of + # transcendental degree 1 over a rational function field of one variable + + if (isinstance(self._base_field, RationalFunctionField) and + self._base_field.constant_field().is_prime_field()): + from sage.interfaces.singular import singular + + # making the auxiliary ring which only has polynomials + # with integral coefficients. + tmpAuxRing = PolynomialRing(self._base_field.constant_field(), + str(self._base_field.gen())+','+str(self._ring.gen())) + intMinPoly, d = self._make_monic_integral(self._polynomial) + curveIdeal = tmpAuxRing.ideal(intMinPoly) + + singular.lib('normal.lib') #loading genus method in Singular + return int(curveIdeal._singular_().genus()) + + else: + raise NotImplementedError("computation of genus over non-prime " + "constant fields not implemented yet") + + def _simple_model(self, name='v'): + r""" + Return a finite extension `N/K(x)` isomorphic to the tower of + extensions `M/L/K(x)` with `K` perfect. + + Helper method for :meth:`simple_model`. + + INPUT: + + - ``name`` -- a string, the name of the generator of `N` + + ALGORITHM: + + Since `K` is perfect, the extension `M/K(x)` is simple, i.e., generated + by a single element [BM1940]_. Therefore, there are only finitely many + intermediate fields (Exercise 3.6.7 in [Bo2009]_). + Let `a` be a generator of `M/L` and let `b` be a generator of `L/K(x)`. + For some `i` the field `N_i=K(x)(a+x^ib)` is isomorphic to `M` and so + it is enough to test for all terms of the form `a+x^ib` whether they + generate a field of the right degree. + Indeed, suppose for contradiction that for all `i` we had `N_i\neq M`. + Then `N_i=N_j` for some `i,j`. Thus `(a+x^ib)-(a+x^jb)=b(x^i-x^j)\in + N_j` and so `b\in N_j`. Similarly, + `a+x^ib-x^{i-j}(a+x^jb)=a(1+x^{i-j})\in N_j` and so `a\in N_j`. + Therefore, `N_j=M`. + + TESTS:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^2 - y) + sage: M._simple_model() + (Function field in v defined by v^4 - x, + Function Field morphism: + From: Function field in v defined by v^4 - x + To: Function field in z defined by z^2 - y + Defn: v |--> z, + Function Field morphism: + From: Function field in z defined by z^2 - y + To: Function field in v defined by v^4 - x + Defn: z |--> v + y |--> v^2) + + Check that this also works for inseparable extensions:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^2 - y) + sage: M._simple_model() + (Function field in v defined by v^4 + x, + Function Field morphism: + From: Function field in v defined by v^4 + x + To: Function field in z defined by z^2 + y + Defn: v |--> z, + Function Field morphism: + From: Function field in z defined by z^2 + y + To: Function field in v defined by v^4 + x + Defn: z |--> v + y |--> v^2) + + An example where the generator of the last extension does not generate + the extension of the rational function field:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^3 - 1) + sage: M._simple_model() + (Function field in v defined by v^6 + x*v^4 + x^2*v^2 + x^3 + 1, + Function Field morphism: + From: Function field in v defined by v^6 + x*v^4 + x^2*v^2 + x^3 + 1 + To: Function field in z defined by z^3 + 1 + Defn: v |--> z + y, + Function Field morphism: + From: Function field in z defined by z^3 + 1 + To: Function field in v defined by v^6 + x*v^4 + x^2*v^2 + x^3 + 1 + Defn: z |--> v^4 + x^2 + y |--> v^4 + v + x^2) + + """ + M = self + L = M.base_field() + K = L.base_field() + + assert(isinstance(K, RationalFunctionField)) + assert(K is not L) + assert(L is not M) + + if not K.constant_field().is_perfect(): + raise NotImplementedError("simple_model() only implemented over perfect constant fields") + + x = K.gen() + b = L.gen() + a = M.gen() + + # using a+x^i*b tends to lead to huge powers of x in the minimal + # polynomial of the resulting field; it is better to try terms of + # the form a+i*b first (but in characteristic p>0 there are only + # finitely many of these) + # We systematically try elements of the form a+b*factor*x^exponent + factor = self.constant_base_field().zero() + exponent = 0 + while True: + v = M(a+b*factor*x**exponent) + minpoly = v.matrix(K).minpoly() + if minpoly.degree() == M.degree()*L.degree(): + break + factor += 1 + if factor == 0: + factor = self.constant_base_field().one() + exponent += 1 + + N = K.extension(minpoly, names=(name,)) + + # the morphism N -> M, v |-> v + N_to_M = N.hom(v) + + # the morphism M -> N, b |-> M_b, a |-> M_a + V, V_to_M, M_to_V = M.free_module(K) + V, V_to_N, N_to_V = N.free_module(K) + from sage.matrix.matrix_space import MatrixSpace + MS = MatrixSpace(V.base_field(), V.dimension()) + # the power basis of v over K + B = [M_to_V(v**i) for i in range(V.dimension())] + B = MS(B) + M_b = V_to_N(B.solve_left(M_to_V(b))) + M_a = V_to_N(B.solve_left(M_to_V(a))) + M_to_N = M.hom([M_a,M_b]) + + return N, N_to_M, M_to_N + + @cached_method + def simple_model(self, name=None): + """ + Return a function field isomorphic to this field which is a simple + extension of a rational function field. + + INPUT: + + - ``name`` -- a string (default: ``None``), the name of generator of + the simple extension. If ``None``, then the name of the generator + will be the same as the name of the generator of this function field. + + OUTPUT: + + A triple ``(F,f,t)`` where ``F`` is a field isomorphic to this field, + ``f`` is an isomorphism from ``F`` to this function field and ``t`` is + the inverse of ``f``. + + EXAMPLES: + + A tower of four function fields:: + + sage: K.<x> = FunctionField(QQ); R.<z> = K[] + sage: L.<z> = K.extension(z^2 - x); R.<u> = L[] + sage: M.<u> = L.extension(u^2 - z); R.<v> = M[] + sage: N.<v> = M.extension(v^2 - u) + + The fields N and M as simple extensions of K:: + + sage: N.simple_model() + (Function field in v defined by v^8 - x, + Function Field morphism: + From: Function field in v defined by v^8 - x + To: Function field in v defined by v^2 - u + Defn: v |--> v, + Function Field morphism: + From: Function field in v defined by v^2 - u + To: Function field in v defined by v^8 - x + Defn: v |--> v + u |--> v^2 + z |--> v^4 + x |--> x) + sage: M.simple_model() + (Function field in u defined by u^4 - x, + Function Field morphism: + From: Function field in u defined by u^4 - x + To: Function field in u defined by u^2 - z + Defn: u |--> u, + Function Field morphism: + From: Function field in u defined by u^2 - z + To: Function field in u defined by u^4 - x + Defn: u |--> u + z |--> u^2 + x |--> x) + + An optional parameter ``name`` can be used to set the name of the + generator of the simple extension:: + + sage: M.simple_model(name='t') + (Function field in t defined by t^4 - x, Function Field morphism: + From: Function field in t defined by t^4 - x + To: Function field in u defined by u^2 - z + Defn: t |--> u, Function Field morphism: + From: Function field in u defined by u^2 - z + To: Function field in t defined by t^4 - x + Defn: u |--> t + z |--> t^2 + x |--> x) + + An example with higher degrees:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3)); R.<y> = K[] + sage: L.<y> = K.extension(y^5 - x); R.<z> = L[] + sage: M.<z> = L.extension(z^3 - x) + sage: M.simple_model() + (Function field in z defined by z^15 + x*z^12 + x^2*z^9 + 2*x^3*z^6 + 2*x^4*z^3 + 2*x^5 + 2*x^3, + Function Field morphism: + From: Function field in z defined by z^15 + x*z^12 + x^2*z^9 + 2*x^3*z^6 + 2*x^4*z^3 + 2*x^5 + 2*x^3 + To: Function field in z defined by z^3 + 2*x + Defn: z |--> z + y, + Function Field morphism: + From: Function field in z defined by z^3 + 2*x + To: Function field in z defined by z^15 + x*z^12 + x^2*z^9 + 2*x^3*z^6 + 2*x^4*z^3 + 2*x^5 + 2*x^3 + Defn: z |--> 2/x*z^6 + 2*z^3 + z + 2*x + y |--> 1/x*z^6 + z^3 + x + x |--> x) + + This also works for inseparable extensions:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x); R.<z> = L[] + sage: M.<z> = L.extension(z^2 - y) + sage: M.simple_model() + (Function field in z defined by z^4 + x, Function Field morphism: + From: Function field in z defined by z^4 + x + To: Function field in z defined by z^2 + y + Defn: z |--> z, Function Field morphism: + From: Function field in z defined by z^2 + y + To: Function field in z defined by z^4 + x + Defn: z |--> z + y |--> z^2 + x |--> x) + """ + if name is None: + name = self.variable_name() + + if isinstance(self.base_field(), RationalFunctionField): + # the extension is simple already + if name == self.variable_name(): + id = Hom(self,self).identity() + return self, id, id + else: + ret = self.base_field().extension(self.polynomial(), names=(name,)) + f = ret.hom(self.gen()) + t = self.hom(ret.gen()) + return ret, f, t + else: + # recursively collapse the tower of fields + base = self.base_field() + base_, from_base_, to_base_ = base.simple_model() + self_ = base_.extension(self.polynomial().map_coefficients(to_base_), names=(name,)) + gens_in_base_ = [to_base_(k.gen()) + for k in base._intermediate_fields(base.rational_function_field())] + to_self_ = self.hom([self_.gen()]+gens_in_base_) + from_self_ = self_.hom([self.gen(),from_base_(base_.gen())]) + + # now collapse self_/base_/K(x) + ret, ret_to_self_, self__to_ret = self_._simple_model(name) + ret_to_self = ret.hom(from_self_(ret_to_self_(ret.gen()))) + gens_in_ret = [self__to_ret(to_self_(k.gen())) + for k in self._intermediate_fields(self.rational_function_field())] + self_to_ret = self.hom(gens_in_ret) + return ret, ret_to_self, self_to_ret + + @cached_method + def primitive_element(self): + r""" + Return a primitive element over the underlying rational function field. + + If this is a finite extension of a rational function field `K(x)` with + `K` perfect, then this is a simple extension of `K(x)`, i.e., there is + a primitive element `y` which generates this field over `K(x)`. This + method returns such an element `y`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^2 - y) + sage: R.<z> = L[] + sage: N.<u> = L.extension(z^2 - x - 1) + sage: N.primitive_element() + u + y + sage: M.primitive_element() + z + sage: L.primitive_element() + y + + This also works for inseparable extensions:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: R.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x) + sage: R.<Z> = L[] + sage: M.<z> = L.extension(Z^2 - y) + sage: M.primitive_element() + z + """ + N, f, t = self.simple_model() + return f(N.gen()) + + @cached_method + def separable_model(self, names=None): + r""" + Return a function field isomorphic to this field which is a separable + extension of a rational function field. + + INPUT: + + - ``names`` -- a tuple of two strings or ``None`` (default: ``None``); + the second entry will be used as the variable name of the rational + function field, the first entry will be used as the variable name of + its separable extension. If ``None``, then the variable names will be + chosen automatically. + + OUTPUT: + + A triple ``(F,f,t)`` where ``F`` is a function field, ``f`` is an + isomorphism from ``F`` to this function field, and ``t`` is the inverse + of ``f``. + + ALGORITHM: + + Suppose that the constant base field is perfect. If this is a monic + integral inseparable extension of a rational function field, then the + defining polynomial is separable if we swap the variables (Proposition + 4.8 in Chapter VIII of [Lan2002]_.) + The algorithm reduces to this case with :meth:`monic_integral_model`. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3) + sage: L.separable_model(('t','w')) + (Function field in t defined by t^3 + w^2, + Function Field morphism: + From: Function field in t defined by t^3 + w^2 + To: Function field in y defined by y^2 + x^3 + Defn: t |--> x + w |--> y, + Function Field morphism: + From: Function field in y defined by y^2 + x^3 + To: Function field in t defined by t^3 + w^2 + Defn: y |--> w + x |--> t) + + This also works for non-integral polynomials:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2/x - x^2) + sage: L.separable_model() + (Function field in y_ defined by y_^3 + x_^2, + Function Field morphism: + From: Function field in y_ defined by y_^3 + x_^2 + To: Function field in y defined by 1/x*y^2 + x^2 + Defn: y_ |--> x + x_ |--> y, + Function Field morphism: + From: Function field in y defined by 1/x*y^2 + x^2 + To: Function field in y_ defined by y_^3 + x_^2 + Defn: y |--> x_ + x |--> y_) + + If the base field is not perfect this is only implemented in trivial cases:: + + sage: # needs sage.rings.finite_rings + sage: k.<t> = FunctionField(GF(2)) + sage: k.is_perfect() + False + sage: K.<x> = FunctionField(k) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^3 - t) + sage: L.separable_model() + (Function field in y defined by y^3 + t, + Function Field endomorphism of Function field in y defined by y^3 + t + Defn: y |--> y + x |--> x, + Function Field endomorphism of Function field in y defined by y^3 + t + Defn: y |--> y + x |--> x) + + Some other cases for which a separable model could be constructed are + not supported yet:: + + sage: R.<y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(y^2 - t) # needs sage.rings.finite_rings + sage: L.separable_model() # needs sage.rings.finite_rings + Traceback (most recent call last): + ... + NotImplementedError: constructing a separable model is only implemented for function fields over a perfect constant base field + + TESTS: + + Check that this also works in characteristic zero:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3) + sage: L.separable_model() + (Function field in y defined by y^2 - x^3, + Function Field endomorphism of Function field in y defined by y^2 - x^3 + Defn: y |--> y + x |--> x, + Function Field endomorphism of Function field in y defined by y^2 - x^3 + Defn: y |--> y + x |--> x) + + Check that this works for towers of inseparable extensions:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^2 - y) + sage: M.separable_model() + (Function field in z_ defined by z_ + x_^4, + Function Field morphism: + From: Function field in z_ defined by z_ + x_^4 + To: Function field in z defined by z^2 + y + Defn: z_ |--> x + x_ |--> z, + Function Field morphism: + From: Function field in z defined by z^2 + y + To: Function field in z_ defined by z_ + x_^4 + Defn: z |--> x_ + y |--> x_^2 + x |--> x_^4) + + Check that this also works if only the first extension is inseparable:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^3 - y) + sage: M.separable_model() + (Function field in z_ defined by z_ + x_^6, Function Field morphism: + From: Function field in z_ defined by z_ + x_^6 + To: Function field in z defined by z^3 + y + Defn: z_ |--> x + x_ |--> z, Function Field morphism: + From: Function field in z defined by z^3 + y + To: Function field in z_ defined by z_ + x_^6 + Defn: z |--> x_ + y |--> x_^3 + x |--> x_^6) + + """ + if names is None: + pass + elif not isinstance(names, tuple): + raise TypeError("names must be a tuple consisting of two strings") + elif len(names) != 2: + raise ValueError("must provide exactly two variable names") + + if self.base_ring() is not self.rational_function_field(): + L, from_L, to_L = self.simple_model() + K, from_K, to_K = L.separable_model(names=names) + f = K.hom([from_L(from_K(K.gen())), from_L(from_K(K.base_field().gen()))]) + t = self.hom([to_K(to_L(k.gen())) for k in self._intermediate_fields(self.rational_function_field())]) + return K, f, t + + if self.polynomial().gcd(self.polynomial().derivative()).is_one(): + # the model is already separable + if names is None: + names = self.variable_name(), self.base_field().variable_name() + return self.change_variable_name(names) + + if not self.constant_base_field().is_perfect(): + raise NotImplementedError("constructing a separable model is only implemented for function fields over a perfect constant base field") + + if names is None: + names = (self.variable_name()+"_", self.rational_function_field().variable_name()+"_") + + L, from_L, to_L = self.monic_integral_model() + + if L.polynomial().gcd(L.polynomial().derivative()).is_one(): + # L is separable + ret, ret_to_L, L_to_ret = L.change_variable_name(names) + f = ret.hom([from_L(ret_to_L(ret.gen())), from_L(ret_to_L(ret.base_field().gen()))]) + t = self.hom([L_to_ret(to_L(self.gen())), L_to_ret(to_L(self.base_field().gen()))]) + return ret, f, t + else: + # otherwise, the polynomial of L must be separable in the other variable + from .constructor import FunctionField + K = FunctionField(self.constant_base_field(), names=(names[1],)) + # construct a field isomorphic to L on top of K + + # turn the minpoly of K into a bivariate polynomial + if names[0] == names[1]: + raise ValueError("names of generators must be distinct") + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self.constant_base_field(), names=names) + S = R.remove_var(names[1]) + f = R( L.polynomial().change_variable_name(names[1]).map_coefficients( + lambda c:c.numerator().change_variable_name(names[0]), S)) + f = f.polynomial(R.gen(0)).change_ring(K) + f /= f.leading_coefficient() + # f must be separable in the other variable (otherwise it would factor) + assert f.gcd(f.derivative()).is_one() + + ret = K.extension(f, names=(names[0],)) + # isomorphisms between L and ret are given by swapping generators + ret_to_L = ret.hom( [L(L.base_field().gen()), L.gen()] ) + L_to_ret = L.hom( [ret(K.gen()), ret.gen()] ) + # compose with from_L and to_L to get the desired isomorphisms between self and ret + f = ret.hom( [from_L(ret_to_L(ret.gen())), from_L(ret_to_L(ret.base_field().gen()))] ) + t = self.hom( [L_to_ret(to_L(self.gen())), L_to_ret(to_L(self.base_field().gen()))] ) + return ret, f, t + + def change_variable_name(self, name): + r""" + Return a field isomorphic to this field with variable(s) ``name``. + + INPUT: + + - ``name`` -- a string or a tuple consisting of a strings, the names of + the new variables starting with a generator of this field and going + down to the rational function field. + + OUTPUT: + + A triple ``F,f,t`` where ``F`` is a function field, ``f`` is an + isomorphism from ``F`` to this field, and ``t`` is the inverse of + ``f``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^2 - y) + + sage: M.change_variable_name('zz') + (Function field in zz defined by zz^2 - y, + Function Field morphism: + From: Function field in zz defined by zz^2 - y + To: Function field in z defined by z^2 - y + Defn: zz |--> z + y |--> y + x |--> x, + Function Field morphism: + From: Function field in z defined by z^2 - y + To: Function field in zz defined by zz^2 - y + Defn: z |--> zz + y |--> y + x |--> x) + sage: M.change_variable_name(('zz','yy')) + (Function field in zz defined by zz^2 - yy, Function Field morphism: + From: Function field in zz defined by zz^2 - yy + To: Function field in z defined by z^2 - y + Defn: zz |--> z + yy |--> y + x |--> x, Function Field morphism: + From: Function field in z defined by z^2 - y + To: Function field in zz defined by zz^2 - yy + Defn: z |--> zz + y |--> yy + x |--> x) + sage: M.change_variable_name(('zz','yy','xx')) + (Function field in zz defined by zz^2 - yy, + Function Field morphism: + From: Function field in zz defined by zz^2 - yy + To: Function field in z defined by z^2 - y + Defn: zz |--> z + yy |--> y + xx |--> x, + Function Field morphism: + From: Function field in z defined by z^2 - y + To: Function field in zz defined by zz^2 - yy + Defn: z |--> zz + y |--> yy + x |--> xx) + + """ + if not isinstance(name, tuple): + name = (name,) + if len(name) == 0: + raise ValueError("name must contain at least one string") + elif len(name) == 1: + base = self.base_field() + from_base = to_base = Hom(base,base).identity() + else: + base, from_base, to_base = self.base_field().change_variable_name(name[1:]) + + ret = base.extension(self.polynomial().map_coefficients(to_base), names=(name[0],)) + f = ret.hom( [k.gen() for k in self._intermediate_fields(self.rational_function_field())] ) + t = self.hom( [k.gen() for k in ret._intermediate_fields(ret.rational_function_field())] ) + return ret, f, t + + +class FunctionField_simple(FunctionField_polymod): + """ + Function fields defined by irreducible and separable polynomials + over rational function fields. + """ + @cached_method + def _inversion_isomorphism(self): + r""" + Return an inverted function field isomorphic to ``self`` and isomorphisms + between them. + + An *inverted* function field `M` is an extension of the base rational + function field `k(x)` of ``self``, and isomorphic to ``self`` by an + isomorphism sending `x` to `1/x`, which we call an *inversion* + isomorphism. Also the defining polynomial of the function field `M` is + required to be monic and integral. + + The inversion isomorphism is for internal use to reposition infinite + places to finite places. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] # needs sage.rings.finite_rings + sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) # needs sage.rings.finite_rings + sage: F._inversion_isomorphism() # needs sage.rings.finite_rings + (Function field in s defined by s^3 + x^16 + x^14 + x^12, Composite map: + From: Function field in s defined by s^3 + x^16 + x^14 + x^12 + To: Function field in y defined by y^3 + x^6 + x^4 + x^2 + Defn: Function Field morphism: + From: Function field in s defined by s^3 + x^16 + x^14 + x^12 + To: Function field in T defined by T^3 + (x^4 + x^2 + 1)/x^6 + Defn: s |--> x^6*T + x |--> x + then + Function Field morphism: + From: Function field in T defined by T^3 + (x^4 + x^2 + 1)/x^6 + To: Function field in y defined by y^3 + x^6 + x^4 + x^2 + Defn: T |--> y + x |--> 1/x, Composite map: + From: Function field in y defined by y^3 + x^6 + x^4 + x^2 + To: Function field in s defined by s^3 + x^16 + x^14 + x^12 + Defn: Function Field morphism: + From: Function field in y defined by y^3 + x^6 + x^4 + x^2 + To: Function field in T defined by T^3 + (x^4 + x^2 + 1)/x^6 + Defn: y |--> T + x |--> 1/x + then + Function Field morphism: + From: Function field in T defined by T^3 + (x^4 + x^2 + 1)/x^6 + To: Function field in s defined by s^3 + x^16 + x^14 + x^12 + Defn: T |--> 1/x^6*s + x |--> x) + """ + K = self.base_field() + R = PolynomialRing(K,'T') + x = K.gen() + xinv = 1/x + + h = K.hom(xinv) + F_poly = R([h(c) for c in self.polynomial().list()]) + F = K.extension(F_poly) + + self2F = self.hom([F.gen(),xinv]) + F2self = F.hom([self.gen(),xinv]) + + M, M2F, F2M = F.monic_integral_model('s') + + return M, F2self*M2F, F2M*self2F + + def places_above(self, p): + """ + Return places lying above ``p``. + + INPUT: + + - ``p`` -- place of the base rational function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) # needs sage.rings.finite_rings + sage: all(q.place_below() == p # needs sage.rings.finite_rings + ....: for p in K.places() for q in F.places_above(p)) + True + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) + sage: O = K.maximal_order() + sage: pls = [O.ideal(x - c).place() for c in [-2, -1, 0, 1, 2]] + sage: all(q.place_below() == p + ....: for p in pls for q in F.places_above(p)) + True + + sage: # needs sage.rings.number_field + sage: K.<x> = FunctionField(QQbar); _.<Y> = K[] + sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) + sage: O = K.maximal_order() + sage: pls = [O.ideal(x - QQbar(sqrt(c))).place() + ....: for c in [-2, -1, 0, 1, 2]] + sage: all(q.place_below() == p # long time (4s) + ....: for p in pls for q in F.places_above(p)) + True + """ + R = self.base_field() + + if p not in R.place_set(): + raise TypeError("not a place of the base rational function field") + + if p.is_infinite_place(): + dec = self.maximal_order_infinite().decomposition() + else: + dec = self.maximal_order().decomposition(p.prime_ideal()) + + return tuple([q.place() for q, deg, exp in dec]) + + def constant_field(self): + """ + Return the algebraic closure of the base constant field in the function + field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(3)); _.<y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) # needs sage.rings.finite_rings + sage: L.constant_field() # needs sage.rings.finite_rings + Finite Field of size 3 + """ + return self.exact_constant_field()[0] + + def exact_constant_field(self, name='t'): + """ + Return the exact constant field and its embedding into the function field. + + INPUT: + + - ``name`` -- name (default: `t`) of the generator of the exact constant field + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3)); _.<Y> = K[] + sage: f = Y^2 - x*Y + x^2 + 1 # irreducible but not absolutely irreducible + sage: L.<y> = K.extension(f) + sage: L.genus() + 0 + sage: L.exact_constant_field() + (Finite Field in t of size 3^2, Ring morphism: + From: Finite Field in t of size 3^2 + To: Function field in y defined by y^2 + 2*x*y + x^2 + 1 + Defn: t |--> y + x) + sage: (y+x).divisor() + 0 + """ + # A basis of the full constant field is obtained from + # computing a Riemann-Roch basis of zero divisor. + basis = self.divisor_group().zero().basis_function_space() + + dim = len(basis) + + for e in basis: + _min_poly = e.minimal_polynomial(name) + if _min_poly.degree() == dim: + break + k = self.constant_base_field() + R = k[name] + min_poly = R([k(c) for c in _min_poly.list()]) + + k_ext = k.extension(min_poly, name) + + if k_ext.is_prime_field(): + # The cover of the quotient ring k_ext is the integer ring + # whose generator is 1. This is different from the generator + # of k_ext. + embedding = k_ext.hom([self(1)], self) + else: + embedding = k_ext.hom([e], self) + + return k_ext, embedding + + def genus(self): + """ + Return the genus of the function field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF(16) + sage: K.<x> = FunctionField(F); K + Rational function field in x over Finite Field in a of size 2^4 + sage: R.<t> = PolynomialRing(K) + sage: L.<y> = K.extension(t^4 + t - x^5) + sage: L.genus() + 6 + + The genus is computed by the Hurwitz genus formula. + """ + k, _ = self.exact_constant_field() + different_degree = self.different().degree() # must be even + return Integer(different_degree // 2 - self.degree() / k.degree()) + 1 + + def residue_field(self, place, name=None): + """ + Return the residue field associated with the place along with the maps + from and to the residue field. + + INPUT: + + - ``place`` -- place of the function field + + - ``name`` -- string; name of the generator of the residue field + + The domain of the map to the residue field is the discrete valuation + ring associated with the place. + + The discrete valuation ring is defined as the ring of all elements of + the function field with nonnegative valuation at the place. The maximal + ideal is the set of elements of positive valuation. The residue field + is then the quotient of the discrete valuation ring by its maximal + ideal. + + If an element not in the valuation ring is applied to the map, an + exception ``TypeError`` is raised. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: R, fr_R, to_R = L.residue_field(p) + sage: R + Finite Field of size 2 + sage: f = 1 + y + sage: f.valuation(p) + -1 + sage: to_R(f) + Traceback (most recent call last): + ... + TypeError: ... + sage: (1+1/f).valuation(p) + 0 + sage: to_R(1 + 1/f) + 1 + sage: [fr_R(e) for e in R] + [0, 1] + """ + return place.residue_field(name=name) + + +class FunctionField_char_zero(FunctionField_simple): + """ + Function fields of characteristic zero. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) + sage: L + Function field in y defined by y^3 + (-x^3 + 1)/(x^3 - 2) + sage: L.characteristic() + 0 + """ + @cached_method + def higher_derivation(self): + """ + Return the higher derivation (also called the Hasse-Schmidt derivation) + for the function field. + + The higher derivation of the function field is uniquely determined with + respect to the separating element `x` of the base rational function + field `k(x)`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) + sage: L.higher_derivation() # needs sage.modules + Higher derivation map: + From: Function field in y defined by y^3 + (-x^3 + 1)/(x^3 - 2) + To: Function field in y defined by y^3 + (-x^3 + 1)/(x^3 - 2) + """ + from .derivations_polymod import FunctionFieldHigherDerivation_char_zero + return FunctionFieldHigherDerivation_char_zero(self) + + +class FunctionField_global(FunctionField_simple): + """ + Global function fields. + + INPUT: + + - ``polynomial`` -- monic irreducible and separable polynomial + + - ``names`` -- name of the generator of the function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) # needs sage.rings.finite_rings + sage: L # needs sage.rings.finite_rings + Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) + + The defining equation needs not be monic:: + + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension((1 - x)*Y^7 - x^3) # needs sage.rings.finite_rings + sage: L.gaps() # long time (6s) # needs sage.rings.finite_rings + [1, 2, 3] + + or may define a trivial extension:: + + sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y-1) # needs sage.rings.finite_rings + sage: L.genus() # needs sage.rings.finite_rings + 0 + """ + _differentials_space = LazyImport('sage.rings.function_field.differential', 'DifferentialsSpace_global') + + def __init__(self, polynomial, names): + """ + Initialize. + + TESTS:: + + sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) # needs sage.rings.finite_rings + sage: TestSuite(L).run() # long time (7s) # needs sage.rings.finite_rings + """ + FunctionField_polymod.__init__(self, polynomial, names) + + def maximal_order(self): + """ + Return the maximal order of the function field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^4 + x^12*t^2 + x^18*t + x^21 + x^18) + sage: O = F.maximal_order() + sage: O.basis() + (1, 1/x^4*y, 1/x^11*y^2 + 1/x^2, 1/x^15*y^3 + 1/x^6*y) + """ + from .order_polymod import FunctionFieldMaximalOrder_global + return FunctionFieldMaximalOrder_global(self) + + @cached_method + def higher_derivation(self): + """ + Return the higher derivation (also called the Hasse-Schmidt derivation) + for the function field. + + The higher derivation of the function field is uniquely determined with + respect to the separating element `x` of the base rational function + field `k(x)`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(5)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) # needs sage.rings.finite_rings + sage: L.higher_derivation() # needs sage.modules sage.rings.finite_rings + Higher derivation map: + From: Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) + To: Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) + """ + from .derivations_polymod import FunctionFieldHigherDerivation_global + return FunctionFieldHigherDerivation_global(self) + + def get_place(self, degree): + """ + Return a place of ``degree``. + + INPUT: + + - ``degree`` -- a positive integer + + OUTPUT: a place of ``degree`` if any exists; otherwise ``None`` + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF(2) + sage: K.<x> = FunctionField(F) + sage: R.<Y> = PolynomialRing(K) + sage: L.<y> = K.extension(Y^4 + Y - x^5) + sage: L.get_place(1) + Place (x, y) + sage: L.get_place(2) + Place (x, y^2 + y + 1) + sage: L.get_place(3) + Place (x^3 + x^2 + 1, y + x^2 + x) + sage: L.get_place(4) + Place (x + 1, x^5 + 1) + sage: L.get_place(5) + Place (x^5 + x^3 + x^2 + x + 1, y + x^4 + 1) + sage: L.get_place(6) + Place (x^3 + x^2 + 1, y^2 + y + x^2) + sage: L.get_place(7) + Place (x^7 + x + 1, y + x^6 + x^5 + x^4 + x^3 + x) + sage: L.get_place(8) + + """ + for p in self._places_finite(degree): + return p + + for p in self._places_infinite(degree): + return p + + return None + + def places(self, degree=1): + """ + Return a list of the places with ``degree``. + + INPUT: + + - ``degree`` -- positive integer (default: `1`) + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF(2) + sage: K.<x> = FunctionField(F) + sage: R.<t> = PolynomialRing(K) + sage: L.<y> = K.extension(t^4 + t - x^5) + sage: L.places(1) + [Place (1/x, 1/x^4*y^3), Place (x, y), Place (x, y + 1)] + """ + return self.places_infinite(degree) + self.places_finite(degree) + + def places_finite(self, degree=1): + """ + Return a list of the finite places with ``degree``. + + INPUT: + + - ``degree`` -- positive integer (default: `1`) + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF(2) + sage: K.<x> = FunctionField(F) + sage: R.<t> = PolynomialRing(K) + sage: L.<y> = K.extension(t^4 + t - x^5) + sage: L.places_finite(1) + [Place (x, y), Place (x, y + 1)] + """ + return list(self._places_finite(degree)) + + def _places_finite(self, degree): + """ + Return a generator of finite places with ``degree``. + + INPUT: + + - ``degree`` -- positive integer + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF(2) + sage: K.<x> = FunctionField(F) + sage: R.<t> = PolynomialRing(K) + sage: L.<y> = K.extension(t^4 + t - x^5) + sage: L._places_finite(1) + <generator object ...> + """ + O = self.maximal_order() + K = self.base_field() + + degree = Integer(degree) + + for d in degree.divisors(): + for p in K._places_finite(degree=d): + for prime,_,_ in O.decomposition(p.prime_ideal()): + place = prime.place() + if place.degree() == degree: + yield place + + def places_infinite(self, degree=1): + """ + Return a list of the infinite places with ``degree``. + + INPUT: + + - ``degree`` -- positive integer (default: `1`) + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF(2) + sage: K.<x> = FunctionField(F) + sage: R.<t> = PolynomialRing(K) + sage: L.<y> = K.extension(t^4 + t - x^5) + sage: L.places_infinite(1) + [Place (1/x, 1/x^4*y^3)] + """ + return list(self._places_infinite(degree)) + + def _places_infinite(self, degree): + """ + Return a generator of *infinite* places with ``degree``. + + INPUT: + + - ``degree`` -- positive integer + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF(2) + sage: K.<x> = FunctionField(F) + sage: R.<t> = PolynomialRing(K) + sage: L.<y> = K.extension(t^4 + t - x^5) + sage: L._places_infinite(1) + <generator object ...> + """ + Oinf = self.maximal_order_infinite() + for prime,_,_ in Oinf.decomposition(): + place = prime.place() + if place.degree() == degree: + yield place + + def gaps(self): + """ + Return the gaps of the function field. + + These are the gaps at the ordinary places, that is, places which are + not Weierstrass places. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 + x^3 * Y + x) # needs sage.rings.finite_rings + sage: L.gaps() # needs sage.modules sage.rings.finite_rings + [1, 2, 3] + """ + return self._weierstrass_places()[1] + + def weierstrass_places(self): + """ + Return all Weierstrass places of the function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 + x^3 * Y + x) # needs sage.rings.finite_rings + sage: L.weierstrass_places() # needs sage.modules sage.rings.finite_rings + [Place (1/x, 1/x^3*y^2 + 1/x), + Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1), + Place (x, y), + Place (x + 1, (x^3 + 1)*y + x + 1), + Place (x^3 + x + 1, y + 1), + Place (x^3 + x + 1, y + x^2), + Place (x^3 + x + 1, y + x^2 + 1), + Place (x^3 + x^2 + 1, y + x), + Place (x^3 + x^2 + 1, y + x^2 + 1), + Place (x^3 + x^2 + 1, y + x^2 + x + 1)] + """ + return self._weierstrass_places()[0].support() + + @cached_method + def _weierstrass_places(self): + """ + Return the Weierstrass places together with the gap sequence for + ordinary places. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 + x^3 * Y + x) # needs sage.rings.finite_rings + sage: len(L.weierstrass_places()) # indirect doctest # needs sage.modules sage.rings.finite_rings + 10 + + This method implements Algorithm 30 in [Hes2002b]_. + """ + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + + W = self(self.base_field().gen()).differential().divisor() + basis = W._basis() + + if not basis: + return [], [] + d = len(basis) + + der = self.higher_derivation() + M = matrix([basis]) + e = 1 + gaps = [1] + while M.nrows() < d: + row = vector([der._derive(basis[i], e) for i in range(d)]) + if row not in M.row_space(): + M = matrix(M.rows() + [row]) + gaps.append(e + 1) + e += 1 + + # This is faster than M.determinant(). Note that Mx + # is a matrix over univariate polynomial ring. + Mx = matrix(M.nrows(), [c._x for c in M.list()]) + detM = self(Mx.determinant() % self._polynomial) + + R = detM.divisor() + sum(gaps)*W # ramification divisor + + return R, gaps + + @cached_method + def L_polynomial(self, name='t'): + """ + Return the L-polynomial of the function field. + + INPUT: + + - ``name`` -- (default: ``t``) name of the variable of the polynomial + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: F.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.finite_rings + sage: F.L_polynomial() # needs sage.rings.finite_rings + 2*t^2 + t + 1 + """ + from sage.rings.integer_ring import ZZ + q = self.constant_field().order() + g = self.genus() + + B = [len(self.places(i+1)) for i in range(g)] + N = [sum(d * B[d-1] for d in ZZ(i+1).divisors()) for i in range(g)] + S = [N[i] - q**(i+1) - 1 for i in range(g)] + + a = [1] + for i in range(1, g+1): + a.append(sum(S[j] * a[i-j-1] for j in range(i)) / i) + for j in range(1, g+1): + a.append(q**j * a[g-j]) + + return ZZ[name](a) + + def number_of_rational_places(self, r=1): + """ + Return the number of rational places of the function field whose + constant field extended by degree ``r``. + + INPUT: + + - ``r`` -- positive integer (default: `1`) + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: F.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: F.number_of_rational_places() + 4 + sage: [F.number_of_rational_places(r) for r in [1..10]] + [4, 8, 4, 16, 44, 56, 116, 288, 508, 968] + """ + from sage.rings.integer_ring import IntegerRing + + q = self.constant_field().order() + L = self.L_polynomial() + Lp = L.derivative() + + R = IntegerRing()[[L.parent().gen()]] # power series ring + + f = R(Lp / L, prec=r) + n = f[r-1] + q**r + 1 + + return n + + +@handle_AA_and_QQbar +def _singular_normal(ideal): + r""" + Compute the normalization of the affine algebra defined by ``ideal`` using + Singular. + + The affine algebra is the quotient algebra of a multivariate polynomial + ring `R` by the ideal. The normalization is by definition the integral + closure of the algebra in its total ring of fractions. + + INPUT: + + - ``ideal`` -- a radical ideal in a multivariate polynomial ring + + OUTPUT: + + a list of lists, one list for each ideal in the equidimensional + decomposition of the ``ideal``, each list giving a set of generators of the + normalization of each ideal as an R-module by dividing all elements of the + list by the final element. Thus the list ``[x, y]`` means that `\{x/y, 1\}` + is the set of generators of the normalization of `R/(x,y)`. + + ALGORITHM: + + Singular's implementation of the normalization algorithm described in G.-M. + Greuel, S. Laplagne, F. Seelisch: Normalization of Rings (2009). + + EXAMPLES:: + + sage: from sage.rings.function_field.function_field_polymod import _singular_normal + sage: R.<x,y> = QQ[] + + sage: f = (x^2 - y^3) * x + sage: _singular_normal(ideal(f)) + [[x, y], [1]] + + sage: f = y^2 - x + sage: _singular_normal(ideal(f)) + [[1]] + """ + from sage.libs.singular.function import singular_function, lib + lib('normal.lib') + normal = singular_function('normal') + execute = singular_function('execute') + + try: + get_printlevel = singular_function('get_printlevel') + except NameError: + execute('proc get_printlevel {return (printlevel);}') + get_printlevel = singular_function('get_printlevel') + + # It's fairly verbose unless printlevel is -1. + saved_printlevel = get_printlevel() + execute('printlevel=-1') + nor = normal(ideal) + execute('printlevel={}'.format(saved_printlevel)) + + return nor[1] + + +class FunctionField_integral(FunctionField_simple): + """ + Integral function fields. + + A function field is integral if it is defined by an irreducible separable + polynomial, which is integral over the maximal order of the base rational + function field. + """ + def _maximal_order_basis(self): + """ + Return a basis of the maximal order of the function field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^4 + x^12*t^2 + x^18*t + x^21 + x^18) + sage: F._maximal_order_basis() + [1, 1/x^4*y, 1/x^11*y^2 + 1/x^2, 1/x^15*y^3 + 1/x^6*y] + + The basis of the maximal order *always* starts with 1. This is assumed + in some algorithms. + """ + from sage.matrix.constructor import matrix + from .hermite_form_polynomial import reversed_hermite_form + + k = self.constant_base_field() + K = self.base_field() # rational function field + n = self.degree() + + # Construct the defining polynomial of the function field as a + # two-variate polynomial g in the ring k[y,x] where k is the constant + # base field. + S,(y,x) = PolynomialRing(k, names='y,x', order='lex').objgens() + v = self.polynomial().list() + g = sum([v[i].numerator().subs(x) * y**i for i in range(len(v))]) + + if self.is_global(): + from sage.libs.singular.function import singular_function, lib + from sage.env import SAGE_EXTCODE + lib(SAGE_EXTCODE + '/singular/function_field/core.lib') + normalize = singular_function('core_normalize') + + # Singular "normalP" algorithm assumes affine domain over + # a prime field. So we construct gflat lifting g as in + # k_prime[yy,xx,zz]/(k_poly) where k = k_prime[zz]/(k_poly) + R = PolynomialRing(k.prime_subfield(), names='yy,xx,zz') + gflat = R.zero() + for m in g.monomials(): + c = g.monomial_coefficient(m).polynomial('zz') + gflat += R(c) * R(m) # R(m) is a monomial in yy and xx + + k_poly = R(k.polynomial('zz')) + + # invoke Singular + pols_in_R = normalize(R.ideal([k_poly, gflat])) + + # reconstruct polynomials in S + h = R.hom([y,x,k.gen()],S) + pols_in_S = [h(f) for f in pols_in_R] + else: + # Call Singular. Singular's "normal" function returns a basis + # of the integral closure of k(x,y)/(g) as a k[x,y]-module. + pols_in_S = _singular_normal(S.ideal(g))[0] + + # reconstruct the polynomials in the function field + x = K.gen() + y = self.gen() + pols = [] + for f in pols_in_S: + p = f.polynomial(S.gen(0)) + s = 0 + for i in range(p.degree()+1): + s += p[i].subs(x) * y**i + pols.append(s) + + # Now if pols = [g1,g2,...gn,g0], then the g1/g0,g2/g0,...,gn/g0, + # and g0/g0=1 are the module generators of the integral closure + # of the equation order Sb = k[xb,yb] in its fraction field, + # that is, the function field. The integral closure of k[x] + # is then obtained by multiplying these generators with powers of y + # as the equation order itself is an integral extension of k[x]. + d = ~ pols[-1] + _basis = [] + for f in pols: + b = d * f + for i in range(n): + _basis.append(b) + b *= y + + # Finally we reduce _basis to get a basis over k[x]. This is done of + # course by Hermite normal form computation. Here we apply a trick to + # get a basis that starts with 1 and is ordered in increasing + # y-degrees. The trick is to use the reversed Hermite normal form. + # Note that it is important that the overall denominator l lies in k[x]. + V, fr_V, to_V = self.free_module() + basis_V = [to_V(bvec) for bvec in _basis] + l = lcm([vvec.denominator() for vvec in basis_V]) + + _mat = matrix([[coeff.numerator() for coeff in l*v] for v in basis_V]) + reversed_hermite_form(_mat) + + basis = [fr_V(v) / l for v in _mat if not v.is_zero()] + return basis + + @cached_method + def equation_order(self): + """ + Return the equation order of the function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); R.<t> = PolynomialRing(K) # needs sage.rings.finite_rings + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) # needs sage.rings.finite_rings + sage: F.equation_order() # needs sage.rings.finite_rings + Order in Function field in y defined by y^3 + x^6 + x^4 + x^2 + + sage: K.<x> = FunctionField(QQ); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: F.equation_order() + Order in Function field in y defined by y^3 - x^6 - 2*x^5 - 3*x^4 - 2*x^3 - x^2 + """ + from .order_basis import FunctionFieldOrder_basis + a = self.gen() + basis = [a**i for i in range(self.degree())] + return FunctionFieldOrder_basis(tuple(basis)) + + @cached_method + def primitive_integal_element_infinite(self): + """ + Return a primitive integral element over the base maximal infinite order. + + This element is integral over the maximal infinite order of the base + rational function field and the function field is a simple extension by + this element over the base order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: b = F.primitive_integal_element_infinite(); b + 1/x^2*y + sage: b.minimal_polynomial('t') + t^3 + (x^4 + x^2 + 1)/x^4 + """ + f = self.polynomial() + n = f.degree() + y = self.gen() + x = self.base_field().gen() + + cf = max([(f[i].numerator().degree()/(n-i)).ceil() for i in range(n) + if f[i] != 0]) + return y*x**(-cf) + + @cached_method + def equation_order_infinite(self): + """ + Return the infinite equation order of the function field. + + This is by definition `o[b]` where `b` is the primitive integral + element from :meth:`primitive_integal_element_infinite()` and `o` is + the maximal infinite order of the base rational function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); R.<t> = PolynomialRing(K) # needs sage.rings.finite_rings + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) # needs sage.rings.finite_rings + sage: F.equation_order_infinite() # needs sage.rings.finite_rings + Infinite order in Function field in y defined by y^3 + x^6 + x^4 + x^2 + + sage: K.<x> = FunctionField(QQ); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: F.equation_order_infinite() + Infinite order in Function field in y defined by y^3 - x^6 - 2*x^5 - 3*x^4 - 2*x^3 - x^2 + """ + from .order_basis import FunctionFieldOrderInfinite_basis + b = self.primitive_integal_element_infinite() + basis = [b**i for i in range(self.degree())] + return FunctionFieldOrderInfinite_basis(tuple(basis)) + + +class FunctionField_char_zero_integral(FunctionField_char_zero, FunctionField_integral): + """ + Function fields of characteristic zero, defined by an irreducible and + separable polynomial, integral over the maximal order of the base rational + function field with a finite constant field. + """ + pass + + +class FunctionField_global_integral(FunctionField_global, FunctionField_integral): + """ + Global function fields, defined by an irreducible and separable polynomial, + integral over the maximal order of the base rational function field with a + finite constant field. + """ + pass diff --git a/src/sage/rings/function_field/function_field_rational.py b/src/sage/rings/function_field/function_field_rational.py new file mode 100644 index 00000000000..1b169275da4 --- /dev/null +++ b/src/sage/rings/function_field/function_field_rational.py @@ -0,0 +1,1018 @@ +r""" +Function Fields: rational +""" + +# ***************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2010 Robert Bradshaw <robertwb@math.washington.edu> +# 2011-2018 Julian Rรผth <julian.rueth@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2011 Syed Ahmad Lavasani +# 2013-2014 Simon King +# 2017 Dean Bisogno +# 2017 Alyson Deines +# 2017-2019 David Roe +# 2017-2022 Kwankyu Lee +# 2018 Marc Mezzarobba +# 2018 Wilfried Luebbe +# 2019 Brent Baccala +# 2022 Frรฉdรฉric Chapoton +# 2022 Gonzalo Tornarรญa +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.arith.functions import lcm +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import LazyImport +from sage.structure.category_object import CategoryObject +from sage.rings.integer import Integer +from sage.categories.homset import Hom +from sage.categories.function_fields import FunctionFields + +from .element import FunctionFieldElement +from .element_rational import FunctionFieldElement_rational +from .function_field import FunctionField + + +class RationalFunctionField(FunctionField): + """ + Rational function field in one variable, over an arbitrary base field. + + INPUT: + + - ``constant_field`` -- arbitrary field + + - ``names`` -- string or tuple of length 1 + + EXAMPLES:: + + sage: K.<t> = FunctionField(GF(3)); K + Rational function field in t over Finite Field of size 3 + sage: K.gen() + t + sage: 1/t + t^3 + 5 + (t^4 + 2*t + 1)/t + + sage: K.<t> = FunctionField(QQ); K + Rational function field in t over Rational Field + sage: K.gen() + t + sage: 1/t + t^3 + 5 + (t^4 + 5*t + 1)/t + + There are various ways to get at the underlying fields and rings + associated to a rational function field:: + + sage: K.<t> = FunctionField(GF(7)) + sage: K.base_field() + Rational function field in t over Finite Field of size 7 + sage: K.field() + Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 + sage: K.constant_field() + Finite Field of size 7 + sage: K.maximal_order() + Maximal order of Rational function field in t over Finite Field of size 7 + + sage: K.<t> = FunctionField(QQ) + sage: K.base_field() + Rational function field in t over Rational Field + sage: K.field() + Fraction Field of Univariate Polynomial Ring in t over Rational Field + sage: K.constant_field() + Rational Field + sage: K.maximal_order() + Maximal order of Rational function field in t over Rational Field + + We define a morphism:: + + sage: K.<t> = FunctionField(QQ) + sage: L = FunctionField(QQ, 'tbar') # give variable name as second input + sage: K.hom(L.gen()) + Function Field morphism: + From: Rational function field in t over Rational Field + To: Rational function field in tbar over Rational Field + Defn: t |--> tbar + + Here are some calculations over a number field:: + + sage: R.<x> = FunctionField(QQ) + sage: L.<y> = R[] + sage: F.<y> = R.extension(y^2 - (x^2+1)) # needs sage.rings.function_field + sage: (y/x).divisor() # needs sage.modules sage.rings.function_field + - Place (x, y - 1) + - Place (x, y + 1) + + Place (x^2 + 1, y) + + sage: # needs sage.rings.number_field + sage: A.<z> = QQ[] + sage: NF.<i> = NumberField(z^2 + 1) + sage: R.<x> = FunctionField(NF) + sage: L.<y> = R[] + sage: F.<y> = R.extension(y^2 - (x^2+1)) # needs sage.modules sage.rings.function_field + + sage: (x/y*x.differential()).divisor() # needs sage.modules sage.rings.function_field sage.rings.number_field + -2*Place (1/x, 1/x*y - 1) + - 2*Place (1/x, 1/x*y + 1) + + Place (x, y - 1) + + Place (x, y + 1) + + sage: (x/y).divisor() # needs sage.modules sage.rings.function_field sage.rings.number_field + - Place (x - i, y) + + Place (x, y - 1) + + Place (x, y + 1) + - Place (x + i, y) + + """ + Element = FunctionFieldElement_rational + + def __init__(self, constant_field, names, category=None): + """ + Initialize. + + EXAMPLES:: + + sage: K.<t> = FunctionField(CC); K # needs sage.rings.real_mpfr + Rational function field in t over Complex Field with 53 bits of precision + sage: TestSuite(K).run() # long time (5s) + + sage: FunctionField(QQ[I], 'alpha') # needs sage.rings.number_field + Rational function field in alpha over + Number Field in I with defining polynomial x^2 + 1 with I = 1*I + + Must be over a field:: + + sage: FunctionField(ZZ, 't') + Traceback (most recent call last): + ... + TypeError: constant_field must be a field + """ + if names is None: + raise ValueError("variable name must be specified") + elif not isinstance(names, tuple): + names = (names, ) + if not constant_field.is_field(): + raise TypeError("constant_field must be a field") + + self._constant_field = constant_field + + FunctionField.__init__(self, self, names=names, category=FunctionFields().or_subcategory(category)) + + from .place_rational import FunctionFieldPlace_rational + self._place_class = FunctionFieldPlace_rational + + R = constant_field[names[0]] + self._hash = hash((constant_field, names)) + self._ring = R + self._field = R.fraction_field() + + hom = Hom(self._field, self) + from .maps import FractionFieldToFunctionField + self.register_coercion(hom.__make_element_class__(FractionFieldToFunctionField)(hom.domain(), hom.codomain())) + + from sage.categories.sets_with_partial_maps import SetsWithPartialMaps + from sage.categories.morphism import SetMorphism + R.register_conversion(SetMorphism(self.Hom(R, SetsWithPartialMaps()), self._to_polynomial)) + + self._gen = self(R.gen()) + + def __reduce__(self): + """ + Return the arguments which were used to create this instance. The + rationale for this is explained in the documentation of + :class:`UniqueRepresentation`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: clazz,args = K.__reduce__() + sage: clazz(*args) + Rational function field in x over Rational Field + """ + from .constructor import FunctionField + return FunctionField, (self._constant_field, self._names) + + def __hash__(self): + """ + Return hash of the function field. + + The hash is formed from the constant field and the variable names. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: hash(K) == hash((K.constant_base_field(), K.variable_names())) + True + + """ + return self._hash + + def _repr_(self): + """ + Return string representation of the function field. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: K._repr_() + 'Rational function field in t over Rational Field' + """ + return "Rational function field in %s over %s" % ( + self.variable_name(), self._constant_field) + + def _element_constructor_(self, x): + r""" + Coerce ``x`` into an element of the function field, possibly not canonically. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: a = K._element_constructor_(K.maximal_order().gen()); a + t + sage: a.parent() + Rational function field in t over Rational Field + + TESTS: + + Conversion of a string:: + + sage: K('t') + t + sage: K('1/t') + 1/t + + Conversion of a constant polynomial over the function field:: + + sage: K(K.polynomial_ring().one()) + 1 + + Some indirect test of conversion:: + + sage: S.<x, y> = K[] + sage: I = S * [x^2 - y^2, y - t] + sage: I.groebner_basis() # needs sage.rings.function_field + [x^2 - t^2, y - t] + + """ + if isinstance(x, FunctionFieldElement): + return self.element_class(self, self._field(x._x)) + try: + x = self._field(x) + except TypeError as Err: + try: + if x.parent() is self.polynomial_ring(): + return x[0] + except AttributeError: + pass + raise Err + return self.element_class(self, x) + + def _to_constant_base_field(self, f): + r""" + Return ``f`` as an element of the constant base field. + + INPUT: + + - ``f`` -- element of the rational function field which is a + constant of the underlying rational function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K._to_constant_base_field(K(1)) + 1 + sage: K._to_constant_base_field(K(x)) + Traceback (most recent call last): + ... + ValueError: only constants can be converted into the constant base field but x is not a constant + + TESTS: + + Verify that :trac:`21872` has been resolved:: + + sage: K(1) in QQ + True + sage: x in QQ + False + + """ + K = self.constant_base_field() + if f.denominator() in K and f.numerator() in K: + # When K is not exact, f.denominator() might not be an exact 1, so + # we need to divide explicitly to get the correct precision + return K(f.numerator()) / K(f.denominator()) + raise ValueError("only constants can be converted into the constant base field but %r is not a constant" % (f,)) + + def _to_polynomial(self, f): + """ + If ``f`` is integral, return it as a polynomial. + + INPUT: + + - ``f`` -- an element of this rational function field whose denominator is a constant. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K._ring(x) # indirect doctest + x + """ + K = f.parent().constant_base_field() + if f.denominator() in K: + return f.numerator()/K(f.denominator()) + raise ValueError("only polynomials can be converted to the underlying polynomial ring") + + def _to_bivariate_polynomial(self, f): + """ + Convert ``f`` from a univariate polynomial over the rational function + field into a bivariate polynomial and a denominator. + + INPUT: + + - ``f`` -- univariate polynomial over the function field + + OUTPUT: + + - bivariate polynomial, denominator + + EXAMPLES:: + + sage: R.<t> = FunctionField(GF(7)) + sage: S.<X> = R[] + sage: f = (1/t)*(X^4 - 1/t^2)*(X^3 - t^3) + sage: R._to_bivariate_polynomial(f) + (X^7*t^2 - X^4*t^5 - X^3 + t^3, t^3) + """ + v = f.list() + denom = lcm([a.denominator() for a in v]) + S = denom.parent() + x,t = S.base_ring()['%s,%s' % (f.parent().variable_name(),self.variable_name())].gens() + phi = S.hom([t]) + return sum([phi((denom * v[i]).numerator()) * x**i for i in range(len(v))]), denom + + def _factor_univariate_polynomial(self, f, proof=None): + """ + Factor the univariate polynomial f over the function field. + + INPUT: + + - ``f`` -- univariate polynomial over the function field + + EXAMPLES: + + We do a factorization over the function field over the rationals:: + + sage: R.<t> = FunctionField(QQ) + sage: S.<X> = R[] + sage: f = (1/t)*(X^4 - 1/t^2)*(X^3 - t^3) + sage: f.factor() # indirect doctest # needs sage.libs.singular + (1/t) * (X - t) * (X^2 - 1/t) * (X^2 + 1/t) * (X^2 + t*X + t^2) + sage: f.factor().prod() == f # needs sage.libs.singular + True + + We do a factorization over a finite prime field:: + + sage: R.<t> = FunctionField(GF(7)) + sage: S.<X> = R[] + sage: f = (1/t)*(X^4 - 1/t^2)*(X^3 - t^3) + sage: f.factor() # needs sage.libs.pari + (1/t) * (X + 3*t) * (X + 5*t) * (X + 6*t) * (X^2 + 1/t) * (X^2 + 6/t) + sage: f.factor().prod() == f # needs sage.libs.pari + True + + Factoring over a function field over a non-prime finite field:: + + sage: # needs sage.rings.finite_rings + sage: k.<a> = GF(9) + sage: R.<t> = FunctionField(k) + sage: S.<X> = R[] + sage: f = (1/t)*(X^3 - a*t^3) + sage: f.factor() + (1/t) * (X + (a + 2)*t)^3 + sage: f.factor().prod() == f + True + + Factoring over a function field over a tower of finite fields:: + + sage: # needs sage.rings.finite_rings + sage: k.<a> = GF(4) + sage: R.<b> = k[] + sage: l.<b> = k.extension(b^2 + b + a) + sage: K.<x> = FunctionField(l) + sage: R.<t> = K[] + sage: F = t*x + sage: F.factor(proof=False) + (x) * t + + """ + old_variable_name = f.variable_name() + # the variables of the bivariate polynomial must be distinct + if self.variable_name() == f.variable_name(): + # replace x with xx to make the variable names distinct + f = f.change_variable_name(old_variable_name + old_variable_name) + + F, d = self._to_bivariate_polynomial(f) + fac = F.factor(proof=proof) + x = f.parent().gen() + t = f.parent().base_ring().gen() + phi = F.parent().hom([x, t]) + v = [(phi(P),e) for P, e in fac] + unit = phi(fac.unit())/d + w = [] + for a, e in v: + c = a.leading_coefficient() + a = a/c + # undo any variable substitution that we introduced for the bivariate polynomial + if old_variable_name != a.variable_name(): + a = a.change_variable_name(old_variable_name) + unit *= (c**e) + if a.is_unit(): + unit *= a**e + else: + w.append((a,e)) + from sage.structure.factorization import Factorization + return Factorization(w, unit=unit) + + def extension(self, f, names=None): + """ + Create an extension `L = K[y]/(f(y))` of the rational function field. + + INPUT: + + - ``f`` -- univariate polynomial over self + + - ``names`` -- string or length-1 tuple + + OUTPUT: + + - a function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: K.extension(y^5 - x^3 - 3*x + x*y) # needs sage.rings.function_field + Function field in y defined by y^5 + x*y - x^3 - 3*x + + A nonintegral defining polynomial:: + + sage: K.<t> = FunctionField(QQ); R.<y> = K[] + sage: K.extension(y^3 + (1/t)*y + t^3/(t+1)) # needs sage.rings.function_field + Function field in y defined by y^3 + 1/t*y + t^3/(t + 1) + + The defining polynomial need not be monic or integral:: + + sage: K.extension(t*y^3 + (1/t)*y + t^3/(t+1)) # needs sage.rings.function_field + Function field in y defined by t*y^3 + 1/t*y + t^3/(t + 1) + """ + from . import constructor + return constructor.FunctionFieldExtension(f, names) + + @cached_method + def polynomial_ring(self, var='x'): + """ + Return a polynomial ring in one variable over the rational function field. + + INPUT: + + - ``var`` -- string; name of the variable + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K.polynomial_ring() + Univariate Polynomial Ring in x over Rational function field in x over Rational Field + sage: K.polynomial_ring('T') + Univariate Polynomial Ring in T over Rational function field in x over Rational Field + """ + return self[var] + + @cached_method(key=lambda self, base, basis, map: map) + def free_module(self, base=None, basis=None, map=True): + """ + Return a vector space `V` and isomorphisms from the field to `V` and + from `V` to the field. + + This function allows us to identify the elements of this field with + elements of a one-dimensional vector space over the field itself. This + method exists so that all function fields (rational or not) have the + same interface. + + INPUT: + + - ``base`` -- the base field of the vector space; must be the function + field itself (the default) + + - ``basis`` -- (ignored) a basis for the vector space + + - ``map`` -- (default ``True``), whether to return maps to and from the vector space + + OUTPUT: + + - a vector space `V` over base field + + - an isomorphism from `V` to the field + + - the inverse isomorphism from the field to `V` + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K.free_module() # needs sage.modules + (Vector space of dimension 1 over Rational function field in x over Rational Field, + Isomorphism: + From: Vector space of dimension 1 over Rational function field in x over Rational Field + To: Rational function field in x over Rational Field, + Isomorphism: + From: Rational function field in x over Rational Field + To: Vector space of dimension 1 over Rational function field in x over Rational Field) + + TESTS:: + + sage: K.free_module() # needs sage.modules + (Vector space of dimension 1 over Rational function field in x over Rational Field, + Isomorphism: + From: Vector space of dimension 1 over Rational function field in x over Rational Field + To: Rational function field in x over Rational Field, + Isomorphism: + From: Rational function field in x over Rational Field + To: Vector space of dimension 1 over Rational function field in x over Rational Field) + + """ + if basis is not None: + raise NotImplementedError + from .maps import MapVectorSpaceToFunctionField, MapFunctionFieldToVectorSpace + if base is None: + base = self + elif base is not self: + raise ValueError("base must be the rational function field itself") + V = base**1 + if not map: + return V + from_V = MapVectorSpaceToFunctionField(V, self) + to_V = MapFunctionFieldToVectorSpace(self, V) + return (V, from_V, to_V) + + def random_element(self, *args, **kwds): + """ + Create a random element of the rational function field. + + Parameters are passed to the random_element method of the + underlying fraction field. + + EXAMPLES:: + + sage: FunctionField(QQ,'alpha').random_element() # random + (-1/2*alpha^2 - 4)/(-12*alpha^2 + 1/2*alpha - 1/95) + """ + return self(self._field.random_element(*args, **kwds)) + + def degree(self, base=None): + """ + Return the degree over the base field of the rational function + field. Since the base field is the rational function field itself, the + degree is 1. + + INPUT: + + - ``base`` -- the base field of the vector space; must be the function + field itself (the default) + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: K.degree() + 1 + """ + if base is None: + base = self + elif base is not self: + raise ValueError("base must be the rational function field itself") + from sage.rings.integer_ring import ZZ + return ZZ(1) + + def gen(self, n=0): + """ + Return the ``n``-th generator of the function field. If ``n`` is not + 0, then an :class:` IndexError` is raised. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ); K.gen() + t + sage: K.gen().parent() + Rational function field in t over Rational Field + sage: K.gen(1) + Traceback (most recent call last): + ... + IndexError: Only one generator. + """ + if n != 0: + raise IndexError("Only one generator.") + return self._gen + + def ngens(self): + """ + Return the number of generators, which is 1. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: K.ngens() + 1 + """ + return 1 + + def base_field(self): + """ + Return the base field of the rational function field, which is just + the function field itself. + + EXAMPLES:: + + sage: K.<t> = FunctionField(GF(7)) + sage: K.base_field() + Rational function field in t over Finite Field of size 7 + """ + return self + + def hom(self, im_gens, base_morphism=None): + """ + Create a homomorphism from ``self`` to another ring. + + INPUT: + + - ``im_gens`` -- exactly one element of some ring. It must be + invertible and transcendental over the image of + ``base_morphism``; this is not checked. + + - ``base_morphism`` -- a homomorphism from the base field into the + other ring. If ``None``, try to use a coercion map. + + OUTPUT: + + - a map between function fields + + EXAMPLES: + + We make a map from a rational function field to itself:: + + sage: K.<x> = FunctionField(GF(7)) + sage: K.hom((x^4 + 2)/x) + Function Field endomorphism of Rational function field in x over Finite Field of size 7 + Defn: x |--> (x^4 + 2)/x + + We construct a map from a rational function field into a + non-rational extension field:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^3 + 6*x^3 + x) + sage: f = K.hom(y^2 + y + 2); f + Function Field morphism: + From: Rational function field in x over Finite Field of size 7 + To: Function field in y defined by y^3 + 6*x^3 + x + Defn: x |--> y^2 + y + 2 + sage: f(x) + y^2 + y + 2 + sage: f(x^2) + 5*y^2 + (x^3 + 6*x + 4)*y + 2*x^3 + 5*x + 4 + """ + if isinstance(im_gens, CategoryObject): + return self.Hom(im_gens).natural_map() + if not isinstance(im_gens, (list,tuple)): + im_gens = [im_gens] + if len(im_gens) != 1: + raise ValueError("there must be exactly one generator") + x = im_gens[0] + R = x.parent() + if base_morphism is None and not R.has_coerce_map_from(self.constant_field()): + raise ValueError("you must specify a morphism on the base field") + from .maps import FunctionFieldMorphism_rational + return FunctionFieldMorphism_rational(self.Hom(R), x, base_morphism) + + def field(self): + """ + Return the underlying field, forgetting the function field + structure. + + EXAMPLES:: + + sage: K.<t> = FunctionField(GF(7)) + sage: K.field() + Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 + + .. SEEALSO:: + + :meth:`sage.rings.fraction_field.FractionField_1poly_field.function_field` + + """ + return self._field + + @cached_method + def maximal_order(self): + """ + Return the maximal order of the function field. + + Since this is a rational function field it is of the form `K(t)`, and the + maximal order is by definition `K[t]`, where `K` is the constant field. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: K.maximal_order() + Maximal order of Rational function field in t over Rational Field + sage: K.equation_order() + Maximal order of Rational function field in t over Rational Field + """ + from .order_rational import FunctionFieldMaximalOrder_rational + return FunctionFieldMaximalOrder_rational(self) + + equation_order = maximal_order + + @cached_method + def maximal_order_infinite(self): + """ + Return the maximal infinite order of the function field. + + By definition, this is the valuation ring of the degree valuation of + the rational function field. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: K.maximal_order_infinite() + Maximal infinite order of Rational function field in t over Rational Field + sage: K.equation_order_infinite() + Maximal infinite order of Rational function field in t over Rational Field + """ + from .order_rational import FunctionFieldMaximalOrderInfinite_rational + return FunctionFieldMaximalOrderInfinite_rational(self) + + equation_order_infinite = maximal_order_infinite + + def constant_base_field(self): + """ + Return the field of which the rational function field is a + transcendental extension. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: K.constant_base_field() + Rational Field + """ + return self._constant_field + + constant_field = constant_base_field + + def different(self): + """ + Return the different of the rational function field. + + For a rational function field, the different is simply the zero + divisor. + + EXAMPLES:: + + sage: K.<t> = FunctionField(QQ) + sage: K.different() # needs sage.modules + 0 + """ + return self.divisor_group().zero() + + def genus(self): + """ + Return the genus of the function field, namely 0. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K.genus() + 0 + """ + return Integer(0) + + def change_variable_name(self, name): + r""" + Return a field isomorphic to this field with variable ``name``. + + INPUT: + + - ``name`` -- a string or a tuple consisting of a single string, the + name of the new variable + + OUTPUT: + + A triple ``F,f,t`` where ``F`` is a rational function field, ``f`` is + an isomorphism from ``F`` to this field, and ``t`` is the inverse of + ``f``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: L,f,t = K.change_variable_name('y') + sage: L,f,t + (Rational function field in y over Rational Field, + Function Field morphism: + From: Rational function field in y over Rational Field + To: Rational function field in x over Rational Field + Defn: y |--> x, + Function Field morphism: + From: Rational function field in x over Rational Field + To: Rational function field in y over Rational Field + Defn: x |--> y) + sage: L.change_variable_name('x')[0] is K + True + + """ + if isinstance(name, tuple): + if len(name) != 1: + raise ValueError("names must be a tuple with a single string") + name = name[0] + if name == self.variable_name(): + id = Hom(self,self).identity() + return self,id,id + else: + from .constructor import FunctionField + ret = FunctionField(self.constant_base_field(), name) + return ret, ret.hom(self.gen()), self.hom(ret.gen()) + + def residue_field(self, place, name=None): + """ + Return the residue field of the place along with the maps from + and to it. + + INPUT: + + - ``place`` -- place of the function field + + - ``name`` -- string; name of the generator of the residue field + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(5)) + sage: p = F.places_finite(2)[0] # needs sage.libs.pari + sage: R, fr_R, to_R = F.residue_field(p) # needs sage.libs.pari sage.rings.function_field + sage: R # needs sage.libs.pari sage.rings.function_field + Finite Field in z2 of size 5^2 + sage: to_R(x) in R # needs sage.libs.pari sage.rings.function_field + True + """ + return place.residue_field(name=name) + + +class RationalFunctionField_char_zero(RationalFunctionField): + """ + Rational function fields of characteristic zero. + """ + @cached_method + def higher_derivation(self): + """ + Return the higher derivation for the function field. + + This is also called the Hasse-Schmidt derivation. + + EXAMPLES:: + + sage: F.<x> = FunctionField(QQ) + sage: d = F.higher_derivation() # needs sage.libs.singular sage.modules + sage: [d(x^5,i) for i in range(10)] # needs sage.libs.singular sage.modules + [x^5, 5*x^4, 10*x^3, 10*x^2, 5*x, 1, 0, 0, 0, 0] + sage: [d(x^9,i) for i in range(10)] # needs sage.libs.singular sage.modules + [x^9, 9*x^8, 36*x^7, 84*x^6, 126*x^5, 126*x^4, 84*x^3, 36*x^2, 9*x, 1] + """ + from .derivations_polymod import FunctionFieldHigherDerivation_char_zero + return FunctionFieldHigherDerivation_char_zero(self) + + +class RationalFunctionField_global(RationalFunctionField): + """ + Rational function field over finite fields. + """ + _differentials_space = LazyImport('sage.rings.function_field.differential', 'DifferentialsSpace_global') + + def places(self, degree=1): + """ + Return all places of the degree. + + INPUT: + + - ``degree`` -- (default: 1) a positive integer + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(5)) + sage: F.places() # needs sage.libs.pari + [Place (1/x), + Place (x), + Place (x + 1), + Place (x + 2), + Place (x + 3), + Place (x + 4)] + """ + if degree == 1: + return [self.place_infinite()] + self.places_finite(degree) + else: + return self.places_finite(degree) + + def places_finite(self, degree=1): + """ + Return the finite places of the degree. + + INPUT: + + - ``degree`` -- (default: 1) a positive integer + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(5)) + sage: F.places_finite() # needs sage.libs.pari + [Place (x), Place (x + 1), Place (x + 2), Place (x + 3), Place (x + 4)] + """ + return list(self._places_finite(degree)) + + def _places_finite(self, degree=1): + """ + Return a generator for all monic irreducible polynomials of the degree. + + INPUT: + + - ``degree`` -- (default: 1) a positive integer + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(5)) + sage: F._places_finite() + <generator object ...> + """ + O = self.maximal_order() + R = O._ring + G = R.polynomials(max_degree=degree - 1) + lm = R.monomial(degree) + for g in G: + h = lm + g + if h.is_irreducible(): + yield O.ideal(h).place() + + def place_infinite(self): + """ + Return the unique place at infinity. + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(5)) + sage: F.place_infinite() + Place (1/x) + """ + return self.maximal_order_infinite().prime_ideal().place() + + def get_place(self, degree): + """ + Return a place of ``degree``. + + INPUT: + + - ``degree`` -- a positive integer + + EXAMPLES:: + + sage: F.<a> = GF(2) + sage: K.<x> = FunctionField(F) + sage: K.get_place(1) # needs sage.libs.pari + Place (x) + sage: K.get_place(2) # needs sage.libs.pari + Place (x^2 + x + 1) + sage: K.get_place(3) # needs sage.libs.pari + Place (x^3 + x + 1) + sage: K.get_place(4) # needs sage.libs.pari + Place (x^4 + x + 1) + sage: K.get_place(5) # needs sage.libs.pari + Place (x^5 + x^2 + 1) + + """ + for p in self._places_finite(degree): + return p + + assert False, "there is a bug around" + + @cached_method + def higher_derivation(self): + """ + Return the higher derivation for the function field. + + This is also called the Hasse-Schmidt derivation. + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(5)) + sage: d = F.higher_derivation() # needs sage.rings.function_field + sage: [d(x^5,i) for i in range(10)] # needs sage.rings.function_field + [x^5, 0, 0, 0, 0, 1, 0, 0, 0, 0] + sage: [d(x^7,i) for i in range(10)] # needs sage.rings.function_field + [x^7, 2*x^6, x^5, 0, 0, x^2, 2*x, 1, 0, 0] + """ + from .derivations_polymod import RationalFunctionFieldHigherDerivation_global + return RationalFunctionFieldHigherDerivation_global(self) diff --git a/src/sage/rings/function_field/function_field_valuation.py b/src/sage/rings/function_field/function_field_valuation.py deleted file mode 100644 index 2573df22267..00000000000 --- a/src/sage/rings/function_field/function_field_valuation.py +++ /dev/null @@ -1,1482 +0,0 @@ -# -*- coding: utf-8 -*- -r""" -Discrete valuations on function fields - -AUTHORS: - -- Julian Rรผth (2016-10-16): initial version - -EXAMPLES: - -We can create classical valuations that correspond to finite and infinite -places on a rational function field:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(1); v - (x - 1)-adic valuation - sage: v = K.valuation(x^2 + 1); v - (x^2 + 1)-adic valuation - sage: v = K.valuation(1/x); v - Valuation at the infinite place - -Note that we can also specify valuations which do not correspond to a place of -the function field:: - - sage: R.<x> = QQ[] - sage: w = valuations.GaussValuation(R, QQ.valuation(2)) - sage: v = K.valuation(w); v - 2-adic valuation - -Valuations on a rational function field can then be extended to finite -extensions:: - - sage: v = K.valuation(x - 1); v - (x - 1)-adic valuation - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: w = v.extensions(L); w - [[ (x - 1)-adic valuation, v(y + 1) = 1 ]-adic valuation, - [ (x - 1)-adic valuation, v(y - 1) = 1 ]-adic valuation] - -TESTS: - -Run test suite for classical places over rational function fields:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(1) - sage: TestSuite(v).run(max_runs=100) # long time - - sage: v = K.valuation(x^2 + 1) - sage: TestSuite(v).run(max_runs=100) # long time - - sage: v = K.valuation(1/x) - sage: TestSuite(v).run(max_runs=100) # long time - -Run test suite over classical places of finite extensions:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x - 1) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: ws = v.extensions(L) - sage: for w in ws: TestSuite(w).run(max_runs=100) # long time - -Run test suite for valuations that do not correspond to a classical place:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<x> = QQ[] - sage: v = GaussValuation(R, QQ.valuation(2)) - sage: w = K.valuation(v) - sage: TestSuite(w).run() # long time - -Run test suite for a non-classical valuation that does not correspond to an -affinoid contained in the unit disk:: - - sage: w = K.valuation((w, K.hom(K.gen()/2), K.hom(2*K.gen()))); w - 2-adic valuation (in Rational function field in x over Rational Field after x |--> 1/2*x) - sage: TestSuite(w).run() # long time - -Run test suite for some other classical places over large ground fields:: - - sage: K.<t> = FunctionField(GF(3)) - sage: M.<x> = FunctionField(K) - sage: v = M.valuation(x^3 - t) - sage: TestSuite(v).run(max_runs=10) # long time - -Run test suite for extensions over the infinite place:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(1/x) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - 1/(x^2 + 1)) - sage: w = v.extensions(L) - sage: TestSuite(w).run() # long time - -Run test suite for a valuation with `v(1/x) > 0` which does not come from a -classical valuation of the infinite place:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<x> = QQ[] - sage: w = GaussValuation(R, QQ.valuation(2)).augmentation(x, 1) - sage: w = K.valuation(w) - sage: v = K.valuation((w, K.hom([~K.gen()]), K.hom([~K.gen()]))) - sage: TestSuite(v).run() # long time - -Run test suite for extensions which come from the splitting in the base field:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x^2 + 1) - sage: L.<x> = FunctionField(GaussianIntegers().fraction_field()) - sage: ws = v.extensions(L) - sage: for w in ws: TestSuite(w).run(max_runs=100) # long time - -Run test suite for a finite place with residual degree and ramification:: - - sage: K.<t> = FunctionField(GF(3)) - sage: L.<x> = FunctionField(K) - sage: v = L.valuation(x^6 - t) - sage: TestSuite(v).run(max_runs=10) # long time - -Run test suite for a valuation which is backed by limit valuation:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - (x^2 + x + 1)) - sage: v = K.valuation(x - 1) - sage: w = v.extension(L) - sage: TestSuite(w).run() # long time - -Run test suite for a valuation which sends an element to `-\infty`:: - - sage: R.<x> = QQ[] - sage: v = GaussValuation(QQ['x'], QQ.valuation(2)).augmentation(x, infinity) - sage: K.<x> = FunctionField(QQ) - sage: w = K.valuation(v) - sage: TestSuite(w).run() # long time - -REFERENCES: - -An overview of some computational tools relating to valuations on function -fields can be found in Section 4.6 of [Rรผt2014]_. Most of this was originally -developed for number fields in [Mac1936I]_ and [Mac1936II]_. - -""" -# **************************************************************************** -# Copyright (C) 2016-2018 Julian Rรผth <julian.rueth@fsfe.org> -# -# Distributed under the terms of the GNU General Public License (GPL) -# as published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# https://www.gnu.org/licenses/ -# **************************************************************************** -from sage.structure.factory import UniqueFactory -from sage.rings.rational_field import QQ -from sage.misc.cachefunc import cached_method - -from sage.rings.valuation.valuation import DiscreteValuation, DiscretePseudoValuation, InfiniteDiscretePseudoValuation, NegativeInfiniteDiscretePseudoValuation -from sage.rings.valuation.trivial_valuation import TrivialValuation -from sage.rings.valuation.mapped_valuation import FiniteExtensionFromLimitValuation, MappedValuation_base - -class FunctionFieldValuationFactory(UniqueFactory): - r""" - Create a valuation on ``domain`` corresponding to ``prime``. - - INPUT: - - - ``domain`` -- a function field - - - ``prime`` -- a place of the function field, a valuation on a subring, or - a valuation on another function field together with information for - isomorphisms to and from that function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(1); v # indirect doctest - (x - 1)-adic valuation - sage: v(x) - 0 - sage: v(x - 1) - 1 - - See :meth:`sage.rings.function_field.function_field.FunctionField.valuation` for further examples. - - """ - def create_key_and_extra_args(self, domain, prime): - r""" - Create a unique key which identifies the valuation given by ``prime`` - on ``domain``. - - TESTS: - - We specify a valuation on a function field by two different means and - get the same object:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x - 1) # indirect doctest - - sage: R.<x> = QQ[] - sage: w = GaussValuation(R, valuations.TrivialValuation(QQ)).augmentation(x - 1, 1) - sage: K.valuation(w) is v - True - - The normalization is, however, not smart enough, to unwrap - substitutions that turn out to be trivial:: - - sage: w = GaussValuation(R, QQ.valuation(2)) - sage: w = K.valuation(w) - sage: w is K.valuation((w, K.hom([~K.gen()]), K.hom([~K.gen()]))) - False - - """ - from sage.categories.function_fields import FunctionFields - if domain not in FunctionFields(): - raise ValueError("Domain must be a function field.") - - if isinstance(prime, tuple): - if len(prime) == 3: - # prime is a triple of a valuation on another function field with - # isomorphism information - return self.create_key_and_extra_args_from_valuation_on_isomorphic_field(domain, prime[0], prime[1], prime[2]) - - from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace - if prime.parent() is DiscretePseudoValuationSpace(domain): - # prime is already a valuation of the requested domain - # if we returned (domain, prime), we would break caching - # because this element has been created from a different key - # Instead, we return the key that was used to create prime - # so the caller gets back a correctly cached version of prime - if not hasattr(prime, "_factory_data"): - raise NotImplementedError("Valuations on function fields must be unique and come out of the FunctionFieldValuation factory but %r has been created by other means" % (prime,)) - return prime._factory_data[2], {} - - if prime in domain: - # prime defines a place - return self.create_key_and_extra_args_from_place(domain, prime) - if prime.parent() is DiscretePseudoValuationSpace(domain._ring): - # prime is a discrete (pseudo-)valuation on the polynomial ring - # that the domain is constructed from - return self.create_key_and_extra_args_from_valuation(domain, prime) - if domain.base_field() is not domain: - # prime might define a valuation on a subring of domain and have a - # unique extension to domain - base_valuation = domain.base_field().valuation(prime) - return self.create_key_and_extra_args_from_valuation(domain, base_valuation) - from sage.rings.ideal import is_Ideal - if is_Ideal(prime): - raise NotImplementedError("a place cannot be given by an ideal yet") - - raise NotImplementedError("argument must be a place or a pseudo-valuation on a supported subring but %r does not satisfy this for the domain %r" % (prime, domain)) - - def create_key_and_extra_args_from_place(self, domain, generator): - r""" - Create a unique key which identifies the valuation at the place - specified by ``generator``. - - TESTS: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(1/x) # indirect doctest - - """ - if generator not in domain.base_field(): - raise NotImplementedError("a place must be defined over a rational function field") - - if domain.base_field() is not domain: - # if this is an extension field, construct the unique place over - # the place on the subfield - return self.create_key_and_extra_args(domain, domain.base_field().valuation(generator)) - - if generator in domain.constant_base_field(): - # generator is a constant, we associate to it the place which - # corresponds to the polynomial (x - generator) - return self.create_key_and_extra_args(domain, domain.gen() - generator) - - if generator in domain._ring: - # generator is a polynomial - generator = domain._ring(generator) - if not generator.is_monic(): - raise ValueError("place must be defined by a monic polynomial but %r is not monic" % (generator,)) - if not generator.is_irreducible(): - raise ValueError("place must be defined by an irreducible polynomial but %r factors over %r" % (generator, domain._ring)) - # we construct the corresponding valuation on the polynomial ring - # with v(generator) = 1 - from sage.rings.valuation.gauss_valuation import GaussValuation - valuation = GaussValuation(domain._ring, TrivialValuation(domain.constant_base_field())).augmentation(generator, 1) - return self.create_key_and_extra_args(domain, valuation) - elif generator == ~domain.gen(): - # generator is 1/x, the infinite place - return (domain, (domain.valuation(domain.gen()), domain.hom(~domain.gen()), domain.hom(~domain.gen()))), {} - else: - raise ValueError("a place must be given by an irreducible polynomial or the inverse of the generator; %r does not define a place over %r" % (generator, domain)) - - def create_key_and_extra_args_from_valuation(self, domain, valuation): - r""" - Create a unique key which identifies the valuation which extends - ``valuation``. - - TESTS: - - sage: K.<x> = FunctionField(QQ) - sage: R.<x> = QQ[] - sage: w = GaussValuation(R, valuations.TrivialValuation(QQ)).augmentation(x - 1, 1) - sage: v = K.valuation(w) # indirect doctest - - Check that :trac:`25294` has been resolved:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^3 + 1/x^3*y + 2/x^4) - sage: v = K.valuation(x) - sage: v.extensions(L) - [[ (x)-adic valuation, v(y) = 1 ]-adic valuation (in Function field in y defined by y^3 + x*y + 2*x^2 after y |--> 1/x^2*y), - [ (x)-adic valuation, v(y) = 1/2 ]-adic valuation (in Function field in y defined by y^3 + x*y + 2*x^2 after y |--> 1/x^2*y)] - - """ - # this should have been handled by create_key already - assert valuation.domain() is not domain - - if valuation.domain() is domain._ring: - if domain.base_field() is not domain: - vK = valuation.restriction(valuation.domain().base_ring()) - if vK.domain() is not domain.base_field(): - raise ValueError("valuation must extend a valuation on the base field but %r extends %r whose domain is not %r" % (valuation, vK, domain.base_field())) - # Valuation is an approximant that describes a single valuation - # on domain. - # For uniqueness of valuations (which provides better caching - # and easier pickling) we need to find a normal form of - # valuation, i.e., the smallest approximant that describes this - # valuation - approximants = vK.mac_lane_approximants(domain.polynomial(), require_incomparability=True) - approximant = vK.mac_lane_approximant(domain.polynomial(), valuation, approximants) - return (domain, approximant), {'approximants': approximants} - else: - # on a rational function field K(x), any valuation on K[x] that - # does not have an element with valuation -infty extends to a - # pseudo-valuation on K(x) - if valuation.is_negative_pseudo_valuation(): - raise ValueError("there must not be an element of valuation -Infinity in the domain of valuation %r" % (valuation,)) - return (domain, valuation), {} - - if valuation.domain().is_subring(domain.base_field()): - # valuation is defined on a subring of this function field, try to lift it - return self.create_key_and_extra_args(domain, valuation.extension(domain)) - - raise NotImplementedError("extension of valuation from %r to %r not implemented yet" % (valuation.domain(), domain)) - - def create_key_and_extra_args_from_valuation_on_isomorphic_field(self, domain, valuation, to_valuation_domain, from_valuation_domain): - r""" - Create a unique key which identifies the valuation which is - ``valuation`` after mapping through ``to_valuation_domain``. - - TESTS:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 + y + x^3) - sage: v = K.valuation(1/x) - sage: w = v.extension(L) # indirect doctest - - """ - from sage.categories.function_fields import FunctionFields - if valuation.domain() not in FunctionFields(): - raise ValueError("valuation must be defined over an isomorphic function field but %r is not a function field" % (valuation.domain(),)) - - from sage.categories.homset import Hom - if to_valuation_domain not in Hom(domain, valuation.domain()): - raise ValueError("to_valuation_domain must map from %r to %r but %r maps from %r to %r" % (domain, valuation.domain(), to_valuation_domain, to_valuation_domain.domain(), to_valuation_domain.codomain())) - if from_valuation_domain not in Hom(valuation.domain(), domain): - raise ValueError("from_valuation_domain must map from %r to %r but %r maps from %r to %r" % (valuation.domain(), domain, from_valuation_domain, from_valuation_domain.domain(), from_valuation_domain.codomain())) - - if domain is domain.base(): - if valuation.domain() is not valuation.domain().base() or valuation.domain().constant_base_field() != domain.constant_base_field(): - raise NotImplementedError("maps must be isomorphisms with a rational function field over the same base field, not with %r" % (valuation.domain(),)) - if domain != valuation.domain(): - # make it harder to create different representations of the same valuation - # (nothing bad happens if we did, but >= and <= are only implemented when this is the case.) - raise NotImplementedError("domain and valuation.domain() must be the same rational function field but %r is not %r" % (domain, valuation.domain())) - else: - if domain.base() is not valuation.domain().base(): - raise NotImplementedError("domain and valuation.domain() must have the same base field but %r is not %r" % (domain.base(), valuation.domain().base())) - if to_valuation_domain != domain.hom([to_valuation_domain(domain.gen())]): - raise NotImplementedError("to_valuation_domain must be trivial on the base fields but %r is not %r" % (to_valuation_domain, domain.hom([to_valuation_domain(domain.gen())]))) - if from_valuation_domain != valuation.domain().hom([from_valuation_domain(valuation.domain().gen())]): - raise NotImplementedError("from_valuation_domain must be trivial on the base fields but %r is not %r" % (from_valuation_domain, valuation.domain().hom([from_valuation_domain(valuation.domain().gen())]))) - if to_valuation_domain(domain.gen()) == valuation.domain().gen(): - raise NotImplementedError("to_valuation_domain seems to be trivial but trivial maps would currently break partial orders of valuations") - - if from_valuation_domain(to_valuation_domain(domain.gen())) != domain.gen(): - # only a necessary condition - raise ValueError("to_valuation_domain and from_valuation_domain are not inverses of each other") - - return (domain, (valuation, to_valuation_domain, from_valuation_domain)), {} - - def create_object(self, version, key, **extra_args): - r""" - Create the valuation specified by ``key``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<x> = QQ[] - sage: w = valuations.GaussValuation(R, QQ.valuation(2)) - sage: v = K.valuation(w); v # indirect doctest - 2-adic valuation - - """ - domain, valuation = key - from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace - parent = DiscretePseudoValuationSpace(domain) - - if isinstance(valuation, tuple) and len(valuation) == 3: - valuation, to_valuation_domain, from_valuation_domain = valuation - if domain is domain.base() and valuation.domain() is valuation.domain().base(): - if valuation == valuation.domain().valuation(valuation.domain().gen()): - if to_valuation_domain != domain.hom([~valuation.domain().gen()]) or from_valuation_domain != valuation.domain().hom([~domain.gen()]): - raise ValueError("the only allowed automorphism for classical valuations is the automorphism x |--> 1/x") - # valuation on the rational function field after x |--> 1/x, - # i.e., the classical valuation at infinity - return parent.__make_element_class__(InfiniteRationalFunctionFieldValuation)(parent) - - from sage.structure.dynamic_class import dynamic_class - clazz = RationalFunctionFieldMappedValuation - if valuation.is_discrete_valuation(): - clazz = dynamic_class("RationalFunctionFieldMappedValuation_discrete", (clazz, DiscreteValuation)) - else: - clazz = dynamic_class("RationalFunctionFieldMappedValuation_infinite", (clazz, InfiniteDiscretePseudoValuation)) - return parent.__make_element_class__(clazz)(parent, valuation, to_valuation_domain, from_valuation_domain) - return parent.__make_element_class__(FunctionFieldExtensionMappedValuation)(parent, valuation, to_valuation_domain, from_valuation_domain) - - if domain is valuation.domain(): - # we cannot just return valuation in this case - # as this would break uniqueness and pickling - raise ValueError("valuation must not be a valuation on domain yet but %r is a valuation on %r" % (valuation, domain)) - - if domain.base_field() is domain: - # valuation is a base valuation on K[x] that induces a valuation on K(x) - if valuation.restriction(domain.constant_base_field()).is_trivial() and valuation.is_discrete_valuation(): - # valuation corresponds to a finite place - return parent.__make_element_class__(FiniteRationalFunctionFieldValuation)(parent, valuation) - else: - from sage.structure.dynamic_class import dynamic_class - clazz = NonClassicalRationalFunctionFieldValuation - if valuation.is_discrete_valuation(): - clazz = dynamic_class("NonClassicalRationalFunctionFieldValuation_discrete", (clazz, DiscreteFunctionFieldValuation_base)) - else: - clazz = dynamic_class("NonClassicalRationalFunctionFieldValuation_negative_infinite", (clazz, NegativeInfiniteDiscretePseudoValuation)) - return parent.__make_element_class__(clazz)(parent, valuation) - else: - # valuation is a limit valuation that singles out an extension - return parent.__make_element_class__(FunctionFieldFromLimitValuation)(parent, valuation, domain.polynomial(), extra_args['approximants']) - - raise NotImplementedError("valuation on %r from %r on %r" % (domain, valuation, valuation.domain())) - -FunctionFieldValuation = FunctionFieldValuationFactory("sage.rings.function_field.function_field_valuation.FunctionFieldValuation") - - -class FunctionFieldValuation_base(DiscretePseudoValuation): - r""" - Abstract base class for any discrete (pseudo-)valuation on a function - field. - - TESTS:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x) # indirect doctest - sage: from sage.rings.function_field.function_field_valuation import FunctionFieldValuation_base - sage: isinstance(v, FunctionFieldValuation_base) - True - - """ - - -class DiscreteFunctionFieldValuation_base(DiscreteValuation): - r""" - Base class for discrete valuations on function fields. - - TESTS:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x) # indirect doctest - sage: from sage.rings.function_field.function_field_valuation import DiscreteFunctionFieldValuation_base - sage: isinstance(v, DiscreteFunctionFieldValuation_base) - True - - """ - def extensions(self, L): - r""" - Return the extensions of this valuation to ``L``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: v.extensions(L) - [(x)-adic valuation] - - TESTS: - - Valuations over the infinite place:: - - sage: v = K.valuation(1/x) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - 1/(x^2 + 1)) - sage: sorted(v.extensions(L), key=str) - [[ Valuation at the infinite place, v(y + 1/x) = 3 ]-adic valuation, - [ Valuation at the infinite place, v(y - 1/x) = 3 ]-adic valuation] - - Iterated extensions over the infinite place:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 + y + x^3) - sage: v = K.valuation(1/x) - sage: w = v.extension(L) - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2 - y) - sage: w.extension(M) # squarefreeness is not implemented here - Traceback (most recent call last): - ... - NotImplementedError - - A case that caused some trouble at some point:: - - sage: R.<x> = QQ[] - sage: v = GaussValuation(R, QQ.valuation(2)) - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(v) - - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^3 - x^4 - 1) - sage: v.extensions(L) - [2-adic valuation] - - Test that this works in towers:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y - x) - sage: R.<z> = L[] - sage: L.<z> = L.extension(z - y) - sage: v = K.valuation(x) - sage: v.extensions(L) - [(x)-adic valuation] - """ - K = self.domain() - from sage.categories.function_fields import FunctionFields - if L is K: - return [self] - if L in FunctionFields(): - if K.is_subring(L): - if L.base() is K: - # L = K[y]/(G) is a simple extension of the domain of this valuation - G = L.polynomial() - if not G.is_monic(): - G = G / G.leading_coefficient() - if any(self(c) < 0 for c in G.coefficients()): - # rewrite L = K[u]/(H) with H integral and compute the extensions - from sage.rings.valuation.gauss_valuation import GaussValuation - g = GaussValuation(G.parent(), self) - y_to_u, u_to_y, H = g.monic_integral_model(G) - M = K.extension(H, names=L.variable_names()) - H_extensions = self.extensions(M) - - from sage.rings.morphism import RingHomomorphism_im_gens - if type(y_to_u) == RingHomomorphism_im_gens and type(u_to_y) == RingHomomorphism_im_gens: - return [L.valuation((w, L.hom([M(y_to_u(y_to_u.domain().gen()))]), M.hom([L(u_to_y(u_to_y.domain().gen()))]))) for w in H_extensions] - raise NotImplementedError - return [L.valuation(w) for w in self.mac_lane_approximants(L.polynomial(), require_incomparability=True)] - elif L.base() is not L and K.is_subring(L): - # recursively call this method for the tower of fields - from operator import add - from functools import reduce - A = [base_valuation.extensions(L) for base_valuation in self.extensions(L.base())] - return reduce(add, A, []) - elif L.constant_base_field() is not K.constant_base_field() and K.constant_base_field().is_subring(L): - # subclasses should override this method and handle this case, so we never get here - raise NotImplementedError("Cannot compute the extensions of %r from %r to %r since the base ring changes." % (self, self.domain(), L)) - raise NotImplementedError("extension of %r from %r to %r not implemented" % (self, K, L)) - - -class RationalFunctionFieldValuation_base(FunctionFieldValuation_base): - r""" - Base class for valuations on rational function fields. - - TESTS:: - - sage: K.<x> = FunctionField(GF(2)) - sage: v = K.valuation(x) # indirect doctest - sage: from sage.rings.function_field.function_field_valuation import RationalFunctionFieldValuation_base - sage: isinstance(v, RationalFunctionFieldValuation_base) - True - - """ - @cached_method - def element_with_valuation(self, s): - r""" - Return an element with valuation ``s``. - - EXAMPLES:: - - sage: K.<a> = NumberField(x^3+6) - sage: v = K.valuation(2) - sage: R.<x> = K[] - sage: w = GaussValuation(R, v).augmentation(x, 1/123) - sage: K.<x> = FunctionField(K) - sage: w = w.extension(K) - sage: w.element_with_valuation(122/123) - 2/x - sage: w.element_with_valuation(1) - 2 - - """ - constant_valuation = self.restriction(self.domain().constant_base_field()) - if constant_valuation.is_trivial(): - return super().element_with_valuation(s) - - a, b = self.value_group()._element_with_valuation(constant_valuation.value_group(), s) - ret = self.uniformizer()**a * constant_valuation.element_with_valuation(constant_valuation.value_group().gen()*b) - - return self.simplify(ret, error=s) - - -class ClassicalFunctionFieldValuation_base(DiscreteFunctionFieldValuation_base): - r""" - Base class for discrete valuations on rational function fields that come - from points on the projective line. - - TESTS:: - - sage: K.<x> = FunctionField(GF(5)) - sage: v = K.valuation(x) # indirect doctest - sage: from sage.rings.function_field.function_field_valuation import ClassicalFunctionFieldValuation_base - sage: isinstance(v, ClassicalFunctionFieldValuation_base) - True - - """ - def _test_classical_residue_field(self, **options): - r""" - Check correctness of the residue field of a discrete valuation at a - classical point. - - TESTS:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x^2 + 1) - sage: v._test_classical_residue_field() - - """ - tester = self._tester(**options) - - tester.assertTrue(self.domain().constant_base_field().is_subring(self.residue_field())) - - def _ge_(self, other): - r""" - Return whether ``self`` is greater or equal to ``other`` everywhere. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x^2 + 1) - sage: w = K.valuation(x) - sage: v >= w - False - sage: w >= v - False - - """ - if other.is_trivial(): - return other.is_discrete_valuation() - if isinstance(other, ClassicalFunctionFieldValuation_base): - return self == other - super()._ge_(other) - - -class InducedRationalFunctionFieldValuation_base(FunctionFieldValuation_base): - r""" - Base class for function field valuation induced by a valuation on the - underlying polynomial ring. - - TESTS:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x^2 + 1) # indirect doctest - - """ - def __init__(self, parent, base_valuation): - r""" - TESTS:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x) # indirect doctest - sage: from sage.rings.function_field.function_field_valuation import InducedRationalFunctionFieldValuation_base - sage: isinstance(v, InducedRationalFunctionFieldValuation_base) - True - - """ - FunctionFieldValuation_base.__init__(self, parent) - - domain = parent.domain() - if base_valuation.domain() is not domain._ring: - raise ValueError("base valuation must be defined on %r but %r is defined on %r" % (domain._ring, base_valuation, base_valuation.domain())) - - self._base_valuation = base_valuation - - def uniformizer(self): - r""" - Return a uniformizing element for this valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K.valuation(x).uniformizer() - x - - """ - return self.domain()(self._base_valuation.uniformizer()) - - def lift(self, F): - r""" - Return a lift of ``F`` to the domain of this valuation such - that :meth:`reduce` returns the original element. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x) - sage: v.lift(0) - 0 - sage: v.lift(1) - 1 - - """ - F = self.residue_ring().coerce(F) - if F in self._base_valuation.residue_ring(): - num = self._base_valuation.residue_ring()(F) - den = self._base_valuation.residue_ring()(1) - elif F in self._base_valuation.residue_ring().fraction_field(): - num = self._base_valuation.residue_ring()(F.numerator()) - den = self._base_valuation.residue_ring()(F.denominator()) - else: - raise NotImplementedError("lifting not implemented for this valuation") - - return self.domain()(self._base_valuation.lift(num)) / self.domain()(self._base_valuation.lift(den)) - - def value_group(self): - r""" - Return the value group of this valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K.valuation(x).value_group() - Additive Abelian Group generated by 1 - - """ - return self._base_valuation.value_group() - - def reduce(self, f): - r""" - Return the reduction of ``f`` in :meth:`residue_ring`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x^2 + 1) - sage: v.reduce(x) - u1 - - """ - f = self.domain().coerce(f) - - if self(f) > 0: - return self.residue_field().zero() - if self(f) < 0: - raise ValueError("cannot reduce element of negative valuation") - - base = self._base_valuation - - num = f.numerator() - den = f.denominator() - - assert base(num) == base(den) - shift = base.element_with_valuation(-base(num)) - num *= shift - den *= shift - ret = base.reduce(num) / base.reduce(den) - assert not ret.is_zero() - return self.residue_field()(ret) - - def _repr_(self): - r""" - Return a printable representation of this valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K.valuation(x^2 + 1) # indirect doctest - (x^2 + 1)-adic valuation - - """ - from sage.rings.valuation.augmented_valuation import AugmentedValuation_base - from sage.rings.valuation.gauss_valuation import GaussValuation - if isinstance(self._base_valuation, AugmentedValuation_base): - if self._base_valuation._base_valuation == GaussValuation(self.domain()._ring, TrivialValuation(self.domain().constant_base_field())): - if self._base_valuation._mu == 1: - return "(%r)-adic valuation" % (self._base_valuation.phi()) - vK = self._base_valuation.restriction(self._base_valuation.domain().base_ring()) - if self._base_valuation == GaussValuation(self.domain()._ring, vK): - return repr(vK) - return "Valuation on rational function field induced by %s" % self._base_valuation - - def extensions(self, L): - r""" - Return all extensions of this valuation to ``L`` which has a larger - constant field than the domain of this valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x^2 + 1) - sage: L.<x> = FunctionField(GaussianIntegers().fraction_field()) - sage: v.extensions(L) # indirect doctest - [(x - I)-adic valuation, (x + I)-adic valuation] - - """ - K = self.domain() - if L is K: - return [self] - - from sage.categories.function_fields import FunctionFields - if (L in FunctionFields() - and K.is_subring(L) - and L.base() is L - and L.constant_base_field() is not K.constant_base_field() - and K.constant_base_field().is_subring(L.constant_base_field())): - # The above condition checks whether L is an extension of K that - # comes from an extension of the field of constants - # Condition "L.base() is L" is important so we do not call this - # code for extensions from K(x) to K(x)(y) - - # We extend the underlying valuation on the polynomial ring - W = self._base_valuation.extensions(L._ring) - return [L.valuation(w) for w in W] - - return super().extensions(L) - - def _call_(self, f): - r""" - Evaluate this valuation at the function ``f``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x) # indirect doctest - sage: v((x+1)/x^2) - -2 - - """ - return self._base_valuation(f.numerator()) - self._base_valuation(f.denominator()) - - def residue_ring(self): - r""" - Return the residue field of this valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K.valuation(x).residue_ring() - Rational Field - - """ - return self._base_valuation.residue_ring().fraction_field() - - def restriction(self, ring): - r""" - Return the restriction of this valuation to ``ring``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K.valuation(x).restriction(QQ) - Trivial valuation on Rational Field - - """ - if ring.is_subring(self._base_valuation.domain()): - return self._base_valuation.restriction(ring) - return super().restriction(ring) - - def simplify(self, f, error=None, force=False): - r""" - Return a simplified version of ``f``. - - Produce an element which differs from ``f`` by an element of - valuation strictly greater than the valuation of ``f`` (or strictly - greater than ``error`` if set.) - - If ``force`` is not set, then expensive simplifications may be avoided. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(2) - sage: f = (x + 1)/(x - 1) - - As the coefficients of this fraction are small, we do not simplify as - this could be very costly in some cases:: - - sage: v.simplify(f) - (x + 1)/(x - 1) - - However, simplification can be forced:: - - sage: v.simplify(f, force=True) - 3 - - """ - f = self.domain().coerce(f) - - if error is None: - # if the caller was sure that we should simplify, then we should try to do the best simplification possible - error = self(f) if force else self.upper_bound(f) - - from sage.rings.infinity import infinity - if error is infinity: - return f - - numerator = f.numerator() - denominator = f.denominator() - - v_numerator = self._base_valuation(numerator) - v_denominator = self._base_valuation(denominator) - - if v_numerator - v_denominator > error: - return self.domain().zero() - - if error == -infinity: - # This case is not implemented yet, so we just return f which is always safe. - return f - - numerator = self.domain()(self._base_valuation.simplify(numerator, error=error+v_denominator, force=force)) - denominator = self.domain()(self._base_valuation.simplify(denominator, error=max(v_denominator, error - v_numerator + 2*v_denominator), force=force)) - - ret = numerator/denominator - assert self(ret - f) > error - return ret - - def _relative_size(self, f): - r""" - Return an estimate on the coefficient size of ``f``. - - The number returned is an estimate on the factor between the number of - bits used by ``f`` and the minimal number of bits used by an element - congruent to ``f``. - - This can be used by :meth:`simplify` to decide whether simplification - of coefficients is going to lead to a significant shrinking of the - coefficients of ``f``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(0) - sage: f = (x + 1024)/(x - 1024) - - Here we report a small size, as the numerator and the denominator - independently cannot be simplified much:: - - sage: v._relative_size(f) - 1 - - However, a forced simplification, finds that we could have saved many - more bits:: - - sage: v.simplify(f, force=True) - -1 - - """ - return max(self._base_valuation._relative_size(f.numerator()), self._base_valuation._relative_size(f.denominator())) - - -class FiniteRationalFunctionFieldValuation(InducedRationalFunctionFieldValuation_base, ClassicalFunctionFieldValuation_base, RationalFunctionFieldValuation_base): - r""" - Valuation of a finite place of a function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x + 1); v # indirect doctest - (x + 1)-adic valuation - - A finite place with residual degree:: - - sage: w = K.valuation(x^2 + 1); w - (x^2 + 1)-adic valuation - - A finite place with ramification:: - - sage: K.<t> = FunctionField(GF(3)) - sage: L.<x> = FunctionField(K) - sage: u = L.valuation(x^3 - t); u - (x^3 + 2*t)-adic valuation - - A finite place with residual degree and ramification:: - - sage: q = L.valuation(x^6 - t); q - (x^6 + 2*t)-adic valuation - - """ - def __init__(self, parent, base_valuation): - r""" - TESTS:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(x + 1) - sage: from sage.rings.function_field.function_field_valuation import FiniteRationalFunctionFieldValuation - sage: isinstance(v, FiniteRationalFunctionFieldValuation) - True - - """ - InducedRationalFunctionFieldValuation_base.__init__(self, parent, base_valuation) - ClassicalFunctionFieldValuation_base.__init__(self, parent) - RationalFunctionFieldValuation_base.__init__(self, parent) - - -class NonClassicalRationalFunctionFieldValuation(InducedRationalFunctionFieldValuation_base, RationalFunctionFieldValuation_base): - r""" - Valuation induced by a valuation on the underlying polynomial ring which is - non-classical. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = GaussValuation(QQ['x'], QQ.valuation(2)) - sage: w = K.valuation(v); w # indirect doctest - 2-adic valuation - - """ - def __init__(self, parent, base_valuation): - r""" - TESTS: - - There is some support for discrete pseudo-valuations on rational - function fields in the code. However, since these valuations must send - elements to `-\infty`, they are not supported yet:: - - sage: R.<x> = QQ[] - sage: v = GaussValuation(QQ['x'], QQ.valuation(2)).augmentation(x, infinity) - sage: K.<x> = FunctionField(QQ) - sage: w = K.valuation(v) - sage: from sage.rings.function_field.function_field_valuation import NonClassicalRationalFunctionFieldValuation - sage: isinstance(w, NonClassicalRationalFunctionFieldValuation) - True - - """ - InducedRationalFunctionFieldValuation_base.__init__(self, parent, base_valuation) - RationalFunctionFieldValuation_base.__init__(self, parent) - - def residue_ring(self): - r""" - Return the residue field of this valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = valuations.GaussValuation(QQ['x'], QQ.valuation(2)) - sage: w = K.valuation(v) - sage: w.residue_ring() - Rational function field in x over Finite Field of size 2 - - sage: R.<x> = QQ[] - sage: vv = v.augmentation(x, 1) - sage: w = K.valuation(vv) - sage: w.residue_ring() - Rational function field in x over Finite Field of size 2 - - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 + 2*x) - sage: w.extension(L).residue_ring() - Function field in u2 defined by u2^2 + x - - TESTS: - - This still works for pseudo-valuations:: - - sage: R.<x> = QQ[] - sage: v = valuations.GaussValuation(R, QQ.valuation(2)) - sage: vv = v.augmentation(x, infinity) - sage: K.<x> = FunctionField(QQ) - sage: w = K.valuation(vv) - sage: w.residue_ring() - Finite Field of size 2 - - """ - if not self.is_discrete_valuation(): - # A pseudo valuation attaining negative infinity does typically not have a function field as its residue ring - return super().residue_ring() - return self._base_valuation.residue_ring().fraction_field().function_field() - - -class FunctionFieldFromLimitValuation(FiniteExtensionFromLimitValuation, DiscreteFunctionFieldValuation_base): - r""" - A valuation on a finite extensions of function fields `L=K[y]/(G)` where `K` is - another function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - (x^2 + x + 1)) - sage: v = K.valuation(x - 1) # indirect doctest - sage: w = v.extension(L); w - (x - 1)-adic valuation - - """ - def __init__(self, parent, approximant, G, approximants): - r""" - TESTS:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - (x^2 + x + 1)) - sage: v = K.valuation(x - 1) # indirect doctest - sage: w = v.extension(L) - sage: from sage.rings.function_field.function_field_valuation import FunctionFieldFromLimitValuation - sage: isinstance(w, FunctionFieldFromLimitValuation) - True - - """ - FiniteExtensionFromLimitValuation.__init__(self, parent, approximant, G, approximants) - DiscreteFunctionFieldValuation_base.__init__(self, parent) - - def _to_base_domain(self, f): - r""" - Return ``f`` as an element of the domain of the underlying limit valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - (x^2 + x + 1)) - sage: v = K.valuation(x - 1) # indirect doctest - sage: w = v.extension(L) - sage: w._to_base_domain(y).parent() - Univariate Polynomial Ring in y over Rational function field in x over Rational Field - - """ - return f.element() - - def scale(self, scalar): - r""" - Return this valuation scaled by ``scalar``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - (x^2 + x + 1)) - sage: v = K.valuation(x - 1) # indirect doctest - sage: w = v.extension(L) - sage: 3*w - 3 * (x - 1)-adic valuation - - """ - if scalar in QQ and scalar > 0 and scalar != 1: - return self.domain().valuation(self._base_valuation._initial_approximation.scale(scalar)) - return super().scale(scalar) - - -class FunctionFieldMappedValuation_base(FunctionFieldValuation_base, MappedValuation_base): - r""" - A valuation on a function field which relies on a ``base_valuation`` on an - isomorphic function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: v = K.valuation(1/x); v - Valuation at the infinite place - - """ - def __init__(self, parent, base_valuation, to_base_valuation_domain, from_base_valuation_domain): - r""" - TESTS:: - - sage: K.<x> = FunctionField(GF(2)) - sage: v = K.valuation(1/x) - sage: from sage.rings.function_field.function_field_valuation import FunctionFieldMappedValuation_base - sage: isinstance(v, FunctionFieldMappedValuation_base) - True - - """ - FunctionFieldValuation_base.__init__(self, parent) - MappedValuation_base.__init__(self, parent, base_valuation) - - self._to_base = to_base_valuation_domain - self._from_base = from_base_valuation_domain - - def _to_base_domain(self, f): - r""" - Return ``f`` as an element in the domain of ``_base_valuation``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 + y + x^3) - sage: v = K.valuation(1/x) - sage: w = v.extension(L) - sage: w._to_base_domain(y) - x^2*y - - """ - return self._to_base(f) - - def _from_base_domain(self, f): - r""" - Return ``f`` as an element in the domain of this valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 + y + x^3) - sage: v = K.valuation(1/x) - sage: w = v.extension(L) - sage: w._from_base_domain(w._to_base_domain(y)) - y - - r""" - return self._from_base(f) - - def scale(self, scalar): - r""" - Return this valuation scaled by ``scalar``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 + y + x^3) - sage: v = K.valuation(1/x) - sage: w = v.extension(L) - sage: 3*w - 3 * (x)-adic valuation (in Rational function field in x over Finite Field of size 2 after x |--> 1/x) - - """ - from sage.rings.rational_field import QQ - if scalar in QQ and scalar > 0 and scalar != 1: - return self.domain().valuation((self._base_valuation.scale(scalar), self._to_base, self._from_base)) - return super().scale(scalar) - - def _repr_(self): - r""" - Return a printable representation of this valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 + y + x^3) - sage: v = K.valuation(1/x) - sage: v.extension(L) # indirect doctest - Valuation at the infinite place - - """ - to_base = repr(self._to_base) - if hasattr(self._to_base, '_repr_defn'): - to_base = self._to_base._repr_defn().replace('\n', ', ') - return "%r (in %r after %s)" % (self._base_valuation, self._base_valuation.domain(), to_base) - - def is_discrete_valuation(self): - r""" - Return whether this is a discrete valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^4 - 1) - sage: v = K.valuation(1/x) - sage: w0,w1 = v.extensions(L) - sage: w0.is_discrete_valuation() - True - - """ - return self._base_valuation.is_discrete_valuation() - - -class FunctionFieldMappedValuationRelative_base(FunctionFieldMappedValuation_base): - r""" - A valuation on a function field which relies on a ``base_valuation`` on an - isomorphic function field and which is such that the map from and to the - other function field is the identity on the constant field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: v = K.valuation(1/x); v - Valuation at the infinite place - - """ - def __init__(self, parent, base_valuation, to_base_valuation_domain, from_base_valuation_domain): - r""" - TESTS:: - - sage: K.<x> = FunctionField(GF(2)) - sage: v = K.valuation(1/x) - sage: from sage.rings.function_field.function_field_valuation import FunctionFieldMappedValuationRelative_base - sage: isinstance(v, FunctionFieldMappedValuationRelative_base) - True - - """ - FunctionFieldMappedValuation_base.__init__(self, parent, base_valuation, to_base_valuation_domain, from_base_valuation_domain) - if self.domain().constant_base_field() is not base_valuation.domain().constant_base_field(): - raise ValueError("constant fields must be identical but they differ for %r and %r" % (self.domain(), base_valuation.domain())) - - def restriction(self, ring): - r""" - Return the restriction of this valuation to ``ring``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: K.valuation(1/x).restriction(GF(2)) - Trivial valuation on Finite Field of size 2 - - """ - if ring.is_subring(self.domain().constant_base_field()): - return self._base_valuation.restriction(ring) - return super().restriction(ring) - - -class RationalFunctionFieldMappedValuation(FunctionFieldMappedValuationRelative_base, RationalFunctionFieldValuation_base): - r""" - Valuation on a rational function field that is implemented after a map to - an isomorphic rational function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<x> = QQ[] - sage: w = GaussValuation(R, QQ.valuation(2)).augmentation(x, 1) - sage: w = K.valuation(w) - sage: v = K.valuation((w, K.hom([~K.gen()]), K.hom([~K.gen()]))); v - Valuation on rational function field induced by [ Gauss valuation induced by 2-adic valuation, v(x) = 1 ] (in Rational function field in x over Rational Field after x |--> 1/x) - - """ - def __init__(self, parent, base_valuation, to_base_valuation_doain, from_base_valuation_domain): - r""" - TESTS:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<x> = QQ[] - sage: w = GaussValuation(R, QQ.valuation(2)).augmentation(x, 1) - sage: w = K.valuation(w) - sage: v = K.valuation((w, K.hom([~K.gen()]), K.hom([~K.gen()]))) - sage: from sage.rings.function_field.function_field_valuation import RationalFunctionFieldMappedValuation - sage: isinstance(v, RationalFunctionFieldMappedValuation) - True - - """ - FunctionFieldMappedValuationRelative_base.__init__(self, parent, base_valuation, to_base_valuation_doain, from_base_valuation_domain) - RationalFunctionFieldValuation_base.__init__(self, parent) - - -class InfiniteRationalFunctionFieldValuation(FunctionFieldMappedValuationRelative_base, RationalFunctionFieldValuation_base, ClassicalFunctionFieldValuation_base): - r""" - Valuation of the infinite place of a function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(1/x) # indirect doctest - - """ - def __init__(self, parent): - r""" - TESTS:: - - sage: K.<x> = FunctionField(QQ) - sage: v = K.valuation(1/x) # indirect doctest - sage: from sage.rings.function_field.function_field_valuation import InfiniteRationalFunctionFieldValuation - sage: isinstance(v, InfiniteRationalFunctionFieldValuation) - True - - """ - x = parent.domain().gen() - FunctionFieldMappedValuationRelative_base.__init__(self, parent, FunctionFieldValuation(parent.domain(), x), parent.domain().hom([1/x]), parent.domain().hom([1/x])) - RationalFunctionFieldValuation_base.__init__(self, parent) - ClassicalFunctionFieldValuation_base.__init__(self, parent) - - def _repr_(self): - r""" - Return a printable representation of this valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K.valuation(1/x) # indirect doctest - Valuation at the infinite place - - """ - return "Valuation at the infinite place" - - -class FunctionFieldExtensionMappedValuation(FunctionFieldMappedValuationRelative_base): - r""" - A valuation on a finite extensions of function fields `L=K[y]/(G)` where `K` is - another function field which redirects to another ``base_valuation`` on an - isomorphism function field `M=K[y]/(H)`. - - The isomorphisms must be trivial on ``K``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 + y + x^3) - sage: v = K.valuation(1/x) - sage: w = v.extension(L) - - sage: w(x) - -1 - sage: w(y) - -3/2 - sage: w.uniformizer() - 1/x^2*y - - TESTS:: - - sage: from sage.rings.function_field.function_field_valuation import FunctionFieldExtensionMappedValuation - sage: isinstance(w, FunctionFieldExtensionMappedValuation) - True - - """ - def _repr_(self): - r""" - Return a printable representation of this valuation. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 + y + x^3) - sage: v = K.valuation(1/x) - sage: w = v.extension(L); w - Valuation at the infinite place - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - 1/x^2 - 1) - sage: v = K.valuation(1/x) - sage: w = v.extensions(L); w - [[ Valuation at the infinite place, v(y + 1) = 2 ]-adic valuation, - [ Valuation at the infinite place, v(y - 1) = 2 ]-adic valuation] - - """ - assert(self.domain().base() is not self.domain()) - if repr(self._base_valuation) == repr(self.restriction(self.domain().base())): - return repr(self._base_valuation) - return super()._repr_() - - def restriction(self, ring): - r""" - Return the restriction of this valuation to ``ring``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 + y + x^3) - sage: v = K.valuation(1/x) - sage: w = v.extension(L) - sage: w.restriction(K) is v - True - """ - if ring.is_subring(self.domain().base()): - return self._base_valuation.restriction(ring) - return super().restriction(ring) diff --git a/src/sage/rings/function_field/hermite_form_polynomial.pyx b/src/sage/rings/function_field/hermite_form_polynomial.pyx index dff24054110..12881615315 100644 --- a/src/sage/rings/function_field/hermite_form_polynomial.pyx +++ b/src/sage/rings/function_field/hermite_form_polynomial.pyx @@ -42,14 +42,15 @@ AUTHORS: - Kwankyu Lee (2021-05-21): initial version """ -#***************************************************************************** + +# **************************************************************************** # Copyright (C) 2021 Kwankyu Lee <ekwankyu@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from sage.matrix.matrix cimport Matrix from sage.rings.polynomial.polynomial_element cimport Polynomial diff --git a/src/sage/rings/function_field/ideal.py b/src/sage/rings/function_field/ideal.py index 1ce0b885f56..22aa15299b1 100644 --- a/src/sage/rings/function_field/ideal.py +++ b/src/sage/rings/function_field/ideal.py @@ -26,46 +26,48 @@ Ideals in the equation order of an extension of a rational function field:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order() - sage: I = O.ideal(y); I + sage: L.<y> = K.extension(y^2 - x^3 - 1) # needs sage.rings.function_field + sage: O = L.equation_order() # needs sage.rings.function_field + sage: I = O.ideal(y); I # needs sage.rings.function_field Ideal (x^3 + 1, -y) of Order in Function field in y defined by y^2 - x^3 - 1 - sage: I^2 + sage: I^2 # needs sage.rings.function_field Ideal (x^3 + 1, (-x^3 - 1)*y) of Order in Function field in y defined by y^2 - x^3 - 1 Ideals in the maximal order of a global function field:: + sage: # needs sage.rings.finite_rings sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3*y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: I^2 + sage: L.<y> = K.extension(y^2 - x^3*y - x) # needs sage.rings.function_field + sage: O = L.maximal_order() # needs sage.rings.function_field + sage: I = O.ideal(y) # needs sage.rings.function_field + sage: I^2 # needs sage.rings.function_field Ideal (x) of Maximal order of Function field in y defined by y^2 + x^3*y + x - sage: ~I + sage: ~I # needs sage.rings.function_field Ideal (1/x*y) of Maximal order of Function field in y defined by y^2 + x^3*y + x - sage: ~I * I + sage: ~I * I # needs sage.rings.function_field Ideal (1) of Maximal order of Function field in y defined by y^2 + x^3*y + x - sage: J = O.ideal(x+y) * I - sage: J.factor() + sage: J = O.ideal(x + y) * I # needs sage.rings.finite_rings sage.rings.function_field + sage: J.factor() # needs sage.rings.finite_rings sage.rings.function_field (Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x)^2 * (Ideal (x^3 + x + 1, y + x) of Maximal order of Function field in y defined by y^2 + x^3*y + x) Ideals in the maximal infinite order of a global function field:: + sage: # needs sage.rings.finite_rings sage: K.<x> = FunctionField(GF(3^2)); R.<t> = K[] - sage: F.<y> = K.extension(t^3 + t^2 - x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/y) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) # needs sage.rings.function_field + sage: Oinf = F.maximal_order_infinite() # needs sage.rings.function_field + sage: I = Oinf.ideal(1/y) # needs sage.rings.function_field sage: I + I == I True - sage: I^2 + sage: I^2 # needs sage.rings.function_field Ideal (1/x^4*y) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 - sage: ~I + sage: ~I # needs sage.rings.function_field Ideal (y) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 - sage: ~I * I + sage: ~I * I # needs sage.rings.function_field Ideal (1) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 - sage: I.factor() + sage: I.factor() # needs sage.rings.function_field (Ideal (1/x^3*y^2) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4)^4 AUTHORS: @@ -77,43 +79,31 @@ - Kwankyu Lee (2017-04-30): added ideals for global function fields """ + # **************************************************************************** -# Copyright (C) 2010 William Stein <wstein@gmail.com> -# Copyright (C) 2011 Maarten Derickx <m.derickx.student@gmail.com> +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2017-2021 Kwankyu Lee +# 2018 Frรฉdรฉric Chapoton +# 2019 Brent Baccala +# 2021 Jonathan Kliem # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -import itertools -from sage.misc.cachefunc import cached_method -from sage.misc.lazy_attribute import lazy_attribute from sage.misc.latex import latex -from sage.misc.misc import powerset - +from sage.combinat.subset import powerset from sage.structure.parent import Parent from sage.structure.element import Element from sage.structure.richcmp import richcmp from sage.structure.factorization import Factorization from sage.structure.unique_representation import UniqueRepresentation - -from sage.arith.power import generic_power - -from sage.modules.free_module_element import vector - from sage.categories.monoids import Monoids - -from sage.rings.infinity import infinity from sage.rings.ideal import Ideal_generic -from sage.matrix.constructor import matrix - -from .divisor import divisor - -from .hermite_form_polynomial import reversed_hermite_form - class FunctionFieldIdeal(Element): """ @@ -127,7 +117,7 @@ class FunctionFieldIdeal(Element): sage: K.<x> = FunctionField(GF(7)) sage: O = K.equation_order() - sage: O.ideal(x^3+1) + sage: O.ideal(x^3 + 1) Ideal (x^3 + 1) of Maximal order of Rational function field in x over Finite Field of size 7 """ def __init__(self, ring): @@ -136,9 +126,10 @@ def __init__(self, ring): TESTS:: + sage: # needs sage.rings.finite_rings sage: K.<x> = FunctionField(GF(7)) sage: O = K.equation_order() - sage: I = O.ideal(x^3+1) + sage: I = O.ideal(x^3 + 1) sage: TestSuite(I).run() """ Element.__init__(self, ring.ideal_monoid()) @@ -151,11 +142,12 @@ def _repr_short(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<x> = FunctionField(GF(3^2)); R.<t> = K[] - sage: F.<y> = K.extension(t^3 + t^2 - x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/y) - sage: I._repr_short() + sage: F.<y> = K.extension(t^3 + t^2 - x^4) # needs sage.rings.function_field + sage: Oinf = F.maximal_order_infinite() # needs sage.rings.function_field + sage: I = Oinf.ideal(1/y) # needs sage.rings.function_field + sage: I._repr_short() # needs sage.rings.function_field '(1/x^4*y^2)' """ if self.is_zero(): @@ -171,21 +163,24 @@ def _repr_(self): sage: K.<x> = FunctionField(QQ) sage: O = K.maximal_order() - sage: I = O.ideal(x,1/(x+1)); I + sage: I = O.ideal(x, 1/(x+1)); I Ideal (1/(x + 1)) of Maximal order of Rational function field in x over Rational Field + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() sage: O.ideal(x^2 + 1) Ideal (x^2 + 1) of Order in Function field in y defined by y^2 - x^3 - 1 + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 - x^3*Y - x) sage: O = L.maximal_order() sage: I = O.ideal(y); I Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x + sage: # needs sage.rings.function_field sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() sage: I = O.ideal(y); I @@ -199,6 +194,7 @@ def _repr_(self): Ideal (1/x) of Maximal infinite order of Rational function field in x over Finite Field of size 2 + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) sage: F.<y> = K.extension(t^3 + t^2 - x^4) sage: Oinf = F.maximal_order_infinite() @@ -206,6 +202,7 @@ def _repr_(self): Ideal (1/x^4*y^2) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: Oinf = L.maximal_order_infinite() @@ -224,6 +221,7 @@ def _latex_(self): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 - x^3*Y - x) sage: O = L.maximal_order() @@ -245,7 +243,7 @@ def _div_(self, other): sage: K.<x> = FunctionField(GF(7)) sage: O = K.equation_order() - sage: I = O.ideal(x^3+1) + sage: I = O.ideal(x^3 + 1) sage: I / I Ideal (1) of Maximal order of Rational function field in x over Finite Field of size 7 @@ -269,7 +267,7 @@ def gens_reduced(self): sage: K.<x> = FunctionField(GF(7)) sage: O = K.equation_order() - sage: I = O.ideal(x,x^2,x^2+x) + sage: I = O.ideal(x, x^2, x^2 + x) sage: I.gens_reduced() (x,) """ @@ -291,7 +289,7 @@ def ring(self): sage: K.<x> = FunctionField(GF(7)) sage: O = K.equation_order() - sage: I = O.ideal(x,x^2,x^2+x) + sage: I = O.ideal(x, x^2, x^2 + x) sage: I.ring() Maximal order of Rational function field in x over Finite Field of size 7 """ @@ -303,6 +301,7 @@ def base_ring(self): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -318,6 +317,7 @@ def place(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<x> = FunctionField(GF(4)) sage: O = K.maximal_order() sage: I = O.ideal(x^2 + x + 1) @@ -325,7 +325,7 @@ def place(self): Traceback (most recent call last): ... TypeError: not a prime ideal - sage: I = O.ideal(x^3+x+1) + sage: I = O.ideal(x^3 + x + 1) sage: I.place() Place (x^3 + x + 1) @@ -336,14 +336,16 @@ def place(self): sage: p.place() Place (1/x) + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) sage: O = F.maximal_order() sage: I = O.ideal(y) sage: [f.place() for f,_ in I.factor()] [Place (x, (1/(x^3 + x^2 + x))*y^2), Place (x^2 + x + 1, (1/(x^3 + x^2 + x))*y^2)] + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() @@ -351,6 +353,7 @@ def place(self): sage: [f.place() for f,_ in I.factor()] [Place (x, x*y), Place (x + 1, x*y)] + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) sage: F.<y> = K.extension(t^3 + t^2 - x^4) sage: Oinf = F.maximal_order_infinite() @@ -364,6 +367,7 @@ def place(self): sage: J.place() Place (1/x, 1/x^3*y^2) + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: Oinf = L.maximal_order_infinite() @@ -392,6 +396,7 @@ def factor(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<x> = FunctionField(GF(4)) sage: O = K.maximal_order() sage: I = O.ideal(x^3*(x + 1)^2) @@ -401,12 +406,14 @@ def factor(self): (Ideal (x + 1) of Maximal order of Rational function field in x over Finite Field in z2 of size 2^2)^2 + sage: # needs sage.rings.finite_rings sage: Oinf = K.maximal_order_infinite() sage: I = Oinf.ideal((x + 1)/(x^3 + 1)) sage: I.factor() (Ideal (1/x) of Maximal infinite order of Rational function field in x over Finite Field in z2 of size 2^2)^2 + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<T> = PolynomialRing(K) sage: F.<y> = K.extension(T^3 - x^2*(x^2 + x + 1)^2) sage: O = F.maximal_order() @@ -414,6 +421,7 @@ def factor(self): sage: I == I.factor().prod() True + sage: # needs sage.rings.function_field sage: Oinf = F.maximal_order_infinite() sage: f= 1/x sage: I = Oinf.ideal(f) @@ -423,6 +431,7 @@ def factor(self): (Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1) of Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2) + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); _.<Y> = K[] sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) sage: O = F.maximal_order() @@ -430,6 +439,7 @@ def factor(self): sage: I == I.factor().prod() True + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() @@ -446,17 +456,20 @@ def divisor(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<x> = FunctionField(GF(4)) sage: O = K.maximal_order() sage: I = O.ideal(x*(x + 1)^2/(x^2 + x + 1)) sage: I.divisor() Place (x) + 2*Place (x + 1) - Place (x + z2) - Place (x + z2 + 1) + sage: # needs sage.rings.finite_rings sage: Oinf = K.maximal_order_infinite() sage: I = Oinf.ideal((x + 1)/(x^3 + 1)) sage: I.divisor() 2*Place (1/x) + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<T> = PolynomialRing(K) sage: F.<y> = K.extension(T^3 - x^2*(x^2 + x + 1)^2) sage: O = F.maximal_order() @@ -465,12 +478,14 @@ def divisor(self): 2*Place (x, (1/(x^3 + x^2 + x))*y^2) + 2*Place (x^2 + x + 1, (1/(x^3 + x^2 + x))*y^2) + sage: # needs sage.rings.function_field sage: Oinf = F.maximal_order_infinite() sage: I = Oinf.ideal(y) sage: I.divisor() -2*Place (1/x, 1/x^4*y^2 + 1/x^2*y + 1) - 2*Place (1/x, 1/x^2*y + 1) + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() @@ -479,11 +494,14 @@ def divisor(self): - Place (x, x*y) + 2*Place (x + 1, x*y) + sage: # needs sage.rings.function_field sage: Oinf = L.maximal_order_infinite() sage: I = Oinf.ideal(y) sage: I.divisor() - Place (1/x, 1/x*y) """ + from .divisor import divisor + if self.is_zero(): raise ValueError("not defined for zero ideal") @@ -497,18 +515,21 @@ def divisor_of_zeros(self): EXAMPLES:: + sage: # needs sage.modules sage.rings.finite_rings sage: K.<x> = FunctionField(GF(4)) sage: O = K.maximal_order() sage: I = O.ideal(x*(x + 1)^2/(x^2 + x + 1)) sage: I.divisor_of_zeros() Place (x) + 2*Place (x + 1) + sage: # needs sage.modules sage: K.<x> = FunctionField(GF(2)) sage: Oinf = K.maximal_order_infinite() sage: I = Oinf.ideal((x + 1)/(x^3 + 1)) sage: I.divisor_of_zeros() 2*Place (1/x) + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() @@ -516,6 +537,8 @@ def divisor_of_zeros(self): sage: I.divisor_of_zeros() 2*Place (x + 1, x*y) """ + from .divisor import divisor + if self.is_zero(): raise ValueError("not defined for zero ideal") @@ -529,18 +552,21 @@ def divisor_of_poles(self): EXAMPLES:: + sage: # needs sage.modules sage.rings.finite_rings sage: K.<x> = FunctionField(GF(4)) sage: O = K.maximal_order() sage: I = O.ideal(x*(x + 1)^2/(x^2 + x + 1)) sage: I.divisor_of_poles() Place (x + z2) + Place (x + z2 + 1) + sage: # needs sage.modules sage: K.<x> = FunctionField(GF(2)) sage: Oinf = K.maximal_order_infinite() sage: I = Oinf.ideal((x + 1)/(x^3 + 1)) sage: I.divisor_of_poles() 0 + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() @@ -548,6 +574,8 @@ def divisor_of_poles(self): sage: I.divisor_of_poles() Place (x, x*y) """ + from .divisor import divisor + if self.is_zero(): raise ValueError("not defined for zero ideal") @@ -556,329 +584,6 @@ def divisor_of_poles(self): return divisor(F, data) -class FunctionFieldIdeal_rational(FunctionFieldIdeal): - """ - Fractional ideals of the maximal order of a rational function field. - - INPUT: - - - ``ring`` -- the maximal order of the rational function field. - - - ``gen`` -- generator of the ideal, an element of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal(1/(x^2+x)); I - Ideal (1/(x^2 + x)) of Maximal order of Rational function field in x over Rational Field - """ - def __init__(self, ring, gen): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal(1/(x^2+x)) - sage: TestSuite(I).run() - """ - FunctionFieldIdeal.__init__(self, ring) - self._gen = gen - - def __hash__(self): - """ - Return the hash computed from the data. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal(1/(x^2+x)) - sage: d = { I: 1, I^2: 2 } - """ - return hash( (self._ring, self._gen) ) - - def __contains__(self, element): - """ - Test if ``element`` is in this ideal. - - INPUT: - - - ``element`` -- element of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal(1/(x+1)) - sage: x in I - True - """ - return (element / self._gen) in self._ring - - def _richcmp_(self, other, op): - """ - Compare the element with the other element with respect - to the comparison operator. - - INPUT: - - - ``other`` -- element - - - ``op`` -- comparison operator - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal(x,x^2+1) - sage: J = O.ideal(x^2+x+1,x) - sage: I == J - True - sage: I = O.ideal(x) - sage: J = O.ideal(x+1) - sage: I < J - True - """ - return richcmp(self._gen, other._gen, op) - - def _add_(self, other): - """ - Add this ideal with the ``other`` ideal. - - INPUT: - - - ``other`` -- ideal - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal(x,x^2+1) - sage: J = O.ideal(x^2+x+1,x) - sage: I + J == J + I - True - """ - return self._ring.ideal([self._gen, other._gen]) - - def _mul_(self, other): - """ - Multiply this ideal with the ``other`` ideal. - - INPUT: - - - ``other`` -- ideal - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal(x,x^2+x) - sage: J = O.ideal(x^2,x) - sage: I * J == J * I - True - """ - return self._ring.ideal([self._gen * other._gen]) - - def _acted_upon_(self, other, on_left): - """ - Multiply ``other`` with this ideal on the right. - - INPUT: - - - ``other`` -- ideal - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal(x^3+x^2) - sage: 2 * I - Ideal (x^3 + x^2) of Maximal order of Rational function field in x over Rational Field - sage: x * I - Ideal (x^4 + x^3) of Maximal order of Rational function field in x over Rational Field - """ - return self._ring.ideal([other * self._gen]) - - def __invert__(self): - """ - Return the ideal inverse of this fractional ideal. - - EXAMPLES:: - - sage: F.<x> = FunctionField(QQ) - sage: O = F.maximal_order() - sage: I = O.ideal(x/(x^2+1)) - sage: ~I - Ideal ((x^2 + 1)/x) of Maximal order of Rational function field - in x over Rational Field - """ - return self._ring.ideal([~(self._gen)]) - - def denominator(self): - """ - Return the denominator of this fractional ideal. - - EXAMPLES:: - - sage: F.<x> = FunctionField(QQ) - sage: O = F.maximal_order() - sage: I = O.ideal(x/(x^2+1)) - sage: I.denominator() - x^2 + 1 - """ - return self._gen.denominator() - - def is_prime(self): - """ - Return ``True`` if this is a prime ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal(x^3+x^2) - sage: [f.is_prime() for f,m in I.factor()] - [True, True] - """ - return self._gen.denominator() == 1 and self._gen.numerator().is_prime() - - @cached_method - def module(self): - """ - Return the module, that is the ideal viewed as a module over the ring. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal(x^3+x^2) - sage: I.module() - Free module of degree 1 and rank 1 over Maximal order of Rational - function field in x over Rational Field - Echelon basis matrix: - [x^3 + x^2] - sage: J = 0*I - sage: J.module() - Free module of degree 1 and rank 0 over Maximal order of Rational - function field in x over Rational Field - Echelon basis matrix: - [] - """ - V, fr, to = self.ring().fraction_field().vector_space() - return V.span([to(g) for g in self.gens()], base_ring=self.ring()) - - def gen(self): - """ - Return the unique generator of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(4)) - sage: O = K.maximal_order() - sage: I = O.ideal(x^2+x) - sage: I.gen() - x^2 + x - """ - return self._gen - - def gens(self): - """ - Return the tuple of the unique generator of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(4)) - sage: O = K.maximal_order() - sage: I = O.ideal(x^2+x) - sage: I.gens() - (x^2 + x,) - """ - return (self._gen,) - - def gens_over_base(self): - """ - Return the generator of this ideal as a rank one module over the maximal - order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(4)) - sage: O = K.maximal_order() - sage: I = O.ideal(x^2+x) - sage: I.gens_over_base() - (x^2 + x,) - """ - return (self._gen,) - - def valuation(self, ideal): - """ - Return the valuation of the ideal at this prime ideal. - - INPUT: - - - ``ideal`` -- fractional ideal - - EXAMPLES:: - - sage: F.<x> = FunctionField(QQ) - sage: O = F.maximal_order() - sage: I = O.ideal(x^2*(x^2+x+1)^3) - sage: [f.valuation(I) for f,_ in I.factor()] - [2, 3] - """ - if not self.is_prime(): - raise TypeError("not a prime ideal") - - O = self.ring() - d = ideal.denominator() - return self._valuation(d*ideal) - self._valuation(O.ideal(d)) - - def _valuation(self, ideal): - """ - Return the valuation of the integral ideal at this prime ideal. - - INPUT: - - - ``ideal`` -- ideal - - EXAMPLES:: - - sage: F.<x> = FunctionField(QQ) - sage: O = F.maximal_order() - sage: p = O.ideal(x) - sage: p.valuation(O.ideal(x+1)) # indirect doctest - 0 - sage: p.valuation(O.ideal(x^2)) # indirect doctest - 2 - sage: p.valuation(O.ideal(1/x^3)) # indirect doctest - -3 - sage: p.valuation(O.ideal(0)) # indirect doctest - +Infinity - """ - return ideal.gen().valuation(self.gen()) - - def _factor(self): - """ - Return the list of prime and multiplicity pairs of the - factorization of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(4)) - sage: O = K.maximal_order() - sage: I = O.ideal(x^3*(x+1)^2) - sage: I.factor() # indirect doctest - (Ideal (x) of Maximal order of Rational function field in x - over Finite Field in z2 of size 2^2)^3 * - (Ideal (x + 1) of Maximal order of Rational function field in x - over Finite Field in z2 of size 2^2)^2 - """ - return [(self.ring().ideal(f), m) for f, m in self._gen.factor()] - - class FunctionFieldIdeal_module(FunctionFieldIdeal, Ideal_generic): """ A fractional ideal specified by a finitely generated module over @@ -894,6 +599,7 @@ class FunctionFieldIdeal_module(FunctionFieldIdeal, Ideal_generic): An ideal in an extension of a rational function field:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -909,6 +615,7 @@ def __init__(self, ring, module): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -932,6 +639,7 @@ def __contains__(self, x): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -952,6 +660,7 @@ def __hash__(self): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -966,6 +675,7 @@ def _richcmp_(self, other, op): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -997,6 +707,7 @@ def module(self): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order(); O @@ -1022,6 +733,7 @@ def gens(self): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -1037,6 +749,7 @@ def gen(self, i): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -1052,6 +765,7 @@ def ngens(self): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -1067,6 +781,7 @@ def _add_(self, other): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -1083,6 +798,7 @@ def _mul_(self, other): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -1099,6 +815,7 @@ def _acted_upon_(self, other, on_left): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -1114,6 +831,7 @@ def intersection(self, other): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -1144,6 +862,7 @@ def __invert__(self): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() @@ -1170,2083 +889,158 @@ def __invert__(self): return inv -class FunctionFieldIdeal_polymod(FunctionFieldIdeal): +class FunctionFieldIdealInfinite(FunctionFieldIdeal): + """ + Base class of ideals of maximal infinite orders """ - Fractional ideals of algebraic function fields + pass - INPUT: - - ``ring`` -- order in a function field +class FunctionFieldIdealInfinite_module(FunctionFieldIdealInfinite, Ideal_generic): + """ + A fractional ideal specified by a finitely generated module over + the integers of the base field. - - ``hnf`` -- matrix in hermite normal form + INPUT: - - ``denominator`` -- denominator + - ``ring`` -- order in a function field - The rows of ``hnf`` is a basis of the ideal, which itself is - ``denominator`` times the fractional ideal. + - ``module`` -- module EXAMPLES:: - sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3*y - x) - sage: O = L.maximal_order() + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.equation_order() sage: O.ideal(y) - Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x + Ideal (x^3 + 1, -y) of Order in Function field in y defined by y^2 - x^3 - 1 """ - def __init__(self, ring, hnf, denominator=1): + def __init__(self, ring, module): """ Initialize. TESTS:: - sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3*y - x) - sage: O = L.maximal_order() + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.equation_order() sage: I = O.ideal(y) sage: TestSuite(I).run() """ - FunctionFieldIdeal.__init__(self, ring) - - # the denominator and the entries of the hnf are - # univariate polynomials. - self._hnf = hnf - self._denominator = denominator + FunctionFieldIdealInfinite.__init__(self, ring) - # for prime ideals - self._relative_degree = None - self._ramification_index = None - self._prime_below = None - self._beta = None + self._module = module + self._structure = ring.fraction_field().vector_space() - # beta in matrix form for fast multiplication - self._beta_matrix = None + V, from_V, to_V = self._structure + gens = tuple([from_V(a) for a in module.basis()]) + self._gens = gens - # (p, q) with irreducible polynomial p and q an element of O in vector - # form, together generating the prime ideal. This data is obtained by - # Kummer's theorem when this prime ideal is constructed. This is used - # for fast multiplication with other ideal. - self._kummer_form = None - - # tuple of at most two gens: - # the first gen is an element of the base ring of the maximal order - # the second gen is the vector form of an element of the maximal order - # if the second gen is zero, the tuple has only the first gen. - self._gens_two_vecs = None - - def __bool__(self): - """ - Test if this ideal is zero. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3*y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(y); I - Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x - sage: I.is_zero() - False - sage: J = 0*I; J - Zero ideal of Maximal order of Function field in y defined by y^2 + x^3*y + x - sage: J.is_zero() - True - - sage: K.<x>=FunctionField(GF(2)); _.<Y>=K[] - sage: L.<y>=K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(y); I - Ideal (y) of Maximal order of Function field in y - defined by y^2 + y + (x^2 + 1)/x - sage: I.is_zero() - False - sage: J = 0*I; J - Zero ideal of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x - sage: J.is_zero() - True - """ - return self._hnf.nrows() != 0 - - - - def __hash__(self): - """ - Return the hash of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3*Y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(1/y) - sage: { I: 2 }[I] == 2 - True - - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(1/y) - sage: { I: 2 }[I] == 2 - True - """ - return hash((self._ring, self._hnf, self._denominator)) + # module generators are still ideal generators + Ideal_generic.__init__(self, ring, self._gens, coerce=False) def __contains__(self, x): """ Return ``True`` if ``x`` is in this ideal. - EXAMPLES:: + INPUT: - sage: K.<x> = FunctionField(GF(7)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3 - 1) - sage: O = L.maximal_order() - sage: I = O.ideal([y]); I - Ideal (y) of Maximal order of Function field in y - defined by y^2 + 6*x^3 + 6 - sage: x * y in I - True - sage: y / x in I - False - sage: y^2 - 2 in I - False + - ``x`` -- element of the function field - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal([y]); I - Ideal (y) of Maximal order of Function field in y - defined by y^2 + y + (x^2 + 1)/x - sage: x * y in I - True - sage: y / x in I - False - sage: y^2 - 2 in I - False + EXAMPLES:: - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3 - 1) - sage: O = L.maximal_order() - sage: I = O.ideal([y]); I - Ideal (y) of Maximal order of Function field in y - defined by y^2 - x^3 - 1 - sage: x * y in I + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.equation_order() + sage: I = O.ideal_with_gens_over_base([1, y]); I + Ideal (1) of Order in Function field in y defined by y^2 + 6*x^3 + 6 + sage: y in I True - sage: y / x in I + sage: y/x in I False sage: y^2 - 2 in I - False - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal([y]); I - Ideal (y) of Maximal order of Function field in y - defined by y^2 + y + (x^2 + 1)/x - sage: x * y in I True - sage: y / x in I - False - sage: y^2 - 2 in I - False """ - vec = self.ring().coordinate_vector(self._denominator * x) - v = [] - for e in vec: - if e.denominator() != 1: - return False - v.append(e.numerator()) - vec = vector(v) - return vec in self._hnf.image() + return self._structure[2](x) in self._module - def __invert__(self): + def __hash__(self): """ - Return the inverse fractional ideal of this ideal. + Return the hash of this ideal EXAMPLES:: - sage: K.<x> = FunctionField(GF(7)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3 - 1) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: ~I - Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 - sage: I^(-1) - Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 - sage: ~I * I - Ideal (1) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 - - :: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: ~I - Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order - of Function field in y defined by y^2 + y + (x^2 + 1)/x - sage: I^(-1) - Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order - of Function field in y defined by y^2 + y + (x^2 + 1)/x - sage: ~I * I - Ideal (1) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x - - :: - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3 - 1) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: ~I - Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 - x^3 - 1 - sage: I^(-1) - Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 - x^3 - 1 - sage: ~I * I - Ideal (1) of Maximal order of Function field in y defined by y^2 - x^3 - 1 - - :: - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: ~I - Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order - of Function field in y defined by y^2 + y + (x^2 + 1)/x - sage: I^(-1) - Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order - of Function field in y defined by y^2 + y + (x^2 + 1)/x - sage: ~I * I - Ideal (1) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.equation_order() + sage: I = O.ideal_with_gens_over_base([1, y]) + sage: d = {I: 2} # indirect doctest """ - R = self.ring() - T = R._codifferent_matrix() - I = self * R.codifferent() - J = I._denominator * (I._hnf * T).inverse() - return R._ideal_from_vectors(J.columns()) + return hash((self._ring,self._module)) - def _richcmp_(self, other, op): + def __eq__(self, other): """ - Compare this ideal with the other ideal with respect to ``op``. + Test equality of this ideal with the ``other`` ideal. INPUT: - ``other`` -- ideal - - ``op`` -- comparison operator - EXAMPLES:: - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3*Y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(1/y) - sage: I == I + I - True - sage: I == I * I - False - - :: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(1/y) - sage: I == I + I - True - sage: I == I * I - False - sage: I < I * I + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.equation_order() + sage: I = O.ideal_with_gens_over_base([1, y]) + sage: I == I + I # indirect doctest True - sage: I > I * I - False - """ - return richcmp((self._denominator, self._hnf), (other._denominator, other._hnf), op) - - def _add_(self, other): - """ - Add with other ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3*Y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: J = O.ideal(x+y) - sage: I + J - Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x - - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: J = O.ideal(x+y) - sage: I + J - Ideal (1, y) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x """ - ds = self._denominator - do = other._denominator - vecs1 = [do * r for r in self._hnf] - vecs2 = [ds * r for r in other._hnf] - return self._ring._ideal_from_vectors_and_denominator(vecs1 + vecs2, ds * do) - - def _mul_(self, other): - """ - Multiply with other ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3*Y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: J = O.ideal(x+y) - sage: I * J - Ideal (x^4 + x^2 + x, x*y + x^2) of Maximal order - of Function field in y defined by y^2 + x^3*y + x + if not isinstance(other, FunctionFieldIdeal_module): + other = self.ring().ideal(other) + if self.ring() != other.ring(): + raise ValueError("rings must be the same") - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: J = O.ideal(x+y) - sage: I * J - Ideal ((x + 1)*y + (x^2 + 1)/x) of Maximal order - of Function field in y defined by y^2 + y + (x^2 + 1)/x - """ - O = self._ring - mul = O._mul_vecs - - if self._kummer_form is not None: - p, q = self._kummer_form - vecs = list(p * other._hnf) + [mul(q, v) for v in other._hnf] - elif other._kummer_form is not None: - p, q = other._kummer_form - vecs = list(p * self._hnf) + [mul(q, v) for v in self._hnf] - elif self._gens_two_vecs is not None: - if len(self._gens_two_vecs) == 1: - g1, = self._gens_two_vecs - vecs = list(g1 * other._hnf) - else: - g1, g2 = self._gens_two_vecs - vecs = list(g1 * other._hnf) + [mul(g2, v) for v in other._hnf] - elif other._gens_two_vecs is not None: - if len(other._gens_two_vecs) == 1: - g1, = other._gens_two_vecs - vecs = list(g1 * self._hnf) - else: - g1, g2 = other._gens_two_vecs - vecs = list(g1 * self._hnf) + [mul(g2, v) for v in self._hnf] + if (self.module().is_submodule(other.module()) and + other.module().is_submodule(self.module())): + return True else: - vecs = [mul(r1,r2) for r1 in self._hnf for r2 in other._hnf] - - return O._ideal_from_vectors_and_denominator(vecs, self._denominator * other._denominator) - - def _acted_upon_(self, other, on_left): - """ - Multiply ``other`` and this ideal on the right. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3*Y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(x+y) - sage: J = O.ideal(x) - sage: x * I == I * J - True - - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(x+y) - sage: J = O.ideal(x) - sage: x * I == I * J - True - """ - O = self._ring - mul = O._mul_vecs - - # compute the vector form of other element - v = O.coordinate_vector(other) - d = v.denominator() - vec = vector([(d * c).numerator() for c in v]) - - # multiply with the ideal - vecs = [mul(vec, r) for r in self._hnf] - - return O._ideal_from_vectors_and_denominator(vecs, d * self._denominator) + return False - def intersect(self, other): + def module(self): """ - Intersect this ideal with the other ideal as fractional ideals. - - INPUT: + Return the module over the maximal order of the base field that + underlies this ideal. - - ``other`` -- ideal + The formation of the module is compatible with the vector + space corresponding to the function field. EXAMPLES:: - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3*Y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(x+y) - sage: J = O.ideal(x) - sage: I.intersect(J) == I * J * (I + J)^-1 + sage: K.<x> = FunctionField(GF(7)) + sage: O = K.maximal_order(); O + Maximal order of Rational function field in x over Finite Field of size 7 + sage: K.polynomial_ring() + Univariate Polynomial Ring in x over + Rational function field in x over Finite Field of size 7 + sage: I = O.ideal([x^2 + 1, x*(x^2+1)]) + sage: I.gens() + (x^2 + 1,) + sage: I.module() # needs sage.modules + Free module of degree 1 and rank 1 over + Maximal order of Rational function field in x over Finite Field of size 7 + Echelon basis matrix: + [x^2 + 1] + sage: V, from_V, to_V = K.vector_space(); V # needs sage.modules + Vector space of dimension 1 over + Rational function field in x over Finite Field of size 7 + sage: I.module().is_submodule(V) # needs sage.modules True - - """ - from sage.matrix.special import block_matrix - - A = self._hnf - B = other._hnf - - ds = self.denominator() - do = other.denominator() - d = ds.lcm(do) - if not d.is_one(): - A = (d // ds) * A - B = (d // do) * B - - MS = A.matrix_space() - I = MS.identity_matrix() - O = MS.zero() - n = A.ncols() - - # intersect the row spaces of A and B - M = block_matrix([[I,I],[A,O],[O,B]]) - - # reversed Hermite form - U = reversed_hermite_form(M, transformation=True) - - vecs = [U[i][:n] for i in range(n)] - - return self._ring._ideal_from_vectors_and_denominator(vecs, d) - - def hnf(self): - """ - Return the matrix in hermite normal form representing this ideal. - - See also :meth:`denominator` - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.maximal_order() - sage: I = O.ideal(y*(y+1)); I.hnf() - [x^6 + x^3 0] - [ x^3 + 1 1] - - :: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.maximal_order() - sage: I = O.ideal(y*(y+1)); I.hnf() - [x^6 + x^3 0] - [ x^3 + 1 1] - """ - return self._hnf - - def denominator(self): """ - Return the denominator of this fractional ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.maximal_order() - sage: I = O.ideal(y/(y+1)) - sage: d = I.denominator(); d - x^3 - sage: d in O - True - - :: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.maximal_order() - sage: I = O.ideal(y/(y+1)) - sage: d = I.denominator(); d - x^3 - sage: d in O - True - """ - return self._denominator - - @cached_method - def module(self): - """ - Return the module, that is the ideal viewed as a module - over the base maximal order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: F.<y> = K.extension(y^2 - x^3 - 1) - sage: O = F.maximal_order() - sage: I = O.ideal(x,1/y) - sage: I.module() - Free module of degree 2 and rank 2 over Maximal order - of Rational function field in x over Finite Field of size 7 - Echelon basis matrix: - [ 1 0] - [ 0 1/(x^3 + 1)] - """ - F = self.ring().fraction_field() - V, fr, to = F.vector_space() - O = F.base_field().maximal_order() - return V.span([to(g) for g in self.gens_over_base()], base_ring=O) - - @cached_method - def gens_over_base(self): - """ - Return the generators of this ideal as a module over the maximal order - of the base rational function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3*Y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(x+y) - sage: I.gens_over_base() - (x^4 + x^2 + x, y + x) - - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(x+y) - sage: I.gens_over_base() - (x^3 + 1, y + x) - """ - gens, d = self._gens_over_base - return tuple([~d * b for b in gens]) - - @lazy_attribute - def _gens_over_base(self): - """ - Return the generators of the integral ideal, which is the denominator - times the fractional ideal, together with the denominator. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3*y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(1/y) - sage: I._gens_over_base - ([x, y], x) - """ - gens = [] - for row in self._hnf: - gens.append(sum([c1*c2 for c1,c2 in zip(row, self._ring.basis())])) - return gens, self._denominator - - def gens(self): - """ - Return a set of generators of this ideal. - - This provides whatever set of generators as quickly - as possible. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3*Y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(x+y) - sage: I.gens() - (x^4 + x^2 + x, y + x) - - sage: L.<y> = K.extension(Y^2 +Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(x+y) - sage: I.gens() - (x^3 + 1, y + x) - """ - return self.gens_over_base() - - @cached_method - def basis_matrix(self): - """ - Return the matrix of basis vectors of this ideal as a module. - - The basis matrix is by definition the hermite norm form of the ideal - divided by the denominator. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(x,1/y) - sage: I.denominator() * I.basis_matrix() == I.hnf() - True - """ - d = self.denominator() - m = (d * self).hnf() - if d != 1: - m = ~d * m - m.set_immutable() - return m - - def is_integral(self): - """ - Return ``True`` if this is an integral ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(x,1/y) - sage: I.is_integral() - False - sage: J = I.denominator() * I - sage: J.is_integral() - True - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(x,1/y) - sage: I.is_integral() - False - sage: J = I.denominator() * I - sage: J.is_integral() - True - - sage: K.<x> = FunctionField(QQ); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(x,1/y) - sage: I.is_integral() - False - sage: J = I.denominator() * I - sage: J.is_integral() - True - """ - return self.denominator() == 1 - - def ideal_below(self): - """ - Return the ideal below this ideal. - - This is defined only for integral ideals. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(x,1/y) - sage: I.ideal_below() - Traceback (most recent call last): - ... - TypeError: not an integral ideal - sage: J = I.denominator() * I - sage: J.ideal_below() - Ideal (x^3 + x^2 + x) of Maximal order of Rational function field - in x over Finite Field of size 2 - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(x,1/y) - sage: I.ideal_below() - Traceback (most recent call last): - ... - TypeError: not an integral ideal - sage: J = I.denominator() * I - sage: J.ideal_below() - Ideal (x^3 + x) of Maximal order of Rational function field - in x over Finite Field of size 2 - - sage: K.<x> = FunctionField(QQ); _.<t> = K[] - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(x,1/y) - sage: I.ideal_below() - Traceback (most recent call last): - ... - TypeError: not an integral ideal - sage: J = I.denominator() * I - sage: J.ideal_below() - Ideal (x^3 + x^2 + x) of Maximal order of Rational function field - in x over Rational Field - """ - if not self.is_integral(): - raise TypeError("not an integral ideal") - - K = self.ring().fraction_field().base_field().maximal_order() - - # self._hnf is in reversed hermite normal form, that is, lower - # triangular form. Thus the generator of the ideal below is - # just the (0,0) entry of the normal form. When self._hnf was in - # hermite normal form, that is, upper triangular form, then the - # generator can be computed in the following way: - # - # m = matrix([hnf[0].parent().gen(0)] + list(hnf)) - # _,T = m.hermite_form(transformation=True) - # return T[-1][0] - # - # This is certainly less efficient! This is an argument for using - # reversed hermite normal form for ideal representation. - l = self._hnf[0][0] - - return K.ideal(l) - - def norm(self): - """ - Return the norm of this fractional ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order() - sage: i1 = O.ideal(x) - sage: i2 = O.ideal(y) - sage: i3 = i1 * i2 - sage: i3.norm() == i1.norm() * i2.norm() - True - sage: i1.norm() - x^3 - sage: i1.norm() == x ** F.degree() - True - sage: i2.norm() - x^6 + x^4 + x^2 - sage: i2.norm() == y.norm() - True - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: i1 = O.ideal(x) - sage: i2 = O.ideal(y) - sage: i3 = i1 * i2 - sage: i3.norm() == i1.norm() * i2.norm() - True - sage: i1.norm() - x^2 - sage: i1.norm() == x ** L.degree() - True - sage: i2.norm() - (x^2 + 1)/x - sage: i2.norm() == y.norm() - True - """ - n = 1 - for e in self.basis_matrix().diagonal(): - n *= e - return n - - @cached_method - def is_prime(self): - """ - Return ``True`` if this ideal is a prime ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(y) - sage: [f.is_prime() for f,_ in I.factor()] - [True, True] - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: [f.is_prime() for f,_ in I.factor()] - [True, True] - - sage: K.<x> = FunctionField(QQ); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(y) - sage: [f.is_prime() for f,_ in I.factor()] - [True, True] - """ - factors = self.factor() - if len(factors) == 1 and factors[0][1] == 1: # prime! - prime = factors[0][0] - assert self == prime - self._relative_degree = prime._relative_degree - self._ramification_index = prime._ramification_index - self._prime_below = prime._prime_below - self._beta = prime._beta - self._beta_matrix = prime._beta_matrix - return True - else: - return False - - ################################################### - # The following methods are only for prime ideals # - ################################################### - - def valuation(self, ideal): - """ - Return the valuation of ``ideal`` at this prime ideal. - - INPUT: - - - ``ideal`` -- fractional ideal - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(x, (1/(x^3 + x^2 + x))*y^2) - sage: I.is_prime() - True - sage: J = O.ideal(y) - sage: I.valuation(J) - 2 - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: [f.valuation(I) for f,_ in I.factor()] - [-1, 2] - - The method closely follows Algorithm 4.8.17 of [Coh1993]_. - """ - if ideal.is_zero(): - return infinity - - O = self.ring() - F = O.fraction_field() - n = F.degree() - - # beta_matrix is for fast multiplication with beta. For performance, - # this is computed here rather than when the prime is constructed. - if self._beta_matrix is None: - beta = self._beta - m = [] - for i in range(n): - mtable_row = O._mtable[i] - c = sum(beta[j] * mtable_row[j] for j in range(n)) - m.append(c) - self._beta_matrix = matrix(m) - - B = self._beta_matrix - - # Step 1: compute the valuation of the denominator times the ideal - # - # This part is highly optimized as it is critical for - # overall performance of the function field machinery. - p = self.prime_below().gen().numerator() - h = ideal._hnf.list() - val = min([c.valuation(p) for c in h]) - i = self._ramification_index * val - while True: - ppow = p ** val - h = (matrix(n, [c // ppow for c in h]) * B).list() - val = min([c.valuation(p) for c in h]) - if val.is_zero(): - break - i += self._ramification_index * (val - 1) + 1 - - # Step 2: compute the valuation of the denominator - j = self._ramification_index * ideal.denominator().valuation(p) - - # Step 3: return the valuation - return i - j - - def prime_below(self): - """ - Return the prime lying below this prime ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(y) - sage: [f.prime_below() for f,_ in I.factor()] - [Ideal (x) of Maximal order of Rational function field in x - over Finite Field of size 2, Ideal (x^2 + x + 1) of Maximal order - of Rational function field in x over Finite Field of size 2] - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: [f.prime_below() for f,_ in I.factor()] - [Ideal (x) of Maximal order of Rational function field in x over Finite Field of size 2, - Ideal (x + 1) of Maximal order of Rational function field in x over Finite Field of size 2] - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(y) - sage: [f.prime_below() for f,_ in I.factor()] - [Ideal (x) of Maximal order of Rational function field in x over Rational Field, - Ideal (x^2 + x + 1) of Maximal order of Rational function field in x over Rational Field] - """ - return self._prime_below - - def _factor(self): - """ - Return the factorization of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(y) - sage: I == I.factor().prod() # indirect doctest - True - """ - O = self.ring() - F = O.fraction_field() - o = F.base_field().maximal_order() - - # First we collect primes below self - d = self._denominator - i = d * self - - factors = [] - primes = set([o.ideal(p) for p,_ in d.factor()] + [p for p,_ in i.ideal_below().factor()]) - for prime in primes: - qs = [q[0] for q in O.decomposition(prime)] - for q in qs: - exp = q.valuation(self) - if exp != 0: - factors.append((q,exp)) - return factors - - -class FunctionFieldIdeal_global(FunctionFieldIdeal_polymod): - """ - Fractional ideals of canonical function fields - - INPUT: - - - ``ring`` -- order in a function field - - - ``hnf`` -- matrix in hermite normal form - - - ``denominator`` -- denominator - - The rows of ``hnf`` is a basis of the ideal, which itself is - ``denominator`` times the fractional ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3*y - x) - sage: O = L.maximal_order() - sage: O.ideal(y) - Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x - """ - def __init__(self, ring, hnf, denominator=1): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(GF(5)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3*y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: TestSuite(I).run() - """ - FunctionFieldIdeal_polymod.__init__(self, ring, hnf, denominator) - - def __pow__(self, mod): - """ - Return ``self`` to the power of ``mod``. - - If a two-generators representation of ``self`` is known, it is used - to speed up powering. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^7 - x^3*Y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: J = O.ideal(x + y) - sage: S = I / J - sage: a = S^100 - sage: _ = S.gens_two() - sage: b = S^100 # faster - sage: b == I^100 / J^100 - True - sage: b == a - True - """ - if mod > 2 and self._gens_two_vecs is not None: - O = self._ring - mul = O._mul_vecs - R = self._hnf.base_ring() - n = self._hnf.ncols() - - I = matrix.identity(R, n) - - if len(self._gens_two_vecs) == 1: - p, = self._gens_two_vecs - ppow = p**mod - J = [ppow * v for v in I] - else: - p, q = self._gens_two_vecs - q = sum(e1 * e2 for e1,e2 in zip(O.basis(), q)) - ppow = p**mod - qpow = O._coordinate_vector(q**mod) - J = [ppow * v for v in I] + [mul(qpow,v) for v in I] - - return O._ideal_from_vectors_and_denominator(J, self._denominator**mod) - - return generic_power(self, mod) - - def gens(self): - """ - Return a set of generators of this ideal. - - This provides whatever set of generators as quickly - as possible. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 - x^3*Y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(x+y) - sage: I.gens() - (x^4 + x^2 + x, y + x) - - sage: L.<y> = K.extension(Y^2 +Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(x+y) - sage: I.gens() - (x^3 + 1, y + x) - """ - if self._gens_two.is_in_cache(): - return self._gens_two.cache - else: - return self.gens_over_base() - - def gens_two(self): - r""" - Return two generators of this fractional ideal. - - If the ideal is principal, one generator *may* be returned. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(y) - sage: I # indirect doctest - Ideal (y) of Maximal order of Function field - in y defined by y^3 + x^6 + x^4 + x^2 - sage: ~I # indirect doctest - Ideal ((1/(x^6 + x^4 + x^2))*y^2) of Maximal order of Function field - in y defined by y^3 + x^6 + x^4 + x^2 - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: I # indirect doctest - Ideal (y) of Maximal order of Function field in y - defined by y^2 + y + (x^2 + 1)/x - sage: ~I # indirect doctest - Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order - of Function field in y defined by y^2 + y + (x^2 + 1)/x - """ - d = self.denominator() - return tuple(e/d for e in self._gens_two()) - - @cached_method - def _gens_two(self): - r""" - Return a set of two generators of the integral ideal, that is - the denominator times this fractional ideal. - - ALGORITHM: - - At most two generators are required to generate ideals in - Dedekind domains. - - Lemma 4.7.9, algorithm 4.7.10, and exercise 4.29 of [Coh1993]_ - tell us that for an integral ideal `I` in a number field, if - we pick `a` such that `\gcd(N(I), N(a)/N(I)) = 1`, then `a` - and `N(I)` generate the ideal. `N()` is the norm, and this - result (presumably) generalizes to function fields. - - After computing `N(I)`, we search exhaustively to find `a`. - - .. TODO:: - - Always return a single generator for a principal ideal. - - Testing for principality is not trivial. Algorithm 6.5.10 - of [Coh1993]_ could probably be adapted for function fields. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: F.<y> = K.extension(Y^3 + x^3*Y + x) - sage: O = F.maximal_order() - sage: I = O.ideal(x^2,x*y,x+y) - sage: I._gens_two() - (x, y) - - sage: K.<x> = FunctionField(GF(3)) - sage: _.<Y> = K[] - sage: L.<y> = K.extension(Y-x) - sage: y.zeros()[0].prime_ideal()._gens_two() - (x,) - """ - O = self.ring() - F = O.fraction_field() - - if self._kummer_form is not None: # prime ideal - _g1, _g2 = self._kummer_form - g1 = F(_g1) - g2 = sum([c1*c2 for c1,c2 in zip(_g2, O.basis())]) - if g2: - self._gens_two_vecs = (_g1, _g2) - return (g1,g2) - else: - self._gens_two_vecs = (_g1,) - return (g1,) - - ### start to search for two generators - - hnf = self._hnf - - norm = 1 - for e in hnf.diagonal(): - norm *= e - - if norm.is_constant(): # unit ideal - self._gens_two_vecs = (1,) - return (F(1),) - - # one generator; see .ideal_below() - _l = hnf[0][0] - p = _l.degree() - l = F(_l) - - if self._hnf == O.ideal(l)._hnf: # principal ideal - self._gens_two_vecs = (_l,) - return (l,) - - R = hnf.base_ring() - - basis = [] - for row in hnf: - basis.append(sum([c1*c2 for c1,c2 in zip(row, O.basis())])) - - n = len(basis) - alpha = None - - def check(alpha): - alpha_norm = alpha.norm().numerator() # denominator is 1 - return norm.gcd(alpha_norm // norm) == 1 - - # Trial 1: search for alpha among generators - for alpha in basis: - if check(alpha): - self._gens_two_vecs = (_l, O._coordinate_vector(alpha)) - return (l, alpha) - - # Trial 2: exhaustive search for alpha using only polynomials - # with coefficients 0 or 1 - for d in range(p): - G = itertools.product(itertools.product([0,1],repeat=d+1), repeat=n) - for g in G: - alpha = sum([R(c1)*c2 for c1,c2 in zip(g, basis)]) - if check(alpha): - self._gens_two_vecs = (_l, O._coordinate_vector(alpha)) - return (l, alpha) - - # Trial 3: exhaustive search for alpha using all polynomials - for d in range(p): - G = itertools.product(R.polynomials(max_degree=d), repeat=n) - for g in G: - # discard duplicate cases - if max(c.degree() for c in g) != d: - continue - for j in range(n): - if g[j] != 0: - break - if g[j].leading_coefficient() != 1: - continue - - alpha = sum([c1*c2 for c1,c2 in zip(g, basis)]) - if check(alpha): - self._gens_two_vecs = (_l, O._coordinate_vector(alpha)) - return (l, alpha) - - # should not reach here - raise ValueError("no two generators found") - - -class FunctionFieldIdealInfinite(FunctionFieldIdeal): - """ - Base class of ideals of maximal infinite orders - """ - pass - - -class FunctionFieldIdealInfinite_rational(FunctionFieldIdealInfinite): - """ - Fractional ideal of the maximal order of rational function field. - - INPUT: - - - ``ring`` -- infinite maximal order - - - ``gen``-- generator - - Note that the infinite maximal order is a principal ideal domain. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: Oinf.ideal(x) - Ideal (x) of Maximal infinite order of Rational function field in x over Finite Field of size 2 - """ - def __init__(self, ring, gen): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal(x) - sage: TestSuite(I).run() - """ - FunctionFieldIdealInfinite.__init__(self, ring) - self._gen = gen - - def __hash__(self): - """ - Return the hash of this fractional ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal(x) - sage: J = Oinf.ideal(1/x) - sage: d = { I: 1, J: 2 } - """ - return hash( (self.ring(), self._gen) ) - - def __contains__(self, element): - """ - Test if ``element`` is in this ideal. - - INPUT: - - - ``element`` -- element of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order_infinite() - sage: I = O.ideal(1/(x+1)) - sage: x in I - False - sage: 1/x in I - True - sage: x/(x+1) in I - False - sage: 1/(x*(x+1)) in I - True - """ - return (element / self._gen) in self._ring - - def _richcmp_(self, other, op): - """ - Compare this ideal and ``other`` with respect to ``op``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal(x+1) - sage: J = Oinf.ideal(x^2+x) - sage: I + J == J - True - """ - return richcmp(self._gen, other._gen, op) - - def _add_(self, other): - """ - Add this ideal with the other ideal. - - INPUT: - - - ``other`` -- ideal - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal(x/(x^2+1)) - sage: J = Oinf.ideal(1/(x+1)) - sage: I + J - Ideal (1/x) of Maximal infinite order of Rational function field - in x over Finite Field of size 2 - """ - return self._ring.ideal([self._gen, other._gen]) - - def _mul_(self, other): - """ - Multiply this ideal with the ``other`` ideal. - - INPUT: - - - ``other`` -- ideal - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal(x/(x^2+1)) - sage: J = Oinf.ideal(1/(x+1)) - sage: I * J - Ideal (1/x^2) of Maximal infinite order of Rational function field - in x over Finite Field of size 2 - """ - return self._ring.ideal([self._gen * other._gen]) - - def _acted_upon_(self, other, on_left): - """ - Multiply this ideal with the ``other`` ideal. - - INPUT: - - - ``other`` -- ideal - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal(x/(x^2+1)) - sage: x * I - Ideal (1) of Maximal infinite order of Rational function field - in x over Finite Field of size 2 - """ - return self._ring.ideal([other * self._gen]) - - def __invert__(self): - """ - Return the multiplicative inverse of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal(x/(x^2 + 1)) - sage: ~I # indirect doctest - Ideal (x) of Maximal infinite order of Rational function field in x - over Finite Field of size 2 - """ - return self._ring.ideal([~self._gen]) - - def is_prime(self): - """ - Return ``True`` if this ideal is a prime ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal(x/(x^2 + 1)) - sage: I.is_prime() - True - """ - x = self._ring.fraction_field().gen() - return self._gen == 1/x - - def gen(self): - """ - Return the generator of this principal ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal((x+1)/(x^3+x),(x^2+1)/x^4) - sage: I.gen() - 1/x^2 - """ - return self._gen - - def gens(self): - """ - Return the generator of this principal ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal((x+1)/(x^3+x),(x^2+1)/x^4) - sage: I.gens() - (1/x^2,) - """ - return (self._gen,) - - def gens_over_base(self): - """ - Return the generator of this ideal as a rank one module - over the infinite maximal order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal((x+1)/(x^3+x),(x^2+1)/x^4) - sage: I.gens_over_base() - (1/x^2,) - """ - return (self._gen,) - - def valuation(self, ideal): - """ - Return the valuation of ``ideal`` at this prime ideal. - - INPUT: - - - ``ideal`` -- fractional ideal - - EXAMPLES:: - - sage: F.<x> = FunctionField(QQ) - sage: O = F.maximal_order_infinite() - sage: p = O.ideal(1/x) - sage: p.valuation(O.ideal(x/(x+1))) - 0 - sage: p.valuation(O.ideal(0)) - +Infinity - """ - if not self.is_prime(): - raise TypeError("not a prime ideal") - - f = ideal.gen() - if f == 0: - return infinity - else: - return f.denominator().degree() - f.numerator().degree() - - def _factor(self): - """ - Return the factorization of this ideal into prime ideals. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal((x+1)/(x^3+1)) - sage: I._factor() - [(Ideal (1/x) of Maximal infinite order of Rational function field in x - over Finite Field of size 2, 2)] - """ - g = ~(self.ring().fraction_field().gen()) - m = self._gen.denominator().degree() - self._gen.numerator().degree() - if m == 0: - return [] - else: - return [(self.ring().ideal(g), m)] - - -class FunctionFieldIdealInfinite_module(FunctionFieldIdealInfinite, Ideal_generic): - """ - A fractional ideal specified by a finitely generated module over - the integers of the base field. - - INPUT: - - - ``ring`` -- order in a function field - - - ``module`` -- module - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order() - sage: O.ideal(y) - Ideal (x^3 + 1, -y) of Order in Function field in y defined by y^2 - x^3 - 1 - """ - def __init__(self, ring, module): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order() - sage: I = O.ideal(y) - sage: TestSuite(I).run() - """ - FunctionFieldIdealInfinite.__init__(self, ring) - - self._module = module - self._structure = ring.fraction_field().vector_space() - - V, from_V, to_V = self._structure - gens = tuple([from_V(a) for a in module.basis()]) - self._gens = gens - - # module generators are still ideal generators - Ideal_generic.__init__(self, ring, self._gens, coerce=False) - - def __contains__(self, x): - """ - Return ``True`` if ``x`` is in this ideal. - - INPUT: - - - ``x`` -- element of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order() - sage: I = O.ideal_with_gens_over_base([1, y]); I - Ideal (1) of Order in Function field in y defined by y^2 + 6*x^3 + 6 - sage: y in I - True - sage: y/x in I - False - sage: y^2 - 2 in I - True - """ - return self._structure[2](x) in self._module - - def __hash__(self): - """ - Return the hash of this ideal - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order() - sage: I = O.ideal_with_gens_over_base([1, y]) - sage: d = {I: 2} # indirect doctest - """ - return hash((self._ring,self._module)) - - def __eq__(self, other): - """ - Test equality of this ideal with the ``other`` ideal. - - INPUT: - - - ``other`` -- ideal - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order() - sage: I = O.ideal_with_gens_over_base([1, y]) - sage: I == I + I # indirect doctest - True - """ - if not isinstance(other, FunctionFieldIdeal_module): - other = self.ring().ideal(other) - if self.ring() != other.ring(): - raise ValueError("rings must be the same") - - if (self.module().is_submodule(other.module()) and - other.module().is_submodule(self.module())): - return True - else: - return False - - def module(self): - """ - Return the module over the maximal order of the base field that - underlies this ideal. - - The formation of the module is compatible with the vector - space corresponding to the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)) - sage: O = K.maximal_order(); O - Maximal order of Rational function field in x over Finite Field of size 7 - sage: K.polynomial_ring() - Univariate Polynomial Ring in x over Rational function field in x over Finite Field of size 7 - sage: I = O.ideal([x^2 + 1, x*(x^2+1)]) - sage: I.gens() - (x^2 + 1,) - sage: I.module() - Free module of degree 1 and rank 1 over Maximal order of Rational function field in x over Finite Field of size 7 - Echelon basis matrix: - [x^2 + 1] - sage: V, from_V, to_V = K.vector_space(); V - Vector space of dimension 1 over Rational function field in x over Finite Field of size 7 - sage: I.module().is_submodule(V) - True - """ - return self._module - - -class FunctionFieldIdealInfinite_polymod(FunctionFieldIdealInfinite): - """ - Ideals of the infinite maximal order of an algebraic function field. - - INPUT: - - - ``ring`` -- infinite maximal order of the function field - - - ``ideal`` -- ideal in the inverted function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3+t^2-x^4) - sage: Oinf = F.maximal_order_infinite() - sage: Oinf.ideal(1/y) - Ideal (1/x^4*y^2) of Maximal infinite order of Function field - in y defined by y^3 + y^2 + 2*x^4 - """ - def __init__(self, ring, ideal): - """ - Initialize this ideal. - - TESTS:: - - sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3+t^2-x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/y) - sage: TestSuite(I).run() - """ - FunctionFieldIdealInfinite.__init__(self, ring) - self._ideal = ideal - - def __hash__(self): - """ - Return the hash of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3 + t^2 - x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/y) - sage: d = { I: 1 } - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(1/y) - sage: d = { I: 1 } - """ - return hash((self.ring(), self._ideal)) - - def __contains__(self, x): - """ - Return ``True`` if ``x`` is in this ideal. - - INPUT: - - - ``x`` -- element of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3 + t^2 - x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/y) - sage: 1/y in I - True - sage: 1/x in I - False - sage: 1/x^2 in I - True - """ - F = self.ring().fraction_field() - iF,from_iF,to_iF = F._inversion_isomorphism() - return to_iF(x) in self._ideal - - def _add_(self, other): - """ - Add this ideal with the ``other`` ideal. - - INPUT: - - - ``ideal`` -- ideal - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3+t^2-x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/x^2*1/y) - sage: J = Oinf.ideal(1/x) - sage: I + J - Ideal (1/x) of Maximal infinite order of Function field in y - defined by y^3 + y^2 + 2*x^4 - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(1/x^2*1/y) - sage: J = Oinf.ideal(1/x) - sage: I + J - Ideal (1/x) of Maximal infinite order of Function field in y - defined by y^2 + y + (x^2 + 1)/x - """ - return FunctionFieldIdealInfinite_polymod(self._ring, self._ideal + other._ideal) - - def _mul_(self, other): - """ - Multiply this ideal with the ``other`` ideal. - - INPUT: - - - ``other`` -- ideal - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3+t^2-x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/x^2*1/y) - sage: J = Oinf.ideal(1/x) - sage: I * J - Ideal (1/x^7*y^2) of Maximal infinite order of Function field - in y defined by y^3 + y^2 + 2*x^4 - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(1/x^2*1/y) - sage: J = Oinf.ideal(1/x) - sage: I * J - Ideal (1/x^4*y) of Maximal infinite order of Function field in y - defined by y^2 + y + (x^2 + 1)/x - """ - return FunctionFieldIdealInfinite_polymod(self._ring, self._ideal * other._ideal) - - def __pow__(self, n): - """ - Raise this ideal to ``n``-th power. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3+t^2-x^4) - sage: Oinf = F.maximal_order_infinite() - sage: J = Oinf.ideal(1/x) - sage: J^3 - Ideal (1/x^3) of Maximal infinite order of Function field - in y defined by y^3 + y^2 + 2*x^4 - """ - return FunctionFieldIdealInfinite_polymod(self._ring, self._ideal ** n) - - def __invert__(self): - """ - Return the inverted ideal of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3 + t^2 - x^4) - sage: Oinf = F.maximal_order_infinite() - sage: J = Oinf.ideal(y) - sage: ~J - Ideal (1/x^4*y^2) of Maximal infinite order - of Function field in y defined by y^3 + y^2 + 2*x^4 - sage: J * ~J - Ideal (1) of Maximal infinite order of Function field - in y defined by y^3 + y^2 + 2*x^4 - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: J = Oinf.ideal(y) - sage: ~J - Ideal (1/x*y) of Maximal infinite order of Function field in y - defined by y^2 + y + (x^2 + 1)/x - sage: J * ~J - Ideal (1) of Maximal infinite order of Function field in y - defined by y^2 + y + (x^2 + 1)/x - """ - return FunctionFieldIdealInfinite_polymod(self._ring, ~ self._ideal) - - def _richcmp_(self, other, op): - """ - Compare this ideal with the ``other`` ideal with respect to ``op``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3+t^2-x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/x^2*1/y) - sage: J = Oinf.ideal(1/x) - sage: I * J == J * I - True - sage: I + J == J - True - sage: I + J == I - False - sage: (I < J) == (not J < I) - True - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(1/x^2*1/y) - sage: J = Oinf.ideal(1/x) - sage: I * J == J * I - True - sage: I + J == J - True - sage: I + J == I - False - sage: (I < J) == (not J < I) - True - """ - return richcmp(self._ideal, other._ideal, op) - - @property - def _relative_degree(self): - """ - Return the relative degree of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(1/x) - sage: [J._relative_degree for J,_ in I.factor()] - [1] - """ - if not self.is_prime(): - raise TypeError("not a prime ideal") - - return self._ideal._relative_degree - - def gens(self): - """ - Return a set of generators of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3+t^2-x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(x+y) - sage: I.gens() - (x, y, 1/x^2*y^2) - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(x+y) - sage: I.gens() - (x, y) - """ - F = self.ring().fraction_field() - iF,from_iF,to_iF = F._inversion_isomorphism() - return tuple(from_iF(b) for b in self._ideal.gens()) - - def gens_two(self): - """ - Return a set of at most two generators of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3+t^2-x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(x+y) - sage: I.gens_two() - (x, y) - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2+Y+x+1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(x+y) - sage: I.gens_two() - (x,) - """ - F = self.ring().fraction_field() - iF,from_iF,to_iF = F._inversion_isomorphism() - return tuple(from_iF(b) for b in self._ideal.gens_two()) - - def gens_over_base(self): - """ - Return a set of generators of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); _.<t> = K[] - sage: F.<y> = K.extension(t^3 + t^2 - x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(x + y) - sage: I.gens_over_base() - (x, y, 1/x^2*y^2) - """ - F = self.ring().fraction_field() - iF,from_iF,to_iF = F._inversion_isomorphism() - return tuple(from_iF(g) for g in self._ideal.gens_over_base()) - - def ideal_below(self): - """ - Return a set of generators of this ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); _.<t> = K[] - sage: F.<y> = K.extension(t^3 + t^2 - x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/y^2) - sage: I.ideal_below() - Ideal (x^3) of Maximal order of Rational function field - in x over Finite Field in z2 of size 3^2 - """ - return self._ideal.ideal_below() - - def is_prime(self): - """ - Return ``True`` if this ideal is a prime ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3 + t^2 - x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/x) - sage: I.factor() - (Ideal (1/x^3*y^2) of Maximal infinite order of Function field - in y defined by y^3 + y^2 + 2*x^4)^3 - sage: I.is_prime() - False - sage: J = I.factor()[0][0] - sage: J.is_prime() - True - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(1/x) - sage: I.factor() - (Ideal (1/x*y) of Maximal infinite order of Function field in y - defined by y^2 + y + (x^2 + 1)/x)^2 - sage: I.is_prime() - False - sage: J = I.factor()[0][0] - sage: J.is_prime() - True - """ - return self._ideal.is_prime() - - @cached_method - def prime_below(self): - """ - Return the prime of the base order that underlies this prime ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3+t^2-x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/x) - sage: I.factor() - (Ideal (1/x^3*y^2) of Maximal infinite order of Function field - in y defined by y^3 + y^2 + 2*x^4)^3 - sage: J = I.factor()[0][0] - sage: J.is_prime() - True - sage: J.prime_below() - Ideal (1/x) of Maximal infinite order of Rational function field - in x over Finite Field in z2 of size 3^2 - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(1/x) - sage: I.factor() - (Ideal (1/x*y) of Maximal infinite order of Function field in y - defined by y^2 + y + (x^2 + 1)/x)^2 - sage: J = I.factor()[0][0] - sage: J.is_prime() - True - sage: J.prime_below() - Ideal (1/x) of Maximal infinite order of Rational function field in x - over Finite Field of size 2 - """ - if not self.is_prime(): - raise TypeError("not a prime ideal") - - F = self.ring().fraction_field() - K = F.base_field() - return K.maximal_order_infinite().prime_ideal() - - def valuation(self, ideal): - """ - Return the valuation of ``ideal`` with respect to this prime ideal. - - INPUT: - - - ``ideal`` -- fractional ideal - - EXAMPLES:: - - sage: K.<x>=FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y>=K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(y) - sage: [f.valuation(I) for f,_ in I.factor()] - [-1] - """ - if not self.is_prime(): - raise TypeError("not a prime ideal") - - return self._ideal.valuation(self.ring()._to_iF(ideal)) - - def _factor(self): - """ - Return factorization of the ideal. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: Oinf = F.maximal_order_infinite() - sage: f= 1/x - sage: I = Oinf.ideal(f) - sage: I._factor() - [(Ideal (1/x, 1/x^4*y^2 + 1/x^2*y + 1) of Maximal infinite order of Function field in y - defined by y^3 + x^6 + x^4 + x^2, 1), - (Ideal (1/x, 1/x^2*y + 1) of Maximal infinite order of Function field in y - defined by y^3 + x^6 + x^4 + x^2, 1)] - """ - if self._ideal.is_prime.is_in_cache() and self._ideal.is_prime(): - return [(self, 1)] - - O = self.ring() - factors = [] - for iprime, exp in O._to_iF(self).factor(): - prime = FunctionFieldIdealInfinite_polymod(O, iprime) - factors.append((prime, exp)) - return factors + return self._module class IdealMonoid(UniqueRepresentation, Parent): @@ -3277,7 +1071,7 @@ def __init__(self, R): sage: TestSuite(M).run() """ self.Element = R._ideal_class - Parent.__init__(self, category = Monoids()) + Parent.__init__(self, category=Monoids()) self.__R = R self._populate_coercion_lists_() diff --git a/src/sage/rings/function_field/ideal_polymod.py b/src/sage/rings/function_field/ideal_polymod.py new file mode 100644 index 00000000000..6735dd6a8fa --- /dev/null +++ b/src/sage/rings/function_field/ideal_polymod.py @@ -0,0 +1,1776 @@ +# sage.doctest: optional - sage.rings.function_field +r""" +Ideals of function fields: extension +""" + +# **************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2017-2021 Kwankyu Lee +# 2018 Frรฉdรฉric Chapoton +# 2019 Brent Baccala +# 2021 Jonathan Kliem +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# **************************************************************************** + +import itertools +from sage.rings.infinity import infinity +from sage.arith.power import generic_power +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.structure.richcmp import richcmp +from sage.matrix.constructor import matrix + +from .ideal import FunctionFieldIdeal, FunctionFieldIdealInfinite + +class FunctionFieldIdeal_polymod(FunctionFieldIdeal): + """ + Fractional ideals of algebraic function fields + + INPUT: + + - ``ring`` -- order in a function field + + - ``hnf`` -- matrix in hermite normal form + + - ``denominator`` -- denominator + + The rows of ``hnf`` is a basis of the ideal, which itself is + ``denominator`` times the fractional ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3*y - x) + sage: O = L.maximal_order() + sage: O.ideal(y) + Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x + """ + def __init__(self, ring, hnf, denominator=1): + """ + Initialize. + + TESTS:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3*y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: TestSuite(I).run() + """ + FunctionFieldIdeal.__init__(self, ring) + + # the denominator and the entries of the hnf are + # univariate polynomials. + self._hnf = hnf + self._denominator = denominator + + # for prime ideals + self._relative_degree = None + self._ramification_index = None + self._prime_below = None + self._beta = None + + # beta in matrix form for fast multiplication + self._beta_matrix = None + + # (p, q) with irreducible polynomial p and q an element of O in vector + # form, together generating the prime ideal. This data is obtained by + # Kummer's theorem when this prime ideal is constructed. This is used + # for fast multiplication with other ideal. + self._kummer_form = None + + # tuple of at most two gens: + # the first gen is an element of the base ring of the maximal order + # the second gen is the vector form of an element of the maximal order + # if the second gen is zero, the tuple has only the first gen. + self._gens_two_vecs = None + + def __bool__(self): + """ + Test if this ideal is zero. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3*y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(y); I + Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x + sage: I.is_zero() + False + sage: J = 0*I; J + Zero ideal of Maximal order of Function field in y defined by y^2 + x^3*y + x + sage: J.is_zero() + True + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y>=K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y); I + Ideal (y) of Maximal order of Function field in y + defined by y^2 + y + (x^2 + 1)/x + sage: I.is_zero() + False + sage: J = 0*I; J + Zero ideal of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x + sage: J.is_zero() + True + """ + return self._hnf.nrows() != 0 + + def __hash__(self): + """ + Return the hash of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(1/y) + sage: { I: 2 }[I] == 2 + True + + sage: # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(1/y) + sage: { I: 2 }[I] == 2 + True + """ + return hash((self._ring, self._hnf, self._denominator)) + + def __contains__(self, x): + """ + Return ``True`` if ``x`` is in this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3 - 1) + sage: O = L.maximal_order() + sage: I = O.ideal([y]); I + Ideal (y) of Maximal order of Function field in y + defined by y^2 + 6*x^3 + 6 + sage: x * y in I + True + sage: y / x in I + False + sage: y^2 - 2 in I + False + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal([y]); I + Ideal (y) of Maximal order of Function field in y + defined by y^2 + y + (x^2 + 1)/x + sage: x * y in I + True + sage: y / x in I + False + sage: y^2 - 2 in I + False + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3 - 1) + sage: O = L.maximal_order() + sage: I = O.ideal([y]); I + Ideal (y) of Maximal order of Function field in y + defined by y^2 - x^3 - 1 + sage: x * y in I + True + sage: y / x in I + False + sage: y^2 - 2 in I + False + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal([y]); I + Ideal (y) of Maximal order of Function field in y + defined by y^2 + y + (x^2 + 1)/x + sage: x * y in I + True + sage: y / x in I + False + sage: y^2 - 2 in I + False + """ + from sage.modules.free_module_element import vector + + vec = self.ring().coordinate_vector(self._denominator * x) + v = [] + for e in vec: + if e.denominator() != 1: + return False + v.append(e.numerator()) + vec = vector(v) + return vec in self._hnf.image() + + def __invert__(self): + """ + Return the inverse fractional ideal of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3 - 1) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: ~I + Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 + sage: I^(-1) + Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 + sage: ~I * I + Ideal (1) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 + + :: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: ~I + Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order + of Function field in y defined by y^2 + y + (x^2 + 1)/x + sage: I^(-1) + Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order + of Function field in y defined by y^2 + y + (x^2 + 1)/x + sage: ~I * I + Ideal (1) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x + + :: + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3 - 1) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: ~I + Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 - x^3 - 1 + sage: I^(-1) + Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 - x^3 - 1 + sage: ~I * I + Ideal (1) of Maximal order of Function field in y defined by y^2 - x^3 - 1 + + :: + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: ~I + Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order + of Function field in y defined by y^2 + y + (x^2 + 1)/x + sage: I^(-1) + Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order + of Function field in y defined by y^2 + y + (x^2 + 1)/x + sage: ~I * I + Ideal (1) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x + """ + R = self.ring() + T = R._codifferent_matrix() + I = self * R.codifferent() + J = I._denominator * (I._hnf * T).inverse() + return R._ideal_from_vectors(J.columns()) + + def _richcmp_(self, other, op): + """ + Compare this ideal with the other ideal with respect to ``op``. + + INPUT: + + - ``other`` -- ideal + + - ``op`` -- comparison operator + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(1/y) + sage: I == I + I + True + sage: I == I * I + False + + :: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(1/y) + sage: I == I + I + True + sage: I == I * I + False + sage: I < I * I + True + sage: I > I * I + False + """ + return richcmp((self._denominator, self._hnf), (other._denominator, other._hnf), op) + + def _add_(self, other): + """ + Add with other ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: J = O.ideal(x + y) + sage: I + J + Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x + + sage: # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: J = O.ideal(x + y) + sage: I + J + Ideal (1, y) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x + """ + ds = self._denominator + do = other._denominator + vecs1 = [do * r for r in self._hnf] + vecs2 = [ds * r for r in other._hnf] + return self._ring._ideal_from_vectors_and_denominator(vecs1 + vecs2, ds * do) + + def _mul_(self, other): + """ + Multiply with other ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: J = O.ideal(x + y) + sage: I * J + Ideal (x^4 + x^2 + x, x*y + x^2) of Maximal order + of Function field in y defined by y^2 + x^3*y + x + + sage: # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: J = O.ideal(x + y) + sage: I * J + Ideal ((x + 1)*y + (x^2 + 1)/x) of Maximal order + of Function field in y defined by y^2 + y + (x^2 + 1)/x + """ + O = self._ring + mul = O._mul_vecs + + if self._kummer_form is not None: + p, q = self._kummer_form + vecs = list(p * other._hnf) + [mul(q, v) for v in other._hnf] + elif other._kummer_form is not None: + p, q = other._kummer_form + vecs = list(p * self._hnf) + [mul(q, v) for v in self._hnf] + elif self._gens_two_vecs is not None: + if len(self._gens_two_vecs) == 1: + g1, = self._gens_two_vecs + vecs = list(g1 * other._hnf) + else: + g1, g2 = self._gens_two_vecs + vecs = list(g1 * other._hnf) + [mul(g2, v) for v in other._hnf] + elif other._gens_two_vecs is not None: + if len(other._gens_two_vecs) == 1: + g1, = other._gens_two_vecs + vecs = list(g1 * self._hnf) + else: + g1, g2 = other._gens_two_vecs + vecs = list(g1 * self._hnf) + [mul(g2, v) for v in self._hnf] + else: + vecs = [mul(r1,r2) for r1 in self._hnf for r2 in other._hnf] + + return O._ideal_from_vectors_and_denominator(vecs, self._denominator * other._denominator) + + def _acted_upon_(self, other, on_left): + """ + Multiply ``other`` and this ideal on the right. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(x + y) + sage: J = O.ideal(x) + sage: x * I == I * J + True + + sage: # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(x + y) + sage: J = O.ideal(x) + sage: x * I == I * J + True + """ + from sage.modules.free_module_element import vector + + O = self._ring + mul = O._mul_vecs + + # compute the vector form of other element + v = O.coordinate_vector(other) + d = v.denominator() + vec = vector([(d * c).numerator() for c in v]) + + # multiply with the ideal + vecs = [mul(vec, r) for r in self._hnf] + + return O._ideal_from_vectors_and_denominator(vecs, d * self._denominator) + + def intersect(self, other): + """ + Intersect this ideal with the other ideal as fractional ideals. + + INPUT: + + - ``other`` -- ideal + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(x + y) + sage: J = O.ideal(x) + sage: I.intersect(J) == I * J * (I + J)^-1 + True + + """ + from sage.matrix.special import block_matrix + from .hermite_form_polynomial import reversed_hermite_form + + A = self._hnf + B = other._hnf + + ds = self.denominator() + do = other.denominator() + d = ds.lcm(do) + if not d.is_one(): + A = (d // ds) * A + B = (d // do) * B + + MS = A.matrix_space() + I = MS.identity_matrix() + O = MS.zero() + n = A.ncols() + + # intersect the row spaces of A and B + M = block_matrix([[I,I],[A,O],[O,B]]) + + # reversed Hermite form + U = reversed_hermite_form(M, transformation=True) + + vecs = [U[i][:n] for i in range(n)] + + return self._ring._ideal_from_vectors_and_denominator(vecs, d) + + def hnf(self): + """ + Return the matrix in hermite normal form representing this ideal. + + See also :meth:`denominator` + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.maximal_order() + sage: I = O.ideal(y*(y+1)); I.hnf() + [x^6 + x^3 0] + [ x^3 + 1 1] + + :: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.maximal_order() + sage: I = O.ideal(y*(y+1)); I.hnf() + [x^6 + x^3 0] + [ x^3 + 1 1] + """ + return self._hnf + + def denominator(self): + """ + Return the denominator of this fractional ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.maximal_order() + sage: I = O.ideal(y/(y+1)) + sage: d = I.denominator(); d + x^3 + sage: d in O + True + + :: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.maximal_order() + sage: I = O.ideal(y/(y+1)) + sage: d = I.denominator(); d + x^3 + sage: d in O + True + """ + return self._denominator + + @cached_method + def module(self): + """ + Return the module, that is the ideal viewed as a module + over the base maximal order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: F.<y> = K.extension(y^2 - x^3 - 1) + sage: O = F.maximal_order() + sage: I = O.ideal(x, 1/y) + sage: I.module() + Free module of degree 2 and rank 2 over Maximal order + of Rational function field in x over Finite Field of size 7 + Echelon basis matrix: + [ 1 0] + [ 0 1/(x^3 + 1)] + """ + F = self.ring().fraction_field() + V, fr, to = F.vector_space() + O = F.base_field().maximal_order() + return V.span([to(g) for g in self.gens_over_base()], base_ring=O) + + @cached_method + def gens_over_base(self): + """ + Return the generators of this ideal as a module over the maximal order + of the base rational function field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(x + y) + sage: I.gens_over_base() + (x^4 + x^2 + x, y + x) + + sage: # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(x + y) + sage: I.gens_over_base() + (x^3 + 1, y + x) + """ + gens, d = self._gens_over_base + return tuple([~d * b for b in gens]) + + @lazy_attribute + def _gens_over_base(self): + """ + Return the generators of the integral ideal, which is the denominator + times the fractional ideal, together with the denominator. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3*y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(1/y) + sage: I._gens_over_base + ([x, y], x) + """ + gens = [] + for row in self._hnf: + gens.append(sum([c1*c2 for c1,c2 in zip(row, self._ring.basis())])) + return gens, self._denominator + + def gens(self): + """ + Return a set of generators of this ideal. + + This provides whatever set of generators as quickly + as possible. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(x + y) + sage: I.gens() + (x^4 + x^2 + x, y + x) + + sage: # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(x + y) + sage: I.gens() + (x^3 + 1, y + x) + """ + return self.gens_over_base() + + @cached_method + def basis_matrix(self): + """ + Return the matrix of basis vectors of this ideal as a module. + + The basis matrix is by definition the hermite norm form of the ideal + divided by the denominator. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(x, 1/y) + sage: I.denominator() * I.basis_matrix() == I.hnf() + True + """ + d = self.denominator() + m = (d * self).hnf() + if d != 1: + m = ~d * m + m.set_immutable() + return m + + def is_integral(self): + """ + Return ``True`` if this is an integral ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(x, 1/y) + sage: I.is_integral() + False + sage: J = I.denominator() * I + sage: J.is_integral() + True + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(x, 1/y) + sage: I.is_integral() + False + sage: J = I.denominator() * I + sage: J.is_integral() + True + + sage: K.<x> = FunctionField(QQ); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(x, 1/y) + sage: I.is_integral() + False + sage: J = I.denominator() * I + sage: J.is_integral() + True + """ + return self.denominator() == 1 + + def ideal_below(self): + """ + Return the ideal below this ideal. + + This is defined only for integral ideals. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(x, 1/y) + sage: I.ideal_below() + Traceback (most recent call last): + ... + TypeError: not an integral ideal + sage: J = I.denominator() * I + sage: J.ideal_below() + Ideal (x^3 + x^2 + x) of Maximal order of Rational function field + in x over Finite Field of size 2 + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(x, 1/y) + sage: I.ideal_below() + Traceback (most recent call last): + ... + TypeError: not an integral ideal + sage: J = I.denominator() * I + sage: J.ideal_below() + Ideal (x^3 + x) of Maximal order of Rational function field + in x over Finite Field of size 2 + + sage: K.<x> = FunctionField(QQ); _.<t> = K[] + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(x, 1/y) + sage: I.ideal_below() + Traceback (most recent call last): + ... + TypeError: not an integral ideal + sage: J = I.denominator() * I + sage: J.ideal_below() + Ideal (x^3 + x^2 + x) of Maximal order of Rational function field + in x over Rational Field + """ + if not self.is_integral(): + raise TypeError("not an integral ideal") + + K = self.ring().fraction_field().base_field().maximal_order() + + # self._hnf is in reversed hermite normal form, that is, lower + # triangular form. Thus the generator of the ideal below is + # just the (0,0) entry of the normal form. When self._hnf was in + # hermite normal form, that is, upper triangular form, then the + # generator can be computed in the following way: + # + # m = matrix([hnf[0].parent().gen(0)] + list(hnf)) + # _,T = m.hermite_form(transformation=True) + # return T[-1][0] + # + # This is certainly less efficient! This is an argument for using + # reversed hermite normal form for ideal representation. + l = self._hnf[0][0] + + return K.ideal(l) + + def norm(self): + """ + Return the norm of this fractional ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: O = F.maximal_order() + sage: i1 = O.ideal(x) + sage: i2 = O.ideal(y) + sage: i3 = i1 * i2 + sage: i3.norm() == i1.norm() * i2.norm() + True + sage: i1.norm() + x^3 + sage: i1.norm() == x ** F.degree() + True + sage: i2.norm() + x^6 + x^4 + x^2 + sage: i2.norm() == y.norm() + True + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: i1 = O.ideal(x) + sage: i2 = O.ideal(y) + sage: i3 = i1 * i2 + sage: i3.norm() == i1.norm() * i2.norm() + True + sage: i1.norm() + x^2 + sage: i1.norm() == x ** L.degree() + True + sage: i2.norm() + (x^2 + 1)/x + sage: i2.norm() == y.norm() + True + """ + n = 1 + for e in self.basis_matrix().diagonal(): + n *= e + return n + + @cached_method + def is_prime(self): + """ + Return ``True`` if this ideal is a prime ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(y) + sage: [f.is_prime() for f,_ in I.factor()] + [True, True] + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: [f.is_prime() for f,_ in I.factor()] + [True, True] + + sage: K.<x> = FunctionField(QQ); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(y) + sage: [f.is_prime() for f,_ in I.factor()] + [True, True] + """ + factors = self.factor() + if len(factors) == 1 and factors[0][1] == 1: # prime! + prime = factors[0][0] + assert self == prime + self._relative_degree = prime._relative_degree + self._ramification_index = prime._ramification_index + self._prime_below = prime._prime_below + self._beta = prime._beta + self._beta_matrix = prime._beta_matrix + return True + else: + return False + + ################################################### + # The following methods are only for prime ideals # + ################################################### + + def valuation(self, ideal): + """ + Return the valuation of ``ideal`` at this prime ideal. + + INPUT: + + - ``ideal`` -- fractional ideal + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(x, (1/(x^3 + x^2 + x))*y^2) + sage: I.is_prime() + True + sage: J = O.ideal(y) + sage: I.valuation(J) + 2 + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: [f.valuation(I) for f,_ in I.factor()] + [-1, 2] + + The method closely follows Algorithm 4.8.17 of [Coh1993]_. + """ + from sage.matrix.constructor import matrix + + if ideal.is_zero(): + return infinity + + O = self.ring() + F = O.fraction_field() + n = F.degree() + + # beta_matrix is for fast multiplication with beta. For performance, + # this is computed here rather than when the prime is constructed. + if self._beta_matrix is None: + beta = self._beta + m = [] + for i in range(n): + mtable_row = O._mtable[i] + c = sum(beta[j] * mtable_row[j] for j in range(n)) + m.append(c) + self._beta_matrix = matrix(m) + + B = self._beta_matrix + + # Step 1: compute the valuation of the denominator times the ideal + # + # This part is highly optimized as it is critical for + # overall performance of the function field machinery. + p = self.prime_below().gen().numerator() + h = ideal._hnf.list() + val = min([c.valuation(p) for c in h]) + i = self._ramification_index * val + while True: + ppow = p ** val + h = (matrix(n, [c // ppow for c in h]) * B).list() + val = min([c.valuation(p) for c in h]) + if val.is_zero(): + break + i += self._ramification_index * (val - 1) + 1 + + # Step 2: compute the valuation of the denominator + j = self._ramification_index * ideal.denominator().valuation(p) + + # Step 3: return the valuation + return i - j + + def prime_below(self): + """ + Return the prime lying below this prime ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(y) + sage: [f.prime_below() for f,_ in I.factor()] + [Ideal (x) of Maximal order of Rational function field in x + over Finite Field of size 2, Ideal (x^2 + x + 1) of Maximal order + of Rational function field in x over Finite Field of size 2] + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: [f.prime_below() for f,_ in I.factor()] + [Ideal (x) of Maximal order of Rational function field in x over Finite Field of size 2, + Ideal (x + 1) of Maximal order of Rational function field in x over Finite Field of size 2] + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(y) + sage: [f.prime_below() for f,_ in I.factor()] + [Ideal (x) of Maximal order of Rational function field in x over Rational Field, + Ideal (x^2 + x + 1) of Maximal order of Rational function field in x over Rational Field] + """ + return self._prime_below + + def _factor(self): + """ + Return the factorization of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(y) + sage: I == I.factor().prod() # indirect doctest + True + """ + O = self.ring() + F = O.fraction_field() + o = F.base_field().maximal_order() + + # First we collect primes below self + d = self._denominator + i = d * self + + factors = [] + primes = set([o.ideal(p) for p,_ in d.factor()] + [p for p,_ in i.ideal_below().factor()]) + for prime in primes: + qs = [q[0] for q in O.decomposition(prime)] + for q in qs: + exp = q.valuation(self) + if exp != 0: + factors.append((q,exp)) + return factors + + +class FunctionFieldIdeal_global(FunctionFieldIdeal_polymod): + """ + Fractional ideals of canonical function fields + + INPUT: + + - ``ring`` -- order in a function field + + - ``hnf`` -- matrix in hermite normal form + + - ``denominator`` -- denominator + + The rows of ``hnf`` is a basis of the ideal, which itself is + ``denominator`` times the fractional ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3*y - x) + sage: O = L.maximal_order() + sage: O.ideal(y) + Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x + """ + def __init__(self, ring, hnf, denominator=1): + """ + Initialize. + + TESTS:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(5)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3*y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: TestSuite(I).run() + """ + FunctionFieldIdeal_polymod.__init__(self, ring, hnf, denominator) + + def __pow__(self, mod): + """ + Return ``self`` to the power of ``mod``. + + If a two-generators representation of ``self`` is known, it is used + to speed up powering. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^7 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: J = O.ideal(x + y) + sage: S = I / J + sage: a = S^100 + sage: _ = S.gens_two() + sage: b = S^100 # faster + sage: b == I^100 / J^100 + True + sage: b == a + True + """ + if mod > 2 and self._gens_two_vecs is not None: + O = self._ring + mul = O._mul_vecs + R = self._hnf.base_ring() + n = self._hnf.ncols() + + I = matrix.identity(R, n) + + if len(self._gens_two_vecs) == 1: + p, = self._gens_two_vecs + ppow = p**mod + J = [ppow * v for v in I] + else: + p, q = self._gens_two_vecs + q = sum(e1 * e2 for e1,e2 in zip(O.basis(), q)) + ppow = p**mod + qpow = O._coordinate_vector(q**mod) + J = [ppow * v for v in I] + [mul(qpow,v) for v in I] + + return O._ideal_from_vectors_and_denominator(J, self._denominator**mod) + + return generic_power(self, mod) + + def gens(self): + """ + Return a set of generators of this ideal. + + This provides whatever set of generators as quickly + as possible. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(x + y) + sage: I.gens() + (x^4 + x^2 + x, y + x) + + sage: # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(x + y) + sage: I.gens() + (x^3 + 1, y + x) + """ + if self._gens_two.is_in_cache(): + return self._gens_two.cache + else: + return self.gens_over_base() + + def gens_two(self): + r""" + Return two generators of this fractional ideal. + + If the ideal is principal, one generator *may* be returned. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(y) + sage: I # indirect doctest + Ideal (y) of Maximal order of Function field + in y defined by y^3 + x^6 + x^4 + x^2 + sage: ~I # indirect doctest + Ideal ((1/(x^6 + x^4 + x^2))*y^2) of Maximal order of Function field + in y defined by y^3 + x^6 + x^4 + x^2 + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: I # indirect doctest + Ideal (y) of Maximal order of Function field in y + defined by y^2 + y + (x^2 + 1)/x + sage: ~I # indirect doctest + Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order + of Function field in y defined by y^2 + y + (x^2 + 1)/x + """ + d = self.denominator() + return tuple(e/d for e in self._gens_two()) + + @cached_method + def _gens_two(self): + r""" + Return a set of two generators of the integral ideal, that is + the denominator times this fractional ideal. + + ALGORITHM: + + At most two generators are required to generate ideals in + Dedekind domains. + + Lemma 4.7.9, algorithm 4.7.10, and exercise 4.29 of [Coh1993]_ + tell us that for an integral ideal `I` in a number field, if + we pick `a` such that `\gcd(N(I), N(a)/N(I)) = 1`, then `a` + and `N(I)` generate the ideal. `N()` is the norm, and this + result (presumably) generalizes to function fields. + + After computing `N(I)`, we search exhaustively to find `a`. + + .. TODO:: + + Always return a single generator for a principal ideal. + + Testing for principality is not trivial. Algorithm 6.5.10 + of [Coh1993]_ could probably be adapted for function fields. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: F.<y> = K.extension(Y^3 + x^3*Y + x) + sage: O = F.maximal_order() + sage: I = O.ideal(x^2, x*y, x + y) + sage: I._gens_two() + (x, y) + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3)) + sage: _.<Y> = K[] + sage: L.<y> = K.extension(Y - x) + sage: y.zeros()[0].prime_ideal()._gens_two() + (x,) + """ + O = self.ring() + F = O.fraction_field() + + if self._kummer_form is not None: # prime ideal + _g1, _g2 = self._kummer_form + g1 = F(_g1) + g2 = sum([c1*c2 for c1,c2 in zip(_g2, O.basis())]) + if g2: + self._gens_two_vecs = (_g1, _g2) + return (g1,g2) + else: + self._gens_two_vecs = (_g1,) + return (g1,) + + ### start to search for two generators + + hnf = self._hnf + + norm = 1 + for e in hnf.diagonal(): + norm *= e + + if norm.is_constant(): # unit ideal + self._gens_two_vecs = (1,) + return (F(1),) + + # one generator; see .ideal_below() + _l = hnf[0][0] + p = _l.degree() + l = F(_l) + + if self._hnf == O.ideal(l)._hnf: # principal ideal + self._gens_two_vecs = (_l,) + return (l,) + + R = hnf.base_ring() + + basis = [] + for row in hnf: + basis.append(sum([c1*c2 for c1,c2 in zip(row, O.basis())])) + + n = len(basis) + alpha = None + + def check(alpha): + alpha_norm = alpha.norm().numerator() # denominator is 1 + return norm.gcd(alpha_norm // norm) == 1 + + # Trial 1: search for alpha among generators + for alpha in basis: + if check(alpha): + self._gens_two_vecs = (_l, O._coordinate_vector(alpha)) + return (l, alpha) + + # Trial 2: exhaustive search for alpha using only polynomials + # with coefficients 0 or 1 + for d in range(p): + G = itertools.product(itertools.product([0,1],repeat=d+1), repeat=n) + for g in G: + alpha = sum([R(c1)*c2 for c1,c2 in zip(g, basis)]) + if check(alpha): + self._gens_two_vecs = (_l, O._coordinate_vector(alpha)) + return (l, alpha) + + # Trial 3: exhaustive search for alpha using all polynomials + for d in range(p): + G = itertools.product(R.polynomials(max_degree=d), repeat=n) + for g in G: + # discard duplicate cases + if max(c.degree() for c in g) != d: + continue + for j in range(n): + if g[j] != 0: + break + if g[j].leading_coefficient() != 1: + continue + + alpha = sum([c1*c2 for c1,c2 in zip(g, basis)]) + if check(alpha): + self._gens_two_vecs = (_l, O._coordinate_vector(alpha)) + return (l, alpha) + + # should not reach here + raise ValueError("no two generators found") + + +class FunctionFieldIdealInfinite_polymod(FunctionFieldIdealInfinite): + """ + Ideals of the infinite maximal order of an algebraic function field. + + INPUT: + + - ``ring`` -- infinite maximal order of the function field + + - ``ideal`` -- ideal in the inverted function field + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: Oinf.ideal(1/y) + Ideal (1/x^4*y^2) of Maximal infinite order of Function field + in y defined by y^3 + y^2 + 2*x^4 + """ + def __init__(self, ring, ideal): + """ + Initialize this ideal. + + TESTS:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(1/y) + sage: TestSuite(I).run() + """ + FunctionFieldIdealInfinite.__init__(self, ring) + self._ideal = ideal + + def __hash__(self): + """ + Return the hash of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(1/y) + sage: d = { I: 1 } + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(1/y) + sage: d = { I: 1 } + """ + return hash((self.ring(), self._ideal)) + + def __contains__(self, x): + """ + Return ``True`` if ``x`` is in this ideal. + + INPUT: + + - ``x`` -- element of the function field + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(1/y) + sage: 1/y in I + True + sage: 1/x in I + False + sage: 1/x^2 in I + True + """ + F = self.ring().fraction_field() + iF,from_iF,to_iF = F._inversion_isomorphism() + return to_iF(x) in self._ideal + + def _add_(self, other): + """ + Add this ideal with the ``other`` ideal. + + INPUT: + + - ``ideal`` -- ideal + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(1/x^2*1/y) + sage: J = Oinf.ideal(1/x) + sage: I + J + Ideal (1/x) of Maximal infinite order of Function field in y + defined by y^3 + y^2 + 2*x^4 + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(1/x^2*1/y) + sage: J = Oinf.ideal(1/x) + sage: I + J + Ideal (1/x) of Maximal infinite order of Function field in y + defined by y^2 + y + (x^2 + 1)/x + """ + return FunctionFieldIdealInfinite_polymod(self._ring, self._ideal + other._ideal) + + def _mul_(self, other): + """ + Multiply this ideal with the ``other`` ideal. + + INPUT: + + - ``other`` -- ideal + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(1/x^2*1/y) + sage: J = Oinf.ideal(1/x) + sage: I * J + Ideal (1/x^7*y^2) of Maximal infinite order of Function field + in y defined by y^3 + y^2 + 2*x^4 + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(1/x^2*1/y) + sage: J = Oinf.ideal(1/x) + sage: I * J + Ideal (1/x^4*y) of Maximal infinite order of Function field in y + defined by y^2 + y + (x^2 + 1)/x + """ + return FunctionFieldIdealInfinite_polymod(self._ring, self._ideal * other._ideal) + + def __pow__(self, n): + """ + Raise this ideal to ``n``-th power. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: J = Oinf.ideal(1/x) + sage: J^3 + Ideal (1/x^3) of Maximal infinite order of Function field + in y defined by y^3 + y^2 + 2*x^4 + """ + return FunctionFieldIdealInfinite_polymod(self._ring, self._ideal ** n) + + def __invert__(self): + """ + Return the inverted ideal of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: J = Oinf.ideal(y) + sage: ~J + Ideal (1/x^4*y^2) of Maximal infinite order + of Function field in y defined by y^3 + y^2 + 2*x^4 + sage: J * ~J + Ideal (1) of Maximal infinite order of Function field + in y defined by y^3 + y^2 + 2*x^4 + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: J = Oinf.ideal(y) + sage: ~J + Ideal (1/x*y) of Maximal infinite order of Function field in y + defined by y^2 + y + (x^2 + 1)/x + sage: J * ~J + Ideal (1) of Maximal infinite order of Function field in y + defined by y^2 + y + (x^2 + 1)/x + """ + return FunctionFieldIdealInfinite_polymod(self._ring, ~ self._ideal) + + def _richcmp_(self, other, op): + """ + Compare this ideal with the ``other`` ideal with respect to ``op``. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(1/x^2*1/y) + sage: J = Oinf.ideal(1/x) + sage: I * J == J * I + True + sage: I + J == J + True + sage: I + J == I + False + sage: (I < J) == (not J < I) + True + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(1/x^2*1/y) + sage: J = Oinf.ideal(1/x) + sage: I * J == J * I + True + sage: I + J == J + True + sage: I + J == I + False + sage: (I < J) == (not J < I) + True + """ + return richcmp(self._ideal, other._ideal, op) + + @property + def _relative_degree(self): + """ + Return the relative degree of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(1/x) + sage: [J._relative_degree for J,_ in I.factor()] + [1] + """ + if not self.is_prime(): + raise TypeError("not a prime ideal") + + return self._ideal._relative_degree + + def gens(self): + """ + Return a set of generators of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(x + y) + sage: I.gens() + (x, y, 1/x^2*y^2) + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(x + y) + sage: I.gens() + (x, y) + """ + F = self.ring().fraction_field() + iF,from_iF,to_iF = F._inversion_isomorphism() + return tuple(from_iF(b) for b in self._ideal.gens()) + + def gens_two(self): + """ + Return a set of at most two generators of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(x + y) + sage: I.gens_two() + (x, y) + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(x + y) + sage: I.gens_two() + (x,) + """ + F = self.ring().fraction_field() + iF,from_iF,to_iF = F._inversion_isomorphism() + return tuple(from_iF(b) for b in self._ideal.gens_two()) + + def gens_over_base(self): + """ + Return a set of generators of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); _.<t> = K[] + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(x + y) + sage: I.gens_over_base() + (x, y, 1/x^2*y^2) + """ + F = self.ring().fraction_field() + iF,from_iF,to_iF = F._inversion_isomorphism() + return tuple(from_iF(g) for g in self._ideal.gens_over_base()) + + def ideal_below(self): + """ + Return a set of generators of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); _.<t> = K[] + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(1/y^2) + sage: I.ideal_below() + Ideal (x^3) of Maximal order of Rational function field + in x over Finite Field in z2 of size 3^2 + """ + return self._ideal.ideal_below() + + def is_prime(self): + """ + Return ``True`` if this ideal is a prime ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(1/x) + sage: I.factor() + (Ideal (1/x^3*y^2) of Maximal infinite order of Function field + in y defined by y^3 + y^2 + 2*x^4)^3 + sage: I.is_prime() + False + sage: J = I.factor()[0][0] + sage: J.is_prime() + True + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(1/x) + sage: I.factor() + (Ideal (1/x*y) of Maximal infinite order of Function field in y + defined by y^2 + y + (x^2 + 1)/x)^2 + sage: I.is_prime() + False + sage: J = I.factor()[0][0] + sage: J.is_prime() + True + """ + return self._ideal.is_prime() + + @cached_method + def prime_below(self): + """ + Return the prime of the base order that underlies this prime ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(3^2)); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(1/x) + sage: I.factor() + (Ideal (1/x^3*y^2) of Maximal infinite order of Function field + in y defined by y^3 + y^2 + 2*x^4)^3 + sage: J = I.factor()[0][0] + sage: J.is_prime() + True + sage: J.prime_below() + Ideal (1/x) of Maximal infinite order of Rational function field + in x over Finite Field in z2 of size 3^2 + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(1/x) + sage: I.factor() + (Ideal (1/x*y) of Maximal infinite order of Function field in y + defined by y^2 + y + (x^2 + 1)/x)^2 + sage: J = I.factor()[0][0] + sage: J.is_prime() + True + sage: J.prime_below() + Ideal (1/x) of Maximal infinite order of Rational function field in x + over Finite Field of size 2 + """ + if not self.is_prime(): + raise TypeError("not a prime ideal") + + F = self.ring().fraction_field() + K = F.base_field() + return K.maximal_order_infinite().prime_ideal() + + def valuation(self, ideal): + """ + Return the valuation of ``ideal`` with respect to this prime ideal. + + INPUT: + + - ``ideal`` -- fractional ideal + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(y) + sage: [f.valuation(I) for f,_ in I.factor()] + [-1] + """ + if not self.is_prime(): + raise TypeError("not a prime ideal") + + return self._ideal.valuation(self.ring()._to_iF(ideal)) + + def _factor(self): + """ + Return factorization of the ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: Oinf = F.maximal_order_infinite() + sage: f = 1/x + sage: I = Oinf.ideal(f) + sage: I._factor() + [(Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1/x^2*y + 1) of Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2, + 1), + (Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1) of Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2, + 1)] + """ + if self._ideal.is_prime.is_in_cache() and self._ideal.is_prime(): + return [(self, 1)] + + O = self.ring() + factors = [] + for iprime, exp in O._to_iF(self).factor(): + prime = FunctionFieldIdealInfinite_polymod(O, iprime) + factors.append((prime, exp)) + return factors diff --git a/src/sage/rings/function_field/ideal_rational.py b/src/sage/rings/function_field/ideal_rational.py new file mode 100644 index 00000000000..e6abe1ff605 --- /dev/null +++ b/src/sage/rings/function_field/ideal_rational.py @@ -0,0 +1,628 @@ +r""" +Ideals of function fields: rational +""" + +# **************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2017-2021 Kwankyu Lee +# 2018 Frรฉdรฉric Chapoton +# 2019 Brent Baccala +# 2021 Jonathan Kliem +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.structure.richcmp import richcmp +from sage.rings.infinity import infinity + +from .ideal import FunctionFieldIdeal, FunctionFieldIdealInfinite + + +class FunctionFieldIdeal_rational(FunctionFieldIdeal): + """ + Fractional ideals of the maximal order of a rational function field. + + INPUT: + + - ``ring`` -- the maximal order of the rational function field. + + - ``gen`` -- generator of the ideal, an element of the function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal(1/(x^2+x)); I + Ideal (1/(x^2 + x)) of Maximal order of Rational function field in x over Rational Field + """ + def __init__(self, ring, gen): + """ + Initialize. + + TESTS:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal(1/(x^2+x)) + sage: TestSuite(I).run() + """ + FunctionFieldIdeal.__init__(self, ring) + self._gen = gen + + def __hash__(self): + """ + Return the hash computed from the data. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal(1/(x^2+x)) + sage: d = { I: 1, I^2: 2 } + """ + return hash( (self._ring, self._gen) ) + + def __contains__(self, element): + """ + Test if ``element`` is in this ideal. + + INPUT: + + - ``element`` -- element of the function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal(1/(x+1)) + sage: x in I + True + """ + return (element / self._gen) in self._ring + + def _richcmp_(self, other, op): + """ + Compare the element with the other element with respect + to the comparison operator. + + INPUT: + + - ``other`` -- element + + - ``op`` -- comparison operator + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal(x, x^2 + 1) + sage: J = O.ideal(x^2 + x + 1, x) + sage: I == J + True + sage: I = O.ideal(x) + sage: J = O.ideal(x + 1) + sage: I < J + True + """ + return richcmp(self._gen, other._gen, op) + + def _add_(self, other): + """ + Add this ideal with the ``other`` ideal. + + INPUT: + + - ``other`` -- ideal + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal(x, x^2 + 1) + sage: J = O.ideal(x^2 + x + 1, x) + sage: I + J == J + I + True + """ + return self._ring.ideal([self._gen, other._gen]) + + def _mul_(self, other): + """ + Multiply this ideal with the ``other`` ideal. + + INPUT: + + - ``other`` -- ideal + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal(x, x^2 + x) + sage: J = O.ideal(x^2, x) + sage: I * J == J * I + True + """ + return self._ring.ideal([self._gen * other._gen]) + + def _acted_upon_(self, other, on_left): + """ + Multiply ``other`` with this ideal on the right. + + INPUT: + + - ``other`` -- ideal + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal(x^3 + x^2) + sage: 2 * I + Ideal (x^3 + x^2) of Maximal order of Rational function field in x over Rational Field + sage: x * I + Ideal (x^4 + x^3) of Maximal order of Rational function field in x over Rational Field + """ + return self._ring.ideal([other * self._gen]) + + def __invert__(self): + """ + Return the ideal inverse of this fractional ideal. + + EXAMPLES:: + + sage: F.<x> = FunctionField(QQ) + sage: O = F.maximal_order() + sage: I = O.ideal(x/(x^2+1)) + sage: ~I + Ideal ((x^2 + 1)/x) of Maximal order of Rational function field + in x over Rational Field + """ + return self._ring.ideal([~(self._gen)]) + + def denominator(self): + """ + Return the denominator of this fractional ideal. + + EXAMPLES:: + + sage: F.<x> = FunctionField(QQ) + sage: O = F.maximal_order() + sage: I = O.ideal(x/(x^2+1)) + sage: I.denominator() + x^2 + 1 + """ + return self._gen.denominator() + + def is_prime(self): + """ + Return ``True`` if this is a prime ideal. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal(x^3 + x^2) + sage: [f.is_prime() for f,m in I.factor()] # needs sage.libs.pari + [True, True] + """ + return self._gen.denominator() == 1 and self._gen.numerator().is_prime() + + @cached_method + def module(self): + """ + Return the module, that is the ideal viewed as a module over the ring. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal(x^3 + x^2) + sage: I.module() # needs sage.modules + Free module of degree 1 and rank 1 over Maximal order of Rational + function field in x over Rational Field + Echelon basis matrix: + [x^3 + x^2] + sage: J = 0*I + sage: J.module() # needs sage.modules + Free module of degree 1 and rank 0 over Maximal order of Rational + function field in x over Rational Field + Echelon basis matrix: + [] + """ + V, fr, to = self.ring().fraction_field().vector_space() + return V.span([to(g) for g in self.gens()], base_ring=self.ring()) + + def gen(self): + """ + Return the unique generator of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)) + sage: O = K.maximal_order() + sage: I = O.ideal(x^2 + x) + sage: I.gen() + x^2 + x + """ + return self._gen + + def gens(self): + """ + Return the tuple of the unique generator of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)) + sage: O = K.maximal_order() + sage: I = O.ideal(x^2 + x) + sage: I.gens() + (x^2 + x,) + """ + return (self._gen,) + + def gens_over_base(self): + """ + Return the generator of this ideal as a rank one module over the maximal + order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)) + sage: O = K.maximal_order() + sage: I = O.ideal(x^2 + x) + sage: I.gens_over_base() + (x^2 + x,) + """ + return (self._gen,) + + def valuation(self, ideal): + """ + Return the valuation of the ideal at this prime ideal. + + INPUT: + + - ``ideal`` -- fractional ideal + + EXAMPLES:: + + sage: F.<x> = FunctionField(QQ) + sage: O = F.maximal_order() + sage: I = O.ideal(x^2*(x^2+x+1)^3) + sage: [f.valuation(I) for f,_ in I.factor()] # needs sage.libs.pari + [2, 3] + """ + if not self.is_prime(): + raise TypeError("not a prime ideal") + + O = self.ring() + d = ideal.denominator() + return self._valuation(d*ideal) - self._valuation(O.ideal(d)) + + def _valuation(self, ideal): + """ + Return the valuation of the integral ideal at this prime ideal. + + INPUT: + + - ``ideal`` -- ideal + + EXAMPLES:: + + sage: F.<x> = FunctionField(QQ) + sage: O = F.maximal_order() + sage: p = O.ideal(x) + sage: p.valuation(O.ideal(x + 1)) # indirect doctest # needs sage.libs.pari + 0 + sage: p.valuation(O.ideal(x^2)) # indirect doctest # needs sage.libs.pari + 2 + sage: p.valuation(O.ideal(1/x^3)) # indirect doctest # needs sage.libs.pari + -3 + sage: p.valuation(O.ideal(0)) # indirect doctest # needs sage.libs.pari + +Infinity + """ + return ideal.gen().valuation(self.gen()) + + def _factor(self): + """ + Return the list of prime and multiplicity pairs of the + factorization of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)) + sage: O = K.maximal_order() + sage: I = O.ideal(x^3*(x+1)^2) + sage: I.factor() # indirect doctest + (Ideal (x) of Maximal order of Rational function field in x + over Finite Field in z2 of size 2^2)^3 * + (Ideal (x + 1) of Maximal order of Rational function field in x + over Finite Field in z2 of size 2^2)^2 + """ + return [(self.ring().ideal(f), m) for f, m in self._gen.factor()] + + +class FunctionFieldIdealInfinite_rational(FunctionFieldIdealInfinite): + """ + Fractional ideal of the maximal order of rational function field. + + INPUT: + + - ``ring`` -- infinite maximal order + + - ``gen``-- generator + + Note that the infinite maximal order is a principal ideal domain. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: Oinf.ideal(x) + Ideal (x) of Maximal infinite order of Rational function field in x over Finite Field of size 2 + """ + def __init__(self, ring, gen): + """ + Initialize. + + TESTS:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal(x) + sage: TestSuite(I).run() + """ + FunctionFieldIdealInfinite.__init__(self, ring) + self._gen = gen + + def __hash__(self): + """ + Return the hash of this fractional ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal(x) + sage: J = Oinf.ideal(1/x) + sage: d = { I: 1, J: 2 } + """ + return hash( (self.ring(), self._gen) ) + + def __contains__(self, element): + """ + Test if ``element`` is in this ideal. + + INPUT: + + - ``element`` -- element of the function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order_infinite() + sage: I = O.ideal(1/(x+1)) + sage: x in I + False + sage: 1/x in I + True + sage: x/(x+1) in I + False + sage: 1/(x*(x+1)) in I + True + """ + return (element / self._gen) in self._ring + + def _richcmp_(self, other, op): + """ + Compare this ideal and ``other`` with respect to ``op``. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal(x + 1) + sage: J = Oinf.ideal(x^2 + x) + sage: I + J == J + True + """ + return richcmp(self._gen, other._gen, op) + + def _add_(self, other): + """ + Add this ideal with the other ideal. + + INPUT: + + - ``other`` -- ideal + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal(x/(x^2+1)) + sage: J = Oinf.ideal(1/(x+1)) + sage: I + J + Ideal (1/x) of Maximal infinite order of Rational function field + in x over Finite Field of size 2 + """ + return self._ring.ideal([self._gen, other._gen]) + + def _mul_(self, other): + """ + Multiply this ideal with the ``other`` ideal. + + INPUT: + + - ``other`` -- ideal + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal(x/(x^2+1)) + sage: J = Oinf.ideal(1/(x+1)) + sage: I * J + Ideal (1/x^2) of Maximal infinite order of Rational function field + in x over Finite Field of size 2 + """ + return self._ring.ideal([self._gen * other._gen]) + + def _acted_upon_(self, other, on_left): + """ + Multiply this ideal with the ``other`` ideal. + + INPUT: + + - ``other`` -- ideal + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal(x/(x^2+1)) + sage: x * I + Ideal (1) of Maximal infinite order of Rational function field + in x over Finite Field of size 2 + """ + return self._ring.ideal([other * self._gen]) + + def __invert__(self): + """ + Return the multiplicative inverse of this ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal(x/(x^2 + 1)) + sage: ~I # indirect doctest + Ideal (x) of Maximal infinite order of Rational function field in x + over Finite Field of size 2 + """ + return self._ring.ideal([~self._gen]) + + def is_prime(self): + """ + Return ``True`` if this ideal is a prime ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal(x/(x^2 + 1)) + sage: I.is_prime() + True + """ + x = self._ring.fraction_field().gen() + return self._gen == 1/x + + def gen(self): + """ + Return the generator of this principal ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal((x+1)/(x^3+x), (x^2+1)/x^4) + sage: I.gen() + 1/x^2 + """ + return self._gen + + def gens(self): + """ + Return the generator of this principal ideal. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal((x+1)/(x^3+x), (x^2+1)/x^4) + sage: I.gens() + (1/x^2,) + """ + return (self._gen,) + + def gens_over_base(self): + """ + Return the generator of this ideal as a rank one module + over the infinite maximal order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal((x+1)/(x^3+x), (x^2+1)/x^4) + sage: I.gens_over_base() + (1/x^2,) + """ + return (self._gen,) + + def valuation(self, ideal): + """ + Return the valuation of ``ideal`` at this prime ideal. + + INPUT: + + - ``ideal`` -- fractional ideal + + EXAMPLES:: + + sage: F.<x> = FunctionField(QQ) + sage: O = F.maximal_order_infinite() + sage: p = O.ideal(1/x) + sage: p.valuation(O.ideal(x/(x+1))) + 0 + sage: p.valuation(O.ideal(0)) + +Infinity + """ + if not self.is_prime(): + raise TypeError("not a prime ideal") + + f = ideal.gen() + if f == 0: + return infinity + else: + return f.denominator().degree() - f.numerator().degree() + + def _factor(self): + """ + Return the factorization of this ideal into prime ideals. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal((x+1)/(x^3+1)) + sage: I._factor() + [(Ideal (1/x) of Maximal infinite order of Rational function field in x + over Finite Field of size 2, 2)] + """ + g = ~(self.ring().fraction_field().gen()) + m = self._gen.denominator().degree() - self._gen.numerator().degree() + if m == 0: + return [] + else: + return [(self.ring().ideal(g), m)] diff --git a/src/sage/rings/function_field/maps.py b/src/sage/rings/function_field/maps.py index fbf3ef9e15d..85377f1c894 100644 --- a/src/sage/rings/function_field/maps.py +++ b/src/sage/rings/function_field/maps.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Morphisms of function fields @@ -10,6 +9,8 @@ sage: K.hom(1/x) Function Field endomorphism of Rational function field in x over Rational Field Defn: x |--> 1/x + + sage: # needs sage.rings.function_field sage: L.<y> = K.extension(y^2 - x) sage: K.hom(y) Function Field morphism: @@ -25,15 +26,6 @@ ... ValueError: invalid morphism -For global function fields, which have positive characteristics, the higher -derivation is available:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y>=K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) - sage: h = L.higher_derivation() - sage: h(y^2, 2) - ((x^7 + 1)/x^2)*y^2 + x^3*y - AUTHORS: - William Stein (2010): initial version @@ -44,9 +36,16 @@ - Kwankyu Lee (2017-04-30): added higher derivations and completions """ + # **************************************************************************** -# Copyright (C) 2010 William Stein <wstein@gmail.com> -# Copyright (C) 2011-2017 Julian Rรผth <julian.rueth@gmail.com> +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011-2017 Julian Rรผth <julian.rueth@gmail.com> +# 2017 Alyson Deines +# 2017-2019 Kwankyu Lee +# 2018-2019 Travis Scrimshaw +# 2019 Brent Baccala +# 2022 Xavier Caruso +# 2022 Frรฉdรฉric Chapoton # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -54,1072 +53,18 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.categories.morphism import Morphism, SetMorphism -from sage.categories.map import Map from sage.categories.homset import Hom -from sage.categories.sets_cat import Sets - +from sage.categories.map import Map +from sage.categories.morphism import Morphism, SetMorphism +from sage.misc.lazy_import import lazy_import from sage.rings.infinity import infinity from sage.rings.morphism import RingHomomorphism -from sage.rings.derivation import RingDerivationWithoutTwist - -from sage.modules.free_module_element import vector - -from sage.functions.other import binomial - -from sage.matrix.constructor import matrix - - -class FunctionFieldDerivation(RingDerivationWithoutTwist): - r""" - Base class for derivations on function fields. - - A derivation on `R` is a map `R \to R` with - `D(\alpha+\beta)=D(\alpha)+D(\beta)` and `D(\alpha\beta)=\beta - D(\alpha)+\alpha D(\beta)` for all `\alpha,\beta\in R`. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: d = K.derivation() - sage: d - d/dx - """ - def __init__(self, parent): - r""" - Initialize a derivation. - - INPUT: - - - ``parent`` -- the differential module in which this - derivation lives - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: d = K.derivation() - sage: TestSuite(d).run() - """ - RingDerivationWithoutTwist.__init__(self, parent) - self.__field = parent.domain() - - def is_injective(self) -> bool: - r""" - Return ``False`` since a derivation is never injective. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: d = K.derivation() - sage: d.is_injective() - False - """ - return False - - def _rmul_(self, factor): - """ - Return the product of this derivation by the scalar ``factor``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: d = K.derivation() - sage: d - d/dx - sage: x * d - x*d/dx - """ - return self._lmul_(factor) - - -class FunctionFieldDerivation_rational(FunctionFieldDerivation): - """ - Derivations on rational function fields. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K.derivation() - d/dx - """ - def __init__(self, parent, u=None): - """ - Initialize a derivation. - - INPUT: - - - ``parent`` -- the parent of this derivation - - - ``u`` -- a parameter describing the derivation - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: d = K.derivation() - sage: TestSuite(d).run() - - The parameter ``u`` can be the name of the variable:: - - sage: K.derivation(x) - d/dx - - or a list of length one whose unique element is the image - of the generator of the underlying function field:: - - sage: K.derivation([x^2]) - x^2*d/dx - """ - FunctionFieldDerivation.__init__(self, parent) - if u is None or u == parent.domain().gen(): - self._u = parent.codomain().one() - elif u == 0 or isinstance(u, (list, tuple)): - if u == 0 or len(u) == 0: - self._u = parent.codomain().zero() - elif len(u) == 1: - self._u = parent.codomain()(u[0]) - else: - raise ValueError("the length does not match") - else: - raise ValueError("you must pass in either a name of a variable or a list of coefficients") - - def _call_(self, x): - """ - Compute the derivation of ``x``. - - INPUT: - - - ``x`` -- element of the rational function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: d = K.derivation() - sage: d(x) # indirect doctest - 1 - sage: d(x^3) - 3*x^2 - sage: d(1/x) - -1/x^2 - """ - f = x.numerator() - g = x.denominator() - numerator = f.derivative() * g - f * g.derivative() - if numerator.is_zero(): - return self.codomain().zero() - else: - v = numerator / g**2 - defining_morphism = self.parent()._defining_morphism - if defining_morphism is not None: - v = defining_morphism(v) - return self._u * v - - def _add_(self, other): - """ - Return the sum of this derivation and ``other``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: d = K.derivation() - sage: d + d - 2*d/dx - """ - return type(self)(self.parent(), [self._u + other._u]) - - def _lmul_(self, factor): - """ - Return the product of this derivation by the scalar ``factor``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: d = K.derivation() - sage: d - d/dx - sage: x * d - x*d/dx - """ - return type(self)(self.parent(), [factor * self._u]) - - -class FunctionFieldDerivation_separable(FunctionFieldDerivation): - """ - Derivations of separable extensions. - - EXAMPLES:: - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: L.derivation() - d/dx - """ - def __init__(self, parent, d): - """ - Initialize a derivation. - - INPUT: - - - ``parent`` -- the parent of this derivation - - - ``d`` -- a variable name or a derivation over - the base field (or something capable to create - such a derivation) - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: d = L.derivation() - sage: TestSuite(d).run() - - sage: L.derivation(y) # d/dy - 2*y*d/dx - - sage: dK = K.derivation([x]); dK - x*d/dx - sage: L.derivation(dK) - x*d/dx - """ - FunctionFieldDerivation.__init__(self, parent) - L = parent.domain() - C = parent.codomain() - dm = parent._defining_morphism - u = L.gen() - if d == L.gen(): - d = parent._base_derivation(None) - f = L.polynomial().change_ring(L) - coeff = -f.derivative()(u) / f.map_coefficients(d)(u) - if dm is not None: - coeff = dm(coeff) - self._d = parent._base_derivation([coeff]) - self._gen_image = C.one() - else: - if isinstance(d, RingDerivationWithoutTwist) and d.domain() is L.base_ring(): - self._d = d - else: - self._d = d = parent._base_derivation(d) - f = L.polynomial() - if dm is None: - denom = f.derivative()(u) - else: - u = dm(u) - denom = f.derivative().map_coefficients(dm, new_base_ring=C)(u) - num = f.map_coefficients(d, new_base_ring=C)(u) - self._gen_image = -num / denom - - def _call_(self, x): - r""" - Evaluate the derivation on ``x``. - - INPUT: - - - ``x`` -- element of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: d = L.derivation() - sage: d(x) # indirect doctest - 1 - sage: d(y) - 1/2/x*y - sage: d(y^2) - 1 - """ - parent = self.parent() - if x.is_zero(): - return parent.codomain().zero() - x = x._x - y = parent.domain().gen() - dm = parent._defining_morphism - tmp1 = x.map_coefficients(self._d, new_base_ring=parent.codomain()) - tmp2 = x.derivative()(y) - if dm is not None: - tmp2 = dm(tmp2) - y = dm(y) - return tmp1(y) + tmp2 * self._gen_image - - def _add_(self, other): - """ - Return the sum of this derivation and ``other``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: d = L.derivation() - sage: d - d/dx - sage: d + d - 2*d/dx - """ - return type(self)(self.parent(), self._d + other._d) - - def _lmul_(self, factor): - """ - Return the product of this derivation by the scalar ``factor``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: d = L.derivation() - sage: d - d/dx - sage: y * d - y*d/dx - """ - return type(self)(self.parent(), factor * self._d) - - -class FunctionFieldDerivation_inseparable(FunctionFieldDerivation): - def __init__(self, parent, u=None): - r""" - Initialize this derivation. - - INPUT: - - - ``parent`` -- the parent of this derivation - - ``u`` -- a parameter describing the derivation - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: d = L.derivation() - - This also works for iterated non-monic extensions:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - 1/x) - sage: R.<z> = L[] - sage: M.<z> = L.extension(z^2*y - x^3) - sage: M.derivation() - d/dz - - We can also create a multiple of the canonical derivation:: - - sage: M.derivation([x]) - x*d/dz - """ - FunctionFieldDerivation.__init__(self, parent) - if u is None: - self._u = parent.codomain().one() - elif u == 0 or isinstance(u, (list, tuple)): - if u == 0 or len(u) == 0: - self._u = parent.codomain().zero() - elif len(u) == 1: - self._u = parent.codomain()(u[0]) - else: - raise ValueError("the length does not match") - else: - raise ValueError("you must pass in either a name of a variable or a list of coefficients") - - def _call_(self, x): - r""" - Evaluate the derivation on ``x``. - - INPUT: - - - ``x`` -- an element of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: d = L.derivation() - sage: d(x) # indirect doctest - 0 - sage: d(y) - 1 - sage: d(y^2) - 0 - - """ - if x.is_zero(): - return self.codomain().zero() - parent = self.parent() - return self._u * parent._d(parent._t(x)) - - def _add_(self, other): - """ - Return the sum of this derivation and ``other``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(3)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^3 - x) - sage: d = L.derivation() - sage: d - d/dy - sage: d + d - 2*d/dy - """ - return type(self)(self.parent(), [self._u + other._u]) - - def _lmul_(self, factor): - """ - Return the product of this derivation by the scalar ``factor``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x) - sage: d = L.derivation() - sage: d - d/dy - sage: y * d - y*d/dy - """ - return type(self)(self.parent(), [factor * self._u]) - - -class FunctionFieldHigherDerivation(Map): - """ - Base class of higher derivations on function fields. - - INPUT: - - - ``field`` -- function field on which the derivation operates - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: F.higher_derivation() - Higher derivation map: - From: Rational function field in x over Finite Field of size 2 - To: Rational function field in x over Finite Field of size 2 - """ - def __init__(self, field): - """ - Initialize. - - TESTS:: - - sage: F.<x> = FunctionField(GF(4)) - sage: h = F.higher_derivation() - sage: TestSuite(h).run(skip='_test_category') - """ - Map.__init__(self, Hom(field, field, Sets())) - self._field = field - # elements of a prime finite field do not have pth_root method - if field.constant_base_field().is_prime_field(): - self._pth_root_func = _pth_root_in_prime_field - else: - self._pth_root_func = _pth_root_in_finite_field - - def _repr_type(self) -> str: - """ - Return a string containing the type of the map. - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: h = F.higher_derivation() - sage: h # indirect doctest - Higher derivation map: - From: Rational function field in x over Finite Field of size 2 - To: Rational function field in x over Finite Field of size 2 - """ - return 'Higher derivation' - - def __eq__(self, other) -> bool: - """ - Test if ``self`` equals ``other``. - - TESTS:: - - sage: F.<x> = FunctionField(GF(2)) - sage: h = F.higher_derivation() - sage: loads(dumps(h)) == h - True - """ - if isinstance(other, FunctionFieldHigherDerivation): - return self._field == other._field - return False - - -def _pth_root_in_prime_field(e): - """ - Return the `p`-th root of element ``e`` in a prime finite field. - - TESTS:: - - sage: from sage.rings.function_field.maps import _pth_root_in_prime_field - sage: p = 5 - sage: F.<a> = GF(p) - sage: e = F.random_element() - sage: _pth_root_in_prime_field(e)^p == e - True - """ - return e - - -def _pth_root_in_finite_field(e): - """ - Return the `p`-th root of element ``e`` in a finite field. - - TESTS:: - - sage: from sage.rings.function_field.maps import _pth_root_in_finite_field - sage: p = 3 - sage: F.<a> = GF(p^2) - sage: e = F.random_element() - sage: _pth_root_in_finite_field(e)^p == e - True - """ - return e.pth_root() - - -class RationalFunctionFieldHigherDerivation_global(FunctionFieldHigherDerivation): - """ - Higher derivations of rational function fields over finite fields. - - INPUT: - - - ``field`` -- function field on which the derivation operates - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: h = F.higher_derivation() - sage: h - Higher derivation map: - From: Rational function field in x over Finite Field of size 2 - To: Rational function field in x over Finite Field of size 2 - sage: h(x^2,2) - 1 - """ - def __init__(self, field): - """ - Initialize. - - TESTS:: - - sage: F.<x> = FunctionField(GF(2)) - sage: h = F.higher_derivation() - sage: TestSuite(h).run(skip='_test_category') - """ - FunctionFieldHigherDerivation.__init__(self, field) - - self._p = field.characteristic() - self._separating_element = field.gen() - - def _call_with_args(self, f, args=(), kwds={}): - """ - Call the derivation with args and kwds. - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: h = F.higher_derivation() - sage: h(x^2,2) # indirect doctest - 1 - """ - return self._derive(f, *args, **kwds) - - def _derive(self, f, i, separating_element=None): - """ - Return the `i`-th derivative of ``f`` with respect to the - separating element. - - This implements Hess' Algorithm 26 in [Hes2002b]_. - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: h = F.higher_derivation() - sage: h._derive(x^3,0) - x^3 - sage: h._derive(x^3,1) - x^2 - sage: h._derive(x^3,2) - x - sage: h._derive(x^3,3) - 1 - sage: h._derive(x^3,4) - 0 - """ - F = self._field - p = self._p - - if separating_element is None: - x = self._separating_element - - def derivative(f): - return f.derivative() - else: - x = separating_element - xderinv = ~(x.derivative()) - - def derivative(f): - return xderinv * f.derivative() - - prime_power_representation = self._prime_power_representation - - def derive(f, i): - # Step 1: zero-th derivative - if i == 0: - return f - # Step 2: - s = i % p - r = i // p - # Step 3: - e = f - while s > 0: - e = derivative(e) / F(s) - s -= 1 - # Step 4: - if r == 0: - return e - else: - # Step 5: - lambdas = prime_power_representation(e, x) - # Step 6 and 7: - der = 0 - for i in range(p): - mu = derive(lambdas[i], r) - der += mu**p * x**i - return der - - return derive(f, i) - - def _prime_power_representation(self, f, separating_element=None): - """ - Return `p`-th power representation of the element ``f``. - - Here `p` is the characteristic of the function field. - - This implements Hess' Algorithm 25. - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: h = F.higher_derivation() - sage: h._prime_power_representation(x^2 + x + 1) - [x + 1, 1] - sage: x^2 + x + 1 == _[0]^2 + _[1]^2 * x - True - """ - F = self._field - p = self._p - - if separating_element is None: - x = self._separating_element - - def derivative(f): - return f.derivative() - else: - x = separating_element - xderinv = ~(x.derivative()) - - def derivative(f): - return xderinv * f.derivative() - - # Step 1: - a = [f] - aprev = f - j = 1 - while j < p: - aprev = derivative(aprev) / F(j) - a.append(aprev) - j += 1 - # Step 2: - b = a - j = p - 2 - while j >= 0: - b[j] -= sum(binomial(i, j) * b[i] * x**(i - j) - for i in range(j + 1, p)) - j -= 1 - # Step 3 - return [self._pth_root(c) for c in b] - - def _pth_root(self, c): - """ - Return the `p`-th root of the rational function ``c``. - - INPUT: - - - ``c`` -- rational function - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: h = F.higher_derivation() - sage: h._pth_root((x^2+1)^2) - x^2 + 1 - """ - K = self._field - p = self._p - - R = K._field.ring() - - poly = c.numerator() - num = R([self._pth_root_func(poly[i]) - for i in range(0, poly.degree() + 1, p)]) - poly = c.denominator() - den = R([self._pth_root_func(poly[i]) - for i in range(0, poly.degree() + 1, p)]) - return K.element_class(K, num / den) - - -class FunctionFieldHigherDerivation_global(FunctionFieldHigherDerivation): - """ - Higher derivations of global function fields. - - INPUT: - - - ``field`` -- function field on which the derivation operates - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: h = L.higher_derivation() - sage: h - Higher derivation map: - From: Function field in y defined by y^3 + x^3*y + x - To: Function field in y defined by y^3 + x^3*y + x - sage: h(y^2, 2) - ((x^7 + 1)/x^2)*y^2 + x^3*y - """ - - def __init__(self, field): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: h = L.higher_derivation() - sage: TestSuite(h).run(skip=['_test_category']) - """ - FunctionFieldHigherDerivation.__init__(self, field) - - self._p = field.characteristic() - self._separating_element = field(field.base_field().gen()) - - p = field.characteristic() - y = field.gen() - - # matrix for pth power map; used in _prime_power_representation method - self.__pth_root_matrix = matrix([(y**(i * p)).list() - for i in range(field.degree())]).transpose() - - # cache computed higher derivatives to speed up later computations - self._cache = {} - - def _call_with_args(self, f, args, kwds): - """ - Call the derivation with ``args`` and ``kwds``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: h = L.higher_derivation() - sage: h(y^2,2) # indirect doctest - ((x^7 + 1)/x^2)*y^2 + x^3*y - """ - return self._derive(f, *args, **kwds) - - def _derive(self, f, i, separating_element=None): - """ - Return ``i``-th derivative of ``f`` with respect to the separating - element. - - This implements Hess' Algorithm 26 in [Hes2002b]_. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: h = L.higher_derivation() - sage: y^3 - x^3*y + x - sage: h._derive(y^3,0) - x^3*y + x - sage: h._derive(y^3,1) - x^4*y^2 + 1 - sage: h._derive(y^3,2) - x^10*y^2 + (x^8 + x)*y - sage: h._derive(y^3,3) - (x^9 + x^2)*y^2 + x^7*y - sage: h._derive(y^3,4) - (x^22 + x)*y^2 + ((x^21 + x^14 + x^7 + 1)/x)*y - """ - F = self._field - p = self._p - frob = F.frobenius_endomorphism() # p-th power map - - if separating_element is None: - x = self._separating_element - - def derivative(f): - return f.derivative() - else: - x = separating_element - xderinv = ~(x.derivative()) - - def derivative(f): - return xderinv * f.derivative() - - try: - cache = self._cache[separating_element] - except KeyError: - cache = self._cache[separating_element] = {} - - def derive(f, i): - # Step 1: zero-th derivative - if i == 0: - return f - - # Step 1.5: use cached result if available - try: - return cache[f, i] - except KeyError: - pass - - # Step 2: - s = i % p - r = i // p - # Step 3: - e = f - while s > 0: - e = derivative(e) / F(s) - s -= 1 - # Step 4: - if r == 0: - der = e - else: - # Step 5: inlined self._prime_power_representation - a = [e] - aprev = e - j = 1 - while j < p: - aprev = derivative(aprev) / F(j) - a.append(aprev) - j += 1 - b = a - j = p - 2 - while j >= 0: - b[j] -= sum(binomial(k, j) * b[k] * x**(k - j) - for k in range(j + 1, p)) - j -= 1 - lambdas = [self._pth_root(c) for c in b] - - # Step 6 and 7: - der = 0 - xpow = 1 - for k in range(p): - mu = derive(lambdas[k], r) - der += frob(mu) * xpow - xpow *= x - - cache[f, i] = der - return der - - return derive(f, i) - - def _prime_power_representation(self, f, separating_element=None): - """ - Return `p`-th power representation of the element ``f``. - - Here `p` is the characteristic of the function field. - - This implements Hess' Algorithm 25 in [Hes2002b]_. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: h = L.higher_derivation() - sage: b = h._prime_power_representation(y) - sage: y == b[0]^2 + b[1]^2 * x - True - """ - F = self._field - p = self._p - - if separating_element is None: - x = self._separating_element - - def derivative(f): - return f.derivative() - else: - x = separating_element - xderinv = ~(x.derivative()) - - def derivative(f): - return xderinv * f.derivative() - - # Step 1: - a = [f] - aprev = f - j = 1 - while j < p: - aprev = derivative(aprev) / F(j) - a.append(aprev) - j += 1 - # Step 2: - b = a - j = p - 2 - while j >= 0: - b[j] -= sum(binomial(i, j) * b[i] * x**(i - j) - for i in range(j + 1, p)) - j -= 1 - # Step 3 - return [self._pth_root(c) for c in b] - - def _pth_root(self, c): - """ - Return the `p`-th root of function field element ``c``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: h = L.higher_derivation() - sage: h._pth_root((x^2 + y^2)^2) - y^2 + x^2 - """ - K = self._field.base_field() # rational function field - p = self._p - - coeffs = [] - for d in self.__pth_root_matrix.solve_right(vector(c.list())): - poly = d.numerator() - num = K([self._pth_root_func(poly[i]) - for i in range(0, poly.degree() + 1, p)]) - poly = d.denominator() - den = K([self._pth_root_func(poly[i]) - for i in range(0, poly.degree() + 1, p)]) - coeffs.append(num / den) - return self._field(coeffs) - - -class FunctionFieldHigherDerivation_char_zero(FunctionFieldHigherDerivation): - """ - Higher derivations of function fields of characteristic zero. - - INPUT: - - - ``field`` -- function field on which the derivation operates - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: h = L.higher_derivation() - sage: h - Higher derivation map: - From: Function field in y defined by y^3 + x^3*y + x - To: Function field in y defined by y^3 + x^3*y + x - sage: h(y,1) == -(3*x^2*y+1)/(3*y^2+x^3) - True - sage: h(y^2,1) == -2*y*(3*x^2*y+1)/(3*y^2+x^3) - True - sage: e = L.random_element() - sage: h(h(e,1),1) == 2*h(e,2) - True - sage: h(h(h(e,1),1),1) == 3*2*h(e,3) - True - """ - def __init__(self, field): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: h = L.higher_derivation() - sage: TestSuite(h).run(skip=['_test_category']) - """ - FunctionFieldHigherDerivation.__init__(self, field) - - self._separating_element = field(field.base_field().gen()) - - # cache computed higher derivatives to speed up later computations - self._cache = {} - - def _call_with_args(self, f, args, kwds): - """ - Call the derivation with ``args`` and ``kwds``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: h = L.higher_derivation() - sage: e = L.random_element() - sage: h(h(e,1),1) == 2*h(e,2) # indirect doctest - True - """ - return self._derive(f, *args, **kwds) - - def _derive(self, f, i, separating_element=None): - """ - Return ``i``-th derivative of ``f`` with respect to the separating - element. - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: h = L.higher_derivation() - sage: y^3 - -x^3*y - x - sage: h._derive(y^3,0) - -x^3*y - x - sage: h._derive(y^3,1) - (-21/4*x^4/(x^7 + 27/4))*y^2 + ((-9/2*x^9 - 45/2*x^2)/(x^7 + 27/4))*y + (-9/2*x^7 - 27/4)/(x^7 + 27/4) - """ - F = self._field - - if separating_element is None: - x = self._separating_element - xderinv = 1 - else: - x = separating_element - xderinv = ~(x.derivative()) - - try: - cache = self._cache[separating_element] - except KeyError: - cache = self._cache[separating_element] = {} - - if i == 0: - return f - - try: - return cache[f, i] - except KeyError: - pass - - s = i - e = f - while s > 0: - e = xderinv * e.derivative() / F(s) - s -= 1 - - der = e - - cache[f, i] = der - return der +lazy_import("sage.rings.function_field.derivations", ( + "FunctionFieldDerivation", + "FunctionFieldHigherDerivation", +), deprecation=35230) class FunctionFieldVectorSpaceIsomorphism(Morphism): @@ -1128,6 +73,7 @@ class FunctionFieldVectorSpaceIsomorphism(Morphism): EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space() @@ -1140,6 +86,7 @@ def _repr_(self) -> str: EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space() @@ -1163,6 +110,7 @@ def is_injective(self) -> bool: EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space() @@ -1177,6 +125,7 @@ def is_surjective(self) -> bool: EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space() @@ -1200,18 +149,18 @@ def _richcmp_(self, other, op): sage: K = QQ['x'].fraction_field() sage: L = K.function_field() sage: f = K.coerce_map_from(L) + sage: f == f + True + sage: # needs sage.rings.number_field sage: K = QQbar['x'].fraction_field() sage: L = K.function_field() sage: g = K.coerce_map_from(L) - sage: f == g False - sage: f == f - True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented from sage.structure.richcmp import richcmp @@ -1243,6 +192,7 @@ class MapVectorSpaceToFunctionField(FunctionFieldVectorSpaceIsomorphism): EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space(); f @@ -1254,6 +204,7 @@ def __init__(self, V, K): """ EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space(); type(f) @@ -1274,20 +225,22 @@ def _call_(self, v): EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ) sage: R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space() - sage: f(x*V.0 + (1/x^3)*V.1) # indirect doctest + sage: f(x*V.0 + (1/x^3)*V.1) # indirect doctest 1/x^3*y + x TESTS: Test that this map is a bijection for some random inputs:: + sage: # needs sage.modules sage.rings.function_field sage: R.<z> = L[] sage: M.<z> = L.extension(z^3 - y - x) - sage: for F in [K,L,M]: + sage: for F in [K, L, M]: ....: for base in F._intermediate_fields(K): ....: V, f, t = F.vector_space(base) ....: for i in range(100): @@ -1318,6 +271,7 @@ def domain(self): EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space() @@ -1332,6 +286,7 @@ def codomain(self): EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space() @@ -1347,6 +302,7 @@ class MapFunctionFieldToVectorSpace(FunctionFieldVectorSpaceIsomorphism): EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space(); t @@ -1366,6 +322,7 @@ def __init__(self, K, V): EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space() @@ -1383,19 +340,21 @@ def _call_(self, x): EXAMPLES:: + sage: # needs sage.modules sage.rings.function_field sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space() - sage: t(x + (1/x^3)*y) # indirect doctest + sage: t(x + (1/x^3)*y) # indirect doctest (x, 1/x^3) TESTS: Test that this map is a bijection for some random inputs:: + sage: # needs sage.modules sage.rings.function_field sage: R.<z> = L[] sage: M.<z> = L.extension(z^3 - y - x) - sage: for F in [K,L,M]: + sage: for F in [K, L, M]: ....: for base in F._intermediate_fields(K): ....: V, f, t = F.vector_space(base) ....: for i in range(100): @@ -1448,6 +407,7 @@ def _repr_type(self) -> str: EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] sage: L.<y> = K.extension(y^3 + 6*x^3 + x) sage: f = L.hom(y*2) @@ -1462,6 +422,7 @@ def _repr_defn(self) -> str: EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] sage: L.<y> = K.extension(y^3 + 6*x^3 + x) sage: f = L.hom(y*2) @@ -1480,6 +441,7 @@ class FunctionFieldMorphism_polymod(FunctionFieldMorphism): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] sage: L.<y> = K.extension(y^3 + 6*x^3 + x) sage: f = L.hom(y*2); f @@ -1496,6 +458,7 @@ def __init__(self, parent, im_gen, base_morphism): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] sage: L.<y> = K.extension(y^3 + 6*x^3 + x) sage: f = L.hom(y*2) @@ -1515,6 +478,7 @@ def _call_(self, x): """ EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] sage: L.<y> = K.extension(y^3 + 6*x^3 + x); f = L.hom(y*2) sage: f(y/x + x^2/(x+1)) # indirect doctest @@ -1550,27 +514,29 @@ def _call_(self, x): """ EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<x> = FunctionField(GF(7)) sage: f = K.hom(1/x); f Function Field endomorphism of Rational function field in x over Finite Field of size 7 Defn: x |--> 1/x - sage: f(x+1) # indirect doctest + sage: f(x + 1) # indirect doctest (x + 1)/x sage: 1/x + 1 (x + 1)/x You can specify a morphism on the base ring:: + sage: # needs sage.rings.number_field sage: Qi = GaussianIntegers().fraction_field() sage: i = Qi.gen() sage: K.<x> = FunctionField(Qi) sage: phi1 = Qi.hom([CC.gen()]) sage: phi2 = Qi.hom([-CC.gen()]) - sage: f = K.hom(CC.pi(),phi1) - sage: f(1+i+x) + sage: f = K.hom(CC.pi(), phi1) + sage: f(1 + i + x) 4.14159265358979 + 1.00000000000000*I - sage: g = K.hom(CC.pi(),phi2) - sage: g(1+i+x) + sage: g = K.hom(CC.pi(), phi2) + sage: g(1 + i + x) 4.14159265358979 - 1.00000000000000*I """ a = x.element() @@ -1619,7 +585,7 @@ def _repr_type(self) -> str: EXAMPLES:: sage: K.<x> = FunctionField(QQ) - sage: QQ.convert_map_from(K) # indirect doctest + sage: QQ.convert_map_from(K) # indirect doctest Conversion map: From: Rational function field in x over Rational Field To: Rational Field @@ -1774,6 +740,7 @@ class FunctionFieldCompletion(Map): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p = L.places_finite()[0] @@ -1796,6 +763,7 @@ class FunctionFieldCompletion(Map): rational such that the residue field is a proper extension of the constant field, you can also specify the generator name of the extension:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: p2 = L.places_finite(2)[0] sage: p2 Place (x^2 + x + 1, x*y + 1) @@ -1812,6 +780,7 @@ def __init__(self, field, place, name=None, prec=None, gen_name=None): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p = L.places_finite()[0] @@ -1850,6 +819,7 @@ def _repr_type(self) -> str: EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p = L.places_finite()[0] @@ -1867,6 +837,7 @@ def _call_(self, f): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p = L.places_finite()[0] @@ -1885,6 +856,7 @@ def _call_with_args(self, f, args, kwds): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p = L.places_finite()[0] @@ -1909,6 +881,7 @@ def _expand(self, f, prec=None): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p = L.places_finite()[0] @@ -1943,6 +916,7 @@ def _expand_lazy(self, f): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p = L.places_finite()[0] @@ -1975,6 +949,7 @@ def default_precision(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p = L.places_finite()[0] @@ -1995,6 +970,7 @@ def _repr_(self) -> str: EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) sage: p = L.places_finite()[0] @@ -2023,10 +999,11 @@ def _repr_(self) -> str: EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(5)); R.<t> = PolynomialRing(K) sage: F.<y> = K.extension(t^2-x^3-1) sage: O = F.maximal_order() - sage: I = O.ideal(x-2) + sage: I = O.ideal(x - 2) sage: D = I.divisor() sage: V, from_V, to_V = D.function_space() sage: from_V @@ -2050,10 +1027,11 @@ def _repr_(self) -> str: EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.function_field sage: K.<x> = FunctionField(GF(5)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^2-x^3-1) + sage: F.<y> = K.extension(t^2 - x^3 - 1) sage: O = F.maximal_order() - sage: I = O.ideal(x-2) + sage: I = O.ideal(x - 2) sage: D = I.divisor() sage: V, from_V, to_V = D.function_space() sage: to_V diff --git a/src/sage/rings/function_field/order.py b/src/sage/rings/function_field/order.py index d27d3c3b452..615cbab3690 100644 --- a/src/sage/rings/function_field/order.py +++ b/src/sage/rings/function_field/order.py @@ -30,8 +30,9 @@ `O` and one maximal infinite order `O_\infty`. There are other non-maximal orders such as equation orders:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(3)); R.<y> = K[] - sage: L.<y> = K.extension(y^3-y-x) + sage: L.<y> = K.extension(y^3 - y - x) sage: O = L.equation_order() sage: 1/y in O False @@ -44,10 +45,11 @@ sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] sage: o = K.maximal_order() - sage: p = o.ideal(x+1) - sage: p.is_prime() + sage: p = o.ideal(x + 1) + sage: p.is_prime() # needs sage.libs.pari True + sage: # needs sage.rings.function_field sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) sage: O = F.maximal_order() sage: O.decomposition(p) @@ -56,7 +58,8 @@ (Ideal (x + 1, (1/(x^3 + x^2 + x))*y^2 + y + 1) of Maximal order of Function field in y defined by y^3 + x^6 + x^4 + x^2, 2, 1)] - sage: p1,relative_degree,ramification_index = O.decomposition(p)[1] + sage: # needs sage.rings.function_field + sage: p1, relative_degree,ramification_index = O.decomposition(p)[1] sage: p1.parent() Monoid of ideals of Maximal order of Function field in y defined by y^3 + x^6 + x^4 + x^2 @@ -68,6 +71,7 @@ When the base constant field is the algebraic field `\QQbar`, the only prime ideals of the maximal order of the rational function field are linear polynomials. :: + sage: # needs sage.rings.function_field sage.rings.number_field sage: K.<x> = FunctionField(QQbar) sage: R.<y> = K[] sage: L.<y> = K.extension(y^2 - (x^3-x^2)) @@ -94,51 +98,25 @@ - Brent Baccala (2019-12-20): support orders in characteristic zero """ -#***************************************************************************** -# Copyright (C) 2010 William Stein <wstein@gmail.com> -# Copyright (C) 2011 Maarten Derickx <m.derickx.student@gmail.com> -# Copyright (C) 2011 Julian Rueth <julian.rueth@gmail.com> + +# **************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2011 Julian Rueth <julian.rueth@gmail.com> +# 2017-2020 Kwankyu Lee +# 2019 Brent Baccala # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** - -from sage.misc.cachefunc import cached_method - -from sage.modules.free_module_element import vector -from sage.arith.functions import lcm -from sage.arith.misc import GCD as gcd - -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.algebras.all import FiniteDimensionalAlgebra - -from sage.rings.qqbar import QQbar -from sage.rings.number_field.number_field_base import NumberField +# **************************************************************************** +from sage.categories.integral_domains import IntegralDomains from sage.structure.parent import Parent from sage.structure.unique_representation import CachedRepresentation, UniqueRepresentation -from sage.categories.integral_domains import IntegralDomains -from sage.categories.principal_ideal_domains import PrincipalIdealDomains -from sage.categories.euclidean_domains import EuclideanDomains - -from sage.matrix.special import block_matrix -from sage.matrix.constructor import matrix - -from .ideal import ( - IdealMonoid, - FunctionFieldIdeal, - FunctionFieldIdeal_module, - FunctionFieldIdeal_rational, - FunctionFieldIdeal_polymod, - FunctionFieldIdeal_global, - FunctionFieldIdealInfinite_module, - FunctionFieldIdealInfinite_rational, - FunctionFieldIdealInfinite_polymod) - -from .hermite_form_polynomial import reversed_hermite_form +from .ideal import IdealMonoid, FunctionFieldIdeal class FunctionFieldOrder_base(CachedRepresentation, Parent): @@ -254,287 +232,6 @@ def _repr_(self): return "Order in {}".format(self._field) -class FunctionFieldOrder_basis(FunctionFieldOrder): - """ - Order given by a basis over the maximal order of the base field. - - INPUT: - - - ``basis`` -- list of elements of the function field - - - ``check`` -- (default: ``True``) if ``True``, check whether the module - that ``basis`` generates forms an order - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order(); O - Order in Function field in y defined by y^4 + x*y + 4*x + 1 - - The basis only defines an order if the module it generates is closed under - multiplication and contains the identity element:: - - sage: K.<x> = FunctionField(QQ) - sage: R.<y> = K[] - sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) - sage: y.is_integral() - False - sage: L.order(y) - Traceback (most recent call last): - ... - ValueError: the module generated by basis (1, y, y^2, y^3, y^4) must be closed under multiplication - - The basis also has to be linearly independent and of the same rank as the - degree of the function field of its elements (only checked when ``check`` - is ``True``):: - - sage: L.order(L(x)) - Traceback (most recent call last): - ... - ValueError: basis (1, x, x^2, x^3, x^4) is not linearly independent - sage: sage.rings.function_field.order.FunctionFieldOrder_basis((y,y,y^3,y^4,y^5)) - Traceback (most recent call last): - ... - ValueError: basis (y, y, y^3, y^4, 2*x*y + (x^4 + 1)/x) is not linearly independent - """ - def __init__(self, basis, check=True): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: TestSuite(O).run() - """ - if len(basis) == 0: - raise ValueError("basis must have positive length") - - field = basis[0].parent() - if len(basis) != field.degree(): - raise ValueError("length of basis must equal degree of field") - - FunctionFieldOrder.__init__(self, field, ideal_class=FunctionFieldIdeal_module) - - V, from_V, to_V = field.vector_space() - - R = V.base_field().maximal_order() - self._module = V.span([to_V(b) for b in basis], base_ring=R) - - self._from_module= from_V - self._to_module = to_V - self._basis = tuple(basis) - self._ring = field.polynomial_ring() - self._populate_coercion_lists_(coerce_list=[self._ring]) - - if check: - if self._module.rank() != field.degree(): - raise ValueError("basis {} is not linearly independent".format(basis)) - if not to_V(field(1)) in self._module: - raise ValueError("the identity element must be in the module spanned by basis {}".format(basis)) - if not all(to_V(a*b) in self._module for a in basis for b in basis): - raise ValueError("the module generated by basis {} must be closed under multiplication".format(basis)) - - def _element_constructor_(self, f): - """ - Construct an element of this order from ``f``. - - INPUT: - - - ``f`` -- element - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: K.maximal_order()._element_constructor_(x) - x - """ - F = self.function_field() - - try: - f = F(f) - except TypeError: - raise TypeError("unable to convert to an element of {}".format(F)) - - V, fr_V, to_V = F.vector_space() - f_vector = to_V(f) - if f_vector not in self._module: - raise TypeError("{} is not an element of {}".format(f_vector, self)) - - return f - - def ideal_with_gens_over_base(self, gens): - """ - Return the fractional ideal with basis ``gens`` over the - maximal order of the base field. - - It is not checked that the ``gens`` really generates an ideal. - - INPUT: - - - ``gens`` -- list of elements of the function field - - EXAMPLES: - - We construct an ideal in a rational function field:: - - sage: K.<y> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal([y]); I - Ideal (y) of Maximal order of Rational function field in y over Rational Field - sage: I*I - Ideal (y^2) of Maximal order of Rational function field in y over Rational Field - - We construct some ideals in a nontrivial function field:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order(); O - Order in Function field in y defined by y^2 + 6*x^3 + 6 - sage: I = O.ideal_with_gens_over_base([1, y]); I - Ideal (1) of Order in Function field in y defined by y^2 + 6*x^3 + 6 - sage: I.module() - Free module of degree 2 and rank 2 over Maximal order of Rational function field in x over Finite Field of size 7 - Echelon basis matrix: - [1 0] - [0 1] - - There is no check if the resulting object is really an ideal:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order() - sage: I = O.ideal_with_gens_over_base([y]); I - Ideal (y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 - sage: y in I - True - sage: y^2 in I - False - """ - F = self.function_field() - S = F.base_field().maximal_order() - - gens = [F(a) for a in gens] - - V, from_V, to_V = F.vector_space() - M = V.span([to_V(b) for b in gens], base_ring=S) - - return self.ideal_monoid().element_class(self, M) - - def ideal(self, *gens): - """ - Return the fractional ideal generated by the elements in ``gens``. - - INPUT: - - - ``gens`` -- list of generators or an ideal in a ring which - coerces to this order - - EXAMPLES:: - - sage: K.<y> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: O.ideal(y) - Ideal (y) of Maximal order of Rational function field in y over Rational Field - sage: O.ideal([y,1/y]) == O.ideal(y,1/y) # multiple generators may be given as a list - True - - A fractional ideal of a nontrivial extension:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: O = K.maximal_order() - sage: I = O.ideal(x^2-4) - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: S = L.equation_order() - sage: S.ideal(1/y) - Ideal (1, (6/(x^3 + 1))*y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 - sage: I2 = S.ideal(x^2-4); I2 - Ideal (x^2 + 3) of Order in Function field in y defined by y^2 + 6*x^3 + 6 - sage: I2 == S.ideal(I) - True - """ - if len(gens) == 1: - gens = gens[0] - if not isinstance(gens, (list, tuple)): - if isinstance(gens, FunctionFieldIdeal): - gens = gens.gens() - else: - gens = [gens] - K = self.function_field() - - return self.ideal_with_gens_over_base([b*K(g) for b in self.basis() for g in gens]) - - def polynomial(self): - """ - Return the defining polynomial of the function field of which this is an order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: O.polynomial() - y^4 + x*y + 4*x + 1 - """ - return self._field.polynomial() - - def basis(self): - """ - Return a basis of the order over the maximal order of the base field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: O.basis() - (1, y, y^2, y^3) - """ - return self._basis - - def free_module(self): - """ - Return the free module formed by the basis over the maximal order - of the base function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: O.free_module() - Free module of degree 4 and rank 4 over Maximal order of Rational - function field in x over Finite Field of size 7 - Echelon basis matrix: - [1 0 0 0] - [0 1 0 0] - [0 0 1 0] - [0 0 0 1] - """ - return self._module - - def coordinate_vector(self, e): - """ - Return the coordinates of ``e`` with respect to the basis of the order. - - INPUT: - - - ``e`` -- element of the order or the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: f = (x + y)^3 - sage: O.coordinate_vector(f) - (x^3, 3*x^2, 3*x, 1) - """ - return self._module.coordinate_vector(self._to_module(e), check=False) - - class FunctionFieldOrderInfinite(FunctionFieldOrder_base): """ Base class for infinite orders in function fields. @@ -549,271 +246,6 @@ def _repr_(self): return "Infinite order in {}".format(self.function_field()) -class FunctionFieldOrderInfinite_basis(FunctionFieldOrderInfinite): - """ - Order given by a basis over the infinite maximal order of the base - field. - - INPUT: - - - ``basis`` -- elements of the function field - - - ``check`` -- boolean (default: ``True``); if ``True``, check the basis generates - an order - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order_infinite(); O - Infinite order in Function field in y defined by y^4 + x*y + 4*x + 1 - - The basis only defines an order if the module it generates is closed under - multiplication and contains the identity element (only checked when - ``check`` is ``True``):: - - sage: O = L.order_infinite_with_basis([1, y, 1/x^2*y^2, y^3]); O - Traceback (most recent call last): - ... - ValueError: the module generated by basis (1, y, 1/x^2*y^2, y^3) must be closed under multiplication - - The basis also has to be linearly independent and of the same rank as the - degree of the function field of its elements (only checked when ``check`` - is ``True``):: - - sage: O = L.order_infinite_with_basis([1, y, 1/x^2*y^2, 1 + y]); O - Traceback (most recent call last): - ... - ValueError: The given basis vectors must be linearly independent. - - Note that 1 does not need to be an element of the basis, as long as it is - in the module spanned by it:: - - sage: O = L.order_infinite_with_basis([1 + 1/x*y, 1/x*y, 1/x^2*y^2, 1/x^3*y^3]); O - Infinite order in Function field in y defined by y^4 + x*y + 4*x + 1 - sage: O.basis() - (1/x*y + 1, 1/x*y, 1/x^2*y^2, 1/x^3*y^3) - """ - def __init__(self, basis, check=True): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order_infinite() - sage: TestSuite(O).run() - """ - if len(basis) == 0: - raise ValueError("basis must have positive length") - - field = basis[0].parent() - if len(basis) != field.degree(): - raise ValueError("length of basis must equal degree of field") - - FunctionFieldOrderInfinite.__init__(self, field, ideal_class=FunctionFieldIdealInfinite_module) - - # function field element f is in this order if and only if - # W.coordinate_vector(to(f)) in M - V, fr, to = field.vector_space() - R = field.base_field().maximal_order_infinite() - W = V.span_of_basis([to(v) for v in basis]) - from sage.modules.free_module import FreeModule - M = FreeModule(R,W.dimension()) - self._basis = tuple(basis) - self._ambient_space = W - self._module = M - - self._ring = field.polynomial_ring() - self._populate_coercion_lists_(coerce_list=[self._ring]) - - if check: - if self._module.rank() != field.degree(): - raise ValueError("basis {} is not linearly independent".format(basis)) - if not W.coordinate_vector(to(field(1))) in self._module: - raise ValueError("the identity element must be in the module spanned by basis {}".format(basis)) - if not all(W.coordinate_vector(to(a*b)) in self._module for a in basis for b in basis): - raise ValueError("the module generated by basis {} must be closed under multiplication".format(basis)) - - def _element_constructor_(self, f): - """ - Construct an element of this order. - - INPUT: - - - ``f`` -- element - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: O(x) - x - sage: O(1/x) - Traceback (most recent call last): - ... - TypeError: 1/x is not an element of Maximal order of Rational function field in x over Rational Field - """ - F = self.function_field() - try: - f = F(f) - except TypeError: - raise TypeError("unable to convert to an element of {}".format(F)) - - V, fr_V, to_V = F.vector_space() - W = self._ambient_space - if not W.coordinate_vector(to_V(f)) in self._module: - raise TypeError("{} is not an element of {}".format(f, self)) - - return f - - def ideal_with_gens_over_base(self, gens): - """ - Return the fractional ideal with basis ``gens`` over the - maximal order of the base field. - - It is not checked that ``gens`` really generates an ideal. - - INPUT: - - - ``gens`` -- list of elements that are a basis for the ideal over the - maximal order of the base field - - EXAMPLES: - - We construct an ideal in a rational function field:: - - sage: K.<y> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal([y]); I - Ideal (y) of Maximal order of Rational function field in y over Rational Field - sage: I*I - Ideal (y^2) of Maximal order of Rational function field in y over Rational Field - - We construct some ideals in a nontrivial function field:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order(); O - Order in Function field in y defined by y^2 + 6*x^3 + 6 - sage: I = O.ideal_with_gens_over_base([1, y]); I - Ideal (1) of Order in Function field in y defined by y^2 + 6*x^3 + 6 - sage: I.module() - Free module of degree 2 and rank 2 over Maximal order of Rational function field in x over Finite Field of size 7 - Echelon basis matrix: - [1 0] - [0 1] - - There is no check if the resulting object is really an ideal:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order() - sage: I = O.ideal_with_gens_over_base([y]); I - Ideal (y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 - sage: y in I - True - sage: y^2 in I - False - """ - F = self.function_field() - S = F.base_field().maximal_order_infinite() - - gens = [F(a) for a in gens] - - V, from_V, to_V = F.vector_space() - M = V.span([to_V(b) for b in gens], base_ring=S) # not work - - return self.ideal_monoid().element_class(self, M) - - def ideal(self, *gens): - """ - Return the fractional ideal generated by the elements in ``gens``. - - INPUT: - - - ``gens`` -- list of generators or an ideal in a ring which coerces - to this order - - EXAMPLES:: - - sage: K.<y> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: O.ideal(y) - Ideal (y) of Maximal order of Rational function field in y over Rational Field - sage: O.ideal([y,1/y]) == O.ideal(y,1/y) # multiple generators may be given as a list - True - - A fractional ideal of a nontrivial extension:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: O = K.maximal_order_infinite() - sage: I = O.ideal(x^2-4) - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: S = L.order_infinite_with_basis([1, 1/x^2*y]) - """ - if len(gens) == 1: - gens = gens[0] - if not isinstance(gens, (list, tuple)): - if isinstance(gens, FunctionFieldIdeal): - gens = gens.gens() - else: - gens = [gens] - K = self.function_field() - - return self.ideal_with_gens_over_base([b*K(g) for b in self.basis() for g in gens]) - - def polynomial(self): - """ - Return the defining polynomial of the function field of which this is an order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: O.polynomial() - y^4 + x*y + 4*x + 1 - """ - return self._field.polynomial() - - def basis(self): - """ - Return a basis of this order over the maximal order of the base field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: O.basis() - (1, y, y^2, y^3) - """ - return self._basis - - def free_module(self): - """ - Return the free module formed by the basis over the maximal order of - the base field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: O.free_module() - Free module of degree 4 and rank 4 over Maximal order of Rational - function field in x over Finite Field of size 7 - Echelon basis matrix: - [1 0 0 0] - [0 1 0 0] - [0 0 1 0] - [0 0 0 1] - """ - return self._module - - class FunctionFieldMaximalOrder(UniqueRepresentation, FunctionFieldOrder): """ Base class of maximal orders of function fields. @@ -827,1947 +259,23 @@ def _repr_(self): sage: FunctionField(QQ,'y').maximal_order()._repr_() 'Maximal order of Rational function field in y over Rational Field' """ - return "Maximal order of %s"%(self.function_field(),) + return "Maximal order of %s" % (self.function_field(),) -class FunctionFieldMaximalOrder_rational(FunctionFieldMaximalOrder): +class FunctionFieldMaximalOrderInfinite(FunctionFieldMaximalOrder, FunctionFieldOrderInfinite): """ - Maximal orders of rational function fields. - - INPUT: - - - ``field`` -- a function field - - EXAMPLES:: - - sage: K.<t> = FunctionField(GF(19)); K - Rational function field in t over Finite Field of size 19 - sage: R = K.maximal_order(); R - Maximal order of Rational function field in t over Finite Field of size 19 + Base class of maximal infinite orders of function fields. """ - def __init__(self, field): - """ - Initialize. - - TESTS:: - - sage: K.<t> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: TestSuite(O).run(skip='_test_gcd_vs_xgcd') - """ - FunctionFieldMaximalOrder.__init__(self, field, ideal_class=FunctionFieldIdeal_rational, - category=EuclideanDomains()) - - self._populate_coercion_lists_(coerce_list=[field._ring]) - - self._ring = field._ring - self._gen = self(self._ring.gen()) - self._basis = (self.one(),) - - def _element_constructor_(self, f): - """ - Make ``f`` a function field element of this order. - - EXAMPLES:: - - sage: K.<y> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: O._element_constructor_(y) - y - sage: O._element_constructor_(1/y) - Traceback (most recent call last): - ... - TypeError: 1/y is not an element of Maximal order of Rational function field in y over Rational Field - """ - F = self.function_field() - try: - f = F(f) - except TypeError: - raise TypeError("unable to convert to an element of {}".format(F)) - - if not f.denominator() in self.function_field().constant_base_field(): - raise TypeError("%r is not an element of %r"%(f,self)) - - return f - - def ideal_with_gens_over_base(self, gens): - """ - Return the fractional ideal with generators ``gens``. - - INPUT: - - - ``gens`` -- elements of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order() - sage: O.ideal_with_gens_over_base([x^3+1,-y]) - Ideal (x^3 + 1, -y) of Order in Function field in y defined by y^2 - x^3 - 1 - """ - return self.ideal(gens) - - def _residue_field(self, ideal, name=None): + def _repr_(self): """ - Return a field isomorphic to the residue field at the prime ideal. - - The residue field is by definition `k[x]/q` where `q` is the irreducible - polynomial generating the prime ideal and `k` is the constant base field. - - INPUT: - - - ``ideal`` -- prime ideal of the order - - - ``name`` -- string; name of the generator of the residue field - - OUTPUT: - - - a field isomorphic to the residue field - - - a morphism from the field to `k[x]` via the residue field - - - a morphism from `k[x]` to the field via the residue field - EXAMPLES:: - sage: F.<x> = FunctionField(GF(2)) - sage: O = F.maximal_order() - sage: I = O.ideal(x^2 + x + 1) - sage: R, fr_R, to_R = O._residue_field(I) - sage: R - Finite Field in z2 of size 2^2 - sage: [to_R(fr_R(e)) == e for e in R] - [True, True, True, True] - sage: [to_R(fr_R(e)).parent() is R for e in R] - [True, True, True, True] - sage: e1, e2 = fr_R(R.random_element()), fr_R(R.random_element()) - sage: to_R(e1 * e2) == to_R(e1) * to_R(e2) - True - sage: to_R(e1 + e2) == to_R(e1) + to_R(e2) - True - sage: to_R(e1).parent() is R - True - sage: to_R(e2).parent() is R - True - - sage: F.<x> = FunctionField(GF(2)) - sage: O = F.maximal_order() - sage: I = O.ideal(x + 1) - sage: R, fr_R, to_R = O._residue_field(I) - sage: R - Finite Field of size 2 - sage: [to_R(fr_R(e)) == e for e in R] - [True, True] - sage: [to_R(fr_R(e)).parent() is R for e in R] - [True, True] - sage: e1, e2 = fr_R(R.random_element()), fr_R(R.random_element()) - sage: to_R(e1 * e2) == to_R(e1) * to_R(e2) - True - sage: to_R(e1 + e2) == to_R(e1) + to_R(e2) - True - sage: to_R(e1).parent() is R - True - sage: to_R(e2).parent() is R - True - - sage: F.<x> = FunctionField(QQ) - sage: O = F.maximal_order() - sage: I = O.ideal(x^2 + x + 1) - sage: R, fr_R, to_R = O._residue_field(I) - sage: R - Number Field in a with defining polynomial x^2 + x + 1 - sage: e1, e2 = fr_R(R.random_element()), fr_R(R.random_element()) - sage: to_R(e1 * e2) == to_R(e1) * to_R(e2) - True - sage: to_R(e1 + e2) == to_R(e1) + to_R(e2) - True - sage: to_R(e1).parent() is R - True - sage: to_R(e2).parent() is R - True - - sage: F.<x> = FunctionField(QQ) - sage: O = F.maximal_order() - sage: I = O.ideal(x + 1) - sage: R, fr_R, to_R = O._residue_field(I) - sage: R - Rational Field - sage: e1, e2 = fr_R(R.random_element()), fr_R(R.random_element()) - sage: to_R(e1 * e2) == to_R(e1) * to_R(e2) - True - sage: to_R(e1 + e2) == to_R(e1) + to_R(e2) - True - sage: to_R(e1).parent() is R - True - sage: to_R(e2).parent() is R - True - """ - F = self.function_field() - K = F.constant_base_field() - - q = ideal.gen().element().numerator() - - if F.is_global(): - R, _from_R, _to_R = self._residue_field_global(q, name=name) - elif isinstance(K, NumberField) or K is QQbar: - if name is None: - name = 'a' - if q.degree() == 1: - R = K - _from_R = lambda e: e - _to_R = lambda e: R(e % q) - else: - R = K.extension(q, names=name) - _from_R = lambda e: self._ring(list(R(e))) - _to_R = lambda e: (e % q)(R.gen(0)) - else: - raise NotImplementedError - - def from_R(e): - return F(_from_R(e)) - - def to_R(f): - return _to_R(f.numerator()) - - return R, from_R, to_R - - def _residue_field_global(self, q, name=None): - """ - Return a finite field isomorphic to the residue field at q. - - This method assumes a global rational function field, that is, - the constant base field is a finite field. - - INPUT: - - - ``q`` -- irreducible polynomial - - - ``name`` -- string; name of the generator of the extension field - - OUTPUT: - - - a finite field - - - a function that outputs a polynomial lifting a finite field element - - - a function that outputs a finite field element for a polynomial - - The residue field is by definition `k[x]/q` where `k` is the base field. - - EXAMPLES:: - - sage: k.<a> = GF(4) - sage: F.<x> = FunctionField(k) - sage: O = F.maximal_order() - sage: O._ring - Univariate Polynomial Ring in x over Finite Field in a of size 2^2 - sage: f = x^3 + x + 1 - sage: _f = f.numerator() - sage: _f.is_irreducible() - True - sage: K, fr_K, to_K = O._residue_field_global(_f) - sage: K - Finite Field in z6 of size 2^6 - sage: all(to_K(fr_K(e)) == e for e in K) - True - - sage: k.<a> = GF(2) - sage: F.<x> = FunctionField(k) - sage: O = F.maximal_order() - sage: O._ring - Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) - sage: f = x^3 + x + 1 - sage: _f = f.numerator() - sage: _f.is_irreducible() - True - sage: K, fr_K, to_K = O._residue_field_global(_f) - sage: all(to_K(fr_K(e)) == e for e in K) - True - - """ - # polynomial ring over the base field - R = self._ring - - # base field of extension degree r over the prime field - k = R.base_ring() - a = k.gen() - r = k.degree() - - # extend the base field to a field of degree r*s over the - # prime field - s = q.degree() - K,sigma = k.extension(s, map=True, name=name) - - # find a root beta in K satisfying the irreducible q - S = K['X'] - beta = S([sigma(c) for c in q.list()]).roots()[0][0] - - # V is a vector space over the prime subfield of k of degree r*s - V = K.vector_space(map=False) - - w = K.one() - beta_pow = [] - for i in range(s): - beta_pow.append(w) - w *= beta - - w = K.one() - sigma_a = sigma(a) - sigma_a_pow = [] - for i in range(r): - sigma_a_pow.append(w) - w *= sigma_a - - basis = [V(sap * bp) for bp in beta_pow for sap in sigma_a_pow] - W = V.span_of_basis(basis) - - def to_K(f): - coeffs = (f % q).list() - return sum((sigma(c) * beta_pow[i] for i, c in enumerate(coeffs)), K.zero()) - - if r == 1: # take care of the prime field case - def fr_K(g): - co = W.coordinates(V(g), check=False) - return R([k(co[j]) for j in range(s)]) - else: - def fr_K(g): - co = W.coordinates(V(g), check=False) - return R([k(co[i:i+r]) for i in range(0, r*s, r)]) - - return K, fr_K, to_K - - def basis(self): - """ - Return the basis (=1) of the order as a module over the polynomial ring. - - EXAMPLES:: - - sage: K.<t> = FunctionField(GF(19)) - sage: O = K.maximal_order() - sage: O.basis() - (1,) - """ - return self._basis - - def gen(self, n=0): - """ - Return the ``n``-th generator of the order. Since there is only one generator ``n`` must be 0. - - EXAMPLES:: - - sage: O = FunctionField(QQ,'y').maximal_order() - sage: O.gen() - y - sage: O.gen(1) - Traceback (most recent call last): - ... - IndexError: there is only one generator - """ - if n != 0: - raise IndexError("there is only one generator") - return self._gen - - def ngens(self): - """ - Return 1 the number of generators of the order. - - EXAMPLES:: - - sage: FunctionField(QQ,'y').maximal_order().ngens() - 1 - """ - return 1 - - def ideal(self, *gens): - """ - Return the fractional ideal generated by ``gens``. - - INPUT: - - - ``gens`` -- elements of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: O.ideal(x) - Ideal (x) of Maximal order of Rational function field in x over Rational Field - sage: O.ideal([x,1/x]) == O.ideal(x,1/x) # multiple generators may be given as a list - True - sage: O.ideal(x^3+1,x^3+6) - Ideal (1) of Maximal order of Rational function field in x over Rational Field - sage: I = O.ideal((x^2+1)*(x^3+1),(x^3+6)*(x^2+1)); I - Ideal (x^2 + 1) of Maximal order of Rational function field in x over Rational Field - sage: O.ideal(I) - Ideal (x^2 + 1) of Maximal order of Rational function field in x over Rational Field - """ - if len(gens) == 1: - gens = gens[0] - if not isinstance(gens, (list, tuple)): - if isinstance(gens, FunctionFieldIdeal): - gens = gens.gens() - else: - gens = (gens,) - K = self.function_field() - gens = [K(e) for e in gens if e != 0] - if len(gens) == 0: - gen = K(0) - else: - d = lcm([c.denominator() for c in gens]).monic() - g = gcd([(d*c).numerator() for c in gens]).monic() - gen = K(g/d) - - return self.ideal_monoid().element_class(self, gen) - - -class FunctionFieldMaximalOrder_polymod(FunctionFieldMaximalOrder): - """ - Maximal orders of extensions of function fields. - """ - - def __init__(self, field, ideal_class=FunctionFieldIdeal_polymod): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.maximal_order() - sage: TestSuite(O).run() - """ - FunctionFieldMaximalOrder.__init__(self, field, ideal_class) - - from .function_field import FunctionField_integral - if isinstance(field, FunctionField_integral): - basis = field._maximal_order_basis() - else: - model, from_model, to_model = field.monic_integral_model('z') - basis = [from_model(g) for g in model._maximal_order_basis()] - - V, fr, to = field.vector_space() - R = field.base_field().maximal_order() - - # This module is over R, but linear algebra over R (MaximalOrder) - # is not well supported in Sage. So we keep it as a vector space - # over rational function field. - self._module = V.span_of_basis([to(b) for b in basis]) - self._module_base_ring = R - self._basis = tuple(basis) - self._from_module = fr - self._to_module = to - - # multiplication table (lower triangular) - n = len(basis) - self._mtable = [] - for i in range(n): - row = [] - for j in range(n): - row.append(self._coordinate_vector(basis[i] * basis[j])) - self._mtable.append(row) - - zero = vector(R._ring, n * [0]) - - def mul_vecs(f, g): - s = zero - for i in range(n): - if f[i].is_zero(): - continue - for j in range(n): - if g[j].is_zero(): - continue - s += f[i] * g[j] * self._mtable[i][j] - return s - self._mul_vecs = mul_vecs - - # We prepare for using Kummer's theorem to decompose primes. Note - # that Kummer's theorem applies to most places. Here we find - # places for which the theorem does not apply. - - # this element is integral over k[x] and a generator of the field. - for gen in basis: - phi = gen.minimal_polynomial() - if phi.degree() == n: - break - - assert phi.degree() == n - - gen_vec = self._coordinate_vector(gen) - g = gen_vec.parent().gen(0) # x - gen_vec_pow = [g] - for i in range(n): - g = mul_vecs(g, gen_vec) - gen_vec_pow.append(g) - - # find places where {1,gen,...,gen^(n-1)} is not integral basis - W = V.span_of_basis([to(gen ** i) for i in range(phi.degree())]) - - supp = [] - for g in basis: - for c in W.coordinate_vector(to(g), check=False): - if not c.is_zero(): - supp += [f for f,_ in c.denominator().factor()] - supp = set(supp) - - self._kummer_gen = gen - self._kummer_gen_vec_pow = gen_vec_pow - self._kummer_polynomial = phi - self._kummer_places = supp - - def _element_constructor_(self, f): - """ - Construct an element of this order from ``f``. - - INPUT: - - - ``f`` -- element convertible to the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2-x*Y+x^2+1) - sage: O = L.maximal_order() - sage: y in O - True - sage: 1/y in O - False - sage: x in O - True - sage: 1/x in O - False - sage: L.<y>=K.extension(Y^2+Y+x+1/x) - sage: O = L.maximal_order() - sage: 1 in O - True - sage: y in O - False - sage: x*y in O - True - sage: x^2*y in O - True - """ - F = self.function_field() - f = F(f) - # check if f is in this order - if not all(e in self._module_base_ring for e in self.coordinate_vector(f)): - raise TypeError( "{} is not an element of {}".format(f, self) ) - - return f - - def ideal_with_gens_over_base(self, gens): - """ - Return the fractional ideal with basis ``gens`` over the - maximal order of the base field. - - INPUT: - - - ``gens`` -- list of elements that generates the ideal over the - maximal order of the base field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.maximal_order(); O - Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 - sage: I = O.ideal_with_gens_over_base([1, y]); I - Ideal (1) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 - sage: I.module() - Free module of degree 2 and rank 2 over Maximal order of Rational function field in x over Finite Field of size 7 - Echelon basis matrix: - [1 0] - [0 1] - - There is no check if the resulting object is really an ideal:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order() - sage: I = O.ideal_with_gens_over_base([y]); I - Ideal (y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 - sage: y in I - True - sage: y^2 in I - False - """ - return self._ideal_from_vectors([self.coordinate_vector(g) for g in gens]) - - def _ideal_from_vectors(self, vecs): - """ - Return an ideal generated as a module by vectors over rational function - field. - - INPUT: - - - ``vec`` -- list of vectors - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.maximal_order() - sage: v1 = O.coordinate_vector(x^3+1) - sage: v2 = O.coordinate_vector(y) - sage: v1 - (x^3 + 1, 0) - sage: v2 - (0, 1) - sage: O._ideal_from_vectors([v1,v2]) - Ideal (y) of Maximal order of Function field in y - defined by y^2 + 6*x^3 + 6 - """ - d = lcm([v.denominator() for v in vecs]) - vecs = [[(d*c).numerator() for c in v] for v in vecs] - return self._ideal_from_vectors_and_denominator(vecs, d, check=False) - - def _ideal_from_vectors_and_denominator(self, vecs, d=1, check=True): - """ - Return an ideal generated as a module by vectors divided by ``d`` over - the polynomial ring underlying the rational function field. - - INPUT: - - - ``vec`` -- list of vectors over the polynomial ring - - - ``d`` -- (default: 1) a nonzero element of the polynomial ring - - - ``check`` -- boolean (default: ``True``); if ``True``, compute the real - denominator of the vectors, possibly different from ``d``. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: O = L.maximal_order() - sage: I = O.ideal(y^2) - sage: m = I.basis_matrix() - sage: v1 = m[0] - sage: v2 = m[1] - sage: v1 - (x^3 + 1, 0) - sage: v2 - (0, x^3 + 1) - sage: O._ideal_from_vectors([v1,v2]) # indirect doctest - Ideal (x^3 + 1) of Maximal order of Function field in y - defined by y^2 + 6*x^3 + 6 - """ - R = self._module_base_ring._ring - - d = R(d) # make it sure that d is in the polynomial ring - - if check and not d.is_one(): # check if d is true denominator - M = [] - g = d - for v in vecs: - for c in v: - g = g.gcd(c) - if g.is_one(): - break - else: - M += list(v) - continue # for v in vecs - mat = matrix(R, vecs) - break - else: - d = d // g - mat = matrix(R, len(vecs), [c // g for c in M]) - else: - mat = matrix(R, vecs) - - # IMPORTANT: make it sure that pivot polynomials monic - # so that we get a unique hnf. Here the hermite form - # algorithm also makes the pivots monic. - - # compute the reversed hermite form with zero rows deleted - reversed_hermite_form(mat) - i = 0 - while i < mat.nrows() and mat.row(i).is_zero(): - i += 1 - hnf = mat[i:] # remove zero rows - - return self.ideal_monoid().element_class(self, hnf, d) - - def ideal(self, *gens, **kwargs): - """ - Return the fractional ideal generated by the elements in ``gens``. - - INPUT: - - - ``gens`` -- list of generators - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: O = K.maximal_order() - sage: I = O.ideal(x^2-4) - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: S = L.maximal_order() - sage: S.ideal(1/y) - Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field - in y defined by y^2 + 6*x^3 + 6 - sage: I2 = S.ideal(x^2-4); I2 - Ideal (x^2 + 3) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 - sage: I2 == S.ideal(I) - True - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: O = K.maximal_order() - sage: I = O.ideal(x^2-4) - sage: L.<y> = K.extension(y^2 - x^3 - 1) - sage: S = L.maximal_order() - sage: S.ideal(1/y) - Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 - x^3 - 1 - sage: I2 = S.ideal(x^2-4); I2 - Ideal (x^2 - 4) of Maximal order of Function field in y defined by y^2 - x^3 - 1 - sage: I2 == S.ideal(I) - True - """ - if len(gens) == 1: - gens = gens[0] - if not isinstance(gens, (list, tuple)): - if isinstance(gens, FunctionFieldIdeal): - gens = gens.gens() - else: - gens = (gens,) - F = self.function_field() - mgens = [b*F(g) for g in gens for b in self.basis()] - return self.ideal_with_gens_over_base(mgens) - - def polynomial(self): - """ - Return the defining polynomial of the function field of which this is an order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: O.polynomial() - y^4 + x*y + 4*x + 1 - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: O.polynomial() - y^4 + x*y + 4*x + 1 - """ - return self._field.polynomial() - - def basis(self): - """ - Return a basis of the order over the maximal order of the base function - field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: O.basis() - (1, y, y^2, y^3) - - sage: K.<x> = FunctionField(QQ) - sage: R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^4 + x^12*t^2 + x^18*t + x^21 + x^18) - sage: O = F.maximal_order() - sage: O.basis() - (1, 1/x^4*y, 1/x^9*y^2, 1/x^13*y^3) - """ - return self._basis - - def gen(self, n=0): - """ - Return the ``n``-th generator of the order. - - The basis elements of the order are generators. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: L.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: O = L.maximal_order() - sage: O.gen() - 1 - sage: O.gen(1) - y - sage: O.gen(2) - (1/(x^3 + x^2 + x))*y^2 - sage: O.gen(3) - Traceback (most recent call last): - ... - IndexError: there are only 3 generators - """ - if not ( n >= 0 and n < self.ngens() ): - raise IndexError("there are only {} generators".format(self.ngens())) - - return self._basis[n] - - def ngens(self): - """ - Return the number of generators of the order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: L.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: Oinf = L.maximal_order() - sage: Oinf.ngens() - 3 - """ - return len(self._basis) - - def free_module(self): - """ - Return the free module formed by the basis over the maximal order of the base field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.maximal_order() - sage: O.free_module() - Free module of degree 4 and rank 4 over Maximal order of Rational function field in x over Finite Field of size 7 - User basis matrix: - [1 0 0 0] - [0 1 0 0] - [0 0 1 0] - [0 0 0 1] - """ - return self._module.change_ring(self._module_base_ring) - - def coordinate_vector(self, e): - """ - Return the coordinates of ``e`` with respect to the basis of this order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.maximal_order() - sage: O.coordinate_vector(y) - (0, 1, 0, 0) - sage: O.coordinate_vector(x*y) - (0, x, 0, 0) - - sage: K.<x> = FunctionField(QQ); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.equation_order() - sage: f = (x + y)^3 - sage: O.coordinate_vector(f) - (x^3, 3*x^2, 3*x, 1) - """ - return self._module.coordinate_vector(self._to_module(e)) - - def _coordinate_vector(self, e): - """ - Return the coordinate vector of ``e`` with respect to the basis - of the order. - - Assuming ``e`` is in the maximal order, the coordinates are given - as univariate polynomials in the underlying ring of the maximal - order of the rational function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.maximal_order() - sage: O._coordinate_vector(y) - (0, 1, 0, 0) - sage: O._coordinate_vector(x*y) - (0, x, 0, 0) - """ - v = self._module.coordinate_vector(self._to_module(e), check=False) - return vector([c.numerator() for c in v]) - - @cached_method - def different(self): - """ - Return the different ideal of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.maximal_order() - sage: O.different() - Ideal (y^3 + 2*x) - of Maximal order of Function field in y defined by y^4 + x*y + 4*x + 1 - """ - return ~self.codifferent() - - @cached_method - def codifferent(self): - """ - Return the codifferent ideal of the function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.maximal_order() - sage: O.codifferent() - Ideal (1, (1/(x^4 + 4*x^3 + 3*x^2 + 6*x + 4))*y^3 - + ((5*x^3 + 6*x^2 + x + 6)/(x^4 + 4*x^3 + 3*x^2 + 6*x + 4))*y^2 - + ((x^3 + 2*x^2 + 2*x + 2)/(x^4 + 4*x^3 + 3*x^2 + 6*x + 4))*y - + 6*x/(x^4 + 4*x^3 + 3*x^2 + 6*x + 4)) of Maximal order of Function field - in y defined by y^4 + x*y + 4*x + 1 - """ - T = self._codifferent_matrix() - return self._ideal_from_vectors(T.inverse().columns()) - - @cached_method - def _codifferent_matrix(self): - """ - Return the matrix `T` defined in Proposition 4.8.19 of [Coh1993]_. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.maximal_order() - sage: O._codifferent_matrix() - [ 4 0 0 4*x] - [ 0 0 4*x 5*x + 3] - [ 0 4*x 5*x + 3 0] - [ 4*x 5*x + 3 0 3*x^2] - """ - rows = [] - for u in self.basis(): - row = [] - for v in self.basis(): - row.append((u*v).trace()) - rows.append(row) - T = matrix(rows) - return T - - @cached_method - def decomposition(self, ideal): - """ - Return the decomposition of the prime ideal. - - INPUT: - - - ``ideal`` -- prime ideal of the base maximal order - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); R.<t> = K[] - sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: o = K.maximal_order() - sage: O = F.maximal_order() - sage: p = o.ideal(x+1) - sage: O.decomposition(p) - [(Ideal (x + 1, y + 1) of Maximal order - of Function field in y defined by y^3 + x^6 + x^4 + x^2, 1, 1), - (Ideal (x + 1, (1/(x^3 + x^2 + x))*y^2 + y + 1) of Maximal order - of Function field in y defined by y^3 + x^6 + x^4 + x^2, 2, 1)] - - ALGORITHM: - - In principle, we're trying to compute a primary decomposition - of the extension of ``ideal`` in ``self`` (an order, and therefore - a ring). However, while we have primary decomposition methods - for polynomial rings, we lack any such method for an order. - Therefore, we construct ``self`` mod ``ideal`` as a - finite-dimensional algebra, a construct for which we do - support primary decomposition. - - See :trac:`28094` and https://github.com/sagemath/sage/files/10659303/decomposition.pdf.gz - - .. TODO:: - - Use Kummer's theorem to shortcut this code if possible, like as - done in :meth:`FunctionFieldMaximalOrder_global.decomposition()` - - """ - F = self.function_field() - n = F.degree() - - # Base rational function field - K = self.function_field().base_field() - - # Univariate polynomial ring isomorphic to the maximal order of K - o = PolynomialRing(K.constant_field(), K.gen()) - - # Prime ideal in o defined by the generator of ideal in the maximal - # order of K - p = o(ideal.gen().numerator()) - - # Residue field k = o mod p - k = o.quo(p) - - # Given an element of the function field expressed as a K-vector times - # the basis of this order, construct the n n-by-n matrices that show - # how to multiply by each of the basis elements. - matrices = [matrix(o, [self.coordinate_vector(b1*b2) for b1 in self.basis()]) - for b2 in self.basis()] - - # Let O denote the maximal order self. When reduced modulo p, - # matrices_reduced give the multiplication matrices used to form the - # algebra O mod pO. - matrices_reduced = list(map(lambda M: M.mod(p), matrices)) - A = FiniteDimensionalAlgebra(k, matrices_reduced) - - # Each prime ideal of the algebra A corresponds to a prime ideal of O, - # and since the algebra is an Artinian ring, all of its prime ideals - # are maximal [stacks 00JA]. Thus, we find all of our factors by - # iterating over the algebra's maximal ideals. - factors = [] - for q in A.maximal_ideals(): - if q == A.zero_ideal(): - # The zero ideal is the unique maximal ideal, which means that - # A is a field, and the ideal itself is a prime ideal. - P = self.ideal(p) - - P.is_prime.set_cache(True) - P._prime_below = ideal - P._relative_degree = n - P._ramification_index = 1 - P._beta = [1] + [0]*(n-1) - else: - Q = q.basis_matrix().apply_map(lambda e: e.lift()) - P = self.ideal(p, *Q*vector(self.basis())) - - # Now we compute an element beta in O but not in pO such that - # beta*P in pO. - - # Since beta is in k[x]-module O, we keep beta as a vector - # in k[x] with respect to the basis of O. As long as at least - # one element in this vector is not divisible by p, beta will - # not be in pO. To ensure that beta*P is in pO, multiplying - # beta by each of P's generators must produce a vector whose - # elements are multiples of p. We can ensure that all this - # occurs by constructing a matrix in k, and finding a non-zero - # vector in the kernel of the matrix. - - m =[] - for g in q.basis_matrix(): - m.extend(matrix([g * mr for mr in matrices_reduced]).columns()) - beta = [c.lift() for c in matrix(m).right_kernel().basis()[0]] - - r = q - index = 1 - while True: - rq = r*q - if rq == r: - break - r = rq - index = index + 1 - - P.is_prime.set_cache(True) - P._prime_below = ideal - P._relative_degree = n - q.basis_matrix().nrows() - P._ramification_index = index - P._beta = beta - - factors.append((P, P._relative_degree, P._ramification_index)) - - return factors - - -class FunctionFieldMaximalOrder_global(FunctionFieldMaximalOrder_polymod): - """ - Maximal orders of global function fields. - - INPUT: - - - ``field`` -- function field to which this maximal order belongs - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: L.maximal_order() - Maximal order of Function field in y defined by y^4 + x*y + 4*x + 1 - """ - - def __init__(self, field): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] - sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) - sage: O = L.maximal_order() - sage: TestSuite(O).run() - """ - FunctionFieldMaximalOrder_polymod.__init__(self, field, ideal_class=FunctionFieldIdeal_global) - - @cached_method - def p_radical(self, prime): - """ - Return the ``prime``-radical of the maximal order. - - INPUT: - - - ``prime`` -- prime ideal of the maximal order of the base - rational function field - - The algorithm is outlined in Section 6.1.3 of [Coh1993]_. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: F.<y> = K.extension(t^3 - x^2 * (x^2 + x + 1)^2) - sage: o = K.maximal_order() - sage: O = F.maximal_order() - sage: p = o.ideal(x+1) - sage: O.p_radical(p) - Ideal (x + 1) of Maximal order of Function field in y - defined by y^3 + x^6 + x^4 + x^2 - """ - g = prime.gens()[0] - - if not (g.denominator() == 1 and g.numerator().is_irreducible()): - raise ValueError('not a prime ideal') - - F = self.function_field() - n = F.degree() - o = prime.ring() - p = g.numerator() - - # Fp is isomorphic to the residue field o/p - Fp, fr_Fp, to_Fp = o._residue_field_global(p) - - # exp = q^j should be at least extension degree where q is - # the order of the residue field o/p - q = F.constant_base_field().order()**p.degree() - exp = q - while exp <= F.degree(): - exp = exp**q - - # radical equals to the kernel of the map x |-> x^exp - mat = [] - for g in self.basis(): - v = [to_Fp(c) for c in self._coordinate_vector(g**exp)] - mat.append(v) - mat = matrix(Fp,mat) - ker = mat.kernel() - - # construct module generators of the p-radical - vecs = [] - for i in range(n): - v = vector([p if j == i else 0 for j in range(n)]) - vecs.append(v) - for b in ker.basis(): - v = vector([fr_Fp(c) for c in b]) - vecs.append(v) - - return self._ideal_from_vectors(vecs) - - @cached_method - def decomposition(self, ideal): - """ - Return the decomposition of the prime ideal. - - INPUT: - - - ``ideal`` -- prime ideal of the base maximal order - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); R.<t> = K[] - sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: o = K.maximal_order() - sage: O = F.maximal_order() - sage: p = o.ideal(x+1) - sage: O.decomposition(p) - [(Ideal (x + 1, y + 1) of Maximal order - of Function field in y defined by y^3 + x^6 + x^4 + x^2, 1, 1), - (Ideal (x + 1, (1/(x^3 + x^2 + x))*y^2 + y + 1) of Maximal order - of Function field in y defined by y^3 + x^6 + x^4 + x^2, 2, 1)] - """ - F = self.function_field() - n = F.degree() - - p = ideal.gen().numerator() - o = ideal.ring() - - # Fp is isomorphic to the residue field o/p - Fp, fr, to = o._residue_field_global(p) - P,X = Fp['X'].objgen() - - V = Fp**n # Ob = O/pO - - mtable = [] - for i in range(n): - row = [] - for j in range(n): - row.append( V([to(e) for e in self._mtable[i][j]]) ) - mtable.append(row) - - if p not in self._kummer_places: - ##################################### - # Decomposition by Kummer's theorem # - ##################################### - # gen is self._kummer_gen - gen_vec_pow = self._kummer_gen_vec_pow - mul_vecs = self._mul_vecs - - f = self._kummer_polynomial - fp = P([to(c.numerator()) for c in f.list()]) - decomposition = [] - for q, exp in fp.factor(): - # construct O.ideal([p,q(gen)]) - gen_vecs = list(matrix.diagonal(n * [p])) - c = q.list() - - # q(gen) in vector form - qgen = sum(fr(c[i]) * gen_vec_pow[i] for i in range(len(c))) - - I = matrix.identity(o._ring, n) - for i in range(n): - gen_vecs.append(mul_vecs(qgen,I[i])) - prime = self._ideal_from_vectors_and_denominator(gen_vecs) - - # Compute an element beta in O but not in pO. How to find beta - # is explained in Section 4.8.3 of [Coh1993]. We keep beta - # as a vector over k[x] with respect to the basis of O. - - # p and qgen generates the prime; modulo pO, qgenb generates the prime - qgenb = [to(qgen[i]) for i in range(n)] - m =[] - for i in range(n): - m.append(sum(qgenb[j] * mtable[i][j] for j in range(n))) - beta = [fr(coeff) for coeff in matrix(m).left_kernel().basis()[0]] - - prime.is_prime.set_cache(True) - prime._prime_below = ideal - prime._relative_degree = q.degree() - prime._ramification_index = exp - prime._beta = beta - - prime._kummer_form = (p, qgen) - - decomposition.append((prime, q.degree(), exp)) - else: - ############################# - # Buchman-Lenstra algorithm # - ############################# - pO = self.ideal(p) - Ip = self.p_radical(ideal) - Ob = matrix.identity(Fp, n) - - def bar(I): # transfer to O/pO - m = [] - for v in I._hnf: - m.append([to(e) for e in v]) - h = matrix(m).echelon_form() - return cut_last_zero_rows(h) - - def liftb(Ib): - m = [vector([fr(e) for e in v]) for v in Ib] - m += [v for v in pO._hnf] - return self._ideal_from_vectors_and_denominator(m,1) - - def cut_last_zero_rows(h): - i = h.nrows() - while i > 0 and h.row(i-1).is_zero(): - i -= 1 - return h[:i] - - def mul_vec(v1,v2): - s = 0 - for i in range(n): - for j in range(n): - s += v1[i] * v2[j] * mtable[i][j] - return s - - def pow(v, r): # r > 0 - m = v - while r > 1: - m = mul_vec(m,v) - r -= 1 - return m - - # Algorithm 6.2.7 of [Coh1993] - def div(Ib, Jb): - # compute a basis of Jb/Ib - sJb = Jb.row_space() - sIb = Ib.row_space() - sJbsIb,proj_sJbsIb,lift_sJbsIb = sJb.quotient_abstract(sIb) - supplement_basis = [lift_sJbsIb(v) for v in sJbsIb.basis()] - - m = [] - for b in V.gens(): # basis of Ob = O/pO - b_row = [] # row vector representation of the map a -> a*b - for a in supplement_basis: - b_row += lift_sJbsIb(proj_sJbsIb( mul_vec(a,b) )) - m.append(b_row) - return matrix(Fp,n,m).left_kernel().basis_matrix() - - # Algorithm 6.2.5 of [Coh1993] - def mul(Ib, Jb): - m = [] - for v1 in Ib: - for v2 in Jb: - m.append(mul_vec(v1,v2)) - h = matrix(m).echelon_form() - return cut_last_zero_rows(h) - - def add(Ib,Jb): - m = block_matrix([[Ib], [Jb]]) - h = m.echelon_form() - return cut_last_zero_rows(h) - - # K_1, K_2, ... - Lb = IpOb = bar(Ip+pO) - Kb = [Lb] - while not Lb.is_zero(): - Lb = mul(Lb,IpOb) - Kb.append(Lb) - - # J_1, J_2, ... - Jb =[Kb[0]] + [div(Kb[j],Kb[j-1]) for j in range(1,len(Kb))] - - # H_1, H_2, ... - Hb = [div(Jb[j],Jb[j+1]) for j in range(len(Jb)-1)] + [Jb[-1]] - - q = Fp.order() - - def split(h): - # VsW represents O/H as a vector space - W = h.row_space() # H/pO - VsW,to_VsW,lift_to_V = V.quotient_abstract(W) - - # compute the space K of elements in O/H that satisfy a^q-a=0 - l = [lift_to_V(b) for b in VsW.basis()] - - images = [to_VsW(pow(x, q) - x) for x in l] - K = VsW.hom(images, VsW).kernel() - - if K.dimension() == 0: - return [] - if K.dimension() == 1: # h is prime - return [(liftb(h),VsW.dimension())] # relative degree - - # choose a such that a^q - a is 0 but a is not in Fp - for a in K.basis(): - # IMPORTANT: This criterion is based on the assumption - # that O.basis() starts with 1. - if a.support() != [0]: - break - else: - raise AssertionError("no appropriate value found") - - a = lift_to_V(a) - # compute the minimal polynomial of a - m = [to_VsW(Ob[0])] # 1 in VsW - apow = a - while True: - v = to_VsW(apow) - try: - sol = matrix(m).solve_left(v) - except ValueError: - m.append(v) - apow = mul_vec(apow, a) - continue - break - - minpol = X**len(sol) - P(list(sol)) - - # The minimal polynomial of a has only linear factors and at least two - # of them. We set f to the first factor and g to the product of the rest. - fac = minpol.factor() - f = fac[0][0] - g = (fac/f).expand() - d,u,v = f.xgcd(g) - - assert d == 1, "Not relatively prime {} and {}".format(f,g) - - # finally, idempotent! - e = lift_to_V(sum([c1*c2 for c1,c2 in zip(u*f,m)])) - - h1 = add(h, matrix([mul_vec(e,Ob[i]) for i in range(n)])) - h2 = add(h, matrix([mul_vec(Ob[0]-e,Ob[i]) for i in range(n)])) - - return split(h1) + split(h2) - - decomposition = [] - for i in range(len(Hb)): - index = i + 1 # Hb starts with H_1 - for prime, degree in split(Hb[i]): - # Compute an element beta in O but not in pO. How to find beta - # is explained in Section 4.8.3 of [Coh1993]. We keep beta - # as a vector over k[x] with respect to the basis of O. - m =[] - for i in range(n): - r = [] - for g in prime._hnf: - r += sum(to(g[j]) * mtable[i][j] for j in range(n)) - m.append(r) - beta = [fr(e) for e in matrix(m).left_kernel().basis()[0]] - - prime.is_prime.set_cache(True) - prime._prime_below = ideal - prime._relative_degree = degree - prime._ramification_index = index - prime._beta = beta - - decomposition.append((prime, degree, index)) - - return decomposition - - -class FunctionFieldMaximalOrderInfinite(FunctionFieldMaximalOrder, FunctionFieldOrderInfinite): - """ - Base class of maximal infinite orders of function fields. - """ - def _repr_(self): - """ - EXAMPLES:: - - sage: FunctionField(QQ,'y').maximal_order_infinite() - Maximal infinite order of Rational function field in y over Rational Field + sage: FunctionField(QQ,'y').maximal_order_infinite() + Maximal infinite order of Rational function field in y over Rational Field sage: K.<x> = FunctionField(GF(2)); R.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: F.maximal_order_infinite() + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) # needs sage.rings.function_field + sage: F.maximal_order_infinite() # needs sage.modules sage.rings.function_field Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2 """ - return "Maximal infinite order of %s"%(self.function_field(),) - - -class FunctionFieldMaximalOrderInfinite_rational(FunctionFieldMaximalOrderInfinite): - """ - Maximal infinite orders of rational function fields. - - INPUT: - - - ``field`` -- a rational function field - - EXAMPLES:: - - sage: K.<t> = FunctionField(GF(19)); K - Rational function field in t over Finite Field of size 19 - sage: R = K.maximal_order_infinite(); R - Maximal infinite order of Rational function field in t over Finite Field of size 19 - """ - def __init__(self, field, category=None): - """ - Initialize. - - TESTS:: - - sage: K.<t> = FunctionField(GF(19)) - sage: O = K.maximal_order_infinite() - sage: TestSuite(O).run(skip='_test_gcd_vs_xgcd') - """ - FunctionFieldOrderInfinite.__init__(self, field, ideal_class=FunctionFieldIdealInfinite_rational, - category=PrincipalIdealDomains().or_subcategory(category)) - self._populate_coercion_lists_(coerce_list=[field.constant_base_field()]) - - def _element_constructor_(self, f): - """ - Make ``f`` an element of this order. - - EXAMPLES:: - - sage: K.<y> = FunctionField(QQ) - sage: O = K.maximal_order() - sage: O._element_constructor_(y) - y - sage: O._element_constructor_(1/y) - Traceback (most recent call last): - ... - TypeError: 1/y is not an element of Maximal order of Rational function field in y over Rational Field - """ - F = self.function_field() - try: - f = F(f) - except TypeError: - raise TypeError("unable to convert to an element of {}".format(F)) - - if f.denominator().degree() < f.numerator().degree(): - raise TypeError("{} is not an element of {}".format(f, self)) - - return f - - def basis(self): - """ - Return the basis (=1) of the order as a module over the polynomial ring. - - EXAMPLES:: - - sage: K.<t> = FunctionField(GF(19)) - sage: O = K.maximal_order() - sage: O.basis() - (1,) - """ - return 1/self.function_field().gen() - - def gen(self, n=0): - """ - Return the ``n``-th generator of self. Since there is only one generator ``n`` must be 0. - - EXAMPLES:: - - sage: O = FunctionField(QQ,'y').maximal_order() - sage: O.gen() - y - sage: O.gen(1) - Traceback (most recent call last): - ... - IndexError: there is only one generator - """ - if n != 0: - raise IndexError("there is only one generator") - return self._gen - - def ngens(self): - """ - Return 1 the number of generators of the order. - - EXAMPLES:: - - sage: FunctionField(QQ,'y').maximal_order().ngens() - 1 - """ - return 1 - - def prime_ideal(self): - """ - Return the unique prime ideal of the order. - - EXAMPLES:: - - sage: K.<t> = FunctionField(GF(19)) - sage: O = K.maximal_order_infinite() - sage: O.prime_ideal() - Ideal (1/t) of Maximal infinite order of Rational function field in t - over Finite Field of size 19 - """ - return self.ideal( 1/self.function_field().gen() ) - - def ideal(self, *gens): - """ - Return the fractional ideal generated by ``gens``. - - INPUT: - - - ``gens`` -- elements of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(QQ) - sage: O = K.maximal_order_infinite() - sage: O.ideal(x) - Ideal (x) of Maximal infinite order of Rational function field in x over Rational Field - sage: O.ideal([x,1/x]) == O.ideal(x,1/x) # multiple generators may be given as a list - True - sage: O.ideal(x^3+1,x^3+6) - Ideal (x^3) of Maximal infinite order of Rational function field in x over Rational Field - sage: I = O.ideal((x^2+1)*(x^3+1),(x^3+6)*(x^2+1)); I - Ideal (x^5) of Maximal infinite order of Rational function field in x over Rational Field - sage: O.ideal(I) - Ideal (x^5) of Maximal infinite order of Rational function field in x over Rational Field - """ - if len(gens) == 1: - gens = gens[0] - if not isinstance(gens, (list, tuple)): - if isinstance(gens, FunctionFieldIdeal): - gens = gens.gens() - else: - gens = (gens,) - K = self.function_field() - gens = [K(g) for g in gens] - try: - d = max(g.numerator().degree() - g.denominator().degree() for g in gens if g != 0) - gen = K.gen() ** d - except ValueError: # all gens are zero - gen = K(0) - - return self.ideal_monoid().element_class(self, gen) - - -class FunctionFieldMaximalOrderInfinite_polymod(FunctionFieldMaximalOrderInfinite): - """ - Maximal infinite orders of function fields. - - INPUT: - - - ``field`` -- function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: F.maximal_order_infinite() - Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2 - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: L.maximal_order_infinite() - Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x - """ - def __init__(self, field, category=None): - """ - Initialize. - - TESTS:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = PolynomialRing(K) - sage: F.<y> = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order_infinite() - sage: TestSuite(O).run() - """ - FunctionFieldOrderInfinite.__init__(self, field, ideal_class=FunctionFieldIdealInfinite_polymod) - - M, from_M, to_M = field._inversion_isomorphism() - basis = [from_M(g) for g in M.maximal_order().basis()] - - V, from_V, to_V = field.vector_space() - R = field.base_field().maximal_order_infinite() - - self._basis = tuple(basis) - self._module = V.span_of_basis([to_V(v) for v in basis]) - self._module_base_ring = R - self._to_module = to_V - - def _element_constructor_(self, f): - """ - Make ``f`` an element of this order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: Oinf.basis() - (1, 1/x*y) - sage: 1 in Oinf - True - sage: 1/x*y in Oinf - True - sage: x*y in Oinf - False - sage: 1/x in Oinf - True - """ - F = self.function_field() - - try: - f = F(f) - except TypeError: - raise TypeError("unable to convert to an element of {}".format(F)) - - O = F.base_field().maximal_order_infinite() - coordinates = self.coordinate_vector(f) - if not all(c in O for c in coordinates): - raise TypeError("%r is not an element of %r"%(f,self)) - - return f - - def basis(self): - """ - Return a basis of this order as a module over the maximal order - of the base function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: L.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: Oinf = L.maximal_order_infinite() - sage: Oinf.basis() - (1, 1/x^2*y, (1/(x^4 + x^3 + x^2))*y^2) - - :: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: Oinf.basis() - (1, 1/x*y) - """ - return self._basis - - def gen(self, n=0): - """ - Return the ``n``-th generator of the order. - - The basis elements of the order are generators. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: L.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: Oinf = L.maximal_order_infinite() - sage: Oinf.gen() - 1 - sage: Oinf.gen(1) - 1/x^2*y - sage: Oinf.gen(2) - (1/(x^4 + x^3 + x^2))*y^2 - sage: Oinf.gen(3) - Traceback (most recent call last): - ... - IndexError: there are only 3 generators - """ - if not ( n >= 0 and n < self.ngens() ): - raise IndexError("there are only {} generators".format(self.ngens())) - - return self._basis[n] - - def ngens(self): - """ - Return the number of generators of the order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: L.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: Oinf = L.maximal_order_infinite() - sage: Oinf.ngens() - 3 - """ - return len(self._basis) - - def ideal(self, *gens): - """ - Return the ideal generated by ``gens``. - - INPUT: - - - ``gens`` -- tuple of elements of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(x,y); I - Ideal (y) of Maximal infinite order of Function field - in y defined by y^3 + x^6 + x^4 + x^2 - - :: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(x,y); I - Ideal (x) of Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x - """ - if len(gens) == 1: - gens = gens[0] - if not type(gens) in (list,tuple): - gens = (gens,) - mgens = [g * b for g in gens for b in self._basis] - return self.ideal_with_gens_over_base(mgens) - - def ideal_with_gens_over_base(self, gens): - """ - Return the ideal generated by ``gens`` as a module. - - INPUT: - - - ``gens`` -- tuple of elements of the function field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); R.<t> = K[] - sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: Oinf = F.maximal_order_infinite() - sage: Oinf.ideal_with_gens_over_base((x^2, y, (1/(x^2 + x + 1))*y^2)) - Ideal (y) of Maximal infinite order of Function field in y - defined by y^3 + x^6 + x^4 + x^2 - """ - F = self.function_field() - iF, from_iF, to_iF = F._inversion_isomorphism() - iO = iF.maximal_order() - - ideal = iO.ideal_with_gens_over_base([to_iF(g) for g in gens]) - - if not ideal.is_zero(): - # Now the ideal does not correspond exactly to the ideal in the - # maximal infinite order through the inversion isomorphism. The - # reason is that the ideal also has factors not lying over x. - # The following procedure removes the spurious factors. The idea - # is that for an integral ideal I, J_n = I + (xO)^n stabilizes - # if n is large enough, and then J_n is the I with the spurious - # factors removed. For a fractional ideal, we also need to find - # the largest factor x^m that divides the denominator. - d = ideal.denominator() - h = ideal.hnf() - x = d.parent().gen() - - # find the largest factor x^m that divides the denominator - i = 0 - while d[i].is_zero(): - i += 1 - d = x ** i - - # find the largest n such that I + (xO)^n stabilizes - h1 = h - MS = h1.matrix_space() - k = MS.identity_matrix() - while True: - k = x * k - - h2 = block_matrix([[h],[k]]) - reversed_hermite_form(h2) - i = 0 - while i < h2.nrows() and h2.row(i).is_zero(): - i += 1 - h2 = h2[i:] # remove zero rows - - if h2 == h1: - break - h1 = h2 - - # reconstruct ideal - ideal = iO._ideal_from_vectors_and_denominator(list(h1), d) - - return self.ideal_monoid().element_class(self, ideal) - - def _to_iF(self, I): - """ - Return the ideal in the inverted function field from ``I``. - - INPUT: - - - ``I`` -- ideal of the function field - - EXAMPLES:: - - sage: K.<x>=FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y>=K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(y) - sage: Oinf._to_iF(I) - Ideal (1, 1/x*s) of Maximal order of Function field in s - defined by s^2 + x*s + x^3 + x - """ - F = self.function_field() - iF,from_iF,to_iF = F._inversion_isomorphism() - iO = iF.maximal_order() - iI = iO.ideal_with_gens_over_base([to_iF(b) for b in I.gens_over_base()]) - return iI - - def decomposition(self): - r""" - Return prime ideal decomposition of `pO_\infty` where `p` is the unique - prime ideal of the maximal infinite order of the rational function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] - sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) - sage: Oinf = F.maximal_order_infinite() - sage: Oinf.decomposition() - [(Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1) of Maximal infinite order - of Function field in y defined by y^3 + x^6 + x^4 + x^2, 1, 1), - (Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1/x^2*y + 1) of Maximal infinite order - of Function field in y defined by y^3 + x^6 + x^4 + x^2, 2, 1)] - - :: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: Oinf.decomposition() - [(Ideal (1/x*y) of Maximal infinite order of Function field in y - defined by y^2 + y + (x^2 + 1)/x, 1, 2)] - - :: - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) - sage: Oinf = F.maximal_order_infinite() - sage: Oinf.decomposition() - [(Ideal (1/x^2*y - 1) of Maximal infinite order - of Function field in y defined by y^3 - x^6 - 2*x^5 - 3*x^4 - 2*x^3 - x^2, 1, 1), - (Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1/x^2*y + 1) of Maximal infinite order - of Function field in y defined by y^3 - x^6 - 2*x^5 - 3*x^4 - 2*x^3 - x^2, 2, 1)] - - :: - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: Oinf.decomposition() - [(Ideal (1/x*y) of Maximal infinite order of Function field in y - defined by y^2 + y + (x^2 + 1)/x, 1, 2)] - """ - F = self.function_field() - iF,from_iF,to_iF = F._inversion_isomorphism() - - x = iF.base_field().gen() - iO = iF.maximal_order() - io = iF.base_field().maximal_order() - ip = io.ideal(x) - - dec = [] - for iprime, deg, exp in iO.decomposition(ip): - prime = self.ideal_monoid().element_class(self, iprime) - dec.append((prime, deg, exp)) - return dec - - def different(self): - """ - Return the different ideal of the maximal infinite order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: Oinf.different() - Ideal (1/x) of Maximal infinite order of Function field in y - defined by y^2 + y + (x^2 + 1)/x - """ - T = self._codifferent_matrix() - codiff_gens = [] - for c in T.inverse().columns(): - codiff_gens.append(sum([ci*bi for ci,bi in zip(c,self.basis())])) - codiff = self.ideal_with_gens_over_base(codiff_gens) - return ~codiff - - @cached_method - def _codifferent_matrix(self): - """ - Return the codifferent matrix of the maximal infinite order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: Oinf._codifferent_matrix() - [ 0 1/x] - [ 1/x 1/x^2] - """ - rows = [] - for u in self.basis(): - row = [] - for v in self.basis(): - row.append((u*v).trace()) - rows.append(row) - T = matrix(rows) - return T - - def coordinate_vector(self, e): - """ - Return the coordinates of ``e`` with respect to the basis of the order. - - INPUT: - - - ``e`` -- element of the function field - - The returned coordinates are in the base maximal infinite order if and only - if the element is in the order. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: f = 1/y^2 - sage: f in Oinf - True - sage: Oinf.coordinate_vector(f) - ((x^3 + x^2 + x)/(x^4 + 1), x^3/(x^4 + 1)) - """ - return self._module.coordinate_vector(self._to_module(e)) + return "Maximal infinite order of %s" % (self.function_field(),) diff --git a/src/sage/rings/function_field/order_basis.py b/src/sage/rings/function_field/order_basis.py new file mode 100644 index 00000000000..eebaeab97d1 --- /dev/null +++ b/src/sage/rings/function_field/order_basis.py @@ -0,0 +1,585 @@ +# sage.doctest: needs sage.modules (because __init__ constructs a vector space) +r""" +Orders of function fields: basis +""" + +# **************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2011 Julian Rueth <julian.rueth@gmail.com> +# 2017-2020 Kwankyu Lee +# 2019 Brent Baccala +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# **************************************************************************** + +from .ideal import FunctionFieldIdeal, FunctionFieldIdeal_module, FunctionFieldIdealInfinite_module +from .order import FunctionFieldOrder, FunctionFieldOrderInfinite + + +class FunctionFieldOrder_basis(FunctionFieldOrder): + """ + Order given by a basis over the maximal order of the base field. + + INPUT: + + - ``basis`` -- list of elements of the function field + + - ``check`` -- (default: ``True``) if ``True``, check whether the module + that ``basis`` generates forms an order + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) # needs sage.rings.function_field + sage: O = L.equation_order(); O # needs sage.rings.function_field + Order in Function field in y defined by y^4 + x*y + 4*x + 1 + + The basis only defines an order if the module it generates is closed under + multiplication and contains the identity element:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) # needs sage.rings.function_field + sage: y.is_integral() # needs sage.rings.function_field + False + sage: L.order(y) # needs sage.rings.function_field + Traceback (most recent call last): + ... + ValueError: the module generated by basis (1, y, y^2, y^3, y^4) + must be closed under multiplication + + The basis also has to be linearly independent and of the same rank as the + degree of the function field of its elements (only checked when ``check`` + is ``True``):: + + sage: # needs sage.rings.function_field + sage: L.order(L(x)) + Traceback (most recent call last): + ... + ValueError: basis (1, x, x^2, x^3, x^4) is not linearly independent + sage: from sage.rings.function_field.order_basis import FunctionFieldOrder_basis + sage: FunctionFieldOrder_basis((y,y,y^3,y^4,y^5)) + Traceback (most recent call last): + ... + ValueError: basis (y, y, y^3, y^4, 2*x*y + (x^4 + 1)/x) is not linearly independent + """ + def __init__(self, basis, check=True): + """ + Initialize. + + TESTS:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.equation_order() + sage: TestSuite(O).run() + """ + if len(basis) == 0: + raise ValueError("basis must have positive length") + + field = basis[0].parent() + if len(basis) != field.degree(): + raise ValueError("length of basis must equal degree of field") + + FunctionFieldOrder.__init__(self, field, ideal_class=FunctionFieldIdeal_module) + + V, from_V, to_V = field.vector_space() + + R = V.base_field().maximal_order() + self._module = V.span([to_V(b) for b in basis], base_ring=R) + + self._from_module = from_V + self._to_module = to_V + self._basis = tuple(basis) + self._ring = field.polynomial_ring() + self._populate_coercion_lists_(coerce_list=[self._ring]) + + if check: + if self._module.rank() != field.degree(): + raise ValueError("basis {} is not linearly independent".format(basis)) + if not to_V(field(1)) in self._module: + raise ValueError("the identity element must be in the module spanned by basis {}".format(basis)) + if not all(to_V(a*b) in self._module for a in basis for b in basis): + raise ValueError("the module generated by basis {} must be closed under multiplication".format(basis)) + + def _element_constructor_(self, f): + """ + Construct an element of this order from ``f``. + + INPUT: + + - ``f`` -- element + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K.maximal_order()._element_constructor_(x) + x + """ + F = self.function_field() + + try: + f = F(f) + except TypeError: + raise TypeError("unable to convert to an element of {}".format(F)) + + V, fr_V, to_V = F.vector_space() + f_vector = to_V(f) + if f_vector not in self._module: + raise TypeError("{} is not an element of {}".format(f_vector, self)) + + return f + + def ideal_with_gens_over_base(self, gens): + """ + Return the fractional ideal with basis ``gens`` over the + maximal order of the base field. + + It is not checked that the ``gens`` really generates an ideal. + + INPUT: + + - ``gens`` -- list of elements of the function field + + EXAMPLES: + + We construct an ideal in a rational function field:: + + sage: K.<y> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal([y]); I + Ideal (y) of Maximal order of Rational function field in y over Rational Field + sage: I * I + Ideal (y^2) of Maximal order of Rational function field in y over Rational Field + + We construct some ideals in a nontrivial function field:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.equation_order(); O + Order in Function field in y defined by y^2 + 6*x^3 + 6 + sage: I = O.ideal_with_gens_over_base([1, y]); I + Ideal (1) of Order in Function field in y defined by y^2 + 6*x^3 + 6 + sage: I.module() + Free module of degree 2 and rank 2 over + Maximal order of Rational function field in x over Finite Field of size 7 + Echelon basis matrix: + [1 0] + [0 1] + + There is no check if the resulting object is really an ideal:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.equation_order() + sage: I = O.ideal_with_gens_over_base([y]); I + Ideal (y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 + sage: y in I + True + sage: y^2 in I + False + """ + F = self.function_field() + S = F.base_field().maximal_order() + + gens = [F(a) for a in gens] + + V, from_V, to_V = F.vector_space() + M = V.span([to_V(b) for b in gens], base_ring=S) + + return self.ideal_monoid().element_class(self, M) + + def ideal(self, *gens): + """ + Return the fractional ideal generated by the elements in ``gens``. + + INPUT: + + - ``gens`` -- list of generators or an ideal in a ring which + coerces to this order + + EXAMPLES:: + + sage: K.<y> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: O.ideal(y) + Ideal (y) of Maximal order of Rational function field in y over Rational Field + sage: O.ideal([y,1/y]) == O.ideal(y,1/y) # multiple generators may be given as a list + True + + A fractional ideal of a nontrivial extension:: + + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: O = K.maximal_order() + sage: I = O.ideal(x^2 - 4) + + sage: # needs sage.rings.function_field + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: S = L.equation_order() + sage: S.ideal(1/y) + Ideal (1, (6/(x^3 + 1))*y) of + Order in Function field in y defined by y^2 + 6*x^3 + 6 + sage: I2 = S.ideal(x^2 - 4); I2 + Ideal (x^2 + 3) of Order in Function field in y defined by y^2 + 6*x^3 + 6 + sage: I2 == S.ideal(I) + True + """ + if len(gens) == 1: + gens = gens[0] + if not isinstance(gens, (list, tuple)): + if isinstance(gens, FunctionFieldIdeal): + gens = gens.gens() + else: + gens = [gens] + K = self.function_field() + + return self.ideal_with_gens_over_base([b*K(g) for b in self.basis() for g in gens]) + + def polynomial(self): + """ + Return the defining polynomial of the function field of which this is an order. + + EXAMPLES:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.equation_order() + sage: O.polynomial() + y^4 + x*y + 4*x + 1 + """ + return self._field.polynomial() + + def basis(self): + """ + Return a basis of the order over the maximal order of the base field. + + EXAMPLES:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.equation_order() + sage: O.basis() + (1, y, y^2, y^3) + """ + return self._basis + + def free_module(self): + """ + Return the free module formed by the basis over the maximal order + of the base function field. + + EXAMPLES:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.equation_order() + sage: O.free_module() + Free module of degree 4 and rank 4 over Maximal order of Rational + function field in x over Finite Field of size 7 + Echelon basis matrix: + [1 0 0 0] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + """ + return self._module + + def coordinate_vector(self, e): + """ + Return the coordinates of ``e`` with respect to the basis of the order. + + INPUT: + + - ``e`` -- element of the order or the function field + + EXAMPLES:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.equation_order() + sage: f = (x + y)^3 + sage: O.coordinate_vector(f) + (x^3, 3*x^2, 3*x, 1) + """ + return self._module.coordinate_vector(self._to_module(e), check=False) + + +class FunctionFieldOrderInfinite_basis(FunctionFieldOrderInfinite): + """ + Order given by a basis over the infinite maximal order of the base field. + + INPUT: + + - ``basis`` -- elements of the function field + + - ``check`` -- boolean (default: ``True``); if ``True``, check the basis generates + an order + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) # needs sage.rings.function_field + sage: O = L.equation_order_infinite(); O # needs sage.rings.function_field + Infinite order in Function field in y defined by y^4 + x*y + 4*x + 1 + + The basis only defines an order if the module it generates is closed under + multiplication and contains the identity element (only checked when + ``check`` is ``True``):: + + sage: O = L.order_infinite_with_basis([1, y, 1/x^2*y^2, y^3]); O # needs sage.rings.function_field + Traceback (most recent call last): + ... + ValueError: the module generated by basis (1, y, 1/x^2*y^2, y^3) + must be closed under multiplication + + The basis also has to be linearly independent and of the same rank as the + degree of the function field of its elements (only checked when ``check`` + is ``True``):: + + sage: O = L.order_infinite_with_basis([1, y, 1/x^2*y^2, 1 + y]); O # needs sage.rings.function_field + Traceback (most recent call last): + ... + ValueError: The given basis vectors must be linearly independent. + + Note that 1 does not need to be an element of the basis, as long as it is + in the module spanned by it:: + + sage: # needs sage.rings.function_field + sage: O = L.order_infinite_with_basis([1 + 1/x*y, 1/x*y, 1/x^2*y^2, 1/x^3*y^3]); O + Infinite order in Function field in y defined by y^4 + x*y + 4*x + 1 + sage: O.basis() + (1/x*y + 1, 1/x*y, 1/x^2*y^2, 1/x^3*y^3) + """ + def __init__(self, basis, check=True): + """ + Initialize. + + TESTS:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.equation_order_infinite() + sage: TestSuite(O).run() + """ + if len(basis) == 0: + raise ValueError("basis must have positive length") + + field = basis[0].parent() + if len(basis) != field.degree(): + raise ValueError("length of basis must equal degree of field") + + FunctionFieldOrderInfinite.__init__(self, field, ideal_class=FunctionFieldIdealInfinite_module) + + # function field element f is in this order if and only if + # W.coordinate_vector(to(f)) in M + V, fr, to = field.vector_space() + R = field.base_field().maximal_order_infinite() + W = V.span_of_basis([to(v) for v in basis]) + from sage.modules.free_module import FreeModule + M = FreeModule(R, W.dimension()) + self._basis = tuple(basis) + self._ambient_space = W + self._module = M + + self._ring = field.polynomial_ring() + self._populate_coercion_lists_(coerce_list=[self._ring]) + + if check: + if self._module.rank() != field.degree(): + raise ValueError("basis {} is not linearly independent".format(basis)) + if not W.coordinate_vector(to(field(1))) in self._module: + raise ValueError("the identity element must be in the module spanned by basis {}".format(basis)) + if not all(W.coordinate_vector(to(a*b)) in self._module for a in basis for b in basis): + raise ValueError("the module generated by basis {} must be closed under multiplication".format(basis)) + + def _element_constructor_(self, f): + """ + Construct an element of this order. + + INPUT: + + - ``f`` -- element + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: O(x) + x + sage: O(1/x) + Traceback (most recent call last): + ... + TypeError: 1/x is not an element of Maximal order of Rational function field in x over Rational Field + """ + F = self.function_field() + try: + f = F(f) + except TypeError: + raise TypeError("unable to convert to an element of {}".format(F)) + + V, fr_V, to_V = F.vector_space() + W = self._ambient_space + if not W.coordinate_vector(to_V(f)) in self._module: + raise TypeError("{} is not an element of {}".format(f, self)) + + return f + + def ideal_with_gens_over_base(self, gens): + """ + Return the fractional ideal with basis ``gens`` over the + maximal order of the base field. + + It is not checked that ``gens`` really generates an ideal. + + INPUT: + + - ``gens`` -- list of elements that are a basis for the ideal over the + maximal order of the base field + + EXAMPLES: + + We construct an ideal in a rational function field:: + + sage: K.<y> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal([y]); I + Ideal (y) of Maximal order of Rational function field in y over Rational Field + sage: I*I + Ideal (y^2) of Maximal order of Rational function field in y over Rational Field + + We construct some ideals in a nontrivial function field:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.equation_order(); O + Order in Function field in y defined by y^2 + 6*x^3 + 6 + sage: I = O.ideal_with_gens_over_base([1, y]); I + Ideal (1) of Order in Function field in y defined by y^2 + 6*x^3 + 6 + sage: I.module() + Free module of degree 2 and rank 2 over + Maximal order of Rational function field in x over Finite Field of size 7 + Echelon basis matrix: + [1 0] + [0 1] + + There is no check if the resulting object is really an ideal:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.equation_order() + sage: I = O.ideal_with_gens_over_base([y]); I + Ideal (y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 + sage: y in I + True + sage: y^2 in I + False + """ + F = self.function_field() + S = F.base_field().maximal_order_infinite() + + gens = [F(a) for a in gens] + + V, from_V, to_V = F.vector_space() + M = V.span([to_V(b) for b in gens], base_ring=S) # not work + + return self.ideal_monoid().element_class(self, M) + + def ideal(self, *gens): + """ + Return the fractional ideal generated by the elements in ``gens``. + + INPUT: + + - ``gens`` -- list of generators or an ideal in a ring which coerces + to this order + + EXAMPLES:: + + sage: K.<y> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: O.ideal(y) + Ideal (y) of Maximal order of Rational function field in y over Rational Field + sage: O.ideal([y,1/y]) == O.ideal(y,1/y) # multiple generators may be given as a list + True + + A fractional ideal of a nontrivial extension:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: O = K.maximal_order_infinite() + sage: I = O.ideal(x^2 - 4) + sage: L.<y> = K.extension(y^2 - x^3 - 1) # needs sage.rings.function_field + sage: S = L.order_infinite_with_basis([1, 1/x^2*y]) # needs sage.rings.function_field + """ + if len(gens) == 1: + gens = gens[0] + if not isinstance(gens, (list, tuple)): + if isinstance(gens, FunctionFieldIdeal): + gens = gens.gens() + else: + gens = [gens] + K = self.function_field() + + return self.ideal_with_gens_over_base([b*K(g) for b in self.basis() for g in gens]) + + def polynomial(self): + """ + Return the defining polynomial of the function field of which this is an order. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) # needs sage.rings.function_field + sage: O = L.equation_order() # needs sage.rings.function_field + sage: O.polynomial() # needs sage.rings.function_field + y^4 + x*y + 4*x + 1 + """ + return self._field.polynomial() + + def basis(self): + """ + Return a basis of this order over the maximal order of the base field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) # needs sage.rings.function_field + sage: O = L.equation_order() # needs sage.rings.function_field + sage: O.basis() # needs sage.rings.function_field + (1, y, y^2, y^3) + """ + return self._basis + + def free_module(self): + """ + Return the free module formed by the basis over the maximal order of + the base field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) # needs sage.rings.function_field + sage: O = L.equation_order() # needs sage.rings.function_field + sage: O.free_module() # needs sage.rings.function_field + Free module of degree 4 and rank 4 over Maximal order of Rational + function field in x over Finite Field of size 7 + Echelon basis matrix: + [1 0 0 0] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + """ + return self._module diff --git a/src/sage/rings/function_field/order_polymod.py b/src/sage/rings/function_field/order_polymod.py new file mode 100644 index 00000000000..97f5a625819 --- /dev/null +++ b/src/sage/rings/function_field/order_polymod.py @@ -0,0 +1,1474 @@ +# sage.doctest: optional - sage.rings.function_field +r""" +Orders of function fields: extension +""" + +# **************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2011 Julian Rueth <julian.rueth@gmail.com> +# 2017-2020 Kwankyu Lee +# 2019 Brent Baccala +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.arith.functions import lcm +from sage.misc.cachefunc import cached_method +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + +from .ideal import FunctionFieldIdeal +from .ideal_polymod import ( + FunctionFieldIdeal_polymod, + FunctionFieldIdeal_global, + FunctionFieldIdealInfinite_polymod +) +from .order import FunctionFieldMaximalOrder, FunctionFieldMaximalOrderInfinite + + +class FunctionFieldMaximalOrder_polymod(FunctionFieldMaximalOrder): + """ + Maximal orders of extensions of function fields. + """ + + def __init__(self, field, ideal_class=FunctionFieldIdeal_polymod): + """ + Initialize. + + TESTS:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.maximal_order() + sage: TestSuite(O).run() + """ + FunctionFieldMaximalOrder.__init__(self, field, ideal_class) + + from sage.modules.free_module_element import vector + from .function_field_polymod import FunctionField_integral + + if isinstance(field, FunctionField_integral): + basis = field._maximal_order_basis() + else: + model, from_model, to_model = field.monic_integral_model('z') + basis = [from_model(g) for g in model._maximal_order_basis()] + + V, fr, to = field.vector_space() + R = field.base_field().maximal_order() + + # This module is over R, but linear algebra over R (MaximalOrder) + # is not well supported in Sage. So we keep it as a vector space + # over rational function field. + self._module = V.span_of_basis([to(b) for b in basis]) + self._module_base_ring = R + self._basis = tuple(basis) + self._from_module = fr + self._to_module = to + + # multiplication table (lower triangular) + n = len(basis) + self._mtable = [] + for i in range(n): + row = [] + for j in range(n): + row.append(self._coordinate_vector(basis[i] * basis[j])) + self._mtable.append(row) + + zero = vector(R._ring, n * [0]) + + def mul_vecs(f, g): + s = zero + for i in range(n): + if f[i].is_zero(): + continue + for j in range(n): + if g[j].is_zero(): + continue + s += f[i] * g[j] * self._mtable[i][j] + return s + self._mul_vecs = mul_vecs + + # We prepare for using Kummer's theorem to decompose primes. Note + # that Kummer's theorem applies to most places. Here we find + # places for which the theorem does not apply. + + # this element is integral over k[x] and a generator of the field. + for gen in basis: + phi = gen.minimal_polynomial() + if phi.degree() == n: + break + + assert phi.degree() == n + + gen_vec = self._coordinate_vector(gen) + g = gen_vec.parent().gen(0) # x + gen_vec_pow = [g] + for i in range(n): + g = mul_vecs(g, gen_vec) + gen_vec_pow.append(g) + + # find places where {1,gen,...,gen^(n-1)} is not integral basis + W = V.span_of_basis([to(gen ** i) for i in range(phi.degree())]) + + supp = [] + for g in basis: + for c in W.coordinate_vector(to(g), check=False): + if not c.is_zero(): + supp += [f for f,_ in c.denominator().factor()] + supp = set(supp) + + self._kummer_gen = gen + self._kummer_gen_vec_pow = gen_vec_pow + self._kummer_polynomial = phi + self._kummer_places = supp + + def _element_constructor_(self, f): + """ + Construct an element of this order from ``f``. + + INPUT: + + - ``f`` -- element convertible to the function field + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 - x*Y + x^2 + 1) + sage: O = L.maximal_order() + sage: y in O + True + sage: 1/y in O + False + sage: x in O + True + sage: 1/x in O + False + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: 1 in O + True + sage: y in O + False + sage: x*y in O + True + sage: x^2*y in O + True + """ + F = self.function_field() + f = F(f) + # check if f is in this order + if not all(e in self._module_base_ring for e in self.coordinate_vector(f)): + raise TypeError( "{} is not an element of {}".format(f, self) ) + + return f + + def ideal_with_gens_over_base(self, gens): + """ + Return the fractional ideal with basis ``gens`` over the + maximal order of the base field. + + INPUT: + + - ``gens`` -- list of elements that generates the ideal over the + maximal order of the base field + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.maximal_order(); O + Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 + sage: I = O.ideal_with_gens_over_base([1, y]); I + Ideal (1) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 + sage: I.module() + Free module of degree 2 and rank 2 over + Maximal order of Rational function field in x over Finite Field of size 7 + Echelon basis matrix: + [1 0] + [0 1] + + There is no check if the resulting object is really an ideal:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.equation_order() + sage: I = O.ideal_with_gens_over_base([y]); I + Ideal (y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 + sage: y in I + True + sage: y^2 in I + False + """ + return self._ideal_from_vectors([self.coordinate_vector(g) for g in gens]) + + def _ideal_from_vectors(self, vecs): + """ + Return an ideal generated as a module by vectors over rational function + field. + + INPUT: + + - ``vec`` -- list of vectors + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.maximal_order() + sage: v1 = O.coordinate_vector(x^3 + 1) + sage: v2 = O.coordinate_vector(y) + sage: v1 + (x^3 + 1, 0) + sage: v2 + (0, 1) + sage: O._ideal_from_vectors([v1, v2]) + Ideal (y) of Maximal order of Function field in y + defined by y^2 + 6*x^3 + 6 + """ + d = lcm([v.denominator() for v in vecs]) + vecs = [[(d*c).numerator() for c in v] for v in vecs] + return self._ideal_from_vectors_and_denominator(vecs, d, check=False) + + def _ideal_from_vectors_and_denominator(self, vecs, d=1, check=True): + """ + Return an ideal generated as a module by vectors divided by ``d`` over + the polynomial ring underlying the rational function field. + + INPUT: + + - ``vec`` -- list of vectors over the polynomial ring + + - ``d`` -- (default: 1) a nonzero element of the polynomial ring + + - ``check`` -- boolean (default: ``True``); if ``True``, compute the real + denominator of the vectors, possibly different from ``d``. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: O = L.maximal_order() + sage: I = O.ideal(y^2) + sage: m = I.basis_matrix() + sage: v1 = m[0] + sage: v2 = m[1] + sage: v1 + (x^3 + 1, 0) + sage: v2 + (0, x^3 + 1) + sage: O._ideal_from_vectors([v1, v2]) # indirect doctest + Ideal (x^3 + 1) of Maximal order of Function field in y + defined by y^2 + 6*x^3 + 6 + """ + from sage.matrix.constructor import matrix + from .hermite_form_polynomial import reversed_hermite_form + + R = self._module_base_ring._ring + + d = R(d) # make it sure that d is in the polynomial ring + + if check and not d.is_one(): # check if d is true denominator + M = [] + g = d + for v in vecs: + for c in v: + g = g.gcd(c) + if g.is_one(): + break + else: + M += list(v) + continue # for v in vecs + mat = matrix(R, vecs) + break + else: + d = d // g + mat = matrix(R, len(vecs), [c // g for c in M]) + else: + mat = matrix(R, vecs) + + # IMPORTANT: make it sure that pivot polynomials monic + # so that we get a unique hnf. Here the hermite form + # algorithm also makes the pivots monic. + + # compute the reversed hermite form with zero rows deleted + reversed_hermite_form(mat) + i = 0 + while i < mat.nrows() and mat.row(i).is_zero(): + i += 1 + hnf = mat[i:] # remove zero rows + + return self.ideal_monoid().element_class(self, hnf, d) + + def ideal(self, *gens, **kwargs): + """ + Return the fractional ideal generated by the elements in ``gens``. + + INPUT: + + - ``gens`` -- list of generators + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: O = K.maximal_order() + sage: I = O.ideal(x^2 - 4) + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: S = L.maximal_order() + sage: S.ideal(1/y) + Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field + in y defined by y^2 + 6*x^3 + 6 + sage: I2 = S.ideal(x^2 - 4); I2 + Ideal (x^2 + 3) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 + sage: I2 == S.ideal(I) + True + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: O = K.maximal_order() + sage: I = O.ideal(x^2 - 4) + sage: L.<y> = K.extension(y^2 - x^3 - 1) + sage: S = L.maximal_order() + sage: S.ideal(1/y) + Ideal ((1/(x^3 + 1))*y) of + Maximal order of Function field in y defined by y^2 - x^3 - 1 + sage: I2 = S.ideal(x^2-4); I2 + Ideal (x^2 - 4) of Maximal order of Function field in y defined by y^2 - x^3 - 1 + sage: I2 == S.ideal(I) + True + """ + if len(gens) == 1: + gens = gens[0] + if not isinstance(gens, (list, tuple)): + if isinstance(gens, FunctionFieldIdeal): + gens = gens.gens() + else: + gens = (gens,) + F = self.function_field() + mgens = [b*F(g) for g in gens for b in self.basis()] + return self.ideal_with_gens_over_base(mgens) + + def polynomial(self): + """ + Return the defining polynomial of the function field of which this is an order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.equation_order() + sage: O.polynomial() + y^4 + x*y + 4*x + 1 + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.equation_order() + sage: O.polynomial() + y^4 + x*y + 4*x + 1 + """ + return self._field.polynomial() + + def basis(self): + """ + Return a basis of the order over the maximal order of the base function + field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.equation_order() + sage: O.basis() + (1, y, y^2, y^3) + + sage: K.<x> = FunctionField(QQ) + sage: R.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^4 + x^12*t^2 + x^18*t + x^21 + x^18) + sage: O = F.maximal_order() + sage: O.basis() + (1, 1/x^4*y, 1/x^9*y^2, 1/x^13*y^3) + """ + return self._basis + + def gen(self, n=0): + """ + Return the ``n``-th generator of the order. + + The basis elements of the order are generators. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: L.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: O = L.maximal_order() + sage: O.gen() + 1 + sage: O.gen(1) + y + sage: O.gen(2) + (1/(x^3 + x^2 + x))*y^2 + sage: O.gen(3) + Traceback (most recent call last): + ... + IndexError: there are only 3 generators + """ + if not ( n >= 0 and n < self.ngens() ): + raise IndexError("there are only {} generators".format(self.ngens())) + + return self._basis[n] + + def ngens(self): + """ + Return the number of generators of the order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: L.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: Oinf = L.maximal_order() + sage: Oinf.ngens() + 3 + """ + return len(self._basis) + + def free_module(self): + """ + Return the free module formed by the basis over the maximal order of the base field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.maximal_order() + sage: O.free_module() + Free module of degree 4 and rank 4 over + Maximal order of Rational function field in x over Finite Field of size 7 + User basis matrix: + [1 0 0 0] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + """ + return self._module.change_ring(self._module_base_ring) + + def coordinate_vector(self, e): + """ + Return the coordinates of ``e`` with respect to the basis of this order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.maximal_order() + sage: O.coordinate_vector(y) + (0, 1, 0, 0) + sage: O.coordinate_vector(x*y) + (0, x, 0, 0) + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.equation_order() + sage: f = (x + y)^3 + sage: O.coordinate_vector(f) + (x^3, 3*x^2, 3*x, 1) + """ + return self._module.coordinate_vector(self._to_module(e)) + + def _coordinate_vector(self, e): + """ + Return the coordinate vector of ``e`` with respect to the basis + of the order. + + Assuming ``e`` is in the maximal order, the coordinates are given + as univariate polynomials in the underlying ring of the maximal + order of the rational function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.maximal_order() + sage: O._coordinate_vector(y) + (0, 1, 0, 0) + sage: O._coordinate_vector(x*y) + (0, x, 0, 0) + """ + from sage.modules.free_module_element import vector + + v = self._module.coordinate_vector(self._to_module(e), check=False) + return vector([c.numerator() for c in v]) + + @cached_method + def different(self): + """ + Return the different ideal of the function field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.maximal_order() + sage: O.different() + Ideal (y^3 + 2*x) + of Maximal order of Function field in y defined by y^4 + x*y + 4*x + 1 + """ + return ~self.codifferent() + + @cached_method + def codifferent(self): + """ + Return the codifferent ideal of the function field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.maximal_order() + sage: O.codifferent() + Ideal (1, (1/(x^4 + 4*x^3 + 3*x^2 + 6*x + 4))*y^3 + + ((5*x^3 + 6*x^2 + x + 6)/(x^4 + 4*x^3 + 3*x^2 + 6*x + 4))*y^2 + + ((x^3 + 2*x^2 + 2*x + 2)/(x^4 + 4*x^3 + 3*x^2 + 6*x + 4))*y + + 6*x/(x^4 + 4*x^3 + 3*x^2 + 6*x + 4)) of Maximal order of Function field + in y defined by y^4 + x*y + 4*x + 1 + """ + T = self._codifferent_matrix() + return self._ideal_from_vectors(T.inverse().columns()) + + @cached_method + def _codifferent_matrix(self): + """ + Return the matrix `T` defined in Proposition 4.8.19 of [Coh1993]_. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.maximal_order() + sage: O._codifferent_matrix() + [ 4 0 0 4*x] + [ 0 0 4*x 5*x + 3] + [ 0 4*x 5*x + 3 0] + [ 4*x 5*x + 3 0 3*x^2] + """ + from sage.matrix.constructor import matrix + + rows = [] + for u in self.basis(): + row = [] + for v in self.basis(): + row.append((u*v).trace()) + rows.append(row) + T = matrix(rows) + return T + + @cached_method + def decomposition(self, ideal): + """ + Return the decomposition of the prime ideal. + + INPUT: + + - ``ideal`` -- prime ideal of the base maximal order + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); R.<t> = K[] + sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: o = K.maximal_order() + sage: O = F.maximal_order() + sage: p = o.ideal(x + 1) + sage: O.decomposition(p) + [(Ideal (x + 1, y + 1) of Maximal order + of Function field in y defined by y^3 + x^6 + x^4 + x^2, 1, 1), + (Ideal (x + 1, (1/(x^3 + x^2 + x))*y^2 + y + 1) of Maximal order + of Function field in y defined by y^3 + x^6 + x^4 + x^2, 2, 1)] + + ALGORITHM: + + In principle, we're trying to compute a primary decomposition + of the extension of ``ideal`` in ``self`` (an order, and therefore + a ring). However, while we have primary decomposition methods + for polynomial rings, we lack any such method for an order. + Therefore, we construct ``self`` mod ``ideal`` as a + finite-dimensional algebra, a construct for which we do + support primary decomposition. + + See :trac:`28094` and https://github.com/sagemath/sage/files/10659303/decomposition.pdf.gz + + .. TODO:: + + Use Kummer's theorem to shortcut this code if possible, like as + done in :meth:`FunctionFieldMaximalOrder_global.decomposition()` + + """ + from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + + F = self.function_field() + n = F.degree() + + # Base rational function field + K = self.function_field().base_field() + + # Univariate polynomial ring isomorphic to the maximal order of K + o = PolynomialRing(K.constant_field(), K.gen()) + + # Prime ideal in o defined by the generator of ideal in the maximal + # order of K + p = o(ideal.gen().numerator()) + + # Residue field k = o mod p + k = o.quo(p) + + # Given an element of the function field expressed as a K-vector times + # the basis of this order, construct the n n-by-n matrices that show + # how to multiply by each of the basis elements. + matrices = [matrix(o, [self.coordinate_vector(b1*b2) for b1 in self.basis()]) + for b2 in self.basis()] + + # Let O denote the maximal order self. When reduced modulo p, + # matrices_reduced give the multiplication matrices used to form the + # algebra O mod pO. + matrices_reduced = list(map(lambda M: M.mod(p), matrices)) + A = FiniteDimensionalAlgebra(k, matrices_reduced) + + # Each prime ideal of the algebra A corresponds to a prime ideal of O, + # and since the algebra is an Artinian ring, all of its prime ideals + # are maximal [stacks 00JA]. Thus, we find all of our factors by + # iterating over the algebra's maximal ideals. + factors = [] + for q in A.maximal_ideals(): + if q == A.zero_ideal(): + # The zero ideal is the unique maximal ideal, which means that + # A is a field, and the ideal itself is a prime ideal. + P = self.ideal(p) + + P.is_prime.set_cache(True) + P._prime_below = ideal + P._relative_degree = n + P._ramification_index = 1 + P._beta = [1] + [0]*(n-1) + else: + Q = q.basis_matrix().apply_map(lambda e: e.lift()) + P = self.ideal(p, *Q*vector(self.basis())) + + # Now we compute an element beta in O but not in pO such that + # beta*P in pO. + + # Since beta is in k[x]-module O, we keep beta as a vector + # in k[x] with respect to the basis of O. As long as at least + # one element in this vector is not divisible by p, beta will + # not be in pO. To ensure that beta*P is in pO, multiplying + # beta by each of P's generators must produce a vector whose + # elements are multiples of p. We can ensure that all this + # occurs by constructing a matrix in k, and finding a non-zero + # vector in the kernel of the matrix. + + m = [] + for g in q.basis_matrix(): + m.extend(matrix([g * mr for mr in matrices_reduced]).columns()) + beta = [c.lift() for c in matrix(m).right_kernel().basis()[0]] + + r = q + index = 1 + while True: + rq = r*q + if rq == r: + break + r = rq + index = index + 1 + + P.is_prime.set_cache(True) + P._prime_below = ideal + P._relative_degree = n - q.basis_matrix().nrows() + P._ramification_index = index + P._beta = beta + + factors.append((P, P._relative_degree, P._ramification_index)) + + return factors + + +class FunctionFieldMaximalOrderInfinite_polymod(FunctionFieldMaximalOrderInfinite): + """ + Maximal infinite orders of function fields. + + INPUT: + + - ``field`` -- function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<t> = PolynomialRing(K) # needs sage.rings.finite_rings + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) # needs sage.rings.finite_rings + sage: F.maximal_order_infinite() # needs sage.rings.finite_rings + Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2 + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.finite_rings + sage: L.maximal_order_infinite() # needs sage.rings.finite_rings + Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x + """ + def __init__(self, field, category=None): + """ + Initialize. + + TESTS:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = PolynomialRing(K) + sage: F.<y> = K.extension(t^3 - x^2*(x^2+x+1)^2) + sage: O = F.maximal_order_infinite() + sage: TestSuite(O).run() + """ + FunctionFieldMaximalOrderInfinite.__init__(self, field, ideal_class=FunctionFieldIdealInfinite_polymod) + + M, from_M, to_M = field._inversion_isomorphism() + basis = [from_M(g) for g in M.maximal_order().basis()] + + V, from_V, to_V = field.vector_space() + R = field.base_field().maximal_order_infinite() + + self._basis = tuple(basis) + self._module = V.span_of_basis([to_V(v) for v in basis]) + self._module_base_ring = R + self._to_module = to_V + + def _element_constructor_(self, f): + """ + Make ``f`` an element of this order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: Oinf.basis() + (1, 1/x*y) + sage: 1 in Oinf + True + sage: 1/x*y in Oinf + True + sage: x*y in Oinf + False + sage: 1/x in Oinf + True + """ + F = self.function_field() + + try: + f = F(f) + except TypeError: + raise TypeError("unable to convert to an element of {}".format(F)) + + O = F.base_field().maximal_order_infinite() + coordinates = self.coordinate_vector(f) + if not all(c in O for c in coordinates): + raise TypeError("%r is not an element of %r" % (f,self)) + + return f + + def basis(self): + """ + Return a basis of this order as a module over the maximal order + of the base function field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: L.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: Oinf = L.maximal_order_infinite() + sage: Oinf.basis() + (1, 1/x^2*y, (1/(x^4 + x^3 + x^2))*y^2) + + :: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: Oinf.basis() + (1, 1/x*y) + """ + return self._basis + + def gen(self, n=0): + """ + Return the ``n``-th generator of the order. + + The basis elements of the order are generators. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: L.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: Oinf = L.maximal_order_infinite() + sage: Oinf.gen() + 1 + sage: Oinf.gen(1) + 1/x^2*y + sage: Oinf.gen(2) + (1/(x^4 + x^3 + x^2))*y^2 + sage: Oinf.gen(3) + Traceback (most recent call last): + ... + IndexError: there are only 3 generators + """ + if not ( n >= 0 and n < self.ngens() ): + raise IndexError("there are only {} generators".format(self.ngens())) + + return self._basis[n] + + def ngens(self): + """ + Return the number of generators of the order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: L.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: Oinf = L.maximal_order_infinite() + sage: Oinf.ngens() + 3 + """ + return len(self._basis) + + def ideal(self, *gens): + """ + Return the ideal generated by ``gens``. + + INPUT: + + - ``gens`` -- tuple of elements of the function field + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(x, y); I + Ideal (y) of Maximal infinite order of Function field + in y defined by y^3 + x^6 + x^4 + x^2 + + :: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(x, y); I + Ideal (x) of Maximal infinite order of Function field + in y defined by y^2 + y + (x^2 + 1)/x + """ + if len(gens) == 1: + gens = gens[0] + if not type(gens) in (list,tuple): + gens = (gens,) + mgens = [g * b for g in gens for b in self._basis] + return self.ideal_with_gens_over_base(mgens) + + def ideal_with_gens_over_base(self, gens): + """ + Return the ideal generated by ``gens`` as a module. + + INPUT: + + - ``gens`` -- tuple of elements of the function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); R.<t> = K[] + sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: Oinf = F.maximal_order_infinite() + sage: Oinf.ideal_with_gens_over_base((x^2, y, (1/(x^2 + x + 1))*y^2)) + Ideal (y) of Maximal infinite order of Function field in y + defined by y^3 + x^6 + x^4 + x^2 + """ + F = self.function_field() + iF, from_iF, to_iF = F._inversion_isomorphism() + iO = iF.maximal_order() + + ideal = iO.ideal_with_gens_over_base([to_iF(g) for g in gens]) + + if not ideal.is_zero(): + # Now the ideal does not correspond exactly to the ideal in the + # maximal infinite order through the inversion isomorphism. The + # reason is that the ideal also has factors not lying over x. + # The following procedure removes the spurious factors. The idea + # is that for an integral ideal I, J_n = I + (xO)^n stabilizes + # if n is large enough, and then J_n is the I with the spurious + # factors removed. For a fractional ideal, we also need to find + # the largest factor x^m that divides the denominator. + from sage.matrix.special import block_matrix + from .hermite_form_polynomial import reversed_hermite_form + + d = ideal.denominator() + h = ideal.hnf() + x = d.parent().gen() + + # find the largest factor x^m that divides the denominator + i = 0 + while d[i].is_zero(): + i += 1 + d = x ** i + + # find the largest n such that I + (xO)^n stabilizes + h1 = h + MS = h1.matrix_space() + k = MS.identity_matrix() + while True: + k = x * k + + h2 = block_matrix([[h],[k]]) + reversed_hermite_form(h2) + i = 0 + while i < h2.nrows() and h2.row(i).is_zero(): + i += 1 + h2 = h2[i:] # remove zero rows + + if h2 == h1: + break + h1 = h2 + + # reconstruct ideal + ideal = iO._ideal_from_vectors_and_denominator(list(h1), d) + + return self.ideal_monoid().element_class(self, ideal) + + def _to_iF(self, I): + """ + Return the ideal in the inverted function field from ``I``. + + INPUT: + + - ``I`` -- ideal of the function field + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(y) + sage: Oinf._to_iF(I) + Ideal (1, 1/x*s) of Maximal order of Function field in s + defined by s^2 + x*s + x^3 + x + """ + F = self.function_field() + iF,from_iF,to_iF = F._inversion_isomorphism() + iO = iF.maximal_order() + iI = iO.ideal_with_gens_over_base([to_iF(b) for b in I.gens_over_base()]) + return iI + + def decomposition(self): + r""" + Return prime ideal decomposition of `pO_\infty` where `p` is the unique + prime ideal of the maximal infinite order of the rational function field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: Oinf = F.maximal_order_infinite() + sage: Oinf.decomposition() + [(Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1) of Maximal infinite order + of Function field in y defined by y^3 + x^6 + x^4 + x^2, 1, 1), + (Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1/x^2*y + 1) of Maximal infinite order + of Function field in y defined by y^3 + x^6 + x^4 + x^2, 2, 1)] + + :: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: Oinf.decomposition() + [(Ideal (1/x*y) of Maximal infinite order of Function field in y + defined by y^2 + y + (x^2 + 1)/x, 1, 2)] + + :: + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2) + sage: Oinf = F.maximal_order_infinite() + sage: Oinf.decomposition() + [(Ideal (1/x^2*y - 1) of Maximal infinite order + of Function field in y defined by y^3 - x^6 - 2*x^5 - 3*x^4 - 2*x^3 - x^2, 1, 1), + (Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1/x^2*y + 1) of Maximal infinite order + of Function field in y defined by y^3 - x^6 - 2*x^5 - 3*x^4 - 2*x^3 - x^2, 2, 1)] + + :: + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: Oinf.decomposition() + [(Ideal (1/x*y) of Maximal infinite order of Function field in y + defined by y^2 + y + (x^2 + 1)/x, 1, 2)] + """ + F = self.function_field() + iF,from_iF,to_iF = F._inversion_isomorphism() + + x = iF.base_field().gen() + iO = iF.maximal_order() + io = iF.base_field().maximal_order() + ip = io.ideal(x) + + dec = [] + for iprime, deg, exp in iO.decomposition(ip): + prime = self.ideal_monoid().element_class(self, iprime) + dec.append((prime, deg, exp)) + return dec + + def different(self): + """ + Return the different ideal of the maximal infinite order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: Oinf.different() + Ideal (1/x) of Maximal infinite order of Function field in y + defined by y^2 + y + (x^2 + 1)/x + """ + T = self._codifferent_matrix() + codiff_gens = [] + for c in T.inverse().columns(): + codiff_gens.append(sum([ci*bi for ci,bi in zip(c,self.basis())])) + codiff = self.ideal_with_gens_over_base(codiff_gens) + return ~codiff + + @cached_method + def _codifferent_matrix(self): + """ + Return the codifferent matrix of the maximal infinite order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: Oinf._codifferent_matrix() + [ 0 1/x] + [ 1/x 1/x^2] + """ + from sage.matrix.constructor import matrix + + rows = [] + for u in self.basis(): + row = [] + for v in self.basis(): + row.append((u*v).trace()) + rows.append(row) + T = matrix(rows) + return T + + def coordinate_vector(self, e): + """ + Return the coordinates of ``e`` with respect to the basis of the order. + + INPUT: + + - ``e`` -- element of the function field + + The returned coordinates are in the base maximal infinite order if and only + if the element is in the order. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: f = 1/y^2 + sage: f in Oinf + True + sage: Oinf.coordinate_vector(f) + ((x^3 + x^2 + x)/(x^4 + 1), x^3/(x^4 + 1)) + """ + return self._module.coordinate_vector(self._to_module(e)) + + +class FunctionFieldMaximalOrder_global(FunctionFieldMaximalOrder_polymod): + """ + Maximal orders of global function fields. + + INPUT: + + - ``field`` -- function field to which this maximal order belongs + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) # needs sage.rings.finite_rings + sage: L.maximal_order() # needs sage.rings.finite_rings + Maximal order of Function field in y defined by y^4 + x*y + 4*x + 1 + """ + + def __init__(self, field): + """ + Initialize. + + TESTS:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(7)); R.<y> = K[] + sage: L.<y> = K.extension(y^4 + x*y + 4*x + 1) + sage: O = L.maximal_order() + sage: TestSuite(O).run() + """ + FunctionFieldMaximalOrder_polymod.__init__(self, field, ideal_class=FunctionFieldIdeal_global) + + @cached_method + def p_radical(self, prime): + """ + Return the ``prime``-radical of the maximal order. + + INPUT: + + - ``prime`` -- prime ideal of the maximal order of the base + rational function field + + The algorithm is outlined in Section 6.1.3 of [Coh1993]_. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<t> = K[] + sage: F.<y> = K.extension(t^3 - x^2 * (x^2 + x + 1)^2) + sage: o = K.maximal_order() + sage: O = F.maximal_order() + sage: p = o.ideal(x + 1) + sage: O.p_radical(p) + Ideal (x + 1) of Maximal order of Function field in y + defined by y^3 + x^6 + x^4 + x^2 + """ + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + + g = prime.gens()[0] + + if not (g.denominator() == 1 and g.numerator().is_irreducible()): + raise ValueError('not a prime ideal') + + F = self.function_field() + n = F.degree() + o = prime.ring() + p = g.numerator() + + # Fp is isomorphic to the residue field o/p + Fp, fr_Fp, to_Fp = o._residue_field_global(p) + + # exp = q^j should be at least extension degree where q is + # the order of the residue field o/p + q = F.constant_base_field().order()**p.degree() + exp = q + while exp <= F.degree(): + exp = exp**q + + # radical equals to the kernel of the map x |-> x^exp + mat = [] + for g in self.basis(): + v = [to_Fp(c) for c in self._coordinate_vector(g**exp)] + mat.append(v) + mat = matrix(Fp, mat) + ker = mat.kernel() + + # construct module generators of the p-radical + vecs = [] + for i in range(n): + v = vector([p if j == i else 0 for j in range(n)]) + vecs.append(v) + for b in ker.basis(): + v = vector([fr_Fp(c) for c in b]) + vecs.append(v) + + return self._ideal_from_vectors(vecs) + + @cached_method + def decomposition(self, ideal): + """ + Return the decomposition of the prime ideal. + + INPUT: + + - ``ideal`` -- prime ideal of the base maximal order + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); R.<t> = K[] + sage: F.<y> = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: o = K.maximal_order() + sage: O = F.maximal_order() + sage: p = o.ideal(x + 1) + sage: O.decomposition(p) + [(Ideal (x + 1, y + 1) of Maximal order + of Function field in y defined by y^3 + x^6 + x^4 + x^2, 1, 1), + (Ideal (x + 1, (1/(x^3 + x^2 + x))*y^2 + y + 1) of Maximal order + of Function field in y defined by y^3 + x^6 + x^4 + x^2, 2, 1)] + """ + from sage.matrix.constructor import matrix + + F = self.function_field() + n = F.degree() + + p = ideal.gen().numerator() + o = ideal.ring() + + # Fp is isomorphic to the residue field o/p + Fp, fr, to = o._residue_field_global(p) + P,X = Fp['X'].objgen() + + V = Fp**n # Ob = O/pO + + mtable = [] + for i in range(n): + row = [] + for j in range(n): + row.append( V([to(e) for e in self._mtable[i][j]]) ) + mtable.append(row) + + if p not in self._kummer_places: + ##################################### + # Decomposition by Kummer's theorem # + ##################################### + # gen is self._kummer_gen + gen_vec_pow = self._kummer_gen_vec_pow + mul_vecs = self._mul_vecs + + f = self._kummer_polynomial + fp = P([to(c.numerator()) for c in f.list()]) + decomposition = [] + for q, exp in fp.factor(): + # construct O.ideal([p,q(gen)]) + gen_vecs = list(matrix.diagonal(n * [p])) + c = q.list() + + # q(gen) in vector form + qgen = sum(fr(c[i]) * gen_vec_pow[i] for i in range(len(c))) + + I = matrix.identity(o._ring, n) + for i in range(n): + gen_vecs.append(mul_vecs(qgen,I[i])) + prime = self._ideal_from_vectors_and_denominator(gen_vecs) + + # Compute an element beta in O but not in pO. How to find beta + # is explained in Section 4.8.3 of [Coh1993]. We keep beta + # as a vector over k[x] with respect to the basis of O. + + # p and qgen generates the prime; modulo pO, qgenb generates the prime + qgenb = [to(qgen[i]) for i in range(n)] + m = [] + for i in range(n): + m.append(sum(qgenb[j] * mtable[i][j] for j in range(n))) + beta = [fr(coeff) for coeff in matrix(m).left_kernel().basis()[0]] + + prime.is_prime.set_cache(True) + prime._prime_below = ideal + prime._relative_degree = q.degree() + prime._ramification_index = exp + prime._beta = beta + + prime._kummer_form = (p, qgen) + + decomposition.append((prime, q.degree(), exp)) + else: + ############################# + # Buchman-Lenstra algorithm # + ############################# + from sage.matrix.special import block_matrix + from sage.modules.free_module_element import vector + + pO = self.ideal(p) + Ip = self.p_radical(ideal) + Ob = matrix.identity(Fp, n) + + def bar(I): # transfer to O/pO + m = [] + for v in I._hnf: + m.append([to(e) for e in v]) + h = matrix(m).echelon_form() + return cut_last_zero_rows(h) + + def liftb(Ib): + m = [vector([fr(e) for e in v]) for v in Ib] + m += [v for v in pO._hnf] + return self._ideal_from_vectors_and_denominator(m,1) + + def cut_last_zero_rows(h): + i = h.nrows() + while i > 0 and h.row(i-1).is_zero(): + i -= 1 + return h[:i] + + def mul_vec(v1,v2): + s = 0 + for i in range(n): + for j in range(n): + s += v1[i] * v2[j] * mtable[i][j] + return s + + def pow(v, r): # r > 0 + m = v + while r > 1: + m = mul_vec(m,v) + r -= 1 + return m + + # Algorithm 6.2.7 of [Coh1993] + def div(Ib, Jb): + # compute a basis of Jb/Ib + sJb = Jb.row_space() + sIb = Ib.row_space() + sJbsIb,proj_sJbsIb,lift_sJbsIb = sJb.quotient_abstract(sIb) + supplement_basis = [lift_sJbsIb(v) for v in sJbsIb.basis()] + + m = [] + for b in V.gens(): # basis of Ob = O/pO + b_row = [] # row vector representation of the map a -> a*b + for a in supplement_basis: + b_row += lift_sJbsIb(proj_sJbsIb( mul_vec(a,b) )) + m.append(b_row) + return matrix(Fp,n,m).left_kernel().basis_matrix() + + # Algorithm 6.2.5 of [Coh1993] + def mul(Ib, Jb): + m = [] + for v1 in Ib: + for v2 in Jb: + m.append(mul_vec(v1,v2)) + h = matrix(m).echelon_form() + return cut_last_zero_rows(h) + + def add(Ib,Jb): + m = block_matrix([[Ib], [Jb]]) + h = m.echelon_form() + return cut_last_zero_rows(h) + + # K_1, K_2, ... + Lb = IpOb = bar(Ip+pO) + Kb = [Lb] + while not Lb.is_zero(): + Lb = mul(Lb,IpOb) + Kb.append(Lb) + + # J_1, J_2, ... + Jb = [Kb[0]] + [div(Kb[j],Kb[j-1]) for j in range(1,len(Kb))] + + # H_1, H_2, ... + Hb = [div(Jb[j],Jb[j+1]) for j in range(len(Jb)-1)] + [Jb[-1]] + + q = Fp.order() + + def split(h): + # VsW represents O/H as a vector space + W = h.row_space() # H/pO + VsW,to_VsW,lift_to_V = V.quotient_abstract(W) + + # compute the space K of elements in O/H that satisfy a^q-a=0 + l = [lift_to_V(b) for b in VsW.basis()] + + images = [to_VsW(pow(x, q) - x) for x in l] + K = VsW.hom(images, VsW).kernel() + + if K.dimension() == 0: + return [] + if K.dimension() == 1: # h is prime + return [(liftb(h),VsW.dimension())] # relative degree + + # choose a such that a^q - a is 0 but a is not in Fp + for a in K.basis(): + # IMPORTANT: This criterion is based on the assumption + # that O.basis() starts with 1. + if a.support() != [0]: + break + else: + raise AssertionError("no appropriate value found") + + a = lift_to_V(a) + # compute the minimal polynomial of a + m = [to_VsW(Ob[0])] # 1 in VsW + apow = a + while True: + v = to_VsW(apow) + try: + sol = matrix(m).solve_left(v) + except ValueError: + m.append(v) + apow = mul_vec(apow, a) + continue + break + + minpol = X**len(sol) - P(list(sol)) + + # The minimal polynomial of a has only linear factors and at least two + # of them. We set f to the first factor and g to the product of the rest. + fac = minpol.factor() + f = fac[0][0] + g = (fac/f).expand() + d,u,v = f.xgcd(g) + + assert d == 1, "Not relatively prime {} and {}".format(f,g) + + # finally, idempotent! + e = lift_to_V(sum([c1*c2 for c1,c2 in zip(u*f,m)])) + + h1 = add(h, matrix([mul_vec(e,Ob[i]) for i in range(n)])) + h2 = add(h, matrix([mul_vec(Ob[0]-e,Ob[i]) for i in range(n)])) + + return split(h1) + split(h2) + + decomposition = [] + for i in range(len(Hb)): + index = i + 1 # Hb starts with H_1 + for prime, degree in split(Hb[i]): + # Compute an element beta in O but not in pO. How to find beta + # is explained in Section 4.8.3 of [Coh1993]. We keep beta + # as a vector over k[x] with respect to the basis of O. + m = [] + for i in range(n): + r = [] + for g in prime._hnf: + r += sum(to(g[j]) * mtable[i][j] for j in range(n)) + m.append(r) + beta = [fr(e) for e in matrix(m).left_kernel().basis()[0]] + + prime.is_prime.set_cache(True) + prime._prime_below = ideal + prime._relative_degree = degree + prime._ramification_index = index + prime._beta = beta + + decomposition.append((prime, degree, index)) + + return decomposition diff --git a/src/sage/rings/function_field/order_rational.py b/src/sage/rings/function_field/order_rational.py new file mode 100644 index 00000000000..99da2af1ebd --- /dev/null +++ b/src/sage/rings/function_field/order_rational.py @@ -0,0 +1,575 @@ +r""" +Orders of function fields: rational +""" + +# **************************************************************************** +# Copyright (C) 2010 William Stein <wstein@gmail.com> +# 2011 Maarten Derickx <m.derickx.student@gmail.com> +# 2011 Julian Rueth <julian.rueth@gmail.com> +# 2017-2020 Kwankyu Lee +# 2019 Brent Baccala +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# **************************************************************************** + +import sage.rings.abc + +from sage.arith.functions import lcm +from sage.arith.misc import GCD as gcd +from sage.categories.euclidean_domains import EuclideanDomains +from sage.categories.principal_ideal_domains import PrincipalIdealDomains +from sage.rings.number_field.number_field_base import NumberField + +from .ideal import FunctionFieldIdeal +from .ideal_rational import FunctionFieldIdeal_rational, FunctionFieldIdealInfinite_rational +from .order import FunctionFieldMaximalOrder, FunctionFieldMaximalOrderInfinite + + +class FunctionFieldMaximalOrder_rational(FunctionFieldMaximalOrder): + """ + Maximal orders of rational function fields. + + INPUT: + + - ``field`` -- a function field + + EXAMPLES:: + + sage: K.<t> = FunctionField(GF(19)); K + Rational function field in t over Finite Field of size 19 + sage: R = K.maximal_order(); R + Maximal order of Rational function field in t over Finite Field of size 19 + """ + def __init__(self, field): + """ + Initialize. + + TESTS:: + + sage: K.<t> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: TestSuite(O).run(skip='_test_gcd_vs_xgcd') + """ + FunctionFieldMaximalOrder.__init__(self, field, ideal_class=FunctionFieldIdeal_rational, + category=EuclideanDomains()) + + self._populate_coercion_lists_(coerce_list=[field._ring]) + + self._ring = field._ring + self._gen = self(self._ring.gen()) + self._basis = (self.one(),) + + def _element_constructor_(self, f): + """ + Make ``f`` a function field element of this order. + + EXAMPLES:: + + sage: K.<y> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: O._element_constructor_(y) + y + sage: O._element_constructor_(1/y) + Traceback (most recent call last): + ... + TypeError: 1/y is not an element of Maximal order of Rational function field in y over Rational Field + """ + F = self.function_field() + try: + f = F(f) + except TypeError: + raise TypeError("unable to convert to an element of {}".format(F)) + + if not f.denominator() in self.function_field().constant_base_field(): + raise TypeError("%r is not an element of %r" % (f,self)) + + return f + + def ideal_with_gens_over_base(self, gens): + """ + Return the fractional ideal with generators ``gens``. + + INPUT: + + - ``gens`` -- elements of the function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ); R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^3 - 1) # needs sage.rings.function_field + sage: O = L.equation_order() # needs sage.rings.function_field + sage: O.ideal_with_gens_over_base([x^3 + 1, -y]) # needs sage.rings.function_field + Ideal (x^3 + 1, -y) of Order in Function field in y defined by y^2 - x^3 - 1 + """ + return self.ideal(gens) + + def _residue_field(self, ideal, name=None): + """ + Return a field isomorphic to the residue field at the prime ideal. + + The residue field is by definition `k[x]/q` where `q` is the irreducible + polynomial generating the prime ideal and `k` is the constant base field. + + INPUT: + + - ``ideal`` -- prime ideal of the order + + - ``name`` -- string; name of the generator of the residue field + + OUTPUT: + + - a field isomorphic to the residue field + + - a morphism from the field to `k[x]` via the residue field + + - a morphism from `k[x]` to the field via the residue field + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: F.<x> = FunctionField(GF(2)) + sage: O = F.maximal_order() + sage: I = O.ideal(x^2 + x + 1) + sage: R, fr_R, to_R = O._residue_field(I) + sage: R + Finite Field in z2 of size 2^2 + sage: [to_R(fr_R(e)) == e for e in R] + [True, True, True, True] + sage: [to_R(fr_R(e)).parent() is R for e in R] + [True, True, True, True] + sage: e1, e2 = fr_R(R.random_element()), fr_R(R.random_element()) + sage: to_R(e1 * e2) == to_R(e1) * to_R(e2) + True + sage: to_R(e1 + e2) == to_R(e1) + to_R(e2) + True + sage: to_R(e1).parent() is R + True + sage: to_R(e2).parent() is R + True + + sage: # needs sage.rings.finite_rings + sage: F.<x> = FunctionField(GF(2)) + sage: O = F.maximal_order() + sage: I = O.ideal(x + 1) + sage: R, fr_R, to_R = O._residue_field(I) + sage: R + Finite Field of size 2 + sage: [to_R(fr_R(e)) == e for e in R] + [True, True] + sage: [to_R(fr_R(e)).parent() is R for e in R] + [True, True] + sage: e1, e2 = fr_R(R.random_element()), fr_R(R.random_element()) + sage: to_R(e1 * e2) == to_R(e1) * to_R(e2) + True + sage: to_R(e1 + e2) == to_R(e1) + to_R(e2) + True + sage: to_R(e1).parent() is R + True + sage: to_R(e2).parent() is R + True + + sage: F.<x> = FunctionField(QQ) + sage: O = F.maximal_order() + sage: I = O.ideal(x^2 + x + 1) + sage: R, fr_R, to_R = O._residue_field(I) # needs sage.rings.number_field + sage: R # needs sage.rings.number_field + Number Field in a with defining polynomial x^2 + x + 1 + sage: e1, e2 = fr_R(R.random_element()), fr_R(R.random_element()) # needs sage.rings.number_field + sage: to_R(e1 * e2) == to_R(e1) * to_R(e2) # needs sage.rings.number_field + True + sage: to_R(e1 + e2) == to_R(e1) + to_R(e2) # needs sage.rings.number_field + True + sage: to_R(e1).parent() is R # needs sage.rings.number_field + True + sage: to_R(e2).parent() is R # needs sage.rings.number_field + True + + sage: F.<x> = FunctionField(QQ) + sage: O = F.maximal_order() + sage: I = O.ideal(x + 1) + sage: R, fr_R, to_R = O._residue_field(I) + sage: R + Rational Field + sage: e1, e2 = fr_R(R.random_element()), fr_R(R.random_element()) + sage: to_R(e1 * e2) == to_R(e1) * to_R(e2) + True + sage: to_R(e1 + e2) == to_R(e1) + to_R(e2) + True + sage: to_R(e1).parent() is R + True + sage: to_R(e2).parent() is R + True + """ + F = self.function_field() + K = F.constant_base_field() + + q = ideal.gen().element().numerator() + + if F.is_global(): + R, _from_R, _to_R = self._residue_field_global(q, name=name) + elif isinstance(K, (NumberField, sage.rings.abc.AlgebraicField)): + if name is None: + name = 'a' + if q.degree() == 1: + R = K + _from_R = lambda e: e + _to_R = lambda e: R(e % q) + else: + R = K.extension(q, names=name) + _from_R = lambda e: self._ring(list(R(e))) + _to_R = lambda e: (e % q)(R.gen(0)) + else: + raise NotImplementedError + + def from_R(e): + return F(_from_R(e)) + + def to_R(f): + return _to_R(f.numerator()) + + return R, from_R, to_R + + def _residue_field_global(self, q, name=None): + """ + Return a finite field isomorphic to the residue field at q. + + This method assumes a global rational function field, that is, + the constant base field is a finite field. + + INPUT: + + - ``q`` -- irreducible polynomial + + - ``name`` -- string; name of the generator of the extension field + + OUTPUT: + + - a finite field + + - a function that outputs a polynomial lifting a finite field element + + - a function that outputs a finite field element for a polynomial + + The residue field is by definition `k[x]/q` where `k` is the base field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: k.<a> = GF(4) + sage: F.<x> = FunctionField(k) + sage: O = F.maximal_order() + sage: O._ring + Univariate Polynomial Ring in x over Finite Field in a of size 2^2 + sage: f = x^3 + x + 1 + sage: _f = f.numerator() + sage: _f.is_irreducible() + True + sage: K, fr_K, to_K = O._residue_field_global(_f) # needs sage.modules + sage: K # needs sage.modules + Finite Field in z6 of size 2^6 + sage: all(to_K(fr_K(e)) == e for e in K) # needs sage.modules + True + + sage: # needs sage.rings.finite_rings + sage: k.<a> = GF(2) + sage: F.<x> = FunctionField(k) + sage: O = F.maximal_order() + sage: O._ring # needs sage.libs.ntl + Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) + sage: f = x^3 + x + 1 + sage: _f = f.numerator() + sage: _f.is_irreducible() + True + sage: K, fr_K, to_K = O._residue_field_global(_f) # needs sage.modules + sage: all(to_K(fr_K(e)) == e for e in K) # needs sage.modules + True + + """ + # polynomial ring over the base field + R = self._ring + + # base field of extension degree r over the prime field + k = R.base_ring() + a = k.gen() + r = k.degree() + + # extend the base field to a field of degree r*s over the + # prime field + s = q.degree() + K,sigma = k.extension(s, map=True, name=name) + + # find a root beta in K satisfying the irreducible q + S = K['X'] + beta = S([sigma(c) for c in q.list()]).roots()[0][0] + + # V is a vector space over the prime subfield of k of degree r*s + V = K.vector_space(map=False) + + w = K.one() + beta_pow = [] + for i in range(s): + beta_pow.append(w) + w *= beta + + w = K.one() + sigma_a = sigma(a) + sigma_a_pow = [] + for i in range(r): + sigma_a_pow.append(w) + w *= sigma_a + + basis = [V(sap * bp) for bp in beta_pow for sap in sigma_a_pow] + W = V.span_of_basis(basis) + + def to_K(f): + coeffs = (f % q).list() + return sum((sigma(c) * beta_pow[i] for i, c in enumerate(coeffs)), K.zero()) + + if r == 1: # take care of the prime field case + def fr_K(g): + co = W.coordinates(V(g), check=False) + return R([k(co[j]) for j in range(s)]) + else: + def fr_K(g): + co = W.coordinates(V(g), check=False) + return R([k(co[i:i+r]) for i in range(0, r*s, r)]) + + return K, fr_K, to_K + + def basis(self): + """ + Return the basis (=1) of the order as a module over the polynomial ring. + + EXAMPLES:: + + sage: K.<t> = FunctionField(GF(19)) + sage: O = K.maximal_order() + sage: O.basis() + (1,) + """ + return self._basis + + def gen(self, n=0): + """ + Return the ``n``-th generator of the order. Since there is only one generator ``n`` must be 0. + + EXAMPLES:: + + sage: O = FunctionField(QQ,'y').maximal_order() + sage: O.gen() + y + sage: O.gen(1) + Traceback (most recent call last): + ... + IndexError: there is only one generator + """ + if n != 0: + raise IndexError("there is only one generator") + return self._gen + + def ngens(self): + """ + Return 1 the number of generators of the order. + + EXAMPLES:: + + sage: FunctionField(QQ,'y').maximal_order().ngens() + 1 + """ + return 1 + + def ideal(self, *gens): + """ + Return the fractional ideal generated by ``gens``. + + INPUT: + + - ``gens`` -- elements of the function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: O.ideal(x) + Ideal (x) of Maximal order of Rational function field in x over Rational Field + sage: O.ideal([x, 1/x]) == O.ideal(x, 1/x) # multiple generators may be given as a list + True + sage: O.ideal(x^3 + 1, x^3 + 6) + Ideal (1) of Maximal order of Rational function field in x over Rational Field + sage: I = O.ideal((x^2+1)*(x^3+1), (x^3+6)*(x^2+1)); I + Ideal (x^2 + 1) of Maximal order of Rational function field in x over Rational Field + sage: O.ideal(I) + Ideal (x^2 + 1) of Maximal order of Rational function field in x over Rational Field + """ + if len(gens) == 1: + gens = gens[0] + if not isinstance(gens, (list, tuple)): + if isinstance(gens, FunctionFieldIdeal): + gens = gens.gens() + else: + gens = (gens,) + K = self.function_field() + gens = [K(e) for e in gens if e != 0] + if len(gens) == 0: + gen = K(0) + else: + d = lcm([c.denominator() for c in gens]).monic() + g = gcd([(d*c).numerator() for c in gens]).monic() + gen = K(g/d) + + return self.ideal_monoid().element_class(self, gen) + + +class FunctionFieldMaximalOrderInfinite_rational(FunctionFieldMaximalOrderInfinite): + """ + Maximal infinite orders of rational function fields. + + INPUT: + + - ``field`` -- a rational function field + + EXAMPLES:: + + sage: K.<t> = FunctionField(GF(19)); K + Rational function field in t over Finite Field of size 19 + sage: R = K.maximal_order_infinite(); R + Maximal infinite order of Rational function field in t over Finite Field of size 19 + """ + def __init__(self, field, category=None): + """ + Initialize. + + TESTS:: + + sage: K.<t> = FunctionField(GF(19)) + sage: O = K.maximal_order_infinite() + sage: TestSuite(O).run(skip='_test_gcd_vs_xgcd') + """ + FunctionFieldMaximalOrderInfinite.__init__(self, field, ideal_class=FunctionFieldIdealInfinite_rational, + category=PrincipalIdealDomains().or_subcategory(category)) + self._populate_coercion_lists_(coerce_list=[field.constant_base_field()]) + + def _element_constructor_(self, f): + """ + Make ``f`` an element of this order. + + EXAMPLES:: + + sage: K.<y> = FunctionField(QQ) + sage: O = K.maximal_order() + sage: O._element_constructor_(y) + y + sage: O._element_constructor_(1/y) + Traceback (most recent call last): + ... + TypeError: 1/y is not an element of Maximal order of Rational function field in y over Rational Field + """ + F = self.function_field() + try: + f = F(f) + except TypeError: + raise TypeError("unable to convert to an element of {}".format(F)) + + if f.denominator().degree() < f.numerator().degree(): + raise TypeError("{} is not an element of {}".format(f, self)) + + return f + + def basis(self): + """ + Return the basis (=1) of the order as a module over the polynomial ring. + + EXAMPLES:: + + sage: K.<t> = FunctionField(GF(19)) + sage: O = K.maximal_order() + sage: O.basis() + (1,) + """ + return 1/self.function_field().gen() + + def gen(self, n=0): + """ + Return the ``n``-th generator of self. Since there is only one generator ``n`` must be 0. + + EXAMPLES:: + + sage: O = FunctionField(QQ,'y').maximal_order() + sage: O.gen() + y + sage: O.gen(1) + Traceback (most recent call last): + ... + IndexError: there is only one generator + """ + if n != 0: + raise IndexError("there is only one generator") + return self._gen + + def ngens(self): + """ + Return 1 the number of generators of the order. + + EXAMPLES:: + + sage: FunctionField(QQ,'y').maximal_order().ngens() + 1 + """ + return 1 + + def prime_ideal(self): + """ + Return the unique prime ideal of the order. + + EXAMPLES:: + + sage: K.<t> = FunctionField(GF(19)) + sage: O = K.maximal_order_infinite() + sage: O.prime_ideal() + Ideal (1/t) of Maximal infinite order of Rational function field in t + over Finite Field of size 19 + """ + return self.ideal( 1/self.function_field().gen() ) + + def ideal(self, *gens): + """ + Return the fractional ideal generated by ``gens``. + + INPUT: + + - ``gens`` -- elements of the function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: O = K.maximal_order_infinite() + sage: O.ideal(x) + Ideal (x) of Maximal infinite order of Rational function field in x over Rational Field + sage: O.ideal([x, 1/x]) == O.ideal(x ,1/x) # multiple generators may be given as a list + True + sage: O.ideal(x^3 + 1, x^3 + 6) + Ideal (x^3) of Maximal infinite order of Rational function field in x over Rational Field + sage: I = O.ideal((x^2+1)*(x^3+1), (x^3+6)*(x^2+1)); I + Ideal (x^5) of Maximal infinite order of Rational function field in x over Rational Field + sage: O.ideal(I) + Ideal (x^5) of Maximal infinite order of Rational function field in x over Rational Field + """ + if len(gens) == 1: + gens = gens[0] + if not isinstance(gens, (list, tuple)): + if isinstance(gens, FunctionFieldIdeal): + gens = gens.gens() + else: + gens = (gens,) + K = self.function_field() + gens = [K(g) for g in gens] + try: + d = max(g.numerator().degree() - g.denominator().degree() for g in gens if g != 0) + gen = K.gen() ** d + except ValueError: # all gens are zero + gen = K(0) + + return self.ideal_monoid().element_class(self, gen) diff --git a/src/sage/rings/function_field/place.py b/src/sage/rings/function_field/place.py index 69993a4b744..dbc3ab0e767 100644 --- a/src/sage/rings/function_field/place.py +++ b/src/sage/rings/function_field/place.py @@ -12,8 +12,8 @@ All rational places of a function field can be computed:: sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x + x^3*Y) - sage: L.places() + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field + sage: L.places() # needs sage.rings.function_field [Place (1/x, 1/x^3*y^2 + 1/x), Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1), Place (x, y)] @@ -23,18 +23,18 @@ sage: F.<x> = FunctionField(GF(2)) sage: O = F.maximal_order() - sage: p = O.ideal(x^2 + x + 1).place() - sage: k, fr_k, to_k = p.residue_field() - sage: k + sage: p = O.ideal(x^2 + x + 1).place() # needs sage.libs.pari + sage: k, fr_k, to_k = p.residue_field() # needs sage.libs.pari sage.rings.function_field + sage: k # needs sage.libs.pari sage.rings.function_field Finite Field in z2 of size 2^2 The homomorphisms are between the valuation ring and the residue field:: - sage: fr_k + sage: fr_k # needs sage.libs.pari sage.rings.function_field Ring morphism: From: Finite Field in z2 of size 2^2 To: Valuation ring at Place (x^2 + x + 1) - sage: to_k + sage: to_k # needs sage.libs.pari sage.rings.function_field Ring morphism: From: Valuation ring at Place (x^2 + x + 1) To: Finite Field in z2 of size 2^2 @@ -46,34 +46,24 @@ - Brent Baccala (2019-12-20): function fields of characteristic zero """ -#***************************************************************************** -# Copyright (C) 2016 Kwankyu Lee <ekwankyu@gmail.com> + +# **************************************************************************** +# Copyright (C) 2016-2022 Kwankyu Lee <ekwankyu@gmail.com> +# 2019 Brent Baccala +# 2021 Jonathan Kliem # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** - -from sage.misc.cachefunc import cached_method - -from sage.arith.functions import lcm - -from sage.rings.integer_ring import ZZ -from sage.rings.qqbar import QQbar -from sage.rings.number_field.number_field_base import NumberField +# **************************************************************************** from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.structure.element import Element from sage.structure.richcmp import richcmp - from sage.categories.sets_cat import Sets -from sage.modules.free_module_element import vector - -from sage.matrix.constructor import matrix - class FunctionFieldPlace(Element): """ @@ -87,9 +77,9 @@ class FunctionFieldPlace(Element): EXAMPLES:: - sage: K.<x>=FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y>=K.extension(Y^3 + x + x^3*Y) - sage: L.places_finite()[0] + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field + sage: L.places_finite()[0] # needs sage.rings.function_field Place (x, y) """ def __init__(self, parent, prime): @@ -98,10 +88,10 @@ def __init__(self, parent, prime): TESTS:: - sage: K.<x>=FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y>=K.extension(Y^3 + x + x^3*Y) - sage: p = L.places_finite()[0] - sage: TestSuite(p).run() + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field + sage: p = L.places_finite()[0] # needs sage.rings.function_field + sage: TestSuite(p).run() # needs sage.rings.function_field """ Element.__init__(self, parent) @@ -113,10 +103,10 @@ def __hash__(self): EXAMPLES:: - sage: K.<x>=FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y>=K.extension(Y^3 + x + x^3*Y) - sage: p = L.places_finite()[0] - sage: {p: 1} + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field + sage: p = L.places_finite()[0] # needs sage.rings.function_field + sage: {p: 1} # needs sage.rings.function_field {Place (x, y): 1} """ return hash((self.function_field(), self._prime)) @@ -128,9 +118,9 @@ def _repr_(self): EXAMPLES:: sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: p = L.places_finite()[0] - sage: p + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) # needs sage.rings.function_field + sage: p = L.places_finite()[0] # needs sage.rings.function_field + sage: p # needs sage.rings.function_field Place (x, y) """ try: @@ -147,9 +137,9 @@ def _latex_(self): EXAMPLES:: sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3+x+x^3*Y) - sage: p = L.places_finite()[0] - sage: latex(p) + sage: L.<y> = K.extension(Y^3 + x + x^3*Y) # needs sage.rings.function_field + sage: p = L.places_finite()[0] # needs sage.rings.function_field + sage: latex(p) # needs sage.rings.function_field \left(y\right) """ return self._prime._latex_() @@ -160,6 +150,7 @@ def _richcmp_(self, other, op): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x + x^3*Y) sage: p1, p2, p3 = L.places()[:3] @@ -186,10 +177,11 @@ def _acted_upon_(self, other, self_on_left): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(5)); R.<Y> = PolynomialRing(K) sage: F.<y> = K.extension(Y^2 - x^3 - 1) sage: O = F.maximal_order() - sage: I = O.ideal(x + 1,y) + sage: I = O.ideal(x + 1, y) sage: P = I.place() sage: -3*P + 5*P 2*Place (x + 1, y) @@ -204,6 +196,7 @@ def _neg_(self): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x^3*Y + x) sage: p1, p2, p3 = L.places()[:3] @@ -220,6 +213,7 @@ def _add_(self, other): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x^3*Y + x) sage: p1, p2, p3 = L.places()[:3] @@ -237,6 +231,7 @@ def _sub_(self, other): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x^3*Y + x) sage: p1, p2 = L.places()[:2] @@ -258,7 +253,7 @@ def __radd__(self, other): sage: k.<a> = GF(2) sage: K.<x> = FunctionField(k) - sage: sum(K.places_finite()) + sage: sum(K.places_finite()) # needs sage.libs.pari Place (x) + Place (x + 1) Note that this does not work, as wanted:: @@ -283,9 +278,9 @@ def function_field(self): EXAMPLES:: sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: p = L.places()[0] - sage: p.function_field() == L + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) # needs sage.rings.function_field + sage: p = L.places()[0] # needs sage.rings.function_field + sage: p.function_field() == L # needs sage.rings.function_field True """ return self.parent()._field @@ -297,9 +292,9 @@ def prime_ideal(self): EXAMPLES:: sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: p = L.places()[0] - sage: p.prime_ideal() + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) # needs sage.rings.function_field + sage: p = L.places()[0] # needs sage.rings.function_field + sage: p.prime_ideal() # needs sage.rings.function_field Ideal (1/x^3*y^2 + 1/x) of Maximal infinite order of Function field in y defined by y^3 + x^3*y + x """ @@ -311,10 +306,11 @@ def divisor(self, multiplicity=1): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(5)); R.<Y> = PolynomialRing(K) sage: F.<y> = K.extension(Y^2 - x^3 - 1) sage: O = F.maximal_order() - sage: I = O.ideal(x + 1,y) + sage: I = O.ideal(x + 1, y) sage: P = I.place() sage: P.divisor() Place (x + 1, y) @@ -323,804 +319,6 @@ def divisor(self, multiplicity=1): return prime_divisor(self.function_field(), self, multiplicity) -class FunctionFieldPlace_rational(FunctionFieldPlace): - """ - Places of rational function fields. - """ - def degree(self): - """ - Return the degree of the place. - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: O = F.maximal_order() - sage: i = O.ideal(x^2 + x + 1) - sage: p = i.place() - sage: p.degree() - 2 - """ - if self.is_infinite_place(): - return 1 - else: - return self._prime.gen().numerator().degree() - - def is_infinite_place(self): - """ - Return ``True`` if the place is at infinite. - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: F.places() - [Place (1/x), Place (x), Place (x + 1)] - sage: [p.is_infinite_place() for p in F.places()] - [True, False, False] - """ - F = self.function_field() - return self.prime_ideal().ring() == F.maximal_order_infinite() - - def local_uniformizer(self): - """ - Return a local uniformizer of the place. - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: F.places() - [Place (1/x), Place (x), Place (x + 1)] - sage: [p.local_uniformizer() for p in F.places()] - [1/x, x, x + 1] - """ - return self.prime_ideal().gen() - - def residue_field(self, name=None): - """ - Return the residue field of the place. - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: O = F.maximal_order() - sage: p = O.ideal(x^2 + x + 1).place() - sage: k, fr_k, to_k = p.residue_field() - sage: k - Finite Field in z2 of size 2^2 - sage: fr_k - Ring morphism: - From: Finite Field in z2 of size 2^2 - To: Valuation ring at Place (x^2 + x + 1) - sage: to_k - Ring morphism: - From: Valuation ring at Place (x^2 + x + 1) - To: Finite Field in z2 of size 2^2 - """ - return self.valuation_ring().residue_field(name=name) - - def _residue_field(self, name=None): - """ - Return the residue field of the place along with the maps from - and to it. - - INPUT: - - - ``name`` -- string; name of the generator of the residue field - - EXAMPLES:: - - sage: F.<x> = FunctionField(GF(2)) - sage: O = F.maximal_order() - sage: i = O.ideal(x^2 + x + 1) - sage: p = i.place() - sage: R, fr, to = p._residue_field() - sage: R - Finite Field in z2 of size 2^2 - sage: [fr(e) for e in R.list()] - [0, x, x + 1, 1] - sage: to(x*(x+1)) == to(x) * to(x+1) - True - """ - F = self.function_field() - prime = self.prime_ideal() - - if self.is_infinite_place(): - K = F.constant_base_field() - - def from_K(e): - return F(e) - - def to_K(f): - n = f.numerator() - d = f.denominator() - - n_deg = n.degree() - d_deg =d.degree() - - if n_deg < d_deg: - return K(0) - elif n_deg == d_deg: - return n.lc() / d.lc() - else: - raise TypeError("not in the valuation ring") - else: - O = F.maximal_order() - K, from_K, _to_K = O._residue_field(prime, name=name) - - def to_K(f): - if f in O: # f.denominator() is 1 - return _to_K(f.numerator()) - else: - d = F(f.denominator()) - n = d * f - - nv = prime.valuation(O.ideal(n)) - dv = prime.valuation(O.ideal(d)) - - if nv > dv: - return K(0) - elif dv > nv: - raise TypeError("not in the valuation ring") - - s = ~prime.gen() - rd = d * s**dv # in O but not in prime - rn = n * s**nv # in O but not in prime - return to_K(rn) / to_K(rd) - - return K, from_K, to_K - - def valuation_ring(self): - """ - Return the valuation ring at the place. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: p = L.places_finite()[0] - sage: p.valuation_ring() - Valuation ring at Place (x, x*y) - """ - from .valuation_ring import FunctionFieldValuationRing - - return FunctionFieldValuationRing(self.function_field(), self) - - -class FunctionFieldPlace_polymod(FunctionFieldPlace): - """ - Places of extensions of function fields. - """ - def place_below(self): - """ - Return the place lying below the place. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: OK = K.maximal_order() - sage: OL = L.maximal_order() - sage: p = OK.ideal(x^2 + x + 1) - sage: dec = OL.decomposition(p) - sage: q = dec[0][0].place() - sage: q.place_below() - Place (x^2 + x + 1) - """ - return self.prime_ideal().prime_below().place() - - def relative_degree(self): - """ - Return the relative degree of the place. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: OK = K.maximal_order() - sage: OL = L.maximal_order() - sage: p = OK.ideal(x^2 + x + 1) - sage: dec = OL.decomposition(p) - sage: q = dec[0][0].place() - sage: q.relative_degree() - 1 - """ - return self._prime._relative_degree - - def degree(self): - """ - Return the degree of the place. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: OK = K.maximal_order() - sage: OL = L.maximal_order() - sage: p = OK.ideal(x^2 + x + 1) - sage: dec = OL.decomposition(p) - sage: q = dec[0][0].place() - sage: q.degree() - 2 - """ - return self.relative_degree() * self.place_below().degree() - - def is_infinite_place(self): - """ - Return ``True`` if the place is above the unique infinite place - of the underlying rational function field. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: pls = L.places() - sage: [p.is_infinite_place() for p in pls] - [True, True, False] - sage: [p.place_below() for p in pls] - [Place (1/x), Place (1/x), Place (x)] - """ - return self.place_below().is_infinite_place() - - def local_uniformizer(self): - """ - Return an element of the function field that has a simple zero - at the place. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: pls = L.places() - sage: [p.local_uniformizer().valuation(p) for p in pls] - [1, 1, 1, 1, 1] - """ - gens = self._prime.gens() - for g in gens: - if g.valuation(self) == 1: - return g - assert False, "Internal error" - - def gaps(self): - """ - Return the gap sequence for the place. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: O = L.maximal_order() - sage: p = O.ideal(x,y).place() - sage: p.gaps() # a Weierstrass place - [1, 2, 4] - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3 * Y + x) - sage: [p.gaps() for p in L.places()] - [[1, 2, 4], [1, 2, 4], [1, 2, 4]] - """ - if self.degree() == 1: - return self._gaps_rational() # faster for rational places - else: - return self._gaps_wronskian() - - def _gaps_rational(self): - """ - Return the gap sequence for the rational place. - - This method computes the gap numbers using the definition of gap - numbers. The dimension of the multiple of the prime divisor - supported at the place is computed by Hess' algorithm. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: O = L.maximal_order() - sage: p = O.ideal(x,y).place() - sage: p.gaps() # indirect doctest - [1, 2, 4] - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: [p.gaps() for p in L.places()] # indirect doctest - [[1, 2, 4], [1, 2, 4], [1, 2, 4]] - """ - F = self.function_field() - n = F.degree() - O = F.maximal_order() - Oinf = F.maximal_order_infinite() - - R = O._module_base_ring._ring - one = R.one() - - # Hess' Riemann-Roch basis algorithm stripped down for gaps computation - def dim_RR(M): - den = lcm([e.denominator() for e in M.list()]) - mat = matrix(R, M.nrows(), [(den*e).numerator() for e in M.list()]) - - # initialise pivot_row and conflicts list - pivot_row = [[] for i in range(n)] - conflicts = [] - for i in range(n): - bestp = -1 - best = -1 - for c in range(n): - d = mat[i,c].degree() - if d >= best: - bestp = c - best = d - - if best >= 0: - pivot_row[bestp].append((i,best)) - if len(pivot_row[bestp]) > 1: - conflicts.append(bestp) - - # while there is a conflict, do a simple transformation - while conflicts: - c = conflicts.pop() - row = pivot_row[c] - i,ideg = row.pop() - j,jdeg = row.pop() - - if jdeg > ideg: - i,j = j,i - ideg,jdeg = jdeg,ideg - - coeff = - mat[i,c].lc() / mat[j,c].lc() - s = coeff * one.shift(ideg - jdeg) - - mat.add_multiple_of_row(i, j, s) - - row.append((j,jdeg)) - - bestp = -1 - best = -1 - for c in range(n): - d = mat[i,c].degree() - if d >= best: - bestp = c - best = d - - if best >= 0: - pivot_row[bestp].append((i,best)) - if len(pivot_row[bestp]) > 1: - conflicts.append(bestp) - - dim = 0 - for j in range(n): - i,ideg = pivot_row[j][0] - k = den.degree() - ideg + 1 - if k > 0: - dim += k - return dim - - V,fr,to = F.vector_space() - - prime_inv = ~ self.prime_ideal() - I = O.ideal(1) - J = Oinf.ideal(1) - - B = matrix([to(b) for b in J.gens_over_base()]) - C = matrix([to(v) for v in I.gens_over_base()]) - - prev = dim_RR(C * B.inverse()) - gaps = [] - g = F.genus() - i = 1 - if self.is_infinite_place(): - while g: - J = J * prime_inv - B = matrix([to(b) for b in J.gens_over_base()]) - dim = dim_RR(C * B.inverse()) - if dim == prev: - gaps.append(i) - g -= 1 - else: - prev = dim - i += 1 - else: # self is a finite place - Binv = B.inverse() - while g: - I = I * prime_inv - C = matrix([to(v) for v in I.gens_over_base()]) - dim = dim_RR(C * Binv) - if dim == prev: - gaps.append(i) - g -= 1 - else: - prev = dim - i += 1 - - return gaps - - def _gaps_wronskian(self): - """ - Return the gap sequence for the place. - - This method implements the local version of Hess' Algorithm 30 of [Hes2002b]_ - based on the Wronskian determinant. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: O = L.maximal_order() - sage: p = O.ideal(x,y).place() - sage: p._gaps_wronskian() # a Weierstrass place - [1, 2, 4] - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3 * Y + x) - sage: [p._gaps_wronskian() for p in L.places()] - [[1, 2, 4], [1, 2, 4], [1, 2, 4]] - """ - F = self.function_field() - R,fr_R,to_R = self._residue_field() - der = F.higher_derivation() - - sep = self.local_uniformizer() - - # a differential divisor satisfying - # v_p(W) = 0 for the place p - W = sep.differential().divisor() - - # Step 3: - basis = W._basis() - d = len(basis) - M = matrix([to_R(b) for b in basis]) - if M.rank() == 0: - return [] - - # Steps 4, 5, 6, 7: - e = 1 - gaps = [1] - while M.nrows() < d: - row = vector([to_R(der._derive(basis[i], e, sep)) for i in range(d)]) - if row not in M.row_space(): - M = matrix(M.rows() + [row]) - M.echelonize() - gaps.append(e + 1) - e += 1 - - return gaps - - def residue_field(self, name=None): - """ - Return the residue field of the place. - - INPUT: - - - ``name`` -- string; name of the generator of the residue field - - OUTPUT: - - - a field isomorphic to the residue field - - - a ring homomorphism from the valuation ring to the field - - - a ring homomorphism from the field to the valuation ring - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: p = L.places_finite()[0] - sage: k, fr_k, to_k = p.residue_field() - sage: k - Finite Field of size 2 - sage: fr_k - Ring morphism: - From: Finite Field of size 2 - To: Valuation ring at Place (x, x*y) - sage: to_k - Ring morphism: - From: Valuation ring at Place (x, x*y) - To: Finite Field of size 2 - sage: to_k(y) - Traceback (most recent call last): - ... - TypeError: y fails to convert into the map's domain - Valuation ring at Place (x, x*y)... - sage: to_k(1/y) - 0 - sage: to_k(y/(1+y)) - 1 - """ - return self.valuation_ring().residue_field(name=name) - - @cached_method - def _residue_field(self, name=None): - """ - Return the residue field of the place along with the functions - mapping from and to it. - - INPUT: - - - ``name`` -- string (default: `None`); name of the generator - of the residue field - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: p = L.places_finite()[0] - sage: k,fr_k,to_k = p._residue_field() - sage: k - Finite Field of size 2 - sage: [fr_k(e) for e in k] - [0, 1] - - :: - - sage: K.<x> = FunctionField(GF(9)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + Y - x^4) - sage: p = L.places()[-1] - sage: p.residue_field() - (Finite Field in z2 of size 3^2, Ring morphism: - From: Finite Field in z2 of size 3^2 - To: Valuation ring at Place (x + 1, y + 2*z2), Ring morphism: - From: Valuation ring at Place (x + 1, y + 2*z2) - To: Finite Field in z2 of size 3^2) - - :: - - sage: K.<x> = FunctionField(QQ); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + Y - x^4) - sage: O = K.maximal_order() - sage: I = O.ideal(x) - sage: [p.residue_field() for p in L.places_above(I.place())] - [(Rational Field, Ring morphism: - From: Rational Field - To: Valuation ring at Place (x, y, y^2), Ring morphism: - From: Valuation ring at Place (x, y, y^2) - To: Rational Field), - (Number Field in s with defining polynomial x^2 - 2*x + 2, Ring morphism: - From: Number Field in s with defining polynomial x^2 - 2*x + 2 - To: Valuation ring at Place (x, x*y, y^2 + 1), Ring morphism: - From: Valuation ring at Place (x, x*y, y^2 + 1) - To: Number Field in s with defining polynomial x^2 - 2*x + 2)] - sage: for p in L.places_above(I.place()): - ....: k, fr_k, to_k = p.residue_field() - ....: assert all(fr_k(k(e)) == e for e in range(10)) - ....: assert all(to_k(fr_k(e)) == e for e in [k.random_element() for i in [1..10]]) - - :: - - sage: K.<x> = FunctionField(QQbar); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + Y - x^4) - sage: O = K.maximal_order() - sage: I = O.ideal(x) - sage: [p.residue_field() for p in L.places_above(I.place())] - [(Algebraic Field, Ring morphism: - From: Algebraic Field - To: Valuation ring at Place (x, y - I, y^2 + 1), Ring morphism: - From: Valuation ring at Place (x, y - I, y^2 + 1) - To: Algebraic Field), (Algebraic Field, Ring morphism: - From: Algebraic Field - To: Valuation ring at Place (x, y, y^2), Ring morphism: - From: Valuation ring at Place (x, y, y^2) - To: Algebraic Field), (Algebraic Field, Ring morphism: - From: Algebraic Field - To: Valuation ring at Place (x, y + I, y^2 + 1), Ring morphism: - From: Valuation ring at Place (x, y + I, y^2 + 1) - To: Algebraic Field)] - """ - F = self.function_field() - prime = self.prime_ideal() # Let P be this prime ideal - - if self.is_infinite_place(): - _F, from_F, to_F = F._inversion_isomorphism() - _prime = prime._ideal - _place = _prime.place() - - K, _from_K, _to_K = _place._residue_field(name=name) - - from_K = lambda e: from_F(_from_K(e)) - to_K = lambda f: _to_K(to_F(f)) - return K, from_K, to_K - - O = F.maximal_order() - Obasis = O.basis() - - M = prime.hnf() - R = M.base_ring() # univariate polynomial ring - n = M.nrows() # extension degree of the function field - - # Step 1: construct a vector space representing the residue field - # - # Given an (reversed) HNF basis M for a prime ideal P of O, every - # element of O mod P can be represented by a vector of polynomials of - # degrees less than those of the (anti)diagonal elements of M. In turn, - # the vector of polynomials can be represented by the vector of the - # coefficients of the polynomials. V is the space of these vectors. - - k = F.constant_base_field() - degs = [M[i,i].degree() for i in range(n)] - deg = sum(degs) # degree of the place - - # Let V = k**deg - - def to_V(e): - """ - An example to show the idea: Suppose that:: - - [x 0 0] - M = [0 1 0] and v = (x^10, x^7 + x^3, x^7 + x^4 + x^3 + 1) - [1 0 1] - - Then to_V(e) = [1] - """ - v = O._coordinate_vector(e) - vec = [] - for i in reversed(range(n)): - q,r = v[i].quo_rem(M[i,i]) - v -= q * M[i] - for j in range(degs[i]): - vec.append(r[j]) - return vector(vec) - - def fr_V(vec): # to_O - vec = vec.list() - pos = 0 - e = F(0) - for i in reversed(range(n)): - if degs[i] == 0: - continue - else: - end = pos + degs[i] - e += R(vec[pos:end]) * Obasis[i] - pos = end - return e - - # Step 2: find a primitive element of the residue field - - def candidates(): - # Trial 1: this suffices for places obtained from Kummers' theorem - # and for places of function fields over number fields or QQbar - - # Note that a = O._kummer_gen is a simple generator of O/prime over - # o/p. If b is a simple generator of o/p over the constant base field - # k, then the set a + k * b contains a simple generator of O/prime - # over k (as there are finite number of intermediate fields). - a = O._kummer_gen - if a is not None: - K,fr_K,_ = self.place_below().residue_field() - b = fr_K(K.gen()) - if isinstance(k, NumberField) or k is QQbar: - kk = ZZ - else: - kk = k - for c in kk: - if c != 0: - yield a + c * b - - # Trial 2: basis elements of the maximal order - for gen in reversed(Obasis): - yield gen - - import itertools - - # Trial 3: exhaustive search in O using only polynomials - # with coefficients 0 or 1 - for d in range(deg): - G = itertools.product(itertools.product([0,1],repeat=d+1), repeat=n) - for g in G: - gen = sum([R(c1)*c2 for c1,c2 in zip(g, Obasis)]) - yield gen - - # Trial 4: exhaustive search in O using all polynomials - for d in range(deg): - G = itertools.product(R.polynomials(max_degree=d), repeat=n) - for g in G: - # discard duplicate cases - if max(c.degree() for c in g) != d: - continue - for j in range(n): - if g[j] != 0: - break - if g[j].leading_coefficient() != 1: - continue - - gen = sum([c1*c2 for c1,c2 in zip(g, Obasis)]) - yield gen - - # Search for a primitive element. It is such an element g of O - # whose powers span the vector space V. - for gen in candidates(): - g = F.one() - m = [] - for i in range(deg): - m.append(to_V(g)) - g *= gen - mat = matrix(m) - if mat.rank() == deg: - break - - # Step 3: compute the minimal polynomial of g - min_poly = R((-mat.solve_left(to_V(g))).list() + [1]) - - # Step 4: construct the residue field K as an extension of the base - # constant field using the minimal polynomial and compute vector space - # representation W of K along with maps between them - if deg > 1: - if isinstance(k, NumberField): - if name is None: - name='s' - K = k.extension(min_poly, names=name) - - def from_W(e): - return K(list(e)) - - def to_W(e): - return vector(K(e)) - else: - K = k.extension(deg, name=name) - - # primitive element in K corresponding to g in O mod P - prim = min_poly.roots(K)[0][0] - - W, from_W, to_W = K.vector_space(k, basis=[prim**i for i in range(deg)], map=True) - else: # deg == 1 - K = k - - def from_W(e): - return K(e[0]) - - def to_W(e): - return vector([e]) - - # Step 5: compute the matrix of change of basis, from V to W via K - C = mat.inverse() - - # Step 6: construct the maps between the residue field of the valuation - # ring at P and K, via O and V and W - - def from_K(e): - return fr_V(to_W(e) * mat) - - # As explained in Section 4.8.3 of [Coh1993]_, alpha has a simple pole - # at this place and no other poles at finite places. - p = prime.prime_below().gen().numerator() - beta = prime._beta - alpha = ~p * sum(c1*c2 for c1,c2 in zip(beta, Obasis)) - alpha_powered_by_ramification_index = alpha ** prime._ramification_index - - def to_K(f): - if f not in O: - den = O.coordinate_vector(f).denominator() - num = den * f - - # s powered by the valuation of den at the prime - alpha_power = alpha_powered_by_ramification_index ** den.valuation(p) - rn = num * alpha_power # in O - rd = den * alpha_power # in O but not in prime - - # Note that rn is not in O if and only if f is - # not in the valuation ring. Hence f is in the - # valuation ring if and only if this procedure - # does not fall into an infinite loop. - return to_K(rn) / to_K(rd) - - return from_W(to_V(f) * C) - - return K, from_K, to_K - - def valuation_ring(self): - """ - Return the valuation ring at the place. - - EXAMPLES:: - - sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) - sage: p = L.places_finite()[0] - sage: p.valuation_ring() - Valuation ring at Place (x, x*y) - """ - from .valuation_ring import FunctionFieldValuationRing - - return FunctionFieldValuationRing(self.function_field(), self) - - class PlaceSet(UniqueRepresentation, Parent): """ Sets of Places of function fields. @@ -1132,8 +330,8 @@ class PlaceSet(UniqueRepresentation, Parent): EXAMPLES:: sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: L.place_set() + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) # needs sage.rings.function_field + sage: L.place_set() # needs sage.rings.function_field Set of places of Function field in y defined by y^3 + x^3*y + x """ Element = FunctionFieldPlace @@ -1145,12 +343,12 @@ def __init__(self, field): TESTS:: sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: places = L.place_set() - sage: TestSuite(places).run() + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) # needs sage.rings.function_field + sage: places = L.place_set() # needs sage.rings.function_field + sage: TestSuite(places).run() # needs sage.rings.function_field """ self.Element = field._place_class - Parent.__init__(self, category = Sets().Infinite()) + Parent.__init__(self, category=Sets().Infinite()) self._field = field @@ -1161,8 +359,8 @@ def _repr_(self): EXAMPLES:: sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] - sage: L.<y> = K.extension(Y^3 + x^3*Y + x) - sage: L.place_set() + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) # needs sage.rings.function_field + sage: L.place_set() # needs sage.rings.function_field Set of places of Function field in y defined by y^3 + x^3*y + x """ return "Set of places of {}".format(self._field) @@ -1173,11 +371,12 @@ def _element_constructor_(self, x): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x^3*Y + x) sage: places = L.place_set() sage: O = L.maximal_order() - sage: places(O.ideal(x,y)) + sage: places(O.ideal(x, y)) Place (x, y) """ from .ideal import FunctionFieldIdeal @@ -1193,6 +392,7 @@ def _an_element_(self): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x^3*Y + x) sage: places = L.place_set() @@ -1216,6 +416,7 @@ def function_field(self): EXAMPLES:: + sage: # needs sage.rings.function_field sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] sage: L.<y> = K.extension(Y^3 + x^3*Y + x) sage: PS = L.place_set() diff --git a/src/sage/rings/function_field/place_polymod.py b/src/sage/rings/function_field/place_polymod.py new file mode 100644 index 00000000000..e11a6c86ab7 --- /dev/null +++ b/src/sage/rings/function_field/place_polymod.py @@ -0,0 +1,680 @@ +# sage.doctest: optional - sage.rings.function_field +""" +Places of function fields: extension +""" + +# **************************************************************************** +# Copyright (C) 2016-2022 Kwankyu Lee <ekwankyu@gmail.com> +# 2019 Brent Baccala +# 2021 Jonathan Kliem +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# **************************************************************************** + +import sage +from sage.arith.functions import lcm +from sage.rings.integer_ring import ZZ +from sage.misc.cachefunc import cached_method +from sage.rings.number_field.number_field_base import NumberField + +from .place import FunctionFieldPlace + + +class FunctionFieldPlace_polymod(FunctionFieldPlace): + """ + Places of extensions of function fields. + """ + def place_below(self): + """ + Return the place lying below the place. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) + sage: OK = K.maximal_order() + sage: OL = L.maximal_order() + sage: p = OK.ideal(x^2 + x + 1) + sage: dec = OL.decomposition(p) + sage: q = dec[0][0].place() + sage: q.place_below() + Place (x^2 + x + 1) + """ + return self.prime_ideal().prime_below().place() + + def relative_degree(self): + """ + Return the relative degree of the place. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) + sage: OK = K.maximal_order() + sage: OL = L.maximal_order() + sage: p = OK.ideal(x^2 + x + 1) + sage: dec = OL.decomposition(p) + sage: q = dec[0][0].place() + sage: q.relative_degree() + 1 + """ + return self._prime._relative_degree + + def degree(self): + """ + Return the degree of the place. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) + sage: OK = K.maximal_order() + sage: OL = L.maximal_order() + sage: p = OK.ideal(x^2 + x + 1) + sage: dec = OL.decomposition(p) + sage: q = dec[0][0].place() + sage: q.degree() + 2 + """ + return self.relative_degree() * self.place_below().degree() + + def is_infinite_place(self): + """ + Return ``True`` if the place is above the unique infinite place + of the underlying rational function field. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) + sage: pls = L.places() + sage: [p.is_infinite_place() for p in pls] + [True, True, False] + sage: [p.place_below() for p in pls] + [Place (1/x), Place (1/x), Place (x)] + """ + return self.place_below().is_infinite_place() + + def local_uniformizer(self): + """ + Return an element of the function field that has a simple zero + at the place. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) + sage: pls = L.places() + sage: [p.local_uniformizer().valuation(p) for p in pls] + [1, 1, 1, 1, 1] + """ + gens = self._prime.gens() + for g in gens: + if g.valuation(self) == 1: + return g + assert False, "Internal error" + + def gaps(self): + """ + Return the gap sequence for the place. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) + sage: O = L.maximal_order() + sage: p = O.ideal(x,y).place() + sage: p.gaps() # a Weierstrass place + [1, 2, 4] + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 + x^3 * Y + x) # needs sage.rings.finite_rings + sage: [p.gaps() for p in L.places()] # needs sage.rings.finite_rings + [[1, 2, 4], [1, 2, 4], [1, 2, 4]] + """ + if self.degree() == 1: + return self._gaps_rational() # faster for rational places + else: + return self._gaps_wronskian() + + def _gaps_rational(self): + """ + Return the gap sequence for the rational place. + + This method computes the gap numbers using the definition of gap + numbers. The dimension of the multiple of the prime divisor + supported at the place is computed by Hess' algorithm. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) + sage: O = L.maximal_order() + sage: p = O.ideal(x, y).place() + sage: p.gaps() # indirect doctest + [1, 2, 4] + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) # needs sage.rings.finite_rings + sage: [p.gaps() for p in L.places()] # indirect doctest # needs sage.rings.finite_rings + [[1, 2, 4], [1, 2, 4], [1, 2, 4]] + """ + from sage.matrix.constructor import matrix + + F = self.function_field() + n = F.degree() + O = F.maximal_order() + Oinf = F.maximal_order_infinite() + + R = O._module_base_ring._ring + one = R.one() + + # Hess' Riemann-Roch basis algorithm stripped down for gaps computation + def dim_RR(M): + den = lcm([e.denominator() for e in M.list()]) + mat = matrix(R, M.nrows(), [(den*e).numerator() for e in M.list()]) + + # initialise pivot_row and conflicts list + pivot_row = [[] for i in range(n)] + conflicts = [] + for i in range(n): + bestp = -1 + best = -1 + for c in range(n): + d = mat[i,c].degree() + if d >= best: + bestp = c + best = d + + if best >= 0: + pivot_row[bestp].append((i,best)) + if len(pivot_row[bestp]) > 1: + conflicts.append(bestp) + + # while there is a conflict, do a simple transformation + while conflicts: + c = conflicts.pop() + row = pivot_row[c] + i,ideg = row.pop() + j,jdeg = row.pop() + + if jdeg > ideg: + i,j = j,i + ideg,jdeg = jdeg,ideg + + coeff = - mat[i,c].lc() / mat[j,c].lc() + s = coeff * one.shift(ideg - jdeg) + + mat.add_multiple_of_row(i, j, s) + + row.append((j,jdeg)) + + bestp = -1 + best = -1 + for c in range(n): + d = mat[i,c].degree() + if d >= best: + bestp = c + best = d + + if best >= 0: + pivot_row[bestp].append((i,best)) + if len(pivot_row[bestp]) > 1: + conflicts.append(bestp) + + dim = 0 + for j in range(n): + i,ideg = pivot_row[j][0] + k = den.degree() - ideg + 1 + if k > 0: + dim += k + return dim + + V,fr,to = F.vector_space() + + prime_inv = ~ self.prime_ideal() + I = O.ideal(1) + J = Oinf.ideal(1) + + B = matrix([to(b) for b in J.gens_over_base()]) + C = matrix([to(v) for v in I.gens_over_base()]) + + prev = dim_RR(C * B.inverse()) + gaps = [] + g = F.genus() + i = 1 + if self.is_infinite_place(): + while g: + J = J * prime_inv + B = matrix([to(b) for b in J.gens_over_base()]) + dim = dim_RR(C * B.inverse()) + if dim == prev: + gaps.append(i) + g -= 1 + else: + prev = dim + i += 1 + else: # self is a finite place + Binv = B.inverse() + while g: + I = I * prime_inv + C = matrix([to(v) for v in I.gens_over_base()]) + dim = dim_RR(C * Binv) + if dim == prev: + gaps.append(i) + g -= 1 + else: + prev = dim + i += 1 + + return gaps + + def _gaps_wronskian(self): + """ + Return the gap sequence for the place. + + This method implements the local version of Hess' Algorithm 30 of [Hes2002b]_ + based on the Wronskian determinant. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + x^3*Y + x) + sage: O = L.maximal_order() + sage: p = O.ideal(x, y).place() + sage: p._gaps_wronskian() # a Weierstrass place + [1, 2, 4] + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] # needs sage.rings.finite_rings + sage: L.<y> = K.extension(Y^3 + x^3 * Y + x) # needs sage.rings.finite_rings + sage: [p._gaps_wronskian() for p in L.places()] # needs sage.rings.finite_rings + [[1, 2, 4], [1, 2, 4], [1, 2, 4]] + """ + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + + F = self.function_field() + R,fr_R,to_R = self._residue_field() + der = F.higher_derivation() + + sep = self.local_uniformizer() + + # a differential divisor satisfying + # v_p(W) = 0 for the place p + W = sep.differential().divisor() + + # Step 3: + basis = W._basis() + d = len(basis) + M = matrix([to_R(b) for b in basis]) + if M.rank() == 0: + return [] + + # Steps 4, 5, 6, 7: + e = 1 + gaps = [1] + while M.nrows() < d: + row = vector([to_R(der._derive(basis[i], e, sep)) for i in range(d)]) + if row not in M.row_space(): + M = matrix(M.rows() + [row]) + M.echelonize() + gaps.append(e + 1) + e += 1 + + return gaps + + def residue_field(self, name=None): + """ + Return the residue field of the place. + + INPUT: + + - ``name`` -- string; name of the generator of the residue field + + OUTPUT: + + - a field isomorphic to the residue field + + - a ring homomorphism from the valuation ring to the field + + - a ring homomorphism from the field to the valuation ring + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: k, fr_k, to_k = p.residue_field() + sage: k + Finite Field of size 2 + sage: fr_k + Ring morphism: + From: Finite Field of size 2 + To: Valuation ring at Place (x, x*y) + sage: to_k + Ring morphism: + From: Valuation ring at Place (x, x*y) + To: Finite Field of size 2 + sage: to_k(y) + Traceback (most recent call last): + ... + TypeError: y fails to convert into the map's domain + Valuation ring at Place (x, x*y)... + sage: to_k(1/y) + 0 + sage: to_k(y/(1+y)) + 1 + """ + return self.valuation_ring().residue_field(name=name) + + @cached_method + def _residue_field(self, name=None): + """ + Return the residue field of the place along with the functions + mapping from and to it. + + INPUT: + + - ``name`` -- string (default: `None`); name of the generator + of the residue field + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: k,fr_k,to_k = p._residue_field() + sage: k + Finite Field of size 2 + sage: [fr_k(e) for e in k] + [0, 1] + + :: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(9)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + Y - x^4) + sage: p = L.places()[-1] + sage: p.residue_field() + (Finite Field in z2 of size 3^2, Ring morphism: + From: Finite Field in z2 of size 3^2 + To: Valuation ring at Place (x + 1, y + 2*z2), Ring morphism: + From: Valuation ring at Place (x + 1, y + 2*z2) + To: Finite Field in z2 of size 3^2) + + :: + + sage: K.<x> = FunctionField(QQ); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + Y - x^4) + sage: O = K.maximal_order() + sage: I = O.ideal(x) + sage: [p.residue_field() for p in L.places_above(I.place())] + [(Rational Field, Ring morphism: + From: Rational Field + To: Valuation ring at Place (x, y, y^2), Ring morphism: + From: Valuation ring at Place (x, y, y^2) + To: Rational Field), + (Number Field in s with defining polynomial x^2 - 2*x + 2, Ring morphism: + From: Number Field in s with defining polynomial x^2 - 2*x + 2 + To: Valuation ring at Place (x, x*y, y^2 + 1), Ring morphism: + From: Valuation ring at Place (x, x*y, y^2 + 1) + To: Number Field in s with defining polynomial x^2 - 2*x + 2)] + sage: for p in L.places_above(I.place()): + ....: k, fr_k, to_k = p.residue_field() + ....: assert all(fr_k(k(e)) == e for e in range(10)) + ....: assert all(to_k(fr_k(e)) == e for e in [k.random_element() for i in [1..10]]) + + :: + + sage: # needs sage.rings.number_field + sage: K.<x> = FunctionField(QQbar); _.<Y> = K[] + sage: L.<y> = K.extension(Y^3 + Y - x^4) + sage: O = K.maximal_order() + sage: I = O.ideal(x) + sage: [p.residue_field() for p in L.places_above(I.place())] + [(Algebraic Field, Ring morphism: + From: Algebraic Field + To: Valuation ring at Place (x, y - I, y^2 + 1), Ring morphism: + From: Valuation ring at Place (x, y - I, y^2 + 1) + To: Algebraic Field), (Algebraic Field, Ring morphism: + From: Algebraic Field + To: Valuation ring at Place (x, y, y^2), Ring morphism: + From: Valuation ring at Place (x, y, y^2) + To: Algebraic Field), (Algebraic Field, Ring morphism: + From: Algebraic Field + To: Valuation ring at Place (x, y + I, y^2 + 1), Ring morphism: + From: Valuation ring at Place (x, y + I, y^2 + 1) + To: Algebraic Field)] + """ + F = self.function_field() + prime = self.prime_ideal() # Let P be this prime ideal + + if self.is_infinite_place(): + _F, from_F, to_F = F._inversion_isomorphism() + _prime = prime._ideal + _place = _prime.place() + + K, _from_K, _to_K = _place._residue_field(name=name) + + from_K = lambda e: from_F(_from_K(e)) + to_K = lambda f: _to_K(to_F(f)) + return K, from_K, to_K + + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + + O = F.maximal_order() + Obasis = O.basis() + + M = prime.hnf() + R = M.base_ring() # univariate polynomial ring + n = M.nrows() # extension degree of the function field + + # Step 1: construct a vector space representing the residue field + # + # Given an (reversed) HNF basis M for a prime ideal P of O, every + # element of O mod P can be represented by a vector of polynomials of + # degrees less than those of the (anti)diagonal elements of M. In turn, + # the vector of polynomials can be represented by the vector of the + # coefficients of the polynomials. V is the space of these vectors. + + k = F.constant_base_field() + degs = [M[i,i].degree() for i in range(n)] + deg = sum(degs) # degree of the place + + # Let V = k**deg + + def to_V(e): + """ + An example to show the idea: Suppose that:: + + [x 0 0] + M = [0 1 0] and v = (x^10, x^7 + x^3, x^7 + x^4 + x^3 + 1) + [1 0 1] + + Then to_V(e) = [1] + """ + v = O._coordinate_vector(e) + vec = [] + for i in reversed(range(n)): + q,r = v[i].quo_rem(M[i,i]) + v -= q * M[i] + for j in range(degs[i]): + vec.append(r[j]) + return vector(vec) + + def fr_V(vec): # to_O + vec = vec.list() + pos = 0 + e = F(0) + for i in reversed(range(n)): + if degs[i] == 0: + continue + else: + end = pos + degs[i] + e += R(vec[pos:end]) * Obasis[i] + pos = end + return e + + # Step 2: find a primitive element of the residue field + + def candidates(): + # Trial 1: this suffices for places obtained from Kummers' theorem + # and for places of function fields over number fields or QQbar + + # Note that a = O._kummer_gen is a simple generator of O/prime over + # o/p. If b is a simple generator of o/p over the constant base field + # k, then the set a + k * b contains a simple generator of O/prime + # over k (as there are finite number of intermediate fields). + a = O._kummer_gen + if a is not None: + K,fr_K,_ = self.place_below().residue_field() + b = fr_K(K.gen()) + if isinstance(k, (NumberField, sage.rings.abc.AlgebraicField)): + kk = ZZ + else: + kk = k + for c in kk: + if c != 0: + yield a + c * b + + # Trial 2: basis elements of the maximal order + for gen in reversed(Obasis): + yield gen + + import itertools + + # Trial 3: exhaustive search in O using only polynomials + # with coefficients 0 or 1 + for d in range(deg): + G = itertools.product(itertools.product([0,1],repeat=d+1), repeat=n) + for g in G: + gen = sum([R(c1)*c2 for c1,c2 in zip(g, Obasis)]) + yield gen + + # Trial 4: exhaustive search in O using all polynomials + for d in range(deg): + G = itertools.product(R.polynomials(max_degree=d), repeat=n) + for g in G: + # discard duplicate cases + if max(c.degree() for c in g) != d: + continue + for j in range(n): + if g[j] != 0: + break + if g[j].leading_coefficient() != 1: + continue + + gen = sum([c1*c2 for c1,c2 in zip(g, Obasis)]) + yield gen + + # Search for a primitive element. It is such an element g of O + # whose powers span the vector space V. + for gen in candidates(): + g = F.one() + m = [] + for i in range(deg): + m.append(to_V(g)) + g *= gen + mat = matrix(m) + if mat.rank() == deg: + break + + # Step 3: compute the minimal polynomial of g + min_poly = R((-mat.solve_left(to_V(g))).list() + [1]) + + # Step 4: construct the residue field K as an extension of the base + # constant field using the minimal polynomial and compute vector space + # representation W of K along with maps between them + if deg > 1: + if isinstance(k, NumberField): + if name is None: + name = 's' + K = k.extension(min_poly, names=name) + + def from_W(e): + return K(list(e)) + + def to_W(e): + return vector(K(e)) + else: + K = k.extension(deg, name=name) + + # primitive element in K corresponding to g in O mod P + prim = min_poly.roots(K)[0][0] + + W, from_W, to_W = K.vector_space(k, basis=[prim**i for i in range(deg)], map=True) + else: # deg == 1 + K = k + + def from_W(e): + return K(e[0]) + + def to_W(e): + return vector([e]) + + # Step 5: compute the matrix of change of basis, from V to W via K + C = mat.inverse() + + # Step 6: construct the maps between the residue field of the valuation + # ring at P and K, via O and V and W + + def from_K(e): + return fr_V(to_W(e) * mat) + + # As explained in Section 4.8.3 of [Coh1993]_, alpha has a simple pole + # at this place and no other poles at finite places. + p = prime.prime_below().gen().numerator() + beta = prime._beta + alpha = ~p * sum(c1*c2 for c1,c2 in zip(beta, Obasis)) + alpha_powered_by_ramification_index = alpha ** prime._ramification_index + + def to_K(f): + if f not in O: + den = O.coordinate_vector(f).denominator() + num = den * f + + # s powered by the valuation of den at the prime + alpha_power = alpha_powered_by_ramification_index ** den.valuation(p) + rn = num * alpha_power # in O + rd = den * alpha_power # in O but not in prime + + # Note that rn is not in O if and only if f is + # not in the valuation ring. Hence f is in the + # valuation ring if and only if this procedure + # does not fall into an infinite loop. + return to_K(rn) / to_K(rd) + + return from_W(to_V(f) * C) + + return K, from_K, to_K + + def valuation_ring(self): + """ + Return the valuation ring at the place. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: p.valuation_ring() + Valuation ring at Place (x, x*y) + """ + from .valuation_ring import FunctionFieldValuationRing + + return FunctionFieldValuationRing(self.function_field(), self) diff --git a/src/sage/rings/function_field/place_rational.py b/src/sage/rings/function_field/place_rational.py new file mode 100644 index 00000000000..9b98397ba90 --- /dev/null +++ b/src/sage/rings/function_field/place_rational.py @@ -0,0 +1,179 @@ +# sage.doctest: optional - sage.rings.finite_rings (because all doctests use finite fields) +""" +Places of function fields: rational +""" + +# **************************************************************************** +# Copyright (C) 2016-2022 Kwankyu Lee <ekwankyu@gmail.com> +# 2019 Brent Baccala +# 2021 Jonathan Kliem +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# **************************************************************************** + +from .place import FunctionFieldPlace + + +class FunctionFieldPlace_rational(FunctionFieldPlace): + """ + Places of rational function fields. + """ + def degree(self): + """ + Return the degree of the place. + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: O = F.maximal_order() + sage: i = O.ideal(x^2 + x + 1) + sage: p = i.place() + sage: p.degree() + 2 + """ + if self.is_infinite_place(): + return 1 + else: + return self._prime.gen().numerator().degree() + + def is_infinite_place(self): + """ + Return ``True`` if the place is at infinite. + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: F.places() + [Place (1/x), Place (x), Place (x + 1)] + sage: [p.is_infinite_place() for p in F.places()] + [True, False, False] + """ + F = self.function_field() + return self.prime_ideal().ring() == F.maximal_order_infinite() + + def local_uniformizer(self): + """ + Return a local uniformizer of the place. + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: F.places() + [Place (1/x), Place (x), Place (x + 1)] + sage: [p.local_uniformizer() for p in F.places()] + [1/x, x, x + 1] + """ + return self.prime_ideal().gen() + + def residue_field(self, name=None): + """ + Return the residue field of the place. + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: O = F.maximal_order() + sage: p = O.ideal(x^2 + x + 1).place() + sage: k, fr_k, to_k = p.residue_field() # needs sage.rings.function_field + sage: k # needs sage.rings.function_field + Finite Field in z2 of size 2^2 + sage: fr_k # needs sage.rings.function_field + Ring morphism: + From: Finite Field in z2 of size 2^2 + To: Valuation ring at Place (x^2 + x + 1) + sage: to_k # needs sage.rings.function_field + Ring morphism: + From: Valuation ring at Place (x^2 + x + 1) + To: Finite Field in z2 of size 2^2 + """ + return self.valuation_ring().residue_field(name=name) + + def _residue_field(self, name=None): + """ + Return the residue field of the place along with the maps from + and to it. + + INPUT: + + - ``name`` -- string; name of the generator of the residue field + + EXAMPLES:: + + sage: F.<x> = FunctionField(GF(2)) + sage: O = F.maximal_order() + sage: i = O.ideal(x^2 + x + 1) + sage: p = i.place() + sage: R, fr, to = p._residue_field() + sage: R + Finite Field in z2 of size 2^2 + sage: [fr(e) for e in R.list()] + [0, x, x + 1, 1] + sage: to(x*(x+1)) == to(x) * to(x+1) + True + """ + F = self.function_field() + prime = self.prime_ideal() + + if self.is_infinite_place(): + K = F.constant_base_field() + + def from_K(e): + return F(e) + + def to_K(f): + n = f.numerator() + d = f.denominator() + + n_deg = n.degree() + d_deg = d.degree() + + if n_deg < d_deg: + return K(0) + elif n_deg == d_deg: + return n.lc() / d.lc() + else: + raise TypeError("not in the valuation ring") + else: + O = F.maximal_order() + K, from_K, _to_K = O._residue_field(prime, name=name) + + def to_K(f): + if f in O: # f.denominator() is 1 + return _to_K(f.numerator()) + else: + d = F(f.denominator()) + n = d * f + + nv = prime.valuation(O.ideal(n)) + dv = prime.valuation(O.ideal(d)) + + if nv > dv: + return K(0) + elif dv > nv: + raise TypeError("not in the valuation ring") + + s = ~prime.gen() + rd = d * s**dv # in O but not in prime + rn = n * s**nv # in O but not in prime + return to_K(rn) / to_K(rd) + + return K, from_K, to_K + + def valuation_ring(self): + """ + Return the valuation ring at the place. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[] + sage: L.<y> = K.extension(Y^2 + Y + x + 1/x) # needs sage.rings.function_field + sage: p = L.places_finite()[0] # needs sage.rings.function_field + sage: p.valuation_ring() # needs sage.rings.function_field + Valuation ring at Place (x, x*y) + """ + from .valuation_ring import FunctionFieldValuationRing + + return FunctionFieldValuationRing(self.function_field(), self) diff --git a/src/sage/rings/function_field/valuation.py b/src/sage/rings/function_field/valuation.py new file mode 100644 index 00000000000..e8afd1cb232 --- /dev/null +++ b/src/sage/rings/function_field/valuation.py @@ -0,0 +1,1499 @@ +r""" +Discrete valuations on function fields + +AUTHORS: + +- Julian Rรผth (2016-10-16): initial version + +EXAMPLES: + +We can create classical valuations that correspond to finite and infinite +places on a rational function field:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(1); v + (x - 1)-adic valuation + sage: v = K.valuation(x^2 + 1); v + (x^2 + 1)-adic valuation + sage: v = K.valuation(1/x); v + Valuation at the infinite place + +Note that we can also specify valuations which do not correspond to a place of +the function field:: + + sage: R.<x> = QQ[] + sage: w = valuations.GaussValuation(R, QQ.valuation(2)) + sage: v = K.valuation(w); v + 2-adic valuation + +Valuations on a rational function field can then be extended to finite +extensions:: + + sage: v = K.valuation(x - 1); v + (x - 1)-adic valuation + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) # needs sage.rings.function_field + sage: w = v.extensions(L); w # needs sage.rings.function_field + [[ (x - 1)-adic valuation, v(y + 1) = 1 ]-adic valuation, + [ (x - 1)-adic valuation, v(y - 1) = 1 ]-adic valuation] + +TESTS: + +Run test suite for classical places over rational function fields:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(1) + sage: TestSuite(v).run(max_runs=100) # long time + + sage: v = K.valuation(x^2 + 1) + sage: TestSuite(v).run(max_runs=100) # long time + + sage: v = K.valuation(1/x) + sage: TestSuite(v).run(max_runs=100) # long time + +Run test suite over classical places of finite extensions:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x - 1) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) # needs sage.rings.function_field + sage: ws = v.extensions(L) # needs sage.rings.function_field + sage: for w in ws: TestSuite(w).run(max_runs=100) # long time # needs sage.rings.function_field + +Run test suite for valuations that do not correspond to a classical place:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<x> = QQ[] + sage: v = GaussValuation(R, QQ.valuation(2)) + sage: w = K.valuation(v) + sage: TestSuite(w).run() # long time + +Run test suite for a non-classical valuation that does not correspond to an +affinoid contained in the unit disk:: + + sage: w = K.valuation((w, K.hom(K.gen()/2), K.hom(2*K.gen()))); w + 2-adic valuation (in Rational function field in x over Rational Field after x |--> 1/2*x) + sage: TestSuite(w).run() # long time + +Run test suite for some other classical places over large ground fields:: + + sage: K.<t> = FunctionField(GF(3)) + sage: M.<x> = FunctionField(K) + sage: v = M.valuation(x^3 - t) + sage: TestSuite(v).run(max_runs=10) # long time + +Run test suite for extensions over the infinite place:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(1/x) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - 1/(x^2 + 1)) # needs sage.rings.function_field + sage: w = v.extensions(L) # needs sage.rings.function_field + sage: TestSuite(w).run() # long time # needs sage.rings.function_field + +Run test suite for a valuation with `v(1/x) > 0` which does not come from a +classical valuation of the infinite place:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<x> = QQ[] + sage: w = GaussValuation(R, QQ.valuation(2)).augmentation(x, 1) + sage: w = K.valuation(w) + sage: v = K.valuation((w, K.hom([~K.gen()]), K.hom([~K.gen()]))) + sage: TestSuite(v).run() # long time + +Run test suite for extensions which come from the splitting in the base field:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x^2 + 1) + sage: L.<x> = FunctionField(GaussianIntegers().fraction_field()) + sage: ws = v.extensions(L) # needs sage.rings.function_field + sage: for w in ws: TestSuite(w).run(max_runs=100) # long time # needs sage.rings.function_field + +Run test suite for a finite place with residual degree and ramification:: + + sage: K.<t> = FunctionField(GF(3)) + sage: L.<x> = FunctionField(K) + sage: v = L.valuation(x^6 - t) + sage: TestSuite(v).run(max_runs=10) # long time + +Run test suite for a valuation which is backed by limit valuation:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - (x^2 + x + 1)) + sage: v = K.valuation(x - 1) + sage: w = v.extension(L) # needs sage.rings.function_field + sage: TestSuite(w).run() # long time # needs sage.rings.function_field + +Run test suite for a valuation which sends an element to `-\infty`:: + + sage: R.<x> = QQ[] + sage: v = GaussValuation(QQ['x'], QQ.valuation(2)).augmentation(x, infinity) + sage: K.<x> = FunctionField(QQ) + sage: w = K.valuation(v) + sage: TestSuite(w).run() # long time + +REFERENCES: + +An overview of some computational tools relating to valuations on function +fields can be found in Section 4.6 of [Rรผt2014]_. Most of this was originally +developed for number fields in [Mac1936I]_ and [Mac1936II]_. + +""" + +# **************************************************************************** +# Copyright (C) 2016-2018 Julian Rรผth <julian.rueth@fsfe.org> +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.structure.factory import UniqueFactory +from sage.rings.rational_field import QQ +from sage.misc.cachefunc import cached_method + +from sage.rings.valuation.valuation import DiscreteValuation, DiscretePseudoValuation, InfiniteDiscretePseudoValuation, NegativeInfiniteDiscretePseudoValuation +from sage.rings.valuation.trivial_valuation import TrivialValuation +from sage.rings.valuation.mapped_valuation import FiniteExtensionFromLimitValuation, MappedValuation_base + +class FunctionFieldValuationFactory(UniqueFactory): + r""" + Create a valuation on ``domain`` corresponding to ``prime``. + + INPUT: + + - ``domain`` -- a function field + + - ``prime`` -- a place of the function field, a valuation on a subring, or + a valuation on another function field together with information for + isomorphisms to and from that function field + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(1); v # indirect doctest + (x - 1)-adic valuation + sage: v(x) + 0 + sage: v(x - 1) + 1 + + See :meth:`sage.rings.function_field.function_field.FunctionField.valuation` for further examples. + + """ + def create_key_and_extra_args(self, domain, prime): + r""" + Create a unique key which identifies the valuation given by ``prime`` + on ``domain``. + + TESTS: + + We specify a valuation on a function field by two different means and + get the same object:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x - 1) # indirect doctest + + sage: R.<x> = QQ[] + sage: w = GaussValuation(R, valuations.TrivialValuation(QQ)).augmentation(x - 1, 1) + sage: K.valuation(w) is v + True + + The normalization is, however, not smart enough, to unwrap + substitutions that turn out to be trivial:: + + sage: w = GaussValuation(R, QQ.valuation(2)) + sage: w = K.valuation(w) + sage: w is K.valuation((w, K.hom([~K.gen()]), K.hom([~K.gen()]))) + False + + """ + from sage.categories.function_fields import FunctionFields + if domain not in FunctionFields(): + raise ValueError("Domain must be a function field.") + + if isinstance(prime, tuple): + if len(prime) == 3: + # prime is a triple of a valuation on another function field with + # isomorphism information + return self.create_key_and_extra_args_from_valuation_on_isomorphic_field(domain, prime[0], prime[1], prime[2]) + + from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace + if prime.parent() is DiscretePseudoValuationSpace(domain): + # prime is already a valuation of the requested domain + # if we returned (domain, prime), we would break caching + # because this element has been created from a different key + # Instead, we return the key that was used to create prime + # so the caller gets back a correctly cached version of prime + if not hasattr(prime, "_factory_data"): + raise NotImplementedError("Valuations on function fields must be unique and come out of the FunctionFieldValuation factory but %r has been created by other means" % (prime,)) + return prime._factory_data[2], {} + + if prime in domain: + # prime defines a place + return self.create_key_and_extra_args_from_place(domain, prime) + if prime.parent() is DiscretePseudoValuationSpace(domain._ring): + # prime is a discrete (pseudo-)valuation on the polynomial ring + # that the domain is constructed from + return self.create_key_and_extra_args_from_valuation(domain, prime) + if domain.base_field() is not domain: + # prime might define a valuation on a subring of domain and have a + # unique extension to domain + base_valuation = domain.base_field().valuation(prime) + return self.create_key_and_extra_args_from_valuation(domain, base_valuation) + from sage.rings.ideal import is_Ideal + if is_Ideal(prime): + raise NotImplementedError("a place cannot be given by an ideal yet") + + raise NotImplementedError("argument must be a place or a pseudo-valuation on a supported subring but %r does not satisfy this for the domain %r" % (prime, domain)) + + def create_key_and_extra_args_from_place(self, domain, generator): + r""" + Create a unique key which identifies the valuation at the place + specified by ``generator``. + + TESTS: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(1/x) # indirect doctest + + """ + if generator not in domain.base_field(): + raise NotImplementedError("a place must be defined over a rational function field") + + if domain.base_field() is not domain: + # if this is an extension field, construct the unique place over + # the place on the subfield + return self.create_key_and_extra_args(domain, domain.base_field().valuation(generator)) + + if generator in domain.constant_base_field(): + # generator is a constant, we associate to it the place which + # corresponds to the polynomial (x - generator) + return self.create_key_and_extra_args(domain, domain.gen() - generator) + + if generator in domain._ring: + # generator is a polynomial + generator = domain._ring(generator) + if not generator.is_monic(): + raise ValueError("place must be defined by a monic polynomial but %r is not monic" % (generator,)) + if not generator.is_irreducible(): + raise ValueError("place must be defined by an irreducible polynomial but %r factors over %r" % (generator, domain._ring)) + # we construct the corresponding valuation on the polynomial ring + # with v(generator) = 1 + from sage.rings.valuation.gauss_valuation import GaussValuation + valuation = GaussValuation(domain._ring, TrivialValuation(domain.constant_base_field())).augmentation(generator, 1) + return self.create_key_and_extra_args(domain, valuation) + elif generator == ~domain.gen(): + # generator is 1/x, the infinite place + return (domain, (domain.valuation(domain.gen()), domain.hom(~domain.gen()), domain.hom(~domain.gen()))), {} + else: + raise ValueError("a place must be given by an irreducible polynomial or the inverse of the generator; %r does not define a place over %r" % (generator, domain)) + + def create_key_and_extra_args_from_valuation(self, domain, valuation): + r""" + Create a unique key which identifies the valuation which extends + ``valuation``. + + TESTS: + + sage: K.<x> = FunctionField(QQ) + sage: R.<x> = QQ[] + sage: w = GaussValuation(R, valuations.TrivialValuation(QQ)).augmentation(x - 1, 1) + sage: v = K.valuation(w) # indirect doctest + + Check that :trac:`25294` has been resolved:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^3 + 1/x^3*y + 2/x^4) # needs sage.rings.function_field + sage: v = K.valuation(x) # needs sage.rings.function_field + sage: v.extensions(L) # needs sage.rings.function_field + [[ (x)-adic valuation, v(y) = 1 ]-adic valuation + (in Function field in y defined by y^3 + x*y + 2*x^2 after y |--> 1/x^2*y), + [ (x)-adic valuation, v(y) = 1/2 ]-adic valuation + (in Function field in y defined by y^3 + x*y + 2*x^2 after y |--> 1/x^2*y)] + + """ + # this should have been handled by create_key already + assert valuation.domain() is not domain + + if valuation.domain() is domain._ring: + if domain.base_field() is not domain: + vK = valuation.restriction(valuation.domain().base_ring()) + if vK.domain() is not domain.base_field(): + raise ValueError("valuation must extend a valuation on the base field but %r extends %r whose domain is not %r" % (valuation, vK, domain.base_field())) + # Valuation is an approximant that describes a single valuation + # on domain. + # For uniqueness of valuations (which provides better caching + # and easier pickling) we need to find a normal form of + # valuation, i.e., the smallest approximant that describes this + # valuation + approximants = vK.mac_lane_approximants(domain.polynomial(), require_incomparability=True) + approximant = vK.mac_lane_approximant(domain.polynomial(), valuation, approximants) + return (domain, approximant), {'approximants': approximants} + else: + # on a rational function field K(x), any valuation on K[x] that + # does not have an element with valuation -infty extends to a + # pseudo-valuation on K(x) + if valuation.is_negative_pseudo_valuation(): + raise ValueError("there must not be an element of valuation -Infinity in the domain of valuation %r" % (valuation,)) + return (domain, valuation), {} + + if valuation.domain().is_subring(domain.base_field()): + # valuation is defined on a subring of this function field, try to lift it + return self.create_key_and_extra_args(domain, valuation.extension(domain)) + + raise NotImplementedError("extension of valuation from %r to %r not implemented yet" % (valuation.domain(), domain)) + + def create_key_and_extra_args_from_valuation_on_isomorphic_field(self, domain, valuation, to_valuation_domain, from_valuation_domain): + r""" + Create a unique key which identifies the valuation which is + ``valuation`` after mapping through ``to_valuation_domain``. + + TESTS:: + + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 + y + x^3) # needs sage.rings.function_field + sage: v = K.valuation(1/x) # needs sage.rings.function_field + sage: w = v.extension(L) # indirect doctest # needs sage.rings.function_field + + """ + from sage.categories.function_fields import FunctionFields + if valuation.domain() not in FunctionFields(): + raise ValueError("valuation must be defined over an isomorphic function field but %r is not a function field" % (valuation.domain(),)) + + from sage.categories.homset import Hom + if to_valuation_domain not in Hom(domain, valuation.domain()): + raise ValueError("to_valuation_domain must map from %r to %r but %r maps from %r to %r" % (domain, valuation.domain(), to_valuation_domain, to_valuation_domain.domain(), to_valuation_domain.codomain())) + if from_valuation_domain not in Hom(valuation.domain(), domain): + raise ValueError("from_valuation_domain must map from %r to %r but %r maps from %r to %r" % (valuation.domain(), domain, from_valuation_domain, from_valuation_domain.domain(), from_valuation_domain.codomain())) + + if domain is domain.base(): + if valuation.domain() is not valuation.domain().base() or valuation.domain().constant_base_field() != domain.constant_base_field(): + raise NotImplementedError("maps must be isomorphisms with a rational function field over the same base field, not with %r" % (valuation.domain(),)) + if domain != valuation.domain(): + # make it harder to create different representations of the same valuation + # (nothing bad happens if we did, but >= and <= are only implemented when this is the case.) + raise NotImplementedError("domain and valuation.domain() must be the same rational function field but %r is not %r" % (domain, valuation.domain())) + else: + if domain.base() is not valuation.domain().base(): + raise NotImplementedError("domain and valuation.domain() must have the same base field but %r is not %r" % (domain.base(), valuation.domain().base())) + if to_valuation_domain != domain.hom([to_valuation_domain(domain.gen())]): + raise NotImplementedError("to_valuation_domain must be trivial on the base fields but %r is not %r" % (to_valuation_domain, domain.hom([to_valuation_domain(domain.gen())]))) + if from_valuation_domain != valuation.domain().hom([from_valuation_domain(valuation.domain().gen())]): + raise NotImplementedError("from_valuation_domain must be trivial on the base fields but %r is not %r" % (from_valuation_domain, valuation.domain().hom([from_valuation_domain(valuation.domain().gen())]))) + if to_valuation_domain(domain.gen()) == valuation.domain().gen(): + raise NotImplementedError("to_valuation_domain seems to be trivial but trivial maps would currently break partial orders of valuations") + + if from_valuation_domain(to_valuation_domain(domain.gen())) != domain.gen(): + # only a necessary condition + raise ValueError("to_valuation_domain and from_valuation_domain are not inverses of each other") + + return (domain, (valuation, to_valuation_domain, from_valuation_domain)), {} + + def create_object(self, version, key, **extra_args): + r""" + Create the valuation specified by ``key``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<x> = QQ[] + sage: w = valuations.GaussValuation(R, QQ.valuation(2)) + sage: v = K.valuation(w); v # indirect doctest + 2-adic valuation + + """ + domain, valuation = key + from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace + parent = DiscretePseudoValuationSpace(domain) + + if isinstance(valuation, tuple) and len(valuation) == 3: + valuation, to_valuation_domain, from_valuation_domain = valuation + if domain is domain.base() and valuation.domain() is valuation.domain().base(): + if valuation == valuation.domain().valuation(valuation.domain().gen()): + if to_valuation_domain != domain.hom([~valuation.domain().gen()]) or from_valuation_domain != valuation.domain().hom([~domain.gen()]): + raise ValueError("the only allowed automorphism for classical valuations is the automorphism x |--> 1/x") + # valuation on the rational function field after x |--> 1/x, + # i.e., the classical valuation at infinity + return parent.__make_element_class__(InfiniteRationalFunctionFieldValuation)(parent) + + from sage.structure.dynamic_class import dynamic_class + clazz = RationalFunctionFieldMappedValuation + if valuation.is_discrete_valuation(): + clazz = dynamic_class("RationalFunctionFieldMappedValuation_discrete", (clazz, DiscreteValuation)) + else: + clazz = dynamic_class("RationalFunctionFieldMappedValuation_infinite", (clazz, InfiniteDiscretePseudoValuation)) + return parent.__make_element_class__(clazz)(parent, valuation, to_valuation_domain, from_valuation_domain) + return parent.__make_element_class__(FunctionFieldExtensionMappedValuation)(parent, valuation, to_valuation_domain, from_valuation_domain) + + if domain is valuation.domain(): + # we cannot just return valuation in this case + # as this would break uniqueness and pickling + raise ValueError("valuation must not be a valuation on domain yet but %r is a valuation on %r" % (valuation, domain)) + + if domain.base_field() is domain: + # valuation is a base valuation on K[x] that induces a valuation on K(x) + if valuation.restriction(domain.constant_base_field()).is_trivial() and valuation.is_discrete_valuation(): + # valuation corresponds to a finite place + return parent.__make_element_class__(FiniteRationalFunctionFieldValuation)(parent, valuation) + else: + from sage.structure.dynamic_class import dynamic_class + clazz = NonClassicalRationalFunctionFieldValuation + if valuation.is_discrete_valuation(): + clazz = dynamic_class("NonClassicalRationalFunctionFieldValuation_discrete", (clazz, DiscreteFunctionFieldValuation_base)) + else: + clazz = dynamic_class("NonClassicalRationalFunctionFieldValuation_negative_infinite", (clazz, NegativeInfiniteDiscretePseudoValuation)) + return parent.__make_element_class__(clazz)(parent, valuation) + else: + # valuation is a limit valuation that singles out an extension + return parent.__make_element_class__(FunctionFieldFromLimitValuation)(parent, valuation, domain.polynomial(), extra_args['approximants']) + + raise NotImplementedError("valuation on %r from %r on %r" % (domain, valuation, valuation.domain())) + + +FunctionFieldValuation = FunctionFieldValuationFactory("sage.rings.function_field.valuation.FunctionFieldValuation") + + +class FunctionFieldValuation_base(DiscretePseudoValuation): + r""" + Abstract base class for any discrete (pseudo-)valuation on a function + field. + + TESTS:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x) # indirect doctest + sage: from sage.rings.function_field.valuation import FunctionFieldValuation_base + sage: isinstance(v, FunctionFieldValuation_base) + True + + """ + + +class DiscreteFunctionFieldValuation_base(DiscreteValuation): + r""" + Base class for discrete valuations on function fields. + + TESTS:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x) # indirect doctest + sage: from sage.rings.function_field.valuation import DiscreteFunctionFieldValuation_base + sage: isinstance(v, DiscreteFunctionFieldValuation_base) + True + + """ + def extensions(self, L): + r""" + Return the extensions of this valuation to ``L``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x) # needs sage.rings.function_field + sage: v.extensions(L) # needs sage.rings.function_field + [(x)-adic valuation] + + TESTS: + + Valuations over the infinite place:: + + sage: v = K.valuation(1/x) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - 1/(x^2 + 1)) # needs sage.rings.function_field + sage: sorted(v.extensions(L), key=str) # needs sage.rings.function_field + [[ Valuation at the infinite place, v(y + 1/x) = 3 ]-adic valuation, + [ Valuation at the infinite place, v(y - 1/x) = 3 ]-adic valuation] + + Iterated extensions over the infinite place:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 + y + x^3) + sage: v = K.valuation(1/x) + sage: w = v.extension(L) + sage: R.<z> = L[] + sage: M.<z> = L.extension(z^2 - y) + sage: w.extension(M) # not implemented + Traceback (most recent call last): + ... + NotImplementedError + + A case that caused some trouble at some point:: + + sage: R.<x> = QQ[] + sage: v = GaussValuation(R, QQ.valuation(2)) + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(v) + + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^3 - x^4 - 1) # needs sage.rings.function_field + sage: v.extensions(L) # needs sage.rings.function_field + [2-adic valuation] + + Test that this works in towers:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y - x) + sage: R.<z> = L[] + sage: L.<z> = L.extension(z - y) + sage: v = K.valuation(x) + sage: v.extensions(L) + [(x)-adic valuation] + """ + K = self.domain() + from sage.categories.function_fields import FunctionFields + if L is K: + return [self] + if L in FunctionFields(): + if K.is_subring(L): + if L.base() is K: + # L = K[y]/(G) is a simple extension of the domain of this valuation + G = L.polynomial() + if not G.is_monic(): + G = G / G.leading_coefficient() + if any(self(c) < 0 for c in G.coefficients()): + # rewrite L = K[u]/(H) with H integral and compute the extensions + from sage.rings.valuation.gauss_valuation import GaussValuation + g = GaussValuation(G.parent(), self) + y_to_u, u_to_y, H = g.monic_integral_model(G) + M = K.extension(H, names=L.variable_names()) + H_extensions = self.extensions(M) + + from sage.rings.morphism import RingHomomorphism_im_gens + if isinstance(y_to_u, RingHomomorphism_im_gens) and isinstance(u_to_y, RingHomomorphism_im_gens): + return [L.valuation((w, L.hom([M(y_to_u(y_to_u.domain().gen()))]), M.hom([L(u_to_y(u_to_y.domain().gen()))]))) for w in H_extensions] + raise NotImplementedError + return [L.valuation(w) for w in self.mac_lane_approximants(L.polynomial(), require_incomparability=True)] + elif L.base() is not L and K.is_subring(L): + # recursively call this method for the tower of fields + from operator import add + from functools import reduce + A = [base_valuation.extensions(L) for base_valuation in self.extensions(L.base())] + return reduce(add, A, []) + elif L.constant_base_field() is not K.constant_base_field() and K.constant_base_field().is_subring(L): + # subclasses should override this method and handle this case, so we never get here + raise NotImplementedError("Cannot compute the extensions of %r from %r to %r since the base ring changes." % (self, self.domain(), L)) + raise NotImplementedError("extension of %r from %r to %r not implemented" % (self, K, L)) + + +class RationalFunctionFieldValuation_base(FunctionFieldValuation_base): + r""" + Base class for valuations on rational function fields. + + TESTS:: + + sage: K.<x> = FunctionField(GF(2)) + sage: v = K.valuation(x) # indirect doctest + sage: from sage.rings.function_field.valuation import RationalFunctionFieldValuation_base + sage: isinstance(v, RationalFunctionFieldValuation_base) + True + + """ + @cached_method + def element_with_valuation(self, s): + r""" + Return an element with valuation ``s``. + + EXAMPLES:: + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 + 6) + sage: v = K.valuation(2) + sage: R.<x> = K[] + sage: w = GaussValuation(R, v).augmentation(x, 1/123) + sage: K.<x> = FunctionField(K) + sage: w = w.extension(K) + sage: w.element_with_valuation(122/123) + 2/x + sage: w.element_with_valuation(1) + 2 + + """ + constant_valuation = self.restriction(self.domain().constant_base_field()) + if constant_valuation.is_trivial(): + return super().element_with_valuation(s) + + a, b = self.value_group()._element_with_valuation(constant_valuation.value_group(), s) + ret = self.uniformizer()**a * constant_valuation.element_with_valuation(constant_valuation.value_group().gen()*b) + + return self.simplify(ret, error=s) + + +class ClassicalFunctionFieldValuation_base(DiscreteFunctionFieldValuation_base): + r""" + Base class for discrete valuations on rational function fields that come + from points on the projective line. + + TESTS:: + + sage: K.<x> = FunctionField(GF(5)) + sage: v = K.valuation(x) # indirect doctest + sage: from sage.rings.function_field.valuation import ClassicalFunctionFieldValuation_base + sage: isinstance(v, ClassicalFunctionFieldValuation_base) + True + + """ + def _test_classical_residue_field(self, **options): + r""" + Check correctness of the residue field of a discrete valuation at a + classical point. + + TESTS:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x^2 + 1) + sage: v._test_classical_residue_field() + + """ + tester = self._tester(**options) + + tester.assertTrue(self.domain().constant_base_field().is_subring(self.residue_field())) + + def _ge_(self, other): + r""" + Return whether ``self`` is greater or equal to ``other`` everywhere. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x^2 + 1) + sage: w = K.valuation(x) + sage: v >= w + False + sage: w >= v + False + + """ + if other.is_trivial(): + return other.is_discrete_valuation() + if isinstance(other, ClassicalFunctionFieldValuation_base): + return self == other + super()._ge_(other) + + +class InducedRationalFunctionFieldValuation_base(FunctionFieldValuation_base): + r""" + Base class for function field valuation induced by a valuation on the + underlying polynomial ring. + + TESTS:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x^2 + 1) # indirect doctest + + """ + def __init__(self, parent, base_valuation): + r""" + TESTS:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x) # indirect doctest + sage: from sage.rings.function_field.valuation import InducedRationalFunctionFieldValuation_base + sage: isinstance(v, InducedRationalFunctionFieldValuation_base) + True + + """ + FunctionFieldValuation_base.__init__(self, parent) + + domain = parent.domain() + if base_valuation.domain() is not domain._ring: + raise ValueError("base valuation must be defined on %r but %r is defined on %r" % (domain._ring, base_valuation, base_valuation.domain())) + + self._base_valuation = base_valuation + + def uniformizer(self): + r""" + Return a uniformizing element for this valuation. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K.valuation(x).uniformizer() + x + + """ + return self.domain()(self._base_valuation.uniformizer()) + + def lift(self, F): + r""" + Return a lift of ``F`` to the domain of this valuation such + that :meth:`reduce` returns the original element. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x) + sage: v.lift(0) + 0 + sage: v.lift(1) + 1 + + """ + F = self.residue_ring().coerce(F) + if F in self._base_valuation.residue_ring(): + num = self._base_valuation.residue_ring()(F) + den = self._base_valuation.residue_ring()(1) + elif F in self._base_valuation.residue_ring().fraction_field(): + num = self._base_valuation.residue_ring()(F.numerator()) + den = self._base_valuation.residue_ring()(F.denominator()) + else: + raise NotImplementedError("lifting not implemented for this valuation") + + return self.domain()(self._base_valuation.lift(num)) / self.domain()(self._base_valuation.lift(den)) + + def value_group(self): + r""" + Return the value group of this valuation. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K.valuation(x).value_group() + Additive Abelian Group generated by 1 + + """ + return self._base_valuation.value_group() + + def reduce(self, f): + r""" + Return the reduction of ``f`` in :meth:`residue_ring`. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x^2 + 1) + sage: v.reduce(x) + u1 + + """ + f = self.domain().coerce(f) + + if self(f) > 0: + return self.residue_field().zero() + if self(f) < 0: + raise ValueError("cannot reduce element of negative valuation") + + base = self._base_valuation + + num = f.numerator() + den = f.denominator() + + assert base(num) == base(den) + shift = base.element_with_valuation(-base(num)) + num *= shift + den *= shift + ret = base.reduce(num) / base.reduce(den) + assert not ret.is_zero() + return self.residue_field()(ret) + + def _repr_(self): + r""" + Return a printable representation of this valuation. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K.valuation(x^2 + 1) # indirect doctest + (x^2 + 1)-adic valuation + + """ + from sage.rings.valuation.augmented_valuation import AugmentedValuation_base + from sage.rings.valuation.gauss_valuation import GaussValuation + if isinstance(self._base_valuation, AugmentedValuation_base): + if self._base_valuation._base_valuation == GaussValuation(self.domain()._ring, TrivialValuation(self.domain().constant_base_field())): + if self._base_valuation._mu == 1: + return "(%r)-adic valuation" % (self._base_valuation.phi()) + vK = self._base_valuation.restriction(self._base_valuation.domain().base_ring()) + if self._base_valuation == GaussValuation(self.domain()._ring, vK): + return repr(vK) + return "Valuation on rational function field induced by %s" % self._base_valuation + + def extensions(self, L): + r""" + Return all extensions of this valuation to ``L`` which has a larger + constant field than the domain of this valuation. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x^2 + 1) + sage: L.<x> = FunctionField(GaussianIntegers().fraction_field()) + sage: v.extensions(L) # indirect doctest + [(x - I)-adic valuation, (x + I)-adic valuation] + + """ + K = self.domain() + if L is K: + return [self] + + from sage.categories.function_fields import FunctionFields + if (L in FunctionFields() + and K.is_subring(L) + and L.base() is L + and L.constant_base_field() is not K.constant_base_field() + and K.constant_base_field().is_subring(L.constant_base_field())): + # The above condition checks whether L is an extension of K that + # comes from an extension of the field of constants + # Condition "L.base() is L" is important so we do not call this + # code for extensions from K(x) to K(x)(y) + + # We extend the underlying valuation on the polynomial ring + W = self._base_valuation.extensions(L._ring) + return [L.valuation(w) for w in W] + + return super().extensions(L) + + def _call_(self, f): + r""" + Evaluate this valuation at the function ``f``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x) # indirect doctest + sage: v((x+1)/x^2) + -2 + + """ + return self._base_valuation(f.numerator()) - self._base_valuation(f.denominator()) + + def residue_ring(self): + r""" + Return the residue field of this valuation. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K.valuation(x).residue_ring() + Rational Field + + """ + return self._base_valuation.residue_ring().fraction_field() + + def restriction(self, ring): + r""" + Return the restriction of this valuation to ``ring``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K.valuation(x).restriction(QQ) + Trivial valuation on Rational Field + + """ + if ring.is_subring(self._base_valuation.domain()): + return self._base_valuation.restriction(ring) + return super().restriction(ring) + + def simplify(self, f, error=None, force=False): + r""" + Return a simplified version of ``f``. + + Produce an element which differs from ``f`` by an element of + valuation strictly greater than the valuation of ``f`` (or strictly + greater than ``error`` if set.) + + If ``force`` is not set, then expensive simplifications may be avoided. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(2) + sage: f = (x + 1)/(x - 1) + + As the coefficients of this fraction are small, we do not simplify as + this could be very costly in some cases:: + + sage: v.simplify(f) + (x + 1)/(x - 1) + + However, simplification can be forced:: + + sage: v.simplify(f, force=True) + 3 + + """ + f = self.domain().coerce(f) + + if error is None: + # if the caller was sure that we should simplify, then we should try to do the best simplification possible + error = self(f) if force else self.upper_bound(f) + + from sage.rings.infinity import infinity + if error is infinity: + return f + + numerator = f.numerator() + denominator = f.denominator() + + v_numerator = self._base_valuation(numerator) + v_denominator = self._base_valuation(denominator) + + if v_numerator - v_denominator > error: + return self.domain().zero() + + if error == -infinity: + # This case is not implemented yet, so we just return f which is always safe. + return f + + numerator = self.domain()(self._base_valuation.simplify(numerator, error=error+v_denominator, force=force)) + denominator = self.domain()(self._base_valuation.simplify(denominator, error=max(v_denominator, error - v_numerator + 2*v_denominator), force=force)) + + ret = numerator/denominator + assert self(ret - f) > error + return ret + + def _relative_size(self, f): + r""" + Return an estimate on the coefficient size of ``f``. + + The number returned is an estimate on the factor between the number of + bits used by ``f`` and the minimal number of bits used by an element + congruent to ``f``. + + This can be used by :meth:`simplify` to decide whether simplification + of coefficients is going to lead to a significant shrinking of the + coefficients of ``f``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(0) + sage: f = (x + 1024)/(x - 1024) + + Here we report a small size, as the numerator and the denominator + independently cannot be simplified much:: + + sage: v._relative_size(f) + 1 + + However, a forced simplification, finds that we could have saved many + more bits:: + + sage: v.simplify(f, force=True) + -1 + + """ + return max(self._base_valuation._relative_size(f.numerator()), self._base_valuation._relative_size(f.denominator())) + + +class FiniteRationalFunctionFieldValuation(InducedRationalFunctionFieldValuation_base, ClassicalFunctionFieldValuation_base, RationalFunctionFieldValuation_base): + r""" + Valuation of a finite place of a function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x + 1); v # indirect doctest + (x + 1)-adic valuation + + A finite place with residual degree:: + + sage: w = K.valuation(x^2 + 1); w + (x^2 + 1)-adic valuation + + A finite place with ramification:: + + sage: K.<t> = FunctionField(GF(3)) + sage: L.<x> = FunctionField(K) + sage: u = L.valuation(x^3 - t); u + (x^3 + 2*t)-adic valuation + + A finite place with residual degree and ramification:: + + sage: q = L.valuation(x^6 - t); q + (x^6 + 2*t)-adic valuation + + """ + def __init__(self, parent, base_valuation): + r""" + TESTS:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(x + 1) + sage: from sage.rings.function_field.valuation import FiniteRationalFunctionFieldValuation + sage: isinstance(v, FiniteRationalFunctionFieldValuation) + True + + """ + InducedRationalFunctionFieldValuation_base.__init__(self, parent, base_valuation) + ClassicalFunctionFieldValuation_base.__init__(self, parent) + RationalFunctionFieldValuation_base.__init__(self, parent) + + +class NonClassicalRationalFunctionFieldValuation(InducedRationalFunctionFieldValuation_base, RationalFunctionFieldValuation_base): + r""" + Valuation induced by a valuation on the underlying polynomial ring which is + non-classical. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = GaussValuation(QQ['x'], QQ.valuation(2)) + sage: w = K.valuation(v); w # indirect doctest + 2-adic valuation + + """ + def __init__(self, parent, base_valuation): + r""" + TESTS: + + There is some support for discrete pseudo-valuations on rational + function fields in the code. However, since these valuations must send + elements to `-\infty`, they are not supported yet:: + + sage: R.<x> = QQ[] + sage: v = GaussValuation(QQ['x'], QQ.valuation(2)).augmentation(x, infinity) + sage: K.<x> = FunctionField(QQ) + sage: w = K.valuation(v) + sage: from sage.rings.function_field.valuation import NonClassicalRationalFunctionFieldValuation + sage: isinstance(w, NonClassicalRationalFunctionFieldValuation) + True + + """ + InducedRationalFunctionFieldValuation_base.__init__(self, parent, base_valuation) + RationalFunctionFieldValuation_base.__init__(self, parent) + + def residue_ring(self): + r""" + Return the residue field of this valuation. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = valuations.GaussValuation(QQ['x'], QQ.valuation(2)) + sage: w = K.valuation(v) + sage: w.residue_ring() + Rational function field in x over Finite Field of size 2 + + sage: R.<x> = QQ[] + sage: vv = v.augmentation(x, 1) + sage: w = K.valuation(vv) + sage: w.residue_ring() + Rational function field in x over Finite Field of size 2 + + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 + 2*x) # needs sage.rings.function_field + sage: w.extension(L).residue_ring() # needs sage.rings.function_field + Function field in u2 defined by u2^2 + x + + TESTS: + + This still works for pseudo-valuations:: + + sage: R.<x> = QQ[] + sage: v = valuations.GaussValuation(R, QQ.valuation(2)) + sage: vv = v.augmentation(x, infinity) + sage: K.<x> = FunctionField(QQ) + sage: w = K.valuation(vv) + sage: w.residue_ring() + Finite Field of size 2 + + """ + if not self.is_discrete_valuation(): + # A pseudo valuation attaining negative infinity does typically not have a function field as its residue ring + return super().residue_ring() + return self._base_valuation.residue_ring().fraction_field().function_field() + + +class FunctionFieldFromLimitValuation(FiniteExtensionFromLimitValuation, DiscreteFunctionFieldValuation_base): + r""" + A valuation on a finite extensions of function fields `L=K[y]/(G)` where `K` is + another function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - (x^2 + x + 1)) # needs sage.rings.function_field + sage: v = K.valuation(x - 1) # indirect doctest # needs sage.rings.function_field + sage: w = v.extension(L); w # needs sage.rings.function_field + (x - 1)-adic valuation + + """ + def __init__(self, parent, approximant, G, approximants): + r""" + TESTS:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - (x^2 + x + 1)) + sage: v = K.valuation(x - 1) # indirect doctest + sage: w = v.extension(L) + sage: from sage.rings.function_field.valuation import FunctionFieldFromLimitValuation + sage: isinstance(w, FunctionFieldFromLimitValuation) + True + + """ + FiniteExtensionFromLimitValuation.__init__(self, parent, approximant, G, approximants) + DiscreteFunctionFieldValuation_base.__init__(self, parent) + + def _to_base_domain(self, f): + r""" + Return ``f`` as an element of the domain of the underlying limit valuation. + + EXAMPLES:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - (x^2 + x + 1)) + sage: v = K.valuation(x - 1) # indirect doctest + sage: w = v.extension(L) + sage: w._to_base_domain(y).parent() + Univariate Polynomial Ring in y over Rational function field in x over Rational Field + + """ + return f.element() + + def scale(self, scalar): + r""" + Return this valuation scaled by ``scalar``. + + EXAMPLES:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - (x^2 + x + 1)) + sage: v = K.valuation(x - 1) # indirect doctest + sage: w = v.extension(L) + sage: 3*w + 3 * (x - 1)-adic valuation + + """ + if scalar in QQ and scalar > 0 and scalar != 1: + return self.domain().valuation(self._base_valuation._initial_approximation.scale(scalar)) + return super().scale(scalar) + + +class FunctionFieldMappedValuation_base(FunctionFieldValuation_base, MappedValuation_base): + r""" + A valuation on a function field which relies on a ``base_valuation`` on an + isomorphic function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: v = K.valuation(1/x); v + Valuation at the infinite place + + """ + def __init__(self, parent, base_valuation, to_base_valuation_domain, from_base_valuation_domain): + r""" + TESTS:: + + sage: K.<x> = FunctionField(GF(2)) + sage: v = K.valuation(1/x) + sage: from sage.rings.function_field.valuation import FunctionFieldMappedValuation_base + sage: isinstance(v, FunctionFieldMappedValuation_base) + True + + """ + FunctionFieldValuation_base.__init__(self, parent) + MappedValuation_base.__init__(self, parent, base_valuation) + + self._to_base = to_base_valuation_domain + self._from_base = from_base_valuation_domain + + def _to_base_domain(self, f): + r""" + Return ``f`` as an element in the domain of ``_base_valuation``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 + y + x^3) # needs sage.rings.function_field + sage: v = K.valuation(1/x) + sage: w = v.extension(L) # needs sage.rings.function_field + sage: w._to_base_domain(y) # needs sage.rings.function_field + x^2*y + + """ + return self._to_base(f) + + def _from_base_domain(self, f): + r""" + Return ``f`` as an element in the domain of this valuation. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 + y + x^3) # needs sage.rings.function_field + sage: v = K.valuation(1/x) + sage: w = v.extension(L) # needs sage.rings.function_field + sage: w._from_base_domain(w._to_base_domain(y)) # needs sage.rings.function_field + y + + r""" + return self._from_base(f) + + def scale(self, scalar): + r""" + Return this valuation scaled by ``scalar``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 + y + x^3) # needs sage.rings.function_field + sage: v = K.valuation(1/x) + sage: w = v.extension(L) # needs sage.rings.function_field + sage: 3*w # needs sage.rings.function_field + 3 * (x)-adic valuation (in Rational function field in x over Finite Field of size 2 after x |--> 1/x) + + """ + from sage.rings.rational_field import QQ + if scalar in QQ and scalar > 0 and scalar != 1: + return self.domain().valuation((self._base_valuation.scale(scalar), self._to_base, self._from_base)) + return super().scale(scalar) + + def _repr_(self): + r""" + Return a printable representation of this valuation. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 + y + x^3) # needs sage.rings.function_field + sage: v = K.valuation(1/x) + sage: v.extension(L) # indirect doctest # needs sage.rings.function_field + Valuation at the infinite place + + """ + to_base = repr(self._to_base) + if hasattr(self._to_base, '_repr_defn'): + to_base = self._to_base._repr_defn().replace('\n', ', ') + return "%r (in %r after %s)" % (self._base_valuation, self._base_valuation.domain(), to_base) + + def is_discrete_valuation(self): + r""" + Return whether this is a discrete valuation. + + EXAMPLES:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - x^4 - 1) + sage: v = K.valuation(1/x) + sage: w0,w1 = v.extensions(L) + sage: w0.is_discrete_valuation() + True + + """ + return self._base_valuation.is_discrete_valuation() + + +class FunctionFieldMappedValuationRelative_base(FunctionFieldMappedValuation_base): + r""" + A valuation on a function field which relies on a ``base_valuation`` on an + isomorphic function field and which is such that the map from and to the + other function field is the identity on the constant field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: v = K.valuation(1/x); v + Valuation at the infinite place + + """ + def __init__(self, parent, base_valuation, to_base_valuation_domain, from_base_valuation_domain): + r""" + TESTS:: + + sage: K.<x> = FunctionField(GF(2)) + sage: v = K.valuation(1/x) + sage: from sage.rings.function_field.valuation import FunctionFieldMappedValuationRelative_base + sage: isinstance(v, FunctionFieldMappedValuationRelative_base) + True + + """ + FunctionFieldMappedValuation_base.__init__(self, parent, base_valuation, to_base_valuation_domain, from_base_valuation_domain) + if self.domain().constant_base_field() is not base_valuation.domain().constant_base_field(): + raise ValueError("constant fields must be identical but they differ for %r and %r" % (self.domain(), base_valuation.domain())) + + def restriction(self, ring): + r""" + Return the restriction of this valuation to ``ring``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: K.valuation(1/x).restriction(GF(2)) + Trivial valuation on Finite Field of size 2 + + """ + if ring.is_subring(self.domain().constant_base_field()): + return self._base_valuation.restriction(ring) + return super().restriction(ring) + + +class RationalFunctionFieldMappedValuation(FunctionFieldMappedValuationRelative_base, RationalFunctionFieldValuation_base): + r""" + Valuation on a rational function field that is implemented after a map to + an isomorphic rational function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<x> = QQ[] + sage: w = GaussValuation(R, QQ.valuation(2)).augmentation(x, 1) + sage: w = K.valuation(w) + sage: v = K.valuation((w, K.hom([~K.gen()]), K.hom([~K.gen()]))); v + Valuation on rational function field induced by + [ Gauss valuation induced by 2-adic valuation, v(x) = 1 ] + (in Rational function field in x over Rational Field after x |--> 1/x) + + """ + def __init__(self, parent, base_valuation, to_base_valuation_doain, from_base_valuation_domain): + r""" + TESTS:: + + sage: K.<x> = FunctionField(QQ) + sage: R.<x> = QQ[] + sage: w = GaussValuation(R, QQ.valuation(2)).augmentation(x, 1) + sage: w = K.valuation(w) + sage: v = K.valuation((w, K.hom([~K.gen()]), K.hom([~K.gen()]))) + sage: from sage.rings.function_field.valuation import RationalFunctionFieldMappedValuation + sage: isinstance(v, RationalFunctionFieldMappedValuation) + True + + """ + FunctionFieldMappedValuationRelative_base.__init__(self, parent, base_valuation, to_base_valuation_doain, from_base_valuation_domain) + RationalFunctionFieldValuation_base.__init__(self, parent) + + +class InfiniteRationalFunctionFieldValuation(FunctionFieldMappedValuationRelative_base, RationalFunctionFieldValuation_base, ClassicalFunctionFieldValuation_base): + r""" + Valuation of the infinite place of a function field. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(1/x) # indirect doctest + + """ + def __init__(self, parent): + r""" + TESTS:: + + sage: K.<x> = FunctionField(QQ) + sage: v = K.valuation(1/x) # indirect doctest + sage: from sage.rings.function_field.valuation import InfiniteRationalFunctionFieldValuation + sage: isinstance(v, InfiniteRationalFunctionFieldValuation) + True + + """ + x = parent.domain().gen() + FunctionFieldMappedValuationRelative_base.__init__(self, parent, FunctionFieldValuation(parent.domain(), x), parent.domain().hom([1/x]), parent.domain().hom([1/x])) + RationalFunctionFieldValuation_base.__init__(self, parent) + ClassicalFunctionFieldValuation_base.__init__(self, parent) + + def _repr_(self): + r""" + Return a printable representation of this valuation. + + EXAMPLES:: + + sage: K.<x> = FunctionField(QQ) + sage: K.valuation(1/x) # indirect doctest + Valuation at the infinite place + + """ + return "Valuation at the infinite place" + + +class FunctionFieldExtensionMappedValuation(FunctionFieldMappedValuationRelative_base): + r""" + A valuation on a finite extensions of function fields `L=K[y]/(G)` where `K` is + another function field which redirects to another ``base_valuation`` on an + isomorphism function field `M=K[y]/(H)`. + + The isomorphisms must be trivial on ``K``. + + EXAMPLES:: + + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 + y + x^3) # needs sage.rings.function_field + sage: v = K.valuation(1/x) + sage: w = v.extension(L) # needs sage.rings.function_field + + sage: w(x) # needs sage.rings.function_field + -1 + sage: w(y) # needs sage.rings.function_field + -3/2 + sage: w.uniformizer() # needs sage.rings.function_field + 1/x^2*y + + TESTS:: + + sage: from sage.rings.function_field.valuation import FunctionFieldExtensionMappedValuation + sage: isinstance(w, FunctionFieldExtensionMappedValuation) # needs sage.rings.function_field + True + + """ + def _repr_(self): + r""" + Return a printable representation of this valuation. + + EXAMPLES:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 + y + x^3) + sage: v = K.valuation(1/x) + sage: w = v.extension(L); w + Valuation at the infinite place + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(QQ) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 - 1/x^2 - 1) + sage: v = K.valuation(1/x) + sage: w = v.extensions(L); w + [[ Valuation at the infinite place, v(y + 1) = 2 ]-adic valuation, + [ Valuation at the infinite place, v(y - 1) = 2 ]-adic valuation] + + """ + assert(self.domain().base() is not self.domain()) + if repr(self._base_valuation) == repr(self.restriction(self.domain().base())): + return repr(self._base_valuation) + return super()._repr_() + + def restriction(self, ring): + r""" + Return the restriction of this valuation to ``ring``. + + EXAMPLES:: + + sage: # needs sage.rings.function_field + sage: K.<x> = FunctionField(GF(2)) + sage: R.<y> = K[] + sage: L.<y> = K.extension(y^2 + y + x^3) + sage: v = K.valuation(1/x) + sage: w = v.extension(L) + sage: w.restriction(K) is v + True + """ + if ring.is_subring(self.domain().base()): + return self._base_valuation.restriction(ring) + return super().restriction(ring) diff --git a/src/sage/rings/function_field/valuation_ring.py b/src/sage/rings/function_field/valuation_ring.py index bb3a39c687a..b9ab7d50fb9 100644 --- a/src/sage/rings/function_field/valuation_ring.py +++ b/src/sage/rings/function_field/valuation_ring.py @@ -1,3 +1,5 @@ +# sage.doctest: optional - sage.rings.finite_rings +# sage.doctest: optional - sage.rings.function_field r""" Valuation rings of function fields @@ -53,8 +55,9 @@ - Kwankyu Lee (2017-04-30): initial version """ + # **************************************************************************** -# Copyright (C) 2016 Kwankyu Lee <ekwankyu@gmail.com> +# Copyright (C) 2016-2019 Kwankyu Lee <ekwankyu@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of diff --git a/src/sage/rings/homset.py b/src/sage/rings/homset.py index 6f7a2d4b415..0e500de2608 100644 --- a/src/sage/rings/homset.py +++ b/src/sage/rings/homset.py @@ -28,15 +28,15 @@ def is_RingHomset(H): True sage: is_RH(ZZ) False - sage: is_RH(Hom(RR, CC)) + sage: is_RH(Hom(RR, CC)) # needs sage.rings.real_mpfr True - sage: is_RH(Hom(FreeModule(ZZ,1), FreeModule(QQ,1))) + sage: is_RH(Hom(FreeModule(ZZ,1), FreeModule(QQ,1))) # needs sage.modules False """ return isinstance(H, RingHomset_generic) -def RingHomset(R, S, category = None): +def RingHomset(R, S, category=None): """ Construct a space of homomorphisms between the rings ``R`` and ``S``. @@ -51,8 +51,8 @@ def RingHomset(R, S, category = None): if quotient_ring.is_QuotientRing(R): from .polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing if not is_PolynomialQuotientRing(R): # backwards compatibility - return RingHomset_quo_ring(R, S, category = category) - return RingHomset_generic(R, S, category = category) + return RingHomset_quo_ring(R, S, category=category) + return RingHomset_generic(R, S, category=category) class RingHomset_generic(HomsetWithBase): @@ -69,7 +69,7 @@ class RingHomset_generic(HomsetWithBase): Element = morphism.RingHomomorphism - def __init__(self, R, S, category = None): + def __init__(self, R, S, category=None): """ Initialize ``self``. @@ -91,7 +91,7 @@ def _repr_(self): sage: Hom(ZZ, QQ) # indirect doctest Set of Homomorphisms from Integer Ring to Rational Field """ - return "Set of Homomorphisms from %s to %s"%(self.domain(), self.codomain()) + return "Set of Homomorphisms from %s to %s" % (self.domain(), self.codomain()) def has_coerce_map_from(self, x): """ @@ -133,25 +133,27 @@ def _element_constructor_(self, x, check=True, base_map=None): You can provide a morphism on the base:: + sage: # needs sage.rings.finite_rings sage: k = GF(9) sage: z2 = k.gen() sage: cc = k.frobenius_endomorphism() sage: R.<x> = k[] sage: H = Hom(R, R) sage: phi = H([x^2], base_map=cc); phi - Ring endomorphism of Univariate Polynomial Ring in x over Finite Field in z2 of size 3^2 + Ring endomorphism of Univariate Polynomial Ring in x + over Finite Field in z2 of size 3^2 Defn: x |--> x^2 with map of base ring - sage: phi(z2*x) == z2^3 * x^2 + sage: phi(z2 * x) == z2^3 * x^2 True sage: R.<x> = ZZ[] - sage: K.<a> = GF(7^2) - sage: L.<u> = K.extension(x^3 - 3) - sage: phi = L.hom([u^7], base_map=K.frobenius_endomorphism()) - sage: phi(u) == u^7 + sage: K.<a> = GF(7^2) # needs sage.rings.finite_rings + sage: L.<u> = K.extension(x^3 - 3) # needs sage.rings.finite_rings + sage: phi = L.hom([u^7], base_map=K.frobenius_endomorphism()) # needs sage.rings.finite_rings + sage: phi(u) == u^7 # needs sage.rings.finite_rings True - sage: phi(a) == a^7 + sage: phi(a) == a^7 # needs sage.rings.finite_rings True TESTS:: @@ -210,7 +212,7 @@ def natural_map(self): """ f = self.codomain().coerce_map_from(self.domain()) if f is None: - raise TypeError("natural coercion morphism from %s to %s not defined"%(self.domain(), self.codomain())) + raise TypeError("natural coercion morphism from %s to %s not defined" % (self.domain(), self.codomain())) return f def zero(self): @@ -247,14 +249,15 @@ class RingHomset_quo_ring(RingHomset_generic): EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ, 2) - sage: S.<a,b> = R.quotient(x^2 + y^2) - sage: phi = S.hom([b,a]); phi - Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) + sage: S.<a,b> = R.quotient(x^2 + y^2) # needs sage.libs.singular + sage: phi = S.hom([b,a]); phi # needs sage.libs.singular + Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y + over Rational Field by the ideal (x^2 + y^2) Defn: a |--> b b |--> a - sage: phi(a) + sage: phi(a) # needs sage.libs.singular b - sage: phi(b) + sage: phi(b) # needs sage.libs.singular a TESTS: @@ -263,6 +266,7 @@ class RingHomset_quo_ring(RingHomset_generic): :: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S.<a,b> = R.quotient(x^2 + y^2) sage: H = S.Hom(R) @@ -271,8 +275,8 @@ class RingHomset_quo_ring(RingHomset_generic): We test pickling of actual homomorphisms in a quotient:: - sage: phi = S.hom([b,a]) - sage: phi == loads(dumps(phi)) + sage: phi = S.hom([b,a]) # needs sage.libs.singular + sage: phi == loads(dumps(phi)) # needs sage.libs.singular True """ @@ -284,6 +288,7 @@ def _element_constructor_(self, x, base_map=None, check=True): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S.<a,b> = R.quotient(x^2 + y^2) sage: H = S.Hom(R) diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 8c51c69a9ae..d36d9406f32 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -126,7 +126,7 @@ def Ideal(*args, **kwds): even if they are PIDs.:: sage: R.<x> = GF(5)[] - sage: I = R*(x^2+3) + sage: I = R * (x^2 + 3) sage: type(I) <class 'sage.rings.polynomial.ideal.Ideal_1poly_field'> @@ -163,11 +163,11 @@ def Ideal(*args, **kwds): sage: J = R.ideal([2*x + 2*x^2]) sage: J Principal ideal (x^2 + x) of Univariate Polynomial Ring in x over Rational Field - sage: S = R.quotient_ring(I) - sage: U = R.quotient_ring(J) + sage: S = R.quotient_ring(I) # needs sage.libs.pari + sage: U = R.quotient_ring(J) # needs sage.libs.pari sage: I == J True - sage: S == U + sage: S == U # needs sage.libs.pari True """ if len(args) == 0: @@ -295,8 +295,8 @@ def _repr_short(self): the generators are not represented from left to right but from top to bottom. This is the case, e.g., for matrices:: - sage: MS = MatrixSpace(QQ,2,2) - sage: MS*[MS.1,2] + sage: MS = MatrixSpace(QQ, 2, 2) # needs sage.modules + sage: MS * [MS.1, 2] # needs sage.modules Left Ideal ( [0 1] @@ -316,8 +316,8 @@ def _repr_short(self): s = s.replace('\n','\n ') L.append(s) if has_return: - return '\n(\n %s\n)\n'%(',\n\n '.join(L)) - return '(%s)'%(', '.join(L)) + return '\n(\n %s\n)\n' % (',\n\n '.join(L)) + return '(%s)' % (', '.join(L)) def __repr__(self): """ @@ -329,7 +329,7 @@ def __repr__(self): sage: P*[a^2,a*b+c,c^3] # indirect doctest Ideal (a^2, a*b + c, c^3) of Multivariate Polynomial Ring in a, b, c over Rational Field """ - return "Ideal %s of %s"%(self._repr_short(), self.ring()) + return "Ideal %s of %s" % (self._repr_short(), self.ring()) def random_element(self, *args, **kwds): """ @@ -376,8 +376,8 @@ def __contains__(self, x): EXAMPLES:: sage: P.<a,b,c> = QQ[] - sage: I = P*[a, b] - sage: a + b in I + sage: I = P * [a, b] + sage: a + b in I # needs sage.libs.singular True sage: P2.<w,x,y,z> = QQ[] sage: x + 2*y + w*z in I @@ -470,11 +470,11 @@ def base_ring(self): And `p`-adic numbers:: - sage: R = Zp(7, prec=10); R + sage: R = Zp(7, prec=10); R # needs sage.rings.padics 7-adic Ring with capped relative precision 10 - sage: I = 7*R; I + sage: I = 7*R; I # needs sage.rings.padics Principal ideal (7 + O(7^11)) of 7-adic Ring with capped relative precision 10 - sage: I.base_ring() + sage: I.base_ring() # needs sage.rings.padics 7-adic Ring with capped relative precision 10 """ return self.ring().base_ring() @@ -486,13 +486,17 @@ def apply_morphism(self, phi): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: psi = CC['x'].hom([-CC['x'].0]) sage: J = ideal([CC['x'].0 + 1]); J - Principal ideal (x + 1.00000000000000) of Univariate Polynomial Ring in x over Complex Field with 53 bits of precision + Principal ideal (x + 1.00000000000000) of Univariate Polynomial Ring in x + over Complex Field with 53 bits of precision sage: psi(J) - Principal ideal (x - 1.00000000000000) of Univariate Polynomial Ring in x over Complex Field with 53 bits of precision + Principal ideal (x - 1.00000000000000) of Univariate Polynomial Ring in x + over Complex Field with 53 bits of precision sage: J.apply_morphism(psi) - Principal ideal (x - 1.00000000000000) of Univariate Polynomial Ring in x over Complex Field with 53 bits of precision + Principal ideal (x - 1.00000000000000) of Univariate Polynomial Ring in x + over Complex Field with 53 bits of precision :: @@ -506,6 +510,8 @@ def apply_morphism(self, phi): TESTS:: + sage: # needs sage.rings.number_fields + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^2 + 1) sage: A = K.ideal(a) sage: taus = K.embeddings(K) @@ -518,6 +524,7 @@ def apply_morphism(self, phi): :: + sage: # needs sage.rings.number_fields sage: K.<a> = NumberField(x^2 + 5) sage: B = K.ideal([2, a + 1]); B Fractional ideal (2, a + 1) @@ -527,9 +534,9 @@ def apply_morphism(self, phi): Since 2 is totally ramified, complex conjugation fixes it:: - sage: B.apply_morphism(taus[1]) # complex conjugation + sage: B.apply_morphism(taus[1]) # complex conjugation # needs sage.rings.number_fields Fractional ideal (2, a + 1) - sage: taus[1](B) + sage: taus[1](B) # needs sage.rings.number_fields Fractional ideal (2, a + 1) """ from sage.categories.morphism import is_Morphism @@ -585,12 +592,14 @@ def ring(self): sage: I = R.ideal(x^2 - 3) sage: I.ring() Univariate Polynomial Ring in x over Rational Field - sage: Rbar = R.quotient(I, names='a') - sage: S = PolynomialRing(Rbar, 'y'); y = Rbar.gen(); S - Univariate Polynomial Ring in y over Univariate Quotient Polynomial Ring in a over Rational Field with modulus x^2 - 3 - sage: J = S.ideal(y^2 + 1) - sage: J.ring() - Univariate Polynomial Ring in y over Univariate Quotient Polynomial Ring in a over Rational Field with modulus x^2 - 3 + sage: Rbar = R.quotient(I, names='a') # needs sage.libs.pari + sage: S = PolynomialRing(Rbar, 'y'); y = Rbar.gen(); S # needs sage.libs.pari + Univariate Polynomial Ring in y over + Univariate Quotient Polynomial Ring in a over Rational Field with modulus x^2 - 3 + sage: J = S.ideal(y^2 + 1) # needs sage.libs.pari + sage: J.ring() # needs sage.libs.pari + Univariate Polynomial Ring in y over + Univariate Quotient Polynomial Ring in a over Rational Field with modulus x^2 - 3 """ return self.__ring @@ -738,28 +747,29 @@ def is_primary(self, P=None): sage: R.<x, y> = QQ[] sage: I = R.ideal([x^2, x*y]) - sage: I.is_primary() + sage: I.is_primary() # needs sage.libs.singular False - sage: J = I.primary_decomposition()[1]; J + sage: J = I.primary_decomposition()[1]; J # needs sage.libs.singular Ideal (y, x^2) of Multivariate Polynomial Ring in x, y over Rational Field - sage: J.is_primary() + sage: J.is_primary() # needs sage.libs.singular True - sage: J.is_prime() + sage: J.is_prime() # needs sage.libs.singular False Some examples from the Macaulay2 documentation:: + sage: # needs sage.rings.finite_rings sage: R.<x, y, z> = GF(101)[] sage: I = R.ideal([y^6]) - sage: I.is_primary() + sage: I.is_primary() # needs sage.libs.singular True - sage: I.is_primary(R.ideal([y])) + sage: I.is_primary(R.ideal([y])) # needs sage.libs.singular True sage: I = R.ideal([x^4, y^7]) - sage: I.is_primary() + sage: I.is_primary() # needs sage.libs.singular True sage: I = R.ideal([x*y, y^2]) - sage: I.is_primary() + sage: I.is_primary() # needs sage.libs.singular False .. NOTE:: @@ -798,16 +808,16 @@ def is_prime(self): sage: R.<x, y> = QQ[] sage: I = R.ideal([x, y]) - sage: I.is_prime() # a maximal ideal + sage: I.is_prime() # a maximal ideal # needs sage.libs.singular True - sage: I = R.ideal([x^2-y]) - sage: I.is_prime() # a non-maximal prime ideal + sage: I = R.ideal([x^2 - y]) + sage: I.is_prime() # a non-maximal prime ideal # needs sage.libs.singular True sage: I = R.ideal([x^2, y]) - sage: I.is_prime() # a non-prime primary ideal + sage: I.is_prime() # a non-prime primary ideal # needs sage.libs.singular False sage: I = R.ideal([x^2, x*y]) - sage: I.is_prime() # a non-prime non-primary ideal + sage: I.is_prime() # a non-prime non-primary ideal # needs sage.libs.singular False sage: S = Integers(8) @@ -886,7 +896,7 @@ def embedded_primes(self): sage: R.<x, y> = QQ[] sage: I = R.ideal(x^2, x*y) - sage: I.embedded_primes() + sage: I.embedded_primes() # needs sage.libs.singular [Ideal (y, x) of Multivariate Polynomial Ring in x, y over Rational Field] """ # by definition, embedded primes are associated primes that @@ -915,13 +925,13 @@ def is_principal(self): EXAMPLES:: - sage: R = ZZ['x'] - sage: I = R.ideal(2,x) + sage: R.<x> = ZZ[] + sage: I = R.ideal(2, x) sage: I.is_principal() Traceback (most recent call last): ... NotImplementedError - sage: J = R.base_extend(QQ).ideal(2,x) + sage: J = R.base_extend(QQ).ideal(2, x) sage: J.is_principal() True """ @@ -954,20 +964,20 @@ def is_trivial(self): :: sage: I = QQ['x', 'y'].ideal(-5) - sage: I.is_trivial() + sage: I.is_trivial() # needs sage.libs.singular True :: - sage: I = CC['x'].ideal(0) - sage: I.is_trivial() + sage: I = CC['x'].ideal(0) # needs sage.rings.real_mpfr + sage: I.is_trivial() # needs sage.rings.real_mpfr True This test addresses issue :trac:`20514`:: sage: R = QQ['x', 'y'] sage: I = R.ideal(R.gens()) - sage: I.is_trivial() + sage: I.is_trivial() # needs sage.libs.singular False """ return self.is_zero() or self == self.ring().unit_ideal() @@ -1112,10 +1122,11 @@ def norm(self): EXAMPLES:: - sage: R.<t> = GF(8, names='a')[] - sage: I = R.ideal(t^4 + t + 1) - sage: I.norm() - Principal ideal (t^4 + t + 1) of Univariate Polynomial Ring in t over Finite Field in a of size 2^3 + sage: R.<t> = GF(8, names='a')[] # needs sage.rings.finite_rings + sage: I = R.ideal(t^4 + t + 1) # needs sage.rings.finite_rings + sage: I.norm() # needs sage.rings.finite_rings + Principal ideal (t^4 + t + 1) of Univariate Polynomial Ring in t + over Finite Field in a of size 2^3 """ return self @@ -1135,9 +1146,9 @@ def absolute_norm(self): EXAMPLES:: - sage: R.<t> = GF(9, names='a')[] - sage: I = R.ideal(t^4 + t + 1) - sage: I.absolute_norm() + sage: R.<t> = GF(9, names='a')[] # needs sage.rings.finite_rings + sage: I = R.ideal(t^4 + t + 1) # needs sage.rings.finite_rings + sage: I.absolute_norm() # needs sage.rings.finite_rings Traceback (most recent call last): ... NotImplementedError @@ -1155,7 +1166,7 @@ def _macaulay2_init_(self, macaulay2=None): sage: R.<x,y,z,w> = PolynomialRing(ZZ, 4) sage: I = R.ideal([x*y-z^2, y^2-w^2]); I Ideal (x*y - z^2, y^2 - w^2) of Multivariate Polynomial Ring in x, y, z, w over Integer Ring - sage: macaulay2(I) # optional - macaulay2 + sage: macaulay2(I) # optional - macaulay2 2 2 2 ideal (x*y - z , y - w ) @@ -1164,7 +1175,7 @@ def _macaulay2_init_(self, macaulay2=None): sage: R.<x> = PolynomialRing(ZZ) sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]); I Ideal (x^2 + 3*x + 4, x^2 + 1) of Univariate Polynomial Ring in x over Integer Ring - sage: macaulay2(I) # optional - macaulay2 + sage: macaulay2(I) # optional - macaulay2 2 2 ideal (x + 3x + 4, x + 1) @@ -1173,19 +1184,19 @@ def _macaulay2_init_(self, macaulay2=None): sage: P.<x,y> = PolynomialRing(GF(2), 2) sage: I = sage.rings.ideal.FieldIdeal(P); I - Ideal (x^2 + x, y^2 + y) of Multivariate Polynomial Ring in x, y over - Finite Field of size 2 - sage: macaulay2(I) # optional - macaulay2 + Ideal (x^2 + x, y^2 + y) of Multivariate Polynomial Ring in x, y + over Finite Field of size 2 + sage: macaulay2(I) # optional - macaulay2 # needs sage.rings.finite_rings 2 2 ideal (x + x, y + y) Ideals in PIDs:: - sage: macaulay2(ideal(5)) # optional - macaulay2 + sage: macaulay2(ideal(5)) # optional - macaulay2 ideal 5 sage: J = ideal(QQ(5)) ... - sage: macaulay2(J) # optional - macaulay2 + sage: macaulay2(J) # optional - macaulay2 ideal 1 TESTS: @@ -1222,7 +1233,7 @@ def free_resolution(self, *args, **kwds): sage: R.<x> = PolynomialRing(QQ) sage: I = R.ideal([x^4 + 3*x^2 + 2]) - sage: I.free_resolution() + sage: I.free_resolution() # needs sage.modules S^1 <-- S^1 <-- 0 """ if not self.is_principal(): @@ -1241,7 +1252,7 @@ def graded_free_resolution(self, *args, **kwds): sage: R.<x> = PolynomialRing(QQ) sage: I = R.ideal([x^3]) - sage: I.graded_free_resolution() + sage: I.graded_free_resolution() # needs sage.modules S(0) <-- S(-3) <-- 0 """ from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module @@ -1269,7 +1280,7 @@ def __repr__(self): sage: I # indirect doctest Principal ideal (x) of Univariate Polynomial Ring in x over Integer Ring """ - return "Principal ideal (%s) of %s"%(self.gen(), self.ring()) + return "Principal ideal (%s) of %s" % (self.gen(), self.ring()) def is_principal(self): r""" @@ -1577,9 +1588,9 @@ def is_prime(self): sage: ZZ.ideal(0).is_prime() True sage: R.<x> = QQ[] - sage: P = R.ideal(x^2+1); P + sage: P = R.ideal(x^2 + 1); P Principal ideal (x^2 + 1) of Univariate Polynomial Ring in x over Rational Field - sage: P.is_prime() + sage: P.is_prime() # needs sage.libs.pari True In fields, only the zero ideal is prime:: @@ -1609,6 +1620,7 @@ def is_maximal(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(5)[] sage: p = R.ideal(t^2 + 2) sage: p.is_maximal() @@ -1638,6 +1650,7 @@ def residue_field(self): EXAMPLES:: + sage: # needs sage.libs.pari sage: P = ZZ.ideal(61); P Principal ideal (61) of Integer Ring sage: F = P.residue_field(); F @@ -1670,9 +1683,9 @@ def residue_field(self): :: - sage: R.<x>=QQ[] - sage: I=R.ideal(x^2+1) - sage: I.is_prime() + sage: R.<x> = QQ[] + sage: I = R.ideal(x^2 + 1) + sage: I.is_prime() # needs sage.libs.pari True sage: I.residue_field() Traceback (most recent call last): @@ -1680,10 +1693,10 @@ def residue_field(self): TypeError: residue fields only supported for polynomial rings over finite fields. """ if not self.is_prime(): - raise ValueError("The ideal (%s) is not prime"%self) + raise ValueError("The ideal (%s) is not prime" % self) from sage.rings.integer_ring import ZZ if self.ring() is ZZ: - return ZZ.residue_field(self, check = False) + return ZZ.residue_field(self, check=False) raise NotImplementedError("residue_field() is only implemented for ZZ and rings of integers of number fields.") class Ideal_fractional(Ideal_generic): @@ -1699,11 +1712,12 @@ def __repr__(self): EXAMPLES:: sage: from sage.rings.ideal import Ideal_fractional - sage: K.<a> = NumberField(x^2 + 1) - sage: Ideal_fractional(K, [a]) # indirect doctest + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 1) # needs sage.rings.number_field + sage: Ideal_fractional(K, [a]) # indirect doctest # needs sage.rings.number_field Fractional ideal (a) of Number Field in a with defining polynomial x^2 + 1 """ - return "Fractional ideal %s of %s"%(self._repr_short(), self.ring()) + return "Fractional ideal %s of %s" % (self._repr_short(), self.ring()) # constructors for standard (benchmark) ideals, written uppercase as # these are constructors @@ -1735,21 +1749,20 @@ def Cyclic(R, n=None, homog=False, singular=None): An example from a multivariate polynomial ring over the rationals:: - sage: P.<x,y,z> = PolynomialRing(QQ,3,order='lex') - sage: I = sage.rings.ideal.Cyclic(P) - sage: I - Ideal (x + y + z, x*y + x*z + y*z, x*y*z - 1) of Multivariate Polynomial - Ring in x, y, z over Rational Field - sage: I.groebner_basis() + sage: P.<x,y,z> = PolynomialRing(QQ, 3, order='lex') + sage: I = sage.rings.ideal.Cyclic(P); I # needs sage.libs.singular + Ideal (x + y + z, x*y + x*z + y*z, x*y*z - 1) + of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: I.groebner_basis() # needs sage.libs.singular [x + y + z, y^2 + y*z + z^2, z^3 - 1] We compute a Groebner basis for cyclic 6, which is a standard benchmark and test ideal:: sage: R.<x,y,z,t,u,v> = QQ['x,y,z,t,u,v'] - sage: I = sage.rings.ideal.Cyclic(R,6) - sage: B = I.groebner_basis() - sage: len(B) + sage: I = sage.rings.ideal.Cyclic(R, 6) # needs sage.libs.singular + sage: B = I.groebner_basis() # needs sage.libs.singular + sage: len(B) # needs sage.libs.singular 45 """ from .rational_field import RationalField @@ -1794,15 +1807,15 @@ def Katsura(R, n=None, homog=False, singular=None): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(QQ,3) - sage: I = sage.rings.ideal.Katsura(P,3); I + sage: P.<x,y,z> = PolynomialRing(QQ, 3) + sage: I = sage.rings.ideal.Katsura(P, 3); I # needs sage.libs.singular Ideal (x + 2*y + 2*z - 1, x^2 + 2*y^2 + 2*z^2 - x, 2*x*y + 2*y*z - y) of Multivariate Polynomial Ring in x, y, z over Rational Field :: - sage: Q.<x> = PolynomialRing(QQ, implementation="singular") - sage: J = sage.rings.ideal.Katsura(Q,1); J + sage: Q.<x> = PolynomialRing(QQ, implementation="singular") # needs sage.libs.singular + sage: J = sage.rings.ideal.Katsura(Q,1); J # needs sage.libs.singular Ideal (x - 1) of Multivariate Polynomial Ring in x over Rational Field """ from .rational_field import RationalField @@ -1842,18 +1855,18 @@ def FieldIdeal(R): The field ideal generated from the polynomial ring over two variables in the finite field of size 2:: - sage: P.<x,y> = PolynomialRing(GF(2),2) + sage: P.<x,y> = PolynomialRing(GF(2), 2) sage: I = sage.rings.ideal.FieldIdeal(P); I - Ideal (x^2 + x, y^2 + y) of Multivariate Polynomial Ring in x, y over - Finite Field of size 2 + Ideal (x^2 + x, y^2 + y) of + Multivariate Polynomial Ring in x, y over Finite Field of size 2 Another, similar example:: - sage: Q.<x1,x2,x3,x4> = PolynomialRing(GF(2^4,name='alpha'), 4) - sage: J = sage.rings.ideal.FieldIdeal(Q); J + sage: Q.<x1,x2,x3,x4> = PolynomialRing(GF(2^4, name='alpha'), 4) # needs sage.rings.finite_rings + sage: J = sage.rings.ideal.FieldIdeal(Q); J # needs sage.rings.finite_rings Ideal (x1^16 + x1, x2^16 + x2, x3^16 + x3, x4^16 + x4) of - Multivariate Polynomial Ring in x1, x2, x3, x4 over Finite - Field in alpha of size 2^4 + Multivariate Polynomial Ring in x1, x2, x3, x4 + over Finite Field in alpha of size 2^4 """ q = R.base_ring().order() import sage.rings.infinity diff --git a/src/sage/rings/ideal_monoid.py b/src/sage/rings/ideal_monoid.py index b22b7208f6f..0988ffc72e5 100644 --- a/src/sage/rings/ideal_monoid.py +++ b/src/sage/rings/ideal_monoid.py @@ -3,8 +3,8 @@ WARNING: This is used by some rings that are not commutative! :: - sage: MS = MatrixSpace(QQ,3,3) - sage: type(MS.ideal(MS.one()).parent()) + sage: MS = MatrixSpace(QQ, 3, 3) # needs sage.modules + sage: type(MS.ideal(MS.one()).parent()) # needs sage.modules <class 'sage.rings.ideal_monoid.IdealMonoid_c_with_category'> """ @@ -21,7 +21,8 @@ def IdealMonoid(R): EXAMPLES:: sage: R = QQ['x'] - sage: sage.rings.ideal_monoid.IdealMonoid(R) + sage: from sage.rings.ideal_monoid import IdealMonoid + sage: IdealMonoid(R) Monoid of ideals of Univariate Polynomial Ring in x over Rational Field """ return IdealMonoid_c(R) @@ -34,7 +35,8 @@ class IdealMonoid_c(Parent): TESTS:: sage: R = QQ['x'] - sage: M = sage.rings.ideal_monoid.IdealMonoid(R) + sage: from sage.rings.ideal_monoid import IdealMonoid + sage: M = IdealMonoid(R) sage: TestSuite(M).run() Failure in _test_category: ... @@ -51,16 +53,18 @@ def __init__(self, R): TESTS:: - sage: R = QuadraticField(-23, 'a') - sage: M = sage.rings.ideal_monoid.IdealMonoid(R); M # indirect doctest - Monoid of ideals of Number Field in a with defining polynomial x^2 + 23 with a = 4.795831523312720?*I + sage: R = QuadraticField(-23, 'a') # needs sage.rings.number_field + sage: from sage.rings.ideal_monoid import IdealMonoid + sage: M = IdealMonoid(R); M # indirect doctest # needs sage.rings.number_field + Monoid of ideals of Number Field in a with defining polynomial x^2 + 23 + with a = 4.795831523312720?*I sage: id = QQ.ideal(6) sage: id.parent().category() Category of commutative monoids - sage: MS = MatrixSpace(QQ,3,3) - sage: MS.ideal(MS.one()).parent().category() + sage: MS = MatrixSpace(QQ, 3, 3) # needs sage.modules + sage: MS.ideal(MS.one()).parent().category() # needs sage.modules Category of monoids """ self.__R = R @@ -77,9 +81,11 @@ def _repr_(self): TESTS:: - sage: R = QuadraticField(-23, 'a') - sage: M = sage.rings.ideal_monoid.IdealMonoid(R); M._repr_() - 'Monoid of ideals of Number Field in a with defining polynomial x^2 + 23 with a = 4.795831523312720?*I' + sage: R = QuadraticField(-23, 'a') # needs sage.rings.number_field + sage: from sage.rings.ideal_monoid import IdealMonoid + sage: M = IdealMonoid(R); M._repr_() # needs sage.rings.number_field + 'Monoid of ideals of Number Field in a with defining polynomial x^2 + 23 + with a = 4.795831523312720?*I' """ return "Monoid of ideals of %s" % self.__R @@ -89,8 +95,9 @@ def ring(self): EXAMPLES:: - sage: R = QuadraticField(-23, 'a') - sage: M = sage.rings.ideal_monoid.IdealMonoid(R); M.ring() is R + sage: R = QuadraticField(-23, 'a') # needs sage.rings.number_field + sage: from sage.rings.ideal_monoid import IdealMonoid + sage: M = IdealMonoid(R); M.ring() is R # needs sage.rings.number_field True """ return self.__R @@ -101,8 +108,10 @@ def _element_constructor_(self, x): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<a> = QuadraticField(-23) - sage: M = sage.rings.ideal_monoid.IdealMonoid(R) + sage: from sage.rings.ideal_monoid import IdealMonoid + sage: M = IdealMonoid(R) sage: M(a) # indirect doctest Fractional ideal (a) sage: M([a-4, 13]) @@ -129,6 +138,7 @@ def _coerce_map_from_(self, x): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R = QuadraticField(-23, 'a') sage: M = R.ideal_monoid() sage: M.has_coerce_map_from(R) # indirect doctest @@ -151,6 +161,7 @@ def __eq__(self, other): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R = QuadraticField(-23, 'a') sage: M = R.ideal_monoid() sage: M == QQ @@ -171,6 +182,7 @@ def __ne__(self, other): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R = QuadraticField(-23, 'a') sage: M = R.ideal_monoid() sage: M != QQ @@ -188,6 +200,7 @@ def __hash__(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R = QuadraticField(-23, 'a') sage: M = R.ideal_monoid() sage: hash(M) == hash(QQ) diff --git a/src/sage/rings/infinity.py b/src/sage/rings/infinity.py index 400e1d060c1..c5ab0b24f32 100644 --- a/src/sage/rings/infinity.py +++ b/src/sage/rings/infinity.py @@ -203,8 +203,8 @@ We check that :trac:`17990` is fixed:: - sage: m = Matrix([Infinity]) - sage: m.rows() + sage: m = Matrix([Infinity]) # needs sage.modules + sage: m.rows() # needs sage.modules [(+Infinity)] """ #***************************************************************************** @@ -216,15 +216,17 @@ #***************************************************************************** from sys import maxsize + +import sage.rings.abc + +from sage.misc.fast_methods import Singleton +from sage.misc.lazy_import import lazy_import from sage.rings.ring import Ring from sage.structure.element import RingElement, InfinityElement from sage.structure.richcmp import rich_to_bool, richcmp -from sage.misc.fast_methods import Singleton -import sage.rings.abc -import sage.rings.integer -import sage.rings.rational -import sage.rings.integer_ring +lazy_import('sage.rings.integer', 'Integer') + _obj = {} class _uniq(): @@ -288,7 +290,7 @@ def _maxima_init_(self): """ TESTS:: - sage: maxima(-oo) + sage: maxima(-oo) # needs sage.symbolic minf sage: [x._maxima_init_() for x in [unsigned_infinity, oo, -oo]] ['inf', 'inf', 'minf'] @@ -304,7 +306,7 @@ def _fricas_init_(self): sage: fricas(-oo) # optional - fricas - infinity - sage: [x._fricas_init_() for x in [unsigned_infinity, oo, -oo]] # optional - fricas + sage: [x._fricas_init_() for x in [unsigned_infinity, oo, -oo]] ['%infinity', '%plusInfinity', '%minusInfinity'] sage: [fricas(x) for x in [unsigned_infinity, oo, -oo]] # optional - fricas [infinity, + infinity, - infinity] @@ -322,17 +324,16 @@ def __pari__(self): EXAMPLES:: - sage: pari(-oo) + sage: pari(-oo) # needs sage.libs.pari -oo - sage: pari(oo) + sage: pari(oo) # needs sage.libs.pari +oo """ - # For some reason, it seems problematic to import sage.libs.all.pari, - # so we call it directly. + from sage.libs.pari.all import pari if self._sign >= 0: - return sage.libs.all.pari('oo') + return pari('oo') else: - return sage.libs.all.pari('-oo') + return pari('-oo') def _latex_(self): r""" @@ -378,7 +379,7 @@ def _add_(self, other): Traceback (most recent call last): ... SignError: cannot add unsigned infinities - sage: unsigned_infinity + oo*i + sage: unsigned_infinity + oo*i # needs sage.symbolic Traceback (most recent call last): ... SignError: cannot add unsigned infinities @@ -415,7 +416,7 @@ def _sub_(self, other): Traceback (most recent call last): ... SignError: cannot subtract unsigned infinities - sage: unsigned_infinity - oo*i + sage: unsigned_infinity - oo*i # needs sage.symbolic Traceback (most recent call last): ... SignError: cannot subtract unsigned infinities @@ -471,7 +472,7 @@ def _div_(self, other): Traceback (most recent call last): ... ValueError: unsigned oo times smaller number not defined - sage: SR(infinity) / unsigned_infinity + sage: SR(infinity) / unsigned_infinity # needs sage.symbolic Traceback (most recent call last): ... RuntimeError: indeterminate expression: 0 * infinity encountered. @@ -489,7 +490,7 @@ def __float__(self): +infinity sage: float(infinity) # random +infinity - sage: CDF(infinity) + sage: CDF(infinity) # needs sage.rings.complex_double +infinity sage: infinity.__float__() # random +infinity @@ -498,7 +499,7 @@ def __float__(self): -infinity sage: float(-infinity) # random -inf - sage: CDF(-infinity) + sage: CDF(-infinity) # needs sage.rings.complex_double -infinity sage: (-infinity).__float__() # random -inf @@ -567,8 +568,8 @@ def __init__(self): Sage can understand SymPy's complex infinity (:trac:`17493`):: - sage: import sympy - sage: SR(sympy.zoo) + sage: import sympy # needs sympy + sage: SR(sympy.zoo) # needs sympy Infinity Some equality checks:: @@ -675,7 +676,7 @@ def _element_constructor_(self, x): sage: UnsignedInfinityRing(2) # indirect doctest A number less than infinity - sage: UnsignedInfinityRing(I) + sage: UnsignedInfinityRing(I) # needs sage.rings.number_field A number less than infinity sage: UnsignedInfinityRing(unsigned_infinity) Infinity @@ -683,31 +684,31 @@ def _element_constructor_(self, x): Infinity sage: UnsignedInfinityRing(-oo) Infinity - sage: K.<a> = QuadraticField(3) - sage: UnsignedInfinityRing(a) + sage: K.<a> = QuadraticField(3) # needs sage.rings.number_field + sage: UnsignedInfinityRing(a) # needs sage.rings.number_field A number less than infinity - sage: UnsignedInfinityRing(a - 2) + sage: UnsignedInfinityRing(a - 2) # needs sage.rings.number_field A number less than infinity sage: UnsignedInfinityRing(RDF(oo)), UnsignedInfinityRing(RDF(-oo)) (Infinity, Infinity) sage: UnsignedInfinityRing(RR(oo)), UnsignedInfinityRing(RR(-oo)) (Infinity, Infinity) - sage: UnsignedInfinityRing(CDF(oo)), UnsignedInfinityRing(CDF(-oo)) + sage: UnsignedInfinityRing(CDF(oo)), UnsignedInfinityRing(CDF(-oo)) # needs sage.rings.complex_double (Infinity, Infinity) - sage: UnsignedInfinityRing(CC(oo)), UnsignedInfinityRing(CC(-oo)) + sage: UnsignedInfinityRing(CC(oo)), UnsignedInfinityRing(CC(-oo)) # needs sage.rings.real_mpfr (Infinity, Infinity) - sage: UnsignedInfinityRing(RIF(oo)), UnsignedInfinityRing(RIF(-oo)) + sage: UnsignedInfinityRing(RIF(oo)), UnsignedInfinityRing(RIF(-oo)) # needs sage.rings.real_interval_field (Infinity, Infinity) sage: UnsignedInfinityRing(float('+inf')), UnsignedInfinityRing(float('-inf')) (Infinity, Infinity) - sage: UnsignedInfinityRing(SR(oo)), UnsignedInfinityRing(SR(-oo)) + sage: UnsignedInfinityRing(SR(oo)), UnsignedInfinityRing(SR(-oo)) # needs sage.symbolic (Infinity, Infinity) The following rings have a ``is_infinity`` method:: sage: RR(oo).is_infinity() True - sage: SR(oo).is_infinity() + sage: SR(oo).is_infinity() # needs sage.symbolic True """ # Lazy elements can wrap infinity or not, unwrap first @@ -745,19 +746,19 @@ def _coerce_map_from_(self, R): sage: UnsignedInfinityRing.has_coerce_map_from(int) # indirect doctest True - sage: UnsignedInfinityRing.has_coerce_map_from(CC) + sage: UnsignedInfinityRing.has_coerce_map_from(CC) # needs sage.rings.real_mpfr True - sage: UnsignedInfinityRing.has_coerce_map_from(QuadraticField(-163, 'a')) + sage: UnsignedInfinityRing.has_coerce_map_from(QuadraticField(-163, 'a')) # needs sage.rings.number_field True - sage: UnsignedInfinityRing.has_coerce_map_from(QQ^3) + sage: UnsignedInfinityRing.has_coerce_map_from(QQ^3) # needs sage.modules False - sage: UnsignedInfinityRing.has_coerce_map_from(SymmetricGroup(13)) + sage: UnsignedInfinityRing.has_coerce_map_from(SymmetricGroup(13)) # needs sage.groups False """ return isinstance(R, Ring) or R in (int, float, complex) -UnsignedInfinityRing = UnsignedInfinityRing_class() +UnsignedInfinityRing = UnsignedInfinityRing_class() class LessThanInfinity(_uniq, RingElement): @@ -851,7 +852,7 @@ def _div_(self, other): 0 """ if isinstance(other, UnsignedInfinity): - return sage.rings.integer_ring.ZZ(0) + return Integer(0) raise ValueError("quotient of number < oo by number < oo not defined") def _richcmp_(self, other, op): @@ -942,12 +943,12 @@ def _sympy_(self): EXAMPLES:: - sage: import sympy - sage: SR(unsigned_infinity)._sympy_() + sage: import sympy # needs sympy + sage: SR(unsigned_infinity)._sympy_() # needs sympy zoo - sage: gamma(-3)._sympy_() is sympy.factorial(-2) + sage: gamma(-3)._sympy_() is sympy.factorial(-2) # needs sympy True - sage: gamma(-3) is sympy.factorial(-2)._sage_() + sage: gamma(-3) is sympy.factorial(-2)._sage_() # needs sympy True """ import sympy @@ -966,10 +967,12 @@ def _richcmp_(self, other, op): return rich_to_bool(op, 1) return rich_to_bool(op, 0) + unsigned_infinity = UnsignedInfinityRing.gen(0) less_than_infinity = UnsignedInfinityRing.less_than_infinity() -def is_Infinite(x): + +def is_Infinite(x) -> bool: """ This is a type check for infinity elements. @@ -1082,7 +1085,7 @@ def gens(self): """ return [self.gen(0), self.gen(1)] - def is_zero(self): + def is_zero(self) -> bool: """ The Infinity Ring is not zero @@ -1093,7 +1096,7 @@ def is_zero(self): """ return False - def is_commutative(self): + def is_commutative(self) -> bool: """ The Infinity Ring is commutative @@ -1128,21 +1131,22 @@ def _element_constructor_(self, x): sage: InfinityRing(-1.5) A negative finite number sage: [InfinityRing(a) for a in [-2..2]] - [A negative finite number, A negative finite number, Zero, A positive finite number, A positive finite number] - sage: K.<a> = QuadraticField(3) - sage: InfinityRing(a) + [A negative finite number, A negative finite number, Zero, + A positive finite number, A positive finite number] + sage: K.<a> = QuadraticField(3) # needs sage.rings.number_field + sage: InfinityRing(a) # needs sage.rings.number_field A positive finite number - sage: InfinityRing(a - 2) + sage: InfinityRing(a - 2) # needs sage.rings.number_field A negative finite number sage: InfinityRing(RDF(oo)), InfinityRing(RDF(-oo)) (+Infinity, -Infinity) sage: InfinityRing(RR(oo)), InfinityRing(RR(-oo)) (+Infinity, -Infinity) - sage: InfinityRing(RIF(oo)), InfinityRing(RIF(-oo)) + sage: InfinityRing(RIF(oo)), InfinityRing(RIF(-oo)) # needs sage.rings.real_interval_field (+Infinity, -Infinity) sage: InfinityRing(float('+inf')), InfinityRing(float('-inf')) (+Infinity, -Infinity) - sage: InfinityRing(SR(oo)), InfinityRing(SR(-oo)) + sage: InfinityRing(SR(oo)), InfinityRing(SR(-oo)) # needs sage.symbolic (+Infinity, -Infinity) The following rings have ``is_positive_infinity`` / @@ -1150,22 +1154,22 @@ def _element_constructor_(self, x): sage: RR(oo).is_positive_infinity(), RR(-oo).is_negative_infinity() (True, True) - sage: SR(oo).is_positive_infinity(), SR(-oo).is_negative_infinity() + sage: SR(oo).is_positive_infinity(), SR(-oo).is_negative_infinity() # needs sage.symbolic (True, True) Complex infinity raises an exception. This is fine (there is no coercion, so there is no promise of functoriality):: - sage: i_infinity = CC(0, oo) - sage: InfinityRing(CC(oo)), InfinityRing(CC(-oo)) + sage: i_infinity = CC(0, oo) # needs sage.rings.real_mpfr + sage: InfinityRing(CC(oo)), InfinityRing(CC(-oo)) # needs sage.rings.real_mpfr (+Infinity, -Infinity) - sage: InfinityRing(i_infinity) + sage: InfinityRing(i_infinity) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: infinite but not with +/- phase - sage: InfinityRing(CDF(oo)), InfinityRing(CDF(-oo)) + sage: InfinityRing(CDF(oo)), InfinityRing(CDF(-oo)) # needs sage.rings.complex_double (+Infinity, -Infinity) - sage: InfinityRing(CDF(i_infinity)) + sage: InfinityRing(CDF(i_infinity)) # needs sage.rings.complex_double sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: infinite but not with +/- phase @@ -1226,18 +1230,18 @@ def _coerce_map_from_(self, R): sage: InfinityRing.has_coerce_map_from(int) # indirect doctest True - sage: InfinityRing.has_coerce_map_from(AA) + sage: InfinityRing.has_coerce_map_from(AA) # needs sage.rings.number_field True sage: InfinityRing.has_coerce_map_from(RDF) True - sage: InfinityRing.has_coerce_map_from(RIF) + sage: InfinityRing.has_coerce_map_from(RIF) # needs sage.rings.real_interval_field True As explained above, comparison works by coercing to the infinity ring:: sage: cm = get_coercion_model() - sage: cm.explain(AA(3), oo, operator.lt) + sage: cm.explain(AA(3), oo, operator.lt) # needs sage.rings.number_field Coercion on left operand via Coercion map: From: Algebraic Real Field @@ -1250,9 +1254,9 @@ def _coerce_map_from_(self, R): symbolic comparisons with infinities all happen in the symbolic ring:: - sage: SR.has_coerce_map_from(InfinityRing) + sage: SR.has_coerce_map_from(InfinityRing) # needs sage.symbolic True - sage: InfinityRing.has_coerce_map_from(SR) + sage: InfinityRing.has_coerce_map_from(SR) # needs sage.symbolic False Complex numbers do not coerce into the infinity ring (what @@ -1260,11 +1264,11 @@ def _coerce_map_from_(self, R): be compared, so we do not have to enforce consistency when comparing with infinity either:: - sage: InfinityRing.has_coerce_map_from(CDF) + sage: InfinityRing.has_coerce_map_from(CDF) # needs sage.rings.complex_double False - sage: InfinityRing.has_coerce_map_from(CC) + sage: InfinityRing.has_coerce_map_from(CC) # needs sage.rings.real_mpfr False - sage: CC(0, oo) < CC(1) # does not coerce to infinity ring + sage: CC(0, oo) < CC(1) # does not coerce to infinity ring # needs sage.rings.real_mpfr True """ from sage.structure.coerce import parent_is_real_numerical @@ -1278,7 +1282,7 @@ def _pushout_(self, other): r""" EXAMPLES:: - sage: QQbar(-2*i)*infinity + sage: QQbar(-2*i)*infinity # needs sage.rings.number_field sage.symbolic (-I)*Infinity """ from sage.symbolic.ring import SR @@ -1391,7 +1395,7 @@ def _mul_(self, other): if other.is_zero(): if isinstance(self, InfinityElement): raise SignError("cannot multiply infinity by zero") - return sage.rings.integer_ring.ZZ(0) + return Integer(0) if self.value < 0: if isinstance(other, InfinityElement): return -other @@ -1403,7 +1407,7 @@ def _mul_(self, other): if self.value == 0: if isinstance(other, InfinityElement): raise SignError("cannot multiply infinity by zero") - return sage.rings.integer_ring.ZZ(0) + return Integer(0) def _div_(self, other): """ @@ -1479,9 +1483,9 @@ def _latex_(self): TESTS:: - sage: a = InfinityRing(pi); a + sage: a = InfinityRing(pi); a # needs sage.symbolic A positive finite number - sage: a._latex_() + sage: a._latex_() # needs sage.symbolic 'A positive finite number' sage: [latex(InfinityRing(a)) for a in [-2..2]] [A negative finite number, A negative finite number, Zero, A positive finite number, A positive finite number] @@ -1622,12 +1626,12 @@ def _sympy_(self): EXAMPLES:: - sage: import sympy - sage: bool(-oo == -sympy.oo) + sage: import sympy # needs sympy + sage: bool(-oo == -sympy.oo) # needs sympy True - sage: bool(SR(-oo) == -sympy.oo) + sage: bool(SR(-oo) == -sympy.oo) # needs sympy True - sage: bool((-oo)._sympy_() == -sympy.oo) + sage: bool((-oo)._sympy_() == -sympy.oo) # needs sympy True """ @@ -1640,9 +1644,9 @@ def _gap_init_(self): EXAMPLES:: - sage: gap(-Infinity) + sage: gap(-Infinity) # needs sage.libs.gap -infinity - sage: libgap(-Infinity) + sage: libgap(-Infinity) # needs sage.libs.gap -infinity """ return '-infinity' @@ -1723,10 +1727,10 @@ def _sympy_(self): EXAMPLES:: - sage: import sympy - sage: bool(oo == sympy.oo) # indirect doctest + sage: import sympy # needs sympy + sage: bool(oo == sympy.oo) # indirect doctest # needs sympy True - sage: bool(SR(oo) == sympy.oo) + sage: bool(SR(oo) == sympy.oo) # needs sympy sage.symbolic True """ import sympy @@ -1738,20 +1742,20 @@ def _gap_init_(self): EXAMPLES:: - sage: gap(+Infinity) + sage: gap(+Infinity) # needs sage.libs.gap infinity - sage: libgap(+Infinity) + sage: libgap(+Infinity) # needs sage.libs.gap infinity """ return 'infinity' + InfinityRing = InfinityRing_class() infinity = InfinityRing.gen(0) Infinity = infinity minus_infinity = InfinityRing.gen(1) - def test_comparison(ring): """ Check comparison with infinity @@ -1769,8 +1773,8 @@ def test_comparison(ring): EXAMPLES:: sage: from sage.rings.infinity import test_comparison - sage: rings = [ZZ, QQ, RR, RealField(200), RDF, RLF, AA, RIF] - sage: for R in rings: + sage: rings = [ZZ, QQ, RR, RealField(200), RDF, RLF, RIF] # needs sage.rings.real_mpfr + sage: for R in rings: # needs sage.rings.real_mpfr ....: print('testing {}'.format(R)) ....: test_comparison(R) testing Integer Ring @@ -1779,20 +1783,21 @@ def test_comparison(ring): testing Real Field with 200 bits of precision testing Real Double Field testing Real Lazy Field - testing Algebraic Real Field testing Real Interval Field with 53 bits of precision + sage: test_comparison(AA) # needs sage.rings.number_field Comparison with number fields does not work:: - sage: K.<sqrt3> = NumberField(x^2-3) - sage: (-oo < 1+sqrt3) and (1+sqrt3 < oo) # known bug + sage: x = polygen(ZZ, 'x') + sage: K.<sqrt3> = NumberField(x^2 - 3) # needs sage.rings.number_field + sage: (-oo < 1 + sqrt3) and (1 + sqrt3 < oo) # known bug # needs sage.rings.number_field False The symbolic ring handles its own infinities, but answers ``False`` (meaning: cannot decide) already for some very elementary comparisons:: - sage: test_comparison(SR) # known bug + sage: test_comparison(SR) # known bug # needs sage.symbolic Traceback (most recent call last): ... AssertionError: testing -1000.0 in Symbolic Ring: id = ... @@ -1850,8 +1855,11 @@ def test_signed_infinity(pos_inf): EXAMPLES:: sage: from sage.rings.infinity import test_signed_infinity - sage: for pos_inf in [oo, float('+inf'), RLF(oo), RIF(oo), SR(oo)]: - ....: test_signed_infinity(pos_inf) + sage: test_signed_infinity(oo) + sage: test_signed_infinity(float('+inf')) + sage: test_signed_infinity(RLF(oo)) + sage: test_signed_infinity(RIF(oo)) # needs sage.rings.real_interval_field + sage: test_signed_infinity(SR(oo)) # needs sage.symbolic """ msg = 'testing {} ({})'.format(pos_inf, type(pos_inf)) assert InfinityRing(pos_inf) is infinity, msg diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index e98b973b592..0ca24804524 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -8,7 +8,7 @@ EXAMPLES: Add 2 integers:: - sage: a = Integer(3) ; b = Integer(4) + sage: a = Integer(3); b = Integer(4) sage: a + b == 7 True @@ -24,8 +24,8 @@ Add an integer and a rational number:: Add an integer and a complex number:: - sage: b = ComplexField().0 + 1.5 - sage: loads((a+b).dumps()) == a+b + sage: b = ComplexField().0 + 1.5 # needs sage.rings.real_mpfr + sage: loads((a + b).dumps()) == a + b True sage: z = 32 @@ -40,7 +40,7 @@ Add an integer and a complex number:: Multiplication:: - sage: a = Integer(3) ; b = Integer(4) + sage: a = Integer(3); b = Integer(4) sage: a * b == 12 True sage: loads((a * 4.0).dumps()) == a*b @@ -55,17 +55,17 @@ Multiplication:: :: - sage: 'sage'*Integer(3) + sage: 'sage' * Integer(3) 'sagesagesage' COERCIONS: Return version of this integer in the multi-precision floating -real field R:: +real field `\RR`:: sage: n = 9390823 - sage: RR = RealField(200) - sage: RR(n) + sage: RR = RealField(200) # needs sage.rings.real_mpfr + sage: RR(n) # needs sage.rings.real_mpfr 9.3908230000000000000000000000000000000000000000000000000000e6 AUTHORS: @@ -143,8 +143,7 @@ AUTHORS: # creation and deletion are setup by the call to hook_fast_tp_functions cimport cython -from libc.math cimport (ldexp, sqrt as sqrt_double, log as log_c, - ceil as ceil_c, isnan) +from libc.math cimport (ldexp, sqrt as sqrt_double, isnan) from libc.string cimport memcpy from libc.limits cimport LONG_MAX @@ -152,7 +151,6 @@ from cysignals.memory cimport check_allocarray, check_malloc, sig_free from cysignals.signals cimport sig_on, sig_off, sig_check, sig_occurred import operator -import sys from sage.ext.stdsage cimport PY_NEW from sage.cpython.python_debug cimport if_Py_TRACE_REFS_then_PyObject_INIT @@ -160,23 +158,21 @@ from sage.cpython.python_debug cimport if_Py_TRACE_REFS_then_PyObject_INIT from sage.libs.gmp.mpz cimport * from sage.libs.gmp.mpq cimport * from sage.cpython.string cimport char_to_str, str_to_bytes -from sage.arith.long cimport (pyobject_to_long, integer_check_long, +from sage.arith.long cimport (integer_check_long, integer_check_long_py, is_small_python_int) from cpython.list cimport * from cpython.number cimport * -from cpython.int cimport * +from cpython.long cimport * from cpython.object cimport * from libc.stdint cimport uint64_t cimport sage.structure.element from sage.structure.coerce cimport coercion_model -from sage.structure.element cimport (Element, EuclideanDomainElement, - parent) +from sage.structure.element cimport (Element, parent) from sage.structure.parent cimport Parent from sage.rings.rational cimport Rational from sage.arith.rational_reconstruction cimport mpq_rational_reconstruction from sage.libs.gmp.pylong cimport * -from sage.libs.gmp.mpq cimport mpq_neg from sage.libs.gmp.binop cimport mpq_add_z, mpq_mul_z, mpq_div_zz import sage.rings.infinity @@ -235,7 +231,7 @@ cdef _digits_naive(mpz_t v,l,int offset,Integer base,digits): - ``base`` -- the base to which we finding digits - ``digits`` - a python sequence type with objects to use for digits - note that python negative index semantics are relied upon + note that python negative index semantics are relied upon AUTHORS: @@ -277,7 +273,7 @@ cdef _digits_internal(mpz_t v,l,int offset,int power_index,power_list,digits): to fill at - ``power_index`` - a measure of size to fill and index to - power_list we're filling 1 << (power_index+1) digits + power_list we're filling ``1 << (power_index+1)`` digits - ``power_list`` - a list of powers of the base, precomputed in method digits digits - a python sequence type with objects to @@ -323,7 +319,7 @@ mpz_ui_pow_ui(PARI_PSEUDOPRIME_LIMIT, 2, 64) def is_Integer(x): """ - Return true if x is of the Sage integer type. + Return ``True`` if ``x`` is of the Sage :class:`Integer` type. EXAMPLES:: @@ -347,30 +343,30 @@ cdef inline Integer as_Integer(x): cdef class IntegerWrapper(Integer): r""" - Rationale for the ``IntegerWrapper`` class: + Rationale for the :class:`IntegerWrapper` class: - With ``Integers``, the allocation/deallocation function slots are + With :class:`Integer` objects, the allocation/deallocation function slots are hijacked with custom functions that stick already allocated - ``Integers`` (with initialized ``parent`` and ``mpz_t`` fields) + :class:`Integer` objects (with initialized ``parent`` and ``mpz_t`` fields) into a pool on "deallocation" and then pull them out whenever a - new one is needed. Because ``Integers`` are so common, this is - actually a significant savings. However , this does cause issues - with subclassing a Python class directly from ``Integer`` (but + new one is needed. Because :class:`Integers` objects are so common, this is + actually a significant savings. However, this does cause issues + with subclassing a Python class directly from :class:`Integer` (but that's ok for a Cython class). As a workaround, one can instead derive a class from the - intermediate class ``IntegerWrapper``, which sets statically its - alloc/dealloc methods to the *original* ``Integer`` alloc/dealloc + intermediate class :class:`IntegerWrapper`, which sets statically its + alloc/dealloc methods to the *original* :class:`Integer` alloc/dealloc methods, before they are swapped manually for the custom ones. - The constructor of ``IntegerWrapper`` further allows for - specifying an alternative parent to ``IntegerRing()``. + The constructor of :class:`IntegerWrapper` further allows for + specifying an alternative parent to :class:`IntegerRing`. """ def __init__(self, parent=None, x=None, unsigned int base=0): """ We illustrate how to create integers with parents different - from ``IntegerRing()``:: + from :class:`IntegerRing``:: sage: from sage.rings.integer import IntegerWrapper @@ -396,15 +392,15 @@ cdef class IntegerWrapper(Integer): cdef class Integer(sage.structure.element.EuclideanDomainElement): r""" - The ``Integer`` class represents arbitrary precision - integers. It derives from the ``Element`` class, so + The :class:`Integer` class represents arbitrary precision + integers. It derives from the :class:`Element` class, so integers can be used as ring elements anywhere in Sage. - Integer() interprets strings that begin with ``0o`` as octal numbers, + The constructor of :class:`Integer` interprets strings that begin with ``0o`` as octal numbers, strings that begin with ``0x`` as hexadecimal numbers and strings that begin with ``0b`` as binary numbers. - The class ``Integer`` is implemented in Cython, as a wrapper of the + The class :class:`Integer` is implemented in Cython, as a wrapper of the GMP ``mpz_t`` integer type. EXAMPLES:: @@ -425,9 +421,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): Conversion from PARI:: - sage: Integer(pari('-10380104371593008048799446356441519384')) + sage: Integer(pari('-10380104371593008048799446356441519384')) # needs sage.libs.pari -10380104371593008048799446356441519384 - sage: Integer(pari('Pol([-3])')) + sage: Integer(pari('Pol([-3])')) # needs sage.libs.pari -3 Conversion from gmpy2:: @@ -463,11 +459,11 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): -901824309821093821093812093810928309183091832091 sage: ZZ(RR(2.0)^80) 1208925819614629174706176 - sage: ZZ(QQbar(sqrt(28-10*sqrt(3)) + sqrt(3))) + sage: ZZ(QQbar(sqrt(28-10*sqrt(3)) + sqrt(3))) # needs sage.rings.number_field sage.symbolic 5 - sage: ZZ(AA(32).nth_root(5)) + sage: ZZ(AA(32).nth_root(5)) # needs sage.rings.number_field 2 - sage: ZZ(pari('Mod(-3,7)')) + sage: ZZ(pari('Mod(-3,7)')) # needs sage.libs.pari 4 sage: ZZ('sage') Traceback (most recent call last): @@ -479,10 +475,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): '3b' sage: ZZ( ZZ(5).digits(3) , 3) 5 - sage: import numpy - sage: ZZ(numpy.int64(7^7)) + sage: import numpy # needs numpy + sage: ZZ(numpy.int64(7^7)) # needs numpy 823543 - sage: ZZ(numpy.ubyte(-7)) + sage: ZZ(numpy.ubyte(-7)) # needs numpy 249 sage: ZZ(True) 1 @@ -499,7 +495,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): :: sage: k = GF(2) - sage: ZZ( (k(0),k(1)), 2) + sage: ZZ((k(0),k(1)), 2) 2 :: @@ -535,6 +531,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): Test conversion from PARI (:trac:`11685`):: + sage: # needs sage.libs.pari sage: ZZ(pari(-3)) -3 sage: ZZ(pari("-3.0")) @@ -551,15 +548,15 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 100000000000000000000000000000000000000000000000000 sage: ZZ(pari("Pol(3)")) 3 - sage: ZZ(GF(3^20,'t')(1)) + sage: ZZ(GF(3^20,'t')(1)) # needs sage.rings.finite_rings 1 - sage: ZZ(pari(GF(3^20,'t')(1))) + sage: ZZ(pari(GF(3^20,'t')(1))) # needs sage.rings.finite_rings 1 sage: x = polygen(QQ) - sage: K.<a> = NumberField(x^2+3) - sage: ZZ(a^2) + sage: K.<a> = NumberField(x^2 + 3) # needs sage.rings.number_field + sage: ZZ(a^2) # needs sage.rings.number_field -3 - sage: ZZ(pari(a)^2) + sage: ZZ(pari(a)^2) # needs sage.rings.number_field -3 sage: ZZ(pari("Mod(x, x^3+x+1)")) # Note error message refers to lifted element Traceback (most recent call last): @@ -568,26 +565,26 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): Test coercion of p-adic with negative valuation:: - sage: ZZ(pari(Qp(11)(11^-7))) + sage: ZZ(pari(Qp(11)(11^-7))) # needs sage.libs.pari sage.rings.padics Traceback (most recent call last): ... - TypeError: Cannot convert p-adic with negative valuation to an integer + TypeError: cannot convert p-adic with negative valuation to an integer Test converting a list with a very large base:: - sage: a=ZZ(randint(0,2^128-1)) + sage: a = ZZ(randint(0, 2^128 - 1)) sage: L = a.digits(2^64) sage: a == sum([x * 2^(64*i) for i,x in enumerate(L)]) True - sage: a == ZZ(L,base=2^64) + sage: a == ZZ(L, base=2^64) True Test comparisons with numpy types (see :trac:`13386` and :trac:`18076`):: - sage: import numpy - sage: numpy.int8('12') == 12 + sage: import numpy # needs numpy + sage: numpy.int8('12') == 12 # needs numpy True - sage: 12 == numpy.int8('12') + sage: 12 == numpy.int8('12') # needs numpy True sage: float('15') == 15 @@ -640,7 +637,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): if n == x: mpz_set_pylong(self.value, n) else: - raise TypeError("Cannot convert non-integral float to integer") + raise TypeError("cannot convert non-integral float to integer") elif isinstance(x, pari_gen): global set_integer_from_gen @@ -762,7 +759,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def _im_gens_(self, codomain, im_gens, base_map=None): """ - Return the image of self under the map that sends the generators of + Return the image of ``self`` under the map that sends the generators of the parent to im_gens. Since ZZ maps canonically in the category of rings, this is just the natural coercion. @@ -972,7 +969,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): """ return [ self ] - def __dealloc__(self): + def __dealloc__(self): mpz_clear(self.value) def __repr__(self): @@ -1007,9 +1004,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: - sage: ex = SR(ZZ(7)); ex + sage: ex = SR(ZZ(7)); ex # needs sage.symbolic 7 - sage: parent(ex) + sage: parent(ex) # needs sage.symbolic Symbolic Ring """ return sring._force_pyobject(self, force=True) @@ -1020,9 +1017,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: - sage: n = 5; n._sympy_() + sage: n = 5; n._sympy_() # needs sympy 5 - sage: n = -5; n._sympy_() + sage: n = -5; n._sympy_() # needs sympy -5 """ import sympy @@ -1077,7 +1074,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): :: - sage: two=Integer(2) + sage: two = Integer(2) sage: two.str(1) Traceback (most recent call last): ... @@ -1114,7 +1111,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def __format__(self, *args, **kwargs): """ - Returns a string representation using Python's Format protocol. + Return a string representation using Python's Format protocol. Valid format descriptions are exactly those for Python integers. EXAMPLES:: @@ -1127,7 +1124,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def ordinal_str(self): """ - Returns a string representation of the ordinal associated to self. + Return a string representation of the ordinal associated to ``self``. EXAMPLES:: @@ -1255,7 +1252,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def bits(self): r""" - Return the bits in self as a list, least significant first. The + Return the bits in ``self`` as a list, least significant first. The result satisfies the identity :: @@ -1338,7 +1335,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def trailing_zero_bits(self): """ - Return the number of trailing zero bits in self, i.e. + Return the number of trailing zero bits in ``self``, i.e. the exponent of the largest power of 2 dividing self. EXAMPLES:: @@ -1364,7 +1361,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): Return a list of digits for ``self`` in the given base in little endian order. - The returned value is unspecified if self is a negative number + The returned value is unspecified if ``self`` is a negative number and the digits are given. INPUT: @@ -1466,7 +1463,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: l[16] [1, 1] - This function is comparable to ``str`` for speed. + This function is comparable to :func:`str` for speed. :: @@ -1594,7 +1591,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): between ``-b//2`` and ``b//2`` (both included). For instance in base 9, one uses digits from -4 to 4. If ``b`` is even, one has to choose between digits from ``-b//2`` to ``b//2 - 1`` or ``-b//2 + 1`` to ``b//2`` - (base 10 for instance: either -5 to 4 or -4 to 5), and this is + (base 10 for instance: either `-5` to `4` or `-4` to `5`), and this is defined by the value of ``positive_shift``. INPUT: @@ -1603,9 +1600,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): nonnegative or the nonpositive integers can be represented by ``balanced_digits``. Thus we say base must be greater than 2. - - ``positive_shift`` -- boolean (default: True); for even bases, the + - ``positive_shift`` -- boolean (default: ``True``); for even bases, the representation uses digits from ``-b//2 + 1`` to ``b//2`` if set to - True, and from ``-b//2`` to ``b//2 - 1`` otherwise. This has no + ``True``, and from ``-b//2`` to ``b//2 - 1`` otherwise. This has no effect for odd bases. EXAMPLES:: @@ -1695,7 +1692,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def ndigits(self, base=10): """ - Return the number of digits of self expressed in the given base. + Return the number of digits of ``self`` expressed in the given base. INPUT: @@ -1906,7 +1903,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: b'hi' * 8 == b'hihihihihihihihi' True """ - if isinstance(s, (list, tuple, basestring, bytes)): + if isinstance(s, (list, tuple, str, bytes)): if mpz_fits_slong_p(self.value): return s * mpz_get_si(self.value) else: @@ -2008,7 +2005,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): Traceback (most recent call last): ... ZeroDivisionError: rational division by zero - sage: 3 / QQbar.zero() + sage: 3 / QQbar.zero() # needs sage.rings.number_field Traceback (most recent call last): ... ZeroDivisionError: division by zero in algebraic field @@ -2056,7 +2053,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: - sage: a = Integer(321) ; b = Integer(10) + sage: a = Integer(321); b = Integer(10) sage: a // b 32 sage: z = Integer(-231) @@ -2113,7 +2110,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 1 sage: 2^-0 1 - sage: (-1)^(1/3) + sage: (-1)^(1/3) # needs sage.symbolic (-1)^(1/3) For consistency with Python and MPFR, 0^0 is defined to be 1 in @@ -2140,26 +2137,27 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): We raise 2 to various interesting exponents:: - sage: 2^x # symbolic x + sage: 2^x # symbolic x # needs sage.symbolic 2^x sage: 2^1.5 # real number 2.82842712474619 sage: 2^float(1.5) # python float abs tol 3e-16 2.8284271247461903 - sage: 2^I # complex number + sage: 2^I # complex number # needs sage.symbolic 2^I sage: r = 2 ^ int(-3); r; type(r) 1/8 <class 'sage.rings.rational.Rational'> - sage: f = 2^(sin(x)-cos(x)); f + sage: f = 2^(sin(x)-cos(x)); f # needs sage.symbolic 2^(-cos(x) + sin(x)) - sage: f(x=3) + sage: f(x=3) # needs sage.symbolic 2^(-cos(3) + sin(3)) A symbolic sum:: - sage: x,y,z = var('x,y,z') - sage: 2^(x+y+z) + sage: # needs sage.symbolic + sage: x, y, z = var('x,y,z') + sage: 2^(x + y + z) 2^(x + y + z) sage: 2^(1/2) sqrt(2) @@ -2220,7 +2218,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ... ZeroDivisionError: rational division by zero - The exponent must fit in a long unless the base is -1, 0, or 1:: + The exponent must fit in a ``long`` unless the base is `-1`, `0`, or `1`:: sage: 2 ^ 100000000000000000000000 Traceback (most recent call last): @@ -2316,25 +2314,25 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def nth_root(self, int n, bint truncate_mode=0): r""" - Returns the (possibly truncated) n'th root of self. + Return the (possibly truncated) ``n``-th root of ``self``. INPUT: - - ``n`` - integer >= 1 (must fit in C int type). + - ``n`` - integer `\geq 1` (must fit in the C ``int`` type). - ``truncate_mode`` - boolean, whether to allow truncation if - self is not an n'th power. + ``self`` is not an ``n``-th power. OUTPUT: - If truncate_mode is 0 (default), then returns the exact n'th root - if self is an n'th power, or raises a ValueError if it is not. + If ``truncate_mode`` is 0 (default), then returns the exact n'th root + if ``self`` is an n'th power, or raises a ValueError if it is not. - If truncate_mode is 1, then if either n is odd or self is - positive, returns a pair (root, exact_flag) where root is the - truncated nth root (rounded towards zero) and exact_flag is a + If ``truncate_mode`` is 1, then if either ``n`` is odd or ``self`` is + positive, returns a pair ``(root, exact_flag)`` where ``root`` is the + truncated ``n``-th root (rounded towards zero) and ``exact_flag`` is a boolean indicating whether the root extraction was exact; - otherwise raises a ValueError. + otherwise raises a :class:`ValueError`. AUTHORS: @@ -2603,7 +2601,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def exact_log(self, m): r""" - Returns the largest integer `k` such that `m^k \leq \text{self}`, + Return the largest integer `k` such that `m^k \leq \text{self}`, i.e., the floor of `\log_m(\text{self})`. This is guaranteed to return the correct answer even when the usual @@ -2611,13 +2609,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): INPUT: - - ``m`` - integer >= 2 + - ``m`` - integer `\geq 2` AUTHORS: - David Harvey (2006-09-15) - Joel B. Mohler (2009-04-08) -- rewrote this to handle small cases - and/or easy cases up to 100x faster.. + and/or easy cases up to 100x faster.. EXAMPLES:: @@ -2643,16 +2641,18 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: # The following are very very fast. sage: # Note that for base m a perfect power of 2, we get the exact log by counting bits. - sage: n=2983579823750185701375109835; m=32 + sage: n = 2983579823750185701375109835; m = 32 sage: n.exact_log(m) 18 sage: # The next is a favorite of mine. The log2 approximate is exact and immediately provable. - sage: n=90153710570912709517902579010793251709257901270941709247901209742124;m=213509721309572 + sage: n = 90153710570912709517902579010793251709257901270941709247901209742124 + sage: m = 213509721309572 sage: n.exact_log(m) 4 :: + sage: # needs sage.rings.real_mpfr sage: x = 3^100000 sage: RR(log(RR(x), 3)) 100000.000000000 @@ -2661,15 +2661,17 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): :: + sage: # needs sage.rings.real_mpfr sage: x.exact_log(3) 100000 - sage: (x+1).exact_log(3) + sage: (x + 1).exact_log(3) 100000 - sage: (x-1).exact_log(3) + sage: (x - 1).exact_log(3) 99999 :: + sage: # needs sage.rings.real_mpfr sage: x.exact_log(2.5) Traceback (most recent call last): ... @@ -2750,71 +2752,71 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def log(self, m=None, prec=None): r""" - Returns symbolic log by default, unless the logarithm is exact (for - an integer argument). When precision is given, the RealField + Return symbolic log by default, unless the logarithm is exact (for + an integer argument). When ``prec`` is given, the :class:`RealField` approximation to that bit precision is used. This function is provided primarily so that Sage integers may be treated in the same manner as real numbers when convenient. Direct - use of exact_log is probably best for arithmetic log computation. + use of :meth:`exact_log` is probably best for arithmetic log computation. INPUT: - ``m`` - default: natural log base e - - ``prec`` - integer (default: None): if None, returns - symbolic, else to given bits of precision as in RealField + - ``prec`` - integer (default: ``None``): if ``None``, returns + symbolic, else to given bits of precision as in :class:`RealField` EXAMPLES:: - sage: Integer(124).log(5) + sage: Integer(124).log(5) # needs sage.symbolic log(124)/log(5) - sage: Integer(124).log(5,100) + sage: Integer(124).log(5, 100) # needs sage.rings.real_mpfr 2.9950093311241087454822446806 sage: Integer(125).log(5) 3 - sage: Integer(125).log(5,prec=53) + sage: Integer(125).log(5, prec=53) # needs sage.rings.real_mpfr 3.00000000000000 - sage: log(Integer(125)) + sage: log(Integer(125)) # needs sage.symbolic 3*log(5) For extremely large numbers, this works:: sage: x = 3^100000 - sage: log(x,3) + sage: log(x, 3) 100000 - With the new Pynac symbolic backend, log(x) also - works in a reasonable amount of time for this x:: + Also ``log(x)``, giving a symbolic output, + works in a reasonable amount of time for this ``x``:: sage: x = 3^100000 - sage: log(x) + sage: log(x) # needs sage.symbolic log(1334971414230...5522000001) But approximations are probably more useful in this case, and work to as high a precision as we desire:: - sage: x.log(3,53) # default precision for RealField + sage: x.log(3, 53) # default precision for RealField # needs sage.rings.real_mpfr 100000.000000000 - sage: (x+1).log(3,53) + sage: (x + 1).log(3, 53) # needs sage.rings.real_mpfr 100000.000000000 - sage: (x+1).log(3,1000) + sage: (x + 1).log(3, 1000) # needs sage.rings.real_mpfr 100000.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 We can use non-integer bases, with default e:: - sage: x.log(2.5,prec=53) + sage: x.log(2.5, prec=53) # needs sage.rings.real_mpfr 119897.784671579 We also get logarithms of negative integers, via the - symbolic ring, using the branch from `-pi` to `pi`:: + symbolic ring, using the branch from `-\pi` to `\pi`:: - sage: log(-1) + sage: log(-1) # needs sage.symbolic I*pi The logarithm of zero is done likewise:: - sage: log(0) + sage: log(0) # needs sage.symbolic -Infinity Some rational bases yield integer logarithms (:trac:`21517`):: @@ -2829,7 +2831,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): TESTS:: - sage: (-2).log(3) + sage: (-2).log(3) # needs sage.symbolic (I*pi + log(2))/log(3) """ cdef int self_sgn @@ -2855,12 +2857,12 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): except (ValueError, TypeError): pass - if type(m) == Integer and type(self) == Integer: + if isinstance(m, Integer): elog = self.exact_log(m) if elog == -sage.rings.infinity.infinity or m**elog == self: return elog - if (type(m) == Rational and type(self) == Integer + if (isinstance(m, Rational) and m.numer() == 1): elog = -self.exact_log(m.denom()) if m**elog == self: @@ -2872,7 +2874,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def exp(self, prec=None): r""" - Returns the exponential function of self as a real number. + Return the exponential function of ``self`` as a real number. This function is provided only so that Sage integers may be treated in the same manner as real numbers when convenient. @@ -2881,26 +2883,26 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): - ``prec`` - integer (default: None): if None, returns - symbolic, else to given bits of precision as in RealField + symbolic, else to given bits of precision as in :class:`RealField` EXAMPLES:: - sage: Integer(8).exp() + sage: Integer(8).exp() # needs sage.symbolic e^8 - sage: Integer(8).exp(prec=100) + sage: Integer(8).exp(prec=100) # needs sage.symbolic 2980.9579870417282747435920995 - sage: exp(Integer(8)) + sage: exp(Integer(8)) # needs sage.symbolic e^8 For even fairly large numbers, this may not be useful. :: - sage: y=Integer(145^145) - sage: y.exp() + sage: y = Integer(145^145) + sage: y.exp() # needs sage.symbolic e^25024207011349079210459585279553675697932183658421565260323592409432707306554163224876110094014450895759296242775250476115682350821522931225499163750010280453185147546962559031653355159703678703793369785727108337766011928747055351280379806937944746847277089168867282654496776717056860661614337004721164703369140625 - sage: y.exp(prec=53) # default RealField precision + sage: y.exp(prec=53) # default RealField precision # needs sage.symbolic +infinity """ from sage.functions.all import exp @@ -2911,8 +2913,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def prime_to_m_part(self, m): """ - Returns the prime-to-m part of self, i.e., the largest divisor of - ``self`` that is coprime to ``m``. + Return the prime-to-`m` part of ``self``, i.e., the largest divisor of + ``self`` that is coprime to `m`. INPUT: @@ -2951,12 +2953,20 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return n - def prime_divisors(self): + def prime_divisors(self, *args, **kwds): """ Return the prime divisors of this integer, sorted in increasing order. - If this integer is negative, we do *not* include -1 among - its prime divisors, since -1 is not a prime number. + If this integer is negative, we do *not* include `-1` among + its prime divisors, since `-1` is not a prime number. + + INPUT: + + - ``limit`` -- (integer, optional keyword argument) + Return only prime divisors up to this bound, and the factorization + is done by checking primes up to ``limit`` using trial division. + + Any additional arguments are passed on to the :meth:`factor` method. EXAMPLES:: @@ -2968,8 +2978,23 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): [2, 5] sage: a = 2004; a.prime_divisors() [2, 3, 167] + + Setting the optional ``limit`` argument works as expected:: + + sage: a = 10^100 + 1 + sage: a.prime_divisors() # needs sage.libs.pari + [73, 137, 401, 1201, 1601, 1676321, 5964848081, + 129694419029057750551385771184564274499075700947656757821537291527196801] + sage: a.prime_divisors(limit=10^3) + [73, 137, 401] + sage: a.prime_divisors(limit=10^7) + [73, 137, 401, 1201, 1601, 1676321] """ - return [r[0] for r in self.factor()] + res = [r[0] for r in self.factor(*args, **kwds)] + limit = kwds.get('limit') + if limit is not None: + res = [r for r in res if r <= limit] + return res prime_factors = prime_divisors @@ -3004,32 +3029,32 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): [1, 2, 3, 4, 6, 8, 9, 12, 17, 18, 24, 34, 36, 51, 68, 72, 102, 136, 153, 204, 306, 408, 612, 1224] sage: a = odd_part(factorial(31)) - sage: v = a.divisors() - sage: len(v) + sage: v = a.divisors() # needs sage.libs.pari + sage: len(v) # needs sage.libs.pari 172800 - sage: prod(e + 1 for p, e in factor(a)) + sage: prod(e + 1 for p, e in factor(a)) # needs sage.libs.pari 172800 - sage: all(t.divides(a) for t in v) + sage: all(t.divides(a) for t in v) # needs sage.libs.pari True :: sage: n = 2^551 - 1 - sage: L = n.divisors() - sage: len(L) + sage: L = n.divisors() # needs sage.libs.pari + sage: len(L) # needs sage.libs.pari 256 - sage: L[-1] == n + sage: L[-1] == n # needs sage.libs.pari True TESTS: Overflow:: - sage: prod(primes_first_n(64)).divisors() + sage: prod(primes_first_n(64)).divisors() # needs sage.libs.pari Traceback (most recent call last): ... OverflowError: value too large - sage: prod(primes_first_n(58)).divisors() + sage: prod(primes_first_n(58)).divisors() # needs sage.libs.pari Traceback (most recent call last): ... OverflowError: value too large # 32-bit @@ -3039,8 +3064,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): (the ``divisors`` call below allocates about 800 MB every time, so a memory leak will not go unnoticed):: - sage: n = prod(primes_first_n(25)) - sage: for i in range(20): # long time + sage: n = prod(primes_first_n(25)) # needs sage.libs.pari + sage: for i in range(20): # long time # needs sage.libs.pari ....: try: ....: alarm(RDF.random_element(1e-3, 0.5)) ....: _ = n.divisors() @@ -3266,7 +3291,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def sign(self): """ - Returns the sign of this integer, which is -1, 0, or 1 + Return the sign of this integer, which is `-1`, `0`, or `1` depending on whether this number is negative, zero, or positive respectively. @@ -3322,9 +3347,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): This example caused trouble in :trac:`6083`:: - sage: a = next_prime(2**31) - sage: b = Integers(a)(100) - sage: a % b + sage: a = next_prime(2**31) # needs sage.libs.pari + sage: b = Integers(a)(100) # needs sage.libs.pari + sage: a % b # needs sage.libs.pari Traceback (most recent call last): ... ArithmeticError: reduction modulo 100 not defined @@ -3371,7 +3396,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def quo_rem(Integer self, other): """ - Returns the quotient and the remainder of self divided by other. + Return the quotient and the remainder of ``self`` divided by other. Note that the remainder returned is always either zero or of the same sign as other. @@ -3420,10 +3445,11 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: divmod(1, sys.maxsize+1r) # should not raise OverflowError: Python int too large to convert to C long (0, 1) - sage: import mpmath - sage: mpmath.mp.prec = 1000 - sage: root = mpmath.findroot(lambda x: x^2 - 3, 2) - sage: len(str(root)) + + sage: import mpmath # needs mpmath + sage: mpmath.mp.prec = 1000 # needs mpmath + sage: root = mpmath.findroot(lambda x: x^2 - 3, 2) # needs mpmath + sage: len(str(root)) # needs mpmath 301 """ cdef Integer q = PY_NEW(Integer) @@ -3431,7 +3457,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cdef long d, res if is_small_python_int(other): - d = PyInt_AS_LONG(other) + d = PyLong_AsLong(other) if d > 0: mpz_fdiv_qr_ui(q.value, r.value, self.value, d) elif d == 0: @@ -3461,7 +3487,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def powermod(self, exp, mod): r""" - Compute self\*\*exp modulo mod. + Compute ``self**exp`` modulo ``mod``. EXAMPLES:: @@ -3494,11 +3520,11 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return x def rational_reconstruction(self, Integer m): - """ - Return the rational reconstruction of this integer modulo m, i.e., - the unique (if it exists) rational number that reduces to self + r""" + Return the rational reconstruction of this integer modulo `m`, i.e., + the unique (if it exists) rational number that reduces to ``self`` modulo m and whose numerator and denominator is bounded by - sqrt(m/2). + `\sqrt{m/2}`. INPUT: @@ -3586,7 +3612,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def _rpy_(self): """ - Returns int(self) so that rpy can convert self into an object it + Return int(self) so that rpy can convert ``self`` into an object it knows how to work with. EXAMPLES:: @@ -3664,20 +3690,19 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def trial_division(self, long bound=LONG_MAX, long start=2): """ - Return smallest prime divisor of self up to bound, beginning - checking at start, or abs(self) if no such divisor is found. + Return smallest prime divisor of ``self`` up to bound, beginning + checking at ``start``, or ``abs(self)`` if no such divisor is found. INPUT: - - ``bound`` -- a positive integer that fits in a C signed long - - ``start`` -- a positive integer that fits in a C signed long - - OUTPUT: + - ``bound`` -- a positive integer that fits in a C ``signed long`` + - ``start`` -- a positive integer that fits in a C ``signed long`` - - a positive integer + OUTPUT: A positive integer EXAMPLES:: + sage: # needs sage.libs.pari sage: n = next_prime(10^6)*next_prime(10^7); n.trial_division() 1000003 sage: (-n).trial_division() @@ -3697,6 +3722,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ... ValueError: self must be nonzero + sage: # needs sage.libs.pari sage: n = next_prime(10^5) * next_prime(10^40); n.trial_division() 100003 sage: n.trial_division(bound=10^4) @@ -3789,11 +3815,11 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): else: limit = bound while m <= limit: - if mpz_divisible_ui_p(self.value, m): + if mpz_divisible_ui_p(self.value, m): mpz_set_ui(x.value, m) sig_off() return x - m += dif[i%8] + m += dif[i % 8] i += 1 mpz_abs(x.value, self.value) sig_off() @@ -3811,6 +3837,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): - ``'pari'`` - (default) use the PARI library + - ``'flint'`` - use the FLINT library + - ``'kash'`` - use the KASH computer algebra system (requires kash) @@ -3824,12 +3852,12 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): - ``'ecm'`` - use ECM-GMP, an implementation of Hendrik Lenstra's elliptic curve method. - - ``proof`` - bool (default: True) whether or not to prove + - ``proof`` - bool (default: ``True``) whether or not to prove primality of each factor (only applicable for ``'pari'`` and ``'ecm'``). - ``limit`` - int or None (default: None) if limit is - given it must fit in a signed int, and the factorization is done + given it must fit in a ``signed int``, and the factorization is done using trial division and primes up to limit. OUTPUT: @@ -3839,7 +3867,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: - sage: n = 2^100 - 1; n.factor() + sage: n = 2^100 - 1; n.factor() # needs sage.libs.pari 3 * 5^3 * 11 * 31 * 41 * 101 * 251 * 601 * 1801 * 4051 * 8101 * 268501 This factorization can be converted into a list of pairs `(p, @@ -3862,13 +3890,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: dict(f)[3] 6 - We use proof=False, which doesn't prove correctness of the primes + We use ``proof=False``, which doesn't prove correctness of the primes that appear in the factorization:: sage: n = 920384092842390423848290348203948092384082349082 - sage: n.factor(proof=False) + sage: n.factor(proof=False) # needs sage.libs.pari 2 * 11 * 1531 * 4402903 * 10023679 * 619162955472170540533894518173 - sage: n.factor(proof=True) + sage: n.factor(proof=True) # needs sage.libs.pari 2 * 11 * 1531 * 4402903 * 10023679 * 619162955472170540533894518173 We factor using trial division only:: @@ -3876,12 +3904,19 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: n.factor(limit=1000) 2 * 11 * 41835640583745019265831379463815822381094652231 + An example where FLINT is used:: + + sage: n = 82862385732327628428164127822 + sage: n.factor(algorithm='flint') # needs sage.libs.flint + 2 * 3 * 11 * 13 * 41 * 73 * 22650083 * 1424602265462161 + We factor using a quadratic sieve algorithm:: + sage: # needs sage.libs.pari sage: p = next_prime(10^20) sage: q = next_prime(10^21) - sage: n = p*q - sage: n.factor(algorithm='qsieve') + sage: n = p * q + sage: n.factor(algorithm='qsieve') # needs sage.libs.flint doctest:... RuntimeWarning: the factorization returned by qsieve may be incomplete (the factors may not be prime) or even wrong; see qsieve? for details @@ -3889,9 +3924,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): We factor using the elliptic curve method:: + sage: # needs sage.libs.pari sage: p = next_prime(10^15) sage: q = next_prime(10^21) - sage: n = p*q + sage: n = p * q sage: n.factor(algorithm='ecm') 1000000000000037 * 1000000000000000000117 @@ -3906,7 +3942,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): from sage.structure.factorization import Factorization from sage.structure.factorization_integer import IntegerFactorization - if algorithm not in ['pari', 'kash', 'magma', 'qsieve', 'ecm']: + if algorithm not in ['pari', 'flint', 'kash', 'magma', 'qsieve', 'ecm']: raise ValueError("Algorithm is not known") cdef Integer n, p, unit @@ -3954,11 +3990,18 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return factor_trial_division(self) if algorithm == 'pari': - from sage.rings.factorint import factor_using_pari + from sage.rings.factorint_pari import factor_using_pari F = factor_using_pari(n, int_=int_, debug_level=verbose, proof=proof) F.sort() return IntegerFactorization(F, unit=unit, unsafe=True, sort=False, simplify=False) + elif algorithm == 'flint': + from sage.rings.factorint_flint import factor_using_flint + F = factor_using_flint(n) + F.sort() + return IntegerFactorization(F, unit=unit, unsafe=True, + sort=False, simplify=False) + elif algorithm in ['kash', 'magma']: if algorithm == 'kash': from sage.interfaces.kash import kash as I @@ -3975,10 +4018,11 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): message = "the factorization returned by qsieve may be incomplete (the factors may not be prime) or even wrong; see qsieve? for details" from warnings import warn warn(message, RuntimeWarning, stacklevel=5) - from sage.interfaces.qsieve import qsieve - res = [(p, 1) for p in qsieve(n)[0]] - F = IntegerFactorization(res, unit) - return F + from sage.libs.flint.qsieve import qsieve + F = qsieve(n) + F.sort() + return IntegerFactorization(F, unit=unit, unsafe=True, + sort=False, simplify=False) else: from sage.interfaces.ecm import ecm res = [(p, 1) for p in ecm.factor(n, proof=proof)] @@ -3999,7 +4043,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: (-999).support() [3, 37] - Trying to find the support of 0 gives an arithmetic error:: + Trying to find the support of 0 raises an :class:`ArithmeticError`:: sage: 0.support() Traceback (most recent call last): @@ -4107,7 +4151,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def divides(self, n): """ - Return True if self divides n. + Return ``True`` if ``self`` divides ``n``. EXAMPLES:: @@ -4131,7 +4175,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cpdef RingElement _valuation(Integer self, Integer p): r""" - Return the p-adic valuation of self. + Return the p-adic valuation of ``self``. We do not require that p be prime, but it must be at least 2. For more documentation see ``valuation`` @@ -4156,8 +4200,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cdef object _val_unit(Integer self, Integer p): r""" - Returns a pair: the p-adic valuation of self, and the p-adic unit - of self. + Return a pair: the p-adic valuation of ``self``, and the p-adic unit + of ``self``. We do not require the p be prime, but it must be at least 2. For more documentation see ``val_unit`` @@ -4181,7 +4225,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def valuation(self, p): """ - Return the p-adic valuation of self. + Return the p-adic valuation of ``self``. INPUT: @@ -4201,7 +4245,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ... ValueError: You can only compute the valuation with respect to a integer larger than 1. - We do not require that p is a prime:: + We do not require that ``p`` is a prime:: sage: (2^11).valuation(4) 5 @@ -4213,7 +4257,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def p_primary_part(self, p): """ - Return the p-primary part of ``self``. + Return the ``p``-primary part of ``self``. INPUT: @@ -4242,8 +4286,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def val_unit(self, p): r""" - Returns a pair: the p-adic valuation of self, and the p-adic unit - of self. + Return a pair: the p-adic valuation of ``self``, and the p-adic unit + of ``self``. INPUT: @@ -4278,10 +4322,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): IMPLEMENTATION: - Currently returns 0 when self is 0. This behaviour is fairly arbitrary, + Currently returns 0 when ``self`` is 0. This behaviour is fairly arbitrary, and in Sage 4.6 this special case was not handled at all, eventually propagating a TypeError. The caller should not rely on the behaviour - in case self is 0. + in case ``self`` is 0. EXAMPLES:: @@ -4305,10 +4349,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cdef Integer _divide_knowing_divisible_by(Integer self, Integer right): r""" - Returns the integer self / right when self is divisible by right. + Return the integer ``self`` / ``right`` when ``self`` is divisible by right. - If self is not divisible by right, the return value is undefined, - and may not even be close to self/right. For more documentation see + If ``self`` is not divisible by right, the return value is undefined, + and may not even be close to ``self`` / ``right``. For more documentation see ``divide_knowing_divisible_by`` AUTHORS: @@ -4331,10 +4375,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def divide_knowing_divisible_by(self, right): r""" - Returns the integer self / right when self is divisible by right. + Return the integer ``self`` / ``right`` when ``self`` is divisible by ``right``. - If self is not divisible by right, the return value is undefined, - and may not even be close to self/right for multi-word integers. + If ``self`` is not divisible by right, the return value is undefined, + and may not even be close to ``self`` / ``right`` for multi-word integers. EXAMPLES:: @@ -4361,7 +4405,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def _lcm(self, Integer n): """ - Returns the least common multiple of self and `n`. + Return the least common multiple of ``self`` and `n`. EXAMPLES:: @@ -4377,7 +4421,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def _gcd(self, Integer n): """ - Return the greatest common divisor of self and `n`. + Return the greatest common divisor of ``self`` and `n`. EXAMPLES:: @@ -4449,7 +4493,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): r""" Return the factorial `n! = 1 \cdot 2 \cdot 3 \cdots n`. - If the input does not fit in an ``unsigned long int`` an ``OverflowError`` + If the input does not fit in an ``unsigned long int``, an :class:`OverflowError` is raised. EXAMPLES:: @@ -4464,14 +4508,14 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 5 120 6 720 - Large integers raise an ``OverflowError``:: + Large integers raise an :class:`OverflowError`:: sage: (2**64).factorial() Traceback (most recent call last): ... OverflowError: argument too large for factorial - And negative ones a ``ValueError``:: + And negative ones a :class:`ValueError`:: sage: (-1).factorial() Traceback (most recent call last): @@ -4494,7 +4538,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def multifactorial(self, long k): r""" - Compute the k-th factorial `n!^{(k)}` of self. + Compute the k-th factorial `n!^{(k)}` of ``self``. The multifactorial number `n!^{(k)}` is defined for non-negative integers `n` as follows. For `k=1` this is the standard factorial, @@ -4528,7 +4572,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ... ValueError: multifactorial undefined - When entries are too large an ``OverflowError`` is raised:: + When entries are too large an :class:`OverflowError` is raised:: sage: (2**64).multifactorial(2) Traceback (most recent call last): @@ -4580,6 +4624,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: + sage: # needs sage.symbolic sage: gamma(5) 24 sage: gamma(0) @@ -4596,7 +4641,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def floor(self): """ - Return the floor of self, which is just self since self is an + Return the floor of ``self``, which is just self since ``self`` is an integer. EXAMPLES:: @@ -4609,7 +4654,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def ceil(self): """ - Return the ceiling of self, which is self since self is an + Return the ceiling of ``self``, which is ``self`` since ``self`` is an integer. EXAMPLES:: @@ -4622,8 +4667,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def trunc(self): """ - Round this number to the nearest integer, which is self since - self is an integer. + Round this number to the nearest integer, which is ``self`` since + ``self`` is an integer. EXAMPLES:: @@ -4635,8 +4680,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def round(Integer self, mode="away"): """ - Returns the nearest integer to ``self``, which is self since - self is an integer. + Return the nearest integer to ``self``, which is ``self`` since + ``self`` is an integer. EXAMPLES: @@ -4650,7 +4695,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def real(self): """ - Returns the real part of self, which is self. + Return the real part of ``self``, which is ``self``. EXAMPLES:: @@ -4661,7 +4706,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def imag(self): """ - Returns the imaginary part of self, which is zero. + Return the imaginary part of ``self``, which is zero. EXAMPLES:: @@ -4672,7 +4717,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def is_one(self): r""" - Returns ``True`` if the integer is `1`, otherwise ``False``. + Return ``True`` if the integer is `1`, otherwise ``False``. EXAMPLES:: @@ -4685,7 +4730,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def __bool__(self): r""" - Returns ``True`` if the integer is not `0`, otherwise ``False``. + Return ``True`` if the integer is not `0`, otherwise ``False``. EXAMPLES:: @@ -4721,7 +4766,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def is_integer(self): """ - Returns ``True`` as they are integers + Return ``True`` as they are integers EXAMPLES:: @@ -4732,7 +4777,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def is_unit(self): r""" - Returns ``true`` if this integer is a unit, i.e., 1 or `-1`. + Return ``True`` if this integer is a unit, i.e., `1` or `-1`. EXAMPLES:: @@ -4748,7 +4793,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def is_square(self): r""" - Returns ``True`` if self is a perfect square. + Return ``True`` if ``self`` is a perfect square. EXAMPLES:: @@ -4761,7 +4806,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def perfect_power(self): r""" - Returns ``(a, b)``, where this integer is `a^b` and `b` is maximal. + Return ``(a, b)``, where this integer is `a^b` and `b` is maximal. If called on `-1`, `0` or `1`, `b` will be `1`, since there is no maximal value of `b`. @@ -4776,7 +4821,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: - sage: 144.perfect_power() + sage: 144.perfect_power() # needs sage.libs.pari (12, 2) sage: 1.perfect_power() (1, 1) @@ -4784,23 +4829,44 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): (0, 1) sage: (-1).perfect_power() (-1, 1) - sage: (-8).perfect_power() + sage: (-8).perfect_power() # needs sage.libs.pari (-2, 3) sage: (-4).perfect_power() (-4, 1) - sage: (101^29).perfect_power() + sage: (101^29).perfect_power() # needs sage.libs.pari (101, 29) - sage: (-243).perfect_power() + sage: (-243).perfect_power() # needs sage.libs.pari (-3, 5) - sage: (-64).perfect_power() + sage: (-64).perfect_power() # needs sage.libs.pari (-4, 3) + + TESTS:: + + sage: 4.perfect_power() + (2, 2) + sage: 256.perfect_power() + (2, 8) """ + cdef long n + # Fast PARI-free path + if mpz_fits_slong_p(self.value): + n = mpz_get_si(self.value) + if -8 < n < 4: + return self, one + if n >= 4: + if not (n & 1): + if mpz_popcount(self.value) == 1: + return smallInteger(2), smallInteger(mpz_sizeinbase(self.value, 2) - 1) + if n < 1000: + if _small_primes_table[n >> 1]: + return self, one + parians = self.__pari__().ispower() return Integer(parians[1]), Integer(parians[0]) def global_height(self, prec=None): r""" - Returns the absolute logarithmic height of this rational integer. + Return the absolute logarithmic height of this rational integer. INPUT: @@ -4817,6 +4883,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: ZZ(5).global_height() 1.60943791243410 sage: ZZ(-2).global_height(prec=100) @@ -4835,10 +4902,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cdef bint _is_power_of(Integer self, Integer n): r""" - Returns a non-zero int if there is an integer b with + Return a non-zero int if there is an integer b with `\mathtt{self} = n^b`. - For more documentation see ``is_power_of``. + For more documentation see :meth:`is_power_of`. AUTHORS: @@ -4955,7 +5022,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def is_power_of(Integer self, n): r""" - Returns ``True`` if there is an integer b with + Return ``True`` if there is an integer `b` with `\mathtt{self} = n^b`. .. SEEALSO:: @@ -4999,8 +5066,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): .. NOTE:: - For large integers self, is_power_of() is faster than - is_perfect_power(). The following examples gives some indication of + For large integers ``self``, :meth:`is_power_of` is faster than + :meth:`is_perfect_power`. The following examples give some indication of how much faster. :: @@ -5008,15 +5075,15 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: b = lcm(range(1,10000)) sage: b.exact_log(2) 14446 - sage: t=cputime() + sage: t = cputime() sage: for a in range(2, 1000): k = b.is_perfect_power() sage: cputime(t) # random 0.53203299999999976 - sage: t=cputime() + sage: t = cputime() sage: for a in range(2, 1000): k = b.is_power_of(2) sage: cputime(t) # random 0.0 - sage: t=cputime() + sage: t = cputime() sage: for a in range(2, 1000): k = b.is_power_of(3) sage: cputime(t) # random 0.032002000000000308 @@ -5026,19 +5093,20 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: b = lcm(range(1, 1000)) sage: b.exact_log(2) 1437 - sage: t=cputime() - sage: for a in range(2, 10000): k = b.is_perfect_power() # note that we change the range from the example above + sage: t = cputime() + sage: for a in range(2, 10000): # note: changed range from the example above + ....: k = b.is_perfect_power() sage: cputime(t) # random 0.17201100000000036 - sage: t=cputime(); TWO=int(2) + sage: t = cputime(); TWO = int(2) sage: for a in range(2, 10000): k = b.is_power_of(TWO) sage: cputime(t) # random 0.0040000000000000036 - sage: t=cputime() + sage: t = cputime() sage: for a in range(2, 10000): k = b.is_power_of(3) sage: cputime(t) # random 0.040003000000000011 - sage: t=cputime() + sage: t = cputime() sage: for a in range(2, 10000): k = b.is_power_of(a) sage: cputime(t) # random 0.02800199999999986 @@ -5079,6 +5147,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: 17.is_prime_power() True sage: 10.is_prime_power() @@ -5101,11 +5170,12 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): True sage: (p^97).is_prime_power() True - sage: (p+1).is_prime_power() + sage: (p + 1).is_prime_power() False With the ``get_data`` keyword set to ``True``:: + sage: # needs sage.libs.pari sage: (3^100).is_prime_power(get_data=True) (3, 100) sage: 12.is_prime_power(get_data=True) @@ -5117,23 +5187,44 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: (p*q).is_prime_power(get_data=True) (10000000000000000016800000000000000005031, 0) - The method works for large entries when `proof=False`:: + The method works for large entries when ``proof=False``:: sage: proof.arithmetic(False) - sage: ((10^500 + 961)^4).is_prime_power() + sage: ((10^500 + 961)^4).is_prime_power() # needs sage.libs.pari True sage: proof.arithmetic(True) We check that :trac:`4777` is fixed:: sage: n = 150607571^14 - sage: n.is_prime_power() + sage: n.is_prime_power() # needs sage.libs.pari True + + TESTS:: + + sage: 2.is_prime_power(get_data=True) + (2, 1) + sage: 4.is_prime_power(get_data=True) + (2, 2) + sage: 512.is_prime_power(get_data=True) + (2, 9) """ + cdef long n + if mpz_sgn(self.value) <= 0: return (self, zero) if get_data else False if mpz_fits_slong_p(self.value): + # Fast PARI-free path + n = mpz_get_si(self.value) + if not (n & 1): + if mpz_popcount(self.value) != 1: + return (self, zero) if get_data else False + return (smallInteger(2), smallInteger(mpz_sizeinbase(self.value, 2) - 1)) if get_data else True + if n < 1000: + if _small_primes_table[n >> 1]: + return (self, one) if get_data else True + global pari_is_prime_power if pari_is_prime_power is None: try: @@ -5143,7 +5234,6 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): if pari_is_prime_power is not None: return pari_is_prime_power(self, get_data) - cdef long n if proof is None: from sage.structure.proof.proof import get_flag proof = get_flag(proof, "arithmetic") @@ -5187,9 +5277,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): INPUT: - - ``proof`` -- Boolean or ``None`` (default). If False, use a + - ``proof`` -- Boolean or ``None`` (default). If ``False``, use a strong pseudo-primality test (see :meth:`is_pseudoprime`). - If True, use a provable primality test. If unset, use the + If ``True``, use a provable primality test. If unset, use the :mod:`default arithmetic proof flag <sage.structure.proof.proof>`. .. NOTE:: @@ -5201,7 +5291,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: sage: z = 2^31 - 1 - sage: z.is_prime() + sage: z.is_prime() # needs sage.libs.pari True sage: z = 2^31 sage: z.is_prime() @@ -5218,9 +5308,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): :: sage: z = 10^80 + 129 - sage: z.is_prime(proof=False) + sage: z.is_prime(proof=False) # needs sage.libs.pari True - sage: z.is_prime(proof=True) + sage: z.is_prime(proof=True) # needs sage.libs.pari True When starting Sage the arithmetic proof flag is True. We can change @@ -5229,17 +5319,17 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: proof.arithmetic() True sage: n = 10^100 + 267 - sage: timeit("n.is_prime()") # not tested + sage: timeit("n.is_prime()") # not tested # needs sage.libs.pari 5 loops, best of 3: 163 ms per loop sage: proof.arithmetic(False) sage: proof.arithmetic() False - sage: timeit("n.is_prime()") # not tested + sage: timeit("n.is_prime()") # not tested # needs sage.libs.pari 1000 loops, best of 3: 573 us per loop ALGORITHM: - Calls the PARI ``isprime`` function. + Calls the PARI function :pari:`isprime`. TESTS: @@ -5251,7 +5341,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ....: if tab[i]: ....: for j in range(2*i, size, i): ....: tab[j] = 0 - sage: all(ZZ(i).is_prime() == b for i,b in enumerate(tab)) + sage: all(ZZ(i).is_prime() == b for i,b in enumerate(tab)) # needs sage.libs.pari True """ if mpz_sgn(self.value) <= 0: @@ -5290,7 +5380,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): - ``self`` -- A PARI pseudoprime - - ``proof`` -- Mandatory proof flag (True, False or None) + - ``proof`` -- Mandatory proof flag (``True``, ``False`` or ``None``) OUTPUT: @@ -5308,13 +5398,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def is_irreducible(self): r""" - Returns ``True`` if self is irreducible, i.e. +/- + Return ``True`` if ``self`` is irreducible, i.e. +/- prime EXAMPLES:: sage: z = 2^31 - 1 - sage: z.is_irreducible() + sage: z.is_irreducible() # needs sage.libs.pari True sage: z = 2^31 sage: z.is_irreducible() @@ -5327,7 +5417,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): True """ cdef Integer n = self if self >= 0 else -self - return n.__pari__().isprime() + return n.is_prime(proof=True) def is_pseudoprime(self): r""" @@ -5335,7 +5425,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): This uses PARI's Baillie-PSW probabilistic primality test. Currently, there are no known pseudoprimes for - Baillie-PSW that are not actually prime. However it is + Baillie-PSW that are not actually prime. However, it is conjectured that there are infinitely many. See :wikipedia:`Baillie-PSW_primality_test` @@ -5343,10 +5433,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: sage: z = 2^31 - 1 - sage: z.is_pseudoprime() + sage: z.is_pseudoprime() # needs sage.libs.pari True sage: z = 2^31 - sage: z.is_pseudoprime() + sage: z.is_pseudoprime() # needs sage.libs.pari False """ return self.__pari__().ispseudoprime() @@ -5366,6 +5456,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: x = 10^200 + 357 sage: x.is_pseudoprime() True @@ -5386,21 +5477,21 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): False sage: (-1).is_pseudoprime_power() False - sage: 1.is_pseudoprime_power() + sage: 1.is_pseudoprime_power() # needs sage.libs.pari False """ return self.is_prime_power(proof=False, get_data=get_data) def is_perfect_power(self): r""" - Returns ``True`` if ``self`` is a perfect power, ie if there exist integers + Return ``True`` if ``self`` is a perfect power, ie if there exist integers `a` and `b`, `b > 1` with ``self`` `= a^b`. .. SEEALSO:: - :meth:`perfect_power`: Finds the minimal base for which this integer is a perfect power. - - :meth:`is_power_of`: If you know the base already this method is + - :meth:`is_power_of`: If you know the base already, this method is the fastest option. - :meth:`is_prime_power`: Checks whether the base is prime. @@ -5453,14 +5544,20 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: + sage: n = 7 + sage: n.is_norm(QQ) + True + sage: n.is_norm(QQ, element=True) + (True, 7) + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^2 - 2, 'beta') sage: n = 4 sage: n.is_norm(K) True sage: 5.is_norm(K) False - sage: 7.is_norm(QQ) - True sage: n.is_norm(K, element=True) (True, -4*beta + 6) sage: n.is_norm(K, element=True)[1].norm() @@ -5468,10 +5565,6 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: n = 5 sage: n.is_norm(K, element=True) (False, None) - sage: n = 7 - sage: n.is_norm(QQ, element=True) - (True, 7) - """ from sage.rings.rational_field import QQ return QQ(self).is_norm(K, element=element, proof=proof) @@ -5482,18 +5575,17 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: - sage: 3._bnfisnorm(QuadraticField(-1, 'i')) + sage: 3._bnfisnorm(QuadraticField(-1, 'i')) # needs sage.rings.number_field (1, 3) - sage: 7._bnfisnorm(CyclotomicField(7)) + sage: 7._bnfisnorm(CyclotomicField(7)) # needs sage.rings.number_field (zeta7^5 - zeta7^2, 1) """ from sage.rings.rational_field import QQ return QQ(self)._bnfisnorm(K, proof=proof, extra_primes=extra_primes) - def jacobi(self, b): r""" - Calculate the Jacobi symbol `\left(\frac{self}{b}\right)`. + Calculate the Jacobi symbol `\left(\frac{\text{self}}{b}\right)`. EXAMPLES:: @@ -5530,9 +5622,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def kronecker(self, b): r""" - Calculate the Kronecker symbol `\left(\frac{self}{b}\right)` - with the Kronecker extension `(self/2)=(2/self)` when `self` is odd, - or `(self/2)=0` when `self` is even. + Calculate the Kronecker symbol `\left(\frac{\text{self}}{b}\right)` + with the Kronecker extension `(\text{self}/2)=(2/\text{self})` when ``self`` is odd, + or `(\text{self}/2)=0` when ``self`` is even. EXAMPLES:: @@ -5561,13 +5653,14 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): INPUT: - - ``self`` -- an integer congruent to `0` or `1\mod4` which is + - ``self`` -- an integer congruent to `0` or `1` mod `4` which is not a square - - ``proof`` (boolean, default ``True``) -- if ``False`` then + - ``proof`` (boolean, default ``True``) -- if ``False``, then for negative discriminants a faster algorithm is used by the PARI library which is known to give incorrect results - when the class group has many cyclic factors. + when the class group has many cyclic factors. However, the + results are correct for discriminants `D` with `|D|\le 2\cdot10^{10}`. OUTPUT: @@ -5576,7 +5669,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): .. NOTE:: - This is not always equal to the number of classes of + For positive `D`, this is not always equal to the number of classes of primitive binary quadratic forms of discriminant `D`, which is equal to the narrow class number. The two notions are the same when `D<0`, or `D>0` and the fundamental unit of @@ -5585,11 +5678,11 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: - sage: (-163).class_number() + sage: (-163).class_number() # needs sage.libs.pari 1 - sage: (-104).class_number() + sage: (-104).class_number() # needs sage.libs.pari 6 - sage: [((4*n+1),(4*n+1).class_number()) for n in [21..29]] + sage: [((4*n + 1), (4*n + 1).class_number()) for n in [21..29]] # needs sage.libs.pari [(85, 2), (89, 1), (93, 1), @@ -5602,7 +5695,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): TESTS: - The integer must not be a square or an error is raised:: + The integer must not be a square, or an error is raised:: sage: 100.class_number() Traceback (most recent call last): @@ -5610,7 +5703,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ValueError: class_number not defined for square integers - The integer must be 0 or 1 mod 4 or an error is raised:: + The integer must be 0 or 1 mod 4, or an error is raised:: sage: 10.class_number() Traceback (most recent call last): @@ -5621,13 +5714,14 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ... ValueError: class_number only defined for integers congruent to 0 or 1 modulo 4 """ - global objtogen - if objtogen is None: - from cypari2.gen import objtogen if self.is_square(): raise ValueError("class_number not defined for square integers") if self % 4 not in [0, 1]: raise ValueError("class_number only defined for integers congruent to 0 or 1 modulo 4") + + global objtogen + if objtogen is None: + from cypari2.gen import objtogen flag = self < 0 and proof return objtogen(self).qfbclassno(flag).sage() @@ -5638,7 +5732,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): Use ``self.radical()`` for the product of the primes that divide self. - If self is 0, just returns 0. + If ``self`` is 0, just returns 0. EXAMPLES:: @@ -5670,8 +5764,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 2 sage: a.squarefree_part(bound=2**14) 2 - sage: a = 7^3 * next_prime(2^100)^2 * next_prime(2^200) - sage: a / a.squarefree_part(bound=1000) + sage: a = 7^3 * next_prime(2^100)^2 * next_prime(2^200) # needs sage.libs.pari + sage: a / a.squarefree_part(bound=1000) # needs sage.libs.pari 49 """ cdef Integer z @@ -5714,10 +5808,11 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def next_probable_prime(self): """ - Return the next probable prime after self, as determined by PARI. + Return the next probable prime after ``self``, as determined by PARI. EXAMPLES:: + sage: # needs sage.libs.pari sage: (-37).next_probable_prime() 2 sage: (100).next_probable_prime() @@ -5735,35 +5830,35 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def next_prime(self, proof=None): r""" - Return the next prime after self. + Return the next prime after ``self``. - This method calls the PARI ``nextprime`` function. + This method calls the PARI function :pari:`nextprime`. INPUT: - ``proof`` - bool or None (default: None, see - proof.arithmetic or sage.structure.proof) Note that the global Sage - default is proof=True + ``proof.arithmetic`` or :mod:`sage.structure.proof`) Note that the global Sage + default is ``proof=True`` EXAMPLES:: - sage: 100.next_prime() + sage: 100.next_prime() # needs sage.libs.pari 101 - sage: (10^50).next_prime() + sage: (10^50).next_prime() # needs sage.libs.pari 100000000000000000000000000000000000000000000000151 Use ``proof=False``, which is way faster since it does not need a primality proof:: - sage: b = (2^1024).next_prime(proof=False) - sage: b - 2^1024 + sage: b = (2^1024).next_prime(proof=False) # needs sage.libs.pari + sage: b - 2^1024 # needs sage.libs.pari 643 :: - sage: Integer(0).next_prime() + sage: Integer(0).next_prime() # needs sage.libs.pari 2 - sage: Integer(1001).next_prime() + sage: Integer(1001).next_prime() # needs sage.libs.pari 1009 """ # Use PARI to compute the next *pseudo*-prime @@ -5774,9 +5869,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def previous_prime(self, proof=None): r""" - Returns the previous prime before self. + Return the previous prime before ``self``. - This method calls the PARI ``precprime`` function. + This method calls the PARI function :pari:`precprime`. INPUT: @@ -5792,11 +5887,11 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: - sage: 10.previous_prime() + sage: 10.previous_prime() # needs sage.libs.pari 7 - sage: 7.previous_prime() + sage: 7.previous_prime() # needs sage.libs.pari 5 - sage: 14376485.previous_prime() + sage: 14376485.previous_prime() # needs sage.libs.pari 14376463 sage: 2.previous_prime() @@ -5807,8 +5902,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): An example using ``proof=False``, which is way faster since it does not need a primality proof:: - sage: b = (2^1024).previous_prime(proof=False) - sage: 2^1024 - b + sage: b = (2^1024).previous_prime(proof=False) # needs sage.libs.pari + sage: 2^1024 - b # needs sage.libs.pari 105 """ if mpz_cmp_ui(self.value, 2) <= 0: @@ -5822,7 +5917,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def next_prime_power(self, proof=None): r""" - Return the next prime power after self. + Return the next prime power after ``self``. INPUT: @@ -5834,7 +5929,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ALGORITHM: - The algorithm is naive. It computes the next power of 2 and go through + The algorithm is naive. It computes the next power of 2 and goes through the odd numbers calling :meth:`is_prime_power`. .. SEEALSO:: @@ -5850,21 +5945,21 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 2 sage: 2.next_prime_power() 3 - sage: 103.next_prime_power() + sage: 103.next_prime_power() # needs sage.libs.pari 107 sage: 107.next_prime_power() 109 - sage: 2044.next_prime_power() + sage: 2044.next_prime_power() # needs sage.libs.pari 2048 TESTS:: - sage: [(2**k-1).next_prime_power() for k in range(1,10)] + sage: [(2**k - 1).next_prime_power() for k in range(1,10)] [2, 4, 8, 16, 32, 64, 128, 256, 512] - sage: [(2**k).next_prime_power() for k in range(10)] + sage: [(2**k).next_prime_power() for k in range(10)] # needs sage.libs.pari [2, 3, 5, 9, 17, 37, 67, 131, 257, 521] - sage: for _ in range(10): + sage: for _ in range(10): # needs sage.libs.pari ....: n = ZZ.random_element(2**256).next_prime_power() ....: m = n.next_prime_power().previous_prime_power() ....: assert m == n, "problem with n = {}".format(n) @@ -5888,7 +5983,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def previous_prime_power(self, proof=None): r""" - Return the previous prime power before self. + Return the previous prime power before ``self``. INPUT: @@ -5900,7 +5995,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ALGORITHM: - The algorithm is naive. It computes the previous power of 2 and go + The algorithm is naive. It computes the previous power of 2 and goes through the odd numbers calling the method :meth:`is_prime_power`. .. SEEALSO:: @@ -5912,6 +6007,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: 3.previous_prime_power() 2 sage: 103.previous_prime_power() @@ -5928,12 +6024,12 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): TESTS:: - sage: [(2**k+1).previous_prime_power() for k in range(1,10)] + sage: [(2**k + 1).previous_prime_power() for k in range(1,10)] [2, 4, 8, 16, 32, 64, 128, 256, 512] - sage: [(2**k).previous_prime_power() for k in range(2, 10)] + sage: [(2**k).previous_prime_power() for k in range(2, 10)] # needs sage.libs.pari [3, 7, 13, 31, 61, 127, 251, 509] - sage: for _ in range(10): + sage: for _ in range(10): # needs sage.libs.pari ....: n = ZZ.random_element(3,2**256).previous_prime_power() ....: m = n.previous_prime_power().next_prime_power() ....: assert m == n, "problem with n = {}".format(n) @@ -5959,7 +6055,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def additive_order(self): """ - Return the additive order of self. + Return the additive order of ``self``. EXAMPLES:: @@ -5975,7 +6071,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def multiplicative_order(self): r""" - Return the multiplicative order of self. + Return the multiplicative order of ``self``. EXAMPLES:: @@ -5997,37 +6093,105 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def is_squarefree(self): """ - Returns True if this integer is not divisible by the square of any - prime and False otherwise. + Return ``True`` if this integer is not divisible by the square of any + prime and ``False`` otherwise. EXAMPLES:: - sage: 100.is_squarefree() + sage: 100.is_squarefree() # needs sage.libs.pari False - sage: 102.is_squarefree() + sage: 102.is_squarefree() # needs sage.libs.pari True - sage: 0.is_squarefree() + sage: 0.is_squarefree() # needs sage.libs.pari False """ return self.__pari__().issquarefree() + def is_discriminant(self): + """ + Return ``True`` if this integer is a discriminant. + + .. NOTE:: + + A discriminant is an integer congruent to 0 or 1 modulo 4. + + EXAMPLES:: + + sage: (-1).is_discriminant() + False + sage: (-4).is_discriminant() + True + sage: 100.is_discriminant() + True + sage: 101.is_discriminant() + True + + TESTS:: + + sage: 0.is_discriminant() + True + sage: 1.is_discriminant() + True + sage: len([D for D in srange(-100,100) if D.is_discriminant()]) + 100 + """ + return self%4 in [0,1] + + def is_fundamental_discriminant(self): + """ + Return ``True`` if this integer is a fundamental discriminant. + + .. NOTE:: + + A fundamental discriminant is a discrimimant, not 0 or 1 and not a square multiple of a smaller discriminant. + + EXAMPLES:: + + sage: (-4).is_fundamental_discriminant() # needs sage.libs.pari + True + sage: (-12).is_fundamental_discriminant() + False + sage: 101.is_fundamental_discriminant() # needs sage.libs.pari + True + + TESTS:: + + sage: 0.is_fundamental_discriminant() + False + sage: 1.is_fundamental_discriminant() + False + sage: len([D for D in srange(-100,100) # needs sage.libs.pari + ....: if D.is_fundamental_discriminant()]) + 61 + + """ + if self in [0,1]: + return False + Dmod4 = self%4 + if Dmod4 in [2,3]: + return False + if Dmod4 == 1: + return self.is_squarefree() + d = self//4 + return d%4 in [2,3] and d.is_squarefree() + cpdef __pari__(self): """ - Returns the PARI version of this integer. + Return the PARI version of this integer. EXAMPLES:: sage: n = 9390823 - sage: m = n.__pari__(); m + sage: m = n.__pari__(); m # needs sage.libs.pari 9390823 - sage: type(m) + sage: type(m) # needs sage.libs.pari <class 'cypari2.gen.Gen'> TESTS:: sage: n = 10^10000000 - sage: m = n.__pari__() # crash from trac 875 - sage: m % 1234567 + sage: m = n.__pari__() # crash from trac 875 # needs sage.libs.pari + sage: m % 1234567 # needs sage.libs.pari 1041334 """ @@ -6057,18 +6221,17 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: + sage: # needs numpy sage: import numpy sage: numpy.array([1, 2, 3]) array([1, 2, 3]) sage: numpy.array([1, 2, 3]).dtype dtype('int32') # 32-bit dtype('int64') # 64-bit - sage: numpy.array(2**40).dtype dtype('int64') sage: numpy.array(2**400).dtype dtype('O') - sage: numpy.array([1,2,3,0.1]).dtype dtype('float64') """ @@ -6096,11 +6259,12 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): '117' Large integers use hex: - sage: m = 3^(2^20) # optional - magma - sage: s = m._magma_init_(magma) # optional - magma - sage: 'StringToInteger' in s # optional - magma + sage: # optional - magma + sage: m = 3^(2^20) + sage: s = m._magma_init_(magma) + sage: 'StringToInteger' in s True - sage: magma(m).sage() == m # optional - magma + sage: magma(m).sage() == m True """ if self.ndigits(2) > 10000: @@ -6151,9 +6315,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def sqrtrem(self): r""" - Return (s, r) where s is the integer square root of self and - r is the remainder such that `\text{self} = s^2 + r`. - Raises ``ValueError`` if self is negative. + Return `(s, r)` where `s` is the integer square root of ``self`` and + `r` is the remainder such that `\text{self} = s^2 + r`. + Raises :class:`ValueError` if ``self`` is negative. EXAMPLES:: @@ -6181,8 +6345,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def isqrt(self): r""" - Returns the integer floor of the square root of self, or raises an - ``ValueError`` if self is negative. + Return the integer floor of the square root of ``self``, or raises an + :class:`ValueError` if ``self`` is negative. EXAMPLES:: @@ -6214,17 +6378,17 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): INPUT: - - ``prec`` - integer (default: None): if None, return an exact + - ``prec`` -- integer (default: ``None``): if ``None``, return an exact square root; otherwise return a numerical square root, to the given bits of precision. - - ``extend`` - bool (default: True); if True, return a + - ``extend`` -- bool (default: ``True``); if ``True``, return a square root in an extension ring, if necessary. Otherwise, raise a - ValueError if the square is not in the base ring. Ignored if prec - is not None. + :class:`ValueError` if the square is not in the base ring. Ignored if ``prec`` + is not ``None``. - - ``all`` - bool (default: False); if True, return all - square roots of self (a list of length 0, 1 or 2). + - ``all`` - bool (default: ``False``); if ``True``, return all + square roots of ``self`` (a list of length 0, 1, or 2). EXAMPLES:: @@ -6232,19 +6396,19 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 12 sage: sqrt(Integer(144)) 12 - sage: Integer(102).sqrt() + sage: Integer(102).sqrt() # needs sage.symbolic sqrt(102) :: sage: n = 2 - sage: n.sqrt(all=True) + sage: n.sqrt(all=True) # needs sage.symbolic [sqrt(2), -sqrt(2)] - sage: n.sqrt(prec=10) + sage: n.sqrt(prec=10) # needs sage.rings.real_mpfr 1.4 - sage: n.sqrt(prec=100) + sage: n.sqrt(prec=100) # needs sage.rings.real_mpfr 1.4142135623730950488016887242 - sage: n.sqrt(prec=100,all=True) + sage: n.sqrt(prec=100, all=True) # needs sage.rings.real_mpfr [1.4142135623730950488016887242, -1.4142135623730950488016887242] sage: n.sqrt(extend=False) Traceback (most recent call last): @@ -6261,13 +6425,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): TESTS:: - sage: type(5.sqrt()) + sage: type(5.sqrt()) # needs sage.symbolic <class 'sage.symbolic.expression.Expression'> - sage: type(5.sqrt(prec=53)) + sage: type(5.sqrt(prec=53)) # needs sage.rings.real_mpfr <class 'sage.rings.real_mpfr.RealNumber'> - sage: type((-5).sqrt(prec=53)) + sage: type((-5).sqrt(prec=53)) # needs sage.rings.real_mpfr <class 'sage.rings.complex_mpfr.ComplexNumber'> - sage: type(0.sqrt(prec=53)) + sage: type(0.sqrt(prec=53)) # needs sage.rings.real_mpfr <class 'sage.rings.real_mpfr.RealNumber'> Check that :trac:`9466` and :trac:`26509` are fixed:: @@ -6479,12 +6643,12 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cpdef _shift_helper(Integer self, y, int sign): """ - Function used to compute left and right shifts of integers. - Shifts self y bits to the left if sign is 1, and to the right - if sign is -1. + Compute left and right shifts of integers. + Shifts ``self`` ``y`` bits to the left if ``sign`` is `1`, and to the right + if ``sign`` is `-1`. WARNING: This function does no error checking. In particular, - it assumes that sign is either 1 or -1, + it assumes that ``sign`` is either `1` or `-1`. EXAMPLES:: @@ -6509,7 +6673,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: try: ....: print('Possible error output from gmp', flush=True) ....: 1 << (2^60) - ....: except (MemoryError, OverflowError, RuntimeError): + ....: except (MemoryError, OverflowError, RuntimeError, FloatingPointError): ....: pass ....: else: ....: print("Failed to raise exception") @@ -6519,7 +6683,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): if type(y) is int: # For a Python int, we can just use the Python/C API. - n = PyInt_AS_LONG(y) + n = PyLong_AsLong(y) else: # If it's not already an Integer, try to convert it. if not isinstance(y, Integer): @@ -6661,7 +6825,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def __invert__(self): """ - Return the multiplicative inverse of self, as a rational number. + Return the multiplicative inverse of ``self``, as a rational number. EXAMPLES:: @@ -6687,8 +6851,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def inverse_of_unit(self): """ - Return inverse of self if self is a unit in the integers, i.e., - self is -1 or 1. Otherwise, raise a ZeroDivisionError. + Return inverse of ``self`` if ``self`` is a unit in the integers, i.e., + ``self`` is `-1` or `1`. Otherwise, raise a :class:`ZeroDivisionError`. EXAMPLES:: @@ -6712,9 +6876,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def inverse_mod(self, n): r""" - Return the inverse of self modulo `n`, if this inverse exists. + Return the inverse of ``self`` modulo `n`, if this inverse exists. - Otherwise, raises a ``ZeroDivisionError`` exception. + Otherwise, raise a :class:`ZeroDivisionError` exception. INPUT: @@ -6729,7 +6893,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): IMPLEMENTATION: - Call the mpz_invert GMP library function. + Call the ``mpz_invert`` GMP library function. EXAMPLES:: @@ -6835,7 +6999,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def popcount(self): """ Return the number of 1 bits in the binary representation. - If self<0, we return Infinity. + If ``self`` < 0, we return Infinity. EXAMPLES:: @@ -6869,7 +7033,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def binomial(self, m, algorithm='gmp'): """ - Return the binomial coefficient "self choose m". + Return the binomial coefficient "``self`` choose ``m``". INPUT: @@ -6879,15 +7043,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ``gmp``), or ``'pari'``; ``'gmp'`` is faster for small ``m``, and ``'pari'`` tends to be faster for large ``m`` - OUTPUT: - - - integer + OUTPUT: integer EXAMPLES:: sage: 10.binomial(2) 45 - sage: 10.binomial(2, algorithm='pari') + sage: 10.binomial(2, algorithm='pari') # needs sage.libs.pari 45 sage: 10.binomial(-2) 0 @@ -6896,11 +7058,11 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: (-3).binomial(0) 1 - The argument ``m`` or (``self-m``) must fit into unsigned long:: + The argument ``m`` or (``self - m``) must fit into an ``unsigned long``:: sage: (2**256).binomial(2**256) 1 - sage: (2**256).binomial(2**256-1) + sage: (2**256).binomial(2**256 - 1) 115792089237316195423570985008687907853269984665640564039457584007913129639936 sage: (2**256).binomial(2**128) Traceback (most recent call last): @@ -6929,7 +7091,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): check for reliable interrupting, see :trac:`18919`:: sage: from cysignals import AlarmInterrupt - sage: for i in [1..10]: # long time (5s) + sage: for i in [1..10]: # long time (5s) # needs sage.libs.pari ....: try: ....: alarm(i/11) ....: (2^100).binomial(2^22, algorithm='pari') @@ -7180,7 +7342,7 @@ def GCD_list(v): @cython.binding(True) def make_integer(s): """ - Create a Sage integer from the base-32 Python *string* s. This is + Create a Sage integer from the base-32 Python *string* ``s``. This is used in unpickling integers. EXAMPLES:: @@ -7253,7 +7415,7 @@ cdef class int_to_Z(Morphism): cpdef Element _call_(self, a): """ - Returns a new integer with the same value as a. + Return a new integer with the same value as ``a``. TESTS:: @@ -7264,7 +7426,7 @@ cdef class int_to_Z(Morphism): if type(a) is not int: raise TypeError("must be a Python int object") - return smallInteger(PyInt_AS_LONG(a)) + return smallInteger(PyLong_AsLong(a)) def _repr_type(self): """ @@ -7326,7 +7488,7 @@ _mpz_realloc(global_dummy_Integer.value, 1) def _check_global_dummy_Integer(): """ - Return true if the global dummy Integer is ok. + Return ``True`` if the global dummy :class:`Integer` is ok. TESTS:: @@ -7537,7 +7699,8 @@ cdef Integer zero = the_integer_ring._zero_element cdef Integer one = the_integer_ring._one_element # pool of small integer for fast sign computation -# Use the same defaults as Python, documented at https://docs.python.org/2/c-api/int.html#PyInt_FromLong +# Use the same defaults as Python3 documented at +# https://docs.python.org/3/c-api/long.html#c.PyLong_FromLong DEF small_pool_min = -5 DEF small_pool_max = 256 # we could use the above zero and one here diff --git a/src/sage/rings/integer_fake.pxd b/src/sage/rings/integer_fake.pxd index de7672fa22e..4a02062c64b 100644 --- a/src/sage/rings/integer_fake.pxd +++ b/src/sage/rings/integer_fake.pxd @@ -17,7 +17,8 @@ This provides two functions: TESTS:: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' ....: from sage.rings.integer_fake cimport Integer_AS_MPZ, is_Integer ....: from sage.rings.integer cimport Integer ....: cdef Integer x = Integer(123456789) diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index 7ba77ca2aa2..c7a05a13e16 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -43,7 +43,7 @@ other types will also coerce to the integers, when it makes sense. # http://www.gnu.org/licenses/ #***************************************************************************** -from cpython.int cimport * +from cpython.long cimport * from cpython.list cimport * from cpython.object cimport Py_NE @@ -58,18 +58,16 @@ import sage.libs.pari.all import sage.rings.ideal from sage.categories.basic import EuclideanDomains from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +from sage.rings.number_field.number_field_element_base import NumberFieldElement_base from sage.structure.coerce cimport is_numpy_type from sage.structure.element cimport parent from sage.structure.parent_gens import ParentWithGens -from sage.structure.parent cimport Parent from sage.structure.richcmp cimport rich_to_bool -from sage.structure.sequence import Sequence from sage.misc.misc_c import prod from sage.misc.randstate cimport randstate, current_randstate, SAGE_RAND_MAX cimport sage.rings.integer as integer -cimport sage.rings.rational as rational from . import ring @@ -125,8 +123,8 @@ cdef class IntegerRing_class(PrincipalIdealDomain): False sage: Z.category() Join of Category of euclidean domains - and Category of infinite enumerated sets - and Category of metric spaces + and Category of infinite enumerated sets + and Category of metric spaces sage: Z(2^(2^5) + 1) 4294967297 @@ -150,9 +148,9 @@ cdef class IntegerRing_class(PrincipalIdealDomain): The lists are interpreted in little-endian order, so that entry ``i`` of the list is the coefficient of ``base^i``:: - sage: Z([4,1,7],base=100) + sage: Z([4,1,7], base=100) 70104 - sage: Z([4,1,7],base=10) + sage: Z([4,1,7], base=10) 714 sage: Z([3, 7], 10) 73 @@ -165,13 +163,13 @@ cdef class IntegerRing_class(PrincipalIdealDomain): ``z`` represent numbers 10 to 36. Letter case does not matter. :: - sage: Z("sage",base=32) + sage: Z("sage", base=32) 928270 - sage: Z("SAGE",base=32) + sage: Z("SAGE", base=32) 928270 - sage: Z("Sage",base=32) + sage: Z("Sage", base=32) 928270 - sage: Z([14, 16, 10, 28],base=32) + sage: Z([14, 16, 10, 28], base=32) 928270 sage: 14 + 16*32 + 10*32^2 + 28*32^3 928270 @@ -247,23 +245,23 @@ cdef class IntegerRing_class(PrincipalIdealDomain): 17 sage: Z(Mod(19,23)) 19 - sage: Z(2 + 3*5 + O(5^3)) + sage: Z(2 + 3*5 + O(5^3)) # needs sage.rings.padics 17 Arbitrary numeric bases are supported; strings or list of integers are used to provide the digits (more details in :class:`IntegerRing_class`):: - sage: Z("sage",base=32) + sage: Z("sage", base=32) 928270 - sage: Z([14, 16, 10, 28],base=32) + sage: Z([14, 16, 10, 28], base=32) 928270 The :meth:`digits<~sage.rings.integer.Integer.digits>` method allows you to get the list of digits of an integer in a different basis (note that the digits are returned in little-endian order):: - sage: b = Z([4,1,7],base=100) + sage: b = Z([4,1,7], base=100) sage: b 70104 sage: b.digits(base=71) @@ -396,17 +394,19 @@ cdef class IntegerRing_class(PrincipalIdealDomain): EXAMPLES:: - sage: ZZ[sqrt(2), sqrt(3)] - Relative Order in Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field sage: ZZ['x'] Univariate Polynomial Ring in x over Integer Ring sage: ZZ['x,y'] Multivariate Polynomial Ring in x, y over Integer Ring + + sage: # needs sage.rings.number_field sage.symbolic + sage: ZZ[sqrt(2), sqrt(3)] + Relative Order in Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field sage: R = ZZ[sqrt(5) + 1]; R Order in Number Field in a with defining polynomial x^2 - 2*x - 4 with a = 3.236067977499790? sage: R.is_maximal() False - sage: R = ZZ[(1+sqrt(5))/2]; R + sage: R = ZZ[(1 + sqrt(5))/2]; R Order in Number Field in a with defining polynomial x^2 - x - 1 with a = 1.618033988749895? sage: R.is_maximal() True @@ -414,9 +414,8 @@ cdef class IntegerRing_class(PrincipalIdealDomain): if x in self: return self - from sage.rings.number_field.number_field_element import NumberFieldElement - if isinstance(x, NumberFieldElement): - K, from_K = parent(x).subfield(x) + if isinstance(x, NumberFieldElement_base): + K, _ = parent(x).subfield(x) return K.order(K.gen()) return PrincipalIdealDomain.__getitem__(self, x) @@ -433,23 +432,25 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: ZZ.range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - sage: ZZ.range(-5,5) + sage: ZZ.range(-5, 5) [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4] - sage: ZZ.range(0,50,5) + sage: ZZ.range(0, 50, 5) [0, 5, 10, 15, 20, 25, 30, 35, 40, 45] - sage: ZZ.range(0,50,-5) + sage: ZZ.range(0, 50, -5) [] - sage: ZZ.range(50,0,-5) + sage: ZZ.range(50, 0, -5) [50, 45, 40, 35, 30, 25, 20, 15, 10, 5] - sage: ZZ.range(50,0,5) + sage: ZZ.range(50, 0, 5) [] - sage: ZZ.range(50,-1,-5) + sage: ZZ.range(50, -1, -5) [50, 45, 40, 35, 30, 25, 20, 15, 10, 5, 0] It uses different code if the step doesn't fit in a long:: - sage: ZZ.range(0,2^83,2^80) - [0, 1208925819614629174706176, 2417851639229258349412352, 3626777458843887524118528, 4835703278458516698824704, 6044629098073145873530880, 7253554917687775048237056, 8462480737302404222943232] + sage: ZZ.range(0, 2^83, 2^80) + [0, 1208925819614629174706176, 2417851639229258349412352, + 3626777458843887524118528, 4835703278458516698824704, 6044629098073145873530880, + 7253554917687775048237056, 8462480737302404222943232] Make sure :trac:`8818` is fixed:: @@ -479,7 +480,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): L = [] if type(step) is int: - istep = PyInt_AS_LONG(step) + istep = PyLong_AsLong(step) step_sign = istep else: zstep = <Integer>step @@ -554,6 +555,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): Coercions are available from numpy integer types:: + sage: # needs numpy sage: import numpy sage: ZZ.coerce(numpy.int8('1')) 1 @@ -601,10 +603,11 @@ cdef class IntegerRing_class(PrincipalIdealDomain): - ``x``, ``y`` integers -- bounds for the result. - ``distribution``-- a string: - - ``'uniform'`` - - ``'mpz_rrandomb'`` - - ``'1/n'`` - - ``'gaussian'`` + + - ``'uniform'`` + - ``'mpz_rrandomb'`` + - ``'1/n'`` + - ``'gaussian'`` OUTPUT: @@ -666,7 +669,8 @@ cdef class IntegerRing_class(PrincipalIdealDomain): ....: counter += 1 ....: dic[ZZ.random_element(*args, **kwds)] += 1 - sage: prob = lambda x : 1/5 + sage: def prob(x): + ....: return 1/5 sage: dic = defaultdict(Integer) sage: counter = 0.0 sage: add_samples(distribution="uniform") @@ -690,7 +694,8 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: -10 <= ZZ.random_element(-10, 10) < 10 True - sage: prob = lambda x : 1/20 + sage: def prob(x): + ....: return 1/20 sage: dic = defaultdict(Integer) sage: counter = 0.0 sage: add_samples(-10, 10) @@ -699,7 +704,8 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: 0 <= ZZ.random_element(5) < 5 True - sage: prob = lambda x : 1/5 + sage: def prob(x): + ....: return 1/5 sage: dic = defaultdict(Integer) sage: counter = 0.0 sage: add_samples(5) @@ -716,7 +722,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): We return a sample from a discrete Gaussian distribution:: - sage: ZZ.random_element(11.0, distribution="gaussian").parent() is ZZ + sage: ZZ.random_element(11.0, distribution="gaussian").parent() is ZZ # needs sage.modules True TESTS: @@ -725,7 +731,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: ZZ.random_element(5, -5, distribution="1/n").parent() is ZZ True - sage: ZZ.random_element(5, -5, distribution="gaussian").parent() is ZZ + sage: ZZ.random_element(5, -5, distribution="gaussian").parent() is ZZ # needs sage.modules True sage: ZZ.random_element(5, -5, distribution="mpz_rrandomb").parent() is ZZ True @@ -831,7 +837,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): True sage: ZZ._is_valid_homomorphism_(ZZ,[2]) False - sage: ZZ._is_valid_homomorphism_(ZZ.quotient_ring(8),[ZZ.quotient_ring(8)(1)]) + sage: ZZ._is_valid_homomorphism_(ZZ.quotient_ring(8), [ZZ.quotient_ring(8)(1)]) True """ if base_map is None: @@ -920,11 +926,12 @@ cdef class IntegerRing_class(PrincipalIdealDomain): EXAMPLES:: - sage: ZZ.extension(x^2-5, 'a') + sage: x = polygen(ZZ, 'x') + sage: ZZ.extension(x^2 - 5, 'a') # needs sage.rings.number_field Order in Number Field in a with defining polynomial x^2 - 5 - sage: ZZ.extension([x^2 + 1, x^2 + 2], 'a,b') - Relative Order in Number Field in a with defining polynomial - x^2 + 1 over its base field + sage: ZZ.extension([x^2 + 1, x^2 + 2], 'a,b') # needs sage.rings.number_field + Relative Order in Number Field in a + with defining polynomial x^2 + 1 over its base field """ from sage.rings.number_field.order import EquationOrder return EquationOrder(poly, names=names, **kwds) @@ -976,6 +983,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): EXAMPLES:: + sage: # needs sage.libs.pari sage: F = ZZ.residue_field(61); F Residue field of Integers modulo 61 sage: pi = F.reduction_map(); pi @@ -1160,7 +1168,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: ZZ.completion(infinity, 53) Integer Ring - sage: ZZ.completion(5, 15, {'print_mode': 'bars'}) + sage: ZZ.completion(5, 15, {'print_mode': 'bars'}) # needs sage.rings.padics 5-adic Ring with capped relative precision 15 """ if p == sage.rings.infinity.Infinity: @@ -1273,6 +1281,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): TESTS:: + sage: # needs sage.libs.pari sage: R.<x> = PolynomialRing(ZZ, sparse=True) sage: p = (x + 1)^23 * (x - 1)^23 * (x - 100) * (x + 5445)^5 sage: ZZ._roots_univariate_polynomial(p) @@ -1290,13 +1299,13 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: ZZ._roots_univariate_polynomial(p, multiplicities=False) [0, 1, -1, 100, -5445] + sage: # needs sage.libs.pari sage: R.<x> = PolynomialRing(ZZ, sparse=False) sage: p = (x + 1)^23 * (x - 1)^23 * (x - 100) * (x + 5445)^5 sage: ZZ._roots_univariate_polynomial(p) [(100, 1), (-5445, 5), (1, 23), (-1, 23)] sage: ZZ._roots_univariate_polynomial(p, multiplicities=False) [100, -5445, 1, -1] - sage: ZZ._roots_univariate_polynomial(p, algorithm="sparse") [(100, 1), (-5445, 5), (1, 23), (-1, 23)] sage: ZZ._roots_univariate_polynomial(p, algorithm="dense") @@ -1306,10 +1315,10 @@ cdef class IntegerRing_class(PrincipalIdealDomain): ... ValueError: unknown algorithm 'foobar' - sage: p = x^20 * p - sage: ZZ._roots_univariate_polynomial(p, algorithm="sparse") + sage: p = x^20 * p # needs sage.libs.pari + sage: ZZ._roots_univariate_polynomial(p, algorithm="sparse") # needs sage.libs.pari [(0, 20), (100, 1), (-5445, 5), (1, 23), (-1, 23)] - sage: ZZ._roots_univariate_polynomial(p, algorithm="dense") + sage: ZZ._roots_univariate_polynomial(p, algorithm="dense") # needs sage.libs.pari [(100, 1), (-5445, 5), (0, 20), (1, 23), (-1, 23)] """ deg = p.degree() @@ -1452,17 +1461,17 @@ cdef class IntegerRing_class(PrincipalIdealDomain): return roots - ################################# - ## Coercions to interfaces + # Coercions to interfaces ################################# + def _gap_init_(self): """ Return a GAP representation of ``self``. EXAMPLES:: - sage: gap(ZZ) # indirect doctest + sage: gap(ZZ) # indirect doctest # needs sage.libs.gap Integers """ return 'Integers' @@ -1495,7 +1504,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): EXAMPLES:: - sage: macaulay2(ZZ) #optional - macaulay2 + sage: macaulay2(ZZ) # optional - macaulay2 ZZ """ return "ZZ" @@ -1518,7 +1527,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): EXAMPLES:: - sage: ZZ._sympy_() + sage: ZZ._sympy_() # needs sympy Integers """ from sympy import Integers @@ -1548,9 +1557,9 @@ cdef class IntegerRing_class(PrincipalIdealDomain): EXAMPLES:: - sage: v = ZZ.valuation(3); v + sage: v = ZZ.valuation(3); v # needs sage.rings.padics 3-adic valuation - sage: v(3) + sage: v(3) # needs sage.rings.padics 1 .. SEEALSO:: @@ -1648,7 +1657,7 @@ def crt_basis(X, xgcd=None): for i in range(len(X)): p = X[i] others = P // p - g, s, t = p.xgcd(others) + g, _, t = p.xgcd(others) if g != ONE: raise ArithmeticError("the elements of the list X must be coprime in pairs") Y.append(t * others) diff --git a/src/sage/rings/invariants/__init__.py b/src/sage/rings/invariants/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/rings/invariants/invariant_theory.py b/src/sage/rings/invariants/invariant_theory.py index 0c0aa1c9f69..a2ee2268c6f 100644 --- a/src/sage/rings/invariants/invariant_theory.py +++ b/src/sage/rings/invariants/invariant_theory.py @@ -140,15 +140,15 @@ def _guess_variables(polynomial, *args): sage: from sage.rings.invariants.invariant_theory import _guess_variables sage: R.<x,y> = QQ[] - sage: _guess_variables(x^2+y^2) + sage: _guess_variables(x^2 + y^2) (x, y) sage: _guess_variables([x^2, y^2]) (x, y) - sage: _guess_variables(x^2+y^2, x) + sage: _guess_variables(x^2 + y^2, x) (x,) - sage: _guess_variables(x^2+y^2, x,y) + sage: _guess_variables(x^2 + y^2, x, y) (x, y) - sage: _guess_variables(x^2+y^2, [x,y]) + sage: _guess_variables(x^2 + y^2, [x,y]) (x, y) """ if isinstance(polynomial, (list, tuple)): @@ -177,7 +177,7 @@ def transvectant(f, g, h=1, scale='default'): INPUT: - - ``f,g`` -- two homogeneous binary forms in the same polynomial ring. + - ``f``, ``g`` -- two homogeneous binary forms in the same polynomial ring. - ``h`` -- the order of the transvectant. If it is not specified, the first transvectant is returned. @@ -214,9 +214,10 @@ def transvectant(f, g, h=1, scale='default'): factor will not be invertible in that case. The scale argument ``'none'`` can be used to compute the transvectant in this case:: + sage: # needs sage.rings.finite_rings sage: R.<a0,a1,a2,a3,a4,a5,x0,x1> = GF(5)[] - sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5 - sage: f = AlgebraicForm(2, 5, p, x0, x1) + sage: f = AlgebraicForm(2, 5, a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + ....: + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5, x0, x1) sage: transvectant(f, f, 4) Traceback (most recent call last): ... @@ -230,8 +231,8 @@ def transvectant(f, g, h=1, scale='default'): it to the scaled version:: sage: R.<a0,a1,a2,a3,a4,a5,x0,x1> = QQ[] - sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5 - sage: f = AlgebraicForm(2, 5, p, x0, x1) + sage: f = AlgebraicForm(2, 5, a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + ....: + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5, x0, x1) sage: transvectant(f, f, 4) Binary quadratic given by 3/50*a3^2*x0^2 - 4/25*a2*a4*x0^2 + 2/5*a1*a5*x0^2 + 1/25*a2*a3*x0*x1 - 6/25*a1*a4*x0*x1 + 2*a0*a5*x0*x1 @@ -247,14 +248,14 @@ def transvectant(f, g, h=1, scale='default'): one variable:: sage: R.<x,y> = QQ[] - sage: quintic = invariant_theory.binary_quintic(x^5+x^3+2*x^2+y^5, x) + sage: quintic = invariant_theory.binary_quintic(x^5 + x^3 + 2*x^2 + y^5, x) sage: transvectant(quintic, quintic, 2) Traceback (most recent call last): ... ValueError: polynomial is not homogeneous sage: R.<y> = QQ[] sage: S.<x> = R[] - sage: quintic = invariant_theory.binary_quintic(x^5+x^3+2*x^2+y^5, x) + sage: quintic = invariant_theory.binary_quintic(x^5 + x^3 + 2*x^2 + y^5, x) sage: transvectant(quintic, quintic, 2) Binary sextic given by 1/5*x^6 + 6/5*x^5*h - 3/25*x^4*h^2 + (50*y^5 - 8)/25*x^3*h^3 - 12/25*x^2*h^4 + (3*y^5)/5*x*h^5 @@ -278,7 +279,7 @@ def transvectant(f, g, h=1, scale='default'): elif scale == 'none': scalar = 1 else: - raise ValueError('unknown scale type: %s' %scale) + raise ValueError('unknown scale type: %s' % scale) def diff(j): df = f.form().derivative(x,j).derivative(y,h-j) @@ -325,7 +326,6 @@ def __init__(self, n, homogeneous, ring, variables): self._ring = ring self._variables = variables - def _jacobian_determinant(self, *args): """ Return the Jacobian determinant. @@ -372,7 +372,6 @@ def diff(p, d): jac = [diff(p,d) for p,d in args] return matrix(self._ring, jac).det() - def ring(self): """ Return the polynomial ring. @@ -387,18 +386,17 @@ def ring(self): EXAMPLES:: sage: R.<x,y,t> = QQ[] - sage: quartic = invariant_theory.binary_quartic(x^4+y^4+t*x^2*y^2, [x,y]) + sage: quartic = invariant_theory.binary_quartic(x^4 + y^4 + t*x^2*y^2, [x,y]) sage: quartic.ring() Multivariate Polynomial Ring in x, y, t over Rational Field sage: R.<x,y,t> = QQ[] - sage: quartic = invariant_theory.binary_quartic(x^4+1+t*x^2, [x]) + sage: quartic = invariant_theory.binary_quartic(x^4 + 1 + t*x^2, [x]) sage: quartic.ring() Multivariate Polynomial Ring in x, y, t over Rational Field """ return self._ring - def variables(self): """ Return the variables of the form. @@ -411,18 +409,17 @@ def variables(self): EXAMPLES:: sage: R.<x,y,t> = QQ[] - sage: quartic = invariant_theory.binary_quartic(x^4+y^4+t*x^2*y^2, [x,y]) + sage: quartic = invariant_theory.binary_quartic(x^4 + y^4 + t*x^2*y^2, [x,y]) sage: quartic.variables() (x, y) sage: R.<x,y,t> = QQ[] - sage: quartic = invariant_theory.binary_quartic(x^4+1+t*x^2, [x]) + sage: quartic = invariant_theory.binary_quartic(x^4 + 1 + t*x^2, [x]) sage: quartic.variables() (x, None) """ return self._variables - def is_homogeneous(self): """ Return whether the forms were defined by homogeneous polynomials. @@ -435,14 +432,14 @@ def is_homogeneous(self): EXAMPLES:: sage: R.<x,y,t> = QQ[] - sage: quartic = invariant_theory.binary_quartic(x^4+y^4+t*x^2*y^2, [x,y]) + sage: quartic = invariant_theory.binary_quartic(x^4 + y^4 + t*x^2*y^2, [x,y]) sage: quartic.is_homogeneous() True sage: quartic.form() x^2*y^2*t + x^4 + y^4 sage: R.<x,y,t> = QQ[] - sage: quartic = invariant_theory.binary_quartic(x^4+1+t*x^2, [x]) + sage: quartic = invariant_theory.binary_quartic(x^4 + 1 + t*x^2, [x]) sage: quartic.is_homogeneous() False sage: quartic.form() @@ -509,7 +506,7 @@ class AlgebraicForm(FormsBase): ... ValueError: polynomial is of the wrong degree - sage: AlgebraicForm(2, 2, x^2+y, [x,y]).variables() + sage: AlgebraicForm(2, 2, x^2 + y, [x,y]).variables() Traceback (most recent call last): ... ValueError: polynomial is not homogeneous @@ -537,7 +534,7 @@ def __init__(self, n, d, polynomial, *args, **kwds): elif len(variables) == n-1: variables = variables + (None,) else: - raise ValueError('need '+str(n)+' or '+ + raise ValueError('need '+str(n)+' or ' + str(n-1)+' variables, got '+str(variables)) ring = polynomial.parent() homogeneous = variables[-1] is not None @@ -566,7 +563,7 @@ def _check(self): deg = sum([ e[R.gens().index(x)] for x in self._variables if x is not None ]) degrees.add(deg) - if self._homogeneous and len(degrees)>1: + if self._homogeneous and len(degrees) > 1: raise ValueError('polynomial is not homogeneous') if degrees == set() or \ (self._homogeneous and degrees == set([self._d])) or \ @@ -639,7 +636,7 @@ def __richcmp__(self, other, op): sage: quartic == quartic True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp(self.coeffs(), other.coeffs(), op) @@ -654,7 +651,7 @@ def _repr_(self): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: quartic = invariant_theory.binary_quartic(x^4+y^4) + sage: quartic = invariant_theory.binary_quartic(x^4 + y^4) sage: quartic._repr_() 'Binary quartic with coefficients (1, 0, 0, 0, 1)' @@ -687,7 +684,6 @@ def _repr_(self): s += ' given by ' + str(self.form()) return s - def form(self): """ Return the defining polynomial. @@ -699,7 +695,7 @@ def form(self): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: quartic = invariant_theory.binary_quartic(x^4+y^4) + sage: quartic = invariant_theory.binary_quartic(x^4 + y^4) sage: quartic.form() x^4 + y^4 sage: quartic.polynomial() @@ -709,7 +705,6 @@ def form(self): polynomial = form - def homogenized(self, var='h'): """ Return form as defined by a homogeneous polynomial. @@ -798,7 +793,7 @@ def _extract_coefficients(self, monomials): (a30, a03, a00, a21, a20, a12, a02, a10, a01, a11) sage: T.<t> = QQ[] - sage: univariate = AlgebraicForm(2, 3, t^3+2*t^2+3*t+4) + sage: univariate = AlgebraicForm(2, 3, t^3 + 2*t^2 + 3*t + 4) sage: m = [t^3, 1, t, t^2] sage: univariate._extract_coefficients(m) (1, 4, 3, 2) @@ -812,7 +807,7 @@ def _extract_coefficients(self, monomials): Check for :trac:`30035`:: sage: R.<a,b,c> = QQ[] - sage: f = 3*a**3+b**3+a*b*c + sage: f = 3*a**3 + b**3 + a*b*c sage: T = invariant_theory.ternary_cubic(f) sage: T.S_invariant().parent() Rational Field @@ -872,7 +867,6 @@ def coeff_tuple_iter(): raise ValueError('less monomials were passed than the form actually has') return result - def coefficients(self): """ Alias for ``coeffs()``. @@ -891,7 +885,6 @@ def coefficients(self): """ return self.coeffs() - def transformed(self, g): r""" Return the image under a linear transformation of the variables. @@ -913,9 +906,9 @@ def transformed(self, g): sage: R.<x,y,z> = QQ[] sage: cubic = invariant_theory.ternary_cubic(x^3 + 2*y^3 + 3*z^3 + 4*x*y*z) - sage: cubic.transformed({x:y, y:z, z:x}).form() + sage: cubic.transformed({x: y, y: z, z: x}).form() 3*x^3 + y^3 + 4*x*y*z + 2*z^3 - sage: cyc = matrix([[0,1,0],[0,0,1],[1,0,0]]) + sage: cyc = matrix([[0,1,0], [0,0,1], [1,0,0]]) sage: cubic.transformed(cyc) == cubic.transformed({x:y, y:z, z:x}) True sage: g = matrix(QQ, [[1, 0, 0], [-1, 1, -3], [-5, -5, 16]]) @@ -981,11 +974,11 @@ def __init__(self, n, d, polynomial, *args): sage: R.<x,y> = QQ[] sage: from sage.rings.invariants.invariant_theory import QuadraticForm - sage: form = QuadraticForm(2, 2, x^2+2*y^2+3*x*y) + sage: form = QuadraticForm(2, 2, x^2 + 2*y^2 + 3*x*y) sage: form Binary quadratic with coefficients (1, 2, 3) sage: form._check_covariant('discriminant', invariant=True) - sage: QuadraticForm(3, 2, x^2+y^2) + sage: QuadraticForm(3, 2, x^2 + y^2) Ternary quadratic with coefficients (1, 1, 0, 0, 0, 0) """ assert d == 2 @@ -1019,7 +1012,6 @@ def from_invariants(cls, discriminant, x, z, *args, **kwargs): polynomial = sum([coeffs[i]*x**(2-i)*z**i for i in range(3)]) return cls(2, 2, polynomial, *args) - @cached_method def monomials(self): """ @@ -1033,11 +1025,11 @@ def monomials(self): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: quadratic = invariant_theory.quadratic_form(x^2+y^2) + sage: quadratic = invariant_theory.quadratic_form(x^2 + y^2) sage: quadratic.monomials() (x^2, y^2, x*y) - sage: quadratic = invariant_theory.inhomogeneous_quadratic_form(x^2+y^2) + sage: quadratic = invariant_theory.inhomogeneous_quadratic_form(x^2 + y^2) sage: quadratic.monomials() (x^2, y^2, 1, x*y, x, y) """ @@ -1060,7 +1052,6 @@ def prod(a, b): mixed = tuple(mixed) return squares + mixed - @cached_method def coeffs(self): r""" @@ -1088,7 +1079,6 @@ def coeffs(self): """ return self._extract_coefficients(self.monomials()) - def scaled_coeffs(self): r""" The scaled coefficients of a quadratic form. @@ -1118,7 +1108,6 @@ def scaled_coeffs(self): mixed = tuple( c/2 for c in coeff[self._n:] ) return squares + mixed - @cached_method def matrix(self): r""" @@ -1158,7 +1147,6 @@ def matrix(self): _matrix_ = matrix - def discriminant(self): """ Return the discriminant of the quadratic form. @@ -1171,7 +1159,7 @@ def discriminant(self): EXAMPLES:: sage: R.<a,b,c, x,y> = QQ[] - sage: p = a*x^2+b*x*y+c*y^2 + sage: p = a*x^2 + b*x*y + c*y^2 sage: quadratic = invariant_theory.quadratic_form(p, x,y) sage: quadratic.discriminant() b^2 - 4*a*c @@ -1290,7 +1278,6 @@ def dual(self): p = sum([ sum([ Aadj[i,j]*var[i]*var[j] for i in range(n) ]) for j in range(n)]) return invariant_theory.quadratic_form(p, self.variables()) - def as_QuadraticForm(self): """ Convert into a :class:`~sage.quadratic_forms.quadratic_form.QuadraticForm`. @@ -1305,7 +1292,7 @@ def as_QuadraticForm(self): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: p = x^2+y^2+z^2+2*x*y+3*x*z + sage: p = x^2 + y^2 + z^2 + 2*x*y + 3*x*z sage: quadratic = invariant_theory.ternary_quadratic(p) sage: matrix(quadratic) [ 1 1 3/2] @@ -1358,7 +1345,7 @@ def __init__(self, n, d, polynomial, *args): sage: R.<x,y> = QQ[] sage: from sage.rings.invariants.invariant_theory import BinaryQuartic - sage: BinaryQuartic(2, 4, x^4+y^4) + sage: BinaryQuartic(2, 4, x^4 + y^4) Binary quartic with coefficients (1, 0, 0, 0, 1) """ assert n == 2 and d == 4 @@ -1379,7 +1366,7 @@ def monomials(self): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: quartic = invariant_theory.binary_quartic(x^4+y^4) + sage: quartic = invariant_theory.binary_quartic(x^4 + y^4) sage: quartic.monomials() (y^4, x*y^3, x^2*y^2, x^3*y, x^4) """ @@ -1420,7 +1407,6 @@ def coeffs(self): """ return self._extract_coefficients(self.monomials()) - def scaled_coeffs(self): """ The coefficients of a binary quartic. @@ -1451,7 +1437,6 @@ def scaled_coeffs(self): coeff = self.coeffs() return (coeff[0], coeff[1]/4, coeff[2]/6, coeff[3]/4, coeff[4]) - @cached_method def EisensteinD(self): r""" @@ -1472,7 +1457,7 @@ def EisensteinD(self): EXAMPLES:: sage: R.<a0, a1, a2, a3, a4, x0, x1> = QQ[] - sage: f = a0*x1^4+4*a1*x0*x1^3+6*a2*x0^2*x1^2+4*a3*x0^3*x1+a4*x0^4 + sage: f = a0*x1^4 + 4*a1*x0*x1^3 + 6*a2*x0^2*x1^2 + 4*a3*x0^3*x1 + a4*x0^4 sage: inv = invariant_theory.binary_quartic(f, x0, x1) sage: inv.EisensteinD() 3*a2^2 - 4*a1*a3 + a0*a4 @@ -1481,7 +1466,6 @@ def EisensteinD(self): assert len(a) == 5 return a[0]*a[4]+3*a[2]**2-4*a[1]*a[3] - @cached_method def EisensteinE(self): r""" @@ -1502,15 +1486,14 @@ def EisensteinE(self): EXAMPLES:: sage: R.<a0, a1, a2, a3, a4, x0, x1> = QQ[] - sage: f = a0*x1^4+4*a1*x0*x1^3+6*a2*x0^2*x1^2+4*a3*x0^3*x1+a4*x0^4 + sage: f = a0*x1^4 + 4*a1*x0*x1^3 + 6*a2*x0^2*x1^2 + 4*a3*x0^3*x1 + a4*x0^4 sage: inv = invariant_theory.binary_quartic(f, x0, x1) sage: inv.EisensteinE() a2^3 - 2*a1*a2*a3 + a0*a3^2 + a1^2*a4 - a0*a2*a4 """ a = self.scaled_coeffs() assert len(a) == 5 - return a[0]*a[3]**2 +a[1]**2*a[4] -a[0]*a[2]*a[4] -2*a[1]*a[2]*a[3] +a[2]**3 - + return a[0]*a[3]**2 + a[1]**2*a[4] - a[0]*a[2]*a[4] - 2*a[1]*a[2]*a[3] + a[2]**3 @cached_method def g_covariant(self): @@ -1535,7 +1518,7 @@ def g_covariant(self): EXAMPLES:: sage: R.<a0, a1, a2, a3, a4, x, y> = QQ[] - sage: p = a0*x^4+4*a1*x^3*y+6*a2*x^2*y^2+4*a3*x*y^3+a4*y^4 + sage: p = a0*x^4 + 4*a1*x^3*y + 6*a2*x^2*y^2 + 4*a3*x*y^3 + a4*y^4 sage: inv = invariant_theory.binary_quartic(p, x, y) sage: g = inv.g_covariant(); g a1^2*x^4 - a0*a2*x^4 + 2*a1*a2*x^3*y - 2*a0*a3*x^3*y + 3*a2^2*x^2*y^2 @@ -1563,7 +1546,6 @@ def g_covariant(self): (2*a2*a3 - 2*a1*a4)*xpow[3] + \ (a3**2 - a2*a4)*xpow[4] - @cached_method def h_covariant(self): r""" @@ -1587,7 +1569,7 @@ def h_covariant(self): EXAMPLES:: sage: R.<a0, a1, a2, a3, a4, x, y> = QQ[] - sage: p = a0*x^4+4*a1*x^3*y+6*a2*x^2*y^2+4*a3*x*y^3+a4*y^4 + sage: p = a0*x^4 + 4*a1*x^3*y + 6*a2*x^2*y^2 + 4*a3*x*y^3 + a4*y^4 sage: inv = invariant_theory.binary_quartic(p, x, y) sage: h = inv.h_covariant(); h -2*a1^3*x^6 + 3*a0*a1*a2*x^6 - a0^2*a3*x^6 - 6*a1^2*a2*x^5*y + 9*a0*a2^2*x^5*y @@ -1606,7 +1588,7 @@ def h_covariant(self): + 2*a1*a3*a4*x + a0*a4^2*x + 2*a3^3 - 3*a2*a3*a4 + a1*a4^2 sage: g = inv.g_covariant() - sage: h == 1/8 * (p.derivative(x)*g.derivative(y)-p.derivative(y)*g.derivative(x)) + sage: h == 1/8 * (p.derivative(x)*g.derivative(y) - p.derivative(y)*g.derivative(x)) True """ a0, a1, a2, a3, a4 = self.scaled_coeffs() @@ -1735,7 +1717,7 @@ def monomials(self): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: quintic = invariant_theory.binary_quintic(x^5+y^5) + sage: quintic = invariant_theory.binary_quintic(x^5 + y^5) sage: quintic.monomials() (y^5, x*y^4, x^2*y^3, x^3*y^2, x^4*y, x^5) """ @@ -2461,9 +2443,9 @@ def arithmetic_invariants(self): invariants = {} invariants['I4'] = R(2)**-1*5**4*clebsch['A'] invariants['I8'] = 5**5 * (R(2)**-1*47*clebsch['A']**2 - -2**2*clebsch['B']) + - 2**2*clebsch['B']) invariants['I12'] = 5**10 * (R(2)**-1*3*clebsch['A']**3 - -2**5*R(3)**-1*clebsch['C']) + - 2**5*R(3)**-1*clebsch['C']) invariants['I18'] = 2**8*R(3)**-1*5**15 * clebsch['R'] return invariants @@ -2545,9 +2527,9 @@ def _covariant_conic(A_scaled_coeffs, B_scaled_coeffs, monomials): (b0*c1+c0*b1-2*f0*f1) * monomials[0] + (a0*c1+c0*a1-2*g0*g1) * monomials[1] + (a0*b1+b0*a1-2*h0*h1) * monomials[2] + - 2*(f0*g1+g0*f1 -c0*h1-h0*c1) * monomials[3] + - 2*(h0*f1+f0*h1 -b0*g1-g0*b1) * monomials[4] + - 2*(g0*h1+h0*g1 -a0*f1-f0*a1) * monomials[5] ) + 2*(f0*g1+g0*f1 - c0*h1-h0*c1) * monomials[3] + + 2*(h0*f1+f0*h1 - b0*g1-g0*b1) * monomials[4] + + 2*(g0*h1+h0*g1 - a0*f1-f0*a1) * monomials[5] ) ###################################################################### @@ -2603,7 +2585,7 @@ def monomials(self): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: quadratic = invariant_theory.ternary_quadratic(x^2+y*z) + sage: quadratic = invariant_theory.ternary_quadratic(x^2 + y*z) sage: quadratic.monomials() (x^2, y^2, z^2, x*y, x*z, y*z) """ @@ -2614,7 +2596,6 @@ def monomials(self): else: return (x**2, y**2, R.one(), x*y, x, y) - @cached_method def coeffs(self): r""" @@ -2643,7 +2624,6 @@ def coeffs(self): """ return self._extract_coefficients(self.monomials()) - def scaled_coeffs(self): r""" Return the scaled coefficients of a quadratic. @@ -2689,8 +2669,8 @@ def covariant_conic(self, other): EXAMPLES:: sage: ring.<x,y,z> = QQ[] - sage: Q = invariant_theory.ternary_quadratic(x^2+y^2+z^2) - sage: R = invariant_theory.ternary_quadratic(x*y+x*z+y*z) + sage: Q = invariant_theory.ternary_quadratic(x^2 + y^2 + z^2) + sage: R = invariant_theory.ternary_quadratic(x*y + x*z + y*z) sage: Q.covariant_conic(R) -x*y - x*z - y*z sage: R.covariant_conic(Q) @@ -2737,7 +2717,7 @@ class TernaryCubic(AlgebraicForm): TESTS:: sage: R.<x,y,z> = QQ[] - sage: cubic = invariant_theory.ternary_cubic(x^3+y^3+z^3) + sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3) sage: cubic Ternary cubic with coefficients (1, 1, 1, 0, 0, 0, 0, 0, 0, 0) sage: TestSuite(cubic).run() @@ -2793,7 +2773,6 @@ def monomials(self): return (x**3, y**3, R.one(), x**2*y, x**2, x*y**2, y**2, x, y, x*y) - @cached_method def coeffs(self): r""" @@ -2827,7 +2806,6 @@ def coeffs(self): """ return self._extract_coefficients(self.monomials()) - def scaled_coeffs(self): r""" Return the coefficients of a cubic. @@ -2866,7 +2844,6 @@ def scaled_coeffs(self): 1/F(3)*a[6], 1/F(3)*a[7], 1/F(3)*a[8], 1/F(6)*a[9]) - def S_invariant(self): """ Return the S-invariant. @@ -2874,21 +2851,20 @@ def S_invariant(self): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: cubic = invariant_theory.ternary_cubic(x^2*y+y^3+z^3+x*y*z) + sage: cubic = invariant_theory.ternary_cubic(x^2*y + y^3 + z^3 + x*y*z) sage: cubic.S_invariant() -1/1296 """ a,b,c,a2,a3,b1,b3,c1,c2,m = self.scaled_coeffs() S = ( a*b*c*m-(b*c*a2*a3+c*a*b1*b3+a*b*c1*c2) - -m*(a*b3*c2+b*c1*a3+c*a2*b1) - +(a*b1*c2**2+a*c1*b3**2+b*a2*c1**2+b*c2*a3**2+c*b3*a2**2+c*a3*b1**2) - -m**4+2*m**2*(b1*c1+c2*a2+a3*b3) - -3*m*(a2*b3*c1+a3*b1*c2) - -(b1**2*c1**2+c2**2*a2**2+a3**2*b3**2) - +(c2*a2*a3*b3+a3*b3*b1*c1+b1*c1*c2*a2) ) + - m*(a*b3*c2+b*c1*a3+c*a2*b1) + + (a*b1*c2**2+a*c1*b3**2+b*a2*c1**2+b*c2*a3**2+c*b3*a2**2+c*a3*b1**2) + - m**4+2*m**2*(b1*c1+c2*a2+a3*b3) + - 3*m*(a2*b3*c1+a3*b1*c2) + - (b1**2*c1**2+c2**2*a2**2+a3**2*b3**2) + + (c2*a2*a3*b3+a3*b3*b1*c1+b1*c1*c2*a2) ) return S - def T_invariant(self): """ Return the T-invariant. @@ -2896,50 +2872,49 @@ def T_invariant(self): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: cubic = invariant_theory.ternary_cubic(x^3+y^3+z^3) + sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3) sage: cubic.T_invariant() 1 sage: R.<x,y,z,t> = GF(7)[] - sage: cubic = invariant_theory.ternary_cubic(x^3+y^3+z^3+t*x*y*z, [x,y,z]) + sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3 + t*x*y*z, [x,y,z]) sage: cubic.T_invariant() -t^6 - t^3 + 1 """ a,b,c,a2,a3,b1,b3,c1,c2,m = self.scaled_coeffs() T = ( a**2*b**2*c**2-6*a*b*c*(a*b3*c2+b*c1*a3+c*a2*b1) - -20*a*b*c*m**3+12*a*b*c*m*(b1*c1+c2*a2+a3*b3) - +6*a*b*c*(a2*b3*c1+a3*b1*c2)+ - 4*(a**2*b*c2**3+a**2*c*b3**3+b**2*c*a3**3+ + - 20*a*b*c*m**3+12*a*b*c*m*(b1*c1+c2*a2+a3*b3) + + 6*a*b*c*(a2*b3*c1+a3*b1*c2) + + 4*(a**2*b*c2**3+a**2*c*b3**3+b**2*c*a3**3 + b**2*a*c1**3+c**2*a*b1**3+c**2*b*a2**3) - +36*m**2*(b*c*a2*a3+c*a*b1*b3+a*b*c1*c2) - -24*m*(b*c*b1*a3**2+b*c*c1*a2**2+c*a*c2*b1**2+c*a*a2*b3**2+a*b*a3*c2**2+ + + 36*m**2*(b*c*a2*a3+c*a*b1*b3+a*b*c1*c2) + - 24*m*(b*c*b1*a3**2+b*c*c1*a2**2+c*a*c2*b1**2+c*a*a2*b3**2+a*b*a3*c2**2 + a*b*b3*c1**2) - -3*(a**2*b3**2*c2**2+b**2*c1**2*a3**2+c**2*a2**2*b1**2)+ + - 3*(a**2*b3**2*c2**2+b**2*c1**2*a3**2+c**2*a2**2*b1**2) + 18*(b*c*b1*c1*a2*a3+c*a*c2*a2*b3*b1+a*b*a3*b3*c1*c2) - -12*(b*c*c2*a3*a2**2+b*c*b3*a2*a3**2+c*a*c1*b3*b1**2+ + - 12*(b*c*c2*a3*a2**2+b*c*b3*a2*a3**2+c*a*c1*b3*b1**2 + c*a*a3*b1*b3**2+a*b*a2*c1*c2**2+a*b*b1*c2*c1**2) - -12*m**3*(a*b3*c2+b*c1*a3+c*a2*b1) - +12*m**2*(a*b1*c2**2+a*c1*b3**2+b*a2*c1**2+ + - 12*m**3*(a*b3*c2+b*c1*a3+c*a2*b1) + + 12*m**2*(a*b1*c2**2+a*c1*b3**2+b*a2*c1**2 + b*c2*a3**2+c*b3*a2**2+c*a3*b1**2) - -60*m*(a*b1*b3*c1*c2+b*c1*c2*a2*a3+c*a2*a3*b1*b3) - +12*m*(a*a2*b3*c2**2+a*a3*c2*b3**2+b*b3*c1*a3**2+ + - 60*m*(a*b1*b3*c1*c2+b*c1*c2*a2*a3+c*a2*a3*b1*b3) + + 12*m*(a*a2*b3*c2**2+a*a3*c2*b3**2+b*b3*c1*a3**2 + b*b1*a3*c1**2+c*c1*a2*b1**2+c*c2*b1*a2**2) - +6*(a*b3*c2+b*c1*a3+c*a2*b1)*(a2*b3*c1+a3*b1*c2) - +24*(a*b1*b3**2*c1**2+a*c1*c2**2*b1**2+b*c2*c1**2*a2**2 - +b*a2*a3**2*c2**2+c*a3*a2**2*b3**2+c*b3*b1**2*a3**2) - -12*(a*a2*b1*c2**3+a*a3*c1*b3**3+b*b3*c2*a3**3+b*b1*a2*c1**3 - +c*c1*a3*b1**3+c*c2*b3*a2**3) - -8*m**6+24*m**4*(b1*c1+c2*a2+a3*b3)-36*m**3*(a2*b3*c1+a3*b1*c2) - -12*m**2*(b1*c1*c2*a2+c2*a2*a3*b3+a3*b3*b1*c1) - -24*m**2*(b1**2*c1**2+c2**2*a2**2+a3**2*b3**2) - +36*m*(a2*b3*c1+a3*b1*c2)*(b1*c1+c2*a2+a3*b3) - +8*(b1**3*c1**3+c2**3*a2**3+a3**3*b3**3) - -27*(a2**2*b3**2*c1**2+a3**2*b1**2*c2**2)-6*b1*c1*c2*a2*a3*b3 - -12*(b1**2*c1**2*c2*a2+b1**2*c1**2*a3*b3+c2**2*a2**2*a3*b3+ + + 6*(a*b3*c2+b*c1*a3+c*a2*b1)*(a2*b3*c1+a3*b1*c2) + + 24*(a*b1*b3**2*c1**2+a*c1*c2**2*b1**2+b*c2*c1**2*a2**2 + + b*a2*a3**2*c2**2+c*a3*a2**2*b3**2+c*b3*b1**2*a3**2) + - 12*(a*a2*b1*c2**3+a*a3*c1*b3**3+b*b3*c2*a3**3+b*b1*a2*c1**3 + + c*c1*a3*b1**3+c*c2*b3*a2**3) + - 8*m**6+24*m**4*(b1*c1+c2*a2+a3*b3)-36*m**3*(a2*b3*c1+a3*b1*c2) + - 12*m**2*(b1*c1*c2*a2+c2*a2*a3*b3+a3*b3*b1*c1) + - 24*m**2*(b1**2*c1**2+c2**2*a2**2+a3**2*b3**2) + + 36*m*(a2*b3*c1+a3*b1*c2)*(b1*c1+c2*a2+a3*b3) + + 8*(b1**3*c1**3+c2**3*a2**3+a3**3*b3**3) + - 27*(a2**2*b3**2*c1**2+a3**2*b1**2*c2**2)-6*b1*c1*c2*a2*a3*b3 + - 12*(b1**2*c1**2*c2*a2+b1**2*c1**2*a3*b3+c2**2*a2**2*a3*b3 + c2**2*a2**2*b1*c1+a3**2*b3**2*b1*c1+a3**2*b3**2*c2*a2) ) return T - @cached_method def polar_conic(self): r""" @@ -2985,7 +2960,6 @@ def polar_conic(self): polar = matrix(self._ring, [[A00, A01, A02],[A01, A11, A12],[A02, A12, A22]]) return polar - @cached_method def Hessian(self): """ @@ -2999,12 +2973,12 @@ def Hessian(self): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: cubic = invariant_theory.ternary_cubic(x^3+y^3+z^3) + sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3) sage: cubic.Hessian() x*y*z sage: R.<x,y> = QQ[] - sage: cubic = invariant_theory.ternary_cubic(x^3+y^3+1) + sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + 1) sage: cubic.Hessian() x*y """ @@ -3023,7 +2997,6 @@ def Hessian(self): F = self._ring.base_ring() return 1/F(216) * H.det() - def Theta_covariant(self): r""" Return the `\Theta` covariant. @@ -3031,12 +3004,12 @@ def Theta_covariant(self): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: cubic = invariant_theory.ternary_cubic(x^3+y^3+z^3) + sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3) sage: cubic.Theta_covariant() -x^3*y^3 - x^3*z^3 - y^3*z^3 sage: R.<x,y> = QQ[] - sage: cubic = invariant_theory.ternary_cubic(x^3+y^3+1) + sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + 1) sage: cubic.Theta_covariant() -x^3*y^3 - x^3 - y^3 @@ -3057,7 +3030,6 @@ def Theta_covariant(self): F = self._ring.base_ring() return 1/F(9) * _covariant_conic(U_coeffs, H_coeffs, quadratic.monomials()) - def J_covariant(self): """ Return the J-covariant of the ternary cubic. @@ -3065,12 +3037,12 @@ def J_covariant(self): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: cubic = invariant_theory.ternary_cubic(x^3+y^3+z^3) + sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3) sage: cubic.J_covariant() x^6*y^3 - x^3*y^6 - x^6*z^3 + y^6*z^3 + x^3*z^6 - y^3*z^6 sage: R.<x,y> = QQ[] - sage: cubic = invariant_theory.ternary_cubic(x^3+y^3+1) + sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + 1) sage: cubic.J_covariant() x^6*y^3 - x^3*y^6 - x^6 + y^6 + x^3 - y^3 """ @@ -3115,8 +3087,8 @@ def syzygy(self, U, S, T, H, Theta, J): return ( -J**2 + 4*Theta**3 + T*U**2*Theta**2 + Theta*(-4*S**3*U**4 + 2*S*T*U**3*H - 72*S**2*U**2*H**2 - 18*T*U*H**3 + 108*S*H**4) - -16*S**4*U**5*H - 11*S**2*T*U**4*H**2 -4*T**2*U**3*H**3 - +54*S*T*U**2*H**4 -432*S**2*U*H**5 -27*T*H**6 ) + - 16*S**4*U**5*H - 11*S**2*T*U**4*H**2 - 4*T**2*U**3*H**3 + + 54*S*T*U**2*H**4 - 432*S**2*U*H**5 - 27*T*H**6 ) ###################################################################### @@ -3188,7 +3160,7 @@ def __richcmp__(self, other, op): sage: two_inv == two_inv True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp(self._forms, other._forms, op) @@ -3268,7 +3240,6 @@ def get_form(self, i): __getitem__ = get_form - def homogenized(self, var='h'): """ Return form as defined by a homogeneous polynomial. @@ -3286,7 +3257,7 @@ def homogenized(self, var='h'): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: q = invariant_theory.quaternary_biquadratic(x^2+1, y^2+1, [x,y,z]) + sage: q = invariant_theory.quaternary_biquadratic(x^2 + 1, y^2 + 1, [x,y,z]) sage: q Joint quaternary quadratic with coefficients (1, 0, 0, 1, 0, 0, 0, 0, 0, 0) and quaternary quadratic with coefficients (0, 1, 0, 1, 0, 0, 0, 0, 0, 0) @@ -3301,7 +3272,6 @@ def homogenized(self, var='h'): forms = [f.homogenized(var=var) for f in self._forms] return self.__class__(forms) - def _check_covariant(self, method_name, g=None, invariant=False): r""" Test whether ``method_name`` actually returns a covariant. @@ -3356,7 +3326,6 @@ def _check_covariant(self, method_name, g=None, invariant=False): class TwoAlgebraicForms(SeveralAlgebraicForms): - def first(self): """ Return the first of the two forms. @@ -3381,7 +3350,6 @@ def first(self): """ return self._forms[0] - def second(self): """ Return the second of the two forms. @@ -3427,7 +3395,8 @@ class TwoTernaryQuadratics(TwoAlgebraicForms): TESTS:: sage: R.<x,y,z> = QQ[] - sage: inv = invariant_theory.ternary_biquadratic(x^2+y^2+z^2, x*y+y*z+x*z, [x, y, z]) + sage: inv = invariant_theory.ternary_biquadratic(x^2 + y^2 + z^2, + ....: x*y + y*z + x*z, [x, y, z]) sage: inv Joint ternary quadratic with coefficients (1, 1, 1, 0, 0, 0) and ternary quadratic with coefficients (0, 0, 0, 1, 1, 1) @@ -3484,7 +3453,7 @@ def _Theta_helper(self, scaled_coeffs_1, scaled_coeffs_2): TESTS:: sage: R.<x,y,z> = QQ[] - sage: inv = invariant_theory.ternary_biquadratic(x^2 + y*z, x*y+z^2, x, y, z) + sage: inv = invariant_theory.ternary_biquadratic(x^2 + y*z, x*y + z^2, x, y, z) sage: inv._Theta_helper([1]*6, [2]*6) 0 """ @@ -3640,7 +3609,7 @@ class TwoQuaternaryQuadratics(TwoAlgebraicForms): TESTS:: sage: R.<w,x,y,z> = QQ[] - sage: inv = invariant_theory.quaternary_biquadratic(w^2+x^2, y^2+z^2, w, x, y, z) + sage: inv = invariant_theory.quaternary_biquadratic(w^2 + x^2, y^2 + z^2, w, x, y, z) sage: inv Joint quaternary quadratic with coefficients (1, 1, 0, 0, 0, 0, 0, 0, 0, 0) and quaternary quadratic with coefficients (0, 0, 1, 1, 0, 0, 0, 0, 0, 0) @@ -3677,7 +3646,6 @@ def Delta_invariant(self): """ return self.get_form(0).matrix().det() - def Delta_prime_invariant(self): r""" Return the `\Delta'` invariant. @@ -3696,7 +3664,6 @@ def Delta_prime_invariant(self): """ return self.get_form(1).matrix().det() - def _Theta_helper(self, scaled_coeffs_1, scaled_coeffs_2): """ Internal helper method for :meth:`Theta_invariant` and @@ -3705,7 +3672,7 @@ def _Theta_helper(self, scaled_coeffs_1, scaled_coeffs_2): TESTS:: sage: R.<w,x,y,z> = QQ[] - sage: inv = invariant_theory.quaternary_biquadratic(w^2+x^2, y^2+z^2, w, x, y, z) + sage: inv = invariant_theory.quaternary_biquadratic(w^2 + x^2, y^2 + z^2, w, x, y, z) sage: inv._Theta_helper([1]*10, [2]*10) 0 """ @@ -3743,7 +3710,6 @@ def Theta_invariant(self): """ return self._Theta_helper(self.get_form(0).scaled_coeffs(), self.get_form(1).scaled_coeffs()) - def Theta_prime_invariant(self): r""" Return the `\Theta'` invariant. @@ -3762,7 +3728,6 @@ def Theta_prime_invariant(self): """ return self._Theta_helper(self.get_form(1).scaled_coeffs(), self.get_form(0).scaled_coeffs()) - def Phi_invariant(self): r""" Return the `\Phi'` invariant. @@ -3800,7 +3765,6 @@ def Phi_invariant(self): - 2*b0*b3*B2*B5 - 2*b0*b2*B3*B5 + 2*a0*b4*B3*B5 - 2*b0*b1*B4*B5 \ + 2*a0*b3*B4*B5 - a0*a1*B5**2 + b0**2*B5**2 - def _T_helper(self, scaled_coeffs_1, scaled_coeffs_2): """ Internal helper method for :meth:`T_covariant` and @@ -3883,7 +3847,6 @@ def T01(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, return t00*w*w + 2*t01*w*x + 2*t02*w*y + 2*t30*w*z + t11*x*x + 2*t12*x*y \ + 2*t13*x*z + t22*y*y + 2*t23*y*z + t33*z*z - def T_covariant(self): """ The `T`-covariant. @@ -3905,7 +3868,6 @@ def T_covariant(self): """ return self._T_helper(self.get_form(0).scaled_coeffs(), self.get_form(1).scaled_coeffs()) - def T_prime_covariant(self): """ The `T'`-covariant. @@ -3928,7 +3890,6 @@ def T_prime_covariant(self): """ return self._T_helper(self.get_form(1).scaled_coeffs(), self.get_form(0).scaled_coeffs()) - def J_covariant(self): """ The `J`-covariant. @@ -3954,7 +3915,6 @@ def J_covariant(self): [self.T_covariant(), 4], [self.T_prime_covariant(), 4]) - def syzygy(self, Delta, Theta, Phi, Theta_prime, Delta_prime, U, V, T, T_prime, J): """ Return the syzygy evaluated on the invariants and covariants. @@ -4008,7 +3968,7 @@ def syzygy(self, Delta, Theta, Phi, Theta_prime, Delta_prime, U, V, T, T_prime, (Theta*Phi - 3*Theta_prime*Delta)*T**2*T_prime + (Theta*Theta_prime - 4*Delta*Delta_prime)*T*T_prime**2 - (Delta_prime*Theta)*T_prime**3 - )* V + \ + ) * V + \ ( (Delta*Phi*Delta_prime) * T**2 + (3*Delta*Theta_prime*Delta_prime - Theta*Phi*Delta_prime) * T*T_prime + (2*Delta*Delta_prime**2 - 2*Theta*Theta_prime*Delta_prime @@ -4064,10 +4024,10 @@ class InvariantTheoryFactory(): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: invariant_theory.ternary_cubic(x^3+y^3+z^3) + sage: invariant_theory.ternary_cubic(x^3 + y^3 + z^3) Ternary cubic with coefficients (1, 1, 1, 0, 0, 0, 0, 0, 0, 0) - sage: invariant_theory.ternary_cubic(x^3+y^3+z^3).J_covariant() + sage: invariant_theory.ternary_cubic(x^3 + y^3 + z^3).J_covariant() x^6*y^3 - x^3*y^6 - x^6*z^3 + y^6*z^3 + x^3*z^6 - y^3*z^6 """ @@ -4101,7 +4061,7 @@ def quadratic_form(self, polynomial, *args): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: quadratic = x^2+y^2+z^2 + sage: quadratic = x^2 + y^2 + z^2 sage: inv = invariant_theory.quadratic_form(quadratic) sage: type(inv) <class 'sage.rings.invariants.invariant_theory.TernaryQuadratic'> @@ -4110,7 +4070,7 @@ def quadratic_form(self, polynomial, *args): you need to specify the polynomial variables:: sage: R.<x,y,z, a,b> = QQ[] - sage: quadratic = a*x^2+b*y^2+z^2+2*y*z + sage: quadratic = a*x^2 + b*y^2 + z^2 + 2*y*z sage: invariant_theory.quadratic_form(quadratic, x,y,z) Ternary quadratic with coefficients (a, b, 1, 0, 0, 2) sage: invariant_theory.quadratic_form(quadratic, [x,y,z]) # alternate syntax @@ -4145,11 +4105,11 @@ def inhomogeneous_quadratic_form(self, polynomial, *args): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: quadratic = x^2+2*y^2+3*x*y+4*x+5*y+6 + sage: quadratic = x^2 + 2*y^2 + 3*x*y + 4*x + 5*y + 6 sage: inv3 = invariant_theory.inhomogeneous_quadratic_form(quadratic) sage: type(inv3) <class 'sage.rings.invariants.invariant_theory.TernaryQuadratic'> - sage: inv4 = invariant_theory.inhomogeneous_quadratic_form(x^2+y^2+z^2) + sage: inv4 = invariant_theory.inhomogeneous_quadratic_form(x^2 + y^2 + z^2) sage: type(inv4) <class 'sage.rings.invariants.invariant_theory.QuadraticForm'> """ @@ -4178,7 +4138,7 @@ def binary_quadratic(self, quadratic, *args): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: invariant_theory.binary_quadratic(x^2+y^2) + sage: invariant_theory.binary_quadratic(x^2 + y^2) Binary quadratic with coefficients (1, 1, 0) sage: T.<t> = QQ[] @@ -4206,11 +4166,11 @@ def quaternary_quadratic(self, quadratic, *args): EXAMPLES:: sage: R.<w,x,y,z> = QQ[] - sage: invariant_theory.quaternary_quadratic(w^2+x^2+y^2+z^2) + sage: invariant_theory.quaternary_quadratic(w^2 + x^2 + y^2 + z^2) Quaternary quadratic with coefficients (1, 1, 1, 1, 0, 0, 0, 0, 0, 0) sage: R.<x,y,z> = QQ[] - sage: invariant_theory.quaternary_quadratic(1+x^2+y^2+z^2) + sage: invariant_theory.quaternary_quadratic(1 + x^2 + y^2 + z^2) Quaternary quadratic with coefficients (1, 1, 1, 1, 0, 0, 0, 0, 0, 0) """ return QuadraticForm(4, 2, quadratic, *args) @@ -4254,7 +4214,7 @@ def binary_quartic(self, quartic, *args, **kwds): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: quartic = invariant_theory.binary_quartic(x^4+y^4) + sage: quartic = invariant_theory.binary_quartic(x^4 + y^4) sage: quartic Binary quartic with coefficients (1, 0, 0, 0, 1) sage: type(quartic) @@ -4293,14 +4253,14 @@ def binary_quintic(self, quintic, *args, **kwds): If no variables are provided, they will be guessed:: sage: R.<x,y> = QQ[] - sage: quintic = invariant_theory.binary_quintic(x^5+y^5) + sage: quintic = invariant_theory.binary_quintic(x^5 + y^5) sage: quintic Binary quintic with coefficients (1, 0, 0, 0, 0, 1) If only one variable is given, the quintic is the homogenisation of the provided polynomial:: - sage: quintic = invariant_theory.binary_quintic(x^5+y^5, x) + sage: quintic = invariant_theory.binary_quintic(x^5 + y^5, x) sage: quintic Binary quintic with coefficients (y^5, 0, 0, 0, 0, 1) sage: quintic.is_homogeneous() @@ -4310,11 +4270,11 @@ def binary_quintic(self, quintic, *args, **kwds): specified:: sage: R.<x,y,z> = QQ[] - sage: quintic = invariant_theory.binary_quintic(x^5+z*y^5) + sage: quintic = invariant_theory.binary_quintic(x^5 + z*y^5) Traceback (most recent call last): ... ValueError: need 2 or 1 variables, got (x, y, z) - sage: quintic = invariant_theory.binary_quintic(x^5+z*y^5, x, y) + sage: quintic = invariant_theory.binary_quintic(x^5 + z*y^5, x, y) sage: quintic Binary quintic with coefficients (z, 0, 0, 0, 0, 1) @@ -4384,12 +4344,13 @@ def binary_form_from_invariants(self, degree, invariants, variables=None, as_for Binary quintic with coefficients (-37725479487783/1048576, 565882192316745/8388608, 0, 1033866765362693115/67108864, 12849486940936328715/268435456, -23129076493685391687/2147483648) - sage: invariant_theory.binary_form_from_invariants(5, invariants, scaling='normalized') + sage: invariant_theory.binary_form_from_invariants(5, invariants, + ....: scaling='normalized') Binary quintic with coefficients (24389/892616806656, 4205/11019960576, 0, 1015/209952, -145/1296, -3/16) - sage: invariant_theory.binary_form_from_invariants(5, invariants, scaling='coprime') - Binary quintic with coefficients (-2048, 3840, 0, 876960, 2724840, - -613089) + sage: invariant_theory.binary_form_from_invariants(5, invariants, + ....: scaling='coprime') + Binary quintic with coefficients (-2048, 3840, 0, 876960, 2724840, -613089) The invariants can also be computed using the invariants of a given binary quintic. The resulting form has the same invariants up to scaling, is @@ -4401,7 +4362,8 @@ def binary_form_from_invariants(self, degree, invariants, variables=None, as_for sage: p = 3*x1^5 + 6*x1^4*x0 + 3*x1^3*x0^2 + 4*x1^2*x0^3 - 5*x1*x0^4 + 4*x0^5 sage: quintic = invariant_theory.binary_quintic(p, x0, x1) sage: invariants = quintic.clebsch_invariants(as_tuple=True) - sage: newquintic = invariant_theory.binary_form_from_invariants(5, invariants, variables=quintic.variables()) + sage: newquintic = invariant_theory.binary_form_from_invariants( + ....: 5, invariants, variables=quintic.variables()) sage: newquintic Binary quintic with coefficients (9592267437341790539005557/244140625000000, 2149296928207625556323004064707/610351562500000000, @@ -4510,14 +4472,14 @@ def ternary_quadratic(self, quadratic, *args, **kwds): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: invariant_theory.ternary_quadratic(x^2+y^2+z^2) + sage: invariant_theory.ternary_quadratic(x^2 + y^2 + z^2) Ternary quadratic with coefficients (1, 1, 1, 0, 0, 0) sage: T.<u, v> = QQ[] - sage: invariant_theory.ternary_quadratic(1+u^2+v^2) + sage: invariant_theory.ternary_quadratic(1 + u^2 + v^2) Ternary quadratic with coefficients (1, 1, 1, 0, 0, 0) - sage: quadratic = x^2+y^2+z^2 + sage: quadratic = x^2 + y^2 + z^2 sage: inv = invariant_theory.ternary_quadratic(quadratic) sage: type(inv) <class 'sage.rings.invariants.invariant_theory.TernaryQuadratic'> @@ -4582,7 +4544,7 @@ def ternary_cubic(self, cubic, *args, **kwds): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: cubic = invariant_theory.ternary_cubic(x^3+y^3+z^3) + sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3) sage: type(cubic) <class 'sage.rings.invariants.invariant_theory.TernaryCubic'> """ @@ -4604,7 +4566,7 @@ def ternary_biquadratic(self, quadratic1, quadratic2, *args, **kwds): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: q1 = x^2+y^2+z^2 + sage: q1 = x^2 + y^2 + z^2 sage: q2 = x*y + y*z + x*z sage: inv = invariant_theory.ternary_biquadratic(q1, q2) sage: type(inv) @@ -4658,7 +4620,7 @@ def quaternary_biquadratic(self, quadratic1, quadratic2, *args, **kwds): EXAMPLES:: sage: R.<w,x,y,z> = QQ[] - sage: q1 = w^2+x^2+y^2+z^2 + sage: q1 = w^2 + x^2 + y^2 + z^2 sage: q2 = w*x + y*z sage: inv = invariant_theory.quaternary_biquadratic(q1, q2) sage: type(inv) diff --git a/src/sage/rings/invariants/reconstruction.py b/src/sage/rings/invariants/reconstruction.py index bde5c307ee4..4619bf777f1 100644 --- a/src/sage/rings/invariants/reconstruction.py +++ b/src/sage/rings/invariants/reconstruction.py @@ -41,7 +41,7 @@ def binary_quadratic_coefficients_from_invariants(discriminant, invariant_choice EXAMPLES:: sage: from sage.rings.invariants.reconstruction import binary_quadratic_coefficients_from_invariants - sage: quadratic = invariant_theory.binary_form_from_invariants(2, [24]) # indirect doctest + sage: quadratic = invariant_theory.binary_form_from_invariants(2, [24]) # indirect doctest sage: quadratic Binary quadratic with coefficients (1, -6, 0) sage: quadratic.discriminant() @@ -142,7 +142,8 @@ def binary_quintic_coefficients_from_invariants(invariants, K=None, invariant_ch sage: p = 3*x1^5 + 6*x1^4*x0 + 3*x1^3*x0^2 + 4*x1^2*x0^3 - 5*x1*x0^4 + 4*x0^5 sage: quintic = invariant_theory.binary_quintic(p, x0, x1) sage: invs = quintic.clebsch_invariants(as_tuple=True) - sage: reconstructed = invariant_theory.binary_form_from_invariants(5, invs, variables=quintic.variables()) # indirect doctest + sage: reconstructed = invariant_theory.binary_form_from_invariants( # indirect doctest + ....: 5, invs, variables=quintic.variables()) sage: reconstructed Binary quintic with coefficients (9592267437341790539005557/244140625000000, 2149296928207625556323004064707/610351562500000000, @@ -167,8 +168,10 @@ def binary_quintic_coefficients_from_invariants(invariants, K=None, invariant_ch sage: alpha = quintic.alpha_covariant() sage: beta = quintic.beta_covariant() - sage: g = matrix([[alpha(x0=1,x1=0),alpha(x0=0,x1=1)],[beta(x0=1,x1=0),beta(x0=0,x1=1)]])^-1 - sage: transformed = tuple([g.determinant()^-5*x for x in quintic.transformed(g).coeffs()]) + sage: g = matrix([[alpha(x0=1,x1=0), alpha(x0=0,x1=1)], + ....: [beta(x0=1,x1=0), beta(x0=0,x1=1)]])^-1 + sage: transformed = tuple([g.determinant()^-5*x + ....: for x in quintic.transformed(g).coeffs()]) sage: transformed == reconstructed.coeffs() True @@ -231,7 +234,8 @@ def binary_quintic_coefficients_from_invariants(invariants, K=None, invariant_ch sage: binary_quintic_coefficients_from_invariants([3,1,2], K=GF(5)) Traceback (most recent call last): ... - NotImplementedError: no reconstruction of binary quintics implemented for fields of characteristic 2, 3 or 5 + NotImplementedError: no reconstruction of binary quintics implemented + for fields of characteristic 2, 3 or 5 TESTS:: @@ -262,7 +266,7 @@ def binary_quintic_coefficients_from_invariants(invariants, K=None, invariant_ch N = K(2)**-1 * (A*C-B**2) R2 = -K(2)**-1 * (A*N**2-2*B*M*N+C*M**2) scale = [1,1,1,1,1,1] - from sage.functions.all import binomial + from sage.arith.misc import binomial from sage.misc.functional import sqrt if len(invariants) == 3: if R2.is_square(): diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index 9cad038840c..565e5d12f4c 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -8,8 +8,8 @@ Rational Field sage: S = LaurentSeriesRing(GF(17)['x'], 'y') sage: S - Laurent Series Ring in y over Univariate Polynomial Ring in x over - Finite Field of size 17 + Laurent Series Ring in y over + Univariate Polynomial Ring in x over Finite Field of size 17 sage: S.base_ring() Univariate Polynomial Ring in x over Finite Field of size 17 @@ -47,6 +47,11 @@ from sage.rings.integer_ring import ZZ +try: + from sage.libs.pari.all import pari_gen +except ImportError: + pari_gen = () + def is_LaurentSeriesRing(x): """ @@ -74,7 +79,7 @@ class LaurentSeriesRing(UniqueRepresentation, CommutativeRing): sage: R = LaurentSeriesRing(QQ, 'x'); R Laurent Series Ring in x over Rational Field sage: x = R.0 - sage: g = 1 - x + x^2 - x^4 +O(x^8); g + sage: g = 1 - x + x^2 - x^4 + O(x^8); g 1 - x + x^2 - x^4 + O(x^8) sage: g = 10*x^(-3) + 2006 - 19*x + x^2 - x^4 +O(x^8); g 10*x^-3 + 2006 - 19*x + x^2 - x^4 + O(x^8) @@ -96,23 +101,23 @@ class LaurentSeriesRing(UniqueRepresentation, CommutativeRing): Laurent series rings are determined by their variable and the base ring, and are globally unique:: - sage: K = Qp(5, prec = 5) - sage: L = Qp(5, prec = 200) + sage: # needs sage.rings.padics + sage: K = Qp(5, prec=5) + sage: L = Qp(5, prec=200) sage: R.<x> = LaurentSeriesRing(K) sage: S.<y> = LaurentSeriesRing(L) sage: R is S False - sage: T.<y> = LaurentSeriesRing(Qp(5,prec=200)) + sage: T.<y> = LaurentSeriesRing(Qp(5, prec=200)) sage: S is T True - sage: W.<y> = LaurentSeriesRing(Qp(5,prec=199)) + sage: W.<y> = LaurentSeriesRing(Qp(5, prec=199)) sage: W is T False - sage: K = LaurentSeriesRing(CC, 'q') - sage: K + sage: K = LaurentSeriesRing(CC, 'q'); K # needs sage.rings.real_mpfr Laurent Series Ring in q over Complex Field with 53 bits of precision - sage: loads(K.dumps()) == K + sage: loads(K.dumps()) == K # needs sage.rings.real_mpfr True sage: P = QQ[['x']] sage: F = Frac(P) @@ -126,7 +131,11 @@ class LaurentSeriesRing(UniqueRepresentation, CommutativeRing): sage: R.<x> = k[[]] sage: F = Frac(R) sage: F.category() - Join of Category of complete discrete valuation fields and Category of commutative algebras over (finite enumerated fields and subquotients of monoids and quotients of semigroups) and Category of infinite sets + Join of + Category of complete discrete valuation fields and + Category of commutative algebras over (finite enumerated fields and + subquotients of monoids and quotients of semigroups) and + Category of infinite sets sage: TestSuite(F).run() TESTS: @@ -147,11 +156,14 @@ class LaurentSeriesRing(UniqueRepresentation, CommutativeRing): Check categories (:trac:`24420`):: sage: LaurentSeriesRing(ZZ, 'x').category() - Category of infinite commutative no zero divisors algebras over (euclidean domains and infinite enumerated sets and metric spaces) + Category of infinite commutative no zero divisors algebras + over (euclidean domains and infinite enumerated sets and metric spaces) sage: LaurentSeriesRing(QQ, 'x').category() - Join of Category of complete discrete valuation fields and Category of commutative algebras over (number fields and quotient fields and metric spaces) and Category of infinite sets + Join of Category of complete discrete valuation fields and Category of commutative algebras + over (number fields and quotient fields and metric spaces) and Category of infinite sets sage: LaurentSeriesRing(Zmod(4), 'x').category() - Category of infinite commutative algebras over (finite commutative rings and subquotients of monoids and quotients of semigroups and finite enumerated sets) + Category of infinite commutative algebras + over (finite commutative rings and subquotients of monoids and quotients of semigroups and finite enumerated sets) Check coercions (:trac:`24431`):: @@ -215,27 +227,34 @@ def __init__(self, power_series): sage: RZZ = LaurentSeriesRing(ZZ, 't') sage: RZZ.category() - Category of infinite commutative no zero divisors algebras over (euclidean domains and infinite enumerated sets and metric spaces) + Category of infinite commutative no zero divisors algebras + over (euclidean domains and infinite enumerated sets and metric spaces) sage: TestSuite(RZZ).run() sage: R1 = LaurentSeriesRing(Zmod(1), 't') sage: R1.category() - Category of finite commutative algebras over (finite commutative rings and subquotients of monoids and quotients of semigroups and finite enumerated sets) + Category of finite commutative algebras + over (finite commutative rings and subquotients of monoids and quotients of semigroups and finite enumerated sets) sage: TestSuite(R1).run() sage: R2 = LaurentSeriesRing(Zmod(2), 't') sage: R2.category() - Join of Category of complete discrete valuation fields and Category of commutative algebras over (finite enumerated fields and subquotients of monoids and quotients of semigroups) and Category of infinite sets + Join of Category of complete discrete valuation fields + and Category of commutative algebras over (finite enumerated fields and subquotients of monoids and quotients of semigroups) + and Category of infinite sets sage: TestSuite(R2).run() sage: R4 = LaurentSeriesRing(Zmod(4), 't') sage: R4.category() - Category of infinite commutative algebras over (finite commutative rings and subquotients of monoids and quotients of semigroups and finite enumerated sets) + Category of infinite commutative algebras + over (finite commutative rings and subquotients of monoids and quotients of semigroups and finite enumerated sets) sage: TestSuite(R4).run() sage: RQQ = LaurentSeriesRing(QQ, 't') sage: RQQ.category() - Join of Category of complete discrete valuation fields and Category of commutative algebras over (number fields and quotient fields and metric spaces) and Category of infinite sets + Join of Category of complete discrete valuation fields + and Category of commutative algebras over (number fields and quotient fields and metric spaces) + and Category of infinite sets sage: TestSuite(RQQ).run() """ base_ring = power_series.base_ring() @@ -361,9 +380,9 @@ def _repr_(self): """ EXAMPLES:: - sage: LaurentSeriesRing(QQ,'q') # indirect doctest + sage: LaurentSeriesRing(QQ, 'q') # indirect doctest Laurent Series Ring in q over Rational Field - sage: LaurentSeriesRing(ZZ,'t',sparse=True) + sage: LaurentSeriesRing(ZZ, 't', sparse=True) Sparse Laurent Series Ring in t over Integer Ring """ s = "Laurent Series Ring in %s over %s" % (self.variable_name(), self.base_ring()) @@ -386,6 +405,7 @@ def _element_constructor_(self, x, n=0, prec=infinity): EXAMPLES:: + sage: # needs sage.rings.padics sage: R.<u> = LaurentSeriesRing(Qp(5, 10)) sage: S.<t> = LaurentSeriesRing(RationalField()) sage: R(t + t^2 + O(t^3)) @@ -396,13 +416,14 @@ def _element_constructor_(self, x, n=0, prec=infinity): Coercing an element into its own parent produces that element again, unless a different ``n`` or ``prec`` is given:: - sage: u is R(u) + sage: u is R(u) # needs sage.rings.padics True - sage: R(u, n=3, prec=7) + sage: R(u, n=3, prec=7) # needs sage.rings.padics (1 + O(5^10))*u^4 + O(u^7) Rational functions are accepted:: + sage: # needs sage.rings.number_field sage.symbolic sage: I = sqrt(-1) sage: K.<I> = QQ[I] sage: P.<t> = PolynomialRing(K) @@ -414,7 +435,7 @@ def _element_constructor_(self, x, n=0, prec=infinity): :: - sage: L(t*I) / L(t^3+I*2*t) + sage: L(t*I) / L(t^3+I*2*t) # needs sage.rings.number_field sage.symbolic 1/2 + 1/4*I*u^2 - 1/8*u^4 - 1/16*I*u^6 + 1/32*u^8 + 1/64*I*u^10 - 1/128*u^12 - 1/256*I*u^14 + 1/512*u^16 + 1/1024*I*u^18 + O(u^20) @@ -423,8 +444,9 @@ def _element_constructor_(self, x, n=0, prec=infinity): Check that :trac:`28993` is fixed:: - sage: from sage.modular.etaproducts import qexp_eta - sage: qexp_eta(S, prec=30) + sage: from sage.modular.etaproducts import qexp_eta # needs sage.modular + sage: S.<t> = LaurentSeriesRing(RationalField()) + sage: qexp_eta(S, prec=30) # needs sage.modular 1 - t - t^2 + t^5 + t^7 - t^12 - t^15 + t^22 + t^26 + O(t^30) When converting from `R((z))` to `R((z))((w))`, the variable @@ -439,6 +461,7 @@ def _element_constructor_(self, x, n=0, prec=infinity): Various conversions from PARI (see also :trac:`2508`):: + sage: # needs sage.libs.pari sage: L.<q> = LaurentSeriesRing(QQ, default_prec=10) sage: L(pari('1/x')) q^-1 @@ -466,10 +489,9 @@ def _element_constructor_(self, x, n=0, prec=infinity): x^-3 """ from sage.rings.fraction_field_element import is_FractionFieldElement - from sage.rings.polynomial.polynomial_element import is_Polynomial - from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial + from sage.rings.polynomial.polynomial_element import Polynomial + from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.structure.element import parent - from sage.libs.pari.all import pari_gen P = parent(x) if isinstance(x, self.element_class) and n == 0 and P is self: @@ -500,7 +522,7 @@ def _element_constructor_(self, x, n=0, prec=infinity): return (self(self.polynomial_ring()(x)) << n).add_bigoh(prec) elif (is_FractionFieldElement(x) and (x.base_ring() is self.base_ring() or x.base_ring() == self.base_ring()) - and (is_Polynomial(x.numerator()) or is_MPolynomial(x.numerator()))): + and isinstance(x.numerator(), (Polynomial, MPolynomial))): x = self(x.numerator()) / self(x.denominator()) return (x << n).add_bigoh(prec) return self.element_class(self, x, n).add_bigoh(prec) @@ -559,9 +581,9 @@ def construction(self): sage: parent(1/2 * t) Laurent Series Ring in t over Rational Field - sage: QQbar.gen() * t + sage: QQbar.gen() * t # needs sage.rings.number_field I*t - sage: parent(QQbar.gen() * t) + sage: parent(QQbar.gen() * t) # needs sage.rings.number_field Laurent Series Ring in t over Algebraic Field """ from sage.categories.pushout import CompletionFunctor @@ -623,9 +645,10 @@ def _coerce_map_from_(self, P): A = self.base_ring() from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.power_series_ring import is_PowerSeriesRing - from sage.rings.polynomial.laurent_polynomial_ring import is_LaurentPolynomialRing + from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic + if ((is_LaurentSeriesRing(P) or - is_LaurentPolynomialRing(P) or + isinstance(P, LaurentPolynomialRing_generic) or is_PowerSeriesRing(P) or is_PolynomialRing(P)) and P.variable_name() == self.variable_name() @@ -636,13 +659,15 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): """ EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<x> = LaurentSeriesRing(GF(17)) sage: S.<y> = LaurentSeriesRing(GF(19)) sage: R.hom([y], S) # indirect doctest Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators - sage: f = R.hom(x+x^3,R) + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators + sage: f = R.hom(x + x^3, R) sage: f(x^2) x^2 + 2*x^4 + x^6 diff --git a/src/sage/rings/laurent_series_ring_element.pxd b/src/sage/rings/laurent_series_ring_element.pxd index d190645ce52..8df5a92c9e7 100644 --- a/src/sage/rings/laurent_series_ring_element.pxd +++ b/src/sage/rings/laurent_series_ring_element.pxd @@ -4,7 +4,7 @@ cdef class LaurentSeries(AlgebraElement): cdef ModuleElement __u cdef long __n - cdef __normalize(self) + cdef _normalize(self) cpdef _add_(self, other) cpdef _mul_(self, other) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 2dee178608b..d56996f3f78 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -21,19 +21,18 @@ We compute with a Laurent series over the complex mpfr numbers. :: - sage: K.<q> = Frac(CC[['q']]) - sage: K + sage: K.<q> = Frac(CC[['q']]); K # needs sage.rings.real_mpfr Laurent Series Ring in q over Complex Field with 53 bits of precision - sage: q + sage: q # needs sage.rings.real_mpfr 1.00000000000000*q Saving and loading. :: - sage: loads(q.dumps()) == q + sage: loads(q.dumps()) == q # needs sage.rings.real_mpfr True - sage: loads(K.dumps()) == K + sage: loads(K.dumps()) == K # needs sage.rings.real_mpfr True IMPLEMENTATION: Laurent series in Sage are represented internally @@ -51,7 +50,7 @@ AUTHORS: - Robert Bradshaw: Cython version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # 2017 Vincent Delecroix <20100.delecroix@gmail.com> # @@ -64,19 +63,16 @@ AUTHORS: # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from .infinity import infinity -from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -import sage.rings.polynomial.polynomial_element as polynomial import sage.misc.latex -from sage.rings.integer import Integer from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_univariate from .power_series_ring_element cimport PowerSeries -from sage.structure.element cimport Element, ModuleElement, RingElement, AlgebraElement +from sage.structure.element cimport Element, AlgebraElement from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool from sage.misc.derivative import multi_derivative @@ -112,11 +108,12 @@ cdef class LaurentSeries(AlgebraElement): sage: R.<q> = LaurentSeriesRing(ZZ) sage: R([1,2,3]) 1 + 2*q + 3*q^2 - sage: R([1,2,3],-5) + sage: R([1,2,3], -5) q^-5 + 2*q^-4 + 3*q^-3 :: + sage: # needs sage.rings.finite_rings sage.rings.padics sage: S.<s> = LaurentSeriesRing(GF(5)) sage: T.<t> = PowerSeriesRing(pAdicRing(5)) sage: S(t) @@ -197,9 +194,9 @@ cdef class LaurentSeries(AlgebraElement): EXAMPLES:: sage: R.<t> = LaurentSeriesRing(QQ) - sage: (2+t).is_unit() + sage: (2 + t).is_unit() True - sage: f = 2+t^2+O(t^10); f.is_unit() + sage: f = 2 + t^2 + O(t^10); f.is_unit() True sage: 1/f 1/2 - 1/4*t^2 + 1/8*t^4 - 1/16*t^6 + 1/32*t^8 + O(t^10) @@ -235,7 +232,7 @@ cdef class LaurentSeries(AlgebraElement): def is_monomial(self): """ - Return True if this element is a monomial. That is, if self is + Return ``True`` if this element is a monomial. That is, if self is `x^n` for some integer `n`. EXAMPLES:: @@ -283,10 +280,11 @@ cdef class LaurentSeries(AlgebraElement): def _im_gens_(self, codomain, im_gens, base_map=None): """ Return the image of this series under the map that sends the generators of - the parent to im_gens. + the parent to ``im_gens``. EXAMPLES:: + sage: # needs sage.rings.number_field sage: Zx.<x> = ZZ[] sage: K.<i> = NumberField(x^2 + 1) sage: R.<t> = LaurentSeriesRing(K) @@ -294,10 +292,10 @@ cdef class LaurentSeries(AlgebraElement): sage: z._im_gens_(R, [t^2]) t^-2 + i*t^2 - The argument base_map is not yet supported, because it isn't over power series:: + The argument ``base_map`` is not yet supported, because it isn't over power series:: - sage: cc = K.hom([i]) - sage: z._im_gens_(R, [t^2], base_map=cc) + sage: cc = K.hom([i]) # needs sage.rings.number_field + sage: z._im_gens_(R, [t^2], base_map=cc) # needs sage.rings.number_field Traceback (most recent call last): ... NotImplementedError @@ -305,7 +303,7 @@ cdef class LaurentSeries(AlgebraElement): x = im_gens[0] return codomain(self.__u._im_gens_(codomain, im_gens, base_map=base_map) * x**self.__n) - cdef __normalize(self): + cdef _normalize(self): r""" A Laurent series is a pair (u(t), n), where either u=0 (to some precision) or u is a unit. This pair corresponds to @@ -339,7 +337,7 @@ cdef class LaurentSeries(AlgebraElement): X = self._parent.variable_name() atomic_repr = self._parent.base_ring()._repr_option('element_is_atomic') first = True - for n in xrange(m): + for n in range(m): x = v[n] e = n + valuation x = str(x) @@ -442,9 +440,9 @@ cdef class LaurentSeries(AlgebraElement): Verify that :trac:`6656` has been fixed:: - sage: R.<a,b>=PolynomialRing(QQ) - sage: T.<x>=LaurentSeriesRing(R) - sage: y = a*x+b*x + sage: R.<a,b> = PolynomialRing(QQ) + sage: T.<x> = LaurentSeriesRing(R) + sage: y = a*x + b*x sage: y._latex_() '\\left(a + b\\right)x' sage: latex(y) @@ -462,7 +460,7 @@ cdef class LaurentSeries(AlgebraElement): X = self._parent.latex_variable_names()[0] atomic_repr = self._parent.base_ring()._repr_option('element_is_atomic') first = True - for n in xrange(m): + for n in range(m): x = v[n] e = n + valuation x = sage.misc.latex.latex(x) @@ -523,22 +521,32 @@ cdef class LaurentSeries(AlgebraElement): sage: f = -5/t^(10) + 1/3 + t + t^2 - 10/3*t^3 + O(t^5); f -5*t^-10 + 1/3 + t + t^2 - 10/3*t^3 + O(t^5) - Slicing is deprecated:: + Slicing can be used to truncate, keeping the same precision:: - sage: f[-10:2] - doctest:...: DeprecationWarning: polynomial slicing with a start index is deprecated, use list() and slice the resulting list instead - See https://github.com/sagemath/sage/issues/18940 for details. + sage: f[:2] -5*t^-10 + 1/3 + t + O(t^5) + + Any other kind of slicing is an error, see :trac:`18940`:: + + sage: f[-10:2:2] + Traceback (most recent call last): + ... + IndexError: polynomial slicing with a step is not defined + sage: f[0:] - 1/3 + t + t^2 - 10/3*t^3 + O(t^5) + Traceback (most recent call last): + ... + IndexError: polynomial slicing with a start is not defined """ if isinstance(i, slice): start, stop, step = i.start, i.stop, i.step - if start is None: - start = 0 + if step is not None: + raise IndexError("polynomial slicing with a step is not defined") + if start is not None: + raise IndexError("polynomial slicing with a start is not defined") if stop > self.__u.degree() or stop is None: stop = self.__u.degree() - f = self.__u[start-self.__n:stop-self.__n:step] # deprecation(18940) + f = self.__u[:stop - self.__n] return type(self)(self._parent, f, self.__n) return self.__u[i - self.__n] @@ -606,10 +614,10 @@ cdef class LaurentSeries(AlgebraElement): EXAMPLES:: sage: t = LaurentSeriesRing(ZZ,'t').gen() - sage: f = 1/t**2+2/t+3+4*t + sage: f = 1/t**2 + 2/t + 3 + 4*t sage: f.residue() 2 - sage: f = t+t**2 + sage: f = t + t**2 sage: f.residue() 0 sage: f.residue().parent() @@ -661,6 +669,7 @@ cdef class LaurentSeries(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A.<t> = LaurentSeriesRing(GF(5)) sage: x = t^(-1) + t^2 + O(t^5) sage: x.lift_to_precision(10) @@ -718,7 +727,7 @@ cdef class LaurentSeries(AlgebraElement): R = self._parent.base_ring() coeffs = [value] + [R(0) for _ in range(1,-j)] + self.__u.list() self.__u = self.__u._parent(coeffs) - self.__normalize() + self._normalize() cpdef _add_(self, right_m): """ @@ -744,6 +753,14 @@ cdef class LaurentSeries(AlgebraElement): t^-3 + t^3 + O(t^9) ALGORITHM: Shift the unit parts to align them, then add. + + TESTS: + + Verify that :trac:`35860` is fixed:: + + sage: R.<t> = LaurentPolynomialRing(ZZ) + sage: sqrt(t^2) + t^-1 + t^-1 + t """ cdef LaurentSeries right = <LaurentSeries>right_m cdef long m @@ -1018,7 +1035,8 @@ cdef class LaurentSeries(AlgebraElement): sage: A.<x> = LaurentSeriesRing(ZZ) sage: f = 1/(1-x) sage: f - 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8 + x^9 + x^10 + x^11 + x^12 + x^13 + x^14 + x^15 + x^16 + x^17 + x^18 + x^19 + O(x^20) + 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8 + x^9 + x^10 + x^11 + + x^12 + x^13 + x^14 + x^15 + x^16 + x^17 + x^18 + x^19 + O(x^20) sage: f.truncate(10) 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8 + x^9 """ @@ -1036,7 +1054,8 @@ cdef class LaurentSeries(AlgebraElement): sage: A.<x> = LaurentSeriesRing(ZZ) sage: f = 1/(1-x) sage: f - 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8 + x^9 + x^10 + x^11 + x^12 + x^13 + x^14 + x^15 + x^16 + x^17 + x^18 + x^19 + O(x^20) + 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8 + x^9 + x^10 + x^11 + + x^12 + x^13 + x^14 + x^15 + x^16 + x^17 + x^18 + x^19 + O(x^20) sage: f.truncate_laurentseries(10) 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8 + x^9 + O(x^10) """ @@ -1246,7 +1265,6 @@ cdef class LaurentSeries(AlgebraElement): deg = prec - 1 cdef long i - cdef int c for i in range(val, deg + 1): li = self[i] ri = right[i] @@ -1479,8 +1497,11 @@ cdef class LaurentSeries(AlgebraElement): ring:: sage: R.<x> = LaurentSeriesRing(QQ, default_prec=20) - sage: (x - x^2).reverse() # get some Catalan numbers - x + x^2 + 2*x^3 + 5*x^4 + 14*x^5 + 42*x^6 + 132*x^7 + 429*x^8 + 1430*x^9 + 4862*x^10 + 16796*x^11 + 58786*x^12 + 208012*x^13 + 742900*x^14 + 2674440*x^15 + 9694845*x^16 + 35357670*x^17 + 129644790*x^18 + 477638700*x^19 + O(x^20) + sage: (x - x^2).reverse() # get some Catalan numbers + x + x^2 + 2*x^3 + 5*x^4 + 14*x^5 + 42*x^6 + 132*x^7 + 429*x^8 + 1430*x^9 + + 4862*x^10 + 16796*x^11 + 58786*x^12 + 208012*x^13 + 742900*x^14 + + 2674440*x^15 + 9694845*x^16 + 35357670*x^17 + 129644790*x^18 + + 477638700*x^19 + O(x^20) sage: (x - x^2).reverse(precision=3) x + x^2 + O(x^3) @@ -1579,8 +1600,8 @@ cdef class LaurentSeries(AlgebraElement): TESTS:: - sage: y = var('y') - sage: f.derivative(y) + sage: y = var('y') # needs sage.symbolic + sage: f.derivative(y) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y @@ -1682,6 +1703,7 @@ cdef class LaurentSeries(AlgebraElement): sage: (x^-2 + 1 + x).nth_root(2)**2 x^-2 + 1 + x + O(x^18) + sage: # needs sage.modular sage: j = j_invariant_qexp() sage: q = j.parent().gen() sage: j(q^3).nth_root(3) @@ -1733,6 +1755,7 @@ cdef class LaurentSeries(AlgebraElement): Check whether a polynomial over a Laurent series ring is contained in the polynomial ring over the power series ring (see :trac:`19459`): + sage: # needs sage.rings.finite_rings sage: L.<t> = LaurentSeriesRing(GF(2)) sage: R.<x,y> = PolynomialRing(L) sage: S.<x,y> = PolynomialRing(L._power_series_ring) @@ -1756,8 +1779,8 @@ cdef class LaurentSeries(AlgebraElement): Test for :trac:`32440`:: - sage: L.<x> = LaurentSeriesRing(QQ, implementation='pari') - sage: (x + O(x^3)).power_series() + sage: L.<x> = LaurentSeriesRing(QQ, implementation='pari') # needs sage.libs.pari + sage: (x + O(x^3)).power_series() # needs sage.libs.pari x + O(x^3) """ if self.__n < 0: @@ -1798,13 +1821,13 @@ cdef class LaurentSeries(AlgebraElement): x*t^-2 + O(t^2) sage: f(y=x) x*t^-2 + x*t^2 + O(t^8) - sage: f(t^3, x=2, y=x+x^2) + sage: f(t^3, x=2, y=x + x^2) 2*t^-6 + (x^2 + x)*t^6 + O(t^24) sage: f(t^3, 2, x+x^2) 2*t^-6 + (x^2 + x)*t^6 + O(t^24) - sage: f(x=2, t=t^3, y=x+x^2) + sage: f(x=2, t=t^3, y=x + x^2) 2*t^-6 + (x^2 + x)*t^6 + O(t^24) - sage: f(2, x+x^2, t=t^3) + sage: f(2, x + x^2, t=t^3) Traceback (most recent call last): ... ValueError: must not specify t keyword and positional argument @@ -1818,9 +1841,9 @@ cdef class LaurentSeries(AlgebraElement): Test for :trac:`23928`:: - sage: R.<x> = LaurentSeriesRing(QQ, implementation='pari') - sage: f = x.add_bigoh(7) - sage: f(x) + sage: R.<x> = LaurentSeriesRing(QQ, implementation='pari') # needs sage.libs.pari + sage: f = x.add_bigoh(7) # needs sage.libs.pari + sage: f(x) # needs sage.libs.pari x + O(x^7) """ if len(kwds) >= 1: @@ -1860,16 +1883,17 @@ cdef class LaurentSeries(AlgebraElement): sage: L.<x> = LaurentSeriesRing(QQ) sage: f = x + 1/x + O(x^2); f x^-1 + x + O(x^2) - sage: f.__pari__() + sage: f.__pari__() # needs sage.libs.pari x^-1 + x + O(x^2) Check that :trac:`32437` is fixed:: + sage: # needs sage.rings.finite_rings sage: F.<u> = GF(257^2) sage: R.<t> = LaurentSeriesRing(F) sage: g = t + O(t^99) sage: f = u*t + O(t^99) - sage: g(f) # indirect doctest + sage: g(f) # indirect doctest # needs sage.libs.pari u*t + O(t^99) """ f = self.__u diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 51eeaf5d065..8086e15f9ef 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -39,7 +39,7 @@ sage: s.coefficient(10) 10 sage: s._coeff_stream._cache - {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 10: 10} + {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 10: 10} Using the dense implementation, all coefficients up to the required coefficient are computed. :: @@ -50,7 +50,7 @@ sage: s.coefficient(10) 10 sage: s._coeff_stream._cache - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] We can do arithmetic with lazy power series:: @@ -83,21 +83,21 @@ A similar statement is true for lazy symmetric functions:: - sage: h = SymmetricFunctions(QQ).h() - sage: L = LazySymmetricFunctions(h) - sage: 1 / (1-L(h[1])) + sage: h = SymmetricFunctions(QQ).h() # needs sage.combinat + sage: L = LazySymmetricFunctions(h) # needs sage.combinat + sage: 1 / (1-L(h[1])) # needs sage.combinat h[] + h[1] + (h[1,1]) + (h[1,1,1]) + (h[1,1,1,1]) + (h[1,1,1,1,1]) + (h[1,1,1,1,1,1]) + O^7 We can change the base ring:: sage: h = g.change_ring(QQ) - sage: h.parent() + sage: h.parent() # needs sage.combinat Lazy Laurent Series Ring in z over Rational Field - sage: h - 4*z + 6*z^2 + 8*z^3 + 19*z^4 + 38*z^5 + 71*z^6 + O(z^7) - sage: hinv = h^-1; hinv + sage: h # needs sage.combinat + 4*z + 6*z^2 + 8*z^3 + 19*z^4 + 38*z^5 + 71*z^6 + 130*z^7 + O(z^8) + sage: hinv = h^-1; hinv # needs sage.combinat 1/4*z^-1 - 3/8 + 1/16*z - 17/32*z^2 + 5/64*z^3 - 29/128*z^4 + 165/256*z^5 + O(z^6) - sage: hinv.valuation() + sage: hinv.valuation() # needs sage.combinat -1 TESTS: @@ -145,9 +145,9 @@ sage: check(L, z) sage: L.<z> = LazyPowerSeriesRing(QQ) sage: check(L, z) - sage: p = SymmetricFunctions(QQ).p() - sage: L = LazySymmetricFunctions(p) - sage: check(L, L(p[1])) + sage: p = SymmetricFunctions(QQ).p() # needs sage.combinat + sage: L = LazySymmetricFunctions(p) # needs sage.combinat + sage: check(L, L(p[1])) # needs sage.combinat We check that the elements in the cache of the stream of homogeneous components are in the correct ring:: @@ -175,8 +175,8 @@ sage: check(L, lambda n: n, valuation=-5) sage: check(L, gen(), valuation=-5) - sage: L = LazyDirichletSeriesRing(QQbar, "s") - sage: check(L, lambda n: n, valuation=2) + sage: L = LazyDirichletSeriesRing(QQbar, "s") # needs sage.rings.number_field + sage: check(L, lambda n: n, valuation=2) # needs sage.rings.number_field sage: check(L, gen(), valuation=2) sage: L.<z> = LazyPowerSeriesRing(GF(2)) @@ -184,17 +184,31 @@ sage: check(L, gen(), valuation=0) sage: L.<x,y> = LazyPowerSeriesRing(GF(2)) - sage: check(L, lambda n: (x + y)^n, valuation=None) + sage: check(L, lambda n: (x + y)^n, valuation=None) # needs sage.rings.finite_rings sage: def gen(): ....: n = 0 ....: while True: ....: yield (x+y)^n ....: n += 1 - sage: check(L, gen(), valuation=None) + sage: check(L, gen(), valuation=None) # needs sage.rings.finite_rings + + sage: s = SymmetricFunctions(GF(2)).s() # needs sage.combinat + sage: L = LazySymmetricFunctions(s) # needs sage.combinat + sage: check(L, lambda n: sum(k*s(la) for k, la in enumerate(Partitions(n))), # needs sage.combinat + ....: valuation=0) + +Check that we can invert matrices:: + + sage: L.<z> = LazyLaurentSeriesRing(QQ) + sage: a11 = 1 + L(lambda n: 1 if not n else 0, valuation=0) + sage: a12 = 1 + L(lambda n: 1 if n == 1 else 0, valuation=0) + sage: a21 = 1 + L(lambda n: 1 if n == 2 else 0, valuation=0) + sage: a22 = 1 + L(lambda n: 1 if n == 3 else 0, valuation=0) + sage: m = matrix([[a11, a12], [a21, a22]]) + sage: m.inverse() + [ 1 + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) -1 - 2*z - 3*z^2 - 4*z^3 - 5*z^4 - 6*z^5 - 7*z^6 + O(z^7)] + [ -1 - z - 3*z^2 - 3*z^3 - 5*z^4 - 5*z^5 - 7*z^6 + O(z^7) 2 + 2*z + 4*z^2 + 4*z^3 + 6*z^4 + 6*z^5 + 8*z^6 + O(z^7)] - sage: s = SymmetricFunctions(GF(2)).s() - sage: L = LazySymmetricFunctions(s) - sage: check(L, lambda n: sum(k*s(la) for k, la in enumerate(Partitions(n))), valuation=0) """ # **************************************************************************** @@ -211,14 +225,14 @@ from sage.structure.element import Element, parent from sage.structure.richcmp import op_EQ, op_NE -from sage.functions.other import factorial from sage.misc.misc_c import prod from sage.arith.power import generic_power from sage.arith.functions import lcm -from sage.arith.misc import divisors, moebius +from sage.arith.misc import divisors, factorial, moebius from sage.combinat.partition import Partition, Partitions from sage.misc.derivative import derivative_parse from sage.categories.integral_domains import IntegralDomains +from sage.categories.rings import Rings from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -228,6 +242,7 @@ from sage.data_structures.stream import ( Stream_add, Stream_cauchy_mul, + Stream_cauchy_mul_commutative, Stream_sub, Stream_cauchy_compose, Stream_lmul, @@ -239,6 +254,7 @@ Stream_exact, Stream_uninitialized, Stream_shift, + Stream_truncated, Stream_function, Stream_derivative, Stream_dirichlet_convolve, @@ -295,9 +311,9 @@ def __init__(self, parent, coeff_stream): sage: L.<z> = LazyLaurentSeriesRing(ZZ) sage: TestSuite(L.an_element()).run() - sage: L = LazyDirichletSeriesRing(QQbar, 'z') - sage: g = L(constant=1) - sage: TestSuite(g).run() + sage: L = LazyDirichletSeriesRing(QQbar, 'z') # needs sage.rings.number_field + sage: g = L(constant=1) # needs sage.rings.number_field + sage: TestSuite(g).run() # needs sage.rings.number_field """ Element.__init__(self, parent) self._coeff_stream = coeff_stream @@ -366,7 +382,7 @@ def __getitem__(self, n): sage: f[:3] [] sage: f._coeff_stream._cache - {1: 0, 2: 0} + {} """ R = self.parent()._internal_poly_ring.base_ring() coeff_stream = self._coeff_stream @@ -489,15 +505,17 @@ def map_coefficients(self, f): sage: m = L(lambda n: n, valuation=0); m z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: m.map_coefficients(lambda c: c + 1) - 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + 8*z^7 + O(z^8) Similarly for Dirichlet series:: sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: s = L(lambda n: n-1); s + sage: s = L(lambda n: n-1) + sage: s # needs sage.symbolic 1/(2^z) + 2/3^z + 3/4^z + 4/5^z + 5/6^z + 6/7^z + O(1/(8^z)) - sage: s.map_coefficients(lambda c: c + 1) - 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) + sage: ms = s.map_coefficients(lambda c: c + 1) # needs sage.symbolic + sage: ms # needs sage.symbolic + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + 8/8^z + O(1/(9^z)) Similarly for multivariate power series:: @@ -517,6 +535,7 @@ def map_coefficients(self, f): Similarly for lazy symmetric functions:: + sage: # needs sage.combinat sage: p = SymmetricFunctions(QQ).p() sage: L = LazySymmetricFunctions(p) sage: f = 1/(1-2*L(p[1])); f @@ -540,7 +559,7 @@ def map_coefficients(self, f): sage: m = L(lambda n: n, valuation=0); m z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: m.map_coefficients(lambda c: c + 1) - 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + 8*z^7 + O(z^8) Test the zero series:: @@ -584,7 +603,8 @@ def map_coefficients(self, f): def truncate(self, d): r""" - Return this series with its terms of degree >= ``d`` truncated. + Return the series obtained by removing all terms of degree at least + ``d``. INPUT: @@ -621,11 +641,22 @@ def truncate(self, d): sage: M = z + z^2 + z^3 + z^4 sage: M.truncate(4) z + z^2 + z^3 + + TESTS: + + Check that :issue:`36154` is fixed:: + + sage: L.<z> = LazyPowerSeriesRing(QQ) + sage: f = L([0,1,2]) + sage: f.truncate(1) + 0 """ P = self.parent() coeff_stream = self._coeff_stream v = coeff_stream._approximate_order initial_coefficients = [coeff_stream[i] for i in range(v, d)] + if not any(initial_coefficients): + return P.zero() return P.element_class(P, Stream_exact(initial_coefficients, order=v)) def shift(self, n): @@ -633,7 +664,13 @@ def shift(self, n): Return ``self`` with the indices shifted by ``n``. For example, a Laurent series is multiplied by the power `z^n`, - where `z` is the variable of ``self``. + where `z` is the variable of ``self``. For series with a fixed + minimal valuation (e.g., power series), this removes any terms + that are less than the minimal valuation. + + INPUT: + + - ``n`` -- the amount to shift EXAMPLES:: @@ -652,11 +689,69 @@ def shift(self, n): 2 + 3*z^2 + z^5 + z^6 + z^7 + O(z^8) sage: D = LazyDirichletSeriesRing(QQ, 't') - sage: f = D([0,1,2]); f + sage: f = D([0,1,2]) + sage: f # needs sage.symbolic 1/(2^t) + 2/3^t - sage: f.shift(3) + sage: sf = f.shift(3) + sage: sf # needs sage.symbolic 1/(5^t) + 2/6^t + Examples with power series (where the minimal valuation is `0`):: + + sage: L.<x> = LazyPowerSeriesRing(QQ) + sage: f = 1 / (1 - x) + sage: f.shift(2) + x^2 + x^3 + x^4 + O(x^5) + sage: g = f.shift(-1); g + 1 + x + x^2 + O(x^3) + sage: f == g + True + sage: g[-1] + 0 + sage: h = L(lambda n: 1) + sage: LazyPowerSeriesRing.options.halting_precision(20) # verify up to degree 20 + sage: f == h + True + sage: h == f + True + sage: h.shift(-1) == h + True + sage: LazyPowerSeriesRing.options._reset() + + sage: fp = L([3,3,3], constant=1) + sage: fp.shift(2) + 3*x^2 + 3*x^3 + 3*x^4 + x^5 + x^6 + x^7 + O(x^8) + sage: fp.shift(-2) + 3 + x + x^2 + x^3 + O(x^4) + sage: fp.shift(-7) + 1 + x + x^2 + O(x^3) + sage: fp.shift(-5) == g + True + + We compare the shifting with converting to the fraction field + (see also :trac:`35293`):: + + sage: M = L.fraction_field() + sage: f = L([1,2,3,4]); f + 1 + 2*x + 3*x^2 + 4*x^3 + sage: f.shift(-3) + 4 + sage: M(f).shift(-3) + x^-3 + 2*x^-2 + 3*x^-1 + 4 + + An example with a more general function:: + + sage: fun = lambda n: 1 if ZZ(n).is_power_of(2) else 0 + sage: f = L(fun); f + x + x^2 + x^4 + O(x^7) + sage: fs = f.shift(-4) + sage: fs + 1 + x^4 + O(x^7) + sage: fs.shift(4) + x^4 + x^8 + O(x^11) + sage: M(f).shift(-4) + x^-3 + x^-2 + 1 + O(x^4) + TESTS:: sage: L.<z> = LazyLaurentSeriesRing(QQ) @@ -669,35 +764,100 @@ def shift(self, n): 0 sage: L.<x> = LazyPowerSeriesRing(QQ) + sage: M = L.fraction_field() sage: f = x.shift(-3); f + 0 + sage: f = M(x).shift(-3); f x^-2 sage: f.parent() Lazy Laurent Series Ring in x over Rational Field + + sage: L.<x, y> = LazyPowerSeriesRing(QQ) + sage: f = x.shift(2) + Traceback (most recent call last): + ... + ValueError: arity must be equal to 1 + + sage: L.<x> = LazyPowerSeriesRing(QQ) + sage: f = L([1,2,3,4]) + sage: f.shift(-10) == L.zero() + True + + Check the truncation works correctly:: + + sage: f = L(lambda n: 1 if ZZ(n).is_power_of(2) else 0) + sage: f.valuation() + 1 + sage: f._coeff_stream._true_order + True + sage: g = f.shift(-5) + sage: g + x^3 + O(x^7) + sage: g._coeff_stream._approximate_order + 3 + sage: g._coeff_stream._true_order + True + sage: g.valuation() + 3 + + sage: f = L(lambda n: 1 if ZZ(n).is_power_of(2) else 0) + sage: g = f.shift(-5) + sage: g._coeff_stream._approximate_order + 0 + sage: g._coeff_stream._true_order + False + sage: g.valuation() + 3 + + sage: f = L([1,2,3,4], constant=7) + sage: fs = f.shift(-4) + sage: fs = f.shift(-4); fs + 7 + 7*x + 7*x^2 + O(x^3) + sage: fs.shift(4) + 7*x^4 + 7*x^5 + 7*x^6 + O(x^7) + + sage: f = L([1,2,3,4], constant=0) + sage: type(f.shift(-5)._coeff_stream) + <class 'sage.data_structures.stream.Stream_zero'> """ + P = self.parent() + if P._arity != 1: + raise ValueError("arity must be equal to 1") + if isinstance(self._coeff_stream, Stream_zero): return self - elif isinstance(self._coeff_stream, Stream_shift): + + if isinstance(self._coeff_stream, Stream_shift): n += self._coeff_stream._shift if n: - coeff_stream = Stream_shift(self._coeff_stream._series, n) + if (P._minimal_valuation is not None + and P._minimal_valuation > self._coeff_stream._approximate_order + n): + coeff_stream = Stream_truncated(self._coeff_stream._series, n, P._minimal_valuation) + else: + coeff_stream = Stream_shift(self._coeff_stream._series, n) else: coeff_stream = self._coeff_stream._series elif isinstance(self._coeff_stream, Stream_exact): init_coeff = self._coeff_stream._initial_coefficients degree = self._coeff_stream._degree + n valuation = self._coeff_stream._approximate_order + n + if P._minimal_valuation is not None and P._minimal_valuation > valuation: + # We need to truncate some terms + init_coeff = init_coeff[P._minimal_valuation-valuation:] + if not init_coeff and not self._coeff_stream._constant: + return P.zero() + degree = max(degree, P._minimal_valuation) + valuation = P._minimal_valuation coeff_stream = Stream_exact(init_coeff, constant=self._coeff_stream._constant, order=valuation, degree=degree) else: - coeff_stream = Stream_shift(self._coeff_stream, n) - P = self.parent() - # If we shift it too much, then it needs to go into the fraction field - # FIXME? This is different than the polynomial rings, which truncates the terms - if (coeff_stream._true_order - and P._minimal_valuation is not None - and coeff_stream._approximate_order < P._minimal_valuation): - P = P.fraction_field() + if (P._minimal_valuation is not None + and P._minimal_valuation > self._coeff_stream._approximate_order + n): + coeff_stream = Stream_truncated(self._coeff_stream, n, P._minimal_valuation) + else: + coeff_stream = Stream_shift(self._coeff_stream, n) + return P.element_class(P, coeff_stream) __lshift__ = shift @@ -792,6 +952,15 @@ def _richcmp_(self, other, op): sage: z + z^2 < z^2 + z False + sage: fz = L(lambda n: 0, valuation=0) + sage: L.zero() == fz + False + sage: fz == L.zero() + False + + With using secure computations:: + + sage: L.options.secure = True sage: fz = L(lambda n: 0, valuation=0) sage: L.zero() == fz Traceback (most recent call last): @@ -801,6 +970,22 @@ def _richcmp_(self, other, op): Traceback (most recent call last): ... ValueError: undecidable + sage: fz != L.zero() + Traceback (most recent call last): + ... + ValueError: undecidable + + With using finite halting precision (which ignores + the ``secure`` option):: + + sage: L.options.halting_precision = 40 + sage: fz = L(lambda n: 0, valuation=0) + sage: L.zero() == fz + True + sage: fz == L.zero() + True + + sage: L.options._reset() TESTS:: @@ -809,33 +994,17 @@ def _richcmp_(self, other, op): sage: g = L([0,0,1,0,1,0,0], degree=7, constant=1) sage: f == g True - """ if op is op_EQ: - if isinstance(self._coeff_stream, Stream_zero): - if isinstance(other._coeff_stream, Stream_zero): - return True - if other._coeff_stream.is_nonzero(): - return False - elif isinstance(other._coeff_stream, Stream_zero): - if self._coeff_stream.is_nonzero(): - return False - elif isinstance(self._coeff_stream, Stream_exact): - if isinstance(other._coeff_stream, Stream_exact): - return self._coeff_stream == other._coeff_stream - if self._coeff_stream != other._coeff_stream: - return False - elif isinstance(other._coeff_stream, Stream_exact): - if other._coeff_stream != self._coeff_stream: - return False - else: - # both streams are inexact, perhaps they are equal by - # construction - if self._coeff_stream == other._coeff_stream: - return True - # perhaps their caches are different - if self._coeff_stream != other._coeff_stream: - return False + if self._coeff_stream == other._coeff_stream: + return True + + if (not self.parent().options['secure'] + and self.parent().options['halting_precision'] is None): + return False + + if self._coeff_stream != other._coeff_stream: + return False # undecidable otherwise prec = self.parent().options['halting_precision'] @@ -847,8 +1016,12 @@ def _richcmp_(self, other, op): return all(self[i] == other[i] for i in range(m, m + prec)) if op is op_NE: - return not (self == other) + ret = (self == other) + if ret is None: + return ret + return not ret + # FIXME: This should check for equality in <= and >= and other return NotImplemented return False def __hash__(self): @@ -871,17 +1044,16 @@ def __bool__(self): """ Test whether ``self`` is not zero. - An uninitialized series returns ``True`` as it is considered - as a formal variable, such as a generator of a polynomial - ring. + When the halting precision is infinite, then any series that is + not known to be zero will be ``True``. TESTS:: + sage: # needs sage.rings.finite_rings sage: L.<z> = LazyLaurentSeriesRing(GF(2)) - sage: bool(z-z) + sage: bool(z - z) False - sage: f = 1/(1 - z) - sage: bool(f) + sage: bool(1/(1 - z)) True sage: M = L(lambda n: n, valuation=0); M z + z^3 + z^5 + O(z^7) @@ -890,28 +1062,39 @@ def __bool__(self): sage: M = L(lambda n: 2*n if n < 10 else 1, valuation=0); M O(z^7) sage: bool(M) + True + + With the `secure` option, we raise an error if we cannot know + whether the series is zero or not:: + + sage: # needs sage.rings.finite_rings + sage: L.options.secure = True + sage: bool(M) Traceback (most recent call last): ... - ValueError: undecidable as lazy Laurent series + ValueError: undecidable sage: M[15] 1 sage: bool(M) True + sage: # needs sage.rings.finite_rings sage: L.<z> = LazyLaurentSeriesRing(GF(2), sparse=True) sage: M = L(lambda n: 2*n if n < 10 else 1, valuation=0); M O(z^7) sage: bool(M) Traceback (most recent call last): ... - ValueError: undecidable as lazy Laurent series + ValueError: undecidable sage: M[15] 1 sage: bool(M) True + sage: L.options._reset() Uninitialized series:: + sage: # needs sage.rings.finite_rings sage: g = L.undefined(valuation=0) sage: bool(g) True @@ -919,6 +1102,7 @@ def __bool__(self): sage: bool(g) False + sage: # needs sage.rings.finite_rings sage: g = L.undefined(valuation=0) sage: bool(g) True @@ -926,41 +1110,161 @@ def __bool__(self): sage: bool(g) True + sage: # needs sage.rings.finite_rings sage: g = L.undefined(valuation=0) sage: bool(g) True sage: g.define(1 + z*g) sage: bool(g) True + + Comparison with finite halting precision:: + + sage: # needs sage.rings.finite_rings + sage: M = L(lambda n: 2*n if n < 10 else 0, valuation=0) + sage: bool(M) + True + sage: M.is_zero() + False + + sage: # needs sage.rings.finite_rings + sage: L.options.halting_precision = 20 + sage: bool(M) + False + sage: M.is_zero() + True + + With finite halting precision, it can be considered to + be indistinguishable from zero until possibly enough + coefficients are computed:: + + sage: # needs sage.rings.finite_rings + sage: L.<z> = LazyLaurentSeriesRing(GF(2)) + sage: L.options.halting_precision = 20 + sage: f = L(lambda n: 0, valuation=0) + sage: f.is_zero() + True + + sage: # needs sage.rings.finite_rings + sage: g = L(lambda n: 0 if n < 50 else 1, valuation=2) + sage: bool(g) # checks up to degree 22 = 2 + 20 + False + sage: bool(g) # checks up to degree 42 = 22 + 20 + False + sage: bool(g) # checks up to degree 62 = 42 + 20 + True + sage: L.options._reset() """ if isinstance(self._coeff_stream, Stream_zero): return False - if isinstance(self._coeff_stream, Stream_exact): + + prec = self.parent().options['halting_precision'] + if prec is None and not self.parent().options['secure']: return True - if isinstance(self._coeff_stream, Stream_uninitialized): - if self._coeff_stream._target is None: - return True - if isinstance(self._coeff_stream._target, Stream_zero): - return False - if isinstance(self._coeff_stream._target, Stream_exact): - return True - if self._coeff_stream._is_sparse: - cache = self._coeff_stream._cache - if any(cache[a] for a in cache): - return True - else: - if any(a for a in self._coeff_stream._cache): - return True - v = self._coeff_stream._approximate_order - if self[v]: + if isinstance(self._coeff_stream, Stream_exact): + return True + if self._coeff_stream.is_uninitialized(): + return True + if self._coeff_stream.is_nonzero(): return True - prec = self.parent().options['halting_precision'] if prec is None: - raise ValueError("undecidable as lazy Laurent series") + raise ValueError("undecidable") + v = self._coeff_stream._approximate_order return any(self[i] for i in range(v, v + prec)) + def is_nonzero(self, proof=False): + r""" + Return ``True`` if ``self`` is *known* to be nonzero. + + INPUT: + + - ``proof`` -- (default: ``False``) if ``True``, this will also return + an index such that ``self`` has a nonzero coefficient + + .. WARNING:: + + If the stream is exactly zero, this will run forever. + + EXAMPLES: + + A series that it not known to be nonzero with no halting precision:: + + sage: L.<z> = LazyLaurentSeriesRing(GF(2)) + sage: f = L(lambda n: 0, valuation=0) + sage: f.is_nonzero() + False + sage: bool(f) + True + sage: g = L(lambda n: 0 if n < 50 else 1, valuation=2) + sage: g.is_nonzero() + False + sage: g[60] + 1 + sage: g.is_nonzero() + True + + With finite halting precision, it can be considered to + be indistinguishable from zero until possibly enough + coefficients are computed:: + + sage: L.options.halting_precision = 20 + sage: f = L(lambda n: 0, valuation=0) + sage: f.is_zero() + True + + sage: g = L(lambda n: 0 if n < 50 else 1, valuation=2) + sage: g.is_nonzero() # checks up to degree 22 = 2 + 20 + False + sage: g.is_nonzero() # checks up to degree 42 = 22 + 20 + False + sage: g.is_nonzero() # checks up to degree 62 = 42 + 20 + True + sage: L.options._reset() + + With a proof:: + + sage: L.<z> = LazyLaurentSeriesRing(GF(5)) + sage: g = L(lambda n: 5 if n < 50 else 1, valuation=2) + sage: g.is_nonzero(proof=True) + (True, 50) + + sage: L.zero().is_nonzero(proof=True) + (False, None) + """ + if proof: + if isinstance(self._coeff_stream, Stream_zero): + return (False, None) + + i = self._coeff_stream._approximate_order + while True: + if self[i]: + return (True, i) + i += 1 + + if self._coeff_stream.is_nonzero(): + return True + if self.parent().options['halting_precision'] is not None: + return bool(self) + return False + + def is_trivial_zero(self): + r""" + Return whether ``self`` is known to be trivially zero. + + EXAMPLES:: + + sage: L.<z> = LazyLaurentSeriesRing(ZZ) + sage: f = L(lambda n: 0, valuation=2) + sage: f.is_trivial_zero() + False + + sage: L.zero().is_trivial_zero() + True + """ + return isinstance(self._coeff_stream, Stream_zero) + def define(self, s): r""" Define an equation by ``self = s``. @@ -978,10 +1282,10 @@ def define(self, s): sage: C.define(1 + z*C^2) sage: C 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + O(z^7) - sage: binomial(2000, 1000) / C[1000] + sage: binomial(2000, 1000) / C[1000] # needs sage.symbolic 1001 - The Catalan numbers but with a valuation 1:: + The Catalan numbers but with a valuation `1`:: sage: B = L.undefined(valuation=1) sage: B.define(z + B^2) @@ -1057,7 +1361,7 @@ def define(self, s): sage: F.define(1 + g*F) sage: F[:16] [1, 1, 1, 2, 1, 3, 1, 4, 2, 3, 1, 8, 1, 3, 3] - sage: oeis(_) # optional, internet + sage: oeis(_) # optional - internet 0: A002033: Number of perfect partitions of n. 1: A074206: Kalmรกr's [Kalmar's] problem: number of ordered factorizations of n. ... @@ -1069,13 +1373,14 @@ def define(self, s): We can compute the Frobenius character of unlabeled trees:: + sage: # needs sage.combinat sage: m = SymmetricFunctions(QQ).m() sage: s = SymmetricFunctions(QQ).s() sage: L = LazySymmetricFunctions(m) sage: E = L(lambda n: s[n], valuation=0) sage: X = L(s[1]) sage: A = L.undefined() - sage: A.define(X*E(A, check=False)) + sage: A.define(X*E(A)) sage: A[:6] [m[1], 2*m[1, 1] + m[2], @@ -1118,7 +1423,7 @@ def define(self, s): sage: g = D.undefined(valuation=2) sage: o = D(constant=1, valuation=2) sage: g.define(o * e(g)) - sage: g + sage: g # needs sage.symbolic 1/(2^s) + 1/(3^s) + 2/4^s + 1/(5^s) + 3/6^s + 1/(7^s) + 9/2/8^s + O(1/(9^s)) For Laurent series there is no minimal valuation, so it has @@ -1143,10 +1448,10 @@ def define(self, s): sage: g = D([0, 1]) sage: f = D.undefined() sage: f.define(1 + ~f*g) - sage: f + sage: f # needs sage.symbolic 1 + 1/(2^s) - 1/(4^s) + O(1/(8^s)) - sage: oeis(f[:30]) # optional, internet + sage: oeis(f[:30]) # optional - internet 0: A122698: a(1)=a(2)=1 then a(n) = Sum_{d|n, 1<d<n} a(d)*a(n/d). Note that we cannot use division in the examples above. @@ -1178,7 +1483,7 @@ def define(self, s): sage: f.define(1+(t*~f).revert()) sage: f 1 + t + t^2 + 2*t^3 + 6*t^4 + 23*t^5 + 104*t^6 + O(t^7) - sage: oeis(f[1:20]) # optional, internet + sage: oeis(f[1:20]) # optional - internet 0: A030266: Shifts left under COMPOSE transform with itself. 1: A110447: Permutations containing 3241 patterns only as part of 35241 patterns. @@ -1191,11 +1496,12 @@ def define(self, s): sage: f 1 + 2*t + 12*t^3 + 32*t^4 + 368*t^5 + 2192*t^6 + O(t^7) + sage: # needs sage.combinat sage: s = SymmetricFunctions(QQ).s() sage: L = LazySymmetricFunctions(s) sage: f = L.undefined() sage: f.define(1+(s[1]*f).revert()) - sage: f + sage: f # needs lrcalc_python s[] + s[1] + (-s[1,1]-s[2]) + (3*s[1,1,1]+6*s[2,1]+3*s[3]) + (-13*s[1,1,1,1]-39*s[2,1,1]-26*s[2,2]-39*s[3,1]-13*s[4]) @@ -1203,9 +1509,27 @@ def define(self, s): + (-419*s[1,1,1,1,1,1]-2095*s[2,1,1,1,1]-3771*s[2,2,1,1]-2095*s[2,2,2]-4190*s[3,1,1,1]-6704*s[3,2,1]-2095*s[3,3]-4190*s[4,1,1]-3771*s[4,2]-2095*s[5,1]-419*s[6]) + O^7 - sage: (f*s[1]).revert() + 1 - f + sage: (f*s[1]).revert() + 1 - f # needs lrcalc_python sage.combinat O^7 + Undefined series inside of another series (see :issue:`35071`):: + + sage: L.<z> = LazyPowerSeriesRing(QQ) + sage: f = z^2 + sage: b = L.undefined(valuation=1) + sage: b.define(z*f(f(b))) + sage: b + O(z^8) + + sage: L.<x> = LazyPowerSeriesRing(ZZ) + sage: f = L.undefined() + sage: f.define(L(lambda n: 0 if not n else sigma(f[n-1]+1))) + sage: f + x + 3*x^2 + 7*x^3 + 15*x^4 + 31*x^5 + 63*x^6 + O(x^7) + sage: f = L.undefined() + sage: f.define((1/(1-L(lambda n: 0 if not n else sigma(f[n-1]+1))))) + sage: f + 1 + 3*x + 16*x^2 + 87*x^3 + 607*x^4 + 4518*x^5 + 30549*x^6 + O(x^7) """ if not isinstance(self._coeff_stream, Stream_uninitialized) or self._coeff_stream._target is not None: raise ValueError("series already defined") @@ -1252,8 +1576,10 @@ def _repr_(self): sage: L(lambda x: x if x > 0 else 0, valuation=-10) O(z^-3) - sage: L.undefined(valuation=0) - Uninitialized Lazy Laurent Series + sage: s = L.undefined(valuation=0); s + Uninitialized Lazy Series + sage: (s + s^2).map_coefficients(lambda f: f % 3) + Uninitialized Lazy Series sage: L(0) 0 @@ -1266,8 +1592,8 @@ def _repr_(self): """ if isinstance(self._coeff_stream, Stream_zero): return '0' - if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: - return 'Uninitialized Lazy Laurent Series' + if self._coeff_stream.is_uninitialized(): + return 'Uninitialized Lazy Series' return self._format_series(repr) def _latex_(self): @@ -1299,7 +1625,10 @@ def _latex_(self): sage: latex(L(lambda x: x if x > 0 else 0, valuation=-10)) O(\frac{1}{z^{3}}) - sage: latex(L.undefined(valuation=0)) + sage: s = L.undefined(valuation=0) + sage: latex(s) + \text{\texttt{Undef}} + sage: latex((s + s^2).map_coefficients(lambda f: f % 3)) \text{\texttt{Undef}} sage: latex(L(0)) 0 @@ -1316,7 +1645,7 @@ def _latex_(self): from sage.misc.latex import latex if isinstance(self._coeff_stream, Stream_zero): return latex('0') - if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: + if self._coeff_stream.is_uninitialized(): return latex("Undef") return self._format_series(latex) @@ -1326,18 +1655,22 @@ def _ascii_art_(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: e = SymmetricFunctions(QQ).e() sage: L.<z> = LazyLaurentSeriesRing(e) sage: L.options.display_length = 3 sage: ascii_art(1 / (1 - e[1]*z)) e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) + sage: x = L.undefined(valuation=0) + sage: ascii_art(x + x^2 - 5) + Uninitialized Lazy Series sage: L.options._reset() """ from sage.typeset.ascii_art import ascii_art, AsciiArt if isinstance(self._coeff_stream, Stream_zero): return AsciiArt('0') - if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: - return AsciiArt('Uninitialized Lazy Laurent Series') + if self._coeff_stream.is_uninitialized(): + return AsciiArt(['Uninitialized Lazy Series']) return self._format_series(ascii_art, True) def _unicode_art_(self): @@ -1346,18 +1679,22 @@ def _unicode_art_(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: e = SymmetricFunctions(QQ).e() sage: L.<z> = LazyLaurentSeriesRing(e) sage: L.options.display_length = 3 sage: unicode_art(1 / (1 - e[1]*z)) e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) + sage: x = L.undefined(valuation=0) + sage: unicode_art(x + x^2 - 5) + Uninitialized Lazy Series sage: L.options._reset() """ from sage.typeset.unicode_art import unicode_art, UnicodeArt if isinstance(self._coeff_stream, Stream_zero): return UnicodeArt('0') - if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: - return UnicodeArt('Uninitialized Lazy Laurent Series') + if self._coeff_stream.is_uninitialized(): + return UnicodeArt(['Uninitialized Lazy Series']) return self._format_series(unicode_art, True) def change_ring(self, ring): @@ -1405,7 +1742,8 @@ def change_ring(self, ring): sage: t = s.change_ring(QQ) sage: t.parent() Lazy Dirichlet Series Ring in z over Rational Field - sage: t^-1 + sage: it = t^-1 + sage: it # needs sage.symbolic 1/2 - 1/2/2^z - 1/2/3^z - 1/2/5^z + 1/2/6^z - 1/2/7^z + O(1/(8^z)) A Taylor series example:: @@ -1471,24 +1809,28 @@ def _add_(self, other): Similarly for Dirichlet series:: + sage: # needs sage.symbolic sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: s = L(lambda n: n); s + sage: s = L(lambda n: n) + sage: s 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) - sage: t = L(constant=1); t + sage: t = L(constant=1) + sage: t 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) - sage: s + t + sage: st = s + t + sage: st 2 + 3/2^z + 4/3^z + 5/4^z + 6/5^z + 7/6^z + 8/7^z + O(1/(8^z)) - sage: r = L(constant=-1) - sage: r + t + sage: rt = r + t + sage: rt 0 - sage: r = L([1,2,3]) - sage: r + t + sage: rt = r + t + sage: rt 2 + 3/2^z + 4/3^z + 1/(4^z) + 1/(5^z) + 1/(6^z) + O(1/(7^z)) - sage: r = L([1,2,3], constant=-1) - sage: r + t + sage: rt = r + t + sage: rt 2 + 3/2^z + 4/3^z """ P = self.parent() @@ -1632,11 +1974,21 @@ def _acted_upon_(self, scalar, self_on_left): Different scalars potentially give different series:: + sage: 2 * M == 3 * M + False + + sage: L.options.secure = True sage: 2 * M == 3 * M Traceback (most recent call last): ... ValueError: undecidable + sage: L.options.halting_precision = 30 + sage: 2 * M == 3 * M + False + + sage: L.options._reset() + Sparse series can be multiplied with a scalar:: sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=True) @@ -1681,6 +2033,7 @@ def _acted_upon_(self, scalar, self_on_left): Similarly for Dirichlet series:: + sage: # needs sage.symbolic sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: g = L([0,1]) sage: 2 * g @@ -1689,14 +2042,35 @@ def _acted_upon_(self, scalar, self_on_left): -1/(2^z) sage: 0*g 0 - sage: M = L(lambda n: n); M + sage: M = L(lambda n: n) + sage: M 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) sage: 3 * M 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + O(1/(8^z)) - sage: 1 * M is M True + TESTS: + + Check that :issue:`36154` is fixed:: + + sage: L.<z> = LazyPowerSeriesRing(Zmod(4)) + sage: f = L(constant=2) + sage: 2*f + 0 + + Check that non-commutativity is taken into account:: + + sage: M = MatrixSpace(ZZ, 2) + sage: L.<z> = LazyPowerSeriesRing(M) + sage: f = L(lambda n: matrix([[1,n],[0,1]])) + sage: m = matrix([[1,0],[1,1]]) + sage: (m * f - f * m)[1] + [-1 0] + [ 0 1] + sage: m * f[1] - f[1] * m + [-1 0] + [ 0 1] """ # With the current design, the coercion model does not have # enough information to detect a priori that this method only @@ -1731,11 +2105,13 @@ def _acted_upon_(self, scalar, self_on_left): else: c = scalar * coeff_stream._constant initial_coefficients = [scalar * val for val in init_coeffs] + if not any(initial_coefficients) and not c: + return P.zero() return P.element_class(P, Stream_exact(initial_coefficients, order=v, constant=c, degree=coeff_stream._degree)) - if self_on_left or R.is_commutative(): + if self_on_left or R in Rings().Commutative(): return P.element_class(P, Stream_lmul(coeff_stream, scalar, P.is_sparse())) return P.element_class(P, Stream_rmul(coeff_stream, scalar, @@ -1814,7 +2190,7 @@ def exp(self): sage: L = LazyDirichletSeriesRing(QQ, "s") sage: Z = L(constant=1, valuation=2) - sage: exp(Z) + sage: exp(Z) # needs sage.symbolic 1 + 1/(2^s) + 1/(3^s) + 3/2/4^s + 1/(5^s) + 2/6^s + 1/(7^s) + O(1/(8^s)) """ from .lazy_series_ring import LazyLaurentSeriesRing @@ -1830,7 +2206,7 @@ def log(self): sage: L = LazyDirichletSeriesRing(QQ, "s") sage: Z = L(constant=1) - sage: log(Z) + sage: log(Z) # needs sage.symbolic 1/(2^s) + 1/(3^s) + 1/2/4^s + 1/(5^s) + 1/(7^s) + O(1/(8^s)) """ from .lazy_series_ring import LazyLaurentSeriesRing @@ -1861,7 +2237,7 @@ def sin(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") + sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") # needs sage.symbolic sage: sin(z)[0:6] == sin(x).series(x, 6).coefficients(sparse=False) True """ @@ -1887,8 +2263,8 @@ def cos(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") - sage: cos(z)[0:6] == cos(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") # needs sage.symbolic + sage: cos(z)[0:6] == cos(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ from .lazy_series_ring import LazyLaurentSeriesRing @@ -1913,8 +2289,8 @@ def tan(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") - sage: tan(z)[0:6] == tan(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") # needs sage.symbolic + sage: tan(z)[0:6] == tan(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ return self.sin() / self.cos() @@ -1935,8 +2311,8 @@ def cot(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") - sage: cot(z)[0:6] == cot(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") # needs sage.symbolic + sage: cot(z)[0:6] == cot(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ return ~self.tan() @@ -1957,8 +2333,8 @@ def csc(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") - sage: (z*csc(z))[0:6] == (x*csc(x)).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") # needs sage.symbolic + sage: (z*csc(z))[0:6] == (x*csc(x)).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ return ~self.sin() @@ -1979,8 +2355,8 @@ def sec(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") - sage: sec(z)[0:6] == sec(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") # needs sage.symbolic + sage: sec(z)[0:6] == sec(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ return ~self.cos() @@ -1989,7 +2365,7 @@ def sec(self): def arcsin(self): r""" - Return the arcsin of ``self``. + Return the arcsine of ``self``. EXAMPLES:: @@ -2005,8 +2381,8 @@ def arcsin(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") - sage: asin(z)[0:6] == asin(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") # needs sage.symbolic + sage: asin(z)[0:6] == asin(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ from .lazy_series_ring import LazyLaurentSeriesRing @@ -2021,29 +2397,29 @@ def f(n): def arccos(self): r""" - Return the arccos of ``self``. + Return the arccosine of ``self``. EXAMPLES:: sage: L.<z> = LazyLaurentSeriesRing(RR) - sage: arccos(z) + sage: arccos(z) # needs sage.symbolic 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 - 0.166666666666667*z^3 + 0.000000000000000*z^4 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) - sage: L.<z> = LazyLaurentSeriesRing(SR) - sage: arccos(z/(1-z)) + sage: L.<z> = LazyLaurentSeriesRing(SR) # needs sage.symbolic + sage: arccos(z/(1-z)) # needs sage.symbolic 1/2*pi - z - z^2 - 7/6*z^3 - 3/2*z^4 - 83/40*z^5 - 73/24*z^6 + O(z^7) - sage: L.<x,y> = LazyPowerSeriesRing(SR) - sage: arccos(x/(1-y)) + sage: L.<x,y> = LazyPowerSeriesRing(SR) # needs sage.symbolic + sage: arccos(x/(1-y)) # needs sage.symbolic 1/2*pi + (-x) + (-x*y) + ((-1/6)*x^3-x*y^2) + ((-1/2)*x^3*y-x*y^3) + ((-3/40)*x^5-x^3*y^2-x*y^4) + ((-3/8)*x^5*y+(-5/3)*x^3*y^3-x*y^5) + O(x,y)^7 TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") - sage: acos(z)[0:6] == acos(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") # needs sage.symbolic + sage: acos(z)[0:6] == acos(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ from sage.symbolic.constants import pi @@ -2066,8 +2442,8 @@ def arctan(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") - sage: atan(z)[0:6] == atan(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") # needs sage.symbolic + sage: atan(z)[0:6] == atan(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ from .lazy_series_ring import LazyLaurentSeriesRing @@ -2089,24 +2465,24 @@ def arccot(self): EXAMPLES:: sage: L.<z> = LazyLaurentSeriesRing(RR) - sage: arccot(z) + sage: arccot(z) # needs sage.symbolic 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 + 0.333333333333333*z^3 + 0.000000000000000*z^4 - 0.200000000000000*z^5 + O(1.00000000000000*z^7) - sage: L.<z> = LazyLaurentSeriesRing(SR) - sage: arccot(z/(1-z)) + sage: L.<z> = LazyLaurentSeriesRing(SR) # needs sage.symbolic + sage: arccot(z/(1-z)) # needs sage.symbolic 1/2*pi - z - z^2 - 2/3*z^3 + 4/5*z^5 + 4/3*z^6 + O(z^7) - sage: L.<x,y> = LazyPowerSeriesRing(SR) - sage: acot(x/(1-y)) + sage: L.<x,y> = LazyPowerSeriesRing(SR) # needs sage.symbolic + sage: acot(x/(1-y)) # needs sage.symbolic 1/2*pi + (-x) + (-x*y) + (1/3*x^3-x*y^2) + (x^3*y-x*y^3) + ((-1/5)*x^5+2*x^3*y^2-x*y^4) + (-x^5*y+10/3*x^3*y^3-x*y^5) + O(x,y)^7 TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") - sage: acot(z)[0:6] == acot(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") # needs sage.symbolic + sage: acot(z)[0:6] == acot(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ from sage.symbolic.constants import pi @@ -2116,7 +2492,7 @@ def arccot(self): def sinh(self): r""" - Return the sinh of ``self``. + Return the hyperbolic sine of ``self``. EXAMPLES:: @@ -2132,8 +2508,8 @@ def sinh(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") - sage: sinh(z)[0:6] == sinh(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") # needs sage.symbolic + sage: sinh(z)[0:6] == sinh(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ from .lazy_series_ring import LazyLaurentSeriesRing @@ -2144,7 +2520,7 @@ def sinh(self): def cosh(self): r""" - Return the cosh of ``self``. + Return the hyperbolic cosine of ``self``. EXAMPLES:: @@ -2159,8 +2535,8 @@ def cosh(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") - sage: cosh(z)[0:6] == cosh(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") # needs sage.symbolic + sage: cosh(z)[0:6] == cosh(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ from .lazy_series_ring import LazyLaurentSeriesRing @@ -2171,23 +2547,23 @@ def cosh(self): def tanh(self): r""" - Return the tanh of ``self``. + Return the hyperbolic tangent of ``self``. EXAMPLES:: sage: L.<z> = LazyLaurentSeriesRing(QQ) - sage: tanh(z) + sage: tanh(z) # needs sage.libs.flint z - 1/3*z^3 + 2/15*z^5 - 17/315*z^7 + O(z^8) sage: L.<x,y> = LazyPowerSeriesRing(QQ) - sage: tanh(x/(1-y)) + sage: tanh(x/(1-y)) # needs sage.libs.flint x + x*y + (-1/3*x^3+x*y^2) + (-x^3*y+x*y^3) + (2/15*x^5-2*x^3*y^2+x*y^4) + (2/3*x^5*y-10/3*x^3*y^3+x*y^5) + (-17/315*x^7+2*x^5*y^2-5*x^3*y^4+x*y^6) + O(x,y)^8 TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") - sage: tanh(z)[0:6] == tanh(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") # needs sage.symbolic + sage: tanh(z)[0:6] == tanh(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ from sage.arith.misc import bernoulli @@ -2209,16 +2585,16 @@ def coth(self): EXAMPLES:: sage: L.<z> = LazyLaurentSeriesRing(QQ) - sage: coth(z) + sage: coth(z) # needs sage.libs.flint z^-1 + 1/3*z - 1/45*z^3 + 2/945*z^5 + O(z^6) - sage: coth(z + z^2) + sage: coth(z + z^2) # needs sage.libs.flint z^-1 - 1 + 4/3*z - 2/3*z^2 + 44/45*z^3 - 16/15*z^4 + 884/945*z^5 + O(z^6) TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") - sage: coth(z)[0:6] == coth(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") # needs sage.symbolic + sage: coth(z)[0:6] == coth(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ from sage.arith.misc import bernoulli @@ -2239,18 +2615,18 @@ def sech(self): EXAMPLES:: sage: L.<z> = LazyLaurentSeriesRing(QQ) - sage: sech(z) + sage: sech(z) # needs sage.libs.flint 1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7) sage: L.<x, y> = LazyPowerSeriesRing(QQ) - sage: sech(x/(1-y)) + sage: sech(x/(1-y)) # needs sage.libs.flint 1 + (-1/2*x^2) + (-x^2*y) + (5/24*x^4-3/2*x^2*y^2) + (5/6*x^4*y-2*x^2*y^3) + (-61/720*x^6+25/12*x^4*y^2-5/2*x^2*y^4) + O(x,y)^7 TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") - sage: sech(z)[0:6] == sech(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") # needs sage.symbolic + sage: sech(z)[0:6] == sech(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ from sage.combinat.combinat import euler_number @@ -2271,17 +2647,17 @@ def csch(self): EXAMPLES:: sage: L.<z> = LazyLaurentSeriesRing(QQ) - sage: csch(z) + sage: csch(z) # needs sage.libs.flint z^-1 - 1/6*z + 7/360*z^3 - 31/15120*z^5 + O(z^6) sage: L.<z> = LazyLaurentSeriesRing(QQ) - sage: csch(z/(1-z)) + sage: csch(z/(1-z)) # needs sage.libs.flint z^-1 - 1 - 1/6*z - 1/6*z^2 - 53/360*z^3 - 13/120*z^4 - 787/15120*z^5 + O(z^6) TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") - sage: csch(z)[0:6] == csch(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") # needs sage.symbolic + sage: csch(z)[0:6] == csch(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ from sage.arith.misc import bernoulli @@ -2319,8 +2695,8 @@ def arcsinh(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") - sage: asinh(z)[0:6] == asinh(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") # needs sage.symbolic + sage: asinh(z)[0:6] == asinh(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ @@ -2357,8 +2733,8 @@ def arctanh(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") - sage: atanh(z)[0:6] == atanh(x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") # needs sage.symbolic + sage: atanh(z)[0:6] == atanh(x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ @@ -2392,8 +2768,8 @@ def hypergeometric(self, a, b): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") - sage: z.hypergeometric([1,1],[1])[0:6] == hypergeometric([1,1],[1], x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(SR); x = var("x") # needs sage.symbolic + sage: z.hypergeometric([1,1],[1])[0:6] == hypergeometric([1,1],[1], x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True """ @@ -2481,6 +2857,7 @@ def __pow__(self, n): EXAMPLES:: + sage: # needs sage.symbolic sage: D = LazyDirichletSeriesRing(QQ, 's') sage: Z = D(constant=1) sage: Z^2 @@ -2544,10 +2921,10 @@ def sqrt(self): This also works for Dirichlet series:: + sage: # needs sage.symbolic sage: D = LazyDirichletSeriesRing(SR, "s") sage: Z = D(constant=1) - sage: f = sqrt(Z) - sage: f + sage: f = sqrt(Z); f 1 + 1/2/2^s + 1/2/3^s + 3/8/4^s + 1/2/5^s + 1/4/6^s + 1/2/7^s + O(1/(8^s)) sage: f*f - Z O(1/(8^s)) @@ -2620,7 +2997,7 @@ def _mul_(self, other): z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: N = M * (1 - M) sage: N - z + z^2 - z^3 - 6*z^4 - 15*z^5 - 29*z^6 + O(z^7) + z + z^2 - z^3 - 6*z^4 - 15*z^5 - 29*z^6 - 49*z^7 + O(z^8) sage: p = (1 - z)*(1 + z^2)^3 * z^-2 sage: p @@ -2648,7 +3025,7 @@ def _mul_(self, other): sage: N = L(lambda n: 1, valuation=0); N 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) sage: M * N - z + 3*z^2 + 6*z^3 + 10*z^4 + 15*z^5 + 21*z^6 + O(z^7) + z + 3*z^2 + 6*z^3 + 10*z^4 + 15*z^5 + 21*z^6 + 28*z^7 + O(z^8) sage: L.one() * M is M True @@ -2658,6 +3035,7 @@ def _mul_(self, other): Multiplication of series with eventually constant coefficients may yield another such series:: + sage: # needs sage.symbolic sage: L.<z> = LazyLaurentSeriesRing(SR) sage: var("a b c d e u v w") (a, b, c, d, e, u, v, w) @@ -2675,6 +3053,14 @@ def _mul_(self, other): sage: (1+z) * L([1,0,1], constant=1) 1 + z + z^2 + 2*z^3 + 2*z^4 + 2*z^5 + O(z^6) + + Check that :issue:`36154` is fixed:: + + sage: L.<z> = LazyLaurentSeriesRing(Zmod(4)) + sage: f = L(constant=2, valuation=0) + sage: g = L([2]) + sage: f * g + 0 """ P = self.parent() left = self._coeff_stream @@ -2693,6 +3079,9 @@ def _mul_(self, other): and right.order() == 0 and not right._constant): return self # right == 1 + if ((isinstance(left, Stream_cauchy_invert) and left._series == right) + or (isinstance(right, Stream_cauchy_invert) and right._series == left)): + return P.one() # The product is exact if and only if both factors are exact # and one of the factors has eventually 0 coefficients: # (p + a x^d/(1-x))(q + b x^e/(1-x)) @@ -2733,12 +3122,18 @@ def _mul_(self, other): c += left._constant * ir[-1] else: c = left._constant # this is zero + if not any(initial_coefficients) and not c: + return P.zero() coeff_stream = Stream_exact(initial_coefficients, order=lv + rv, constant=c) return P.element_class(P, coeff_stream) - return P.element_class(P, Stream_cauchy_mul(left, right, P.is_sparse())) + if P in Rings().Commutative(): + coeff_stream = Stream_cauchy_mul_commutative(left, right, P.is_sparse()) + else: + coeff_stream = Stream_cauchy_mul(left, right, P.is_sparse()) + return P.element_class(P, coeff_stream) def __pow__(self, n): r""" @@ -2765,7 +3160,7 @@ def __pow__(self, n): sage: M = L(lambda n: n, valuation=0); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: M^2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + 56*z^7 + 84*z^8 + O(z^9) We can create a really large power of a monomial, even with the dense implementation:: @@ -2780,7 +3175,7 @@ def __pow__(self, n): sage: M = L(lambda n: n, valuation=0); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: M^2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + 56*z^7 + 84*z^8 + O(z^9) Lazy Laurent series that are known to be exact can be raised to the power ``n``:: @@ -2794,10 +3189,18 @@ def __pow__(self, n): We also support the general case:: - sage: L.<z> = LazyLaurentSeriesRing(SR) - sage: (1 + z)^(1 + z) + sage: L.<z> = LazyLaurentSeriesRing(SR) # needs sage.symbolic + sage: (1 + z)^(1 + z) # needs sage.symbolic 1 + z + z^2 + 1/2*z^3 + 1/3*z^4 + 1/12*z^5 + 3/40*z^6 + O(z^7) + TESTS: + + Check that :issue:`36154` is fixed:: + + sage: L.<z> = LazyLaurentSeriesRing(Zmod(4)) + sage: f = L([2]) + sage: f^2 + 0 """ if n == 0: return self.parent().one() @@ -2810,6 +3213,8 @@ def __pow__(self, n): # return P(self.finite_part() ** ZZ(n)) P = self.parent() ret = cs._polynomial_part(P._internal_poly_ring) ** ZZ(n) + if not ret: + return P.zero() val = ret.valuation() deg = ret.degree() + 1 initial_coefficients = [ret[i] for i in range(val, deg)] @@ -2817,7 +3222,6 @@ def __pow__(self, n): constant=cs._constant, degree=deg, order=val)) - return super().__pow__(n) def __invert__(self): @@ -2855,6 +3259,7 @@ def __invert__(self): We can also compute the multiplicative inverse of a symmetric function:: + sage: # needs sage.modules sage: h = SymmetricFunctions(QQ).h() sage: p = SymmetricFunctions(QQ).p() sage: L = LazySymmetricFunctions(p) @@ -2862,7 +3267,7 @@ def __invert__(self): sage: (~E)[:4] [p[], -p[1], 1/2*p[1, 1] - 1/2*p[2], -1/6*p[1, 1, 1] + 1/2*p[2, 1] - 1/3*p[3]] - sage: (E * ~E)[:6] + sage: (E * ~E)[:6] # needs sage.modules [p[], 0, 0, 0, 0, 0] TESTS:: @@ -2871,17 +3276,27 @@ def __invert__(self): sage: g = L([2], valuation=-1, constant=1); g 2*x^-1 + 1 + x + x^2 + O(x^3) sage: g * g^-1 - 1 + O(x^7) + 1 sage: L.<x> = LazyPowerSeriesRing(QQ) sage: ~(x + x^2) Traceback (most recent call last): ... ZeroDivisionError: cannot divide by a series of positive valuation + + Check that :issue:`36253` is fixed:: + + sage: f = L(lambda n: n) + sage: ~f + Traceback (most recent call last): + ... + ZeroDivisionError: cannot divide by a series of positive valuation """ P = self.parent() coeff_stream = self._coeff_stream - if P._minimal_valuation is not None and coeff_stream._approximate_order > 0: + if (P._minimal_valuation is not None + and (coeff_stream._approximate_order > 0 + or not coeff_stream.is_uninitialized() and not coeff_stream[0])): raise ZeroDivisionError("cannot divide by a series of positive valuation") # the inverse is exact if and only if coeff_stream corresponds to one of @@ -2947,7 +3362,7 @@ def _div_(self, other): sage: N = L(lambda n: 1, 0); N 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) sage: P = M / N; P - z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + O(z^8) Lazy Laurent series that have a sparse implementation can be divided:: @@ -2957,7 +3372,7 @@ def _div_(self, other): sage: N = L(lambda n: 1, 0); N 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) sage: P = M / N; P - z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + O(z^8) If the division of exact Lazy Laurent series yields a Laurent polynomial, it is represented as an exact series:: @@ -2973,9 +3388,9 @@ def _div_(self, other): An example over the ring of symmetric functions:: - sage: e = SymmetricFunctions(QQ).e() - sage: R.<z> = LazyLaurentSeriesRing(e) - sage: 1 / (1 - e[1]*z) + sage: e = SymmetricFunctions(QQ).e() # needs sage.modules + sage: R.<z> = LazyLaurentSeriesRing(e) # needs sage.modules + sage: 1 / (1 - e[1]*z) # needs sage.modules e[] + e[1]*z + e[1, 1]*z^2 + e[1, 1, 1]*z^3 + e[1, 1, 1, 1]*z^4 + e[1, 1, 1, 1, 1]*z^5 + e[1, 1, 1, 1, 1, 1]*z^6 + O(e[]*z^7) @@ -2985,7 +3400,7 @@ def _div_(self, other): sage: 1 / (1 - y) 1 + y + y^2 + y^3 + y^4 + y^5 + y^6 + O(x,y)^7 - sage: (x + y) / (1 - y) + sage: (x + y) / (1 - y) # needs sage.libs.singular (x+y) + (x*y+y^2) + (x*y^2+y^3) + (x*y^3+y^4) + (x*y^4+y^5) + (x*y^5+y^6) + (x*y^6+y^7) + O(x,y)^8 TESTS:: @@ -3015,8 +3430,31 @@ def _div_(self, other): sage: f / f s[] + Dividing when the coefficient ring is a lazy Dirichlet ring:: + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: zeta = D(constant=1) + sage: L.<t> = LazyLaurentSeriesRing(D) + sage: 1 / (1 - t*zeta) + (1 + O(1/(8^s))) + + (1 + 1/(2^s) + 1/(3^s) + 1/(4^s) + 1/(5^s) + 1/(6^s) + 1/(7^s) + O(1/(8^s)))*t + + ... + O(t^7) + + Check for dividing by other type of `0` series:: + + sage: L.<t> = LazyPowerSeriesRing(QQ) + sage: f = L(lambda n: 0, valuation=0) + sage: L.options.halting_precision = 20 + sage: 1 / f + Traceback (most recent call last): + ... + ZeroDivisionError: cannot divide by 0 + sage: L.options._reset() """ - if isinstance(other._coeff_stream, Stream_zero): + # currently __invert__ and _div_ behave differently with + # respect to division by lazy power series of positive + # valuation, so we cannot call ~other if self.is_one() + if not other: raise ZeroDivisionError("cannot divide by 0") P = self.parent() @@ -3034,7 +3472,7 @@ def _div_(self, other): return self # self is right - if left is right: + if left == right: return P.one() if (P._minimal_valuation is not None @@ -3109,8 +3547,11 @@ def _div_(self, other): # P._minimal_valuation is zero, because we allow division by # series of positive valuation right_inverse = Stream_cauchy_invert(right) - return P.element_class(P, Stream_cauchy_mul(left, right_inverse, P.is_sparse())) - + if P in Rings().Commutative(): + coeff_stream = Stream_cauchy_mul_commutative(left, right_inverse, P.is_sparse()) + else: + coeff_stream = Stream_cauchy_mul(left, right_inverse, P.is_sparse()) + return P.element_class(P, coeff_stream) def _floordiv_(self, other): r""" @@ -3162,7 +3603,7 @@ def exp(self): 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) sage: exp(z + z^2) 1 + z + 3/2*z^2 + 7/6*z^3 + 25/24*z^4 + 27/40*z^5 + 331/720*z^6 + O(z^7) - sage: exp(0) + sage: exp(0) # needs sage.symbolic 1 sage: exp(1 + z) Traceback (most recent call last): @@ -3177,7 +3618,7 @@ def exp(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") + sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") # needs sage.symbolic sage: exp(z)[0:6] == exp(x).series(x, 6).coefficients(sparse=False) True @@ -3191,9 +3632,10 @@ def exp(self): P = self.parent() R = self.base_ring() coeff_stream = self._coeff_stream - # TODO: coefficients should not be checked here, it prevents + # coefficients must not be checked here, it prevents # us from using self.define in some cases! - if any(coeff_stream[i] for i in range(coeff_stream._approximate_order, 1)): + if ((not coeff_stream.is_uninitialized()) + and any(coeff_stream[i] for i in range(coeff_stream._approximate_order, 1))): raise ValueError("can only compose with a positive valuation series") # WARNING: d_self need not be a proper element of P, e.g. for # multivariate power series @@ -3201,7 +3643,9 @@ def exp(self): d_self = Stream_function(lambda n: (n + 1) * coeff_stream[n + 1], False, 0) f = P.undefined(valuation=0) - d_self_f = Stream_cauchy_mul(d_self, f._coeff_stream, False) + # d_self and f._coeff_stream always commute, the coefficients + # of the product are of the form sum_{k=1}^n a_k a_{n+1-k}. + d_self_f = Stream_cauchy_mul_commutative(d_self, f._coeff_stream, False) int_d_self_f = Stream_function(lambda n: d_self_f[n-1] / R(n) if n else R.one(), False, 0) f._coeff_stream._target = int_d_self_f @@ -3229,8 +3673,8 @@ def log(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") - sage: log(1+z)[0:6] == log(1+x).series(x, 6).coefficients(sparse=False) + sage: L.<z> = LazyLaurentSeriesRing(QQ); x = var("x") # needs sage.symbolic + sage: log(1+z)[0:6] == log(1+x).series(x, 6).coefficients(sparse=False) # needs sage.symbolic True sage: log(z) @@ -3241,18 +3685,21 @@ def log(self): P = self.parent() R = self.base_ring() coeff_stream = self._coeff_stream - # TODO: coefficients should not be checked here, it prevents + # coefficients must not be checked here, it prevents # us from using self.define in some cases! - if (any(coeff_stream[i] for i in range(coeff_stream._approximate_order, 0)) - or coeff_stream[0] != R.one()): + if ((not coeff_stream.is_uninitialized()) + and (any(coeff_stream[i] for i in range(coeff_stream._approximate_order, 0)) + or coeff_stream[0] != R.one())): raise ValueError("can only compose with a positive valuation series") # WARNING: d_self need not be a proper element of P, e.g. for # multivariate power series d_self = Stream_function(lambda n: (n + 1) * coeff_stream[n + 1], P.is_sparse(), 0) - d_self_quo_self = Stream_cauchy_mul(d_self, - Stream_cauchy_invert(coeff_stream), - P.is_sparse()) + coeff_stream_inverse = Stream_cauchy_invert(coeff_stream) + # d_self and coeff_stream_inverse always commute + d_self_quo_self = Stream_cauchy_mul_commutative(d_self, + coeff_stream_inverse, + P.is_sparse()) int_d_self_quo_self = Stream_function(lambda n: d_self_quo_self[n-1] / R(n), P.is_sparse(), 1) return P.element_class(P, int_d_self_quo_self) @@ -3361,16 +3808,15 @@ def _im_gens_(self, codomain, im_gens, base_map=None): EXAMPLES:: + sage: # needs sage.rings.number_field sage: Z.<x> = ZZ[] sage: K.<i> = NumberField(x^2 + 1) sage: R.<t> = LazyLaurentSeriesRing(K) - sage: f = R(lambda n: i^n, valuation=-2) - sage: f + sage: f = R(lambda n: i^n, valuation=-2); f -t^-2 - i*t^-1 + 1 + i*t - t^2 - i*t^3 + t^4 + O(t^5) sage: f._im_gens_(R, [t + t^2]) -t^-2 + (-i + 2)*t^-1 + (i - 2) + 4*t + (2*i - 6)*t^2 + (-2*i + 4)*t^3 + (-2*i - 7)*t^4 + O(t^5) - sage: cc = K.hom([-i]) sage: f._im_gens_(R, [t + t^2], base_map=cc) -t^-2 + (i + 2)*t^-1 + (-i - 2) + 4*t + (-2*i - 6)*t^2 @@ -3381,16 +3827,16 @@ def _im_gens_(self, codomain, im_gens, base_map=None): return codomain(self.map_coefficients(base_map)(im_gens[0])) - def __call__(self, g, *, check=True): + def __call__(self, g): r""" Return the composition of ``self`` with ``g``. Given two Laurent series `f` and `g` over the same base ring, the composition `(f \circ g)(z) = f(g(z))` is defined if and only if: - - `g = 0` and `val(f) >= 0`, + - `g = 0` and `\mathrm{val}(f) \geq 0`, - `g` is non-zero and `f` has only finitely many non-zero coefficients, - - `g` is non-zero and `val(g) > 0`. + - `g` is non-zero and `\mathrm{val}(g) > 0`. INPUT: @@ -3455,7 +3901,7 @@ def __call__(self, g, *, check=True): sage: f = L(lambda n: n, valuation=0); f z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: f(z^2) - z^2 + 2*z^4 + 3*z^6 + O(z^7) + z^2 + 2*z^4 + 3*z^6 + 4*z^8 + O(z^9) sage: f = L(lambda n: n, valuation=-2); f -2*z^-2 - z^-1 + z + 2*z^2 + 3*z^3 + 4*z^4 + O(z^5) @@ -3499,7 +3945,7 @@ def __call__(self, g, *, check=True): sage: f(0) 0 sage: f(y) - y + 2*y^2 + 3*y^3 + 4*y^4 + 5*y^5 + 6*y^6 + O(y^7) + y + 2*y^2 + 3*y^3 + 4*y^4 + 5*y^5 + 6*y^6 + 7*y^7 + O(y^8) sage: fp = f(y - y) sage: fp == 0 True @@ -3574,7 +4020,7 @@ def __call__(self, g, *, check=True): y We look at cases where the composition does not exist. - `g = 0` and `val(f) < 0`:: + `g = 0` and `\mathrm{val}(f) < 0`:: sage: g = L(0) sage: f = z^-1 + z^-2 @@ -3585,7 +4031,7 @@ def __call__(self, g, *, check=True): ... ZeroDivisionError: the valuation of the series must be nonnegative - `g \neq 0` and `val(g) \leq 0` and `f` has infinitely many + `g \neq 0` and `\mathrm{val}(g) \leq 0` and `f` has infinitely many non-zero coefficients:: sage: g = z^-1 + z^-2 @@ -3608,7 +4054,8 @@ def __call__(self, g, *, check=True): sage: L.<z> = LazyLaurentSeriesRing(QQ) sage: e = L(lambda n: 1/factorial(n), 0) sage: D = LazyDirichletSeriesRing(QQ, "s") - sage: g = D(constant=1)-1; g + sage: g = D(constant=1)-1 + sage: g # needs sage.symbolic 1/(2^s) + 1/(3^s) + 1/(4^s) + O(1/(5^s)) sage: e(g)[0:10] @@ -3617,7 +4064,8 @@ def __call__(self, g, *, check=True): sage: sum(g^k/factorial(k) for k in range(10))[0:10] [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] - sage: g = D([0,1,0,1,1,2]); g + sage: g = D([0,1,0,1,1,2]) + sage: g # needs sage.symbolic 1/(2^s) + 1/(4^s) + 1/(5^s) + 2/6^s sage: e(g)[0:10] [0, 1, 1, 0, 3/2, 1, 2, 0, 7/6, 0] @@ -3629,11 +4077,12 @@ def __call__(self, g, *, check=True): ... ValueError: can only compose with a positive valuation series - sage: e5 = L(e, degree=5); e5 + sage: e5 = L(e, degree=5) + sage: e5 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 - sage: e5(g) + sage: e5(g) # needs sage.symbolic 1 + 1/(2^s) + 3/2/4^s + 1/(5^s) + 2/6^s + O(1/(8^s)) - sage: sum(e5[k] * g^k for k in range(5)) + sage: sum(e5[k] * g^k for k in range(5)) # needs sage.symbolic 1 + 1/(2^s) + 3/2/4^s + 1/(5^s) + 2/6^s + O(1/(8^s)) The output parent is always the common parent between the base ring @@ -3664,6 +4113,17 @@ def __call__(self, g, *, check=True): sage: g = L.undefined(valuation=0) sage: f(g) == f.polynomial()(g) True + + TESTS: + + Check that :issue:`36154` is fixed:: + + sage: L.<z> = LazyLaurentSeriesRing(Zmod(4)) + sage: f = L([0,2]) + sage: g = L([2]) + sage: f(g) + 0 + """ # Find a good parent for the result from sage.structure.element import get_coercion_model @@ -3708,6 +4168,8 @@ def __call__(self, g, *, check=True): except (ValueError, TypeError): # the result is not a Laurent polynomial ret = None if ret is not None and ret.parent() is R: + if not ret: + return P.zero() val = ret.valuation() deg = ret.degree() + 1 initial_coefficients = [ret[i] for i in range(val, deg)] @@ -3759,18 +4221,18 @@ def __call__(self, g, *, check=True): raise NotImplementedError("can only compose with a lazy series") # Perhaps we just don't yet know if the valuation is positive - if check: - if g._coeff_stream._approximate_order <= 0: - if any(g._coeff_stream[i] for i in range(g._coeff_stream._approximate_order, 1)): - raise ValueError("can only compose with a positive valuation series") - g._coeff_stream._approximate_order = 1 + if g._coeff_stream._approximate_order <= 0: + if (not g._coeff_stream.is_uninitialized() + and any(g._coeff_stream[i] for i in range(g._coeff_stream._approximate_order, 1))): + raise ValueError("can only compose with a positive valuation series") + g._coeff_stream._approximate_order = 1 if isinstance(g, LazyDirichletSeries): - if check: - if g._coeff_stream._approximate_order == 1: - if g._coeff_stream[1] != 0: - raise ValueError("can only compose with a positive valuation series") - g._coeff_stream._approximate_order = 2 + if g._coeff_stream._approximate_order == 1: + if (not g._coeff_stream.is_uninitialized() + and g._coeff_stream[1] != 0): + raise ValueError("can only compose with a positive valuation series") + g._coeff_stream._approximate_order = 2 # we assume that the valuation of self[i](g) is at least i def coefficient(n): @@ -3797,11 +4259,11 @@ def revert(self): The compositional inverse exists if and only if: - - `val(f) = 1`, or + - `\mathrm{val}(f) = 1`, or - `f = a + b z` with `a, b \neq 0`, or - - `f = a/z` with `a \neq 0` + - `f = a/z` with `a \neq 0`. EXAMPLES:: @@ -3821,6 +4283,17 @@ def revert(self): sage: s.revert() z - z^2 + z^3 - z^4 + z^5 - z^6 + z^7 + O(z^8) + .. WARNING:: + + For series not known to be eventually constant (e.g., being + defined by a function) with approximate valuation `\leq 1` + (but not necessarily its true valuation), this assumes + that this is the actual valuation:: + + sage: f = L(lambda n: n if n > 2 else 0, valuation=1) + sage: f.revert() + <repr(... failed: ValueError: inverse does not exist> + TESTS:: sage: L.<z> = LazyLaurentSeriesRing(QQ) @@ -3870,7 +4343,7 @@ def revert(self): ... ValueError: compositional inverse does not exist - `val(f) != 1` and `f(0) * f(1) = 0`:: + `\mathrm{val}(f) != 1` and `f(0) * f(1) = 0`:: sage: (z^2).revert() Traceback (most recent call last): @@ -3918,6 +4391,7 @@ def revert(self): R = P.base_ring() # we cannot assume that the last initial coefficient # and the constant differ, see stream.Stream_exact + # TODO: provide example or remove this claim if (coeff_stream._degree == 1 + len(coeff_stream._initial_coefficients) and coeff_stream._constant == -R.one() and all(c == -R.one() for c in coeff_stream._initial_coefficients)): @@ -3975,7 +4449,7 @@ def derivative(self, *args): TESTS: - Check the derivative of the logarithm: + Check the derivative of the logarithm:: sage: L.<z> = LazyLaurentSeriesRing(QQ) sage: -log(1-z).derivative() @@ -4011,6 +4485,12 @@ def derivative(self, *args): sage: f.derivative(q)[3] 3*q^2 - 2 + Check that :issue:`36154` is fixed:: + + sage: L.<z> = LazyLaurentSeriesRing(Zmod(4)) + sage: f = L([0,0,2]) + sage: f.derivative() + 0 """ P = self.parent() R = P._laurent_poly_ring @@ -4038,6 +4518,8 @@ def derivative(self, *args): coeffs = [prod(i-k for k in range(order)) * c for i, c in enumerate(coeff_stream._initial_coefficients, coeff_stream._approximate_order)] + if not any(coeffs): + return P.zero() coeff_stream = Stream_exact(coeffs, order=coeff_stream._approximate_order - order, constant=coeff_stream._constant) @@ -4287,7 +4769,7 @@ def exponential(self): def compute_coefficients(self, i): r""" - Computes all the coefficients of self up to i. + Computes all the coefficients of ``self`` up to ``i``. This method is deprecated, it has no effect anymore. @@ -4333,7 +4815,7 @@ def _im_gens_(self, codomain, im_gens, base_map=None): return codomain(self.map_coefficients(base_map)(*im_gens)) - def __call__(self, *g, check=True): + def __call__(self, *g): r""" Return the composition of ``self`` with ``g``. @@ -4343,12 +4825,12 @@ def __call__(self, *g, check=True): Given a Taylor series `f` of arity `n` and a tuple of Taylor series `g = (g_1,\dots, g_n)` over the same base ring, the composition `f \circ g` is defined if and only if for each - `1\leq k\leq n`: + `1\leq i\leq n`: - `g_i` is zero, or - - setting all variables except the `i`th in `f` to zero + - setting all variables except the `i`-th in `f` to zero yields a polynomial, or - - `val(g_i) > 0`. + - `\mathrm{val}(g_i) > 0`. If `f` is a univariate 'exact' series, we can check whether `f` is a actually a polynomial. However, if `f` is a @@ -4392,25 +4874,29 @@ def __call__(self, *g, check=True): We perform the composition with a lazy Dirichlet series:: + sage: # needs sage.symbolic sage: D = LazyDirichletSeriesRing(QQ, "s") - sage: g = D(constant=1)-1; g + sage: g = D(constant=1)-1 + sage: g 1/(2^s) + 1/(3^s) + 1/(4^s) + O(1/(5^s)) sage: f = 1 / (1 - x - y*z); f 1 + x + (x^2+y*z) + (x^3+2*x*y*z) + (x^4+3*x^2*y*z+y^2*z^2) + (x^5+4*x^3*y*z+3*x*y^2*z^2) + (x^6+5*x^4*y*z+6*x^2*y^2*z^2+y^3*z^3) + O(x,y,z)^7 - sage: fog = f(g, g, g); fog + sage: fog = f(g, g, g) + sage: fog 1 + 1/(2^s) + 1/(3^s) + 3/4^s + 1/(5^s) + 5/6^s + O(1/(7^s)) - sage: fg = 1 / (1 - g - g*g); fg + sage: fg = 1 / (1 - g - g*g) + sage: fg 1 + 1/(2^s) + 1/(3^s) + 3/4^s + 1/(5^s) + 5/6^s + 1/(7^s) + O(1/(8^s)) sage: fog - fg - O(1/(7^s)) + O(1/(8^s)) sage: f = 1 / (1 - 2*a) - sage: f(g) + sage: f(g) # needs sage.symbolic 1 + 2/2^s + 2/3^s + 6/4^s + 2/5^s + 10/6^s + 2/7^s + O(1/(8^s)) - sage: 1 / (1 - 2*g) + sage: 1 / (1 - 2*g) # needs sage.symbolic 1 + 2/2^s + 2/3^s + 6/4^s + 2/5^s + 10/6^s + 2/7^s + O(1/(8^s)) The output parent is always the common parent between the base ring @@ -4507,6 +4993,21 @@ def __call__(self, *g, check=True): sage: T(1-x-2*y + x*y^2)(1/(1-a), 3) 3 + 8*a + 8*a^2 + 8*a^3 + 8*a^4 + 8*a^5 + 8*a^6 + O(a,b)^7 + Check that issue :trac:`35261` is fixed:: + + sage: L.<z> = LazyPowerSeriesRing(QQ) + sage: fun = lambda n: 1 if ZZ(n).is_power_of(2) else 0 + sage: f = L(fun) + sage: g = L.undefined(valuation=1) + sage: g.define((~f.shift(-1)(g)).shift(1)) + sage: g + z - z^2 + 2*z^3 - 6*z^4 + 20*z^5 - 70*z^6 + 256*z^7 + O(z^8) + + sage: f = L(fun) + sage: g = L.undefined(valuation=1) + sage: g.define((z - (f - z)(g))) + sage: g + z - z^2 + 2*z^3 - 6*z^4 + 20*z^5 - 70*z^6 + 256*z^7 + O(z^8) """ fP = parent(self) if len(g) != fP._arity: @@ -4567,18 +5068,17 @@ def __call__(self, *g, check=True): g = [P(h) for h in g] R = P._internal_poly_ring.base_ring() - if check: - for h in g: - if h._coeff_stream._approximate_order == 0: - if h[0]: - raise ValueError("can only compose with a positive valuation series") - h._coeff_stream._approximate_order = 1 + for h in g: + if h._coeff_stream._approximate_order == 0: + if not h._coeff_stream.is_uninitialized() and h[0]: + raise ValueError("can only compose with a positive valuation series") + h._coeff_stream._approximate_order = 1 - if isinstance(h, LazyDirichletSeries): - if h._coeff_stream._approximate_order == 1: - if h._coeff_stream[1] != 0: - raise ValueError("can only compose with a positive valuation series") - h._coeff_stream._approximate_order = 2 + if isinstance(h, LazyDirichletSeries): + if h._coeff_stream._approximate_order == 1: + if not h._coeff_stream.is_uninitialized() and h._coeff_stream[1] != 0: + raise ValueError("can only compose with a positive valuation series") + h._coeff_stream._approximate_order = 2 # We now have that every element of g has a _coeff_stream sorder = self._coeff_stream._approximate_order @@ -4615,15 +5115,15 @@ def revert(self): r""" Return the compositional inverse of ``self``. - Given a Taylor series `f`, the compositional inverse is a - Laurent series `g` over the same base ring, such that + Given a Taylor series `f` in one variable, the compositional + inverse is a power series `g` over the same base ring, such that `(f \circ g)(z) = f(g(z)) = z`. The compositional inverse exists if and only if: - - `val(f) = 1`, or + - `\mathrm{val}(f) = 1`, or - - `f = a + b z` with `a, b \neq 0` + - `f = a + b z` with `a, b \neq 0`. EXAMPLES:: @@ -4641,6 +5141,17 @@ def revert(self): sage: s.revert() z - z^2 + z^3 - z^4 + z^5 - z^6 + z^7 + O(z^8) + .. WARNING:: + + For series not known to be eventually constant (e.g., being + defined by a function) with approximate valuation `\leq 1` + (but not necessarily its true valuation), this assumes + that this is the actual valuation:: + + sage: f = L(lambda n: n if n > 2 else 0) + sage: f.revert() + <repr(... failed: ValueError: generator already executing> + TESTS:: sage: L.<z> = LazyPowerSeriesRing(QQ) @@ -4649,7 +5160,7 @@ def revert(self): sage: s.revert() 1/2*z + O(z^8) - sage: (2+3*z).revert() + sage: (2 + 3*z).revert() -2/3 + 1/3*z sage: s = L(lambda n: 2 if n == 0 else 3 if n == 1 else 0, valuation=0); s @@ -4681,7 +5192,7 @@ def revert(self): ... ValueError: compositional inverse does not exist - `val(f) != 1` and `f(0) * f(1) = 0`:: + `\mathrm{val}(f) != 1` and `f(0) * f(1) = 0`:: sage: (z^2).revert() Traceback (most recent call last): @@ -4693,6 +5204,13 @@ def revert(self): ... ValueError: compositional inverse does not exist + `\mathrm{val}(f) > 1`:: + + sage: L(lambda n: n, valuation=2).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + Reversion of exact series:: sage: f = L([1, 2], valuation=0, constant=1) @@ -4712,6 +5230,15 @@ def revert(self): sage: f = L([-1], valuation=1, degree=3, constant=-1) sage: f.revert() (-z) + z^3 + (-z^4) + (-2*z^5) + 6*z^6 + z^7 + O(z^8) + + Check that issue :trac:`35261` is fixed:: + + sage: L.<z> = LazyPowerSeriesRing(QQ) + sage: f = L(lambda n: 1 if ZZ(n).is_power_of(2) else 0) + sage: f + z + z^2 + z^4 + O(z^7) + sage: f.revert() + z - z^2 + 2*z^3 - 6*z^4 + 20*z^5 - 70*z^6 + 256*z^7 + O(z^8) """ P = self.parent() if P._arity != 1: @@ -4744,9 +5271,11 @@ def revert(self): if coeff_stream.order() != 1: raise ValueError("compositional inverse does not exist") + if coeff_stream._approximate_order > 1: + raise ValueError("compositional inverse does not exist") # TODO: coefficients should not be checked here, it prevents # us from using self.define in some cases! - if coeff_stream[0]: + if coeff_stream._approximate_order == 0 and coeff_stream[0]: raise ValueError("cannot determine whether the compositional inverse exists") g = P.undefined(valuation=1) @@ -4793,6 +5322,14 @@ def derivative(self, *args): + (6*q^5*x^6+(-30*q^4)*x^5*y+60*q^3*x^4*y^2+(-60*q^2)*x^3*y^3+30*q*x^2*y^4+(-6)*x*y^5) + O(x,y)^7 + TESTS: + + Check that :issue:`36154` is fixed:: + + sage: L.<z> = LazyPowerSeriesRing(Zmod(4)) + sage: f = L([0,0,2]) + sage: f.derivative() + 0 """ P = self.parent() R = P._laurent_poly_ring @@ -4838,6 +5375,8 @@ def derivative(self, *args): coeffs = [prod(i-k for k in range(order)) * c for i, c in enumerate(coeff_stream._initial_coefficients, coeff_stream._approximate_order)] + if not any(coeffs): + return P.zero() coeff_stream = Stream_exact(coeffs, order=coeff_stream._approximate_order - order, constant=coeff_stream._constant) @@ -4901,24 +5440,24 @@ def _format_series(self, formatter, format_strings=False): poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) elif formatter == ascii_art: if atomic_repr: - poly = ascii_art(*(mons + bigO), sep = " + ") + poly = ascii_art(*(mons + bigO), sep=" + ") else: def parenthesize(m): a = ascii_art(m) h = a.height() return ascii_art(ascii_left_parenthesis.character_art(h), a, ascii_right_parenthesis.character_art(h)) - poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep=" + ") elif formatter == unicode_art: if atomic_repr: - poly = unicode_art(*(mons + bigO), sep = " + ") + poly = unicode_art(*(mons + bigO), sep=" + ") else: def parenthesize(m): a = unicode_art(m) h = a.height() return unicode_art(unicode_left_parenthesis.character_art(h), a, unicode_right_parenthesis.character_art(h)) - poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep=" + ") return poly @@ -5005,11 +5544,11 @@ def _floordiv_(self, other): sage: g = x^2 + y*x sage: x // g 0 - sage: g = (x^2 + y*x) / (1 - x + x*y) + sage: g = (x^2 + y*x) / (1 - x + x*y) # needs sage.libs.singular sage: x // g 0 - sage: f = (x + y) / (1 - x - y + x*y) - sage: f // g + sage: f = (x + y) / (1 - x - y + x*y) # needs sage.libs.singular + sage: f // g # needs sage.libs.singular 0 sage: L.<x> = LazyPowerSeriesRing(QQ) @@ -5114,6 +5653,7 @@ def xgcd(self, f): sage: g == s * a + t * b True + sage: # needs sage.rings.finite_rings sage: L.<x> = LazyPowerSeriesRing(GF(2)) sage: a = L(lambda n: n % 2, valuation=3); a x^3 + x^5 + x^7 + x^9 + O(x^10) @@ -5168,6 +5708,7 @@ def _format_series(self, formatter, format_strings=False): TESTS:: + sage: # needs sage.modules sage: h = SymmetricFunctions(ZZ).h() sage: e = SymmetricFunctions(ZZ).e() sage: L = LazySymmetricFunctions(tensor([h, e])) @@ -5215,24 +5756,24 @@ def _format_series(self, formatter, format_strings=False): poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) elif formatter == ascii_art: if atomic_repr: - poly = ascii_art(*(mons + bigO), sep = " + ") + poly = ascii_art(*(mons + bigO), sep=" + ") else: def parenthesize(m): a = ascii_art(m) h = a.height() return ascii_art(ascii_left_parenthesis.character_art(h), a, ascii_right_parenthesis.character_art(h)) - poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep=" + ") elif formatter == unicode_art: if atomic_repr: - poly = unicode_art(*(mons + bigO), sep = " + ") + poly = unicode_art(*(mons + bigO), sep=" + ") else: def parenthesize(m): a = unicode_art(m) h = a.height() return unicode_art(unicode_left_parenthesis.character_art(h), a, unicode_right_parenthesis.character_art(h)) - poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep=" + ") return poly @@ -5243,8 +5784,8 @@ class LazySymmetricFunction(LazyCompletionGradedAlgebraElement): EXAMPLES:: - sage: s = SymmetricFunctions(ZZ).s() - sage: L = LazySymmetricFunctions(s) + sage: s = SymmetricFunctions(ZZ).s() # needs sage.modules + sage: L = LazySymmetricFunctions(s) # needs sage.modules """ def is_unit(self): """ @@ -5252,21 +5793,17 @@ def is_unit(self): EXAMPLES:: + sage: # needs sage.modules sage: m = SymmetricFunctions(ZZ).m() sage: L = LazySymmetricFunctions(m) - sage: L(2*m[1]).is_unit() False - sage: L(-1 + 2*m[1]).is_unit() True - sage: L(2 + m[1]).is_unit() False - sage: m = SymmetricFunctions(QQ).m() sage: L = LazySymmetricFunctions(m) - sage: L(2 + 3*m[1]).is_unit() True """ @@ -5274,7 +5811,7 @@ def is_unit(self): return False return self[0].is_unit() - def __call__(self, *args, check=True): + def __call__(self, *args): r""" Return the composition of ``self`` with ``g``. @@ -5284,13 +5821,13 @@ def __call__(self, *args, check=True): Given a lazy symmetric function `f` of arity `n` and a tuple of lazy symmetric functions `g = (g_1,\dots, g_n)` over the same base ring, the composition (or plethysm) `(f \circ g)` - is defined if and only if for each `1\leq k\leq n`: + is defined if and only if for each `1\leq i\leq n`: - `g_i = 0`, or - - setting all alphabets except the `i`th in `f` to zero + - setting all alphabets except the `i`-th in `f` to zero yields a symmetric function with only finitely many non-zero coefficients, or - - `val(g) > 0`. + - `\mathrm{val}(g) > 0`. If `f` is a univariate 'exact' lazy symmetric function, we can check whether `f` has only finitely many non-zero @@ -5310,6 +5847,7 @@ def __call__(self, *args, check=True): EXAMPLES:: + sage: # needs sage.modules sage: P.<q> = QQ[] sage: s = SymmetricFunctions(P).s() sage: L = LazySymmetricFunctions(s) @@ -5317,15 +5855,12 @@ def __call__(self, *args, check=True): sage: g = s[3] sage: L(f)(L(g)) - L(f(g)) 0 - sage: f = s[2] + s[2,1] sage: g = s[1] + s[2,2] sage: L(f)(L(g)) - L(f(g)) 0 - sage: L(f)(g) - L(f(g)) 0 - sage: f = s[2] + s[2,1] sage: g = s[1] + s[2,2] sage: L(f)(L(q*g)) - L(f(q*g)) @@ -5334,6 +5869,7 @@ def __call__(self, *args, check=True): The Frobenius character of the permutation action on set partitions is a plethysm:: + sage: # needs sage.modules sage: s = SymmetricFunctions(QQ).s() sage: S = LazySymmetricFunctions(s) sage: E1 = S(lambda n: s[n], valuation=1) @@ -5344,6 +5880,7 @@ def __call__(self, *args, check=True): The plethysm with a tensor product is also implemented:: + sage: # needs sage.modules sage: s = SymmetricFunctions(QQ).s() sage: X = tensor([s[1],s[[]]]) sage: Y = tensor([s[[]],s[1]]) @@ -5351,14 +5888,14 @@ def __call__(self, *args, check=True): sage: S2 = LazySymmetricFunctions(tensor([s, s])) sage: A = S(s[1,1,1]) sage: B = S2(X+Y) - sage: A(B) + sage: A(B) # needs lrcalc_python (s[]#s[1,1,1]+s[1]#s[1,1]+s[1,1]#s[1]+s[1,1,1]#s[]) - sage: H = S(lambda n: s[n]) - sage: H(S2(X*Y)) + sage: H = S(lambda n: s[n]) # needs sage.modules + sage: H(S2(X*Y)) # needs lrcalc_python sage.modules (s[]#s[]) + (s[1]#s[1]) + (s[1,1]#s[1,1]+s[2]#s[2]) + (s[1,1,1]#s[1,1,1]+s[2,1]#s[2,1]+s[3]#s[3]) + O^7 - sage: H(S2(X+Y)) + sage: H(S2(X+Y)) # needs sage.modules (s[]#s[]) + (s[]#s[1]+s[1]#s[]) + (s[]#s[2]+s[1]#s[1]+s[2]#s[]) + (s[]#s[3]+s[1]#s[2]+s[2]#s[1]+s[3]#s[]) + (s[]#s[4]+s[1]#s[3]+s[2]#s[2]+s[3]#s[1]+s[4]#s[]) @@ -5368,22 +5905,23 @@ def __call__(self, *args, check=True): TESTS:: + sage: # needs sage.modules sage: s = SymmetricFunctions(QQ).s() sage: S = LazySymmetricFunctions(s) sage: f = 1 / (1 - S(s[2])) - sage: g = f(s[2]); g + sage: g = f(s[2]); g # needs lrcalc_python s[] + (s[2,2]+s[4]) + O^7 - sage: S(sum(f[i](s[2]) for i in range(5))).truncate(10) == g.truncate(10) + sage: S(sum(f[i](s[2]) for i in range(5))).truncate(10) == g.truncate(10) # needs lrcalc_python True sage: f = 1 / (1 - S(s[2])) sage: g = S(s[1]) / (1 - S(s[1])) - sage: f(g) + sage: f(g) # needs lrcalc_python s[] + s[2] + (s[1,1,1]+2*s[2,1]+s[3]) + (2*s[1,1,1,1]+4*s[2,1,1]+5*s[2,2]+5*s[3,1]+3*s[4]) + (2*s[1,1,1,1,1]+10*s[2,1,1,1]+14*s[2,2,1]+18*s[3,1,1]+16*s[3,2]+14*s[4,1]+4*s[5]) + (3*s[1,1,1,1,1,1]+22*s[2,1,1,1,1]+38*s[2,2,1,1]+28*s[2,2,2]+48*s[3,1,1,1]+82*s[3,2,1]+25*s[3,3]+51*s[4,1,1]+56*s[4,2]+31*s[5,1]+9*s[6]) + O^7 - sage: f(0) + sage: f(0) # needs lrcalc_python 1 sage: f(s(1)) Traceback (most recent call last): @@ -5393,6 +5931,7 @@ def __call__(self, *args, check=True): Check that composing the zero series with anything yields zero in the correct parent:: + sage: # needs sage.modules sage: e = SymmetricFunctions(QQ).e() sage: h = SymmetricFunctions(QQ).h() sage: s = SymmetricFunctions(QQ).s() @@ -5405,10 +5944,10 @@ def __call__(self, *args, check=True): Check that composing `f` with zero series yields the constant term of `f`:: - sage: f = 3*L(tensor([s[1], s[1]])) - sage: f(0, 0) + sage: f = 3*L(tensor([s[1], s[1]])) # needs sage.modules + sage: f(0, 0) # needs sage.modules 0 - sage: (3+f)(0, 0) + sage: (3+f)(0, 0) # needs sage.modules 3 """ fP = parent(self) @@ -5458,10 +5997,10 @@ def __call__(self, *args, check=True): P = LazySymmetricFunctions(R) g = P(g) - if check and not (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): + if not (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): if g._coeff_stream._approximate_order == 0: - if g[0]: + if not g._coeff_stream.is_uninitialized() and g[0]: raise ValueError("can only compose with a positive valuation series") g._coeff_stream._approximate_order = 1 @@ -5489,44 +6028,43 @@ def revert(self): The compositional inverse exists if and only if: - - `val(f) = 1`, or + - `\mathrm{val}(f) = 1`, or - `f = a + b p_1` with `a, b \neq 0`. EXAMPLES:: + sage: # needs sage.modules sage: h = SymmetricFunctions(QQ).h() sage: L = LazySymmetricFunctions(h) sage: f = L(lambda n: h[n]) - 1 sage: f(f.revert()) - h[1] + O^7 + h[1] + O^8 TESTS:: - sage: f = L(lambda n: h[n]) - 1 - h[1] - sage: g = f.revert() - sage: g[1] + sage: f = L(lambda n: h[n]) - 1 - h[1] # needs sage.modules + sage: g = f.revert() # needs sage.modules + sage: g[1] # needs sage.modules Traceback (most recent call last): ... ValueError: compositional inverse does not exist + sage: # needs sage.modules sage: R.<a,b> = QQ[] sage: p = SymmetricFunctions(R.fraction_field()).p() sage: L = LazySymmetricFunctions(p) sage: f = L(a + b*p[1]) sage: f.revert() (((-a)/b)*p[]) + 1/b*p[1] - sage: f = L(2*p[1]) sage: f.revert() 1/2*p[1] - sage: f = L(2*p[1] + p[1,1]) sage: f.revert() 1/2*p[1] + (-1/8*p[1,1]) + (1/16*p[1,1,1]) + (-5/128*p[1,1,1,1]) + (7/256*p[1,1,1,1,1]) + (-21/1024*p[1,1,1,1,1,1]) + (33/2048*p[1,1,1,1,1,1,1]) + O^8 - sage: f.revert()(f) p[1] + O^8 @@ -5620,6 +6158,7 @@ def derivative_with_respect_to_p1(self, n=1): The species `E` of sets satisfies the relationship `E' = E`:: + sage: # needs sage.modules sage: h = SymmetricFunctions(QQ).h() sage: T = LazySymmetricFunctions(h) sage: E = T(lambda n: h[n]) @@ -5629,14 +6168,17 @@ def derivative_with_respect_to_p1(self, n=1): The species `C` of cyclic orderings and the species `L` of linear orderings satisfy the relationship `C' = L`:: + sage: # needs sage.modules sage: p = SymmetricFunctions(QQ).p() - sage: C = T(lambda n: (sum(euler_phi(k)*p([k])**(n//k) for k in divisors(n))/n if n > 0 else 0)) + sage: C = T(lambda n: (sum(euler_phi(k)*p([k])**(n//k) + ....: for k in divisors(n))/n if n > 0 else 0)) sage: L = T(lambda n: p([1]*n)) - sage: L - C.derivative_with_respect_to_p1() + sage: L - C.derivative_with_respect_to_p1() # needs sage.libs.pari O^6 TESTS:: + sage: # needs sage.modules sage: T = LazySymmetricFunctions(p) sage: a = T(p([1,1,1])) sage: a.derivative_with_respect_to_p1() @@ -5699,13 +6241,14 @@ def functorial_composition(self, *args): \mathfrak{p}_{2}`, where `\mathfrak{p}` is the :class:`~sage.combinat.species.subset_species.SubsetSpecies`.:: + sage: # needs sage.modules sage: R.<q> = QQ[] sage: h = SymmetricFunctions(R).h() sage: m = SymmetricFunctions(R).m() sage: L = LazySymmetricFunctions(m) sage: P = L(lambda n: sum(q^k*h[n-k]*h[k] for k in range(n+1))) sage: P2 = L(lambda n: h[2]*h[n-2], valuation=2) - sage: P.functorial_composition(P2)[:4] + sage: P.functorial_composition(P2)[:4] # needs sage.libs.pari [m[], m[1], (q+1)*m[1, 1] + (q+1)*m[2], @@ -5713,12 +6256,12 @@ def functorial_composition(self, *args): For example, there are:: - sage: P.functorial_composition(P2)[4].coefficient([4])[3] + sage: P.functorial_composition(P2)[4].coefficient([4])[3] # needs sage.libs.pari sage.modules 3 unlabelled graphs on 4 vertices and 3 edges, and:: - sage: P.functorial_composition(P2)[4].coefficient([2,2])[3] + sage: P.functorial_composition(P2)[4].coefficient([2,2])[3] # needs sage.libs.pari sage.modules 8 labellings of their vertices with two 1's and two 2's. @@ -5726,47 +6269,60 @@ def functorial_composition(self, *args): The symmetric function `h_1 \sum_n h_n` is the neutral element with respect to functorial composition:: + sage: # needs sage.modules sage: p = SymmetricFunctions(QQ).p() sage: h = SymmetricFunctions(QQ).h() sage: e = SymmetricFunctions(QQ).e() sage: L = LazySymmetricFunctions(h) - sage: E = L(lambda n: h[n]) - sage: Ep = p[1]*E.derivative_with_respect_to_p1(); Ep + sage: H = L(lambda n: h[n]) + sage: Ep = p[1]*H.derivative_with_respect_to_p1(); Ep h[1] + (h[1,1]) + (h[2,1]) + (h[3,1]) + (h[4,1]) + (h[5,1]) + O^7 sage: f = L(lambda n: h[n-n//2, n//2]) - sage: f - Ep.functorial_composition(f) + sage: f - Ep.functorial_composition(f) # needs sage.libs.pari + O^7 + + The symmetric function `\sum_n h_n` is a left absorbing element:: + + sage: # needs sage.modules + sage: H.functorial_composition(f) - H O^7 The functorial composition distributes over the sum:: + sage: # needs sage.modules sage: F1 = L(lambda n: h[n]) sage: F2 = L(lambda n: e[n]) sage: f1 = F1.functorial_composition(f) sage: f2 = F2.functorial_composition(f) - sage: (F1 + F2).functorial_composition(f) - f1 - f2 # long time + sage: (F1 + F2).functorial_composition(f) - f1 - f2 # long time O^7 TESTS: Check a corner case:: - sage: h = SymmetricFunctions(QQ).h() - sage: L = LazySymmetricFunctions(h) - sage: L(h[2,1]).functorial_composition(3*h[0]) + sage: h = SymmetricFunctions(QQ).h() # needs sage.modules + sage: L = LazySymmetricFunctions(h) # needs sage.modules + sage: L(h[2,1]).functorial_composition(3*h[0]) # needs sage.libs.pari sage.modules 3*h[] + O^7 Check an instance of a non-group action:: + sage: # needs sage.modules sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() sage: L = LazySymmetricFunctions(p) sage: f = L(lambda n: s[n]) sage: g = 2*s[2, 1, 1] + s[2, 2] + 3*s[4] - sage: r = f.functorial_composition(g); r[4] + sage: r = f.functorial_composition(g); r[4] # needs sage.libs.pari + Traceback (most recent call last): + ... + ValueError: the argument is not the Frobenius character of a permutation representation + sage: g = -p[1, 1, 1] + sage: r = f.functorial_composition(g); r[3] Traceback (most recent call last): ... ValueError: the argument is not the Frobenius character of a permutation representation - """ if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") @@ -5799,21 +6355,24 @@ def g_cycle_type(s, n): if g[0]: return Partition([1]*ZZ(g[0].coefficient([]))) return Partition([]) + + g_n = g[n] + if not g_n: + return Partition([]) + if any(c < 0 for c in g_n.monomial_coefficients(copy=False).values()): + raise ValueError("the argument is not the Frobenius character of a permutation representation") res = [] - # in the species case, k is at most - # factorial(n) * g[n].coefficient([1]*n) - for k in range(1, lcm(s) + 1): + # k is the length of a cycle in G[sigma], and + # n! g_n([1]*n) is the number of elements in G[n] + for k in range(1, 1 + min(lcm(s), + ZZ(factorial(n) * g_n.coefficient([1]*n)))): e = 0 for d in divisors(k): m = moebius(d) if not m: continue u = s.power(k // d) - # it could be, that we never need to compute - # g[n], so we only do this here - g_u = g[n] - if g_u: - e += m * u.aut() * g_u.coefficient(u) + e += m * u.aut() * g_n.coefficient(u) # e / k might not be an integer if g is not a # group action, so it is good to check res.extend([k] * ZZ(e / k)) @@ -5841,7 +6400,7 @@ def coefficient(n): else: raise NotImplementedError("only implemented for arity 1") - def arithmetic_product(self, *args, check=True): + def arithmetic_product(self, *args): r""" Return the arithmetic product of ``self`` with ``g``. @@ -5890,9 +6449,6 @@ def arithmetic_product(self, *args, check=True): - ``g`` -- a cycle index series having the same parent as ``self`` - - ``check`` -- (default: ``True``) a Boolean which, when set - to ``False``, will cause input checks to be skipped - OUTPUT: The arithmetic product of ``self`` with ``g``. @@ -5911,14 +6467,15 @@ def arithmetic_product(self, *args, check=True): consistent for all the lists in the structure. :: sage: R.<q> = QQ[] - sage: p = SymmetricFunctions(R).p() - sage: m = SymmetricFunctions(R).m() - sage: L = LazySymmetricFunctions(m) + sage: p = SymmetricFunctions(R).p() # needs sage.modules + sage: m = SymmetricFunctions(R).m() # needs sage.modules + sage: L = LazySymmetricFunctions(m) # needs sage.modules + sage: # needs sage.modules sage: C = species.CycleSpecies().cycle_index_series() sage: c = L(lambda n: C[n]) sage: Lplus = L(lambda n: p([1]*n), valuation=1) - sage: r = c.arithmetic_product(Lplus); r + sage: r = c.arithmetic_product(Lplus); r # needs sage.libs.pari m[1] + (3*m[1,1]+2*m[2]) + (8*m[1,1,1]+4*m[2,1]+2*m[3]) + (42*m[1,1,1,1]+21*m[2,1,1]+12*m[2,2]+7*m[3,1]+3*m[4]) @@ -5928,7 +6485,7 @@ def arithmetic_product(self, *args, check=True): In particular, the number of regular octopuses is:: - sage: [r[n].coefficient([1]*n) for n in range(8)] + sage: [r[n].coefficient([1]*n) for n in range(8)] # needs sage.libs.pari sage.modules [0, 1, 3, 8, 42, 144, 1440, 5760] It is shown in [MM2008]_ that the exponential generating @@ -5936,7 +6493,7 @@ def arithmetic_product(self, *args, check=True): (x) = \sum_{n \geq 1} \sigma (n) (n - 1)! \frac{x^{n}}{n!}` (where `\sigma (n)` is the sum of the divisors of `n`). :: - sage: [sum(divisors(i))*factorial(i-1) for i in range(1,8)] + sage: [sum(divisors(i))*factorial(i-1) for i in range(1,8)] # needs sage.modules [1, 3, 8, 42, 144, 1440, 5760] AUTHORS: @@ -5951,6 +6508,7 @@ def arithmetic_product(self, *args, check=True): Check that the product with zero works:: + sage: # needs sage.modules sage: s = SymmetricFunctions(QQ).s() sage: L = LazySymmetricFunctions(s) sage: L(0).arithmetic_product(s[2]) @@ -5961,27 +6519,27 @@ def arithmetic_product(self, *args, check=True): Check that the arithmetic product of symmetric functions of finite support works:: - sage: L(s([2])).arithmetic_product(s([1,1,1])) + sage: L(s([2])).arithmetic_product(s([1,1,1])) # needs sage.modules s[2, 2, 1, 1] + s[3, 1, 1, 1] + s[3, 2, 1] + s[3, 3] + 2*s[4, 1, 1] - sage: f = 1/(1-L(s[1])) - sage: f.arithmetic_product(s[1]) - f + sage: f = 1/(1-L(s[1])) # needs sage.modules + sage: f.arithmetic_product(s[1]) - f # needs lrcalc_python sage.modules O^7 Check that the arithmetic product of symmetric functions with constant a term works as advertised:: - sage: p = SymmetricFunctions(QQ).p() - sage: L = LazySymmetricFunctions(p) - sage: L(5).arithmetic_product(3*p[2,1]) + sage: p = SymmetricFunctions(QQ).p() # needs sage.modules + sage: L = LazySymmetricFunctions(p) # needs sage.modules + sage: L(5).arithmetic_product(3*p[2,1]) # needs sage.modules 15*p[] Check the arithmetic product of symmetric functions over a finite field works:: - sage: s = SymmetricFunctions(FiniteField(2)).s() - sage: L = LazySymmetricFunctions(s) - sage: L(s([2])).arithmetic_product(s([1,1,1])) + sage: s = SymmetricFunctions(FiniteField(2)).s() # needs sage.modules + sage: L = LazySymmetricFunctions(s) # needs sage.modules + sage: L(s([2])).arithmetic_product(s([1,1,1])) # needs sage.modules s[2, 2, 1, 1] + s[3, 1, 1, 1] + s[3, 2, 1] + s[3, 3] """ @@ -6034,15 +6592,11 @@ def arithmetic_product(self, *args, check=True): and not g._coeff_stream._constant): gs = g.symmetric_function() c += self[0].arithmetic_product(gs) - elif check: - raise ValueError("can only take the arithmetic product with a positive valuation series") if g[0]: if (isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant): fs = self.symmetric_function() c += fs.arithmetic_product(g[0]) - elif check: - raise ValueError("can only take the arithmetic product with a positive valuation series") p = R.realization_of().p() # TODO: does the following introduce a memory leak? @@ -6078,6 +6632,7 @@ def symmetric_function(self, degree=None): EXAMPLES:: + sage: # needs sage.modules sage: s = SymmetricFunctions(QQ).s() sage: S = LazySymmetricFunctions(s) sage: elt = S(s[2]) @@ -6086,28 +6641,30 @@ def symmetric_function(self, degree=None): TESTS:: + sage: # needs sage.modules sage: s = SymmetricFunctions(QQ).s() sage: S = LazySymmetricFunctions(s) sage: elt = S(s[2]) sage: elt.symmetric_function() s[2] sage: f = 1 / (1 - elt) - sage: f + sage: f # needs lrcalc_python s[] + s[2] + (s[2,2]+s[3,1]+s[4]) + (s[2,2,2]+2*s[3,2,1]+s[3,3]+s[4,1,1]+3*s[4,2]+2*s[5,1]+s[6]) + O^7 sage: f.symmetric_function() Traceback (most recent call last): ... ValueError: not a symmetric function - sage: f4 = f.truncate(5); f4 + sage: # needs sage.modules + sage: f4 = f.truncate(5); f4 # needs lrcalc_python s[] + s[2] + (s[2,2]+s[3,1]+s[4]) - sage: f4.symmetric_function() + sage: f4.symmetric_function() # needs lrcalc_python s[] + s[2] + s[2, 2] + s[3, 1] + s[4] - sage: f4.symmetric_function() == f.symmetric_function(4) + sage: f4.symmetric_function() == f.symmetric_function(4) # needs lrcalc_python True sage: S.zero().symmetric_function() 0 - sage: f4.symmetric_function(0) + sage: f4.symmetric_function(0) # needs lrcalc_python s[] """ @@ -6136,15 +6693,16 @@ class LazyDirichletSeries(LazyModuleElement): EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: f = L(constant=1)^2; f + sage: f = L(constant=1)^2 + sage: f # needs sage.symbolic 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z)) - sage: f.coefficient(100) == number_of_divisors(100) + sage: f.coefficient(100) == number_of_divisors(100) # needs sage.libs.pari True Lazy Dirichlet series is picklable:: sage: g = loads(dumps(f)) - sage: g + sage: g # needs sage.symbolic 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z)) sage: g == f True @@ -6184,14 +6742,14 @@ def valuation(self): EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: mu = L(moebius); mu.valuation() + sage: mu = L(moebius); mu.valuation() # needs sage.libs.pari 0 - sage: (mu - mu).valuation() + sage: (mu - mu).valuation() # needs sage.libs.pari +Infinity sage: g = L(constant=1, valuation=2) - sage: g.valuation() + sage: g.valuation() # needs sage.symbolic log(2) - sage: (g*g).valuation() + sage: (g*g).valuation() # needs sage.symbolic 2*log(2) """ if isinstance(self._coeff_stream, Stream_zero): @@ -6210,35 +6768,37 @@ def _mul_(self, other): TESTS:: sage: D = LazyDirichletSeriesRing(QQ, "s") - sage: zeta = D(constant=1); zeta + sage: zeta = D(constant=1) + sage: zeta # needs sage.symbolic 1 + 1/(2^s) + 1/(3^s) + O(1/(4^s)) - sage: zeta * zeta + sage: zeta * zeta # needs sage.symbolic 1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)) - sage: [number_of_divisors(n) for n in range(1, 8)] + sage: [number_of_divisors(n) for n in range(1, 8)] # needs sage.libs.pari [1, 2, 2, 3, 2, 4, 2] - sage: mu = D(moebius); mu + sage: mu = D(moebius) + sage: mu # needs sage.symbolic 1 - 1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(8^s)) - sage: zeta * mu + sage: zeta * mu # needs sage.symbolic 1 + O(1/(8^s)) sage: D.one() * mu is mu True sage: mu * D.one() is mu True - sage: zeta*(2-zeta) + sage: zeta*(2-zeta) # needs sage.symbolic 1 - 1/(4^s) - 2/6^s + O(1/(8^s)) sage: d1 = D([0,0,1,2,3]) sage: d2 = D([0,1,2,3]) - sage: d1 * d2 + sage: d1 * d2 # needs sage.symbolic 1/(6^s) + 2/8^s + 2/9^s + 3/10^s + 7/12^s + O(1/(13^s)) - sage: d1 * d2 # not tested - exact result + sage: d1 * d2 # not tested # needs sage.symbolic 1/(6^s) + 2/8^s + 2/9^s + 3/10^s + 7/12^s + 6/15^s + 6/16^s + 9/20^s sage: L.<t> = LazyLaurentSeriesRing(D) - sage: 1/(1-t*zeta) + sage: 1/(1-t*zeta) # needs sage.symbolic (1 + O(1/(8^s))) + (1 + 1/(2^s) + 1/(3^s) + 1/(4^s) + 1/(5^s) + 1/(6^s) + 1/(7^s) + O(1/(8^s)))*t + (1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)))*t^2 @@ -6286,10 +6846,10 @@ def __invert__(self): TESTS:: sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=False) - sage: ~L(constant=1) - L(moebius) + sage: ~L(constant=1) - L(moebius) # needs sage.libs.pari O(1/(8^z)) sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) - sage: ~L(constant=1) - L(moebius) + sage: ~L(constant=1) - L(moebius) # needs sage.libs.pari O(1/(8^z)) Trying to invert a non-invertible 'exact' series raises a @@ -6311,7 +6871,7 @@ def __invert__(self): return P.element_class(P, Stream_dirichlet_invert(self._coeff_stream, P.is_sparse())) - def __call__(self, p, *, check=True): + def __call__(self, p): r""" Return the composition of ``self`` with a linear polynomial ``p``. @@ -6336,12 +6896,13 @@ def __call__(self, p, *, check=True): sage: Z = D(constant=1) sage: from sage.arith.misc import dedekind_psi sage: Psi = D(dedekind_psi) - sage: Z(s)*Z(s-1)/Z(2*s) - Psi + sage: Z(s)*Z(s-1)/Z(2*s) - Psi # needs sage.symbolic O(1/(8^s)) - sage: Z(s)*Z(s-1)/Z(2*s-2) - (1/Psi).map_coefficients(abs) + sage: Z(s)*Z(s-1)/Z(2*s-2) - (1/Psi).map_coefficients(abs) # needs sage.symbolic O(1/(8^s)) + sage: # needs sage.symbolic sage: Z(5) zeta(5) sage: Z(1+I) @@ -6351,7 +6912,8 @@ def __call__(self, p, *, check=True): sage: Z(1) Infinity - sage: f = D([1,2,-3,-4], valuation=2); f + sage: f = D([1,2,-3,-4], valuation=2) + sage: f # needs sage.symbolic 1/(2^s) + 2/3^s - 3/4^s - 4/5^s sage: f(2) 449/3600 @@ -6369,11 +6931,11 @@ def __call__(self, p, *, check=True): 5 sage: f = D([1,2,-3,-4], constant=2) - sage: bool(f(2) == -1 + -5/3^2 + -6/4^2 + 2*zeta(2)) + sage: bool(f(2) == -1 + -5/3^2 + -6/4^2 + 2*zeta(2)) # needs sage.symbolic True - sage: f(0) + sage: f(0) # needs sage.symbolic -13 - sage: f(1) + sage: f(1) # needs sage.symbolic Infinity """ P = self.parent() @@ -6419,6 +6981,7 @@ def _format_series(self, formatter, format_strings=False): TESTS:: + sage: # needs sage.symbolic sage: L = LazyDirichletSeriesRing(QQ, "s") sage: f = L(constant=1) sage: f._format_series(repr) @@ -6426,14 +6989,11 @@ def _format_series(self, formatter, format_strings=False): sage: f._format_series(unicode_art) -s -s 1 + 2 + 3 + O(1/(4^s)) - sage: L([1,-1,1])._format_series(repr) '1 - 1/(2^s) + 1/(3^s)' - sage: L([1,-1,1])._format_series(ascii_art) -s -s 1 + -2 + 3 - sage: R.<x> = QQ[] sage: L = LazyDirichletSeriesRing(R, "s") sage: L([1,-1 + x,1/3])._format_series(ascii_art) @@ -6444,9 +7004,10 @@ def _format_series(self, formatter, format_strings=False): sage: L.<z> = LazyLaurentSeriesRing(QQ) sage: D = LazyDirichletSeriesRing(L, "s") - sage: f = D([2, 0, 1/(1-z), 3]); f + sage: f = D([2, 0, 1/(1-z), 3]) + sage: f # needs sage.symbolic (2)/1^s + ((1+z+z^2+O(z^3))/3^s) + (3)/4^s - sage: f._format_series(ascii_art) + sage: f._format_series(ascii_art) # needs sage.symbolic ((2)/1^s) + ((1 + z + z^2 + O(z^3))/3^s) + ((3)/4^s) """ P = self.parent() diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index b8613ba2b9c..07e08938696 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -19,6 +19,21 @@ :class:`sage.rings.padics.generic_nodes.pAdicRelaxedGeneric`, :func:`sage.rings.padics.factory.ZpER` +.. WARNING:: + + When the halting precision is infinite, the default for ``bool(f)`` + is ``True`` for any lazy series ``f`` that is not known to be zero. + This could end up resulting in infinite loops:: + + sage: L.<x> = LazyPowerSeriesRing(ZZ) + sage: f = L(lambda n: 0, valuation=0) + sage: 1 / f # not tested - infinite loop + +.. SEEALSO:: + + The examples of :class:`LazyLaurentSeriesRing` contain a discussion + about the different methods of comparisons the lazy series can use. + AUTHORS: - Kwankyu Lee (2019-02-24): initial version @@ -52,8 +67,10 @@ CompleteDiscreteValuationRings) from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute from sage.rings.integer_ring import ZZ +from sage.rings.infinity import infinity from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.lazy_series import (LazyModuleElement, @@ -64,7 +81,6 @@ LazySymmetricFunction, LazyDirichletSeries) from sage.structure.global_options import GlobalOptions -from sage.symbolic.ring import SR from sage.data_structures.stream import ( Stream_zero, @@ -187,8 +203,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: def g(i): ....: if i < 0: ....: return 1 - ....: else: - ....: return 1 + sum(k for k in range(i+1)) + ....: return 1 + sum(range(i + 1)) sage: e = L(g, valuation=-5); e z^-5 + z^-4 + z^-3 + z^-2 + z^-1 + 1 + 2*z + O(z^2) sage: f = e^-1; f @@ -257,13 +272,13 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: D = LazyDirichletSeriesRing(QQ, "s") sage: L.<z> = LazyLaurentSeriesRing(D) - sage: L(lambda n: 1/factorial(n), valuation=0) + sage: L(lambda n: 1/factorial(n), valuation=0) # needs sage.symbolic (1 + 1/2/2^s + 1/6/3^s + 1/24/4^s + 1/120/5^s + 1/720/6^s + 1/5040/7^s + O(1/(8^s))) We can also specify that the given function should be interpreted as the coefficients of the Laurent series:: - sage: L(coefficients=lambda n: 1/factorial(n), valuation=0) + sage: L(coefficients=lambda n: 1/factorial(n), valuation=0) # needs sage.symbolic 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) When the argument ``x`` is callable and not convertible into @@ -273,14 +288,14 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: R.<q> = QQ[] sage: D = LazyDirichletSeriesRing(ZZ, 't') - sage: D(1+2*q) + sage: D(1+2*q) # needs sage.symbolic 3 + 5/2^t + 7/3^t + 9/4^t + 11/5^t + 13/6^t + 15/7^t + O(1/(8^t)) In this example, the Dirichlet series ``m`` is considered as an element in the base ring:: sage: m = D(moebius) - sage: s = L(m, valuation=0) + sage: s = L(m, valuation=0) # needs sage.symbolic sage: s[0] 1 - 1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(8^s)) sage: s[1] @@ -288,12 +303,13 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No Converting various series from a univariate power series:: + sage: # needs sage.rings.finite_rings sage: L = LazyLaurentSeriesRing(GF(2), 'z') sage: R = LazyPowerSeriesRing(ZZ, 'z') sage: L.has_coerce_map_from(R) True sage: L(R(lambda n: n)) - z + z^3 + z^5 + O(z^7) + z + z^3 + z^5 + z^7 + O(z^8) sage: L(R([2,4,6])) == L.zero() True sage: L(R([2,4,6], valuation=2, constant=4)) == L.zero() @@ -329,6 +345,28 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No ... ValueError: unable to convert ... + Converting from the corresponding rational functions:: + + sage: L = LazyLaurentSeriesRing(QQ, 't') + sage: tt = L.gen() + sage: R.<t> = LaurentPolynomialRing(QQ) + sage: f = (1 + t) / (1 + t + t^2); f + (t + 1)/(t^2 + t + 1) + sage: f.parent() + Fraction Field of Univariate Polynomial Ring in t over Rational Field + sage: L(f) + 1 - t^2 + t^3 - t^5 + t^6 + O(t^7) + sage: L(f) == (1 + tt) / (1 + tt + tt^2) + True + sage: f = (3 + t) / (t^3 - t^5); f + (-t - 3)/(t^5 - t^3) + sage: f.parent() + Fraction Field of Univariate Polynomial Ring in t over Rational Field + sage: L(f) + 3*t^-3 + t^-2 + 3*t^-1 + 1 + 3*t + t^2 + 3*t^3 + O(t^4) + sage: L(f) - (3 + tt) / (tt^3 - tt^5) + O(t^4) + TESTS: Checking the valuation is consistent:: @@ -379,7 +417,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: D = LazyDirichletSeriesRing(ZZ, "s") sage: E = LazyDirichletSeriesRing(QQ, "t") - sage: D(E([1,2,3])) + sage: D(E([1,2,3])) # needs sage.symbolic 1 + 2/2^s + 3/3^s This gives zero:: @@ -467,7 +505,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No if valuation is None: raise ValueError("you must specify the degree for the polynomial 0") degree = valuation - if x == R.zero(): + if not x: coeff_stream = Stream_exact([], order=degree, constant=constant) return self.element_class(self, coeff_stream) initial_coefficients = [x[i] for i in range(x.valuation(), x.degree() + 1)] @@ -543,6 +581,15 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No return self.element_class(self, stream) raise ValueError(f"unable to convert {x} into {self}") + # Check if we can realize the input as a rational function + try: + FF = self._laurent_poly_ring.fraction_field() + x = FF(x) + except (TypeError, ValueError, AttributeError): + pass + else: + return self(x.numerator()) / self(x.denominator()) + else: x = coefficients @@ -631,6 +678,7 @@ class options(GlobalOptions): - constant_length: 3 - display_length: 7 - halting_precision: None + - secure: False sage: LLS.options.display_length 7 @@ -664,8 +712,11 @@ class options(GlobalOptions): description='the number of coefficients to display for nonzero constant series', checker=lambda x: x in ZZ and x > 0) halting_precision = dict(default=None, - description='the number of coefficients, beginning with the approximate valuation, to check in equality tests', - checker=lambda x: x is None or x in ZZ and x > 0) + description='the number of coefficients, beginning with the approximate valuation, to check in equality tests', + checker=lambda x: x is None or x in ZZ and x > 0) + secure = dict(default=False, + description='whether to raise an error when a comparison is unknown', + checker=lambda x: x is True or x is False) @cached_method def one(self): @@ -682,9 +733,9 @@ def one(self): sage: L.one() 1 - sage: m = SymmetricFunctions(ZZ).m() - sage: L = LazySymmetricFunctions(m) - sage: L.one() + sage: m = SymmetricFunctions(ZZ).m() # needs sage.modules + sage: L = LazySymmetricFunctions(m) # needs sage.modules + sage: L.one() # needs sage.modules m[] """ @@ -703,9 +754,9 @@ def zero(self): sage: L.zero() 0 - sage: s = SymmetricFunctions(ZZ).s() - sage: L = LazySymmetricFunctions(s) - sage: L.zero() + sage: s = SymmetricFunctions(ZZ).s() # needs sage.modules + sage: L = LazySymmetricFunctions(s) # needs sage.modules + sage: L.zero() # needs sage.modules 0 sage: L = LazyDirichletSeriesRing(ZZ, 'z') @@ -777,6 +828,7 @@ def _coerce_map_from_(self, S): sage: L.has_coerce_map_from(GF(2)) True + sage: # needs sage.modules sage.rings.finite_rings sage: s = SymmetricFunctions(GF(2)).s() sage: L = LazySymmetricFunctions(s) sage: L.has_coerce_map_from(ZZ) @@ -814,11 +866,14 @@ def _coerce_map_from_base_ring(self): sage: L = LazyDirichletSeriesRing(QQ, 'z') sage: phi = L._coerce_map_from_base_ring() - sage: phi(2) + sage: m = phi(2) + sage: m # needs sage.symbolic 2 - sage: phi(2, valuation=2) + sage: m = phi(2, valuation=2) + sage: m # needs sage.symbolic 2/2^z - sage: phi(2, valuation=2, constant=4) + sage: m = phi(2, valuation=2, constant=4) + sage: m # needs sage.symbolic 2/2^z + 4/3^z + 4/4^z + 4/5^z + O(1/(6^z)) """ # Return a DefaultConvertMap_unique; this can pass additional @@ -857,6 +912,193 @@ def is_exact(self): """ return self.base_ring().is_exact() + def prod(self, f, a=None, b=infinity, add_one=False): + r""" + The product of elements of ``self``. + + INPUT: + + - ``f`` -- a list (or iterable) of elements of ``self`` + - ``a``, ``b`` -- optional arguments + - ``add_one`` -- (default: ``False``); if ``True``, then converts a + lazy series `p_i` from ``args`` into `1 + p_i` for the product + + If ``a`` and ``b`` are both integers, then this returns the product + `\prod_{i=a}^b f(i)`, where `f(i) = p_i` if ``add_one=False`` or + `f(i) = 1 + p_i` otherwise. If ``b`` is not specified, then we consider + `b = \infty`. Note this corresponds to the Python ``range(a, b+1)``. + + If `a` is any other iterable, then this returns the product + `\prod_{i \in a} f(i)`, where `f(i) = p_i` if ``add_one=False`` or + `f(i) = 1 + p_i`. + + .. NOTE:: + + For infinite products, it is faster to use ``add_one=True`` since + the implementation is based on `p_i` in `\prod_i (1 + p_i)`. + + .. WARNING:: + + When ``f`` is an infinite generator, then the first argument + ``a`` must be ``True``. Otherwise this will loop forever. + + .. WARNING:: + + For an *infinite* product of the form `\prod_i (1 + p_i)`, + if `p_i = 0`, then this will loop forever. + + EXAMPLES:: + + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: euler = L.prod(lambda n: 1 - t^n, PositiveIntegers()) + sage: euler + 1 - t - t^2 + t^5 + O(t^7) + sage: 1 / euler + 1 + t + 2*t^2 + 3*t^3 + 5*t^4 + 7*t^5 + 11*t^6 + O(t^7) + sage: euler - L.euler() + O(t^7) + sage: L.prod(lambda n: -t^n, 1, add_one=True) + 1 - t - t^2 + t^5 + O(t^7) + + sage: L.prod((1 - t^n for n in PositiveIntegers()), True) + 1 - t - t^2 + t^5 + O(t^7) + sage: L.prod((-t^n for n in PositiveIntegers()), True, add_one=True) + 1 - t - t^2 + t^5 + O(t^7) + + sage: L.prod((1 + t^(n-3) for n in PositiveIntegers()), True) + 2*t^-3 + 4*t^-2 + 4*t^-1 + 4 + 6*t + 10*t^2 + 16*t^3 + O(t^4) + + sage: L.prod(lambda n: 2 + t^n, -3, 5) + 96*t^-6 + 240*t^-5 + 336*t^-4 + 840*t^-3 + 984*t^-2 + 1248*t^-1 + + 1980 + 1668*t + 1824*t^2 + 1872*t^3 + 1782*t^4 + 1710*t^5 + + 1314*t^6 + 1122*t^7 + 858*t^8 + 711*t^9 + 438*t^10 + 282*t^11 + + 210*t^12 + 84*t^13 + 60*t^14 + 24*t^15 + sage: L.prod(lambda n: t^n / (1 + abs(n)), -2, 2, add_one=True) + 1/3*t^-3 + 5/6*t^-2 + 13/9*t^-1 + 25/9 + 13/9*t + 5/6*t^2 + 1/3*t^3 + sage: L.prod(lambda n: t^-2 + t^n / n, -4, -2) + 1/24*t^-9 - 1/8*t^-8 - 1/6*t^-7 + 1/2*t^-6 + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: D.prod(lambda p: (1+D(1, valuation=p)).inverse(), Primes()) + 1 - 1/(2^s) - 1/(3^s) + 1/(4^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(8^s)) + + sage: D.prod(lambda p: D(1, valuation=p), Primes(), add_one=True) + 1 + 1/(2^s) + 1/(3^s) + 1/(5^s) + 1/(6^s) + 1/(7^s) + O(1/(8^s)) + """ + if a is None: + if add_one: + return super().prod(self.one() + g for g in f) + return super().prod(f) + + if a is True: + it = f + elif a in ZZ: + if b != infinity: + if add_one: + return super().prod(self.one() + f(i) for i in range(a, b+1)) + return super().prod(f(i) for i in range(a, b+1)) + from sage.sets.non_negative_integers import NonNegativeIntegers + it = (f(i+a) for i in NonNegativeIntegers()) + else: + it = (f(i) for i in a) + + # NOTE: We must have a new variable name for each new iterator + if not add_one: + data = (g - self.one() for g in it) + else: + data = it + + from sage.data_structures.stream import Stream_infinite_product + coeff_stream = Stream_infinite_product(data) + return self.element_class(self, coeff_stream) + + def sum(self, f, a=None, b=infinity): + r""" + The sum of elements of ``self``. + + INPUT: + + - ``f`` -- a list (or iterable or function) of elements of ``self`` + - ``a``, ``b`` -- optional arguments + + If ``a`` and ``b`` are both integers, then this returns the sum + `\sum_{i=a}^b f(i)`. If ``b`` is not specified, then we consider + `b = \infty`. Note this corresponds to the Python ``range(a, b+1)``. + + If `a` is any other iterable, then this returns the sum + `\sum{i \in a} f(i)`. + + .. WARNING:: + + When ``f`` is an infinite generator, then the first argument + ``a`` must be ``True``. Otherwise this will loop forever. + + .. WARNING:: + + For an *infinite* sum of the form `\sum_i s_i`, + if `s_i = 0`, then this will loop forever. + + EXAMPLES:: + + sage: L.<t> = LazyLaurentSeriesRing(QQ) + sage: L.sum(lambda n: t^n / (n+1), PositiveIntegers()) + 1/2*t + 1/3*t^2 + 1/4*t^3 + 1/5*t^4 + 1/6*t^5 + 1/7*t^6 + 1/8*t^7 + O(t^8) + + sage: L.<z> = LazyPowerSeriesRing(QQ) + sage: T = L.undefined(1) + sage: D = L.undefined(0) + sage: H = L.sum(lambda k: T(z^k)/k, 2) + sage: T.define(z*exp(T)*D) + sage: D.define(exp(H)) + sage: T + z + z^2 + 2*z^3 + 4*z^4 + 9*z^5 + 20*z^6 + 48*z^7 + O(z^8) + sage: D + 1 + 1/2*z^2 + 1/3*z^3 + 7/8*z^4 + 11/30*z^5 + 281/144*z^6 + O(z^7) + + We verify the Rogers-Ramanujan identities up to degree 100:: + + sage: L.<q> = LazyPowerSeriesRing(QQ) + sage: Gpi = L.prod(lambda k: -q^(1+5*k), 0, oo, add_one=True) + sage: Gpi *= L.prod(lambda k: -q^(4+5*k), 0, oo, add_one=True) + sage: Gp = 1 / Gpi + sage: G = L.sum(lambda n: q^(n^2) / prod(1 - q^(k+1) for k in range(n)), 0, oo) + sage: G - Gp + O(q^7) + sage: all(G[k] == Gp[k] for k in range(100)) + True + + sage: Hpi = L.prod(lambda k: -q^(2+5*k), 0, oo, add_one=True) + sage: Hpi *= L.prod(lambda k: -q^(3+5*k), 0, oo, add_one=True) + sage: Hp = 1 / Hpi + sage: H = L.sum(lambda n: q^(n^2+n) / prod(1 - q^(k+1) for k in range(n)), 0, oo) + sage: H - Hp + O(q^7) + sage: all(H[k] == Hp[k] for k in range(100)) + True + + :: + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: D.sum(lambda p: D(1, valuation=p), Primes()) + 1/(2^s) + 1/(3^s) + 1/(5^s) + 1/(7^s) + O(1/(9^s)) + """ + if a is None: + return super().sum(f) + + if a is True: + it = f + elif a in ZZ: + if b != infinity: + return super().sum(f(i) for i in range(a, b+1)) + from sage.sets.non_negative_integers import NonNegativeIntegers + it = (f(i+a) for i in NonNegativeIntegers()) + else: + it = (f(i) for i in a) + + from sage.data_structures.stream import Stream_infinite_sum + coeff_stream = Stream_infinite_sum(it) + return self.element_class(self, coeff_stream) + def _test_invert(self, **options): """ Test multiplicative inversion of elements of ``self``. @@ -986,7 +1228,7 @@ def _test_revert(self, **options): count += 1 e1 = y(x) e2 = x(y) - tester.assertEqual(e1, e2, "y(x) and x(y) differ for x = %s and y = %s" %(x, y)) + tester.assertEqual(e1, e2, "y(x) and x(y) differ for x = %s and y = %s" % (x, y)) # tester.assertEqual(e1, self.gen()) # we want to test at least 2 elements tester.assertGreater(count, 1, msg="only %s elements in %s.some_elements() have a compositional inverse" % (count, self)) @@ -1017,6 +1259,7 @@ class LazyLaurentSeriesRing(LazySeriesRing): Lazy Laurent series ring over a finite field:: + sage: # needs sage.rings.finite_rings sage: L.<z> = LazyLaurentSeriesRing(GF(3)); L Lazy Laurent Series Ring in z over Finite Field of size 3 sage: e = 1 / (1 + z) @@ -1106,12 +1349,59 @@ class LazyLaurentSeriesRing(LazySeriesRing): sage: s 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + O(z^7) - If the series is not specified by a finite number of initial - coefficients and a constant for the remaining coefficients, then - equality checking will depend on the coefficients which have - already been computed. If this information is not enough to - check that two series are different we raise an error:: + By default, any two series ``f`` and ``g`` that are not known to + be equal are considered to be different:: + + sage: f = L(lambda n: 0, valuation=0) + sage: f == 0 + False + + sage: f = L(constant=1, valuation=0).derivative(); f + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + sage: g = L(lambda n: (n+1), valuation=0); g + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + sage: f == g + False + + .. WARNING:: + We have imposed that ``(f == g) == not (f != g)``, and so + ``f != g`` returning ``True`` might not mean that the two + series are actually different:: + + sage: f = L(lambda n: 0, valuation=0) + sage: g = L.zero() + sage: f != g + True + + This can be verified by :meth:`~sage.rings.lazy_series.is_nonzero()`, + which only returns ``True`` if the series is known to be nonzero:: + + sage: (f - g).is_nonzero() + False + + The implementation of the ring can be either be a sparse or a dense one. + The default is a sparse implementation:: + + sage: L.<z> = LazyLaurentSeriesRing(ZZ) + sage: L.is_sparse() + True + sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: L.is_sparse() + False + + We additionally provide two other methods of performing comparisons. + The first is raising a ``ValueError`` and the second uses a check + up to a (user set) finite precision. These behaviors are set using the + options ``secure`` and ``halting_precision``. In particular, + this applies to series that are not specified by a finite number + of initial coefficients and a constant for the remaining coefficients. + Equality checking will depend on the coefficients which have + already been computed. If this information is not enough to + check that two series are different, then if ``L.options.secure`` + is set to ``True``, then we raise a ``ValueError``:: + + sage: L.options.secure = True sage: f = 1 / (z + z^2); f z^-1 - 1 + z - z^2 + z^3 - z^4 + z^5 + O(z^6) sage: f2 = f * 2 # currently no coefficients computed @@ -1126,16 +1416,45 @@ class LazyLaurentSeriesRing(LazySeriesRing): 3*z^-1 - 3 + 3*z - 3*z^2 + 3*z^3 - 3*z^4 + 3*z^5 + O(z^6) sage: f2 == f3 False + sage: f2a = f + f + sage: f2 == f2a + Traceback (most recent call last): + ... + ValueError: undecidable + sage: zf = L(lambda n: 0, valuation=0) + sage: zf == 0 + Traceback (most recent call last): + ... + ValueError: undecidable - The implementation of the ring can be either be a sparse or a dense one. - The default is a sparse implementation:: + For boolean checks, an error is raised when it is not known to be nonzero:: - sage: L.<z> = LazyLaurentSeriesRing(ZZ) - sage: L.is_sparse() - True - sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: L.is_sparse() + sage: bool(zf) + Traceback (most recent call last): + ... + ValueError: undecidable + + If the halting precision is set to a finite number `p` (for unlimited + precision, it is set to ``None``), then it will check up to `p` values + from the current position:: + + sage: L.options.halting_precision = 20 + sage: f2 = f * 2 # currently no coefficients computed + sage: f3 = f * 3 # currently no coefficients computed + sage: f2 == f3 False + sage: f2a = f + f + sage: f2 == f2a + True + sage: zf = L(lambda n: 0, valuation=0) + sage: zf == 0 + True + + TESTS: + + We reset the options:: + + sage: L.options._reset() """ Element = LazyLaurentSeries @@ -1164,7 +1483,7 @@ def __init__(self, base_ring, names, sparse=True, category=None): and Category of infinite sets sage: L = LazyLaurentSeriesRing(ZZ['x, y'], 't') - sage: TestSuite(L).run() + sage: TestSuite(L).run() # needs sage.libs.singular sage: L.category() Category of infinite commutative no zero divisors algebras over (unique factorization domains and commutative algebras over @@ -1187,8 +1506,8 @@ def __init__(self, base_ring, names, sparse=True, category=None): (finite commutative rings and subquotients of monoids and quotients of semigroups and finite enumerated sets) - sage: E.<x,y> = ExteriorAlgebra(QQ) - sage: L = LazyLaurentSeriesRing(E, 't') # not tested + sage: E.<x,y> = ExteriorAlgebra(QQ) # needs sage.modules + sage: L = LazyLaurentSeriesRing(E, 't') # not tested # needs sage.modules sage: LazyLaurentSeriesRing.options._reset() # reset the options """ @@ -1475,7 +1794,6 @@ def residue_field(self): # === special functions === - def q_pochhammer(self, q=None): r""" Return the infinite ``q``-Pochhammer symbol `(a; q)_{\infty}`, @@ -1527,7 +1845,7 @@ def q_pochhammer(self, q=None): sage: R = ZZ['q'].fraction_field() sage: q = R.gen() sage: L.<z> = LazyLaurentSeriesRing(LazyDirichletSeriesRing(R, "s")) - sage: z.q_pochhammer(q) + sage: z.q_pochhammer(q) # needs sage.symbolic 1 + ((1/(q-1)))*z + ((q/(q^3-q^2-q+1)))*z^2 + ... + O(z^7) REFERENCES: @@ -1571,13 +1889,13 @@ def euler(self): sage: P = 1 / phi; P 1 + q + 2*q^2 + 3*q^3 + 5*q^4 + 7*q^5 + 11*q^6 + O(q^7) - sage: P[:20] == [Partitions(n).cardinality() for n in range(20)] + sage: P[:20] == [Partitions(n).cardinality() for n in range(20)] # needs sage.libs.flint True TESTS:: sage: L.<q> = LazyLaurentSeriesRing(LazyDirichletSeriesRing(QQ, "s")) - sage: q.euler() + sage: q.euler() # needs sage.symbolic 1 - q - q^2 + q^5 + O(q^7) REFERENCES: @@ -1853,7 +2171,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: X.valuation() 2 - sage: e = L(lambda n: n+1); e + sage: e = L(lambda n: n + 1); e 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) sage: f = e^-1; f 1 - 2*z + z^2 + O(z^7) @@ -1879,7 +2197,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: g = L([1,3,5,7,9], 5, -1); g z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) - Finally, ``x`` can be a polynomial:: + Additionally, ``x`` can be a polynomial:: sage: P.<x> = QQ[] sage: p = x + 3*x^2 + x^5 @@ -1896,6 +2214,22 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: L(p) x + (x*y+y^2) + Finally ``x`` can be in the corresponding fraction field:: + + sage: R.<a,b,c> = PolynomialRing(ZZ) + sage: L = LazyPowerSeriesRing(ZZ, 'a,b,c') + sage: aa, bb, cc = L.gens() + sage: f = (1 + a + b) / (1 + a*b + c^3); f + (a + b + 1)/(c^3 + a*b + 1) + sage: f.parent() + Fraction Field of Multivariate Polynomial Ring in a, b, c over Integer Ring + sage: L(f) # needs sage.libs.singular + 1 + (a+b) + (-a*b) + (-a^2*b-a*b^2-c^3) + (a^2*b^2-a*c^3-b*c^3) + + (a^3*b^2+a^2*b^3+2*a*b*c^3) + (-a^3*b^3+2*a^2*b*c^3+2*a*b^2*c^3+c^6) + + O(a,b,c)^7 + sage: L(f) == (1 + aa + bb) / (1 + aa*bb + cc^3) # needs sage.libs.singular + True + TESTS:: sage: L.<x,y> = LazyPowerSeriesRing(ZZ) @@ -2003,6 +2337,15 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No valuation=valuation) return self.element_class(self, stream) + # Check if we can realize the input as a rational function + try: + FF = self._laurent_poly_ring.fraction_field() + x = FF(x) + except (TypeError, ValueError, AttributeError): + pass + else: + return self(x.numerator()) / self(x.denominator()) + if callable(x) or isinstance(x, (GeneratorType, map, filter)): if valuation is None: valuation = 0 @@ -2180,17 +2523,16 @@ class LazyCompletionGradedAlgebra(LazySeriesRing): EXAMPLES:: + sage: # needs sage.modules sage: NCSF = NonCommutativeSymmetricFunctions(QQ) sage: S = NCSF.Complete() - sage: L = S.formal_series_ring() - sage: L - Lazy completion of Non-Commutative Symmetric Functions over the Rational Field in the Complete basis - - sage: f = 1 / (1 - L(S[1])) - sage: f - S[] + S[1] + (S[1,1]) + (S[1,1,1]) + (S[1,1,1,1]) + (S[1,1,1,1,1]) + (S[1,1,1,1,1,1]) + O^7 - sage: g = 1 / (1 - L(S[2])) - sage: g + sage: L = S.formal_series_ring(); L + Lazy completion of Non-Commutative Symmetric Functions + over the Rational Field in the Complete basis + sage: f = 1 / (1 - L(S[1])); f + S[] + S[1] + (S[1,1]) + (S[1,1,1]) + (S[1,1,1,1]) + (S[1,1,1,1,1]) + + (S[1,1,1,1,1,1]) + O^7 + sage: g = 1 / (1 - L(S[2])); g S[] + S[2] + (S[2,2]) + (S[2,2,2]) + O^7 sage: f * g S[] + S[1] + (S[1,1]+S[2]) + (S[1,1,1]+S[1,2]) @@ -2215,23 +2557,23 @@ def __init__(self, basis, sparse=True, category=None): sage: LazySymmetricFunctions.options.halting_precision(6) + sage: # needs sage.modules sage: s = SymmetricFunctions(QQ).s() sage: L = LazySymmetricFunctions(s) - sage: TestSuite(L).run() - + sage: TestSuite(L).run() # needs lrcalc_python sage: p = SymmetricFunctions(GF(5)).p() sage: L = LazySymmetricFunctions(p) sage: TestSuite(L).run() Reversion will only work when the base ring is a field:: + sage: # needs sage.modules sage: s = SymmetricFunctions(ZZ).s() sage: L = LazySymmetricFunctions(s) - sage: TestSuite(L).run(skip=['_test_revert']) - + sage: TestSuite(L).run(skip=['_test_revert']) # needs lrcalc_python sage: s = SymmetricFunctions(QQ["q"]).s() sage: L = LazySymmetricFunctions(s) - sage: TestSuite(L).run(skip=['_test_revert']) + sage: TestSuite(L).run(skip=['_test_revert']) # needs lrcalc_python Options are remembered across doctests:: @@ -2240,15 +2582,15 @@ def __init__(self, basis, sparse=True, category=None): Check that :trac:`34470` is fixed. The ideal generated by `p[1]` and `p[2]` is not principal:: - sage: p = SymmetricFunctions(QQ).p() - sage: L = LazySymmetricFunctions(s) - sage: L in PrincipalIdealDomains + sage: p = SymmetricFunctions(QQ).p() # needs sage.modules + sage: L = LazySymmetricFunctions(s) # needs sage.modules + sage: L in PrincipalIdealDomains # needs sage.modules False Check that a basis which is not graded is not enough:: - sage: ht = SymmetricFunctions(ZZ).ht() - sage: L = LazySymmetricFunctions(ht) + sage: ht = SymmetricFunctions(ZZ).ht() # needs sage.modules + sage: L = LazySymmetricFunctions(ht) # needs sage.modules Traceback (most recent call last): ... ValueError: basis should be in GradedAlgebrasWithBasis @@ -2262,10 +2604,10 @@ def __init__(self, basis, sparse=True, category=None): if basis not in GradedAlgebrasWithBasis: raise ValueError("basis should be in GradedAlgebrasWithBasis") self._arity = 1 - category = Algebras(base_ring.category()) - if base_ring in IntegralDomains(): + category = Algebras(basis.category()) + if basis in IntegralDomains(): category &= IntegralDomains() - elif base_ring in Rings().Commutative(): + elif basis in Rings().Commutative(): category = category.Commutative() if base_ring.is_zero(): @@ -2287,8 +2629,8 @@ def _repr_(self): EXAMPLES:: - sage: s = SymmetricFunctions(GF(2)).s() - sage: LazySymmetricFunctions(s) + sage: s = SymmetricFunctions(GF(2)).s() # needs sage.modules + sage: LazySymmetricFunctions(s) # needs sage.modules Lazy completion of Symmetric Functions over Finite Field of size 2 in the Schur basis """ return "Lazy completion of {}".format(self._laurent_poly_ring) @@ -2299,9 +2641,9 @@ def _latex_(self): EXAMPLES:: - sage: s = SymmetricFunctions(GF(2)).s() - sage: L = LazySymmetricFunctions(s) - sage: latex(L) + sage: s = SymmetricFunctions(GF(2)).s() # needs sage.modules + sage: L = LazySymmetricFunctions(s) # needs sage.modules + sage: latex(L) # needs sage.modules \text{\texttt{Symmetric{ }Functions{ }over{ }Finite{ }Field{ }of{ }size{ }2{ }in{ }the{ }Schur{ }basis}} """ from sage.misc.latex import latex @@ -2313,6 +2655,7 @@ def _monomial(self, c, n): EXAMPLES:: + sage: # needs sage.modules sage: m = SymmetricFunctions(ZZ).m() sage: s = SymmetricFunctions(ZZ).s() sage: L = LazySymmetricFunctions(m) @@ -2338,6 +2681,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No EXAMPLES:: + sage: # needs sage.modules sage: m = SymmetricFunctions(GF(2)).m() sage: L = LazySymmetricFunctions(m) sage: L(2) @@ -2345,11 +2689,11 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: L(3) m[] + sage: # needs sage.modules sage: m = SymmetricFunctions(ZZ).m() sage: L = LazySymmetricFunctions(m) sage: f = L(lambda i: m([i]), valuation=5, degree=10); f m[5] + m[6] + m[7] + m[8] + m[9] - sage: f.coefficient(6) m[6] sage: f[20] @@ -2359,11 +2703,12 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No Then these elements are read as coefficients of the terms of degrees starting from the ``valuation``:: - sage: f = L([m[1],m[2],m[3]], valuation=1); f + sage: f = L([m[1],m[2],m[3]], valuation=1); f # needs sage.modules m[1] + m[2] + m[3] Finally, ``x`` can be a symmetric function:: + sage: # needs sage.modules sage: m = SymmetricFunctions(ZZ).m() sage: s = SymmetricFunctions(ZZ).s() sage: L = LazySymmetricFunctions(m) @@ -2372,29 +2717,31 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No TESTS:: + sage: # needs sage.modules sage: e = SymmetricFunctions(ZZ).e() sage: h = SymmetricFunctions(ZZ).h() sage: L = LazySymmetricFunctions(tensor([h, e])) sage: L(lambda n: 0) O^7 + sage: # needs sage.modules sage: L(lambda n: tensor([h[n], e([])]) + tensor([h([]), e[n]]), degree=3) (2*h[]#e[]) + (h[]#e[1]+h[1]#e[]) + (h[]#e[2]+h[2]#e[]) - sage: L(lambda n: n)[3]; Traceback (most recent call last): ... - ValueError: coefficient 3*h[] # e[] should be an element of homogeneous degree 3 but has degree 0 - + ValueError: coefficient 3*h[] # e[] should be an element + of homogeneous degree 3 but has degree 0 sage: L([1, 2, 3]); Traceback (most recent call last): ... - ValueError: coefficient 2*h[] # e[] should be an element of homogeneous degree 1 but has degree 0 - + ValueError: coefficient 2*h[] # e[] should be an element + of homogeneous degree 1 but has degree 0 sage: L(lambda n: n, degree=3); Traceback (most recent call last): ... - ValueError: coefficient h[] # e[] should be an element of homogeneous degree 1 but has degree 0 + ValueError: coefficient h[] # e[] should be an element + of homogeneous degree 1 but has degree 0 """ if valuation is None: valuation = 0 @@ -2509,9 +2856,9 @@ def _an_element_(self): EXAMPLES:: - sage: m = SymmetricFunctions(ZZ).m() - sage: L = LazySymmetricFunctions(m) - sage: L.an_element() + sage: m = SymmetricFunctions(ZZ).m() # needs sage.modules + sage: L = LazySymmetricFunctions(m) # needs sage.modules + sage: L.an_element() # needs sage.modules 2*m[] + 2*m[1] + 3*m[2] """ return self(self._laurent_poly_ring.an_element()) @@ -2522,9 +2869,9 @@ def some_elements(self): EXAMPLES:: - sage: m = SymmetricFunctions(GF(5)).m() - sage: L = LazySymmetricFunctions(m) - sage: L.some_elements()[:5] + sage: m = SymmetricFunctions(GF(5)).m() # needs sage.modules + sage: L = LazySymmetricFunctions(m) # needs sage.modules + sage: L.some_elements()[:5] # needs sage.modules [0, m[], 2*m[] + 2*m[1] + 3*m[2], 2*m[1] + 3*m[2], 3*m[] + 2*m[1] + (m[1,1]+m[2]) + (2*m[1,1,1]+m[3]) @@ -2533,6 +2880,7 @@ def some_elements(self): + (2*m[2,2,1,1]+m[2,2,2]+2*m[3,2,1]+2*m[3,3]+m[4,1,1]+3*m[4,2]+4*m[5,1]+4*m[6]) + O^7] + sage: # needs sage.modules sage: NCSF = NonCommutativeSymmetricFunctions(QQ) sage: S = NCSF.Complete() sage: L = S.formal_series_ring() @@ -2575,13 +2923,15 @@ class LazySymmetricFunctions(LazyCompletionGradedAlgebra): EXAMPLES:: - sage: s = SymmetricFunctions(ZZ).s() - sage: LazySymmetricFunctions(s) + sage: s = SymmetricFunctions(ZZ).s() # needs sage.modules + sage: LazySymmetricFunctions(s) # needs sage.modules Lazy completion of Symmetric Functions over Integer Ring in the Schur basis - sage: m = SymmetricFunctions(ZZ).m() - sage: LazySymmetricFunctions(tensor([s, m])) - Lazy completion of Symmetric Functions over Integer Ring in the Schur basis # Symmetric Functions over Integer Ring in the monomial basis + sage: m = SymmetricFunctions(ZZ).m() # needs sage.modules + sage: LazySymmetricFunctions(tensor([s, m])) # needs sage.modules + Lazy completion of + Symmetric Functions over Integer Ring in the Schur basis + # Symmetric Functions over Integer Ring in the monomial basis """ Element = LazySymmetricFunction @@ -2655,6 +3005,24 @@ class LazyDirichletSeriesRing(LazySeriesRing): # Follow the "generic" normalization __classcall_private__ = LazySeriesRing.__classcall_private__ + @lazy_attribute + def _laurent_poly_ring(self): + r""" + Return the symbolic ring. + + .. TODO:: + + It would be good to have something better than the symbolic ring. + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, 't') + sage: L._laurent_poly_ring is SR # needs sage.symbolic + True + """ + from sage.symbolic.ring import SR + return SR + def __init__(self, base_ring, names, sparse=True, category=None): r""" Initialize the ring. @@ -2664,10 +3032,10 @@ def __init__(self, base_ring, names, sparse=True, category=None): sage: LazyDirichletSeriesRing.options.halting_precision(12) sage: L = LazyDirichletSeriesRing(ZZ, 't') - sage: TestSuite(L).run() + sage: TestSuite(L).run() # needs sage.symbolic sage: L = LazyDirichletSeriesRing(QQ, 't') - sage: TestSuite(L).run() + sage: TestSuite(L).run() # needs sage.symbolic sage: LazyDirichletSeriesRing.options._reset() # reset the options @@ -2678,7 +3046,6 @@ def __init__(self, base_ring, names, sparse=True, category=None): self._sparse = sparse self._minimal_valuation = 1 self._arity = 1 - self._laurent_poly_ring = SR # TODO: it would be good to have something better than the symbolic ring self._internal_poly_ring = PolynomialRing(base_ring, names, sparse=sparse) category = Algebras(base_ring.category()) @@ -2696,7 +3063,7 @@ def _repr_(self): EXAMPLES:: - sage: LazyDirichletSeriesRing(QQbar, 'z') + sage: LazyDirichletSeriesRing(QQbar, 'z') # needs sage.rings.number_field Lazy Dirichlet Series Ring in z over Algebraic Field """ return "Lazy Dirichlet Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) @@ -2709,9 +3076,9 @@ def one(self): EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L.one() + sage: L.one() # needs sage.symbolic 1 - sage: ~L.one() + sage: ~L.one() # needs sage.symbolic 1 + O(1/(8^z)) """ R = self.base_ring() @@ -2749,25 +3116,32 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L(3) + sage: R = L(3) + sage: R # needs sage.symbolic 3 - sage: L(lambda i: i, constant=1, degree=6) + sage: S = L(lambda i: i, constant=1, degree=6) + sage: S # needs sage.symbolic 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 1/(6^z) + 1/(7^z) + 1/(8^z) + O(1/(9^z)) - sage: X = L(constant=5, degree=3); X + sage: X = L(constant=5, degree=3) + sage: X # needs sage.symbolic 5/3^z + 5/4^z + 5/5^z + O(1/(6^z)) - sage: X.valuation() + sage: X.valuation() # needs sage.symbolic log(3) - sage: e = L(moebius); e + sage: e = L(moebius) + sage: e # needs sage.symbolic 1 - 1/(2^z) - 1/(3^z) - 1/(5^z) + 1/(6^z) - 1/(7^z) + O(1/(8^z)) - sage: L([0], constant=1) + sage: T = L([0], constant=1) + sage: T # needs sage.symbolic 1/(2^z) + 1/(3^z) + 1/(4^z) + O(1/(5^z)) - sage: L(constant=1) + sage: U = L(constant=1) + sage: U # needs sage.symbolic 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) - sage: L(lambda i: i, valuation=3) + sage: V = L(lambda i: i, valuation=3) + sage: V # needs sage.symbolic 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + 8/8^z + 9/9^z + O(1/(10^z)) Alternatively, ``x`` can be a list of elements of the base ring. @@ -2776,10 +3150,13 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No may be just an element of the base ring instead of a tuple or can be simply omitted if it is zero:: - sage: f = L([1,2,3,4], 4); f + sage: f = L([1,2,3,4], 4) + sage: f # needs sage.symbolic 1/(4^z) + 2/5^z + 3/6^z + 4/7^z - sage: g = L([1,3,5,7,9], 6, constant=-1); g - 1/(6^z) + 3/7^z + 5/8^z + 7/9^z + 9/10^z - 1/(11^z) - 1/(12^z) - 1/(13^z) + O(1/(14^z)) + sage: g = L([1,3,5,7,9], 6, constant=-1) + sage: g # needs sage.symbolic + 1/(6^z) + 3/7^z + 5/8^z + 7/9^z + 9/10^z - 1/(11^z) - 1/(12^z) + - 1/(13^z) + O(1/(14^z)) TESTS:: @@ -2790,23 +3167,28 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: L.<z> = LazyLaurentSeriesRing(QQ) sage: D = LazyDirichletSeriesRing(QQ, 't') - sage: D(L.one()) + sage: d = D(L.one()) # needs sage.symbolic + sage: d # needs sage.symbolic 1 + 1/(2^t) + 1/(3^t) + 1/(4^t) + 1/(5^t) + 1/(6^t) + 1/(7^t) + O(1/(8^t)) sage: R.<z> = LaurentPolynomialRing(QQ) sage: D = LazyDirichletSeriesRing(QQ, 't') - sage: D(coefficients=z+z^2) + sage: dd = D(coefficients=z + z^2) + sage: dd # needs sage.symbolic 2 + 6/2^t + 12/3^t + 20/4^t + 30/5^t + 42/6^t + 56/7^t + O(1/(8^t)) sage: s = D(lambda n: n) - sage: D(s, valuation=2) + sage: d2 = D(s, valuation=2) # needs sage.symbolic + sage: d2 # needs sage.symbolic 1/(2^t) + 2/3^t + 3/4^t + 4/5^t + 5/6^t + 6/7^t + 7/8^t + O(1/(9^t)) sage: Ds = LazyDirichletSeriesRing(ZZ, 's') - sage: m = Ds(moebius, valuation=2); m + sage: m = Ds(moebius, valuation=2) + sage: m # needs sage.symbolic -1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(9^s)) sage: D = LazyDirichletSeriesRing(QQ, 't') - sage: D(m) + sage: dm = D(m) # needs sage.libs.pari + sage: dm # needs sage.libs.pari sage.symbolic -1/(2^t) - 1/(3^t) - 1/(5^t) + 1/(6^t) - 1/(7^t) + O(1/(9^t)) """ if isinstance(x, (list, tuple)): @@ -2851,7 +3233,8 @@ def _an_element_(self): EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L.an_element() + sage: m = L.an_element() + sage: m # needs sage.symbolic 1/(4^z) + 1/(5^z) + 1/(6^z) + O(1/(7^z)) """ c = self.base_ring().an_element() @@ -2864,7 +3247,8 @@ def some_elements(self): EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L.some_elements() + sage: l = L.some_elements() + sage: l # needs sage.symbolic [0, 1, 1/(4^z) + 1/(5^z) + 1/(6^z) + O(1/(7^z)), 1/(2^z) - 1/(3^z) + 2/4^z - 2/5^z + 3/6^z - 3/7^z + 4/8^z - 4/9^z, @@ -2872,7 +3256,8 @@ def some_elements(self): 1 + 4/2^z + 9/3^z + 16/4^z + 25/5^z + 36/6^z + 49/7^z + O(1/(8^z))] sage: L = LazyDirichletSeriesRing(QQ, 'z') - sage: L.some_elements() + sage: l = L.some_elements() + sage: l # needs sage.symbolic [0, 1, 1/2/4^z + 1/2/5^z + 1/2/6^z + O(1/(7^z)), 1/2 - 1/2/2^z + 2/3^z - 2/4^z + 1/(6^z) - 1/(7^z) + 42/8^z + 2/3/9^z, @@ -2894,7 +3279,7 @@ def _monomial(self, c, n): EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L._monomial(5, 3) + sage: m = L._monomial(5, 3); m # needs sage.symbolic 5/3^z """ try: @@ -2914,6 +3299,7 @@ def _skip_leading_zeros(iterator): sage: [x for x, _ in zip(_skip_leading_zeros(it), range(10))] [10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + sage: # needs sage.rings.finite_rings sage: it = map(GF(3), NN) sage: [x for x, _ in zip(it, range(10))] [0, 1, 2, 0, 1, 2, 0, 1, 2, 0] diff --git a/src/sage/rings/localization.py b/src/sage/rings/localization.py index 8d46e8f4475..20c090da681 100644 --- a/src/sage/rings/localization.py +++ b/src/sage/rings/localization.py @@ -9,6 +9,7 @@ EXAMPLES:: + sage: # needs sage.modules sage: LZ = Localization(ZZ, (5,11)) sage: m = matrix(LZ, [[5, 7], [0,11]]) sage: m.parent() @@ -34,14 +35,15 @@ sage: I = S.cartesian_product(S) sage: add_units = u + [q, q + 1] + [ui - uj for ui, uj in I if ui != uj] sage: add_units += [q*ui - uj for ui, uj in I if ui != uj] - sage: L = R.localization(tuple(add_units)); L + sage: L = R.localization(tuple(add_units)); L # needs sage.libs.pari Multivariate Polynomial Ring in u0, u1, u2, q over Integer Ring localized at - (q, q + 1, u2, u1, u1 - u2, u0, u0 - u2, u0 - u1, u2*q - u1, u2*q - u0, - u1*q - u2, u1*q - u0, u0*q - u2, u0*q - u1) + (q, q + 1, u2, u1, u1 - u2, u0, u0 - u2, u0 - u1, u2*q - u1, u2*q - u0, + u1*q - u2, u1*q - u0, u0*q - u2, u0*q - u1) Define the representation matrices (of one of the three dimensional irreducible representations):: - sage: m1 = matrix(L, [[u1, 0, 0],[0, u0, 0],[0, 0, u0]]) + sage: # needs sage.libs.pari sage.modules + sage: m1 = matrix(L, [[u1, 0, 0], [0, u0, 0], [0, 0, u0]]) sage: m2 = matrix(L, [[(u0*q - u0)/(u0 - u1), (u0*q - u1)/(u0 - u1), 0], ....: [(-u1*q + u0)/(u0 - u1), (-u1*q + u1)/(u0 - u1), 0], ....: [0, 0, -1]]) @@ -53,17 +55,18 @@ Check relations of the Ariki-Koike algebra:: + sage: # needs sage.libs.pari sage.modules sage: m1*m2*m1*m2 == m2*m1*m2*m1 True sage: m2*m3*m2 == m3*m2*m3 True sage: m1*m3 == m3*m1 True - sage: m1**3 -(u0+u1+u2)*m1**2 +(u0*u1+u0*u2+u1*u2)*m1 - u0*u1*u2 == 0 + sage: m1**3 - (u0+u1+u2)*m1**2 + (u0*u1+u0*u2+u1*u2)*m1 - u0*u1*u2 == 0 True - sage: m2**2 -(q-1)*m2 - q == 0 + sage: m2**2 - (q-1)*m2 - q == 0 True - sage: m3**2 -(q-1)*m3 - q == 0 + sage: m3**2 - (q-1)*m3 - q == 0 True sage: ~m1 in m1.parent() True @@ -74,83 +77,88 @@ Obtain specializations in positive characteristic:: + sage: # needs sage.libs.pari sage.modules sage: Fp = GF(17) sage: f = L.hom((3,5,7,11), codomain=Fp); f Ring morphism: From: Multivariate Polynomial Ring in u0, u1, u2, q over Integer Ring localized at - (q, q + 1, u2, u1, u1 - u2, u0, u0 - u2, u0 - u1, u2*q - u1, u2*q - u0, - u1*q - u2, u1*q - u0, u0*q - u2, u0*q - u1) + (q, q + 1, u2, u1, u1 - u2, u0, u0 - u2, u0 - u1, u2*q - u1, u2*q - u0, + u1*q - u2, u1*q - u0, u0*q - u2, u0*q - u1) To: Finite Field of size 17 Defn: u0 |--> 3 u1 |--> 5 u2 |--> 7 q |--> 11 - sage: mFp1 = matrix({k:f(v) for k, v in m1.dict().items()}); mFp1 + sage: mFp1 = matrix({k: f(v) for k, v in m1.dict().items()}); mFp1 [5 0 0] [0 3 0] [0 0 3] sage: mFp1.base_ring() Finite Field of size 17 - sage: mFp2 = matrix({k:f(v) for k, v in m2.dict().items()}); mFp2 + sage: mFp2 = matrix({k: f(v) for k, v in m2.dict().items()}); mFp2 [ 2 3 0] [ 9 8 0] [ 0 0 16] - sage: mFp3 = matrix({k:f(v) for k, v in m3.dict().items()}); mFp3 + sage: mFp3 = matrix({k: f(v) for k, v in m3.dict().items()}); mFp3 [16 0 0] [ 0 4 5] [ 0 7 6] Obtain specializations in characteristic 0:: + sage: # needs sage.libs.pari sage: fQ = L.hom((3,5,7,11), codomain=QQ); fQ Ring morphism: - From: Multivariate Polynomial Ring in u0, u1, u2, q over Integer Ring localized at - (q, q + 1, u2, u1, u1 - u2, u0, u0 - u2, u0 - u1, u2*q - u1, u2*q - u0, - u1*q - u2, u1*q - u0, u0*q - u2, u0*q - u1) + From: Multivariate Polynomial Ring in u0, u1, u2, q over Integer Ring + localized at (q, q + 1, u2, u1, u1 - u2, u0, u0 - u2, u0 - u1, + u2*q - u1, u2*q - u0, u1*q - u2, u1*q - u0, u0*q - u2, u0*q - u1) To: Rational Field Defn: u0 |--> 3 u1 |--> 5 u2 |--> 7 q |--> 11 - sage: mQ1 = matrix({k:fQ(v) for k, v in m1.dict().items()}); mQ1 + + sage: # needs sage.libs.pari sage.modules sage.rings.finite_rings + sage: mQ1 = matrix({k: fQ(v) for k, v in m1.dict().items()}); mQ1 [5 0 0] [0 3 0] [0 0 3] sage: mQ1.base_ring() Rational Field - sage: mQ2 = matrix({k:fQ(v) for k, v in m2.dict().items()}); mQ2 + sage: mQ2 = matrix({k: fQ(v) for k, v in m2.dict().items()}); mQ2 [-15 -14 0] [ 26 25 0] [ 0 0 -1] - sage: mQ3 = matrix({k:fQ(v) for k, v in m3.dict().items()}); mQ3 + sage: mQ3 = matrix({k: fQ(v) for k, v in m3.dict().items()}); mQ3 [ -1 0 0] [ 0 -15/26 11/26] [ 0 301/26 275/26] + sage: # needs sage.libs.pari sage.libs.singular sage: S.<x, y, z, t> = QQ[] - sage: T = S.quo(x+y+z) + sage: T = S.quo(x + y + z) sage: F = T.fraction_field() sage: fF = L.hom((x, y, z, t), codomain=F); fF Ring morphism: - From: Multivariate Polynomial Ring in u0, u1, u2, q over Integer Ring localized at - (q, q + 1, u2, u1, u1 - u2, u0, u0 - u2, u0 - u1, u2*q - u1, u2*q - u0, - u1*q - u2, u1*q - u0, u0*q - u2, u0*q - u1) - To: Fraction Field of Quotient of Multivariate Polynomial Ring in x, y, z, t over - Rational Field by the ideal (x + y + z) + From: Multivariate Polynomial Ring in u0, u1, u2, q over Integer Ring + localized at (q, q + 1, u2, u1, u1 - u2, u0, u0 - u2, u0 - u1, + u2*q - u1, u2*q - u0, u1*q - u2, u1*q - u0, u0*q - u2, u0*q - u1) + To: Fraction Field of Quotient of Multivariate Polynomial Ring in x, y, z, t + over Rational Field by the ideal (x + y + z) Defn: u0 |--> -ybar - zbar u1 |--> ybar u2 |--> zbar q |--> tbar - sage: mF1 = matrix({k:fF(v) for k, v in m1.dict().items()}); mF1 + sage: mF1 = matrix({k: fF(v) for k, v in m1.dict().items()}); mF1 # needs sage.modules [ ybar 0 0] [ 0 -ybar - zbar 0] [ 0 0 -ybar - zbar] - sage: mF1.base_ring() == F + sage: mF1.base_ring() == F # needs sage.modules True TESTS:: - sage: TestSuite(L).run() + sage: TestSuite(L).run() # needs sage.libs.pari sage.libs.singular sage.modules AUTHORS: @@ -199,21 +207,24 @@ def normalize_extra_units(base_ring, add_units, warning=True): sage: normalize_extra_units(ZZ, [3, -15, 45, 9, 2, 50]) [2, 3, 5] sage: P.<x,y,z> = ZZ[] - sage: normalize_extra_units(P, [3*x, z*y**2, 2*z, 18*(x*y*z)**2, x*z, 6*x*z, 5]) + sage: normalize_extra_units(P, # needs sage.libs.pari + ....: [3*x, z*y**2, 2*z, 18*(x*y*z)**2, x*z, 6*x*z, 5]) [2, 3, 5, z, y, x] sage: P.<x,y,z> = QQ[] - sage: normalize_extra_units(P, [3*x, z*y**2, 2*z, 18*(x*y*z)**2, x*z, 6*x*z, 5]) + sage: normalize_extra_units(P, # needs sage.libs.pari + ....: [3*x, z*y**2, 2*z, 18*(x*y*z)**2, x*z, 6*x*z, 5]) [z, y, x] + sage: # needs sage.libs.singular sage: R.<x, y> = ZZ[] - sage: Q.<a, b> = R.quo(x**2-5) - sage: p = b**2-5 + sage: Q.<a, b> = R.quo(x**2 - 5) + sage: p = b**2 - 5 sage: p == (b-a)*(b+a) True - sage: normalize_extra_units(Q, [p]) + sage: normalize_extra_units(Q, [p]) # needs sage.libs.pari doctest:...: UserWarning: Localization may not be represented uniquely [b^2 - 5] - sage: normalize_extra_units(Q, [p], warning=False) + sage: normalize_extra_units(Q, [p], warning=False) # needs sage.libs.pari [b^2 - 5] """ # convert to base ring @@ -250,13 +261,15 @@ class LocalizationElement(IntegralDomainElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.rings.localization import LocalizationElement sage: P.<x,y,z> = GF(5)[] - sage: L = P.localization((x, y*z-x)) + sage: L = P.localization((x, y*z - x)) sage: LocalizationElement(L, 4/(y*z-x)**2) (-1)/(y^2*z^2 - 2*x*y*z + x^2) sage: _.parent() - Multivariate Polynomial Ring in x, y, z over Finite Field of size 5 localized at (x, y*z - x) + Multivariate Polynomial Ring in x, y, z over Finite Field of size 5 + localized at (x, y*z - x) """ def __init__(self, parent, x): @@ -267,9 +280,9 @@ def __init__(self, parent, x): sage: from sage.rings.localization import LocalizationElement sage: P.<x> = RR[] - sage: L = Localization(P, x**2+x+1) - sage: l = LocalizationElement(L, (x**2+1)/(x**2+x+1)) - sage: l._value == (x**2+1)/(x**2+x+1) + sage: L = Localization(P, x**2 + x + 1) # needs sage.libs.pari + sage: l = LocalizationElement(L, (x**2+1)/(x**2+x+1)) # needs sage.libs.pari + sage: l._value == (x**2+1)/(x**2+x+1) # needs sage.libs.pari True """ IntegralDomainElement.__init__(self, parent) @@ -281,15 +294,16 @@ def _repr_(self): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: from sage.rings.localization import LocalizationElement sage: P.<x> = CC[] - sage: L = Localization(P, x**2+x+1) + sage: L = Localization(P, x**2 + x + 1) sage: l = LocalizationElement(L, (x**2+1)/(x**2+x+1)) sage: l._repr_() == str(l) True sage: R.<X, Y> = ZZ[] - sage: L.<x, y> = R.localization(X-Y) + sage: L.<x, y> = R.localization(X - Y) sage: x*y/(x-y) x*y/(x - y) """ @@ -389,10 +403,10 @@ def factor(self, proof=None): EXAMPLES:: sage: P.<X, Y> = QQ['x, y'] - sage: L = P.localization(X-Y) + sage: L = P.localization(X - Y) sage: x, y = L.gens() - sage: p = (x^2 - y^2)/(x-y)^2 - sage: p.factor() + sage: p = (x^2 - y^2)/(x-y)^2 # needs sage.libs.singular + sage: p.factor() # needs sage.libs.singular (1/(x - y)) * (x + y) """ num = self._value.numerator() @@ -411,9 +425,9 @@ def _im_gens_(self, codomain, im_gens, base_map=None): EXAMPLES:: sage: R.<x> = ZZ[] - sage: L = Localization(R, x**2+1) - sage: f = L.hom([5], codomain=Localization(ZZ, 26)) # indirect doctest - sage: f(x/(x**2+1)) + sage: L = Localization(R, x**2 + 1) # needs sage.libs.pari + sage: f = L.hom([5], codomain=Localization(ZZ, 26)) # indirect doctest # needs sage.libs.pari + sage: f(x/(x**2+1)) # needs sage.libs.pari 5/26 """ return self._value._im_gens_(codomain, im_gens, base_map=base_map) @@ -448,6 +462,7 @@ def is_unit(self): EXAMPLES:: + sage: # needs sage.libs.pari sage.singular sage: P.<x,y,z> = QQ[] sage: L = P.localization((x, y*z)) sage: L(y*z).is_unit() @@ -467,9 +482,9 @@ def inverse_of_unit(self): sage: P.<x,y,z> = ZZ[] sage: L = Localization(P, x*y*z) - sage: L(x*y*z).inverse_of_unit() + sage: L(x*y*z).inverse_of_unit() # needs sage.libs.singular 1/(x*y*z) - sage: L(z).inverse_of_unit() + sage: L(z).inverse_of_unit() # needs sage.libs.singular 1/z """ parent = self.parent() @@ -481,6 +496,7 @@ def _richcmp_(self, other, op): """ EXAMPLES:: + sage: # needs sage.libs.singular sage: P.<x,y,z> = GF(7)[] sage: L = Localization(P, (x, y, z)) sage: L(1/x) < L(3/(x*y*z)**3) @@ -519,7 +535,7 @@ def _rational_(self): sage: L = ZZ.localization(5) sage: cp3 = cyclotomic_polynomial(3).change_ring(L) - sage: cp3.splitting_field('t') # indirect doctest + sage: cp3.splitting_field('t') # indirect doctest # needs sage.libs.pari sage.rings.number_field Number Field in t with defining polynomial x^2 + x + 1 """ from sage.rings.rational_field import QQ @@ -601,13 +617,15 @@ class Localization(IntegralDomain, UniqueRepresentation): ... ValueError: factor 7 of denominator is not a unit - sage: Localization(Zp(7), (3, 5)) + sage: Localization(Zp(7), (3, 5)) # needs sage.rings.padics Traceback (most recent call last): ... - ValueError: all given elements are invertible in 7-adic Ring with capped relative precision 20 + ValueError: all given elements are invertible in + 7-adic Ring with capped relative precision 20 + sage: # needs sage.libs.pari sage: R.<x> = ZZ[] - sage: L = R.localization(x**2+1) + sage: L = R.localization(x**2 + 1) sage: s = (x+5)/(x**2+1) sage: s in L True @@ -633,9 +651,9 @@ class Localization(IntegralDomain, UniqueRepresentation): ... ValueError: factor x^2 + 2 of denominator is not a unit - sage: Lau.<u, v> = LaurentPolynomialRing(ZZ) - sage: LauL = Lau.localization(u+1) - sage: LauL(~u).parent() + sage: Lau.<u, v> = LaurentPolynomialRing(ZZ) # needs sage.modules + sage: LauL = Lau.localization(u + 1) # needs sage.modules + sage: LauL(~u).parent() # needs sage.modules Multivariate Polynomial Ring in u, v over Integer Ring localized at (v, u, u + 1) More examples will be shown typing ``sage.rings.localization?`` @@ -657,11 +675,11 @@ def __init__(self, base_ring, extra_units, names=None, normalize=True, category= TESTS:: - sage: L = Localization(ZZ, (3,5)) + sage: L = Localization(ZZ, (3, 5)) sage: TestSuite(L).run() sage: R.<x> = ZZ[] - sage: L = R.localization(x**2+1) + sage: L = R.localization(x**2 + 1) # needs sage.libs.pari sage: TestSuite(L).run() """ if type(extra_units) is tuple: @@ -669,8 +687,9 @@ def __init__(self, base_ring, extra_units, names=None, normalize=True, category= if not type(extra_units) is list: extra_units = [extra_units] - from sage.rings.polynomial.laurent_polynomial_ring import is_LaurentPolynomialRing - if is_LaurentPolynomialRing(base_ring): + from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic + + if isinstance(base_ring, LaurentPolynomialRing_generic): extra_units += list(base_ring.gens()) base_ring = base_ring.polynomial_ring() @@ -702,8 +721,9 @@ def _repr_(self): EXAMPLES:: sage: R.<a> = GF(3)[] - sage: Localization(R, a**2-1) - Univariate Polynomial Ring in a over Finite Field of size 3 localized at (a + 1, a + 2) + sage: Localization(R, a**2 - 1) # needs sage.libs.pari + Univariate Polynomial Ring in a over Finite Field of size 3 + localized at (a + 1, a + 2) """ return "%s localized at %s" % (self.base(), self._extra_units) @@ -732,21 +752,23 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): EXAMPLES:: sage: R.<x> = ZZ[] - sage: L = Localization(R, x**2+1) - sage: L.hom([5]) # indirect doctest + sage: L = Localization(R, x**2 + 1) # needs sage.libs.pari + sage: L.hom([5]) # indirect doctest # needs sage.libs.pari Traceback (most recent call last): ... ValueError: images of some localized elements fail to be units - sage: L.hom([5], codomain=Localization(ZZ, 26)) # indirect doctest + sage: L.hom([5], codomain=Localization(ZZ, 26)) # indirect doctest # needs sage.libs.pari Ring morphism: - From: Univariate Polynomial Ring in x over Integer Ring localized at (x^2 + 1,) + From: Univariate Polynomial Ring in x over Integer Ring + localized at (x^2 + 1,) To: Integer Ring localized at (2, 13) Defn: x |--> 5 TESTS:: - sage: phi=R.hom([5]) + sage: # needs sage.libs.pari + sage: phi = R.hom([5]) sage: L._is_valid_homomorphism_(ZZ, [3], base_map=phi) Traceback (most recent call last): ... @@ -755,13 +777,11 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): Traceback (most recent call last): ... ValueError: images of some localized elements fail to be units - - sage: phi=R.hom([5], codomain=QQ) + sage: phi = R.hom([5], codomain=QQ) sage: L._is_valid_homomorphism_(ZZ, [5], base_map=phi) Traceback (most recent call last): ... ValueError: codomain of base_map must be Integer Ring - sage: L._is_valid_homomorphism_(QQ, [5], base_map=phi) True """ @@ -794,7 +814,7 @@ def ngens(self): EXAMPLES:: sage: R.<x, y> = ZZ[] - sage: Localization(R, (x**2+1, y-1)).ngens() + sage: Localization(R, (x**2 + 1, y - 1)).ngens() # needs sage.libs.pari 2 sage: Localization(ZZ, 2).ngens() @@ -810,7 +830,7 @@ def gen(self, i): EXAMPLES:: sage: R.<x, y> = ZZ[] - sage: R.localization((x**2+1, y-1)).gen(0) + sage: R.localization((x**2 + 1, y - 1)).gen(0) # needs sage.libs.pari x sage: ZZ.localization(2).gen(0) @@ -826,7 +846,7 @@ def gens(self): EXAMPLES:: sage: R.<x, y> = ZZ[] - sage: Localization(R, (x**2+1, y-1)).gens() + sage: Localization(R, (x**2 + 1, y - 1)).gens() # needs sage.libs.pari (x, y) sage: Localization(ZZ, 2).gens() @@ -850,10 +870,10 @@ def _cut_off_extra_units_from_base_ring_element(self, x): EXAMPLES:: sage: P.<x,y,z> = QQ[] - sage: L = Localization(P, (x, y*z)) - sage: L._cut_off_extra_units_from_base_ring_element(x*y*z) + sage: L = Localization(P, (x, y*z)) # needs sage.libs.pari + sage: L._cut_off_extra_units_from_base_ring_element(x*y*z) # needs sage.libs.pari 1 - sage: L._cut_off_extra_units_from_base_ring_element(x*z) + sage: L._cut_off_extra_units_from_base_ring_element(x*z) # needs sage.libs.pari 1 TESTS: @@ -892,8 +912,9 @@ def _fraction_to_element(self, x): EXAMPLES:: + sage: # needs sage.libs.pari sage.libs.singular sage: P.<x,y,z> = QQ[] - sage: d = x**2+y**2+z**2 + sage: d = x**2 + y**2 + z**2 sage: L = Localization(P, d) sage: L._fraction_to_element((x+y+z)/d) (x + y + z)/(x^2 + y^2 + z^2) @@ -902,7 +923,7 @@ def _fraction_to_element(self, x): TESTS:: - sage: TestSuite(L).run() + sage: TestSuite(L).run() # needs sage.libs.pari sage.libs.singular """ potential_non_unit_denom = self._cut_off_extra_units_from_base_ring_element(x.denominator()) if potential_non_unit_denom.is_unit(): @@ -918,6 +939,7 @@ def _coerce_map_from_(self, S): EXAMPLES:: + sage: # needs sage.libs.pari sage.libs.singular sage: P.<x,y,z> = QQ[] sage: L = Localization(P, y*z) sage: M = Localization(P, (x, y, z)) @@ -931,7 +953,7 @@ def _coerce_map_from_(self, S): True sage: N._coerce_map_from_(M) False - sage: O = Localization(L, x**2+1) + sage: O = Localization(L, x**2 + 1) sage: O._coerce_map_from_(M) False sage: O._coerce_map_from_(L) @@ -950,8 +972,9 @@ def fraction_field(self): EXAMPLES:: + sage: # needs sage.libs.pari sage: R.<a> = GF(5)[] - sage: L = Localization(R, (a**2-3, a)) + sage: L = Localization(R, (a**2 - 3, a)) sage: L.fraction_field() Fraction Field of Univariate Polynomial Ring in a over Finite Field of size 5 sage: L.is_subring(_) @@ -965,8 +988,9 @@ def characteristic(self): EXAMPLES:: + sage: # needs sage.libs.pari sage: R.<a> = GF(5)[] - sage: L = R.localization((a**2-3, a)) + sage: L = R.localization((a**2 - 3, a)) sage: L.characteristic() 5 """ @@ -983,7 +1007,7 @@ def krull_dimension(self): EXAMPLES:: - sage: R = ZZ.localization((2,3)) + sage: R = ZZ.localization((2, 3)) sage: R.krull_dimension() 1 """ @@ -1007,7 +1031,7 @@ def is_field(self, proof=True): EXAMPLES:: - sage: R = ZZ.localization((2,3)) + sage: R = ZZ.localization((2, 3)) sage: R.is_field() False """ diff --git a/src/sage/rings/monomials.py b/src/sage/rings/monomials.py index 0beb25a1044..ed154ab8c06 100644 --- a/src/sage/rings/monomials.py +++ b/src/sage/rings/monomials.py @@ -9,7 +9,7 @@ def _monomials(gens, R, n, i): EXAMPLES:: - sage: monomials([x], [3]) # indirect doctest + sage: monomials([x], [3]) # indirect doctest # needs sage.symbolic [1, x, x^2] """ # each power of the ith generator times all products @@ -34,8 +34,10 @@ def _monomials(gens, R, n, i): z *= gens[i] return v + from sage.structure.sequence import Sequence + def monomials(v, n): """ Given two lists ``v`` and ``n``, of exactly the same length, @@ -51,7 +53,7 @@ def monomials(v, n): EXAMPLES:: - sage: monomials([x], [3]) + sage: monomials([x], [3]) # needs sage.symbolic [1, x, x^2] sage: R.<x,y,z> = QQ[] sage: monomials([x,y], [5,5]) diff --git a/src/sage/rings/morphism.pxd b/src/sage/rings/morphism.pxd index ea6089f29b4..4b8e8d052df 100644 --- a/src/sage/rings/morphism.pxd +++ b/src/sage/rings/morphism.pxd @@ -14,7 +14,7 @@ cdef class RingMap_lift(RingMap): cdef class RingHomomorphism(RingMap): cdef Morphism _lift - cdef public dict __cached_methods + cdef public dict _cached_methods cdef class RingHomomorphism_im_gens(RingHomomorphism): cdef _im_gens diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index f7f83974425..5f7dc12cdb1 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -17,7 +17,8 @@ Natural inclusion `\ZZ \hookrightarrow \QQ`:: sage: phi(2/3) Traceback (most recent call last): ... - TypeError: 2/3 fails to convert into the map's domain Integer Ring, but a `pushforward` method is not properly implemented + TypeError: 2/3 fails to convert into the map's domain Integer Ring, + but a `pushforward` method is not properly implemented There is no homomorphism in the other direction:: @@ -25,12 +26,14 @@ There is no homomorphism in the other direction:: sage: H([1]) Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators EXAMPLES: Reduction to finite field:: + sage: # needs sage.rings.finite_rings sage: H = Hom(ZZ, GF(9, 'a')) sage: phi = H([1]) sage: phi(5) @@ -61,21 +64,23 @@ Identity map on the real numbers:: sage: f = RR.hom( [2.0] ) Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators Homomorphism from one precision of field to another. From smaller to bigger doesn't make sense:: - sage: R200 = RealField(200) - sage: f = RR.hom( R200 ) + sage: R200 = RealField(200) # needs sage.rings.real_mpfr + sage: f = RR.hom( R200 ) # needs sage.rings.real_mpfr Traceback (most recent call last): ... - TypeError: natural coercion morphism from Real Field with 53 bits of precision to Real Field with 200 bits of precision not defined + TypeError: natural coercion morphism from Real Field with 53 bits of precision + to Real Field with 200 bits of precision not defined From bigger to small does:: - sage: f = RR.hom( RealField(15) ) + sage: f = RR.hom( RealField(15) ) # needs sage.rings.real_mpfr sage: f(2.5) 2.500 sage: f(RR.pi()) @@ -94,21 +99,23 @@ Inclusion map from the reals to the complexes:: A map from a multivariate polynomial ring to itself:: sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: phi = R.hom([y,z,x^2]); phi + sage: phi = R.hom([y, z, x^2]); phi Ring endomorphism of Multivariate Polynomial Ring in x, y, z over Rational Field Defn: x |--> y y |--> z z |--> x^2 - sage: phi(x+y+z) + sage: phi(x + y + z) x^2 + y + z An endomorphism of a quotient of a multi-variate polynomial ring:: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ) sage: S.<a,b> = quo(R, ideal(1 + y^2)) sage: phi = S.hom([a^2, -b]) sage: phi - Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (y^2 + 1) + Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y + over Rational Field by the ideal (y^2 + 1) Defn: a |--> a^2 b |--> -b sage: phi(b) @@ -120,8 +127,7 @@ The reduction map from the integers to the integers modulo 8, viewed as a quotient ring:: sage: R = ZZ.quo(8*ZZ) - sage: pi = R.cover() - sage: pi + sage: pi = R.cover(); pi Ring morphism: From: Integer Ring To: Ring of integers modulo 8 @@ -142,6 +148,7 @@ a quotient ring:: Inclusion of ``GF(2)`` into ``GF(4,'a')``:: + sage: # needs sage.rings.finite_rings sage: k = GF(2) sage: i = k.hom(GF(4, 'a')) sage: i @@ -157,6 +164,7 @@ Inclusion of ``GF(2)`` into ``GF(4,'a')``:: We next compose the inclusion with reduction from the integers to ``GF(2)``:: + sage: # needs sage.rings.finite_rings sage: pi = ZZ.hom(k) sage: pi Natural morphism: @@ -182,7 +190,8 @@ We next compose the inclusion with reduction from the integers to Inclusion from `\QQ` to the 3-adic field:: - sage: phi = QQ.hom(Qp(3, print_mode = 'series')) + sage: # needs sage.rings.padics + sage: phi = QQ.hom(Qp(3, print_mode='series')) sage: phi Ring morphism: From: Rational Field @@ -194,8 +203,9 @@ Inclusion from `\QQ` to the 3-adic field:: An automorphism of a quotient of a univariate polynomial ring:: + sage: # needs sage.libs.pari sage: R.<x> = PolynomialRing(QQ) - sage: S.<sqrt2> = R.quo(x^2-2) + sage: S.<sqrt2> = R.quo(x^2 - 2) sage: sqrt2^2 2 sage: (3+sqrt2)^10 @@ -206,12 +216,13 @@ An automorphism of a quotient of a univariate polynomial ring:: Note that Sage verifies that the morphism is valid:: - sage: (1 - sqrt2)^2 + sage: (1 - sqrt2)^2 # needs sage.libs.pari -2*sqrt2 + 3 - sage: c = S.hom([1-sqrt2]) # this is not valid + sage: c = S.hom([1 - sqrt2]) # this is not valid # needs sage.libs.pari Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators Endomorphism of power series ring:: @@ -265,14 +276,17 @@ positive:: sage: R.hom([1/t]) Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators sage: R.hom([1]) Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators Complex conjugation on cyclotomic fields:: + sage: # needs sage.rings.number_field sage: K.<zeta7> = CyclotomicField(7) sage: c = K.hom([1/zeta7]); c Ring endomorphism of Cyclotomic Field of order 7 and degree 6 @@ -288,6 +302,7 @@ Complex conjugation on cyclotomic fields:: Embedding a number field into the reals:: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) sage: K.<beta> = NumberField(x^3 - 2) sage: alpha = RR(2)^(1/3); alpha @@ -306,7 +321,7 @@ Embedding a number field into the reals:: An example from Jim Carlson:: - sage: K = QQ # by the way :-) + sage: K = QQ # by the way :-) sage: R.<a,b,c,d> = K[]; R Multivariate Polynomial Ring in a, b, c, d over Rational Field sage: S.<u> = K[]; S @@ -319,9 +334,9 @@ An example from Jim Carlson:: b |--> 0 c |--> 0 d |--> u - sage: f(a+b+c+d) + sage: f(a + b + c + d) u - sage: f( (a+b+c+d)^2 ) + sage: f((a+b+c+d)^2) u^2 TESTS:: @@ -332,8 +347,8 @@ TESTS:: :: - sage: K.<zeta7> = CyclotomicField(7) - sage: c = K.hom([1/zeta7]) + sage: K.<zeta7> = CyclotomicField(7) # needs sage.rings.number_field + sage: c = K.hom([1/zeta7]) # needs sage.rings.number_field sage: c == loads(dumps(c)) True @@ -347,75 +362,57 @@ TESTS:: We define the identity map in many possible ways. These should all compare equal:: + sage: # needs sage.rings.finite_rings sage: k = GF(2) sage: R.<x> = k[] sage: F4.<a> = R.quo(x^2+x+1) sage: H = End(F4) - sage: from sage.rings.morphism import * sage: phi1 = H.identity(); phi1 - Identity endomorphism of Univariate Quotient Polynomial Ring in a over Finite Field of size 2 with modulus x^2 + x + 1 + Identity endomorphism of Univariate Quotient Polynomial Ring in a + over Finite Field of size 2 with modulus x^2 + x + 1 sage: phi2 = H([a]); phi2 - Ring endomorphism of Univariate Quotient Polynomial Ring in a over Finite Field of size 2 with modulus x^2 + x + 1 + Ring endomorphism of Univariate Quotient Polynomial Ring in a + over Finite Field of size 2 with modulus x^2 + x + 1 Defn: a |--> a - sage: phi3 = RingHomomorphism_from_base(H, R.hom([x])); phi3 - Ring endomorphism of Univariate Quotient Polynomial Ring in a over Finite Field of size 2 with modulus x^2 + x + 1 + sage: phi3 = RingHomomorphism_from_base(H, R.hom([x])); phi3 # needs sage.libs.ntl + Ring endomorphism of Univariate Quotient Polynomial Ring in a + over Finite Field of size 2 with modulus x^2 + x + 1 Defn: Induced from base ring by - Ring endomorphism of Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) + Ring endomorphism of Univariate Polynomial Ring in x + over Finite Field of size 2 (using GF2X) Defn: x |--> x sage: phi4 = RingHomomorphism_cover(H); phi4 - Ring endomorphism of Univariate Quotient Polynomial Ring in a over Finite Field of size 2 with modulus x^2 + x + 1 + Ring endomorphism of Univariate Quotient Polynomial Ring in a + over Finite Field of size 2 with modulus x^2 + x + 1 Defn: Natural quotient map sage: phi5 = F4.frobenius_endomorphism() ^ 2; phi5 - Frobenius endomorphism x |--> x^(2^2) of Univariate Quotient Polynomial Ring in a over Finite Field of size 2 with modulus x^2 + x + 1 - sage: maps = [phi1, phi2, phi3, phi4, phi5] - sage: for f in maps: + Frobenius endomorphism x |--> x^(2^2) of + Univariate Quotient Polynomial Ring in a + over Finite Field of size 2 with modulus x^2 + x + 1 + sage: maps = [phi1, phi2, phi3, phi4, phi5] # needs sage.libs.ntl + sage: for f in maps: # needs sage.libs.ntl ....: for g in maps: ....: if f != g: ....: print("{} != {}".format(f, g)) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein <wstein@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** - -from cpython.object cimport Py_EQ, Py_NE +# https://www.gnu.org/licenses/ +# **************************************************************************** from . import ideal import sage.structure.all -from sage.structure.richcmp cimport (richcmp, rich_to_bool, richcmp_not_equal) +from sage.structure.richcmp cimport (richcmp, rich_to_bool) from sage.misc.cachefunc import cached_method -def is_RingHomomorphism(phi): - """ - Return ``True`` if ``phi`` is of type :class:`RingHomomorphism`. - - EXAMPLES:: - - sage: f = Zmod(8).cover() - sage: sage.rings.morphism.is_RingHomomorphism(f) - doctest:warning - ... - DeprecationWarning: is_RingHomomorphism() should not be used anymore. Check whether the category_for() your morphism is a subcategory of Rings() instead. - See https://github.com/sagemath/sage/issues/23204 for details. - True - sage: sage.rings.morphism.is_RingHomomorphism(2/3) - False - """ - sage.misc.superseded.deprecation(23204, "is_RingHomomorphism() should not be used anymore. Check whether the category_for() your morphism is a subcategory of Rings() instead.") - # We use the category framework to determine whether something is a ring homomorphism. - from sage.categories.map import Map - from sage.categories.rings import Rings - return isinstance(phi, Map) and phi.category_for().is_subcategory(Rings()) - - cdef class RingMap(Morphism): """ Set-theoretic map between rings. @@ -457,13 +454,14 @@ cdef class RingMap_lift(RingMap): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: S.<xbar,ybar> = R.quo( (x^2 + y^2, y) ) - sage: S.lift() + sage: S.<xbar,ybar> = R.quo( (x^2 + y^2, y) ) # needs sage.libs.singular + sage: S.lift() # needs sage.libs.singular Set-theoretic ring morphism: - From: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2, y) + From: Quotient of Multivariate Polynomial Ring in x, y + over Rational Field by the ideal (x^2 + y^2, y) To: Multivariate Polynomial Ring in x, y over Rational Field Defn: Choice of lifting map - sage: S.lift() == 0 + sage: S.lift() == 0 # needs sage.libs.singular False Since :trac:`11068`, it is possible to create @@ -473,8 +471,9 @@ cdef class RingMap_lift(RingMap): of :class:`sage.rings.ring.Ring`, as in the following example:: - sage: MS = MatrixSpace(GF(5),2,2) - sage: I = MS*[MS.0*MS.1,MS.2+MS.3]*MS + sage: # needs sage.modules sage.rings.finite_rings + sage: MS = MatrixSpace(GF(5), 2, 2) + sage: I = MS * [MS.0*MS.1, MS.2+MS.3] * MS sage: Q = MS.quo(I) sage: Q.0*Q.1 # indirect doctest [0 1] @@ -496,12 +495,13 @@ cdef class RingMap_lift(RingMap): An invalid example:: - sage: GF9.<one, a> = GaussianIntegers().quotient(3) + sage: GF9.<one, a> = GaussianIntegers().quotient(3) # needs sage.rings.number_field sage: from sage.rings.morphism import RingMap_lift - sage: RingMap_lift(GF9, ZZ) + sage: RingMap_lift(GF9, ZZ) # needs sage.rings.number_field Traceback (most recent call last): ... - TypeError: no canonical coercion from Number Field in I with defining polynomial x^2 + 1 with I = 1*I to Integer Ring + TypeError: no canonical coercion from Number Field in I + with defining polynomial x^2 + 1 with I = 1*I to Integer Ring """ self.S = <Parent?>S x = <Element?>R(0).lift() @@ -640,14 +640,14 @@ cdef class RingHomomorphism(RingMap): EXAMPLES:: - sage: f = ZZ.hom(Zp(3)); f + sage: f = ZZ.hom(Zp(3)); f # needs sage.rings.padics Ring morphism: From: Integer Ring To: 3-adic Ring with capped relative precision 20 TESTS:: - sage: isinstance(f, sage.rings.morphism.RingHomomorphism) + sage: isinstance(f, sage.rings.morphism.RingHomomorphism) # needs sage.rings.padics True """ @@ -662,7 +662,7 @@ cdef class RingHomomorphism(RingMap): TESTS:: - sage: ZZ.hom(Zp(3))._repr_type() + sage: ZZ.hom(Zp(3))._repr_type() # needs sage.rings.padics 'Ring' """ @@ -775,18 +775,19 @@ cdef class RingHomomorphism(RingMap): result has the type of a homomorphism between its domain and codomain:: - sage: C = CyclotomicField(24) - sage: f = End(C)[1] - sage: type(f*f) == type(f) + sage: C = CyclotomicField(24) # needs sage.rings.number_field + sage: f = End(C)[1] # needs sage.rings.number_field + sage: type(f*f) == type(f) # needs sage.rings.number_field True An example where the domain of ``right`` is a relative number field:: sage: PQ.<X> = QQ[] - sage: K.<a, b> = NumberField([X^2 - 2, X^2 - 3]) - sage: e, u, v, w = End(K) - sage: u*v - Relative number field endomorphism of Number Field in a with defining polynomial X^2 - 2 over its base field + sage: K.<a, b> = NumberField([X^2 - 2, X^2 - 3]) # needs sage.rings.number_field + sage: e, u, v, w = End(K) # needs sage.rings.number_field + sage: u*v # needs sage.rings.number_field + Relative number field endomorphism of + Number Field in a with defining polynomial X^2 - 2 over its base field Defn: a |--> -a b |--> b @@ -804,20 +805,24 @@ cdef class RingHomomorphism(RingMap): then Coercion map: From: Multivariate Polynomial Ring in a, b over Rational Field - To: Fraction Field of Multivariate Polynomial Ring in a, b over Rational Field + To: Fraction Field of + Multivariate Polynomial Ring in a, b over Rational Field We check that composition works when there is a base map:: + sage: # needs sage.rings.finite_rings sage: R.<x> = ZZ[] sage: K.<a> = GF(7^2) sage: L.<u> = K.extension(x^3 - 3) sage: phi = L.hom([u^7], base_map=K.frobenius_endomorphism()) sage: phi - Ring endomorphism of Univariate Quotient Polynomial Ring in u over Finite Field in a of size 7^2 with modulus u^3 + 4 + Ring endomorphism of Univariate Quotient Polynomial Ring in u + over Finite Field in a of size 7^2 with modulus u^3 + 4 Defn: u |--> 2*u with map of base ring sage: psi = phi^3; psi - Ring endomorphism of Univariate Quotient Polynomial Ring in u over Finite Field in a of size 7^2 with modulus u^3 + 4 + Ring endomorphism of Univariate Quotient Polynomial Ring in u + over Finite Field in a of size 7^2 with modulus u^3 + 4 Defn: u |--> u with map of base ring sage: psi(a) == phi(phi(phi(a))) @@ -827,16 +832,18 @@ cdef class RingHomomorphism(RingMap): sage: S.<x> = QQ[] sage: T.<y> = S[] - sage: cc = S.hom([x+y]) - sage: f = T.hom([x-y], base_map=cc) + sage: cc = S.hom([x + y]) + sage: f = T.hom([x - y], base_map=cc) sage: f*f - Ring endomorphism of Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + Ring endomorphism of Univariate Polynomial Ring in y + over Univariate Polynomial Ring in x over Rational Field Defn: y |--> 2*y with map of base ring sage: (f*f).base_map() Ring morphism: From: Univariate Polynomial Ring in x over Rational Field - To: Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + To: Univariate Polynomial Ring in y over + Univariate Polynomial Ring in x over Rational Field Defn: x |--> 2*x with map of base ring @@ -887,9 +894,10 @@ cdef class RingHomomorphism(RingMap): EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2,y^2]); f = S.cover() - sage: f.pushforward(R.ideal([x,3*x+x*y+y^2])) - Ideal (xx, xx*yy + 3*xx) of Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y^2) + sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2, y^2]); f = S.cover() # needs sage.libs.singular + sage: f.pushforward(R.ideal([x, 3*x + x*y + y^2])) # needs sage.libs.singular + Ideal (xx, xx*yy + 3*xx) of Quotient of Multivariate Polynomial Ring + in x, y over Rational Field by the ideal (x^2, y^2) """ if not ideal.is_Ideal(I): raise TypeError("I must be an ideal") @@ -920,18 +928,18 @@ cdef class RingHomomorphism(RingMap): sage: S.<u,v> = QQ[] sage: f = R.hom([u^2, u*v, v^2], S) sage: I = S.ideal([u^6, u^5*v, u^4*v^2, u^3*v^3]) - sage: J = f.inverse_image(I); J + sage: J = f.inverse_image(I); J # needs sage.libs.singular Ideal (y^2 - x*z, x*y*z, x^2*z, x^2*y, x^3) of Multivariate Polynomial Ring in x, y, z over Rational Field - sage: f(J) == I + sage: f(J) == I # needs sage.libs.singular True Under the above homomorphism, there exists an inverse image for every element that only involves monomials of even degree:: - sage: [f.inverse_image(p) for p in [u^2, u^4, u*v + u^3*v^3]] + sage: [f.inverse_image(p) for p in [u^2, u^4, u*v + u^3*v^3]] # needs sage.libs.singular [x, x^2, x*y*z + y] - sage: f.inverse_image(u*v^2) + sage: f.inverse_image(u*v^2) # needs sage.libs.singular Traceback (most recent call last): ... ValueError: element u*v^2 does not have preimage @@ -939,6 +947,7 @@ cdef class RingHomomorphism(RingMap): The image of the inverse image ideal can be strictly smaller than the original ideal:: + sage: # needs sage.libs.singular sage.rings.number_field sage: S.<u,v> = QQ['u,v'].quotient('v^2 - 2') sage: f = QuadraticField(2).hom([v], S) sage: I = S.ideal(u + v) @@ -950,6 +959,7 @@ cdef class RingHomomorphism(RingMap): Fractional ideals are not yet fully supported:: + sage: # needs sage.rings.number_field sage: K.<a> = NumberField(QQ['x']('x^2+2')) sage: f = K.hom([-a], K) sage: I = K.ideal([a + 1]) @@ -973,7 +983,7 @@ cdef class RingHomomorphism(RingMap): TESTS:: - sage: ZZ.hom(Zp(2)).inverse_image(ZZ.ideal(2)) + sage: ZZ.hom(Zp(2)).inverse_image(ZZ.ideal(2)) # needs sage.rings.padics Traceback (most recent call last): ... ValueError: not an ideal or element in codomain 2-adic Ring @@ -981,7 +991,7 @@ cdef class RingHomomorphism(RingMap): :: - sage: ZZ.hom(Zp(2)).inverse_image(Zp(2).ideal(2)) + sage: ZZ.hom(Zp(2)).inverse_image(Zp(2).ideal(2)) # needs sage.rings.padics Traceback (most recent call last): ... NotImplementedError: base rings must be equal @@ -1001,12 +1011,13 @@ cdef class RingHomomorphism(RingMap): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: f = R.hom([x, QQbar(i) * x + y^2], R) sage: I = R.ideal(y^3) sage: J = f._inverse_image_ideal(I); J Ideal (x^2 + 2*I*x*y - y^2) - of Multivariate Polynomial Ring in x, y over Algebraic Field + of Multivariate Polynomial Ring in x, y over Algebraic Field sage: f(J) <= I True @@ -1015,17 +1026,17 @@ cdef class RingHomomorphism(RingMap): Check that :trac:`31367` is fixed:: sage: A.<t> = QQ[] - sage: B.<x,y> = QQ['x,y'].quotient('y') - sage: f = A.hom([x], B) - sage: f.kernel() + sage: B.<x,y> = QQ['x,y'].quotient('y') # needs sage.libs.singular + sage: f = A.hom([x], B) # needs sage.libs.singular + sage: f.kernel() # needs sage.libs.singular Principal ideal (0) of Univariate Polynomial Ring in t over Rational Field :: sage: A.<t,u> = QQ[] - sage: B.<x,y,z> = QQ['x,y,z'].quotient('z') - sage: f = A.hom([x, y], B) - sage: f.kernel() + sage: B.<x,y,z> = QQ['x,y,z'].quotient('z') # needs sage.libs.singular + sage: f = A.hom([x, y], B) # needs sage.libs.singular + sage: f.kernel() # needs sage.libs.singular Ideal (0) of Multivariate Polynomial Ring in t, u over Rational Field """ from .polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing @@ -1067,14 +1078,15 @@ cdef class RingHomomorphism(RingMap): A degenerate case:: - sage: R.<x,y> = QQ['x,y'].quotient(1) - sage: f = R.hom([y, x], R) - sage: f.inverse_image(x), f.inverse_image(y) # indirect doctest + sage: R.<x,y> = QQ['x,y'].quotient(1) # needs sage.libs.singular + sage: f = R.hom([y, x], R) # needs sage.libs.singular + sage: f.inverse_image(x), f.inverse_image(y) # indirect doctest # needs sage.libs.singular (0, 0) Check cases involving quotient rings in which a generator is constant (:trac:`31178`):: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ[] sage: B.<c,d> = R.quotient(R.ideal(x)) sage: g = R.hom([d^2, d^3], B) @@ -1093,6 +1105,7 @@ cdef class RingHomomorphism(RingMap): Check that quotient rings are handled correctly (:trac:`33217`):: + sage: # needs sage.libs.singular sage: A.<x,y,z> = QQ['X,Y,Z'].quotient('X^2+Y^2+Z^2-1') sage: B.<t,u,v,w> = QQ['T,U,V,W'].quotient(['T^2+U^2-1', 'V^2+W^2-1']) sage: psi = A.hom([v*u, w*u, t], B) @@ -1116,7 +1129,7 @@ cdef class RingHomomorphism(RingMap): sage: A.<x,y> = QQ[] sage: B.<t> = QQ[] sage: f = A.hom([t^4, t^3 - t^2], B) - sage: f.kernel() + sage: f.kernel() # needs sage.libs.singular Ideal (y^4 - x^3 + 4*x^2*y - 2*x*y^2 + x^2) of Multivariate Polynomial Ring in x, y over Rational Field @@ -1124,44 +1137,45 @@ cdef class RingHomomorphism(RingMap): sage: A.<a,b,c,d> = QQ[] sage: B.<u,v> = QQ[] - sage: f = A.hom([u^3, u^2*v, u*v^2, v^3],B) - sage: f.kernel() == A.ideal(matrix.hankel([a, b, c], [d]).minors(2)) + sage: f = A.hom([u^3, u^2*v, u*v^2, v^3], B) + sage: f.kernel() == A.ideal(matrix.hankel([a, b, c], [d]).minors(2)) # needs sage.libs.singular True - sage: Q = A.quotient(f.kernel()) - sage: Q.hom(f.im_gens(), B).is_injective() + sage: Q = A.quotient(f.kernel()) # needs sage.libs.singular + sage: Q.hom(f.im_gens(), B).is_injective() # needs sage.libs.singular True The Steiner-Roman surface:: sage: R.<x,y,z> = QQ[] sage: S = R.quotient(x^2 + y^2 + z^2 - 1) - sage: f = R.hom([x*y, x*z, y*z], S) - sage: f.kernel() + sage: f = R.hom([x*y, x*z, y*z], S) # needs sage.libs.singular + sage: f.kernel() # needs sage.libs.singular Ideal (x^2*y^2 + x^2*z^2 + y^2*z^2 - x*y*z) - of Multivariate Polynomial Ring in x, y, z over Rational Field + of Multivariate Polynomial Ring in x, y, z over Rational Field TESTS: The results are cached:: - sage: f.kernel() is f.kernel() + sage: f.kernel() is f.kernel() # needs sage.libs.singular True A degenerate case:: sage: R.<x,y> = QQ[] - sage: f = R.hom([0, 0], R.quotient(1)) - sage: f.kernel().is_one() + sage: f = R.hom([0, 0], R.quotient(1)) # needs sage.libs.singular + sage: f.kernel().is_one() # needs sage.libs.singular True :: - sage: K.<sqrt2> = QuadraticField(2) - sage: K.hom([-sqrt2], K).kernel().is_zero() + sage: K.<sqrt2> = QuadraticField(2) # needs sage.rings.number_field + sage: K.hom([-sqrt2], K).kernel().is_zero() # needs sage.rings.number_field True :: + sage: # needs sage.rings.number_field sage: A.<a> = QuadraticField(2) sage: B.<b> = A.extension(A['b']('b^2-3')) sage: C.<c> = B.absolute_field() @@ -1242,6 +1256,7 @@ cdef class RingHomomorphism(RingMap): Ideals in quotient rings over ``QQbar`` do not support reduction yet, so the graph is constructed in the ambient ring instead:: + sage: # needs sage.rings.number_field sage: A.<z,w> = QQbar['z,w'].quotient('z*w - 1') sage: B.<x,y> = QQbar['x,y'].quotient('2*x^2 + y^2 - 1') sage: f = A.hom([QQbar(2).sqrt()*x + QQbar(I)*y, @@ -1256,6 +1271,7 @@ cdef class RingHomomorphism(RingMap): Non-trivial base maps are not supported:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(2) sage: R.<x,y> = K[] sage: f = R.hom([x, a*x + y], R, base_map=K.hom([-a], K)) @@ -1266,8 +1282,8 @@ cdef class RingHomomorphism(RingMap): Non-commutative rings are not supported (:trac:`32824`):: - sage: A = GradedCommutativeAlgebra(QQ, 'x,y,z') - sage: A.hom(A.gens(), A).kernel() + sage: A = GradedCommutativeAlgebra(QQ, 'x,y,z') # needs sage.combinat sage.modules + sage: A.hom(A.gens(), A).kernel() # needs sage.combinat sage.modules Traceback (most recent call last): ... NotImplementedError: rings are not commutative @@ -1324,13 +1340,14 @@ cdef class RingHomomorphism(RingMap): sage: R.<t> = QQ[] sage: f = R.hom([2*t - 1], R) - sage: f.inverse() + sage: f.inverse() # needs sage.libs.singular Ring endomorphism of Univariate Polynomial Ring in t over Rational Field Defn: t |--> 1/2*t + 1/2 The following non-linear homomorphism is not invertible, but it induces an isomorphism on a quotient ring:: + sage: # needs sage.libs.singular sage: R.<x,y,z> = QQ[] sage: f = R.hom([y*z, x*z, x*y], R) sage: f.inverse() @@ -1352,24 +1369,24 @@ cdef class RingHomomorphism(RingMap): sage: S.<x,y> = ZZ[] sage: f = S.hom([x + 2*y, x + 3*y], S) - sage: f.inverse() + sage: f.inverse() # needs sage.libs.singular Ring endomorphism of Multivariate Polynomial Ring in x, y over Integer Ring Defn: x |--> 3*x - 2*y y |--> -x + y - sage: (f.inverse() * f).is_identity() + sage: (f.inverse() * f).is_identity() # needs sage.libs.singular True The following homomorphism is invertible over the rationals, but not over the integers:: sage: g = S.hom([x + y, x - y - 2], S) - sage: g.inverse() + sage: g.inverse() # needs sage.libs.singular Traceback (most recent call last): ... ZeroDivisionError: ring homomorphism not surjective sage: R.<x,y> = QQ[x,y] sage: h = R.hom([x + y, x - y - 2], R) - sage: (h.inverse() * h).is_identity() + sage: (h.inverse() * h).is_identity() # needs sage.libs.singular True This example by M. Nagata is a wild automorphism:: @@ -1377,13 +1394,13 @@ cdef class RingHomomorphism(RingMap): sage: R.<x,y,z> = QQ[] sage: sigma = R.hom([x - 2*y*(z*x+y^2) - z*(z*x+y^2)^2, ....: y + z*(z*x+y^2), z], R) - sage: tau = sigma.inverse(); tau + sage: tau = sigma.inverse(); tau # needs sage.libs.singular Ring endomorphism of Multivariate Polynomial Ring in x, y, z over Rational Field Defn: x |--> -y^4*z - 2*x*y^2*z^2 - x^2*z^3 + 2*y^3 + 2*x*y*z + x y |--> -y^2*z - x*z^2 + y z |--> z - sage: (tau * sigma).is_identity() + sage: (tau * sigma).is_identity() # needs sage.libs.singular True We compute the triangular automorphism that converts moments to @@ -1407,29 +1424,30 @@ cdef class RingHomomorphism(RingMap): x1^5 + 10*x1^3*x2 + 15*x1*x2^2 + 10*x1^2*x3 + 10*x2*x3 + 5*x1*x4 + x5] sage: all(p.is_homogeneous() for p in phi.im_gens()) True - sage: phi.inverse().im_gens()[:5] + sage: phi.inverse().im_gens()[:5] # needs sage.libs.singular [x1, -x1^2 + x2, 2*x1^3 - 3*x1*x2 + x3, -6*x1^4 + 12*x1^2*x2 - 3*x2^2 - 4*x1*x3 + x4, 24*x1^5 - 60*x1^3*x2 + 30*x1*x2^2 + 20*x1^2*x3 - 10*x2*x3 - 5*x1*x4 + x5] - sage: (phi.inverse() * phi).is_identity() + sage: (phi.inverse() * phi).is_identity() # needs sage.libs.singular True Automorphisms of number fields as well as Galois fields are supported:: - sage: K.<zeta7> = CyclotomicField(7) - sage: c = K.hom([1/zeta7]) - sage: (c.inverse() * c).is_identity() + sage: K.<zeta7> = CyclotomicField(7) # needs sage.rings.number_field + sage: c = K.hom([1/zeta7]) # needs sage.rings.number_field + sage: (c.inverse() * c).is_identity() # needs sage.rings.number_field True - sage: F.<t> = GF(7^3) - sage: f = F.hom(t^7, F) - sage: (f.inverse() * f).is_identity() + sage: F.<t> = GF(7^3) # needs sage.rings.finite_rings + sage: f = F.hom(t^7, F) # needs sage.rings.finite_rings + sage: (f.inverse() * f).is_identity() # needs sage.rings.finite_rings True An isomorphism between the algebraic torus and the circle over a number field:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: A.<z,w> = K['z,w'].quotient('z*w - 1') sage: B.<x,y> = K['x,y'].quotient('x^2 + y^2 - 1') @@ -1444,12 +1462,13 @@ cdef class RingHomomorphism(RingMap): Morphisms involving quotient rings:: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ[] sage: S.<s,u,t> = QQ['s,u,t'].quotient('u-t^2') sage: f = R.hom([s, -t], S) sage: (f.inverse() * f).is_identity() True - sage: Q.<v,w> = R.quotient(x-y^2) + sage: Q.<v,w> = R.quotient(x - y^2) sage: g = Q.hom([v, -w], Q) sage: g.inverse()(g(v)) == v and g.inverse()(g(w)) == w True @@ -1460,6 +1479,7 @@ cdef class RingHomomorphism(RingMap): Morphisms between number fields and quotient rings:: + sage: # needs sage.rings.number_field sage: K.<sqrt2> = QuadraticField(2) sage: f = K.hom([-sqrt2], K.polynomial_quotient_ring()) sage: (f.inverse() * f).is_identity() @@ -1470,6 +1490,7 @@ cdef class RingHomomorphism(RingMap): Morphisms involving Galois fields:: + sage: # needs sage.rings.finite_rings sage: A.<t> = GF(7^3) sage: R = A.polynomial_ring().quotient(A.polynomial()) sage: g = A.hom(R.gens(), R) @@ -1489,6 +1510,7 @@ cdef class RingHomomorphism(RingMap): Non-injective homomorphisms:: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ[] sage: S.<a,b,c> = QQ[] sage: S.hom([x, y, 0], R).inverse() @@ -1512,23 +1534,23 @@ cdef class RingHomomorphism(RingMap): Univariate quotient rings:: - sage: R.<t> = QQ['t'].quotient('t^5') + sage: R.<t> = QQ['t'].quotient('t^5') # needs sage.libs.pari sage: f = R.hom([2*t], R) - sage: (f.inverse() * f).is_identity() + sage: (f.inverse() * f).is_identity() # needs sage.libs.singular True A homomorphism over ``QQbar``:: - sage: R.<x,y> = QQbar[] - sage: f = R.hom([x + QQbar(I)*y^2, -y], R) - sage: (f.inverse() * f).is_identity() + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: f = R.hom([x + QQbar(I)*y^2, -y], R) # needs sage.rings.number_field + sage: (f.inverse() * f).is_identity() # needs sage.rings.number_field True Check that results are cached:: sage: R.<x,y> = GF(823)[] sage: f = R.hom([x, y+x^2], R) - sage: f.inverse() is f.inverse() + sage: f.inverse() is f.inverse() # needs sage.rings.finite_rings True Some subclasses of ring homomorphisms are not supported:: @@ -1564,9 +1586,9 @@ cdef class RingHomomorphism(RingMap): sage: f = R.hom([x + 123*y^2, y], R) sage: f._graph_ideal()[0].groebner_basis.is_in_cache() False - sage: f.is_injective() + sage: f.is_injective() # needs sage.libs.singular True - sage: f._graph_ideal()[0].groebner_basis.is_in_cache() + sage: f._graph_ideal()[0].groebner_basis.is_in_cache() # needs sage.libs.singular True """ if not self.is_injective(): @@ -1588,7 +1610,7 @@ cdef class RingHomomorphism(RingMap): sage: R.<x,y> = GF(17)[] sage: f = R.hom([3*x, y + x^2 + x^3], R) - sage: (f * ~f).is_identity() + sage: (f * ~f).is_identity() # needs sage.rings.finite_rings True """ return self.inverse() @@ -1600,10 +1622,10 @@ cdef class RingHomomorphism(RingMap): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: R.hom([y*z, x*z, x*y], R).is_surjective() + sage: R.hom([y*z, x*z, x*y], R).is_surjective() # needs sage.libs.singular False - sage: Q.<x,y,z> = R.quotient(x*y*z - 1) - sage: R.hom([y*z, x*z, x*y], Q).is_surjective() + sage: Q.<x,y,z> = R.quotient(x*y*z - 1) # needs sage.libs.singular + sage: R.hom([y*z, x*z, x*y], Q).is_surjective() # needs sage.libs.singular True ALGORITHM: @@ -1624,10 +1646,10 @@ cdef class RingHomomorphism(RingMap): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: R.hom([y*z, x*z, x*y], R).is_invertible() + sage: R.hom([y*z, x*z, x*y], R).is_invertible() # needs sage.libs.singular False - sage: Q.<x,y,z> = R.quotient(x*y*z - 1) - sage: Q.hom([y*z, x*z, x*y], Q).is_invertible() + sage: Q.<x,y,z> = R.quotient(x*y*z - 1) # needs sage.libs.singular + sage: Q.hom([y*z, x*z, x*y], Q).is_invertible() # needs sage.libs.singular True ALGORITHM: @@ -1637,120 +1659,6 @@ cdef class RingHomomorphism(RingMap): return self.is_injective() and self.is_surjective() -cdef class RingHomomorphism_coercion(RingHomomorphism): - r""" - A ring homomorphism that is a coercion. - - .. WARNING:: - - This class is obsolete. Set the category of your morphism to a - subcategory of ``Rings`` instead. - - TESTS: - - sage: from sage.rings.morphism import RingHomomorphism_coercion - sage: parent = Hom(ZZ,ZZ) - sage: f = parent.__make_element_class__(RingHomomorphism_coercion)(parent) - doctest:warning - ... - DeprecationWarning: Set the category of your morphism to a subcategory of Rings instead. - See https://github.com/sagemath/sage/issues/23204 for details. - sage: TestSuite(f).run() - - """ - def __init__(self, parent, check=True): - r""" - TESTS: - - sage: from sage.rings.morphism import RingHomomorphism_coercion - sage: parent = Hom(ZZ,ZZ) - sage: f = parent.__make_element_class__(RingHomomorphism_coercion)(parent) - doctest:warning - ... - DeprecationWarning: Set the category of your morphism to a subcategory of Rings instead. - See https://github.com/sagemath/sage/issues/23204 for details. - sage: isinstance(f, RingHomomorphism_coercion) - True - - """ - sage.misc.superseded.deprecation(23204, "Set the category of your morphism to a subcategory of Rings instead.") - - RingHomomorphism.__init__(self, parent) - # putting in check allows us to define subclasses of RingHomomorphism_coercion that implement _coerce_map_from - if check and not self.codomain().has_coerce_map_from(self.domain()): - raise TypeError("Natural coercion morphism from %s to %s not defined."%(self.domain(), self.codomain())) - - def _repr_type(self): - """ - Used internally when printing this. - - EXAMPLES:: - - sage: from sage.rings.morphism import RingHomomorphism_coercion - sage: parent = Hom(ZZ,ZZ) - sage: f = parent.__make_element_class__(RingHomomorphism_coercion)(parent) - sage: f._repr_type() - 'Ring Coercion' - - """ - return "Ring Coercion" - - cpdef _richcmp_(self, other, int op): - """ - Compare a ring coercion morphism ``self`` to ``other``. - - Ring coercion morphisms never compare equal to any other data type. If - other is a ring coercion morphism, the parents of ``self`` and - ``other`` are compared. - - EXAMPLES:: - - sage: from sage.rings.morphism import RingHomomorphism_coercion - sage: parent = Hom(ZZ,ZZ) - sage: f = parent.__make_element_class__(RingHomomorphism_coercion)(parent) - sage: f == f - True - sage: f != f - False - """ - if not isinstance(other, RingHomomorphism_coercion): - # Generic comparison - return RingMap._richcmp_(self, other, op) - # Two coercion maps with the same parent must be equal - return rich_to_bool(op, 0) - - def __hash__(self): - """ - Return the hash of this morphism. - - TESTS:: - - sage: from sage.rings.morphism import RingHomomorphism_coercion - sage: parent = Hom(ZZ,ZZ) - sage: f = parent.__make_element_class__(RingHomomorphism_coercion)(parent) - sage: g = parent.__make_element_class__(RingHomomorphism_coercion)(parent) - sage: hash(f) == hash(g) - True - - """ - return hash((self.domain(), self.codomain())) - - cpdef Element _call_(self, x): - """ - Evaluate this coercion morphism at ``x``. - - EXAMPLES:: - - sage: from sage.rings.morphism import RingHomomorphism_coercion - sage: parent = Hom(ZZ,ZZ) - sage: f = parent.__make_element_class__(RingHomomorphism_coercion)(parent) - sage: f(0) - 0 - - """ - return self.codomain().coerce(x) - - cdef class RingHomomorphism_im_gens(RingHomomorphism): """ A ring homomorphism determined by the images of generators. @@ -1760,7 +1668,7 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: phi = R.hom([x,x+y]); phi + sage: phi = R.hom([x, x + y]); phi Ring endomorphism of Multivariate Polynomial Ring in x, y over Rational Field Defn: x |--> x y |--> x + y @@ -1769,18 +1677,20 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): Here's another example where the domain isn't free:: - sage: S.<xx,yy> = R.quotient(x - y) - sage: phi = S.hom([xx+1,xx+1]) + sage: S.<xx,yy> = R.quotient(x - y) # needs sage.libs.singular + sage: phi = S.hom([xx + 1, xx + 1]) # needs sage.libs.singular Note that one has to specify valid images:: - sage: phi = S.hom([xx+1,xx-1]) + sage: phi = S.hom([xx + 1, xx - 1]) # needs sage.libs.singular Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators You can give a map of the base ring:: + sage: # needs sage.rings.number_field sage: Zx.<x> = ZZ[] sage: K.<i> = NumberField(x^2 + 1) sage: cc = K.hom([-i]) @@ -1793,9 +1703,9 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): sage: S.<x> = QQ[] sage: T.<y> = S[] - sage: cc = S.hom([x+1]) - sage: f = T.hom([x-y], base_map=cc) - sage: g = T.hom([x-y], base_map=cc.extend_codomain(T)) + sage: cc = S.hom([x + 1]) + sage: f = T.hom([x - y], base_map=cc) + sage: g = T.hom([x - y], base_map=cc.extend_codomain(T)) sage: f == g True sage: f.base_map() == cc.extend_codomain(T) @@ -1806,11 +1716,12 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): speed up creation of a homomorphism:: sage: R.<x,y> = QQ[] - sage: S.<xx,yy> = R.quotient(x - y) - sage: phi = S.hom([xx+1,xx-1], check=False) + sage: S.<xx,yy> = R.quotient(x - y) # needs sage.libs.singular + sage: phi = S.hom([xx + 1, xx - 1], check=False) # needs sage.libs.singular Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators """ RingHomomorphism.__init__(self, parent) if not isinstance(im_gens, sage.structure.sequence.Sequence_generic): @@ -1848,7 +1759,7 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: f = R.hom([x,x+y]) + sage: f = R.hom([x, x + y]) sage: f.im_gens() [x, x + y] @@ -1868,13 +1779,15 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = ZZ[] sage: K.<i> = NumberField(x^2 + 1) sage: cc = K.hom([-i]) sage: S.<y> = K[] sage: phi = S.hom([y^2], base_map=cc) sage: phi - Ring endomorphism of Univariate Polynomial Ring in y over Number Field in i with defining polynomial x^2 + 1 + Ring endomorphism of Univariate Polynomial Ring in y + over Number Field in i with defining polynomial x^2 + 1 Defn: y |--> y^2 with map of base ring sage: phi(y) @@ -1884,13 +1797,15 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): sage: phi.base_map() Composite map: From: Number Field in i with defining polynomial x^2 + 1 - To: Univariate Polynomial Ring in y over Number Field in i with defining polynomial x^2 + 1 + To: Univariate Polynomial Ring in y over Number Field in i + with defining polynomial x^2 + 1 Defn: Ring endomorphism of Number Field in i with defining polynomial x^2 + 1 Defn: i |--> -i then Polynomial base injection morphism: From: Number Field in i with defining polynomial x^2 + 1 - To: Univariate Polynomial Ring in y over Number Field in i with defining polynomial x^2 + 1 + To: Univariate Polynomial Ring in y over Number Field in i + with defining polynomial x^2 + 1 """ return self._base_map @@ -1901,7 +1816,7 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: f = R.hom([x,x+y]) + sage: f = R.hom([x, x + y]) sage: g = copy(f) # indirect doctest sage: g == f True @@ -1921,7 +1836,7 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: f = R.hom([x,x+y]) + sage: f = R.hom([x, x + y]) sage: g = copy(f) # indirect doctest sage: g == f True @@ -1941,6 +1856,7 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): A single variate quotient over `\QQ`:: + sage: # needs sage.libs.pari sage: R.<x> = QQ[] sage: Q.<a> = R.quotient(x^2 + x + 1) sage: f1 = R.hom([a]) @@ -1956,12 +1872,12 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): TESTS:: - sage: loads(dumps(f2)) == f2 + sage: loads(dumps(f2)) == f2 # needs sage.libs.pari True :: - sage: R.<x,y> = QQ[]; f = R.hom([x,x+y]); g = R.hom([y,x]) + sage: R.<x,y> = QQ[]; f = R.hom([x, x + y]); g = R.hom([y, x]) sage: f == g # indirect doctest False @@ -1975,7 +1891,7 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): sage: f2 = R.hom([a + a^2 + a + 1, b + b^2 + b + 1]) sage: f1 == f2 True - sage: f1 == R.hom([b,a]) + sage: f1 == R.hom([b, a]) False sage: x^3 + x + y^2 x^3 + y^2 + x @@ -1986,7 +1902,7 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): TESTS:: - sage: loads(dumps(f2)) == f2 + sage: loads(dumps(f2)) == f2 # needs sage.rings.finite_rings True This was fixed in :trac:`24277`:: @@ -2035,8 +1951,8 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): """ D = self.domain() ig = self._im_gens - s = '\n'.join(['%s |--> %s'%(D.gen(i), ig[i]) for\ - i in range(D.ngens())]) + s = '\n'.join('{} |--> {}'.format(D.gen(i), ig[i]) + for i in range(D.ngens())) if s and self._base_map is not None: s += '\nwith map of base ring' return s @@ -2078,8 +1994,10 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): sage: Pf = PR.hom(f,PS) sage: Pf Ring morphism: - From: Univariate Polynomial Ring in t over Multivariate Polynomial Ring in x, y over Rational Field - To: Univariate Polynomial Ring in t over Univariate Polynomial Ring in z over Rational Field + From: Univariate Polynomial Ring in t + over Multivariate Polynomial Ring in x, y over Rational Field + To: Univariate Polynomial Ring in t + over Univariate Polynomial Ring in z over Rational Field Defn: Induced from base ring by Ring morphism: From: Multivariate Polynomial Ring in x, y over Rational Field @@ -2093,14 +2011,18 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): Similarly, we can construct the induced homomorphism on a matrix ring over our polynomial rings:: - sage: MR = MatrixSpace(R,2,2) - sage: MS = MatrixSpace(S,2,2) - sage: M = MR([x^2 + 1/7*x*y - y^2, - 1/2*y^2 + 2*y + 1/6, 4*x^2 - 14*x, 1/2*y^2 + 13/4*x - 2/11*y]) - sage: Mf = MR.hom(f,MS) + sage: # needs sage.modules + sage: MR = MatrixSpace(R, 2, 2) + sage: MS = MatrixSpace(S, 2, 2) + sage: M = MR([x^2 + 1/7*x*y - y^2, -1/2*y^2 + 2*y + 1/6, + ....: 4*x^2 - 14*x, 1/2*y^2 + 13/4*x - 2/11*y]) + sage: Mf = MR.hom(f, MS) sage: Mf Ring morphism: - From: Full MatrixSpace of 2 by 2 dense matrices over Multivariate Polynomial Ring in x, y over Rational Field - To: Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in z over Rational Field + From: Full MatrixSpace of 2 by 2 dense matrices + over Multivariate Polynomial Ring in x, y over Rational Field + To: Full MatrixSpace of 2 by 2 dense matrices + over Univariate Polynomial Ring in z over Rational Field Defn: Induced from base ring by Ring morphism: From: Multivariate Polynomial Ring in x, y over Rational Field @@ -2113,17 +2035,25 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): The construction of induced homomorphisms is recursive, and so we have:: + sage: # needs sage.modules sage: MPR = MatrixSpace(PR, 2) sage: MPS = MatrixSpace(PS, 2) - sage: M = MPR([(- x + y)*t^2 + 58*t - 3*x^2 + x*y, (- 1/7*x*y - 1/40*x)*t^2 + (5*x^2 + y^2)*t + 2*y, (- 1/3*y + 1)*t^2 + 1/3*x*y + y^2 + 5/2*y + 1/4, (x + 6*y + 1)*t^2]) - sage: MPf = MPR.hom(f,MPS); MPf + sage: M = MPR([(-x + y)*t^2 + 58*t - 3*x^2 + x*y, + ....: (- 1/7*x*y - 1/40*x)*t^2 + (5*x^2 + y^2)*t + 2*y, + ....: (- 1/3*y + 1)*t^2 + 1/3*x*y + y^2 + 5/2*y + 1/4, + ....: (x + 6*y + 1)*t^2]) + sage: MPf = MPR.hom(f, MPS); MPf Ring morphism: - From: Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in t over Multivariate Polynomial Ring in x, y over Rational Field - To: Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in t over Univariate Polynomial Ring in z over Rational Field + From: Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial + Ring in t over Multivariate Polynomial Ring in x, y over Rational Field + To: Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial + Ring in t over Univariate Polynomial Ring in z over Rational Field Defn: Induced from base ring by Ring morphism: - From: Univariate Polynomial Ring in t over Multivariate Polynomial Ring in x, y over Rational Field - To: Univariate Polynomial Ring in t over Univariate Polynomial Ring in z over Rational Field + From: Univariate Polynomial Ring in t + over Multivariate Polynomial Ring in x, y over Rational Field + To: Univariate Polynomial Ring in t + over Univariate Polynomial Ring in z over Rational Field Defn: Induced from base ring by Ring morphism: From: Multivariate Polynomial Ring in x, y over Rational Field @@ -2142,11 +2072,12 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): sage: from sage.rings.morphism import RingHomomorphism_from_base sage: R.<x> = ZZ[] - sage: f = R.hom([2*x],R) - sage: P = MatrixSpace(R,2).Hom(MatrixSpace(R,2)) - sage: g = RingHomomorphism_from_base(P,f) - sage: g - Ring endomorphism of Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring + sage: f = R.hom([2*x], R) + sage: P = MatrixSpace(R, 2).Hom(MatrixSpace(R, 2)) # needs sage.modules + sage: g = RingHomomorphism_from_base(P, f) # needs sage.modules + sage: g # needs sage.modules + Ring endomorphism of Full MatrixSpace of 2 by 2 dense matrices + over Univariate Polynomial Ring in x over Integer Ring Defn: Induced from base ring by Ring endomorphism of Univariate Polynomial Ring in x over Integer Ring Defn: x |--> 2*x @@ -2155,11 +2086,13 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): codomain are constructed in a compatible way. So, the following results in an error:: - sage: P = MatrixSpace(R,2).Hom(R['t']) - sage: g = RingHomomorphism_from_base(P,f) + sage: P = MatrixSpace(R, 2).Hom(R['t']) # needs sage.modules + sage: g = RingHomomorphism_from_base(P, f) # needs sage.modules Traceback (most recent call last): ... - ValueError: domain (Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring) and codomain (Univariate Polynomial Ring in t over Univariate Polynomial Ring in x over Integer Ring) must have the same functorial construction over their base rings + ValueError: domain (Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring) + and codomain (Univariate Polynomial Ring in t over Univariate Polynomial Ring in x over Integer Ring) + must have the same functorial construction over their base rings """ RingHomomorphism.__init__(self, parent) if underlying.domain() != parent.domain().base(): @@ -2176,12 +2109,13 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): EXAMPLES:: + sage: # needs sage.modules sage: R.<x,y> = QQ[] sage: S.<z> = QQ[] - sage: f = R.hom([2*z,3*z],S) - sage: MR = MatrixSpace(R,2) - sage: MS = MatrixSpace(S,2) - sage: g = MR.hom(f,MS) + sage: f = R.hom([2*z, 3*z], S) + sage: MR = MatrixSpace(R, 2) + sage: MS = MatrixSpace(S, 2) + sage: g = MR.hom(f, MS) sage: g.underlying_map() == f True """ @@ -2195,10 +2129,10 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): sage: R.<x,y> = QQ[] sage: S.<z> = QQ[] - sage: f = R.hom([2*z,3*z],S) + sage: f = R.hom([2*z, 3*z],S) sage: PR.<t> = R[] sage: PS = S['t'] - sage: phi = PR.hom(f,PS) + sage: phi = PR.hom(f, PS) sage: type(phi) <class 'sage.rings.morphism.RingHomomorphism_from_base'> sage: psi = copy(phi); psi # indirect doctest @@ -2255,6 +2189,7 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): A multivariate polynomial ring over a single variate quotient over `\QQ`:: + sage: # needs sage.libs.pari sage.libs.singular sage.modules sage: R.<x> = QQ[] sage: Q.<a> = R.quotient(x^2 + x + 1) sage: f1 = R.hom([a]) @@ -2268,12 +2203,12 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): TESTS:: - sage: f1P == loads(dumps(f1P)) + sage: f1P == loads(dumps(f1P)) # needs sage.libs.pari sage.libs.singular sage.modules True - sage: R.<x,y> = QQ[]; f = R.hom([x,x+y]); g = R.hom([y,x]) + sage: R.<x,y> = QQ[]; f = R.hom([x, x + y]); g = R.hom([y, x]) sage: S.<z> = R[] - sage: fS = S.hom(f,S); gS = S.hom(g,S) + sage: fS = S.hom(f, S); gS = S.hom(g, S) sage: fS != gS # indirect doctest True @@ -2281,20 +2216,21 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): A matrix ring over a multivariate quotient over a finite field:: + sage: # needs sage.modules sage: R.<x,y> = GF(7)[] sage: Q.<a,b> = R.quotient([x^2 + x + 1, y^2 + y + 1]) sage: f1 = R.hom([a, b]) sage: f2 = R.hom([a + a^2 + a + 1, b + b^2 + b + 1]) - sage: MR = MatrixSpace(R,2) - sage: MQ = MatrixSpace(Q,2) - sage: f1M = MR.hom(f1,MQ) - sage: f2M = MR.hom(f2,MQ) + sage: MR = MatrixSpace(R, 2) + sage: MQ = MatrixSpace(Q, 2) + sage: f1M = MR.hom(f1, MQ) + sage: f2M = MR.hom(f2, MQ) sage: f1M == f2M True TESTS:: - sage: f1M == loads(dumps(f1M)) + sage: f1M == loads(dumps(f1M)) # needs sage.modules True """ if not isinstance(other, RingHomomorphism_from_base): @@ -2314,11 +2250,12 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): over a multivariate polynomial ring:: sage: R1.<x,y> = ZZ[] - sage: f = R1.hom([x+y,x-y]) - sage: R2 = MatrixSpace(FractionField(R1)['t'],2) - sage: g = R2.hom(f,R2) - sage: g #indirect doctest - Ring endomorphism of Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in t over Fraction Field of Multivariate Polynomial Ring in x, y over Integer Ring + sage: f = R1.hom([x + y, x - y]) + sage: R2 = MatrixSpace(FractionField(R1)['t'], 2) # needs sage.modules + sage: g = R2.hom(f, R2) # needs sage.modules + sage: g # indirect doctest # needs sage.modules + Ring endomorphism of Full MatrixSpace of 2 by 2 dense matrices + over Univariate Polynomial Ring in t over Fraction Field of Multivariate Polynomial Ring in x, y over Integer Ring Defn: Induced from base ring by Ring endomorphism of Univariate Polynomial Ring in t over Fraction Field of Multivariate Polynomial Ring in x, y over Integer Ring Defn: Induced from base ring by @@ -2364,11 +2301,11 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): sage: R.<x,y> = QQ[] sage: S.<a,b> = QQ[] - sage: f = R.hom([a+b, a-b], S) + sage: f = R.hom([a + b, a - b], S) sage: PR.<t> = R[] sage: PS = S['t'] sage: Pf = PR.hom(f, PS) - sage: Pf.inverse() + sage: Pf.inverse() # needs sage.libs.singular Ring morphism: From: Univariate Polynomial Ring in t over Multivariate Polynomial Ring in a, b over Rational Field @@ -2380,7 +2317,7 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): To: Multivariate Polynomial Ring in x, y over Rational Field Defn: a |--> 1/2*x + 1/2*y b |--> 1/2*x - 1/2*y - sage: Pf.inverse()(Pf(x*t^2 + y*t)) + sage: Pf.inverse()(Pf(x*t^2 + y*t)) # needs sage.libs.singular x*t^2 + y*t """ return self.parent().reversed()(self._underlying.inverse()) @@ -2394,8 +2331,8 @@ cdef class RingHomomorphism_from_fraction_field(RingHomomorphism): sage: S.<x> = QQ[] sage: f = S.hom([x^2]) - sage: g = f.extend_to_fraction_field() - sage: type(g) + sage: g = f.extend_to_fraction_field() # needs sage.libs.singular + sage: type(g) # needs sage.libs.singular <class 'sage.rings.morphism.RingHomomorphism_from_fraction_field'> """ def __init__(self, parent, morphism): @@ -2404,6 +2341,8 @@ cdef class RingHomomorphism_from_fraction_field(RingHomomorphism): TESTS:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = ZZ.extension(x^2 - 2) sage: f = A.coerce_map_from(ZZ) sage: g = f.extend_to_fraction_field() # indirect doctest @@ -2422,11 +2361,11 @@ cdef class RingHomomorphism_from_fraction_field(RingHomomorphism): EXAMPLES:: sage: S.<x> = QQ[] - sage: f = S.hom([x^2]).extend_to_fraction_field() - sage: f + sage: f = S.hom([x^2]).extend_to_fraction_field() # needs sage.libs.singular + sage: f # needs sage.libs.singular Ring endomorphism of Fraction Field of Univariate Polynomial Ring in x over Rational Field Defn: x |--> x^2 - sage: f._repr_defn() + sage: f._repr_defn() # needs sage.libs.singular 'x |--> x^2' """ return self._morphism._repr_defn() @@ -2442,10 +2381,10 @@ cdef class RingHomomorphism_from_fraction_field(RingHomomorphism): EXAMPLES:: sage: S.<x> = QQ[] - sage: f = S.hom([x+1]).extend_to_fraction_field() - sage: f(1/x) + sage: f = S.hom([x + 1]).extend_to_fraction_field() # needs sage.libs.singular + sage: f(1/x) # needs sage.libs.singular 1/(x + 1) - sage: f(1/(x-1)) + sage: f(1/(x-1)) # needs sage.libs.singular 1/x """ return self._morphism(x.numerator()) / self._morphism(x.denominator()) @@ -2456,13 +2395,14 @@ cdef class RingHomomorphism_from_fraction_field(RingHomomorphism): TESTS:: + sage: # needs sage.libs.singular sage: S.<x> = QQ[] - sage: f = S.hom([x+1]).extend_to_fraction_field() + sage: f = S.hom([x + 1]).extend_to_fraction_field() - sage: g = copy(f) # indirect doctest - sage: f == g + sage: g = copy(f) # indirect doctest # needs sage.libs.singular + sage: f == g # needs sage.libs.singular True - sage: f is g + sage: f is g # needs sage.libs.singular False """ self._morphism = _slots['_morphism'] @@ -2475,8 +2415,8 @@ cdef class RingHomomorphism_from_fraction_field(RingHomomorphism): TESTS:: sage: S.<x> = QQ[] - sage: f = S.hom([x+1]).extend_to_fraction_field() - sage: loads(dumps(f)) == f + sage: f = S.hom([x + 1]).extend_to_fraction_field() # needs sage.libs.singular + sage: loads(dumps(f)) == f # needs sage.libs.singular True """ slots = RingHomomorphism._extra_slots(self) @@ -2492,10 +2432,10 @@ cdef class RingHomomorphism_from_fraction_field(RingHomomorphism): sage: S.<x> = QQ[] sage: f = S.hom([2*x - 1]) - sage: g = f.extend_to_fraction_field() - sage: g.inverse() + sage: g = f.extend_to_fraction_field() # needs sage.libs.singular + sage: g.inverse() # needs sage.libs.singular Ring endomorphism of Fraction Field of Univariate Polynomial Ring - in x over Rational Field + in x over Rational Field Defn: x |--> 1/2*x + 1/2 """ return self.parent().reversed()(self._morphism.inverse()) @@ -2508,13 +2448,14 @@ cdef class RingHomomorphism_cover(RingHomomorphism): EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ, 2) - sage: S.<a,b> = R.quo(x^2 + y^2) - sage: phi = S.cover(); phi + sage: S.<a,b> = R.quo(x^2 + y^2) # needs sage.libs.singular + sage: phi = S.cover(); phi # needs sage.libs.singular Ring morphism: From: Multivariate Polynomial Ring in x, y over Rational Field - To: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) + To: Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2 + y^2) Defn: Natural quotient map - sage: phi(x+y) + sage: phi(x + y) # needs sage.libs.singular a + b """ def __init__(self, parent): @@ -2551,7 +2492,7 @@ cdef class RingHomomorphism_cover(RingHomomorphism): We verify that calling directly raises the expected error (just coercing into the codomain), but calling with __call__ - (the second call below) gives a TypeError since 1/2 can't be + (the second call below) gives a :class:`TypeError` since 1/2 cannot be coerced into the domain. :: sage: f._call_(1/2) @@ -2561,7 +2502,8 @@ cdef class RingHomomorphism_cover(RingHomomorphism): sage: f(1/2) Traceback (most recent call last): ... - TypeError: 1/2 fails to convert into the map's domain Integer Ring, but a `pushforward` method is not properly implemented + TypeError: 1/2 fails to convert into the map's domain Integer Ring, + but a `pushforward` method is not properly implemented """ return self.codomain()(x) @@ -2598,6 +2540,7 @@ cdef class RingHomomorphism_cover(RingHomomorphism): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S.<a,b> = R.quo(x^2 + y^2) sage: phi = S.cover() @@ -2618,6 +2561,7 @@ cdef class RingHomomorphism_cover(RingHomomorphism): TESTS:: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S.<a,b> = R.quo(x^2 + y^2) sage: phi = S.cover() @@ -2640,6 +2584,7 @@ cdef class RingHomomorphism_cover(RingHomomorphism): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ['x,y'].quotient('x^2 * y^2') sage: R.cover().inverse_image(R.ideal(x^3, y^3 + 1)) Ideal (x^2*y^2, x^3, y^3 + 1) of Multivariate Polynomial Ring @@ -2660,8 +2605,8 @@ cdef class RingHomomorphism_cover(RingHomomorphism): EXAMPLES:: - sage: Q.<u,v> = QQ['x,y'].quotient('x + y') - sage: Q.cover().inverse_image(u) + sage: Q.<u,v> = QQ['x,y'].quotient('x + y') # needs sage.libs.singular + sage: Q.cover().inverse_image(u) # needs sage.libs.singular -y """ return b.lift() @@ -2689,14 +2634,16 @@ cdef class RingHomomorphism_from_quotient(RingHomomorphism): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x, y, z> = PolynomialRing(QQ, 3) sage: S.<a, b, c> = R.quo(x^3 + y^3 + z^3) sage: phi = S.hom([b, c, a]); phi - Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y, z over Rational Field by the ideal (x^3 + y^3 + z^3) + Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y, z + over Rational Field by the ideal (x^3 + y^3 + z^3) Defn: a |--> b b |--> c c |--> a - sage: phi(a+b+c) + sage: phi(a + b + c) a + b + c sage: loads(dumps(phi)) == phi True @@ -2705,10 +2652,11 @@ cdef class RingHomomorphism_from_quotient(RingHomomorphism): ``TypeError`` is raised if there is no homomorphism sending the generators to the given images:: - sage: S.hom([b^2, c^2, a^2]) + sage: S.hom([b^2, c^2, a^2]) # needs sage.libs.singular Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators """ def __init__(self, parent, phi): """ @@ -2716,8 +2664,9 @@ cdef class RingHomomorphism_from_quotient(RingHomomorphism): EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2,y^2]); S.hom([yy,xx]) - Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y^2) + sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2,y^2]); S.hom([yy,xx]) # needs sage.libs.singular + Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y + over Rational Field by the ideal (x^2, y^2) Defn: xx |--> yy yy |--> xx """ @@ -2742,14 +2691,16 @@ cdef class RingHomomorphism_from_quotient(RingHomomorphism): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x, y, z> = PolynomialRing(QQ, 3) sage: S.<a, b, c> = R.quo(x^3 + y^3 + z^3) sage: phi = S.hom([b, c, a]); phi - Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y, z over Rational Field by the ideal (x^3 + y^3 + z^3) + Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y, z + over Rational Field by the ideal (x^3 + y^3 + z^3) Defn: a |--> b b |--> c c |--> a - sage: phi(a+b+c) + sage: phi(a + b + c) a + b + c sage: psi = copy(phi) # indirect doctest sage: psi == phi @@ -2769,14 +2720,16 @@ cdef class RingHomomorphism_from_quotient(RingHomomorphism): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x, y, z> = PolynomialRing(QQ, 3) sage: S.<a, b, c> = R.quo(x^3 + y^3 + z^3) sage: phi = S.hom([b, c, a]); phi - Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y, z over Rational Field by the ideal (x^3 + y^3 + z^3) + Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y, z + over Rational Field by the ideal (x^3 + y^3 + z^3) Defn: a |--> b b |--> c c |--> a - sage: phi(a+b+c) + sage: phi(a + b + c) a + b + c sage: psi = copy(phi) # indirect doctest sage: psi == phi @@ -2797,8 +2750,8 @@ cdef class RingHomomorphism_from_quotient(RingHomomorphism): EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2,y^2]); f = S.hom([yy,xx]) - sage: f._phi() + sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2, y^2]); f = S.hom([yy,xx]) # needs sage.libs.singular + sage: f._phi() # needs sage.libs.singular Ring morphism: From: Multivariate Polynomial Ring in x, y over Rational Field To: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y^2) @@ -2814,11 +2767,12 @@ cdef class RingHomomorphism_from_quotient(RingHomomorphism): EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2,y^2]) - sage: S.hom([yy,xx]).morphism_from_cover() + sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2, y^2]) # needs sage.libs.singular + sage: S.hom([yy,xx]).morphism_from_cover() # needs sage.libs.singular Ring morphism: From: Multivariate Polynomial Ring in x, y over Rational Field - To: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y^2) + To: Quotient of Multivariate Polynomial Ring in x, y + over Rational Field by the ideal (x^2, y^2) Defn: x |--> yy y |--> xx """ @@ -2830,6 +2784,7 @@ cdef class RingHomomorphism_from_quotient(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<x, y, z> = PolynomialRing(GF(19), 3) sage: S.<a, b, c> = R.quo(x^3 + y^3 + z^3) sage: phi = S.hom([b, c, a]) @@ -2854,6 +2809,7 @@ cdef class RingHomomorphism_from_quotient(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<x, y, z> = PolynomialRing(GF(19), 3) sage: S.<a, b, c> = R.quo(x^3 + y^3 + z^3) sage: phi = S.hom([b, c, a]) @@ -2866,21 +2822,22 @@ cdef class RingHomomorphism_from_quotient(RingHomomorphism): """ return hash(self.phi) - def _repr_defn(self): + def _repr_defn(self) -> str: """ Used internally for printing this function. EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2,y^2]); f = S.hom([yy,xx]) - sage: print(f._repr_defn()) + sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2,y^2]) # needs sage.libs.singular + sage: f = S.hom([yy, xx]) # needs sage.libs.singular + sage: print(f._repr_defn()) # needs sage.libs.singular xx |--> yy yy |--> xx """ D = self.domain() ig = self.phi.im_gens() - return '\n'.join(['%s |--> %s'%(D.gen(i), ig[i]) for\ - i in range(D.ngens())]) + return '\n'.join('{} |--> {}'.format(D.gen(i), ig[i]) + for i in range(D.ngens())) cpdef Element _call_(self, x): """ @@ -2888,8 +2845,8 @@ cdef class RingHomomorphism_from_quotient(RingHomomorphism): EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2,y^2]); f = S.hom([yy,xx]) - sage: f(3*x + (1/2)*y) # indirect doctest + sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2, y^2]); f = S.hom([yy, xx]) # needs sage.libs.singular + sage: f(3*x + (1/2)*y) # indirect doctest # needs sage.libs.singular 1/2*xx + 3*yy """ return self.phi(self.lift(x)) @@ -2918,9 +2875,11 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): sage: from sage.rings.morphism import FrobeniusEndomorphism_generic sage: K.<u> = PowerSeriesRing(GF(5)) sage: FrobeniusEndomorphism_generic(K) - Frobenius endomorphism x |--> x^5 of Power Series Ring in u over Finite Field of size 5 + Frobenius endomorphism x |--> x^5 of Power Series Ring in u + over Finite Field of size 5 sage: FrobeniusEndomorphism_generic(K, 2) - Frobenius endomorphism x |--> x^(5^2) of Power Series Ring in u over Finite Field of size 5 + Frobenius endomorphism x |--> x^(5^2) of Power Series Ring in u + over Finite Field of size 5 """ from .ring import CommutativeRing from sage.categories.homset import Hom @@ -2947,6 +2906,7 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K = Frac(GF(5)['T']) sage: phi = K.frobenius_endomorphism() sage: psi = copy(phi) @@ -2967,13 +2927,15 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K = Frac(GF(25)['T']) sage: phi = K.frobenius_endomorphism(2) sage: phi - Frobenius endomorphism x |--> x^(5^2) of Fraction Field of Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 - + Frobenius endomorphism x |--> x^(5^2) of Fraction Field of + Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 sage: psi = loads(dumps(phi)); psi - Frobenius endomorphism x |--> x^(5^2) of Fraction Field of Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 + Frobenius endomorphism x |--> x^(5^2) of Fraction Field of + Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2 sage: phi == psi True """ @@ -2989,10 +2951,12 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): sage: K.<u> = PowerSeriesRing(GF(5)) sage: Frob = K.frobenius_endomorphism(); Frob - Frobenius endomorphism x |--> x^5 of Power Series Ring in u over Finite Field of size 5 + Frobenius endomorphism x |--> x^5 of Power Series Ring in u + over Finite Field of size 5 sage: Frob._repr_() - 'Frobenius endomorphism x |--> x^5 of Power Series Ring in u over Finite Field of size 5' + 'Frobenius endomorphism x |--> x^5 of Power Series Ring in u + over Finite Field of size 5' """ if self._power == 0: s = "Identity endomorphism" @@ -3009,6 +2973,7 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<u> = PowerSeriesRing(GF(5)) sage: Frob = K.frobenius_endomorphism() sage: Frob._repr_short() @@ -3047,11 +3012,12 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): """ TESTS:: + sage: # needs sage.rings.finite_rings sage: K.<u> = PowerSeriesRing(GF(5)) sage: Frob = K.frobenius_endomorphism() sage: Frob(u) u^5 - sage: (Frob^2)(1+u) + sage: (Frob^2)(1 + u) 1 + u^25 """ return x ** self._q @@ -3064,6 +3030,7 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<u> = PowerSeriesRing(GF(5)) sage: Frob = K.frobenius_endomorphism() sage: Frob.power() @@ -3081,9 +3048,11 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): sage: K.<u> = PowerSeriesRing(GF(5)) sage: Frob = K.frobenius_endomorphism(); Frob - Frobenius endomorphism x |--> x^5 of Power Series Ring in u over Finite Field of size 5 + Frobenius endomorphism x |--> x^5 of Power Series Ring in u + over Finite Field of size 5 sage: Frob^2 - Frobenius endomorphism x |--> x^(5^2) of Power Series Ring in u over Finite Field of size 5 + Frobenius endomorphism x |--> x^(5^2) of Power Series Ring in u + over Finite Field of size 5 """ return self.__class__(self.domain(), self.power()*n) @@ -3093,13 +3062,17 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<u> = PowerSeriesRing(GF(5)) sage: f = K.frobenius_endomorphism(); f - Frobenius endomorphism x |--> x^5 of Power Series Ring in u over Finite Field of size 5 + Frobenius endomorphism x |--> x^5 of Power Series Ring in u + over Finite Field of size 5 sage: g = K.frobenius_endomorphism(2); g - Frobenius endomorphism x |--> x^(5^2) of Power Series Ring in u over Finite Field of size 5 + Frobenius endomorphism x |--> x^(5^2) of Power Series Ring in u + over Finite Field of size 5 sage: f * g - Frobenius endomorphism x |--> x^(5^3) of Power Series Ring in u over Finite Field of size 5 + Frobenius endomorphism x |--> x^(5^3) of Power Series Ring in u + over Finite Field of size 5 """ if isinstance(right, FrobeniusEndomorphism_generic): return self.__class__(self.domain(), self._power + right.power()) @@ -3139,11 +3112,11 @@ def _tensor_product_ring(B, A): sage: from sage.rings.morphism import _tensor_product_ring sage: R.<x,y> = QQ[] - sage: S.<u,v> = R.quotient(x^2 + y^2) - sage: Q = _tensor_product_ring(S, R); Q + sage: S.<u,v> = R.quotient(x^2 + y^2) # needs sage.libs.singular + sage: Q = _tensor_product_ring(S, R); Q # needs sage.libs.singular Quotient of Multivariate Polynomial Ring in u, v, x, y over Rational Field by the ideal (u^2 + v^2) - sage: Q.term_order() + sage: Q.term_order() # needs sage.libs.singular Block term order with blocks: (Degree reverse lexicographic term order of length 2, Degree reverse lexicographic term order of length 2) @@ -3160,8 +3133,8 @@ def _tensor_product_ring(B, A): ... ValueError: term ordering must be global """ - from .finite_rings.finite_field_base import is_FiniteField - from .number_field.number_field_base import is_NumberField + from .finite_rings.finite_field_base import FiniteField + from .number_field.number_field_base import NumberField from .polynomial.multi_polynomial_ring import is_MPolynomialRing from .polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing from .polynomial.polynomial_ring import is_PolynomialRing @@ -3178,7 +3151,7 @@ def _tensor_product_ring(B, A): def term_order(A): # univariate rings do not have a term order if (is_PolynomialRing(A) or is_PolynomialQuotientRing(A) - or ((is_NumberField(A) or is_FiniteField(A)) + or (isinstance(A, (NumberField, FiniteField)) and not A.is_prime_field())): return TermOrder('lex', 1) try: @@ -3201,7 +3174,7 @@ def _tensor_product_ring(B, A): elif is_QuotientRing(A): to_R = A.ambient().hom(R_gens_A, R, check=False) return list(to_R(A.defining_ideal()).gens()) - elif ((is_NumberField(A) or is_FiniteField(A)) + elif (isinstance(A, (NumberField, FiniteField)) and not A.is_prime_field()): to_R = A.polynomial_ring().hom(R_gens_A, R, check=False) return [to_R(A.polynomial())] diff --git a/src/sage/rings/multi_power_series_ring.py b/src/sage/rings/multi_power_series_ring.py index 7f0d5d1bfb8..3d96666e222 100644 --- a/src/sage/rings/multi_power_series_ring.py +++ b/src/sage/rings/multi_power_series_ring.py @@ -49,9 +49,9 @@ True sage: TestSuite(M).run() - sage: H = PowerSeriesRing(PolynomialRing(ZZ,3,'z'),4,'f'); H - Multivariate Power Series Ring in f0, f1, f2, f3 over Multivariate - Polynomial Ring in z0, z1, z2 over Integer Ring + sage: H = PowerSeriesRing(PolynomialRing(ZZ, 3, 'z'), 4, 'f'); H + Multivariate Power Series Ring in f0, f1, f2, f3 + over Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring sage: TestSuite(H).run() sage: loads(dumps(H)) is H True @@ -75,6 +75,7 @@ - Use angle-bracket notation:: + sage: # needs sage.rings.finite_rings sage: S.<x,y> = PowerSeriesRing(GF(65537)); S Multivariate Power Series Ring in x, y over Finite Field of size 65537 sage: s = -30077*x + 9485*x*y - 6260*y^3 + 12870*x^2*y^2 - 20289*y^4 + S.O(5); s @@ -89,7 +90,7 @@ sage: ZZ[['s,t,u']] Multivariate Power Series Ring in s, t, u over Integer Ring - sage: GF(127931)[['x,y']] + sage: GF(127931)[['x,y']] # needs sage.rings.finite_rings Multivariate Power Series Ring in x, y over Finite Field of size 127931 Variable ordering determines how series are displayed. @@ -117,16 +118,16 @@ sage: R.<t,u,v> = PowerSeriesRing(QQ); R Multivariate Power Series Ring in t, u, v over Rational Field - sage: R.base_extend(RR) - Multivariate Power Series Ring in t, u, v over Real Field with 53 - bits of precision + sage: R.base_extend(RR) # needs sage.rings.real_mpfr + Multivariate Power Series Ring in t, u, v + over Real Field with 53 bits of precision sage: R.change_ring(IntegerModRing(10)) - Multivariate Power Series Ring in t, u, v over Ring of integers - modulo 10 + Multivariate Power Series Ring in t, u, v + over Ring of integers modulo 10 - sage: S = PowerSeriesRing(GF(65537),2,'x,y'); S + sage: S = PowerSeriesRing(GF(65537),2,'x,y'); S # needs sage.rings.finite_rings Multivariate Power Series Ring in x, y over Finite Field of size 65537 - sage: S.change_ring(GF(5)) + sage: S.change_ring(GF(5)) # needs sage.rings.finite_rings Multivariate Power Series Ring in x, y over Finite Field of size 5 Coercion from polynomial ring:: @@ -159,6 +160,7 @@ Coercion from symbolic ring:: + sage: # needs sage.symbolic sage: x,y = var('x,y') sage: S = PowerSeriesRing(GF(11),2,'x,y'); S Multivariate Power Series Ring in x, y over Finite Field of size 11 @@ -166,7 +168,6 @@ <class 'sage.symbolic.expression.Expression'> sage: type(S(x)) <class 'sage.rings.multi_power_series_ring.MPowerSeriesRing_generic_with_category.element_class'> - sage: f = S(2/7 -100*x^2 + 1/3*x*y + y^2).O(3); f 5 - x^2 + 4*x*y + y^2 + O(x, y)^3 sage: f.parent() @@ -205,7 +206,7 @@ from sage.rings.ring import CommutativeRing -from sage.rings.polynomial.all import PolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.polynomial.term_order import TermOrder @@ -224,18 +225,18 @@ def is_MPowerSeriesRing(x): """ - Return true if input is a multivariate power series ring. + Return ``True`` if input is a multivariate power series ring. TESTS:: sage: from sage.rings.power_series_ring import is_PowerSeriesRing sage: from sage.rings.multi_power_series_ring import is_MPowerSeriesRing - sage: M = PowerSeriesRing(ZZ,4,'v') + sage: M = PowerSeriesRing(ZZ, 4, 'v') sage: is_PowerSeriesRing(M) False sage: is_MPowerSeriesRing(M) True - sage: T = PowerSeriesRing(RR,'v') + sage: T = PowerSeriesRing(RR, 'v') sage: is_PowerSeriesRing(T) True sage: is_MPowerSeriesRing(T) @@ -281,6 +282,7 @@ class MPowerSeriesRing_generic(PowerSeriesRing_generic, Nonexact): # # sparse setting may not be implemented completely Element = MPowerSeries + @staticmethod def __classcall__(cls, base_ring, num_gens, name_list, order='negdeglex', default_prec=10, sparse=False): @@ -290,7 +292,7 @@ def __classcall__(cls, base_ring, num_gens, name_list, TESTS:: - sage: P1 = PowerSeriesRing(QQ, ['f0','f1','f2','f3'], order = TermOrder('degrevlex')) + sage: P1 = PowerSeriesRing(QQ, ['f0','f1','f2','f3'], order=TermOrder('degrevlex')) sage: P2 = PowerSeriesRing(QQ,4,'f', order='degrevlex') sage: P1 is P2 # indirect doctest True @@ -365,8 +367,7 @@ def __init__(self, base_ring, num_gens, name_list, # Multivariate power series rings inherit from power series rings. But # apparently we can not call their initialisation. Instead, initialise # CommutativeRing and Nonexact: - CommutativeRing.__init__(self, base_ring, name_list, category = - _IntegralDomains if base_ring in + CommutativeRing.__init__(self, base_ring, name_list, category=_IntegralDomains if base_ring in _IntegralDomains else _CommutativeRings) Nonexact.__init__(self, default_prec) @@ -402,7 +403,7 @@ def _repr_(self): else: generators_rep = ", ".join(self.variable_names()) - s = "Multivariate Power Series Ring in %s over %s"%(generators_rep, self.base_ring()) + s = "Multivariate Power Series Ring in %s over %s" % (generators_rep, self.base_ring()) if self.is_sparse(): s = 'Sparse ' + s return s @@ -419,11 +420,11 @@ def _latex_(self): '\\Bold{Q}[[v_{0}, v_{1}, v_{2}, v_{3}]]' """ generators_latex = ", ".join(self.latex_variable_names()) - return "%s[[%s]]"%(latex.latex(self.base_ring()), generators_latex) + return "%s[[%s]]" % (latex.latex(self.base_ring()), generators_latex) def is_integral_domain(self, proof=False): """ - Return True if the base ring is an integral domain; otherwise + Return ``True`` if the base ring is an integral domain; otherwise return False. EXAMPLES:: @@ -479,10 +480,10 @@ def characteristic(self): EXAMPLES:: - sage: H = PowerSeriesRing(GF(65537),4,'f'); H + sage: H = PowerSeriesRing(GF(65537),4,'f'); H # needs sage.rings.finite_rings Multivariate Power Series Ring in f0, f1, f2, f3 over Finite Field of size 65537 - sage: H.characteristic() + sage: H.characteristic() # needs sage.rings.finite_rings 65537 """ return self.base_ring().characteristic() @@ -493,12 +494,12 @@ def construction(self): EXAMPLES:: - sage: M = PowerSeriesRing(QQ,4,'f'); M + sage: M = PowerSeriesRing(QQ, 4, 'f'); M Multivariate Power Series Ring in f0, f1, f2, f3 over Rational Field sage: (c,R) = M.construction(); (c,R) (Completion[('f0', 'f1', 'f2', 'f3'), prec=12], - Multivariate Polynomial Ring in f0, f1, f2, f3 over Rational Field) + Multivariate Polynomial Ring in f0, f1, f2, f3 over Rational Field) sage: c Completion[('f0', 'f1', 'f2', 'f3'), prec=12] sage: c(R) @@ -543,7 +544,7 @@ def change_ring(self, R): sage: R.<t,u,v> = PowerSeriesRing(QQ); R Multivariate Power Series Ring in t, u, v over Rational Field - sage: R.base_extend(RR) + sage: R.base_extend(RR) # needs sage.rings.real_mpfr Multivariate Power Series Ring in t, u, v over Real Field with 53 bits of precision sage: R.change_ring(IntegerModRing(10)) @@ -555,15 +556,13 @@ def change_ring(self, R): TypeError: no base extension defined - sage: S = PowerSeriesRing(GF(65537),2,'x,y'); S + sage: S = PowerSeriesRing(GF(65537),2,'x,y'); S # needs sage.rings.finite_rings Multivariate Power Series Ring in x, y over Finite Field of size 65537 - sage: S.change_ring(GF(5)) + sage: S.change_ring(GF(5)) # needs sage.rings.finite_rings Multivariate Power Series Ring in x, y over Finite Field of size 5 """ - return PowerSeriesRing(R, names = self.variable_names(), default_prec = self.default_prec()) - - + return PowerSeriesRing(R, names=self.variable_names(), default_prec=self.default_prec()) def remove_var(self, *var): """ @@ -579,11 +578,11 @@ def remove_var(self, *var): sage: M = PowerSeriesRing(GF(5),5,'t'); M - Multivariate Power Series Ring in t0, t1, t2, t3, t4 over - Finite Field of size 5 + Multivariate Power Series Ring in t0, t1, t2, t3, t4 + over Finite Field of size 5 sage: M.remove_var(M.gens()[3]) - Multivariate Power Series Ring in t0, t1, t2, t4 over Finite - Field of size 5 + Multivariate Power Series Ring in t0, t1, t2, t4 + over Finite Field of size 5 Removing all variables results in the base ring:: @@ -676,8 +675,8 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): EXAMPLES:: sage: R.<a,b,c> = PowerSeriesRing(Zmod(8)); R - Multivariate Power Series Ring in a, b, c over Ring of integers - modulo 8 + Multivariate Power Series Ring in a, b, c + over Ring of integers modulo 8 sage: M = PowerSeriesRing(ZZ,3,'x,y,z') sage: M._is_valid_homomorphism_(R,[a,c,b]) True @@ -710,12 +709,13 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): You must either give a base map or there must be a coercion from the base ring to the codomain:: + sage: # needs sage.rings.number_field sage: T.<t> = ZZ[] sage: K.<i> = NumberField(t^2 + 1) sage: Q8.<z> = CyclotomicField(8) sage: X.<x> = PowerSeriesRing(Q8) sage: M.<a,b,c> = PowerSeriesRing(K) - sage: M._is_valid_homomorphism_(X, [x,x,x+x^2]) # no coercion + sage: M._is_valid_homomorphism_(X, [x,x,x+x^2]) # no coercion False sage: M._is_valid_homomorphism_(X, [x,x,x+x^2], base_map=K.hom([z^2])) True @@ -759,6 +759,7 @@ def _coerce_map_from_(self, P): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A = GF(17)[['x','y']] sage: A.has_coerce_map_from(ZZ) True @@ -779,12 +780,12 @@ def _coerce_map_from_(self, P): TESTS:: - sage: M = PowerSeriesRing(ZZ,3,'x,y,z') + sage: M = PowerSeriesRing(ZZ, 3, 'x,y,z') sage: M._coerce_map_from_(M) True - sage: M._coerce_map_from_(M.remove_var(x)) + sage: M._coerce_map_from_(M.remove_var(x)) # needs sage.symbolic True - sage: M._coerce_map_from_(PowerSeriesRing(ZZ,x)) + sage: M._coerce_map_from_(PowerSeriesRing(ZZ,x)) # needs sage.symbolic True sage: M._coerce_map_from_(PolynomialRing(ZZ,'x,z')) True @@ -802,7 +803,8 @@ def _coerce_map_from_(self, P): sage: P = PolynomialRing(ZZ,3,'z') sage: H = PowerSeriesRing(P,4,'f'); H - Multivariate Power Series Ring in f0, f1, f2, f3 over Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring + Multivariate Power Series Ring in f0, f1, f2, f3 over + Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring sage: H._coerce_map_from_(P) True sage: H._coerce_map_from_(P.remove_var(P.gen(1))) @@ -921,11 +923,11 @@ def is_sparse(self): EXAMPLES:: - sage: M = PowerSeriesRing(ZZ,3,'s,t,u'); M + sage: M = PowerSeriesRing(ZZ, 3, 's,t,u'); M Multivariate Power Series Ring in s, t, u over Integer Ring sage: M.is_sparse() False - sage: N = PowerSeriesRing(ZZ,3,'s,t,u',sparse=True); N + sage: N = PowerSeriesRing(ZZ, 3, 's,t,u', sparse=True); N Sparse Multivariate Power Series Ring in s, t, u over Integer Ring sage: N.is_sparse() True @@ -938,11 +940,11 @@ def is_dense(self): EXAMPLES:: - sage: M = PowerSeriesRing(ZZ,3,'s,t,u'); M + sage: M = PowerSeriesRing(ZZ, 3, 's,t,u'); M Multivariate Power Series Ring in s, t, u over Integer Ring sage: M.is_dense() True - sage: N = PowerSeriesRing(ZZ,3,'s,t,u',sparse=True); N + sage: N = PowerSeriesRing(ZZ, 3, 's,t,u', sparse=True); N Sparse Multivariate Power Series Ring in s, t, u over Integer Ring sage: N.is_dense() False @@ -955,7 +957,7 @@ def gen(self, n=0): EXAMPLES:: - sage: M = PowerSeriesRing(ZZ,10,'v') + sage: M = PowerSeriesRing(ZZ, 10, 'v') sage: M.gen(6) v6 """ @@ -970,7 +972,7 @@ def ngens(self): EXAMPLES:: - sage: M = PowerSeriesRing(ZZ,10,'v') + sage: M = PowerSeriesRing(ZZ, 10, 'v') sage: M.ngens() 10 """ @@ -986,8 +988,8 @@ def prec_ideal(self): sage: A.<s,t,u> = PowerSeriesRing(ZZ) sage: A.prec_ideal() - Ideal (s, t, u) of Multivariate Polynomial Ring in s, t, u over - Integer Ring + Ideal (s, t, u) of + Multivariate Polynomial Ring in s, t, u over Integer Ring """ return self._poly_ring().ideal(self._poly_ring().gens()) diff --git a/src/sage/rings/multi_power_series_ring_element.py b/src/sage/rings/multi_power_series_ring_element.py index 91ac18389c2..bd6fbde6247 100644 --- a/src/sage/rings/multi_power_series_ring_element.py +++ b/src/sage/rings/multi_power_series_ring_element.py @@ -29,7 +29,7 @@ sage: f*g - g 2*s^2*t^2 + O(s, t)^5 - sage: f*=s; f + sage: f *= s; f s + 2*s^2 + 3*s^3 + O(s, t)^8 sage: f%2 s + s^3 + O(s, t)^8 @@ -56,43 +56,43 @@ sage: f = s^2 + s*t + s^3 + s^2*t + 3*s^4 + 3*s^3*t + R.O(5); f s^2 + s*t + s^3 + s^2*t + 3*s^4 + 3*s^3*t + O(s, t)^5 - sage: f(t,s) + sage: f(t, s) s*t + t^2 + s*t^2 + t^3 + 3*s*t^3 + 3*t^4 + O(s, t)^5 - sage: f(t^2,s^2) + sage: f(t^2, s^2) s^2*t^2 + t^4 + s^2*t^4 + t^6 + 3*s^2*t^6 + 3*t^8 + O(s, t)^10 Substitution is defined only for elements of positive valuation, unless `f` has infinite precision:: - sage: f(t^2,s^2+1) + sage: f(t^2, s^2 + 1) Traceback (most recent call last): ... TypeError: Substitution defined only for elements of positive valuation, unless self has infinite precision. sage: g = f.truncate() - sage: g(t^2,s^2+1) + sage: g(t^2, s^2 + 1) t^2 + s^2*t^2 + 2*t^4 + s^2*t^4 + 4*t^6 + 3*s^2*t^6 + 3*t^8 - sage: g(t^2,(s^2+1).O(3)) + sage: g(t^2, (s^2+1).O(3)) t^2 + s^2*t^2 + 2*t^4 + O(s, t)^5 0 has valuation ``+Infinity``:: - sage: f(t^2,0) + sage: f(t^2, 0) t^4 + t^6 + 3*t^8 + O(s, t)^10 - sage: f(t^2,s^2+s) + sage: f(t^2, s^2 + s) s*t^2 + s^2*t^2 + t^4 + O(s, t)^5 Substitution of power series with finite precision works too:: - sage: f(s.O(2),t) + sage: f(s.O(2), t) s^2 + s*t + O(s, t)^3 - sage: f(f,f) + sage: f(f, f) 2*s^4 + 4*s^3*t + 2*s^2*t^2 + 4*s^5 + 8*s^4*t + 4*s^3*t^2 + 16*s^6 + 34*s^5*t + 20*s^4*t^2 + 2*s^3*t^3 + O(s, t)^7 - sage: t(f,f) + sage: t(f, f) s^2 + s*t + s^3 + s^2*t + 3*s^4 + 3*s^3*t + O(s, t)^5 - sage: t(0,f) == s(f,0) + sage: t(0, f) == s(f, 0) True The ``subs`` syntax works as expected:: @@ -100,10 +100,10 @@ sage: r0 = -t^2 - s*t^3 - 2*t^6 + s^7 + s^5*t^2 + R.O(10) sage: r1 = s^4 - s*t^4 + s^6*t - 4*s^2*t^5 - 6*s^3*t^5 + R.O(10) sage: r2 = 2*s^3*t^2 - 2*s*t^4 - 2*s^3*t^4 + s*t^7 + R.O(10) - sage: r0.subs({t:r2,s:r1}) + sage: r0.subs({t: r2, s: r1}) -4*s^6*t^4 + 8*s^4*t^6 - 4*s^2*t^8 + 8*s^6*t^6 - 8*s^4*t^8 - 4*s^4*t^9 + 4*s^2*t^11 - 4*s^6*t^8 + O(s, t)^15 - sage: r0.subs({t:r2,s:r1}) == r0(r1,r2) + sage: r0.subs({t: r2, s: r1}) == r0(r1, r2) True Construct ring homomorphisms from one power series ring to another:: @@ -252,10 +252,9 @@ class MPowerSeries(PowerSeries): sage: g = 1 + s + t - s*t + S.O(5); g 1 + s + t - s*t + O(s, t)^5 - sage: T = PowerSeriesRing(GF(3),5,'t'); T - Multivariate Power Series Ring in t0, t1, t2, t3, t4 over Finite - Field of size 3 + Multivariate Power Series Ring in t0, t1, t2, t3, t4 + over Finite Field of size 3 sage: t = T.gens() sage: w = t[0] - 2*t[1]*t[3] + 5*t[4]^3 - t[0]^3*t[2]^2; w t0 + t1*t3 - t4^3 - t0^3*t2^2 @@ -271,16 +270,17 @@ class MPowerSeries(PowerSeries): Get random elements:: - sage: S.random_element(4) # random + sage: S.random_element(4) # random -2*t + t^2 - 12*s^3 + O(s, t)^4 - sage: T.random_element(10) # random + sage: T.random_element(10) # random -t1^2*t3^2*t4^2 + t1^5*t3^3*t4 + O(t0, t1, t2, t3, t4)^10 Convert elements from polynomial rings:: - sage: R = PolynomialRing(ZZ,5,T.variable_names()) + sage: # needs sage.rings.finite_rings + sage: R = PolynomialRing(ZZ, 5, T.variable_names()) sage: t = R.gens() sage: r = -t[2]*t[3] + t[3]^2 + t[4]^2 sage: T(r) @@ -313,10 +313,12 @@ def __init__(self, parent, x=0, prec=infinity, is_gen=False, check=False): sage: g.parent() Multivariate Power Series Ring in s, t over Rational Field - sage: K = NumberField(x-3,'a') - sage: g = K.random_element()*f - sage: g.parent() - Multivariate Power Series Ring in s, t over Number Field in a with defining polynomial x - 3 + sage: x = polygen(ZZ, 'x') + sage: K = NumberField(x - 3,'a') # needs sage.rings.number_field + sage: g = K.random_element()*f # needs sage.rings.number_field + sage: g.parent() # needs sage.rings.number_field + Multivariate Power Series Ring in s, t over + Number Field in a with defining polynomial x - 3 TESTS:: @@ -355,7 +357,6 @@ def __init__(self, parent, x=0, prec=infinity, is_gen=False, check=False): except AttributeError: pass - # set the correct background value, depending on what type of input x is try: xparent = x.parent() # 'int' types have no parent @@ -457,6 +458,7 @@ def __call__(self, *x, **kwds): Since :trac:`26105` you can specify a map on the base ring:: + sage: # needs sage.rings.number_field sage: Zx.<x> = ZZ[] sage: K.<i> = NumberField(x^2 + 1) sage: cc = K.hom([-i]) @@ -511,33 +513,33 @@ def _subs_formal(self, *x, **kwds): z sage: f = -2/33*s*t^2 - 1/5*t^5 - s^5*t + s^2*t^4 - sage: f(z,z) #indirect doctest + sage: f(z,z) # indirect doctest -2/33*z^3 - 1/5*z^5 - sage: f(z,1) #indirect doctest + sage: f(z,1) # indirect doctest -1/5 - 2/33*z + z^2 - z^5 - sage: RF = RealField(10) - sage: f(z,RF(1)) #indirect doctest + sage: RF = RealField(10) # needs sage.rings.real_mpfr + sage: f(z, RF(1)) # indirect doctest # needs sage.rings.real_mpfr -0.20 - 0.061*z + 1.0*z^2 - 0.00*z^3 - 0.00*z^4 - 1.0*z^5 - sage: m = matrix(QQ,[[1,0,1],[0,2,1],[-1,0,0]]) - sage: m + sage: m = matrix(QQ,[[1,0,1],[0,2,1],[-1,0,0]]); m # needs sage.modules [ 1 0 1] [ 0 2 1] [-1 0 0] - sage: f(m,m) #indirect doctest + sage: f(m,m) # indirect doctest # needs sage.modules [ 2/33 0 1/5] [ 131/55 -1136/165 -24/11] [ -1/5 0 -23/165] - sage: f(m,m) == -2/33*m^3 - 1/5*m^5 #indirect doctest + sage: f(m,m) == -2/33*m^3 - 1/5*m^5 # indirect doctest # needs sage.modules True sage: f = f.add_bigoh(10) sage: f(z,z) -2/33*z^3 - 1/5*z^5 + O(z^10) - sage: f(m,m) + sage: f(m,m) # needs sage.modules Traceback (most recent call last): ... - AttributeError: 'sage.matrix.matrix_rational_dense.Matrix_rational_dense' object has no attribute 'add_bigoh' + AttributeError: 'sage.matrix.matrix_rational_dense.Matrix_rational_dense' + object has no attribute 'add_bigoh' """ from sage.misc.misc_c import prod @@ -592,7 +594,7 @@ def _repr_(self): if self._prec == infinity: return "%s" % self._value() return "%(val)s + O(%(gens)s)^%(prec)s" \ - %{'val':self._value(), + % {'val':self._value(), 'gens':', '.join(str(g) for g in self.parent().gens()), 'prec':self._prec} @@ -605,8 +607,8 @@ def _latex_(self): sage: M = PowerSeriesRing(GF(5),3,'t'); M Multivariate Power Series Ring in t0, t1, t2 over Finite Field of size 5 sage: t = M.gens() - sage: f = -t[0]^4*t[1]^3*t[2]^4 - 2*t[0]*t[1]^4*t[2]^7 \ - + 2*t[1]*t[2]^12 + 2*t[0]^7*t[1]^5*t[2]^2 + M.O(15) + sage: f = (-t[0]^4*t[1]^3*t[2]^4 - 2*t[0]*t[1]^4*t[2]^7 + ....: + 2*t[1]*t[2]^12 + 2*t[0]^7*t[1]^5*t[2]^2 + M.O(15)) sage: f -t0^4*t1^3*t2^4 - 2*t0*t1^4*t2^7 + 2*t1*t2^12 + 2*t0^7*t1^5*t2^2 + O(t0, t1, t2)^15 @@ -627,11 +629,10 @@ def _latex_(self): if self._prec == infinity: return "%s" % self._value()._latex_() return "%(val)s + O(%(gens)s)^{%(prec)s}" \ - %{'val':self._value()._latex_(), + % {'val':self._value()._latex_(), 'gens':', '.join(g._latex_() for g in self.parent().gens()), 'prec':self._prec} - def _im_gens_(self, codomain, im_gens, base_map=None): """ Returns the image of this series under the map that sends the @@ -891,27 +892,25 @@ def quo_rem(self, other, precision=None): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<a,b,c> = PowerSeriesRing(ZZ) sage: f = 1 + a + b - a*b + R.O(3) sage: g = 1 + 2*a - 3*a*b + R.O(3) sage: q, r = f.quo_rem(g); q, r (1 - a + b + 2*a^2 + O(a, b, c)^3, 0 + O(a, b, c)^3) - sage: f == q*g+r + sage: f == q*g + r True - sage: q, r = (a*f).quo_rem(g); q, r (a - a^2 + a*b + 2*a^3 + O(a, b, c)^4, 0 + O(a, b, c)^4) - sage: a*f == q*g+r + sage: a*f == q*g + r True - sage: q, r = (a*f).quo_rem(a*g); q, r (1 - a + b + 2*a^2 + O(a, b, c)^3, 0 + O(a, b, c)^4) - sage: a*f == q*(a*g)+r + sage: a*f == q*(a*g) + r True - sage: q, r = (a*f).quo_rem(b*g); q, r (a - 3*a^2 + O(a, b, c)^3, a + a^2 + O(a, b, c)^4) - sage: a*f == q*(b*g)+r + sage: a*f == q*(b*g) + r True Trying to divide two polynomials, we run into the issue that @@ -920,55 +919,54 @@ def quo_rem(self, other, precision=None): algorithm would never terminate). Here, default precision comes to our help:: - sage: (1+a^3).quo_rem(a+a^2) - (a^2 - a^3 + a^4 - a^5 + a^6 - a^7 + a^8 - a^9 + a^10 + O(a, b, c)^11, 1 + O(a, b, c)^12) - - sage: (1+a^3+a*b).quo_rem(b+c) + sage: # needs sage.libs.singular + sage: (1 + a^3).quo_rem(a + a^2) + (a^2 - a^3 + a^4 - a^5 + a^6 - a^7 + a^8 - a^9 + a^10 + O(a, b, c)^11, + 1 + O(a, b, c)^12) + sage: (1 + a^3 + a*b).quo_rem(b + c) (a + O(a, b, c)^11, 1 - a*c + a^3 + O(a, b, c)^12) - sage: (1+a^3+a*b).quo_rem(b+c, precision=17) + sage: (1 + a^3 + a*b).quo_rem(b + c, precision=17) (a + O(a, b, c)^16, 1 - a*c + a^3 + O(a, b, c)^17) - - sage: (a^2+b^2+c^2).quo_rem(a+b+c) + sage: (a^2 + b^2 + c^2).quo_rem(a + b + c) (a - b - c + O(a, b, c)^11, 2*b^2 + 2*b*c + 2*c^2 + O(a, b, c)^12) - - sage: (a^2+b^2+c^2).quo_rem(1/(1+a+b+c)) - (a^2 + b^2 + c^2 + a^3 + a^2*b + a^2*c + a*b^2 + a*c^2 + b^3 + b^2*c + b*c^2 + c^3 + O(a, b, c)^14, + sage: (a^2 + b^2 + c^2).quo_rem(1/(1+a+b+c)) + (a^2 + b^2 + c^2 + a^3 + a^2*b + a^2*c + a*b^2 + a*c^2 + + b^3 + b^2*c + b*c^2 + c^3 + O(a, b, c)^14, 0) - - sage: (a^2+b^2+c^2).quo_rem(a/(1+a+b+c)) + sage: (a^2 + b^2 + c^2).quo_rem(a/(1+a+b+c)) (a + a^2 + a*b + a*c + O(a, b, c)^13, b^2 + c^2) - - sage: (1+a+a^15).quo_rem(a^2) + sage: (1 + a + a^15).quo_rem(a^2) (0 + O(a, b, c)^10, 1 + a + O(a, b, c)^12) - sage: (1+a+a^15).quo_rem(a^2, precision=15) + sage: (1 + a + a^15).quo_rem(a^2, precision=15) (0 + O(a, b, c)^13, 1 + a + O(a, b, c)^15) - sage: (1+a+a^15).quo_rem(a^2, precision=16) + sage: (1 + a + a^15).quo_rem(a^2, precision=16) (a^13 + O(a, b, c)^14, 1 + a + O(a, b, c)^16) Illustrating the dependency on the ordering of variables:: - sage: (1+a+b).quo_rem(b+c) + sage: # needs sage.libs.singular + sage: (1 + a + b).quo_rem(b + c) (1 + O(a, b, c)^11, 1 + a - c + O(a, b, c)^12) - sage: (1+b+c).quo_rem(c+a) + sage: (1 + b + c).quo_rem(c + a) (0 + O(a, b, c)^11, 1 + b + c + O(a, b, c)^12) - sage: (1+c+a).quo_rem(a+b) + sage: (1 + c + a).quo_rem(a + b) (1 + O(a, b, c)^11, 1 - b + c + O(a, b, c)^12) TESTS:: - sage: (f).quo_rem(R.zero()) + sage: (f).quo_rem(R.zero()) # needs sage.libs.singular Traceback (most recent call last): ... ZeroDivisionError - sage: (f).quo_rem(R.zero().add_bigoh(2)) + sage: (f).quo_rem(R.zero().add_bigoh(2)) # needs sage.libs.singular Traceback (most recent call last): ... ZeroDivisionError Coercion is applied on ``other``:: - sage: (a+b).quo_rem(1) + sage: (a + b).quo_rem(1) # needs sage.libs.singular (a + b + O(a, b, c)^12, 0 + O(a, b, c)^12) sage: R.<a,b,c> = PowerSeriesRing(QQ) @@ -1036,7 +1034,7 @@ def _div_(self, denom_r): When possible, division by non-units also works:: - sage: a/(a*f) + sage: a/(a*f) # needs sage.libs.singular 1 - a - b + a^2 + 3*a*b + b^2 + O(a, b, c)^3 sage: a/(R.zero()) @@ -1045,21 +1043,21 @@ def _div_(self, denom_r): sage: (a*f)/f a + O(a, b, c)^4 - sage: f/(a*f) + sage: f/(a*f) # needs sage.libs.singular Traceback (most recent call last): ... ValueError: not divisible An example where one loses precision:: - sage: ((1+a)*f - f) / a*f + sage: ((1+a)*f - f) / a*f # needs sage.libs.singular 1 + 2*a + 2*b + O(a, b, c)^2 TESTS:: sage: ((a+b)*f) / f == (a+b) True - sage: ((a+b)*f) / (a+b) == f + sage: ((a+b)*f) / (a+b) == f # needs sage.libs.singular True """ if denom_r.is_unit(): # faster if denom_r is a unit @@ -1082,7 +1080,7 @@ def __mod__(self, other): False sage: g in R.base_extend(Zmod(2)) True - sage: g.polynomial() == f.polynomial() % 2 + sage: g.polynomial() == f.polynomial() % 2 # needs sage.libs.singular True """ if isinstance(other, (int, Integer)): @@ -1218,7 +1216,7 @@ def coefficients(self): tmp = {} for j in self._bg_value.coefficients(): for m in j.monomials(): - tmp[self.parent(m)]=j.monomial_coefficient(self.parent()._poly_ring(m)) + tmp[self.parent(m)] = j.monomial_coefficient(self.parent()._poly_ring(m)) return tmp def constant_coefficient(self): @@ -1394,9 +1392,10 @@ def valuation(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<a,b> = PowerSeriesRing(GF(4949717)); R - Multivariate Power Series Ring in a, b over Finite Field of - size 4949717 + Multivariate Power Series Ring in a, b + over Finite Field of size 4949717 sage: f = a^2 + a*b + a^3 + R.O(9) sage: f.valuation() 2 @@ -1443,8 +1442,7 @@ def is_nilpotent(self): EXAMPLES:: sage: R.<a,b,c> = PowerSeriesRing(Zmod(8)); R - Multivariate Power Series Ring in a, b, c over Ring of integers - modulo 8 + Multivariate Power Series Ring in a, b, c over Ring of integers modulo 8 sage: f = a + b + c + a^2*c sage: f.is_nilpotent() False @@ -1537,7 +1535,7 @@ def is_square(self): TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.is_square() Traceback (most recent call last): @@ -1553,7 +1551,7 @@ def square_root(self): TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.square_root() Traceback (most recent call last): @@ -1571,7 +1569,7 @@ def derivative(self, *args): EXAMPLES:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a^2*b + T.O(5) sage: f.derivative(a) 1 + 2*a*b + O(a, b)^4 @@ -1604,7 +1602,7 @@ def integral(self, *args): EXAMPLES:: - sage: T.<a,b> = PowerSeriesRing(QQ,2) + sage: T.<a,b> = PowerSeriesRing(QQ, 2) sage: f = a + b + a^2*b + T.O(5) sage: f.integral(a, 2) 1/6*a^3 + 1/2*a^2*b + 1/12*a^4*b + O(a, b)^7 @@ -1615,7 +1613,7 @@ def integral(self, *args): Only integration with respect to variables works:: - sage: f.integral(a+b) + sage: f.integral(a + b) Traceback (most recent call last): ... ValueError: a + b is not a variable @@ -1628,7 +1626,7 @@ def integral(self, *args): first case, Sage will report that it has not been able to coerce some coefficient to the base ring:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + T.O(5) sage: f.integral(a) Traceback (most recent call last): @@ -1650,7 +1648,7 @@ def integral(self, *args): In non-zero characteristic, Sage will report that a zero division occurred :: - sage: T.<a,b> = PowerSeriesRing(Zmod(3),2) + sage: T.<a,b> = PowerSeriesRing(Zmod(3), 2) sage: (a^3).integral(a) a^4 sage: (a^2).integral(a) @@ -1726,7 +1724,7 @@ def ogf(self): TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.ogf() Traceback (most recent call last): @@ -1741,7 +1739,7 @@ def egf(self): TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.egf() Traceback (most recent call last): @@ -1756,7 +1754,7 @@ def __pari__(self): TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.__pari__() Traceback (most recent call last): @@ -1765,8 +1763,6 @@ def __pari__(self): """ raise NotImplementedError("__pari__") - - ### ### the following don't make sense for multivariable power series ### @@ -1777,7 +1773,7 @@ def list(self): TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.list() Traceback (most recent call last): @@ -1788,14 +1784,13 @@ def list(self): #return [self.parent(c) for c in self._bg_value.list()] raise NotImplementedError("Multivariate power series do not have list of coefficients; use 'coefficients' to get a dict of coefficients.") - def variable(self): """ Doesn't make sense for multivariate power series. TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.variable() Traceback (most recent call last): @@ -1811,7 +1806,7 @@ def shift(self, n): TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.shift(3) Traceback (most recent call last): @@ -1826,7 +1821,7 @@ def __lshift__(self, n): TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.__lshift__(3) Traceback (most recent call last): @@ -1841,7 +1836,7 @@ def __rshift__(self, n): TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.__rshift__(3) Traceback (most recent call last): @@ -1857,7 +1852,7 @@ def valuation_zero_part(self): TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.valuation_zero_part() Traceback (most recent call last): @@ -1873,7 +1868,7 @@ def solve_linear_de(self, prec=infinity, b=None, f0=None): TESTS:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(5) sage: f.solve_linear_de() Traceback (most recent call last): @@ -1898,7 +1893,7 @@ def exp(self, prec=infinity): EXAMPLES:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = a + b + a*b + T.O(3) sage: exp(f) 1 + a + b + 1/2*a^2 + 2*a*b + 1/2*b^2 + O(a, b)^3 @@ -1914,8 +1909,8 @@ def exp(self, prec=infinity): power series over the :class:`~sage.symbolic.ring.SymbolicRing`. These are not yet implemented and therefore such cases raise an error:: - sage: g = 2+f - sage: exp(g) + sage: g = 2 + f + sage: exp(g) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for *: 'Symbolic Ring' and @@ -1949,9 +1944,12 @@ def exp(self, prec=infinity): R = self.parent() Rbg = R._bg_power_series_ring - from sage.functions.log import exp c = self.constant_coefficient() - exp_c = exp(c) + if not c: + exp_c = self.base_ring().one() + else: + from sage.functions.log import exp + exp_c = exp(c) x = self._bg_value - c if x.is_zero(): return exp_c @@ -1990,7 +1988,7 @@ def log(self, prec=infinity): EXAMPLES:: - sage: T.<a,b> = PowerSeriesRing(ZZ,2) + sage: T.<a,b> = PowerSeriesRing(ZZ, 2) sage: f = 1 + a + b + a*b + T.O(5) sage: f.log() a + b - 1/2*a^2 - 1/2*b^2 + 1/3*a^3 + 1/3*b^3 - 1/4*a^4 - 1/4*b^4 + O(a, b)^5 @@ -2004,8 +2002,8 @@ def log(self, prec=infinity): power series over the :class:`~sage.symbolic.ring.SymbolicRing`. These are not yet implemented and therefore such cases raise an error:: - sage: g = 2+f - sage: log(g) + sage: g = 2 + f + sage: log(g) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for -: 'Symbolic Ring' and 'Power @@ -2041,11 +2039,14 @@ def log(self, prec=infinity): R = self.parent() Rbg = R._bg_power_series_ring - from sage.functions.log import log c = self.constant_coefficient() if c.is_zero(): raise ValueError('Can only take formal power series for non-zero constant term.') - log_c = log(c) + if c.is_one(): + log_c = self.base_ring().zero() + else: + from sage.functions.log import log + log_c = log(c) x = 1 - self._bg_value/c if x.is_zero(): return log_c @@ -2095,7 +2096,7 @@ class MO(): sage: m^1 0 + O(u, v)^1 - sage: T.<a,b,c> = PowerSeriesRing(ZZ,3) + sage: T.<a,b,c> = PowerSeriesRing(ZZ, 3) sage: z = O(a, b, c) sage: z^1 0 + O(a, b, c)^1 diff --git a/src/sage/rings/noncommutative_ideals.pyx b/src/sage/rings/noncommutative_ideals.pyx index 0661987be2a..6965f1c6c61 100644 --- a/src/sage/rings/noncommutative_ideals.pyx +++ b/src/sage/rings/noncommutative_ideals.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modules """ Ideals of non-commutative rings @@ -38,6 +39,7 @@ algebras. TESTS:: + sage: # needs sage.combinat sage: A = SteenrodAlgebra(2) sage: IL = A*[A.1+A.2,A.1^2]; IL Left Ideal (Sq(2) + Sq(4), Sq(1,1)) of mod 2 Steenrod algebra, milnor basis @@ -114,6 +116,7 @@ class IdealMonoid_nc(IdealMonoid_c): TESTS:: + sage: # needs sage.combinat sage: A = SteenrodAlgebra(2) # indirect doctest sage: IL = A*[A.1+A.2,A.1^2]; IL Left Ideal (Sq(2) + Sq(4), Sq(1,1)) of mod 2 Steenrod algebra, milnor basis @@ -127,6 +130,7 @@ class IdealMonoid_nc(IdealMonoid_c): :: + sage: # needs sage.combinat sage: IL == loads(dumps(IL)) True sage: IR == loads(dumps(IR)) @@ -243,6 +247,7 @@ class Ideal_nc(Ideal_generic): TESTS:: + sage: # needs sage.combinat sage: A = SteenrodAlgebra(2) sage: A*[A.1+A.2,A.1^2] # indirect doctest Left Ideal (Sq(2) + Sq(4), Sq(1,1)) of mod 2 Steenrod algebra, milnor basis @@ -262,14 +267,15 @@ class Ideal_nc(Ideal_generic): EXAMPLES:: - sage: A = SteenrodAlgebra(2) - sage: IR = [A.1+A.2,A.1^2]*A - sage: IL = A*[A.1+A.2,A.1^2] - sage: IT = A*[A.1+A.2,A.1^2]*A - sage: IT == IL - False - sage: IR == [A.1+A.2,A.1^2]*A - True + sage: # needs sage.combinat + sage: A = SteenrodAlgebra(2) + sage: IR = [A.1+A.2,A.1^2]*A + sage: IL = A*[A.1+A.2,A.1^2] + sage: IT = A*[A.1+A.2,A.1^2]*A + sage: IT == IL + False + sage: IR == [A.1+A.2,A.1^2]*A + True """ if not isinstance(right, Ideal_nc): return False @@ -288,14 +294,15 @@ class Ideal_nc(Ideal_generic): EXAMPLES:: - sage: A = SteenrodAlgebra(2) - sage: IR = [A.1+A.2,A.1^2]*A - sage: IL = A*[A.1+A.2,A.1^2] - sage: IT = A*[A.1+A.2,A.1^2]*A - sage: IT != IL - True - sage: IR != [A.1+A.2,A.1^2]*A - False + sage: # needs sage.combinat + sage: A = SteenrodAlgebra(2) + sage: IR = [A.1+A.2,A.1^2]*A + sage: IL = A*[A.1+A.2,A.1^2] + sage: IT = A*[A.1+A.2,A.1^2]*A + sage: IT != IL + True + sage: IR != [A.1+A.2,A.1^2]*A + False """ return not self.__eq__(right) @@ -305,14 +312,15 @@ class Ideal_nc(Ideal_generic): EXAMPLES:: - sage: A = SteenrodAlgebra(2) - sage: IR = [A.1+A.2,A.1^2]*A - sage: IL = A*[A.1+A.2,A.1^2] - sage: IT = A*[A.1+A.2,A.1^2]*A - sage: hash(IT) == hash(IL) - False - sage: hash(IR) == hash([A.1^2,A.1+A.2]*A) - True + sage: # needs sage.combinat + sage: A = SteenrodAlgebra(2) + sage: IR = [A.1+A.2,A.1^2]*A + sage: IL = A*[A.1+A.2,A.1^2] + sage: IT = A*[A.1+A.2,A.1^2]*A + sage: hash(IT) == hash(IL) + False + sage: hash(IR) == hash([A.1^2,A.1+A.2]*A) + True """ return hash((self.parent(), self.__side, frozenset(self.gens()))) @@ -322,6 +330,7 @@ class Ideal_nc(Ideal_generic): EXAMPLES:: + sage: # needs sage.combinat sage: A = SteenrodAlgebra(2) sage: IL = A*[A.1+A.2,A.1^2] sage: IR = [A.1+A.2,A.1^2]*A diff --git a/src/sage/rings/number_field/S_unit_solver.py b/src/sage/rings/number_field/S_unit_solver.py index a0eb41b75b3..92f7af1bf19 100644 --- a/src/sage/rings/number_field/S_unit_solver.py +++ b/src/sage/rings/number_field/S_unit_solver.py @@ -1,7 +1,7 @@ r""" Solve S-unit equation x + y = 1 -Inspired by work of Tzanakis--de Weger, Baker--Wustholz and Smart, we use the LLL methods in Sage to implement an algorithm that returns all S-unit solutions to the equation `x + y = 1`. +Inspired by work of Tzanakis--de Weger, Baker--Wustholz and Smart, we use the LLL methods in Sage to implement an algorithm that returns all `S`-unit solutions to the equation `x + y = 1`. REFERENCES: @@ -22,7 +22,8 @@ EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import solve_S_unit_equation, eq_up_to_order - sage: K.<xi> = NumberField(x^2+x+1) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^2 + x + 1) sage: S = K.primes_above(3) sage: expected = [((0, 1), (4, 0), xi + 2, -xi - 1), ....: ((1, -1), (0, -1), 1/3*xi + 2/3, -1/3*xi + 1/3), @@ -96,7 +97,8 @@ def column_Log(SUK, iota, U, prec=106): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import column_Log - sage: K.<xi> = NumberField(x^3-3) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) sage: S = tuple(K.primes_above(3)) sage: SUK = UnitGroup(K, S=S) sage: phi_complex = K.places()[1] @@ -125,15 +127,16 @@ def c3_func(SUK, prec=106): OUTPUT: - The constant ``c3``, as a real number + The constant `c_3`, as a real number EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import c3_func - sage: K.<xi> = NumberField(x^3-3) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3))) - sage: c3_func(SUK) # abs tol 1e-29 + sage: c3_func(SUK) # abs tol 1e-29 0.4257859134798034746197327286726 .. NOTE:: @@ -177,25 +180,26 @@ def c4_func(SUK, v, A, prec=106): OUTPUT: - The constant ``c4``, as a real number + The constant `c_4`, as a real number EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import c4_func - sage: K.<xi> = NumberField(x^3-3) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3))) sage: phi_real = K.places()[0] sage: phi_complex = K.places()[1] sage: v_fin = tuple(K.primes_above(3))[0] sage: A = K.roots_of_unity() - sage: c4_func(SUK,phi_real,A) + sage: c4_func(SUK, phi_real, A) 1.000000000000000000000000000000 - sage: c4_func(SUK,phi_complex,A) + sage: c4_func(SUK, phi_complex, A) 1.000000000000000000000000000000 - sage: c4_func(SUK,v_fin,A) + sage: c4_func(SUK, v_fin, A) 1.000000000000000000000000000000 REFERENCES: @@ -220,11 +224,12 @@ def beta_k(betas_and_ns): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import beta_k - sage: K.<xi> = NumberField(x^3-3) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3))) sage: v_fin = tuple(K.primes_above(3))[0] - sage: betas = [ [beta, beta.valuation(v_fin)] for beta in SUK.fundamental_units() ] + sage: betas = [[beta, beta.valuation(v_fin)] for beta in SUK.fundamental_units()] sage: beta_k(betas) [xi, 1] @@ -258,7 +263,8 @@ def mus(SUK, v): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import mus - sage: K.<xi> = NumberField(x^3-3) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3))) sage: v_fin = tuple(K.primes_above(3))[0] @@ -272,7 +278,7 @@ def mus(SUK, v): """ betas = SUK.fundamental_units() beta_and_ns = [[beta,beta.valuation(v)] for beta in betas] - if all(pair[1]==0 for pair in beta_and_ns): + if all(pair[1] == 0 for pair in beta_and_ns): return betas else: good_pair = beta_k(beta_and_ns) @@ -297,12 +303,13 @@ def possible_mu0s(SUK, v): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import possible_mu0s - sage: K.<xi> = NumberField(x^3-3) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) sage: S = tuple(K.primes_above(3)) sage: SUK = UnitGroup(K, S=S) sage: v_fin = S[0] - sage: possible_mu0s(SUK,v_fin) + sage: possible_mu0s(SUK, v_fin) [-1, 1] .. NOTE:: @@ -343,7 +350,7 @@ def Yu_a1_kappa1_c1(p, dK, ep): - ``p`` -- a rational prime number - ``dK`` -- the absolute degree of some number field `K` - - ``ep`` -- the absolute ramification index of some prime `frak_p` of `K` lying above `p` + - ``ep`` -- the absolute ramification index of some prime ``frak_p`` of `K` lying above `p` OUTPUT: @@ -390,7 +397,7 @@ def Yu_a1_kappa1_c1(p, dK, ep): c1 = 1473 else: c1 = 319 - elif p%4 == 1: + elif p % 4 == 1: if ep == 1: c1 = 1473 else: @@ -424,6 +431,7 @@ def Yu_condition_115(K, v): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import Yu_condition_115 + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 5) sage: v2 = K.primes_above(2)[0] sage: v11 = K.primes_above(11)[0] @@ -453,10 +461,10 @@ def Yu_condition_115(K, v): if q == 2: if p**f % 4 == 1: return True - if w%4 == 0: + if w % 4 == 0: return True else: - if w%3 == 0: + if w % 3 == 0: return True return False @@ -479,6 +487,7 @@ def Yu_modified_height(mu, n, v, prec=106): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 5) sage: v11 = K.primes_above(11)[0] sage: from sage.rings.number_field.S_unit_solver import Yu_modified_height @@ -515,22 +524,23 @@ def Yu_modified_height(mu, n, v, prec=106): def Omega_prime(dK, v, mu_list, prec=106): r""" - Return the constant Omega' appearing in [AKMRVW]_. + Return the constant `\Omega'` appearing in [AKMRVW]_. INPUT: - ``dK`` -- the degree of a number field `K` - ``v`` -- a finite place of `K` - - ``mu_list`` -- a list of nonzero elements of `K`. It is assumed that the sublist mu[1:] is multiplicatively independent. + - ``mu_list`` -- a list of nonzero elements of `K`. It is assumed that the sublist ``mu_list[1:]`` is multiplicatively independent. - ``prec`` -- the precision of the real field OUTPUT: - The constant `Omega'`. + The constant `\Omega'`. EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import mus, Omega_prime + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 3) sage: SUK = UnitGroup(K, S=tuple(K.primes_above(6))) sage: v = K.primes_above(3)[0] @@ -559,7 +569,7 @@ def Omega_prime(dK, v, mu_list, prec=106): def Yu_C1_star(n, v, prec=106): r""" - Return the constant C_1^* appearing in [Yu2007]_ (1.23). + Return the constant `C_1^*` appearing in [Yu2007]_ (1.23). INPUT: @@ -569,10 +579,11 @@ def Yu_C1_star(n, v, prec=106): OUTPUT: - The constant `C1_star` as a real number. + The constant `C_1^*` as a real number. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 5) sage: v11 = K.primes_above(11)[0] sage: from sage.rings.number_field.S_unit_solver import Yu_C1_star @@ -619,7 +630,7 @@ def Yu_C1_star(n, v, prec=106): def Yu_bound(SUK, v, prec=106): r""" - Return `c8` such that `c8 >= exp(2)/\log(2)` and `ord_p (\Theta - 1) < c8 \log B`, + Return `c_8` such that `c_8 \geq exp(2)/\log(2)` and `ord_p (\Theta - 1) < c_8 \log B`, where `\Theta = \prod_{j=1}^n \alpha_j^{b_j}` and `B \geq \max_j |b_j|` and `B \geq 3`. INPUT: @@ -630,11 +641,12 @@ def Yu_bound(SUK, v, prec=106): OUTPUT: - The constant `c8` as a real number. + The constant `c_8` as a real number. EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import Yu_bound + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 11) sage: SUK = UnitGroup(K, S=tuple(K.primes_above(6))) sage: v = K.primes_above(3)[0] @@ -707,16 +719,17 @@ def K0_func(SUK, A, prec=106): INPUT: - ``SUK`` -- a group of `S`-units - - ``A`` -- the set of the products of the coefficients of the `S`-unit equation with each root of unity of ``K`` + - ``A`` -- the set of the products of the coefficients of the `S`-unit equation with each root of unity of `K` - ``prec`` -- the precision of the real field (default: 106) OUTPUT: - The constant ``K0``, a real number. + The constant `K_0`, a real number. EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import K0_func + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 11) sage: SUK = UnitGroup(K, S=tuple(K.primes_above(6))) sage: v = K.primes_above(3)[0] @@ -756,18 +769,19 @@ def c11_func(SUK, v, A, prec=106): INPUT: - ``SUK`` -- a group of `S`-units - - ``v`` -- a place of ``K``, finite (a fractional ideal) or infinite (element of ``SUK.number_field().places(prec)``) - - ``A`` -- the set of the product of the coefficients of the `S`-unit equation with each root of unity of ``K`` + - ``v`` -- a place of `K`, finite (a fractional ideal) or infinite (element of ``SUK.number_field().places(prec)``) + - ``A`` -- the set of the product of the coefficients of the `S`-unit equation with each root of unity of `K` - ``prec`` -- the precision of the real field (default: 106) OUTPUT: - The constant ``c11``, a real number + The constant `c_{11}`, a real number EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import c11_func - sage: K.<xi> = NumberField(x^3-3) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3))) sage: phi_real = K.places()[0] sage: phi_complex = K.places()[1] @@ -802,12 +816,13 @@ def c13_func(SUK, v, prec=106): OUTPUT: - The constant ``c13``, as a real number + The constant `c_{13}`, as a real number EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import c13_func - sage: K.<xi> = NumberField(x^3-3) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3))) sage: phi_real = K.places()[0] sage: phi_complex = K.places()[1] @@ -848,18 +863,19 @@ def K1_func(SUK, v, A, prec=106): INPUT: - ``SUK`` -- a group of `S`-units - - ``v`` -- an infinite place of ``K`` (element of ``SUK.number_field().places(prec)``) - - ``A`` -- a list of all products of each potential ``a``, ``b`` in the `S`-unit equation ``ax + by + 1 = 0`` with each root of unity of ``K`` + - ``v`` -- an infinite place of `K` (element of ``SUK.number_field().places(prec)``) + - ``A`` -- a list of all products of each potential `a`, `b` in the `S`-unit equation `ax + by + 1 = 0` with each root of unity of `K` - ``prec`` -- the precision of the real field (default: 106) OUTPUT: - The constant ``K1,`` a real number + The constant `K_1`, a real number EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import K1_func - sage: K.<xi> = NumberField(x^3-3) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3))) sage: phi_real = K.places()[0] sage: phi_complex = K.places()[1] @@ -914,9 +930,9 @@ def minimal_vector(A, y, prec=106): r""" INPUT: - - ``A`` : a square n by n non-singular integer matrix whose rows generate a lattice `\mathcal L` - - ``y`` : a row (1 by n) vector with integer coordinates - - ``prec`` : precision of real field (default: 106) + - ``A`` -- a square `n` by `n` non-singular integer matrix whose rows generate a lattice `\mathcal L` + - ``y`` -- a row (1 by `n`) vector with integer coordinates + - ``prec`` -- precision of real field (default: 106) OUTPUT: @@ -966,11 +982,12 @@ def minimal_vector(A, y, prec=106): ALLLinv = ALLL.inverse() ybrace = [ abs(R(a-a.round())) for a in y * ALLLinv if (a-a.round()) != 0] + v = ALLL.rows()[0] if len(ybrace) == 0: - return (ALLL.rows()[0].norm())**2 / c1 + return v.dot_product(v) / c1 else: sigma = ybrace[len(ybrace)-1] - return ((ALLL.rows()[0].norm())**2 * sigma) / c1 + return v.dot_product(v) * sigma / c1 def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): @@ -1002,9 +1019,11 @@ def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import reduction_step_complex_case - sage: K.<a> = NumberField([x^3-2]) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField([x^3 - 2]) sage: SK = sum([K.primes_above(p) for p in [2,3,5]],[]) - sage: G = [g for g in K.S_unit_group(S=SK).gens_values() if g.multiplicative_order()==Infinity] + sage: G = [g for g in K.S_unit_group(S=SK).gens_values() + ....: if g.multiplicative_order() == Infinity] sage: p1 = K.places(prec=100)[1] sage: reduction_step_complex_case(p1, 10^5, G, -1, 2) (18, False) @@ -1160,7 +1179,7 @@ def cx_LLL_bound(SUK, A, prec=106): INPUT: - ``SUK`` -- a group of `S`-units - - ``A`` -- a list of all products of each potential ``a``, ``b`` in the `S`-unit equation ``ax + by + 1 = 0`` with each root of unity of ``K`` + - ``A`` -- a list of all products of each potential `a`, `b` in the `S`-unit equation `ax + by + 1 = 0` with each root of unity of `K` - ``prec`` -- precision of real field (default: 106) OUTPUT: @@ -1170,11 +1189,12 @@ def cx_LLL_bound(SUK, A, prec=106): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import cx_LLL_bound - sage: K.<xi> = NumberField(x^3-3) - sage: SUK = UnitGroup(K,S=tuple(K.primes_above(3))) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) + sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3))) sage: A = K.roots_of_unity() - sage: cx_LLL_bound(SUK,A) # long time + sage: cx_LLL_bound(SUK, A) # long time 35 """ cx_LLL = 0 @@ -1219,7 +1239,7 @@ def log_p(a, prime, prec): OUTPUT: - An element of `K` which is congruent to the ``prime``-adic logarithm of ``a`` with respect to ``prime`` modulo ``p^prec``, where ``p`` is the rational prime below ``prime`` + An element of `K` which is congruent to the ``prime``-adic logarithm of `a` with respect to ``prime`` modulo ``p^prec``, where `p` is the rational prime below ``prime`` .. NOTE:: @@ -1228,7 +1248,8 @@ def log_p(a, prime, prec): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import log_p - sage: K.<a> = NumberField(x^2+14) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 14) sage: p1 = K.primes_above(3)[0] sage: p1 Fractional ideal (3, a + 1) @@ -1237,7 +1258,7 @@ def log_p(a, prime, prec): :: - sage: K.<a> = NumberField(x^4+14) + sage: K.<a> = NumberField(x^4 + 14) sage: p1 = K.primes_above(5)[0] sage: p1 Fractional ideal (5, a + 1) @@ -1283,7 +1304,7 @@ def log_p_series_part(a, prime, prec): OUTPUT: - The ``prime``-adic logarithm of ``a`` and accuracy ``p^prec``, where ``p`` is the rational prime below ``prime`` + The ``prime``-adic logarithm of `a` and accuracy ``p^prec``, where `p` is the rational prime below ``prime`` ALGORITHM: @@ -1292,16 +1313,17 @@ def log_p_series_part(a, prime, prec): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import log_p_series_part - sage: K.<a> = NumberField(x^2-5) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 5) sage: p1 = K.primes_above(3)[0] sage: p1 Fractional ideal (3) - sage: log_p_series_part(a^2-a+1, p1, 30) + sage: log_p_series_part(a^2 - a + 1, p1, 30) 120042736778562*a + 263389019530092 :: - sage: K.<a> = NumberField(x^4+14) + sage: K.<a> = NumberField(x^4 + 14) sage: p1 = K.primes_above(5)[0] sage: p1 Fractional ideal (5, a + 1) @@ -1320,7 +1342,7 @@ def log_p_series_part(a, prime, prec): divisor = q.divisors() order = min(d for d in divisor if (a**d - 1).valuation(prime) > 0) - gamma= a**order + gamma = a**order t = 0 while (gamma-1).valuation(prime) <= e: t += 1 @@ -1339,7 +1361,6 @@ def log_p_series_part(a, prime, prec): ZZ((gi * p**(-gi.valuation(p))) % (p**(prec+w-gi.valuation(p)))) * p**(gi.valuation(p)) * g**i for i,gi in enumerate(gamma) if gi != 0]) - beta = 0 delta = 1 - gamma for i in range(1, n+1): @@ -1443,7 +1464,7 @@ def embedding_to_Kp(a, prime, prec): OUTPUT: - An element of `K` that is equivalent to ``a`` modulo ``p^(prec)`` and the generator of `K` appears with exponent less than `e \cdot f`, where ``p`` is the rational prime below ``prime`` and `e,f` are the ramification index and residue degree, respectively. + An element of `K` that is equivalent to `a` modulo ``p^(prec)`` and the generator of `K` appears with exponent less than `e \cdot f`, where `p` is the rational prime below ``prime`` and `e`, `f` are the ramification index and residue degree, respectively. .. NOTE:: @@ -1460,10 +1481,11 @@ def embedding_to_Kp(a, prime, prec): :: - sage: K.<a> = NumberField(x^4-2) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^4 - 2) sage: p = K.prime_above(7); p Fractional ideal (-a^2 + a - 1) - sage: embedding_to_Kp(a^3-3, p, 15) + sage: embedding_to_Kp(a^3 - 3, p, 15) -1261985118949117459462968282807202378 """ K = prime.ring() @@ -1487,7 +1509,7 @@ def p_adic_LLL_bound_one_prime(prime, B0, M, M_logp, m0, c3, prec=106): - ``M_logp`` -- the p-adic logarithm of elements in `M` - ``m0`` -- an element of `K`, this is `\mu_0` from Lemma IX.3 of [Sma1998]_ - ``c3`` -- a positive real constant - - ``prec`` -- the precision of the calculations (default: 106), i.e., values are known to O(p^prec) + - ``prec`` -- the precision of the calculations (default: 106), i.e., values are known to ``O(p^prec)`` OUTPUT: @@ -1507,32 +1529,37 @@ def p_adic_LLL_bound_one_prime(prime, B0, M, M_logp, m0, c3, prec=106): sage: from sage.rings.number_field.S_unit_solver import p_adic_LLL_bound_one_prime sage: prec = 50 - sage: K.<a> = NumberField(x^3-3) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 3) sage: S = tuple(K.primes_above(3)) sage: SUK = UnitGroup(K, S=S) sage: v = S[0] sage: A = SUK.roots_of_unity() sage: K0_old = 9.4755766731093e17 sage: Mus = [a^2 - 2] - sage: Log_p_Mus = [185056824593551109742400*a^2 + 1389583284398773572269676*a + 717897987691852588770249] + sage: Log_p_Mus = [185056824593551109742400*a^2 + ....: + 1389583284398773572269676*a + 717897987691852588770249] sage: mu0 = K(-1) sage: c3_value = 0.42578591347980 - sage: m0_Kv_new, increase_precision = p_adic_LLL_bound_one_prime(v, K0_old, Mus, Log_p_Mus, mu0, c3_value, prec) + sage: m0_Kv_new, increase_prec = p_adic_LLL_bound_one_prime(v, K0_old, Mus, Log_p_Mus, + ....: mu0, c3_value, prec) sage: m0_Kv_new 0 - sage: increase_precision + sage: increase_prec True And now we increase the precision to make it all work:: sage: prec = 106 sage: K0_old = 9.475576673109275443280257946930e17 - sage: Log_p_Mus = [1029563604390986737334686387890424583658678662701816*a^2 + 661450700156368458475507052066889190195530948403866*a] + sage: Log_p_Mus = [1029563604390986737334686387890424583658678662701816*a^2 + ....: + 661450700156368458475507052066889190195530948403866*a] sage: c3_value = 0.4257859134798034746197327286726 - sage: m0_Kv_new, increase_precision = p_adic_LLL_bound_one_prime(v, K0_old, Mus, Log_p_Mus, mu0, c3_value, prec) + sage: m0_Kv_new, increase_prec = p_adic_LLL_bound_one_prime(v, K0_old, Mus, Log_p_Mus, + ....: mu0, c3_value, prec) sage: m0_Kv_new 476 - sage: increase_precision + sage: increase_prec False """ if any(g.valuation(prime) != 0 for g in M+[m0]): @@ -1630,7 +1657,7 @@ def p_adic_LLL_bound(SUK, A, prec=106): INPUT: - ``SUK`` -- a group of `S`-units - - ``A`` -- a list of all products of each potential ``a``, ``b`` in the `S`-unit equation ``ax + by + 1 = 0`` with each root of unity of ``K`` + - ``A`` -- a list of all products of each potential `a`, `b` in the `S`-unit equation `ax + by + 1 = 0` with each root of unity of `K` - ``prec``-- precision for p-adic LLL calculations (default: 106) OUTPUT: @@ -1640,11 +1667,12 @@ def p_adic_LLL_bound(SUK, A, prec=106): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import p_adic_LLL_bound - sage: K.<xi> = NumberField(x^3-3) - sage: SUK = UnitGroup(K,S=tuple(K.primes_above(3))) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) + sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3))) sage: A = SUK.roots_of_unity() sage: prec = 100 - sage: p_adic_LLL_bound(SUK,A, prec) + sage: p_adic_LLL_bound(SUK, A, prec) 89 """ S = SUK.primes() @@ -1684,7 +1712,7 @@ def p_adic_LLL_bound(SUK, A, prec=106): def split_primes_large_lcm(SUK, bound): r""" - Return a list ``L`` of rational primes `q` which split completely in `K` and which have desirable properties (see NOTE). + Return a list `L` of rational primes `q` which split completely in `K` and which have desirable properties (see NOTE). INPUT: @@ -1698,7 +1726,7 @@ def split_primes_large_lcm(SUK, bound): - each prime `q` in `L` splits completely in `K` - if `Q` is a prime in `S` and `q` is the rational prime below `Q`, then `q` is **not** in `L` - - the value ``lcm { q-1 : q in L }`` is greater than or equal to ``2*bound + 1``. + - the value `\lcm(\{ q-1 : q \in L \})` is greater than or equal to ``2*bound + 1``. .. NOTE:: @@ -1712,9 +1740,10 @@ def split_primes_large_lcm(SUK, bound): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import split_primes_large_lcm + sage: x = polygen(ZZ, 'x') sage: K.<xi> = NumberField(x^3 - 3*x + 1) sage: S = K.primes_above(3) - sage: SUK = UnitGroup(K,S=tuple(S)) + sage: SUK = UnitGroup(K, S=tuple(S)) sage: split_primes_large_lcm(SUK, 200) [17, 19, 37, 53] @@ -1753,7 +1782,7 @@ def split_primes_large_lcm(SUK, bound): def sieve_ordering(SUK, q): r""" - Returns ordered data for running sieve on the primes in `SUK` over the rational prime `q`. + Return ordered data for running sieve on the primes in ``SUK`` over the rational prime `q`. INPUT: @@ -1764,7 +1793,7 @@ def sieve_ordering(SUK, q): A list of tuples, ``[ideals_over_q, residue_fields, rho_images, product_rho_orders]``, where - 1. ``ideals_over_q`` is a list of the `d = [K:\mathbb{Q}]` ideals in `K` over `q` + 1. ``ideals_over_q`` is a list of the `d = [K:\QQ]` ideals in `K` over `q` 2. ``residue_fields[i]`` is the residue field of ``ideals_over_q[i]`` 3. ``rho_images[i]`` is a list of the reductions of the generators in of the `S`-unit group, modulo ``ideals_over_q[i]`` 4. ``product_rho_orders[i]`` is the product of the multiplicative orders of the elements in ``rho_images[i]`` @@ -1772,11 +1801,12 @@ def sieve_ordering(SUK, q): .. NOTE:: - The list ``ideals_over_q`` is sorted so that the product of orders is smallest for ``ideals_over_q[0]``, as this will make the later sieving steps more efficient. - - The primes of ``S`` must not lie over ``q``. + - The primes of `S` must not lie over `q`. EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import sieve_ordering + sage: x = polygen(ZZ, 'x') sage: K.<xi> = NumberField(x^3 - 3*x + 1) sage: SUK = K.S_unit_group(S=3) sage: sieve_data = list(sieve_ordering(SUK, 19)) @@ -1822,7 +1852,7 @@ def sieve_ordering(SUK, q): def clean_rfv_dict(rfv_dictionary): r""" - Given a residue field vector dictionary, removes some impossible keys and entries. + Given a residue field vector dictionary, remove some impossible keys and entries. INPUT: @@ -1830,13 +1860,13 @@ def clean_rfv_dict(rfv_dictionary): OUTPUT: - None. But it removes some keys from the input dictionary. + ``None``. But it removes some keys from the input dictionary. .. NOTE:: - - The keys of a residue field vector dictionary are exponent vectors modulo ``(q-1)`` for some prime ``q``. - - The values are residue field vectors. It is known that the entries of a residue field vector - which comes from a solution to the S-unit equation cannot have 1 in any entry. + - The keys of a residue field vector dictionary are exponent vectors modulo `q-1` for some prime `q`. + - The values are residue field vectors. It is known that a residue field vector + which comes from a solution to the `S`-unit equation cannot have 1 in any entry. EXAMPLES: @@ -1844,7 +1874,8 @@ def clean_rfv_dict(rfv_dictionary): polynomial `x^2+x+1` and `S` consists of the primes above 3:: sage: from sage.rings.number_field.S_unit_solver import clean_rfv_dict - sage: rfv_dict = {(1, 3): [3, 2], (3, 0): [6, 6], (5, 4): [3, 6], (2, 1): [4, 6], (5, 1): [3, 1], (2, 5): [1, 5], (0, 3): [1, 6]} + sage: rfv_dict = {(1, 3): [3, 2], (3, 0): [6, 6], (5, 4): [3, 6], (2, 1): [4, 6], + ....: (5, 1): [3, 1], (2, 5): [1, 5], (0, 3): [1, 6]} sage: len(rfv_dict) 7 sage: clean_rfv_dict(rfv_dict) @@ -1867,8 +1898,8 @@ def construct_rfv_to_ev(rfv_dictionary, q, d, verbose=False): - ``rfv_dictionary`` -- a dictionary whose keys are exponent vectors and whose values are the associated residue field vectors - ``q`` -- a prime (assumed to split completely in the relevant number field) - - ``d`` -- the number of primes in `K` above the rational prime ``q`` - - ``verbose`` -- a boolean flag to indicate more detailed output is desired (default: False) + - ``d`` -- the number of primes in `K` above the rational prime `q` + - ``verbose`` -- a boolean flag to indicate more detailed output is desired (default: ``False``) OUTPUT: @@ -1877,7 +1908,7 @@ def construct_rfv_to_ev(rfv_dictionary, q, d, verbose=False): .. NOTE:: - - For example, if ``rfv_dictionary[ e0 ] = r0``, then ``P[ r0 ]`` is a list which contains ``e0``. + - For example, if ``rfv_dictionary[e0] = r0``, then ``P[r0]`` is a list which contains ``e0``. - During construction, some residue field vectors can be eliminated as coming from solutions to the `S`-unit equation. Such vectors are dropped from the keys of the dictionary ``P``. @@ -1887,7 +1918,8 @@ def construct_rfv_to_ev(rfv_dictionary, q, d, verbose=False): polynomial `x^2+x+1` and `S` consists of the primes above 3:: sage: from sage.rings.number_field.S_unit_solver import construct_rfv_to_ev - sage: rfv_dict = {(1, 3): [3, 2], (3, 0): [6, 6], (5, 4): [3, 6], (2, 1): [4, 6], (4, 0): [4, 2], (1, 2): [5, 6]} + sage: rfv_dict = {(1, 3): [3, 2], (3, 0): [6, 6], (5, 4): [3, 6], (2, 1): [4, 6], + ....: (4, 0): [4, 2], (1, 2): [5, 6]} sage: construct_rfv_to_ev(rfv_dict,7,2,False) {(3, 2): [(1, 3)], (4, 2): [(4, 0)], (4, 6): [(2, 1)], (5, 6): [(1, 2)]} """ @@ -2014,7 +2046,15 @@ def construct_comp_exp_vec(rfv_to_ev_dict, q): :: sage: from sage.rings.number_field.S_unit_solver import construct_comp_exp_vec - sage: rfv_to_ev_dict = {(6, 6): [(3, 0)], (5, 6): [(1, 2)], (5, 4): [(5, 3)], (6, 2): [(5, 5)], (2, 5): [(0, 1)], (5, 5): [(3, 4)], (4, 4): [(0, 2)], (6, 3): [(1, 4)], (3, 6): [(5, 4)], (2, 2): [(0, 4)], (3, 5): [(1, 0)], (6, 4): [(1, 1)], (3, 2): [(1, 3)], (2, 6): [(4, 5)], (4, 5): [(4, 3)], (2, 3): [(2, 3)], (4, 2): [(4, 0)], (6, 5): [(5, 2)], (3, 3): [(3, 2)], (5, 3): [(5, 0)], (4, 6): [(2, 1)], (3, 4): [(3, 5)], (4, 3): [(0, 5)], (5, 2): [(3, 1)], (2, 4): [(2, 0)]} + sage: rfv_to_ev_dict = {(6, 6): [(3, 0)], (5, 6): [(1, 2)], (5, 4): [(5, 3)], + ....: (6, 2): [(5, 5)], (2, 5): [(0, 1)], (5, 5): [(3, 4)], + ....: (4, 4): [(0, 2)], (6, 3): [(1, 4)], (3, 6): [(5, 4)], + ....: (2, 2): [(0, 4)], (3, 5): [(1, 0)], (6, 4): [(1, 1)], + ....: (3, 2): [(1, 3)], (2, 6): [(4, 5)], (4, 5): [(4, 3)], + ....: (2, 3): [(2, 3)], (4, 2): [(4, 0)], (6, 5): [(5, 2)], + ....: (3, 3): [(3, 2)], (5, 3): [(5, 0)], (4, 6): [(2, 1)], + ....: (3, 4): [(3, 5)], (4, 3): [(0, 5)], (5, 2): [(3, 1)], + ....: (2, 4): [(2, 0)]} sage: construct_comp_exp_vec(rfv_to_ev_dict, 7) {(0, 1): [(1, 4)], (0, 2): [(0, 2)], @@ -2055,17 +2095,17 @@ def construct_comp_exp_vec(rfv_to_ev_dict, q): def drop_vector(ev, p, q, complement_ev_dict): r""" - Determines if the exponent vector, ``ev``, may be removed from the complement dictionary during construction. - This will occur if ``ev`` is not compatible with an exponent vector mod ``q-1``. + Determine if the exponent vector, ``ev``, may be removed from the complement dictionary during construction. + This will occur if ``ev`` is not compatible with an exponent vector mod `q-1`. INPUT: - - ``ev`` -- an exponent vector modulo ``p - 1`` - - ``p`` -- the prime such that ev is an exponent vector modulo ``p-1`` - - ``q`` -- a prime, distinct from ``p``, that is a key in the ``complement_ev_dict`` - - ``complement_ev_dict`` -- a dictionary of dictionaries, whose keys are primes - ``complement_ev_dict[q]`` is a dictionary whose keys are exponent vectors modulo ``q-1`` - and whose values are lists of complementary exponent vectors modulo ``q-1`` + - ``ev`` -- an exponent vector modulo `p-1` + - ``p`` -- the prime such that ``ev`` is an exponent vector modulo `p-1` + - ``q`` -- a prime, distinct from `p`, that is a key in the ``complement_ev_dict`` + - ``complement_ev_dict`` -- a dictionary of dictionaries, whose keys are primes. + ``complement_ev_dict[q]`` is a dictionary whose keys are exponent vectors modulo `q-1` + and whose values are lists of complementary exponent vectors modulo `q-1` OUTPUT: @@ -2073,19 +2113,35 @@ def drop_vector(ev, p, q, complement_ev_dict): .. NOTE:: - - If ``ev`` is not compatible with any of the vectors modulo ``q-1``, then it can no longer correspond to a solution + - If ``ev`` is not compatible with any of the vectors modulo `q-1`, then it can no longer correspond to a solution of the `S`-unit equation. It returns ``True`` to indicate that it should be removed. EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import drop_vector - sage: drop_vector((1, 2, 5), 7, 11, {11: {(1, 1, 3): [(1, 1, 3),(2, 3, 4)]}}) + sage: drop_vector((1, 2, 5), 7, 11, {11: {(1, 1, 3): [(1, 1, 3), (2, 3, 4)]}}) True :: - sage: P={3: {(1, 0, 0): [(1, 0, 0), (0, 1, 0)], (0, 1, 0): [(1, 0, 0), (0, 1, 0)]}, 7: {(0, 3, 4): [(0, 1, 2), (0, 3, 4), (0, 5, 0)], (1, 2, 4): [(1, 0, 4), (1, 4, 2), (1, 2, 0)], (0, 1, 2): [(0, 1, 2), (0, 3, 4), (0, 5, 0)], (0, 5, 4): [(1, 0, 0), (1, 4, 4), (1, 2, 2)], (1, 4, 2): [(1, 2, 4), (1, 4, 0), (1, 0, 2)], (1, 0, 4): [(1, 2, 4), (1, 4, 0), (1, 0, 2)], (0, 3, 2): [(1, 0, 0), (1, 4, 4), (1, 2, 2)], (1, 0, 0): [(0, 5, 4), (0, 3, 2), (0, 1, 0)], (1, 2, 0): [(1, 2, 4), (1, 4, 0), (1, 0, 2)], (0, 1, 0): [(1, 0, 0), (1, 4, 4), (1, 2, 2)], (0, 5, 0): [(0, 1, 2), (0, 3, 4), (0, 5, 0)], (1, 2, 2): [(0, 5, 4), (0, 3, 2), (0, 1, 0)], (1, 4, 0): [(1, 0, 4), (1, 4, 2), (1, 2, 0)], (1, 0, 2): [(1, 0, 4), (1, 4, 2), (1, 2, 0)], (1, 4, 4): [(0, 5, 4), (0, 3, 2), (0, 1, 0)]}} - sage: drop_vector((0,1,0),3,7,P) + sage: P = {3: {(1, 0, 0): [(1, 0, 0), (0, 1, 0)], + ....: (0, 1, 0): [(1, 0, 0), (0, 1, 0)]}, + ....: 7: {(0, 3, 4): [(0, 1, 2), (0, 3, 4), (0, 5, 0)], + ....: (1, 2, 4): [(1, 0, 4), (1, 4, 2), (1, 2, 0)], + ....: (0, 1, 2): [(0, 1, 2), (0, 3, 4), (0, 5, 0)], + ....: (0, 5, 4): [(1, 0, 0), (1, 4, 4), (1, 2, 2)], + ....: (1, 4, 2): [(1, 2, 4), (1, 4, 0), (1, 0, 2)], + ....: (1, 0, 4): [(1, 2, 4), (1, 4, 0), (1, 0, 2)], + ....: (0, 3, 2): [(1, 0, 0), (1, 4, 4), (1, 2, 2)], + ....: (1, 0, 0): [(0, 5, 4), (0, 3, 2), (0, 1, 0)], + ....: (1, 2, 0): [(1, 2, 4), (1, 4, 0), (1, 0, 2)], + ....: (0, 1, 0): [(1, 0, 0), (1, 4, 4), (1, 2, 2)], + ....: (0, 5, 0): [(0, 1, 2), (0, 3, 4), (0, 5, 0)], + ....: (1, 2, 2): [(0, 5, 4), (0, 3, 2), (0, 1, 0)], + ....: (1, 4, 0): [(1, 0, 4), (1, 4, 2), (1, 2, 0)], + ....: (1, 0, 2): [(1, 0, 4), (1, 4, 2), (1, 2, 0)], + ....: (1, 4, 4): [(0, 5, 4), (0, 3, 2), (0, 1, 0)]}} + sage: drop_vector((0, 1, 0), 3, 7, P) False """ # returns True if it is OK to drop exp_vec given the current comp_exp_vec dictionary associated to some q. @@ -2106,7 +2162,7 @@ def drop_vector(ev, p, q, complement_ev_dict): def construct_complement_dictionaries(split_primes_list, SUK, verbose=False): r""" - A function to construct the complement exponent vector dictionaries. + Construct the complement exponent vector dictionaries. INPUT: @@ -2117,15 +2173,15 @@ def construct_complement_dictionaries(split_primes_list, SUK, verbose=False): OUTPUT: A dictionary of dictionaries. The keys coincide with the primes in ``split_primes_list`` - For each ``q``, ``comp_exp_vec[q]`` is a dictionary whose keys are exponent vectors modulo ``q-1``, - and whose values are lists of exponent vectors modulo ``q-1`` + For each `q`, ``comp_exp_vec[q]`` is a dictionary whose keys are exponent vectors modulo `q-1`, + and whose values are lists of exponent vectors modulo `q-1` - If ``w`` is an exponent vector in ``comp_exp_vec[q][v]``, then the residue field vectors modulo ``q`` for - ``v`` and ``w`` sum to ``[1,1,...,1]`` + If `w` is an exponent vector in ``comp_exp_vec[q][v]``, then the residue field vectors modulo `q` for + `v` and `w` sum to ``[1,1,...,1]`` .. NOTE:: - - The data of ``comp_exp_vec`` will later be lifted to `\mathbb{Z}` to look for true `S`-Unit equation solutions. + - The data of ``comp_exp_vec`` will later be lifted to `\ZZ` to look for true `S`-Unit equation solutions. - During construction, the various dictionaries are compared to each other several times to eliminate as many mod `q` solutions as possible. - The authors acknowledge a helpful discussion with Norman Danner which helped formulate this code. @@ -2133,6 +2189,7 @@ def construct_complement_dictionaries(split_primes_list, SUK, verbose=False): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import construct_complement_dictionaries + sage: x = polygen(ZZ, 'x') sage: f = x^2 + 5 sage: H = 10 sage: K.<xi> = NumberField(f) @@ -2156,7 +2213,8 @@ def construct_complement_dictionaries(split_primes_list, SUK, verbose=False): ....: (1, 4, 0): [(1, 0, 4), (1, 4, 2), (1, 2, 0)], ....: (1, 4, 2): [(1, 2, 4), (1, 4, 0), (1, 0, 2)], ....: (1, 4, 4): [(0, 5, 4), (0, 3, 2), (0, 1, 0)]}} - sage: all(set(actual[p][vec]) == set(expected[p][vec]) for p in [3,7] for vec in expected[p]) + sage: all(set(actual[p][vec]) == set(expected[p][vec]) + ....: for p in [3, 7] for vec in expected[p]) True """ # We initialize some dictionaries. @@ -2319,7 +2377,7 @@ def epsilon_q(a, i): def compatible_vectors_check(a0, a1, g, l): r""" - Given exponent vectors with respect to two moduli, determines if they are compatible. + Given exponent vectors with respect to two moduli, determine if they are compatible. INPUT: @@ -2330,7 +2388,7 @@ def compatible_vectors_check(a0, a1, g, l): OUTPUT: - True if there is an integer exponent vector a satisfying + ``True`` if there is an integer exponent vector a satisfying .. MATH:: @@ -2340,7 +2398,7 @@ def compatible_vectors_check(a0, a1, g, l): a[1:] &== a1[1:] \mod m_1 \end{aligned} - and False otherwise. + and ``False`` otherwise. .. NOTE:: @@ -2364,14 +2422,14 @@ def compatible_vectors_check(a0, a1, g, l): def compatible_vectors(a, m0, m1, g): r""" - Given an exponent vector ``a`` modulo ``m0``, returns an iterator over the exponent vectors for the modulus ``m1``, such that a lift to the lcm modulus exists. + Given an exponent vector ``a`` modulo ``m0``, return an iterator over the exponent vectors for the modulus ``m1``, such that a lift to the lcm modulus exists. INPUT: - ``a`` -- an exponent vector for the modulus ``m0`` - ``m0`` -- a positive integer (specifying the modulus for ``a``) - ``m1`` -- a positive integer (specifying the alternate modulus) - - ``g`` -- the gcd of m0 and m1 + - ``g`` -- the gcd of ``m0`` and ``m1`` OUTPUT: @@ -2387,13 +2445,13 @@ def compatible_vectors(a, m0, m1, g): sage: a = (3, 1, 8, 1) sage: list(compatible_vectors(a, 18, 12, gcd(18,12))) [(3, 1, 2, 1), - (3, 1, 2, 7), - (3, 1, 8, 1), - (3, 1, 8, 7), - (3, 7, 2, 1), - (3, 7, 2, 7), - (3, 7, 8, 1), - (3, 7, 8, 7)] + (3, 1, 2, 7), + (3, 1, 8, 1), + (3, 1, 8, 7), + (3, 7, 2, 1), + (3, 7, 2, 7), + (3, 7, 8, 1), + (3, 7, 8, 7)] The order of the moduli matters. :: @@ -2403,13 +2461,13 @@ def compatible_vectors(a, m0, m1, g): 27 """ # recall that the 0th entry must be an exact match. - ranges = [[a[0]]] + [range(a[i]%g, (a[i]%g) + m1, g) for i in range(1, len(a))] + ranges = [[a[0]]] + [range(a[i] % g, (a[i] % g) + m1, g) for i in range(1, len(a))] return itertools.product(*ranges) def compatible_systems(split_prime_list, complement_exp_vec_dict): r""" - Given dictionaries of complement exponent vectors for various primes that split in K, compute all possible compatible systems. + Given dictionaries of complement exponent vectors for various primes that split in `K`, compute all possible compatible systems. INPUT: @@ -2422,21 +2480,21 @@ def compatible_systems(split_prime_list, complement_exp_vec_dict): .. NOTE:: - - For any ``q`` in ``split_prime_list``, ``complement_exp_vec_dict[q]`` is a dictionary whose keys are exponent vectors modulo ``q-1`` - and whose values are lists of exponent vectors modulo ``q-1`` which are complementary to the key. + - For any `q` in ``split_prime_list``, ``complement_exp_vec_dict[q]`` is a dictionary whose keys are exponent vectors modulo `q-1` + and whose values are lists of exponent vectors modulo `q-1` which are complementary to the key. - - an item in system_list has the form ``[ [v0, w0], [v1, w1], ..., [vk, wk] ]``, where:: + - An item in ``system_list`` has the form ``[ [v0, w0], [v1, w1], ..., [vk, wk] ]``, where:: - - ``qj = split_prime_list[j]`` - - ``vj`` and ``wj`` are complementary exponent vectors modulo ``qj - 1`` - - the pairs are all simultaneously compatible. + - ``qj = split_prime_list[j]`` + - ``vj`` and ``wj`` are complementary exponent vectors modulo ``qj - 1`` + - the pairs are all simultaneously compatible. - Let ``H = lcm( qj - 1 : qj in split_primes_list )``. Then for any compatible system, there is at most one pair of integer exponent vectors ``[v, w]`` such that:: - - every entry of ``v`` and ``w`` is bounded in absolute value by ``H`` - - for any ``qj``, ``v`` and ``vj`` agree modulo ``(qj - 1)`` - - for any ``qj``, ``w`` and ``wj`` agree modulo ``(qj - 1)`` + - every entry of ``v`` and ``w`` is bounded in absolute value by ``H`` + - for any ``qj``, ``v`` and ``vj`` agree modulo ``(qj - 1)`` + - for any ``qj``, ``w`` and ``wj`` agree modulo ``(qj - 1)`` EXAMPLES:: @@ -2536,14 +2594,14 @@ def compatible_system_lift(compatible_system, split_primes_list): def solutions_from_systems(SUK, bound, cs_list, split_primes_list): r""" - Lifts compatible systems to the integers and returns the S-unit equation solutions the lifts yield. + Lift compatible systems to the integers and return the `S`-unit equation solutions that the lifts yield. INPUT: - ``SUK`` -- the group of `S`-units where we search for solutions - ``bound`` -- a bound for the entries of all entries of all lifts - ``cs_list`` -- a list of compatible systems of exponent vectors modulo `q-1` for - various primes `q` + various primes `q` - ``split_primes_list`` -- a list of primes giving the moduli of the exponent vectors in ``cs_list`` OUTPUT: @@ -2566,11 +2624,12 @@ def solutions_from_systems(SUK, bound, cs_list, split_primes_list): Given a single compatible system, a solution can be found. :: sage: from sage.rings.number_field.S_unit_solver import solutions_from_systems - sage: K.<xi> = NumberField(x^2-15) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^2 - 15) sage: SUK = K.S_unit_group(S=K.primes_above(2)) sage: split_primes_list = [7, 17] sage: a_compatible_system = [[[(0, 0, 5), (0, 0, 5)], [(0, 0, 15), (0, 0, 15)]]] - sage: solutions_from_systems( SUK, 20, a_compatible_system, split_primes_list ) + sage: solutions_from_systems(SUK, 20, a_compatible_system, split_primes_list) [((0, 0, -1), (0, 0, -1), 1/2, 1/2)] """ solutions = [] @@ -2592,19 +2651,19 @@ def solutions_from_systems(SUK, bound, cs_list, split_primes_list): def clean_sfs(sfs_list): r""" - Given a list of S-unit equation solutions, remove trivial redundancies. + Given a list of `S`-unit equation solutions, remove trivial redundancies. INPUT: - - ``sfs_list`` -- a list of solutions to the S-unit equation + - ``sfs_list`` -- a list of solutions to the `S`-unit equation OUTPUT: - A list of solutions to the S-unit equation + A list of solutions to the `S`-unit equation .. NOTE:: - The function looks for cases where ``x + y = 1`` and ``y + x = 1`` appear\ + The function looks for cases where `x + y = 1` and `y + x = 1` appear as separate solutions, and removes one. EXAMPLES: @@ -2628,37 +2687,39 @@ def clean_sfs(sfs_list): def sieve_below_bound(K, S, bound=10, bump=10, split_primes_list=[], verbose=False): r""" - Return all solutions to the S-unit equation ``x + y = 1`` over K with exponents below the given bound. + Return all solutions to the `S`-unit equation `x + y = 1` over `K` with exponents below the given bound. INPUT: - ``K`` -- a number field (an absolute extension of the rationals) - - ``S`` -- a list of finite primes of ``K`` + - ``S`` -- a list of finite primes of `K` - ``bound`` -- a positive integer upper bound for exponents, solutions with exponents having absolute value below this bound will be found (default: 10) - ``bump`` -- a positive integer by which the minimum LCM will be increased if not enough split primes are found in sieving step (default: 10) - - ``split_primes_list`` -- a list of rational primes that split completely in the extension K/Q, used for sieving. For complete list of solutions should have lcm of {(p_i-1)} for primes p_i greater than bound (default: []) - - ``verbose`` -- an optional parameter allowing the user to print information during the sieving process (default: False) + - ``split_primes_list`` -- a list of rational primes that split completely in the extension `K/\QQ`, used for sieving. + For complete list of solutions should have lcm of `\{(p_i-1)\} for primes `p_i` greater than bound (default: ``[]``) + - ``verbose`` -- an optional parameter allowing the user to print information during the sieving process (default: ``False``) OUTPUT: - A list of tuples ``[( A_1, B_1, x_1, y_1), (A_2, B_2, x_2, y_2), ... ( A_n, B_n, x_n, y_n)]`` such that: + A list of tuples `[(A_1, B_1, x_1, y_1), (A_2, B_2, x_2, y_2), \dots (A_n, B_n, x_n, y_n)]` such that: - 1. The first two entries are tuples ``A_i = (a_0, a_1, ... , a_t)`` and ``B_i = (b_0, b_1, ... , b_t)`` of exponents. - 2. The last two entries are ``S``-units ``x_i`` and ``y_i`` in ``K`` with ``x_i + y_i = 1``. - 3. If the default generators for the ``S``-units of ``K`` are ``(rho_0, rho_1, ... , rho_t)``, then these satisfy ``x_i = \prod(rho_i)^(a_i)`` and ``y_i = \prod(rho_i)^(b_i)``. + 1. The first two entries are tuples `A_i = (a_0, a_1, \dots, a_t)` and `B_i = (b_0, b_1, \dots, b_t)` of exponents. + 2. The last two entries are `S`-units `x_i` and `y_i` in `K` with `x_i + y_i = 1`. + 3. If the default generators for the `S`-units of `K` are `(\rho_0, \rho_1, \dots, \rho_t)`, + then these satisfy `x_i = \prod(\rho_i)^{(a_i)}` and `y_i = \prod(\rho_i)^{(b_i)}`. EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import sieve_below_bound, eq_up_to_order - sage: K.<xi> = NumberField(x^2+x+1) - sage: SUK = UnitGroup(K,S=tuple(K.primes_above(3))) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^2 + x + 1) + sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3))) sage: S = SUK.primes() sage: sols = sieve_below_bound(K, S, 10) - sage: expected = [ - ....: ((1, -1), (0, -1), 1/3*xi + 2/3, -1/3*xi + 1/3), - ....: ((0, 1), (4, 0), xi + 2, -xi - 1), - ....: ((2, 0), (5, 1), xi, -xi + 1), - ....: ((1, 0), (5, 0), xi + 1, -xi)] + sage: expected = [((1, -1), (0, -1), 1/3*xi + 2/3, -1/3*xi + 1/3), + ....: ((0, 1), (4, 0), xi + 2, -xi - 1), + ....: ((2, 0), (5, 1), xi, -xi + 1), + ....: ((1, 0), (5, 0), xi + 1, -xi)] sage: eq_up_to_order(sols, expected) True """ @@ -2688,42 +2749,42 @@ def sieve_below_bound(K, S, bound=10, bump=10, split_primes_list=[], verbose=Fal def solve_S_unit_equation(K, S, prec=106, include_exponents=True, include_bound=False, proof=None, verbose=False): r""" - Return all solutions to the S-unit equation ``x + y = 1`` over K. + Return all solutions to the `S`-unit equation `x + y = 1` over `K`. INPUT: - ``K`` -- a number field (an absolute extension of the rationals) - - ``S`` -- a list of finite primes of ``K`` + - ``S`` -- a list of finite primes of `K` - ``prec`` -- precision used for computations in real, complex, and p-adic fields (default: 106) - - ``include_exponents`` -- whether to include the exponent vectors in the returned value (default: True). - - ``include_bound`` -- whether to return the final computed bound (default: False) - - ``verbose`` -- whether to print information during the sieving step (default: False) + - ``include_exponents`` -- whether to include the exponent vectors in the returned value (default: ``True``). + - ``include_bound`` -- whether to return the final computed bound (default: ``False``) + - ``verbose`` -- whether to print information during the sieving step (default: ``False``) OUTPUT: - A list of tuples ``[( A_1, B_1, x_1, y_1), (A_2, B_2, x_2, y_2), ... ( A_n, B_n, x_n, y_n)]`` such that: + A list of tuples `[(A_1, B_1, x_1, y_1), (A_2, B_2, x_2, y_2), \dots (A_n, B_n, x_n, y_n)]` such that: - 1. The first two entries are tuples ``A_i = (a_0, a_1, ... , a_t)`` and ``B_i = (b_0, b_1, ... , b_t)`` of exponents. These will be omitted if ``include_exponents`` is ``False``. - 2. The last two entries are ``S``-units ``x_i`` and ``y_i`` in ``K`` with ``x_i + y_i = 1``. - 3. If the default generators for the ``S``-units of ``K`` are ``(rho_0, rho_1, ... , rho_t)``, then these satisfy ``x_i = \prod(rho_i)^(a_i)`` and ``y_i = \prod(rho_i)^(b_i)``. + 1. The first two entries are tuples `A_i = (a_0, a_1, \dots, a_t)` and `B_i = (b_0, b_1, \dots, b_t)` of exponents. These will be omitted if ``include_exponents`` is ``False``. + 2. The last two entries are `S`-units `x_i` and `y_i` in `K` with `x_i + y_i = 1`. + 3. If the default generators for the `S`-units of `K` are `(\rho_0, \rho_1, \dots, \rho_t)``, then these satisfy `x_i = \prod(\rho_i)^{(a_i)}` and `y_i = \prod(\rho_i)^{(b_i)}`. If ``include_bound``, will return a pair ``(sols, bound)`` where ``sols`` is as above and ``bound`` is the bound used for the entries in the exponent vectors. EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import solve_S_unit_equation, eq_up_to_order - sage: K.<xi> = NumberField(x^2+x+1) + sage: x = polygen(ZZ, 'x') + sage: K.<xi> = NumberField(x^2 + x + 1) sage: S = K.primes_above(3) sage: sols = solve_S_unit_equation(K, S, 200) - sage: expected = [ - ....: ((0, 1), (4, 0), xi + 2, -xi - 1), - ....: ((1, -1), (0, -1), 1/3*xi + 2/3, -1/3*xi + 1/3), - ....: ((1, 0), (5, 0), xi + 1, -xi), - ....: ((2, 0), (5, 1), xi, -xi + 1)] + sage: expected = [((0, 1), (4, 0), xi + 2, -xi - 1), + ....: ((1, -1), (0, -1), 1/3*xi + 2/3, -1/3*xi + 1/3), + ....: ((1, 0), (5, 0), xi + 1, -xi), + ....: ((2, 0), (5, 1), xi, -xi + 1)] sage: eq_up_to_order(sols, expected) True - In order to see the bound as well use the optional parameter ``include_bound``:: + In order to see the bound as well, use the optional parameter ``include_bound``:: sage: solutions, bound = solve_S_unit_equation(K, S, 100, include_bound=True) sage: bound @@ -2732,7 +2793,8 @@ def solve_S_unit_equation(K, S, prec=106, include_exponents=True, include_bound= You can omit the exponent vectors:: sage: sols = solve_S_unit_equation(K, S, 200, include_exponents=False) - sage: expected = [(xi + 2, -xi - 1), (1/3*xi + 2/3, -1/3*xi + 1/3), (-xi, xi + 1), (-xi + 1, xi)] + sage: expected = [(xi + 2, -xi - 1), (1/3*xi + 2/3, -1/3*xi + 1/3), + ....: (-xi, xi + 1), (-xi + 1, xi)] sage: set(frozenset(a) for a in sols) == set(frozenset(b) for b in expected) True @@ -2741,11 +2803,12 @@ def solve_S_unit_equation(K, S, prec=106, include_exponents=True, include_bound= sage: solve_S_unit_equation(K, [3], 200) Traceback (most recent call last): ... - ValueError: S must consist only of prime ideals, or a single element from which a prime ideal can be constructed. + ValueError: S must consist only of prime ideals, + or a single element from which a prime ideal can be constructed. We check the case that the rank is 0:: - sage: K.<xi> = NumberField(x^2+x+1) + sage: K.<xi> = NumberField(x^2 + x + 1) sage: solve_S_unit_equation(K, []) [((1,), (5,), xi + 1, -xi)] """ @@ -2800,8 +2863,8 @@ def solve_S_unit_equation(K, S, prec=106, include_exponents=True, include_bound= def eq_up_to_order(A, B): """ - If A and B are lists of four-tuples ``[a0,a1,a2,a3]`` and ``[b0,b1,b2,b3]``, - checks that there is some reordering so that either ``ai=bi`` for all ``i`` or + If ``A`` and ``B`` are lists of four-tuples ``[a0,a1,a2,a3]`` and ``[b0,b1,b2,b3]``, + check that there is some reordering so that either ``ai=bi`` for all ``i`` or ``a0==b1``, ``a1==b0``, ``a2==b3``, ``a3==b2``. The entries must be hashable. @@ -2809,14 +2872,14 @@ def eq_up_to_order(A, B): EXAMPLES:: sage: from sage.rings.number_field.S_unit_solver import eq_up_to_order - sage: L = [(1,2,3,4),(5,6,7,8)] - sage: L1 = [L[1],L[0]] - sage: L2 = [(2,1,4,3),(6,5,8,7)] + sage: L = [(1,2,3,4), (5,6,7,8)] + sage: L1 = [L[1], L[0]] + sage: L2 = [(2,1,4,3), (6,5,8,7)] sage: eq_up_to_order(L, L1) True sage: eq_up_to_order(L, L2) True - sage: eq_up_to_order(L, [(1,2,4,3),(5,6,8,7)]) + sage: eq_up_to_order(L, [(1,2,4,3), (5,6,8,7)]) False """ # does not look very optimal diff --git a/src/sage/rings/number_field/__init__.py b/src/sage/rings/number_field/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/rings/number_field/bdd_height.py b/src/sage/rings/number_field/bdd_height.py index b7c8c33d0be..e467ee9df0e 100644 --- a/src/sage/rings/number_field/bdd_height.py +++ b/src/sage/rings/number_field/bdd_height.py @@ -69,6 +69,7 @@ def bdd_norm_pr_gens_iq(K, norm_list): norm 5, but no principal ideals of norm 7:: sage: from sage.rings.number_field.bdd_height import bdd_norm_pr_gens_iq + sage: x = polygen(ZZ, 'x') sage: K.<g> = NumberField(x^2 + 1) sage: L = range(10) sage: bdd_pr_ideals = bdd_norm_pr_gens_iq(K, L) @@ -129,6 +130,7 @@ def bdd_height_iq(K, height_bound): EXAMPLES:: sage: from sage.rings.number_field.bdd_height import bdd_height_iq + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 191) sage: for t in bdd_height_iq(K,8): ....: print(exp(2*t.global_height())) @@ -253,6 +255,7 @@ def bdd_norm_pr_ideal_gens(K, norm_list): :: sage: from sage.rings.number_field.bdd_height import bdd_norm_pr_ideal_gens + sage: x = polygen(ZZ, 'x') sage: K.<g> = NumberField(x^5 - x + 19) sage: b = bdd_norm_pr_ideal_gens(K, range(30)) sage: key = ZZ(28) @@ -279,9 +282,9 @@ def integer_points_in_polytope(matrix, interval_radius): Return the set of integer points in the polytope obtained by acting on a cube by a linear transformation. - Given an r-by-r matrix ``matrix`` and a real number ``interval_radius``, + Given an `r`-by-`r` matrix ``matrix`` and a real number ``interval_radius``, this function finds all integer lattice points in the polytope obtained by - transforming the cube [-interval_radius,interval_radius]^r via the linear + transforming the cube ``[-interval_radius, interval_radius]^r`` via the linear map induced by ``matrix``. INPUT: @@ -296,37 +299,38 @@ def integer_points_in_polytope(matrix, interval_radius): EXAMPLES: - Stretch the interval [-1,1] by a factor of 2 and find the integers in the + Stretch the interval `[-1,1]` by a factor of 2 and find the integers in the resulting interval:: sage: from sage.rings.number_field.bdd_height import integer_points_in_polytope sage: m = matrix([2]) sage: r = 1 - sage: integer_points_in_polytope(m,r) + sage: integer_points_in_polytope(m, r) [(-2), (-1), (0), (1), (2)] Integer points inside a parallelogram:: sage: from sage.rings.number_field.bdd_height import integer_points_in_polytope - sage: m = matrix([[1, 2],[3, 4]]) + sage: m = matrix([[1, 2], [3, 4]]) sage: r = RealField()(1.3) - sage: integer_points_in_polytope(m,r) - [(-3, -7), (-2, -5), (-2, -4), (-1, -3), (-1, -2), (-1, -1), (0, -1), (0, 0), (0, 1), (1, 1), (1, 2), (1, 3), (2, 4), (2, 5), (3, 7)] + sage: integer_points_in_polytope(m, r) + [(-3, -7), (-2, -5), (-2, -4), (-1, -3), (-1, -2), (-1, -1), (0, -1), + (0, 0), (0, 1), (1, 1), (1, 2), (1, 3), (2, 4), (2, 5), (3, 7)] Integer points inside a parallelepiped:: sage: from sage.rings.number_field.bdd_height import integer_points_in_polytope - sage: m = matrix([[1.2,3.7,0.2],[-5.3,-.43,3],[1.2,4.7,-2.1]]) + sage: m = matrix([[1.2,3.7,0.2], [-5.3,-.43,3], [1.2,4.7,-2.1]]) sage: r = 2.2 - sage: L = integer_points_in_polytope(m,r) + sage: L = integer_points_in_polytope(m, r) sage: len(L) 4143 If ``interval_radius`` is 0, the output should include only the zero tuple:: sage: from sage.rings.number_field.bdd_height import integer_points_in_polytope - sage: m = matrix([[1,2,3,7],[4,5,6,2],[7,8,9,3],[0,3,4,5]]) - sage: integer_points_in_polytope(m,0) + sage: m = matrix([[1,2,3,7], [4,5,6,2], [7,8,9,3], [0,3,4,5]]) + sage: integer_points_in_polytope(m, 0) [(0, 0, 0, 0)] """ T = matrix @@ -350,15 +354,15 @@ def bdd_height(K, height_bound, tolerance=1e-2, precision=53): multiplicative height at most ``height_bound``. The function can only be called for number fields `K` with positive unit - rank. An error will occur if `K` is `QQ` or an imaginary quadratic field. + rank. An error will occur if `K` is `\QQ` or an imaginary quadratic field. - This algorithm computes 2 lists: L containing elements x in `K` such that - H_k(x) <= B, and a list L' containing elements x in `K` that, due to + This algorithm computes 2 lists: `L`, containing elements `x` in `K` such that + `H_k(x) \leq B`, and a list `L'` containing elements `x` in `K` that, due to floating point issues, may be slightly larger then the bound. This can be controlled by lowering the tolerance. - In current implementation both lists (L,L') are merged and returned in + In current implementation both lists `(L,L')` are merged and returned in form of iterator. ALGORITHM: @@ -376,43 +380,44 @@ def bdd_height(K, height_bound, tolerance=1e-2, precision=53): OUTPUT: - - an iterator of number field elements + an iterator of number field elements EXAMPLES: There are no elements of negative height:: sage: from sage.rings.number_field.bdd_height import bdd_height + sage: x = polygen(ZZ, 'x') sage: K.<g> = NumberField(x^5 - x + 7) - sage: list(bdd_height(K,-3)) + sage: list(bdd_height(K, -3)) [] The only nonzero elements of height 1 are the roots of unity:: sage: from sage.rings.number_field.bdd_height import bdd_height sage: K.<g> = QuadraticField(3) - sage: list(bdd_height(K,1)) + sage: list(bdd_height(K, 1)) [0, -1, 1] :: sage: from sage.rings.number_field.bdd_height import bdd_height sage: K.<g> = QuadraticField(36865) - sage: len(list(bdd_height(K,101))) # long time (4 s) + sage: len(list(bdd_height(K, 101))) # long time (4 s) 131 :: sage: from sage.rings.number_field.bdd_height import bdd_height sage: K.<g> = NumberField(x^6 + 2) - sage: len(list(bdd_height(K,60))) # long time (5 s) + sage: len(list(bdd_height(K, 60))) # long time (5 s) 1899 :: sage: from sage.rings.number_field.bdd_height import bdd_height sage: K.<g> = NumberField(x^4 - x^3 - 3*x^2 + x + 1) - sage: len(list(bdd_height(K,10))) + sage: len(list(bdd_height(K, 10))) 99 TESTS: @@ -430,7 +435,6 @@ def bdd_height(K, height_bound, tolerance=1e-2, precision=53): if B < 1: return embeddings = K.places(prec=precision) - O_K = K.ring_of_integers() r1, r2 = K.signature() r = r1 + r2 - 1 RF = RealField(precision) @@ -455,14 +459,14 @@ def rational_in(x, y): def delta_approximation(x, delta): r""" - Compute a rational number in range `(x-delta, x+delta)` + Compute a rational number in range `(x-\delta, x+\delta)` """ return rational_in(x - delta, x + delta) def vector_delta_approximation(v, delta): r""" Compute a rational vector `w=(w_1, ..., w_n)` - such that `|v_i-w_i|<delta` for all `i` in `[1, n]` + such that `|v_i-w_i|<\delta` for all `i` in `[1, n]` """ return [delta_approximation(vi, delta) for vi in v] @@ -486,7 +490,7 @@ def log_height_for_generators_approx(alpha, beta, Lambda): Return a lambda approximation h_K(alpha/beta) """ delta = Lambda / (r + 2) - norm_log = delta_approximation(RR(O_K.ideal(alpha, beta).norm()).log(), delta) + norm_log = delta_approximation(RR(K.ideal(alpha, beta).norm()).log(), delta) log_ga = vector_delta_approximation(log_map(alpha), delta) log_gb = vector_delta_approximation(log_map(beta), delta) arch_sum = sum([max(log_ga[k], log_gb[k]) for k in range(r + 1)]) diff --git a/src/sage/rings/number_field/class_group.py b/src/sage/rings/number_field/class_group.py index 46b98c242e8..2bae4dd2df0 100644 --- a/src/sage/rings/number_field/class_group.py +++ b/src/sage/rings/number_field/class_group.py @@ -9,6 +9,7 @@ EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23) sage: I = K.class_group().gen(); I Fractional ideal class (2, 1/2*a - 1/2) @@ -53,30 +54,31 @@ class FractionalIdealClass(AbelianGroupWithValuesElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: G = NumberField(x^2 + 23,'a').class_group(); G - Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23 + Class group of order 3 with structure C3 of + Number Field in a with defining polynomial x^2 + 23 sage: I = G.0; I Fractional ideal class (2, 1/2*a - 1/2) sage: I.ideal() Fractional ideal (2, 1/2*a - 1/2) - EXAMPLES:: - - sage: K.<w>=QuadraticField(-23) - sage: OK=K.ring_of_integers() - sage: C=OK.class_group() - sage: P2a,P2b=[P for P,e in (2*OK).factor()] - sage: c = C(P2a); c - Fractional ideal class (2, 1/2*w - 1/2) - sage: c.gens() - (2, 1/2*w - 1/2) + sage: K.<w> = QuadraticField(-23) + sage: OK = K.ring_of_integers() + sage: C = OK.class_group() + sage: P2a, P2b = [P for P, e in (2*OK).factor()] + sage: c = C(P2a); c + Fractional ideal class (2, 1/2*w - 1/2) + sage: c.gens() + (2, 1/2*w - 1/2) """ def __init__(self, parent, element, ideal=None): """ - Returns the ideal class of this fractional ideal. + Return the ideal class of this fractional ideal. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23,'a'); G = K.class_group() sage: G(K.ideal(13, a + 4)) Fractional ideal class (13, 1/2*a + 17/2) @@ -91,6 +93,7 @@ def _repr_(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23,'a'); G = K.class_group() sage: G(K.ideal(13, a + 4))._repr_() 'Fractional ideal class (13, 1/2*a + 17/2)' @@ -99,7 +102,7 @@ def _repr_(self): """ if self.is_principal(): return 'Trivial principal fractional ideal class' - return 'Fractional ideal class %s'%self._value._repr_short() + return 'Fractional ideal class %s' % self._value._repr_short() def _mul_(self, other): r""" @@ -107,8 +110,10 @@ def _mul_(self, other): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: G = NumberField(x^2 + 23,'a').class_group(); G - Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23 + Class group of order 3 with structure C3 of + Number Field in a with defining polynomial x^2 + 23 sage: I = G.0; I Fractional ideal class (2, 1/2*a - 1/2) sage: I*I # indirect doctest @@ -134,8 +139,10 @@ def _div_(self, other): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: G = NumberField(x^2 + 23,'a').class_group(); G - Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23 + Class group of order 3 with structure C3 of + Number Field in a with defining polynomial x^2 + 23 sage: I = G.0; I Fractional ideal class (2, 1/2*a - 1/2) sage: I*I # indirect doctest @@ -153,8 +160,9 @@ def __pow__(self, n): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 3*x + 8) - sage: C=K.class_group() + sage: C = K.class_group() sage: c = C(2, a) sage: c^2 Fractional ideal class (4, a) @@ -178,6 +186,7 @@ def inverse(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 3*x + 8); G = K.class_group() sage: G(2, a).inverse() Fractional ideal class (2, a^2 + 2*a - 1) @@ -192,15 +201,15 @@ def inverse(self): def is_principal(self): r""" - Returns True iff this ideal class is the trivial (principal) class + Return ``True`` iff this ideal class is the trivial (principal) class. EXAMPLES:: - sage: K.<w>=QuadraticField(-23) - sage: OK=K.ring_of_integers() - sage: C=OK.class_group() - sage: P2a,P2b=[P for P,e in (2*OK).factor()] - sage: c=C(P2a) + sage: K.<w> = QuadraticField(-23) + sage: OK = K.ring_of_integers() + sage: C = OK.class_group() + sage: P2a, P2b = [P for P, e in (2*OK).factor()] + sage: c = C(P2a) sage: c.is_principal() False sage: (c^2).is_principal() @@ -217,9 +226,10 @@ def reduce(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 20072); G = k.class_group(); G - Class group of order 76 with structure C38 x C2 - of Number Field in a with defining polynomial x^2 + 20072 + Class group of order 76 with structure C38 x C2 of + Number Field in a with defining polynomial x^2 + 20072 sage: I = (G.0)^11; I Fractional ideal class (33, 1/2*a + 8) sage: J = G(I.ideal()^5); J @@ -237,11 +247,11 @@ def ideal(self): EXAMPLES:: - sage: K.<w>=QuadraticField(-23) - sage: OK=K.ring_of_integers() - sage: C=OK.class_group() - sage: P2a,P2b=[P for P,e in (2*OK).factor()] - sage: c=C(P2a); c + sage: K.<w> = QuadraticField(-23) + sage: OK = K.ring_of_integers() + sage: C = OK.class_group() + sage: P2a, P2b = [P for P, e in (2*OK).factor()] + sage: c = C(P2a); c Fractional ideal class (2, 1/2*w - 1/2) sage: c.ideal() Fractional ideal (2, 1/2*w - 1/2) @@ -254,31 +264,32 @@ def representative_prime(self, norm_bound=1000): INPUT: - ``norm_bound`` (positive integer) -- upper bound on the norm of primes tested. + - ``norm_bound`` -- (positive integer) upper bound on the norm of primes tested. EXAMPLES:: - sage: K.<a> = NumberField(x^2+31) - sage: K.class_number() - 3 - sage: Cl = K.class_group() - sage: [c.representative_prime() for c in Cl] - [Fractional ideal (3), - Fractional ideal (2, 1/2*a + 1/2), - Fractional ideal (2, 1/2*a - 1/2)] - - sage: K.<a> = NumberField(x^2+223) - sage: K.class_number() - 7 - sage: Cl = K.class_group() - sage: [c.representative_prime() for c in Cl] - [Fractional ideal (3), - Fractional ideal (2, 1/2*a + 1/2), - Fractional ideal (17, 1/2*a + 7/2), - Fractional ideal (7, 1/2*a - 1/2), - Fractional ideal (7, 1/2*a + 1/2), - Fractional ideal (17, 1/2*a + 27/2), - Fractional ideal (2, 1/2*a - 1/2)] + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 31) + sage: K.class_number() + 3 + sage: Cl = K.class_group() + sage: [c.representative_prime() for c in Cl] + [Fractional ideal (3), + Fractional ideal (2, 1/2*a + 1/2), + Fractional ideal (2, 1/2*a - 1/2)] + + sage: K.<a> = NumberField(x^2 + 223) + sage: K.class_number() + 7 + sage: Cl = K.class_group() + sage: [c.representative_prime() for c in Cl] + [Fractional ideal (3), + Fractional ideal (2, 1/2*a + 1/2), + Fractional ideal (17, 1/2*a + 7/2), + Fractional ideal (7, 1/2*a - 1/2), + Fractional ideal (7, 1/2*a + 1/2), + Fractional ideal (17, 1/2*a + 27/2), + Fractional ideal (2, 1/2*a - 1/2)] """ if self.value().is_prime(): return self.value() @@ -290,22 +301,21 @@ def representative_prime(self, norm_bound=1000): K = Cl.number_field() from sage.rings.real_mpfr import RR for P in K.primes_of_bounded_norm_iter(RR(norm_bound)): - if Cl(P)==c: + if Cl(P) == c: return P raise RuntimeError("No prime of norm less than %s found in class %s" % (norm_bound, c)) - def gens(self): r""" Return generators for a representative ideal in this - (S-)ideal class. + (`S`-)ideal class. EXAMPLES:: - sage: K.<w>=QuadraticField(-23) + sage: K.<w> = QuadraticField(-23) sage: OK = K.ring_of_integers() sage: C = OK.class_group() - sage: P2a,P2b=[P for P,e in (2*OK).factor()] + sage: P2a, P2b = [P for P, e in (2*OK).factor()] sage: c = C(P2a); c Fractional ideal class (2, 1/2*w - 1/2) sage: c.gens() @@ -314,51 +324,49 @@ def gens(self): return self.ideal().gens() - class SFractionalIdealClass(FractionalIdealClass): r""" - An S-fractional ideal class in a number field for a tuple of primes S. - - EXAMPLES:: + An `S`-fractional ideal class in a number field for a tuple `S` of primes. - sage: K.<a> = QuadraticField(-14) - sage: I = K.ideal(2,a) - sage: S = (I,) - sage: CS = K.S_class_group(S) - sage: J = K.ideal(7,a) - sage: G = K.ideal(3,a+1) - sage: CS(I) - Trivial S-ideal class - sage: CS(J) - Trivial S-ideal class - sage: CS(G) - Fractional S-ideal class (3, a + 1) + EXAMPLES:: - EXAMPLES:: + sage: K.<a> = QuadraticField(-14) + sage: I = K.ideal(2, a) + sage: S = (I,) + sage: CS = K.S_class_group(S) + sage: J = K.ideal(7, a) + sage: G = K.ideal(3, a + 1) + sage: CS(I) + Trivial S-ideal class + sage: CS(J) + Trivial S-ideal class + sage: CS(G) + Fractional S-ideal class (3, a + 1) - sage: K.<a> = QuadraticField(-14) - sage: I = K.ideal(2,a) - sage: S = (I,) - sage: CS = K.S_class_group(S) - sage: J = K.ideal(7,a) - sage: G = K.ideal(3,a+1) - sage: CS(I).ideal() - Fractional ideal (2, a) - sage: CS(J).ideal() - Fractional ideal (7, a) - sage: CS(G).ideal() - Fractional ideal (3, a + 1) + :: + sage: K.<a> = QuadraticField(-14) + sage: I = K.ideal(2, a) + sage: S = (I,) + sage: CS = K.S_class_group(S) + sage: J = K.ideal(7, a) + sage: G = K.ideal(3, a + 1) + sage: CS(I).ideal() + Fractional ideal (2, a) + sage: CS(J).ideal() + Fractional ideal (7, a) + sage: CS(G).ideal() + Fractional ideal (3, a + 1) - EXAMPLES:: + :: - sage: K.<a> = QuadraticField(-14) - sage: I = K.ideal(2,a) - sage: S = (I,) - sage: CS = K.S_class_group(S) - sage: G = K.ideal(3,a+1) - sage: CS(G).inverse() - Fractional S-ideal class (3, a + 2) + sage: K.<a> = QuadraticField(-14) + sage: I = K.ideal(2, a) + sage: S = (I,) + sage: CS = K.S_class_group(S) + sage: G = K.ideal(3, a + 1) + sage: CS(G).inverse() + Fractional S-ideal class (3, a + 2) TESTS:: @@ -378,7 +386,7 @@ class SFractionalIdealClass(FractionalIdealClass): def _repr_(self): r""" - Returns a string representation of the S-ideal class of this fractional ideal. + Return a string representation of the `S`-ideal class of this fractional ideal. EXAMPLES:: @@ -397,16 +405,17 @@ def _repr_(self): return 'Fractional S-ideal class %s' % self._value._repr_short() - class ClassGroup(AbelianGroupWithValues_class): r""" The class group of a number field. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23) sage: G = K.class_group(); G - Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23 + Class group of order 3 with structure C3 of + Number Field in a with defining polynomial x^2 + 23 sage: G.category() Category of finite enumerated commutative groups @@ -434,6 +443,7 @@ def __init__(self, gens_orders, names, number_field, gens, proof=True): TESTS:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23) sage: G = K.class_group() sage: TestSuite(G).run() @@ -451,6 +461,7 @@ def _element_constructor_(self, *args, **kwds): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<b> = NumberField(x^2 + 389) sage: C = K.class_group() sage: C(K.ideal(b)) # indirect doctest @@ -485,7 +496,8 @@ def _ideal_log(self, ideal): EXAMPLES:: - sage: K.<a> = NumberField(x^2 + 23,'a') + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 23, 'a') sage: G = K.class_group() sage: g = G.an_element() sage: G._ideal_log(g.ideal()) @@ -497,7 +509,7 @@ def _ideal_log(self, ideal): def gens_ideals(self): r""" - Return generating ideals for the (S-)class group. + Return generating ideals for the (`S`-)class group. This is an alias for :meth:`gens_values`. @@ -507,6 +519,7 @@ def gens_ideals(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 + 23) sage: K.class_group().gens_ideals() # random gens (platform dependent) (Fractional ideal (2, 1/4*a^3 - 1/4*a^2 + 1/4*a - 1/4),) @@ -527,6 +540,7 @@ def __iter__(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 + 23) sage: G = K.class_group() sage: G @@ -584,28 +598,31 @@ def _iter_inner(self, i0, k): def _repr_(self): r""" - Return string representation of self. + Return string representation of ``self``. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: C = NumberField(x^2 + 23, 'a').class_group() sage: C._repr_() 'Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23' """ - s = 'Class group of order %s '%self.order() + s = 'Class group of order %s ' % self.order() if self.order() > 1: - s += 'with structure %s '%self._group_notation(self.gens_orders()) - s += 'of %s'%self.number_field() + s += 'with structure %s ' % self._group_notation(self.gens_orders()) + s += 'of %s' % self.number_field() return s def number_field(self): r""" - Return the number field that this (S-)class group is attached to. + Return the number field that this (`S`-)class group is attached to. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: C = NumberField(x^2 + 23, 'w').class_group(); C - Class group of order 3 with structure C3 of Number Field in w with defining polynomial x^2 + 23 + Class group of order 3 with structure C3 of + Number Field in w with defining polynomial x^2 + 23 sage: C.number_field() Number Field in w with defining polynomial x^2 + 23 @@ -617,12 +634,9 @@ def number_field(self): return self._number_field - - - class SClassGroup(ClassGroup): r""" - The S-class group of a number field. + The `S`-class group of a number field. EXAMPLES:: @@ -633,7 +647,8 @@ class SClassGroup(ClassGroup): sage: K.<a> = QuadraticField(-974) sage: CS = K.S_class_group(K.primes_above(2)); CS - S-class group of order 18 with structure C6 x C3 of Number Field in a with defining polynomial x^2 + 974 with a = 31.20897306865447?*I + S-class group of order 18 with structure C6 x C3 of + Number Field in a with defining polynomial x^2 + 974 with a = 31.20897306865447?*I sage: CS.gen(0) # random Fractional S-ideal class (3, a + 2) sage: CS.gen(1) # random @@ -643,7 +658,7 @@ class SClassGroup(ClassGroup): def __init__(self, gens_orders, names, number_field, gens, S, proof=True): r""" - Create an S-class group. + Create an `S`-class group. EXAMPLES:: @@ -669,13 +684,15 @@ def S(self): EXAMPLES:: sage: K.<a> = QuadraticField(-14) - sage: I = K.ideal(2,a) + sage: I = K.ideal(2, a) sage: S = (I,) sage: CS = K.S_class_group(S);CS - S-class group of order 2 with structure C2 of Number Field in a with defining polynomial x^2 + 14 with a = 3.741657386773942?*I + S-class group of order 2 with structure C2 of + Number Field in a with defining polynomial x^2 + 14 with a = 3.741657386773942?*I sage: T = tuple() sage: CT = K.S_class_group(T);CT - S-class group of order 4 with structure C4 of Number Field in a with defining polynomial x^2 + 14 with a = 3.741657386773942?*I + S-class group of order 4 with structure C4 of + Number Field in a with defining polynomial x^2 + 14 with a = 3.741657386773942?*I sage: CS.S() (Fractional ideal (2, a),) sage: CT.S() diff --git a/src/sage/rings/number_field/galois_group.py b/src/sage/rings/number_field/galois_group.py index 1bf6189b7d9..07b58b7b2a2 100644 --- a/src/sage/rings/number_field/galois_group.py +++ b/src/sage/rings/number_field/galois_group.py @@ -11,6 +11,7 @@ Standard test of pickleability:: + sage: x = polygen(ZZ, 'x') sage: G = NumberField(x^3 + 2, 'alpha').galois_group(names='beta'); G Galois group 3T2 (S3) with order 6 of x^3 + 2 sage: G == loads(dumps(G)) @@ -44,12 +45,15 @@ class GaloisGroup_v1(SageObject): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.rings.number_field.galois_group import GaloisGroup_v1 sage: K = QQ[2^(1/3)] - sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K); G + sage: pK = K.absolute_polynomial() + sage: G = GaloisGroup_v1(pK.galois_group(pari_group=True), K); G ...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2 See https://github.com/sagemath/sage/issues/28782 for details. - Galois group PARI group [6, -1, 2, "S3"] of degree 3 of the Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873? + Galois group PARI group [6, -1, 2, "S3"] of degree 3 of the + Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873? sage: G.order() 6 sage: G.group() @@ -65,11 +69,13 @@ def __init__(self, group, number_field): EXAMPLES:: sage: from sage.rings.number_field.galois_group import GaloisGroup_v1 + sage: x = polygen(ZZ, 'x') sage: K = NumberField([x^2 + 1, x^2 + 2],'a') sage: GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K) ...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2 See https://github.com/sagemath/sage/issues/28782 for details. - Galois group PARI group [4, 1, 2, "E(4) = 2[x]2"] of degree 4 of the Number Field in a0 with defining polynomial x^2 + 1 over its base field + Galois group PARI group [4, 1, 2, "E(4) = 2[x]2"] of degree 4 of the + Number Field in a0 with defining polynomial x^2 + 1 over its base field """ deprecation(28782, "GaloisGroup_v1 is deprecated; please use GaloisGroup_v2") self.__group = group @@ -87,10 +93,13 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.rings.number_field.galois_group import GaloisGroup_v1 + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^3 + 2, 'alpha') sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K) ...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2 See https://github.com/sagemath/sage/issues/28782 for details. + + sage: # needs sage.symbolic sage: L = QQ[sqrt(2)] sage: H = GaloisGroup_v1(L.absolute_polynomial().galois_group(pari_group=True), L) sage: H == G @@ -115,10 +124,13 @@ def __ne__(self, other): EXAMPLES:: sage: from sage.rings.number_field.galois_group import GaloisGroup_v1 + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^3 + 2, 'alpha') sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K) ...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2 See https://github.com/sagemath/sage/issues/28782 for details. + + sage: # needs sage.symbolic sage: L = QQ[sqrt(2)] sage: H = GaloisGroup_v1(L.absolute_polynomial().galois_group(pari_group=True), L) sage: H != G @@ -137,6 +149,7 @@ def __repr__(self): EXAMPLES:: sage: from sage.rings.number_field.galois_group import GaloisGroup_v1 + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^4 + 2*x + 2, 'a') sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K) ...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2 @@ -154,6 +167,7 @@ def group(self): EXAMPLES:: sage: from sage.rings.number_field.galois_group import GaloisGroup_v1 + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^3 + 2*x + 2, 'theta') sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K) ...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2 @@ -174,11 +188,13 @@ def order(self): EXAMPLES:: sage: from sage.rings.number_field.galois_group import GaloisGroup_v1 + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^5 + 2, 'theta_1') sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K); G ...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2 See https://github.com/sagemath/sage/issues/28782 for details. - Galois group PARI group [20, -1, 3, "F(5) = 5:4"] of degree 5 of the Number Field in theta_1 with defining polynomial x^5 + 2 + Galois group PARI group [20, -1, 3, "F(5) = 5:4"] of degree 5 of the + Number Field in theta_1 with defining polynomial x^5 + 2 sage: G.order() 20 """ @@ -191,11 +207,13 @@ def number_field(self): EXAMPLES:: sage: from sage.rings.number_field.galois_group import GaloisGroup_v1 + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^6 + 2, 't') sage: G = GaloisGroup_v1(K.absolute_polynomial().galois_group(pari_group=True), K); G ...DeprecationWarning: GaloisGroup_v1 is deprecated; please use GaloisGroup_v2 See https://github.com/sagemath/sage/issues/28782 for details. - Galois group PARI group [12, -1, 3, "D(6) = S(3)[x]2"] of degree 6 of the Number Field in t with defining polynomial x^6 + 2 + Galois group PARI group [12, -1, 3, "D(6) = S(3)[x]2"] of degree 6 of the + Number Field in t with defining polynomial x^6 + 2 sage: G.number_field() Number Field in t with defining polynomial x^6 + 2 """ @@ -208,10 +226,10 @@ class GaloisGroup_v2(GaloisGroup_perm): .. NOTE:: - We define the Galois group of a non-normal field K to be the - Galois group of its Galois closure L, and elements are stored as - permutations of the roots of the defining polynomial of L, *not* as - permutations of the roots (in L) of the defining polynomial of K. The + We define the Galois group of a non-normal field `K` to be the + Galois group of its Galois closure `L`, and elements are stored as + permutations of the roots of the defining polynomial of `L`, *not* as + permutations of the roots (in `L`) of the defining polynomial of `K`. The latter would probably be preferable, but is harder to implement. Thus the permutation group that is returned is always simply-transitive. @@ -220,9 +238,11 @@ class GaloisGroup_v2(GaloisGroup_perm): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: G = NumberField(x^3 - x - 1, 'a').galois_closure('b').galois_group() sage: G.subgroup([G([(1,2,3),(4,5,6)])]) - Subgroup generated by [(1,2,3)(4,5,6)] of (Galois group 6T2 ([3]2) with order 6 of x^6 - 6*x^4 + 9*x^2 + 23) + Subgroup generated by [(1,2,3)(4,5,6)] of + (Galois group 6T2 ([3]2) with order 6 of x^6 - 6*x^4 + 9*x^2 + 23) Subgroups can be specified using generators (:trac:`26816`):: @@ -258,6 +278,7 @@ def __init__(self, number_field, algorithm='pari', names=None, gc_numbering=None You can specify the variable name for the Galois closure:: + sage: x = polygen(ZZ, 'x') sage: G = NumberField(x^3 - 2, 'b').galois_group(names="c"); G Galois group 3T2 (S3) with order 6 of x^3 - 2 sage: G._galois_closure @@ -300,6 +321,7 @@ def _pol_galgp(self, algorithm=None): EXAMPLES:: sage: R.<x> = ZZ[] + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2*x + 2) sage: G = K.galois_group() sage: G._pol_galgp() @@ -314,18 +336,20 @@ def _pol_galgp(self, algorithm=None): def group(self): """ - While GaloisGroup_v1 is being deprecated, this provides public access to the Pari/GAP group + While :class:`GaloisGroup_v1` is being deprecated, this provides public access to the PARI/GAP group in order to keep all aspects of that API. EXAMPLES:: sage: R.<x> = ZZ[] + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2*x + 2) sage: G = K.galois_group(type="pari") ...DeprecationWarning: the different Galois types have been merged into one class See https://github.com/sagemath/sage/issues/28782 for details. sage: G.group() - ...DeprecationWarning: the group method is deprecated; you can use _pol_galgp if you really need it + ...DeprecationWarning: the group method is deprecated; + you can use _pol_galgp if you really need it See https://github.com/sagemath/sage/issues/28782 for details. PARI group [6, -1, 2, "S3"] of degree 3 """ @@ -340,6 +364,7 @@ def order(self, algorithm=None, recompute=False): EXAMPLES:: sage: R.<x> = ZZ[] + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2*x + 2) sage: G = K.galois_group() sage: G.order() @@ -359,10 +384,12 @@ def easy_order(self, algorithm=None): EXAMPLES:: sage: R.<x> = ZZ[] + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2*x + 2) sage: G = K.galois_group() sage: G.easy_order() 6 + sage: x = polygen(ZZ, 'x') sage: L.<b> = NumberField(x^72 + 2*x + 2) sage: H = L.galois_group() sage: H.easy_order() @@ -379,7 +406,7 @@ def easy_order(self, algorithm=None): @cached_method(key=_alg_key) def transitive_number(self, algorithm=None, recompute=False): """ - Regardless of the value of ``gc_numbering``, this gives the transitive number + Regardless of the value of ``gc_numbering``, give the transitive number for the action on the roots of the defining polynomial of the original number field, not the Galois closure. @@ -391,10 +418,12 @@ def transitive_number(self, algorithm=None, recompute=False): EXAMPLES:: sage: R.<x> = ZZ[] + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2*x + 2) sage: G = K.galois_group() sage: G.transitive_number() 2 + sage: x = polygen(ZZ, 'x') sage: L.<b> = NumberField(x^13 + 2*x + 2) sage: H = L.galois_group(algorithm="gap") sage: H.transitive_number() # optional - gap_packages @@ -413,11 +442,12 @@ def transitive_number(self, algorithm=None, recompute=False): def pari_label(self): """ - Return the label assigned by Pari for this Galois group, an attempt at giving a human readable description of the group. + Return the label assigned by PARI for this Galois group, an attempt at giving a human readable description of the group. EXAMPLES:: sage: R.<x> = ZZ[] + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^8 - x^5 + x^4 - x^3 + 1) sage: G = K.galois_group() sage: G.transitive_label() @@ -430,11 +460,12 @@ def pari_label(self): @cached_method def signature(self): """ - Return 1 if contained in the alternating group, -1 otherwise. + Return `1` if contained in the alternating group, `-1` otherwise. EXAMPLES:: sage: R.<x> = ZZ[] + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: K.galois_group().signature() -1 @@ -455,11 +486,12 @@ def signature(self): @lazy_attribute def _gcdata(self): """ - Return the galois closure, together with the embedding of the top field into it + Return the Galois closure, together with the embedding of the top field into it EXAMPLES:: sage: R.<x> = ZZ[] + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: G = K.galois_group() sage: G._gcdata @@ -506,11 +538,12 @@ def _gcdata(self): @lazy_attribute def _pari_data(self): """ - Return the corresponding Pari Galois group structure. + Return the corresponding PARI Galois group structure. EXAMPLES:: sage: R.<x> = ZZ[] + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: G = K.galois_group() sage: G._pari_data @@ -526,6 +559,7 @@ def _elts(self): EXAMPLES:: sage: R.<x> = ZZ[] + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: G = K.galois_group() sage: G._elts @@ -548,12 +582,13 @@ def _elts(self): @lazy_attribute def _gens(self): """ - Computes the generators as permutations. + Compute the generators as permutations. EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^5-2) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^5 - 2) sage: G = K.galois_group(gc_numbering=False); G Galois group 5T3 (5:4) with order 20 of x^5 - 2 sage: G._gens @@ -641,10 +676,11 @@ def _element_constructor_(self, x, check=True): def is_galois(self): r""" - Whether the underlying number field is Galois + Whether the underlying number field is Galois. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: NumberField(x^3 - x + 1,'a').galois_group(names='b').is_galois() False sage: NumberField(x^2 - x + 1,'a').galois_group().is_galois() @@ -666,6 +702,7 @@ def _repr_(self): sage: G = QuadraticField(-23, 'a').galois_group() sage: G._repr_() 'Galois group 2T1 (S2) with order 2 of x^2 + 23' + sage: x = polygen(ZZ, 'x') sage: G = NumberField(x^3 - 2, 'a').galois_group(names='b') sage: G._repr_() 'Galois group 3T2 (S3) with order 6 of x^3 - 2' @@ -689,6 +726,7 @@ def number_field(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^3 - x + 1, 'a') sage: K.galois_group(names='b').number_field() is K True @@ -697,10 +735,11 @@ def number_field(self): def list(self): r""" - List of the elements of self. + List of the elements of ``self``. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: NumberField(x^3 - 3*x + 1,'a').galois_group().list() [(), (1,2,3), (1,3,2)] """ @@ -708,21 +747,23 @@ def list(self): def unrank(self, i): r""" - Return the ``i``-th element of ``self``. + Return the `i`-th element of ``self``. INPUT: - - ``i`` -- integer between ``0`` and ``n-1`` where - ``n`` is the cardinality of this set + - ``i`` -- integer between `0` and `n-1` where + `n` is the cardinality of this set EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: G = NumberField(x^3 - 3*x + 1,'a').galois_group() sage: [G.unrank(i) for i in range(G.cardinality())] [(), (1,2,3), (1,3,2)] TESTS:: + sage: x = polygen(ZZ, 'x') sage: G = NumberField(x^3 - 3*x + 1,'a').galois_group() sage: L = [G.unrank(i) for i in range(G.cardinality())] sage: L == G.list() @@ -736,6 +777,7 @@ def __iter__(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: G = NumberField(x^3 - 3*x + 1,'a').galois_group() sage: list(G) == G.list() True @@ -765,6 +807,7 @@ def _ramgroups(self, P): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 - 2*x^2 + 2,'b').galois_closure() sage: P = K.ideal([17, a^2]) sage: G = K.galois_group() @@ -777,22 +820,24 @@ def _ramgroups(self, P): def decomposition_group(self, P): r""" - Decomposition group of a prime ideal P, i.e. the subgroup of elements - that map P to itself. This is the same as the Galois group of the - extension of local fields obtained by completing at P. + Decomposition group of a prime ideal `P`, i.e., the subgroup of elements + that map `P` to itself. This is the same as the Galois group of the + extension of local fields obtained by completing at `P`. - This function will raise an error if P is not prime or the given number + This function will raise an error if `P` is not prime or the given number field is not Galois. - P can also be an infinite prime, i.e. an embedding into `\RR` or `\CC`. + `P` can also be an infinite prime, i.e., an embedding into `\RR` or `\CC`. EXAMPLES:: - sage: K.<a> = NumberField(x^4 - 2*x^2 + 2,'b').galois_closure() + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^4 - 2*x^2 + 2, 'b').galois_closure() sage: P = K.ideal([17, a^2]) sage: G = K.galois_group() sage: G.decomposition_group(P) - Subgroup generated by [(1,8)(2,7)(3,6)(4,5)] of (Galois group 8T4 ([4]2) with order 8 of x^8 - 20*x^6 + 104*x^4 - 40*x^2 + 1156) + Subgroup generated by [(1,8)(2,7)(3,6)(4,5)] of + (Galois group 8T4 ([4]2) with order 8 of x^8 - 20*x^6 + 104*x^4 - 40*x^2 + 1156) sage: G.decomposition_group(P^2) Traceback (most recent call last): ... @@ -804,7 +849,8 @@ def decomposition_group(self, P): An example with an infinite place:: - sage: L.<b> = NumberField(x^3 - 2,'a').galois_closure(); G=L.galois_group() + sage: x = polygen(ZZ, 'x') + sage: L.<b> = NumberField(x^3 - 2,'a').galois_closure(); G = L.galois_group() sage: x = L.places()[0] sage: G.decomposition_group(x).order() 2 @@ -822,8 +868,8 @@ def decomposition_group(self, P): def complex_conjugation(self, P=None): """ - Return the unique element of self corresponding to complex conjugation, - for a specified embedding P into the complex numbers. If P is not + Return the unique element of ``self`` corresponding to complex conjugation, + for a specified embedding `P` into the complex numbers. If `P` is not specified, use the "standard" embedding, whenever that is well-defined. EXAMPLES:: @@ -838,7 +884,8 @@ def complex_conjugation(self, P=None): An example where the field is not CM, so complex conjugation really depends on the choice of embedding:: - sage: L = NumberField(x^6 + 40*x^3 + 1372,'a') + sage: x = polygen(ZZ, 'x') + sage: L = NumberField(x^6 + 40*x^3 + 1372, 'a') sage: G = L.galois_group() sage: [G.complex_conjugation(x) for x in L.places()] [(1,3)(2,6)(4,5), (1,5)(2,4)(3,6), (1,2)(3,4)(5,6)] @@ -865,17 +912,19 @@ def complex_conjugation(self, P=None): def ramification_group(self, P, v): """ - Return the vth ramification group of self for the prime P, i.e. the set - of elements s of self such that s acts trivially modulo P^(v+1). This + Return the `v`-th ramification group of ``self`` for the prime `P`, i.e., the set + of elements `s` of ``self`` such that `s` acts trivially modulo `P^{(v+1)}`. This is only defined for Galois fields. EXAMPLES:: - sage: K.<b> = NumberField(x^3 - 3,'a').galois_closure() + sage: x = polygen(ZZ, 'x') + sage: K.<b> = NumberField(x^3 - 3, 'a').galois_closure() sage: G=K.galois_group() sage: P = K.primes_above(3)[0] sage: G.ramification_group(P, 3) - Subgroup generated by [(1,2,4)(3,5,6)] of (Galois group 6T2 ([3]2) with order 6 of x^6 + 243) + Subgroup generated by [(1,2,4)(3,5,6)] of + (Galois group 6T2 ([3]2) with order 6 of x^6 + 243) sage: G.ramification_group(P, 5) Subgroup generated by [()] of (Galois group 6T2 ([3]2) with order 6 of x^6 + 243) """ @@ -891,12 +940,13 @@ def ramification_group(self, P, v): def inertia_group(self, P): """ - Return the inertia group of the prime P, i.e. the group of elements acting - trivially modulo P. This is just the 0th ramification group of P. + Return the inertia group of the prime `P`, i.e., the group of elements acting + trivially modulo `P`. This is just the 0th ramification group of `P`. EXAMPLES:: - sage: K.<b> = NumberField(x^2 - 3,'a') + sage: x = polygen(ZZ, 'x') + sage: K.<b> = NumberField(x^2 - 3, 'a') sage: G = K.galois_group() sage: G.inertia_group(K.primes_above(2)[0]) Subgroup generated by [(1,2)] of (Galois group 2T1 (S2) with order 2 of x^2 - 3) @@ -909,18 +959,21 @@ def inertia_group(self, P): def ramification_breaks(self, P): r""" - Return the set of ramification breaks of the prime ideal P, i.e. the - set of indices i such that the ramification group `G_{i+1} \ne G_{i}`. + Return the set of ramification breaks of the prime ideal `P`, i.e., the + set of indices `i` such that the ramification group `G_{i+1} \ne G_{i}`. This is only defined for Galois fields. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<b> = NumberField(x^8 - 20*x^6 + 104*x^4 - 40*x^2 + 1156) sage: G = K.galois_group() sage: P = K.primes_above(2)[0] sage: G.ramification_breaks(P) {1, 3, 5} - sage: min( [ G.ramification_group(P, i).order() / G.ramification_group(P, i+1).order() for i in G.ramification_breaks(P)] ) + sage: min(G.ramification_group(P, i).order() + ....: / G.ramification_group(P, i + 1).order() + ....: for i in G.ramification_breaks(P)) 2 """ if not self.is_galois(): @@ -934,17 +987,19 @@ def ramification_breaks(self, P): def artin_symbol(self, P): r""" Return the Artin symbol `\left(\frac{K / - \QQ}{\mathfrak{P}}\right)`, where K is the number field of self, + \QQ}{\mathfrak{P}}\right)`, where `K` is the number field of ``self``, and `\mathfrak{P}` is an unramified prime ideal. This is the unique - element s of the decomposition group of `\mathfrak{P}` such that `s(x) = x^p \bmod - \mathfrak{P}`, where p is the residue characteristic of `\mathfrak{P}`. + element `s` of the decomposition group of `\mathfrak{P}` such that `s(x) = x^p \bmod + \mathfrak{P}`, where `p` is the residue characteristic of `\mathfrak{P}`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<b> = NumberField(x^4 - 2*x^2 + 2, 'a').galois_closure() sage: G = K.galois_group() sage: [G.artin_symbol(P) for P in K.primes_above(7)] - [(1,4)(2,3)(5,8)(6,7), (1,4)(2,3)(5,8)(6,7), (1,5)(2,6)(3,7)(4,8), (1,5)(2,6)(3,7)(4,8)] + [(1,4)(2,3)(5,8)(6,7), (1,4)(2,3)(5,8)(6,7), + (1,5)(2,6)(3,7)(4,8), (1,5)(2,6)(3,7)(4,8)] sage: G.artin_symbol(17) Traceback (most recent call last): ... @@ -990,18 +1045,20 @@ class GaloisGroup_subgroup(GaloisSubgroup_perm): - ``category`` -- the category for this object - - ``canonicalize`` -- if true, sorts and removes duplicates + - ``canonicalize`` -- if ``True``, sorts and removes duplicates - ``check`` -- whether to check that generators actually lie in the ambient group EXAMPLES:: sage: from sage.rings.number_field.galois_group import GaloisGroup_subgroup + sage: x = polygen(ZZ, 'x') sage: G = NumberField(x^3 - x - 1, 'a').galois_closure('b').galois_group() sage: GaloisGroup_subgroup( G, [G([(1,2,3),(4,5,6)])]) - Subgroup generated by [(1,2,3)(4,5,6)] of (Galois group 6T2 ([3]2) with order 6 of x^6 - 6*x^4 + 9*x^2 + 23) + Subgroup generated by [(1,2,3)(4,5,6)] of + (Galois group 6T2 ([3]2) with order 6 of x^6 - 6*x^4 + 9*x^2 + 23) - sage: K.<a> = NumberField(x^6-3*x^2-1) + sage: K.<a> = NumberField(x^6 - 3*x^2 - 1) sage: L.<b> = K.galois_closure() sage: G = L.galois_group() sage: P = L.primes_above(3)[0] @@ -1012,7 +1069,8 @@ class GaloisGroup_subgroup(GaloisSubgroup_perm): sage: G = NumberField(x^3 - x - 1, 'a').galois_closure('b').galois_group() sage: H = G.subgroup([G([(1,2,3),(4,5,6)])]) sage: H - Subgroup generated by [(1,2,3)(4,5,6)] of (Galois group 6T2 ([3]2) with order 6 of x^6 - 6*x^4 + 9*x^2 + 23) + Subgroup generated by [(1,2,3)(4,5,6)] of + (Galois group 6T2 ([3]2) with order 6 of x^6 - 6*x^4 + 9*x^2 + 23) TESTS: @@ -1030,10 +1088,11 @@ class GaloisGroup_subgroup(GaloisSubgroup_perm): @lazy_attribute def _pari_data(self): """ - Access to Pari information for the ambient Galois group. + Access to PARI information for the ambient Galois group. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a> = NumberField(x^4 + 1) sage: G = L.galois_group() sage: H = G.decomposition_group(L.primes_above(3)[0]) @@ -1052,13 +1111,14 @@ def fixed_field(self, name=None, polred=None, threshold=None): - ``name`` -- a variable name for the new field. - ``polred`` -- whether to optimize the generator of the newly created field - for a simpler polynomial, using pari's polredbest. + for a simpler polynomial, using PARI's :pari:`polredbest`. Defaults to ``True`` when the degree of the fixed field is at most 8. - ``threshold`` -- positive number; polred only performed if the cost is at most this threshold EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a> = NumberField(x^4 + 1) sage: G = L.galois_group() sage: H = G.decomposition_group(L.primes_above(3)[0]) @@ -1077,28 +1137,32 @@ def fixed_field(self, name=None, polred=None, threshold=None): sage: sigma, tau = G.gens() sage: H = G.subgroup([tau]) sage: H.fixed_field(polred=False) - (Number Field in a0 with defining polynomial x^2 + 84375 with a0 = 5*ac^5 + 25*ac^3, + (Number Field in a0 with defining polynomial x^2 + 84375 + with a0 = 5*ac^5 + 25*ac^3, Ring morphism: - From: Number Field in a0 with defining polynomial x^2 + 84375 with a0 = 5*ac^5 + 25*ac^3 + From: Number Field in a0 with defining polynomial x^2 + 84375 + with a0 = 5*ac^5 + 25*ac^3 To: Number Field in ac with defining polynomial x^10 + 10*x^8 + 25*x^6 + 3375 Defn: a0 |--> 5*ac^5 + 25*ac^3) sage: H.fixed_field(polred=True) - (Number Field in a0 with defining polynomial x^2 - x + 4 with a0 = -1/30*ac^5 - 1/6*ac^3 + 1/2, + (Number Field in a0 with defining polynomial x^2 - x + 4 + with a0 = -1/30*ac^5 - 1/6*ac^3 + 1/2, Ring morphism: - From: Number Field in a0 with defining polynomial x^2 - x + 4 with a0 = -1/30*ac^5 - 1/6*ac^3 + 1/2 + From: Number Field in a0 with defining polynomial x^2 - x + 4 + with a0 = -1/30*ac^5 - 1/6*ac^3 + 1/2 To: Number Field in ac with defining polynomial x^10 + 10*x^8 + 25*x^6 + 3375 Defn: a0 |--> -1/30*ac^5 - 1/6*ac^3 + 1/2) sage: G.splitting_field() Number Field in ac with defining polynomial x^10 + 10*x^8 + 25*x^6 + 3375 - An embedding is returned also if the subgroup is trivial (:trac:`26817`):: sage: H = G.subgroup([]) sage: H.fixed_field() (Number Field in ac with defining polynomial x^10 + 10*x^8 + 25*x^6 + 3375, - Identity endomorphism of Number Field in ac with defining polynomial x^10 + 10*x^8 + 25*x^6 + 3375) + Identity endomorphism of + Number Field in ac with defining polynomial x^10 + 10*x^8 + 25*x^6 + 3375) """ G = self._ambient_group L = G._galois_closure @@ -1138,6 +1202,7 @@ class GaloisGroupElement(PermutationGroupElement): sage: G[1](w + 2) -w + 2 + sage: x = polygen(ZZ, 'x') sage: L.<v> = NumberField(x^3 - 2); G = L.galois_group(names='y') sage: G[4] (1,5)(2,4)(3,6) @@ -1151,14 +1216,15 @@ class GaloisGroupElement(PermutationGroupElement): @cached_method def as_hom(self): r""" - Return the homomorphism L -> L corresponding to self, where L is the + Return the homomorphism `L \to L` corresponding to ``self``, where `L` is the Galois closure of the ambient number field. EXAMPLES:: sage: G = QuadraticField(-7,'w').galois_group() sage: G[1].as_hom() - Ring endomorphism of Number Field in w with defining polynomial x^2 + 7 with w = 2.645751311064591?*I + Ring endomorphism of Number Field in w with defining polynomial x^2 + 7 + with w = 2.645751311064591?*I Defn: w |--> -w TESTS: @@ -1167,6 +1233,7 @@ def as_hom(self): polynomials are supported (:trac:`252`):: sage: R.<x> = QQ[] + sage: x = polygen(ZZ, 'x') sage: f = 7/9*x^3 + 7/3*x^2 - 56*x + 123 sage: K.<a> = NumberField(f) sage: G = K.galois_group() @@ -1206,11 +1273,12 @@ def __call__(self, x): def ramification_degree(self, P): """ - Return the greatest value of v such that s acts trivially modulo P^v. - Should only be used if P is prime and s is in the decomposition group of P. + Return the greatest value of `v` such that `s` acts trivially modulo `P^v`. + Should only be used if `P` is prime and `s` is in the decomposition group of `P`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<b> = NumberField(x^3 - 3, 'a').galois_closure() sage: G = K.galois_group() sage: P = K.primes_above(3)[0] @@ -1224,6 +1292,7 @@ def ramification_degree(self, P): w = [(self(g) - g).valuation(P) for g in gens] return min(w) + GaloisGroup_v2.Element = GaloisGroupElement GaloisGroup_v2.Subgroup = GaloisGroup_subgroup GaloisGroup_subgroup.Element = GaloisGroupElement diff --git a/src/sage/rings/number_field/homset.py b/src/sage/rings/number_field/homset.py index 6353353afe1..ca5329668c5 100644 --- a/src/sage/rings/number_field/homset.py +++ b/src/sage/rings/number_field/homset.py @@ -14,8 +14,6 @@ # **************************************************************************** from sage.misc.cachefunc import cached_method -from sage.misc.superseded import deprecation - from sage.rings.homset import RingHomset_generic from sage.rings.number_field.morphism import (NumberFieldHomomorphism_im_gens, RelativeNumberFieldHomomorphism_from_abs, @@ -43,6 +41,7 @@ def __init__(self, R, S, category=None): Check that :trac:`23647` is fixed:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 - 2, x^2 - 3]) sage: e, u, v, w = End(K) sage: e.abs_hom().parent().category() @@ -142,7 +141,7 @@ def _an_element_(self): else: from sage.categories.sets_cat import EmptySetError raise EmptySetError("There is no morphism from {} to {}".format( - self.domain(), self.codomain())) + self.domain(), self.codomain())) def _repr_(self): r""" @@ -168,6 +167,7 @@ def order(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: End(k) Automorphism group of Number Field in a with defining polynomial x^2 + 1 @@ -177,7 +177,7 @@ def order(self): sage: End(k).order() 1 - sage: K.<a> = NumberField( [x^3 + 2, x^2 + x + 1] ) + sage: K.<a> = NumberField([x^3 + 2, x^2 + x + 1]) sage: End(K).order() 6 """ @@ -188,10 +188,11 @@ def order(self): @cached_method def list(self): """ - Return a list of all the elements of self. + Return a list of all the elements of ``self``. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 3*x + 1) sage: End(K).list() [ @@ -235,7 +236,7 @@ def list(self): v = [D.hom([r], codomain=C, check=False) for r in roots] else: v = [] - return Sequence(v, universe=self, check=False, immutable=True, cr=v!=[]) + return Sequence(v, universe=self, check=False, immutable=True, cr=bool(v)) def __getitem__(self, n): r""" @@ -259,15 +260,17 @@ class RelativeNumberFieldHomset(NumberFieldHomset): We construct a homomorphism from a relative field by giving the image of a generator:: + sage: x = polygen(ZZ, 'x') sage: L.<cuberoot2, zeta3> = CyclotomicField(3).extension(x^3 - 2) sage: phi = L.hom([cuberoot2 * zeta3]); phi - Relative number field endomorphism of Number Field in cuberoot2 with defining polynomial x^3 - 2 over its base field + Relative number field endomorphism of + Number Field in cuberoot2 with defining polynomial x^3 - 2 over its base field Defn: cuberoot2 |--> zeta3*cuberoot2 zeta3 |--> zeta3 sage: phi(cuberoot2 + zeta3) zeta3*cuberoot2 + zeta3 - In fact, this phi is a generator for the Kummer Galois group of this + In fact, this ``phi`` is a generator for the Kummer Galois group of this cyclic extension:: sage: phi(phi(cuberoot2 + zeta3)) @@ -278,7 +281,7 @@ class RelativeNumberFieldHomset(NumberFieldHomset): Element = RelativeNumberFieldHomomorphism_from_abs - def _element_constructor_(self, x, base_map=None, base_hom=None, check=True): + def _element_constructor_(self, x, base_map=None, check=True): """ Construct an element of ``self`` from ``x``. @@ -300,6 +303,7 @@ def _element_constructor_(self, x, base_map=None, base_hom=None, check=True): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 1) sage: L.<b> = K.extension(x^4 - 2) sage: E = End(L) @@ -336,10 +340,10 @@ def _element_constructor_(self, x, base_map=None, base_hom=None, check=True): are only approximate:: sage: K.<a> = QuadraticField(-7) - sage: f = K.hom([CC(sqrt(-7))], check=False) + sage: f = K.hom([CC(sqrt(-7))], check=False) # needs sage.symbolic sage: x = polygen(K) sage: L.<b> = K.extension(x^2 - a - 5) - sage: L.Hom(CC)(f(a + 5).sqrt(), f, check=False) + sage: L.Hom(CC)(f(a + 5).sqrt(), f, check=False) # needs sage.symbolic Relative number field morphism: From: Number Field in b with defining polynomial x^2 - a - 5 over its base field To: Complex Field with 53 bits of precision @@ -371,9 +375,6 @@ def _element_constructor_(self, x, base_map=None, base_hom=None, check=True): sage: (x^2 + a).change_ring(phi) x^2 + 1/6*c^3 + 1/6*c """ - if base_hom is not None: - deprecation(26105, "Use base_map rather than base_hom") - base_map = base_hom if isinstance(x, NumberFieldHomomorphism_im_gens): # Then it must be a homomorphism from the corresponding # absolute number field @@ -383,7 +384,7 @@ def _element_constructor_(self, x, base_map=None, base_hom=None, check=True): raise ValueError("codomain of absolute homomorphism must be codomain of this homset.") return self.element_class(self, x) if (isinstance(x, RelativeNumberFieldHomomorphism_from_abs) - and x.parent() == self): + and x.parent() == self): return self.element_class(self, x.abs_hom()) if base_map is None: base_map = self.default_base_hom() @@ -400,6 +401,7 @@ def _from_im(self, im_gen, base_map, check=True): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23) sage: L.<b> = K.extension(x^3 - x + 1) sage: End(L)._from_im( -3/23*a*b^2 + (-9/46*a - 1/2)*b + 2/23*a, K.hom([-a], K)) @@ -422,11 +424,12 @@ def _from_im(self, im_gen, base_map, check=True): @cached_method def default_base_hom(self): r""" - Pick an embedding of the base field of self into the codomain of this + Pick an embedding of the base field of ``self`` into the codomain of this homset. This is done in an essentially arbitrary way. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^3 - x + 1, x^2 + 23]) sage: M.<c> = NumberField(x^4 + 80*x^2 + 36) sage: Hom(L, M).default_base_hom() @@ -468,25 +471,29 @@ def default_base_hom(self): @cached_method def list(self): """ - Return a list of all the elements of self (for which the domain + Return a list of all the elements of ``self`` (for which the domain is a relative number field). EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + x + 1, x^3 + 2]) sage: End(K).list() [ - Relative number field endomorphism of Number Field in a with defining polynomial x^2 + x + 1 over its base field + Relative number field endomorphism of + Number Field in a with defining polynomial x^2 + x + 1 over its base field Defn: a |--> a b |--> b, ... - Relative number field endomorphism of Number Field in a with defining polynomial x^2 + x + 1 over its base field + Relative number field endomorphism of + Number Field in a with defining polynomial x^2 + x + 1 over its base field Defn: a |--> a b |--> -b*a - b ] An example with an absolute codomain:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 - 3, x^2 + 2]) sage: Hom(K, CyclotomicField(24, 'z')).list() [ @@ -507,7 +514,7 @@ def list(self): C = self.codomain() D_abs = D.absolute_field('a') v = [self(f, check=False) for f in D_abs.Hom(C).list()] - return Sequence(v, universe=self, check=False, immutable=True, cr=v!=[]) + return Sequence(v, universe=self, check=False, immutable=True, cr=bool(v)) class CyclotomicFieldHomset(NumberFieldHomset): @@ -567,14 +574,14 @@ def _element_constructor_(self, x, check=True): x^2 + b """ if (isinstance(x, CyclotomicFieldHomomorphism_im_gens) - and x.parent() == self): + and x.parent() == self): return self.element_class(self, x.im_gens()) return self.element_class(self, x, check=check) @cached_method def list(self): """ - Return a list of all the elements of self (for which the domain + Return a list of all the elements of ``self`` (for which the domain is a cyclotomic field). EXAMPLES:: @@ -584,6 +591,7 @@ def list(self): Automorphism group of Cyclotomic Field of order 12 and degree 4 sage: [g(z) for g in G] [z, z^3 - z, -z, -z^3 + z] + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + x + 1, x^4 + 1]) sage: L Number Field in a with defining polynomial x^2 + x + 1 over its base field @@ -602,11 +610,11 @@ def list(self): z = D.gen() n = z.multiplicative_order() if not n.divides(C.zeta_order()): - v =[] + v = [] else: if D == C: w = z else: w = C.zeta(n) v = [self([w**k], check=False) for k in Zmod(n) if k.is_unit()] - return Sequence(v, universe=self, check=False, immutable=True, cr=v!=[]) + return Sequence(v, universe=self, check=False, immutable=True, cr=bool(v)) diff --git a/src/sage/rings/number_field/maps.py b/src/sage/rings/number_field/maps.py index 68d03c73af3..182bfea18d2 100644 --- a/src/sage/rings/number_field/maps.py +++ b/src/sage/rings/number_field/maps.py @@ -6,17 +6,22 @@ EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<cuberoot2, zeta3> = CyclotomicField(3).extension(x^3 - 2) sage: K = L.absolute_field('a') sage: from_K, to_K = K.structure() sage: from_K Isomorphism map: - From: Number Field in a with defining polynomial x^6 - 3*x^5 + 6*x^4 - 11*x^3 + 12*x^2 + 3*x + 1 - To: Number Field in cuberoot2 with defining polynomial x^3 - 2 over its base field + From: Number Field in a with defining polynomial + x^6 - 3*x^5 + 6*x^4 - 11*x^3 + 12*x^2 + 3*x + 1 + To: Number Field in cuberoot2 with defining polynomial + x^3 - 2 over its base field sage: to_K Isomorphism map: - From: Number Field in cuberoot2 with defining polynomial x^3 - 2 over its base field - To: Number Field in a with defining polynomial x^6 - 3*x^5 + 6*x^4 - 11*x^3 + 12*x^2 + 3*x + 1 + From: Number Field in cuberoot2 with defining polynomial + x^3 - 2 over its base field + To: Number Field in a with defining polynomial + x^6 - 3*x^5 + 6*x^4 - 11*x^3 + 12*x^2 + 3*x + 1 """ #***************************************************************************** @@ -54,6 +59,7 @@ class NumberFieldIsomorphism(Map): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 + 3*x + 1) sage: V, fr, to = K.vector_space() sage: isinstance(fr, sage.rings.number_field.maps.NumberFieldIsomorphism) @@ -63,6 +69,7 @@ def _repr_type(self): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 + 3*x + 1) sage: V, fr, to = K.vector_space() sage: fr._repr_type() @@ -72,23 +79,25 @@ def _repr_type(self): def is_injective(self): r""" - EXAMPLES:: + EXAMPLES:: - sage: K.<a> = NumberField(x^4 + 3*x + 1) - sage: V, fr, to = K.vector_space() - sage: fr.is_injective() - True + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^4 + 3*x + 1) + sage: V, fr, to = K.vector_space() + sage: fr.is_injective() + True """ return True def is_surjective(self): r""" - EXAMPLES:: + EXAMPLES:: - sage: K.<a> = NumberField(x^4 + 3*x + 1) - sage: V, fr, to = K.vector_space() - sage: fr.is_surjective() - True + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^4 + 3*x + 1) + sage: V, fr, to = K.vector_space() + sage: fr.is_surjective() + True """ return True @@ -98,6 +107,7 @@ class MapVectorSpaceToNumberField(NumberFieldIsomorphism): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 + 3*x + 1) sage: V, fr, to = K.vector_space() sage: V @@ -118,9 +128,11 @@ class MapVectorSpaceToNumberField(NumberFieldIsomorphism): (True, True) sage: fr.domain(), to.codomain() - (Vector space of dimension 4 over Rational Field, Vector space of dimension 4 over Rational Field) + (Vector space of dimension 4 over Rational Field, + Vector space of dimension 4 over Rational Field) sage: to.domain(), fr.codomain() - (Number Field in a with defining polynomial x^4 + 3*x + 1, Number Field in a with defining polynomial x^4 + 3*x + 1) + (Number Field in a with defining polynomial x^4 + 3*x + 1, + Number Field in a with defining polynomial x^4 + 3*x + 1) sage: fr * to Composite map: From: Number Field in a with defining polynomial x^4 + 3*x + 1 @@ -154,6 +166,7 @@ def __init__(self, V, K): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<c> = NumberField(x^9 + 3) sage: V, fr, to = K.vector_space(); fr # indirect doctest Isomorphism map: @@ -168,6 +181,7 @@ def _call_(self, v): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<c> = NumberField(x^9 + 3) sage: V, fr, to = K.vector_space() sage: list(map(fr, V.gens())) # indirect doctest @@ -184,6 +198,7 @@ class MapNumberFieldToVectorSpace(Map): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a> = NumberField(x^3 - x + 1) sage: V, fr, to = L.vector_space() sage: type(to) @@ -195,6 +210,7 @@ def __init__(self, K, V): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a> = NumberField(x^3 - x + 1) sage: L.vector_space()[2] # indirect doctest Isomorphism map: @@ -207,6 +223,7 @@ def _repr_type(self): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 1, x^2 - 3]) sage: V, fr, to = L.relative_vector_space() sage: fr._repr_type() @@ -218,6 +235,7 @@ def _call_(self, x): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a> = NumberField(x^3 - x + 1) sage: V, _, to = L.vector_space() sage: v = to(a^2 - a/37 + 56); v # indirect doctest @@ -235,6 +253,7 @@ class MapRelativeVectorSpaceToRelativeNumberField(NumberFieldIsomorphism): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<b> = NumberField(x^4 + 3*x^2 + 1) sage: K = L.relativize(L.subfields(2)[0][1], 'a'); K Number Field in a with defining polynomial x^2 - b0*x + 1 over its base field @@ -243,8 +262,10 @@ class MapRelativeVectorSpaceToRelativeNumberField(NumberFieldIsomorphism): Vector space of dimension 2 over Number Field in b0 with defining polynomial x^2 + 1 sage: fr Isomorphism map: - From: Vector space of dimension 2 over Number Field in b0 with defining polynomial x^2 + 1 - To: Number Field in a with defining polynomial x^2 - b0*x + 1 over its base field + From: Vector space of dimension 2 + over Number Field in b0 with defining polynomial x^2 + 1 + To: Number Field in a + with defining polynomial x^2 - b0*x + 1 over its base field sage: type(fr) <class 'sage.rings.number_field.maps.MapRelativeVectorSpaceToRelativeNumberField'> @@ -261,6 +282,7 @@ def __init__(self, V, K): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 1, x^2 - 2]) sage: V, _, to = K.relative_vector_space(); to # indirect doctest Isomorphism map: @@ -273,6 +295,7 @@ def _call_(self, v): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<b> = NumberField(x^4 + 3*x^2 + 1) sage: K = L.relativize(L.subfields(2)[0][1], 'a') sage: a0 = K.gen(); b0 = K.base_field().gen() @@ -295,6 +318,7 @@ class MapRelativeNumberFieldToRelativeVectorSpace(NumberFieldIsomorphism): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^3 - x + 1, x^2 + 23]) sage: V, fr, to = K.relative_vector_space() sage: type(to) @@ -305,6 +329,7 @@ def __init__(self, K, V): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<b> = NumberField(x^4 + 3*x^2 + 1) sage: K = L.relativize(L.subfields(2)[0][1], 'a') sage: V, fr, to = K.relative_vector_space() @@ -319,7 +344,8 @@ def _call_(self, alpha): """ TESTS:: - sage: K.<a> = NumberField(x^5+2) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^5 + 2) sage: R.<y> = K[] sage: D.<x0> = K.extension(y + a + 1) sage: D(a) @@ -368,6 +394,7 @@ class NameChangeMap(NumberFieldIsomorphism): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 3) sage: L.<b> = K.change_names() sage: from_L, to_L = L.structure() @@ -380,18 +407,21 @@ class NameChangeMap(NumberFieldIsomorphism): From: Number Field in a with defining polynomial x^2 - 3 To: Number Field in b with defining polynomial x^2 - 3 sage: type(from_L), type(to_L) - (<class 'sage.rings.number_field.maps.NameChangeMap'>, <class 'sage.rings.number_field.maps.NameChangeMap'>) + (<class 'sage.rings.number_field.maps.NameChangeMap'>, + <class 'sage.rings.number_field.maps.NameChangeMap'>) """ def __init__(self, K, L): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 - 3, x^2 + 7]) sage: L.<c, d> = K.change_names() sage: L.structure() (Isomorphism given by variable name change map: From: Number Field in c with defining polynomial x^2 - 3 over its base field - To: Number Field in a with defining polynomial x^2 - 3 over its base field, Isomorphism given by variable name change map: + To: Number Field in a with defining polynomial x^2 - 3 over its base field, + Isomorphism given by variable name change map: From: Number Field in a with defining polynomial x^2 - 3 over its base field To: Number Field in c with defining polynomial x^2 - 3 over its base field) """ @@ -401,6 +431,7 @@ def _repr_type(self): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 3) sage: L.<b> = K.change_names() sage: from_L, to_L = L.structure() @@ -413,6 +444,7 @@ def _call_(self, x): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 - 3, x^2 + 7]) sage: L.<c, d> = K.change_names() sage: to_K, from_K = L.structure() @@ -428,6 +460,7 @@ class MapRelativeToAbsoluteNumberField(NumberFieldIsomorphism): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^6 + 4*x^2 + 200) sage: L = K.relativize(K.subfields(3)[0][1], 'b'); L Number Field in b with defining polynomial x^2 + a0 over its base field @@ -473,6 +506,7 @@ def __init__(self, R, A): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: K.<c> = L.absolute_field() sage: f = K.structure()[1]; f @@ -488,6 +522,7 @@ def _call_(self, x): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: K.<c> = L.absolute_field() sage: f = K.structure()[1] @@ -506,6 +541,7 @@ def __init__(self, A, R): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: K.<c> = L.absolute_field() sage: f = K.structure()[0] # indirect doctest @@ -518,6 +554,7 @@ def _call_(self, x): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: K.<c> = L.absolute_field() sage: f = K.structure()[0] @@ -535,6 +572,7 @@ class MapVectorSpaceToRelativeNumberField(NumberFieldIsomorphism): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: V, fr, to = L.absolute_vector_space() sage: type(fr) @@ -545,6 +583,7 @@ def __init__(self, V, L, from_V, from_K): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: V, fr, to = L.absolute_vector_space() # indirect doctest sage: fr @@ -560,6 +599,7 @@ def _call_(self, x): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: V, fr, to = L.absolute_vector_space() sage: fr(V([1,3,0,1/17])) # indirect doctest @@ -576,6 +616,7 @@ class MapRelativeNumberFieldToVectorSpace(NumberFieldIsomorphism): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^8 + 100*x^6 + x^2 + 5) sage: L = K.relativize(K.subfields(4)[0][1], 'b'); L Number Field in b with defining polynomial x^2 + a0 over its base field @@ -606,6 +647,7 @@ def __init__(self, L, V, to_K, to_V): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: V, fr, to = L.absolute_vector_space() # indirect doctest sage: to @@ -621,6 +663,7 @@ def _call_(self, x): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: V, fr, to = L.absolute_vector_space() sage: to(1 + 2*a + 3*b + 4*a*b) # indirect doctest diff --git a/src/sage/rings/number_field/morphism.py b/src/sage/rings/number_field/morphism.py index 174252dad61..14ad5772d3b 100644 --- a/src/sage/rings/number_field/morphism.py +++ b/src/sage/rings/number_field/morphism.py @@ -30,6 +30,7 @@ def __invert__(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 5) sage: tau1, tau2 = K.automorphisms(); tau1, tau2 (Ring endomorphism of Number Field in a with defining polynomial x^2 + 5 @@ -86,20 +87,21 @@ def __invert__(self): def preimage(self, y): r""" - Computes a preimage of `y` in the domain, provided one exists. - Raises a ValueError if `y` has no preimage. + Compute a preimage of `y` in the domain, provided one exists. + Raises a :class:`ValueError` if `y` has no preimage. INPUT: - - `y` -- an element of the codomain of self. + - ``y`` -- an element of the codomain of ``self``. OUTPUT: Returns the preimage of `y` in the domain, if one exists. - Raises a ValueError if `y` has no preimage. + Raises a :class:`ValueError` if `y` has no preimage. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 7) sage: L.<b> = NumberField(x^4 - 7) sage: f = K.embeddings(L)[0] @@ -113,9 +115,9 @@ def preimage(self, y): :: sage: F.<b> = QuadraticField(23) - sage: G.<a> = F.extension(x^3+5) + sage: G.<a> = F.extension(x^3 + 5) sage: f = F.embeddings(G)[0] - sage: f.preimage(a^3+2*b+3) + sage: f.preimage(a^3 + 2*b + 3) 2*b - 2 """ # Throughout this method I am using the convention that self is a homomorphism from the number field K to the number field L @@ -153,9 +155,11 @@ def __init__(self, parent, abs_hom): r""" EXAMPLES:: - sage: K.<a, b> = NumberField( [x^3 + 2, x^2 + x + 1] ) + sage: x = polygen(ZZ, 'x') + sage: K.<a, b> = NumberField([x^3 + 2, x^2 + x + 1]) sage: f = K.hom(-a*b - a, K); f - Relative number field endomorphism of Number Field in a with defining polynomial x^3 + 2 over its base field + Relative number field endomorphism of + Number Field in a with defining polynomial x^3 + 2 over its base field Defn: a |--> (-b - 1)*a b |--> b sage: type(f) @@ -174,10 +178,12 @@ def abs_hom(self): EXAMPLES:: - sage: K.<a, b> = NumberField( [x^3 + 2, x^2 + x + 1] ) + sage: x = polygen(ZZ, 'x') + sage: K.<a, b> = NumberField([x^3 + 2, x^2 + x + 1]) sage: K.hom(a, K).abs_hom() Ring morphism: - From: Number Field in a with defining polynomial x^6 - 3*x^5 + 6*x^4 - 3*x^3 - 9*x + 9 + From: Number Field in a with defining polynomial + x^6 - 3*x^5 + 6*x^4 - 3*x^3 - 9*x + 9 To: Number Field in a with defining polynomial x^3 + 2 over its base field Defn: a |--> a - b """ @@ -189,7 +195,8 @@ def _repr_type(self): EXAMPLES:: - sage: K.<a, b> = NumberField( [x^3 + 2, x^2 + x + 1] ) + sage: x = polygen(ZZ, 'x') + sage: K.<a, b> = NumberField([x^3 + 2, x^2 + x + 1]) sage: K.hom(a, K)._repr_type() 'Relative number field' """ @@ -202,7 +209,8 @@ def im_gens(self): EXAMPLES:: - sage: K.<a, b> = NumberField( [x^3 + 2, x^2 + x + 1] ) + sage: x = polygen(ZZ, 'x') + sage: K.<a, b> = NumberField([x^3 + 2, x^2 + x + 1]) sage: K.hom(a, K).im_gens() [a, b] """ @@ -216,6 +224,7 @@ def _richcmp_(self, other, op): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 - 2, x^2 - 3]) sage: e, u, v, w = End(K) sage: all([u^2 == e, u*v == w, u != e]) @@ -229,7 +238,8 @@ def _repr_defn(self): EXAMPLES:: - sage: K.<a, b> = NumberField( [x^3 + 2, x^2 + x + 1] ) + sage: x = polygen(ZZ, 'x') + sage: K.<a, b> = NumberField([x^3 + 2, x^2 + x + 1]) sage: K.hom(a, K)._repr_defn() 'a |--> a\nb |--> b' """ @@ -248,7 +258,8 @@ def _call_(self, x): EXAMPLES:: - sage: K.<a, b> = NumberField( [x^3 + 2, x^2 + x + 1] ) + sage: x = polygen(ZZ, 'x') + sage: K.<a, b> = NumberField([x^3 + 2, x^2 + x + 1]) sage: K.hom(a*b, K)(17 + 3*a + 2*b) # indirect doctest 3*b*a + 2*b + 17 """ @@ -257,8 +268,3 @@ def _call_(self, x): class CyclotomicFieldHomomorphism_im_gens(NumberFieldHomomorphism_im_gens): pass - - -lazy_import('sage.rings.number_field.homset', - ('NumberFieldHomset', 'RelativeNumberFieldHomset', 'CyclotomicFieldHomset'), - deprecation=29010) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index e10d4eeeb33..7fe89197011 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -47,6 +47,7 @@ This example follows one in the Magma reference manual:: + sage: x = polygen(ZZ, 'x') sage: K.<y> = NumberField(x^4 - 420*x^2 + 40000) sage: z = y^5/11; z 420/11*y^3 - 40000/11*y @@ -114,7 +115,7 @@ import sage.interfaces.gap import sage.rings.complex_mpfr -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_element import Polynomial import sage.rings.real_mpfr import sage.rings.real_mpfi import sage.rings.complex_double @@ -181,6 +182,7 @@ def is_NumberFieldHomsetCodomain(codomain): sage: from sage.rings.number_field.number_field import is_NumberFieldHomsetCodomain sage: is_NumberFieldHomsetCodomain(QQ) True + sage: x = polygen(ZZ, 'x') sage: is_NumberFieldHomsetCodomain(NumberField(x^2 + 1, 'x')) True sage: is_NumberFieldHomsetCodomain(ZZ) @@ -208,7 +210,7 @@ def proof_flag(t): """ Used for easily determining the correct proof flag to use. - Return t if t is not ``None``, otherwise return the system-wide + Return ``t`` if ``t`` is not ``None``, otherwise return the system-wide proof-flag for number fields (default: ``True``). EXAMPLES:: @@ -262,30 +264,30 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, INPUT: - - ``polynomial`` - a polynomial over `\QQ` or a number field, or a list - of such polynomials. - - ``names`` (or ``name``) - a string or a list of strings, the names of - the generators - - ``check`` - a boolean (default: ``True``); do type checking and - irreducibility checking. - - ``embedding`` - ``None``, an element, or a list of elements, the - images of the generators in an ambient field (default: ``None``) - - ``latex_names`` (or ``latex_name``) - ``None``, a string, or a - list of strings (default: ``None``), how the generators are printed - for latex output - - ``assume_disc_small`` -- a boolean (default: ``False``); if ``True``, - assume that no square of a prime greater than PARI's primelimit - (which should be 500000); only applies for absolute fields at - present. - - ``maximize_at_primes`` -- ``None`` or a list of primes (default: - ``None``); if not ``None``, then the maximal order is computed by - maximizing only at the primes in this list, which completely avoids - having to factor the discriminant, but of course can lead to wrong - results; only applies for absolute fields at present. - - ``structure`` -- ``None``, a list or an instance of - :class:`structure.NumberFieldStructure` (default: ``None``), - internally used to pass in additional structural information, e.g., - about the field from which this field is created as a subfield. + - ``polynomial`` -- a polynomial over `\QQ` or a number field, or a list + of such polynomials. + - ``names`` (or ``name``) - a string or a list of strings, the names of + the generators + - ``check`` -- a boolean (default: ``True``); do type checking and + irreducibility checking. + - ``embedding`` -- ``None``, an element, or a list of elements, the + images of the generators in an ambient field (default: ``None``) + - ``latex_names`` (or ``latex_name``) - ``None``, a string, or a + list of strings (default: ``None``), how the generators are printed + for latex output + - ``assume_disc_small`` -- a boolean (default: ``False``); if ``True``, + assume that no square of a prime greater than PARI's primelimit + (which should be 500000); only applies for absolute fields at + present. + - ``maximize_at_primes`` -- ``None`` or a list of primes (default: + ``None``); if not ``None``, then the maximal order is computed by + maximizing only at the primes in this list, which completely avoids + having to factor the discriminant, but of course can lead to wrong + results; only applies for absolute fields at present. + - ``structure`` -- ``None``, a list or an instance of + :class:`structure.NumberFieldStructure` (default: ``None``), + internally used to pass in additional structural information, e.g., + about the field from which this field is created as a subfield. We accept ``implementation`` and ``prec`` attributes for compatibility with :class:`~sage.categories.pushout.AlgebraicExtensionFunctor` @@ -294,7 +296,7 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, EXAMPLES:: sage: z = QQ['z'].0 - sage: K = NumberField(z^2 - 2,'s'); K + sage: K = NumberField(z^2 - 2, 's'); K Number Field in s with defining polynomial z^2 - 2 sage: s = K.0; s s @@ -305,9 +307,10 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, Constructing a relative number field:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 2) sage: R.<t> = K[] - sage: L.<b> = K.extension(t^3+t+a); L + sage: L.<b> = K.extension(t^3 + t + a); L Number Field in b with defining polynomial t^3 + t + a over its base field sage: L.absolute_field('c') Number Field in c with defining polynomial x^6 + 2*x^4 + x^2 - 2 @@ -357,13 +360,14 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, for arithmetic and deduce relations with other number fields which would not be valid for an abstract number field. :: - sage: K.<a> = NumberField(x^3-2, embedding=1.2) + sage: K.<a> = NumberField(x^3 - 2, embedding=1.2) sage: RR.coerce_map_from(K) Composite map: From: Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873? To: Real Field with 53 bits of precision Defn: Generic morphism: - From: Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873? + From: Number Field in a with defining polynomial x^3 - 2 + with a = 1.259921049894873? To: Real Lazy Field Defn: a -> 1.259921049894873? then @@ -378,7 +382,7 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, 1/3*a^2 - 1/3*a + 1/3 sage: RR(b) 0.442493334024442 - sage: L.<b> = NumberField(x^6-2, embedding=1.1) + sage: L.<b> = NumberField(x^6 - 2, embedding=1.1) sage: L(a) b^2 sage: a + b @@ -400,7 +404,8 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, sage: f = polygen(L)^3 - 2 sage: K.<a> = NumberField(x^3-2, embedding=f.roots()[0][0]) sage: a + L(1) - 4 + 2*5^2 + 2*5^3 + 3*5^4 + 5^5 + 4*5^6 + 2*5^8 + 3*5^9 + 4*5^12 + 4*5^14 + 4*5^15 + 3*5^16 + 5^17 + 5^18 + 2*5^19 + O(5^20) + 4 + 2*5^2 + 2*5^3 + 3*5^4 + 5^5 + 4*5^6 + 2*5^8 + 3*5^9 + 4*5^12 + + 4*5^14 + 4*5^15 + 3*5^16 + 5^17 + 5^18 + 2*5^19 + O(5^20) sage: L.<b> = NumberField(x^6-x^2+1/10, embedding=1) sage: K.<a> = NumberField(x^3-x+1/10, embedding=b^2) sage: a+b @@ -410,7 +415,8 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, sage: K.coerce_embedding() Generic morphism: From: Number Field in a with defining polynomial x^3 - x + 1/10 with a = b^2 - To: Number Field in b with defining polynomial x^6 - x^2 + 1/10 with b = 0.9724449978911874? + To: Number Field in b with defining polynomial x^6 - x^2 + 1/10 + with b = 0.9724449978911874? Defn: a -> b^2 The ``QuadraticField`` and ``CyclotomicField`` constructors @@ -429,7 +435,7 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, Note that the codomain of the embedding must be ``QQbar`` or ``AA`` for this to work (see :trac:`20184`):: - sage: N.<g> = NumberField(x^3+2,embedding=1) + sage: N.<g> = NumberField(x^3 + 2,embedding=1) sage: 1 < g False sage: g > 1 @@ -440,7 +446,7 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, If no embedding is specified or is complex, the comparison is not returning something meaningful.:: - sage: N.<g> = NumberField(x^3+2) + sage: N.<g> = NumberField(x^3 + 2) sage: 1 < g False sage: g > 1 @@ -505,7 +511,7 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, :: - sage: W1 = NumberField(x^2+1,'a') + sage: W1 = NumberField(x^2 + 1,'a') sage: K.<x> = CyclotomicField(5)[] sage: W.<a> = NumberField(x^2 + 1); W Number Field in a with defining polynomial x^2 + 1 over its base field @@ -513,8 +519,8 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, The following has been fixed in :trac:`8800`:: sage: P.<x> = QQ[] - sage: K.<a> = NumberField(x^3-5,embedding=0) - sage: L.<b> = K.extension(x^2+a) + sage: K.<a> = NumberField(x^3 - 5,embedding=0) + sage: L.<b> = K.extension(x^2 + a) sage: F, R = L.construction() sage: F(R) == L # indirect doctest True @@ -534,7 +540,10 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, Another problem that was found while working on :trac:`11670`, ``maximize_at_primes`` and ``assume_disc_small`` were lost when pickling:: - sage: K.<a> = NumberField(x^3-2, assume_disc_small=True, maximize_at_primes=[2], latex_name='\\alpha', embedding=2^(1/3)) + sage: # needs sage.symbolic + sage: K.<a> = NumberField(x^3 - 2, assume_disc_small=True, + ....: maximize_at_primes=[2], + ....: latex_name='\\alpha', embedding=2^(1/3)) sage: L = loads(dumps(K)) sage: L._assume_disc_small True @@ -543,7 +552,7 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, It is an error not to specify the generator:: - sage: K = NumberField(x^2-2) + sage: K = NumberField(x^2 - 2) Traceback (most recent call last): ... TypeError: You must specify the name of the generator. @@ -585,34 +594,35 @@ class NumberFieldFactory(UniqueFactory): INPUT: - - ``polynomial`` - a polynomial over `\QQ` or a number field. - - ``name`` - a string (default: ``'a'``), the name of the generator - - ``check`` - a boolean (default: ``True``); do type checking and - irreducibility checking. - - ``embedding`` - ``None`` or an element, the images of the generator - in an ambient field (default: ``None``) - - ``latex_name`` - ``None`` or a string (default: ``None``), how the - generator is printed for latex output - - ``assume_disc_small`` -- a boolean (default: ``False``); if ``True``, - assume that no square of a prime greater than PARI's primelimit - (which should be 500000); only applies for absolute fields at - present. - - ``maximize_at_primes`` -- ``None`` or a list of primes (default: - ``None``); if not ``None``, then the maximal order is computed by - maximizing only at the primes in this list, which completely avoids - having to factor the discriminant, but of course can lead to wrong - results; only applies for absolute fields at present. - - ``structure`` -- ``None`` or an instance of - :class:`structure.NumberFieldStructure` (default: ``None``), - internally used to pass in additional structural information, e.g., - about the field from which this field is created as a subfield. + - ``polynomial`` -- a polynomial over `\QQ` or a number field. + - ``name`` -- a string (default: ``'a'``), the name of the generator + - ``check`` -- a boolean (default: ``True``); do type checking and + irreducibility checking. + - ``embedding`` -- ``None`` or an element, the images of the generator + in an ambient field (default: ``None``) + - ``latex_name`` -- ``None`` or a string (default: ``None``), how the + generator is printed for latex output + - ``assume_disc_small`` -- a boolean (default: ``False``); if ``True``, + assume that no square of a prime greater than PARI's primelimit + (which should be 500000); only applies for absolute fields at + present. + - ``maximize_at_primes`` -- ``None`` or a list of primes (default: + ``None``); if not ``None``, then the maximal order is computed by + maximizing only at the primes in this list, which completely avoids + having to factor the discriminant, but of course can lead to wrong + results; only applies for absolute fields at present. + - ``structure`` -- ``None`` or an instance of + :class:`structure.NumberFieldStructure` (default: ``None``), + internally used to pass in additional structural information, e.g., + about the field from which this field is created as a subfield. TESTS:: sage: from sage.rings.number_field.number_field import NumberFieldFactory sage: nff = NumberFieldFactory("number_field_factory") sage: R.<x> = QQ[] - sage: nff(x^2 + 1, name='a', check=False, embedding=None, latex_name=None, assume_disc_small=False, maximize_at_primes=None, structure=None) + sage: nff(x^2 + 1, name='a', check=False, embedding=None, latex_name=None, + ....: assume_disc_small=False, maximize_at_primes=None, structure=None) Number Field in a with defining polynomial x^2 + 1 Pickling preserves the ``structure()`` of a number field:: @@ -638,7 +648,8 @@ def create_key_and_extra_args(self, polynomial, name, check, embedding, latex_na sage: from sage.rings.number_field.number_field import NumberFieldFactory sage: nff = NumberFieldFactory("number_field_factory") sage: R.<x> = QQ[] - sage: nff.create_key_and_extra_args(x^2+1, name='a', check=False, embedding=None, latex_name=None, assume_disc_small=False, maximize_at_primes=None, structure=None) + sage: nff.create_key_and_extra_args(x^2+1, name='a', check=False, embedding=None, + ....: latex_name=None, assume_disc_small=False, maximize_at_primes=None, structure=None) ((Rational Field, x^2 + 1, ('a',), None, 'a', None, False, None), {'check': False}) @@ -647,7 +658,7 @@ def create_key_and_extra_args(self, polynomial, name, check, embedding, latex_na raise TypeError("You must specify the name of the generator.") name = normalize_names(1, name) - if not is_Polynomial(polynomial): + if not isinstance(polynomial, Polynomial): try: polynomial = polynomial.polynomial(QQ) except (AttributeError, TypeError): @@ -722,20 +733,20 @@ def NumberFieldTower(polynomials, names, check=True, embeddings=None, latex_name INPUT: - - ``polynomials`` - a list of polynomials. Each entry must be polynomial + - ``polynomials`` -- a list of polynomials. Each entry must be polynomial which is irreducible over the number field generated by the roots of the following entries. - - ``names`` - a list of strings or a string, the names of the generators of + - ``names`` -- a list of strings or a string, the names of the generators of the relative number fields. If a single string, then names are generated from that string. - - ``check`` - a boolean (default: ``True``), whether to check that the + - ``check`` -- a boolean (default: ``True``), whether to check that the polynomials are irreducible - - ``embeddings`` - a list of elements or ``None`` (default: ``None``), + - ``embeddings`` -- a list of elements or ``None`` (default: ``None``), embeddings of the relative number fields in an ambient field. - - ``latex_names`` - a list of strings or ``None`` (default: ``None``), names + - ``latex_names`` -- a list of strings or ``None`` (default: ``None``), names used to print the generators for latex output. - ``assume_disc_small`` -- a boolean (default: ``False``); if ``True``, - assume that no square of a prime greater than PARI's primelimit + assume that no square of a prime greater than PARI's ``primelimit`` (which should be 500000); only applies for absolute fields at present. - ``maximize_at_primes`` -- ``None`` or a list of primes (default: @@ -756,7 +767,8 @@ def NumberFieldTower(polynomials, names, check=True, embeddings=None, latex_name EXAMPLES:: - sage: k.<a,b,c> = NumberField([x^2 + 1, x^2 + 3, x^2 + 5]); k # indirect doctest + sage: x = polygen(ZZ, 'x') + sage: k.<a,b,c> = NumberField([x^2 + 1, x^2 + 3, x^2 + 5]); k # indirect doctest Number Field in a with defining polynomial x^2 + 1 over its base field sage: a^2 -1 @@ -793,16 +805,14 @@ def NumberFieldTower(polynomials, names, check=True, embeddings=None, latex_name We mix polynomial parent rings:: sage: k.<y> = QQ[] - sage: m = NumberField([y^3 - 3, x^2 + x + 1, y^3 + 2], 'beta') - sage: m + sage: m = NumberField([y^3 - 3, x^2 + x + 1, y^3 + 2], 'beta'); m Number Field in beta0 with defining polynomial y^3 - 3 over its base field sage: m.base_field () Number Field in beta1 with defining polynomial x^2 + x + 1 over its base field A tower of quadratic fields:: - sage: K.<a> = NumberField([x^2 + 3, x^2 + 2, x^2 + 1]) - sage: K + sage: K.<a> = NumberField([x^2 + 3, x^2 + 2, x^2 + 1]); K Number Field in a0 with defining polynomial x^2 + 3 over its base field sage: K.base_field() Number Field in a1 with defining polynomial x^2 + 2 over its base field @@ -811,7 +821,8 @@ def NumberFieldTower(polynomials, names, check=True, embeddings=None, latex_name LaTeX versions of generator names can be specified either as:: - sage: K = NumberField([x^3 - 2, x^3 - 3, x^3 - 5], names=['a', 'b', 'c'], latex_names=[r'\alpha', r'\beta', r'\gamma']) + sage: K = NumberField([x^3 - 2, x^3 - 3, x^3 - 5], names=['a', 'b', 'c'], + ....: latex_names=[r'\alpha', r'\beta', r'\gamma']) sage: K.inject_variables(verbose=False) sage: latex(a + b + c) \alpha + \beta + \gamma @@ -868,7 +879,7 @@ def NumberFieldTower(polynomials, names, check=True, embeddings=None, latex_name f = polynomials[0] name = names[0] w = NumberFieldTower(polynomials[1:], names=names[1:], check=check, embeddings=embeddings[1:], latex_names=latex_names[1:], assume_disc_small=assume_disc_small, maximize_at_primes=maximize_at_primes, structures=structures[1:]) - var = f.variable_name() if is_Polynomial(f) else 'x' + var = f.variable_name() if isinstance(f, Polynomial) else 'x' R = w[var] # polynomial ring return w.extension(R(f), name, check=check, embedding=embeddings[0], structure=structures[0], latex_name=latex_names[0]) # currently, extension does not accept assume_disc_small, or maximize_at_primes @@ -882,16 +893,16 @@ def QuadraticField(D, name='a', check=True, embedding=True, latex_name='sqrt', * INPUT: - - ``D`` - a rational number + - ``D`` -- a rational number - - ``name`` - variable name (default: 'a') + - ``name`` -- variable name (default: ``'a'``) - - ``check`` - bool (default: ``True``) + - ``check`` -- bool (default: ``True``) - - ``embedding`` - bool or square root of D in an - ambient field (default: ``True``) + - ``embedding`` -- bool or square root of `D` in an + ambient field (default: ``True``) - - ``latex_name`` - latex variable name (default: \sqrt{D}) + - ``latex_name`` -- latex variable name (default: `\sqrt{D}`) OUTPUT: A number field defined by a quadratic polynomial. Unless @@ -918,10 +929,10 @@ def QuadraticField(D, name='a', check=True, embedding=True, latex_name='sqrt', * :: - sage: from sage.rings.number_field.number_field import is_NumberField + sage: from sage.rings.number_field.number_field_base import NumberField sage: type(K) <class 'sage.rings.number_field.number_field.NumberField_quadratic_with_category'> - sage: is_NumberField(K) + sage: isinstance(K, NumberField) True Quadratic number fields are cached:: @@ -944,9 +955,9 @@ def QuadraticField(D, name='a', check=True, embedding=True, latex_name='sqrt', * We can provide our own name as well:: sage: K.<a> = QuadraticField(next_prime(10^10), latex_name=r'\sqrt{D}') - sage: 1+a + sage: 1 + a a + 1 - sage: latex(1+a) + sage: latex(1 + a) \sqrt{D} + 1 sage: latex(QuadraticField(-1, 'a', latex_name=None).gen()) a @@ -1004,7 +1015,7 @@ def QuadraticField(D, name='a', check=True, embedding=True, latex_name='sqrt', * def GaussianField(): r""" - The field QQ[i]. + The field `\QQ[i]`. TESTS:: @@ -1022,15 +1033,16 @@ def GaussianField(): def is_AbsoluteNumberField(x): - """ - Return True if x is an absolute number field. + r""" + Return ``True`` if ``x`` is an absolute number field. EXAMPLES:: sage: from sage.rings.number_field.number_field import is_AbsoluteNumberField - sage: is_AbsoluteNumberField(NumberField(x^2+1,'a')) + sage: x = polygen(ZZ, 'x') + sage: is_AbsoluteNumberField(NumberField(x^2 + 1, 'a')) True - sage: is_AbsoluteNumberField(NumberField([x^3 + 17, x^2+1],'a')) + sage: is_AbsoluteNumberField(NumberField([x^3 + 17, x^2 + 1], 'a')) False The rationals are a number field, but they're not of the absolute @@ -1044,38 +1056,6 @@ def is_AbsoluteNumberField(x): return isinstance(x, NumberField_absolute) -def is_QuadraticField(x) -> bool: - r""" - Return True if x is of the quadratic *number* field type. - - This function is deprecated. Use :func:`isinstance` with - :class:`~sage.rings.abc.NumberField_quadratic` instead. - - EXAMPLES:: - - sage: from sage.rings.number_field.number_field import is_QuadraticField - sage: is_QuadraticField(QuadraticField(5,'a')) - doctest:warning... - DeprecationWarning: is_QuadraticField is deprecated; - use isinstance(..., sage.rings.abc.NumberField_quadratic instead - See https://github.com/sagemath/sage/issues/32660 for details. - True - sage: is_QuadraticField(NumberField(x^2 - 5, 'b')) - True - sage: is_QuadraticField(NumberField(x^3 - 5, 'b')) - False - - A quadratic field specially refers to a number field, not a finite - field:: - - sage: is_QuadraticField(GF(9,'a')) - False - """ - from sage.misc.superseded import deprecation - deprecation(32660, 'is_QuadraticField is deprecated; use isinstance(..., sage.rings.abc.NumberField_quadratic instead') - return isinstance(x, NumberField_quadratic) - - class CyclotomicFieldFactory(UniqueFactory): r""" Return the `n`-th cyclotomic field, where n is a positive integer, @@ -1086,14 +1066,14 @@ class CyclotomicFieldFactory(UniqueFactory): INPUT: - - ``n`` - a nonnegative integer, default:``0`` + - ``n`` -- a nonnegative integer, default: ``0`` - - ``names`` - name of generator (optional - defaults to zetan) + - ``names`` -- name of generator (optional - defaults to zetan) - - ``bracket`` - Defines the brackets in the case of ``n==0``, and + - ``bracket`` -- Defines the brackets in the case of ``n==0``, and is ignored otherwise. Can be any even length string, with ``"()"`` being the default. - - ``embedding`` - bool or n-th root of unity in an + - ``embedding`` -- bool or `n`-th root of unity in an ambient field (default True) EXAMPLES: @@ -1101,7 +1081,7 @@ class CyclotomicFieldFactory(UniqueFactory): If called without a parameter, we get the :class:`universal cyclotomic field<sage.rings.universal_cyclotomic_field.UniversalCyclotomicField>`:: - sage: CyclotomicField() + sage: CyclotomicField() # needs sage.libs.gap Universal Cyclotomic Field We create the `7`\th cyclotomic field @@ -1238,39 +1218,6 @@ def create_object(self, version, key, **extra_args): CyclotomicField = CyclotomicFieldFactory("sage.rings.number_field.number_field.CyclotomicField") -def is_CyclotomicField(x) -> bool: - """ - Return True if x is a cyclotomic field, i.e., of the special - cyclotomic field class. This function does not return True for a - number field that just happens to be isomorphic to a cyclotomic - field. - - This function is deprecated. Use :func:`isinstance` with - :class:`~sage.rings.abc.NumberField_cyclotomic` instead. - - EXAMPLES:: - - sage: from sage.rings.number_field.number_field import is_CyclotomicField - sage: is_CyclotomicField(NumberField(x^2 + 1,'zeta4')) - doctest:warning... - DeprecationWarning: is_CyclotomicField is deprecated; - use isinstance(..., sage.rings.abc.NumberField_cyclotomic instead - See https://github.com/sagemath/sage/issues/32660 for details. - False - sage: is_CyclotomicField(CyclotomicField(4)) - True - sage: is_CyclotomicField(CyclotomicField(1)) - True - sage: is_CyclotomicField(QQ) - False - sage: is_CyclotomicField(7) - False - """ - from sage.misc.superseded import deprecation - deprecation(32660, 'is_CyclotomicField is deprecated; use isinstance(..., sage.rings.abc.NumberField_cyclotomic instead') - return isinstance(x, NumberField_cyclotomic) - - from . import number_field_base @@ -1278,12 +1225,13 @@ def is_CyclotomicField(x) -> bool: class NumberField_generic(WithEqualityById, number_field_base.NumberField): - """ + r""" Generic class for number fields defined by an irreducible - polynomial over `\\QQ`. + polynomial over `\QQ`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2); K Number Field in a with defining polynomial x^3 - 2 sage: TestSuite(K).run() @@ -1332,7 +1280,7 @@ class NumberField_generic(WithEqualityById, number_field_base.NumberField): sage: K.<a> = QuadraticField(2) sage: R.<x> = K[] - sage: L.<b> = K.extension(x^2+1) + sage: L.<b> = K.extension(x^2 + 1) sage: M.<b> = L.absolute_field() sage: M == L False @@ -1341,8 +1289,8 @@ class NumberField_generic(WithEqualityById, number_field_base.NumberField): sage: R.<x> = QQ[] sage: R.<y> = QQ[] - sage: K.<a> = NumberField(x^2+1) - sage: L.<a> = NumberField(y^2+1) + sage: K.<a> = NumberField(x^2 + 1) + sage: L.<a> = NumberField(y^2 + 1) sage: K == L False sage: hash(K) == hash(L) @@ -1365,7 +1313,7 @@ class NumberField_generic(WithEqualityById, number_field_base.NumberField): This example illustrates the issue resolved in :trac:`18942`:: - sage: F.<omega> = NumberField(x^2+x+1) + sage: F.<omega> = NumberField(x^2 + x + 1) sage: xx = polygen(F) sage: ps = [p for p, _ in F(7).factor()] sage: for mu in ps: @@ -1382,7 +1330,7 @@ class NumberField_generic(WithEqualityById, number_field_base.NumberField): This example was suggested on sage-nt; see :trac:`18942`:: sage: G = DirichletGroup(80) - sage: for chi in G: + sage: for chi in G: # long time ....: D = ModularSymbols(chi, 2, -1).cuspidal_subspace().new_subspace().decomposition() ....: for f in D: ....: elt = f.q_eigenform(10, 'alpha')[3] @@ -1397,6 +1345,7 @@ def __init__(self, polynomial, name, latex_name, EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: NumberField(x^97 - 19, 'a') Number Field in a with defining polynomial x^97 - 19 @@ -1407,7 +1356,7 @@ def __init__(self, polynomial, name, latex_name, ... ValueError: defining polynomial (x^2 - 1) must be irreducible - If you use check=False, you avoid checking irreducibility of the + If you use ``check=False``, you avoid checking irreducibility of the defining polynomial, which can save time. :: @@ -1438,7 +1387,7 @@ def __init__(self, polynomial, name, latex_name, Number Field in a with defining polynomial x^4 + 23 sage: NumberField(QQ['x'].0^4 + 23, 'a') Number Field in a with defining polynomial x^4 + 23 - sage: NumberField(GF(7)['x'].0^4 + 23, 'a') + sage: NumberField(GF(7)['x'].0^4 + 23, 'a') # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: polynomial must be defined over rational field @@ -1503,6 +1452,7 @@ def _convert_map_from_(self, other): This also works for relative number fields and their absolute fields:: sage: K.<a> = QuadraticField(2) + sage: x = polygen(ZZ, 'x') sage: L.<i> = K.extension(x^2 + 1) sage: M.<b> = L.absolute_field() sage: M(i) @@ -1532,16 +1482,17 @@ def _magma_polynomial_(self, magma): EXAMPLES:: - sage: R.<x> = QQ[] # optional - magma - sage: K.<a> = NumberField(x^3+2) # optional - magma - sage: K._magma_polynomial_(magma) # optional - magma + sage: # optional - magma + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(x^3 + 2) + sage: K._magma_polynomial_(magma) x^3 + 2 - sage: magma2=Magma() # optional - magma - sage: K._magma_polynomial_(magma2) # optional - magma + sage: magma2 = Magma() + sage: K._magma_polynomial_(magma2) x^3 + 2 - sage: K._magma_polynomial_(magma) is K._magma_polynomial_(magma) # optional - magma + sage: K._magma_polynomial_(magma) is K._magma_polynomial_(magma) True - sage: K._magma_polynomial_(magma) is K._magma_polynomial_(magma2) # optional - magma + sage: K._magma_polynomial_(magma) is K._magma_polynomial_(magma2) False """ # NB f must not be garbage-collected, otherwise the @@ -1554,34 +1505,36 @@ def _magma_init_(self, magma): EXAMPLES:: - sage: R.<t> = QQ[] # optional - magma - sage: K.<a> = NumberField(t^2 + 1) # optional - magma - sage: K._magma_init_(magma) # optional - magma + sage: # optional - magma + sage: R.<t> = QQ[] + sage: K.<a> = NumberField(t^2 + 1) + sage: K._magma_init_(magma) 'SageCreateWithNames(NumberField(_sage_[...]),["a"])' - sage: L = magma(K) # optional - magma - sage: L # optional - magma + sage: L = magma(K) + sage: L Number Field with defining polynomial t^2 + 1 over the Rational Field - sage: L.sage() # optional - magma + sage: L.sage() Number Field in a with defining polynomial t^2 + 1 - sage: L.sage() is K # optional - magma + sage: L.sage() is K True - sage: L.1 # optional - magma + sage: L.1 a - sage: L.1^2 # optional - magma + sage: L.1^2 -1 - sage: m = magma(a+1/2); m # optional - magma + sage: m = magma(a+1/2); m 1/2*(2*a + 1) - sage: m.sage() # optional - magma + sage: m.sage() a + 1/2 A relative number field:: - sage: S.<u> = K[] # optional - magma - sage: M.<b> = NumberField(u^3+u+a) # optional - magma - sage: L = magma(M) # optional - magma - sage: L # optional - magma + sage: # optional - magma + sage: S.<u> = K[] + sage: M.<b> = NumberField(u^3+u+a) + sage: L = magma(M) + sage: L Number Field with defining polynomial u^3 + u + a over its ground field - sage: L.sage() is M # optional - magma + sage: L.sage() is M True """ # Get magma version of defining polynomial of this number field @@ -1591,12 +1544,13 @@ def _magma_init_(self, magma): def construction(self): r""" - Construction of self. + Construction of ``self``. EXAMPLES:: - sage: K.<a>=NumberField(x^3+x^2+1,embedding=CC.gen()) - sage: F,R = K.construction() + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 + x^2 + 1, embedding=CC.gen()) + sage: F, R = K.construction() sage: F AlgebraicExtensionFunctor sage: R @@ -1611,11 +1565,11 @@ def construction(self): TESTS:: - sage: K.<a> = NumberField(x^3+x+1) + sage: K.<a> = NumberField(x^3 + x + 1) sage: R.<t> = ZZ[] - sage: a+t # indirect doctest + sage: a + t # indirect doctest t + a - sage: (a+t).parent() + sage: (a + t).parent() Univariate Polynomial Ring in t over Number Field in a with defining polynomial x^3 + x + 1 The construction works for non-absolute number fields as well:: @@ -1673,8 +1627,9 @@ def _element_constructor_(self, x, check=True): TESTS:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 17) - sage: K(a) is a # indirect doctest + sage: K(a) is a # indirect doctest True sage: K('a^2 + 2/3*a + 5') a^2 + 2/3*a + 5 @@ -1690,78 +1645,80 @@ def _element_constructor_(self, x, check=True): We can create number field elements from PARI:: sage: K.<a> = NumberField(x^3 - 17) - sage: K(pari(42)) + sage: K(pari(42)) # needs sage.libs.pari 42 - sage: K(pari("5/3")) + sage: K(pari("5/3")) # needs sage.libs.pari 5/3 - sage: K(pari("[3/2, -5, 0]~")) # Uses Z-basis + sage: K(pari("[3/2, -5, 0]~")) # Uses Z-basis # needs sage.libs.pari -5/3*a^2 + 5/3*a - 1/6 From a PARI polynomial or ``POLMOD``, note that the variable name does not matter:: - sage: K(pari("-5/3*q^2 + 5/3*q - 1/6")) + sage: K(pari("-5/3*q^2 + 5/3*q - 1/6")) # needs sage.libs.pari -5/3*a^2 + 5/3*a - 1/6 - sage: K(pari("Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 17)")) + sage: K(pari("Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 17)")) # needs sage.libs.pari -5/3*a^2 + 5/3*a - 1/6 - sage: K(pari("x^5/17")) + sage: K(pari("x^5/17")) # needs sage.libs.pari a^2 An error is raised when a PARI element with an incorrect - modulus is given: + modulus is given:: - sage: K(pari("Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 999)")) + sage: K(pari("Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 999)")) # needs sage.libs.pari Traceback (most recent call last): ... - TypeError: cannot convert PARI element Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 999) into Number Field in a with defining polynomial x^3 - 17 + TypeError: cannot convert PARI element Mod(-5/3*q^2 + 5/3*q - 1/6, q^3 - 999) + into Number Field in a with defining polynomial x^3 - 17 Test round-trip conversion to PARI and back:: sage: x = polygen(QQ) sage: K.<a> = NumberField(x^3 - 1/2*x + 1/3) sage: b = K.random_element() - sage: K(pari(b)) == b + sage: K(pari(b)) == b # needs sage.libs.pari True sage: F.<c> = NumberField(2*x^3 + x + 1) sage: d = F.random_element() - sage: F(F.pari_nf().nfalgtobasis(d)) == d + sage: F(F.pari_nf().nfalgtobasis(d)) == d # needs sage.libs.pari True If the PARI polynomial is different from the Sage polynomial, a warning is printed unless ``check=False`` is specified:: - sage: b = pari(a); b + sage: b = pari(a); b # needs sage.libs.pari Mod(-1/12*y^2 - 1/12*y + 1/6, y^3 - 3*y - 22) - sage: K(b.lift()) - doctest:...: UserWarning: interpreting PARI polynomial -1/12*y^2 - 1/12*y + 1/6 relative to the defining polynomial x^3 - 3*x - 22 of the PARI number field + sage: K(b.lift()) # needs sage.libs.pari + doctest:...: UserWarning: interpreting PARI polynomial -1/12*y^2 - 1/12*y + 1/6 + relative to the defining polynomial x^3 - 3*x - 22 of the PARI number field a - sage: K(b.lift(), check=False) + sage: K(b.lift(), check=False) # needs sage.libs.pari a Using a GAP element may be tricky, as it may contain an exclamation mark:: - sage: L.<tau> = NumberField(x^3-2) - sage: gap(tau^3) + sage: L.<tau> = NumberField(x^3 - 2) + sage: gap(tau^3) # needs sage.libs.gap 2 - sage: gap(tau)^3 + sage: gap(tau)^3 # needs sage.libs.gap !2 - sage: L(gap(tau)^3) # indirect doctest + sage: L(gap(tau)^3) # indirect doctest # needs sage.libs.gap 2 Check that :trac:`22202` and :trac:`27765` are fixed:: sage: y = QQ['y'].gen() - sage: R = QQ.extension(y^2-1/2,'a')['x'] + sage: R = QQ.extension(y^2 - 1/2, 'a')['x'] sage: R("a*x").factor() (a) * x Check that :trac:`30961` is fixed:: sage: QQi = i.parent() - sage: x = SR.var('x') - sage: QQi((x, x)) + sage: x = SR.var('x') # needs sage.symbolic + sage: QQi((x, x)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert x to a rational @@ -1847,6 +1804,7 @@ def _convert_non_number_field_element(self, x): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 + 2/3) sage: K._convert_non_number_field_element(-7/8) -7/8 @@ -1869,10 +1827,10 @@ def _convert_non_number_field_element(self, x): But not this one over a field of order 27:: - sage: F27.<g> = GF(27) - sage: f = F27['z']([g^2, 2*g, 1]); f + sage: F27.<g> = GF(27) # needs sage.rings.finite_rings + sage: f = F27['z']([g^2, 2*g, 1]); f # needs sage.rings.finite_rings z^2 + 2*g*z + g^2 - sage: K._convert_non_number_field_element(f) + sage: K._convert_non_number_field_element(f) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: unable to convert g^2 to a rational @@ -1887,6 +1845,7 @@ def _convert_non_number_field_element(self, x): We can convert symbolic expressions:: + sage: # needs sage.symbolic sage: I = sqrt(-1); parent(I) Symbolic Ring sage: GaussianIntegers()(2 + I) @@ -1956,7 +1915,8 @@ def _convert_from_qqbar(self, x): sage: CyclotomicField(12)(QQbar.zeta(5)) Traceback (most recent call last): ... - TypeError: unable to convert 0.3090169943749474? + 0.9510565162951536?*I to Cyclotomic Field of order 12 and degree 4 + TypeError: unable to convert 0.3090169943749474? + 0.9510565162951536?*I + to Cyclotomic Field of order 12 and degree 4 """ # We use the diagram # @@ -1986,11 +1946,12 @@ def _convert_from_str(self, x): INPUT: - - x -- string + - ``x`` -- string EXAMPLES:: - sage: k.<theta25> = NumberField(x^3+(2/3)*x+1) + sage: x = polygen(ZZ, 'x') + sage: k.<theta25> = NumberField(x^3 + (2/3)*x + 1) sage: k._convert_from_str('theta25^3 + (1/3)*theta25') -1/3*theta25 - 1 @@ -2008,24 +1969,32 @@ def _convert_from_str(self, x): def _Hom_(self, codomain, category=None): """ - Return homset of homomorphisms from self to the number field codomain. + Return homset of homomorphisms from ``self`` to the number field codomain. EXAMPLES: This method is implicitly called by :meth:`Hom` and :meth:`sage.categories.homset.Hom`:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1); K Number Field in i with defining polynomial x^2 + 1 - sage: K.Hom(K) # indirect doctest + sage: K.Hom(K) # indirect doctest Automorphism group of Number Field in i with defining polynomial x^2 + 1 sage: Hom(K, QuadraticField(-1, 'b')) - Set of field embeddings from Number Field in i with defining polynomial x^2 + 1 to Number Field in b with defining polynomial x^2 + 1 with b = 1*I + Set of field embeddings + from Number Field in i with defining polynomial x^2 + 1 + to Number Field in b with defining polynomial x^2 + 1 with b = 1*I CHECKME: handling of the case where codomain is not a number field? - sage: Hom(K, VectorSpace(QQ,3)) - Set of Morphisms from Number Field in i with defining polynomial x^2 + 1 to Vector space of dimension 3 over Rational Field in Category of commutative additive groups + :: + + sage: Hom(K, VectorSpace(QQ,3)) + Set of Morphisms + from Number Field in i with defining polynomial x^2 + 1 + to Vector space of dimension 3 over Rational Field + in Category of commutative additive groups TESTS: @@ -2052,13 +2021,14 @@ def _Hom_(self, codomain, category=None): @cached_method def structure(self): """ - Return fixed isomorphism or embedding structure on self. + Return fixed isomorphism or embedding structure on ``self``. This is used to record various isomorphisms or embeddings that arise naturally in other constructions. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<z> = NumberField(x^2 + 3) sage: L.<a> = K.absolute_field(); L Number Field in a with defining polynomial x^2 + 3 @@ -2085,7 +2055,7 @@ def structure(self): def completion(self, p, prec, extras={}): """ - Return the completion of self at `p` to the specified precision. + Return the completion of ``self`` at `p` to the specified precision. Only implemented at archimedean places, and then only if an embedding has been fixed. @@ -2119,10 +2089,11 @@ def primitive_element(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: K.primitive_element() a - sage: K.<a,b,c> = NumberField([x^2-2,x^2-3,x^2-5]) + sage: K.<a,b,c> = NumberField([x^2 - 2, x^2 - 3, x^2 - 5]) sage: K.primitive_element() a - b + c sage: alpha = K.primitive_element(); alpha @@ -2148,27 +2119,26 @@ def random_element(self, num_bound=None, den_bound=None, INPUT: - - ``num_bound`` - Bound on numerator of the coefficients of - the resulting element + - ``num_bound`` -- Bound on numerator of the coefficients of + the resulting element - - ``den_bound`` - Bound on denominators of the coefficients - of the resulting element + - ``den_bound`` -- Bound on denominators of the coefficients + of the resulting element - - ``integral_coefficients`` (default: ``False``) - If ``True``, then - the resulting element will have integral - coefficients. This option overrides any - value of `den_bound`. + - ``integral_coefficients`` -- (default: ``False``) If ``True``, then + the resulting element will have integral + coefficients. This option overrides any + value of ``den_bound``. - - ``distribution`` - Distribution to use for the coefficients - of the resulting element + - ``distribution`` -- Distribution to use for the coefficients + of the resulting element - OUTPUT: - - - Element of this number field + OUTPUT: Element of this number field EXAMPLES:: - sage: K.<j> = NumberField(x^8+1) + sage: x = polygen(ZZ, 'x') + sage: K.<j> = NumberField(x^8 + 1) sage: K.random_element().parent() is K True @@ -2181,7 +2151,7 @@ def random_element(self, num_bound=None, den_bound=None, sage: while not K.random_element().is_prime(): ....: pass - sage: K.<a,b,c> = NumberField([x^2-2,x^2-3,x^2-5]) + sage: K.<a,b,c> = NumberField([x^2 - 2, x^2 - 3, x^2 - 5]) sage: K.random_element().parent() is K True @@ -2190,7 +2160,7 @@ def random_element(self, num_bound=None, den_bound=None, sage: while not K.random_element().is_prime(): # long time ....: pass - sage: K.<a> = NumberField(x^5-2) + sage: K.<a> = NumberField(x^5 - 2) sage: p = K.random_element(integral_coefficients=True) sage: p.is_integral() True @@ -2199,12 +2169,12 @@ def random_element(self, num_bound=None, den_bound=None, TESTS:: - sage: K.<a> = NumberField(x^5-2) + sage: K.<a> = NumberField(x^5 - 2) sage: K.random_element(-1) Traceback (most recent call last): ... TypeError: x must be < y - sage: K.random_element(5,0) + sage: K.random_element(5, 0) Traceback (most recent call last): ... TypeError: x must be < y @@ -2224,22 +2194,23 @@ def subfield(self, alpha, name=None, names=None): r""" Return a number field `K` isomorphic to `\QQ(\alpha)` (if this is an absolute number field) or `L(\alpha)` (if this - is a relative extension `M/L`) and a map from K to self that - sends the generator of K to alpha. + is a relative extension `M/L`) and a map from `K` to ``self`` that + sends the generator of `K` to ``alpha``. INPUT: - - ``alpha`` - an element of self, or something that - coerces to an element of self. + - ``alpha`` -- an element of ``self``, or something that + coerces to an element of ``self``. OUTPUT: - - ``K`` - a number field - - ``from_K`` - a homomorphism from K to self that - sends the generator of K to alpha. + - ``K`` -- a number field + - ``from_K`` -- a homomorphism from `K` to ``self`` that + sends the generator of `K` to ``alpha``. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 - 3); K Number Field in a with defining polynomial x^4 - 3 sage: H.<b>, from_H = K.subfield(a^2) @@ -2265,7 +2236,7 @@ def subfield(self, alpha, name=None, names=None): Subfields inherit embeddings:: sage: K.<z> = CyclotomicField(5) - sage: L, K_from_L = K.subfield(z-z^2-z^3+z^4) + sage: L, K_from_L = K.subfield(z - z^2 - z^3 + z^4) sage: L Number Field in z0 with defining polynomial x^2 - 5 with z0 = 2.236067977499790? sage: CLF_from_K = K.coerce_embedding(); CLF_from_K @@ -2275,7 +2246,8 @@ def subfield(self, alpha, name=None, names=None): Defn: z -> 0.309016994374948? + 0.951056516295154?*I sage: CLF_from_L = L.coerce_embedding(); CLF_from_L Generic morphism: - From: Number Field in z0 with defining polynomial x^2 - 5 with z0 = 2.236067977499790? + From: Number Field in z0 with defining polynomial x^2 - 5 + with z0 = 2.236067977499790? To: Complex Lazy Field Defn: z0 -> 2.236067977499790? @@ -2286,8 +2258,8 @@ def subfield(self, alpha, name=None, names=None): sage: CLF_from_K(K_from_L(L.gen())) 2.23606797749979? + 0.?e-14*I - If `self` has no specified embedding, then `K` comes with an - embedding in `self`:: + If ``self`` has no specified embedding, then `K` comes with an + embedding in ``self``:: sage: K.<a> = NumberField(x^6 - 6*x^4 + 8*x^2 - 1) sage: L.<b>, from_L = K.subfield(a^2) @@ -2298,7 +2270,7 @@ def subfield(self, alpha, name=None, names=None): You can also view a number field as having a different generator by just choosing the input to generate the whole field; for that it is - better to use ``self.change_generator``, which gives + better to use :meth:`change_generator`, which gives isomorphisms in both directions. """ if names is not None: @@ -2319,13 +2291,14 @@ def subfield(self, alpha, name=None, names=None): def change_generator(self, alpha, name=None, names=None): r""" - Given the number field self, construct another isomorphic number - field `K` generated by the element alpha of self, along - with isomorphisms from `K` to self and from self to + Given the number field ``self``, construct another isomorphic number + field `K` generated by the element ``alpha`` of ``self``, along + with isomorphisms from `K` to ``self`` and from ``self`` to `K`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<i> = NumberField(x^2 + 1); L Number Field in i with defining polynomial x^2 + 1 sage: K, from_K, to_K = L.change_generator(i/2 + 3) @@ -2333,13 +2306,15 @@ def change_generator(self, alpha, name=None, names=None): Number Field in i0 with defining polynomial x^2 - 6*x + 37/4 with i0 = 1/2*i + 3 sage: from_K Ring morphism: - From: Number Field in i0 with defining polynomial x^2 - 6*x + 37/4 with i0 = 1/2*i + 3 + From: Number Field in i0 with defining polynomial x^2 - 6*x + 37/4 + with i0 = 1/2*i + 3 To: Number Field in i with defining polynomial x^2 + 1 Defn: i0 |--> 1/2*i + 3 sage: to_K Ring morphism: From: Number Field in i with defining polynomial x^2 + 1 - To: Number Field in i0 with defining polynomial x^2 - 6*x + 37/4 with i0 = 1/2*i + 3 + To: Number Field in i0 with defining polynomial x^2 - 6*x + 37/4 + with i0 = 1/2*i + 3 Defn: i |--> 2*i0 - 6 We can also do @@ -2357,7 +2332,7 @@ def change_generator(self, alpha, name=None, names=None): sage: to_K(i) 2*c - 6 - Note that the image is indeed a square root of -1. + Note that the image is indeed a square root of `-1`. :: @@ -2396,23 +2371,23 @@ def subfield_from_elements(self, alpha, name=None, polred=True, threshold=None): INPUT: - - ``alpha`` - list of elements in this number field + - ``alpha`` -- list of elements in this number field - - ``name`` - a name for the generator of the new number field + - ``name`` -- a name for the generator of the new number field - - ``polred`` (boolean, default ``True``) - whether to optimize the generator of + - ``polred`` -- (boolean, default ``True``); whether to optimize the generator of the newly created field - - ``threshold`` (positive number, default ``None``) - threshold to be passed to + - ``threshold`` -- (positive number, default ``None``) threshold to be passed to the ``do_polred`` function OUTPUT: a triple ``(field, beta, hom)`` where - - ``field`` - a subfield of this number field + - ``field`` -- a subfield of this number field - - ``beta`` - a list of elements of ``field`` corresponding to ``alpha`` + - ``beta`` -- a list of elements of ``field`` corresponding to ``alpha`` - - ``hom`` - inclusion homomorphism from ``field`` to ``self`` + - ``hom`` -- inclusion homomorphism from ``field`` to ``self`` EXAMPLES:: @@ -2430,8 +2405,10 @@ def subfield_from_elements(self, alpha, name=None, polred=True, threshold=None): [a0, -1/3*a0 + 1] sage: phi Ring morphism: - From: Number Field in a0 with defining polynomial x^2 - 2 with a0 = 1.414213562373095? - To: Number Field in a with defining polynomial x^4 - 4*x^2 + 1 with a = 0.5176380902050415? + From: Number Field in a0 with defining polynomial x^2 - 2 + with a0 = 1.414213562373095? + To: Number Field in a with defining polynomial x^4 - 4*x^2 + 1 + with a = 0.5176380902050415? Defn: a0 |--> -a^3 + 3*a sage: assert phi(elts[0]) == sqrt2 sage: assert phi(elts[1]) == 1 - sqrt2/3 @@ -2443,7 +2420,8 @@ def subfield_from_elements(self, alpha, name=None, polred=True, threshold=None): sage: L, elts, phi = K.subfield_from_elements([sqrt2, sqrt3]) sage: phi - Identity endomorphism of Number Field in a with defining polynomial x^4 - 4*x^2 + 1 with a = 0.5176380902050415? + Identity endomorphism of Number Field in a with defining polynomial + x^4 - 4*x^2 + 1 with a = 0.5176380902050415? TESTS:: @@ -2555,7 +2533,7 @@ def subfield_from_elements(self, alpha, name=None, polred=True, threshold=None): def is_absolute(self): """ - Return ``True`` if self is an absolute field. + Return ``True`` if ``self`` is an absolute field. This function will be implemented in the derived classes. @@ -2571,6 +2549,7 @@ def is_relative(self): """ EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^10 - 2) sage: K.is_absolute() True @@ -2597,6 +2576,7 @@ def quadratic_defect(self, a, p, check=True): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 + 2) sage: p = K.primes_above(2)[0] sage: K.quadratic_defect(5, p) @@ -2680,10 +2660,11 @@ def absolute_field(self, names): def is_isomorphic(self, other, isomorphism_maps=False) -> bool: """ - Return True if self is isomorphic as a number field to other. + Return ``True`` if ``self`` is isomorphic as a number field to ``other``. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: m.<b> = NumberField(x^2 + 4) sage: k.is_isomorphic(m) @@ -2740,47 +2721,50 @@ def is_isomorphic(self, other, isomorphism_maps=False) -> bool: def is_totally_real(self): """ - Return True if self is totally real, and False otherwise. + Return ``True`` if ``self`` is totally real, and ``False`` otherwise. - Totally real means that every isomorphic embedding of self into the + Totally real means that every isomorphic embedding of ``self`` into the complex numbers has image contained in the real numbers. EXAMPLES:: - sage: NumberField(x^2+2, 'alpha').is_totally_real() + sage: x = polygen(QQ, 'x') + sage: NumberField(x^2 + 2, 'alpha').is_totally_real() False - sage: NumberField(x^2-2, 'alpha').is_totally_real() + sage: NumberField(x^2 - 2, 'alpha').is_totally_real() True - sage: NumberField(x^4-2, 'alpha').is_totally_real() + sage: NumberField(x^4 - 2, 'alpha').is_totally_real() False """ return self.signature()[1] == 0 def is_totally_imaginary(self): """ - Return True if self is totally imaginary, and False otherwise. + Return ``True`` if ``self`` is totally imaginary, and ``False`` otherwise. - Totally imaginary means that no isomorphic embedding of self into + Totally imaginary means that no isomorphic embedding of ``self`` into the complex numbers has image contained in the real numbers. EXAMPLES:: - sage: NumberField(x^2+2, 'alpha').is_totally_imaginary() + sage: x = polygen(QQ, 'x') + sage: NumberField(x^2 + 2, 'alpha').is_totally_imaginary() True - sage: NumberField(x^2-2, 'alpha').is_totally_imaginary() + sage: NumberField(x^2 - 2, 'alpha').is_totally_imaginary() False - sage: NumberField(x^4-2, 'alpha').is_totally_imaginary() + sage: NumberField(x^4 - 2, 'alpha').is_totally_imaginary() False """ return self.signature()[0] == 0 def is_CM(self): r""" - Return True if self is a CM field (i.e. a totally imaginary + Return ``True`` if ``self`` is a CM field (i.e., a totally imaginary quadratic extension of a totally real field). EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: Q.<a> = NumberField(x - 1) sage: Q.is_CM() False @@ -2799,7 +2783,7 @@ def is_CM(self): sage: F.<a> = NumberField(x^3 - 2) sage: F.is_CM() False - sage: F.<a> = NumberField(x^4-x^3-3*x^2+x+1) + sage: F.<a> = NumberField(x^4 - x^3 - 3*x^2 + x + 1) sage: F.is_CM() False @@ -2812,9 +2796,8 @@ def is_CM(self): True sage: F.is_CM() False - sage: F2.<a> = NumberField(x^12 - 5*x^11 + 8*x^10 - 5*x^9 - \ - x^8 + 9*x^7 + 7*x^6 - 3*x^5 + 5*x^4 + \ - 7*x^3 - 4*x^2 - 7*x + 7) + sage: F2.<a> = NumberField(x^12 - 5*x^11 + 8*x^10 - 5*x^9 - x^8 + 9*x^7 + ....: + 7*x^6 - 3*x^5 + 5*x^4 + 7*x^3 - 4*x^2 - 7*x + 7) sage: F2.is_totally_imaginary() True sage: F2.is_CM() @@ -2833,8 +2816,8 @@ def is_CM(self): :: - sage: E_0.<a> = NumberField(x^7 - 4*x^6 - 4*x^5 + 10*x^4 + 4*x^3 - \ - 6*x^2 - x + 1) + sage: E_0.<a> = NumberField(x^7 - 4*x^6 - 4*x^5 + 10*x^4 + 4*x^3 + ....: - 6*x^2 - x + 1) sage: E_0.is_totally_real() True sage: E.<b> = E_0.extension(x^2 + 1) @@ -2899,31 +2882,36 @@ def is_CM(self): def complex_conjugation(self): """ - Return the complex conjugation of self. + Return the complex conjugation of ``self``. This is only well-defined for fields contained in CM fields (i.e. for totally real fields and CM fields). Recall that a CM field is a totally imaginary quadratic extension of a totally - real field. For other fields, a ValueError is raised. + real field. For other fields, a :class:`ValueError` is raised. EXAMPLES:: sage: QuadraticField(-1, 'I').complex_conjugation() - Ring endomorphism of Number Field in I with defining polynomial x^2 + 1 with I = 1*I + Ring endomorphism of + Number Field in I with defining polynomial x^2 + 1 with I = 1*I Defn: I |--> -I sage: CyclotomicField(8).complex_conjugation() Ring endomorphism of Cyclotomic Field of order 8 and degree 4 Defn: zeta8 |--> -zeta8^3 sage: QuadraticField(5, 'a').complex_conjugation() - Identity endomorphism of Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? + Identity endomorphism of Number Field in a with defining + polynomial x^2 - 5 with a = 2.236067977499790? + sage: x = polygen(QQ, 'x') sage: F = NumberField(x^4 + x^3 - 3*x^2 - x + 1, 'a') sage: F.is_totally_real() True sage: F.complex_conjugation() - Identity endomorphism of Number Field in a with defining polynomial x^4 + x^3 - 3*x^2 - x + 1 + Identity endomorphism of Number Field in a with defining + polynomial x^4 + x^3 - 3*x^2 - x + 1 sage: F.<b> = NumberField(x^2 - 2) sage: F.extension(x^2 + 1, 'a').complex_conjugation() - Relative number field endomorphism of Number Field in a with defining polynomial x^2 + 1 over its base field + Relative number field endomorphism of Number Field in a + with defining polynomial x^2 + 1 over its base field Defn: a |--> -a b |--> b sage: F2.<b> = NumberField(x^2 + 2) @@ -2991,45 +2979,59 @@ def complex_conjugation(self): def maximal_totally_real_subfield(self): """ - Return the maximal totally real subfield of self together with an embedding of it into self. + Return the maximal totally real subfield of ``self`` together with an embedding of it into ``self``. EXAMPLES:: sage: F.<a> = QuadraticField(11) sage: F.maximal_totally_real_subfield() [Number Field in a with defining polynomial x^2 - 11 with a = 3.316624790355400?, - Identity endomorphism of Number Field in a with defining polynomial x^2 - 11 with a = 3.316624790355400?] + Identity endomorphism of + Number Field in a with defining polynomial x^2 - 11 with a = 3.316624790355400?] sage: F.<a> = QuadraticField(-15) sage: F.maximal_totally_real_subfield() [Rational Field, Natural morphism: From: Rational Field - To: Number Field in a with defining polynomial x^2 + 15 with a = 3.872983346207417?*I] + To: Number Field in a with defining polynomial x^2 + 15 + with a = 3.872983346207417?*I] sage: F.<a> = CyclotomicField(29) sage: F.maximal_totally_real_subfield() - (Number Field in a0 with defining polynomial x^14 + x^13 - 13*x^12 - 12*x^11 + 66*x^10 + 55*x^9 - 165*x^8 - 120*x^7 + 210*x^6 + 126*x^5 - 126*x^4 - 56*x^3 + 28*x^2 + 7*x - 1 with a0 = 1.953241111420174?, + (Number Field in a0 with defining polynomial x^14 + x^13 - 13*x^12 - 12*x^11 + + 66*x^10 + 55*x^9 - 165*x^8 - 120*x^7 + 210*x^6 + 126*x^5 - 126*x^4 + - 56*x^3 + 28*x^2 + 7*x - 1 with a0 = 1.953241111420174?, Ring morphism: - From: Number Field in a0 with defining polynomial x^14 + x^13 - 13*x^12 - 12*x^11 + 66*x^10 + 55*x^9 - 165*x^8 - 120*x^7 + 210*x^6 + 126*x^5 - 126*x^4 - 56*x^3 + 28*x^2 + 7*x - 1 with a0 = 1.953241111420174? + From: Number Field in a0 with defining polynomial x^14 + x^13 - 13*x^12 - 12*x^11 + + 66*x^10 + 55*x^9 - 165*x^8 - 120*x^7 + 210*x^6 + 126*x^5 - 126*x^4 + - 56*x^3 + 28*x^2 + 7*x - 1 with a0 = 1.953241111420174? To: Cyclotomic Field of order 29 and degree 28 - Defn: a0 |--> -a^27 - a^26 - a^25 - a^24 - a^23 - a^22 - a^21 - a^20 - a^19 - a^18 - a^17 - a^16 - a^15 - a^14 - a^13 - a^12 - a^11 - a^10 - a^9 - a^8 - a^7 - a^6 - a^5 - a^4 - a^3 - a^2 - 1) + Defn: a0 |--> -a^27 - a^26 - a^25 - a^24 - a^23 - a^22 - a^21 - a^20 - a^19 + - a^18 - a^17 - a^16 - a^15 - a^14 - a^13 - a^12 - a^11 - a^10 + - a^9 - a^8 - a^7 - a^6 - a^5 - a^4 - a^3 - a^2 - 1) + sage: x = polygen(QQ, 'x') sage: F.<a> = NumberField(x^3 - 2) sage: F.maximal_totally_real_subfield() - [Rational Field, Coercion map: + [Rational Field, + Coercion map: From: Rational Field To: Number Field in a with defining polynomial x^3 - 2] sage: F.<a> = NumberField(x^4 - x^3 - x^2 + x + 1) sage: F.maximal_totally_real_subfield() - [Rational Field, Coercion map: + [Rational Field, + Coercion map: From: Rational Field To: Number Field in a with defining polynomial x^4 - x^3 - x^2 + x + 1] sage: F.<a> = NumberField(x^4 - x^3 + 2*x^2 + x + 1) sage: F.maximal_totally_real_subfield() - [Number Field in a1 with defining polynomial x^2 - x - 1, Ring morphism: + [Number Field in a1 with defining polynomial x^2 - x - 1, + Ring morphism: From: Number Field in a1 with defining polynomial x^2 - x - 1 To: Number Field in a with defining polynomial x^4 - x^3 + 2*x^2 + x + 1 Defn: a1 |--> -1/2*a^3 - 1/2] - sage: F.<a> = NumberField(x^4-4*x^2-x+1) + sage: F.<a> = NumberField(x^4 - 4*x^2 - x + 1) sage: F.maximal_totally_real_subfield() - [Number Field in a with defining polynomial x^4 - 4*x^2 - x + 1, Identity endomorphism of Number Field in a with defining polynomial x^4 - 4*x^2 - x + 1] + [Number Field in a with defining polynomial x^4 - 4*x^2 - x + 1, + Identity endomorphism of + Number Field in a with defining polynomial x^4 - 4*x^2 - x + 1] An example of a relative extension where the base field is not the maximal totally real subfield. @@ -3039,17 +3041,21 @@ def maximal_totally_real_subfield(self): sage: y = polygen(E_0) sage: E.<z> = E_0.extension(y^2 - E_0.gen() / 2) sage: E.maximal_totally_real_subfield() - [Number Field in z1 with defining polynomial x^2 - 2*x - 5, Composite map: + [Number Field in z1 with defining polynomial x^2 - 2*x - 5, + Composite map: From: Number Field in z1 with defining polynomial x^2 - 2*x - 5 To: Number Field in z with defining polynomial x^2 - 1/2*a over its base field Defn: Ring morphism: From: Number Field in z1 with defining polynomial x^2 - 2*x - 5 - To: Number Field in z with defining polynomial x^4 - 2*x^3 + x^2 + 6*x + 3 + To: Number Field in z with defining + polynomial x^4 - 2*x^3 + x^2 + 6*x + 3 Defn: z1 |--> -1/3*z^3 + 1/3*z^2 + z - 1 then Isomorphism map: - From: Number Field in z with defining polynomial x^4 - 2*x^3 + x^2 + 6*x + 3 - To: Number Field in z with defining polynomial x^2 - 1/2*a over its base field] + From: Number Field in z with defining + polynomial x^4 - 2*x^3 + x^2 + 6*x + 3 + To: Number Field in z with defining + polynomial x^2 - 1/2*a over its base field] """ @@ -3099,7 +3105,7 @@ def maximal_totally_real_subfield(self): def complex_embeddings(self, prec=53): r""" Return all homomorphisms of this number field into the approximate - complex field with precision prec. + complex field with precision ``prec``. This always embeds into an MPFR based complex field. If you want embeddings into the 53-bit double precision, which is @@ -3107,16 +3113,17 @@ def complex_embeddings(self, prec=53): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^5 + x + 17) sage: v = k.complex_embeddings() - sage: ls = [phi(k.0^2) for phi in v] ; ls # random order + sage: ls = [phi(k.0^2) for phi in v]; ls # random order [2.97572074038..., -2.40889943716 + 1.90254105304*I, -2.40889943716 - 1.90254105304*I, 0.921039066973 + 3.07553311885*I, 0.921039066973 - 3.07553311885*I] sage: K.<a> = NumberField(x^3 + 2) - sage: ls = K.complex_embeddings() ; ls # random order + sage: ls = K.complex_embeddings(); ls # random order [ Ring morphism: From: Number Field in a with defining polynomial x^3 + 2 @@ -3138,9 +3145,9 @@ def complex_embeddings(self, prec=53): def real_embeddings(self, prec=53): r""" Return all homomorphisms of this number field into the approximate - real field with precision prec. + real field with precision ``prec``. - If prec is 53 (the default), then the real double field is + If ``prec`` is 53 (the default), then the real double field is used; otherwise the arbitrary precision (but slow) real field is used. If you want embeddings into the 53-bit double precision, which is faster, use ``self.embeddings(RDF)``. @@ -3153,6 +3160,7 @@ def real_embeddings(self, prec=53): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: K.real_embeddings() [ @@ -3179,7 +3187,7 @@ def real_embeddings(self, prec=53): As this is a numerical function, the number of embeddings may be incorrect if the precision is too low:: - sage: K = NumberField(x^2+2*10^1000*x + 10^2000+1, 'a') + sage: K = NumberField(x^2 + 2*10^1000*x + 10^2000 + 1, 'a') sage: len(K.real_embeddings()) 2 sage: len(K.real_embeddings(100)) @@ -3198,10 +3206,10 @@ def specified_complex_embedding(self): Return the embedding of this field into the complex numbers which has been specified. - Fields created with the ``QuadraticField`` or - ``CyclotomicField`` constructors come with an implicit + Fields created with the :func:`QuadraticField` or + :func:`CyclotomicField` constructors come with an implicit embedding. To get one of these fields without the embedding, use - the generic ``NumberField`` constructor. + the generic :class:`NumberField` constructor. EXAMPLES:: @@ -3215,7 +3223,8 @@ def specified_complex_embedding(self): sage: QuadraticField(3, 'a').specified_complex_embedding() Generic morphism: - From: Number Field in a with defining polynomial x^2 - 3 with a = 1.732050807568878? + From: Number Field in a with defining polynomial x^2 - 3 + with a = 1.732050807568878? To: Real Lazy Field Defn: a -> 1.732050807568878? @@ -3230,33 +3239,43 @@ def specified_complex_embedding(self): Most fields don't implicitly have embeddings unless explicitly specified:: - sage: NumberField(x^2-2, 'a').specified_complex_embedding() is None + sage: x = polygen(QQ, 'x') + sage: NumberField(x^2 - 2, 'a').specified_complex_embedding() is None True - sage: NumberField(x^3-x+5, 'a').specified_complex_embedding() is None + sage: NumberField(x^3 - x + 5, 'a').specified_complex_embedding() is None True - sage: NumberField(x^3-x+5, 'a', embedding=2).specified_complex_embedding() + sage: NumberField(x^3 - x + 5, 'a', embedding=2).specified_complex_embedding() Generic morphism: - From: Number Field in a with defining polynomial x^3 - x + 5 with a = -1.904160859134921? + From: Number Field in a with defining polynomial x^3 - x + 5 + with a = -1.904160859134921? To: Real Lazy Field Defn: a -> -1.904160859134921? - sage: NumberField(x^3-x+5, 'a', embedding=CDF.0).specified_complex_embedding() + sage: NumberField(x^3 - x + 5, 'a', embedding=CDF.0).specified_complex_embedding() Generic morphism: - From: Number Field in a with defining polynomial x^3 - x + 5 with a = 0.952080429567461? + 1.311248044077123?*I + From: Number Field in a with defining polynomial x^3 - x + 5 + with a = 0.952080429567461? + 1.311248044077123?*I To: Complex Lazy Field Defn: a -> 0.952080429567461? + 1.311248044077123?*I This function only returns complex embeddings:: - sage: K.<a> = NumberField(x^2-2, embedding=Qp(7)(2).sqrt()) + sage: # needs sage.rings.padics + sage: K.<a> = NumberField(x^2 - 2, embedding=Qp(7)(2).sqrt()) sage: K.specified_complex_embedding() is None True sage: K.gen_embedding() - 3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 + 6*7^9 + 6*7^10 + 2*7^11 + 7^12 + 7^13 + 2*7^15 + 7^16 + 7^17 + 4*7^18 + 6*7^19 + O(7^20) + 3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 + 6*7^9 + 6*7^10 + + 2*7^11 + 7^12 + 7^13 + 2*7^15 + 7^16 + 7^17 + 4*7^18 + 6*7^19 + O(7^20) sage: K.coerce_embedding() Generic morphism: - From: Number Field in a with defining polynomial x^2 - 2 with a = 3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 + 6*7^9 + 6*7^10 + 2*7^11 + 7^12 + 7^13 + 2*7^15 + 7^16 + 7^17 + 4*7^18 + 6*7^19 + O(7^20) + From: Number Field in a with defining polynomial x^2 - 2 + with a = 3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 + + 6*7^9 + 6*7^10 + 2*7^11 + 7^12 + 7^13 + 2*7^15 + 7^16 + + 7^17 + 4*7^18 + 6*7^19 + O(7^20) To: 7-adic Field with capped relative precision 20 - Defn: a -> 3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 + 6*7^9 + 6*7^10 + 2*7^11 + 7^12 + 7^13 + 2*7^15 + 7^16 + 7^17 + 4*7^18 + 6*7^19 + O(7^20) + Defn: a -> 3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 + + 6*7^9 + 6*7^10 + 2*7^11 + 7^12 + 7^13 + 2*7^15 + 7^16 + + 7^17 + 4*7^18 + 6*7^19 + O(7^20) """ embedding = self.coerce_embedding() if embedding is not None and embedding.codomain()._is_numerical(): @@ -3266,13 +3285,14 @@ def specified_complex_embedding(self): def gen_embedding(self): """ If an embedding has been specified, return the image of the - generator under that embedding. Otherwise return None. + generator under that embedding. Otherwise return ``None``. EXAMPLES:: sage: QuadraticField(-7, 'a').gen_embedding() 2.645751311064591?*I - sage: NumberField(x^2+7, 'a').gen_embedding() # None + sage: x = polygen(QQ, 'x') + sage: NumberField(x^2 + 7, 'a').gen_embedding() # None """ embedding = self.coerce_embedding() if embedding is None: @@ -3282,14 +3302,15 @@ def gen_embedding(self): def algebraic_closure(self): """ - Return the algebraic closure of self (which is QQbar). + Return the algebraic closure of ``self`` (which is ``QQbar``). EXAMPLES:: sage: K.<i> = QuadraticField(-1) sage: K.algebraic_closure() Algebraic Field - sage: K.<a> = NumberField(x^3-2) + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: K.algebraic_closure() Algebraic Field sage: K = CyclotomicField(23) @@ -3303,12 +3324,13 @@ def algebraic_closure(self): def conductor(self, check_abelian=True): r""" Computes the conductor of the abelian field `K`. - If check_abelian is set to false and the field is not an + If ``check_abelian`` is set to ``False`` and the field is not an abelian extension of `\QQ`, the output is not meaningful. INPUT: - - ``check_abelian`` - a boolean (default: ``True``); check to see that this is an abelian extension of `\QQ` + - ``check_abelian`` -- a boolean (default: ``True``); check to see + that this is an abelian extension of `\QQ` OUTPUT: @@ -3320,10 +3342,11 @@ def conductor(self, check_abelian=True): sage: k = K.subfields(9)[0][0] sage: k.conductor() 27 - sage: K.<t> = NumberField(x^3+x^2-2*x-1) + sage: x = polygen(QQ, 'x') + sage: K.<t> = NumberField(x^3 + x^2 - 2*x - 1) sage: K.conductor() 7 - sage: K.<t> = NumberField(x^3+x^2-36*x-4) + sage: K.<t> = NumberField(x^3 + x^2 - 36*x - 4) sage: K.conductor() 109 sage: K = CyclotomicField(48) @@ -3332,17 +3355,17 @@ def conductor(self, check_abelian=True): 48 sage: NumberField(x,'a').conductor() 1 - sage: NumberField(x^8 - 8*x^6 + 19*x^4 - 12*x^2 + 1,'a').conductor() + sage: NumberField(x^8 - 8*x^6 + 19*x^4 - 12*x^2 + 1, 'a').conductor() 40 - sage: NumberField(x^8 + 7*x^4 + 1,'a').conductor() + sage: NumberField(x^8 + 7*x^4 + 1, 'a').conductor() 40 - sage: NumberField(x^8 - 40*x^6 + 500*x^4 - 2000*x^2 + 50,'a').conductor() + sage: NumberField(x^8 - 40*x^6 + 500*x^4 - 2000*x^2 + 50, 'a').conductor() 160 ALGORITHM: For odd primes, it is easy to compute from the ramification - index because the p-Sylow subgroup is cyclic. For p=2, there + index because the `p`-Sylow subgroup is cyclic. For `p=2`, there are two choices for a given ramification index. They can be distinguished by the parity of the exponent in the discriminant of a 2-adic completion. @@ -3375,35 +3398,34 @@ def conductor(self, check_abelian=True): def dirichlet_group(self): r""" - Given a abelian field `K`, this computes and returns the + Given a abelian field `K`, compute and return the set of all Dirichlet characters corresponding to the - characters of the Galois group of `K/\mathbb{Q}`. + characters of the Galois group of `K/\QQ`. - The output is random if the field is not abelian + The output is random if the field is not abelian. - OUTPUT: - - - a list of Dirichlet characters + OUTPUT: a list of Dirichlet characters EXAMPLES:: - sage: K.<t> = NumberField(x^3+x^2-36*x-4) + sage: x = polygen(QQ, 'x') + sage: K.<t> = NumberField(x^3 + x^2 - 36*x - 4) sage: K.conductor() 109 sage: K.dirichlet_group() [Dirichlet character modulo 109 of conductor 1 mapping 6 |--> 1, - Dirichlet character modulo 109 of conductor 109 mapping 6 |--> zeta3, - Dirichlet character modulo 109 of conductor 109 mapping 6 |--> -zeta3 - 1] + Dirichlet character modulo 109 of conductor 109 mapping 6 |--> zeta3, + Dirichlet character modulo 109 of conductor 109 mapping 6 |--> -zeta3 - 1] sage: K = CyclotomicField(44) sage: L = K.subfields(5)[0][0] sage: X = L.dirichlet_group() sage: X [Dirichlet character modulo 11 of conductor 1 mapping 2 |--> 1, - Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta5, - Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta5^2, - Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta5^3, - Dirichlet character modulo 11 of conductor 11 mapping 2 |--> -zeta5^3 - zeta5^2 - zeta5 - 1] + Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta5, + Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta5^2, + Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta5^3, + Dirichlet character modulo 11 of conductor 11 mapping 2 |--> -zeta5^3 - zeta5^2 - zeta5 - 1] sage: X[4]^2 Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta5^3 sage: X[4]^2 in X @@ -3427,34 +3449,13 @@ def dirichlet_group(self): H.append(chi) return H - def latex_variable_name(self, name=None): - """ - Return the latex representation of the variable name for this - number field. - - EXAMPLES:: - - sage: NumberField(x^2 + 3, 'a').latex_variable_name() - doctest:...: DeprecationWarning: This method is replaced by ... - See https://github.com/sagemath/sage/issues/30372 for details. - 'a' - sage: NumberField(x^3 + 3, 'theta3').latex_variable_name() - '\\theta_{3}' - sage: CyclotomicField(5).latex_variable_name() - '\\zeta_{5}' - """ - deprecation(30372, 'This method is replaced by the method latex_variable_names') - if name is None: - return self._latex_names[0] - else: - self._latex_names = (name,) - def _repr_(self): """ Return string representation of this number field. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^13 - (2/3)*x + 3) sage: k._repr_() 'Number Field in a with defining polynomial x^13 - 2/3*x + 3' @@ -3476,6 +3477,7 @@ def _latex_(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^13 - (2/3)*x + 3) sage: k._latex_() '\\Bold{Q}[a]/(a^{13} - \\frac{2}{3} a + 3)' @@ -3502,6 +3504,7 @@ def _ideal_class_(self, n=0): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^2 + 2, 'c')._ideal_class_() <class 'sage.rings.number_field.number_field_ideal.NumberFieldIdeal'> """ @@ -3515,10 +3518,11 @@ def _fractional_ideal_class_(self): This function is required by the general ring/ideal machinery. The value defined here is the default value for all number fields *except* relative number fields; this function is overridden by - one of the same name on class NumberField_relative. + one of the same name in class :class:`NumberField_relative`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^2 + 2, 'c')._fractional_ideal_class_() <class 'sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal'> """ @@ -3526,15 +3530,16 @@ def _fractional_ideal_class_(self): def ideal(self, *gens, **kwds): """ - K.ideal() returns a fractional ideal of the field, except for the - zero ideal which is not a fractional ideal. + Return a fractional ideal of the field, except for the + zero ideal, which is not a fractional ideal. EXAMPLES:: - sage: K.<i>=NumberField(x^2+1) + sage: x = polygen(QQ, 'x') + sage: K.<i> = NumberField(x^2 + 1) sage: K.ideal(2) Fractional ideal (2) - sage: K.ideal(2+i) + sage: K.ideal(2 + i) Fractional ideal (i + 2) sage: K.ideal(0) Ideal (0) of Number Field in i with defining polynomial x^2 + 1 @@ -3545,7 +3550,7 @@ def ideal(self, *gens, **kwds): sage: x = polygen(QQ) sage: K.<a> = NumberField(x^6 - x^5 - 5*x^4 + 4*x^3 + 6*x^2 - 3*x - 1) - sage: K.ideal(1,1) + sage: K.ideal(1, 1) Fractional ideal (1) """ try: @@ -3562,9 +3567,9 @@ def idealchinese(self, ideals, residues): INPUT: - - ``ideals`` - a list of ideals of the number field. + - ``ideals`` -- a list of ideals of the number field. - - ``residues`` - a list of elements of the number field. + - ``residues`` -- a list of elements of the number field. OUTPUT: @@ -3580,25 +3585,27 @@ def idealchinese(self, ideals, residues): This is the example from the pari page on ``idealchinese``:: + sage: # needs sage.symbolic sage: K.<sqrt2> = NumberField(sqrt(2).minpoly()) - sage: ideals = [K.ideal(4),K.ideal(3)] - sage: residues = [sqrt2,1] - sage: r = K.idealchinese(ideals,residues); r + sage: ideals = [K.ideal(4), K.ideal(3)] + sage: residues = [sqrt2, 1] + sage: r = K.idealchinese(ideals, residues); r -3*sqrt2 + 4 - sage: all((r - a) in I for I,a in zip(ideals,residues)) + sage: all((r - a) in I for I, a in zip(ideals, residues)) True The result may be non-integral if the results are non-integral:: + sage: # needs sage.symbolic sage: K.<sqrt2> = NumberField(sqrt(2).minpoly()) - sage: ideals = [K.ideal(4),K.ideal(21)] - sage: residues = [1/sqrt2,1] - sage: r = K.idealchinese(ideals,residues); r + sage: ideals = [K.ideal(4), K.ideal(21)] + sage: residues = [1/sqrt2, 1] + sage: r = K.idealchinese(ideals, residues); r -63/2*sqrt2 - 20 sage: all( - ....: (r-a).valuation(P) >= k - ....: for I,a in zip(ideals,residues) - ....: for P,k in I.factor() + ....: (r - a).valuation(P) >= k + ....: for I, a in zip(ideals, residues) + ....: for P, k in I.factor() ....: ) True """ @@ -3614,22 +3621,23 @@ def idealchinese(self, ideals, residues): def fractional_ideal(self, *gens, **kwds): r""" - Return the ideal in `\mathcal{O}_K` generated by gens. - This overrides the ``sage.rings.ring.Field`` method to - use the ``sage.rings.ring.Ring`` one instead, since + Return the ideal in `\mathcal{O}_K` generated by ``gens``. + This overrides the :class:`sage.rings.ring.Field` method to + use the :class:`sage.rings.ring.Ring` one instead, since we're not really concerned with ideals in a field but in its ring of integers. INPUT: - - ``gens`` - a list of generators, or a number field + - ``gens`` -- a list of generators, or a number field ideal. EXAMPLES:: - sage: K.<a> = NumberField(x^3-2) + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: K.fractional_ideal([1/a]) Fractional ideal (1/2*a^2) @@ -3668,20 +3676,19 @@ def fractional_ideal(self, *gens, **kwds): return self._fractional_ideal_class_()(self, gens, **kwds) def ideals_of_bdd_norm(self, bound): - """ - All integral ideals of bounded norm. + r""" + Return all integral ideals of bounded norm. INPUT: + - ``bound`` -- a positive integer - - ``bound`` - a positive integer - - - OUTPUT: A dict of all integral ideals I such that Norm(I) <= bound, + OUTPUT: A dict of all integral ideals `I` such that Norm(`I`) `\leq` ``bound``, keyed by norm. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 + 23) sage: d = K.ideals_of_bdd_norm(10) sage: for n in d: @@ -3726,19 +3733,19 @@ def ideals_of_bdd_norm(self, bound): def primes_above(self, x, degree=None): r""" - Return prime ideals of self lying over x. + Return prime ideals of ``self`` lying over `x`. INPUT: - - ``x``: usually an element or ideal of self. It - should be such that self.ideal(x) is sensible. This excludes x=0. + - ``x`` -- usually an element or ideal of ``self``. It + should be such that ``self.ideal(x)`` is sensible. This excludes `x=0`. - - ``degree`` (default: ``None``): ``None`` or an integer. - If ``None``, find all primes above x of any degree. If an - integer, find all primes above x such that the resulting + - ``degree`` -- (default: ``None``) ``None`` or an integer. + If ``None``, find all primes above `x` of any degree. If an + integer, find all primes above `x` such that the resulting residue field has exactly this degree. - OUTPUT: A list of prime ideals of self lying over x. If degree + OUTPUT: A list of prime ideals of ``self`` lying over `x`. If ``degree`` is specified and no such ideal exists, returns the empty list. The output is sorted by residue degree first, then by underlying prime (or equivalently, by norm). @@ -3751,7 +3758,7 @@ def primes_above(self, x, degree=None): :: sage: P2s = F.primes_above(2) - sage: P2s # random + sage: P2s # random [Fractional ideal (-t)] sage: all(2 in P2 for P2 in P2s) True @@ -3772,7 +3779,7 @@ def primes_above(self, x, degree=None): sage: [ P3.norm() for P3 in P3s ] [3] - The ideal (3) is totally ramified in F, so there is no degree 2 + The ideal `(3)` is totally ramified in `F`, so there is no degree 2 prime above 3:: sage: F.primes_above(3, degree=2) @@ -3811,7 +3818,7 @@ def primes_above(self, x, degree=None): sage: K.primes_above(I, degree=4) == [Q] True - It doesn't make sense to factor the ideal (0), so this raises an error:: + It doesn't make sense to factor the ideal `(0)`, so this raises an error:: sage: F.prime_above(0) Traceback (most recent call last): @@ -3829,20 +3836,20 @@ def primes_above(self, x, degree=None): def prime_above(self, x, degree=None): r""" - Return a prime ideal of self lying over x. + Return a prime ideal of ``self`` lying over `x`. INPUT: - - ``x``: usually an element or ideal of self. It - should be such that self.ideal(x) is sensible. This excludes x=0. + - ``x`` -- usually an element or ideal of ``self``. It + should be such that ``self.ideal(x)`` is sensible. This excludes `x=0`. - - ``degree`` (default: ``None``): ``None`` or an integer. - If one, find a prime above x of any degree. If an integer, find a - prime above x such that the resulting residue field has exactly + - ``degree`` -- (default: ``None``) ``None`` or an integer. + If one, find a prime above `x` of any degree. If an integer, find a + prime above `x` such that the resulting residue field has exactly this degree. - OUTPUT: A prime ideal of self lying over x. If degree is specified - and no such ideal exists, raises a ValueError. + OUTPUT: A prime ideal of ``self`` lying over `x`. If ``degree`` is specified + and no such ideal exists, raises a :class:`ValueError`. EXAMPLES:: @@ -3873,8 +3880,8 @@ def prime_above(self, x, degree=None): sage: P3.norm() 3 - The ideal (3) is totally ramified in F, so there is no degree 2 - prime above 3:: + The ideal `(3)` is totally ramified in `F`, so there is no degree 2 + prime above `3`:: sage: F.prime_above(3, degree=2) Traceback (most recent call last): @@ -3905,7 +3912,7 @@ def prime_above(self, x, degree=None): sage: G.prime_above(7) Fractional ideal (b + 2) - It doesn't make sense to factor the ideal (0):: + It doesn't make sense to factor the ideal `(0)`:: sage: F.prime_above(0) Traceback (most recent call last): @@ -3945,10 +3952,12 @@ def primes_of_bounded_norm(self, B): sage: K.<i> = QuadraticField(-1) sage: K.primes_of_bounded_norm(10) - [Fractional ideal (i + 1), Fractional ideal (-i - 2), Fractional ideal (2*i + 1), Fractional ideal (3)] + [Fractional ideal (i + 1), Fractional ideal (-i - 2), + Fractional ideal (2*i + 1), Fractional ideal (3)] sage: K.primes_of_bounded_norm(1) [] - sage: K.<a> = NumberField(x^3-2) + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: P = K.primes_of_bounded_norm(30) sage: P [Fractional ideal (a), @@ -4054,17 +4063,15 @@ def primes_of_degree_one_iter(self, num_integer_primes=10000, max_iterations=100 INPUT: + - ``num_integer_primes`` -- (default: 10000) an + integer. We try to find primes of absolute norm no greater than the + ``num_integer_primes``-th prime number. For example, if + ``num_integer_primes`` is 2, the largest norm found will be 3, since + the second prime is 3. - - ``num_integer_primes (default: 10000)`` - an - integer. We try to find primes of absolute norm no greater than the - num_integer_primes-th prime number. For example, if - num_integer_primes is 2, the largest norm found will be 3, since - the second prime is 3. - - - ``max_iterations (default: 100)`` - an integer. We - test max_iterations integers to find small primes before raising - StopIteration. - + - ``max_iterations`` -- (default: 100) an integer. We + test ``max_iterations`` integers to find small primes before raising + :class:`StopIteration`. EXAMPLES:: @@ -4072,10 +4079,12 @@ def primes_of_degree_one_iter(self, num_integer_primes=10000, max_iterations=100 sage: it = K.primes_of_degree_one_iter() sage: Ps = [ next(it) for i in range(3) ] sage: Ps # random - [Fractional ideal (z^3 + z + 1), Fractional ideal (3*z^3 - z^2 + z - 1), Fractional ideal (2*z^3 - 3*z^2 + z - 2)] - sage: [ P.norm() for P in Ps ] # random + [Fractional ideal (z^3 + z + 1), + Fractional ideal (3*z^3 - z^2 + z - 1), + Fractional ideal (2*z^3 - 3*z^2 + z - 2)] + sage: [P.norm() for P in Ps] # random [11, 31, 41] - sage: [ P.residue_class_degree() for P in Ps ] + sage: [P.residue_class_degree() for P in Ps] [1, 1, 1] """ from sage.rings.number_field.small_primes_of_degree_one import Small_primes_of_degree_one_iter @@ -4083,13 +4092,13 @@ def primes_of_degree_one_iter(self, num_integer_primes=10000, max_iterations=100 def primes_of_degree_one_list(self, n, num_integer_primes=10000, max_iterations=100): r""" - Return a list of n prime ideals of absolute degree one and small + Return a list of `n` prime ideals of absolute degree one and small norm. .. warning:: It is possible that there are no primes of `K` of - absolute degree one of small prime norm, and it possible + absolute degree one of small prime norm, and it is possible that this algorithm will not find any primes of small norm. See module :mod:`sage.rings.number_field.small_primes_of_degree_one` @@ -4097,25 +4106,27 @@ def primes_of_degree_one_list(self, n, num_integer_primes=10000, max_iterations= INPUT: - - ``num_integer_primes (default: 10000)`` - an - integer. We try to find primes of absolute norm no greater than the - num_integer_primes-th prime number. For example, if - num_integer_primes is 2, the largest norm found will be 3, since - the second prime is 3. + - ``num_integer_primes`` -- (default: 10000) an + integer. We try to find primes of absolute norm no greater than the + ``num_integer_primes``-th prime number. For example, if + ``num_integer_primes`` is 2, the largest norm found will be 3, since + the second prime is 3. - - ``max_iterations (default: 100)`` - an integer. We - test max_iterations integers to find small primes before raising - ``StopIteration``. + - ``max_iterations`` -- (default: 100) an integer. We + test ``max_iterations`` integers to find small primes before raising + :class:`StopIteration`. EXAMPLES:: sage: K.<z> = CyclotomicField(10) sage: Ps = K.primes_of_degree_one_list(3) sage: Ps # random output - [Fractional ideal (-z^3 - z^2 + 1), Fractional ideal (2*z^3 - 2*z^2 + 2*z - 3), Fractional ideal (2*z^3 - 3*z^2 + z - 2)] - sage: [ P.norm() for P in Ps ] + [Fractional ideal (-z^3 - z^2 + 1), + Fractional ideal (2*z^3 - 2*z^2 + 2*z - 3), + Fractional ideal (2*z^3 - 3*z^2 + z - 2)] + sage: [P.norm() for P in Ps] [11, 31, 41] - sage: [ P.residue_class_degree() for P in Ps ] + sage: [P.residue_class_degree() for P in Ps] [1, 1, 1] """ it = self.primes_of_degree_one_iter() @@ -4131,10 +4142,11 @@ def completely_split_primes(self, B=200): OUTPUT: - A list of all primes ``p < B`` which split completely in ``K``. + A list of all primes `p < B` which split completely in ``K``. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<xi> = NumberField(x^3 - 3*x + 1) sage: K.completely_split_primes(100) [17, 19, 37, 53, 71, 73, 89] @@ -4158,11 +4170,12 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): images of generators. To do this we just check that the elements of the image of the - given generator (im_gens always has length 1) satisfies the + given generator (``im_gens`` always has length 1) satisfies the relation of the defining poly of this field. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 - 3) sage: k._is_valid_homomorphism_(QQ, [0]) False @@ -4217,6 +4230,7 @@ def _pari_absolute_structure(self): If `f` is monic and integral, the result satisfies ``g = f`` and ``alpha = beta = x``:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 - 2) sage: K._pari_absolute_structure() (y^2 - 2, Mod(y, y^2 - 2), Mod(y, y^2 - 2)) @@ -4268,6 +4282,7 @@ def pari_polynomial(self, name='x'): Some examples with relative number fields:: + sage: x = polygen(ZZ, 'x') sage: k.<a, c> = NumberField([x^2 + 3, x^2 + 1]) sage: k.pari_polynomial() x^4 + 8*x^2 + 4 @@ -4307,7 +4322,7 @@ def pari_nf(self, important=True): INPUT: - ``important`` -- boolean (default: ``True``). If ``False``, - raise a ``RuntimeError`` if we need to do a difficult + raise a :class:`RuntimeError` if we need to do a difficult discriminant factorization. This is useful when an integral basis is not strictly required, such as for factoring polynomials over this number field. @@ -4323,6 +4338,7 @@ def pari_nf(self, important=True): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^4 - 3*x + 7); k Number Field in a with defining polynomial x^4 - 3*x + 7 sage: k.pari_nf()[:4] @@ -4352,7 +4368,7 @@ def pari_nf(self, important=True): RuntimeError: Unable to factor discriminant with trial division Next, we illustrate the ``maximize_at_primes`` and ``assume_disc_small`` - parameters of the ``NumberField`` constructor. The following would take + parameters of the :class:`NumberField` constructor. The following would take a very long time without the ``maximize_at_primes`` option:: sage: K.<a> = NumberField(x^2 - p*q, maximize_at_primes=[p]) @@ -4375,13 +4391,14 @@ def pari_nf(self, important=True): return self._pari_nf def pari_zk(self): - """ + r""" Integral basis of the PARI number field corresponding to this field. - This is the same as pari_nf().getattr('zk'), but much faster. + This is the same as ``pari_nf().getattr('zk')``, but much faster. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 - 17) sage: k.pari_zk() [1, 1/3*y^2 - 1/3*y + 1/3, y] @@ -4396,6 +4413,7 @@ def __pari__(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k = NumberField(x^2 + x + 1, 'a') sage: k.__pari__() [y^2 + y + 1, [0, 1], -3, 1, ... [1, y], [1, 0; 0, 1], [1, 0, 0, -1; 0, 1, 1, -1]] @@ -4410,6 +4428,7 @@ def _pari_init_(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k = NumberField(x^2 + x + 1, 'a') sage: k._pari_init_() '[y^2 + y + 1, [0, 1], -3, 1, ... [1, y], [1, 0; 0, 1], [1, 0, 0, -1; 0, 1, 1, -1]]' @@ -4443,6 +4462,7 @@ def pari_bnf(self, proof=None, units=True): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 1); k Number Field in a with defining polynomial x^2 + 1 sage: len(k.pari_bnf()) @@ -4476,7 +4496,7 @@ def pari_bnf(self, proof=None, units=True): def pari_rnfnorm_data(self, L, proof=True): """ Return the PARI :pari:`rnfisnorminit` data corresponding to the - extension L/self. + extension `L` / ``self``. EXAMPLES:: @@ -4500,16 +4520,16 @@ def pari_rnfnorm_data(self, L, proof=True): def _gap_init_(self): """ - Create a gap object representing self and return its name + Create a GAP object representing ``self`` and return its name. EXAMPLES:: + sage: # needs sage.libs.gap sage: z = QQ['z'].0 sage: K.<zeta> = NumberField(z^2 - 2) - sage: K._gap_init_() # the following variable name $sage1 represents the F.base_ring() in gap and is somehow random + sage: K._gap_init_() # the following variable name $sage1 represents the F.base_ring() in gap and is somehow random 'CallFuncList(function() local z,E; z:=Indeterminate($sage1,"z"); E:=AlgebraicExtension($sage1,z^2 - 2,"zeta"); return E; end,[])' - sage: k = gap(K) - sage: k + sage: k = gap(K); k <algebraic extension over the Rationals of degree 2> sage: k.GeneratorsOfDivisionRing() [ zeta ] @@ -4519,6 +4539,7 @@ def _gap_init_(self): ``E`` is used as a local variable in the above GAP ``CallFuncList``:: + sage: # needs sage.libs.gap sage: P.<E> = QQ[] sage: L.<tau> = NumberField(E^3 - 2) sage: l = gap(L); l @@ -4544,6 +4565,7 @@ def characteristic(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^99 + 2); k Number Field in a with defining polynomial x^99 + 2 sage: k.characteristic() @@ -4558,22 +4580,22 @@ def class_group(self, proof=None, names='c'): INPUT: + - ``proof`` -- if ``True`` then compute the class group + provably correctly. Default is ``True``. Call :func:`number_field_proof` to + change this default globally. - - ``proof`` - if True then compute the class group - provably correctly. Default is True. Call number_field_proof to - change this default globally. - - - ``names`` - names of the generators of this class - group. - + - ``names`` -- names of the generators of this class + group. OUTPUT: The class group of this number field. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 + 23) sage: G = K.class_group(); G - Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23 + Class group of order 3 with structure C3 of + Number Field in a with defining polynomial x^2 + 23 sage: G.0 Fractional ideal class (2, 1/2*a - 1/2) sage: G.gens() @@ -4594,7 +4616,8 @@ def class_group(self, proof=None, names='c'): sage: k.<a> = NumberField(x^2 + 20072) sage: G = k.class_group(); G - Class group of order 76 with structure C38 x C2 of Number Field in a with defining polynomial x^2 + 20072 + Class group of order 76 with structure C38 x C2 of + Number Field in a with defining polynomial x^2 + 20072 sage: G.0 # random Fractional ideal class (41, a + 10) sage: G.0^38 @@ -4635,13 +4658,12 @@ def class_number(self, proof=None): INPUT: - - - ``proof`` - bool (default: ``True`` unless you called - number_field_proof) - + - ``proof`` -- bool (default: ``True`` unless you called + ``number_field_proof``) EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^2 + 23, 'a').class_number() 3 sage: NumberField(x^2 + 163, 'a').class_number() @@ -4658,17 +4680,15 @@ def S_class_group(self, S, proof=None, names='c'): INPUT: - - ``S`` - a set of primes of the base field + - ``S`` -- a set of primes of the base field - - ``proof`` - if False, assume the GRH in computing the class group. - Default is True. Call ``number_field_proof`` to change this + - ``proof`` -- if False, assume the GRH in computing the class group. + Default is ``True``. Call ``number_field_proof`` to change this default globally. - - ``names`` - names of the generators of this class group. - - OUTPUT: + - ``names`` -- names of the generators of this class group. - The S-class group of this number field. + OUTPUT: The S-class group of this number field. EXAMPLES: @@ -4676,26 +4696,31 @@ def S_class_group(self, S, proof=None, names='c'): sage: K.<a> = QuadraticField(-5) sage: K.S_class_group([]) - S-class group of order 2 with structure C2 of Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I + S-class group of order 2 with structure C2 of Number Field in a + with defining polynomial x^2 + 5 with a = 2.236067977499790?*I When we include the prime `(2, a+1)`, the S-class group becomes trivial:: - sage: K.S_class_group([K.ideal(2,a+1)]) - S-class group of order 1 of Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I + sage: K.S_class_group([K.ideal(2, a + 1)]) + S-class group of order 1 of Number Field in a + with defining polynomial x^2 + 5 with a = 2.236067977499790?*I TESTS:: sage: K.<a> = QuadraticField(-14) - sage: I = K.ideal(2,a) + sage: I = K.ideal(2, a) sage: S = (I,) - sage: CS = K.S_class_group(S);CS - S-class group of order 2 with structure C2 of Number Field in a with defining polynomial x^2 + 14 with a = 3.741657386773942?*I + sage: CS = K.S_class_group(S); CS + S-class group of order 2 with structure C2 of Number Field in a + with defining polynomial x^2 + 14 with a = 3.741657386773942?*I sage: T = tuple() - sage: CT = K.S_class_group(T);CT - S-class group of order 4 with structure C4 of Number Field in a with defining polynomial x^2 + 14 with a = 3.741657386773942?*I + sage: CT = K.S_class_group(T); CT + S-class group of order 4 with structure C4 of Number Field in a + with defining polynomial x^2 + 14 with a = 3.741657386773942?*I sage: K.class_group() - Class group of order 4 with structure C4 of Number Field in a with defining polynomial x^2 + 14 with a = 3.741657386773942?*I + Class group of order 4 with structure C4 of Number Field in a + with defining polynomial x^2 + 14 with a = 3.741657386773942?*I """ proof = proof_flag(proof) if all(P.is_principal() for P in S): @@ -4716,19 +4741,18 @@ def S_units(self, S, proof=True): - ``proof`` -- if ``False``, assume the GRH in computing the class group - OUTPUT: - - A list of generators of the unit group. + OUTPUT: A list of generators of the unit group. .. note:: - For more functionality see the S_unit_group() function. + For more functionality see the function :func:`S_unit_group`. EXAMPLES:: sage: K.<a> = QuadraticField(-3) sage: K.unit_group() - Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + Unit group with structure C6 of Number Field in a + with defining polynomial x^2 + 3 with a = 1.732050807568878?*I sage: K.S_units([]) # random [1/2*a + 1/2] sage: K.S_units([])[0].multiplicative_order() @@ -4736,6 +4760,7 @@ def S_units(self, S, proof=True): An example in a relative extension (see :trac:`8722`):: + sage: x = polygen(QQ, 'x') sage: L.<a,b> = NumberField([x^2 + 1, x^2 - 5]) sage: p = L.ideal((-1/2*b - 1/2)*a + 1/2*b - 1/2) sage: W = L.S_units([p]); [x.norm() for x in W] @@ -4754,7 +4779,7 @@ def S_units(self, S, proof=True): This checks that the multiple entries issue at :trac:`9341` is fixed:: sage: _.<t> = QQ[] - sage: K.<T> = NumberField(t-1) + sage: K.<T> = NumberField(t - 1) sage: I = K.ideal(2) sage: K.S_units([I]) [2, -1] @@ -4772,24 +4797,23 @@ def _S_class_group_and_units(self, S, proof=True): INPUT: - - ``S`` - a tuple of prime ideals of self + - ``S`` -- a tuple of prime ideals of ``self`` - - ``proof`` - if False, assume the GRH in computing the class group + - ``proof`` -- if ``False``, assume the GRH in computing the class group OUTPUT: - - ``units, clgp_gens``, where: - - - ``units`` - A list of generators of the unit group. + - ``units`` -- A list of generators of the unit group. - - ``clgp_gens`` - A list of generators of the `S`-class group. + - ``clgp_gens`` -- A list of generators of the `S`-class group. Each generator is represented as a pair ``(gen, order)``, where ``gen`` is a fractional ideal of self and ``order`` is its order in the `S`-class group. EXAMPLES:: - sage: K.<a> = NumberField(x^2+5) + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField(x^2 + 5) sage: K._S_class_group_and_units(()) ([-1], [(Fractional ideal (2, a + 1), 2)]) @@ -4893,9 +4917,9 @@ def selmer_generators(self, S, m, proof=True, orders=False): - ``m`` -- a positive integer - - ``proof`` -- if False, assume the GRH in computing the class group + - ``proof`` -- if ``False``, assume the GRH in computing the class group - - ``orders`` (default False) -- if True, output two lists, the + - ``orders`` -- (default: ``False``) if ``True``, output two lists, the generators and their orders OUTPUT: @@ -4925,7 +4949,7 @@ def selmer_generators(self, S, m, proof=True, orders=False): :meth:`NumberField_generic.selmer_space`, which gives additional output when `m=p` is prime: as well as generators, - it gives an abstract vector space over `GF(p)` isomorphic to + it gives an abstract vector space over `\GF{p}` isomorphic to `K(S,p)` and maps implementing the isomorphism between this space and `K(S,p)` as a subgroup of `K^*/(K^*)^p`. @@ -4948,8 +4972,8 @@ def selmer_generators(self, S, m, proof=True, orders=False): When `m` is prime all the orders are equal to `m`, but in general they are only divisors of `m`:: sage: K.<a> = QuadraticField(-5) - sage: P2 = K.ideal(2, -a+1) - sage: P3 = K.ideal(3, a+1) + sage: P2 = K.ideal(2, -a + 1) + sage: P3 = K.ideal(3, a + 1) sage: K.selmer_generators((), 2, orders=True) ([-1, 2], [2, 2]) sage: K.selmer_generators((), 4, orders=True) @@ -4980,8 +5004,8 @@ def selmer_generators(self, S, m, proof=True, orders=False): TESTS:: sage: K.<a> = QuadraticField(-5) - sage: P2 = K.ideal(2, -a+1) - sage: P3 = K.ideal(3, a+1) + sage: P2 = K.ideal(2, -a + 1) + sage: P3 = K.ideal(3, a + 1) sage: P5 = K.ideal(a) sage: S = K.selmer_generators([P2, P3, P5], 3) sage: S in ([2, a + 1, a], [2, a + 1, -a], [2, -a - 1, a], [2, -a - 1, -a]) or S @@ -4990,6 +5014,7 @@ def selmer_generators(self, S, m, proof=True, orders=False): Verify that :trac:`14489` is fixed; the representation depends on the PARI version:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 - 381 * x + 127) sage: gens = K.selmer_generators(K.primes_above(13), 2) sage: len(gens) == 8 @@ -5060,9 +5085,6 @@ def selmer_generators(self, S, m, proof=True, orders=False): else: return gens - # For backwards compatibility: - selmer_group = deprecated_function_alias(31345, selmer_generators) - def selmer_group_iterator(self, S, m, proof=True): r""" Return an iterator through elements of the finite group `K(S,m)`. @@ -5073,7 +5095,7 @@ def selmer_group_iterator(self, S, m, proof=True): - ``m`` -- a positive integer - - ``proof`` -- if False, assume the GRH in computing the class group + - ``proof`` -- if ``False``, assume the GRH in computing the class group OUTPUT: @@ -5088,9 +5110,9 @@ def selmer_group_iterator(self, S, m, proof=True): [1, 2, -1, -2] sage: list(K.selmer_group_iterator((), 4)) [1, 4, -1, -4] - sage: list(K.selmer_group_iterator([K.ideal(2, -a+1)], 2)) + sage: list(K.selmer_group_iterator([K.ideal(2, -a + 1)], 2)) [1, -1, 2, -2] - sage: list(K.selmer_group_iterator([K.ideal(2, -a+1), K.ideal(3, a+1)], 2)) + sage: list(K.selmer_group_iterator([K.ideal(2, -a + 1), K.ideal(3, a + 1)], 2)) [1, -1, -a - 1, a + 1, 2, -2, -2*a - 2, 2*a + 2] Examples over `\QQ` (as a number field):: @@ -5154,8 +5176,8 @@ def selmer_space(self, S, p, proof=None): sage: K.<a> = QuadraticField(-5) sage: K.class_number() 2 - sage: P2 = K.ideal(2, -a+1) - sage: P3 = K.ideal(3, a+1) + sage: P2 = K.ideal(2, -a + 1) + sage: P3 = K.ideal(3, a + 1) sage: P5 = K.ideal(a) sage: KS2, gens, fromKS2, toKS2 = K.selmer_space([P2, P3, P5], 2) sage: KS2 @@ -5167,9 +5189,9 @@ def selmer_space(self, S, p, proof=None): sage: [K.ideal(g).factor() for g in gens] [(Fractional ideal (2, a + 1)) * (Fractional ideal (3, a + 1)), - Fractional ideal (a), - (Fractional ideal (2, a + 1))^2, - 1] + Fractional ideal (a), + (Fractional ideal (2, a + 1))^2, + 1] sage: toKS2(10) (0, 0, 1, 1) @@ -5197,11 +5219,12 @@ def selmer_space(self, S, p, proof=None): Vector space of dimension 2 over Finite Field of size 2 sage: gens [2, -1] + sage: x = polygen(ZZ, 'x') sage: for v in KS2: ....: if not v: ....: continue ....: a = fromKS2(v) - ....: print((a,K.extension(x^2-a, 'roota').relative_discriminant().factor())) + ....: print((a, K.extension(x^2 - a, 'roota').relative_discriminant().factor())) (2, (Fractional ideal (2, a + 1))^4) (-1, 1) (-2, (Fractional ideal (2, a + 1))^4) @@ -5260,6 +5283,7 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^4 - 2) sage: K.composite_fields(K) [Number Field in a with defining polynomial x^4 - 2, @@ -5269,6 +5293,7 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin into the compositum, if the fields are endowed with a real or complex embedding:: + sage: # needs sage.symbolic sage: K1 = NumberField(x^4 - 2, 'a', embedding=RR(2^(1/4))) sage: K2 = NumberField(x^4 - 2, 'a', embedding=RR(-2^(1/4))) sage: K1.composite_fields(K2) @@ -5281,16 +5306,17 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin With ``preserve_embedding`` set to ``False``, the embeddings are ignored:: - sage: K1.composite_fields(K2, preserve_embedding=False) + sage: K1.composite_fields(K2, preserve_embedding=False) # needs sage.symbolic [Number Field in a with defining polynomial x^4 - 2 with a = 1.189207115002722?, Number Field in a0 with defining polynomial x^8 + 28*x^4 + 2500] Changing the embedding selects a different compositum:: - sage: K3 = NumberField(x^4 - 2, 'a', embedding=CC(2^(1/4)*I)) - sage: [F, f, g, k], = K1.composite_fields(K3, both_maps=True); F - Number Field in a0 with defining polynomial x^8 + 28*x^4 + 2500 with a0 = -2.378414230005443? + 1.189207115002722?*I - sage: f(K1.0), g(K3.0) + sage: K3 = NumberField(x^4 - 2, 'a', embedding=CC(2^(1/4)*I)) # needs sage.symbolic + sage: [F, f, g, k], = K1.composite_fields(K3, both_maps=True); F # needs sage.symbolic + Number Field in a0 with defining polynomial x^8 + 28*x^4 + 2500 + with a0 = -2.378414230005443? + 1.189207115002722?*I + sage: f(K1.0), g(K3.0) # needs sage.symbolic (1/240*a0^5 - 41/120*a0, 1/120*a0^5 + 19/60*a0) If no embeddings are specified, the maps into the compositum @@ -5299,12 +5325,15 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin sage: Q1.<a> = NumberField(x^4 + 10*x^2 + 1) sage: Q2.<b> = NumberField(x^4 + 16*x^2 + 4) sage: Q1.composite_fields(Q2, 'c') - [Number Field in c with defining polynomial x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600] - sage: F, Q1_into_F, Q2_into_F, k = Q1.composite_fields(Q2, 'c', both_maps=True)[0] + [Number Field in c with defining polynomial + x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600] + sage: F, Q1_into_F, Q2_into_F, k = Q1.composite_fields(Q2, 'c', + ....: both_maps=True)[0] sage: Q1_into_F Ring morphism: From: Number Field in a with defining polynomial x^4 + 10*x^2 + 1 - To: Number Field in c with defining polynomial x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600 + To: Number Field in c with defining polynomial + x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600 Defn: a |--> 19/14400*c^7 + 137/1800*c^5 + 2599/3600*c^3 + 8/15*c This is just one of four embeddings of ``Q1`` into ``F``:: @@ -5318,7 +5347,8 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin sage: x = polygen(ZZ) sage: A.<a> = NumberField(x^3 - 7, embedding=CC(-0.95+1.65*I)) - sage: B.<a> = NumberField(x^9 - 7, embedding=QQbar.polynomial_root(x^9 - 7, RIF(1.2, 1.3))) + sage: r = QQbar.polynomial_root(x^9 - 7, RIF(1.2, 1.3)) + sage: B.<a> = NumberField(x^9 - 7, embedding=r) sage: len(A.composite_fields(B, preserve_embedding=True)) 2 @@ -5356,12 +5386,16 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin sage: L.<a, b> = NumberField([x^3 - 5, x^2 + 3]) sage: CyclotomicField(3, 'w').composite_fields(L, both_maps=True) - [(Number Field in a with defining polynomial x^3 - 5 over its base field, Ring morphism: - From: Cyclotomic Field of order 3 and degree 2 - To: Number Field in a with defining polynomial x^3 - 5 over its base field - Defn: w |--> -1/2*b - 1/2, Relative number field endomorphism of Number Field in a with defining polynomial x^3 - 5 over its base field - Defn: a |--> a - b |--> b, None)] + [(Number Field in a with defining polynomial x^3 - 5 over its base field, + Ring morphism: + From: Cyclotomic Field of order 3 and degree 2 + To: Number Field in a with defining polynomial x^3 - 5 over its base field + Defn: w |--> -1/2*b - 1/2, + Relative number field endomorphism of Number Field in a + with defining polynomial x^3 - 5 over its base field + Defn: a |--> a + b |--> b, + None)] Number fields defined by non-monic and non-integral polynomials are supported (:trac:`252`):: @@ -5411,7 +5445,7 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin Check that the bugs reported at :trac:`24357` are fixed:: sage: A.<a> = NumberField(x^9 - 7) - sage: B.<b> = NumberField(x^3-7, embedding=a^3) + sage: B.<b> = NumberField(x^3 - 7, embedding=a^3) sage: C.<c> = QuadraticField(-1) sage: B.composite_fields(C) [Number Field in bc with defining polynomial x^6 + 3*x^4 + 14*x^3 + 3*x^2 - 42*x + 50] @@ -5420,7 +5454,8 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin sage: A.<a> = NumberField(x^3 - 7, embedding=CC(-0.95+1.65*I)) sage: B.<b> = NumberField(y^9 - 7, embedding=CC(-1.16+0.42*I)) sage: A.composite_fields(B) - [Number Field in b with defining polynomial y^9 - 7 with b = -1.166502297945062? + 0.4245721146551276?*I] + [Number Field in b with defining polynomial y^9 - 7 + with b = -1.166502297945062? + 0.4245721146551276?*I] """ if not isinstance(other, NumberField_generic): raise TypeError("other must be a number field.") @@ -5588,10 +5623,11 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin def absolute_degree(self): r""" - Return the degree of self over `\QQ`. + Return the degree of ``self`` over `\QQ`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^3 + x^2 + 997*x + 1, 'a').absolute_degree() 3 sage: NumberField(x + 1, 'a').absolute_degree() @@ -5602,11 +5638,12 @@ def absolute_degree(self): return self.polynomial().degree() def degree(self): - """ + r""" Return the degree of this number field. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^3 + x^2 + 997*x + 1, 'a').degree() 3 sage: NumberField(x + 1, 'a').degree() @@ -5631,6 +5668,7 @@ def different(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: d = k.different() sage: d @@ -5664,8 +5702,8 @@ def different(self): def discriminant(self, v=None): """ Return the discriminant of the ring of integers of the number - field, or if v is specified, the determinant of the trace pairing - on the elements of the list v. + field, or if ``v`` is specified, the determinant of the trace pairing + on the elements of the list ``v``. INPUT: @@ -5673,10 +5711,11 @@ def discriminant(self, v=None): OUTPUT: - Integer if `v` is omitted, and Rational otherwise. + Integer if ``v`` is omitted, and Rational otherwise. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<t> = NumberField(x^3 + x^2 - 2*x + 8) sage: K.disc() -503 @@ -5700,10 +5739,11 @@ def discriminant(self, v=None): def disc(self, v=None): """ - Shortcut for self.discriminant. + Shortcut for :meth:`discriminant`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<b> = NumberField(x^2 - 123) sage: k.disc() 492 @@ -5716,6 +5756,7 @@ def trace_dual_basis(self, b): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 + x + 1) sage: b = [1, 2*a, 3*a^2] sage: T = K.trace_dual_basis(b); T @@ -5736,7 +5777,7 @@ def elements_of_norm(self, n, proof=None) -> list: INPUT: - - `n` -- integer + - ``n`` -- integer - ``proof`` -- boolean (default: ``True``, unless you called :meth:`proof.number_field` and set it otherwise) @@ -5748,7 +5789,8 @@ def elements_of_norm(self, n, proof=None) -> list: EXAMPLES:: - sage: K.<a> = NumberField(x^2+1) + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField(x^2 + 1) sage: K.elements_of_norm(3) [] sage: K.elements_of_norm(50) @@ -5776,6 +5818,7 @@ def extension(self, poly, name=None, names=None, latex_name=None, latex_names=No EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: R.<t> = K[] sage: L.<b> = K.extension(t^2 + a); L @@ -5789,7 +5832,7 @@ def extension(self, poly, name=None, names=None, latex_name=None, latex_names=No sage: m.<b> = k.extension(y^2 + 2); m Number Field in b with defining polynomial y^2 + 2 over its base field - Note that b is a root of `y^2 + 2`:: + Note that `b` is a root of `y^2 + 2`:: sage: b.minpoly() x^2 + 2 @@ -5836,6 +5879,7 @@ def factor(self, n): Here we show how to factor Gaussian integers (up to units). First we form a number field defined by `x^2 + 1`:: + sage: x = polygen(QQ, 'x') sage: K.<I> = NumberField(x^2 + 1); K Number Field in I with defining polynomial x^2 + 1 @@ -5864,7 +5908,8 @@ def factor(self, n): sage: K.factor(1+a) Fractional ideal (a + 1) sage: K.factor(1+a/5) - (Fractional ideal (a + 1)) * (Fractional ideal (-a - 2))^-1 * (Fractional ideal (2*a + 1))^-1 * (Fractional ideal (-2*a + 3)) + (Fractional ideal (a + 1)) * (Fractional ideal (-a - 2))^-1 + * (Fractional ideal (2*a + 1))^-1 * (Fractional ideal (-2*a + 3)) An example over a relative number field:: @@ -5876,7 +5921,7 @@ def factor(self, n): sage: f.value() == a+1 True - It doesn't make sense to factor the ideal (0), so this raises an error:: + It doesn't make sense to factor the ideal `(0)`, so this raises an error:: sage: L.factor(0) Traceback (most recent call last): @@ -5906,7 +5951,7 @@ def factor(self, n): def prime_factors(self, x): """ - Return a list of the prime ideals of self which divide + Return a list of the prime ideals of ``self`` which divide the ideal generated by `x`. OUTPUT: list of prime ideals (a new list is returned each time this @@ -5914,9 +5959,12 @@ def prime_factors(self, x): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<w> = NumberField(x^2 + 23) sage: K.prime_factors(w + 1) - [Fractional ideal (2, 1/2*w - 1/2), Fractional ideal (2, 1/2*w + 1/2), Fractional ideal (3, 1/2*w + 1/2)] + [Fractional ideal (2, 1/2*w - 1/2), + Fractional ideal (2, 1/2*w + 1/2), + Fractional ideal (3, 1/2*w + 1/2)] """ return self.ideal(x).prime_factors() @@ -5941,7 +5989,8 @@ def decomposition_type(self, p): EXAMPLES:: sage: R.<x> = ZZ[] - sage: K.<a> = NumberField(x^20 + 3*x^18 + 15*x^16 + 28*x^14 + 237*x^12 + 579*x^10 + 1114*x^8 + 1470*x^6 + 2304*x^4 + 1296*x^2 + 729) + sage: K.<a> = NumberField(x^20 + 3*x^18 + 15*x^16 + 28*x^14 + 237*x^12 + 579*x^10 + ....: + 1114*x^8 + 1470*x^6 + 2304*x^4 + 1296*x^2 + 729) sage: K.is_galois() True sage: K.discriminant().factor() @@ -5955,7 +6004,8 @@ def decomposition_type(self, p): This example is only ramified at 11:: - sage: K.<a> = NumberField(x^24 + 11^2*(90*x^12 - 640*x^8 + 2280*x^6 - 512*x^4 +2432/11*x^2 - 11)) + sage: K.<a> = NumberField(x^24 + 11^2*(90*x^12 - 640*x^8 + 2280*x^6 + ....: - 512*x^4 + 2432/11*x^2 - 11)) sage: K.discriminant().factor() -1 * 11^43 sage: K.decomposition_type(11) @@ -5976,7 +6026,8 @@ def decomposition_type(self, p): It also works for relative extensions:: sage: K.<a> = QuadraticField(-143) - sage: M.<c> = K.extension(x^10 - 6*x^8 + (a + 12)*x^6 + (-7/2*a - 89/2)*x^4 + (13/2*a - 77/2)*x^2 + 25) + sage: M.<c> = K.extension(x^10 - 6*x^8 + (a + 12)*x^6 + (-7/2*a - 89/2)*x^4 + ....: + (13/2*a - 77/2)*x^2 + 25) There is a unique prime above `11` and above `13` in `K`, each of which is unramified in `M`:: @@ -6027,12 +6078,13 @@ def gen(self, n=0): INPUT: - - ``n`` - must be 0 (the default), or an exception is + - ``n`` -- must be 0 (the default), or an exception is raised. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<theta> = NumberField(x^14 + 2); k Number Field in theta with defining polynomial x^14 + 2 sage: k.gen() @@ -6088,10 +6140,11 @@ def _generator_matrix(self): def is_field(self, proof=True): """ - Return True since a number field is a field. + Return ``True`` since a number field is a field. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^5 + x + 3, 'c').is_field() True """ @@ -6100,18 +6153,25 @@ def is_field(self, proof=True): @cached_method def is_galois(self): r""" - Return True if this number field is a Galois extension of + Return ``True`` if this number field is a Galois extension of `\QQ`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^2 + 1, 'i').is_galois() True sage: NumberField(x^3 + 2, 'a').is_galois() False - sage: NumberField(x^15 + x^14 - 14*x^13 - 13*x^12 + 78*x^11 + 66*x^10 - 220*x^9 - 165*x^8 + 330*x^7 + 210*x^6 - 252*x^5 - 126*x^4 + 84*x^3 + 28*x^2 - 8*x - 1, 'a').is_galois() + sage: K = NumberField(x^15 + x^14 - 14*x^13 - 13*x^12 + 78*x^11 + 66*x^10 + ....: - 220*x^9 - 165*x^8 + 330*x^7 + 210*x^6 - 252*x^5 + ....: - 126*x^4 + 84*x^3 + 28*x^2 - 8*x - 1, 'a') + sage: K.is_galois() True - sage: NumberField(x^15 + x^14 - 14*x^13 - 13*x^12 + 78*x^11 + 66*x^10 - 220*x^9 - 165*x^8 + 330*x^7 + 210*x^6 - 252*x^5 - 126*x^4 + 84*x^3 + 28*x^2 - 8*x - 10, 'a').is_galois() + sage: K = NumberField(x^15 + x^14 - 14*x^13 - 13*x^12 + 78*x^11 + 66*x^10 + ....: - 220*x^9 - 165*x^8 + 330*x^7 + 210*x^6 - 252*x^5 + ....: - 126*x^4 + 84*x^3 + 28*x^2 - 8*x - 10, 'a') + sage: K.is_galois() False """ return self.galois_group().is_galois() @@ -6119,11 +6179,12 @@ def is_galois(self): @cached_method def is_abelian(self): r""" - Return True if this number field is an abelian Galois extension of + Return ``True`` if this number field is an abelian Galois extension of `\QQ`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^2 + 1, 'i').is_abelian() True sage: NumberField(x^3 + 2, 'a').is_abelian() @@ -6156,23 +6217,23 @@ def galois_group(self, type=None, algorithm='pari', names=None, gc_numbering=Non INPUT: - - ``type`` - Deprecated; the different versions of Galois groups have been - merged in :trac:`28782`. + - ``type`` -- Deprecated; the different versions of Galois groups have been + merged in :trac:`28782`. - - ``algorithm`` - 'pari', 'gap', 'kash', 'magma'. (default: 'pari'; - for degrees between 12 and 15 default is 'gap', and - when the degree is >= 16 it is 'kash'.) + - ``algorithm`` -- ``'pari'``, ``'gap'``, ``'kash'``, ``'magma'``. (default: ``'pari'``; + for degrees between 12 and 15 default is ``'gap'``, and + when the degree is >= 16 it is ``'kash'``.) - - ``names`` - a string giving a name for the generator of the Galois - closure of self, when this field is not Galois. + - ``names`` -- a string giving a name for the generator of the Galois + closure of ``self``, when this field is not Galois. - - ``gc_numbering`` -- if ``True``, permutations will be written - in terms of the action on the roots of a defining polynomial - for the Galois closure, rather than the defining polynomial for - the original number field. This is significantly faster; - but not the standard way of presenting Galois groups. - The default currently depends on the algorithm (``True`` for ``'pari'``, - ``False`` for ``'magma'``) and may change in the future. + - ``gc_numbering`` -- if ``True``, permutations will be written + in terms of the action on the roots of a defining polynomial + for the Galois closure, rather than the defining polynomial for + the original number field. This is significantly faster; + but not the standard way of presenting Galois groups. + The default currently depends on the algorithm (``True`` for ``'pari'``, + ``False`` for ``'magma'``) and may change in the future. The resulting group will only compute with automorphisms when necessary, so certain functions (such as :meth:`sage.rings.number_field.galois_group.GaloisGroup_v2.order`) @@ -6183,7 +6244,8 @@ def galois_group(self, type=None, algorithm='pari', names=None, gc_numbering=Non EXAMPLES:: - sage: k.<b> = NumberField(x^2 - 14) # a Galois extension + sage: x = polygen(QQ, 'x') + sage: k.<b> = NumberField(x^2 - 14) # a Galois extension sage: G = k.galois_group(); G Galois group 2T1 (S2) with order 2 of x^2 - 14 sage: G.gen(0) @@ -6200,7 +6262,8 @@ def galois_group(self, type=None, algorithm='pari', names=None, gc_numbering=Non (1,2,3)(4,5,6) sage: NumberField(x^3 + 2*x + 1, 'a').galois_group(algorithm='magma') # optional - magma - Galois group Transitive group number 2 of degree 3 of the Number Field in a with defining polynomial x^3 + 2*x + 1 + Galois group Transitive group number 2 of degree 3 + of the Number Field in a with defining polynomial x^3 + 2*x + 1 EXPLICIT GALOIS GROUP: We compute the Galois group as an explicit group of automorphisms of the Galois closure of a field. @@ -6223,7 +6286,7 @@ def galois_group(self, type=None, algorithm='pari', names=None, gc_numbering=Non sage: G[2](b1) 1/12*b1^4 + 1/2*b1 - many examples for higher degrees may be found in the online databases + Many examples for higher degrees may be found in the online databases http://galoisdb.math.upb.de/ by Jรผrgen Klรผners and Gunter Malle and https://www.lmfdb.org/NumberField/ by the LMFDB collaboration, although these might need a lot of computing time. @@ -6235,9 +6298,10 @@ def galois_group(self, type=None, algorithm='pari', names=None, gc_numbering=Non sage: x = polygen(QQ) sage: K.<a> = NumberField(x^2 + 1) sage: R.<t> = PolynomialRing(K) - sage: L = K.extension(t^5-t+a, 'b') + sage: L = K.extension(t^5 - t + a, 'b') sage: L.galois_group() - ...DeprecationWarning: Use .absolute_field().galois_group() if you want the Galois group of the absolute field + ...DeprecationWarning: Use .absolute_field().galois_group() + if you want the Galois group of the absolute field See https://github.com/sagemath/sage/issues/28782 for details. Galois group 10T22 (S(5)[x]2) with order 240 of t^5 - t + a @@ -6245,7 +6309,7 @@ def galois_group(self, type=None, algorithm='pari', names=None, gc_numbering=Non We check that the changes in :trac:`28782` won't break code that used v1 Galois groups:: - sage: G = NumberField(x^3-2, 'a').galois_group(type="pari") + sage: G = NumberField(x^3 - 2, 'a').galois_group(type="pari") ...DeprecationWarning: the different Galois types have been merged into one class See https://github.com/sagemath/sage/issues/28782 for details. sage: G.group() @@ -6261,11 +6325,12 @@ def galois_group(self, type=None, algorithm='pari', names=None, gc_numbering=Non def _normalize_prime_list(self, v): """ - Internal function to convert into a tuple of primes either None or + Internal function to convert into a tuple of primes either ``None`` or a single prime or a list. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K._normalize_prime_list(None) () @@ -6300,6 +6365,7 @@ def power_basis(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^5 + 10*x + 1) sage: K.power_basis() [1, a, a^2, a^3, a^4] @@ -6323,16 +6389,17 @@ def power_basis(self): def integral_basis(self, v=None): """ - Return a list containing a ZZ-basis for the full ring of integers + Return a list containing a ``ZZ``-basis for the full ring of integers of this number field. INPUT: - - ``v`` - None, a prime, or a list of primes. See the - documentation for self.maximal_order. + - ``v`` -- ``None``, a prime, or a list of primes. See the + documentation for :meth:`maximal_order`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^5 + 10*x + 1) sage: K.integral_basis() [1, a, a^2, a^3, a^4] @@ -6347,7 +6414,7 @@ def integral_basis(self, v=None): sage: K.integral_basis() [1, 1/2*a^2 + 1/2*a, a^2] - ALGORITHM: Uses the pari library (via _pari_integral_basis). + ALGORITHM: Uses the PARI library (via :pari:`_pari_integral_basis`). """ return self.maximal_order(v=v).basis() @@ -6358,16 +6425,17 @@ def _pari_integral_basis(self, v=None, important=True): INPUT: - - ``v`` -- None, a prime, or a list of primes. See the - documentation for self.maximal_order. + - ``v`` -- ``None``, a prime, or a list of primes. See the + documentation for :meth:``maximal_order``. - ``important`` -- boolean (default: ``True``). If ``False``, - raise a ``RuntimeError`` if we need to do a difficult + raise a :class:`RuntimeError` if we need to do a difficult discriminant factorization. This is useful when an integral basis is not strictly required. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^5 + 10*x + 1) sage: K._pari_integral_basis() [1, y, y^2, y^3, y^4] @@ -6450,11 +6518,15 @@ def reduced_basis(self, prec=None): EXAMPLES:: - sage: F.<t> = NumberField(x^6-7*x^4-x^3+11*x^2+x-1) + sage: x = polygen(QQ, 'x') + sage: F.<t> = NumberField(x^6 - 7*x^4 - x^3 + 11*x^2 + x - 1) sage: F.maximal_order().basis() [1/2*t^5 + 1/2*t^4 + 1/2*t^2 + 1/2, t, t^2, t^3, t^4, t^5] sage: F.reduced_basis() - [-1, -1/2*t^5 + 1/2*t^4 + 3*t^3 - 3/2*t^2 - 4*t - 1/2, t, 1/2*t^5 + 1/2*t^4 - 4*t^3 - 5/2*t^2 + 7*t + 1/2, 1/2*t^5 - 1/2*t^4 - 2*t^3 + 3/2*t^2 - 1/2, 1/2*t^5 - 1/2*t^4 - 3*t^3 + 5/2*t^2 + 4*t - 5/2] + [-1, -1/2*t^5 + 1/2*t^4 + 3*t^3 - 3/2*t^2 - 4*t - 1/2, t, + 1/2*t^5 + 1/2*t^4 - 4*t^3 - 5/2*t^2 + 7*t + 1/2, + 1/2*t^5 - 1/2*t^4 - 2*t^3 + 3/2*t^2 - 1/2, + 1/2*t^5 - 1/2*t^4 - 3*t^3 + 5/2*t^2 + 4*t - 5/2] sage: CyclotomicField(12).reduced_basis() [1, zeta12^2, zeta12, zeta12^3] @@ -6504,9 +6576,9 @@ def reduced_gram_matrix(self, prec=None): to calculate the Minkowski embedding. (See NOTE below.) OUTPUT: The Gram matrix `[\langle x_i,x_j \rangle]` of an LLL reduced - basis for the maximal order of self, where the integral basis for - self is given by `\{x_0, \dots, x_{n-1}\}`. Here `\langle , \rangle` is - the usual inner product on `\RR^n`, and self is embedded in `\RR^n` by + basis for the maximal order of ``self``, where the integral basis for + ``self`` is given by `\{x_0, \dots, x_{n-1}\}`. Here `\langle , \rangle` is + the usual inner product on `\RR^n`, and ``self`` is embedded in `\RR^n` by the Minkowski embedding. See the docstring for :meth:`NumberField_absolute.minkowski_embedding` for more information. @@ -6517,16 +6589,17 @@ def reduced_gram_matrix(self, prec=None): approximations, and so the result is only as good as the precision promised by PARI. In particular, in this case, the returned matrix will *not* be integral, and may not - have enough precision to recover the correct gram matrix + have enough precision to recover the correct Gram matrix (which is known to be integral for theoretical - reasons). Thus the need for the prec flag above. + reasons). Thus the need for the ``prec`` parameter above. If the following run-time error occurs: "PariError: not a definite - matrix in lllgram (42)" try increasing the prec parameter, + matrix in lllgram (42)", try increasing the ``prec`` parameter, EXAMPLES:: - sage: F.<t> = NumberField(x^6-7*x^4-x^3+11*x^2+x-1) + sage: x = polygen(QQ, 'x') + sage: F.<t> = NumberField(x^6 - 7*x^4 - x^3 + 11*x^2 + x - 1) sage: F.reduced_gram_matrix() [ 6 3 0 2 0 1] [ 3 9 0 1 0 -2] @@ -6534,7 +6607,8 @@ def reduced_gram_matrix(self, prec=None): [ 2 1 6 16 -3 3] [ 0 0 -2 -3 16 6] [ 1 -2 3 3 6 19] - sage: Matrix(6, [(x*y).trace() for x in F.integral_basis() for y in F.integral_basis()]) + sage: Matrix(6, [(x*y).trace() + ....: for x in F.integral_basis() for y in F.integral_basis()]) [2550 133 259 664 1368 3421] [ 133 14 3 54 30 233] [ 259 3 54 30 233 217] @@ -6545,7 +6619,7 @@ def reduced_gram_matrix(self, prec=None): :: sage: x = polygen(QQ) - sage: F.<alpha> = NumberField(x^4+x^2+712312*x+131001238) + sage: F.<alpha> = NumberField(x^4 + x^2 + 712312*x + 131001238) sage: F.reduced_gram_matrix(prec=128) [ 4.0000000000000000000000000000000000000 0.00000000000000000000000000000000000000 -1.9999999999999999999999999999999999037 -0.99999999999999999999999999999999383702] [ 0.00000000000000000000000000000000000000 46721.539331563218381658483353092335550 -11488.910026551724275122749703614966768 -418.12718083977141198754424579680468382] @@ -6593,21 +6667,21 @@ def reduced_gram_matrix(self, prec=None): def _positive_integral_elements_with_trace(self, C): r""" - Find all totally positive integral elements in self whose + Find all totally positive integral elements in ``self`` whose trace is between C[0] and C[1], inclusive. .. note:: - This is currently only implemented in the case that self is + This is currently only implemented in the case that ``self`` is totally real, since it requires exact computation of :meth:`.reduced_gram_matrix`. EXAMPLES:: - sage: K.<alpha> = NumberField(ZZ['x'].0^2-2) + sage: K.<alpha> = NumberField(ZZ['x'].0^2 - 2) sage: K._positive_integral_elements_with_trace([0,5]) [alpha + 2, -alpha + 2, 2, 1] - sage: L.<beta> = NumberField(ZZ['x'].0^2+1) + sage: L.<beta> = NumberField(ZZ['x'].0^2 + 1) sage: L._positive_integral_elements_with_trace([5,11]) Traceback (most recent call last): ... @@ -6644,12 +6718,13 @@ def narrow_class_group(self, proof=None): INPUT: - - ``proof`` - default: ``None`` (use the global proof + - ``proof`` -- default: ``None`` (use the global proof setting, which defaults to ``True``). EXAMPLES:: - sage: NumberField(x^3+x+9, 'a').narrow_class_group() + sage: x = polygen(QQ, 'x') + sage: NumberField(x^3 + x + 9, 'a').narrow_class_group() Multiplicative Abelian group isomorphic to C2 TESTS:: @@ -6670,6 +6745,7 @@ def ngens(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^2 + 17,'a').ngens() 1 sage: NumberField(x + 3,'a').ngens() @@ -6690,6 +6766,7 @@ def order(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^2 + 19,'a').order() +Infinity """ @@ -6701,13 +6778,14 @@ def absolute_polynomial_ntl(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^2 + (2/3)*x - 9/17,'a').absolute_polynomial_ntl() ([-27 34 51], 51) """ return self.polynomial_ntl() def polynomial_ntl(self): - """ + r""" Return defining polynomial of this number field as a pair, an ntl polynomial and a denominator. @@ -6715,6 +6793,7 @@ def polynomial_ntl(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^2 + (2/3)*x - 9/17,'a').polynomial_ntl() ([-27 34 51], 51) """ @@ -6728,31 +6807,31 @@ def polynomial_ntl(self): return (self.__polynomial_ntl, self.__denominator_ntl) def polynomial(self): - """ + r""" Return the defining polynomial of this number field. - This is exactly the same as - ``self.defining_polynomial()``. + This is exactly the same as :meth:`defining_polynomial`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: NumberField(x^2 + (2/3)*x - 9/17,'a').polynomial() x^2 + 2/3*x - 9/17 """ return self.__polynomial def defining_polynomial(self): # do not overload this -- overload polynomial instead - """ + r""" Return the defining polynomial of this number field. - This is exactly the same as ``self.polynomial()``. + This is exactly the same as :meth:`polynomial`. EXAMPLES:: sage: k5.<z> = CyclotomicField(5) sage: k5.defining_polynomial() x^4 + x^3 + x^2 + x + 1 - sage: y = polygen(QQ,'y') + sage: y = polygen(QQ, 'y') sage: k.<a> = NumberField(y^9 - 3*y + 5); k Number Field in a with defining polynomial y^9 - 3*y + 5 sage: k.defining_polynomial() @@ -6761,12 +6840,13 @@ def defining_polynomial(self): # do not overload this -- overload polynomial i return self.polynomial() def polynomial_ring(self): - """ + r""" Return the polynomial ring that we view this number field as being a quotient of (by a principal ideal). EXAMPLES: An example with an absolute field:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^2 + 3) sage: y = polygen(QQ, 'y') sage: k.<a> = NumberField(y^2 + 3) @@ -6779,25 +6859,28 @@ def polynomial_ring(self): sage: M.<a> = NumberField([y^3 + 97, y^2 + 1]); M Number Field in a0 with defining polynomial y^3 + 97 over its base field sage: M.polynomial_ring() - Univariate Polynomial Ring in y over Number Field in a1 with defining polynomial y^2 + 1 + Univariate Polynomial Ring in y over + Number Field in a1 with defining polynomial y^2 + 1 """ return self.relative_polynomial().parent() def polynomial_quotient_ring(self): - """ + r""" Return the polynomial quotient ring isomorphic to this number field. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K = NumberField(x^3 + 2*x - 5, 'alpha') sage: K.polynomial_quotient_ring() - Univariate Quotient Polynomial Ring in alpha over Rational Field with modulus x^3 + 2*x - 5 + Univariate Quotient Polynomial Ring in alpha over Rational Field + with modulus x^3 + 2*x - 5 """ return self.polynomial_ring().quotient(self.relative_polynomial(), self.variable_name()) def regulator(self, proof=None): - """ + r""" Return the regulator of this number field. Note that PARI computes the regulator to higher precision than the @@ -6805,13 +6888,14 @@ def regulator(self, proof=None): INPUT: - - ``proof`` - default: ``True``, unless you set it otherwise. + - ``proof`` -- default: ``True``, unless you set it otherwise. EXAMPLES:: - sage: NumberField(x^2-2, 'a').regulator() + sage: x = polygen(QQ, 'x') + sage: NumberField(x^2 - 2, 'a').regulator() 0.881373587019543 - sage: NumberField(x^4+x^3+x^2+x+1, 'a').regulator() + sage: NumberField(x^4 + x^3 + x^2 + x + 1, 'a').regulator() 0.962423650119207 """ proof = proof_flag(proof) @@ -6824,30 +6908,27 @@ def regulator(self, proof=None): return self.__regulator def residue_field(self, prime, names=None, check=True): - """ + r""" Return the residue field of this number field at a given prime, ie `O_K / p O_K`. INPUT: + - ``prime`` -- a prime ideal of the maximal order in + this number field, or an element of the field which generates a + principal prime ideal. - - ``prime`` - a prime ideal of the maximal order in - this number field, or an element of the field which generates a - principal prime ideal. - - - ``names`` - the name of the variable in the residue - field - - - ``check`` - whether or not to check the primality of - prime. + - ``names`` -- the name of the variable in the residue + field + - ``check`` -- whether or not to check the primality of ``prime``. OUTPUT: The residue field at this prime. EXAMPLES:: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) sage: P = K.ideal(61).factor()[0][0] sage: K.residue_field(P) Residue field in abar of Fractional ideal (61, a^2 + 30) @@ -6894,29 +6975,31 @@ def residue_field(self, prime, names=None, check=True): return ResidueField(prime, names=names, check=False) def signature(self): - """ - Return (r1, r2), where r1 and r2 are the number of real embeddings + r""" + Return `(r_1, r_2)`, where `r_1` and `r_2` are the number of real embeddings and pairs of complex embeddings of this field, respectively. EXAMPLES:: - sage: NumberField(x^2+1, 'a').signature() + sage: x = polygen(QQ, 'x') + sage: NumberField(x^2 + 1, 'a').signature() (0, 1) - sage: NumberField(x^3-2, 'a').signature() + sage: NumberField(x^3 - 2, 'a').signature() (1, 1) """ r1, r2 = self.pari_nf().nf_get_sign() return (ZZ(r1), ZZ(r2)) def trace_pairing(self, v): - """ + r""" Return the matrix of the trace pairing on the elements of the list - `v`. + ``v``. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<zeta3> = NumberField(x^2 + 3) - sage: K.trace_pairing([1,zeta3]) + sage: K.trace_pairing([1, zeta3]) [ 2 0] [ 0 -6] """ @@ -6931,31 +7014,32 @@ def trace_pairing(self, v): def uniformizer(self, P, others="positive"): """ - Return an element of self with valuation 1 at the prime ideal P. + Return an element of ``self`` with valuation 1 at the prime ideal `P`. INPUT: - - ``self`` - a number field + - ``self`` -- a number field - - ``P`` - a prime ideal of self + - ``P`` -- a prime ideal of ``self`` - - ``others`` - either "positive" (default), in which + - ``others`` -- either ``"positive"`` (default), in which case the element will have non-negative valuation at all other - primes of self, or "negative", in which case the element will have - non-positive valuation at all other primes of self. + primes of ``self``, or ``"negative"``, in which case the element will have + non-positive valuation at all other primes of ``self``. .. note:: - When P is principal (e.g. always when self has class number - one) the result may or may not be a generator of P! + When `P` is principal (e.g., always when ``self`` has class number + one) the result may or may not be a generator of `P`! EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 + 5); K Number Field in a with defining polynomial x^2 + 5 - sage: P,Q = K.ideal(3).prime_factors() + sage: P, Q = K.ideal(3).prime_factors() sage: P Fractional ideal (3, a + 1) sage: pi = K.uniformizer(P); pi @@ -6970,11 +7054,11 @@ def uniformizer(self, P, others="positive"): :: sage: K = CyclotomicField(9) - sage: Plist=K.ideal(17).prime_factors() + sage: Plist = K.ideal(17).prime_factors() sage: pilist = [K.uniformizer(P) for P in Plist] sage: [pi.is_integral() for pi in pilist] [True, True, True] - sage: [pi.valuation(P) for pi,P in zip(pilist,Plist)] + sage: [pi.valuation(P) for pi, P in zip(pilist, Plist)] [1, 1, 1] sage: [ pilist[i] in Plist[i] for i in range(len(Plist)) ] [True, True, True] @@ -6997,7 +7081,7 @@ def uniformizer(self, P, others="positive"): Use PARI. More precisely, use the second component of :pari:`idealprimedec` in the "positive" case. Use :pari:`idealappr` - with exponent of -1 and invert the result in the "negative" + with exponent of `-1` and invert the result in the "negative" case. TESTS: @@ -7029,11 +7113,11 @@ def units(self, proof=None): INPUT: - - ``proof`` (bool, default True) flag passed to ``pari``. + - ``proof`` (bool, default ``True``) flag passed to PARI. .. note:: - For more functionality see the unit_group() function. + For more functionality see :meth:`unit_group`. .. SEEALSO:: @@ -7111,7 +7195,7 @@ def unit_group(self, proof=None): INPUT: - - ``proof`` (bool, default True) flag passed to ``pari``. + - ``proof`` (bool, default ``True``) flag passed to PARI. .. note:: @@ -7129,7 +7213,8 @@ def unit_group(self, proof=None): sage: A = x^4 - 10*x^3 + 20*5*x^2 - 15*5^2*x + 11*5^3 sage: K = NumberField(A, 'a') sage: U = K.unit_group(); U - Unit group with structure C10 x Z of Number Field in a with defining polynomial x^4 - 10*x^3 + 100*x^2 - 375*x + 1375 + Unit group with structure C10 x Z of Number Field in a + with defining polynomial x^4 - 10*x^3 + 100*x^2 - 375*x + 1375 sage: U.gens() (u0, u1) sage: U.gens_values() # random @@ -7149,11 +7234,20 @@ def unit_group(self, proof=None): ... sage: U = K.unit_group(proof=False) sage: U - Unit group with structure C2 x Z x Z x Z x Z x Z x Z x Z x Z of Number Field in a with defining polynomial x^17 + 3 + Unit group with structure C2 x Z x Z x Z x Z x Z x Z x Z x Z of + Number Field in a with defining polynomial x^17 + 3 sage: U.gens() (u0, u1, u2, u3, u4, u5, u6, u7, u8) sage: U.gens_values() # result not independently verified - [-1, -a^9 - a + 1, -a^16 + a^15 - a^14 + a^12 - a^11 + a^10 + a^8 - a^7 + 2*a^6 - a^4 + 3*a^3 - 2*a^2 + 2*a - 1, 2*a^16 - a^14 - a^13 + 3*a^12 - 2*a^10 + a^9 + 3*a^8 - 3*a^6 + 3*a^5 + 3*a^4 - 2*a^3 - 2*a^2 + 3*a + 4, a^15 + a^14 + 2*a^11 + a^10 - a^9 + a^8 + 2*a^7 - a^5 + 2*a^3 - a^2 - 3*a + 1, -a^16 - a^15 - a^14 - a^13 - a^12 - a^11 - a^10 - a^9 - a^8 - a^7 - a^6 - a^5 - a^4 - a^3 - a^2 + 2, -2*a^16 + 3*a^15 - 3*a^14 + 3*a^13 - 3*a^12 + a^11 - a^9 + 3*a^8 - 4*a^7 + 5*a^6 - 6*a^5 + 4*a^4 - 3*a^3 + 2*a^2 + 2*a - 4, a^15 - a^12 + a^10 - a^9 - 2*a^8 + 3*a^7 + a^6 - 3*a^5 + a^4 + 4*a^3 - 3*a^2 - 2*a + 2, 2*a^16 + a^15 - a^11 - 3*a^10 - 4*a^9 - 4*a^8 - 4*a^7 - 5*a^6 - 7*a^5 - 8*a^4 - 6*a^3 - 5*a^2 - 6*a - 7] + [-1, + -a^9 - a + 1, + -a^16 + a^15 - a^14 + a^12 - a^11 + a^10 + a^8 - a^7 + 2*a^6 - a^4 + 3*a^3 - 2*a^2 + 2*a - 1, + 2*a^16 - a^14 - a^13 + 3*a^12 - 2*a^10 + a^9 + 3*a^8 - 3*a^6 + 3*a^5 + 3*a^4 - 2*a^3 - 2*a^2 + 3*a + 4, + a^15 + a^14 + 2*a^11 + a^10 - a^9 + a^8 + 2*a^7 - a^5 + 2*a^3 - a^2 - 3*a + 1, + -a^16 - a^15 - a^14 - a^13 - a^12 - a^11 - a^10 - a^9 - a^8 - a^7 - a^6 - a^5 - a^4 - a^3 - a^2 + 2, + -2*a^16 + 3*a^15 - 3*a^14 + 3*a^13 - 3*a^12 + a^11 - a^9 + 3*a^8 - 4*a^7 + 5*a^6 - 6*a^5 + 4*a^4 - 3*a^3 + 2*a^2 + 2*a - 4, + a^15 - a^12 + a^10 - a^9 - 2*a^8 + 3*a^7 + a^6 - 3*a^5 + a^4 + 4*a^3 - 3*a^2 - 2*a + 2, + 2*a^16 + a^15 - a^11 - 3*a^10 - 4*a^9 - 4*a^8 - 4*a^7 - 5*a^6 - 7*a^5 - 8*a^4 - 6*a^3 - 5*a^2 - 6*a - 7] """ proof = proof_flag(proof) @@ -7177,18 +7271,18 @@ def unit_group(self, proof=None): def S_unit_group(self, proof=None, S=None): """ - Return the S-unit group (including torsion) of this number field. + Return the `S`-unit group (including torsion) of this number field. ALGORITHM: Uses PARI's :pari:`bnfsunit` command. INPUT: - - ``proof`` (bool, default True) flag passed to ``pari``. + - ``proof`` -- bool (default: ``True``); flag passed to PARI - - ``S`` - list or tuple of prime ideals, or an ideal, or a single + - ``S`` -- list or tuple of prime ideals, or an ideal, or a single ideal or element from which an ideal can be constructed, in - which case the support is used. If None, the global unit - group is constructed; otherwise, the S-unit group is + which case the support is used. If ``None``, the global unit + group is constructed; otherwise, the `S`-unit group is constructed. .. note:: @@ -7200,17 +7294,22 @@ def S_unit_group(self, proof=None, S=None): sage: x = polygen(QQ) sage: K.<a> = NumberField(x^4 - 10*x^3 + 20*5*x^2 - 15*5^2*x + 11*5^3) sage: U = K.S_unit_group(S=a); U - S-unit group with structure C10 x Z x Z x Z of Number Field in a with defining polynomial x^4 - 10*x^3 + 100*x^2 - 375*x + 1375 with S = (Fractional ideal (5, 1/275*a^3 + 4/55*a^2 - 5/11*a + 5), Fractional ideal (11, 1/275*a^3 + 4/55*a^2 - 5/11*a + 9)) + S-unit group with structure C10 x Z x Z x Z of + Number Field in a with defining polynomial x^4 - 10*x^3 + 100*x^2 - 375*x + 1375 + with S = (Fractional ideal (5, 1/275*a^3 + 4/55*a^2 - 5/11*a + 5), + Fractional ideal (11, 1/275*a^3 + 4/55*a^2 - 5/11*a + 9)) sage: U.gens() (u0, u1, u2, u3) sage: U.gens_values() # random - [-1/275*a^3 + 7/55*a^2 - 6/11*a + 4, 1/275*a^3 + 4/55*a^2 - 5/11*a + 3, 1/275*a^3 + 4/55*a^2 - 5/11*a + 5, -14/275*a^3 + 21/55*a^2 - 29/11*a + 6] + [-1/275*a^3 + 7/55*a^2 - 6/11*a + 4, 1/275*a^3 + 4/55*a^2 - 5/11*a + 3, + 1/275*a^3 + 4/55*a^2 - 5/11*a + 5, -14/275*a^3 + 21/55*a^2 - 29/11*a + 6] sage: U.invariants() (10, 0, 0, 0) sage: [u.multiplicative_order() for u in U.gens()] [10, +Infinity, +Infinity, +Infinity] sage: U.primes() - (Fractional ideal (5, 1/275*a^3 + 4/55*a^2 - 5/11*a + 5), Fractional ideal (11, 1/275*a^3 + 4/55*a^2 - 5/11*a + 9)) + (Fractional ideal (5, 1/275*a^3 + 4/55*a^2 - 5/11*a + 5), + Fractional ideal (11, 1/275*a^3 + 4/55*a^2 - 5/11*a + 9)) With the default value of `S`, the S-unit group is the same as the global unit group:: @@ -7226,20 +7325,29 @@ def S_unit_group(self, proof=None, S=None): sage: K.<a> = NumberField(x^3 + 3) sage: U = K.S_unit_group(proof=False, S=K.ideal(6).prime_factors()); U - S-unit group with structure C2 x Z x Z x Z x Z of Number Field in a with defining polynomial x^3 + 3 with S = (Fractional ideal (-a^2 + a - 1), Fractional ideal (a + 1), Fractional ideal (a)) + S-unit group with structure C2 x Z x Z x Z x Z + of Number Field in a with defining polynomial x^3 + 3 + with S = (Fractional ideal (-a^2 + a - 1), + Fractional ideal (a + 1), + Fractional ideal (a)) sage: K.<a> = NumberField(x^3 + 3) sage: U = K.S_unit_group(proof=False, S=K.ideal(6)); U - S-unit group with structure C2 x Z x Z x Z x Z of Number Field in a with defining polynomial x^3 + 3 with S = (Fractional ideal (-a^2 + a - 1), Fractional ideal (a + 1), Fractional ideal (a)) + S-unit group with structure C2 x Z x Z x Z x Z + of Number Field in a with defining polynomial x^3 + 3 + with S = (Fractional ideal (-a^2 + a - 1), + Fractional ideal (a + 1), + Fractional ideal (a)) sage: K.<a> = NumberField(x^3 + 3) sage: U = K.S_unit_group(proof=False, S=6); U - S-unit group with structure C2 x Z x Z x Z x Z of Number Field in a with defining polynomial x^3 + 3 with S = (Fractional ideal (-a^2 + a - 1), Fractional ideal (a + 1), Fractional ideal (a)) - - sage: U - S-unit group with structure C2 x Z x Z x Z x Z of Number Field in a with defining polynomial x^3 + 3 with S = (Fractional ideal (-a^2 + a - 1), Fractional ideal (a + 1), Fractional ideal (a)) + S-unit group with structure C2 x Z x Z x Z x Z + of Number Field in a with defining polynomial x^3 + 3 + with S = (Fractional ideal (-a^2 + a - 1), + Fractional ideal (a + 1), + Fractional ideal (a)) sage: U.primes() (Fractional ideal (-a^2 + a - 1), - Fractional ideal (a + 1), - Fractional ideal (a)) + Fractional ideal (a + 1), + Fractional ideal (a)) sage: U.gens() (u0, u1, u2, u3, u4) sage: U.gens_values() @@ -7303,7 +7411,7 @@ def S_unit_group(self, proof=None, S=None): def S_unit_solutions(self, S=[], prec=106, include_exponents=False, include_bound=False, proof=None): r""" - Return all solutions to the S-unit equation ``x + y = 1`` over K. + Return all solutions to the `S`-unit equation `x + y = 1` over ``self``. INPUT: @@ -7315,19 +7423,25 @@ def S_unit_solutions(self, S=[], prec=106, include_exponents=False, include_boun OUTPUT: - A list of tuples ``[( A_1, B_1, x_1, y_1), (A_2, B_2, x_2, y_2), ... ( A_n, B_n, x_n, y_n)]`` such that: + A list `[(A_1, B_1, x_1, y_1), (A_2, B_2, x_2, y_2), \dots, (A_n, B_n, x_n, y_n)]` of tuples such that: + + 1. The first two entries are tuples `A_i = (a_0, a_1, \dots, a_t)` and `B_i = (b_0, b_1, \dots, b_t)` of exponents. + These will be omitted if ``include_exponents`` is ``False``. - 1. The first two entries are tuples ``A_i = (a_0, a_1, ... , a_t)`` and ``B_i = (b_0, b_1, ... , b_t)`` of exponents. These will be omitted if ``include_exponents`` is ``False``. - 2. The last two entries are ``S``-units ``x_i`` and ``y_i`` in ``K`` with ``x_i + y_i = 1``. - 3. If the default generators for the ``S``-units of ``K`` are ``(rho_0, rho_1, ... , rho_t)``, then these satisfy ``x_i = \prod(rho_i)^(a_i)`` and ``y_i = \prod(rho_i)^(b_i)``. + 2. The last two entries are `S`-units `x_i` and `y_i` in ``self`` with `x_i + y_i = 1`. - If ``include_bound``, will return a pair ``(sols, bound)`` where ``sols`` is as above and ``bound`` is the bound used for the entries in the exponent vectors. + 3. If the default generators for the `S`-units of ``self`` are `(\rho_0, \rho_1, \dots, \rho_t)``, + then these satisfy `x_i = \prod(\rho_i)^{(a_i)}` and `y_i = \prod(\rho_i)^{(b_i)}`. + + If ``include_bound`` is ``True``, will return a pair ``(sols, bound)`` where ``sols`` is as above + and ``bound`` is the bound used for the entries in the exponent vectors. EXAMPLES:: - sage: K.<xi> = NumberField(x^2+x+1) + sage: x = polygen(QQ, 'x') + sage: K.<xi> = NumberField(x^2 + x + 1) sage: S = K.primes_above(3) - sage: K.S_unit_solutions(S) # random, due to ordering + sage: K.S_unit_solutions(S) # random, due to ordering [(xi + 2, -xi - 1), (1/3*xi + 2/3, -1/3*xi + 1/3), (-xi, xi + 1), (-xi + 1, xi)] You can get the exponent vectors:: @@ -7349,14 +7463,14 @@ def S_unit_solutions(self, S=[], prec=106, include_exponents=False, include_boun def zeta(self, n=2, all=False): """ - Return one, or a list of all, primitive n-th root of unity in this field. + Return one, or a list of all, primitive `n`-th root of unity in this field. INPUT: - - ``n`` -- positive integer + - ``n`` -- positive integer - ``all`` -- boolean. If ``False`` (default), return a primitive - `n`-th root of unity in this field, or raise a ``ValueError`` + `n`-th root of unity in this field, or raise a :class:`ValueError` exception if there are none. If ``True``, return a list of all primitive `n`-th roots of unity in this field (possibly empty). @@ -7373,6 +7487,7 @@ def zeta(self, n=2, all=False): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<z> = NumberField(x^2 + 3) sage: K.zeta(1) 1 @@ -7392,7 +7507,7 @@ def zeta(self, n=2, all=False): :: sage: r.<x> = QQ[] - sage: K.<b> = NumberField(x^2+1) + sage: K.<b> = NumberField(x^2 + 1) sage: K.zeta(4) b sage: K.zeta(4,all=True) @@ -7401,7 +7516,7 @@ def zeta(self, n=2, all=False): Traceback (most recent call last): ... ValueError: there are no 3rd roots of unity in self - sage: K.zeta(3,all=True) + sage: K.zeta(3, all=True) [] Number fields defined by non-monic and non-integral @@ -7465,10 +7580,11 @@ def zeta_order(self): EXAMPLES:: - sage: F.<alpha> = NumberField(x**22+3) + sage: x = polygen(QQ, 'x') + sage: F.<alpha> = NumberField(x^22 + 3) sage: F.zeta_order() 6 - sage: F.<alpha> = NumberField(x**2-7) + sage: F.<alpha> = NumberField(x^2 - 7) sage: F.zeta_order() 2 @@ -7510,13 +7626,14 @@ def primitive_root_of_unity(self): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) + sage: x = polygen(QQ, 'x') + sage: K.<i> = NumberField(x^2 + 1) sage: z = K.primitive_root_of_unity(); z i sage: z.multiplicative_order() 4 - sage: K.<a> = NumberField(x^2+x+1) + sage: K.<a> = NumberField(x^2 + x + 1) sage: z = K.primitive_root_of_unity(); z a + 1 sage: z.multiplicative_order() @@ -7581,10 +7698,11 @@ def roots_of_unity(self): EXAMPLES:: - sage: K.<b> = NumberField(x^2+1) + sage: x = polygen(QQ, 'x') + sage: K.<b> = NumberField(x^2 + 1) sage: zs = K.roots_of_unity(); zs [b, -1, -b, 1] - sage: [ z**K.number_of_roots_of_unity() for z in zs ] + sage: [z**K.number_of_roots_of_unity() for z in zs] [1, 1, 1, 1] """ z = self.primitive_root_of_unity() @@ -7593,13 +7711,13 @@ def roots_of_unity(self): def zeta_coefficients(self, n): """ - Compute the first n coefficients of the Dedekind zeta function of + Compute the first `n` coefficients of the Dedekind zeta function of this field as a Dirichlet series. EXAMPLES:: sage: x = QQ['x'].0 - sage: NumberField(x^2+1, 'a').zeta_coefficients(10) + sage: NumberField(x^2 + 1, 'a').zeta_coefficients(10) [1, 1, 0, 1, 2, 0, 0, 1, 1, 2] """ return self.pari_nf().dirzetak(n) @@ -7614,11 +7732,11 @@ def solve_CRT(self, reslist, Ilist, check=True): - ``Ilist`` -- a list of integral ideals, assumed pairwise coprime - - ``check`` (boolean, default True) -- if True, result is checked + - ``check`` -- (boolean, default ``True``) if ``True``, result is checked OUTPUT: - An integral element x such that x-reslist[i] is in Ilist[i] for all i. + An integral element `x` such that ``x - reslist[i]`` is in ``Ilist[i]`` for all `i`. .. note:: @@ -7627,17 +7745,18 @@ def solve_CRT(self, reslist, Ilist, check=True): EXAMPLES:: - sage: K.<a> = NumberField(x^2-10) + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: Ilist = [K.primes_above(p)[0] for p in prime_range(10)] - sage: b = K.solve_CRT([1,2,3,4],Ilist,True) - sage: all(b-i-1 in Ilist[i] for i in range(4)) + sage: b = K.solve_CRT([1,2,3,4], Ilist, True) + sage: all(b - i - 1 in Ilist[i] for i in range(4)) True sage: Ilist = [K.ideal(a), K.ideal(2)] - sage: K.solve_CRT([0,1],Ilist,True) + sage: K.solve_CRT([0,1], Ilist, True) Traceback (most recent call last): ... ArithmeticError: ideals in solve_CRT() must be pairwise coprime - sage: Ilist[0]+Ilist[1] + sage: Ilist[0] + Ilist[1] Fractional ideal (2, a) """ n = len(reslist) @@ -7676,6 +7795,7 @@ def valuation(self, prime): The valuation can be specified with an integer ``prime`` that is completely ramified in ``R``:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 + 1) sage: K.valuation(2) 2-adic valuation @@ -7690,7 +7810,8 @@ def valuation(self, prime): sage: K.valuation(5) Traceback (most recent call last): ... - ValueError: The valuation Gauss valuation induced by 5-adic valuation does not approximate a unique extension of 5-adic valuation with respect to x^2 + 1 + ValueError: The valuation Gauss valuation induced by 5-adic valuation does not + approximate a unique extension of 5-adic valuation with respect to x^2 + 1 The valuation can also be selected by giving a valuation on the base ring that extends uniquely:: @@ -7703,7 +7824,8 @@ def valuation(self, prime): sage: K.valuation(ZZ.valuation(5)) Traceback (most recent call last): ... - ValueError: The valuation Gauss valuation induced by 5-adic valuation does not approximate a unique extension of 5-adic valuation with respect to x^2 + 1 + ValueError: The valuation Gauss valuation induced by 5-adic valuation does not + approximate a unique extension of 5-adic valuation with respect to x^2 + 1 For a number field which is of the form `K[x]/(G)`, you can specify a valuation by providing a discrete pseudo-valuation on `K[x]` which sends @@ -7711,15 +7833,16 @@ def valuation(self, prime): valuation we care about in the above example:: sage: R.<x> = QQ[] - sage: v = K.valuation(GaussValuation(R, QQ.valuation(5)).augmentation(x + 2, infinity)) - sage: w = K.valuation(GaussValuation(R, QQ.valuation(5)).augmentation(x + 1/2, infinity)) + sage: G5 = GaussValuation(R, QQ.valuation(5)) + sage: v = K.valuation(G5.augmentation(x + 2, infinity)) + sage: w = K.valuation(G5.augmentation(x + 1/2, infinity)) sage: v == w False Note that you get the same valuation, even if you write down the pseudo-valuation differently:: - sage: ww = K.valuation(GaussValuation(R, QQ.valuation(5)).augmentation(x + 3, infinity)) + sage: ww = K.valuation(G5.augmentation(x + 3, infinity)) sage: w is ww True @@ -7729,7 +7852,7 @@ def valuation(self, prime): completion, i.e., if it is not possible to write down one of the factors within the number field:: - sage: v = GaussValuation(R, QQ.valuation(5)).augmentation(x + 3, 1) + sage: v = G5.augmentation(x + 3, 1) sage: K.valuation(v) [ 5-adic valuation, v(x + 3) = 1 ]-adic valuation @@ -7823,36 +7946,37 @@ def maximal_order(self, v=None, assume_maximal='non-maximal-non-unique'): INPUT: - - ``v`` - ``None``, a prime, or a list of integer primes (default: ``None``) + - ``v`` -- ``None``, a prime, or a list of integer primes (default: ``None``) - - if ``None``, return the maximal order. + - if ``None``, return the maximal order. - - if a prime `p`, return an order that is `p`-maximal. + - if a prime `p`, return an order that is `p`-maximal. - - if a list, return an order that is maximal at each prime of these primes + - if a list, return an order that is maximal at each prime of these primes - - ``assume_maximal`` - ``True``, ``False``, ``None``, or + - ``assume_maximal`` -- ``True``, ``False``, ``None``, or ``"non-maximal-non-unique"`` (default: ``"non-maximal-non-unique"``) ignored when ``v`` is ``None``; otherwise, controls whether we assume that the order :meth:`order.is_maximal` outside of ``v``. - - if ``True``, the order is assumed to be maximal at all primes. + - if ``True``, the order is assumed to be maximal at all primes. - - if ``False``, the order is assumed to be non-maximal at some prime - not in ``v``. + - if ``False``, the order is assumed to be non-maximal at some prime + not in ``v``. - - if ``None``, no assumptions are made about primes not in ``v``. + - if ``None``, no assumptions are made about primes not in ``v``. - - if ``"non-maximal-non-unique"`` (deprecated), like ``False``, - however, the order is not a unique parent, so creating the same - order later does typically not poison caches with the information - that the order is not maximal. + - if ``"non-maximal-non-unique"`` (deprecated), like ``False``, + however, the order is not a unique parent, so creating the same + order later does typically not poison caches with the information + that the order is not maximal. EXAMPLES: In this example, the maximal order cannot be generated by a single element:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + x^2 - 2*x+8) sage: o = k.maximal_order() sage: o @@ -7919,7 +8043,8 @@ def maximal_order(self, v=None, assume_maximal='non-maximal-non-unique'): sage: K.maximal_order(v=2, assume_maximal=False) Traceback (most recent call last): ... - ValueError: cannot assume this order to be non-maximal because we already found it to be a maximal order + ValueError: cannot assume this order to be non-maximal + because we already found it to be a maximal order TESTS: @@ -7934,7 +8059,8 @@ def maximal_order(self, v=None, assume_maximal='non-maximal-non-unique'): sage: K.<a, b> = NumberField([x^4 + 1, x^4 - 3]) sage: K.maximal_order() - Maximal Relative Order in Number Field in a with defining polynomial x^4 + 1 over its base field + Maximal Relative Order in + Number Field in a with defining polynomial x^4 + 1 over its base field An example with nontrivial ``v``:: @@ -7962,11 +8088,12 @@ def maximal_order(self, v=None, assume_maximal='non-maximal-non-unique'): class NumberField_absolute(NumberField_generic): def __init__(self, polynomial, name, latex_name=None, check=True, embedding=None, assume_disc_small=False, maximize_at_primes=None, structure=None): - """ + r""" Function to initialize an absolute number field. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K = NumberField(x^17 + 3, 'a'); K Number Field in a with defining polynomial x^17 + 3 sage: type(K) @@ -7982,7 +8109,7 @@ def __init__(self, polynomial, name, latex_name=None, check=True, embedding=None self._init_embedding_approx() def _coerce_from_other_number_field(self, x): - """ + r""" Coerce a number field element x into this number field. Unless `x` is in ``QQ``, this requires ``x.parent()`` and @@ -8009,6 +8136,7 @@ def _coerce_from_other_number_field(self, x): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: L.<b> = NumberField(x^2 + 1) sage: K._coerce_from_other_number_field(L(2/3)) @@ -8018,12 +8146,14 @@ def _coerce_from_other_number_field(self, x): sage: K._coerce_from_other_number_field(b) Traceback (most recent call last): ... - TypeError: No compatible natural embeddings found for Number Field in a with defining polynomial x^3 + 2 and Number Field in b with defining polynomial x^2 + 1 + TypeError: No compatible natural embeddings found for + Number Field in a with defining polynomial x^3 + 2 and + Number Field in b with defining polynomial x^2 + 1 Two number fields both containing `i`:: - sage: K.<a> = NumberField(x^4 + 6*x^2 + 1, embedding = CC(-2.4*I)) - sage: L.<b> = NumberField(x^4 + 8*x^2 + 4, embedding = CC(2.7*I)) + sage: K.<a> = NumberField(x^4 + 6*x^2 + 1, embedding=CC(-2.4*I)) + sage: L.<b> = NumberField(x^4 + 8*x^2 + 4, embedding=CC(2.7*I)) sage: Ki = 1/2*a^3 + 5/2*a; Ki.minpoly() x^2 + 1 sage: L(Ki) @@ -8035,7 +8165,7 @@ def _coerce_from_other_number_field(self, x): i sage: Q(L(Ki)) i - sage: L( (Ki+2)^1000 ) + sage: L((Ki+2)^1000) 737533628...075020804*b^3 + 442520177...450124824*b + 793311113...453515313 This fails if we don't specify the embeddings:: @@ -8045,25 +8175,31 @@ def _coerce_from_other_number_field(self, x): sage: L(1/2*a^3 + 5/2*a) Traceback (most recent call last): ... - TypeError: No compatible natural embeddings found for Number Field in b with defining polynomial x^4 + 8*x^2 + 4 and Number Field in a with defining polynomial x^4 + 6*x^2 + 1 + TypeError: No compatible natural embeddings found for + Number Field in b with defining polynomial x^4 + 8*x^2 + 4 and + Number Field in a with defining polynomial x^4 + 6*x^2 + 1 Embeddings can also be `p`-adic:: + sage: # needs sage.rings.padics sage: F = Qp(73) - sage: K.<a> = NumberField(x^4 + 6*x^2 + 1, embedding = F(1290990671961076190983179596556712119)) - sage: L.<b> = NumberField(x^4 + 8*x^2 + 4, embedding = F(1773398470280167815153042237103591466)) + sage: K.<a> = NumberField(x^4 + 6*x^2 + 1, + ....: embedding=F(1290990671961076190983179596556712119)) + sage: L.<b> = NumberField(x^4 + 8*x^2 + 4, + ....: embedding=F(1773398470280167815153042237103591466)) sage: L(2*a^3 + 10*a + 3) b^3 + 6*b + 3 If we take the same non-Galois number field with two different embeddings, conversion fails:: - sage: K.<a> = NumberField(x^3 - 4*x + 1, embedding = 0.254) - sage: L.<b> = NumberField(x^3 - 4*x + 1, embedding = 1.86) + sage: K.<a> = NumberField(x^3 - 4*x + 1, embedding=0.254) + sage: L.<b> = NumberField(x^3 - 4*x + 1, embedding=1.86) sage: L(a) Traceback (most recent call last): ... - ValueError: Cannot convert a to Number Field in b with defining polynomial x^3 - 4*x + 1 with b = 1.860805853111704? (using the specified embeddings) + ValueError: cannot convert a to Number Field in b with defining polynomial x^3 - 4*x + 1 + with b = 1.860805853111704? (using the specified embeddings) Subfields automatically come with an embedding:: @@ -8080,11 +8216,11 @@ def _coerce_from_other_number_field(self, x): Since `L2` and `L3` both embed in `K`, conversion works:: sage: K.<z> = NumberField(x^8 - x^4 + 1) - sage: i = (x^2+1).roots(ring=K)[0][0] - sage: r2 = (x^2-2).roots(ring=K)[0][0] - sage: r3 = (x^2-3).roots(ring=K)[0][0] - sage: L2.<a2>, phi2 = K.subfield(r2+i) - sage: L3.<a3>, phi3 = K.subfield(r3+i) + sage: i = (x^2 + 1).roots(ring=K)[0][0] + sage: r2 = (x^2 - 2).roots(ring=K)[0][0] + sage: r3 = (x^2 - 3).roots(ring=K)[0][0] + sage: L2.<a2>, phi2 = K.subfield(r2 + i) + sage: L3.<a3>, phi3 = K.subfield(r3 + i) sage: i_in_L2 = L2(i); i_in_L2 1/6*a2^3 + 1/6*a2 sage: i_in_L3 = L3(i); i_in_L3 @@ -8099,8 +8235,8 @@ def _coerce_from_other_number_field(self, x): The following was fixed in :trac:`8800`:: sage: P.<x> = QQ[] - sage: K.<a> = NumberField(x^3-5,embedding=0) - sage: L.<b> = K.extension(x^2+a) + sage: K.<a> = NumberField(x^3 - 5,embedding=0) + sage: L.<b> = K.extension(x^2 + a) sage: F,R = L.construction() sage: F(R) == L #indirect doctest True @@ -8156,7 +8292,7 @@ def _coerce_from_other_number_field(self, x): f = x.minpoly() ys = f.roots(ring=K, multiplicities=False) if not ys: - raise ValueError("Cannot convert %s to %s (regardless of embeddings)" % (x, K)) + raise ValueError("cannot convert %s to %s (regardless of embeddings)" % (x, K)) # Define a function are_roots_equal to determine whether two # roots of f are equal. A simple a == b does not suffice for @@ -8213,11 +8349,11 @@ def _coerce_from_other_number_field(self, x): emb_y = y.polynomial()(Kgen) if are_roots_equal(emb_x, emb_y): return y - raise ValueError("Cannot convert %s to %s (using the specified embeddings)" % (x, K)) + raise ValueError("cannot convert %s to %s (using the specified embeddings)" % (x, K)) def _coerce_map_from_(self, R): - """ - Canonical coercion of a ring R into self. + r""" + Canonical coercion of a ring `R` into ``self``. Currently any ring coercing into the base ring canonically coerces into this field, as well as orders in any number field coercing into @@ -8229,8 +8365,9 @@ def _coerce_map_from_(self, R): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: S.<y> = NumberField(x^3 + x + 1) - sage: S.coerce(int(4)) # indirect doctest + sage: S.coerce(int(4)) # indirect doctest 4 sage: S.coerce(-Integer(2)) -2 @@ -8255,14 +8392,14 @@ def _coerce_map_from_(self, R): Two embedded number fields with mutual coercions (testing against a bug that was fixed in :trac:`8800`):: - sage: K.<r4> = NumberField(x^4-2) - sage: L1.<r2_1> = NumberField(x^2-2, embedding = r4**2) - sage: L2.<r2_2> = NumberField(x^2-2, embedding = -r4**2) - sage: r2_1+r2_2 # indirect doctest + sage: K.<r4> = NumberField(x^4 - 2) + sage: L1.<r2_1> = NumberField(x^2 - 2, embedding=r4**2) + sage: L2.<r2_2> = NumberField(x^2 - 2, embedding=-r4**2) + sage: r2_1 + r2_2 # indirect doctest 0 - sage: (r2_1+r2_2).parent() is L1 + sage: (r2_1 + r2_2).parent() is L1 True - sage: (r2_2+r2_1).parent() is L2 + sage: (r2_2 + r2_1).parent() is L2 True Coercion of an order (testing against a bug that was fixed in @@ -8282,20 +8419,21 @@ def _coerce_map_from_(self, R): there will be no coercion from the Symbolic Ring to a Number Field:: sage: K.<a> = QuadraticField(2) - sage: K.coerce(sqrt(2)) + sage: K.coerce(sqrt(2)) # needs sage.symbolic Traceback (most recent call last): ... - TypeError: no canonical coercion from Symbolic Ring to Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? + TypeError: no canonical coercion from Symbolic Ring to Number Field in a + with defining polynomial x^2 - 2 with a = 1.414213562373095? TESTS:: - sage: K.<a> = NumberField(polygen(QQ)^3-2) + sage: K.<a> = NumberField(polygen(QQ)^3 - 2) sage: type(K.coerce_map_from(QQ)) <class 'sage.structure.coerce_maps.DefaultConvertMap_unique'> Make sure we still get our optimized morphisms for special fields:: - sage: K.<a> = NumberField(polygen(QQ)^2-2) + sage: K.<a> = NumberField(polygen(QQ)^2 - 2) sage: type(K.coerce_map_from(QQ)) <class 'sage.rings.number_field.number_field_element_quadratic.Q_to_quadratic_field_element'> @@ -8308,7 +8446,7 @@ def _coerce_map_from_(self, R): if is_NumberFieldOrder(R) and self.has_coerce_map_from(R.number_field()): return self._generic_coerce_map(R) # R is not QQ by the above tests - if is_NumberField(R) and R.coerce_embedding() is not None: + if isinstance(R, number_field_base.NumberField) and R.coerce_embedding() is not None: if self.coerce_embedding() is not None: try: return number_field_morphisms.EmbeddedNumberFieldMorphism(R, self) @@ -8321,8 +8459,8 @@ def _coerce_map_from_(self, R): return None def base_field(self): - """ - Return the base field of self, which is always ``QQ``. + r""" + Return the base field of ``self``, which is always ``QQ``. EXAMPLES:: @@ -8333,8 +8471,8 @@ def base_field(self): return QQ def is_absolute(self): - """ - Return ``True`` since self is an absolute field. + r""" + Return ``True`` since ``self`` is an absolute field. EXAMPLES:: @@ -8347,10 +8485,11 @@ def is_absolute(self): def absolute_polynomial(self): r""" Return absolute polynomial that defines this absolute field. This - is the same as ``self.polynomial()``. + is the same as :meth:`polynomial`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 + 1) sage: K.absolute_polynomial () x^2 + 1 @@ -8369,6 +8508,7 @@ def absolute_generator(self): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 - 17) sage: K.absolute_generator() a @@ -8376,10 +8516,10 @@ def absolute_generator(self): return self.gen() def optimized_representation(self, name=None, both_maps=True): - """ - Return a field isomorphic to self with a better defining polynomial + r""" + Return a field isomorphic to ``self`` with a better defining polynomial if possible, along with field isomorphisms from the new field to - self and from self to the new field. + ``self`` and from ``self`` to the new field. EXAMPLES: We construct a compositum of 3 quadratic fields, then find an optimized representation and transform elements back and @@ -8387,12 +8527,12 @@ def optimized_representation(self, name=None, both_maps=True): :: + sage: x = polygen(QQ, 'x') sage: K = NumberField([x^2 + p for p in [5, 3, 2]],'a').absolute_field('b'); K Number Field in b with defining polynomial x^8 + 40*x^6 + 352*x^4 + 960*x^2 + 576 sage: L, from_L, to_L = K.optimized_representation() sage: L # your answer may different, since algorithm is random - Number Field in b1 with defining polynomial x^8 + 4*x^6 + 7*x^4 + - 36*x^2 + 81 + Number Field in b1 with defining polynomial x^8 + 4*x^6 + 7*x^4 + 36*x^2 + 81 sage: to_L(K.0) # random 4/189*b1^7 + 1/63*b1^6 + 1/27*b1^5 - 2/9*b1^4 - 5/27*b1^3 - 8/9*b1^2 + 3/7*b1 - 3/7 sage: from_L(L.0) # random @@ -8478,11 +8618,12 @@ def optimized_representation(self, name=None, both_maps=True): def optimized_subfields(self, degree=0, name=None, both_maps=True): """ Return optimized representations of many (but *not* necessarily - all!) subfields of self of the given degree, or of all possible degrees if - degree is 0. + all!) subfields of ``self`` of the given ``degree``, or of all possible degrees if + ``degree`` is 0. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K = NumberField([x^2 + p for p in [5, 3, 2]],'a').absolute_field('b'); K Number Field in b with defining polynomial x^8 + 40*x^6 + 352*x^4 + 960*x^2 + 576 sage: L = K.optimized_subfields(name='b') @@ -8505,10 +8646,12 @@ def optimized_subfields(self, degree=0, name=None, both_maps=True): sage: from_M # may be slightly random Ring morphism: From: Number Field in b2 with defining polynomial x^4 - 5*x^2 + 25 - To: Number Field in a1 with defining polynomial x^8 + 40*x^6 + 352*x^4 + 960*x^2 + 576 - Defn: b2 |--> -5/1152*a1^7 + 1/96*a1^6 - 97/576*a1^5 + 17/48*a1^4 - 95/72*a1^3 + 17/12*a1^2 - 53/24*a1 - 1 + To: Number Field in a1 with defining polynomial + x^8 + 40*x^6 + 352*x^4 + 960*x^2 + 576 + Defn: b2 |--> -5/1152*a1^7 + 1/96*a1^6 - 97/576*a1^5 + 17/48*a1^4 + - 95/72*a1^3 + 17/12*a1^2 - 53/24*a1 - 1 - The to_M map is None, since there is no map from K to M:: + The ``to_M`` map is ``None``, since there is no map from `K` to `M`:: sage: to_M @@ -8516,7 +8659,8 @@ def optimized_subfields(self, degree=0, name=None, both_maps=True): rather large element of `K`:: sage: from_M(M.0) # random - -5/1152*a1^7 + 1/96*a1^6 - 97/576*a1^5 + 17/48*a1^4 - 95/72*a1^3 + 17/12*a1^2 - 53/24*a1 - 1 + -5/1152*a1^7 + 1/96*a1^6 - 97/576*a1^5 + 17/48*a1^4 + - 95/72*a1^3 + 17/12*a1^2 - 53/24*a1 - 1 Nevertheless, that large-ish element lies in a degree 4 subfield:: @@ -8569,21 +8713,20 @@ def optimized_subfields(self, degree=0, name=None, both_maps=True): def change_names(self, names): r""" - Return number field isomorphic to self but with the given generator + Return number field isomorphic to ``self`` but with the given generator name. INPUT: + - ``names`` -- should be exactly one variable name. - - ``names`` - should be exactly one variable name. - - - Also, ``K.structure()`` returns from_K and to_K, - where from_K is an isomorphism from K to self and to_K is an - isomorphism from self to K. + Also, ``K.structure()`` returns ``from_K`` and ``to_K``, + where ``from_K`` is an isomorphism from `K` to ``self`` and ``to_K`` is an + isomorphism from ``self`` to `K`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<z> = NumberField(x^2 + 3); K Number Field in z with defining polynomial x^2 + 3 sage: L.<ww> = K.change_names() @@ -8600,14 +8743,15 @@ def change_names(self, names): def subfields(self, degree=0, name=None): """ - Return all subfields of self of the given degree, - or of all possible degrees if degree is 0. The subfields are returned as - absolute fields together with an embedding into self. For the case of the + Return all subfields of ``self`` of the given ``degree``, + or of all possible degrees if ``degree`` is 0. The subfields are returned as + absolute fields together with an embedding into ``self``. For the case of the field itself, the reverse isomorphism is also provided. EXAMPLES:: - sage: K.<a> = NumberField( [x^3 - 2, x^2 + x + 1] ) + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField([x^3 - 2, x^2 + x + 1]) sage: K = K.absolute_field('b') sage: S = K.subfields() sage: len(S) @@ -8673,31 +8817,32 @@ def subfields(self, degree=0, name=None): def _subfields_helper(self, degree=0, name=None, both_maps=True, optimize=False): """ - Internal function: common code for optimized_subfields() and subfields(). + Internal function: common code for :meth:`optimized_subfields` and :meth:`subfields`. TESTS: Let's make sure embeddings are being respected:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^4 - 23, embedding=50) sage: K, CDF(a) (Number Field in a with defining polynomial x^4 - 23 with a = 2.189938703094843?, 2.1899387030948425) - sage: Ss = K.subfields(); len(Ss) # indirect doctest + sage: Ss = K.subfields(); len(Ss) # indirect doctest 3 sage: diffs = [ S.coerce_embedding()(S.gen()) - CDF(S_into_K(S.gen())) for S, S_into_K, _ in Ss ] sage: all(abs(diff) < 1e-5 for diff in diffs) True - sage: L1, _, _ = K.subfields(2)[0]; L1, CDF(L1.gen()) # indirect doctest + sage: L1, _, _ = K.subfields(2)[0]; L1, CDF(L1.gen()) # indirect doctest (Number Field in a0 with defining polynomial x^2 - 23 with a0 = -4.795831523312720?, -4.795831523312719) - If we take a different embedding of the large field, we get a - different embedding of the degree 2 subfield:: + If we take a different embedding of the large field, we get a + different embedding of the degree 2 subfield:: sage: K.<a> = NumberField(x^4 - 23, embedding=-50) - sage: L2, _, _ = K.subfields(2)[0]; L2, CDF(L2.gen()) # indirect doctest + sage: L2, _, _ = K.subfields(2)[0]; L2, CDF(L2.gen()) # indirect doctest (Number Field in a0 with defining polynomial x^2 - 23 with a0 = -4.795831523312720?, -4.795831523312719) @@ -8769,6 +8914,7 @@ def _maximal_order(self, v=(), assume_maximal=None): TESTS:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + x^2 - 2*x+8) sage: k.maximal_order() is k.maximal_order() # indirect doctest True @@ -8788,23 +8934,24 @@ def order(self, *args, **kwds): INPUT: - - ``gens`` - list of elements in this number field; if no generators + - ``gens`` -- list of elements in this number field; if no generators are given, just returns the cardinality of this number field (`\infty`) for consistency. - - ``check_is_integral`` - bool (default: ``True``), whether to check + - ``check_is_integral`` -- bool (default: ``True``), whether to check that each generator is integral. - - ``check_rank`` - bool (default: ``True``), whether to check that the + - ``check_rank`` -- bool (default: ``True``), whether to check that the ring generated by ``gens`` is of full rank. - - ``allow_subfield`` - bool (default: ``False``), if ``True`` and the + - ``allow_subfield`` -- bool (default: ``False``), if ``True`` and the generators do not generate an order, i.e., they generate a subring of smaller rank, instead of raising an error, return an order in a smaller number field. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<i> = NumberField(x^2 + 1) sage: k.order(2*i) Order in Number Field in i with defining polynomial x^2 + 1 @@ -8859,6 +9006,7 @@ def _order(self, gens, **kwds): Test that caching works:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: K.order(a) is K.order(a) # indirect doctest True @@ -8871,7 +9019,7 @@ def _order(self, gens, **kwds): Even if the order lives in a different field, caching works (currently, however, ``allow_subfield`` is incorrect :trac:`16046`):: - sage: K.<a> = NumberField(x**4+3) + sage: K.<a> = NumberField(x**4 + 3) sage: o = K.order([a**2], allow_subfield=True) sage: o is K.order([a**2], allow_subfield=True) True @@ -8887,8 +9035,8 @@ def _order(self, gens, **kwds): @cached_method(key=lambda self, base, basis, map: (base or self.base_ring(), basis, map)) def free_module(self, base=None, basis=None, map=True): - """ - Return a vector space V and isomorphisms self --> V and V --> self. + r""" + Return a vector space `V` and isomorphisms ``self`` `\to` `V` and `V` `\to` ``self``. INPUT: @@ -8901,19 +9049,17 @@ def free_module(self, base=None, basis=None, map=True): - ``maps`` -- boolean (default ``True``), whether to return `R`-linear maps to and from `V` - OUTPUT: + - `V` -- a vector space over the rational numbers - - ``V`` - a vector space over the rational numbers - - - ``from_V`` - an isomorphism from V to self (if requested) - - - ``to_V`` - an isomorphism from self to V (if requested) + - ``from_V`` -- an isomorphism from `V` to ``self`` (if requested) + - ``to_V`` -- an isomorphism from ``self`` to `V` (if requested) EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: k.<a> = NumberField(x^3 + 2) sage: V, from_V, to_V = k.free_module() sage: from_V(V([1,2,3])) @@ -8951,10 +9097,11 @@ def absolute_vector_space(self, *args, **kwds): and in the other direction. For an absolute extension this is identical to - ``self.vector_space()``. + :meth:`vector_space`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 - 5) sage: K.absolute_vector_space() (Vector space of dimension 3 over Rational Field, @@ -8969,12 +9116,12 @@ def absolute_vector_space(self, *args, **kwds): def _galois_closure_and_embedding(self, names=None): r""" - Return number field `K` that is the Galois closure of self and an - embedding of self into `K`. + Return number field `K` that is the Galois closure of ``self`` and an + embedding of ``self`` into `K`. INPUT: - - ``names`` - variable name for Galois closure + - ``names`` -- variable name for Galois closure .. warning:: @@ -8985,6 +9132,7 @@ def _galois_closure_and_embedding(self, names=None): For medium-sized Galois groups of fields with small discriminants, this computation is feasible:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^6 + 4*x^2 + 2) sage: K.galois_group().order() 48 @@ -9019,18 +9167,19 @@ def _galois_closure_and_embedding(self, names=None): def galois_closure(self, names=None, map=False): """ - Return number field `K` that is the Galois closure of self, + Return number field `K` that is the Galois closure of ``self``, i.e., is generated by all roots of the defining polynomial of - self, and possibly an embedding of self into `K`. + ``self``, and possibly an embedding of ``self`` into `K`. INPUT: - - ``names`` - variable name for Galois closure + - ``names`` -- variable name for Galois closure - - ``map`` - (default: ``False``) also return an embedding of self into `K` + - ``map`` -- (default: ``False``) also return an embedding of ``self`` into `K` EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^4 - 2) sage: M = K.galois_closure('b'); M Number Field in b with defining polynomial x^8 + 28*x^4 + 2500 @@ -9061,7 +9210,9 @@ def galois_closure(self, names=None, map=False): sage: K.<a> = NumberField(cyclotomic_polynomial(23)) sage: L.<z> = K.galois_closure() sage: L - Number Field in z with defining polynomial x^22 + x^21 + x^20 + x^19 + x^18 + x^17 + x^16 + x^15 + x^14 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1 + Number Field in z with defining polynomial + x^22 + x^21 + x^20 + x^19 + x^18 + x^17 + x^16 + x^15 + x^14 + x^13 + x^12 + + x^11 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1 TESTS: @@ -9082,13 +9233,14 @@ def galois_closure(self, names=None, map=False): def automorphisms(self): r""" - Compute all Galois automorphisms of self. + Compute all Galois automorphisms of ``self``. This uses PARI's :pari:`nfgaloisconj` and is much faster than root finding for many fields. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 + 10000) sage: K.automorphisms() [ @@ -9107,7 +9259,10 @@ def automorphisms(self): `L` is the Galois closure of `K`:: - sage: L = NumberField(x^24 - 84*x^22 + 2814*x^20 - 15880*x^18 - 409563*x^16 - 8543892*x^14 + 25518202*x^12 + 32831026956*x^10 - 672691027218*x^8 - 4985379093428*x^6 + 320854419319140*x^4 + 817662865724712*x^2 + 513191437605441, 'a') + sage: L = NumberField(x^24 - 84*x^22 + 2814*x^20 - 15880*x^18 - 409563*x^16 + ....: - 8543892*x^14 + 25518202*x^12 + 32831026956*x^10 + ....: - 672691027218*x^8 - 4985379093428*x^6 + 320854419319140*x^4 + ....: + 817662865724712*x^2 + 513191437605441, 'a') sage: len(L.automorphisms()) 24 @@ -9134,11 +9289,11 @@ def automorphisms(self): @cached_method def embeddings(self, K): """ - Compute all field embeddings of this field into the field K (which need + Compute all field embeddings of this field into the field `K` (which need not even be a number field, e.g., it could be the complex numbers). - This will return an identical result when given K as input again. + This will return an identical result when given `K` as input again. - If possible, the most natural embedding of this field into K + If possible, the most natural embedding of this field into `K` is put first in the list. INPUT: @@ -9147,6 +9302,7 @@ def embeddings(self, K): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: L.<a1> = K.galois_closure(); L Number Field in a1 with defining polynomial x^6 + 108 @@ -9165,11 +9321,13 @@ def embeddings(self, K): sage: L.embeddings(K) [ Ring morphism: - From: Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I + From: Number Field in a with defining polynomial x^2 + 7 + with a = 2.645751311064591?*I To: Cyclotomic Field of order 7 and degree 6 Defn: a |--> 2*zeta7^4 + 2*zeta7^2 + 2*zeta7 + 1, Ring morphism: - From: Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I + From: Number Field in a with defining polynomial x^2 + 7 + with a = 2.645751311064591?*I To: Cyclotomic Field of order 7 and degree 6 Defn: a |--> -2*zeta7^4 - 2*zeta7^2 - 2*zeta7 - 1 ] @@ -9224,23 +9382,23 @@ def embeddings(self, K): def minkowski_embedding(self, B=None, prec=None): r""" - Return an nxn matrix over RDF whose columns are the images of the - basis `\{1, \alpha, \dots, \alpha^{n-1}\}` of self over + Return an `n \times n` matrix over ``RDF`` whose columns are the images of the + basis `\{1, \alpha, \dots, \alpha^{n-1}\}` of ``self`` over `\QQ` (as vector spaces), where here - `\alpha` is the generator of self over - `\QQ`, i.e. self.gen(0). If B is not None, return - the images of the vectors in B as the columns instead. If prec is - not None, use RealField(prec) instead of RDF. + `\alpha` is the generator of ``self`` over + `\QQ`, i.e. ``self.gen(0)``. If `B` is not ``None``, return + the images of the vectors in `B` as the columns instead. If ``prec`` is + not ``None``, use ``RealField(prec)`` instead of ``RDF``. This embedding is the so-called "Minkowski embedding" of a number field in `\RR^n`: given the `n` embeddings - `\sigma_1, \dots, \sigma_n` of self in + `\sigma_1, \dots, \sigma_n` of ``self`` in `\CC`, write `\sigma_1, \dots, \sigma_r` for the real embeddings, and `\sigma_{r+1}, \dots, \sigma_{r+s}` for choices of one of each pair of complex conjugate embeddings (in our case, we simply choose the one where the image of `\alpha` has positive - real part). Here `(r,s)` is the signature of self. Then the + real part). Here `(r,s)` is the signature of ``self``. Then the Minkowski embedding is given by .. MATH:: @@ -9251,9 +9409,9 @@ def minkowski_embedding(self, B=None, prec=None): \sqrt{2}\Re(\sigma_{r+s}(x)), \sqrt{2}\Im(\sigma_{r+s}(x))) - Equivalently, this is an embedding of self in `\RR^n` so + Equivalently, this is an embedding of ``self`` in `\RR^n` so that the usual norm on `\RR^n` coincides with - `|x| = \sum_i |\sigma_i(x)|^2` on self. + `|x| = \sum_i |\sigma_i(x)|^2` on ``self``. .. TODO:: @@ -9262,7 +9420,8 @@ def minkowski_embedding(self, B=None, prec=None): EXAMPLES:: - sage: F.<alpha> = NumberField(x^3+2) + sage: x = polygen(QQ, 'x') + sage: F.<alpha> = NumberField(x^3 + 2) sage: F.minkowski_embedding() [ 1.00000000000000 -1.25992104989487 1.58740105196820] [ 1.41421356237... 0.8908987181... -1.12246204830...] @@ -9320,7 +9479,7 @@ def logarithmic_embedding(self, prec=53): OUTPUT: - - the morphism of ``self`` under the logarithmic embedding in the category Set. + the morphism of ``self`` under the logarithmic embedding in the category Set. EXAMPLES:: @@ -9333,6 +9492,7 @@ def logarithmic_embedding(self, prec=53): :: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^3 + 5) sage: f = K.logarithmic_embedding() sage: f(0) @@ -9379,71 +9539,72 @@ def closure_map(x, prec=53): def places(self, all_complex=False, prec=None): r""" - Return the collection of all infinite places of self. + Return the collection of all infinite places of ``self``. By default, this returns the set of real places as - homomorphisms into RIF first, followed by a choice of one of - each pair of complex conjugate homomorphisms into CIF. + homomorphisms into ``RIF`` first, followed by a choice of one of + each pair of complex conjugate homomorphisms into ``CIF``. - On the other hand, if prec is not None, we simply return places - into RealField(prec) and ComplexField(prec) (or RDF, CDF if - prec=53). One can also use ``prec=infinity``, which returns embeddings + On the other hand, if ``prec`` is not ``None``, we simply return places + into ``RealField(prec)`` and ``ComplexField(prec)`` (or ``RDF``, ``CDF`` if + ``prec=53``). One can also use ``prec=infinity``, which returns embeddings into the field `\overline{\QQ}` of algebraic numbers (or its subfield `\mathbb{A}` of algebraic reals); this permits exact computation, but can be extremely slow. - There is an optional flag all_complex, which defaults to False. If - all_complex is True, then the real embeddings are returned as - embeddings into CIF instead of RIF. + There is an optional flag ``all_complex``, which defaults to ``False``. If + ``all_complex`` is ``True``, then the real embeddings are returned as + embeddings into ``CIF`` instead of ``RIF``. EXAMPLES:: - sage: F.<alpha> = NumberField(x^3-100*x+1) ; F.places() + sage: x = polygen(QQ, 'x') + sage: F.<alpha> = NumberField(x^3 - 100*x + 1); F.places() [Ring morphism: - From: Number Field in alpha with defining polynomial x^3 - 100*x + 1 - To: Real Field with 106 bits of precision - Defn: alpha |--> -10.00499625499181184573367219280, - Ring morphism: - From: Number Field in alpha with defining polynomial x^3 - 100*x + 1 - To: Real Field with 106 bits of precision - Defn: alpha |--> 0.01000001000003000012000055000273, - Ring morphism: - From: Number Field in alpha with defining polynomial x^3 - 100*x + 1 - To: Real Field with 106 bits of precision - Defn: alpha |--> 9.994996244991781845613530439509] + From: Number Field in alpha with defining polynomial x^3 - 100*x + 1 + To: Real Field with 106 bits of precision + Defn: alpha |--> -10.00499625499181184573367219280, + Ring morphism: + From: Number Field in alpha with defining polynomial x^3 - 100*x + 1 + To: Real Field with 106 bits of precision + Defn: alpha |--> 0.01000001000003000012000055000273, + Ring morphism: + From: Number Field in alpha with defining polynomial x^3 - 100*x + 1 + To: Real Field with 106 bits of precision + Defn: alpha |--> 9.994996244991781845613530439509] :: - sage: F.<alpha> = NumberField(x^3+7) ; F.places() + sage: F.<alpha> = NumberField(x^3 + 7); F.places() [Ring morphism: - From: Number Field in alpha with defining polynomial x^3 + 7 - To: Real Field with 106 bits of precision - Defn: alpha |--> -1.912931182772389101199116839549, - Ring morphism: - From: Number Field in alpha with defining polynomial x^3 + 7 - To: Complex Field with 53 bits of precision - Defn: alpha |--> 0.956465591386195 + 1.65664699997230*I] + From: Number Field in alpha with defining polynomial x^3 + 7 + To: Real Field with 106 bits of precision + Defn: alpha |--> -1.912931182772389101199116839549, + Ring morphism: + From: Number Field in alpha with defining polynomial x^3 + 7 + To: Complex Field with 53 bits of precision + Defn: alpha |--> 0.956465591386195 + 1.65664699997230*I] :: - sage: F.<alpha> = NumberField(x^3+7) ; F.places(all_complex=True) + sage: F.<alpha> = NumberField(x^3 + 7) ; F.places(all_complex=True) [Ring morphism: - From: Number Field in alpha with defining polynomial x^3 + 7 - To: Complex Field with 53 bits of precision - Defn: alpha |--> -1.91293118277239, - Ring morphism: - From: Number Field in alpha with defining polynomial x^3 + 7 - To: Complex Field with 53 bits of precision - Defn: alpha |--> 0.956465591386195 + 1.65664699997230*I] + From: Number Field in alpha with defining polynomial x^3 + 7 + To: Complex Field with 53 bits of precision + Defn: alpha |--> -1.91293118277239, + Ring morphism: + From: Number Field in alpha with defining polynomial x^3 + 7 + To: Complex Field with 53 bits of precision + Defn: alpha |--> 0.956465591386195 + 1.65664699997230*I] sage: F.places(prec=10) [Ring morphism: - From: Number Field in alpha with defining polynomial x^3 + 7 - To: Real Field with 10 bits of precision - Defn: alpha |--> -1.9, - Ring morphism: - From: Number Field in alpha with defining polynomial x^3 + 7 - To: Complex Field with 10 bits of precision - Defn: alpha |--> 0.96 + 1.7*I] + From: Number Field in alpha with defining polynomial x^3 + 7 + To: Real Field with 10 bits of precision + Defn: alpha |--> -1.9, + Ring morphism: + From: Number Field in alpha with defining polynomial x^3 + 7 + To: Complex Field with 10 bits of precision + Defn: alpha |--> 0.96 + 1.7*I] """ if prec is None: R = RIF @@ -9489,19 +9650,20 @@ def places(self, all_complex=False, prec=None): def real_places(self, prec=None): """ - Return all real places of self as homomorphisms into RIF. + Return all real places of ``self`` as homomorphisms into ``RIF``. EXAMPLES:: - sage: F.<alpha> = NumberField(x^4-7) ; F.real_places() + sage: x = polygen(QQ, 'x') + sage: F.<alpha> = NumberField(x^4 - 7) ; F.real_places() [Ring morphism: - From: Number Field in alpha with defining polynomial x^4 - 7 - To: Real Field with 106 bits of precision - Defn: alpha |--> -1.626576561697785743211232345494, - Ring morphism: - From: Number Field in alpha with defining polynomial x^4 - 7 - To: Real Field with 106 bits of precision - Defn: alpha |--> 1.626576561697785743211232345494] + From: Number Field in alpha with defining polynomial x^4 - 7 + To: Real Field with 106 bits of precision + Defn: alpha |--> -1.626576561697785743211232345494, + Ring morphism: + From: Number Field in alpha with defining polynomial x^4 - 7 + To: Real Field with 106 bits of precision + Defn: alpha |--> 1.626576561697785743211232345494] """ return self.places(prec=prec)[0:self.signature()[0]] @@ -9521,18 +9683,19 @@ def abs_val(self, v, iota, prec=None): EXAMPLES:: - sage: K.<xi> = NumberField(x^3-3) + sage: x = polygen(QQ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) sage: phi_real = K.places()[0] sage: phi_complex = K.places()[1] sage: v_fin = tuple(K.primes_above(3))[0] - sage: K.abs_val(phi_real,xi^2) + sage: K.abs_val(phi_real, xi^2) 2.08008382305190 - sage: K.abs_val(phi_complex,xi^2) + sage: K.abs_val(phi_complex, xi^2) 4.32674871092223 - sage: K.abs_val(v_fin,xi^2) + sage: K.abs_val(v_fin, xi^2) 0.111111111111111 Check that :trac:`28345` is fixed:: @@ -9558,17 +9721,17 @@ def abs_val(self, v, iota, prec=None): def relativize(self, alpha, names, structure=None): r""" - Given an element in self or an embedding of a subfield into self, - return a relative number field `K` isomorphic to self that is relative - over the absolute field `\QQ(\alpha)` or the domain of `alpha`, along - with isomorphisms from `K` to self and from self to `K`. + Given an element in ``self`` or an embedding of a subfield into ``self``, + return a relative number field `K` isomorphic to ``self`` that is relative + over the absolute field `\QQ(\alpha)` or the domain of `\alpha`, along + with isomorphisms from `K` to ``self`` and from ``self`` to `K`. INPUT: - - ``alpha`` - an element of self or an embedding of a subfield into - self - - ``names`` - 2-tuple of names of generator for output field K and the - subfield QQ(alpha) names[0] generators K and names[1] QQ(alpha). + - ``alpha`` -- an element of ``self`` or an embedding of a subfield into + ``self`` + - ``names`` -- 2-tuple of names of generator for output field `K` and the + subfield `\QQ(\alpha)` - ``structure`` -- an instance of :class:`structure.NumberFieldStructure` or ``None`` (default: ``None``), if ``None``, then the resulting field's :meth:`structure` @@ -9577,17 +9740,19 @@ def relativize(self, alpha, names, structure=None): OUTPUT: - K -- relative number field + `K` -- relative number field - Also, ``K.structure()`` returns from_K and to_K, where - from_K is an isomorphism from K to self and to_K is an isomorphism - from self to K. + Also, ``K.structure()`` returns ``from_K`` and ``to_K``, where + ``from_K`` is an isomorphism from `K` to ``self`` and ``to_K`` is an isomorphism + from ``self`` to `K`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^10 - 2) sage: L.<c,d> = K.relativize(a^4 + a^2 + 2); L - Number Field in c with defining polynomial x^2 - 1/5*d^4 + 8/5*d^3 - 23/5*d^2 + 7*d - 18/5 over its base field + Number Field in c with defining polynomial + x^2 - 1/5*d^4 + 8/5*d^3 - 23/5*d^2 + 7*d - 18/5 over its base field sage: c.absolute_minpoly() x^10 - 2 sage: d.absolute_minpoly() @@ -9692,7 +9857,8 @@ def relativize(self, alpha, names, structure=None): sage: K.<z> = CyclotomicField(16) sage: L, L_into_K, _ = K.subfields(4)[0]; L - Number Field in z0 with defining polynomial x^4 + 16 with z0 = 1.414213562373095? + 1.414213562373095?*I + Number Field in z0 with defining polynomial x^4 + 16 + with z0 = 1.414213562373095? + 1.414213562373095?*I sage: F, F_into_L, _ = L.subfields(2)[0]; F Number Field in z0_0 with defining polynomial x^2 + 64 with z0_0 = 8*I @@ -9819,10 +9985,11 @@ def relativize(self, alpha, names, structure=None): def absolute_degree(self): """ - A synonym for degree. + A synonym for :meth:`degree`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K.absolute_degree() 2 @@ -9831,10 +9998,11 @@ def absolute_degree(self): def relative_degree(self): """ - A synonym for degree. + A synonym for :meth:`degree`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K.relative_degree() 2 @@ -9843,10 +10011,11 @@ def relative_degree(self): def relative_polynomial(self): """ - A synonym for polynomial. + A synonym for :meth:`polynomial`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K.relative_polynomial() x^2 + 1 @@ -9855,10 +10024,11 @@ def relative_polynomial(self): def relative_vector_space(self, *args, **kwds): """ - A synonym for vector_space. + A synonym for :meth:`vector_space`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K.relative_vector_space() (Vector space of dimension 2 over Rational Field, @@ -9873,10 +10043,11 @@ def relative_vector_space(self, *args, **kwds): def absolute_discriminant(self): """ - A synonym for discriminant. + A synonym for :meth:`discriminant`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K.absolute_discriminant() -4 @@ -9885,10 +10056,11 @@ def absolute_discriminant(self): def relative_discriminant(self): """ - A synonym for discriminant. + A synonym for :meth:`discriminant`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K.relative_discriminant() -4 @@ -9897,10 +10069,11 @@ def relative_discriminant(self): def absolute_different(self): """ - A synonym for different. + A synonym for :meth:`different`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K.absolute_different() Fractional ideal (2) @@ -9909,10 +10082,11 @@ def absolute_different(self): def relative_different(self): """ - A synonym for different. + A synonym for :meth:`different`. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K.relative_different() Fractional ideal (2) @@ -9921,64 +10095,65 @@ def relative_different(self): def hilbert_symbol(self, a, b, P=None): r""" - Return the Hilbert symbol `(a,b)_P` for a prime P of self - and non-zero elements a and b of self. + Return the Hilbert symbol `(a,b)_P` for a prime `P` of ``self`` + and non-zero elements `a` and `b` of ``self``. - If P is omitted, return the global Hilbert symbol `(a,b)` instead. + If `P` is omitted, return the global Hilbert symbol `(a,b)` instead. INPUT: - - ``a``, ``b`` -- elements of self + - ``a``, ``b`` -- elements of ``self`` - - ``P`` -- (default: ``None``) If `P` is ``None``, compute the global - symbol. Otherwise, `P` should be either a prime ideal of self + - ``P`` -- (default: ``None``) If ``None``, compute the global + symbol. Otherwise, `P` should be either a prime ideal of ``self`` (which may also be given as a generator or set of generators) or a real or complex embedding. OUTPUT: - If a or b is zero, returns 0. + If `a` or `b` is zero, returns 0. - If a and b are non-zero and P is specified, returns - the Hilbert symbol `(a,b)_P`, which is 1 if the equation + If `a` and `b` are non-zero and `P` is specified, returns + the Hilbert symbol `(a,b)_P`, which is `1` if the equation `a x^2 + b y^2 = 1` has a solution in the completion of - self at P, and is -1 otherwise. + ``self`` at `P`, and is `-1` otherwise. - If a and b are non-zero and P is unspecified, returns 1 - if the equation has a solution in self and -1 otherwise. + If `a` and `b` are non-zero and `P` is unspecified, returns `1` + if the equation has a solution in ``self`` and `-1` otherwise. EXAMPLES: Some global examples:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 - 23) - sage: K.hilbert_symbol(0, a+5) + sage: K.hilbert_symbol(0, a + 5) 0 sage: K.hilbert_symbol(a, 0) 0 - sage: K.hilbert_symbol(-a, a+1) + sage: K.hilbert_symbol(-a, a + 1) 1 - sage: K.hilbert_symbol(-a, a+2) + sage: K.hilbert_symbol(-a, a + 2) -1 - sage: K.hilbert_symbol(a, a+5) + sage: K.hilbert_symbol(a, a + 5) -1 That the latter two are unsolvable should be visible in local obstructions. For the first, this is a prime ideal above 19. For the second, the ramified prime above 23:: - sage: K.hilbert_symbol(-a, a+2, a+2) + sage: K.hilbert_symbol(-a, a + 2, a + 2) -1 - sage: K.hilbert_symbol(a, a+5, K.ideal(23).factor()[0][0]) + sage: K.hilbert_symbol(a, a + 5, K.ideal(23).factor()[0][0]) -1 More local examples:: sage: K.hilbert_symbol(a, 0, K.ideal(5)) 0 - sage: K.hilbert_symbol(a, a+5, K.ideal(5)) + sage: K.hilbert_symbol(a, a + 5, K.ideal(5)) 1 - sage: K.hilbert_symbol(a+1, 13, (a+6)*K.maximal_order()) + sage: K.hilbert_symbol(a + 1, 13, (a+6)*K.maximal_order()) -1 sage: [emb1, emb2] = K.embeddings(AA) sage: K.hilbert_symbol(a, -1, emb1) @@ -9990,10 +10165,10 @@ def hilbert_symbol(self, a, b, P=None): sage: K.<a> = NumberField(x^5 - 23) sage: pi = 2*a^4 + 3*a^3 + 4*a^2 + 15*a + 11 - sage: K.hilbert_symbol(a, a+5, pi) + sage: K.hilbert_symbol(a, a + 5, pi) 1 sage: rho = 2*a^4 + 3*a^3 + 4*a^2 + 15*a + 11 - sage: K.hilbert_symbol(a, a+5, rho) + sage: K.hilbert_symbol(a, a + 5, rho) 1 This also works for non-principal ideals:: @@ -10002,9 +10177,9 @@ def hilbert_symbol(self, a, b, P=None): sage: P = K.ideal(3).factor()[0][0] sage: P.gens_reduced() # random, could be the other factor (3, a + 1) - sage: K.hilbert_symbol(a, a+3, P) + sage: K.hilbert_symbol(a, a + 3, P) 1 - sage: K.hilbert_symbol(a, a+3, [3, a+1]) + sage: K.hilbert_symbol(a, a + 3, [3, a+1]) 1 Primes above 2:: @@ -10012,11 +10187,11 @@ def hilbert_symbol(self, a, b, P=None): sage: K.<a> = NumberField(x^5 - 23) sage: O = K.maximal_order() sage: p = [p[0] for p in (2*O).factor() if p[0].norm() == 16][0] - sage: K.hilbert_symbol(a, a+5, p) + sage: K.hilbert_symbol(a, a + 5, p) 1 sage: K.hilbert_symbol(a, 2, p) 1 - sage: K.hilbert_symbol(-1, a-2, p) + sage: K.hilbert_symbol(-1, a - 2, p) -1 Various real fields are allowed:: @@ -10036,36 +10211,40 @@ def hilbert_symbol(self, a, b, P=None): Traceback (most recent call last): ... ValueError: Possibly real place (=Ring morphism: - From: Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? + From: Number Field in a with defining polynomial x^2 - 5 + with a = 2.236067977499790? To: Complex Field with 53 bits of precision - Defn: a |--> -2.23606797749979) given as complex embedding in hilbert_symbol. Is it real or complex? + Defn: a |--> -2.23606797749979) + given as complex embedding in hilbert_symbol. Is it real or complex? sage: K.hilbert_symbol(-1, -1, K.embeddings(QQbar)[0]) Traceback (most recent call last): ... ValueError: Possibly real place (=Ring morphism: - From: Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? + From: Number Field in a with defining polynomial x^2 - 5 + with a = 2.236067977499790? To: Algebraic Field - Defn: a |--> -2.236067977499790?) given as complex embedding in hilbert_symbol. Is it real or complex? + Defn: a |--> -2.236067977499790?) + given as complex embedding in hilbert_symbol. Is it real or complex? sage: K.<b> = QuadraticField(-5) sage: K.hilbert_symbol(-1, -1, K.embeddings(CDF)[0]) 1 sage: K.hilbert_symbol(-1, -1, K.embeddings(QQbar)[0]) 1 - a and b do not have to be integral or coprime:: + `a` and `b` do not have to be integral or coprime:: sage: K.<i> = QuadraticField(-1) sage: O = K.maximal_order() sage: K.hilbert_symbol(1/2, 1/6, 3*O) 1 - sage: p = 1+i + sage: p = 1 + i sage: K.hilbert_symbol(p, p, p) 1 sage: K.hilbert_symbol(p, 3*p, p) -1 sage: K.hilbert_symbol(3, p, p) -1 - sage: K.hilbert_symbol(1/3, 1/5, 1+i) + sage: K.hilbert_symbol(1/3, 1/5, 1 + i) 1 sage: L = QuadraticField(5, 'a') sage: L.hilbert_symbol(-3, -1/2, 2) @@ -10073,24 +10252,24 @@ def hilbert_symbol(self, a, b, P=None): Various other examples:: - sage: K.<a> = NumberField(x^3+x+1) - sage: K.hilbert_symbol(-6912, 24, -a^2-a-2) + sage: K.<a> = NumberField(x^3 + x + 1) + sage: K.hilbert_symbol(-6912, 24, -a^2 - a - 2) 1 - sage: K.<a> = NumberField(x^5-23) + sage: K.<a> = NumberField(x^5 - 23) sage: P = K.ideal(-1105*a^4 + 1541*a^3 - 795*a^2 - 2993*a + 11853) sage: Q = K.ideal(-7*a^4 + 13*a^3 - 13*a^2 - 2*a + 50) sage: b = -a+5 - sage: K.hilbert_symbol(a,b,P) + sage: K.hilbert_symbol(a, b, P) 1 - sage: K.hilbert_symbol(a,b,Q) + sage: K.hilbert_symbol(a, b, Q) 1 - sage: K.<a> = NumberField(x^5-23) + sage: K.<a> = NumberField(x^5 - 23) sage: P = K.ideal(-1105*a^4 + 1541*a^3 - 795*a^2 - 2993*a + 11853) - sage: K.hilbert_symbol(a, a+5, P) + sage: K.hilbert_symbol(a, a + 5, P) 1 sage: K.hilbert_symbol(a, 2, P) 1 - sage: K.hilbert_symbol(a+5, 2, P) + sage: K.hilbert_symbol(a + 5, 2, P) -1 sage: K.<a> = NumberField(x^3 - 4*x + 2) sage: K.hilbert_symbol(2, -2, K.primes_above(2)[0]) @@ -10148,13 +10327,13 @@ def hilbert_symbol(self, a, b, P=None): def hilbert_symbol_negative_at_S(self, S, b, check=True): """ - Return `a` such that the hilbert conductor of `a` and `b` is `S`. + Return `a` such that the Hilbert conductor of `a` and `b` is `S`. INPUT: - ``S`` -- a list of places (or prime ideals) of even cardinality - ``b`` -- a non-zero rational number which is a non-square locally - at every place in S. + at every place in `S`. - ``check`` -- bool (default: ``True``) perform additional checks on the input and confirm the output @@ -10172,6 +10351,7 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 + 20072) sage: S = [K.primes_above(3)[0], K.primes_above(23)[0]] sage: b = K.hilbert_symbol_negative_at_S(S, a + 1) @@ -10191,7 +10371,7 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): sage: [k.hilbert_symbol(a, b, p) for p in S] [-1, -1, -1, -1] - Note that the closely related hilbert conductor + Note that the closely related Hilbert conductor takes only the finite places into account:: sage: k.hilbert_conductor(a, b) @@ -10323,7 +10503,7 @@ def phi(x): def hilbert_conductor(self, a, b): """ - This is the product of all (finite) primes where the Hilbert symbol is -1. + This is the product of all (finite) primes where the Hilbert symbol is `-1`. What is the same, this is the (reduced) discriminant of the quaternion algebra `(a,b)` over a number field. @@ -10333,17 +10513,18 @@ def hilbert_conductor(self, a, b): OUTPUT: - - squarefree ideal of the ring of integers of ``self`` + squarefree ideal of the ring of integers of ``self`` EXAMPLES:: - sage: F.<a> = NumberField(x^2-x-1) - sage: F.hilbert_conductor(2*a,F(-1)) + sage: x = polygen(QQ, 'x') + sage: F.<a> = NumberField(x^2 - x - 1) + sage: F.hilbert_conductor(2*a, F(-1)) Fractional ideal (2) - sage: K.<b> = NumberField(x^3-4*x+2) - sage: K.hilbert_conductor(K(2),K(-2)) + sage: K.<b> = NumberField(x^3 - 4*x + 2) + sage: K.hilbert_conductor(K(2), K(-2)) Fractional ideal (1) - sage: K.hilbert_conductor(K(2*b),K(-2)) + sage: K.hilbert_conductor(K(2*b), K(-2)) Fractional ideal (b^2 + b - 2) AUTHOR: @@ -10362,13 +10543,13 @@ def elements_of_bounded_height(self, **kwds): Return an iterator over the elements of ``self`` with relative multiplicative height at most ``bound``. - This algorithm computes 2 lists: L containing elements x in `K` such that - H_k(x) <= B, and a list L' containing elements x in `K` that, due to + This algorithm computes 2 lists: `L` containing elements `x` in `K` such that + `H_k(x) \leq B`, and a list `L'` containing elements `x` in `K` that, due to floating point issues, - may be slightly larger then the bound. This can be controlled + may be slightly larger than the bound. This can be controlled by lowering the tolerance. - In current implementation both lists (L,L') are merged and returned in + In the current implementation, both lists `(L,L')` are merged and returned in form of iterator. ALGORITHM: @@ -10380,21 +10561,22 @@ def elements_of_bounded_height(self, **kwds): kwds: - - ``bound`` - a real number + - ``bound`` -- a real number - - ``tolerance`` - (default: 0.01) a rational number in (0,1] + - ``tolerance`` -- (default: 0.01) a rational number in `(0,1]` - - ``precision`` - (default: 53) a positive integer + - ``precision`` -- (default: 53) a positive integer OUTPUT: - - an iterator of number field elements + an iterator of number field elements EXAMPLES: There are no elements in a number field with multiplicative height less than 1:: + sage: x = polygen(QQ, 'x') sage: K.<g> = NumberField(x^5 - x + 19) sage: list(K.elements_of_bounded_height(bound=0.9)) [] @@ -10500,9 +10682,10 @@ def _factor_univariate_polynomial(self, poly, **kwargs): EXAMPLES:: - sage: K.<i> = NumberField(x**2+1) - sage: x = polygen(K,'x') - sage: factor(x*x+4) # indirect doctest + sage: x = polygen(QQ, 'x') + sage: K.<i> = NumberField(x**2 + 1) + sage: x = polygen(K, 'x') + sage: factor(x*x + 4) # indirect doctest (x - 2*i) * (x + 2*i) TESTS:: @@ -10541,8 +10724,8 @@ class NumberField_cyclotomic(NumberField_absolute, sage.rings.abc.NumberField_cy """ Create a cyclotomic extension of the rational field. - The command CyclotomicField(n) creates the n-th cyclotomic field, - obtained by adjoining an n-th root of unity to the rational field. + The command ``CyclotomicField(n)`` creates the `n`-th cyclotomic field, + obtained by adjoining an `n`-th root of unity to the rational field. EXAMPLES:: @@ -10567,26 +10750,26 @@ class NumberField_cyclotomic(NumberField_absolute, sage.rings.abc.NumberField_cy :: - sage: cf12 = CyclotomicField( 12 ) + sage: cf12 = CyclotomicField(12) sage: z12 = cf12.0 - sage: cf6 = CyclotomicField( 6 ) + sage: cf6 = CyclotomicField(6) sage: z6 = cf6.0 - sage: FF = Frac( cf12['x'] ) + sage: FF = Frac(cf12['x']) sage: x = FF.0 sage: z6*x^3/(z6 + x) zeta12^2*x^3/(x + zeta12^2) :: - sage: cf6 = CyclotomicField(6) ; z6 = cf6.gen(0) - sage: cf3 = CyclotomicField(3) ; z3 = cf3.gen(0) + sage: cf6 = CyclotomicField(6); z6 = cf6.gen(0) + sage: cf3 = CyclotomicField(3); z3 = cf3.gen(0) sage: cf3(z6) zeta3 + 1 sage: cf6(z3) zeta6 - 1 sage: type(cf6(z3)) <class 'sage.rings.number_field.number_field_element_quadratic.NumberFieldElement_quadratic'> - sage: cf1 = CyclotomicField(1) ; z1 = cf1.0 + sage: cf1 = CyclotomicField(1); z1 = cf1.0 sage: cf3(z1) 1 sage: type(cf3(z1)) @@ -10594,7 +10777,7 @@ class NumberField_cyclotomic(NumberField_absolute, sage.rings.abc.NumberField_cy """ def __init__(self, n, names, embedding=None, assume_disc_small=False, maximize_at_primes=None): """ - A cyclotomic field, i.e., a field obtained by adjoining an n-th + A cyclotomic field, i.e., a field obtained by adjoining an `n`-th root of unity to the rational numbers. EXAMPLES:: @@ -10751,10 +10934,10 @@ def _magma_init_(self, magma): EXAMPLES:: - sage: K=CyclotomicField(7,'z') # optional - magma + sage: K = CyclotomicField(7,'z') sage: K._magma_init_(magma) # optional - magma 'SageCreateWithNames(CyclotomicField(7),["z"])' - sage: K=CyclotomicField(7,'zeta') # optional - magma + sage: K = CyclotomicField(7,'zeta') sage: K._magma_init_(magma) # optional - magma 'SageCreateWithNames(CyclotomicField(7),["zeta"])' """ @@ -10800,9 +10983,9 @@ def _libgap_(self): TESTS:: sage: K = CyclotomicField(8) - sage: K._libgap_() + sage: K._libgap_() # needs sage.libs.gap CF(8) - sage: libgap(K) # indirect doctest + sage: libgap(K) # indirect doctest # needs sage.libs.gap CF(8) """ from sage.libs.gap.libgap import libgap @@ -10829,7 +11012,7 @@ def _repr_(self): def _n(self): """ - Return the n used to create this cyclotomic field. + Return the `n` used to create this cyclotomic field. EXAMPLES:: @@ -10849,7 +11032,7 @@ def _latex_(self): sage: Z = CyclotomicField(4) sage: Z.gen() zeta4 - sage: latex(Z) # indirect doctest + sage: latex(Z) # indirect doctest \Bold{Q}(\zeta_{4}) Latex printing respects the generator name:: @@ -10881,7 +11064,7 @@ def _latex_(self): def _coerce_map_from_(self, K): r""" - Return a coercion map from `K` to ``self``, or None. + Return a coercion map from `K` to ``self``, or ``None``. The cyclotomic field `\QQ(\zeta_n)` coerces into the cyclotomic field `\QQ(\zeta_m)` if and only if `n' \mid m`, @@ -10897,7 +11080,7 @@ def _coerce_map_from_(self, K): sage: K.<a> = CyclotomicField(12) sage: L.<b> = CyclotomicField(132) - sage: L.coerce_map_from(K) # indirect doctest + sage: L.coerce_map_from(K) # indirect doctest Generic morphism: From: Cyclotomic Field of order 12 and degree 4 To: Cyclotomic Field of order 132 and degree 40 @@ -10947,6 +11130,7 @@ def _coerce_map_from_(self, K): Check that custom embeddings are respected (:trac:`13765`):: + sage: # needs sage.symbolic sage: z105 = CDF(exp(2*pi*I/105)) sage: Ka.<a> = CyclotomicField(105, embedding=z105^11) sage: Kb.<b> = CyclotomicField(35, embedding=z105^6) @@ -10954,20 +11138,25 @@ def _coerce_map_from_(self, K): Generic morphism: From: Cyclotomic Field of order 35 and degree 24 To: Cyclotomic Field of order 105 and degree 48 - Defn: b -> -a^44 - a^42 + a^39 + a^37 + a^35 - a^29 - a^27 - a^25 + a^24 - a^23 + a^22 - a^21 + a^20 + a^18 + a^16 - a^12 - a^10 - a^8 - a^6 + a^5 + a^3 + a + Defn: b -> -a^44 - a^42 + a^39 + a^37 + a^35 - a^29 - a^27 - a^25 + a^24 + - a^23 + a^22 - a^21 + a^20 + a^18 + a^16 - a^12 - a^10 + - a^8 - a^6 + a^5 + a^3 + a sage: CC(b) 0.936234870639737 + 0.351374824081343*I - sage: CC(-a^44 - a^42 + a^39 + a^37 + a^35 - a^29 - a^27 - a^25 + a^24 - a^23 + a^22 - a^21 + a^20 + a^18 + a^16 - a^12 - a^10 - a^8 - a^6 + a^5 + a^3 + a) + sage: CC(-a^44 - a^42 + a^39 + a^37 + a^35 - a^29 - a^27 - a^25 + a^24 + ....: - a^23 + a^22 - a^21 + a^20 + a^18 + a^16 - a^12 - a^10 + ....: - a^8 - a^6 + a^5 + a^3 + a) 0.936234870639731 + 0.351374824081341*I - sage: z15 = CDF(exp(2*pi*I/15)) - sage: CyclotomicField(15).coerce_map_from(CyclotomicField(6, embedding=-z15^5)) + sage: z15 = CDF(exp(2*pi*I/15)) # needs sage.symbolic + sage: K6 = CyclotomicField(6, embedding=-z15^5) # needs sage.symbolic + sage: CyclotomicField(15).coerce_map_from(K6) # needs sage.symbolic Generic morphism: From: Cyclotomic Field of order 6 and degree 2 To: Cyclotomic Field of order 15 and degree 8 Defn: zeta6 -> -zeta15^5 - sage: CyclotomicField(15, embedding=z15^4).coerce_map_from(CyclotomicField(6, embedding=-z15^5)) + sage: CyclotomicField(15, embedding=z15^4).coerce_map_from(K6) # needs sage.symbolic Generic morphism: From: Cyclotomic Field of order 6 and degree 2 To: Cyclotomic Field of order 15 and degree 8 @@ -11015,13 +11204,13 @@ def _coerce_map_from_(self, K): def _log_gen(self, x): """ - Return an integer `e` such that `self.gen()^e == x`, or `None` + Return an integer `e` such that `self.gen()^e == x`, or ``None`` if no such integer exists. This is primarily used to construct embedding-respecting coercions. If `x` is complex, the result is either an integer `e` such - that the absolute value of `self.gen()^e-x` is small or - `None` if no such `e` is found. + that the absolute value of ``self.gen()^e - x`` is small or + ``None`` if no such `e` is found. EXAMPLES:: @@ -11031,25 +11220,30 @@ def _log_gen(self, x): sage: K._log_gen(CDF(a^4)) 4 + sage: # needs sage.symbolic sage: zeta105 = CC(exp(2*pi*i/105)) sage: K.<a> = CyclotomicField(105, embedding=zeta105^13) sage: zeta105^13, CC(a) - (0.712376096951345 + 0.701797902883992*I, 0.712376096951345 + 0.701797902883991*I) + (0.712376096951345 + 0.701797902883992*I, + 0.712376096951345 + 0.701797902883991*I) sage: K._log_gen(zeta105^26) 2 sage: K._log_gen(zeta105) 97 sage: zeta105, CC(a^97) - (0.998210129767735 + 0.0598041539450342*I, 0.998210129767736 + 0.0598041539450313*I) + (0.998210129767735 + 0.0598041539450342*I, + 0.998210129767736 + 0.0598041539450313*I) sage: K._log_gen(zeta105^3) 81 sage: zeta105^3, CC(a)^81 - (0.983929588598630 + 0.178556894798637*I, 0.983929588598631 + 0.178556894798635*I) + (0.983929588598630 + 0.178556894798637*I, + 0.983929588598631 + 0.178556894798635*I) sage: K.<a> = CyclotomicField(5, embedding=None) sage: K._log_gen(CDF(.5, -.8)) is None True + sage: # needs sage.rings.padics sage: zeta5 = cyclotomic_polynomial(5).change_ring(Qp(11)).roots()[0][0] sage: zeta5 ^ 5 1 + O(11^20) @@ -11102,22 +11296,21 @@ def _log_gen(self, x): gen_pow_e *= gen def _element_constructor_(self, x, check=True): - """ + r""" Create an element of this cyclotomic field from `x`. EXAMPLES: The following example illustrates coercion from the - cyclotomic field Q(zeta_42) to the cyclotomic field Q(zeta_6), in + cyclotomic field `\QQ(\zeta_{42})` to the cyclotomic field `\QQ(\zeta_6)`, in a case where such coercion is defined:: sage: k42 = CyclotomicField(42) sage: k6 = CyclotomicField(6) sage: a = k42.gen(0) - sage: b = a^7 - sage: b + sage: b = a^7; b zeta42^7 - sage: k6(b) # indirect doctest + sage: k6(b) # indirect doctest zeta6 sage: b^2 zeta42^7 - 1 @@ -11127,17 +11320,17 @@ def _element_constructor_(self, x, check=True): Conversion of elements of the :class:`~sage.rings.universal_cyclotomic_field.UniversalCyclotomicField`:: sage: CF = CyclotomicField(5) - sage: UCF.<E> = UniversalCyclotomicField() - sage: CF(E(5)) + sage: UCF.<E> = UniversalCyclotomicField() # needs sage.libs.gap + sage: CF(E(5)) # needs sage.libs.gap zeta5 sage: CF = CyclotomicField(10) - sage: CF(E(5)) + sage: CF(E(5)) # needs sage.libs.gap zeta10^2 - Coercion of GAP cyclotomic elements is also supported:: + Coercion of GAP cyclotomic elements is also supported:: - sage: CyclotomicField(18)(gap('E(3)')) # indirect doctest + sage: CyclotomicField(18)(gap('E(3)')) # indirect doctest # needs sage.libs.gap zeta18^3 - 1 Converting from rings of integers:: @@ -11170,21 +11363,21 @@ def _element_constructor_(self, x, check=True): def _coerce_from_other_cyclotomic_field(self, x, only_canonical=False): """ - Coerce an element x of a cyclotomic field into self, if at all + Coerce an element `x` of a cyclotomic field into ``self``, if at all possible. INPUT: - - ``x`` - number field element + - ``x`` -- number field element - - ``only_canonical`` - bool (default: ``False``); Attempt - to work, even in some cases when x is not in a subfield of the - cyclotomics (as long as x is a root of unity). + - ``only_canonical`` -- bool (default: ``False``); Attempt + to work, even in some cases when `x` is not in a subfield of the + cyclotomics (as long as `x` is a root of unity). EXAMPLES:: - sage: K = CyclotomicField(24) ; L = CyclotomicField(48) - sage: L._coerce_from_other_cyclotomic_field(K.0+1) + sage: K = CyclotomicField(24); L = CyclotomicField(48) + sage: L._coerce_from_other_cyclotomic_field(K.0 + 1) zeta48^2 + 1 sage: K(L.0**2) zeta24 @@ -11220,7 +11413,7 @@ def _coerce_from_other_cyclotomic_field(self, x, only_canonical=False): if z == x: return self.zeta(m)**(r+1) z *= y - raise TypeError("Cannot coerce %s into %s" % (x, self)) + raise TypeError("cannot coerce %s into %s" % (x, self)) return self._element_class(self, x) def _coerce_from_gap(self, x): @@ -11231,12 +11424,11 @@ def _coerce_from_gap(self, x): EXAMPLES:: sage: k5.<z> = CyclotomicField(5) - sage: w = libgap.eval('E(5)^7 + 3') - sage: w + sage: w = libgap.eval('E(5)^7 + 3'); w # needs sage.libs.gap -3*E(5)-2*E(5)^2-3*E(5)^3-3*E(5)^4 - sage: z^7 + 3 + sage: z^7 + 3 # needs sage.libs.gap z^2 + 3 - sage: k5(w) # indirect doctest + sage: k5(w) # indirect doctest # needs sage.libs.gap z^2 + 3 It may be that GAP uses a name for the generator of the cyclotomic field. @@ -11244,20 +11436,21 @@ def _coerce_from_gap(self, x): sage: F = CyclotomicField(8) sage: z = F.gen() - sage: a = libgap(z+1/z); a + sage: a = libgap(z + 1/z); a # needs sage.libs.gap E(8)-E(8)^3 - sage: F(a) + sage: F(a) # needs sage.libs.gap -zeta8^3 + zeta8 Matrices over cyclotomic fields are correctly dealt with it as well:: - sage: b = libgap.eval('[[E(4), 1], [0, 1+E(8)-E(8)^3]]') - sage: matrix(F, b) + sage: b = libgap.eval('[[E(4), 1], [0, 1+E(8)-E(8)^3]]') # needs sage.libs.gap + sage: matrix(F, b) # needs sage.libs.gap [ zeta8^2 1] [ 0 -zeta8^3 + zeta8 + 1] It also works with the old pexpect interface to GAP:: + sage: # needs sage.libs.gap sage: a = gap(z + 1/z) sage: b = gap(Matrix(F,[[z^2,1],[0,a+1]])); b [ [ E(4), 1 ], [ 0, 1+E(8)-E(8)^3 ] ] @@ -11277,10 +11470,10 @@ def _coerce_from_gap(self, x): def _Hom_(self, codomain, cat=None): """ - Return homset of homomorphisms from the cyclotomic field self to + Return homset of homomorphisms from the cyclotomic field ``self`` to the number field codomain. - The cat option is currently ignored. + The ``cat`` option is currently ignored. EXAMPLES: @@ -11289,10 +11482,13 @@ def _Hom_(self, codomain, cat=None): :: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 3); K Number Field in a with defining polynomial x^2 + 3 - sage: CyclotomicField(3).Hom(K) # indirect doctest - Set of field embeddings from Cyclotomic Field of order 3 and degree 2 to Number Field in a with defining polynomial x^2 + 3 + sage: CyclotomicField(3).Hom(K) # indirect doctest + Set of field embeddings + from Cyclotomic Field of order 3 and degree 2 + to Number Field in a with defining polynomial x^2 + 3 sage: End(CyclotomicField(21)) Automorphism group of Cyclotomic Field of order 21 and degree 12 """ @@ -11304,7 +11500,7 @@ def _Hom_(self, codomain, cat=None): def is_galois(self): """ - Return True since all cyclotomic fields are automatically Galois. + Return ``True`` since all cyclotomic fields are automatically Galois. EXAMPLES:: @@ -11315,7 +11511,7 @@ def is_galois(self): def is_abelian(self): """ - Return True since all cyclotomic fields are automatically abelian. + Return ``True`` since all cyclotomic fields are automatically abelian. EXAMPLES:: @@ -11326,8 +11522,8 @@ def is_abelian(self): def is_isomorphic(self, other): """ - Return True if the cyclotomic field self is isomorphic as a number - field to other. + Return ``True`` if the cyclotomic field ``self`` is isomorphic as a number + field to ``other``. EXAMPLES:: @@ -11335,7 +11531,8 @@ def is_isomorphic(self, other): True sage: CyclotomicField(11).is_isomorphic(CyclotomicField(23)) False - sage: CyclotomicField(3).is_isomorphic(NumberField(x^2 + x +1, 'a')) + sage: x = polygen(QQ, 'x') + sage: CyclotomicField(3).is_isomorphic(NumberField(x^2 + x + 1, 'a')) True sage: CyclotomicField(18).is_isomorphic(CyclotomicField(9)) True @@ -11345,7 +11542,7 @@ def is_isomorphic(self, other): Check :trac:`14300`:: sage: K = CyclotomicField(4) - sage: N = K.extension(x^2-5, 'z') + sage: N = K.extension(x^2 - 5, 'z') sage: K.is_isomorphic(N) False sage: K.is_isomorphic(CyclotomicField(8)) @@ -11358,8 +11555,8 @@ def is_isomorphic(self, other): def complex_embedding(self, prec=53): r""" Return the embedding of this cyclotomic field into the approximate - complex field with precision prec obtained by sending the generator - `\zeta` of self to exp(2\*pi\*i/n), where `n` is + complex field with precision ``prec`` obtained by sending the generator + `\zeta` of ``self`` to exp(2\*pi\*i/n), where `n` is the multiplicative order of `\zeta`. EXAMPLES:: @@ -11371,8 +11568,8 @@ def complex_embedding(self, prec=53): To: Complex Field with 53 bits of precision Defn: zeta4 |--> 6.12323399573677e-17 + 1.00000000000000*I - Note in the example above that the way zeta is computed (using sin - and cosine in MPFR) means that only the prec bits of the number + Note in the example above that the way zeta is computed (using sine + and cosine in MPFR) means that only the ``prec`` bits of the number after the decimal point are valid. :: @@ -11394,7 +11591,7 @@ def complex_embedding(self, prec=53): @cached_method def embeddings(self, K): r""" - Compute all field embeddings of this field into the field ``K``. + Compute all field embeddings of this field into the field `K`. INPUT: @@ -11407,7 +11604,7 @@ def embeddings(self, K): From: Cyclotomic Field of order 5 and degree 4 To: Complex Field with 53 bits of precision Defn: zeta5 |--> -0.809016994374947 + 0.587785252292473*I - sage: CyclotomicField(5).embeddings(Qp(11, 4, print_mode='digits'))[1] + sage: CyclotomicField(5).embeddings(Qp(11, 4, print_mode='digits'))[1] # needs sage.rings.padics Ring morphism: From: Cyclotomic Field of order 5 and degree 4 To: 11-adic Field with capped relative precision 4 @@ -11434,7 +11631,7 @@ def embeddings(self, K): def complex_embeddings(self, prec=53): r""" Return all embeddings of this cyclotomic field into the approximate - complex field with precision prec. + complex field with precision ``prec``. If you want 53-bit double precision, which is faster but less reliable, then do ``self.embeddings(CDF)``. @@ -11467,7 +11664,7 @@ def complex_embeddings(self, prec=53): def real_embeddings(self, prec=53): r""" Return all embeddings of this cyclotomic field into the approximate - real field with precision prec. + real field with precision ``prec``. Mostly, of course, there are no such embeddings. @@ -11487,12 +11684,12 @@ def real_embeddings(self, prec=53): return self.embeddings(K) def signature(self): - """ - Return (r1, r2), where r1 and r2 are the number of real embeddings + r""" + Return `(r_1, r_2)`, where `r_1` and `r_2` are the number of real embeddings and pairs of complex embeddings of this cyclotomic field, respectively. - Trivial since, apart from QQ, cyclotomic fields are totally + Trivial since, apart from `\QQ`, cyclotomic fields are totally complex. EXAMPLES:: @@ -11510,7 +11707,7 @@ def signature(self): def different(self): """ - Return the different ideal of the cyclotomic field self. + Return the different ideal of the cyclotomic field ``self``. EXAMPLES:: @@ -11542,20 +11739,17 @@ def different(self): def discriminant(self, v=None): """ Return the discriminant of the ring of integers of the cyclotomic - field self, or if v is specified, the determinant of the trace - pairing on the elements of the list v. + field ``self``, or if ``v`` is specified, the determinant of the trace + pairing on the elements of the list ``v``. Uses the formula for the discriminant of a prime power cyclotomic field and Hilbert Theorem 88 on the discriminant of composita. INPUT: + - ``v`` -- (optional) list of elements of this number field - - ``v (optional)`` - list of element of this number - field - - - OUTPUT: Integer if v is omitted, and Rational otherwise. + OUTPUT: Integer if ``v`` is omitted, and Rational otherwise. EXAMPLES:: @@ -11651,8 +11845,8 @@ def zeta_order(self): return self.__zeta_order def _multiplicative_order_table(self): - """ - Return a dictionary that maps powers of zeta to their order. This + r""" + Return a dictionary that maps powers of `\zeta` to their order. This makes computing the orders of the elements of finite order in this field faster. @@ -11683,14 +11877,14 @@ def zeta(self, n=None, all=False): Return an element of multiplicative order `n` in this cyclotomic field. - If there is no such element, raise a ``ValueError``. + If there is no such element, raise a :class:`ValueError`. INPUT: - ``n`` -- integer (default: ``None``, returns element of maximal order) - - ``all`` -- bool (default: ``False``) - whether to return + - ``all`` -- bool (default: ``False``); whether to return a list of all primitive `n`-th roots of unity. OUTPUT: root of unity or list @@ -11851,8 +12045,8 @@ def __init__(self, polynomial, name=None, latex_name=None, check=True, embedding Check that :trac:`23008` is fixed:: sage: z = polygen(ZZ, 'z') - sage: K.<phi> = NumberField(z^2 - z - 1, embedding=QQbar(golden_ratio)) - sage: floor(phi) + sage: K.<phi> = NumberField(z^2 - z - 1, embedding=QQbar(golden_ratio)) # needs sage.symbolic + sage: floor(phi) # needs sage.symbolic 1 """ NumberField_absolute.__init__(self, polynomial, name=name, check=check, @@ -11902,7 +12096,7 @@ def _coerce_map_from_(self, K): EXAMPLES:: sage: K.<a> = QuadraticField(-3) - sage: f = K.coerce_map_from(QQ); f # indirect doctest + sage: f = K.coerce_map_from(QQ); f # indirect doctest Natural morphism: From: Rational Field To: Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I @@ -11911,7 +12105,7 @@ def _coerce_map_from_(self, K): sage: parent(f(3/5)) is K True - sage: g = K.coerce_map_from(ZZ); g # indirect doctest + sage: g = K.coerce_map_from(ZZ); g # indirect doctest Natural morphism: From: Integer Ring To: Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I @@ -11935,11 +12129,11 @@ def _latex_(self): EXAMPLES:: sage: Z = QuadraticField(7) - sage: latex(Z) # indirect doctest + sage: latex(Z) # indirect doctest \Bold{Q}(\sqrt{7}) sage: Z = QuadraticField(7, latex_name='x') - sage: latex(Z) # indirect doctest + sage: latex(Z) # indirect doctest \Bold{Q}[x]/(x^{2} - 7) """ v = self.latex_variable_names()[0] @@ -11958,7 +12152,7 @@ def _polymake_init_(self): EXAMPLES:: sage: Z = QuadraticField(7) - sage: polymake(Z) # optional - jupymake # indirect doctest + sage: polymake(Z) # optional - jupymake # indirect doctest QuadraticExtension """ @@ -11967,27 +12161,27 @@ def _polymake_init_(self): def discriminant(self, v=None): """ Return the discriminant of the ring of integers of the number - field, or if v is specified, the determinant of the trace pairing - on the elements of the list v. + field, or if ``v`` is specified, the determinant of the trace pairing + on the elements of the list ``v``. INPUT: - - ``v (optional)`` - list of element of this number - field + - ``v`` -- (optional) list of element of this number field - OUTPUT: Integer if v is omitted, and Rational otherwise. + OUTPUT: Integer if ``v`` is omitted, and Rational otherwise. EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) + sage: x = polygen(QQ, 'x') + sage: K.<i> = NumberField(x^2 + 1) sage: K.discriminant() -4 - sage: K.<a> = NumberField(x^2+5) + sage: K.<a> = NumberField(x^2 + 5) sage: K.discriminant() -20 - sage: K.<a> = NumberField(x^2-5) + sage: K.<a> = NumberField(x^2 - 5) sage: K.discriminant() 5 """ @@ -12005,7 +12199,7 @@ def discriminant(self, v=None): def is_galois(self): """ - Return True since all quadratic fields are automatically Galois. + Return ``True`` since all quadratic fields are automatically Galois. EXAMPLES:: @@ -12016,7 +12210,7 @@ def is_galois(self): def class_number(self, proof=None): r""" - Return the size of the class group of self. + Return the size of the class group of ``self``. INPUT: @@ -12041,7 +12235,8 @@ def class_number(self, proof=None): These are all the primes so that the class number of `\QQ(\sqrt{-p})` is `1`:: - sage: [d for d in prime_range(2,300) if not is_square(d) and QuadraticField(-d,'a').class_number() == 1] + sage: [d for d in prime_range(2,300) + ....: if not is_square(d) and QuadraticField(-d,'a').class_number() == 1] [2, 3, 7, 11, 19, 43, 67, 163] It is an open problem to *prove* that there are infinity many @@ -12050,13 +12245,15 @@ def class_number(self, proof=None): :: - sage: len([d for d in range(2,200) if not is_square(d) and QuadraticField(d,'a').class_number() == 1]) + sage: len([d for d in range(2,200) + ....: if not is_square(d) and QuadraticField(d,'a').class_number() == 1]) 121 TESTS:: sage: type(QuadraticField(-23,'a').class_number()) <class 'sage.rings.integer.Integer'> + sage: x = polygen(QQ, 'x') sage: type(NumberField(x^3 + 23, 'a').class_number()) <class 'sage.rings.integer.Integer'> sage: type(NumberField(x^3 + 23, 'a').extension(x^2 + 5, 'b').class_number()) @@ -12101,7 +12298,9 @@ def hilbert_class_field_defining_polynomial(self, name='x'): sage: K.class_number() 21 sage: K.hilbert_class_field_defining_polynomial(name='z') - z^21 + 6*z^20 + 9*z^19 - 4*z^18 + 33*z^17 + 140*z^16 + 220*z^15 + 243*z^14 + 297*z^13 + 461*z^12 + 658*z^11 + 743*z^10 + 722*z^9 + 681*z^8 + 619*z^7 + 522*z^6 + 405*z^5 + 261*z^4 + 119*z^3 + 35*z^2 + 7*z + 1 + z^21 + 6*z^20 + 9*z^19 - 4*z^18 + 33*z^17 + 140*z^16 + 220*z^15 + 243*z^14 + + 297*z^13 + 461*z^12 + 658*z^11 + 743*z^10 + 722*z^9 + 681*z^8 + 619*z^7 + + 522*z^6 + 405*z^5 + 261*z^4 + 119*z^3 + 35*z^2 + 7*z + 1 """ f = pari(self.discriminant()).quadhilbert() return QQ[name](f) @@ -12114,17 +12313,19 @@ def hilbert_class_field(self, names): .. note:: For the polynomial that defines this field as a relative - extension, see the ``hilbert_class_field_defining_polynomial`` - command, which is vastly faster than this command, since it doesn't + extension, see the method :meth:`hilbert_class_field_defining_polynomial`, + which is vastly faster than this method, since it doesn't construct a relative extension. EXAMPLES:: + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^2 + 23) sage: L = K.hilbert_class_field('b'); L Number Field in b with defining polynomial x^3 - x^2 + 1 over its base field sage: L.absolute_field('c') - Number Field in c with defining polynomial x^6 - 2*x^5 + 70*x^4 - 90*x^3 + 1631*x^2 - 1196*x + 12743 + Number Field in c with defining polynomial + x^6 - 2*x^5 + 70*x^4 - 90*x^3 + 1631*x^2 - 1196*x + 12743 sage: K.hilbert_class_field_defining_polynomial() x^3 - x^2 + 1 """ @@ -12153,14 +12354,14 @@ def hilbert_class_polynomial(self, name='x'): if D > 0: raise NotImplementedError("Hilbert class polynomial is not implemented for real quadratic fields.") - from sage.schemes.elliptic_curves.all import hilbert_class_polynomial as HCP + from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial as HCP return QQ[name](HCP(D)) def number_of_roots_of_unity(self): """ Return the number of roots of unity in this quadratic field. - This is always 2 except when d is -3 or -4. + This is always 2 except when `d` is `-3` or `-4`. EXAMPLES:: @@ -12175,10 +12376,35 @@ def number_of_roots_of_unity(self): return 6 return 2 + def order_of_conductor(self, f): + r""" + Return the unique order with the given conductor in this quadratic field. + + .. SEEALSO :: + + :meth:`sage.rings.number_field.order.Order.conductor` + + EXAMPLES:: + + sage: K.<t> = QuadraticField(-123) + sage: K.order_of_conductor(1) is K.maximal_order() + True + sage: K.order_of_conductor(2).gens() + (1, t) + sage: K.order_of_conductor(44).gens() + (1, 22*t) + sage: K.order_of_conductor(9001).conductor() + 9001 + """ + f = ZZ(f) + if f <= 0: + raise ValueError('conductor must be a positive integer') + return self.order([f * g for g in self.maximal_order().gens()]) + def is_fundamental_discriminant(D): r""" - Return True if the integer `D` is a fundamental + Return ``True`` if the integer `D` is a fundamental discriminant, i.e., if `D \cong 0,1\pmod{4}`, and `D\neq 0, 1` and either (1) `D` is square free or (2) we have `D\cong 0\pmod{4}` with @@ -12188,16 +12414,17 @@ def is_fundamental_discriminant(D): EXAMPLES:: sage: [D for D in range(-15,15) if is_fundamental_discriminant(D)] + ... + DeprecationWarning: is_fundamental_discriminant(D) is deprecated; + please use D.is_fundamental_discriminant() + ... [-15, -11, -8, -7, -4, -3, 5, 8, 12, 13] - sage: [D for D in range(-15,15) if not is_square(D) and QuadraticField(D,'a').disc() == D] + sage: [D for D in range(-15,15) + ....: if not is_square(D) and QuadraticField(D,'a').disc() == D] [-15, -11, -8, -7, -4, -3, 5, 8, 12, 13] """ - d = D % 4 - if d not in [0, 1]: - return False - return D != 1 and D != 0 and \ - (arith.is_squarefree(D) or - (d == 0 and (D // 4) % 4 in [2, 3] and arith.is_squarefree(D // 4))) + deprecation(35147, "is_fundamental_discriminant(D) is deprecated; please use D.is_fundamental_discriminant()") + return Integer(D).is_fundamental_discriminant() ################### @@ -12255,7 +12482,9 @@ def put_natural_embedding_first(v): """ Helper function for embeddings() functions for number fields. - INPUT: a list of embeddings of a number field + INPUT: + + - ``v`` -- a list of embeddings of a number field OUTPUT: ``None``. The list is altered in-place, so that, if possible, the first embedding @@ -12267,19 +12496,19 @@ def put_natural_embedding_first(v): sage: K.<a> = CyclotomicField(7) sage: embs = K.embeddings(K) - sage: [e(a) for e in embs] # random - there is no natural sort order + sage: [e(a) for e in embs] # random - there is no natural sort order [a, a^2, a^3, a^4, a^5, -a^5 - a^4 - a^3 - a^2 - a - 1] - sage: id = [ e for e in embs if e(a) == a ][0]; id + sage: id = [e for e in embs if e(a) == a][0]; id Ring endomorphism of Cyclotomic Field of order 7 and degree 6 Defn: a |--> a sage: permuted_embs = list(embs); permuted_embs.remove(id); permuted_embs.append(id) - sage: [e(a) for e in permuted_embs] # random - but natural map is not first + sage: [e(a) for e in permuted_embs] # random - but natural map is not first [a^2, a^3, a^4, a^5, -a^5 - a^4 - a^3 - a^2 - a - 1, a] sage: permuted_embs[0] != a True sage: from sage.rings.number_field.number_field import put_natural_embedding_first sage: put_natural_embedding_first(permuted_embs) - sage: [e(a) for e in permuted_embs] # random - but natural map is first + sage: [e(a) for e in permuted_embs] # random - but natural map is first [a, a^3, a^4, a^5, -a^5 - a^4 - a^3 - a^2 - a - 1, a^2] sage: permuted_embs[0] == id True @@ -12297,15 +12526,15 @@ def put_natural_embedding_first(v): def refine_embedding(e, prec=None): r""" Given an embedding from a number field to either `\RR` or - `\CC`, returns an equivalent embedding with higher precision. + `\CC`, return an equivalent embedding with higher precision. INPUT: - - ``e`` - an embedding of a number field into either - RR or CC (with some precision) + - ``e`` -- an embedding of a number field into either + `\RR` or `\CC` (with some precision) - - ``prec`` - (default None) the desired precision; if None, - current precision is doubled; if Infinity, the equivalent + - ``prec`` -- (default ``None``) the desired precision; if ``None``, + current precision is doubled; if ``Infinity``, the equivalent embedding into either ``QQbar`` or ``AA`` is returned. EXAMPLES:: @@ -12321,7 +12550,8 @@ def refine_embedding(e, prec=None): An example where we extend a real embedding into ``AA``:: - sage: K.<a> = NumberField(x^3-2) + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: K.signature() (1, 1) sage: e = K.embeddings(RR)[0]; e @@ -12329,7 +12559,7 @@ def refine_embedding(e, prec=None): From: Number Field in a with defining polynomial x^3 - 2 To: Real Field with 53 bits of precision Defn: a |--> 1.25992104989487 - sage: e = refine_embedding(e,Infinity); e + sage: e = refine_embedding(e, Infinity); e Ring morphism: From: Number Field in a with defining polynomial x^3 - 2 To: Algebraic Real Field @@ -12341,7 +12571,7 @@ def refine_embedding(e, prec=None): 1.2599210498948731647672106072782283505702515 sage: _^3 2.0000000000000000000000000000000000000000000 - sage: RealField(200)(e(a^2-3*a+7)) + sage: RealField(200)(e(a^2 - 3*a + 7)) 4.8076379022835799804500738174376232086807389337953290695624 Complex embeddings can be extended into ``QQbar``:: @@ -12357,7 +12587,8 @@ def refine_embedding(e, prec=None): To: Algebraic Field Defn: a |--> -0.6299605249474365? - 1.091123635971722?*I sage: ComplexField(200)(e(a)) - -0.62996052494743658238360530363911417528512573235075399004099 - 1.0911236359717214035600726141898088813258733387403009407036*I + -0.62996052494743658238360530363911417528512573235075399004099 + - 1.0911236359717214035600726141898088813258733387403009407036*I sage: e(a)^3 2 @@ -12373,7 +12604,8 @@ def refine_embedding(e, prec=None): Ring morphism: From: Cyclotomic Field of order 7 and degree 6 To: Complex Field with 300 bits of precision - Defn: zeta7 |--> 0.623489801858733530525004884004239810632274730896402105365549439096853652456487284575942507 + 0.781831482468029808708444526674057750232334518708687528980634958045091731633936441700868007*I + Defn: zeta7 |--> 0.623489801858733530525004884004239810632274730896402105365549439096853652456487284575942507 + + 0.781831482468029808708444526674057750232334518708687528980634958045091731633936441700868007*I sage: refine_embedding(x, infinity) Ring morphism: From: Cyclotomic Field of order 7 and degree 6 @@ -12435,11 +12667,11 @@ def refine_embedding(e, prec=None): def is_real_place(v): r""" - Return ``True`` if ``v`` is real, ``False`` if ``v`` is complex + Return ``True`` if `v` is real, ``False`` if `v` is complex INPUT: - - ``v`` -- an infinite place of ``K`` + - ``v`` -- an infinite place of ``self`` OUTPUT: @@ -12447,7 +12679,8 @@ def is_real_place(v): EXAMPLES:: - sage: K.<xi> = NumberField(x^3-3) + sage: x = polygen(QQ, 'x') + sage: K.<xi> = NumberField(x^3 - 3) sage: phi_real = K.places()[0] sage: phi_complex = K.places()[1] sage: v_fin = tuple(K.primes_above(3))[0] @@ -12480,7 +12713,7 @@ def _splitting_classes_gens_(K, m, d): r""" Given a number field `K` of conductor `m` and degree `d`, this returns a set of multiplicative generators of the - subgroup of `(\mathbb{Z}/m\mathbb{Z})^{\times}` + subgroup of `(\ZZ/m\ZZ)^{\times}` containing exactly the classes that contain the primes splitting completely in `K`. @@ -12504,7 +12737,8 @@ def _splitting_classes_gens_(K, m, d): sage: K.degree() 20 sage: L - Number Field in zeta44_0 with defining polynomial x^5 - 2*x^4 - 16*x^3 + 24*x^2 + 48*x - 32 with zeta44_0 = 3.837971894457990? + Number Field in zeta44_0 with defining polynomial x^5 - 2*x^4 - 16*x^3 + 24*x^2 + 48*x - 32 + with zeta44_0 = 3.837971894457990? sage: L.conductor() 11 sage: _splitting_classes_gens_(L,11,5) @@ -12534,7 +12768,7 @@ def map_Zmstar_to_Zm(h): p = u.lift() while not p.is_prime(): p += m - f = R.ideal(p).prime_factors()[0].residue_class_degree() + f = K.fractional_ideal(p).prime_factors()[0].residue_class_degree() h = g**f if h not in H: Hgens += [h] diff --git a/src/sage/rings/number_field/number_field_base.pyx b/src/sage/rings/number_field/number_field_base.pyx index 26d09cf9ed3..1d09825477a 100644 --- a/src/sage/rings/number_field/number_field_base.pyx +++ b/src/sage/rings/number_field/number_field_base.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.number_field """ Base class for all number fields @@ -11,29 +12,41 @@ TESTS:: def is_NumberField(x): """ - Return True if x is of number field type. + Return ``True`` if ``x`` is of number field type. + + This function is deprecated. EXAMPLES:: sage: from sage.rings.number_field.number_field_base import is_NumberField - sage: is_NumberField(NumberField(x^2+1,'a')) + sage: is_NumberField(NumberField(x^2 + 1, 'a')) + doctest:...: DeprecationWarning: the function is_NumberField is deprecated; use + isinstance(x, sage.rings.number_field.number_field_base.NumberField) instead + See https://github.com/sagemath/sage/issues/35283 for details. True - sage: is_NumberField(QuadraticField(-97,'theta')) + sage: is_NumberField(QuadraticField(-97, 'theta')) True sage: is_NumberField(CyclotomicField(97)) True - Note that the rational numbers QQ are a number field.:: + Note that the rational numbers ``QQ`` are a number field.:: sage: is_NumberField(QQ) True sage: is_NumberField(ZZ) False """ + from sage.misc.superseded import deprecation + deprecation(35283, + "the function is_NumberField is deprecated; use " + "isinstance(x, sage.rings.number_field.number_field_base.NumberField) instead") + return isinstance(x, NumberField) + from sage.rings.ring cimport Field + cdef class NumberField(Field): r""" Base class for all number fields. @@ -122,17 +135,19 @@ cdef class NumberField(Field): else: codomain_other = other - from sage.rings.qqbar import AA - if codomain_self is AA and codomain_other is AA: - return AA - - from sage.rings.qqbar import QQbar - if codomain_self in (AA, QQbar) and codomain_other in (AA, QQbar): - return QQbar + try: + from sage.rings.qqbar import AA, QQbar + except ImportError: + pass + else: + if codomain_self is AA and codomain_other is AA: + return AA + if codomain_self in (AA, QQbar) and codomain_other in (AA, QQbar): + return QQbar def ring_of_integers(self, *args, **kwds): r""" - Synonym for ``self.maximal_order(...)``. + Synonym for :meth:`maximal_order`. EXAMPLES:: @@ -144,7 +159,7 @@ cdef class NumberField(Field): def OK(self, *args, **kwds): r""" - Synonym for ``self.maximal_order(...)``. + Synonym for :meth:`maximal_order`. EXAMPLES:: @@ -154,7 +169,7 @@ cdef class NumberField(Field): return self.maximal_order(*args, **kwds) def maximal_order(self): - """ + r""" Return the maximal order, i.e., the ring of integers of this number field. @@ -166,8 +181,8 @@ cdef class NumberField(Field): raise NotImplementedError def is_absolute(self): - """ - Return True if self is viewed as a single extension over Q. + r""" + Return ``True`` if ``self`` is viewed as a single extension over `\QQ`. EXAMPLES:: @@ -184,8 +199,8 @@ cdef class NumberField(Field): raise NotImplementedError def signature(self): - """ - Return (r1, r2), where r1 and r2 are the number of real embeddings + r""" + Return `(r_1, r_2)`, where `r_1` and `r_2` are the number of real embeddings and pairs of complex embeddings of this field, respectively. EXAMPLES:: @@ -221,9 +236,9 @@ cdef class NumberField(Field): r""" Return the Minkowski bound associated to this number field. - This is a bound B so that every integral ideal is equivalent + This is a bound `B` so that every integral ideal is equivalent modulo principal fractional ideals to an integral ideal of - norm at most B. + norm at most `B`. .. SEEALSO:: @@ -296,9 +311,9 @@ cdef class NumberField(Field): r""" Return the Bach bound associated to this number field. - Assuming the General Riemann Hypothesis, this is a bound B so + Assuming the General Riemann Hypothesis, this is a bound `B` so that every integral ideal is equivalent modulo principal - fractional ideals to an integral ideal of norm at most B. + fractional ideals to an integral ideal of norm at most `B`. .. SEEALSO:: @@ -332,7 +347,8 @@ cdef class NumberField(Field): sage: K.bach_bound().n() 191669.304126267 - The bound of course also works for the rational numbers: + The bound of course also works for the rational numbers:: + sage: QQ.minkowski_bound() 1 """ @@ -407,7 +423,7 @@ cdef class NumberField(Field): If a real embedding is not specified, this method will result in an error:: - sage: N.<g> = NumberField(x^3+2) + sage: N.<g> = NumberField(x^3 + 2) sage: N._get_embedding_approx(1) Traceback (most recent call last): ... @@ -435,7 +451,7 @@ cdef class NumberField(Field): def _matrix_charpoly(self, M, var): r""" - Use PARI to compute the characteristic polynomial of self as a + Use PARI to compute the characteristic polynomial of ``self`` as a polynomial over the base ring. EXAMPLES:: diff --git a/src/sage/rings/number_field/number_field_element.pxd b/src/sage/rings/number_field/number_field_element.pxd index d7e62edf18c..c3d8a8b4a4b 100644 --- a/src/sage/rings/number_field/number_field_element.pxd +++ b/src/sage/rings/number_field/number_field_element.pxd @@ -1,21 +1,22 @@ cimport sage.structure.element from sage.libs.gmp.types cimport mpz_t from sage.rings.integer cimport Integer +from sage.rings.number_field.number_field_element_base cimport NumberFieldElement_base from sage.rings.polynomial.polynomial_element cimport Polynomial -from sage.structure.element cimport FieldElement, RingElement, ModuleElement from sage.structure.parent cimport Parent from sage.structure.parent_base cimport ParentWithBase from sage.libs.ntl.types cimport ZZ_c, ZZX_c from sage.libs.ntl.ntl_ZZX cimport ntl_ZZX from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ -cdef class NumberFieldElement(FieldElement): - cdef ZZX_c __numerator - cdef ZZ_c __denominator + +cdef class NumberFieldElement(NumberFieldElement_base): + cdef ZZX_c _numerator + cdef ZZ_c _denominator # Pointers to the defining polynomial (with numerator) for the field. # I keep these as pointers for arithmetic speed. - cdef ntl_ZZX __fld_numerator - cdef ntl_ZZ __fld_denominator + cdef ntl_ZZX _fld_numerator + cdef ntl_ZZ _fld_denominator cdef object __multiplicative_order cdef object __pari cdef object __matrix diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 09a51a1264a..749b10437f3 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ """ -Number Field Elements +Number field elements (implementation using NTL) AUTHORS: @@ -36,7 +36,7 @@ AUTHORS: import operator -from cpython.int cimport * +from cpython.long cimport * from cysignals.signals cimport sig_on, sig_off from sage.ext.stdsage cimport PY_NEW @@ -45,7 +45,7 @@ include "sage/libs/ntl/decl.pxi" from sage.libs.gmp.mpz cimport * from sage.libs.gmp.mpq cimport * -from sage.libs.mpfi cimport mpfi_t, mpfi_init, mpfi_set, mpfi_clear, mpfi_div_z, mpfi_init2, mpfi_get_prec, mpfi_set_prec +from sage.libs.mpfi cimport mpfi_t, mpfi_clear, mpfi_div_z, mpfi_init2, mpfi_get_prec, mpfi_set_prec from sage.libs.mpfr cimport mpfr_equal_p, mpfr_less_p, mpfr_greater_p, mpfr_greaterequal_p, mpfr_floor, mpfr_get_z, MPFR_RNDN from sage.libs.ntl.error import NTLError from sage.libs.ntl.convert cimport mpz_to_ZZ @@ -67,12 +67,10 @@ from sage.rings.real_mpfi cimport RealIntervalFieldElement cimport sage.rings.number_field.number_field_base as number_field_base -from sage.rings.integer_ring cimport IntegerRing_class from sage.rings.rational cimport Rational from sage.rings.infinity import infinity from sage.categories.fields import Fields from sage.misc.superseded import deprecation -from sage.modules.free_module_element import vector from sage.structure.element cimport Element, FieldElement from sage.structure.element cimport parent @@ -101,67 +99,41 @@ TUNE_CHARPOLY_NF = 25 def is_NumberFieldElement(x): """ - Return True if x is of type NumberFieldElement, i.e., an element of + Return ``True`` if `x` is of type :class:`NumberFieldElement`, i.e., an element of a number field. EXAMPLES:: sage: from sage.rings.number_field.number_field_element import is_NumberFieldElement sage: is_NumberFieldElement(2) + doctest:warning... + DeprecationWarning: is_NumberFieldElement is deprecated; + use isinstance(..., sage.structure.element.NumberFieldElement) instead + See https://github.com/sagemath/sage/issues/34931 for details. False + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^7 + 17*x + 1) sage: is_NumberFieldElement(a+1) True """ + from sage.misc.superseded import deprecation + deprecation(34931, + 'is_NumberFieldElement is deprecated; ' + 'use isinstance(..., sage.structure.element.NumberFieldElement) instead') return isinstance(x, NumberFieldElement) -def __create__NumberFieldElement_version0(parent, poly): - """ - Used in unpickling elements of number fields pickled under very old Sage versions. - - TESTS:: - - sage: k.<a> = NumberField(x^3 - 2) - sage: R.<z> = QQ[] - sage: sage.rings.number_field.number_field_element.__create__NumberFieldElement_version0(k, z^2 + z + 1) - doctest:...: DeprecationWarning: __create__NumberFieldElement_version0() is deprecated - See https://github.com/sagemath/sage/issues/25848 for details. - a^2 + a + 1 - """ - from sage.misc.superseded import deprecation_cython as deprecation - deprecation(25848, '__create__NumberFieldElement_version0() is deprecated') - return NumberFieldElement(parent, poly) - - -def __create__NumberFieldElement_version1(parent, cls, poly): - """ - Used in unpickling elements of number fields pickled under old Sage versions. - - TESTS:: - - sage: k.<a> = NumberField(x^3 - 2) - sage: R.<z> = QQ[] - sage: sage.rings.number_field.number_field_element.__create__NumberFieldElement_version1(k, type(a), z^2 + z + 1) - doctest:...: DeprecationWarning: __create__NumberFieldElement_version1() is deprecated - See https://github.com/sagemath/sage/issues/25848 for details. - a^2 + a + 1 - """ - from sage.misc.superseded import deprecation_cython as deprecation - deprecation(25848, '__create__NumberFieldElement_version1() is deprecated') - return cls(parent, poly) - - def _inverse_mod_generic(elt, I): r""" - Return an inverse of elt modulo the given ideal. This is a separate - function called from each of the OrderElement_xxx classes, since + Return an inverse of ``elt`` modulo the given ideal. This is a separate + function called from each of the ``OrderElement_xxx`` classes, since otherwise we'd have to have the same code three times over (there - is no OrderElement_generic class - no multiple inheritance). See + is no ``OrderElement_generic`` class - no multiple inheritance). See :trac:`4190`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: OE.<w> = EquationOrder(x^3 - x + 2) sage: from sage.rings.number_field.number_field_element import _inverse_mod_generic sage: _inverse_mod_generic(w, 13*OE) @@ -169,9 +141,8 @@ def _inverse_mod_generic(elt, I): """ from sage.matrix.constructor import matrix R = elt.parent() - try: - I = R.ideal(I) - except ValueError: + I = R.number_field().fractional_ideal(I) + if not I.is_integral(): raise ValueError("inverse is only defined modulo integral ideals") if I == 0: raise ValueError("inverse is not defined modulo the zero ideal") @@ -184,18 +155,19 @@ def _inverse_mod_generic(elt, I): raise ZeroDivisionError("%s is not invertible modulo %s" % (elt, I)) v = R.coordinates(1) y = R(0) - for j in xrange(n): + for j in range(n): if v[j] != 0: - y += v[j] * sum([b[j,i+n] * B[i] for i in xrange(n)]) + y += v[j] * sum([b[j,i+n] * B[i] for i in range(n)]) return I.small_residue(y) -cdef class NumberFieldElement(FieldElement): +cdef class NumberFieldElement(NumberFieldElement_base): """ An element of a number field. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^3 + x + 1) sage: a^3 -a - 1 @@ -208,8 +180,8 @@ cdef class NumberFieldElement(FieldElement): cdef type t = type(self) cdef NumberFieldElement x = <NumberFieldElement>t.__new__(t) x._parent = self._parent - x.__fld_numerator = self.__fld_numerator - x.__fld_denominator = self.__fld_denominator + x._fld_numerator = self._fld_numerator + x._fld_denominator = self._fld_denominator return x cdef number_field(self): @@ -218,6 +190,7 @@ cdef class NumberFieldElement(FieldElement): Return the number field of self. Only accessible from Cython. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 3) sage: a._number_field() # indirect doctest Number Field in a with defining polynomial x^3 + 3 @@ -228,6 +201,7 @@ cdef class NumberFieldElement(FieldElement): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 3) sage: a._number_field() Number Field in a with defining polynomial x^3 + 3 @@ -239,9 +213,9 @@ cdef class NumberFieldElement(FieldElement): INPUT: - - ``parent`` - a number field + - ``parent`` -- a number field - - ``f`` - defines an element of a number field. + - ``f`` -- defines an element of a number field. EXAMPLES: @@ -305,20 +279,20 @@ cdef class NumberFieldElement(FieldElement): True """ FieldElement.__init__(self, parent) - self.__fld_numerator, self.__fld_denominator = parent.absolute_polynomial_ntl() + self._fld_numerator, self._fld_denominator = parent.absolute_polynomial_ntl() cdef ZZ_c coeff if isinstance(f, (int, Integer_sage)): # set it up and exit immediately # fast pathway mpz_to_ZZ(&coeff, (<Integer>ZZ(f)).value) - ZZX_SetCoeff( self.__numerator, 0, coeff ) - ZZ_conv_from_int( self.__denominator, 1 ) + ZZX_SetCoeff( self._numerator, 0, coeff ) + ZZ_conv_from_int( self._denominator, 1 ) return elif isinstance(f, NumberFieldElement): if type(self) is type(f): - self.__numerator = (<NumberFieldElement>f).__numerator - self.__denominator = (<NumberFieldElement>f).__denominator + self._numerator = (<NumberFieldElement>f)._numerator + self._denominator = (<NumberFieldElement>f)._denominator return else: f = f.polynomial() @@ -330,11 +304,11 @@ cdef class NumberFieldElement(FieldElement): cdef long i den = f.denominator() - mpz_to_ZZ(&self.__denominator, (<Integer>ZZ(den)).value) + mpz_to_ZZ(&self._denominator, (<Integer>ZZ(den)).value) num = f * den for i from 0 <= i <= num.degree(): mpz_to_ZZ(&coeff, (<Integer>ZZ(num[i])).value) - ZZX_SetCoeff( self.__numerator, i, coeff ) + ZZX_SetCoeff( self._numerator, i, coeff ) def _lift_cyclotomic_element(self, new_parent, bint check=True, int rel=0): """ @@ -405,17 +379,17 @@ cdef class NumberFieldElement(FieldElement): cdef type t = type(self) cdef NumberFieldElement x = <NumberFieldElement>t.__new__(t) x._parent = <ParentWithBase>new_parent - x.__fld_numerator, x.__fld_denominator = new_parent.polynomial_ntl() - x.__denominator = self.__denominator + x._fld_numerator, x._fld_denominator = new_parent.polynomial_ntl() + x._denominator = self._denominator cdef ZZX_c result cdef ZZ_c tmp cdef int i cdef ntl_ZZX _num cdef ntl_ZZ _den - for i from 0 <= i <= ZZX_deg(self.__numerator): - tmp = ZZX_coeff(self.__numerator, i) + for i from 0 <= i <= ZZX_deg(self._numerator): + tmp = ZZX_coeff(self._numerator, i) ZZX_SetCoeff(result, i*rel, tmp) - ZZX_rem(x.__numerator, result, x.__fld_numerator.x) + ZZX_rem(x._numerator, result, x._fld_numerator.x) return x def __reduce__(self): @@ -424,6 +398,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^3 - 17*x^2 + 1) sage: t = a.__reduce__(); t (<class 'sage.rings.number_field.number_field_element.NumberFieldElement_absolute'>, @@ -454,6 +429,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 2) sage: b = (2/3)*a + 3/5 sage: b._repr_() @@ -469,6 +445,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 - 2) sage: m.<b> = NumberField(x^4 - 2) sage: phi = k.hom([b^2]) @@ -511,6 +488,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: (a**2 - a + 1)._gap_init_() '\\$sage4^2 - \\$sage4 + 1' @@ -525,10 +503,9 @@ cdef class NumberFieldElement(FieldElement): sage: f = gap(F) sage: f.GeneratorsOfDivisionRing() [ E(8) ] - sage: p = F.gen()^2+2*F.gen()-3 - sage: p + sage: p = F.gen()^2 + 2*F.gen() - 3; p zeta8^2 + 2*zeta8 - 3 - sage: p._gap_init_() # The variable name $sage2 belongs to the gap(F) and is somehow random + sage: p._gap_init_() # The variable name $sage2 belongs to the gap(F) and is somehow random 'GeneratorsOfField($sage2)[1]^2 + 2*GeneratorsOfField($sage2)[1] - 3' sage: gap(p._gap_init_()) -3+2*E(8)+E(8)^2 @@ -567,19 +544,19 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: sage: F = CyclotomicField(8) - sage: F.gen()._libgap_() + sage: F.gen()._libgap_() # needs sage.libs.gap E(8) - sage: libgap(F.gen()) # syntactic sugar + sage: libgap(F.gen()) # syntactic sugar # needs sage.libs.gap E(8) - sage: E8 = F.gen() - sage: libgap(E8 + 3/2*E8^2 + 100*E8^7) + sage: E8 = F.gen() # needs sage.libs.gap + sage: libgap(E8 + 3/2*E8^2 + 100*E8^7) # needs sage.libs.gap E(8)+3/2*E(8)^2-100*E(8)^3 - sage: type(_) + sage: type(_) # needs sage.libs.gap <class 'sage.libs.gap.element.GapElement_Cyclotomic'> Check that :trac:`15276` is fixed:: - sage: for n in range(2,20): + sage: for n in range(2,20): # needs sage.libs.gap ....: K = CyclotomicField(n) ....: assert K(libgap(K.gen())) == K.gen(), "n = {}".format(n) ....: assert K(libgap(K.one())) == K.one(), "n = {}".format(n) @@ -605,14 +582,15 @@ cdef class NumberFieldElement(FieldElement): TESTS: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) - sage: K.zero()._pari_polynomial('x') + sage: K.zero()._pari_polynomial('x') # needs sage.libs.pari 0 - sage: K.one()._pari_polynomial() + sage: K.one()._pari_polynomial() # needs sage.libs.pari 1 - sage: (a + 1)._pari_polynomial() + sage: (a + 1)._pari_polynomial() # needs sage.libs.pari y + 1 - sage: a._pari_polynomial('c') + sage: a._pari_polynomial('c') # needs sage.libs.pari c """ f = pari(self._coefficients()).Polrev() @@ -635,21 +613,22 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) - sage: K(1).__pari__() + sage: K(1).__pari__() # needs sage.libs.pari Mod(1, y^3 + 2) - sage: (a + 2).__pari__() + sage: (a + 2).__pari__() # needs sage.libs.pari Mod(y + 2, y^3 + 2) sage: L.<b> = K.extension(x^2 + 2) - sage: (b + a).__pari__() + sage: (b + a).__pari__() # needs sage.libs.pari Mod(24/101*y^5 - 9/101*y^4 + 160/101*y^3 - 156/101*y^2 + 397/101*y + 364/101, y^6 + 6*y^4 - 4*y^3 + 12*y^2 + 24*y + 12) :: sage: k.<j> = QuadraticField(-1) - sage: j.__pari__('j') + sage: j.__pari__('j') # needs sage.libs.pari Mod(j, j^2 + 1) - sage: pari(j) + sage: pari(j) # needs sage.libs.pari Mod(y, y^2 + 1) By default the variable name is 'y'. This allows 'x' to be used @@ -658,7 +637,7 @@ cdef class NumberFieldElement(FieldElement): sage: P.<a> = PolynomialRing(QQ) sage: K.<b> = NumberField(a^2 + 1) sage: R.<x> = PolynomialRing(K) - sage: pari(b*x) + sage: pari(b*x) # needs sage.libs.pari Mod(y, y^2 + 1)*x In PARI many variable names are reserved, for example ``theta`` @@ -666,25 +645,25 @@ cdef class NumberFieldElement(FieldElement): sage: R.<theta> = PolynomialRing(QQ) sage: K.<theta> = NumberField(theta^2 + 1) - sage: theta.__pari__('theta') + sage: theta.__pari__('theta') # needs sage.libs.pari Traceback (most recent call last): ... PariError: theta already exists with incompatible valence - sage: theta.__pari__() + sage: theta.__pari__() # needs sage.libs.pari Mod(y, y^2 + 1) sage: k.<I> = QuadraticField(-1) - sage: I.__pari__('I') + sage: I.__pari__('I') # needs sage.libs.pari Traceback (most recent call last): ... PariError: I already exists with incompatible valence Instead, request the variable be named different for the coercion:: - sage: pari(I) + sage: pari(I) # needs sage.libs.pari Mod(y, y^2 + 1) - sage: I.__pari__('i') + sage: I.__pari__('i') # needs sage.libs.pari Mod(i, i^2 + 1) - sage: I.__pari__('II') + sage: I.__pari__('II') # needs sage.libs.pari Mod(II, II^2 + 1) Examples with relative number fields, which always yield an @@ -692,13 +671,13 @@ cdef class NumberFieldElement(FieldElement): sage: y = QQ['y'].gen() sage: k.<j> = NumberField([y^2 - 7, y^3 - 2]) - sage: pari(j) + sage: pari(j) # needs sage.libs.pari Mod(42/5515*y^5 - 9/11030*y^4 - 196/1103*y^3 + 273/5515*y^2 + 10281/5515*y + 4459/11030, y^6 - 21*y^4 + 4*y^3 + 147*y^2 + 84*y - 339) sage: j^2 7 - sage: pari(j)^2 + sage: pari(j)^2 # needs sage.libs.pari Mod(7, y^6 - 21*y^4 + 4*y^3 + 147*y^2 + 84*y - 339) - sage: (j^2).__pari__('x') + sage: (j^2).__pari__('x') # needs sage.libs.pari Mod(7, x^6 - 21*x^4 + 4*x^3 + 147*x^2 + 84*x - 339) A tower of three number fields:: @@ -707,11 +686,11 @@ cdef class NumberFieldElement(FieldElement): sage: K.<a> = NumberField(x^2 + 2) sage: L.<b> = NumberField(polygen(K)^2 + a) sage: M.<c> = NumberField(polygen(L)^3 + b) - sage: L(b).__pari__() + sage: L(b).__pari__() # needs sage.libs.pari Mod(y, y^4 + 2) - sage: M(b).__pari__('c') + sage: M(b).__pari__('c') # needs sage.libs.pari Mod(-c^3, c^12 + 2) - sage: c.__pari__('c') + sage: c.__pari__('c') # needs sage.libs.pari Mod(c, c^12 + 2) """ f = self._pari_polynomial(name) @@ -732,10 +711,11 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^5 - x - 1) - sage: ((1 + 1/3*a)^4)._pari_init_() + sage: ((1 + 1/3*a)^4)._pari_init_() # needs sage.libs.pari 'Mod(1/81*y^4 + 4/27*y^3 + 2/3*y^2 + 4/3*y + 1, y^5 - y - 1)' - sage: ((1 + 1/3*a)^4)._pari_init_('a') + sage: ((1 + 1/3*a)^4)._pari_init_('a') # needs sage.libs.pari 'Mod(1/81*a^4 + 4/27*a^3 + 2/3*a^2 + 4/3*a + 1, a^5 - a - 1)' Note that _pari_init_ can fail because of reserved words in @@ -745,7 +725,7 @@ cdef class NumberFieldElement(FieldElement): sage: K.<theta> = NumberField(x^5 - x - 1) sage: b = (1/2 - 2/3*theta)^3; b -8/27*theta^3 + 2/3*theta^2 - 1/2*theta + 1/8 - sage: b._pari_init_('theta') + sage: b._pari_init_('theta') # needs sage.libs.pari Traceback (most recent call last): ... PariError: theta already exists with incompatible valence @@ -753,7 +733,7 @@ cdef class NumberFieldElement(FieldElement): Fortunately pari_init returns everything in terms of y by default:: - sage: pari(b) + sage: pari(b) # needs sage.libs.pari Mod(-8/27*y^3 + 2/3*y^2 - 1/2*y + 1/8, y^5 - y - 1) """ return repr(self.__pari__(name=name)) @@ -768,6 +748,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: m.<b> = NumberField(x^4 - 1789) sage: c = (2/3-4/5*b)^3; c -64/125*b^3 + 32/25*b^2 - 16/15*b + 8/27 @@ -789,7 +770,7 @@ cdef class NumberFieldElement(FieldElement): ... IndexError: index must be between 0 and degree minus 1 - The list method implicitly calls ``__getitem__``:: + The :func:`list` function implicitly calls :meth:`__getitem__`:: sage: list(c) [8/27, -16/15, 32/25, -64/125] @@ -807,6 +788,7 @@ cdef class NumberFieldElement(FieldElement): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 3*x + 8) sage: a + 1 > a # indirect doctest True @@ -838,7 +820,7 @@ cdef class NumberFieldElement(FieldElement): cdef int res # fast equality check - res = left.__numerator == _right.__numerator and left.__denominator == _right.__denominator + res = left._numerator == _right._numerator and left._denominator == _right._denominator if res: if op == Py_EQ or op == Py_GE or op == Py_LE: return True @@ -863,15 +845,15 @@ cdef class NumberFieldElement(FieldElement): if P._embedded_real: mpz_init(ld) mpz_init(rd) - ZZ_to_mpz(ld, &left.__denominator) - ZZ_to_mpz(rd, &_right.__denominator) + ZZ_to_mpz(ld, &left._denominator) + ZZ_to_mpz(rd, &_right._denominator) v = <RealIntervalFieldElement> P._get_embedding_approx(0) mpfi_init2(la, mpfi_get_prec(v.value)) mpfi_init2(ra, mpfi_get_prec(v.value)) - ZZX_evaluation_mpfi(la, left.__numerator, v.value) + ZZX_evaluation_mpfi(la, left._numerator, v.value) mpfi_div_z(la, la, ld) - ZZX_evaluation_mpfi(ra, _right.__numerator, v.value) + ZZX_evaluation_mpfi(ra, _right._numerator, v.value) mpfi_div_z(ra, ra, rd) while mpfr_greaterequal_p(&la.right, &ra.left) \ and mpfr_greaterequal_p(&ra.right, &la.left): @@ -879,9 +861,9 @@ cdef class NumberFieldElement(FieldElement): v = <RealIntervalFieldElement> P._get_embedding_approx(i) mpfi_set_prec(la, mpfi_get_prec(v.value)) mpfi_set_prec(ra, mpfi_get_prec(v.value)) - ZZX_evaluation_mpfi(la, left.__numerator, v.value) + ZZX_evaluation_mpfi(la, left._numerator, v.value) mpfi_div_z(la, la, ld) - ZZX_evaluation_mpfi(ra, _right.__numerator, v.value) + ZZX_evaluation_mpfi(ra, _right._numerator, v.value) mpfi_div_z(ra, ra, rd) if op == Py_LT or op == Py_LE: res = mpfr_less_p(&la.right, &ra.left) @@ -897,22 +879,23 @@ cdef class NumberFieldElement(FieldElement): def _random_element(self, num_bound=None, den_bound=None, distribution=None): """ - Return a new random element with the same parent as self. + Return a new random element with the same parent as ``self``. INPUT: - - ``num_bound`` - Bound for the numerator of coefficients of result + - ``num_bound`` -- Bound for the numerator of coefficients of result - - ``den_bound`` - Bound for the denominator of coefficients of result + - ``den_bound`` -- Bound for the denominator of coefficients of result - - ``distribution`` - Distribution to use for coefficients of result + - ``distribution`` -- Distribution to use for coefficients of result EXAMPLES:: - sage: K.<a> = NumberField(x^3-2) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: a._random_element().parent() is K True - sage: K.<a> = NumberField(x^2-5) + sage: K.<a> = NumberField(x^2 - 5) sage: a._random_element().parent() is K True """ @@ -929,8 +912,8 @@ cdef class NumberFieldElement(FieldElement): cdef Rational tmp_rational # It seems like a simpler approach would be to simply generate - # random integers for each coefficient of self.__numerator - # and an integer for self.__denominator. However, this would + # random integers for each coefficient of self._numerator + # and an integer for self._denominator. However, this would # generate things with a fairly fixed shape: in particular, # we'd be very unlikely to get elements like 1/3*a^3 + 1/7, # or anything where the denominators are actually unrelated @@ -944,19 +927,19 @@ cdef class NumberFieldElement(FieldElement): # set the denominator mpz_set_si(denom_temp.value, 1) - mpz_to_ZZ(&self.__denominator, (<Integer>denom_temp).value) - for i from 0 <= i < ZZX_deg(self.__fld_numerator.x): + mpz_to_ZZ(&self._denominator, (<Integer>denom_temp).value) + for i from 0 <= i < ZZX_deg(self._fld_numerator.x): tmp_integer = <Integer>(ZZ.random_element(x=num_bound, distribution=distribution)) mpz_to_ZZ(&ntl_temp, (<Integer>tmp_integer).value) - ZZX_SetCoeff(self.__numerator, i, ntl_temp) + ZZX_SetCoeff(self._numerator, i, ntl_temp) else: coeff_list = [] mpz_set_si(denom_temp.value, 1) tmp_integer = Integer.__new__(Integer) - for i from 0 <= i < ZZX_deg(self.__fld_numerator.x): + for i from 0 <= i < ZZX_deg(self._fld_numerator.x): tmp_rational = <Rational>(QQ.random_element(num_bound=num_bound, den_bound=den_bound, distribution=distribution)) @@ -968,10 +951,10 @@ cdef class NumberFieldElement(FieldElement): # scale the numerators and set everything appropriately # first, the denominator (easy) - mpz_to_ZZ(&self.__denominator, (<Integer>denom_temp).value) + mpz_to_ZZ(&self._denominator, (<Integer>denom_temp).value) # now the coefficients themselves. - for i from 0 <= i < ZZX_deg(self.__fld_numerator.x): + for i from 0 <= i < ZZX_deg(self._fld_numerator.x): # calculate the new numerator. if our old entry is # p/q, and the lcm is k, it's just pk/q, which we # also know is integral -- so we can use mpz_divexact @@ -985,7 +968,7 @@ cdef class NumberFieldElement(FieldElement): # now set the coefficient of self mpz_to_ZZ(&ntl_temp, (<Integer>tmp_integer).value) - ZZX_SetCoeff(self.__numerator, i, ntl_temp) + ZZX_SetCoeff(self._numerator, i, ntl_temp) return 0 # No error @@ -1006,6 +989,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^3 - 2) sage: abs(a) 1.25992104989487 @@ -1038,7 +1022,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: - + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2, embedding=AA(2)**(1/3)) sage: K.zero().sign() 0 @@ -1067,10 +1051,10 @@ cdef class NumberFieldElement(FieldElement): sage: L.zero().sign() 0 """ - if ZZX_deg(self.__numerator) == -1: + if ZZX_deg(self._numerator) == -1: return 0 - if ZZX_deg(self.__numerator) == 0: - return ZZ_sign(ZZX_coeff(self.__numerator, 0)) + if ZZX_deg(self._numerator) == 0: + return ZZ_sign(ZZX_coeff(self._numerator, 0)) if not (<number_field_base.NumberField> self._parent)._embedded_real: raise TypeError("sign not well defined since no real embedding is specified") @@ -1131,12 +1115,12 @@ cdef class NumberFieldElement(FieldElement): cdef RealIntervalFieldElement v - if ZZX_deg(self.__numerator) <= 0: + if ZZX_deg(self._numerator) <= 0: mpz_init(num) mpz_init(den) - ZZX_getitem_as_mpz(num, &self.__numerator, 0) - ZZ_to_mpz(den, &self.__denominator) + ZZX_getitem_as_mpz(num, &self._numerator, 0) + ZZ_to_mpz(den, &self._denominator) ans = PY_NEW(Integer) mpz_fdiv_q(ans.value, num, den) @@ -1161,9 +1145,9 @@ cdef class NumberFieldElement(FieldElement): mpz_init(den) mpfi_init2(a, mpfi_get_prec(v.value)) - ZZ_to_mpz(den, &self.__denominator) + ZZ_to_mpz(den, &self._denominator) - ZZX_evaluation_mpfi(a, self.__numerator, v.value) + ZZX_evaluation_mpfi(a, self._numerator, v.value) mpfi_div_z(a, a, den) mpfr_floor(&a.left, &a.left) @@ -1175,7 +1159,7 @@ cdef class NumberFieldElement(FieldElement): v = <RealIntervalFieldElement> P._get_embedding_approx(i) mpfi_set_prec(a, mpfi_get_prec(v.value)) - ZZX_evaluation_mpfi(a, self.__numerator, v.value) + ZZX_evaluation_mpfi(a, self._numerator, v.value) mpfi_div_z(a, a, den) mpfr_floor(&a.left ,&a.left) mpfr_floor(&a.right, &a.right) @@ -1226,7 +1210,7 @@ cdef class NumberFieldElement(FieldElement): ... TypeError: ceil not uniquely defined since no real embedding is specified """ - if ZZX_deg(self.__numerator) <= 0: + if ZZX_deg(self._numerator) <= 0: return self._rational_().ceil() if not (<number_field_base.NumberField> self._parent)._embedded_real: @@ -1246,7 +1230,8 @@ cdef class NumberFieldElement(FieldElement): def round(self): r""" - Return the round (nearest integer) of this number field element. + Return the round (nearest integer) of this number field element. In case + of ties, this relies on the default rounding for rational numbers. EXAMPLES:: @@ -1261,9 +1246,9 @@ cdef class NumberFieldElement(FieldElement): 4 sage: (-b).round() -4 - sage: (b+1/2).round() + sage: (b + 1/2).round() 5 - sage: (-b-1/2).round() + sage: (-b - 1/2).round() -5 This function always succeeds even if a tremendous precision is needed:: @@ -1288,7 +1273,7 @@ cdef class NumberFieldElement(FieldElement): ... TypeError: floor not uniquely defined since no real embedding is specified """ - if ZZX_deg(self.__numerator) <= 0: + if ZZX_deg(self._numerator) <= 0: return self._rational_().round() return (self + QQ((1,2))).floor() @@ -1314,9 +1299,9 @@ cdef class NumberFieldElement(FieldElement): INPUT: - - ``prec`` - (default: None) integer bits of precision + - ``prec`` -- (default: None) integer bits of precision - - ``i`` - (default: None) integer, which embedding to + - ``i`` -- (default: None) integer, which embedding to use @@ -1327,19 +1312,20 @@ cdef class NumberFieldElement(FieldElement): 1.00000000000000 sage: abs(z^2 + 17*z - 3) 16.0604426799931 - sage: K.<a> = NumberField(x^3+17) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 + 17) sage: abs(a) 2.57128159065824 sage: a.abs(prec=100) 2.5712815906582353554531872087 - sage: a.abs(prec=100,i=1) + sage: a.abs(prec=100, i=1) 2.5712815906582353554531872087 sage: a.abs(100, 2) 2.5712815906582353554531872087 Here's one where the absolute value depends on the embedding:: - sage: K.<b> = NumberField(x^2-2) + sage: K.<b> = NumberField(x^2 - 2) sage: a = 1 + b sage: a.abs(i=0) 0.414213562373095 @@ -1399,10 +1385,10 @@ cdef class NumberFieldElement(FieldElement): INPUT: - - ``P`` - a prime ideal of the parent of self + - ``P`` -- a prime ideal of the parent of ``self`` - ``prec`` (int) -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). OUTPUT: @@ -1414,7 +1400,8 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: - sage: K.<a> = NumberField(x^2+5) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 5) sage: [1/K(2).abs_non_arch(P) for P in K.primes_above(2)] [2.00000000000000] sage: [1/K(3).abs_non_arch(P) for P in K.primes_above(3)] @@ -1424,7 +1411,7 @@ cdef class NumberFieldElement(FieldElement): A relative example:: - sage: L.<b> = K.extension(x^2-5) + sage: L.<b> = K.extension(x^2 - 5) sage: [b.abs_non_arch(P) for P in L.primes_above(b)] [0.447213595499958, 0.447213595499958] """ @@ -1442,9 +1429,9 @@ cdef class NumberFieldElement(FieldElement): def coordinates_in_terms_of_powers(self): r""" - Let `\alpha` be self. Return a callable object (of type + Let `\alpha` be ``self``. Return a callable object (of type :class:`~CoordinateFunction`) that takes any element of the - parent of self in `\QQ(\alpha)` and writes it in terms of the + parent of ``self`` in `\QQ(\alpha)` and writes it in terms of the powers of `\alpha`: `1, \alpha, \alpha^2, ...`. (NOT CACHED). @@ -1471,11 +1458,12 @@ cdef class NumberFieldElement(FieldElement): sage: c((1+beta)^10) [54, 162, 189] - This function works even if self only generates a subfield of this + This function works even if ``self`` only generates a subfield of this number field. :: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^6 - 5) sage: alpha = a^3 sage: c = alpha.coordinates_in_terms_of_powers() @@ -1489,8 +1477,8 @@ cdef class NumberFieldElement(FieldElement): ArithmeticError: vector is not in free module """ K = self.number_field() - V, from_V, to_V = K.absolute_vector_space() - h = K(1) + V, _, to_V = K.absolute_vector_space() + h = K.one() B = [to_V(h)] f = self.absolute_minpoly() for i in range(f.degree()-1): @@ -1507,29 +1495,35 @@ cdef class NumberFieldElement(FieldElement): INPUT: - - ``prec`` - integer (default: 53) bits of precision + - ``prec`` -- integer (default: 53) bits of precision EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^3 - 2) sage: a.complex_embeddings() - [-0.629960524947437 - 1.09112363597172*I, -0.629960524947437 + 1.09112363597172*I, 1.25992104989487] + [-0.629960524947437 - 1.09112363597172*I, + -0.629960524947437 + 1.09112363597172*I, + 1.25992104989487] sage: a.complex_embeddings(10) [-0.63 - 1.1*I, -0.63 + 1.1*I, 1.3] sage: a.complex_embeddings(100) - [-0.62996052494743658238360530364 - 1.0911236359717214035600726142*I, -0.62996052494743658238360530364 + 1.0911236359717214035600726142*I, 1.2599210498948731647672106073] + [-0.62996052494743658238360530364 - 1.0911236359717214035600726142*I, + -0.62996052494743658238360530364 + 1.0911236359717214035600726142*I, + 1.2599210498948731647672106073] """ phi = self.number_field().complex_embeddings(prec) return [f(self) for f in phi] def complex_embedding(self, prec=53, i=0): """ - Return the i-th embedding of self in the complex numbers, to the + Return the `i`-th embedding of ``self`` in the complex numbers, to the given precision. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^3 - 2) sage: a.complex_embedding() -0.629960524947437 - 1.09112363597172*I @@ -1550,6 +1544,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - x - 1) sage: OK = K.ring_of_integers() sage: OK(a).is_unit() @@ -1576,35 +1571,37 @@ cdef class NumberFieldElement(FieldElement): def is_norm(self, L, element=False, proof=True): r""" - Determine whether self is the relative norm of an element - of L/K, where K is self.parent(). + Determine whether ``self`` is the relative norm of an element + of `L/K`, where `K` is ``self.parent()``. INPUT: - - L -- a number field containing K=self.parent() - - element -- True or False, whether to also output an element - of which self is a norm - - proof -- If True, then the output is correct unconditionally. - If False, then the output is correct under GRH. + - ``L`` -- a number field containing `K` = ``self.parent()``. + - ``element`` -- ``True`` or ``False``, whether to also output an element + of which ``self`` is a norm. + - ``proof`` -- If ``True``, then the output is correct unconditionally. + If ``False``, then the output is correct under GRH. OUTPUT: - If element is False, then the output is a boolean B, which is - True if and only if self is the relative norm of an element of L - to K. - If element is False, then the output is a pair (B, x), where - B is as above. If B is True, then x is an element of L such that - self == x.norm(K). Otherwise, x is None. + If ``element`` is ``False``, then the output is a boolean `B`, which is + ``True`` if and only if ``self`` is the relative norm of an element of `L` + to `K`. + + If ``element`` is ``True``, then the output is a pair `(B, x)`, where + `B` is as above. If `B` is ``True``, then `x` is an element of `L` such that + ``self == x.norm(K)``. Otherwise, `x` is ``None``. ALGORITHM: - Uses PARI's :pari:`rnfisnorm`. See self._rnfisnorm(). + Uses PARI's :pari:`rnfisnorm`. See :meth:`_rnfisnorm`. EXAMPLES:: - sage: K.<beta> = NumberField(x^3+5) + sage: x = polygen(ZZ, 'x') + sage: K.<beta> = NumberField(x^3 + 5) sage: Q.<X> = K[] - sage: L = K.extension(X^2+X+beta, 'gamma') + sage: L = K.extension(X^2 + X + beta, 'gamma') sage: (beta/2).is_norm(L) False sage: beta.is_norm(L) @@ -1630,14 +1627,15 @@ cdef class NumberFieldElement(FieldElement): sage: (a/2).is_norm(L) Traceback (most recent call last): ... - NotImplementedError: is_norm is not implemented unconditionally for norms from non-Galois number fields + NotImplementedError: is_norm is not implemented unconditionally + for norms from non-Galois number fields sage: (a/2).is_norm(L, proof=False) False sage: K.<a> = NumberField(x^3 + x + 1) sage: Q.<X> = K[] sage: L.<b> = NumberField(X^4 + a) - sage: t, u = (-a).is_norm(L, element=True); u # random (not unique) + sage: t, u = (-a).is_norm(L, element=True); u # random (not unique) b^3 + 1 sage: t and u.norm(K) == -a True @@ -1647,7 +1645,8 @@ cdef class NumberFieldElement(FieldElement): sage: L.<z24> = CyclotomicField(24); L Cyclotomic Field of order 24 and degree 8 sage: K = L.subfield(z24^3, 'z8')[0]; K - Number Field in z8 with defining polynomial x^4 + 1 with z8 = 0.7071067811865475? + 0.7071067811865475?*I + Number Field in z8 with defining polynomial x^4 + 1 + with z8 = 0.7071067811865475? + 0.7071067811865475?*I sage: flag, c = K(-7).is_norm(K, element=True); flag True sage: c.norm(K) @@ -1665,8 +1664,8 @@ cdef class NumberFieldElement(FieldElement): return self.is_norm(L, element=True, proof=proof)[0] K = self.parent() - from sage.rings.number_field.number_field_base import is_NumberField - if not is_NumberField(L): + from sage.rings.number_field.number_field_base import NumberField + if not isinstance(L, NumberField): raise ValueError("L (=%s) must be a NumberField in is_norm" % L) from sage.rings.number_field.number_field import is_AbsoluteNumberField @@ -1704,44 +1703,45 @@ cdef class NumberFieldElement(FieldElement): def _rnfisnorm(self, L, proof=True, extra_primes=0): r""" - Gives the output of the PARI function rnfisnorm. + Give the output of the PARI function :pari:`rnfisnorm`. - This tries to decide whether the number field element self is - the norm of some x in the extension L/K (with K = self.parent()). + This tries to decide whether the number field element ``self`` is + the norm of some `x` in the extension `L/K` (with `K` = ``self.parent()``). - The output is a pair (x, q), where self = Norm(x)*q. The - algorithm looks for a solution x that is an S-integer, with S - a list of places of L containing at least the ramified primes, - the generators of the class group of L, as well as those primes + The output is a pair `(x, q)`, where ``self`` = ``Norm(x)*q``. The + algorithm looks for a solution `x` that is an `S`-integer, with `S` + a list of places of `L` containing at least the ramified primes, + the generators of the class group of `L`, as well as those primes dividing self. - If L/K is Galois, then this is enough; otherwise, - extra_primes is used to add more primes to S: all the places - above the primes p <= extra_primes (resp. p|extra_primes) if - extra_primes > 0 (resp. extra_primes < 0). + If `L/K` is Galois, then this is enough; otherwise, + ``extra_primes`` is used to add more primes to `S`: all the places + above the primes `p \leq ` ``extra_primes`` (resp., `p \mid` ``extra_primes``) if + ``extra_primes`` > 0 (resp., ``extra_primes`` < 0). - The answer is guaranteed (i.e., self is a norm iff q = 1) if the - field is Galois, or, under GRH, if S contains all primes less - than 12log^2|\disc(M)|, where M is the normal closure of L/K. + The answer is guaranteed (i.e., ``self`` is a norm iff `q = 1`) if the + field is Galois, or, under GRH, if `S` contains all primes less + than `12 \log^2|\disc(M)|`, where `M` is the normal closure of `L/K`. INPUT: - - L -- a relative number field with base field self.parent() - - proof -- whether to certify outputs of PARI init functions. - If false, truth of the output depends on GRH. - - extra_primes -- an integer as explained above. + - `L` -- a relative number field with base field ``self.parent()`` + - ``proof`` -- whether to certify outputs of PARI init functions. + If ``False``, truth of the output depends on GRH. + - ``extra_primes`` -- an integer as explained above. OUTPUT: - A pair (x, q) with x in L and q in K as explained above - such that self == x.norm(K)*q. + A pair `(x, q)` with `x` in `L` and `q` in `K` as explained above + such that ``self == x.norm(K)*q``. ALGORITHM: - Uses PARI's rnfisnorm. + Uses PARI's :pari:`rnfisnorm`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + x^2 - 2*x - 1, 'a') sage: P.<X> = K[] sage: L = NumberField(X^2 + a^2 + 2*a + 1, 'b') @@ -1820,6 +1820,7 @@ cdef class NumberFieldElement(FieldElement): """ EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: RR(a^2) -1.00000000000000 @@ -1832,14 +1833,14 @@ cdef class NumberFieldElement(FieldElement): Verify that :trac:`13005` has been fixed:: - sage: K.<a> = NumberField(x^2-5) + sage: K.<a> = NumberField(x^2 - 5) sage: RR(K(1)) 1.00000000000000 sage: RR(a) Traceback (most recent call last): ... TypeError: Unable to coerce a to a rational - sage: K.<a> = NumberField(x^3+2, embedding=-1.25) + sage: K.<a> = NumberField(x^3 + 2, embedding=-1.25) sage: RR(a) -1.25992104989487 sage: RealField(prec=100)(a) @@ -1857,6 +1858,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: sage: Pol.<x> = QQ[] + sage: x = polygen(ZZ, 'x') sage: NF.<a> = NumberField(x^7 + 2, embedding=CC(0.99, 0.47)) sage: CBF(a) [0.9947502791976272 +/- 1.09e-17] + [0.4790464865132800 +/- 1.46e-17]*I @@ -1898,6 +1900,7 @@ cdef class NumberFieldElement(FieldElement): """ EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: float(a^2) -1.0 @@ -1925,6 +1928,7 @@ cdef class NumberFieldElement(FieldElement): """ EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: abs(CDF(a)) 1.0 @@ -1935,6 +1939,7 @@ cdef class NumberFieldElement(FieldElement): """ EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 1) sage: complex(a) 1j @@ -1949,24 +1954,25 @@ cdef class NumberFieldElement(FieldElement): OUTPUT: - (Factorization) If all the prime ideals in the support are - principal, the output is a Factorization as a product of prime + (:class:`Factorization`) If all the prime ideals in the support are + principal, the output is a :class:`Factorization` as a product of prime elements raised to appropriate powers, with an appropriate unit factor. - Raise ValueError if the factorization of the - ideal (self) contains a non-principal prime ideal. + Raise :class:`ValueError` if the factorization of the + ideal (``self``) contains a non-principal prime ideal. EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) sage: (6*i + 6).factor() (-i) * (i + 1)^3 * 3 In the following example, the class number is 2. If a factorization in prime elements exists, we will find it:: - sage: K.<a> = NumberField(x^2-10) + sage: K.<a> = NumberField(x^2 - 10) sage: factor(169*a + 531) (-6*a - 19) * (-3*a - 1) * (-2*a + 9) sage: factor(K(3)) @@ -1987,6 +1993,9 @@ cdef class NumberFieldElement(FieldElement): raise ArithmeticError("factorization of 0 is not defined") K = self.parent() + from .order import is_NumberFieldOrder + if is_NumberFieldOrder(K): + K = K.number_field() fac = K.ideal(self).factor() # Check whether all prime ideals in `fac` are principal for P,e in fac: @@ -1995,10 +2004,34 @@ cdef class NumberFieldElement(FieldElement): element_fac = [(P.gens_reduced()[0],e) for P,e in fac] # Compute the product of the p^e to figure out the unit from sage.misc.misc_c import prod - element_product = prod([p**e for p,e in element_fac], K(1)) + element_product = prod([p**e for p,e in element_fac], K.one()) from sage.structure.all import Factorization return Factorization(element_fac, unit=self/element_product) + def is_prime(self): + r""" + Test whether this number-field element is prime as + an algebraic integer. + + Note that the behavior of this method differs from the behavior + of :meth:`~sage.structure.element.RingElement.is_prime` in a + general ring, according to which (number) fields would have no + nonzero prime elements. + + EXAMPLES:: + + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) + sage: (1 + i).is_prime() + True + sage: ((1+i)/2).is_prime() + False + """ + if not self or not self.is_integral(): + return False + I = self.number_field().fractional_ideal(self) + return I.is_prime() + @coerce_binop def gcd(self, other): """ @@ -2013,7 +2046,7 @@ cdef class NumberFieldElement(FieldElement): - A generator of the ideal ``(self, other)``. If the parent is a number field, this always returns 0 or 1. For maximal orders, - this raises ``ArithmeticError`` if the ideal is not principal. + this raises :class:`ArithmeticError` if the ideal is not principal. EXAMPLES:: @@ -2034,11 +2067,13 @@ cdef class NumberFieldElement(FieldElement): sage: R(1).gcd(R(4*i)) Traceback (most recent call last): ... - NotImplementedError: gcd() for Order in Number Field in i with defining polynomial x^2 + 1 with i = 1*I is not implemented + NotImplementedError: gcd() for Order in Number Field in i + with defining polynomial x^2 + 1 with i = 1*I is not implemented The following field has class number 3, but if the ideal ``(self, other)`` happens to be principal, this still works:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 7) sage: K.class_number() 3 @@ -2068,7 +2103,8 @@ cdef class NumberFieldElement(FieldElement): if not is_NumberFieldOrder(R) or not R.is_maximal(): raise NotImplementedError("gcd() for %r is not implemented" % R) - g = R.ideal(self, other).gens_reduced() + K = R.number_field() + g = K.fractional_ideal(self, other).gens_reduced() if len(g) > 1: raise ArithmeticError("ideal (%r, %r) is not principal, gcd is not defined" % (self, other) ) @@ -2077,13 +2113,14 @@ cdef class NumberFieldElement(FieldElement): def is_totally_positive(self): """ - Returns True if self is positive for all real embeddings of its + Return ``True`` if ``self`` is positive for all real embeddings of its parent number field. We do nothing at complex places, so e.g. any - element of a totally complex number field will return True. + element of a totally complex number field will return ``True``. EXAMPLES:: - sage: F.<b> = NumberField(x^3-3*x-1) + sage: x = polygen(ZZ, 'x') + sage: F.<b> = NumberField(x^3 - 3*x - 1) sage: b.is_totally_positive() False sage: (b^2).is_totally_positive() @@ -2098,19 +2135,19 @@ cdef class NumberFieldElement(FieldElement): sage: a = 30122754096401; b = 21300003689580 sage: (a/b)^2 > 2 True - sage: (a/b+sqrt2).is_totally_positive() + sage: (a/b + sqrt2).is_totally_positive() True sage: r = RealField(3020)(2).sqrt()*2^3000 sage: a = floor(r)/2^3000 sage: b = ceil(r)/2^3000 - sage: (a+sqrt2).is_totally_positive() + sage: (a + sqrt2).is_totally_positive() False - sage: (b+sqrt2).is_totally_positive() + sage: (b + sqrt2).is_totally_positive() True Check that 0 is handled correctly:: - sage: K.<a> = NumberField(x^5+4*x+1) + sage: K.<a> = NumberField(x^5 + 4*x + 1) sage: K(0).is_totally_positive() False """ @@ -2121,18 +2158,19 @@ cdef class NumberFieldElement(FieldElement): def is_square(self, root=False): """ - Return True if self is a square in its parent number field and - otherwise return False. + Return ``True`` if ``self`` is a square in its parent number field and + otherwise return ``False``. INPUT: - - ``root`` - if True, also return a square root (or - None if self is not a perfect square) + - ``root`` -- if ``True``, also return a square root (or + ``None`` if ``self`` is not a perfect square) EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: m.<b> = NumberField(x^4 - 1789) sage: b.is_square() False @@ -2151,7 +2189,7 @@ cdef class NumberFieldElement(FieldElement): (True, 2/3*b + 5) sage: is_square(c) True - sage: is_square(c+1) + sage: is_square(c + 1) False TESTS: @@ -2184,6 +2222,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 2) sage: p = K.primes_above(2)[0] sage: K(5).is_padic_square(p) @@ -2206,6 +2245,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 3) sage: K(3).sqrt() a @@ -2239,7 +2279,7 @@ cdef class NumberFieldElement(FieldElement): Using the ``extend`` keyword:: sage: K = QuadraticField(-5) - sage: z = K(-7).sqrt(extend=True); z + sage: z = K(-7).sqrt(extend=True); z # needs sage.symbolic sqrt(-7) sage: CyclotomicField(4)(4).sqrt(extend=False) 2 @@ -2250,9 +2290,10 @@ cdef class NumberFieldElement(FieldElement): sage: K(-7).sqrt(extend=False) Traceback (most recent call last): ... - ValueError: -7 not a square in Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I + ValueError: -7 not a square in Number Field in a + with defining polynomial x^2 + 5 with a = 2.236067977499790?*I - ALGORITHM: Use PARI to factor `x^2` - ``self`` in `K`. + ALGORITHM: Use PARI to factor `x^2` `-` ``self`` in `K`. """ # For now, use pari's factoring abilities K = self.number_field() @@ -2282,7 +2323,8 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: - sage: K.<a> = NumberField(x^4-7) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^4 - 7) sage: K(7).nth_root(2) a^2 sage: K((a-3)^5).nth_root(5) @@ -2304,11 +2346,12 @@ cdef class NumberFieldElement(FieldElement): def is_nth_power(self, n): r""" - Return True if ``self`` is an `n`'th power in its parent `K`. + Return ``True`` if ``self`` is an `n`'th power in its parent `K`. EXAMPLES:: - sage: K.<a> = NumberField(x^4-7) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^4 - 7) sage: K(7).is_nth_power(2) True sage: K(7).is_nth_power(4) @@ -2339,12 +2382,12 @@ cdef class NumberFieldElement(FieldElement): If the exponent is not integral, perform this operation in the symbolic ring:: - sage: sqrt2^(1/5) + sage: sqrt2^(1/5) # needs sage.symbolic 2^(1/10) - sage: sqrt2^sqrt2 + sage: sqrt2^sqrt2 # needs sage.symbolic 2^(1/2*sqrt(2)) - Sage follows Python's convention 0^0 = 1:: + Sage follows Python's convention `0^0 = 1`:: sage: a = K(0)^0; a 1 @@ -2353,16 +2396,17 @@ cdef class NumberFieldElement(FieldElement): TESTS:: - sage: 2^I + sage: 2^I # needs sage.symbolic 2^I Test :trac:`14895`:: sage: K.<sqrt2> = QuadraticField(2) - sage: 2^sqrt2 + sage: 2^sqrt2 # needs sage.symbolic 2^sqrt(2) + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2+1) - sage: 2^a + sage: 2^a # needs sage.symbolic Traceback (most recent call last): ... TypeError: no canonical coercion from Number Field in a with defining polynomial x^2 + 1 to Symbolic Ring @@ -2401,17 +2445,17 @@ cdef class NumberFieldElement(FieldElement): cdef ZZ_c gcd cdef ZZ_c t1 cdef ZZX_c t2 - if ZZ_IsOne(self.__denominator): + if ZZ_IsOne(self._denominator): return - ZZX_content(t1, self.__numerator) - ZZ_GCD(gcd, t1, self.__denominator) - if ZZ_sign(gcd) != ZZ_sign(self.__denominator): + ZZX_content(t1, self._numerator) + ZZ_GCD(gcd, t1, self._denominator) + if ZZ_sign(gcd) != ZZ_sign(self._denominator): ZZ_negate(t1, gcd) gcd = t1 - ZZX_div_ZZ(t2, self.__numerator, gcd) - ZZ_div(t1, self.__denominator, gcd) - self.__numerator = t2 - self.__denominator = t1 + ZZX_div_ZZ(t2, self._numerator, gcd) + ZZ_div(t1, self._denominator, gcd) + self._numerator = t2 + self._denominator = t1 cpdef _add_(self, right): r""" @@ -2427,15 +2471,15 @@ cdef class NumberFieldElement(FieldElement): cdef NumberFieldElement _right = right cdef ZZ_c g, q1, q2 x = self._new() - ZZ_GCD(g, self.__denominator, _right.__denominator) - ZZ_div(q1, self.__denominator, g) - ZZ_div(q2, _right.__denominator, g) - ZZ_mul(x.__denominator, q1, q2) - ZZ_mul(x.__denominator, x.__denominator, g) + ZZ_GCD(g, self._denominator, _right._denominator) + ZZ_div(q1, self._denominator, g) + ZZ_div(q2, _right._denominator, g) + ZZ_mul(x._denominator, q1, q2) + ZZ_mul(x._denominator, x._denominator, g) cdef ZZX_c t1, t2 - ZZX_mul_ZZ(t1, self.__numerator, q2) - ZZX_mul_ZZ(t2, _right.__numerator, q1) - ZZX_add(x.__numerator, t1, t2) + ZZX_mul_ZZ(t1, self._numerator, q2) + ZZX_mul_ZZ(t2, _right._numerator, q1) + ZZX_add(x._numerator, t1, t2) x._reduce_c_() return x @@ -2443,6 +2487,7 @@ cdef class NumberFieldElement(FieldElement): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: (a/2) - (a + 3) # indirect doctest -1/2*a - 3 @@ -2451,15 +2496,15 @@ cdef class NumberFieldElement(FieldElement): cdef NumberFieldElement _right = right cdef ZZ_c g, q1, q2 x = self._new() - ZZ_GCD(g, self.__denominator, _right.__denominator) - ZZ_div(q1, self.__denominator, g) - ZZ_div(q2, _right.__denominator, g) - ZZ_mul(x.__denominator, q1, q2) - ZZ_mul(x.__denominator, x.__denominator, g) + ZZ_GCD(g, self._denominator, _right._denominator) + ZZ_div(q1, self._denominator, g) + ZZ_div(q2, _right._denominator, g) + ZZ_mul(x._denominator, q1, q2) + ZZ_mul(x._denominator, x._denominator, g) cdef ZZX_c t1, t2 - ZZX_mul_ZZ(t1, self.__numerator, q2) - ZZX_mul_ZZ(t2, _right.__numerator, q1) - ZZX_sub(x.__numerator, t1, t2) + ZZX_mul_ZZ(t1, self._numerator, q2) + ZZX_mul_ZZ(t2, _right._numerator, q1) + ZZX_sub(x._numerator, t1, t2) x._reduce_c_() return x @@ -2473,6 +2518,7 @@ cdef class NumberFieldElement(FieldElement): sage: C.<zeta12>=CyclotomicField(12) sage: zeta12*zeta12^11 1 + sage: x = polygen(ZZ, 'x') sage: G.<a> = NumberField(x^3 + 2/3*x + 1) sage: a^3 # indirect doctest -2/3*a - 1 @@ -2487,18 +2533,18 @@ cdef class NumberFieldElement(FieldElement): sig_on() # MulMod doesn't handle non-monic polynomials. # Therefore, we handle the non-monic case entirely separately. - ZZ_mul(x.__denominator, self.__denominator, _right.__denominator) - if ZZ_IsOne(ZZX_LeadCoeff(self.__fld_numerator.x)): - ZZX_MulMod(x.__numerator, self.__numerator, _right.__numerator, self.__fld_numerator.x) + ZZ_mul(x._denominator, self._denominator, _right._denominator) + if ZZ_IsOne(ZZX_LeadCoeff(self._fld_numerator.x)): + ZZX_MulMod(x._numerator, self._numerator, _right._numerator, self._fld_numerator.x) else: - ZZX_mul(x.__numerator, self.__numerator, _right.__numerator) - if ZZX_deg(x.__numerator) >= ZZX_deg(self.__fld_numerator.x): - ZZX_mul_ZZ( x.__numerator, x.__numerator, self.__fld_denominator.x ) - ZZX_mul_ZZ( temp, self.__fld_numerator.x, x.__denominator ) - ZZ_power(temp1,ZZX_LeadCoeff(temp),ZZX_deg(x.__numerator)-ZZX_deg(self.__fld_numerator.x)+1) - ZZX_PseudoRem(x.__numerator, x.__numerator, temp) - ZZ_mul(x.__denominator, x.__denominator, self.__fld_denominator.x) - ZZ_mul(x.__denominator, x.__denominator, temp1) + ZZX_mul(x._numerator, self._numerator, _right._numerator) + if ZZX_deg(x._numerator) >= ZZX_deg(self._fld_numerator.x): + ZZX_mul_ZZ( x._numerator, x._numerator, self._fld_denominator.x ) + ZZX_mul_ZZ( temp, self._fld_numerator.x, x._denominator ) + ZZ_power(temp1,ZZX_LeadCoeff(temp),ZZX_deg(x._numerator)-ZZX_deg(self._fld_numerator.x)+1) + ZZX_PseudoRem(x._numerator, x._numerator, temp) + ZZ_mul(x._denominator, x._denominator, self._fld_denominator.x) + ZZ_mul(x._denominator, x._denominator, temp1) sig_off() x._reduce_c_() return x @@ -2527,6 +2573,7 @@ cdef class NumberFieldElement(FieldElement): :: + sage: x = polygen(ZZ, 'x') sage: G.<a> = NumberField(x^3 + 2/3*x + 1) sage: a/a # indirect doctest 1 @@ -2604,7 +2651,7 @@ cdef class NumberFieldElement(FieldElement): def __bool__(self): """ - Return True if this number field element is nonzero. + Return ``True`` if this number field element is nonzero. EXAMPLES:: @@ -2619,20 +2666,21 @@ cdef class NumberFieldElement(FieldElement): sage: bool(b + 1) True """ - return not IsZero_ZZX(self.__numerator) + return not IsZero_ZZX(self._numerator) cpdef _neg_(self): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: -a # indirect doctest -a """ cdef NumberFieldElement x x = self._new() - ZZX_mul_long(x.__numerator, self.__numerator, -1) - x.__denominator = self.__denominator + ZZX_mul_long(x._numerator, self._numerator, -1) + x._denominator = self._denominator return x cpdef _copy_for_parent(self, Parent parent): @@ -2641,6 +2689,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: L.<b> = K.change_names() sage: La = a._copy_for_parent(L) @@ -2651,8 +2700,8 @@ cdef class NumberFieldElement(FieldElement): """ cdef NumberFieldElement x x = self._new() - x.__numerator = self.__numerator - x.__denominator = self.__denominator + x._numerator = self._numerator + x._denominator = self._denominator x._set_parent(parent) return x @@ -2660,6 +2709,7 @@ cdef class NumberFieldElement(FieldElement): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: b = copy(a) sage: b is a @@ -2672,6 +2722,7 @@ cdef class NumberFieldElement(FieldElement): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: b = deepcopy(a) sage: b is a @@ -2697,6 +2748,7 @@ cdef class NumberFieldElement(FieldElement): :: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^10 - x - 1) sage: int(a) Traceback (most recent call last): @@ -2717,7 +2769,7 @@ cdef class NumberFieldElement(FieldElement): def __invert__(self): """ - Returns the multiplicative inverse of self in the number field. + Return the multiplicative inverse of self in the number field. EXAMPLES:: @@ -2736,7 +2788,7 @@ cdef class NumberFieldElement(FieldElement): sage: L.<a> = K.extension(f) sage: alpha = (a^8 + (zeta22^9 - zeta22^6 + 2*zeta22^4 + 33)*a^7)/(10**2555) #long time """ - if IsZero_ZZX(self.__numerator): + if IsZero_ZZX(self._numerator): raise ZeroDivisionError("number field element division by zero") cdef NumberFieldElement x cdef ZZX_c temp @@ -2745,8 +2797,8 @@ cdef class NumberFieldElement(FieldElement): # but may fail if NTL runs out of FFT primes. x = self._new() sig_on() - ZZX_XGCD(x.__denominator, x.__numerator, temp, self.__numerator, self.__fld_numerator.x, 1) - ZZX_mul_ZZ(x.__numerator, x.__numerator, self.__denominator) + ZZX_XGCD(x._denominator, x._numerator, temp, self._numerator, self._fld_numerator.x, 1) + ZZX_mul_ZZ(x._numerator, x._numerator, self._denominator) x._reduce_c_() sig_off() except NTLError: @@ -2768,7 +2820,7 @@ cdef class NumberFieldElement(FieldElement): sage: (2*I*I)._integer_() -2 """ - if ZZX_deg(self.__numerator) >= 1: + if ZZX_deg(self._numerator) >= 1: raise TypeError("Unable to coerce %s to an integer" % self) return ZZ(self._rational_()) @@ -2787,12 +2839,12 @@ cdef class NumberFieldElement(FieldElement): sage: (I*I/2)._rational_() -1/2 """ - if ZZX_deg(self.__numerator) >= 1: + if ZZX_deg(self._numerator) >= 1: raise TypeError("Unable to coerce %s to a rational"%self) cdef Integer num = Integer.__new__(Integer) - ZZX_getitem_as_mpz(num.value, &self.__numerator, 0) + ZZX_getitem_as_mpz(num.value, &self._numerator, 0) cdef Integer den = Integer.__new__(Integer) - ZZ_to_mpz(den.value, &self.__denominator) + ZZ_to_mpz(den.value, &self._denominator) return num / den def _algebraic_(self, parent): @@ -2801,6 +2853,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: NF.<alpha> = NumberField(x^5 + 7*x + 3, embedding=CC(0,1)) sage: QQbar(alpha) -1.032202770009288? + 1.168103873894207?*I @@ -2850,46 +2903,48 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: # needs sage.symbolic sage: K.<a> = QuadraticField(2) - sage: SR(a) # indirect doctest + sage: SR(a) # indirect doctest sqrt(2) - sage: SR(3*a-5) # indirect doctest + sage: SR(3*a - 5) # indirect doctest 3*sqrt(2) - 5 sage: K.<a> = QuadraticField(2, embedding=-1.4) - sage: SR(a) # indirect doctest + sage: SR(a) # indirect doctest -sqrt(2) + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 2) - sage: SR(a) # indirect doctest + sage: SR(a) # indirect doctest Traceback (most recent call last): ... TypeError: an embedding into RR or CC must be specified Now a more complicated example:: - sage: K.<a> = NumberField(x^3 + x - 1, embedding=0.68) - sage: b = SR(a); b # indirect doctest + sage: K.<a> = NumberField(x^3 + x - 1, embedding=0.68) # needs sage.symbolic + sage: b = SR(a); b # indirect doctest # needs sage.symbolic (1/18*sqrt(31)*sqrt(3) + 1/2)^(1/3) - 1/3/(1/18*sqrt(31)*sqrt(3) + 1/2)^(1/3) - sage: (b^3 + b - 1).canonicalize_radical() + sage: (b^3 + b - 1).canonicalize_radical() # needs sage.symbolic 0 Make sure we got the right one:: - sage: CC(a) + sage: CC(a) # needs sage.symbolic 0.682327803828019 - sage: CC(b) + sage: CC(b) # needs sage.symbolic 0.682327803828019 Special case for cyclotomic fields:: sage: K.<zeta> = CyclotomicField(19) - sage: SR(zeta) # indirect doctest + sage: SR(zeta) # indirect doctest # needs sage.symbolic e^(2/19*I*pi) sage: CC(zeta) 0.945817241700635 + 0.324699469204683*I - sage: CC(SR(zeta)) + sage: CC(SR(zeta)) # needs sage.symbolic 0.945817241700635 + 0.324699469204683*I - sage: SR(zeta^5 + 2) + sage: SR(zeta^5 + 2) # needs sage.symbolic e^(10/19*I*pi) + 2 For degree greater than 5, sometimes Galois theory prevents a @@ -2897,23 +2952,23 @@ cdef class NumberFieldElement(FieldElement): embedded into the symbolic ring, which will usually get printed as a numerical approximation:: - sage: K.<a> = NumberField(x^5-x+1, embedding=-1) - sage: SR(a) + sage: K.<a> = NumberField(x^5-x+1, embedding=-1) # needs sage.symbolic + sage: SR(a) # needs sage.symbolic -1.167303978261419? :: - sage: K.<a> = NumberField(x^6-x^3-1, embedding=1) - sage: SR(a) + sage: K.<a> = NumberField(x^6-x^3-1, embedding=1) # needs sage.symbolic + sage: SR(a) # needs sage.symbolic (1/2*sqrt(5) + 1/2)^(1/3) In this field, general elements cannot be written in terms of radicals, but particular elements might be:: - sage: K.<a> = NumberField(x^10 + 6*x^6 + 9*x^2 + 1, embedding=CC(0.332*I)) - sage: SR(a) + sage: K.<a> = NumberField(x^10 + 6*x^6 + 9*x^2 + 1, embedding=CC(0.332*I)) # needs sage.symbolic + sage: SR(a) # needs sage.symbolic 0.3319890295845093?*I - sage: SR(a^5+3*a) + sage: SR(a^5+3*a) # needs sage.symbolic I Conversely, some elements are too complicated to be written in @@ -2925,10 +2980,11 @@ cdef class NumberFieldElement(FieldElement): sage: K.<a> = NumberField(QQ['x']([6, -65, 163, -185, 81, -15, 1]), embedding=4.9) sage: b = a + a^3 - sage: SR(b.minpoly()).solve(SR('x'), explicit_solutions=True) + sage: SR(b.minpoly()).solve(SR('x'), explicit_solutions=True) # needs sage.symbolic [] - sage: SR(b) - 1/8*(sqrt(4*(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) - 4/3/(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) + 17) + 5)^3 + 1/2*sqrt(4*(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) - 4/3/(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) + 17) + 5/2 + sage: SR(b) # needs sage.symbolic + 1/8*(sqrt(4*(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) - 4/3/(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) + 17) + 5)^3 + + 1/2*sqrt(4*(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) - 4/3/(1/9*sqrt(109)*sqrt(3) + 2)^(1/3) + 17) + 5/2 TESTS: @@ -2938,7 +2994,7 @@ cdef class NumberFieldElement(FieldElement): sage: p = x^8 + x^7 - 9*x^6 - 3*x^5 - 6*x^4 + x^3 - 14*x^2 + 2*x + 2 sage: rt = sorted(p.roots(AA, multiplicities=False))[1] sage: K.<a> = NumberField(p, embedding=rt) - sage: SR(a) + sage: SR(a) # needs sage.symbolic -0.3056815681115094? """ @@ -2954,7 +3010,6 @@ cdef class NumberFieldElement(FieldElement): from sage.functions.log import exp from sage.rings.complex_mpfr import ComplexField from sage.rings.imaginary_unit import I - from sage.rings.real_mpfr import RR from sage.symbolic.constants import pi CC = ComplexField(53) two_pi_i = 2 * pi * I @@ -2978,12 +3033,13 @@ cdef class NumberFieldElement(FieldElement): def galois_conjugates(self, K): r""" Return all Gal(Qbar/Q)-conjugates of this number field element in - the field K. + the field `K`. EXAMPLES: In the first example the conjugates are obvious:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 2) sage: a.galois_conjugates(K) [a, -a] @@ -3034,7 +3090,7 @@ cdef class NumberFieldElement(FieldElement): This is only well-defined for fields contained in CM fields (i.e. for totally real fields and CM fields). Recall that a CM field is a totally imaginary quadratic extension of a totally - real field. For other fields, a ValueError is raised. + real field. For other fields, a :class:`ValueError` is raised. EXAMPLES:: @@ -3051,12 +3107,13 @@ cdef class NumberFieldElement(FieldElement): :: + sage: x = polygen(ZZ, 'x') sage: F.<b> = NumberField(x^2 - 2) sage: K.<j> = F.extension(x^2 + 1) sage: j.conjugate() -j - Raise a ValueError if the field is not contained in a CM field. + Raise a :class:`ValueError` if the field is not contained in a CM field. :: @@ -3064,7 +3121,8 @@ cdef class NumberFieldElement(FieldElement): sage: b.conjugate() Traceback (most recent call last): ... - ValueError: Complex conjugation is only well-defined for fields contained in CM fields. + ValueError: Complex conjugation is only well-defined + for fields contained in CM fields. An example of a non-quadratic totally real field. @@ -3098,6 +3156,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^5 - x - 1) sage: f = (-2/3 + 1/3*a)^4; f 1/81*a^4 - 8/81*a^3 + 8/27*a^2 - 32/81*a + 16/81 @@ -3142,6 +3201,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<b> = NumberField(x^3 - 2) sage: hash(b^2 + 1) # random 175247765440 @@ -3171,15 +3231,15 @@ cdef class NumberFieldElement(FieldElement): cdef mpz_t z mpz_init(z) - ZZX_getitem_as_mpz(z, &self.__numerator, 0) + ZZX_getitem_as_mpz(z, &self._numerator, 0) h = mpz_pythonhash(z) - for i from 1 <= i <= ZZX_deg(self.__numerator): - ZZX_getitem_as_mpz(z, &self.__numerator, i) + for i from 1 <= i <= ZZX_deg(self._numerator): + ZZX_getitem_as_mpz(z, &self._numerator, i) # magic number below is floor(2^63 / (2+sqrt(2))) h ^= mpz_pythonhash(z) + (<Py_hash_t> 2701463124188384701) + (h << 16) + (h >> 2) - ZZ_to_mpz(z, &self.__denominator) + ZZ_to_mpz(z, &self._denominator) # magic number below is floor((1+sqrt(5)) * 2^61) h += (mpz_pythonhash(z) - 1) * (<Py_hash_t> 7461864723258187525) @@ -3199,6 +3259,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<b> = NumberField(x^3 - 2) sage: (b^2 + 1)._coefficients() [1, 0, 1] @@ -3207,12 +3268,12 @@ cdef class NumberFieldElement(FieldElement): cdef int i cdef mpz_t den mpz_init(den) - ZZ_to_mpz(den, &self.__denominator) - cdef int size = ZZX_deg(self.__numerator) + 1 + ZZ_to_mpz(den, &self._denominator) + cdef int size = ZZX_deg(self._numerator) + 1 cdef list coeffs = [None]*size for i in range(size): coeff = Rational.__new__(Rational) - ZZX_getitem_as_mpz(mpq_numref(coeff.value), &self.__numerator, i) + ZZX_getitem_as_mpz(mpq_numref(coeff.value), &self._numerator, i) mpz_set(mpq_denref(coeff.value), den) mpq_canonicalize(coeff.value) coeffs[i] = coeff @@ -3220,14 +3281,14 @@ cdef class NumberFieldElement(FieldElement): return coeffs cdef void _ntl_coeff_as_mpz(self, mpz_t z, long i): - if i > ZZX_deg(self.__numerator): + if i > ZZX_deg(self._numerator): mpz_set_ui(z, 0) else: - ZZX_getitem_as_mpz(z, &self.__numerator, i) + ZZX_getitem_as_mpz(z, &self._numerator, i) cdef void _ntl_denom_as_mpz(self, mpz_t z): cdef Integer denom = Integer.__new__(Integer) - ZZ_to_mpz(denom.value, &self.__denominator) + ZZ_to_mpz(denom.value, &self._denominator) mpz_set(z, denom.value) def denominator(self): @@ -3246,7 +3307,7 @@ cdef class NumberFieldElement(FieldElement): 15 """ cdef Integer ans = Integer.__new__(Integer) - ZZ_to_mpz(ans.value, &self.__denominator) + ZZ_to_mpz(ans.value, &self._denominator) return ans def _set_multiplicative_order(self, n): @@ -3261,12 +3322,13 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + x + 1) sage: a._set_multiplicative_order(3) sage: a.multiplicative_order() 3 - You can be evil with this so be careful. That's why the function + You can be evil with this, so be careful. That's why the function name begins with an underscore. :: @@ -3292,7 +3354,7 @@ cdef class NumberFieldElement(FieldElement): +Infinity sage: x = polygen(QQ) - sage: K.<a>=NumberField(x^40 - x^20 + 4) + sage: K.<a> = NumberField(x^40 - x^20 + 4) sage: u = 1/4*a^30 + 1/4*a^10 + 1/2 sage: u.multiplicative_order() 6 @@ -3307,13 +3369,12 @@ cdef class NumberFieldElement(FieldElement): 12 sage: z^12==1 and z^6!=1 and z^4!=1 True - """ if self.__multiplicative_order is None: from .number_field import NumberField_cyclotomic if self.is_rational(): if self.is_one(): - self.__multiplicative_order = ZZ(1) + self.__multiplicative_order = ZZ.one() elif (-self).is_one(): self.__multiplicative_order = ZZ(2) else: @@ -3340,17 +3401,18 @@ cdef class NumberFieldElement(FieldElement): def additive_order(self): r""" - Return the additive order of this element (i.e. infinity if - self != 0, 1 if self == 0) + Return the additive order of this element (i.e., infinity if + ``self != 0`` and 1 if ``self == 0``) EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<u> = NumberField(x^4 - 3*x^2 + 3) sage: u.additive_order() +Infinity sage: K(0).additive_order() 1 - sage: K.ring_of_integers().characteristic() # implicit doctest + sage: K.ring_of_integers().characteristic() # implicit doctest 0 """ if not self: return ZZ.one() @@ -3362,6 +3424,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 3) sage: K(1).is_one() True @@ -3374,12 +3437,12 @@ cdef class NumberFieldElement(FieldElement): sage: a.is_one() False """ - return ZZX_IsOne(self.__numerator) == 1 and \ - ZZ_IsOne(self.__denominator) == 1 + return ZZX_IsOne(self._numerator) == 1 and \ + ZZ_IsOne(self._denominator) == 1 cpdef bint is_rational(self): r""" - Test whether this number field element is a rational number + Test whether this number field element is a rational number. .. SEEALSO:: @@ -3388,6 +3451,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<cbrt3> = NumberField(x^3 - 3) sage: cbrt3.is_rational() False @@ -3400,11 +3464,11 @@ cdef class NumberFieldElement(FieldElement): sage: K(1/2).is_rational() True """ - return ZZX_deg(self.__numerator) <= 0 + return ZZX_deg(self._numerator) <= 0 def is_integer(self): r""" - Test whether this number field element is an integer + Test whether this number field element is an integer. .. SEEALSO:: @@ -3413,6 +3477,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<cbrt3> = NumberField(x^3 - 3) sage: cbrt3.is_integer() False @@ -3425,24 +3490,25 @@ cdef class NumberFieldElement(FieldElement): sage: K(1/2).is_integer() False """ - return ZZX_deg(self.__numerator) <= 0 and ZZ_IsOne(self.__denominator) == 1 + return ZZX_deg(self._numerator) <= 0 and ZZ_IsOne(self._denominator) == 1 def trace(self, K=None): - """ + r""" Return the absolute or relative trace of this number field element. - If K is given then K must be a subfield of the parent L of self, in - which case the trace is the relative trace from L to K. In all - other cases, the trace is the absolute trace down to QQ. + If `K` is given, then `K` must be a subfield of the parent `L` of ``self``, in + which case the trace is the relative trace from `L` to `K`. In all + other cases, the trace is the absolute trace down to `\QQ`. EXAMPLES:: - sage: K.<a> = NumberField(x^3 -132/7*x^2 + x + 1); K + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 132/7*x^2 + x + 1); K Number Field in a with defining polynomial x^3 - 132/7*x^2 + x + 1 sage: a.trace() 132/7 - sage: (a+1).trace() == a.trace() + 3 + sage: (a + 1).trace() == a.trace() + 3 True If we are in an order, the trace is an integer:: @@ -3454,7 +3520,7 @@ cdef class NumberFieldElement(FieldElement): TESTS:: - sage: F.<z> = CyclotomicField(5) ; t = 3*z**3 + 4*z**2 + 2 + sage: F.<z> = CyclotomicField(5); t = 3*z**3 + 4*z**2 + 2 sage: t.trace(F) 3*z^3 + 4*z^2 + 2 """ @@ -3464,15 +3530,16 @@ cdef class NumberFieldElement(FieldElement): return self.matrix(K).trace() def norm(self, K=None): - """ + r""" Return the absolute or relative norm of this number field element. - If K is given then K must be a subfield of the parent L of self, in - which case the norm is the relative norm from L to K. In all other - cases, the norm is the absolute norm down to QQ. + If `K` is given, then `K` must be a subfield of the parent `L` of ``self``, in + which case the norm is the relative norm from `L` to `K`. In all other + cases, the norm is the absolute norm down to `\QQ`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + x^2 + x - 132/7); K Number Field in a with defining polynomial x^3 + x^2 + x - 132/7 sage: a.norm() @@ -3496,21 +3563,21 @@ cdef class NumberFieldElement(FieldElement): 1 sage: a a - sage: (a+b+c).norm() + sage: (a + b + c).norm() 121 - sage: (a+b+c).norm(L) + sage: (a + b + c).norm(L) 2*c*b - 7 - sage: (a+b+c).norm(M) + sage: (a + b + c).norm(M) -11 We illustrate that norm is compatible with towers:: - sage: z = (a+b+c).norm(L); z.norm(M) + sage: z = (a + b + c).norm(L); z.norm(M) -11 If we are in an order, the norm is an integer:: - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: a.norm().parent() Rational Field sage: R = K.ring_of_integers() @@ -3546,6 +3613,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: sage: K1.<a1> = CyclotomicField(11) + sage: x = polygen(ZZ, 'x') sage: K2.<a2> = K1.extension(x^2 - 3) sage: K3.<a3> = K2.extension(x^2 + 1) sage: (a1 + a2 + a3).absolute_norm() @@ -3564,6 +3632,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: sage: K1.<a1> = CyclotomicField(11) + sage: x = polygen(ZZ, 'x') sage: K2.<a2> = K1.extension(x^2 - 3) sage: (a1 + a2).relative_norm() a1^2 - 3 @@ -3578,11 +3647,12 @@ cdef class NumberFieldElement(FieldElement): def vector(self): """ - Return vector representation of self in terms of the basis for the + Return vector representation of ``self`` in terms of the basis for the ambient number field. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 1) sage: (2/3*a - 5/6).vector() (-5/6, 2/3) @@ -3608,6 +3678,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 7) sage: a.charpoly() x^3 + 7 @@ -3622,11 +3693,12 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: - sage: K.<a> = NumberField(x^2+3) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 3) sage: a.minpoly('x') x^2 + 3 sage: R.<X> = K['X'] - sage: L.<b> = K.extension(X^2-(22 + a)) + sage: L.<b> = K.extension(X^2 - (22 + a)) sage: b.minpoly('t') t^2 - a - 22 sage: b.absolute_minpoly('t') @@ -3643,6 +3715,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23) sage: a.is_integral() True @@ -3659,8 +3732,8 @@ cdef class NumberFieldElement(FieldElement): An example in a relative extension:: - sage: K.<a,b> = NumberField([x^2+1, x^2+3]) - sage: (a+b).is_integral() + sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 3]) + sage: (a + b).is_integral() True sage: ((a-b)/2).is_integral() False @@ -3669,24 +3742,24 @@ cdef class NumberFieldElement(FieldElement): def matrix(self, base=None): r""" - If base is None, return the matrix of right multiplication by the + If ``base`` is ``None``, return the matrix of right multiplication by the element on the power basis `1, x, x^2, \ldots, x^{d-1}` for the number field. Thus the *rows* of this matrix give the images of each of the `x^i`. - If base is not None, then base must be either a field that embeds - in the parent of self or a morphism to the parent of self, in which - case this function returns the matrix of multiplication by self on + If ``base`` is not ``None``, then ``base`` must be either a field that embeds + in the parent of ``self`` or a morphism to the parent of ``self``, in which + case this function returns the matrix of multiplication by ``self`` on the power basis, where we view the parent field as a field over - base. + ``base``. - Specifying base as the base field over which the parent of self - is a relative extension is equivalent to base being None + Specifying ``base`` as the base field over which the parent of ``self`` + is a relative extension is equivalent to ``base`` being ``None``. INPUT: - - ``base`` - field or morphism + - ``base`` -- field or morphism EXAMPLES: @@ -3734,6 +3807,7 @@ cdef class NumberFieldElement(FieldElement): An example where we explicitly give the subfield or the embedding:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 + 1); L.<a2> = NumberField(x^2 + 1) sage: a.matrix(L) [ 0 1] @@ -3756,7 +3830,7 @@ cdef class NumberFieldElement(FieldElement): TESTS:: - sage: F.<z> = CyclotomicField(5) ; t = 3*z**3 + 4*z**2 + 2 + sage: F.<z> = CyclotomicField(5); t = 3*z**3 + 4*z**2 + 2 sage: t.matrix(F) [3*z^3 + 4*z^2 + 2] sage: x = QQ['x'].gen() @@ -3778,8 +3852,8 @@ cdef class NumberFieldElement(FieldElement): if base is self.parent(): return MatrixSpace(base,1)([self]) if base is not None and base is not self.base_ring(): - from sage.rings.number_field.number_field_base import is_NumberField - if is_NumberField(base): + from sage.rings.number_field.number_field_base import NumberField + if isinstance(base, NumberField): return self._matrix_over_base(base) else: return self._matrix_over_base_morphism(base) @@ -3803,7 +3877,7 @@ cdef class NumberFieldElement(FieldElement): def valuation(self, P): """ - Return the valuation of ``self`` at a given prime ideal ``P``. + Return the valuation of ``self`` at a given prime ideal `P`. INPUT: @@ -3811,12 +3885,12 @@ cdef class NumberFieldElement(FieldElement): .. NOTE:: - The function ``ord()`` is an alias for ``valuation()``. + The method :meth:`ord` is an alias for :meth:`valuation`. EXAMPLES:: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) sage: P = K.ideal(61).factor()[0][0] sage: b = a^2 + 30 sage: b.valuation(P) @@ -3858,7 +3932,7 @@ cdef class NumberFieldElement(FieldElement): """ from .number_field_ideal import is_NumberFieldIdeal if not is_NumberFieldIdeal(P): - if is_NumberFieldElement(P): + if isinstance(P, NumberFieldElement): P = self.number_field().fractional_ideal(P) else: raise TypeError("P must be an ideal") @@ -3874,29 +3948,29 @@ cdef class NumberFieldElement(FieldElement): def local_height(self, P, prec=None, weighted=False): r""" - Returns the local height of self at a given prime ideal `P`. + Returns the local height of ``self`` at a given prime ideal `P`. INPUT: - - ``P`` - a prime ideal of the parent of self + - ``P`` -- a prime ideal of the parent of ``self`` - ``prec`` (int) -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). - - ``weighted`` (bool, default False) -- if True, apply local + - ``weighted`` (bool, default ``False``) -- if ``True``, apply local degree weighting. OUTPUT: (real) The local height of this number field element at the - place `P`. If ``weighted`` is True, this is multiplied by the + place `P`. If ``weighted`` is ``True``, this is multiplied by the local degree (as required for global heights). EXAMPLES:: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) sage: P = K.ideal(61).factor()[0][0] sage: b = 1/(a^2 + 30) sage: b.local_height(P) @@ -3914,7 +3988,7 @@ cdef class NumberFieldElement(FieldElement): sage: PK.<y> = K[] sage: L.<c> = NumberField(y^2 + a) - sage: L(1/4).local_height(L.ideal(2, c-a+1)) + sage: L(1/4).local_height(L.ideal(2, c - a + 1)) 1.38629436111989 """ if self.valuation(P) >= 0: ## includes the case self=0 @@ -3931,36 +4005,35 @@ cdef class NumberFieldElement(FieldElement): def local_height_arch(self, i, prec=None, weighted=False): r""" - Returns the local height of self at the `i`'th infinite place. + Returns the local height of ``self`` at the `i`'th infinite place. INPUT: - - - ``i`` (int) - an integer in ``range(r+s)`` where `(r,s)` is the - signature of the parent field (so `n=r+2s` is the degree). + - ``i`` (int) -- an integer in ``range(r+s)`` where `(r,s)` is the + signature of the parent field (so `n=r+2s` is the degree). - ``prec`` (int) -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). - - ``weighted`` (bool, default False) -- if True, apply local + - ``weighted`` (bool, default ``False``) -- if ``True``, apply local degree weighting, i.e. double the value for complex places. OUTPUT: (real) The archimedean local height of this number field element at the `i`'th infinite place. If ``weighted`` is - True, this is multiplied by the local degree (as required for + ``True``, this is multiplied by the local degree (as required for global heights), i.e. 1 for real places and 2 for complex places. EXAMPLES:: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) sage: [p.codomain() for p in K.places()] [Real Field with 106 bits of precision, - Real Field with 106 bits of precision, - Complex Field with 53 bits of precision] + Real Field with 106 bits of precision, + Complex Field with 53 bits of precision] sage: [a.local_height_arch(i) for i in range(3)] [0.5301924545717755083366563897519, 0.5301924545717755083366563897519, @@ -4013,7 +4086,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) sage: b = a/6 sage: b.global_height_non_arch() 7.16703787691222 @@ -4046,12 +4119,12 @@ cdef class NumberFieldElement(FieldElement): def global_height_arch(self, prec=None): """ - Returns the total archimedean component of the height of self. + Returns the total archimedean component of the height of ``self``. INPUT: - ``prec`` (int) -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). OUTPUT: @@ -4062,7 +4135,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) sage: b = a/2 sage: b.global_height_arch() 0.38653407379277... @@ -4078,7 +4151,7 @@ cdef class NumberFieldElement(FieldElement): INPUT: - ``prec`` (int) -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). OUTPUT: @@ -4090,7 +4163,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) sage: b = a/2 sage: b.global_height() 0.789780699008... @@ -4137,7 +4210,8 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: - sage: K.<a> = NumberField(x^2+5) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 5) sage: b = (1+a)/2 sage: b.norm() 3/2 @@ -4168,7 +4242,8 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: - sage: K.<a> = NumberField(x^2+5) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 5) sage: b = (1+a)/2 sage: b.norm() 3/2 @@ -4189,7 +4264,7 @@ cdef class NumberFieldElement(FieldElement): """ Return the support of this number field element. - OUTPUT: A sorted list of the primes ideals at which this number + OUTPUT: A sorted list of the prime ideals at which this number field element has nonzero valuation. An error is raised if the element is zero. @@ -4225,12 +4300,12 @@ cdef class NumberFieldElement(FieldElement): def _matrix_over_base(self, L): """ - Return the matrix of self over the base field L. + Return the matrix of ``self`` over the base field `L`. EXAMPLES:: - sage: K.<a> = NumberField(ZZ['x'].0^3-2, 'a') - sage: L.<b> = K.extension(ZZ['x'].0^2+3, 'b') + sage: K.<a> = NumberField(ZZ['x'].0^3 - 2, 'a') + sage: L.<b> = K.extension(ZZ['x'].0^2 + 3, 'b') sage: L(a)._matrix_over_base(K) == L(a).matrix() True """ @@ -4243,12 +4318,12 @@ cdef class NumberFieldElement(FieldElement): def _matrix_over_base_morphism(self, phi): """ - Return the matrix of self over a specified base, where phi gives a - map from the specified base to self.parent(). + Return the matrix of ``self`` over a specified base, where ``phi`` gives a + map from the specified base to ``self.parent()``. EXAMPLES:: - sage: F.<alpha> = NumberField(ZZ['x'].0^5-2) + sage: F.<alpha> = NumberField(ZZ['x'].0^5 - 2) sage: h = Hom(QQ,F)([1]) sage: alpha._matrix_over_base_morphism(h) == alpha.matrix() True @@ -4267,7 +4342,7 @@ cdef class NumberFieldElement(FieldElement): ## the variable name is irrelevant below, because the ## matrix is over QQ F = K.absolute_field('alpha') - from_f, to_F = F.structure() + _, to_F = F.structure() return to_F(self).matrix() alpha = L.primitive_element() @@ -4280,7 +4355,7 @@ cdef class NumberFieldElement(FieldElement): M = K.relativize(beta, (K.variable_name()+'0', L.variable_name()+'0') ) # Carry self over to M. - from_M, to_M = M.structure() + _, to_M = M.structure() try: z = to_M(self) except Exception: @@ -4296,11 +4371,12 @@ cdef class NumberFieldElement(FieldElement): def list(self): """ - Return the list of coefficients of self written in terms of a power + Return the list of coefficients of ``self`` written in terms of a power basis. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - x + 2); ((a + 1)/(a + 2)).list() [1/4, 1/2, -1/4] sage: K.<a, b> = NumberField([x^3 - x + 2, x^2 + 23]); ((a + b)/(a + 2)).list() @@ -4309,20 +4385,23 @@ cdef class NumberFieldElement(FieldElement): raise NotImplementedError def inverse_mod(self, I): - """ - Returns the inverse of self mod the integral ideal I. + r""" + Returns the inverse of ``self`` mod the integral ideal `I`. INPUT: - - ``I`` - may be an ideal of self.parent(), or an element or list - of elements of self.parent() generating a nonzero ideal. A ValueError - is raised if I is non-integral or zero. A ZeroDivisionError is - raised if I + (x) != (1). + - ``I`` -- may be an ideal of ``self.parent()``, or an element or list + of elements of ``self.parent()`` generating a nonzero ideal. A :class:`ValueError` + is raised if `I` is non-integral or zero. A :class:`ZeroDivisionError` is + raised if `I + (x) \neq (1)`. - NOTE: It's not implemented yet for non-integral elements. + .. NOTE:: + + It's not implemented yet for non-integral elements. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 23) sage: N = k.ideal(3) sage: d = 3*a + 1 @@ -4354,36 +4433,40 @@ cdef class NumberFieldElement(FieldElement): def residue_symbol(self, P, m, check=True): r""" - The m-th power residue symbol for an element self and proper ideal P. + The `m`-th power residue symbol for an element ``self`` and proper ideal `P`. .. MATH:: \left(\frac{\alpha}{\mathbf{P}}\right) \equiv \alpha^{\frac{N(\mathbf{P})-1}{m}} \operatorname{mod} \mathbf{P} - .. NOTE:: accepts m=1, in which case returns 1 + .. NOTE:: accepts `m=1`, in which case returns 1 .. NOTE:: can also be called for an ideal from sage.rings.number_field_ideal.residue_symbol .. NOTE:: self is coerced into the number field of the ideal P - .. NOTE:: if m=2, self is an integer, and P is an ideal of a number field of absolute degree 1 (i.e. it is a copy of the rationals), then this calls kronecker_symbol, which is implemented using GMP. + .. NOTE:: + + if `m=2`, ``self`` is an integer, and `P` is an ideal of a number field of absolute degree 1 (i.e. it is a copy of the rationals), + then this calls :func:`kronecker_symbol`, which is implemented using GMP. INPUT: - - ``P`` - proper ideal of the number field (or an extension) + - ``P`` -- proper ideal of the number field (or an extension) - - ``m`` - positive integer + - ``m`` -- positive integer OUTPUT: - - an m-th root of unity in the number field + - an `m`-th root of unity in the number field EXAMPLES: Quadratic Residue (11 is not a square modulo 17):: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x - 1) sage: K(11).residue_symbol(K.ideal(17),2) -1 - sage: kronecker_symbol(11,17) + sage: kronecker_symbol(11, 17) -1 The result depends on the number field of the ideal:: @@ -4419,17 +4502,17 @@ cdef class NumberFieldElement(FieldElement): INPUT: - - ``K`` (number field, default \QQ) -- a subfield of the + - ``K`` (number field, default `\QQ`) -- a subfield of the parent number field `L` of ``self`` - ``d`` (positive integer, default 2) -- an integer at least 2 OUTPUT: - A list, possibly empty, of elements of ``K`` equal to ``self`` + A list, possibly empty, of elements of `K` equal to ``self`` modulo `d`'th powers, i.e. the preimages of ``self`` under the map `K^*/(K^*)^d \rightarrow L^*/(L^*)^d` where `L` is the - parent of ``self``. A ``ValueError`` is raised if `K` does + parent of ``self``. A :class:`ValueError` is raised if `K` does not embed into `L`. ALGORITHM: @@ -4517,6 +4600,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: a.different() 3*a^2 @@ -4567,6 +4651,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberFieldTower([x^2 - 17, x^3 - 2]) sage: a.absolute_different() 0 @@ -4587,7 +4672,7 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): INPUT: - - ``magma`` - a Magma interpreter + - ``magma`` -- a Magma interpreter OUTPUT: MagmaElement that has parent the Magma object corresponding @@ -4595,26 +4680,29 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): EXAMPLES:: - sage: K.<a> = NumberField(x^3 + 2) # optional - magma - sage: a._magma_init_(magma) # optional - magma + sage: # optional - magma + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 + 2) + sage: a._magma_init_(magma) '(_sage_[...]![0, 1, 0])' - sage: m = magma((2/3)*a^2 - 17/3); m # optional - magma + sage: m = magma((2/3)*a^2 - 17/3); m 1/3*(2*a^2 - 17) - sage: m.sage() # optional - magma + sage: m.sage() 2/3*a^2 - 17/3 An element of a cyclotomic field. :: - sage: K = CyclotomicField(9) # optional - magma - sage: K.gen() # optional - magma + sage: # optional - magma + sage: K = CyclotomicField(9) + sage: K.gen() zeta9 - sage: K.gen()._magma_init_(magma) # optional - magma + sage: K.gen()._magma_init_(magma) '(_sage_[...]![0, 1, 0, 0, 0, 0])' - sage: magma(K.gen()) # optional - magma + sage: magma(K.gen()) zeta9 - sage: _.sage() # optional - magma + sage: _.sage() zeta9 """ K = magma(self.parent()) @@ -4642,10 +4730,6 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): sage: a.absolute_charpoly(algorithm='pari') == a.absolute_charpoly(algorithm='sage') True """ - # this hack is necessary because quadratic fields override - # charpoly(), and they don't take the argument 'algorithm' - if algorithm is None: - return self.charpoly(var) return self.charpoly(var, algorithm) def absolute_minpoly(self, var='x', algorithm=None): @@ -4658,42 +4742,44 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): EXAMPLES:: sage: x = ZZ['x'].0 - sage: f = x^10 - 5*x^9 + 15*x^8 - 68*x^7 + 81*x^6 - 221*x^5 + 141*x^4 - 242*x^3 - 13*x^2 - 33*x - 135 + sage: f = (x^10 - 5*x^9 + 15*x^8 - 68*x^7 + 81*x^6 - 221*x^5 + ....: + 141*x^4 - 242*x^3 - 13*x^2 - 33*x - 135) sage: K.<a> = NumberField(f, 'a') sage: a.absolute_charpoly() - x^10 - 5*x^9 + 15*x^8 - 68*x^7 + 81*x^6 - 221*x^5 + 141*x^4 - 242*x^3 - 13*x^2 - 33*x - 135 + x^10 - 5*x^9 + 15*x^8 - 68*x^7 + 81*x^6 - 221*x^5 + + 141*x^4 - 242*x^3 - 13*x^2 - 33*x - 135 sage: a.absolute_charpoly('y') - y^10 - 5*y^9 + 15*y^8 - 68*y^7 + 81*y^6 - 221*y^5 + 141*y^4 - 242*y^3 - 13*y^2 - 33*y - 135 - sage: b = -79/9995*a^9 + 52/9995*a^8 + 271/9995*a^7 + 1663/9995*a^6 + 13204/9995*a^5 + 5573/9995*a^4 + 8435/1999*a^3 - 3116/9995*a^2 + 7734/1999*a + 1620/1999 + y^10 - 5*y^9 + 15*y^8 - 68*y^7 + 81*y^6 - 221*y^5 + + 141*y^4 - 242*y^3 - 13*y^2 - 33*y - 135 + sage: b = (-79/9995*a^9 + 52/9995*a^8 + 271/9995*a^7 + 1663/9995*a^6 + ....: + 13204/9995*a^5 + 5573/9995*a^4 + 8435/1999*a^3 + ....: - 3116/9995*a^2 + 7734/1999*a + 1620/1999) sage: b.absolute_charpoly() - x^10 + 10*x^9 + 25*x^8 - 80*x^7 - 438*x^6 + 80*x^5 + 2950*x^4 + 1520*x^3 - 10439*x^2 - 5130*x + 18225 + x^10 + 10*x^9 + 25*x^8 - 80*x^7 - 438*x^6 + 80*x^5 + + 2950*x^4 + 1520*x^3 - 10439*x^2 - 5130*x + 18225 sage: b.absolute_minpoly() x^5 + 5*x^4 - 40*x^2 - 19*x + 135 - sage: b.absolute_minpoly(algorithm='pari') == b.absolute_minpoly(algorithm='sage') + sage: b.absolute_minpoly(algorithm='pari') == b.absolute_minpoly(algorithm='sage') # needs sage.libs.pari True """ - # this hack is necessary because quadratic fields override - # minpoly(), and they don't take the argument 'algorithm' - if algorithm is None: - return self.minpoly(var) return self.minpoly(var, algorithm) def charpoly(self, var='x', algorithm=None): r""" The characteristic polynomial of this element, over - `\QQ` if self is an element of a field, and over - `\ZZ` is self is an element of an order. + `\QQ` if ``self`` is an element of a field, and over + `\ZZ` is ``self`` is an element of an order. - This is the same as ``self.absolute_charpoly`` since + This is the same as :meth:`absolute_charpoly` since this is an element of an absolute extension. - The optional argument algorithm controls how the - characteristic polynomial is computed: 'pari' uses PARI, - 'sage' uses charpoly for Sage matrices. The default value - None means that 'pari' is used for small degrees (up to the - value of the constant TUNE_CHARPOLY_NF, currently at 25), - otherwise 'sage' is used. The constant TUNE_CHARPOLY_NF + The optional argument ``algorithm`` controls how the + characteristic polynomial is computed: ``'pari'`` uses PARI, + ``'sage'`` uses ``charpoly`` for Sage matrices. The default value + ``None`` means that ``'pari'`` is used for small degrees (up to the + value of the constant ``TUNE_CHARPOLY_NF``, currently at 25), + otherwise ``'sage'`` is used. The constant ``TUNE_CHARPOLY_NF`` should give reasonable performance on all architectures; however, if you feel the need to customize it to your own machine, see :trac:`5213` for a tuning script. @@ -4705,7 +4791,7 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): :: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: a.charpoly('x') x^3 - 2 sage: a.charpoly('y').parent() @@ -4719,7 +4805,7 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): sage: R(a).charpoly().parent() Univariate Polynomial Ring in x over Integer Ring - sage: R(a).charpoly(algorithm='pari') == R(a).charpoly(algorithm='sage') + sage: R(a).charpoly(algorithm='pari') == R(a).charpoly(algorithm='sage') # needs sage.libs.pari True """ if algorithm is None: @@ -4737,7 +4823,7 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): """ Return the minimal polynomial of this number field element. - For the meaning of the optional argument algorithm, see charpoly(). + For the meaning of the optional argument ``algorithm``, see :meth:`charpoly`. EXAMPLES: @@ -4746,7 +4832,7 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): :: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: a.minpoly('x') x^3 - 2 sage: a.minpoly('y').parent() @@ -4767,14 +4853,14 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): return self.charpoly(var, algorithm).radical() # square free part of charpoly def list(self): - """ - Return the list of coefficients of self written in terms of a power + r""" + Return the list of coefficients of ``self`` written in terms of a power basis. EXAMPLES:: sage: K.<z> = CyclotomicField(3) - sage: (2+3/5*z).list() + sage: (2 + 3/5*z).list() [2, 3/5] sage: (5*z).list() [0, 5] @@ -4787,9 +4873,9 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): return v + [z]*(n - len(v)) def lift(self, var='x'): - """ - Return an element of QQ[x], where this number field element - lives in QQ[x]/(f(x)). + r""" + Return an element of `\QQ[x]`, where this number field element + lives in `\QQ[x]/(f(x))`. EXAMPLES:: @@ -4810,29 +4896,29 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): The algorithm first checks that ``self`` is not a strictly complex number. Then if ``self`` is not zero, by approximation - more and more precise, the method answers True if the - number is positive. Using `RealInterval`, the result is + more and more precise, the method answers ``True`` if the + number is positive. Using :class:`RealInterval`, the result is guaranteed to be correct. - For CyclotomicField, the embedding is the natural one - sending `zetan` on `cos(2*pi/n)`. + For :class:`CyclotomicField`, the embedding is the natural one + sending ``zetan`` on `\cos(2*\pi/n)`. EXAMPLES:: sage: K.<a> = CyclotomicField(3) - sage: (a+a^2).is_real_positive() + sage: (a + a^2).is_real_positive() False - sage: (-a-a^2).is_real_positive() + sage: (-a - a^2).is_real_positive() True sage: K.<a> = CyclotomicField(1000) - sage: (a+a^(-1)).is_real_positive() + sage: (a + a^(-1)).is_real_positive() True sage: K.<a> = CyclotomicField(1009) sage: d = a^252 - sage: (d+d.conjugate()).is_real_positive() + sage: (d + d.conjugate()).is_real_positive() True sage: d = a^253 - sage: (d+d.conjugate()).is_real_positive() + sage: (d + d.conjugate()).is_real_positive() False sage: K.<a> = QuadraticField(3) sage: a.is_real_positive() @@ -4840,7 +4926,7 @@ cdef class NumberFieldElement_absolute(NumberFieldElement): sage: K.<a> = QuadraticField(-3) sage: a.is_real_positive() False - sage: (a-a).is_real_positive() + sage: (a - a).is_real_positive() False """ if self != self.conjugate() or self.is_zero(): @@ -4867,6 +4953,7 @@ cdef class NumberFieldElement_relative(NumberFieldElement): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 1, x^2 + 2]) sage: type(a) # indirect doctest <class 'sage.rings.number_field.number_field_element.NumberFieldElement_relative'> @@ -4875,7 +4962,7 @@ cdef class NumberFieldElement_relative(NumberFieldElement): def __getitem__(self, n): """ - Return the n-th coefficient of this relative number field element, written + Return the `n`-th coefficient of this relative number field element, written as a polynomial in the generator. Note that `n` must be between 0 and `d-1`, where @@ -4883,6 +4970,7 @@ cdef class NumberFieldElement_relative(NumberFieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^3 - 5, x^2 + 3]) sage: c = (a + b)^3; c 3*b*a^2 - 9*a - 3*b + 5 @@ -4915,6 +5003,7 @@ cdef class NumberFieldElement_relative(NumberFieldElement): """ EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^3 - 5, x^2 + 3]) sage: a._magma_init_(magma) Traceback (most recent call last): @@ -4925,15 +5014,16 @@ cdef class NumberFieldElement_relative(NumberFieldElement): def list(self): """ - Return the list of coefficients of self written in terms of a power + Return the list of coefficients of ``self`` written in terms of a power basis. EXAMPLES:: - sage: K.<a,b> = NumberField([x^3+2, x^2+1]) + sage: x = polygen(ZZ, 'x') + sage: K.<a,b> = NumberField([x^3 + 2, x^2 + 1]) sage: a.list() [0, 1, 0] - sage: v = (K.base_field().0 + a)^2 ; v + sage: v = (K.base_field().0 + a)^2; v a^2 + 2*b*a - 1 sage: v.list() [-1, 2*b, 1] @@ -4942,8 +5032,8 @@ cdef class NumberFieldElement_relative(NumberFieldElement): def lift(self, var='x'): """ - Return an element of K[x], where this number field element - lives in the relative number field K[x]/(f(x)). + Return an element of `K[x]`, where this number field element + lives in the relative number field `K[x]/(f(x))`. EXAMPLES:: @@ -4964,6 +5054,7 @@ cdef class NumberFieldElement_relative(NumberFieldElement): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^3 - x + 1, x^2 + 23]) sage: repr(a^4*b) # indirect doctest 'b*a^2 - b*a' @@ -4975,7 +5066,7 @@ cdef class NumberFieldElement_relative(NumberFieldElement): def _latex_(self): r""" - Returns the latex representation for this element. + Return the latex representation for this element. EXAMPLES:: @@ -5042,12 +5133,12 @@ cdef class NumberFieldElement_relative(NumberFieldElement): We construct a relative extension and find the characteristic polynomial over `\QQ`. - The optional argument algorithm controls how the - characteristic polynomial is computed: 'pari' uses PARI, - 'sage' uses charpoly for Sage matrices. The default value - None means that 'pari' is used for small degrees (up to the - value of the constant TUNE_CHARPOLY_NF, currently at 25), - otherwise 'sage' is used. The constant TUNE_CHARPOLY_NF + The optional argument ``algorithm`` controls how the + characteristic polynomial is computed: ``'pari'`` uses PARI, + ``'sage'`` uses ``charpoly`` for Sage matrices. The default value + ``None`` means that ``'pari'`` is used for small degrees (up to the + value of the constant ``TUNE_CHARPOLY_NF``, currently at 25), + otherwise ``'sage'`` is used. The constant ``TUNE_CHARPOLY_NF`` should give reasonable performance on all architectures; however, if you feel the need to customize it to your own machine, see :trac:`5213` for a tuning script. @@ -5070,7 +5161,7 @@ cdef class NumberFieldElement_relative(NumberFieldElement): sage: a.absolute_charpoly('y') y^9 + 51*y^6 + 867*y^3 + 4913 - sage: a.absolute_charpoly(algorithm='pari') == a.absolute_charpoly(algorithm='sage') + sage: a.absolute_charpoly(algorithm='pari') == a.absolute_charpoly(algorithm='sage') # needs sage.libs.pari True """ if algorithm is None: @@ -5096,6 +5187,7 @@ cdef class NumberFieldElement_relative(NumberFieldElement): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 2, x^2 + 1000*x + 1]) sage: y = K['y'].0 sage: L.<c> = K.extension(y^2 + a*y + b) @@ -5108,7 +5200,8 @@ cdef class NumberFieldElement_relative(NumberFieldElement): sage: L(a).absolute_minpoly() x^2 + 2 sage: L(b).absolute_charpoly() - x^8 + 4000*x^7 + 6000004*x^6 + 4000012000*x^5 + 1000012000006*x^4 + 4000012000*x^3 + 6000004*x^2 + 4000*x + 1 + x^8 + 4000*x^7 + 6000004*x^6 + 4000012000*x^5 + 1000012000006*x^4 + + 4000012000*x^3 + 6000004*x^2 + 4000*x + 1 sage: L(b).absolute_minpoly() x^2 + 1000*x + 1 """ @@ -5116,16 +5209,15 @@ cdef class NumberFieldElement_relative(NumberFieldElement): def valuation(self, P): """ - Returns the valuation of self at a given prime ideal P. + Return the valuation of ``self`` at a given prime ideal `P`. INPUT: - - - ``P`` - a prime ideal of relative number field which is the parent of self - + - ``P`` -- a prime ideal of relative number field which is the parent of ``self`` EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b, c> = NumberField([x^2 - 2, x^2 - 3, x^2 - 5]) sage: P = K.prime_factors(5)[1] sage: (2*a + b - c).valuation(P) @@ -5143,6 +5235,7 @@ cdef class OrderElement_absolute(NumberFieldElement_absolute): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 1) sage: O2 = K.order(2*a) sage: w = O2.1; w @@ -5163,6 +5256,7 @@ cdef class OrderElement_absolute(NumberFieldElement_absolute): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: O2 = K.order(2*a) sage: type(O2.1) # indirect doctest @@ -5176,12 +5270,13 @@ cdef class OrderElement_absolute(NumberFieldElement_absolute): cdef _new(self): """ Quickly creates a new initialized NumberFieldElement with the same - parent as self. + parent as ``self``. EXAMPLES: This is called implicitly in multiplication:: + sage: x = polygen(ZZ, 'x') sage: O = EquationOrder(x^3 + 18, 'a') sage: O.1 * O.1 * O.1 -18 @@ -5190,16 +5285,17 @@ cdef class OrderElement_absolute(NumberFieldElement_absolute): cdef OrderElement_absolute x = <OrderElement_absolute>t.__new__(t) x._parent = self._parent x._number_field = self._parent.number_field() - x.__fld_numerator = self.__fld_numerator - x.__fld_denominator = self.__fld_denominator + x._fld_numerator = self._fld_numerator + x._fld_denominator = self._fld_denominator return x cdef number_field(self): r""" - Return the number field of self. Only accessible from Cython. + Return the number field of ``self``. Only accessible from Cython. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^3 - 17, 'a') sage: OK = K.ring_of_integers() sage: a = OK(K.gen()) @@ -5210,19 +5306,18 @@ cdef class OrderElement_absolute(NumberFieldElement_absolute): def inverse_mod(self, I): r""" - Return an inverse of self modulo the given ideal. + Return an inverse of ``self`` modulo the given ideal. INPUT: - - - ``I`` - may be an ideal of self.parent(), or an - element or list of elements of self.parent() generating a nonzero - ideal. A ValueError is raised if I is non-integral or is zero. - A ZeroDivisionError is raised if I + (x) != (1). - + - ``I`` -- may be an ideal of ``self.parent()``, or an + element or list of elements of ``self.parent()`` generating a nonzero + ideal. A :class:`ValueError` is raised if `I` is non-integral or is zero. + A :class:`ZeroDivisionError` is raised if `I + (x) \neq (1)`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: OE.<w> = EquationOrder(x^3 - x + 2) sage: w.inverse_mod(13*OE) 6*w^2 - 6 @@ -5247,7 +5342,8 @@ cdef class OrderElement_absolute(NumberFieldElement_absolute): EXAMPLES:: - sage: K = NumberField(x^3 -x + 2, 'a') + sage: x = polygen(ZZ, 'x') + sage: K = NumberField(x^3 - x + 2, 'a') sage: OK = K.ring_of_integers() sage: a = OK(K.gen()) sage: (~a).parent() is K @@ -5266,7 +5362,8 @@ cdef class OrderElement_relative(NumberFieldElement_relative): EXAMPLES:: - sage: O = EquationOrder([x^2 + x + 1, x^3 - 2],'a,b') + sage: x = polygen(ZZ, 'x') + sage: O = EquationOrder([x^2 + x + 1, x^3 - 2], 'a,b') sage: c = O.1; c (-2*b^2 - 2)*a - 2*b^2 - b sage: type(c) @@ -5276,8 +5373,9 @@ cdef class OrderElement_relative(NumberFieldElement_relative): r""" EXAMPLES:: - sage: O = EquationOrder([x^2 + x + 1, x^3 - 2],'a,b') - sage: type(O.1) # indirect doctest + sage: x = polygen(ZZ, 'x') + sage: O = EquationOrder([x^2 + x + 1, x^3 - 2], 'a,b') + sage: type(O.1) # indirect doctest <class 'sage.rings.number_field.number_field_element.OrderElement_relative'> """ K = order.number_field() @@ -5297,6 +5395,7 @@ cdef class OrderElement_relative(NumberFieldElement_relative): This is called implicitly in multiplication:: + sage: x = polygen(ZZ, 'x') sage: O = EquationOrder([x^2 + 18, x^3 + 2], 'a,b') sage: c = O.1 * O.2; c (-23321*b^2 - 9504*b + 10830)*a + 10152*b^2 - 104562*b - 110158 @@ -5307,8 +5406,8 @@ cdef class OrderElement_relative(NumberFieldElement_relative): cdef OrderElement_relative x = <OrderElement_relative>t.__new__(t) x._parent = self._parent x._number_field = self._parent.number_field() - x.__fld_numerator = self.__fld_numerator - x.__fld_denominator = self.__fld_denominator + x._fld_numerator = self._fld_numerator + x._fld_denominator = self._fld_denominator return x def __invert__(self): @@ -5319,6 +5418,7 @@ cdef class OrderElement_relative(NumberFieldElement_relative): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K1.<a> = NumberField(x^3 - 17) sage: R.<y> = K1[] sage: K2 = K1.extension(y^2 - a, 'b') @@ -5338,19 +5438,20 @@ cdef class OrderElement_relative(NumberFieldElement_relative): def inverse_mod(self, I): r""" - Return an inverse of self modulo the given ideal. + Return an inverse of ``self`` modulo the given ideal. INPUT: - - ``I`` - may be an ideal of self.parent(), or an - element or list of elements of self.parent() generating a nonzero - ideal. A ValueError is raised if I is non-integral or is zero. - A ZeroDivisionError is raised if I + (x) != (1). + - ``I`` -- may be an ideal of ``self.parent()``, or an + element or list of elements of ``self.parent()`` generating a nonzero + ideal. A :class:`ValueError` is raised if `I` is non-integral or is zero. + A :class:`ZeroDivisionError` is raised if `I + (x) \neq (1)`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: E.<a,b> = NumberField([x^2 - x + 2, x^2 + 1]) sage: OE = E.ring_of_integers() sage: t = OE(b - a).inverse_mod(17*b) @@ -5366,8 +5467,8 @@ cdef class OrderElement_relative(NumberFieldElement_relative): r""" The characteristic polynomial of this order element over its base ring. - This special implementation works around bug \#4738. At this - time the base ring of relative order elements is ZZ; it should + This special implementation works around :trac:`4738`. At this + time the base ring of relative order elements is `\ZZ`; it should be the ring of integers of the base field. EXAMPLES:: @@ -5379,7 +5480,8 @@ cdef class OrderElement_relative(NumberFieldElement_relative): sage: charpoly(OK.1) x^2 + b*x + 1 sage: charpoly(OK.1).parent() - Univariate Polynomial Ring in x over Maximal Order in Number Field in b with defining polynomial x^2 - 3 + Univariate Polynomial Ring in x over + Maximal Order in Number Field in b with defining polynomial x^2 - 3 sage: [ charpoly(t) for t in OK.basis() ] [x^2 - 2*x + 1, x^2 + b*x + 1, x^2 - x + 1, x^2 + 1] """ @@ -5390,8 +5492,8 @@ cdef class OrderElement_relative(NumberFieldElement_relative): r""" The minimal polynomial of this order element over its base ring. - This special implementation works around bug \#4738. At this - time the base ring of relative order elements is ZZ; it should + This special implementation works around :trac:`4738`. At this + time the base ring of relative order elements is `\ZZ`; it should be the ring of integers of the base field. EXAMPLES:: @@ -5403,7 +5505,8 @@ cdef class OrderElement_relative(NumberFieldElement_relative): sage: minpoly(OK.1) x^2 + b*x + 1 sage: charpoly(OK.1).parent() - Univariate Polynomial Ring in x over Maximal Order in Number Field in b with defining polynomial x^2 - 3 + Univariate Polynomial Ring in x over + Maximal Order in Number Field in b with defining polynomial x^2 - 3 sage: _, u, _, v = OK.basis() sage: t = 2*u - v; t -b @@ -5423,7 +5526,7 @@ cdef class OrderElement_relative(NumberFieldElement_relative): def absolute_charpoly(self, var='x'): r""" - The absolute characteristic polynomial of this order element over ZZ. + The absolute characteristic polynomial of this order element over `\ZZ`. EXAMPLES:: @@ -5446,7 +5549,7 @@ cdef class OrderElement_relative(NumberFieldElement_relative): def absolute_minpoly(self, var='x'): r""" - The absolute minimal polynomial of this order element over ZZ. + The absolute minimal polynomial of this order element over `\ZZ`. EXAMPLES:: @@ -5476,6 +5579,7 @@ class CoordinateFunction(): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + x + 3) sage: f = (a + 1).coordinates_in_terms_of_powers(); f Coordinate function that writes elements in terms of the powers of a + 1 @@ -5490,6 +5594,7 @@ class CoordinateFunction(): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + x + 3) sage: f = (a + 1).coordinates_in_terms_of_powers(); f # indirect doctest Coordinate function that writes elements in terms of the powers of a + 1 @@ -5503,6 +5608,7 @@ class CoordinateFunction(): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + x + 3) sage: f = (a + 1).coordinates_in_terms_of_powers(); repr(f) # indirect doctest 'Coordinate function that writes elements in terms of the powers of a + 1' @@ -5513,6 +5619,7 @@ class CoordinateFunction(): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: (a + 2).coordinates_in_terms_of_powers().alpha() a + 2 @@ -5523,6 +5630,7 @@ class CoordinateFunction(): r""" EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: f = (a + 2).coordinates_in_terms_of_powers() sage: f(1/a) @@ -5550,6 +5658,7 @@ class CoordinateFunction(): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: c = (a + 2).coordinates_in_terms_of_powers() sage: c == (a - 3).coordinates_in_terms_of_powers() @@ -5575,6 +5684,7 @@ class CoordinateFunction(): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: c = (a + 2).coordinates_in_terms_of_powers() sage: c != (a - 3).coordinates_in_terms_of_powers() diff --git a/src/sage/rings/number_field/number_field_element_base.pxd b/src/sage/rings/number_field/number_field_element_base.pxd new file mode 100644 index 00000000000..060f0c754c4 --- /dev/null +++ b/src/sage/rings/number_field/number_field_element_base.pxd @@ -0,0 +1,5 @@ +from sage.structure.element cimport FieldElement + + +cdef class NumberFieldElement_base(FieldElement): + pass diff --git a/src/sage/rings/number_field/number_field_element_base.pyx b/src/sage/rings/number_field/number_field_element_base.pyx new file mode 100644 index 00000000000..5fee5817cbc --- /dev/null +++ b/src/sage/rings/number_field/number_field_element_base.pyx @@ -0,0 +1,34 @@ +r""" +Number field elements (abstract base class) +""" + +# **************************************************************************** +# Copyright (C) 2023 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +cdef class NumberFieldElement_base(FieldElement): + r""" + Abstract base class for :class:`~sage.rings.number_field.number_field_element.NumberFieldElement` + + This class is defined for the purpose of :func:`isinstance` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: x = polygen(ZZ, 'x') + sage: k.<a> = NumberField(x^3 + x + 1) # needs sage.rings.number_field + sage: isinstance(a, sage.rings.number_field.number_field_element_base.NumberFieldElement_base) # needs sage.rings.number_field + True + + By design, there is a unique direct subclass:: + + sage: len(sage.rings.number_field.number_field_element_base.NumberFieldElement_base.__subclasses__()) <= 1 + True + """ + + pass diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index 77661f1aca1..c32f6aadd10 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -7,7 +7,7 @@ r""" Optimized Quadratic Number Field Elements -This file defines a Cython class ``NumberFieldElement_quadratic`` to speed up +This file defines a Cython class :class:`NumberFieldElement_quadratic` to speed up computations in quadratic extensions of `\QQ`. AUTHORS: @@ -56,8 +56,6 @@ from sage.structure.richcmp cimport rich_to_bool_sgn from sage.rings.rational cimport Rational from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.real_double import RDF -from sage.rings.complex_double import CDF from sage.categories.morphism cimport Morphism from sage.rings.number_field.number_field_element import _inverse_mod_generic from sage.rings.real_mpfi cimport RealIntervalField_class @@ -74,7 +72,8 @@ def __make_NumberFieldElement_quadratic0(parent, a, b, denom): TESTS:: - sage: K.<a> = NumberField(x^2-x+13) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - x + 13) sage: loads(dumps(a)) == a # indirect doctest True """ @@ -86,7 +85,8 @@ def __make_NumberFieldElement_quadratic1(parent, cls, a, b, denom): TESTS:: - sage: K.<a> = NumberField(x^2-x+13) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - x + 13) sage: loads(dumps(a)) == a # indirect doctest True @@ -101,11 +101,11 @@ def __make_NumberFieldElement_quadratic1(parent, cls, a, b, denom): cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): r""" - A NumberFieldElement_quadratic object gives an efficient representation of + A :class:`NumberFieldElement_quadratic` object gives an efficient representation of an element of a quadratic extension of `\QQ`. Elements are represented internally as triples `(a, b, c)` of integers, - where `{\rm gcd}(a, b, c) = 1` and `c > 0`, representing the element `(a + + where `\gcd(a, b, c) = 1` and `c > 0`, representing the element `(a + b \sqrt{D}) / c`. Note that if the discriminant `D` is `1 \bmod 4`, integral elements do not necessarily have `c = 1`. @@ -116,19 +116,20 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): We set up some fields:: - sage: K.<a> = NumberField(x^2+23) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 23) sage: a.parts() (0, 1) - sage: F.<b> = NumberField(x^2-x+7) + sage: F.<b> = NumberField(x^2 - x + 7) sage: b.parts() (1/2, 3/2) - We construct elements of these fields in various ways - firstly, from + We construct elements of these fields in various ways -- firstly, from polynomials:: - sage: NumberFieldElement_quadratic_sqrt(K, x-1) + sage: NumberFieldElement_quadratic_sqrt(K, x - 1) a - 1 - sage: NumberFieldElement_quadratic(F, x-1) + sage: NumberFieldElement_quadratic(F, x - 1) b - 1 From triples of Integers:: @@ -142,11 +143,11 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): From pairs of Rationals:: - sage: NumberFieldElement_quadratic_sqrt(K, (1/2,1/3)) + sage: NumberFieldElement_quadratic_sqrt(K, (1/2, 1/3)) 1/3*a + 1/2 - sage: NumberFieldElement_quadratic(F, (1/2,1/3)) + sage: NumberFieldElement_quadratic(F, (1/2, 1/3)) 2/9*b + 7/18 - sage: NumberFieldElement_quadratic(F, (1/2,1/3)).parts() + sage: NumberFieldElement_quadratic(F, (1/2, 1/3)).parts() (1/2, 1/3) Direct from Rationals:: @@ -158,7 +159,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): This checks a bug when converting from lists:: - sage: w = CyclotomicField(3)([1/2,1]) + sage: w = CyclotomicField(3)([1/2, 1]) sage: w == w.__invert__().__invert__() True """ @@ -294,9 +295,9 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): EXAMPLES:: sage: K.<a> = QuadraticField(-1) - sage: (1/3 + a/2)._sympy_() + sage: (1/3 + a/2)._sympy_() # needs sympy 1/3 + I/2 - sage: type(_) + sage: type(_) # needs sympy <class 'sympy.core.add.Add'> """ a = self.parent().gen() @@ -313,7 +314,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): EXAMPLES:: sage: K.<sqrt5> = QuadraticField(5) - sage: polymake(3+2*sqrt5) # optional - jupymake + sage: polymake(3 + 2*sqrt5) # optional - jupymake 3+2r5 sage: polymake(2**100/7 - 2*sqrt5/3**50) # optional - jupymake 1267650600228229401496703205376/7-2/717897987691852588770249r5 @@ -422,7 +423,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): TESTS: - sage: K.<a> = NumberField(x^2-13) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 13) sage: loads(dumps(a)) == a True sage: loads(dumps(a/3+5)) == a/3+5 @@ -504,10 +506,10 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): Verify embeddings are respected:: - sage: cf6c = CyclotomicField(6, embedding=CDF(exp(-pi*I/3))) ; z6c = cf6c.0 - sage: cf3(z6c) + sage: cf6c = CyclotomicField(6, embedding=CDF(exp(-pi*I/3))); z6c = cf6c.0 # needs sage.symbolic + sage: cf3(z6c) # needs sage.symbolic -zeta3 - sage: cf6c(z3) + sage: cf6c(z3) # needs sage.symbolic -zeta6 AUTHOR: @@ -608,8 +610,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): mpz_clear(tmp_mpz) x._parent = <ParentWithBase>new_parent - x.__fld_numerator, x.__fld_denominator = new_parent.polynomial_ntl() - x.__denominator = elt_den + x._fld_numerator, x._fld_denominator = new_parent.polynomial_ntl() + x._denominator = elt_den cdef ZZX_c result cdef ZZ_c tmp cdef int i @@ -619,7 +621,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): for i from 0 <= i <= ZZX_deg(elt_num): tmp = ZZX_coeff(elt_num, i) ZZX_SetCoeff(result, i*rel, tmp) - ZZX_rem(x.__numerator, result, _num.x) + ZZX_rem(x._numerator, result, _num.x) (<NumberFieldElement_absolute>x)._reduce_c_() return x @@ -892,7 +894,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): cpdef tuple parts(self): r""" - This function returns a pair of rationals `a` and `b` such that self `= + Return a pair of rationals `a` and `b` such that ``self`` `= a+b\sqrt{D}`. This is much closer to the internal storage format of the @@ -902,19 +904,20 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): EXAMPLES:: - sage: K.<a> = NumberField(x^2-13) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 13) sage: K.discriminant() 13 sage: a.parts() (0, 1) - sage: (a/2-4).parts() + sage: (a/2 - 4).parts() (-4, 1/2) - sage: K.<a> = NumberField(x^2-7) + sage: K.<a> = NumberField(x^2 - 7) sage: K.discriminant() 28 sage: a.parts() (0, 1) - sage: K.<a> = NumberField(x^2-x+7) + sage: K.<a> = NumberField(x^2 - x + 7) sage: a.parts() (1/2, 3/2) sage: a._coefficients() @@ -943,7 +946,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): def sign(self): r""" - Returns the sign of self (0 if zero, +1 if positive and -1 if negative). + Returns the sign of ``self`` (`0` if zero, `+1` if positive, and `-1` if negative). EXAMPLES:: @@ -983,6 +986,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: (-a-2).sign() -1 + sage: # needs sage.symbolic + sage: x = polygen(ZZ, 'x') sage: K.<b> = NumberField(x^2 + 2*x + 7, 'b', embedding=CC(-1,-sqrt(6))) sage: b.sign() Traceback (most recent call last): @@ -1046,6 +1051,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): Make some random tests to check that the order is compatible with the ones of the real field (RR) and complex field (CC):: + sage: x = polygen(ZZ, 'x') sage: K1 = NumberField(x^2 - 2, 'a', embedding=RR(1.4)) sage: K2 = NumberField(x^2 - 2, 'a', embedding=RR(-1.4)) sage: for _ in range(500): # long time @@ -1235,7 +1241,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: K.<sqrt2> = QuadraticField(2) sage: sqrt2.continued_fraction_list() ((1,), (2,)) - sage: (1/2+sqrt2/3).continued_fraction_list() + sage: (1/2 + sqrt2/3).continued_fraction_list() ((0, 1, 33), (1, 32)) For rational entries a pair of tuples is also returned but the second @@ -1316,7 +1322,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2-5) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 5) sage: K.discriminant() 5 sage: a+a # indirect doctest @@ -1373,7 +1380,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2-13) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 13) sage: b = (a-3)/10; b # indirect doctest 1/10*a - 3/10 sage: b-1 @@ -1420,7 +1428,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2+163) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 163) sage: -a -a sage: -(a+4) @@ -1439,7 +1448,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2+23) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 23) sage: a*a # indirect doctest -23 sage: (a+1)*(a-1) @@ -1506,7 +1516,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2+43) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 43) sage: (1+a)*3 # indirect doctest 3*a + 3 """ @@ -1522,7 +1533,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2+43) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 43) sage: 5*(a-1/5) # indirect doctest 5*a - 1 """ @@ -1538,7 +1550,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2-5) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 5) sage: ~a 1/5*a sage: ~(a+1) @@ -1611,6 +1624,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: a.galois_conjugate() -a + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 5*x + 1) sage: a.galois_conjugate() -a + 5 @@ -1629,7 +1643,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): return res ################################################################################# -# We must override everything that makes uses of self.__numerator/__denominator +# We must override everything that makes uses of self._numerator/_denominator ################################################################################# def __hash__(self): @@ -1667,7 +1681,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): EXAMPLES:: - sage: K.<a> = NumberField(x^2+163) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 163) sage: not a False sage: not (a-a) @@ -1679,7 +1694,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2+163) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 163) sage: (a+1-a)._integer_() 1 sage: (a+1/2-a)._integer_() @@ -1699,7 +1715,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2+163) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 163) sage: (a+1/2-a)._rational_() 1/2 sage: (a+1/2)._rational_() @@ -1755,7 +1772,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: K.<sqrt3> = QuadraticField(3) sage: sqrt3.is_rational() False - sage: (sqrt3-1/2).is_rational() + sage: (sqrt3 - 1/2).is_rational() False sage: K(0).is_rational() True @@ -1780,7 +1797,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: K.<sqrt3> = QuadraticField(3) sage: sqrt3.is_integer() False - sage: (sqrt3-1/2).is_integer() + sage: (sqrt3 - 1/2).is_integer() False sage: K(0).is_integer() True @@ -1806,6 +1823,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): 0 sage: (a + 1/2).real() 1/2 + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + x + 1) sage: a.real() -1/2 @@ -1843,12 +1861,13 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: parent(i.imag()) Rational Field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + x + 1, embedding=CDF.0) sage: a.imag() 1/2*sqrt3 sage: a.real() -1/2 - sage: SR(a) + sage: SR(a) # needs sage.symbolic 1/2*I*sqrt(3) - 1/2 sage: bool(QQbar(I)*QQbar(a.imag()) + QQbar(a.real()) == QQbar(a)) True @@ -1916,13 +1935,11 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: F.<b> = NumberField(x^2 - x + 7) sage: b._coefficients() [0, 1] """ - # In terms of the generator... - cdef Rational const = <Rational>Rational.__new__(Rational) - cdef Rational lin = <Rational>Rational.__new__(Rational) if not self: return [] ad, bd = self.parts() @@ -1938,11 +1955,12 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): r""" Return the denominator of ``self``. - This is the LCM of the denominators of the coefficients of `self``, and + This is the LCM of the denominators of the coefficients of ``self``, and thus it may well be `> 1` even when the element is an algebraic integer. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 5) sage: b = (a + 1)/2 sage: b.denominator() @@ -1950,7 +1968,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: b.is_integral() True - sage: K.<c> = NumberField(x^2-x+7) + sage: K.<c> = NumberField(x^2 - x + 7) sage: c.denominator() 1 """ @@ -1970,7 +1988,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): EXAMPLES:: - sage: K.<a> = NumberField(x^2+x+41) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + x + 41) sage: b = (2*a+1)/6 sage: b.denominator() 6 @@ -1979,16 +1998,16 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ return self * self.denominator() - -######################################################### -# Some things are so much easier to compute -######################################################### + ######################################################### + # Some things are so much easier to compute + ######################################################### def trace(self): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2+x+41) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + x + 41) sage: a.trace() -1 sage: a.matrix() @@ -1997,14 +2016,14 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): The trace is additive:: - sage: K.<a> = NumberField(x^2+7) - sage: (a+1).trace() + sage: K.<a> = NumberField(x^2 + 7) + sage: (a + 1).trace() 2 sage: K(3).trace() 6 - sage: (a+4).trace() + sage: (a + 4).trace() 8 - sage: (a/3+1).trace() + sage: (a/3 + 1).trace() 2 """ # trace = 2*self.a / self.denom @@ -2023,24 +2042,25 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): Return the norm of ``self``. If the second argument is ``None``, this is the - norm down to `\QQ`. Otherwise, return the norm down to K (which had + norm down to `\QQ`. Otherwise, return the norm down to `K` (which had better be either `\QQ` or this number field). EXAMPLES:: - sage: K.<a> = NumberField(x^2-x+3) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - x + 3) sage: a.norm() 3 sage: a.matrix() [ 0 1] [-3 1] - sage: K.<a> = NumberField(x^2+5) - sage: (1+a).norm() + sage: K.<a> = NumberField(x^2 + 5) + sage: (1 + a).norm() 6 The norm is multiplicative:: - sage: K.<a> = NumberField(x^2-3) + sage: K.<a> = NumberField(x^2 - 3) sage: a.norm() -3 sage: K(3).norm() @@ -2129,16 +2149,23 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): # D = 1 mod 4 return mpz_fdiv_ui(self.D.value, 4) == 1 - def charpoly(self, var='x'): + def charpoly(self, var='x', algorithm=None): r""" The characteristic polynomial of this element over `\QQ`. + INPUT: + + - ``var`` -- the minimal polynomial is defined over a polynomial ring + in a variable with this name. If not specified, this defaults to ``'x'`` + - ``algorithm`` -- for compatibility with general number field elements; ignored + EXAMPLES:: - sage: K.<a> = NumberField(x^2-x+13) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - x + 13) sage: a.charpoly() x^2 - x + 13 - sage: b = 3-a/2 + sage: b = 3 - a/2 sage: f = b.charpoly(); f x^2 - 11/2*x + 43/4 sage: f(b) @@ -2147,24 +2174,25 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): R = QQ[var] return R([self.norm(), -self.trace(), 1]) - def minpoly(self, var='x'): + def minpoly(self, var='x', algorithm=None): r""" The minimal polynomial of this element over `\QQ`. INPUT: - - ``var`` -- the minimal polynomial is defined over a polynomial ring - in a variable with this name. If not specified this defaults to - ``x``. + - ``var`` -- the minimal polynomial is defined over a polynomial ring + in a variable with this name. If not specified, this defaults to ``'x'`` + - ``algorithm`` -- for compatibility with general number field elements: and ignored EXAMPLES:: - sage: K.<a> = NumberField(x^2+13) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 13) sage: a.minpoly() x^2 + 13 sage: a.minpoly('T') T^2 + 13 - sage: (a+1/2-a).minpoly() + sage: (a + 1/2 - a).minpoly() x - 1/2 """ if self.is_rational(): @@ -2185,8 +2213,9 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: abs(a+2) # indirect test a + 2 - sage: K.<a> = NumberField(x^2+1, embedding=CDF.gen()) - sage: abs(a+1) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 1, embedding=CDF.gen()) + sage: abs(a+1) # needs sage.symbolic sqrt(2) """ if mpz_sgn(self.D.value) == 1: @@ -2201,18 +2230,18 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): def floor(self): r""" - Returns the floor of x. + Returns the floor of ``self``. EXAMPLES:: - sage: K.<sqrt2> = QuadraticField(2,name='sqrt2') + sage: K.<sqrt2> = QuadraticField(2, name='sqrt2') sage: sqrt2.floor() 1 sage: (-sqrt2).floor() -2 sage: (13/197 + 3702/123*sqrt2).floor() 42 - sage: (13/197-3702/123*sqrt2).floor() + sage: (13/197 - 3702/123*sqrt2).floor() -43 TESTS:: @@ -2267,7 +2296,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): def ceil(self): r""" - Returns the ceil. + Return the ceil. EXAMPLES:: @@ -2303,7 +2332,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): def round(self): r""" - Returns the round (nearest integer). + Return the round (nearest integer) of this number field element. In case + of ties, this relies on the default rounding for rational numbers. EXAMPLES:: @@ -2325,12 +2355,14 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: for _ in range(100): ....: a = QQ.random_element(1000,20) ....: b = QQ.random_element(1000,20) - ....: assert round(a) == round(K2(a)), a - ....: assert round(a) == round(K3(a)), a - ....: assert round(a) == round(K5(a)), a + ....: assert a.round() == round(K2(a)), a + ....: assert a.round() == round(K3(a)), a + ....: assert a.round() == round(K5(a)), a ....: assert round(a+b*sqrt(2.)) == round(a+b*sqrt2), (a, b) ....: assert round(a+b*sqrt(3.)) == round(a+b*sqrt3), (a, b) ....: assert round(a+b*sqrt(5.)) == round(a+b*sqrt5), (a, b) + doctest...: DeprecationWarning: the default rounding for rationals, currently `away`, will be changed to `even`. + See https://github.com/sagemath/sage/issues/35473 for details. """ n = self.floor() test = 2 * (self - n).abs() @@ -2346,7 +2378,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): cdef class NumberFieldElement_quadratic_sqrt(NumberFieldElement_quadratic): r""" - A NumberFieldElement_quadratic object gives an efficient representation of + A :class:`NumberFieldElement_quadratic_sqrt` object gives an efficient representation of an element of a quadratic extension of `\QQ` for the case when :func:`is_sqrt_disc()` is ``True``. """ @@ -2354,12 +2386,13 @@ cdef class NumberFieldElement_quadratic_sqrt(NumberFieldElement_quadratic): r""" Return the denominator of ``self``. - This is the LCM of the denominators of the coefficients of `self``, and + This is the LCM of the denominators of the coefficients of ``self``, and thus it may well be `> 1` even when the element is an algebraic integer. EXAMPLES:: - sage: K.<a> = NumberField(x^2+x+41) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + x + 41) sage: a.denominator() 1 sage: b = (2*a+1)/6 @@ -2388,7 +2421,8 @@ cdef class NumberFieldElement_quadratic_sqrt(NumberFieldElement_quadratic): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2+41) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 41) sage: a._coefficients() [0, 1] sage: K.zero()._coefficients() @@ -2396,8 +2430,6 @@ cdef class NumberFieldElement_quadratic_sqrt(NumberFieldElement_quadratic): sage: (3/2*K.one())._coefficients() [3/2] """ - # In terms of the generator... Rational const = <Rational>Rational.__new__(Rational) - cdef Rational lin = <Rational>Rational.__new__(Rational) if not self: return [] cdef tuple parts = self.parts() @@ -2414,7 +2446,8 @@ cdef class NumberFieldElement_quadratic_sqrt(NumberFieldElement_quadratic): EXAMPLES:: - sage: K.<a> = NumberField(x^2-13) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 13) sage: elt = a/4 + 1/3 sage: elt[0] 1/3 @@ -2474,11 +2507,11 @@ cdef class NumberFieldElement_gaussian(NumberFieldElement_quadratic_sqrt): r""" EXAMPLES:: - sage: SR(1 + 2*i) + sage: SR(1 + 2*i) # needs sage.symbolic 2*I + 1 sage: K.<mi> = QuadraticField(-1, embedding=CC(0,-1)) - sage: SR(1 + mi) + sage: SR(1 + mi) # needs sage.symbolic -I + 1 """ from sage.symbolic.constants import I @@ -2584,7 +2617,7 @@ cdef class NumberFieldElement_gaussian(NumberFieldElement_quadratic_sqrt): EXAMPLES:: - sage: I.log() + sage: I.log() # needs sage.symbolic 1/2*I*pi """ from sage.symbolic.ring import SR @@ -2596,6 +2629,7 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 1) sage: O2 = K.order(2*a) sage: w = O2.1; w @@ -2609,6 +2643,7 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: OK.<y> = EquationOrder(x^2 + 5) sage: v = OK.1 # indirect doctest sage: type(v) @@ -2624,6 +2659,7 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 3) sage: O2 = K.order(2*a) sage: w = O2.gen(1); w @@ -2641,6 +2677,7 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 5) sage: R = K.ring_of_integers() sage: b = R((1+a)/2) @@ -2651,13 +2688,21 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): """ return ZZ(NumberFieldElement_quadratic.trace(self)) - def charpoly(self, var='x'): + def charpoly(self, var='x', algorithm=None): r""" The characteristic polynomial of this element, which is over `\ZZ` because this element is an algebraic integer. + INPUT: + + - ``var`` -- the minimal polynomial is defined over a polynomial ring + in a variable with this name. If not specified, this defaults to ``'x'`` + - ``algorithm`` -- for compatibility with general number field elements; ignored + + EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 5) sage: R = K.ring_of_integers() sage: b = R((5+a)/2) @@ -2671,12 +2716,19 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): R = ZZ[var] return R([self.norm(), -self.trace(), 1]) - def minpoly(self, var='x'): + def minpoly(self, var='x', algorithm=None): r""" The minimal polynomial of this element over `\ZZ`. + INPUT: + + - ``var`` -- the minimal polynomial is defined over a polynomial ring + in a variable with this name. If not specified, this defaults to ``'x'`` + - ``algorithm`` -- for compatibility with general number field elements; ignored + EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 163) sage: R = K.ring_of_integers() sage: f = R(a).minpoly('x'); f @@ -2703,7 +2755,8 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2-27) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 27) sage: R = K.ring_of_integers() sage: aa = R.gen(1); aa 1/3*a @@ -2722,7 +2775,8 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2+43) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 43) sage: R = K.ring_of_integers() sage: aa = R.gen(0); aa 1/2*a + 1/2 @@ -2744,7 +2798,8 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): EXAMPLES:: - sage: K = NumberField(x^2 -x + 2, 'a') + sage: x = polygen(ZZ, 'x') + sage: K = NumberField(x^2 - x + 2, 'a') sage: OK = K.ring_of_integers() sage: a = OK(K.gen()) sage: (~a).parent() is K @@ -2758,19 +2813,18 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): def inverse_mod(self, I): r""" - Return an inverse of self modulo the given ideal. + Return an inverse of ``self`` modulo the given ideal. INPUT: - - - ``I`` - may be an ideal of self.parent(), or an - element or list of elements of self.parent() generating a nonzero - ideal. A ValueError is raised if I is non-integral or is zero. - A ZeroDivisionError is raised if I + (x) != (1). - + - ``I`` -- may be an ideal of ``self.parent()``, or an + element or list of elements of ``self.parent()`` generating a nonzero + ideal. A :class:`ValueError` is raised if `I` is non-integral or is zero. + A :class:`ZeroDivisionError` is raised if `I + (x) \neq (1)`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: OE.<w> = EquationOrder(x^2 - x + 2) sage: w.inverse_mod(13) == 6*w - 6 True @@ -2790,15 +2844,13 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): """ EXAMPLES:: - sage: K.<a> = NumberField(x^2-27) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 27) sage: R = K.ring_of_integers() sage: aa = R.gen(1) sage: aa._coefficients() [0, 1/3] """ - # In terms of the generator... - cdef Rational const = <Rational>Rational.__new__(Rational) - cdef Rational lin = <Rational>Rational.__new__(Rational) if not self: return [] ad, bd = self.parts() @@ -2817,12 +2869,13 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): r""" Return the denominator of ``self``. - This is the LCM of the denominators of the coefficients of `self``, and + This is the LCM of the denominators of the coefficients of ``self``, and thus it may well be `> 1` even when the element is an algebraic integer. EXAMPLES:: - sage: K.<a> = NumberField(x^2-27) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 27) sage: R = K.ring_of_integers() sage: aa = R.gen(1) sage: aa.denominator() @@ -2850,7 +2903,7 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): cdef class Z_to_quadratic_field_element(Morphism): """ Morphism that coerces from integers to elements of a quadratic number - field K. + field `K`. EXAMPLES:: @@ -2952,7 +3005,7 @@ cdef class Z_to_quadratic_field_element(Morphism): cdef class Q_to_quadratic_field_element(Morphism): """ Morphism that coerces from rationals to elements of a quadratic number - field K. + field `K`. EXAMPLES:: @@ -3052,6 +3105,7 @@ cpdef bint is_sqrt_disc(Rational ad, Rational bd): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: F.<b> = NumberField(x^2 - x + 7) sage: b.denominator() # indirect doctest 1 diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index d5f7157217f..161ef40a842 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari sage.rings.number_field """ Number Field Ideals @@ -11,10 +12,13 @@ NumberFieldFractionalIdeal now used for all except the 0 ideal - Radoslav Kirov and Alyson Deines (2010-06-22): - prime_to_S_part, is_S_unit, is_S_integral + prime_to_S_part, is_S_unit, is_S_integral + +TESTS: We test that pickling works:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^2 - 5) sage: I = K.ideal(2/(5+a)) sage: I == loads(dumps(I)) @@ -69,12 +73,13 @@ def __init__(self, field, gens, coerce=True): """ INPUT: - - ``field`` - a number field + - ``field`` -- a number field - - ``x`` - a list of NumberFieldElements belonging to the field + - ``x`` -- a list of :class:`NumberFieldElement` objects belonging to the field EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<i> = NumberField(x^2 + 1) sage: K.ideal(7) Fractional ideal (7) @@ -95,7 +100,7 @@ def __init__(self, field, gens, coerce=True): TESTS: - Check that _pari_prime is set when initializing from a PARI + Check that ``_pari_prime`` is set when initializing from a PARI prime ideal:: sage: K.ideal(pari(K).idealprimedec(5)[0])._pari_prime @@ -130,7 +135,7 @@ def __init__(self, field, gens, coerce=True): else: # Assume one element of the field gens = [field(gens, check=False)] - if len(gens)==0: + if len(gens) == 0: raise ValueError("gens must have length at least 1 (zero ideal is not a fractional ideal)") Ideal_generic.__init__(self, field, gens, coerce) if field.absolute_degree() == 2: @@ -143,14 +148,15 @@ def _magma_init_(self, magma): INPUT: - - ``magma`` - a Magma interpreter + - ``magma`` -- a Magma interpreter - OUTPUT: MagmaElement corresponding to this ideal. + OUTPUT: :class:`MagmaElement` corresponding to this ideal. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^3 + 2) # optional - magma sage: I = K.ideal(5) # optional - magma sage: I._magma_init_(magma) # optional - magma @@ -168,6 +174,7 @@ def __hash__(self): """ EXAMPLES:: + sage: x = polygen(ZZ) sage: NumberField(x^2 + 1, 'a').ideal(7).__hash__() # random 7806919040325273549 """ @@ -183,6 +190,7 @@ def _latex_(self): r""" EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^2 + 23) sage: K.ideal([2, 1/2*a - 1/2])._latex_() '\\left(2, \\frac{1}{2} a - \\frac{1}{2}\\right)' @@ -229,6 +237,7 @@ def _richcmp_(self, other, op): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^2 + 3); K Number Field in a with defining polynomial x^2 + 3 sage: f = K.factor(15); f @@ -258,9 +267,9 @@ def _richcmp_(self, other, op): def _mul_(self, other): """ - Returns the product of self and other. + Return the product of ``self`` and ``other``. - This is implemented by just calling pari to do the multiplication. + This is implemented by just calling PARI to do the multiplication. EXAMPLES:: @@ -285,43 +294,45 @@ def _mul_(self, other): if self.ngens() == 1 and other.ngens() == 1: return self.ring().ideal(self.gen(0) * other.gen(0)) - K=self.ring() - K_pari=K.pari_nf() + K = self.ring() + K_pari = K.pari_nf() return K.ideal(K_pari.idealmul(self, other)) def coordinates(self, x): r""" - Returns the coordinate vector of `x` with respect to this ideal. + Return the coordinate vector of `x` with respect to this ideal. INPUT: - ``x`` -- an element of the number field (or ring of integers) of this ideal. + + - ``x`` -- an element of the number field (or ring of integers) of this ideal. OUTPUT: - List giving the coordinates of `x` with respect to the integral basis - of the ideal. In general this will be a vector of - rationals; it will consist of integers if and only if `x` - is in the ideal. + + List giving the coordinates of `x` with respect to the integral basis + of the ideal. In general this will be a vector of + rationals; it will consist of integers if and only if `x` + is in the ideal. AUTHOR: John Cremona 2008-10-31 ALGORITHM: Uses linear algebra. - Provides simpler implementations for ``_contains_()``, - ``is_integral()`` and ``smallest_integer()``. + Provides simpler implementations for :meth:`_contains_`, + :meth:`is_integral` and :meth:`smallest_integer`. EXAMPLES:: sage: K.<i> = QuadraticField(-1) - sage: I = K.ideal(7+3*i) + sage: I = K.ideal(7 + 3*i) sage: Ibasis = I.integral_basis(); Ibasis [58, i + 41] - sage: a = 23-14*i + sage: a = 23 - 14*i sage: acoords = I.coordinates(a); acoords (597/58, -14) sage: sum([Ibasis[j]*acoords[j] for j in range(2)]) == a True - sage: b = 123+456*i + sage: b = 123 + 456*i sage: bcoords = I.coordinates(b); bcoords (-18573/58, 456) sage: sum([Ibasis[j]*bcoords[j] for j in range(2)]) == b @@ -343,12 +354,13 @@ def coordinates(self, x): def _contains_(self, x): """ - Return True if x is an element of this ideal. + Return ``True`` if `x` is an element of this ideal. This function is called (indirectly) when the ``in`` operator is used. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^2 + 23); K Number Field in a with defining polynomial x^2 + 23 sage: I = K.factor(13)[0][0]; I @@ -401,6 +413,7 @@ def __elements_from_hnf(self, hnf): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^3 + 389); K Number Field in a with defining polynomial x^3 + 389 sage: I = K.factor(17)[0][0] @@ -428,7 +441,8 @@ def __repr__(self): EXAMPLES:: - sage: K.<a> = NumberField(x^3-2) + sage: x = polygen(ZZ) + sage: K.<a> = NumberField(x^3 - 2) sage: I = K.ideal(0); I Ideal (0) of Number Field in a with defining polynomial x^3 - 2 sage: type(I) @@ -461,6 +475,7 @@ def _repr_short(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^4 + 389); K Number Field in a with defining polynomial x^4 + 389 sage: I = K.factor(17)[0][0]; I @@ -490,13 +505,14 @@ def _repr_short(self): def _gens_repr(self): """ - Returns tuple of generators to be used for printing this number + Return tuple of generators to be used for printing this number field ideal. The gens are reduced only if the absolute value of the norm of the discriminant of the defining polynomial is at most sage.rings.number_field.number_field_ideal.SMALL_DISC. EXAMPLES:: + sage: x = polygen(ZZ) sage: sage.rings.number_field.number_field_ideal.SMALL_DISC 1000000 sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) @@ -526,11 +542,12 @@ def _gens_repr(self): def __pari__(self): """ - Returns PARI Hermite Normal Form representations of this + Return PARI Hermite Normal Form representations of this ideal. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<w> = NumberField(x^2 + 23) sage: I = K.class_group().0.ideal(); I Fractional ideal (2, 1/2*w - 1/2) @@ -541,10 +558,11 @@ def __pari__(self): def _pari_init_(self): """ - Returns self in PARI Hermite Normal Form as a string + Return self in PARI Hermite Normal Form as a string EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<w> = NumberField(x^2 + 23) sage: I = K.class_group().0.ideal() sage: I._pari_init_() @@ -558,6 +576,7 @@ def pari_hnf(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(x^3 - 2) sage: I = K.ideal(2/(5+a)) @@ -577,7 +596,7 @@ def pari_hnf(self): @cached_method def basis(self): r""" - Return a basis for this ideal viewed as a `\ZZ` -module. + Return a basis for this ideal viewed as a `\ZZ`-module. OUTPUT: @@ -589,7 +608,8 @@ def basis(self): sage: K.<z> = CyclotomicField(7) sage: I = K.factor(11)[0][0] sage: I.basis() # warning -- choice of basis can be somewhat random - [11, 11*z, 11*z^2, z^3 + 5*z^2 + 4*z + 10, z^4 + z^2 + z + 5, z^5 + z^4 + z^3 + 2*z^2 + 6*z + 5] + [11, 11*z, 11*z^2, z^3 + 5*z^2 + 4*z + 10, + z^4 + z^2 + z + 5, z^5 + z^4 + z^3 + 2*z^2 + 6*z + 5] An example of a non-integral ideal.:: @@ -597,11 +617,14 @@ def basis(self): sage: J # warning -- choice of generators can be somewhat random Fractional ideal (2/11*z^5 + 2/11*z^4 + 3/11*z^3 + 2/11) sage: J.basis() # warning -- choice of basis can be somewhat random - [1, z, z^2, 1/11*z^3 + 7/11*z^2 + 6/11*z + 10/11, 1/11*z^4 + 1/11*z^2 + 1/11*z + 7/11, 1/11*z^5 + 1/11*z^4 + 1/11*z^3 + 2/11*z^2 + 8/11*z + 7/11] + [1, z, z^2, 1/11*z^3 + 7/11*z^2 + 6/11*z + 10/11, + 1/11*z^4 + 1/11*z^2 + 1/11*z + 7/11, + 1/11*z^5 + 1/11*z^4 + 1/11*z^3 + 2/11*z^2 + 8/11*z + 7/11] Number fields defined by non-monic and non-integral polynomials are supported (:trac:`252`):: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(2*x^2 - 1/3) sage: K.ideal(a).basis() [1, a] @@ -657,6 +680,7 @@ def free_module(self): This also works for relative extensions:: + sage: x = polygen(ZZ) sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 2]) sage: I = K.fractional_ideal(4) sage: I.free_module() @@ -713,6 +737,7 @@ def reduce_equiv(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<w> = NumberField(x^2 + 23) sage: I = ideal(w*23^5); I Fractional ideal (6436343*w) @@ -734,22 +759,23 @@ def gens_reduced(self, proof=None): Express this ideal in terms of at most two generators, and one if possible. - This function indirectly uses ``bnfisprincipal``, so set + This function indirectly uses :pari:`bnfisprincipal`, so set ``proof=True`` if you want to prove correctness (which *is* the default). EXAMPLES:: + sage: x = polygen(ZZ) sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(x^2 + 5) sage: K.ideal(0).gens_reduced() (0,) - sage: J = K.ideal([a+2, 9]) + sage: J = K.ideal([a + 2, 9]) sage: J.gens() (a + 2, 9) sage: J.gens_reduced() # random sign (a + 2,) - sage: K.ideal([a+2, 3]).gens_reduced() + sage: K.ideal([a + 2, 3]).gens_reduced() (3, a + 2) TESTS:: @@ -802,14 +828,15 @@ def gens_two(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(x^2 + 5) - sage: J = K.ideal([a+2, 9]) + sage: J = K.ideal([a + 2, 9]) sage: J.gens() (a + 2, 9) sage: J.gens_two() (9, a + 2) - sage: K.ideal([a+5, a+8]).gens_two() + sage: K.ideal([a + 5, a + 8]).gens_two() (3, a + 2) sage: K.ideal(0).gens_two() (0, 0) @@ -853,9 +880,10 @@ def integral_basis(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: R.<x> = PolynomialRing(QQ) sage: K.<i> = NumberField(x^2 + 1) - sage: J = K.ideal(i+1) + sage: J = K.ideal(i + 1) sage: J.integral_basis() [2, i + 1] """ @@ -869,12 +897,13 @@ def integral_split(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: R.<x> = PolynomialRing(QQ) - sage: K.<a> = NumberField(x^2-5) + sage: K.<a> = NumberField(x^2 - 5) sage: I = K.ideal(2/(5+a)) sage: I.is_integral() False - sage: J,d = I.integral_split() + sage: J, d = I.integral_split() sage: J Fractional ideal (-1/2*a + 5/2) sage: J.is_integral() @@ -904,20 +933,21 @@ def integral_split(self): def intersection(self, other): r""" - Return the intersection of self and other. + Return the intersection of ``self`` and ``other``. EXAMPLES:: sage: K.<a> = QuadraticField(-11) sage: p = K.ideal((a + 1)/2); q = K.ideal((a + 3)/2) - sage: p.intersection(q) == q.intersection(p) == K.ideal(a-2) + sage: p.intersection(q) == q.intersection(p) == K.ideal(a - 2) True An example with non-principal ideals:: + sage: x = polygen(ZZ) sage: L.<a> = NumberField(x^3 - 7) sage: p = L.ideal(a^2 + a + 1, 2) - sage: q = L.ideal(a+1) + sage: q = L.ideal(a + 1) sage: p.intersection(q) == L.ideal(8, 2*a + 2) True @@ -948,12 +978,12 @@ def intersection(self, other): def is_integral(self): """ - Return True if this ideal is integral. + Return ``True`` if this ideal is integral. EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: K.<a> = NumberField(x^5-x+1) + sage: K.<a> = NumberField(x^5 - x + 1) sage: K.ideal(a).is_integral() True sage: (K.ideal(1) / (3*a+1)).is_integral() @@ -968,8 +998,8 @@ def is_integral(self): def is_maximal(self): """ - Return True if this ideal is maximal. This is equivalent to - self being prime and nonzero. + Return ``True`` if this ideal is maximal. This is equivalent to + ``self`` being prime and nonzero. EXAMPLES:: @@ -984,7 +1014,7 @@ def is_maximal(self): def is_prime(self): """ - Return True if this ideal is prime. + Return ``True`` if this ideal is prime. EXAMPLES:: @@ -996,24 +1026,46 @@ def is_prime(self): False sage: K.ideal(17).is_prime() # ramified False + + TESTS: + + Check that we do not factor the norm of the ideal, this used + to take half an hour, see :trac:`33360`:: + + sage: K.<a,b,c> = NumberField([x^2-2,x^2-3,x^2-5]) + sage: t = (((-2611940*c + 1925290/7653)*b - 1537130/7653*c + ....: + 10130950)*a + (1343014/7653*c - 8349770)*b + ....: + 6477058*c - 2801449990/4002519) + sage: t.is_prime() + False """ try: return self._pari_prime is not None except AttributeError: - F = self.factor() # factorization with caching - if len(F) != 1 or F[0][1] != 1: - self._pari_prime = None - else: - self._pari_prime = F[0][0]._pari_prime - return self._pari_prime is not None + pass + + K = self.number_field().pari_nf() + I = self.pari_hnf() + + candidate = K.idealismaximal(I) or None + + # PARI uses probabilistic primality testing inside idealismaximal(). + if get_flag(None, 'arithmetic'): + # proof required, check using isprime() + if candidate and not candidate[0].isprime(): + candidate = None + + self._pari_prime = candidate + + return self._pari_prime is not None def pari_prime(self): r""" - Returns a PARI prime ideal corresponding to the ideal ``self``. + Return a PARI prime ideal corresponding to the ideal ``self``. INPUT: - - ``self`` - a prime ideal. + - ``self`` -- a prime ideal. OUTPUT: a PARI "prime ideal", i.e. a five-component vector `[p,a,e,f,b]` representing the prime ideal `p O_K + a O_K`, `e`, `f` as usual, `a` as @@ -1107,7 +1159,7 @@ def _cache_bnfisprincipal(self, proof=None, gens=False): def is_principal(self, proof=None): r""" - Return True if this ideal is principal. + Return ``True`` if this ideal is principal. Since it uses the PARI method :pari:`bnfisprincipal`, specify ``proof=True`` (this is the default setting) to prove the correctness @@ -1122,7 +1174,7 @@ def is_principal(self, proof=None): sage: I = P^5 sage: I.is_principal() True - sage: I # random + sage: I # random Fractional ideal (-1/2*a + 3/2) sage: P = K.ideal([2]).factor()[1][0] sage: I = P^5 @@ -1167,9 +1219,11 @@ def ideal_class_log(self, proof=None): An example with a more complicated class group:: + sage: x = polygen(ZZ) sage: K.<a, b> = NumberField([x^3 - x + 1, x^2 + 26]) sage: K.class_group() - Class group of order 18 with structure C6 x C3 of Number Field in a with defining polynomial x^3 - x + 1 over its base field + Class group of order 18 with structure C6 x C3 of + Number Field in a with defining polynomial x^3 - x + 1 over its base field sage: K.primes_above(7)[0].ideal_class_log() # random [1, 2] """ @@ -1216,18 +1270,19 @@ def S_ideal_class_log(self, S): def is_zero(self): """ - Return True iff self is the zero ideal + Return ``True`` iff ``self`` is the zero ideal - Note that `(0)` is a ``NumberFieldIdeal``, not a - ``NumberFieldFractionalIdeal``. + Note that `(0)` is a :class:`NumberFieldIdeal`, not a + :class:`NumberFieldFractionalIdeal`. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^2 + 2); K Number Field in a with defining polynomial x^2 + 2 sage: K.ideal(3).is_zero() False - sage: I=K.ideal(0); I.is_zero() + sage: I = K.ideal(0); I.is_zero() True sage: I Ideal (0) of Number Field in a with defining polynomial x^2 + 2 @@ -1240,6 +1295,7 @@ def norm(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^4 + 23); K Number Field in a with defining polynomial x^4 + 23 sage: I = K.ideal(19); I @@ -1261,10 +1317,11 @@ def norm(self): def absolute_norm(self): """ - A synonym for norm. + A synonym for :meth:`norm`. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<i> = NumberField(x^2 + 1) sage: K.ideal(1 + 2*i).absolute_norm() 5 @@ -1273,10 +1330,11 @@ def absolute_norm(self): def relative_norm(self): """ - A synonym for norm. + A synonym for :meth:`norm`. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<i> = NumberField(x^2 + 1) sage: K.ideal(1 + 2*i).relative_norm() 5 @@ -1285,10 +1343,11 @@ def relative_norm(self): def absolute_ramification_index(self): """ - A synonym for ramification_index. + A synonym for :meth:`ramification_index`. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<i> = NumberField(x^2 + 1) sage: K.ideal(1 + i).absolute_ramification_index() 2 @@ -1297,10 +1356,11 @@ def absolute_ramification_index(self): def relative_ramification_index(self): """ - A synonym for ramification_index. + A synonym for :meth:`ramification_index`. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<i> = NumberField(x^2 + 1) sage: K.ideal(1 + i).relative_ramification_index() 2 @@ -1313,11 +1373,12 @@ def number_field(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^2 + 2); K Number Field in a with defining polynomial x^2 + 2 sage: K.ideal(3).number_field() Number Field in a with defining polynomial x^2 + 2 - sage: K.ideal(0).number_field() # not tested (not implemented) + sage: K.ideal(0).number_field() # not tested (not implemented) Number Field in a with defining polynomial x^2 + 2 """ return self.ring() @@ -1330,8 +1391,8 @@ def smallest_integer(self): EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: K.<a> = NumberField(x^2+6) - sage: I = K.ideal([4,a])/7; I + sage: K.<a> = NumberField(x^2 + 6) + sage: I = K.ideal([4, a])/7; I Fractional ideal (2/7, 1/7*a) sage: I.smallest_integer() 2 @@ -1391,10 +1452,11 @@ def valuation(self, p): (integer) The valuation of this fractional ideal at the prime `\mathfrak{p}`. If `\mathfrak{p}` is not prime, raise a - ValueError. + :class:`ValueError`. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^5 + 2); K Number Field in a with defining polynomial x^5 + 2 sage: i = K.ideal(38); i @@ -1408,7 +1470,8 @@ def valuation(self, p): sage: i.valuation(0) Traceback (most recent call last): ... - ValueError: p (= Ideal (0) of Number Field in a with defining polynomial x^5 + 2) must be nonzero + ValueError: p (= Ideal (0) of Number Field in a + with defining polynomial x^5 + 2) must be nonzero sage: K.ideal(0).valuation(K.factor(2)[0][0]) +Infinity """ @@ -1425,11 +1488,10 @@ def valuation(self, p): def decomposition_group(self): r""" - Return the decomposition group of self, as a subset of the - automorphism group of the number field of self. Raises an - error if the field isn't Galois. See the decomposition_group - method of the ``GaloisGroup_v2`` class for further examples - and doctests. + Return the decomposition group of ``self``, as a subset of the + automorphism group of the number field of ``self``. Raises an + error if the field isn't Galois. See the :meth:`GaloisGroup_v2.decomposition_group` + method for further examples and doctests. EXAMPLES:: @@ -1440,11 +1502,11 @@ def decomposition_group(self): def ramification_group(self, v): r""" - Return the `v`'th ramification group of self, i.e. the set of - elements `s` of the Galois group of the number field of self + Return the `v`'th ramification group of ``self``, i.e. the set of + elements `s` of the Galois group of the number field of ``self`` (which we assume is Galois) such that `s` acts trivially modulo the `(v+1)`'st power of self. See the - ramification_group method of the ``GaloisGroup`` class for + :meth:`GaloisGroup.ramification_group` method for further examples and doctests. EXAMPLES:: @@ -1459,11 +1521,11 @@ def ramification_group(self, v): def inertia_group(self): r""" - Return the inertia group of self, i.e. the set of elements s of the - Galois group of the number field of self (which we assume is Galois) - such that s acts trivially modulo self. This is the same as the 0th - ramification group of self. See the inertia_group method of the - ``GaloisGroup_v2`` class for further examples and doctests. + Return the inertia group of ``self``, i.e. the set of elements `s` of the + Galois group of the number field of ``self`` (which we assume is Galois) + such that `s` acts trivially modulo ``self``. This is the same as the 0th + ramification group of ``self``. See the + :meth:`GaloisGroup_v2.inertia_group` method further examples and doctests. EXAMPLES:: @@ -1489,24 +1551,25 @@ def random_element(self, *args, **kwds): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^3 + 2) - sage: I = K.ideal(1-a) + sage: I = K.ideal(1 - a) sage: I.random_element() # random output -a^2 - a - 19 sage: I.random_element(distribution="uniform") # random output a^2 - 2*a - 8 - sage: I.random_element(-30,30) # random output + sage: I.random_element(-30, 30) # random output -7*a^2 - 17*a - 75 sage: I.random_element(-100, 200).is_integral() True - sage: I.random_element(-30,30).parent() is K + sage: I.random_element(-30, 30).parent() is K True A relative example:: sage: K.<a, b> = NumberField([x^2 + 2, x^2 + 1000*x + 1]) - sage: I = K.ideal(1-a) - sage: I.random_element() # random output + sage: I = K.ideal(1 - a) + sage: I.random_element() # random output 17/500002*a^3 + 737253/250001*a^2 - 1494505893/500002*a + 752473260/250001 sage: I.random_element().is_integral() True @@ -1521,14 +1584,14 @@ def random_element(self, *args, **kwds): def artin_symbol(self): r""" - Return the Artin symbol `( K / \QQ, P)`, where `K` is the - number field of `P` =self. This is the unique element `s` of + Return the Artin symbol `(K / \QQ, P)`, where `K` is the + number field of `P` = ``self``. This is the unique element `s` of the decomposition group of `P` such that `s(x) = x^p \pmod{P}` where `p` is the residue characteristic of `P`. (Here `P` - (self) should be prime and unramified.) + (``self``) should be prime and unramified.) - See the ``artin_symbol`` method of the ``GaloisGroup_v2`` - class for further documentation and examples. + See the :meth:`GaloisGroup_v2.artin_symbol` method + for further documentation and examples. EXAMPLES:: @@ -1539,23 +1602,26 @@ class for further documentation and examples. def residue_symbol(self, e, m, check=True): r""" - The m-th power residue symbol for an element e and the proper ideal. + The `m`-th power residue symbol for an element `e` and the proper ideal. .. MATH:: \left(\frac{\alpha}{\mathbf{P}}\right) \equiv \alpha^{\frac{N(\mathbf{P})-1}{m}} \operatorname{mod} \mathbf{P} - .. note:: accepts m=1, in which case returns 1 + .. note:: accepts `m=1`, in which case returns 1 .. note:: can also be called for an element from sage.rings.number_field_element.residue_symbol - .. note:: e is coerced into the number field of self + .. note:: `e` is coerced into the number field of ``self`` + + .. note:: - .. note:: if m=2, e is an integer, and self.number_field() has absolute degree 1 (i.e. it is a copy of the rationals), then this calls kronecker_symbol, which is implemented using GMP. + if `m=2`, `e` is an integer, and ``self.number_field()`` has absolute degree 1 (i.e. it is a copy of the rationals), + then this calls :func:`kronecker_symbol`, which is implemented using GMP. INPUT: - - ``e`` - element of the number field + - ``e`` -- element of the number field - - ``m`` - positive integer + - ``m`` -- positive integer OUTPUT: @@ -1565,6 +1631,7 @@ def residue_symbol(self, e, m, check=True): Quadratic Residue (7 is not a square modulo 11):: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x - 1) sage: K.ideal(11).residue_symbol(7,2) -1 @@ -1572,13 +1639,13 @@ def residue_symbol(self, e, m, check=True): Cubic Residue:: sage: K.<w> = NumberField(x^2 - x + 1) - sage: K.ideal(17).residue_symbol(w^2 + 3,3) + sage: K.ideal(17).residue_symbol(w^2 + 3, 3) -w - The field must contain the m-th roots of unity:: + The field must contain the `m`-th roots of unity:: sage: K.<w> = NumberField(x^2 - x + 1) - sage: K.ideal(17).residue_symbol(w^2 + 3,5) + sage: K.ideal(17).residue_symbol(w^2 + 3, 5) Traceback (most recent call last): ... ValueError: The residue symbol to that power is not defined for the number field @@ -1659,8 +1726,8 @@ def _quadratic_form(self): This is not defined for higher-degree extensions:: - sage: x = var('x') - sage: K.<a> = NumberField(x**3-x-1) + sage: x = polygen(ZZ) + sage: K.<a> = NumberField(x**3 - x - 1) sage: K.ideal(a)._quadratic_form() Traceback (most recent call last): ... @@ -1698,6 +1765,7 @@ def basis_to_module(B, K): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<w> = NumberField(x^4 + 1) sage: from sage.rings.number_field.number_field_ideal import basis_to_module sage: basis_to_module([K.0, K.0^2 + 3], K) @@ -1713,7 +1781,7 @@ def basis_to_module(B, K): def is_NumberFieldIdeal(x): """ - Return True if x is an ideal of a number field. + Return ``True`` if `x` is an ideal of a number field. EXAMPLES:: @@ -1722,6 +1790,8 @@ def is_NumberFieldIdeal(x): False sage: is_NumberFieldIdeal(ideal(5)) False + + sage: x = polygen(ZZ) sage: k.<a> = NumberField(x^2 + 2) sage: I = k.ideal([a + 1]); I Fractional ideal (a + 1) @@ -1741,6 +1811,7 @@ class NumberFieldFractionalIdeal(MultiplicativeGroupElement, NumberFieldIdeal, I EXAMPLES:: + sage: x = polygen(ZZ) sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(x^3 - 2) sage: I = K.ideal(2/(5+a)) @@ -1765,6 +1836,7 @@ def __init__(self, field, gens, coerce=True): EXAMPLES:: + sage: x = polygen(ZZ) sage: NumberField(x^2 + 1, 'a').ideal(7) Fractional ideal (7) """ @@ -1792,7 +1864,8 @@ def __repr__(self): EXAMPLES:: - sage: K.<a>=NumberField(x^2+5) + sage: x = polygen(ZZ) + sage: K.<a> = NumberField(x^2 + 5) sage: I = K.ideal([2,1+a]); I Fractional ideal (2, a + 1) sage: type(I) @@ -1802,7 +1875,7 @@ def __repr__(self): def divides(self, other): """ - Returns True if this ideal divides other and False otherwise. + Return ``True`` if this ideal divides other and False otherwise. EXAMPLES:: @@ -1827,16 +1900,19 @@ def factor(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^4 + 23); K Number Field in a with defining polynomial x^4 + 23 sage: I = K.ideal(19); I Fractional ideal (19) sage: F = I.factor(); F - (Fractional ideal (19, 1/2*a^2 + a - 17/2)) * (Fractional ideal (19, 1/2*a^2 - a - 17/2)) + (Fractional ideal (19, 1/2*a^2 + a - 17/2)) + * (Fractional ideal (19, 1/2*a^2 - a - 17/2)) sage: type(F) <class 'sage.structure.factorization.Factorization'> sage: list(F) - [(Fractional ideal (19, 1/2*a^2 + a - 17/2), 1), (Fractional ideal (19, 1/2*a^2 - a - 17/2), 1)] + [(Fractional ideal (19, 1/2*a^2 + a - 17/2), 1), + (Fractional ideal (19, 1/2*a^2 - a - 17/2), 1)] sage: F.prod() Fractional ideal (19) @@ -1871,18 +1947,22 @@ def factor(self): def prime_factors(self): """ - Return a list of the prime ideal factors of self + Return a list of the prime ideal factors of ``self``. OUTPUT: - list -- list of prime ideals (a new list is returned - each time this function is called) + + list of prime ideals (a new list is returned + each time this function is called) EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<w> = NumberField(x^2 + 23) sage: I = ideal(w+1) sage: I.prime_factors() - [Fractional ideal (2, 1/2*w - 1/2), Fractional ideal (2, 1/2*w + 1/2), Fractional ideal (3, 1/2*w + 1/2)] + [Fractional ideal (2, 1/2*w - 1/2), + Fractional ideal (2, 1/2*w + 1/2), + Fractional ideal (3, 1/2*w + 1/2)] """ return [x[0] for x in self.factor()] @@ -1890,10 +1970,11 @@ def prime_factors(self): def _div_(self, other): """ - Return the quotient self / other. + Return the quotient ``self`` / ``other``. EXAMPLES:: + sage: x = polygen(ZZ) sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(x^2 - 5) sage: I = K.ideal(2/(5+a)) @@ -1910,10 +1991,11 @@ def _div_(self, other): def __invert__(self): """ - Return the multiplicative inverse of self. Call with ~self. + Return the multiplicative inverse of ``self``. Call with ``~self``. EXAMPLES:: + sage: x = polygen(ZZ) sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(x^3 - 2) sage: I = K.ideal(2/(5+a)) @@ -1933,11 +2015,12 @@ def __invert__(self): def is_maximal(self): """ - Return True if this ideal is maximal. This is equivalent to - self being prime, since it is nonzero. + Return ``True`` if this ideal is maximal. This is equivalent to + ``self`` being prime, since it is nonzero. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^3 + 3); K Number Field in a with defining polynomial x^3 + 3 sage: K.ideal(5).is_maximal() @@ -1949,7 +2032,7 @@ def is_maximal(self): def is_trivial(self, proof=None): """ - Returns True if this is a trivial ideal. + Return ``True`` if this is a trivial ideal. EXAMPLES:: @@ -1960,7 +2043,7 @@ def is_trivial(self, proof=None): sage: J = F.ideal(5) sage: J.is_trivial() False - sage: (I+J).is_trivial() + sage: (I + J).is_trivial() True """ return self == self.number_field().ideal(1) @@ -1968,7 +2051,7 @@ def is_trivial(self, proof=None): def ramification_index(self): r""" Return the ramification index of this fractional ideal, - assuming it is prime. Otherwise, raise a ValueError. + assuming it is prime. Otherwise, raise a :class:`ValueError`. The ramification index is the power of this prime appearing in the factorization of the prime in `\ZZ` that this prime lies @@ -1976,6 +2059,7 @@ def ramification_index(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^2 + 2); K Number Field in a with defining polynomial x^2 + 2 sage: f = K.factor(2); f @@ -1993,8 +2077,8 @@ def ramification_index(self): def reduce(self, f): r""" - Return the canonical reduction of the element of `f` modulo the ideal - `I` (=self). This is an element of `R` (the ring of integers of the + Return the canonical reduction of the element `f` modulo the ideal + `I` (= ``self``). This is an element of `R` (the ring of integers of the number field) that is equivalent modulo `I` to `f`. An error is raised if this fractional ideal is not integral or @@ -2002,25 +2086,27 @@ def reduce(self, f): INPUT: - - ``f`` - an integral element of the number field + - ``f`` -- an integral element of the number field OUTPUT: - An integral element `g`, such that `f - g` belongs to the ideal self + An integral element `g`, such that `f - g` belongs to the ideal ``self`` and such that `g` is a canonical reduced representative of the coset - `f + I` (`I` =self) as described in the ``residues`` function, namely an integral element with coordinates `(r_0, \dots,r_{n-1})`, where: + `f + I` (where `I` = ``self``) as described in the method :meth:`residues`, + namely an integral element with coordinates `(r_0, \dots,r_{n-1})`, where: - `r_i` is reduced modulo `d_i` - - `d_i = b_i[i]`, with `{b_0, b_1, \dots, b_n}` HNF basis - of the ideal self. + - `d_i = b_i[i]`, with `\{b_0, b_1, \dots, b_n\}` HNF basis + of the ideal ``self``. .. note:: The reduced element `g` is not necessarily small. To get a - small `g` use the method ``small_residue``. + small `g` use the method :meth:`small_residue`. EXAMPLES:: + sage: x = polygen(ZZ) sage: k.<a> = NumberField(x^3 + 11) sage: I = k.ideal(5, a^2 - a + 1) sage: c = 4*a + 9 @@ -2038,7 +2124,7 @@ def reduce(self, f): True The reduced element does not necessarily have smaller norm (use - ``small_residue`` for that) + :meth:`small_residue` for that) :: @@ -2105,31 +2191,33 @@ def residues(self): - `r_i` is reduced modulo `d_i` - - `d_i = b_i[i]`, with `{b_0, b_1, \dots, b_n}` HNF basis + - `d_i = b_i[i]`, with `\{b_0, b_1, \dots, b_n\}` HNF basis of the ideal. AUTHOR: John Cremona (modified by Maite Aranes) EXAMPLES:: - sage: K.<i>=NumberField(x^2+1) - sage: res = K.ideal(2).residues(); res + sage: x = polygen(ZZ) + sage: K.<i> = NumberField(x^2 + 1) + sage: res = K.ideal(2).residues(); res xmrange_iter([[0, 1], [0, 1]], <function ...<lambda> at 0x...>) sage: list(res) [0, i, 1, i + 1] - sage: list(K.ideal(2+i).residues()) + sage: list(K.ideal(2 + i).residues()) [-2*i, -i, 0, i, 2*i] sage: list(K.ideal(i).residues()) [0] - sage: I = K.ideal(3+6*i) - sage: reps=I.residues() + sage: I = K.ideal(3 + 6*i) + sage: reps = I.residues() sage: len(list(reps)) == I.norm() True - sage: all(r == s or not (r-s) in I for r in reps for s in reps) # long time (6s on sage.math, 2011) + sage: all(r == s or not (r-s) in I # long time (6s on sage.math, 2011) + ....: for r in reps for s in reps) True - sage: K.<a> = NumberField(x^3-10) - sage: I = K.ideal(a-1) + sage: K.<a> = NumberField(x^3 - 10) + sage: I = K.ideal(a - 1) sage: len(list(I.residues())) == I.norm() True @@ -2154,45 +2242,46 @@ def residues(self): def invertible_residues(self, reduce=True): r""" - Returns a iterator through a list of invertible residues + Return an iterator through a list of invertible residues modulo this integral ideal. An error is raised if this fractional ideal is not integral. INPUT: - - ``reduce`` - bool. If True (default), use ``small_residue`` to get + - ``reduce`` -- bool. If ``True`` (default), use ``small_residue`` to get small representatives of the residues. OUTPUT: - - An iterator through a list of invertible residues modulo this ideal - `I`, i.e. a list of elements in the ring of integers `R` representing - the elements of `(R/I)^*`. + An iterator through a list of invertible residues modulo this ideal + `I`, i.e. a list of elements in the ring of integers `R` representing + the elements of `(R/I)^*`. ALGORITHM: Use :pari:`idealstar` to find the group structure and generators of the multiplicative group modulo the ideal. EXAMPLES:: - sage: K.<i>=NumberField(x^2+1) - sage: ires = K.ideal(2).invertible_residues(); ires + sage: x = polygen(ZZ) + sage: K.<i> = NumberField(x^2 + 1) + sage: ires = K.ideal(2).invertible_residues(); ires xmrange_iter([[0, 1]], <function ...<lambda> at 0x...>) sage: list(ires) [1, -i] - sage: list(K.ideal(2+i).invertible_residues()) + sage: list(K.ideal(2 + i).invertible_residues()) [1, 2, 4, 3] sage: list(K.ideal(i).residues()) [0] sage: list(K.ideal(i).invertible_residues()) [1] - sage: I = K.ideal(3+6*i) - sage: units=I.invertible_residues() - sage: len(list(units))==I.euler_phi() + sage: I = K.ideal(3 + 6*i) + sage: units = I.invertible_residues() + sage: len(list(units)) == I.euler_phi() True - sage: K.<a> = NumberField(x^3-10) - sage: I = K.ideal(a-1) + sage: K.<a> = NumberField(x^3 - 10) + sage: I = K.ideal(a - 1) sage: len(list(I.invertible_residues())) == I.euler_phi() True @@ -2214,38 +2303,39 @@ def invertible_residues(self, reduce=True): def invertible_residues_mod(self, subgp_gens=[], reduce=True): r""" - Returns a iterator through a list of representatives for the invertible + Return a iterator through a list of representatives for the invertible residues modulo this integral ideal, modulo the subgroup generated by the elements in the list ``subgp_gens``. INPUT: - - ``subgp_gens`` - either None or a list of elements of the number - field of self. These need not be integral, but should be coprime to - the ideal self. If the list is empty or None, the function returns + - ``subgp_gens`` -- either ``None`` or a list of elements of the number + field of ``self``. These need not be integral, but should be coprime to + the ideal ``self``. If the list is empty or ``None``, the function returns an iterator through a list of representatives for the invertible - residues modulo the integral ideal self. + residues modulo the integral ideal ``self``. - - ``reduce`` - bool. If True (default), use ``small_residues`` to + - ``reduce`` -- bool. If ``True`` (default), use ``small_residues`` to get small representatives of the residues. .. note:: - See also invertible_residues() for a simpler version without the subgroup. + See also :meth:`invertible_residues` for a simpler version without the subgroup. OUTPUT: - - An iterator through a list of representatives for the invertible - residues modulo self and modulo the group generated by - ``subgp_gens``, i.e. a list of elements in the ring of integers `R` - representing the elements of `(R/I)^*/U`, where `I` is this ideal and - `U` is the subgroup of `(R/I)^*` generated by ``subgp_gens``. + An iterator through a list of representatives for the invertible + residues modulo ``self`` and modulo the group generated by + ``subgp_gens``, i.e. a list of elements in the ring of integers `R` + representing the elements of `(R/I)^*/U`, where `I` is this ideal and + `U` is the subgroup of `(R/I)^*` generated by ``subgp_gens``. EXAMPLES: :: - sage: k.<a> = NumberField(x^2 +23) + sage: x = polygen(ZZ) + sage: k.<a> = NumberField(x^2 + 23) sage: I = k.ideal(a) sage: list(I.invertible_residues_mod([-1])) [1, 5, 2, 10, 4, 20, 8, 17, 16, 11, 9] @@ -2258,8 +2348,8 @@ def invertible_residues_mod(self, subgp_gens=[], reduce=True): :: - sage: K.<a> = NumberField(x^3-10) - sage: I = K.ideal(a-1) + sage: K.<a> = NumberField(x^3 - 10) + sage: I = K.ideal(a - 1) sage: len(list(I.invertible_residues_mod([]))) == I.euler_phi() True @@ -2315,7 +2405,8 @@ def denominator(self): EXAMPLES:: - sage: K.<i>=NumberField(x^2+1) + sage: x = polygen(ZZ) + sage: K.<i> = NumberField(x^2 + 1) sage: I = K.ideal((3+4*i)/5); I Fractional ideal (4/5*i + 3/5) sage: I.denominator() @@ -2345,7 +2436,8 @@ def numerator(self): EXAMPLES:: - sage: K.<i>=NumberField(x^2+1) + sage: x = polygen(ZZ) + sage: K.<i> = NumberField(x^2 + 1) sage: I = K.ideal((3+4*i)/5); I Fractional ideal (4/5*i + 3/5) sage: I.denominator() @@ -2368,7 +2460,7 @@ def numerator(self): def is_coprime(self, other): """ - Returns True if this ideal is coprime to the other, else False. + Return ``True`` if this ideal is coprime to ``other``, else ``False``. INPUT: @@ -2377,7 +2469,7 @@ def is_coprime(self, other): OUTPUT: - True if self and other are coprime, else False. + ``True`` if ``self`` and ``other`` are coprime, else ``False``. .. note:: @@ -2388,16 +2480,17 @@ def is_coprime(self, other): EXAMPLES:: - sage: K.<i>=NumberField(x^2+1) - sage: I = K.ideal(2+i) - sage: J = K.ideal(2-i) + sage: x = polygen(ZZ) + sage: K.<i> = NumberField(x^2 + 1) + sage: I = K.ideal(2 + i) + sage: J = K.ideal(2 - i) sage: I.is_coprime(J) True sage: (I^-1).is_coprime(J^3) True sage: I.is_coprime(5) False - sage: I.is_coprime(6+i) + sage: I.is_coprime(6 + i) True See :trac:`4536`:: @@ -2431,26 +2524,29 @@ def is_coprime(self, other): N1 = self.numerator() D2 = other.denominator() N2 = other.numerator() - return N1+N2==one and N1+D2==one and D1+N2==one and D1+D2==one + return N1+N2 == one and N1+D2 == one and D1+N2 == one and D1+D2 == one def idealcoprime(self, J): """ - Returns l such that l*self is coprime to J. + Return `l` such that ``l*self`` is coprime to `J`. INPUT: - - ``J`` - another integral ideal of the same field as self, which must also be integral. + - ``J`` -- another integral ideal of the same field as ``self``, which must also be integral. OUTPUT: - - ``l`` - an element such that l*self is coprime to the ideal J + an element `l` such that ``l*self`` is coprime to the ideal `J` - TODO: Extend the implementation to non-integral ideals. + .. TODO:: + + Extend the implementation to non-integral ideals. EXAMPLES:: + sage: x = polygen(ZZ) sage: k.<a> = NumberField(x^2 + 23) - sage: A = k.ideal(a+1) + sage: A = k.ideal(a + 1) sage: B = k.ideal(3) sage: A.is_coprime(B) False @@ -2468,7 +2564,7 @@ def idealcoprime(self, J): depends on the PARI version:: sage: k.<a> = NumberField(x^2 + 23) - sage: A = k.ideal(a+1) + sage: A = k.ideal(a + 1) sage: B = k.ideal(3) sage: lam = A.idealcoprime(B) sage: lam in (-1/6*a + 1/6, 1/6*a - 1/6) @@ -2485,20 +2581,21 @@ def idealcoprime(self, J): def small_residue(self, f): r""" - Given an element `f` of the ambient number field, returns an - element `g` such that `f - g` belongs to the ideal self (which + Given an element `f` of the ambient number field, return an + element `g` such that `f - g` belongs to the ideal ``self`` (which must be integral), and `g` is small. .. note:: The reduced representative returned is not uniquely determined. - ALGORITHM: Uses Pari function :pari:`nfeltreduce`. + ALGORITHM: Uses PARI function :pari:`nfeltreduce`. EXAMPLES: :: + sage: x = polygen(ZZ) sage: k.<a> = NumberField(x^2 + 5) sage: I = k.ideal(a) sage: I.small_residue(14) @@ -2519,13 +2616,13 @@ def small_residue(self, f): def _pari_bid_(self, flag=1): """ - Returns the pari structure ``bid`` associated to the ideal self. + Return the PARI structure ``bid`` associated to the ideal ``self``. INPUT: - - ``flag`` - when flag=2 it computes the generators of the group - `(O_K/I)^*`, which takes more time. By default - flag=1 (no generators are computed). + - ``flag`` -- when ``flag=2`` it computes the generators of the group + `(O_K/I)^*`, which takes more time. By default + ``flag=1`` (no generators are computed). OUTPUT: @@ -2533,6 +2630,7 @@ def _pari_bid_(self, flag=1): EXAMPLES:: + sage: x = polygen(ZZ) sage: k.<a> = NumberField(x^4 + 13) sage: I = k.ideal(2, a^2 + 1) sage: hasattr(I, '_bid') @@ -2557,15 +2655,15 @@ def _pari_bid_(self, flag=1): def idealstar(self, flag=1): r""" - Returns the finite abelian group `(O_K/I)^*`, where I is the ideal self - of the number field K, and `O_K` is the ring of integers of K. + Return the finite abelian group `(O_K/I)^*`, where `I` is the ideal ``self`` + of the number field `K`, and `O_K` is the ring of integers of `K`. INPUT: - ``flag`` (int default 1) -- when ``flag`` =2, it also computes the generators of the group `(O_K/I)^*`, which takes more time. By default ``flag`` =1 (no generators are - computed). In both cases the special pari structure ``bid`` + computed). In both cases the special PARI structure ``bid`` is computed as well. If ``flag`` =0 (deprecated) it computes only the group structure of `(O_K/I)^*` (with generators) and not the special ``bid`` structure. @@ -2576,14 +2674,15 @@ def idealstar(self, flag=1): .. note:: - Uses the pari function :pari:`idealstar`. The pari function outputs + Uses the PARI function :pari:`idealstar`. The PARI function outputs a special ``bid`` structure which is stored in the internal - field ``_bid`` of the ideal (when flag=1,2). The special structure - ``bid`` is used in the pari function :pari:`ideallog` + field ``_bid`` of the ideal (when ``flag`` = 1,2). The special structure + ``bid`` is used in the PARI function :pari:`ideallog` to compute discrete logarithms. EXAMPLES:: + sage: x = polygen(ZZ) sage: k.<a> = NumberField(x^3 - 11) sage: A = k.ideal(5) sage: G = A.idealstar(); G @@ -2608,7 +2707,7 @@ def idealstar(self, flag=1): ALGORITHM: Uses Pari function :pari:`idealstar` """ k = self.number_field() - if flag==0 and not hasattr(self, '_bid'): + if flag == 0 and not hasattr(self, '_bid'): G = k.pari_nf().idealstar(self.pari_hnf(), 0) else: G = self._pari_bid_(flag) @@ -2625,41 +2724,42 @@ def idealstar(self, flag=1): def ideallog(self, x, gens=None, check=True): r""" - Returns the discrete logarithm of x with respect to the generators - given in the ``bid`` structure of the ideal self, or with respect to + Return the discrete logarithm of `x` with respect to the generators + given in the ``bid`` structure of the ideal ``self``, or with respect to the generators ``gens`` if these are given. INPUT: - - ``x`` - a non-zero element of the number field of self, + - ``x`` -- a non-zero element of the number field of ``self``, which must have valuation equal to 0 at all prime ideals in - the support of the ideal self. - - ``gens`` - a list of elements of the number field which generate `(R + the support of the ideal ``self``. + - ``gens`` -- a list of elements of the number field which generate `(R / I)^*`, where `R` is the ring of integers of the field and `I` is this ideal, or ``None``. If ``None``, use the generators calculated by :meth:`~idealstar`. - - ``check`` - if True, do a consistency check on the results. Ignored - if ``gens`` is None. + - ``check`` -- if ``True``, do a consistency check on the results. Ignored + if ``gens`` is ``None``. OUTPUT: - - ``l`` - a list of non-negative integers `(x_i)` such that `x = - \prod_i g_i^{x_i}` in `(R/I)^*`, where `x_i` are the generators, and - the list `(x_i)` is lexicographically minimal with respect to this - requirement. If the `x_i` generate independent cyclic factors of - order `d_i`, as is the case for the default generators calculated by - :meth:`~idealstar`, this just means that `0 \le x_i < d_i`. + a list of non-negative integers `(x_i)` such that `x = + \prod_i g_i^{x_i}` in `(R/I)^*`, where `x_i` are the generators, and + the list `(x_i)` is lexicographically minimal with respect to this + requirement. If the `x_i` generate independent cyclic factors of + order `d_i`, as is the case for the default generators calculated by + :meth:`~idealstar`, this just means that `0 \le x_i < d_i`. - A ``ValueError`` will be raised if the elements specified in ``gens`` + A :class:`ValueError` will be raised if the elements specified in ``gens`` do not in fact generate the unit group (even if the element `x` is in the subgroup they generate). EXAMPLES:: + sage: x = polygen(ZZ) sage: k.<a> = NumberField(x^3 - 11) sage: A = k.ideal(5) sage: G = A.idealstar(2) - sage: l = A.ideallog(a^2 +3) + sage: l = A.ideallog(a^2 + 3) sage: r = G(l).value() sage: (a^2 + 3) - r in A True @@ -2670,16 +2770,16 @@ def ideallog(self, x, gens=None, check=True): sage: K.<a> = NumberField(x^2 - 7) sage: I = K.ideal(17) - sage: I.ideallog(a + 7, [1+a, 2]) + sage: I.ideallog(a + 7, [1 + a, 2]) [10, 3] - sage: I.ideallog(a + 7, [2, 1+a]) + sage: I.ideallog(a + 7, [2, 1 + a]) [0, 118] sage: L.<b> = NumberField(x^4 - x^3 - 7*x^2 + 3*x + 2) sage: J = L.ideal(-b^3 - b^2 - 2) sage: u = -14*b^3 + 21*b^2 + b - 1 sage: v = 4*b^2 + 2*b - 1 - sage: J.ideallog(5+2*b, [u, v], check=True) + sage: J.ideallog(5 + 2*b, [u, v], check=True) [4, 13] A non-example:: @@ -2687,10 +2787,11 @@ def ideallog(self, x, gens=None, check=True): sage: I.ideallog(a + 7, [2]) Traceback (most recent call last): ... - ValueError: Given elements do not generate unit group -- they generate a subgroup of index 36 + ValueError: Given elements do not generate unit group -- + they generate a subgroup of index 36 - ALGORITHM: Uses Pari function :pari:`ideallog`, and (if ``gens`` is not - None) a Hermite normal form calculation to express the result in terms + ALGORITHM: Uses PARI function :pari:`ideallog`, and (if ``gens`` is not + ``None``) a Hermite normal form calculation to express the result in terms of the generators ``gens``. """ # sanitise input @@ -2713,7 +2814,7 @@ def ideallog(self, x, gens=None, check=True): G = self.idealstar(2) invs = G.invariants() - from sage.matrix.constructor import Matrix as matrix + from sage.matrix.constructor import matrix from sage.matrix.special import identity_matrix from sage.matrix.special import zero_matrix from sage.matrix.special import diagonal_matrix @@ -2748,7 +2849,7 @@ def ideallog(self, x, gens=None, check=True): def element_1_mod(self, other): r""" - Returns an element `r` in this ideal such that `1-r` is in other + Return an element `r` in this ideal such that `1-r` is in ``other`` An error is raised if either ideal is not integral of if they are not coprime. @@ -2760,29 +2861,30 @@ def element_1_mod(self, other): OUTPUT: - An element `r` of the ideal self such that `1-r` is in the ideal other + An element `r` of the ideal self such that `1-r` is in the ideal ``other`` AUTHOR: Maite Aranes (modified to use PARI's :pari:`idealaddtoone` by Francis Clarke) EXAMPLES:: - sage: K.<a> = NumberField(x^3-2) - sage: A = K.ideal(a+1); A; A.norm() + sage: x = polygen(ZZ) + sage: K.<a> = NumberField(x^3 - 2) + sage: A = K.ideal(a + 1); A; A.norm() Fractional ideal (a + 1) 3 - sage: B = K.ideal(a^2-4*a+2); B; B.norm() + sage: B = K.ideal(a^2 - 4*a + 2); B; B.norm() Fractional ideal (a^2 - 4*a + 2) 68 sage: r = A.element_1_mod(B); r -33 sage: r in A True - sage: 1-r in B + sage: 1 - r in B True TESTS:: - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: A = K.ideal(a+1) sage: B = K.ideal(a^2-4*a+1); B; B.norm() Fractional ideal (a^2 - 4*a + 1) @@ -2817,7 +2919,7 @@ def element_1_mod(self, other): def euler_phi(self): r""" - Returns the Euler `\varphi`-function of this integral ideal. + Return the Euler `\varphi`-function of this integral ideal. This is the order of the multiplicative group of the quotient modulo the ideal. @@ -2826,8 +2928,9 @@ def euler_phi(self): EXAMPLES:: - sage: K.<i>=NumberField(x^2+1) - sage: I = K.ideal(2+i) + sage: x = polygen(ZZ) + sage: K.<i> = NumberField(x^2 + 1) + sage: I = K.ideal(2 + i) sage: [r for r in I.residues() if I.is_coprime(r)] [-2*i, -i, i, 2*i] sage: I.euler_phi() @@ -2837,7 +2940,7 @@ def euler_phi(self): 100 sage: len([r for r in J.residues() if J.is_coprime(r)]) 100 - sage: J = K.ideal(3-2*i) + sage: J = K.ideal(3 - 2*i) sage: I.is_coprime(J) True sage: I.euler_phi()*J.euler_phi() == (I*J).euler_phi() @@ -2848,14 +2951,13 @@ def euler_phi(self): """ if not self.is_integral(): raise ValueError("euler_phi only defined for integral ideals") - return prod([(np-1)*np**(e-1) \ - for np,e in [(p.absolute_norm(),e) \ - for p,e in self.factor()]]) + it = ((p.absolute_norm(), e) for p, e in self.factor()) + return prod((np - 1) * np**(e - 1) for np, e in it) - def prime_to_S_part(self,S): + def prime_to_S_part(self, S): r""" Return the part of this fractional ideal which is coprime to - the prime ideals in the list ``S``. + the prime ideals in the list `S`. .. NOTE:: @@ -2865,7 +2967,7 @@ def prime_to_S_part(self,S): INPUT: - - `S` -- a list of prime ideals + - ``S`` -- a list of prime ideals OUTPUT: @@ -2875,18 +2977,21 @@ def prime_to_S_part(self,S): EXAMPLES:: - sage: K.<a> = NumberField(x^2-23) + sage: x = polygen(ZZ) + sage: K.<a> = NumberField(x^2 - 23) sage: I = K.ideal(24) - sage: S = [K.ideal(-a+5),K.ideal(5)] + sage: S = [K.ideal(-a + 5), K.ideal(5)] sage: I.prime_to_S_part(S) Fractional ideal (3) sage: J = K.ideal(15) sage: J.prime_to_S_part(S) Fractional ideal (3) - sage: K.<a> = NumberField(x^5-23) + sage: K.<a> = NumberField(x^5 - 23) sage: I = K.ideal(24) - sage: S = [K.ideal(15161*a^4 + 28383*a^3 + 53135*a^2 + 99478*a + 186250),K.ideal(2*a^4 + 3*a^3 + 4*a^2 + 15*a + 11), K.ideal(101)] + sage: S = [K.ideal(15161*a^4 + 28383*a^3 + 53135*a^2 + 99478*a + 186250), + ....: K.ideal(2*a^4 + 3*a^3 + 4*a^2 + 15*a + 11), + ....: K.ideal(101)] sage: I.prime_to_S_part(S) Fractional ideal (24) """ @@ -2898,11 +3003,11 @@ def prime_to_S_part(self,S): def is_S_unit(self, S): r""" - Return True if this fractional ideal is a unit with respect to the list of primes ``S``. + Return ``True`` if this fractional ideal is a unit with respect to the list of primes `S`. INPUT: - - `S` - a list of prime ideals (not checked if they are + - ``S`` -- a list of prime ideals (not checked if they are indeed prime). .. note:: @@ -2913,12 +3018,13 @@ def is_S_unit(self, S): OUTPUT: - True, if the ideal is an `S`-unit: that is, if the valuations of - the ideal at all primes not in `S` are zero. False, otherwise. + ``True``, if the ideal is an `S`-unit: that is, if the valuations of + the ideal at all primes not in `S` are zero. ``False``, otherwise. EXAMPLES:: - sage: K.<a> = NumberField(x^2+23) + sage: x = polygen(ZZ) + sage: K.<a> = NumberField(x^2 + 23) sage: I = K.ideal(2) sage: P = I.factor()[0][0] sage: I.is_S_unit([P]) @@ -2928,11 +3034,11 @@ def is_S_unit(self, S): def is_S_integral(self, S): r""" - Return True if this fractional ideal is integral with respect to the list of primes ``S``. + Return ``True`` if this fractional ideal is integral with respect to the list of primes `S`. INPUT: - - `S` - a list of prime ideals (not checked if they are indeed + - `S` -- a list of prime ideals (not checked if they are indeed prime). .. note:: @@ -2943,15 +3049,16 @@ def is_S_integral(self, S): OUTPUT: - True, if the ideal is `S`-integral: that is, if the valuations - of the ideal at all primes not in `S` are non-negative. False, + ``True``, if the ideal is `S`-integral: that is, if the valuations + of the ideal at all primes not in `S` are non-negative. ``False``, otherwise. EXAMPLES:: - sage: K.<a> = NumberField(x^2+23) + sage: x = polygen(ZZ) + sage: K.<a> = NumberField(x^2 + 23) sage: I = K.ideal(1/2) - sage: P = K.ideal(2,1/2*a - 1/2) + sage: P = K.ideal(2, 1/2*a - 1/2) sage: I.is_S_integral([P]) False @@ -2966,7 +3073,7 @@ def is_S_integral(self, S): def prime_to_idealM_part(self, M): r""" Version for integral ideals of the ``prime_to_m_part`` function over `\ZZ`. - Returns the largest divisor of self that is coprime to the ideal ``M``. + Return the largest divisor of ``self`` that is coprime to the ideal `M`. INPUT: @@ -2974,14 +3081,15 @@ def prime_to_idealM_part(self, M): OUTPUT: - An ideal which is the largest divisor of self that is coprime to `M`. + An ideal which is the largest divisor of ``self`` that is coprime to `M`. AUTHOR: Maite Aranes EXAMPLES:: + sage: x = polygen(ZZ) sage: k.<a> = NumberField(x^2 + 23) - sage: I = k.ideal(a+1) + sage: I = k.ideal(a + 1) sage: M = k.ideal(2, 1/2*a - 1/2) sage: J = I.prime_to_idealM_part(M); J Fractional ideal (12, 1/2*a + 13/2) @@ -3020,13 +3128,14 @@ def _p_quotient(self, p): OUTPUT: - - ``V`` -- a vector space of characteristic ``p`` + - `V` -- a vector space of characteristic `p` - ``quo`` -- a partially defined quotient homomorphism from the - ambient number field to ``V`` + ambient number field to `V` - ``lift`` -- a section of ``quo``. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<i> = NumberField(x^2 + 1); O = K.maximal_order() sage: I = K.factor(3)[0][0] sage: Q, quo, lift = I._p_quotient(3); Q @@ -3041,7 +3150,7 @@ def _p_quotient(self, p): sage: K.<i> = NumberField(x^2 + 1); O = K.maximal_order() sage: I = K.factor(5)[0][0] - sage: Q,quo,lift = I._p_quotient(5) + sage: Q, quo, lift = I._p_quotient(5) sage: lift(quo(i)) 3 sage: lift(quo(i)) - i in I @@ -3057,9 +3166,14 @@ def _p_quotient(self, p): Basis matrix: [1 3] sage: quo - Partially defined quotient map from Number Field in i with defining polynomial x^2 + 1 to an explicit vector space representation for the quotient of the ring of integers by (p,I) for the ideal I=Fractional ideal (-i - 2). + Partially defined quotient map + from Number Field in i with defining polynomial x^2 + 1 + to an explicit vector space representation for the quotient of + the ring of integers by (p,I) for the ideal I=Fractional ideal (-i - 2). sage: lift - Lifting map to Gaussian Integers in Number Field in i with defining polynomial x^2 + 1 from quotient of integers by Fractional ideal (-i - 2) + Lifting map + to Gaussian Integers in Number Field in i with defining polynomial x^2 + 1 + from quotient of integers by Fractional ideal (-i - 2) """ return quotient_char_p(self, p) @@ -3070,7 +3184,8 @@ def residue_field(self, names=None): EXAMPLES:: - sage: K.<a> = NumberField(x^3-7) + sage: x = polygen(ZZ) + sage: K.<a> = NumberField(x^3 - 7) sage: P = K.ideal(29).factor()[0][0] sage: P.residue_field() Residue field in abar of Fractional ideal (2*a^2 + 3*a - 10) @@ -3079,7 +3194,7 @@ def residue_field(self, names=None): Another example:: - sage: K.<a> = NumberField(x^3-7) + sage: K.<a> = NumberField(x^3 - 7) sage: P = K.ideal(389).factor()[0][0]; P Fractional ideal (389, a^2 - 44*a - 9) sage: P.residue_class_degree() @@ -3103,11 +3218,12 @@ def residue_field(self, names=None): has been fixed:: sage: K.<i> = NumberField(x^2 + 1) - sage: P1, P2 = [g[0] for g in K.factor(5)]; (P1,P2) + sage: P1, P2 = [g[0] for g in K.factor(5)]; P1, P2 (Fractional ideal (-i - 2), Fractional ideal (2*i + 1)) sage: a = 1/(1+2*i) - sage: F1, F2 = [g.residue_field() for g in [P1,P2]]; (F1,F2) - (Residue field of Fractional ideal (-i - 2), Residue field of Fractional ideal (2*i + 1)) + sage: F1, F2 = [g.residue_field() for g in [P1, P2]]; F1, F2 + (Residue field of Fractional ideal (-i - 2), + Residue field of Fractional ideal (2*i + 1)) sage: a.valuation(P1) 0 sage: F1(i/7) @@ -3119,7 +3235,8 @@ def residue_field(self, names=None): sage: F2(a) Traceback (most recent call last): ... - ZeroDivisionError: Cannot reduce field element -2/5*i + 1/5 modulo Fractional ideal (2*i + 1): it has negative valuation + ZeroDivisionError: Cannot reduce field element -2/5*i + 1/5 + modulo Fractional ideal (2*i + 1): it has negative valuation An example with a relative number field:: @@ -3144,22 +3261,25 @@ def residue_field(self, names=None): """ if not self.is_prime(): raise ValueError("The ideal must be prime") - return self.number_field().residue_field(self, names = names) + return self.number_field().residue_field(self, names=names) def residue_class_degree(self): r""" Return the residue class degree of this fractional ideal, - assuming it is prime. Otherwise, raise a ValueError. + assuming it is prime. Otherwise, raise a :class:`ValueError`. The residue class degree of a prime ideal `I` is the degree of the extension `O_K/I` of its prime subfield. EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^5 + 2); K Number Field in a with defining polynomial x^5 + 2 sage: f = K.factor(19); f - (Fractional ideal (a^2 + a - 3)) * (Fractional ideal (2*a^4 + a^2 - 2*a + 1)) * (Fractional ideal (a^2 + a - 1)) + (Fractional ideal (a^2 + a - 3)) + * (Fractional ideal (2*a^4 + a^2 - 2*a + 1)) + * (Fractional ideal (a^2 + a - 1)) sage: [i.residue_class_degree() for i, _ in f] [2, 2, 1] """ @@ -3168,7 +3288,7 @@ def residue_class_degree(self): def ray_class_number(self): r""" Return the order of the ray class group modulo this ideal. This is a - wrapper around Pari's :pari:`bnrclassno` function. + wrapper around PARI's :pari:`bnrclassno` function. EXAMPLES:: @@ -3189,7 +3309,7 @@ def ray_class_number(self): def is_NumberFieldFractionalIdeal(x): """ - Return True if x is a fractional ideal of a number field. + Return ``True`` if `x` is a fractional ideal of a number field. EXAMPLES:: @@ -3198,6 +3318,7 @@ def is_NumberFieldFractionalIdeal(x): False sage: is_NumberFieldFractionalIdeal(ideal(5)) False + sage: x = polygen(ZZ) sage: k.<a> = NumberField(x^2 + 2) sage: I = k.ideal([a + 1]); I Fractional ideal (a + 1) @@ -3224,6 +3345,7 @@ def __init__(self, K, M_OK_change, Q, I): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^3 + 4) sage: f = K.ideal(1 + a^2/2).residue_field().reduction_map(); f # indirect doctest Partially defined reduction map: @@ -3248,6 +3370,7 @@ def __call__(self, x): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^3 + 4) sage: f = K.ideal(1 + a^2/2).residue_field().reduction_map() sage: f(a) @@ -3263,6 +3386,7 @@ def __repr__(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^3 + 4) sage: f = K.ideal(1 + a^2/2).residue_field().reduction_map() sage: repr(f) @@ -3282,6 +3406,7 @@ def __init__(self, OK, M_OK_map, Q, I): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^3 + 4) sage: I = K.ideal(1 + a^2/2) sage: f = I.residue_field().lift_map() @@ -3300,6 +3425,7 @@ def __call__(self, x): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^3 + 4) sage: R = K.ideal(1 + a^2/2).residue_field() sage: f = R.lift_map() @@ -3328,6 +3454,7 @@ def __repr__(self): EXAMPLES:: + sage: x = polygen(ZZ) sage: K.<a> = NumberField(x^3 + 4) sage: R = K.ideal(1 + a^2/2).residue_field() sage: repr(R.lift_map()) @@ -3346,6 +3473,7 @@ def quotient_char_p(I, p): sage: from sage.rings.number_field.number_field_ideal import quotient_char_p + sage: x = polygen(ZZ) sage: K.<i> = NumberField(x^2 + 1); O = K.maximal_order(); I = K.fractional_ideal(15) sage: quotient_char_p(I, 5)[0] Vector space quotient V/W of dimension 2 over Finite Field of size 5 where diff --git a/src/sage/rings/number_field/number_field_ideal_rel.py b/src/sage/rings/number_field/number_field_ideal_rel.py index 192c8f15034..5ef403e7e23 100644 --- a/src/sage/rings/number_field/number_field_ideal_rel.py +++ b/src/sage/rings/number_field/number_field_ideal_rel.py @@ -11,6 +11,7 @@ EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 2]) sage: A = K.absolute_field('z') sage: I = A.factor(7)[0][0] @@ -49,6 +50,7 @@ class NumberFieldFractionalIdeal_rel(NumberFieldFractionalIdeal): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField([x^2 + 1, x^2 + 2]); K Number Field in a0 with defining polynomial x^2 + 1 over its base field sage: i = K.ideal(38); i @@ -81,6 +83,7 @@ def _richcmp_(self, other, op): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 23, x^2 - 7]) sage: I = K.ideal(2, (a + 2*b + 3)/2) sage: J = K.ideal(2, a - b) @@ -93,12 +96,13 @@ def _richcmp_(self, other, op): def _contains_(self, x): """ - Return True if x is an element of this ideal. + Return ``True`` if `x` is an element of this ideal. This function is called (indirectly) when the ``in`` operator is used. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 23, x^2 - 7]) sage: I = K.ideal(2, (a + 2*b + 3)/2) sage: [z in I for z in [a, b, 2, a + b]] # indirect doctest @@ -115,6 +119,7 @@ def pari_rhnf(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 23, x^2 - 7]) sage: I = K.ideal(2, (a + 2*b + 3)/2) sage: I.pari_rhnf() @@ -129,7 +134,7 @@ def pari_rhnf(self): self.__pari_rhnf = rnf.rnfidealabstorel(nfzk * L_hnf) return self.__pari_rhnf - def absolute_ideal(self, names = 'a'): + def absolute_ideal(self, names='a'): r""" If this is an ideal in the extension `L/K`, return the ideal with the same generators in the absolute field `L/\QQ`. @@ -154,10 +159,10 @@ def absolute_ideal(self, names = 'a'): Fractional ideal (13) Now a non-trivial ideal in `L` that is principal in the - subfield `K`. Since the optional 'names' argument is not - passed, the generators of the absolute ideal J are returned - in terms of the default field generator 'a'. This does not agree - with the generator 'm' of the absolute field F defined above:: + subfield `K`. Since the optional ``names`` argument is not + passed, the generators of the absolute ideal `J` are returned + in terms of the default field generator `a`. This does not agree + with the generator `m` of the absolute field `F` defined above:: sage: J = L.ideal(b); J Fractional ideal (b) @@ -170,7 +175,7 @@ def absolute_ideal(self, names = 'a'): sage: J.absolute_ideal().norm() 4 - Now pass 'm' as the name for the generator of the absolute field: + Now pass `m` as the name for the generator of the absolute field:: sage: J.absolute_ideal('m') Fractional ideal (m^2) @@ -202,12 +207,13 @@ def absolute_ideal(self, names = 'a'): def _from_absolute_ideal(self, id): r""" - Convert the absolute ideal id to a relative number field ideal. + Convert the absolute ideal ``id`` to a relative number field ideal. WARNING: This is an internal helper function. TESTS:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = QQ.extension([x^2 + 71, x^3 + 2*x + 1]) sage: (2*a + b).norm() 22584817 @@ -236,6 +242,7 @@ def free_module(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^3 - x + 1, x^2 + 23]) sage: I = K.ideal(a*b - 1) sage: I.free_module() @@ -256,6 +263,7 @@ def gens_reduced(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 1, x^2 - 2]) sage: I = K.ideal((a + 1)*b/2 + 1) sage: I.gens_reduced() @@ -291,10 +299,11 @@ def gens_reduced(self): def __invert__(self): """ - Return the multiplicative inverse of self. Call with ~self. + Return the multiplicative inverse of ``self``. Call with ``~self``. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 2]) sage: I = K.fractional_ideal(4) sage: I^(-1) @@ -308,11 +317,12 @@ def __invert__(self): def is_principal(self, proof=None): """ - Return True if this ideal is principal. If so, set - self.__reduced_generators, with length one. + Return ``True`` if this ideal is principal. If so, set + ``self.__reduced_generators``, with length one. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 - 23, x^2 + 1]) sage: I = K.ideal([7, (-1/2*b - 3/2)*a + 3/2*b + 9/2]) sage: I.is_principal() @@ -334,10 +344,11 @@ def is_principal(self, proof=None): def is_zero(self): r""" - Return True if this is the zero ideal. + Return ``True`` if this is the zero ideal. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 3, x^3 + 4]) sage: K.ideal(17).is_zero() False @@ -354,6 +365,7 @@ def absolute_norm(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b, c> = QQ.extension([x^2 - 23, x^2 - 5, x^2 - 7]) sage: I = L.ideal(a + b) sage: I.absolute_norm() @@ -371,7 +383,7 @@ def relative_norm(self): EXAMPLES:: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^2+6) + sage: K.<a> = NumberField(x^2 + 6) sage: L.<b> = K.extension(K['x'].gen()^4 + a) sage: N = L.ideal(b).relative_norm(); N Fractional ideal (-a) @@ -416,11 +428,13 @@ def norm(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 1, x^2 - 2]) sage: K.ideal(2).norm() Traceback (most recent call last): ... - NotImplementedError: For a fractional ideal in a relative number field you must use relative_norm or absolute_norm as appropriate + NotImplementedError: For a fractional ideal in a relative number field + you must use relative_norm or absolute_norm as appropriate """ raise NotImplementedError("For a fractional ideal in a relative number field you must use relative_norm or absolute_norm as appropriate") @@ -431,12 +445,12 @@ def ideal_below(self): EXAMPLES:: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^2+6) + sage: K.<a> = NumberField(x^2 + 6) sage: L.<b> = K.extension(K['x'].gen()^4 + a) sage: N = L.ideal(b) sage: M = N.ideal_below(); M == K.ideal([-a]) True - sage: Np = L.ideal( [ L(t) for t in M.gens() ]) + sage: Np = L.ideal([L(t) for t in M.gens()]) sage: Np.ideal_below() == M True sage: M.parent() @@ -496,7 +510,7 @@ def ideal_below(self): sage: K0.ideal([-a0 + 1]) == K0.ideal([-a0 + 5]) False - It works when the base_field is itself a relative number field:: + It works when the base field is itself a relative number field:: sage: PQ.<X> = QQ[] sage: F.<a, b> = NumberFieldTower([X^2 - 2, X^2 - 3]) @@ -532,11 +546,14 @@ def factor(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = QQ.extension([x^2 + 11, x^2 - 5]) sage: K.factor(5) - (Fractional ideal (5, (-1/4*b - 1/4)*a + 1/4*b - 3/4))^2 * (Fractional ideal (5, (-1/4*b - 1/4)*a + 1/4*b - 7/4))^2 + (Fractional ideal (5, (-1/4*b - 1/4)*a + 1/4*b - 3/4))^2 + * (Fractional ideal (5, (-1/4*b - 1/4)*a + 1/4*b - 7/4))^2 sage: K.ideal(5).factor() - (Fractional ideal (5, (-1/4*b - 1/4)*a + 1/4*b - 3/4))^2 * (Fractional ideal (5, (-1/4*b - 1/4)*a + 1/4*b - 7/4))^2 + (Fractional ideal (5, (-1/4*b - 1/4)*a + 1/4*b - 3/4))^2 + * (Fractional ideal (5, (-1/4*b - 1/4)*a + 1/4*b - 7/4))^2 sage: K.ideal(5).prime_factors() [Fractional ideal (5, (-1/4*b - 1/4)*a + 1/4*b - 3/4), Fractional ideal (5, (-1/4*b - 1/4)*a + 1/4*b - 7/4)] @@ -564,13 +581,14 @@ def factor(self): def integral_basis(self): r""" - Return a basis for self as a `\ZZ`-module. + Return a basis for ``self`` as a `\ZZ`-module. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^2 + 1, x^2 - 3]) sage: I = K.ideal(17*b - 3*a) - sage: x = I.integral_basis(); x # random + sage: x = I.integral_basis(); x # random [438, -b*a + 309, 219*a - 219*b, 156*a - 154*b] The exact results are somewhat unpredictable, hence the ``# random`` @@ -591,6 +609,7 @@ def integral_split(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberFieldTower([x^2 - 23, x^2 + 1]) sage: I = K.ideal([a + b/3]) sage: J, d = I.integral_split() @@ -608,6 +627,7 @@ def is_prime(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 - 17, x^3 - 2]) sage: K.ideal(a + b).is_prime() True @@ -624,31 +644,32 @@ def is_prime(self): def is_integral(self): """ - Return True if this ideal is integral. + Return ``True`` if this ideal is integral. EXAMPLES:: - sage: K.<a, b> = QQ.extension([x^2 + 11, x^2 - 5]) - sage: I = K.ideal(7).prime_factors()[0] - sage: I.is_integral() - True - sage: (I/2).is_integral() - False + sage: x = polygen(ZZ, 'x') + sage: K.<a, b> = QQ.extension([x^2 + 11, x^2 - 5]) + sage: I = K.ideal(7).prime_factors()[0] + sage: I.is_integral() + True + sage: (I/2).is_integral() + False """ return self.absolute_ideal().is_integral() def absolute_ramification_index(self): """ Return the absolute ramification index of this fractional ideal, - assuming it is prime. Otherwise, raise a ValueError. + assuming it is prime. Otherwise, raise a :class:`ValueError`. The absolute ramification index is the power of this prime appearing in the factorization of the rational prime that this prime lies over. - Use relative_ramification_index to obtain the power of this + Use :meth:`relative_ramification_index` to obtain the power of this prime occurring in the factorization of the prime ideal - of the base field that this prime lies over. + of the base field that this prime lies over. EXAMPLES:: @@ -666,18 +687,18 @@ def absolute_ramification_index(self): """ if self.is_prime(): return self.absolute_ideal().ramification_index() - raise ValueError("the fractional ideal (= %s) is not prime"%self) + raise ValueError("the fractional ideal (= %s) is not prime" % self) def relative_ramification_index(self): """ Return the relative ramification index of this fractional ideal, - assuming it is prime. Otherwise, raise a ValueError. + assuming it is prime. Otherwise, raise a :class:`ValueError`. The relative ramification index is the power of this prime appearing in the factorization of the prime ideal of the base field that this prime lies over. - Use absolute_ramification_index to obtain the power of this + Use :meth:`absolute_ramification_index` to obtain the power of this prime occurring in the factorization of the rational prime that this prime lies over. @@ -701,22 +722,24 @@ def relative_ramification_index(self): abs_index = self.absolute_ramification_index() base_ideal = self.ideal_below() return ZZ(abs_index/base_ideal.absolute_ramification_index()) - raise ValueError("the fractional ideal (= %s) is not prime"%self) + raise ValueError("the fractional ideal (= %s) is not prime" % self) def ramification_index(self): r""" - For ideals in relative number fields, ``ramification_index`` + For ideals in relative number fields, :meth:`ramification_index` is deliberately not implemented in order to avoid ambiguity. Either :meth:`~relative_ramification_index` or :meth:`~absolute_ramification_index` should be used instead. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 1, x^2 - 2]) sage: K.ideal(2).ramification_index() Traceback (most recent call last): ... - NotImplementedError: For an ideal in a relative number field you must use relative_ramification_index or absolute_ramification_index as appropriate + NotImplementedError: For an ideal in a relative number field you must use + relative_ramification_index or absolute_ramification_index as appropriate """ raise NotImplementedError("For an ideal in a relative number field you must use relative_ramification_index or absolute_ramification_index as appropriate") @@ -735,7 +758,7 @@ def residue_class_degree(self): """ if self.is_prime(): return self.absolute_ideal().residue_class_degree() - raise ValueError("the ideal (= %s) is not prime"%self) + raise ValueError("the ideal (= %s) is not prime" % self) def residues(self): """ @@ -745,6 +768,7 @@ def residues(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, w> = NumberFieldTower([x^2 - 3, x^2 + x + 1]) sage: I = K.ideal(6, -w*a - w + 4) sage: list(I.residues())[:5] @@ -762,7 +786,7 @@ def residues(self): def element_1_mod(self, other): r""" - Returns an element `r` in this ideal such that `1-r` is in other. + Returns an element `r` in this ideal such that `1-r` is in ``other``. An error is raised if either ideal is not integral of if they are not coprime. @@ -774,10 +798,11 @@ def element_1_mod(self, other): OUTPUT: an element `r` of the ideal self such that `1-r` is in the - ideal other. + ideal ``other``. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberFieldTower([x^2 - 23, x^2 + 1]) sage: I = Ideal(2, (a - 3*b + 2)/2) sage: J = K.ideal(a) @@ -790,14 +815,14 @@ def element_1_mod(self, other): # Catch invalid inputs by making sure that we can make an ideal out of other. K = self.number_field() if not self.is_integral(): - raise TypeError("%s is not an integral ideal"%self) + raise TypeError("%s is not an integral ideal" % self) other = K.ideal(other) if not other.is_integral(): - raise TypeError("%s is not an integral ideal"%other) + raise TypeError("%s is not an integral ideal" % other) if not self.is_coprime(other): - raise TypeError("%s and %s are not coprime ideals"%(self, other)) + raise TypeError("%s and %s are not coprime ideals" % (self, other)) to_K = K.absolute_field('a').structure()[0] return to_K(self.absolute_ideal().element_1_mod(other.absolute_ideal())) @@ -809,6 +834,7 @@ def smallest_integer(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberFieldTower([x^2 - 23, x^2 + 1]) sage: I = K.ideal([a + b]) sage: I.smallest_integer() @@ -820,7 +846,7 @@ def smallest_integer(self): def valuation(self, p): r""" - Return the valuation of this fractional ideal at ``p``. + Return the valuation of this fractional ideal at `\mathfrak{p}`. INPUT: @@ -830,11 +856,12 @@ def valuation(self, p): (integer) The valuation of this fractional ideal at the prime `\mathfrak{p}`. If `\mathfrak{p}` is not prime, raise a - ValueError. + :class:`ValueError`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 - 17, x^3 - 2]) sage: A = K.ideal(a + b) sage: A.is_prime() @@ -847,18 +874,18 @@ def valuation(self, p): ValueError: p (= Fractional ideal (5)) must be a prime """ if p == 0: - raise ValueError("p (= %s) must be nonzero"%p) + raise ValueError("p (= %s) must be nonzero" % p) if not isinstance(p, NumberFieldFractionalIdeal): p = self.number_field().ideal(p) if not p.is_prime(): - raise ValueError("p (= %s) must be a prime"%p) + raise ValueError("p (= %s) must be a prime" % p) if p.ring() != self.number_field(): - raise ValueError("p (= %s) must be an ideal in %s"%self.number_field()) + raise ValueError("p (= %s) must be an ideal in %s" % self.number_field()) return self.absolute_ideal().valuation(p.absolute_ideal()) def is_NumberFieldFractionalIdeal_rel(x): """ - Return True if x is a fractional ideal of a relative number field. + Return ``True`` if `x` is a fractional ideal of a relative number field. EXAMPLES:: @@ -868,13 +895,14 @@ def is_NumberFieldFractionalIdeal_rel(x): False sage: is_NumberFieldFractionalIdeal_rel(ideal(5)) False + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 2) sage: I = k.ideal([a + 1]); I Fractional ideal (a + 1) sage: is_NumberFieldFractionalIdeal_rel(I) False sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^2+6) + sage: K.<a> = NumberField(x^2 + 6) sage: L.<b> = K.extension(K['x'].gen()^4 + a) sage: I = L.ideal(b); I Fractional ideal (6, b) diff --git a/src/sage/rings/number_field/number_field_morphisms.pyx b/src/sage/rings/number_field/number_field_morphisms.pyx index 34a51a97c62..862b32ffc02 100644 --- a/src/sage/rings/number_field/number_field_morphisms.pyx +++ b/src/sage/rings/number_field/number_field_morphisms.pyx @@ -26,8 +26,6 @@ from sage.categories.morphism cimport Morphism from sage.categories.map cimport Map from sage.categories.pushout import pushout -from sage.rings.real_mpfr import RealField, mpfr_prec_min -from sage.rings.complex_mpfr import ComplexField from sage.rings.real_lazy import RLF, CLF, LazyField, LazyAlgebraic @@ -138,7 +136,8 @@ cdef class NumberFieldEmbedding(Morphism): EXAMPLES:: sage: from sage.rings.number_field.number_field_morphisms import NumberFieldEmbedding - sage: K.<a> = NumberField(x^2-2) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 2) sage: f = NumberFieldEmbedding(K, RLF, 1.4) sage: f # indirect doctest Generic morphism: @@ -150,7 +149,7 @@ cdef class NumberFieldEmbedding(Morphism): def gen_image(self): """ - Returns the image of the generator under this embedding. + Return the image of the generator under this embedding. EXAMPLES:: @@ -177,15 +176,16 @@ cdef class EmbeddedNumberFieldMorphism(NumberFieldEmbedding): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1,embedding=QQbar(I)) - sage: L.<i> = NumberField(x^2+1,embedding=-QQbar(I)) + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1, embedding=QQbar(I)) + sage: L.<i> = NumberField(x^2 + 1, embedding=-QQbar(I)) sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldMorphism - sage: EmbeddedNumberFieldMorphism(K,L,CDF) + sage: EmbeddedNumberFieldMorphism(K, L, CDF) Generic morphism: From: Number Field in i with defining polynomial x^2 + 1 with i = I To: Number Field in i with defining polynomial x^2 + 1 with i = -I Defn: i -> -i - sage: EmbeddedNumberFieldMorphism(K,L,QQbar) + sage: EmbeddedNumberFieldMorphism(K, L, QQbar) Generic morphism: From: Number Field in i with defining polynomial x^2 + 1 with i = I To: Number Field in i with defining polynomial x^2 + 1 with i = -I @@ -199,8 +199,9 @@ cdef class EmbeddedNumberFieldMorphism(NumberFieldEmbedding): EXAMPLES:: sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldMorphism - sage: K.<a> = NumberField(x^2-17, embedding=4.1) - sage: L.<b> = NumberField(x^4-17, embedding=2.0) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 17, embedding=4.1) + sage: L.<b> = NumberField(x^4 - 17, embedding=2.0) sage: f = EmbeddedNumberFieldMorphism(K, L) sage: f(a) b^2 @@ -225,7 +226,9 @@ cdef class EmbeddedNumberFieldMorphism(NumberFieldEmbedding): sage: F1.gen() + F2.gen() Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for +: 'Number Field in a with defining polynomial x^3 + 2 with a = -1.259921049894873?' and 'Number Field in a with defining polynomial x^3 + 2 with a = 0.6299605249474365? + 1.091123635971722?*I' + TypeError: unsupported operand parent(s) for +: + 'Number Field in a with defining polynomial x^3 + 2 with a = -1.259921049894873?' and + 'Number Field in a with defining polynomial x^3 + 2 with a = 0.6299605249474365? + 1.091123635971722?*I' The following was fixed to raise a ``TypeError`` in :trac:`15331`:: @@ -272,13 +275,14 @@ cdef class EmbeddedNumberFieldMorphism(NumberFieldEmbedding): EXAMPLES:: sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldMorphism - sage: K.<a> = NumberField(x^2-700, embedding=25) - sage: L.<b> = NumberField(x^6-700, embedding=3) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 700, embedding=25) + sage: L.<b> = NumberField(x^6 - 700, embedding=3) sage: f = EmbeddedNumberFieldMorphism(K, L) - sage: f(2*a-1) + sage: f(2*a - 1) 2*b^3 - 1 sage: g = f.section() - sage: g(2*b^3-1) + sage: g(2*b^3 - 1) 2*a - 1 """ return EmbeddedNumberFieldConversion(self.codomain(), self.domain(), self.ambient_field) @@ -302,8 +306,9 @@ cdef class EmbeddedNumberFieldConversion(Map): EXAMPLES:: sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldConversion - sage: K.<a> = NumberField(x^2-17, embedding=4.1) - sage: L.<b> = NumberField(x^4-17, embedding=2.0) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 17, embedding=4.1) + sage: L.<b> = NumberField(x^4 - 17, embedding=2.0) sage: f = EmbeddedNumberFieldConversion(K, L) sage: f(a) b^2 @@ -340,12 +345,12 @@ cdef class EmbeddedNumberFieldConversion(Map): cpdef matching_root(poly, target, ambient_field=None, margin=1, max_prec=None): """ - Given a polynomial and a target, this function chooses the root that - target best approximates as compared in ambient_field. + Given a polynomial and a ``target``, choose the root that + ``target`` best approximates as compared in ``ambient_field``. - If the parent of target is exact, the equality is required, otherwise + If the parent of ``target`` is exact, the equality is required, otherwise find closest root (with respect to the ``abs`` function) in the - ambient field to the target, and return the root of poly (if any) that + ambient field to the ``target``, and return the root of ``poly`` (if any) that approximates it best. EXAMPLES:: @@ -403,11 +408,11 @@ cpdef matching_root(poly, target, ambient_field=None, margin=1, max_prec=None): cpdef closest(target, values, margin=1): """ - This is a utility function that returns the item in values closest to - target (with respect to the ``abs`` function). If margin is greater - than 1, and x and y are the first and second closest elements to target, - then only return x if x is margin times closer to target than y, i.e. - margin * abs(target-x) < abs(target-y). + This is a utility function that returns the item in ``values`` closest to + target (with respect to the ``abs`` function). If ``margin`` is greater + than 1, and `x` and `y` are the first and second closest elements to ``target``, + then only return `x` if `x` is ``margin`` times closer to ``target`` than `y`, i.e. + ``margin * abs(target-x) < abs(target-y)``. TESTS:: @@ -475,9 +480,9 @@ def root_from_approx(f, a): sage: root_from_approx(x^2 + 1, CC(0)) -1*I - sage: root_from_approx(x^2 - 2, sqrt(2)) + sage: root_from_approx(x^2 - 2, sqrt(2)) # needs sage.symbolic sqrt(2) - sage: root_from_approx(x^2 - 2, sqrt(3)) + sage: root_from_approx(x^2 - 2, sqrt(3)) # needs sage.symbolic Traceback (most recent call last): ... ValueError: sqrt(3) is not a root of x^2 - 2 @@ -512,7 +517,8 @@ def create_embedding_from_approx(K, gen_image): EXAMPLES:: sage: from sage.rings.number_field.number_field_morphisms import create_embedding_from_approx - sage: K.<a> = NumberField(x^3-x+1/10) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - x + 1/10) sage: create_embedding_from_approx(K, 1) Generic morphism: From: Number Field in a with defining polynomial x^3 - x + 1/10 @@ -560,7 +566,7 @@ cdef class CyclotomicFieldEmbedding(NumberFieldEmbedding): """ Specialized class for converting cyclotomic field elements into a cyclotomic field of higher order. All the real work is done by - _lift_cyclotomic_element. + :meth:`_lift_cyclotomic_element`. """ cdef ratio diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index 8ecb87fce28..1e8a6a17fe1 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -13,6 +13,7 @@ This example follows one in the Magma reference manual:: + sage: x = polygen(ZZ, 'x') sage: K.<y> = NumberField(x^4 - 420*x^2 + 40000) sage: z = y^5/11; z 420/11*y^3 - 40000/11*y @@ -93,7 +94,7 @@ from .number_field import (NumberField, NumberField_generic, put_natural_embedding_first, proof_flag, is_NumberFieldHomsetCodomain) -from sage.rings.number_field.number_field_base import is_NumberField +from sage.rings.number_field.number_field_base import NumberField as NumberField_base from sage.rings.number_field.order import (RelativeOrder, is_NumberFieldOrder, relative_order_from_ring_generators) from sage.rings.number_field.morphism import RelativeNumberFieldHomomorphism_from_abs @@ -116,6 +117,7 @@ def is_RelativeNumberField(x): EXAMPLES:: sage: from sage.rings.number_field.number_field_rel import is_RelativeNumberField + sage: x = polygen(ZZ, 'x') sage: is_RelativeNumberField(NumberField(x^2+1,'a')) False sage: k.<a> = NumberField(x^3 - 2) @@ -155,14 +157,15 @@ class NumberField_relative(NumberField_generic): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: t = polygen(K) - sage: L.<b> = K.extension(t^2+t+a); L + sage: L.<b> = K.extension(t^2 + t + a); L Number Field in b with defining polynomial x^2 + x + a over its base field TESTS:: - sage: Z = var('Z') + sage: Z = polygen(ZZ, 'Z') sage: K.<w> = NumberField(Z^3 + Z + 1) sage: L.<z> = K.extension(Z^3 + 2) sage: K = loads(dumps(L)) @@ -277,8 +280,8 @@ def __init__(self, base, polynomial, name, raise NotImplementedError("Embeddings not implemented for relative number fields") if names is not None: name = names - if not is_NumberField(base): - raise TypeError("base (=%s) must be a number field"%base) + if not isinstance(base, NumberField_base): + raise TypeError("base (=%s) must be a number field" % base) if not isinstance(polynomial, polynomial_element.Polynomial): try: polynomial = polynomial.polynomial(base) @@ -310,7 +313,7 @@ def __init__(self, base, polynomial, name, self._element_class = number_field_element.NumberFieldElement_relative if check and not self.pari_relative_polynomial().polisirreducible(): - raise ValueError("defining polynomial (%s) must be irreducible"%polynomial) + raise ValueError("defining polynomial (%s) must be irreducible" % polynomial) names = (name,) + base.variable_names() self._assign_names(tuple(names), normalize=False) @@ -320,25 +323,26 @@ def __init__(self, base, polynomial, name, embedding=embedding, structure=structure) self._zero_element = self(0) - self._one_element = self(1) + self._one_element = self(1) def change_names(self, names): r""" - Return relative number field isomorphic to self but with the + Return relative number field isomorphic to ``self`` but with the given generator names. INPUT: - ``names`` -- number of names should be at most the number of - generators of self, i.e., the number of steps in the tower + generators of ``self``, i.e., the number of steps in the tower of relative fields. Also, ``K.structure()`` returns ``from_K`` and ``to_K``, where - from_K is an isomorphism from `K` to self and ``to_K`` is an + ``from_K`` is an isomorphism from `K` to ``self`` and ``to_K`` is an isomorphism from self to `K`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^4 + 3, x^2 + 2]); K Number Field in a with defining polynomial x^4 + 3 over its base field sage: L.<c,d> = K.change_names() @@ -366,14 +370,19 @@ def change_names(self, names): sage: PF.<Y> = F[] sage: K.<c> = F.extension(Y^2 - (1 + a)*(a + b)*a*b) sage: L.<m, n, r> = K.change_names(); L - Number Field in m with defining polynomial x^2 + (-2*r - 3)*n - 2*r - 6 over its base field + Number Field in m with defining polynomial + x^2 + (-2*r - 3)*n - 2*r - 6 over its base field sage: L.structure() (Isomorphism given by variable name change map: - From: Number Field in m with defining polynomial x^2 + (-2*r - 3)*n - 2*r - 6 over its base field - To: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field, + From: Number Field in m with defining polynomial + x^2 + (-2*r - 3)*n - 2*r - 6 over its base field + To: Number Field in c with defining polynomial + Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field, Isomorphism given by variable name change map: - From: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - To: Number Field in m with defining polynomial x^2 + (-2*r - 3)*n - 2*r - 6 over its base field) + From: Number Field in c with defining polynomial + Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + To: Number Field in m with defining polynomial + x^2 + (-2*r - 3)*n - 2*r - 6 over its base field) """ if len(names) == 0: names = self.variable_names() @@ -387,9 +396,9 @@ def change_names(self, names): def subfields(self, degree=0, name=None): """ - Return all subfields of this relative number field self of the given degree, + Return all subfields of this relative number field ``self`` of the given degree, or of all possible degrees if degree is 0. The subfields are returned as - absolute fields together with an embedding into self. For the case of the + absolute fields together with an embedding into ``self``. For the case of the field itself, the reverse isomorphism is also provided. EXAMPLES:: @@ -400,27 +409,42 @@ def subfields(self, degree=0, name=None): sage: K.<c> = F.extension(Y^2 - (1 + a)*(a + b)*a*b) sage: K.subfields(2) [ - (Number Field in c0 with defining polynomial x^2 - 24*x + 96, Ring morphism: - From: Number Field in c0 with defining polynomial x^2 - 24*x + 96 - To: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - Defn: c0 |--> -4*b + 12, None), - (Number Field in c1 with defining polynomial x^2 - 24*x + 120, Ring morphism: - From: Number Field in c1 with defining polynomial x^2 - 24*x + 120 - To: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - Defn: c1 |--> 2*b*a + 12, None), - (Number Field in c2 with defining polynomial x^2 - 24*x + 72, Ring morphism: - From: Number Field in c2 with defining polynomial x^2 - 24*x + 72 - To: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - Defn: c2 |--> -6*a + 12, None) + (Number Field in c0 with defining polynomial x^2 - 24*x + 96, + Ring morphism: + From: Number Field in c0 with defining polynomial x^2 - 24*x + 96 + To: Number Field in c with defining polynomial + Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Defn: c0 |--> -4*b + 12, + None), + (Number Field in c1 with defining polynomial x^2 - 24*x + 120, + Ring morphism: + From: Number Field in c1 with defining polynomial x^2 - 24*x + 120 + To: Number Field in c with defining polynomial + Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Defn: c1 |--> 2*b*a + 12, + None), + (Number Field in c2 with defining polynomial x^2 - 24*x + 72, + Ring morphism: + From: Number Field in c2 with defining polynomial x^2 - 24*x + 72 + To: Number Field in c with defining polynomial + Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Defn: c2 |--> -6*a + 12, + None) ] sage: K.subfields(8, 'w') [ - (Number Field in w0 with defining polynomial x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9, Ring morphism: - From: Number Field in w0 with defining polynomial x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9 - To: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - Defn: w0 |--> (-1/2*b*a + 1/2*b + 1/2)*c, Relative number field morphism: - From: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - To: Number Field in w0 with defining polynomial x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9 + (Number Field in w0 with defining polynomial x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9, + Ring morphism: + From: Number Field in w0 with defining polynomial + x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9 + To: Number Field in c with defining polynomial + Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Defn: w0 |--> (-1/2*b*a + 1/2*b + 1/2)*c, + Relative number field morphism: + From: Number Field in c with defining polynomial + Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + To: Number Field in w0 with defining polynomial + x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9 Defn: c |--> -1/3*w0^7 + 4*w0^5 - 12*w0^3 + 11*w0 a |--> 1/3*w0^6 - 10/3*w0^4 + 5*w0^2 b |--> -2/3*w0^6 + 7*w0^4 - 14*w0^2 + 6) @@ -439,15 +463,16 @@ def subfields(self, degree=0, name=None): if to_K is not None: to_K = RelativeNumberFieldHomomorphism_from_abs(self.Hom(K), to_K*to_abs) ans.append((K, from_K, to_K)) - ans = Sequence(ans, immutable=True, cr=ans!=[]) + ans = Sequence(ans, immutable=True, cr=bool(ans)) return ans def is_absolute(self): r""" - Returns False, since this is not an absolute field. + Return ``False``, since this is not an absolute field. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^4 + 3, x^2 + 2]); K Number Field in a with defining polynomial x^4 + 3 over its base field sage: K.is_absolute() @@ -463,6 +488,7 @@ def gens(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^4 + 3, x^2 + 2]); K Number Field in a with defining polynomial x^4 + 3 over its base field sage: K.gens() @@ -490,6 +516,7 @@ def _first_ngens(self, n): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^4 + 3, x^2 + 2]); K Number Field in a with defining polynomial x^4 + 3 over its base field sage: K._first_ngens(0) @@ -514,6 +541,7 @@ def ngens(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^4 + 3, x^2 + 2]); K Number Field in a with defining polynomial x^4 + 3 over its base field sage: K.gens() @@ -529,6 +557,7 @@ def gen(self, n=0): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^4 + 3, x^2 + 2]); K Number Field in a with defining polynomial x^4 + 3 over its base field sage: K.gens() @@ -547,60 +576,67 @@ def galois_closure(self, names=None): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^4 + 3, x^2 + 2]); K Number Field in a with defining polynomial x^4 + 3 over its base field sage: K.galois_closure('c') - Number Field in c with defining polynomial x^16 + 16*x^14 + 28*x^12 + 784*x^10 + 19846*x^8 - 595280*x^6 + 2744476*x^4 + 3212848*x^2 + 29953729 + Number Field in c with defining polynomial x^16 + 16*x^14 + 28*x^12 + + 784*x^10 + 19846*x^8 - 595280*x^6 + 2744476*x^4 + 3212848*x^2 + 29953729 """ return self.absolute_field('a').galois_closure(names=names) def composite_fields(self, other, names=None, both_maps=False, preserve_embedding=True): """ - List of all possible composite number fields formed from self and - other, together with (optionally) embeddings into the compositum; - see the documentation for both_maps below. + List of all possible composite number fields formed from ``self`` and + ``other``, together with (optionally) embeddings into the compositum; + see the documentation for ``both_maps`` below. Since relative fields do not have ambient embeddings, - preserve_embedding has no effect. In every case all possible + ``preserve_embedding`` has no effect. In every case all possible composite number fields are returned. INPUT: - - ``other`` - a number field + - ``other`` -- a number field - - ``names`` - generator name for composite fields + - ``names`` -- generator name for composite fields - - ``both_maps`` - (default: False) if True, return quadruples - (F, self_into_F, other_into_F, k) such that self_into_F maps self into - F, other_into_F maps other into F. For relative number fields k is - always None. - - ``preserve_embedding`` - (default: True) has no effect, but is kept - for compatibility with the absolute version of this function. In every + - ``both_maps`` -- (default: ``False``) if ``True``, return quadruples + (`F`, ``self_into_F, ``other_into_F``, `k`) such that ``self_into_F`` maps ``self`` into + `F`, ``other_into_F`` maps ``other`` into `F`. For relative number fields, `k` is + always ``None``. + + - ``preserve_embedding`` -- (default: ``True``) has no effect, but is kept + for compatibility with the absolute version of this method. In every case the list of all possible compositums is returned. OUTPUT: - - ``list`` - list of the composite fields, possibly with maps. - + list of the composite fields, possibly with maps. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 5, x^2 - 2]) sage: L.<c, d> = NumberField([x^2 + 5, x^2 - 3]) sage: K.composite_fields(L, 'e') - [Number Field in e with defining polynomial x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600] + [Number Field in e with defining polynomial + x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600] sage: K.composite_fields(L, 'e', both_maps=True) - [[Number Field in e with defining polynomial x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600, + [[Number Field in e with defining polynomial + x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600, Relative number field morphism: - From: Number Field in a with defining polynomial x^2 + 5 over its base field - To: Number Field in e with defining polynomial x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600 - Defn: a |--> -9/66560*e^7 + 11/4160*e^5 - 241/4160*e^3 - 101/104*e - b |--> -21/166400*e^7 + 73/20800*e^5 - 779/10400*e^3 + 7/260*e, + From: Number Field in a with defining polynomial x^2 + 5 over its base field + To: Number Field in e with defining polynomial + x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600 + Defn: a |--> -9/66560*e^7 + 11/4160*e^5 - 241/4160*e^3 - 101/104*e + b |--> -21/166400*e^7 + 73/20800*e^5 - 779/10400*e^3 + 7/260*e, Relative number field morphism: - From: Number Field in c with defining polynomial x^2 + 5 over its base field - To: Number Field in e with defining polynomial x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600 - Defn: c |--> -9/66560*e^7 + 11/4160*e^5 - 241/4160*e^3 - 101/104*e - d |--> -3/25600*e^7 + 7/1600*e^5 - 147/1600*e^3 + 1/40*e, + From: Number Field in c with defining polynomial x^2 + 5 over its base field + To: Number Field in e with defining polynomial + x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600 + Defn: c |--> -9/66560*e^7 + 11/4160*e^5 - 241/4160*e^3 - 101/104*e + d |--> -3/25600*e^7 + 7/1600*e^5 - 147/1600*e^3 + 1/40*e, None]] """ if not isinstance(other, NumberField_generic): @@ -644,6 +680,7 @@ def absolute_degree(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberFieldTower([x^2 - 17, x^3 - 2]) sage: K.absolute_degree() 6 @@ -656,6 +693,7 @@ def relative_degree(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberFieldTower([x^2 - 17, x^3 - 2]) sage: K.relative_degree() 2 @@ -670,11 +708,13 @@ def degree(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberFieldTower([x^2 - 17, x^3 - 2]) sage: K.degree() Traceback (most recent call last): ... - NotImplementedError: For a relative number field you must use relative_degree or absolute_degree as appropriate + NotImplementedError: For a relative number field + you must use relative_degree or absolute_degree as appropriate """ raise NotImplementedError("For a relative number field you must use relative_degree or absolute_degree as appropriate") @@ -686,6 +726,7 @@ def _maximal_order(self, v=(), assume_maximal='non-maximal-non-unique'): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberFieldTower([x^2 - 17, x^3 - 2]) sage: K.maximal_order() is K.maximal_order() # indirect doctest True @@ -704,6 +745,7 @@ def _repr_(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a, b> = NumberField([x^5 + 2, x^7 + 3]) sage: repr(k) # indirect doctest 'Number Field in a with defining polynomial x^5 + 2 over its base field' @@ -711,7 +753,7 @@ def _repr_(self): Number Field in b with defining polynomial x^7 + 3 """ - return "Number Field in %s with defining polynomial %s over its base field"%(self.variable_name(), self.relative_polynomial()) + return "Number Field in %s with defining polynomial %s over its base field" % (self.variable_name(), self.relative_polynomial()) def _Hom_(self, codomain, category=None): """ @@ -723,6 +765,7 @@ def _Hom_(self, codomain, category=None): This function is implicitly called by the ``Hom`` method or function:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^3 - 2, x^2+1]) sage: K.Hom(K) # indirect doctest Automorphism group of Number Field in a with defining polynomial x^3 - 2 over its base field @@ -748,13 +791,14 @@ def _latex_(self): EXAMPLES:: sage: x = polygen(QQ) + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: t = polygen(K) sage: K.extension(t^2+t+a, 'b')._latex_() '( \\Bold{Q}[a]/(a^{3} - 2) )[b]/(b^{2} + b + a)' """ latex_name = self.latex_variable_names()[0] - return "( %s )[%s]/(%s)"%(latex(self.base_field()), latex_name, + return "( %s )[%s]/(%s)" % (latex(self.base_field()), latex_name, self.relative_polynomial()._latex_(latex_name)) def _coerce_from_other_number_field(self, x): @@ -770,6 +814,7 @@ def _coerce_from_other_number_field(self, x): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: L.<b> = NumberField(x^2 + 1) sage: K._coerce_from_other_number_field(L(2/3)) @@ -839,6 +884,7 @@ def _convert_non_number_field_element(self, x): Examples from :trac:`4727`:: + sage: # needs sage.symbolic sage: K.<j,b> = QQ[sqrt(-1), sqrt(2)] sage: j I @@ -867,7 +913,8 @@ def _convert_non_number_field_element(self, x): sage: L(L) Traceback (most recent call last): ... - TypeError: unable to convert Number Field in a0 with defining polynomial x^2 + 1 over its base field to Number Field in a0 with defining polynomial x^2 + 1 over its base field + TypeError: unable to convert Number Field in a0 with defining polynomial x^2 + 1 over its base field + to Number Field in a0 with defining polynomial x^2 + 1 over its base field sage: L in L False @@ -951,6 +998,7 @@ def _coerce_map_from_(self, R): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField([x^5 + 2, x^7 + 3]) sage: b = k(k.base_field().gen()) sage: b = k.coerce(k.base_field().gen()) # indirect doctest @@ -1032,6 +1080,7 @@ def __base_inclusion(self, element): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField([x^2 + 3, x^2 + 1]) sage: m = k.base_field(); m Number Field in a1 with defining polynomial x^2 + 1 @@ -1079,6 +1128,7 @@ def _fractional_ideal_class_(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField([x^5 + 2, x^7 + 3]) sage: k._fractional_ideal_class_ () <class 'sage.rings.number_field.number_field_ideal_rel.NumberFieldFractionalIdeal_rel'> @@ -1100,6 +1150,7 @@ def _pari_base_bnf(self, proof=False, units=True): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField([x^3 + 2, x^2 + 2]) sage: k._pari_base_bnf() [[;], matrix(0,3), [;], ...] @@ -1127,27 +1178,31 @@ def _pari_base_nf(self): def is_galois(self): r""" - For a relative number field, ``is_galois()`` is deliberately not + For a relative number field, :meth:`is_galois` is deliberately not implemented, since it is not clear whether this would mean "Galois over - `\QQ`" or "Galois over the given base field". Use either ``is_galois_absolute()`` or ``is_galois_relative()`` respectively. + `\QQ`" or "Galois over the given base field". + Use either :meth:`is_galois_absolute` or :meth:`is_galois_relative`, respectively. EXAMPLES:: - sage: k.<a> =NumberField([x^3 - 2, x^2 + x + 1]) + sage: x = polygen(ZZ, 'x') + sage: k.<a> = NumberField([x^3 - 2, x^2 + x + 1]) sage: k.is_galois() Traceback (most recent call last): ... - NotImplementedError: For a relative number field L you must use either L.is_galois_relative() or L.is_galois_absolute() as appropriate + NotImplementedError: For a relative number field L you must use + either L.is_galois_relative() or L.is_galois_absolute() as appropriate """ raise NotImplementedError("For a relative number field L you must use either L.is_galois_relative() or L.is_galois_absolute() as appropriate") def is_galois_relative(self): r""" - Return True if for this relative extension `L/K`, `L` is a + Return ``True`` if for this relative extension `L/K`, `L` is a Galois extension of `K`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: y = polygen(K) sage: L.<b> = K.extension(y^2 - a) @@ -1172,10 +1227,11 @@ def is_galois_relative(self): def is_galois_absolute(self): r""" - Return True if for this relative extension `L/K`, `L` is a Galois extension of `\QQ`. + Return ``True`` if for this relative extension `L/K`, `L` is a Galois extension of `\QQ`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: y = polygen(K); L.<b> = K.extension(y^2 - a) sage: L.is_galois_absolute() @@ -1187,13 +1243,14 @@ def is_galois_absolute(self): def is_isomorphic_relative(self, other, base_isom=None): r""" - For this relative extension `L/K` and another relative extension `M/K`, return True + For this relative extension `L/K` and another relative extension `M/K`, return ``True`` if there is a `K`-linear isomorphism from `L` to `M`. More generally, ``other`` can be a relative extension `M/K^\prime` with ``base_isom`` an isomorphism from `K` to `K^\prime`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<z9> = NumberField(x^6 + x^3 + 1) sage: R.<z> = PolynomialRing(K) sage: m1 = 3*z9^4 - 4*z9^3 - 4*z9^2 + 3*z9 - 8 @@ -1210,7 +1267,7 @@ def is_isomorphic_relative(self, other, base_isom=None): False If we have two extensions over different, but isomorphic, bases, we can compare them by - letting ``base_isom`` be an isomorphism from self's base field to other's base field:: + letting ``base_isom`` be an isomorphism from ``self``'s base field to ``other``'s base field:: sage: Kcyc.<zeta9> = CyclotomicField(9) sage: Rcyc.<zcyc> = PolynomialRing(Kcyc) @@ -1227,12 +1284,14 @@ def is_isomorphic_relative(self, other, base_isom=None): sage: L2.is_isomorphic_relative(L1cyc, base_isom=phi2) True - Omitting ``base_isom`` raises a ValueError when the base fields are not identical:: + Omitting ``base_isom`` raises a :class:`ValueError` when the base fields are not identical:: sage: L1.is_isomorphic_relative(L1cyc) Traceback (most recent call last): ... - ValueError: other does not have the same base field as self, so an isomorphism from self's base_field to other's base_field must be provided using the base_isom parameter. + ValueError: other does not have the same base field as self, + so an isomorphism from self's base_field to other's base_field + must be provided using the base_isom parameter. The parameter ``base_isom`` can also be used to check if the relative extensions are Galois conjugate:: @@ -1265,11 +1324,12 @@ def is_isomorphic_relative(self, other, base_isom=None): def is_CM_extension(self): """ - Return True is this is a CM extension, i.e. a totally imaginary + Return ``True`` is this is a CM extension, i.e. a totally imaginary quadratic extension of a totally real field. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: F.<a> = NumberField(x^2 - 5) sage: K.<z> = F.extension(x^2 + 7) sage: K.is_CM_extension() @@ -1283,7 +1343,7 @@ def is_CM_extension(self): sage: K.is_CM_extension() False - A CM field K such that K/F is not a CM extension + A CM field `K` such that `K/F` is not a CM extension :: @@ -1327,6 +1387,7 @@ def free_module(self, base=None, basis=None, map=True): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b,c> = NumberField([x^2 + 2, x^3 + 2, x^3 + 3]); K Number Field in a with defining polynomial x^2 + 2 over its base field sage: V, from_V, to_V = K.free_module() @@ -1362,11 +1423,12 @@ def free_module(self, base=None, basis=None, map=True): def relative_vector_space(self, base=None, *args, **kwds): """ - Return vector space over the base field of self and isomorphisms - from the vector space to self and in the other direction. + Return vector space over the base field of ``self`` and isomorphisms + from the vector space to ``self`` and in the other direction. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b,c> = NumberField([x^2 + 2, x^3 + 2, x^3 + 3]); K Number Field in a with defining polynomial x^2 + 2 over its base field sage: V, from_V, to_V = K.relative_vector_space() @@ -1398,6 +1460,7 @@ def absolute_vector_space(self, base=None, *args, **kwds): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^3 + 3, x^3 + 2]); K Number Field in a with defining polynomial x^3 + 3 over its base field sage: V,from_V,to_V = K.absolute_vector_space(); V @@ -1425,17 +1488,19 @@ def absolute_vector_space(self, base=None, *args, **kwds): def vector_space(self, *args, **kwds): r""" - For a relative number field, ``vector_space()`` is + For a relative number field, :meth:`vector_space` is deliberately not implemented, so that a user cannot confuse :meth:`~relative_vector_space` with :meth:`~absolute_vector_space`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberFieldTower([x^2 - 17, x^3 - 2]) sage: K.vector_space() Traceback (most recent call last): ... - NotImplementedError: For a relative number field L you must use either L.relative_vector_space() or L.absolute_vector_space() as appropriate + NotImplementedError: For a relative number field L you must use either + L.relative_vector_space() or L.absolute_vector_space() as appropriate """ raise NotImplementedError("For a relative number field L you must use either L.relative_vector_space() or L.absolute_vector_space() as appropriate") @@ -1447,6 +1512,7 @@ def absolute_base_field(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b,c> = NumberField([x^2 + 2, x^3 + 3, x^3 + 2]) sage: K Number Field in a with defining polynomial x^2 + 2 over its base field @@ -1473,6 +1539,7 @@ def _pari_rnfeq(self): TESTS:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 2) sage: x = polygen(K) sage: L.<b> = K.extension(x^5 + 2*a) @@ -1484,6 +1551,7 @@ def _pari_rnfeq(self): Initialization is lazy enough to allow arithmetic in massive fields:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^10 + 2000*x + 100001) sage: x = polygen(K) sage: L.<b> = K.extension(x^10 + 2*a) @@ -1508,6 +1576,7 @@ def _pari_nfzk(self): TESTS:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 2) sage: L.<b> = K.extension(x^2 - 3) sage: L._pari_nfzk() @@ -1601,10 +1670,11 @@ def _gen_relative(self): EXAMPLES:: - sage: k.<a> = NumberField(x^2+1); k + sage: x = polygen(ZZ, 'x') + sage: k.<a> = NumberField(x^2 + 1); k Number Field in a with defining polynomial x^2 + 1 sage: y = polygen(k) - sage: m.<b> = k.extension(y^2+3); m + sage: m.<b> = k.extension(y^2 + 3); m Number Field in b with defining polynomial x^2 + 3 over its base field sage: c = m.gen(); c # indirect doctest b @@ -1630,6 +1700,7 @@ def pari_rnf(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField([x^4 + 3, x^2 + 2]) sage: k.pari_rnf() [x^4 + 3, [364, -10*x^7 - 87*x^5 - 370*x^3 - 41*x], [108, 3], ...] @@ -1643,6 +1714,7 @@ def pari_absolute_base_polynomial(self): EXAMPLES:: sage: x = polygen(ZZ) + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 2, x^2 + 3]); K Number Field in a with defining polynomial x^2 + 2 over its base field sage: K.pari_absolute_base_polynomial() @@ -1669,13 +1741,14 @@ def pari_relative_polynomial(self): Return the PARI relative polynomial associated to this number field. - This is always a polynomial in x and y, suitable for PARI's - rnfinit function. Notice that if this is a relative extension + This is always a polynomial in `x` and `y`, suitable for PARI's + :pari:`rnfinit` function. Notice that if this is a relative extension of a relative extension, the base field is the absolute base field. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<i> = NumberField(x^2 + 1) sage: m.<z> = k.extension(k['w']([i,0,1])) sage: m @@ -1690,24 +1763,26 @@ def pari_relative_polynomial(self): return self._pari_relative_structure()[0] def number_of_roots_of_unity(self): - """ - Return number of roots of unity in this relative field. + r""" + Return the number of roots of unity in this relative field. EXAMPLES:: - sage: K.<a, b> = NumberField( [x^2 + x + 1, x^4 + 1] ) + sage: x = polygen(ZZ, 'x') + sage: K.<a, b> = NumberField([x^2 + x + 1, x^4 + 1]) sage: K.number_of_roots_of_unity() 24 """ return self.absolute_field('a').number_of_roots_of_unity() def roots_of_unity(self): - """ + r""" Return all the roots of unity in this relative field, primitive or not. EXAMPLES:: - sage: K.<a, b> = NumberField( [x^2 + x + 1, x^4 + 1] ) + sage: x = polygen(ZZ, 'x') + sage: K.<a, b> = NumberField([x^2 + x + 1, x^4 + 1]) sage: rts = K.roots_of_unity() sage: len(rts) 24 @@ -1757,6 +1832,7 @@ def absolute_field(self, names): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^4 + 3, x^2 + 2]); K Number Field in a with defining polynomial x^4 + 3 over its base field sage: L.<xyz> = K.absolute_field(); L @@ -1767,14 +1843,16 @@ def absolute_field(self, names): sage: from_L, to_L = L.structure() sage: from_L Isomorphism map: - From: Number Field in c with defining polynomial x^8 + 8*x^6 + 30*x^4 - 40*x^2 + 49 + From: Number Field in c with defining polynomial + x^8 + 8*x^6 + 30*x^4 - 40*x^2 + 49 To: Number Field in a with defining polynomial x^4 + 3 over its base field sage: from_L(c) a - b sage: to_L Isomorphism map: From: Number Field in a with defining polynomial x^4 + 3 over its base field - To: Number Field in c with defining polynomial x^8 + 8*x^6 + 30*x^4 - 40*x^2 + 49 + To: Number Field in c with defining polynomial + x^8 + 8*x^6 + 30*x^4 - 40*x^2 + 49 sage: to_L(a) -5/182*c^7 - 87/364*c^5 - 185/182*c^3 + 323/364*c sage: to_L(b) @@ -1795,6 +1873,7 @@ def absolute_polynomial_ntl(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: NumberField(x^2 + (2/3)*x - 9/17,'a').absolute_polynomial_ntl() ([-27 34 51], 51) """ @@ -1826,6 +1905,7 @@ def absolute_polynomial(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a, b> = NumberField([x^2 + 1, x^3 + x + 1]); k Number Field in a with defining polynomial x^2 + 1 over its base field sage: k.absolute_polynomial() @@ -1834,6 +1914,7 @@ def absolute_polynomial(self): An example comparing the various defining polynomials to their PARI counterparts:: + sage: x = polygen(ZZ, 'x') sage: k.<a, c> = NumberField([x^2 + 1/3, x^2 + 1/4]) sage: k.absolute_polynomial() x^4 - x^2 + 1 @@ -1856,11 +1937,12 @@ def relative_polynomial(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberFieldTower([x^2 + x + 1, x^3 + x + 1]) sage: K.relative_polynomial() x^2 + x + 1 - Use absolute polynomial for a polynomial that defines the absolute + Use :meth:`absolute_polynomial` for a polynomial that defines the absolute extension.:: sage: K.absolute_polynomial() @@ -1872,7 +1954,7 @@ def defining_polynomial(self): """ Return the defining polynomial of this relative number field. - This is exactly the same as ``relative_polynomial()``. + This is exactly the same as :meth:`relative_polynomial`. EXAMPLES:: @@ -1887,17 +1969,19 @@ def defining_polynomial(self): def polynomial(self): """ - For a relative number field, ``polynomial()`` is deliberately + For a relative number field, :meth:`polynomial` is deliberately not implemented. Either :meth:`~relative_polynomial` or :meth:`~absolute_polynomial` must be used. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberFieldTower([x^2 + x + 1, x^3 + x + 1]) sage: K.polynomial() Traceback (most recent call last): ... - NotImplementedError: For a relative number field L you must use either L.relative_polynomial() or L.absolute_polynomial() as appropriate + NotImplementedError: For a relative number field L you must use either + L.relative_polynomial() or L.absolute_polynomial() as appropriate """ raise NotImplementedError("For a relative number field L you must use either L.relative_polynomial() or L.absolute_polynomial() as appropriate") @@ -1907,6 +1991,7 @@ def base_field(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField([x^3 + x + 1]) sage: R.<z> = k[] sage: L.<b> = NumberField(z^3 + a) @@ -1929,6 +2014,7 @@ def base_ring(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField([x^2 + 1, x^3 + x + 1]) sage: k.base_ring() Number Field in a1 with defining polynomial x^3 + x + 1 @@ -1953,7 +2039,8 @@ def embeddings(self, K): EXAMPLES:: - sage: K.<a,b> = NumberField([x^3 - 2, x^2+1]) + sage: x = polygen(ZZ, 'x') + sage: K.<a,b> = NumberField([x^3 - 2, x^2 + 1]) sage: f = K.embeddings(ComplexField(58)); f [ Relative number field morphism: @@ -1990,25 +2077,28 @@ def embeddings(self, K): # then it is most natural, so we put it first. put_natural_embedding_first(v) - self.__embeddings[K] = Sequence(v, cr=v!=[], immutable=True, check=False, universe=self.Hom(K)) + self.__embeddings[K] = Sequence(v, cr=bool(v), immutable=True, check=False, universe=self.Hom(K)) return self.__embeddings[K] def automorphisms(self): r""" - Compute all Galois automorphisms of self over the base field. This is - different than computing the embeddings of self into self; there, + Compute all Galois automorphisms of ``self`` over the base field. This is + different from computing the embeddings of ``self`` into ``self``; there, automorphisms that do not fix the base field are considered. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 10000, x^2 + x + 50]); K Number Field in a with defining polynomial x^2 + 10000 over its base field sage: K.automorphisms() [ - Relative number field endomorphism of Number Field in a with defining polynomial x^2 + 10000 over its base field + Relative number field endomorphism of Number Field in a + with defining polynomial x^2 + 10000 over its base field Defn: a |--> a b |--> b, - Relative number field endomorphism of Number Field in a with defining polynomial x^2 + 10000 over its base field + Relative number field endomorphism of Number Field in a + with defining polynomial x^2 + 10000 over its base field Defn: a |--> -a b |--> b ] @@ -2022,10 +2112,12 @@ def automorphisms(self): Number Field in b with defining polynomial x^2 + x + 50 over its base field sage: L.automorphisms() [ - Relative number field endomorphism of Number Field in b with defining polynomial x^2 + x + 50 over its base field + Relative number field endomorphism of Number Field in b + with defining polynomial x^2 + x + 50 over its base field Defn: b |--> b a |--> a, - Relative number field endomorphism of Number Field in b with defining polynomial x^2 + x + 50 over its base field + Relative number field endomorphism of Number Field in b + with defining polynomial x^2 + x + 50 over its base field Defn: b |--> -b - 1 a |--> a ] @@ -2041,11 +2133,13 @@ def automorphisms(self): sage: K.<c> = F.extension(Y^2 - (1 + a)*(a + b)*a*b) sage: K.automorphisms() [ - Relative number field endomorphism of Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Relative number field endomorphism of Number Field in c + with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field Defn: c |--> c a |--> a b |--> b, - Relative number field endomorphism of Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Relative number field endomorphism of Number Field in c + with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field Defn: c |--> -c a |--> a b |--> b @@ -2058,13 +2152,14 @@ def automorphisms(self): L = self.absolute_field('a') L_into_self, self_into_L = L.structure() - aas = L.automorphisms() # absolute automorphisms + aas = L.automorphisms() # absolute automorphisms a = self_into_L(self.gen()) abs_base_gens = [self_into_L(_) for _ in self.base_field().gens()] - v = sorted([ self.hom([ L_into_self(aa(a)) ]) for aa in aas if all(aa(g) == g for g in abs_base_gens) ]) + v = sorted([self.hom([L_into_self(aa(a))]) for aa in aas + if all(aa(g) == g for g in abs_base_gens)]) put_natural_embedding_first(v) - self.__automorphisms = Sequence(v, cr = (v != []), immutable=True, + self.__automorphisms = Sequence(v, cr=bool(v), immutable=True, check=False, universe=self.Hom(self)) return self.__automorphisms @@ -2083,7 +2178,7 @@ def logarithmic_embedding(self, prec=53): OUTPUT: - - the morphism of ``self`` under the logarithmic embedding in the category Set. + the morphism of ``self`` under the logarithmic embedding in the category Set. EXAMPLES:: @@ -2139,44 +2234,45 @@ def closure_map(x, prec=53): def places(self, all_complex=False, prec=None): """ - Return the collection of all infinite places of self. + Return the collection of all infinite places of ``self``. By default, this returns the set of real places as - homomorphisms into RIF first, followed by a choice of one of - each pair of complex conjugate homomorphisms into CIF. + homomorphisms into ``RIF`` first, followed by a choice of one of + each pair of complex conjugate homomorphisms into ``CIF``. - On the other hand, if prec is not None, we simply return places - into RealField(prec) and ComplexField(prec) (or RDF, CDF if - prec=53). + On the other hand, if ``prec`` is not ``None``, we simply return places + into ``RealField(prec)`` and ``ComplexField(prec)`` (or ``RDF``, ``CDF`` if + ``prec=53``). - There is an optional flag all_complex, which defaults to False. If - all_complex is True, then the real embeddings are returned as - embeddings into CIF instead of RIF. + There is an optional flag ``all_complex``, which defaults to ``False``. If + ``all_complex`` is ``True``, then the real embeddings are returned as + embeddings into ``CIF`` instead of ``RIF``. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<b, c> = NumberFieldTower([x^2 - 5, x^3 + x + 3]) sage: L.places() [Relative number field morphism: - From: Number Field in b with defining polynomial x^2 - 5 over its base field - To: Real Field with 106 bits of precision - Defn: b |--> -2.236067977499789696409173668937 - c |--> -1.213411662762229634132131377426, - Relative number field morphism: - From: Number Field in b with defining polynomial x^2 - 5 over its base field - To: Real Field with 106 bits of precision - Defn: b |--> 2.236067977499789696411548005367 - c |--> -1.213411662762229634130492421800, - Relative number field morphism: - From: Number Field in b with defining polynomial x^2 - 5 over its base field - To: Complex Field with 53 bits of precision - Defn: b |--> -2.23606797749979 ...e-1...*I - c |--> 0.606705831381... - 1.45061224918844*I, - Relative number field morphism: - From: Number Field in b with defining polynomial x^2 - 5 over its base field - To: Complex Field with 53 bits of precision - Defn: b |--> 2.23606797749979 - 4.44089209850063e-16*I - c |--> 0.606705831381115 - 1.45061224918844*I] + From: Number Field in b with defining polynomial x^2 - 5 over its base field + To: Real Field with 106 bits of precision + Defn: b |--> -2.236067977499789696409173668937 + c |--> -1.213411662762229634132131377426, + Relative number field morphism: + From: Number Field in b with defining polynomial x^2 - 5 over its base field + To: Real Field with 106 bits of precision + Defn: b |--> 2.236067977499789696411548005367 + c |--> -1.213411662762229634130492421800, + Relative number field morphism: + From: Number Field in b with defining polynomial x^2 - 5 over its base field + To: Complex Field with 53 bits of precision + Defn: b |--> -2.23606797749979 ...e-1...*I + c |--> 0.606705831381... - 1.45061224918844*I, + Relative number field morphism: + From: Number Field in b with defining polynomial x^2 - 5 over its base field + To: Complex Field with 53 bits of precision + Defn: b |--> 2.23606797749979 - 4.44089209850063e-16*I + c |--> 0.606705831381115 - 1.45061224918844*I] """ L = self.absolute_field('a') pl = L.places(all_complex, prec) @@ -2186,10 +2282,11 @@ def absolute_different(self): r""" Return the absolute different of this relative number field `L`, as an ideal of `L`. To get the relative different of `L/K`, use - ``L.relative_different()``. + :meth:`relative_different`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: t = K['t'].gen() sage: L.<b> = K.extension(t^4 - i) @@ -2204,10 +2301,11 @@ def relative_different(self): r""" Return the relative different of this extension `L/K` as an ideal of `L`. If you want the absolute different of - `L/\QQ`, use ``L.absolute_different()``. + `L/\QQ`, use :meth:`absolute_different`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: PK.<t> = K[] sage: L.<a> = K.extension(t^4 - i) @@ -2226,11 +2324,13 @@ def different(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberFieldTower([x^2 + x + 1, x^3 + x + 1]) sage: K.different() Traceback (most recent call last): ... - NotImplementedError: For a relative number field you must use relative_different or absolute_different as appropriate + NotImplementedError: For a relative number field you must use + relative_different or absolute_different as appropriate """ raise NotImplementedError("For a relative number field you must use relative_different or absolute_different as appropriate") @@ -2248,6 +2348,7 @@ def absolute_discriminant(self, v=None): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: t = K['t'].gen() sage: L.<b> = K.extension(t^4 - i) @@ -2270,6 +2371,7 @@ def relative_discriminant(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: t = K['t'].gen() sage: L.<b> = K.extension(t^4 - i) @@ -2305,11 +2407,13 @@ def discriminant(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberFieldTower([x^2 + x + 1, x^3 + x + 1]) sage: K.discriminant() Traceback (most recent call last): ... - NotImplementedError: For a relative number field you must use relative_discriminant or absolute_discriminant as appropriate + NotImplementedError: For a relative number field you must use + relative_discriminant or absolute_discriminant as appropriate """ raise NotImplementedError("For a relative number field you must use relative_discriminant or absolute_discriminant as appropriate") @@ -2321,11 +2425,13 @@ def disc(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberFieldTower([x^2 + x + 1, x^3 + x + 1]) sage: K.disc() Traceback (most recent call last): ... - NotImplementedError: For a relative number field you must use relative_discriminant or absolute_discriminant as appropriate + NotImplementedError: For a relative number field you must use + relative_discriminant or absolute_discriminant as appropriate """ raise NotImplementedError("For a relative number field you must use relative_discriminant or absolute_discriminant as appropriate") @@ -2336,35 +2442,36 @@ def order(self, *gens, **kwds): INPUT: - - ``gens`` -- list of elements of self; if no generators are given, just - returns the cardinality of this number field (oo) for consistency. - - ``check_is_integral`` -- bool (default: True), whether to check that each + - ``gens`` -- list of elements of ``self``; if no generators are given, just + returns the cardinality of this number field (`\infty`) for consistency. + - ``check_is_integral`` -- bool (default: ``True``), whether to check that each generator is integral. - - ``check_rank`` -- bool (default: True), whether to check that the ring - generated by gens is of full rank. - - ``allow_subfield`` -- bool (default: False), if True and the generators + - ``check_rank`` -- bool (default: ``True``), whether to check that the ring + generated by ``gens`` is of full rank. + - ``allow_subfield`` -- bool (default: ``False``), if ``True`` and the generators do not generate an order, i.e., they generate a subring of smaller rank, instead of raising an error, return an order in a smaller number field. - The check_is_integral and check_rank inputs must be given as + The ``check_is_integral`` and ``check_rank`` inputs must be given as explicit keyword arguments. EXAMPLES:: - sage: P.<a,b,c> = QQ[2^(1/2), 2^(1/3), 3^(1/2)] - sage: R = P.order([a,b,c]); R - Relative Order in Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field + sage: P.<a,b,c> = QQ[2^(1/2), 2^(1/3), 3^(1/2)] # needs sage.symbolic + sage: R = P.order([a,b,c]); R # needs sage.symbolic + Relative Order in Number Field in sqrt2 + with defining polynomial x^2 - 2 over its base field The base ring of an order in a relative extension is still `\ZZ`.:: - sage: R.base_ring() + sage: R.base_ring() # needs sage.symbolic Integer Ring One must give enough generators to generate a ring of finite index in the maximal order:: - sage: P.order([a,b]) + sage: P.order([a, b]) # needs sage.symbolic Traceback (most recent call last): ... ValueError: the rank of the span of gens is wrong @@ -2389,7 +2496,7 @@ def is_free(self, proof=None): EXAMPLES:: sage: x = polygen(QQ) - sage: K.<a> = NumberField(x^2+6) + sage: K.<a> = NumberField(x^2 + 6) sage: x = polygen(K) sage: L.<b> = K.extension(x^2 + 3) # extend by x^2+3 sage: L.is_free() @@ -2407,8 +2514,9 @@ def _factor_univariate_polynomial(self, poly, **kwargs): EXAMPLES:: - sage: K.<i> = NumberField(x**2+1) - sage: L.<sqrt2> = K.extension(x*x-2) + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x**2 + 1) + sage: L.<sqrt2> = K.extension(x*x - 2) sage: x = polygen(L,'x') sage: factor(x**2+8) # indirect doctest (x + 2*i*sqrt2) * (x - 2*i*sqrt2) @@ -2424,7 +2532,7 @@ def _factor_univariate_polynomial(self, poly, **kwargs): def lift_to_base(self, element): """ Lift an element of this extension into the base field if possible, - or raise a ValueError if it is not possible. + or raise a :class:`ValueError` if it is not possible. EXAMPLES:: @@ -2469,29 +2577,30 @@ def lift_to_base(self, element): # Now we should have a polynomial in the variable y. # Otherwise we're not in the base field. if r.type() != "t_POL" or str(r.variable()) != 'y': - raise ValueError("The element %s is not in the base field"%element) + raise ValueError("The element %s is not in the base field" % element) return self.base_field()(r, check=False) def relativize(self, alpha, names): r""" - Given an element in self or an embedding of a subfield into self, - return a relative number field `K` isomorphic to self that is relative + Given an element in ``self`` or an embedding of a subfield into ``self``, + return a relative number field `K` isomorphic to ``self`` that is relative over the absolute field `\QQ(\alpha)` or the domain of `\alpha`, along - with isomorphisms from `K` to self and from self to `K`. + with isomorphisms from `K` to ``self`` and from ``self`` to `K`. INPUT: - - ``alpha`` -- an element of self, or an embedding of a subfield into self + - ``alpha`` -- an element of ``self``, or an embedding of a subfield into ``self`` - ``names`` -- name of generator for output field `K`. OUTPUT: `K` -- a relative number field Also, ``K.structure()`` returns ``from_K`` and ``to_K``, where - ``from_K`` is an isomorphism from `K` to self and ``to_K`` is - an isomorphism from self to `K`. + ``from_K`` is an isomorphism from `K` to ``self`` and ``to_K`` is + an isomorphism from ``self`` to `K`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^4 + 3, x^2 + 2]); K Number Field in a with defining polynomial x^4 + 3 over its base field sage: L.<z,w> = K.relativize(a^2) @@ -2500,7 +2609,8 @@ def relativize(self, alpha, names): sage: w^2 -3 sage: L - Number Field in z with defining polynomial x^4 + (-2*w + 4)*x^2 + 4*w + 1 over its base field + Number Field in z with defining polynomial + x^4 + (-2*w + 4)*x^2 + 4*w + 1 over its base field sage: L.base_field() Number Field in w with defining polynomial x^2 + 3 @@ -2517,7 +2627,8 @@ def relativize(self, alpha, names): sage: L_over_K = L.relativize(K_into_L, 'c'); L_over_K Number Field in c with defining polynomial x^2 + a0_0 over its base field sage: L_over_K_to_L, L_to_L_over_K = L_over_K.structure() - sage: M_over_L_over_K = M.relativize(L_into_M * L_over_K_to_L, 'd'); M_over_L_over_K + sage: M_over_L_over_K = M.relativize(L_into_M * L_over_K_to_L, 'd') + sage: M_over_L_over_K Number Field in d with defining polynomial x^2 + c over its base field sage: M_over_L_over_K.base_field() is L_over_K True @@ -2565,30 +2676,30 @@ def relativize(self, alpha, names): L = K.relativize(beta, names) return K.relativize(beta, names, structure=structure.RelativeFromRelative(L)) - def uniformizer(self, P, others = "positive"): + def uniformizer(self, P, others="positive"): """ - Returns an element of self with valuation 1 at the prime ideal P. + Returns an element of ``self`` with valuation 1 at the prime ideal `P`. INPUT: + - ``self`` -- a number field - - ``self`` - a number field - - - ``P`` - a prime ideal of self + - ``P`` -- a prime ideal of ``self`` - - ``others`` - either "positive" (default), in which + - ``others`` -- either ``"positive"`` (default), in which case the element will have non-negative valuation at all other - primes of self, or "negative", in which case the element will have - non-positive valuation at all other primes of self. + primes of ``self``, or ``"negative"``, in which case the element will have + non-positive valuation at all other primes of ``self``. .. note:: - When P is principal (e.g. always when self has class number - one) the result may or may not be a generator of P! + When `P` is principal (e.g., always when ``self`` has class number + one), the result may or may not be a generator of `P`! EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 23, x^2 - 3]) sage: P = K.prime_factors(5)[0]; P Fractional ideal (5, 1/2*a + b - 5/2) @@ -2601,7 +2712,7 @@ def uniformizer(self, P, others = "positive"): if not is_NumberFieldIdeal(P): P = self.ideal(P) if not P.is_maximal(): - raise ValueError("P (=%s) must be a nonzero prime."%P) + raise ValueError("P (=%s) must be a nonzero prime." % P) abs = self.absolute_field('a') from_abs = abs.structure()[0] return from_abs(abs.uniformizer(P.absolute_ideal(), others=others)) @@ -2621,4 +2732,5 @@ def NumberField_relative_v1(base_field, poly, name, latex_name, canonical_embedd return NumberField(poly.change_ring(base_field), name, check=False, embedding=canonical_embedding, latex_name=latex_name) + NumberField_extension_v1 = NumberField_relative_v1 # historical reasons only diff --git a/src/sage/rings/number_field/order.py b/src/sage/rings/number_field/order.py index f0b0c0f9656..e789a97bc75 100644 --- a/src/sage/rings/number_field/order.py +++ b/src/sage/rings/number_field/order.py @@ -9,6 +9,7 @@ We define an absolute order:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 1); O = K.order(2*a) sage: O.basis() [1, 2*a] @@ -16,7 +17,7 @@ We compute a basis for an order in a relative extension that is generated by 2 elements:: - sage: K.<a,b> = NumberField([x^2 + 1, x^2 - 3]); O = K.order([3*a,2*b]) + sage: K.<a,b> = NumberField([x^2 + 1, x^2 - 3]); O = K.order([3*a, 2*b]) sage: O.basis() [1, 3*a - 2*b, -6*b*a + 6, 3*a] @@ -24,12 +25,14 @@ sage: K.<a> = NumberField((x+1)^10 + 17) sage: K.maximal_order() - Maximal Order in Number Field in a with defining polynomial x^10 + 10*x^9 + 45*x^8 + 120*x^7 + 210*x^6 + 252*x^5 + 210*x^4 + 120*x^3 + 45*x^2 + 10*x + 18 + Maximal Order in Number Field in a with defining polynomial x^10 + 10*x^9 + + 45*x^8 + 120*x^7 + 210*x^6 + 252*x^5 + 210*x^4 + 120*x^3 + 45*x^2 + 10*x + 18 We compute a suborder, which has index a power of 17 in the maximal order:: sage: O = K.order(17*a); O - Order in Number Field in a with defining polynomial x^10 + 10*x^9 + 45*x^8 + 120*x^7 + 210*x^6 + 252*x^5 + 210*x^4 + 120*x^3 + 45*x^2 + 10*x + 18 + Order in Number Field in a with defining polynomial x^10 + 10*x^9 + + 45*x^8 + 120*x^7 + 210*x^6 + 252*x^5 + 210*x^4 + 120*x^3 + 45*x^2 + 10*x + 18 sage: m = O.index_in(K.maximal_order()); m 23453165165327788911665591944416226304630809183732482257 sage: factor(m) @@ -65,7 +68,7 @@ # 2020 John H. Palmieri <jhpalmieri64@gmail.com> # 2020 Thierry Monteil <sage@lma.metelu.net> # 2021 Antonio Rojas <arojas@archlinux.org> -# 2021 Jonathan Kliem <jonathan.kliem@fu-berlin.de> +# 2021 Jonathan Kliem <jonathan.kliem@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -115,6 +118,7 @@ def get_object(self, version, key, extra_args): internal state when they are recreated with more additional information available about them:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 - 1000003, x^2 - 5*1000099^2]) sage: O = L.maximal_order([2], assume_maximal=None) @@ -152,6 +156,7 @@ class AbsoluteOrderFactory(OrderFactory): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K.order(i) Order in Number Field in i with defining polynomial x^2 + 1 @@ -166,6 +171,7 @@ def create_key_and_extra_args(self, K, module_rep, is_maximal=None, check=True, In particular, this normalizes the data that is used when pickling orders:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: OK = K.order(i) sage: OK._factory_data @@ -204,6 +210,7 @@ def create_object(self, version, key, is_maximal=None, is_maximal_at=()): This method is also used during unpickling:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: OK = K.order(i) sage: loads(dumps(OK)) is OK @@ -228,6 +235,7 @@ def reduce_data(self, order): This also works for relative orders since they are wrapping absolute orders:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 - 1000003, x^2 - 5*1000099^2]) sage: O = L.maximal_order([5], assume_maximal=None) @@ -258,11 +266,13 @@ class RelativeOrderFactory(OrderFactory): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: R.<j> = K[] sage: L.<j> = K.extension(j^2 - 2) sage: L.order([i, j]) - Relative Order in Number Field in j with defining polynomial j^2 - 2 over its base field + Relative Order in Number Field in j + with defining polynomial j^2 - 2 over its base field """ @@ -274,6 +284,7 @@ def create_key_and_extra_args(self, K, absolute_order, is_maximal=None, check=Tr In particular, this normalizes the data that is used when pickling orders:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: R.<j> = K[] sage: L.<j> = K.extension(j^2 - 2) @@ -301,6 +312,7 @@ def create_object(self, version, key, is_maximal=None, is_maximal_at=()): This method is also used during unpickling:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: R.<j> = K[] sage: L.<j> = K.extension(j^2 - 2) @@ -321,12 +333,13 @@ def create_object(self, version, key, is_maximal=None, is_maximal_at=()): def is_NumberFieldOrder(R): r""" - Return True if R is either an order in a number field or is the ring `\ZZ` of integers. + Return ``True`` if `R` is either an order in a number field or is the ring `\ZZ` of integers. EXAMPLES:: sage: from sage.rings.number_field.order import is_NumberFieldOrder - sage: is_NumberFieldOrder(NumberField(x^2+1,'a').maximal_order()) + sage: x = polygen(ZZ, 'x') + sage: is_NumberFieldOrder(NumberField(x^2 + 1,'a').maximal_order()) True sage: is_NumberFieldOrder(ZZ) True @@ -341,7 +354,7 @@ def is_NumberFieldOrder(R): def EquationOrder(f, names, **kwds): r""" Return the equation order generated by a root of the irreducible - polynomial f or list of polynomials `f` (to construct a relative + polynomial `f` or list ``f`` of polynomials (to construct a relative equation order). IMPORTANT: Note that the generators of the returned order need @@ -350,9 +363,11 @@ def EquationOrder(f, names, **kwds): EXAMPLES:: - sage: O.<a,b> = EquationOrder([x^2+1, x^2+2]) + sage: x = polygen(ZZ, 'x') + sage: O.<a,b> = EquationOrder([x^2 + 1, x^2 + 2]) sage: O - Relative Order in Number Field in a with defining polynomial x^2 + 1 over its base field + Relative Order in Number Field in a + with defining polynomial x^2 + 1 over its base field sage: O.0 -b*a - 1 sage: O.1 @@ -365,7 +380,7 @@ def EquationOrder(f, names, **kwds): ... ValueError: each generator must be integral - sage: R = EquationOrder( [x^3 + x + 1, x^2 + 1/2], 'alpha'); R + sage: R = EquationOrder([x^3 + x + 1, x^2 + 1/2], 'alpha'); R Traceback (most recent call last): ... ValueError: each generator must be integral @@ -397,6 +412,7 @@ class Order(IntegralDomain, sage.rings.abc.Order): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<theta> = NumberField(x^4 + x + 17) sage: K.maximal_order() Maximal Order in Number Field in theta with defining polynomial x^4 + x + 17 @@ -432,7 +448,8 @@ def __init__(self, K): TESTS:: - sage: k.<alg> = NumberField(x^7+3*x+1, embedding=CC(0,1)) + sage: x = polygen(ZZ, 'x') + sage: k.<alg> = NumberField(x^7 + 3*x + 1, embedding=CC(0,1)) sage: O = k.order(alg) sage: ordelt = O(alg) sage: CC(ordelt) @@ -450,6 +467,7 @@ def fractional_ideal(self, *args, **kwds): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 2) sage: R = K.maximal_order() sage: R.fractional_ideal(2/3 + 7*a, a) @@ -463,12 +481,14 @@ def ideal(self, *args, **kwds): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 7) sage: R = K.maximal_order() sage: R.ideal(2/3 + 7*a, a) Traceback (most recent call last): ... - ValueError: ideal must be integral; use fractional_ideal to create a non-integral ideal. + ValueError: ideal must be integral; + use fractional_ideal to create a non-integral ideal. sage: R.ideal(7*a, 77 + 28*a) Fractional ideal (7) sage: R = K.order(4*a) @@ -491,6 +511,14 @@ def ideal(self, *args, **kwds): """ if not self.is_maximal(): raise NotImplementedError("ideals of non-maximal orders not yet supported.") + from sage.misc.superseded import deprecation + deprecation(34806, 'In the future, constructing an ideal of the ring of ' + 'integers of a number field will use an implementation ' + 'compatible with ideals of other (non-maximal) orders, ' + 'rather than returning an integral fractional ideal of ' + 'its containing number field. Use .fractional_ideal(), ' + 'together with an .is_integral() check if desired, to ' + 'avoid your code breaking with future changes to Sage.') I = self.number_field().ideal(*args, **kwds) if not I.is_integral(): raise ValueError("ideal must be integral; use fractional_ideal to create a non-integral ideal.") @@ -502,6 +530,7 @@ def _coerce_map_from_(self, R): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5077) sage: Ok = k.maximal_order() sage: Ok.has_coerce_map_from(k) #indirect doctest @@ -517,6 +546,7 @@ def __mul__(self, right): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5077); G = k.class_group(); G Class group of order 22 with structure C22 of Number Field in a with defining polynomial x^2 + 5077 sage: G.0 ^ -9 @@ -538,6 +568,7 @@ def __rmul__(self, left): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 431); G = k.class_group(); G Class group of order 21 with structure C21 of Number Field in a with defining polynomial x^2 + 431 sage: G.0 # random output @@ -557,6 +588,7 @@ def is_field(self, proof=True): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<alpha> = NumberField(x**4 - x**2 + 7) sage: O = L.maximal_order() ; O.is_field() False @@ -571,6 +603,7 @@ def is_noetherian(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<alpha> = NumberField(x**4 - x**2 + 7) sage: O = L.maximal_order() ; O.is_noetherian() True @@ -581,12 +614,13 @@ def is_noetherian(self): return True def is_integrally_closed(self): - """ + r""" Return ``True`` if this ring is integrally closed, i.e., is equal to the maximal order. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 189*x + 394) sage: R = K.order(2*a) sage: R.is_integrally_closed() @@ -601,7 +635,7 @@ def is_integrally_closed(self): return self.is_maximal() def krull_dimension(self): - """ + r""" Return the Krull dimension of this order, which is 1. EXAMPLES:: @@ -617,16 +651,18 @@ def krull_dimension(self): return ZZ(1) def integral_closure(self): - """ + r""" Return the integral closure of this order. EXAMPLES:: sage: K.<a> = QuadraticField(5) sage: O2 = K.order(2*a); O2 - Order in Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? + Order in Number Field in a with defining polynomial x^2 - 5 + with a = 2.236067977499790? sage: O2.integral_closure() - Maximal Order in Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? + Maximal Order in Number Field in a with defining polynomial x^2 - 5 + with a = 2.236067977499790? sage: OK = K.maximal_order() sage: OK is OK.integral_closure() True @@ -642,6 +678,7 @@ def gen(self, i): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<c> = NumberField(x^3 + 2*x + 17) sage: O = K.maximal_order(); O Maximal Order in Number Field in c with defining polynomial x^3 + 2*x + 17 @@ -666,11 +703,12 @@ def gen(self, i): return self.basis()[i] def ngens(self): - """ + r""" Return the number of module generators of this order. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8) sage: O = K.maximal_order() sage: O.ngens() @@ -684,6 +722,7 @@ def basis(self): # this must be defined in derived class EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + x^2 - 16*x + 16) sage: O = K.maximal_order(); O Maximal Order in Number Field in a with defining polynomial x^3 + x^2 - 16*x + 16 @@ -714,7 +753,7 @@ def coordinates(self, x): Uses linear algebra. The change-of-basis matrix is cached. Provides simpler implementations for - ``_contains_()``, ``is_integral()`` and ``smallest_integer()``. + :meth:`_contains_`, :meth:`is_integral` and :meth:`smallest_integer`. EXAMPLES:: @@ -760,6 +799,7 @@ def free_module(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8) sage: O = K.maximal_order(); O.basis() [1, 1/2*a^2 + 1/2*a, a^2] @@ -771,9 +811,10 @@ def free_module(self): [ 0 0 1] An example in a relative extension. Notice that the module is - a `\ZZ`-module in the absolute_field associated to the relative + a `\ZZ`-module in the absolute field associated to the relative field:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 2]) sage: O = K.maximal_order(); O.basis() [(-3/2*b - 5)*a + 7/2*b - 2, -3*a + 2*b, -2*b*a - 3, -7*a + 5*b] @@ -797,10 +838,11 @@ def free_module(self): @cached_method def ring_generators(self): """ - Return generators for self as a ring. + Return generators for ``self`` as a ring. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: O = K.maximal_order(); O Gaussian Integers in Number Field in i with defining polynomial x^2 + 1 @@ -821,7 +863,9 @@ def ring_generators(self): sage: K.<a, b> = NumberField([x^2 + x + 1, x^3 - 3]) sage: O = K.maximal_order() sage: O.ring_generators() - [(-5/3*b^2 + 3*b - 2)*a - 7/3*b^2 + b + 3, (-5*b^2 - 9)*a - 5*b^2 - b, (-6*b^2 - 11)*a - 6*b^2 - b] + [(-5/3*b^2 + 3*b - 2)*a - 7/3*b^2 + b + 3, + (-5*b^2 - 9)*a - 5*b^2 - b, + (-6*b^2 - 11)*a - 6*b^2 - b] """ K = self._K n = [] @@ -845,6 +889,7 @@ def _defining_names(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: B.<z> = EquationOrder(x^2 + 3) sage: B._defining_names() (z,) @@ -860,12 +905,13 @@ def _defining_names(self): def zeta(self, n=2, all=False): r""" - Return a primitive n-th root of unity in this order, if it - contains one. If all is True, return all of them. + Return a primitive `n`-th root of unity in this order, if it + contains one. If ``all`` is ``True``, return all of them. EXAMPLES:: - sage: F.<alpha> = NumberField(x**2+3) + sage: x = polygen(ZZ, 'x') + sage: F.<alpha> = NumberField(x**2 + 3) sage: F.ring_of_integers().zeta(6) -1/2*alpha + 1/2 sage: O = F.order([3*alpha]) @@ -893,6 +939,7 @@ def number_field(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<b> = NumberField(x^4 + x^2 + 2) sage: O = K.order(2*b); O Order in Number Field in b with defining polynomial x^4 + x^2 + 2 @@ -907,13 +954,14 @@ def number_field(self): def ambient(self): r""" - Return the ambient number field that contains self. + Return the ambient number field that contains ``self``. - This is the same as ``self.number_field()`` and - ``self.fraction_field()`` + This is the same as :meth:`number_field` and + :meth:`fraction_field` EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<z> = NumberField(x^2 - 389) sage: o = k.order(389*z + 1) sage: o @@ -927,12 +975,12 @@ def ambient(self): def residue_field(self, prime, names=None, check=False): """ - Return the residue field of this order at a given prime, ie `O/pO`. + Return the residue field of this order at a given prime, i.e., `O/pO`. INPUT: - ``prime`` -- a prime ideal of the maximal order in this number field. - - ``names`` -- the name of the variable in the residue field + - ``names`` -- the name of the variable in the residue field. - ``check`` -- whether or not to check the primality of prime. OUTPUT: @@ -942,7 +990,8 @@ def residue_field(self, prime, names=None, check=False): EXAMPLES:: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^4+3*x^2-17) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^4 + 3*x^2 - 17) sage: P = K.ideal(61).factor()[0][0] sage: OK = K.maximal_order() sage: OK.residue_field(P) @@ -964,6 +1013,7 @@ def fraction_field(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<b> = NumberField(x^4 + 17*x^2 + 17) sage: O = K.order(17*b); O Order in Number Field in b with defining polynomial x^4 + 17*x^2 + 17 @@ -979,6 +1029,7 @@ def degree(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<c> = NumberField(x^3 + x^2 - 2*x+8) sage: o = k.maximal_order() sage: o.degree() @@ -994,10 +1045,11 @@ def rank(self): `\ZZ`-module, or the degree of the ambient number field that contains this order. - This is a synonym for ``degree()``. + This is a synonym for :meth:`degree`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<c> = NumberField(x^5 + x^2 + 1) sage: o = k.maximal_order(); o Maximal Order in Number Field in c with defining polynomial x^5 + x^2 + 1 @@ -1012,23 +1064,24 @@ def class_number(self, proof=None): EXAMPLES:: - sage: ZZ[2^(1/3)].class_number() + sage: ZZ[2^(1/3)].class_number() # needs sage.symbolic 1 - sage: QQ[sqrt(-23)].maximal_order().class_number() + sage: QQ[sqrt(-23)].maximal_order().class_number() # needs sage.symbolic 3 - sage: ZZ[120*sqrt(-23)].class_number() + sage: ZZ[120*sqrt(-23)].class_number() # needs sage.symbolic 288 Note that non-maximal orders are only supported in quadratic fields:: - sage: ZZ[120*sqrt(-23)].class_number() + sage: ZZ[120*sqrt(-23)].class_number() # needs sage.symbolic 288 - sage: ZZ[100*sqrt(3)].class_number() + sage: ZZ[100*sqrt(3)].class_number() # needs sage.symbolic 4 - sage: ZZ[11*2^(1/3)].class_number() + sage: ZZ[11*2^(1/3)].class_number() # needs sage.symbolic Traceback (most recent call last): ... - NotImplementedError: computation of class numbers of non-maximal orders not in quadratic fields is not implemented + NotImplementedError: computation of class numbers of non-maximal orders + not in quadratic fields is not implemented """ if not self.is_maximal(): @@ -1046,11 +1099,13 @@ def class_group(self, proof=None, names='c'): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^2 + 5077) sage: O = k.maximal_order(); O Maximal Order in Number Field in a with defining polynomial x^2 + 5077 sage: O.class_group() - Class group of order 22 with structure C22 of Number Field in a with defining polynomial x^2 + 5077 + Class group of order 22 with structure C22 of + Number Field in a with defining polynomial x^2 + 5077 """ if self.is_maximal(): return self.number_field().class_group(proof=proof, names=names) @@ -1059,11 +1114,12 @@ def class_group(self, proof=None, names='c'): def is_suborder(self, other): """ - Return True if self and other are both orders in the - same ambient number field and self is a subset of other. + Return ``True`` if ``self`` and ``other`` are both orders in the + same ambient number field and ``self`` is a subset of ``other``. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: W.<i> = NumberField(x^2 + 1) sage: O5 = W.order(5*i) sage: O10 = W.order(10*i) @@ -1080,13 +1136,13 @@ def is_suborder(self, other): sage: W2.<j> = NumberField(x^2 + 1) sage: P5 = W2.order(5*j) - This is False because the ambient number fields are not equal.:: + This is ``False`` because the ambient number fields are not equal.:: sage: O5.is_suborder(P5) False - We create a field that contains (in no natural way!) W, - and of course again is_suborder returns False:: + We create a field that contains (in no natural way!) `W`, + and of course again :meth:`is_suborder` returns False:: sage: K.<z> = NumberField(x^4 + 1) sage: M = K.order(5*z) @@ -1111,6 +1167,7 @@ def __eq__(self, other): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: O1 = K.order(a); O1 Order in Number Field in a with defining polynomial x^3 + 2 @@ -1143,6 +1200,7 @@ def __ne__(self, other): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: O1 = K.order(a); O1 Order in Number Field in a with defining polynomial x^3 + 2 @@ -1159,6 +1217,7 @@ def __hash__(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: L.<b> = NumberField(x^3 + 3) sage: O1 = K.order(a) @@ -1171,6 +1230,44 @@ def __hash__(self): """ return hash((self._K, self._module_rep)) + def conductor(self): + r""" + For orders in *quadratic* number fields, return the conductor + of this order. + + The conductor is the unique positive integer `f` such that + the discriminant of this order is `f^2` times the discriminant + of the containing quadratic field. + + Not implemented for orders in number fields of degree `\neq 2`. + + .. SEEALSO :: + + :meth:`sage.rings.number_field.number_field.NumberField_quadratic.order_of_conductor` + + EXAMPLES:: + + sage: K.<t> = QuadraticField(-101) + sage: K.maximal_order().conductor() + 1 + sage: K.order(5*t).conductor() + 5 + sage: K.discriminant().factor() + -1 * 2^2 * 101 + sage: K.order(5*t).discriminant().factor() + -1 * 2^2 * 5^2 * 101 + + TESTS:: + + sage: type(K.order(5*t).conductor()) + <class 'sage.rings.integer.Integer'> + """ + if not isinstance(self._K, sage.rings.abc.NumberField_quadratic): + raise NotImplementedError('not implemented for number fields of degree != 2') + D = self.discriminant() + D0 = self._K.discriminant() + return (D // D0).sqrt() + def random_element(self, *args, **kwds): r""" Return a random element of this order. @@ -1188,6 +1285,7 @@ def random_element(self, *args, **kwds): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: OK = K.ring_of_integers() sage: OK.random_element() # random output @@ -1204,7 +1302,8 @@ def random_element(self, *args, **kwds): sage: K.<z> = CyclotomicField(17) sage: OK = K.ring_of_integers() sage: OK.random_element() # random output - z^15 - z^11 - z^10 - 4*z^9 + z^8 + 2*z^7 + z^6 - 2*z^5 - z^4 - 445*z^3 - 2*z^2 - 15*z - 2 + z^15 - z^11 - z^10 - 4*z^9 + z^8 + 2*z^7 + z^6 + - 2*z^5 - z^4 - 445*z^3 - 2*z^2 - 15*z - 2 sage: OK.random_element().is_integral() True sage: OK.random_element().parent() is OK @@ -1241,10 +1340,11 @@ def random_element(self, *args, **kwds): def absolute_degree(self): r""" - Return the absolute degree of this order, ie the degree of this order over `\ZZ`. + Return the absolute degree of this order, i.e., the degree of this order over `\ZZ`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: O = K.maximal_order() sage: O.absolute_degree() @@ -1254,13 +1354,14 @@ def absolute_degree(self): def valuation(self, p): r""" - Return the ``p``-adic valuation on this order. + Return the `p`-adic valuation on this order. EXAMPLES: - The valuation can be specified with an integer ``prime`` that is + The valuation can be specified with an integer prime `p` that is completely ramified or unramified:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 1) sage: O = K.order(2*a) sage: valuations.pAdicValuation(O, 2) @@ -1274,12 +1375,13 @@ def valuation(self, p): sage: GaussianIntegers().valuation(3) 3-adic valuation - A ``prime`` that factors into pairwise distinct factors, results in an error:: + A prime `p` that factors into pairwise distinct factors, results in an error:: sage: GaussianIntegers().valuation(5) Traceback (most recent call last): ... - ValueError: The valuation Gauss valuation induced by 5-adic valuation does not approximate a unique extension of 5-adic valuation with respect to x^2 + 1 + ValueError: The valuation Gauss valuation induced by 5-adic valuation does not + approximate a unique extension of 5-adic valuation with respect to x^2 + 1 The valuation can also be selected by giving a valuation on the base ring that extends uniquely:: @@ -1292,15 +1394,17 @@ def valuation(self, p): sage: GaussianIntegers().valuation(ZZ.valuation(5)) Traceback (most recent call last): ... - ValueError: The valuation Gauss valuation induced by 5-adic valuation does not approximate a unique extension of 5-adic valuation with respect to x^2 + 1 + ValueError: The valuation Gauss valuation induced by 5-adic valuation does not + approximate a unique extension of 5-adic valuation with respect to x^2 + 1 If the fraction field is of the form `K[x]/(G)`, you can specify a valuation by providing a discrete pseudo-valuation on `K[x]` which sends `G` to infinity:: sage: R.<x> = QQ[] - sage: v = GaussianIntegers().valuation(GaussValuation(R, QQ.valuation(5)).augmentation(x + 2, infinity)) - sage: w = GaussianIntegers().valuation(GaussValuation(R, QQ.valuation(5)).augmentation(x + 1/2, infinity)) + sage: GV5 = GaussValuation(R, QQ.valuation(5)) + sage: v = GaussianIntegers().valuation(GV5.augmentation(x + 2, infinity)) + sage: w = GaussianIntegers().valuation(GV5.augmentation(x + 1/2, infinity)) sage: v == w False @@ -1395,7 +1499,7 @@ def __init__(self, K, module_rep): sage: from sage.rings.number_field.order import * sage: x = polygen(QQ) - sage: K.<a> = NumberField(x^3+2) + sage: K.<a> = NumberField(x^3 + 2) sage: V, from_v, to_v = K.vector_space() sage: M = span([to_v(a^2), to_v(a), to_v(1)],ZZ) sage: O = AbsoluteOrder(K, M); O @@ -1450,7 +1554,7 @@ def _element_constructor_(self, x): (see :trac:`10017`):: sage: x = polygen(QQ) - sage: K.<a> = NumberField(x^3-10) + sage: K.<a> = NumberField(x^3 - 10) sage: ZK = K.ring_of_integers() sage: ZK.basis() [1/3*a^2 + 1/3*a + 1/3, a, a^2] @@ -1525,6 +1629,7 @@ def __and__(left, right): Verify that an absolute order can be intersected with a relative order:: + sage: x = polygen(ZZ, 'x') sage: L.<a> = K.extension(x^2 - 2) sage: L.absolute_field('z').maximal_order() & L.maximal_order() Maximal Order in Number Field in z with defining polynomial x^4 - 2*x^2 + 9 @@ -1560,10 +1665,11 @@ def _magma_init_(self, magma): OUTPUT: - a MagmaElement, the magma version of this absolute order + a :class:`MagmaElement`, the magma version of this absolute order EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) # optional - magma sage: magma(K.maximal_order()) # optional - magma Equation Order with defining polynomial x^3 + 2 over its ground order @@ -1583,6 +1689,7 @@ def discriminant(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^8 + x^3 - 13*x + 26) sage: O = K.maximal_order() sage: factor(O.discriminant()) @@ -1594,6 +1701,11 @@ def discriminant(self): 3 * 5 * 13^29 * 733 sage: L.discriminant() / O.discriminant() == L.index_in(O)^2 True + + TESTS:: + + sage: type(K.order(5*a).discriminant()) + <class 'sage.rings.integer.Integer'> """ try: return self.__discriminant @@ -1601,7 +1713,7 @@ def discriminant(self): if self._is_maximal(): D = self._K.discriminant() else: - D = self._K.discriminant(self.basis()) + D = ZZ(self._K.discriminant(self.basis())) self.__discriminant = D return D @@ -1614,10 +1726,11 @@ def is_maximal(self, p=None): INPUT: - ``p`` -- an integer prime or ``None`` (default: ``None``); if - set, return whether this order is maximal at the prime ``p``. + set, return whether this order is maximal at the prime `p`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K.order(3*i).is_maximal() @@ -1643,7 +1756,7 @@ def is_maximal(self, p=None): An example involving a relative order:: sage: K.<a, b> = NumberField([x^2 + 1, x^2 - 3]) - sage: O = K.order([3*a,2*b]) + sage: O = K.order([3*a, 2*b]) sage: O.is_maximal() False @@ -1672,6 +1785,7 @@ def _is_maximal(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) sage: K.order(1337*i)._is_maximal() is None @@ -1695,6 +1809,7 @@ def _is_maximal_at(self, p=None): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^13 - 2) sage: O = K.order(a) @@ -1732,6 +1847,7 @@ def _assume_maximal(self, is_maximal=True, p=None): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 - 10001822082820*x^2 + 25009091240356266913960000) sage: O = K.maximal_order([13], assume_maximal=None) @@ -1819,6 +1935,7 @@ def change_names(self, names): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: R = EquationOrder(x^3 + x + 1, 'alpha'); R Order in Number Field in alpha with defining polynomial x^3 + x + 1 sage: R.basis() @@ -1835,10 +1952,10 @@ def change_names(self, names): def index_in(self, other): """ - Return the index of self in other. + Return the index of ``self`` in ``other``. This is a lattice index, - so it is a rational number if self is not contained in other. + so it is a rational number if ``self`` is not contained in ``other``. INPUT: @@ -1850,6 +1967,7 @@ def index_in(self, other): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<i> = NumberField(x^2 + 1) sage: O1 = k.order(i) sage: O5 = k.order(5*i) @@ -1887,6 +2005,7 @@ def module(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a> = NumberField(x^3 + x + 3) sage: m = k.order(3*a); m Order in Number Field in a with defining polynomial x^3 + x + 3 @@ -1905,6 +2024,7 @@ def intersection(self, other): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<i> = NumberField(x^2 + 1) sage: O6 = k.order(6*i) sage: O9 = k.order(9*i) @@ -1927,6 +2047,7 @@ def _repr_(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 - 5) sage: K.maximal_order()._repr_() 'Maximal Order in Number Field in a with defining polynomial x^4 - 5' @@ -1960,6 +2081,7 @@ def basis(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<c> = NumberField(x^3 + x^2 + 1) sage: O = k.maximal_order(); O Maximal Order in Number Field in c with defining polynomial x^3 + x^2 + 1 @@ -1997,6 +2119,7 @@ def absolute_order(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 + 2) sage: O1 = K.order(a); O1 Maximal Order in Number Field in a with defining polynomial x^3 + 2 @@ -2010,7 +2133,7 @@ class Order_relative(Order): """ A relative order in a number field. - A relative order is an order in some relative number field + A relative order is an order in some relative number field. Invariants of this order may be computed with respect to the contained order. @@ -2022,6 +2145,7 @@ def __init__(self, K, absolute_order): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: k.<a,b> = NumberFieldTower([x^2 - 3, x^2 + 1]) sage: O = k.maximal_order(); O # indirect doctest Maximal Relative Order in Number Field in a with defining polynomial x^2 - 3 over its base field @@ -2046,6 +2170,7 @@ def _element_constructor_(self, x): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 2, x^2 + 1000*x + 1]) sage: OK = K.ring_of_integers() sage: OK(a) @@ -2089,6 +2214,7 @@ def _repr_(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: O = EquationOrder([x^2 + x + 1, x^3 - 2],'a,b') sage: O._repr_() 'Relative Order in Number Field in a with defining polynomial x^2 + x + 1 over its base field' @@ -2111,8 +2237,10 @@ def absolute_order(self, names='z'): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: R = EquationOrder([x^2 + 1, x^2 - 5], 'i,g'); R - Relative Order in Number Field in i with defining polynomial x^2 + 1 over its base field + Relative Order in Number Field in i + with defining polynomial x^2 + 1 over its base field sage: R.basis() [1, 6*i - g, -g*i + 2, 7*i - g] @@ -2122,11 +2250,12 @@ def absolute_order(self, names='z'): [1, 5/12*z^3 + 1/6*z, 1/2*z^2, 1/2*z^3] We compute a relative order in alpha0, alpha1, then make the - number field that contains the absolute order be called + generator of the number field that contains the absolute order be called gamma.:: - sage: R = EquationOrder( [x^2 + 2, x^2 - 3], 'alpha'); R - Relative Order in Number Field in alpha0 with defining polynomial x^2 + 2 over its base field + sage: R = EquationOrder([x^2 + 2, x^2 - 3], 'alpha'); R + Relative Order in Number Field in alpha0 + with defining polynomial x^2 + 2 over its base field sage: R.absolute_order('gamma') Order in Number Field in gamma with defining polynomial x^4 - 2*x^2 + 25 sage: R.absolute_order('gamma').basis() @@ -2143,7 +2272,8 @@ def basis(self): EXAMPLES:: - sage: K.<a,b> = NumberField([x^2+1, x^2+3]) + sage: x = polygen(ZZ, 'x') + sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 3]) sage: O = K.order([a,b]) sage: O.basis() [1, -2*a + b, -b*a - 2, -5*a + 3*b] @@ -2169,7 +2299,8 @@ def __add__(left, right): EXAMPLES:: - sage: K.<a,b> = NumberField([x^2+1, x^2+3]) + sage: x = polygen(ZZ, 'x') + sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 3]) sage: O2 = K.order([2*a, b]); O2.absolute_discriminant() 36864 sage: O3 = K.order([3*a, 2*b]); O3.absolute_discriminant() @@ -2209,6 +2340,7 @@ def __and__(left, right): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 + 1, x^2 - 5]) sage: O1 = L.order([a, 2*b]) sage: O2 = L.order([2*a, b]) @@ -2243,10 +2375,11 @@ def is_maximal(self, p=None): INPUT: - ``p`` -- an integer prime or ``None`` (default: ``None``); if - set, return whether this order is maximal at the prime ``p``. + set, return whether this order is maximal at the prime `p`. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 1, x^2 - 5]) sage: K.order(3*a, b).is_maximal() @@ -2278,6 +2411,7 @@ def _is_maximal(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 + 1, x^2 - 5]) sage: O = K.order(a, b) sage: O._is_maximal() is None @@ -2299,6 +2433,7 @@ def _is_maximal_at(self, p=None): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a, b> = NumberField([x^2 - 2, x^13 - 2]) sage: O = K.maximal_order([2, 3, 5], assume_maximal=None) sage: O._is_maximal_at(p=7) is None @@ -2324,6 +2459,7 @@ def _assume_maximal(self, is_maximal=True, p=None): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: L.<a, b> = NumberField([x^2 - 1000005, x^2 - 5*1000099^2]) sage: O = L.maximal_order([13], assume_maximal=None) @@ -2374,8 +2510,8 @@ def _assume_maximal(self, is_maximal=True, p=None): def absolute_discriminant(self): """ - Return the absolute discriminant of self, which is the discriminant - of the absolute order associated to self. + Return the absolute discriminant of ``self``, which is the discriminant + of the absolute order associated to ``self``. OUTPUT: @@ -2383,6 +2519,7 @@ def absolute_discriminant(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: R = EquationOrder([x^2 + 1, x^3 + 2], 'a,b') sage: d = R.absolute_discriminant(); d -746496 @@ -2395,13 +2532,14 @@ def absolute_discriminant(self): def is_suborder(self, other): """ - Return True if self is a subset of the order other. + Return ``True`` if ``self`` is a subset of the order ``other``. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^2 + 1, x^3 + 2]) - sage: R1 = K.order([a,b]) - sage: R2 = K.order([2*a,b]) + sage: R1 = K.order([a, b]) + sage: R2 = K.order([2*a, b]) sage: R3 = K.order([a + b, b + 2*a]) sage: R1.is_suborder(R2) False @@ -2418,10 +2556,10 @@ def is_suborder(self, other): def index_in(self, other): """ - Return the index of self in other. + Return the index of ``self`` in ``other``. This is a lattice index, - so it is a rational number if self is not contained in other. + so it is a rational number if ``self`` is not contained in ``other``. INPUT: @@ -2433,6 +2571,7 @@ def index_in(self, other): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a,b> = NumberField([x^3 + x + 3, x^2 + 1]) sage: R1 = K.order([3*a, 2*b]) sage: R2 = K.order([a, 4*b]) @@ -2453,6 +2592,7 @@ def each_is_integral(v): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: W.<sqrt5> = NumberField(x^2 - 5) sage: from sage.rings.number_field.order import each_is_integral sage: each_is_integral([sqrt5, 2, (1+sqrt5)/2]) @@ -2470,18 +2610,19 @@ def absolute_order_from_ring_generators(gens, check_is_integral=True, INPUT: - ``gens`` -- list of integral elements of an absolute order. - - ``check_is_integral`` -- bool (default: True), whether to check that each + - ``check_is_integral`` -- bool (default: ``True``), whether to check that each generator is integral. - - ``check_rank`` -- bool (default: True), whether to check that the ring - generated by gens is of full rank. - - ``is_maximal`` -- bool (or None); set if maximality of the generated order is + - ``check_rank`` -- bool (default: ``True``), whether to check that the ring + generated by ``gens`` is of full rank. + - ``is_maximal`` -- bool (or ``None``); set if maximality of the generated order is known - - ``allow_subfield`` -- bool (default: False), if True and the generators do + - ``allow_subfield`` -- bool (default: ``False``), if ``True`` and the generators do not generate an order, i.e., they generate a subring of smaller rank, instead of raising an error, return an order in a smaller number field. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 - 5) sage: K.order(a) Order in Number Field in a with defining polynomial x^4 - 5 @@ -2492,7 +2633,7 @@ def absolute_order_from_ring_generators(gens, check_is_integral=True, sage: from sage.rings.number_field.order import absolute_order_from_ring_generators sage: absolute_order_from_ring_generators([a]) Order in Number Field in a with defining polynomial x^4 - 5 - sage: absolute_order_from_ring_generators([3*a, 2, 6*a+1]) + sage: absolute_order_from_ring_generators([3*a, 2, 6*a + 1]) Order in Number Field in a with defining polynomial x^4 - 5 If one of the inputs is non-integral, it is an error.:: @@ -2502,7 +2643,7 @@ def absolute_order_from_ring_generators(gens, check_is_integral=True, ... ValueError: each generator must be integral - If the gens do not generate an order, i.e., generate a ring of full + If the ``gens`` do not generate an order, i.e., generate a ring of full rank, then it is an error.:: sage: absolute_order_from_ring_generators([a^2]) @@ -2536,16 +2677,16 @@ def absolute_order_from_module_generators(gens, check_integral=True, check_rank=True, check_is_ring=True, is_maximal=None, allow_subfield=False, is_maximal_at=()): - """ + r""" INPUT: - ``gens`` -- list of elements of an absolute number field that generates an - order in that number field as a ZZ *module*. - - ``check_integral`` -- check that each gen is integral - - ``check_rank`` -- check that the gens span a module of the correct rank + order in that number field as a `\ZZ`-*module*. + - ``check_integral`` -- check that each generator is integral + - ``check_rank`` -- check that the ``gens`` span a module of the correct rank - ``check_is_ring`` -- check that the module is closed under multiplication (this is very expensive) - - ``is_maximal`` -- bool (or None); set if maximality of the generated order is known + - ``is_maximal`` -- bool (or ``None``); set if maximality of the generated order is known - ``is_maximal_at`` -- a tuple of primes where this order is known to be maximal OUTPUT: @@ -2559,6 +2700,7 @@ def absolute_order_from_module_generators(gens, sage: from sage.rings.number_field.order import absolute_order_from_module_generators + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 - 5) sage: O = K.maximal_order(); O Maximal Order in Number Field in a with defining polynomial x^4 - 5 @@ -2590,11 +2732,13 @@ def absolute_order_from_module_generators(gens, off various check flags:: sage: k.<i> = NumberField(x^2 + 1) - sage: R = absolute_order_from_module_generators([2, 2*i], check_is_ring=False); R + sage: R = absolute_order_from_module_generators([2, 2*i], + ....: check_is_ring=False); R Order in Number Field in i with defining polynomial x^2 + 1 sage: R.basis() [2, 2*i] - sage: R = absolute_order_from_module_generators([k(1)], check_rank=False); R + sage: R = absolute_order_from_module_generators([k(1)], + ....: check_rank=False); R Order in Number Field in i with defining polynomial x^2 + 1 sage: R.basis() [1] @@ -2603,25 +2747,31 @@ def absolute_order_from_module_generators(gens, that, we will find that the rank is wrong or that the order is not closed under multiplication:: - sage: absolute_order_from_module_generators([1/2, i], check_integral=False) + sage: absolute_order_from_module_generators([1/2, i], + ....: check_integral=False) Traceback (most recent call last): ... ValueError: the module span of the gens is not closed under multiplication. - sage: R = absolute_order_from_module_generators([1/2, i], check_is_ring=False, check_integral=False); R + sage: R = absolute_order_from_module_generators([1/2, i], + ....: check_is_ring=False, + ....: check_integral=False); R Order in Number Field in i with defining polynomial x^2 + 1 sage: R.basis() [1/2, i] We turn off all check flags and make a really messed up order:: - sage: R = absolute_order_from_module_generators([1/2, i], check_is_ring=False, check_integral=False, check_rank=False); R + sage: R = absolute_order_from_module_generators([1/2, i], + ....: check_is_ring=False, + ....: check_integral=False, + ....: check_rank=False); R Order in Number Field in i with defining polynomial x^2 + 1 sage: R.basis() [1/2, i] An order that lives in a subfield:: - sage: F.<alpha> = NumberField(x**4+3) + sage: F.<alpha> = NumberField(x**4 + 3) sage: F.order([alpha**2], allow_subfield=True) Order in Number Field in beta with defining polynomial ... with beta = ... """ @@ -2682,12 +2832,12 @@ def relative_order_from_ring_generators(gens, INPUT: - ``gens`` -- list of integral elements of an absolute order. - - ``check_is_integral`` -- bool (default: True), whether to check that each + - ``check_is_integral`` -- bool (default: ``True``), whether to check that each generator is integral. - - ``check_rank`` -- bool (default: True), whether to check that the ring - generated by gens is of full rank. - - ``is_maximal`` -- bool (or None); set if maximality of the generated order is - known + - ``check_rank`` -- bool (default: ``True``), whether to check that the ring + generated by ``gens`` is of full rank. + - ``is_maximal`` -- bool (or ``None``); set if maximality of the generated order is + known. EXAMPLES: @@ -2695,10 +2845,12 @@ def relative_order_from_ring_generators(gens, for regular usage:: sage: from sage.rings.number_field.order import relative_order_from_ring_generators + sage: x = polygen(ZZ, 'x') sage: K.<i, a> = NumberField([x^2 + 1, x^2 - 17]) sage: R = K.base_field().maximal_order() sage: S = relative_order_from_ring_generators([i,a]); S - Relative Order in Number Field in i with defining polynomial x^2 + 1 over its base field + Relative Order in Number Field in i + with defining polynomial x^2 + 1 over its base field Basis for the relative order, which is obtained by computing the algebra generated by i and a:: @@ -2765,13 +2917,14 @@ def EisensteinIntegers(names="omega"): This is the ring of all complex numbers of the form `a + b \omega` with `a` and `b` integers and - `omega = (-1 + \sqrt{-3})/2`. + `\omega = (-1 + \sqrt{-3})/2`. EXAMPLES:: sage: R.<omega> = EisensteinIntegers() sage: R - Eisenstein Integers in Number Field in omega with defining polynomial x^2 + x + 1 with omega = -0.50000000000000000? + 0.866025403784439?*I + Eisenstein Integers in Number Field in omega with defining polynomial x^2 + x + 1 + with omega = -0.50000000000000000? + 0.866025403784439?*I sage: factor(3 + omega) (-1) * (-omega - 3) sage: CC(omega) diff --git a/src/sage/rings/number_field/selmer_group.py b/src/sage/rings/number_field/selmer_group.py index 487550ef4d5..37abe43101e 100644 --- a/src/sage/rings/number_field/selmer_group.py +++ b/src/sage/rings/number_field/selmer_group.py @@ -172,6 +172,7 @@ def _coords_in_C_mod_p(I,C,p): of which is not cyclic:: sage: from sage.rings.number_field.selmer_group import _coords_in_C_mod_p + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - x + 58) sage: C = K.class_group() sage: C.gens_orders() @@ -207,6 +208,7 @@ def _root_ideal(I, C, p): EXAMPLES:: sage: from sage.rings.number_field.selmer_group import _root_ideal + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - x + 58) sage: C = K.class_group() sage: cyclic_gens = C.gens_ideals() @@ -264,6 +266,7 @@ def coords_in_U_mod_p(u, U, p): EXAMPLES:: sage: from sage.rings.number_field.selmer_group import coords_in_U_mod_p + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 - 5*x^2 + 1) sage: U = K.unit_group() sage: U @@ -283,7 +286,7 @@ def coords_in_U_mod_p(u, U, p): """ coords = U.log(u) start = 1 - int(p.divides(U.zeta_order())) # 0 or 1 - return [c%p for c in coords[start:]] + return [c % p for c in coords[start:]] def basis_for_p_cokernel(S, C, p): r""" @@ -314,6 +317,7 @@ class is a ``p``'th power; EXAMPLES:: sage: from sage.rings.number_field.selmer_group import basis_for_p_cokernel + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - x + 58) sage: S = K.ideal(30).support(); S [Fractional ideal (2, a), @@ -353,23 +357,23 @@ class is a ``p``'th power; def pSelmerGroup(K, S, p, proof=None, debug=False): r""" - Return the ``p``-Selmer group `K(S,p)` of the number field ``K`` - with respect to the prime ideals in ``S`` + Return the `p`-Selmer group `K(S,p)` of the number field `K` + with respect to the prime ideals in ``S``. INPUT: - - ``K`` (number field) -- a number field, or `\QQ`. + - ``K`` -- a number field or `\QQ`. - - ``S`` (list) -- a list of prime ideals in ``K``, or prime - numbers when ``K`` is `\QQ`. + - ``S`` -- a list of prime ideals in `K`, or prime + numbers when `K` is `\QQ`. - - ``p`` (prime) -- a prime number. + - ``p`` -- a prime number. - - ``proof`` - if True then compute the class group provably - correctly. Default is True. Call :meth:`proof.number_field` to + - ``proof`` -- if ``True``, compute the class group provably + correctly. Default is ``True``. Call :meth:`proof.number_field` to change this default globally. - - ``debug`` (boolean, default ``False``) -- debug flag. + - ``debug`` -- (boolean, default ``False``) debug flag. OUTPUT: @@ -544,7 +548,7 @@ def pSelmerGroup(K, S, p, proof=None, debug=False): hK = 1 if K == QQ else K.class_number(proof=proof) C = K.class_group() if K == QQ else K.class_group(proof=proof) - hKp = (hK%p == 0) # flag whether the class number is divisible by p + hKp = (hK % p == 0) # flag whether the class number is divisible by p if K == QQ: if p == 2: @@ -680,7 +684,7 @@ def to_KSp(a): if debug: print("B={}".format(B)) - a3 = B if K==QQ else _ideal_generator(B) + a3 = B if K == QQ else _ideal_generator(B) if debug: print("a3={}".format(a3)) a /= a3 ** p @@ -695,7 +699,7 @@ def to_KSp(a): if debug: if K == QQ: - assert a.abs()==1 + assert a.abs() == 1 else: assert K.ideal(a).is_one() diff --git a/src/sage/rings/number_field/small_primes_of_degree_one.py b/src/sage/rings/number_field/small_primes_of_degree_one.py index facd5207a1c..b5cb57bb2df 100644 --- a/src/sage/rings/number_field/small_primes_of_degree_one.py +++ b/src/sage/rings/number_field/small_primes_of_degree_one.py @@ -108,17 +108,17 @@ class Small_primes_of_degree_one_iter(): INPUT: - - ``field`` -- a ``NumberField``. + - ``field`` -- a :class:`NumberField`. - - ``num_integer_primes`` (default: 10000) -- an integer. We try to find + - ``num_integer_primes`` -- (default: 10000) an integer. We try to find primes of absolute norm no greater than the ``num_integer_primes``-th prime number. For example, if ``num_integer_primes`` is 2, the largest norm found will be 3, since the second prime is 3. - - ``max_iterations`` (default: 100) -- an integer. We test + - ``max_iterations`` -- (default: 100) an integer. We test ``max_iterations`` integers to find small primes before raising - ``StopIteration``. + :class:`StopIteration`. AUTHOR: diff --git a/src/sage/rings/number_field/splitting_field.py b/src/sage/rings/number_field/splitting_field.py index 14871fecc05..927ecb3b5fb 100644 --- a/src/sage/rings/number_field/splitting_field.py +++ b/src/sage/rings/number_field/splitting_field.py @@ -20,8 +20,8 @@ from sage.rings.integer import Integer from sage.arith.misc import factorial -from sage.rings.number_field.all import NumberField -from sage.rings.polynomial.all import PolynomialRing +from sage.rings.number_field.number_field import NumberField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import RationalField, is_RationalField from sage.libs.pari.all import pari, PariError @@ -109,7 +109,7 @@ def __repr__(self): sage: print(SplittingData(pari("polcyclo(24)"), 2)) SplittingData(x^8 - x^4 + 1, 2) """ - return "SplittingData(%s, %s)"%(self.pol, self.dm) + return "SplittingData(%s, %s)" % (self.pol, self.dm) def _repr_tuple(self): """ @@ -164,7 +164,8 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = (x^3 + 2).splitting_field(); K - Number Field in a with defining polynomial x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1 + Number Field in a with defining polynomial + x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1 sage: K.<a> = (x^3 - 3*x + 1).splitting_field(); K Number Field in a with defining polynomial x^3 - 3*x + 1 @@ -175,11 +176,25 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No :: sage: (x^4 - x + 1).splitting_field('a', simplify=False) - Number Field in a with defining polynomial x^24 - 2780*x^22 + 2*x^21 + 3527512*x^20 - 2876*x^19 - 2701391985*x^18 + 945948*x^17 + 1390511639677*x^16 + 736757420*x^15 - 506816498313560*x^14 - 822702898220*x^13 + 134120588299548463*x^12 + 362240696528256*x^11 - 25964582366880639486*x^10 - 91743672243419990*x^9 + 3649429473447308439427*x^8 + 14310332927134072336*x^7 - 363192569823568746892571*x^6 - 1353403793640477725898*x^5 + 24293393281774560140427565*x^4 + 70673814899934142357628*x^3 - 980621447508959243128437933*x^2 - 1539841440617805445432660*x + 18065914012013502602456565991 + Number Field in a with defining polynomial + x^24 - 2780*x^22 + 2*x^21 + 3527512*x^20 - 2876*x^19 - 2701391985*x^18 + 945948*x^17 + + 1390511639677*x^16 + 736757420*x^15 - 506816498313560*x^14 - 822702898220*x^13 + + 134120588299548463*x^12 + 362240696528256*x^11 - 25964582366880639486*x^10 + - 91743672243419990*x^9 + 3649429473447308439427*x^8 + 14310332927134072336*x^7 + - 363192569823568746892571*x^6 - 1353403793640477725898*x^5 + + 24293393281774560140427565*x^4 + 70673814899934142357628*x^3 + - 980621447508959243128437933*x^2 - 1539841440617805445432660*x + + 18065914012013502602456565991 sage: (x^4 - x + 1).splitting_field('a', simplify=True) - Number Field in a with defining polynomial x^24 + 8*x^23 - 32*x^22 - 310*x^21 + 540*x^20 + 4688*x^19 - 6813*x^18 - 32380*x^17 + 49525*x^16 + 102460*x^15 - 129944*x^14 - 287884*x^13 + 372727*x^12 + 150624*x^11 - 110530*x^10 - 566926*x^9 + 1062759*x^8 - 779940*x^7 + 863493*x^6 - 1623578*x^5 + 1759513*x^4 - 955624*x^3 + 459975*x^2 - 141948*x + 53919 + Number Field in a with defining polynomial + x^24 + 8*x^23 - 32*x^22 - 310*x^21 + 540*x^20 + 4688*x^19 - 6813*x^18 - 32380*x^17 + + 49525*x^16 + 102460*x^15 - 129944*x^14 - 287884*x^13 + 372727*x^12 + 150624*x^11 + - 110530*x^10 - 566926*x^9 + 1062759*x^8 - 779940*x^7 + 863493*x^6 - 1623578*x^5 + + 1759513*x^4 - 955624*x^3 + 459975*x^2 - 141948*x + 53919 sage: (x^4 - x + 1).splitting_field('a', simplify_all=True) - Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 + Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 Reducible polynomials also work:: @@ -208,7 +223,10 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No sage: (x^4 - x + 1).splitting_field('a', simplify_all=True, map=True)[1] Ring morphism: From: Rational Field - To: Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 + To: Number Field in a with defining polynomial + x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 + - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 Defn: 1 |--> 1 We can enable verbose messages:: @@ -242,13 +260,22 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No Number Field in x with defining polynomial x^8 + 24*x^6 + 608*x^4 + 9792*x^2 + 53824 sage: C4pol = x^4 + x^3 + x^2 + x + 1 sage: C4pol.splitting_field('x') - Number Field in x with defining polynomial x^8 - x^7 - 2*x^6 + 5*x^5 + x^4 + 15*x^3 - 18*x^2 - 27*x + 81 + Number Field in x with defining polynomial + x^8 - x^7 - 2*x^6 + 5*x^5 + x^4 + 15*x^3 - 18*x^2 - 27*x + 81 sage: D8pol = x^4 - 2 sage: D8pol.splitting_field('x') - Number Field in x with defining polynomial x^16 + 8*x^15 + 68*x^14 + 336*x^13 + 1514*x^12 + 5080*x^11 + 14912*x^10 + 35048*x^9 + 64959*x^8 + 93416*x^7 + 88216*x^6 + 41608*x^5 - 25586*x^4 - 60048*x^3 - 16628*x^2 + 12008*x + 34961 + Number Field in x with defining polynomial + x^16 + 8*x^15 + 68*x^14 + 336*x^13 + 1514*x^12 + 5080*x^11 + 14912*x^10 + + 35048*x^9 + 64959*x^8 + 93416*x^7 + 88216*x^6 + 41608*x^5 - 25586*x^4 + - 60048*x^3 - 16628*x^2 + 12008*x + 34961 sage: A4pol = x^4 - 4*x^3 + 14*x^2 - 28*x + 21 sage: A4pol.splitting_field('x') - Number Field in x with defining polynomial x^24 - 20*x^23 + 290*x^22 - 3048*x^21 + 26147*x^20 - 186132*x^19 + 1130626*x^18 - 5913784*x^17 + 26899345*x^16 - 106792132*x^15 + 371066538*x^14 - 1127792656*x^13 + 2991524876*x^12 - 6888328132*x^11 + 13655960064*x^10 - 23000783036*x^9 + 32244796382*x^8 - 36347834476*x^7 + 30850889884*x^6 - 16707053128*x^5 + 1896946429*x^4 + 4832907884*x^3 - 3038258802*x^2 - 200383596*x + 593179173 + Number Field in x with defining polynomial + x^24 - 20*x^23 + 290*x^22 - 3048*x^21 + 26147*x^20 - 186132*x^19 + 1130626*x^18 + - 5913784*x^17 + 26899345*x^16 - 106792132*x^15 + 371066538*x^14 - 1127792656*x^13 + + 2991524876*x^12 - 6888328132*x^11 + 13655960064*x^10 - 23000783036*x^9 + + 32244796382*x^8 - 36347834476*x^7 + 30850889884*x^6 - 16707053128*x^5 + + 1896946429*x^4 + 4832907884*x^3 - 3038258802*x^2 - 200383596*x + 593179173 sage: S4pol = x^4 + x + 1 sage: S4pol.splitting_field('x') Number Field in x with defining polynomial x^48 ... @@ -256,9 +283,11 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No Some bigger examples:: sage: R.<x> = PolynomialRing(QQ) - sage: pol15 = chebyshev_T(31, x) - 1 # 2^30*(x-1)*minpoly(cos(2*pi/31))^2 - sage: pol15.splitting_field('a') - Number Field in a with defining polynomial x^15 - x^14 - 14*x^13 + 13*x^12 + 78*x^11 - 66*x^10 - 220*x^9 + 165*x^8 + 330*x^7 - 210*x^6 - 252*x^5 + 126*x^4 + 84*x^3 - 28*x^2 - 8*x + 1 + sage: pol15 = chebyshev_T(31, x) - 1 # 2^30*(x-1)*minpoly(cos(2*pi/31))^2 # needs sage.symbolic + sage: pol15.splitting_field('a') # needs sage.symbolic + Number Field in a with defining polynomial + x^15 - x^14 - 14*x^13 + 13*x^12 + 78*x^11 - 66*x^10 - 220*x^9 + 165*x^8 + + 330*x^7 - 210*x^6 - 252*x^5 + 126*x^4 + 84*x^3 - 28*x^2 - 8*x + 1 sage: pol48 = x^6 - 4*x^4 + 12*x^2 - 12 sage: pol48.splitting_field('a') Number Field in a with defining polynomial x^48 ... @@ -268,8 +297,10 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No computation, in particular for polynomials of degree >= 12 or for relative extensions:: - sage: pol15.splitting_field('a', degree_multiple=15) - Number Field in a with defining polynomial x^15 + x^14 - 14*x^13 - 13*x^12 + 78*x^11 + 66*x^10 - 220*x^9 - 165*x^8 + 330*x^7 + 210*x^6 - 252*x^5 - 126*x^4 + 84*x^3 + 28*x^2 - 8*x - 1 + sage: pol15.splitting_field('a', degree_multiple=15) # needs sage.symbolic + Number Field in a with defining polynomial + x^15 + x^14 - 14*x^13 - 13*x^12 + 78*x^11 + 66*x^10 - 220*x^9 - 165*x^8 + + 330*x^7 + 210*x^6 - 252*x^5 - 126*x^4 + 84*x^3 + 28*x^2 - 8*x - 1 A value for ``degree_multiple`` which isn't actually a multiple of the absolute degree of the splitting field can @@ -297,10 +328,14 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No Number Field in x with defining polynomial x^5 + x^4 - 4*x^3 - 3*x^2 + 3*x + 1 sage: D10pol = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1 sage: D10pol.splitting_field('x') - Number Field in x with defining polynomial x^10 - 28*x^8 + 216*x^6 - 681*x^4 + 902*x^2 - 401 + Number Field in x with defining polynomial + x^10 - 28*x^8 + 216*x^6 - 681*x^4 + 902*x^2 - 401 sage: AGL_1_5pol = x^5 - 2 sage: AGL_1_5pol.splitting_field('x') - Number Field in x with defining polynomial x^20 + 10*x^19 + 55*x^18 + 210*x^17 + 595*x^16 + 1300*x^15 + 2250*x^14 + 3130*x^13 + 3585*x^12 + 3500*x^11 + 2965*x^10 + 2250*x^9 + 1625*x^8 + 1150*x^7 + 750*x^6 + 400*x^5 + 275*x^4 + 100*x^3 + 75*x^2 + 25 + Number Field in x with defining polynomial + x^20 + 10*x^19 + 55*x^18 + 210*x^17 + 595*x^16 + 1300*x^15 + 2250*x^14 + + 3130*x^13 + 3585*x^12 + 3500*x^11 + 2965*x^10 + 2250*x^9 + 1625*x^8 + + 1150*x^7 + 750*x^6 + 400*x^5 + 275*x^4 + 100*x^3 + 75*x^2 + 25 sage: A5pol = x^5 - x^4 + 2*x^2 - 2*x + 2 sage: A5pol.splitting_field('x') Number Field in x with defining polynomial x^60 ... @@ -309,11 +344,11 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No fields of too large degree (this can be used to check whether the splitting field has small degree):: - sage: (x^5+x+3).splitting_field('b', abort_degree=119) + sage: (x^5 + x + 3).splitting_field('b', abort_degree=119) Traceback (most recent call last): ... SplittingFieldAbort: degree of splitting field equals 120 - sage: (x^10+x+3).splitting_field('b', abort_degree=60) # long time (10s on sage.math, 2014) + sage: (x^10 + x + 3).splitting_field('b', abort_degree=60) # long time (10s on sage.math, 2014) Traceback (most recent call last): ... SplittingFieldAbort: degree of splitting field is a multiple of 180 @@ -324,7 +359,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No sage: from sage.rings.number_field.splitting_field import SplittingFieldAbort sage: try: # long time (4s on sage.math, 2014) - ....: (x^8+x+1).splitting_field('b', abort_degree=60, simplify=False) + ....: (x^8 + x + 1).splitting_field('b', abort_degree=60, simplify=False) ....: except SplittingFieldAbort as e: ....: print(e.degree_divisor) ....: print(e.degree_multiple) @@ -340,7 +375,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No To: Number Field in x with defining polynomial x Defn: 1 |--> 1) """ - from sage.misc.misc import cputime + from sage.misc.timing import cputime from sage.misc.verbose import verbose degree_multiple = Integer(degree_multiple or 0) @@ -356,7 +391,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No # (only needed if map=True) if map: Fgen = F.gen().__pari__() - verbose("Starting field: %s"%Kpol) + verbose("Starting field: %s" % Kpol) # L and Lred are lists of SplittingData. # L contains polynomials which are irreducible over K, @@ -380,7 +415,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No raise SplittingFieldAbort(absolute_degree * rel_degree_divisor, degree_multiple) # First, factor polynomials in Lred and store the result in L - verbose("SplittingData to factor: %s"%[s._repr_tuple() for s in Lred]) + verbose("SplittingData to factor: %s" % [s._repr_tuple() for s in Lred]) t = cputime() for splitting in Lred: m = splitting.dm.gcd(degree_multiple).gcd(factorial(splitting.poldegree())) @@ -420,7 +455,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No # Compute cubic resolvent a0, a1, a2, a3, a4 = (q/q.pollead()).Vecrev() assert a4 == 1 - cubicpol = pari([4*a0*a2 - a1*a1 -a0*a3*a3, a1*a3 - 4*a0, -a2, 1]).Polrev() + cubicpol = pari([4*a0*a2 - a1*a1 - a0*a3*a3, a1*a3 - 4*a0, -a2, 1]).Polrev() cubicfactors = Kpol.nffactor(cubicpol)[0] if len(cubicfactors) == 1: # A4 or S4 # After adding a root of the cubic resolvent, @@ -470,8 +505,8 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No # Sort according to degree to handle low degrees first L.sort(key=lambda x: x.key()) - verbose("SplittingData to handle: %s"%[s._repr_tuple() for s in L]) - verbose("Bounds for absolute degree: [%s, %s]"%(degree_divisor,degree_multiple)) + verbose("SplittingData to handle: %s" % [s._repr_tuple() for s in L]) + verbose("Bounds for absolute degree: [%s, %s]" % (degree_divisor,degree_multiple)) # Check consistency if degree_multiple % degree_divisor != 0: @@ -490,7 +525,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No # Add a root of f = L[0] to construct the field N = K[x]/f(x) splitting = L[0] f = splitting.pol - verbose("Handling polynomial %s"%(f.lift()), level=2) + verbose("Handling polynomial %s" % (f.lift()), level=2) t = cputime() Npol, KtoN, k = Kpol.rnfequation(f, flag=1) @@ -512,7 +547,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No if simplify_all or (simplify and not finished): # Find a simpler defining polynomial Lpol for Mpol - verbose("New field before simplifying: %s"%Mpol, t) + verbose("New field before simplifying: %s" % Mpol, t) t = cputime() M = Mpol.polred(flag=3) n = len(M[0])-1 @@ -527,7 +562,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No NtoL = MtoL/Mdiv KtoL = KtoN.lift().subst("x", NtoL).Mod(Lpol) Kpol = Lpol # New Kpol (for next iteration) - verbose("New field: %s"%Kpol, t) + verbose("New field: %s" % Kpol, t) if map: t = cputime() Fgen = Fgen.lift().subst("y", KtoL) diff --git a/src/sage/rings/number_field/structure.py b/src/sage/rings/number_field/structure.py index f933affe775..ee699716638 100644 --- a/src/sage/rings/number_field/structure.py +++ b/src/sage/rings/number_field/structure.py @@ -14,8 +14,10 @@ identical because `M` carries additional information:: sage: L.structure() - (Identity endomorphism of Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?, - Identity endomorphism of Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?) + (Identity endomorphism of + Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?, + Identity endomorphism of + Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?) sage: M.structure() (Isomorphism given by variable name change map: From: Number Field in a with defining polynomial x^2 - 2 @@ -26,7 +28,7 @@ This used to cause trouble with caching and made (absolute) number fields not unique when they should have been. The underlying technical problem is that the -morphisms returned by ``structure()`` can only be defined once the fields in +morphisms returned by :meth:`structure` can only be defined once the fields in question have been created. Therefore, these morphisms cannot be part of a key which uniquely identifies a number field. @@ -72,7 +74,8 @@ class NumberFieldStructure(UniqueRepresentation): True sage: R.<x> = QQ[] - sage: K.<i> = NumberField(x^2+1) + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) sage: L = K.change_names('j').change_names('i') sage: K is L # K and L differ in "structure", one is the "name-change" of the other False @@ -81,8 +84,8 @@ class NumberFieldStructure(UniqueRepresentation): sage: NumberFieldStructure(K) is NumberFieldStructure(L) False sage: from sage.rings.number_field.structure import NameChange - sage: KK.<j> = NumberField(x^2+1, structure=NameChange(K)) - sage: LL.<j> = NumberField(x^2+1, structure=NameChange(L)) + sage: KK.<j> = NumberField(x^2 + 1, structure=NameChange(K)) + sage: LL.<j> = NumberField(x^2 + 1, structure=NameChange(L)) sage: KK is LL False @@ -151,9 +154,10 @@ class NameChange(NumberFieldStructure): sage: NameChange(K) <sage.rings.number_field.structure.NameChange object at 0x...> - Check for memory leaks: + Check for memory leaks:: - sage: u=id(NumberField(x^2-5,'a').absolute_field('b')) + sage: x = polygen(ZZ, 'x') + sage: u = id(NumberField(x^2 - 5,'a').absolute_field('b')) sage: import gc sage: gc.collect() #random 10 diff --git a/src/sage/rings/number_field/totallyreal.pyx b/src/sage/rings/number_field/totallyreal.pyx index ecb8236260c..87ae68a4d59 100644 --- a/src/sage/rings/number_field/totallyreal.pyx +++ b/src/sage/rings/number_field/totallyreal.pyx @@ -45,7 +45,8 @@ fields of discriminant `\le 50`. [40, x^2 - 10], [41, x^2 - x - 10], [44, x^2 - 11]] - sage: [ d for d in range(5,50) if (is_squarefree(d) and d%4 == 1) or (d%4 == 0 and is_squarefree(d/4)) ] + sage: [d for d in range(5,50) + ....: if (is_squarefree(d) and d%4 == 1) or (d%4 == 0 and is_squarefree(d/4))] [5, 8, 12, 13, 17, 20, 21, 24, 28, 29, 33, 37, 40, 41, 44] Next, we compute all totally real quintic fields of discriminant `\le 10^5`:: @@ -81,15 +82,15 @@ Authors ------ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 William Stein and John Voight # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.memory cimport check_calloc, sig_free @@ -104,10 +105,8 @@ from sage.libs.pari.misc cimport new_t_POL_from_int_star from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer from sage.rings.integer cimport Integer -from sage.rings.integer_ring import IntegerRing from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.misc.misc import cputime from sage.rings.number_field.totallyreal_data import tr_data, int_has_small_square_divisor from sage.rings.number_field.totallyreal_data cimport tr_data @@ -116,15 +115,15 @@ from sage.rings.number_field.totallyreal_data cimport tr_data cpdef double odlyzko_bound_totallyreal(int n): r""" This function returns the unconditional Odlyzko bound for the root - discriminant of a totally real number field of degree n. + discriminant of a totally real number field of degree `n`. .. NOTE:: - The bounds for n > 50 are not necessarily optimal. + The bounds for `n > 50` are not necessarily optimal. INPUT: - - n (integer) the degree + - ``n`` -- (integer) the degree OUTPUT: @@ -132,7 +131,8 @@ cpdef double odlyzko_bound_totallyreal(int n): EXAMPLES:: - sage: [sage.rings.number_field.totallyreal.odlyzko_bound_totallyreal(n) for n in range(1,5)] + sage: from sage.rings.number_field.totallyreal import odlyzko_bound_totallyreal + sage: [odlyzko_bound_totallyreal(n) for n in range(1, 5)] [1.0, 2.223, 3.61, 5.067] AUTHORS: @@ -164,7 +164,7 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False just_print=False, return_pari_objects=True): r""" - This function enumerates primitive totally real fields of degree + Enumerate primitive totally real fields of degree `n>1` with discriminant `d \leq B`; optionally one can specify the first few coefficients, where the sequence `a` corresponds to @@ -183,26 +183,26 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False - ``n`` -- (integer) the degree - ``B`` -- (integer) the discriminant bound - - ``a`` -- (list, default: []) the coefficient list to begin with + - ``a`` -- (list, default: ``[]``) the coefficient list to begin with - ``verbose`` -- (integer or string, default: 0) if ``verbose == 1`` (or ``2``), then print to the screen (really) verbosely; if verbose is a string, then print verbosely to the file specified by verbose. - - ``return_seqs`` -- (boolean, default False) If ``True``, then return + - ``return_seqs`` -- (boolean, default ``False``) If ``True``, then return the polynomials as sequences (for easier exporting to a file). - - ``phc`` -- boolean or integer (default: False) - - ``keep_fields`` -- (boolean or integer, default: False) If - ``keep_fields`` is True, then keep fields up to ``B*log(B)``; if + - ``phc`` -- boolean or integer (default: ``False``) + - ``keep_fields`` -- (boolean or integer, default: ``False``) If + ``keep_fields`` is ``True``, then keep fields up to ``B*log(B)``; if ``keep_fields`` is an integer, then keep fields up to that integer. - ``t_2`` -- (boolean or integer, default: False) If ``t_2 = T``, then keep only polynomials with t_2 norm >= T. - - ``just_print`` -- (boolean, default: False): if ``just_print`` is not - False, instead of creating a sorted list of totally real number + - ``just_print`` -- (boolean, default: ``False``): if ``just_print`` is not + ``False``, instead of creating a sorted list of totally real number fields, we simply write each totally real field we find to the file whose filename is given by ``just_print``. In this case, we don't return anything. - - ``return_pari_objects`` -- (boolean, default: True) if + - ``return_pari_objects`` -- (boolean, default: ``True``) if both ``return_seqs`` and ``return_pari_objects`` are ``False`` then - it returns the elements as Sage objects; otherwise it returns pari + it returns the elements as Sage objects; otherwise it returns PARI objects. OUTPUT: @@ -256,7 +256,6 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False cdef Py_ssize_t k0, lenS cdef tr_data T cdef Integer dB - cdef double db_odlyzko if not isinstance(n, Integer): try: @@ -280,7 +279,6 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False t2val = B_pari ngt2 = B_pari ng = B_pari - pari_tmp1 = B_pari dB = Integer.__new__(Integer) dB_odlyzko = odlyzko_bound_totallyreal(n_int) @@ -294,7 +292,7 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False f_out[n_int] = 1 if keep_fields: - if type(keep_fields) == bool: + if isinstance(keep_fields, bool): keepB = pari(int(math.floor(B*math.log(B)))) else: keepB = pari(keep_fields) @@ -339,7 +337,7 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False if verbose: verb_int = 1 saveout = sys.stdout - if type(verbose) == str: + if isinstance(verbose, str): fsock = open(verbose, 'w') sys.stdout = fsock # Else, print to screen @@ -460,7 +458,7 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False print("Polynomials with nfdisc <= B:", counts[3]) for i from 0 <= i < lenS: print(S[i]) - if type(verbose) == str: + if isinstance(verbose, str): fsock.close() sys.stdout = saveout @@ -479,7 +477,7 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False def weed_fields(S, Py_ssize_t lenS=0): r""" Function used internally by the :func:`~enumerate_totallyreal_fields_prim` - routine. (Weeds the fields listed by [discriminant, polynomial] + routine. (Weeds the fields listed by ``[discriminant, polynomial]`` for isomorphism classes.) Returns the size of the resulting list. EXAMPLES:: diff --git a/src/sage/rings/number_field/totallyreal_data.pyx b/src/sage/rings/number_field/totallyreal_data.pyx index adc52e6cfab..84e292f79b2 100644 --- a/src/sage/rings/number_field/totallyreal_data.pyx +++ b/src/sage/rings/number_field/totallyreal_data.pyx @@ -30,9 +30,7 @@ from cysignals.memory cimport sig_malloc, sig_free from sage.arith.misc import binomial from sage.arith.misc import GCD as gcd from sage.libs.gmp.mpz cimport * -from sage.rings.rational_field import RationalField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.real_mpfi import RealIntervalField from sage.rings.real_mpfr import RealField from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer @@ -51,9 +49,9 @@ from libc.math cimport lrint, floor, ceil, fabs, round def hermite_constant(n): r""" - This function returns the nth Hermite constant + Return the `n`-th Hermite constant. - The nth Hermite constant (typically denoted `\gamma_n`), is defined + The `n`-th Hermite constant (typically denoted `\gamma_n`), is defined to be .. MATH:: @@ -67,11 +65,11 @@ def hermite_constant(n): INPUT: - - n -- integer + - ``n`` -- integer OUTPUT: - - (an upper bound for) the Hermite constant gamma_n + (an upper bound for) the Hermite constant `\gamma_n` EXAMPLES:: @@ -122,13 +120,13 @@ cdef double eval_seq_as_poly(int *f, int n, double x): f[n]*x^n + f[n-1]*x^(n-1) + ... + f[0]. """ - cdef double s, xp + cdef double s # Horner's method: With polynomials of small degree, we shouldn't # expect asymptotic methods to be any faster. s = f[n] for i from n > i >= 0: - s = s*x+f[i] + s = s * x + f[i] return s cdef double newton(int *f, int *df, int n, double x0, double eps): @@ -197,12 +195,14 @@ cdef void newton_in_intervals(int *f, int *df, int n, double *beta, cpdef lagrange_degree_3(int n, int an1, int an2, int an3): r""" Private function. Solves the equations which arise in the Lagrange multiplier - for degree 3: for each 1 <= r <= n-2, we solve + for degree 3: for each `1 \leq r \leq n-2`, we solve - r*x^i + (n-1-r)*y^i + z^i = s_i (i = 1,2,3) + .. MATH:: + + r*x^i + (n-1-r)\cdot y^i + z^i = s_i \quad (i = 1,2,3) - where the s_i are the power sums determined by the coefficients a. - We output the largest value of z which occurs. + where the `s_i` are the power sums determined by the coefficients `a`. + We output the largest value of `z` which occurs. We use a precomputed elimination ideal. EXAMPLES:: @@ -220,13 +220,10 @@ cpdef lagrange_degree_3(int n, int an1, int an2, int an3): sage: sage.rings.number_field.totallyreal_data.lagrange_degree_3(4,12,19,42) [0.0, -1.0] """ - cdef double zmin, zmax, val - cdef double *roots_data cdef long coeffs[7] cdef int r, rsq, rcu cdef int nr, nrsq, nrcu cdef int s1, s1sq, s1cu, s1fo, s2, s2sq, s2cu, s3, s3sq - cdef int found_minmax = 0 RRx = PolynomialRing(RealField(20),'x') @@ -323,7 +320,7 @@ for i from 0 <= i < 46: def int_has_small_square_divisor(sage.rings.integer.Integer d): r""" - Returns the largest a such that a^2 divides d and a has prime divisors < 200. + Return the largest `a` such that `a^2` divides `d` and `a` has prime divisors `< 200`. EXAMPLES:: @@ -357,11 +354,11 @@ cdef int eval_seq_as_poly_int(int *f, int n, int x): f[n]*x^n + f[n-1]*x^(n-1) + ... + f[0]. """ - cdef int s, xp + cdef int s s = f[n] for i from n > i >= 0: - s = s*x+f[i] + s = s * x + f[i] return s cdef double eps_abs, phi, sqrt2 @@ -374,7 +371,7 @@ cdef int easy_is_irreducible(int *a, int n): Very often, polynomials have roots in {+/-1, +/-2, +/-phi, sqrt2}, so we rule these out quickly. Returns 0 if reducible, 1 if inconclusive. """ - cdef int s, t, st, sgn, i + cdef int s, t, st, i # Check if a has a root in {1,-1,2,-2}. if eval_seq_as_poly_int(a,n,1) == 0 or eval_seq_as_poly_int(a,n,-1) == 0 or eval_seq_as_poly_int(a,n,2) == 0 or eval_seq_as_poly_int(a,n,-2) == 0: @@ -452,7 +449,7 @@ cdef class tr_data: We do not give a complete description here. For more information, see the attached functions; all of these are used internally by the - functions in totallyreal.py, so see that file for examples and + functions in :mod:`.totallyreal`, so see that file for examples and further documentation. """ @@ -584,9 +581,9 @@ cdef class tr_data: def increment(self, verbose=False, haltk=0, phc=False): r""" - This function 'increments' the totally real data to the next + 'Increment' the totally real data to the next value which satisfies the bounds essentially given by Rolle's - theorem, and returns the next polynomial as a sequence of + theorem, and return the next polynomial as a sequence of integers. The default or usual case just increments the constant @@ -598,10 +595,10 @@ cdef class tr_data: INPUT: - - verbose -- boolean to print verbosely computational details - - haltk -- integer, the level at which to halt the inductive + - ``verbose`` -- boolean to print verbosely computational details + - ``haltk`` -- integer, the level at which to halt the inductive coefficient bounds - - phc -- boolean, if PHCPACK is available, use it when k == n-5 to + - ``phc`` -- boolean, if PHCPACK is available, use it when `k = n-5` to compute an improved Lagrange multiplier bound OUTPUT: @@ -666,8 +663,7 @@ cdef class tr_data: None. The return value is stored in the variable f_out. """ - - cdef int n, np1, k, i, j, nk, kz + cdef int n, np1, k, i, nk, kz cdef int *gnkm cdef int *gnkm1 cdef double *betak @@ -912,7 +908,7 @@ cdef class tr_data: def printa(self): """ - Print relevant data for self. + Print relevant data for ``self``. EXAMPLES:: diff --git a/src/sage/rings/number_field/totallyreal_phc.py b/src/sage/rings/number_field/totallyreal_phc.py index 59467e5af40..4143feb67b3 100644 --- a/src/sage/rings/number_field/totallyreal_phc.py +++ b/src/sage/rings/number_field/totallyreal_phc.py @@ -3,8 +3,7 @@ AUTHORS: - -- John Voight (2007-10-10): - * Zeroth attempt. +- John Voight (2007-10-10): Zeroth attempt. """ # **************************************************************************** @@ -23,14 +22,14 @@ def coefficients_to_power_sums(n, m, a): r""" - Takes the list a, representing a list of initial coefficients of - a (monic) polynomial of degree n, and returns the power sums - of the roots of f up to (m-1)th powers. + Take the list ``a``, representing a list of initial coefficients of + a (monic) polynomial of degree `n`, and return the power sums + of the roots of `f` up to `(m-1)`-th powers. INPUT: - - n -- integer, the degree - - a -- list of integers, the coefficients + - ``n`` -- integer, the degree + - ``a`` -- list of integers, the coefficients OUTPUT: @@ -87,15 +86,16 @@ def __lagrange_bounds_phc(n, m, a, tmpfile=None): EXAMPLES:: + sage: # optional - phc sage: from sage.rings.number_field.totallyreal_phc import __lagrange_bounds_phc - sage: __lagrange_bounds_phc(3,5,[8,1,2,0,1]) # optional - phc + sage: __lagrange_bounds_phc(3,5,[8,1,2,0,1]) [] - sage: x, y = __lagrange_bounds_phc(3,2,[8,1,2,0,1]) # optional - phc - sage: x # optional - phc + sage: x, y = __lagrange_bounds_phc(3,2,[8,1,2,0,1]) + sage: x -1.3333333333333299 - sage: y < 0.00000001 # optional - phc + sage: y < 0.00000001 True - sage: __lagrange_bounds_phc(3,1,[8,1,2,0,1]) # optional - phc + sage: __lagrange_bounds_phc(3,1,[8,1,2,0,1]) [] """ @@ -126,12 +126,12 @@ def __lagrange_bounds_phc(n, m, a, tmpfile=None): for P in sage.combinat.partition.Partitions(n-1,length=m-1): f = open(tmpfile, 'w') # First line: number of variables/equations - f.write('%d'%m + '\n') + f.write('%d' % m + '\n') # In the next m-1 lines, write the equation S_j(x) = S[j] for j in range(1,m+1): for i in range(m-1): - f.write('%d'%P[i] + '*x%d'%i + '**%d'%j + ' + ') - f.write('xn**%d'%j + ' - (%d'%S[j] + ');\n') + f.write('%d' % P[i] + '*x%d' % i + '**%d' % j + ' + ') + f.write('xn**%d' % j + ' - (%d' % S[j] + ');\n') f.close() os.remove(tmpfile + '.phc') diff --git a/src/sage/rings/number_field/totallyreal_rel.py b/src/sage/rings/number_field/totallyreal_rel.py index 07477c46f8f..d7039c26c86 100644 --- a/src/sage/rings/number_field/totallyreal_rel.py +++ b/src/sage/rings/number_field/totallyreal_rel.py @@ -12,8 +12,8 @@ :: - sage: ZZx = ZZ['x'] - sage: F.<t> = NumberField(x^2-2) + sage: ZZx.<x> = ZZ[] + sage: F.<t> = NumberField(x^2 - 2) sage: enumerate_totallyreal_fields_rel(F, 2, 2000) [[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]] @@ -24,7 +24,7 @@ :: - sage: F.<t> = NumberField(x^2-5) + sage: F.<t> = NumberField(x^2 - 5) sage: ls = enumerate_totallyreal_fields_rel(F, 2, 10^4) sage: ls # random (the second factor is platform-dependent) [[725, x^4 - x^3 - 3*x^2 + x + 1, xF^2 + (-1/2*t - 7/2)*xF + 1], @@ -111,30 +111,32 @@ def integral_elements_in_box(K, C): r""" Return all integral elements of the totally real field `K` whose embeddings lie *numerically* within the bounds specified by the - list `C`. The output is architecture dependent, and one may want - to expand the bounds that define C by some epsilon. + list ``C``. The output is architecture dependent, and one may want + to expand the bounds that define ``C`` by some epsilon. INPUT: - - `K` -- a totally real number field - - `C` -- a list [[lower, upper], ...] of lower and upper bounds, + - ``K`` -- a totally real number field + - ``C`` -- a list ``[[lower, upper], ...]`` of lower and upper bounds, for each embedding EXAMPLES:: sage: x = polygen(QQ) - sage: K.<alpha> = NumberField(x^2-2) + sage: K.<alpha> = NumberField(x^2 - 2) sage: eps = 10e-6 - sage: C = [[0-eps,5+eps],[0-eps,10+eps]] + sage: C = [[0-eps, 5+eps], [0-eps, 10+eps]] sage: ls = sage.rings.number_field.totallyreal_rel.integral_elements_in_box(K, C) - sage: sorted([ a.trace() for a in ls ]) + sage: sorted(a.trace() for a in ls) [0, 2, 4, 4, 4, 6, 6, 6, 6, 8, 8, 8, 10, 10, 10, 10, 12, 12, 14] sage: len(ls) 19 sage: v = sage.rings.number_field.totallyreal_rel.integral_elements_in_box(K, C) sage: sorted(v) - [0, -alpha + 2, 1, -alpha + 3, 2, 3, alpha + 2, 4, alpha + 3, 5, alpha + 4, 2*alpha + 3, alpha + 5, 2*alpha + 4, alpha + 6, 2*alpha + 5, 2*alpha + 6, 3*alpha + 5, 2*alpha + 7] + [0, -alpha + 2, 1, -alpha + 3, 2, 3, alpha + 2, 4, alpha + 3, 5, alpha + 4, + 2*alpha + 3, alpha + 5, 2*alpha + 4, alpha + 6, 2*alpha + 5, 2*alpha + 6, + 3*alpha + 5, 2*alpha + 7] A cubic field:: @@ -148,7 +150,8 @@ def integral_elements_in_box(K, C): below, and sometimes it isn't):: sage: sorted(v) - [-1/2*a + 2, 1/4*a^2 + 1/2*a, 0, 1, 2, 3, 4,...-1/4*a^2 - 1/2*a + 5, 1/2*a + 3, -1/4*a^2 + 5] + [-1/2*a + 2, 1/4*a^2 + 1/2*a, 0, 1, 2, 3, 4,...-1/4*a^2 - 1/2*a + 5, + 1/2*a + 3, -1/4*a^2 + 5] """ d = K.degree() Foo = K.real_embeddings() @@ -243,18 +246,19 @@ def __init__(self, F, m, B, a=None): - ``F`` -- number field, the base field - ``m`` -- integer, the relative degree - ``B`` -- integer, the discriminant bound - - ``a`` -- list (default: []), the coefficient list to begin with, + - ``a`` -- list (default: ``[]``), the coefficient list to begin with, corresponding to ``a[len(a)]*x^n + ... + a[0]x^(n-len(a))``. OUTPUT: the data initialized to begin enumeration of totally real fields - with base field F, degree n, discriminant bounded by B, and starting - with coefficients a. + with base field `F`, degree `n`, discriminant bounded by `B`, and starting + with coefficients `a`. EXAMPLES:: - sage: F.<t> = NumberField(x^2-2) + sage: x = polygen(ZZ, 'x') + sage: F.<t> = NumberField(x^2 - 2) sage: T = sage.rings.number_field.totallyreal_rel.tr_data_rel(F, 2, 2000) """ if a is None: # don't make the stupid noob mistake of putting a=[] @@ -296,7 +300,7 @@ def __init__(self, F, m, B, a=None): import numpy for i in range(len(anm1s)): Q = [[v(m*x) for v in self.Foo] + [0] for x in Z_Fbasis] + [[v(anm1s[i]) for v in self.Foo] + [10**6]] - pari_string = '['+';'.join([','.join(["%s"%ii for ii in row]) for row in zip(*Q)])+']' + pari_string = '['+';'.join([','.join(["%s" % ii for ii in row]) for row in zip(*Q)])+']' adj = pari(pari_string).qflll()[self.d] anm1s[i] += sum([m*Z_Fbasis[ii]*int(adj[ii])//int(adj[self.d]) for ii in range(self.d)]) @@ -318,7 +322,7 @@ def __init__(self, F, m, B, a=None): # currently unknown; e.g., if k == -1, then we can iterate # over polynomials, and if k == n-1, then we have finished iterating. if a[len(a)-1] != 1: - raise ValueError("a[len(a)-1](=%s) must be 1 so polynomial is monic"%a[len(a)-1]) + raise ValueError("a[len(a)-1](=%s) must be 1 so polynomial is monic" % a[len(a)-1]) raise NotImplementedError("These have not been checked.") @@ -352,10 +356,10 @@ def __init__(self, F, m, B, a=None): def incr(self, f_out, verbose=False, haltk=0): r""" - This function 'increments' the totally real data to the next + 'Increment' the totally real data to the next value which satisfies the bounds essentially given by Rolle's - theorem, and returns the next polynomial in the sequence - f_out. + theorem, and return the next polynomial in the sequence + ``f_out``. The default or usual case just increments the constant coefficient; then inductively, if this is outside of the @@ -368,7 +372,7 @@ def incr(self, f_out, verbose=False, haltk=0): - ``f_out`` -- an integer sequence, to be written with the coefficients of the next polynomial - - ``verbose`` -- boolean or nonnegative integer (default: False) + - ``verbose`` -- boolean or nonnegative integer (default: ``False``) print verbosely computational details. It prints extra information if ``verbose`` is set to ``2`` or more - ``haltk`` -- integer, the level at which to halt the inductive @@ -662,26 +666,26 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, - ``F`` -- number field, the base field - ``m`` -- integer, the degree - ``B`` -- integer, the discriminant bound - - ``a`` -- list (default: []), the coefficient list to begin with + - ``a`` -- list (default: ``[]``), the coefficient list to begin with - ``verbose`` -- boolean or nonnegative integer or string (default: 0) give a verbose description of the computations being performed. If ``verbose`` is set to ``2`` or more then it outputs some extra information. If ``verbose`` is a string then it outputs to a file specified by ``verbose`` - - ``return_seqs`` -- (boolean, default False) If ``True``, then return + - ``return_seqs`` -- (boolean, default ``False``) If ``True``, then return the polynomials as sequences (for easier exporting to a file). This also returns a list of four numbers, as explained in the OUTPUT section below. - - ``return_pari_objects`` -- (boolean, default: True) if + - ``return_pari_objects`` -- (boolean, default: ``True``) if both ``return_seqs`` and ``return_pari_objects`` are ``False`` then - it returns the elements as Sage objects; otherwise it returns pari + it returns the elements as Sage objects; otherwise it returns PARI objects. OUTPUT: - the list of fields with entries ``[d,fabs,f]``, where ``d`` is the discriminant, ``fabs`` is an absolute defining polynomial, and ``f`` - is a defining polynomial relative to ``F``, sorted by discriminant. + is a defining polynomial relative to `F`, sorted by discriminant. - if ``return_seqs`` is ``True``, then the first field of the list is a list containing the count of four items as explained below @@ -691,12 +695,12 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, discriminant having a large enough square divisor - the third entry is the number of irreducible polynomials - the fourth entry is the number of irreducible polynomials with - discriminant at most ``B`` + discriminant at most `B` EXAMPLES:: - sage: ZZx = ZZ['x'] - sage: F.<t> = NumberField(x^2-2) + sage: ZZx.<x> = ZZ[] + sage: F.<t> = NumberField(x^2 - 2) sage: enumerate_totallyreal_fields_rel(F, 1, 2000) [[1, [-2, 0, 1], xF - 1]] sage: enumerate_totallyreal_fields_rel(F, 2, 2000) @@ -902,7 +906,7 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False, return_pari_objects=True): r""" - Enumerates *all* totally real fields of degree ``n`` with discriminant + Enumerate *all* totally real fields of degree ``n`` with discriminant at most ``B``, primitive or otherwise. INPUT: @@ -911,16 +915,16 @@ def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False, - ``B`` -- integer, the discriminant bound - ``verbose`` -- boolean or nonnegative integer or string (default: 0) give a verbose description of the computations being performed. If - ``verbose`` is set to ``2`` or more then it outputs some extra - information. If ``verbose`` is a string then it outputs to a file + ``verbose`` is set to ``2`` or more, it outputs some extra + information. If ``verbose`` is a string, it outputs to a file specified by ``verbose`` - - ``return_seqs`` -- (boolean, default False) If ``True``, then return + - ``return_seqs`` -- (boolean, default ``False``) If ``True``, then return the polynomials as sequences (for easier exporting to a file). This also returns a list of four numbers, as explained in the OUTPUT section below. - ``return_pari_objects`` -- (boolean, default: True) if both ``return_seqs`` and ``return_pari_objects`` are ``False`` then it - returns the elements as Sage objects; otherwise it returns pari + returns the elements as Sage objects; otherwise it returns PARI objects. EXAMPLES:: diff --git a/src/sage/rings/number_field/unit_group.py b/src/sage/rings/number_field/unit_group.py index d8f9b7a9c2f..5f9d5c0654c 100644 --- a/src/sage/rings/number_field/unit_group.py +++ b/src/sage/rings/number_field/unit_group.py @@ -4,9 +4,10 @@ EXAMPLES:: sage: x = polygen(QQ) - sage: K.<a> = NumberField(x^4-8*x^2+36) + sage: K.<a> = NumberField(x^4 - 8*x^2 + 36) sage: UK = UnitGroup(K); UK - Unit group with structure C4 x Z of Number Field in a with defining polynomial x^4 - 8*x^2 + 36 + Unit group with structure C4 x Z of + Number Field in a with defining polynomial x^4 - 8*x^2 + 36 The first generator is a primitive root of unity in the field:: @@ -36,12 +37,12 @@ 1 sage: UK(-1) u0^2 - sage: [UK(u) for u in (x^4-1).roots(K, multiplicities=False)] + sage: [UK(u) for u in (x^4 - 1).roots(K, multiplicities=False)] [1, u0^2, u0, u0^3] sage: UK.fundamental_units() # random [1/24*a^3 + 1/4*a^2 - 1/12*a - 1] - sage: torsion_gen = UK.torsion_generator(); torsion_gen + sage: torsion_gen = UK.torsion_generator(); torsion_gen u0 sage: torsion_gen.value() 1/12*a^3 - 1/6*a @@ -63,20 +64,22 @@ sage: all(UK.log(u^k) == (0,k) for k in range(10)) True - sage: K.<a> = NumberField(x^5-2,'a') + sage: K.<a> = NumberField(x^5 - 2,'a') sage: UK = UnitGroup(K) sage: UK.rank() 2 sage: UK.fundamental_units() [a^3 + a^2 - 1, a - 1] -S-unit groups may be constructed, where S is a set of primes:: +`S`-unit groups may be constructed, where `S` is a set of primes:: - sage: K.<a> = NumberField(x^6+2) + sage: K.<a> = NumberField(x^6 + 2) sage: S = K.ideal(3).prime_factors(); S [Fractional ideal (3, a + 1), Fractional ideal (3, a - 1)] sage: SUK = UnitGroup(K,S=tuple(S)); SUK - S-unit group with structure C2 x Z x Z x Z x Z of Number Field in a with defining polynomial x^6 + 2 with S = (Fractional ideal (3, a + 1), Fractional ideal (3, a - 1)) + S-unit group with structure C2 x Z x Z x Z x Z of + Number Field in a with defining polynomial x^6 + 2 + with S = (Fractional ideal (3, a + 1), Fractional ideal (3, a - 1)) sage: SUK.primes() (Fractional ideal (3, a + 1), Fractional ideal (3, a - 1)) sage: SUK.rank() @@ -94,7 +97,8 @@ sage: L.<a, b> = NumberField([x^2 + x + 1, x^4 + 1]) sage: UL = L.unit_group(); UL - Unit group with structure C24 x Z x Z x Z of Number Field in a with defining polynomial x^2 + x + 1 over its base field + Unit group with structure C24 x Z x Z x Z of + Number Field in a with defining polynomial x^2 + x + 1 over its base field sage: UL.gens_values() # random [-b^3*a - b^3, -b^3*a + b, (-b^3 - b^2 - b)*a - b - 1, (-b^3 - 1)*a - b^2 + b - 1] sage: UL.zeta_order() @@ -132,7 +136,8 @@ sage: PF.<Y> = F[] sage: K.<c> = F.extension(Y^2 - (1 + a)*(a + b)*a*b) sage: K.unit_group() - Unit group with structure C2 x Z x Z x Z x Z x Z x Z x Z of Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Unit group with structure C2 x Z x Z x Z x Z x Z x Z x Z of Number Field in c + with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field TESTS:: @@ -169,7 +174,7 @@ class UnitGroup(AbelianGroupWithValues_class): """ - The unit group or an S-unit group of a number field. + The unit group or an `S`-unit group of a number field. TESTS:: @@ -229,17 +234,17 @@ def __init__(self, number_field, proof=True, S=None): INPUT: - - ``number_field`` - a number field - - ``proof`` - boolean (default True): proof flag - - ``S`` - tuple of prime ideals, or an ideal, or a single + - ``number_field`` -- a number field + - ``proof`` -- boolean (default ``True``): proof flag + - ``S`` -- tuple of prime ideals, or an ideal, or a single ideal or element from which an ideal can be constructed, in - which case the support is used. If None, the global unit - group is constructed; otherwise, the S-unit group is + which case the support is used. If ``None``, the global unit + group is constructed; otherwise, the `S`-unit group is constructed. - The proof flag is passed to pari via the ``pari_bnf()`` function + The ``proof`` flag is passed to PARI via the :pari:`pari_bnf` function which computes the unit group. See the documentation for the - number_field module. + ``number_field`` module. EXAMPLES:: @@ -268,7 +273,8 @@ def __init__(self, number_field, proof=True, S=None): sage: UK.gens_values() # random [-z^11, z^5 + z^3, z^6 + z^5, z^9 + z^7 + z^5, z^9 + z^5 + z^4 + 1, z^5 + z] sage: SUK = UnitGroup(K,S=2); SUK - S-unit group with structure C26 x Z x Z x Z x Z x Z x Z of Cyclotomic Field of order 13 and degree 12 with S = (Fractional ideal (2),) + S-unit group with structure C26 x Z x Z x Z x Z x Z x Z of + Cyclotomic Field of order 13 and degree 12 with S = (Fractional ideal (2),) TESTS: @@ -278,9 +284,12 @@ def __init__(self, number_field, proof=True, S=None): sage: K.<a> = NumberField(7/9*x^3 + 7/3*x^2 - 56*x + 123) sage: K.unit_group() - Unit group with structure C2 x Z x Z of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 + Unit group with structure C2 x Z x Z of + Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 sage: UnitGroup(K, S=tuple(K.primes_above(7))) - S-unit group with structure C2 x Z x Z x Z of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 with S = (Fractional ideal (...),) + S-unit group with structure C2 x Z x Z x Z of + Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 + with S = (Fractional ideal (...),) sage: K.primes_above(7)[0] in (7/225*a^2 - 7/75*a - 42/25, 28/225*a^2 + 77/75*a - 133/25) True @@ -312,12 +321,12 @@ def __init__(self, number_field, proof=True, S=None): try: S = tuple(K.ideal(S).prime_factors()) except (NameError, TypeError, ValueError): - raise ValueError("Cannot make a set of primes from %s"%(S,)) + raise ValueError("Cannot make a set of primes from %s" % (S,)) else: try: S = tuple(K.ideal(P) for P in S) except (NameError, TypeError, ValueError): - raise ValueError("Cannot make a set of primes from %s"%(S,)) + raise ValueError("Cannot make a set of primes from %s" % (S,)) if not all(P.is_prime() for P in S): raise ValueError("Not all elements of %s are prime ideals" % (S,)) self.__S = S @@ -389,14 +398,14 @@ def _element_constructor_(self, u): try: u = K(u) except TypeError: - raise ValueError("%s is not an element of %s"%(u,K)) + raise ValueError("%s is not an element of %s" % (u,K)) if self.__S: m = pK.bnfisunit(pari(u), self.__S_unit_data).mattranspose() if m.ncols() == 0: - raise ValueError("%s is not an S-unit"%u) + raise ValueError("%s is not an S-unit" % u) else: if not u.is_integral() or u.norm().abs() != 1: - raise ValueError("%s is not a unit"%u) + raise ValueError("%s is not a unit" % u) m = pK.bnfisunit(pari(u)).mattranspose() # convert column matrix to a list: @@ -416,7 +425,7 @@ def rank(self): sage: K.<z> = CyclotomicField(13) sage: UnitGroup(K).rank() 5 - sage: SUK = UnitGroup(K,S=2); SUK.rank() + sage: SUK = UnitGroup(K, S=2); SUK.rank() 6 """ return self.ngens()-1 @@ -433,15 +442,17 @@ def _repr_(self): Unit group with structure C2 x Z of Number Field in a with defining polynomial x^3 - 2 sage: U._repr_() 'Unit group with structure C2 x Z of Number Field in a with defining polynomial x^3 - 2' - sage: UnitGroup(NumberField(x^3 - 2, 'a'),S=2) - S-unit group with structure C2 x Z x Z of Number Field in a with defining polynomial x^3 - 2 with S = (Fractional ideal (a),) + sage: UnitGroup(NumberField(x^3 - 2, 'a'), S=2) + S-unit group with structure C2 x Z x Z of + Number Field in a with defining polynomial x^3 - 2 + with S = (Fractional ideal (a),) """ if self.__S: - return 'S-unit group with structure %s of %s with S = %s'%( + return 'S-unit group with structure %s of %s with S = %s' % ( self._group_notation(self.gens_orders()), self.number_field(), self.primes()) - return 'Unit group with structure %s of %s'%( + return 'Unit group with structure %s of %s' % ( self._group_notation(self.gens_orders()), self.number_field()) @@ -466,7 +477,7 @@ def roots_of_unity(self): EXAMPLES:: sage: x = polygen(QQ) - sage: K.<b> = NumberField(x^2+1) + sage: K.<b> = NumberField(x^2 + 1) sage: U = UnitGroup(K) sage: zs = U.roots_of_unity(); zs [b, -1, -b, 1] @@ -509,7 +520,7 @@ def zeta_order(self): def zeta(self, n=2, all=False): """ - Return one, or a list of all, primitive n-th root of unity in this unit group. + Return one, or a list of all, primitive `n`-th root of unity in this unit group. EXAMPLES:: @@ -532,7 +543,7 @@ def zeta(self, n=2, all=False): ValueError: n (=4) does not divide order of generator sage: r.<x> = QQ[] - sage: K.<b> = NumberField(x^2+1) + sage: K.<b> = NumberField(x^2 + 1) sage: U = UnitGroup(K) sage: U.zeta(4) b @@ -542,7 +553,7 @@ def zeta(self, n=2, all=False): Traceback (most recent call last): ... ValueError: n (=3) does not divide order of generator - sage: U.zeta(3,all=True) + sage: U.zeta(3, all=True) [] """ @@ -550,7 +561,7 @@ def zeta(self, n=2, all=False): K = self.number_field() n = ZZ(n) if n <= 0: - raise ValueError("n (=%s) must be positive"%n) + raise ValueError("n (=%s) must be positive" % n) if n == 1: if all: return [K(1)] @@ -571,7 +582,7 @@ def zeta(self, n=2, all=False): if all: return [] else: - raise ValueError("n (=%s) does not divide order of generator"%n) + raise ValueError("n (=%s) does not divide order of generator" % n) def number_field(self): """ @@ -580,7 +591,8 @@ def number_field(self): EXAMPLES:: sage: U = UnitGroup(QuadraticField(-23, 'w')); U - Unit group with structure C2 of Number Field in w with defining polynomial x^2 + 23 with w = 4.795831523312720?*I + Unit group with structure C2 of + Number Field in w with defining polynomial x^2 + 23 with w = 4.795831523312720?*I sage: U.number_field() Number Field in w with defining polynomial x^2 + 23 with w = 4.795831523312720?*I """ @@ -596,7 +608,9 @@ def primes(self): sage: S = tuple(K.ideal(3).prime_factors()); S (Fractional ideal (3, 1/2*a - 1/2), Fractional ideal (3, 1/2*a + 1/2)) sage: U = UnitGroup(K,S=tuple(S)); U - S-unit group with structure C2 x Z x Z of Number Field in a with defining polynomial x^2 + 23 with a = 4.795831523312720?*I with S = (Fractional ideal (3, 1/2*a - 1/2), Fractional ideal (3, 1/2*a + 1/2)) + S-unit group with structure C2 x Z x Z of + Number Field in a with defining polynomial x^2 + 23 with a = 4.795831523312720?*I + with S = (Fractional ideal (3, 1/2*a - 1/2), Fractional ideal (3, 1/2*a + 1/2)) sage: U.primes() == S True """ @@ -604,16 +618,16 @@ def primes(self): def log(self, u): r""" - Return the exponents of the unit ``u`` with respect to group generators. + Return the exponents of the unit `u` with respect to group generators. INPUT: - ``u`` -- Any object from which an element of the unit group's number field `K` may be constructed; an error is raised if an element of `K` - cannot be constructed from u, or if the element constructed is not a + cannot be constructed from `u`, or if the element constructed is not a unit. - OUTPUT: a list of integers giving the exponents of ``u`` with + OUTPUT: a list of integers giving the exponents of `u` with respect to the unit group's basis. EXAMPLES:: @@ -630,16 +644,18 @@ def log(self, u): (0, 0, 0, 0, 0, 1)] sage: vec = [65,6,7,8,9,10] sage: unit = UK.exp(vec); unit # random - -253576*z^11 + 7003*z^10 - 395532*z^9 - 35275*z^8 - 500326*z^7 - 35275*z^6 - 395532*z^5 + 7003*z^4 - 253576*z^3 - 59925*z - 59925 + -253576*z^11 + 7003*z^10 - 395532*z^9 - 35275*z^8 - 500326*z^7 - 35275*z^6 + - 395532*z^5 + 7003*z^4 - 253576*z^3 - 59925*z - 59925 sage: UK.log(unit) (13, 6, 7, 8, 9, 10) An S-unit example:: - sage: SUK = UnitGroup(K,S=2) + sage: SUK = UnitGroup(K, S=2) sage: v = (3,1,4,1,5,9,2) sage: u = SUK.exp(v); u - 8732*z^11 - 15496*z^10 - 51840*z^9 - 68804*z^8 - 51840*z^7 - 15496*z^6 + 8732*z^5 - 34216*z^3 - 64312*z^2 - 64312*z - 34216 + 8732*z^11 - 15496*z^10 - 51840*z^9 - 68804*z^8 - 51840*z^7 - 15496*z^6 + + 8732*z^5 - 34216*z^3 - 64312*z^2 - 64312*z - 34216 sage: SUK.log(u) (3, 1, 4, 1, 5, 9, 2) sage: SUK.log(u) == v @@ -655,10 +671,10 @@ def exp(self, exponents): - ``u`` -- Any object from which an element of the unit group's number field `K` may be constructed; an error is - raised if an element of `K` cannot be constructed from u, or + raised if an element of `K` cannot be constructed from `u`, or if the element constructed is not a unit. - OUTPUT: a list of integers giving the exponents of ``u`` with + OUTPUT: a list of integers giving the exponents of `u` with respect to the unit group's basis. EXAMPLES:: @@ -686,7 +702,8 @@ def exp(self, exponents): sage: SUK = UnitGroup(K,S=2) sage: v = (3,1,4,1,5,9,2) sage: u = SUK.exp(v); u - 8732*z^11 - 15496*z^10 - 51840*z^9 - 68804*z^8 - 51840*z^7 - 15496*z^6 + 8732*z^5 - 34216*z^3 - 64312*z^2 - 64312*z - 34216 + 8732*z^11 - 15496*z^10 - 51840*z^9 - 68804*z^8 - 51840*z^7 - 15496*z^6 + + 8732*z^5 - 34216*z^3 - 64312*z^2 - 64312*z - 34216 sage: SUK.log(u) (3, 1, 4, 1, 5, 9, 2) sage: SUK.log(u) == v diff --git a/src/sage/rings/numbers_abc.py b/src/sage/rings/numbers_abc.py index 478a0b36408..18f794d66c5 100644 --- a/src/sage/rings/numbers_abc.py +++ b/src/sage/rings/numbers_abc.py @@ -2,6 +2,49 @@ Support Python's numbers abstract base class .. SEEALSO:: :pep:`3141` for more information about :class:`numbers`. + +TESTS:: + + sage: import numbers + sage: isinstance(5, numbers.Integral) + True + sage: isinstance(5, numbers.Number) + True + sage: isinstance(5/1, numbers.Integral) + False + sage: isinstance(22/7, numbers.Rational) + True + sage: isinstance(1.3, numbers.Real) + True + sage: isinstance(CC(1.3), numbers.Real) + False + sage: isinstance(CC(1.3 + I), numbers.Complex) + True + sage: isinstance(RDF(1.3), numbers.Real) + True + sage: isinstance(CDF(1.3, 4), numbers.Complex) + True + sage: isinstance(AA(sqrt(2)), numbers.Real) # needs sage.rings.number_field sage.symbolic + True + sage: isinstance(QQbar(I), numbers.Complex) # needs sage.rings.number_field + True + +This doesn't work with symbolic expressions at all:: + + sage: isinstance(pi, numbers.Real) # needs sage.symbolic + False + sage: isinstance(I, numbers.Complex) # needs sage.rings.number_field + False + sage: isinstance(sqrt(2), numbers.Real) # needs sage.rings.number_field sage.symbolic + False + +Because we do this, NumPy's ``isscalar()`` recognizes Sage types:: + + sage: from numpy import isscalar # needs numpy + sage: isscalar(3.141) # needs numpy + True + sage: isscalar(4/17) # needs numpy + True """ #***************************************************************************** @@ -13,55 +56,3 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** - - -def register_sage_classes(): - """ - Register all relevant Sage classes in the :class:`numbers` - hierarchy. - - EXAMPLES:: - - sage: import numbers - sage: isinstance(5, numbers.Integral) - True - sage: isinstance(5, numbers.Number) - True - sage: isinstance(5/1, numbers.Integral) - False - sage: isinstance(22/7, numbers.Rational) - True - sage: isinstance(1.3, numbers.Real) - True - sage: isinstance(CC(1.3), numbers.Real) - False - sage: isinstance(CC(1.3 + I), numbers.Complex) - True - sage: isinstance(RDF(1.3), numbers.Real) - True - sage: isinstance(CDF(1.3, 4), numbers.Complex) - True - sage: isinstance(AA(sqrt(2)), numbers.Real) - True - sage: isinstance(QQbar(I), numbers.Complex) - True - - This doesn't work with symbolic expressions at all:: - - sage: isinstance(pi, numbers.Real) - False - sage: isinstance(I, numbers.Complex) - False - sage: isinstance(sqrt(2), numbers.Real) - False - - Because we do this, NumPy's ``isscalar()`` recognizes Sage types:: - - sage: from numpy import isscalar - sage: isscalar(3.141) - True - sage: isscalar(4/17) - True - """ - from sage.misc.superseded import deprecation - deprecation(32641, "register_sage_classes is a deprecated no-op") diff --git a/src/sage/rings/padics/CA_template.pxi b/src/sage/rings/padics/CA_template.pxi index a0a66c19621..d821b5c1576 100644 --- a/src/sage/rings/padics/CA_template.pxi +++ b/src/sage/rings/padics/CA_template.pxi @@ -1463,7 +1463,7 @@ cdef class pAdicCoercion_CA_frac_field(RingHomomorphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] ans._normalize() return ans @@ -1516,7 +1516,7 @@ cdef class pAdicCoercion_CA_frac_field(RingHomomorphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] pass return ans @@ -1686,7 +1686,7 @@ cdef class pAdicConvert_CA_frac_field(Morphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. R = ans.value.base_ring() - ans.value.__coeffs = [R(c) for c in ans.value.__coeffs] + ans.value._coeffs = [R(c) for c in ans.value._coeffs] return ans cpdef Element _call_with_args(self, _x, args=(), kwds={}): @@ -1741,7 +1741,7 @@ cdef class pAdicConvert_CA_frac_field(Morphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. R = ans.value.base_ring() - ans.value.__coeffs = [R(c) for c in ans.value.__coeffs] + ans.value._coeffs = [R(c) for c in ans.value._coeffs] return ans cdef dict _extra_slots(self): diff --git a/src/sage/rings/padics/CR_template.pxi b/src/sage/rings/padics/CR_template.pxi index 1b3134f3195..863c612587c 100644 --- a/src/sage/rings/padics/CR_template.pxi +++ b/src/sage/rings/padics/CR_template.pxi @@ -2,14 +2,14 @@ Capped relative template for complete discrete valuation rings and their fraction fields In order to use this template you need to write a linkage file and gluing file. -For an example see mpz_linkage.pxi (linkage file) and padic_capped_relative_element.pyx (gluing file). +For an example see ``mpz_linkage.pxi`` (linkage file) and ``padic_capped_relative_element.pyx`` (gluing file). -The linkage file implements a common API that is then used in the class CRElement defined here. -See the documentation of mpz_linkage.pxi for the functions needed. +The linkage file implements a common API that is then used in the class :class:`CRElement` defined here. +See the documentation of ``mpz_linkage.pxi`` for the functions needed. The gluing file does the following: -- ctypedef's celement to be the appropriate type (e.g. mpz_t) +- ``ctypedef``'s ``celement`` to be the appropriate type (e.g. ``mpz_t``) - includes the linkage file - includes this template - defines a concrete class inheriting from ``CRElement``, and implements @@ -423,7 +423,7 @@ cdef class CRElement(pAdicTemplateElement): def __invert__(self): r""" - Returns the multiplicative inverse of this element. + Return the multiplicative inverse of this element. .. NOTE:: @@ -882,7 +882,7 @@ cdef class CRElement(pAdicTemplateElement): def add_bigoh(self, absprec): """ - Returns a new element with absolute precision decreased to + Return a new element with absolute precision decreased to ``absprec``. INPUT: @@ -891,7 +891,7 @@ cdef class CRElement(pAdicTemplateElement): OUTPUT: - an equal element with precision set to the minimum of ``self's`` + an equal element with precision set to the minimum of ``self``'s precision and ``absprec`` EXAMPLES:: @@ -905,13 +905,13 @@ cdef class CRElement(pAdicTemplateElement): sage: b = R(0); b.add_bigoh(3) O(7^3) - The precision never increases:: + The precision never increases:: sage: R(4).add_bigoh(2).add_bigoh(4) 4 + O(7^2) - Another example that illustrates that the precision does - not increase:: + Another example that illustrates that the precision does + not increase:: sage: k = Qp(3,5) sage: a = k(1234123412/3^70); a @@ -959,7 +959,7 @@ cdef class CRElement(pAdicTemplateElement): cpdef bint _is_exact_zero(self) except -1: """ - Returns true if this element is exactly zero. + Return ``True`` if this element is exactly zero. EXAMPLES:: @@ -975,7 +975,7 @@ cdef class CRElement(pAdicTemplateElement): cpdef bint _is_inexact_zero(self) except -1: """ - Returns True if this element is indistinguishable from zero + Return ``True`` if this element is indistinguishable from zero but has finite precision. EXAMPLES:: @@ -992,10 +992,10 @@ cdef class CRElement(pAdicTemplateElement): def is_zero(self, absprec = None): r""" - Determines whether this element is zero modulo + Determine whether this element is zero modulo `\pi^{\mbox{absprec}}`. - If ``absprec is None``, returns ``True`` if this element is + If ``absprec`` is ``None``, returns ``True`` if this element is indistinguishable from zero. INPUT: @@ -1037,7 +1037,7 @@ cdef class CRElement(pAdicTemplateElement): def __bool__(self): """ - Returns True if self is distinguishable from zero. + Return ``True`` if ``self`` is distinguishable from zero. For most applications, explicitly specifying the power of p modulo which the element is supposed to be nonzero is @@ -1053,10 +1053,10 @@ cdef class CRElement(pAdicTemplateElement): def is_equal_to(self, _right, absprec=None): r""" - Returns whether self is equal to right modulo + Return whether ``self`` is equal to ``right`` modulo `\pi^{\mbox{absprec}}`. - If ``absprec is None``, returns True if self and right are + If ``absprec`` is ``None``, returns ``True`` if ``self`` and ``right`` are equal to the minimum of their precisions. INPUT: @@ -1390,10 +1390,10 @@ cdef class CRElement(pAdicTemplateElement): def precision_relative(self): """ - Returns the relative precision of this element. + Return the relative precision of this element. This is the power of the maximal ideal modulo which the unit - part of self is defined. + part of ``self`` is defined. EXAMPLES:: @@ -1417,7 +1417,7 @@ cdef class CRElement(pAdicTemplateElement): cpdef pAdicTemplateElement unit_part(self): r""" - Returns `u`, where this element is `\pi^v u`. + Return `u`, where this element is `\pi^v u`. EXAMPLES:: @@ -1461,7 +1461,7 @@ cdef class CRElement(pAdicTemplateElement): cdef long valuation_c(self): """ - Returns the valuation of this element. + Return the valuation of this element. If self is an exact zero, returns ``maxordp``, which is defined as ``(1L << (sizeof(long) * 8 - 2))-1``. @@ -1480,16 +1480,16 @@ cdef class CRElement(pAdicTemplateElement): cpdef val_unit(self, p=None): """ - Returns a pair ``(self.valuation(), self.unit_part())``. + Return a pair ``(self.valuation(), self.unit_part())``. INPUT: - - ``p`` -- a prime (default: ``None``). If specified, will make sure that p==self.parent().prime() + - ``p`` -- a prime (default: ``None``). If specified, will make sure that ``p == self.parent().prime()`` .. NOTE:: The optional argument ``p`` is used for consistency with the - valuation methods on integer and rational. + valuation methods on integers and rationals. EXAMPLES:: @@ -1707,7 +1707,7 @@ cdef class pAdicConvert_CR_ZZ(RingMap): returns the smallest non-negative integer approximation to its input which is accurate up to the precision. - Raises a ``ValueError``, if the input is not in the closure of the image of + Raises a :class:`ValueError`, if the input is not in the closure of the image of the integers. EXAMPLES:: @@ -2113,7 +2113,7 @@ cdef class pAdicConvert_QQ_CR(Morphism): def section(self): """ - Returns the map back to the rationals that returns the smallest + Return the map back to the rationals that returns the smallest non-negative integer approximation to its input which is accurate up to the precision. @@ -2130,8 +2130,8 @@ cdef class pAdicConvert_QQ_CR(Morphism): return self._section cdef class pAdicCoercion_CR_frac_field(RingHomomorphism): - """ - The canonical inclusion of Zq into its fraction field. + r""" + The canonical inclusion of `\ZZ_q` into its fraction field. EXAMPLES:: @@ -2184,7 +2184,7 @@ cdef class pAdicCoercion_CR_frac_field(RingHomomorphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] return ans cpdef Element _call_with_args(self, _x, args=(), kwds={}): @@ -2241,12 +2241,12 @@ cdef class pAdicCoercion_CR_frac_field(RingHomomorphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] return ans def section(self): """ - Returns a map back to the ring that converts elements of + Return a map back to the ring that converts elements of non-negative valuation. EXAMPLES:: @@ -2356,8 +2356,8 @@ cdef class pAdicCoercion_CR_frac_field(RingHomomorphism): cdef class pAdicConvert_CR_frac_field(Morphism): - """ - The section of the inclusion from `\ZZ_q`` to its fraction field. + r""" + The section of the inclusion from `\ZZ_q` to its fraction field. EXAMPLES:: @@ -2404,7 +2404,7 @@ cdef class pAdicConvert_CR_frac_field(Morphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] return ans cpdef Element _call_with_args(self, _x, args=(), kwds={}): @@ -2463,7 +2463,7 @@ cdef class pAdicConvert_CR_frac_field(Morphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] return ans cdef dict _extra_slots(self): diff --git a/src/sage/rings/padics/FM_template.pxi b/src/sage/rings/padics/FM_template.pxi index df7bd8bdf38..3bae827a08c 100644 --- a/src/sage/rings/padics/FM_template.pxi +++ b/src/sage/rings/padics/FM_template.pxi @@ -2,19 +2,19 @@ Fixed modulus template for complete discrete valuation rings In order to use this template you need to write a linkage file and -gluing file. For an example see mpz_linkage.pxi (linkage file) and -padic_fixed_modulus_element.pyx (gluing file). +gluing file. For an example see ``mpz_linkage.pxi`` (linkage file) and +``padic_fixed_modulus_element.pyx`` (gluing file). The linkage file implements a common API that is then used in the -class FMElement defined here. See sage/libs/linkages/padics/API.pxi +class :class:`FMElement` defined here. See ``sage/libs/linkages/padics/API.pxi`` for the functions needed. The gluing file does the following: -- ctypedef's celement to be the appropriate type (e.g. mpz_t) +- ``ctypedef``'s ``celement`` to be the appropriate type (e.g. ``mpz_t``) - includes the linkage file - includes this template -- defines a concrete class inheriting from FMElement, and implements +- defines a concrete class inheriting from :class:`FMElement`, and implements any desired extra methods AUTHORS: @@ -34,7 +34,7 @@ AUTHORS: #***************************************************************************** include "padic_template_element.pxi" -from cpython.int cimport * +from cpython.long cimport * from sage.structure.element cimport Element from sage.rings.padics.common_conversion cimport comb_prec, _process_args_and_kwds @@ -463,7 +463,7 @@ cdef class FMElement(pAdicTemplateElement): def add_bigoh(self, absprec): """ - Returns a new element truncated modulo `\pi^{\mbox{absprec}}`. + Return a new element truncated modulo `\pi^{\mbox{absprec}}`. INPUT: @@ -471,7 +471,7 @@ cdef class FMElement(pAdicTemplateElement): OUTPUT: - - a new element truncated modulo `\pi^{\mbox{absprec}}`. + a new element truncated modulo `\pi^{\mbox{absprec}}`. EXAMPLES:: @@ -525,7 +525,7 @@ cdef class FMElement(pAdicTemplateElement): cpdef bint _is_inexact_zero(self) except -1: """ - Returns True if self is indistinguishable from zero. + Return ``True`` if self is indistinguishable from zero. EXAMPLES:: @@ -539,7 +539,7 @@ cdef class FMElement(pAdicTemplateElement): def is_zero(self, absprec = None): r""" - Returns whether self is zero modulo `\pi^{\mbox{absprec}}`. + Returns whether ``self`` is zero modulo `\pi^{\mbox{absprec}}`. INPUT: @@ -582,13 +582,13 @@ cdef class FMElement(pAdicTemplateElement): def is_equal_to(self, _right, absprec=None): r""" - Returns whether this element is equal to ``right`` modulo `p^{\mbox{absprec}}`. + Return whether this element is equal to ``right`` modulo `p^{\mbox{absprec}}`. If ``absprec`` is ``None``, returns if ``self == 0``. INPUT: - - ``right`` -- a p-adic element with the same parent + - ``right`` -- a `p`-adic element with the same parent - ``absprec`` -- a positive integer or ``None`` (default: ``None``) EXAMPLES:: @@ -780,9 +780,9 @@ cdef class FMElement(pAdicTemplateElement): cpdef pAdicTemplateElement unit_part(FMElement self): r""" - Returns the unit part of self. + Return the unit part of ``self``. - If the valuation of self is positive, then the high digits of the + If the valuation of ``self`` is positive, then the high digits of the result will be zero. EXAMPLES:: @@ -805,7 +805,7 @@ cdef class FMElement(pAdicTemplateElement): cdef long valuation_c(self): """ - Returns the valuation of this element. + Return the valuation of this element. TESTS:: @@ -836,10 +836,10 @@ cdef class FMElement(pAdicTemplateElement): cpdef val_unit(self): """ - Returns a 2-tuple, the first element set to the valuation of - self, and the second to the unit part of self. + Return a 2-tuple, the first element set to the valuation of + ``self``, and the second to the unit part of ``self``. - If self == 0, then the unit part is O(p^self.parent().precision_cap()). + If ``self == 0``, then the unit part is ``O(p^self.parent().precision_cap())``. EXAMPLES:: @@ -868,8 +868,8 @@ cdef class FMElement(pAdicTemplateElement): return chash(self.value, 0, self.prime_pow.ram_prec_cap, self.prime_pow) cdef class pAdicCoercion_ZZ_FM(RingHomomorphism): - """ - The canonical inclusion from ZZ to a fixed modulus ring. + r""" + The canonical inclusion from `\ZZ` to a fixed modulus ring. EXAMPLES:: @@ -993,8 +993,8 @@ cdef class pAdicCoercion_ZZ_FM(RingHomomorphism): return ans def section(self): - """ - Returns a map back to ZZ that approximates an element of this + r""" + Returns a map back to `\ZZ` that approximates an element of this `p`-adic ring by an integer. EXAMPLES:: @@ -1010,11 +1010,11 @@ cdef class pAdicCoercion_ZZ_FM(RingHomomorphism): return self._section cdef class pAdicConvert_FM_ZZ(RingMap): - """ - The map from a fixed modulus ring back to ZZ that returns the smallest + r""" + The map from a fixed modulus ring back to `\ZZ` that returns the smallest non-negative integer approximation to its input which is accurate up to the precision. - If the input is not in the closure of the image of ZZ, raises a ValueError. + If the input is not in the closure of the image of `\ZZ`, raises a :class:`ValueError`. EXAMPLES:: @@ -1057,9 +1057,9 @@ cdef class pAdicConvert_FM_ZZ(RingMap): return ans cdef class pAdicConvert_QQ_FM(Morphism): - """ - The inclusion map from QQ to a fixed modulus ring that is defined - on all elements with non-negative p-adic valuation. + r""" + The inclusion map from `\QQ` to a fixed modulus ring that is defined + on all elements with non-negative `p`-adic valuation. EXAMPLES:: @@ -1175,8 +1175,8 @@ cdef class pAdicConvert_QQ_FM(Morphism): return ans cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): - """ - The canonical inclusion of Zq into its fraction field. + r""" + The canonical inclusion of `\ZZ_q` into its fraction field. EXAMPLES:: @@ -1227,7 +1227,7 @@ cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] return ans cpdef Element _call_with_args(self, _x, args=(), kwds={}): @@ -1277,12 +1277,12 @@ cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] return ans def section(self): """ - Returns a map back to the ring that converts elements of + Return a map back to the ring that converts elements of non-negative valuation. EXAMPLES:: @@ -1388,7 +1388,7 @@ cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): cdef class pAdicConvert_FM_frac_field(Morphism): r""" - The section of the inclusion from `\ZZ_q`` to its fraction field. + The section of the inclusion from `\ZZ_q` to its fraction field. EXAMPLES:: @@ -1435,7 +1435,7 @@ cdef class pAdicConvert_FM_frac_field(Morphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. R = ans.value.base_ring() - ans.value.__coeffs = [R(c) for c in ans.value.__coeffs] + ans.value._coeffs = [R(c) for c in ans.value._coeffs] return ans cpdef Element _call_with_args(self, _x, args=(), kwds={}): @@ -1483,7 +1483,7 @@ cdef class pAdicConvert_FM_frac_field(Morphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. R = ans.value.base_ring() - ans.value.__coeffs = [R(c) for c in ans.value.__coeffs] + ans.value._coeffs = [R(c) for c in ans.value._coeffs] return ans cdef dict _extra_slots(self): diff --git a/src/sage/rings/padics/FP_template.pxi b/src/sage/rings/padics/FP_template.pxi index befd8ee01fb..d253d208410 100644 --- a/src/sage/rings/padics/FP_template.pxi +++ b/src/sage/rings/padics/FP_template.pxi @@ -2,19 +2,19 @@ Floating point template for complete discrete valuation rings In order to use this template you need to write a linkage file and -gluing file. For an example see mpz_linkage.pxi (linkage file) and -padic_floating_point_element.pyx (gluing file). +gluing file. For an example see ``mpz_linkage.pxi`` (linkage file) and +``padic_floating_point_element.pyx`` (gluing file). The linkage file implements a common API that is then used in the -class FPElement defined here. See sage/libs/linkages/padics/API.pxi +class :class:`FPElement` defined here. See ``sage/libs/linkages/padics/API.pxi`` for the functions needed. The gluing file does the following: -- ctypedef's celement to be the appropriate type (e.g. mpz_t) +- ``ctypedef``'s ``celement`` to be the appropriate type (e.g. ``mpz_t``) - includes the linkage file - includes this template -- defines a concrete class inheriting from FPElement, and implements +- defines a concrete class inheriting from :class:`FPElement`, and implements any desired extra methods AUTHORS: @@ -35,7 +35,7 @@ AUTHORS: from sage.ext.stdsage cimport PY_NEW include "padic_template_element.pxi" -from cpython.int cimport * +from cpython.long cimport * from sage.structure.element cimport Element from sage.rings.padics.common_conversion cimport comb_prec, _process_args_and_kwds @@ -795,7 +795,7 @@ cdef class FPElement(pAdicTemplateElement): def add_bigoh(self, absprec): """ - Returns a new element truncated modulo `\pi^{\mbox{absprec}}`. + Return a new element truncated modulo `\pi^{\mbox{absprec}}`. INPUT: @@ -803,7 +803,7 @@ cdef class FPElement(pAdicTemplateElement): OUTPUT: - - a new element truncated modulo `\pi^{\mbox{absprec}}`. + a new element truncated modulo `\pi^{\mbox{absprec}}`. EXAMPLES:: @@ -851,7 +851,7 @@ cdef class FPElement(pAdicTemplateElement): cpdef bint _is_inexact_zero(self) except -1: """ - Returns True if self is indistinguishable from zero. + Return ``True`` if self is indistinguishable from zero. EXAMPLES:: @@ -865,7 +865,7 @@ cdef class FPElement(pAdicTemplateElement): def is_zero(self, absprec = None): r""" - Returns whether self is zero modulo `\pi^{\mbox{absprec}}`. + Returns whether ``self`` is zero modulo `\pi^{\mbox{absprec}}`. INPUT: @@ -897,7 +897,7 @@ cdef class FPElement(pAdicTemplateElement): """ Return ``True`` if this element is distinguishable from zero. - For most applications, explicitly specifying the power of p + For most applications, explicitly specifying the power of `p` modulo which the element is supposed to be nonzero is preferable. EXAMPLES:: @@ -910,14 +910,14 @@ cdef class FPElement(pAdicTemplateElement): def is_equal_to(self, _right, absprec=None): r""" - Returns whether this element is equal to ``right`` modulo `p^{\mbox{absprec}}`. + Return whether this element is equal to ``right`` modulo `p^{\mbox{absprec}}`. - If ``absprec`` is ``None``, determines whether self and right + If ``absprec`` is ``None``, determines whether ``self`` and ``right`` have the same value. INPUT: - - ``right`` -- a p-adic element with the same parent + - ``right`` -- a `p`-adic element with the same parent - ``absprec`` -- a positive integer or ``None`` (default: ``None``) EXAMPLES:: @@ -1137,7 +1137,7 @@ cdef class FPElement(pAdicTemplateElement): cpdef pAdicTemplateElement unit_part(FPElement self): r""" - Returns the unit part of this element. + Return the unit part of this element. If the valuation of this element is positive, then the high digits of the result will be zero. @@ -1167,7 +1167,7 @@ cdef class FPElement(pAdicTemplateElement): cdef long valuation_c(self): """ - Returns the valuation of this element. + Return the valuation of this element. If this element is an exact zero, returns ``maxordp``, which is defined as ``(1L << (sizeof(long) * 8 - 2))-1``. @@ -1204,7 +1204,7 @@ cdef class FPElement(pAdicTemplateElement): cpdef val_unit(self, p=None): """ - Returns a 2-tuple, the first element set to the valuation of + Return a 2-tuple, the first element set to the valuation of this element, and the second to the unit part. If this element is either zero or infinity, raises an error. @@ -1380,8 +1380,8 @@ cdef class pAdicCoercion_ZZ_FP(RingHomomorphism): return ans def section(self): - """ - Returns a map back to ZZ that approximates an element of this + r""" + Returns a map back to `\ZZ` that approximates an element of this `p`-adic ring by an integer. EXAMPLES:: @@ -1398,11 +1398,11 @@ cdef class pAdicCoercion_ZZ_FP(RingHomomorphism): cdef class pAdicConvert_FP_ZZ(RingMap): - """ - The map from a floating point ring back to ZZ that returns the smallest + r""" + The map from a floating point ring back to `\ZZ` that returns the smallest non-negative integer approximation to its input which is accurate up to the precision. - If the input is not in the closure of the image of ZZ, raises a ValueError. + If the input is not in the closure of the image of `\ZZ`, raises a :class:`ValueError`. EXAMPLES:: @@ -1602,7 +1602,7 @@ cdef class pAdicCoercion_QQ_FP(RingHomomorphism): def section(self): """ - Returns a map back to the rationals that approximates an element by + Return a map back to the rationals that approximates an element by a rational number. EXAMPLES:: @@ -1669,8 +1669,8 @@ cdef class pAdicConvert_FP_QQ(RingMap): return ans cdef class pAdicConvert_QQ_FP(Morphism): - """ - The inclusion map from QQ to a floating point ring. + r""" + The inclusion map from `\QQ` to a floating point ring. EXAMPLES:: @@ -1849,7 +1849,7 @@ cdef class pAdicCoercion_FP_frac_field(RingHomomorphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] return ans cpdef Element _call_with_args(self, _x, args=(), kwds={}): @@ -1903,12 +1903,12 @@ cdef class pAdicCoercion_FP_frac_field(RingHomomorphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] return ans def section(self): r""" - Returns a map back to the ring that converts elements of + Return a map back to the ring that converts elements of non-negative valuation. EXAMPLES:: @@ -2025,7 +2025,7 @@ cdef class pAdicConvert_FP_frac_field(Morphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] return ans cpdef Element _call_with_args(self, _x, args=(), kwds={}): @@ -2081,7 +2081,7 @@ cdef class pAdicConvert_FP_frac_field(Morphism): IF CELEMENT_IS_PY_OBJECT: # The base ring is wrong, so we fix it. K = ans.unit.base_ring() - ans.unit.__coeffs = [K(c) for c in ans.unit.__coeffs] + ans.unit._coeffs = [K(c) for c in ans.unit._coeffs] return ans cdef dict _extra_slots(self): diff --git a/src/sage/rings/padics/__init__.py b/src/sage/rings/padics/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/rings/padics/all.py b/src/sage/rings/padics/all.py index b90b7da1d8a..7014f5622d8 100644 --- a/src/sage/rings/padics/all.py +++ b/src/sage/rings/padics/all.py @@ -1,4 +1,3 @@ -from .generic_nodes import is_pAdicField, is_pAdicRing from .factory import Zp, Zq, Zp as pAdicRing, ZpCR, ZpCA, ZpFM, ZpFP, ZpLC, ZpLF, ZqCR, ZqCA, ZqFM, ZqFP, ZpER from .factory import Qp, Qq, Qp as pAdicField, QpCR, QpFP, QpLC, QpLF, QqCR, QqFP, QpER from .factory import pAdicExtension diff --git a/src/sage/rings/padics/common_conversion.pyx b/src/sage/rings/padics/common_conversion.pyx index 4ed5570d306..0afddcc30a4 100644 --- a/src/sage/rings/padics/common_conversion.pyx +++ b/src/sage/rings/padics/common_conversion.pyx @@ -26,7 +26,7 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from cpython.int cimport * +from cpython.long cimport * from sage.ext.stdsage cimport PY_NEW from sage.libs.gmp.all cimport * from sage.arith.rational_reconstruction cimport mpq_rational_reconstruction @@ -84,7 +84,7 @@ cdef long get_ordp(x, PowComputer_class prime_pow) except? -10000: if x == 0: return maxordp try: - n = PyInt_AsLong(x) + n = PyLong_AsLong(x) except OverflowError: return get_ordp(Integer(x), prime_pow) else: @@ -250,7 +250,7 @@ cdef long comb_prec(iprec, long prec) except? -10000: raise OverflowError("precision overflow") return mpz_get_si(intprec.value) if isinstance(iprec, int): - return min(PyInt_AS_LONG(iprec), prec) + return min(PyLong_AsLong(iprec), prec) return comb_prec(Integer(iprec), prec) cdef int _process_args_and_kwds(long *aprec, long *rprec, args, kwds, bint absolute, PowComputer_class prime_pow) except -1: @@ -405,7 +405,7 @@ cdef inline int cconv_shared(mpz_t out, x, long prec, long valshift, PowComputer - ``prime_pow`` -- a PowComputer for the ring. """ - if PyInt_Check(x): + if PyLong_Check(x): x = Integer(x) elif isinstance(x, pari_gen): x = x.sage() diff --git a/src/sage/rings/padics/eisenstein_extension_generic.py b/src/sage/rings/padics/eisenstein_extension_generic.py index 4f68e63ffae..bf9a3d96158 100644 --- a/src/sage/rings/padics/eisenstein_extension_generic.py +++ b/src/sage/rings/padics/eisenstein_extension_generic.py @@ -26,7 +26,7 @@ class EisensteinExtensionGeneric(pAdicExtensionGeneric): def __init__(self, poly, prec, print_mode, names, element_class): """ - Initializes self. + Initializes ``self``. EXAMPLES:: @@ -50,6 +50,7 @@ def _extension_type(self): sage: K._extension_type() 'Unramified' + sage: x = polygen(ZZ, 'x') sage: L.<pi> = Qp(5).extension(x^2 - 5) sage: L._extension_type() 'Eisenstein' @@ -66,6 +67,7 @@ def absolute_e(self): sage: K.absolute_e() 1 + sage: x = polygen(ZZ, 'x') sage: L.<pi> = Qp(3).extension(x^2 - 3) sage: L.absolute_e() 2 @@ -74,7 +76,7 @@ def absolute_e(self): def inertia_subring(self): """ - Returns the inertia subring. + Return the inertia subring. Since an Eisenstein extension is totally ramified, this is just the ground field. @@ -83,7 +85,7 @@ def inertia_subring(self): sage: A = Zp(7,10) sage: S.<x> = A[] - sage: B.<t> = A.ext(x^2+7) + sage: B.<t> = A.ext(x^2 + 7) sage: B.inertia_subring() 7-adic Ring with capped relative precision 10 """ @@ -91,21 +93,21 @@ def inertia_subring(self): def residue_class_field(self): """ - Returns the residue class field. + Return the residue class field. INPUT: - - self -- a p-adic ring + - ``self`` -- a p-adic ring OUTPUT: - - the residue field + the residue field EXAMPLES:: sage: A = Zp(7,10) sage: S.<x> = A[] - sage: B.<t> = A.ext(x^2+7) + sage: B.<t> = A.ext(x^2 + 7) sage: B.residue_class_field() Finite Field of size 7 """ @@ -113,7 +115,7 @@ def residue_class_field(self): def residue_ring(self, n): """ - Return the quotient of the ring of integers by the nth power of its maximal ideal. + Return the quotient of the ring of integers by the `n`-th power of its maximal ideal. EXAMPLES:: @@ -162,13 +164,13 @@ def residue_ring(self, n): def gen(self, n=0): """ - Returns a generator for self as an extension of its ground ring. + Return a generator for ``self`` as an extension of its ground ring. EXAMPLES:: sage: A = Zp(7,10) sage: S.<x> = A[] - sage: B.<t> = A.ext(x^2+7) + sage: B.<t> = A.ext(x^2 + 7) sage: B.gen() t + O(t^21) """ @@ -178,14 +180,14 @@ def gen(self, n=0): def uniformizer_pow(self, n): """ - Returns the nth power of the uniformizer of self (as an - element of self). + Return the `n`-th power of the uniformizer of ``self`` (as an + element of ``self``). EXAMPLES:: sage: A = Zp(7,10) sage: S.<x> = A[] - sage: B.<t> = A.ext(x^2+7) + sage: B.<t> = A.ext(x^2 + 7) sage: B.uniformizer_pow(5) t^5 + O(t^25) """ @@ -196,14 +198,14 @@ def uniformizer_pow(self, n): def uniformizer(self): """ - Returns the uniformizer of self, ie a generator for the unique + Return the uniformizer of ``self``, i.e., a generator for the unique maximal ideal. EXAMPLES:: sage: A = Zp(7,10) sage: S.<x> = A[] - sage: B.<t> = A.ext(x^2+7) + sage: B.<t> = A.ext(x^2 + 7) sage: B.uniformizer() t + O(t^21) """ @@ -211,7 +213,7 @@ def uniformizer(self): def _uniformizer_print(self): """ - Returns a string representation of how the uniformizer of self + Return a string representation of how the uniformizer of self prints. Mainly for internal use. EXAMPLES:: diff --git a/src/sage/rings/padics/factory.py b/src/sage/rings/padics/factory.py index 3e396efa8ac..d8d7c7e3c3b 100644 --- a/src/sage/rings/padics/factory.py +++ b/src/sage/rings/padics/factory.py @@ -35,7 +35,7 @@ from sage.rings.infinity import Infinity from sage.structure.factorization import Factorization from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_element import Polynomial from sage.structure.element import is_Element from .padic_base_leaves import (pAdicRingCappedRelative, pAdicRingCappedAbsolute, @@ -161,7 +161,7 @@ def _canonicalize_show_prec(type, print_mode, show_prec=None): def get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_sep, print_alphabet, print_max_terms, show_prec, check, valid_types, label=None): r""" - This implements create_key for Zp and Qp: moving it here prevents code duplication. + This implements ``create_key`` for ``Zp`` and ``Qp``: moving it here prevents code duplication. It fills in unspecified values and checks for contradictions in the input. It also standardizes irrelevant options so that duplicate parents are not created. @@ -301,7 +301,7 @@ def get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_se if not isinstance(print_ram_name, str): print_ram_name = str(print_ram_name) if names != print_ram_name: - raise ValueError("If both names (%s) and print_ram_name (%s) are specified, they must agree"%(names, print_ram_name)) + raise ValueError("If both names (%s) and print_ram_name (%s) are specified, they must agree" % (names, print_ram_name)) name = names else: if names is None: @@ -311,7 +311,7 @@ def get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_se else: name = str(names) if type not in valid_types: - raise ValueError("type must be %s"%(", ".join(valid_types))) + raise ValueError("type must be %s" % (", ".join(valid_types))) show_prec = _canonicalize_show_prec(type, print_mode, show_prec) key = (p, prec, type, print_mode, name, print_pos, print_sep, tuple(print_alphabet), print_max_terms, show_prec, label) return key @@ -468,7 +468,9 @@ class Qp_class(UniqueFactory): sage: R = Qp(5, print_mode='series'); a = R(70700); a 3*5^2 + 3*5^4 + 2*5^5 + 4*5^6 + O(5^22) sage: b = R(-70700); b - 2*5^2 + 4*5^3 + 5^4 + 2*5^5 + 4*5^7 + 4*5^8 + 4*5^9 + 4*5^10 + 4*5^11 + 4*5^12 + 4*5^13 + 4*5^14 + 4*5^15 + 4*5^16 + 4*5^17 + 4*5^18 + 4*5^19 + 4*5^20 + 4*5^21 + O(5^22) + 2*5^2 + 4*5^3 + 5^4 + 2*5^5 + 4*5^7 + 4*5^8 + 4*5^9 + 4*5^10 + 4*5^11 + + 4*5^12 + 4*5^13 + 4*5^14 + 4*5^15 + 4*5^16 + 4*5^17 + 4*5^18 + + 4*5^19 + 4*5^20 + 4*5^21 + O(5^22) *print_pos* controls whether negatives can be used in the coefficients of powers of `p`. :: @@ -721,10 +723,10 @@ class Qp_class(UniqueFactory): sage: K = Qp(15, check=False); a = K(999); a 9 + 6*15 + 4*15^2 + O(15^20) """ - def create_key(self, p, prec = None, type = 'capped-rel', print_mode = None, - names = None, ram_name = None, print_pos = None, - print_sep = None, print_alphabet = None, print_max_terms = None, show_prec = None, check = True, - label = None): # specific to Lattice precision + def create_key(self, p, prec=None, type='capped-rel', print_mode=None, + names=None, ram_name=None, print_pos=None, + print_sep=None, print_alphabet=None, print_max_terms=None, show_prec=None, check=True, + label=None): # specific to Lattice precision r""" Creates a key from input parameters for ``Qp``. @@ -813,6 +815,7 @@ def create_object(self, version, key): else: raise ValueError("unexpected type") + Qp = Qp_class("Qp") @@ -820,10 +823,10 @@ def create_object(self, version, key): # Qq -- unramified extensions ###################################################### -def Qq(q, prec = None, type = 'capped-rel', modulus = None, names=None, - print_mode=None, ram_name = None, res_name = None, print_pos = None, - print_sep = None, print_max_ram_terms = None, - print_max_unram_terms = None, print_max_terse_terms = None, show_prec=None, check = True, implementation = 'FLINT'): +def Qq(q, prec=None, type='capped-rel', modulus=None, names=None, + print_mode=None, ram_name=None, res_name=None, print_pos=None, + print_sep=None, print_max_ram_terms=None, + print_max_unram_terms=None, print_max_terse_terms=None, show_prec=None, check=True, implementation='FLINT'): r""" Given a prime power `q = p^n`, return the unique unramified extension of `\QQ_p` of degree `n`. @@ -832,7 +835,7 @@ def Qq(q, prec = None, type = 'capped-rel', modulus = None, names=None, - ``q`` -- integer, list, tuple or ``Factorization`` object. If ``q`` is an integer, it is the prime power `q` in `\QQ_q`. If ``q`` is a - ``Factorization`` object, it is the factorization of the prime power `q`. + :class:`Factorization` object, it is the factorization of the prime power `q`. As a tuple it is the pair ``(p, n)``, and as a list it is a single element list ``[(p, n)]``. @@ -860,7 +863,7 @@ def Qq(q, prec = None, type = 'capped-rel', modulus = None, names=None, - ``res_name`` -- string (defaults to ``None``, which corresponds to adding a ``'0'`` to the end of the name). Controls how elements of - the reside field print. + the residue field print. - ``print_pos`` -- bool (default ``None``) Whether to only use positive integers in the representations of elements. See PRINTING below. @@ -973,10 +976,10 @@ def Qq(q, prec = None, type = 'capped-rel', modulus = None, names=None, 2. The modulus can also be given as a **symbolic expression**. :: - sage: x = var('x') - sage: X.<a> = Qq(27, modulus = x^3 + 2*x + 1); X.modulus() + sage: x = var('x') # needs sage.symbolic + sage: X.<a> = Qq(27, modulus = x^3 + 2*x + 1); X.modulus() # needs sage.symbolic (1 + O(3^20))*x^3 + O(3^20)*x^2 + (2 + O(3^20))*x + 1 + O(3^20) - sage: X == R + sage: X == R # needs sage.symbolic True By default, the polynomial chosen is the standard lift of the @@ -1012,9 +1015,15 @@ def Qq(q, prec = None, type = 'capped-rel', modulus = None, names=None, sage: R.<a> = Qq(9, 20, 'capped-rel', print_mode='series'); (1+2*a)^4 2 + (2*a + 2)*3 + (2*a + 1)*3^2 + O(3^20) sage: -3*(1+2*a)^4 - 3 + a*3^2 + 3^3 + (2*a + 2)*3^4 + (2*a + 2)*3^5 + (2*a + 2)*3^6 + (2*a + 2)*3^7 + (2*a + 2)*3^8 + (2*a + 2)*3^9 + (2*a + 2)*3^10 + (2*a + 2)*3^11 + (2*a + 2)*3^12 + (2*a + 2)*3^13 + (2*a + 2)*3^14 + (2*a + 2)*3^15 + (2*a + 2)*3^16 + (2*a + 2)*3^17 + (2*a + 2)*3^18 + (2*a + 2)*3^19 + (2*a + 2)*3^20 + O(3^21) + 3 + a*3^2 + 3^3 + (2*a + 2)*3^4 + (2*a + 2)*3^5 + (2*a + 2)*3^6 + (2*a + 2)*3^7 + + (2*a + 2)*3^8 + (2*a + 2)*3^9 + (2*a + 2)*3^10 + (2*a + 2)*3^11 + + (2*a + 2)*3^12 + (2*a + 2)*3^13 + (2*a + 2)*3^14 + (2*a + 2)*3^15 + + (2*a + 2)*3^16 + (2*a + 2)*3^17 + (2*a + 2)*3^18 + (2*a + 2)*3^19 + + (2*a + 2)*3^20 + O(3^21) sage: ~(3*a+18) - (a + 2)*3^-1 + 1 + 2*3 + (a + 1)*3^2 + 3^3 + 2*3^4 + (a + 1)*3^5 + 3^6 + 2*3^7 + (a + 1)*3^8 + 3^9 + 2*3^10 + (a + 1)*3^11 + 3^12 + 2*3^13 + (a + 1)*3^14 + 3^15 + 2*3^16 + (a + 1)*3^17 + 3^18 + O(3^19) + (a + 2)*3^-1 + 1 + 2*3 + (a + 1)*3^2 + 3^3 + 2*3^4 + (a + 1)*3^5 + 3^6 + 2*3^7 + + (a + 1)*3^8 + 3^9 + 2*3^10 + (a + 1)*3^11 + 3^12 + 2*3^13 + (a + 1)*3^14 + + 3^15 + 2*3^16 + (a + 1)*3^17 + 3^18 + O(3^19) *print_pos* controls whether negatives can be used in the coefficients of powers of `p`. :: @@ -1074,7 +1083,8 @@ def Qq(q, prec = None, type = 'capped-rel', modulus = None, names=None, *print_pos* controls whether to use a balanced representation or not. :: - sage: S.<a> = Qq(9, 7, print_mode='val-unit', print_pos=False); b = (1+3*a)^9 - 1; b + sage: S.<a> = Qq(9, 7, print_mode='val-unit', print_pos=False) + sage: b = (1+3*a)^9 - 1; b 3^3 * (15 - 17*a) + O(3^7) sage: ~b 3^-3 * (-40 + a) + O(3) @@ -1082,15 +1092,19 @@ def Qq(q, prec = None, type = 'capped-rel', modulus = None, names=None, *ram_name* affects how the prime is printed. :: sage: A.<x> = Qp(next_prime(10^6), print_mode='val-unit')[] - sage: T.<a> = Qq(next_prime(10^6)^3, 4, print_mode='val-unit', ram_name='p', modulus=x^3+385831*x^2+106556*x+321036); b = ~(next_prime(10^6)^2*(a^2 + a - 4)); b - p^-2 * (503009563508519137754940 + 704413692798200940253892*a + 968097057817740999537581*a^2) + O(p^2) + sage: T.<a> = Qq(next_prime(10^6)^3, 4, print_mode='val-unit', ram_name='p', + ....: modulus=x^3+385831*x^2+106556*x+321036) + sage: b = ~(next_prime(10^6)^2*(a^2 + a - 4)); b + p^-2 * (503009563508519137754940 + 704413692798200940253892*a + + 968097057817740999537581*a^2) + O(p^2) sage: b * (a^2 + a - 4) p^-2 * 1 + O(p^2) *print_max_terse_terms* controls how many terms of the polynomial appear in the unit part. :: - sage: U.<a> = Qq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3); b = ~(17*(a^3-a+14)); b + sage: U.<a> = Qq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3) + sage: b = ~(17*(a^3-a+14)); b 17^-1 * (22110411 + 11317400*a + 20656972*a^2 + ...) + O(17^5) sage: b*17*(a^3-a+14) 1 + O(17^6) @@ -1176,7 +1190,8 @@ def Qq(q, prec = None, type = 'capped-rel', modulus = None, names=None, series, but more compactly. :: sage: R.<a> = Qq(125); (a+5)^6 - (4*a^2 + 3*a + 4) + (3*a^2 + 2*a)*5 + (a^2 + a + 1)*5^2 + (3*a + 2)*5^3 + (3*a^2 + a + 3)*5^4 + (2*a^2 + 3*a + 2)*5^5 + O(5^20) + (4*a^2 + 3*a + 4) + (3*a^2 + 2*a)*5 + (a^2 + a + 1)*5^2 + (3*a + 2)*5^3 + + (3*a^2 + a + 3)*5^4 + (2*a^2 + 3*a + 2)*5^5 + O(5^20) sage: R.<a> = Qq(125, print_mode='bars', prec=8); repr((a+5)^6) '...[2, 3, 2]|[3, 1, 3]|[2, 3]|[1, 1, 1]|[0, 2, 3]|[4, 3, 4]' sage: repr((a-5)^6) @@ -1267,14 +1282,16 @@ def Qq(q, prec = None, type = 'capped-rel', modulus = None, names=None, sage: p = next_prime(2^123) sage: k = Qp(p) sage: R.<x> = k[] - sage: K = Qq([(p, 5)], modulus=x^5+x+4, names='a', ram_name='p', print_pos=False, check=False) + sage: K = Qq([(p, 5)], modulus=x^5+x+4, names='a', ram_name='p', + ....: print_pos=False, check=False) sage: K.0^5 (-a - 4) + O(p^20) In tests on ``sage.math.washington.edu``, the creation of ``K`` as above took an average of 1.58ms, while:: - sage: K = Qq(p^5, modulus=x^5+x+4, names='a', ram_name='p', print_pos=False, check=True) + sage: K = Qq(p^5, modulus=x^5+x+4, names='a', ram_name='p', + ....: print_pos=False, check=True) took an average of 24.5ms. Of course, with smaller primes these savings disappear. @@ -1326,7 +1343,7 @@ def Qq(q, prec = None, type = 'capped-rel', modulus = None, names=None, k = Integer(k) if check: - if not p.is_prime() or k <=0: + if not p.is_prime() or k <= 0: raise ValueError("q must be a prime power") if prec is not None and not isinstance(prec, Integer): @@ -1364,11 +1381,11 @@ def Qq(q, prec = None, type = 'capped-rel', modulus = None, names=None, # Short constructor names for different types ###################################################### -def QpCR(p, prec = None, *args, **kwds): +def QpCR(p, prec=None, *args, **kwds): r""" A shortcut function to create capped relative `p`-adic fields. - Same functionality as ``Qp``. See documentation for ``Qp`` for a + Same functionality as :func:`Qp`. See documentation for :func:`Qp` for a description of the input parameters. EXAMPLES:: @@ -1378,11 +1395,11 @@ def QpCR(p, prec = None, *args, **kwds): """ return Qp(p, prec, 'capped-rel', *args, **kwds) -def QpFP(p, prec = None, *args, **kwds): +def QpFP(p, prec=None, *args, **kwds): r""" A shortcut function to create floating point `p`-adic fields. - Same functionality as ``Qp``. See documentation for ``Qp`` for a + Same functionality as :func:`Qp`. See documentation for :func:`Qp` for a description of the input parameters. EXAMPLES:: @@ -1392,12 +1409,12 @@ def QpFP(p, prec = None, *args, **kwds): """ return Qp(p, prec, 'floating-point', *args, **kwds) -def QqCR(q, prec = None, *args, **kwds): +def QqCR(q, prec=None, *args, **kwds): r""" A shortcut function to create capped relative unramified `p`-adic fields. - Same functionality as ``Qq``. See documentation for ``Qq`` for a + Same functionality as :func:`Qq`. See documentation for :func:`Qq` for a description of the input parameters. EXAMPLES:: @@ -1407,12 +1424,12 @@ def QqCR(q, prec = None, *args, **kwds): """ return Qq(q, prec, 'capped-rel', *args, **kwds) -def QqFP(q, prec = None, *args, **kwds): +def QqFP(q, prec=None, *args, **kwds): r""" A shortcut function to create floating point unramified `p`-adic fields. - Same functionality as ``Qq``. See documentation for ``Qq`` for a + Same functionality as :func:`Qq`. See documentation for :func:`Qq` for a description of the input parameters. EXAMPLES:: @@ -1423,7 +1440,7 @@ def QqFP(q, prec = None, *args, **kwds): return Qq(q, prec, 'floating-point', *args, **kwds) @experimental(23505) -def QpLC(p, prec = None, *args, **kwds): +def QpLC(p, prec=None, *args, **kwds): r""" A shortcut function to create `p`-adic fields with lattice precision. @@ -1438,7 +1455,7 @@ def QpLC(p, prec = None, *args, **kwds): return Qp(p, prec, 'lattice-cap', *args, **kwds) @experimental(23505) -def QpLF(p, prec = None, *args, **kwds): +def QpLF(p, prec=None, *args, **kwds): r""" A shortcut function to create `p`-adic fields with lattice precision. @@ -1486,22 +1503,22 @@ class Zp_class(UniqueFactory): - ``prec`` -- integer (default: ``20``) the precision cap of the ring. In the lattice capped case, ``prec`` can either be a pair (``relative_cap``, ``absolute_cap``) or an integer - (understood at relative cap). + (understood as relative cap). In the relaxed case, ``prec`` can be either a pair (``default_prec``, ``halting_prec``) or an integer - (understood at default precision). + (understood as default precision). Except for the fixed modulus and floating point cases, individual elements keep track of their own precision. See TYPES and PRECISION below. - ``type`` -- string (default: ``'capped-rel'``) Valid types are ``'capped-rel'``, ``'capped-abs'``, ``'fixed-mod'``, - ``'floating-point'``, ``'lattice-cap'``, ``'lattice-float'``, ``'relaxed'`` - See TYPES and PRECISION below + ``'floating-point'``, ``'lattice-cap'``, ``'lattice-float'``, ``'relaxed'``. + See TYPES and PRECISION below. - ``print_mode`` -- string (default: ``None``). Valid modes are ``'series'``, ``'val-unit'``, ``'terse'``, ``'digits'``, and - ``'bars'``. See PRINTING below + ``'bars'``. See PRINTING below. - ``names`` -- string or tuple (defaults to a string representation of `p`). What to use whenever `p` is printed. @@ -1630,7 +1647,7 @@ class Zp_class(UniqueFactory): There are many different ways to print `p`-adic elements. The way elements of a given ring print is controlled by options passed in at the creation of the ring. There are five basic - printing modes (series, val-unit, terse, digits and bars), as + printing modes (``'series'``, ``'val-unit'``, ``'terse'``, ``'digits'`` and ``'bars'``), as well as various options that either hide some information in the print representation or sometimes make print representations more compact. Note that the printing options @@ -1641,7 +1658,9 @@ class Zp_class(UniqueFactory): sage: R = Zp(5, print_mode='series'); a = R(70700); a 3*5^2 + 3*5^4 + 2*5^5 + 4*5^6 + O(5^22) sage: b = R(-70700); b - 2*5^2 + 4*5^3 + 5^4 + 2*5^5 + 4*5^7 + 4*5^8 + 4*5^9 + 4*5^10 + 4*5^11 + 4*5^12 + 4*5^13 + 4*5^14 + 4*5^15 + 4*5^16 + 4*5^17 + 4*5^18 + 4*5^19 + 4*5^20 + 4*5^21 + O(5^22) + 2*5^2 + 4*5^3 + 5^4 + 2*5^5 + 4*5^7 + 4*5^8 + 4*5^9 + 4*5^10 + 4*5^11 + + 4*5^12 + 4*5^13 + 4*5^14 + 4*5^15 + 4*5^16 + 4*5^17 + 4*5^18 + + 4*5^19 + 4*5^20 + 4*5^21 + O(5^22) *print_pos* controls whether negatives can be used in the coefficients of powers of `p`. :: @@ -1768,12 +1787,13 @@ class Zp_class(UniqueFactory): greater than 9. Defaults to ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'):: - sage: T = Zp(5, print_mode='digits', print_alphabet=('1','2','3','4','5')); repr(T(-70700)) + sage: T = Zp(5, print_mode='digits', print_alphabet=('1','2','3','4','5')) + sage: repr(T(-70700)) '...5555555555555551325311' *show_prec* determines how the precision is printed. - It can be either 'none' (or equivalently ``False``), 'dots' - (or equivalently ``True``) or 'bigoh'. + It can be either ``'none'`` (or equivalently ``False``), ``'dots'`` + (or equivalently ``True``) or ``'bigoh'``. The default is ``False`` for the ``'floating-point'`` and ``'fixed-mod'`` types and ``True`` for all other types. :: @@ -1802,7 +1822,7 @@ class Zp_class(UniqueFactory): *print_pos* controls whether the digits can be negative. :: - sage: S = Zp(5, print_mode='bars',print_pos=False); b = S(-70700); repr(b) + sage: S = Zp(5, print_mode='bars', print_pos=False); b = S(-70700); repr(b) '...-1|0|2|2|-1|2|0|0' *print_max_terms* limits the number of digits that are printed. :: @@ -1835,7 +1855,7 @@ class Zp_class(UniqueFactory): EXAMPLES: - We allow non-prime `p`, but only if ``check = False``. Note that some + We allow non-prime `p`, but only if ``check=False``. Note that some features will not work. :: sage: K = Zp(15, check=False); a = K(999); a @@ -1857,7 +1877,8 @@ class Zp_class(UniqueFactory): It works even with a fairly huge cap:: sage: Zp(next_prime(10^50), 100000) - 100000000000000000000000000000000000000000000000151-adic Ring with capped relative precision 100000 + 100000000000000000000000000000000000000000000000151-adic Ring + with capped relative precision 100000 We create each type of ring:: @@ -1910,14 +1931,14 @@ class Zp_class(UniqueFactory): sage: a + b 1 + 5 + O(5^10) """ - def create_key(self, p, prec = None, type = 'capped-rel', print_mode = None, - names = None, ram_name = None, print_pos = None, print_sep = None, print_alphabet = None, - print_max_terms = None, show_prec = None, check = True, - label = None): + def create_key(self, p, prec=None, type='capped-rel', print_mode=None, + names=None, ram_name=None, print_pos=None, print_sep=None, print_alphabet=None, + print_max_terms=None, show_prec=None, check=True, + label=None): r""" Creates a key from input parameters for ``Zp``. - See the documentation for ``Zp`` for more information. + See the documentation for :func:`Zp` for more information. TESTS:: @@ -1955,7 +1976,7 @@ def create_object(self, version, key): r""" Creates an object using a given key. - See the documentation for ``Zp`` for more information. + See the documentation for :func:`Zp` for more information. TESTS:: @@ -2007,6 +2028,7 @@ def create_object(self, version, key): else: raise ValueError("unexpected type") + Zp = Zp_class("Zp") @@ -2014,10 +2036,10 @@ def create_object(self, version, key): # Zq -- unramified extensions ###################################################### -def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, - print_mode=None, ram_name = None, res_name = None, print_pos = None, - print_sep = None, print_max_ram_terms = None, - print_max_unram_terms = None, print_max_terse_terms = None, show_prec = None, check = True, implementation = 'FLINT'): +def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, + print_mode=None, ram_name=None, res_name=None, print_pos=None, + print_sep=None, print_max_ram_terms=None, + print_max_unram_terms=None, print_max_terse_terms=None, show_prec=None, check=True, implementation='FLINT'): r""" Given a prime power `q = p^n`, return the unique unramified extension of `\ZZ_p` of degree `n`. @@ -2025,7 +2047,7 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, INPUT: - ``q`` -- integer, list or tuple: the prime power in `\QQ_q`. Or a - factorization object, single element list ``[(p, n)]`` where ``p`` is + :class:`Factorization` object, single element list ``[(p, n)]`` where ``p`` is a prime and ``n`` a positive integer, or the pair ``(p, n)``. - ``prec`` -- integer (default: ``20``) the precision cap of the @@ -2034,9 +2056,9 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, - ``type`` -- string (default: ``'capped-rel'``) Valid types are ``'capped-abs'``, ``'capped-rel'``, ``'fixed-mod'``, and - ``'floating-point'``. See TYPES and PRECISION below + ``'floating-point'``. See TYPES and PRECISION below. - - modulus -- polynomial (default None) A polynomial defining an + - ``modulus`` -- polynomial (default None) A polynomial defining an unramified extension of `\ZZ_p`. See MODULUS below. - ``names`` -- string or tuple (``None`` is only allowed when @@ -2047,12 +2069,12 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, ``'val-unit'``, ``'terse'``, and ``'bars'``. See PRINTING below. - ``ram_name`` -- string (defaults to string representation of `p` if - None). ``ram_name`` controls how the prime is printed. See PRINTING + ``None``). ``ram_name`` controls how the prime is printed. See PRINTING below. - ``res_name`` -- string (defaults to ``None``, which corresponds to adding a ``'0'`` to the end of the name). Controls how - elements of the reside field print. + elements of the residue field print. - ``print_pos`` -- bool (default ``None``) Whether to only use positive integers in the representations of elements. See @@ -2077,12 +2099,12 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, - ``check`` -- bool (default ``True``) whether to check inputs. - - ``implementation`` -- string (default ``FLINT``) which - implementation to use. ``NTL`` is the other option. + - ``implementation`` -- string (default ``'FLINT'``) which + implementation to use. ``'NTL'`` is the other option. OUTPUT: - - The corresponding unramified `p`-adic ring. + The corresponding unramified `p`-adic ring. TYPES AND PRECISION: @@ -2205,10 +2227,10 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, 2. The modulus can also be given as a **symbolic expression**. :: - sage: x = var('x') - sage: X.<a> = Zq(27, modulus = x^3 + 2*x + 1); X.modulus() + sage: x = var('x') # needs sage.symbolic + sage: X.<a> = Zq(27, modulus = x^3 + 2*x + 1); X.modulus() # needs sage.symbolic (1 + O(3^20))*x^3 + O(3^20)*x^2 + (2 + O(3^20))*x + 1 + O(3^20) - sage: X == R + sage: X == R # needs sage.symbolic True By default, the polynomial chosen is the standard lift of the @@ -2284,7 +2306,7 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, '(...)*2 + (...)*2^2 + (...)*2^3 + (...)*2^4 + (...)*2^5 + (...)*2^6 + (...)*2^7 + O(2^8)' *show_prec* determines how the precision is printed. - It can be either 'none' (or equivalently ``False``), 'bigoh' + It can be either ``'none'`` (or equivalently ``False``), ``'bigoh'`` (or equivalently ``True``). The default is ``False`` for the ``'floating-point'`` and ``'fixed-mod'`` types and ``True`` for all other types. :: @@ -2317,19 +2339,23 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, *ram_name* affects how the prime is printed. :: sage: A.<x> = Zp(next_prime(10^6), print_mode='val-unit')[] - sage: T.<a> = Zq(next_prime(10^6)^3, 4, print_mode='val-unit', ram_name='p', modulus=x^3+385831*x^2+106556*x+321036); b = (next_prime(10^6)^2*(a^2 + a - 4)^4); b - p^2 * (87996187118837557387483 + 246348888344392418464080*a + 1353538653775332610349*a^2) + O(p^6) + sage: T.<a> = Zq(next_prime(10^6)^3, 4, print_mode='val-unit', ram_name='p', + ....: modulus=x^3+385831*x^2+106556*x+321036) + sage: b = next_prime(10^6)^2*(a^2 + a - 4)^4; b + p^2 * (87996187118837557387483 + 246348888344392418464080*a + 1353538653775332610349*a^2) + + O(p^6) sage: b * (a^2 + a - 4)^-4 p^2 * 1 + O(p^6) *print_max_terse_terms* controls how many terms of the polynomial appear in the unit part. :: - sage: U.<a> = Zq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3); b = (17*(a^3-a+14)^6); b + sage: U.<a> = Zq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3) + sage: b = 17*(a^3-a+14)^6; b 17 * (12131797 + 12076378*a + 10809706*a^2 + ...) + O(17^7) *show_prec* determines how the precision is printed. - It can be either 'none' (or equivalently ``False``), 'bigoh' + It can be either ``'none'`` (or equivalently ``False``), ``'bigoh'`` (or equivalently ``True``). The default is ``False`` for the ``'floating-point'`` and ``'fixed-mod'`` types and ``True`` for all other types. :: @@ -2386,7 +2412,7 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, 106251/5^6 + 49994/5^5*a + ... + O(5^14) *show_prec* determines how the precision is printed. - It can be either 'none' (or equivalently ``False``), 'bigoh' + It can be either ``'none'`` (or equivalently ``False``), ``'bigoh'`` (or equivalently ``True``). The default is ``False`` for the ``'floating-point'`` and ``'fixed-mod'`` types and ``True`` for all other types. :: @@ -2410,7 +2436,8 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, but more compactly. :: sage: R.<a> = Zq(125); (a+5)^6 - (4*a^2 + 3*a + 4) + (3*a^2 + 2*a)*5 + (a^2 + a + 1)*5^2 + (3*a + 2)*5^3 + (3*a^2 + a + 3)*5^4 + (2*a^2 + 3*a + 2)*5^5 + O(5^20) + (4*a^2 + 3*a + 4) + (3*a^2 + 2*a)*5 + (a^2 + a + 1)*5^2 + (3*a + 2)*5^3 + + (3*a^2 + a + 3)*5^4 + (2*a^2 + 3*a + 2)*5^5 + O(5^20) sage: R.<a> = Zq(125, print_mode='bars', prec=8); repr((a+5)^6) '...[2, 3, 2]|[3, 1, 3]|[2, 3]|[1, 1, 1]|[0, 2, 3]|[4, 3, 4]' sage: repr((a-5)^6) @@ -2464,8 +2491,8 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, '...[...][...][...][...][][...][...]' *show_prec* determines how the precision is printed. - It can be either 'none' (or equivalently ``False``), 'dots' - (or equivalently ``True``) or 'bigoh'. + It can be either ``'none'`` (or equivalently ``False``), ``'dots'`` + (or equivalently ``True``) or ``'bigoh'``. The default is ``False`` for the ``'floating-point'`` and ``'fixed-mod'`` types and ``True`` for all other types. :: @@ -2481,7 +2508,7 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, EXAMPLES: - Unlike for ``Zp``, you can't create ``Zq(N)`` when ``N`` is not a prime power. + Unlike for :func:`Zp`, you can't create ``Zq(N)`` when ``N`` is not a prime power. However, you can use ``check=False`` to pass in a pair in order to not have to factor. If you do so, you need to use names explicitly @@ -2490,14 +2517,16 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, sage: p = next_prime(2^123) sage: k = Zp(p) sage: R.<x> = k[] - sage: K = Zq([(p, 5)], modulus=x^5+x+4, names='a', ram_name='p', print_pos=False, check=False) + sage: K = Zq([(p, 5)], modulus=x^5+x+4, names='a', ram_name='p', + ....: print_pos=False, check=False) sage: K.0^5 (-a - 4) + O(p^20) In tests on sage.math, the creation of ``K`` as above took an average of 1.58ms, while:: - sage: K = Zq(p^5, modulus=x^5+x+4, names='a', ram_name='p', print_pos=False, check=True) + sage: K = Zq(p^5, modulus=x^5+x+4, names='a', ram_name='p', + ....: print_pos=False, check=True) took an average of 24.5ms. Of course, with smaller primes these savings disappear. @@ -2535,7 +2564,7 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, if isinstance(names, (list, tuple)): names = names[0] from sage.structure.element import Expression - if not (modulus is None or is_Polynomial(modulus) or isinstance(modulus, Expression)): + if not (modulus is None or isinstance(modulus, Polynomial) or isinstance(modulus, Expression)): raise TypeError("modulus must be a polynomial") if names is not None and not isinstance(names, str): names = str(names) @@ -2572,11 +2601,11 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, # Short constructor names for different types ###################################################### -def ZpCR(p, prec = None, *args, **kwds): +def ZpCR(p, prec=None, *args, **kwds): r""" A shortcut function to create capped relative `p`-adic rings. - Same functionality as ``Zp``. See documentation for ``Zp`` for a + Same functionality as :func:`Zp`. See documentation for :func:`Zp` for a description of the input parameters. EXAMPLES:: @@ -2586,7 +2615,7 @@ def ZpCR(p, prec = None, *args, **kwds): """ return Zp(p, prec, 'capped-rel', *args, **kwds) -def ZpCA(p, prec = None, *args, **kwds): +def ZpCA(p, prec=None, *args, **kwds): r""" A shortcut function to create capped absolute `p`-adic rings. @@ -2599,7 +2628,7 @@ def ZpCA(p, prec = None, *args, **kwds): """ return Zp(p, prec, 'capped-abs', *args, **kwds) -def ZpFM(p, prec = None, *args, **kwds): +def ZpFM(p, prec=None, *args, **kwds): r""" A shortcut function to create fixed modulus `p`-adic rings. @@ -2612,11 +2641,11 @@ def ZpFM(p, prec = None, *args, **kwds): """ return Zp(p, prec, 'fixed-mod', *args, **kwds) -def ZpFP(p, prec = None, *args, **kwds): +def ZpFP(p, prec=None, *args, **kwds): r""" A shortcut function to create floating point `p`-adic rings. - Same functionality as ``Zp``. See documentation for ``Zp`` for a + Same functionality as :func:`Zp`. See documentation for :func:`Zp` for a description of the input parameters. EXAMPLES:: @@ -2626,11 +2655,11 @@ def ZpFP(p, prec = None, *args, **kwds): """ return Zp(p, prec, 'floating-point', *args, **kwds) -def ZqCR(q, prec = None, *args, **kwds): +def ZqCR(q, prec=None, *args, **kwds): r""" A shortcut function to create capped relative unramified `p`-adic rings. - Same functionality as ``Zq``. See documentation for ``Zq`` for a + Same functionality as :func:`Zq`. See documentation for :func:`Zq` for a description of the input parameters. EXAMPLES:: @@ -2640,7 +2669,7 @@ def ZqCR(q, prec = None, *args, **kwds): """ return Zq(q, prec, 'capped-rel', *args, **kwds) -def ZqCA(q, prec = None, *args, **kwds): +def ZqCA(q, prec=None, *args, **kwds): r""" A shortcut function to create capped absolute unramified `p`-adic rings. @@ -2653,7 +2682,7 @@ def ZqCA(q, prec = None, *args, **kwds): """ return Zq(q, prec, 'capped-abs', *args, **kwds) -def ZqFM(q, prec = None, *args, **kwds): +def ZqFM(q, prec=None, *args, **kwds): r""" A shortcut function to create fixed modulus unramified `p`-adic rings. @@ -2666,11 +2695,11 @@ def ZqFM(q, prec = None, *args, **kwds): """ return Zq(q, prec, 'fixed-mod', *args, **kwds) -def ZqFP(q, prec = None, *args, **kwds): +def ZqFP(q, prec=None, *args, **kwds): r""" A shortcut function to create floating point unramified `p`-adic rings. - Same functionality as ``Zq``. See documentation for ``Zq`` for a + Same functionality as :func:`Zq`. See documentation for :func:`Zq` for a description of the input parameters. EXAMPLES:: @@ -3019,7 +3048,7 @@ def ZpER(p, prec=None, halt=None, secure=False, *args, **kwds): 40 However, both the default precision and the halting precision can be - customized at the creation of the parent as follows: + customized at the creation of the parent as follows:: sage: S = ZpER(5, prec=10, halt=100) sage: S.default_prec() @@ -3110,7 +3139,7 @@ def ZpER(p, prec=None, halt=None, secure=False, *args, **kwds): sage: a == aa False - This annoying situation, where the output of `a == aa` may change + This annoying situation, where the output of ``a == aa`` may change depending on previous computations, cannot occur when the parent is created with ``secure=True``. Indeed, in this case, if the equality cannot be decided, an error @@ -3202,22 +3231,22 @@ class pAdicExtension_class(UniqueFactory): sage: R = Zp(5,3) sage: S.<x> = ZZ[] - sage: W.<w> = pAdicExtension(R, x^4-15) + sage: W.<w> = pAdicExtension(R, x^4 - 15) sage: W 5-adic Eisenstein Extension Ring in w defined by x^4 - 15 sage: W.precision_cap() 12 """ - def create_key_and_extra_args(self, base, modulus, prec = None, print_mode = None, - names = None, var_name = None, res_name = None, - unram_name = None, ram_name = None, print_pos = None, - print_sep = None, print_alphabet = None, print_max_ram_terms = None, - print_max_unram_terms = None, print_max_terse_terms = None, - show_prec = None, check = True, unram = False, implementation='FLINT'): + def create_key_and_extra_args(self, base, modulus, prec=None, print_mode=None, + names=None, var_name=None, res_name=None, + unram_name=None, ram_name=None, print_pos=None, + print_sep=None, print_alphabet=None, print_max_ram_terms=None, + print_max_unram_terms=None, print_max_terse_terms=None, + show_prec=None, check=True, unram=False, implementation='FLINT'): r""" - Creates a key from input parameters for pAdicExtension. + Creates a key from input parameters for :class:`pAdicExtension`. - See the documentation for ``Qq`` for more information. + See the documentation for :func:`Qq` for more information. TESTS:: @@ -3278,7 +3307,7 @@ def create_key_and_extra_args(self, base, modulus, prec = None, print_mode = Non raise ValueError("symbolic expression must be in only one variable") exact_modulus = modulus.polynomial(base.exact_field()) approx_modulus = modulus.polynomial(base) - elif is_Polynomial(modulus): + elif isinstance(modulus, Polynomial): if modulus.parent().ngens() != 1: raise ValueError("must use univariate polynomial") exact_modulus = modulus.change_ring(base.exact_field()) @@ -3362,7 +3391,7 @@ def create_object(self, version, key, approx_modulus=None, shift_seed=None): r""" Creates an object using a given key. - See the documentation for pAdicExtension for more information. + See the documentation for :class:`pAdicExtension` for more information. TESTS:: @@ -3381,7 +3410,7 @@ def create_object(self, version, key, approx_modulus=None, shift_seed=None): from sage.structure.element import Expression if isinstance(premodulus, Expression): exact_modulus = premodulus.polynomial(base.exact_field()) - elif is_Polynomial(premodulus): + elif isinstance(premodulus, Polynomial): exact_modulus = premodulus.change_ring(base.exact_field()) show_prec = None else: @@ -3404,8 +3433,10 @@ def create_object(self, version, key, approx_modulus=None, shift_seed=None): 'max_ram_terms': print_max_ram_terms, 'max_unram_terms': print_max_unram_terms, 'max_terse_terms': print_max_terse_terms, 'show_prec': show_prec}, shift_seed, names, implementation) + ExtensionFactory = pAdicExtension = pAdicExtension_class("pAdicExtension") + ###################################################### # Helper functions for the Extension Factory ###################################################### @@ -3425,11 +3456,12 @@ def split(poly, prec): sage: k = Qp(13) sage: x = polygen(k) - sage: f = x^2+1 + sage: f = x^2 + 1 sage: sage.rings.padics.factory.split(f, 10) Traceback (most recent call last): ... - NotImplementedError: Extensions by general polynomials not yet supported. Please use an unramified or Eisenstein polynomial. + NotImplementedError: Extensions by general polynomials not yet supported. + Please use an unramified or Eisenstein polynomial. TESTS: @@ -3463,24 +3495,24 @@ def truncate_to_prec(poly, R, absprec): def krasner_check(poly, prec): r""" - Returns True iff poly determines a unique isomorphism class of - extensions at precision prec. + Return ``True`` iff ``poly`` determines a unique isomorphism class of + extensions at precision ``prec``. - Currently just returns True (thus allowing extensions that are not + Currently just returns ``True`` (thus allowing extensions that are not defined to high enough precision in order to specify them up to isomorphism). This will change in the future. EXAMPLES:: sage: from sage.rings.padics.factory import krasner_check - sage: krasner_check(1,2) #this is a stupid example. + sage: krasner_check(1,2) # this is a stupid example. True """ return True #This needs to be implemented def is_eisenstein(poly): r""" - Returns True iff this monic polynomial is Eisenstein. + Return ``True`` iff this monic polynomial is Eisenstein. A polynomial is Eisenstein if it is monic, the constant term has valuation 1 and all other terms have positive valuation. @@ -3508,7 +3540,7 @@ def is_eisenstein(poly): def is_unramified(poly): r""" - Returns true iff this monic polynomial is unramified. + Return ``True`` iff this monic polynomial is unramified. A polynomial is unramified if its reduction modulo the maximal ideal is irreducible. diff --git a/src/sage/rings/padics/generic_nodes.py b/src/sage/rings/padics/generic_nodes.py index 3c5d9c2aaf5..7047020edec 100644 --- a/src/sage/rings/padics/generic_nodes.py +++ b/src/sage/rings/padics/generic_nodes.py @@ -272,7 +272,7 @@ class pAdicLatticeGeneric(pAdicGeneric): INPUT: - - `p` -- the underlying prime number + - ``p`` -- the underlying prime number - ``prec`` -- the precision @@ -616,7 +616,7 @@ def convert_multiple(self, *elts): 6 As a consequence, if we convert ``x`` and ``y`` separately, we - loose some precision:: + lose some precision:: sage: R2 = ZpLC(2, label='copy') sage: x2 = R2(x); y2 = R2(y) @@ -706,7 +706,7 @@ class pAdicRelaxedGeneric(pAdicGeneric): INPUT: - - `p` -- the underlying prime number + - ``p`` -- the underlying prime number - ``prec`` -- the default precision @@ -777,7 +777,7 @@ def is_relaxed(self): def is_secure(self): r""" Return ``False`` if this `p`-adic relaxed ring is not secure - (i.e. if indistinguishable elements at the working precision + (i.e., if indistinguishable elements at the working precision are considered as equal); ``True`` otherwise (in which case, an error is raised when equality cannot be decided). @@ -1135,7 +1135,8 @@ def random_element(self, integral=False, prec=None): sage: b = R.random_element(prec=15) sage: b # random - 2 + 3*5^2 + 5^3 + 3*5^4 + 5^5 + 3*5^6 + 3*5^8 + 3*5^9 + 4*5^10 + 5^11 + 4*5^12 + 5^13 + 2*5^14 + O(5^15) + 2 + 3*5^2 + 5^3 + 3*5^4 + 5^5 + 3*5^6 + 3*5^8 + 3*5^9 + 4*5^10 + + 5^11 + 4*5^12 + 5^13 + 2*5^14 + O(5^15) sage: b.precision_absolute() 15 """ @@ -1179,28 +1180,8 @@ def teichmuller_system(self): return [ self.teichmuller(ZZ(i)) for i in R if i != 0 ] -def is_pAdicRing(R): - """ - Return ``True`` if and only if ``R`` is a `p`-adic ring (not a - field). - - EXAMPLES:: - - sage: is_pAdicRing(Zp(5)) - doctest:warning... - DeprecationWarning: is_pAdicRing is deprecated; use isinstance(..., sage.rings.abc.pAdicRing) instead - See https://github.com/sagemath/sage/issues/32750 for details. - True - sage: is_pAdicRing(RR) - False - """ - from sage.misc.superseded import deprecation - deprecation(32750, "is_pAdicRing is deprecated; use isinstance(..., sage.rings.abc.pAdicRing) instead") - return isinstance(R, pAdicRingGeneric) - - class pAdicRingGeneric(pAdicGeneric, sage.rings.abc.pAdicRing): - def is_field(self, proof = True): + def is_field(self, proof=True): """ Return whether this ring is actually a field, ie ``False``. @@ -1211,7 +1192,6 @@ def is_field(self, proof = True): """ return False - def krull_dimension(self): r""" Return the Krull dimension of self, i.e. 1 @@ -1326,25 +1306,6 @@ def _gcd_univariate_polynomial(self, f, g): return self._xgcd_univariate_polynomial(f, g)[0] -def is_pAdicField(R): - """ - Return ``True`` if and only if ``R`` is a `p`-adic field. - - EXAMPLES:: - - sage: is_pAdicField(Zp(17)) - doctest:warning... - DeprecationWarning: is_pAdicField is deprecated; use isinstance(..., sage.rings.abc.pAdicField) instead - See https://github.com/sagemath/sage/issues/32750 for details. - False - sage: is_pAdicField(Qp(17)) - True - """ - from sage.misc.superseded import deprecation - deprecation(32750, "is_pAdicField is deprecated; use isinstance(..., sage.rings.abc.pAdicField) instead") - return isinstance(R, pAdicFieldGeneric) - - class pAdicFieldGeneric(pAdicGeneric, sage.rings.abc.pAdicField): pass @@ -1394,11 +1355,11 @@ class pAdicFloatingPointFieldGeneric(pAdicFieldGeneric, FloatingPointFieldGeneri class pAdicRingBaseGeneric(pAdicBaseGeneric, pAdicRingGeneric): def construction(self, forbid_frac_field=False): """ - Return the functorial construction of self, namely, - completion of the rational numbers with respect a given prime. + Return the functorial construction of ``self``, namely, + completion of the rational numbers with respect to a given prime. Also preserves other information that makes this field unique - (e.g. precision, rounding, print mode). + (e.g., precision, rounding, print mode). INPUT: @@ -1423,24 +1384,30 @@ def construction(self, forbid_frac_field=False): sage: S = F(Z) sage: S._precision_cap() (31, 41) + + The `secure` attribute for relaxed type is included in the functor:: + + sage: R = ZpER(5, secure=True) + sage: R.construction() + (Completion[5, prec=(20, 40, True)], Integer Ring) """ from sage.categories.pushout import CompletionFunctor extras = {'print_mode':self._printer.dict(), 'type':self._prec_type(), 'names':self._names} if hasattr(self, '_label'): extras['label'] = self._label if self._prec_type() == "relaxed": - prec = (self._default_prec, self._halting_prec) + prec = (self._default_prec, self._halting_prec, self._secure) else: prec = self._precision_cap() return (CompletionFunctor(self.prime(), prec, extras), ZZ) def random_element(self, algorithm='default'): r""" - Return a random element of self, optionally using the - algorithm argument to decide how it generates the + Return a random element of ``self``, optionally using the + ``algorithm`` argument to decide how it generates the element. Algorithms currently implemented: - - default: Choose `a_i`, `i >= 0`, randomly between `0` and + - ``'default'``: Choose `a_i`, `i \geq 0`, randomly between `0` and `p-1` until a nonzero choice is made. Then continue choosing `a_i` randomly between `0` and `p-1` until we reach precision_cap, and return `\sum a_i p^i`. @@ -1465,7 +1432,7 @@ def random_element(self, algorithm='default'): else: return self(ZZ.random_element(self.prime_pow.pow_Integer_Integer(self.precision_cap()))) else: - raise NotImplementedError("Don't know %s algorithm"%algorithm) + raise NotImplementedError("Don't know %s algorithm" % algorithm) #def unit_group(self): # raise NotImplementedError @@ -1479,7 +1446,7 @@ def random_element(self, algorithm='default'): class pAdicFieldBaseGeneric(pAdicBaseGeneric, pAdicFieldGeneric): def composite(self, subfield1, subfield2): r""" - Return the composite of two subfields of self, i.e., the + Return the composite of two subfields of ``self``, i.e., the largest subfield containing both INPUT: @@ -1490,7 +1457,7 @@ def composite(self, subfield1, subfield2): OUTPUT: - - the composite of subfield1 and subfield2 + the composite of ``subfield1`` and ``subfield2`` EXAMPLES:: @@ -1504,7 +1471,7 @@ def composite(self, subfield1, subfield2): def subfields_of_degree(self, n): r""" - Return the number of subfields of self of degree `n` + Return the number of subfields of ``self`` of degree `n` INPUT: @@ -1513,7 +1480,7 @@ def subfields_of_degree(self, n): OUTPUT: - - integer -- the number of subfields of degree ``n`` over self.base_ring() + integer -- the number of subfields of degree `n` over ``self.base_ring()`` EXAMPLES:: @@ -1528,7 +1495,7 @@ def subfields_of_degree(self, n): def subfield(self, list): r""" - Return the subfield generated by the elements in list + Return the subfield generated by the elements in ``list`` INPUT: @@ -1537,7 +1504,7 @@ def subfield(self, list): OUTPUT: - - the subfield of ``self`` generated by the elements of list + the subfield of ``self`` generated by the elements of ``list`` EXAMPLES:: @@ -1555,7 +1522,7 @@ def construction(self, forbid_frac_field=False): completion of the rational numbers with respect a given prime. Also preserves other information that makes this field unique - (e.g. precision, rounding, print mode). + (e.g., precision, rounding, print mode). INPUT: @@ -1595,6 +1562,12 @@ def construction(self, forbid_frac_field=False): sage: S = F(Z) sage: S._precision_cap() (31, 41) + + The `secure` attribute for relaxed type is included in the functor:: + + sage: K = QpER(5, secure=True) + sage: K.construction(forbid_frac_field=True) + (Completion[5, prec=(20, 40, True)], Rational Field) """ from sage.categories.pushout import FractionField, CompletionFunctor if forbid_frac_field: @@ -1602,7 +1575,7 @@ def construction(self, forbid_frac_field=False): if hasattr(self, '_label'): extras['label'] = self._label if self._prec_type() == "relaxed": - prec = (self._default_prec, self._halting_prec) + prec = (self._default_prec, self._halting_prec, self._secure) else: prec = self._precision_cap() return (CompletionFunctor(self.prime(), prec, extras), QQ) diff --git a/src/sage/rings/padics/lattice_precision.py b/src/sage/rings/padics/lattice_precision.py index 654ba06bfe7..9c76ff88362 100644 --- a/src/sage/rings/padics/lattice_precision.py +++ b/src/sage/rings/padics/lattice_precision.py @@ -32,7 +32,7 @@ from collections import defaultdict -from sage.misc.misc import walltime +from sage.misc.timing import walltime from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation @@ -60,7 +60,7 @@ class pRational: r""" This class implements rational numbers viewed as elements of ``Qp``. In particular, it provides additional methods which are specific to - ``p``-adics (as ``p``-adic valuation). + `p`-adics (as `p`-adic valuation). Only for internal use. @@ -72,8 +72,8 @@ class pRational: - ``exponent`` -- an integer (default: 0) - - ``valuation`` -- an integer or None (default: ``None``), - the ``p``-adic valuation of this element + - ``valuation`` -- an integer or ``None`` (default: ``None``), + the `p`-adic valuation of this element If not ``None``, this method trusts the given value to the attribute ``valuation``. @@ -259,7 +259,7 @@ def valuation(self): def is_p_power(self): r""" - Return true if this element is a power of `p`. + Return ``True`` if this element is a power of `p`. TESTS:: @@ -279,7 +279,7 @@ def is_p_power(self): def is_zero(self): r""" - Return true if this element vanishes. + Return ``True`` if this element vanishes. TESTS:: @@ -440,7 +440,6 @@ def _quo_rem(self, other): return (self.__class__(self.p, (sx - sred)/(pd*ox), 0), self.__class__(self.p, sred, sval, valuation=sval)) - def __lshift__(self, n): r""" Return the product of this element by ``p^n``. @@ -504,7 +503,7 @@ def unit_part(self): def xgcd(self, other): r""" Return the gcd of ``self`` and ``other`` together with two - element ``u`` and ``v`` such that ``u*self + v*other = gcd``. + elements ``u`` and ``v`` such that ``u*self + v*other = gcd``. The ``gcd`` is normalized so that it is a power of `p`. @@ -677,9 +676,9 @@ def _repr_(self): sage: R.precision() Precision lattice on 0 objects (label: mylabel) """ - label = "" if self._label is None else " (label: %s)"%(self._label,) - count = "1 object" if len(self._elements) == 1 else "%s objects"%len(self._elements) - return "%s on %s%s"%(self._repr_type, count, label) + label = "" if self._label is None else " (label: %s)" % (self._label,) + count = "1 object" if len(self._elements) == 1 else "%s objects" % len(self._elements) + return "%s on %s%s" % (self._repr_type, count, label) def threshold_deletion(self, threshold=None): r""" @@ -974,7 +973,7 @@ def precision_lattice(self, elements=None): [ 0 2048] If the precision module does not project to a lattice, - an error is raised. + an error is raised. :: sage: R = ZpLF(2, label='precision_lattice') sage: prec = R.precision() @@ -1250,7 +1249,6 @@ def _format_history(self, time, status, timings): else: return status - def history(self, compact=True, separate_reduce=False, timings=True, output_type='asciiart'): r""" Show history. @@ -1485,20 +1483,20 @@ def timings(self, action=None): INPUT: - - ``action`` -- ``None`` (the default), ``add``, ``mark``, ``del``, - ``partial reduce`` or ``full reduce``; if not None, return the + - ``action`` -- ``None`` (the default), ``'add'``, ``'mark'``, ``'del'``, + ``'partial reduce'`` or ``'full reduce'``; if not ``None``, return the cumulated timing corresponding to this action; otherwise, return a dictionary Here are the meanings of the keywords above: - - ``add``: time spent in adding new columns to the precision matrix + - ``'add'``: time spent in adding new columns to the precision matrix (corresponding to the creation of new elements) - - ``mark``: time spent in marking elements for deletion - - ``del``: time spent in deleting columns of the precision matrix + - ``'mark'``: time spent in marking elements for deletion + - ``'del'``: time spent in deleting columns of the precision matrix and re-echelonizing the matrix - - ``partial reduce``: time spent in partial Hermite reduction - - ``full reduce``: time spent in full Hermite reduction. + - ``'partial reduce'``: time spent in partial Hermite reduction + - ``'full reduce'``: time spent in full Hermite reduction. EXAMPLES:: @@ -2689,7 +2687,7 @@ def precision_lattice(self, elements=None): [ 0 2048] If the precision module does not project to a lattice, - an error is raised. + an error is raised. :: sage: prec.precision_lattice([x, y, u, v]) Traceback (most recent call last): @@ -2788,7 +2786,7 @@ def __init__(self, element, callback=None): """ if not hasattr(element, '_proxy_id'): element._proxy_id = pAdicLatticeElementWeakProxy._next_id - pAdicLatticeElementWeakProxy._next_id +=1 + pAdicLatticeElementWeakProxy._next_id += 1 self._id = element._proxy_id from weakref import ref proxy_callback = callback @@ -2858,12 +2856,12 @@ def __repr__(self): [WeakProxy#...] """ - return "WeakProxy#%s"%(self._id,) + return "WeakProxy#%s" % (self._id,) def list_of_padics(elements): r""" - Convert a list of p-adic composed elements (such as polynomials, matrices) - to a list of weak references of their p-adic coefficients. + Convert a list of `p`-adic composed elements (such as polynomials, matrices) + to a list of weak references of their `p`-adic coefficients. This is a helper function for the method :meth:`precision_lattice`. diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 2168d2e348b..5726055d2be 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.padics r""" Local Generic @@ -230,7 +231,7 @@ def _latex_(self): sage: latex(Zq(27,names='a')) #indirect doctest \Bold{Z}_{3^{3}} """ - return self._repr_(do_latex = True) + return self._repr_(do_latex=True) def change(self, **kwds): r""" @@ -375,6 +376,25 @@ def change(self, **kwds): 37-adic Ring with lattice-cap precision (label: change) sage: S.change(label = "new") 37-adic Ring with lattice-cap precision (label: new) + + + TESTS: + + The `secure` attribute for relaxed type is copied:: + + sage: R = ZpER(5, secure=True); R + 5-adic Ring handled with relaxed arithmetics + sage: K = R.change(field=True); K + 5-adic Field handled with relaxed arithmetics + sage: K.is_secure() + True + + The `check=False` option works for relaxed type:: + + sage: R = ZpER(5) ; R + 5-adic Ring handled with relaxed arithmetics + sage: K = R.change(field=True, check=False) ; K + 5-adic Field handled with relaxed arithmetics """ # We support both print_* and * for *=mode, pos, sep, alphabet for atr in ('print_mode', 'print_pos', 'print_sep', 'print_alphabet'): @@ -432,7 +452,7 @@ def get_unramified_modulus(q, res_name): functor.extras = copy(functor.extras) functor.extras['print_mode'] = copy(functor.extras['print_mode']) if 'type' in kwds and kwds['type'] not in functor._dvr_types: - raise ValueError("completion type must be one of %s"%(", ".join(functor._dvr_types[1:]))) + raise ValueError("completion type must be one of %s" % (", ".join(functor._dvr_types[1:]))) if 'field' in kwds: field = kwds.pop('field') if field: @@ -473,7 +493,7 @@ def get_unramified_modulus(q, res_name): if atr in kwds: functor.extras['print_mode'][atr] = kwds.pop(atr) if kwds: - raise ValueError("Extra arguments received: %s"%(", ".join(kwds.keys()))) + raise ValueError("Extra arguments received: %s" % (", ".join(kwds.keys()))) if q is not None: # Create an unramified extension base = functor(ring) @@ -682,7 +702,6 @@ def ground_ring_of_tower(self): """ return self - def absolute_degree(self): r""" Return the degree of this extension over the prime p-adic field/ring. @@ -736,7 +755,6 @@ def degree(self): else: raise NotImplementedError("For a relative p-adic ring or field you must use relative_degree or absolute_degree as appropriate") - def absolute_e(self): r""" Return the absolute ramification index of this ring/field. @@ -844,7 +862,6 @@ def ramification_index(self): """ return self.e() - def absolute_f(self): r""" Return the degree of the residue field of this ring/field @@ -1172,7 +1189,6 @@ def _matrix_flatten_precision(self, M): M[i,j] <<= s return shift_rows, shift_cols - def _matrix_smith_form(self, M, transformation, integral, exact): r""" Return the Smith normal form of the matrix `M`. diff --git a/src/sage/rings/padics/local_generic_element.pyx b/src/sage/rings/padics/local_generic_element.pyx index e7b9ba76b80..6c78114f395 100644 --- a/src/sage/rings/padics/local_generic_element.pyx +++ b/src/sage/rings/padics/local_generic_element.pyx @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.rings.padics """ Local Generic Element @@ -23,7 +23,7 @@ AUTHORS: # **************************************************************************** from sage.rings.infinity import infinity -from sage.structure.element cimport ModuleElement, RingElement, CommutativeRingElement +from sage.structure.element cimport CommutativeRingElement from sage.structure.element import coerce_binop from itertools import islice diff --git a/src/sage/rings/padics/misc.py b/src/sage/rings/padics/misc.py index 71f9e80ed99..b535dbb07c5 100644 --- a/src/sage/rings/padics/misc.py +++ b/src/sage/rings/padics/misc.py @@ -71,9 +71,9 @@ def gauss_sum(a, p, f, prec=20, factored=False, algorithm='pari', parent=None): - ``prec`` -- positive integer (optional, 20 by default) - - ``factored`` - boolean (optional, False by default) + - ``factored`` -- boolean (optional, ``False`` by default) - - ``algorithm`` - flag passed to p-adic Gamma function (optional, "pari" by default) + - ``algorithm`` -- flag passed to p-adic Gamma function (optional, ``"pari"`` by default) OUTPUT: @@ -91,25 +91,25 @@ def gauss_sum(a, p, f, prec=20, factored=False, algorithm='pari', parent=None): In this example, we verify that `g_3(0) = -1`:: sage: from sage.rings.padics.misc import gauss_sum - sage: -gauss_sum(0,3,1) + sage: -gauss_sum(0, 3, 1) # needs sage.rings.padics 1 + O(pi^40) Next, we verify that `g_5(a) g_5(-a) = 5 (-1)^a`:: sage: from sage.rings.padics.misc import gauss_sum - sage: gauss_sum(2,5,1)^2-5 + sage: gauss_sum(2,5,1)^2 - 5 # needs sage.rings.padics O(pi^84) - sage: gauss_sum(1,5,1)*gauss_sum(3,5,1)+5 + sage: gauss_sum(1,5,1)*gauss_sum(3,5,1) + 5 # needs sage.rings.padics O(pi^84) Finally, we compute a non-trivial value:: sage: from sage.rings.padics.misc import gauss_sum - sage: gauss_sum(2,13,2) + sage: gauss_sum(2,13,2) # needs sage.rings.padics 6*pi^2 + 7*pi^14 + 11*pi^26 + 3*pi^62 + 6*pi^74 + 3*pi^86 + 5*pi^98 + pi^110 + 7*pi^134 + 9*pi^146 + 4*pi^158 + 6*pi^170 + 4*pi^194 + pi^206 + 6*pi^218 + 9*pi^230 + O(pi^242) - sage: gauss_sum(2,13,2,prec=5,factored=True) + sage: gauss_sum(2,13,2, prec=5, factored=True) # needs sage.rings.padics (2, 6 + 6*13 + 10*13^2 + O(13^5)) .. SEEALSO:: @@ -201,10 +201,10 @@ def precprint(prec_type, prec_cap, p): sage: precprint('fixed-mod', 1, 17) 'of fixed modulus 17^1' """ - precD = {'capped-rel':'with capped relative precision %s'%prec_cap, - 'capped-abs':'with capped absolute precision %s'%prec_cap, - 'floating-point':'with floating precision %s'%prec_cap, - 'fixed-mod':'of fixed modulus %s^%s'%(p, prec_cap), + precD = {'capped-rel':'with capped relative precision %s' % prec_cap, + 'capped-abs':'with capped absolute precision %s' % prec_cap, + 'floating-point':'with floating precision %s' % prec_cap, + 'fixed-mod':'of fixed modulus %s^%s' % (p, prec_cap), 'lattice-cap':'with lattice-cap precision', 'lattice-float':'with lattice-float precision', 'relaxed':'handled with relaxed arithmetics'} diff --git a/src/sage/rings/padics/morphism.pyx b/src/sage/rings/padics/morphism.pyx index 407bc146990..73ae1d53471 100644 --- a/src/sage/rings/padics/morphism.pyx +++ b/src/sage/rings/padics/morphism.pyx @@ -1,41 +1,37 @@ """ Frobenius endomorphisms on p-adic fields """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Xavier Caruso <xavier.caruso@normalesup.org> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.rings.integer cimport Integer from sage.rings.infinity import Infinity -from sage.rings.ring import CommutativeRing from sage.categories.homset import Hom from sage.structure.element cimport Element from sage.structure.richcmp cimport (richcmp, rich_to_bool, - richcmp_not_equal) + richcmp_not_equal) from sage.rings.morphism cimport RingHomomorphism from .padic_generic import pAdicGeneric -from sage.categories.morphism cimport Morphism - cdef class FrobeniusEndomorphism_padics(RingHomomorphism): """ - A class implementing Frobenius endomorphisms on padic fields. + A class implementing Frobenius endomorphisms on p-adic fields. """ def __init__ (self,domain,n=1): """ INPUT: - - ``domain`` -- an unramified padic field + - ``domain`` -- an unramified p-adic field - ``n`` -- an integer (default: 1) @@ -63,6 +59,7 @@ cdef class FrobeniusEndomorphism_padics(RingHomomorphism): TypeError: n (=a + O(5^20)) is not an integer sage: K = Qp(5) + sage: x = polygen(ZZ, 'x') sage: L.<pi> = K.extension(x^2 - 5) sage: FrobeniusEndomorphism_padics(L) Traceback (most recent call last): @@ -271,8 +268,8 @@ cdef class FrobeniusEndomorphism_padics(RingHomomorphism): def is_injective(self): """ - Return true since any power of the Frobenius endomorphism - over an unramified padic field is always injective. + Return ``True`` since any power of the Frobenius endomorphism + over an unramified p-adic field is always injective. EXAMPLES:: @@ -286,8 +283,8 @@ cdef class FrobeniusEndomorphism_padics(RingHomomorphism): def is_surjective(self): """ - Return true since any power of the Frobenius endomorphism - over an unramified padic field is always surjective. + Return ``True`` since any power of the Frobenius endomorphism + over an unramified p-adic field is always surjective. EXAMPLES:: @@ -301,7 +298,7 @@ cdef class FrobeniusEndomorphism_padics(RingHomomorphism): def is_identity(self): """ - Return true if this morphism is the identity morphism. + Return ``True`` if this morphism is the identity morphism. EXAMPLES:: @@ -335,7 +332,7 @@ cdef class FrobeniusEndomorphism_padics(RingHomomorphism): cpdef _richcmp_(left, right, int op): """ - Compare ``left'' and ``right'' + Compare ``left`` and ``right`` EXAMPLES:: diff --git a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx index a159aa14c9b..979f9d54ba5 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx @@ -56,7 +56,7 @@ element contains the following data: ``prime_pow.get_top_context`` -- obtain an ``ntl_ZZ_pContext_class`` corresponding to `p^n`. The capdiv version divides by ``prime_pow.e`` as appropriate. - ``top_context`` corresponds to `p^{prec_cap}`. + ``top_context`` corresponds to `p^{\texttt{prec\_cap}}`. + ``prime_pow.restore_context``, ``prime_pow.restore_context_capdiv``, @@ -175,7 +175,6 @@ from sage.libs.ntl.ntl_ZZX cimport ntl_ZZX from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class -from sage.libs.ntl.ntl_ZZ_pContext import ntl_ZZ_pContext from sage.rings.padics.padic_generic_element cimport pAdicGenericElement from sage.libs.pari.all import pari_gen from sage.interfaces.abc import GpElement @@ -184,10 +183,6 @@ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.padics.padic_ext_element cimport pAdicExtElement from sage.rings.padics.precision_error import PrecisionError -from sage.rings.padics.pow_computer_ext cimport PowComputer_ZZ_pX -from sage.rings.padics.pow_computer_ext cimport PowComputer_ZZ_pX_small_Eis -from sage.rings.padics.pow_computer_ext cimport PowComputer_ZZ_pX_big_Eis - cdef object infinity from sage.rings.infinity import infinity diff --git a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx index 3d744acd62c..e3bd45e9037 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx @@ -10,14 +10,14 @@ r""" This file implements elements of Eisenstein and unramified extensions of `\ZZ_p` and `\QQ_p` with capped relative precision. -For the parent class see padic_extension_leaves.pyx. +For the parent class see :mod:`sage.rings.padics.padic_extension_leaves`. The underlying implementation is through NTL's ``ZZ_pX`` class. Each element contains the following data: - ``ordp`` (``long``) -- A power of the uniformizer to scale the unit by. For unramified extensions this uniformizer is `p`, for Eisenstein - extensions it is not. A value equal to the maximum value of a long + extensions it is not. A value equal to the maximum value of a ``long`` indicates that the element is an exact zero. - ``relprec`` (``long``) -- A signed integer giving the precision to @@ -39,14 +39,14 @@ element contains the following data: may not actually be a unit. This ``ZZ_pX`` is created with global ntl modulus determined by the absolute value of ``relprec``. If ``relprec`` is 0, ``unit`` **is not initialized**, or destructed if - normalized and found to be zero. Otherwise, let `r` be relprec and + normalized and found to be zero. Otherwise, let `r` be ``relprec`` and `e` be the ramification index over `\QQ_p` or `\ZZ_p`. Then the modulus of unit is given by `p^{ceil(r/e)}`. Note that all kinds of problems arise if you try to mix moduli. ``ZZ_pX_conv_modulus`` gives a semi-safe way to convert between different moduli without having to pass through ``ZZX``. -- ``prime_pow`` (some subclass of ``PowComputer_ZZ_pX``) -- a class, +- ``prime_pow`` (some subclass of :class:`PowComputer_ZZ_pX`) -- a class, identical among all elements with the same parent, holding common data. @@ -57,7 +57,7 @@ element contains the following data: + ``prime_pow.f`` -- The inertia degree + ``prime_pow.prec_cap`` -- the unramified precision cap. For - Eisenstein extensions this is the smallest power of p that is + Eisenstein extensions this is the smallest power of `p` that is zero. + ``prime_pow.ram_prec_cap`` -- the ramified precision cap. For @@ -67,14 +67,14 @@ element contains the following data: + ``prime_pow.pow_ZZ_tmp``, prime_pow.pow_mpz_t_tmp``, ``prime_pow.pow_Integer`` -- functions for accessing powers of `p`. The first two return pointers. See - ``sage/rings/padics/pow_computer_ext`` for examples and important + :mod:`sage.rings.padics.pow_computer_ext` for examples and important warnings. + ``prime_pow.get_context``, ``prime_pow.get_context_capdiv``, ``prime_pow.get_top_context`` -- obtain an ``ntl_ZZ_pContext_class`` corresponding to `p^n`. The capdiv version divides by ``prime_pow.e`` as appropriate. - ``top_context`` corresponds to `p^{prec_cap}`. + ``top_context`` corresponds to `p^{\texttt{prec\_cap}}`. + ``prime_pow.restore_context``, ``prime_pow.restore_context_capdiv``, @@ -176,8 +176,7 @@ AUTHORS: - Julian Rueth (2014-05-09): enable caching through ``_cache_key`` """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 David Roe <roed.math@gmail.com> # William Stein <wstein@gmail.com> # 2014 Julian Rueth <julian.rueth@fsfe.org> @@ -186,8 +185,8 @@ AUTHORS: # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off from sage.ext.stdsage cimport PY_NEW @@ -201,7 +200,6 @@ from sage.libs.ntl.ntl_ZZX cimport ntl_ZZX from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class -from sage.libs.ntl.ntl_ZZ_pContext import ntl_ZZ_pContext from sage.rings.padics.padic_generic_element cimport pAdicGenericElement from sage.libs.pari.all import pari_gen from sage.interfaces.abc import GpElement @@ -209,13 +207,9 @@ from sage.rings.finite_rings.integer_mod import is_IntegerMod from sage.rings.padics.padic_ext_element cimport pAdicExtElement from sage.rings.padics.precision_error import PrecisionError -from sage.rings.padics.pow_computer_ext cimport PowComputer_ZZ_pX from sage.rings.padics.pow_computer_ext cimport PowComputer_ZZ_pX_small_Eis from sage.rings.padics.pow_computer_ext cimport PowComputer_ZZ_pX_big_Eis from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from sage.rings.padics.unramified_extension_generic import UnramifiedExtensionGeneric - -from sage.rings.real_double cimport RealDoubleElement cdef object infinity from sage.rings.infinity import infinity @@ -726,7 +720,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): cdef int _set_from_mpz_rel(self, mpz_t x, long relprec) except -1: """ - Sets ``self`` from an ``mpz_t`` with relative precision bounded by ``relprec``. + Set ``self`` from an ``mpz_t`` with relative precision bounded by ``relprec``. EXAMPLES:: @@ -772,7 +766,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): cdef int _set_from_mpz_both(self, mpz_t x, long absprec, long relprec) except -1: """ - Sets ``self`` from an ``mpz_t`` with relative precision bounded by ``relprec`` + Set ``self`` from an ``mpz_t`` with relative precision bounded by ``relprec`` and absolute precision bounded by ``absprec``. EXAMPLES:: @@ -1256,7 +1250,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): If ``relprec`` is negative, will set ``self.relprec`` to be negative (indicating unnormalized unit) - Returns`` True`` iff ``self.relprec = 0``, ie ``self`` was set to an + Returns ``True`` iff ``self.relprec = 0``, ie ``self`` was set to an inexact zero. Note that this will wipe out anything in ``self.unit``. Be @@ -1538,7 +1532,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): cdef int _cmp_units(left, pAdicGenericElement right) except -2: """ - For units ``left`` and ``right``, returns 0 if they are equal up to + For units ``left`` and ``right``, return 0 if they are equal up to the lesser of the two precisions, or 1 if they are not. EXAMPLES:: @@ -2056,7 +2050,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): cpdef _add_(self, _right): """ - Computes the sum of ``self`` and ``right``. + Compute the sum of ``self`` and ``right``. EXAMPLES:: @@ -2350,7 +2344,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): is indistinguishable from zero. If this element is an inexact zero of valuation less than ``absprec``, - raises a ``PrecisionError``. + raises a :class:`PrecisionError`. EXAMPLES:: @@ -2660,9 +2654,11 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): sage: a = W(345, 17); a 4*w^5 + 3*w^7 + w^9 + 3*w^10 + 2*w^11 + 4*w^12 + w^13 + 2*w^14 + 2*w^15 + O(w^17) sage: b = a.lift_to_precision(19); b - 4*w^5 + 3*w^7 + w^9 + 3*w^10 + 2*w^11 + 4*w^12 + w^13 + 2*w^14 + 2*w^15 + w^17 + 2*w^18 + O(w^19) + 4*w^5 + 3*w^7 + w^9 + 3*w^10 + 2*w^11 + 4*w^12 + w^13 + 2*w^14 + 2*w^15 + + w^17 + 2*w^18 + O(w^19) sage: c = a.lift_to_precision(24); c - 4*w^5 + 3*w^7 + w^9 + 3*w^10 + 2*w^11 + 4*w^12 + w^13 + 2*w^14 + 2*w^15 + w^17 + 2*w^18 + 4*w^19 + 4*w^20 + 2*w^21 + 4*w^23 + O(w^24) + 4*w^5 + 3*w^7 + w^9 + 3*w^10 + 2*w^11 + 4*w^12 + w^13 + 2*w^14 + 2*w^15 + + w^17 + 2*w^18 + 4*w^19 + 4*w^20 + 2*w^21 + 4*w^23 + O(w^24) sage: a._ntl_rep() [19 35 118 60 121] sage: b._ntl_rep() @@ -2718,7 +2714,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): def expansion(self, n = None, lift_mode = 'simple'): """ - Return a list giving a series representation of self. + Return a list giving a series representation of ``self``. - If ``lift_mode == 'simple'`` or ``'smallest'``, the returned list will consist of integers (in the Eisenstein case) or a @@ -2838,7 +2834,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): the power basis `1, x, x^2, \ldots, x^{d-1}` for this extension field. Thus the *rows* of this matrix give the images of each of the `x^i`. The entries of the matrices are - IntegerMod elements, defined modulo `p^{N / e}` where `N` is + :class:`IntegerMod` elements, defined modulo `p^{N / e}` where `N` is the absolute precision of this element (unless this element is zero to arbitrary precision; in that case the entries are integer zeros.) @@ -2954,7 +2950,11 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): sage: E = a.teichmuller_expansion(); E 5-adic expansion of a + O(5^4) (teichmuller) sage: list(E) - [a + (2*a^3 + 2*a^2 + 3*a + 4)*5 + (4*a^3 + 3*a^2 + 3*a + 2)*5^2 + (4*a^2 + 2*a + 2)*5^3 + O(5^4), (3*a^3 + 3*a^2 + 2*a + 1) + (a^3 + 4*a^2 + 1)*5 + (a^2 + 4*a + 4)*5^2 + O(5^3), (4*a^3 + 2*a^2 + a + 1) + (2*a^3 + 2*a^2 + 2*a + 4)*5 + O(5^2), (a^3 + a^2 + a + 4) + O(5)] + [a + (2*a^3 + 2*a^2 + 3*a + 4)*5 + (4*a^3 + 3*a^2 + 3*a + 2)*5^2 + + (4*a^2 + 2*a + 2)*5^3 + O(5^4), + (3*a^3 + 3*a^2 + 2*a + 1) + (a^3 + 4*a^2 + 1)*5 + (a^2 + 4*a + 4)*5^2 + O(5^3), + (4*a^3 + 2*a^2 + a + 1) + (2*a^3 + 2*a^2 + 2*a + 4)*5 + O(5^2), + (a^3 + a^2 + a + 4) + O(5)] sage: sum([c * 5^i for i, c in enumerate(E)]) a + O(5^4) sage: all(c^625 == c for c in E) @@ -2964,14 +2964,17 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): sage: f = x^3 - 98*x + 7 sage: W.<w> = ZpCR(7,3).ext(f) sage: b = (1+w)^5; L = b.teichmuller_expansion(); L - [1 + O(w^9), 5 + 5*w^3 + w^6 + 4*w^7 + O(w^8), 3 + 3*w^3 + O(w^7), 3 + 3*w^3 + O(w^6), O(w^5), 4 + 5*w^3 + O(w^4), 3 + O(w^3), 6 + O(w^2), 6 + O(w)] + [1 + O(w^9), 5 + 5*w^3 + w^6 + 4*w^7 + O(w^8), 3 + 3*w^3 + O(w^7), + 3 + 3*w^3 + O(w^6), O(w^5), 4 + 5*w^3 + O(w^4), 3 + O(w^3), + 6 + O(w^2), 6 + O(w)] sage: sum([w^i*L[i] for i in range(9)]) == b True sage: all(L[i]^(7^3) == L[i] for i in range(9)) True sage: L = W(3).teichmuller_expansion(); L - [3 + 3*w^3 + w^7 + O(w^9), O(w^8), O(w^7), 4 + 5*w^3 + O(w^6), O(w^5), O(w^4), 3 + O(w^3), 6 + O(w^2)] + [3 + 3*w^3 + w^7 + O(w^9), O(w^8), O(w^7), 4 + 5*w^3 + O(w^6), + O(w^5), O(w^4), 3 + O(w^3), 6 + O(w^2)] sage: sum([w^i*L[i] for i in range(len(L))]) 3 + O(w^9) """ @@ -3039,7 +3042,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): sage: S.<x> = R[] sage: f = x^5 + 77*x^3 - 98*x^2 - 7 sage: W.<w> = R.ext(f) - sage: y = W.teichmuller(3, 15); y #indirect doctest + sage: y = W.teichmuller(3, 15); y # indirect doctest 3 + 4*w^5 + 2*w^8 + 6*w^10 + w^11 + 6*w^12 + 5*w^13 + 4*w^14 + O(w^15) sage: y^7 == y @@ -3081,7 +3084,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): def precision_absolute(self): """ - Return the absolute precision of this element, ie the power of the + Return the absolute precision of this element, i.e., the power of the uniformizer modulo which this element is defined. EXAMPLES:: @@ -3116,7 +3119,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): def precision_relative(self): """ - Return the relative precision of this element, ie the power of the + Return the relative precision of this element, i.e., the power of the uniformizer modulo which the unit part of ``self`` is defined. EXAMPLES:: @@ -3149,7 +3152,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): cdef long valuation_c(self): """ - Return the valuation of this element + Return the valuation of this element. EXAMPLES:: @@ -3173,7 +3176,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): cpdef pAdicZZpXCRElement unit_part(self): """ - Return the unit part of this element, ie ``self / uniformizer^(self.valuation())`` + Return the unit part of this element, ie ``self / uniformizer^(self.valuation())``. EXAMPLES:: @@ -3222,7 +3225,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): otherwise they will be in the interval `[(1-p)/2, p/2]`. Note that zeros are truncated from the returned list, so you - must use the ``valuation()`` function to completely recover ``self``. + must use the method :meth:`valuation` to completely recover ``self``. EXAMPLES:: diff --git a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx index 548a8e635d2..9dec3affd53 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx @@ -20,7 +20,7 @@ element contains the following data: This ``ZZ_pX`` is created with global ntl modulus determined by the parent's precision cap and shared among all elements. -- ``prime_pow`` (some subclass of ``PowComputer_ZZ_pX``) -- a class, +- ``prime_pow`` (some subclass of :class:`PowComputer_ZZ_pX`) -- a class, identical among all elements with the same parent, holding common data. @@ -48,7 +48,7 @@ element contains the following data: ``prime_pow.get_top_context`` -- obtain an ``ntl_ZZ_pContext_class`` corresponding to `p^n`. The capdiv version divides by ``prime_pow.e`` as appropriate. - ``top_context`` corresponds to `p^{prec_cap}`. + ``top_context`` corresponds to `p^{\texttt{prec\_cap}}`. * ``prime_pow.restore_context``, ``prime_pow.restore_context_capdiv``, @@ -113,8 +113,7 @@ AUTHORS: - David Roe (2008-01-01) initial version """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 David Roe <roed.math@gmail.com> # William Stein <wstein@gmail.com> # @@ -122,18 +121,14 @@ AUTHORS: # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off include "sage/libs/ntl/decl.pxi" from sage.structure.richcmp cimport rich_to_bool -from sage.structure.element cimport Element -from sage.rings.padics.padic_printing cimport pAdicPrinter_class -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer from sage.rings.padics.padic_generic_element cimport pAdicGenericElement from sage.rings.padics.padic_ext_element cimport pAdicExtElement @@ -144,13 +139,11 @@ from sage.libs.ntl.ntl_ZZX cimport ntl_ZZX from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class -from sage.libs.ntl.ntl_ZZ_pContext import ntl_ZZ_pContext from sage.rings.rational cimport Rational from sage.libs.pari.all import pari_gen from sage.interfaces.abc import GpElement from sage.rings.finite_rings.integer_mod import is_IntegerMod from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from sage.rings.padics.pow_computer_ext cimport PowComputer_ZZ_pX_FM_Eis cdef class pAdicZZpXFMElement(pAdicZZpXElement): diff --git a/src/sage/rings/padics/padic_ZZ_pX_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_element.pyx index ec33070be49..b0beaa85617 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_element.pyx @@ -614,7 +614,8 @@ def _test_preprocess_list(R, L): ([1, 10, 25, 0], -1, NTL modulus 625) sage: _test_preprocess_list(ZqCA(25,names='a',implementation="NTL"), [1/5,mod(2,625),Zp(5)(5,3),mod(0,3125)]) ([1, 10, 25, 0], -1, NTL modulus 625) - sage: T.<a> = Qp(5).extension(x^2-5) + sage: x = polygen(ZZ, 'x') + sage: T.<a> = Qp(5).extension(x^2 - 5) sage: _test_preprocess_list(T, [5^-1 + O(5)]) ([1], -1, NTL modulus 25) """ diff --git a/src/sage/rings/padics/padic_base_generic.py b/src/sage/rings/padics/padic_base_generic.py index 45730e8b816..6fb5f464a7f 100644 --- a/src/sage/rings/padics/padic_base_generic.py +++ b/src/sage/rings/padics/padic_base_generic.py @@ -30,8 +30,10 @@ from sage.rings.padics.padic_fixed_mod_element import pAdicCoercion_ZZ_FM, pAdicConvert_QQ_FM from sage.rings.padics.padic_floating_point_element import pAdicCoercion_ZZ_FP, pAdicCoercion_QQ_FP, pAdicConvert_QQ_FP + class pAdicBaseGeneric(pAdicGeneric): _implementation = 'GMP' + def __init__(self, p, prec, print_mode, names, element_class): """ Initialization @@ -131,12 +133,12 @@ def _repr_(self, do_latex=False): else: s = r"\Bold{Z}_{%s}" % self.prime() if hasattr(self, '_label') and self._label: - s = r"\verb'%s' (\simeq %s)"%(self._label, s) + s = r"\verb'%s' (\simeq %s)" % (self._label, s) else: s = "Field " if self.is_field() else "Ring " - s = "%s-adic "%self.prime() + s + precprint(self._prec_type(), self.precision_cap(), self.prime()) + s = "%s-adic " % self.prime() + s + precprint(self._prec_type(), self.precision_cap(), self.prime()) if hasattr(self, '_label') and self._label: - s+= " (label: %s)"%self._label + s += " (label: %s)" % self._label return s def exact_field(self): @@ -385,7 +387,7 @@ def zeta(self, n=None): if n == 1: return self(1) else: - raise ValueError("No, %sth root of unity in self"%n) + raise ValueError("No, %sth root of unity in self" % n) else: from sage.rings.finite_rings.finite_field_constructor import GF return self.teichmuller(GF(self.prime()).zeta(n).lift()) @@ -431,11 +433,11 @@ def plot(self, max_points=2500, **args): EXAMPLES:: - sage: Zp(3).plot() + sage: Zp(3).plot() # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: Zp(5).plot(max_points=625) + sage: Zp(5).plot(max_points=625) # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: Zp(23).plot(rgbcolor=(1,0,0)) + sage: Zp(23).plot(rgbcolor=(1,0,0)) # needs sage.plot Graphics object consisting of 1 graphics primitive """ if 'pointsize' not in args: diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index 3930103df75..1c47b0083c2 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -32,8 +32,8 @@ 22 The number of times that `p` divides the element is called the -valuation, and can be accessed with the functions ``valuation()`` and -``ordp()``: +valuation, and can be accessed with the methods :meth:`valuation` and +:meth:`ordp`: sage: a.valuation() 2 @@ -111,7 +111,7 @@ 1 + 2*5^2 + 5^3 `p`-adic rings and fields should be created using the creation -functions ``Zp`` and ``Qp`` as above. This will ensure that there is +functions :func:`Zp` and :func:`Qp` as above. This will ensure that there is only one instance of `\ZZ_p` and `\QQ_p` of a given type, `p`, print mode and precision. It also saves typing very long class names.:: @@ -347,7 +347,7 @@ def __init__(self, p, prec, print_mode, names): def _coerce_map_from_(self, R): """ - Returns ``True`` if there is a coerce map from ``R`` to ``self``. + Return ``True`` if there is a coerce map from ``R`` to ``self``. EXAMPLES:: @@ -446,7 +446,7 @@ def __init__(self, p, prec, print_mode, names): def _coerce_map_from_(self, R): """ - Returns ``True`` if there is a coerce map from ``R`` to ``self``. + Return ``True`` if there is a coerce map from ``R`` to ``self``. EXAMPLES:: @@ -478,7 +478,7 @@ def _coerce_map_from_(self, R): def _convert_map_from_(self, R): """ - Finds conversion maps from R to this ring. + Finds conversion maps from ``R`` to this ring. EXAMPLES:: @@ -548,7 +548,7 @@ def __init__(self, p, prec, print_mode, names): def _coerce_map_from_(self, R): """ - Returns ``True`` if there is a coerce map from ``R`` to ``self``. + Return ``True`` if there is a coerce map from ``R`` to ``self``. EXAMPLES:: @@ -653,7 +653,7 @@ def __init__(self, p, prec, print_mode, names): def _coerce_map_from_(self, R): """ - Returns ``True`` if there is a coerce map from ``R`` to ``self``. + Return ``True`` if there is a coerce map from ``R`` to ``self``. EXAMPLES:: @@ -711,11 +711,11 @@ def _convert_map_from_(self, R): def random_element(self, algorithm='default'): r""" - Returns a random element of ``self``, optionally using the ``algorithm`` + Return a random element of ``self``, optionally using the ``algorithm`` argument to decide how it generates the element. Algorithms currently implemented: - - default: Choose an integer `k` using the standard + - ``'default'``: Choose an integer `k` using the standard distribution on the integers. Then choose an integer `a` uniformly in the range `0 \le a < p^N` where `N` is the precision cap of ``self``. Return ``self(p^k * a, absprec = @@ -729,9 +729,9 @@ def random_element(self, algorithm='default'): if (algorithm == 'default'): k = ZZ.random_element() a = ZZ.random_element(self.prime()**self.precision_cap()) - return self(self.prime()**k * a, absprec = k + self.precision_cap()) + return self(self.prime()**k * a, absprec=k + self.precision_cap()) else: - raise NotImplementedError("Don't know %s algorithm"%algorithm) + raise NotImplementedError("Don't know %s algorithm" % algorithm) class pAdicFieldFloatingPoint(pAdicFieldBaseGeneric, pAdicFloatingPointFieldGeneric): r""" @@ -778,7 +778,7 @@ def __init__(self, p, prec, print_mode, names): def _coerce_map_from_(self, R): """ - Returns ``True`` if there is a coerce map from ``R`` to ``self``. + Return ``True`` if there is a coerce map from ``R`` to ``self``. EXAMPLES:: @@ -858,7 +858,8 @@ class pAdicRingLattice(pAdicLatticeGeneric, pAdicRingBaseGeneric): EXAMPLES:: sage: R = ZpLC(next_prime(10^60)) # indirect doctest - doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. + doctest:...: FutureWarning: This class/method/function is marked as experimental. + It, its functionality or its interface might change without a formal deprecation. See https://github.com/sagemath/sage/issues/23505 for details. sage: type(R) <class 'sage.rings.padics.padic_base_leaves.pAdicRingLattice_with_category'> @@ -904,7 +905,7 @@ def _coerce_map_from_(self, R): True Note that coerce map does not exist between ``p``-adic rings with - lattice precision and other ``p``-adic rings. + lattice precision and other ``p``-adic rings. :: sage: S = Zp(2) sage: R.has_coerce_map_from(S) @@ -913,7 +914,7 @@ def _coerce_map_from_(self, R): False Similarly there is no coercion maps between ``p``-adic rings with - different labels. + different labels. :: sage: R2 = ZpLC(2, label='coerce') sage: R.has_coerce_map_from(R2) @@ -937,7 +938,8 @@ def random_element(self, prec=None): sage: R = ZpLC(2) sage: R.random_element() # random - 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^10 + 2^11 + 2^14 + 2^15 + 2^16 + 2^17 + 2^18 + 2^19 + 2^21 + O(2^23) + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^10 + 2^11 + 2^14 + 2^15 + 2^16 + + 2^17 + 2^18 + 2^19 + 2^21 + O(2^23) sage: R.random_element(prec=10) # random 1 + 2^3 + 2^4 + 2^7 + O(2^10) @@ -987,7 +989,8 @@ class pAdicFieldLattice(pAdicLatticeGeneric, pAdicFieldBaseGeneric): EXAMPLES:: sage: R = QpLC(next_prime(10^60)) # indirect doctest - doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. + doctest:...: FutureWarning: This class/method/function is marked as experimental. + It, its functionality or its interface might change without a formal deprecation. See https://github.com/sagemath/sage/issues/23505 for details. sage: type(R) <class 'sage.rings.padics.padic_base_leaves.pAdicFieldLattice_with_category'> @@ -1033,7 +1036,7 @@ def _coerce_map_from_(self, R): True Note that coerce map does not exist between ``p``-adic fields with - lattice precision and other ``p``-adic rings. + lattice precision and other ``p``-adic rings. :: sage: L = Qp(2) sage: K.has_coerce_map_from(L) @@ -1062,7 +1065,7 @@ def random_element(self, prec=None, integral=False): - ``prec`` -- an integer or ``None`` (the default): the absolute precision of the generated random element - - ``integral`` -- a boolean (default: ``False``); if true + - ``integral`` -- a boolean (default: ``False``); if ``True``, return an element in the ring of integers EXAMPLES:: @@ -1071,7 +1074,8 @@ def random_element(self, prec=None, integral=False): sage: K.random_element() # not tested, known bug (see :trac:`32126`) 2^-8 + 2^-7 + 2^-6 + 2^-5 + 2^-3 + 1 + 2^2 + 2^3 + 2^5 + O(2^12) sage: K.random_element(integral=True) # random - 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^10 + 2^11 + 2^14 + 2^15 + 2^16 + 2^17 + 2^18 + 2^19 + O(2^20) + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^10 + 2^11 + 2^14 + 2^15 + 2^16 + + 2^17 + 2^18 + 2^19 + O(2^20) sage: K.random_element(prec=10) # random 2^(-3) + 1 + 2 + 2^4 + 2^8 + O(2^10) @@ -1128,6 +1132,8 @@ def __init__(self, p, prec, print_mode, names): sage: R = ZpER(7) sage: TestSuite(R).run(skip=['_test_log', '_test_matrix_smith']) + sage: R = ZpER(7, secure=True) + sage: TestSuite(R).run(skip=['_test_log', '_test_matrix_smith']) """ from sage.rings.padics import padic_relaxed_element self._default_prec, self._halting_prec, self._secure = prec @@ -1163,6 +1169,8 @@ def __init__(self, p, prec, print_mode, names): sage: K = QpER(7) sage: TestSuite(K).run(skip=['_test_log', '_test_matrix_smith']) + sage: K = QpER(7, secure=True) + sage: TestSuite(K).run(skip=['_test_log', '_test_matrix_smith']) """ from sage.rings.padics import padic_relaxed_element self._default_prec, self._halting_prec, self._secure = prec diff --git a/src/sage/rings/padics/padic_capped_relative_element.pyx b/src/sage/rings/padics/padic_capped_relative_element.pyx index b5843d467a7..f09708db2c7 100644 --- a/src/sage/rings/padics/padic_capped_relative_element.pyx +++ b/src/sage/rings/padics/padic_capped_relative_element.pyx @@ -235,6 +235,7 @@ cdef class pAdicCappedRelativeElement(CRElement): self.prime_pow.prime.value, self.prime_pow.pow_mpz_t_tmp(self.relprec), self.unit) + def _integer_(self, Z=None): r""" Return an integer congruent to this element modulo @@ -604,7 +605,7 @@ def base_p_list(Integer n, bint pos, PowComputer_class prime_pow): raise ValueError("n must be nonnegative") cdef expansion_mode mode = simple_mode if pos else smallest_mode # We need a p-adic element to feed to ExpansionIter before resetting its curvalue - from sage.rings.padics.all import Zp + from sage.rings.padics.factory import Zp p = prime_pow.prime dummy = Zp(p)(0) cdef ExpansionIter expansion = ExpansionIter(dummy, n.exact_log(p) + 2, mode) diff --git a/src/sage/rings/padics/padic_ext_element.pyx b/src/sage/rings/padics/padic_ext_element.pyx index 39f58efcd0b..94a7d93c727 100644 --- a/src/sage/rings/padics/padic_ext_element.pyx +++ b/src/sage/rings/padics/padic_ext_element.pyx @@ -16,8 +16,7 @@ AUTHORS: - Julian Rueth (2012-10-18): added residue """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007-2010 David Roe <roed.math@gmail.com> # 2012 Julian Rueth <julian.rueth@fsfe.org> # @@ -25,11 +24,10 @@ AUTHORS: # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.rings.padics.pow_computer cimport PowComputer_class -from sage.rings.integer import Integer from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p cdef class pAdicExtElement(pAdicGenericElement): @@ -368,6 +366,7 @@ cdef class pAdicExtElement(pAdicGenericElement): An error will be raised if the parent of self is a ramified extension:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = Qp(5).extension(x^2 - 5) sage: a.frobenius() Traceback (most recent call last): diff --git a/src/sage/rings/padics/padic_extension_generic.py b/src/sage/rings/padics/padic_extension_generic.py index ff2d0a5ec6c..88027e19439 100644 --- a/src/sage/rings/padics/padic_extension_generic.py +++ b/src/sage/rings/padics/padic_extension_generic.py @@ -118,6 +118,7 @@ def _extension_type(self): sage: K._extension_type() 'Unramified' + sage: x = polygen(ZZ, 'x') sage: L.<pi> = Qp(5).extension(x^2 - 5) sage: L._extension_type() 'Eisenstein' @@ -138,7 +139,8 @@ def _repr_(self, do_latex=False): 7-adic Unramified Extension Ring in a defined by x^3 + 6*x^2 + 4 sage: R1._latex_() '\\Bold{Z}_{7^{3}}' - sage: R2.<t> = R.ext(x^2+7) + sage: x = polygen(ZZ, 'x') + sage: R2.<t> = R.ext(x^2 + 7) sage: R2 #indirect doctest 7-adic Eisenstein Extension Ring in t defined by x^2 + 7 sage: R2._latex_() @@ -510,7 +512,7 @@ def construction(self, forbid_frac_field=False): sage: c(R0) == R True - For a field, by default we return a fraction field functor. + For a field, by default we return a fraction field functor. :: sage: K.<a> = Qq(25, 8) sage: c, R = K.construction(); R diff --git a/src/sage/rings/padics/padic_extension_leaves.py b/src/sage/rings/padics/padic_extension_leaves.py index 14fe737b0a1..ed171e833e4 100644 --- a/src/sage/rings/padics/padic_extension_leaves.py +++ b/src/sage/rings/padics/padic_extension_leaves.py @@ -1,7 +1,7 @@ -""" +r""" `p`-adic Extension Leaves -The final classes for extensions of Zp and Qp (ie classes that are not +The final classes for extensions of `\ZZ_p` and `\QQ_p` (i.e., classes that are not just designed to be inherited from). AUTHORS: @@ -89,12 +89,12 @@ class UnramifiedExtensionRingCappedRelative(UnramifiedExtensionGeneric, pAdicCap """ TESTS:: - sage: R.<a> = ZqCR(27,10000) + sage: R.<a> = ZqCR(27,1000) sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): - """ - A capped relative representation of Zq. + r""" + A capped relative representation of `\ZZ_q`. INPUT: @@ -102,7 +102,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp This could be a polynomial with integer coefficients, for example, while ``poly`` has coefficients in a `p`-adic ring. - - ``poly`` -- t polynomial with coefficients in :meth:`base_ring` + - ``poly`` -- the polynomial with coefficients in :meth:`base_ring` defining this extension - ``prec`` -- the precision cap of this ring @@ -147,12 +147,12 @@ class UnramifiedExtensionFieldCappedRelative(UnramifiedExtensionGeneric, pAdicCa """ TESTS:: - sage: R.<a> = QqCR(27,10000) + sage: R.<a> = QqCR(27,1000) sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): r""" - A representation of Qq. + A representation of `\QQ_q`. INPUT: @@ -233,25 +233,25 @@ class UnramifiedExtensionRingCappedAbsolute(UnramifiedExtensionGeneric, pAdicCap """ TESTS:: - sage: R.<a> = ZqCA(27,10000) + sage: R.<a> = ZqCA(27,1000) sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): - """ - A capped absolute representation of Zq. + r""" + A capped absolute representation of `ZZ_q`. INPUT: - ``exact_modulus`` -- the original polynomial defining the extension. This could be a polynomial with integer coefficients, for example, - while poly has coefficients in a `p`-adic ring. + while ``poly`` has coefficients in a `p`-adic ring. - ``poly`` -- the polynomial with coefficients in :meth:`base_ring` defining this extension - ``prec`` -- the precision cap of this ring - - ``print_mode`` -- A dictionary of print options + - ``print_mode`` -- a dictionary of print options - ``shift_seed`` -- unused @@ -292,7 +292,7 @@ class UnramifiedExtensionRingFixedMod(UnramifiedExtensionGeneric, pAdicFixedModR """ TESTS:: - sage: R.<a> = ZqFM(27,10000) + sage: R.<a> = ZqFM(27,1000) sage: TestSuite(R).run(skip='_test_log',max_runs=4) # long time """ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): @@ -358,14 +358,14 @@ class UnramifiedExtensionRingFloatingPoint(UnramifiedExtensionGeneric, pAdicFloa True """ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): - """ - A floating point representation of Zq. + r""" + A floating point representation of `\ZZ_q`. INPUT: - ``exact_modulus`` -- the original polynomial defining the extension. This could be a polynomial with integer coefficients, for example, - while ``poly`` has coefficients in Zp. + while ``poly`` has coefficients in `\ZZ_p`. - ``poly`` -- the polynomial with coefficients in :meth:`base_ring` defining this extension @@ -415,8 +415,8 @@ class UnramifiedExtensionFieldFloatingPoint(UnramifiedExtensionGeneric, pAdicFlo True """ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): - """ - A representation of Qq. + r""" + A representation of `\QQ_q`. INPUT: @@ -479,13 +479,13 @@ class EisensteinExtensionRingCappedRelative(EisensteinExtensionGeneric, pAdicCap """ TESTS:: - sage: R = Zp(3, 10000, print_pos=False); S.<x> = ZZ[]; f = x^3 + 9*x - 3 + sage: R = Zp(3, 1000, print_pos=False); S.<x> = ZZ[]; f = x^3 + 9*x - 3 sage: W.<w> = R.ext(f) sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='NTL'): - """ - A capped relative representation of an eisenstein extension of Zp. + r""" + A capped relative representation of an Eisenstein extension of `\ZZ_p`. INPUT: @@ -534,13 +534,13 @@ class EisensteinExtensionFieldCappedRelative(EisensteinExtensionGeneric, pAdicCa """ TESTS:: - sage: R = Qp(3, 10000, print_pos=False); S.<x> = ZZ[]; f = x^3 + 9*x - 3 + sage: R = Qp(3, 1000, print_pos=False); S.<x> = ZZ[]; f = x^3 + 9*x - 3 sage: W.<w> = R.ext(f) sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='NTL'): - """ - A capped relative representation of an eisenstein extension of Qp. + r""" + A capped relative representation of an Eisenstein extension of `\QQ_p`. INPUT: @@ -590,13 +590,13 @@ class EisensteinExtensionRingCappedAbsolute(EisensteinExtensionGeneric, pAdicCap """ TESTS:: - sage: R = ZpCA(3, 10000, print_pos=False); S.<x> = ZZ[]; f = x^3 + 9*x - 3 + sage: R = ZpCA(3, 1000, print_pos=False); S.<x> = ZZ[]; f = x^3 + 9*x - 3 sage: W.<w> = R.ext(f) sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation): - """ - A capped absolute representation of an eisenstein extension of Zp. + r""" + A capped absolute representation of an Eisenstein extension of `\ZZ_p`. INPUT: @@ -645,13 +645,13 @@ class EisensteinExtensionRingFixedMod(EisensteinExtensionGeneric, pAdicFixedModR """ TESTS:: - sage: R = ZpFM(3, 10000, print_pos=False); S.<x> = ZZ[]; f = x^3 + 9*x - 3 + sage: R = ZpFM(3, 1000, print_pos=False); S.<x> = ZZ[]; f = x^3 + 9*x - 3 sage: W.<w> = R.ext(f) sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='NTL'): - """ - A fixed modulus representation of an eisenstein extension of Zp. + r""" + A fixed modulus representation of an eisenstein extension of `\ZZ_p`. INPUT: @@ -706,7 +706,8 @@ def fraction_field(self): sage: R.fraction_field() Traceback (most recent call last): ... - TypeError: This implementation of the p-adic ring does not support fields of fractions. + TypeError: This implementation of the p-adic ring + does not support fields of fractions. """ raise TypeError("This implementation of the p-adic ring does not support fields of fractions.") diff --git a/src/sage/rings/padics/padic_floating_point_element.pyx b/src/sage/rings/padics/padic_floating_point_element.pyx index 13eb30a3abc..d6153a1f673 100644 --- a/src/sage/rings/padics/padic_floating_point_element.pyx +++ b/src/sage/rings/padics/padic_floating_point_element.pyx @@ -223,6 +223,7 @@ cdef class pAdicFloatingPointElement(FPElement): self.prime_pow.prime.value, self.prime_pow.pow_mpz_t_top(), self.unit) + def _integer_(self, Z=None): r""" Return an integer congruent to this element modulo diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 2f9c2195720..a929ee60a75 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.padics r""" `p`-adic Generic @@ -35,7 +36,6 @@ from sage.rings.ring import PrincipalIdealDomain from sage.rings.integer import Integer from sage.rings.infinity import Infinity -from sage.rings.padics.padic_printing import pAdicPrinter from sage.rings.padics.precision_error import PrecisionError from sage.misc.cachefunc import cached_method from sage.structure.richcmp import richcmp_not_equal @@ -58,6 +58,8 @@ def __init__(self, base, p, prec, print_mode, names, element_class, category=Non sage: R = Zp(17) # indirect doctest """ + from sage.rings.padics.padic_printing import pAdicPrinter + if category is None: if self.is_field(): category = Fields() @@ -90,7 +92,6 @@ def some_elements(self): return L def _modified_print_mode(self, print_mode): - r""" Return a dictionary of print options, starting with ``self``'s print options but modified by the options in the dictionary @@ -478,6 +479,12 @@ def integer_ring(self, print_mode=None): 2-adic Ring with lattice-cap precision (label: test) sage: R.integer_ring({'mode':'series'}) is R True + + The `secure` attribute for relaxed type is preserved:: + + sage: K = QpER(5, secure=True) + sage: K.integer_ring().is_secure() + True """ # Currently does not support fields with non integral defining # polynomials. This should change when the padic_general_extension @@ -485,13 +492,13 @@ def integer_ring(self, print_mode=None): if not self.is_field() and print_mode is None: return self if print_mode is None: - return self.change(field=False) + return self.change(field=False, check=False) else: from sage.misc.superseded import deprecation deprecation(23227, "Use the change method if you want to change print options in integer_ring()") return self.change(field=False, **print_mode) - def teichmuller(self, x, prec = None): + def teichmuller(self, x, prec=None): r""" Return the Teichmรผller representative of ``x``. @@ -608,7 +615,7 @@ def teichmuller_system(self): # """ # raise NotImplementedError - def extension(self, modulus, prec = None, names = None, print_mode = None, implementation='FLINT', **kwds): + def extension(self, modulus, prec=None, names=None, print_mode=None, implementation='FLINT', **kwds): r""" Create an extension of this p-adic ring. @@ -659,7 +666,7 @@ def extension(self, modulus, prec = None, names = None, print_mode = None, imple print_mode[option] = kwds[option] else: print_mode[option] = self._printer.dict()[option] - return ExtensionFactory(base=self, modulus=modulus, prec=prec, names=names, check = True, implementation=implementation, **print_mode) + return ExtensionFactory(base=self, modulus=modulus, prec=prec, names=names, check=True, implementation=implementation, **print_mode) def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): r""" @@ -963,7 +970,6 @@ def _test_shift(self, **options): xx = y + (x % b) tester.assertTrue(xx.is_equal_to(x,prec)) - def _test_log(self, **options): r""" Test the log operator on elements of this ring. @@ -1039,7 +1045,7 @@ def _test_teichmuller(self, **options): try: y = self.teichmuller(x) except ValueError: - tester.assertTrue(x.valuation() < 0 or x.precision_absolute()==0) + tester.assertTrue(x.valuation() < 0 or x.precision_absolute() == 0) else: try: tester.assertEqual(x.residue(), y.residue()) @@ -1736,7 +1742,7 @@ def _richcmp_(self, other, op): sage: f == g True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self.domain(), self.codomain()), (other.domain(), other.codomain()), op) @@ -1869,7 +1875,7 @@ def _richcmp_(self, other, op): sage: f == g True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self.domain(), self.codomain()), (other.domain(), other.codomain()), op) @@ -1891,6 +1897,8 @@ def local_print_mode(obj, print_options, pos=None, ram_name=None): For more documentation see :class:`sage.structure.parent_gens.localvars`. """ + from sage.rings.padics.padic_printing import pAdicPrinter + if isinstance(print_options, str): print_options = {'mode': print_options} elif not isinstance(print_options, dict): diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 7f0a64aa5ef..f68405dcc6f 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -14,8 +14,7 @@ AUTHORS: - Julian Rueth: fixes for exp() and log(), implemented gcd, xgcd """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007-2013 David Roe <roed@math.harvard.edu> # 2007 William Stein <wstein@gmail.com> # 2013-2014 Julian Rueth <julian.rueth@gmail.com> @@ -24,11 +23,10 @@ AUTHORS: # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.ext.stdsage cimport PY_NEW -from cysignals.memory cimport sig_malloc, sig_free cimport sage.rings.padics.local_generic_element from sage.libs.gmp.mpz cimport mpz_set_si @@ -46,7 +44,7 @@ cdef long maxordp = (1L << (sizeof(long) * 8 - 2)) - 1 cdef class pAdicGenericElement(LocalGenericElement): cpdef _richcmp_(left, right, int op): - """ + r""" First compare valuations, then compare normalized residue of unit part. @@ -173,7 +171,7 @@ cdef class pAdicGenericElement(LocalGenericElement): cpdef bint _is_exact_zero(self) except -1: """ - Returns True if self is exactly zero. Since + Return ``True`` if self is exactly zero. Since non-capped-relative elements cannot be exact, this function always returns False. @@ -186,7 +184,7 @@ cdef class pAdicGenericElement(LocalGenericElement): cpdef bint _is_inexact_zero(self) except -1: """ - Returns True if self is indistinguishable from zero, but not + Return ``True`` if self is indistinguishable from zero, but not exactly zero. EXAMPLES:: @@ -198,7 +196,7 @@ cdef class pAdicGenericElement(LocalGenericElement): cpdef bint _is_zero_rep(self) except -1: """ - Returns True is self is indistinguishable from zero. + Return ``True`` is self is indistinguishable from zero. EXAMPLES:: @@ -534,7 +532,7 @@ cdef class pAdicGenericElement(LocalGenericElement): def str(self, mode=None): """ - Returns a string representation of self. + Return a string representation of ``self``. EXAMPLES:: @@ -545,7 +543,7 @@ cdef class pAdicGenericElement(LocalGenericElement): def _repr_(self, mode=None, do_latex=False): r""" - Returns a string representation of this element. + Return a string representation of this element. INPUT: @@ -562,6 +560,7 @@ cdef class pAdicGenericElement(LocalGenericElement): We check that :trac:`26479` is fixed:: + sage: x = polygen(ZZ, 'x') sage: K.<pi> = Qp(2).extension(x^3 - 2) sage: latex(pi) \pi + O(\pi^{61}) @@ -570,8 +569,8 @@ cdef class pAdicGenericElement(LocalGenericElement): def additive_order(self, prec=None): r""" - Returns the additive order of this element truncated - at precision ``prec`` + Return the additive order of this element truncated + at precision ``prec``. INPUT: @@ -606,11 +605,11 @@ cdef class pAdicGenericElement(LocalGenericElement): the desired precision on the result; if ``None``, the precision is derived from the precision on the input - - ``algorithm`` -- ``direct``, ``series``, ``newton`` or + - ``algorithm`` -- ``'direct'``, ``'series'``, ``'newton'`` or ``None`` (default) The direct algorithm computes the Artin-Hasse exponential - of ``x``, namely ``AH(x)`` as + of `x`, namely ``AH(x)`` as .. MATH:: @@ -622,7 +621,7 @@ cdef class pAdicGenericElement(LocalGenericElement): The series algorithm computes the series defining the Artin-Hasse exponential and evaluates it. - The ``Newton`` algorithm solves the equation + The ``'newton'`` algorithm solves the equation .. MATH:: @@ -631,11 +630,11 @@ cdef class pAdicGenericElement(LocalGenericElement): using a Newton scheme. It runs roughly as fast as the computation of the logarithm. - By default, we use the direct algorithm if a fast algorithm for + By default, we use the ``'direct'`` algorithm if a fast algorithm for computing the exponential is available. - If not, we use the Newton algorithm if a fast algorithm for + If not, we use the ``'newton'`` algorithm if a fast algorithm for computing the logarithm is available. - Otherwise we switch to the series algorithm. + Otherwise we switch to the ``'series'`` algorithm. OUTPUT: @@ -849,11 +848,11 @@ cdef class pAdicGenericElement(LocalGenericElement): AH(x) = \exp(x + \frac{x^p}{p} + \frac{x^{p^2}}{p^2} + \dots) - at enough precision and the plug the input element in it. + at enough precision and then plugs in the input element. INPUT: - - ``prec`` -- an integer, this precision at which the + - ``prec`` -- an integer, the precision at which the result should be computed EXAMPLES:: @@ -889,8 +888,8 @@ cdef class pAdicGenericElement(LocalGenericElement): r""" Return the Artin-Hasse exponential of this element. - If ``x`` denotes the input element, its Artin-Hasse exponential - is computed by solving the following equation in ``y`` + If `x` denotes the input element, its Artin-Hasse exponential + is computed by solving the following equation in `y` .. MATH:: @@ -903,7 +902,7 @@ cdef class pAdicGenericElement(LocalGenericElement): INPUT: - - ``prec`` -- an integer, this precision at which the + - ``prec`` -- an integer, the precision at which the result should be computed EXAMPLES:: @@ -972,7 +971,7 @@ cdef class pAdicGenericElement(LocalGenericElement): INPUT: - - ``name`` -- string (default: ``x``): the name of the variable + - ``name`` -- string (default: ``'x'``): the name of the variable - ``base`` -- a ring (default: the base ring of the parent): the base ring over which the minimal polynomial is computed @@ -1035,13 +1034,13 @@ cdef class pAdicGenericElement(LocalGenericElement): def norm(self, base=None): """ - Returns the norm of this `p`-adic element over ``base``. + Return the norm of this `p`-adic element over ``base``. .. WARNING:: This is not the `p`-adic absolute value. This is a field theoretic norm down to a base ring. If you want the - `p`-adic absolute value, use the ``abs()`` function + `p`-adic absolute value, use the method :meth:`abs` instead. INPUT: @@ -1135,22 +1134,23 @@ cdef class pAdicGenericElement(LocalGenericElement): irreducible, and indeed usually won't be if this number is a good approximation to an algebraic number of degree less than `n`. - ALGORITHM: Uses the PARI C-library ``algdep`` command. + ALGORITHM: Uses the PARI C-library :pari:`algdep` command. INPUT: - - ``self`` -- a p-adic element + - ``self`` -- a `p`-adic element - ``n`` -- an integer OUTPUT: - polynomial -- degree n polynomial approximately satisfied by self + polynomial -- degree `n` polynomial approximately satisfied by ``self`` EXAMPLES:: sage: K = Qp(3,20,'capped-rel','series'); R = Zp(3,20,'capped-rel','series') sage: a = K(7/19); a - 1 + 2*3 + 3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^8 + 2*3^9 + 3^11 + 3^12 + 2*3^15 + 2*3^16 + 3^17 + 2*3^19 + O(3^20) + 1 + 2*3 + 3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^8 + 2*3^9 + 3^11 + 3^12 + + 2*3^15 + 2*3^16 + 3^17 + 2*3^19 + O(3^20) sage: a.algdep(1) 19*x - 7 sage: K2 = Qp(7,20,'capped-rel') @@ -1160,7 +1160,8 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: b = K2.zeta(); b.algdep(4) x^4 - x^3 + x^2 - x + 1 sage: a = R(7/19); a - 1 + 2*3 + 3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^8 + 2*3^9 + 3^11 + 3^12 + 2*3^15 + 2*3^16 + 3^17 + 2*3^19 + O(3^20) + 1 + 2*3 + 3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^8 + 2*3^9 + 3^11 + 3^12 + + 2*3^15 + 2*3^16 + 3^17 + 2*3^19 + O(3^20) sage: a.algdep(1) 19*x - 7 sage: R2 = Zp(7,20,'capped-rel') @@ -1181,7 +1182,7 @@ cdef class pAdicGenericElement(LocalGenericElement): be irreducible, and indeed usually won't be if this number is a good approximation to an algebraic number of degree less than `n`. - ALGORITHM: Uses the PARI C-library algdep command. + ALGORITHM: Uses the PARI C-library :pari:`algdep` command. INPUT: @@ -1190,13 +1191,14 @@ cdef class pAdicGenericElement(LocalGenericElement): OUTPUT: - polynomial -- degree n polynomial approximately satisfied by self + polynomial -- degree `n` polynomial approximately satisfied by ``self`` EXAMPLES:: sage: K = Qp(3,20,'capped-rel','series'); R = Zp(3,20,'capped-rel','series') sage: a = K(7/19); a - 1 + 2*3 + 3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^8 + 2*3^9 + 3^11 + 3^12 + 2*3^15 + 2*3^16 + 3^17 + 2*3^19 + O(3^20) + 1 + 2*3 + 3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^8 + 2*3^9 + 3^11 + 3^12 + + 2*3^15 + 2*3^16 + 3^17 + 2*3^19 + O(3^20) sage: a.algebraic_dependency(1) 19*x - 7 sage: K2 = Qp(7,20,'capped-rel') @@ -1206,7 +1208,8 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: b = K2.zeta(); b.algebraic_dependency(4) x^4 - x^3 + x^2 - x + 1 sage: a = R(7/19); a - 1 + 2*3 + 3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^8 + 2*3^9 + 3^11 + 3^12 + 2*3^15 + 2*3^16 + 3^17 + 2*3^19 + O(3^20) + 1 + 2*3 + 3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^8 + 2*3^9 + 3^11 + 3^12 + + 2*3^15 + 2*3^16 + 3^17 + 2*3^19 + O(3^20) sage: a.algebraic_dependency(1) 19*x - 7 sage: R2 = Zp(7,20,'capped-rel') @@ -1239,7 +1242,7 @@ cdef class pAdicGenericElement(LocalGenericElement): OUTPUT: - A ``p``-- adic integer. + A `p`-adic integer. .. NOTE:: @@ -1301,9 +1304,9 @@ cdef class pAdicGenericElement(LocalGenericElement): INPUT: - ``algorithm`` -- string. Can be set to ``'pari'`` to call - the pari function, or ``'sage'`` to call the function - implemented in sage. The default is ``'pari'`` since - pari is about 10 times faster than sage. + the PARI function, or ``'sage'`` to call the function + implemented in Sage. The default is ``'pari'`` since + PARI is about 10 times faster than Sage. OUTPUT: @@ -1315,7 +1318,7 @@ cdef class pAdicGenericElement(LocalGenericElement): Villegas (http://www.ma.utexas.edu/cnt/cnt-frames.html). William Stein sped it up for GP (http://sage.math.washington.edu/home/wstein/www/home/wbhart/pari-2.4.2.alpha/src/basemath/trans2.c). - The 'sage' version uses dwork_expansion() to compute the + The ``'sage'`` version uses dwork_expansion() to compute the `p`-adic gamma function of self as in [RV2007]_ section 6.2. EXAMPLES: @@ -1368,9 +1371,9 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: p = next_prime(200) sage: F = Qp(p) - sage: l1 = [F(a/(p-1)).gamma(algorithm='pari') for a in range(p-1)] - sage: l2 = [F(a/(p-1)).gamma(algorithm='sage') for a in range(p-1)] - sage: all(l1[i] == l2[i] for i in range(p-1)) + sage: l1 = [F(a/(p-1)).gamma(algorithm='pari') for a in range(p-1)] # long time + sage: l2 = [F(a/(p-1)).gamma(algorithm='sage') for a in range(p-1)] # long time + sage: all(l1[i] == l2[i] for i in range(p-1)) # long time True The `p`-adic Gamma function has anomalous behavior for the prime 2:: @@ -1732,7 +1735,7 @@ cdef class pAdicGenericElement(LocalGenericElement): INPUT: - - ``self`` -- a p-adic element + - ``self`` -- a `p`-adic element EXAMPLES:: @@ -1900,17 +1903,17 @@ cdef class pAdicGenericElement(LocalGenericElement): def multiplicative_order(self, prec = None): r""" - Returns the multiplicative order of self, where self is + Returns the multiplicative order of ``self``, where ``self`` is considered to be one if it is one modulo `p^{\mbox{prec}}`. INPUT: - - ``self`` -- a p-adic element + - ``self`` -- a `p`-adic element - ``prec`` -- an integer OUTPUT: - - integer -- the multiplicative order of self + - integer -- the multiplicative order of ``self`` EXAMPLES:: @@ -1939,6 +1942,7 @@ cdef class pAdicGenericElement(LocalGenericElement): Over totally ramified extensions:: + sage: x = polygen(ZZ, 'x') sage: L2.<pi> = Qp(5).extension(x^4 + 5*x^3 + 10*x^2 + 10*x + 5) sage: u = 1 + pi sage: u.multiplicative_order() @@ -1996,22 +2000,22 @@ cdef class pAdicGenericElement(LocalGenericElement): return infinity def valuation(self, p = None): - """ - Returns the valuation of this element. + r""" + Return the valuation of this element. INPUT: - - ``self`` -- a p-adic element - - ``p`` -- a prime (default: None). If specified, will make sure that p==self.parent().prime() + - ``self`` -- a `p`-adic element + - ``p`` -- a prime (default: ``None``). If specified, will make sure that ``p == self.parent().prime()`` .. NOTE:: - The optional argument p is used for consistency with the valuation - methods on integer and rational. + The optional argument `p` is used for consistency with the valuation + methods on integers and rationals. OUTPUT: - integer -- the valuation of self + integer -- the valuation of ``self`` EXAMPLES:: @@ -2109,7 +2113,7 @@ cdef class pAdicGenericElement(LocalGenericElement): raise NotImplementedError cpdef val_unit(self): - """ + r""" Return ``(self.valuation(), self.unit_part())``. To be overridden in derived classes. @@ -2122,21 +2126,21 @@ cdef class pAdicGenericElement(LocalGenericElement): def ordp(self, p = None): r""" - Returns the valuation of self, normalized so that the valuation of `p` is 1 + Return the valuation of ``self``, normalized so that the valuation of `p` is 1. INPUT: - - ``self`` -- a p-adic element + - ``self`` -- a `p`-adic element - ``p`` -- a prime (default: ``None``). If specified, will make sure that ``p == self.parent().prime()`` .. NOTE:: - The optional argument p is used for consistency with the valuation - methods on integer and rational. + The optional argument `p` is used for consistency with the valuation + methods on integers and rationals. OUTPUT: - integer -- the valuation of self, normalized so that the valuation of `p` is 1 + integer -- the valuation of ``self``, normalized so that the valuation of `p` is 1 EXAMPLES:: @@ -2162,7 +2166,7 @@ cdef class pAdicGenericElement(LocalGenericElement): def is_prime(self): """ - Return whether this element is prime in its parent + Return whether this element is prime in its parent. EXAMPLES:: @@ -2178,6 +2182,7 @@ cdef class pAdicGenericElement(LocalGenericElement): :: + sage: x = polygen(ZZ, 'x') sage: B.<pi> = A.extension(x^5 - 2) sage: pi.is_prime() True @@ -2192,9 +2197,9 @@ cdef class pAdicGenericElement(LocalGenericElement): def rational_reconstruction(self): r""" - Returns a rational approximation to this `p`-adic number + Returns a rational approximation to this `p`-adic number. - This will raise an ArithmeticError if there are no valid + This will raise an :class:`ArithmeticError` if there are no valid approximations to the unit part with numerator and denominator bounded by ``sqrt(p^absprec / 2)``. @@ -2204,7 +2209,7 @@ cdef class pAdicGenericElement(LocalGenericElement): OUTPUT: - rational -- an approximation to self + rational -- an approximation to ``self`` EXAMPLES:: @@ -2245,7 +2250,7 @@ cdef class pAdicGenericElement(LocalGenericElement): def _number_field_(self, K): r""" - Return an element of K approximating this p-adic number. + Return an element of `K` approximating this `p`-adic number. INPUT: @@ -2417,7 +2422,7 @@ cdef class pAdicGenericElement(LocalGenericElement): while True: # we compute the sum for the possible values for u using Horner's method inner_sum = R.zero() - for u in xrange(upper_u,0,-1): + for u in range(upper_u,0,-1): # We want u to be a p-adic unit if u%p==0: new_term = R.zero() @@ -2546,7 +2551,7 @@ cdef class pAdicGenericElement(LocalGenericElement): the same as the input (default) or if it should change to the fraction field of the input. - - ``algorithm`` -- ``generic``, ``binary_splitting`` or ``None`` (default) + - ``algorithm`` -- ``'generic'``, ``'binary_splitting'`` or ``None`` (default) The generic algorithm evaluates naively the series defining the log, namely @@ -2556,10 +2561,10 @@ cdef class pAdicGenericElement(LocalGenericElement): Its binary complexity is quadratic with respect to the precision. - The binary splitting algorithm is faster, it has a quasi-linear + The ``'binary_splitting'`` algorithm is faster, it has a quasi-linear complexity. - By default, we use the binary splitting if it is available. Otherwise - we switch to the generic algorithm. + By default, we use ``'binary_splitting'`` if it is available. Otherwise + we switch to the ``'generic'`` algorithm. .. NOTE:: @@ -2573,7 +2578,7 @@ cdef class pAdicGenericElement(LocalGenericElement): .. TODO:: There is a soft-linear time algorithm for logarithm described - by Dan Berstein at + by Dan Bernstein at http://cr.yp.to/lineartime/multapps-20041007.pdf EXAMPLES:: @@ -2656,15 +2661,19 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: b.log(p_branch=w) w + O(w^20) sage: b.log(pi_branch=0) - 3*w^2 + 2*w^4 + 2*w^6 + 3*w^8 + 4*w^10 + w^13 + w^14 + 2*w^15 + 2*w^16 + w^18 + 4*w^19 + O(w^20) + 3*w^2 + 2*w^4 + 2*w^6 + 3*w^8 + 4*w^10 + w^13 + w^14 + 2*w^15 + + 2*w^16 + w^18 + 4*w^19 + O(w^20) sage: b.unit_part().log() - 3*w^2 + 2*w^4 + 2*w^6 + 3*w^8 + 4*w^10 + w^13 + w^14 + 2*w^15 + 2*w^16 + w^18 + 4*w^19 + O(w^20) + 3*w^2 + 2*w^4 + 2*w^6 + 3*w^8 + 4*w^10 + w^13 + w^14 + 2*w^15 + + 2*w^16 + w^18 + 4*w^19 + O(w^20) sage: y = w^2 * 4*w^7; y 4*w^9 + O(w^29) sage: y.log(p_branch=0) - 2*w^2 + 2*w^4 + 2*w^6 + 2*w^8 + w^10 + w^12 + 4*w^13 + 4*w^14 + 3*w^15 + 4*w^16 + 4*w^17 + w^18 + 4*w^19 + O(w^20) + 2*w^2 + 2*w^4 + 2*w^6 + 2*w^8 + w^10 + w^12 + 4*w^13 + 4*w^14 + 3*w^15 + + 4*w^16 + 4*w^17 + w^18 + 4*w^19 + O(w^20) sage: y.log(p_branch=w) - w + 2*w^2 + 2*w^4 + 4*w^5 + 2*w^6 + 2*w^7 + 2*w^8 + 4*w^9 + w^10 + 3*w^11 + w^12 + 4*w^14 + 4*w^16 + 2*w^17 + w^19 + O(w^20) + w + 2*w^2 + 2*w^4 + 4*w^5 + 2*w^6 + 2*w^7 + 2*w^8 + 4*w^9 + w^10 + + 3*w^11 + w^12 + 4*w^14 + 4*w^16 + 2*w^17 + w^19 + O(w^20) Check that log is multiplicative:: @@ -2677,7 +2686,8 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: A.<a> = R.ext(g) sage: b = 1 + 5*(1 + a^2) + 5^3*(3 + 2*a) sage: b.log() - (a^2 + 1)*5 + (3*a^2 + 4*a + 2)*5^2 + (3*a^2 + 2*a)*5^3 + (3*a^2 + 2*a + 2)*5^4 + O(5^5) + (a^2 + 1)*5 + (3*a^2 + 4*a + 2)*5^2 + (3*a^2 + 2*a)*5^3 + + (3*a^2 + 2*a + 2)*5^4 + O(5^5) Check that log is multiplicative:: @@ -2685,7 +2695,7 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: b.log() + c.log() - (b*c).log() O(5^5) - We illustrate the effect of the precision argument:: + We illustrate the effect of the ``precision`` argument:: sage: R = ZpCA(7,10) sage: x = R(41152263); x @@ -2723,7 +2733,8 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: w.log(p_branch=2) Traceback (most recent call last): ... - ValueError: logarithm is not integral, use change_frac=True to obtain a result in the fraction field + ValueError: logarithm is not integral, use change_frac=True + to obtain a result in the fraction field sage: w.log(p_branch=2, change_frac=True) 2*w^-3 + O(w^24) @@ -3148,10 +3159,10 @@ cdef class pAdicGenericElement(LocalGenericElement): - ``aprec`` -- an integer or ``None`` (default: ``None``); if specified, computes only up to the indicated precision - - ``algorithm`` -- ``generic``, ``binary_splitting``, ``newton`` + - ``algorithm`` -- ``'generic'``, ``'binary_splitting'``, ``'newton'`` or ``None`` (default) - The generic algorithm evaluates naively the series defining the + The ``'generic'`` algorithm evaluates naively the series defining the exponential, namely .. MATH:: @@ -3160,17 +3171,17 @@ cdef class pAdicGenericElement(LocalGenericElement): Its binary complexity is quadratic with respect to the precision. - The binary splitting algorithm is faster, it has a quasi-linear + The ``'binary_splitting'`` algorithm is faster, it has a quasi-linear complexity. - The ``Newton`` algorithms solve the equation `\log(x) =` ``self`` + The ``'newton'`` algorithms solve the equation `\log(x) =` ``self`` using a Newton scheme. It runs roughly as fast as the computation of the logarithm. - By default, we use the binary splitting if it is available. - If it is not, we use the Newton algorithm if a fast algorithm for + By default, we use the ``'binary_splitting'`` if it is available. + If it is not, we use the ``'newton'`` algorithm if a fast algorithm for computing the logarithm is available. - Otherwise we switch to the generic algorithm. + Otherwise we switch to the ``'generic'`` algorithm. EXAMPLES: @@ -3194,7 +3205,8 @@ cdef class pAdicGenericElement(LocalGenericElement): exponentials:: sage: R = Zp(5,10) - sage: e = R(2*5 + 2*5**2 + 4*5**3 + 3*5**4 + 5**5 + 3*5**7 + 2*5**8 + 4*5**9).add_bigoh(10); e + sage: e = R(2*5 + 2*5**2 + 4*5**3 + 3*5**4 + ....: + 5**5 + 3*5**7 + 2*5**8 + 4*5**9).add_bigoh(10); e 2*5 + 2*5^2 + 4*5^3 + 3*5^4 + 5^5 + 3*5^7 + 2*5^8 + 4*5^9 + O(5^10) sage: e.exp()*R.teichmuller(4) 4 + 2*5 + 3*5^3 + O(5^10) @@ -3202,7 +3214,8 @@ cdef class pAdicGenericElement(LocalGenericElement): :: sage: K = Qp(5,10) - sage: e = K(2*5 + 2*5**2 + 4*5**3 + 3*5**4 + 5**5 + 3*5**7 + 2*5**8 + 4*5**9).add_bigoh(10); e + sage: e = K(2*5 + 2*5**2 + 4*5**3 + 3*5**4 + ....: + 5**5 + 3*5**7 + 2*5**8 + 4*5**9).add_bigoh(10); e 2*5 + 2*5^2 + 4*5^3 + 3*5^4 + 5^5 + 3*5^7 + 2*5^8 + 4*5^9 + O(5^10) sage: e.exp()*K.teichmuller(4) 4 + 2*5 + 3*5^3 + O(5^10) @@ -3373,15 +3386,15 @@ cdef class pAdicGenericElement(LocalGenericElement): - ``extend`` -- a boolean (default: ``True``); if ``True``, return a square root in an extension if necessary; if ``False`` and no root - exists in the given ring or field, raise a ValueError. + exists in the given ring or field, raise a :class:`ValueError`. - ``all`` -- a boolean (default: ``False``); if ``True``, return a list of all square roots. - ``algorithm`` -- ``"pari"``, ``"sage"`` or ``None`` (default: ``None``); Sage provides an implementation for any extension of - `Q_p` whereas only square roots over `Q_p` is implemented in Pari; - the default is ``"pari"`` if the ground field is `Q_p`, ``"sage"`` + `\QQ_p`, whereas only square roots over `\QQ_p` are implemented in PARI; + the default is ``"pari"`` if the ground field is `\QQ_p`, ``"sage"`` otherwise. OUTPUT: @@ -3426,8 +3439,10 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: R.<t> = Zq(2^10, 10) sage: u = 1 + 8*t sage: u.square_root() - 1 + t*2^2 + t^2*2^3 + t^2*2^4 + (t^4 + t^3 + t^2)*2^5 + (t^4 + t^2)*2^6 + (t^5 + t^2)*2^7 + (t^6 + t^5 + t^4 + t^2)*2^8 + O(2^9) + 1 + t*2^2 + t^2*2^3 + t^2*2^4 + (t^4 + t^3 + t^2)*2^5 + (t^4 + t^2)*2^6 + + (t^5 + t^2)*2^7 + (t^6 + t^5 + t^4 + t^2)*2^8 + O(2^9) + sage: x = polygen(ZZ, 'x') sage: R.<a> = Zp(2).extension(x^3 - 2) sage: u = R(1 + a^4 + a^5 + a^7 + a^8, 10); u 1 + a^4 + a^5 + a^7 + a^8 + O(a^10) @@ -3566,14 +3581,14 @@ cdef class pAdicGenericElement(LocalGenericElement): def nth_root(self, n, all=False): """ - Return the nth root of this element. + Return the `n`-th root of this element. INPUT: - ``n`` -- an integer - ``all`` -- a boolean (default: ``False``): if ``True``, - return all ntn roots of this element, instead of just one. + return all `n`-th roots of this element, instead of just one. EXAMPLES:: @@ -3593,7 +3608,7 @@ cdef class pAdicGenericElement(LocalGenericElement): When `n` is divisible by the underlying prime `p`, we are losing precision (which is consistent with the fact - that raising to the pth power increases precision):: + that raising to the `p`-th power increases precision):: sage: z = x.nth_root(5); z 1 + 5^2 + 3*5^3 + 2*5^4 + 5^5 + 3*5^7 + 2*5^8 + O(5^9) @@ -3610,7 +3625,7 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: R(5).nth_root(7, all=True) [pi + O(pi^141)] - An error is raised if the given element is not a nth power + An error is raised if the given element is not an `n`-th power in the ring:: sage: R(5).nth_root(11) @@ -3632,7 +3647,7 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: K = Qp(29) sage: x = polygen(K) - sage: L.<a> = K.extension(x^2 -29) + sage: L.<a> = K.extension(x^2 - 29) sage: L(4).nth_root(2) 2 + O(a^40) @@ -3836,9 +3851,9 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: S.<x> = W[] sage: R.<pi> = W.extension(x^8 + 15*a*x - 5) sage: y = R.random_element() - sage: for n in [5, 10, 15]: + sage: for n in [5, 10, 15]: # indirect doctest ....: z = y**n - ....: assert z.nth_root(n)**n == z # indirect doctest + ....: assert z.nth_root(n)**n == z """ ring = self.parent() @@ -4036,8 +4051,8 @@ cdef class pAdicGenericElement(LocalGenericElement): return Rational(K.prime())**(-self.valuation()) cpdef bint _is_base_elt(self, p) except -1: - """ - Return ``True`` if this element is an element of Zp or Qp (rather than + r""" + Return ``True`` if this element is an element of `\ZZ_p` or `\QQ_p` (rather than an extension). INPUT: @@ -4085,7 +4100,7 @@ cdef class pAdicGenericElement(LocalGenericElement): ValueError: Polylogarithm only implemented for n at least 2. """ from sage.rings.power_series_ring import PowerSeriesRing - from sage.functions.other import ceil,floor + from sage.arith.misc import integer_ceil as ceil, integer_floor as floor from sage.rings.padics.factory import Qp from sage.misc.verbose import verbose @@ -4148,7 +4163,7 @@ cdef class pAdicGenericElement(LocalGenericElement): - ``n`` -- a non-negative integer - ``p_branch`` -- an element in the base ring or its fraction field; the implementation will choose the branch of the - logarithm which sends `p` to ``branch`` + logarithm which sends `p` to ``p_branch`` EXAMPLES: @@ -4227,7 +4242,7 @@ cdef class pAdicGenericElement(LocalGenericElement): from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.padics.factory import Qp from sage.misc.verbose import verbose - from sage.functions.other import ceil,floor + from sage.arith.misc import integer_ceil as ceil, integer_floor as floor from sage.rings.infinity import PlusInfinity if self.parent().absolute_degree() != 1: @@ -4376,7 +4391,8 @@ def _AHE_coefficients(p, N, prec): """ from sage.rings.padics.factory import ZpFM - from sage.functions.other import floor + from sage.arith.misc import integer_floor as floor + if N < p: internal_prec = prec else: @@ -4437,7 +4453,8 @@ def _findprec(c_1, c_2, c_3, p): See Remark 7.11 of [BdJ2008]_. """ - from sage.functions.other import ceil + from sage.arith.misc import integer_ceil as ceil + k = Integer(max(ceil(c_2/c_1), 2)) while True: if c_1*k - c_2*k.log(p).n() > c_3: @@ -4457,7 +4474,7 @@ def _compute_g(p, n, prec, terms): O(7^3)*v^2 + (1 + O(7^3))*v + O(7^3) """ from sage.rings.power_series_ring import PowerSeriesRing - from sage.functions.other import ceil + from sage.arith.misc import integer_ceil as ceil from sage.rings.padics.factory import Qp # Compute the sequence of power series g @@ -4478,7 +4495,7 @@ cpdef dwork_mahler_coeffs(R, int bd=20): INPUT: - - ``R`` -- p-adic ring in which to compute + - ``R`` -- `p`-adic ring in which to compute - ``bd`` -- integer. Number of terms in the expansion to use OUTPUT: @@ -4492,9 +4509,11 @@ cpdef dwork_mahler_coeffs(R, int bd=20): sage: v = dwork_mahler_coeffs(R) sage: x = R(1/7) sage: evaluate_dwork_mahler(v, x, 3, 20, 1) - 2 + 2*3 + 3^2 + 3^3 + 3^4 + 3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^11 + 2*3^12 + 3^13 + 3^14 + 2*3^16 + 3^17 + 3^19 + O(3^20) - sage: x.dwork_expansion(a=1) # Same result - 2 + 2*3 + 3^2 + 3^3 + 3^4 + 3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^11 + 2*3^12 + 3^13 + 3^14 + 2*3^16 + 3^17 + 3^19 + O(3^20) + 2 + 2*3 + 3^2 + 3^3 + 3^4 + 3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^11 + + 2*3^12 + 3^13 + 3^14 + 2*3^16 + 3^17 + 3^19 + O(3^20) + sage: x.dwork_expansion(a=1) # Same result + 2 + 2*3 + 3^2 + 3^3 + 3^4 + 3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^11 + + 2*3^12 + 3^13 + 3^14 + 2*3^16 + 3^17 + 3^19 + O(3^20) """ from sage.rings.padics.factory import Qp cdef int i @@ -4526,9 +4545,11 @@ cpdef evaluate_dwork_mahler(v, x, long long p, int bd, long long a): sage: v = dwork_mahler_coeffs(R) sage: x = R(1/7) sage: evaluate_dwork_mahler(v, x, 3, 20, 1) - 2 + 2*3 + 3^2 + 3^3 + 3^4 + 3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^11 + 2*3^12 + 3^13 + 3^14 + 2*3^16 + 3^17 + 3^19 + O(3^20) - sage: x.dwork_expansion(a=1) # Same result - 2 + 2*3 + 3^2 + 3^3 + 3^4 + 3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^11 + 2*3^12 + 3^13 + 3^14 + 2*3^16 + 3^17 + 3^19 + O(3^20) + 2 + 2*3 + 3^2 + 3^3 + 3^4 + 3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^11 + + 2*3^12 + 3^13 + 3^14 + 2*3^16 + 3^17 + 3^19 + O(3^20) + sage: x.dwork_expansion(a=1) # Same result + 2 + 2*3 + 3^2 + 3^3 + 3^4 + 3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^11 + + 2*3^12 + 3^13 + 3^14 + 2*3^16 + 3^17 + 3^19 + O(3^20) """ cdef int k bd -= 1 @@ -4567,16 +4588,16 @@ cpdef gauss_table(long long p, int f, int prec, bint use_longs): INPUT: - - `p` - prime - - `f`, `prec` - positive integers - - `use_longs` - boolean; if True, computations are done in C long long + - ``p`` - prime + - ``f``, ``prec`` - positive integers + - ``use_longs`` - boolean; if ``True``, computations are done in C ``long long`` integers rather than Sage `p`-adics, and the results are returned as a Python array rather than a list. OUTPUT: A list of length `q-1=p^f-1`. The entries are `p`-adic units created with - absolute precision `prec`. + absolute precision ``prec``. EXAMPLES:: diff --git a/src/sage/rings/padics/padic_lattice_element.py b/src/sage/rings/padics/padic_lattice_element.py index 3518ce86c67..a8d9e507b90 100644 --- a/src/sage/rings/padics/padic_lattice_element.py +++ b/src/sage/rings/padics/padic_lattice_element.py @@ -17,10 +17,11 @@ sage: R3 = QpLC(2) sage: R4 = QpLF(2) - sage: TestSuite(R1).run(skip=['_test_teichmuller', '_test_matrix_smith']) # long time - sage: TestSuite(R2).run(skip=['_test_teichmuller', '_test_matrix_smith']) # long time - sage: TestSuite(R3).run(skip=['_test_teichmuller', '_test_matrix_smith']) # long time - sage: TestSuite(R4).run(skip=['_test_teichmuller', '_test_matrix_smith']) # long time + sage: # long time + sage: TestSuite(R1).run(skip=['_test_teichmuller', '_test_matrix_smith']) + sage: TestSuite(R2).run(skip=['_test_teichmuller', '_test_matrix_smith']) + sage: TestSuite(R3).run(skip=['_test_teichmuller', '_test_matrix_smith']) + sage: TestSuite(R4).run(skip=['_test_teichmuller', '_test_matrix_smith']) """ # **************************************************************************** @@ -1010,7 +1011,7 @@ def unit_part(self): sage: b.unit_part() 1 + 16*17 + O(17^3) - If the element is indistinguishable from zero, an error is raised. + If the element is indistinguishable from zero, an error is raised:: sage: c = R(0, 5); c O(17^5) diff --git a/src/sage/rings/padics/padic_printing.pyx b/src/sage/rings/padics/padic_printing.pyx index e989d236c09..344a1e544a7 100644 --- a/src/sage/rings/padics/padic_printing.pyx +++ b/src/sage/rings/padics/padic_printing.pyx @@ -48,16 +48,16 @@ cdef enum print_modes: def pAdicPrinter(ring, options={}): """ - Creates a pAdicPrinter. + Create a :class:`pAdicPrinter`. INPUT: - - ring -- a p-adic ring or field. + - ring -- a p-adic ring or field. - - options -- a dictionary, with keys in 'mode', 'pos', - 'ram_name', 'unram_name', 'var_name', 'max_ram_terms', - 'max_unram_terms', 'max_terse_terms', 'sep', 'alphabet'; see - pAdicPrinter_class for the meanings of these keywords. + - options -- a dictionary, with keys in ``'mode'``, ``'pos'``, + ``'ram_name'``, ``'unram_name'``, ``'var_name'``, ``'max_ram_terms'``, + ``'max_unram_terms'``, ``'max_terse_terms'``, ``'sep'``, ``'alphabet'``; see + :class:`pAdicPrinter_class` for the meanings of these keywords. EXAMPLES:: @@ -76,7 +76,7 @@ class pAdicPrinterDefaults(SageObject): This class stores global defaults for p-adic printing. """ def __init__(self, mode = 'series', pos = True, max_ram_terms = -1, max_unram_terms = -1, max_terse_terms = -1, sep = "|", alphabet = None): - """ + r""" Instances of this class store global defaults used in determining printing options during the creation of p-adic rings and fields. One instance stored in padic_printing @@ -109,13 +109,13 @@ class pAdicPrinterDefaults(SageObject): self._alphabet = alphabet def mode(self, mode=None): - """ + r""" Set the default printing mode. - mode=None returns the current value. + ``mode=None`` returns the current value. - The allowed values for mode are: 'val-unit', 'series', - 'terse', 'digits' and 'bars'. + The allowed values for mode are: ``'val-unit'``, ``'series'``, + ``'terse'``, ``'digits'`` and ``'bars'``. EXAMPLES:: @@ -150,10 +150,10 @@ class pAdicPrinterDefaults(SageObject): raise ValueError("invalid printing mode") def allow_negatives(self, neg = None): - """ + r""" Controls whether or not to display a balanced representation. - neg=None returns the current value. + ``neg=None`` returns the current value. EXAMPLES:: @@ -172,13 +172,13 @@ class pAdicPrinterDefaults(SageObject): self._pos = not neg def max_series_terms(self, max = None): - """ + r""" Controls the maximum number of terms shown when printing in - 'series', 'digits' or 'bars' mode. + ``'series'``, ``'digits'`` or ``'bars'`` mode. - max=None returns the current value. + ``max=None`` returns the current value. - max=-1 encodes 'no limit.' + ``max=-1`` encodes 'no limit.' EXAMPLES:: @@ -197,14 +197,14 @@ class pAdicPrinterDefaults(SageObject): self._max_ram_terms = int(max) def max_unram_terms(self, max = None): - """ + r""" For rings with non-prime residue fields, controls how many - terms appear in the coefficient of each pi^n when printing in - 'series' or 'bar' modes. + terms appear in the coefficient of each ``pi^n`` when printing in + ``'series'`` or ``'bar'`` modes. - max=None returns the current value. + ``max=None`` returns the current value. - max=-1 encodes 'no limit.' + ``max=-1`` encodes 'no limit.' EXAMPLES:: @@ -222,13 +222,13 @@ class pAdicPrinterDefaults(SageObject): self._max_unram_terms = int(max) def max_poly_terms(self, max = None): - """ + r""" Controls the number of terms appearing when printing - polynomial representations in 'terse' or 'val-unit' modes. + polynomial representations in ``'terse'`` or ``'val-unit'`` modes. - max=None returns the current value. + ``max=None`` returns the current value. - max=-1 encodes 'no limit.' + ``max=-1`` encodes 'no limit.' EXAMPLES:: @@ -248,10 +248,10 @@ class pAdicPrinterDefaults(SageObject): self._max_terse_terms = int(max) def sep(self, sep = None): - """ - Controls the separator used in 'bars' mode. + r""" + Controls the separator used in ``'bars'`` mode. - sep=None returns the current value. + ``sep=None`` returns the current value. EXAMPLES:: @@ -271,13 +271,13 @@ class pAdicPrinterDefaults(SageObject): self._sep = str(sep) def alphabet(self, alphabet = None): - """ + r""" Controls the alphabet used to translate p-adic digits into - strings (so that no separator need be used in 'digits' mode). + strings (so that no separator need be used in ``'digits'`` mode). - alphabet should be passed in as a list or tuple. + ``alphabet`` should be passed in as a list or tuple. - alphabet=None returns the current value. + ``alphabet=None`` returns the current value. EXAMPLES:: @@ -305,11 +305,11 @@ cdef class pAdicPrinter_class(SageObject): """ def __init__(self, ring, mode, pos, ram_name, unram_name, var_name, max_ram_terms, max_unram_terms, max_terse_terms, sep, alphabet, show_prec): """ - Initializes a pAdicPrinter. + Initializes a :class:`pAdicPrinter`. INPUT: - - ring -- the ring or field to which this pAdicPrinter is + - ring -- the ring or field to which this :class:`pAdicPrinter` is attached. - mode -- The allowed values for mode are: 'val-unit', @@ -483,18 +483,17 @@ cdef class pAdicPrinter_class(SageObject): sage: P._sep() '&' """ - - return pAdicPrinter, (self.ring, \ - {'mode': self._print_mode(), \ - 'pos': self.pos, \ - 'ram_name': self.ram_name, \ - 'unram_name': self.unram_name, \ - 'var_name': self.var_name, \ - 'max_ram_terms': self.max_ram_terms, \ - 'max_unram_terms': self.max_unram_terms, \ - 'max_terse_terms': self.max_terse_terms, \ - 'sep':self.sep, \ - 'alphabet': self.alphabet, \ + return pAdicPrinter, (self.ring, + {'mode': self._print_mode(), + 'pos': self.pos, + 'ram_name': self.ram_name, + 'unram_name': self.unram_name, + 'var_name': self.var_name, + 'max_ram_terms': self.max_ram_terms, + 'max_unram_terms': self.max_unram_terms, + 'max_terse_terms': self.max_terse_terms, + 'sep':self.sep, + 'alphabet': self.alphabet, 'show_prec': self.show_prec}) def __richcmp__(self, other, op): @@ -515,14 +514,14 @@ cdef class pAdicPrinter_class(SageObject): def richcmp_modes(pAdicPrinter_class self, pAdicPrinter_class other, int op): """ - Return a comparison of the printing modes of self and other. + Return a comparison of the printing modes of ``self`` and ``other``. Return 0 if and only if all relevant modes are equal - (max_unram_terms is irrelevant if the ring is totally ramified - over the base for example). This does not check if the rings are + (``max_unram_terms`` is irrelevant if the ring is totally ramified + over the base, for example). This does not check if the rings are equal (to prevent infinite recursion in the comparison functions of p-adic rings), but it does check if the primes - are the same (since the prime affects whether pos is + are the same (since the prime affects whether ``pos`` is relevant). EXAMPLES:: @@ -532,7 +531,7 @@ cdef class pAdicPrinter_class(SageObject): sage: R._printer == S._printer True sage: R = Qp(7) - sage: S = Qp(7,print_mode='val-unit') + sage: S = Qp(7, print_mode='val-unit') sage: R == S False sage: R._printer < S._printer @@ -637,7 +636,7 @@ cdef class pAdicPrinter_class(SageObject): def dict(self): """ - Returns a dictionary storing all of self's printing options. + Return a dictionary storing all of ``self``'s printing options. EXAMPLES:: @@ -850,10 +849,10 @@ cdef class pAdicPrinter_class(SageObject): INPUT: - - elt -- a p-adic element of the appropriate ring to print. + - ``elt`` -- a p-adic element of the appropriate ring to print. - - do_latex -- whether to return a latex representation or - a normal one. + - ``do_latex`` -- whether to return a latex representation or + a normal one. EXAMPLES:: diff --git a/src/sage/rings/padics/padic_template_element.pxi b/src/sage/rings/padics/padic_template_element.pxi index 712f7dc9eeb..06cc00e73f0 100644 --- a/src/sage/rings/padics/padic_template_element.pxi +++ b/src/sage/rings/padics/padic_template_element.pxi @@ -22,20 +22,23 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from cpython.int cimport * +from cpython.long cimport * from sage.libs.gmp.all cimport * import sage.rings.finite_rings.integer_mod from cypari2.types cimport * from cypari2.gen cimport Gen as pari_gen from sage.libs.pari.convert_gmp cimport INT_to_mpz +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.padics.common_conversion cimport get_ordp, get_preccap from sage.rings.integer cimport Integer from sage.rings.infinity import infinity from sage.rings.rational import Rational from sage.rings.padics.precision_error import PrecisionError from sage.rings.padics.misc import trim_zeros +from sage.rings.polynomial.polynomial_element import Polynomial from sage.structure.element import canonical_coercion + import itertools cdef long maxordp = (1L << (sizeof(long) * 8 - 2)) - 1 @@ -144,7 +147,7 @@ cdef class pAdicTemplateElement(pAdicGenericElement): elif sage.rings.finite_rings.integer_mod.is_IntegerMod(x): if not Integer(self.prime_pow.prime).divides(x.parent().order()): raise TypeError("p does not divide modulus %s"%x.parent().order()) - elif sage.rings.finite_rings.element_base.is_FiniteFieldElement(x): + elif isinstance(x, Element) and isinstance(x.parent(), FiniteField): k = self.parent().residue_field() if not k.has_coerce_map_from(x.parent()): raise NotImplementedError("conversion from finite fields which do not embed into the residue field not implemented") @@ -155,7 +158,7 @@ cdef class pAdicTemplateElement(pAdicGenericElement): x = x + [k.prime_subfield().zero()] * (k.degree() - len(x)) elif isinstance(x, (Integer, Rational, list, tuple)): pass - elif sage.rings.polynomial.polynomial_element.is_Polynomial(x) and x.variable_name() == self.parent().variable_name(): + elif isinstance(x, Polynomial) and x.variable_name() == self.parent().variable_name(): x = x.list() else: x = Rational(x) @@ -250,7 +253,7 @@ cdef class pAdicTemplateElement(pAdicGenericElement): # The "verify that shift is an integer" part could be shared cdef long s if isinstance(shift, int): - s = PyInt_AS_LONG(shift) + s = PyLong_AsLong(shift) else: if not isinstance(shift, Integer): shift = Integer(shift) @@ -298,7 +301,7 @@ cdef class pAdicTemplateElement(pAdicGenericElement): """ cdef long s if isinstance(shift, int): - s = PyInt_AS_LONG(shift) + s = PyLong_AsLong(shift) else: if not isinstance(shift, Integer): shift = Integer(shift) diff --git a/src/sage/rings/padics/padic_valuation.py b/src/sage/rings/padics/padic_valuation.py index 2d444d0e676..b6ea2ea75ee 100644 --- a/src/sage/rings/padics/padic_valuation.py +++ b/src/sage/rings/padics/padic_valuation.py @@ -122,7 +122,7 @@ def create_key_and_extra_args(self, R, prime=None, approximants=None): from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.padics.padic_generic import pAdicGeneric - from sage.rings.number_field.number_field import is_NumberField + from sage.rings.number_field.number_field_base import NumberField from sage.rings.polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing if R.characteristic() != 0: @@ -133,10 +133,10 @@ def create_key_and_extra_args(self, R, prime=None, approximants=None): return self.create_key_for_integers(R, prime), {} elif isinstance(R, pAdicGeneric): return self.create_key_for_local_ring(R, prime), {} - elif is_NumberField(R.fraction_field()) or is_PolynomialQuotientRing(R): + elif isinstance(R.fraction_field(), NumberField) or is_PolynomialQuotientRing(R): return self.create_key_and_extra_args_for_number_field(R, prime, approximants=approximants) else: - raise NotImplementedError("p-adic valuations not implemented for %r"%(R,)) + raise NotImplementedError("p-adic valuations not implemented for %r" % (R,)) def create_key_for_integers(self, R, prime): r""" @@ -156,7 +156,7 @@ def create_key_for_integers(self, R, prime): if isinstance(prime, DiscretePseudoValuation): prime = prime.uniformizer() if prime not in ZZ or not ZZ(prime).is_prime(): - raise ValueError("prime must be a prime in the integers but %s is not"%(prime,)) + raise ValueError("prime must be a prime in the integers but %s is not" % (prime,)) return R, prime def create_key_for_local_ring(self, R, prime): @@ -254,8 +254,7 @@ def create_key_and_extra_args_for_number_field_from_valuation(self, R, v, prime, # v is defined on a ring whose field of fractions is L v = v._base_valuation._initial_approximation.change_domain(G.parent()) else: - raise NotImplementedError("cannot rewrite %r which is defined on %r as a pseudo-valuation on %r"%(v, v.domain(), G.parent())) - + raise NotImplementedError("cannot rewrite %r which is defined on %r as a pseudo-valuation on %r" % (v, v.domain(), G.parent())) assert(v.domain() is G.parent()) @@ -283,7 +282,7 @@ def create_key_and_extra_args_for_number_field_from_ideal(self, R, I, prime): EXAMPLES:: - sage: GaussianIntegers().valuation(GaussianIntegers().ideal(2)) # indirect doctest + sage: GaussianIntegers().valuation(GaussianIntegers().number_field().fractional_ideal(2)) # indirect doctest 2-adic valuation TESTS: @@ -316,7 +315,7 @@ def create_key_and_extra_args_for_number_field_from_ideal(self, R, I, prime): p = I.relative_norm() F = p.factor() if len(F) != 1: - raise ValueError("%r does not lie over a single prime of %r"%(I, K)) + raise ValueError("%r does not lie over a single prime of %r" % (I, K)) vK = K.valuation(F[0][0]) approximants = vK.mac_lane_approximants(G, require_incomparability=True) @@ -337,7 +336,7 @@ def create_key_and_extra_args_for_number_field_from_ideal(self, R, I, prime): match = [i for (i, v) in enumerate(candidates) if v and all(v(g) > 0 for g in gens)] if len(match) > 1: - raise ValueError("%s does not single out a unique extension of %s to %s"%(prime, vK, L)) + raise ValueError("%s does not single out a unique extension of %s to %s" % (prime, vK, L)) if len(match) == 1: return (R, approximants[match[0]]), {'approximants': approximants} @@ -362,15 +361,15 @@ def _normalize_number_field_data(self, R): """ from sage.rings.polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing - from sage.rings.number_field.number_field import is_NumberField - if is_NumberField(R.fraction_field()): + from sage.rings.number_field.number_field_base import NumberField + if isinstance(R.fraction_field(), NumberField): L = R.fraction_field() G = L.relative_polynomial() K = L.base_ring() elif is_PolynomialQuotientRing(R): from sage.categories.number_fields import NumberFields if R.base_ring().fraction_field() not in NumberFields(): - raise NotImplementedError("cannot normalize quotients over %r"%(R.base_ring(),)) + raise NotImplementedError("cannot normalize quotients over %r" % (R.base_ring(),)) L = R.fraction_field() K = R.base_ring().fraction_field() G = R.modulus().change_ring(K) @@ -379,7 +378,6 @@ def _normalize_number_field_data(self, R): return K, L, G - def create_object(self, version, key, **extra_args): r""" Create a `p`-adic valuation from ``key``. @@ -395,22 +393,22 @@ def create_object(self, version, key, **extra_args): from sage.rings.padics.padic_generic import pAdicGeneric from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace from sage.rings.polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing - from sage.rings.number_field.number_field import is_NumberField + from sage.rings.number_field.number_field_base import NumberField R = key[0] parent = DiscretePseudoValuationSpace(R) if isinstance(R, pAdicGeneric): - assert(len(key)==1) + assert(len(key) == 1) return parent.__make_element_class__(pAdicValuation_padic)(parent) elif R is ZZ or R is QQ: prime = key[1] - assert(len(key)==2) + assert(len(key) == 2) return parent.__make_element_class__(pAdicValuation_int)(parent, prime) else: v = key[1] approximants = extra_args['approximants'] parent = DiscretePseudoValuationSpace(R) K = R.fraction_field() - if is_NumberField(K): + if isinstance(K, NumberField): G = K.relative_polynomial() elif is_PolynomialQuotientRing(R): G = R.modulus() @@ -418,8 +416,10 @@ def create_object(self, version, key, **extra_args): raise NotImplementedError return parent.__make_element_class__(pAdicFromLimitValuation)(parent, v, G.change_ring(R.base_ring()), approximants) + pAdicValuation = PadicValuationFactory("sage.rings.padics.padic_valuation.pAdicValuation") + class pAdicValuation_base(DiscreteValuation): r""" Abstract base class for `p`-adic valuations. @@ -439,7 +439,7 @@ class pAdicValuation_base(DiscreteValuation): sage: QQ.valuation(5) 5-adic valuation - For `p`-adic rings, ``p`` has to match the `p` of the ring. + For `p`-adic rings, ``p`` has to match the `p` of the ring. :: sage: v = valuations.pAdicValuation(Zp(3), 2); v Traceback (most recent call last): @@ -592,7 +592,7 @@ def is_unramified(self, G, include_steps=False, assume_squarefree=False): break next = v.mac_lane_step(G, assume_squarefree=True) - if len(next)>1: + if len(next) > 1: ret = False break steps.append(next[0]) @@ -689,7 +689,7 @@ def is_totally_ramified(self, G, include_steps=False, assume_squarefree=False): break next = v.mac_lane_step(G, assume_squarefree=True) - if len(next)>1: + if len(next) > 1: ret = False break steps.append(next[0]) @@ -740,6 +740,7 @@ def extensions(self, ring): TESTS:: sage: R.<a> = QQ[] + sage: x = polygen(ZZ, 'x') sage: L.<a> = QQ.extension(x^3 - 2) sage: R.<b> = L[] sage: M.<b> = L.extension(b^2 + 2*b + a) @@ -803,8 +804,8 @@ def extensions(self, ring): return self._extensions_to_quotient(ring) elif self.domain().is_subring(ring.base_ring()): return sum([w.extensions(ring) for w in self.extensions(ring.base_ring())], []) - from sage.rings.number_field.number_field import is_NumberField - if is_NumberField(ring.fraction_field()): + from sage.rings.number_field.number_field_base import NumberField + if isinstance(ring.fraction_field(), NumberField): if ring.base_ring().fraction_field() is self.domain().fraction_field(): approximants = self.mac_lane_approximants(ring.fraction_field().relative_polynomial().change_ring(self.domain()), assume_squarefree=True, require_incomparability=True) return [pAdicValuation(ring, approximant, approximants) for approximant in approximants] @@ -827,7 +828,7 @@ def restriction(self, ring): return self if not ring.is_subring(self.domain()): - raise ValueError("ring must be a subring of the domain of this valuation but %r is not a subring of %r"%(ring, self.domain())) + raise ValueError("ring must be a subring of the domain of this valuation but %r is not a subring of %r" % (ring, self.domain())) return pAdicValuation(ring, self.p()) @@ -962,7 +963,7 @@ def element_with_valuation(self, v): from sage.rings.rational_field import QQ v = QQ(v) if v not in self.value_semigroup(): - raise ValueError("%r is not in the value semigroup of %r"%(v, self)) + raise ValueError("%r is not in the value semigroup of %r" % (v, self)) v = ZZ(v * self.domain().absolute_e()) return self.domain().one() << v @@ -976,7 +977,7 @@ def _repr_(self): '3-adic valuation' """ - return "%s-adic valuation"%(self.p()) + return "%s-adic valuation" % (self.p()) def _call_(self, x): r""" @@ -1101,7 +1102,7 @@ def _repr_(self): '3-adic valuation' """ - return "%s-adic valuation"%(self.p()) + return "%s-adic valuation" % (self.p()) def _call_(self, x): """ @@ -1280,7 +1281,7 @@ def simplify(self, x, error=None, force=False, size_heuristic_bound=32): if self._relative_size(rational) < self._relative_size(best): best = rational - assert(self(x-best)>error) + assert(self(x-best) > error) return best @@ -1386,6 +1387,7 @@ def _to_base_domain(self, f): Check that this also works for relative extensions:: sage: v = QQ.valuation(2) + sage: x = polygen(ZZ, 'x') sage: L.<a> = NumberField(x^2 + 2) sage: M.<b> = L.extension(x^2 + 1) sage: w = v.extension(L).extension(M) diff --git a/src/sage/rings/padics/pow_computer.pxd b/src/sage/rings/padics/pow_computer.pxd index 2a93e42254e..8766725882e 100644 --- a/src/sage/rings/padics/pow_computer.pxd +++ b/src/sage/rings/padics/pow_computer.pxd @@ -6,7 +6,7 @@ cdef class PowComputer_class(SageObject): cdef Integer prime cdef Integer p2 # floor(p/2) cdef bint in_field - cdef int __allocated + cdef int _allocated cdef public object _prec_type cdef long ram_prec_cap # = prec_cap * e diff --git a/src/sage/rings/padics/pow_computer.pyx b/src/sage/rings/padics/pow_computer.pyx index c2fa8031086..1c5bdf86897 100644 --- a/src/sage/rings/padics/pow_computer.pyx +++ b/src/sage/rings/padics/pow_computer.pyx @@ -65,7 +65,7 @@ cdef class PowComputer_class(SageObject): sig_on() mpz_init(self.temp_m) sig_off() - self.__allocated = 1 + self._allocated = 1 def __init__(self, Integer prime, long cache_limit, long prec_cap, long ram_prec_cap, bint in_field, poly=None, shift_seed=None): """ @@ -485,7 +485,7 @@ cdef class PowComputer_base(PowComputer_class): finally: sig_off() - self.__allocated = 2 + self._allocated = 2 def __init__(self, Integer prime, long cache_limit, long prec_cap, long ram_prec_cap, bint in_field, poly=None, shift_seed=None): """ @@ -529,7 +529,7 @@ cdef class PowComputer_base(PowComputer_class): """ cdef Py_ssize_t i - if self.__allocated >= 2: + if self._allocated >= 2: for i in range(self.cache_limit + 1): mpz_clear(self.small_powers[i]) mpz_clear(self.top_power) diff --git a/src/sage/rings/padics/pow_computer_ext.pyx b/src/sage/rings/padics/pow_computer_ext.pyx index fe60e6bde33..1626990a051 100644 --- a/src/sage/rings/padics/pow_computer_ext.pyx +++ b/src/sage/rings/padics/pow_computer_ext.pyx @@ -42,8 +42,7 @@ AUTHORS: - David Roe (2008-01-01) initial version """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 David Roe <roed.math@gmail.com> # William Stein <wstein@gmail.com> # @@ -51,8 +50,8 @@ AUTHORS: # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cpython.list cimport * from cpython.dict cimport * @@ -61,9 +60,7 @@ from cysignals.signals cimport sig_on, sig_off include "sage/libs/ntl/decl.pxi" -import weakref -from sage.misc.misc import cputime -from sage.rings.infinity import infinity +from sage.misc.timing import cputime from sage.libs.gmp.mpz cimport * from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_factory from sage.libs.ntl.ntl_ZZ_pContext import ZZ_pContext_factory diff --git a/src/sage/rings/padics/pow_computer_flint.pyx b/src/sage/rings/padics/pow_computer_flint.pyx index 9f914defcc6..e521ea6e078 100644 --- a/src/sage/rings/padics/pow_computer_flint.pyx +++ b/src/sage/rings/padics/pow_computer_flint.pyx @@ -59,7 +59,7 @@ cdef class PowComputer_flint(PowComputer_class): finally: sig_off() - self.__allocated = 4 + self._allocated = 4 def __init__(self, Integer prime, long cache_limit, long prec_cap, long ram_prec_cap, bint in_field, poly=None, shift_seed=None): """ @@ -87,7 +87,7 @@ cdef class PowComputer_flint(PowComputer_class): sage: A = PowComputer_flint(5, 20, 20, 20, False) sage: del A """ - if self.__allocated >= 4: + if self._allocated >= 4: fmpz_clear(self.fprime) fmpz_clear(self.half_prime) fmpz_clear(self._fpow_variable) @@ -208,7 +208,7 @@ cdef class PowComputer_flint_1step(PowComputer_flint): """ cdef Polynomial_integer_dense_flint poly = _poly - cdef long length = fmpz_poly_length(poly.__poly) + cdef long length = fmpz_poly_length(poly._poly) cdef Py_ssize_t i @@ -251,7 +251,7 @@ cdef class PowComputer_flint_1step(PowComputer_flint): finally: sig_off() - self.__allocated = 8 + self._allocated = 8 def __init__(self, Integer prime, long cache_limit, long prec_cap, long ram_prec_cap, bint in_field, _poly, shift_seed=None): """ @@ -268,10 +268,10 @@ cdef class PowComputer_flint_1step(PowComputer_flint): PowComputer_flint.__init__(self, prime, cache_limit, prec_cap, ram_prec_cap, in_field, _poly, shift_seed) cdef Polynomial_integer_dense_flint poly = _poly - cdef long length = fmpz_poly_length(poly.__poly) + cdef long length = fmpz_poly_length(poly._poly) self.deg = length - 1 - fmpz_poly_set(self.modulus, poly.__poly) + fmpz_poly_set(self.modulus, poly._poly) cdef Py_ssize_t i cdef fmpz* coeffs = self.modulus.coeffs @@ -296,7 +296,7 @@ cdef class PowComputer_flint_1step(PowComputer_flint): """ cdef Py_ssize_t i - if self.__allocated >= 8: + if self._allocated >= 8: fmpz_clear(self.q) fmpz_poly_clear(self.modulus) fmpz_poly_clear(self.powhelper_oneunit) @@ -427,9 +427,9 @@ cdef class PowComputer_flint_1step(PowComputer_flint): x = R.gen() cdef Polynomial_integer_dense_flint ans = (<Polynomial_integer_dense_flint?>x)._new() if _n is None: - fmpz_poly_set(ans.__poly, self.modulus) + fmpz_poly_set(ans._poly, self.modulus) else: - fmpz_poly_set(ans.__poly, self.get_modulus(_n)[0]) + fmpz_poly_set(ans._poly, self.get_modulus(_n)[0]) return ans cdef _new_fmpz_poly(self, fmpz_poly_t value, var='x'): @@ -440,7 +440,7 @@ cdef class PowComputer_flint_1step(PowComputer_flint): R = ZZ[var] x = R.gen() cdef Polynomial_integer_dense_flint ans = (<Polynomial_integer_dense_flint?>x)._new() - fmpz_poly_set(ans.__poly, value) + fmpz_poly_set(ans._poly, value) return ans cdef class PowComputer_flint_unram(PowComputer_flint_1step): @@ -501,7 +501,7 @@ cdef class PowComputer_flint_unram(PowComputer_flint_1step): mpz_init(self.mpz_matmod) sig_off() - self.__allocated = 16 + self._allocated = 16 def __dealloc__(self): """ @@ -515,7 +515,7 @@ cdef class PowComputer_flint_unram(PowComputer_flint_1step): sage: del A """ - if self.__allocated >= 16: + if self._allocated >= 16: fmpz_clear(self.fmpz_ccmp) fmpz_clear(self.fmpz_cval) fmpz_clear(self.fmpz_cinv) diff --git a/src/sage/rings/padics/pow_computer_relative.pxd b/src/sage/rings/padics/pow_computer_relative.pxd index fc7d5b21f42..e0e5aa5600e 100644 --- a/src/sage/rings/padics/pow_computer_relative.pxd +++ b/src/sage/rings/padics/pow_computer_relative.pxd @@ -18,7 +18,7 @@ cdef class PowComputer_relative(PowComputer_class): cdef Polynomial_generic_dense shift_rem cdef Polynomial_generic_dense aliasing # allow cached methods - cdef public dict __cached_methods + cdef public dict _cached_methods cdef unsigned long capdiv(self, unsigned long n) diff --git a/src/sage/rings/padics/pow_computer_relative.pyx b/src/sage/rings/padics/pow_computer_relative.pyx index 29cee93968c..2253281bd35 100644 --- a/src/sage/rings/padics/pow_computer_relative.pyx +++ b/src/sage/rings/padics/pow_computer_relative.pyx @@ -17,7 +17,7 @@ AUTHORS: - David Roe, Julian Rรผth (2017-06-11): initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 David Roe <roed.math@gmail.com> # 2017 Julian Rรผth <julian.rueth@fsfe.org> # @@ -25,19 +25,13 @@ AUTHORS: # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -from cysignals.memory cimport sig_malloc, sig_free -from cysignals.signals cimport sig_on, sig_off - -from sage.libs.gmp.mpz cimport mpz_init, mpz_clear, mpz_pow_ui - -from cpython.object cimport Py_EQ, Py_NE from sage.rings.integer cimport Integer -from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method + cdef class PowComputer_relative(PowComputer_class): r""" Base class for a ``PowComputer`` for use in `p`-adics implemented by Sage @@ -75,7 +69,7 @@ cdef class PowComputer_relative(PowComputer_class): sage: PC = PowComputer_relative_maker(3, 20, 20, 60, False, f, shift_seed, 'fixed-mod') """ - self.__allocated = 4 + self._allocated = 4 def __init__(self, Integer prime, long cache_limit, long prec_cap, long ram_prec_cap, bint in_field, poly, shift_seed): r""" diff --git a/src/sage/rings/padics/relative_extension_leaves.py b/src/sage/rings/padics/relative_extension_leaves.py index 455af0bdd35..a9f20adce21 100644 --- a/src/sage/rings/padics/relative_extension_leaves.py +++ b/src/sage/rings/padics/relative_extension_leaves.py @@ -210,7 +210,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, """ self._exact_modulus = exact_modulus unram_prec = (prec + approx_modulus.degree() - 1) // approx_modulus.degree() - KFP = approx_modulus.base_ring().change(prec = unram_prec+1) + KFP = approx_modulus.base_ring().change(prec=unram_prec+1) self.prime_pow = PowComputer_relative_maker(approx_modulus.base_ring().prime(), max(min(unram_prec - 1, 30), 1), unram_prec, prec, False, exact_modulus.change_ring(KFP), shift_seed.change_ring(KFP), 'fixed-mod') self._implementation = 'Polynomial' EisensteinExtensionGeneric.__init__(self, approx_modulus, prec, print_mode, names, RelativeRamifiedFixedModElement) diff --git a/src/sage/rings/padics/relaxed_template.pxi b/src/sage/rings/padics/relaxed_template.pxi index 4de2b197ad1..a18ffb1cb03 100644 --- a/src/sage/rings/padics/relaxed_template.pxi +++ b/src/sage/rings/padics/relaxed_template.pxi @@ -811,7 +811,7 @@ cdef class RelaxedElement(pAdicGenericElement): def __bool__(self): r""" - Return ``True`` if this element is indistinguishable from zero. + Return ``True`` if this element is distinguishable from zero. TESTS:: diff --git a/src/sage/rings/padics/unramified_extension_generic.py b/src/sage/rings/padics/unramified_extension_generic.py index 7973ed814c3..b73b88ebc1c 100644 --- a/src/sage/rings/padics/unramified_extension_generic.py +++ b/src/sage/rings/padics/unramified_extension_generic.py @@ -26,21 +26,21 @@ class UnramifiedExtensionGeneric(pAdicExtensionGeneric): - """ - An unramified extension of Qp or Zp. + r""" + An unramified extension of `\QQ_p` or `\ZZ_p`. """ def __init__(self, poly, prec, print_mode, names, element_class): """ - Initializes self + Initializes ``self``. INPUT: - - poly -- Polynomial defining this extension. - - prec -- The precision cap - - print_mode -- a dictionary with print options - - names -- a 4-tuple, (variable_name, residue_name, - unramified_subextension_variable_name, uniformizer_name) - - element_class -- the class for elements of this unramified extension. + - ``poly`` -- Polynomial defining this extension. + - ``prec`` -- The precision cap + - ``print_mode`` -- a dictionary with print options + - ``names`` -- a 4-tuple, (``variable_name``, ``residue_name``, + ``unramified_subextension_variable_name``, ``uniformizer_name``) + - ``element_class`` -- the class for elements of this unramified extension. EXAMPLES:: @@ -52,7 +52,7 @@ def __init__(self, poly, prec, print_mode, names, element_class): #else: # self._PQR = pqr.PolynomialQuotientRing_domain(poly.parent(), poly, name = names) pAdicExtensionGeneric.__init__(self, poly, prec, print_mode, names, element_class) - self._res_field = GF(self.prime_pow.pow_Integer_Integer(poly.degree()), name = names[1], modulus = poly.change_ring(poly.base_ring().residue_field())) + self._res_field = GF(self.prime_pow.pow_Integer_Integer(poly.degree()), name=names[1], modulus=poly.change_ring(poly.base_ring().residue_field())) def _extension_type(self): """ @@ -67,6 +67,7 @@ def _extension_type(self): sage: K._extension_type() 'Unramified' + sage: x = polygen(ZZ, 'x') sage: L.<pi> = Qp(5).extension(x^2 - 5) sage: L._extension_type() 'Eisenstein' @@ -76,7 +77,7 @@ def _extension_type(self): def absolute_f(self): """ Return the degree of the residue field of this ring/field - over its prime subfield + over its prime subfield. EXAMPLES:: @@ -84,6 +85,7 @@ def absolute_f(self): sage: K.absolute_f() 5 + sage: x = polygen(ZZ, 'x') sage: L.<pi> = Qp(3).extension(x^2 - 3) sage: L.absolute_f() 1 @@ -113,7 +115,7 @@ def residue_class_field(self): def residue_ring(self, n): """ - Return the quotient of the ring of integers by the nth power of its maximal ideal. + Return the quotient of the ring of integers by the `n`-th power of its maximal ideal. EXAMPLES:: @@ -135,11 +137,11 @@ def residue_ring(self, n): def discriminant(self, K=None): """ - Returns the discriminant of self over the subring K. + Return the discriminant of ``self`` over the subring `K`. INPUT: - - K -- a subring/subfield (defaults to the base ring). + - ``K`` -- a subring/subfield (defaults to the base ring). EXAMPLES:: @@ -174,13 +176,13 @@ def discriminant(self, K=None): def is_galois(self, K=None): """ - Returns True if this extension is Galois. + Return ``True`` if this extension is Galois. Every unramified extension is Galois. INPUT: - - K -- a subring/subfield (defaults to the base ring). + - ``K`` -- a subring/subfield (defaults to the base ring). EXAMPLES:: @@ -193,7 +195,7 @@ def is_galois(self, K=None): def gen(self, n=0): """ - Returns a generator for this unramified extension. + Return a generator for this unramified extension. This is an element that satisfies the polynomial defining this extension. Such an element will reduce to a generator of the @@ -209,9 +211,9 @@ def gen(self, n=0): return self([0,1]) @cached_method - def _frob_gen(self, arithmetic = True): + def _frob_gen(self, arithmetic=True): """ - Returns frobenius of the generator for this unramified extension + Return frobenius of the generator for this unramified extension EXAMPLES:: @@ -233,7 +235,7 @@ def _frob_gen(self, arithmetic = True): def uniformizer_pow(self, n): """ - Returns the nth power of the uniformizer of self (as an element of self). + Return the `n`-th power of the uniformizer of ``self`` (as an element of ``self``). EXAMPLES:: @@ -244,8 +246,8 @@ def uniformizer_pow(self, n): return self(self.prime_pow(n)) def uniformizer(self): - """ - Returns a uniformizer for this extension. + r""" + Return a uniformizer for this extension. Since this extension is unramified, a uniformizer for the ground ring will also be a uniformizer for this extension. @@ -259,8 +261,8 @@ def uniformizer(self): return self(self.ground_ring().uniformizer()) def _uniformizer_print(self): - """ - Returns how the uniformizer is supposed to print. + r""" + Return how the uniformizer is supposed to print. EXAMPLES:: @@ -270,8 +272,8 @@ def _uniformizer_print(self): return self.ground_ring()._uniformizer_print() def _unram_print(self): - """ - Returns how the generator prints. + r""" + Return how the generator prints. EXAMPLES:: @@ -282,20 +284,19 @@ def _unram_print(self): def has_pth_root(self): r""" - Returns whether or not `\ZZ_p` has a primitive `p^{\mbox{th}}` root of unity. + Return whether or not `\ZZ_p` has a primitive `p`-th root of unity. - Since adjoining a `p^{\mbox{th}}` root of unity yields a - totally ramified extension, self will contain one if and only + Since adjoining a `p`-th root of unity yields a + totally ramified extension, ``self`` will contain one if and only if the ground ring does. INPUT: - - self -- a p-adic ring + - ``self`` -- a `p`-adic ring OUTPUT: - - boolean -- whether self has primitive `p^{\mbox{th}}` - root of unity. + boolean -- whether ``self`` has primitive `p`-th root of unity. EXAMPLES:: @@ -308,12 +309,12 @@ def has_pth_root(self): def has_root_of_unity(self, n): r""" - Return whether or not `\ZZ_p` has a primitive `n^{\mbox{th}}` + Return whether or not `\ZZ_p` has a primitive `n`-th root of unity. INPUT: - - ``self`` -- a p-adic ring + - ``self`` -- a `p`-adic ring - ``n`` -- an integer OUTPUT: diff --git a/src/sage/rings/pari_ring.py b/src/sage/rings/pari_ring.py index c46fceed07b..98b42c2634a 100644 --- a/src/sage/rings/pari_ring.py +++ b/src/sage/rings/pari_ring.py @@ -230,4 +230,5 @@ def zeta(self): """ return self(-1) + _inst = PariRing() diff --git a/src/sage/rings/polynomial/__init__.py b/src/sage/rings/polynomial/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/rings/polynomial/all.py b/src/sage/rings/polynomial/all.py index 816db5efe2a..853f422bdc7 100644 --- a/src/sage/rings/polynomial/all.py +++ b/src/sage/rings/polynomial/all.py @@ -1,8 +1,7 @@ """ Polynomials """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) @@ -14,8 +13,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.lazy_import import lazy_import @@ -51,3 +50,7 @@ # Evaluation of cyclotomic polynomials from sage.rings.polynomial.cyclotomic import cyclotomic_value + +# Integer-valued Univariate Polynomial Ring +lazy_import('sage.rings.polynomial.integer_valued_polynomials', + 'IntegerValuedPolynomialRing') diff --git a/src/sage/rings/polynomial/commutative_polynomial.pxd b/src/sage/rings/polynomial/commutative_polynomial.pxd new file mode 100644 index 00000000000..c4a8956daa5 --- /dev/null +++ b/src/sage/rings/polynomial/commutative_polynomial.pxd @@ -0,0 +1,5 @@ +from sage.structure.element cimport CommutativeAlgebraElement + + +cdef class CommutativePolynomial(CommutativeAlgebraElement): + pass diff --git a/src/sage/rings/polynomial/commutative_polynomial.pyx b/src/sage/rings/polynomial/commutative_polynomial.pyx new file mode 100644 index 00000000000..dc9f2cab8b7 --- /dev/null +++ b/src/sage/rings/polynomial/commutative_polynomial.pyx @@ -0,0 +1,23 @@ +cdef class CommutativePolynomial(CommutativeAlgebraElement): + r""" + Abstract base class for commutative polynomials in any number of variables + + It is a common base for :class:`~sage.rings.polynomial.polynomial_element.Polynomial`, + :class:`~sage.rings.polynomial.multi_polynomial.MPolynomial`, and + :class:`~sage.rings.polynomial.infinite_polynomial_element.InfinitePolynomial`. + + EXAMPLES:: + + sage: from sage.rings.polynomial.commutative_polynomial import CommutativePolynomial + sage: K.<x> = PolynomialRing(QQ) + sage: isinstance(x, CommutativePolynomial) + True + sage: K.<x,y> = PolynomialRing(QQ) + sage: isinstance(x, CommutativePolynomial) + True + sage: X.<x,y> = InfinitePolynomialRing(ZZ, implementation='sparse') + sage: isinstance(x[2], CommutativePolynomial) + True + """ + + pass diff --git a/src/sage/rings/polynomial/complex_roots.py b/src/sage/rings/polynomial/complex_roots.py index 0d84a9c757b..cbbd42c8ccf 100644 --- a/src/sage/rings/polynomial/complex_roots.py +++ b/src/sage/rings/polynomial/complex_roots.py @@ -147,7 +147,6 @@ def row_disjoint(): return True - def complex_roots(p, skip_squarefree=False, retval='interval', min_prec=0): """ Compute the complex roots of a given polynomial with exact diff --git a/src/sage/rings/polynomial/cyclotomic.pyx b/src/sage/rings/polynomial/cyclotomic.pyx index 1053f471a7a..3a891ec1ae8 100644 --- a/src/sage/rings/polynomial/cyclotomic.pyx +++ b/src/sage/rings/polynomial/cyclotomic.pyx @@ -30,34 +30,34 @@ import sys from cysignals.memory cimport sig_malloc, check_calloc, sig_free from cysignals.signals cimport sig_on, sig_off -from sage.structure.element cimport parent - from sage.arith.misc import factor -from sage.rings.integer_ring import ZZ +from sage.combinat.subset import subsets from sage.misc.misc_c import prod -from sage.misc.misc import subsets -from sage.rings.integer cimport Integer -from sage.rings.rational cimport Rational -from sage.libs.pari.all import pari +from sage.rings.integer_ring import ZZ +from sage.structure.element cimport parent +try: + from sage.libs.pari.all import pari +except ImportError: + pass def cyclotomic_coeffs(nn, sparse=None): """ - Return the coefficients of the n-th cyclotomic polynomial + Return the coefficients of the `n`-th cyclotomic polynomial by using the formula .. MATH:: \\Phi_n(x) = \\prod_{d|n} (1-x^{n/d})^{\\mu(d)} - where `\\mu(d)` is the Mรถbius function that is 1 if d has an even - number of distinct prime divisors, -1 if it has an odd number of - distinct prime divisors, and 0 if d is not squarefree. + where `\\mu(d)` is the Mรถbius function that is 1 if `d` has an even + number of distinct prime divisors, `-1` if it has an odd number of + distinct prime divisors, and `0` if `d` is not squarefree. Multiplications and divisions by polynomials of the form `1-x^n` can be done very quickly in a single pass. - If sparse is ``True``, the result is returned as a dictionary of + If ``sparse`` is ``True``, the result is returned as a dictionary of the non-zero entries, otherwise the result is returned as a list of python ints. @@ -74,17 +74,19 @@ def cyclotomic_coeffs(nn, sparse=None): Check that it has the right degree:: - sage: euler_phi(30) + sage: euler_phi(30) # needs sage.libs.pari 8 - sage: R(cyclotomic_coeffs(14)).factor() + sage: R(cyclotomic_coeffs(14)).factor() # needs sage.libs.pari x^6 - x^5 + x^4 - x^3 + x^2 - x + 1 The coefficients are not always +/-1:: sage: cyclotomic_coeffs(105) - [1, 1, 1, 0, 0, -1, -1, -2, -1, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1, -1, -2, -1, -1, 0, 0, 1, 1, 1] + [1, 1, 1, 0, 0, -1, -1, -2, -1, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1, + 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1, -1, -2, + -1, -1, 0, 0, 1, 1, 1] - In fact the height is not bounded by any polynomial in n (Erdos), + In fact the height is not bounded by any polynomial in `n` (Erdos), although takes a while just to exceed linear:: sage: v = cyclotomic_coeffs(1181895) @@ -202,10 +204,10 @@ def cyclotomic_value(n, x): INPUT: - - `n` -- an Integer, specifying which cyclotomic polynomial is to be + - ``n`` -- an Integer, specifying which cyclotomic polynomial is to be evaluated - - `x` -- an element of a ring + - ``x`` -- an element of a ring OUTPUT: @@ -249,9 +251,12 @@ def cyclotomic_value(n, x): TESTS:: - sage: R.<x> = QQ[] - sage: K.<i> = NumberField(x^2 + 1) - sage: for y in [-1, 0, 1, 2, 1/2, Mod(3, 8), Mod(3,11), GF(9,'a').gen(), Zp(3)(54), i, x^2+2]: + sage: elements = [-1, 0, 1, 2, 1/2, Mod(3, 8), Mod(3,11)] + sage: R.<x> = QQ[]; elements += [x^2 + 2] + sage: K.<i> = NumberField(x^2 + 1); elements += [i] # needs sage.rings.number_fields + sage: elements += [GF(9,'a').gen()] # needs sage.rings.finite_rings + sage: elements += [Zp(3)(54)] # needs sage.rings.padics + sage: for y in elements: ....: for n in [1..60]: ....: val1 = cyclotomic_value(n, y) ....: val2 = cyclotomic_polynomial(n)(y) @@ -260,29 +265,31 @@ def cyclotomic_value(n, x): ....: if val1.parent() is not val2.parent(): ....: print("Wrong parent for cyclotomic_value(%s, %s) in %s"%(n,y,parent(y))) - sage: cyclotomic_value(20, I) + sage: cyclotomic_value(20, I) # needs sage.symbolic 5 sage: a = cyclotomic_value(10, mod(3, 11)); a 6 sage: a.parent() Ring of integers modulo 11 - sage: cyclotomic_value(30, -1.0) + sage: cyclotomic_value(30, -1.0) # needs sage.rings.real_mpfr 1.00000000000000 + + sage: # needs sage.libs.pari sage: S.<t> = R.quotient(R.cyclotomic_polynomial(15)) sage: cyclotomic_value(15, t) 0 sage: cyclotomic_value(30, t) 2*t^7 - 2*t^5 - 2*t^3 + 2*t sage: S.<t> = R.quotient(x^10) - sage: cyclotomic_value(2^128-1, t) + sage: cyclotomic_value(2^128 - 1, t) -t^7 - t^6 - t^5 + t^2 + t + 1 - sage: cyclotomic_value(10,mod(3,4)) + sage: cyclotomic_value(10, mod(3,4)) 1 Check that the issue with symbolic element in :trac:`14982` is fixed:: - sage: a = cyclotomic_value(3, I) - sage: parent(a) + sage: a = cyclotomic_value(3, I) # needs sage.rings.number_fields + sage: parent(a) # needs sage.rings.number_fields Number Field in I with defining polynomial x^2 + 1 with I = 1*I """ n = ZZ(n) @@ -338,10 +345,10 @@ def cyclotomic_value(n, x): mu = 1 num = x - 1 den = 1 - for i in xrange(L): + for i in range(L): ti = 1 << i p = primes[i] - for j in xrange(ti): + for j in range(ti): xpow = xd[j]**p xd.append(xpow) md[ti + j] = -md[j] @@ -372,7 +379,7 @@ def cyclotomic_value(n, x): # If root_of_unity = (1<<L) - (1<<(i-1)) - 1 for some i < L, # then n/d == primes[i] and we need to multiply by primes[i], # otherwise n/d is composite and nothing more needs to be done. - for i in xrange(L): + for i in range(L): if root_of_unity + (1 << i) + 1 == 1 << L: ans *= primes[i] break @@ -389,10 +396,10 @@ def bateman_bound(nn): EXAMPLES:: sage: from sage.rings.polynomial.cyclotomic import bateman_bound - sage: bateman_bound(2**8*1234567893377) + sage: bateman_bound(2**8 * 1234567893377) # needs sage.libs.pari 66944986927 """ _, n = nn.val_unit(2) primes = [p for p, _ in factor(n)] j = len(primes) - return prod(primes[k] ** (2 ** (j - k - 2) - 1) for k in xrange(j - 2)) + return prod(primes[k] ** (2 ** (j - k - 2) - 1) for k in range(j - 2)) diff --git a/src/sage/rings/polynomial/flatten.py b/src/sage/rings/polynomial/flatten.py index 4ffe29f9ebe..cfc5f96179c 100644 --- a/src/sage/rings/polynomial/flatten.py +++ b/src/sage/rings/polynomial/flatten.py @@ -10,7 +10,10 @@ sage: from sage.rings.polynomial.flatten import FlatteningMorphism sage: phi = FlatteningMorphism(R); phi Flattening morphism: - From: Univariate Polynomial Ring in X over Multivariate Polynomial Ring in s, t over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + From: Univariate Polynomial Ring in X + over Multivariate Polynomial Ring in s, t + over Univariate Polynomial Ring in y + over Univariate Polynomial Ring in x over Rational Field To: Multivariate Polynomial Ring in x, y, s, t, X over Rational Field sage: phi('x*y*s + t*X').parent() Multivariate Polynomial Ring in x, y, s, t, X over Rational Field @@ -108,6 +111,8 @@ def __init__(self, domain): :: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<v> = NumberField(x^3 - 2) sage: R = K['x','y']['a','b'] sage: from sage.rings.polynomial.flatten import FlatteningMorphism @@ -117,15 +122,17 @@ def __init__(self, domain): :: + sage: # needs sage.rings.number_field sage: R = QQbar['x','y']['a','b'] sage: from sage.rings.polynomial.flatten import FlatteningMorphism sage: f = FlatteningMorphism(R) - sage: f(R('QQbar(sqrt(2))*a*x^2 + b^2 + QQbar(I)*y')) + sage: f(R('QQbar(sqrt(2))*a*x^2 + b^2 + QQbar(I)*y')) # needs sage.symbolic 1.414213562373095?*x^2*a + b^2 + I*y :: - sage: R.<z> = PolynomialRing(QQbar,1) + sage: # needs sage.rings.number_field + sage: R.<z> = PolynomialRing(QQbar, 1) sage: from sage.rings.polynomial.flatten import FlatteningMorphism sage: f = FlatteningMorphism(R) sage: f.domain(), f.codomain() @@ -134,6 +141,7 @@ def __init__(self, domain): :: + sage: # needs sage.rings.number_field sage: R.<z> = PolynomialRing(QQbar) sage: from sage.rings.polynomial.flatten import FlatteningMorphism sage: f = FlatteningMorphism(R) @@ -243,7 +251,8 @@ def section(self): sage: h.section() Unflattening morphism: From: Multivariate Polynomial Ring in a, b, c, x, y, z over Rational Field - To: Multivariate Polynomial Ring in x, y, z over Multivariate Polynomial Ring in a, b, c over Rational Field + To: Multivariate Polynomial Ring in x, y, z + over Multivariate Polynomial Ring in a, b, c over Rational Field :: @@ -252,7 +261,8 @@ def section(self): sage: FlatteningMorphism(R).section() Unflattening morphism: From: Multivariate Polynomial Ring in a, b, c over Integer Ring - To: Univariate Polynomial Ring in c over Univariate Polynomial Ring in b over Univariate Polynomial Ring in a over Integer Ring + To: Univariate Polynomial Ring in c over Univariate Polynomial Ring in b + over Univariate Polynomial Ring in a over Integer Ring """ return UnflatteningMorphism(self.codomain(), self.domain()) @@ -268,7 +278,8 @@ def inverse(self): sage: f.inverse() Unflattening morphism: From: Multivariate Polynomial Ring in x, y, u, v over Rational Field - To: Multivariate Polynomial Ring in u, v over Multivariate Polynomial Ring in x, y over Rational Field + To: Multivariate Polynomial Ring in u, v + over Multivariate Polynomial Ring in x, y over Rational Field """ return self.section() @@ -286,7 +297,8 @@ class UnflatteningMorphism(Morphism): sage: g = f(R('x^2 + c*y^2 - z^2'));g x^2 + c*y^2 - z^2 sage: g.parent() - Multivariate Polynomial Ring in x, y, z over Univariate Polynomial Ring in c over Rational Field + Multivariate Polynomial Ring in x, y, z + over Univariate Polynomial Ring in c over Rational Field :: @@ -296,7 +308,8 @@ class UnflatteningMorphism(Morphism): sage: UnflatteningMorphism(R, S) Unflattening morphism: From: Multivariate Polynomial Ring in a, b, x, y over Rational Field - To: Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Rational Field + To: Multivariate Polynomial Ring in x, y + over Multivariate Polynomial Ring in a, b over Rational Field """ def __init__(self, domain, codomain): @@ -366,8 +379,10 @@ def _call_(self, p): TESTS:: sage: from sage.rings.polynomial.flatten import FlatteningMorphism - sage: for R in [ZZ['x']['y']['a,b,c'], GF(4)['x','y']['a','b'], - ....: AA['x']['a','b']['y'], QQbar['a1','a2']['t']['X','Y']]: + sage: rings = [ZZ['x']['y']['a,b,c']] + sage: rings += [GF(4)['x','y']['a','b']] # needs sage.rings.finite_rings + sage: rings += [AA['x']['a','b']['y'], QQbar['a1','a2']['t']['X','Y']] # needs sage.rings.number_field + sage: for R in rings: ....: f = FlatteningMorphism(R) ....: g = f.section() ....: for _ in range(10): @@ -423,8 +438,9 @@ class SpecializationMorphism(Morphism): sage: from sage.rings.polynomial.flatten import SpecializationMorphism sage: xi = SpecializationMorphism(S, {c:0}); xi Specialization morphism: - From: Univariate Polynomial Ring in z over Univariate Polynomial Ring in c over Rational Field - To: Univariate Polynomial Ring in z over Rational Field + From: Univariate Polynomial Ring in z + over Univariate Polynomial Ring in c over Rational Field + To: Univariate Polynomial Ring in z over Rational Field sage: xi(z^2+c) z^2 @@ -437,8 +453,11 @@ class SpecializationMorphism(Morphism): sage: from sage.rings.polynomial.flatten import SpecializationMorphism sage: xi = SpecializationMorphism(S, D); xi Specialization morphism: - From: Multivariate Polynomial Ring in x, y, z over Multivariate Polynomial Ring in a, b, c over Multivariate Polynomial Ring in u, v over Rational Field - To: Multivariate Polynomial Ring in y, z over Univariate Polynomial Ring in c over Univariate Polynomial Ring in v over Rational Field + From: Multivariate Polynomial Ring in x, y, z + over Multivariate Polynomial Ring in a, b, c + over Multivariate Polynomial Ring in u, v over Rational Field + To: Multivariate Polynomial Ring in y, z over Univariate Polynomial Ring in c + over Univariate Polynomial Ring in v over Rational Field sage: xi(a*(x*z+y^2)*u+b*v*u*(x*z+y^2)*y^2*c+c*y^2*z^2) 2*v*c*y^4 + c*y^2*z^2 + y^2 """ @@ -475,8 +494,9 @@ def __init__(self, domain, D): sage: P.<z> = AffineSpace(R, 1) sage: H = End(P) sage: f = H([z^2 + c]) - sage: f.specialization({c:1}) - Scheme endomorphism of Affine Space of dimension 1 over Real Field with 53 bits of precision + sage: f.specialization({c:1}) # needs sage.modules + Scheme endomorphism of + Affine Space of dimension 1 over Real Field with 53 bits of precision Defn: Defined on coordinates by sending (z) to (z^2 + 1.00000000000000) """ @@ -655,8 +675,10 @@ def __init__(self, domain, D): sage: phi = FractionSpecializationMorphism(Frac(S), {c:3}) sage: phi Fraction Specialization morphism: - From: Fraction Field of Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, c over Rational Field - To: Fraction Field of Multivariate Polynomial Ring in x, y over Univariate Polynomial Ring in a over Rational Field + From: Fraction Field of Multivariate Polynomial Ring in x, y + over Multivariate Polynomial Ring in a, c over Rational Field + To: Fraction Field of Multivariate Polynomial Ring in x, y + over Univariate Polynomial Ring in a over Rational Field """ if not is_FractionField(domain): raise TypeError("domain must be a fraction field") diff --git a/src/sage/rings/polynomial/groebner_fan.py b/src/sage/rings/polynomial/groebner_fan.py index 6c6548d9e85..7e067a3a087 100644 --- a/src/sage/rings/polynomial/groebner_fan.py +++ b/src/sage/rings/polynomial/groebner_fan.py @@ -1157,8 +1157,7 @@ def __iter__(self): sage: next(a) [y^9 - 3*y^6 + 3*y^3 - y - 1, -y^3 + x + 1] """ - for x in self.reduced_groebner_bases(): - yield x + yield from self.reduced_groebner_bases() def __getitem__(self, i): """ @@ -1247,27 +1246,27 @@ def render(self, file=None, larger=False, shift=0, rgbcolor=(0, 0, 0), INPUT: - - ``file`` - a filename if you prefer the output + - ``file`` -- a filename if you prefer the output saved to a file. This will be in xfig format. - - ``shift`` - shift the positions of the variables in + - ``shift`` -- shift the positions of the variables in the drawing. For example, with shift=1, the corners will be b (right), c (left), and d (top). The shifting is done modulo the number of variables in the polynomial ring. The default is 0. - - ``larger`` - bool (default: ``False``); if ``True``, make + - ``larger`` -- bool (default: ``False``); if ``True``, make the triangle larger so that the shape of the Groebner region appears. Affects the xfig file but probably not the sage graphics (?) - - ``rgbcolor`` - This will not affect the saved xfig + - ``rgbcolor`` -- This will not affect the saved xfig file, only the sage graphics produced. - - ``polyfill`` - Whether or not to fill the cones with + - ``polyfill`` -- Whether or not to fill the cones with a color determined by the highest degree in each reduced Groebner basis for that cone. - - ``scale_colors`` - if True, this will normalize + - ``scale_colors`` -- if True, this will normalize color values to try to maximize the range @@ -1275,23 +1274,23 @@ def render(self, file=None, larger=False, shift=0, rgbcolor=(0, 0, 0), sage: R.<x,y,z> = PolynomialRing(QQ,3) sage: G = R.ideal([y^3 - x^2, y^2 - 13*x,z]).groebner_fan() - sage: test_render = G.render() + sage: test_render = G.render() # needs sage.plot :: sage: R.<x,y,z> = PolynomialRing(QQ,3) sage: G = R.ideal([x^2*y - z, y^2*z - x, z^2*x - y]).groebner_fan() - sage: test_render = G.render(larger=True) + sage: test_render = G.render(larger=True) # needs sage.plot TESTS: Testing the case where the number of generators is < 3. Currently, - this should raise a ``NotImplementedError`` error. + this should raise a :class:`NotImplementedError`. :: sage: R.<x,y> = PolynomialRing(QQ, 2) - sage: R.ideal([y^3 - x^2, y^2 - 13*x]).groebner_fan().render() + sage: R.ideal([y^3 - x^2, y^2 - 13*x]).groebner_fan().render() # needs sage.plot Traceback (most recent call last): ... NotImplementedError @@ -1461,17 +1460,17 @@ def render3d(self, verbose=False): sage: R4.<w,x,y,z> = PolynomialRing(QQ,4) sage: gf = R4.ideal([w^2-x,x^2-y,y^2-z,z^2-x]).groebner_fan() - sage: three_d = gf.render3d() + sage: three_d = gf.render3d() # needs sage.plot TESTS: Now test the case where the number of generators is not 4. Currently, - this should raise a ``NotImplementedError`` error. + this should raise a :class:`NotImplementedError` error. :: sage: P.<a,b,c> = PolynomialRing(QQ, 3, order="lex") - sage: sage.rings.ideal.Katsura(P, 3).groebner_fan().render3d() + sage: sage.rings.ideal.Katsura(P, 3).groebner_fan().render3d() # needs sage.plot Traceback (most recent call last): ... NotImplementedError diff --git a/src/sage/rings/polynomial/hilbert.pyx b/src/sage/rings/polynomial/hilbert.pyx index 0c49e1655c2..d2abf325fd8 100644 --- a/src/sage/rings/polynomial/hilbert.pyx +++ b/src/sage/rings/polynomial/hilbert.pyx @@ -20,9 +20,10 @@ in any example with more than 34 variables. # #***************************************************************************** +import sage.interfaces.abc + from sage.rings.polynomial.polydict cimport ETuple from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint -from sage.interfaces.singular import Singular from cysignals.memory cimport sig_malloc from cpython.list cimport PyList_GET_ITEM @@ -45,10 +46,12 @@ cdef class Node: cdef fmpz_poly_t LMult cdef fmpz_poly_t RMult cdef fmpz_poly_t LeftFHS + def __cinit__(self): fmpz_poly_init(self.LMult) fmpz_poly_init(self.RMult) fmpz_poly_init(self.LeftFHS) + def __dealloc__(self): fmpz_poly_clear(self.LMult) fmpz_poly_clear(self.RMult) @@ -133,9 +136,8 @@ cdef list quotient_by_var(list L, size_t index): cdef list result = L[:len(L)] # creates a copy cdef size_t i for i in range(len(L)): - m_j = (<ETuple>PyList_GET_ITEM(L,i)).divide_by_var(index) - if m_j is not None: - result.append(m_j) + if (<ETuple> PyList_GET_ITEM(L, i)).get_exp(index): + result.append((<ETuple> PyList_GET_ITEM(L, i)).divide_by_var(index)) return interred(result) cdef ETuple sum_from_list(list L, size_t s, size_t l): @@ -168,7 +170,7 @@ cdef bint HilbertBaseCase(Polynomial_integer_dense_flint fhs, Node D, tuple w): cdef int e # First, the easiest cases: if not D.Id: # The zero ideal - fmpz_poly_set_coeff_si(fhs.__poly, 0, 1) # = PR(1) + fmpz_poly_set_coeff_si(fhs._poly, 0, 1) # = PR(1) return True cdef ETuple m = <ETuple>PyList_GET_ITEM(D.Id, len(D.Id)-1) if m._nonzero == 0: # The one ideal @@ -181,18 +183,18 @@ cdef bint HilbertBaseCase(Polynomial_integer_dense_flint fhs, Node D, tuple w): if m._nonzero == 1 and m._data[1] == 1: fmpz_poly_init(poly_tmp) fmpz_poly_set_coeff_si(poly_tmp, 0, 1) - fmpz_poly_set_coeff_si(fhs.__poly, 0, 1) # = PR(1) + fmpz_poly_set_coeff_si(fhs._poly, 0, 1) # = PR(1) if w is None: for i in range(len(D.Id)): exp = (<ETuple>PyList_GET_ITEM(D.Id, i)).unweighted_degree() fmpz_poly_set_coeff_si(poly_tmp, exp, -1) - fmpz_poly_mul(fhs.__poly, fhs.__poly, poly_tmp) + fmpz_poly_mul(fhs._poly, fhs._poly, poly_tmp) fmpz_poly_set_coeff_si(poly_tmp, exp, 0) else: for i in range(len(D.Id)): exp = (<ETuple>PyList_GET_ITEM(D.Id, i)).weighted_degree(w) fmpz_poly_set_coeff_si(poly_tmp, exp, -1) - fmpz_poly_mul(fhs.__poly, fhs.__poly, poly_tmp) + fmpz_poly_mul(fhs._poly, fhs._poly, poly_tmp) fmpz_poly_set_coeff_si(poly_tmp, exp, 0) fmpz_poly_clear(poly_tmp) return True # PR.prod([(1-t**degree(m,w)) for m in D.Id]) @@ -208,18 +210,18 @@ cdef bint HilbertBaseCase(Polynomial_integer_dense_flint fhs, Node D, tuple w): # The ideal is generated by some powers of single variables, i.e., it splits. fmpz_poly_init(poly_tmp) fmpz_poly_set_coeff_si(poly_tmp, 0, 1) - fmpz_poly_set_coeff_si(fhs.__poly, 0, 1) # = PR(1) + fmpz_poly_set_coeff_si(fhs._poly, 0, 1) # = PR(1) if w is None: for i in range(len(D.Id)): exp = (<ETuple>PyList_GET_ITEM(D.Id, i)).unweighted_degree() fmpz_poly_set_coeff_si(poly_tmp, exp, -1) - fmpz_poly_mul(fhs.__poly, fhs.__poly, poly_tmp) + fmpz_poly_mul(fhs._poly, fhs._poly, poly_tmp) fmpz_poly_set_coeff_si(poly_tmp, exp, 0) else: for i in range(len(D.Id)): exp = (<ETuple>PyList_GET_ITEM(D.Id, i)).weighted_degree(w) fmpz_poly_set_coeff_si(poly_tmp, exp, -1) - fmpz_poly_mul(fhs.__poly, fhs.__poly, poly_tmp) + fmpz_poly_mul(fhs._poly, fhs._poly, poly_tmp) fmpz_poly_set_coeff_si(poly_tmp, exp, 0) fmpz_poly_clear(poly_tmp) return True # PR.prod([(1-t**degree(m,w)) for m in D.Id]) @@ -276,8 +278,8 @@ cdef bint HilbertBaseCase(Polynomial_integer_dense_flint fhs, Node D, tuple w): fmpz_poly_mul(SecondSummand, SecondSummand, poly_tmp) fmpz_poly_set_coeff_si(poly_tmp, exp, 0) fmpz_poly_clear(poly_tmp) - fmpz_poly_add(fhs.__poly, fhs.__poly, FirstSummand) - fmpz_poly_add(fhs.__poly, fhs.__poly, SecondSummand) + fmpz_poly_add(fhs._poly, fhs._poly, FirstSummand) + fmpz_poly_add(fhs._poly, fhs._poly, SecondSummand) fmpz_poly_clear(FirstSummand) fmpz_poly_clear(SecondSummand) return True @@ -443,16 +445,16 @@ def first_hilbert_series(I, grading=None, return_grading=False): sage: I = singular.ideal(['x^2','y^2','z^2']) sage: first_hilbert_series(I) -t^6 + 3*t^4 - 3*t^2 + 1 - sage: first_hilbert_series(I,return_grading=True) + sage: first_hilbert_series(I, return_grading=True) (-t^6 + 3*t^4 - 3*t^2 + 1, (1, 1, 1)) - sage: first_hilbert_series(I,grading=(1,2,3)) + sage: first_hilbert_series(I, grading=(1,2,3)) -t^12 + t^10 + t^8 - t^4 - t^2 + 1 TESTS: We test against some corner cases:: - sage: R.<x,y,z>=PolynomialRing(QQ) + sage: R.<x,y,z> = PolynomialRing(QQ) sage: I = 0*R sage: first_hilbert_series(I) 1 @@ -477,7 +479,7 @@ def first_hilbert_series(I, grading=None, return_grading=False): cdef Polynomial_integer_dense_flint fhs = Polynomial_integer_dense_flint.__new__(Polynomial_integer_dense_flint) fhs._parent = PR fhs._is_gen = 0 - if isinstance(I.parent(), Singular): + if isinstance(I, sage.interfaces.abc.SingularElement): S = I._check_valid() # First, we need to deal with quotient rings, which also covers the case # of graded commutative rings that arise as cohomology rings in odd characteristic. @@ -530,11 +532,11 @@ def first_hilbert_series(I, grading=None, return_grading=False): if AN.Back.Right is None: AN = AN.Back #~ fhs *= AN.LMult - fmpz_poly_mul(fhs.__poly, fhs.__poly, AN.LMult) + fmpz_poly_mul(fhs._poly, fhs._poly, AN.LMult) got_result = True else: - fmpz_poly_set(AN.Back.LeftFHS, fhs.__poly) - fmpz_poly_set_si(fhs.__poly, 0) + fmpz_poly_set(AN.Back.LeftFHS, fhs._poly) + fmpz_poly_set_si(fhs._poly, 0) AN = AN.Back.Right AN.Back.Left = None got_result = HilbertBaseCase(fhs, AN, w) @@ -543,8 +545,8 @@ def first_hilbert_series(I, grading=None, return_grading=False): AN.Right = None #~ fhs = AN.LMult*AN.LeftFHS + AN.RMult*fhs fmpz_poly_mul(AN.LMult, AN.LMult, AN.LeftFHS) - fmpz_poly_mul(AN.RMult, AN.RMult, fhs.__poly) - fmpz_poly_add(fhs.__poly, AN.LMult, AN.RMult) + fmpz_poly_mul(AN.RMult, AN.RMult, fhs._poly) + fmpz_poly_add(fhs._poly, AN.LMult, AN.RMult) got_result = True def hilbert_poincare_series(I, grading=None): @@ -560,30 +562,23 @@ def hilbert_poincare_series(I, grading=None): sage: from sage.rings.polynomial.hilbert import hilbert_poincare_series sage: R = PolynomialRing(QQ,'x',9) - sage: I = [m.lm() for m in ((matrix(R,3,R.gens())^2).list()*R).groebner_basis()]*R + sage: I = [m.lm() + ....: for m in ((matrix(R, 3, R.gens())^2).list() * R).groebner_basis()] * R sage: hilbert_poincare_series(I) (t^7 - 3*t^6 + 2*t^5 + 2*t^4 - 2*t^3 + 6*t^2 + 5*t + 1)/(t^4 - 4*t^3 + 6*t^2 - 4*t + 1) - sage: hilbert_poincare_series((R*R.gens())^2, grading=range(1,10)) + sage: hilbert_poincare_series((R * R.gens())^2, grading=range(1,10)) t^9 + t^8 + t^7 + t^6 + t^5 + t^4 + t^3 + t^2 + t + 1 The following example is taken from :trac:`20145`:: - sage: n=4;m=11;P = PolynomialRing(QQ,n*m,"x"); x = P.gens(); M = Matrix(n,x) + sage: n=4; m=11; P = PolynomialRing(QQ, n*m, "x"); x = P.gens(); M = Matrix(n, x) sage: from sage.rings.polynomial.hilbert import first_hilbert_series sage: I = P.ideal(M.minors(2)) - sage: J = P*[m.lm() for m in I.groebner_basis()] + sage: J = P * [m.lm() for m in I.groebner_basis()] sage: hilbert_poincare_series(J).numerator() 120*t^3 + 135*t^2 + 30*t + 1 sage: hilbert_poincare_series(J).denominator().factor() (t - 1)^14 - - This example exceeded the capabilities of Singular before version 4.2.1p2. - In Singular 4.3.1, it works correctly on 64-bit, but on 32-bit, it prints overflow warnings - and omits some terms. - - sage: J.hilbert_numerator(algorithm='singular') - 120*t^33 - 3465*t^32 + 48180*t^31 - 429374*t^30 + 2753520*t^29 - 13522410*t^28 + 52832780*t^27 - 168384150*t^26 + 445188744*t^25 - 987193350*t^24 + 1847488500*t^23 + 1372406746*t^22 - 403422496*t^21 - 8403314*t^20 - 471656596*t^19 + 1806623746*t^18 + 752776200*t^17 + 752776200*t^16 - 1580830020*t^15 + 1673936550*t^14 - 1294246800*t^13 + 786893250*t^12 - 382391100*t^11 + 146679390*t^10 - 42299400*t^9 + 7837830*t^8 - 172260*t^7 - 468930*t^6 + 183744*t^5 - 39270*t^4 + 5060*t^3 - 330*t^2 + 1 # 64-bit - ...120*t^33 - 3465*t^32 + 48180*t^31 - ... # 32-bit """ cdef Polynomial_integer_dense_flint HP HP, grading = first_hilbert_series(I, grading=grading, return_grading=True) diff --git a/src/sage/rings/polynomial/ideal.py b/src/sage/rings/polynomial/ideal.py index 857718c9a10..1ab86736d5b 100644 --- a/src/sage/rings/polynomial/ideal.py +++ b/src/sage/rings/polynomial/ideal.py @@ -26,7 +26,7 @@ class Ideal_1poly_field(Ideal_pid): """ def residue_class_degree(self): """ - Returns the degree of the generator of this ideal. + Return the degree of the generator of this ideal. This function is included for compatibility with ideals in rings of integers of number fields. @@ -41,19 +41,20 @@ def residue_class_degree(self): def residue_field(self, names=None, check=True): r""" - If this ideal is `P \subset F_p[t]`, returns the quotient `F_p[t]/P`. + If this ideal is `P \subset F_p[t]`, return the quotient `F_p[t]/P`. EXAMPLES:: sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + 2*t + 9) - sage: k.<a> = P.residue_field(); k - Residue field in a of Principal ideal (t^3 + 2*t + 9) of Univariate Polynomial Ring in t over Finite Field of size 17 + sage: k.<a> = P.residue_field(); k # needs sage.rings.finite_rings + Residue field in a of Principal ideal (t^3 + 2*t + 9) of + Univariate Polynomial Ring in t over Finite Field of size 17 """ if check: if not self.ring().base_ring().is_finite(): raise TypeError("residue fields only supported for polynomial rings over finite fields.") if not self.is_prime(): - raise ValueError("%s is not a prime ideal"%self) + raise ValueError("%s is not a prime ideal" % self) from sage.rings.finite_rings.residue_field import ResidueField return ResidueField(self, names, check=False) diff --git a/src/sage/rings/polynomial/infinite_polynomial_element.py b/src/sage/rings/polynomial/infinite_polynomial_element.py index 5ac9bd00147..fc8449b340e 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_element.py +++ b/src/sage/rings/polynomial/infinite_polynomial_element.py @@ -18,7 +18,7 @@ x_3 sage: b y_4 - sage: c = a*b+a^3-2*b^4 + sage: c = a*b + a^3 - 2*b^4 sage: c x_3^3 + x_3*y_4 - 2*y_4^4 @@ -80,7 +80,7 @@ sage: C.<b,c> = InfinitePolynomialRing(B,order='degrevlex') sage: C Infinite polynomial ring in b, c over Infinite polynomial ring in a over Integer Ring - sage: 1/2*b_1*a[4]+c[3] + sage: 1/2*b_1*a[4] + c[3] 1/2*a_4*b_1 + c_3 """ @@ -103,14 +103,16 @@ from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer -from sage.structure.element import RingElement from sage.structure.richcmp import richcmp from sage.misc.cachefunc import cached_method -from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.structure.element import RingElement +from .commutative_polynomial import CommutativePolynomial +from .multi_polynomial import MPolynomial import copy -def InfinitePolynomial(A, p): +class InfinitePolynomial(CommutativePolynomial, metaclass=InheritComparisonClasscallMetaclass): """ Create an element of a Polynomial Ring with a Countably Infinite Number of Variables. @@ -176,73 +178,72 @@ def InfinitePolynomial(A, p): alpha_2^2 + alpha_1^2 """ - from sage.structure.element import parent - if hasattr(A, '_P'): - if parent(p) is A._P or (A._P.base_ring().has_coerce_map_from(parent(p))): - return InfinitePolynomial_dense(A, p) - # MPolynomialRing_polydict is crab. So, in that case, use sage_eval - from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict - if isinstance(A._P, MPolynomialRing_polydict): - from sage.rings.polynomial.infinite_polynomial_ring import GenDictWithBasering - from sage.misc.sage_eval import sage_eval - p = sage_eval(repr(p), GenDictWithBasering(A._P, A._P.gens_dict())) - return InfinitePolynomial_dense(A, p) - else: - # Now there remains to fight the oddities and bugs of libsingular. - PP = p.parent() - if A._P.has_coerce_map_from(PP): - if A._P.ngens() == PP.ngens(): # coercion is sometimes by position! - f = PP.hom(PP.variable_names(), A._P) - try: - return InfinitePolynomial_dense(A, f(p)) - except (ValueError, TypeError): - # last desperate attempt: String conversion - from sage.misc.sage_eval import sage_eval - from sage.rings.polynomial.infinite_polynomial_ring import GenDictWithBasering - # the base ring may be a function field, therefore - # we need GenDictWithBasering - return InfinitePolynomial_dense(A, sage_eval(repr(p), GenDictWithBasering(A._P, A._P.gens_dict()))) - return InfinitePolynomial_dense(A, A._P(p)) - # there is no coercion, so, we set up a name-preserving map. - SV = set(repr(x) for x in p.variables()) - f = PP.hom([x if x in SV else 0 for x in PP.variable_names()], A._P) - try: - return InfinitePolynomial_dense(A, f(p)) - except (ValueError, TypeError): - # last desperate attempt: String conversion - from sage.misc.sage_eval import sage_eval - from sage.rings.polynomial.infinite_polynomial_ring import GenDictWithBasering - # the base ring may be a function field, therefore - # we need GenDictWithBasering - return InfinitePolynomial_dense(A, sage_eval(repr(p), GenDictWithBasering(A._P, A._P.gens_dict()))) - return InfinitePolynomial_sparse(A, p) - - -class InfinitePolynomial_sparse(RingElement): - """ - Element of a sparse Polynomial Ring with a Countably Infinite Number of Variables. - - INPUT: - - - ``A`` -- an Infinite Polynomial Ring in sparse implementation - - ``p`` -- a *classical* polynomial that can be interpreted in ``A``. - - Of course, one should not directly invoke this class, but rather - construct elements of ``A`` in the usual way. - EXAMPLES:: + @staticmethod + def __classcall_private__(cls, A, p): + r""" + TESTS:: - sage: A.<a> = QQ[] - sage: B.<b,c> = InfinitePolynomialRing(A,implementation='sparse') - sage: p = a*b[100] + 1/2*c[4] - sage: p - a*b_100 + 1/2*c_4 - sage: p.parent() - Infinite polynomial ring in b, c over Univariate Polynomial Ring in a over Rational Field - sage: p.polynomial().parent() - Multivariate Polynomial Ring in b_100, b_0, c_4, c_0 over Univariate Polynomial Ring in a over Rational Field + sage: from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial + sage: X.<x,y> = InfinitePolynomialRing(ZZ, implementation='sparse') + sage: xy = (x[0] + y[0]).polynomial() + sage: xy.parent() + Multivariate Polynomial Ring in x_1, x_0, y_1, y_0 over Integer Ring + sage: sparse_xy = InfinitePolynomial(X, xy); sparse_xy + x_0 + y_0 + sage: isinstance(sparse_xy, InfinitePolynomial) + True + sage: type(sparse_xy) + <class 'sage.rings.polynomial.infinite_polynomial_element.InfinitePolynomial_sparse'> + sage: X.<x,y> = InfinitePolynomialRing(ZZ, implementation='dense') + sage: dense_xy = InfinitePolynomial(X, xy); dense_xy + x_0 + y_0 + sage: isinstance(dense_xy, InfinitePolynomial) + True + sage: type(dense_xy) + <class 'sage.rings.polynomial.infinite_polynomial_element.InfinitePolynomial_dense'> + """ + from sage.structure.element import parent + if hasattr(A, '_P'): + if parent(p) is A._P or (A._P.base_ring().has_coerce_map_from(parent(p))): + return InfinitePolynomial_dense(A, p) + # MPolynomialRing_polydict is crab. So, in that case, use sage_eval + from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict + if isinstance(A._P, MPolynomialRing_polydict): + from sage.rings.polynomial.infinite_polynomial_ring import GenDictWithBasering + from sage.misc.sage_eval import sage_eval + p = sage_eval(repr(p), GenDictWithBasering(A._P, A._P.gens_dict())) + return InfinitePolynomial_dense(A, p) + else: + # Now there remains to fight the oddities and bugs of libsingular. + PP = p.parent() + if A._P.has_coerce_map_from(PP): + if A._P.ngens() == PP.ngens(): # coercion is sometimes by position! + f = PP.hom(PP.variable_names(), A._P) + try: + return InfinitePolynomial_dense(A, f(p)) + except (ValueError, TypeError): + # last desperate attempt: String conversion + from sage.misc.sage_eval import sage_eval + from sage.rings.polynomial.infinite_polynomial_ring import GenDictWithBasering + # the base ring may be a function field, therefore + # we need GenDictWithBasering + return InfinitePolynomial_dense(A, sage_eval(repr(p), GenDictWithBasering(A._P, A._P.gens_dict()))) + return InfinitePolynomial_dense(A, A._P(p)) + # there is no coercion, so, we set up a name-preserving map. + SV = set(repr(x) for x in p.variables()) + f = PP.hom([x if x in SV else 0 for x in PP.variable_names()], A._P) + try: + return InfinitePolynomial_dense(A, f(p)) + except (ValueError, TypeError): + # last desperate attempt: String conversion + from sage.misc.sage_eval import sage_eval + from sage.rings.polynomial.infinite_polynomial_ring import GenDictWithBasering + # the base ring may be a function field, therefore + # we need GenDictWithBasering + return InfinitePolynomial_dense(A, sage_eval(repr(p), GenDictWithBasering(A._P, A._P.gens_dict()))) + return InfinitePolynomial_sparse(A, p) - """ # Construction and other basic methods # We assume that p is good input. Type checking etc. is now done # in the _element_constructor_ of the parent. @@ -261,7 +262,7 @@ def __init__(self, A, p): # the wrong ring and we get here without going through # _element_constructor_. See trac 22514 for examples. # So a little extra checking is done here. - if not is_MPolynomial(p) or p.base_ring() is not A.base_ring(): + if not isinstance(p, MPolynomial) or p.base_ring() is not A.base_ring(): # coerce to a convenient multivariate polynomial ring p = A._minP(p) @@ -299,73 +300,20 @@ def polynomial(self): EXAMPLES:: sage: X.<x,y> = InfinitePolynomialRing(GF(7)) - sage: p = x[2]*y[1]+3*y[0] + sage: p = x[2]*y[1] + 3*y[0] sage: p x_2*y_1 + 3*y_0 sage: p.polynomial() x_2*y_1 + 3*y_0 sage: p.polynomial().parent() - Multivariate Polynomial Ring in x_2, x_1, x_0, y_2, y_1, y_0 over Finite Field of size 7 + Multivariate Polynomial Ring in x_2, x_1, x_0, y_2, y_1, y_0 + over Finite Field of size 7 sage: p.parent() Infinite polynomial ring in x, y over Finite Field of size 7 """ return self._p - def __call__(self, *args, **kwargs): - """ - EXAMPLES:: - - sage: X.<x> = InfinitePolynomialRing(QQ,implementation='sparse') - sage: a = x[0] + x[1] - sage: a(x_0=2,x_1=x[1]) - x_1 + 2 - sage: _.parent() - Infinite polynomial ring in x over Rational Field - sage: a(x_1=3) - x_0 + 3 - sage: _.parent() - Infinite polynomial ring in x over Rational Field - sage: a(x_1=x[100]) - x_100 + x_0 - - sage: M = matrix([[1,1],[2,0]]) - sage: a(x_1=M) - [x_0 + 1 1] - [ 2 x_0] - """ - # Replace any InfinitePolynomials by their underlying polynomials - if hasattr(self._p, 'variables'): - V = [str(x) for x in self._p.variables()] - else: - V = [] - for kw in kwargs: - value = kwargs[kw] - if isinstance(value, InfinitePolynomial_sparse): - kwargs[kw] = value._p - V.append(kw) - if hasattr(value._p, 'variables'): - V.extend([str(x) for x in value._p.variables()]) - args = list(args) - for i, arg in enumerate(args): - if isinstance(arg, InfinitePolynomial_sparse): - args[i] = arg._p - if hasattr(arg._p, 'variables'): - V.extend([str(x) for x in arg._p.variables()]) - V = list(set(V)) - V.sort(key=self.parent().varname_key, reverse=True) - if V: - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(self._p.base_ring(), V, order=self.parent()._order) - else: - return self - res = R(self._p)(*args, **kwargs) - try: - from sage.misc.sage_eval import sage_eval - return sage_eval(repr(res), self.parent().gens_dict()) - except Exception: - return res - def _getAttributeNames(self): """ This method implements tab completion, see :trac:`6854`. @@ -455,7 +403,7 @@ def subs(self, fixed=None, **kwargs): INPUT: - - ``fixed`` -- (optional) ``dict`` with ``{variable:value}`` pairs + - ``fixed`` -- (optional) ``dict`` with ``{variable: value}`` pairs - ``**kwargs`` -- named parameters OUTPUT: @@ -492,8 +440,9 @@ def subs(self, fixed=None, **kwargs): The substitution can also handle matrices:: - sage: M = matrix([[1,0],[0,2]]) - sage: N = matrix([[0,3],[4,0]]) + sage: # needs sage.modules + sage: M = matrix([[1,0], [0,2]]) + sage: N = matrix([[0,3], [4,0]]) sage: g = x[0]^2 + 3*x[1] sage: g.subs({'x_0': M}) [3*x_1 + 1 0] @@ -507,16 +456,16 @@ def subs(self, fixed=None, **kwargs): sage: R.<x,y> = InfinitePolynomialRing(QQ) sage: f = x[0] - sage: f.subs({x[0]:1}) + sage: f.subs({x[0]: 1}) 1 sage: f.subs(x_0=5) 5 - sage: f.subs({x[0]:1}, x_0=5) + sage: f.subs({x[0]: 1}, x_0=5) 1 TESTS:: - sage: g.subs(fixed=x[0], x_1=N) + sage: g.subs(fixed=x[0], x_1=N) # needs sage.modules Traceback (most recent call last): ... ValueError: fixed must be a dict @@ -540,7 +489,7 @@ def ring(self): EXAMPLES:: sage: X.<x,y> = InfinitePolynomialRing(ZZ,implementation='sparse') - sage: p = x[100]*y[1]^3*x[1]^2+2*x[10]*y[30] + sage: p = x[100]*y[1]^3*x[1]^2 + 2*x[10]*y[30] sage: p.ring() Infinite polynomial ring in x, y over Integer Ring @@ -555,7 +504,7 @@ def is_unit(self): sage: R1.<x,y> = InfinitePolynomialRing(ZZ) sage: R2.<a,b> = InfinitePolynomialRing(QQ) - sage: (1+x[2]).is_unit() + sage: (1 + x[2]).is_unit() False sage: R1(1).is_unit() True @@ -563,7 +512,7 @@ def is_unit(self): False sage: R2(2).is_unit() True - sage: (1+a[2]).is_unit() + sage: (1 + a[2]).is_unit() False Check that :trac:`22454` is fixed:: @@ -592,10 +541,10 @@ def is_nilpotent(self): EXAMPLES:: - sage: R.<x> = InfinitePolynomialRing(QQbar) - sage: (x[0]+x[1]).is_nilpotent() + sage: R.<x> = InfinitePolynomialRing(QQbar) # needs sage.rings.number_field + sage: (x[0] + x[1]).is_nilpotent() # needs sage.rings.number_field False - sage: R(0).is_nilpotent() + sage: R(0).is_nilpotent() # needs sage.rings.number_field True sage: _.<x> = InfinitePolynomialRing(Zmod(4)) sage: (2*x[0]).is_nilpotent() @@ -639,7 +588,7 @@ def max_index(self): EXAMPLES:: sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: p=x[1]^2+y[2]^2+x[1]*x[2]*y[3]+x[1]*y[4] + sage: p = x[1]^2 + y[2]^2 + x[1]*x[2]*y[3] + x[1]*y[4] sage: p.max_index() 4 sage: x[0].max_index() @@ -649,79 +598,6 @@ def max_index(self): """ return max([Integer(str(X).split('_')[1]) for X in self.variables()]+[-1]) - # Basic arithmetics - def _add_(self, x): - """ - EXAMPLES:: - - sage: X.<x> = InfinitePolynomialRing(QQ) - sage: x[1] + x[2] # indirect doctest - x_2 + x_1 - - Check adding from a different parent:: - - sage: Y.<x_0> = PolynomialRing(QQ) - sage: x[0] - x_0 - 0 - """ - # One may need a new parent for self._p and x._p - try: - return InfinitePolynomial_sparse(self.parent(), self._p + x._p) - except Exception: - pass - # We can now assume that self._p and x._p actually are polynomials, - # hence, their parent is not simply the underlying ring. - VarList = list(set(self._p.parent().variable_names()).union(set(x._p.parent().variable_names()))) - VarList.sort(key=self.parent().varname_key, reverse=True) - if VarList: - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) - else: - R = self._p.base_ring() - return InfinitePolynomial_sparse(self.parent(), R(self._p) + R(x._p)) - - def _mul_(self, x): - """ - EXAMPLES:: - - sage: X.<x> = InfinitePolynomialRing(ZZ) - sage: x[2]*x[1] # indirect doctest - x_2*x_1 - - """ - try: - return InfinitePolynomial_sparse(self.parent(), self._p * x._p) - except Exception: - pass - # We can now assume that self._p and x._p actually are polynomials, - # hence, their parent is not just the underlying ring. - VarList = list(set(self._p.parent().variable_names()).union(set(x._p.parent().variable_names()))) - VarList.sort(key=self.parent().varname_key, reverse=True) - if VarList: - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) - else: - R = self._p.base_ring() - return InfinitePolynomial_sparse(self.parent(), R(self._p) * R(x._p)) - - def gcd(self, x): - """ - computes the greatest common divisor - - EXAMPLES:: - - sage: R.<x>=InfinitePolynomialRing(QQ) - sage: p1=x[0]+x[1]**2 - sage: gcd(p1,p1+3) - 1 - sage: gcd(p1,p1)==p1 - True - """ - P = self.parent() - self._p = P._P(self._p) - x._p = P._P(x._p) - return InfinitePolynomial_sparse(self.parent(), self._p.gcd(x._p)) - def _rmul_(self, left): """ TESTS:: @@ -731,7 +607,7 @@ def _rmul_(self, left): 4 """ - return InfinitePolynomial_sparse(self.parent(), left * self._p) + return type(self)(self.parent(), left * self._p) def _lmul_(self, right): """ @@ -742,7 +618,7 @@ def _lmul_(self, right): 4*alpha_3 """ - return InfinitePolynomial_sparse(self.parent(), self._p * right) + return type(self)(self.parent(), self._p * right) def _div_(self, x): r""" @@ -759,7 +635,7 @@ def _div_(self, x): Division by an integer over `\ZZ`:: sage: R.<x> = InfinitePolynomialRing(ZZ, implementation='sparse') - sage: p = x[3]+x[2] + sage: p = x[3] + x[2] sage: q = p/2 sage: q 1/2*x_3 + 1/2*x_2 @@ -773,7 +649,7 @@ def _div_(self, x): 1/x_1 sage: (x[0]/x[0]) x_0/x_0 - sage: qt = 1/x[2]+2/x[1]; qt + sage: qt = 1/x[2] + 2/x[1]; qt (2*x_2 + x_1)/(x_2*x_1) sage: qt.parent() Fraction Field of Infinite polynomial ring in x over Rational Field @@ -781,7 +657,7 @@ def _div_(self, x): sage: z = 1/(x[2]*(x[1]+x[2]))+1/(x[1]*(x[1]+x[2])) sage: z.parent() Fraction Field of Infinite polynomial ring in x over Rational Field - sage: factor(z) + sage: factor(z) # needs sage.libs.singular x_1^-1 * x_2^-1 """ if not x.variables(): @@ -818,240 +694,77 @@ def _floordiv_(self, x): R = self._p.base_ring() return InfinitePolynomial_sparse(self.parent(), R(self._p) // R(x._p)) - def _sub_(self, x): + @cached_method + def lm(self): """ + The leading monomial of ``self``. + EXAMPLES:: - sage: X.<x> = InfinitePolynomialRing(QQ) - sage: x[2] - x[1] # indirect doctest - x_2 - x_1 + sage: X.<x,y> = InfinitePolynomialRing(QQ) + sage: p = 2*x[10]*y[30] + x[10]*y[1]^3*x[1]^2 + sage: p.lm() + x_10*x_1^2*y_1^3 """ - try: - return InfinitePolynomial_sparse(self.parent(), self._p - x._p) - except Exception: - pass - # We can now assume that self._p and x._p actually are polynomials, - # hence, their parent is not just the underlying ring. - VarList = list(set(self._p.parent().variable_names()).union(x._p.parent().variable_names())) - VarList.sort(key=self.parent().varname_key, reverse=True) - if VarList: - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) - else: - R = self._p.base_ring() - return InfinitePolynomial_sparse(self.parent(), R(self._p) - R(x._p)) + if hasattr(self._p, 'lm'): + return InfinitePolynomial(self.parent(), self._p.lm()) + if self._p == 0: + return self + if hasattr(self._p, 'variable_name'): # if it is univariate + return InfinitePolynomial(self.parent(), + self._p.parent().gen() ** max(self._p.exponents())) + return self # if it is scalar - def __pow__(self, n): + @cached_method + def lc(self): """ - Exponentiation by an integer, or action by a callable object + The coefficient of the leading term of ``self``. - NOTE: + EXAMPLES:: - The callable object must accept non-negative integers as input - and return non-negative integers. Typical use case is a - permutation, that will result in the corresponding permutation - of variables. + sage: X.<x,y> = InfinitePolynomialRing(QQ) + sage: p = 2*x[10]*y[30] + 3*x[10]*y[1]^3*x[1]^2 + sage: p.lc() + 3 + + """ + if hasattr(self._p, 'lc'): + return self._p.lc() + if hasattr(self._p, 'variable_name'): # univariate case + return self._p.leading_coefficient() + # scalar case + return self._p + + @cached_method + def lt(self): + """ + The leading term (= product of coefficient and monomial) of ``self``. EXAMPLES:: - sage: X.<x,y> = InfinitePolynomialRing(QQ,implementation='sparse') - sage: p = x[10]*y[2]+2*x[1]*y[3] - sage: P = Permutation(((1,2),(3,4,5))) - sage: p^P # indirect doctest - x_10*y_1 + 2*x_2*y_4 + sage: X.<x,y> = InfinitePolynomialRing(QQ) + sage: p = 2*x[10]*y[30] + 3*x[10]*y[1]^3*x[1]^2 + sage: p.lt() + 3*x_10*x_1^2*y_1^3 """ - P = self.parent() - if callable(n): - if (self._p.parent() == self._p.base_ring()): - return self - if not (hasattr(self._p, 'variables') and self._p.variables()): - return self - if hasattr(n, 'to_cycles') and hasattr(n, '__len__'): # duck typing Permutation - # auxiliary function, necessary since n(m) raises an error if m>len(n) - l = len(n) + if hasattr(self._p, 'lt'): + return InfinitePolynomial(self.parent(), self._p.lt()) + if self._p == 0: + return self + if hasattr(self._p, 'variable_name'): # if it is univariate + return InfinitePolynomial(self.parent(), self._p.leading_coefficient()*self._p.parent().gen()**max(self._p.exponents())) + return self # if it is scalar - def p(m): - return n(m) if 0 < m <= l else m - else: # Permutation group element - p = n + def tail(self): + """ + The tail of ``self`` (this is ``self`` minus its leading term). - def q(s): - return s[0] + '_' + str(p(ZZ(s[1]))) - - newVars = [q(X.split('_')) for X in self._p.parent().variable_names()] - if not newVars: - return self - copyVars = copy.copy(newVars) - newVars = list(set(list(self._p.parent().variable_names())+newVars)) - newVars.sort(key=self.parent().varname_key, reverse=True) - if newVars == list(self._p.parent().variable_names()): - newR = self._p.parent() - else: - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - newR = PolynomialRing(self._p.base_ring(), newVars, order=P._order) - mapR = self._p.parent().hom(copyVars, newR) - return InfinitePolynomial_sparse(self.parent(), mapR(self._p)) - return InfinitePolynomial_sparse(self.parent(), self._p**n) - - # Basic tools for Buchberger algorithm: - # order, leading term/monomial, symmetric cancellation order - - def _richcmp_(self, x, op): - r""" - Comparison of Infinite Polynomials. - - NOTE: - - Let x and y be generators of the parent of self. We only consider - monomial orderings in which x[m] > y[n] iff x appears earlier in the - list of generators than y, or x==y and m>n - - Under this restriction, the monomial ordering can be 'lex' (default), - 'degrevlex' or 'deglex'. - - EXAMPLES:: - - sage: X.<x,y> = InfinitePolynomialRing(QQ, implementation='sparse') - sage: a = x[10]^3 - sage: b = x[1] + x[2] - sage: c = x[1] + x[2] - sage: d = y[1] + x[2] - sage: a == a # indirect doctest - True - sage: b == c # indirect doctest - True - sage: a == b # indirect doctest - False - sage: c > d # indirect doctest - True - - TESTS: - - A classical and an infinite sparse polynomial ring. Note that - the Sage coercion system allows comparison only if a common - parent for the two rings can be constructed. This is why we - have to have the order 'degrevlex':: - - sage: X.<x,y> = InfinitePolynomialRing(ZZ,order='degrevlex', implementation='sparse') - sage: Y.<z,x_3,x_1> = QQ[] - sage: x[3] == x_3 # indirect doctest - True - - Two infinite polynomial rings in different implementation and - order:: - - sage: Y = InfinitePolynomialRing(QQ,['x','y'],order='deglex',implementation='dense') - sage: x[2] == Y(x[2]) # indirect doctest - True - - An example in which a previous version had failed:: - - sage: X.<x,y> = InfinitePolynomialRing(GF(3), order='degrevlex', implementation='sparse') - sage: p = Y('x_3*x_0^2 + x_0*y_3*y_0') - sage: q = Y('x_1*x_0^2 + x_0*y_1*y_0') - sage: p < q # indirect doctest - False - - """ - # We can assume that self.parent() is x.parent(), - # but of course the underlying polynomial rings - # may be widely different, and the sage coercion - # system can't guess what order we want. - from sage.structure.element import parent - R1 = parent(self._p) - R2 = parent(x._p) - if (hasattr(R1, 'has_coerce_map_from') and R1.has_coerce_map_from(R2)) or (hasattr(R2, 'has_coerce_map_from') and R2.has_coerce_map_from(R1)): - return richcmp(self._p, x._p, op) - VarList = list(set(self._p.parent().variable_names()).union(x._p.parent().variable_names())) - VarList.sort(key=self.parent().varname_key, reverse=True) - if VarList: - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) - else: - R = self._p.base_ring() - if (self._p.parent() is self._p.base_ring()) or not self._p.parent().gens(): - fself = self._p.base_ring() - else: - fself = self._p.parent().hom(self._p.parent().variable_names(), R) - if (x._p.parent() is x._p.base_ring()) or not x._p.parent().gens(): - fx = x._p.base_ring() - else: - fx = x._p.parent().hom(x._p.parent().variable_names(), R) - return richcmp(fself(self._p), fx(x._p), op) - - @cached_method - def lm(self): - """ - The leading monomial of ``self``. - - EXAMPLES:: - - sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: p = 2*x[10]*y[30]+x[10]*y[1]^3*x[1]^2 - sage: p.lm() - x_10*x_1^2*y_1^3 - - """ - if hasattr(self._p, 'lm'): - return InfinitePolynomial(self.parent(), self._p.lm()) - if self._p == 0: - return self - if hasattr(self._p, 'variable_name'): # if it is univariate - return InfinitePolynomial(self.parent(), - self._p.parent().gen() ** max(self._p.exponents())) - return self # if it is scalar - - @cached_method - def lc(self): - """ - The coefficient of the leading term of ``self``. - - EXAMPLES:: + EXAMPLES:: sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: p = 2*x[10]*y[30]+3*x[10]*y[1]^3*x[1]^2 - sage: p.lc() - 3 - - """ - if hasattr(self._p, 'lc'): - return self._p.lc() - if hasattr(self._p, 'variable_name'): # univariate case - return self._p.leading_coefficient() - # scalar case - return self._p - - @cached_method - def lt(self): - """ - The leading term (= product of coefficient and monomial) of ``self``. - - EXAMPLES:: - - sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: p = 2*x[10]*y[30]+3*x[10]*y[1]^3*x[1]^2 - sage: p.lt() - 3*x_10*x_1^2*y_1^3 - - """ - if hasattr(self._p, 'lt'): - return InfinitePolynomial(self.parent(), self._p.lt()) - if self._p == 0: - return self - if hasattr(self._p, 'variable_name'): # if it is univariate - return InfinitePolynomial(self.parent(), self._p.leading_coefficient()*self._p.parent().gen()**max(self._p.exponents())) - return self # if it is scalar - - def tail(self): - """ - The tail of ``self`` (this is ``self`` minus its leading term). - - EXAMPLES:: - - sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: p = 2*x[10]*y[30]+3*x[10]*y[1]^3*x[1]^2 + sage: p = 2*x[10]*y[30] + 3*x[10]*y[1]^3*x[1]^2 sage: p.tail() 2*x_10*y_30 @@ -1100,7 +813,7 @@ def footprint(self): EXAMPLES:: sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: p = x[30]*y[1]^3*x[1]^2+2*x[10]*y[30] + sage: p = x[30]*y[1]^3*x[1]^2 + 2*x[10]*y[30] sage: sorted(p.footprint().items()) [(1, [2, 3]), (30, [1, 0])] @@ -1126,7 +839,7 @@ def footprint(self): l = len(self.parent()._names) # get the pairs (shift,exponent) of the leading monomial, indexed by the variable names Vars = self._p.parent().variable_names() - from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomial_libsingular + from sage.rings.polynomial.multi_polynomial import MPolynomial_libsingular if isinstance(self._p, MPolynomial_libsingular): L = [(Vars[i].split('_'), e) for i, e in enumerate(self._p.lm().exponents(as_ETuples=False)[0]) if e] elif hasattr(self._p, 'lm'): @@ -1152,7 +865,7 @@ def symmetric_cancellation_order(self, other): INPUT: - self, other -- two Infinite Polynomials + ``self``, ``other`` -- two Infinite Polynomials ASSUMPTION: @@ -1374,7 +1087,7 @@ def reduce(self, I, tailreduce=False, report=None): EXAMPLES:: sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: p = y[1]^2*y[3]+y[2]*x[3]^3 + sage: p = y[1]^2*y[3] + y[2]*x[3]^3 sage: p.reduce([y[2]*x[1]^2]) x_3^3*y_2 + y_3*y_1^2 @@ -1385,7 +1098,7 @@ def reduce(self, I, tailreduce=False, report=None): reduction. However, reduction by ``y[1]*x[2]^2`` works, since one can change variable index 1 into 2 and 2 into 3:: - sage: p.reduce([y[1]*x[2]^2]) + sage: p.reduce([y[1]*x[2]^2]) # needs sage.libs.singular y_3*y_1^2 The next example shows that tail reduction is not done, unless @@ -1395,13 +1108,13 @@ def reduce(self, I, tailreduce=False, report=None): sage: I = (y[3])*X sage: p.reduce(I) x_3^3*y_2 + y_3*y_1^2 - sage: p.reduce(I, tailreduce=True) + sage: p.reduce(I, tailreduce=True) # needs sage.libs.singular x_3^3*y_2 Last, we demonstrate the ``report`` option:: - sage: p=x[1]^2+y[2]^2+x[1]*x[2]*y[3]+x[1]*y[4] - sage: p.reduce(I, tailreduce=True, report=True) + sage: p = x[1]^2 + y[2]^2 + x[1]*x[2]*y[3] + x[1]*y[4] + sage: p.reduce(I, tailreduce=True, report=True) # needs sage.libs.singular :T[2]:> > x_1^2 + y_2^2 @@ -1482,8 +1195,327 @@ def __iter__(self): self.__class__(self.parent(), monomial)) for coefficient, monomial in self._p) + def gcd(self, x): + """ + computes the greatest common divisor + + EXAMPLES:: + + sage: R.<x>=InfinitePolynomialRing(QQ) + sage: p1=x[0] + x[1]**2 + sage: gcd(p1,p1+3) + 1 + sage: gcd(p1,p1)==p1 + True + """ + P = self.parent() + self._p = P._P(self._p) + x._p = P._P(x._p) + return self.__class__.__base__(self.parent(), self._p.gcd(x._p)) + -class InfinitePolynomial_dense(InfinitePolynomial_sparse): +class InfinitePolynomial_sparse(InfinitePolynomial): + """ + Element of a sparse Polynomial Ring with a Countably Infinite Number of Variables. + + INPUT: + + - ``A`` -- an Infinite Polynomial Ring in sparse implementation + - ``p`` -- a *classical* polynomial that can be interpreted in ``A``. + + Of course, one should not directly invoke this class, but rather + construct elements of ``A`` in the usual way. + + EXAMPLES:: + + sage: A.<a> = QQ[] + sage: B.<b,c> = InfinitePolynomialRing(A,implementation='sparse') + sage: p = a*b[100] + 1/2*c[4] + sage: p + a*b_100 + 1/2*c_4 + sage: p.parent() + Infinite polynomial ring in b, c + over Univariate Polynomial Ring in a over Rational Field + sage: p.polynomial().parent() + Multivariate Polynomial Ring in b_100, b_0, c_4, c_0 + over Univariate Polynomial Ring in a over Rational Field + + """ + + def __call__(self, *args, **kwargs): + """ + EXAMPLES:: + + sage: X.<x> = InfinitePolynomialRing(QQ,implementation='sparse') + sage: a = x[0] + x[1] + sage: a(x_0=2,x_1=x[1]) + x_1 + 2 + sage: _.parent() + Infinite polynomial ring in x over Rational Field + sage: a(x_1=3) + x_0 + 3 + sage: _.parent() + Infinite polynomial ring in x over Rational Field + sage: a(x_1=x[100]) + x_100 + x_0 + + sage: M = matrix([[1,1], [2,0]]) # needs sage.modules + sage: a(x_1=M) # needs sage.modules + [x_0 + 1 1] + [ 2 x_0] + """ + # Replace any InfinitePolynomials by their underlying polynomials + if hasattr(self._p, 'variables'): + V = [str(x) for x in self._p.variables()] + else: + V = [] + for kw in kwargs: + value = kwargs[kw] + if isinstance(value, InfinitePolynomial): + kwargs[kw] = value._p + V.append(kw) + if hasattr(value._p, 'variables'): + V.extend([str(x) for x in value._p.variables()]) + args = list(args) + for i, arg in enumerate(args): + if isinstance(arg, InfinitePolynomial): + args[i] = arg._p + if hasattr(arg._p, 'variables'): + V.extend([str(x) for x in arg._p.variables()]) + V = list(set(V)) + V.sort(key=self.parent().varname_key, reverse=True) + if V: + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._p.base_ring(), V, order=self.parent()._order) + else: + return self + res = R(self._p)(*args, **kwargs) + try: + from sage.misc.sage_eval import sage_eval + return sage_eval(repr(res), self.parent().gens_dict()) + except Exception: + return res + + # Basic arithmetics + def _add_(self, x): + """ + EXAMPLES:: + + sage: X.<x> = InfinitePolynomialRing(QQ) + sage: x[1] + x[2] # indirect doctest + x_2 + x_1 + + Check adding from a different parent:: + + sage: Y.<x_0> = PolynomialRing(QQ) + sage: x[0] - x_0 + 0 + """ + # One may need a new parent for self._p and x._p + try: + return InfinitePolynomial_sparse(self.parent(), self._p + x._p) + except Exception: + pass + # We can now assume that self._p and x._p actually are polynomials, + # hence, their parent is not simply the underlying ring. + VarList = list(set(self._p.parent().variable_names()).union(set(x._p.parent().variable_names()))) + VarList.sort(key=self.parent().varname_key, reverse=True) + if VarList: + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) + else: + R = self._p.base_ring() + return InfinitePolynomial_sparse(self.parent(), R(self._p) + R(x._p)) + + def _mul_(self, x): + """ + EXAMPLES:: + + sage: X.<x> = InfinitePolynomialRing(ZZ) + sage: x[2]*x[1] # indirect doctest + x_2*x_1 + + """ + try: + return InfinitePolynomial_sparse(self.parent(), self._p * x._p) + except Exception: + pass + # We can now assume that self._p and x._p actually are polynomials, + # hence, their parent is not just the underlying ring. + VarList = list(set(self._p.parent().variable_names()).union(set(x._p.parent().variable_names()))) + VarList.sort(key=self.parent().varname_key, reverse=True) + if VarList: + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) + else: + R = self._p.base_ring() + return InfinitePolynomial_sparse(self.parent(), R(self._p) * R(x._p)) + + def _sub_(self, x): + """ + EXAMPLES:: + + sage: X.<x> = InfinitePolynomialRing(QQ) + sage: x[2] - x[1] # indirect doctest + x_2 - x_1 + + """ + try: + return InfinitePolynomial_sparse(self.parent(), self._p - x._p) + except Exception: + pass + # We can now assume that self._p and x._p actually are polynomials, + # hence, their parent is not just the underlying ring. + VarList = list(set(self._p.parent().variable_names()).union(x._p.parent().variable_names())) + VarList.sort(key=self.parent().varname_key, reverse=True) + if VarList: + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) + else: + R = self._p.base_ring() + return InfinitePolynomial_sparse(self.parent(), R(self._p) - R(x._p)) + + def __pow__(self, n): + """ + Exponentiation by an integer, or action by a callable object + + NOTE: + + The callable object must accept non-negative integers as input + and return non-negative integers. Typical use case is a + permutation, that will result in the corresponding permutation + of variables. + + EXAMPLES:: + + sage: X.<x,y> = InfinitePolynomialRing(QQ, implementation='sparse') + sage: p = x[10]*y[2] + 2*x[1]*y[3] + sage: P = Permutation(((1,2),(3,4,5))) + sage: p^P # indirect doctest + x_10*y_1 + 2*x_2*y_4 + + """ + P = self.parent() + if callable(n): + if (self._p.parent() == self._p.base_ring()): + return self + if not (hasattr(self._p, 'variables') and self._p.variables()): + return self + if hasattr(n, 'to_cycles') and hasattr(n, '__len__'): # duck typing Permutation + # auxiliary function, necessary since n(m) raises an error if m>len(n) + l = len(n) + + def p(m): + return n(m) if 0 < m <= l else m + else: # Permutation group element + p = n + + def q(s): + return s[0] + '_' + str(p(ZZ(s[1]))) + + newVars = [q(X.split('_')) for X in self._p.parent().variable_names()] + if not newVars: + return self + copyVars = copy.copy(newVars) + newVars = list(set(list(self._p.parent().variable_names())+newVars)) + newVars.sort(key=self.parent().varname_key, reverse=True) + if newVars == list(self._p.parent().variable_names()): + newR = self._p.parent() + else: + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + newR = PolynomialRing(self._p.base_ring(), newVars, order=P._order) + mapR = self._p.parent().hom(copyVars, newR) + return InfinitePolynomial_sparse(self.parent(), mapR(self._p)) + return InfinitePolynomial_sparse(self.parent(), self._p**n) + + # Basic tools for Buchberger algorithm: + # order, leading term/monomial, symmetric cancellation order + + def _richcmp_(self, x, op): + r""" + Comparison of Infinite Polynomials. + + NOTE: + + Let x and y be generators of the parent of self. We only consider + monomial orderings in which x[m] > y[n] iff x appears earlier in the + list of generators than y, or x==y and m>n + + Under this restriction, the monomial ordering can be 'lex' (default), + 'degrevlex' or 'deglex'. + + EXAMPLES:: + + sage: X.<x,y> = InfinitePolynomialRing(QQ, implementation='sparse') + sage: a = x[10]^3 + sage: b = x[1] + x[2] + sage: c = x[1] + x[2] + sage: d = y[1] + x[2] + sage: a == a # indirect doctest + True + sage: b == c # indirect doctest + True + sage: a == b # indirect doctest + False + sage: c > d # indirect doctest + True + + TESTS: + + A classical and an infinite sparse polynomial ring. Note that + the Sage coercion system allows comparison only if a common + parent for the two rings can be constructed. This is why we + have to have the order 'degrevlex':: + + sage: X.<x,y> = InfinitePolynomialRing(ZZ,order='degrevlex', implementation='sparse') + sage: Y.<z,x_3,x_1> = QQ[] + sage: x[3] == x_3 # indirect doctest + True + + Two infinite polynomial rings in different implementation and + order:: + + sage: Y = InfinitePolynomialRing(QQ,['x','y'],order='deglex', implementation='dense') + sage: x[2] == Y(x[2]) # indirect doctest + True + + An example in which a previous version had failed:: + + sage: X.<x,y> = InfinitePolynomialRing(GF(3), order='degrevlex', implementation='sparse') + sage: p = Y('x_3*x_0^2 + x_0*y_3*y_0') + sage: q = Y('x_1*x_0^2 + x_0*y_1*y_0') + sage: p < q + False + + """ + # We can assume that self.parent() is x.parent(), + # but of course the underlying polynomial rings + # may be widely different, and the sage coercion + # system can't guess what order we want. + from sage.structure.element import parent + R1 = parent(self._p) + R2 = parent(x._p) + if (hasattr(R1, 'has_coerce_map_from') and R1.has_coerce_map_from(R2)) or (hasattr(R2, 'has_coerce_map_from') and R2.has_coerce_map_from(R1)): + return richcmp(self._p, x._p, op) + VarList = list(set(self._p.parent().variable_names()).union(x._p.parent().variable_names())) + VarList.sort(key=self.parent().varname_key, reverse=True) + if VarList: + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) + else: + R = self._p.base_ring() + if (self._p.parent() is self._p.base_ring()) or not self._p.parent().gens(): + fself = self._p.base_ring() + else: + fself = self._p.parent().hom(self._p.parent().variable_names(), R) + if (x._p.parent() is x._p.base_ring()) or not x._p.parent().gens(): + fx = x._p.base_ring() + else: + fx = x._p.parent().hom(x._p.parent().variable_names(), R) + return richcmp(fself(self._p), fx(x._p), op) + + +class InfinitePolynomial_dense(InfinitePolynomial): """ Element of a dense Polynomial Ring with a Countably Infinite Number of Variables. @@ -1495,12 +1527,7 @@ class InfinitePolynomial_dense(InfinitePolynomial_sparse): Of course, one should not directly invoke this class, but rather construct elements of ``A`` in the usual way. - This class inherits from - :class:`~sage.rings.polynomial.infinite_polynomial_element.InfinitePolynomial_sparse`. See - there for a description of the methods. """ - # Construction and other basic methods -## def __init__(self, A, p): # is inherited from the dense implementation def __call__(self, *args, **kwargs): """ @@ -1508,7 +1535,7 @@ def __call__(self, *args, **kwargs): sage: X.<x> = InfinitePolynomialRing(QQ) sage: a = x[0] + x[1] - sage: a(x_0=2,x_1=x[1]) + sage: a(x_0=2, x_1=x[1]) x_1 + 2 sage: _.parent() Infinite polynomial ring in x over Rational Field @@ -1524,11 +1551,11 @@ def __call__(self, *args, **kwargs): # Replace any InfinitePolynomials by their underlying polynomials for kw in kwargs: value = kwargs[kw] - if isinstance(value, InfinitePolynomial_sparse): + if isinstance(value, InfinitePolynomial): kwargs[kw] = value._p args = list(args) for i, arg in enumerate(args): - if isinstance(arg, InfinitePolynomial_sparse): + if isinstance(arg, InfinitePolynomial): args[i] = arg._p self._p = self.parent().polynomial_ring()(self._p) res = self._p(*args, **kwargs) @@ -1543,7 +1570,7 @@ def _richcmp_(self, x, op): A classical and an infinite polynomial ring:: - sage: X.<x,y> = InfinitePolynomialRing(ZZ,order='degrevlex') + sage: X.<x,y> = InfinitePolynomialRing(ZZ, order='degrevlex') sage: Y.<z,x_3,x_1> = QQ[] sage: x[3] == x_3 True @@ -1551,7 +1578,7 @@ def _richcmp_(self, x, op): Two infinite polynomial rings with different order and implementation:: - sage: Y = InfinitePolynomialRing(QQ,['x','y'],order='deglex',implementation='sparse') + sage: Y = InfinitePolynomialRing(QQ,['x','y'], order='deglex', implementation='sparse') sage: x[2] == Y(x[2]) True @@ -1608,28 +1635,6 @@ def _mul_(self, x): x._p = P._P(x._p) return InfinitePolynomial_dense(self.parent(), self._p * x._p) - def _rmul_(self, left): - """ - TESTS:: - - sage: R.<alpha,beta> = InfinitePolynomialRing(QQ) - sage: R.from_base_ring(4) # indirect doctest - 4 - - """ - return InfinitePolynomial_dense(self.parent(), left*self._p) - - def _lmul_(self, right): - """ - TESTS:: - - sage: R.<alpha,beta> = InfinitePolynomialRing(QQ) - sage: alpha[3]*4 # indirect doctest - 4*alpha_3 - - """ - return InfinitePolynomial_dense(self.parent(), self._p*right) - def _sub_(self, x): """ EXAMPLES:: @@ -1660,7 +1665,7 @@ def __pow__(self, n): sage: X.<x,y> = InfinitePolynomialRing(QQ) sage: x[10]^3 x_10^3 - sage: p = x[10]*y[2]+2*x[1]*y[3] + sage: p = x[10]*y[2] + 2*x[1]*y[3] sage: P = Permutation(((1,2),(3,4,5))) sage: p^P x_10*y_1 + 2*x_2*y_4 diff --git a/src/sage/rings/polynomial/infinite_polynomial_ring.py b/src/sage/rings/polynomial/infinite_polynomial_ring.py index ff237743f4a..f1db4c7d275 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_ring.py +++ b/src/sage/rings/polynomial/infinite_polynomial_ring.py @@ -71,11 +71,12 @@ sage: g2 = 3*beta[1]; g2 3*beta_1 sage: A.polynomial_ring() - Multivariate Polynomial Ring in alpha_5, alpha_4, alpha_3, alpha_2, alpha_1, alpha_0, beta_5, beta_4, beta_3, beta_2, beta_1, beta_0 over Rational Field + Multivariate Polynomial Ring in alpha_5, alpha_4, alpha_3, alpha_2, alpha_1, alpha_0, + beta_5, beta_4, beta_3, beta_2, beta_1, beta_0 over Rational Field Of course, we provide the usual polynomial arithmetic:: - sage: f+g + sage: f + g x_5 + 3*y_1 + 2 sage: p = x[10]^2*(f+g); p x_10^2*x_5 + 3*x_10^2*y_1 + 2*x_10^2 @@ -101,8 +102,8 @@ multiplication by ring elements and permutation of variables. If the base ring is a field, one can compute Symmetric Groebner Bases:: - sage: J = A*(alpha[1]*beta[2]) - sage: J.groebner_basis() + sage: J = A * (alpha[1]*beta[2]) + sage: J.groebner_basis() # needs sage.combinat sage.libs.singular [alpha_1*beta_2, alpha_2*beta_1] For more details, see :class:`~sage.rings.polynomial.symmetric_ideal.SymmetricIdeal`. @@ -126,7 +127,8 @@ sage: A.<a_3,a_1,b_1,c_2,c_0> = ZZ[] sage: B.<b,c,d> = InfinitePolynomialRing(A, order='degrevlex') sage: B - Infinite polynomial ring in b, c, d over Multivariate Polynomial Ring in a_3, a_1 over Integer Ring + Infinite polynomial ring in b, c, d over + Multivariate Polynomial Ring in a_3, a_1 over Integer Ring It is no problem if one generator of the Infinite Polynomial Ring is called ``x`` and one variable of the base ring is also called @@ -144,7 +146,8 @@ :: sage: Y - Infinite polynomial ring in x, z over Multivariate Polynomial Ring in x, y_1 over Integer Ring + Infinite polynomial ring in x, z over + Multivariate Polynomial Ring in x, y_1 over Integer Ring The variable ``x`` of ``X`` can still be interpreted in ``Y``, although the first generator of ``Y`` is called ``x`` as well:: @@ -171,7 +174,7 @@ Traceback (most recent call last): ... CoercionException: Overlapping variables (('z', 'y'),['y_1']) are incompatible - sage: X.<x_3,y_1,y_2> = PolynomialRing(ZZ,order='lex') + sage: X.<x_3,y_1,y_2> = PolynomialRing(ZZ, order='lex') sage: # y_1 and y_2 would be in opposite order in an Infinite Polynomial Ring sage: Y.<y> = InfinitePolynomialRing(X) Traceback (most recent call last): @@ -184,10 +187,10 @@ construction available:: sage: X.<x,y> = InfinitePolynomialRing(ZZ) - sage: Y.<z> = InfinitePolynomialRing(X,order='degrevlex') + sage: Y.<z> = InfinitePolynomialRing(X, order='degrevlex') sage: Y Infinite polynomial ring in z over Infinite polynomial ring in x, y over Integer Ring - sage: Y.<z> = InfinitePolynomialRing(X,implementation='sparse') + sage: Y.<z> = InfinitePolynomialRing(X, implementation='sparse') sage: Y Infinite polynomial ring in z over Infinite polynomial ring in x, y over Integer Ring @@ -203,18 +206,18 @@ sage: x[2]/2+(5/3)*a[3]*x[4] + 1 5/3*a_3*x_4 + 1/2*x_2 + 1 - sage: R.<a,b> = InfinitePolynomialRing(ZZ,implementation='sparse') + sage: R.<a,b> = InfinitePolynomialRing(ZZ, implementation='sparse') sage: X.<x> = InfinitePolynomialRing(R) sage: x[2]/2+(5/3)*a[3]*x[4] + 1 5/3*a_3*x_4 + 1/2*x_2 + 1 - sage: R.<a,b> = InfinitePolynomialRing(ZZ,implementation='sparse') - sage: X.<x> = InfinitePolynomialRing(R,implementation='sparse') + sage: R.<a,b> = InfinitePolynomialRing(ZZ, implementation='sparse') + sage: X.<x> = InfinitePolynomialRing(R, implementation='sparse') sage: x[2]/2+(5/3)*a[3]*x[4] + 1 5/3*a_3*x_4 + 1/2*x_2 + 1 sage: R.<a,b> = InfinitePolynomialRing(ZZ) - sage: X.<x> = InfinitePolynomialRing(R,implementation='sparse') + sage: X.<x> = InfinitePolynomialRing(R, implementation='sparse') sage: x[2]/2+(5/3)*a[3]*x[4] + 1 5/3*a_3*x_4 + 1/2*x_2 + 1 @@ -309,11 +312,13 @@ def create_key(self, R, names=('x',), order='lex', implementation='dense'): (InfPoly{[y1], "lex", "dense"}(FractionField(...)), Integer Ring) sage: _[0].all [FractionField, InfPoly{[y1], "lex", "dense"}] - sage: InfinitePolynomialRing.create_key(QQ, names=['beta'], order='deglex', implementation='sparse') + sage: InfinitePolynomialRing.create_key(QQ, names=['beta'], order='deglex', + ....: implementation='sparse') (InfPoly{[beta], "deglex", "sparse"}(FractionField(...)), Integer Ring) sage: _[0].all [FractionField, InfPoly{[beta], "deglex", "sparse"}] - sage: InfinitePolynomialRing.create_key(QQ, names=['x','y'], implementation='dense') + sage: InfinitePolynomialRing.create_key(QQ, names=['x','y'], + ....: implementation='dense') (InfPoly{[x,y], "lex", "dense"}(FractionField(...)), Integer Ring) sage: _[0].all [FractionField, InfPoly{[x,y], "lex", "dense"}] @@ -326,7 +331,7 @@ def create_key(self, R, names=('x',), order='lex', implementation='dense'): sage: _[0].all [FractionField, InfPoly{[x], "lex", "dense"}] - If it is attempted to use no generator, a ValueError is raised:: + If it is attempted to use no generator, a :class:`ValueError` is raised:: sage: InfinitePolynomialRing.create_key(ZZ, names=[]) Traceback (most recent call last): @@ -646,7 +651,7 @@ class InfinitePolynomialRing_sparse(CommutativeRing): sage: Z = InfinitePolynomialRing_sparse(QQ, ['x','y'], 'lex') Nevertheless, since infinite polynomial rings are supposed to be unique - parent structures, they do not evaluate equal. + parent structures, they do not evaluate equal. :: sage: Z == X False @@ -936,7 +941,7 @@ def _element_constructor_(self, x): raise ValueError("cannot convert %s into an element of %s" % (x, self)) # direct conversion will only be used if the underlying polynomials are libsingular. - from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomial_libsingular, MPolynomialRing_libsingular + from sage.rings.polynomial.multi_polynomial import MPolynomial_libsingular # try interpretation in self._P, if we have a dense implementation if hasattr(self, '_P'): if x.parent() is self._P: @@ -945,36 +950,38 @@ def _element_constructor_(self, x): # that MPolynomialRing_polydict does not work in complicated settings. # So, if self._P is libsingular (and this will be the case in many # applications!), we do it "nicely". Otherwise, we have to use sage_eval. - if isinstance(x, MPolynomial_libsingular) and isinstance(self._P, MPolynomialRing_libsingular): - if xmaxind == -1: # Otherwise, x has been an InfinitePolynomial - # We infer the correct variable shift. - # Note: Since we are in the "libsingular" case, there are - # no further "variables" hidden in the base ring of x.parent() + if isinstance(x, MPolynomial_libsingular): + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if isinstance(self._P, MPolynomialRing_libsingular): + if xmaxind == -1: # Otherwise, x has been an InfinitePolynomial + # We infer the correct variable shift. + # Note: Since we are in the "libsingular" case, there are + # no further "variables" hidden in the base ring of x.parent() + try: + VarList = [repr(v) for v in x.variables()] + # since interpretation in base ring + # was impossible, it *must* have + # variables + # This tests admissibility on the fly: + VarList.sort(key=self.varname_key, reverse=True) + except ValueError: + raise ValueError("cannot convert %s into an element of %s - variables are not admissible" % (x, self)) + xmaxind = max([int(v.split('_')[1]) for v in VarList]) try: - VarList = [repr(v) for v in x.variables()] - # since interpretation in base ring - # was impossible, it *must* have - # variables - # This tests admissibility on the fly: - VarList.sort(key=self.varname_key, reverse=True) - except ValueError: - raise ValueError("cannot convert %s into an element of %s - variables are not admissible" % (x, self)) - xmaxind = max([int(v.split('_')[1]) for v in VarList]) - try: - # Apparently, in libsingular, the polynomial conversion is not done by - # name but by position, if the number of variables in the parents coincide. - # So, we shift self._P to achieve xmaxind, and if the number of variables is - # the same then we shift further. We then *must* be - # able to convert x into self._P, or conversion to self is - # impossible (and will be done in InfinitePolynomial(...) - if self._max < xmaxind: - self.gen()[xmaxind] - if self._P.ngens() == x.parent().ngens(): - self.gen()[self._max + 1] - # conversion to self._P will be done in InfinitePolynomial.__init__ - return InfinitePolynomial(self, x) - except (ValueError, TypeError, NameError): - raise ValueError("cannot convert %s (from %s, but variables %s) into an element of %s - no conversion into underlying polynomial ring %s" % (x, x.parent(), x.variables(), self, self._P)) + # Apparently, in libsingular, the polynomial conversion is not done by + # name but by position, if the number of variables in the parents coincide. + # So, we shift self._P to achieve xmaxind, and if the number of variables is + # the same then we shift further. We then *must* be + # able to convert x into self._P, or conversion to self is + # impossible (and will be done in InfinitePolynomial(...) + if self._max < xmaxind: + self.gen()[xmaxind] + if self._P.ngens() == x.parent().ngens(): + self.gen()[self._max + 1] + # conversion to self._P will be done in InfinitePolynomial.__init__ + return InfinitePolynomial(self, x) + except (ValueError, TypeError, NameError): + raise ValueError("cannot convert %s (from %s, but variables %s) into an element of %s - no conversion into underlying polynomial ring %s" % (x, x.parent(), x.variables(), self, self._P)) # By now, x or self._P are not libsingular. Since MPolynomialRing_polydict # is too buggy, we use string evaluation try: @@ -1014,25 +1021,26 @@ def _element_constructor_(self, x): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = PolynomialRing(self._base, VarList, order=self._order) - if isinstance(R, MPolynomialRing_libsingular) and isinstance(x, MPolynomial_libsingular): # everything else is so buggy that it's even not worth to try. - try: - # Problem: If there is only a partial overlap in the variables - # of x.parent() and R, then R(x) raises an error (which, I think, - # is a bug, since we talk here about conversion, not coercion). - # Hence, for being on the safe side, we coerce into a pushout ring: - x = R(1) * x - return InfinitePolynomial(self, x) - except Exception: - # OK, last resort, to be on the safe side + if isinstance(x, MPolynomial_libsingular): # everything else is so buggy that it's even not worth to try. + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if isinstance(R, MPolynomialRing_libsingular): try: - return sage_eval(repr(x), self.gens_dict()) - except (ValueError, TypeError, NameError): - raise ValueError("cannot convert %s into an element of %s; conversion of the underlying polynomial failed" % (x, self)) - else: - try: - return sage_eval(repr(x), self.gens_dict()) - except (ValueError, TypeError, NameError): - raise ValueError("cannot convert %s into an element of %s" % (x, self)) + # Problem: If there is only a partial overlap in the variables + # of x.parent() and R, then R(x) raises an error (which, I think, + # is a bug, since we talk here about conversion, not coercion). + # Hence, for being on the safe side, we coerce into a pushout ring: + x = R(1) * x + return InfinitePolynomial(self, x) + except Exception: + # OK, last resort, to be on the safe side + try: + return sage_eval(repr(x), self.gens_dict()) + except (ValueError, TypeError, NameError): + raise ValueError("cannot convert %s into an element of %s; conversion of the underlying polynomial failed" % (x, self)) + try: + return sage_eval(repr(x), self.gens_dict()) + except (ValueError, TypeError, NameError): + raise ValueError("cannot convert %s into an element of %s" % (x, self)) def tensor_with_ring(self, R): """ @@ -1289,10 +1297,10 @@ def characteristic(self): EXAMPLES:: - sage: X.<x,y> = InfinitePolynomialRing(GF(25,'a')) - sage: X + sage: X.<x,y> = InfinitePolynomialRing(GF(25,'a')) # needs sage.rings.finite_rings + sage: X # needs sage.rings.finite_rings Infinite polynomial ring in x, y over Finite Field in a of size 5^2 - sage: X.characteristic() + sage: X.characteristic() # needs sage.rings.finite_rings 5 """ @@ -1356,12 +1364,13 @@ def key_basis(self): EXAMPLES:: sage: R.<x> = InfinitePolynomialRing(GF(2)) - sage: R.key_basis() + sage: R.key_basis() # needs sage.combinat sage.modules Key polynomial basis over Finite Field of size 2 """ from sage.combinat.key_polynomial import KeyPolynomialBasis return KeyPolynomialBasis(self) + class InfinitePolynomialGen(SageObject): """ This class provides the object which is responsible for returning @@ -1638,7 +1647,8 @@ def polynomial_ring(self): Multivariate Polynomial Ring in xx_0, yy_0 over Integer Ring sage: a = yy[3] sage: X.polynomial_ring() - Multivariate Polynomial Ring in xx_3, xx_2, xx_1, xx_0, yy_3, yy_2, yy_1, yy_0 over Integer Ring + Multivariate Polynomial Ring in xx_3, xx_2, xx_1, xx_0, yy_3, yy_2, yy_1, yy_0 + over Integer Ring """ return self._P diff --git a/src/sage/rings/polynomial/integer_valued_polynomials.py b/src/sage/rings/polynomial/integer_valued_polynomials.py new file mode 100644 index 00000000000..41975882cc2 --- /dev/null +++ b/src/sage/rings/polynomial/integer_valued_polynomials.py @@ -0,0 +1,1138 @@ +# -*- coding: utf-8 -*- +r""" +Integer-valued polynomial rings + +AUTHORS: + +- Frรฉdรฉric Chapoton (2023-03): Initial version +""" +# *************************************************************************** +# Copyright (C) 2013 Frรฉdรฉric Chapoton +# +# Distributed under the terms of the GNU General Public License (GPL) +# https://www.gnu.org/licenses/ +# *************************************************************************** +from sage.arith.misc import (binomial, factorial) +from sage.categories.algebras import Algebras +from sage.categories.rings import Rings +from sage.categories.realizations import Category_realization_of_parent +from sage.combinat.free_module import CombinatorialFreeModule +from sage.matrix.constructor import matrix +from sage.misc.cachefunc import cached_method +from sage.modules.free_module_element import vector +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ +from sage.sets.non_negative_integers import NonNegativeIntegers +from sage.sets.family import Family +from sage.misc.bindable_class import BindableClass +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent + + +class IntegerValuedPolynomialRing(UniqueRepresentation, Parent): + r""" + The integer-valued polynomial ring over a base ring `R`. + + Integer-valued polynomial rings are commutative and associative + algebras, with a basis indexed by non-negative integers. + + There are two natural bases, made of the sequence + `\binom{x}{n}` for `n \geq 0` (the *binomial basis*) and of + the other sequence `\binom{x+n}{n}` for `n \geq 0` (the *shifted basis*). + + These two bases are available as follows:: + + sage: B = IntegerValuedPolynomialRing(QQ).Binomial() + sage: S = IntegerValuedPolynomialRing(QQ).Shifted() + + or by using the shortcuts:: + + sage: B = IntegerValuedPolynomialRing(QQ).B() + sage: S = IntegerValuedPolynomialRing(QQ).S() + + There is a conversion formula between the two bases: + + .. MATH:: + + \binom{x}{i} = \sum_{k=0}^{i} (-1)^{i-k} \binom{i}{k} \binom{x+k}{k} + + with inverse: + + .. MATH:: + + \binom{x+i}{i} = \sum_{k=0}^{i} \binom{i}{k} \binom{x}{k}. + + REFERENCES: + + - :wikipedia:`Integer-valued polynomial` + + TESTS:: + + sage: IntegerValuedPolynomialRing(24) + Traceback (most recent call last): + ... + TypeError: argument R must be a commutative ring + """ + def __init__(self, R): + """ + TESTS:: + + sage: IV = IntegerValuedPolynomialRing(ZZ) + sage: TestSuite(IV).run() + """ + if R not in Rings().Commutative(): + raise TypeError("argument R must be a commutative ring") + self._base = R + cat = Algebras(R).Commutative().WithBasis() + Parent.__init__(self, base=R, category=cat.WithRealizations()) + + _shorthands = ["B", "S"] + + def _repr_(self) -> str: + r""" + Return the string representation. + + EXAMPLES:: + + sage: IntegerValuedPolynomialRing(QQ) + Integer-Valued Polynomial Ring over Rational Field + """ + br = self.base_ring() + return f"Integer-Valued Polynomial Ring over {br}" + + def a_realization(self): + """ + Return a default realization. + + The Binomial realization is chosen. + + EXAMPLES:: + + sage: IntegerValuedPolynomialRing(QQ).a_realization() + Integer-Valued Polynomial Ring over Rational Field + in the binomial basis + """ + return self.Binomial() + + class Bases(Category_realization_of_parent): + def super_categories(self) -> list: + r""" + Return the super-categories of ``self``. + + EXAMPLES:: + + sage: A = IntegerValuedPolynomialRing(QQ); A + Integer-Valued Polynomial Ring over Rational Field + sage: C = A.Bases(); C + Category of bases of Integer-Valued Polynomial Ring + over Rational Field + sage: C.super_categories() + [Category of realizations of Integer-Valued Polynomial Ring + over Rational Field, + Join of Category of algebras with basis over Rational Field and + Category of filtered algebras over Rational Field and + Category of commutative algebras over Rational Field and + Category of realizations of unital magmas] + """ + A = self.base() + category = Algebras(A.base_ring()).Commutative().Filtered() + return [A.Realizations(), + category.Realizations().WithBasis()] + + class ParentMethods: + def _repr_(self) -> str: + r""" + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(QQ).S() + sage: F # indirect doctest + Integer-Valued Polynomial Ring over Rational Field + in the shifted basis + sage: F = IntegerValuedPolynomialRing(QQ).B() + sage: F # indirect doctest + Integer-Valued Polynomial Ring over Rational Field + in the binomial basis + """ + real = self.realization_of() + return f"{real} in the {self._realization_name()} basis" + + @cached_method + def one_basis(self): + r""" + Return the number 0, which index the unit of this algebra. + + EXAMPLES:: + + sage: A = IntegerValuedPolynomialRing(QQ).S() + sage: A.one_basis() + 0 + sage: A.one() + S[0] + """ + return self.basis().keys()(0) + + def degree_on_basis(self, m): + r""" + Return the degree of the basis element indexed by ``m``. + + EXAMPLES:: + + sage: A = IntegerValuedPolynomialRing(QQ).S() + sage: A.degree_on_basis(4) + 4 + """ + return ZZ(m) + + def from_polynomial(self, p): + """ + Convert a polynomial into the ring of integer-valued polynomials. + + This raises a ``ValueError`` if this is not possible. + + INPUT: + + - ``p`` -- a polynomial in one variable + + EXAMPLES:: + + sage: A = IntegerValuedPolynomialRing(ZZ).S() + sage: S = A.basis() + sage: S[5].polynomial() + 1/120*x^5 + 1/8*x^4 + 17/24*x^3 + 15/8*x^2 + 137/60*x + 1 + sage: A.from_polynomial(_) + S[5] + sage: x = polygen(QQ, 'x') + sage: A.from_polynomial(x) + -S[0] + S[1] + + sage: A = IntegerValuedPolynomialRing(ZZ).B() + sage: B = A.basis() + sage: B[5].polynomial() + 1/120*x^5 - 1/12*x^4 + 7/24*x^3 - 5/12*x^2 + 1/5*x + sage: A.from_polynomial(_) + B[5] + sage: x = polygen(QQ, 'x') + sage: A.from_polynomial(x) + B[1] + + TESTS:: + + sage: x = polygen(QQ,'x') + sage: A.from_polynomial(x+1/3) + Traceback (most recent call last): + ... + ValueError: not a polynomial with integer values: 1/3 + + sage: t = polygen(ZZ,'t') + sage: B = IntegerValuedPolynomialRing(QQ).B() + sage: B.from_polynomial(t+1) + B[0] + B[1] + """ + B = self.basis() + poly = self._poly + remain = p.change_variable_name('x') + result = self.zero() + while remain: + N = remain.degree() + top_coeff = remain.leading_coefficient() * factorial(N) + try: + top_coeff = self.base_ring()(top_coeff) + except TypeError as exc: + msg = 'not a polynomial with integer' + msg += f' values: {top_coeff}' + raise ValueError(msg) from exc + remain += -top_coeff * poly(N) + result += top_coeff * B[N] + return result + + def gen(self, i=0): + r""" + Return the generator of this algebra. + + The optional argument is ignored. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(ZZ).B() + sage: F.gen() + B[1] + """ + return self.algebra_generators()[0] + + @cached_method + def algebra_generators(self): + r""" + Return the generators of this algebra. + + EXAMPLES:: + + sage: A = IntegerValuedPolynomialRing(ZZ).S(); A + Integer-Valued Polynomial Ring over Integer Ring + in the shifted basis + sage: A.algebra_generators() + Family (S[1],) + """ + NonNeg = self.basis().keys() + return Family([self.monomial(NonNeg(1))]) + + gens = algebra_generators + + class ElementMethods: + def __call__(self, v): + """ + Evaluation at some value ``v`` + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: f = B**2+4*B+6 + sage: f(1/3) + 118/9 + + sage: F = IntegerValuedPolynomialRing(ZZ).B() + sage: B = F.gen() + sage: f = B**2+4*B+6 + sage: f(1/3) + 67/9 + """ + return self.polynomial()(v) + + def polynomial(self): + """ + Convert to a polynomial in `x`. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: (B+1).polynomial() + x + 2 + + sage: F = IntegerValuedPolynomialRing(ZZ).B() + sage: B = F.gen() + sage: (B+1).polynomial() + x + 1 + + TESTS:: + + sage: F.zero().polynomial().parent() + Univariate Polynomial Ring in x over Rational Field + """ + R = PolynomialRing(QQ, 'x') + p = self.parent()._poly + return R.sum(c * p(i) for i, c in self) + + def shift(self, j=1): + """ + Shift all indices by `j`. + + INPUT: + + - `j` -- integer (default: 1) + + In the binomial basis, the shift by 1 corresponds to + a summation operator from `0` to `x`. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(ZZ).B() + sage: B = F.gen() + sage: (B+1).shift() + B[1] + B[2] + sage: (B+1).shift(3) + B[3] + B[4] + """ + A = self.parent() + return A._from_dict({A._indices(i + j): c for i, c in self}) + + def sum_of_coefficients(self): + """ + Return the sum of coefficients. + + In the shifted basis, this is the evaluation at `x=0`. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(ZZ).S() + sage: B = F.basis() + sage: (B[2]*B[4]).sum_of_coefficients() + 1 + + TESTS:: + + sage: (0*B[2]).sum_of_coefficients().parent() + Integer Ring + """ + R = self.parent().base_ring() + return R.sum(self._monomial_coefficients.values()) + + def content(self): + """ + Return the content of ``self``. + + This is the gcd of the coefficients. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(ZZ).S() + sage: B = F.basis() + sage: (3*B[4]+6*B[7]).content() + 3 + + TESTS:: + + sage: (0*B[2]).content() + 0 + """ + from sage.arith.misc import gcd + return gcd(self._monomial_coefficients.values()) + + class Shifted(CombinatorialFreeModule, BindableClass): + r""" + The integer-valued polynomial ring in the shifted basis. + + The basis used here is given by `S[i] = \binom{i+x}{i}` for `i \in \NN`. + + Assuming `n_1 \leq n_2`, the product of two monomials `S[n_1] \cdot S[n_2]` + is given by the sum + + .. MATH:: + + \sum_{k=0}^{n_1} (-1)^k \binom{n_1}{k}\binom{n_1+n_2-k}{n_1} S[n_1 + n_2 - k]. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(QQ).S(); F + Integer-Valued Polynomial Ring over Rational Field + in the shifted basis + + sage: F.gen() + S[1] + + sage: S = IntegerValuedPolynomialRing(ZZ).S(); S + Integer-Valued Polynomial Ring over Integer Ring + in the shifted basis + sage: S.base_ring() + Integer Ring + + sage: G = IntegerValuedPolynomialRing(S).S(); G + Integer-Valued Polynomial Ring over Integer-Valued Polynomial + Ring over Integer Ring in the shifted basis in the shifted basis + sage: G.base_ring() + Integer-Valued Polynomial Ring over Integer Ring + in the shifted basis + + Integer-valued polynomial rings commute with their base ring:: + + sage: K = IntegerValuedPolynomialRing(QQ).S() + sage: a = K.gen() + sage: K.is_commutative() + True + sage: L = IntegerValuedPolynomialRing(K).S() + sage: c = L.gen() + sage: L.is_commutative() + True + sage: s = a * c^3; s + S[1]*S[1] + (-6*S[1])*S[2] + 6*S[1]*S[3] + sage: parent(s) + Integer-Valued Polynomial Ring over Integer-Valued Polynomial + Ring over Rational Field in the shifted basis in the shifted basis + + Integer-valued polynomial rings are commutative:: + + sage: c^3 * a == c * a * c * c + True + + We can also manipulate elements in the basis and + coerce elements from our base field:: + + sage: F = IntegerValuedPolynomialRing(QQ).S() + sage: S = F.basis() + sage: S[2] * S[3] + 3*S[3] - 12*S[4] + 10*S[5] + sage: 1 - S[2] * S[2] / 2 + S[0] - 1/2*S[2] + 3*S[3] - 3*S[4] + """ + def __init__(self, A): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(QQ).S(); F + Integer-Valued Polynomial Ring over Rational Field + in the shifted basis + sage: TestSuite(F).run() + """ + CombinatorialFreeModule.__init__(self, A.base_ring(), + NonNegativeIntegers(), + category=A.Bases(), + prefix="S", + latex_prefix=r"\mathbb{S}") + + def _realization_name(self) -> str: + r""" + TESTS:: + + sage: F = IntegerValuedPolynomialRing(QQ).S() + sage: F._realization_name() + 'shifted' + """ + return "shifted" + + def product_on_basis(self, n1, n2): + r""" + Return the product of basis elements ``n1`` and ``n2``. + + INPUT: + + - ``n1``, ``n2`` -- integers + + EXAMPLES:: + + sage: A = IntegerValuedPolynomialRing(QQ).S() + sage: A.product_on_basis(0, 1) + S[1] + sage: A.product_on_basis(1, 2) + -2*S[2] + 3*S[3] + """ + i = ZZ(n1) + j = ZZ(n2) + if j < i: + j, i = i, j + + R = self.base_ring() + return self._from_dict({i + j - k: R((-1)**k * i.binomial(k) * (i + j - k).binomial(i)) + for k in range(i + 1)}) + + def _from_binomial_basis(self, i): + """ + Convert from the ``binomial(x,k)`` basis. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: S = IntegerValuedPolynomialRing(ZZ).S() + sage: B = IntegerValuedPolynomialRing(ZZ).B() + sage: b = B.basis() + sage: S(b[3]+1) # indirect doctest + 3*S[1] - 3*S[2] + S[3] + sage: B(_) + B[0] + B[3] + """ + i = ZZ(i) + R = self.base_ring() + return self._from_dict({k: R((-1)**(i - k) * i.binomial(k)) + for k in range(i + 1)}) + + def from_h_vector(self, h): + """ + Convert from some `h`-vector. + + INPUT: + + - ``h`` -- a tuple or vector + + .. SEEALSO:: :meth:`Element.h_vector` + + EXAMPLES:: + + sage: A = IntegerValuedPolynomialRing(ZZ).S() + sage: S = A.basis() + sage: ex = S[2]+S[4] + sage: A.from_h_vector(ex.h_vector()) + S[2] + S[4] + """ + d = len(h) - 1 + m = matrix(QQ, d + 1, d + 1, + lambda j, i: (-1)**(d - j) * binomial(d - i, d - j)) + v = vector(QQ, [h[i] for i in range(d + 1)]) + R = self.base_ring() + return self._from_dict({i: R(c) + for i, c in enumerate(m * v)}) + + def _element_constructor_(self, x): + r""" + Convert ``x`` into ``self``. + + INPUT: + + - ``x`` -- an element of the base ring or something convertible + + EXAMPLES:: + + sage: R = IntegerValuedPolynomialRing(QQ).S() + sage: x = R.gen() + sage: R(3) + 3*S[0] + sage: R(x) + S[1] + """ + P = x.parent() + if isinstance(P, IntegerValuedPolynomialRing.Shifted): + if P is self: + return x + if P is not self.base_ring(): + return self.element_class(self, x.monomial_coefficients()) + + # ok, not a integer-valued polynomial ring element + R = self.base_ring() + # coercion via base ring + x = R(x) + if x == 0: + return self.element_class(self, {}) + return self.from_base_ring_from_one_basis(x) + + def _coerce_map_from_(self, R): + r""" + Return ``True`` if there is a coercion from ``R`` into ``self`` + and ``False`` otherwise. + + INPUT: + + - ``R`` -- a commutative ring + + The things that coerce into ``self`` are + + - Integer-Valued Polynomial Rings over a base + with a coercion map into ``self.base_ring()``. + + - Anything with a coercion into ``self.base_ring()``. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(GF(7)).S(); F + Integer-Valued Polynomial Ring over Finite Field of size 7 + in the shifted basis + + Elements of the integer-valued polynomial ring canonically + coerce in:: + + sage: x = F.gen() + sage: F.coerce(x*x) # indirect doctest + 6*S[1] + 2*S[2] + + Elements of the integers coerce in, since there is a coerce map + from `\ZZ` to `\GF(7)`:: + + sage: F.coerce(1) # indirect doctest + S[0] + + There is no coerce map from `\QQ` to `\GF{7}`:: + + sage: F.coerce(2/3) # indirect doctest + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Rational Field to + Integer-Valued Polynomial Ring over Finite Field of size 7 + in the shifted basis + + Elements of the base ring coerce in:: + + sage: F.coerce(GF(7)(5)) + 5*S[0] + + The integer-valued polynomial ring over `\ZZ` on `x` coerces in, + since `\ZZ` coerces to `\GF{7}`:: + + sage: G = IntegerValuedPolynomialRing(ZZ).S() + sage: Gx = G.gen() + sage: z = F.coerce(Gx**2); z + -S[1] + 2*S[2] + sage: z.parent() is F + True + + However, `\GF{7}` does not coerce to `\ZZ`, so the + integer-valued polynomial algebra over `\GF{7}` does not + coerce to the one over `\ZZ`:: + + sage: G.coerce(x^3+x) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Integer-Valued Polynomial + Ring over Finite Field of size 7 in the shifted basis + to Integer-Valued Polynomial + Ring over Integer Ring in the shifted basis + + TESTS:: + + sage: F = IntegerValuedPolynomialRing(ZZ).S() + sage: G = IntegerValuedPolynomialRing(QQ).S() + sage: H = IntegerValuedPolynomialRing(ZZ).S() + sage: F._coerce_map_from_(G) + False + sage: G._coerce_map_from_(F) + True + sage: F._coerce_map_from_(H) + True + sage: F._coerce_map_from_(QQ) + False + sage: G._coerce_map_from_(QQ) + True + sage: F.has_coerce_map_from(PolynomialRing(ZZ,'x')) + False + """ + # integer-valued polynomial rings over any base + # that coerces in: + if isinstance(R, IntegerValuedPolynomialRing.Shifted): + return self.base_ring().has_coerce_map_from(R.base_ring()) + if isinstance(R, IntegerValuedPolynomialRing.Binomial): + return R.module_morphism(self._from_binomial_basis, + codomain=self) + return self.base_ring().has_coerce_map_from(R) + + def _poly(self, i): + """ + Convert the basis element `S[i]` to a polynomial. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(ZZ).S() + sage: F._poly(4) + 1/24*x^4 + 5/12*x^3 + 35/24*x^2 + 25/12*x + 1 + """ + x = polygen(QQ, 'x') + return binomial(x + i, i) + + class Element(CombinatorialFreeModule.Element): + + def umbra(self): + """ + Return the Bernoulli umbra. + + This is the derivative at `-1` of the shift by one. + + .. SEEALSO:: :meth:`derivative_at_minus_one` + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: (B+1).umbra() + 3/2 + + TESTS:: + + sage: [(B**n).umbra() for n in range(1, 11)] + [1/2, 1/6, 0, -1/30, 0, 1/42, 0, -1/30, 0, 5/66] + """ + return self.shift().derivative_at_minus_one() + + def delta(self): + r""" + Return the image by the difference operator `\Delta`. + + The operator `\Delta` is defined on polynomials by + + .. MATH:: + + f \mapsto f(x+1)-f(x). + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(ZZ).S() + sage: S = F.basis() + sage: S[5].delta() + S[0] + S[1] + S[2] + S[3] + S[4] + """ + return self.variable_shift() - self + + def variable_shift(self, k=1): + r""" + Return the image by the shift of variables. + + On polynomials, the action is the shift + on variables `x \mapsto x + k`. + + INPUT: + + - `k` -- integer (default: 1) + + EXAMPLES:: + + sage: A = IntegerValuedPolynomialRing(ZZ).S() + sage: S = A.basis() + sage: S[5].variable_shift() + S[0] + S[1] + S[2] + S[3] + S[4] + S[5] + + sage: S[5].variable_shift(-1) + -S[4] + S[5] + + TESTS:: + + sage: S[5].variable_shift(0) + S[5] + sage: S[5].variable_shift().variable_shift(-1) + S[5] + """ + if k == 0: + return self + + A = self.parent() + + if k > 0: + B = A.basis() + resu = A.linear_combination((B[j], c) for i, c in self + for j in range(i + 1)) + if k == 1: + return resu + return resu.variable_shift(k - 1) + + resu = self - A._from_dict({i - 1: c for i, c in self if i}) + if k == -1: + return resu + return resu.variable_shift(k + 1) + + def derivative_at_minus_one(self): + """ + Return the derivative at `-1`. + + This is sometimes useful when `-1` is a root. + + .. SEEALSO:: :meth:`umbra` + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: (B+1).derivative_at_minus_one() + 1 + """ + return QQ.sum(c / QQ(i) for i, c in self if i) + + def h_vector(self): + """ + Return the numerator of the generating series of values. + + If ``self`` is an Ehrhart polynomial, this is the `h`-vector. + + .. SEEALSO:: :meth:`h_polynomial` + + EXAMPLES:: + + sage: x = polygen(QQ,'x') + sage: A = IntegerValuedPolynomialRing(ZZ).S() + sage: ex = A.from_polynomial((1+x)**3) + sage: ex.h_vector() + (0, 1, 4, 1) + """ + d = max(self.support(), default=-1) + m = matrix(QQ, d + 1, d + 1, + lambda j, i: (-1)**(d - j) * (d - i).binomial(d - j)) + v = vector(QQ, [self.coefficient(i) for i in range(d + 1)]) + return m * v + + def h_polynomial(self): + """ + Return the `h`-vector as a polynomial. + + .. SEEALSO:: :meth:`h_vector` + + EXAMPLES:: + + sage: x = polygen(QQ,'x') + sage: A = IntegerValuedPolynomialRing(ZZ).S() + sage: ex = A.from_polynomial((1+x)**3) + sage: ex.h_polynomial() + z^3 + 4*z^2 + z + """ + anneau = PolynomialRing(self.parent().base_ring(), 'z') + return anneau(list(self.h_vector())) + + S = Shifted + + # ===== Another basis for the same algebra ===== + + class Binomial(CombinatorialFreeModule, BindableClass): + r""" + The integer-valued polynomial ring in the binomial basis. + + The basis used here is given by `B[i] = \binom{x}{i}` for `i \in \NN`. + + Assuming `n_1 \leq n_2`, the product of two monomials `B[n_1] \cdot B[n_2]` + is given by the sum + + .. MATH:: + + \sum_{k=0}^{n_1} \binom{n_1}{k}\binom{n_1+n_2-k}{n_1} B[n_1 + n_2 - k]. + + The product of two monomials is therefore a positive linear combination + of monomials. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(QQ).B(); F + Integer-Valued Polynomial Ring over Rational Field + in the binomial basis + + sage: F.gen() + B[1] + + sage: S = IntegerValuedPolynomialRing(ZZ).B(); S + Integer-Valued Polynomial Ring over Integer Ring + in the binomial basis + sage: S.base_ring() + Integer Ring + + sage: G = IntegerValuedPolynomialRing(S).B(); G + Integer-Valued Polynomial Ring over Integer-Valued Polynomial Ring + over Integer Ring in the binomial basis in the binomial basis + sage: G.base_ring() + Integer-Valued Polynomial Ring over Integer Ring + in the binomial basis + + Integer-valued polynomial rings commute with their base ring:: + + sage: K = IntegerValuedPolynomialRing(QQ).B() + sage: a = K.gen() + sage: K.is_commutative() + True + sage: L = IntegerValuedPolynomialRing(K).B() + sage: c = L.gen() + sage: L.is_commutative() + True + sage: s = a * c^3; s + B[1]*B[1] + 6*B[1]*B[2] + 6*B[1]*B[3] + sage: parent(s) + Integer-Valued Polynomial Ring over Integer-Valued Polynomial + Ring over Rational Field in the binomial basis in the binomial basis + + Integer-valued polynomial rings are commutative:: + + sage: c^3 * a == c * a * c * c + True + + We can also manipulate elements in the basis:: + + sage: F = IntegerValuedPolynomialRing(QQ).B() + sage: B = F.basis() + sage: B[2] * B[3] + 3*B[3] + 12*B[4] + 10*B[5] + sage: 1 - B[2] * B[2] / 2 + B[0] - 1/2*B[2] - 3*B[3] - 3*B[4] + + and coerce elements from our base field:: + + sage: F(4/3) + 4/3*B[0] + """ + def __init__(self, A): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(QQ).B(); F + Integer-Valued Polynomial Ring over Rational Field + in the binomial basis + sage: TestSuite(F).run() + """ + CombinatorialFreeModule.__init__(self, A.base_ring(), + NonNegativeIntegers(), + latex_prefix="", + category=A.Bases()) + + def _realization_name(self) -> str: + r""" + TESTS:: + + sage: F = IntegerValuedPolynomialRing(QQ).B() + sage: F._realization_name() + 'binomial' + """ + return "binomial" + + def product_on_basis(self, n1, n2): + r""" + Return the product of basis elements ``n1`` and ``n2``. + + INPUT: + + - ``n1``, ``n2`` -- integers + + EXAMPLES:: + + sage: A = IntegerValuedPolynomialRing(QQ).B() + sage: A.product_on_basis(0, 1) + B[1] + sage: A.product_on_basis(1, 2) + 2*B[2] + 3*B[3] + """ + i = ZZ(n1) + j = ZZ(n2) + if j < i: + j, i = i, j + + R = self.base_ring() + return self._from_dict({i + j - k: + R(binomial(i, k) * binomial(i + j - k, i)) + for k in range(i + 1)}) + + def _from_shifted_basis(self, i): + """ + Convert from the shifted binomial(x+k,k) basis. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: S = IntegerValuedPolynomialRing(ZZ).S() + sage: B = IntegerValuedPolynomialRing(ZZ).B() + sage: s = S.basis() + sage: B(s[3]+1) # indirect doctest + 2*B[0] + 3*B[1] + 3*B[2] + B[3] + sage: S(_) + S[0] + S[3] + """ + i = ZZ(i) + R = self.base_ring() + return self._from_dict({k: R(i.binomial(k)) + for k in range(i + 1)}) + + def _element_constructor_(self, x): + r""" + Convert ``x`` into ``self``. + + EXAMPLES:: + + sage: R = IntegerValuedPolynomialRing(QQ).B() + sage: x = R.gen() + sage: R(3) + 3*B[0] + sage: R(x) + B[1] + """ + P = x.parent() + if isinstance(P, IntegerValuedPolynomialRing.Binomial): + if P is self: + return x + if P is not self.base_ring(): + return self.element_class(self, x.monomial_coefficients()) + + # ok, not a integer-valued polynomial ring element + R = self.base_ring() + # coercion via base ring + x = R(x) + if x == 0: + return self.element_class(self, {}) + return self.from_base_ring_from_one_basis(x) + + def _coerce_map_from_(self, R): + r""" + Return ``True`` if there is a coercion from ``R`` into ``self`` + and ``False`` otherwise. + + The things that coerce into ``self`` are + + - Integer-Valued Polynomial Rings over a base + with a coercion map into ``self.base_ring()``. + + - Anything with a coercion into ``self.base_ring()``. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(GF(7)).B(); F + Integer-Valued Polynomial Ring over Finite Field of size 7 + in the binomial basis + + Elements of the integer-valued polynomial ring canonically coerce + in:: + + sage: x = F.gen() + sage: F.coerce(x*x) # indirect doctest + B[1] + 2*B[2] + + Elements of the integers coerce in, since there is a coerce map + from `\ZZ` to `\GF(7)`:: + + sage: F.coerce(1) # indirect doctest + B[0] + + There is no coerce map from `\QQ` to `\GF{7}`:: + + sage: F.coerce(2/3) # indirect doctest + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Rational Field to + Integer-Valued Polynomial Ring over Finite Field of size 7 + in the binomial basis + + Elements of the base ring coerce in:: + + sage: F.coerce(GF(7)(5)) + 5*B[0] + + The integer-valued polynomial ring over `\ZZ` on `x` coerces in, + since `\ZZ` coerces to `\GF{7}`:: + + sage: G = IntegerValuedPolynomialRing(ZZ).B() + sage: Gx = G.gen() + sage: z = F.coerce(Gx**2); z + B[1] + 2*B[2] + sage: z.parent() is F + True + + However, `\GF{7}` does not coerce to `\ZZ`, so the + integer-valued polynomial algebra over `\GF{7}` does not + coerce to the one over `\ZZ`:: + + sage: G.coerce(x^3+x) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Integer-Valued Polynomial + Ring over Finite Field of size 7 in the binomial basis to + Integer-Valued Polynomial Ring over Integer Ring + in the binomial basis + + TESTS:: + + sage: F = IntegerValuedPolynomialRing(ZZ).B() + sage: G = IntegerValuedPolynomialRing(QQ).B() + sage: H = IntegerValuedPolynomialRing(ZZ).B() + sage: F._coerce_map_from_(G) + False + sage: G._coerce_map_from_(F) + True + sage: F._coerce_map_from_(H) + True + sage: F._coerce_map_from_(QQ) + False + sage: G._coerce_map_from_(QQ) + True + sage: F.has_coerce_map_from(PolynomialRing(ZZ,'x')) + False + """ + # integer-valued polynomial rings over any base + # that coerces in: + if isinstance(R, IntegerValuedPolynomialRing.Binomial): + return self.base_ring().has_coerce_map_from(R.base_ring()) + if isinstance(R, IntegerValuedPolynomialRing.Shifted): + return R.module_morphism(self._from_shifted_basis, + codomain=self) + return self.base_ring().has_coerce_map_from(R) + + def _poly(self, i): + """ + Convert the basis element `B[i]` to a polynomial. + + EXAMPLES:: + + sage: F = IntegerValuedPolynomialRing(ZZ).B() + sage: F._poly(4) + 1/24*x^4 - 1/4*x^3 + 11/24*x^2 - 1/4*x + """ + x = polygen(QQ, 'x') + return binomial(x, i) + + class Element(CombinatorialFreeModule.Element): + pass + + B = Binomial diff --git a/src/sage/rings/polynomial/laurent_polynomial.pxd b/src/sage/rings/polynomial/laurent_polynomial.pxd index cb0a4ab4ea0..8e9107aeb47 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pxd +++ b/src/sage/rings/polynomial/laurent_polynomial.pxd @@ -1,6 +1,4 @@ from sage.structure.element cimport CommutativeAlgebraElement, ModuleElement, RingElement, Element -from sage.rings.polynomial.polydict cimport ETuple, PolyDict -from sage.rings.polynomial.multi_polynomial cimport MPolynomial cdef class LaurentPolynomial(CommutativeAlgebraElement): @@ -14,16 +12,6 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): cdef class LaurentPolynomial_univariate(LaurentPolynomial): cdef ModuleElement __u cdef long __n - cpdef __normalize(self) + cpdef _normalize(self) cpdef _unsafe_mutate(self, i, value) -cdef class LaurentPolynomial_mpair(LaurentPolynomial): - cdef ETuple _mon - cdef MPolynomial _poly - cdef PolyDict _prod - cdef _compute_polydict(self) - cdef _normalize(self, i=*) - cpdef rescale_vars(self, dict d, h=*, new_ring=*) - cpdef toric_coordinate_change(self, M, h=*, new_ring=*) - cpdef toric_substitute(self, v, v1, a, h=*, new_ring=*) - diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index b6e83588af6..cf92b0e43d1 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1,7 +1,6 @@ r""" Elements of Laurent polynomial rings """ - # **************************************************************************** # 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 @@ -9,16 +8,14 @@ Elements of Laurent polynomial rings # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - -from sage.rings.integer cimport Integer from sage.categories.map cimport Map -from sage.structure.element import is_Element, coerce_binop +from sage.structure.element import coerce_binop, parent from sage.structure.factorization import Factorization from sage.misc.derivative import multi_derivative from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.structure.richcmp cimport richcmp, rich_to_bool -from sage.matrix.matrix0 cimport Matrix + cdef class LaurentPolynomial(CommutativeAlgebraElement): """ @@ -30,8 +27,8 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: L.<x,y> = LaurentPolynomialRing(QQ) # indirect doctest - sage: x*y + sage: L.<x,y> = LaurentPolynomialRing(QQ) # indirect doctest # needs sage.modules + sage: x*y # needs sage.modules x*y """ cdef type t = type(self) @@ -113,6 +110,7 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): :: + sage: # needs sage.modules sage: L.<a, b> = LaurentPolynomialRing(QQ) sage: L(42)._integer_(ZZ) 42 @@ -155,6 +153,7 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): :: + sage: # needs sage.modules sage: L.<a, b> = LaurentPolynomialRing(QQ) sage: L(42)._rational_() 42 @@ -183,9 +182,9 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): Check that :trac:`22277` is fixed:: - sage: R.<x, y> = LaurentPolynomialRing(QQ) - sage: a = 2*x^2 + 3*x^3 + 4*x^-1 - sage: a.change_ring(GF(3)) + sage: R.<x, y> = LaurentPolynomialRing(QQ) # needs sage.modules + sage: a = 2*x^2 + 3*x^3 + 4*x^-1 # needs sage.modules + sage: a.change_ring(GF(3)) # needs sage.modules -x^2 + x^-1 """ return self._parent.change_ring(R)(self) @@ -254,35 +253,39 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(9) sage: R.<x> = LaurentPolynomialRing(k) sage: f = x*a + a - sage: f.map_coefficients(lambda a : a + 1) + sage: f.map_coefficients(lambda a: a + 1) (a + 1) + (a + 1)*x sage: R.<x,y> = LaurentPolynomialRing(k, 2) sage: f = x*a + 2*x^3*y*a + a - sage: f.map_coefficients(lambda a : a + 1) + sage: f.map_coefficients(lambda a: a + 1) (2*a + 1)*x^3*y + (a + 1)*x + a + 1 Examples with different base ring:: + sage: # needs sage.modules sage.rings.finite_rings sage: R.<r> = GF(9); S.<s> = GF(81) - sage: h = Hom(R,S)[0]; h + sage: h = Hom(R, S)[0]; h Ring morphism: From: Finite Field in r of size 3^2 To: Finite Field in s of size 3^4 Defn: r |--> 2*s^3 + 2*s^2 + 1 sage: T.<X,Y> = LaurentPolynomialRing(R, 2) - sage: f = r*X+Y + sage: f = r*X + Y sage: g = f.map_coefficients(h); g (2*s^3 + 2*s^2 + 1)*X + Y sage: g.parent() - Multivariate Laurent Polynomial Ring in X, Y over Finite Field in s of size 3^4 + Multivariate Laurent Polynomial Ring in X, Y + over Finite Field in s of size 3^4 sage: h = lambda x: x.trace() sage: g = f.map_coefficients(h); g X - Y sage: g.parent() - Multivariate Laurent Polynomial Ring in X, Y over Finite Field in r of size 3^2 + Multivariate Laurent Polynomial Ring in X, Y + over Finite Field in r of size 3^2 sage: g = f.map_coefficients(h, new_base_ring=GF(3)); g X - Y sage: g.parent() @@ -330,6 +333,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): :: + sage: # needs sage.rings.padics sage: S.<s> = LaurentPolynomialRing(GF(5)) sage: T.<t> = PolynomialRing(pAdicRing(5)) sage: S(t) @@ -362,7 +366,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): # self is that t^n * u: self.__u = f self.__n = n - self.__normalize() + self._normalize() def __reduce__(self): """ @@ -394,8 +398,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p5 = Lx.gen()**3 + 2*Lx.gen()**2 sage: p6 = Lx.gen() >> 2 - sage: for P,x in [(Px, Px.gen()), (Qx, Qx.gen()), (Rx, Rx.gen()), - ....: (Pxy, Pxy.gen(0)), (Paxb, Paxb.gen(1))]: + sage: Pxes = [(Px, Px.gen()), (Qx, Qx.gen()), + ....: (Pxy, Pxy.gen(0)), (Paxb, Paxb.gen(1))] + sage: Pxes += [(Rx, Rx.gen())] + sage: for P, x in Pxes: ....: assert P(p1) == x and parent(P(p1)) is P ....: assert P(p2) == P.zero() and parent(P(p2)) is P ....: assert P(p3) == P.one() and parent(P(p3)) is P @@ -438,7 +444,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): EXAMPLES:: sage: R.<t> = LaurentPolynomialRing(QQ) - sage: (2+t).is_unit() + sage: (2 + t).is_unit() False sage: f = 2*t sage: f.is_unit() @@ -509,6 +515,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): You can specify a map on the base ring:: + sage: # needs sage.rings.number_field sage: Zx.<x> = ZZ[] sage: K.<i> = NumberField(x^2 + 1) sage: cc = K.hom([-i]) @@ -524,7 +531,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): u = u.map_coefficients(base_map) return codomain(u(x) * x**self.__n) - cpdef __normalize(self): + cpdef _normalize(self): r""" A Laurent series is a pair `(u(t), n)`, where either `u = 0` (to some precision) or `u` is a unit. This pair corresponds to @@ -533,7 +540,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): EXAMPLES:: sage: R.<t> = LaurentPolynomialRing(QQ) - sage: elt = t^2 + t^4 # indirect doctest + sage: elt = t^2 + t^4 # indirect doctest sage: elt.polynomial_construction() (t^2 + 1, 2) @@ -571,7 +578,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): X = self._parent.variable_name() atomic_repr = self._parent.base_ring()._repr_option('element_is_atomic') first = True - for n in xrange(m): + for n in range(m): x = v[n] e = n + valuation x = str(x) @@ -604,9 +611,9 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): Verify that :trac:`6656` has been fixed:: - sage: R.<a,b>=PolynomialRing(QQ) - sage: T.<x>=LaurentPolynomialRing(R) - sage: y = a*x+b*x + sage: R.<a,b> = PolynomialRing(QQ) + sage: T.<x> = LaurentPolynomialRing(R) + sage: y = a*x + b*x sage: y._latex_() '\\left(a + b\\right)x' sage: latex(y) @@ -632,7 +639,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): X = self._parent.latex_variable_names()[0] atomic_repr = self._parent.base_ring()._repr_option('element_is_atomic') first = True - for n in xrange(m): + for n in range(m): x = v[n] e = n + valuation x = latex(x) @@ -729,30 +736,34 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: f = -5/t^(10) + 1/3 + t + t^2 - 10/3*t^3; f -5*t^-10 + 1/3 + t + t^2 - 10/3*t^3 - Slicing is deprecated:: + Slicing can be used to truncate Laurent polynomials:: - sage: f[-10:2] - doctest:...: DeprecationWarning: polynomial slicing with a start index is deprecated, use list() and slice the resulting list instead - See https://github.com/sagemath/sage/issues/18940 for details. - -5*t^-10 + 1/3 + t - sage: f[0:] - 1/3 + t + t^2 - 10/3*t^3 sage: f[:3] -5*t^-10 + 1/3 + t + t^2 + + Any other kind of slicing is an error, see :trac:`18940`:: + + sage: f[-10:2] + Traceback (most recent call last): + ... + IndexError: polynomial slicing with a start is not defined + sage: f[-14:5:2] Traceback (most recent call last): ... - NotImplementedError: polynomial slicing with a step is not defined + IndexError: polynomial slicing with a step is not defined """ cdef LaurentPolynomial_univariate ret if isinstance(i, slice): - start = i.start - self.__n if i.start is not None else 0 - stop = i.stop - self.__n if i.stop is not None else self.__u.degree() + 1 - f = self.__u[start:stop:i.step] # deprecation(18940) + start, stop, step = i.start, i.stop, i.step + if start is not None or step is not None: + self.__u[start:stop:step] # error out, see issue #18940 + stop = stop - self.__n if stop is not None else self.__u.degree() + 1 + f = self.__u[:stop] ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = f ret.__n = self.__n - ret.__normalize() + ret._normalize() return ret return self.__u[i - self.__n] @@ -806,13 +817,13 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ EXAMPLES:: + sage: # needs sage.symbolic sage: R.<x> = LaurentPolynomialRing(QQ) sage: f = x^3 + 2/x sage: g = f._symbolic_(SR); g (x^4 + 2)/x sage: g(x=2) 9 - sage: g = SR(f) sage: g(x=2) 9 @@ -821,7 +832,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): characteristic:: sage: R.<w> = LaurentPolynomialRing(GF(7)) - sage: SR(2*w^3 + 1) + sage: SR(2*w^3 + 1) # needs sage.symbolic Traceback (most recent call last): ... TypeError: positive characteristic not allowed in symbolic computations @@ -908,7 +919,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): R = self._parent.base_ring() coeffs = [value] + [R.zero() for _ in range(1,-j)] + self.__u.list() self.__u = self.__u._parent(coeffs) - self.__normalize() + self._normalize() cpdef _add_(self, right_m): """ @@ -961,7 +972,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = <ModuleElement> (f1 + f2) ret.__n = m - ret.__normalize() + ret._normalize() return ret cpdef _sub_(self, right_m): @@ -1001,7 +1012,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = <ModuleElement> (f1 - f2) ret.__n = m - ret.__normalize() + ret._normalize() return ret def degree(self): @@ -1052,7 +1063,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = <ModuleElement> (self.__u * right.__u) ret.__n = self.__n + right.__n - ret.__normalize() + ret._normalize() return ret cpdef _rmul_(self, Element c): @@ -1068,7 +1079,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = <ModuleElement> self.__u._rmul_(c) ret.__n = self.__n - ret.__normalize() + ret._normalize() return ret cpdef _lmul_(self, Element c): @@ -1084,7 +1095,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = <ModuleElement> self.__u._lmul_(c) ret.__n = self.__n - ret.__normalize() + ret._normalize() return ret def is_monomial(self): @@ -1164,7 +1175,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = <ModuleElement> (self.__u // right.__u) ret.__n = self.__n - right.__n - ret.__normalize() + ret._normalize() return ret def shift(self, k): @@ -1276,7 +1287,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): if self.__u.is_unit(): ret.__u = self.__u.inverse_of_unit() ret.__n = -self.__n - ret.__normalize() + ret._normalize() return ret # Enlarge the ring so we can divide by the coefficient R = self._parent.base_ring().fraction_field() @@ -1351,7 +1362,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = self.__u.gcd(b.__u) ret.__n = min(self.__n, b.__n) - ret.__normalize() + ret._normalize() return ret @coerce_binop @@ -1397,11 +1408,11 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ql = <LaurentPolynomial_univariate> self._new_c() ql.__u = <ModuleElement> q ql.__n = self.__n - right.__n - ql.__normalize() + ql._normalize() qr = <LaurentPolynomial_univariate> self._new_c() qr.__u = <ModuleElement> r qr.__n = self.__n - qr.__normalize() + qr._normalize() return ql, qr cpdef _richcmp_(self, right_r, int op): @@ -1508,7 +1519,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = <ModuleElement> self.__u.truncate(n - self.__n) ret.__n = self.__n - ret.__normalize() + ret._normalize() return ret def variable_name(self): @@ -1560,6 +1571,25 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ return (self.__u, self.__n) + def monomial_reduction(self): + """ + Return the decomposition as a polynomial and a power of the variable. + Constructed for compatibility with the multivariate case. + + OUTPUT: + + A tuple ``(u, t^n)`` where ``u`` is the underlying polynomial and ``n`` + is the power of the exponent shift. + + EXAMPLES:: + + sage: R.<x> = LaurentPolynomialRing(QQ) + sage: f = 1/x + x^2 + 3*x^4 + sage: f.monomial_reduction() + (3*x^5 + x^3 + 1, x^-1) + """ + return (self.__u, self._parent.gen(0) ** self.__n) + def is_constant(self): """ Return whether this Laurent polynomial is constant. @@ -1620,6 +1650,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): The answer is dependent of the base ring:: + sage: # needs sage.rings.number_field sage: S.<u> = LaurentPolynomialRing(QQbar) sage: (2 + 4*t + 2*t^2).is_square() False @@ -1746,6 +1777,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): Check that :trac:`28187` is fixed:: + sage: # needs sage.symbolic sage: R.<x> = LaurentPolynomialRing(ZZ) sage: p = 1/x + 1 + x sage: x,y = var("x, y") @@ -1764,7 +1796,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = <ModuleElement> self._parent._R(u) ret.__n = self.__n - ret.__normalize() + ret._normalize() return ret except AttributeError: raise ValueError('cannot differentiate with respect to {}'.format(var)) @@ -1779,7 +1811,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = <ModuleElement> self._parent._R(a) ret.__n = self.__n - 1 - ret.__normalize() + ret._normalize() return ret def integral(self): @@ -1844,7 +1876,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ret = <LaurentPolynomial_univariate> self._new_c() ret.__u = <ModuleElement> u ret.__n = n + 1 - ret.__normalize() + ret._normalize() return ret def __call__(self, *x, **kwds): @@ -1898,7 +1930,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: R.<t> = LaurentPolynomialRing(ZZ) sage: f = 4*t^-7 + 3*t^3 + 2*t^4 + t^-6 - sage: f.factor() + sage: f.factor() # needs sage.libs.pari (t^-7) * (4 + t + 3*t^10 + 2*t^11) """ cdef LaurentPolynomial_univariate u, d @@ -1906,14 +1938,14 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): u = <LaurentPolynomial_univariate> self._new_c() u.__u = pf.unit() u.__n = self.__n - u.__normalize() + u._normalize() f = [] for t in pf: d = <LaurentPolynomial_univariate> self._new_c() d.__u = t[0] d.__n = 0 - d.__normalize() + d._normalize() if d.is_unit(): u *= d ** t[1] else: @@ -1956,1810 +1988,3 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): 0 """ return self.__u[-self.__n] - - -cdef class LaurentPolynomial_mpair(LaurentPolynomial): - """ - Multivariate Laurent polynomials. - """ - def __init__(self, parent, x, mon=None, reduce=True): - """ - Currently, one can only create LaurentPolynomials out of dictionaries - and elements of the base ring. - - INPUT: - - - ``parent`` -- a SageMath parent - - - ``x`` -- an element or dictionary or anything the underlying - polynomial ring accepts - - - ``mon`` -- (default: ``None``) a tuple specifying the shift - in the exponents - - - ``reduce`` -- (default: ``True``) a boolean - - EXAMPLES:: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: f = L({(-1,-1):1}); f - w^-1*z^-1 - sage: f = L({(1,1):1}); f - w*z - sage: f = L({(-1,-1):1, (1,3):4}); f - 4*w*z^3 + w^-1*z^-1 - sage: L(1/2) - 1/2 - - TESTS: - - Check that :trac:`19538` is fixed:: - - sage: R = LaurentPolynomialRing(QQ,'x2,x0') - sage: S = LaurentPolynomialRing(QQ,'x',3) - sage: f = S.coerce_map_from(R) - sage: f(R.gen(0) + R.gen(1)^2) - x0^2 + x2 - sage: _.parent() - Multivariate Laurent Polynomial Ring in x0, x1, x2 over Rational Field - - :: - - sage: from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_mpair - sage: LaurentPolynomial_mpair(L, {(1,2): 1/42}, mon=(-3, -3)) - 1/42*w^-2*z^-1 - - :trac:`22398`:: - - sage: LQ = LaurentPolynomialRing(QQ, 'x0, x1, x2, y0, y1, y2, y3, y4, y5') - sage: LZ = LaurentPolynomialRing(ZZ, 'x0, x1, x2, y0, y1, y2, y3, y4, y5') - sage: LQ.inject_variables() - Defining x0, x1, x2, y0, y1, y2, y3, y4, y5 - sage: x2^-1*y0*y1*y2*y3*y4*y5 + x1^-1*x2^-1*y0*y1*y3*y4 + x0^-1 in LZ - True - sage: x2^-1*y0*y1*y2*y3*y4*y5 + x1^-1*x2^-1*y0*y1*y3*y4 + x0^-1*x1^-1*y0*y3 + x0^-1 in LZ - True - - Check that input is not modified:: - - sage: LQ.<x,y> = LaurentPolynomialRing(QQ) - sage: D = {(-1, 1): 1} - sage: k = tuple(D)[0] - sage: v = D[k] - sage: type(k), type(v) - (<... 'tuple'>, <class 'sage.rings.integer.Integer'>) - sage: LQ(D) - x^-1*y - sage: tuple(D)[0] is k - True - sage: D[k] is v - True - """ - if isinstance(x, PolyDict): - x = x.dict() - if mon is not None: - if isinstance(mon, ETuple): - self._mon = mon - else: - self._mon = ETuple(mon) - else: - if isinstance(x, dict): - self._mon = ETuple({}, int(parent.ngens())) - D = {} - for k, x_k in x.iteritems(): # ETuple-ize keys, set _mon - if not isinstance(k, (tuple, ETuple)) or len(k) != parent.ngens(): - self._mon = ETuple({}, int(parent.ngens())) - break - if isinstance(k, tuple): - k = ETuple(k) - D[k] = x_k - self._mon = self._mon.emin(k) # point-wise min of _mon and k - else: - x = D - if not self._mon.is_constant(): # factor out _mon - x = {k.esub(self._mon): x_k for k, x_k in x.iteritems()} - elif (isinstance(x, LaurentPolynomial_mpair) and - parent.variable_names() == x.parent().variable_names()): - self._mon = (<LaurentPolynomial_mpair>x)._mon - x = (<LaurentPolynomial_mpair>x)._poly - else: # since x should coerce into parent, _mon should be (0,...,0) - self._mon = ETuple({}, int(parent.ngens())) - self._poly = parent._R(x) - CommutativeAlgebraElement.__init__(self, parent) - - def __reduce__(self): - """ - TESTS:: - - sage: R = LaurentPolynomialRing(QQ,2,'x') - sage: R.<x1,x2> = LaurentPolynomialRing(QQ) - sage: loads(dumps(x1)) == x1 # indirect doctest - True - sage: z = x1/x2 - sage: loads(dumps(z)) == z - True - """ - return self._parent, (self._poly, self._mon) - - def __hash__(self): - r""" - TESTS: - - Test that the hash is non-constant (see also :trac:`27914`):: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: len({hash(w^i*z^j) for i in [-2..2] for j in [-2..2]}) - 25 - - Check that :trac:`20490` is fixed:: - - sage: R.<a,b> = LaurentPolynomialRing(ZZ) - sage: p = a*~a - sage: p._fraction_pair() - (a, a) - sage: p == R.one() - True - sage: hash(p) - 1 - - Check that :trac:`23864` is fixed (compatibility with integers, rationals - and polynomial rings):: - - sage: L = LaurentPolynomialRing(QQ, 'x0,x1,x2') - sage: hash(L.zero()) - 0 - sage: hash(L.one()) - 1 - sage: hash(-L.one()) - -2 - sage: hash(L(1/2)) == hash(1/2) - True - - sage: R = PolynomialRing(QQ, 'x0,x1,x2') - sage: x0,x1,x2 = R.gens() - sage: hash(x0) == hash(L(x0)) - True - sage: hash(1 - 7*x0 + x1*x2) == hash(L(1 - 7*x0 + x1*x2)) - True - - Check that :trac:`27914` is fixed:: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: Lw = LaurentPolynomialRing(QQ, 'w') - sage: Lz = LaurentPolynomialRing(QQ, 'z') - sage: all(hash(w^k) == hash(Lw(w^k)) - ....: and hash(z^k) == hash(Lz(z^k)) for k in (-5..5)) - True - sage: p = w^-1 + 2 + w - sage: hash(p) == hash(Lw(p)) - True - """ - # we reimplement the hash from multipolynomial to handle negative exponents - # (see multi_polynomial.pyx) - cdef long result = 0 - cdef long exponent - cdef list var_name_hash = [hash(v) for v in self._parent.variable_names()] - cdef int p - cdef int n = len(var_name_hash) - cdef long c_hash - for m, c in self._poly.iterator_exp_coeff(): - c_hash = hash(c) - if c_hash != 0: - for p in range(n): - exponent = m[p] + self._mon[p] - if exponent > 0: - c_hash = (1000003 * c_hash) ^ var_name_hash[p] - c_hash = (1000003 * c_hash) ^ exponent - elif exponent < 0: - c_hash = (1000003 * c_hash) ^ var_name_hash[p] - c_hash = (700005 * c_hash) ^ exponent - result += c_hash - - return result - - def _im_gens_(self, codomain, im_gens, base_map=None): - """ - Return the image of ``self`` under the morphism defined by - ``im_gens`` in ``codomain``. - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(ZZ) - sage: M.<u,v> = LaurentPolynomialRing(ZZ) - sage: phi = L.hom([u,v]) - sage: phi(x^2*~y -5*y**3) # indirect doctest - -5*v^3 + u^2*v^-1 - - TESTS: - - check compatibility with :trac:`26105`:: - - sage: F.<t> = GF(4) - sage: LF.<a,b> = LaurentPolynomialRing(F) - sage: rho = LF.hom([b,a], base_map=F.frobenius_endomorphism()) - sage: s = t*~a + b +~t*(b**-3)*a**2; rs = rho(s); rs - a + (t + 1)*b^-1 + t*a^-3*b^2 - sage: s == rho(rs) - True - """ - p = self._poly - m = self._mon - if base_map is not None: - p = p.map_coefficients(base_map) - from sage.misc.misc_c import prod - return codomain(p(im_gens) * prod(ig**m[im_gens.index(ig)] for ig in im_gens)) - - cdef _normalize(self, i=None): - r""" - Remove the common monomials from ``self._poly`` and store - them in ``self._mon``. - - INPUT: - - - ``i`` -- an integer - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ) - sage: f = x*y + 2*y*x^2 + y # indirect doctest - sage: f.factor() # Notice the y has been factored out. - (y) * (2*x^2 + x + 1) - - Check that :trac:`23864` has been fixed:: - - sage: hash(L.zero()) - 0 - """ - if not self._poly: - self._mon = ETuple({}, int(self._parent.ngens())) - return - - #cdef dict D = <dict> self._poly._mpoly_dict_recursive( - # <tuple> self._parent.variable_names(), - # self._parent.base_ring() - # ) - cdef dict D = <dict> self._poly.dict() - - cdef ETuple e - if i is None: - e = None - for k in D: - if e is None: - e = <ETuple> k - else: - e = e.emin(k) - if not e.is_constant(): - self._poly = <ModuleElement> (self._poly // self._poly._parent({e: 1})) - self._mon = self._mon.eadd(e) - else: - e = None - for k in D: - if e is None or k[i] < e: - e = <ETuple> k[i] - if e > 0: - self._poly = <ModuleElement> (self._poly // self._poly._parent.gen(i)) - self._mon = self._mon.eadd_p(e, i) - - cdef _compute_polydict(self): - """ - EXAMPLES:: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: a = w^2*z^-1 +3 - sage: a.dict() # indirect doctest - {(0, 0): 3, (2, -1): 1} - """ - #cdef dict D = <dict> self._poly._mpoly_dict_recursive(self._parent.variable_names(), - # self._parent.base_ring()) - cdef dict D = <dict> self._poly.dict() - cdef dict DD - if self._mon.is_constant(): - self._prod = PolyDict(D, force_etuples=False) - return - DD = {} - for k in D: - DD[k.eadd(self._mon)] = D[k] - self._prod = PolyDict(DD, force_etuples=False) - - def is_unit(self): - """ - Return ``True`` if ``self`` is a unit. - - The ground ring is assumed to be an integral domain. - - This means that the Laurent polynomial is a monomial - with unit coefficient. - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ) - sage: (x*y/2).is_unit() - True - sage: (x + y).is_unit() - False - sage: (L.zero()).is_unit() - False - sage: (L.one()).is_unit() - True - - sage: L.<x,y> = LaurentPolynomialRing(ZZ) - sage: (2*x*y).is_unit() - False - """ - coeffs = self.coefficients() - if len(coeffs) != 1: - return False - return coeffs[0].is_unit() - - def _repr_(self): - """ - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ) - sage: f = x^2 + x*y/2 + 2*y^-1 - sage: f._repr_() - 'x^2 + 1/2*x*y + 2*y^-1' - """ - if self._prod is None: - self._compute_polydict() - try: - key = self.parent().term_order().sortkey - except AttributeError: - key = None - atomic = self.parent().base_ring()._repr_option('element_is_atomic') - return self._prod.poly_repr(self.parent().variable_names(), - atomic_coefficients=atomic, sortkey=key) - - def _latex_(self): - r""" - EXAMPLES:: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: a = w^2*z^-1+3; a - w^2*z^-1 + 3 - sage: latex(a) - w^{2} z^{-1} + 3 - - TESTS:: - - sage: L.<lambda2, y2> = LaurentPolynomialRing(QQ) - sage: latex(1/lambda2 + y2^(-3)) - \lambda_{2}^{-1} + y_{2}^{-3} - """ - if self._prod is None: - self._compute_polydict() - try: - key = self.parent().term_order().sortkey - except AttributeError: - key = None - atomic = self.parent().base_ring()._repr_option('element_is_atomic') - return self._prod.latex(self.parent().latex_variable_names(), - atomic_coefficients=atomic, sortkey=key) - - cpdef long number_of_terms(self) except -1: - """ - Return the number of non-zero coefficients of ``self``. - - Also called weight, hamming weight or sparsity. - - EXAMPLES:: - - sage: R.<x, y> = LaurentPolynomialRing(ZZ) - sage: f = x^3 - y - sage: f.number_of_terms() - 2 - sage: R(0).number_of_terms() - 0 - sage: f = (x+1/y)^100 - sage: f.number_of_terms() - 101 - - The method :meth:`hamming_weight` is an alias:: - - sage: f.hamming_weight() - 101 - """ - return self._poly.number_of_terms() - - def __invert__(LaurentPolynomial_mpair self): - """ - Return the inverse of ``self``. - - This treats monomials specially so they remain Laurent - polynomials; the inverse of any other polynomial is an element - of the rational function field. - - TESTS:: - - sage: L.<x,y> = LaurentPolynomialRing(ZZ) - sage: f = ~x - sage: parent(f) - Multivariate Laurent Polynomial Ring in x, y over Integer Ring - sage: parent(f.coefficients()[0]) is parent(f).base_ring() - True - sage: g = ~(2*x) - sage: parent(g) - Multivariate Laurent Polynomial Ring in x, y over Rational Field - sage: parent(g.coefficients()[0]) is parent(g).base_ring() - True - """ - cdef ETuple e - if self._poly.is_term(): - (e, c), = self.dict().items() - e = e.emul(-1) - P = self._parent - try: - c = c.inverse_of_unit() - except (AttributeError, ZeroDivisionError, ArithmeticError): - c = ~c - if c.parent() is not P.base_ring(): - P = P.change_ring(c.parent()) - return P({e: c}) - return super().__invert__() - - def __pow__(LaurentPolynomial_mpair self, n, m): - """ - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ) - sage: f = x + y - sage: f^2 - x^2 + 2*x*y + y^2 - sage: f^(-1) - 1/(x + y) - - TESTS: - - Check that :trac:`2952` is fixed:: - - sage: R.<q> = QQ[] - sage: L.<x,y,z> = LaurentPolynomialRing(R) - sage: f = (x+y+z^-1)^2 - sage: f.substitute(z=1) - x^2 + 2*x*y + y^2 + 2*x + 2*y + 1 - """ - cdef LaurentPolynomial_mpair ans - if n < 0: - return ~(self ** -n) - ans = self._new_c() - ans._poly = self._poly ** n - ans._mon = self._mon.emul(n) - return ans - - def __getitem__(self, n): - r""" - Return the coefficient of `x^n = x_1^{n_1} \cdots x_k^{n_k}` where - `n` is a tuple of length `k` and `k` is the number of variables. - - If the number of inputs is not equal to the number of variables, this - raises a ``TypeError``. - - EXAMPLES:: - - sage: P.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + x*z; f - -x^6 + x*z - 7*x^-2*y^3 + 5*x^-2*y + x^-3*y^2 - sage: f[6,0,0] - -1 - sage: f[-2,3,0] - -7 - sage: f[-1,4,2] - 0 - sage: f[1,0,1] - 1 - sage: f[6] - Traceback (most recent call last): - ... - TypeError: must have exactly 3 inputs - sage: f[6,0] - Traceback (most recent call last): - ... - TypeError: must have exactly 3 inputs - sage: f[6,0,0,0] - Traceback (most recent call last): - ... - TypeError: must have exactly 3 inputs - """ - if isinstance(n, slice): - raise TypeError("multivariate Laurent polynomials are not iterable") - if not isinstance(n, tuple) or len(n) != self._parent.ngens(): - raise TypeError("must have exactly %s inputs" % - self.parent().ngens()) - cdef ETuple t = ETuple(n) - if self._prod is None: - self._compute_polydict() - try: - return self._prod[t] - except KeyError: - return self._parent.base_ring().zero() - - def __iter__(self): - """ - Iterate through all terms by returning a list of the coefficient and - the corresponding monomial. - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 - sage: sorted(f) # indirect doctest - [(-7, x^-2*y^3), (-1, x^6), (1, x^-3*y^2), (5, x^-2*y)] - """ - P = self._parent - one = P._R.one() - if self._mon.is_constant(): - for exp, coeff in self._poly.iterator_exp_coeff(): - yield (coeff, P.element_class(P, one, exp)) - else: - for exp, coeff in self._poly.iterator_exp_coeff(): - yield (coeff, P.element_class(P, one, exp.eadd(self._mon))) - - def iterator_exp_coeff(self): - """ - Iterate over ``self`` as pairs of (ETuple, coefficient). - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 - sage: list(f.iterator_exp_coeff()) - [((6, 0), -1), ((-2, 3), -7), ((-2, 1), 5), ((-3, 2), 1)] - """ - for exp, coeff in self._poly.iterator_exp_coeff(): - yield (exp.eadd(self._mon), coeff) - - def monomials(self): - """ - Return the list of monomials in ``self``. - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 - sage: sorted(f.monomials()) - [x^-3*y^2, x^-2*y, x^-2*y^3, x^6] - """ - return [mon for coeff, mon in self] - - def monomial_coefficient(self, mon): - """ - Return the coefficient in the base ring of the monomial ``mon`` in - ``self``, where ``mon`` must have the same parent as ``self``. - - This function contrasts with the function :meth:`coefficient()` - which returns the coefficient of a monomial viewing this - polynomial in a polynomial ring over a base ring having fewer - variables. - - INPUT: - - - ``mon`` -- a monomial - - .. SEEALSO:: - - For coefficients in a base ring of fewer variables, see - :meth:`coefficient()`. - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 - sage: f.monomial_coefficient(x^-2*y^3) - -7 - sage: f.monomial_coefficient(x^2) - 0 - - TESTS:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = y^2 * x^-2 - sage: f.monomial_coefficient(x + y) - Traceback (most recent call last): - ... - ValueError: input must be a monomial - """ - if mon.parent() != self._parent: - raise TypeError("input must have the same parent") - cdef LaurentPolynomial_mpair m = <LaurentPolynomial_mpair> mon - if m._prod is None: - m._compute_polydict() - if len(m._prod) != 1: - raise ValueError("input must be a monomial") - if self._prod is None: - self._compute_polydict() - c = self._prod.monomial_coefficient(m._prod.dict()) - return self._parent.base_ring()(c) - - def constant_coefficient(self): - """ - Return the constant coefficient of ``self``. - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^2 + 5*x*y)*x^-3; f - -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 - sage: f.constant_coefficient() - 0 - sage: f = (x^3 + 2*x^-2*y+y^3)*y^-3; f - x^3*y^-3 + 1 + 2*x^-2*y^-2 - sage: f.constant_coefficient() - 1 - """ - return self[(0,)*self._parent.ngens()] - - def coefficient(self, mon): - r""" - Return the coefficient of ``mon`` in ``self``, where ``mon`` must - have the same parent as ``self``. - - The coefficient is defined as follows. If `f` is this polynomial, then - the coefficient `c_m` is sum: - - .. MATH:: - - c_m := \sum_T \frac{T}{m} - - where the sum is over terms `T` in `f` that are exactly divisible - by `m`. - - A monomial `m(x,y)` 'exactly divides' `f(x,y)` if `m(x,y) | f(x,y)` - and neither `x \cdot m(x,y)` nor `y \cdot m(x,y)` divides `f(x,y)`. - - INPUT: - - - ``mon`` -- a monomial - - OUTPUT: - - Element of the parent of ``self``. - - .. NOTE:: - - To get the constant coefficient, call - :meth:`constant_coefficient()`. - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - - The coefficient returned is an element of the parent of ``self``; in - this case, ``P``. :: - - sage: f = 2 * x * y - sage: c = f.coefficient(x*y); c - 2 - sage: c.parent() - Multivariate Laurent Polynomial Ring in x, y over Rational Field - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^2 + 5*x*y)*x^-3; f - -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 - sage: f.coefficient(y) - 5*x^-2 - sage: f.coefficient(y^2) - -7*x^-2 + x^-3 - sage: f.coefficient(x*y) - 0 - sage: f.coefficient(x^-2) - -7*y^2 + 5*y - sage: f.coefficient(x^-2*y^2) - -7 - sage: f.coefficient(1) - -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 - """ - if mon.parent() is not self._parent: - mon = self._parent(mon) - cdef LaurentPolynomial_mpair m = <LaurentPolynomial_mpair> mon - if self._prod is None: - self._compute_polydict() - if m._prod is None: - m._compute_polydict() - return self._parent(self._prod.coefficient(m.dict())) - - def coefficients(self): - """ - Return the nonzero coefficients of ``self`` in a list. - - The returned list is decreasingly ordered by the term ordering - of ``self.parent()``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ,order='degrevlex') - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.coefficients() - [4, 3, 2, 1] - sage: L.<x,y,z> = LaurentPolynomialRing(QQ,order='lex') - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.coefficients() - [4, 1, 2, 3] - """ - return self._poly.coefficients() - - def variables(self, sort=True): - """ - Return a tuple of all variables occurring in ``self``. - - INPUT: - - - ``sort`` -- specifies whether the indices shall be sorted - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.variables() - (z, y, x) - sage: f.variables(sort=False) #random - (y, z, x) - """ - cdef dict d = self.dict() - cdef tuple g = self._parent.gens() - cdef Py_ssize_t nvars = len(g) - cdef set vars = set() - for k in d: - vars.update(k.nonzero_positions()) - if len(vars) == nvars: - break - cdef list v = [g[i] for i in vars] - if sort: - v.sort() - return tuple(v) - - cpdef dict dict(self): - """ - Return ``self`` represented as a ``dict``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: sorted(f.dict().items()) - [((3, 1, 0), 3), ((4, 0, -2), 2), ((6, -7, 0), 1), ((7, 0, -1), 4)] - """ - if self._prod is None: - self._compute_polydict() - return <dict> self._prod.dict() - - def _fraction_pair(self): - """ - Return one representation of ``self`` as a pair - ``(numerator, denominator)``. - - Here both the numerator and the denominator are polynomials. - - This is used for coercion into the fraction field. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f._fraction_pair() - (4*x^7*y^7*z + 3*x^3*y^8*z^2 + 2*x^4*y^7 + x^6*z^2, y^7*z^2) - """ - ring = self._parent._R - numer = self._poly - denom = ring.one() - var = ring.gens() - for i, j in enumerate(self._mon): - if j > 0: - numer *= var[i] ** j - else: - denom *= var[i] ** (-j) - return (numer, denom) - - cpdef _add_(self, _right): - """ - Return the Laurent polynomial ``self + right``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: g = y + z - sage: f + g - x + y + z + y^-1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair>_right - ans._mon, a, b = self._mon.combine_to_positives(right._mon) - if not a.is_constant(): - ans._poly = self._poly * self._poly._parent({a: 1}) - else: - ans._poly = self._poly - if not b.is_constant(): - ans._poly += right._poly * self._poly._parent({b: 1}) - else: - ans._poly += right._poly - return ans - - cpdef _sub_(self, _right): - """ - Return the Laurent polynomial ``self - right``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: g = y + z + x - sage: f - g - -y - z + y^-1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair>_right - cdef ETuple a, b - ans._mon, a, b = self._mon.combine_to_positives(right._mon) - if not a.is_constant(): - ans._poly = self._poly * self._poly._parent({a: 1}) - else: - ans._poly = self._poly - if not b.is_constant(): - ans._poly -= right._poly * self._poly._parent({b: 1}) - else: - ans._poly -= right._poly - return ans - - cpdef _div_(self, rhs): - """ - Return the division of ``self`` by ``rhs``. - - If the denominator is not a unit, - the result will be given in the fraction field. - - EXAMPLES:: - - sage: R.<s,q,t> = LaurentPolynomialRing(QQ) - sage: 1/s - s^-1 - sage: 1/(s*q) - s^-1*q^-1 - sage: 1/(s+q) - 1/(s + q) - sage: (1/(s+q)).parent() - Fraction Field of Multivariate Polynomial Ring in s, q, t over Rational Field - sage: (1/(s*q)).parent() - Multivariate Laurent Polynomial Ring in s, q, t over Rational Field - sage: (s+q)/(q^2*t^(-2)) - s*q^-2*t^2 + q^-1*t^2 - """ - cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair> rhs - if right.is_zero(): - raise ZeroDivisionError - if right._poly.is_term(): - return self * ~right - else: - return RingElement._div_(self, rhs) - - def is_monomial(self): - """ - Return ``True`` if ``self`` is a monomial. - - EXAMPLES:: - - sage: k.<y,z> = LaurentPolynomialRing(QQ) - sage: z.is_monomial() - True - sage: k(1).is_monomial() - True - sage: (z+1).is_monomial() - False - sage: (z^-2909).is_monomial() - True - sage: (38*z^-2909).is_monomial() - False - """ - return self._poly.is_monomial() - - cpdef _neg_(self): - """ - Return ``-self``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: -f - -x - y^-1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - ans._mon = self._mon - ans._poly = -self._poly - return ans - - cpdef _lmul_(self, Element right): - """ - Return ``self * right`` where ``right`` is in ``self``'s base ring. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: f*(1/2) - 1/2*x + 1/2*y^-1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - ans._mon = self._mon - ans._poly = self._poly * right - return ans - - cpdef _rmul_(self, Element left): - """ - Return ``left * self`` where ``left`` is in ``self``'s base ring. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: (1/2)*f - 1/2*x + 1/2*y^-1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - ans._mon = self._mon - ans._poly = left * self._poly - return ans - - cpdef _mul_(self, right): - """ - Return ``self * right``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: g = y + z - sage: f*g - x*y + x*z + 1 + y^-1*z - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - ans._mon = self._mon.eadd((<LaurentPolynomial_mpair>right)._mon) - ans._poly = self._poly * (<LaurentPolynomial_mpair>right)._poly - return ans - - cpdef _floordiv_(self, right): - """ - Perform division with remainder and return the quotient. - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ) - sage: f = x^3 + y^-3 - sage: g = y + x - sage: f // g - x^5*y^-3 - x^4*y^-2 + x^3*y^-1 - - sage: h = x + y^(-1) - sage: f // h - x^2 - x*y^-1 + y^-2 - sage: h * (f // h) == f - True - sage: f // 1 - x^3 + y^-3 - sage: 1 // f - 0 - - TESTS: - - Check that :trac:`19357` is fixed:: - - sage: x // y - x*y^-1 - - Check that :trac:`21999` is fixed:: - - sage: L.<a,b> = LaurentPolynomialRing(QQbar) - sage: (a+a*b) // a - b + 1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - cdef LaurentPolynomial_mpair rightl = <LaurentPolynomial_mpair> right - self._normalize() - rightl._normalize() - ans._mon = self._mon.esub(rightl._mon) - ans._poly = self._poly // rightl._poly - return ans - - @coerce_binop - def quo_rem(self, right): - """ - Divide this Laurent polynomial by ``right`` and return a quotient and - a remainder. - - INPUT: - - - ``right`` -- a Laurent polynomial - - OUTPUT: - - A pair of Laurent polynomials. - - EXAMPLES:: - - sage: R.<s, t> = LaurentPolynomialRing(QQ) - sage: (s^2-t^2).quo_rem(s-t) - (s + t, 0) - sage: (s^-2-t^2).quo_rem(s-t) - (s + t, -s^2 + s^-2) - sage: (s^-2-t^2).quo_rem(s^-1-t) - (t + s^-1, 0) - - TESTS: - - Verify that :trac:`31257` is fixed:: - - sage: R.<x,y> = LaurentPolynomialRing(QQ) - sage: q, r = (1/x).quo_rem(y) - sage: q, r - (x^-1*y^-1, 0) - sage: q*y + r == 1/x - True - sage: q,r = (x^-2 - y^2).quo_rem(x - y) - sage: q*(x - y) + r == x^-2 - y^2 - True - """ - # make copies of self and right so that the input can be normalized - # without affecting the objects that were passed to the method - cdef LaurentPolynomial_mpair selfl = self._new_c() - selfl._poly = self._poly - selfl._mon = self._mon - cdef LaurentPolynomial_mpair rightl = self._new_c() - rightl._poly = (<LaurentPolynomial_mpair> right)._poly - rightl._mon = (<LaurentPolynomial_mpair> right)._mon - - selfl._normalize() - rightl._normalize() - q, r = selfl._poly.quo_rem(rightl._poly) - ql = LaurentPolynomial_mpair(self._parent, q, - mon=selfl._mon.esub(rightl._mon)) - rl = LaurentPolynomial_mpair(self._parent, r, - mon=selfl._mon) - ql._normalize() - rl._normalize() - return (ql, rl) - - cpdef _richcmp_(self, right, int op): - """ - Compare two polynomials in a `LaurentPolynomialRing` based on the term - order from the parent ring. If the parent ring does not specify a term - order then only comparison by equality is supported. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: g = y + z - sage: f == f - True - sage: f == g - False - sage: f == 2 - False - """ - if self._prod is None: - self._compute_polydict() - if (<LaurentPolynomial_mpair> right)._prod is None: - (<LaurentPolynomial_mpair> right)._compute_polydict() - - try: - sortkey = self._parent.term_order().sortkey - except AttributeError: - sortkey = None - - return self._prod.rich_compare((<LaurentPolynomial_mpair>right)._prod, - op, sortkey) - - def exponents(self): - """ - Return a list of the exponents of ``self``. - - EXAMPLES:: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: a = w^2*z^-1+3; a - w^2*z^-1 + 3 - sage: e = a.exponents() - sage: e.sort(); e - [(0, 0), (2, -1)] - - """ - return [a.eadd(self._mon) for a in self._poly.exponents()] - - def degree(self, x=None): - """ - Return the degree of ``x`` in ``self``. - - EXAMPLES:: - - sage: R.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.degree(x) - 7 - sage: f.degree(y) - 1 - sage: f.degree(z) - 0 - """ - if not x: - return self._poly.total_degree() + sum(self._mon) - - cdef tuple g = <tuple> self._parent.gens() - cdef Py_ssize_t i - cdef bint no_generator_found = True - for i in range(len(g)): - if g[i] is x: - no_generator_found = False - break - if no_generator_found: - raise TypeError("x must be a generator of parent") - return self._poly.degree(self._parent._R.gens()[i]) + self._mon[i] - - def has_inverse_of(self, i): - """ - INPUT: - - - ``i`` -- The index of a generator of ``self.parent()`` - - OUTPUT: - - Returns True if self contains a monomial including the inverse of - ``self.parent().gen(i)``, False otherwise. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.has_inverse_of(0) - False - sage: f.has_inverse_of(1) - True - sage: f.has_inverse_of(2) - True - """ - if (not isinstance(i, (int, Integer))) or (i < 0) or (i >= self._parent.ngens()): - raise TypeError("argument is not the index of a generator") - if self._mon[i] < 0: - self._normalize(i) - if self._mon[i] < 0: - return True - return False - return False - - def has_any_inverse(self): - """ - Returns True if self contains any monomials with a negative exponent, False otherwise. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.has_any_inverse() - True - sage: g = x^2 + y^2 - sage: g.has_any_inverse() - False - """ - for m in self._mon.nonzero_values(sort=False): - if m < 0: - return True - return False - - def __call__(self, *x, **kwds): - """ - Compute value of ``self`` at ``x``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + 2*y + 3*z - sage: f(1,1,1) - 6 - sage: f = x^-1 + y + z - sage: f(0,1,1) - Traceback (most recent call last): - ... - ZeroDivisionError - - TESTS:: - - sage: f = x + 2*y + 3*z - sage: f(2) - Traceback (most recent call last): - ... - TypeError: number of arguments does not match the number of generators in parent - sage: f(2,0) - Traceback (most recent call last): - ... - TypeError: number of arguments does not match the number of generators in parent - sage: f( (1,1,1) ) - 6 - """ - if kwds: - f = self.subs(**kwds) - if x: # More than 1 non-keyword argument - return f(*x) - else: - return f - - cdef int l = len(x) - - if l == 1 and isinstance(x[0], (tuple, list)): - x = x[0] - l = len(x) - - if l != self._parent.ngens(): - raise TypeError("number of arguments does not match the number" - " of generators in parent") - - #Check to make sure that we aren't dividing by zero - cdef Py_ssize_t m - for m in range(l): - if x[m] == 0: - if self.has_inverse_of(m): - raise ZeroDivisionError - - ans = self._poly(*x) - if ans: - for m in self._mon.nonzero_positions(): - ans *= x[m]**self._mon[m] - - return ans - - def subs(self, in_dict=None, **kwds): - """ - Substitute some variables in this Laurent polynomial. - - Variable/value pairs for the substitution may be given - as a dictionary or via keyword-value pairs. If both are - present, the latter take precedence. - - INPUT: - - - ``in_dict`` -- dictionary (optional) - - - ``**kwargs`` -- keyword arguments - - OUTPUT: - - A Laurent polynomial. - - EXAMPLES:: - - sage: L.<x, y, z> = LaurentPolynomialRing(QQ) - sage: f = x + 2*y + 3*z - sage: f.subs(x=1) - 2*y + 3*z + 1 - sage: f.subs(y=1) - x + 3*z + 2 - sage: f.subs(z=1) - x + 2*y + 3 - sage: f.subs(x=1, y=1, z=1) - 6 - - sage: f = x^-1 - sage: f.subs(x=2) - 1/2 - sage: f.subs({x: 2}) - 1/2 - - sage: f = x + 2*y + 3*z - sage: f.subs({x: 1, y: 1, z: 1}) - 6 - sage: f.substitute(x=1, y=1, z=1) - 6 - - TESTS:: - - sage: f = x + 2*y + 3*z - sage: f(q=10) - x + 2*y + 3*z - - sage: x.subs({x: 2}, x=1) - 1 - """ - cdef list variables = list(self._parent.gens()) - cdef Py_ssize_t i - for i in range(len(variables)): - if str(variables[i]) in kwds: - variables[i] = kwds[str(variables[i])] - elif in_dict and variables[i] in in_dict: - variables[i] = in_dict[variables[i]] - return self(tuple(variables)) - - def is_constant(self): - r""" - Return whether this Laurent polynomial is constant. - - EXAMPLES:: - - sage: L.<a, b> = LaurentPolynomialRing(QQ) - sage: L(0).is_constant() - True - sage: L(42).is_constant() - True - sage: a.is_constant() - False - sage: (1/b).is_constant() - False - """ - return (self._mon == ETuple({}, int(self._parent.ngens())) and - self._poly.is_constant()) - - def _symbolic_(self, R): - """ - EXAMPLES:: - - sage: R.<x,y> = LaurentPolynomialRing(QQ) - sage: f = x^3 + y/x - sage: g = f._symbolic_(SR); g - (x^4 + y)/x - sage: g(x=2,y=2) - 9 - - sage: g = SR(f) - sage: g(x=2,y=2) - 9 - """ - d = {repr(g): R.var(g) for g in self._parent.gens()} - return self.subs(**d) - - def derivative(self, *args): - r""" - The formal derivative of this Laurent polynomial, with respect - to variables supplied in args. - - Multiple variables and iteration counts may be supplied; see - documentation for the global :func:`derivative` function for more - details. - - .. SEEALSO:: - - :meth:`_derivative` - - EXAMPLES:: - - sage: R = LaurentPolynomialRing(ZZ,'x, y') - sage: x, y = R.gens() - sage: t = x**4*y+x*y+y+x**(-1)+y**(-3) - sage: t.derivative(x, x) - 12*x^2*y + 2*x^-3 - sage: t.derivative(y, 2) - 12*y^-5 - """ - return multi_derivative(self, args) - - # add .diff(), .differentiate() as aliases for .derivative() - diff = differentiate = derivative - - def _derivative(self, var=None): - """ - Computes formal derivative of this Laurent polynomial with - respect to the given variable. - - If var is among the generators of this ring, the derivative - is with respect to the generator. Otherwise, ``_derivative(var)`` is called - recursively for each coefficient of this polynomial. - - .. SEEALSO:: :meth:`derivative` - - EXAMPLES:: - - sage: R = LaurentPolynomialRing(ZZ,'x, y') - sage: x, y = R.gens() - sage: t = x**4*y+x*y+y+x**(-1)+y**(-3) - sage: t._derivative(x) - 4*x^3*y + y - x^-2 - sage: t._derivative(y) - x^4 + x + 1 - 3*y^-4 - - sage: R = LaurentPolynomialRing(QQ['z'],'x') - sage: z = R.base_ring().gen() - sage: x = R.gen() - sage: t = 33*z*x**4+x**(-1) - sage: t._derivative(z) - 33*x^4 - sage: t._derivative(x) - -x^-2 + 132*z*x^3 - """ - if var is None: - raise ValueError("must specify which variable to differentiate " - "with respect to") - P = self._parent - cdef list gens = list(P.gens()) - - # check if var is one of the generators - try: - index = gens.index(var) - except ValueError: - # call _derivative() recursively on coefficients - return P({m: c._derivative(var) - for (m, c) in self.dict().iteritems()}) - - # compute formal derivative with respect to generator - cdef dict d = {} - for m, c in self.dict().iteritems(): - if m[index] != 0: - new_m = [u for u in m] - new_m[index] += -1 - d[ETuple(new_m)] = m[index] * c - return P(d) - - def is_univariate(self): - """ - Return ``True`` if this is a univariate or constant Laurent polynomial, - and ``False`` otherwise. - - EXAMPLES:: - - sage: R.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = (x^3 + y^-3)*z - sage: f.is_univariate() - False - sage: g = f(1,y,4) - sage: g.is_univariate() - True - sage: R(1).is_univariate() - True - """ - return len(self.variables()) < 2 - - def univariate_polynomial(self, R=None): - """ - Returns a univariate polynomial associated to this - multivariate polynomial. - - INPUT: - - - ``R`` - (default: ``None``) a univariate Laurent polynomial ring - - If this polynomial is not in at most one variable, then a - ``ValueError`` exception is raised. The new polynomial is over - the same base ring as the given ``LaurentPolynomial`` and in the - variable ``x`` if no ring ``R`` is provided. - - EXAMPLES:: - - sage: R.<x, y> = LaurentPolynomialRing(ZZ) - sage: f = 3*x^2 - 2*y^-1 + 7*x^2*y^2 + 5 - sage: f.univariate_polynomial() - Traceback (most recent call last): - ... - TypeError: polynomial must involve at most one variable - sage: g = f(10,y); g - 700*y^2 + 305 - 2*y^-1 - sage: h = g.univariate_polynomial(); h - -2*y^-1 + 305 + 700*y^2 - sage: h.parent() - Univariate Laurent Polynomial Ring in y over Integer Ring - sage: g.univariate_polynomial(LaurentPolynomialRing(QQ,'z')) - -2*z^-1 + 305 + 700*z^2 - - Here's an example with a constant multivariate polynomial:: - - sage: g = R(1) - sage: h = g.univariate_polynomial(); h - 1 - sage: h.parent() - Univariate Laurent Polynomial Ring in x over Integer Ring - """ - from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing - v = self.variables() - if len(v) > 1: - raise TypeError("polynomial must involve at most one variable") - elif len(v) == 1: - x = v[0] - i = self._parent.gens().index(x) - x = str(x) - else: - x = 'x' - i = 0 - - #construct ring if none - if R is None: - R = LaurentPolynomialRing(self.base_ring(), x) - - return R({m[i]: c for m,c in self.dict().iteritems()}) - - def factor(self): - """ - Returns a Laurent monomial (the unit part of the factorization) and a factored multi-polynomial. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.factor() - (x^3*y^-7*z^-2) * (4*x^4*y^7*z + 3*y^8*z^2 + 2*x*y^7 + x^3*z^2) - - TESTS: - - Tests for :trac:`29173`:: - - sage: L.<a, b> = LaurentPolynomialRing(ZZ, 'a, b') - sage: (a*b + a + b + 1).factor() - (b + 1) * (a + 1) - sage: ((a^-1)*(a*b + a + b + 1)).factor() - (a^-1) * (b + 1) * (a + 1) - sage: L(-12).factor() - -1 * 2^2 * 3 - """ - pf = self._poly.factor() - - if self._poly.degree() == 0: - # Factorization is broken for polynomials, see - # https://github.com/sagemath/sage/issues/20214 - return pf - - u = self.parent(pf.unit()) - - cdef tuple g = <tuple> self._parent.gens() - for i in self._mon.nonzero_positions(): - u *= g[i] ** self._mon[i] - - cdef list f = [] - cdef dict d - for t in pf: - d = <dict> (t[0].dict()) - if len(d) == 1: # monomials are units - u *= self.parent(d) ** t[1] - else: - f.append((self.parent(d), t[1])) - - return Factorization(f, unit=u) - - def is_square(self, root=False): - r""" - Test whether this Laurent polynomial is a square. - - INPUT: - - - ``root`` - boolean (default ``False``) - if set to ``True`` - then return a pair ``(True, sqrt)`` with ``sqrt`` a square - root of this Laurent polynomial when it exists or - ``(False, None)``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: p = (1 + x*y + z^-3) - sage: (p**2).is_square() - True - sage: (p**2).is_square(root=True) - (True, x*y + 1 + z^-3) - - sage: x.is_square() - False - sage: x.is_square(root=True) - (False, None) - - sage: (x**-4 * (1 + z)).is_square(root=False) - False - sage: (x**-4 * (1 + z)).is_square(root=True) - (False, None) - """ - self._normalize() - if not self._mon.is_multiple_of(2): - return (False, None) if root else False - - cdef LaurentPolynomial_mpair ans - - if not root: - return self._poly.is_square(root=False) - else: - (pans, root) = self._poly.is_square(root=True) - if not pans: - return (False, None) - - mon = self._mon.escalar_div(2) - ans = self._new_c() - ans._mon = mon - ans._poly = root - return (True, ans) - - cpdef rescale_vars(self, dict d, h=None, new_ring=None): - r""" - Rescale variables in a Laurent polynomial. - - INPUT: - - - ``d`` -- a ``dict`` whose keys are the generator indices - and values are the coefficients; so a pair ``(i, v)`` - means `x_i \mapsto v x_i` - - ``h`` -- (optional) a map to be applied to coefficients - done after rescaling - - ``new_ring`` -- (optional) a new ring to map the result into - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: p = x^-2*y + x*y^-2 - sage: p.rescale_vars({0: 2, 1: 3}) - 2/9*x*y^-2 + 3/4*x^-2*y - sage: F = GF(2) - sage: p.rescale_vars({0: 3, 1: 7}, new_ring=L.change_ring(F)) - x*y^-2 + x^-2*y - - Test for :trac:`30331`:: - - sage: F.<z> = CyclotomicField(3) - sage: p.rescale_vars({0: 2, 1: z}, new_ring=L.change_ring(F)) - 2*z*x*y^-2 + 1/4*z*x^-2*y - """ - cdef int i - cdef dict df - cdef ETuple v - cdef LaurentPolynomial_mpair ans - - if self._prod is None: - self._compute_polydict() - - df = dict(self._prod.__repn) # This makes a copy for us to manipulate - if new_ring is None: - R = self._parent._base - else: - R = new_ring._base - if h is None: - for v in df: - val = df[v] - for i in d: - val *= d[i]**v[i] - df[v] = val - else: - for v in df: - val = df[v] - for i in d: - val *= d[i]**v[i] - df[v] = R(h(val)) - - ans = <LaurentPolynomial_mpair> self._new_c() - ans._prod = PolyDict(df) - ans._mon = self._mon - if new_ring is None: - S = self._poly._parent - else: - S = self._poly._parent.change_ring(R) - ans._poly = <MPolynomial> S({v.esub(ans._mon): df[v] for v in df}) - if new_ring is not None: - return new_ring(ans) - return ans - - cpdef toric_coordinate_change(self, M, h=None, new_ring=None): - r""" - Apply a matrix to the exponents in a Laurent polynomial. - - For efficiency, we implement this directly, rather than as a substitution. - - The optional argument ``h`` is a map to be applied to coefficients. - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: p = 2*x^2 + y - x*y - sage: p.toric_coordinate_change(Matrix([[1,-3],[1,1]])) - 2*x^2*y^2 - x^-2*y^2 + x^-3*y - sage: F = GF(2) - sage: p.toric_coordinate_change(Matrix([[1,-3],[1,1]]), new_ring=L.change_ring(F)) - x^-2*y^2 + x^-3*y - - """ - cdef int n, i, j, x - cdef dict d, dr - cdef ETuple v - cdef LaurentPolynomial_mpair ans - cdef list L, mon, exp - cdef Matrix mat = M - - n = self._parent.ngens() - if mat.dimensions() != (n, n): - raise ValueError("the matrix M must be a {k} x {k} matrix".format(k=n)) - - if not self: - if new_ring is None: - return self._parent.zero() - else: - return new_ring.zero() - - if self._prod is None: - self._compute_polydict() - - d = self._prod.__repn - dr = {} - mon = [0] * n - for v in d: - # Make a copy of mon as this might be faster than creating the data from scratch. - # We will set every entry, so no need to clear the data. - exp = list(mon) - for j in range(n): - x = 0 - for i in range(n): - if not mat.get_is_zero_unsafe(j, i): - x += (<int> v[i]) * int(mat.get_unsafe(j, i)) - if x < (<int> mon[j]): - mon[j] = x - exp[j] = x - dr[ETuple(exp)] = d[v] - - if h is not None: - for v in dr: - dr[v] = self._parent._base(h(dr[v])) - - ans = <LaurentPolynomial_mpair> self._new_c() - ans._prod = PolyDict(dr) - ans._mon = ETuple(mon) - ans._poly = <MPolynomial> self._poly._parent({v.esub(ans._mon): dr[v] for v in dr}) - if new_ring is not None: - return new_ring(ans) - return ans - - cpdef toric_substitute(self, v, v1, a, h=None, new_ring=None): - r""" - Perform a single-variable substitution up to a toric coordinate change. - - The optional argument ``h`` is a map to be applied to coefficients. - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: p = x + y - sage: p.toric_substitute((2,3), (-1,1), 2) - 1/2*x^3*y^3 + 2*x^-2*y^-2 - sage: F = GF(5) - sage: p.toric_substitute((2,3), (-1,1), 2, new_ring=L.change_ring(F)) - 3*x^3*y^3 + 2*x^-2*y^-2 - - TESTS: - - Tests for :trac:`30331`:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: p = x + y - sage: F.<z> = CyclotomicField(3) - sage: p.toric_substitute((2,3), (-1,1), z, new_ring=L.change_ring(F)) - (-z - 1)*x^3*y^3 + z*x^-2*y^-2 - - sage: P.<x> = LaurentPolynomialRing(QQ, 1) - sage: u = x - 1 - sage: v = u.toric_substitute((-1,), (-1,), 1) - sage: v.is_zero() - True - """ - cdef dict d, dr - cdef ETuple ve, v1e, w, w1, mon - cdef LaurentPolynomial_mpair ans - cdef int t - - if self._prod is None: - self._compute_polydict() - - d = self._prod.__repn - dr = {} - ve = ETuple(v) - v1e = ETuple(v1) - mon = self._mon - if h is not None: - d = dict(d) # Make a copy so we can manipulate it - for w in d: - d[w] = h(d[w]) - for w in d: - x = d[w] - t = w.dotprod(v1e) - w1 = w.eadd_scaled(ve, -t) - if w1 in dr: - dr[w1] += x * a**t - else: - dr[w1] = x * a**t - mon = mon.emin(w1) - for v in tuple(dr.keys()): - if not dr[v]: - del dr[v] - - if new_ring is None: - S = self._poly._parent - else: - S = self._poly._parent.change_ring(new_ring._base) - ans = <LaurentPolynomial_mpair> self._new_c() - ans._prod = PolyDict(dr) - ans._mon = mon - ans._poly = <MPolynomial> S({v.esub(ans._mon): dr[v] for v in dr}) - if new_ring is not None: - return new_ring(ans) - return ans diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 76d1b495274..aa18314e523 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.libs.singular sage.modules (because all doctests need laurent_polynomial_mpair, Groebner bases) r""" Ideals in Laurent polynomial rings. @@ -55,34 +55,38 @@ def __init__(self, ring, gens, coerce=True, hint=None): sage: R.<x,y> = LaurentPolynomialRing(IntegerRing(), 2, order='lex') sage: R.ideal([x, y]) - Ideal (x, y) of Multivariate Laurent Polynomial Ring in x, y over Integer Ring + Ideal (x, y) of Multivariate Laurent Polynomial Ring in x, y + over Integer Ring sage: R.<x0,x1> = LaurentPolynomialRing(GF(3), 2) sage: R.ideal([x0^2, x1^-3]) - Ideal (x0^2, x1^-3) of Multivariate Laurent Polynomial Ring in x0, x1 over Finite Field of size 3 + Ideal (x0^2, x1^-3) of Multivariate Laurent Polynomial Ring in x0, x1 + over Finite Field of size 3 sage: P.<x,y> = LaurentPolynomialRing(QQ, 2) sage: I = P.ideal([~x + ~y - 1]) sage: print(I) - Ideal (-1 + y^-1 + x^-1) of Multivariate Laurent Polynomial Ring in x, y over Rational Field + Ideal (-1 + y^-1 + x^-1) of + Multivariate Laurent Polynomial Ring in x, y over Rational Field sage: I.is_zero() False sage: (x^(-2) + x^(-1)*y^(-1) - x^(-1)) in I True sage: P.<x,y,z> = LaurentPolynomialRing(QQ, 3) - sage: I1 = P.ideal([x*y*z+x*y+2*y^2, x+z]) - sage: I2 = P.ideal([x*y*z+x*y+2*y^2+x+z, x+z]) + sage: I1 = P.ideal([x*y*z + x*y + 2*y^2, x + z]) + sage: I2 = P.ideal([x*y*z + x*y + 2*y^2 + x + z, x + z]) sage: I1 == I2 True - sage: I3 = P.ideal([x*y*z+x*y+2*y^2+x+z, x+z, y]) + sage: I3 = P.ideal([x*y*z + x*y + 2*y^2 + x + z, x + z, y]) sage: I1 < I3 True sage: I1.minimal_associated_primes() - (Ideal (-1/2*z^2 + y - 1/2*z, x + z) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field,) + (Ideal (-1/2*z^2 + y - 1/2*z, x + z) of Multivariate + Laurent Polynomial Ring in x, y, z over Rational Field,) - sage: K.<z> = CyclotomicField(4) - sage: J = I1.base_extend(K) - sage: J.base_ring() + sage: K.<z> = CyclotomicField(4) # needs sage.rings.number_field + sage: J = I1.base_extend(K) # needs sage.rings.number_field + sage: J.base_ring() # needs sage.rings.number_field Cyclotomic Field of order 4 and degree 2 """ Ideal_generic.__init__(self, ring, gens, coerce=coerce) @@ -103,6 +107,8 @@ def set_hint(self, hint): to speed up computation of the associated ideal in some cases; normally the end user will have no need to work with it directly. + EXAMPLES:: + sage: P.<x,y,z> = LaurentPolynomialRing(QQ, 3) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.hint() @@ -205,10 +211,11 @@ def change_ring(self, R, hint=None): EXAMPLES:: sage: P.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: I = P.ideal([x+y]) + sage: I = P.ideal([x + y]) sage: Q.<x,y,z> = LaurentPolynomialRing(QQ, 3) sage: I.change_ring(Q) - Ideal (x + y) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field + Ideal (x + y) of Multivariate Laurent Polynomial Ring in x, y, z + over Rational Field """ return R.ideal(self.gens(), hint=hint) @@ -221,10 +228,11 @@ def base_extend(self, F): EXAMPLES:: sage: P.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: I = P.ideal([x+y]) - sage: K.<z> = CyclotomicField(3) - sage: I.base_extend(K) - Ideal (x + y) of Multivariate Laurent Polynomial Ring in x, y over Cyclotomic Field of order 3 and degree 2 + sage: I = P.ideal([x + y]) + sage: K.<z> = CyclotomicField(3) # needs sage.rings.number_field + sage: I.base_extend(K) # needs sage.rings.number_field + Ideal (x + y) of Multivariate Laurent Polynomial Ring in x, y + over Cyclotomic Field of order 3 and degree 2 """ ring = self.ring() return self.change_ring(ring.change_ring(F), hint=self._hint) @@ -239,12 +247,14 @@ def apply_map(self, f, new_ring=None, new_base_ring=None, apply_to_hint=None): EXAMPLES:: sage: P.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: I = P.ideal([x+1, y-1]) - sage: I.apply_map(lambda z: z+2) - Ideal (x + 3, y + 1) of Multivariate Laurent Polynomial Ring in x, y over Rational Field - sage: K.<i> = CyclotomicField(4) - sage: I.apply_map(lambda z: z+2, new_base_ring=K) - Ideal (x + 3, y + 1) of Multivariate Laurent Polynomial Ring in x, y over Cyclotomic Field of order 4 and degree 2 + sage: I = P.ideal([x + 1, y - 1]) + sage: I.apply_map(lambda z: z + 2) + Ideal (x + 3, y + 1) of Multivariate Laurent Polynomial Ring in x, y + over Rational Field + sage: K.<i> = CyclotomicField(4) # needs sage.rings.number_field + sage: I.apply_map(lambda z: z + 2, new_base_ring=K) # needs sage.rings.number_field + Ideal (x + 3, y + 1) of Multivariate Laurent Polynomial Ring in x, y + over Cyclotomic Field of order 4 and degree 2 """ ring = self.ring() if new_ring is not None: @@ -267,16 +277,19 @@ def apply_coeff_map(self, f, new_base_ring=None, forward_hint=True): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<z> = CyclotomicField(3) sage: P.<x,y> = LaurentPolynomialRing(K, 2) - sage: I = P.ideal([x+z, y-z]) + sage: I = P.ideal([x + z, y - z]) sage: h = K.hom([z^2]) sage: I.apply_coeff_map(h) - Ideal (x - z - 1, y + z + 1) of Multivariate Laurent Polynomial Ring in x, y over Cyclotomic Field of order 3 and degree 2 + Ideal (x - z - 1, y + z + 1) of Multivariate Laurent Polynomial Ring + in x, y over Cyclotomic Field of order 3 and degree 2 sage: K1.<z1> = CyclotomicField(12) sage: h1 = K.hom([z1^4]) sage: I.apply_coeff_map(h1, new_base_ring=K1) - Ideal (x + z1^2 - 1, y - z1^2 + 1) of Multivariate Laurent Polynomial Ring in x, y over Cyclotomic Field of order 12 and degree 4 + Ideal (x + z1^2 - 1, y - z1^2 + 1) of Multivariate Laurent Polynomial Ring + in x, y over Cyclotomic Field of order 12 and degree 4 """ ring = self.ring() if new_base_ring is None: @@ -299,12 +312,14 @@ def toric_coordinate_change(self, M, forward_hint=True): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<z> = CyclotomicField(3) sage: P.<x,y> = LaurentPolynomialRing(K, 2) - sage: I = P.ideal([x+1, y-1]) - sage: M = Matrix([[2,1],[1,-3]]) + sage: I = P.ideal([x + 1, y - 1]) + sage: M = Matrix([[2,1], [1,-3]]) sage: I.toric_coordinate_change(M) - Ideal (x^2*y + 1, -1 + x*y^-3) of Multivariate Laurent Polynomial Ring in x, y over Cyclotomic Field of order 3 and degree 2 + Ideal (x^2*y + 1, -1 + x*y^-3) of Multivariate Laurent Polynomial Ring + in x, y over Cyclotomic Field of order 3 and degree 2 """ if forward_hint: R = self.ring() @@ -355,10 +370,12 @@ def normalize_gens(self): sage: P.<x,y> = LaurentPolynomialRing(QQ, 2) sage: I = P.ideal([~x+y]) sage: J = P.ideal([y+1]) - sage: I+J - Ideal (y + x^-1, y + 1) of Multivariate Laurent Polynomial Ring in x, y over Rational Field - sage: (I+J).normalize_gens() - Ideal (x - 1, y + 1) of Multivariate Laurent Polynomial Ring in x, y over Rational Field + sage: I + J + Ideal (y + x^-1, y + 1) of Multivariate Laurent Polynomial Ring + in x, y over Rational Field + sage: (I + J).normalize_gens() + Ideal (x - 1, y + 1) of Multivariate Laurent Polynomial Ring + in x, y over Rational Field """ return self.ring().ideal(self.groebner_basis(), hint=self._hint) @@ -379,7 +396,8 @@ def polynomial_ideal(self, saturate=True): sage: P.<x,y> = LaurentPolynomialRing(QQ, 2) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.polynomial_ideal() - Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y over Rational Field + Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y + over Rational Field """ if self._poly_ideal is not None and (self._saturated or not saturate): return self._poly_ideal @@ -414,9 +432,9 @@ def groebner_basis(self, saturate=True): EXAMPLES:: sage: P.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: I = P.ideal([x+y]) - sage: J = P.ideal([y+1]) - sage: (I+J).groebner_basis() + sage: I = P.ideal([x + y]) + sage: J = P.ideal([y + 1]) + sage: (I + J).groebner_basis() (x - 1, y + 1) """ l = self.polynomial_ideal(saturate=saturate).groebner_basis() @@ -468,10 +486,12 @@ def associated_primes(self): sage: P.<x,y,z> = LaurentPolynomialRing(QQ, 3) sage: p = z^2 + 1; q = z^3 + 2 - sage: I = P.ideal((p*q^2, y-z^2)) + sage: I = P.ideal((p*q^2, y - z^2)) sage: tuple(sorted(I.associated_primes(), key=str)) - (Ideal (y + 1, z^2 + 1) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field, - Ideal (z^2 - y, y*z + 2, y^2 + 2*z) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) + (Ideal (y + 1, z^2 + 1) of + Multivariate Laurent Polynomial Ring in x, y, z over Rational Field, + Ideal (z^2 - y, y*z + 2, y^2 + 2*z) of + Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ l = self.polynomial_ideal(saturate=False).associated_primes() l2 = [self.ring().ideal(I.gens(), hint=I) for I in l] @@ -488,10 +508,12 @@ def minimal_associated_primes(self, saturate=False): sage: P.<x,y,z> = LaurentPolynomialRing(QQ, 3) sage: p = z^2 + 1; q = z^3 + 2 - sage: I = P.ideal((p*q^2, y-z^2)) + sage: I = P.ideal((p*q^2, y - z^2)) sage: tuple(sorted(I.minimal_associated_primes(), key=str)) - (Ideal (z^2 + 1, -z^2 + y) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field, - Ideal (z^3 + 2, -z^2 + y) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) + (Ideal (z^2 + 1, -z^2 + y) of + Multivariate Laurent Polynomial Ring in x, y, z over Rational Field, + Ideal (z^3 + 2, -z^2 + y) of + Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ l = self.polynomial_ideal(saturate=saturate).minimal_associated_primes() l2 = [self.ring().ideal(I.gens(), hint=I) for I in l] @@ -506,7 +528,8 @@ def radical(self): sage: P.<x,y,z> = LaurentPolynomialRing(QQ, 3) sage: I = P.ideal(((x+1)^2, (y+1)^3, ((x+1)*z)^4 + (y+1)^3 + 10*(x+1)^2)) sage: I.radical() - Ideal (y + 1, x + 1) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field + Ideal (y + 1, x + 1) of Multivariate Laurent Polynomial Ring in x, y, z + over Rational Field """ J = self.polynomial_ideal().radical() return self.ring().ideal(J.gens()) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pxd b/src/sage/rings/polynomial/laurent_polynomial_mpair.pxd new file mode 100644 index 00000000000..79f09def6aa --- /dev/null +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pxd @@ -0,0 +1,14 @@ +from sage.rings.polynomial.laurent_polynomial cimport LaurentPolynomial +from sage.rings.polynomial.multi_polynomial cimport MPolynomial +from sage.rings.polynomial.polydict cimport ETuple, PolyDict + + +cdef class LaurentPolynomial_mpair(LaurentPolynomial): + cdef ETuple _mon + cdef MPolynomial _poly + cdef PolyDict _prod + cdef _compute_polydict(self) + cdef _normalize(self, i=*) + cpdef rescale_vars(self, dict d, h=*, new_ring=*) + cpdef toric_coordinate_change(self, M, h=*, new_ring=*) + cpdef toric_substitute(self, v, v1, a, h=*, new_ring=*) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx new file mode 100644 index 00000000000..e14f1b36ce5 --- /dev/null +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -0,0 +1,1856 @@ +r""" +Elements of multivariate Laurent polynomial rings +""" +# **************************************************************************** +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.rings.integer cimport Integer +from sage.structure.element cimport CommutativeAlgebraElement, Element, ModuleElement, RingElement +from sage.structure.element import coerce_binop, parent +from sage.structure.factorization import Factorization +from sage.misc.derivative import multi_derivative +from sage.rings.polynomial.polydict cimport monomial_exponent +from sage.matrix.matrix0 cimport Matrix + + +cdef class LaurentPolynomial_mpair(LaurentPolynomial): + """ + Multivariate Laurent polynomials. + """ + def __init__(self, parent, x, mon=None, reduce=True): + """ + Currently, one can only create LaurentPolynomials out of dictionaries + and elements of the base ring. + + INPUT: + + - ``parent`` -- a SageMath parent + + - ``x`` -- an element or dictionary or anything the underlying + polynomial ring accepts + + - ``mon`` -- (default: ``None``) a tuple specifying the shift + in the exponents + + - ``reduce`` -- (default: ``True``) a boolean + + EXAMPLES:: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: f = L({(-1,-1):1}); f + w^-1*z^-1 + sage: f = L({(1,1):1}); f + w*z + sage: f = L({(-1,-1):1, (1,3):4}); f + 4*w*z^3 + w^-1*z^-1 + sage: L(1/2) + 1/2 + + TESTS: + + Check that :trac:`19538` is fixed:: + + sage: R = LaurentPolynomialRing(QQ,'x2,x0') + sage: S = LaurentPolynomialRing(QQ,'x',3) + sage: f = S.coerce_map_from(R) + sage: f(R.gen(0) + R.gen(1)^2) + x0^2 + x2 + sage: _.parent() + Multivariate Laurent Polynomial Ring in x0, x1, x2 over Rational Field + + :: + + sage: from sage.rings.polynomial.laurent_polynomial_mpair import LaurentPolynomial_mpair + sage: LaurentPolynomial_mpair(L, {(1,2): 1/42}, mon=(-3, -3)) + 1/42*w^-2*z^-1 + + :trac:`22398`:: + + sage: LQ = LaurentPolynomialRing(QQ, 'x0, x1, x2, y0, y1, y2, y3, y4, y5') + sage: LZ = LaurentPolynomialRing(ZZ, 'x0, x1, x2, y0, y1, y2, y3, y4, y5') + sage: LQ.inject_variables() + Defining x0, x1, x2, y0, y1, y2, y3, y4, y5 + sage: x2^-1*y0*y1*y2*y3*y4*y5 + x1^-1*x2^-1*y0*y1*y3*y4 + x0^-1 in LZ + True + sage: x2^-1*y0*y1*y2*y3*y4*y5 + x1^-1*x2^-1*y0*y1*y3*y4 + x0^-1*x1^-1*y0*y3 + x0^-1 in LZ + True + + Check that input is not modified:: + + sage: LQ.<x,y> = LaurentPolynomialRing(QQ) + sage: D = {(-1, 1): 1} + sage: k = tuple(D)[0] + sage: v = D[k] + sage: type(k), type(v) + (<... 'tuple'>, <class 'sage.rings.integer.Integer'>) + sage: LQ(D) + x^-1*y + sage: tuple(D)[0] is k + True + sage: D[k] is v + True + """ + if isinstance(x, PolyDict): + x = x.dict() + if mon is not None: + if isinstance(mon, ETuple): + self._mon = mon + else: + self._mon = ETuple(mon) + else: + if isinstance(x, dict): + self._mon = ETuple({}, int(parent.ngens())) + D = {} + for k, x_k in x.iteritems(): # ETuple-ize keys, set _mon + if not isinstance(k, (tuple, ETuple)) or len(k) != parent.ngens(): + self._mon = ETuple({}, int(parent.ngens())) + break + if isinstance(k, tuple): + k = ETuple(k) + D[k] = x_k + self._mon = self._mon.emin(k) # point-wise min of _mon and k + else: + x = D + if not self._mon.is_constant(): # factor out _mon + x = {k.esub(self._mon): x_k for k, x_k in x.iteritems()} + elif (isinstance(x, LaurentPolynomial_mpair) and + parent.variable_names() == x.parent().variable_names()): + self._mon = (<LaurentPolynomial_mpair>x)._mon + x = (<LaurentPolynomial_mpair>x)._poly + else: # since x should coerce into parent, _mon should be (0,...,0) + self._mon = ETuple({}, int(parent.ngens())) + self._poly = parent._R(x) + CommutativeAlgebraElement.__init__(self, parent) + + def __reduce__(self): + """ + TESTS:: + + sage: R = LaurentPolynomialRing(QQ, 2, 'x') + sage: R.<x1,x2> = LaurentPolynomialRing(QQ) + sage: loads(dumps(x1)) == x1 # indirect doctest + True + sage: z = x1/x2 + sage: loads(dumps(z)) == z + True + """ + return self._parent, (self._poly, self._mon) + + def __hash__(self): + r""" + TESTS: + + Test that the hash is non-constant (see also :trac:`27914`):: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: len({hash(w^i*z^j) for i in [-2..2] for j in [-2..2]}) + 25 + + Check that :trac:`20490` is fixed:: + + sage: R.<a,b> = LaurentPolynomialRing(ZZ) + sage: p = a*~a + sage: p._fraction_pair() + (a, a) + sage: p == R.one() + True + sage: hash(p) + 1 + + Check that :trac:`23864` is fixed (compatibility with integers, rationals + and polynomial rings):: + + sage: L = LaurentPolynomialRing(QQ, 'x0,x1,x2') + sage: hash(L.zero()) + 0 + sage: hash(L.one()) + 1 + sage: hash(-L.one()) + -2 + sage: hash(L(1/2)) == hash(1/2) + True + + sage: R = PolynomialRing(QQ, 'x0,x1,x2') + sage: x0,x1,x2 = R.gens() + sage: hash(x0) == hash(L(x0)) + True + sage: hash(1 - 7*x0 + x1*x2) == hash(L(1 - 7*x0 + x1*x2)) + True + + Check that :trac:`27914` is fixed:: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: Lw = LaurentPolynomialRing(QQ, 'w') + sage: Lz = LaurentPolynomialRing(QQ, 'z') + sage: all(hash(w^k) == hash(Lw(w^k)) + ....: and hash(z^k) == hash(Lz(z^k)) for k in (-5..5)) + True + sage: p = w^-1 + 2 + w + sage: hash(p) == hash(Lw(p)) + True + """ + # we reimplement the hash from multipolynomial to handle negative exponents + # (see multi_polynomial.pyx) + cdef long result = 0 + cdef long exponent + cdef list var_name_hash = [hash(v) for v in self._parent.variable_names()] + cdef int p + cdef int n = len(var_name_hash) + cdef long c_hash + for m, c in self._poly.iterator_exp_coeff(): + c_hash = hash(c) + if c_hash != 0: + for p in range(n): + exponent = m[p] + self._mon[p] + if exponent > 0: + c_hash = (1000003 * c_hash) ^ var_name_hash[p] + c_hash = (1000003 * c_hash) ^ exponent + elif exponent < 0: + c_hash = (1000003 * c_hash) ^ var_name_hash[p] + c_hash = (700005 * c_hash) ^ exponent + result += c_hash + + return result + + def _im_gens_(self, codomain, im_gens, base_map=None): + """ + Return the image of ``self`` under the morphism defined by + ``im_gens`` in ``codomain``. + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(ZZ) + sage: M.<u,v> = LaurentPolynomialRing(ZZ) + sage: phi = L.hom([u,v]) + sage: phi(x^2*~y -5*y**3) # indirect doctest + -5*v^3 + u^2*v^-1 + + TESTS: + + check compatibility with :trac:`26105`:: + + sage: # needs sage.rings.finite_rings + sage: F.<t> = GF(4) + sage: LF.<a,b> = LaurentPolynomialRing(F) + sage: rho = LF.hom([b,a], base_map=F.frobenius_endomorphism()) + sage: s = t*~a + b +~t*(b**-3)*a**2; rs = rho(s); rs + a + (t + 1)*b^-1 + t*a^-3*b^2 + sage: s == rho(rs) + True + """ + p = self._poly + m = self._mon + if base_map is not None: + p = p.map_coefficients(base_map) + from sage.misc.misc_c import prod + return codomain(p(im_gens) * prod(ig**m[im_gens.index(ig)] for ig in im_gens)) + + cdef _normalize(self, i=None): + r""" + Remove the common monomials from ``self._poly`` and store + them in ``self._mon``. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ) + sage: f = x*y + 2*y*x^2 + y # indirect doctest + sage: f.factor() # Notice the y has been factored out. + (y) * (2*x^2 + x + 1) + + Check that :trac:`23864` has been fixed:: + + sage: hash(L.zero()) + 0 + """ + if not self._poly: + self._mon = ETuple({}, int(self._parent.ngens())) + return + + # cdef dict D = <dict> self._poly._mpoly_dict_recursive( + # <tuple> self._parent.variable_names(), + # self._parent.base_ring() + # ) + cdef dict D = <dict> self._poly.dict() + + cdef ETuple e + if i is None: + e = None + for k in D: + if e is None: + e = <ETuple> k + else: + e = e.emin(k) + if not e.is_constant(): + self._poly = <ModuleElement> (self._poly // self._poly._parent({e: 1})) + self._mon = self._mon.eadd(e) + else: + e = None + for k in D: + if e is None or k[i] < e: + e = <ETuple> k[i] + if e > 0: + self._poly = <ModuleElement> (self._poly // self._poly._parent.gen(i)) + self._mon = self._mon.eadd_p(e, i) + + cdef _compute_polydict(self): + """ + EXAMPLES:: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: a = w^2*z^-1 +3 + sage: a.dict() # indirect doctest + {(0, 0): 3, (2, -1): 1} + """ + # cdef dict D = <dict> self._poly._mpoly_dict_recursive(self._parent.variable_names(), + # self._parent.base_ring()) + cdef dict D = <dict> self._poly.dict() + cdef dict DD + if self._mon.is_constant(): + self._prod = PolyDict(D) + return + DD = {} + for k in D: + DD[k.eadd(self._mon)] = D[k] + self._prod = PolyDict(DD) + + def is_unit(self): + """ + Return ``True`` if ``self`` is a unit. + + The ground ring is assumed to be an integral domain. + + This means that the Laurent polynomial is a monomial + with unit coefficient. + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ) + sage: (x*y/2).is_unit() + True + sage: (x + y).is_unit() + False + sage: (L.zero()).is_unit() + False + sage: (L.one()).is_unit() + True + + sage: L.<x,y> = LaurentPolynomialRing(ZZ) + sage: (2*x*y).is_unit() + False + """ + coeffs = self.coefficients() + if len(coeffs) != 1: + return False + return coeffs[0].is_unit() + + def _repr_(self): + """ + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ) + sage: f = x^2 + x*y/2 + 2*y^-1 + sage: f._repr_() + 'x^2 + 1/2*x*y + 2*y^-1' + """ + if self._prod is None: + self._compute_polydict() + try: + key = self.parent().term_order().sortkey + except AttributeError: + key = None + atomic = self.parent().base_ring()._repr_option('element_is_atomic') + return self._prod.poly_repr(self.parent().variable_names(), + atomic_coefficients=atomic, sortkey=key) + + def _latex_(self): + r""" + EXAMPLES:: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: a = w^2*z^-1+3; a + w^2*z^-1 + 3 + sage: latex(a) + w^{2} z^{-1} + 3 + + TESTS:: + + sage: L.<lambda2, y2> = LaurentPolynomialRing(QQ) + sage: latex(1/lambda2 + y2^(-3)) + \lambda_{2}^{-1} + y_{2}^{-3} + """ + if self._prod is None: + self._compute_polydict() + try: + key = self.parent().term_order().sortkey + except AttributeError: + key = None + atomic = self.parent().base_ring()._repr_option('element_is_atomic') + return self._prod.latex(self.parent().latex_variable_names(), + atomic_coefficients=atomic, sortkey=key) + + cpdef long number_of_terms(self) except -1: + """ + Return the number of non-zero coefficients of ``self``. + + Also called weight, hamming weight or sparsity. + + EXAMPLES:: + + sage: R.<x, y> = LaurentPolynomialRing(ZZ) + sage: f = x^3 - y + sage: f.number_of_terms() + 2 + sage: R(0).number_of_terms() + 0 + sage: f = (x+1/y)^100 + sage: f.number_of_terms() + 101 + + The method :meth:`hamming_weight` is an alias:: + + sage: f.hamming_weight() + 101 + """ + return self._poly.number_of_terms() + + def __invert__(LaurentPolynomial_mpair self): + """ + Return the inverse of ``self``. + + This treats monomials specially so they remain Laurent + polynomials; the inverse of any other polynomial is an element + of the rational function field. + + TESTS:: + + sage: L.<x,y> = LaurentPolynomialRing(ZZ) + sage: f = ~x + sage: parent(f) + Multivariate Laurent Polynomial Ring in x, y over Integer Ring + sage: parent(f.coefficients()[0]) is parent(f).base_ring() + True + sage: g = ~(2*x) + sage: parent(g) + Multivariate Laurent Polynomial Ring in x, y over Rational Field + sage: parent(g.coefficients()[0]) is parent(g).base_ring() + True + """ + cdef ETuple e + if self._poly.is_term(): + (e, c), = self.dict().items() + e = e.emul(-1) + P = self._parent + try: + c = c.inverse_of_unit() + except (AttributeError, ZeroDivisionError, ArithmeticError): + c = ~c + if c.parent() is not P.base_ring(): + P = P.change_ring(c.parent()) + return P({e: c}) + return super().__invert__() + + def __pow__(LaurentPolynomial_mpair self, n, m): + """ + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ) + sage: f = x + y + sage: f^2 + x^2 + 2*x*y + y^2 + sage: f^(-1) + 1/(x + y) + + TESTS: + + Check that :trac:`2952` is fixed:: + + sage: R.<q> = QQ[] + sage: L.<x,y,z> = LaurentPolynomialRing(R) + sage: f = (x+y+z^-1)^2 + sage: f.substitute(z=1) + x^2 + 2*x*y + y^2 + 2*x + 2*y + 1 + """ + cdef LaurentPolynomial_mpair ans + if n < 0: + return ~(self ** -n) + ans = self._new_c() + ans._poly = self._poly ** n + ans._mon = self._mon.emul(n) + return ans + + def __getitem__(self, n): + r""" + Return the coefficient of `x^n = x_1^{n_1} \cdots x_k^{n_k}` where + `n` is a tuple of length `k` and `k` is the number of variables. + + If the number of inputs is not equal to the number of variables, this + raises a ``TypeError``. + + EXAMPLES:: + + sage: P.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + x*z; f + -x^6 + x*z - 7*x^-2*y^3 + 5*x^-2*y + x^-3*y^2 + sage: f[6,0,0] + -1 + sage: f[-2,3,0] + -7 + sage: f[-1,4,2] + 0 + sage: f[1,0,1] + 1 + sage: f[6] + Traceback (most recent call last): + ... + TypeError: must have exactly 3 inputs + sage: f[6,0] + Traceback (most recent call last): + ... + TypeError: must have exactly 3 inputs + sage: f[6,0,0,0] + Traceback (most recent call last): + ... + TypeError: must have exactly 3 inputs + """ + if isinstance(n, slice): + raise TypeError("multivariate Laurent polynomials are not iterable") + if not isinstance(n, tuple) or len(n) != self._parent.ngens(): + raise TypeError("must have exactly %s inputs" % + self.parent().ngens()) + cdef ETuple t = ETuple(n) + if self._prod is None: + self._compute_polydict() + try: + return self._prod[t] + except KeyError: + return self._parent.base_ring().zero() + + def __iter__(self): + """ + Iterate through all terms by returning a list of the coefficient and + the corresponding monomial. + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + sage: sorted(f) # indirect doctest + [(-7, x^-2*y^3), (-1, x^6), (1, x^-3*y^2), (5, x^-2*y)] + """ + P = self._parent + one = P._R.one() + if self._mon.is_constant(): + for exp, coeff in self._poly.iterator_exp_coeff(): + yield (coeff, P.element_class(P, one, exp)) + else: + for exp, coeff in self._poly.iterator_exp_coeff(): + yield (coeff, P.element_class(P, one, exp.eadd(self._mon))) + + def iterator_exp_coeff(self): + """ + Iterate over ``self`` as pairs of (ETuple, coefficient). + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + sage: list(f.iterator_exp_coeff()) + [((6, 0), -1), ((-2, 3), -7), ((-2, 1), 5), ((-3, 2), 1)] + """ + for exp, coeff in self._poly.iterator_exp_coeff(): + yield (exp.eadd(self._mon), coeff) + + def monomials(self): + """ + Return the list of monomials in ``self``. + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + sage: sorted(f.monomials()) + [x^-3*y^2, x^-2*y, x^-2*y^3, x^6] + """ + return [mon for coeff, mon in self] + + def monomial_coefficient(self, mon): + """ + Return the coefficient in the base ring of the monomial ``mon`` in + ``self``, where ``mon`` must have the same parent as ``self``. + + This function contrasts with the function :meth:`coefficient()` + which returns the coefficient of a monomial viewing this + polynomial in a polynomial ring over a base ring having fewer + variables. + + INPUT: + + - ``mon`` -- a monomial + + .. SEEALSO:: + + For coefficients in a base ring of fewer variables, see + :meth:`coefficient()`. + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + sage: f.monomial_coefficient(x^-2*y^3) + -7 + sage: f.monomial_coefficient(x^2) + 0 + + TESTS:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = y^2 * x^-2 + sage: f.monomial_coefficient(x + y) + Traceback (most recent call last): + ... + ValueError: not a monomial + """ + if parent(mon) != self._parent: + raise TypeError("input must have the same parent") + cdef LaurentPolynomial_mpair m = <LaurentPolynomial_mpair> mon + if m._prod is None: + m._compute_polydict() + if self._prod is None: + self._compute_polydict() + exp = monomial_exponent(m._prod) + zero = self._parent.base_ring().zero() + return self._prod.get(exp, zero) + + def constant_coefficient(self): + """ + Return the constant coefficient of ``self``. + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^2 + 5*x*y)*x^-3; f + -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 + sage: f.constant_coefficient() + 0 + sage: f = (x^3 + 2*x^-2*y+y^3)*y^-3; f + x^3*y^-3 + 1 + 2*x^-2*y^-2 + sage: f.constant_coefficient() + 1 + """ + return self[(0,)*self._parent.ngens()] + + def coefficient(self, mon): + r""" + Return the coefficient of ``mon`` in ``self``, where ``mon`` must + have the same parent as ``self``. + + The coefficient is defined as follows. If `f` is this polynomial, then + the coefficient `c_m` is sum: + + .. MATH:: + + c_m := \sum_T \frac{T}{m} + + where the sum is over terms `T` in `f` that are exactly divisible + by `m`. + + A monomial `m(x,y)` 'exactly divides' `f(x,y)` if `m(x,y) | f(x,y)` + and neither `x \cdot m(x,y)` nor `y \cdot m(x,y)` divides `f(x,y)`. + + INPUT: + + - ``mon`` -- a monomial + + OUTPUT: + + Element of the parent of ``self``. + + .. NOTE:: + + To get the constant coefficient, call + :meth:`constant_coefficient()`. + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + + The coefficient returned is an element of the parent of ``self``; in + this case, ``P``. :: + + sage: f = 2 * x * y + sage: c = f.coefficient(x*y); c + 2 + sage: c.parent() + Multivariate Laurent Polynomial Ring in x, y over Rational Field + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^2 + 5*x*y)*x^-3; f + -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 + sage: f.coefficient(y) + 5*x^-2 + sage: f.coefficient(y^2) + -7*x^-2 + x^-3 + sage: f.coefficient(x*y) + 0 + sage: f.coefficient(x^-2) + -7*y^2 + 5*y + sage: f.coefficient(x^-2*y^2) + -7 + sage: f.coefficient(1) + -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 + """ + if mon.parent() is not self._parent: + mon = self._parent(mon) + cdef LaurentPolynomial_mpair m = <LaurentPolynomial_mpair> mon + if self._prod is None: + self._compute_polydict() + if m._prod is None: + m._compute_polydict() + return self._parent(self._prod.coefficient(m.dict())) + + def coefficients(self): + """ + Return the nonzero coefficients of ``self`` in a list. + + The returned list is decreasingly ordered by the term ordering + of ``self.parent()``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ, order='degrevlex') + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.coefficients() + [4, 3, 2, 1] + sage: L.<x,y,z> = LaurentPolynomialRing(QQ,order='lex') + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.coefficients() + [4, 1, 2, 3] + """ + return self._poly.coefficients() + + def variables(self, sort=True): + """ + Return a tuple of all variables occurring in ``self``. + + INPUT: + + - ``sort`` -- specifies whether the indices shall be sorted + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.variables() + (z, y, x) + sage: f.variables(sort=False) #random + (y, z, x) + """ + cdef dict d = self.dict() + cdef tuple g = self._parent.gens() + cdef Py_ssize_t nvars = len(g) + cdef set vars = set() + for k in d: + vars.update(k.nonzero_positions()) + if len(vars) == nvars: + break + cdef list v = [g[i] for i in vars] + if sort: + v.sort() + return tuple(v) + + cpdef dict dict(self): + """ + Return ``self`` represented as a ``dict``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: sorted(f.dict().items()) + [((3, 1, 0), 3), ((4, 0, -2), 2), ((6, -7, 0), 1), ((7, 0, -1), 4)] + """ + if self._prod is None: + self._compute_polydict() + return <dict> self._prod.dict() + + def _fraction_pair(self): + """ + Return one representation of ``self`` as a pair + ``(numerator, denominator)``. + + Here both the numerator and the denominator are polynomials. + + This is used for coercion into the fraction field. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f._fraction_pair() + (4*x^7*y^7*z + 3*x^3*y^8*z^2 + 2*x^4*y^7 + x^6*z^2, y^7*z^2) + """ + ring = self._parent._R + numer = self._poly + denom = ring.one() + var = ring.gens() + for i, j in enumerate(self._mon): + if j > 0: + numer *= var[i] ** j + else: + denom *= var[i] ** (-j) + return (numer, denom) + + cpdef _add_(self, _right): + """ + Return the Laurent polynomial ``self + right``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: g = y + z + sage: f + g + x + y + z + y^-1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair>_right + ans._mon, a, b = self._mon.combine_to_positives(right._mon) + if not a.is_constant(): + ans._poly = self._poly * self._poly._parent({a: 1}) + else: + ans._poly = self._poly + if not b.is_constant(): + ans._poly += right._poly * self._poly._parent({b: 1}) + else: + ans._poly += right._poly + return ans + + cpdef _sub_(self, _right): + """ + Return the Laurent polynomial ``self - right``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: g = y + z + x + sage: f - g + -y - z + y^-1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair>_right + cdef ETuple a, b + ans._mon, a, b = self._mon.combine_to_positives(right._mon) + if not a.is_constant(): + ans._poly = self._poly * self._poly._parent({a: 1}) + else: + ans._poly = self._poly + if not b.is_constant(): + ans._poly -= right._poly * self._poly._parent({b: 1}) + else: + ans._poly -= right._poly + return ans + + cpdef _div_(self, rhs): + """ + Return the division of ``self`` by ``rhs``. + + If the denominator is not a unit, + the result will be given in the fraction field. + + EXAMPLES:: + + sage: R.<s,q,t> = LaurentPolynomialRing(QQ) + sage: 1/s + s^-1 + sage: 1/(s*q) + s^-1*q^-1 + sage: 1/(s+q) + 1/(s + q) + sage: (1/(s+q)).parent() + Fraction Field of Multivariate Polynomial Ring in s, q, t over Rational Field + sage: (1/(s*q)).parent() + Multivariate Laurent Polynomial Ring in s, q, t over Rational Field + sage: (s+q)/(q^2*t^(-2)) + s*q^-2*t^2 + q^-1*t^2 + """ + cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair> rhs + if right.is_zero(): + raise ZeroDivisionError + if right._poly.is_term(): + return self * ~right + else: + return RingElement._div_(self, rhs) + + def is_monomial(self): + """ + Return ``True`` if ``self`` is a monomial. + + EXAMPLES:: + + sage: k.<y,z> = LaurentPolynomialRing(QQ) + sage: z.is_monomial() + True + sage: k(1).is_monomial() + True + sage: (z+1).is_monomial() + False + sage: (z^-2909).is_monomial() + True + sage: (38*z^-2909).is_monomial() + False + """ + return self._poly.is_monomial() + + cpdef _neg_(self): + """ + Return ``-self``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: -f + -x - y^-1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + ans._mon = self._mon + ans._poly = -self._poly + return ans + + cpdef _lmul_(self, Element right): + """ + Return ``self * right`` where ``right`` is in ``self``'s base ring. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: f*(1/2) + 1/2*x + 1/2*y^-1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + ans._mon = self._mon + ans._poly = self._poly * right + return ans + + cpdef _rmul_(self, Element left): + """ + Return ``left * self`` where ``left`` is in ``self``'s base ring. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: (1/2)*f + 1/2*x + 1/2*y^-1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + ans._mon = self._mon + ans._poly = left * self._poly + return ans + + cpdef _mul_(self, right): + """ + Return ``self * right``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: g = y + z + sage: f*g + x*y + x*z + 1 + y^-1*z + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + ans._mon = self._mon.eadd((<LaurentPolynomial_mpair>right)._mon) + ans._poly = self._poly * (<LaurentPolynomial_mpair>right)._poly + return ans + + cpdef _floordiv_(self, right): + """ + Perform division with remainder and return the quotient. + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ) + sage: f = x^3 + y^-3 + sage: g = y + x + sage: f // g # needs sage.libs.singular + x^5*y^-3 - x^4*y^-2 + x^3*y^-1 + + sage: h = x + y^(-1) + sage: f // h # needs sage.libs.singular + x^2 - x*y^-1 + y^-2 + sage: h * (f // h) == f # needs sage.libs.singular + True + sage: f // 1 + x^3 + y^-3 + sage: 1 // f # needs sage.libs.singular + 0 + + TESTS: + + Check that :trac:`19357` is fixed:: + + sage: x // y + x*y^-1 + + Check that :trac:`21999` is fixed:: + + sage: L.<a,b> = LaurentPolynomialRing(QQbar) # needs sage.rings.number_field + sage: (a+a*b) // a # needs sage.libs.singular sage.rings.number_field + b + 1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + cdef LaurentPolynomial_mpair rightl = <LaurentPolynomial_mpair> right + self._normalize() + rightl._normalize() + ans._mon = self._mon.esub(rightl._mon) + ans._poly = self._poly // rightl._poly + return ans + + @coerce_binop + def quo_rem(self, right): + """ + Divide this Laurent polynomial by ``right`` and return a quotient and + a remainder. + + INPUT: + + - ``right`` -- a Laurent polynomial + + OUTPUT: + + A pair of Laurent polynomials. + + EXAMPLES:: + + sage: R.<s, t> = LaurentPolynomialRing(QQ) + sage: (s^2 - t^2).quo_rem(s - t) # needs sage.libs.singular + (s + t, 0) + sage: (s^-2 - t^2).quo_rem(s - t) # needs sage.libs.singular + (s + t, -s^2 + s^-2) + sage: (s^-2 - t^2).quo_rem(s^-1 - t) # needs sage.libs.singular + (t + s^-1, 0) + + TESTS: + + Verify that :trac:`31257` is fixed:: + + sage: # needs sage.libs.singular + sage: R.<x,y> = LaurentPolynomialRing(QQ) + sage: q, r = (1/x).quo_rem(y) + sage: q, r + (x^-1*y^-1, 0) + sage: q*y + r == 1/x + True + sage: q, r = (x^-2 - y^2).quo_rem(x - y) + sage: q*(x - y) + r == x^-2 - y^2 + True + """ + # make copies of self and right so that the input can be normalized + # without affecting the objects that were passed to the method + cdef LaurentPolynomial_mpair selfl = self._new_c() + selfl._poly = self._poly + selfl._mon = self._mon + cdef LaurentPolynomial_mpair rightl = self._new_c() + rightl._poly = (<LaurentPolynomial_mpair> right)._poly + rightl._mon = (<LaurentPolynomial_mpair> right)._mon + + selfl._normalize() + rightl._normalize() + q, r = selfl._poly.quo_rem(rightl._poly) + ql = LaurentPolynomial_mpair(self._parent, q, + mon=selfl._mon.esub(rightl._mon)) + rl = LaurentPolynomial_mpair(self._parent, r, + mon=selfl._mon) + ql._normalize() + rl._normalize() + return (ql, rl) + + cpdef _richcmp_(self, right, int op): + """ + Compare two polynomials in a `LaurentPolynomialRing` based on the term + order from the parent ring. If the parent ring does not specify a term + order then only comparison by equality is supported. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: g = y + z + sage: f == f + True + sage: f == g + False + sage: f == 2 + False + """ + if self._prod is None: + self._compute_polydict() + if (<LaurentPolynomial_mpair> right)._prod is None: + (<LaurentPolynomial_mpair> right)._compute_polydict() + + try: + sortkey = self._parent.term_order().sortkey + except AttributeError: + sortkey = None + + return self._prod.rich_compare((<LaurentPolynomial_mpair>right)._prod, + op, sortkey) + + def exponents(self): + """ + Return a list of the exponents of ``self``. + + EXAMPLES:: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: a = w^2*z^-1 + 3; a + w^2*z^-1 + 3 + sage: e = a.exponents() + sage: e.sort(); e + [(0, 0), (2, -1)] + + """ + return [a.eadd(self._mon) for a in self._poly.exponents()] + + def degree(self, x=None): + """ + Return the degree of ``x`` in ``self``. + + EXAMPLES:: + + sage: R.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.degree(x) + 7 + sage: f.degree(y) + 1 + sage: f.degree(z) + 0 + """ + if not x: + return self._poly.total_degree() + sum(self._mon) + + cdef tuple g = <tuple> self._parent.gens() + cdef Py_ssize_t i + cdef bint no_generator_found = True + for i in range(len(g)): + if g[i] is x: + no_generator_found = False + break + if no_generator_found: + raise TypeError("x must be a generator of parent") + return self._poly.degree(self._parent._R.gens()[i]) + self._mon[i] + + def has_inverse_of(self, i): + """ + INPUT: + + - ``i`` -- The index of a generator of ``self.parent()`` + + OUTPUT: + + Return ``True`` if ``self`` contains a monomial including the inverse of + ``self.parent().gen(i)``, ``False`` otherwise. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.has_inverse_of(0) + False + sage: f.has_inverse_of(1) + True + sage: f.has_inverse_of(2) + True + """ + if (not isinstance(i, (int, Integer))) or (i < 0) or (i >= self._parent.ngens()): + raise TypeError("argument is not the index of a generator") + if self._mon[i] < 0: + self._normalize(i) + if self._mon[i] < 0: + return True + return False + return False + + def has_any_inverse(self): + """ + Return ``True`` if ``self`` contains any monomials with a negative exponent, False otherwise. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.has_any_inverse() + True + sage: g = x^2 + y^2 + sage: g.has_any_inverse() + False + """ + for m in self._mon.nonzero_values(sort=False): + if m < 0: + return True + return False + + def __call__(self, *x, **kwds): + """ + Compute value of ``self`` at ``x``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + 2*y + 3*z + sage: f(1,1,1) + 6 + sage: f = x^-1 + y + z + sage: f(0,1,1) + Traceback (most recent call last): + ... + ZeroDivisionError + + TESTS:: + + sage: f = x + 2*y + 3*z + sage: f(2) + Traceback (most recent call last): + ... + TypeError: number of arguments does not match the number of generators in parent + sage: f(2,0) + Traceback (most recent call last): + ... + TypeError: number of arguments does not match the number of generators in parent + sage: f( (1,1,1) ) + 6 + """ + if kwds: + f = self.subs(**kwds) + if x: # More than 1 non-keyword argument + return f(*x) + else: + return f + + cdef int l = len(x) + + if l == 1 and isinstance(x[0], (tuple, list)): + x = x[0] + l = len(x) + + if l != self._parent.ngens(): + raise TypeError("number of arguments does not match the number" + " of generators in parent") + + # Check to make sure that we aren't dividing by zero + cdef Py_ssize_t m + for m in range(l): + if x[m] == 0: + if self.has_inverse_of(m): + raise ZeroDivisionError + + ans = self._poly(*x) + if ans: + for m in self._mon.nonzero_positions(): + ans *= x[m]**self._mon[m] + + return ans + + def subs(self, in_dict=None, **kwds): + """ + Substitute some variables in this Laurent polynomial. + + Variable/value pairs for the substitution may be given + as a dictionary or via keyword-value pairs. If both are + present, the latter take precedence. + + INPUT: + + - ``in_dict`` -- dictionary (optional) + + - ``**kwds`` -- keyword arguments + + OUTPUT: + + A Laurent polynomial. + + EXAMPLES:: + + sage: L.<x, y, z> = LaurentPolynomialRing(QQ) + sage: f = x + 2*y + 3*z + sage: f.subs(x=1) + 2*y + 3*z + 1 + sage: f.subs(y=1) + x + 3*z + 2 + sage: f.subs(z=1) + x + 2*y + 3 + sage: f.subs(x=1, y=1, z=1) + 6 + + sage: f = x^-1 + sage: f.subs(x=2) + 1/2 + sage: f.subs({x: 2}) + 1/2 + + sage: f = x + 2*y + 3*z + sage: f.subs({x: 1, y: 1, z: 1}) + 6 + sage: f.substitute(x=1, y=1, z=1) + 6 + + TESTS:: + + sage: f = x + 2*y + 3*z + sage: f(q=10) + x + 2*y + 3*z + + sage: x.subs({x: 2}, x=1) + 1 + """ + cdef list variables = list(self._parent.gens()) + cdef Py_ssize_t i + for i in range(len(variables)): + if str(variables[i]) in kwds: + variables[i] = kwds[str(variables[i])] + elif in_dict and variables[i] in in_dict: + variables[i] = in_dict[variables[i]] + return self(tuple(variables)) + + def is_constant(self): + r""" + Return whether this Laurent polynomial is constant. + + EXAMPLES:: + + sage: L.<a, b> = LaurentPolynomialRing(QQ) + sage: L(0).is_constant() + True + sage: L(42).is_constant() + True + sage: a.is_constant() + False + sage: (1/b).is_constant() + False + """ + return (self._mon == ETuple({}, int(self._parent.ngens())) and + self._poly.is_constant()) + + def _symbolic_(self, R): + """ + EXAMPLES:: + + sage: # needs sage.symbolic + sage: R.<x,y> = LaurentPolynomialRing(QQ) + sage: f = x^3 + y/x + sage: g = f._symbolic_(SR); g + (x^4 + y)/x + sage: g(x=2, y=2) + 9 + sage: g = SR(f) + sage: g(x=2, y=2) + 9 + """ + d = {repr(g): R.var(g) for g in self._parent.gens()} + return self.subs(**d) + + def derivative(self, *args): + r""" + The formal derivative of this Laurent polynomial, with respect + to variables supplied in args. + + Multiple variables and iteration counts may be supplied; see + documentation for the global :func:`derivative` function for more + details. + + .. SEEALSO:: + + :meth:`_derivative` + + EXAMPLES:: + + sage: R = LaurentPolynomialRing(ZZ,'x, y') + sage: x, y = R.gens() + sage: t = x**4*y + x*y + y + x**(-1) + y**(-3) + sage: t.derivative(x, x) + 12*x^2*y + 2*x^-3 + sage: t.derivative(y, 2) + 12*y^-5 + """ + return multi_derivative(self, args) + + # add .diff(), .differentiate() as aliases for .derivative() + diff = differentiate = derivative + + def _derivative(self, var=None): + """ + Compute formal derivative of this Laurent polynomial with + respect to the given variable. + + If ``var`` is among the generators of this ring, the derivative + is with respect to the generator. Otherwise, ``_derivative(var)`` is called + recursively for each coefficient of this polynomial. + + .. SEEALSO:: :meth:`derivative` + + EXAMPLES:: + + sage: R = LaurentPolynomialRing(ZZ,'x, y') + sage: x, y = R.gens() + sage: t = x**4*y+x*y+y+x**(-1)+y**(-3) + sage: t._derivative(x) + 4*x^3*y + y - x^-2 + sage: t._derivative(y) + x^4 + x + 1 - 3*y^-4 + + sage: R = LaurentPolynomialRing(QQ['z'],'x') + sage: z = R.base_ring().gen() + sage: x = R.gen() + sage: t = 33*z*x**4+x**(-1) + sage: t._derivative(z) + 33*x^4 + sage: t._derivative(x) + -x^-2 + 132*z*x^3 + """ + if var is None: + raise ValueError("must specify which variable to differentiate " + "with respect to") + P = self._parent + cdef list gens = list(P.gens()) + + # check if var is one of the generators + try: + index = gens.index(var) + except ValueError: + # call _derivative() recursively on coefficients + return P({m: c._derivative(var) + for (m, c) in self.dict().iteritems()}) + + # compute formal derivative with respect to generator + cdef dict d = {} + for m, c in self.dict().iteritems(): + if m[index] != 0: + new_m = [u for u in m] + new_m[index] += -1 + d[ETuple(new_m)] = m[index] * c + return P(d) + + def is_univariate(self): + """ + Return ``True`` if this is a univariate or constant Laurent polynomial, + and ``False`` otherwise. + + EXAMPLES:: + + sage: R.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = (x^3 + y^-3)*z + sage: f.is_univariate() + False + sage: g = f(1, y, 4) + sage: g.is_univariate() + True + sage: R(1).is_univariate() + True + """ + return len(self.variables()) < 2 + + def univariate_polynomial(self, R=None): + """ + Return a univariate polynomial associated to this + multivariate polynomial. + + INPUT: + + - ``R`` - (default: ``None``) a univariate Laurent polynomial ring + + If this polynomial is not in at most one variable, then a + :class:`ValueError` exception is raised. The new polynomial is over + the same base ring as the given :class:`LaurentPolynomial` and in the + variable ``x`` if no ring ``R`` is provided. + + EXAMPLES:: + + sage: R.<x, y> = LaurentPolynomialRing(ZZ) + sage: f = 3*x^2 - 2*y^-1 + 7*x^2*y^2 + 5 + sage: f.univariate_polynomial() + Traceback (most recent call last): + ... + TypeError: polynomial must involve at most one variable + sage: g = f(10, y); g + 700*y^2 + 305 - 2*y^-1 + sage: h = g.univariate_polynomial(); h + -2*y^-1 + 305 + 700*y^2 + sage: h.parent() + Univariate Laurent Polynomial Ring in y over Integer Ring + sage: g.univariate_polynomial(LaurentPolynomialRing(QQ,'z')) + -2*z^-1 + 305 + 700*z^2 + + Here's an example with a constant multivariate polynomial:: + + sage: g = R(1) + sage: h = g.univariate_polynomial(); h + 1 + sage: h.parent() + Univariate Laurent Polynomial Ring in x over Integer Ring + """ + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + v = self.variables() + if len(v) > 1: + raise TypeError("polynomial must involve at most one variable") + elif len(v) == 1: + x = v[0] + i = self._parent.gens().index(x) + x = str(x) + else: + x = 'x' + i = 0 + + # construct ring if none + if R is None: + R = LaurentPolynomialRing(self.base_ring(), x) + + return R({m[i]: c for m, c in self.dict().iteritems()}) + + def monomial_reduction(self): + """ + Factor ``self`` into a polynomial and a monomial. + + OUTPUT: + + A tuple ``(p, v)`` where ``p`` is the underlying polynomial and ``v`` + is a monomial. + + EXAMPLES:: + + sage: R.<x, y> = LaurentPolynomialRing(QQ) + sage: f = y / x + x^2 / y + 3 * x^4 * y^-2 + sage: f.monomial_reduction() + (3*x^5 + x^3*y + y^3, 1/(x*y^2)) + sage: f = y * x + x^2 / y + 3 * x^4 * y^-2 + sage: f.monomial_reduction() + (3*x^3 + y^3 + x*y, x/y^2) + sage: x.monomial_reduction() + (1, x) + sage: (y^-1).monomial_reduction() + (1, 1/y) + """ + self._normalize() + ring = self._parent._R + g = ring.gens() + mon = ring.prod(g[i] ** j for i, j in enumerate(self._mon)) + return (self._poly, mon) + + def factor(self): + """ + Return a Laurent monomial (the unit part of the factorization) and a factored multi-polynomial. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.factor() + (x^3*y^-7*z^-2) * (4*x^4*y^7*z + 3*y^8*z^2 + 2*x*y^7 + x^3*z^2) + + TESTS: + + Tests for :trac:`29173`:: + + sage: L.<a, b> = LaurentPolynomialRing(ZZ, 'a, b') + sage: (a*b + a + b + 1).factor() + (b + 1) * (a + 1) + sage: ((a^-1)*(a*b + a + b + 1)).factor() + (a^-1) * (b + 1) * (a + 1) + sage: L(-12).factor() + -1 * 2^2 * 3 + """ + pf = self._poly.factor() + + if self._poly.degree() == 0: + # Factorization is broken for polynomials, see + # https://github.com/sagemath/sage/issues/20214 + return pf + + u = self.parent(pf.unit()) + + cdef tuple g = <tuple> self._parent.gens() + for i in self._mon.nonzero_positions(): + u *= g[i] ** self._mon[i] + + cdef list f = [] + cdef dict d + for t in pf: + d = <dict> (t[0].dict()) + if len(d) == 1: # monomials are units + u *= self.parent(d) ** t[1] + else: + f.append((self.parent(d), t[1])) + + return Factorization(f, unit=u) + + def is_square(self, root=False): + r""" + Test whether this Laurent polynomial is a square. + + INPUT: + + - ``root`` - boolean (default ``False``) - if set to ``True`` + then return a pair ``(True, sqrt)`` with ``sqrt`` a square + root of this Laurent polynomial when it exists or + ``(False, None)``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: p = 1 + x*y + z^-3 + sage: (p**2).is_square() + True + sage: (p**2).is_square(root=True) + (True, x*y + 1 + z^-3) + + sage: x.is_square() + False + sage: x.is_square(root=True) + (False, None) + + sage: (x**-4 * (1 + z)).is_square(root=False) + False + sage: (x**-4 * (1 + z)).is_square(root=True) + (False, None) + """ + self._normalize() + if not self._mon.is_multiple_of(2): + return (False, None) if root else False + + cdef LaurentPolynomial_mpair ans + + if not root: + return self._poly.is_square(root=False) + else: + (pans, root) = self._poly.is_square(root=True) + if not pans: + return (False, None) + + mon = self._mon.escalar_div(2) + ans = self._new_c() + ans._mon = mon + ans._poly = root + return (True, ans) + + cpdef rescale_vars(self, dict d, h=None, new_ring=None): + r""" + Rescale variables in a Laurent polynomial. + + INPUT: + + - ``d`` -- a ``dict`` whose keys are the generator indices + and values are the coefficients; so a pair ``(i, v)`` + means `x_i \mapsto v x_i` + - ``h`` -- (optional) a map to be applied to coefficients + done after rescaling + - ``new_ring`` -- (optional) a new ring to map the result into + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) + sage: p = x^-2*y + x*y^-2 + sage: p.rescale_vars({0: 2, 1: 3}) + 2/9*x*y^-2 + 3/4*x^-2*y + sage: F = GF(2) + sage: p.rescale_vars({0: 3, 1: 7}, new_ring=L.change_ring(F)) + x*y^-2 + x^-2*y + + Test for :trac:`30331`:: + + sage: F.<z> = CyclotomicField(3) # needs sage.rings.number_field + sage: p.rescale_vars({0: 2, 1: z}, new_ring=L.change_ring(F)) # needs sage.rings.number_field + 2*z*x*y^-2 + 1/4*z*x^-2*y + """ + cdef int i + cdef dict df + cdef ETuple v + cdef LaurentPolynomial_mpair ans + + if self._prod is None: + self._compute_polydict() + + df = dict(self._prod.__repn) # This makes a copy for us to manipulate + if new_ring is None: + R = self._parent._base + else: + R = new_ring._base + if h is None: + for v in df: + val = df[v] + for i in d: + val *= d[i]**v[i] + df[v] = val + else: + for v in df: + val = df[v] + for i in d: + val *= d[i]**v[i] + df[v] = R(h(val)) + + ans = <LaurentPolynomial_mpair> self._new_c() + ans._prod = PolyDict(df) + ans._mon = self._mon + if new_ring is None: + S = self._poly._parent + else: + S = self._poly._parent.change_ring(R) + ans._poly = <MPolynomial> S({v.esub(ans._mon): df[v] for v in df}) + if new_ring is not None: + return new_ring(ans) + return ans + + cpdef toric_coordinate_change(self, M, h=None, new_ring=None): + r""" + Apply a matrix to the exponents in a Laurent polynomial. + + For efficiency, we implement this directly, rather than as a substitution. + + The optional argument ``h`` is a map to be applied to coefficients. + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) + sage: p = 2*x^2 + y - x*y + sage: p.toric_coordinate_change(Matrix([[1,-3], [1,1]])) + 2*x^2*y^2 - x^-2*y^2 + x^-3*y + sage: F = GF(2) + sage: p.toric_coordinate_change(Matrix([[1,-3], [1,1]]), + ....: new_ring=L.change_ring(F)) + x^-2*y^2 + x^-3*y + + """ + cdef int n, i, j, x + cdef dict d, dr + cdef ETuple v + cdef LaurentPolynomial_mpair ans + cdef list mon, exp + cdef Matrix mat = M + + n = self._parent.ngens() + if mat.dimensions() != (n, n): + raise ValueError("the matrix M must be a {k} x {k} matrix".format(k=n)) + + if not self: + if new_ring is None: + return self._parent.zero() + else: + return new_ring.zero() + + if self._prod is None: + self._compute_polydict() + + d = self._prod.__repn + dr = {} + mon = [0] * n + for v in d: + # Make a copy of mon as this might be faster than creating the data from scratch. + # We will set every entry, so no need to clear the data. + exp = list(mon) + for j in range(n): + x = 0 + for i in range(n): + if not mat.get_is_zero_unsafe(j, i): + x += (<int> v[i]) * int(mat.get_unsafe(j, i)) + if x < (<int> mon[j]): + mon[j] = x + exp[j] = x + dr[ETuple(exp)] = d[v] + + if h is not None: + for v in dr: + dr[v] = self._parent._base(h(dr[v])) + + ans = <LaurentPolynomial_mpair> self._new_c() + ans._prod = PolyDict(dr) + ans._mon = ETuple(mon) + ans._poly = <MPolynomial> self._poly._parent({v.esub(ans._mon): dr[v] for v in dr}) + if new_ring is not None: + return new_ring(ans) + return ans + + cpdef toric_substitute(self, v, v1, a, h=None, new_ring=None): + r""" + Perform a single-variable substitution up to a toric coordinate change. + + The optional argument ``h`` is a map to be applied to coefficients. + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) + sage: p = x + y + sage: p.toric_substitute((2,3), (-1,1), 2) + 1/2*x^3*y^3 + 2*x^-2*y^-2 + sage: F = GF(5) + sage: p.toric_substitute((2,3), (-1,1), 2, new_ring=L.change_ring(F)) + 3*x^3*y^3 + 2*x^-2*y^-2 + + TESTS: + + Tests for :trac:`30331`:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) + sage: p = x + y + sage: F.<z> = CyclotomicField(3) # needs sage.rings.number_field + sage: p.toric_substitute((2,3), (-1,1), z, new_ring=L.change_ring(F)) # needs sage.rings.number_field + (-z - 1)*x^3*y^3 + z*x^-2*y^-2 + + sage: P.<x> = LaurentPolynomialRing(QQ, 1) + sage: u = x - 1 + sage: v = u.toric_substitute((-1,), (-1,), 1) + sage: v.is_zero() + True + """ + cdef dict d, dr + cdef ETuple ve, v1e, w, w1, mon + cdef LaurentPolynomial_mpair ans + cdef int t + + if self._prod is None: + self._compute_polydict() + + d = self._prod.__repn + dr = {} + ve = ETuple(v) + v1e = ETuple(v1) + mon = self._mon + if h is not None: + d = dict(d) # Make a copy so we can manipulate it + for w in d: + d[w] = h(d[w]) + for w in d: + x = d[w] + t = w.dotprod(v1e) + w1 = w.eadd_scaled(ve, -t) + if w1 in dr: + dr[w1] += x * a**t + else: + dr[w1] = x * a**t + mon = mon.emin(w1) + for v in tuple(dr.keys()): + if not dr[v]: + del dr[v] + + if new_ring is None: + S = self._poly._parent + else: + S = self._poly._parent.change_ring(new_ring._base) + ans = <LaurentPolynomial_mpair> self._new_c() + ans._prod = PolyDict(dr) + ans._mon = mon + ans._poly = <MPolynomial> S({v.esub(ans._mon): dr[v] for v in dr}) + if new_ring is not None: + return new_ring(ans) + return ans diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index c10faf46568..ac40e815724 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -20,7 +20,7 @@ sage: A.<Y> = QQ[] sage: R.<X> = LaurentPolynomialRing(A) - sage: matrix(R,2,2,[X,0,0,1]) + sage: matrix(R,2,2,[X,0,0,1]) # needs sage.modules [X 0] [0 1] @@ -42,33 +42,40 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.element import parent -from sage.structure.parent import Parent -from sage.rings.infinity import infinity +from sage.misc.lazy_import import LazyImport +from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial, LaurentPolynomial_univariate +from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.misc.latex import latex -from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_mpair, LaurentPolynomial_univariate -from sage.rings.ring import CommutativeRing +from sage.structure.element import parent -import sage.rings.polynomial.laurent_polynomial_ideal as lp_ideal def is_LaurentPolynomialRing(R): """ - Returns True if and only if R is a Laurent polynomial ring. + Return ``True`` if and only if R is a Laurent polynomial ring. EXAMPLES:: sage: from sage.rings.polynomial.laurent_polynomial_ring import is_LaurentPolynomialRing - sage: P = PolynomialRing(QQ,2,'x') + sage: P = PolynomialRing(QQ, 2, 'x') sage: is_LaurentPolynomialRing(P) + doctest:warning... + DeprecationWarning: is_LaurentPolynomialRing is deprecated; use isinstance(..., + sage.rings.polynomial.laurent_polynomial_ring_base.LaurentPolynomialRing_generic) instead + See https://github.com/sagemath/sage/issues/35229 for details. False - sage: R = LaurentPolynomialRing(QQ,3,'x') - sage: is_LaurentPolynomialRing(R) + sage: R = LaurentPolynomialRing(QQ,3,'x') # needs sage.modules + sage: is_LaurentPolynomialRing(R) # needs sage.modules True """ + from sage.misc.superseded import deprecation + deprecation(35229, + "is_LaurentPolynomialRing is deprecated; use " + "isinstance(..., sage.rings.polynomial.laurent_polynomial_ring_base." + "LaurentPolynomialRing_generic) instead") return isinstance(R, LaurentPolynomialRing_generic) + _cache = {} def LaurentPolynomialRing(base_ring, *args, **kwds): r""" @@ -82,7 +89,7 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): 3. ``LaurentPolynomialRing(base_ring, name, n, order='degrevlex')`` 4. ``LaurentPolynomialRing(base_ring, n, name, order='degrevlex')`` - The optional arguments sparse and order *must* be explicitly + The optional arguments ``sparse`` and ``order`` *must* be explicitly named, and the other arguments must be given positionally. INPUT: @@ -95,10 +102,10 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): - ``order`` -- string or :class:`~sage.rings.polynomial.term_order.TermOrder`, e.g., - - ``'degrevlex'`` (default) -- degree reverse lexicographic - - ``'lex'`` -- lexicographic - - ``'deglex'`` -- degree lexicographic - - ``TermOrder('deglex',3) + TermOrder('deglex',3)`` -- block ordering + - ``'degrevlex'`` (default) -- degree reverse lexicographic + - ``'lex'`` -- lexicographic + - ``'deglex'`` -- degree lexicographic + - ``TermOrder('deglex',3) + TermOrder('deglex',3)`` -- block ordering OUTPUT: @@ -114,9 +121,9 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: R.<x,y> = LaurentPolynomialRing(QQ,2); R + sage: R.<x,y> = LaurentPolynomialRing(QQ, 2); R # needs sage.modules Multivariate Laurent Polynomial Ring in x, y over Rational Field - sage: f = x^2 - 2*y^-2 + sage: f = x^2 - 2*y^-2 # needs sage.modules You can't just globally change the names of those variables. This is because objects all over Sage could have pointers to @@ -124,7 +131,7 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: R._assign_names(['z','w']) + sage: R._assign_names(['z','w']) # needs sage.modules Traceback (most recent call last): ... ValueError: variable names cannot be changed after object creation. @@ -157,7 +164,8 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): Univariate Laurent Polynomial Ring in abc over Rational Field sage: R.<w> = LaurentPolynomialRing(PolynomialRing(GF(7),'k')); R - Univariate Laurent Polynomial Ring in w over Univariate Polynomial Ring in k over Finite Field of size 7 + Univariate Laurent Polynomial Ring in w over + Univariate Polynomial Ring in k over Finite Field of size 7 Rings with different variables are different:: @@ -168,24 +176,25 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: R = LaurentPolynomialRing(QQ, 'a,b,c'); R + sage: R = LaurentPolynomialRing(QQ, 'a,b,c'); R # needs sage.modules Multivariate Laurent Polynomial Ring in a, b, c over Rational Field - sage: S = LaurentPolynomialRing(QQ, ['a','b','c']); S + sage: S = LaurentPolynomialRing(QQ, ['a','b','c']); S # needs sage.modules Multivariate Laurent Polynomial Ring in a, b, c over Rational Field - sage: T = LaurentPolynomialRing(QQ, ('a','b','c')); T + sage: T = LaurentPolynomialRing(QQ, ('a','b','c')); T # needs sage.modules Multivariate Laurent Polynomial Ring in a, b, c over Rational Field All three rings are identical. :: - sage: (R is S) and (S is T) + sage: (R is S) and (S is T) # needs sage.modules True There is a unique Laurent polynomial ring with each term order:: + sage: # needs sage.modules sage: R = LaurentPolynomialRing(QQ, 'x,y,z', order='degrevlex'); R Multivariate Laurent Polynomial Ring in x, y, z over Rational Field sage: S = LaurentPolynomialRing(QQ, 'x,y,z', order='invlex'); S @@ -203,24 +212,27 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: LaurentPolynomialRing(QQ, 'x', 10) - Multivariate Laurent Polynomial Ring in x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 over Rational Field + sage: LaurentPolynomialRing(QQ, 'x', 10) # needs sage.modules + Multivariate Laurent Polynomial Ring in x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 + over Rational Field - sage: LaurentPolynomialRing(GF(7), 'y', 5) - Multivariate Laurent Polynomial Ring in y0, y1, y2, y3, y4 over Finite Field of size 7 + sage: LaurentPolynomialRing(GF(7), 'y', 5) # needs sage.modules + Multivariate Laurent Polynomial Ring in y0, y1, y2, y3, y4 + over Finite Field of size 7 - sage: LaurentPolynomialRing(QQ, 'y', 3, sparse=True) + sage: LaurentPolynomialRing(QQ, 'y', 3, sparse=True) # needs sage.modules Multivariate Laurent Polynomial Ring in y0, y1, y2 over Rational Field By calling the :meth:`~sage.structure.category_object.CategoryObject.inject_variables` method, all those variable names are available for interactive use:: - sage: R = LaurentPolynomialRing(GF(7),15,'w'); R - Multivariate Laurent Polynomial Ring in w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14 over Finite Field of size 7 - sage: R.inject_variables() + sage: R = LaurentPolynomialRing(GF(7), 15, 'w'); R # needs sage.modules + Multivariate Laurent Polynomial Ring in w0, w1, w2, w3, w4, w5, w6, w7, + w8, w9, w10, w11, w12, w13, w14 over Finite Field of size 7 + sage: R.inject_variables() # needs sage.modules Defining w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14 - sage: (w0 + 2*w8 + w13)^2 + sage: (w0 + 2*w8 + w13)^2 # needs sage.modules w0^2 + 4*w0*w8 + 4*w8^2 + 2*w0*w13 + 4*w8*w13 + w13^2 """ from sage.rings.polynomial.polynomial_ring import is_PolynomialRing @@ -343,6 +355,7 @@ def _split_laurent_polynomial_dict_(P, M, d): TESTS:: + sage: # needs sage.modules sage: L.<a, b, c, d> = LaurentPolynomialRing(ZZ) sage: M = LaurentPolynomialRing(ZZ, 'c, d') sage: N = LaurentPolynomialRing(M, 'a, b') @@ -399,6 +412,7 @@ def from_fraction_field(L, x): EXAMPLES:: + sage: # needs sage.modules sage: from sage.rings.polynomial.laurent_polynomial_ring import from_fraction_field sage: L.<x, y> = LaurentPolynomialRing(ZZ) sage: F = L.fraction_field() @@ -413,495 +427,6 @@ def from_fraction_field(L, x): else: raise TypeError("fraction must have unit denominator") -class LaurentPolynomialRing_generic(CommutativeRing, Parent): - """ - Laurent polynomial ring (base class). - - EXAMPLES: - - This base class inherits from :class:`~sage.rings.ring.CommutativeRing`. - Since :trac:`11900`, it is also initialised as such:: - - sage: R.<x1,x2> = LaurentPolynomialRing(QQ) - sage: R.category() - Join of Category of unique factorization domains and Category of commutative algebras over (number fields and quotient fields and metric spaces) and Category of infinite sets - sage: TestSuite(R).run() - - """ - def __init__(self, R): - """ - EXAMPLES:: - - sage: R = LaurentPolynomialRing(QQ,2,'x') - sage: R == loads(dumps(R)) - True - """ - self._n = R.ngens() - self._R = R - names = R.variable_names() - self._one_element = self.element_class(self, R.one()) - CommutativeRing.__init__(self, R.base_ring(), names=names, - category=R.category()) - - def ngens(self): - """ - Return the number of generators of ``self``. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').ngens() - 2 - sage: LaurentPolynomialRing(QQ,1,'x').ngens() - 1 - """ - return self._n - - def gen(self, i=0): - r""" - Returns the `i^{th}` generator of self. If i is not specified, then - the first generator will be returned. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').gen() - x0 - sage: LaurentPolynomialRing(QQ,2,'x').gen(0) - x0 - sage: LaurentPolynomialRing(QQ,2,'x').gen(1) - x1 - - TESTS:: - - sage: LaurentPolynomialRing(QQ,2,'x').gen(3) - Traceback (most recent call last): - ... - ValueError: generator not defined - """ - if i < 0 or i >= self._n: - raise ValueError("generator not defined") - try: - return self.__generators[i] - except AttributeError: - self.__generators = tuple(self(x) for x in self._R.gens()) - return self.__generators[i] - - - def variable_names_recursive(self, depth=infinity): - r""" - Return the list of variable names of this ring and its base rings, - as if it were a single multi-variate Laurent polynomial. - - INPUT: - - - ``depth`` -- an integer or :mod:`Infinity <sage.rings.infinity>`. - - OUTPUT: - - A tuple of strings. - - EXAMPLES:: - - sage: T = LaurentPolynomialRing(QQ, 'x') - sage: S = LaurentPolynomialRing(T, 'y') - sage: R = LaurentPolynomialRing(S, 'z') - sage: R.variable_names_recursive() - ('x', 'y', 'z') - sage: R.variable_names_recursive(2) - ('y', 'z') - """ - if depth <= 0: - return () - if depth == 1: - return self.variable_names() - my_vars = self.variable_names() - try: - return self.base_ring().variable_names_recursive(depth - len(my_vars)) + my_vars - except AttributeError: - return my_vars - - def is_integral_domain(self, proof=True): - """ - Returns True if self is an integral domain. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').is_integral_domain() - True - - The following used to fail; see :trac:`7530`:: - - sage: L = LaurentPolynomialRing(ZZ, 'X') - sage: L['Y'] - Univariate Polynomial Ring in Y over Univariate Laurent Polynomial Ring in X over Integer Ring - """ - return self.base_ring().is_integral_domain(proof) - - def is_noetherian(self): - """ - Returns True if self is Noetherian. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').is_noetherian() - Traceback (most recent call last): - ... - NotImplementedError - """ - raise NotImplementedError - - def construction(self): - """ - Return the construction of ``self``. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x,y').construction() - (LaurentPolynomialFunctor, - Univariate Laurent Polynomial Ring in x over Rational Field) - - """ - from sage.categories.pushout import LaurentPolynomialFunctor - vars = self.variable_names() - if len(vars) == 1: - return LaurentPolynomialFunctor(vars[0], False), self.base_ring() - else: - return LaurentPolynomialFunctor(vars[-1], True), LaurentPolynomialRing(self.base_ring(), vars[:-1]) - - def completion(self, p, prec=20, extras=None): - """ - EXAMPLES:: - - sage: P.<x>=LaurentPolynomialRing(QQ) - sage: P - Univariate Laurent Polynomial Ring in x over Rational Field - sage: PP=P.completion(x) - sage: PP - Laurent Series Ring in x over Rational Field - sage: f=1-1/x - sage: PP(f) - -x^-1 + 1 - sage: 1/PP(f) - -x - x^2 - x^3 - x^4 - x^5 - x^6 - x^7 - x^8 - x^9 - x^10 - x^11 - x^12 - x^13 - x^14 - x^15 - x^16 - x^17 - x^18 - x^19 - x^20 + O(x^21) - - TESTS: - - Check that the precision is taken into account (:trac:`24431`):: - - sage: L = LaurentPolynomialRing(QQ, 'x') - sage: L.completion('x', 100).default_prec() - 100 - sage: L.completion('x', 20).default_prec() - 20 - """ - if str(p) == self._names[0] and self._n == 1: - from sage.rings.laurent_series_ring import LaurentSeriesRing - R = self.polynomial_ring().completion(self._names[0], prec) - return LaurentSeriesRing(R) - else: - raise TypeError("Cannot complete %s with respect to %s" % (self, p)) - - def remove_var(self, var): - """ - EXAMPLES:: - - sage: R = LaurentPolynomialRing(QQ,'x,y,z') - sage: R.remove_var('x') - Multivariate Laurent Polynomial Ring in y, z over Rational Field - sage: R.remove_var('x').remove_var('y') - Univariate Laurent Polynomial Ring in z over Rational Field - """ - vars = list(self.variable_names()) - vars.remove(str(var)) - return LaurentPolynomialRing(self.base_ring(), vars) - - def _coerce_map_from_(self, R): - """ - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ) - sage: L.coerce_map_from(QQ) - Generic morphism: - From: Rational Field - To: Multivariate Laurent Polynomial Ring in x, y over Rational Field - - Let us check that coercion between Laurent Polynomials over - different base rings works (:trac:`15345`):: - - sage: R = LaurentPolynomialRing(ZZ, 'x') - sage: T = LaurentPolynomialRing(QQ, 'x') - sage: R.gen() + 3*T.gen() - 4*x - """ - if R is self._R: - return self._generic_coerce_map(R) - f = self._coerce_map_via([self._R], R) - if f is not None: - return f - if (isinstance(R, LaurentPolynomialRing_generic) - and self._R.has_coerce_map_from(R._R)): - return self._generic_coerce_map(R) - - def __eq__(self, right): - """ - Check whether ``self`` is equal to ``right``. - - EXAMPLES:: - - sage: R = LaurentPolynomialRing(QQ,'x,y,z') - sage: P = LaurentPolynomialRing(ZZ,'x,y,z') - sage: Q = LaurentPolynomialRing(QQ,'x,y') - - sage: R == R - True - sage: R == Q - False - sage: Q == P - False - sage: P == R - False - """ - if type(self) != type(right): - return False - return self._R == right._R - - def __ne__(self, other): - """ - Check whether ``self`` is not equal to ``other``. - - EXAMPLES:: - - sage: R = LaurentPolynomialRing(QQ,'x,y,z') - sage: P = LaurentPolynomialRing(ZZ,'x,y,z') - sage: Q = LaurentPolynomialRing(QQ,'x,y') - - sage: R != R - False - sage: R != Q - True - sage: Q != P - True - sage: P != R - True - """ - return not (self == other) - - def __hash__(self): - """ - Return the hash of ``self``. - - EXAMPLES:: - - sage: h1 = hash(LaurentPolynomialRing(ZZ,'x,y,z')) - sage: h2 = hash(LaurentPolynomialRing(ZZ,'x,y,z')) - sage: h3 = hash(LaurentPolynomialRing(QQ,'x,y,z')) - sage: h4 = hash(LaurentPolynomialRing(ZZ,'x,y')) - sage: h1 == h2 and h1 != h3 and h1 != h4 - True - """ - return hash(self._R) ^ 12059065606945654693 - - def _latex_(self): - r""" - EXAMPLES:: - - sage: latex(LaurentPolynomialRing(QQ,2,'x')) - \Bold{Q}[x_{0}^{\pm 1}, x_{1}^{\pm 1}] - """ - vars = ', '.join(a + r'^{\pm 1}' for a in self.latex_variable_names()) - return "%s[%s]" % (latex(self.base_ring()), vars) - - def _ideal_class_(self, n=0): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x')._ideal_class_() - Traceback (most recent call last): - ... - NotImplementedError - """ - # One may eventually want ideal classes in these guys. - raise NotImplementedError - - def ideal(self, *args, **kwds): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').ideal([1]) - Ideal (1) of Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field - - TESTS: - - check that :trac:`26421` is fixed: - - sage: R.<t> = LaurentPolynomialRing(ZZ) - sage: P.<x> = PolynomialRing(R) - sage: p = x-t - sage: p.content_ideal() # indirect doctest - Ideal (-t, 1) of Univariate Laurent Polynomial Ring in t over Integer Ring - """ - return lp_ideal.LaurentPolynomialIdeal(self, *args, **kwds) - - def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): - """ - EXAMPLES:: - - sage: T.<t> = ZZ[] - sage: K.<i> = NumberField(t^2 + 1) - sage: L.<x,y> = LaurentPolynomialRing(K) - sage: L._is_valid_homomorphism_(K, (K(1/2), K(3/2))) - True - sage: Q5 = Qp(5); i5 = Q5(-1).sqrt() - sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2))) # no coercion - False - sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2)), base_map=K.hom([i5])) - True - """ - if base_map is None and not codomain.has_coerce_map_from(self.base_ring()): - # we need that elements of the base ring - # canonically coerce into codomain. - return False - for a in im_gens: - # in addition, the image of each generator must be invertible. - if not a.is_unit(): - return False - return True - - def term_order(self): - """ - Returns the term order of self. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').term_order() - Degree reverse lexicographic term order - - """ - return self._R.term_order() - - def is_finite(self): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').is_finite() - False - - """ - return False - - def is_field(self, proof = True): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').is_field() - False - """ - return False - - def polynomial_ring(self): - """ - Returns the polynomial ring associated with self. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').polynomial_ring() - Multivariate Polynomial Ring in x0, x1 over Rational Field - sage: LaurentPolynomialRing(QQ,1,'x').polynomial_ring() - Multivariate Polynomial Ring in x over Rational Field - """ - return self._R - - def characteristic(self): - """ - Returns the characteristic of the base ring. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').characteristic() - 0 - sage: LaurentPolynomialRing(GF(3),2,'x').characteristic() - 3 - - """ - return self.base_ring().characteristic() - - def krull_dimension(self): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').krull_dimension() - Traceback (most recent call last): - ... - NotImplementedError - """ - raise NotImplementedError - - def random_element(self, low_degree = -2, high_degree = 2, terms = 5, choose_degree=False,*args, **kwds): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').random_element() - Traceback (most recent call last): - ... - NotImplementedError - """ - raise NotImplementedError - - def is_exact(self): - """ - Returns True if the base ring is exact. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').is_exact() - True - sage: LaurentPolynomialRing(RDF,2,'x').is_exact() - False - """ - return self.base_ring().is_exact() - - def change_ring(self, base_ring=None, names=None, sparse=False, order=None): - """ - EXAMPLES:: - - sage: R = LaurentPolynomialRing(QQ,2,'x') - sage: R.change_ring(ZZ) - Multivariate Laurent Polynomial Ring in x0, x1 over Integer Ring - - Check that the distinction between a univariate ring and a multivariate ring with one - generator is preserved:: - - sage: P.<x> = LaurentPolynomialRing(QQ, 1) - sage: P - Multivariate Laurent Polynomial Ring in x over Rational Field - sage: K.<i> = CyclotomicField(4) - sage: P.change_ring(K) - Multivariate Laurent Polynomial Ring in x over Cyclotomic Field of order 4 and degree 2 - """ - if base_ring is None: - base_ring = self.base_ring() - if names is None: - names = self.variable_names() - if isinstance(self, LaurentPolynomialRing_univariate): - return LaurentPolynomialRing(base_ring, names[0], sparse = sparse) - - if order is None: - order = self.polynomial_ring().term_order() - return LaurentPolynomialRing(base_ring, self._n, names, order = order) - - def fraction_field(self): - """ - The fraction field is the same as the fraction field of the - polynomial ring. - - EXAMPLES:: - - sage: L.<x> = LaurentPolynomialRing(QQ) - sage: L.fraction_field() - Fraction Field of Univariate Polynomial Ring in x over Rational Field - sage: (x^-1 + 2) / (x - 1) - (2*x + 1)/(x^2 - x) - """ - return self.polynomial_ring().fraction_field() class LaurentPolynomialRing_univariate(LaurentPolynomialRing_generic): def __init__(self, R): @@ -934,7 +459,7 @@ def _repr_(self): sage: LaurentPolynomialRing(QQ,'x') # indirect doctest Univariate Laurent Polynomial Ring in x over Rational Field """ - return "Univariate Laurent Polynomial Ring in %s over %s"%(self._R.variable_name(), self._R.base_ring()) + return "Univariate Laurent Polynomial Ring in %s over %s" % (self._R.variable_name(), self._R.base_ring()) def _element_constructor_(self, x): """ @@ -944,18 +469,19 @@ def _element_constructor_(self, x): sage: L(1/2) 1/2 - sage: L(x + 3/x) + sage: L(x + 3/x) # needs sage.symbolic 3*x^-1 + x :: - sage: L(exp(x)) + sage: L(exp(x)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert e^x to a rational :: + sage: # needs sage.modules sage: U = LaurentPolynomialRing(QQ, 'a') sage: V = LaurentPolynomialRing(QQ, 'c') sage: L.<a, b, c, d> = LaurentPolynomialRing(QQ) @@ -968,6 +494,7 @@ def _element_constructor_(self, x): sage: V(Mc) c + sage: # needs sage.modules sage: M(L(0)) 0 sage: N(L(0)) @@ -986,8 +513,8 @@ def _element_constructor_(self, x): sage: C.<c> = LaurentPolynomialRing(B) sage: B(C(b)) b - sage: D.<d, e> = LaurentPolynomialRing(B) - sage: B(D(b)) + sage: D.<d, e> = LaurentPolynomialRing(B) # needs sage.modules + sage: B(D(b)) # needs sage.modules b TESTS: @@ -1009,7 +536,7 @@ def _element_constructor_(self, x): if isinstance(x, Expression): return x.laurent_polynomial(ring=self) - elif isinstance(x, (LaurentPolynomial_univariate, LaurentPolynomial_mpair)): + elif isinstance(x, LaurentPolynomial): P = x.parent() if set(self.variable_names()) & set(P.variable_names()): if isinstance(x, LaurentPolynomial_univariate): @@ -1050,16 +577,17 @@ def __reduce__(self): """ return LaurentPolynomialRing_univariate, (self._R,) + class LaurentPolynomialRing_mpair(LaurentPolynomialRing_generic): def __init__(self, R): """ EXAMPLES:: - sage: L = LaurentPolynomialRing(QQ,2,'x') - sage: type(L) + sage: L = LaurentPolynomialRing(QQ,2,'x') # needs sage.modules + sage: type(L) # needs sage.modules <class 'sage.rings.polynomial.laurent_polynomial_ring.LaurentPolynomialRing_mpair_with_category'> - sage: L == loads(dumps(L)) + sage: L == loads(dumps(L)) # needs sage.modules True """ if R.ngens() <= 0: @@ -1068,18 +596,18 @@ def __init__(self, R): raise ValueError("base ring must be an integral domain") LaurentPolynomialRing_generic.__init__(self, R) - Element = LaurentPolynomial_mpair + Element = LazyImport('sage.rings.polynomial.laurent_polynomial_mpair', 'LaurentPolynomial_mpair') def _repr_(self): """ TESTS:: - sage: LaurentPolynomialRing(QQ,2,'x').__repr__() + sage: LaurentPolynomialRing(QQ,2,'x').__repr__() # needs sage.modules 'Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field' - sage: LaurentPolynomialRing(QQ,1,'x').__repr__() + sage: LaurentPolynomialRing(QQ,1,'x').__repr__() # needs sage.modules 'Multivariate Laurent Polynomial Ring in x over Rational Field' """ - return "Multivariate Laurent Polynomial Ring in %s over %s"%(", ".join(self._R.variable_names()), self._R.base_ring()) + return "Multivariate Laurent Polynomial Ring in %s over %s" % (", ".join(self._R.variable_names()), self._R.base_ring()) def monomial(self, *args): r""" @@ -1087,6 +615,7 @@ def monomial(self, *args): EXAMPLES:: + sage: # needs sage.modules sage: L = LaurentPolynomialRing(QQ, 'x', 2) sage: L.monomial(-3, 5) x0^-3*x1^5 @@ -1097,11 +626,11 @@ def monomial(self, *args): sage: L.monomial(-2, -3) x0^-2*x1^-3 - sage: x0, x1 = L.gens() - sage: L.monomial(-1, 2) == x0^-1 * x1^2 + sage: x0, x1 = L.gens() # needs sage.modules + sage: L.monomial(-1, 2) == x0^-1 * x1^2 # needs sage.modules True - sage: L.monomial(1, 2, 3) + sage: L.monomial(1, 2, 3) # needs sage.modules Traceback (most recent call last): ... TypeError: tuple key must have same length as ngens @@ -1117,25 +646,26 @@ def _element_constructor_(self, x, mon=None): """ EXAMPLES:: - sage: L = LaurentPolynomialRing(QQ,2,'x') - sage: L(1/2) + sage: L = LaurentPolynomialRing(QQ,2,'x') # needs sage.modules + sage: L(1/2) # needs sage.modules 1/2 - sage: M = LaurentPolynomialRing(QQ, 'x, y') - sage: var('x, y') + sage: M = LaurentPolynomialRing(QQ, 'x, y') # needs sage.modules + sage: var('x, y') # needs sage.modules sage.symbolic (x, y) - sage: M(x/y + 3/x) + sage: M(x/y + 3/x) # needs sage.modules sage.symbolic x*y^-1 + 3*x^-1 :: - sage: M(exp(x)) + sage: M(exp(x)) # needs sage.modules sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert e^x to a rational :: + sage: # needs sage.modules sage: L.<a, b, c, d> = LaurentPolynomialRing(QQ) sage: M = LaurentPolynomialRing(QQ, 'c, d') sage: Mc, Md = M.gens() @@ -1152,6 +682,7 @@ def _element_constructor_(self, x, mon=None): sage: L(Nb) b + sage: # needs sage.modules sage: M(L(0)) 0 sage: N(L(0)) @@ -1161,6 +692,7 @@ def _element_constructor_(self, x, mon=None): sage: L(N(0)) 0 + sage: # needs sage.modules sage: U = LaurentPolynomialRing(QQ, 'a') sage: Ua = U.gen() sage: V = LaurentPolynomialRing(QQ, 'c') @@ -1174,6 +706,7 @@ def _element_constructor_(self, x, mon=None): sage: M(Vc) c + sage: # needs sage.modules sage: P = LaurentPolynomialRing(QQ, 'a, b') sage: Q = LaurentPolynomialRing(P, 'c, d') sage: Q(P.0) @@ -1181,6 +714,7 @@ def _element_constructor_(self, x, mon=None): :: + sage: # needs sage.modules sage: A.<a> = LaurentPolynomialRing(QQ) sage: B.<b> = LaurentPolynomialRing(A) sage: C = LaurentPolynomialRing(QQ, 'a, b') @@ -1193,6 +727,7 @@ def _element_constructor_(self, x, mon=None): :: + sage: # needs sage.modules sage: from sage.rings.polynomial.polydict import ETuple sage: R.<x,y,z> = LaurentPolynomialRing(QQ) sage: mon = ETuple({}, int(3)) @@ -1204,7 +739,8 @@ def _element_constructor_(self, x, mon=None): :: - sage: RL = R.localization(x+1) + sage: # needs sage.modules + sage: RL = R.localization(x + 1) sage: xi = RL(~x) sage: R(xi) == ~x # indirect doctests True @@ -1224,7 +760,7 @@ def _element_constructor_(self, x, mon=None): elif isinstance(x, Expression): return x.laurent_polynomial(ring=self) - elif isinstance(x, (LaurentPolynomial_univariate, LaurentPolynomial_mpair)): + elif isinstance(x, LaurentPolynomial): if self.variable_names() == P.variable_names(): # No special processing needed here; # handled by LaurentPolynomial_mpair.__init__ @@ -1263,8 +799,8 @@ def __reduce__(self): EXAMPLES:: - sage: L = LaurentPolynomialRing(QQ, 2, 'x') - sage: loads(dumps(L)) == L + sage: L = LaurentPolynomialRing(QQ, 2, 'x') # needs sage.modules + sage: loads(dumps(L)) == L # needs sage.modules True """ return LaurentPolynomialRing_mpair, (self._R,) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py new file mode 100644 index 00000000000..0c9022c492c --- /dev/null +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -0,0 +1,554 @@ +# sage.doctest: needs sage.modules +r""" +Ring of Laurent Polynomials (base class) + +If `R` is a commutative ring, then the ring of Laurent polynomials in `n` +variables over `R` is `R[x_1^{\pm 1}, x_2^{\pm 1}, \ldots, x_n^{\pm 1}]`. + +AUTHORS: + +- David Roe (2008-2-23): created +- David Loeffler (2009-07-10): cleaned up docstrings +""" +# **************************************************************************** +# Copyright (C) 2008 David Roe <roed@math.harvard.edu>, +# William Stein <wstein@gmail.com>, +# Mike Hansen <mhansen@gmail.com> +# Vincent Delecroix <20100.delecroix@gmail.com> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + + +from sage.rings.infinity import infinity +from sage.rings.ring import CommutativeRing +from sage.structure.parent import Parent + + +class LaurentPolynomialRing_generic(CommutativeRing, Parent): + """ + Laurent polynomial ring (base class). + + EXAMPLES: + + This base class inherits from :class:`~sage.rings.ring.CommutativeRing`. + Since :trac:`11900`, it is also initialised as such:: + + sage: R.<x1,x2> = LaurentPolynomialRing(QQ) + sage: R.category() + Join of Category of unique factorization domains + and Category of commutative algebras + over (number fields and quotient fields and metric spaces) + and Category of infinite sets + sage: TestSuite(R).run() + + """ + def __init__(self, R): + """ + EXAMPLES:: + + sage: R = LaurentPolynomialRing(QQ, 2, 'x') + sage: R == loads(dumps(R)) + True + """ + self._n = R.ngens() + self._R = R + names = R.variable_names() + self._one_element = self.element_class(self, R.one()) + CommutativeRing.__init__(self, R.base_ring(), names=names, + category=R.category()) + + def ngens(self): + """ + Return the number of generators of ``self``. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').ngens() + 2 + sage: LaurentPolynomialRing(QQ, 1, 'x').ngens() + 1 + """ + return self._n + + def gen(self, i=0): + r""" + Returns the `i^{th}` generator of self. If i is not specified, then + the first generator will be returned. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').gen() + x0 + sage: LaurentPolynomialRing(QQ, 2, 'x').gen(0) + x0 + sage: LaurentPolynomialRing(QQ, 2, 'x').gen(1) + x1 + + TESTS:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').gen(3) + Traceback (most recent call last): + ... + ValueError: generator not defined + """ + if i < 0 or i >= self._n: + raise ValueError("generator not defined") + try: + return self.__generators[i] + except AttributeError: + self.__generators = tuple(self(x) for x in self._R.gens()) + return self.__generators[i] + + def variable_names_recursive(self, depth=infinity): + r""" + Return the list of variable names of this ring and its base rings, + as if it were a single multi-variate Laurent polynomial. + + INPUT: + + - ``depth`` -- an integer or :mod:`Infinity <sage.rings.infinity>`. + + OUTPUT: + + A tuple of strings. + + EXAMPLES:: + + sage: T = LaurentPolynomialRing(QQ, 'x') + sage: S = LaurentPolynomialRing(T, 'y') + sage: R = LaurentPolynomialRing(S, 'z') + sage: R.variable_names_recursive() + ('x', 'y', 'z') + sage: R.variable_names_recursive(2) + ('y', 'z') + """ + if depth <= 0: + return () + if depth == 1: + return self.variable_names() + my_vars = self.variable_names() + try: + return self.base_ring().variable_names_recursive(depth - len(my_vars)) + my_vars + except AttributeError: + return my_vars + + def is_integral_domain(self, proof=True): + """ + Return ``True`` if self is an integral domain. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').is_integral_domain() + True + + The following used to fail; see :trac:`7530`:: + + sage: L = LaurentPolynomialRing(ZZ, 'X') + sage: L['Y'] + Univariate Polynomial Ring in Y over + Univariate Laurent Polynomial Ring in X over Integer Ring + """ + return self.base_ring().is_integral_domain(proof) + + def is_noetherian(self): + """ + Return ``True`` if self is Noetherian. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').is_noetherian() + Traceback (most recent call last): + ... + NotImplementedError + """ + raise NotImplementedError + + def construction(self): + """ + Return the construction of ``self``. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x,y').construction() + (LaurentPolynomialFunctor, + Univariate Laurent Polynomial Ring in x over Rational Field) + + """ + from sage.categories.pushout import LaurentPolynomialFunctor + from .laurent_polynomial_ring import LaurentPolynomialRing + + vars = self.variable_names() + if len(vars) == 1: + return LaurentPolynomialFunctor(vars[0], False), self.base_ring() + else: + return LaurentPolynomialFunctor(vars[-1], True), LaurentPolynomialRing(self.base_ring(), vars[:-1]) + + def completion(self, p=None, prec=20, extras=None): + r""" + Return the completion of ``self``. + + Currently only implemented for the ring of formal Laurent series. + The ``prec`` variable controls the precision used in the + Laurent series ring. If ``prec`` is `\infty`, then this + returns a :class:`LazyLaurentSeriesRing`. + + EXAMPLES:: + + sage: P.<x> = LaurentPolynomialRing(QQ); P + Univariate Laurent Polynomial Ring in x over Rational Field + sage: PP = P.completion(x); PP + Laurent Series Ring in x over Rational Field + sage: f = 1 - 1/x + sage: PP(f) + -x^-1 + 1 + sage: g = 1 / PP(f); g + -x - x^2 - x^3 - x^4 - x^5 - x^6 - x^7 - x^8 - x^9 - x^10 - x^11 + - x^12 - x^13 - x^14 - x^15 - x^16 - x^17 - x^18 - x^19 - x^20 + O(x^21) + sage: 1 / g + -x^-1 + 1 + O(x^19) + + sage: # needs sage.combinat + sage: PP = P.completion(x, prec=oo); PP + Lazy Laurent Series Ring in x over Rational Field + sage: g = 1 / PP(f); g + -x - x^2 - x^3 + O(x^4) + sage: 1 / g == f + True + + TESTS: + + Check that the precision is taken into account (:trac:`24431`):: + + sage: L = LaurentPolynomialRing(QQ, 'x') + sage: L.completion('x', 100).default_prec() + 100 + sage: L.completion('x', 20).default_prec() + 20 + """ + if p is None or str(p) == self._names[0] and self._n == 1: + if prec == float('inf'): + from sage.rings.lazy_series_ring import LazyLaurentSeriesRing + sparse = self.polynomial_ring().is_sparse() + return LazyLaurentSeriesRing(self.base_ring(), names=(self._names[0],), sparse=sparse) + from sage.rings.laurent_series_ring import LaurentSeriesRing + R = self.polynomial_ring().completion(self._names[0], prec) + return LaurentSeriesRing(R) + + raise TypeError("cannot complete %s with respect to %s" % (self, p)) + + def remove_var(self, var): + """ + EXAMPLES:: + + sage: R = LaurentPolynomialRing(QQ,'x,y,z') + sage: R.remove_var('x') + Multivariate Laurent Polynomial Ring in y, z over Rational Field + sage: R.remove_var('x').remove_var('y') + Univariate Laurent Polynomial Ring in z over Rational Field + """ + from .laurent_polynomial_ring import LaurentPolynomialRing + + vars = list(self.variable_names()) + vars.remove(str(var)) + return LaurentPolynomialRing(self.base_ring(), vars) + + def _coerce_map_from_(self, R): + """ + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ) + sage: L.coerce_map_from(QQ) + Generic morphism: + From: Rational Field + To: Multivariate Laurent Polynomial Ring in x, y over Rational Field + + Let us check that coercion between Laurent Polynomials over + different base rings works (:trac:`15345`):: + + sage: R = LaurentPolynomialRing(ZZ, 'x') + sage: T = LaurentPolynomialRing(QQ, 'x') + sage: R.gen() + 3*T.gen() + 4*x + """ + if R is self._R: + return self._generic_coerce_map(R) + f = self._coerce_map_via([self._R], R) + if f is not None: + return f + if (isinstance(R, LaurentPolynomialRing_generic) + and self._R.has_coerce_map_from(R._R)): + return self._generic_coerce_map(R) + + def __eq__(self, right): + """ + Check whether ``self`` is equal to ``right``. + + EXAMPLES:: + + sage: R = LaurentPolynomialRing(QQ,'x,y,z') + sage: P = LaurentPolynomialRing(ZZ,'x,y,z') + sage: Q = LaurentPolynomialRing(QQ,'x,y') + + sage: R == R + True + sage: R == Q + False + sage: Q == P + False + sage: P == R + False + """ + if type(self) is not type(right): + return False + return self._R == right._R + + def __ne__(self, other): + """ + Check whether ``self`` is not equal to ``other``. + + EXAMPLES:: + + sage: R = LaurentPolynomialRing(QQ,'x,y,z') + sage: P = LaurentPolynomialRing(ZZ,'x,y,z') + sage: Q = LaurentPolynomialRing(QQ,'x,y') + + sage: R != R + False + sage: R != Q + True + sage: Q != P + True + sage: P != R + True + """ + return not (self == other) + + def __hash__(self): + """ + Return the hash of ``self``. + + EXAMPLES:: + + sage: h1 = hash(LaurentPolynomialRing(ZZ,'x,y,z')) + sage: h2 = hash(LaurentPolynomialRing(ZZ,'x,y,z')) + sage: h3 = hash(LaurentPolynomialRing(QQ,'x,y,z')) + sage: h4 = hash(LaurentPolynomialRing(ZZ,'x,y')) + sage: h1 == h2 and h1 != h3 and h1 != h4 + True + """ + return hash(self._R) ^ 12059065606945654693 + + def _latex_(self): + r""" + EXAMPLES:: + + sage: latex(LaurentPolynomialRing(QQ, 2, 'x')) + \Bold{Q}[x_{0}^{\pm 1}, x_{1}^{\pm 1}] + """ + from sage.misc.latex import latex + + vars = ', '.join(a + r'^{\pm 1}' for a in self.latex_variable_names()) + return "%s[%s]" % (latex(self.base_ring()), vars) + + def _ideal_class_(self, n=0): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x')._ideal_class_() + Traceback (most recent call last): + ... + NotImplementedError + """ + # One may eventually want ideal classes in these guys. + raise NotImplementedError + + def ideal(self, *args, **kwds): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').ideal([1]) + Ideal (1) of Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field + + TESTS: + + check that :trac:`26421` is fixed:: + + sage: R.<t> = LaurentPolynomialRing(ZZ) + sage: P.<x> = PolynomialRing(R) + sage: p = x-t + sage: p.content_ideal() # indirect doctest + Ideal (-t, 1) of Univariate Laurent Polynomial Ring in t over Integer Ring + """ + from sage.rings.polynomial.laurent_polynomial_ideal import LaurentPolynomialIdeal + return LaurentPolynomialIdeal(self, *args, **kwds) + + def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): + """ + EXAMPLES:: + + sage: # needs sage.rings.number_field + sage: T.<t> = ZZ[] + sage: K.<i> = NumberField(t^2 + 1) + sage: L.<x,y> = LaurentPolynomialRing(K) + sage: L._is_valid_homomorphism_(K, (K(1/2), K(3/2))) + True + sage: Q5 = Qp(5); i5 = Q5(-1).sqrt() # needs sage.rings.padics + sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2))) # no coercion # needs sage.rings.padics + False + sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2)), base_map=K.hom([i5])) # needs sage.rings.padics + True + """ + if base_map is None and not codomain.has_coerce_map_from(self.base_ring()): + # we need that elements of the base ring + # canonically coerce into codomain. + return False + for a in im_gens: + # in addition, the image of each generator must be invertible. + if not a.is_unit(): + return False + return True + + def term_order(self): + """ + Returns the term order of self. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').term_order() + Degree reverse lexicographic term order + + """ + return self._R.term_order() + + def is_finite(self): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').is_finite() + False + + """ + return False + + def is_field(self, proof=True): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').is_field() + False + """ + return False + + def polynomial_ring(self): + """ + Returns the polynomial ring associated with self. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').polynomial_ring() + Multivariate Polynomial Ring in x0, x1 over Rational Field + sage: LaurentPolynomialRing(QQ, 1, 'x').polynomial_ring() + Multivariate Polynomial Ring in x over Rational Field + """ + return self._R + + def characteristic(self): + """ + Returns the characteristic of the base ring. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').characteristic() + 0 + sage: LaurentPolynomialRing(GF(3), 2, 'x').characteristic() + 3 + + """ + return self.base_ring().characteristic() + + def krull_dimension(self): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').krull_dimension() + Traceback (most recent call last): + ... + NotImplementedError + """ + raise NotImplementedError + + def random_element(self, low_degree=-2, high_degree=2, terms=5, choose_degree=False,*args, **kwds): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').random_element() + Traceback (most recent call last): + ... + NotImplementedError + """ + raise NotImplementedError + + def is_exact(self): + """ + Return ``True`` if the base ring is exact. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ, 2, 'x').is_exact() + True + sage: LaurentPolynomialRing(RDF, 2, 'x').is_exact() + False + """ + return self.base_ring().is_exact() + + def change_ring(self, base_ring=None, names=None, sparse=False, order=None): + """ + EXAMPLES:: + + sage: R = LaurentPolynomialRing(QQ, 2, 'x') + sage: R.change_ring(ZZ) + Multivariate Laurent Polynomial Ring in x0, x1 over Integer Ring + + Check that the distinction between a univariate ring and a multivariate ring with one + generator is preserved:: + + sage: P.<x> = LaurentPolynomialRing(QQ, 1) + sage: P + Multivariate Laurent Polynomial Ring in x over Rational Field + sage: K.<i> = CyclotomicField(4) # needs sage.rings.number_field + sage: P.change_ring(K) # needs sage.rings.number_field + Multivariate Laurent Polynomial Ring in x over + Cyclotomic Field of order 4 and degree 2 + """ + from .laurent_polynomial_ring import LaurentPolynomialRing, LaurentPolynomialRing_univariate + + if base_ring is None: + base_ring = self.base_ring() + if names is None: + names = self.variable_names() + if isinstance(self, LaurentPolynomialRing_univariate): + return LaurentPolynomialRing(base_ring, names[0], sparse=sparse) + + if order is None: + order = self.polynomial_ring().term_order() + return LaurentPolynomialRing(base_ring, self._n, names, order=order) + + def fraction_field(self): + """ + The fraction field is the same as the fraction field of the + polynomial ring. + + EXAMPLES:: + + sage: L.<x> = LaurentPolynomialRing(QQ) + sage: L.fraction_field() + Fraction Field of Univariate Polynomial Ring in x over Rational Field + sage: (x^-1 + 2) / (x - 1) + (2*x + 1)/(x^2 - x) + """ + return self.polynomial_ring().fraction_field() diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 0be0c676758..70af8250f58 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -64,7 +64,7 @@ def _run_msolve(ideal, options): return msolve_out.stdout -def groebner_basis_degrevlex(ideal): +def groebner_basis_degrevlex(ideal, proof=True): r""" Compute a degrevlex Grรถbner basis using msolve @@ -85,25 +85,27 @@ def groebner_basis_degrevlex(ideal): [c^4 + 38*c^3 - 6*c^2 - 6*c, 30*c^3 + 32*c^2 + b - 14*c, a + 2*b + 2*c - 1] - TESTS:: - - sage: R.<foo, bar> = PolynomialRing(GF(536870909), 2) - sage: I = Ideal([ foo^2 - 1, bar^2 - 1 ]) - sage: I.groebner_basis(algorithm='msolve') # optional - msolve - [bar^2 - 1, foo^2 - 1] + Grรถbner bases over the rationals require `proof=False`:: sage: R.<x, y> = PolynomialRing(QQ, 2) sage: I = Ideal([ x*y - 1, (x-2)^2 + (y-1)^2 - 1]) sage: I.groebner_basis(algorithm='msolve') # optional - msolve Traceback (most recent call last): ... - NotImplementedError: unsupported base field: Rational Field + ValueError: msolve relies on heuristics; please use proof=False + sage: I.groebner_basis(algorithm='msolve', proof=False) # optional - msolve + [x*y - 1, x^2 + y^2 - 4*x - 2*y + 4, y^3 - 2*y^2 + x + 4*y - 4] + + TESTS:: + + sage: R.<foo, bar> = PolynomialRing(GF(536870909), 2) + sage: I = Ideal([ foo^2 - 1, bar^2 - 1 ]) + sage: I.groebner_basis(algorithm='msolve') # optional - msolve + [bar^2 - 1, foo^2 - 1] """ - base = ideal.base_ring() - if not (isinstance(base, FiniteField) and base.is_prime_field() and - base.characteristic() < 2**31): - raise NotImplementedError(f"unsupported base field: {base}") + if ideal.base_ring() is QQ and sage.structure.proof.proof.get_flag(proof, "polynomial"): + raise ValueError("msolve relies on heuristics; please use proof=False") drlpolring = ideal.ring().change_ring(order='degrevlex') msolve_out = _run_msolve(ideal, ["-g", "2"]) diff --git a/src/sage/rings/polynomial/multi_polynomial.pxd b/src/sage/rings/polynomial/multi_polynomial.pxd index 44fdf3edfc4..5dc75e6bd3f 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pxd +++ b/src/sage/rings/polynomial/multi_polynomial.pxd @@ -1,7 +1,11 @@ -from sage.structure.element cimport CommutativeRingElement +from .commutative_polynomial cimport CommutativePolynomial -cdef class MPolynomial(CommutativeRingElement): + +cdef class MPolynomial(CommutativePolynomial): cdef long _hash_c(self) except -1 cpdef _mod_(self, right) cpdef dict _mpoly_dict_recursive(self, tuple vars=*, base_ring=*) + +cdef class MPolynomial_libsingular(MPolynomial): + pass diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 7bb03631661..d0a430bbfd8 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -14,23 +14,24 @@ from sage.rings.integer cimport Integer from sage.rings.integer_ring import ZZ from sage.structure.coerce cimport coercion_model from sage.misc.derivative import multi_derivative +from itertools import chain from sage.misc.misc_c import prod def is_MPolynomial(x): + from sage.misc.superseded import deprecation + deprecation(32709, "the function is_MPolynomial is deprecated; use isinstance(x, sage.rings.polynomial.multi_polynomial.MPolynomial) instead") + return isinstance(x, MPolynomial) from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.categories.map cimport Map -from sage.modules.free_module_element import vector from sage.rings.rational_field import QQ -from sage.rings.complex_interval_field import ComplexIntervalField -from sage.rings.real_mpfr import RealField_class,RealField from sage.rings.polynomial.polydict cimport ETuple from sage.rings.polynomial.polynomial_element cimport Polynomial -cdef class MPolynomial(CommutativeRingElement): +cdef class MPolynomial(CommutativePolynomial): #################### # Some standard conversions @@ -39,7 +40,8 @@ cdef class MPolynomial(CommutativeRingElement): r""" TESTS:: - sage: ZZ(RR['x,y'](0)) # indirect doctest + sage: # needs sage.rings.real_mpfr + sage: ZZ(RR['x,y'](0)) # indirect doctest 0 sage: ZZ(RR['x,y'](0.5)) Traceback (most recent call last): @@ -50,20 +52,23 @@ cdef class MPolynomial(CommutativeRingElement): ... TypeError: unable to convert non-constant polynomial x to Integer Ring - sage: RR(RR['x,y'](0)) # indirect doctest + sage: # needs sage.rings.real_mpfr + sage: RR(RR['x,y'](0)) # indirect doctest 0.000000000000000 sage: RR(ZZ['x,y'].gen(0)) Traceback (most recent call last): ... TypeError: unable to convert non-constant polynomial x to Real Field with 53 bits of precision - sage: CC(RR['x,y'](0)) # indirect doctest + sage: # needs sage.rings.real_mpfr + sage: CC(RR['x,y'](0)) # indirect doctest 0.000000000000000 sage: CC(ZZ['x,y'].gen(0)) Traceback (most recent call last): ... TypeError: unable to convert non-constant polynomial x to Complex Field with 53 bits of precision + sage: # needs sage.rings.real_mpfr sage: RDF(RR['x,y'](0)) 0.0 sage: RDF(ZZ['x,y'].gen(0)) @@ -71,13 +76,15 @@ cdef class MPolynomial(CommutativeRingElement): ... TypeError: unable to convert non-constant polynomial x to Real Double Field - sage: CDF(RR['x,y'](0)) # indirect doctest + sage: # needs sage.rings.real_mpfr + sage: CDF(RR['x,y'](0)) # indirect doctest 0.0 sage: CDF(ZZ['x,y'].gen(0)) Traceback (most recent call last): ... TypeError: unable to convert non-constant polynomial x to Complex Double Field + sage: # needs sage.libs.flint sage.rings.real_mpfr sage: a = RR['x,y'](1) sage: RBF(a) 1.000000000000000 @@ -87,8 +94,7 @@ cdef class MPolynomial(CommutativeRingElement): 1.000000000000000 sage: CIF(a) 1 - - sage: CBF(RR['x,y'](1)) # indirect doctest + sage: CBF(RR['x,y'](1)) # indirect doctest 1.000000000000000 sage: CBF(ZZ['x,y'].gen(0)) Traceback (most recent call last): @@ -96,8 +102,8 @@ cdef class MPolynomial(CommutativeRingElement): TypeError: unable to convert non-constant polynomial x to Complex ball field with 53 bits of precision sage: x = polygen(QQ) - sage: A.<u> = NumberField(x^3 - 2) - sage: A(A['x,y'](u)) + sage: A.<u> = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: A(A['x,y'](u)) # needs sage.rings.number_field u """ if self.degree() <= 0: @@ -117,7 +123,7 @@ cdef class MPolynomial(CommutativeRingElement): _number_field_ = _scalar_conversion def __int__(self): - """ + r""" TESTS:: sage: type(RR['x,y']) @@ -125,7 +131,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: type(RR['x, y'](0)) <class 'sage.rings.polynomial.multi_polynomial_element.MPolynomial_polydict'> - sage: int(RR['x,y'](0)) # indirect doctest + sage: int(RR['x,y'](0)) # indirect doctest 0 sage: int(RR['x,y'](10)) 10 @@ -134,7 +140,7 @@ cdef class MPolynomial(CommutativeRingElement): ... TypeError: unable to convert non-constant polynomial x to <class 'int'> - sage: ZZ(RR['x,y'](0)) # indirect doctest + sage: ZZ(RR['x,y'](0)) # indirect doctest 0 sage: ZZ(RR['x,y'](0.5)) Traceback (most recent call last): @@ -148,10 +154,10 @@ cdef class MPolynomial(CommutativeRingElement): return self._scalar_conversion(int) def __float__(self): - """ + r""" TESTS:: - sage: float(RR['x,y'](0)) # indirect doctest + sage: float(RR['x,y'](0)) # indirect doctest 0.0 sage: float(ZZ['x,y'].gen(0)) Traceback (most recent call last): @@ -161,10 +167,10 @@ cdef class MPolynomial(CommutativeRingElement): return self._scalar_conversion(float) def _rational_(self): - """ + r""" TESTS:: - sage: QQ(RR['x,y'](0.5)) # indirect doctest + sage: QQ(RR['x,y'](0.5)) # indirect doctest 1/2 sage: QQ(RR['x,y'].gen(0)) Traceback (most recent call last): @@ -175,18 +181,18 @@ cdef class MPolynomial(CommutativeRingElement): return self._scalar_conversion(QQ) def _symbolic_(self, R): - """ + r""" EXAMPLES:: + sage: # needs sage.symbolic sage: R.<x,y> = QQ[] sage: f = x^3 + y sage: g = f._symbolic_(SR); g x^3 + y - sage: g(x=2,y=2) + sage: g(x=2, y=2) 10 - sage: g = SR(f) - sage: g(x=2,y=2) + sage: g(x=2, y=2) 10 """ d = dict([(repr(g), R.var(g)) for g in self.parent().gens()]) @@ -209,23 +215,23 @@ cdef class MPolynomial(CommutativeRingElement): EXAMPLES:: - sage: R.<x,y,z> = PolynomialRing(QQ,3,order='degrevlex') - sage: f=23*x^6*y^7 + x^3*y+6*x^7*z + sage: R.<x,y,z> = PolynomialRing(QQ, 3, order='degrevlex') + sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z sage: f.coefficients() [23, 6, 1] - sage: R.<x,y,z> = PolynomialRing(QQ,3,order='lex') - sage: f=23*x^6*y^7 + x^3*y+6*x^7*z + sage: R.<x,y,z> = PolynomialRing(QQ, 3, order='lex') + sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z sage: f.coefficients() [6, 23, 1] Test the same stuff with base ring `\ZZ` -- different implementation:: - sage: R.<x,y,z> = PolynomialRing(ZZ,3,order='degrevlex') - sage: f=23*x^6*y^7 + x^3*y+6*x^7*z + sage: R.<x,y,z> = PolynomialRing(ZZ, 3, order='degrevlex') + sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z sage: f.coefficients() [23, 6, 1] - sage: R.<x,y,z> = PolynomialRing(ZZ,3,order='lex') - sage: f=23*x^6*y^7 + x^3*y+6*x^7*z + sage: R.<x,y,z> = PolynomialRing(ZZ, 3, order='lex') + sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z sage: f.coefficients() [6, 23, 1] @@ -233,15 +239,14 @@ cdef class MPolynomial(CommutativeRingElement): - Didier Deshommes """ - degs = self.exponents() d = self.dict() - return [ d[i] for i in degs ] + return [d[i] for i in self.exponents()] def truncate(self, var, n): - """ - Returns a new multivariate polynomial obtained from self by + r""" + Returns a new multivariate polynomial obtained from ``self`` by deleting all terms that involve the given variable to a power - at least n. + at least ``n``. """ cdef int ind R = self.parent() @@ -255,8 +260,8 @@ cdef class MPolynomial(CommutativeRingElement): return R(dict([(k, c) for k, c in d.iteritems() if k[ind] < n])) def _fast_callable_(self, etb): - """ - Given an ExpressionTreeBuilder, return an Expression representing + r""" + Given an :class:`ExpressionTreeBuilder`, return an :class:`Expression` representing this value. EXAMPLES:: @@ -299,10 +304,10 @@ cdef class MPolynomial(CommutativeRingElement): def derivative(self, *args): r""" The formal derivative of this polynomial, with respect to - variables supplied in args. + variables supplied in ``args``. Multiple variables and iteration counts may be supplied; see - documentation for the global derivative() function for more details. + documentation for the global function :func:`derivative` for more details. .. SEEALSO:: :meth:`._derivative` @@ -310,6 +315,7 @@ cdef class MPolynomial(CommutativeRingElement): Polynomials implemented via Singular:: + sage: # needs sage.libs.singular sage: R.<x, y> = PolynomialRing(FiniteField(5)) sage: f = x^3*y^5 + x^7*y sage: type(f) @@ -326,23 +332,24 @@ cdef class MPolynomial(CommutativeRingElement): sage: f = (t^2 + O(t^3))*x^2*y^3 + (37*t^4 + O(t^5))*x^3 sage: type(f) <class 'sage.rings.polynomial.multi_polynomial_element.MPolynomial_polydict'> - sage: f.derivative(x) # with respect to x + sage: f.derivative(x) # with respect to x (2*t^2 + O(t^3))*x*y^3 + (111*t^4 + O(t^5))*x^2 - sage: f.derivative(y) # with respect to y + sage: f.derivative(y) # with respect to y (3*t^2 + O(t^3))*x^2*y^2 - sage: f.derivative(t) # with respect to t (recurses into base ring) + sage: f.derivative(t) # with respect to t (recurses into base ring) (2*t + O(t^2))*x^2*y^3 + (148*t^3 + O(t^4))*x^3 - sage: f.derivative(x, y) # with respect to x and then y + sage: f.derivative(x, y) # with respect to x and then y (6*t^2 + O(t^3))*x*y^2 - sage: f.derivative(y, 3) # with respect to y three times + sage: f.derivative(y, 3) # with respect to y three times (6*t^2 + O(t^3))*x^2 - sage: f.derivative() # can't figure out the variable + sage: f.derivative() # can't figure out the variable Traceback (most recent call last): ... ValueError: must specify which variable to differentiate with respect to Polynomials over the symbolic ring (just for fun....):: + sage: # needs sage.symbolic sage: x = var("x") sage: S.<u, v> = PolynomialRing(SR) sage: f = u*v*x @@ -355,9 +362,9 @@ cdef class MPolynomial(CommutativeRingElement): def polynomial(self, var): - """ - Let var be one of the variables of the parent of self. This - returns self viewed as a univariate polynomial in var over the + r""" + Let ``var`` be one of the variables of the parent of ``self``. This + returns ``self`` viewed as a univariate polynomial in ``var`` over the polynomial ring generated by all the other variables of the parent. EXAMPLES:: @@ -367,7 +374,8 @@ cdef class MPolynomial(CommutativeRingElement): sage: f.polynomial(x) x^3 + (17*w^3 + 3*w)*x + w^5 + z^5 sage: parent(f.polynomial(x)) - Univariate Polynomial Ring in x over Multivariate Polynomial Ring in w, z over Rational Field + Univariate Polynomial Ring in x + over Multivariate Polynomial Ring in w, z over Rational Field sage: f.polynomial(w) w^5 + 17*x*w^3 + 3*x*w + z^5 + x^3 @@ -383,8 +391,8 @@ cdef class MPolynomial(CommutativeRingElement): z^5 + x*w*k*z + w^5 + 17*x*w^3 + x^3 + 3*x*w + 5 sage: f.polynomial(k) x*w*z*k + w^5 + z^5 + 17*x*w^3 + x^3 + 3*x*w + 5 - sage: R.<x,y>=GF(5)[] - sage: f=x^2+x+y + sage: R.<x,y> = GF(5)[] + sage: f = x^2 + x + y sage: f.polynomial(x) x^2 + x + y sage: f.polynomial(y) @@ -440,6 +448,7 @@ cdef class MPolynomial(CommutativeRingElement): TESTS:: + sage: # needs sage.rings.padics sage: R = Qp(7)['x,y,z,t,p']; S = ZZ['x,z,t']['p'] sage: R(S.0) p @@ -451,7 +460,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: z = S.base_ring().gen(1); p = S.0; x = S.base_ring().base_ring().gen() sage: R(z+p) z + p - sage: R = Qp(7)['x,y,z,p']; S = ZZ['x']['y,z,t']['p'] # shouldn't work, but should throw a better error + sage: R = Qp(7)['x,y,z,p']; S = ZZ['x']['y,z,t']['p'] # shouldn't work, but should throw a better error sage: R(S.0) p @@ -461,7 +470,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: a._mpoly_dict_recursive(('c', 'b', 'a')) {(0, 0, 1): 1} sage: testR.<a,b,c> = PolynomialRing(QQ,3) - sage: id_ringA = ideal([a^2-b,b^2-c,c^2-a]) + sage: id_ringA = ideal([a^2 - b, b^2 - c, c^2 - a]) sage: id_ringB = ideal(id_ringA.gens()).change_ring(PolynomialRing(QQ,'c,b,a')) """ if not self: @@ -524,7 +533,7 @@ cdef class MPolynomial(CommutativeRingElement): return D cdef long _hash_c(self) except -1: - """ + r""" This hash incorporates the variable name in an effort to respect the obvious inclusions into multi-variable polynomial rings. @@ -555,9 +564,9 @@ cdef class MPolynomial(CommutativeRingElement): Verify that :trac:`16251` has been resolved, i.e., polynomials with unhashable coefficients are unhashable:: - sage: K.<a> = Qq(9) - sage: R.<t,s> = K[] - sage: hash(t) + sage: K.<a> = Qq(9) # needs sage.rings.padics + sage: R.<t,s> = K[] # needs sage.rings.padics + sage: hash(t) # needs sage.rings.padics Traceback (most recent call last): ... TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement' @@ -593,7 +602,7 @@ cdef class MPolynomial(CommutativeRingElement): def args(self): r""" - Returns the named of the arguments of self, in the + Returns the names of the arguments of ``self``, in the order they are accepted from call. EXAMPLES:: @@ -705,7 +714,7 @@ cdef class MPolynomial(CommutativeRingElement): if self.is_homogeneous(): return self - if isinstance(var, basestring): + if isinstance(var, str): V = list(P.variable_names()) try: i = V.index(var) @@ -734,7 +743,7 @@ cdef class MPolynomial(CommutativeRingElement): def is_homogeneous(self): r""" - Return ``True`` if self is a homogeneous polynomial. + Return ``True`` if ``self`` is a homogeneous polynomial. TESTS:: @@ -769,7 +778,7 @@ cdef class MPolynomial(CommutativeRingElement): return True def homogeneous_components(self): - """ + r""" Return the homogeneous components of this polynomial. OUTPUT: @@ -804,21 +813,21 @@ cdef class MPolynomial(CommutativeRingElement): return {k: self._parent(d[k]) for k in d} cpdef _mod_(self, other): - """ + r""" EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ) sage: f = (x^2*y + 2*x - 3) sage: g = (x + 1)*f - sage: g % f + sage: g % f # needs sage.libs.singular 0 - sage: (g+1) % f + sage: (g+1) % f # needs sage.libs.singular 1 sage: M = x*y sage: N = x^2*y^3 - sage: M.divides(N) + sage: M.divides(N) # needs sage.libs.singular True """ try: @@ -830,7 +839,7 @@ cdef class MPolynomial(CommutativeRingElement): return r def change_ring(self, R): - """ + r""" Return a copy of this polynomial but with coefficients in ``R``, if at all possible. @@ -847,12 +856,13 @@ cdef class MPolynomial(CommutativeRingElement): :: - sage: R.<x,y> = GF(9,'a')[] + sage: R.<x,y> = GF(9,'a')[] # needs sage.rings.finite_rings sage: (x+2*y).change_ring(GF(3)) x - y :: + sage: # needs sage.rings.number_field sage: K.<z> = CyclotomicField(3) sage: R.<x,y> = K[] sage: f = x^2 + z*y @@ -864,7 +874,7 @@ cdef class MPolynomial(CommutativeRingElement): Check that :trac:`25022` is fixed:: sage: K.<x,y> = ZZ[] - sage: (x*y).change_ring(SR).monomials() + sage: (x*y).change_ring(SR).monomials() # needs sage.rings.number_field sage.symbolic [x*y] """ if isinstance(R, Map): @@ -886,6 +896,7 @@ cdef class MPolynomial(CommutativeRingElement): EXAMPLES:: + sage: # needs sage.groups sage: R.<x,y,z> = QQ[] sage: p = (x+y+z)**2 - 3 * (x+y)*(x+z)*(y+z) sage: p.is_symmetric() @@ -894,7 +905,6 @@ cdef class MPolynomial(CommutativeRingElement): False sage: R.one().is_symmetric() True - sage: p = (x-y)*(y-z)*(z-x) sage: p.is_symmetric() False @@ -902,33 +912,37 @@ cdef class MPolynomial(CommutativeRingElement): True sage: R.<x,y> = QQ[] - sage: ((x + y)**2).is_symmetric() + sage: ((x + y)**2).is_symmetric() # needs sage.groups True - sage: R.one().is_symmetric() + sage: R.one().is_symmetric() # needs sage.groups True - sage: (x + 2*y).is_symmetric() + sage: (x + 2*y).is_symmetric() # needs sage.groups False An example with a GAP permutation group (here the quaternions):: sage: R = PolynomialRing(QQ, 'x', 8) sage: x = R.gens() - sage: p = sum(prod(x[i] for i in e) for e in [(0,1,2), (0,1,7), (0,2,7), (1,2,7), (3,4,5), (3,4,6), (3,5,6), (4,5,6)]) - sage: p.is_symmetric(libgap.TransitiveGroup(8, 5)) + sage: p = sum(prod(x[i] for i in e) + ....: for e in [(0,1,2), (0,1,7), (0,2,7), (1,2,7), + ....: (3,4,5), (3,4,6), (3,5,6), (4,5,6)]) + sage: p.is_symmetric(libgap.TransitiveGroup(8, 5)) # needs sage.groups True - sage: p = sum(prod(x[i] for i in e) for e in [(0,1,2), (0,1,7), (0,2,7), (1,2,7), (3,4,5), (3,4,6), (3,5,6)]) - sage: p.is_symmetric(libgap.TransitiveGroup(8, 5)) + sage: p = sum(prod(x[i] for i in e) + ....: for e in [(0,1,2), (0,1,7), (0,2,7), (1,2,7), + ....: (3,4,5), (3,4,6), (3,5,6)]) + sage: p.is_symmetric(libgap.TransitiveGroup(8, 5)) # needs sage.groups False TESTS:: sage: R = PolynomialRing(QQ, 'x', 3) - sage: R.one().is_symmetric(3) + sage: R.one().is_symmetric(3) # needs sage.groups Traceback (most recent call last): ... ValueError: argument must be a permutation group - sage: R.one().is_symmetric(SymmetricGroup(4)) + sage: R.one().is_symmetric(SymmetricGroup(4)) # needs sage.groups Traceback (most recent call last): ... ValueError: invalid data to initialize a permutation @@ -959,7 +973,7 @@ cdef class MPolynomial(CommutativeRingElement): for e, coeff in coeffs.items() for g in gens) def _gap_(self, gap): - """ + r""" Return a representation of ``self`` in the GAP interface INPUT: @@ -970,6 +984,7 @@ cdef class MPolynomial(CommutativeRingElement): Multivariate polynomial over integers:: + sage: # needs sage.libs.gap sage: R.<x,y,z> = ZZ[] sage: gap(-x*y + 3*z) # indirect doctest -x*y+3*z @@ -978,16 +993,17 @@ cdef class MPolynomial(CommutativeRingElement): sage: (x+y+z)._gap_(libgap) x+y+z - sage: g = gap(x - y + 3*x*y*z) - sage: R(g) + sage: g = gap(x - y + 3*x*y*z) # needs sage.libs.gap + sage: R(g) # needs sage.libs.gap 3*x*y*z + x - y - sage: g = libgap(5*x - y*z) - sage: R(g) + sage: g = libgap(5*x - y*z) # needs sage.libs.gap + sage: R(g) # needs sage.libs.gap -y*z + 5*x Multivariate polynomial over a cyclotomic field:: + sage: # needs sage.libs.gap sage.rings.number_field sage: F.<zeta> = CyclotomicField(8) sage: P.<x,y> = F[] sage: p = zeta + zeta^2*x + zeta^3*y + (1+zeta)*x*y @@ -998,6 +1014,7 @@ cdef class MPolynomial(CommutativeRingElement): Multivariate polynomial over a polynomial ring over a cyclotomic field:: + sage: # needs sage.libs.gap sage.rings.number_field sage: S.<z> = F[] sage: P.<x,y> = S[] sage: p = zeta + zeta^2*x*z + zeta^3*y*z^2 + (1+zeta)*x*y*z @@ -1015,35 +1032,36 @@ cdef class MPolynomial(CommutativeRingElement): TESTS:: sage: R.<x,y,z> = ZZ[] - sage: libgap(-x*y + 3*z) # indirect doctest + sage: libgap(-x*y + 3*z) # indirect doctest # needs sage.libs.gap -x*y+3*z - sage: libgap(R.zero()) # indirect doctest + sage: libgap(R.zero()) # indirect doctest # needs sage.libs.gap 0 """ from sage.libs.gap.libgap import libgap return self._gap_(libgap) def _magma_init_(self, magma): - """ - Returns a Magma string representation of self valid in the + r""" + Returns a Magma string representation of ``self`` valid in the given magma session. EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<b> = GF(25); R.<x,y> = k[] sage: f = y*x^2*b + x*(b+1) + 1 sage: magma = Magma() # so var names same below - sage: magma(f) # optional - magma + sage: magma(f) # optional - magma b*x^2*y + b^22*x + 1 - sage: f._magma_init_(magma) # optional - magma + sage: f._magma_init_(magma) # optional - magma '_sage_[...]!((_sage_[...]!(_sage_[...]))*_sage_[...]^2*_sage_[...]+(_sage_[...]!(_sage_[...] + 1))*_sage_[...]+(_sage_[...]!(1))*1)' A more complicated nested example:: sage: R.<x,y> = QQ[]; S.<z,w> = R[]; f = (2/3)*x^3*z + w^2 + 5 - sage: f._magma_init_(magma) # optional - magma + sage: f._magma_init_(magma) # optional - magma '_sage_[...]!((_sage_[...]!((1/1)*1))*_sage_[...]^2+(_sage_[...]!((2/3)*_sage_[...]^3))*_sage_[...]+(_sage_[...]!((5/1)*1))*1)' - sage: magma(f) # optional - magma + sage: magma(f) # optional - magma w^2 + 2/3*x^3*z + 5 """ R = magma(self.parent()) @@ -1065,6 +1083,7 @@ cdef class MPolynomial(CommutativeRingElement): TESTS:: + sage: # needs sage.libs.giac sage: R.<x,y,z> = GF(101)['e,i'][] sage: f = R('e*i') * x + y^2 sage: f._giac_init_() @@ -1087,7 +1106,7 @@ cdef class MPolynomial(CommutativeRingElement): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(ZZ,3) + sage: P.<x,y,z> = PolynomialRing(ZZ, 3) sage: f = x*y + 1 sage: f.gradient() [y, x, 0] @@ -1103,32 +1122,32 @@ cdef class MPolynomial(CommutativeRingElement): sage: R.<x,y,z> = QQ[] sage: f = x^3 + y^3 + z^3 sage: f.jacobian_ideal() - Ideal (3*x^2, 3*y^2, 3*z^2) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (3*x^2, 3*y^2, 3*z^2) of + Multivariate Polynomial Ring in x, y, z over Rational Field """ return self.parent().ideal(self.gradient()) def newton_polytope(self): - """ + r""" Return the Newton polytope of this polynomial. EXAMPLES:: sage: R.<x,y> = QQ[] sage: f = 1 + x*y + x^3 + y^3 - sage: P = f.newton_polytope() - sage: P + sage: P = f.newton_polytope(); P # needs sage.geometry.polyhedron A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices - sage: P.is_simple() + sage: P.is_simple() # needs sage.geometry.polyhedron True TESTS:: sage: R.<x,y> = QQ[] - sage: R(0).newton_polytope() + sage: R(0).newton_polytope() # needs sage.geometry.polyhedron The empty polyhedron in ZZ^0 - sage: R(1).newton_polytope() + sage: R(1).newton_polytope() # needs sage.geometry.polyhedron A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex - sage: R(x^2+y^2).newton_polytope().integral_points() + sage: R(x^2+y^2).newton_polytope().integral_points() # needs sage.geometry.polyhedron ((0, 2), (1, 1), (2, 0)) """ from sage.geometry.polyhedron.constructor import Polyhedron @@ -1137,8 +1156,8 @@ cdef class MPolynomial(CommutativeRingElement): return P def __iter__(self): - """ - Facilitates iterating over the monomials of self, + r""" + Facilitates iterating over the monomials of ``self``, returning tuples of the form ``(coeff, mon)`` for each non-zero monomial. @@ -1156,13 +1175,13 @@ cdef class MPolynomial(CommutativeRingElement): yield (coeff, self.monomial(exp)) def iterator_exp_coeff(self, as_ETuples=True): - """ + r""" Iterate over ``self`` as pairs of ((E)Tuple, coefficient). INPUT: - - ``as_ETuples`` -- (default: ``True``) if ``True`` iterate over - pairs whose first element is an ETuple, otherwise as a tuples + - ``as_ETuples`` -- (default: ``True``) if ``True``, iterate over + pairs whose first element is an :class:`ETuple`, otherwise as a tuples EXAMPLES:: @@ -1182,8 +1201,8 @@ cdef class MPolynomial(CommutativeRingElement): yield (exp, self.monomial_coefficient(exp)) def content(self): - """ - Returns the content of this polynomial. Here, we define content as + r""" + Return the content of this polynomial. Here, we define content as the gcd of the coefficients in the base ring. .. SEEALSO:: @@ -1214,7 +1233,7 @@ cdef class MPolynomial(CommutativeRingElement): return gcd(self.coefficients()) def content_ideal(self): - """ + r""" Return the content ideal of this polynomial, defined as the ideal generated by its coefficients. @@ -1242,17 +1261,17 @@ cdef class MPolynomial(CommutativeRingElement): EXAMPLES:: - sage: R.<x,y>=ZZ[] + sage: R.<x,y> = ZZ[] sage: x.is_generator() True - sage: (x+y-y).is_generator() + sage: (x + y - y).is_generator() True sage: (x*y).is_generator() False - sage: R.<x,y>=QQ[] + sage: R.<x,y> = QQ[] sage: x.is_generator() True - sage: (x+y-y).is_generator() + sage: (x + y - y).is_generator() True sage: (x*y).is_generator() False @@ -1260,30 +1279,31 @@ cdef class MPolynomial(CommutativeRingElement): return (self in self.parent().gens()) def map_coefficients(self, f, new_base_ring=None): - """ + r""" Returns the polynomial obtained by applying ``f`` to the non-zero - coefficients of self. + coefficients of ``self``. If ``f`` is a :class:`sage.categories.map.Map`, then the resulting polynomial will be defined over the codomain of ``f``. Otherwise, the - resulting polynomial will be over the same ring as self. Set + resulting polynomial will be over the same ring as ``self``. Set ``new_base_ring`` to override this behaviour. INPUT: - - ``f`` -- a callable that will be applied to the coefficients of self. + - ``f`` -- a callable that will be applied to the coefficients of ``self``. - ``new_base_ring`` (optional) -- if given, the resulting polynomial will be defined over this ring. EXAMPLES:: - sage: k.<a> = GF(9); R.<x,y> = k[]; f = x*a + 2*x^3*y*a + a - sage: f.map_coefficients(lambda a : a + 1) + sage: k.<a> = GF(9); R.<x,y> = k[]; f = x*a + 2*x^3*y*a + a # needs sage.rings.finite_rings + sage: f.map_coefficients(lambda a: a + 1) # needs sage.rings.finite_rings (-a + 1)*x^3*y + (a + 1)*x + (a + 1) Examples with different base ring:: + sage: # needs sage.rings.finite_rings sage: R.<r> = GF(9); S.<s> = GF(81) sage: h = Hom(R,S)[0]; h Ring morphism: @@ -1291,7 +1311,7 @@ cdef class MPolynomial(CommutativeRingElement): To: Finite Field in s of size 3^4 Defn: r |--> 2*s^3 + 2*s^2 + 1 sage: T.<X,Y> = R[] - sage: f = r*X+Y + sage: f = r*X + Y sage: g = f.map_coefficients(h); g (-s^3 - s^2 + 1)*X + Y sage: g.parent() @@ -1327,9 +1347,10 @@ cdef class MPolynomial(CommutativeRingElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(9) sage: R.<x,y> = PolynomialRing(k) - sage: f = (x-a)*(y-a) + sage: f = (x-a) * (y-a) sage: f._norm_over_nonprime_finite_field() x^2*y^2 - x^2*y - x*y^2 - x^2 + x*y - y^2 + x + y + 1 """ @@ -1343,8 +1364,8 @@ cdef class MPolynomial(CommutativeRingElement): return prod(v).change_ring(k.prime_subfield()) def sylvester_matrix(self, right, variable = None): - """ - Given two nonzero polynomials self and right, returns the Sylvester + r""" + Given two nonzero polynomials ``self`` and ``right``, return the Sylvester matrix of the polynomials with respect to a given variable. Note that the Sylvester matrix is not defined if one of the polynomials @@ -1352,22 +1373,22 @@ cdef class MPolynomial(CommutativeRingElement): INPUT: - - self , right: multivariate polynomials - - variable: optional, compute the Sylvester matrix with respect to this - variable. If variable is not provided, the first variable of the + - ``self``, ``right`` -- multivariate polynomials + - ``variable`` -- optional, compute the Sylvester matrix with respect to this + variable. If ``variable`` is not provided, the first variable of the polynomial ring is used. OUTPUT: - - The Sylvester matrix of self and right. + - The Sylvester matrix of ``self`` and ``right``. EXAMPLES:: sage: R.<x, y> = PolynomialRing(ZZ) sage: f = (y + 1)*x + 3*x**2 sage: g = (y + 2)*x + 4*x**2 - sage: M = f.sylvester_matrix(g, x) - sage: M + sage: M = f.sylvester_matrix(g, x) # needs sage.modules + sage: M # needs sage.modules [ 3 y + 1 0 0] [ 0 3 y + 1 0] [ 4 y + 2 0 0] @@ -1376,18 +1397,18 @@ cdef class MPolynomial(CommutativeRingElement): If the polynomials share a non-constant common factor then the determinant of the Sylvester matrix will be zero:: - sage: M.determinant() + sage: M.determinant() # needs sage.modules 0 - sage: f.sylvester_matrix(1 + g, x).determinant() + sage: f.sylvester_matrix(1 + g, x).determinant() # needs sage.modules y^2 - y + 7 - If both polynomials are of positive degree with respect to variable, the + If both polynomials are of positive degree with respect to ``variable``, the determinant of the Sylvester matrix is the resultant:: - sage: f = R.random_element(4) - sage: g = R.random_element(4) - sage: f.sylvester_matrix(g, x).determinant() == f.resultant(g, x) + sage: f = R.random_element(4) or (x^2 * y^2) + sage: g = R.random_element(4) or (x^2 * y^2) + sage: f.sylvester_matrix(g, x).determinant() == f.resultant(g, x) # needs sage.libs.singular sage.modules True TESTS: @@ -1396,28 +1417,31 @@ cdef class MPolynomial(CommutativeRingElement): sage: f = x + y sage: g = x + y - sage: f.sylvester_matrix(g) + sage: f.sylvester_matrix(g) # needs sage.modules [1 y] [1 y] Polynomials must be defined over compatible base rings:: + sage: # needs sage.modules sage: K.<x, y> = QQ[] sage: f = x + y sage: L.<x, y> = ZZ[] sage: g = x + y - sage: R.<x, y> = GF(25, 'a')[] + sage: R.<x, y> = GF(25, 'a')[] # needs sage.rings.finite_rings sage: h = x + y sage: f.sylvester_matrix(g, 'x') [1 y] [1 y] - sage: g.sylvester_matrix(h, 'x') + sage: g.sylvester_matrix(h, 'x') # needs sage.rings.finite_rings [1 y] [1 y] - sage: f.sylvester_matrix(h, 'x') + sage: f.sylvester_matrix(h, 'x') # needs sage.rings.finite_rings Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Multivariate Polynomial Ring in x, y over Rational Field' and 'Multivariate Polynomial Ring in x, y over Finite Field in a of size 5^2' + TypeError: no common canonical parent for objects with parents: + 'Multivariate Polynomial Ring in x, y over Rational Field' and + 'Multivariate Polynomial Ring in x, y over Finite Field in a of size 5^2' sage: K.<x, y, z> = QQ[] sage: f = x + y sage: L.<x, z> = QQ[] @@ -1428,8 +1452,9 @@ cdef class MPolynomial(CommutativeRingElement): Corner cases:: - sage: K.<x ,y>=QQ[] - sage: f = x^2+1 + sage: # needs sage.modules + sage: K.<x, y> = QQ[] + sage: f = x^2 + 1 sage: g = K(0) sage: f.sylvester_matrix(g) Traceback (most recent call last): @@ -1496,53 +1521,50 @@ cdef class MPolynomial(CommutativeRingElement): return M def discriminant(self,variable): - """ - Returns the discriminant of self with respect to the given variable. + r""" + Returns the discriminant of ``self`` with respect to the given variable. INPUT: - - ``variable`` - The variable with respect to which we compute - the discriminant - - OUTPUT: - - - An element of the base ring of the polynomial ring. + - ``variable`` - The variable with respect to which we compute + the discriminant + OUTPUT: An element of the base ring of the polynomial ring. EXAMPLES:: - sage: R.<x,y,z>=QQ[] - sage: f=4*x*y^2 + 1/4*x*y*z + 3/2*x*z^2 - 1/2*z^2 - sage: f.discriminant(x) + sage: R.<x,y,z> = QQ[] + sage: f = 4*x*y^2 + 1/4*x*y*z + 3/2*x*z^2 - 1/2*z^2 + sage: f.discriminant(x) # needs sage.libs.singular 1 - sage: f.discriminant(y) + sage: f.discriminant(y) # needs sage.libs.singular -383/16*x^2*z^2 + 8*x*z^2 - sage: f.discriminant(z) + sage: f.discriminant(z) # needs sage.libs.singular -383/16*x^2*y^2 + 8*x*y^2 Note that, unlike the univariate case, the result lives in the same ring as the polynomial:: - sage: R.<x,y>=QQ[] - sage: f=x^5*y+3*x^2*y^2-2*x+y-1 - sage: f.discriminant(y) + sage: R.<x,y> = QQ[] + sage: f = x^5*y + 3*x^2*y^2 - 2*x + y - 1 + sage: f.discriminant(y) # needs sage.libs.singular x^10 + 2*x^5 + 24*x^3 + 12*x^2 + 1 sage: f.polynomial(y).discriminant() x^10 + 2*x^5 + 24*x^3 + 12*x^2 + 1 - sage: f.discriminant(y).parent()==f.polynomial(y).discriminant().parent() + sage: f.discriminant(y).parent() == f.polynomial(y).discriminant().parent() # needs sage.libs.singular False TESTS: Test polynomials over QQbar (:trac:`25265`):: - sage: R.<x,y>=QQbar[] - sage: f=x^5*y+3*x^2*y^2-2*x+y-1 + sage: # needs sage.rings.number_field + sage: R.<x,y> = QQbar[] + sage: f = x^5*y + 3*x^2*y^2 - 2*x + y - 1 sage: f.discriminant(y) x^10 + 2*x^5 + 24*x^3 + 12*x^2 + 1 - AUTHOR: - Miguel Marco + AUTHOR: Miguel Marco """ if self.is_zero(): return self.parent().zero() @@ -1587,11 +1609,11 @@ cdef class MPolynomial(CommutativeRingElement): x = variable p = self.polynomial(x) q = other.polynomial(x) - return [R(f) for f in p.subresultants(q)] + return [R(f) for f in p.subresultants(q)] def macaulay_resultant(self, *args): r""" - This is an implementation of the Macaulay Resultant. It computes + This is an implementation of the Macaulay resultant. It computes the resultant of universal polynomials as well as polynomials with constant coefficients. This is a project done in sage days 55. It's based on the implementation in Maple by @@ -1606,36 +1628,36 @@ cdef class MPolynomial(CommutativeRingElement): INPUT: - ``args`` -- a list of `n-1` homogeneous polynomials in `n` variables. - works when ``args[0]`` is the list of polynomials, - or ``args`` is itself the list of polynomials + works when ``args[0]`` is the list of polynomials, + or ``args`` is itself the list of polynomials OUTPUT: - - the macaulay resultant + - the Macaulay resultant EXAMPLES: The number of polynomials has to match the number of variables:: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: y.macaulay_resultant(x+z) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: y.macaulay_resultant(x + z) # needs sage.modules Traceback (most recent call last): ... TypeError: number of polynomials(= 2) must equal number of variables (= 3) The polynomials need to be all homogeneous:: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: y.macaulay_resultant([x+z, z+x^3]) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: y.macaulay_resultant([x + z, z + x^3]) # needs sage.modules Traceback (most recent call last): ... TypeError: resultant for non-homogeneous polynomials is not supported All polynomials must be in the same ring:: - sage: R.<x,y,z> = PolynomialRing(QQ,3) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) sage: S.<x,y> = PolynomialRing(QQ, 2) - sage: y.macaulay_resultant(z+x,z) + sage: y.macaulay_resultant(z + x, z) # needs sage.modules Traceback (most recent call last): ... TypeError: not all inputs are polynomials in the calling ring @@ -1643,15 +1665,19 @@ cdef class MPolynomial(CommutativeRingElement): The following example recreates Proposition 2.10 in Ch.3 of Using Algebraic Geometry:: sage: K.<x,y> = PolynomialRing(ZZ, 2) - sage: flist,R = K._macaulay_resultant_universal_polynomials([1,1,2]) - sage: flist[0].macaulay_resultant(flist[1:]) - u2^2*u4^2*u6 - 2*u1*u2*u4*u5*u6 + u1^2*u5^2*u6 - u2^2*u3*u4*u7 + u1*u2*u3*u5*u7 + u0*u2*u4*u5*u7 - u0*u1*u5^2*u7 + u1*u2*u3*u4*u8 - u0*u2*u4^2*u8 - u1^2*u3*u5*u8 + u0*u1*u4*u5*u8 + u2^2*u3^2*u9 - 2*u0*u2*u3*u5*u9 + u0^2*u5^2*u9 - u1*u2*u3^2*u10 + u0*u2*u3*u4*u10 + u0*u1*u3*u5*u10 - u0^2*u4*u5*u10 + u1^2*u3^2*u11 - 2*u0*u1*u3*u4*u11 + u0^2*u4^2*u11 + sage: flist, R = K._macaulay_resultant_universal_polynomials([1,1,2]) + sage: flist[0].macaulay_resultant(flist[1:]) # needs sage.modules + u2^2*u4^2*u6 - 2*u1*u2*u4*u5*u6 + u1^2*u5^2*u6 - u2^2*u3*u4*u7 + u1*u2*u3*u5*u7 + + u0*u2*u4*u5*u7 - u0*u1*u5^2*u7 + u1*u2*u3*u4*u8 - u0*u2*u4^2*u8 - u1^2*u3*u5*u8 + + u0*u1*u4*u5*u8 + u2^2*u3^2*u9 - 2*u0*u2*u3*u5*u9 + u0^2*u5^2*u9 + - u1*u2*u3^2*u10 + u0*u2*u3*u4*u10 + u0*u1*u3*u5*u10 - u0^2*u4*u5*u10 + + u1^2*u3^2*u11 - 2*u0*u1*u3*u4*u11 + u0^2*u4^2*u11 - The following example degenerates into the determinant of a `3*3` matrix:: + The following example degenerates into the determinant of a `3\times 3` matrix:: sage: K.<x,y> = PolynomialRing(ZZ, 2) - sage: flist,R = K._macaulay_resultant_universal_polynomials([1,1,1]) - sage: flist[0].macaulay_resultant(flist[1:]) + sage: flist, R = K._macaulay_resultant_universal_polynomials([1,1,1]) + sage: flist[0].macaulay_resultant(flist[1:]) # needs sage.modules -u2*u4*u6 + u1*u5*u6 + u2*u3*u7 - u0*u5*u7 - u1*u3*u8 + u0*u4*u8 The following example is by Patrick Ingram (:arxiv:`1310.4114`):: @@ -1661,56 +1687,56 @@ cdef class MPolynomial(CommutativeRingElement): sage: f0 = y0*x2^2 - x0^2 + 2*x1*x2 sage: f1 = y1*x2^2 - x1^2 + 2*x0*x2 sage: f2 = x0*x1 - x2^2 - sage: f0.macaulay_resultant(f1,f2) + sage: f0.macaulay_resultant(f1, f2) # needs sage.modules y0^2*y1^2 - 4*y0^3 - 4*y1^3 + 18*y0*y1 - 27 a simple example with constant rational coefficients:: - sage: R.<x,y,z,w> = PolynomialRing(QQ,4) - sage: w.macaulay_resultant([z,y,x]) + sage: R.<x,y,z,w> = PolynomialRing(QQ, 4) + sage: w.macaulay_resultant([z, y, x]) # needs sage.modules 1 an example where the resultant vanishes:: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: (x+y).macaulay_resultant([y^2,x]) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: (x + y).macaulay_resultant([y^2, x]) # needs sage.modules 0 an example of bad reduction at a prime ``p = 5``:: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: y.macaulay_resultant([x^3+25*y^2*x,5*z]) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: y.macaulay_resultant([x^3 + 25*y^2*x, 5*z]) # needs sage.libs.pari sage.modules 125 The input can given as an unpacked list of polynomials:: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: y.macaulay_resultant(x^3+25*y^2*x,5*z) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: y.macaulay_resultant(x^3 + 25*y^2*x, 5*z) # needs sage.libs.pari sage.modules 125 an example when the coefficients live in a finite field:: sage: F = FiniteField(11) - sage: R.<x,y,z,w> = PolynomialRing(F,4) - sage: z.macaulay_resultant([x^3,5*y,w]) + sage: R.<x,y,z,w> = PolynomialRing(F, 4) + sage: z.macaulay_resultant([x^3, 5*y, w]) # needs sage.modules sage.rings.finite_rings 4 example when the denominator in the algorithm vanishes(in this case the resultant is the constant term of the quotient of char polynomials of numerator/denominator):: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: y.macaulay_resultant([x+z, z^2]) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: y.macaulay_resultant([x + z, z^2]) # needs sage.libs.pari sage.modules -1 - when there are only 2 polynomials, macaulay resultant degenerates to the traditional resultant:: + When there are only 2 polynomials, the Macaulay resultant degenerates to the traditional resultant:: - sage: R.<x> = PolynomialRing(QQ,1) - sage: f = x^2+1; g = x^5+1 + sage: R.<x> = PolynomialRing(QQ, 1) + sage: f = x^2 + 1; g = x^5 + 1 sage: fh = f.homogenize() sage: gh = g.homogenize() sage: RH = fh.parent() - sage: f.resultant(g) == fh.macaulay_resultant(gh) + sage: f.resultant(g) == fh.macaulay_resultant(gh) # needs sage.modules True """ @@ -1719,12 +1745,12 @@ cdef class MPolynomial(CommutativeRingElement): return self.parent().macaulay_resultant(self, *args) def denominator(self): - """ - Return a denominator of self. + r""" + Return a denominator of ``self``. - First, the lcm of the denominators of the entries of self + First, the lcm of the denominators of the entries of ``self`` is computed and returned. If this computation fails, the - unit of the parent of self is returned. + unit of the parent of ``self`` is returned. Note that some subclasses may implement its own denominator function. @@ -1751,7 +1777,8 @@ cdef class MPolynomial(CommutativeRingElement): :: - sage: R.<x,y> = NumberField(symbolic_expression(x^2+3) ,'a')['x,y'] + sage: # needs sage.rings.number_field sage.symbolic + sage: R.<x,y> = NumberField(symbolic_expression(x^2+3),'a')['x,y'] sage: f = (1/17)*x^19 + (1/6)*y - (2/3)*x + 1/3; f 1/17*x^19 - 2/3*x + 1/6*y + 1/3 sage: f.denominator() @@ -1763,10 +1790,10 @@ cdef class MPolynomial(CommutativeRingElement): :: - sage: R.<a,b,c> = RR[] - sage: f = a + b + RR('0.3'); f + sage: R.<a,b,c> = RR[] # needs sage.rings.real_mpfr + sage: f = a + b + RR('0.3'); f # needs sage.rings.real_mpfr a + b + 0.300000000000000 - sage: f.denominator() + sage: f.denominator() # needs sage.rings.real_mpfr 1.00000000000000 Check that the denominator is an element over the base whenever the base @@ -1798,8 +1825,8 @@ cdef class MPolynomial(CommutativeRingElement): return self.base_ring().one() def numerator(self): - """ - Return a numerator of self computed as self * self.denominator() + r""" + Return a numerator of ``self``, computed as ``self * self.denominator()``. Note that some subclasses may implement its own numerator function. @@ -1807,13 +1834,13 @@ cdef class MPolynomial(CommutativeRingElement): .. warning:: This is not the numerator of the rational function - defined by self, which would always be self since self is a + defined by ``self``, which would always be self since ``self`` is a polynomial. EXAMPLES: First we compute the numerator of a polynomial with - integer coefficients, which is of course self. + integer coefficients, which is of course ``self``. :: @@ -1828,7 +1855,8 @@ cdef class MPolynomial(CommutativeRingElement): :: - sage: R.<x,y> = NumberField(symbolic_expression(x^2+3) ,'a')['x,y'] + sage: # needs sage.rings.number_field sage.symbolic + sage: R.<x,y> = NumberField(symbolic_expression(x^2+3), 'a')['x,y'] sage: f = (1/17)*y^19 - (2/3)*x + 1/3; f 1/17*y^19 - 2/3*x + 1/3 sage: f.numerator() @@ -1848,59 +1876,61 @@ cdef class MPolynomial(CommutativeRingElement): -x*z - z^2 - y + 1 We check that the computation the numerator and denominator - are valid + are valid. :: - sage: K=NumberField(symbolic_expression('x^3+2'),'a')['x']['s,t'] - sage: f=K.random_element() + sage: # needs sage.rings.number_field sage.symbolic + sage: K = NumberField(symbolic_expression('x^3+2'), 'a')['x']['s,t'] + sage: f = K.random_element() sage: f.numerator() / f.denominator() == f True - sage: R=RR['x,y,z'] - sage: f=R.random_element() + sage: R = RR['x,y,z'] + sage: f = R.random_element() sage: f.numerator() / f.denominator() == f True """ return self * self.denominator() def lift(self, I): - """ - given an ideal ``I = (f_1,...,f_r)`` and some ``g (== self)`` in ``I``, - find ``s_1,...,s_r`` such that ``g = s_1 f_1 + ... + s_r f_r``. + r""" + Given an ideal `I = (f_1,\dots,f_r)` that contains ``self``, + find `s_1,\dots,s_r` such that ``self`` `= s_1 f_1 + ... + s_r f_r`. EXAMPLES:: - sage: A.<x,y> = PolynomialRing(CC,2,order='degrevlex') + sage: # needs sage.rings.real_mpfr + sage: A.<x,y> = PolynomialRing(CC, 2, order='degrevlex') sage: I = A.ideal([x^10 + x^9*y^2, y^8 - x^2*y^7 ]) sage: f = x*y^13 + y^12 - sage: M = f.lift(I) - sage: M + sage: M = f.lift(I); M # needs sage.libs.singular [y^7, x^7*y^2 + x^8 + x^5*y^3 + x^6*y + x^3*y^4 + x^4*y^2 + x*y^5 + x^2*y^3 + y^4] - sage: sum( map( mul , zip( M, I.gens() ) ) ) == f + sage: sum(map(mul, zip(M, I.gens()))) == f # needs sage.libs.singular True """ raise NotImplementedError def inverse_mod(self, I): - """ - Returns an inverse of self modulo the polynomial ideal `I`, + r""" + Returns an inverse of ``self`` modulo the polynomial ideal `I`, namely a multivariate polynomial `f` such that ``self * f - 1`` belongs to `I`. INPUT: - - ``I`` -- an ideal of the polynomial ring in which self lives + + - ``I`` -- an ideal of the polynomial ring in which ``self`` lives OUTPUT: - - a multivariate polynomial representing the inverse of ``f`` modulo ``I`` + a multivariate polynomial representing the inverse of ``f`` modulo `I` EXAMPLES:: sage: R.<x1,x2> = QQ[] sage: I = R.ideal(x2**2 + x1 - 2, x1**2 - 1) - sage: f = x1 + 3*x2^2; g = f.inverse_mod(I); g + sage: f = x1 + 3*x2^2; g = f.inverse_mod(I); g # needs sage.libs.singular 1/16*x1 + 3/16 - sage: (f*g).reduce(I) + sage: (f*g).reduce(I) # needs sage.libs.singular 1 Test a non-invertible element:: @@ -1908,7 +1938,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: R.<x1,x2> = QQ[] sage: I = R.ideal(x2**2 + x1 - 2, x1**2 - 1) sage: f = x1 + x2 - sage: f.inverse_mod(I) + sage: f.inverse_mod(I) # needs sage.libs.singular Traceback (most recent call last): ... ArithmeticError: element is non-invertible @@ -1922,7 +1952,7 @@ cdef class MPolynomial(CommutativeRingElement): raise ArithmeticError("element is non-invertible") def weighted_degree(self, *weights): - """ + r""" Return the weighted degree of ``self``, which is the maximum weighted degree of all monomials in ``self``; the weighted degree of a monomial is the sum of all powers of the variables in the monomial, each power @@ -1953,7 +1983,7 @@ cdef class MPolynomial(CommutativeRingElement): 4 sage: p.weighted_degree(2**64, 2**50, 2**128) 680564733841876926945195958937245974528 - sage: q = R.random_element(100, 20) #random + sage: q = R.random_element(100, 20) sage: q.weighted_degree(1, 1, 1) == q.total_degree() True @@ -1968,15 +1998,15 @@ cdef class MPolynomial(CommutativeRingElement): :: - sage: p.weighted_degree(x,1,1) + sage: p.weighted_degree(x, 1, 1) Traceback (most recent call last): ... TypeError: unable to convert non-constant polynomial x to Integer Ring - sage: p.weighted_degree(2/1,1,1) + sage: p.weighted_degree(2/1, 1, 1) 6 - The ``weighted_degree`` coincides with the ``degree`` of a weighted - polynomial ring, but the later is faster. + The :meth:`weighted_degree` coincides with the :meth:`degree` of a weighted + polynomial ring, but the latter is faster. :: @@ -1987,6 +2017,7 @@ cdef class MPolynomial(CommutativeRingElement): TESTS:: + sage: # needs sage.modules sage: R = PolynomialRing(QQ, 'a', 5) sage: f = R.random_element(terms=20) sage: w = random_vector(ZZ,5) @@ -2030,7 +2061,7 @@ cdef class MPolynomial(CommutativeRingElement): return deg def gcd(self, other): - """ + r""" Return a greatest common divisor of this polynomial and ``other``. INPUT: @@ -2044,7 +2075,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: r = x*y - (2*z-1)/(z^2+z+1) * x + y/z sage: p = r * (x + z*y - 1/z^2) sage: q = r * (x*y*z + 1) - sage: gcd(p,q) + sage: gcd(p, q) (z^3 + z^2 + z)*x*y + (-2*z^2 + z)*x + (z^2 + z + 1)*y Polynomials over polynomial rings are converted to a simpler polynomial @@ -2052,21 +2083,23 @@ cdef class MPolynomial(CommutativeRingElement): sage: A.<z,t> = ZZ[] sage: B.<x,y> = A[] - sage: r = x*y*z*t+1 + sage: r = x*y*z*t + 1 sage: p = r * (x - y + z - t + 1) sage: q = r * (x*z - y*t) - sage: gcd(p,q) + sage: gcd(p, q) z*t*x*y + 1 sage: _.parent() - Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in z, t over Integer Ring + Multivariate Polynomial Ring in x, y over + Multivariate Polynomial Ring in z, t over Integer Ring Some multivariate polynomial rings have no gcd implementation:: - sage: R.<x,y> =GaussianIntegers()[] + sage: R.<x,y> = GaussianIntegers()[] # needs sage.rings.number_field sage: x.gcd(x) Traceback (most recent call last): ... - NotImplementedError: GCD is not implemented for multivariate polynomials over Gaussian Integers in Number Field in I with defining polynomial x^2 + 1 with I = 1*I + NotImplementedError: GCD is not implemented for multivariate polynomials over + Gaussian Integers in Number Field in I with defining polynomial x^2 + 1 with I = 1*I TESTS:: @@ -2155,11 +2188,11 @@ cdef class MPolynomial(CommutativeRingElement): def is_square(self, root=False): r""" - Test whether this polynomial is a square root. + Test whether this polynomial is a square. INPUT: - - ``root`` - if set to ``True`` return a pair ``(True, root)`` + - ``root`` - if set to ``True``, return a pair ``(True, root)`` where ``root`` is a square root or ``(False, None)`` if it is not a square. @@ -2192,7 +2225,7 @@ cdef class MPolynomial(CommutativeRingElement): - ``D`` -- dictionary (optional) - - ``phi`` -- SpecializationMorphism (optional) + - ``phi`` -- :class:`SpecializationMorphism` (optional) OUTPUT: a new polynomial @@ -2269,11 +2302,11 @@ cdef class MPolynomial(CommutativeRingElement): keywords: - - ``prec`` -- integer, sets the precision (default:300) + - ``prec`` -- integer, sets the precision (default: 300) - - ``return_conjugation`` -- boolean. Returns element of `SL(2, \ZZ)` (default:True) + - ``return_conjugation`` -- boolean. Returns element of `SL(2, \ZZ)` (default: True) - - ``error_limit`` -- sets the error tolerance (default:0.000001) + - ``error_limit`` -- sets the error tolerance (default: 0.000001) - ``smallest_coeffs`` -- (default: True), boolean, whether to find the model with smallest coefficients @@ -2281,16 +2314,18 @@ cdef class MPolynomial(CommutativeRingElement): - ``norm_type`` -- either ``'norm'`` or ``'height'``. What type of norm to use for smallest coefficients - - ``emb`` -- (optional) embedding of based field into CC + - ``emb`` -- (optional) embedding of based field into ``CC`` OUTPUT: - - a polynomial (reduced binary form) + - a polynomial (reduced binary form) - - a matrix (element of `SL(2, \ZZ)`) + - a matrix (element of `SL(2, \ZZ)`) - TODO: When Newton's Method doesn't converge to a root in the upper half plane. - Now we just return z0. It would be better to modify and find the unique root + .. TODO:: + + When Newton's Method doesn't converge to a root in the upper half plane. + Now we just return `z_0`. It would be better to modify and find the unique root in the upper half plane. EXAMPLES:: @@ -2298,7 +2333,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: R.<x,h> = PolynomialRing(QQ) sage: f = 19*x^8 - 262*x^7*h + 1507*x^6*h^2 - 4784*x^5*h^3 + 9202*x^4*h^4\ -10962*x^3*h^5 + 7844*x^2*h^6 - 3040*x*h^7 + 475*h^8 - sage: f.reduced_form(prec=200, smallest_coeffs=False) + sage: f.reduced_form(prec=200, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field ( -x^8 - 2*x^7*h + 7*x^6*h^2 + 16*x^5*h^3 + 2*x^4*h^4 - 2*x^3*h^5 + 4*x^2*h^6 - 5*h^8, <BLANKLINE> @@ -2311,7 +2346,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: R.<x,y> = PolynomialRing(QQ) sage: f = x^3 + 378666*x^2*y - 12444444*x*y^2 + 1234567890*y^3 sage: j = f * (x-545*y)^9 - sage: j.reduced_form(prec=200, smallest_coeffs=False) + sage: j.reduced_form(prec=200, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field Traceback (most recent call last): ... ValueError: cannot have a root with multiplicity >= 12/2 @@ -2320,7 +2355,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: R.<x,y> = PolynomialRing(QQ) sage: F = x^6 + 3*x^5*y - 8*x^4*y^2 - 2*x^3*y^3 - 44*x^2*y^4 - 8*x*y^5 - sage: F.reduced_form(smallest_coeffs=False, prec=400) + sage: F.reduced_form(smallest_coeffs=False, prec=400) # needs sage.modules sage.rings.complex_interval_field Traceback (most recent call last): ... ArithmeticError: Newton's method converged to z not in the upper half plane @@ -2329,7 +2364,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: R.<x,y> = PolynomialRing(QQ) sage: F = 5*x^2*y - 5*x*y^2 - 30*y^3 - sage: F.reduced_form(smallest_coeffs=False) + sage: F.reduced_form(smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field ( [1 1] 5*x^2*y + 5*x*y^2 - 30*y^3, [0 1] @@ -2338,12 +2373,14 @@ cdef class MPolynomial(CommutativeRingElement): An example where precision needs to be increased:: sage: R.<x,y> = PolynomialRing(QQ) - sage: F=-16*x^7 - 114*x^6*y - 345*x^5*y^2 - 599*x^4*y^3 - 666*x^3*y^4 - 481*x^2*y^5 - 207*x*y^6 - 40*y^7 - sage: F.reduced_form(prec=50, smallest_coeffs=False) + sage: F = (-16*x^7 - 114*x^6*y - 345*x^5*y^2 - 599*x^4*y^3 + ....: - 666*x^3*y^4 - 481*x^2*y^5 - 207*x*y^6 - 40*y^7) + sage: F.reduced_form(prec=50, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field Traceback (most recent call last): ... - ValueError: accuracy of Newton's root not within tolerance(0.0000124... > 1e-06), increase precision - sage: F.reduced_form(prec=100, smallest_coeffs=False) + ValueError: accuracy of Newton's root not within tolerance(0.000012... > 1e-06), + increase precision + sage: F.reduced_form(prec=100, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field ( [-1 -1] -x^5*y^2 - 24*x^3*y^4 - 3*x^2*y^5 - 2*x*y^6 + 16*y^7, [ 1 0] @@ -2353,14 +2390,14 @@ cdef class MPolynomial(CommutativeRingElement): sage: R.<x,y> = PolynomialRing(QQ) sage: F = - 8*x^4 - 3933*x^3*y - 725085*x^2*y^2 - 59411592*x*y^3 - 1825511633*y^4 - sage: F.reduced_form(return_conjugation=False) + sage: F.reduced_form(return_conjugation=False) # needs sage.modules sage.rings.complex_interval_field x^4 + 9*x^3*y - 3*x*y^3 - 8*y^4 :: sage: R.<x,y> = QQ[] sage: F = -2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3 - sage: F.reduced_form() + sage: F.reduced_form() # needs sage.modules sage.rings.complex_interval_field ( [1 4] -2*x^3 - 22*x^2*y - 77*x*y^2 + 43*y^3, [0 1] @@ -2370,7 +2407,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: R.<x,y> = QQ[] sage: F = -2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3 - sage: F.reduced_form(norm_type='height') + sage: F.reduced_form(norm_type='height') # needs sage.modules sage.rings.complex_interval_field ( [5 4] -58*x^3 - 47*x^2*y + 52*x*y^2 + 43*y^3, [1 1] @@ -2380,7 +2417,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: R.<x,y,z> = PolynomialRing(QQ) sage: F = x^4 + x^3*y*z + y^2*z - sage: F.reduced_form() + sage: F.reduced_form() # needs sage.modules sage.rings.complex_interval_field Traceback (most recent call last): ... ValueError: (=x^3*y*z + x^4 + y^2*z) must have two variables @@ -2389,7 +2426,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: R.<x,y> = PolynomialRing(ZZ) sage: F = - 8*x^6 - 3933*x^3*y - 725085*x^2*y^2 - 59411592*x*y^3 - 99*y^6 - sage: F.reduced_form(return_conjugation=False) + sage: F.reduced_form(return_conjugation=False) # needs sage.modules sage.rings.complex_interval_field Traceback (most recent call last): ... ValueError: (=-8*x^6 - 99*y^6 - 3933*x^3*y - 725085*x^2*y^2 - @@ -2398,11 +2435,12 @@ cdef class MPolynomial(CommutativeRingElement): :: sage: R.<x,y> = PolynomialRing(RR) - sage: F = 217.992172373276*x^3 + 96023.1505442490*x^2*y + 1.40987971253579e7*x*y^2\ - + 6.90016027113216e8*y^3 - sage: F.reduced_form(smallest_coeffs=False) # tol 1e-8 + sage: F = (217.992172373276*x^3 + 96023.1505442490*x^2*y + ....: + 1.40987971253579e7*x*y^2 + 6.90016027113216e8*y^3) + sage: F.reduced_form(smallest_coeffs=False) # tol 1e-8 # needs sage.modules sage.rings.complex_interval_field ( - -39.5673942565918*x^3 + 111.874026298523*x^2*y + 231.052762985229*x*y^2 - 138.380829811096*y^3, + -39.5673942565918*x^3 + 111.874026298523*x^2*y + + 231.052762985229*x*y^2 - 138.380829811096*y^3, <BLANKLINE> [-147 -148] [ 1 1] @@ -2410,19 +2448,26 @@ cdef class MPolynomial(CommutativeRingElement): :: - sage: R.<x,y> = PolynomialRing(CC) - sage: F = (0.759099196558145 + 0.845425869641446*CC.0)*x^3 + (84.8317207268542 + 93.8840848648033*CC.0)*x^2*y\ - + (3159.07040755858 + 3475.33037377779*CC.0)*x*y^2 + (39202.5965389079 + 42882.5139724962*CC.0)*y^3 - sage: F.reduced_form(smallest_coeffs=False) # tol 1e-11 + sage: R.<x,y> = PolynomialRing(CC) # needs sage.rings.real_mpfr + sage: F = ((0.759099196558145 + 0.845425869641446*CC.0)*x^3 # needs sage.rings.real_mpfr + ....: + (84.8317207268542 + 93.8840848648033*CC.0)*x^2*y + ....: + (3159.07040755858 + 3475.33037377779*CC.0)*x*y^2 + ....: + (39202.5965389079 + 42882.5139724962*CC.0)*y^3) + sage: F.reduced_form(smallest_coeffs=False) # tol 1e-11 # needs sage.modules sage.rings.complex_interval_field sage.rings.real_mpfr ( - (-0.759099196558145 - 0.845425869641446*I)*x^3 + (-0.571709908900118 - 0.0418133346027929*I)*x^2*y - + (0.856525964330103 - 0.0721403997649759*I)*x*y^2 + (-0.965531044130330 + 0.754252314465703*I)*y^3, + (-0.759099196558145 - 0.845425869641446*I)*x^3 + + (-0.571709908900118 - 0.0418133346027929*I)*x^2*y + + (0.856525964330103 - 0.0721403997649759*I)*x*y^2 + + (-0.965531044130330 + 0.754252314465703*I)*y^3, <BLANKLINE> [-1 37] [ 0 -1] ) """ from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + from sage.rings.complex_interval_field import ComplexIntervalField + from sage.rings.real_mpfr import RealField if self.parent().ngens() != 2: raise ValueError("(=%s) must have two variables"%self) @@ -2435,7 +2480,7 @@ cdef class MPolynomial(CommutativeRingElement): emb = kwds.get('emb', None) # getting a numerical approximation of the roots of our polynomial - CF = ComplexIntervalField(prec=prec) # keeps trac of our precision error + CF = ComplexIntervalField(prec=prec) # keeps trac of our precision error RF = RealField(prec=prec) R = self.parent() x,y = R.gens() @@ -2503,8 +2548,9 @@ cdef class MPolynomial(CommutativeRingElement): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] - sage: (x+y).is_unit() + sage: (x + y).is_unit() False sage: R(0).is_unit() False @@ -2549,18 +2595,18 @@ cdef class MPolynomial(CommutativeRingElement): EXAMPLES:: - sage: R.<x,y> = QQbar[] - sage: (x+y).is_nilpotent() + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: (x + y).is_nilpotent() # needs sage.rings.number_field False - sage: R(0).is_nilpotent() + sage: R(0).is_nilpotent() # needs sage.rings.number_field True sage: _.<x,y> = Zmod(4)[] sage: (2*x).is_nilpotent() True - sage: (2+y*x).is_nilpotent() + sage: (2 + y*x).is_nilpotent() False sage: _.<x,y> = Zmod(36)[] - sage: (4+6*x).is_nilpotent() + sage: (4 + 6*x).is_nilpotent() False sage: (6*x + 12*y + 18*x*y + 24*(x^2+y^2)).is_nilpotent() True @@ -2581,8 +2627,8 @@ cdef class MPolynomial(CommutativeRingElement): TESTS:: - sage: R.<x,y> = QQbar[] - sage: (x + y)._test_subs() + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: (x + y)._test_subs() # needs sage.rings.number_field """ if tester is None: tester = self._tester(**options) @@ -2613,6 +2659,238 @@ cdef class MPolynomial(CommutativeRingElement): with tester.assertRaises((ValueError, TypeError)): self.subs(**d) + def is_lorentzian(self, explain=False): + r""" + Return whether this is a Lorentzian polynomial. + + INPUT: + + - ``explain`` -- boolean (default: ``False``); if ``True`` + return a tuple whose first element is the boolean result of the test, + and the second element is a string describing the reason the test failed, + or ``None`` if the test succeeded. + + Lorentzian polynomials are a class of polynomials connected with the area + of discrete convex analysis. A polynomial `f` with positive real coefficients + is Lorentzian if: + + - `f` is homogeneous; + + - the support of `f` is `M`-convex + + - `f` has degree less than `2`, or if its degree is at least two, + the collection of sequential partial derivatives of `f` which are + quadratic forms have Gram matrices with at most one positive eigenvalue. + + Note in particular that the zero polynomial is Lorentzian. Examples of + Lorentzian polynomials include homogeneous stable polynomials, volume + polynomials of convex bodies and projective varieties, and Schur polynomials + after renormalizing the coefficient of each monomial `x^\alpha` by `1/\alpha!`. + + EXAMPLES: + + Renormalized Schur polynomials are Lorentzian, but not in general if the + renormalization is skipped:: + + sage: P.<x,y> = QQ[] + sage: p = (x^2 / 2) + x*y + (y^2 / 2) + sage: p.is_lorentzian() + True + sage: p = x^2 + x*y + y^2 + sage: p.is_lorentzian() + False + + Homogeneous linear forms and constant polynomials with positive + coefficients are Lorentzian, as well as the zero polynomial:: + + sage: p = x + 2*y + sage: p.is_lorentzian() + True + sage: p = P(5) + sage: p.is_lorentzian() + True + sage: P.zero().is_lorentzian() + True + + Inhomogeneous polynomials and polynomials with negative coefficients + are not Lorentzian:: + + sage: p = x^2 + 2*x + y^2 + sage: p.is_lorentzian() + False + sage: p = 2*x^2 - y^2 + sage: p.is_lorentzian() + False + + It is an error to check if a polynomial is Lorentzian if its base ring + is not a subring of the real numbers, as the notion is not defined in + this case:: + + sage: Q.<z,w> = CC[] + sage: q = z^2 + w^2 + sage: q.is_lorentzian() + Traceback (most recent call last): + ... + NotImplementedError: is_lorentzian only implemented for real polynomials + + The method can give a reason for a polynomial failing to be Lorentzian:: + + sage: p = x^2 + 2*x + y^2 + sage: p.is_lorentzian(explain=True) + (False, 'inhomogeneous') + + REFERENCES: + + For full definitions and related discussion, see [BrHu2019]_ and + [HMMS2019]_. The second reference gives the characterization of + Lorentzian polynomials applied in this implementation explicitly. + """ + from sage.rings.imaginary_unit import I + + # function to handle return value when reason requested + def result(val, explanation=None): + return (val, explanation) if explain else val + + try: + # this would better be handled by a category of RealFields() + self.base_ring()(I) + except (ValueError, TypeError): + pass + else: + raise NotImplementedError("is_lorentzian only implemented for real polynomials") + + if self.is_zero(): + return result(True) + + if not self.is_homogeneous(): + return result(False, "inhomogeneous") + + if any(coeff < 0 for coeff in self.coefficients()): + return result(False, "negative coefficient") + + # for degree <= 1, homogeneous with positive coefficients is sufficient + if self.degree() <= 1: + return result(True) + + # check support is M-convex + if not _is_M_convex_(self.exponents()): + return result(False, "not M-convex") + + # compute quadratic forms coming from a sequence of partial derivatives + if self.degree() == 2: + quadratic_derivs = set([self]) + else: + from sage.combinat.integer_lists.invlex import IntegerListsLex + + gens = self.parent().gens() + quadratic_derivs = set() + multi_exponents = IntegerListsLex(self.degree() - 2, length=len(gens)) + for alpha in multi_exponents: + # construct list [gen_1, exp_1, ..., gen_n, exp_n] for derivative function + d_list = chain(*zip(gens, alpha)) + d = self.derivative(*d_list) + quadratic_derivs.add(d) + + # check derivative quadratic forms have at most one positive eigenvalue + for deriv in quadratic_derivs: + from sage.quadratic_forms.quadratic_form import QuadraticForm + G = QuadraticForm(deriv).Gram_matrix() + spectrum = sorted(G.eigenvalues(), reverse=True) + if len(spectrum) > 1 and spectrum[1] > 0: + return result(False, "multiple positive eigenvalues") + + return result(True) + + +def _is_M_convex_(points): + r""" + Return whether ``points`` represents a set of integer lattice points + which are M-convex. + + Utility function for method ``is_lorentzian``, which would more properly + fit with code related to discrete convex geometry, generalized permutahedra, + or polymatroids, which are not currently implemented in Sage. + + INPUT: + + - ``points`` -- iterable for a list of integer lattice points of the + same dimension + + Examples of M-convex sets include the vertices of a matroid polytope, and the + support sets of Schur polynomials. + + EXAMPLES: + + The following points represent the vertices of a matroid polytope (indicator + vectors of the bases) of rank `2` on five elements:: + + sage: from sage.rings.polynomial.multi_polynomial import _is_M_convex_ + sage: P = [[1,1,0,0], [1,0,1,0], [0,1,1,0], [0,1,0,1], [0,0,1,1]] + sage: _is_M_convex_(P) + True + + These points are the support of the Schur polynomial in three variables for + the partition `(2,2)`:: + + sage: P = [[2,2,0], [2,0,2], [0,2,2], [2,1,1], [1,2,1], [1,1,2]] + sage: _is_M_convex_(P) + True + + The following are not examples of `M`-convex sets of points:: + + sage: P = [[1, 0, 0], [1, 1, 0], [1, 1, 1]] + sage: _is_M_convex_(P) + False + + sage: P = [[0, 1, 2], [2, 1]] + sage: _is_M_convex_(P) + Traceback (most recent call last): + ... + ValueError: input points are not the same dimension + + sage: P = [[0, 0.5, 1], [1, 1.5, 2]] + sage: _is_M_convex_(P) + Traceback (most recent call last): + ... + ValueError: input points are not integer lattice points + + REFERENCES: + + See [BrHu2019]_ for a definition of M-convexity. + """ + points_set = set(map(tuple, points)) + if not points_set: + return True + dim = len(next(iter(points_set))) + if any(len(p) != dim for p in points_set): + raise ValueError("input points are not the same dimension") + if any(entry not in ZZ for p in points_set for entry in p): + raise ValueError("input points are not integer lattice points") + for p1 in points_set: + list_p1 = list(p1) + for p2 in points_set: + if p2 == p1: + continue + delta = list(x2 - x1 for x1, x2 in zip(p1, p2)) + for i in range(dim): + if p2[i] > p1[i]: + # modify list_p1 to represent point p1 + e_i - e_j for various i, j + list_p1[i] += 1 # add e_i + # check exchange condition is satisfied by some index j + for j in range(dim): + if p2[j] < p1[j]: + list_p1[j] -= 1 # subtract e_j + exch = tuple(list_p1) # p1 + e_i - e_j + list_p1[j] += 1 # add e_j again + if tuple(exch) in points_set: + break + else: + return False + list_p1[i] -= 1 # subtract e_i + # list_p1 should now have same entries as p1 again + return True + + cdef remove_from_tuple(e, int ind): w = list(e) del w[ind] @@ -2620,3 +2898,27 @@ cdef remove_from_tuple(e, int ind): return w[0] else: return tuple(w) + + +cdef class MPolynomial_libsingular(MPolynomial): + r""" + Abstract base class for :class:`~sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular` + + This class is defined for the purpose of :func:`isinstance` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: from sage.rings.polynomial.multi_polynomial import MPolynomial_libsingular + sage: R1.<x> = QQ[] + sage: isinstance(x, MPolynomial_libsingular) + False + sage: R2.<y,z> = QQ[] + sage: isinstance(y, MPolynomial_libsingular) # needs sage.libs.singular + True + + By design, there is a unique direct subclass:: + + sage: len(sage.rings.polynomial.multi_polynomial.MPolynomial_libsingular.__subclasses__()) <= 1 + True + """ diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 702bf9af7eb..0c510df8d59 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -31,8 +31,10 @@ We verify Lagrange's four squares identity:: - sage: R.<a0,a1,a2,a3,b0,b1,b2,b3> = QQbar[] - sage: (a0^2 + a1^2 + a2^2 + a3^2)*(b0^2 + b1^2 + b2^2 + b3^2) == (a0*b0 - a1*b1 - a2*b2 - a3*b3)^2 + (a0*b1 + a1*b0 + a2*b3 - a3*b2)^2 + (a0*b2 - a1*b3 + a2*b0 + a3*b1)^2 + (a0*b3 + a1*b2 - a2*b1 + a3*b0)^2 + sage: R.<a0,a1,a2,a3,b0,b1,b2,b3> = QQbar[] # needs sage.rings.number_field + sage: ((a0^2 + a1^2 + a2^2 + a3^2) * (b0^2 + b1^2 + b2^2 + b3^2) == # needs sage.rings.number_field + ....: (a0*b0 - a1*b1 - a2*b2 - a3*b3)^2 + (a0*b1 + a1*b0 + a2*b3 - a3*b2)^2 + ....: + (a0*b2 - a1*b3 + a2*b0 + a3*b1)^2 + (a0*b3 + a1*b2 - a2*b1 + a3*b0)^2) True """ #***************************************************************************** @@ -40,6 +42,7 @@ # Sage: Open Source Mathematical Software # # Copyright (C) 2005 William Stein <wstein@gmail.com> +# 2022 Vincent Delecroix <20100.delecroix@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # @@ -53,33 +56,46 @@ # https://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.element import CommutativeRingElement, coerce_binop +import operator + +from sage.structure.element import CommutativeRingElement, coerce_binop, get_coercion_model, parent from sage.misc.misc_c import prod -import sage.rings.integer +from sage.rings.integer import Integer +import sage.rings.integer_ring from sage.rings.qqbar_decorators import handle_AA_and_QQbar from . import polydict from sage.structure.factorization import Factorization from sage.rings.polynomial.polynomial_singular_interface import Polynomial_singular_repr from sage.structure.sequence import Sequence -from .multi_polynomial import MPolynomial +from .multi_polynomial import MPolynomial, is_MPolynomial from sage.categories.morphism import Morphism from sage.misc.lazy_attribute import lazy_attribute from sage.rings.rational_field import QQ from sage.rings.fraction_field import FractionField -from sage.rings.number_field.order import is_NumberFieldOrder -from sage.categories.number_fields import NumberFields -from sage.rings.real_mpfr import RealField - -def is_MPolynomial(x): - return isinstance(x, MPolynomial) class MPolynomial_element(MPolynomial): + r""" + Generic multivariate polynomial. + + This implementation is based on the :class:`~sage.rings.polynomial.polydict.PolyDict`. + + .. TODO:: + + As mentioned in their docstring, + :class:`~sage.rings.polynomial.polydict.PolyDict` objects never clear + zeros. In all arithmetic operations on :class:`MPolynomial_element` + there is an additional call to the method ``remove_zeros`` to clear + them. This is not ideal because of the presence of inexact zeros, see + :trac:`35174`. + """ def __init__(self, parent, x): """ EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<cuberoot2> = NumberField(x^3 - 2) sage: L.<cuberoot3> = K.extension(x^3 - 3) sage: S.<sqrt2> = L.extension(x^2 - 2) @@ -94,11 +110,11 @@ def _repr_(self): """ EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(QQbar) - sage: x + QQbar(sqrt(2) - 1/2*I) # indirect doctest + sage: P.<x,y,z> = PolynomialRing(QQbar) # needs sage.rings.number_field + sage: x + QQbar(sqrt(2) - 1/2*I) # indirect doctest # needs sage.rings.number_field sage.symbolic x + 1.414213562373095? - 0.50000000000000000?*I """ - return "%s"%self.__element + return "%s" % self.__element #################### @@ -112,6 +128,7 @@ def __call__(self, *x, **kwds): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: R.<x,y> = CC[] sage: f = x^2 + y^2 sage: f(1,2) @@ -121,9 +138,9 @@ def __call__(self, *x, **kwds): :: - sage: x = PolynomialRing(CC,3,'x').gens() - sage: f = x[0] + x[1] - 2*x[1]*x[2] - sage: f + sage: # needs sage.rings.real_mpfr + sage: x = PolynomialRing(CC, 3, 'x').gens() + sage: f = x[0] + x[1] - 2*x[1]*x[2]; f (-2.00000000000000)*x1*x2 + x0 + x1 sage: f(1,2,0) 3.00000000000000 @@ -172,26 +189,26 @@ def _richcmp_(self, right, op): EXAMPLES:: - sage: R.<x,y,z>=PolynomialRing(QQbar,3,order='lex') - sage: x^1*y^2 > y^3*z^4 + sage: R.<x,y,z> = PolynomialRing(QQbar, 3, order='lex') # needs sage.rings.number_field + sage: x^1*y^2 > y^3*z^4 # needs sage.rings.number_field True - sage: x^3*y^2*z^4 < x^3*y^2*z^1 + sage: x^3*y^2*z^4 < x^3*y^2*z^1 # needs sage.rings.number_field False :: - sage: R.<x,y,z>=PolynomialRing(CC,3,order='deglex') - sage: x^1*y^2*z^3 > x^3*y^2*z^0 + sage: R.<x,y,z> = PolynomialRing(CC, 3, order='deglex') # needs sage.rings.real_mpfr + sage: x^1*y^2*z^3 > x^3*y^2*z^0 # needs sage.rings.real_mpfr True - sage: x^1*y^2*z^4 < x^1*y^1*z^5 + sage: x^1*y^2*z^4 < x^1*y^1*z^5 # needs sage.rings.real_mpfr False :: - sage: R.<x,y,z>=PolynomialRing(QQbar,3,order='degrevlex') - sage: x^1*y^5*z^2 > x^4*y^1*z^3 + sage: R.<x,y,z> = PolynomialRing(QQbar, 3, order='degrevlex') # needs sage.rings.number_field + sage: x^1*y^5*z^2 > x^4*y^1*z^3 # needs sage.rings.number_field True - sage: x^4*y^7*z^1 < x^4*y^2*z^3 + sage: x^4*y^7*z^1 < x^4*y^2*z^3 # needs sage.rings.number_field False """ return self.__element.rich_compare(right.__element, op, @@ -201,9 +218,9 @@ def _im_gens_(self, codomain, im_gens, base_map=None): """ EXAMPLES:: - sage: R.<x,y> = PolynomialRing(QQbar, 2) - sage: f = R.hom([y,x], R) - sage: f(x^2 + 3*y^5) # indirect doctest + sage: R.<x,y> = PolynomialRing(QQbar, 2) # needs sage.rings.number_field + sage: f = R.hom([y, x], R) # needs sage.rings.number_field + sage: f(x^2 + 3*y^5) # indirect doctest # needs sage.rings.number_field 3*x^5 + y^2 You can specify a map on the base ring:: @@ -235,6 +252,7 @@ def number_of_terms(self): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: R.<x, y> = CC[] sage: f = x^3 - y sage: f.number_of_terms() @@ -247,24 +265,68 @@ def number_of_terms(self): The method :meth:`hamming_weight` is an alias:: - sage: f.hamming_weight() + sage: f.hamming_weight() # needs sage.rings.real_mpfr 101 """ return len(self.element().dict()) hamming_weight = number_of_terms + def __neg__(self): + """ + Return the negative of ``self``. + + EXAMPLES:: + + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: -x # needs sage.rings.number_field + -x + sage: -(y-1) # needs sage.rings.number_field + -y + 1 + """ + return self.__class__(self.parent(), -self.__element) + def _add_(self, right): - #return self.parent()(self.__element + right.__element) - return self.__class__(self.parent(),self.__element + right.__element) + """ + Return the sum of ``self`` and ``right``. + + EXAMPLES:: + + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: x + y # needs sage.rings.number_field + x + y + """ + elt = self.__element + right.__element + elt.remove_zeros() + return self.__class__(self.parent(), elt) def _sub_(self, right): - # return self.parent()(self.__element - right.__element) - return self.__class__(self.parent(),self.__element - right.__element) + """ + Return the difference between ``self`` and ``right``. + + EXAMPLES:: + + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: x - y # needs sage.rings.number_field + x - y + """ + elt = self.__element - right.__element + elt.remove_zeros() + return self.__class__(self.parent(), elt) def _mul_(self, right): - #return self.parent()(self.__element * right.__element) - return self.__class__(self.parent(),self.__element * right.__element) + """ + Return the product between ``self`` and ``right``. + + EXAMPLES:: + + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: x * y # needs sage.rings.number_field + x*y + """ + elt = self.__element * right.__element + elt.remove_zeros() + return self.__class__(self.parent(), elt) def _lmul_(self, a): """ @@ -278,12 +340,14 @@ def _lmul_(self, a): :: - sage: R.<x,y> = QQbar[] - sage: f = (x + y) - sage: 3*f + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: f = (x + y) # needs sage.rings.number_field + sage: 3 * f # needs sage.rings.number_field 3*x + 3*y """ - return self.__class__(self.parent(),self.__element.scalar_lmult(a)) + elt = self.__element.scalar_lmult(a) + elt.remove_zeros() + return self.__class__(self.parent(), elt) def _rmul_(self, a): """ @@ -297,30 +361,32 @@ def _rmul_(self, a): :: - sage: R.<x,y> = QQbar[] - sage: f = (x + y) - sage: f*3 + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: f = (x + y) # needs sage.rings.number_field + sage: f * 3 # needs sage.rings.number_field 3*x + 3*y """ - return self.__class__(self.parent(),self.__element.scalar_rmult(a)) + elt = self.__element.scalar_rmult(a) + elt.remove_zeros() + return self.__class__(self.parent(), elt) def _div_(self, right): r""" EXAMPLES:: - sage: R.<x,y> = CC['x,y'] - sage: f = (x + y)/x; f + sage: R.<x,y> = CC['x,y'] # needs sage.rings.real_mpfr + sage: f = (x + y)/x; f # needs sage.rings.real_mpfr (x + y)/x - sage: f.parent() + sage: f.parent() # needs sage.rings.real_mpfr Fraction Field of Multivariate Polynomial Ring in x, y over Complex Field with 53 bits of precision If dividing by a scalar, there is no need to go to the fraction field of the polynomial ring:: - sage: f = (x + y)/2; f + sage: f = (x + y)/2; f # needs sage.rings.real_mpfr 0.500000000000000*x + 0.500000000000000*y - sage: f.parent() + sage: f.parent() # needs sage.rings.real_mpfr Multivariate Polynomial Ring in x, y over Complex Field with 53 bits of precision @@ -328,18 +394,18 @@ def _div_(self, right): Ensure that :trac:`13704` is fixed.:: - sage: R.<t>=PolynomialRing(QQ) - sage: S.<x,y>=PolynomialRing(R) + sage: R.<t> = PolynomialRing(QQ) + sage: S.<x,y> = PolynomialRing(R) sage: x/S(2) 1/2*x """ - if right in self.base_ring(): - inv = self.base_ring().one()/self.base_ring()(right) - return inv*self + if right.is_constant(): + inv = self.base_ring().one() / right.constant_coefficient() + return inv * self return self.parent().fraction_field()(self, right, coerce=False) def __rpow__(self, n): - if not isinstance(n, (int, sage.rings.integer.Integer)): + if not isinstance(n, (int, Integer)): raise TypeError("The exponent must be an integer.") return self.parent()(self.__element**n) @@ -365,6 +431,7 @@ def change_ring(self, R): :: + sage: # needs sage.rings.number_field sage: K.<w> = CyclotomicField(5) sage: R.<x,y> = K[] sage: f = x^2 + w*y @@ -389,14 +456,15 @@ def __init__(self, parent, x): """ EXAMPLES:: - sage: R, x = PolynomialRing(QQbar, 10, 'x').objgens() - sage: x + sage: R, x = PolynomialRing(QQbar, 10, 'x').objgens() # needs sage.rings.number_field + sage: x # needs sage.rings.number_field (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) - sage: loads(dumps(x)) == x + sage: loads(dumps(x)) == x # needs sage.rings.number_field True """ if not isinstance(x, polydict.PolyDict): - x = polydict.PolyDict(x, parent.base_ring().zero(), remove_zero=True) + x = polydict.PolyDict(x) + x.remove_zeros() MPolynomial_element.__init__(self, parent, x) def _new_constant_poly(self, x, P): @@ -417,28 +485,17 @@ def _new_constant_poly(self, x, P): """ return MPolynomial_polydict(P, {P._zero_tuple:x}) - def __neg__(self): - """ - EXAMPLES:: - - sage: R.<x,y>=QQbar[] - sage: -x - -x - sage: -(y-1) - -y + 1 - """ - return self*(-1) - def _repr_(self): """ EXAMPLES:: - sage: R.<x,y>=QQbar[] - sage: repr(-x^2-y+1) # indirect doc-test + sage: # needs sage.rings.number_field + sage: R.<x,y> = QQbar[] + sage: repr(-x^2 - y + 1) # indirect doctest '-x^2 - y + 1' - sage: K.<I>=QuadraticField(-1) - sage: R.<x,y>=K[] - sage: repr(-I*y-x^2) # indirect doc-test + sage: K.<I> = QuadraticField(-1) + sage: R.<x,y> = K[] + sage: repr(-I*y - x^2) # indirect doctest '-x^2 + (-I)*y' """ try: @@ -454,12 +511,13 @@ def _latex_(self): r""" EXAMPLES:: - sage: R.<x,y>=QQbar[] - sage: latex(-x^2-y+1) + sage: # needs sage.rings.number_field + sage: R.<x,y> = QQbar[] + sage: latex(-x^2 - y + 1) -x^{2} - y + 1 - sage: K.<I>=QuadraticField(-1) - sage: R.<x,y>=K[] - sage: latex(-I*y+I*x^2) + sage: K.<I> = QuadraticField(-1) + sage: R.<x,y> = K[] + sage: latex(-I*y + I*x^2) \left(\sqrt{-1}\right) x^{2} + \left(-\sqrt{-1}\right) y """ try: @@ -474,9 +532,9 @@ def _repr_with_changed_varnames(self, varnames): """ EXAMPLES:: - sage: R.<x,y>=QQbar[] - sage: f=-x^2-y+1 - sage: f._repr_with_changed_varnames(['jack','jill']) + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: f = -x^2 - y + 1 # needs sage.rings.number_field + sage: f._repr_with_changed_varnames(['jack', 'jill']) # needs sage.rings.number_field '-jack^2 - jill + 1' """ try: @@ -492,7 +550,7 @@ def _macaulay2_(self, macaulay2=None): EXAMPLES:: sage: R = GF(13)['a,b']['c,d'] - sage: macaulay2(R('a^2 + c')) # optional - macaulay2 + sage: macaulay2(R('a^2 + c')) # optional - macaulay2 2 c + a @@ -501,7 +559,7 @@ def _macaulay2_(self, macaulay2=None): Elements of the base ring are coerced to the polynomial ring correctly:: - sage: macaulay2(R('a^2')).ring()._operator('===', R) # optional - macaulay2 + sage: macaulay2(R('a^2')).ring()._operator('===', R) # optional - macaulay2 true """ if macaulay2 is None: @@ -519,40 +577,41 @@ def degrees(self): EXAMPLES:: - sage: R.<x,y,z>=PolynomialRing(QQbar) + sage: # needs sage.rings.number_field + sage: R.<x,y,z> = PolynomialRing(QQbar) sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 sage: f.degrees() (2, 2, 0) - sage: f = x^2+z^2 + sage: f = x^2 + z^2 sage: f.degrees() (2, 0, 2) sage: f.total_degree() # this simply illustrates that total degree is not the sum of the degrees 2 - sage: R.<x,y,z,u>=PolynomialRing(QQbar) - sage: f=(1-x)*(1+y+z+x^3)^5 + sage: R.<x,y,z,u> = PolynomialRing(QQbar) + sage: f = (1-x) * (1+y+z+x^3)^5 sage: f.degrees() (16, 5, 5, 0) sage: R(0).degrees() (0, 0, 0, 0) """ - if self.is_zero(): - return polydict.ETuple({},self.parent().ngens()) + if not self: + return polydict.ETuple({}, self.parent().ngens()) else: return self._MPolynomial_element__element.max_exp() def degree(self, x=None, std_grading=False): """ - Return the degree of self in x, where x must be one of the - generators for the parent of self. + Return the degree of ``self`` in ``x``, where ``x`` must be one of the + generators for the parent of ``self``. INPUT: - ``x`` - multivariate polynomial (a generator of the parent - of self). If ``x`` is not specified (or is None), return - the total degree, which is the maximum degree of any - monomial. Note that a weighted term ordering alters the - grading of the generators of the ring; see the tests below. - To avoid this behavior, set the optional argument ``std_grading=True``. + of ``self``). If ``x`` is not specified (or is None), return + the total degree, which is the maximum degree of any + monomial. Note that a weighted term ordering alters the + grading of the generators of the ring; see the tests below. + To avoid this behavior, set the optional argument ``std_grading=True``. OUTPUT: integer @@ -574,15 +633,15 @@ def degree(self, x=None, std_grading=False): :: - sage: R = PolynomialRing(QQ,'x,y',order=TermOrder('wdeglex',(2,3))) + sage: R = PolynomialRing(QQ, 'x,y', order=TermOrder('wdeglex',(2,3))) sage: x,y = R.gens() sage: x.degree() 2 sage: y.degree() 3 - sage: x.degree(y),x.degree(x),y.degree(x),y.degree(y) + sage: x.degree(y), x.degree(x), y.degree(x), y.degree(y) (0, 1, 0, 1) - sage: f = (x^2*y+x*y^2) + sage: f = x^2*y + x*y^2 sage: f.degree(x) 2 sage: f.degree(y) @@ -592,7 +651,7 @@ def degree(self, x=None, std_grading=False): sage: f.degree(std_grading=True) 3 - Note that if ``x`` is not a generator of the parent of self, + Note that if ``x`` is not a generator of the parent of ``self``, for example if it is a generator of a polynomial algebra which maps naturally to this one, then it is converted to an element of this algebra. (This fixes the problem reported in @@ -601,31 +660,32 @@ def degree(self, x=None, std_grading=False): :: sage: x, y = ZZ['x','y'].gens() - sage: GF(3037000453)['x','y'].gen(0).degree(x) + sage: GF(3037000453)['x','y'].gen(0).degree(x) # needs sage.rings.finite_rings 1 sage: x0, y0 = QQ['x','y'].gens() - sage: GF(3037000453)['x','y'].gen(0).degree(x0) + sage: GF(3037000453)['x','y'].gen(0).degree(x0) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: x must canonically coerce to parent - sage: GF(3037000453)['x','y'].gen(0).degree(x^2) + sage: GF(3037000453)['x','y'].gen(0).degree(x^2) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: x must be one of the generators of the parent TESTS:: - sage: R = PolynomialRing(GF(2)['t'],'x,y',order=TermOrder('wdeglex',(2,3))) - sage: x,y = R.gens() + sage: R = PolynomialRing(GF(2)['t'], 'x,y', + ....: order=TermOrder('wdeglex', (2,3))) + sage: x, y = R.gens() sage: x.degree() 2 sage: y.degree() 3 - sage: x.degree(y),x.degree(x),y.degree(x),y.degree(y) + sage: x.degree(y), x.degree(x), y.degree(x), y.degree(y) (0, 1, 0, 1) - sage: f = (x^2*y+x*y^2) + sage: f = (x^2*y + x*y^2) sage: f.degree(x) 2 sage: f.degree(y) @@ -639,7 +699,7 @@ def degree(self, x=None, std_grading=False): Degree of zero polynomial for other implementation :trac:`20048` :: - sage: R.<x,y> = GF(3037000453)[] + sage: R.<x,y> = GF(3037000453)[] # needs sage.rings.finite_rings sage: R.zero().degree(x) -1 """ @@ -661,28 +721,29 @@ def degree(self, x=None, std_grading=False): def total_degree(self): """ - Return the total degree of self, which is the maximum degree of any - monomial in self. + Return the total degree of ``self``, which is the maximum degree of any + monomial in ``self``. EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y,z> = QQbar[] - sage: f=2*x*y^3*z^2 + sage: f = 2*x*y^3*z^2 sage: f.total_degree() 6 - sage: f=4*x^2*y^2*z^3 + sage: f = 4*x^2*y^2*z^3 sage: f.total_degree() 7 - sage: f=99*x^6*y^3*z^9 + sage: f = 99*x^6*y^3*z^9 sage: f.total_degree() 18 - sage: f=x*y^3*z^6+3*x^2 + sage: f = x*y^3*z^6 + 3*x^2 sage: f.total_degree() 10 - sage: f=z^3+8*x^4*y^5*z + sage: f = z^3 + 8*x^4*y^5*z sage: f.total_degree() 10 - sage: f=z^9+10*x^4+y^8*x^2 + sage: f = z^9 + 10*x^4 + y^8*x^2 sage: f.total_degree() 10 """ @@ -690,8 +751,8 @@ def total_degree(self): def monomial_coefficient(self, mon): """ - Return the coefficient in the base ring of the monomial mon in - self, where mon must have the same parent as self. + Return the coefficient in the base ring of the monomial ``mon`` in + ``self``, where ``mon`` must have the same parent as ``self``. This function contrasts with the function ``coefficient`` which returns the coefficient of a @@ -712,16 +773,10 @@ def monomial_coefficient(self, mon): EXAMPLES: - The parent of the return is a member of the base ring. - - :: - - sage: R.<x,y>=QQbar[] - - The parent of the return is a member of the base ring. - :: + sage: # needs sage.rings.number_field + sage: R.<x,y> = QQbar[] sage: f = 2 * x * y sage: c = f.monomial_coefficient(x*y); c 2 @@ -730,6 +785,7 @@ def monomial_coefficient(self, mon): :: + sage: # needs sage.rings.number_field sage: f = y^2 + y^2*x - x^9 - 7*x + 5*x*y sage: f.monomial_coefficient(y^2) 1 @@ -742,19 +798,20 @@ def monomial_coefficient(self, mon): :: - sage: var('a') - a - sage: K.<a> = NumberField(a^2+a+1) + sage: # needs sage.rings.number_field + sage: a = polygen(ZZ, 'a') + sage: K.<a> = NumberField(a^2 + a + 1) sage: P.<x,y> = K[] - sage: f=(a*x-1)*((a+1)*y-1); f + sage: f = (a*x - 1) * ((a+1)*y - 1); f -x*y + (-a)*x + (-a - 1)*y + 1 sage: f.monomial_coefficient(x) -a """ - if not (isinstance(mon, MPolynomial) and mon.parent() is self.parent() and mon.is_monomial()): - raise TypeError("mon must be a monomial in the parent of self.") - R = self.parent().base_ring() - return R(self.element().monomial_coefficient(mon.element().dict())) + if parent(mon) is not self.parent(): + raise TypeError("mon must be a monomial in the parent of self") + exp = polydict.monomial_exponent(mon.element()) + zero = self.parent().base_ring().zero() + return self.element().get(exp, zero) def dict(self): """ @@ -769,23 +826,23 @@ def __iter__(self): EXAMPLES:: - sage: R.<x,y,z> = PolynomialRing(QQbar, order='lex') - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) - sage: list(f) + sage: R.<x,y,z> = PolynomialRing(QQbar, order='lex') # needs sage.rings.number_field + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # needs sage.rings.number_field + sage: list(f) # needs sage.rings.number_field [(1, x^4*y*z^3), (1, x^2*z), (1, x*y^5*z^2)] :: - sage: R.<x,y,z> = PolynomialRing(QQbar, order='deglex') - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) - sage: list(f) + sage: R.<x,y,z> = PolynomialRing(QQbar, order='deglex') # needs sage.rings.number_field + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # needs sage.rings.number_field + sage: list(f) # needs sage.rings.number_field [(1, x^4*y*z^3), (1, x*y^5*z^2), (1, x^2*z)] :: - sage: R.<x,y,z> = PolynomialRing(QQbar, order='degrevlex') - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) - sage: list(f) + sage: R.<x,y,z> = PolynomialRing(QQbar, order='degrevlex') # needs sage.rings.number_field + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # needs sage.rings.number_field + sage: list(f) # needs sage.rings.number_field [(1, x*y^5*z^2), (1, x^4*y*z^3), (1, x^2*z)] :: @@ -803,11 +860,7 @@ def __iter__(self): ring = self.parent() one = ring.base_ring().one() for exp in self._exponents: - yield (elt[exp], - MPolynomial_polydict(ring, polydict.PolyDict({exp:one}, - force_int_exponents=False, - force_etuples=False)) - ) + yield (elt[exp], MPolynomial_polydict(ring, polydict.PolyDict({exp: one}, check=False))) def __getitem__(self, x): """ @@ -820,6 +873,7 @@ def __getitem__(self, x): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x, y> = PolynomialRing(QQbar, 2) sage: f = -10*x^3*y + 17*x*y sage: f[3,1] @@ -831,11 +885,11 @@ def __getitem__(self, x): :: - sage: R.<x> = PolynomialRing(QQbar,1); R + sage: R.<x> = PolynomialRing(QQbar, 1); R # needs sage.rings.number_field Multivariate Polynomial Ring in x over Algebraic Field - sage: f = 5*x^2 + 3; f + sage: f = 5*x^2 + 3; f # needs sage.rings.number_field 5*x^2 + 3 - sage: f[2] + sage: f[2] # needs sage.rings.number_field 5 """ if isinstance(x, MPolynomial): @@ -861,14 +915,14 @@ def iterator_exp_coeff(self, as_ETuples=True): EXAMPLES:: - sage: R.<x,y,z> = PolynomialRing(QQbar, order='lex') - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) - sage: list(f.iterator_exp_coeff()) + sage: R.<x,y,z> = PolynomialRing(QQbar, order='lex') # needs sage.rings.number_field + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # needs sage.rings.number_field + sage: list(f.iterator_exp_coeff()) # needs sage.rings.number_field [((4, 1, 3), 1), ((2, 0, 1), 1), ((1, 5, 2), 1)] - sage: R.<x,y,z> = PolynomialRing(QQbar, order='deglex') - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) - sage: list(f.iterator_exp_coeff(as_ETuples=False)) + sage: R.<x,y,z> = PolynomialRing(QQbar, order='deglex') # needs sage.rings.number_field + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) # needs sage.rings.number_field + sage: list(f.iterator_exp_coeff(as_ETuples=False)) # needs sage.rings.number_field [((4, 1, 3), 1), ((1, 5, 2), 1), ((2, 0, 1), 1)] """ elt = self.element() @@ -904,7 +958,7 @@ def coefficient(self, degrees): - a monomial (very fast, but not as flexible) - OUTPUT: element of the parent of self + OUTPUT: element of the parent of ``self`` .. SEEALSO:: @@ -913,25 +967,26 @@ def coefficient(self, degrees): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x, y> = QQbar[] sage: f = 2 * x * y - sage: c = f.coefficient({x:1,y:1}); c + sage: c = f.coefficient({x: 1, y: 1}); c 2 sage: c.parent() Multivariate Polynomial Ring in x, y over Algebraic Field - sage: c in PolynomialRing(QQbar, 2, names = ['x','y']) + sage: c in PolynomialRing(QQbar, 2, names=['x', 'y']) True sage: f = y^2 - x^9 - 7*x + 5*x*y - sage: f.coefficient({y:1}) + sage: f.coefficient({y: 1}) 5*x - sage: f.coefficient({y:0}) + sage: f.coefficient({y: 0}) -x^9 + (-7)*x - sage: f.coefficient({x:0,y:0}) + sage: f.coefficient({x: 0, y: 0}) 0 - sage: f=(1+y+y^2)*(1+x+x^2) - sage: f.coefficient({x:0}) + sage: f = (1+y+y^2) * (1+x+x^2) + sage: f.coefficient({x: 0}) y^2 + y + 1 - sage: f.coefficient([0,None]) + sage: f.coefficient([0, None]) y^2 + y + 1 sage: f.coefficient(x) y^2 + y + 1 @@ -942,9 +997,10 @@ def coefficient(self, degrees): :: + sage: # needs sage.rings.real_mpfr sage: R.<x,y> = RR[] - sage: f=x*y+5 - sage: c=f.coefficient({x:0,y:0}); c + sage: f = x*y + 5 + sage: c = f.coefficient({x: 0, y: 0}); c 5.00000000000000 sage: parent(c) Multivariate Polynomial Ring in x, y over Real Field with 53 bits of precision @@ -979,21 +1035,20 @@ def global_height(self, prec=None): INPUT: - ``prec`` -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). - OUTPUT: - - - a real number. + OUTPUT: a real number. EXAMPLES:: - sage: R.<x,y> = PolynomialRing(QQbar, 2) - sage: f = QQbar(i)*x^2 + 3*x*y - sage: f.global_height() + sage: R.<x,y> = PolynomialRing(QQbar, 2) # needs sage.rings.number_field + sage: f = QQbar(i)*x^2 + 3*x*y # needs sage.rings.number_field + sage: f.global_height() # needs sage.rings.number_field 1.09861228866811 Scaling should not change the result:: + sage: # needs sage.rings.number_field sage.symbolic sage: R.<x, y> = PolynomialRing(QQbar, 2) sage: f = 1/25*x^2 + 25/3*x + 1 + QQbar(sqrt(2))*y^2 sage: f.global_height() @@ -1004,10 +1059,11 @@ def global_height(self, prec=None): :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: K.<k> = NumberField(x^2 + 1) sage: Q.<q,r> = PolynomialRing(K, implementation='generic') - sage: f = 12*q + sage: f = 12 * q sage: f.global_height() 0.000000000000000 @@ -1015,30 +1071,33 @@ def global_height(self, prec=None): sage: R.<x,y> = PolynomialRing(QQ, implementation='generic') sage: f = 1/123*x*y + 12 - sage: f.global_height(prec=2) + sage: f.global_height(prec=2) # needs sage.symbolic 8.0 :: sage: R.<x,y> = PolynomialRing(QQ, implementation='generic') sage: f = 0*x*y - sage: f.global_height() + sage: f.global_height() # needs sage.rings.real_mpfr 0.000000000000000 """ if prec is None: prec = 53 if self.is_zero(): + from sage.rings.real_mpfr import RealField return RealField(prec).zero() - from sage.rings.qqbar import QQbar, number_field_elements_from_algebraics + from sage.categories.number_fields import NumberFields K = self.base_ring() - if K in NumberFields() or is_NumberFieldOrder(K): + if K in NumberFields() or isinstance(K, (sage.rings.abc.Order, sage.rings.integer_ring.IntegerRing_class)): from sage.schemes.projective.projective_space import ProjectiveSpace Pr = ProjectiveSpace(K, self.number_of_terms()-1) return Pr.point(self.coefficients()).global_height(prec=prec) - if K is QQbar: + if isinstance(K, sage.rings.abc.AlgebraicField): + from sage.rings.qqbar import number_field_elements_from_algebraics + K_pre, P, phi = number_field_elements_from_algebraics(list(self.coefficients())) from sage.schemes.projective.projective_space import ProjectiveSpace Pr = ProjectiveSpace(K_pre, len(P)-1) @@ -1058,39 +1117,40 @@ def local_height(self, v, prec=None): - ``prec`` -- desired floating point precision (default: default RealField precision). - OUTPUT: - - - a real number. + OUTPUT: a real number. EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ, implementation='generic') sage: f = 1/1331*x^2 + 1/4000*y - sage: f.local_height(1331) + sage: f.local_height(1331) # needs sage.rings.real_mpfr 7.19368581839511 :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: K.<k> = NumberField(x^2 - 5) sage: T.<t,w> = PolynomialRing(K, implementation='generic') sage: I = K.ideal(3) sage: f = 1/3*t*w + 3 - sage: f.local_height(I) + sage: f.local_height(I) # needs sage.symbolic 1.09861228866811 :: sage: R.<x,y> = PolynomialRing(QQ, implementation='generic') sage: f = 1/2*x*y + 2 - sage: f.local_height(2, prec=2) + sage: f.local_height(2, prec=2) # needs sage.rings.real_mpfr 0.75 """ + from sage.categories.number_fields import NumberFields + if prec is None: prec = 53 K = FractionField(self.base_ring()) - if K not in NumberFields() or is_NumberFieldOrder(K): + if not (K in NumberFields() or isinstance(K, (sage.rings.abc.Order, IntegerRing_class))): raise TypeError("must be over a Numberfield or a Numberfield order") return max([K(c).local_height(v, prec=prec) for c in self.coefficients()]) @@ -1105,21 +1165,20 @@ def local_height_arch(self, i, prec=None): - ``i`` -- an integer. - ``prec`` -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). - OUTPUT: - - - a real number. + OUTPUT: a real number. EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ, implementation='generic') sage: f = 210*x*y - sage: f.local_height_arch(0) + sage: f.local_height_arch(0) # needs sage.rings.real_mpfr 5.34710753071747 :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: K.<k> = NumberField(x^2 - 5) sage: T.<t,w> = PolynomialRing(K, implementation='generic') @@ -1131,14 +1190,16 @@ def local_height_arch(self, i, prec=None): sage: R.<x,y> = PolynomialRing(QQ, implementation='generic') sage: f = 1/2*x*y + 3 - sage: f.local_height_arch(0, prec=2) + sage: f.local_height_arch(0, prec=2) # needs sage.rings.real_mpfr 1.0 """ + from sage.categories.number_fields import NumberFields + if prec is None: prec = 53 K = FractionField(self.base_ring()) - if K not in NumberFields() or is_NumberFieldOrder(K): + if not (K in NumberFields() or isinstance(K, (sage.rings.abc.Order, IntegerRing_class))): return TypeError("must be over a Numberfield or a Numberfield Order") if K == QQ: @@ -1153,9 +1214,9 @@ def _exponents(self): EXAMPLES:: - sage: R.<a,b,c> = PolynomialRing(QQbar, 3) - sage: f = a^3 + b + 2*b^2 - sage: f._exponents + sage: R.<a,b,c> = PolynomialRing(QQbar, 3) # needs sage.rings.number_field + sage: f = a^3 + b + 2*b^2 # needs sage.rings.number_field + sage: f._exponents # needs sage.rings.number_field [(3, 0, 0), (0, 2, 0), (0, 1, 0)] """ return sorted(self.element().dict(), key=self.parent().term_order().sortkey, reverse=True) @@ -1175,22 +1236,23 @@ def exponents(self, as_ETuples=True): EXAMPLES:: - sage: R.<a,b,c> = PolynomialRing(QQbar, 3) - sage: f = a^3 + b + 2*b^2 - sage: f.exponents() + sage: R.<a,b,c> = PolynomialRing(QQbar, 3) # needs sage.rings.number_field + sage: f = a^3 + b + 2*b^2 # needs sage.rings.number_field + sage: f.exponents() # needs sage.rings.number_field [(3, 0, 0), (0, 2, 0), (0, 1, 0)] By default the list of exponents is a list of ETuples:: - sage: type(f.exponents()[0]) + sage: type(f.exponents()[0]) # needs sage.rings.number_field <class 'sage.rings.polynomial.polydict.ETuple'> - sage: type(f.exponents(as_ETuples=False)[0]) + sage: type(f.exponents(as_ETuples=False)[0]) # needs sage.rings.number_field <... 'tuple'> TESTS: Check that we can mutate the list and not change the result:: + sage: # needs sage.rings.number_field sage: R.<a,b,c> = PolynomialRing(QQbar, 3) sage: f = a^3 + b + 2*b^2 sage: E = f.exponents(); E @@ -1225,16 +1287,17 @@ def inverse_of_unit(self): def is_homogeneous(self): """ - Return True if self is a homogeneous polynomial. + Return ``True`` if ``self`` is a homogeneous polynomial. EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] - sage: (x+y).is_homogeneous() + sage: (x + y).is_homogeneous() True sage: (x.parent()(0)).is_homogeneous() True - sage: (x+y^2).is_homogeneous() + sage: (x + y^2).is_homogeneous() False sage: (x^2 + y^2).is_homogeneous() True @@ -1262,6 +1325,7 @@ def _homogenize(self, var): EXAMPLES:: + sage: # needs sage.rings.number_field sage: P.<x,y> = QQbar[] sage: f = x^2 + y + 1 + 5*x*y^1 sage: g = f.homogenize('z'); g # indirect doctest @@ -1274,6 +1338,7 @@ def _homogenize(self, var): if self.is_homogeneous(): return self X = self.element().homogenize(var) + X.remove_zeros() R = self.parent() return R(X) @@ -1283,10 +1348,11 @@ def is_generator(self): EXAMPLES:: - sage: R.<x,y>=QQbar[] + sage: # needs sage.rings.number_field + sage: R.<x,y> = QQbar[] sage: x.is_generator() True - sage: (x+y-y).is_generator() + sage: (x + y - y).is_generator() True sage: (x*y).is_generator() False @@ -1306,21 +1372,22 @@ def is_monomial(self): EXAMPLES:: - sage: R.<x,y>=QQbar[] + sage: # needs sage.rings.number_field + sage: R.<x,y> = QQbar[] sage: x.is_monomial() True - sage: (x+2*y).is_monomial() + sage: (x + 2*y).is_monomial() False sage: (2*x).is_monomial() False sage: (x*y).is_monomial() True - To allow a non-1 leading coefficient, use is_term():: + To allow a non-1 leading coefficient, use :meth:`is_term`:: - sage: (2*x*y).is_term() + sage: (2*x*y).is_term() # needs sage.rings.number_field True - sage: (2*x*y).is_monomial() + sage: (2*x*y).is_monomial() # needs sage.rings.number_field False """ return len(self.element()) == 1 and self.element().coefficients()[0] == 1 @@ -1335,31 +1402,32 @@ def is_term(self): EXAMPLES:: - sage: R.<x,y>=QQbar[] + sage: # needs sage.rings.number_field + sage: R.<x,y> = QQbar[] sage: x.is_term() True - sage: (x+2*y).is_term() + sage: (x + 2*y).is_term() False sage: (2*x).is_term() True sage: (7*x^5*y).is_term() True - To require leading coefficient 1, use is_monomial():: + To require leading coefficient 1, use :meth:`is_monomial`:: - sage: (2*x*y).is_monomial() + sage: (2*x*y).is_monomial() # needs sage.rings.number_field False - sage: (2*x*y).is_term() + sage: (2*x*y).is_term() # needs sage.rings.number_field True """ return len(self.element()) == 1 def subs(self, fixed=None, **kw): """ - Fixes some given variables in a given multivariate polynomial and - returns the changed multivariate polynomials. The polynomial itself - is not affected. The variable,value pairs for fixing are to be - provided as a dictionary of the form {variable:value}. + Fix some given variables in a given multivariate polynomial and + return the changed multivariate polynomials. The polynomial itself + is not affected. The variable, value pairs for fixing are to be + provided as a dictionary of the form ``{variable: value}``. This is a special case of evaluating the polynomial with some of the variables constants and the others the original variables. @@ -1372,55 +1440,56 @@ def subs(self, fixed=None, **kw): - ``**kw`` - named parameters - OUTPUT: new MPolynomial + OUTPUT: new :class:`MPolynomial` EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: f = x^2 + y + x^2*y^2 + 5 - sage: f((5,y)) + sage: f((5, y)) 25*y^2 + y + 30 - sage: f.subs({x:5}) + sage: f.subs({x: 5}) 25*y^2 + y + 30 """ variables = list(self.parent().gens()) for i in range(0,len(variables)): if str(variables[i]) in kw: - variables[i]=kw[str(variables[i])] + variables[i] = kw[str(variables[i])] elif fixed and variables[i] in fixed: variables[i] = fixed[variables[i]] return self(tuple(variables)) def monomials(self): """ - Returns the list of monomials in self. The returned list is - decreasingly ordered by the term ordering of self.parent(). + Return the list of monomials in ``self``. The returned list is + decreasingly ordered by the term ordering of ``self.parent()``. - OUTPUT: list of MPolynomials representing Monomials + OUTPUT: list of :class:`MPolynomial` instances, representing monomials EXAMPLES:: - sage: R.<x,y> = QQbar[] - sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 - sage: f.monomials() + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 # needs sage.rings.number_field + sage: f.monomials() # needs sage.rings.number_field [x^2*y^2, x^2, y, 1] :: + sage: # needs sage.rings.number_field sage: R.<fx,fy,gx,gy> = QQbar[] - sage: F = ((fx*gy - fy*gx)^3) - sage: F + sage: F = (fx*gy - fy*gx)^3; F -fy^3*gx^3 + 3*fx*fy^2*gx^2*gy + (-3)*fx^2*fy*gx*gy^2 + fx^3*gy^3 sage: F.monomials() [fy^3*gx^3, fx*fy^2*gx^2*gy, fx^2*fy*gx*gy^2, fx^3*gy^3] sage: F.coefficients() [-1, 3, -3, 1] - sage: sum(map(mul,zip(F.coefficients(),F.monomials()))) == F + sage: sum(map(mul, zip(F.coefficients(), F.monomials()))) == F True """ ring = self.parent() one = ring.base_ring().one() - return [MPolynomial_polydict(ring, polydict.PolyDict({m:one}, force_int_exponents=False, force_etuples=False)) + return [MPolynomial_polydict(ring, polydict.PolyDict({m: one}, check=False)) for m in self._exponents] def constant_coefficient(self): @@ -1429,6 +1498,7 @@ def constant_coefficient(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 sage: f.constant_coefficient() @@ -1446,16 +1516,17 @@ def constant_coefficient(self): def is_univariate(self): """ - Returns True if this multivariate polynomial is univariate and + Return ``True`` if this multivariate polynomial is univariate and False otherwise. EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 sage: f.is_univariate() False - sage: g = f.subs({x:10}); g + sage: g = f.subs({x: 10}); g 700*y^2 + (-2)*y + 305 sage: g.is_univariate() True @@ -1483,27 +1554,28 @@ def univariate_polynomial(self, R=None): INPUT: - - ``R`` - (default: None) PolynomialRing + - ``R`` - (default: None) :class:`PolynomialRing` If this polynomial is not in at most one variable, then a - ValueError exception is raised. This is checked using the - is_univariate() method. The new Polynomial is over the same base - ring as the given MPolynomial. + :class:`ValueError` exception is raised. This is checked using the + method :meth:`is_univariate`. The new :class:`Polynomial` is over the same base + ring as the given :class:`MPolynomial`. EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 sage: f.univariate_polynomial() Traceback (most recent call last): ... TypeError: polynomial must involve at most one variable - sage: g = f.subs({x:10}); g + sage: g = f.subs({x: 10}); g 700*y^2 + (-2)*y + 305 - sage: g.univariate_polynomial () + sage: g.univariate_polynomial() 700*y^2 - 2*y + 305 - sage: g.univariate_polynomial(PolynomialRing(QQ,'z')) + sage: g.univariate_polynomial(PolynomialRing(QQ, 'z')) 700*z^2 - 2*z + 305 TESTS:: @@ -1558,11 +1630,12 @@ def variables(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 sage: f.variables() (x, y) - sage: g = f.subs({x:10}); g + sage: g = f.subs({x: 10}); g 700*y^2 + (-2)*y + 305 sage: g.variables() (y,) @@ -1579,10 +1652,11 @@ def variables(self): def variable(self,i): """ - Returns `i`-th variable occurring in this polynomial. + Return the `i`-th variable occurring in this polynomial. EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 sage: f.variable(0) @@ -1594,17 +1668,18 @@ def variable(self,i): def nvariables(self): """ - Number of variables in this polynomial + Return the number of variables in this polynomial. EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 - sage: f.nvariables () + sage: f.nvariables() 2 - sage: g = f.subs({x:10}); g + sage: g = f.subs({x: 10}); g 700*y^2 + (-2)*y + 305 - sage: g.nvariables () + sage: g.nvariables() 1 """ return len(self.degrees().nonzero_positions()) @@ -1615,6 +1690,7 @@ def is_constant(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: f = 3*x^2 - 2*y + 7*x^2*y^2 + 5 sage: f.is_constant() @@ -1627,12 +1703,12 @@ def is_constant(self): def lm(self): """ - Returns the lead monomial of self with respect to the term order of - self.parent(). + Return the lead monomial of ``self`` with respect to the term order of + ``self.parent()``. EXAMPLES:: - sage: R.<x,y,z>=PolynomialRing(GF(7),3,order='lex') + sage: R.<x,y,z> = PolynomialRing(GF(7), 3, order='lex') sage: (x^1*y^2 + y^3*z^4).lm() x*y^2 sage: (x^3*y^2*z^4 + x^3*y^2*z^1).lm() @@ -1640,7 +1716,8 @@ def lm(self): :: - sage: R.<x,y,z>=PolynomialRing(CC,3,order='deglex') + sage: # needs sage.rings.real_mpfr + sage: R.<x,y,z> = PolynomialRing(CC, 3, order='deglex') sage: (x^1*y^2*z^3 + x^3*y^2*z^0).lm() x*y^2*z^3 sage: (x^1*y^2*z^4 + x^1*y^1*z^5).lm() @@ -1648,7 +1725,8 @@ def lm(self): :: - sage: R.<x,y,z>=PolynomialRing(QQbar,3,order='degrevlex') + sage: # needs sage.rings.number_field + sage: R.<x,y,z> = PolynomialRing(QQbar, 3, order='degrevlex') sage: (x^1*y^5*z^2 + x^4*y^1*z^3).lm() x*y^5*z^2 sage: (x^4*y^7*z^1 + x^4*y^2*z^3).lm() @@ -1657,8 +1735,8 @@ def lm(self): TESTS:: sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict - sage: R.<x,y>=MPolynomialRing_polydict(GF(2),2,order='lex') - sage: f=x+y + sage: R.<x,y> = MPolynomialRing_polydict(GF(2), 2, order='lex') + sage: f = x + y sage: f.lm() x @@ -1669,21 +1747,21 @@ def lm(self): if self.is_zero(): return self R = self.parent() - f = self._MPolynomial_element__element.lcmt( R.term_order().greater_tuple ) + f = self._MPolynomial_element__element.lcmt(R.term_order().greater_tuple) one = R.base_ring().one() - self.__lm = MPolynomial_polydict(R,polydict.PolyDict({f:one},zero=R.base_ring().zero(),force_int_exponents=False, force_etuples=False)) + self.__lm = MPolynomial_polydict(R,polydict.PolyDict({f: one}, check=False)) return self.__lm def lc(self): """ - Returns the leading coefficient of self i.e., - self.coefficient(self.lm()) + Returns the leading coefficient of ``self``, i.e., + ``self.coefficient(self.lm())`` EXAMPLES:: - sage: R.<x,y,z>=QQbar[] - sage: f=3*x^2-y^2-x*y - sage: f.lc() + sage: R.<x,y,z> = QQbar[] # needs sage.rings.number_field + sage: f = 3*x^2 - y^2 - x*y # needs sage.rings.number_field + sage: f.lc() # needs sage.rings.number_field 3 """ try: @@ -1698,26 +1776,27 @@ def lc(self): def lt(self): r""" - Returns the leading term of self i.e., self.lc()\*self.lm(). The + Return the leading term of ``self`` i.e., ``self.lc()*self.lm()``. The notion of "leading term" depends on the ordering defined in the parent ring. EXAMPLES:: - sage: R.<x,y,z>=PolynomialRing(QQbar) - sage: f=3*x^2-y^2-x*y + sage: # needs sage.rings.number_field + sage: R.<x,y,z> = PolynomialRing(QQbar) + sage: f = 3*x^2 - y^2 - x*y sage: f.lt() 3*x^2 - sage: R.<x,y,z>=PolynomialRing(QQbar,order="invlex") - sage: f=3*x^2-y^2-x*y + sage: R.<x,y,z> = PolynomialRing(QQbar, order="invlex") + sage: f = 3*x^2 - y^2 - x*y sage: f.lt() -y^2 TESTS:: sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict - sage: R.<x,y>=MPolynomialRing_polydict(GF(2),2,order='lex') - sage: f=x+y + sage: R.<x,y> = MPolynomialRing_polydict(GF(2), 2, order='lex') + sage: f = x + y sage: f.lt() x """ @@ -1728,11 +1807,11 @@ def lt(self): return self R = self.parent() f = self._MPolynomial_element__element.dict() - res = self._MPolynomial_element__element.lcmt( R.term_order().greater_tuple ) - self.__lt = MPolynomial_polydict(R,polydict.PolyDict({res:f[res]},zero=R.base_ring().zero(),force_int_exponents=False, force_etuples=False)) + res = self._MPolynomial_element__element.lcmt(R.term_order().greater_tuple) + self.__lt = MPolynomial_polydict(R, polydict.PolyDict({res: f[res]}, check=False)) return self.__lt - def __eq__(self,right): + def __eq__(self, right): if not isinstance(right, MPolynomial_polydict): # we want comparison with zero to be fast if not right: @@ -1740,7 +1819,7 @@ def __eq__(self,right): return CommutativeRingElement.__eq__(self, right) return self._MPolynomial_element__element == right._MPolynomial_element__element - def __ne__(self,right): + def __ne__(self, right): if not isinstance(right, MPolynomial_polydict): # we want comparison with zero to be fast if not right: @@ -1753,17 +1832,17 @@ def __ne__(self,right): def __bool__(self): """ - Return True if self != 0 + Return ``True`` if self != 0 .. note:: This is much faster than actually writing ``self == 0``. """ - return self._MPolynomial_element__element.dict()!={} + return bool(self._MPolynomial_element__element) def _floordiv_(self, right): r""" - Quotient of division of self by other. This is denoted //. + Quotient of division of ``self`` by other. This is denoted //. .. note:: @@ -1772,7 +1851,8 @@ def _floordiv_(self, right): EXAMPLES:: - sage: R.<x,y>=QQbar[] + sage: # needs sage.rings.number_field + sage: R.<x,y> = QQbar[] sage: 2*x*y//y 2*x sage: 2*x//y @@ -1800,7 +1880,7 @@ def _derivative(self, var=None): r""" Differentiates ``self`` with respect to variable ``var``. - If ``var`` is not one of the generators of this ring, _derivative(var) + If ``var`` is not one of the generators of this ring, ``_derivative(var)`` is called recursively on each coefficient of this polynomial. .. SEEALSO:: @@ -1809,15 +1889,18 @@ def _derivative(self, var=None): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<t> = PowerSeriesRing(QQbar) sage: S.<x, y> = PolynomialRing(R) sage: f = (t^2 + O(t^3))*x^2*y^3 + (37*t^4 + O(t^5))*x^3 sage: f.parent() - Multivariate Polynomial Ring in x, y over Power Series Ring in t over Algebraic Field + Multivariate Polynomial Ring in x, y + over Power Series Ring in t over Algebraic Field sage: f._derivative(x) # with respect to x (2*t^2 + O(t^3))*x*y^3 + (111*t^4 + O(t^5))*x^2 sage: f._derivative(x).parent() - Multivariate Polynomial Ring in x, y over Power Series Ring in t over Algebraic Field + Multivariate Polynomial Ring in x, y + over Power Series Ring in t over Algebraic Field sage: f._derivative(y) # with respect to y (3*t^2 + O(t^3))*x^2*y^2 sage: f._derivative(t) # with respect to t (recurses into base ring) @@ -1835,36 +1918,31 @@ def _derivative(self, var=None): raise ValueError("must specify which variable to differentiate with respect to") P = self.parent() - gens = list(P.gens()) # check if var is one of the generators - try: - index = gens.index(var) - except ValueError: + index = polydict.gen_index(P(var).element()) + if index == -1: # var is not a generator; do term-by-term differentiation recursively # var may be, for example, a generator of the base ring d = dict([(e, x._derivative(var)) for (e, x) in self.dict().items()]) - d = polydict.PolyDict(d, P.base_ring().zero(), remove_zero=True) + d = polydict.PolyDict(d, check=False) + d.remove_zeros() return MPolynomial_polydict(P, d) # differentiate w.r.t. indicated variable - d = {} - v = polydict.ETuple({index:1}, len(gens)) - for (exp, coeff) in self.dict().items(): - if exp[index] > 0: - d[exp.esub(v)] = coeff * exp[index] - d = polydict.PolyDict(d, P.base_ring().zero(), remove_zero=True) - return MPolynomial_polydict(P, d) + elt = self.element().derivative_i(index) + elt.remove_zeros() + return MPolynomial_polydict(P, elt) def integral(self, var=None): r""" - Integrates ``self`` with respect to variable ``var``. + Integrate ``self`` with respect to variable ``var``. .. NOTE:: The integral is always chosen so the constant term is 0. - If ``var`` is not one of the generators of this ring, integral(var) + If ``var`` is not one of the generators of this ring, ``integral(var)`` is called recursively on each coefficient of this polynomial. EXAMPLES: @@ -1878,18 +1956,26 @@ def integral(self, var=None): sage: it.parent() == x.parent() True + sage: R = ZZ['x']['y, z'] + sage: y, z = R.gens() + sage: R.an_element().integral(y).parent() + Multivariate Polynomial Ring in y, z + over Univariate Polynomial Ring in x over Rational Field + On polynomials with coefficients in power series:: + sage: # needs sage.rings.number_field sage: R.<t> = PowerSeriesRing(QQbar) sage: S.<x, y> = PolynomialRing(R) sage: f = (t^2 + O(t^3))*x^2*y^3 + (37*t^4 + O(t^5))*x^3 sage: f.parent() - Multivariate Polynomial Ring in x, y over Power Series Ring in t over Algebraic Field + Multivariate Polynomial Ring in x, y + over Power Series Ring in t over Algebraic Field sage: f.integral(x) # with respect to x (1/3*t^2 + O(t^3))*x^3*y^3 + (37/4*t^4 + O(t^5))*x^4 sage: f.integral(x).parent() - Multivariate Polynomial Ring in x, y over Power Series Ring in t over Algebraic Field - + Multivariate Polynomial Ring in x, y + over Power Series Ring in t over Algebraic Field sage: f.integral(y) # with respect to y (1/4*t^2 + O(t^3))*x^2*y^4 + (37*t^4 + O(t^5))*x^3*y sage: f.integral(t) # with respect to t (recurses into base ring) @@ -1897,36 +1983,50 @@ def integral(self, var=None): TESTS:: - sage: f.integral() # can't figure out the variable + sage: f.integral() # can't figure out the variable # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: must specify which variable to integrate with respect to + + :trac:`34000`:: + + sage: R = ZZ['x']['y,z'] + sage: y, z = R.gens() + sage: parent(y.integral(y)) + Multivariate Polynomial Ring in y, z over Univariate Polynomial Ring in x over Rational Field """ if var is None: raise ValueError("must specify which variable to integrate " "with respect to") + # TODO: + # calling the coercion model bin_op is much more accurate than using the + # true division (which is bypassed by polynomials). But it does not work + # in all cases!! + # See similar in polynomial_element.pyx P = self.parent() - gens = list(P.gens()) + cm = get_coercion_model() + try: + S = cm.bin_op(P.one(), sage.rings.integer_ring.ZZ.one(), operator.truediv).parent() + except TypeError: + Q = (P.base_ring().one() / sage.rings.integer_ring.ZZ.one()).parent() + S = P.change_ring(Q) + + if P is not S: + return S.coerce(self).integral(var) # check if var is one of the generators - try: - index = gens.index(var) - except ValueError: + index = polydict.gen_index(P(var).element()) + if index == -1: # var is not a generator; do term-by-term integration recursively # var may be, for example, a generator of the base ring - d = dict([(e, x.integral(var)) - for (e, x) in self.dict().items()]) - d = polydict.PolyDict(d, P.base_ring().zero(), - remove_zero=True) - return MPolynomial_polydict(P, d) - - # integrate w.r.t. indicated variable - d = {} - v = polydict.ETuple({index:1}, len(gens)) - for (exp, coeff) in self.dict().items(): - d[exp.eadd(v)] = coeff / (1+exp[index]) - d = polydict.PolyDict(d, P.base_ring().zero(), remove_zero=True) + d = {e: x.integral(var) + for e, x in self.dict().items()} + d = polydict.PolyDict(d, check=False) + d.remove_zeros() + else: + # integrate w.r.t. indicated variable + d = self.element().integral_i(index) return MPolynomial_polydict(P, d) def factor(self, proof=None): @@ -1935,7 +2035,7 @@ def factor(self, proof=None): INPUT: - - ``proof'' - insist on provably correct results (default: ``True`` + - ``proof`` - insist on provably correct results (default: ``True`` unless explicitly disabled for the ``"polynomial"`` subsystem with :class:`sage.structure.proof.proof.WithProof`.) @@ -1960,22 +2060,23 @@ def factor(self, proof=None): Check if we can factor a constant polynomial, see :trac:`8207`:: - sage: R.<x,y> = CC[] - sage: R(1).factor() + sage: R.<x,y> = CC[] # needs sage.rings.real_mpfr + sage: R(1).factor() # needs sage.rings.real_mpfr 1.00000000000000 Check that we prohibit too large moduli, :trac:`11829`:: - sage: R.<x,y> = GF(previous_prime(2^31))[] - sage: factor(x+y+1) + sage: R.<x,y> = GF(previous_prime(2^31))[] # needs sage.rings.finite_rings + sage: factor(x + y + 1) # needs sage.rings.finite_rings Traceback (most recent call last): ... - NotImplementedError: Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + NotImplementedError: Factorization of multivariate polynomials + over prime fields with characteristic > 2^29 is not implemented. Check that we can factor over the algebraic field (:trac:`25390`):: - sage: R.<x,y> = PolynomialRing(QQbar) - sage: factor(x^2 + y^2) + sage: R.<x,y> = PolynomialRing(QQbar) # needs sage.rings.number_field + sage: factor(x^2 + y^2) # needs sage.rings.number_field (x + (-1*I)*y) * (x + 1*I*y) Check that the global proof flag for polynomials is honored:: @@ -1986,7 +2087,9 @@ def factor(self, proof=None): ....: f.factor() Traceback (most recent call last): ... - NotImplementedError: Provably correct factorization not implemented. Disable this error by wrapping your code in a `with proof.WithProof('polynomial', False):` block. + NotImplementedError: Provably correct factorization not implemented. + Disable this error by wrapping your code in a + `with proof.WithProof('polynomial', False):` block. sage: with proof.WithProof('polynomial', False): ....: f.factor() Traceback (most recent call last): @@ -1997,7 +2100,7 @@ def factor(self, proof=None): sage: K.<a> = PolynomialRing(QQ) sage: R.<x,y> = PolynomialRing(FractionField(K)) - sage: factor(x) + sage: factor(x) # needs sage.libs.pari x In the example below, we set the special method @@ -2011,20 +2114,23 @@ def factor(self, proof=None): ... NotImplementedError: ... sage: R.base_ring()._factor_multivariate_polynomial = lambda f, **kwargs: f.change_ring(QQ).factor() - sage: (x*y).factor() + sage: (x*y).factor() # needs sage.libs.pari y * x sage: del R.base_ring()._factor_multivariate_polynomial # clean up Check that a "multivariate" polynomial in one variable is factored correctly:: - sage: R.<z> = PolynomialRing(CC,1) - sage: f = z^4 - 6*z + 3 - sage: f.factor() - (z - 1.60443920904349) * (z - 0.511399619393097) * (z + 1.05791941421830 - 1.59281852704435*I) * (z + 1.05791941421830 + 1.59281852704435*I) + sage: R.<z> = PolynomialRing(CC,1) # needs sage.rings.real_mpfr + sage: f = z^4 - 6*z + 3 # needs sage.rings.real_mpfr + sage: f.factor() # needs sage.rings.real_mpfr + (z - 1.60443920904349) * (z - 0.511399619393097) + * (z + 1.05791941421830 - 1.59281852704435*I) + * (z + 1.05791941421830 + 1.59281852704435*I) We check a case that failed with an exception at some point:: + sage: # needs sage.rings.finite_rings sage: k.<u> = GF(4) sage: R.<v> = k[] sage: l.<v> = R.quo(v^3 + v + 1) @@ -2056,13 +2162,13 @@ def factor(self, proof=None): # try to use univariate factoring try: F = self.univariate_polynomial().factor() - return Factorization([(R(f),m) for f,m in F], unit=F.unit()) + return Factorization([(R(f), m) for f, m in F], unit=F.unit()) except TypeError: pass base_ring = self.base_ring() if base_ring.is_finite(): - if base_ring.characteristic() > 1<<29: + if base_ring.characteristic() > 1 << 29: raise NotImplementedError("Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") if proof is None: @@ -2075,8 +2181,8 @@ def factor(self, proof=None): S = self._singular_().factorize() factors = S[1] exponents = S[2] - v = sorted([(R(factors[i+1]), sage.rings.integer.Integer(exponents[i+1])) \ - for i in range(len(factors))]) + v = sorted([(R(factors[i + 1]), Integer(exponents[i + 1])) + for i in range(len(factors))]) unit = R(1) for i in range(len(v)): if v[i][0].is_unit(): @@ -2089,31 +2195,32 @@ def factor(self, proof=None): @handle_AA_and_QQbar def lift(self,I): """ - given an ideal I = (f_1,...,f_r) and some g (== self) in I, find - s_1,...,s_r such that g = s_1 f_1 + ... + s_r f_r + Given an ideal `I = (f_1,...,f_r)` and some `g` (= ``self``) in `I`, find + `s_1,...,s_r` such that `g = s_1 f_1 + ... + s_r f_r`. ALGORITHM: Use Singular. EXAMPLES:: - sage: A.<x,y> = PolynomialRing(CC,2,order='degrevlex') - sage: I = A.ideal([x^10 + x^9*y^2, y^8 - x^2*y^7 ]) + sage: # needs sage.rings.real_mpfr + sage: A.<x,y> = PolynomialRing(CC, 2, order='degrevlex') + sage: I = A.ideal([x^10 + x^9*y^2, y^8 - x^2*y^7]) sage: f = x*y^13 + y^12 - sage: M = f.lift(I) - sage: M + sage: M = f.lift(I); M # needs sage.libs.singular [y^7, x^7*y^2 + x^8 + x^5*y^3 + x^6*y + x^3*y^4 + x^4*y^2 + x*y^5 + x^2*y^3 + y^4] - sage: sum( map( mul , zip( M, I.gens() ) ) ) == f + sage: sum(map(mul, zip(M, I.gens()))) == f # needs sage.libs.singular True TESTS: - Check that this method works over QQbar (:trac:`25351`):: + Check that this method works over ``QQbar`` (:trac:`25351`):: + sage: # needs sage.rings.number_field sage: A.<x,y> = QQbar[] sage: I = A.ideal([x^2 + y^2 - 1, x^2 - y^2]) sage: f = 2*x^2 - 1 - sage: M = f.lift(I) - sage: sum( map( mul , zip( M, I.gens() ) ) ) == f + sage: M = f.lift(I) # needs sage.libs.singular + sage: sum(map(mul, zip(M, I.gens()))) == f # needs sage.libs.singular True """ fs = self._singular_() @@ -2129,23 +2236,23 @@ def lift(self,I): @handle_AA_and_QQbar def quo_rem(self, right): """ - Returns quotient and remainder of self and right. + Returns quotient and remainder of ``self`` and ``right``. EXAMPLES:: - sage: R.<x,y> = CC[] - sage: f = y*x^2 + x + 1 - sage: f.quo_rem(x) + sage: R.<x,y> = CC[] # needs sage.rings.real_mpfr + sage: f = y*x^2 + x + 1 # needs sage.rings.real_mpfr + sage: f.quo_rem(x) # needs sage.libs.singular sage.rings.real_mpfr (x*y + 1.00000000000000, 1.00000000000000) sage: R = QQ['a','b']['x','y','z'] sage: p1 = R('a + (1+2*b)*x*y + (3-a^2)*z') sage: p2 = R('x-1') - sage: p1.quo_rem(p2) + sage: p1.quo_rem(p2) # needs sage.libs.singular ((2*b + 1)*y, (2*b + 1)*y + (-a^2 + 3)*z + a) - sage: R.<x,y> = Qp(5)[] - sage: x.quo_rem(y) + sage: R.<x,y> = Qp(5)[] # needs sage.rings.padics + sage: x.quo_rem(y) # needs sage.rings.padics Traceback (most recent call last): ... TypeError: no conversion of this ring to a Singular ring defined @@ -2154,11 +2261,11 @@ def quo_rem(self, right): TESTS: - Check that this method works over QQbar (:trac:`25351`):: + Check that this method works over ``QQbar`` (:trac:`25351`):: - sage: R.<x,y> = QQbar[] - sage: f = y*x^2 + x + 1 - sage: f.quo_rem(x) + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: f = y*x^2 + x + 1 # needs sage.rings.number_field + sage: f.quo_rem(x) # needs sage.rings.number_field (x*y + 1, 1) """ R = self.parent() @@ -2200,9 +2307,9 @@ def resultant(self, other, variable=None): sage: P.<x,y> = PolynomialRing(QQ, 2) sage: a = x + y sage: b = x^3 - y^3 - sage: a.resultant(b) + sage: a.resultant(b) # needs sage.libs.singular -2*y^3 - sage: a.resultant(b, y) + sage: a.resultant(b, y) # needs sage.libs.singular 2*x^3 TESTS:: @@ -2211,15 +2318,15 @@ def resultant(self, other, variable=None): sage: P.<x,y> = MPolynomialRing_polydict_domain(QQ, 2, order='degrevlex') sage: a = x + y sage: b = x^3 - y^3 - sage: a.resultant(b) + sage: a.resultant(b) # needs sage.libs.singular -2*y^3 - sage: a.resultant(b, y) + sage: a.resultant(b, y) # needs sage.libs.singular 2*x^3 Check that :trac:`15061` is fixed:: - sage: R.<x, y> = AA[] - sage: (x^2 + 1).resultant(x^2 - y) + sage: R.<x, y> = AA[] # needs sage.rings.number_field + sage: (x^2 + 1).resultant(x^2 - y) # needs sage.rings.number_field y^2 + 2*y + 1 Test for :trac:`2693`:: @@ -2227,11 +2334,12 @@ def resultant(self, other, variable=None): sage: R.<x,y> = RR[] sage: p = x + y sage: q = x*y - sage: p.resultant(q) + sage: p.resultant(q) # needs sage.modules -y^2 Check that this method works over QQbar (:trac:`25351`):: + sage: # needs sage.rings.number_field sage: P.<x,y> = QQbar[] sage: a = x + y sage: b = x^3 - y^3 @@ -2267,6 +2375,7 @@ def subresultants(self, other, variable=None): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: p = (y^2 + 6)*(x - 1) - y*(x^2 + 1) sage: q = (x^2 + 6)*(y - 1) - x*(y^2 + 1) @@ -2297,11 +2406,12 @@ def reduce(self, I): EXAMPLES:: + sage: # needs sage.rings.number_field sage: P.<x,y,z> = QQbar[] sage: f1 = -2 * x^2 + x^3 - sage: f2 = -2 * y + x* y + sage: f2 = -2 * y + x * y sage: f3 = -x^2 + y^2 - sage: F = Ideal([f1,f2,f3]) + sage: F = Ideal([f1, f2, f3]) sage: g = x*y - 3*x*y^2 sage: g.reduce(F) (-6)*y^2 + 2*y @@ -2310,15 +2420,16 @@ def reduce(self, I): :: - sage: f = 3*x - sage: f.reduce([2*x,y]) + sage: f = 3*x # needs sage.rings.number_field + sage: f.reduce([2*x, y]) # needs sage.rings.number_field 0 :: + sage: # needs sage.rings.number_field sage: k.<w> = CyclotomicField(3) sage: A.<y9,y12,y13,y15> = PolynomialRing(k) - sage: J = [ y9 + y12] + sage: J = [y9 + y12] sage: f = y9 - y12; f.reduce(J) -2*y12 sage: f = y13*y15; f.reduce(J) @@ -2328,17 +2439,17 @@ def reduce(self, I): Make sure the remainder returns the correct type, fixing :trac:`13903`:: - sage: R.<y1,y2>=PolynomialRing(Qp(5),2, order='lex') - sage: G=[y1^2 + y2^2, y1*y2 + y2^2, y2^3] - sage: type((y2^3).reduce(G)) + sage: R.<y1,y2> = PolynomialRing(Qp(5), 2, order='lex') # needs sage.rings.padics + sage: G = [y1^2 + y2^2, y1*y2 + y2^2, y2^3] # needs sage.rings.padics + sage: type((y2^3).reduce(G)) # needs sage.rings.padics <class 'sage.rings.polynomial.multi_polynomial_element.MPolynomial_polydict'> TESTS: Verify that :trac:`34105` is fixed:: - sage: R.<x,y> = AA[] - sage: x.reduce(R.zero_ideal()) + sage: R.<x,y> = AA[] # needs sage.rings.number_field + sage: x.reduce(R.zero_ideal()) # needs sage.rings.number_field x """ from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal @@ -2385,30 +2496,28 @@ def reduce(self, I): def degree_lowest_rational_function(r, x): r""" - Return the difference of valuations of r with respect to variable x. + Return the difference of valuations of ``r`` with respect to variable ``x``. INPUT: - ``r`` -- a multivariate rational function - - ``x`` -- a multivariate polynomial ring generator x - - OUTPUT: + - ``x`` -- a multivariate polynomial ring generator - - ``integer`` -- the difference val_x(p) - val_x(q) where r = p/q + OUTPUT: integer -- the difference `val_x(p) - val_x(q)` where `r = p/q` .. NOTE:: This function should be made a method of the - FractionFieldElement class. + :class:`FractionFieldElement` class. EXAMPLES:: - sage: R1 = PolynomialRing(FiniteField(5), 3, names = ["a","b","c"]) + sage: R1 = PolynomialRing(FiniteField(5), 3, names=["a", "b", "c"]) sage: F = FractionField(R1) sage: a,b,c = R1.gens() - sage: f = 3*a*b^2*c^3+4*a*b*c - sage: g = a^2*b*c^2+2*a^2*b^4*c^7 + sage: f = 3*a*b^2*c^3 + 4*a*b*c + sage: g = a^2*b*c^2 + 2*a^2*b^4*c^7 Consider the quotient `f/g = \frac{4 + 3 bc^{2}}{ac + 2 ab^{3}c^{6}}` (note the @@ -2416,13 +2525,14 @@ def degree_lowest_rational_function(r, x): :: + sage: # needs sage.rings.finite_rings sage: r = f/g; r (-2*b*c^2 - 1)/(2*a*b^3*c^6 + a*c) - sage: degree_lowest_rational_function(r,a) + sage: degree_lowest_rational_function(r, a) -1 - sage: degree_lowest_rational_function(r,b) + sage: degree_lowest_rational_function(r, b) 0 - sage: degree_lowest_rational_function(r,c) + sage: degree_lowest_rational_function(r, c) -1 """ from sage.rings.fraction_field import FractionField diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 71494eddbc0..66dd4a6db3d 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular r""" Ideals in multivariate polynomial rings @@ -11,7 +12,7 @@ EXAMPLES: We compute a Groebner basis for some given ideal. The type returned by -the ``groebner_basis`` method is ``PolynomialSequence``, i.e. it is not a +the ``groebner_basis`` method is ``PolynomialSequence``, i.e., it is not a :class:`MPolynomialIdeal`:: sage: x,y,z = QQ['x,y,z'].gens() @@ -144,42 +145,43 @@ surprising as there are 4 equations in 3 unknowns). :: sage: P.<x,y,z> = PolynomialRing(ZZ,order='lex') - sage: I = ideal(-y^2 - 3*y + z^2 + 3, -2*y*z + z^2 + 2*z + 1, \ - x*z + y*z + z^2, -3*x*y + 2*y*z + 6*z^2) + sage: I = ideal(-y^2 - 3*y + z^2 + 3, -2*y*z + z^2 + 2*z + 1, + ....: x*z + y*z + z^2, -3*x*y + 2*y*z + 6*z^2) sage: I.change_ring(P.change_ring(QQ)).groebner_basis() [1] - However, when we compute the Groebner basis of I (defined over + However, when we compute the Groebner basis of `I` (defined over `\ZZ`), we note that there is a certain integer in the ideal which is not 1. :: sage: I.groebner_basis() - [x + y + 57119*z + 4, y^2 + 3*y + 17220, y*z + ..., 2*y + 158864, z^2 + 17223, 2*z + 41856, 164878] + [x + y + 57119*z + 4, y^2 + 3*y + 17220, y*z + ..., + 2*y + 158864, z^2 + 17223, 2*z + 41856, 164878] Now for each prime `p` dividing this integer 164878, the Groebner - basis of I modulo `p` will be non-trivial and will thus give a + basis of `I` modulo `p` will be non-trivial and will thus give a solution of the original system modulo `p`. :: sage: factor(164878) 2 * 7 * 11777 - sage: I.change_ring(P.change_ring( GF(2) )).groebner_basis() + sage: I.change_ring(P.change_ring(GF(2))).groebner_basis() # needs sage.rings.finite_rings [x + y + z, y^2 + y, y*z + y, z^2 + 1] - sage: I.change_ring(P.change_ring( GF(7) )).groebner_basis() + sage: I.change_ring(P.change_ring(GF(7))).groebner_basis() # needs sage.rings.finite_rings [x - 1, y + 3, z - 2] - sage: I.change_ring(P.change_ring( GF(11777 ))).groebner_basis() + sage: I.change_ring(P.change_ring(GF(11777))).groebner_basis() # needs sage.rings.finite_rings [x + 5633, y - 3007, z - 2626] The Groebner basis modulo any product of the prime factors is also non-trivial:: - sage: I.change_ring(P.change_ring( IntegerModRing(2*7) )).groebner_basis() + sage: I.change_ring(P.change_ring(IntegerModRing(2 * 7))).groebner_basis() [x + 9*y + 13*z, y^2 + 3*y, y*z + 7*y + 6, 2*y + 6, z^2 + 3, 2*z + 10] Modulo any other prime the Groebner basis is trivial so there are no other solutions. For example:: - sage: I.change_ring( P.change_ring( GF(3) ) ).groebner_basis() + sage: I.change_ring(P.change_ring(GF(3))).groebner_basis() # needs sage.rings.finite_rings [1] TESTS:: @@ -232,36 +234,40 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from warnings import warn -from sage.interfaces.singular import singular as singular_default -from sage.interfaces.magma import magma as magma_default - -from sage.interfaces.expect import StdOutContext +import sage.rings.abc +import sage.rings.polynomial.toy_buchberger as toy_buchberger +import sage.rings.polynomial.toy_variety as toy_variety +import sage.rings.polynomial.toy_d_basis as toy_d_basis +from sage.misc.cachefunc import cached_method +from sage.misc.method_decorator import MethodDecorator +from sage.misc.misc_c import prod +from sage.misc.verbose import verbose, get_verbose from sage.rings.ideal import Ideal_generic -from sage.rings.noncommutative_ideals import Ideal_nc from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.noncommutative_ideals import Ideal_nc +from sage.rings.qqbar_decorators import handle_AA_and_QQbar from sage.structure.sequence import Sequence from sage.structure.richcmp import (richcmp_method, op_EQ, op_NE, op_LT, op_GT, op_LE, op_GE, rich_to_bool) -from sage.misc.cachefunc import cached_method -from sage.misc.misc_c import prod -from sage.misc.verbose import verbose, get_verbose -from sage.misc.method_decorator import MethodDecorator -from sage.rings.integer_ring import ZZ -import sage.rings.abc -import sage.rings.polynomial.toy_buchberger as toy_buchberger -import sage.rings.polynomial.toy_variety as toy_variety -import sage.rings.polynomial.toy_d_basis as toy_d_basis - -from warnings import warn -from sage.rings.qqbar_decorators import handle_AA_and_QQbar +try: + from sage.interfaces.expect import StdOutContext + from sage.interfaces.singular import singular as singular_default, singular_gb_standard_options + from sage.libs.singular.standard_options import libsingular_gb_standard_options +except ImportError: + singular_default = None + singular_gb_standard_options = libsingular_gb_standard_options = MethodDecorator -from sage.interfaces.magma import magma_gb_standard_options -from sage.interfaces.singular import singular_gb_standard_options -from sage.libs.singular.standard_options import libsingular_gb_standard_options +try: + from sage.interfaces.magma import magma as magma_default, magma_gb_standard_options +except ImportError: + magma_default = None + magma_gb_standard_options = MethodDecorator class RequireField(MethodDecorator): @@ -294,14 +300,16 @@ def __call__(self, *args, **kwds): """ R = self._instance.ring() if not R.base_ring().is_field(): - raise ValueError("Coefficient ring must be a field for function '%s'."%(self.f.__name__)) + raise ValueError("Coefficient ring must be a field for function '%s'." % (self.f.__name__)) return self.f(self._instance, *args, **kwds) + require_field = RequireField -def is_MPolynomialIdeal(x): + +def is_MPolynomialIdeal(x) -> bool: """ - Return ``True`` if the provided argument ``x`` is an ideal in the + Return ``True`` if the provided argument ``x`` is an ideal in a multivariate polynomial ring. INPUT: @@ -329,6 +337,7 @@ def is_MPolynomialIdeal(x): """ return isinstance(x, MPolynomialIdeal) + class MPolynomialIdeal_magma_repr: def _magma_init_(self, magma): """ @@ -341,9 +350,10 @@ def _magma_init_(self, magma): EXAMPLES:: - sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127),10) - sage: I = sage.rings.ideal.Cyclic(R,4) # indirect doctest - sage: magma(I) # optional - magma + sage: # optional - magma + sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127), 10) + sage: I = sage.rings.ideal.Cyclic(R,4) # indirect doctest + sage: magma(I) Ideal of Polynomial ring of rank 10 over GF(127) Order: Graded Reverse Lexicographical Variables: a, b, c, d, e, f, g, h, i, j @@ -357,7 +367,7 @@ def _magma_init_(self, magma): """ P = magma(self.ring()) G = magma(self.gens()) - return 'ideal<%s|%s>'%(P.name(), G._ref()) + return 'ideal<%s|%s>' % (P.name(), G._ref()) @magma_gb_standard_options def _groebner_basis_magma(self, deg_bound=None, prot=False, magma=magma_default): @@ -378,25 +388,27 @@ def _groebner_basis_magma(self, deg_bound=None, prot=False, magma=magma_default) EXAMPLES:: - sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127),10) - sage: I = sage.rings.ideal.Cyclic(R,6) - sage: gb = I.groebner_basis('magma:GroebnerBasis') # indirect doctest; optional - magma - sage: len(gb) # optional - magma + sage: # optional - magma + sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127), 10) + sage: I = sage.rings.ideal.Cyclic(R, 6) + sage: gb = I.groebner_basis('magma:GroebnerBasis') + sage: len(gb) 45 We may also pass a degree bound to Magma:: - sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127),10) - sage: I = sage.rings.ideal.Cyclic(R,6) - sage: gb = I.groebner_basis('magma:GroebnerBasis', deg_bound=4) # indirect doctest; optional - magma - sage: len(gb) # optional - magma + sage: # optional - magma + sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127), 10) + sage: I = sage.rings.ideal.Cyclic(R, 6) + sage: gb = I.groebner_basis('magma:GroebnerBasis', deg_bound=4) + sage: len(gb) 5 """ R = self.ring() if not deg_bound: mself = magma(self) else: - mself = magma(list(self.gens())) # PolynomialSequence converts to a Magma Ideal too, so we force a list + mself = magma(list(self.gens())) # PolynomialSequence converts to a Magma Ideal too, so we force a list if get_verbose() >= 2: prot = True @@ -404,7 +416,7 @@ def _groebner_basis_magma(self, deg_bound=None, prot=False, magma=magma_default) from sage.interfaces.magma import MagmaGBLogPrettyPrinter if prot: - log_parser = MagmaGBLogPrettyPrinter(verbosity=get_verbose()+ 1, style="sage" if prot=="sage" else "magma") + log_parser = MagmaGBLogPrettyPrinter(verbosity=get_verbose() + 1, style="sage" if prot == "sage" else "magma") else: log_parser = None @@ -526,7 +538,7 @@ def _groebner_basis_libsingular(self, algorithm="groebner", *args, **kwds): from sage.libs.singular.function_factory import ff groebner = ff.groebner - if get_verbose()>=2: + if get_verbose() >= 2: opt['prot'] = True for name, value in kwds.items(): if value is not None: @@ -543,7 +555,7 @@ def _groebner_basis_libsingular(self, algorithm="groebner", *args, **kwds): fnc = singular_function(algorithm) S = fnc(self) except NameError: - raise NameError("Algorithm '%s' unknown"%algorithm) + raise NameError("Algorithm '%s' unknown" % algorithm) return S @libsingular_gb_standard_options @@ -726,7 +738,7 @@ def complete_primary_decomposition(self, algorithm="sy"): `b^n \in Q` for some `n \in \ZZ`. If `Q` is a primary ideal of the ring `R`, then the radical - ideal `P` of `Q` (i.e. the ideal consisting of all `a \in R` + ideal `P` of `Q` (i.e., the ideal consisting of all `a \in R` with a^n \in Q` for some `n \in \ZZ`), is called the associated prime of `Q`. @@ -760,7 +772,7 @@ def complete_primary_decomposition(self, algorithm="sy"): sage: R.<x,y,z> = PolynomialRing(QQ, 3, order='lex') sage: p = z^2 + 1; q = z^3 + 2 - sage: I = (p*q^2, y-z^2)*R + sage: I = (p*q^2, y - z^2) * R sage: pd = I.complete_primary_decomposition(); sorted(pd, key=str) [(Ideal (z^2 + 1, y + 1) of Multivariate Polynomial Ring in x, y, z over Rational Field, Ideal (z^2 + 1, y + 1) of Multivariate Polynomial Ring in x, y, z over Rational Field), @@ -815,10 +827,10 @@ def complete_primary_decomposition(self, algorithm="sy"): from sage.libs.singular.function_factory import ff if algorithm == 'sy': - primdecSY = ff.primdec__lib.primdecSY + primdecSY = ff.primdec__lib.primdecSY P = primdecSY(self) elif algorithm == 'gtz': - primdecGTZ = ff.primdec__lib.primdecGTZ + primdecGTZ = ff.primdec__lib.primdecGTZ P = primdecGTZ(self) R = self.ring() @@ -839,8 +851,8 @@ def primary_decomposition(self, algorithm='sy'): `b^n \in Q` for some `n \in \ZZ`. If `Q` is a primary ideal of the ring `R`, then the radical - ideal `P` of `Q` (i.e. the ideal consisting of all `a \in R` - with a^n \in Q` for some `n \in \ZZ`), is called the + ideal `P` of `Q` (i.e., the ideal consisting of all `a \in R` + with `a^n \in Q` for some `n \in \ZZ`), is called the associated prime of `Q`. If `I` is a proper ideal of a Noetherian ring `R`, then there @@ -872,15 +884,17 @@ def primary_decomposition(self, algorithm='sy'): sage: R.<x,y,z> = PolynomialRing(QQ, 3, order='lex') sage: p = z^2 + 1; q = z^3 + 2 - sage: I = (p*q^2, y-z^2)*R + sage: I = (p*q^2, y - z^2) * R sage: pd = I.primary_decomposition(); sorted(pd, key=str) - [Ideal (z^2 + 1, y + 1) of Multivariate Polynomial Ring in x, y, z over Rational Field, - Ideal (z^6 + 4*z^3 + 4, y - z^2) of Multivariate Polynomial Ring in x, y, z over Rational Field] + [Ideal (z^2 + 1, y + 1) + of Multivariate Polynomial Ring in x, y, z over Rational Field, + Ideal (z^6 + 4*z^3 + 4, y - z^2) + of Multivariate Polynomial Ring in x, y, z over Rational Field] :: sage: from functools import reduce - sage: reduce(lambda Qi,Qj: Qi.intersection(Qj), pd) == I + sage: reduce(lambda Qi, Qj: Qi.intersection(Qj), pd) == I True ALGORITHM: @@ -929,22 +943,20 @@ def associated_primes(self, algorithm='sy'): INPUT: - - ``algorithm`` - string: - - - ``'sy'`` - (default) use the Shimoyama-Yokoyama algorithm + - ``algorithm`` -- string: - - ``'gtz'`` - use the Gianni-Trager-Zacharias algorithm + - ``'sy'`` -- (default) use the Shimoyama-Yokoyama algorithm + - ``'gtz'`` -- use the Gianni-Trager-Zacharias algorithm - OUTPUT: - - ``list`` - a list of associated primes + OUTPUT: a list of associated primes EXAMPLES:: sage: R.<x,y,z> = PolynomialRing(QQ, 3, order='lex') sage: p = z^2 + 1; q = z^3 + 2 - sage: I = (p*q^2, y-z^2)*R + sage: I = (p*q^2, y - z^2) * R sage: pd = I.associated_primes(); sorted(pd, key=str) [Ideal (z^2 + 1, y + 1) of Multivariate Polynomial Ring in x, y, z over Rational Field, Ideal (z^3 + 2, y - z^2) of Multivariate Polynomial Ring in x, y, z over Rational Field] @@ -968,19 +980,19 @@ def is_prime(self, **kwds): INPUT: - keyword arguments are passed on to - ``complete_primary_decomposition``; in this way you can + :meth:`complete_primary_decomposition`; in this way you can specify the algorithm to use. EXAMPLES:: sage: R.<x, y> = PolynomialRing(QQ, 2) - sage: I = (x^2 - y^2 - 1)*R + sage: I = (x^2 - y^2 - 1) * R sage: I.is_prime() True sage: (I^2).is_prime() False - sage: J = (x^2 - y^2)*R + sage: J = (x^2 - y^2) * R sage: J.is_prime() False sage: (J^3).is_prime() @@ -994,9 +1006,12 @@ def is_prime(self, **kwds): fraction field is not the quotient ring itself:: sage: Q = R.quotient(I); Q - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 - y^2 - 1) + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2 - y^2 - 1) sage: Q.fraction_field() - Fraction Field of Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 - y^2 - 1) + Fraction Field of + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2 - y^2 - 1) """ if not self.ring().base_ring().is_field(): raise NotImplementedError @@ -1016,7 +1031,7 @@ def triangular_decomposition(self, algorithm=None, singular=singular_default): sets. This requires that the given basis is reduced w.r.t. to the - lexicographical monomial ordering. If the basis of self does + lexicographical monomial ordering. If the basis of ``self`` does not have this property, the required Groebner basis is computed implicitly. @@ -1026,14 +1041,14 @@ def triangular_decomposition(self, algorithm=None, singular=singular_default): ALGORITHMS: - - ``singular:triangL`` - decomposition of self into triangular + - ``"singular:triangL"`` - decomposition of ``self`` into triangular systems (Lazard). - - ``singular:triangLfak`` - decomp. of self into tri. systems + - ``"singular:triangLfak"`` - decomposition of ``self`` into triangular systems plus factorization. - - ``singular:triangM`` - decomposition of self into - triangular systems (Moeller). + - ``"singular:triangM"`` - decomposition of ``self`` into + triangular systems (Moeller). OUTPUT: a list `T` of lists `t` such that the variety of ``self`` is the union of the varieties of `t` in `L` and each @@ -1041,23 +1056,38 @@ def triangular_decomposition(self, algorithm=None, singular=singular_default): EXAMPLES:: - sage: P.<e,d,c,b,a> = PolynomialRing(QQ,5,order='lex') + sage: P.<e,d,c,b,a> = PolynomialRing(QQ, 5, order='lex') sage: I = sage.rings.ideal.Cyclic(P) sage: GB = Ideal(I.groebner_basis('libsingular:stdfglm')) sage: GB.triangular_decomposition('singular:triangLfak') [Ideal (a - 1, b - 1, c - 1, d^2 + 3*d + 1, e + d + 3) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a - 1, b - 1, c^2 + 3*c + 1, d + c + 3, e - 1) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a - 1, b^2 + 3*b + 1, c + b + 3, d - 1, e - 1) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a - 1, b^4 + b^3 + b^2 + b + 1, -c + b^2, -d + b^3, e + b^3 + b^2 + b + 1) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a^2 + 3*a + 1, b - 1, c - 1, d - 1, e + a + 3) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a^2 + 3*a + 1, b + a + 3, c - 1, d - 1, e - 1) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a^4 - 4*a^3 + 6*a^2 + a + 1, -11*b^2 + 6*b*a^3 - 26*b*a^2 + 41*b*a - 4*b - 8*a^3 + 31*a^2 - 40*a - 24, 11*c + 3*a^3 - 13*a^2 + 26*a - 2, 11*d + 3*a^3 - 13*a^2 + 26*a - 2, -11*e - 11*b + 6*a^3 - 26*a^2 + 41*a - 4) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a^4 + a^3 + a^2 + a + 1, b - 1, c + a^3 + a^2 + a + 1, -d + a^3, -e + a^2) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a^4 + a^3 + a^2 + a + 1, b - a, c - a, d^2 + 3*d*a + a^2, e + d + 3*a) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a^4 + a^3 + a^2 + a + 1, b - a, c^2 + 3*c*a + a^2, d + c + 3*a, e - a) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a^4 + a^3 + a^2 + a + 1, b^2 + 3*b*a + a^2, c + b + 3*a, d - a, e - a) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a^4 + a^3 + a^2 + a + 1, b^3 + b^2*a + b^2 + b*a^2 + b*a + b + a^3 + a^2 + a + 1, c + b^2*a^3 + b^2*a^2 + b^2*a + b^2, -d + b^2*a^2 + b^2*a + b^2 + b*a^2 + b*a + a^2, -e + b^2*a^3 - b*a^2 - b*a - b - a^2 - a) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, - Ideal (a^4 + a^3 + 6*a^2 - 4*a + 1, -11*b^2 + 6*b*a^3 + 10*b*a^2 + 39*b*a + 2*b + 16*a^3 + 23*a^2 + 104*a - 24, 11*c + 3*a^3 + 5*a^2 + 25*a + 1, 11*d + 3*a^3 + 5*a^2 + 25*a + 1, -11*e - 11*b + 6*a^3 + 10*a^2 + 39*a + 2) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field] + Ideal (a - 1, b - 1, c^2 + 3*c + 1, d + c + 3, e - 1) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, + Ideal (a - 1, b^2 + 3*b + 1, c + b + 3, d - 1, e - 1) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, + Ideal (a - 1, b^4 + b^3 + b^2 + b + 1, -c + b^2, -d + b^3, + e + b^3 + b^2 + b + 1) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, + Ideal (a^2 + 3*a + 1, b - 1, c - 1, d - 1, e + a + 3) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, + Ideal (a^2 + 3*a + 1, b + a + 3, c - 1, d - 1, e - 1) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, + Ideal (a^4 - 4*a^3 + 6*a^2 + a + 1, + -11*b^2 + 6*b*a^3 - 26*b*a^2 + 41*b*a - 4*b - 8*a^3 + 31*a^2 - 40*a - 24, + 11*c + 3*a^3 - 13*a^2 + 26*a - 2, 11*d + 3*a^3 - 13*a^2 + 26*a - 2, + -11*e - 11*b + 6*a^3 - 26*a^2 + 41*a - 4) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, + Ideal (a^4 + a^3 + a^2 + a + 1, + b - 1, c + a^3 + a^2 + a + 1, -d + a^3, -e + a^2) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, + Ideal (a^4 + a^3 + a^2 + a + 1, + b - a, c - a, d^2 + 3*d*a + a^2, e + d + 3*a) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, + Ideal (a^4 + a^3 + a^2 + a + 1, + b - a, c^2 + 3*c*a + a^2, d + c + 3*a, e - a) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, + Ideal (a^4 + a^3 + a^2 + a + 1, + b^2 + 3*b*a + a^2, c + b + 3*a, d - a, e - a) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, + Ideal (a^4 + a^3 + a^2 + a + 1, + b^3 + b^2*a + b^2 + b*a^2 + b*a + b + a^3 + a^2 + a + 1, + c + b^2*a^3 + b^2*a^2 + b^2*a + b^2, + -d + b^2*a^2 + b^2*a + b^2 + b*a^2 + b*a + a^2, + -e + b^2*a^3 - b*a^2 - b*a - b - a^2 - a) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field, + Ideal (a^4 + a^3 + 6*a^2 - 4*a + 1, + -11*b^2 + 6*b*a^3 + 10*b*a^2 + 39*b*a + 2*b + 16*a^3 + 23*a^2 + 104*a - 24, + 11*c + 3*a^3 + 5*a^2 + 25*a + 1, 11*d + 3*a^3 + 5*a^2 + 25*a + 1, + -11*e - 11*b + 6*a^3 + 10*a^2 + 39*a + 2) of Multivariate Polynomial Ring in e, d, c, b, a over Rational Field] sage: R.<x1,x2> = PolynomialRing(QQ, 2, order='lex') sage: f1 = 1/2*((x1^2 + 2*x1 - 4)*x2^2 + 2*(x1^2 + x1)*x2 + x1^2) @@ -1067,7 +1097,8 @@ def triangular_decomposition(self, algorithm=None, singular=singular_default): [Ideal (x2, x1^2) of Multivariate Polynomial Ring in x1, x2 over Rational Field, Ideal (x2, x1^2) of Multivariate Polynomial Ring in x1, x2 over Rational Field, Ideal (x2, x1^2) of Multivariate Polynomial Ring in x1, x2 over Rational Field, - Ideal (x2^4 + 4*x2^3 - 6*x2^2 - 20*x2 + 5, 8*x1 - x2^3 + x2^2 + 13*x2 - 5) of Multivariate Polynomial Ring in x1, x2 over Rational Field] + Ideal (x2^4 + 4*x2^3 - 6*x2^2 - 20*x2 + 5, 8*x1 - x2^3 + x2^2 + 13*x2 - 5) + of Multivariate Polynomial Ring in x1, x2 over Rational Field] TESTS:: @@ -1078,9 +1109,9 @@ def triangular_decomposition(self, algorithm=None, singular=singular_default): Check that this method works over QQbar (:trac:`25351`):: - sage: R.<x,y> = QQbar[] - sage: J = Ideal(x^2+y^2-2, y^2-1) - sage: J.triangular_decomposition() + sage: R.<x,y> = QQbar[] # needs sage.rings.number_field + sage: J = Ideal(x^2 + y^2 - 2, y^2 - 1) # needs sage.rings.number_field + sage: J.triangular_decomposition() # needs sage.rings.number_field [Ideal (y^2 - 1, x^2 - 1) of Multivariate Polynomial Ring in x, y over Algebraic Field] """ P = self.ring() @@ -1096,16 +1127,16 @@ def triangular_decomposition(self, algorithm=None, singular=singular_default): # the Singular routines are quite picky about their input. if is_groebner: if Q == P: - I = MPolynomialIdeal(P, self.interreduced_basis()[::-1]) + I = MPolynomialIdeal(P, self.interreduced_basis()[::-1]) else: I = self - I = MPolynomialIdeal(P, I.transformed_basis('fglm')[::-1]) # -> 'lex' - I = I.change_ring(Q) # transform to 'lex' GB + I = MPolynomialIdeal(P, I.transformed_basis('fglm')[::-1]) # -> 'lex' + I = I.change_ring(Q) # transform to 'lex' GB else: if Q == P: I = MPolynomialIdeal(P, self.groebner_basis()[::-1]) else: - I = self.change_ring(Q) # transform to 'lex' GB + I = self.change_ring(Q) # transform to 'lex' GB I = MPolynomialIdeal(Q, I.groebner_basis()[::-1]) if I.dimension() != 0: @@ -1123,7 +1154,7 @@ def triangular_decomposition(self, algorithm=None, singular=singular_default): f = singular_function(algorithm[9:]) Tbar = f(I, attributes={I:{'isSB':1}}) else: - raise TypeError("algorithm '%s' unknown"%algorithm) + raise TypeError("algorithm '%s' unknown" % algorithm) T = Sequence([ MPolynomialIdeal(Q,t) for t in Tbar]) return sorted(T, key=lambda x: x.gens()) @@ -1136,9 +1167,9 @@ def dimension(self, singular=singular_default): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(GF(32003),order='degrevlex') - sage: I = ideal(x^2-y,x^3) - sage: I.dimension() + sage: P.<x,y,z> = PolynomialRing(GF(32003), order='degrevlex') # needs sage.rings.finite_rings + sage: I = ideal(x^2 - y, x^3) # needs sage.rings.finite_rings + sage: I.dimension() # needs sage.rings.finite_rings 1 If the ideal is the total ring, the dimension is `-1` by convention. @@ -1150,20 +1181,21 @@ def dimension(self, singular=singular_default): EXAMPLES:: - sage: R.<x,y> = PolynomialRing(GF(2147483659^2),order='lex') - sage: I = R.ideal([x*y,x*y+1]) + sage: # needs sage.rings.finite_rings + sage: R.<x,y> = PolynomialRing(GF(2147483659^2), order='lex') + sage: I = R.ideal([x*y, x*y + 1]) sage: I.dimension() verbose 0 (...: multi_polynomial_ideal.py, dimension) Warning: falling back to very slow toy implementation. -1 - sage: I=ideal([x*(x*y+1),y*(x*y+1)]) + sage: I=ideal([x*(x*y+1), y*(x*y+1)]) sage: I.dimension() verbose 0 (...: multi_polynomial_ideal.py, dimension) Warning: falling back to very slow toy implementation. 1 - sage: I = R.ideal([x^3*y,x*y^2]) + sage: I = R.ideal([x^3*y, x*y^2]) sage: I.dimension() verbose 0 (...: multi_polynomial_ideal.py, dimension) Warning: falling back to very slow toy implementation. 1 - sage: R.<x,y> = PolynomialRing(GF(2147483659^2),order='lex') + sage: R.<x,y> = PolynomialRing(GF(2147483659^2), order='lex') sage: I = R.ideal(0) sage: I.dimension() verbose 0 (...: multi_polynomial_ideal.py, dimension) Warning: falling back to very slow toy implementation. @@ -1177,9 +1209,9 @@ def dimension(self, singular=singular_default): Check that this method works over QQbar (:trac:`25351`):: - sage: P.<x,y,z> = QQbar[] - sage: I = ideal(x^2-y,x^3-QQbar(-1)) - sage: I.dimension() + sage: P.<x,y,z> = QQbar[] # needs sage.rings.number_field + sage: I = ideal(x^2-y, x^3-QQbar(-1)) # needs sage.rings.number_field + sage: I.dimension() # needs sage.rings.number_field 1 .. NOTE:: @@ -1251,7 +1283,7 @@ def dimension(self, singular=singular_default): def vector_space_dimension(self): """ Return the vector space dimension of the ring modulo this ideal. If - the ideal is not zero-dimensional, a TypeError is raised. + the ideal is not zero-dimensional, a :class:`TypeError` is raised. ALGORITHM: @@ -1278,14 +1310,15 @@ def vector_space_dimension(self): Due to integer overflow, the result is correct only modulo ``2^32``, see :trac:`8586`:: - sage: P.<x,y,z> = PolynomialRing(GF(32003),3) - sage: sage.rings.ideal.FieldIdeal(P).vector_space_dimension() # known bug + sage: P.<x,y,z> = PolynomialRing(GF(32003), 3) # needs sage.rings.finite_rings + sage: sage.rings.ideal.FieldIdeal(P).vector_space_dimension() # known bug, needs sage.rings.finite_rings 32777216864027 TESTS: Check that this method works over QQbar (:trac:`25351`):: + sage: # needs sage.rings.number_field sage: P.<x,y,z> = QQbar[] sage: I = ideal(x^2-y,x^3-QQbar(-1),z-y) sage: I.dimension() @@ -1325,14 +1358,14 @@ def _groebner_basis_ginv(self, algorithm="TQ", criteria='CritPartially', divisio Currently, only `\GF{p}` and `\QQ` are supported as base fields:: - sage: P.<x,y,z> = PolynomialRing(QQ,order='degrevlex') + sage: # optional - ginv + sage: P.<x,y,z> = PolynomialRing(QQ, order='degrevlex') sage: I = sage.rings.ideal.Katsura(P) - sage: I.groebner_basis(algorithm='ginv') # optional - ginv + sage: I.groebner_basis(algorithm='ginv') [z^3 - 79/210*z^2 + 1/30*y + 1/70*z, y^2 - 3/5*z^2 - 1/5*y + 1/5*z, y*z + 6/5*z^2 - 1/10*y - 2/5*z, x + 2*y + 2*z - 1] - - sage: P.<x,y,z> = PolynomialRing(GF(127),order='degrevlex') + sage: P.<x,y,z> = PolynomialRing(GF(127), order='degrevlex') sage: I = sage.rings.ideal.Katsura(P) - sage: I.groebner_basis(algorithm='ginv') # optional - ginv + sage: I.groebner_basis(algorithm='ginv') ... [z^3 + 22*z^2 - 55*y + 49*z, y^2 - 26*z^2 - 51*y + 51*z, y*z + 52*z^2 + 38*y + 25*z, x + 2*y + 2*z - 1] @@ -1360,7 +1393,7 @@ def _groebner_basis_ginv(self, algorithm="TQ", criteria='CritPartially', divisio try: im = ginv.MonomInterface(term_order_map[T.name()], st, list(P.variable_names())) except KeyError: - raise NotImplementedError("Term order '%s' not supported by Sage's GINV interface or GINV"%T.term_order()) + raise NotImplementedError("Term order '%s' not supported by Sage's GINV interface or GINV" % T.term_order()) from sage.rings.rational_field import QQ if K is QQ: @@ -1368,7 +1401,7 @@ def _groebner_basis_ginv(self, algorithm="TQ", criteria='CritPartially', divisio elif K.order() <= 2**16 and K.order().is_prime(): ic = ginv.CoeffInterface("ModularShort", st, modularShort=K.order()) else: - raise NotImplementedError("GINV interface for base ring '%s' is not implemented."%K) + raise NotImplementedError("GINV interface for base ring '%s' is not implemented." % K) ip = ginv.PolyInterface("PolyList", st, im, ic) iw = ginv.WrapInterface(criteria, ip) @@ -1442,7 +1475,7 @@ def _groebner_basis_singular(self, algorithm="groebner", *args, **kwds): R = self.ring() S = self._groebner_basis_singular_raw(algorithm=algorithm, *args, **kwds) - S = PolynomialSequence([R(S[i+1]) for i in range(len(S))], R, immutable=True) + S = PolynomialSequence([R(S[i+1]) for i in range(len(S))], R, immutable=True) return S @cached_method @@ -1464,7 +1497,7 @@ def _groebner_basis_singular_raw(self, algorithm="groebner", singular=singular_d sage: R.<a,b,c,d> = PolynomialRing(QQ, 4, order='lex') sage: I = sage.rings.ideal.Cyclic(R,4) - sage: I._groebner_basis_singular() # indirect doctest + sage: I._groebner_basis_singular() # indirect doctest [c^2*d^6 - c^2*d^2 - d^4 + 1, c^3*d^2 + c^2*d^3 - c - d, b*d^4 - b + d^5 - d, b*c - b*d + c^2*d^4 + c*d - 2*d^2, b^2 + 2*b*d + d^2, a + b + c + d] @@ -1486,7 +1519,7 @@ def _groebner_basis_singular_raw(self, algorithm="groebner", singular=singular_d o = _options_py_to_singular.get(o,o) if v: if o in ['degBound','multBound']: - singular.eval(o+'=%d'%v) + singular.eval(o+'=%d' % v) else: singular.option(o) else: @@ -1521,7 +1554,7 @@ def _groebner_basis_singular_raw(self, algorithm="groebner", singular=singular_d elif algorithm == "stdfglm": S = obj.stdfglm() else: - raise TypeError("algorithm '%s' unknown"%algorithm) + raise TypeError("algorithm '%s' unknown" % algorithm) self.__gb_singular = S if prot == "sage": print("") @@ -1575,9 +1608,9 @@ def genus(self): Check that this method works over QQbar (:trac:`25351`):: - sage: P.<x,y> = QQbar[] - sage: I = ideal(y^3*z + x^3*y + x*z^3) - sage: I.genus() + sage: P.<x,y> = QQbar[] # needs sage.rings.number_field + sage: I = ideal(y^3*z + x^3*y + x*z^3) # needs sage.rings.number_field + sage: I.genus() # needs sage.rings.number_field 3 """ from sage.libs.singular.function_factory import ff @@ -1601,22 +1634,23 @@ def intersection(self, *others): The following simple example illustrates that the product need not equal the intersection. :: - sage: I = (x^2, y)*R - sage: J = (y^2, x)*R + sage: I = (x^2, y) * R + sage: J = (y^2, x) * R sage: K = I.intersection(J); K Ideal (y^2, x*y, x^2) of Multivariate Polynomial Ring in x, y over Rational Field sage: IJ = I*J; IJ - Ideal (x^2*y^2, x^3, y^3, x*y) of Multivariate Polynomial Ring in x, y over Rational Field + Ideal (x^2*y^2, x^3, y^3, x*y) + of Multivariate Polynomial Ring in x, y over Rational Field sage: IJ == K False Intersection of several ideals:: sage: R.<x,y,z> = PolynomialRing(QQ, 3, order='lex') - sage: I1 = x*R - sage: I2 = y*R - sage: I3 = (x, y)*R - sage: I4 = (x^2 + x*y*z, y^2 - z^3*y, z^3 + y^5*x*z)*R + sage: I1 = x * R + sage: I2 = y * R + sage: I3 = (x, y) * R + sage: I4 = (x^2 + x*y*z, y^2 - z^3*y, z^3 + y^5*x*z) * R sage: I1.intersection(I2, I3, I4).groebner_basis() [x^2*y + x*y*z^4, x*y^2 - x*y*z^3, x*y*z^20 - x*y*z^3] @@ -1635,6 +1669,7 @@ def intersection(self, *others): Check that this method works over QQbar (:trac:`25351`):: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: I = x*R sage: J = y*R @@ -1643,7 +1678,6 @@ def intersection(self, *others): """ R = self.ring() - for other in others: if not isinstance(other, MPolynomialIdeal_singular_repr) or other.ring() != R: raise TypeError("Intersection is only available for ideals of the same ring.") @@ -1666,10 +1700,12 @@ def minimal_associated_primes(self): sage: R.<x,y,z> = PolynomialRing(QQ, 3, 'xyz') sage: p = z^2 + 1; q = z^3 + 2 - sage: I = (p*q^2, y-z^2)*R + sage: I = (p*q^2, y - z^2) * R sage: sorted(I.minimal_associated_primes(), key=str) - [Ideal (z^2 + 1, -z^2 + y) of Multivariate Polynomial Ring in x, y, z over Rational Field, - Ideal (z^3 + 2, -z^2 + y) of Multivariate Polynomial Ring in x, y, z over Rational Field] + [Ideal (z^2 + 1, -z^2 + y) + of Multivariate Polynomial Ring in x, y, z over Rational Field, + Ideal (z^3 + 2, -z^2 + y) + of Multivariate Polynomial Ring in x, y, z over Rational Field] ALGORITHM: @@ -1693,7 +1729,7 @@ def radical(self): This is an obviously not radical ideal:: sage: R.<x,y,z> = PolynomialRing(QQ, 3) - sage: I = (x^2, y^3, (x*z)^4 + y^3 + 10*x^2)*R + sage: I = (x^2, y^3, (x*z)^4 + y^3 + 10*x^2) * R sage: I.radical() Ideal (y, x) of Multivariate Polynomial Ring in x, y, z over Rational Field @@ -1705,9 +1741,10 @@ def radical(self): This is the example from the Singular manual:: sage: p = z^2 + 1; q = z^3 + 2 - sage: I = (p*q^2, y-z^2)*R + sage: I = (p*q^2, y - z^2) * R sage: I.radical() - Ideal (z^2 - y, y^2*z + y*z + 2*y + 2) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (z^2 - y, y^2*z + y*z + 2*y + 2) + of Multivariate Polynomial Ring in x, y, z over Rational Field .. NOTE:: @@ -1717,11 +1754,13 @@ def radical(self): :: + sage: # needs sage.rings.finite_rings sage: R.<x,y,z> = PolynomialRing(GF(37), 3) sage: p = z^2 + 1; q = z^3 + 2 - sage: I = (p*q^2, y - z^2)*R + sage: I = (p*q^2, y - z^2) * R sage: I.radical() - Ideal (z^2 - y, y^2*z + y*z + 2*y + 2) of Multivariate Polynomial Ring in x, y, z over Finite Field of size 37 + Ideal (z^2 - y, y^2*z + y*z + 2*y + 2) + of Multivariate Polynomial Ring in x, y, z over Finite Field of size 37 """ from sage.libs.singular.function_factory import ff radical = ff.primdec__lib.radical @@ -1744,22 +1783,22 @@ def integral_closure(self, p=0, r=True, singular=singular_default): Return the integral closure of `I, ..., I^p`, where `sI` is an ideal in the polynomial ring `R=k[x(1),...x(n)]`. If `p` is not given, or `p=0`, compute the closure of all powers up to - the maximum degree in t occurring in the closure of `R[It]` + the maximum degree in `t` occurring in the closure of `R[It]` (so this is the last power whose closure is not just the sum/product of the smaller). If `r` is given and ``r is - True``, ``I.integral_closure()`` starts with a check whether I + True``, ``I.integral_closure()`` starts with a check whether `I` is already a radical ideal. INPUT: - - ``p`` - powers of I (default: 0) + - ``p`` - powers of `I` (default: 0) - - ``r`` - check whether self is a radical ideal first (default: ``True``) + - ``r`` - check whether ``self`` is a radical ideal first (default: ``True``) EXAMPLES:: sage: R.<x,y> = QQ[] - sage: I = ideal([x^2,x*y^4,y^5]) + sage: I = ideal([x^2, x*y^4, y^5]) sage: I.integral_closure() [x^2, x*y^4, y^5, x*y^3] @@ -1804,6 +1843,7 @@ def syzygy_module(self): Check that this method works over QQbar (:trac:`25351`):: + sage: # needs sage.rings.number_field sage: R.<x,y> = QQbar[] sage: f = 2*x^2 + y sage: g = y @@ -1905,38 +1945,38 @@ def graded_free_resolution(self, *args, **kwds): @libsingular_gb_standard_options def interreduced_basis(self): r""" - If this ideal is spanned by `(f_1, ..., f_n)` this method - returns `(g_1, ..., g_s)` such that: + If this ideal is spanned by `(f_1, ..., f_n)`, + return `(g_1, ..., g_s)` such that: - `(f_1,...,f_n) = (g_1,...,g_s)` - - `LT(g_i) != LT(g_j)` for all `i != j` + - `LT(g_i) \neq LT(g_j)` for all `i \neq j` - `LT(g_i)` does not divide `m` for all monomials `m` of - `\{g_1,...,g_{i-1},g_{i+1},...,g_s\}` + `\{g_1,...,g_{i-1},g_{i+1},...,g_s\}` - - `LC(g_i) == 1` for all `i` if the coefficient ring is a field. + - `LC(g_i) = 1` for all `i` if the coefficient ring is a field. EXAMPLES:: sage: R.<x,y,z> = PolynomialRing(QQ) - sage: I = Ideal([z*x+y^3,z+y^3,z+x*y]) + sage: I = Ideal([z*x + y^3, z + y^3, z + x*y]) sage: I.interreduced_basis() [y^3 + z, x*y + z, x*z - z] Note that tail reduction for local orderings is not well-defined:: sage: R.<x,y,z> = PolynomialRing(QQ,order='negdegrevlex') - sage: I = Ideal([z*x+y^3,z+y^3,z+x*y]) + sage: I = Ideal([z*x + y^3, z + y^3, z + x*y]) sage: I.interreduced_basis() [z + x*y, x*y - y^3, x^2*y - y^3] A fixed error with nonstandard base fields:: - sage: R.<t>=QQ['t'] - sage: K.<x,y>=R.fraction_field()['x,y'] - sage: I=t*x*K + sage: R.<t> = QQ['t'] + sage: K.<x,y> = R.fraction_field()['x,y'] + sage: I = t*x * K sage: I.interreduced_basis() [x] @@ -1948,7 +1988,7 @@ def interreduced_basis(self): ALGORITHM: - Uses Singular's interred command or + Uses Singular's ``interred`` command or :func:`sage.rings.polynomial.toy_buchberger.inter_reduction` if conversion to Singular fails. @@ -1956,9 +1996,9 @@ def interreduced_basis(self): Check that this method works over QQbar (:trac:`25351`):: - sage: R.<x,y,z> = QQbar[] - sage: I = Ideal([z*x+y^3,z+y^3,z+x*y]) - sage: I.interreduced_basis() + sage: R.<x,y,z> = QQbar[] # needs sage.rings.number_field + sage: I = Ideal([z*x + y^3, z + y^3, z + x*y]) # needs sage.rings.number_field + sage: I.interreduced_basis() # needs sage.rings.number_field [y^3 + z, x*y + z, x*z - z] """ return self.basis.reduced() @@ -1986,8 +2026,9 @@ def basis_is_groebner(self, singular=singular_default): EXAMPLES:: - sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127),10) - sage: I = sage.rings.ideal.Cyclic(R,4) + sage: # needs sage.rings.finite_rings + sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127), 10) + sage: I = sage.rings.ideal.Cyclic(R, 4) sage: I.basis_is_groebner() False sage: I2 = Ideal(I.groebner_basis()) @@ -1996,34 +2037,53 @@ def basis_is_groebner(self, singular=singular_default): A more complicated example:: - sage: R.<U6,U5,U4,U3,U2, u6,u5,u4,u3,u2, h> = PolynomialRing(GF(7583)) - sage: l = [u6 + u5 + u4 + u3 + u2 - 3791*h, \ - U6 + U5 + U4 + U3 + U2 - 3791*h, \ - U2*u2 - h^2, U3*u3 - h^2, U4*u4 - h^2, \ - U5*u4 + U5*u3 + U4*u3 + U5*u2 + U4*u2 + U3*u2 - 3791*U5*h - 3791*U4*h - 3791*U3*h - 3791*U2*h - 2842*h^2, \ - U4*u5 + U3*u5 + U2*u5 + U3*u4 + U2*u4 + U2*u3 - 3791*u5*h - 3791*u4*h - 3791*u3*h - 3791*u2*h - 2842*h^2, \ - U5*u5 - h^2, U4*U2*u3 + U5*U3*u2 + U4*U3*u2 + U3^2*u2 - 3791*U5*U3*h - 3791*U4*U3*h - 3791*U3^2*h - 3791*U5*U2*h \ - - 3791*U4*U2*h + U3*U2*h - 3791*U2^2*h - 3791*U4*u3*h - 3791*U4*u2*h - 3791*U3*u2*h - 2843*U5*h^2 + 1897*U4*h^2 - 946*U3*h^2 - 947*U2*h^2 + 2370*h^3, \ - U3*u5*u4 + U2*u5*u4 + U3*u4^2 + U2*u4^2 + U2*u4*u3 - 3791*u5*u4*h - 3791*u4^2*h - 3791*u4*u3*h - 3791*u4*u2*h + u5*h^2 - 2842*u4*h^2, \ - U2*u5*u4*u3 + U2*u4^2*u3 + U2*u4*u3^2 - 3791*u5*u4*u3*h - 3791*u4^2*u3*h - 3791*u4*u3^2*h - 3791*u4*u3*u2*h + u5*u4*h^2 + u4^2*h^2 + u5*u3*h^2 - 2842*u4*u3*h^2, \ - U5^2*U4*u3 + U5*U4^2*u3 + U5^2*U4*u2 + U5*U4^2*u2 + U5^2*U3*u2 + 2*U5*U4*U3*u2 + U5*U3^2*u2 - 3791*U5^2*U4*h - 3791*U5*U4^2*h - 3791*U5^2*U3*h \ - + U5*U4*U3*h - 3791*U5*U3^2*h - 3791*U5^2*U2*h + U5*U4*U2*h + U5*U3*U2*h - 3791*U5*U2^2*h - 3791*U5*U3*u2*h - 2842*U5^2*h^2 + 1897*U5*U4*h^2 \ - - U4^2*h^2 - 947*U5*U3*h^2 - U4*U3*h^2 - 948*U5*U2*h^2 - U4*U2*h^2 - 1422*U5*h^3 + 3791*U4*h^3, \ - u5*u4*u3*u2*h + u4^2*u3*u2*h + u4*u3^2*u2*h + u4*u3*u2^2*h + 2*u5*u4*u3*h^2 + 2*u4^2*u3*h^2 + 2*u4*u3^2*h^2 + 2*u5*u4*u2*h^2 + 2*u4^2*u2*h^2 \ - + 2*u5*u3*u2*h^2 + 1899*u4*u3*u2*h^2, \ - U5^2*U4*U3*u2 + U5*U4^2*U3*u2 + U5*U4*U3^2*u2 - 3791*U5^2*U4*U3*h - 3791*U5*U4^2*U3*h - 3791*U5*U4*U3^2*h - 3791*U5*U4*U3*U2*h \ - + 3791*U5*U4*U3*u2*h + U5^2*U4*h^2 + U5*U4^2*h^2 + U5^2*U3*h^2 - U4^2*U3*h^2 - U5*U3^2*h^2 - U4*U3^2*h^2 - U5*U4*U2*h^2 \ - - U5*U3*U2*h^2 - U4*U3*U2*h^2 + 3791*U5*U4*h^3 + 3791*U5*U3*h^3 + 3791*U4*U3*h^3, \ - u4^2*u3*u2*h^2 + 1515*u5*u3^2*u2*h^2 + u4*u3^2*u2*h^2 + 1515*u5*u4*u2^2*h^2 + 1515*u5*u3*u2^2*h^2 + u4*u3*u2^2*h^2 \ - + 1521*u5*u4*u3*h^3 - 3028*u4^2*u3*h^3 - 3028*u4*u3^2*h^3 + 1521*u5*u4*u2*h^3 - 3028*u4^2*u2*h^3 + 1521*u5*u3*u2*h^3 + 3420*u4*u3*u2*h^3, \ - U5^2*U4*U3*U2*h + U5*U4^2*U3*U2*h + U5*U4*U3^2*U2*h + U5*U4*U3*U2^2*h + 2*U5^2*U4*U3*h^2 + 2*U5*U4^2*U3*h^2 + 2*U5*U4*U3^2*h^2 \ - + 2*U5^2*U4*U2*h^2 + 2*U5*U4^2*U2*h^2 + 2*U5^2*U3*U2*h^2 - 2*U4^2*U3*U2*h^2 - 2*U5*U3^2*U2*h^2 - 2*U4*U3^2*U2*h^2 \ - - 2*U5*U4*U2^2*h^2 - 2*U5*U3*U2^2*h^2 - 2*U4*U3*U2^2*h^2 - U5*U4*U3*h^3 - U5*U4*U2*h^3 - U5*U3*U2*h^3 - U4*U3*U2*h^3] - - sage: Ideal(l).basis_is_groebner() + sage: R.<U6,U5,U4,U3,U2, u6,u5,u4,u3,u2, h> = PolynomialRing(GF(7583)) # needs sage.rings.finite_rings + sage: l = [u6 + u5 + u4 + u3 + u2 - 3791*h, # needs sage.rings.finite_rings + ....: U6 + U5 + U4 + U3 + U2 - 3791*h, + ....: U2*u2 - h^2, U3*u3 - h^2, U4*u4 - h^2, + ....: U5*u4 + U5*u3 + U4*u3 + U5*u2 + U4*u2 + U3*u2 - 3791*U5*h + ....: - 3791*U4*h - 3791*U3*h - 3791*U2*h - 2842*h^2, + ....: U4*u5 + U3*u5 + U2*u5 + U3*u4 + U2*u4 + U2*u3 - 3791*u5*h + ....: - 3791*u4*h - 3791*u3*h - 3791*u2*h - 2842*h^2, + ....: U5*u5 - h^2, U4*U2*u3 + U5*U3*u2 + U4*U3*u2 + U3^2*u2 - 3791*U5*U3*h + ....: - 3791*U4*U3*h - 3791*U3^2*h - 3791*U5*U2*h- 3791*U4*U2*h + U3*U2*h + ....: - 3791*U2^2*h - 3791*U4*u3*h - 3791*U4*u2*h - 3791*U3*u2*h + ....: - 2843*U5*h^2 + 1897*U4*h^2 - 946*U3*h^2 - 947*U2*h^2 + 2370*h^3, + ....: U3*u5*u4 + U2*u5*u4 + U3*u4^2 + U2*u4^2 + U2*u4*u3 - 3791*u5*u4*h + ....: - 3791*u4^2*h - 3791*u4*u3*h - 3791*u4*u2*h + u5*h^2 - 2842*u4*h^2, + ....: U2*u5*u4*u3 + U2*u4^2*u3 + U2*u4*u3^2 - 3791*u5*u4*u3*h + ....: - 3791*u4^2*u3*h - 3791*u4*u3^2*h - 3791*u4*u3*u2*h + u5*u4*h^2 + ....: + u4^2*h^2 + u5*u3*h^2 - 2842*u4*u3*h^2, + ....: U5^2*U4*u3 + U5*U4^2*u3 + U5^2*U4*u2 + U5*U4^2*u2 + U5^2*U3*u2 + ....: + 2*U5*U4*U3*u2 + U5*U3^2*u2 - 3791*U5^2*U4*h - 3791*U5*U4^2*h + ....: - 3791*U5^2*U3*h + U5*U4*U3*h - 3791*U5*U3^2*h - 3791*U5^2*U2*h + ....: + U5*U4*U2*h+ U5*U3*U2*h - 3791*U5*U2^2*h - 3791*U5*U3*u2*h + ....: - 2842*U5^2*h^2 + 1897*U5*U4*h^2 - U4^2*h^2 - 947*U5*U3*h^2 + ....: - U4*U3*h^2 - 948*U5*U2*h^2 - U4*U2*h^2 - 1422*U5*h^3 + 3791*U4*h^3, + ....: u5*u4*u3*u2*h + u4^2*u3*u2*h + u4*u3^2*u2*h + u4*u3*u2^2*h + ....: + 2*u5*u4*u3*h^2 + 2*u4^2*u3*h^2 + 2*u4*u3^2*h^2 + 2*u5*u4*u2*h^2 + ....: + 2*u4^2*u2*h^2 + 2*u5*u3*u2*h^2 + 1899*u4*u3*u2*h^2, + ....: U5^2*U4*U3*u2 + U5*U4^2*U3*u2 + U5*U4*U3^2*u2 - 3791*U5^2*U4*U3*h + ....: - 3791*U5*U4^2*U3*h - 3791*U5*U4*U3^2*h - 3791*U5*U4*U3*U2*h + ....: + 3791*U5*U4*U3*u2*h + U5^2*U4*h^2 + U5*U4^2*h^2 + U5^2*U3*h^2 + ....: - U4^2*U3*h^2 - U5*U3^2*h^2 - U4*U3^2*h^2 - U5*U4*U2*h^2 - U5*U3*U2*h^2 + ....: - U4*U3*U2*h^2 + 3791*U5*U4*h^3 + 3791*U5*U3*h^3 + 3791*U4*U3*h^3, + ....: u4^2*u3*u2*h^2 + 1515*u5*u3^2*u2*h^2 + u4*u3^2*u2*h^2 + ....: + 1515*u5*u4*u2^2*h^2 + 1515*u5*u3*u2^2*h^2 + u4*u3*u2^2*h^2 + ....: + 1521*u5*u4*u3*h^3 - 3028*u4^2*u3*h^3 - 3028*u4*u3^2*h^3 + ....: + 1521*u5*u4*u2*h^3 - 3028*u4^2*u2*h^3 + 1521*u5*u3*u2*h^3 + ....: + 3420*u4*u3*u2*h^3, + ....: U5^2*U4*U3*U2*h + U5*U4^2*U3*U2*h + U5*U4*U3^2*U2*h + U5*U4*U3*U2^2*h + ....: + 2*U5^2*U4*U3*h^2 + 2*U5*U4^2*U3*h^2 + 2*U5*U4*U3^2*h^2 + ....: + 2*U5^2*U4*U2*h^2 + 2*U5*U4^2*U2*h^2 + 2*U5^2*U3*U2*h^2 + ....: - 2*U4^2*U3*U2*h^2 - 2*U5*U3^2*U2*h^2 - 2*U4*U3^2*U2*h^2 + ....: - 2*U5*U4*U2^2*h^2 - 2*U5*U3*U2^2*h^2 - 2*U4*U3*U2^2*h^2 + ....: - U5*U4*U3*h^3 - U5*U4*U2*h^3 - U5*U3*U2*h^3 - U4*U3*U2*h^3] + + sage: Ideal(l).basis_is_groebner() # needs sage.rings.finite_rings False - sage: gb = Ideal(l).groebner_basis() - sage: Ideal(gb).basis_is_groebner() + sage: gb = Ideal(l).groebner_basis() # needs sage.rings.finite_rings + sage: Ideal(gb).basis_is_groebner() # needs sage.rings.finite_rings True .. NOTE:: @@ -2032,15 +2092,16 @@ def basis_is_groebner(self, singular=singular_default): this method: 'The result may have no meaning if the second argument (``self``) is not a standard basis'. I (malb) believe this refers to the mathematical fact that the - results may have no meaning if self is no standard basis, + results may have no meaning if ``self`` is no standard basis, i.e., Singular doesn't 'add' any additional 'nonsense' to the result. So we may actually use reduce to determine if - self is a Groebner basis. + ``self`` is a Groebner basis. TESTS: Check that this method works over QQbar (:trac:`25351`):: + sage: # needs sage.rings.number_field sage: R.<a,b,c,d,e,f,g,h,i,j> = QQbar[] sage: I = sage.rings.ideal.Cyclic(R,4) sage: I.basis_is_groebner() @@ -2079,7 +2140,7 @@ def basis_is_groebner(self, singular=singular_default): M = (F * LTF.syz()).reduce(self._singular_()) for i in range(M.ncols()): - if int(singular.eval("%s[1,%s+1]!=0"%(M.name(),i))): + if int(singular.eval("%s[1,%s+1]!=0" % (M.name(),i))): return False self._singular_().attrib('isSB',1) return True @@ -2096,25 +2157,25 @@ def transformed_basis(self, algorithm="gwalk", other_ring=None, singular=singula - ``algorithm`` - see below for options. - - ``other_ring`` - only valid for algorithm 'fglm', if - provided conversion will be performed to this + - ``other_ring`` - only valid for ``algorithm='fglm'``; if + provided, conversion will be performed to this ring. Otherwise a lex Groebner basis will be returned. ALGORITHMS: - - ``fglm`` - FGLM algorithm. The input ideal must be given with a reduced + - ``"fglm"`` - FGLM algorithm. The input ideal must be given with a reduced Groebner Basis of a zero-dimensional ideal - - ``gwalk`` - Groebner Walk algorithm (*default*) + - ``"gwalk"`` - Groebner Walk algorithm (*default*) - - ``awalk1`` - 'first alternative' algorithm + - ``"awalk1"`` - 'first alternative' algorithm - - ``awalk2`` - 'second alternative' algorithm + - ``"awalk2"`` - 'second alternative' algorithm - - ``twalk`` - Tran algorithm + - ``"twalk"`` - Tran algorithm - - ``fwalk`` - Fractal Walk algorithm + - ``"fwalk"`` - Fractal Walk algorithm EXAMPLES:: @@ -2125,21 +2186,22 @@ def transformed_basis(self, algorithm="gwalk", other_ring=None, singular=singula sage: J = Ideal(I.transformed_basis('fglm',S)) sage: J Ideal (z^4 + y^3 - y, x^2 + y^3, x*y^3 - y^3, y^4 + y^3) - of Multivariate Polynomial Ring in z, x, y over Rational Field + of Multivariate Polynomial Ring in z, x, y over Rational Field :: - sage: R.<z,y,x>=PolynomialRing(GF(32003),3,order='lex') - sage: I=Ideal([y^3+x*y*z+y^2*z+x*z^3,3+x*y+x^2*y+y^2*z]) - sage: I.transformed_basis('gwalk') + sage: R.<z,y,x> = PolynomialRing(GF(32003), 3, order='lex') # needs sage.rings.finite_rings + sage: I = Ideal([y^3 + x*y*z + y^2*z + x*z^3, 3 + x*y + x^2*y + y^2*z]) # needs sage.rings.finite_rings + sage: I.transformed_basis('gwalk') # needs sage.rings.finite_rings [z*y^2 + y*x^2 + y*x + 3, - z*x + 8297*y^8*x^2 + 8297*y^8*x + 3556*y^7 - 8297*y^6*x^4 + 15409*y^6*x^3 - 8297*y^6*x^2 - - 8297*y^5*x^5 + 15409*y^5*x^4 - 8297*y^5*x^3 + 3556*y^5*x^2 + 3556*y^5*x + 3556*y^4*x^3 - + 3556*y^4*x^2 - 10668*y^4 - 10668*y^3*x - 8297*y^2*x^9 - 1185*y^2*x^8 + 14224*y^2*x^7 - - 1185*y^2*x^6 - 8297*y^2*x^5 - 14223*y*x^7 - 10666*y*x^6 - 10666*y*x^5 - 14223*y*x^4 - + x^5 + 2*x^4 + x^3, - y^9 - y^7*x^2 - y^7*x - y^6*x^3 - y^6*x^2 - 3*y^6 - 3*y^5*x - y^3*x^7 - 3*y^3*x^6 - - 3*y^3*x^5 - y^3*x^4 - 9*y^2*x^5 - 18*y^2*x^4 - 9*y^2*x^3 - 27*y*x^3 - 27*y*x^2 - 27*x] + z*x + 8297*y^8*x^2 + 8297*y^8*x + 3556*y^7 - 8297*y^6*x^4 + 15409*y^6*x^3 + - 8297*y^6*x^2 - 8297*y^5*x^5 + 15409*y^5*x^4 - 8297*y^5*x^3 + 3556*y^5*x^2 + + 3556*y^5*x + 3556*y^4*x^3 + 3556*y^4*x^2 - 10668*y^4 - 10668*y^3*x + - 8297*y^2*x^9 - 1185*y^2*x^8 + 14224*y^2*x^7 - 1185*y^2*x^6 - 8297*y^2*x^5 + - 14223*y*x^7 - 10666*y*x^6 - 10666*y*x^5 - 14223*y*x^4 + x^5 + 2*x^4 + x^3, + y^9 - y^7*x^2 - y^7*x - y^6*x^3 - y^6*x^2 - 3*y^6 - 3*y^5*x - y^3*x^7 + - 3*y^3*x^6 - 3*y^3*x^5 - y^3*x^4 - 9*y^2*x^5 - 18*y^2*x^4 - 9*y^2*x^3 + - 27*y*x^3 - 27*y*x^2 - 27*x] ALGORITHM: @@ -2150,12 +2212,13 @@ def transformed_basis(self, algorithm="gwalk", other_ring=None, singular=singula Check that this method works over QQbar (:trac:`25351`). We are not currently able to specify other_ring, due to the limitations of @handle_AA_and_QQbar:: + sage: # needs sage.rings.number_field sage: R.<x,y,z> = QQbar[] - sage: I = Ideal([y^3+x^2,x^2*y+x^2, x^3-x^2, z^4-x^2-y]) + sage: I = Ideal([y^3 + x^2, x^2*y + x^2, x^3 - x^2, z^4 - x^2 - y]) sage: I = Ideal(I.groebner_basis()) - sage: S.<z,x,y> = PolynomialRing(QQbar,3,order='lex') - sage: J = Ideal(I.transformed_basis('fglm',other_ring=S)) # known bug - sage: J # known bug + sage: S.<z,x,y> = PolynomialRing(QQbar, 3, order='lex') + sage: J = Ideal(I.transformed_basis('fglm', other_ring=S)) # known bug + sage: J # known bug """ from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence R = self.ring() @@ -2187,7 +2250,7 @@ def transformed_basis(self, algorithm="gwalk", other_ring=None, singular=singula return PolynomialSequence(nR, sorted([nR(f) for f in nIs],reverse=True), immutable=True) else: - raise TypeError("Cannot convert basis with given algorithm") + raise TypeError("cannot convert basis with given algorithm") @handle_AA_and_QQbar def elimination_ideal(self, variables, algorithm=None, *args, **kwds): @@ -2200,7 +2263,7 @@ def elimination_ideal(self, variables, algorithm=None, *args, **kwds): - ``variables`` -- a list or tuple of variables in ``self.ring()`` - ``algorithm`` - determines the algorithm to use, see below - for available algorithms. + for available algorithms. ALGORITHMS: @@ -2215,10 +2278,10 @@ def elimination_ideal(self, variables, algorithm=None, *args, **kwds): EXAMPLES:: sage: R.<x,y,t,s,z> = PolynomialRing(QQ,5) - sage: I = R * [x-t,y-t^2,z-t^3,s-x+y^3] - sage: J = I.elimination_ideal([t,s]); J - Ideal (y^2 - x*z, x*y - z, x^2 - y) of Multivariate - Polynomial Ring in x, y, t, s, z over Rational Field + sage: I = R * [x - t, y - t^2, z - t^3, s - x + y^3] + sage: J = I.elimination_ideal([t, s]); J + Ideal (y^2 - x*z, x*y - z, x^2 - y) + of Multivariate Polynomial Ring in x, y, t, s, z over Rational Field You can use Giac to compute the elimination ideal:: @@ -2242,9 +2305,10 @@ def elimination_ideal(self, variables, algorithm=None, *args, **kwds): Check that this method works over QQbar (:trac:`25351`):: + sage: # needs sage.rings.number_field sage: R.<x,y,t,s,z> = QQbar[] - sage: I = R * [x-t,y-t^2,z-t^3,s-x+y^3] - sage: J = I.elimination_ideal([t,s]); J + sage: I = R * [x - t, y - t^2, z - t^3, s - x + y^3] + sage: J = I.elimination_ideal([t, s]); J Ideal (y^2 - x*z, x*y - z, x^2 - y) of Multivariate Polynomial Ring in x, y, t, s, z over Algebraic Field sage: print("possible output from giac", flush=True); I.elimination_ideal([t, s], algorithm="giac") == J @@ -2317,8 +2381,9 @@ def quotient(self, J): EXAMPLES:: - sage: R.<x,y,z> = PolynomialRing(GF(181),3) - sage: I = Ideal([x^2+x*y*z,y^2-z^3*y,z^3+y^5*x*z]) + sage: # needs sage.rings.finite_rings + sage: R.<x,y,z> = PolynomialRing(GF(181), 3) + sage: I = Ideal([x^2 + x*y*z, y^2 - z^3*y, z^3 + y^5*x*z]) sage: J = Ideal([x]) sage: Q = I.quotient(J) sage: y*z + x in I @@ -2340,8 +2405,9 @@ def quotient(self, J): Check that this method works over QQbar (:trac:`25351`):: + sage: # needs sage.rings.number_field sage: R.<x,y,z> = QQbar[] - sage: I = ideal(x,z) + sage: I = ideal(x, z) sage: J = ideal(R(1)) sage: I.quotient(J) Ideal (z, x) of Multivariate Polynomial Ring in x, y, z over Algebraic Field @@ -2380,9 +2446,7 @@ def saturation(self, other): - ``other`` -- another ideal in the same ring - OUTPUT: - - - a pair (ideal, integer) + OUTPUT: a pair (ideal, integer) EXAMPLES:: @@ -2396,6 +2460,7 @@ def saturation(self, other): Check that this method works over QQbar (:trac:`25351`):: + sage: # needs sage.rings.number_field sage: R.<x, y, z> = QQbar[] sage: I = R.ideal(x^5*z^3, x*y*z, y*z^4) sage: J = R.ideal(z) @@ -2403,7 +2468,11 @@ def saturation(self, other): (Ideal (y, x^5) of Multivariate Polynomial Ring in x, y, z over Algebraic Field, 4) """ from sage.libs.singular.function_factory import ff - sat = ff.elim__lib.sat + # function renamed in singular > 4.3.2p4, see issue #35980 + try: + sat = ff.elim__lib.sat_with_exp + except NameError: + sat = ff.elim__lib.sat R = self.ring() ideal, expo = sat(self, other) return (R.ideal(ideal), ZZ(expo)) @@ -2413,7 +2482,7 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True r""" Return the variety of this ideal. - Given a zero-dimensional ideal `I` (== ``self``) of a + Given a zero-dimensional ideal `I` (= ``self``) of a polynomial ring `P` whose order is lexicographic, return the variety of `I` as a list of dictionaries with ``(variable, value)`` pairs. By default, the variety of the ideal over its @@ -2449,41 +2518,41 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True EXAMPLES:: - sage: K.<w> = GF(27) # this example is from the MAGMA handbook + sage: # needs sage.rings.finite_rings + sage: K.<w> = GF(27) # this example is from the MAGMA handbook sage: P.<x, y> = PolynomialRing(K, 2, order='lex') - sage: I = Ideal([ x^8 + y + 2, y^6 + x*y^5 + x^2 ]) + sage: I = Ideal([x^8 + y + 2, y^6 + x*y^5 + x^2]) sage: I = Ideal(I.groebner_basis()); I - Ideal (x - y^47 - y^45 + y^44 - y^43 + y^41 - y^39 - y^38 - - y^37 - y^36 + y^35 - y^34 - y^33 + y^32 - y^31 + y^30 + - y^28 + y^27 + y^26 + y^25 - y^23 + y^22 + y^21 - y^19 - - y^18 - y^16 + y^15 + y^13 + y^12 - y^10 + y^9 + y^8 + y^7 - - y^6 + y^4 + y^3 + y^2 + y - 1, y^48 + y^41 - y^40 + y^37 - - y^36 - y^33 + y^32 - y^29 + y^28 - y^25 + y^24 + y^2 + y - + 1) of Multivariate Polynomial Ring in x, y over Finite - Field in w of size 3^3 - + Ideal (x - y^47 - y^45 + y^44 - y^43 + y^41 - y^39 - y^38 - y^37 - y^36 + + y^35 - y^34 - y^33 + y^32 - y^31 + y^30 + y^28 + y^27 + y^26 + + y^25 - y^23 + y^22 + y^21 - y^19 - y^18 - y^16 + y^15 + y^13 + + y^12 - y^10 + y^9 + y^8 + y^7 - y^6 + y^4 + y^3 + y^2 + y - 1, + y^48 + y^41 - y^40 + y^37 - y^36 - y^33 + y^32 - y^29 + y^28 + - y^25 + y^24 + y^2 + y + 1) + of Multivariate Polynomial Ring in x, y over Finite Field in w of size 3^3 sage: V = I.variety(); sage: sorted(V, key=str) [{y: w^2 + 2*w, x: 2*w + 2}, {y: w^2 + 2, x: 2*w}, {y: w^2 + w, x: 2*w + 1}] - sage: [f.subs(v) for f in I.gens() for v in V] # check that all polynomials vanish + sage: [f.subs(v) # check that all polynomials vanish + ....: for f in I.gens() for v in V] [0, 0, 0, 0, 0, 0] - sage: [I.subs(v).is_zero() for v in V] # same test, but nicer syntax + sage: [I.subs(v).is_zero() for v in V] # same test, but nicer syntax [True, True, True] However, we only account for solutions in the ground field and not in the algebraic closure:: - sage: I.vector_space_dimension() + sage: I.vector_space_dimension() # needs sage.rings.finite_rings 48 Here we compute the points of intersection of a hyperbola and a circle, in several fields:: sage: K.<x, y> = PolynomialRing(QQ, 2, order='lex') - sage: I = Ideal([ x*y - 1, (x-2)^2 + (y-1)^2 - 1]) + sage: I = Ideal([x*y - 1, (x-2)^2 + (y-1)^2 - 1]) sage: I = Ideal(I.groebner_basis()); I Ideal (x + y^3 - 2*y^2 + 4*y - 4, y^4 - 2*y^3 + 4*y^2 - 4*y + 1) - of Multivariate Polynomial Ring in x, y over Rational Field + of Multivariate Polynomial Ring in x, y over Rational Field These two curves have one rational intersection:: @@ -2495,7 +2564,7 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True sage: sorted(I.variety(ring=RR), key=str) [{y: 0.361103080528647, x: 2.76929235423863}, {y: 1.00000000000000, x: 1.00000000000000}] - sage: I.variety(ring=AA) + sage: I.variety(ring=AA) # needs sage.rings.number_field [{y: 1, x: 1}, {y: 0.3611030805286474?, x: 2.769292354238632?}] @@ -2508,7 +2577,7 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True x: 0.11535382288068... + 0.58974280502220...*I}, {y: 0.36110308052864..., x: 2.7692923542386...}, {y: 1.00000000000000, x: 1.00000000000000}] - sage: sorted(I.variety(ring=QQbar), key=str) + sage: sorted(I.variety(ring=QQbar), key=str) # needs sage.rings.number_field [{y: 0.3194484597356763? + 1.633170240915238?*I, x: 0.11535382288068429? - 0.5897428050222055?*I}, {y: 0.3194484597356763? - 1.633170240915238?*I, @@ -2520,7 +2589,7 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True to compute the variety. See :mod:`~sage.rings.polynomial.msolve` for more information. :: - sage: I.variety(RBF, algorithm='msolve', proof=False) # optional - msolve + sage: I.variety(RBF, algorithm='msolve', proof=False) # optional - msolve [{x: [2.76929235423863 +/- 2.08e-15], y: [0.361103080528647 +/- 4.53e-16]}, {x: 1.000000000000000, y: 1.000000000000000}] @@ -2543,8 +2612,9 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True If the ground field's characteristic is too large for Singular, we resort to a toy implementation:: - sage: R.<x,y> = PolynomialRing(GF(2147483659^3),order='lex') - sage: I=ideal([x^3-2*y^2,3*x+y^4]) + sage: # needs sage.rings.finite_rings + sage: R.<x,y> = PolynomialRing(GF(2147483659^3), order='lex') + sage: I = ideal([x^3 - 2*y^2, 3*x + y^4]) sage: I.variety() verbose 0 (...: multi_polynomial_ideal.py, groebner_basis) Warning: falling back to very slow toy implementation. verbose 0 (...: multi_polynomial_ideal.py, dimension) Warning: falling back to very slow toy implementation. @@ -2556,8 +2626,9 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True But the mapping will also accept generators of the original ring, or even generator names as strings, when provided as keys:: + sage: # needs sage.rings.number_field sage: K.<x,y> = QQ[] - sage: I = ideal([x^2+2*y-5,x+y+3]) + sage: I = ideal([x^2 + 2*y - 5, x + y + 3]) sage: v = I.variety(AA)[0]; v[x], v[y] (4.464101615137755?, -7.464101615137755?) sage: list(v)[0].parent() @@ -2567,11 +2638,13 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True sage: v["y"] -7.464101615137755? - msolve also works over finite fields:: + ``msolve`` also works over finite fields:: - sage: R.<x, y> = PolynomialRing(GF(536870909), 2, order='lex') - sage: I = Ideal([ x^2 - 1, y^2 - 1 ]) - sage: sorted(I.variety(algorithm='msolve', proof=False), key=str) # optional - msolve + sage: R.<x, y> = PolynomialRing(GF(536870909), 2, order='lex') # needs sage.rings.finite_rings + sage: I = Ideal([x^2 - 1, y^2 - 1]) # needs sage.rings.finite_rings + sage: sorted(I.variety(algorithm='msolve', # optional - msolve, needs sage.rings.finite_rings + ....: proof=False), + ....: key=str) [{x: 1, y: 1}, {x: 1, y: 536870908}, {x: 536870908, y: 1}, @@ -2581,8 +2654,8 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True degree with respect to the characteristic:: sage: R.<x, y> = PolynomialRing(GF(3), 2, order='lex') - sage: I = Ideal([ x^2 - 1, y^2 - 1 ]) - sage: I.variety(algorithm='msolve', proof=False) # optional - msolve + sage: I = Ideal([x^2 - 1, y^2 - 1]) + sage: I.variety(algorithm='msolve', proof=False) # optional - msolve Traceback (most recent call last): ... NotImplementedError: characteristic 3 too small @@ -2617,14 +2690,14 @@ def _variety_triangular_decomposition(self, ring): TESTS:: - sage: K.<w> = GF(27) - sage: P.<x, y> = PolynomialRing(K, 2, order='lex') - sage: I = Ideal([ x^8 + y + 2, y^6 + x*y^5 + x^2 ]) + sage: K.<w> = GF(27) # needs sage.rings.finite_rings + sage: P.<x, y> = PolynomialRing(K, 2, order='lex') # needs sage.rings.finite_rings + sage: I = Ideal([ x^8 + y + 2, y^6 + x*y^5 + x^2 ]) # needs sage.rings.finite_rings Testing the robustness of the Singular interface:: - sage: T = I.triangular_decomposition('singular:triangLfak') - sage: sorted(I.variety(), key=str) + sage: T = I.triangular_decomposition('singular:triangLfak') # needs sage.rings.finite_rings + sage: sorted(I.variety(), key=str) # needs sage.rings.finite_rings [{y: w^2 + 2*w, x: 2*w + 2}, {y: w^2 + 2, x: 2*w}, {y: w^2 + w, x: 2*w + 1}] Testing that a bug is indeed fixed :: @@ -2679,10 +2752,10 @@ def _variety_triangular_decomposition(self, ring): Check that the issue at :trac:`7425` is fixed:: - sage: S.<t>=PolynomialRing(QQ) - sage: F.<q>=QQ.extension(t^4+1) - sage: R.<x,y>=PolynomialRing(F) - sage: I=R.ideal(x,y^4+1) + sage: S.<t> = PolynomialRing(QQ) + sage: F.<q> = QQ.extension(t^4 + 1) + sage: R.<x,y> = PolynomialRing(F) + sage: I = R.ideal(x, y^4 + 1) sage: I.variety() [...{y: -q^3, x: 0}...] @@ -2696,8 +2769,8 @@ def _variety_triangular_decomposition(self, ring): Check that the issue at :trac:`16485` is fixed:: sage: R.<a,b,c> = PolynomialRing(QQ, order='lex') - sage: I = R.ideal(c^2-2, b-c, a) - sage: I.variety(QQbar) + sage: I = R.ideal(c^2 - 2, b - c, a) + sage: I.variety(QQbar) # needs sage.rings.number_field [...a: 0...] An early version of :trac:`25351` broke this method by adding the @@ -2705,6 +2778,7 @@ def _variety_triangular_decomposition(self, ring): that this circle and this hyperbola have two real intersections and two more complex ones:: + sage: # needs sage.rings.number_field sage: K.<x, y> = PolynomialRing(AA) sage: I = Ideal([ x*y - 1, (x-2)^2 + (y-1)^2 - 1]) sage: len(I.variety()) @@ -2747,7 +2821,7 @@ def _variety(T, V, v=None): d = self.dimension() if d > 0: - raise ValueError("The dimension of the ideal is %s, but it should be 0"%d) + raise ValueError("The dimension of the ideal is %s, but it should be 0" % d) if d == -1: return [] @@ -2790,38 +2864,40 @@ def hilbert_polynomial(self, algorithm='sage'): `R = \bigoplus_d R_d` (which is ``self.ring()``) be a graded commutative algebra over a field `K`. The *Hilbert polynomial* is the unique polynomial `HP(t)` with rational coefficients - such that `HP(d) = dim_K R_d` for all but finitely many + such that `HP(d) = \dim_K R_d` for all but finitely many positive integers `d`. EXAMPLES:: sage: P.<x,y,z> = PolynomialRing(QQ) sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) - sage: I.hilbert_polynomial() + sage: I.hilbert_polynomial() # needs sage.libs.flint 5*t - 5 Of course, the Hilbert polynomial of a zero-dimensional ideal is zero:: - sage: J0 = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5, y^3-2*x*z^2+x*y,x^4+x*y-y*z^2]) + sage: J0 = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5, + ....: y^3 - 2*x*z^2 + x*y, x^4 + x*y - y*z^2]) sage: J = P*[m.lm() for m in J0.groebner_basis()] sage: J.dimension() 0 - sage: J.hilbert_polynomial() + sage: J.hilbert_polynomial() # needs sage.libs.flint 0 It is possible to request a computation using the Singular library:: - sage: I.hilbert_polynomial(algorithm = 'singular') == I.hilbert_polynomial() + sage: I.hilbert_polynomial(algorithm='singular') == I.hilbert_polynomial() # needs sage.libs.flint True - sage: J.hilbert_polynomial(algorithm = 'singular') == J.hilbert_polynomial() + sage: J.hilbert_polynomial(algorithm='singular') == J.hilbert_polynomial() # needs sage.libs.flint True Here is a bigger examples:: - sage: n = 4; m = 11; P = PolynomialRing(QQ, n * m, "x"); x = P.gens(); M = Matrix(n, x) + sage: n = 4; m = 11; P = PolynomialRing(QQ, n * m, "x"); x = P.gens() + sage: M = Matrix(n, x) sage: Minors = P.ideal(M.minors(2)) - sage: hp = Minors.hilbert_polynomial(); hp + sage: hp = Minors.hilbert_polynomial(); hp # needs sage.libs.flint 1/21772800*t^13 + 61/21772800*t^12 + 1661/21772800*t^11 + 26681/21772800*t^10 + 93841/7257600*t^9 + 685421/7257600*t^8 + 1524809/3110400*t^7 + 39780323/21772800*t^6 + 6638071/1360800*t^5 @@ -2832,7 +2908,7 @@ def hilbert_polynomial(self, algorithm='sage'): with Singular. We don't test it here, as it has a side-effect on other tests that is not understood yet (see :trac:`26300`):: - sage: Minors.hilbert_polynomial(algorithm = 'singular') # not tested + sage: Minors.hilbert_polynomial(algorithm='singular') # not tested Traceback (most recent call last): ... RuntimeError: error in Singular function call 'hilbPoly': @@ -2843,9 +2919,10 @@ def hilbert_polynomial(self, algorithm='sage'): Note that in this example, the Hilbert polynomial gives the coefficients of the Hilbert-Poincarรฉ series in all degrees:: - sage: P = PowerSeriesRing(QQ, 't', default_prec = 50) - sage: hs = Minors.hilbert_series() - sage: list(P(hs.numerator()) / P(hs.denominator())) == [hp(t = k) for k in range(50)] + sage: P = PowerSeriesRing(QQ, 't', default_prec=50) + sage: hs = Minors.hilbert_series() # needs sage.libs.flint + sage: list(P(hs.numerator()) / P(hs.denominator())) == [hp(t=k) # needs sage.libs.flint + ....: for k in range(50)] True TESTS: @@ -2856,21 +2933,21 @@ def hilbert_polynomial(self, algorithm='sage'): sage: I = Ideal([x^3, x*y^2, y^4, x^2*y*z, y^3*z, x^2*z^2, x*y*z^2, x*z^3]) sage: I.hilbert_polynomial(algorithm='singular') 3 - sage: I.hilbert_polynomial() + sage: I.hilbert_polynomial() # needs sage.libs.flint 3 - Check that this method works over QQbar (:trac:`25351`):: + Check that this method works over ``QQbar`` (:trac:`25351`):: - sage: P.<x,y,z> = QQbar[] - sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) - sage: I.hilbert_polynomial() + sage: P.<x,y,z> = QQbar[] # needs sage.rings.number_field + sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) # needs sage.rings.number_field + sage: I.hilbert_polynomial() # needs sage.rings.number_field 5*t - 5 Check for :trac:`33597`:: sage: R.<X, Y, Z> = QQ[] sage: I = R.ideal([X^2*Y^3, X*Z]) - sage: I.hilbert_polynomial() + sage: I.hilbert_polynomial() # needs sage.libs.flint t + 5 """ if not self.is_homogeneous(): @@ -2916,13 +2993,13 @@ def hilbert_series(self, grading=None, algorithm='sage'): Let `I` (which is ``self``) be a homogeneous ideal and `R = \bigoplus_d R_d` (which is ``self.ring()``) be a graded commutative algebra over a field `K`. Then the - *Hilbert function* is defined as `H(d) = dim_K R_d` and + *Hilbert function* is defined as `H(d) = \dim_K R_d` and the *Hilbert series* of `I` is defined as the formal power series `HS(t) = \sum_{d=0}^{\infty} H(d) t^d`. This power series can be expressed as `HS(t) = Q(t) / (1-t)^n` where `Q(t)` is a polynomial - over `Z` and `n` the number of variables in `R`. + over `\ZZ` and `n` the number of variables in `R`. This method returns `Q(t) / (1-t)^n`, normalised so that the leading monomial of the numerator is positive. @@ -2933,48 +3010,49 @@ def hilbert_series(self, grading=None, algorithm='sage'): sage: P.<x,y,z> = PolynomialRing(QQ) sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) - sage: I.hilbert_series() + sage: I.hilbert_series() # needs sage.libs.flint (t^4 + t^3 + t^2 + t + 1)/(t^2 - 2*t + 1) sage: R.<a,b> = PolynomialRing(QQ) - sage: J = R.ideal([a^2*b,a*b^2]) - sage: J.hilbert_series() + sage: J = R.ideal([a^2*b, a*b^2]) + sage: J.hilbert_series() # needs sage.libs.flint (t^3 - t^2 - t - 1)/(t - 1) - sage: J.hilbert_series(grading=(10,3)) + sage: J.hilbert_series(grading=(10,3)) # needs sage.libs.flint (t^25 + t^24 + t^23 - t^15 - t^14 - t^13 - t^12 - t^11 - t^10 - t^9 - t^8 - t^7 - t^6 - t^5 - t^4 - t^3 - t^2 - t - 1)/(t^12 + t^11 + t^10 - t^2 - t - 1) sage: K = R.ideal([a^2*b^3, a*b^4 + a^3*b^2]) - sage: K.hilbert_series(grading=[1,2]) + sage: K.hilbert_series(grading=[1,2]) # needs sage.libs.flint (t^11 + t^8 - t^6 - t^5 - t^4 - t^3 - t^2 - t - 1)/(t^2 - 1) - sage: K.hilbert_series(grading=[2,1]) + sage: K.hilbert_series(grading=[2,1]) # needs sage.libs.flint (2*t^7 - t^6 - t^4 - t^2 - 1)/(t - 1) TESTS:: - sage: I.hilbert_series() == I.hilbert_series(algorithm = 'singular') + sage: # needs sage.libs.flint + sage: I.hilbert_series() == I.hilbert_series(algorithm='singular') True - sage: J.hilbert_series() == J.hilbert_series(algorithm = 'singular') + sage: J.hilbert_series() == J.hilbert_series(algorithm='singular') True - sage: J.hilbert_series(grading = (10,3)) == J.hilbert_series(grading = (10,3), algorithm = 'singular') + sage: J.hilbert_series(grading=(10,3)) == J.hilbert_series(grading=(10,3), algorithm='singular') True - sage: K.hilbert_series(grading = (1,2)) == K.hilbert_series(grading = (1,2), algorithm = 'singular') + sage: K.hilbert_series(grading=(1,2)) == K.hilbert_series(grading=(1,2), algorithm='singular') True - sage: K.hilbert_series(grading = (2,1)) == K.hilbert_series(grading = (2,1), algorithm = 'singular') + sage: K.hilbert_series(grading=(2,1)) == K.hilbert_series(grading=(2,1), algorithm='singular') True sage: P.<x,y,z> = PolynomialRing(QQ) sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) - sage: I.hilbert_series(grading=5) + sage: I.hilbert_series(grading=5) # needs sage.libs.flint Traceback (most recent call last): ... TypeError: grading must be a list or a tuple of integers Check that this method works over QQbar (:trac:`25351`):: - sage: P.<x,y,z> = QQbar[] - sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) - sage: I.hilbert_series() + sage: P.<x,y,z> = QQbar[] # needs sage.rings.number_field + sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) # needs sage.rings.number_field + sage: I.hilbert_series() # needs sage.rings.number_field (t^4 + t^3 + t^2 + t + 1)/(t^2 - 2*t + 1) """ if not self.is_homogeneous(): @@ -3004,7 +3082,7 @@ def hilbert_series(self, grading=None, algorithm='sage'): @require_field @handle_AA_and_QQbar - def hilbert_numerator(self, grading = None, algorithm = 'sage'): + def hilbert_numerator(self, grading=None, algorithm='sage'): r""" Return the Hilbert numerator of this ideal. @@ -3017,13 +3095,13 @@ def hilbert_numerator(self, grading = None, algorithm = 'sage'): Let `I` (which is ``self``) be a homogeneous ideal and `R = \bigoplus_d R_d` (which is ``self.ring()``) be a graded commutative algebra over a field `K`. Then the - *Hilbert function* is defined as `H(d) = dim_K R_d` and + *Hilbert function* is defined as `H(d) = \dim_K R_d` and the *Hilbert series* of `I` is defined as the formal power series `HS(t) = \sum_{d=0}^{\infty} H(d) t^d`. This power series can be expressed as `HS(t) = Q(t) / (1-t)^n` where `Q(t)` is a polynomial - over `Z` and `n` the number of variables in `R`. This + over `\ZZ` and `n` the number of variables in `R`. This method returns `Q(t)`, the numerator; hence the name, ``hilbert_numerator``. An optional ``grading`` can be given, in which case the graded (or weighted) Hilbert numerator is given. @@ -3032,42 +3110,54 @@ def hilbert_numerator(self, grading = None, algorithm = 'sage'): sage: P.<x,y,z> = PolynomialRing(QQ) sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) - sage: I.hilbert_numerator() + sage: I.hilbert_numerator() # needs sage.libs.flint -t^5 + 1 sage: R.<a,b> = PolynomialRing(QQ) - sage: J = R.ideal([a^2*b,a*b^2]) - sage: J.hilbert_numerator() + sage: J = R.ideal([a^2*b, a*b^2]) + sage: J.hilbert_numerator() # needs sage.libs.flint t^4 - 2*t^3 + 1 - sage: J.hilbert_numerator(grading=(10,3)) + sage: J.hilbert_numerator(grading=(10,3)) # needs sage.libs.flint t^26 - t^23 - t^16 + 1 TESTS:: - sage: I.hilbert_numerator() == I.hilbert_numerator(algorithm = 'singular') + sage: I.hilbert_numerator() == I.hilbert_numerator(algorithm='singular') # needs sage.libs.flint True - sage: J.hilbert_numerator() == J.hilbert_numerator(algorithm = 'singular') + sage: J.hilbert_numerator() == J.hilbert_numerator(algorithm='singular') # needs sage.libs.flint True - sage: J.hilbert_numerator(grading=(10,3)) == J.hilbert_numerator(grading=(10,3), algorithm = 'singular') + sage: J.hilbert_numerator(grading=(10,3)) == J.hilbert_numerator(grading=(10,3), algorithm='singular') # needs sage.libs.flint True Check that this method works over QQbar (:trac:`25351`):: - sage: P.<x,y,z> = QQbar[] - sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) - sage: I.hilbert_numerator() + sage: P.<x,y,z> = QQbar[] # needs sage.rings.number_field + sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) # needs sage.rings.number_field + sage: I.hilbert_numerator() # needs sage.rings.number_field -t^5 + 1 + This example returns a wrong answer in singular < 4.3.2p4 due to an integer overflow:: + + sage: n=4; m=11; P = PolynomialRing(QQ, n*m, "x"); x = P.gens(); M = Matrix(n, x) + sage: I = P.ideal(M.minors(2)) + sage: J = P * [m.lm() for m in I.groebner_basis()] + sage: J.hilbert_numerator(algorithm='singular') # known bug + Traceback (most recent call last): + .... + RuntimeError: error in Singular function call 'hilb': + overflow at t^22 + Our two algorithms should always agree; not tested until :trac:`33178` is fixed:: - sage: m = ZZ.random_element(2,8) # not tested - sage: nvars = m^2 # not tested - sage: R = PolynomialRing(QQ, "x", nvars) # not tested - sage: M = matrix(R, m, R.gens()) # not tested - sage: I = R.ideal(M.minors(2)) # not tested - sage: n1 = I.hilbert_numerator() # not tested - sage: n2 = I.hilbert_numerator(algorithm='singular') # not tested - sage: n1 == n2 # not tested + sage: # not tested + sage: m = ZZ.random_element(2,8) + sage: nvars = m^2 + sage: R = PolynomialRing(QQ, "x", nvars) + sage: M = matrix(R, m, R.gens()) + sage: I = R.ideal(M.minors(2)) + sage: n1 = I.hilbert_numerator() + sage: n2 = I.hilbert_numerator(algorithm='singular') + sage: n1 == n2 True """ @@ -3125,7 +3215,7 @@ def _normal_basis_libsingular(self, degree, weights=None): sage: R.<x,y,z> = PolynomialRing(QQ) sage: I = R.ideal(x^2-2*x*z+5, x*y^2+y*z+1, 3*y^2-8*x*z) - sage: I.normal_basis() #indirect doctest + sage: I.normal_basis() # indirect doctest [z^2, y*z, x*z, z, x*y, y, x, 1] sage: J = R.ideal(x^2-2*x*z+5) sage: J.normal_basis(3) # indirect doctest @@ -3192,7 +3282,7 @@ def normal_basis(self, degree=None, algorithm='libsingular', EXAMPLES:: sage: R.<x,y,z> = PolynomialRing(QQ) - sage: I = R.ideal(x^2+y^2+z^2-4, x^2+2*y^2-5, x*z-1) + sage: I = R.ideal(x^2 + y^2 + z^2 - 4, x^2 + 2*y^2 - 5, x*z - 1) sage: I.normal_basis() [y*z^2, z^2, y*z, z, x*y, y, x, 1] sage: I.normal_basis(algorithm='singular') @@ -3202,7 +3292,7 @@ def normal_basis(self, degree=None, algorithm='libsingular', particularly useful when the quotient ring is not finite-dimensional as a vector space. :: - sage: J = R.ideal(x^2+y^2+z^2-4, x^2+2*y^2-5) + sage: J = R.ideal(x^2 + y^2 + z^2 - 4, x^2 + 2*y^2 - 5) sage: J.dimension() 1 sage: [J.normal_basis(d) for d in (0..3)] @@ -3224,6 +3314,7 @@ def normal_basis(self, degree=None, algorithm='libsingular', Check that this method works over QQbar (:trac:`25351`):: + sage: # needs sage.rings.number_field sage: R.<x,y,z> = QQbar[] sage: I = R.ideal(x^2+y^2+z^2-4, x^2+2*y^2-5, x*z-1) sage: I.normal_basis() @@ -3235,8 +3326,8 @@ def normal_basis(self, degree=None, algorithm='libsingular', Check the option ``algorithm="singular"`` with a weighted term order:: sage: T = TermOrder('wdegrevlex', (1, 2, 3)) - sage: S.<x,y,z> = PolynomialRing(GF(2), order=T) - sage: S.ideal(x^6 + y^3 + z^2).normal_basis(6, algorithm='singular') + sage: S.<x,y,z> = PolynomialRing(GF(2), order=T) # needs sage.rings.finite_rings + sage: S.ideal(x^6 + y^3 + z^2).normal_basis(6, algorithm='singular') # needs sage.rings.finite_rings [x^4*y, x^2*y^2, y^3, x^3*z, x*y*z, z^2] """ from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence @@ -3316,14 +3407,15 @@ def _groebner_basis_macaulay2(self, strategy=None): Over finite fields, Macaulay2 supports different algorithms to compute Grรถbner bases:: + sage: # needs sage.rings.finite_rings sage: R = PolynomialRing(GF(101), 'x', 4) sage: I = sage.rings.ideal.Cyclic(R) - sage: gb1 = I.groebner_basis('macaulay2:gb') # optional - macaulay2 + sage: gb1 = I.groebner_basis('macaulay2:gb') # optional - macaulay2 sage: I = sage.rings.ideal.Cyclic(R) - sage: gb2 = I.groebner_basis('macaulay2:mgb') # optional - macaulay2 + sage: gb2 = I.groebner_basis('macaulay2:mgb') # optional - macaulay2 sage: I = sage.rings.ideal.Cyclic(R) - sage: gb3 = I.groebner_basis('macaulay2:f4') # optional - macaulay2 - sage: gb1 == gb2 == gb3 # optional - macaulay2 + sage: gb3 = I.groebner_basis('macaulay2:f4') # optional - macaulay2 + sage: gb1 == gb2 == gb3 # optional - macaulay2 True TESTS:: @@ -3366,12 +3458,12 @@ def _reduce_using_macaulay2(self, f): """ I = self._macaulay2_() M2 = I.parent() - k = M2('(%r) %% %s'%(f, I.name())) + k = M2('(%r) %% %s' % (f, I.name())) R = self.ring() return R(k) class NCPolynomialIdeal(MPolynomialIdeal_singular_repr, Ideal_nc): - def __init__(self, ring, gens, coerce=True, side = "left"): + def __init__(self, ring, gens, coerce=True, side="left"): r""" Creates a non-commutative polynomial ideal. @@ -3381,26 +3473,33 @@ def __init__(self, ring, gens, coerce=True, side = "left"): - ``gens`` - the generators of this ideal - ``coerce`` (optional - default True) - generators are coerced into the ring before creating the ideal - - ``side`` - optional string, either "left" (default) - or "twosided"; defines whether this ideal is left + - ``side`` - optional string, either ``"left"`` (default) + or ``"twosided"``; defines whether this ideal is left of two-sided. EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = FreeAlgebra(QQ, 3) - sage: H = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) + sage: H = A.g_algebra({y*x: x*y-z, z*x: x*z+2*x, z*y: y*z-2*y}) sage: H.inject_variables() Defining x, y, z - sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) # indirect doctest - sage: I #random - Left Ideal (y^2, x^2, z^2 - 1) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} - sage: sorted(I.gens(),key=str) + sage: I = H.ideal([y^2, x^2, z^2 - H.one()], # indirect doctest + ....: coerce=False) + sage: I # random + Left Ideal (y^2, x^2, z^2 - 1) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(I.gens(), key=str) [x^2, y^2, z^2 - 1] - sage: H.ideal([y^2, x^2, z^2-H.one()], side="twosided") #random - Twosided Ideal (y^2, x^2, z^2 - 1) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} - sage: sorted(H.ideal([y^2, x^2, z^2-H.one()], side="twosided").gens(),key=str) + sage: H.ideal([y^2, x^2, z^2 - H.one()], side="twosided") # random + Twosided Ideal (y^2, x^2, z^2 - 1) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(H.ideal([y^2, x^2, z^2 - H.one()], side="twosided").gens(), + ....: key=str) [x^2, y^2, z^2 - 1] - sage: H.ideal([y^2, x^2, z^2-H.one()], side="right") + sage: H.ideal([y^2, x^2, z^2 - H.one()], side="right") Traceback (most recent call last): ... ValueError: Only left and two-sided ideals are allowed. @@ -3410,7 +3509,7 @@ def __init__(self, ring, gens, coerce=True, side = "left"): raise ValueError("Only left and two-sided ideals are allowed.") Ideal_nc.__init__(self, ring, gens, coerce=coerce, side=side) - def __call_singular(self, cmd, arg = None): + def __call_singular(self, cmd, arg=None): """ Internal function for calling a Singular function. @@ -3425,14 +3524,16 @@ def __call_singular(self, cmd, arg = None): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = FreeAlgebra(QQ, 3) - sage: H = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) + sage: H = A.g_algebra({y*x: x*y-z, z*x: x*z+2*x, z*y: y*z-2*y}) sage: H.inject_variables() Defining x, y, z sage: id = H.ideal(x + y, y + z) - sage: id.std() # indirect doctest # random - Left Ideal (z, y, x) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} - sage: sorted(id.std().gens(),key=str) + sage: id.std() # indirect doctest # random + Left Ideal (z, y, x) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(id.std().gens(), key=str) [x, y, z] """ from sage.libs.singular.function import singular_function @@ -3445,47 +3546,63 @@ def __call_singular(self, cmd, arg = None): @cached_method def std(self): r""" - Computes a GB of the ideal. It is two-sided if and only if the ideal is two-sided. + Compute a GB of the ideal. It is two-sided if and only if the ideal is two-sided. EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = FreeAlgebra(QQ, 3) - sage: H = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) + sage: H = A.g_algebra({y*x: x*y-z, z*x: x*z+2*x, z*y: y*z-2*y}) sage: H.inject_variables() Defining x, y, z - sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) - sage: I.std() #random - Left Ideal (z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} - sage: sorted(I.std().gens(),key=str) + sage: I = H.ideal([y^2, x^2, z^2 - H.one()], coerce=False) + sage: I.std() #random + Left Ideal (z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(I.std().gens(), key=str) [2*x*y - z - 1, x*z + x, x^2, y*z - y, y^2, z^2 - 1] - If the ideal is a left ideal, then std returns a left + If the ideal is a left ideal, then :meth:`std` returns a left Groebner basis. But if it is a two-sided ideal, then - the output of std and :meth:`twostd` coincide:: + the output of :meth:`std` and :meth:`twostd` coincide:: + sage: # needs sage.combinat sage.modules sage: JL = H.ideal([x^3, y^3, z^3 - 4*z]) - sage: JL #random - Left Ideal (x^3, y^3, z^3 - 4*z) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} - sage: sorted(JL.gens(),key=str) + sage: JL #random + Left Ideal (x^3, y^3, z^3 - 4*z) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(JL.gens(), key=str) [x^3, y^3, z^3 - 4*z] - sage: JL.std() #random - Left Ideal (z^3 - 4*z, y*z^2 - 2*y*z, x*z^2 + 2*x*z, 2*x*y*z - z^2 - 2*z, y^3, x^3) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} - sage: sorted(JL.std().gens(),key=str) + sage: JL.std() # random + Left Ideal (z^3 - 4*z, y*z^2 - 2*y*z, + x*z^2 + 2*x*z, 2*x*y*z - z^2 - 2*z, y^3, x^3) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(JL.std().gens(), key=str) [2*x*y*z - z^2 - 2*z, x*z^2 + 2*x*z, x^3, y*z^2 - 2*y*z, y^3, z^3 - 4*z] sage: JT = H.ideal([x^3, y^3, z^3 - 4*z], side='twosided') - sage: JT #random - Twosided Ideal (x^3, y^3, z^3 - 4*z) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} - sage: sorted(JT.gens(),key=str) + sage: JT #random + Twosided Ideal (x^3, y^3, z^3 - 4*z) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(JT.gens(), key=str) [x^3, y^3, z^3 - 4*z] - sage: JT.std() #random - Twosided Ideal (z^3 - 4*z, y*z^2 - 2*y*z, x*z^2 + 2*x*z, y^2*z - 2*y^2, 2*x*y*z - z^2 - 2*z, x^2*z + 2*x^2, y^3, x*y^2 - y*z, x^2*y - x*z - 2*x, x^3) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} - sage: sorted(JT.std().gens(),key=str) - [2*x*y*z - z^2 - 2*z, x*y^2 - y*z, x*z^2 + 2*x*z, x^2*y - x*z - 2*x, x^2*z + 2*x^2, x^3, y*z^2 - 2*y*z, y^2*z - 2*y^2, y^3, z^3 - 4*z] + sage: JT.std() #random + Twosided Ideal (z^3 - 4*z, y*z^2 - 2*y*z, x*z^2 + 2*x*z, + y^2*z - 2*y^2, 2*x*y*z - z^2 - 2*z, x^2*z + 2*x^2, + y^3, x*y^2 - y*z, x^2*y - x*z - 2*x, x^3) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(JT.std().gens(), key=str) + [2*x*y*z - z^2 - 2*z, x*y^2 - y*z, x*z^2 + 2*x*z, x^2*y - x*z - 2*x, + x^2*z + 2*x^2, x^3, y*z^2 - 2*y*z, y^2*z - 2*y^2, y^3, z^3 - 4*z] sage: JT.std() == JL.twostd() True - ALGORITHM: Uses Singular's std command + ALGORITHM: Uses Singular's ``std`` command """ if self.side() == 'twosided': return self.twostd() @@ -3495,25 +3612,31 @@ def std(self): def elimination_ideal(self, variables): r""" Return the elimination ideal of this ideal with respect to the - variables given in "variables". + variables given in ``variables``. EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = FreeAlgebra(QQ, 3) - sage: H = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) + sage: H = A.g_algebra({y*x: x*y-z, z*x: x*z+2*x, z*y: y*z-2*y}) sage: H.inject_variables() Defining x, y, z - sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) + sage: I = H.ideal([y^2, x^2, z^2 - H.one()], coerce=False) sage: I.elimination_ideal([x, z]) - Left Ideal (y^2) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {...} - sage: J = I.twostd() - sage: J - Twosided Ideal (z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {...} + Left Ideal (y^2) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {...} + sage: J = I.twostd(); J + Twosided Ideal (z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {...} sage: J.elimination_ideal([x, z]) - Twosided Ideal (y^2) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {...} + Twosided Ideal (y^2) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {...} - ALGORITHM: Uses Singular's eliminate command + ALGORITHM: Uses Singular's ``eliminate`` command """ from sage.misc.misc_c import prod if self.side() == 'twosided': @@ -3526,21 +3649,23 @@ def elimination_ideal(self, variables): @cached_method def twostd(self): r""" - Computes a two-sided GB of the ideal (even if it is a left ideal). + Compute a two-sided GB of the ideal (even if it is a left ideal). EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = FreeAlgebra(QQ, 3) - sage: H = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) + sage: H = A.g_algebra({y*x: x*y-z, z*x: x*z+2*x, z*y: y*z-2*y}) sage: H.inject_variables() Defining x, y, z - sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) - sage: I.twostd() #random - Twosided Ideal (z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field... - sage: sorted(I.twostd().gens(),key=str) + sage: I = H.ideal([y^2, x^2, z^2 - H.one()], coerce=False) + sage: I.twostd() #random + Twosided Ideal (z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field... + sage: sorted(I.twostd().gens(), key=str) [2*x*y - z - 1, x*z + x, x^2, y*z - y, y^2, z^2 - 1] - ALGORITHM: Uses Singular's twostd command + ALGORITHM: Uses Singular's ``twostd`` command """ return self.ring().ideal( self.__call_singular('twostd'), side='twosided') # return self.__call_singular('twostd') @@ -3556,13 +3681,14 @@ def _groebner_strategy(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = FreeAlgebra(QQ, 3) - sage: H.<x,y,z> = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) - sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) - sage: I._groebner_strategy() #random + sage: H.<x,y,z> = A.g_algebra({y*x: x*y-z, z*x: x*z+2*x, z*y: y*z-2*y}) + sage: I = H.ideal([y^2, x^2, z^2-H.one()], coerce=False) + sage: I._groebner_strategy() # random Groebner Strategy for ideal generated by 6 elements over - Noncommutative Multivariate Polynomial Ring in x, y, z over Rational - Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} .. NOTE:: @@ -3578,31 +3704,30 @@ def reduce(self,p): It returns 0 if and only if the element is in this ideal. In any case, this reduction is unique up to monomial orders. - NOTE: - - There are left and two-sided ideals. Hence, - EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = FreeAlgebra(QQ, 3) - sage: H.<x,y,z> = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) - sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False, side='twosided') - sage: Q = H.quotient(I); Q #random - Quotient of Noncommutative Multivariate Polynomial Ring in x, y, z - over Rational Field, nc-relations: {z*x: x*z + 2*x, - z*y: y*z - 2*y, y*x: x*y - z} by the ideal (y^2, x^2, z^2 - 1) + sage: H.<x,y,z> = A.g_algebra({y*x: x*y-z, z*x: x*z+2*x, z*y: y*z-2*y}) + sage: I = H.ideal([y^2, x^2, z^2 - H.one()], + ....: coerce=False, side='twosided') + sage: Q = H.quotient(I); Q #random + Quotient of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + by the ideal (y^2, x^2, z^2 - 1) sage: Q.2^2 == Q.one() # indirect doctest True Here, we see that the relation that we just found in the quotient is actually a consequence of the given relations:: - sage: H.2^2-H.one() in I.std().gens() + sage: H.2^2 - H.one() in I.std().gens() # needs sage.combinat sage.modules True Here is the corresponding direct test:: - sage: I.reduce(z^2) + sage: I.reduce(z^2) # needs sage.combinat sage.modules 1 """ @@ -3614,21 +3739,27 @@ def _contains_(self,p): We define a left and a two-sided ideal:: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = FreeAlgebra(QQ, 3) - sage: H.<x,y,z> = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) + sage: H.<x,y,z> = A.g_algebra({y*x: x*y-z, z*x: x*z+2*x, z*y: y*z-2*y}) sage: JL = H.ideal([x^3, y^3, z^3 - 4*z]) - sage: JL.std() #random - Left Ideal (z^3 - 4*z, y*z^2 - 2*y*z, x*z^2 + 2*x*z, 2*x*y*z - z^2 - 2*z, y^3, x^3) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: JL.std() #random + Left Ideal (z^3 - 4*z, y*z^2 - 2*y*z, x*z^2 + 2*x*z, 2*x*y*z - z^2 - 2*z, y^3, x^3) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} sage: JT = H.ideal([x^3, y^3, z^3 - 4*z], side='twosided') - sage: JT.std() #random - Twosided Ideal (z^3 - 4*z, y*z^2 - 2*y*z, x*z^2 + 2*x*z, y^2*z - 2*y^2, 2*x*y*z - z^2 - 2*z, x^2*z + 2*x^2, y^3, x*y^2 - y*z, x^2*y - x*z - 2*x, x^3) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: JT.std() #random + Twosided Ideal (z^3 - 4*z, y*z^2 - 2*y*z, x*z^2 + 2*x*z, y^2*z - 2*y^2, 2*x*y*z - z^2 - 2*z, + x^2*z + 2*x^2, y^3, x*y^2 - y*z, x^2*y - x*z - 2*x, x^3) of + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} Apparently, ``x*y^2-y*z`` should be in the two-sided, but not in the left ideal:: - sage: x*y^2-y*z in JL #indirect doctest + sage: x*y^2-y*z in JL #indirect doctest # needs sage.combinat sage.modules False - sage: x*y^2-y*z in JT + sage: x*y^2-y*z in JT # needs sage.combinat sage.modules True """ @@ -3637,7 +3768,7 @@ def _contains_(self,p): @require_field def syzygy_module(self): r""" - Computes the first syzygy (i.e., the module of relations of the + Compute the first syzygy (i.e., the module of relations of the given generators) of the ideal. NOTE: @@ -3648,11 +3779,12 @@ def syzygy_module(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = FreeAlgebra(QQ, 3) - sage: H = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) + sage: H = A.g_algebra({y*x: x*y-z, z*x: x*z+2*x, z*y: y*z-2*y}) sage: H.inject_variables() Defining x, y, z - sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) + sage: I = H.ideal([y^2, x^2, z^2-H.one()], coerce=False) sage: G = vector(I.gens()); G d...: UserWarning: You are constructing a free module over a noncommutative ring. Sage does not have a concept @@ -3676,10 +3808,10 @@ def syzygy_module(self): [ x^4*z + 4*x^4 -x^2*y^2*z + 4*x^2*y^2 - 4*x*y*z^2 + 32*x*y*z - 6*z^3 - 64*x*y + 66*z^2 - 240*z + 288 0] [x^3*y^2*z + 4*x^3*y^2 + 18*x^2*y*z - 36*x*z^3 + 66*x^2*y - 432*x*z^2 - 1656*x*z - 2052*x -x*y^4*z + 4*x*y^4 - 8*y^3*z^2 + 62*y^3*z - 114*y^3 48*y*z^2 - 36*y*z] - sage: M*G + sage: M*G # needs sage.combinat sage.modules (0, 0, 0, 0, 0, 0, 0, 0, 0) - ALGORITHM: Uses Singular's syz command + ALGORITHM: Uses Singular's ``syz`` command """ if self.side() == 'twosided': warn("The result of this Syzygy computation is one-sided (left)!") @@ -3703,11 +3835,12 @@ def res(self, length): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: A.<x,y,z> = FreeAlgebra(QQ, 3) - sage: H = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) + sage: H = A.g_algebra({y*x: x*y-z, z*x: x*z+2*x, z*y: y*z-2*y}) sage: H.inject_variables() Defining x, y, z - sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) + sage: I = H.ideal([y^2, x^2, z^2-H.one()], coerce=False) sage: I.res(3) <Resolution> """ @@ -3717,10 +3850,10 @@ def res(self, length): @richcmp_method -class MPolynomialIdeal( MPolynomialIdeal_singular_repr, \ - MPolynomialIdeal_macaulay2_repr, \ - MPolynomialIdeal_magma_repr, \ - Ideal_generic ): +class MPolynomialIdeal(MPolynomialIdeal_singular_repr, + MPolynomialIdeal_macaulay2_repr, + MPolynomialIdeal_magma_repr, + Ideal_generic): def __init__(self, ring, gens, coerce=True): r""" Create an ideal in a multivariate polynomial ring. @@ -3731,7 +3864,7 @@ def __init__(self, ring, gens, coerce=True): - ``gens`` - a list of generators for the ideal - - ``coerce`` - coerce elements to the ring ``ring``? + - ``coerce`` - whether to coerce elements to the ring ``ring`` EXAMPLES:: @@ -3766,7 +3899,7 @@ def gens(self): EXAMPLES:: sage: P.<x,y> = PolynomialRing(QQ,2) - sage: I = Ideal([x,y+1]); I + sage: I = Ideal([x, y + 1]); I Ideal (x, y + 1) of Multivariate Polynomial Ring in x, y over Rational Field sage: I.gens() [x, y + 1] @@ -3782,7 +3915,7 @@ def basis(self): EXAMPLES:: sage: P.<x,y> = PolynomialRing(QQ,2) - sage: I = Ideal([x,y+1]) + sage: I = Ideal([x, y + 1]) sage: I.basis [x, y + 1] @@ -3825,6 +3958,7 @@ def __richcmp__(self, other, op): :: + sage: # needs sage.rings.finite_rings sage: R.<x,y> = GF(32003)[] sage: I = R*[x^2 + x, y] sage: J = R*[x + 1, y] @@ -3835,6 +3969,7 @@ def __richcmp__(self, other, op): :: + sage: # needs sage.rings.finite_rings sage: R.<x,y> = GF(32003)[] sage: I = R*[x^2 + x, y] sage: J = R*[x + 1, y] @@ -3859,8 +3994,8 @@ def __richcmp__(self, other, op): :: sage: R.<x,y> = QQ[] - sage: I = (x^3 + y, y)*R - sage: J = (x^3 + y, y, y*x^3 + y^2)*R + sage: I = (x^3 + y, y) * R + sage: J = (x^3 + y, y, y*x^3 + y^2) * R sage: I == J True @@ -3878,6 +4013,7 @@ def __richcmp__(self, other, op): We test to make sure that pickling works with the cached Groebner basis:: + sage: # needs sage.rings.finite_rings sage: R.<x,y> = GF(32003)[] sage: I = R*[x^2 + x, y] sage: J = R*[x + 1, y] @@ -3886,7 +4022,7 @@ def __richcmp__(self, other, op): sage: I >= J False - sage: loads(dumps(I)).__getstate__() + sage: loads(dumps(I)).__getstate__() # needs sage.rings.finite_rings (Monoid of ideals of Multivariate Polynomial Ring in x, y over Finite Field of size 32003, {'_Ideal_generic__gens': (x^2 + x, y), '_Ideal_generic__ring': Multivariate Polynomial Ring in x, y over Finite Field of size 32003, @@ -4060,7 +4196,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal INPUT: - ``algorithm`` - determines the algorithm to use, see below - for available algorithms. + for available algorithms. - ``deg_bound`` - only compute to degree ``deg_bound``, that is, ignore all S-polynomials of higher degree. (default: @@ -4080,78 +4216,77 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal :func:`set_verbose`. - ``*args`` - additional parameters passed to the respective - implementations + implementations - ``**kwds`` - additional keyword parameters passed to the - respective implementations + respective implementations ALGORITHMS: - '' + ``''`` autoselect (default) - 'singular:groebner' + ``'singular:groebner'`` Singular's ``groebner`` command - 'singular:std' + ``'singular:std'`` Singular's ``std`` command - 'singular:stdhilb' + ``'singular:stdhilb'`` Singular's ``stdhib`` command - 'singular:stdfglm' + ``'singular:stdfglm'`` Singular's ``stdfglm`` command - 'singular:slimgb' + ``'singular:slimgb'`` Singular's ``slimgb`` command - 'libsingular:groebner' + ``'libsingular:groebner'`` libSingular's ``groebner`` command - 'libsingular:std' + ``'libsingular:std'`` libSingular's ``std`` command - 'libsingular:slimgb' + ``'libsingular:slimgb'`` libSingular's ``slimgb`` command - 'libsingular:stdhilb' + ``'libsingular:stdhilb'`` libSingular's ``stdhib`` command - 'libsingular:stdfglm' + ``'libsingular:stdfglm'`` libSingular's ``stdfglm`` command - 'toy:buchberger' + ``'toy:buchberger'`` Sage's toy/educational buchberger without Buchberger criteria - 'toy:buchberger2' + ``'toy:buchberger2'`` Sage's toy/educational buchberger with Buchberger criteria - 'toy:d_basis' + ``'toy:d_basis'`` Sage's toy/educational algorithm for computation over PIDs - 'macaulay2:gb' + ``'macaulay2:gb'`` Macaulay2's ``gb`` command (if available) - 'macaulay2:f4' + ``'macaulay2:f4'`` Macaulay2's ``GroebnerBasis`` command with the strategy "F4" (if available) - 'macaulay2:mgb' + ``'macaulay2:mgb'`` Macaulay2's ``GroebnerBasis`` command with the strategy "MGB" (if available) - 'msolve' - `optional package msolve <../spkg/msolve.html>`_ (degrevlex order, - prime fields) + ``'msolve'`` + `optional package msolve <../spkg/msolve.html>`_ (degrevlex order) - 'magma:GroebnerBasis' + ``'magma:GroebnerBasis'`` Magma's ``Groebnerbasis`` command (if available) - 'ginv:TQ', 'ginv:TQBlockHigh', 'ginv:TQBlockLow' and 'ginv:TQDegree' + ``'ginv:TQ'``, ``'ginv:TQBlockHigh'``, ``'ginv:TQBlockLow'`` and ``'ginv:TQDegree'`` One of GINV's implementations (if available) - 'giac:gbasis' + ``'giac:gbasis'`` Giac's ``gbasis`` command (if available) - If only a system is given - e.g. 'magma' - the default algorithm is + If only a system is given - e.g. ``'magma'`` - the default algorithm is chosen for that system. .. NOTE:: @@ -4159,7 +4294,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal The Singular and libSingular versions of the respective algorithms are identical, but the former calls an external Singular process while the latter calls a C function, - i.e. the calling overhead is smaller. However, the + and thus the calling overhead is smaller. However, the libSingular interface does not support pretty printing of computation protocols. @@ -4172,37 +4307,37 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal :: sage: P.<a,b,c> = PolynomialRing(QQ,3, order='lex') - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis() [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:groebner') [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:std') [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:stdhilb') [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:stdfglm') [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:slimgb') [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] @@ -4210,22 +4345,22 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal reverse lexicographical ordering here, in order to test against :trac:`21884`:: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: J = I.change_ring(P.change_ring(order='degrevlex')) - sage: gb = J.groebner_basis('giac') # random + sage: gb = J.groebner_basis('giac') # random sage: gb [c^3 - 79/210*c^2 + 1/30*b + 1/70*c, b^2 - 3/5*c^2 - 1/5*b + 1/5*c, b*c + 6/5*c^2 - 1/10*b - 2/5*c, a + 2*b + 2*c - 1] sage: J.groebner_basis.set_cache(gb) - sage: ideal(J.transformed_basis()).change_ring(P).interreduced_basis() # testing trac 21884 + sage: ideal(J.transformed_basis()).change_ring(P).interreduced_basis() # testing issue #21884 ...[a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] Giac's gbasis over `\QQ` can benefit from a probabilistic lifting and multi threaded operations:: - sage: A9=PolynomialRing(QQ,9,'x') - sage: I9=sage.rings.ideal.Katsura(A9) - sage: print("possible output from giac", flush=True); I9.groebner_basis("giac",proba_epsilon=1e-7) # long time (3s) + sage: A9 = PolynomialRing(QQ, 9, 'x') + sage: I9 = sage.rings.ideal.Katsura(A9) + sage: print("possible output from giac", flush=True); I9.groebner_basis("giac", proba_epsilon=1e-7) # long time (3s) possible output... Polynomial Sequence with 143 Polynomials in 9 Variables @@ -4234,7 +4369,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal Note that ``toy:buchberger`` does not return the reduced Groebner basis, :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: gb = I.groebner_basis('toy:buchberger') sage: gb.is_groebner() True @@ -4243,7 +4378,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal but that ``toy:buchberger2`` does. :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: gb = I.groebner_basis('toy:buchberger2'); gb [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] sage: gb == gb.reduced() @@ -4252,41 +4387,45 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal Here we use Macaulay2 with three different strategies over a finite field. :: + sage: # optional - macaulay2 sage: R.<a,b,c> = PolynomialRing(GF(101), 3) - sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching - sage: I.groebner_basis('macaulay2:gb') # optional - macaulay2 - [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] - - sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching - sage: I.groebner_basis('macaulay2:f4') # optional - macaulay2 - [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] - - sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching - sage: I.groebner_basis('macaulay2:mgb') # optional - macaulay2 - [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('macaulay2:gb') + [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, + b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('macaulay2:f4') + [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, + b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('macaulay2:mgb') + [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, + b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] Over prime fields of small characteristic, we can also use the `optional package msolve <../spkg/msolve.html>`_:: sage: R.<a,b,c> = PolynomialRing(GF(101), 3) - sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching - sage: I.groebner_basis('msolve') # optional - msolve - [a + 2*b + 2*c - 1, b*c - 19*c^2 + 10*b + 40*c, b^2 - 41*c^2 + 20*b - 20*c, c^3 + 28*c^2 - 37*b + 13*c] + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('msolve') # optional - msolve + [a + 2*b + 2*c - 1, b*c - 19*c^2 + 10*b + 40*c, + b^2 - 41*c^2 + 20*b - 20*c, c^3 + 28*c^2 - 37*b + 13*c] :: - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching - sage: I.groebner_basis('magma:GroebnerBasis') # optional - magma - [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('magma:GroebnerBasis') # optional - magma + [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, + b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] Singular and libSingular can compute Groebner basis with degree restrictions. :: sage: R.<x,y> = QQ[] - sage: I = R*[x^3+y^2,x^2*y+1] + sage: I = R*[x^3 + y^2, x^2*y + 1] sage: I.groebner_basis(algorithm='singular') [x^3 + y^2, x^2*y + 1, y^3 - x] - sage: I.groebner_basis(algorithm='singular',deg_bound=2) + sage: I.groebner_basis(algorithm='singular', deg_bound=2) [x^3 + y^2, x^2*y + 1] sage: I.groebner_basis() [x^3 + y^2, x^2*y + 1, y^3 - x] @@ -4338,7 +4477,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal :: - sage: I.groebner_basis('macaulay2') # optional - macaulay2 + sage: I.groebner_basis('macaulay2') # optional - macaulay2 [b^3 + b*c^2 + 12*c^3 + b^2 + b*c - 4*c^2, 2*b*c^2 - 6*c^3 + b^2 + 5*b*c + 8*c^2 - b - 2*c, 42*c^3 + b^2 + 2*b*c - 14*c^2 + b, @@ -4347,7 +4486,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal Groebner bases over `\ZZ/n\ZZ` are also supported:: - sage: P.<a,b,c> = PolynomialRing(Zmod(1000),3) + sage: P.<a,b,c> = PolynomialRing(Zmod(1000), 3) sage: I = P * (a + 2*b + 2*c - 1, a^2 - a + 2*b^2 + 2*c^2, 2*a*b + 2*b*c - b) sage: I.groebner_basis() [b*c^2 + 732*b*c + 808*b, @@ -4368,23 +4507,23 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal Sage also supports local orderings:: - sage: P.<x,y,z> = PolynomialRing(QQ,3,order='negdegrevlex') - sage: I = P * ( x*y*z + z^5, 2*x^2 + y^3 + z^7, 3*z^5 +y ^5 ) + sage: P.<x,y,z> = PolynomialRing(QQ, 3, order='negdegrevlex') + sage: I = P * ( x*y*z + z^5, 2*x^2 + y^3 + z^7, 3*z^5 + y^5 ) sage: I.groebner_basis() [x^2 + 1/2*y^3, x*y*z + z^5, y^5 + 3*z^5, y^4*z - 2*x*z^5, z^6] We can represent every element in the ideal as a combination of the generators using the :meth:`~sage.rings.polynomial.multi_polynomial_element.MPolynomial_polydict.lift` method:: - sage: P.<x,y,z> = PolynomialRing(QQ,3) - sage: I = P * ( x*y*z + z^5, 2*x^2 + y^3 + z^7, 3*z^5 +y ^5 ) + sage: P.<x,y,z> = PolynomialRing(QQ, 3) + sage: I = P * ( x*y*z + z^5, 2*x^2 + y^3 + z^7, 3*z^5 + y^5 ) sage: J = Ideal(I.groebner_basis()) sage: f = sum(P.random_element(terms=2)*f for f in I.gens()) - sage: f # random + sage: f # random 1/2*y^2*z^7 - 1/4*y*z^8 + 2*x*z^5 + 95*z^6 + 1/2*y^5 - 1/4*y^4*z + x^2*y^2 + 3/2*x^2*y*z + 95*x*y*z^2 - sage: f.lift(I.gens()) # random + sage: f.lift(I.gens()) # random [2*x + 95*z, 1/2*y^2 - 1/4*y*z, 0] - sage: l = f.lift(J.gens()); l # random + sage: l = f.lift(J.gens()); l # random [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1/2*y^2 + 1/4*y*z, 1/2*y^2*z^2 - 1/4*y*z^3 + 2*x + 95*z] sage: sum(map(mul, zip(l,J.gens()))) == f True @@ -4449,54 +4588,50 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal Check that this method works over QQbar (:trac:`25351`):: - sage: P.<a,b,c> = PolynomialRing(QQbar,3, order='lex') - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: # needs sage.rings.number_field + sage: P.<a,b,c> = PolynomialRing(QQbar, 3, order='lex') + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis() [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:groebner') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:std') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:stdhilb') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:stdfglm') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('libsingular:slimgb') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: # needs sage.rings.number_field + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: J = I.change_ring(P.change_ring(order='degrevlex')) - sage: gb = J.groebner_basis('giac') # random + sage: gb = J.groebner_basis('giac') # random sage: gb [c^3 + (-79/210)*c^2 + 1/30*b + 1/70*c, b^2 + (-3/5)*c^2 + (-1/5)*b + 1/5*c, b*c + 6/5*c^2 + (-1/10)*b + (-2/5)*c, a + 2*b + 2*c - 1] - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: # needs sage.rings.number_field + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('toy:buchberger2') [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching - sage: I.groebner_basis('macaulay2:gb') # optional - macaulay2 + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('macaulay2:gb') # optional - macaulay2 [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] - - sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching - sage: I.groebner_basis('magma:GroebnerBasis') # optional - magma + sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching + sage: I.groebner_basis('magma:GroebnerBasis') # optional - magma [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] msolve currently supports the degrevlex order only:: sage: R.<a,b,c> = PolynomialRing(GF(101), 3, order='lex') - sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching - sage: I.groebner_basis('msolve') # optional - msolve + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('msolve') # optional - msolve Traceback (most recent call last): ... NotImplementedError: msolve only supports the degrevlex order (use transformed_basis()) @@ -4520,10 +4655,10 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal if not algorithm: try: gb = self._groebner_basis_libsingular("groebner", deg_bound=deg_bound, mult_bound=mult_bound, *args, **kwds) - except (TypeError, NameError): # conversion to Singular not supported + except (TypeError, NameError, ImportError): # conversion to Singular not supported try: gb = self._groebner_basis_singular("groebner", deg_bound=deg_bound, mult_bound=mult_bound, *args, **kwds) - except (TypeError, NameError, NotImplementedError): # conversion to Singular not supported + except (TypeError, NameError, NotImplementedError, ImportError): # conversion to Singular not supported R = self.ring() B = R.base_ring() if R.ngens() == 0: @@ -4581,7 +4716,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal ginv,alg = algorithm.split(":") gb = self._groebner_basis_ginv(algorithm=alg,*args, **kwds) else: - raise NameError("Algorithm '%s' unknown."%algorithm) + raise NameError("Algorithm '%s' unknown." % algorithm) elif algorithm == 'giac:gbasis': from sage.libs.giac import groebner_basis as groebner_basis_libgiac gb = groebner_basis_libgiac(self, prot=prot, *args, **kwds) @@ -4594,7 +4729,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal from . import msolve return msolve.groebner_basis_degrevlex(self, *args, **kwds) else: - raise NameError("Algorithm '%s' unknown."%algorithm) + raise NameError("Algorithm '%s' unknown." % algorithm) gb = sorted(gb, reverse=True) if self.ring().base_ring().is_field(): @@ -4628,18 +4763,22 @@ def groebner_cover(self): sage: R.<x,y,z> = F[] sage: I = R.ideal([-x+3*y+z-5,2*x+a*z+4,4*x-3*z-1/a]) sage: I.groebner_cover() - {Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, where X is defined by: - 0 - and Y is defined by: - 2*a^2 + 3*a: [(2*a^2 + 3*a)*z + (8*a + 1), (12*a^2 + 18*a)*y + (-20*a^2 - 35*a - 2), (4*a + 6)*x + 11], - Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, where X is defined by: - ... - and Y is defined by: - 1: [1], - Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, where X is defined by: - ... - and Y is defined by: - 1: [1]} + {Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, + where X is defined by: + 0 + and Y is defined by: + 2*a^2 + 3*a: [(2*a^2 + 3*a)*z + (8*a + 1), + (12*a^2 + 18*a)*y + (-20*a^2 - 35*a - 2), (4*a + 6)*x + 11], + Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, + where X is defined by: + ... + and Y is defined by: + 1: [1], + Quasi-affine subscheme X - Y of Affine Space of dimension 1 over Rational Field, + where X is defined by: + ... + and Y is defined by: + 1: [1]} """ from sage.schemes.affine.affine_space import AffineSpace gc = self._groebner_cover() @@ -4718,43 +4857,49 @@ def subs(self, in_dict=None, **kwds): OUTPUT: A new ideal with modified generators. If possible, in the same - polynomial ring. Raises a ``TypeError`` if no common + polynomial ring. Raises a :class:`TypeError` if no common polynomial ring of the substituted generators can be found. EXAMPLES:: - sage: R.<x,y> = PolynomialRing(ZZ,2,'xy') - sage: I = R.ideal(x^5+y^5, x^2 + y + x^2*y^2 + 5); I - Ideal (x^5 + y^5, x^2*y^2 + x^2 + y + 5) of Multivariate Polynomial Ring in x, y over Integer Ring + sage: R.<x,y> = PolynomialRing(ZZ, 2, 'xy') + sage: I = R.ideal(x^5 + y^5, x^2 + y + x^2*y^2 + 5); I + Ideal (x^5 + y^5, x^2*y^2 + x^2 + y + 5) + of Multivariate Polynomial Ring in x, y over Integer Ring sage: I.subs(x=y) - Ideal (2*y^5, y^4 + y^2 + y + 5) of Multivariate Polynomial Ring in x, y over Integer Ring - sage: I.subs({x:y}) # same substitution but with dictionary - Ideal (2*y^5, y^4 + y^2 + y + 5) of Multivariate Polynomial Ring in x, y over Integer Ring + Ideal (2*y^5, y^4 + y^2 + y + 5) + of Multivariate Polynomial Ring in x, y over Integer Ring + sage: I.subs({x: y}) # same substitution but with dictionary + Ideal (2*y^5, y^4 + y^2 + y + 5) + of Multivariate Polynomial Ring in x, y over Integer Ring The new ideal can be in a different ring:: - sage: R.<a,b> = PolynomialRing(QQ,2) - sage: S.<x,y> = PolynomialRing(QQ,2) - sage: I = R.ideal(a^2+b^2+a-b+2); I - Ideal (a^2 + b^2 + a - b + 2) of Multivariate Polynomial Ring in a, b over Rational Field + sage: R.<a,b> = PolynomialRing(QQ, 2) + sage: S.<x,y> = PolynomialRing(QQ, 2) + sage: I = R.ideal(a^2 + b^2 + a - b + 2); I + Ideal (a^2 + b^2 + a - b + 2) + of Multivariate Polynomial Ring in a, b over Rational Field sage: I.subs(a=x, b=y) - Ideal (x^2 + y^2 + x - y + 2) of Multivariate Polynomial Ring in x, y over Rational Field + Ideal (x^2 + y^2 + x - y + 2) + of Multivariate Polynomial Ring in x, y over Rational Field The resulting ring need not be a multivariate polynomial ring:: sage: T.<t> = PolynomialRing(QQ) sage: I.subs(a=t, b=t) Principal ideal (t^2 + 1) of Univariate Polynomial Ring in t over Rational Field - sage: var("z") + sage: var("z") # needs sage.symbolic z - sage: I.subs(a=z, b=z) + sage: I.subs(a=z, b=z) # needs sage.symbolic Principal ideal (2*z^2 + 2) of Symbolic Ring Variables that are not substituted remain unchanged:: - sage: R.<x,y> = PolynomialRing(QQ,2) - sage: I = R.ideal(x^2+y^2+x-y+2); I - Ideal (x^2 + y^2 + x - y + 2) of Multivariate Polynomial Ring in x, y over Rational Field + sage: R.<x,y> = PolynomialRing(QQ, 2) + sage: I = R.ideal(x^2 + y^2 + x - y + 2); I + Ideal (x^2 + y^2 + x - y + 2) + of Multivariate Polynomial Ring in x, y over Rational Field sage: I.subs(x=1) Ideal (y^2 - y + 4) of Multivariate Polynomial Ring in x, y over Rational Field """ @@ -4776,7 +4921,7 @@ def reduce(self, f): EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ, 2) - sage: I = (x^3 + y, y)*R + sage: I = (x^3 + y, y) * R sage: I.reduce(y) 0 sage: I.reduce(x^3) @@ -4784,7 +4929,7 @@ def reduce(self, f): sage: I.reduce(x - y) x - sage: I = (y^2 - (x^3 + x))*R + sage: I = (y^2 - (x^3 + x)) * R sage: I.reduce(x^3) y^2 - x sage: I.reduce(x^6) @@ -4814,8 +4959,8 @@ def _contains_(self, f): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: I = (x^3 + y, y)*R - sage: x in I # indirect doctest + sage: I = (x^3 + y, y) * R + sage: x in I # indirect doctest False sage: y in I True @@ -4863,7 +5008,7 @@ def homogenize(self, var='h'): :: - sage: I = Ideal([x^2*y + z^3 + y^2*x, x + y^2 + 1]) + sage: I = Ideal([x^2*y + z^3 + y^2*x, x + y^2 + 1]) sage: I.homogenize() Ideal (x^2*y + x*y^2 + z^3, y^2 + x*h + h^2) of Multivariate Polynomial Ring in x, y, z, h over Finite @@ -4876,7 +5021,7 @@ def homogenize(self, var='h'): def is_homogeneous(self): r""" Return ``True`` if this ideal is spanned by homogeneous - polynomials, i.e. if it is a homogeneous ideal. + polynomials, i.e., if it is a homogeneous ideal. EXAMPLES:: @@ -4941,11 +5086,11 @@ def degree_of_semi_regularity(self): sage: n = 8 sage: K = GF(127) - sage: P = PolynomialRing(K,n,'x') + sage: P = PolynomialRing(K, n, 'x') sage: s = [K.random_element() for _ in range(n)] sage: L = [] - sage: for i in range(2*n): - ....: f = P.random_element(degree=2, terms=binomial(n,2)) + sage: for i in range(2 * n): + ....: f = P.random_element(degree=2, terms=binomial(n, 2)) ....: f -= f(*s) ....: L.append(f.homogenize()) sage: I = Ideal(L) @@ -4962,8 +5107,8 @@ def degree_of_semi_regularity(self): We increase the number of polynomials and observe a decrease the degree of regularity:: - sage: for i in range(2*n): - ....: f = P.random_element(degree=2, terms=binomial(n,2)) + sage: for i in range(2 * n): + ....: f = P.random_element(degree=2, terms=binomial(n, 2)) ....: f -= f(*s) ....: L.append(f.homogenize()) sage: I = Ideal(L) @@ -4976,8 +5121,8 @@ def degree_of_semi_regularity(self): The degree of regularity approaches 2 for quadratic systems as the number of polynomials approaches `n^2`:: - sage: for i in range((n-4)*n): - ....: f = P.random_element(degree=2, terms=binomial(n,2)) + sage: for i in range((n-4) * n): + ....: f = P.random_element(degree=2, terms=binomial(n, 2)) ....: f -= f(*s) ....: L.append(f.homogenize()) sage: I = Ideal(L) @@ -4994,7 +5139,7 @@ def degree_of_semi_regularity(self): semi-regular sequences. For more details about semi-regular sequences see [BFS2004]_. """ - degs = [f.degree() for f in self.gens() if f!=0] # we ignore zeroes + degs = [f.degree() for f in self.gens() if f != 0] # we ignore zeroes m, n = self.ngens(), len(set(sum([f.variables() for f in self.gens()],()))) if m <= n: raise ValueError("This function requires an overdefined system of polynomials.") @@ -5019,59 +5164,59 @@ def plot(self, *args, **kwds): - ``self`` - a principal ideal in 2 variables - ``algorithm`` - set this to 'surf' if you want 'surf' to - plot the ideal (default: None) + plot the ideal (default: None) - ``*args`` - optional tuples ``(variable, minimum, maximum)`` - for plotting dimensions + for plotting dimensions - ``**kwds`` - optional keyword arguments passed on to - ``implicit_plot`` + ``implicit_plot`` EXAMPLES: Implicit plotting in 2-d:: - sage: R.<x,y> = PolynomialRing(QQ,2) + sage: R.<x,y> = PolynomialRing(QQ, 2) sage: I = R.ideal([y^3 - x^2]) - sage: I.plot() # cusp + sage: I.plot() # cusp # needs sage.plot Graphics object consisting of 1 graphics primitive :: sage: I = R.ideal([y^2 - x^2 - 1]) - sage: I.plot((x,-3, 3), (y, -2, 2)) # hyperbola + sage: I.plot((x,-3, 3), (y, -2, 2)) # hyperbola # needs sage.plot Graphics object consisting of 1 graphics primitive :: sage: I = R.ideal([y^2 + x^2*(1/4) - 1]) - sage: I.plot() # ellipse + sage: I.plot() # ellipse # needs sage.plot Graphics object consisting of 1 graphics primitive :: sage: I = R.ideal([y^2-(x^2-1)*(x-2)]) - sage: I.plot() # elliptic curve + sage: I.plot() # elliptic curve # needs sage.plot Graphics object consisting of 1 graphics primitive :: sage: f = ((x+3)^3 + 2*(x+3)^2 - y^2)*(x^3 - y^2)*((x-3)^3-2*(x-3)^2-y^2) sage: I = R.ideal(f) - sage: I.plot() # the Singular logo + sage: I.plot() # the Singular logo # needs sage.plot Graphics object consisting of 1 graphics primitive :: - sage: R.<x,y> = PolynomialRing(QQ,2) + sage: R.<x,y> = PolynomialRing(QQ, 2) sage: I = R.ideal([x - 1]) - sage: I.plot((y, -2, 2)) # vertical line + sage: I.plot((y, -2, 2)) # vertical line # needs sage.plot Graphics object consisting of 1 graphics primitive :: sage: I = R.ideal([-x^2*y + 1]) - sage: I.plot() # blow up + sage: I.plot() # blow up # needs sage.plot Graphics object consisting of 1 graphics primitive """ @@ -5093,7 +5238,7 @@ def plot(self, *args, **kwds): V = [(variables[0], None, None), (variables[1], None, None)] if len(args) > 2: - raise TypeError("Expected up to 2 optional parameters but got %d."%len(args)) + raise TypeError("Expected up to 2 optional parameters but got %d." % len(args)) # first check whether user supplied boundaries for e in args: @@ -5168,23 +5313,26 @@ def random_element(self, degree, compute_gb=False, *args, **kwds): 1. We sample `n^d` uniformly random elements in the ideal:: - sage: F = Sequence(I.random_element(degree=d, compute_gb=True, terms=infinity) for _ in range(n^d)) + sage: F = Sequence(I.random_element(degree=d, compute_gb=True, + ....: terms=infinity) + ....: for _ in range(n^d)) 2. We linearize and compute the echelon form:: - sage: A,v = F.coefficient_matrix() - sage: A.echelonize() + sage: A, v = F.coefficient_matrix() + sage: A.echelonize() 3. The result is the desired Grรถbner basis:: - sage: G = Sequence((A*v).list()) - sage: G.is_groebner() - True - sage: Ideal(G) == I - True + sage: G = Sequence((A * v).list()) + sage: G.is_groebner() + True + sage: Ideal(G) == I + True We return some element in the ideal with no guarantee on the distribution:: + sage: # needs sage.rings.finite_rings sage: P = PolynomialRing(GF(127), 10, 'x') sage: I = sage.rings.ideal.Katsura(P) sage: f = I.random_element(degree=3) @@ -5195,13 +5343,15 @@ def random_element(self, degree, compute_gb=False, *args, **kwds): We show that the default method does not sample uniformly at random from the ideal:: + sage: # needs sage.rings.finite_rings sage: P.<x,y,z> = GF(127)[] - sage: G = Sequence([x+7, y-2, z+110]) - sage: I = Ideal([sum(P.random_element() * g for g in G) for _ in range(4)]) + sage: G = Sequence([x + 7, y - 2, z + 110]) + sage: I = Ideal([sum(P.random_element() * g for g in G) + ....: for _ in range(4)]) sage: all(I.random_element(degree=1) == 0 for _ in range(100)) True - If degree equals the degree of the generators a random linear + If ``degree`` equals the degree of the generators, a random linear combination of the generators is returned:: sage: P.<x,y> = QQ[] @@ -5259,29 +5409,29 @@ def weil_restriction(self): If the input and the output ideals are radical, this is equivalent to the statement about algebraic varieties above. - OUTPUT: MPolynomial Ideal + OUTPUT: :class:`MPolynomialIdeal` EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(2^2) - sage: P.<x,y> = PolynomialRing(k,2) + sage: P.<x,y> = PolynomialRing(k, 2) sage: I = Ideal([x*y + 1, a*x + 1]) sage: I.variety() [{y: a, x: a + 1}] sage: J = I.weil_restriction() sage: J Ideal (x0*y0 + x1*y1 + 1, x1*y0 + x0*y1 + x1*y1, x1 + 1, x0 + x1) of - Multivariate Polynomial Ring in x0, x1, y0, y1 over Finite Field of size - 2 - sage: J += sage.rings.ideal.FieldIdeal(J.ring()) # ensure radical ideal + Multivariate Polynomial Ring in x0, x1, y0, y1 over Finite Field of size 2 + sage: J += sage.rings.ideal.FieldIdeal(J.ring()) # ensure radical ideal sage: J.variety() [{y1: 1, y0: 0, x1: 1, x0: 1}] + sage: J.weil_restriction() # returns J + Ideal (x0*y0 + x1*y1 + 1, x1*y0 + x0*y1 + x1*y1, x1 + 1, x0 + x1, + x0^2 + x0, x1^2 + x1, y0^2 + y0, y1^2 + y1) of Multivariate + Polynomial Ring in x0, x1, y0, y1 over Finite Field of size 2 - sage: J.weil_restriction() # returns J - Ideal (x0*y0 + x1*y1 + 1, x1*y0 + x0*y1 + x1*y1, x1 + 1, x0 + x1, x0^2 + - x0, x1^2 + x1, y0^2 + y0, y1^2 + y1) of Multivariate Polynomial Ring in - x0, x1, y0, y1 over Finite Field of size 2 - + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(3^5) sage: P.<x,y,z> = PolynomialRing(k) sage: I = sage.rings.ideal.Katsura(P) @@ -5289,88 +5439,100 @@ def weil_restriction(self): 0 sage: I.variety() [{z: 0, y: 0, x: 1}] - sage: J = I.weil_restriction(); J - Ideal (x0 - y0 - z0 - 1, x1 - y1 - z1, x2 - y2 - z2, x3 - y3 - z3, x4 - - y4 - z4, x0^2 + x2*x3 + x1*x4 - y0^2 - y2*y3 - y1*y4 - z0^2 - z2*z3 - - z1*z4 - x0, -x0*x1 - x2*x3 - x3^2 - x1*x4 + x2*x4 + y0*y1 + y2*y3 + y3^2 - + y1*y4 - y2*y4 + z0*z1 + z2*z3 + z3^2 + z1*z4 - z2*z4 - x1, x1^2 - - x0*x2 + x3^2 - x2*x4 + x3*x4 - y1^2 + y0*y2 - y3^2 + y2*y4 - y3*y4 - - z1^2 + z0*z2 - z3^2 + z2*z4 - z3*z4 - x2, -x1*x2 - x0*x3 - x3*x4 - x4^2 - + y1*y2 + y0*y3 + y3*y4 + y4^2 + z1*z2 + z0*z3 + z3*z4 + z4^2 - x3, x2^2 - - x1*x3 - x0*x4 + x4^2 - y2^2 + y1*y3 + y0*y4 - y4^2 - z2^2 + z1*z3 + - z0*z4 - z4^2 - x4, -x0*y0 + x4*y1 + x3*y2 + x2*y3 + x1*y4 - y0*z0 + - y4*z1 + y3*z2 + y2*z3 + y1*z4 - y0, -x1*y0 - x0*y1 - x4*y1 - x3*y2 + - x4*y2 - x2*y3 + x3*y3 - x1*y4 + x2*y4 - y1*z0 - y0*z1 - y4*z1 - y3*z2 + - y4*z2 - y2*z3 + y3*z3 - y1*z4 + y2*z4 - y1, -x2*y0 - x1*y1 - x0*y2 - - x4*y2 - x3*y3 + x4*y3 - x2*y4 + x3*y4 - y2*z0 - y1*z1 - y0*z2 - y4*z2 - - y3*z3 + y4*z3 - y2*z4 + y3*z4 - y2, -x3*y0 - x2*y1 - x1*y2 - x0*y3 - - x4*y3 - x3*y4 + x4*y4 - y3*z0 - y2*z1 - y1*z2 - y0*z3 - y4*z3 - y3*z4 + - y4*z4 - y3, -x4*y0 - x3*y1 - x2*y2 - x1*y3 - x0*y4 - x4*y4 - y4*z0 - - y3*z1 - y2*z2 - y1*z3 - y0*z4 - y4*z4 - y4) of Multivariate Polynomial - Ring in x0, x1, x2, x3, x4, y0, y1, y2, y3, y4, z0, z1, z2, z3, z4 over - Finite Field of size 3 - sage: J += sage.rings.ideal.FieldIdeal(J.ring()) # ensure radical ideal + Ideal (x0 - y0 - z0 - 1, + x1 - y1 - z1, x2 - y2 - z2, x3 - y3 - z3, x4 - y4 - z4, + x0^2 + x2*x3 + x1*x4 - y0^2 - y2*y3 - y1*y4 - z0^2 - z2*z3 - z1*z4 - x0, + -x0*x1 - x2*x3 - x3^2 - x1*x4 + x2*x4 + y0*y1 + y2*y3 + + y3^2 + y1*y4 - y2*y4 + z0*z1 + z2*z3 + z3^2 + z1*z4 - z2*z4 - x1, + x1^2 - x0*x2 + x3^2 - x2*x4 + x3*x4 - y1^2 + y0*y2 + - y3^2 + y2*y4 - y3*y4 - z1^2 + z0*z2 - z3^2 + z2*z4 - z3*z4 - x2, + -x1*x2 - x0*x3 - x3*x4 - x4^2 + + y1*y2 + y0*y3 + y3*y4 + y4^2 + z1*z2 + z0*z3 + z3*z4 + z4^2 - x3, + x2^2 - x1*x3 - x0*x4 + x4^2 - y2^2 + + y1*y3 + y0*y4 - y4^2 - z2^2 + z1*z3 + z0*z4 - z4^2 - x4, + -x0*y0 + x4*y1 + x3*y2 + x2*y3 + + x1*y4 - y0*z0 + y4*z1 + y3*z2 + y2*z3 + y1*z4 - y0, + -x1*y0 - x0*y1 - x4*y1 - x3*y2 + x4*y2 - x2*y3 + x3*y3 + - x1*y4 + x2*y4 - y1*z0 - y0*z1 - y4*z1 - y3*z2 + + y4*z2 - y2*z3 + y3*z3 - y1*z4 + y2*z4 - y1, + -x2*y0 - x1*y1 - x0*y2 - x4*y2 - x3*y3 + x4*y3 - x2*y4 + x3*y4 + - y2*z0 - y1*z1 - y0*z2 - y4*z2 - y3*z3 + y4*z3 - y2*z4 + y3*z4 - y2, + -x3*y0 - x2*y1 - x1*y2 - x0*y3 - x4*y3 - x3*y4 + x4*y4 + - y3*z0 - y2*z1 - y1*z2 - y0*z3 - y4*z3 - y3*z4 + y4*z4 - y3, + -x4*y0 - x3*y1 - x2*y2 - x1*y3 - x0*y4 - x4*y4 + - y4*z0 - y3*z1 - y2*z2 - y1*z3 - y0*z4 - y4*z4 - y4) + of Multivariate Polynomial Ring in x0, x1, x2, x3, x4, y0, y1, y2, y3, y4, + z0, z1, z2, z3, z4 over Finite Field of size 3 + sage: J += sage.rings.ideal.FieldIdeal(J.ring()) # ensure radical ideal sage: from sage.doctest.fixtures import reproducible_repr sage: print(reproducible_repr(J.variety())) - [{x0: 1, x1: 0, x2: 0, x3: 0, x4: 0, y0: 0, y1: 0, y2: 0, y3: 0, y4: 0, z0: 0, z1: 0, z2: 0, z3: 0, z4: 0}] + [{x0: 1, x1: 0, x2: 0, x3: 0, x4: 0, + y0: 0, y1: 0, y2: 0, y3: 0, y4: 0, + z0: 0, z1: 0, z2: 0, z3: 0, z4: 0}] Weil restrictions are often used to study elliptic curves over extension fields so we give a simple example involving those:: - sage: K.<a> = QuadraticField(1/3) - sage: E = EllipticCurve(K,[1,2,3,4,5]) + sage: K.<a> = QuadraticField(1/3) # needs sage.rings.number_field + sage: E = EllipticCurve(K, [1,2,3,4,5]) # needs sage.rings.number_field We pick a point on ``E``:: - sage: p = E.lift_x(1); p - (1 : 2 : 1) + sage: p = E.lift_x(1); p # needs sage.rings.number_field + (1 : -6 : 1) - sage: I = E.defining_ideal(); I - Ideal (-x^3 - 2*x^2*z + x*y*z + y^2*z - 4*x*z^2 + 3*y*z^2 - 5*z^3) of Multivariate Polynomial Ring in x, y, z over Number Field in a with defining polynomial x^2 - 1/3 with a = 0.5773502691896258? + sage: I = E.defining_ideal(); I # needs sage.rings.number_field + Ideal (-x^3 - 2*x^2*z + x*y*z + y^2*z - 4*x*z^2 + 3*y*z^2 - 5*z^3) + of Multivariate Polynomial Ring in x, y, z + over Number Field in a with defining polynomial x^2 - 1/3 + with a = 0.5773502691896258? Of course, the point ``p`` is a root of all generators of ``I``:: - sage: I.subs(x=1,y=2,z=1) - Ideal (0) of Multivariate Polynomial Ring in x, y, z over Number Field in a with defining polynomial x^2 - 1/3 with a = 0.5773502691896258? + sage: I.subs(x=1, y=2, z=1) # needs sage.rings.number_field + Ideal (0) of Multivariate Polynomial Ring in x, y, z + over Number Field in a with defining polynomial x^2 - 1/3 + with a = 0.5773502691896258? ``I`` is also radical:: - sage: I.radical() == I + sage: I.radical() == I # needs sage.rings.number_field True So we compute its Weil restriction:: - sage: J = I.weil_restriction() - sage: J - Ideal (-x0^3 - x0*x1^2 - 2*x0^2*z0 - 2/3*x1^2*z0 + x0*y0*z0 + y0^2*z0 + - 1/3*x1*y1*z0 + 1/3*y1^2*z0 - 4*x0*z0^2 + 3*y0*z0^2 - 5*z0^3 - - 4/3*x0*x1*z1 + 1/3*x1*y0*z1 + 1/3*x0*y1*z1 + 2/3*y0*y1*z1 - 8/3*x1*z0*z1 - + 2*y1*z0*z1 - 4/3*x0*z1^2 + y0*z1^2 - 5*z0*z1^2, -3*x0^2*x1 - 1/3*x1^3 - - 4*x0*x1*z0 + x1*y0*z0 + x0*y1*z0 + 2*y0*y1*z0 - 4*x1*z0^2 + 3*y1*z0^2 - - 2*x0^2*z1 - 2/3*x1^2*z1 + x0*y0*z1 + y0^2*z1 + 1/3*x1*y1*z1 + - 1/3*y1^2*z1 - 8*x0*z0*z1 + 6*y0*z0*z1 - 15*z0^2*z1 - 4/3*x1*z1^2 + - y1*z1^2 - 5/3*z1^3) of Multivariate Polynomial Ring in x0, x1, y0, y1, - z0, z1 over Rational Field + sage: J = I.weil_restriction(); J # needs sage.rings.number_field + Ideal (-x0^3 - x0*x1^2 - 2*x0^2*z0 - 2/3*x1^2*z0 + x0*y0*z0 + y0^2*z0 + + 1/3*x1*y1*z0 + 1/3*y1^2*z0 - 4*x0*z0^2 + 3*y0*z0^2 - 5*z0^3 + - 4/3*x0*x1*z1 + 1/3*x1*y0*z1 + 1/3*x0*y1*z1 + 2/3*y0*y1*z1 + - 8/3*x1*z0*z1 + 2*y1*z0*z1 - 4/3*x0*z1^2 + y0*z1^2 - 5*z0*z1^2, + -3*x0^2*x1 - 1/3*x1^3 - 4*x0*x1*z0 + x1*y0*z0 + x0*y1*z0 + + 2*y0*y1*z0 - 4*x1*z0^2 + 3*y1*z0^2 - 2*x0^2*z1 - 2/3*x1^2*z1 + + x0*y0*z1 + y0^2*z1 + 1/3*x1*y1*z1 + 1/3*y1^2*z1 - 8*x0*z0*z1 + + 6*y0*z0*z1 - 15*z0^2*z1 - 4/3*x1*z1^2 + y1*z1^2 - 5/3*z1^3) + of Multivariate Polynomial Ring in x0, x1, y0, y1, z0, z1 over Rational Field We can check that the point ``p`` is still a root of all generators of ``J``:: - sage: J.subs(x0=1,y0=2,z0=1,x1=0,y1=0,z1=0) - Ideal (0, 0) of Multivariate Polynomial Ring in x0, x1, y0, y1, z0, z1 over Rational Field + sage: J.subs(x0=1, y0=2, z0=1, x1=0, y1=0, z1=0) # needs sage.rings.number_field + Ideal (0, 0) of Multivariate Polynomial Ring in x0, x1, y0, y1, z0, z1 + over Rational Field Example for relative number fields:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: K.<w> = NumberField(x^5-2) + sage: K.<w> = NumberField(x^5 - 2) sage: R.<x> = K[] - sage: L.<v> = K.extension(x^2+1) + sage: L.<v> = K.extension(x^2 + 1) sage: S.<x,y> = L[] - sage: I = S.ideal([y^2-x^3-1]) + sage: I = S.ideal([y^2 - x^3 - 1]) sage: I.weil_restriction() - Ideal (-x0^3 + 3*x0*x1^2 + y0^2 - y1^2 - 1, -3*x0^2*x1 + x1^3 + 2*y0*y1) - of Multivariate Polynomial Ring in x0, x1, y0, y1 over Number Field in w - with defining polynomial x^5 - 2 + Ideal (-x0^3 + 3*x0*x1^2 + y0^2 - y1^2 - 1, -3*x0^2*x1 + x1^3 + 2*y0*y1) of + Multivariate Polynomial Ring in x0, x1, y0, y1 + over Number Field in w with defining polynomial x^5 - 2 .. NOTE:: @@ -5443,8 +5605,9 @@ class MPolynomialIdeal_quotient(MPolynomialIdeal): sage: Q.<x,y,z,w> = QQ['x,y,z,w'].quotient(['x*y-z^2', 'y^2-w^2']) sage: I = ideal(x + y^2 + z - 1) sage: I - Ideal (w^2 + x + z - 1) of Quotient of Multivariate Polynomial Ring - in x, y, z, w over Rational Field by the ideal (x*y - z^2, y^2 - w^2) + Ideal (w^2 + x + z - 1) of Quotient + of Multivariate Polynomial Ring in x, y, z, w over Rational Field + by the ideal (x*y - z^2, y^2 - w^2) """ def reduce(self, f): r""" @@ -5455,9 +5618,9 @@ def reduce(self, f): EXAMPLES:: sage: R.<T,U,V,W,X,Y,Z> = PolynomialRing(QQ, order='lex') - sage: I = R.ideal([T^2+U^2-1, V^2+W^2-1, X^2+Y^2+Z^2-1]) + sage: I = R.ideal([T^2 + U^2 - 1, V^2 + W^2 - 1, X^2 + Y^2 + Z^2 - 1]) sage: Q.<t,u,v,w,x,y,z> = R.quotient(I) - sage: J = Q.ideal([u*v-x, u*w-y, t-z]) + sage: J = Q.ideal([u*v - x, u*w - y, t - z]) sage: J.reduce(t^2 - z^2) 0 sage: J.reduce(u^2) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx index e37147491dd..14820418454 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx @@ -56,12 +56,11 @@ from sage.libs.singular.decl cimport scKBase, poly, testHomog, idSkipZeroes, id_ from sage.libs.singular.decl cimport OPT_REDTAIL, singular_options, kInterRed, t_rep_gb, p_GetCoeff from sage.libs.singular.decl cimport pp_Mult_nn, p_Delete, n_Delete from sage.libs.singular.decl cimport rIsPluralRing -from sage.libs.singular.decl cimport n_unknown, n_Zp, n_Q, n_R, n_GF, n_long_R, n_algExt,n_transExt,n_long_C, n_Z, n_Zn, n_Znm, n_Z2m, n_CF +from sage.libs.singular.decl cimport n_Z, n_Zn, n_Znm, n_Z2m from sage.rings.polynomial.multi_polynomial_libsingular cimport new_MP from sage.rings.polynomial.plural cimport new_NCP -from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular from sage.structure.sequence import Sequence diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pxd b/src/sage/rings/polynomial/multi_polynomial_libsingular.pxd index f0518c93f9c..c9cec10e2bc 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pxd +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pxd @@ -1,11 +1,11 @@ from sage.libs.singular.decl cimport poly, ring -from sage.rings.polynomial.multi_polynomial cimport MPolynomial +from sage.rings.polynomial.multi_polynomial cimport MPolynomial_libsingular as MPolynomial_libsingular_base from sage.rings.polynomial.multi_polynomial_ring_base cimport MPolynomialRing_base cdef class MPolynomialRing_libsingular -cdef class MPolynomial_libsingular(MPolynomial): +cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): cdef poly *_poly cdef ring *_parent_ring cpdef _add_(self, other) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index c8d4ad59156..9b10b54371f 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -30,21 +30,18 @@ We show how to construct various multivariate polynomial rings:: sage: P.term_order() Degree reverse lexicographic term order - sage: P = PolynomialRing(GF(127),3,names='abc', order='lex') - sage: P + sage: P = PolynomialRing(GF(127), 3, names='abc', order='lex'); P Multivariate Polynomial Ring in a, b, c over Finite Field of size 127 - sage: a,b,c = P.gens() sage: f = 57 * a^2*b + 43 * c + 1; f 57*a^2*b + 43*c + 1 - sage: P.term_order() Lexicographic term order sage: z = QQ['z'].0 - sage: K.<s> = NumberField(z^2 - 2) - sage: P.<x,y> = PolynomialRing(K, 2) - sage: 1/2*s*x^2 + 3/4*s + sage: K.<s> = NumberField(z^2 - 2) # needs sage.rings.number_field + sage: P.<x,y> = PolynomialRing(K, 2) # needs sage.rings.number_field + sage: 1/2*s*x^2 + 3/4*s # needs sage.rings.number_field (1/2*s)*x^2 + (3/4*s) sage: P.<x,y,z> = ZZ[]; P @@ -57,7 +54,8 @@ We show how to construct various multivariate polynomial rings:: Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 59049 sage: P.<x,y,z> = Zmod(2^100)[]; P - Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 1267650600228229401496703205376 + Multivariate Polynomial Ring in x, y, z over + Ring of integers modulo 1267650600228229401496703205376 sage: P.<x,y,z> = Zmod(2521352)[]; P Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 2521352 @@ -75,9 +73,9 @@ We construct the Frobenius morphism on `\GF{5}[x,y,z]` over `\GF{5}`:: sage: frob = R.hom([x^5, y^5, z^5]) sage: frob(x^2 + 2*y - z^4) -z^20 + x^10 + 2*y^5 - sage: frob((x + 2*y)^3) + sage: frob((x + 2*y)^3) # needs sage.rings.finite_rings x^15 + x^10*y^5 + 2*x^5*y^10 - 2*y^15 - sage: (x^5 + 2*y^5)^3 + sage: (x^5 + 2*y^5)^3 # needs sage.rings.finite_rings x^15 + x^10*y^5 + 2*x^5*y^10 - 2*y^15 We make a polynomial ring in one variable over a polynomial ring in @@ -95,7 +93,7 @@ TESTS:: True sage: loads(dumps(x)) == x True - sage: P.<x,y,z> = GF(2^8,'a')[] + sage: P.<x,y,z> = GF(2^8,'a')[] # needs sage.rings.finite_rings sage: loads(dumps(P)) == P True sage: loads(dumps(x)) == x @@ -119,10 +117,10 @@ TESTS:: Check if :trac:`6160` is fixed:: - sage: x=var('x') - sage: K.<j> = NumberField(x-1728) - sage: R.<b,c> = K[] - sage: b-j*c + sage: x = polygen(ZZ, 'x') + sage: K.<j> = NumberField(x - 1728) # needs sage.rings.number_field + sage: R.<b,c> = K[] # needs sage.rings.number_field + sage: b - j*c # needs sage.rings.number_field b - 1728*c .. TODO:: @@ -185,13 +183,13 @@ from sage.libs.singular.decl cimport (ring, poly, ideal, intvec, number, # singular functions from sage.libs.singular.decl cimport ( errorreported, - n_IsUnit, n_Invers, n_GetChar, + n_Invers, n_GetChar, p_ISet, rChangeCurrRing, p_Copy, p_Init, p_SetCoeff, p_Setm, p_SetExp, p_Add_q, p_NSet, p_GetCoeff, p_Delete, p_GetExp, pNext, rRingVar, omAlloc0, omStrDup, omFree, p_Divide, p_SetCoeff0, n_Init, p_DivisibleBy, pLcm, p_LmDivisibleBy, pMDivide, p_MDivide, p_IsConstant, p_ExpVectorEqual, p_String, p_LmInit, n_Copy, - p_IsUnit, p_IsOne, p_Series, p_Head, idInit, fast_map_common_subexp, id_Delete, - p_IsHomogeneous, p_Homogen, p_Totaldegree,pLDeg1_Totaldegree, singclap_pdivide, singclap_factorize, + p_IsUnit, p_IsOne, p_Head, idInit, fast_map_common_subexp, id_Delete, + p_IsHomogeneous, p_Homogen, p_Totaldegree, singclap_pdivide, singclap_factorize, idLift, IDELEMS, On, Off, SW_USE_CHINREM_GCD, SW_USE_EZGCD, p_LmIsConstant, pTakeOutComp, singclap_gcd, pp_Mult_qq, p_GetMaxExp, pLength, kNF, p_Neg, p_Minus_mm_Mult_qq, p_Plus_mm_Mult_qq, @@ -222,13 +220,11 @@ from sage.rings.polynomial.polynomial_ring import is_PolynomialRing # base ring imports import sage.rings.abc -from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn from sage.rings.rational cimport Rational from sage.rings.rational_field import QQ import sage.rings.abc from sage.rings.integer_ring import is_IntegerRing, ZZ from sage.rings.integer cimport Integer -from sage.rings.integer import GCD_list from sage.rings.number_field.number_field_base cimport NumberField from sage.rings.number_field.order import is_NumberFieldOrder @@ -240,7 +236,7 @@ from sage.structure.parent cimport Parent from sage.structure.category_object cimport CategoryObject from sage.structure.coerce cimport coercion_model -from sage.structure.element cimport Element, CommutativeRingElement +from sage.structure.element cimport Element from sage.structure.richcmp cimport rich_to_bool, richcmp from sage.structure.factorization import Factorization @@ -299,31 +295,25 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): EXAMPLES:: - sage: P.<x,y,z> = QQ[] - sage: P + sage: P.<x,y,z> = QQ[]; P Multivariate Polynomial Ring in x, y, z over Rational Field - sage: f = 27/113 * x^2 + y*z + 1/2; f 27/113*x^2 + y*z + 1/2 - sage: P.term_order() Degree reverse lexicographic term order - sage: P = PolynomialRing(GF(127),3,names='abc', order='lex') - sage: P + sage: P = PolynomialRing(GF(127), 3, names='abc', order='lex'); P Multivariate Polynomial Ring in a, b, c over Finite Field of size 127 - sage: a,b,c = P.gens() sage: f = 57 * a^2*b + 43 * c + 1; f 57*a^2*b + 43*c + 1 - sage: P.term_order() Lexicographic term order sage: z = QQ['z'].0 - sage: K.<s> = NumberField(z^2 - 2) - sage: P.<x,y> = PolynomialRing(K, 2) - sage: 1/2*s*x^2 + 3/4*s + sage: K.<s> = NumberField(z^2 - 2) # needs sage.rings.number_field + sage: P.<x,y> = PolynomialRing(K, 2) # needs sage.rings.number_field + sage: 1/2*s*x^2 + 3/4*s # needs sage.rings.number_field (1/2*s)*x^2 + (3/4*s) sage: P.<x,y,z> = ZZ[]; P @@ -336,7 +326,8 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 59049 sage: P.<x,y,z> = Zmod(2^100)[]; P - Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 1267650600228229401496703205376 + Multivariate Polynomial Ring in x, y, z over + Ring of integers modulo 1267650600228229401496703205376 sage: P.<x,y,z> = Zmod(2521352)[]; P Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 2521352 @@ -344,11 +335,12 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): <class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomialRing_libsingular'> sage: P.<x,y,z> = Zmod(25213521351515232)[]; P - Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 25213521351515232 + Multivariate Polynomial Ring in x, y, z over + Ring of integers modulo 25213521351515232 sage: type(P) <class 'sage.rings.polynomial.multi_polynomial_ring.MPolynomialRing_polydict_with_category'> - sage: P.<x,y,z> = PolynomialRing(Integers(2^32),order='lex') + sage: P.<x,y,z> = PolynomialRing(Integers(2^32), order='lex') sage: P(2^32-1) 4294967295 @@ -370,7 +362,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Traceback (most recent call last): ... NotImplementedError: polynomials over Ring of integers modulo 1 are not supported in Singular - sage: MPolynomialRing_libsingular(SR, 1, ["x"], "lex") + sage: MPolynomialRing_libsingular(SR, 1, ["x"], "lex") # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: polynomials over Symbolic Ring are not supported in Singular @@ -383,7 +375,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): ... NotImplementedError: polynomials in -1 variables are not supported in Singular """ - self.__ngens = n + self._ngens = n self._ring = singular_ring_new(base_ring, n, names, order) self._zero_element = new_MP(self, NULL) cdef MPolynomial_libsingular one = new_MP(self, p_ISet(1, self._ring)) @@ -405,9 +397,12 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: import gc sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular - sage: R1 = MPolynomialRing_libsingular(GF(5), 2, ('x', 'y'), TermOrder('degrevlex', 2)) - sage: R2 = MPolynomialRing_libsingular(GF(11), 2, ('x', 'y'), TermOrder('degrevlex', 2)) - sage: R3 = MPolynomialRing_libsingular(GF(13), 2, ('x', 'y'), TermOrder('degrevlex', 2)) + sage: R1 = MPolynomialRing_libsingular(GF(5), 2, ('x', 'y'), + ....: TermOrder('degrevlex', 2)) + sage: R2 = MPolynomialRing_libsingular(GF(11), 2, ('x', 'y'), + ....: TermOrder('degrevlex', 2)) + sage: R3 = MPolynomialRing_libsingular(GF(13), 2, ('x', 'y'), + ....: TermOrder('degrevlex', 2)) sage: _ = gc.collect() sage: foo = R1.gen(0) sage: del foo @@ -429,23 +424,24 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): TESTS:: + sage: # needs sage.rings.function_field sage: import gc sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular sage: from sage.libs.singular.ring import ring_refcount_dict sage: gc.collect() # random output sage: n = len(ring_refcount_dict) - sage: R = MPolynomialRing_libsingular(GF(547), 2, ('x', 'y'), TermOrder('degrevlex', 2)) + sage: R = MPolynomialRing_libsingular(GF(547), 2, ('x', 'y'), + ....: TermOrder('degrevlex', 2)) sage: len(ring_refcount_dict) == n + 1 True - sage: Q = copy(R) # indirect doctest - sage: p = R.gen(0) ^2+R.gen(1)^2 + sage: p = R.gen(0)^2 + R.gen(1)^2 sage: q = copy(p) sage: del R sage: del Q sage: del p sage: del q - sage: gc.collect() # random output + sage: gc.collect() # random output sage: len(ring_refcount_dict) == n False """ @@ -460,7 +456,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): TESTS:: sage: R.<x,y> = GF(547)[] - sage: R is deepcopy(R) # indirect doctest + sage: R is deepcopy(R) True """ memo[id(self)] = self @@ -468,7 +464,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): cpdef _coerce_map_from_(self, other): """ - Return True if and only if there exists a coercion map from + Return ``True`` if and only if there exists a coercion map from ``other`` to ``self``. TESTS:: @@ -561,15 +557,15 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P.coerce(int(1)) 1 - sage: k.<a> = GF(2^8) - sage: P.<x,y> = PolynomialRing(k,2) - sage: P.coerce(a) + sage: k.<a> = GF(2^8) # needs sage.rings.finite_rings + sage: P.<x,y> = PolynomialRing(k,2) # needs sage.rings.finite_rings + sage: P.coerce(a) # needs sage.rings.finite_rings a sage: z = QQ['z'].0 - sage: K.<s> = NumberField(z^2 - 2) - sage: P.<x,y> = PolynomialRing(K, 2) - sage: P.coerce(1/2*s) + sage: K.<s> = NumberField(z^2 - 2) # needs sage.rings.number_field + sage: P.<x,y> = PolynomialRing(K, 2) # needs sage.rings.number_field + sage: P.coerce(1/2*s) # needs sage.rings.number_field (1/2*s) TESTS:: @@ -585,16 +581,16 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Check if :trac:`7582` is fixed:: - sage: R.<x,y,z> = PolynomialRing(CyclotomicField(2),3) - sage: R.coerce(1) + sage: R.<x,y,z> = PolynomialRing(CyclotomicField(2), 3) # needs sage.rings.number_field + sage: R.coerce(1) # needs sage.rings.number_field 1 Check if :trac:`6160` is fixed:: - sage: x=var('x') - sage: K.<j> = NumberField(x-1728) - sage: R.<b,c> = K[] - sage: R.coerce(1) + sage: x = polygen(ZZ, 'x') + sage: K.<j> = NumberField(x - 1728) # needs sage.rings.number_field + sage: R.<b,c> = K[] # needs sage.rings.number_field + sage: R.coerce(1) # needs sage.rings.number_field 1 Check if coercion from zero variable polynomial rings work @@ -626,15 +622,15 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: P._singular_().set_ring() - sage: P(singular('x + 3/4')) + sage: P(singular('x + 3/4')) # needs sage.rings.function_field x + 3/4 Coercion from symbolic variables:: sage: R = QQ['x,y,z'] - sage: var('x') + sage: var('x') # needs sage.symbolic x - sage: R(x) + sage: R(x) # needs sage.symbolic x Coercion from 'similar' rings, which maps by index:: @@ -654,9 +650,9 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Coercion from PARI objects:: sage: P.<x,y,z> = QQ[] - sage: P(pari('x^2 + y')) + sage: P(pari('x^2 + y')) # needs sage.libs.pari x^2 + y - sage: P(pari('x*y')) + sage: P(pari('x*y')) # needs sage.libs.pari x*y Coercion from boolean polynomials, also by index:: @@ -669,7 +665,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): If everything else fails, we try to convert to the base ring:: sage: R.<x,y,z> = GF(3)[] - sage: R(1/2) + sage: R(1/2) # needs sage.rings.finite_rings -1 Finally, conversions from other polynomial rings which are not @@ -679,7 +675,8 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): preserving conversion:: sage: P.<y_2, y_1, z_3, z_2, z_1> = GF(3)[] - sage: Q = GF(3)['y_4', 'y_3', 'y_2', 'y_1', 'z_5', 'z_4', 'z_3', 'z_2', 'z_1'] + sage: Q = GF(3)['y_4', 'y_3', 'y_2', 'y_1', + ....: 'z_5', 'z_4', 'z_3', 'z_2', 'z_1'] sage: Q(y_1*z_2^2*z_1) y_1*z_2^2*z_1 @@ -689,7 +686,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P.<a,b,c> = GF(2)[] sage: Q = GF(2)['c','b','d','e'] sage: f = Q.convert_map_from(P) - sage: f(a), f(b), f(c) + sage: f(a), f(b), f(c) # needs sage.rings.finite_rings (c, b, d) :: @@ -705,14 +702,15 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P.<a,b,c,f> = GF(2)[] sage: Q = GF(2)['c','d','e'] sage: f = Q.convert_map_from(P) - sage: f(a) + sage: f(a) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: Could not find a mapping of the passed element to this ring. Coerce in a polydict where a coefficient reduces to 0 but isn't 0. :: - sage: R.<x,y> = QQ[]; S.<xx,yy> = GF(5)[]; S( (5*x*y + x + 17*y)._mpoly_dict_recursive() ) + sage: R.<x,y> = QQ[]; S.<xx,yy> = GF(5)[] + sage: S((5*x*y + x + 17*y)._mpoly_dict_recursive()) xx + 2*yy Coerce in a polynomial one of whose coefficients reduces to 0. :: @@ -723,7 +721,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Some other examples that illustrate the same coercion idea:: sage: R.<x,y> = ZZ[] - sage: S.<xx,yy> = GF(25,'a')[] + sage: S.<xx,yy> = GF(25,'a')[] # needs sage.rings.finite_rings sage: S(5*x*y + x + 17*y) xx + 2*yy @@ -749,11 +747,11 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): And :trac:`7597` is fixed if this does not segfault:: sage: F2 = GF(2) - sage: F.<x> = GF(2^8) + sage: F.<x> = GF(2^8) # needs sage.rings.finite_rings sage: R4.<a,b> = PolynomialRing(F) sage: R.<u,v> = PolynomialRing(F2) sage: P = a - sage: (P(0,0).polynomial()[0])*u + sage: (P(0,0).polynomial()[0])*u # needs sage.rings.finite_rings 0 sage: P(a,b) a @@ -766,6 +764,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Check that :trac:`17964` is fixed:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(17) sage: Q.<x,y> = K[] sage: f = (-3*a)*y + (5*a) @@ -1020,7 +1019,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Multivariate Polynomial Ring in x, y over Rational Field """ varstr = ", ".join(char_to_str(rRingVar(i,self._ring)) - for i in range(self.__ngens)) + for i in range(self._ngens)) return "Multivariate Polynomial Ring in %s over %s" % (varstr, self.base_ring()) def ngens(self): @@ -1033,12 +1032,12 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P.ngens() 2 - sage: k.<a> = GF(2^16) - sage: P = PolynomialRing(k,1000,'x') - sage: P.ngens() + sage: k.<a> = GF(2^16) # needs sage.rings.finite_rings + sage: P = PolynomialRing(k, 1000, 'x') # needs sage.rings.finite_rings + sage: P.ngens() # needs sage.rings.finite_rings 1000 """ - return int(self.__ngens) + return int(self._ngens) def gen(self, int n=0): """ @@ -1052,10 +1051,10 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): EXAMPLES:: sage: P.<x,y,z> = QQ[] - sage: P.gen(),P.gen(1) + sage: P.gen(), P.gen(1) (x, y) - sage: P = PolynomialRing(GF(127),1000,'x') + sage: P = PolynomialRing(GF(127), 1000, 'x') sage: P.gen(500) x500 @@ -1066,7 +1065,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): cdef poly *_p cdef ring *_ring = self._ring - if n < 0 or n >= self.__ngens: + if n < 0 or n >= self._ngens: raise ValueError("Generator not defined.") rChangeCurrRing(_ring) @@ -1091,11 +1090,13 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): EXAMPLES:: sage: P.<x,y,z> = QQ[] - sage: sage.rings.ideal.Katsura(P) - Ideal (x + 2*y + 2*z - 1, x^2 + 2*y^2 + 2*z^2 - x, 2*x*y + 2*y*z - y) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: sage.rings.ideal.Katsura(P) # needs sage.rings.function_field + Ideal (x + 2*y + 2*z - 1, x^2 + 2*y^2 + 2*z^2 - x, 2*x*y + 2*y*z - y) + of Multivariate Polynomial Ring in x, y, z over Rational Field sage: P.ideal([x + 2*y + 2*z-1, 2*x*y + 2*y*z-y, x^2 + 2*y^2 + 2*z^2-x]) - Ideal (x + 2*y + 2*z - 1, 2*x*y + 2*y*z - y, x^2 + 2*y^2 + 2*z^2 - x) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (x + 2*y + 2*z - 1, 2*x*y + 2*y*z - y, x^2 + 2*y^2 + 2*z^2 - x) + of Multivariate Polynomial Ring in x, y, z over Rational Field """ coerce = kwds.get('coerce', True) if len(gens) == 1: @@ -1138,7 +1139,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): QQ[x...y] sage: R.<x,y> = GF(17)[] - sage: macaulay2(R) # optional - macaulay2 + sage: macaulay2(R) # optional - macaulay2 # needs sage.rings.finite_rings ZZ --[x...y] 17 @@ -1193,9 +1194,9 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P._singular_().name() == P._singular_().name() True - sage: k.<a> = GF(3^3) - sage: P.<x,y,z> = PolynomialRing(k,3) - sage: P._singular_() + sage: k.<a> = GF(3^3) # needs sage.rings.finite_rings + sage: P.<x,y,z> = PolynomialRing(k, 3) # needs sage.rings.finite_rings + sage: P._singular_() # needs sage.rings.finite_rings polynomial ring, over a field, global ordering // coefficients: ZZ/3[a]/(a^3-a+1) // number of vars : 3 @@ -1203,10 +1204,10 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // : names x y z // block 2 : ordering C - sage: P._singular_() is P._singular_() + sage: P._singular_() is P._singular_() # needs sage.rings.finite_rings True - sage: P._singular_().name() == P._singular_().name() + sage: P._singular_().name() == P._singular_().name() # needs sage.rings.finite_rings True TESTS:: @@ -1234,8 +1235,8 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): if self.base_ring().is_finite() \ or (isinstance(self.base_ring(), NumberField) and self.base_ring().is_absolute()): R.set_ring() #sorry for that, but needed for minpoly - if singular.eval('minpoly') != "(" + self.__minpoly + ")": - singular.eval("minpoly=%s"%(self.__minpoly)) + if singular.eval('minpoly') != "(" + self.__minpoly + ")": + singular.eval("minpoly=%s" % (self.__minpoly)) self.__minpoly = singular.eval('minpoly')[1:-1] # store in correct format return R except (AttributeError, ValueError): @@ -1267,9 +1268,9 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P._singular_init_().name() == P._singular_init_().name() False - sage: w = var('w') - sage: R.<x,y> = PolynomialRing(NumberField(w^2+1,'s')) - sage: singular(R) + sage: w = polygen(ZZ, 'w') + sage: R.<x,y> = PolynomialRing(NumberField(w^2 + 1,'s')) # needs sage.rings.number_field + sage: singular(R) # needs sage.rings.number_field polynomial ring, over a field, global ordering // coefficients: QQ[s]/(s^2+1) // number of vars : 2 @@ -1277,8 +1278,8 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // : names x y // block 2 : ordering C - sage: R = PolynomialRing(GF(2**8,'a'),10,'x', order='invlex') - sage: singular(R) + sage: R = PolynomialRing(GF(2**8,'a'),10,'x', order='invlex') # needs sage.rings.finite_rings + sage: singular(R) # needs sage.rings.finite_rings polynomial ring, over a field, global ordering // coefficients: ZZ/2[a]/(a^8+a^4+a^3+a^2+1) // number of vars : 10 @@ -1287,7 +1288,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = PolynomialRing(GF(127),2,'x', order='invlex') - sage: singular(R) + sage: singular(R) # needs sage.rings.finite_rings polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 2 @@ -1296,7 +1297,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = PolynomialRing(QQ,2,'x', order='invlex') - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 2 @@ -1305,7 +1306,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = PolynomialRing(QQ,2,'x', order='degneglex') - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 2 @@ -1317,7 +1318,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 3 : ordering C sage: R = PolynomialRing(QQ,'x') - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 @@ -1326,7 +1327,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = PolynomialRing(GF(127),'x') - sage: singular(R) + sage: singular(R) # needs sage.rings.finite_rings polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 1 @@ -1335,7 +1336,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = ZZ['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a domain, global ordering // coefficients: ZZ // number of vars : 2 @@ -1344,7 +1345,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = IntegerModRing(1024)['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a ring (with zero-divisors), global ordering // coefficients: ZZ/(2^10) // number of vars : 2 @@ -1353,7 +1354,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C sage: R = IntegerModRing(15)['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.rings.function_field polynomial ring, over a ring (with zero-divisors), global ordering // coefficients: ZZ/...(15) // number of vars : 2 @@ -1373,12 +1374,10 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): // block 2 : ordering C """ - from sage.functions.other import ceil - if singular is None: from sage.interfaces.singular import singular - if self.ngens()==1: + if self.ngens() == 1: _vars = str(self.gen()) if "*" in _vars: # 1.000...000*x _vars = _vars.split("*")[1] @@ -1434,7 +1433,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P == R False - sage: R.<x,y,z> = PolynomialRing(QQ,order='invlex') + sage: R.<x,y,z> = PolynomialRing(QQ, order='invlex') sage: P == R False @@ -1480,22 +1479,22 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P == loads(dumps(P)) True - sage: P = PolynomialRing(GF(2^8,'F'), names='abc') + sage: P = PolynomialRing(GF(2^8,'F'), names='abc') # needs sage.rings.finite_rings sage: P == loads(dumps(P)) True - sage: P = PolynomialRing(GF(2^16,'B'), names='abc') + sage: P = PolynomialRing(GF(2^16,'B'), names='abc') # needs sage.rings.finite_rings sage: P == loads(dumps(P)) True sage: z = QQ['z'].0 - sage: P = PolynomialRing(NumberField(z^2 + 3,'B'), names='abc') - sage: P == loads(dumps(P)) + sage: P = PolynomialRing(NumberField(z^2 + 3, 'B'), names='abc') # needs sage.rings.number_field + sage: P == loads(dumps(P)) # needs sage.rings.number_field True """ return unpickle_MPolynomialRing_libsingular, \ (self.base_ring(), self.variable_names(), self.term_order()) - def __temporarily_change_names(self, names, latex_names): + def _temporarily_change_names(self, names, latex_names): """ This is used by the variable names context manager. @@ -1605,7 +1604,6 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): cdef poly *res cdef ring *r = self._ring cdef number *n - cdef number *denom if self is not f._parent: f = self.coerce(f) @@ -1724,7 +1722,8 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): if g._poly == NULL: raise ArithmeticError("Cannot compute LCM of zero and nonzero element.") - if(self._ring != currRing): rChangeCurrRing(self._ring) + if self._ring != currRing: + rChangeCurrRing(self._ring) pLcm(f._poly, g._poly, m) p_Setm(m, self._ring) @@ -1897,7 +1896,7 @@ def unpickle_MPolynomialRing_libsingular(base_ring, names, term_order): return _multi_variate(base_ring, tuple(names), None, term_order, None) -cdef class MPolynomial_libsingular(MPolynomial): +cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): """ A multivariate polynomial implemented using libSINGULAR. """ @@ -1908,8 +1907,8 @@ cdef class MPolynomial_libsingular(MPolynomial): EXAMPLES:: sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomial_libsingular - sage: P = PolynomialRing(GF(32003),3,'x') - sage: MPolynomial_libsingular(P) + sage: P = PolynomialRing(GF(32003), 3, 'x') # needs sage.rings.finite_rings + sage: MPolynomial_libsingular(P) # needs sage.rings.finite_rings 0 """ self._poly = NULL @@ -1936,6 +1935,7 @@ cdef class MPolynomial_libsingular(MPolynomial): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(7^2) sage: R.<x,y> = F[] sage: p = a*x^2 + y + a^3; p @@ -2042,11 +2042,12 @@ cdef class MPolynomial_libsingular(MPolynomial): See :trac:`8502`:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: K.<t> = NumberField(x^2+47) + sage: K.<t> = NumberField(x^2 + 47) sage: R.<X,Y,Z> = K[] - sage: f = X+Y+Z - sage: a = f(t,t,t); a + sage: f = X + Y + Z + sage: a = f(t, t, t); a 3*t sage: a.parent() is K True @@ -2057,7 +2058,19 @@ cdef class MPolynomial_libsingular(MPolynomial): 9 sage: a.parent() is QQ True + + See :trac:`33373`:: + + sage: # needs sage.rings.finite_rings + sage: k.<a> = GF(2^4) + sage: R.<x> = PolynomialRing(k, 1) + sage: f = R(1) + sage: S.<y> = PolynomialRing(k, 1) + sage: f(y).parent() + Multivariate Polynomial Ring in y over Finite Field in a of size 2^4 """ + cdef Element sage_res + if len(kwds) > 0: f = self.subs(**kwds) if len(x) > 0: @@ -2076,29 +2089,27 @@ cdef class MPolynomial_libsingular(MPolynomial): if l != parent._ring.N: raise TypeError("number of arguments does not match number of variables in parent") + res_parent = coercion_model.common_parent(parent._base, *x) + cdef poly *res # ownership will be transferred to us in the else block try: - # Attempt evaluation via singular. coerced_x = [parent.coerce(e) for e in x] except TypeError: # give up, evaluate functional - y = parent.base_ring().zero() - for (m,c) in self.dict().iteritems(): - y += c*mul([ x[i]**m[i] for i in m.nonzero_positions()]) - return y - - cdef poly *res # ownership will be transferred to us in the next line - singular_polynomial_call(&res, self._poly, _ring, coerced_x, MPolynomial_libsingular_get_element) - res_parent = coercion_model.common_parent(parent._base, *x) - - if res == NULL: - return res_parent(0) - if p_LmIsConstant(res, _ring): - sage_res = si2sa( p_GetCoeff(res, _ring), _ring, parent._base ) - p_Delete(&res, _ring) # sage_res contains copy + sage_res = parent.base_ring().zero() + for m, c in self.dict().iteritems(): + sage_res += c * mul([x[i] ** m[i] for i in m.nonzero_positions()]) else: - sage_res = new_MP(parent, res) # pass on ownership of res to sage_res + singular_polynomial_call(&res, self._poly, _ring, coerced_x, MPolynomial_libsingular_get_element) + + if res == NULL: + return res_parent(0) + if p_LmIsConstant(res, _ring): + sage_res = si2sa(p_GetCoeff(res, _ring), _ring, parent._base) + p_Delete(&res, _ring) # sage_res contains copy + else: + sage_res = new_MP(parent, res) # pass on ownership of res to sage_res - if parent(sage_res) is not res_parent: + if sage_res._parent is not res_parent: sage_res = res_parent(sage_res) return sage_res @@ -2517,7 +2528,9 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: print(f._repr_with_changed_varnames(['FOO', 'BAR', 'FOOBAR'])) -FOO^2*BAR - 25/27*BAR^3 - FOOBAR^2 """ - return singular_polynomial_str_with_changed_varnames(self._poly, self._parent_ring, varnames) + return singular_polynomial_str_with_changed_varnames(self._poly, + self._parent_ring, + varnames) def degree(self, MPolynomial_libsingular x=None, int std_grading=False): """ @@ -2721,7 +2734,7 @@ cdef class MPolynomial_libsingular(MPolynomial): if std_grading: result = 0 while p: - result = max(result, sum([p_GetExp(p,i,r) for i in xrange(1,r.N+1)])) + result = max(result, sum([p_GetExp(p,i,r) for i in range(1,r.N+1)])) p = pNext(p) return result return singular_polynomial_deg(p, NULL, r) @@ -2768,12 +2781,11 @@ cdef class MPolynomial_libsingular(MPolynomial): INPUT: - ``degrees`` - Can be any of: - - a dictionary of degree restrictions - - a list of degree restrictions (with None in the unrestricted variables) - - a monomial (very fast, but not as flexible) + - a dictionary of degree restrictions + - a list of degree restrictions (with ``None`` in the unrestricted variables) + - a monomial (very fast, but not as flexible) - OUTPUT: - element of the parent of this element. + OUTPUT: element of the parent of this element. .. NOTE:: @@ -2811,8 +2823,8 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: f.coefficient(x^0) # outputs the full polynomial x^2*y^2 + x^2*y + x*y^2 + x^2 + x*y + y^2 + x + y + 1 sage: R.<x,y> = GF(389)[] - sage: f=x*y+5 - sage: c=f.coefficient({x:0,y:0}); c + sage: f = x*y + 5 + sage: c = f.coefficient({x:0, y:0}); c 5 sage: parent(c) Multivariate Polynomial Ring in x, y over Finite Field of size 389 @@ -3202,7 +3214,7 @@ cdef class MPolynomial_libsingular(MPolynomial): cdef list pl, ml pl = list() - ml = list(xrange(r.N)) + ml = list(range(r.N)) if as_ETuples: while p: for v from 1 <= v <= r.N: @@ -3233,7 +3245,8 @@ cdef class MPolynomial_libsingular(MPolynomial): 2 """ cdef ring *_ring = self._parent_ring - if(_ring != currRing): rChangeCurrRing(_ring) + if _ring != currRing: + rChangeCurrRing(_ring) if not (p_IsUnit(self._poly,_ring)): raise ArithmeticError("Element is not a unit.") @@ -3264,7 +3277,8 @@ cdef class MPolynomial_libsingular(MPolynomial): True """ cdef ring *_ring = self._parent_ring - if(_ring != currRing): rChangeCurrRing(_ring) + if _ring != currRing: + rChangeCurrRing(_ring) return bool(p_IsHomogeneous(self._poly,_ring)) cpdef _homogenize(self, int var): @@ -3296,17 +3310,16 @@ cdef class MPolynomial_libsingular(MPolynomial): """ cdef ring *_ring = self._parent_ring cdef MPolynomialRing_libsingular parent = self._parent - cdef MPolynomial_libsingular f if self.is_homogeneous(): return self - if(_ring != currRing): rChangeCurrRing(_ring) + if _ring != currRing: + rChangeCurrRing(_ring) if var < parent._ring.N: - return new_MP(parent, p_Homogen(self._poly, var+1, _ring)) - else: - raise TypeError("var must be < self.parent().ngens()") + return new_MP(parent, p_Homogen(self._poly, var + 1, _ring)) + raise TypeError("var must be < self.parent().ngens()") def is_monomial(self): """ @@ -3337,12 +3350,13 @@ cdef class MPolynomial_libsingular(MPolynomial): if self._poly == NULL: return False - if(_ring != currRing): rChangeCurrRing(_ring) + if _ring != currRing: + rChangeCurrRing(_ring) _p = p_Head(self._poly, _ring) _n = p_GetCoeff(_p, _ring) - ret = bool((not self._poly.next) and _ring.cf.cfIsOne(_n,_ring.cf)) + ret = bool((not self._poly.next) and _ring.cf.cfIsOne(_n, _ring.cf)) p_Delete(&_p, _ring) return ret @@ -3391,8 +3405,7 @@ cdef class MPolynomial_libsingular(MPolynomial): - ``fixed`` - (optional) dict with variable:value pairs - ``**kw`` - names parameters - OUTPUT: - a new multivariate polynomial + OUTPUT: a new multivariate polynomial EXAMPLES:: @@ -3400,12 +3413,12 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: f = x^2 + y + x^2*y^2 + 5 sage: f(5,y) 25*y^2 + y + 30 - sage: f.subs({x:5}) + sage: f.subs({x: 5}) 25*y^2 + y + 30 sage: f.subs(x=5) 25*y^2 + y + 30 - sage: P.<x,y,z> = PolynomialRing(GF(2),3) + sage: P.<x,y,z> = PolynomialRing(GF(2), 3) sage: f = x + y + 1 sage: f.subs({x:y+1}) 0 @@ -3413,14 +3426,14 @@ cdef class MPolynomial_libsingular(MPolynomial): 1 sage: f.subs(x=x) x + y + 1 - sage: f.subs({x:z}) + sage: f.subs({x: z}) y + z + 1 - sage: f.subs(x=z+1) + sage: f.subs(x=z + 1) y + z sage: f.subs(x=1/y) (y^2 + y + 1)/y - sage: f.subs({x:1/y}) + sage: f.subs({x: 1/y}) (y^2 + y + 1)/y The parameters are substituted in order and without side effects:: @@ -3451,8 +3464,8 @@ cdef class MPolynomial_libsingular(MPolynomial): We test that we change the ring even if there is nothing to do:: sage: P = QQ['x,y'] - sage: x = var('x') - sage: parent(P.zero() / x) + sage: x = var('x') # needs sage.symbolic + sage: parent(P.zero().subs(x=x)) # needs sage.symbolic Symbolic Ring We are catching overflows:: @@ -3503,163 +3516,122 @@ cdef class MPolynomial_libsingular(MPolynomial): c*x^2*y + d*x^2 + (2*c)*x*y + (2*d)*x + c*y + d """ - cdef int mi, i, need_map, try_symbolic + cdef int mi, i + cdef bint change_ring = False # indicates the need to change the parent ring + cdef bint need_map = False cdef unsigned long degree = 0 cdef MPolynomialRing_libsingular parent = self._parent cdef ring *_ring = parent._ring - if(_ring != currRing): rChangeCurrRing(_ring) + if (_ring != currRing): + rChangeCurrRing(_ring) cdef poly *_p = p_Copy(self._poly, _ring) cdef poly *_f - cdef ideal *to_id = idInit(_ring.N,1) + cdef ideal *to_id = idInit(_ring.N, 1) cdef ideal *from_id cdef ideal *res_id - need_map = 0 - try_symbolic = 0 + cdef dict gd - if _p == NULL: - # the polynomial is 0. There is nothing to do except to change the - # ring - try_symbolic = 1 - - if not try_symbolic and fixed is not None: - for m,v in fixed.items(): - if isinstance(m, (int, Integer)): - mi = m+1 - elif isinstance(m,MPolynomial_libsingular) and m.parent() is parent: - for i from 0 < i <= _ring.N: - if p_GetExp((<MPolynomial_libsingular>m)._poly, i, _ring) != 0: - mi = i - break - if i > _ring.N: - id_Delete(&to_id, _ring) - p_Delete(&_p, _ring) - raise TypeError("key does not match") - else: - id_Delete(&to_id, _ring) - p_Delete(&_p, _ring) - raise TypeError("keys do not match self's parent") - try: - v = parent.coerce(v) - except TypeError: - try_symbolic = 1 - break - _f = (<MPolynomial_libsingular>v)._poly - if p_IsConstant(_f, _ring): - singular_polynomial_subst(&_p, mi-1, _f, _ring) - else: - need_map = 1 - degree = <unsigned long>p_GetExp(_p, mi, _ring) * <unsigned long>p_GetMaxExp(_f, _ring) - if degree > _ring.bitmask: + cdef list g = list(parent.gens()) + cdef list items = [] + + if not change_ring: + if fixed is not None: + for m, v in fixed.items(): + if isinstance(m, (int, Integer)): + mi = m + 1 + elif isinstance(m, MPolynomial_libsingular) and m.parent() is parent: + for i from 0 < i <= _ring.N: + if p_GetExp((<MPolynomial_libsingular> m)._poly, i, _ring) != 0: + mi = i + break + if i > _ring.N: + id_Delete(&to_id, _ring) + p_Delete(&_p, _ring) + raise TypeError("key does not match") + else: id_Delete(&to_id, _ring) p_Delete(&_p, _ring) - raise OverflowError("exponent overflow (%d)"%(degree)) - to_id.m[mi-1] = p_Copy(_f, _ring) - + raise TypeError("keys do not match self's parent") + + items.append((g[mi - 1], v)) + if kw: + gd = parent.gens_dict(copy=False) + for m, v in kw.items(): + items.append((gd[m], v)) + for m, v in items: if _p == NULL: - # polynomial becomes 0 after some substitution - try_symbolic = 1 + change_ring = True break - - cdef dict gd - - if not try_symbolic: - gd = parent.gens_dict(copy=False) - for m,v in kw.iteritems(): - m = gd[m] - for i from 0 < i <= _ring.N: - if p_GetExp((<MPolynomial_libsingular>m)._poly, i, _ring) != 0: - mi = i - break - if i > _ring.N: - id_Delete(&to_id, _ring) - p_Delete(&_p, _ring) - raise TypeError("key does not match") + i = g.index(m) try: v = parent.coerce(v) - except TypeError: - try_symbolic = 1 - break - _f = (<MPolynomial_libsingular>v)._poly + except TypeError: # give up, evaluate symbolically + id_Delete(&to_id, _ring) + p_Delete(&_p, _ring) + + gg = list(parent.gens()) + for m, v in items: + gg[g.index(m)] = v + y = parent.base_ring().zero() + for (m,c) in self.dict().items(): + y += c*mul([ gg[i]**m[i] for i in m.nonzero_positions()]) + return y + _f = (<MPolynomial_libsingular> v)._poly if p_IsConstant(_f, _ring): - singular_polynomial_subst(&_p, mi-1, _f, _ring) + singular_polynomial_subst(&_p, i, _f, _ring) else: - if to_id.m[mi-1] != NULL: - p_Delete(&to_id.m[mi-1],_ring) - to_id.m[mi-1] = p_Copy(_f, _ring) - degree = <unsigned long>p_GetExp(_p, mi, _ring) * <unsigned long>p_GetMaxExp(_f, _ring) + need_map = True + degree = (<unsigned long> p_GetExp(_p, i + 1, _ring)) * (<unsigned long> p_GetMaxExp(_f, _ring)) if degree > _ring.bitmask: id_Delete(&to_id, _ring) p_Delete(&_p, _ring) - raise OverflowError("exponent overflow (%d)"%(degree)) - need_map = 1 + raise OverflowError("exponent overflow (%d)" % (degree,)) + to_id.m[i] = p_Copy(_f, _ring) - if _p == NULL: - # the polynomial is 0 - try_symbolic = 1 - break + if not change_ring and need_map: + for mi from 0 <= mi < _ring.N: + if to_id.m[mi] == NULL: + to_id.m[mi] = p_ISet(1,_ring) + p_SetExp(to_id.m[mi], mi + 1, 1, _ring) + p_Setm(to_id.m[mi], _ring) - if need_map: - for mi from 0 <= mi < _ring.N: - if to_id.m[mi] == NULL: - to_id.m[mi] = p_ISet(1,_ring) - p_SetExp(to_id.m[mi], mi+1, 1, _ring) - p_Setm(to_id.m[mi], _ring) + from_id = idInit(1, 1) + from_id.m[0] = _p - from_id=idInit(1,1) - from_id.m[0] = _p - - rChangeCurrRing(_ring) - res_id = fast_map_common_subexp(from_id, _ring, to_id, _ring) - _p = res_id.m[0] + rChangeCurrRing(_ring) + res_id = fast_map_common_subexp(from_id, _ring, to_id, _ring) + _p = res_id.m[0] - from_id.m[0] = NULL - res_id.m[0] = NULL + from_id.m[0] = NULL + res_id.m[0] = NULL - id_Delete(&from_id, _ring) - id_Delete(&res_id, _ring) + id_Delete(&from_id, _ring) + id_Delete(&res_id, _ring) id_Delete(&to_id, _ring) - if not try_symbolic: + if not change_ring: return new_MP(parent,_p) - # now as everything else failed, try to do it symbolically with call + # finally change the parent of the result - cdef list g = list(parent.gens()) - - if fixed is not None: - for m,v in fixed.items(): - if isinstance(m, (int, Integer)): - mi = m+1 - elif isinstance(m, MPolynomial_libsingular) and m.parent() is parent: - for i from 0 < i <= _ring.N: - if p_GetExp((<MPolynomial_libsingular>m)._poly, i, _ring) != 0: - mi = i - break - if i > _ring.N: - raise TypeError("key does not match") - else: - raise TypeError("keys do not match self's parent") + res_parent = coercion_model.common_parent(parent._base, *[v for _, v in items]) - g[mi-1] = v - - gd = parent.gens_dict(copy=False) - for m,v in kw.iteritems(): - m = gd[m] - for i from 0 < i <= _ring.N: - if p_GetExp((<MPolynomial_libsingular>m)._poly, i, _ring) != 0: - mi = i - break - if i > _ring.N: - raise TypeError("key does not match") - - g[mi-1] = v + if _p == NULL: + return res_parent(0) - return self(*g) + if p_LmIsConstant(_p, _ring): + res = si2sa(p_GetCoeff(_p, _ring), _ring, parent._base) + p_Delete(&_p, _ring) # safe to delete; res contains copy + else: + res = new_MP(parent, _p) + if parent(res) is not res_parent: + res = res_parent(res) + return res def monomials(self): """ @@ -3692,7 +3664,7 @@ cdef class MPolynomial_libsingular(MPolynomial): Check if :trac:`7152` is fixed:: - sage: x=var('x') + sage: x = polygen(ZZ, 'x') sage: K.<rho> = NumberField(x**2 + 1) sage: R.<x,y> = QQ[] sage: p = rho*x @@ -3707,7 +3679,8 @@ cdef class MPolynomial_libsingular(MPolynomial): cdef list l = [] cdef MPolynomialRing_libsingular parent = self._parent cdef ring *_ring = parent._ring - if(_ring != currRing): rChangeCurrRing(_ring) + if _ring != currRing: + rChangeCurrRing(_ring) cdef poly *p = p_Copy(self._poly, _ring) cdef poly *t @@ -3806,7 +3779,8 @@ cdef class MPolynomial_libsingular(MPolynomial): zero = k(0) - if(r != currRing): rChangeCurrRing(r) + if r != currRing: + rChangeCurrRing(r) pTotDegMax = -1 while p2: @@ -3816,7 +3790,7 @@ cdef class MPolynomial_libsingular(MPolynomial): coefficients = [zero] * (pTotDegMax + 1) while p: pTotDeg = p_Totaldegree(p, r) - if ( pTotDeg >= len(coefficients) or pTotDeg < 0 ): + if (pTotDeg >= len(coefficients) or pTotDeg < 0): raise IndexError("list index("+str(pTotDeg)+" out of range(0-"+str(len(coefficients))+")") coefficients[pTotDeg] = si2sa(p_GetCoeff(p, r), r, k) p = pNext(p) @@ -3825,8 +3799,8 @@ cdef class MPolynomial_libsingular(MPolynomial): def is_univariate(self): """ - Return ``True`` if self is a univariate polynomial, that is if - self contains only one variable. + Return ``True`` if ``self`` is a univariate polynomial, that is if + ``self`` contains only one variable. EXAMPLES:: @@ -3845,13 +3819,13 @@ cdef class MPolynomial_libsingular(MPolynomial): def _variable_indices_(self, sort=True): """ - Return the indices of all variables occurring in self. This + Return the indices of all variables occurring in ``self``. This index is the index as Sage uses them (starting at zero), not as SINGULAR uses them (starting at one). INPUT: - - ``sort`` - specifies whether the indices shall be sorted + - ``sort`` -- specifies whether the indices shall be sorted EXAMPLES:: @@ -3878,7 +3852,7 @@ cdef class MPolynomial_libsingular(MPolynomial): def variables(self): """ - Return a tuple of all variables occurring in self. + Return a tuple of all variables occurring in ``self``. EXAMPLES:: @@ -3890,7 +3864,8 @@ cdef class MPolynomial_libsingular(MPolynomial): cdef poly *p cdef poly *v cdef ring *r = self._parent_ring - if(r != currRing): rChangeCurrRing(r) + if r != currRing: + rChangeCurrRing(r) cdef int i l = list() si = set() @@ -3908,8 +3883,7 @@ cdef class MPolynomial_libsingular(MPolynomial): def variable(self, i=0): """ - - Return the i-th variable occurring in self. The index i is the + Return the `i`-th variable occurring in ``self``. The index `i` is the index in ``self.variables()``. EXAMPLES:: @@ -3955,13 +3929,13 @@ cdef class MPolynomial_libsingular(MPolynomial): def lm(MPolynomial_libsingular self): """ - Returns the lead monomial of self with respect to the term + Returns the lead monomial of ``self`` with respect to the term order of ``self.parent()``. In Sage a monomial is a product of variables in some power without a coefficient. EXAMPLES:: - sage: R.<x,y,z>=PolynomialRing(GF(7),3,order='lex') + sage: R.<x,y,z> = PolynomialRing(GF(7), 3, order='lex') sage: f = x^1*y^2 + y^3*z^4 sage: f.lm() x*y^2 @@ -3969,7 +3943,7 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: f.lm() x^3*y^2*z^4 - sage: R.<x,y,z>=PolynomialRing(QQ,3,order='deglex') + sage: R.<x,y,z>=PolynomialRing(QQ, 3, order='deglex') sage: f = x^1*y^2*z^3 + x^3*y^2*z^0 sage: f.lm() x*y^2*z^3 @@ -3977,7 +3951,7 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: f.lm() x*y^2*z^4 - sage: R.<x,y,z>=PolynomialRing(GF(127),3,order='degrevlex') + sage: R.<x,y,z>=PolynomialRing(GF(127), 3, order='degrevlex') sage: f = x^1*y^5*z^2 + x^4*y^1*z^3 sage: f.lm() x*y^5*z^2 @@ -4002,7 +3976,7 @@ cdef class MPolynomial_libsingular(MPolynomial): EXAMPLES:: - sage: R.<x,y,z>=PolynomialRing(GF(7),3,order='lex') + sage: R.<x,y,z> = PolynomialRing(GF(7), 3, order='lex') sage: f = 3*x^1*y^2 + 2*y^3*z^4 sage: f.lc() 3 @@ -4019,7 +3993,8 @@ cdef class MPolynomial_libsingular(MPolynomial): if self._poly == NULL: return self._parent._base._zero_element - if(_ring != currRing): rChangeCurrRing(_ring) + if _ring != currRing: + rChangeCurrRing(_ring) _p = p_Head(self._poly, _ring) _n = p_GetCoeff(_p, _ring) @@ -4035,7 +4010,7 @@ cdef class MPolynomial_libsingular(MPolynomial): EXAMPLES:: - sage: R.<x,y,z>=PolynomialRing(GF(7),3,order='lex') + sage: R.<x,y,z> = PolynomialRing(GF(7), 3, order='lex') sage: f = 3*x^1*y^2 + 2*y^3*z^4 sage: f.lt() 3*x*y^2 @@ -4057,7 +4032,7 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: P.<x,y> = PolynomialRing(QQ) sage: x.is_zero() False - sage: (x-x).is_zero() + sage: (x - x).is_zero() True """ if self._poly is NULL: @@ -4091,6 +4066,7 @@ cdef class MPolynomial_libsingular(MPolynomial): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<x,y,z> = GF(32003)[] sage: f = y*x^2 + x + 1 sage: f//x @@ -4185,15 +4161,14 @@ cdef class MPolynomial_libsingular(MPolynomial): INPUT: - - ``proof`` - ignored. + - ``proof`` -- ignored. EXAMPLES:: sage: R.<x, y> = QQ[] sage: f = (x^3 + 2*y^2*x) * (x^2 + x + 1); f x^5 + 2*x^3*y^2 + x^4 + 2*x^2*y^2 + x^3 + 2*x*y^2 - sage: F = f.factor() - sage: F + sage: F = f.factor(); F x * (x^2 + x + 1) * (x^2 + 2*y^2) Next we factor the same polynomial, but over the finite field @@ -4203,25 +4178,26 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: f = (x^3 + 2*y^2*x) * (x^2 + x + 1); f x^5 - x^3*y^2 + x^4 - x^2*y^2 + x^3 - x*y^2 sage: F = f.factor() - sage: F # order is somewhat random + sage: F # order is somewhat random (-1) * x * (-x + y) * (x + y) * (x - 1)^2 Next we factor a polynomial, but over a finite field of order 9.:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(3^2) sage: R.<x, y> = K[] sage: f = (x^3 + 2*a*y^2*x) * (x^2 + x + 1); f x^5 + (-a)*x^3*y^2 + x^4 + (-a)*x^2*y^2 + x^3 + (-a)*x*y^2 - sage: F = f.factor() - sage: F + sage: F = f.factor(); F ((-a)) * x * (x - 1)^2 * ((-a + 1)*x^2 + y^2) sage: f - F 0 Next we factor a polynomial over a number field.:: - sage: p = var('p') - sage: K.<s> = NumberField(p^3-2) + sage: # needs sage.rings.number_field + sage: p = polygen(ZZ, 'p') + sage: K.<s> = NumberField(p^3 - 2) sage: KXY.<x,y> = K[] sage: factor(x^3 - 2*y^3) (x + (-s)*y) * (x^2 + s*x*y + (s^2)*y^2) @@ -4232,7 +4208,8 @@ cdef class MPolynomial_libsingular(MPolynomial): This shows that issue :trac:`2780` is fixed, i.e. that the unit part of the factorization is set correctly:: - sage: x = var('x') + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 1) sage: R.<y, z> = PolynomialRing(K) sage: f = 2*y^2 + 2*z^2 @@ -4241,9 +4218,9 @@ cdef class MPolynomial_libsingular(MPolynomial): Another example:: - sage: R.<x,y,z> = GF(32003)[] - sage: f = 9*(x-1)^2*(y+z) - sage: f.factor() + sage: R.<x,y,z> = GF(32003)[] # needs sage.rings.finite_rings + sage: f = 9*(x-1)^2*(y+z) # needs sage.rings.finite_rings + sage: f.factor() # needs sage.rings.finite_rings (9) * (y + z) * (x - 1)^2 sage: R.<x,w,v,u> = QQ['x','w','v','u'] @@ -4272,12 +4249,13 @@ cdef class MPolynomial_libsingular(MPolynomial): `> 2^{29}` is not supported :: sage: q = 1073741789 - sage: T.<aa, bb> = PolynomialRing(GF(q)) - sage: f = aa^2 + 12124343*bb*aa + 32434598*bb^2 - sage: f.factor() + sage: T.<aa, bb> = PolynomialRing(GF(q)) # needs sage.rings.finite_rings + sage: f = aa^2 + 12124343*bb*aa + 32434598*bb^2 # needs sage.rings.finite_rings + sage: f.factor() # needs sage.rings.finite_rings Traceback (most recent call last): ... - NotImplementedError: Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + NotImplementedError: Factorization of multivariate polynomials + over prime fields with characteristic > 2^29 is not implemented. Factorization over the integers is now supported, see :trac:`17840`:: @@ -4298,7 +4276,8 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: f.factor() Traceback (most recent call last): ... - NotImplementedError: Factorization of multivariate polynomials over Ring of integers modulo 4 is not implemented. + NotImplementedError: Factorization of multivariate polynomials + over Ring of integers modulo 4 is not implemented. TESTS: @@ -4311,6 +4290,7 @@ cdef class MPolynomial_libsingular(MPolynomial): This checks that :trac:`11838` is fixed:: + sage: # needs sage.rings.finite_rings sage: K = GF(4,'a') sage: a = K.gens()[0] sage: R.<x,y> = K[] @@ -4337,8 +4317,8 @@ cdef class MPolynomial_libsingular(MPolynomial): :: sage: R.<x,y> = GF(2)[] - sage: p=x^8 + y^8; q=x^2*y^4 + x - sage: f=p*q + sage: p = x^8 + y^8; q=x^2*y^4 + x + sage: f = p*q sage: lf = f.factor() sage: f-lf 0 @@ -4359,18 +4339,18 @@ cdef class MPolynomial_libsingular(MPolynomial): :: sage: R.<x,y> = GF(5)[] - sage: p=x^27*y^9 + x^32*y^3 + 2*x^20*y^10 - x^4*y^24 - 2*x^17*y - sage: q=-2*x^10*y^24 + x^9*y^24 - 2*x^3*y^30 - sage: f=p*q; f-f.factor() + sage: p = x^27*y^9 + x^32*y^3 + 2*x^20*y^10 - x^4*y^24 - 2*x^17*y + sage: q = -2*x^10*y^24 + x^9*y^24 - 2*x^3*y^30 + sage: f = p*q; f - f.factor() 0 :: sage: R.<x,y> = GF(7)[] - sage: p=-3*x^47*y^24 - sage: q=-3*x^47*y^37 - 3*x^24*y^49 + 2*x^56*y^8 + 3*x^29*y^15 - x^2*y^33 - sage: f=p*q - sage: f-f.factor() + sage: p = -3*x^47*y^24 + sage: q = -3*x^47*y^37 - 3*x^24*y^49 + 2*x^56*y^8 + 3*x^29*y^15 - x^2*y^33 + sage: f = p*q + sage: f - f.factor() 0 The following examples used to give a Segmentation Fault, see @@ -4397,13 +4377,14 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: U.<y,t> = GF(2)[] sage: f = y*t^8 + y^5*t^2 + y*t^6 + t^7 + y^6 + y^5*t + y^2*t^4 + y^2*t^2 + y^2*t + t^3 + y^2 + t^2 sage: l = f.factor() - sage: l[0][0]==t^2 + y + t + 1 or l[1][0]==t^2 + y + t + 1 + sage: l[0][0] == t^2 + y + t + 1 or l[1][0] == t^2 + y + t + 1 True The following used to sometimes take a very long time or get stuck, see :trac:`12846`. These 100 iterations should take less than 1 second:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(4) sage: R.<x,y> = K[] sage: f = (a + 1)*x^145*y^84 + (a + 1)*x^205*y^17 + x^32*y^112 + x^92*y^45 @@ -4413,7 +4394,7 @@ cdef class MPolynomial_libsingular(MPolynomial): Test for :trac:`20435`:: sage: x,y = polygen(ZZ,'x,y') - sage: p = x**2-y**2 + sage: p = x**2 - y**2 sage: z = factor(p); z (x - y) * (x + y) sage: z[0][0].parent() @@ -4545,7 +4526,7 @@ cdef class MPolynomial_libsingular(MPolynomial): _I = idInit(len(I),1) for f in I: - if not (isinstance(f,MPolynomial_libsingular) \ + if not (isinstance(f,MPolynomial_libsingular) and (<MPolynomial_libsingular>f)._parent is parent): try: f = parent.coerce(f) @@ -4672,8 +4653,8 @@ cdef class MPolynomial_libsingular(MPolynomial): _I = idInit(len(I),1) for f in I: - if not (isinstance(f,MPolynomial_libsingular) \ - and (<MPolynomial_libsingular>f)._parent is parent): + if not (isinstance(f,MPolynomial_libsingular) + and (<MPolynomial_libsingular>f)._parent is parent): try: f = parent.coerce(f) except TypeError as msg: @@ -4721,8 +4702,8 @@ cdef class MPolynomial_libsingular(MPolynomial): rChangeCurrRing(r) _I = idInit(1, 1) - if not (isinstance(other,MPolynomial_libsingular) \ - and (<MPolynomial_libsingular>other)._parent is parent): + if not (isinstance(other,MPolynomial_libsingular) + and (<MPolynomial_libsingular>other)._parent is parent): try: other = parent.coerce(other) except TypeError as msg: @@ -4747,11 +4728,11 @@ cdef class MPolynomial_libsingular(MPolynomial): INPUT: - - ``right`` - polynomial + - ``right`` -- polynomial - ``algorithm`` - - ``ezgcd`` - EZGCD algorithm - - ``modular`` - multi-modular algorithm (default) - - ``**kwds`` - ignored + - ``'ezgcd'`` -- EZGCD algorithm + - ``'modular'`` -- multi-modular algorithm (default) + - ``**kwds`` -- ignored EXAMPLES:: @@ -4771,6 +4752,7 @@ cdef class MPolynomial_libsingular(MPolynomial): We compute a gcd over a finite field:: + sage: # needs sage.rings.finite_rings sage: F.<u> = GF(31^2) sage: R.<x,y,z> = F[] sage: p = x^3 + (1+u)*y^3 + z^3 @@ -4782,6 +4764,7 @@ cdef class MPolynomial_libsingular(MPolynomial): We compute a gcd over a number field:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) sage: F.<u> = NumberField(x^3 - 2) sage: R.<x,y,z> = F[] @@ -4799,10 +4782,11 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: x.gcd(1) 1 + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(9) sage: R.<x,y> = PolynomialRing(k) sage: f = R.change_ring(GF(3)).gen() - sage: g = x+y + sage: g = x + y sage: g.gcd(f) 1 sage: x.gcd(R.change_ring(GF(3)).gen()) @@ -4873,13 +4857,15 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: lcm(p,q) 6*x*y*z^4 + 6*y^2*z^4 + 6*x*z^5 + 6*y*z^5 + 12*x*y + 12*y^2 + 12*x*z + 12*y*z + sage: # needs sage.rings.finite_rings sage: r.<x,y> = PolynomialRing(GF(2**8, 'a'), 2) sage: a = r.base_ring().0 sage: f = (a^2+a)*x^2*y + (a^4+a^3+a)*y + a^5 sage: f.lcm(x^4) (a^2 + a)*x^6*y + (a^4 + a^3 + a)*x^4*y + (a^5)*x^4 - sage: w = var('w') + sage: # needs sage.rings.number_field + sage: w = polygen(ZZ, 'w') sage: r.<x,y> = PolynomialRing(NumberField(w^4 + 1, 'a'), 2) sage: a = r.base_ring().0 sage: f = (a^2+a)*x^2*y + (a^4+a^3+a)*y + a^5 @@ -4949,7 +4935,7 @@ cdef class MPolynomial_libsingular(MPolynomial): @coerce_binop def quo_rem(self, MPolynomial_libsingular right): """ - Returns quotient and remainder of self and right. + Return quotient and remainder of ``self`` and ``right``. EXAMPLES:: @@ -5018,15 +5004,15 @@ cdef class MPolynomial_libsingular(MPolynomial): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(GF(127),3) - sage: x._singular_init_() + sage: P.<x,y,z> = PolynomialRing(GF(127), 3) + sage: x._singular_init_() # needs sage.libs.singular 'x' - sage: (x^2+37*y+128)._singular_init_() + sage: (x^2+37*y+128)._singular_init_() # needs sage.libs.singular 'x2+37y+1' TESTS:: - sage: P(0)._singular_init_() + sage: P(0)._singular_init_() # needs sage.libs.singular '0' """ if singular is None: @@ -5046,17 +5032,17 @@ cdef class MPolynomial_libsingular(MPolynomial): EXAMPLES:: - sage: P.<x,y,z>=PolynomialRing(QQ,3) - sage: x.sub_m_mul_q(y,z) + sage: P.<x,y,z> = PolynomialRing(QQ,3) + sage: x.sub_m_mul_q(y, z) -y*z + x TESTS:: - sage: Q.<x,y,z>=PolynomialRing(QQ,3) - sage: P.<x,y,z>=PolynomialRing(QQ,3) - sage: P(0).sub_m_mul_q(P(0),P(1)) + sage: Q.<x,y,z> = PolynomialRing(QQ,3) + sage: P.<x,y,z> = PolynomialRing(QQ,3) + sage: P(0).sub_m_mul_q(P(0), P(1)) 0 - sage: x.sub_m_mul_q(Q.gen(1),Q.gen(2)) + sage: x.sub_m_mul_q(Q.gen(1), Q.gen(2)) -y*z + x """ cdef ring *r = self._parent_ring @@ -5092,21 +5078,21 @@ cdef class MPolynomial_libsingular(MPolynomial): EXAMPLES:: + sage: # optional - macaulay2 sage: R.<x,y> = PolynomialRing(GF(7), 2) sage: f = (x^3 + 2*y^2*x)^7; f # indirect doctest x^21 + 2*x^7*y^14 - - sage: h = macaulay2(f); h # optional - macaulay2 + sage: h = macaulay2(f); h 21 7 14 x + 2x y - sage: k = macaulay2(x+y); k # optional - macaulay2 + sage: k = macaulay2(x+y); k x + y - sage: k + h # optional - macaulay2 + sage: k + h 21 7 14 x + 2x y + x + y - sage: R(h) # optional - macaulay2 + sage: R(h) x^21 + 2*x^7*y^14 - sage: R(h^20) == f^20 # optional - macaulay2 + sage: R(h^20) == f^20 True TESTS: @@ -5131,12 +5117,12 @@ cdef class MPolynomial_libsingular(MPolynomial): INPUT: - - ``m`` - a monomial - - ``q`` - a polynomial + - ``m`` -- a monomial + - ``q`` -- a polynomial EXAMPLES:: - sage: P.<x,y,z>=PolynomialRing(QQ,3) + sage: P.<x,y,z> = PolynomialRing(QQ,3) sage: x.add_m_mul_q(y,z) y*z + x @@ -5175,12 +5161,12 @@ cdef class MPolynomial_libsingular(MPolynomial): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(QQ,3, order='degrevlex') + sage: P.<x,y,z> = PolynomialRing(QQ, 3, order='degrevlex') sage: f = 27/113 * x^2 + y*z + 1/2 sage: f == loads(dumps(f)) True - sage: P = PolynomialRing(GF(127),3,names='abc') + sage: P = PolynomialRing(GF(127), 3, names='abc') sage: a,b,c = P.gens() sage: f = 57 * a^2*b + 43 * c + 1 sage: f == loads(dumps(f)) @@ -5220,6 +5206,7 @@ cdef class MPolynomial_libsingular(MPolynomial): You can specify a map on the base ring:: + sage: # needs sage.rings.number_field sage: Zx.<x> = ZZ[] sage: K.<i> = NumberField(x^2 + 1) sage: cc = K.hom([-i]) @@ -5264,9 +5251,9 @@ cdef class MPolynomial_libsingular(MPolynomial): The derivative is also defined over finite fields:: - sage: R.<x,y> = PolynomialRing(GF(2**8, 'a'),2) + sage: R.<x,y> = PolynomialRing(GF(2**8, 'a'), 2) # needs sage.rings.finite_rings sage: f = x^3*y^2 + y^2 + x + 2 - sage: f._derivative(x) + sage: f._derivative(x) # needs sage.rings.finite_rings x^2*y^2 + 1 """ @@ -5404,16 +5391,16 @@ cdef class MPolynomial_libsingular(MPolynomial): The SINGULAR example:: - sage: R.<x,y,z> = PolynomialRing(GF(32003),3) + sage: R.<x,y,z> = PolynomialRing(GF(32003), 3) # needs sage.rings.finite_rings sage: f = 3 * (x+2)^3 + y - sage: g = x+y+z - sage: f.resultant(g,x) + sage: g = x + y + z # needs sage.rings.finite_rings + sage: f.resultant(g, x) # needs sage.rings.finite_rings 3*y^3 + 9*y^2*z + 9*y*z^2 + 3*z^3 - 18*y^2 - 36*y*z - 18*z^2 + 35*y + 36*z - 24 Resultants are also supported over the Integers:: - sage: R.<x,y,a,b,u>=PolynomialRing(ZZ, 5, order='lex') - sage: r = (x^4*y^2+x^2*y-y).resultant(x*y-y*a-x*b+a*b+u,x) + sage: R.<x,y,a,b,u> = PolynomialRing(ZZ, 5, order='lex') + sage: r = (x^4*y^2 + x^2*y - y).resultant(x*y - y*a - x*b + a*b + u, x) sage: r y^6*a^4 - 4*y^5*a^4*b - 4*y^5*a^3*u + y^5*a^2 - y^5 + 6*y^4*a^4*b^2 + 12*y^4*a^3*b*u - 4*y^4*a^2*b + 6*y^4*a^2*u^2 - 2*y^4*a*u + 4*y^4*b - 4*y^3*a^4*b^3 - 12*y^3*a^3*b^2*u + 6*y^3*a^2*b^2 - 12*y^3*a^2*b*u^2 + 6*y^3*a*b*u - 4*y^3*a*u^3 - 6*y^3*b^2 + y^3*u^2 + y^2*a^4*b^4 + 4*y^2*a^3*b^3*u - 4*y^2*a^2*b^3 + 6*y^2*a^2*b^2*u^2 - 6*y^2*a*b^2*u + 4*y^2*a*b*u^3 + 4*y^2*b^3 - 2*y^2*b*u^2 + y^2*u^4 + y*a^2*b^4 + 2*y*a*b^3*u - y*b^4 + y*b^2*u^2 @@ -5508,21 +5495,20 @@ cdef class MPolynomial_libsingular(MPolynomial): INPUT: - ``prec`` -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). - OUTPUT: - - - a real number. + OUTPUT: a real number. EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ) sage: f = 3*x^3 + 2*x*y^2 - sage: exp(f.global_height()) + sage: exp(f.global_height()) # needs sage.symbolic 3.00000000000000 :: + sage: # needs sage.rings.number_field sage: K.<k> = CyclotomicField(3) sage: R.<x,y> = PolynomialRing(K, sparse=True) sage: f = k*x*y + 1 @@ -5533,10 +5519,10 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: R.<x,y> = PolynomialRing(QQ) sage: f = 1/25*x^2 + 25/3*x*y + y^2 - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 6.43775164973640 sage: g = 100 * f - sage: g.global_height() + sage: g.global_height() # needs sage.symbolic 6.43775164973640 :: @@ -5545,14 +5531,14 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: K.<k> = NumberField(x^2 + 5) sage: T.<t,w> = PolynomialRing(K) sage: f = 1/1331 * t^2 + 5 * w + 7 - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 9.13959596745043 :: sage: R.<x,y> = QQ[] sage: f = 1/123*x*y + 12 - sage: f.global_height(prec=2) + sage: f.global_height(prec=2) # needs sage.symbolic 8.0 :: @@ -5588,11 +5574,9 @@ cdef class MPolynomial_libsingular(MPolynomial): - ``v`` -- a prime or prime ideal of the base ring. - ``prec`` -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). - OUTPUT: - - - a real number. + OUTPUT: a real number. EXAMPLES:: @@ -5603,6 +5587,7 @@ cdef class MPolynomial_libsingular(MPolynomial): :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: K.<k> = NumberField(x^2 - 5) sage: T.<t,w> = K[] @@ -5637,11 +5622,9 @@ cdef class MPolynomial_libsingular(MPolynomial): - ``i`` -- an integer. - ``prec`` -- desired floating point precision (default: - default RealField precision). - - OUTPUT: + default :class:`RealField` precision). - - a real number. + OUTPUT: a real number. EXAMPLES:: @@ -5652,6 +5635,7 @@ cdef class MPolynomial_libsingular(MPolynomial): :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: K.<k> = NumberField(x^2 - 5) sage: T.<t,w> = K[] @@ -5758,20 +5742,98 @@ cdef class MPolynomial_libsingular(MPolynomial): True """ if self.base_ring() is QQ: - #This part is for compatibility with the univariate case, - #where the numerator of a polynomial over RationalField - #is a polynomial over IntegerRing + # This part is for compatibility with the univariate case, + # where the numerator of a polynomial over RationalField + # is a polynomial over IntegerRing # # Github issue #11780: Create the polynomial ring over # the integers using the (cached) polynomial ring constructor: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - integer_polynomial_ring = PolynomialRing(ZZ,\ - self.parent().ngens(), self.parent().gens(), order =\ - self.parent().term_order()) - return integer_polynomial_ring(self * self.denominator()) + integer_poly_ring = PolynomialRing(ZZ, + self.parent().ngens(), + self.parent().gens(), + order=self.parent().term_order()) + return integer_poly_ring(self * self.denominator()) else: return self * self.denominator() + def in_subalgebra(self, J, algorithm="algebra_containment"): + """ + Return whether this polynomial is contained in the subalgebra + generated by ``J`` + + INPUT: + + - ``J`` -- list of elements of the parent polynomial ring + + - ``algorithm`` -- can be ``"algebra_containment"`` (the default), + ``"inSubring"``, or ``"groebner"``. + + - ``"algebra_containment"``: use Singular's + ``algebra_containment`` function, + https://www.singular.uni-kl.de/Manual/4-2-1/sing_1247.htm#SEC1328. The + Singular documentation suggests that this is frequently + faster than the next option. + + - ``"inSubring"``: use Singular's ``inSubring`` function, + https://www.singular.uni-kl.de/Manual/4-2-0/sing_1240.htm#SEC1321. + + - ``"groebner"``: use the algorithm described in Singular's + documentation, but within Sage: if the subalgebra + generators are `y_1`, ..., `y_m`, then create a new + polynomial algebra with the old generators along with new + ones: `z_1`, ..., `z_m`. Create the ideal `(z_1 - y_1, + ..., z_m - y_m)`, and reduce the polynomial modulo this + ideal. The polynomial is contained in the subalgebra if + and only if the remainder involves only the new variables + `z_i`. + + EXAMPLES:: + + sage: P.<x,y,z> = QQ[] + sage: J = [x^2 + y^2, x^2 + z^2] + sage: (y^2).in_subalgebra(J) + False + sage: a = (x^2 + y^2) * (x^2 + z^2) + sage: a.in_subalgebra(J, algorithm='inSubring') + True + sage: (a^2).in_subalgebra(J, algorithm='groebner') + True + sage: (a + a^2).in_subalgebra(J) + True + """ + R = self.parent() + algorithm = algorithm.lower() + from sage.libs.singular.function import singular_function, lib as singular_lib + singular_lib('algebra.lib') + if algorithm == "algebra_containment": + execute = singular_function('execute') + try: + get_printlevel = singular_function('get_printlevel') + except NameError: + execute('proc get_printlevel {return (printlevel);}') + get_printlevel = singular_function('get_printlevel') + # It's fairly verbose unless printlevel is -1. + saved_printlevel = get_printlevel() + execute('printlevel=-1') + contains = singular_function('algebra_containment')(self, R.ideal(J)) == 1 + execute('printlevel={}'.format(saved_printlevel)) + return contains + elif algorithm == "insubring": + return singular_function('inSubring')(self, R.ideal(J))[0] == 1 + elif algorithm == "groebner": + new_gens = [f"newgens{i}" for i in range(len(J))] + ngens = len(new_gens) + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + S = PolynomialRing(R.base_ring(), R.gens() + tuple(new_gens), + order=f'degrevlex({len(R.gens())}),degrevlex({ngens})') + new_gens = S.gens()[-ngens:] + I = S.ideal([g - S(j) for (g,j) in zip(new_gens, J)]) + z = S(self).reduce(I) + return set(z.variables()).issubset(new_gens) + else: + raise ValueError("unknown algorithm") + def unpickle_MPolynomial_libsingular(MPolynomialRing_libsingular R, d): """ diff --git a/src/sage/rings/polynomial/multi_polynomial_ring.py b/src/sage/rings/polynomial/multi_polynomial_ring.py index f0381318b30..f61d3103fa8 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring.py +++ b/src/sage/rings/polynomial/multi_polynomial_ring.py @@ -31,9 +31,9 @@ sage: frob = R.hom([x^5, y^5, z^5]) sage: frob(x^2 + 2*y - z^4) -z^20 + x^10 + 2*y^5 - sage: frob((x + 2*y)^3) + sage: frob((x + 2*y)^3) # needs sage.rings.finite_rings x^15 + x^10*y^5 + 2*x^5*y^10 - 2*y^15 - sage: (x^5 + 2*y^5)^3 + sage: (x^5 + 2*y^5)^3 # needs sage.rings.finite_rings x^15 + x^10*y^5 + 2*x^5*y^10 - 2*y^15 We make a polynomial ring in one variable over a polynomial ring in @@ -63,8 +63,6 @@ from sage.rings.ring import IntegralDomain import sage.rings.fraction_field_element as fraction_field_element -import sage.rings.polynomial.multi_polynomial_ideal as multi_polynomial_ideal - from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base, is_MPolynomialRing from sage.rings.polynomial.polynomial_singular_interface import PolynomialRing_singular_repr from sage.rings.polynomial.polydict import PolyDict, ETuple @@ -72,7 +70,10 @@ import sage.interfaces.abc -from sage.libs.pari.all import pari_gen +try: + from sage.libs.pari.all import pari_gen +except ImportError: + pari_gen = () from sage.structure.element import Element @@ -248,6 +249,7 @@ def __call__(self, x=0, check=True): Conversion from symbolic variables:: + sage: # needs sage.symbolic sage: x,y,z = var('x,y,z') sage: R = QQ['x,y,z'] sage: type(x) @@ -266,6 +268,7 @@ def __call__(self, x=0, check=True): :: + sage: # needs sage.symbolic sage: R = QQ['x,y,z'] sage: f = (x^3 + y^3 - z^3)^10; f (x^3 + y^3 - z^3)^10 @@ -375,16 +378,16 @@ def __call__(self, x=0, check=True): sage: A.<a> = PolynomialRing(QQ) sage: B.<d,e> = PolynomialRing(A) - sage: f = pari(a*d) + sage: f = pari(a*d) # needs sage.libs.pari sage: B(f) a*d - sage: f = pari(a*d - (a+1)*d*e^3 + a*d^2) + sage: f = pari(a*d - (a+1)*d*e^3 + a*d^2) # needs sage.libs.pari sage: B(f) (-a - 1)*d*e^3 + a*d^2 + a*d sage: A.<a,b> = PolynomialRing(QQ) sage: B.<d,e> = PolynomialRing(A) - sage: f = pari(a*d) + sage: f = pari(a*d) # needs sage.libs.pari sage: B(f) a*d @@ -402,7 +405,7 @@ def __call__(self, x=0, check=True): Check that :trac:`21999` is fixed:: - sage: R = QQbar['s,t'] + sage: R = QQbar['s,t'] # needs sage.rings.number_field sage: type(R({(1,2): 3}).coefficients()[0]) <class 'sage.rings.qqbar.AlgebraicNumber'> """ @@ -420,7 +423,7 @@ def __call__(self, x=0, check=True): except TypeError: pass - from .multi_polynomial_libsingular import MPolynomial_libsingular + from .multi_polynomial import MPolynomial_libsingular if isinstance(x, MPolynomial_polydict): P = x.parent() @@ -639,9 +642,7 @@ def monomial_quotient(self, f, g, coeff=False): res = f.esub(g) - return MPolynomial_polydict(self, PolyDict({res: coeff}, - force_int_exponents=False, - force_etuples=False)) + return MPolynomial_polydict(self, PolyDict({res: coeff})) def monomial_lcm(self, f, g): """ @@ -690,8 +691,7 @@ def monomial_lcm(self, f, g): res = {i: max(f[i], g[i]) for i in f.common_nonzero_positions(g)} - return self(PolyDict({ETuple(res, length): one}, - force_int_exponents=False, force_etuples=False)) + return self(PolyDict({ETuple(res, length): one})) def monomial_reduce(self, f, G): r""" @@ -796,7 +796,7 @@ def monomial_divides(self, a, b): def monomial_pairwise_prime(self, h, g): r""" - Return True if ``h`` and ``g`` are pairwise prime. + Return ``True`` if ``h`` and ``g`` are pairwise prime. Both are treated as monomials. @@ -891,11 +891,37 @@ def addwithcarry(tempvector, maxvector, pos): while tempvector != maxvector: tempvector = addwithcarry(list(tempvector), maxvector, pos) - M.append(R(PolyDict({ETuple(tempvector): one}, - force_int_exponents=False, - force_etuples=False))) + M.append(R(PolyDict({ETuple(tempvector): one}))) return M + def sum(self, terms): + r""" + Return a sum of elements of this multipolynomial ring. + + This is method is much faster than the Python builtin :func:`sum`. + + EXAMPLES:: + + sage: R = QQ['x'] + sage: S = R['y, z'] + sage: x = R.gen() + sage: y, z = S.gens() + sage: S.sum([x*y, 2*x^2*z - 2*x*y, 1 + y + z]) + (-x + 1)*y + (2*x^2 + 1)*z + 1 + + Comparison with builtin :func:`sum`:: + + sage: sum([x*y, 2*x^2*z - 2*x*y, 1 + y + z]) + (-x + 1)*y + (2*x^2 + 1)*z + 1 + """ + elt = PolyDict({}, check=False) + for t in terms: + elt += self(t).element() + # NOTE: here we should be using self.element_class but polynomial rings are not complient + # with categories... + from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict + return MPolynomial_polydict(self, elt) + class MPolynomialRing_polydict_domain(IntegralDomain, MPolynomialRing_polydict): @@ -927,6 +953,9 @@ def ideal(self, *gens, **kwds): if not self._has_singular: # pass through MPolynomialRing_base.ideal(self, gens, **kwds) + + from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal + if isinstance(gens, (sage.interfaces.abc.SingularElement, sage.interfaces.abc.Macaulay2Element)): gens = list(gens) do_coerce = True @@ -934,4 +963,4 @@ def ideal(self, *gens, **kwds): gens = [gens] if ('coerce' in kwds and kwds['coerce']) or do_coerce: gens = [self(x) for x in gens] # this will even coerce from singular ideals correctly! - return multi_polynomial_ideal.MPolynomialIdeal(self, gens, **kwds) + return MPolynomialIdeal(self, gens, **kwds) diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd b/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd index 7e713c01dac..eb6f8b70917 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd @@ -2,10 +2,14 @@ cimport sage.rings.ring from sage.structure.parent cimport Parent cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): - cdef object __ngens - cdef object __term_order + cdef object _ngens + cdef object _term_order cdef public object _has_singular cdef public object _magma_gens cdef public dict _magma_cache cdef _coerce_c_impl(self, x) + + +cdef class BooleanPolynomialRing_base(MPolynomialRing_base): + pass diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index 6e8ca561e2a..c8f66508cc2 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -2,10 +2,7 @@ r""" Base class for multivariate polynomial rings """ import itertools -import warnings from collections.abc import Iterable -from sage.matrix.constructor import matrix -from sage.modules.free_module_element import vector import sage.misc.latex from sage.misc.cachefunc import cached_method @@ -23,14 +20,9 @@ _CommutativeRings = CommutativeRings() from sage.arith.misc import binomial -from sage.combinat.integer_vector import IntegerVectors - from sage.rings.integer_ring import ZZ -from .polydict import PolyDict -from . import (multi_polynomial_ideal, - polynomial_ring, - multi_polynomial_element) +from . import polynomial_ring from .term_order import TermOrder from .polynomial_ring_constructor import (PolynomialRing, polynomial_default_category) @@ -74,10 +66,10 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): Check that :trac:`26958` is fixed:: - sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular - sage: class Foo(MPolynomialRing_libsingular): + sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular # needs sage.libs.singular + sage: class Foo(MPolynomialRing_libsingular): # needs sage.libs.singular ....: pass - sage: Foo(QQ, 2, ['x','y'], 'degrevlex') + sage: Foo(QQ, 2, ['x','y'], 'degrevlex') # needs sage.libs.singular Multivariate Polynomial Ring in x, y over Rational Field """ if base_ring not in _CommutativeRings: @@ -88,8 +80,8 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): raise ValueError("Multivariate Polynomial Rings must " "have more than 0 variables.") order = TermOrder(order, n) - self.__ngens = n - self.__term_order = order + self._ngens = n + self._term_order = order self._has_singular = False # cannot convert to Singular by default self._magma_cache = {} # Ring.__init__ already does assign the names. @@ -133,14 +125,13 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: QQ['a','b']['x','y'].flattening_morphism() Flattening morphism: - From: Multivariate Polynomial Ring in x, y over Multivariate - Polynomial Ring in a, b over Rational Field - To: Multivariate Polynomial Ring in a, b, x, y over Rational - Field + From: Multivariate Polynomial Ring in x, y + over Multivariate Polynomial Ring in a, b over Rational Field + To: Multivariate Polynomial Ring in a, b, x, y over Rational Field sage: QQ['x,y'].flattening_morphism() - Identity endomorphism of Multivariate Polynomial Ring in x, y - over Rational Field + Identity endomorphism of + Multivariate Polynomial Ring in x, y over Rational Field """ base = self.base_ring() if is_MPolynomialRing(base) or polynomial_ring.is_PolynomialRing(base): @@ -151,7 +142,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): def construction(self): """ - Returns a functor F and base ring R such that F(R) == self. + Returns a functor ``F`` and base ring ``R`` such that ``F(R) == self``. EXAMPLES:: @@ -186,51 +177,59 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): """ return self.ideal(self.gens(), check=False) - def completion(self, names, prec=20, extras={}): - """ - Return the completion of self with respect to the ideal + def completion(self, names=None, prec=20, extras={}, **kwds): + r""" + Return the completion of ``self`` with respect to the ideal generated by the variable(s) ``names``. INPUT: - - ``names`` -- variable or list/tuple of variables (given either - as elements of the polynomial ring or as strings) - - - ``prec`` -- default precision of resulting power series ring - - - ``extras`` -- passed as keywords to ``PowerSeriesRing`` + - ``names`` -- (optional) variable or list/tuple of variables + (given either as elements of the polynomial ring or as strings); + the default is all variables of ``self`` + - ``prec`` -- default precision of resulting power series ring, + possibly infinite + - ``extras`` -- passed as keywords to :class:`PowerSeriesRing` + or :class:`LazyPowerSeriesRing`; can also be keyword arguments EXAMPLES:: sage: P.<x,y,z,w> = PolynomialRing(ZZ) sage: P.completion('w') Power Series Ring in w over Multivariate Polynomial Ring in - x, y, z over Integer Ring + x, y, z over Integer Ring sage: P.completion((w,x,y)) - Multivariate Power Series Ring in w, x, y over Univariate - Polynomial Ring in z over Integer Ring + Multivariate Power Series Ring in w, x, y over + Univariate Polynomial Ring in z over Integer Ring sage: Q.<w,x,y,z> = P.completion(); Q Multivariate Power Series Ring in w, x, y, z over Integer Ring sage: H = PolynomialRing(PolynomialRing(ZZ,3,'z'),4,'f'); H Multivariate Polynomial Ring in f0, f1, f2, f3 over - Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring + Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring sage: H.completion(H.gens()) Multivariate Power Series Ring in f0, f1, f2, f3 over - Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring + Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring sage: H.completion(H.gens()[2]) Power Series Ring in f2 over - Multivariate Polynomial Ring in f0, f1, f3 over - Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring + Multivariate Polynomial Ring in f0, f1, f3 over + Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring + + sage: P.<x,y,z,w> = PolynomialRing(ZZ) + sage: P.completion(prec=oo) # needs sage.combinat + Multivariate Lazy Taylor Series Ring in x, y, z, w over Integer Ring + sage: P.completion((w,x,y), prec=oo) # needs sage.combinat + Multivariate Lazy Taylor Series Ring in w, x, y over + Univariate Polynomial Ring in z over Integer Ring TESTS:: sage: P.<x,y> = PolynomialRing(ZZ) sage: P.completion([]) is P True - sage: P.completion(SR.var('x')) + sage: P.completion(SR.var('x')) # needs sage.symbolic Traceback (most recent call last): ... TypeError: x is not an element of Multivariate Polynomial Ring @@ -246,7 +245,9 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): ValueError: q is not a variable of Multivariate Polynomial Ring in x, y over Integer Ring """ - if not isinstance(names, (list, tuple)): + if names is None: + names = self.variable_names() + elif not isinstance(names, (list, tuple)): names = [names] # Single variable elif not names: return self # 0 variables => completion is self @@ -265,13 +266,16 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): raise ValueError(f"{v} is not a variable of {self}") vars.append(v) - from sage.rings.power_series_ring import PowerSeriesRing new_base = self.remove_var(*vars) - return PowerSeriesRing(new_base, names=vars, default_prec=prec, **extras) + if prec == float('inf'): + from sage.rings.lazy_series_ring import LazyPowerSeriesRing + return LazyPowerSeriesRing(new_base, names=vars, **extras, **kwds) + from sage.rings.power_series_ring import PowerSeriesRing + return PowerSeriesRing(new_base, names=vars, default_prec=prec, **extras, **kwds) def remove_var(self, *var, order=None): """ - Remove a variable or sequence of variables from self. + Remove a variable or sequence of variables from ``self``. If ``order`` is not specified, then the subring inherits the term order of the original ring, if possible. @@ -281,14 +285,14 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: P.<x,y,z,w> = PolynomialRing(ZZ) sage: P.remove_var(z) Multivariate Polynomial Ring in x, y, w over Integer Ring - sage: P.remove_var(z,x) + sage: P.remove_var(z, x) Multivariate Polynomial Ring in y, w over Integer Ring - sage: P.remove_var(y,z,x) + sage: P.remove_var(y, z, x) Univariate Polynomial Ring in w over Integer Ring Removing all variables results in the base ring:: - sage: P.remove_var(y,z,x,w) + sage: P.remove_var(y, z, x, w) Integer Ring If possible, the term order is kept:: @@ -304,7 +308,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): Be careful with block orders when removing variables:: sage: R.<x,y,z,u,v> = PolynomialRing(ZZ, order='deglex(2),lex(3)') - sage: R.remove_var(x,y,z) + sage: R.remove_var(x, y, z) Traceback (most recent call last): ... ValueError: impossible to use the original term order (most @@ -332,18 +336,18 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): def univariate_ring(self, x): """ Return a univariate polynomial ring whose base ring comprises all - but one variables of self. + but one variables of ``self``. INPUT: - - ``x`` -- a variable of self. + - ``x`` -- a variable of ``self``. EXAMPLES:: sage: P.<x,y,z> = QQ[] sage: P.univariate_ring(y) - Univariate Polynomial Ring in y over Multivariate Polynomial - Ring in x, z over Rational Field + Univariate Polynomial Ring in y + over Multivariate Polynomial Ring in x, z over Rational Field """ return self.remove_var(x)[str(x)] @@ -355,9 +359,9 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): This function can be called in two ways: - 1. interpolation(bound, points, values) + 1. ``interpolation(bound, points, values)`` - 2. interpolation(bound, function) + 2. ``interpolation(bound, function)`` INPUT: @@ -386,18 +390,16 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): ....: return a^3*b + b + c^2 + 25 ....: sage: R.<x,y,z> = PolynomialRing(QQ) - sage: R.interpolation(4, F) + sage: R.interpolation(4, F) # needs sage.modules x^3*y + z^2 + y + 25 - sage: def F(a,b,c): ....: return a^3*b + b + c^2 + 25 ....: sage: R.<x,y,z> = PolynomialRing(QQ) - sage: R.interpolation([3,1,2], F) + sage: R.interpolation([3,1,2], F) # needs sage.modules x^3*y + z^2 + y + 25 - sage: def F(a,b,c): ....: return a^3*b + b + c^2 + 25 ....: @@ -406,7 +408,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): ....: (2,7,0),(1,10,13),(0,0,1),(-1,1,0),(2,5,3),(1,1,1),(7,4,11), ....: (12,1,9),(1,1,3),(4,-1,2),(0,1,5),(5,1,3),(3,1,-2),(2,11,3), ....: (4,12,19),(3,1,1),(5,2,-3),(12,1,1),(2,3,4)] - sage: R.interpolation([3,1,2], points, [F(*x) for x in points]) + sage: R.interpolation([3,1,2], points, [F(*x) for x in points]) # needs sage.modules x^3*y + z^2 + y + 25 ALGORITHM: @@ -425,7 +427,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): without any notice that there are more. Lastly, the interpolation function for univariate polynomial rings - is called ``lagrange_polynomial()``. + is called :meth:`lagrange_polynomial`. .. WARNING:: @@ -434,19 +436,22 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): the given bounds. In particular it will *not* notice or check whether the result yields the correct evaluation for other points as well. So if you give wrong bounds, you will get a wrong answer - without any warning. + without any warning. :: - sage: def F(a,b,c): - ....: return a^3*b + b + c^2 + 25 - ....: - sage: R.<x,y,z> = PolynomialRing(QQ) - sage: R.interpolation(3,F) - 1/2*x^3 + x*y + z^2 - 1/2*x + y + 25 + sage: def F(a,b,c): + ....: return a^3*b + b + c^2 + 25 + ....: + sage: R.<x,y,z> = PolynomialRing(QQ) + sage: R.interpolation(3, F) # needs sage.modules + 1/2*x^3 + x*y + z^2 - 1/2*x + y + 25 .. SEEALSO:: :meth:`lagrange_polynomial<sage.rings.polynomial.polynomial_ring.PolynomialRing_field.lagrange_polynomial>` """ + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + # get ring and number of variables R = self.base_ring() n = self.ngens() @@ -569,10 +574,11 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): This fairly complicated code (from Michel Vandenbergh) ends up implicitly calling ``_coerce_c_impl``:: + sage: # needs sage.rings.number_field sage: z = polygen(QQ, 'z') - sage: W.<s>=NumberField(z^2+1) + sage: W.<s> = NumberField(z^2 + 1) sage: Q.<u,v,w> = W[] - sage: W1 = FractionField (Q) + sage: W1 = FractionField(Q) sage: S.<x,y,z> = W1[] sage: u + x x + u @@ -633,12 +639,12 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): lft = <MPolynomialRing_base>left other = <MPolynomialRing_base>right - lx = (lft.base_ring(), lft.__ngens, + lx = (lft.base_ring(), lft._ngens, lft.variable_names(), - lft.__term_order) - rx = (other.base_ring(), other.__ngens, + lft._term_order) + rx = (other.base_ring(), other._ngens, other.variable_names(), - other.__term_order) + other._term_order) return richcmp(lx, rx, op) def _repr_(self): @@ -666,7 +672,8 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(QQ,order=TermOrder('degrevlex',1)+TermOrder('lex',2)) + sage: P.<x,y,z> = PolynomialRing(QQ, order=TermOrder('degrevlex',1) + ....: + TermOrder('lex',2)) sage: print(P.repr_long()) Polynomial Ring Base Ring : Rational Field @@ -698,12 +705,14 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): return "%s[%s]" % (sage.misc.latex.latex(self.base_ring()), vars) def _ideal_class_(self, n=0): - return multi_polynomial_ideal.MPolynomialIdeal + from .multi_polynomial_ideal import MPolynomialIdeal + return MPolynomialIdeal def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): """ EXAMPLES:: + sage: # needs sage.rings.number_field sage: T.<t> = ZZ[] sage: K.<i> = NumberField(t^2 + 1) sage: R.<x,y> = K[] @@ -727,38 +736,39 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): EXAMPLES:: + sage: # optional - magma sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127),10) - sage: R._magma_init_(magma) # optional - magma + sage: R._magma_init_(magma) 'SageCreateWithNames(PolynomialRing(_sage_ref...,10,"grevlex"),["a","b","c","d","e","f","g","h","i","j"])' - sage: R.<y,z,w> = PolynomialRing(QQ,3) - sage: magma(R) # optional - magma + sage: R.<y,z,w> = PolynomialRing(QQ, 3) + sage: magma(R) Polynomial ring of rank 3 over Rational Field Order: Graded Reverse Lexicographical Variables: y, z, w A complicated nested example:: + sage: # optional - magma, needs sage.rings.finite_rings sage: R.<a,b,c> = PolynomialRing(GF(9,'a')); S.<T,W> = R[]; S Multivariate Polynomial Ring in T, W over Multivariate Polynomial Ring in a, b, c over Finite Field in a of size 3^2 - sage: magma(S) # optional - magma + sage: magma(S) Polynomial ring of rank 2 over Polynomial ring of rank 3 over GF(3^2) Order: Graded Reverse Lexicographical Variables: T, W - sage: magma(PolynomialRing(GF(7),4, 'x')) # optional - magma + sage: # optional - magma + sage: magma(PolynomialRing(GF(7),4, 'x')) Polynomial ring of rank 4 over GF(7) Order: Graded Reverse Lexicographical Variables: x0, x1, x2, x3 - - sage: magma(PolynomialRing(GF(49,'a'),10, 'x')) # optional - magma + sage: magma(PolynomialRing(GF(49,'a'),10, 'x')) # needs sage.rings.finite_rings Polynomial ring of rank 10 over GF(7^2) Order: Graded Reverse Lexicographical Variables: x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 - - sage: magma(PolynomialRing(ZZ['a,b,c'],3, 'x')) # optional - magma + sage: magma(PolynomialRing(ZZ['a,b,c'],3, 'x')) Polynomial ring of rank 3 over Polynomial ring of rank 3 over Integer Ring Order: Graded Reverse Lexicographical @@ -787,6 +797,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): EXAMPLES:: + sage: # needs sage.rings.number_field sage: F = CyclotomicField(8) sage: P.<x,y> = F[] sage: gap(P) # indirect doctest @@ -838,7 +849,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): return False def term_order(self): - return self.__term_order + return self._term_order def characteristic(self): """ @@ -849,14 +860,14 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: R = PolynomialRing(QQ, 'x', 3) sage: R.characteristic() 0 - sage: R = PolynomialRing(GF(7),'x', 20) + sage: R = PolynomialRing(GF(7), 'x', 20) sage: R.characteristic() 7 """ return self.base_ring().characteristic() def gen(self, n=0): - if n < 0 or n >= self.__ngens: + if n < 0 or n >= self._ngens: raise ValueError("Generator not defined.") return self._gens[int(n)] @@ -916,7 +927,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): return self.base_ring().krull_dimension() + self.ngens() def ngens(self): - return self.__ngens + return self._ngens def _monomial_order_function(self): raise NotImplementedError @@ -1044,7 +1055,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): ....: return 1.0/(8*total) sage: more_samples() - sage: while any(abs(prob(i) - dic[i]/counter) > 0.01 for i in dic): + sage: while any(abs(prob(i) - dic[i]/counter) > 0.01 for i in dic): # needs sage.symbolic ....: more_samples() """ # bug: doesn't handle n=1 @@ -1167,12 +1178,12 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): Default values apply if no degree and/or number of terms is provided:: + sage: # needs sage.modules sage: M = random_matrix(QQ['x,y,z'], 2, 2) sage: all(a.degree() <= 2 for a in M.list()) True sage: all(len(list(a)) <= 5 for a in M.list()) True - sage: M = random_matrix(QQ['x,y,z'], 2, 2, terms=1, degree=2) sage: all(a.degree() <= 2 for a in M.list()) True @@ -1310,9 +1321,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: R.<x,y> = QQ[] sage: R.some_elements() [x, y, x + y, x^2 + x*y, 0, 1] - """ - R = self.base_ring() L = list(self.gens()) if L: L.append(L[0] + L[-1]) @@ -1322,9 +1331,9 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): def change_ring(self, base_ring=None, names=None, order=None): """ - Return a new multivariate polynomial ring which isomorphic to - self, but has a different ordering given by the parameter - 'order' or names given by the parameter 'names'. + Return a new multivariate polynomial ring which is isomorphic to + ``self``, but has a different ordering given by the parameter + ``order`` or names given by the parameter ``names``. INPUT: @@ -1334,7 +1343,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(GF(127),3,order='lex') + sage: P.<x,y,z> = PolynomialRing(GF(127), 3, order='lex') sage: x > y^2 True sage: Q.<x,y,z> = P.change_ring(order='degrevlex') @@ -1376,19 +1385,32 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): EXAMPLES:: + sage: # needs sage.combinat sage: R.<x,y,z> = ZZ[] sage: mons = R.monomials_of_degree(2) sage: mons - [x^2, x*y, x*z, y^2, y*z, z^2] + [z^2, y*z, x*z, y^2, x*y, x^2] + sage: P = PolynomialRing(QQ, 3, 'x, y, z', order=TermOrder('wdeglex', [1, 2, 1])) + sage: P.monomials_of_degree(2) + [z^2, y, x*z, x^2] + sage: P = PolynomialRing(QQ, 3, 'x, y, z', order='lex') + sage: P.monomials_of_degree(3) + [z^3, y*z^2, y^2*z, y^3, x*z^2, x*y*z, x*y^2, x^2*z, x^2*y, x^3] + sage: P = PolynomialRing(QQ, 3, 'x, y, z', order='invlex') + sage: P.monomials_of_degree(3) + [x^3, x^2*y, x*y^2, y^3, x^2*z, x*y*z, y^2*z, x*z^2, y*z^2, z^3] The number of such monomials equals `\binom{n+k-1}{k}` where `n` is the number of variables and `k` the degree:: - sage: len(mons) == binomial(3+2-1,2) + sage: len(mons) == binomial(3 + 2 - 1, 2) # needs sage.combinat True """ - from sage.combinat.integer_vector import IntegerVectors - return [self.monomial(*a) for a in IntegerVectors(degree, self.ngens())] + deg_of_gens = [x.degree() for x in self.gens()] + from sage.combinat.integer_vector_weighted import WeightedIntegerVectors + mons = [self.monomial(*a) for a in WeightedIntegerVectors(degree, deg_of_gens)] + mons.sort() # This could be implemented in WeightedIntegerVectors instead + return mons def _macaulay_resultant_getS(self, mon_deg_tuple, dlist): r""" @@ -1482,6 +1504,8 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): Polynomial Ring in u0, u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11 over Integer Ring) """ + from sage.combinat.integer_vector import IntegerVectors + n = len(dlist) - 1 number_of_coeffs = sum([binomial(n + di, di) for di in dlist]) U = PolynomialRing(ZZ, 'u', number_of_coeffs) @@ -1502,7 +1526,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): def macaulay_resultant(self, *args, **kwds): r""" - This is an implementation of the Macaulay Resultant. It computes + This is an implementation of the Macaulay resultant. It computes the resultant of universal polynomials as well as polynomials with constant coefficients. This is a project done in sage days 55. It's based on the implementation in Maple by @@ -1525,17 +1549,17 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): INPUT: - ``args`` -- a list of `n` homogeneous polynomials in `n` variables. - works when ``args[0]`` is the list of polynomials, - or ``args`` is itself the list of polynomials + works when ``args[0]`` is the list of polynomials, + or ``args`` is itself the list of polynomials kwds: - ``sparse`` -- boolean (optional - default: ``False``) - if ``True`` function creates sparse matrices. + if ``True``, the function creates sparse matrices. OUTPUT: - - the macaulay resultant, an element of the base ring of ``self`` + - the Macaulay resultant, an element of the base ring of ``self`` .. TODO:: Working with sparse matrices should usually give faster results, @@ -1546,27 +1570,25 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): The number of polynomials has to match the number of variables:: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: R.macaulay_resultant([y,x+z]) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: R.macaulay_resultant([y, x + z]) # needs sage.modules Traceback (most recent call last): ... - TypeError: number of polynomials(= 2) must equal number of - variables (= 3) + TypeError: number of polynomials(= 2) must equal number of variables (= 3) The polynomials need to be all homogeneous:: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: R.macaulay_resultant([y, x+z, z+x^3]) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: R.macaulay_resultant([y, x + z, z + x^3]) # needs sage.modules Traceback (most recent call last): ... - TypeError: resultant for non-homogeneous polynomials is - not supported + TypeError: resultant for non-homogeneous polynomials is not supported All polynomials must be in the same ring:: sage: S.<x,y> = PolynomialRing(QQ, 2) sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: S.macaulay_resultant([y, z+x]) + sage: S.macaulay_resultant([y, z+x]) # needs sage.modules Traceback (most recent call last): ... TypeError: not all inputs are polynomials in the calling ring @@ -1574,8 +1596,8 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): The following example recreates Proposition 2.10 in Ch.3 in [CLO2005]:: sage: K.<x,y> = PolynomialRing(ZZ, 2) - sage: flist,R = K._macaulay_resultant_universal_polynomials([1,1,2]) - sage: R.macaulay_resultant(flist) + sage: flist, R = K._macaulay_resultant_universal_polynomials([1,1,2]) + sage: R.macaulay_resultant(flist) # needs sage.modules u2^2*u4^2*u6 - 2*u1*u2*u4*u5*u6 + u1^2*u5^2*u6 - u2^2*u3*u4*u7 + u1*u2*u3*u5*u7 + u0*u2*u4*u5*u7 - u0*u1*u5^2*u7 + u1*u2*u3*u4*u8 - u0*u2*u4^2*u8 - u1^2*u3*u5*u8 + u0*u1*u4*u5*u8 + u2^2*u3^2*u9 - @@ -1584,11 +1606,11 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): u1^2*u3^2*u11 - 2*u0*u1*u3*u4*u11 + u0^2*u4^2*u11 The following example degenerates into the determinant of - a `3*3` matrix:: + a `3\times 3` matrix:: sage: K.<x,y> = PolynomialRing(ZZ, 2) sage: flist,R = K._macaulay_resultant_universal_polynomials([1,1,1]) - sage: R.macaulay_resultant(flist) + sage: R.macaulay_resultant(flist) # needs sage.modules -u2*u4*u6 + u1*u5*u6 + u2*u3*u7 - u0*u5*u7 - u1*u3*u8 + u0*u4*u8 The following example is by Patrick Ingram (:arxiv:`1310.4114`):: @@ -1599,62 +1621,63 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: f1 = y1*x2^2 - x1^2 + 2*x0*x2 sage: f2 = x0*x1 - x2^2 sage: flist = [f0,f1,f2] - sage: R.macaulay_resultant([f0,f1,f2]) + sage: R.macaulay_resultant([f0,f1,f2]) # needs sage.modules y0^2*y1^2 - 4*y0^3 - 4*y1^3 + 18*y0*y1 - 27 A simple example with constant rational coefficients:: - sage: R.<x,y,z,w> = PolynomialRing(QQ,4) - sage: R.macaulay_resultant([w,z,y,x]) + sage: R.<x,y,z,w> = PolynomialRing(QQ, 4) + sage: R.macaulay_resultant([w, z, y, x]) # needs sage.modules 1 An example where the resultant vanishes:: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: R.macaulay_resultant([x+y,y^2,x]) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: R.macaulay_resultant([x + y, y^2, x]) # needs sage.modules 0 An example of bad reduction at a prime `p = 5`:: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: R.macaulay_resultant([y,x^3+25*y^2*x,5*z]) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: R.macaulay_resultant([y, x^3 + 25*y^2*x, 5*z]) # needs sage.libs.pari sage.modules 125 The input can given as an unpacked list of polynomials:: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: R.macaulay_resultant(y,x^3+25*y^2*x,5*z) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: R.macaulay_resultant(y, x^3 + 25*y^2*x, 5*z) # needs sage.libs.pari sage.modules 125 An example when the coefficients live in a finite field:: sage: F = FiniteField(11) - sage: R.<x,y,z,w> = PolynomialRing(F,4) - sage: R.macaulay_resultant([z,x^3,5*y,w]) + sage: R.<x,y,z,w> = PolynomialRing(F, 4) + sage: R.macaulay_resultant([z, x^3, 5*y, w]) # needs sage.modules sage.rings.finite_rings 4 Example when the denominator in the algorithm vanishes(in this case the resultant is the constant term of the quotient of char polynomials of numerator/denominator):: - sage: R.<x,y,z> = PolynomialRing(QQ,3) - sage: R.macaulay_resultant([y, x+z, z^2]) + sage: R.<x,y,z> = PolynomialRing(QQ, 3) + sage: R.macaulay_resultant([y, x + z, z^2]) # needs sage.libs.pari sage.modules -1 - When there are only 2 polynomials, macaulay resultant degenerates + When there are only 2 polynomials, the Macaulay resultant degenerates to the traditional resultant:: - sage: R.<x> = PolynomialRing(QQ,1) - sage: f = x^2+1; g = x^5+1 + sage: R.<x> = PolynomialRing(QQ, 1) + sage: f = x^2 + 1; g = x^5 + 1 sage: fh = f.homogenize() sage: gh = g.homogenize() sage: RH = fh.parent() - sage: f.resultant(g) == RH.macaulay_resultant([fh,gh]) + sage: f.resultant(g) == RH.macaulay_resultant([fh, gh]) # needs sage.modules True """ from sage.matrix.constructor import matrix from sage.matrix.constructor import zero_matrix + from sage.combinat.integer_vector import IntegerVectors if len(args) == 1 and isinstance(args[0], list): flist = args[0] @@ -1683,7 +1706,6 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): mons_idx = {str(mon): idx for idx, mon in enumerate(mons)} mons_num = len(mons) mons_to_keep = [] - newflist = [] # strip coefficients of the input polynomials: flist = [[f.exponents(), f.coefficients()] for f in flist] numer_matrix = zero_matrix(self.base_ring(), mons_num, sparse=sparse) @@ -1729,15 +1751,37 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): EXAMPLES:: sage: R = QQ['x,y,z'] - sage: W = R.weyl_algebra(); W + sage: W = R.weyl_algebra(); W # needs sage.modules Differential Weyl algebra of polynomials in x, y, z over Rational Field - sage: W.polynomial_ring() == R + sage: W.polynomial_ring() == R # needs sage.modules True """ from sage.algebras.weyl_algebra import DifferentialWeylAlgebra return DifferentialWeylAlgebra(self) +cdef class BooleanPolynomialRing_base(MPolynomialRing_base): + r""" + Abstract base class for :class:`~sage.rings.polynomial.pbori.pbori.BooleanPolynomialRing`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: from sage.rings.polynomial.multi_polynomial_ring_base import BooleanPolynomialRing_base + sage: R.<x, y, z> = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: isinstance(R, BooleanPolynomialRing_base) # needs sage.rings.polynomial.pbori + True + + By design, there is only one direct implementation subclass:: + + sage: len(BooleanPolynomialRing_base.__subclasses__()) <= 1 + True + """ + pass + + #################### # Leave *all* old versions! diff --git a/src/sage/rings/polynomial/multi_polynomial_sequence.py b/src/sage/rings/polynomial/multi_polynomial_sequence.py index 10c3582d79f..19c53c392b2 100644 --- a/src/sage/rings/polynomial/multi_polynomial_sequence.py +++ b/src/sage/rings/polynomial/multi_polynomial_sequence.py @@ -23,24 +23,24 @@ As an example consider a small scale variant of the AES:: - sage: sr = mq.SR(2,1,2,4,gf2=True,polybori=True) - sage: sr + sage: sr = mq.SR(2, 1, 2, 4, gf2=True, polybori=True) # needs sage.rings.polynomial.pbori + sage: sr # needs sage.rings.polynomial.pbori SR(2,1,2,4) We can construct a polynomial sequence for a random plaintext-ciphertext pair and study it:: sage: set_random_seed(1) - sage: while True: # workaround (see :trac:`31891`) + sage: while True: # workaround (see :trac:`31891`) # needs sage.rings.polynomial.pbori ....: try: ....: F, s = sr.polynomial_system() ....: break ....: except ZeroDivisionError: ....: pass - sage: F + sage: F # needs sage.rings.polynomial.pbori Polynomial Sequence with 112 Polynomials in 64 Variables - sage: r2 = F.part(2); r2 + sage: r2 = F.part(2); r2 # needs sage.rings.polynomial.pbori (w200 + k100 + x100 + x102 + x103, w201 + k101 + x100 + x101 + x103 + 1, w202 + k102 + x100 + x101 + x102 + 1, @@ -76,69 +76,71 @@ We separate the system in independent subsystems:: - sage: C = Sequence(r2).connected_components(); C - [[w213 + k113 + x111 + x112 + x113, - w212 + k112 + x110 + x111 + x112 + 1, - w211 + k111 + x110 + x111 + x113 + 1, - w210 + k110 + x110 + x112 + x113, - x110*w112 + x111*w111 + x112*w110 + x113*w113 + 1, - x110*w112 + x111*w110 + x111*w111 + x111*w113 + x112*w111 + x113*w110 + x113*w112 + w111, - x110*w111 + x111*w110 + x111*w112 + x112*w110 + x113*w111 + x113*w113 + w113, - x110*w111 + x110*w113 + x111*w111 + x111*w112 + x112*w110 + x112*w113 + x113*w111 + x111, - x110*w111 + x110*w112 + x111*w110 + x111*w113 + x112*w111 + x113*w113 + x113, - x110*w111 + x110*w112 + x111*w110 + x111*w111 + x112*w110 + x112*w113 + x113*w112, - x110*w110 + x110*w113 + x111*w112 + x112*w111 + x113*w110, - x110*w110 + x110*w112 + x111*w110 + x111*w112 + x111*w113 + x112*w110 + x112*w111 + x113*w112 + x112, - x110*w110 + x110*w112 + x110*w113 + x111*w110 + x111*w111 + x112*w112 + x113*w110 + x110, - x110*w110 + x110*w111 + x111*w110 + x111*w113 + x112*w112 + x113*w111, - x110*w110 + x110*w111 + x110*w113 + x111*w111 + x112*w110 + x112*w112 + x113*w110 + w110, - x110*w110 + x110*w111 + x110*w112 + x111*w112 + x112*w110 + x112*w111 + x112*w113 + x113*w111 + w112], - [w203 + k103 + x101 + x102 + x103, - w202 + k102 + x100 + x101 + x102 + 1, - w201 + k101 + x100 + x101 + x103 + 1, - w200 + k100 + x100 + x102 + x103, - x100*w102 + x101*w101 + x102*w100 + x103*w103 + 1, - x100*w102 + x101*w100 + x101*w101 + x101*w103 + x102*w101 + x103*w100 + x103*w102 + w101, - x100*w101 + x101*w100 + x101*w102 + x102*w100 + x103*w101 + x103*w103 + w103, - x100*w101 + x100*w103 + x101*w101 + x101*w102 + x102*w100 + x102*w103 + x103*w101 + x101, - x100*w101 + x100*w102 + x101*w100 + x101*w103 + x102*w101 + x103*w103 + x103, x100*w101 + x100*w102 + x101*w100 + x101*w101 + x102*w100 + x102*w103 + x103*w102, - x100*w100 + x100*w103 + x101*w102 + x102*w101 + x103*w100, - x100*w100 + x100*w102 + x101*w100 + x101*w102 + x101*w103 + x102*w100 + x102*w101 + x103*w102 + x102, - x100*w100 + x100*w102 + x100*w103 + x101*w100 + x101*w101 + x102*w102 + x103*w100 + x100, - x100*w100 + x100*w101 + x101*w100 + x101*w103 + x102*w102 + x103*w101, - x100*w100 + x100*w101 + x100*w103 + x101*w101 + x102*w100 + x102*w102 + x103*w100 + w100, - x100*w100 + x100*w101 + x100*w102 + x101*w102 + x102*w100 + x102*w101 + x102*w103 + x103*w101 + w102]] - sage: C[0].groebner_basis() + sage: C = Sequence(r2).connected_components(); C # needs sage.rings.polynomial.pbori + [[w200 + k100 + x100 + x102 + x103, + w201 + k101 + x100 + x101 + x103 + 1, + w202 + k102 + x100 + x101 + x102 + 1, + w203 + k103 + x101 + x102 + x103, + x100*w100 + x100*w103 + x101*w102 + x102*w101 + x103*w100, + x100*w100 + x100*w101 + x101*w100 + x101*w103 + x102*w102 + x103*w101, + x100*w101 + x100*w102 + x101*w100 + x101*w101 + x102*w100 + x102*w103 + x103*w102, + x100*w100 + x100*w102 + x100*w103 + x101*w100 + x101*w101 + x102*w102 + x103*w100 + x100, + x100*w101 + x100*w103 + x101*w101 + x101*w102 + x102*w100 + x102*w103 + x103*w101 + x101, + x100*w100 + x100*w102 + x101*w100 + x101*w102 + x101*w103 + x102*w100 + x102*w101 + x103*w102 + x102, + x100*w101 + x100*w102 + x101*w100 + x101*w103 + x102*w101 + x103*w103 + x103, + x100*w100 + x100*w101 + x100*w103 + x101*w101 + x102*w100 + x102*w102 + x103*w100 + w100, + x100*w102 + x101*w100 + x101*w101 + x101*w103 + x102*w101 + x103*w100 + x103*w102 + w101, + x100*w100 + x100*w101 + x100*w102 + x101*w102 + x102*w100 + x102*w101 + x102*w103 + x103*w101 + w102, + x100*w101 + x101*w100 + x101*w102 + x102*w100 + x103*w101 + x103*w103 + w103, + x100*w102 + x101*w101 + x102*w100 + x103*w103 + 1], + [w210 + k110 + x110 + x112 + x113, + w211 + k111 + x110 + x111 + x113 + 1, + w212 + k112 + x110 + x111 + x112 + 1, + w213 + k113 + x111 + x112 + x113, + x110*w110 + x110*w113 + x111*w112 + x112*w111 + x113*w110, + x110*w110 + x110*w111 + x111*w110 + x111*w113 + x112*w112 + x113*w111, + x110*w111 + x110*w112 + x111*w110 + x111*w111 + x112*w110 + x112*w113 + x113*w112, + x110*w110 + x110*w112 + x110*w113 + x111*w110 + x111*w111 + x112*w112 + x113*w110 + x110, + x110*w111 + x110*w113 + x111*w111 + x111*w112 + x112*w110 + x112*w113 + x113*w111 + x111, + x110*w110 + x110*w112 + x111*w110 + x111*w112 + x111*w113 + x112*w110 + x112*w111 + x113*w112 + x112, + x110*w111 + x110*w112 + x111*w110 + x111*w113 + x112*w111 + x113*w113 + x113, + x110*w110 + x110*w111 + x110*w113 + x111*w111 + x112*w110 + x112*w112 + x113*w110 + w110, + x110*w112 + x111*w110 + x111*w111 + x111*w113 + x112*w111 + x113*w110 + x113*w112 + w111, + x110*w110 + x110*w111 + x110*w112 + x111*w112 + x112*w110 + x112*w111 + x112*w113 + x113*w111 + w112, + x110*w111 + x111*w110 + x111*w112 + x112*w110 + x113*w111 + x113*w113 + w113, + x110*w112 + x111*w111 + x112*w110 + x113*w113 + 1]] + sage: C[0].groebner_basis() # needs sage.rings.polynomial.pbori Polynomial Sequence with 30 Polynomials in 16 Variables and compute the coefficient matrix:: - sage: A,v = Sequence(r2).coefficient_matrix() - sage: A.rank() + sage: A,v = Sequence(r2).coefficient_matrix() # needs sage.rings.polynomial.pbori + sage: A.rank() # needs sage.rings.polynomial.pbori 32 Using these building blocks we can implement a simple XL algorithm easily:: - sage: sr = mq.SR(1,1,1,4, gf2=True, polybori=True, order='lex') - sage: while True: # workaround (see :trac:`31891`) + sage: sr = mq.SR(1,1,1,4, gf2=True, polybori=True, order='lex') # needs sage.rings.polynomial.pbori + sage: while True: # workaround (see :trac:`31891`) # needs sage.rings.polynomial.pbori ....: try: ....: F, s = sr.polynomial_system() ....: break ....: except ZeroDivisionError: ....: pass - sage: monomials = [a*b for a in F.variables() for b in F.variables() if a<b] + sage: # needs sage.rings.polynomial.pbori + sage: monomials = [a*b for a in F.variables() for b in F.variables() if a < b] sage: len(monomials) 190 sage: F2 = Sequence(map(mul, cartesian_product_iterator((monomials, F)))) - sage: A,v = F2.coefficient_matrix(sparse=False) + sage: A, v = F2.coefficient_matrix(sparse=False) sage: A.echelonize() sage: A - 6840 x 4474 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries) + 6840 x 4474 dense matrix over Finite Field of size 2... sage: A.rank() 4056 - sage: A[4055]*v + sage: A[4055] * v (k001*k003) TESTS:: @@ -160,22 +162,25 @@ """ from sage.misc.cachefunc import cached_method - from sage.misc.converting_dict import KeyConvertingDict - -from sage.structure.sequence import Sequence_generic - -from sage.rings.infinity import Infinity -from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.misc.method_decorator import MethodDecorator from sage.rings.finite_rings.finite_field_base import FiniteField -from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing -from sage.rings.quotient_ring import is_QuotientRing +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.infinity import Infinity from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal +from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.quotient_ring import is_QuotientRing +from sage.structure.sequence import Sequence_generic + + +try: + from sage.interfaces.singular import singular, singular_gb_standard_options + from sage.libs.singular.standard_options import libsingular_gb_standard_options +except ImportError: + singular = None + singular_gb_standard_options = libsingular_gb_standard_options = MethodDecorator -from sage.interfaces.singular import singular_gb_standard_options -from sage.libs.singular.standard_options import libsingular_gb_standard_options -from sage.interfaces.singular import singular def is_PolynomialSequence(F): """ @@ -219,12 +224,12 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): EXAMPLES:: - sage: P.<a,b,c,d> = PolynomialRing(GF(127),4) - sage: I = sage.rings.ideal.Katsura(P) + sage: P.<a,b,c,d> = PolynomialRing(GF(127), 4) + sage: I = sage.rings.ideal.Katsura(P) # needs sage.libs.singular If a list of tuples is provided, those form the parts:: - sage: F = Sequence([I.gens(),I.gens()], I.ring()); F # indirect doctest + sage: F = Sequence([I.gens(),I.gens()], I.ring()); F # indirect doctest # needs sage.libs.singular [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, @@ -233,12 +238,12 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] - sage: F.nparts() + sage: F.nparts() # needs sage.libs.singular 2 If an ideal is provided, the generators are used:: - sage: Sequence(I) + sage: Sequence(I) # needs sage.libs.singular [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, @@ -246,12 +251,12 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): If a list of polynomials is provided, the system has only one part:: - sage: F = Sequence(I.gens(), I.ring()); F + sage: F = Sequence(I.gens(), I.ring()); F # needs sage.libs.singular [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] - sage: F.nparts() + sage: F.nparts() # needs sage.libs.singular 1 We test that the ring is inferred correctly:: @@ -287,7 +292,10 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): [x, y, z] """ from sage.structure.element import is_Matrix - from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid + try: + from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid + except ImportError: + BooleanMonomialMonoid = () is_ring = lambda r: is_MPolynomialRing(r) or isinstance(r, BooleanMonomialMonoid) or (is_QuotientRing(r) and is_MPolynomialRing(r.cover_ring())) @@ -308,7 +316,7 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): if arg2: ring = arg2 if not is_ring(ring): - raise TypeError("Ring '%s' not supported."%ring) + raise TypeError("Ring '%s' not supported." % ring) else: try: e = next(iter(gens)) @@ -385,22 +393,25 @@ def __init__(self, parts, ring, immutable=False, cr=False, cr_str=None): EXAMPLES:: - sage: P.<a,b,c,d> = PolynomialRing(GF(127),4) - sage: I = sage.rings.ideal.Katsura(P) + sage: P.<a,b,c,d> = PolynomialRing(GF(127), 4) + sage: I = sage.rings.ideal.Katsura(P) # needs sage.rings.finite_rings - sage: Sequence([I.gens()], I.ring()) # indirect doctest - [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] + sage: Sequence([I.gens()], I.ring()) # indirect doctest # needs sage.rings.finite_rings + [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, + 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] If an ideal is provided, the generators are used.:: - sage: Sequence(I) - [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] + sage: Sequence(I) # needs sage.rings.finite_rings + [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, + 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] If a list of polynomials is provided, the system has only one part.:: - sage: Sequence(I.gens(), I.ring()) - [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] + sage: Sequence(I.gens(), I.ring()) # needs sage.rings.finite_rings + [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, + 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] """ Sequence_generic.__init__(self, sum(parts,tuple()), ring, check=False, immutable=immutable, @@ -414,9 +425,10 @@ def __copy__(self): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: sr = mq.SR(allow_zero_inversions=True) sage: F,s = sr.polynomial_system() - sage: copy(F) # indirect doctest + sage: copy(F) # indirect doctest Polynomial Sequence with 40 Polynomials in 20 Variables sage: type(F) == type(copy(F)) True @@ -429,9 +441,9 @@ def ring(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True,gf2=True,order='block') - sage: F,s = sr.polynomial_system() - sage: print(F.ring().repr_long()) + sage: sr = mq.SR(allow_zero_inversions=True, gf2=True, order='block') # needs sage.rings.polynomial.pbori + sage: F, s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: print(F.ring().repr_long()) # needs sage.rings.polynomial.pbori Polynomial Ring Base Ring : Finite Field of size 2 Size : 20 Variables @@ -450,9 +462,9 @@ def nparts(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) - sage: F,s = sr.polynomial_system() - sage: F.nparts() + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F, s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: F.nparts() # needs sage.rings.polynomial.pbori 4 """ return len(self._parts) @@ -463,8 +475,9 @@ def parts(self): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: sr = mq.SR(allow_zero_inversions=True) - sage: F,s = sr.polynomial_system() + sage: F, s = sr.polynomial_system() sage: l = F.parts() sage: len(l) 4 @@ -477,8 +490,9 @@ def part(self, i): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: sr = mq.SR(allow_zero_inversions=True) - sage: F,s = sr.polynomial_system() + sage: F, s = sr.polynomial_system() sage: R0 = F.part(1) sage: R0 (k000^2 + k001, k001^2 + k002, k002^2 + k003, k003^2 + k000) @@ -491,8 +505,9 @@ def ideal(self): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: sr = mq.SR(allow_zero_inversions=True) - sage: F,s = sr.polynomial_system() + sage: F, s = sr.polynomial_system() sage: P = F.ring() sage: I = F.ideal() sage: J = I.elimination_ideal(P.gens()[4:-4]) @@ -518,8 +533,9 @@ def groebner_basis(self, *args, **kwargs): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: sr = mq.SR(allow_zero_inversions=True) - sage: F,s = sr.polynomial_system() + sage: F, s = sr.polynomial_system() sage: gb = F.groebner_basis() sage: Ideal(gb).basis_is_groebner() True @@ -529,8 +545,9 @@ def groebner_basis(self, *args, **kwargs): Check that this method also works for boolean polynomials (:trac:`10680`):: + sage: # needs sage.rings.polynomial.pbori sage: B.<a,b,c,d> = BooleanPolynomialRing() - sage: F0 = Sequence(map(lambda f: f.lm(),[a,b,c,d])) + sage: F0 = Sequence(map(lambda f: f.lm(), [a,b,c,d])) sage: F0.groebner_basis() [a, b, c, d] sage: F1 = Sequence([a,b,c*d,d^2]) @@ -545,9 +562,9 @@ def monomials(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) - sage: F,s = sr.polynomial_system() - sage: len(F.monomials()) + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: len(F.monomials()) # needs sage.rings.polynomial.pbori 49 """ M = set() @@ -562,9 +579,9 @@ def nmonomials(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) - sage: F,s = sr.polynomial_system() - sage: F.nmonomials() + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: F.nmonomials() # needs sage.rings.polynomial.pbori 49 """ return len(self.monomials()) @@ -576,9 +593,9 @@ def variables(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) - sage: F,s = sr.polynomial_system() - sage: F.variables()[:10] + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: F.variables()[:10] # needs sage.rings.polynomial.pbori (k003, k002, k001, k000, s003, s002, s001, s000, w103, w102) """ V = set() @@ -593,9 +610,9 @@ def nvariables(self): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) - sage: F,s = sr.polynomial_system() - sage: F.nvariables() + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F,s = sr.polynomial_system() # needs sage.rings.polynomial.pbori + sage: F.nvariables() # needs sage.rings.polynomial.pbori 20 """ return len(self.variables()) @@ -638,9 +655,11 @@ def algebraic_dependence(self): sage: R.<x,y> = PolynomialRing(GF(7)) sage: S = Sequence([x, (x^2 + y^2 - 1)^2, x*y - 2]) - sage: I = S.algebraic_dependence(); I - Ideal (2 - 3*T2 - T0^2 + 3*T2^2 - T0^2*T2 + T2^3 + 2*T0^4 - 2*T0^2*T2^2 + T2^4 - T0^4*T1 + T0^4*T2 - 2*T0^6 + 2*T0^4*T2^2 + T0^8) of Multivariate Polynomial Ring in T0, T1, T2 over Finite Field of size 7 - sage: [F(S) for F in I.gens()] + sage: I = S.algebraic_dependence(); I # needs sage.rings.finite_rings + Ideal (2 - 3*T2 - T0^2 + 3*T2^2 - T0^2*T2 + T2^3 + 2*T0^4 - 2*T0^2*T2^2 + + T2^4 - T0^4*T1 + T0^4*T2 - 2*T0^6 + 2*T0^4*T2^2 + T0^8) + of Multivariate Polynomial Ring in T0, T1, T2 over Finite Field of size 7 + sage: [F(S) for F in I.gens()] # needs sage.rings.finite_rings [0] .. NOTE:: @@ -701,14 +720,14 @@ def coefficient_matrix(self, sparse=True): EXAMPLES:: - sage: P.<a,b,c,d> = PolynomialRing(GF(127),4) + sage: # needs sage.libs.singular + sage: P.<a,b,c,d> = PolynomialRing(GF(127), 4) sage: I = sage.rings.ideal.Katsura(P) sage: I.gens() [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] - sage: F = Sequence(I) sage: A,v = F.coefficient_matrix() sage: A @@ -716,7 +735,6 @@ def coefficient_matrix(self, sparse=True): [ 1 0 2 0 0 2 0 0 2 126 0 0 0 0] [ 0 2 0 0 2 0 0 2 0 0 126 0 0 0] [ 0 0 1 2 0 0 2 0 0 0 0 126 0 0] - sage: v [a^2] [a*b] @@ -732,7 +750,6 @@ def coefficient_matrix(self, sparse=True): [ c] [ d] [ 1] - sage: A*v [ a + 2*b + 2*c + 2*d - 1] [a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a] @@ -763,20 +780,20 @@ def coefficient_matrix(self, sparse=True): def subs(self, *args, **kwargs): """ Substitute variables for every polynomial in this system and - return a new system. See ``MPolynomial.subs`` for calling + return a new system. See :meth:`MPolynomial.subs` for calling convention. INPUT: - - ``args`` - arguments to be passed to ``MPolynomial.subs`` - - ``kwargs`` - keyword arguments to be passed to ``MPolynomial.subs`` + - ``args`` - arguments to be passed to :meth:`MPolynomial.subs` + - ``kwargs`` - keyword arguments to be passed to :meth:`MPolynomial.subs` EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True) - sage: F,s = sr.polynomial_system(); F + sage: sr = mq.SR(allow_zero_inversions=True) # needs sage.rings.polynomial.pbori + sage: F, s = sr.polynomial_system(); F # needs sage.rings.polynomial.pbori Polynomial Sequence with 40 Polynomials in 20 Variables - sage: F = F.subs(s); F + sage: F = F.subs(s); F # needs sage.rings.polynomial.pbori Polynomial Sequence with 40 Polynomials in 16 Variables """ return PolynomialSequence(self._ring, [tuple([f.subs(*args,**kwargs) for f in r]) for r in self._parts]) @@ -787,6 +804,7 @@ def _singular_(self): EXAMPLES:: + sage: # needs sage.libs.singular sage: P.<a,b,c,d> = PolynomialRing(GF(127)) sage: I = sage.rings.ideal.Katsura(P) sage: F = Sequence(I); F @@ -809,10 +827,11 @@ def _magma_init_(self, magma): EXAMPLES:: - sage: sr = mq.SR(allow_zero_inversions=True,gf2=True) + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(allow_zero_inversions=True, gf2=True) sage: F,s = sr.polynomial_system() sage: F.set_immutable() - sage: magma(F) # indirect doctest; optional - magma + sage: magma(F) # optional - magma Ideal of Boolean polynomial ring of rank 20 over GF(2) Order: Graded Lexicographical (bit vector word) Variables: k100, k101, k102, k103, x100, x101, x102, x103, w100, w101, w102, w103, s000, s001, s002, s003, k000, k001, k002, k003 @@ -823,7 +842,7 @@ def _magma_init_(self, magma): """ P = magma(self.ring()).name() v = [x._magma_init_(magma) for x in list(self)] - return 'ideal<%s|%s>'%(P, ','.join(v)) + return 'ideal<%s|%s>' % (P, ','.join(v)) def _repr_(self): """ @@ -831,9 +850,10 @@ def _repr_(self): EXAMPLES:: + sage: # needs sage.libs.singular sage: P.<a,b,c,d> = PolynomialRing(GF(127)) sage: I = sage.rings.ideal.Katsura(P) - sage: F = Sequence(I); F # indirect doctest + sage: F = Sequence(I); F # indirect doctest [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, @@ -842,15 +862,15 @@ def _repr_(self): If the system contains 20 or more polynomials, a short summary is printed:: - sage: sr = mq.SR(allow_zero_inversions=True,gf2=True) - sage: F,s = sr.polynomial_system(); F + sage: sr = mq.SR(allow_zero_inversions=True, gf2=True) # needs sage.rings.polynomial.pbori + sage: F,s = sr.polynomial_system(); F # needs sage.rings.polynomial.pbori Polynomial Sequence with 36 Polynomials in 20 Variables """ if len(self) < 20: return Sequence_generic._repr_(self) else: - return "Polynomial Sequence with %d Polynomials in %d Variables"%(len(self),self.nvariables()) + return "Polynomial Sequence with %d Polynomials in %d Variables" % (len(self),self.nvariables()) def __add__(self, right): """ @@ -859,6 +879,7 @@ def __add__(self, right): EXAMPLES:: + sage: # needs sage.libs.singular sage: P.<a,b,c,d> = PolynomialRing(GF(127)) sage: I = sage.rings.ideal.Katsura(P) sage: F = Sequence(I) @@ -868,14 +889,12 @@ def __add__(self, right): 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c, a^127 + a] - sage: F + P.ideal([a^127 + a]) [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c, a^127 + a] - sage: F + Sequence([a^127 + a], P) [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, @@ -903,20 +922,43 @@ def connection_graph(self): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: B.<x,y,z> = BooleanPolynomialRing() sage: F = Sequence([x*y + y + 1, z + 1]) - sage: F.connection_graph() + sage: G = F.connection_graph(); G Graph on 3 vertices + sage: G.is_connected() + False + sage: F = Sequence([x]) + sage: F.connection_graph() + Graph on 1 vertex + + TESTS:: + + sage: # needs sage.rings.polynomial.pbori + sage: F = Sequence([], B) + sage: F.connection_graph() + Graph on 0 vertices + sage: F = Sequence([1], B) + sage: F.connection_graph() + Graph on 0 vertices + sage: F = Sequence([x]) + sage: F.connection_graph() + Graph on 1 vertex + sage: F = Sequence([x, y]) + sage: F.connection_graph() + Graph on 2 vertices + sage: F = Sequence([x*y*z]) + sage: F.connection_graph().is_clique() + True + sage: F = Sequence([x*y, y*z]) + sage: F.connection_graph().is_clique() + False """ - V = sorted(self.variables()) from sage.graphs.graph import Graph g = Graph() - g.add_vertices(sorted(V)) for f in self: - v = f.variables() - a,tail = v[0],v[1:] - for b in tail: - g.add_edge((a,b)) + g.add_clique(f.variables()) return g def connected_components(self): @@ -929,7 +971,8 @@ def connected_components(self): As an example consider one part of AES, which naturally splits into four subsystems which are independent:: - sage: sr = mq.SR(2,4,4,8,gf2=True,polybori=True) + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(2, 4, 4, 8, gf2=True, polybori=True) sage: while True: # workaround (see :trac:`31891`) ....: try: ....: F, s = sr.polynomial_system() @@ -942,18 +985,37 @@ def connected_components(self): Polynomial Sequence with 128 Polynomials in 128 Variables, Polynomial Sequence with 128 Polynomials in 128 Variables, Polynomial Sequence with 128 Polynomials in 128 Variables] + + TESTS: + + Check the order of the output (:trac:`35518`):: + + sage: R.<x,y,z> = PolynomialRing(ZZ) + sage: Sequence([x,z,y]).connected_components() + [[x], [z], [y]] + sage: Sequence([x,z,x*y*z,y]).connected_components() + [[x, z, x*y*z, y]] """ - g = self.connection_graph() - C = sorted(g.connected_components()) + # precompute the list of variables in each polynomial + vss = [f.variables() for f in self] + + # Use a union-find data structure to encode relationships between + # variables, i.e., that they belong to a same polynomial + from sage.sets.disjoint_set import DisjointSet + DS = DisjointSet(set().union(*vss)) + for u, *vs in vss: + for v in vs: + DS.union(u, v) + + Ps = {} # map root element -> polynomials in this component + for f, vs in zip(self, vss): + r = DS.find(vs[0]) + if r in Ps: + Ps[r].append(f) + else: + Ps[r] = [f] - P = [[] for _ in range(len(C))] - for f in self: - for i,c in enumerate(C): - if len(set(f.variables()).difference(c)) == 0: - P[i].append(f) - break - P = sorted([PolynomialSequence(sorted(p)) for p in P]) - return P + return [PolynomialSequence(self.ring(), p) for p in Ps.values()] def _groebner_strategy(self): """ @@ -966,7 +1028,7 @@ def _groebner_strategy(self): sage: P.<x,y,z> = PolynomialRing(GF(127)) sage: F = Sequence([x*y + z, y + z + 1]) - sage: F._groebner_strategy() + sage: F._groebner_strategy() # needs sage.libs.singular Groebner Strategy for ideal generated by 2 elements over Multivariate Polynomial Ring in x, y, z over Finite Field of size 127 """ @@ -1000,7 +1062,7 @@ def __reduce__(self): sage: P.<x,y,z> = PolynomialRing(GF(127)) sage: F = Sequence([x*y + z, y + z + 1]) - sage: loads(dumps(F)) == F # indirect doctest + sage: loads(dumps(F)) == F True We check that :trac:`26354` is fixed:: @@ -1022,12 +1084,12 @@ def reduced(self): - `(f_1,...,f_n) = (g_1,...,g_s)` - - `LT(g_i) != LT(g_j)` for all `i != j` + - `LT(g_i) \neq LT(g_j)` for all `i \neq j` - `LT(g_i)` does not divide `m` for all monomials `m` of - `\{g_1,...,g_{i-1},g_{i+1},...,g_s\}` + `\{g_1,...,g_{i-1},g_{i+1},...,g_s\}` - - `LC(g_i) == 1` for all `i` if the coefficient ring is a field. + - `LC(g_i) = 1` for all `i` if the coefficient ring is a field. EXAMPLES:: @@ -1078,7 +1140,7 @@ def reduced(self): Check that :trac:`26952` is fixed:: sage: Qp = pAdicField(2) - sage: R.<x,y,z> = PolynomialRing(Qp, implementation="generic") + sage: R.<x,y,z> = PolynomialRing(Qp, implementation="generic") # needs sage.rings.padics sage: F = Sequence([z*x+y^3,z+y^3,3*z+x*y]) sage: F.reduced() [y^3 + z, x*y + (1 + 2 + O(2^20))*z, x*z - z] @@ -1125,8 +1187,8 @@ def is_groebner(self, singular=singular): EXAMPLES:: - sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127),10) - sage: I = sage.rings.ideal.Cyclic(R,4) + sage: R.<a,b,c,d,e,f,g,h,i,j> = PolynomialRing(GF(127), 10) + sage: I = sage.rings.ideal.Cyclic(R, 4) sage: I.basis.is_groebner() False sage: I2 = Ideal(I.groebner_basis()) @@ -1162,33 +1224,34 @@ def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reduc with linear leading terms which were used for reduction is also returned (default: ``False``). - - ```use_polybori`` - if ``True`` then ``polybori.ll.eliminate`` is - called. While this is typically faster what is implemented here, it + - ``use_polybori`` - if ``True`` then ``polybori.ll.eliminate`` is + called. While this is typically faster than what is implemented here, it is less flexible (``skip`` is not supported) and may increase the degree (default: ``False``) OUTPUT: - When ``return_reductors==True``, then a pair of sequences of + With ``return_reductors=True``, a pair of sequences of boolean polynomials are returned, along with the promises that: - 1. The union of the two sequences spans the - same boolean ideal as the argument of the method + 1. The union of the two sequences spans the + same boolean ideal as the argument of the method - 2. The second sequence only contains linear polynomials, and - it forms a reduced groebner basis (they all have pairwise - distinct leading variables, and the leading variable of a - polynomial does not occur anywhere in other polynomials). + 2. The second sequence only contains linear polynomials, and + it forms a reduced groebner basis (they all have pairwise + distinct leading variables, and the leading variable of a + polynomial does not occur anywhere in other polynomials). - 3. The leading variables of the second sequence do not occur - anywhere in the first sequence (these variables have been - eliminated). + 3. The leading variables of the second sequence do not occur + anywhere in the first sequence (these variables have been + eliminated). - When ``return_reductors==False``, only the first sequence is + With ``return_reductors=False``, only the first sequence is returned. EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: F = Sequence([c + d + b + 1, a + c + d, a*b + c, b*c*d + c]) sage: F.eliminate_linear_variables() # everything vanishes @@ -1198,27 +1261,28 @@ def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reduc sage: F.eliminate_linear_variables(skip=lambda lm,tail: str(lm)=='a') [a + c + d, a*c + a*d + a + c, c*d + c] - The list of reductors can be requested by setting 'return_reductors' to ``True``:: + The list of reductors can be requested by setting ``return_reductors`` to ``True``:: + sage: # needs sage.rings.polynomial.pbori sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: F = Sequence([a + b + d, a + b + c]) - sage: F,R = F.eliminate_linear_variables(return_reductors=True) + sage: F, R = F.eliminate_linear_variables(return_reductors=True) sage: F [] sage: R [a + b + d, c + d] - If the input system is detected to be inconsistent then [1] is returned + If the input system is detected to be inconsistent then ``[1]`` is returned, and the list of reductors is empty:: + sage: # needs sage.rings.polynomial.pbori sage: R.<x,y,z> = BooleanPolynomialRing() - sage: S = Sequence([x*y*z+x*y+z*y+x*z, x+y+z+1, x+y+z]) + sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z]) sage: S.eliminate_linear_variables() [1] - sage: R.<x,y,z> = BooleanPolynomialRing() - sage: S = Sequence([x*y*z+x*y+z*y+x*z, x+y+z+1, x+y+z]) + sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z]) sage: S.eliminate_linear_variables(return_reductors=True) ([1], []) @@ -1227,27 +1291,27 @@ def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reduc The function should really dispose of linear equations (:trac:`13968`):: - sage: R.<x,y,z> = BooleanPolynomialRing() - sage: S = Sequence([x+y+z+1, y+z]) - sage: S.eliminate_linear_variables(return_reductors=True) + sage: R.<x,y,z> = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: S = Sequence([x + y + z + 1, y + z]) # needs sage.rings.polynomial.pbori + sage: S.eliminate_linear_variables(return_reductors=True) # needs sage.rings.polynomial.pbori ([], [x + 1, y + z]) The function should take care of linear variables created by previous substitution of linear variables :: - sage: R.<x,y,z> = BooleanPolynomialRing() - sage: S = Sequence([x*y*z+x*y+z*y+x*z, x+y+z+1, x+y]) - sage: S.eliminate_linear_variables(return_reductors=True) + sage: R.<x,y,z> = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y]) # needs sage.rings.polynomial.pbori + sage: S.eliminate_linear_variables(return_reductors=True) # needs sage.rings.polynomial.pbori ([], [x + y, z + 1]) We test a case which would increase the degree with ``polybori=True``:: + sage: # needs sage.rings.polynomial.pbori sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: f = a*d + a + b*d + c*d + 1 sage: Sequence([f, a + b*c + c+d + 1]).eliminate_linear_variables() [a*d + a + b*d + c*d + 1, a + b*c + c + d + 1] - sage: B.<a,b,c,d> = BooleanPolynomialRing() sage: f = a*d + a + b*d + c*d + 1 sage: Sequence([f, a + b*c + c+d + 1]).eliminate_linear_variables(use_polybori=True) @@ -1257,14 +1321,16 @@ def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reduc This is called "massaging" in [BCJ2007]_. """ - from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing,gauss_on_polys - from sage.rings.polynomial.pbori.ll import eliminate,ll_encode,ll_red_nf_redsb + from sage.rings.polynomial.multi_polynomial_ring_base import BooleanPolynomialRing_base R = self.ring() - if not isinstance(R, BooleanPolynomialRing): + if not isinstance(R, BooleanPolynomialRing_base): raise NotImplementedError("Only BooleanPolynomialRing's are supported.") + from sage.rings.polynomial.pbori.pbori import gauss_on_polys + from sage.rings.polynomial.pbori.ll import eliminate, ll_encode, ll_red_nf_redsb + F = self reductors = [] @@ -1335,15 +1401,17 @@ def _groebner_strategy(self): Groebner Strategy for ideal generated by 2 elements over Multivariate Polynomial Ring in x, y, z over Finite Field of size 2 + sage: # needs sage.rings.polynomial.pbori sage: P.<x,y,z> = BooleanPolynomialRing() sage: F = Sequence([x*y + z, y + z + 1]) sage: F._groebner_strategy() <sage.rings.polynomial.pbori.pbori.GroebnerStrategy object at 0x...> """ - from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing + from sage.rings.polynomial.multi_polynomial_ring_base import BooleanPolynomialRing_base + R = self.ring() - if not isinstance(R, BooleanPolynomialRing): + if not isinstance(R, BooleanPolynomialRing_base): from sage.libs.singular.groebner_strategy import GroebnerStrategy return GroebnerStrategy(self.ideal()) else: @@ -1351,7 +1419,7 @@ def _groebner_strategy(self): g = GroebnerStrategy(R) for p in self: g.add_as_you_wish(p) - g.reduction_strategy.opt_red_tail=True + g.reduction_strategy.opt_red_tail = True return g def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, verbose=False, **kwds): @@ -1391,68 +1459,69 @@ def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, ver Without argument, a single arbitrary solution is returned:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.doctest.fixtures import reproducible_repr sage: R.<x,y,z> = BooleanPolynomialRing() - sage: S = Sequence([x*y+z, y*z+x, x+y+z+1]) + sage: S = Sequence([x*y + z, y*z + x, x + y + z + 1]) sage: sol = S.solve() sage: print(reproducible_repr(sol)) [{x: 0, y: 1, z: 0}] We check that it is actually a solution:: - sage: S.subs( sol[0] ) + sage: S.subs(sol[0]) # needs sage.rings.polynomial.pbori [0, 0, 0] We obtain all solutions:: - sage: sols = S.solve(n=Infinity) - sage: print(reproducible_repr(sols)) + sage: sols = S.solve(n=Infinity) # needs sage.rings.polynomial.pbori + sage: print(reproducible_repr(sols)) # needs sage.rings.polynomial.pbori [{x: 0, y: 1, z: 0}, {x: 1, y: 1, z: 1}] - sage: [S.subs(x) for x in sols] + sage: [S.subs(x) for x in sols] # needs sage.rings.polynomial.pbori [[0, 0, 0], [0, 0, 0]] We can force the use of exhaustive search if the optional package ``FES`` is present:: - sage: sol = S.solve(algorithm='exhaustive_search') # optional - FES - sage: print(reproducible_repr(sol)) # optional - FES + sage: sol = S.solve(algorithm='exhaustive_search') # optional - fes # needs sage.rings.polynomial.pbori + sage: print(reproducible_repr(sol)) # optional - fes # needs sage.rings.polynomial.pbori [{x: 1, y: 1, z: 1}] - sage: S.subs( sol[0] ) + sage: S.subs(sol[0]) # optional - fes # needs sage.rings.polynomial.pbori [0, 0, 0] And we may use SAT-solvers if they are available:: - sage: sol = S.solve(algorithm='sat') # optional - pycryptosat - sage: print(reproducible_repr(sol)) # optional - pycryptosat + sage: sol = S.solve(algorithm='sat') # optional - pycryptosat # needs sage.rings.polynomial.pbori + sage: print(reproducible_repr(sol)) # optional - pycryptosat # needs sage.rings.polynomial.pbori [{x: 0, y: 1, z: 0}] - sage: S.subs( sol[0] ) + sage: S.subs(sol[0]) # needs sage.rings.polynomial.pbori [0, 0, 0] TESTS: Make sure that variables not occurring in the equations are no problem:: + sage: # needs sage.rings.polynomial.pbori sage: R.<x,y,z,t> = BooleanPolynomialRing() - sage: S = Sequence([x*y+z, y*z+x, x+y+z+1]) + sage: S = Sequence([x*y + z, y*z + x, x + y + z + 1]) sage: sols = S.solve(n=Infinity) sage: [S.subs(x) for x in sols] [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] Not eliminating linear variables:: - sage: sols = S.solve(n=Infinity, eliminate_linear_variables=False) - sage: [S.subs(x) for x in sols] + sage: sols = S.solve(n=Infinity, eliminate_linear_variables=False) # needs sage.rings.polynomial.pbori + sage: [S.subs(x) for x in sols] # needs sage.rings.polynomial.pbori [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] A tricky case where the linear equations are insatisfiable:: - sage: R.<x,y,z> = BooleanPolynomialRing() - sage: S = Sequence([x*y*z+x*y+z*y+x*z, x+y+z+1, x+y+z]) - sage: S.solve() + sage: R.<x,y,z> = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: S = Sequence([x*y*z + x*y + z*y + x*z, x + y + z + 1, x + y + z]) # needs sage.rings.polynomial.pbori + sage: S.solve() # needs sage.rings.polynomial.pbori [] """ - from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing from sage.modules.free_module import VectorSpace S = self @@ -1462,6 +1531,8 @@ def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, ver if eliminate_linear_variables: T, reductors = self.eliminate_linear_variables(return_reductors=True) if T.variables() != (): + from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing + R_solving = BooleanPolynomialRing( T.nvariables(), [str(_) for _ in list(T.variables())] ) S = PolynomialSequence( R_solving, [ R_solving(f) for f in T] ) @@ -1515,16 +1586,17 @@ def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, ver return solutions def reduced(self): - """ - If this sequence is `(f_1, ..., f_n)` this method returns `(g_1, ..., g_s)` such that: + r""" + If this sequence is `f_1, ..., f_n`, return `g_1, ..., g_s` such that: - - `<f_1,...,f_n> = <g_1,...,g_s>` - - `LT(g_i) != LT(g_j)` for all `i != j`` + - `(f_1,...,f_n) = (g_1,...,g_s)` + - `LT(g_i) \neq LT(g_j)` for all `i \neq j` - `LT(g_i)` does not divide `m` for all monomials `m` of `{g_1,...,g_{i-1},g_{i+1},...,g_s}` EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) sage: while True: # workaround (see :trac:`31891`) ....: try: @@ -1543,12 +1615,14 @@ def reduced(self): ....: assert g[i].lt() not in t.divisors() """ - from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing + from sage.rings.polynomial.multi_polynomial_ring_base import BooleanPolynomialRing_base + R = self.ring() - if isinstance(R, BooleanPolynomialRing): + if isinstance(R, BooleanPolynomialRing_base): from sage.rings.polynomial.pbori.interred import interred as inter_red - l = [p for p in self if not p==0] + + l = [p for p in self if not p == 0] l = sorted(inter_red(l, completely=True), reverse=True) return PolynomialSequence(l, R, immutable=True) else: @@ -1571,18 +1645,20 @@ def weil_restriction(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(2^2) - sage: P.<x,y> = PolynomialRing(k,2) + sage: P.<x,y> = PolynomialRing(k, 2) sage: a = P.base_ring().gen() sage: F = Sequence([x*y + 1, a*x + 1], P) sage: F2 = F.weil_restriction() sage: F2 [x0*y0 + x1*y1 + 1, x1*y0 + x0*y1 + x1*y1, x1 + 1, x0 + x1, x0^2 + x0, - x1^2 + x1, y0^2 + y0, y1^2 + y1] + x1^2 + x1, y0^2 + y0, y1^2 + y1] Another bigger example for a small scale AES:: - sage: sr = mq.SR(1,1,1,4,gf2=False) + sage: # needs sage.rings.polynomial.pbori + sage: sr = mq.SR(1, 1, 1, 4, gf2=False) sage: while True: # workaround (see :trac:`31891`) ....: try: ....: F, s = sr.polynomial_system() @@ -1599,6 +1675,7 @@ def weil_restriction(self): J += FieldIdeal(J.ring()) return PolynomialSequence(J) + from sage.misc.persist import register_unpickle_override register_unpickle_override("sage.crypto.mq.mpolynomialsystem","MPolynomialSystem_generic", PolynomialSequence_generic) register_unpickle_override("sage.crypto.mq.mpolynomialsystem","MPolynomialRoundSystem_generic", PolynomialSequence_generic) diff --git a/src/sage/rings/polynomial/omega.py b/src/sage/rings/polynomial/omega.py index f2ab5232b2e..5f5dfb441e7 100644 --- a/src/sage/rings/polynomial/omega.py +++ b/src/sage/rings/polynomial/omega.py @@ -877,6 +877,7 @@ def _Omega_factors_denominator_(x, y): :: + sage: # needs sage.rings.number_field sage: B.<zeta> = ZZ.extension(cyclotomic_polynomial(3)) sage: L.<x, y> = LaurentPolynomialRing(B) sage: _Omega_factors_denominator_(((x, -x),), ((y,),)) diff --git a/src/sage/rings/polynomial/ore_function_element.py b/src/sage/rings/polynomial/ore_function_element.py index d21ed8d1ed4..3afaff91a10 100644 --- a/src/sage/rings/polynomial/ore_function_element.py +++ b/src/sage/rings/polynomial/ore_function_element.py @@ -165,7 +165,7 @@ def _richcmp_(self, other, op): sage: P = K.random_element() sage: Q = K.random_element() sage: D = K.random_element() - sage: Q == 0 or D == 0 or (P*D) / (Q*D) == P/Q + sage: Q == 0 or D == 0 or (P*D) / (Q*D) == P/Q # long time True """ @@ -845,7 +845,7 @@ def reduced_trace(self, var=None): 3/(z^2 + 2) The reduced trace lies in the center of `S`, which is the fraction field - of a univariate polynomial ring in the variable `z = x^3` over `GF(5)`. + of a univariate polynomial ring in the variable `z = x^3` over `GF(5)`:: sage: tr.parent() Fraction Field of Univariate Polynomial Ring in z over Finite Field of size 5 @@ -906,7 +906,7 @@ def reduced_norm(self, var=None): (z + 2)/(z^2 + 4) The reduced norm lies in the center of `S`, which is the fraction field - of a univariate polynomial ring in the variable `z = x^3` over `GF(5)`. + of a univariate polynomial ring in the variable `z = x^3` over `GF(5)`. :: sage: N.parent() Fraction Field of Univariate Polynomial Ring in z over Finite Field of size 5 diff --git a/src/sage/rings/polynomial/ore_function_field.py b/src/sage/rings/polynomial/ore_function_field.py index f223f9799dd..5a50e7c22b0 100644 --- a/src/sage/rings/polynomial/ore_function_field.py +++ b/src/sage/rings/polynomial/ore_function_field.py @@ -35,7 +35,7 @@ sage: g (d - 1/t)^(-1) * t -The left numerator and right denominator are accessible as follows: +The left numerator and right denominator are accessible as follows:: sage: g.left_numerator() t @@ -355,7 +355,6 @@ def characteristic(self): """ return self.base_ring().characteristic() - def twisting_morphism(self, n=1): r""" Return the twisting endomorphism defining this Ore function field iterated ``n`` times diff --git a/src/sage/rings/polynomial/ore_polynomial_element.pxd b/src/sage/rings/polynomial/ore_polynomial_element.pxd index 4a90682f01b..aa36112ab90 100644 --- a/src/sage/rings/polynomial/ore_polynomial_element.pxd +++ b/src/sage/rings/polynomial/ore_polynomial_element.pxd @@ -1,5 +1,6 @@ from sage.structure.element cimport AlgebraElement from sage.structure.parent cimport Parent +from sage.rings.integer cimport Integer from sage.rings.morphism cimport Morphism from sage.structure.element cimport RingElement from sage.rings.polynomial.polynomial_element cimport Polynomial_generic_dense @@ -23,7 +24,7 @@ cdef class OrePolynomial(AlgebraElement): cdef OrePolynomial _right_lcm_cofactor(self, OrePolynomial other) # Abstract methods - cpdef int degree(self) + cpdef Integer degree(self) cpdef list coefficients(self, sparse=*) @@ -32,7 +33,7 @@ cdef void lmul_gen(list A, Morphism m, d) cdef class OrePolynomial_generic_dense(OrePolynomial): cdef list _coeffs - cdef void __normalize(self) + cdef void _normalize(self) cpdef _add_(self, other) cdef list _mul_list(self, list A) cpdef _mul_(self, other) diff --git a/src/sage/rings/polynomial/ore_polynomial_element.pyx b/src/sage/rings/polynomial/ore_polynomial_element.pyx index 820c758496c..be154ba8b1a 100644 --- a/src/sage/rings/polynomial/ore_polynomial_element.pyx +++ b/src/sage/rings/polynomial/ore_polynomial_element.pyx @@ -13,7 +13,7 @@ The generic implementation of dense Ore polynomials is The classes :class:`~sage.rings.polynomial.ore_polynomial_element.ConstantOrePolynomialSection` and :class:`~sage.rings.polynomial.ore_polynomial_element.OrePolynomialBaseringInjection` -handle conversion from a Ore polynomial ring to its base ring and vice versa. +handle conversion from an Ore polynomial ring to its base ring and vice versa. AUTHORS: @@ -27,26 +27,23 @@ AUTHORS: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # *************************************************************************** import re from cysignals.signals cimport sig_check from sage.structure.element import coerce_binop -from sage.misc.superseded import experimental from sage.rings.infinity import infinity -from sage.structure.factorization import Factorization -from sage.structure.element cimport Element, RingElement, AlgebraElement, ModuleElement +from sage.structure.element cimport Element, RingElement, AlgebraElement from sage.structure.parent cimport Parent from sage.structure.parent_gens cimport ParentWithGens -from sage.misc.abstract_method import abstract_method from sage.categories.homset import Hom from sage.rings.ring import _Fields from sage.rings.integer cimport Integer from cpython.object cimport PyObject_RichCompare from sage.categories.map cimport Map -from sage.rings.morphism cimport Morphism, RingHomomorphism +from sage.rings.morphism cimport Morphism from sage.rings.polynomial.polynomial_element cimport _dict_to_list @@ -61,7 +58,7 @@ cdef class OrePolynomial(AlgebraElement): Let `R` be a commutative ring equipped with an automorphism `\sigma` and a `\sigma`-derivation `\partial`. - A Ore polynomial is given by the equation: + An Ore polynomial is given by the equation: .. MATH:: @@ -76,23 +73,23 @@ cdef class OrePolynomial(AlgebraElement): is equal to the sum of the degrees of the factors. Let `a` and `b` be two Ore polynomials in the same ring `S`. - The *left (resp. right) euclidean division* of `a` by `b` is a couple + The *right (resp. left) Euclidean division* of `a` by `b` is a couple `(q,r)` of elements in `S` such that - - `a = q b + r` (resp. `a = b q + r`) + - `a = q b + r` (resp. `a = b q + r`) - - the degree of `r` is less than the degree of `b` + - the degree of `r` is less than the degree of `b` `q` (resp. `r`) is called the *quotient* (resp. the remainder) - of this euclidean division. + of this Euclidean division. .. RUBRIC:: Properties Keeping the previous notation, if the leading coefficient of `b` is a unit (e.g. if `b` is monic) then the quotient and the remainder - in the *right* euclidean division exist and are unique. + in the *right* Euclidean division exist and are unique. - The same result holds for the *left* euclidean division if in addition + The same result holds for the *left* Euclidean division if in addition the twisting morphism defining the Ore polynomial ring is invertible. EXAMPLES: @@ -145,7 +142,7 @@ cdef class OrePolynomial(AlgebraElement): True The operators ``//`` and ``%`` give respectively the quotient - and the remainder of the *right* euclidean division:: + and the remainder of the *right* Euclidean division:: sage: q == c // b True @@ -164,12 +161,13 @@ cdef class OrePolynomial(AlgebraElement): Here is another example over a finite field:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x^4 + (4*t + 1)*x^3 + (t^2 + 3*t + 3)*x^2 + (3*t^2 + 2*t + 2)*x + (3*t^2 + 3*t + 1) sage: b = (2*t^2 + 3)*x^2 + (3*t^2 + 1)*x + 4*t + 2 - sage: q,r = a.left_quo_rem(b) + sage: q, r = a.left_quo_rem(b) sage: q (4*t^2 + t + 1)*x^2 + (2*t^2 + 2*t + 2)*x + 2*t^2 + 4*t + 3 sage: r @@ -177,9 +175,10 @@ cdef class OrePolynomial(AlgebraElement): sage: a == b*q + r True - Once we have euclidean divisions, we have for free gcd and lcm + Once we have Euclidean divisions, we have for free gcd and lcm (at least if the base ring is a field):: + sage: # needs sage.rings.finite_rings sage: a = (x + t) * (x + t^2)^2 sage: b = (x + t) * (t*x + t + 1) * (x + t^2) sage: a.right_gcd(b) @@ -191,21 +190,21 @@ cdef class OrePolynomial(AlgebraElement): their left lcm is the least degree polynomial `c = ua = vb` for some Ore polynomials `u, v`. Such a `c` always exist if the base ring is a field:: - sage: c = a.left_lcm(b); c + sage: c = a.left_lcm(b); c # needs sage.rings.finite_rings x^5 + (4*t^2 + t + 3)*x^4 + (3*t^2 + 4*t)*x^3 + 2*t^2*x^2 + (2*t^2 + t)*x + 4*t^2 + 4 - sage: c.is_right_divisible_by(a) + sage: c.is_right_divisible_by(a) # needs sage.rings.finite_rings True - sage: c.is_right_divisible_by(b) + sage: c.is_right_divisible_by(b) # needs sage.rings.finite_rings True The right lcm is defined similarly as the least degree polynomial `c = au = bv` for some `u,v`:: - sage: d = a.right_lcm(b); d + sage: d = a.right_lcm(b); d # needs sage.rings.finite_rings x^5 + (t^2 + 1)*x^4 + (3*t^2 + 3*t + 3)*x^3 + (3*t^2 + t + 2)*x^2 + (4*t^2 + 3*t)*x + 4*t + 4 - sage: d.is_left_divisible_by(a) + sage: d.is_left_divisible_by(a) # needs sage.rings.finite_rings True - sage: d.is_left_divisible_by(b) + sage: d.is_left_divisible_by(b) # needs sage.rings.finite_rings True .. SEEALSO:: @@ -252,7 +251,7 @@ cdef class OrePolynomial(AlgebraElement): """ return self._hash_c() - cpdef int degree(self): + cpdef Integer degree(self): r""" Return the degree of ``self``. @@ -290,6 +289,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() @@ -312,6 +312,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -348,7 +349,7 @@ cdef class OrePolynomial(AlgebraElement): def constant_coefficient(self): r""" - Return the constant coefficient (i.e. the coefficient of term + Return the constant coefficient (i.e., the coefficient of term of degree `0`) of ``self``. EXAMPLES:: @@ -393,7 +394,7 @@ cdef class OrePolynomial(AlgebraElement): r""" Return ``True`` if this Ore polynomial is a unit. - When the base ring `R` is an integral domain, then a Ore polynomial `f` + When the base ring `R` is an integral domain, then an Ore polynomial `f` is a unit if and only if degree of `f` is `0` and `f` is then a unit in `R`. @@ -478,12 +479,13 @@ cdef class OrePolynomial(AlgebraElement): Return the unique monic Ore polynomial `m` which divides this polynomial on the left and has the same degree. - Given a Ore polynomial `P` of degree `n`, its left monic is given by + Given an Ore polynomial `P` of degree `n`, its left monic is given by `P \cdot \sigma^{-n}(1/k)`, where `k` is the leading coefficient of `P` and `\sigma` is the twisting morphism. EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -493,9 +495,10 @@ cdef class OrePolynomial(AlgebraElement): Check list:: + sage: # needs sage.rings.finite_rings sage: b.degree() == a.degree() True - sage: b.is_left_divisible_by(a) + sage: a.is_left_divisible_by(b) True sage: twist = S.twisting_morphism(-a.degree()) sage: a == b * twist(a.leading_coefficient()) @@ -503,7 +506,7 @@ cdef class OrePolynomial(AlgebraElement): Note that `b` does not divide `a` on the right:: - sage: a.is_right_divisible_by(b) + sage: a.is_right_divisible_by(b) # needs sage.rings.finite_rings False This function does not work if the leading coefficient is not a @@ -532,11 +535,12 @@ cdef class OrePolynomial(AlgebraElement): Return the unique monic Ore polynomial which divides this polynomial on the right and has the same degree. - Given a Ore polynomial `P` of degree `n`, its left monic is given by - `(1/k) \cdot P`, where `k` is the leading coefficient of `p`. + Given an Ore polynomial `P` of degree `n`, its right monic is given by + `(1/k) \cdot P`, where `k` is the leading coefficient of `P`. EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -546,16 +550,16 @@ cdef class OrePolynomial(AlgebraElement): Check list:: - sage: b.degree() == a.degree() + sage: b.degree() == a.degree() # needs sage.rings.finite_rings True - sage: b.is_right_divisible_by(a) + sage: a.is_right_divisible_by(b) # needs sage.rings.finite_rings True - sage: a == a.leading_coefficient() * b + sage: a == a.leading_coefficient() * b # needs sage.rings.finite_rings True Note that `b` does not divide `a` on the right:: - sage: a.is_left_divisible_by(b) + sage: a.is_left_divisible_by(b) # needs sage.rings.finite_rings False This function does not work if the leading coefficient is not a @@ -578,7 +582,7 @@ cdef class OrePolynomial(AlgebraElement): cpdef _mod_(self, other): r""" - Return the remainder in the *right* euclidean division of + Return the remainder in the *right* Euclidean division of ``self`` by ``other```. TESTS:: @@ -600,7 +604,7 @@ cdef class OrePolynomial(AlgebraElement): cpdef _floordiv_(self, right): r""" - Return the quotient of the *right* euclidean division of + Return the quotient of the *right* Euclidean division of ``self`` by ``right``. The algorithm fails if the leading coefficient of the divisor @@ -631,10 +635,11 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``right`` -- a Ore polynomial + - ``right`` -- an Ore polynomial EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(11)[] sage: der = R.derivation() sage: S.<x> = R['x', der] @@ -642,7 +647,8 @@ cdef class OrePolynomial(AlgebraElement): sage: f (x + 10/t)^(-1) * t sage: f.parent() - Ore Function Field in x over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 11 twisted by d/dt + Ore Function Field in x over + Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 11 twisted by d/dt """ parent = self.parent().fraction_field() return parent(self) / parent(right) @@ -653,7 +659,7 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` OUTPUT: @@ -688,7 +694,7 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` OUTPUT: @@ -696,6 +702,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -709,7 +716,7 @@ cdef class OrePolynomial(AlgebraElement): Divisibility by `0` does not make sense:: - sage: c.is_right_divisible_by(S(0)) + sage: c.is_right_divisible_by(S(0)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ZeroDivisionError: division by zero is not valid @@ -737,7 +744,7 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` OUTPUT: @@ -745,12 +752,13 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x^2 + t*x + t^2 + 3 sage: b = x^3 + (t + 1)*x^2 + 1 - sage: c = a*b + sage: c = a * b sage: a.left_divides(c) True sage: b.left_divides(c) @@ -758,7 +766,7 @@ cdef class OrePolynomial(AlgebraElement): Divisibility by `0` does not make sense:: - sage: S(0).left_divides(c) + sage: S(0).left_divides(c) # needs sage.rings.finite_rings Traceback (most recent call last): ... ZeroDivisionError: division by zero is not valid @@ -772,7 +780,7 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` OUTPUT: @@ -780,12 +788,13 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x^2 + t*x + t^2 + 3 sage: b = x^3 + (t + 1)*x^2 + 1 - sage: c = a*b + sage: c = a * b sage: a.right_divides(c) False sage: b.right_divides(c) @@ -793,7 +802,7 @@ cdef class OrePolynomial(AlgebraElement): Divisibility by `0` does not make sense:: - sage: S(0).right_divides(c) + sage: S(0).right_divides(c) # needs sage.rings.finite_rings Traceback (most recent call last): ... ZeroDivisionError: division by zero is not valid @@ -827,14 +836,14 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``); return whether the left gcd should be normalized to be monic OUTPUT: - - The left gcd of ``self`` and ``other``, that is a Ore polynomial + - The left gcd of ``self`` and ``other``, that is an Ore polynomial `g` with the following property: any Ore polynomial is divisible on the left by `g` iff it is divisible on the left by both ``self`` and ``other``. @@ -845,7 +854,7 @@ cdef class OrePolynomial(AlgebraElement): .. MATH:: - g = a * u + b * v, + g = a \cdot u + b \cdot v, where `s` is ``self`` and `b` is ``other``. @@ -858,6 +867,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -870,9 +880,9 @@ cdef class OrePolynomial(AlgebraElement): Specifying ``monic=False``, we *can* get a nonmonic gcd:: - sage: g,u,v = a.left_xgcd(b, monic=False); g + sage: g,u,v = a.left_xgcd(b, monic=False); g # needs sage.rings.finite_rings 2*t*x + 4*t + 2 - sage: a*u + b*v == g + sage: a*u + b*v == g # needs sage.rings.finite_rings True The base ring must be a field:: @@ -932,7 +942,7 @@ cdef class OrePolynomial(AlgebraElement): cdef _left_quo_rem(self, OrePolynomial other): r""" - Return the quotient and remainder of the left euclidean + Return the quotient and remainder of the left Euclidean division of ``self`` by ``other`` (C implementation). Must be implemented in subclasses. @@ -942,16 +952,16 @@ cdef class OrePolynomial(AlgebraElement): @coerce_binop def left_quo_rem(self, other): r""" - Return the quotient and remainder of the left euclidean + Return the quotient and remainder of the left Euclidean division of ``self`` by ``other``. INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` OUTPUT: - - the quotient and the remainder of the left euclidean + - the quotient and the remainder of the left Euclidean division of this Ore polynomial by ``other`` .. NOTE:: @@ -961,6 +971,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -991,7 +1002,7 @@ cdef class OrePolynomial(AlgebraElement): cdef _right_quo_rem(self, OrePolynomial other): r""" - Return the quotient and remainder of the right euclidean + Return the quotient and remainder of the right Euclidean division of ``self`` by ``other`` (C implementation). Must be implemented in subclasses. @@ -1001,16 +1012,16 @@ cdef class OrePolynomial(AlgebraElement): @coerce_binop def right_quo_rem(self, other): r""" - Return the quotient and remainder of the right euclidean + Return the quotient and remainder of the right Euclidean division of ``self`` by ``other``. INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` OUTPUT: - - the quotient and the remainder of the left euclidean + - the quotient and the remainder of the right Euclidean division of this Ore polynomial by ``other`` .. NOTE:: @@ -1061,14 +1072,14 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``); return whether the right gcd should be normalized to be monic OUTPUT: - - The right gcd of ``self`` and ``other``, that is a Ore polynomial + - The right gcd of ``self`` and ``other``, that is an Ore polynomial `g` with the following property: any Ore polynomial is divisible on the right by `g` iff it is divisible on the right by both ``self`` and ``other``. @@ -1079,7 +1090,7 @@ cdef class OrePolynomial(AlgebraElement): .. MATH:: - g = u * a + v * b + g = u \cdot a + v \cdot b where `a` is ``self`` and `b` is ``other``. @@ -1090,6 +1101,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -1102,9 +1114,9 @@ cdef class OrePolynomial(AlgebraElement): Specifying ``monic=False``, we *can* get a nonmonic gcd:: - sage: g,u,v = a.right_xgcd(b,monic=False); g + sage: g,u,v = a.right_xgcd(b, monic=False); g # needs sage.rings.finite_rings (4*t^2 + 4*t + 1)*x + 4*t^2 + 4*t + 3 - sage: u*a + v*b == g + sage: u*a + v*b == g # needs sage.rings.finite_rings True The base ring must be a field:: @@ -1152,14 +1164,14 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``); return whether the right gcd should be normalized to be monic OUTPUT: - The right gcd of ``self`` and ``other``, that is a Ore polynomial + The right gcd of ``self`` and ``other``, that is an Ore polynomial `g` with the following property: any Ore polynomial is divisible on the right by `g` iff it is divisible on the right by both ``self`` and ``other``. @@ -1173,6 +1185,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -1183,7 +1196,7 @@ cdef class OrePolynomial(AlgebraElement): Specifying ``monic=False``, we *can* get a nonmonic gcd:: - sage: a.right_gcd(b,monic=False) + sage: a.right_gcd(b,monic=False) # needs sage.rings.finite_rings (4*t^2 + 4*t + 1)*x + 4*t^2 + 4*t + 3 The base ring need to be a field:: @@ -1217,14 +1230,14 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``); return whether the left gcd should be normalized to be monic OUTPUT: - The left gcd of ``self`` and ``other``, that is a Ore polynomial + The left gcd of ``self`` and ``other``, that is an Ore polynomial `g` with the following property: any Ore polynomial is divisible on the left by `g` iff it is divisible on the left by both ``self`` and ``other``. @@ -1240,6 +1253,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -1250,13 +1264,14 @@ cdef class OrePolynomial(AlgebraElement): Specifying ``monic=False``, we *can* get a nonmonic gcd:: - sage: a.left_gcd(b,monic=False) + sage: a.left_gcd(b,monic=False) # needs sage.rings.finite_rings 2*t*x + 4*t + 2 The base ring needs to be a field:: + sage: # needs sage.rings.finite_rings sage: R.<t> = QQ[] - sage: sigma = R.hom([t+1]) + sage: sigma = R.hom([t + 1]) sage: S.<x> = R['x',sigma] sage: a = (x + t) * (x^2 + t*x + 1) sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) @@ -1267,6 +1282,7 @@ cdef class OrePolynomial(AlgebraElement): And the twisting morphism needs to be bijective:: + sage: # needs sage.rings.finite_rings sage: FR = R.fraction_field() sage: f = FR.hom([FR(t)^2]) sage: S.<x> = FR['x',f] @@ -1275,7 +1291,8 @@ cdef class OrePolynomial(AlgebraElement): sage: a.left_gcd(b) Traceback (most recent call last): ... - NotImplementedError: inversion of the twisting morphism Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Rational Field + NotImplementedError: inversion of the twisting morphism Ring endomorphism + of Fraction Field of Univariate Polynomial Ring in t over Rational Field Defn: t |--> t^2 """ if self.base_ring() not in _Fields: @@ -1294,23 +1311,23 @@ cdef class OrePolynomial(AlgebraElement): cdef OrePolynomial _left_lcm_cofactor(self, OrePolynomial other): r""" - Return a Ore polynomial `U` such that `U P = c L` + Return an Ore polynomial `U` such that `U P = c L` where `P` is this Ore polynomial (``self``), `L` is the left lcm of `P` and ``other`` and `c` is a constant TESTS:: - sage: cython(''' # optional - sage.misc.cython + sage: # needs sage.misc.cython sage.rings.finite_rings + sage: cython( + ....: ''' ....: from sage.rings.polynomial.ore_polynomial_element cimport OrePolynomial ....: def left_lcm_cofactor(OrePolynomial P, OrePolynomial Q): ....: return P._left_lcm_cofactor(Q) ....: ''') - sage: k.<a> = GF(7^5) sage: Frob = k.frobenius_endomorphism(3) sage: S.<x> = k['x', Frob] - sage: D = S.random_element(degree=2) sage: P = S.random_element(degree=2) * D sage: Q = S.random_element(degree=2) * D @@ -1343,6 +1360,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -1352,9 +1370,9 @@ cdef class OrePolynomial(AlgebraElement): sage: L x^5 + (2*t^2 + t + 4)*x^4 + (3*t^2 + 4)*x^3 + (3*t^2 + 3*t + 2)*x^2 + (t^2 + t + 2)*x - sage: U*P == L + sage: U * P == L # needs sage.rings.finite_rings True - sage: V*Q == L + sage: V * Q == L # needs sage.rings.finite_rings True """ if self.base_ring() not in _Fields: @@ -1371,23 +1389,23 @@ cdef class OrePolynomial(AlgebraElement): cdef OrePolynomial _right_lcm_cofactor(self, OrePolynomial other): r""" - Return a Ore polynomial `U` such that `P U = L c` + Return an Ore polynomial `U` such that `P U = L c` where `P` is this Ore polynomial (``self``), `L` is the right lcm of `P` and ``other`` and `c` is a constant TESTS:: - sage: cython(''' # optional - sage.misc.cython + sage: # needs sage.misc.cython sage.rings.finite_rings + sage: cython( + ....: ''' ....: from sage.rings.polynomial.ore_polynomial_element cimport OrePolynomial ....: def right_lcm_cofactor(OrePolynomial P, OrePolynomial Q): ....: return P._right_lcm_cofactor(Q) ....: ''') - sage: k.<a> = GF(7^5) sage: Frob = k.frobenius_endomorphism(3) sage: S.<x> = k['x', Frob] - sage: D = S.random_element(degree=2) sage: P = D * S.random_element(degree=2) sage: Q = D * S.random_element(degree=2) @@ -1420,13 +1438,14 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` - ``monic`` -- a boolean (default: ``True``); whether the right lcm should be normalized to be monic EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -1435,9 +1454,9 @@ cdef class OrePolynomial(AlgebraElement): sage: L, U, V = P.right_xlcm(Q) sage: L x^4 + (2*t^2 + t + 2)*x^3 + (3*t^2 + 4*t + 1)*x^2 + (3*t^2 + 4*t + 1)*x + t^2 + 4 - sage: P*U == L + sage: P * U == L True - sage: Q*V == L + sage: Q * V == L True """ if self.base_ring() not in _Fields: @@ -1461,18 +1480,17 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``); return whether the left lcm should be normalized to be monic OUTPUT: - The left lcm of ``self`` and ``other``, that is a Ore polynomial - `g` with the following property: any Ore polynomial divides - `g` on the *right* iff it divides both ``self`` and ``other`` - on the *right*. - If monic is ``True``, `g` is in addition monic. (With this + The left lcm of ``self`` and ``other``, that is an Ore polynomial + `l` with the following property: any Ore polynomial is a left multiple of `l` (right divisible by `l`) + iff it is a left multiple of both ``self`` and ``other`` (right divisible by ``self`` and ``other``). + If monic is ``True``, `l` is in addition monic. (With this extra condition, it is uniquely determined.) .. NOTE:: @@ -1482,6 +1500,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -1496,9 +1515,9 @@ cdef class OrePolynomial(AlgebraElement): sage: a.degree() + b.degree() == c.degree() + a.right_gcd(b).degree() True - Specifying ``monic=False``, we *can* get a nonmonic gcd:: + Specifying ``monic=False``, we *can* get a nonmonic lcm:: - sage: a.left_lcm(b,monic=False) + sage: a.left_lcm(b,monic=False) # needs sage.rings.finite_rings (t^2 + t)*x^5 + (4*t^2 + 4*t + 1)*x^4 + (t + 1)*x^3 + (t^2 + 2)*x^2 + (3*t + 4)*x The base ring needs to be a field:: @@ -1529,17 +1548,16 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a Ore polynomial in the same ring as ``self`` + - ``other`` -- an Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``); return whether the right lcm should be normalized to be monic OUTPUT: - The right lcm of ``self`` and ``other``, that is a Ore polynomial - `g` with the following property: any Ore polynomial divides - `g` on the *left* iff it divides both ``self`` and ``other`` - on the *left*. + The right lcm of ``self`` and ``other``, that is an Ore polynomial + `l` with the following property: any Ore polynomial is a right multiple of `g` (left divisible by `l`) + iff it is a right multiple of both ``self`` and ``other`` (left divisible by ``self`` and ``other``). If monic is ``True``, `g` is in addition monic. (With this extra condition, it is uniquely determined.) @@ -1552,6 +1570,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -1568,7 +1587,7 @@ cdef class OrePolynomial(AlgebraElement): Specifying ``monic=False``, we *can* get a nonmonic gcd:: - sage: a.right_lcm(b,monic=False) + sage: a.right_lcm(b,monic=False) # needs sage.rings.finite_rings 2*t*x^4 + (3*t + 1)*x^3 + (4*t^2 + 4*t + 3)*x^2 + (3*t^2 + 4*t + 2)*x + 3*t^2 + 2*t + 3 @@ -1594,7 +1613,8 @@ cdef class OrePolynomial(AlgebraElement): sage: a.right_lcm(b) Traceback (most recent call last): ... - NotImplementedError: inversion of the twisting morphism Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Rational Field + NotImplementedError: inversion of the twisting morphism Ring endomorphism of + Fraction Field of Univariate Polynomial Ring in t over Rational Field Defn: t |--> t^2 """ if self.base_ring() not in _Fields: @@ -2050,6 +2070,7 @@ cdef class OrePolynomial(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] @@ -2171,7 +2192,7 @@ cdef class OrePolynomial(AlgebraElement): cdef void lmul_gen(list A, Morphism m, d): r""" - If ``A`` is the list of coefficients of a Ore polynomial ``P``, + If ``A`` is the list of coefficients of an Ore polynomial ``P``, replace it by the list of coefficients of ``X*P`` (where ``X`` is the variable in the Ore polynomial ring). @@ -2203,7 +2224,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): """ def __init__(self, parent, x=None, int check=1, int construct=0, **kwds): r""" - Construct a Ore polynomial over the given parent with the given + Construct an Ore polynomial over the given parent with the given coefficients. INPUT: @@ -2222,7 +2243,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] - We create a Ore polynomial from a list:: + We create an Ore polynomial from a list:: sage: S([t,1]) x + t @@ -2248,7 +2269,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): if isinstance(x, list): if check: self._coeffs = [R(t) for t in x] - self.__normalize() + self._normalize() else: self._coeffs = x return @@ -2267,7 +2288,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): else: self._coeffs = [R(a, **kwds) for a in x.list()] if check: - self.__normalize() + self._normalize() return elif isinstance(x, int) and x == 0: @@ -2281,7 +2302,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): x = [x] if check: self._coeffs = [R(z, **kwds) for z in x] - self.__normalize() + self._normalize() else: self._coeffs = x @@ -2356,10 +2377,10 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): f._parent = P f._coeffs = coeffs if check: - f.__normalize() + f._normalize() return f - cdef void __normalize(self): + cdef void _normalize(self): r""" Remove higher order `0`-coefficients from the representation of ``self``. @@ -2492,7 +2513,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): X[i] = c return X - cpdef int degree(self): + cpdef Integer degree(self): r""" Return the degree of ``self``. @@ -2511,8 +2532,25 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): sage: S(0).degree() -1 + + TESTS: + + We check that the degree is an ``Integer`` object (see #35519):: + + sage: R.<t> = ZZ[] + sage: sigma = R.hom([t+1]) + sage: S.<x> = R['x',sigma] + sage: a = x^2 + t*x^3 + t^2*x + 1 + sage: isinstance(a.degree(), Integer) + True + + :: + + sage: R.<t> = OrePolynomialRing(GF(5)['T'], GF(5)['T'].frobenius_endomorphism()) + sage: isinstance((t + 1).degree(), Integer) + True """ - return len(self._coeffs) - 1 + return Integer(len(self._coeffs) - 1) cpdef _add_(self, right): r""" @@ -2714,7 +2752,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): INPUT: - - ``right`` -- a Ore polynomial in the same ring as ``self`` + - ``right`` -- an Ore polynomial in the same ring as ``self`` EXAMPLES:: @@ -2749,7 +2787,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): cdef _left_quo_rem(self, OrePolynomial other): r""" - Return the quotient and remainder of the left euclidean + Return the quotient and remainder of the left Euclidean division of ``self`` by ``other`` (C implementation). """ sig_check() @@ -2778,7 +2816,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): cdef _right_quo_rem(self, OrePolynomial other): r""" - Return the quotient and remainder of the right euclidean + Return the quotient and remainder of the right Euclidean division of ``self`` by ``other`` (C implementation). """ sig_check() @@ -2869,22 +2907,23 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): When the twisting morphism is not trivial, the output lies in a different Ore polynomial ring:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x', Frob] - sage: P = x^2 + a*x + a^2 sage: Q = P.hilbert_shift(a); Q x^2 + (2*a^2 + a + 4)*x + a^2 + 3*a + 4 - sage: Q.parent() - Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 and a*([a |--> a^5] - id) + Ore Polynomial Ring in x over + Finite Field in a of size 5^3 twisted by a |--> a^5 and a*([a |--> a^5] - id) sage: Q.parent() is S False This behavior ensures that the Hilbert shift by a fixed element defines an homomorphism of rings:: + sage: # needs sage.rings.finite_rings sage: U = S.random_element(degree=5) sage: V = S.random_element(degree=5) sage: s = k.random_element() @@ -2896,6 +2935,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): We check that shifting by an element and then by its opposite gives back the initial Ore polynomial:: + sage: # needs sage.rings.finite_rings sage: P = S.random_element(degree=10) sage: s = k.random_element() sage: P.hilbert_shift(s).hilbert_shift(-s) == P @@ -2930,7 +2970,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): cdef class ConstantOrePolynomialSection(Map): r""" - Representation of the canonical homomorphism from the constants of a Ore + Representation of the canonical homomorphism from the constants of an Ore polynomial ring to the base ring. This class is necessary for automatic coercion from zero-degree Ore @@ -2944,7 +2984,8 @@ cdef class ConstantOrePolynomialSection(Map): sage: S.<x> = R['x',sigma] sage: m = ConstantOrePolynomialSection(S, R); m Generic map: - From: Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 + From: Ore Polynomial Ring in x over Univariate Polynomial Ring in t + over Rational Field twisted by t |--> t + 1 To: Univariate Polynomial Ring in t over Rational Field """ cpdef Element _call_(self, x): @@ -2982,7 +3023,7 @@ cdef class ConstantOrePolynomialSection(Map): cdef class OrePolynomialBaseringInjection(Morphism): r""" - Representation of the canonical homomorphism from a ring `R` into a Ore + Representation of the canonical homomorphism from a ring `R` into an Ore polynomial ring over `R`. This class is necessary for automatic coercion from the base ring to the Ore @@ -3000,7 +3041,8 @@ cdef class OrePolynomialBaseringInjection(Morphism): sage: S.coerce_map_from(S.base_ring()) #indirect doctest Ore Polynomial base injection morphism: From: Univariate Polynomial Ring in t over Rational Field - To: Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 + To: Ore Polynomial Ring in x over Univariate Polynomial Ring in t + over Rational Field twisted by t |--> t + 1 """ def __init__(self, domain, codomain): r""" @@ -3010,11 +3052,12 @@ cdef class OrePolynomialBaseringInjection(Morphism): - ``domain`` -- a ring `R`. This will be the domain of the injection. - - ``codomain`` -- a Ore polynomial ring over ``domain``. This will be + - ``codomain`` -- an Ore polynomial ring over ``domain``. This will be the codomain. TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() @@ -3042,6 +3085,7 @@ cdef class OrePolynomialBaseringInjection(Morphism): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() @@ -3067,6 +3111,7 @@ cdef class OrePolynomialBaseringInjection(Morphism): TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() @@ -3084,11 +3129,12 @@ cdef class OrePolynomialBaseringInjection(Morphism): def section(self): r""" - Return the canonical homomorphism from the constants of a Ore + Return the canonical homomorphism from the constants of an Ore polynomial ring to the base ring according to ``self``. TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() @@ -3096,7 +3142,8 @@ cdef class OrePolynomialBaseringInjection(Morphism): sage: m = OrePolynomialBaseringInjection(k, k['x', Frob]) sage: m.section() Generic map: - From: Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 - To: Finite Field in t of size 5^3 + From: Ore Polynomial Ring in x over Finite Field in t of size 5^3 + twisted by t |--> t^5 + To: Finite Field in t of size 5^3 """ return ConstantOrePolynomialSection(self._codomain, self.domain()) diff --git a/src/sage/rings/polynomial/ore_polynomial_ring.py b/src/sage/rings/polynomial/ore_polynomial_ring.py index f7eacf3112a..88db16fd111 100644 --- a/src/sage/rings/polynomial/ore_polynomial_ring.py +++ b/src/sage/rings/polynomial/ore_polynomial_ring.py @@ -23,6 +23,7 @@ from sage.misc.prandom import randint from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.rings.infinity import Infinity from sage.structure.category_object import normalize_names @@ -36,11 +37,12 @@ from sage.rings.ring import _Fields from sage.categories.morphism import Morphism -from sage.rings.derivation import RingDerivation from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection +lazy_import('sage.rings.derivation', 'RingDerivation') + WORKING_CENTER_MAX_TRIES = 1000 diff --git a/src/sage/rings/polynomial/padics/__init__.py b/src/sage/rings/polynomial/padics/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/games/__init__.py b/src/sage/rings/polynomial/padics/all.py similarity index 100% rename from src/sage/games/__init__.py rename to src/sage/rings/polynomial/padics/all.py diff --git a/src/sage/rings/polynomial/padics/polynomial_padic.py b/src/sage/rings/polynomial/padics/polynomial_padic.py index c4719f31836..b9c16923cc3 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic.py @@ -189,7 +189,8 @@ def factor(self): sage: factor(t^2) Traceback (most recent call last): ... - PrecisionError: p-adic factorization not well-defined since the discriminant is zero up to the requestion p-adic precision + PrecisionError: p-adic factorization not well-defined since + the discriminant is zero up to the requestion p-adic precision An example of factoring a constant polynomial (see :trac:`26669`):: @@ -252,11 +253,10 @@ def factor(self): G = self_normal.__pari__().factorpadic(self.base_ring().prime(), absprec) return _pari_padic_factorization_to_sage(G, self.parent(), self.leading_coefficient()) - def root_field(self, names, check_irreducible=True, **kwds): """ - Return the p-adic extension field generated by the roots of the irreducible - polynomial self. + Return the `p`-adic extension field generated by the roots of the irreducible + polynomial ``self``. INPUT: diff --git a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py index d41eaee7dd1..204ae5c54f4 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py @@ -354,11 +354,12 @@ def lift(self): def __getitem__(self, n): """ - Returns the coefficient of x^n if `n` is an integer, - returns the monomials of self of degree in slice `n` if `n` is a slice. - Return the `n`-th coefficient of ``self``. + This returns the coefficient of `x^n` if `n` is an integer, + and returns the monomials of ``self`` of degree + in slice `n` if `n` is a slice ``[:k]``. + EXAMPLES:: sage: K = Qp(13,7) @@ -372,35 +373,28 @@ def __getitem__(self, n): sage: a[:2] (13^2 + O(13^4))*t + 12*13^4 + 12*13^5 + 12*13^6 + 12*13^7 + 12*13^8 + 12*13^9 + 12*13^10 + O(13^11) - Any other kind of slicing is deprecated or an error, see - :trac:`18940`:: + Any other kind of slicing is an error, see :trac:`18940`:: sage: a[1:3] - doctest:warning...: - DeprecationWarning: polynomial slicing with a start index is deprecated, use list() and slice the resulting list instead - See https://github.com/sagemath/sage/issues/18940 for details. - 0*t^2 + (13^2 + O(13^4))*t + Traceback (most recent call last): + ... + IndexError: polynomial slicing with a start is not defined + sage: a[1:3:2] Traceback (most recent call last): ... - NotImplementedError: polynomial slicing with a step is not defined + IndexError: polynomial slicing with a step is not defined """ d = len(self._relprecs) # = degree + 1 if isinstance(n, slice): start, stop, step = n.start, n.stop, n.step if step is not None: - raise NotImplementedError("polynomial slicing with a step is not defined") - if start is None: - start = 0 - else: - if start < 0: - start = 0 - from sage.misc.superseded import deprecation - deprecation(18940, "polynomial slicing with a start index is deprecated, use list() and slice the resulting list instead") + raise IndexError("polynomial slicing with a step is not defined") + if start is not None: + raise IndexError("polynomial slicing with a start is not defined") if stop is None or stop > d: stop = d - values = ([self.base_ring().zero()] * start - + [self[i] for i in range(start, stop)]) + values = [self[i] for i in range(stop)] return self.parent()(values) try: @@ -661,7 +655,7 @@ def rshift_coeffs(self, shift, no_list=False): return Polynomial_padic_capped_relative_dense(self.parent(), (self._poly // fdiv, 0, [0 if a <= shift else a - shift for a in self._relprecs], False, None, None), construct=True) # def __floordiv__(self, right): - # if is_Polynomial(right) and right.is_constant() and right[0] in self.base_ring(): + # if isinstance(right, Polynomial) and right.is_constant() and right[0] in self.base_ring(): # d = self.base_ring()(right[0]) # elif (right in self.base_ring()): # d = self.base_ring()(right) @@ -737,7 +731,7 @@ def _unsafe_mutate(self, n, value): def __pari__(self, variable=None): """ - Return ``self`` as a Pari object. + Return ``self`` as a PARI object. """ if variable is None: variable = self.parent().variable_name() @@ -755,7 +749,7 @@ def degree(self, secure=False): INPUT: - - secure -- a boolean (default: ``False``) + - ``secure`` -- a boolean (default: ``False``) If ``secure`` is ``True`` and the degree of this polynomial is not determined (because the leading coefficient is @@ -823,15 +817,15 @@ def precision_absolute(self, n=None): INPUT: - ``self`` -- a p-adic polynomial + - ``self`` -- a p-adic polynomial - n -- ``None`` or an integer (default ``None``). + - ``n`` -- ``None`` or an integer (default ``None``). OUTPUT: - If n == None, returns a list of absolute precisions of + If ``n`` is ``None``, returns a list of absolute precisions of coefficients. Otherwise, returns the absolute precision of - the coefficient of x^n. + the coefficient of `x^n`. EXAMPLES:: @@ -852,15 +846,15 @@ def precision_relative(self, n=None): INPUT: - ``self`` -- a p-adic polynomial + - ``self`` -- a p-adic polynomial - n -- ``None`` or an integer (default ``None``). + - ``n`` -- ``None`` or an integer (default ``None``). OUTPUT: - If n == None, returns a list of relative precisions of + If ``n`` is ``None``, returns a list of relative precisions of coefficients. Otherwise, returns the relative precision of - the coefficient of x^n. + the coefficient of `x^n`. EXAMPLES:: @@ -888,14 +882,14 @@ def valuation_of_coefficient(self, n=None): INPUT: - ``self`` -- a p-adic polynomial + - ``self`` -- a p-adic polynomial - n -- ``None`` or an integer (default ``None``). + - ``n`` -- ``None`` or an integer (default ``None``). OUTPUT: - If n == None, returns a list of valuations of coefficients. Otherwise, - returns the valuation of the coefficient of x^n. + If ``n`` is ``None``, returns a list of valuations of coefficients. Otherwise, + returns the valuation of the coefficient of `x^n`. EXAMPLES:: @@ -922,15 +916,15 @@ def valuation(self, val_of_var=None): INPUT: - ``self`` -- a p-adic polynomial + - ``self`` -- a p-adic polynomial - val_of_var -- ``None`` or a rational (default ``None``). + - ``val_of_var`` -- ``None`` or a rational (default ``None``). OUTPUT: - If val_of_var == None, returns the largest power of the + If ``val_of_var`` is ``None``, returns the largest power of the variable dividing self. Otherwise, returns the valuation of - ``self`` where the variable is assigned valuation val_of_var + ``self`` where the variable is assigned valuation ``val_of_var`` EXAMPLES:: @@ -1003,7 +997,7 @@ def reverse(self, degree=None): def rescale(self, a): r""" - Return f(a*X) + Return `f(a\cdot x)`. .. TODO:: @@ -1091,7 +1085,7 @@ def _quo_rem_naive(self, right): def _quo_rem_list(self, right, secure): """ - An implementation of quo_rem using lists of coefficients. + An implementation of :meth:`quo_rem` using lists of coefficients. Faster than :meth:`_quo_rem_naive`. @@ -1144,7 +1138,7 @@ def newton_polygon(self): OUTPUT: - - a Newton polygon + - a :class:`NewtonPolygon` EXAMPLES:: diff --git a/src/sage/rings/polynomial/pbori/__init__.py b/src/sage/rings/polynomial/pbori/__init__.py index 8fe962e2275..325ed646516 100644 --- a/src/sage/rings/polynomial/pbori/__init__.py +++ b/src/sage/rings/polynomial/pbori/__init__.py @@ -41,75 +41,3 @@ from .blocks import HigherOrderBlock, AlternatingBlock, Block from .gbrefs import load_file from .specialsets import all_monomials_of_degree_d, power_set - -# Advertised reimports -# ... any from below? ... - -# Deprecated reimports - -lazy_import('sage.rings.polynomial.pbori.pbori', - ['BooleConstant', - 'BooleSet', - 'BooleSetIterator', - 'BooleanMonomial', - 'BooleanMonomialIterator', - 'BooleanMonomialMonoid', - 'BooleanMonomialVariableIterator', - 'BooleanMulAction', - 'BooleanPolynomial', - 'BooleanPolynomialEntry', - 'BooleanPolynomialIdeal', - 'BooleanPolynomialIterator', - 'BooleanPolynomialRing', - 'BooleanPolynomialVector', - 'BooleanPolynomialVectorIterator', - 'CCuddNavigator', - 'FGLMStrategy', - 'GroebnerStrategy', - 'MonomialConstruct', - 'MonomialFactory', - 'PolynomialConstruct', - 'PolynomialFactory', - 'ReductionStrategy', - 'TermOrder_from_pb_order', - 'VariableBlock', - 'VariableConstruct', - 'add_up_polynomials', - 'block_dlex', - 'block_dp_asc', - 'contained_vars', - 'dlex', - 'dp', - 'dp_asc', - 'easy_linear_factors', - 'gauss_on_polys', - 'get_var_mapping', - 'if_then_else', - 'interpolate', - 'interpolate_smallest_lex', - 'inv_order_dict', - 'll_red_nf_noredsb', - 'll_red_nf_noredsb_single_recursive_call', - 'll_red_nf_redsb', - 'lp', - 'map_every_x_to_x_plus_one', - 'mod_mon_set', - 'mod_var_set', - 'mult_fact_sim_C', - 'nf3', - 'order_dict', - 'order_mapping', - 'parallel_reduce', - 'random_set', - 'recursively_insert', - 'red_tail', - 'rings', - 'set_random_seed', - 'singular_default', - 'substitute_variables', - 'top_index', - 'unpickle_BooleanPolynomial', - 'unpickle_BooleanPolynomial0', - 'unpickle_BooleanPolynomialRing', - 'zeros'], - deprecation=30332) diff --git a/src/sage/rings/polynomial/pbori/blocks.py b/src/sage/rings/polynomial/pbori/blocks.py index 4115c35f832..752e0a14ee8 100644 --- a/src/sage/rings/polynomial/pbori/blocks.py +++ b/src/sage/rings/polynomial/pbori/blocks.py @@ -366,8 +366,7 @@ def canonicalize(blocks): if isinstance(elt, str): yield elt else: - for subelt in elt: - yield subelt + yield from elt blocks = list(blocks) n = 0 diff --git a/src/sage/rings/polynomial/pbori/ll.py b/src/sage/rings/polynomial/pbori/ll.py index b12985797a7..a48e7e2a84a 100644 --- a/src/sage/rings/polynomial/pbori/ll.py +++ b/src/sage/rings/polynomial/pbori/ll.py @@ -284,6 +284,8 @@ def invert(self, poly): r""" Inverted map to initial ring. + EXAMPLES:: + sage: from sage.rings.polynomial.pbori.pbori import * sage: from sage.rings.polynomial.pbori.blocks import declare_ring, Block sage: to_ring = declare_ring([Block("x", 10)], globals()) diff --git a/src/sage/rings/polynomial/pbori/pbori.pxd b/src/sage/rings/polynomial/pbori/pbori.pxd index 85f21d0edf3..ae4ac1353d2 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pxd +++ b/src/sage/rings/polynomial/pbori/pbori.pxd @@ -1,14 +1,13 @@ from libcpp.memory cimport unique_ptr, shared_ptr, make_shared -from sage.rings.polynomial.multi_polynomial_ring_base cimport \ - MPolynomialRing_base +from sage.rings.polynomial.multi_polynomial_ring_base cimport MPolynomialRing_base, BooleanPolynomialRing_base from sage.rings.polynomial.multi_polynomial cimport MPolynomial from sage.structure.element cimport MonoidElement from sage.libs.polybori.decl cimport * -cdef class BooleanPolynomialRing(MPolynomialRing_base): +cdef class BooleanPolynomialRing(BooleanPolynomialRing_base): cdef PBRing _pbring cdef Py_ssize_t* pbind cdef public _monom_monoid @@ -42,8 +41,9 @@ cdef class BooleanMonomialVariableIterator: cdef object parent cdef BooleanPolynomialRing _ring cdef BooleanMonomial obj - cdef PBMonomVarIter _iter - cdef PBMonomVarIter _end + cdef PBMonomIter _iter + cdef PBMonomIter _end + cdef Py_ssize_t* pbind cdef class BooleanMonomialIterator: cdef BooleanMonomial obj diff --git a/src/sage/rings/polynomial/pbori/pbori.pyx b/src/sage/rings/polynomial/pbori/pbori.pyx index 7765e87995d..314196faa14 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pyx +++ b/src/sage/rings/polynomial/pbori/pbori.pyx @@ -178,7 +178,6 @@ native PolyBoRi counterparts. For instance, sets of points can be represented as tuples of tuples (Sage) or as ``BooleSet`` (PolyBoRi) and naturally the second option is faster. """ - from cpython.object cimport Py_EQ, Py_NE from cython.operator cimport dereference as deref from cysignals.memory cimport sig_malloc, sig_free @@ -188,10 +187,7 @@ import operator from sage.cpython.string cimport str_to_bytes, char_to_str -from sage.misc.cachefunc import cached_method - from sage.misc.randstate import current_randstate -from sage.arith.long cimport pyobject_to_long import sage.misc.weak_dict from sage.rings.integer import Integer from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF @@ -203,7 +199,6 @@ from sage.rings.polynomial.polynomial_ring import PolynomialRing_general from sage.rings.ideal import FieldIdeal -from sage.structure.coerce cimport coercion_model from sage.structure.element cimport Element from sage.structure.parent cimport Parent @@ -257,7 +252,7 @@ block_dp_asc = int(pbblock_dp_asc) rings = sage.misc.weak_dict.WeakValueDictionary() -cdef class BooleanPolynomialRing(MPolynomialRing_base): +cdef class BooleanPolynomialRing(BooleanPolynomialRing_base): """ Construct a boolean polynomial ring with the following parameters: @@ -410,7 +405,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): pbnames = tuple(names) names = [name.replace('(', '').replace(')', '') for name in pbnames] - MPolynomialRing_base.__init__(self, GF((2,1)), n, names, order) + BooleanPolynomialRing_base.__init__(self, GF((2,1)), n, names, order) counter = 0 for i in range(len(order.blocks()) - 1): @@ -552,7 +547,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): """ return tuple(new_BP_from_PBVar(self, self._pbring.variable(self.pbind[i])) - for i in range(self.__ngens)) + for i in range(self._ngens)) def change_ring(self, base_ring=None, names=None, order=None): """ @@ -841,8 +836,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): raise TypeError("cannot coerce monomial %s to %s" % (other, self)) elif isinstance(other, BooleanPolynomial) and \ - ((<BooleanPolynomialRing>(<BooleanPolynomial>other)\ - ._parent)._pbring.nVariables() <= self._pbring.nVariables()): + ((<BooleanPolynomialRing>(<BooleanPolynomial>other)._parent)._pbring.nVariables() <= self._pbring.nVariables()): # try PolyBoRi's built-in coercions if self._pbring.hash() == \ (<BooleanPolynomialRing>(<BooleanPolynomial>other)._parent)._pbring.hash(): @@ -1099,13 +1093,11 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): INPUT: - - ``gens`` - list or tuple of generators - ``coerce`` - bool (default: True) automatically coerce the given polynomials to this ring to form the ideal - EXAMPLES:: sage: P.<x,y,z> = BooleanPolynomialRing(3) @@ -1220,7 +1212,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: B = BooleanPolynomialRing(n, 'x') sage: r = B.random_element(terms=(n/2)**2) """ - from sage.rings.integer import Integer from sage.arith.misc import binomial if not vars_set: @@ -1271,7 +1262,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): INPUT: - - ``degree`` - maximum degree - ``monom_counts`` - a list containing total number @@ -1285,7 +1275,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): - ``l`` - number of monomials to generate - EXAMPLES:: sage: P.<x,y,z> = BooleanPolynomialRing(3) @@ -1293,8 +1282,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: all(t in [x, y, x*y, P(1)] for t in f.terms()) True """ - from sage.rings.integer import Integer - from sage.rings.integer_ring import ZZ if l == 0: return self._zero_element if l == 1: @@ -1303,10 +1290,10 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): else: return self._random_monomial_uniform(monom_counts, vars_set) - return self._random_uniform_rec(degree, monom_counts, - vars_set, dfirst, l//2) + \ - self._random_uniform_rec(degree, monom_counts, - vars_set, dfirst, l - l//2) + return (self._random_uniform_rec(degree, monom_counts, + vars_set, dfirst, l // 2) + + self._random_uniform_rec(degree, monom_counts, + vars_set, dfirst, l - l // 2)) def _random_monomial_uniform(self, monom_counts, vars_set): r""" @@ -1315,14 +1302,12 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): INPUT: - - ``monom_counts`` - list of number of monomials up to given degree - ``vars_set`` - list of variable indices to use in the generated monomial - EXAMPLES:: sage: P.<x,y,z> = BooleanPolynomialRing(3) @@ -1361,12 +1346,10 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): INPUT: - - ``degree`` - maximum degree - ``vars_set`` - list of variable indices of self - EXAMPLES:: sage: P.<x,y,z> = BooleanPolynomialRing(3) @@ -1491,14 +1474,12 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): INPUT: - - ``zeros`` - the set of interpolation points mapped to zero - ``ones`` - the set of interpolation points mapped to one - EXAMPLES: First we create a random-ish boolean polynomial. @@ -1879,7 +1860,6 @@ class BooleanMonomialMonoid(UniqueRepresentation, Monoid_class): - ``polring`` - the polynomial ring our monomials lie in - EXAMPLES:: sage: from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid @@ -2080,7 +2060,7 @@ class BooleanMonomialMonoid(UniqueRepresentation, Monoid_class): ValueError: cannot convert monomial t*x*y to MonomialMonoid of Boolean PolynomialRing in x, y, z: name t not defined """ if isinstance(other, BooleanMonomial) and \ - ((<BooleanMonomial>other)._parent.ngens() <= \ + ((<BooleanMonomial>other)._parent.ngens() <= (<BooleanPolynomialRing>self._ring)._pbring.nVariables()): try: var_mapping = get_var_mapping(self, other.parent()) @@ -2182,14 +2162,12 @@ class BooleanMonomialMonoid(UniqueRepresentation, Monoid_class): return new_BM_from_PBMonom(self, (<BooleanPolynomialRing>self._ring), (<BooleanPolynomial>other)._pbpoly.lead()) - elif ((<BooleanPolynomial>other)._pbpoly.nUsedVariables() <= \ + elif ((<BooleanPolynomial>other)._pbpoly.nUsedVariables() <= (<BooleanPolynomialRing>self._ring)._pbring.nVariables()): try: var_mapping = get_var_mapping(self, other) except NameError as msg: raise ValueError("cannot convert polynomial %s to %s: %s" % (other, self, msg)) - t = (<BooleanPolynomial>other)._pbpoly.lead() - m = self._one_element for i in new_BMI_from_BooleanMonomial(other.lm()): m*= var_mapping[i] @@ -2373,7 +2351,6 @@ cdef class BooleanMonomial(MonoidElement): sage: m(x=B(1)) y """ - P = self.parent() if args and kwds: raise ValueError("using keywords and regular arguments not supported") if args: @@ -2810,7 +2787,6 @@ cdef class BooleanMonomial(MonoidElement): - ``rhs`` - a boolean monomial - EXAMPLES:: sage: B.<a,b,c,d> = BooleanPolynomialRing() @@ -2874,11 +2850,14 @@ cdef class BooleanMonomialVariableIterator: sage: next(iter(m)) x """ + cdef int index cdef PBVar value if self._iter == self._end: raise StopIteration - value = self._iter.dereference() + index = self._iter.dereference() self._iter.increment() + value = PBBooleVariable(self.pbind[index], + (<BooleanPolynomialRing>self._ring)._pbring) return new_BM_from_PBVar(self.parent, self._ring, value) cdef inline BooleanMonomialVariableIterator new_BMVI_from_BooleanMonomial( @@ -2892,8 +2871,9 @@ cdef inline BooleanMonomialVariableIterator new_BMVI_from_BooleanMonomial( m.parent = monom._parent m._ring = monom._ring m.obj = monom - m._iter = m.obj._pbmonom.variableBegin() - m._end = m.obj._pbmonom.variableEnd() + m._iter = m.obj._pbmonom.begin() + m._end = m.obj._pbmonom.end() + m.pbind = (<BooleanPolynomialRing> monom.ring()).pbind return m @@ -2954,7 +2934,6 @@ cdef class BooleanPolynomial(MPolynomial): - ``parent`` - a boolean polynomial ring - TESTS:: sage: from sage.rings.polynomial.pbori.pbori import BooleanPolynomial @@ -3740,7 +3719,7 @@ cdef class BooleanPolynomial(MPolynomial): sage: g = R(1) sage: h = g.univariate_polynomial(); h 1 - sage: h.parent() + sage: h.parent() # needs sage.libs.ntl Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) """ if not self.is_univariate(): @@ -3823,10 +3802,8 @@ cdef class BooleanPolynomial(MPolynomial): INPUT: - - ``mon`` - a monomial - EXAMPLES:: sage: P.<x,y> = BooleanPolynomialRing(2) @@ -3938,9 +3915,9 @@ cdef class BooleanPolynomial(MPolynomial): Evaluation of polynomials can be used fully symbolic:: - sage: f(x=var('a'),y=var('b'),z=var('c')) + sage: f(x=var('a'), y=var('b'), z=var('c')) # needs sage.symbolic a*b + c + 1 - sage: f(var('a'),var('b'),1) + sage: f(var('a'), var('b'), 1) # needs sage.symbolic a*b """ P = self._parent @@ -3985,13 +3962,11 @@ cdef class BooleanPolynomial(MPolynomial): INPUT: - - ``in_dict`` - (optional) dict with variable:value pairs - ``**kwds`` - names parameters - EXAMPLES:: sage: P.<x,y,z> = BooleanPolynomialRing(3) @@ -4021,9 +3996,9 @@ cdef class BooleanPolynomial(MPolynomial): This method can work fully symbolic:: - sage: f.subs(x=var('a'),y=var('b'),z=var('c')) + sage: f.subs(x=var('a'), y=var('b'), z=var('c')) # needs sage.symbolic a*b + b*c + c + 1 - sage: f.subs({'x':var('a'),'y':var('b'),'z':var('c')}) + sage: f.subs({'x': var('a'), 'y': var('b'), 'z': var('c')}) # needs sage.symbolic a*b + b*c + c + 1 """ P = self._parent @@ -4031,7 +4006,7 @@ cdef class BooleanPolynomial(MPolynomial): fixed = {} if in_dict is not None: for var, val in in_dict.items(): - if isinstance(var, basestring): + if isinstance(var, str): var = P(var) elif var.parent() is not P: var = P(var) @@ -4388,10 +4363,8 @@ cdef class BooleanPolynomial(MPolynomial): INPUT: - - ``rhs`` - a boolean polynomial - EXAMPLES:: sage: B.<a,b,c,d> = BooleanPolynomialRing(4,order='deglex') @@ -4453,10 +4426,8 @@ cdef class BooleanPolynomial(MPolynomial): INPUT: - - ``deg`` - a degree - EXAMPLES:: sage: B.<a,b,c,d> = BooleanPolynomialRing(4) @@ -4509,10 +4480,8 @@ cdef class BooleanPolynomial(MPolynomial): INPUT: - - ``s`` - candidate points for evaluation to zero - EXAMPLES:: sage: B.<a,b,c,d> = BooleanPolynomialRing(4) @@ -4620,11 +4589,9 @@ cdef class BooleanPolynomial(MPolynomial): INPUT: - - ``I`` - a list/set of polynomials in self.parent(). If I is an ideal, the generators are used. - EXAMPLES:: sage: B.<x0,x1,x2,x3> = BooleanPolynomialRing(4) @@ -4660,7 +4627,6 @@ cdef class BooleanPolynomial(MPolynomial): ... TypeError: argument must be a BooleanPolynomial """ - from sage.rings.polynomial.pbori.pbori import red_tail if not I: return self if isinstance(I, BooleanPolynomialIdeal): @@ -5154,7 +5120,6 @@ class BooleanPolynomialIdeal(MPolynomialIdeal): sage: I.reduce(gb[0]*B.gen(1)) 0 """ - from sage.rings.polynomial.pbori.pbori import red_tail try: g = self.__gb except AttributeError: @@ -6472,7 +6437,6 @@ cdef class ReductionStrategy: return deref(self._strat).size() def __getitem__(self, Py_ssize_t i): - cdef PBPoly t if i < 0 or <size_t>i >= deref(self._strat).size(): raise IndexError return BooleanPolynomialEntry(new_BP_from_PBPoly(self._parent, @@ -6973,7 +6937,6 @@ cdef class GroebnerStrategy: return deref(self._strat).generators.size() def __getitem__(self, Py_ssize_t i): - cdef PBPoly t if i < 0 or <size_t>i >= deref(self._strat).generators.size(): raise IndexError return new_BP_from_PBPoly(self._parent, deref(self._strat).generators[i].p) @@ -7542,10 +7505,9 @@ def if_then_else(root, a, b): if not isinstance(root, int): raise TypeError("only variables are acceptable as root") - cdef Py_ssize_t* pbind = ring.pbind root = ring.pbind[root] - if (root >= a_set.navigation().value()) or (root >= b_set.navigation().value()): + if root >= a_set.navigation().value() or root >= b_set.navigation().value(): raise IndexError("index of root must be less than " "the values of roots of the branches") @@ -7624,7 +7586,7 @@ cdef BooleanPolynomialRing BooleanPolynomialRing_from_PBRing(PBRing _ring): """ Get BooleanPolynomialRing from C++-implementation """ - cdef int i, j + cdef int i cdef BooleanPolynomialRing self = BooleanPolynomialRing.__new__(BooleanPolynomialRing) cdef int n = _ring.nVariables() @@ -7645,7 +7607,7 @@ cdef BooleanPolynomialRing BooleanPolynomialRing_from_PBRing(PBRing _ring): self._pbring = _ring - MPolynomialRing_base.__init__(self, GF(2), n, names, T) + BooleanPolynomialRing_base.__init__(self, GF(2), n, names, T) self._zero_element = new_BP(self) (<BooleanPolynomial>self._zero_element)._pbpoly = PBBoolePolynomial(0, self._pbring) diff --git a/src/sage/rings/polynomial/plural.pxd b/src/sage/rings/polynomial/plural.pxd index 41db2a144e7..d3a46f6aa0d 100644 --- a/src/sage/rings/polynomial/plural.pxd +++ b/src/sage/rings/polynomial/plural.pxd @@ -13,10 +13,10 @@ cdef extern from *: ctypedef long Py_hash_t cdef class NCPolynomialRing_plural(Ring): - cdef object __ngens + cdef object _ngens cdef object _c cdef object _d - cdef object __term_order + cdef object _term_order cdef public object _has_singular cdef public object _magma_gens, _magma_cache diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index d019a89d99e..c9903625b38 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -102,23 +102,21 @@ TESTS:: True """ - from cysignals.memory cimport sig_malloc, sig_free -from sage.cpython.string cimport bytes_to_str from sage.categories.algebras import Algebras from sage.cpython.string cimport char_to_str # singular rings -from sage.libs.singular.ring cimport singular_ring_new, singular_ring_delete, wrap_ring, singular_ring_reference +from sage.libs.singular.ring cimport singular_ring_delete, wrap_ring, singular_ring_reference from sage.libs.singular.singular cimport si2sa, sa2si, overflow_check from sage.libs.singular.function cimport RingWrap -from sage.libs.singular.polynomial cimport (singular_polynomial_call, singular_polynomial_cmp, singular_polynomial_add, singular_polynomial_sub, singular_polynomial_neg, singular_polynomial_pow, singular_polynomial_mul, singular_polynomial_rmul, singular_polynomial_deg, singular_polynomial_str_with_changed_varnames, singular_polynomial_latex, singular_polynomial_str, singular_polynomial_div_coeff) +from sage.libs.singular.polynomial cimport (singular_polynomial_cmp, singular_polynomial_add, singular_polynomial_sub, singular_polynomial_neg, singular_polynomial_pow, singular_polynomial_mul, singular_polynomial_rmul, singular_polynomial_deg, singular_polynomial_str_with_changed_varnames, singular_polynomial_latex, singular_polynomial_str, singular_polynomial_div_coeff) import sage.libs.singular.ring @@ -131,7 +129,7 @@ from sage.rings.polynomial.multi_polynomial_ideal import NCPolynomialIdeal from sage.rings.polynomial.polydict import ETuple from sage.rings.ring import check_default_category -from sage.structure.element cimport CommutativeRingElement, Element, ModuleElement, RingElement +from sage.structure.element cimport CommutativeRingElement, Element, RingElement from sage.structure.factory import UniqueFactory from sage.structure.richcmp cimport rich_to_bool from sage.structure.parent cimport Parent @@ -338,8 +336,8 @@ cdef class NCPolynomialRing_plural(Ring): self._ring = singular_ring_reference(rw._ring) self._ring.ShortOut = 0 - self.__ngens = n - self.__term_order = order + self._ngens = n + self._term_order = order Ring.__init__(self, base_ring, names, category=category) self._populate_coercion_lists_() @@ -533,7 +531,7 @@ cdef class NCPolynomialRing_plural(Ring): elif isinstance(element, CommutativeRingElement): # base ring elements - if <Parent>element.parent() is base_ring: + if <Parent>element.parent() is base_ring: # shortcut for GF(p) if isinstance(base_ring, FiniteField_prime_modn): _p = p_ISet(int(element) % _ring.cf.ch, _ring) @@ -657,7 +655,7 @@ cdef class NCPolynomialRing_plural(Ring): Ambient free module of rank 3 over Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {y*x: -x*y} """ - from sage.modules.all import FreeModule + from sage.modules.free_module import FreeModule return FreeModule(self, n) def term_order(self): @@ -675,7 +673,7 @@ cdef class NCPolynomialRing_plural(Ring): sage: P.term_order() Degree reverse lexicographic term order """ - return self.__term_order + return self._term_order def is_commutative(self): """ @@ -729,7 +727,7 @@ cdef class NCPolynomialRing_plural(Ring): from sage.repl.rich_output.backend_base import BackendBase from sage.repl.display.pretty_print import SagePrettyPrinter varstr = ", ".join(char_to_str(rRingVar(i, self._ring)) - for i in range(self.__ngens)) + for i in range(self._ngens)) backend = BackendBase() relations = backend._apply_pretty_printer(SagePrettyPrinter, self.relations()) @@ -815,7 +813,7 @@ cdef class NCPolynomialRing_plural(Ring): n = self.ngens() for r in range(0, n-1, 1): for c in range(r+1, n, 1): - if (self.gen(c) * self.gen(r) != self.gen(r) * self.gen(c)): + if (self.gen(c) * self.gen(r) != self.gen(r) * self.gen(c)): res[ A.gen(c) * A.gen(r) ] = self.gen(c) * self.gen(r) # C[r, c] * P.gen(r) * P.gen(c) + D[r, c] self._relations = res @@ -832,7 +830,7 @@ cdef class NCPolynomialRing_plural(Ring): sage: P.ngens() 3 """ - return int(self.__ngens) + return int(self._ngens) def gen(self, int n=0): """ @@ -859,7 +857,7 @@ cdef class NCPolynomialRing_plural(Ring): cdef poly *_p cdef ring *_ring = self._ring - if n < 0 or n >= self.__ngens: + if n < 0 or n >= self._ngens: raise ValueError("Generator not defined.") rChangeCurrRing(_ring) @@ -966,10 +964,9 @@ cdef class NCPolynomialRing_plural(Ring): # W = self._list_to_ring(L) # return new_NRing(W, self.base_ring()) - - ### The following methods are handy for implementing Groebner - ### basis algorithms. They do only superficial type/sanity checks - ### and should be called carefully. + # The following methods are handy for implementing Groebner + # basis algorithms. They do only superficial type/sanity checks + # and should be called carefully. def monomial_quotient(self, NCPolynomial_plural f, NCPolynomial_plural g, coeff=False): r""" @@ -1040,14 +1037,13 @@ cdef class NCPolynomialRing_plural(Ring): .. WARNING:: - Assumes that the head term of f is a multiple of the head - term of g and return the multiplicant m. If this rule is - violated, funny things may happen. + Assumes that the head term of f is a multiple of the head + term of g and return the multiplicant m. If this rule is + violated, funny things may happen. """ cdef poly *res cdef ring *r = self._ring cdef number *n - cdef number *denom if self is not f._parent: f = self.coerce(f) @@ -1780,7 +1776,7 @@ cdef class NCPolynomial_plural(RingElement): _I = idInit(len(I),1) for f in I: - if not (isinstance(f, NCPolynomial_plural) \ + if not (isinstance(f, NCPolynomial_plural) and <NCPolynomialRing_plural>(<NCPolynomial_plural>f)._parent is parent): try: f = parent.coerce(f) @@ -1871,7 +1867,7 @@ cdef class NCPolynomial_plural(RingElement): sage: print(f._repr_with_changed_varnames(['FOO', 'BAR', 'FOOBAR'])) -FOO^2*FOOBAR - BAR^2 - 25/27*FOOBAR^3 """ - return singular_polynomial_str_with_changed_varnames(self._poly, (<NCPolynomialRing_plural>self._parent)._ring, varnames) + return singular_polynomial_str_with_changed_varnames(self._poly, (<NCPolynomialRing_plural>self._parent)._ring, varnames) def degree(self, NCPolynomial_plural x=None): """ @@ -1881,7 +1877,7 @@ cdef class NCPolynomial_plural(RingElement): INPUT: - - ``x`` - multivariate polynomial (a generator of the parent of + - ``x`` -- multivariate polynomial (a generator of the parent of self) If x is not specified (or is ``None``), return the total degree, which is the maximum degree of any monomial. @@ -2356,7 +2352,7 @@ cdef class NCPolynomial_plural(RingElement): except TypeError: x = (x,) - if len(x) != (<NCPolynomialRing_plural>self._parent).__ngens: + if len(x) != (<NCPolynomialRing_plural>self._parent)._ngens: raise TypeError("x must have length self.ngens()") m = p_ISet(1,r) @@ -2407,7 +2403,7 @@ cdef class NCPolynomial_plural(RingElement): p = self._poly pl = list() - ml = list(xrange(r.N)) + ml = list(range(r.N)) while p: for v from 1 <= v <= r.N: ml[v - 1] = p_GetExp(p, v, r) @@ -2526,7 +2522,8 @@ cdef class NCPolynomial_plural(RingElement): Check if :trac:`7152` is fixed:: - sage: x=var('x') + sage: # needs sage.symbolic + sage: x = var('x') sage: K.<rho> = NumberField(x**2 + 1) sage: R.<x,y> = QQ[] sage: p = rho*x @@ -2893,8 +2890,8 @@ cpdef MPolynomialRing_libsingular new_CRing(RingWrap rw, base_ring): self._ring.ShortOut = 0 - self.__ngens = rw.ngens() - self.__term_order = TermOrder(rw.ordering_string(), force=True) + self._ngens = rw.ngens() + self._term_order = TermOrder(rw.ordering_string(), force=True) ParentWithGens.__init__(self, base_ring, tuple(rw.var_names()), normalize=False) @@ -2965,8 +2962,8 @@ cpdef NCPolynomialRing_plural new_NRing(RingWrap rw, base_ring): self._ring.ShortOut = 0 - self.__ngens = rw.ngens() - self.__term_order = TermOrder(rw.ordering_string(), force=True) + self._ngens = rw.ngens() + self._term_order = TermOrder(rw.ordering_string(), force=True) ParentWithGens.__init__(self, base_ring, rw.var_names()) # self._populate_coercion_lists_() # ??? diff --git a/src/sage/rings/polynomial/polydict.pxd b/src/sage/rings/polynomial/polydict.pxd index b2c3145c112..6bc1901bd7e 100644 --- a/src/sage/rings/polynomial/polydict.pxd +++ b/src/sage/rings/polynomial/polydict.pxd @@ -1,34 +1,42 @@ cdef class PolyDict: cdef dict __repn - cdef object __zero + + cdef PolyDict _new(self, dict pdict) + cpdef remove_zeros(self, zero_test=*) + cdef class ETuple: cdef size_t _length cdef size_t _nonzero cdef int *_data - cpdef size_t unweighted_degree(self) - cdef size_t weighted_degree(self, tuple w) - cdef size_t unweighted_quotient_degree(self, ETuple other) - cdef size_t weighted_quotient_degree(self, ETuple other, tuple w) - cpdef ETuple eadd(ETuple self, ETuple other) - cpdef ETuple esub(ETuple self, ETuple other) - cpdef ETuple emul(ETuple self, int factor) - cpdef ETuple emin(ETuple self, ETuple other) - cpdef ETuple emax(ETuple self, ETuple other) - cpdef ETuple eadd_p(ETuple self, int other, int pos) - cpdef ETuple eadd_scaled(ETuple self, ETuple other, int scalar) - cpdef int dotprod(ETuple self, ETuple other) - cpdef ETuple escalar_div(ETuple self, int n) - cdef ETuple divide_by_gcd(self, ETuple other) - cdef ETuple divide_by_var(self, size_t index) - cdef bint divides(self, ETuple other) - cpdef bint is_constant(ETuple self) - cpdef bint is_multiple_of(ETuple self, int n) - cpdef list nonzero_positions(ETuple self, bint sort=*) - cpdef common_nonzero_positions(ETuple self, ETuple other, bint sort=*) - cpdef list nonzero_values(ETuple self, bint sort=*) - cpdef ETuple reversed(ETuple self) - cdef ETuple _new(ETuple self) - cdef size_t get_exp(ETuple self, int i) + cdef size_t get_position(self, size_t i, size_t start, size_t end) + cdef ETuple _new(self) + cdef int get_exp(self, size_t i) + + cpdef int unweighted_degree(self) except * + cpdef int weighted_degree(self, tuple w) except * + cpdef int unweighted_quotient_degree(self, ETuple other) except * + cpdef int weighted_quotient_degree(self, ETuple other, tuple w) except * + + cpdef ETuple eadd(self, ETuple other) + cpdef ETuple esub(self, ETuple other) + cpdef ETuple emul(self, int factor) + cpdef ETuple emin(self, ETuple other) + cpdef ETuple emax(self, ETuple other) + cpdef ETuple eadd_p(self, int other, size_t pos) + cpdef ETuple eadd_scaled(self, ETuple other, int scalar) + cpdef int dotprod(self, ETuple other) except * + cpdef ETuple escalar_div(self, int n) + cpdef ETuple divide_by_gcd(self, ETuple other) + cpdef ETuple divide_by_var(self, size_t pos) + cpdef bint divides(self, ETuple other) except * + cpdef bint is_constant(self) + cpdef bint is_multiple_of(self, int n) except * + cpdef list nonzero_positions(self, bint sort=*) + cpdef common_nonzero_positions(self, ETuple other, bint sort=*) + cpdef list nonzero_values(self, bint sort=*) + cpdef ETuple reversed(self) +cpdef int gen_index(PolyDict x) +cpdef ETuple monomial_exponent(PolyDict p) diff --git a/src/sage/rings/polynomial/polydict.pyx b/src/sage/rings/polynomial/polydict.pyx index 51f411aed91..0c847d125a4 100644 --- a/src/sage/rings/polynomial/polydict.pyx +++ b/src/sage/rings/polynomial/polydict.pyx @@ -1,23 +1,15 @@ """ -PolyDict engine for generic multivariate polynomial rings +Generic data structures for multivariate polynomials -This module provides an implementation of the underlying arithmetic for -multi-variate polynomial rings using Python dicts. - -This class is not meant for end users, but instead for implementing -multivariate polynomial rings over a completely general base. It does -not do strong type checking or have parents, etc. For speed, it has been -implemented in Cython. - -The functions in this file use the 'dictionary representation' of multivariate -polynomials +This module provides an implementation of a generic data structure +:class:`PolyDict` and the underlying arithmetic for multi-variate polynomial +rings. It uses a sparse representation of polynomials encoded as a Python +dictionary where keys are exponents and values coefficients. ``{(e1,...,er):c1,...} <-> c1*x1^e1*...*xr^er+...``, -which we call a polydict. The exponent tuple ``(e1,...,er)`` in this -representation is an instance of the class :class:`ETuple`. This class behaves -like a normal Python tuple but also offers advanced access methods for sparse -monomials like positions of non-zero exponents etc. +The exponent ``(e1,...,er)`` in this representation is an instance of the class +:class:`ETuple`. AUTHORS: @@ -29,6 +21,7 @@ AUTHORS: # **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> +# 2022 Vincent Delecroix <20100.delecroix@gmail.com> # # 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 @@ -42,131 +35,313 @@ from cpython.dict cimport * cimport cython from cpython.object cimport (Py_EQ, Py_NE, Py_LT, Py_LE, Py_GT, Py_GE) from cysignals.memory cimport sig_malloc, sig_free + from sage.structure.richcmp cimport rich_to_bool -import copy from functools import reduce -from sage.arith.power import generic_power from pprint import pformat -from sage.misc.misc import cputime from sage.misc.latex import latex -from sage.misc.superseded import deprecation_cython as deprecation + + +cpdef int gen_index(PolyDict x): + r""" + Return the index of the variable represented by ``x`` or ``-1`` if ``x`` + is not a monomial of degree one. + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict, gen_index + sage: gen_index(PolyDict({(1, 0): 1})) + 0 + sage: gen_index(PolyDict({(0, 1): 1})) + 1 + sage: gen_index(PolyDict({})) + -1 + """ + if len(x.__repn) != 1: + return -1 + cdef ETuple e = next(iter(x.__repn)) + if e._nonzero != 1 or e._data[1] != 1: + return -1 + if not next(iter(x.__repn.values())).is_one(): + return -1 + return e._data[0] + + +cpdef ETuple monomial_exponent(PolyDict p): + r""" + Return the unique exponent of ``p`` if it is a monomial or raise a ``ValueError``. + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict, monomial_exponent + sage: monomial_exponent(PolyDict({(2, 3): 1})) + (2, 3) + sage: monomial_exponent(PolyDict({(2, 3): 3})) + Traceback (most recent call last): + ... + ValueError: not a monomial + sage: monomial_exponent(PolyDict({(1, 0): 1, (0, 1): 1})) + Traceback (most recent call last): + ... + ValueError: not a monomial + """ + if len(p.__repn) != 1 or not next(iter(p.__repn.values())).is_one(): + raise ValueError('not a monomial') + return next(iter(p.__repn)) cdef class PolyDict: - def __init__(PolyDict self, pdict, zero=0, remove_zero=False, force_int_exponents=True, force_etuples=True): + r""" + Data structure for multivariate polynomials. + + A PolyDict holds a dictionary all of whose keys are :class:`ETuple` and + whose values are coefficients on which it is implicitely assumed that + arithmetic operations can be performed. + + No arithmetic operation on :class:`PolyDict` clear zero coefficients as of + now there is no reliable way of testing it in the most general setting, see + :trac:`35319`. For removing zero coefficients from a :class:`PolyDict` you + can use the method :meth:`remove_zeros` which can be parametrized by a zero + test. + """ + def __init__(self, pdict, zero=None, remove_zero=None, force_int_exponents=None, force_etuples=None, bint check=True): """ INPUT: - ``pdict`` -- dict or list, which represents a multi-variable - polynomial with the distribute representation (a copy is not made) + polynomial with the distribute representation (a copy is made) + + - ``zero`` -- deprecated + + - ``remove_zero`` -- deprecated - - ``zero`` -- (optional) zero in the base ring + - ``force_int_exponents`` -- deprecated - - ``force_int_exponents`` -- bool (optional) arithmetic with int - exponents is much faster than some of the alternatives, so this is - ``True`` by default + - ``force_etuples`` -- deprecated - - ``force_etuples`` -- bool (optional) enforce that the exponent tuples - are instances of ETuple class + - ``check`` -- if set to ``False`` then assumes that the exponents are + all valid ``ETuple``; in that case the construction is a bit faster. EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: PolyDict({(2,3):2, (1,2):3, (2,1):4}) + sage: PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) PolyDict with representation {(1, 2): 3, (2, 1): 4, (2, 3): 2} - # I've removed fractional exponent support in ETuple when moving to a sparse C integer array - #sage: PolyDict({(2/3,3,5):2, (1,2,1):3, (2,1):4}, force_int_exponents=False) - #PolyDict with representation {(2, 1): 4, (1, 2, 1): 3, (2/3, 3, 5): 2} + sage: PolyDict({(2, 3): 0, (1, 2): 3, (2, 1): 4}) + PolyDict with representation {(1, 2): 3, (2, 1): 4, (2, 3): 0} - sage: PolyDict({(2,3):0, (1,2):3, (2,1):4}, remove_zero=True) - PolyDict with representation {(1, 2): 3, (2, 1): 4} - - sage: PolyDict({(0,0):RIF(-1,1)}, remove_zero=True) + sage: PolyDict({(0, 0): RIF(-1,1)}) # needs sage.rings.real_interval_field PolyDict with representation {(0, 0): 0.?} - """ - cdef dict v - - if not isinstance(pdict, dict): - if isinstance(pdict, list): - v = {} - L = <list> pdict - for w in L: - if w[0] != 0: - v[ETuple(w[1])] = w[0] - remove_zero = False - pdict = v - else: - raise TypeError("pdict must be a list") - - if isinstance(pdict, dict) and force_etuples is True: - v = pdict - pdict = {} - for k, val in v.iteritems(): - pdict[ETuple(k)] = val - - if force_int_exponents: - new_pdict = {} - if remove_zero and zero is not None: - for k, c in pdict.iteritems(): - if not c == zero: - new_pdict[ETuple([int(i) for i in k])] = c + + TESTS:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + sage: len(f) + 3 + sage: f = PolyDict({}, zero=3, force_int_exponents=True, force_etuples=True) + doctest:warning + ... + DeprecationWarning: the arguments "zero", "forced_int_exponents" + and "forced_etuples" of PolyDict constructor are deprecated + See https://github.com/sagemath/sage/issues/34000 for details. + sage: f = PolyDict({}, remove_zero=False) + doctest:warning + ... + DeprecationWarning: the argument "remove_zero" of PolyDict + constructor is deprecated; call the method remove_zeros + See https://github.com/sagemath/sage/issues/34000 for details. + """ + if zero is not None or force_int_exponents is not None or force_etuples is not None: + from sage.misc.superseded import deprecation + deprecation(34000, 'the arguments "zero", "forced_int_exponents" and "forced_etuples" of PolyDict constructor are deprecated') + + self.__repn = {} + cdef bint has_only_etuple = True + if isinstance(pdict, (tuple, list)): + for coeff, exp in pdict: + if check and type(exp) is not ETuple: + exp = ETuple(exp) + self.__repn[exp] = coeff + elif isinstance(pdict, dict): + if check: + for k in (<dict> pdict): + if type(k) is not ETuple: + has_only_etuple = False + break + if has_only_etuple: + self.__repn = (<dict> pdict).copy() else: - for k, c in pdict.iteritems(): - new_pdict[ETuple([int(i) for i in k])] = c - pdict = new_pdict + self.__repn = {} + for exp, coeff in pdict.items(): + if type(exp) is not ETuple: + exp = ETuple(exp) + self.__repn[exp] = coeff else: - if remove_zero and zero is not None: - for k in list(pdict): - if pdict[k] == zero: - del pdict[k] - self.__repn = <dict> pdict - self.__zero = zero + raise TypeError("pdict must be a dict or a list of pairs (coeff, exponent)") + + if remove_zero is not None: + from sage.misc.superseded import deprecation + deprecation(34000, 'the argument "remove_zero" of PolyDict constructor is deprecated; call the method remove_zeros') + if remove_zero: + self.remove_zeros() + + cdef PolyDict _new(self, dict pdict): + cdef PolyDict ans = PolyDict.__new__(PolyDict) + ans.__repn = pdict + return ans + + cpdef remove_zeros(self, zero_test=None): + r""" + Remove the entries with zero coefficients. + + INPUT: + + - ``zero_test`` -- optional function that performs test to zero of a coefficient + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: f = PolyDict({(2, 3):0}) + sage: f + PolyDict with representation {(2, 3): 0} + sage: f.remove_zeros() + sage: f + PolyDict with representation {} + + The following example shows how to remove only exact zeros from a ``PolyDict`` + containing univariate power series:: + + sage: R.<t> = PowerSeriesRing(QQ) + sage: f = PolyDict({(1, 1): O(t), (1, 0): R.zero()}) + sage: f.remove_zeros(lambda s: s.is_zero() and s.prec() is Infinity) + sage: f + PolyDict with representation {(1, 1): O(t^1)} + """ + if not self.__repn: + return + # NOTE: in each of the conditional statements below, what the first + # loop does is equivalent to + # + # if all(self.__repn.values()): + # return + # + # and + # + # if all(not zero_test(coeff) for coeff in self.__repn.values()): + # return + # + # However, 'all(...)' is badly handled by the Cython compiler and we + # rather unfold it for efficiency. + cdef bint has_zero_coefficient = False + if zero_test is None: + for coeff in self.__repn.values(): + if not coeff: + has_zero_coefficient = True + break + if not has_zero_coefficient: + return + for k in list(self.__repn): + if not self.__repn[k]: + del self.__repn[k] + else: + for coeff in self.__repn.values(): + if zero_test(coeff): + has_zero_coefficient = True + break + if not has_zero_coefficient: + return + for k in list(self.__repn): + if zero_test(self.__repn[k]): + del self.__repn[k] + + def apply_map(self, f): + r""" + Apply the map ``f`` on the coefficients (inplace). + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: f = PolyDict({(1, 0): 1, (1, 1): -2}) + sage: f.apply_map(lambda x: x^2) + sage: f + PolyDict with representation {(1, 0): 1, (1, 1): 4} + """ + for k, v in self.__repn.items(): + self.__repn[k] = f(v) + + def coerce_coefficients(self, A): + r""" + Coerce the coefficients in the parent ``A`` + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: f = PolyDict({(2, 3): 0}) + sage: f + PolyDict with representation {(2, 3): 0} + sage: f.coerce_coefficients(QQ) + doctest:warning + ... + DeprecationWarning: coerce_cefficients is deprecated; use apply_map instead + See https://github.com/sagemath/sage/issues/34000 for details. + sage: f + PolyDict with representation {(2, 3): 0} + """ + from sage.misc.superseded import deprecation + deprecation(34000, 'coerce_cefficients is deprecated; use apply_map instead') + self.apply_map(A.coerce) def __hash__(self): """ Return the hash. - The hash of two PolyDicts is the same whether or not they use ETuples - for their keys since that's just an implementation detail. - EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: PD1 = PolyDict({(2,3):0, (1,2):3, (2,1):4}) - sage: PD2 = PolyDict({(2,3):0, (1,2):3, (2,1):4}, remove_zero=True) - sage: PD3 = PolyDict({(2,3):0, (1,2):3, (2,1):4}, - ....: force_etuples=False, force_int_exponents=False) - sage: PD4 = PolyDict({(2,3):0, (1,2):3, (2,1):4}, zero=4) + sage: PD1 = PolyDict({(2, 3): 0, (1, 2): 3, (2, 1): 4}) + sage: PD2 = PolyDict({(2, 3): 0, (1, 2): 3, (2, 1): 4}) + sage: PD3 = PolyDict({(2, 3): 1, (1, 2): 3, (2, 1): 4}) sage: hash(PD1) == hash(PD2) - False - sage: hash(PD1) == hash(PolyDict({(2,3):0, (1,2):3, (2,1):4})) True sage: hash(PD1) == hash(PD3) - True - sage: hash(PD3) == hash(PolyDict({(2,3):0, (1,2):3, (2,1):4}, - ....: force_etuples=False)) - True - sage: hash(PD1) == hash(PD4) False - sage: hash(PD4) == hash(PolyDict({(2,3):0, (1,2):3, (2,1):4}, - ....: zero=4)) + """ + return hash(frozenset(self.__repn.items())) + + def __bool__(self): + """ + Return whether the PolyDict is empty. + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: PD1 = PolyDict({(2, 3): 0, (1, 2): 3, (2, 1): 4}) + sage: bool(PD1) True """ + return bool(self.__repn) + + def __len__(self): + """ + Return the number of terms of this polynomial. - repn = frozenset((tuple(key), val) for key, val in self.__repn.items()) - return hash((type(self), repn, self.__zero)) + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: PD1 = PolyDict({(2, 3): 0, (1, 2): 3, (2, 1): 4}) + sage: len(PD1) + 3 + """ + return len(self.__repn) def __richcmp__(PolyDict left, PolyDict right, int op): """ Implement the ``__richcmp__`` protocol for `PolyDict`s. - Uses `PolyDict.rich_compare` without a key (so only ``==`` and ``!=`` - are supported on Python 3; on Python 2 this will fall back on Python 2 - default comparison behavior). - EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict @@ -177,22 +352,18 @@ cdef class PolyDict: sage: p1 < p2 Traceback (most recent call last): ... - TypeError: '<' not supported between instances of - 'sage.rings.polynomial.polydict.PolyDict' and - 'sage.rings.polynomial.polydict.PolyDict' + TypeError: unsupported comparison between PolyDict """ - try: - return left.rich_compare(right, op) - except TypeError: - return NotImplemented + if op == Py_EQ: + return left.__repn == right.__repn + elif op == Py_NE: + return left.__repn != right.__repn - def rich_compare(PolyDict self, PolyDict other, int op, sortkey=None): - """ - Compare two `PolyDict`s. If a ``sortkey`` argument is given it should - be a sort key used to specify a term order. + raise TypeError('unsupported comparison between PolyDict') - If not sort key is provided than only comparison by equality (``==`` or - ``!=``) is supported. + def rich_compare(self, PolyDict other, int op, sortkey=None): + """ + Compare two `PolyDict`s using a specified term ordering ``sortkey``. EXAMPLES:: @@ -200,18 +371,13 @@ cdef class PolyDict: sage: from sage.structure.richcmp import op_EQ, op_NE, op_LT sage: p1 = PolyDict({(0,): 1}) sage: p2 = PolyDict({(0,): 2}) - sage: p1.rich_compare(PolyDict({(0,): 1}), op_EQ) + sage: O = TermOrder() + sage: p1.rich_compare(PolyDict({(0,): 1}), op_EQ, O.sortkey) True - sage: p1.rich_compare(p2, op_EQ) + sage: p1.rich_compare(p2, op_EQ, O.sortkey) False - sage: p1.rich_compare(p2, op_NE) + sage: p1.rich_compare(p2, op_NE, O.sortkey) True - sage: p1.rich_compare(p2, op_LT) - Traceback (most recent call last): - ... - TypeError: ordering of PolyDicts requires a sortkey - - sage: O = TermOrder() sage: p1.rich_compare(p2, op_LT, O.sortkey) True @@ -219,26 +385,44 @@ cdef class PolyDict: sage: p4 = PolyDict({(3, 2, 4): 1, (3, 2, 3): 2}) sage: p3.rich_compare(p4, op_LT, O.sortkey) False + + TESTS:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: from sage.structure.richcmp import op_EQ, op_NE, op_LT + sage: p = PolyDict({}) + sage: ans = p.rich_compare(p, op_EQ) + doctest:warning + ... + DeprecationWarning: the argument "sortkey" will become mandatory in future sage versions + See https://github.com/sagemath/sage/issues/34000 for details. + sage: ans + True """ - if sortkey is not None: - # start with biggest - left = iter(sorted(self.__repn, key=sortkey, reverse=True)) - right = iter(sorted(other.__repn, key=sortkey, reverse=True)) - elif not (op == Py_EQ or op == Py_NE): - raise TypeError("ordering of PolyDicts requires a sortkey") - else: - return (op == Py_EQ) == (self.__repn == other.__repn) + if sortkey is None: + from sage.misc.superseded import deprecation + deprecation(34000, 'the argument "sortkey" will become mandatory in future sage versions') + if op == Py_EQ: + return self.__repn == other.__repn + elif op == Py_NE: + return self.__repn != other.__repn - for m in left: - try: - n = next(right) - except StopIteration: - return rich_to_bool(op, 1) # left has terms, right does not + if sortkey is None: + raise TypeError("ordering of PolyDicts requires a sortkey") - # first compare the leading monomials + # start with biggest + cdef list left = sorted(self.__repn, key=sortkey, reverse=True) + cdef list right = sorted(other.__repn, key=sortkey, reverse=True) + + cdef size_t i + for i in range(min(len(left), len(right))): + m = left[i] + n = right[i] keym = sortkey(m) keyn = sortkey(n) + + # first compare the leading monomials if keym > keyn: return rich_to_bool(op, 1) elif keym < keyn: @@ -252,176 +436,176 @@ cdef class PolyDict: elif coefm < coefn: return rich_to_bool(op, -1) - # try next pair - try: - n = next(right) - return rich_to_bool(op, -1) # right has terms, left does not - except StopIteration: - return rich_to_bool(op, 0) # both have no terms + return rich_to_bool(op, (len(left) > len(right)) - (len(left) < len(right))) - def list(PolyDict self): + def list(self): """ - Return a list that defines ``self``. It is safe to change this. + Return a list that defines ``self``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) sage: sorted(f.list()) [[2, [2, 3]], [3, [1, 2]], [4, [2, 1]]] """ - ret = [] - for e, c in self.__repn.iteritems(): - ret.append([c, list(e)]) - return ret + return [[c, list(e)] for e, c in self.__repn.items()] - def dict(PolyDict self): + def dict(self): """ - Return a copy of the dict that defines self. It is - safe to change this. For a reference, use dictref. + Return a copy of the dict that defines ``self``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) sage: f.dict() {(1, 2): 3, (2, 1): 4, (2, 3): 2} """ return self.__repn.copy() - def coefficients(PolyDict self): + def coefficients(self): """ - Return the coefficients of self. + Return the coefficients of ``self``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) sage: sorted(f.coefficients()) [2, 3, 4] """ return list(self.__repn.values()) - def exponents(PolyDict self): + def exponents(self): """ - Return the exponents of self. + Return the exponents of ``self``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) sage: sorted(f.exponents()) [(1, 2), (2, 1), (2, 3)] """ return list(self.__repn) - def __len__(PolyDict self): + def __getitem__(self, e): """ - Return the number of terms of the polynomial. + Return a coefficient of the polynomial. EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) - sage: len(f) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + sage: f[1, 2] 3 + sage: f[(2, 1)] + 4 """ - return len(self.__repn) + if type(e) is not ETuple: + e = ETuple(e) + return self.__repn[e] - def __getitem__(PolyDict self, e): - """ - Return a coefficient of the polynomial. + def get(self, ETuple e, default=None): + r""" + Return the coefficient of the ETuple ``e`` if present and ``default`` otherwise. EXAMPLES:: - sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) - sage: f[1,2] + sage: from sage.rings.polynomial.polydict import PolyDict, ETuple + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + sage: f.get(ETuple([1,2])) 3 - sage: f[(2,1)] - 4 + sage: f.get(ETuple([1,1]), 'hello') + 'hello' """ - return self.__repn[ETuple(e)] + return self.__repn.get(e, default) - def __repr__(PolyDict self): + def __repr__(self): + r""" + String representation. + """ repn = ' '.join(pformat(self.__repn).splitlines()) return 'PolyDict with representation %s' % repn - def degree(PolyDict self, PolyDict x=None): + def degree(self, PolyDict x=None): + r""" + Return the total degree or the maximum degree in the variable ``x``. + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + sage: f.degree() + 5 + sage: f.degree(PolyDict({(1, 0): 1})) + 2 + sage: f.degree(PolyDict({(0, 1): 1})) + 3 + """ if x is None: return self.total_degree() - L = list(x.__repn) - if len(L) != 1: - raise TypeError("x must be one of the generators of the parent.") - L = L[0] - nonzero_positions = L.nonzero_positions() - if len(nonzero_positions) != 1: - raise TypeError("x must be one of the generators of the parent.") - i = nonzero_positions[0] - if L[i] != 1: - raise TypeError("x must be one of the generators of the parent.") - _max = [] - for v in self.__repn: - _max.append(v[i]) - return max(_max or [-1]) - - def valuation(PolyDict self, PolyDict x=None): - if x is None: - _min = [] - negative = False - for v in self.__repn.values(): - _sum = 0 - for m in v.nonzero_values(sort=False): - if m < 0: - negative = True - break - _sum += m - if negative: - break - _min.append(_sum) - else: - return min(_min) - for v in self.__repn.values(): - _min.append(sum(m for m in v.nonzero_values(sort=False) if m < 0)) - return min(_min) - - L = list(x.__repn) - if len(L) != 1: - raise TypeError("x must be one of the generators of the parent.") - L = L[0] - nonzero_positions = L.nonzero_positions() - if len(nonzero_positions) != 1: - raise TypeError("x must be one of the generators of the parent.") - i = nonzero_positions[0] - if L[i] != 1: - raise TypeError("x must be one of the generators of the parent.") - _min = [] - for v in self.__repn: - _min.append(v[i]) - return min(_min) - - def total_degree(PolyDict self): - return max([-1] + [sum(k) for k in self.__repn]) - - def monomial_coefficient(PolyDict self, mon): + cdef int i = gen_index(x) + if i < 0: + raise ValueError('x must be a generator') + if not self.__repn: + return -1 + return max((<ETuple> e).get_exp(i) for e in self.__repn) + + def total_degree(self, tuple w=None): + r""" + Return the total degree. + + INPUT: + + - ``w`` -- (optional) a tuple of weights + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + sage: f.total_degree() + 5 + sage: f.total_degree((3, 1)) + 9 + sage: PolyDict({}).degree() + -1 """ + if not self.__repn: + return -1 + if w is None: + return max((<ETuple> e).unweighted_degree() for e in self.__repn) + else: + return max((<ETuple> e).weighted_degree(w) for e in self.__repn) + + def monomial_coefficient(self, mon): + """ + Return the coefficient of the monomial ``mon``. + INPUT: - a PolyDict with a single key + - ``mon`` -- a PolyDict with a single key EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.monomial_coefficient(PolyDict({(2,1):1}).dict()) + doctest:warning + ... + DeprecationWarning: PolyDict.monomial_coefficient is deprecated; use PolyDict.get instead + See https://github.com/sagemath/sage/issues/34000 for details. 4 """ + from sage.misc.superseded import deprecation + deprecation(34000, 'PolyDict.monomial_coefficient is deprecated; use PolyDict.get instead') K, = mon.keys() if K not in self.__repn: return 0 return self.__repn[K] - def polynomial_coefficient(PolyDict self, degrees): + def polynomial_coefficient(self, degrees): """ Return a polydict that defines the coefficient in the current polynomial viewed as a tower of polynomial extensions. @@ -434,19 +618,20 @@ cdef class PolyDict: EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) - sage: f.polynomial_coefficient([2,None]) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + sage: f.polynomial_coefficient([2, None]) PolyDict with representation {(0, 1): 4, (0, 3): 2} - sage: f = PolyDict({(0,3):2, (0,2):3, (2,1):4}) - sage: f.polynomial_coefficient([0,None]) + sage: f = PolyDict({(0, 3): 2, (0, 2): 3, (2, 1): 4}) + sage: f.polynomial_coefficient([0, None]) PolyDict with representation {(0, 2): 3, (0, 3): 2} """ nz = [] cdef int i - for i from 0<=i<len(degrees): + for i in range(len(degrees)): if degrees[i] is not None: nz.append(i) - ans = {} + cdef dict ans = {} + cdef bint exactly_divides for S in self.__repn: exactly_divides = True for j in nz: @@ -458,9 +643,9 @@ cdef class PolyDict: for m in nz: t[m] = 0 ans[ETuple(t)] = self.__repn[S] - return PolyDict(ans, force_etuples=False) + return self._new(ans) - def coefficient(PolyDict self, mon): + def coefficient(self, mon): """ Return a polydict that defines a polynomial in 1 less number of variables that gives the coefficient of mon in this @@ -484,47 +669,87 @@ cdef class PolyDict: for m in nz: t[m] = 0 ans[ETuple(t)] = self.__repn[S] - return PolyDict(ans, force_etuples=False) + return self._new(ans) + + def is_homogeneous(self): + r""" + Return whether this polynomial is homogeneous. + + EXAMPLES:: - def is_homogeneous(PolyDict self): + sage: from sage.rings.polynomial.polydict import PolyDict + sage: PolyDict({}).is_homogeneous() + True + sage: PolyDict({(1, 2): 1, (0, 3): -2}).is_homogeneous() + True + sage: PolyDict({(1, 0): 1, (1, 2): 3}).is_homogeneous() + False + """ if not self.__repn: return True - # A polynomial is homogeneous if the number of different - # exponent sums is at most 1. - return len(set(map(sum, self.__repn))) <= 1 + it = iter(self.__repn) + cdef size_t s = (<ETuple> next(it)).unweighted_degree() + for elt in it: + if (<ETuple> elt).unweighted_degree() != s: + return False + return True def is_constant(self): """ - Return ``True`` if ``self`` is a constant and ``False`` otherwise. + Return whether this polynomial is constant. EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) sage: f.is_constant() False - sage: g = PolyDict({(0,0):2}) + sage: g = PolyDict({(0, 0): 2}) sage: g.is_constant() True sage: h = PolyDict({}) sage: h.is_constant() True """ - cdef int ell = len(self.__repn) - return ell == 0 or (ell == 1 and sum(sum(k) for k in self.__repn) == 0) - - def homogenize(PolyDict self, var): - R = self.__repn - H = {} - deg = self.degree() - for e, val in R.iteritems(): - i = deg - sum(e) - f = list(e) - f[var] += i - H[ETuple(f)] = val - return PolyDict(H, zero=self.__zero, force_etuples=False) - - def latex(PolyDict self, vars, atomic_exponents=True, + if not self.__repn: + return True + if len(self.__repn) > 1: + return False + return not any(self.__repn) + + def homogenize(self, size_t var): + r""" + Return the homogeneization of ``self`` by increasing the degree of the + variable ``var``. + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: f = PolyDict({(0, 0): 1, (2, 1): 3, (1, 1): 5}) + sage: f.homogenize(0) + PolyDict with representation {(2, 1): 8, (3, 0): 1} + sage: f.homogenize(1) + PolyDict with representation {(0, 3): 1, (1, 2): 5, (2, 1): 3} + + sage: PolyDict({(0, 1): 1, (1, 1): -1}).homogenize(0) + PolyDict with representation {(1, 1): 0} + """ + cdef dict H = {} + cdef int deg = self.degree() + cdef int shift + for e, val in self.__repn.items(): + shift = deg - (<ETuple> e).unweighted_degree() + if shift: + f = (<ETuple> e).eadd_p(shift, var) + else: + f = e + if f in H: + H[f] += val + else: + H[f] = val + return self._new(H) + + def latex(self, vars, atomic_exponents=True, atomic_coefficients=True, sortkey=None): r""" Return a nice polynomial latex representation of this PolyDict, where @@ -539,18 +764,10 @@ cdef class PolyDict: EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) sage: f.latex(['a', 'WW']) '2 a^{2} WW^{3} + 4 a^{2} WW + 3 a WW^{2}' - When ``atomic_exponents`` is False, the exponents are surrounded in - parenthesis, since ^ has such high precedence:: - - # I've removed fractional exponent support in ETuple when moving to a sparse C integer array - #sage: f = PolyDict({(2/3,3,5):2, (1,2,1):3, (2,1,1):4}, force_int_exponents=False) - #sage: f.latex(['a', 'b', 'c'], atomic_exponents=False) - #'4 a^{2}bc + 3 ab^{2}c + 2 a^{2/3}b^{3}c^{5}' - TESTS: We check that the issue on :trac:`9478` is resolved:: @@ -567,7 +784,9 @@ cdef class PolyDict: sage: PolyDict({(1, 0): GF(2)(1)}).latex(['x', 'y']) 'x' """ - n = len(vars) + if not self: + return "0" + poly = "" sort_kwargs = {'reverse': True} @@ -576,8 +795,6 @@ cdef class PolyDict: E = sorted(self.__repn, **sort_kwargs) - if not E: - return "0" try: ring = self.__repn[E[0]].parent() pos_one = ring.one() @@ -591,42 +808,41 @@ cdef class PolyDict: for e in E: c = self.__repn[e] - if not c == self.__zero: - sign_switch = False - # First determine the multinomial: - multi = " ".join([vars[j] + - ("^{%s}" % e[j] if e[j] != 1 else "") - for j in e.nonzero_positions(sort=True)]) - # Next determine coefficient of multinomial - if len(multi) == 0: - multi = latex(c) - elif c == neg_one and not is_characteristic_2: - # handle -1 specially because it's a pain - if len(poly) > 0: - sign_switch = True - else: - multi = "-%s" % multi - elif c != pos_one: - c = latex(c) - if (not atomic_coefficients and multi and - ('+' in c or '-' in c or ' ' in c)): - c = "\\left(%s\\right)" % c - multi = "%s %s" % (c, multi) - - # Now add on coefficiented multinomials + sign_switch = False + # First determine the multinomial: + multi = " ".join([vars[j] + + ("^{%s}" % e[j] if e[j] != 1 else "") + for j in e.nonzero_positions(sort=True)]) + # Next determine coefficient of multinomial + if len(multi) == 0: + multi = latex(c) + elif c == neg_one and not is_characteristic_2: + # handle -1 specially because it's a pain if len(poly) > 0: - if sign_switch: - poly = poly + " - " - else: - poly = poly + " + " - poly = poly + multi + sign_switch = True + else: + multi = "-%s" % multi + elif c != pos_one: + c = latex(c) + if (not atomic_coefficients and multi and + ('+' in c or '-' in c or ' ' in c)): + c = "\\left(%s\\right)" % c + multi = "%s %s" % (c, multi) + + # Now add on coefficiented multinomials + if len(poly) > 0: + if sign_switch: + poly = poly + " - " + else: + poly = poly + " + " + poly = poly + multi poly = poly.lstrip().rstrip() poly = poly.replace("+ -", "- ") if len(poly) == 0: return "0" return poly - def poly_repr(PolyDict self, vars, atomic_exponents=True, + def poly_repr(self, vars, atomic_exponents=True, atomic_coefficients=True, sortkey=None): """ Return a nice polynomial string representation of this PolyDict, where @@ -645,14 +861,6 @@ cdef class PolyDict: sage: f.poly_repr(['a', 'WW']) '2*a^2*WW^3 + 4*a^2*WW + 3*a*WW^2' - When atomic_exponents is ``False``, the exponents are surrounded - in parenthesis, since ^ has such high precedence. :: - - # I've removed fractional exponent support in ETuple when moving to a sparse C integer array - #sage: f = PolyDict({(2/3,3,5):2, (1,2,1):3, (2,1,1):4}, force_int_exponents=False) - #sage: f.poly_repr(['a', 'b', 'c'], atomic_exponents=False) - #'4*a^(2)*b*c + 3*a*b^(2)*c + 2*a^(2/3)*b^(3)*c^(5)' - We check to make sure that when we are in characteristic two, we don't put negative signs on the generators. :: @@ -661,15 +869,15 @@ cdef class PolyDict: We make sure that intervals are correctly represented. :: - sage: f = PolyDict({(2,3):RIF(1/2,3/2), (1,2):RIF(-1,1)}) - sage: f.poly_repr(['x', 'y']) + sage: f = PolyDict({(2, 3): RIF(1/2,3/2), (1, 2): RIF(-1,1)}) # needs sage.rings.real_interval_field + sage: f.poly_repr(['x', 'y']) # needs sage.rings.real_interval_field '1.?*x^2*y^3 + 0.?*x*y^2' TESTS: Check that :trac:`29604` is fixed:: - sage: PolyDict({(1, 0): GF(4)(1)}).poly_repr(['x', 'y']) + sage: PolyDict({(1, 0): GF(4)(1)}).poly_repr(['x', 'y']) # needs sage.rings.finite_rings 'x' sage: P.<x,y> = LaurentPolynomialRing(GF(2), 2) sage: P.gens() @@ -677,7 +885,6 @@ cdef class PolyDict: sage: -x - y x + y """ - n = len(vars) poly = "" sort_kwargs = {'reverse': True} if sortkey: @@ -700,48 +907,86 @@ cdef class PolyDict: for e in E: c = self.__repn[e] - if not c == self.__zero: - sign_switch = False - # First determine the multinomial: - multi = "" - for j in e.nonzero_positions(sort=True): - if len(multi) > 0: - multi = multi + "*" - multi = multi + vars[j] - if e[j] != 1: - if atomic_exponents: - multi = multi + "^%s" % e[j] - else: - multi = multi + "^(%s)" % e[j] - # Next determine coefficient of multinomial - if len(multi) == 0: - multi = str(c) - elif c == neg_one and not is_characteristic_2: - # handle -1 specially because it's a pain - if len(poly) > 0: - sign_switch = True + sign_switch = False + # First determine the multinomial: + multi = "" + for j in e.nonzero_positions(sort=True): + if multi: + multi = multi + "*" + multi = multi + vars[j] + if e[j] != 1: + if atomic_exponents: + multi = multi + "^%s" % e[j] else: - multi = "-%s" % multi - elif not c == pos_one: - if not atomic_coefficients: - c = str(c) - if c.find("+") != -1 or c.find("-") != -1 or c.find(" ") != -1: - c = "(%s)" % c - multi = "%s*%s" % (c, multi) - - # Now add on coefficiented multinomials - if len(poly) > 0: - if sign_switch: - poly = poly + " - " - else: - poly = poly + " + " - poly = poly + multi + multi = multi + "^(%s)" % e[j] + # Next determine coefficient of multinomial + if not multi: + multi = str(c) + elif c == neg_one and not is_characteristic_2: + # handle -1 specially because it's a pain + if poly: + sign_switch = True + else: + multi = "-%s" % multi + elif not c == pos_one: + if not atomic_coefficients: + c = str(c) + if c.find("+") != -1 or c.find("-") != -1 or c.find(" ") != -1: + c = "(%s)" % c + multi = "%s*%s" % (c, multi) + + # Now add on coefficiented multinomials + if poly: + if sign_switch: + poly = poly + " - " + else: + poly = poly + " + " + poly = poly + multi poly = poly.lstrip().rstrip() poly = poly.replace("+ -", "- ") - if len(poly) == 0: + if not poly: return "0" return poly + def __iadd__(PolyDict self, PolyDict other): + r""" + Inplace addition + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + sage: g = PolyDict({(1, 5): -3, (2, 3): -2, (1, 1): 3}) + sage: f += g + sage: f + PolyDict with representation {(1, 1): 3, (1, 2): 3, (1, 5): -3, (2, 1): 4, (2, 3): 0} + """ + cdef dict D = self.__repn + if self is other: + for e in D: + v = D[e] + D[e] += v + else: + for e, c in other.__repn.items(): + if e in D: + D[e] += c + else: + D[e] = c + return self + + def __neg__(self): + r""" + TESTS:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: -PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + PolyDict with representation {(1, 2): -3, (2, 1): -4, (2, 3): -2} + """ + cdef dict D = self.__repn.copy() + for e, c in D.items(): + D[e] = -c + return self._new(D) + def __add__(PolyDict self, PolyDict other): """ Add two PolyDict's in the same number of variables. @@ -751,112 +996,126 @@ cdef class PolyDict: We add two polynomials in 2 variables:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) - sage: g = PolyDict({(1,5):-3, (2,3):-2, (1,1):3}) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + sage: g = PolyDict({(1, 5): -3, (2, 3): -2, (1, 1): 3}) sage: f + g - PolyDict with representation {(1, 1): 3, (1, 2): 3, (1, 5): -3, (2, 1): 4} - - Next we add two polynomials with fractional exponents in 3 variables:: - - # I've removed fractional exponent support in ETuple when moving to a sparse C integer array - #sage: f = PolyDict({(2/3,3,5):2, (1,2,1):3, (2,1,1):4}, force_int_exponents=False) - #sage: g = PolyDict({(2/3,3,5):3}, force_int_exponents=False) - #sage: f+g - #PolyDict with representation {(1, 2, 1): 3, (2/3, 3, 5): 5, (2, 1, 1): 4} - """ - zero = self.__zero - # D = copy.copy(self.__repn) - D = self.__repn.copy() # faster! - R = other.__repn - for e, c in R.iteritems(): - try: + PolyDict with representation {(1, 1): 3, (1, 2): 3, (1, 5): -3, (2, 1): 4, (2, 3): 0} + + sage: K = GF(2) + sage: f = PolyDict({(1, 1): K(1)}) + sage: f + f + PolyDict with representation {(1, 1): 0} + """ + cdef dict D = self.__repn + cdef dict R = other.__repn + if len(D) < len(R): + D, R = R, D + D = D.copy() + for e, c in R.items(): + if e in D: D[e] += c - except KeyError: + else: D[e] = c - return PolyDict(D, zero=zero, remove_zero=True, - force_int_exponents=False, force_etuples=False) + return self._new(D) def __mul__(PolyDict self, PolyDict right): """ Multiply two PolyDict's in the same number of variables. + The algorithm do not test whether a product of coefficients is zero + or whether a final coefficient is zero because there is no reliable way + to do so in general (eg power series ring or p-adic rings). + EXAMPLES: - We multiply two polynomials in 2 variables:: + + Multiplication of polynomials in 2 variables with rational coefficients:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) - sage: g = PolyDict({(1,5):-3, (2,3):-2, (1,1):3}) - sage: f*g + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + sage: g = PolyDict({(1, 5): -3, (2, 3): -2, (1, 1): 3}) + sage: f * g PolyDict with representation {(2, 3): 9, (2, 7): -9, (3, 2): 12, (3, 4): 6, (3, 5): -6, (3, 6): -12, (3, 8): -6, (4, 4): -8, (4, 6): -4} + + Multiplication of polynomials in 2 variables with power series coefficients:: + + sage: R.<t> = PowerSeriesRing(QQ) + sage: f = PolyDict({(1, 0): 1 + O(t), (0, 1): 1 + O(t^2)}) + sage: g = PolyDict({(1, 0): 1, (0, 1): -1}) + sage: f * g + PolyDict with representation {(0, 2): -1 + O(t^2), (1, 1): O(t^1), (2, 0): 1 + O(t)} + sage: f = PolyDict({(1, 0): O(t), (0, 1): O(t)}) + sage: g = PolyDict({(1, 0): 1, (0, 1): O(t)}) + sage: f * g + PolyDict with representation {(0, 2): O(t^2), (1, 1): O(t^1), (2, 0): O(t^1)} """ cdef PyObject *cc + cdef dict newpoly + if not self.__repn or not right.__repn: + return self._new({}) newpoly = {} - if len(self.__repn) == 0: # product is zero anyways - return self - for e0, c0 in self.__repn.iteritems(): - for e1, c1 in right.__repn.iteritems(): - e = (<ETuple>e0).eadd(<ETuple>e1) - c = c0*c1 + for e0, c0 in self.__repn.items(): + for e1, c1 in right.__repn.items(): + e = (<ETuple> e0).eadd(<ETuple> e1) + c = c0 * c1 cc = PyDict_GetItem(newpoly, e) - if cc == <PyObject*>0: + if cc == <PyObject*> 0: PyDict_SetItem(newpoly, e, c) else: - PyDict_SetItem(newpoly, e, <object>cc+c) - F = PolyDict(newpoly, self.__zero, force_int_exponents=False, remove_zero=True, force_etuples=False) - return F + PyDict_SetItem(newpoly, e, <object> cc + c) + return self._new(newpoly) - def scalar_rmult(PolyDict self, s): + def scalar_rmult(self, s): """ - Right Scalar Multiplication + Return the right scalar multiplication of ``self`` by ``s``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! - sage: f = PolyDict({(2,3):x}) - sage: f.scalar_rmult(y) + + sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat + sage: f = PolyDict({(2, 3): x}) # needs sage.combinat + sage: f.scalar_rmult(y) # needs sage.combinat PolyDict with representation {(2, 3): x*y} - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) + + sage: f = PolyDict({(2,3):2, (1, 2): 3, (2, 1): 4}) sage: f.scalar_rmult(-2) PolyDict with representation {(1, 2): -6, (2, 1): -8, (2, 3): -4} - sage: f.scalar_rmult(RIF(-1,1)) + sage: f.scalar_rmult(RIF(-1,1)) # needs sage.rings.real_interval_field PolyDict with representation {(1, 2): 0.?e1, (2, 1): 0.?e1, (2, 3): 0.?e1} """ - v = {} - # if s is 0, then all the products will be zero - if not s == self.__zero: - for e, c in self.__repn.iteritems(): - v[e] = c*s - return PolyDict(v, self.__zero, force_int_exponents=False, force_etuples=False) + cdef dict v = {} + for e, c in self.__repn.items(): + v[e] = c * s + return self._new(v) - def scalar_lmult(PolyDict self, s): + def scalar_lmult(self, s): """ - Left Scalar Multiplication + Return the left scalar multiplication of ``self`` by ``s``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! - sage: f = PolyDict({(2,3):x}) - sage: f.scalar_lmult(y) + + sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat + sage: f = PolyDict({(2,3):x}) # needs sage.combinat + sage: f.scalar_lmult(y) # needs sage.combinat PolyDict with representation {(2, 3): y*x} + sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.scalar_lmult(-2) PolyDict with representation {(1, 2): -6, (2, 1): -8, (2, 3): -4} - sage: f.scalar_lmult(RIF(-1,1)) + sage: f.scalar_lmult(RIF(-1,1)) # needs sage.rings.real_interval_field PolyDict with representation {(1, 2): 0.?e1, (2, 1): 0.?e1, (2, 3): 0.?e1} """ - v = {} - # if s is 0, then all the products will be zero - if not s == self.__zero: - for e, c in self.__repn.iteritems(): - v[e] = s*c - return PolyDict(v, self.__zero, force_int_exponents=False, force_etuples=False) + cdef dict v = {} + for e, c in self.__repn.items(): + v[e] = s * c + return self._new(v) def term_lmult(self, exponent, s): """ - Return this element multiplied by ``s`` on the left - and with exponents shifted by ``exponent``. + Return this element multiplied by ``s`` on the left and with exponents + shifted by ``exponent``. INPUT: @@ -867,9 +1126,10 @@ cdef class PolyDict: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple, PolyDict - sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! - sage: f = PolyDict({(2, 3): x}) - sage: f.term_lmult(ETuple((1, 2)), y) + + sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat + sage: f = PolyDict({(2, 3): x}) # needs sage.combinat + sage: f.term_lmult(ETuple((1, 2)), y) # needs sage.combinat PolyDict with representation {(3, 5): y*x} sage: f = PolyDict({(2,3): 2, (1,2): 3, (2,1): 4}) @@ -877,17 +1137,15 @@ cdef class PolyDict: PolyDict with representation {(2, 4): -6, (3, 3): -8, (3, 5): -4} """ - v = {} - # if s is 0, then all the products will be zero - if not s == self.__zero: - for e, c in self.__repn.iteritems(): - v[e.eadd(exponent)] = s*c - return PolyDict(v, self.__zero, force_int_exponents=False, force_etuples=False) + cdef dict v = {} + for e, c in self.__repn.items(): + v[(<ETuple> e).eadd(exponent)] = s*c + return self._new(v) def term_rmult(self, exponent, s): """ - Return this element multiplied by ``s`` on the right - and with exponents shifted by ``exponent``. + Return this element multiplied by ``s`` on the right and with exponents + shifted by ``exponent``. INPUT: @@ -898,25 +1156,23 @@ cdef class PolyDict: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple, PolyDict - sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! - sage: f = PolyDict({(2, 3): x}) - sage: f.term_rmult(ETuple((1, 2)), y) + + sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! # needs sage.combinat + sage: f = PolyDict({(2, 3): x}) # needs sage.combinat + sage: f.term_rmult(ETuple((1, 2)), y) # needs sage.combinat PolyDict with representation {(3, 5): x*y} - sage: f = PolyDict({(2,3): 2, (1,2): 3, (2,1): 4}) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) sage: f.term_rmult(ETuple((1, 2)), -2) PolyDict with representation {(2, 4): -6, (3, 3): -8, (3, 5): -4} """ - v = {} - # if s is 0, then all the products will be zero - if not s == self.__zero: - for e, c in self.__repn.iteritems(): - v[e.eadd(exponent)] = c*s - return PolyDict(v, self.__zero, force_int_exponents=False, force_etuples=False) + cdef dict v = {} + for e, c in self.__repn.items(): + v[(<ETuple> e).eadd(exponent)] = c * s + return self._new(v) - - def __sub__(PolyDict self, PolyDict other): + def __sub__(PolyDict self, PolyDict other): """ Subtract two PolyDict's. @@ -926,42 +1182,113 @@ cdef class PolyDict: sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: g = PolyDict({(2,3):2, (1,1):-10}) sage: f - g - PolyDict with representation {(1, 1): 10, (1, 2): 3, (2, 1): 4} + PolyDict with representation {(1, 1): 10, (1, 2): 3, (2, 1): 4, (2, 3): 0} sage: g - f - PolyDict with representation {(1, 1): -10, (1, 2): -3, (2, 1): -4} + PolyDict with representation {(1, 1): -10, (1, 2): -3, (2, 1): -4, (2, 3): 0} + sage: f - f + PolyDict with representation {(1, 2): 0, (2, 1): 0, (2, 3): 0} + """ + cdef dict D = self.__repn.copy() + cdef dict R = other.__repn + for e, c in R.items(): + if e in D: + D[e] -= c + else: + D[e] = -c + return self._new(D) + + def derivative_i(self, size_t i): + r""" + Return the derivative of ``self`` with respect to the ``i``-th variable. + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: PolyDict({(1, 1): 1}).derivative_i(0) + PolyDict with representation {(0, 1): 1} """ + cdef dict D = {} + for e, c in self.__repn.items(): + D[(<ETuple> e).eadd_p(-1, i)] = c * (<ETuple> e).get_exp(i) + return self._new(D) - # TODO: should refactor add, make abstract operator, so can do both +/-; or copy code. - return self + other.scalar_lmult(-1) + def derivative(self, PolyDict x): + r""" + Return the derivative of ``self`` with respect to ``x`` - def __one(PolyDict self): - one = self.__zero + 1 - if len(self.__repn) == 0: - v = {(0):one} - else: - v = {ETuple({}, len(next(iter(self.__repn)))): one} - return PolyDict(v, self.__zero, force_int_exponents=False, force_etuples=False) + EXAMPLES:: - def __pow__(PolyDict self, n, ignored): + sage: from sage.rings.polynomial.polydict import PolyDict + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + sage: f.derivative(PolyDict({(1, 0): 1})) + PolyDict with representation {(0, 2): 3, (1, 1): 8, (1, 3): 4} + sage: f.derivative(PolyDict({(0, 1): 1})) + PolyDict with representation {(1, 1): 6, (2, 0): 4, (2, 2): 6} + + sage: PolyDict({(-1,): 1}).derivative(PolyDict({(1,): 1})) + PolyDict with representation {(-2,): -1} + sage: PolyDict({(-2,): 1}).derivative(PolyDict({(1,): 1})) + PolyDict with representation {(-3,): -2} + + sage: PolyDict({}).derivative(PolyDict({(1, 1): 1})) + Traceback (most recent call last): + ... + ValueError: x must be a generator """ - Return the n-th nonnegative power of this PolyDict. + cdef int i = gen_index(x) + if i < 0: + raise ValueError('x must be a generator') + return self.derivative_i(i) + + def integral_i(self, size_t i): + r""" + Return the derivative of ``self`` with respect to the ``i``-th variable. EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) - sage: f**2 - PolyDict with representation {(2, 4): 9, (3, 3): 24, (3, 5): 12, (4, 2): 16, (4, 4): 16, (4, 6): 4} - sage: f**0 - PolyDict with representation {(0, 0): 1} - sage: (f-f)**0 - PolyDict with representation {0: 1} + sage: PolyDict({(1, 1): 1}).integral_i(0) + PolyDict with representation {(2, 1): 1/2} + """ + cdef dict D = {} + cdef int exp + for e, c in self.__repn.items(): + exp = (<ETuple> e).get_exp(i) + if exp == -1: + raise ArithmeticError('integral of monomial with exponent -1') + D[(<ETuple> e).eadd_p(1, i)] = c / (exp + 1) + return self._new(D) + + def integral(self, PolyDict x): + r""" + Return the integral of ``self`` with respect to ``x`` + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) + sage: f.integral(PolyDict({(1, 0): 1})) + PolyDict with representation {(2, 2): 3/2, (3, 1): 4/3, (3, 3): 2/3} + sage: f.integral(PolyDict({(0, 1): 1})) + PolyDict with representation {(1, 3): 1, (2, 2): 2, (2, 4): 1/2} + + sage: PolyDict({(-1,): 1}).integral(PolyDict({(1,): 1})) + Traceback (most recent call last): + ... + ArithmeticError: integral of monomial with exponent -1 + sage: PolyDict({(-2,): 1}).integral(PolyDict({(1,): 1})) + PolyDict with representation {(-1,): -1} + sage: PolyDict({}).integral(PolyDict({(1, 1): 1})) + Traceback (most recent call last): + ... + ValueError: x must be a generator """ - if not n: - return self.__one() - return generic_power(self, n) + cdef int i = gen_index(x) + if i < 0: + raise ValueError('x must be a generator') + return self.integral_i(i) - def lcmt(PolyDict self, greater_etuple): + def lcmt(self, greater_etuple): """ Provides functionality of lc, lm, and lt by calling the tuple compare function on the provided term order T. @@ -975,17 +1302,17 @@ cdef class PolyDict: except KeyError: raise ArithmeticError("%s not supported", greater_etuple) - def __reduce__(PolyDict self): + def __reduce__(self): """ EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) sage: loads(dumps(f)) == f True """ - return make_PolyDict, (self.__repn,) + return PolyDict, (self.__repn,) def min_exp(self): """ @@ -998,7 +1325,7 @@ cdef class PolyDict: EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) sage: f.min_exp() (1, 1) sage: PolyDict({}).min_exp() # returns None @@ -1024,7 +1351,7 @@ cdef class PolyDict: EXAMPLES:: sage: from sage.rings.polynomial.polydict import PolyDict - sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) + sage: f = PolyDict({(2, 3): 2, (1, 2): 3, (2, 1): 4}) sage: f.max_exp() (2, 3) sage: PolyDict({}).max_exp() # returns None @@ -1101,7 +1428,7 @@ cdef class ETuple: question (although, there is no question that this is much faster than the prior use of python dicts). """ - cdef ETuple _new(ETuple self): + cdef ETuple _new(self): """ Quickly creates a new initialized ETuple with the same length as self. @@ -1111,7 +1438,7 @@ cdef class ETuple: x._length = self._length return x - def __init__(ETuple self, data=None, length=None): + def __init__(self, data=None, length=None): """ - ``ETuple()`` -> an empty ETuple - ``ETuple(sequence)`` -> ETuple initialized from sequence's items @@ -1125,6 +1452,8 @@ cdef class ETuple: (1, 1, 0) sage: ETuple({int(1): int(2)}, int(3)) (0, 2, 0) + sage: ETuple([1, -1, 0]) + (1, -1, 0) TESTS: @@ -1171,13 +1500,29 @@ cdef class ETuple: else: raise TypeError("Error in ETuple(%s, %s, %s)" % (self, data, length)) - def __cinit__(ETuple self): + def __cinit__(self): self._data = <int*>0 def __dealloc__(self): if self._data != <int*>0: sig_free(self._data) + def __bool__(self): + r""" + Return whether self is nonzero. + + TESTS:: + + sage: from sage.rings.polynomial.polydict import ETuple + sage: bool(ETuple([1])) + True + sage: bool(ETuple([])) + False + sage: bool(ETuple([0, 0, 0])) + False + """ + return bool(self._nonzero) + # methods to simulate tuple def __add__(ETuple self, ETuple other): @@ -1189,7 +1534,7 @@ cdef class ETuple: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: ETuple([1,1,0]) + ETuple({int(1):int(2)}, int(3)) + sage: ETuple([1, 1, 0]) + ETuple({int(1): int(2)}, int(3)) (1, 1, 0, 0, 2, 0) """ cdef size_t index = 0 @@ -1212,7 +1557,7 @@ cdef class ETuple: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: ETuple([1,2,3])*2 + sage: ETuple([1, 2, 3])*2 (1, 2, 3, 1, 2, 3) """ cdef int _factor = factor @@ -1232,17 +1577,17 @@ cdef class ETuple: result._data[2*(f*self._nonzero+index)+1] = self._data[2*index+1] return result - def __getitem__(ETuple self, i): + def __getitem__(self, i): """ EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: m = ETuple([1,2,0,3]) + sage: m = ETuple([1, 2, 0, 3]) sage: m[2] 0 sage: m[1] 2 - sage: e = ETuple([1,2,3]) + sage: e = ETuple([1, 2, 3]) sage: e[1:] (2, 3) sage: e[:1] @@ -1268,60 +1613,76 @@ cdef class ETuple: d = [self[ind] for ind from start <= ind < stop] return ETuple(d) else: - for ind in range(0, 2*self._nonzero, 2): - if self._data[ind] == i: - return self._data[ind+1] - elif self._data[ind] > i: - # the indices are sorted in _data, we are beyond, so quit - return 0 - return 0 + return self.get_exp(i) - cdef size_t get_exp(ETuple self, int i): + cdef size_t get_position(self, size_t i, size_t start, size_t end): + r""" + Return where to insert ``i`` in the data between ``start`` and ``end``. + """ + if end <= start: + return start + cdef size_t left = start + cdef size_t right = end - 1 + cdef size_t mid + if self._data[2 * left] >= i: + return left + if self._data[2 * right] < i: + return end + if self._data[2 * right] == i: + return right + while right - left > 1: + mid = (left + right) / 2 + if self._data[2 * mid] == i: + return mid + if self._data[2 * mid] > i: + right = mid + else: + left = mid + return right + + cdef int get_exp(self, size_t i): """ Return the exponent for the ``i``-th variable. """ - cdef size_t ind = 0 - for ind in range(0, 2*self._nonzero, 2): - if self._data[ind] == i: - return self._data[ind+1] - elif self._data[ind] > i: - # the indices are sorted in _data, we are beyond, so quit - return 0 + cdef size_t ind = self.get_position(i, 0, self._nonzero) + if ind != self._nonzero and self._data[2 * ind] == i: + return self._data[2 * ind + 1] return 0 - def __hash__(ETuple self): + def __hash__(self): """ x.__hash__() <==> hash(x) """ cdef int i cdef int result = 0 - for i from 0 <= i < self._nonzero: + for i in range(self._nonzero): result += (1000003 * result) ^ self._data[2*i] result += (1000003 * result) ^ self._data[2*i+1] result = (1000003 * result) ^ self._length return result - def __len__(ETuple self): + def __len__(self): """ x.__len__() <==> len(x) EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e=ETuple([1,0,2,0,3]) + sage: e = ETuple([1, 0, 2, 0, 3]) sage: len(e) 5 """ return self._length - def __contains__(ETuple self, elem): + def __contains__(self, elem): """ x.__contains__(n) <==> n in x EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple({int(1):int(2)}, int(3)); e + sage: e = ETuple({int(1): int(2)}, int(3)) + sage: e (0, 2, 0) sage: 1 in e False @@ -1332,8 +1693,8 @@ cdef class ETuple: return self._length > self._nonzero cdef size_t ind = 0 - for ind from 0 <= ind < self._nonzero: - if elem == self._data[2*ind+1]: + for ind in range(self._nonzero): + if elem == self._data[2 * ind + 1]: return True return False @@ -1342,35 +1703,35 @@ cdef class ETuple: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: ETuple([1,1,0])<ETuple([1,1,0]) + sage: ETuple([1, 1, 0])<ETuple([1, 1, 0]) False - sage: ETuple([1,1,0])<ETuple([1,0,0]) + sage: ETuple([1, 1, 0])<ETuple([1, 0, 0]) False - sage: ETuple([1,1,0])<ETuple([1,2,0]) + sage: ETuple([1, 1, 0])<ETuple([1, 2, 0]) True - sage: ETuple([1,1,0])<ETuple([1,-1,0]) + sage: ETuple([1, 1, 0])<ETuple([1, -1, 0]) False - sage: ETuple([0,-2,0])<ETuple([1,-1,0]) + sage: ETuple([0, -2, 0])<ETuple([1, -1, 0]) True - sage: ETuple([1,1,0])>ETuple([1,1,0]) + sage: ETuple([1, 1, 0])>ETuple([1, 1, 0]) False - sage: ETuple([1,1,0])>ETuple([1,0,0]) + sage: ETuple([1, 1, 0])>ETuple([1, 0, 0]) True - sage: ETuple([1,1,0])>ETuple([1,2,0]) + sage: ETuple([1, 1, 0])>ETuple([1, 2, 0]) False - sage: ETuple([1,1,0])>ETuple([1,-1,0]) + sage: ETuple([1, 1, 0])>ETuple([1, -1, 0]) True - sage: ETuple([0,-2,0])>ETuple([1,-1,0]) + sage: ETuple([0, -2, 0])>ETuple([1, -1, 0]) False """ cdef size_t ind = 0 if op == Py_EQ: # == if self._nonzero != other._nonzero: return False - for ind from 0 <= ind < self._nonzero: - if self._data[2*ind] != other._data[2*ind]: + for ind in range(self._nonzero): + if self._data[2 * ind] != other._data[2 * ind]: return False - if self._data[2*ind+1] != other._data[2*ind+1]: + if self._data[2 * ind + 1] != other._data[2 * ind + 1]: return False return self._length == other._length @@ -1415,14 +1776,14 @@ cdef class ETuple: if op == Py_GE: # >= return tuple(self) >= tuple(other) - def __iter__(ETuple self): + def __iter__(self): """ x.__iter__() <==> iter(x) TESTS:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple((4,0,0,2,0)) + sage: e = ETuple((4, 0, 0, 2, 0)) sage: list(e) [4, 0, 0, 2, 0] @@ -1444,10 +1805,10 @@ cdef class ETuple: else: yield 0 - def __str__(ETuple self): + def __str__(self): return repr(self) - def __repr__(ETuple self): + def __repr__(self): r""" TESTS:: @@ -1456,7 +1817,7 @@ cdef class ETuple: (0,) sage: ETuple((1,)) (1,) - sage: ETuple((0,1,2)) + sage: ETuple((0, 1, 2)) (0, 1, 2) """ if self._length == 1: @@ -1467,48 +1828,42 @@ cdef class ETuple: else: return '(' + ', '.join(map(str, self)) + ')' - def __reduce__(ETuple self): + def __reduce__(self): """ EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,1,0]) - sage: bool(e == loads(dumps(e))) + sage: e = ETuple([1, 1, 0]) + sage: e == loads(dumps(e)) True """ cdef size_t ind - # this is not particularly fast, but I doubt many people care - # if you do, feel free to tweak! - d = {self._data[2*ind]: self._data[2*ind+1] - for ind from 0 <= ind < self._nonzero} - return make_ETuple, (d, int(self._length)) + d = {self._data[2 * ind]: self._data[2 * ind + 1] for ind in range(self._nonzero)} + return ETuple, (d, int(self._length)) # additional methods - cpdef size_t unweighted_degree(self): + cpdef int unweighted_degree(self) except *: r""" Return the sum of entries. - ASSUMPTION: - - All entries are non-negative. - EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,1,0,2,0]) - sage: e.unweighted_degree() + sage: ETuple([1, 1, 0, 2, 0]).unweighted_degree() 4 + sage: ETuple([-1, 1]).unweighted_degree() + 0 """ - cdef size_t degree = 0 + cdef int degree = 0 cdef size_t i - for i in range(1, 2*self._nonzero, 2): - degree += self._data[i] + for i in range(self._nonzero): + degree += self._data[2 * i + 1] return degree @cython.boundscheck(False) @cython.wraparound(False) - cdef size_t weighted_degree(self, tuple w): + cpdef int weighted_degree(self, tuple w) except *: r""" Return the weighted sum of entries. @@ -1516,21 +1871,35 @@ cdef class ETuple: - ``w`` -- tuple of non-negative integers - ASSUMPTIONS: + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import ETuple + sage: e = ETuple([1, 1, 0, 2, 0]) + sage: e.weighted_degree((1, 2, 3, 4, 5)) + 11 + sage: ETuple([-1, 1]).weighted_degree((1, 2)) + 1 - ``w`` has the same length as ``self``, and the entries of ``self`` - and ``w`` are non-negative. + sage: ETuple([1, 0]).weighted_degree((1, 2, 3)) + Traceback (most recent call last): + ... + ValueError: w must be of the same length as the ETuple """ + if len(w) != self._length: + raise ValueError('w must be of the same length as the ETuple') + cdef size_t i - cdef size_t deg = 0 - assert len(w) == self._length - for i in range(0, 2*self._nonzero, 2): - deg += <size_t> self._data[i+1] * <size_t> w[self._data[i]] + cdef int deg = 0 + if len(w) != self._length: + raise ValueError + # NOTE: cython does optimize range(a) and range(a, b) but not range(a, b, c) + for i in range(self._nonzero): + deg += self._data[2 * i + 1] * <int> w[self._data[2 * i]] return deg - cdef size_t unweighted_quotient_degree(self, ETuple other): + cpdef int unweighted_quotient_degree(self, ETuple other) except *: """ - Degree of ``self`` divided by its gcd with ``other``. + Return the degree of ``self`` divided by its gcd with ``other``. It amounts to counting the non-negative entries of ``self.esub(other)``. @@ -1542,42 +1911,40 @@ cdef class ETuple: cdef size_t selfnz = 2 * self._nonzero cdef size_t othernz = 2 * other._nonzero - cdef size_t deg = 0 + cdef int deg = 0 while ind1 < selfnz: position = self._data[ind1] - exponent = self._data[ind1+1] + exponent = self._data[ind1 + 1] while ind2 < othernz and other._data[ind2] < position: ind2 += 2 if ind2 == othernz: while ind1 < selfnz: - deg += self._data[ind1+1] + deg += self._data[ind1 + 1] ind1 += 2 return deg if other._data[ind2] > position: # other[position] = 0 deg += exponent - elif other._data[ind2+1] < exponent: + elif other._data[ind2 + 1] < exponent: # There is a positive difference that we have to insert - deg += (exponent - other._data[ind2+1]) + deg += (exponent - other._data[ind2 + 1]) ind1 += 2 return deg @cython.boundscheck(False) @cython.wraparound(False) - cdef size_t weighted_quotient_degree(self, ETuple other, tuple w): + cpdef int weighted_quotient_degree(self, ETuple other, tuple w) except *: r""" - Weighted degree of ``self`` divided by its gcd with ``other``. + Return the weighted degree of ``self`` divided by its gcd with ``other``. INPUT: - ``other`` -- an :class:`~sage.rings.polynomial.polydict.ETuple` - ``w`` -- tuple of non-negative integers. - - ASSUMPTIONS: - - ``w`` and ``other`` have the same length as ``self``, and the - entries of ``self``, ``other`` and ``w`` are non-negative. """ + if len(w) != self._length: + raise ValueError('w must be of the same length as the ETuple') + cdef size_t ind1 = 0 # both ind1 and ind2 will be increased in double steps. cdef size_t ind2 = 0 cdef size_t exponent @@ -1606,20 +1973,21 @@ cdef class ETuple: ind1 += 2 return deg - cpdef ETuple eadd(ETuple self, ETuple other): + cpdef ETuple eadd(self, ETuple other): """ - Vector addition of ``self`` with ``other``. + Return the vector addition of ``self`` with ``other``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2]) - sage: f = ETuple([0,1,1]) + sage: e = ETuple([1, 0, 2]) + sage: f = ETuple([0, 1, 1]) sage: e.eadd(f) (1, 1, 3) Verify that :trac:`6428` has been addressed:: + sage: # needs sage.libs.singular sage: R.<y, z> = Frac(QQ['x'])[] sage: type(y) <class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'> @@ -1629,8 +1997,8 @@ cdef class ETuple: OverflowError: exponent overflow (...) # 64-bit OverflowError: Python int too large to convert to C unsigned long # 32-bit """ - if self._length!=other._length: - raise ArithmeticError + if self._length != other._length: + raise ArithmeticError('ETuple of different lengths') cdef size_t ind1 = 0 cdef size_t ind2 = 0 @@ -1655,86 +2023,108 @@ cdef class ETuple: result._nonzero += 1 return result - cpdef ETuple eadd_p(ETuple self, int other, int pos): + cpdef ETuple eadd_p(self, int other, size_t pos): """ Add ``other`` to ``self`` at position ``pos``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2]) + sage: e = ETuple([1, 0, 2]) sage: e.eadd_p(5, 1) (1, 5, 2) sage: e = ETuple([0]*7) - sage: e.eadd_p(5,4) + sage: e.eadd_p(5, 4) (0, 0, 0, 0, 5, 0, 0) sage: ETuple([0,1]).eadd_p(1, 0) == ETuple([1,1]) True - """ - cdef size_t index = 0 + sage: e = ETuple([0, 1, 0]) + sage: e.eadd_p(0, 0).nonzero_positions() + [1] + sage: e.eadd_p(0, 1).nonzero_positions() + [1] + sage: e.eadd_p(0, 2).nonzero_positions() + [1] + + TESTS: + + Test segmentation faults occurring as described in :trac:`34000`:: + + sage: ETuple([0, 1, 1]).eadd_p(1, 0) + (1, 1, 1) + sage: ETuple([0, 2, 4, 3]).eadd_p(5, 0) + (5, 2, 4, 3) + sage: ETuple([0, 2]).eadd_p(5, 0) + (5, 2) + sage: e = ETuple([0, 1, 0]) + sage: e.eadd_p(0, 0).nonzero_positions() + [1] + sage: e.eadd_p(0, 1).nonzero_positions() + [1] + sage: e.eadd_p(0, 2).nonzero_positions() + [1] + sage: e.eadd_p(-1, 1).nonzero_positions() + [] + """ + cdef size_t sindex = 0 cdef size_t rindex = 0 cdef int new_value - cdef int need_to_add = 1 - if pos < 0 or pos >= self._length: + if pos >= self._length: raise ValueError("pos must be between 0 and %s" % self._length) - cdef size_t alloc_len = self._nonzero + 1 - - cdef ETuple result = <ETuple>self._new() + cdef ETuple result = self._new() result._nonzero = self._nonzero - result._data = <int*>sig_malloc(sizeof(int)*alloc_len*2) + if not other: + # return a copy + result._data = <int*> sig_malloc(sizeof(int) * self._nonzero * 2) + memcpy(result._data, self._data, sizeof(int) * self._nonzero * 2) + return result - for index from 0 <= index < self._nonzero: - if self._data[2*index] == pos: - new_value = self._data[2*index+1] + other - if new_value != 0: - result._data[2*rindex] = pos - result._data[2*rindex+1] = new_value - else: - result._nonzero -= 1 - rindex -= 1 - need_to_add = 0 + result._data = <int*> sig_malloc(sizeof(int) * (self._nonzero + 1) * 2) + while sindex < self._nonzero and self._data[2 * sindex] < pos: + result._data[2 * sindex] = self._data[2 * sindex] + result._data[2 * sindex + 1] = self._data[2 * sindex + 1] + sindex += 1 + + if sindex < self._nonzero and self._data[2 * sindex] == pos: + new_value = self._data[2 * sindex + 1] + other + if new_value: + result._data[2 * sindex] = pos + result._data[2 * sindex + 1] = new_value + sindex += 1 + rindex = sindex else: - result._data[2*rindex] = self._data[2*index] - result._data[2*rindex+1] = self._data[2*index+1] - - rindex += 1 - - rindex = 0 - if need_to_add: - for index from 0 <= index < self._nonzero: - if self._data[2*index] > pos: - result._data[2*rindex] = pos - result._data[2*rindex+1] = other - rindex += 1 - result._nonzero += 1 - result._data[2*rindex] = self._data[2*index] - result._data[2*rindex+1] = self._data[2*index+1] - rindex += 1 + result._nonzero -= 1 + rindex = sindex + sindex += 1 + else: + result._data[2 * sindex] = pos + result._data[2 * sindex + 1] = other + result._nonzero += 1 + rindex = sindex + 1 - if rindex == index and other: - result._data[2*rindex] = pos - result._data[2*rindex+1] = other - result._nonzero += 1 + memcpy(result._data + 2 * rindex, + self._data + 2 * sindex, + sizeof(int) * 2 * (self._nonzero - sindex)) return result - cpdef ETuple eadd_scaled(ETuple self, ETuple other, int scalar): + cpdef ETuple eadd_scaled(self, ETuple other, int scalar): """ Vector addition of ``self`` with ``scalar * other``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2]) - sage: f = ETuple([0,1,1]) + sage: e = ETuple([1, 0, 2]) + sage: f = ETuple([0, 1, 1]) sage: e.eadd_scaled(f, 3) (1, 3, 5) """ if self._length != other._length: - raise ArithmeticError + raise ArithmeticError('ETuple of different lengths') cdef size_t ind1 = 0 cdef size_t ind2 = 0 @@ -1760,15 +2150,15 @@ cdef class ETuple: result._nonzero += 1 return result - cpdef ETuple esub(ETuple self, ETuple other): + cpdef ETuple esub(self, ETuple other): """ Vector subtraction of ``self`` with ``other``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2]) - sage: f = ETuple([0,1,1]) + sage: e = ETuple([1, 0, 2]) + sage: f = ETuple([0, 1, 1]) sage: e.esub(f) (1, -1, 1) """ @@ -1798,14 +2188,14 @@ cdef class ETuple: result._nonzero += 1 return result - cpdef ETuple emul(ETuple self, int factor): + cpdef ETuple emul(self, int factor): """ Scalar Vector multiplication of ``self``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2]) + sage: e = ETuple([1, 0, 2]) sage: e.emul(2) (2, 0, 4) """ @@ -1813,32 +2203,32 @@ cdef class ETuple: cdef ETuple result = <ETuple>self._new() if factor == 0: result._nonzero = 0 # all zero, no non-zero entries! - result._data = <int*>sig_malloc(sizeof(int)*result._nonzero*2) + result._data = <int*>sig_malloc(sizeof(int) * result._nonzero * 2) else: result._nonzero = self._nonzero - result._data = <int*>sig_malloc(sizeof(int)*result._nonzero*2) - for ind from 0 <= ind < self._nonzero: - result._data[2*ind] = self._data[2*ind] - result._data[2*ind+1] = self._data[2*ind+1]*factor + result._data = <int*>sig_malloc(sizeof(int) * result._nonzero * 2) + for ind in range(self._nonzero): + result._data[2 * ind] = self._data[2 * ind] + result._data[2 * ind + 1] = self._data[2 * ind + 1] * factor return result - cpdef ETuple emax(ETuple self, ETuple other): + cpdef ETuple emax(self, ETuple other): """ Vector of maximum of components of ``self`` and ``other``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2]) - sage: f = ETuple([0,1,1]) + sage: e = ETuple([1, 0, 2]) + sage: f = ETuple([0, 1, 1]) sage: e.emax(f) (1, 1, 2) - sage: e = ETuple((1,2,3,4)) - sage: f = ETuple((4,0,2,1)) + sage: e = ETuple((1, 2, 3, 4)) + sage: f = ETuple((4, 0, 2, 1)) sage: f.emax(e) (4, 2, 3, 4) - sage: e = ETuple((1,-2,-2,4)) - sage: f = ETuple((4,0,0,0)) + sage: e = ETuple((1, -2, -2, 4)) + sage: f = ETuple((4, 0, 0, 0)) sage: f.emax(e) (4, 0, 0, 4) sage: f.emax(e).nonzero_positions() @@ -1869,19 +2259,19 @@ cdef class ETuple: result._nonzero += 1 return result - cpdef ETuple emin(ETuple self, ETuple other): + cpdef ETuple emin(self, ETuple other): """ Vector of minimum of components of ``self`` and ``other``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2]) - sage: f = ETuple([0,1,1]) + sage: e = ETuple([1, 0, 2]) + sage: f = ETuple([0, 1, 1]) sage: e.emin(f) (0, 0, 1) - sage: e = ETuple([1,0,-1]) - sage: f = ETuple([0,-2,1]) + sage: e = ETuple([1, 0, -1]) + sage: f = ETuple([0, -2, 1]) sage: e.emin(f) (0, -2, -1) """ @@ -1910,22 +2300,21 @@ cdef class ETuple: result._nonzero += 1 return result - cpdef int dotprod(ETuple self, ETuple other): + cpdef int dotprod(self, ETuple other) except *: """ Return the dot product of this tuple by ``other``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2]) - sage: f = ETuple([0,1,1]) + sage: e = ETuple([1, 0, 2]) + sage: f = ETuple([0, 1, 1]) sage: e.dotprod(f) 2 - sage: e = ETuple([1,1,-1]) - sage: f = ETuple([0,-2,1]) + sage: e = ETuple([1, 1, -1]) + sage: f = ETuple([0, -2, 1]) sage: e.dotprod(f) -3 - """ if self._length != other._length: raise ArithmeticError @@ -1940,19 +2329,19 @@ cdef class ETuple: result += exp1 * exp2 return result - cpdef ETuple escalar_div(ETuple self, int n): + cpdef ETuple escalar_div(self, int n): r""" Divide each exponent by ``n``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: ETuple([1,0,2]).escalar_div(2) + sage: ETuple([1, 0, 2]).escalar_div(2) (0, 0, 1) - sage: ETuple([0,3,12]).escalar_div(3) + sage: ETuple([0, 3, 12]).escalar_div(3) (0, 1, 4) - sage: ETuple([1,5,2]).escalar_div(0) + sage: ETuple([1, 5, 2]).escalar_div(0) Traceback (most recent call last): ... ZeroDivisionError @@ -1963,16 +2352,17 @@ cdef class ETuple: sage: from sage.rings.polynomial.polydict import ETuple sage: t = ETuple(list(range(2048))) - sage: for n in range(1,9): + sage: for n in range(1, 9): ....: t = t.escalar_div(n) sage: assert t.is_constant() """ if not n: raise ZeroDivisionError - cdef size_t i, j + cdef size_t i cdef ETuple result = self._new() result._data = <int*> sig_malloc(sizeof(int) * 2 * self._nonzero) result._nonzero = 0 + # NOTE: cython does optimize range(a) and range(a, b) but not range(a, b, c) for i in range(self._nonzero): result._data[2 * result._nonzero + 1] = self._data[2 * i + 1] / n if result._data[2 * result._nonzero + 1]: @@ -1980,13 +2370,15 @@ cdef class ETuple: result._nonzero += 1 return result - cdef ETuple divide_by_gcd(self, ETuple other): + cpdef ETuple divide_by_gcd(self, ETuple other): """ Return ``self / gcd(self, other)``. The entries of the result are the maximum of 0 and the difference of the corresponding entries of ``self`` and ``other``. """ + if self._length != other._length: + raise ArithmeticError('ETuple of different lengths') cdef size_t ind1 = 0 # both ind1 and ind2 will be increased in 2-steps. cdef size_t ind2 = 0 cdef int exponent @@ -2021,85 +2413,111 @@ cdef class ETuple: ind1 += 2 return result - cdef ETuple divide_by_var(self, size_t index): + cpdef ETuple divide_by_var(self, size_t pos): """ - Return division of ``self`` by ``var(index)`` or ``None``. + Return division of ``self`` by the variable with index ``pos``. + + If ``self[pos] == 0`` then a ``ArithmeticError`` is raised. Otherwise, + an :class:`~sage.rings.polynomial.polydict.ETuple` is returned that is + zero in position ``pos`` and coincides with ``self`` in the other + positions. - If ``self[Index] == 0`` then None is returned. Otherwise, an - :class:`~sage.rings.polynomial.polydict.ETuple` is returned - that is zero in position ``index`` and coincides with ``self`` - in the other positions. + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import ETuple + sage: e = ETuple([1, 2, 0, 1]) + sage: e.divide_by_var(0) + (0, 2, 0, 1) + sage: e.divide_by_var(1) + (1, 1, 0, 1) + sage: e.divide_by_var(3) + (1, 2, 0, 0) + sage: e.divide_by_var(2) + Traceback (most recent call last): + ... + ArithmeticError: not divisible by this variable """ - cdef size_t i, j cdef int exp1 cdef ETuple result - for i in range(0, 2*self._nonzero,2): - if self._data[i] == index: - result = <ETuple>self._new() - result._data = <int*>sig_malloc(sizeof(int)*self._nonzero*2) - exp1 = self._data[i+1] - if exp1>1: - # division doesn't change the number of nonzero positions - result._nonzero = self._nonzero - for j in range(0, 2*self._nonzero, 2): - result._data[j] = self._data[j] - result._data[j+1] = self._data[j+1] - result._data[i+1] = exp1-1 - else: - # var(index) disappears from self - result._nonzero = self._nonzero-1 - for j in range(0, i, 2): - result._data[j] = self._data[j] - result._data[j+1] = self._data[j+1] - for j in range(i+2, 2*self._nonzero, 2): - result._data[j-2] = self._data[j] - result._data[j-1] = self._data[j+1] - return result - return None + cdef size_t ind - cdef bint divides(self, ETuple other): + ind = self.get_position(pos, 0, self._nonzero) + if ind == self._nonzero or self._data[2 * ind] != pos: + raise ArithmeticError('not divisible by this variable') + result = <ETuple> self._new() + result._data = <int*> sig_malloc(sizeof(int) * 2 * self._nonzero) + exp1 = self._data[2 * ind + 1] + if exp1 > 1: + # division doesn't change the number of nonzero positions + result._nonzero = self._nonzero + memcpy(result._data, self._data, sizeof(int) * 2 * self._nonzero) + result._data[2 * ind + 1] = exp1 - 1 + else: + # var(pos) disappears from self + result._nonzero = self._nonzero - 1 + memcpy(result._data, self._data, sizeof(int) * 2 * ind) + if ind + 1 < self._nonzero: + memcpy(result._data + 2 * ind, self._data + 2 * (ind + 1), sizeof(int) * 2 * (self._nonzero - ind - 1)) + return result + + cpdef bint divides(self, ETuple other) except *: """ - Whether ``self`` divides ``other``, i.e., no entry of ``self`` + Return whether ``self`` divides ``other``, i.e., no entry of ``self`` exceeds that of ``other``. + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import ETuple + sage: ETuple([1, 1, 0, 1, 0]).divides(ETuple([2, 2, 2, 2, 2])) + True + sage: ETuple([0, 3, 0, 1, 0]).divides(ETuple([2, 2, 2, 2, 2])) + False + sage: ETuple([0, 3, 0, 1, 0]).divides(ETuple([0, 3, 2, 2, 2])) + True + sage: ETuple([0, 0, 0, 0, 0]).divides(ETuple([2, 2, 2, 2, 2])) + True + + sage: ETuple({104: 18, 256: 25, 314:78}, length=400r).divides(ETuple({104: 19, 105: 20, 106: 21}, length=400r)) + False + sage: ETuple({104: 18, 256: 25, 314:78}, length=400r).divides(ETuple({104: 19, 105: 20, 106: 21, 255: 2, 256: 25, 312: 5, 314: 79, 315: 28}, length=400r)) + True """ - cdef size_t ind1 # will be increased in 2-steps - cdef size_t ind2 = 0 # will be increased in 2-steps - cdef int pos1, exp1 - if self._nonzero > other._nonzero: - # Trivially self cannot divide other - return False - cdef size_t othernz2 = 2 * other._nonzero - for ind1 in range(0, 2*self._nonzero, 2): - pos1 = self._data[ind1] - exp1 = self._data[ind1+1] - # Because of the above trivial test, other._nonzero>0. - # So, other._data[ind2] initially makes sense. - while other._data[ind2] < pos1: - ind2 += 2 - if ind2 >= othernz2: - return False - if other._data[ind2] > pos1 or other._data[ind2+1] < exp1: - # Either other has no exponent at position pos1 or the exponent is less than in self + cdef size_t ind1 = 0 + cdef size_t ind2 = 0 + cdef int pos1 + + if self._length != other._length: + raise ArithmeticError('ETuple of different length') + + while ind1 < self._nonzero: + if self._nonzero - ind1 > other._nonzero - ind2: + return False + pos1 = self._data[2 * ind1] + ind2 = other.get_position(pos1, ind2, other._nonzero) + if ind2 == other._nonzero or other._data[2 * ind2] != pos1 or other._data[2 * ind2 + 1] < self._data[2 * ind1 + 1]: return False + ind1 += 1 + ind2 += 1 + return True - cpdef bint is_constant(ETuple self): + cpdef bint is_constant(self): """ Return if all exponents are zero in the tuple. EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2]) + sage: e = ETuple([1, 0, 2]) sage: e.is_constant() False - sage: e = ETuple([0,0]) + sage: e = ETuple([0, 0]) sage: e.is_constant() True """ return self._nonzero == 0 - cpdef bint is_multiple_of(ETuple self, int n): + cpdef bint is_multiple_of(self, int n) except *: r""" Test whether each entry is a multiple of ``n``. @@ -2107,22 +2525,22 @@ cdef class ETuple: sage: from sage.rings.polynomial.polydict import ETuple - sage: ETuple([0,0]).is_multiple_of(3) + sage: ETuple([0, 0]).is_multiple_of(3) True - sage: ETuple([0,3,12,0,6]).is_multiple_of(3) + sage: ETuple([0, 3, 12, 0, 6]).is_multiple_of(3) True - sage: ETuple([0,0,2]).is_multiple_of(3) + sage: ETuple([0, 0, 2]).is_multiple_of(3) False """ if not n: raise ValueError('n should not be zero') - cdef int i + cdef size_t i for i in range(self._nonzero): if self._data[2 * i + 1] % n: return False return True - cpdef list nonzero_positions(ETuple self, bint sort=False): + cpdef list nonzero_positions(self, bint sort=False): """ Return the positions of non-zero exponents in the tuple. @@ -2134,14 +2552,14 @@ cdef class ETuple: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2]) + sage: e = ETuple([1, 0, 2]) sage: e.nonzero_positions() [0, 2] """ cdef size_t ind - return [self._data[2*ind] for ind from 0 <= ind < self._nonzero] + return [self._data[2 * ind] for ind in range(self._nonzero)] - cpdef common_nonzero_positions(ETuple self, ETuple other, bint sort=False): + cpdef common_nonzero_positions(self, ETuple other, bint sort=False): """ Returns an optionally sorted list of non zero positions either in self or other, i.e. the only positions that need to be @@ -2150,8 +2568,8 @@ cdef class ETuple: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2]) - sage: f = ETuple([0,0,1]) + sage: e = ETuple([1, 0, 2]) + sage: f = ETuple([0, 0, 1]) sage: e.common_nonzero_positions(f) {0, 2} sage: e.common_nonzero_positions(f, sort=True) @@ -2164,7 +2582,7 @@ cdef class ETuple: else: return res - cpdef list nonzero_values(ETuple self, bint sort=True): + cpdef list nonzero_values(self, bint sort=True): """ Return the non-zero values of the tuple. @@ -2176,37 +2594,37 @@ cdef class ETuple: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([2,0,1]) + sage: e = ETuple([2, 0, 1]) sage: e.nonzero_values() [2, 1] - sage: f = ETuple([0,-1,1]) + sage: f = ETuple([0, -1, 1]) sage: f.nonzero_values(sort=True) [-1, 1] """ cdef size_t ind - return [self._data[2*ind+1] for ind from 0 <= ind < self._nonzero] + return [self._data[2 * ind + 1] for ind in range(self._nonzero)] - cpdef ETuple reversed(ETuple self): + cpdef ETuple reversed(self): """ Return the reversed ETuple of ``self``. EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,2,3]) + sage: e = ETuple([1, 2, 3]) sage: e.reversed() (3, 2, 1) """ cdef size_t ind cdef ETuple result = <ETuple>self._new() result._nonzero = self._nonzero - result._data = <int*>sig_malloc(sizeof(int)*result._nonzero*2) - for ind from 0 <= ind < self._nonzero: - result._data[2*(result._nonzero-ind-1)] = self._length - self._data[2*ind] - 1 - result._data[2*(result._nonzero-ind-1)+1] = self._data[2*ind+1] + result._data = <int*>sig_malloc(sizeof(int) * result._nonzero * 2) + for ind in range(self._nonzero): + result._data[2 * (result._nonzero - ind - 1)] = self._length - self._data[2 * ind] - 1 + result._data[2 * (result._nonzero - ind - 1) + 1] = self._data[2 * ind + 1] return result - def sparse_iter(ETuple self): + def sparse_iter(self): """ Iterator over the elements of ``self`` where the elements are returned as ``(i, e)`` where ``i`` is the position of ``e`` in the tuple. @@ -2214,15 +2632,15 @@ cdef class ETuple: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([1,0,2,0,3]) + sage: e = ETuple([1, 0, 2, 0, 3]) sage: list(e.sparse_iter()) [(0, 1), (2, 2), (4, 3)] """ cdef size_t ind - for ind from 0 <= ind < self._nonzero: - yield (self._data[2*ind], self._data[2*ind+1]) + for ind in range(self._nonzero): + yield (self._data[2 * ind], self._data[2 * ind + 1]) - def combine_to_positives(ETuple self, ETuple other): + def combine_to_positives(self, ETuple other): """ Given a pair of ETuples (self, other), returns a triple of ETuples (a, b, c) so that self = a + b, other = a + c and b and c @@ -2231,8 +2649,8 @@ cdef class ETuple: EXAMPLES:: sage: from sage.rings.polynomial.polydict import ETuple - sage: e = ETuple([-2,1,-5, 3, 1,0]) - sage: f = ETuple([1,-3,-3,4,0,2]) + sage: e = ETuple([-2, 1, -5, 3, 1, 0]) + sage: f = ETuple([1, -3, -3, 4, 0, 2]) sage: e.combine_to_positives(f) ((-2, -3, -5, 3, 0, 0), (0, 4, 0, 0, 1, 0), (3, 0, 2, 1, 0, 2)) """ @@ -2241,9 +2659,14 @@ cdef class ETuple: def make_PolyDict(data): - return PolyDict(data, remove_zero=False, force_int_exponents=False, - force_etuples=False) + r""" + Ensure support for pickled data from older sage versions. + """ + return PolyDict(data) def make_ETuple(data, length): + r""" + Ensure support for pickled data from older sage versions. + """ return ETuple(data, length) diff --git a/src/sage/rings/polynomial/polynomial_compiled.pyx b/src/sage/rings/polynomial/polynomial_compiled.pyx index 83f33a3a4d2..f7568893309 100644 --- a/src/sage/rings/polynomial/polynomial_compiled.pyx +++ b/src/sage/rings/polynomial/polynomial_compiled.pyx @@ -12,7 +12,7 @@ AUTHORS: # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ################################################################################ from sage.misc.binary_tree cimport BinaryTree @@ -140,9 +140,8 @@ cdef class CompiledPolynomialFunction: Return the resultant head DAG node, and a binary tree containing the dummy nodes. """ - cdef BinaryTree gaps - cdef int d, i + cdef int d cdef generic_pd s s = univar_pd() @@ -154,7 +153,7 @@ cdef class CompiledPolynomialFunction: s = coeff_pd(d) gap_width = 0 - d-= 1 + d -= 1 while d > 0: gap_width += 1 if self._coeffs[d]: @@ -393,8 +392,9 @@ cdef class var_pd(generic_pd): self.index = index cdef int eval(var_pd self, object vars, object coeffs) except -2: self.value = vars[self.index] + def __repr__(self): - return "x[%s]"%(self.index) + return "x[%s]" % (self.index) cdef class univar_pd(generic_pd): @@ -403,6 +403,7 @@ cdef class univar_pd(generic_pd): self.label = 1 cdef int eval(univar_pd self, object var, object coeffs) except -2: self.value = var + def __repr__(self): return "x" @@ -412,8 +413,9 @@ cdef class coeff_pd(generic_pd): self.index = index cdef int eval(coeff_pd self, object vars, object coeffs) except -2: self.value = coeffs[self.index] + def __repr__(self): - return "a%s"%(self.index) + return "a%s" % (self.index) cdef void reset(self): pass @@ -440,7 +442,7 @@ cdef class sqr_pd(unary_pd): pd_clean(self.operand) def __repr__(self): - return "(%s)^2"%(self.operand) + return "(%s)^2" % (self.operand) cdef class pow_pd(unary_pd): def __init__(unary_pd self, generic_pd base, object exponent): @@ -453,7 +455,7 @@ cdef class pow_pd(unary_pd): pd_clean(self.operand) def __repr__(self): - return "(%s^%s)"%(self.left, self.exponent) + return "(%s^%s)" % (self.left, self.exponent) @@ -482,8 +484,9 @@ cdef class add_pd(binary_pd): self.value = self.left.value + self.right.value pd_clean(self.left) pd_clean(self.right) + def __repr__(self): - return "(%s+%s)"%(self.left, self.right) + return "(%s+%s)" % (self.left, self.right) cdef class mul_pd(binary_pd): cdef int eval(mul_pd self, object vars, object coeffs) except -2: @@ -492,8 +495,9 @@ cdef class mul_pd(binary_pd): self.value = self.left.value * self.right.value pd_clean(self.left) pd_clean(self.right) + def __repr__(self): - return "(%s*%s)"%(self.left, self.right) + return "(%s*%s)" % (self.left, self.right) cdef class abc_pd(binary_pd): def __init__(abc_pd self, generic_pd left, generic_pd right, int index): @@ -501,7 +505,7 @@ cdef class abc_pd(binary_pd): self.index = index def __repr__(self): - return "(%s*%s+a%s)"%(self.left, self.right, self.index) + return "(%s*%s+a%s)" % (self.left, self.right, self.index) cdef int eval(abc_pd self, object vars, object coeffs) except -2: pd_eval(self.left, vars, coeffs) diff --git a/src/sage/rings/polynomial/polynomial_complex_arb.pxd b/src/sage/rings/polynomial/polynomial_complex_arb.pxd index aa4e2a1c0dc..e54d85e961b 100644 --- a/src/sage/rings/polynomial/polynomial_complex_arb.pxd +++ b/src/sage/rings/polynomial/polynomial_complex_arb.pxd @@ -2,5 +2,5 @@ from sage.libs.arb.acb_poly cimport * from sage.rings.polynomial.polynomial_element cimport Polynomial cdef class Polynomial_complex_arb(Polynomial): - cdef acb_poly_struct[1] __poly # https://github.com/cython/cython/issues/1984 + cdef acb_poly_struct[1] _poly # https://github.com/cython/cython/issues/1984 cdef Polynomial_complex_arb _new(self) diff --git a/src/sage/rings/polynomial/polynomial_complex_arb.pyx b/src/sage/rings/polynomial/polynomial_complex_arb.pyx index 5fc4ff1f6af..57c1a52ede4 100644 --- a/src/sage/rings/polynomial/polynomial_complex_arb.pyx +++ b/src/sage/rings/polynomial/polynomial_complex_arb.pyx @@ -47,7 +47,7 @@ cdef class Polynomial_complex_arb(Polynomial): sage: type(x) <class 'sage.rings.polynomial.polynomial_complex_arb.Polynomial_complex_arb'> - sage: Pol(), Pol(1), Pol([0,1,2]), Pol({1: pi, 3: i}) + sage: Pol(), Pol(1), Pol([0,1,2]), Pol({1: pi, 3: i}) # needs sage.symbolic (0, 1.000000000000000, 2.000000000000000*x^2 + x, @@ -75,7 +75,7 @@ cdef class Polynomial_complex_arb(Polynomial): sage: ComplexBallField(2)['y']() 0 """ - acb_poly_init(self.__poly) + acb_poly_init(self._poly) def __dealloc__(self): r""" @@ -84,7 +84,7 @@ cdef class Polynomial_complex_arb(Polynomial): sage: pol = CBF['x']() sage: del pol """ - acb_poly_clear(self.__poly) + acb_poly_clear(self._poly) cdef Polynomial_complex_arb _new(self): r""" @@ -125,9 +125,9 @@ cdef class Polynomial_complex_arb(Polynomial): x + 2.000000000000000 sage: Polynomial_complex_arb(Pol, QQ['x'](0)) 0 - sage: Polynomial_complex_arb(Pol, {10: pi}) + sage: Polynomial_complex_arb(Pol, {10: pi}) # needs sage.symbolic ([3.141592653589793 +/- ...e-16])*x^10 - sage: Polynomial_complex_arb(Pol, pi) + sage: Polynomial_complex_arb(Pol, pi) # needs sage.symbolic [3.141592653589793 +/- ...e-16] """ cdef ComplexBall ball @@ -140,49 +140,49 @@ cdef class Polynomial_complex_arb(Polynomial): Polynomial.__init__(self, parent, is_gen=is_gen) if is_gen: - acb_poly_set_coeff_si(self.__poly, 1, 1) + acb_poly_set_coeff_si(self._poly, 1, 1) elif x is None: - acb_poly_zero(self.__poly) + acb_poly_zero(self._poly) elif isinstance(x, Polynomial_complex_arb): - acb_poly_set(self.__poly, (<Polynomial_complex_arb> x).__poly) + acb_poly_set(self._poly, (<Polynomial_complex_arb> x)._poly) elif isinstance(x, ComplexBall): - acb_poly_set_coeff_acb(self.__poly, 0, (<ComplexBall> x).value) + acb_poly_set_coeff_acb(self._poly, 0, (<ComplexBall> x).value) else: Coeff = parent.base_ring() if isinstance(x, list): lst = <list> x length = len(lst) - sig_on(); acb_poly_fit_length(self.__poly, length); sig_off() + sig_on(); acb_poly_fit_length(self._poly, length); sig_off() for i in range(length): ball = Coeff(lst[i]) - acb_poly_set_coeff_acb(self.__poly, i, ball.value) + acb_poly_set_coeff_acb(self._poly, i, ball.value) elif isinstance(x, tuple): tpl = <tuple> x length = len(tpl) - sig_on(); acb_poly_fit_length(self.__poly, length); sig_off() + sig_on(); acb_poly_fit_length(self._poly, length); sig_off() for i in range(length): ball = Coeff(tpl[i]) - acb_poly_set_coeff_acb(self.__poly, i, ball.value) + acb_poly_set_coeff_acb(self._poly, i, ball.value) elif isinstance(x, Polynomial): pol = <Polynomial> x length = pol.degree() + 1 - sig_on(); acb_poly_fit_length(self.__poly, length); sig_off() + sig_on(); acb_poly_fit_length(self._poly, length); sig_off() for i in range(length): ball = Coeff(pol.get_unsafe(i)) - acb_poly_set_coeff_acb(self.__poly, i, ball.value) + acb_poly_set_coeff_acb(self._poly, i, ball.value) elif isinstance(x, dict): dct = <dict> x if len(dct) == 0: - acb_poly_zero(self.__poly) + acb_poly_zero(self._poly) else: length = max(int(i) for i in dct) + 1 - sig_on(); acb_poly_fit_length(self.__poly, length); sig_off() + sig_on(); acb_poly_fit_length(self._poly, length); sig_off() for i, c in dct.iteritems(): ball = Coeff(c) - acb_poly_set_coeff_acb(self.__poly, i, ball.value) + acb_poly_set_coeff_acb(self._poly, i, ball.value) else: ball = Coeff(x) - acb_poly_set_coeff_acb(self.__poly, 0, ball.value) + acb_poly_set_coeff_acb(self._poly, 0, ball.value) def __reduce__(self): r""" @@ -219,12 +219,12 @@ cdef class Polynomial_complex_arb(Polynomial): sage: Pol([1, 0, 0, 0]).degree() 0 """ - return smallInteger(acb_poly_degree(self.__poly)) + return smallInteger(acb_poly_degree(self._poly)) cdef get_unsafe(self, Py_ssize_t n): cdef ComplexBall res = ComplexBall.__new__(ComplexBall) res._parent = self._parent._base - acb_poly_get_coeff_acb(res.value, self.__poly, n) + acb_poly_get_coeff_acb(res.value, self._poly, n) return res cpdef list list(self, bint copy=True): @@ -241,7 +241,7 @@ cdef class Polynomial_complex_arb(Polynomial): sage: Pol([0, 1, RBF(0, rad=.1), 0]).list() [0, 1.000000000000000, [+/- 0.101]] """ - cdef unsigned long length = acb_poly_length(self.__poly) + cdef unsigned long length = acb_poly_length(self._poly) return [self.get_unsafe(n) for n in range(length)] def __bool__(self): @@ -257,7 +257,7 @@ cdef class Polynomial_complex_arb(Polynomial): sage: bool(z) True """ - return acb_poly_length(self.__poly) + return acb_poly_length(self._poly) # Ring and Euclidean arithmetic @@ -274,9 +274,9 @@ cdef class Polynomial_complex_arb(Polynomial): cdef Polynomial_complex_arb res = self._new() sig_on() acb_poly_add( - res.__poly, - self.__poly, - (<Polynomial_complex_arb> other).__poly, + res._poly, + self._poly, + (<Polynomial_complex_arb> other)._poly, prec(self)) sig_off() return res @@ -293,7 +293,7 @@ cdef class Polynomial_complex_arb(Polynomial): """ cdef Polynomial_complex_arb res = self._new() sig_on() - acb_poly_neg(res.__poly, self.__poly) + acb_poly_neg(res._poly, self._poly) sig_off() return res @@ -310,9 +310,9 @@ cdef class Polynomial_complex_arb(Polynomial): cdef Polynomial_complex_arb res = self._new() sig_on() acb_poly_sub( - res.__poly, - self.__poly, - (<Polynomial_complex_arb> other).__poly, + res._poly, + self._poly, + (<Polynomial_complex_arb> other)._poly, prec(self)) sig_off() return res @@ -331,9 +331,9 @@ cdef class Polynomial_complex_arb(Polynomial): cdef Polynomial_complex_arb res = self._new() sig_on() acb_poly_mul( - res.__poly, - self.__poly, - (<Polynomial_complex_arb> other).__poly, + res._poly, + self._poly, + (<Polynomial_complex_arb> other)._poly, prec(self)) sig_off() return res @@ -354,7 +354,7 @@ cdef class Polynomial_complex_arb(Polynomial): """ cdef Polynomial_complex_arb res = self._new() sig_on() - acb_poly_scalar_mul(res.__poly, self.__poly, (<ComplexBall> a).value, prec(self)) + acb_poly_scalar_mul(res._poly, self._poly, (<ComplexBall> a).value, prec(self)) sig_off() return res @@ -383,8 +383,11 @@ cdef class Polynomial_complex_arb(Polynomial): sage: Pol.<x> = CBF[] - sage: (x^3/7 - CBF(i)).quo_rem(x + CBF(pi)) - (([0.1428571428571428 +/- ...e-17])*x^2 + ([-0.448798950512828 +/- ...e-16])*x + [1.409943485869908 +/- ...e-16], [-4.42946809718569 +/- ...e-15] - I) + sage: (x^3/7 - CBF(i)).quo_rem(x + CBF(pi)) # needs sage.symbolic + (([0.1428571428571428 +/- ...e-17])*x^2 + + ([-0.448798950512828 +/- ...e-16])*x + + [1.409943485869908 +/- ...e-16], + [-4.42946809718569 +/- ...e-15] - I) sage: Pol(0).quo_rem(x + 1) (0, 0) @@ -406,8 +409,8 @@ cdef class Polynomial_complex_arb(Polynomial): cdef Polynomial_complex_arb quo = self._new() cdef Polynomial_complex_arb rem = self._new() sig_on() - cdef bint success = acb_poly_divrem(quo.__poly, rem.__poly, self.__poly, - div.__poly, prec(self)) + cdef bint success = acb_poly_divrem(quo._poly, rem._poly, self._poly, + div._poly, prec(self)) sig_off() if success: return quo, rem @@ -442,15 +445,15 @@ cdef class Polynomial_complex_arb(Polynomial): if n < 0: n = 0 sig_on() - acb_poly_set(res.__poly, self.__poly) - acb_poly_truncate(res.__poly, n) + acb_poly_set(res._poly, self._poly) + acb_poly_truncate(res._poly, n) sig_off() return res cdef _inplace_truncate(self, long n): if n < 0: n = 0 - acb_poly_truncate(self.__poly, n) + acb_poly_truncate(self._poly, n) return self def __lshift__(val, n): @@ -482,7 +485,7 @@ cdef class Polynomial_complex_arb(Polynomial): cdef Polynomial_complex_arb self = (<Polynomial_complex_arb> val) cdef Polynomial_complex_arb res = self._new() sig_on() - acb_poly_shift_left(res.__poly, self.__poly, n) + acb_poly_shift_left(res._poly, self._poly, n) sig_off() return res @@ -515,7 +518,7 @@ cdef class Polynomial_complex_arb(Polynomial): cdef Polynomial_complex_arb self = (<Polynomial_complex_arb> val) cdef Polynomial_complex_arb res = self._new() sig_on() - acb_poly_shift_right(res.__poly, self.__poly, n) + acb_poly_shift_right(res._poly, self._poly, n) sig_off() return res @@ -545,7 +548,7 @@ cdef class Polynomial_complex_arb(Polynomial): if n < 0: n = 0 sig_on() - acb_poly_mullow(res.__poly, self.__poly, my_other.__poly, n, prec(self)) + acb_poly_mullow(res._poly, self._poly, my_other._poly, n, prec(self)) sig_off() return res @@ -573,7 +576,7 @@ cdef class Polynomial_complex_arb(Polynomial): if n < 0: n = 0 sig_on() - acb_poly_inv_series(res.__poly, self.__poly, n, prec(self)) + acb_poly_inv_series(res._poly, self._poly, n, prec(self)) sig_off() return res @@ -609,7 +612,7 @@ cdef class Polynomial_complex_arb(Polynomial): if n < 0: n = 0 sig_on() - acb_poly_pow_ui_trunc_binexp(res.__poly, self.__poly, expo, n, prec(self)) + acb_poly_pow_ui_trunc_binexp(res._poly, self._poly, expo, n, prec(self)) sig_off() return res @@ -645,7 +648,7 @@ cdef class Polynomial_complex_arb(Polynomial): if n < 0: n = 0 sig_on() - acb_poly_log_series(res.__poly, self.__poly, n, prec(self)) + acb_poly_log_series(res._poly, self._poly, n, prec(self)) sig_off() return res @@ -661,7 +664,7 @@ cdef class Polynomial_complex_arb(Polynomial): 0.5000000000000000*x^2 + x + 1.000000000000000 sage: (1 + x/3)._log_series(3)._exp_series(3) ([+/- ...e-17])*x^2 + ([0.3333333333333333 +/- ...e-17])*x + 1.000000000000000 - sage: (CBF(0, pi) + x)._exp_series(4) + sage: (CBF(0, pi) + x)._exp_series(4) # needs sage.symbolic ([-0.166...] + [+/- ...]*I)*x^3 + ([-0.500...] + [+/- ...]*I)*x^2 + ([-1.000...] + [+/- ...]*I)*x + [-1.000...] + [+/- ...]*I """ @@ -669,7 +672,7 @@ cdef class Polynomial_complex_arb(Polynomial): if n < 0: n = 0 sig_on() - acb_poly_exp_series(res.__poly, self.__poly, n, prec(self)) + acb_poly_exp_series(res._poly, self._poly, n, prec(self)) sig_off() return res @@ -694,7 +697,7 @@ cdef class Polynomial_complex_arb(Polynomial): if n < 0: n = 0 sig_on() - acb_poly_sqrt_series(res.__poly, self.__poly, n, prec(self)) + acb_poly_sqrt_series(res._poly, self._poly, n, prec(self)) sig_off() return res @@ -713,7 +716,7 @@ cdef class Polynomial_complex_arb(Polynomial): if n < 0: n = 0 sig_on() - acb_poly_gamma_series(res.__poly, self.__poly, n, prec(self)) + acb_poly_gamma_series(res._poly, self._poly, n, prec(self)) sig_off() return res @@ -732,7 +735,7 @@ cdef class Polynomial_complex_arb(Polynomial): if n < 0: n = 0 sig_on() - acb_poly_lgamma_series(res.__poly, self.__poly, n, prec(self)) + acb_poly_lgamma_series(res._poly, self._poly, n, prec(self)) sig_off() return res @@ -751,7 +754,7 @@ cdef class Polynomial_complex_arb(Polynomial): if n < 0: n = 0 sig_on() - acb_poly_rgamma_series(res.__poly, self.__poly, n, prec(self)) + acb_poly_rgamma_series(res._poly, self._poly, n, prec(self)) sig_off() return res @@ -781,7 +784,7 @@ cdef class Polynomial_complex_arb(Polynomial): if n < 0: n = 0 sig_on() - acb_poly_lambertw_series(res.__poly, self.__poly, _branch, 0, n, prec(self)) + acb_poly_lambertw_series(res._poly, self._poly, _branch, 0, n, prec(self)) sig_off() fmpz_clear(_branch) return res @@ -811,7 +814,7 @@ cdef class Polynomial_complex_arb(Polynomial): cdef ComplexBall _a = <ComplexBall> (self._parent._base.coerce(a)) cdef Polynomial_complex_arb res = self._new() sig_on() - acb_poly_zeta_series(res.__poly, self.__poly, _a.value, deflate, n, prec(self)) + acb_poly_zeta_series(res._poly, self._poly, _a.value, deflate, n, prec(self)) sig_off() return res @@ -843,24 +846,24 @@ cdef class Polynomial_complex_arb(Polynomial): cdef Polynomial_complex_arb res = self._new() cdef acb_poly_t self_ts, other_ts cdef acb_ptr cc - if acb_poly_length(other1.__poly) > 0: - cc = acb_poly_get_coeff_ptr(other1.__poly, 0) + if acb_poly_length(other1._poly) > 0: + cc = acb_poly_get_coeff_ptr(other1._poly, 0) if not acb_is_zero(cc): sig_on() try: acb_poly_init(self_ts) acb_poly_init(other_ts) - acb_poly_taylor_shift(self_ts, self.__poly, cc, prec(self)) - acb_poly_set(other_ts, other1.__poly) + acb_poly_taylor_shift(self_ts, self._poly, cc, prec(self)) + acb_poly_set(other_ts, other1._poly) acb_zero(acb_poly_get_coeff_ptr(other_ts, 0)) - acb_poly_compose_series(res.__poly, self_ts, other_ts, n, prec(self)) + acb_poly_compose_series(res._poly, self_ts, other_ts, n, prec(self)) finally: acb_poly_clear(other_ts) acb_poly_clear(self_ts) sig_off() return res sig_on() - acb_poly_compose_series(res.__poly, self.__poly, other1.__poly, n, prec(self)) + acb_poly_compose_series(res._poly, self._poly, other1._poly, n, prec(self)) sig_off() return res @@ -892,12 +895,12 @@ cdef class Polynomial_complex_arb(Polynomial): cdef Polynomial_complex_arb res = self._new() if n < 0: n = 0 - if not acb_is_zero(acb_poly_get_coeff_ptr(self.__poly, 0)): + if not acb_is_zero(acb_poly_get_coeff_ptr(self._poly, 0)): raise ValueError("the constant coefficient must be zero") - if acb_contains_zero(acb_poly_get_coeff_ptr(self.__poly, 1)): + if acb_contains_zero(acb_poly_get_coeff_ptr(self._poly, 1)): raise ValueError("the linear term must be nonzero") sig_on() - acb_poly_revert_series(res.__poly, self.__poly, n, prec(self)) + acb_poly_revert_series(res._poly, self._poly, n, prec(self)) sig_off() return res @@ -911,7 +914,7 @@ cdef class Polynomial_complex_arb(Polynomial): sage: Pol.<x> = CBF[] sage: pol = x^2 - 1 - sage: pol(CBF(pi)) + sage: pol(CBF(pi)) # needs sage.symbolic [8.86960440108936 +/- ...e-15] sage: pol(x^3 + 1) x^6 + 2.000000000000000*x^3 @@ -935,15 +938,15 @@ cdef class Polynomial_complex_arb(Polynomial): ball = ComplexBall.__new__(ComplexBall) ball._parent = self._parent._base sig_on() - acb_poly_evaluate(ball.value, self.__poly, + acb_poly_evaluate(ball.value, self._poly, (<ComplexBall> point).value, prec(self)) sig_off() return ball elif isinstance(point, Polynomial_complex_arb): poly = (<Polynomial_complex_arb> point)._new() sig_on() - acb_poly_compose(poly.__poly, self.__poly, - (<Polynomial_complex_arb> point).__poly, prec(self)) + acb_poly_compose(poly._poly, self._poly, + (<Polynomial_complex_arb> point)._poly, prec(self)) sig_off() return poly # TODO: perhaps add more special cases, e.g. for real ball, diff --git a/src/sage/rings/polynomial/polynomial_element.pxd b/src/sage/rings/polynomial/polynomial_element.pxd index 1ba103329c3..5dcbf4597d0 100644 --- a/src/sage/rings/polynomial/polynomial_element.pxd +++ b/src/sage/rings/polynomial/polynomial_element.pxd @@ -1,11 +1,12 @@ -from sage.structure.element import Element, CommutativeAlgebraElement +from sage.structure.element import Element from sage.structure.element cimport Element, CommutativeAlgebraElement, ModuleElement from sage.structure.parent cimport Parent from sage.rings.integer cimport Integer +from .commutative_polynomial cimport CommutativePolynomial from .polynomial_compiled cimport CompiledPolynomialFunction -cdef class Polynomial(CommutativeAlgebraElement): +cdef class Polynomial(CommutativePolynomial): cdef Polynomial _new_generic(self, list coeffs) cdef char _is_gen cdef CompiledPolynomialFunction _compiled @@ -44,12 +45,12 @@ cdef class Polynomial(CommutativeAlgebraElement): cpdef _mul_(self, right) cpdef _floordiv_(self, right) - cdef public dict __cached_methods + cdef public dict _cached_methods cdef class Polynomial_generic_dense(Polynomial): cdef Polynomial_generic_dense _new_c(self, list coeffs, Parent P) - cdef list __coeffs - cdef int __normalize(self) except -1 + cdef list _coeffs + cdef int _normalize(self) except -1 cpdef list list(self, bint copy=*) cdef class Polynomial_generic_dense_inexact(Polynomial_generic_dense): diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index a522af5457c..c5a1129aecf 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -60,23 +60,20 @@ cdef is_FractionField cdef ZZ, QQ, RR, CC, RDF, CDF cimport cython -from cpython.number cimport PyNumber_TrueDivide, PyNumber_Check +from cpython.number cimport PyNumber_Check import operator import copy import re +from io import StringIO from sage.cpython.wrapperdescr cimport wrapperdescr_fastcall import sage.rings.rational import sage.rings.integer -from . import polynomial_ring import sage.rings.integer_ring import sage.rings.rational_field -import sage.rings.finite_rings.integer_mod_ring import sage.rings.fraction_field_element import sage.rings.infinity as infinity -from sage.misc.sage_eval import sage_eval -from sage.misc.abstract_method import abstract_method from sage.misc.latex import latex from sage.arith.power cimport generic_power from sage.arith.misc import crt @@ -86,16 +83,18 @@ from sage.structure.factorization import Factorization from sage.structure.richcmp cimport (richcmp, richcmp_item, rich_to_bool, rich_to_bool_sgn) -from sage.libs.pari.all import pari, pari_gen, PariError +try: + from sage.libs.pari.all import pari, pari_gen, PariError +except ImportError: + pari_gen = () + pari = None -cimport sage.rings.abc -from sage.rings.real_mpfr import RealField, RR + class PariError(Exception): + pass -from sage.rings.complex_mpfr import ComplexField -from sage.rings.cc import CC +cimport sage.rings.abc from sage.rings.real_double import RDF -from sage.rings.complex_double import CDF import sage.rings.abc import sage.interfaces.abc @@ -122,7 +121,6 @@ from sage.arith.functions import lcm from . import polynomial_fateman from sage.rings.ideal import is_Ideal -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.polynomial.multi_polynomial cimport MPolynomial @@ -135,13 +133,12 @@ from sage.categories.morphism cimport Morphism from sage.misc.superseded import deprecation_cython as deprecation, deprecated_function_alias from sage.misc.cachefunc import cached_method -from sage.rings.number_field.order import is_NumberFieldOrder -from sage.categories.number_fields import NumberFields - cpdef is_Polynomial(f): """ - Return True if f is of type univariate polynomial. + Return ``True`` if ``f`` is of type univariate polynomial. + + This function is deprecated. INPUT: @@ -152,29 +149,37 @@ cpdef is_Polynomial(f): sage: from sage.rings.polynomial.polynomial_element import is_Polynomial sage: R.<x> = ZZ[] sage: is_Polynomial(x^3 + x + 1) + doctest:...: DeprecationWarning: the function is_Polynomial is deprecated; + use isinstance(x, sage.rings.polynomial.polynomial_element.Polynomial) instead + See https://github.com/sagemath/sage/issues/32709 for details. True sage: S.<y> = R[] - sage: f = y^3 + x*y -3*x; f + sage: f = y^3 + x*y - 3*x; f y^3 + x*y - 3*x sage: is_Polynomial(f) True - However this function does not return True for genuine multivariate + However this function does not return ``True`` for genuine multivariate polynomial type objects or symbolic polynomials, since those are not of the same data type as univariate polynomials:: sage: R.<x,y> = QQ[] - sage: f = y^3 + x*y -3*x; f + sage: f = y^3 + x*y - 3*x; f y^3 + x*y - 3*x sage: is_Polynomial(f) False + + sage: # needs sage.symbolic sage: var('x,y') (x, y) - sage: f = y^3 + x*y -3*x; f + sage: f = y^3 + x*y - 3*x; f y^3 + x*y - 3*x sage: is_Polynomial(f) False """ + from sage.misc.superseded import deprecation + deprecation(32709, "the function is_Polynomial is deprecated; use isinstance(x, sage.rings.polynomial.polynomial_element.Polynomial) instead") + return isinstance(f, Polynomial) from .polynomial_compiled cimport CompiledPolynomialFunction @@ -182,7 +187,7 @@ from .polynomial_compiled cimport CompiledPolynomialFunction from sage.rings.polynomial.polydict cimport ETuple -cdef class Polynomial(CommutativeAlgebraElement): +cdef class Polynomial(CommutativePolynomial): """ A polynomial. @@ -308,7 +313,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: R.<x> = QQ[] - sage: (x-3).is_one() + sage: (x - 3).is_one() False sage: R(1).is_one() True @@ -342,14 +347,14 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: x = polygen(GF(389)) - sage: plot(x^2 + 1, rgbcolor=(0,0,1)) + sage: plot(x^2 + 1, rgbcolor=(0,0,1)) # needs sage.plot Graphics object consisting of 1 graphics primitive sage: x = polygen(QQ) - sage: plot(x^2 + 1, rgbcolor=(1,0,0)) + sage: plot(x^2 + 1, rgbcolor=(1,0,0)) # needs sage.plot Graphics object consisting of 1 graphics primitive """ R = self.base_ring() - from sage.plot.all import plot, point, line + from sage.plot.all import plot, point if R.characteristic() == 0: if xmin is None and xmax is None: (xmin, xmax) = (-1,1) @@ -407,9 +412,9 @@ cdef class Polynomial(CommutativeAlgebraElement): def subs(self, *x, **kwds): r""" - Identical to self(\*x). + Identical to ``self(*x)``. - See the docstring for ``self.__call__``. + See the docstring for :meth:`__call__`. EXAMPLES:: @@ -481,8 +486,9 @@ cdef class Polynomial(CommutativeAlgebraElement): We evaluate a polynomial over a quaternion algebra:: - sage: A.<i,j,k> = QuaternionAlgebra(QQ, -1,-1) - sage: R.<w> = PolynomialRing(A,sparse=True) + sage: # needs sage.combinat sage.modules + sage: A.<i,j,k> = QuaternionAlgebra(QQ, -1, -1) + sage: R.<w> = PolynomialRing(A, sparse=True) sage: f = i*j*w^5 - 13*i*w^2 + (i+j)*w + i sage: f(i+j+1) 24 + 26*i - 10*j - 25*k @@ -495,9 +501,10 @@ cdef class Polynomial(CommutativeAlgebraElement): of that matrix may change depending on the base of the polynomial ring. :: + sage: # needs sage.combinat sage.modules sage: R.<x> = QQ[] sage: f = R(2/3) - sage: a = matrix(ZZ,2) + sage: a = matrix(ZZ, 2) sage: b = f(a); b [2/3 0] [ 0 2/3] @@ -518,27 +525,27 @@ cdef class Polynomial(CommutativeAlgebraElement): 6 sage: f(w=5) 6 - sage: f(x=10) # x isn't mentioned + sage: f(x=10) # x isn't mentioned w^3 + 3*w + 2 Nested polynomial ring elements can be called like multivariate polynomials. Note the order of the arguments:: sage: R.<x> = QQ[]; S.<y> = R[] - sage: f = x+y*x+y^2 + sage: f = x + y*x + y^2 sage: f.parent() Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field sage: f(2) 3*x + 4 sage: f(2,4) 16 - sage: f(y=2,x=4) + sage: f(y=2, x=4) 16 - sage: f(2,x=4) + sage: f(2, x=4) 16 - sage: f(2,x=4,z=5) + sage: f(2, x=4, z=5) 16 - sage: f(2,4, z=10) + sage: f(2, 4, z=10) 16 sage: f(y=x) 2*x^2 + x @@ -558,16 +565,16 @@ cdef class Polynomial(CommutativeAlgebraElement): tuple containing the values to be substituted, though it is perhaps more natural to just unpack the list:: - sage: f([2]) # calling with a list + sage: f([2]) # calling with a list 3*x + 4 - sage: f((2,)) # calling with a tuple + sage: f((2,)) # calling with a tuple 3*x + 4 - sage: f(*[2]) # unpacking the list to call normally + sage: f(*[2]) # unpacking the list to call normally 3*x + 4 The following results in an element of the symbolic ring. :: - sage: f(x=sqrt(2)) + sage: f(x=sqrt(2)) # needs sage.symbolic y^2 + sqrt(2)*y + sqrt(2) :: @@ -593,11 +600,19 @@ cdef class Polynomial(CommutativeAlgebraElement): 3 sage: parent(f(0)) Rational Field - sage: parent(f(Qp(5)(0))) + sage: parent(f(Qp(5)(0))) # needs sage.rings.padics 5-adic Field with capped relative precision 20 TESTS: + One test for a simple evaluation:: + + sage: x, y = polygens(ZZ, 'x,y') + sage: t = polygen(x.parent(), 't') + sage: F = x*y*t + sage: F(y=1) + x*t + The following shows that :trac:`2360` is indeed fixed. :: sage: R.<x,y> = ZZ[] @@ -621,6 +636,7 @@ cdef class Polynomial(CommutativeAlgebraElement): The following test came up in :trac:`9051`:: + sage: # needs sage.rings.complex_interval_field sage: Cif = ComplexIntervalField(64) sage: R.<x> = Cif[] sage: f = 2*x-1 @@ -658,8 +674,8 @@ cdef class Polynomial(CommutativeAlgebraElement): Univariate Polynomial Ring in x over Rational Field sage: zero = QQ['x'](0) - sage: a = matrix(ZZ, [[1]]) - sage: zero(a).parent() + sage: a = matrix(ZZ, [[1]]) # needs sage.modules + sage: zero(a).parent() # needs sage.modules Full MatrixSpace of 1 by 1 dense matrices over Rational Field sage: pol(y, x).parent() is pol(x, y).parent() is pol(y, y).parent() is Pol_xy @@ -669,11 +685,11 @@ cdef class Polynomial(CommutativeAlgebraElement): Univariate Polynomial Ring in x over Rational Field sage: one = Pol_xy(1) - sage: one(1, 1.).parent() + sage: one(1, 1.).parent() # needs sage.rings.real_mpfr Real Field with 53 bits of precision sage: zero = GF(2)['x'](0) - sage: zero(1.).parent() # should raise an error + sage: zero(1.).parent() # needs sage.rings.real_mpfr Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: @@ -702,21 +718,23 @@ cdef class Polynomial(CommutativeAlgebraElement): These were drastically slower prior to :trac:`33165`:: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(31337)[] - sage: f = R(list(range(100,201))) - sage: g = R(list(range(1,1001))) + sage: f = R(list(range(100, 201))) + sage: g = R(list(range(1, 1001))) sage: S.<y> = R.quotient(f) sage: g(y) 22537*y^99 + 4686*y^98 + 13285*y^97 + 4216*y^96 + ... + 6389*y^3 + 30062*y^2 + 13755*y + 11875 :: + sage: # needs sage.rings.finite_rings sage: T.<z> = GF(31337)[] sage: g(z) 1000*z^999 + 999*z^998 + 998*z^997 + 997*z^996 + ... + 5*z^4 + 4*z^3 + 3*z^2 + 2*z + 1 sage: g(z^2) 1000*z^1998 + 999*z^1996 + 998*z^1994 + 997*z^1992 + ... + 5*z^8 + 4*z^6 + 3*z^4 + 2*z^2 + 1 - sage: g(T([0,1])) + sage: g(T([0, 1])) 1000*z^999 + 999*z^998 + 998*z^997 + 997*z^996 + ... + 5*z^4 + 4*z^3 + 3*z^2 + 2*z + 1 sage: g(T.zero()) 1 @@ -725,6 +743,7 @@ cdef class Polynomial(CommutativeAlgebraElement): :: + sage: # needs sage.rings.finite_rings sage: U.<u,v> = GF(31337)[] sage: g(u) 1000*u^999 + 999*u^998 + 998*u^997 + 997*u^996 + ... + 5*u^4 + 4*u^3 + 3*u^2 + 2*u + 1 @@ -772,14 +791,20 @@ cdef class Polynomial(CommutativeAlgebraElement): - Francis Clarke (2012-08-26): fix keyword substitution in the leading coefficient. """ - cdef long i, j + cdef long i, j, d, deg cdef Polynomial pol = self - cdef long d cdef ETuple etup cdef list cs cdef dict coeff_sparse, coeff_dict - cst = self._parent._base.zero() if self.degree() < 0 else self.get_unsafe(0) + deg = self.degree() + if deg < 0: + top = self._parent._base.one() + cst = self._parent._base.zero() + else: + top = self.get_unsafe(deg) + cst = self.get_unsafe(0) + a = args[0] if len(args) == 1 else None if kwds or not (isinstance(a, Element) or PyNumber_Check(a)): # slow path @@ -805,18 +830,22 @@ cdef class Polynomial(CommutativeAlgebraElement): try: # Note that we may be calling a different implementation that # is more permissive about its arguments than we are. - cst = cst(*args, **kwds) - eval_coeffs = True + top = top(*args, **kwds) except TypeError: if args: # bwd compat: nonsense *keyword* arguments are okay raise TypeError("Wrong number of arguments") + else: + eval_coeffs = True # Evaluate the coefficients, then fall through to evaluate the # resulting univariate polynomial if eval_coeffs: + new_base = parent(top) + # tentative common parent of the evaluated coefficients pol = pol.map_coefficients(lambda c: c(*args, **kwds), - new_base_ring=parent(cst)) + new_base_ring=new_base) + cst = cst(*args, **kwds) R = parent(a) @@ -829,8 +858,6 @@ cdef class Polynomial(CommutativeAlgebraElement): if isinstance(a, Polynomial) and a.base_ring() is pol._parent._base: if (<Polynomial> a).is_gen(): return R(pol) - if (<Polynomial> a).is_zero(): - return R(cst) d = (<Polynomial> a).degree() if d < 0: # f(0) return R(cst) @@ -897,7 +924,7 @@ cdef class Polynomial(CommutativeAlgebraElement): if pol._compiled is None: if d < 4 or d > 50000: result = pol.get_unsafe(d) - for i in xrange(d - 1, -1, -1): + for i in range(d - 1, -1, -1): result = result * a + pol.get_unsafe(i) return result pol._compiled = CompiledPolynomialFunction(pol.list()) @@ -911,15 +938,16 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: Pol.<x> = CBF[] - sage: (1 + x + x^2/2 + x^3/6 + x^4/24 + x^5/120).compose_trunc(1 + x, 2) + sage: Pol.<x> = CBF[] # needs sage.libs.flint + sage: (1 + x + x^2/2 + x^3/6 + x^4/24 + x^5/120).compose_trunc(1 + x, 2) # needs sage.libs.flint ([2.708333333333333 +/- ...e-16])*x + [2.71666666666667 +/- ...e-15] sage: Pol.<x> = QQ['y'][] sage: (1 + x + x^2/2 + x^3/6 + x^4/24 + x^5/120).compose_trunc(1 + x, 2) Traceback (most recent call last): ... - NotImplementedError: truncated composition is not implemented for this subclass of polynomials + NotImplementedError: truncated composition is not implemented + for this subclass of polynomials """ raise NotImplementedError("truncated composition is not implemented " "for this subclass of polynomials") @@ -1018,6 +1046,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Test that comparisons are consistent when using interval coefficients:: + sage: # needs sage.rings.real_interval_field sage: R.<x> = RIF[] sage: a = RIF(0,1) * x sage: b = RIF(1,2) * x @@ -1038,9 +1067,9 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: a != b False - sage: R.<x> = RBF[] - sage: pol = RBF(1.0, 0.1) - sage: pol == pol + sage: R.<x> = RBF[] # needs sage.libs.flint + sage: pol = RBF(1.0, 0.1) # needs sage.libs.flint + sage: pol == pol # needs sage.libs.flint False """ cdef Polynomial pol = <Polynomial?>other @@ -1079,7 +1108,7 @@ cdef class Polynomial(CommutativeAlgebraElement): """ EXAMPLES:: - sage: P = PolynomialRing(ZZ,'x')(0) + sage: P = PolynomialRing(ZZ, 'x')(0) sage: bool(P) False sage: P = PolynomialRing(ZZ, 'x')([1,2,3]) @@ -1121,33 +1150,28 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: pol[:6] 5*x^5 + 4*x^4 + 3*x^3 + 2*x^2 + x - Any other kind of slicing is deprecated or an error, see - :trac:`18940`:: + Any other kind of slicing is an error, see :trac:`18940`:: sage: f[1:3] - doctest:...: DeprecationWarning: polynomial slicing with a start index is deprecated, use list() and slice the resulting list instead - See https://github.com/sagemath/sage/issues/18940 for details. - x + Traceback (most recent call last): + ... + IndexError: polynomial slicing with a start is not defined + sage: f[1:3:2] Traceback (most recent call last): ... - NotImplementedError: polynomial slicing with a step is not defined + IndexError: polynomial slicing with a step is not defined """ cdef Py_ssize_t d = self.degree() + 1 if isinstance(n, slice): start, stop, step = n.start, n.stop, n.step if step is not None: - raise NotImplementedError("polynomial slicing with a step is not defined") - if start is None: - start = 0 - else: - if start < 0: - start = 0 - deprecation(18940, "polynomial slicing with a start index is deprecated, use list() and slice the resulting list instead") + raise IndexError("polynomial slicing with a step is not defined") + if start is not None: + raise IndexError("polynomial slicing with a start is not defined") if stop is None or stop > d: stop = d - values = ([self.base_ring().zero()] * start - + [self.get_unsafe(i) for i in xrange(start, stop)]) + values = [self.get_unsafe(i) for i in range(stop)] return self._new_generic(values) return self.get_coeff_c(pyobject_to_long(n)) @@ -1188,6 +1212,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: + sage: # needs sage.rings.padics sage: K.<u> = Qq(4) sage: R.<x> = K[] sage: f = x @@ -1239,9 +1264,9 @@ cdef class Polynomial(CommutativeAlgebraElement): Verify that :trac:`16251` has been resolved, i.e., polynomials with unhashable coefficients are unhashable:: - sage: K.<a> = Qq(9) - sage: R.<t> = K[] - sage: hash(t) + sage: K.<a> = Qq(9) # needs sage.rings.padics + sage: R.<t> = K[] # needs sage.rings.padics + sage: hash(t) # needs sage.rings.padics Traceback (most recent call last): ... TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement' @@ -1292,9 +1317,10 @@ cdef class Polynomial(CommutativeAlgebraElement): Defn: x |--> 5 sage: f(x) 5 - sage: f(x^2 + 3) # indirect doctest + sage: f(x^2 + 3) # indirect doctest 28 + sage: # needs sage.rings.number_field sage: K.<i> = NumberField(x^2 + 1) sage: cc = K.hom([-i]) sage: S.<y> = K[] @@ -1328,21 +1354,21 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: a = QQ['x'](1/5) sage: QQ(a) 1/5 - sage: AA(a) + sage: AA(a) # needs sage.rings.number_field 1/5 - sage: QQbar(a) + sage: QQbar(a) # needs sage.rings.number_field 1/5 sage: RDF(a) 0.2 - sage: CDF(a) + sage: CDF(a) # needs sage.rings.complex_double 0.2 sage: RR(a) 0.200000000000000 sage: CC(a) 0.200000000000000 - sage: RBF(a) + sage: RBF(a) # needs sage.libs.flint [0.2000000000000000 +/- 4.45e-17] - sage: CBF(a) + sage: CBF(a) # needs sage.libs.flint [0.2000000000000000 +/- 4.45e-17] sage: RIF(a) 0.2000000000000000? @@ -1353,18 +1379,20 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: complex(a) (0.2+0j) + sage: # needs sage.rings.number_field sage: b = AA['x'](AA(2/3).sqrt()) sage: AA(b) 0.8164965809277260? sage: RR(b) 0.816496580927726 - sage: RBF(b) + sage: RBF(b) # needs sage.libs.flint [0.816496580927726 +/- 2.44e-16] sage: RIF(b) 0.8164965809277260? sage: float(b) 0.816496580927726 + sage: # needs sage.rings.number_field sage: c = QQbar['x'](QQbar(-2/5).sqrt()) sage: QQbar(c) 0.6324555320336758?*I @@ -1372,7 +1400,7 @@ cdef class Polynomial(CommutativeAlgebraElement): 0.6324555320336758*I sage: CC(c) 0.632455532033676*I - sage: CBF(c) # abs tol 1e-16 + sage: CBF(c) # abs tol 1e-16 # needs sage.libs.flint [0.6324555320336759 +/- 3.38e-17]*I sage: CIF(c) 0.6324555320336758?*I @@ -1388,8 +1416,8 @@ cdef class Polynomial(CommutativeAlgebraElement): TypeError: cannot convert nonconstant polynomial sage: x = polygen(QQ) - sage: A.<u> = NumberField(x^3 - 2) - sage: A(A['x'](u)) + sage: A.<u> = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: A(A['x'](u)) # needs sage.rings.number_field u """ if self.degree() > 0: @@ -1431,8 +1459,8 @@ cdef class Polynomial(CommutativeAlgebraElement): r""" EXAMPLES:: - sage: p = PolynomialRing(QQbar, 'x')(1+I) - sage: complex(p) + sage: p = PolynomialRing(QQbar, 'x')(1+I) # needs sage.rings.number_field + sage: complex(p) # needs sage.rings.number_field (1+1j) """ return self._scalar_conversion(complex) @@ -1455,13 +1483,13 @@ cdef class Polynomial(CommutativeAlgebraElement): """ EXAMPLES:: + sage: # needs sage.symbolic sage: R.<x> = QQ[] sage: f = x^3 + x sage: g = f._symbolic_(SR); g x^3 + x sage: g(x=2) 10 - sage: g = SR(f) sage: g(x=2) 10 @@ -1470,7 +1498,7 @@ cdef class Polynomial(CommutativeAlgebraElement): :trac:`24072`):: sage: R.<w> = GF(7)[] - sage: f = SR(2*w^3 + 1); f + sage: f = SR(2*w^3 + 1); f # needs sage.symbolic Traceback (most recent call last): ... TypeError: positive characteristic not allowed in symbolic computations @@ -1500,7 +1528,8 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: f.inverse_of_unit() Traceback (most recent call last): ... - ArithmeticError: x - 90283 is not a unit in Univariate Polynomial Ring in x over Rational Field + ArithmeticError: x - 90283 is not a unit + in Univariate Polynomial Ring in x over Rational Field sage: f = R(-90283); g = f.inverse_of_unit(); g -1/90283 sage: parent(g) @@ -1526,10 +1555,11 @@ cdef class Polynomial(CommutativeAlgebraElement): def inverse_mod(a, m): """ - Inverts the polynomial a with respect to m, or raises a ValueError - if no such inverse exists. The parameter m may be either a single - polynomial or an ideal (for consistency with inverse_mod in other - rings). + Invert the polynomial ``a`` with respect to ``m``, or raise a :class:`ValueError` + if no such inverse exists. + + The parameter ``m`` may be either a single polynomial or an ideal + (for consistency with :meth:`inverse_mod` in other rings). .. SEEALSO:: @@ -1544,9 +1574,9 @@ cdef class Polynomial(CommutativeAlgebraElement): -1/2*t^2 - 1/2*t + 1/2 sage: f * (t^2 + 1) % (t^3 + 1) 1 - sage: f = t.inverse_mod((t+1)^7); f + sage: f = t.inverse_mod((t + 1)^7); f -t^6 - 7*t^5 - 21*t^4 - 35*t^3 - 35*t^2 - 21*t - 7 - sage: (f * t) + (t+1)^7 + sage: (f * t) + (t + 1)^7 1 sage: t.inverse_mod(S.ideal((t + 1)^7)) == f True @@ -1555,30 +1585,33 @@ cdef class Polynomial(CommutativeAlgebraElement): error the product may not always exactly equal the constant polynomial 1 and have extra terms with coefficients close to zero. :: + sage: # needs sage.modules sage: R.<x> = RDF[] sage: epsilon = RDF(1).ulp()*50 # Allow an error of up to 50 ulp sage: f = inverse_mod(x^2 + 1, x^5 + x + 1); f # abs tol 1e-14 0.4*x^4 - 0.2*x^3 - 0.4*x^2 + 0.2*x + 0.8 sage: poly = f * (x^2 + 1) % (x^5 + x + 1) sage: # Remove noisy zero terms: - sage: parent(poly)([ 0.0 if abs(c)<=epsilon else c for c in poly.coefficients(sparse=False) ]) + sage: parent(poly)([0.0 if abs(c) <= epsilon else c + ....: for c in poly.coefficients(sparse=False)]) 1.0 sage: f = inverse_mod(x^3 - x + 1, x - 2); f 0.14285714285714285 sage: f * (x^3 - x + 1) % (x - 2) 1.0 - sage: g = 5*x^3+x-7; m = x^4-12*x+13; f = inverse_mod(g, m); f + sage: g = 5*x^3 + x - 7; m = x^4 - 12*x + 13; f = inverse_mod(g, m); f -0.0319636125...*x^3 - 0.0383269759...*x^2 - 0.0463050900...*x + 0.346479687... sage: poly = f*g % m sage: # Remove noisy zero terms: - sage: parent(poly)([ 0.0 if abs(c)<=epsilon else c for c in poly.coefficients(sparse=False) ]) # abs tol 1e-14 + sage: parent(poly)([0.0 if abs(c) <= epsilon else c # abs tol 1e-14 + ....: for c in poly.coefficients(sparse=False)]) 1.0000000000000004 - ALGORITHM: Solve the system as + mt = 1, returning s as the inverse - of a mod m. + ALGORITHM: Solve the system `as + mt = 1`, returning `s` as the inverse + of `a` mod `m`. Uses the Euclidean algorithm for exact rings, and solves a linear - system for the coefficients of s and t for inexact rings (as the + system for the coefficients of `s` and `t` for inexact rings (as the Euclidean algorithm may not converge in that case). AUTHORS: @@ -1648,10 +1681,10 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: x = polygen(ZZ) - sage: s = (1+x).inverse_series_trunc(5) + sage: s = (1 + x).inverse_series_trunc(5) sage: s x^4 - x^3 + x^2 - x + 1 - sage: s * (1+x) + sage: s * (1 + x) x^5 + 1 Note that the constant coefficient needs to be a unit:: @@ -1678,7 +1711,8 @@ cdef class Polynomial(CommutativeAlgebraElement): Even noncommutative ones:: - sage: M = MatrixSpace(ZZ,2) + sage: # needs sage.modules + sage: M = MatrixSpace(ZZ, 2) sage: x = polygen(M) sage: p = M([1,2,3,4])*x^3 + M([-1,0,0,1])*x^2 + M([1,3,-1,0])*x + M.one() sage: q = p.inverse_series_trunc(5) @@ -1691,7 +1725,7 @@ cdef class Polynomial(CommutativeAlgebraElement): TESTS:: sage: x = polygen(ZZ['a','b']) - sage: (x+1).inverse_series_trunc(0) + sage: (x + 1).inverse_series_trunc(0) Traceback (most recent call last): ... ValueError: the precision must be positive, got 0 @@ -1736,9 +1770,11 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: Pol.<x> = QQ[] sage: (x + x^3/6 + x^5/120).revert_series(6) 3/40*x^5 - 1/6*x^3 + x - sage: Pol.<x> = CBF[] - sage: (x + x^3/6 + x^5/120).revert_series(6) + sage: Pol.<x> = CBF[] # needs sage.libs.flint + sage: (x + x^3/6 + x^5/120).revert_series(6) # needs sage.libs.flint ([0.075000000000000 +/- ...e-17])*x^5 + ([-0.166666666666667 +/- ...e-16])*x^3 + x + + sage: # needs sage.symbolic sage: Pol.<x> = SR[] sage: x.revert_series(6) Traceback (most recent call last): @@ -1752,7 +1788,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: R.<x> = ZZ[] - sage: (x - 4)*(x^2 - 8*x + 16) + sage: (x - 4) * (x^2 - 8*x + 16) x^3 - 12*x^2 + 48*x - 64 sage: C.<t> = PowerSeriesRing(ZZ) sage: D.<s> = PolynomialRing(C) @@ -1769,9 +1805,10 @@ cdef class Polynomial(CommutativeAlgebraElement): TESTS:: + sage: # needs sage.modules sage: Pol.<x> = MatrixSpace(ZZ, 2)[] - sage: a = matrix([[1,0],[0,0]]) - sage: b = matrix([[1,2],[3,4]]) + sage: a = matrix([[1,0], [0,0]]) + sage: b = matrix([[1,2], [3,4]]) sage: list((a*x)*(b*x + 1)) [ [0 0] [1 0] [1 2] @@ -1908,17 +1945,17 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: x = polygen(QQ) - sage: p = 37 * (x-1)^3 * (x-2)^3 * (x-1/3)^7 * (x-3/7) + sage: p = 37 * (x - 1)^3 * (x - 2)^3 * (x - 1/3)^7 * (x - 3/7) sage: p.squarefree_decomposition() (37*x - 111/7) * (x^2 - 3*x + 2)^3 * (x - 1/3)^7 - sage: p = 37 * (x-2/3)^2 + sage: p = 37 * (x - 2/3)^2 sage: p.squarefree_decomposition() (37) * (x - 2/3)^2 sage: x = polygen(GF(3)) sage: x.squarefree_decomposition() x - sage: f = QQbar['x'](1) - sage: f.squarefree_decomposition() + sage: f = QQbar['x'](1) # needs sage.rings.number_field + sage: f.squarefree_decomposition() # needs sage.rings.number_field 1 """ @@ -1956,7 +1993,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: (x^4 + 2*x^3 - x^2 - 2*x + 1).is_square(root=True) (True, x^2 + x - 1) - sage: f = 12*(x+1)^2 * (x+3)^2 + sage: f = 12 * (x + 1)^2 * (x + 3)^2 sage: f.is_square() False sage: f.is_square(root=True) @@ -1968,7 +2005,7 @@ cdef class Polynomial(CommutativeAlgebraElement): (True, 2*x^2 + 8*x + 6) sage: S.<y> = PolynomialRing(RR) - sage: g = 12*(y+1)^2 * (y+3)^2 + sage: g = 12 * (y + 1)^2 * (y + 3)^2 sage: g.is_square() True @@ -1985,6 +2022,12 @@ cdef class Polynomial(CommutativeAlgebraElement): False sage: R(0).is_square() True + + Make sure :trac:`35860` is fixed:: + + sage: S.<x> = PolynomialRing(ZZ) + sage: is_square(S(1), True)[1].parent() + Univariate Polynomial Ring in x over Integer Ring """ if self.is_zero(): return (True, self) if root else True @@ -1997,7 +2040,7 @@ cdef class Polynomial(CommutativeAlgebraElement): u = self._parent.base_ring()(f.unit()) if all(a[1] % 2 == 0 for a in f) and u.is_square(): - g = u.sqrt() + g = self._parent(u.sqrt()) for a in f: g *= a[0] ** (a[1] // 2) return (True, g) if root else True @@ -2021,11 +2064,12 @@ cdef class Polynomial(CommutativeAlgebraElement): contained within the given ring. - ``assume_squarefree`` (bool) -- Used for polynomials over - finite fields. If True, this polynomial is assumed to be + finite fields. If ``True``, this polynomial is assumed to be squarefree. EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(11)[] sage: f = 7*x^7 + 8*x^6 + 4*x^5 + x^4 + 6*x^3 + 10*x^2 + 8*x + 5 sage: f.any_root() @@ -2036,10 +2080,16 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: f.any_root(GF(11^6, 'a')) a^5 + a^4 + 7*a^3 + 2*a^2 + 10*a sage: sorted(f.roots(GF(11^6, 'a'))) - [(10*a^5 + 2*a^4 + 8*a^3 + 9*a^2 + a, 1), (a^5 + a^4 + 7*a^3 + 2*a^2 + 10*a, 1), (9*a^5 + 5*a^4 + 10*a^3 + 8*a^2 + 3*a + 1, 1), (2*a^5 + 8*a^4 + 3*a^3 + 6*a + 2, 1), (a^5 + 3*a^4 + 8*a^3 + 2*a^2 + 3*a + 4, 1), (10*a^5 + 3*a^4 + 8*a^3 + a^2 + 10*a + 4, 1)] + [(10*a^5 + 2*a^4 + 8*a^3 + 9*a^2 + a, 1), + (a^5 + a^4 + 7*a^3 + 2*a^2 + 10*a, 1), + (9*a^5 + 5*a^4 + 10*a^3 + 8*a^2 + 3*a + 1, 1), + (2*a^5 + 8*a^4 + 3*a^3 + 6*a + 2, 1), + (a^5 + 3*a^4 + 8*a^3 + 2*a^2 + 3*a + 4, 1), + (10*a^5 + 3*a^4 + 8*a^3 + a^2 + 10*a + 4, 1)] sage: f.any_root(GF(11^6, 'a')) a^5 + a^4 + 7*a^3 + 2*a^2 + 10*a + sage: # needs sage.rings.finite_rings sage: g = (x-1)*(x^2 + 3*x + 9) * (x^5 + 5*x^4 + 8*x^3 + 5*x^2 + 3*x + 5) sage: g.any_root(ring=GF(11^10, 'b'), degree=1) 1 @@ -2051,14 +2101,15 @@ cdef class Polynomial(CommutativeAlgebraElement): TESTS:: sage: R.<x> = GF(5)[] - sage: K.<a> = GF(5^12) - sage: for _ in range(40): + sage: K.<a> = GF(5^12) # needs sage.rings.finite_rings + sage: for _ in range(40): # needs sage.rings.finite_rings ....: f = R.random_element(degree=4) ....: assert f(f.any_root(K)) == 0 Check that our Cantor-Zassenhaus implementation does not loop over finite fields of even characteristic (see :trac:`16162`):: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(2**8) sage: x = polygen(K) sage: r = (x**2+x+1).any_root() # used to loop @@ -2069,6 +2120,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Also check that such computations can be interrupted:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(2^8) sage: x = polygen(K) sage: pol = x^1000000 + x + a @@ -2079,17 +2131,28 @@ cdef class Polynomial(CommutativeAlgebraElement): Check root computation over large finite fields:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(2**50) sage: x = polygen(K) sage: (x**10+x+a).any_root() - a^49 + a^47 + a^44 + a^42 + a^41 + a^39 + a^38 + a^37 + a^36 + a^34 + a^33 + a^29 + a^27 + a^26 + a^25 + a^23 + a^18 + a^13 + a^7 + a^5 + a^4 + a^3 + a^2 + a + a^49 + a^47 + a^44 + a^42 + a^41 + a^39 + a^38 + a^37 + a^36 + + a^34 + a^33 + a^29 + a^27 + a^26 + a^25 + a^23 + a^18 + + a^13 + a^7 + a^5 + a^4 + a^3 + a^2 + a sage: K.<a> = GF(2**150) sage: x = polygen(K) sage: (x**10+x+a).any_root() - a^149 + a^148 + a^146 + a^144 + a^143 + a^140 + a^138 + a^136 + a^134 + a^132 + a^131 + a^130 + a^129 + a^127 + a^123 + a^120 + a^118 + a^114 + a^113 + a^112 + a^111 + a^108 + a^104 + a^103 + a^102 + a^99 + a^98 + a^94 + a^91 + a^90 + a^88 + a^79 + a^78 + a^75 + a^73 + a^72 + a^67 + a^65 + a^64 + a^63 + a^62 + a^61 + a^59 + a^57 + a^52 + a^50 + a^48 + a^47 + a^46 + a^45 + a^43 + a^41 + a^39 + a^37 + a^34 + a^31 + a^29 + a^27 + a^25 + a^23 + a^22 + a^20 + a^18 + a^16 + a^14 + a^11 + a^10 + a^8 + a^6 + a^5 + a^4 + a + 1 + a^149 + a^148 + a^146 + a^144 + a^143 + a^140 + a^138 + a^136 + a^134 + + a^132 + a^131 + a^130 + a^129 + a^127 + a^123 + a^120 + a^118 + a^114 + + a^113 + a^112 + a^111 + a^108 + a^104 + a^103 + a^102 + a^99 + a^98 + + a^94 + a^91 + a^90 + a^88 + a^79 + a^78 + a^75 + a^73 + a^72 + a^67 + + a^65 + a^64 + a^63 + a^62 + a^61 + a^59 + a^57 + a^52 + a^50 + a^48 + + a^47 + a^46 + a^45 + a^43 + a^41 + a^39 + a^37 + a^34 + a^31 + a^29 + + a^27 + a^25 + a^23 + a^22 + a^20 + a^18 + a^16 + a^14 + a^11 + a^10 + + a^8 + a^6 + a^5 + a^4 + a + 1 Check that :trac:`21998` has been resolved:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(2^4) sage: R.<x> = K[] sage: f = x^2 + x + a^2 + a @@ -2288,9 +2351,9 @@ cdef class Polynomial(CommutativeAlgebraElement): :: - sage: R.<x> = PolynomialRing(GF(5^2, 'a'), 'x') + sage: R.<x> = PolynomialRing(GF(5^2, 'a'), 'x') # needs sage.rings.finite_rings sage: f = x^3 + 4*x - sage: f / (x - 1) + sage: f / (x - 1) # needs sage.rings.finite_rings x^2 + x Be careful about coercions (this used to be broken):: @@ -2311,8 +2374,8 @@ cdef class Polynomial(CommutativeAlgebraElement): ... ZeroDivisionError: inverse of Mod(0, 5) does not exist - sage: P.<x> = GF(25, 'a')[] - sage: x/5 + sage: P.<x> = GF(25, 'a')[] # needs sage.rings.finite_rings + sage: x/5 # needs sage.rings.finite_rings Traceback (most recent call last): ... ZeroDivisionError: division by zero in finite field @@ -2382,6 +2445,7 @@ cdef class Polynomial(CommutativeAlgebraElement): :: + sage: # needs sage.rings.finite_rings sage: k = GF(5) sage: D.<x> = k[] sage: l.<x> = k.extension(x^2 + 2) @@ -2396,7 +2460,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Check that :trac:`18457` is fixed:: sage: R.<x> = PolynomialRing(GF(5), sparse=True) - sage: (1+x)^(5^10) # used to hang forever + sage: (1+x)^(5^10) x^9765625 + 1 sage: S.<t> = GF(3)[] sage: R1.<x> = PolynomialRing(S, sparse=True) @@ -2408,12 +2472,13 @@ cdef class Polynomial(CommutativeAlgebraElement): Check that the algorithm used is indeed correct:: + sage: # needs sage.rings.finite_rings sage: from sage.arith.power import generic_power sage: R1 = PolynomialRing(GF(8,'a'), 'x') sage: R2 = PolynomialRing(GF(9,'b'), 'x', sparse=True) sage: R3 = PolynomialRing(R2, 'y') sage: R4 = PolynomialRing(R1, 'y', sparse=True) - sage: for d in range(20,40): # long time + sage: for d in range(20,40): # long time ....: for R in [R1, R2, R3, R3]: ....: a = R.random_element() ....: assert a^d == generic_power(a, d) @@ -2432,8 +2497,9 @@ cdef class Polynomial(CommutativeAlgebraElement): Check that fallback method is used when it is not possible to compute the characteristic of the base ring (:trac:`24308`):: + sage: # needs sage.libs.singular sage: kk.<a,b> = GF(2)[] - sage: k.<y,w> = kk.quo(a^2+a+1) + sage: k.<y,w> = kk.quo(a^2 + a + 1) sage: K.<T> = k[] sage: (T*y)^21 T^21 @@ -2522,22 +2588,20 @@ cdef class Polynomial(CommutativeAlgebraElement): -1800*x^7 + 1590*x^6 - 1052*x^5 + 530*x^4 - 200*x^3 + 55*x^2 - 10*x + 1 sage: S.<y> = R[] - sage: (x+y).power_trunc(5,5) + sage: (x + y).power_trunc(5,5) 5*x*y^4 + 10*x^2*y^3 + 10*x^3*y^2 + 5*x^4*y + x^5 - sage: ((x+y)^5).truncate(5) + sage: ((x + y)^5).truncate(5) 5*x*y^4 + 10*x^2*y^3 + 10*x^3*y^2 + 5*x^4*y + x^5 sage: R.<x> = GF(3)[] sage: p = x^2 - x + 1 - sage: q = p.power_trunc(80, 20) - sage: q + sage: q = p.power_trunc(80, 20); q x^19 + x^18 + ... + 2*x^4 + 2*x^3 + x + 1 sage: (p^80).truncate(20) == q True sage: R.<x> = GF(7)[] - sage: p = (x^2 + x + 1).power_trunc(2^100, 100) - sage: p + sage: p = (x^2 + x + 1).power_trunc(2^100, 100); p 2*x^99 + x^98 + x^95 + 2*x^94 + ... + 3*x^2 + 2*x + 1 sage: for i in range(100): @@ -2549,16 +2613,16 @@ cdef class Polynomial(CommutativeAlgebraElement): TESTS:: sage: x = polygen(QQ) - sage: (3*x-5).power_trunc(2^200, 0) + sage: (3*x - 5).power_trunc(2^200, 0) 0 sage: x.power_trunc(-1, 10) Traceback (most recent call last): ... ValueError: n must be a non-negative integer sage: R.<y> = QQ['x'] - sage: y.power_trunc(2**32-1, 2) + sage: y.power_trunc(2**32 - 1, 2) 0 - sage: y.power_trunc(2**64-1, 2) + sage: y.power_trunc(2**64 - 1, 2) 0 """ cdef Integer ZZn = ZZ(n) @@ -2630,10 +2694,10 @@ cdef class Polynomial(CommutativeAlgebraElement): elements in the Sage library yet that do not implement ``__bool__``, so we have to create one artificially.):: - sage: class PatchedAlgebraicNumber(sage.rings.qqbar.AlgebraicNumber): + sage: class PatchedAlgebraicNumber(sage.rings.qqbar.AlgebraicNumber): # needs sage.rings.number_field ....: def __bool__(self): raise NotImplementedError() - sage: R.<x> = QQbar[] - sage: R([PatchedAlgebraicNumber(0), 1]) + sage: R.<x> = QQbar[] # needs sage.rings.number_field + sage: R([PatchedAlgebraicNumber(0), 1]) # needs sage.rings.number_field x + 0 """ if name is None: @@ -2642,11 +2706,12 @@ cdef class Polynomial(CommutativeAlgebraElement): # want their coefficient printed with its O() term if self._is_gen and not isinstance(self._parent._base, pAdicGeneric): return name - s = " " + sbuf = StringIO() + sbuf.write(" ") m = self.degree() + 1 atomic_repr = self._parent.base_ring()._repr_option('element_is_atomic') coeffs = self.list(copy=False) - for n in reversed(xrange(m)): + for n in reversed(range(m)): x = coeffs[n] is_nonzero = False try: @@ -2658,7 +2723,7 @@ cdef class Polynomial(CommutativeAlgebraElement): is_nonzero = True if is_nonzero: if n != m-1: - s += " + " + sbuf.write(" + ") x = y = repr(x) if y.find("-") == 0: y = y[1:] @@ -2670,7 +2735,9 @@ cdef class Polynomial(CommutativeAlgebraElement): var = "*%s"%name else: var = "" - s += "%s%s"%(x,var) + sbuf.write(x) + sbuf.write(var) + s = sbuf.getvalue() s = s.replace(" + -", " - ") s = re.sub(r' 1(\.0+)?\*',' ', s) s = re.sub(r' -1(\.0+)?\*',' -', s) @@ -2705,11 +2772,13 @@ cdef class Polynomial(CommutativeAlgebraElement): :: + sage: # needs sage.rings.number_field sage: C3.<omega> = CyclotomicField(3) sage: R.<X> = C3[] sage: f = X^3 - omega*X sage: latex(f) X^{3} - \omega X + sage: R.<x> = RDF[] sage: latex(x+2) x + 2.0 @@ -2721,9 +2790,9 @@ cdef class Polynomial(CommutativeAlgebraElement): The following illustrates a (non-intentional) superfluity of parentheses - sage: K.<I>=QuadraticField(-1) - sage: R.<x>=K[] - sage: latex(I*x^2-I*x) + sage: K.<I> = QuadraticField(-1) # needs sage.rings.number_field + sage: R.<x> = K[] # needs sage.rings.number_field + sage: latex(I*x^2 - I*x) # needs sage.rings.number_field \left(\sqrt{-1}\right) x^{2} + \left(-\sqrt{-1}\right) x """ s = " " @@ -2732,7 +2801,7 @@ cdef class Polynomial(CommutativeAlgebraElement): if name is None: name = self._parent.latex_variable_names()[0] atomic_repr = self._parent.base_ring()._repr_option('element_is_atomic') - for n in reversed(xrange(m)): + for n in reversed(range(m)): x = coeffs[n] x = y = latex(x) if x != '0': @@ -2792,7 +2861,7 @@ cdef class Polynomial(CommutativeAlgebraElement): R1.<x> = ZZ[] R2.<y> = R1[] y^2 + (2*x + 2)*y + (x^2 + 2*x + 1) - sage: sage_input(RR(pi) * polygen(RR), verify=True) + sage: sage_input(RR(pi) * polygen(RR), verify=True) # needs sage.symbolic # Verified R.<x> = RR[] 3.1415926535897931*x @@ -2836,8 +2905,7 @@ cdef class Polynomial(CommutativeAlgebraElement): - ``value`` - value to set the n-th coefficient to - - OUTPUT: an IndexError is always raised. + OUTPUT: an :class:`IndexError` is always raised. EXAMPLES:: @@ -2852,7 +2920,7 @@ cdef class Polynomial(CommutativeAlgebraElement): cpdef _floordiv_(self, right): r""" - Quotient of division of self by other. This is denoted //. + Quotient of division of ``self`` by ``other``. This is denoted //. If self = quotient \* right + remainder, this function returns quotient. @@ -2875,7 +2943,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def __mod__(self, other): """ - Remainder of division of self by other. + Remainder of division of ``self`` by ``other``. EXAMPLES:: @@ -2890,7 +2958,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def mod(self, other): """ - Remainder of division of self by other. + Remainder of division of ``self`` by ``other``. EXAMPLES:: @@ -2904,6 +2972,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Check the problem reported at :trac:`12529` is fixed:: + sage: # needs sage.rings.finite_rings sage: gens = 'y a0 a1 a2 b0 b1 b2 c1 c2 d0 d1 d2 d3 d4 d5 d6 d7'.split() sage: R = PolynomialRing(GF(8), 17, gens) sage: R.inject_variables(verbose=False) @@ -2935,7 +3004,7 @@ cdef class Polynomial(CommutativeAlgebraElement): cpdef _mul_generic(self, right): """ - Compute the product of self and right using the classical quadratic + Compute the product of ``self`` and ``right`` using the classical quadratic algorithm. This method is the default for inexact rings. For two polynomials of degree n and m this method needs @@ -2951,14 +3020,15 @@ cdef class Polynomial(CommutativeAlgebraElement): Show the product in the symbolic ring:: - sage: L = SR['x'] - sage: var('a0,a1,b0,b1') + sage: L = SR['x'] # needs sage.symbolic + sage: var('a0,a1,b0,b1') # needs sage.symbolic (a0, a1, b0, b1) - sage: L([a0,a1])._mul_generic(L([b0,b1])) + sage: L([a0, a1])._mul_generic(L([b0, b1])) # needs sage.symbolic a1*b1*x^2 + (a1*b0 + a0*b1)*x + a0*b0 A non-commutative example:: + sage: # needs sage.combinat sage.modules sage: A.<i,j,k> = QuaternionAlgebra(QQ, -1,-1) sage: R.<w> = PolynomialRing(A) sage: f = i*w + j @@ -3095,7 +3165,7 @@ cdef class Polynomial(CommutativeAlgebraElement): INPUT: - ``self`` - Polynomial - - ``right`` - Polynomial (over same base ring as self) + - ``right`` - Polynomial (over same base ring as ``self``) - ``K_threshold`` - (optional) Integer. A threshold to fall back to schoolbook algorithm. In the recursion, if one of the polynomials is of degree less that K_threshold then the classic quadratic @@ -3169,16 +3239,18 @@ cdef class Polynomial(CommutativeAlgebraElement): Show the product in the symbolic ring:: + sage: # needs sage.symbolic sage: L = SR['x'] sage: var('a0,a1,b0,b1') (a0, a1, b0, b1) - sage: L([a0,a1])._mul_karatsuba(L([b0,b1]),0) + sage: L([a0, a1])._mul_karatsuba(L([b0, b1]), 0) a1*b1*x^2 + ((a0 + a1)*(b0 + b1) - a0*b0 - a1*b1)*x + a0*b0 - sage: L([a0,a1])._mul_karatsuba(L([b0,b1]),2) + sage: L([a0, a1])._mul_karatsuba(L([b0, b1]), 2) a1*b1*x^2 + (a1*b0 + a0*b1)*x + a0*b0 A noncommutative example:: + sage: # needs sage.combinat sage.modules sage: A.<i,j,k> = QuaternionAlgebra(QQ, -1,-1) sage: R.<w> = PolynomialRing(A) sage: f = i*w + j @@ -3211,6 +3283,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Random tests for noncommutative rings:: + sage: # needs sage.combinat sage.modules sage: A.<i,j,k> = QuaternionAlgebra(QQ, -1,-1) sage: R.<w> = PolynomialRing(A) sage: f = R.random_element(randint(10,100)) @@ -3227,11 +3300,12 @@ cdef class Polynomial(CommutativeAlgebraElement): Polynomials over matrices:: - sage: K = PolynomialRing(MatrixSpace(QQ,2),'x') - sage: f = K.random_element(randint(5,10)) - sage: g = K.random_element(randint(5,10)) + sage: # needs sage.modules + sage: K = PolynomialRing(MatrixSpace(QQ, 2), 'x') + sage: f = K.random_element(randint(5, 10)) + sage: g = K.random_element(randint(5, 10)) sage: h1 = f._mul_generic(g) - sage: h2 = f._mul_karatsuba(g,randint(0,10)) + sage: h2 = f._mul_karatsuba(g,randint(0, 10)) sage: h1 == h2 True """ @@ -3281,22 +3355,22 @@ cdef class Polynomial(CommutativeAlgebraElement): def base_ring(self): """ - Return the base ring of the parent of self. + Return the base ring of the parent of ``self``. EXAMPLES:: sage: R.<x> = ZZ[] sage: x.base_ring() Integer Ring - sage: (2*x+3).base_ring() + sage: (2*x + 3).base_ring() Integer Ring """ return self._parent.base_ring() cpdef base_extend(self, R): """ - Return a copy of this polynomial but with coefficients in R, if - there is a natural map from coefficient ring of self to R. + Return a copy of this polynomial but with coefficients in ``R``, if + there is a natural map from the coefficient ring of ``self`` to ``R``. EXAMPLES:: @@ -3325,6 +3399,8 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: f.change_variable_name('theta') -2/7*theta^3 + 2/3*theta - 19/993 """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._parent.base_ring(), names=var) return R(self) @@ -3339,24 +3415,25 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: K.<z> = CyclotomicField(3) - sage: f = K.defining_polynomial() - sage: f.change_ring(GF(7)) + sage: K.<z> = CyclotomicField(3) # needs sage.rings.number_field + sage: f = K.defining_polynomial() # needs sage.rings.number_field + sage: f.change_ring(GF(7)) # needs sage.rings.finite_rings sage.rings.number_field x^2 + x + 1 :: + sage: # needs sage.rings.number_field sage: K.<z> = CyclotomicField(3) sage: R.<x> = K[] sage: f = x^2 + z - sage: f.change_ring(K.embeddings(CC)[1]) + sage: f.change_ring(K.embeddings(CC)[1]) # needs sage.rings.real_mpfr x^2 - 0.500000000000000 - 0.866025403784438*I :: sage: R.<x> = QQ[] sage: f = x^2 + 1 - sage: f.change_ring(QQ.embeddings(CC)[0]) + sage: f.change_ring(QQ.embeddings(CC)[0]) # needs sage.rings.real_mpfr x^2 + 1.00000000000000 TESTS: @@ -3364,13 +3441,14 @@ cdef class Polynomial(CommutativeAlgebraElement): Check that :trac:`25022` is fixed:: sage: K.<x> = ZZ[] - sage: x.change_ring(SR) == SR['x'].gen() + sage: x.change_ring(SR) == SR['x'].gen() # needs sage.symbolic True sage: x.change_ring(ZZ['x']) == ZZ['x']['x'].gen() True Check that :trac:`28541` is fixed:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(7^2) sage: S.<x> = F[] sage: P = x^2 + a*x + a^2 @@ -3439,8 +3517,9 @@ cdef class Polynomial(CommutativeAlgebraElement): def __copy__(self): """ - Return a "copy" of self. This is just self, since in Sage - polynomials are immutable this just returns self again. + Return a "copy" of ``self``. + + This is just ``self``, since in Sage polynomials are immutable. EXAMPLES: @@ -3461,7 +3540,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def degree(self, gen=None): """ Return the degree of this polynomial. The zero polynomial has - degree -1. + degree `-1`. EXAMPLES:: @@ -3518,20 +3597,20 @@ cdef class Polynomial(CommutativeAlgebraElement): def denominator(self): """ - Return a denominator of self. + Return a denominator of ``self``. - First, the lcm of the denominators of the entries of self + First, the lcm of the denominators of the entries of ``self`` is computed and returned. If this computation fails, the - unit of the parent of self is returned. + unit of the parent of ``self`` is returned. Note that some subclasses may implement their own - denominator function. For example, see + :meth:`denominator` method. For example, see :class:`sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint` .. warning:: This is not the denominator of the rational function - defined by self, which would always be 1 since self is a + defined by ``self``, which would always be 1 since ``self`` is a polynomial. EXAMPLES: @@ -3559,7 +3638,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Finally, we try to compute the denominator of a polynomial with coefficients in the real numbers, which is a ring whose elements do - not have a denominator method. + not have a :meth:`denominator` method. :: @@ -3570,7 +3649,7 @@ cdef class Polynomial(CommutativeAlgebraElement): 1.00000000000000 Check that the denominator is an element over the base whenever the base - has no denominator function. This closes :trac:`9063`. :: + has no :meth:`denominator` method. This closes :trac:`9063`. :: sage: R.<a> = GF(5)[] sage: x = R(0) @@ -3606,7 +3685,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def numerator(self): """ - Return a numerator of self computed as self * self.denominator() + Return a numerator of ``self``, computed as ``self * self.denominator()`` Note that some subclasses may implement its own numerator function. For example, see @@ -3615,13 +3694,13 @@ cdef class Polynomial(CommutativeAlgebraElement): .. warning:: This is not the numerator of the rational function - defined by self, which would always be self since self is a + defined by ``self``, which would always be ``self`` since ``self`` is a polynomial. EXAMPLES: First we compute the numerator of a polynomial with - integer coefficients, which is of course self. + integer coefficients, which is of course ``self``. :: @@ -3657,17 +3736,19 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: f.numerator() x + 0.300000000000000 - We check that the computation the numerator and denominator - are valid + We check that the computation of the numerator and denominator + are valid. :: - sage: K=NumberField(symbolic_expression('x^3+2'),'a')['s,t']['x'] - sage: f=K.random_element() + sage: # needs sage.rings.number_field sage.symbolic + sage: K = NumberField(symbolic_expression('x^3+2'), 'a')['s,t']['x'] + sage: f = K.random_element() sage: f.numerator() / f.denominator() == f True - sage: R=RR['x'] - sage: f=R.random_element() + + sage: R = RR['x'] + sage: f = R.random_element() sage: f.numerator() / f.denominator() == f True """ @@ -3676,10 +3757,10 @@ cdef class Polynomial(CommutativeAlgebraElement): def derivative(self, *args): r""" The formal derivative of this polynomial, with respect to variables - supplied in args. + supplied in ``args``. Multiple variables and iteration counts may be supplied; see - documentation for the global derivative() function for more + documentation for the global :func:`derivative` function for more details. .. SEEALSO:: @@ -3777,6 +3858,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Check that :trac:`28147` is fixed:: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(65537)[] sage: p = x^4 - 17*x^3 + 2*x^2 - x + 7 sage: p.derivative() @@ -3785,6 +3867,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: p = x^4 - 17*x^3 + 2*x^2 - x + 7 sage: p.derivative() 4*x^3 + 6*x^2 + 4*x + 18 + sage: R.<x> = GF(2)[] sage: p = x^4 + x^2 + x sage: p.derivative() @@ -3802,6 +3885,7 @@ cdef class Polynomial(CommutativeAlgebraElement): ... ValueError: cannot differentiate with respect to 2*x + sage: # needs sage.symbolic sage: y = var("y") sage: f._derivative(y) Traceback (most recent call last): @@ -3819,11 +3903,13 @@ cdef class Polynomial(CommutativeAlgebraElement): Check that :trac:`28187` is fixed:: - sage: R.<x> = GF(65537)[] + sage: R.<x> = GF(65537)[] # needs sage.rings.finite_rings sage: x._derivative(2*x) Traceback (most recent call last): ... ValueError: cannot differentiate with respect to 2*x + + sage: # needs sage.symbolic sage: y = var('y') sage: R.gen()._derivative(y) Traceback (most recent call last): @@ -3902,15 +3988,17 @@ cdef class Polynomial(CommutativeAlgebraElement): This shows that the issue at :trac:`7711` is resolved:: + sage: # needs sage.rings.finite_rings sage: P.<x,z> = PolynomialRing(GF(2147483647)) sage: Q.<y> = PolynomialRing(P) - sage: p=x+y+z + sage: p = x + y + z sage: p.integral() -1073741823*y^2 + (x + z)*y + sage: # needs sage.rings.finite_rings sage: P.<x,z> = PolynomialRing(GF(next_prime(2147483647))) sage: Q.<y> = PolynomialRing(P) - sage: p=x+y+z + sage: p = x + y + z sage: p.integral() 1073741830*y^2 + (x + z)*y @@ -3943,7 +4031,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = QQ[] sage: t = PolynomialRing(R,'t').gen() - sage: f = x*t +5*t^2 + sage: f = x*t + 5*t^2 sage: f.integral(x) 5*x*t^2 + 1/2*x^2*t @@ -4016,7 +4104,7 @@ cdef class Polynomial(CommutativeAlgebraElement): cdef dict X = {} cdef list Y = self.list(copy=False) cdef Py_ssize_t i - for i in xrange(len(Y)): + for i in range(len(Y)): c = Y[i] if c: X[i] = c @@ -4029,14 +4117,14 @@ cdef class Polynomial(CommutativeAlgebraElement): INPUT: - ``kwargs`` -- any keyword arguments are passed to the method - ``_factor_univariate_polynomial()`` of the base ring if it + :meth:`_factor_univariate_polynomial` of the base ring if it defines such a method. OUTPUT: - - A factorization of ``self`` over its parent into a unit and - irreducible factors. If the parent is a polynomial ring - over a field, these factors are monic. + A factorization of ``self`` over its parent into a unit and + irreducible factors. If the parent is a polynomial ring + over a field, these factors are monic. EXAMPLES: @@ -4044,38 +4132,40 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: x = QQ['x'].0 sage: f = (x^3 - 1)^2 - sage: f.factor() + sage: f.factor() # needs sage.libs.pari (x - 1)^2 * (x^2 + x + 1)^2 Since `\QQ` is a field, the irreducible factors are monic:: sage: f = 10*x^5 - 1 - sage: f.factor() + sage: f.factor() # needs sage.libs.pari (10) * (x^5 - 1/10) sage: f = 10*x^5 - 10 - sage: f.factor() + sage: f.factor() # needs sage.libs.pari (10) * (x - 1) * (x^4 + x^3 + x^2 + x + 1) Over `\ZZ` the irreducible factors need not be monic:: sage: x = ZZ['x'].0 sage: f = 10*x^5 - 1 - sage: f.factor() + sage: f.factor() # needs sage.libs.pari 10*x^5 - 1 We factor a non-monic polynomial over a finite field of 25 elements:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(25) sage: R.<x> = k[] sage: f = 2*x^10 + 2*x + 2*a sage: F = f.factor(); F - (2) * (x + a + 2) * (x^2 + 3*x + 4*a + 4) * (x^2 + (a + 1)*x + a + 2) * (x^5 + (3*a + 4)*x^4 + (3*a + 3)*x^3 + 2*a*x^2 + (3*a + 1)*x + 3*a + 1) + (2) * (x + a + 2) * (x^2 + 3*x + 4*a + 4) * (x^2 + (a + 1)*x + a + 2) + * (x^5 + (3*a + 4)*x^4 + (3*a + 3)*x^3 + 2*a*x^2 + (3*a + 1)*x + 3*a + 1) Notice that the unit factor is included when we multiply `F` back out:: - sage: expand(F) + sage: expand(F) # needs sage.rings.finite_rings sage.symbolic 2*x^10 + 2*x + 2*a A new ring. In the example below, we set the special method @@ -4084,32 +4174,38 @@ cdef class Polynomial(CommutativeAlgebraElement): used to easily extend polynomial factorization to work over new rings you introduce:: - sage: R.<x> = PolynomialRing(IntegerModRing(4),implementation="NTL") + sage: # needs sage.libs.ntl + sage: R.<x> = PolynomialRing(IntegerModRing(4), implementation="NTL") sage: (x^2).factor() Traceback (most recent call last): ... - NotImplementedError: factorization of polynomials over rings with composite characteristic is not implemented - sage: R.base_ring()._factor_univariate_polynomial = lambda f: f.change_ring(ZZ).factor() - sage: (x^2).factor() + NotImplementedError: factorization of polynomials over rings with + composite characteristic is not implemented + sage: def my_factor(f): + ....: return f.change_ring(ZZ).factor() + sage: R.base_ring()._factor_univariate_polynomial = my_factor + sage: (x^2).factor() # needs sage.libs.pari x^2 - sage: del R.base_ring()._factor_univariate_polynomial # clean up + sage: del R.base_ring()._factor_univariate_polynomial # clean up Arbitrary precision real and complex factorization:: + sage: # needs sage.libs.pari sage.rings.real_mpfr sage: R.<x> = RealField(100)[] - sage: F = factor(x^2-3); F + sage: F = factor(x^2 - 3); F (x - 1.7320508075688772935274463415) * (x + 1.7320508075688772935274463415) sage: expand(F) x^2 - 3.0000000000000000000000000000 sage: factor(x^2 + 1) x^2 + 1.0000000000000000000000000000 + sage: # needs sage.libs.pari sage.rings.real_mpfr sage: R.<x> = ComplexField(100)[] - sage: F = factor(x^2+3); F + sage: F = factor(x^2 + 3); F (x - 1.7320508075688772935274463415*I) * (x + 1.7320508075688772935274463415*I) sage: expand(F) x^2 + 3.0000000000000000000000000000 - sage: factor(x^2+1) + sage: factor(x^2 + 1) (x - I) * (x + I) sage: f = R(I) * (x^2 + 1) ; f I*x^2 + I @@ -4120,28 +4216,33 @@ cdef class Polynomial(CommutativeAlgebraElement): Over a number field:: + sage: # needs sage.rings.number_field sage: K.<z> = CyclotomicField(15) sage: x = polygen(K) - sage: ((x^3 + z*x + 1)^3*(x - z)).factor() + sage: ((x^3 + z*x + 1)^3 * (x - z)).factor() (x - z) * (x^3 + z*x + 1)^3 sage: cyclotomic_polynomial(12).change_ring(K).factor() (x^2 - z^5 - 1) * (x^2 + z^5) - sage: ((x^3 + z*x + 1)^3*(x/(z+2) - 1/3)).factor() - (-1/331*z^7 + 3/331*z^6 - 6/331*z^5 + 11/331*z^4 - 21/331*z^3 + 41/331*z^2 - 82/331*z + 165/331) * (x - 1/3*z - 2/3) * (x^3 + z*x + 1)^3 + sage: ((x^3 + z*x + 1)^3 * (x/(z+2) - 1/3)).factor() + (-1/331*z^7 + 3/331*z^6 - 6/331*z^5 + 11/331*z^4 + - 21/331*z^3 + 41/331*z^2 - 82/331*z + 165/331) + * (x - 1/3*z - 2/3) * (x^3 + z*x + 1)^3 Over a relative number field:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) sage: K.<z> = CyclotomicField(3) sage: L.<a> = K.extension(x^3 - 2) sage: t = polygen(L, 't') - sage: f = (t^3 + t + a)*(t^5 + t + z); f + sage: f = (t^3 + t + a) * (t^5 + t + z); f t^8 + t^6 + a*t^5 + t^4 + z*t^3 + t^2 + (a + z)*t + z*a sage: f.factor() (t^3 + t + a) * (t^5 + t + z) Over the real double field:: + sage: # needs numpy sage: R.<x> = RDF[] sage: (-2*x^2 - 1).factor() (-2.0) * (x^2 + 0.5000000000000001) @@ -4155,70 +4256,95 @@ cdef class Polynomial(CommutativeAlgebraElement): :meth:`.roots` method, which does not detect that all the roots are real:: - sage: f.roots() # abs tol 2e-5 + sage: f.roots() # abs tol 2e-5 # needs numpy [(1.0000065719436413, 1)] Over the complex double field the factors are approximate and therefore occur with multiplicity 1:: + sage: # needs numpy sage.rings.complex_double sage: R.<x> = CDF[] sage: f = (x^2 + 2*R(I))^3 sage: F = f.factor() sage: F # abs tol 3e-5 - (x - 1.0000138879287663 + 1.0000013435286879*I) * (x - 0.9999942196864997 + 0.9999873009803959*I) * (x - 0.9999918923847313 + 1.0000113554909125*I) * (x + 0.9999908759550227 - 1.0000069659624138*I) * (x + 0.9999985293216753 - 0.9999886153831807*I) * (x + 1.0000105947233 - 1.0000044186544053*I) - sage: [f(t[0][0]).abs() for t in F] # abs tol 1e-13 - [1.979365054e-14, 1.97936298566e-14, 1.97936990747e-14, 3.6812407475e-14, 3.65211563729e-14, 3.65220890052e-14] + (x - 1.0000138879287663 + 1.0000013435286879*I) + * (x - 0.9999942196864997 + 0.9999873009803959*I) + * (x - 0.9999918923847313 + 1.0000113554909125*I) + * (x + 0.9999908759550227 - 1.0000069659624138*I) + * (x + 0.9999985293216753 - 0.9999886153831807*I) + * (x + 1.0000105947233 - 1.0000044186544053*I) + sage: [f(t[0][0]).abs() for t in F] # abs tol 1e-13 + [1.979365054e-14, 1.97936298566e-14, 1.97936990747e-14, + 3.6812407475e-14, 3.65211563729e-14, 3.65220890052e-14] Factoring polynomials over `\ZZ/n\ZZ` for composite `n` is not implemented:: sage: R.<x> = PolynomialRing(Integers(35)) - sage: f = (x^2+2*x+2)*(x^2+3*x+9) + sage: f = (x^2 + 2*x + 2) * (x^2 + 3*x + 9) sage: f.factor() Traceback (most recent call last): ... - NotImplementedError: factorization of polynomials over rings with composite characteristic is not implemented + NotImplementedError: factorization of polynomials over + rings with composite characteristic is not implemented Factoring polynomials over the algebraic numbers (see :trac:`8544`):: - sage: R.<x> = QQbar[] - sage: (x^8-1).factor() - (x - 1) * (x - 0.7071067811865475? - 0.7071067811865475?*I) * (x - 0.7071067811865475? + 0.7071067811865475?*I) * (x - I) * (x + I) * (x + 0.7071067811865475? - 0.7071067811865475?*I) * (x + 0.7071067811865475? + 0.7071067811865475?*I) * (x + 1) + sage: R.<x> = QQbar[] # needs sage.rings.number_field + sage: (x^8 - 1).factor() # needs sage.rings.number_field + (x - 1) * (x - 0.7071067811865475? - 0.7071067811865475?*I) + * (x - 0.7071067811865475? + 0.7071067811865475?*I) * (x - I) * (x + I) + * (x + 0.7071067811865475? - 0.7071067811865475?*I) + * (x + 0.7071067811865475? + 0.7071067811865475?*I) * (x + 1) Factoring polynomials over the algebraic reals (see :trac:`8544`):: - sage: R.<x> = AA[] - sage: (x^8+1).factor() - (x^2 - 1.847759065022574?*x + 1.000000000000000?) * (x^2 - 0.7653668647301795?*x + 1.000000000000000?) * (x^2 + 0.7653668647301795?*x + 1.000000000000000?) * (x^2 + 1.847759065022574?*x + 1.000000000000000?) + sage: R.<x> = AA[] # needs sage.rings.number_field + sage: (x^8 + 1).factor() # needs sage.rings.number_field + (x^2 - 1.847759065022574?*x + 1.000000000000000?) + * (x^2 - 0.7653668647301795?*x + 1.000000000000000?) + * (x^2 + 0.7653668647301795?*x + 1.000000000000000?) + * (x^2 + 1.847759065022574?*x + 1.000000000000000?) TESTS: This came up in :trac:`7088`:: - sage: R.<x>=PolynomialRing(ZZ) + sage: R.<x> = PolynomialRing(ZZ) sage: f = 12*x^10 + x^9 + 432*x^3 + 9011 sage: g = 13*x^11 + 89*x^3 + 1 sage: F = f^2 * g^3 - sage: F = f^2 * g^3; F.factor() + sage: F = f^2 * g^3; F.factor() # needs sage.libs.pari (12*x^10 + x^9 + 432*x^3 + 9011)^2 * (13*x^11 + 89*x^3 + 1)^3 - sage: F = f^2 * g^3 * 7; F.factor() + sage: F = f^2 * g^3 * 7; F.factor() # needs sage.libs.pari 7 * (12*x^10 + x^9 + 432*x^3 + 9011)^2 * (13*x^11 + 89*x^3 + 1)^3 This example came up in :trac:`7097`:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) sage: f = 8*x^9 + 42*x^6 + 6*x^3 - 1 - sage: g = x^24 - 12*x^23 + 72*x^22 - 286*x^21 + 849*x^20 - 2022*x^19 + 4034*x^18 - 6894*x^17 + 10182*x^16 - 13048*x^15 + 14532*x^14 - 13974*x^13 + 11365*x^12 - 7578*x^11 + 4038*x^10 - 1766*x^9 + 762*x^8 - 408*x^7 + 236*x^6 - 126*x^5 + 69*x^4 - 38*x^3 + 18*x^2 - 6*x + 1 - sage: assert g.is_irreducible() + sage: g = (x^24 - 12*x^23 + 72*x^22 - 286*x^21 + 849*x^20 - 2022*x^19 + 4034*x^18 + ....: - 6894*x^17 + 10182*x^16 - 13048*x^15 + 14532*x^14 - 13974*x^13 + ....: + 11365*x^12 - 7578*x^11 + 4038*x^10 - 1766*x^9 + 762*x^8 - 408*x^7 + ....: + 236*x^6 - 126*x^5 + 69*x^4 - 38*x^3 + 18*x^2 - 6*x + 1) + sage: assert g.is_irreducible() # needs sage.libs.pari sage: K.<a> = NumberField(g) sage: len(f.roots(K)) 9 - sage: f.factor() + sage: f.factor() # needs sage.libs.pari (8) * (x^3 + 1/4) * (x^6 + 5*x^3 - 1/2) sage: f.change_ring(K).factor() - (8) * (x - 3260097/3158212*a^22 + 35861067/3158212*a^21 - 197810817/3158212*a^20 + 722970825/3158212*a^19 - 1980508347/3158212*a^18 + 4374189477/3158212*a^17 - 4059860553/1579106*a^16 + 6442403031/1579106*a^15 - 17542341771/3158212*a^14 + 20537782665/3158212*a^13 - 20658463789/3158212*a^12 + 17502836649/3158212*a^11 - 11908953451/3158212*a^10 + 6086953981/3158212*a^9 - 559822335/789553*a^8 + 194545353/789553*a^7 - 505969453/3158212*a^6 + 338959407/3158212*a^5 - 155204647/3158212*a^4 + 79628015/3158212*a^3 - 57339525/3158212*a^2 + 26692783/3158212*a - 1636338/789553) * ... + (8) * (x - 3260097/3158212*a^22 + 35861067/3158212*a^21 - 197810817/3158212*a^20 + + 722970825/3158212*a^19 - 1980508347/3158212*a^18 + 4374189477/3158212*a^17 + - 4059860553/1579106*a^16 + 6442403031/1579106*a^15 - 17542341771/3158212*a^14 + + 20537782665/3158212*a^13 - 20658463789/3158212*a^12 + 17502836649/3158212*a^11 + - 11908953451/3158212*a^10 + 6086953981/3158212*a^9 - 559822335/789553*a^8 + + 194545353/789553*a^7 - 505969453/3158212*a^6 + 338959407/3158212*a^5 + - 155204647/3158212*a^4 + 79628015/3158212*a^3 - 57339525/3158212*a^2 + + 26692783/3158212*a - 1636338/789553) * ... sage: f = QQbar['x'](1) sage: f.factor() 1 @@ -4226,15 +4352,18 @@ cdef class Polynomial(CommutativeAlgebraElement): Factorization also works even if the variable of the finite field is nefariously labeled `x`:: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(3^2, 'x')[] - sage: f = x^10 +7*x -13 + sage: f = x^10 + 7*x - 13 sage: G = f.factor(); G - (x + x) * (x + 2*x + 1) * (x^4 + (x + 2)*x^3 + (2*x + 2)*x + 2) * (x^4 + 2*x*x^3 + (x + 1)*x + 2) + (x + x) * (x + 2*x + 1) * (x^4 + (x + 2)*x^3 + (2*x + 2)*x + 2) + * (x^4 + 2*x*x^3 + (x + 1)*x + 2) sage: prod(G) == f True :: + sage: # needs sage.rings.finite_rings sage: R.<x0> = GF(9,'x')[] # purposely calling it x to test robustness sage: f = x0^3 + x0 + 1 sage: f.factor() @@ -4247,12 +4376,13 @@ cdef class Polynomial(CommutativeAlgebraElement): :: - sage: f = x0^0 - sage: f.factor() + sage: f = x0^0 # needs sage.rings.finite_rings + sage: f.factor() # needs sage.rings.finite_rings 1 Over a complicated number field:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ, 'x') sage: f = x^6 + 10/7*x^5 - 867/49*x^4 - 76/245*x^3 + 3148/35*x^2 - 25944/245*x + 48771/1225 sage: K.<a> = NumberField(f) @@ -4263,30 +4393,29 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: len(F) 4 sage: F[:2] - [(T - a, 1), (T - 40085763200/924556084127*a^5 - 145475769880/924556084127*a^4 + 527617096480/924556084127*a^3 + 1289745809920/924556084127*a^2 - 3227142391585/924556084127*a - 401502691578/924556084127, 1)] + [(T - a, 1), + (T - 40085763200/924556084127*a^5 - 145475769880/924556084127*a^4 + + 527617096480/924556084127*a^3 + 1289745809920/924556084127*a^2 + - 3227142391585/924556084127*a - 401502691578/924556084127, 1)] sage: expand(F) T^6 + 10/7*T^5 - 867/49*T^4 - 76/245*T^3 + 3148/35*T^2 - 25944/245*T + 48771/1225 :: + sage: # needs sage.rings.number_field sage: f = x^2 - 1/3 sage: K.<a> = NumberField(f) sage: A.<T> = K[] sage: A(x^2 - 1).factor() (T - 1) * (T + 1) - - :: - sage: A(3*x^2 - 1).factor() (3) * (T - a) * (T + a) - - :: - sage: A(x^2 - 1/3).factor() (T - a) * (T + a) Test that :trac:`10279` is fixed:: + sage: # needs sage.rings.number_field sage: R.<t> = PolynomialRing(QQ) sage: K.<a> = NumberField(t^4 - t^2 + 1) sage: pol = t^3 + (-4*a^3 + 2*a)*t^2 - 11/3*a^2*t + 2/3*a^3 - 4/3*a @@ -4295,6 +4424,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Test that this factorization really uses ``nffactor()`` internally:: + sage: # needs sage.libs.pari sage.rings.number_field sage: pari.default("debug", 3) sage: F = pol.factor() <BLANKLINE> @@ -4304,25 +4434,53 @@ cdef class Polynomial(CommutativeAlgebraElement): Test that :trac:`10369` is fixed:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) sage: K.<a> = NumberField(x^6 + x^5 + x^4 + x^3 + x^2 + x + 1) sage: R.<t> = PolynomialRing(K) - - sage: pol = (-1/7*a^5 - 1/7*a^4 - 1/7*a^3 - 1/7*a^2 - 2/7*a - 1/7)*t^10 + (4/7*a^5 - 2/7*a^4 - 2/7*a^3 - 2/7*a^2 - 2/7*a - 6/7)*t^9 + (90/49*a^5 + 152/49*a^4 + 18/49*a^3 + 24/49*a^2 + 30/49*a + 36/49)*t^8 + (-10/49*a^5 + 10/7*a^4 + 198/49*a^3 - 102/49*a^2 - 60/49*a - 26/49)*t^7 + (40/49*a^5 + 45/49*a^4 + 60/49*a^3 + 277/49*a^2 - 204/49*a - 78/49)*t^6 + (90/49*a^5 + 110/49*a^4 + 2*a^3 + 80/49*a^2 + 46/7*a - 30/7)*t^5 + (30/7*a^5 + 260/49*a^4 + 250/49*a^3 + 232/49*a^2 + 32/7*a + 8)*t^4 + (-184/49*a^5 - 58/49*a^4 - 52/49*a^3 - 66/49*a^2 - 72/49*a - 72/49)*t^3 + (18/49*a^5 - 32/49*a^4 + 10/49*a^3 + 4/49*a^2)*t^2 + (2/49*a^4 - 4/49*a^3 + 2/49*a^2)*t + sage: pol = ((-1/7*a^5 - 1/7*a^4 - 1/7*a^3 - 1/7*a^2 - 2/7*a - 1/7)*t^10 + ....: + (4/7*a^5 - 2/7*a^4 - 2/7*a^3 - 2/7*a^2 - 2/7*a - 6/7)*t^9 + ....: + (90/49*a^5 + 152/49*a^4 + 18/49*a^3 + 24/49*a^2 + 30/49*a + 36/49)*t^8 + ....: + (-10/49*a^5 + 10/7*a^4 + 198/49*a^3 - 102/49*a^2 - 60/49*a - 26/49)*t^7 + ....: + (40/49*a^5 + 45/49*a^4 + 60/49*a^3 + 277/49*a^2 - 204/49*a - 78/49)*t^6 + ....: + (90/49*a^5 + 110/49*a^4 + 2*a^3 + 80/49*a^2 + 46/7*a - 30/7)*t^5 + ....: + (30/7*a^5 + 260/49*a^4 + 250/49*a^3 + 232/49*a^2 + 32/7*a + 8)*t^4 + ....: + (-184/49*a^5 - 58/49*a^4 - 52/49*a^3 - 66/49*a^2 - 72/49*a - 72/49)*t^3 + ....: + (18/49*a^5 - 32/49*a^4 + 10/49*a^3 + 4/49*a^2)*t^2 + ....: + (2/49*a^4 - 4/49*a^3 + 2/49*a^2)*t) sage: pol.factor() - (-1/7*a^5 - 1/7*a^4 - 1/7*a^3 - 1/7*a^2 - 2/7*a - 1/7) * t * (t - a^5 - a^4 - a^3 - a^2 - a - 1)^4 * (t^5 + (-12/7*a^5 - 10/7*a^4 - 8/7*a^3 - 6/7*a^2 - 4/7*a - 2/7)*t^4 + (12/7*a^5 - 8/7*a^3 + 16/7*a^2 + 2/7*a + 20/7)*t^3 + (-20/7*a^5 - 20/7*a^3 - 20/7*a^2 + 4/7*a - 2)*t^2 + (12/7*a^5 + 12/7*a^3 + 2/7*a + 16/7)*t - 4/7*a^5 - 4/7*a^3 - 4/7*a - 2/7) - - sage: pol = (1/7*a^2 - 1/7*a)*t^10 + (4/7*a - 6/7)*t^9 + (102/49*a^5 + 99/49*a^4 + 96/49*a^3 + 93/49*a^2 + 90/49*a + 150/49)*t^8 + (-160/49*a^5 - 36/49*a^4 - 48/49*a^3 - 8/7*a^2 - 60/49*a - 60/49)*t^7 + (30/49*a^5 - 55/49*a^4 + 20/49*a^3 + 5/49*a^2)*t^6 + (6/49*a^4 - 12/49*a^3 + 6/49*a^2)*t^5 + (-1/7*a^5 - 1/7*a^4 - 1/7*a^3 - 1/7*a^2 - 2/7*a - 1/7) * t + * (t - a^5 - a^4 - a^3 - a^2 - a - 1)^4 + * (t^5 + (-12/7*a^5 - 10/7*a^4 - 8/7*a^3 - 6/7*a^2 - 4/7*a - 2/7)*t^4 + + (12/7*a^5 - 8/7*a^3 + 16/7*a^2 + 2/7*a + 20/7)*t^3 + + (-20/7*a^5 - 20/7*a^3 - 20/7*a^2 + 4/7*a - 2)*t^2 + + (12/7*a^5 + 12/7*a^3 + 2/7*a + 16/7)*t + - 4/7*a^5 - 4/7*a^3 - 4/7*a - 2/7) + sage: pol = ((1/7*a^2 - 1/7*a)*t^10 + (4/7*a - 6/7)*t^9 + ....: + (102/49*a^5 + 99/49*a^4 + 96/49*a^3 + 93/49*a^2 + 90/49*a + 150/49)*t^8 + ....: + (-160/49*a^5 - 36/49*a^4 - 48/49*a^3 - 8/7*a^2 - 60/49*a - 60/49)*t^7 + ....: + (30/49*a^5 - 55/49*a^4 + 20/49*a^3 + 5/49*a^2)*t^6 + ....: + (6/49*a^4 - 12/49*a^3 + 6/49*a^2)*t^5) sage: pol.factor() - (1/7*a^2 - 1/7*a) * t^5 * (t^5 + (-40/7*a^5 - 38/7*a^4 - 36/7*a^3 - 34/7*a^2 - 32/7*a - 30/7)*t^4 + (60/7*a^5 - 30/7*a^4 - 18/7*a^3 - 9/7*a^2 - 3/7*a)*t^3 + (60/7*a^4 - 40/7*a^3 - 16/7*a^2 - 4/7*a)*t^2 + (30/7*a^3 - 25/7*a^2 - 5/7*a)*t + 6/7*a^2 - 6/7*a) - - sage: pol = x^10 + (4/7*a - 6/7)*x^9 + (9/49*a^2 - 3/7*a + 15/49)*x^8 + (8/343*a^3 - 32/343*a^2 + 40/343*a - 20/343)*x^7 + (5/2401*a^4 - 20/2401*a^3 + 40/2401*a^2 - 5/343*a + 15/2401)*x^6 + (-6/16807*a^4 + 12/16807*a^3 - 18/16807*a^2 + 12/16807*a - 6/16807)*x^5 + (1/7*a^2 - 1/7*a) * t^5 + * (t^5 + (-40/7*a^5 - 38/7*a^4 - 36/7*a^3 - 34/7*a^2 - 32/7*a - 30/7)*t^4 + + (60/7*a^5 - 30/7*a^4 - 18/7*a^3 - 9/7*a^2 - 3/7*a)*t^3 + + (60/7*a^4 - 40/7*a^3 - 16/7*a^2 - 4/7*a)*t^2 + + (30/7*a^3 - 25/7*a^2 - 5/7*a)*t + 6/7*a^2 - 6/7*a) + sage: pol = (x^10 + (4/7*a - 6/7)*x^9 + (9/49*a^2 - 3/7*a + 15/49)*x^8 + ....: + (8/343*a^3 - 32/343*a^2 + 40/343*a - 20/343)*x^7 + ....: + (5/2401*a^4 - 20/2401*a^3 + 40/2401*a^2 - 5/343*a + 15/2401)*x^6 + ....: + (-6/16807*a^4 + 12/16807*a^3 - 18/16807*a^2 + 12/16807*a - 6/16807)*x^5) sage: pol.factor() - x^5 * (x^5 + (4/7*a - 6/7)*x^4 + (9/49*a^2 - 3/7*a + 15/49)*x^3 + (8/343*a^3 - 32/343*a^2 + 40/343*a - 20/343)*x^2 + (5/2401*a^4 - 20/2401*a^3 + 40/2401*a^2 - 5/343*a + 15/2401)*x - 6/16807*a^4 + 12/16807*a^3 - 18/16807*a^2 + 12/16807*a - 6/16807) + x^5 * (x^5 + (4/7*a - 6/7)*x^4 + (9/49*a^2 - 3/7*a + 15/49)*x^3 + + (8/343*a^3 - 32/343*a^2 + 40/343*a - 20/343)*x^2 + + (5/2401*a^4 - 20/2401*a^3 + 40/2401*a^2 - 5/343*a + 15/2401)*x + - 6/16807*a^4 + 12/16807*a^3 - 18/16807*a^2 + 12/16807*a - 6/16807) Factoring over a number field over which we cannot factor the discriminant by trial division:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) sage: K.<a> = NumberField(x^16 - x - 6) sage: R.<x> = PolynomialRing(K) @@ -4337,6 +4495,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Factoring over a number field over which we cannot factor the discriminant and over which `nffactor()` fails:: + sage: # needs sage.libs.pari sage.rings.number_field sage: p = next_prime(10^50); q = next_prime(10^51); n = p*q sage: K.<a> = QuadraticField(p*q) sage: R.<x> = PolynomialRing(K) @@ -4344,13 +4503,14 @@ cdef class Polynomial(CommutativeAlgebraElement): Mat([x^2 + 1, 1]) sage: factor(x^2 + 1) x^2 + 1 - sage: factor( (x - a) * (x + 2*a) ) + sage: factor((x - a) * (x + 2*a)) (x - a) * (x + 2*a) A test where nffactor used to fail without a nf structure:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: K = NumberField([x^2-1099511627777, x^3-3],'a') + sage: K = NumberField([x^2 - 1099511627777, x^3 - 3], 'a') sage: x = polygen(K) sage: f = x^3 - 3 sage: factor(f) @@ -4361,7 +4521,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: L.<q> = LaurentPolynomialRing(QQ) sage: F = L.fraction_field() sage: R.<x> = PolynomialRing(F) - sage: factor(x) + sage: factor(x) # needs sage.libs.pari x sage: factor(x^2 - q^2) (x - q) * (x + q) @@ -4370,7 +4530,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: P.<a,b,c> = PolynomialRing(ZZ) sage: R.<x> = PolynomialRing(FractionField(P)) - sage: p = (x - a)*(b*x + c)*(a*b*x + a*c) / (a + 2) + sage: p = (x - a) * (b*x + c) * (a*b*x + a*c) / (a + 2) sage: factor(p) (a/(a + 2)) * (x - a) * (b*x + c)^2 @@ -4470,7 +4630,7 @@ cdef class Polynomial(CommutativeAlgebraElement): if not (ch == 0 or is_prime(ch)): raise NotImplementedError("factorization of polynomials over rings with composite characteristic is not implemented") - from sage.rings.finite_rings.finite_field_constructor import is_FiniteField + from sage.rings.finite_rings.finite_field_base import FiniteField n = None @@ -4480,7 +4640,7 @@ cdef class Polynomial(CommutativeAlgebraElement): except PariError: raise NotImplementedError - elif is_FiniteField(R): + elif isinstance(R, FiniteField): v = [x.__pari__("a") for x in self.list()] f = pari(v).Polrev() G = list(f.factor()) @@ -4533,7 +4693,8 @@ cdef class Polynomial(CommutativeAlgebraElement): TESTS:: - sage: R.<x>=PolynomialRing(ZZ) + sage: # needs sage.libs.pari + sage: R.<x> = PolynomialRing(ZZ) sage: f = (2*x + 1) * (3*x^2 - 5)^2 sage: f._factor_pari_helper(pari(f).factor()) (2*x + 1) * (3*x^2 - 5)^2 @@ -4548,6 +4709,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: QQ['x'](f)._factor_pari_helper(pari(f).factor(), unit=11) (198) * (x + 1/2) * (x^2 - 5/3)^2 + sage: # needs sage.libs.pari sage: f = prod((k^2*x^k + k)^(k-1) for k in primes(10)) sage: F = f._factor_pari_helper(pari(f).factor()); F 1323551250 * (2*x^2 + 1) * (3*x^3 + 1)^2 * (5*x^5 + 1)^4 * (7*x^7 + 1)^6 @@ -4556,9 +4718,12 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: QQ['x'](f)._factor_pari_helper(pari(f).factor()) (1751787911376562500) * (x^2 + 1/2) * (x^3 + 1/3)^2 * (x^5 + 1/5)^4 * (x^7 + 1/7)^6 + sage: # needs sage.libs.pari sage: g = GF(19)['x'](f) sage: G = g._factor_pari_helper(pari(g).factor()); G - (4) * (x + 3) * (x + 16)^5 * (x + 11)^6 * (x^2 + 7*x + 9)^4 * (x^2 + 15*x + 9)^4 * (x^3 + 13)^2 * (x^6 + 8*x^5 + 7*x^4 + 18*x^3 + 11*x^2 + 12*x + 1)^6 + (4) * (x + 3) * (x + 16)^5 * (x + 11)^6 * (x^2 + 7*x + 9)^4 + * (x^2 + 15*x + 9)^4 * (x^3 + 13)^2 + * (x^6 + 8*x^5 + 7*x^4 + 18*x^3 + 11*x^2 + 12*x + 1)^6 sage: G.prod() == g True """ @@ -4620,13 +4785,15 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: R.<x> = PolynomialRing(ZZ) - sage: K.<a> = (x^3 + 2).splitting_field(); K - Number Field in a with defining polynomial x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1 - sage: K.<a> = (x^3 - 3*x + 1).splitting_field(); K + sage: K.<a> = (x^3 + 2).splitting_field(); K # needs sage.rings.number_field + Number Field in a with defining polynomial + x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1 + sage: K.<a> = (x^3 - 3*x + 1).splitting_field(); K # needs sage.rings.number_field Number Field in a with defining polynomial x^3 - 3*x + 1 Relative situation:: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(x^3 + 2) sage: S.<t> = PolynomialRing(K) @@ -4637,8 +4804,8 @@ cdef class Polynomial(CommutativeAlgebraElement): With ``map=True``, we also get the embedding of the base field into the splitting field:: - sage: L.<b>, phi = (t^2 - a).splitting_field(map=True) - sage: phi + sage: L.<b>, phi = (t^2 - a).splitting_field(map=True) # needs sage.rings.number_field + sage: phi # needs sage.rings.number_field Ring morphism: From: Number Field in a with defining polynomial x^3 + 2 To: Number Field in b with defining polynomial t^6 + 2 @@ -4648,12 +4815,12 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: P.<x> = PolynomialRing(GF(7)) sage: t = x^2 + 1 - sage: t.splitting_field('b') + sage: t.splitting_field('b') # needs sage.rings.finite_rings Finite Field in b of size 7^2 - sage: P.<x> = PolynomialRing(GF(7^3, 'a')) + sage: P.<x> = PolynomialRing(GF(7^3, 'a')) # needs sage.rings.finite_rings sage: t = x^2 + 1 - sage: t.splitting_field('b', map=True) + sage: t.splitting_field('b', map=True) # needs sage.rings.finite_rings (Finite Field in b of size 7^6, Ring morphism: From: Finite Field in a of size 7^3 @@ -4664,12 +4831,12 @@ cdef class Polynomial(CommutativeAlgebraElement): name, the map will be the identity:: sage: t = 24*x^13 + 2*x^12 + 14 - sage: t.splitting_field('a', map=True) + sage: t.splitting_field('a', map=True) # needs sage.rings.finite_rings (Finite Field in a of size 7^3, Identity endomorphism of Finite Field in a of size 7^3) sage: t = x^56 - 14*x^3 - sage: t.splitting_field('b', map=True) + sage: t.splitting_field('b', map=True) # needs sage.rings.finite_rings (Finite Field in b of size 7^3, Ring morphism: From: Finite Field in a of size 7^3 @@ -4691,6 +4858,7 @@ cdef class Polynomial(CommutativeAlgebraElement): ... NotImplementedError: splitting_field() is only implemented over number fields and finite fields + sage: # needs sage.rings.finite_rings sage: P.<x> = PolynomialRing(GF(11^5, 'a')) sage: t = x^2 + 1 sage: t.splitting_field('b') @@ -4702,6 +4870,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: t.splitting_field('b') Finite Field in b of size 11^130 + sage: # needs sage.rings.finite_rings sage: P.<x> = PolynomialRing(GF(19^6, 'a')) sage: t = -x^6 + x^2 + 1 sage: t.splitting_field('b') @@ -4713,6 +4882,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: t.splitting_field('b') Finite Field in b of size 19^156 + sage: # needs sage.rings.finite_rings sage: P.<x> = PolynomialRing(GF(83^6, 'a')) sage: t = 2*x^14 - 5 + 6*x sage: t.splitting_field('b') @@ -4724,6 +4894,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: t.splitting_field('b') Finite Field in b of size 83^12 + sage: # needs sage.rings.finite_rings sage: P.<x> = PolynomialRing(GF(401^13, 'a')) sage: t = 2*x^14 - 5 + 6*x sage: t.splitting_field('b') @@ -4747,8 +4918,8 @@ cdef class Polynomial(CommutativeAlgebraElement): raise TypeError("You must specify the name of the generator.") name = normalize_names(1, names)[0] - from sage.rings.number_field.number_field_base import is_NumberField - from sage.rings.finite_rings.finite_field_base import is_FiniteField + from sage.rings.number_field.number_field_base import NumberField + from sage.rings.finite_rings.finite_field_base import FiniteField f = self.monic() # Given polynomial, made monic F = f.parent().base_ring() # Base field @@ -4756,10 +4927,10 @@ cdef class Polynomial(CommutativeAlgebraElement): F = F.fraction_field() f = self.change_ring(F) - if is_NumberField(F): + if isinstance(F, NumberField): from sage.rings.number_field.splitting_field import splitting_field return splitting_field(f, name, map, **kwds) - elif is_FiniteField(F): + elif isinstance(F, FiniteField): degree = lcm([f.degree() for f, _ in self.factor()]) return F.extension(degree, name, map=map, **kwds) @@ -4789,7 +4960,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = PolynomialRing(ZZ, sparse=True) sage: p = x^4 + 6*x^3 + x^2 - x + 2 sage: q = 2*x^2 - 3*x - 1 - sage: (quo,rem)=p.pseudo_quo_rem(q); quo,rem + sage: quo, rem = p.pseudo_quo_rem(q); quo, rem (4*x^2 + 30*x + 51, 175*x + 67) sage: 2^(4-2+1)*p == quo*q + rem True @@ -4797,9 +4968,10 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: S.<T> = R[] sage: p = (-3*x^2 - x)*T^3 - 3*x*T^2 + (x^2 - x)*T + 2*x^2 + 3*x - 2 sage: q = (-x^2 - 4*x - 5)*T^2 + (6*x^2 + x + 1)*T + 2*x^2 - x - sage: quo,rem=p.pseudo_quo_rem(q); quo,rem + sage: quo, rem = p.pseudo_quo_rem(q); quo, rem ((3*x^4 + 13*x^3 + 19*x^2 + 5*x)*T + 18*x^4 + 12*x^3 + 16*x^2 + 16*x, - (-113*x^6 - 106*x^5 - 133*x^4 - 101*x^3 - 42*x^2 - 41*x)*T - 34*x^6 + 13*x^5 + 54*x^4 + 126*x^3 + 134*x^2 - 5*x - 50) + (-113*x^6 - 106*x^5 - 133*x^4 - 101*x^3 - 42*x^2 - 41*x)*T + - 34*x^6 + 13*x^5 + 54*x^4 + 126*x^3 + 134*x^2 - 5*x - 50) sage: (-x^2 - 4*x - 5)^(3-2+1) * p == quo*q + rem True """ @@ -4845,7 +5017,7 @@ cdef class Polynomial(CommutativeAlgebraElement): The actual algorithm for computing greatest common divisors depends on the base ring underlying the polynomial ring. If the base ring - defines a method ``_gcd_univariate_polynomial``, then this method + defines a method :meth:`_gcd_univariate_polynomial`, then this method will be called (see examples below). EXAMPLES:: @@ -4861,6 +5033,7 @@ cdef class Polynomial(CommutativeAlgebraElement): One can easily add gcd functionality to new rings by providing a method ``_gcd_univariate_polynomial``:: + sage: # needs sage.rings.number_field sage.symbolic sage: O = ZZ[-sqrt(5)] sage: R.<x> = O[] sage: a = O.1 @@ -4869,9 +5042,11 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: p.gcd(q) Traceback (most recent call last): ... - NotImplementedError: Order in Number Field in a with defining polynomial x^2 - 5 with a = -2.236067977499790? does not provide a gcd implementation for univariate polynomials + NotImplementedError: Order in Number Field in a + with defining polynomial x^2 - 5 with a = -2.236067977499790? + does not provide a gcd implementation for univariate polynomials sage: S.<x> = O.number_field()[] - sage: O._gcd_univariate_polynomial = lambda f,g : R(S(f).gcd(S(g))) + sage: O._gcd_univariate_polynomial = lambda f, g: R(S(f).gcd(S(g))) sage: p.gcd(q) x + a sage: del O._gcd_univariate_polynomial @@ -4884,7 +5059,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: r = 2*x*y + z sage: p = r * (3*x*y*z - 1) sage: q = r * (x + y + z - 2) - sage: p.gcd(q) + sage: p.gcd(q) # needs sage.libs.singular z + 2*x*y sage: R.<x> = QQ[] @@ -4892,7 +5067,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: r = 2*x*y + 1 sage: p = r * (x - 1/2 * y) sage: q = r * (x*y^2 - x + 1/3) - sage: p.gcd(q) + sage: p.gcd(q) # needs sage.libs.singular 2*x*y + 1 TESTS:: @@ -4921,8 +5096,8 @@ cdef class Polynomial(CommutativeAlgebraElement): @coerce_binop def lcm(self, other): """ - Let f and g be two polynomials. Then this function returns the - monic least common multiple of f and g. + Let `f` and `g` be two polynomials. Then this function returns the + monic least common multiple of `f` and `g`. TESTS: @@ -4948,8 +5123,8 @@ cdef class Polynomial(CommutativeAlgebraElement): def _lcm(self, other): """ - Let f and g be two polynomials. Then this function returns the - monic least common multiple of f and g. + Let `f` and `g` be two polynomials. Then this function returns the + monic least common multiple of `f` and `g`. """ if self.is_zero() or other.is_zero(): P = self.parent() @@ -4972,7 +5147,7 @@ cdef class Polynomial(CommutativeAlgebraElement): - (ring theory) A polynomial over a ring is primitive if its coefficients generate the unit ideal. - Calling `is_primitive` on a polynomial over an infinite field will + Calling :meth:`is_primitive` on a polynomial over an infinite field will raise an error. The additional inputs to this function are to speed up computation for @@ -4980,115 +5155,118 @@ cdef class Polynomial(CommutativeAlgebraElement): INPUT: - - ``n`` (default: ``None``) - if provided, should equal - `q-1` where ``self.parent()`` is the field with `q` - elements; otherwise it will be computed. + - ``n`` (default: ``None``) - if provided, should equal + `q-1` where ``self.parent()`` is the field with `q` + elements; otherwise it will be computed. - - ``n_prime_divs`` (default: ``None``) - if provided, should - be a list of the prime divisors of ``n``; otherwise it - will be computed. + - ``n_prime_divs`` (default: ``None``) - if provided, should + be a list of the prime divisors of `n`; otherwise it + will be computed. .. NOTE:: - Computation of the prime divisors of ``n`` can dominate the running + Computation of the prime divisors of `n` can dominate the running time of this method, so performing this computation externally - (e.g. ``pdivs=n.prime_divisors()``) is a good idea for repeated calls - to is_primitive for polynomials of the same degree. + (e.g., ``pdivs = n.prime_divisors()``) is a good idea for repeated calls + to :meth:`is_primitive` for polynomials of the same degree. - Results may be incorrect if the wrong ``n`` and/or factorization are + Results may be incorrect if the wrong `n` and/or factorization are provided. - EXAMPLES:: + EXAMPLES: - Field semantics examples. + Field semantics examples. - :: + :: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(2)['x'] - sage: f = x^4+x^3+x^2+x+1 + sage: f = x^4 + x^3 + x^2 + x + 1 sage: f.is_irreducible(), f.is_primitive() (True, False) - sage: f = x^3+x+1 + sage: f = x^3 + x + 1 sage: f.is_irreducible(), f.is_primitive() (True, True) sage: R.<x> = GF(3)[] - sage: f = x^3-x+1 + sage: f = x^3 - x + 1 sage: f.is_irreducible(), f.is_primitive() (True, True) - sage: f = x^2+1 + sage: f = x^2 + 1 sage: f.is_irreducible(), f.is_primitive() (True, False) sage: R.<x> = GF(5)[] - sage: f = x^2+x+1 + sage: f = x^2 + x + 1 sage: f.is_primitive() False - sage: f = x^2-x+2 + sage: f = x^2 - x + 2 sage: f.is_primitive() True - sage: x=polygen(QQ); f=x^2+1 + sage: x = polygen(QQ); f = x^2 + 1 sage: f.is_primitive() Traceback (most recent call last): ... NotImplementedError: is_primitive() not defined for polynomials over infinite fields. - Ring semantics examples. + Ring semantics examples. - :: + :: - sage: x=polygen(ZZ) - sage: f = 5*x^2+2 + sage: x = polygen(ZZ) + sage: f = 5*x^2 + 2 sage: f.is_primitive() True - sage: f = 5*x^2+5 + sage: f = 5*x^2 + 5 sage: f.is_primitive() False - sage: K=NumberField(x^2+5,'a') - sage: R=K.ring_of_integers() - sage: a=R.gen(1) + sage: # needs sage.rings.number_field + sage: K = NumberField(x^2 + 5, 'a') + sage: R = K.ring_of_integers() + sage: a = R.gen(1) sage: a^2 -5 - sage: f=a*x+2 + sage: f = a*x + 2 sage: f.is_primitive() True - sage: f=(1+a)*x+2 + sage: f = (1+a)*x + 2 sage: f.is_primitive() False sage: x = polygen(Integers(10)) - sage: f = 5*x^2+2 + sage: f = 5*x^2 + 2 sage: #f.is_primitive() #BUG:: elsewhere in Sage, should return True - sage: f=4*x^2+2 + sage: f = 4*x^2 + 2 sage: #f.is_primitive() #BUG:: elsewhere in Sage, should return False TESTS:: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(2)['x'] - sage: f = x^4+x^3+x^2+x+1 + sage: f = x^4 + x^3 + x^2 + x + 1 sage: f.is_primitive(15) False sage: f.is_primitive(15, [3,5]) False sage: f.is_primitive(n_prime_divs=[3,5]) False - sage: f = x^3+x+1 + sage: f = x^3 + x + 1 sage: f.is_primitive(7, [7]) True sage: R.<x> = GF(3)[] - sage: f = x^3-x+1 + sage: f = x^3 - x + 1 sage: f.is_primitive(26, [2,13]) True - sage: f = x^2+1 + sage: f = x^2 + 1 sage: f.is_primitive(8, [2]) False sage: R.<x> = GF(5)[] - sage: f = x^2+x+1 + sage: f = x^2 + x + 1 sage: f.is_primitive(24, [2,3]) False - sage: f = x^2-x+2 + sage: f = x^2 - x + 2 sage: f.is_primitive(24, [2,3]) True - sage: x=polygen(Integers(103)); f=x^2+1 + sage: x = polygen(Integers(103)); f = x^2 + 1 sage: f.is_primitive() False """ @@ -5105,17 +5283,20 @@ cdef class Polynomial(CommutativeAlgebraElement): y = self._parent.quo(self).gen() from sage.groups.generic import order_from_multiple return n == order_from_multiple(y, n, n_prime_divs, operation="*") + elif isinstance(R, sage.rings.abc.Order): + K = R.number_field() + return K.fractional_ideal(self.coefficients()) == K.fractional_ideal(1) else: - return R.ideal(self.coefficients())==R.ideal(1) + return R.ideal(self.coefficients()) == R.ideal(1) def is_constant(self): """ - Return True if this is a constant polynomial. + Return ``True`` if this is a constant polynomial. OUTPUT: - - ``bool`` - True if and only if this polynomial is + - ``bool`` - ``True`` if and only if this polynomial is constant @@ -5133,14 +5314,14 @@ cdef class Polynomial(CommutativeAlgebraElement): def is_monomial(self): """ - Return True if self is a monomial, i.e., a power of the generator. + Return ``True`` if ``self`` is a monomial, i.e., a power of the generator. EXAMPLES:: sage: R.<x> = QQ[] sage: x.is_monomial() True - sage: (x+1).is_monomial() + sage: (x + 1).is_monomial() False sage: (x^2).is_monomial() True @@ -5152,15 +5333,15 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: (2*x^5).is_monomial() False - To allow a non-1 leading coefficient, use is_term():: + To allow a non-1 leading coefficient, use :meth:`is_term`:: sage: (2*x^5).is_term() True .. warning:: - The definition of is_monomial in Sage up to 4.7.1 was the - same as is_term, i.e., it allowed a coefficient not equal + The definition of :meth:`is_monomial` in Sage up to 4.7.1 was the + same as :meth:`is_term`, i.e., it allowed a coefficient not equal to 1. """ return len(self.exponents()) == 1 and self.leading_coefficient() == 1 @@ -5181,10 +5362,10 @@ cdef class Polynomial(CommutativeAlgebraElement): True sage: (3*x^5).is_term() True - sage: (1+3*x^5).is_term() + sage: (1 + 3*x^5).is_term() False - To require that the coefficient is 1, use :meth:`is_monomial()` + To require that the coefficient is 1, use :meth:`is_monomial` instead:: sage: (3*x^5).is_monomial() @@ -5195,7 +5376,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def root_field(self, names, check_irreducible=True): """ Return the field generated by the roots of the irreducible - polynomial self. The output is either a number field, relative + polynomial ``self``. The output is either a number field, relative number field, a quotient of a polynomial ring over a field, or the fraction field of the base ring. @@ -5203,27 +5384,28 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = QQ['x'] sage: f = x^3 + x + 17 - sage: f.root_field('a') + sage: f.root_field('a') # needs sage.rings.number_field Number Field in a with defining polynomial x^3 + x + 17 :: sage: R.<x> = QQ['x'] sage: f = x - 3 - sage: f.root_field('b') + sage: f.root_field('b') # needs sage.rings.number_field Rational Field :: sage: R.<x> = ZZ['x'] sage: f = x^3 + x + 17 - sage: f.root_field('b') + sage: f.root_field('b') # needs sage.rings.number_field Number Field in b with defining polynomial x^3 + x + 17 :: + sage: # needs sage.rings.number_field sage: y = QQ['x'].0 - sage: L.<a> = NumberField(y^3-2) + sage: L.<a> = NumberField(y^3 - 2) sage: R.<x> = L['x'] sage: f = x^3 + x + 17 sage: f.root_field('c') @@ -5231,10 +5413,12 @@ cdef class Polynomial(CommutativeAlgebraElement): :: - sage: R.<x> = PolynomialRing(GF(9,'a')) + sage: # needs sage.rings.finite_rings + sage: R.<x> = PolynomialRing(GF(9, 'a')) sage: f = x^3 + x^2 + 8 sage: K.<alpha> = f.root_field(); K - Univariate Quotient Polynomial Ring in alpha over Finite Field in a of size 3^2 with modulus x^3 + x^2 + 2 + Univariate Quotient Polynomial Ring in alpha + over Finite Field in a of size 3^2 with modulus x^3 + x^2 + 2 sage: alpha^2 + 1 alpha^2 + 1 sage: alpha^3 + alpha^2 @@ -5244,18 +5428,16 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = QQ[] sage: f = x^2 - sage: K.<alpha> = f.root_field() + sage: K.<alpha> = f.root_field() # needs sage.libs.pari Traceback (most recent call last): ... ValueError: polynomial must be irreducible TESTS:: - sage: (PolynomialRing(Integers(31),name='x').0+5).root_field('a') + sage: (PolynomialRing(Integers(31), name='x').0 + 5).root_field('a') # needs sage.rings.finite_rings Ring of integers modulo 31 """ - from sage.rings.number_field.number_field import is_NumberField, NumberField - R = self.base_ring() if not R.is_integral_domain(): raise ValueError("the base ring must be a domain") @@ -5266,34 +5448,39 @@ cdef class Polynomial(CommutativeAlgebraElement): if self.degree() <= 1: return R.fraction_field() + from sage.rings.number_field.number_field import is_NumberField, NumberField + if is_IntegerRing(R): + from sage.rings.number_field.number_field import NumberField return NumberField(self, names) - if sage.rings.rational_field.is_RationalField(R) or is_NumberField(R): + from sage.rings.number_field.number_field_base import NumberField as NumberField_base + + if sage.rings.rational_field.is_RationalField(R) or isinstance(R, NumberField_base): + from sage.rings.number_field.number_field import NumberField return NumberField(self, names) return R.fraction_field()[self._parent.variable_name()].quotient(self, names) def sylvester_matrix(self, right, variable = None): """ - Return the Sylvester matrix of self and right. + Return the Sylvester matrix of ``self`` and ``right``. Note that the Sylvester matrix is not defined if one of the polynomials is zero. INPUT: - - right: a polynomial in the same ring as self. - - variable: optional, included for compatibility with the multivariate + - ``right`` -- a polynomial in the same ring as ``self``. + - ``variable`` -- optional, included for compatibility with the multivariate case only. The variable of the polynomials. EXAMPLES:: sage: R.<x> = PolynomialRing(ZZ) - sage: f = (6*x + 47)*(7*x^2 - 2*x + 38) - sage: g = (6*x + 47)*(3*x^3 + 2*x + 1) - sage: M = f.sylvester_matrix(g) - sage: M + sage: f = (6*x + 47) * (7*x^2 - 2*x + 38) + sage: g = (6*x + 47) * (3*x^3 + 2*x + 1) + sage: M = f.sylvester_matrix(g); M # needs sage.modules [ 42 317 134 1786 0 0 0] [ 0 42 317 134 1786 0 0] [ 0 0 42 317 134 1786 0] @@ -5305,24 +5492,24 @@ cdef class Polynomial(CommutativeAlgebraElement): If the polynomials share a non-constant common factor then the determinant of the Sylvester matrix will be zero:: - sage: M.determinant() + sage: M.determinant() # needs sage.modules 0 - If self and right are polynomials of positive degree, the determinant + If ``self`` and ``right`` are polynomials of positive degree, the determinant of the Sylvester matrix is the resultant of the polynomials.:: sage: h1 = R._random_nonzero_element() sage: h2 = R._random_nonzero_element() - sage: M1 = h1.sylvester_matrix(h2) - sage: M1.determinant() == h1.resultant(h2) + sage: M1 = h1.sylvester_matrix(h2) # needs sage.modules + sage: M1.determinant() == h1.resultant(h2) # needs sage.libs.pari sage.modules True The rank of the Sylvester matrix is related to the degree of the - gcd of self and right:: + gcd of ``self`` and ``right``:: - sage: f.gcd(g).degree() == f.degree() + g.degree() - M.rank() + sage: f.gcd(g).degree() == f.degree() + g.degree() - M.rank() # needs sage.modules True - sage: h1.gcd(h2).degree() == h1.degree() + h2.degree() - M1.rank() + sage: h1.gcd(h2).degree() == h1.degree() + h2.degree() - M1.rank() # needs sage.modules True TESTS: @@ -5330,48 +5517,53 @@ cdef class Polynomial(CommutativeAlgebraElement): The variable is optional, but must be the same in both rings:: sage: K.<x> = QQ['x'] - sage: f = x+1 + sage: f = x + 1 sage: g = QQ['y']([1, 0, 1]) - sage: f.sylvester_matrix(f, x) + sage: f.sylvester_matrix(f, x) # needs sage.modules [1 1] [1 1] sage: f.sylvester_matrix(g, x) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Univariate Polynomial Ring in x over Rational Field' and 'Univariate Polynomial Ring in y over Rational Field' + TypeError: no common canonical parent for objects with parents: + 'Univariate Polynomial Ring in x over Rational Field' and + 'Univariate Polynomial Ring in y over Rational Field' Polynomials must be defined over compatible base rings:: sage: f = QQ['x']([1, 0, 1]) sage: g = ZZ['x']([1, 0, 1]) - sage: h = GF(25, 'a')['x']([1, 0, 1]) - sage: f.sylvester_matrix(g) + sage: h = GF(25, 'a')['x']([1, 0, 1]) # needs sage.rings.finite_rings + sage: f.sylvester_matrix(g) # needs sage.modules [1 0 1 0] [0 1 0 1] [1 0 1 0] [0 1 0 1] - sage: g.sylvester_matrix(h) + sage: g.sylvester_matrix(h) # needs sage.modules sage.rings.finite_rings [1 0 1 0] [0 1 0 1] [1 0 1 0] [0 1 0 1] - sage: f.sylvester_matrix(h) + sage: f.sylvester_matrix(h) # needs sage.modules sage.rings.finite_rings Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Univariate Polynomial Ring in x over Rational Field' and 'Univariate Polynomial Ring in x over Finite Field in a of size 5^2' + TypeError: no common canonical parent for objects with parents: + 'Univariate Polynomial Ring in x over Rational Field' and + 'Univariate Polynomial Ring in x over Finite Field in a of size 5^2' We can compute the sylvester matrix of a univariate and multivariate polynomial:: sage: K.<x,y> = QQ['x,y'] sage: g = K.random_element() - sage: f.sylvester_matrix(g) == K(f).sylvester_matrix(g,x) + sage: f.sylvester_matrix(g) == K(f).sylvester_matrix(g, x) # needs sage.modules True Corner cases:: - sage: K.<x>=QQ[] - sage: f = x^2+1 + sage: # needs sage.modules + sage: K.<x> = QQ[] + sage: f = x^2 + 1 sage: g = K(0) sage: f.sylvester_matrix(g) Traceback (most recent call last): @@ -5460,10 +5652,10 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: R.<w> = PolynomialRing(GF(9,'a'), sparse=True) - sage: a = w._new_constant_poly(0, R); a + sage: R.<w> = PolynomialRing(GF(9, 'a'), sparse=True) # needs sage.rings.finite_rings + sage: a = w._new_constant_poly(0, R); a # needs sage.rings.finite_rings 0 - sage: a.coefficients() + sage: a.coefficients() # needs sage.rings.finite_rings [] """ t = type(self) @@ -5471,7 +5663,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def is_monic(self): """ - Returns True if this polynomial is monic. The zero polynomial is by + Returns ``True`` if this polynomial is monic. The zero polynomial is by definition not monic. EXAMPLES:: @@ -5498,7 +5690,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def is_unit(self): r""" - Return True if this polynomial is a unit. + Return ``True`` if this polynomial is a unit. EXAMPLES:: @@ -5506,6 +5698,8 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: b = a(2*191*236607587) sage: b.is_nilpotent() True + + sage: # needs sage.libs.pari sage: R.<x> = a[] sage: f = 3 + b*x + b^2*x^2 sage: f.is_unit() @@ -5545,7 +5739,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def is_nilpotent(self): r""" - Return True if this polynomial is nilpotent. + Return ``True`` if this polynomial is nilpotent. EXAMPLES:: @@ -5580,7 +5774,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def is_gen(self): r""" - Return True if this polynomial is the distinguished generator of + Return ``True`` if this polynomial is the distinguished generator of the parent polynomial ring. EXAMPLES:: @@ -5591,8 +5785,8 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R(x).is_gen() True - Important - this function doesn't return True if self equals the - generator; it returns True if self *is* the generator. + Important - this function doesn't return ``True`` if ``self`` equals the + generator; it returns ``True`` if ``self`` *is* the generator. :: @@ -5612,7 +5806,8 @@ cdef class Polynomial(CommutativeAlgebraElement): Return the leading coefficient of this polynomial. OUTPUT: element of the base ring - This method is same as :meth:`leading_coefficient`. + + This method is the same as :meth:`leading_coefficient`. EXAMPLES:: @@ -5741,7 +5936,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: _.<x> = PolynomialRing(ZZ) - sage: f = x^4+2*x^2+1 + sage: f = x^4 + 2*x^2 + 1 sage: f.coefficients() [1, 2, 1] sage: f.coefficients(sparse=False) @@ -5763,38 +5958,37 @@ cdef class Polynomial(CommutativeAlgebraElement): INPUT: - ``prec`` -- desired floating point precision (default: - default RealField precision). - - OUTPUT: + default :class:`RealField` precision). - - a real number. + OUTPUT: a real number. EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) sage: f = 3*x^3 + 2*x^2 + x - sage: exp(f.global_height()) + sage: exp(f.global_height()) # needs sage.symbolic 3.00000000000000 Scaling should not change the result:: sage: R.<x> = PolynomialRing(QQ) sage: f = 1/25*x^2 + 25/3*x + 1 - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 6.43775164973640 sage: g = 100 * f - sage: g.global_height() + sage: g.global_height() # needs sage.symbolic 6.43775164973640 :: - sage: R.<x> = PolynomialRing(QQbar) - sage: f = QQbar(i)*x^2 + 3*x - sage: f.global_height() + sage: R.<x> = PolynomialRing(QQbar) # needs sage.rings.number_field + sage: f = QQbar(i)*x^2 + 3*x # needs sage.rings.number_field + sage: f.global_height() # needs sage.rings.number_field 1.09861228866811 :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) sage: K.<k> = NumberField(x^2 + 5) sage: T.<t> = PolynomialRing(K) @@ -5806,37 +6000,39 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = QQ[] sage: f = 1/123*x^2 + 12 - sage: f.global_height(prec=2) + sage: f.global_height(prec=2) # needs sage.symbolic 8.0 :: sage: R.<x> = QQ[] sage: f = 0*x - sage: f.global_height() + sage: f.global_height() # needs sage.rings.real_mpfr 0.000000000000000 """ if prec is None: prec = 53 if self.is_zero(): + from sage.rings.real_mpfr import RealField return RealField(prec).zero() - from sage.rings.qqbar import QQbar, number_field_elements_from_algebraics + from sage.categories.number_fields import NumberFields K = self.base_ring() - if K in NumberFields() or is_NumberFieldOrder(K): + if K in NumberFields() or isinstance(K, sage.rings.abc.Order) or is_IntegerRing(K): from sage.schemes.projective.projective_space import ProjectiveSpace P = ProjectiveSpace(K, self.number_of_terms()-1) return P.point(self.coefficients()).global_height(prec=prec) - elif K is QQbar: - K_pre, P, phi = number_field_elements_from_algebraics(self.coefficients()) + elif isinstance(K, sage.rings.abc.AlgebraicField): + from sage.rings.qqbar import number_field_elements_from_algebraics from sage.schemes.projective.projective_space import ProjectiveSpace + + K_pre, P, phi = number_field_elements_from_algebraics(self.coefficients()) Pr = ProjectiveSpace(K_pre, len(P)-1) return Pr.point(P).global_height(prec=prec) raise TypeError("Must be over a Numberfield or a Numberfield Order.") - def local_height(self, v, prec=None): """ Return the maximum of the local height of the coefficients of @@ -5847,21 +6043,20 @@ cdef class Polynomial(CommutativeAlgebraElement): - ``v`` -- a prime or prime ideal of the base ring. - ``prec`` -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). - OUTPUT: - - - a real number. + OUTPUT: a real number. EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) sage: f = 1/1331*x^2 + 1/4000*x - sage: f.local_height(1331) + sage: f.local_height(1331) # needs sage.rings.real_mpfr 7.19368581839511 :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: K.<k> = NumberField(x^2 - 5) sage: T.<t> = K[] @@ -5874,14 +6069,16 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = QQ[] sage: f = 1/2*x^2 + 2 - sage: f.local_height(2, prec=2) + sage: f.local_height(2, prec=2) # needs sage.rings.real_mpfr 0.75 """ + from sage.categories.number_fields import NumberFields + if prec is None: prec = 53 K = FractionField(self.base_ring()) - if K not in NumberFields() or is_NumberFieldOrder(K): + if not (K in NumberFields() or isinstance(K, sage.rings.abc.Order) or is_IntegerRing(K)): raise TypeError("must be over a Numberfield or a Numberfield order") return max([K(c).local_height(v, prec=prec) for c in self.coefficients()]) @@ -5896,21 +6093,20 @@ cdef class Polynomial(CommutativeAlgebraElement): - ``i`` -- an integer. - ``prec`` -- desired floating point precision (default: - default RealField precision). - - OUTPUT: + default :class:`RealField` precision). - - a real number. + OUTPUT: a real number. EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) sage: f = 210*x^2 - sage: f.local_height_arch(0) + sage: f.local_height_arch(0) # needs sage.rings.real_mpfr 5.34710753071747 :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: K.<k> = NumberField(x^2 - 5) sage: T.<t> = K[] @@ -5922,14 +6118,16 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = QQ[] sage: f = 1/2*x^2 + 3 - sage: f.local_height_arch(0, prec=2) + sage: f.local_height_arch(0, prec=2) # needs sage.rings.real_mpfr 1.0 """ + from sage.categories.number_fields import NumberFields + if prec is None: prec = 53 K = FractionField(self.base_ring()) - if K not in NumberFields() or is_NumberFieldOrder(K): + if not (K in NumberFields() or isinstance(K, sage.rings.abc.Order) or is_IntegerRing(K)): return TypeError("must be over a Numberfield or a Numberfield Order") if K == QQ: @@ -5943,7 +6141,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: _.<x> = PolynomialRing(ZZ) - sage: f = x^4+2*x^2+1 + sage: f = x^4 + 2*x^2 + 1 sage: f.exponents() [0, 2, 4] @@ -5967,7 +6165,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: v = f.list(); v [-1/3, 2, 0, -2/5] - Note that v is a list, it is mutable, and each call to the list + Note that ``v`` is a list, it is mutable, and each call to the :meth:`list` method returns a new list:: sage: type(v) @@ -5980,7 +6178,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = QQ[] sage: S.<y> = R[] - sage: f = y^3 + x*y -3*x; f + sage: f = y^3 + x*y - 3*x; f y^3 + x*y - 3*x sage: type(f) <class 'sage.rings.polynomial.polynomial_element.Polynomial_generic_dense'> @@ -6010,7 +6208,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def padded_list(self, n=None): """ - Return list of coefficients of self up to (but not including) + Return list of coefficients of ``self`` up to (but not including) `q^n`. Includes 0's in the list on the right so that the list has length @@ -6070,15 +6268,11 @@ cdef class Polynomial(CommutativeAlgebraElement): - ``m`` - a monomial - OUTPUT: - - Coefficient in base ring. + OUTPUT: Coefficient in base ring. EXAMPLES:: sage: P.<x> = QQ[] - - The parent of the return is a member of the base ring. sage: f = 2 * x sage: c = f.monomial_coefficient(x); c 2 @@ -6129,10 +6323,12 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: f = - 1/2*x^2 + x^9 + 7*x + 5/11 sage: f.monomials() [x^9, x^2, x, 1] - sage: x = var('x') + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<rho> = NumberField(x**2 + 1) sage: R.<y> = QQ[] - sage: p = rho*y + sage: p = rho * y sage: p.monomials() [y] """ @@ -6149,28 +6345,28 @@ cdef class Polynomial(CommutativeAlgebraElement): polynomial, computed using the Newton-Raphson method. The Newton-Raphson method is an iterative root-finding algorithm. - For f(x) a polynomial, as is the case here, this is essentially the + For `f(x)` a polynomial, as is the case here, this is essentially the same as Horner's method. INPUT: - - ``n`` - an integer (=the number of iterations), + - ``n`` - an integer (the number of iterations), - - ``x0`` - an initial guess x0. + - ``x0`` - an initial guess `x_0`. OUTPUT: A list of numbers hopefully approximating a root of - f(x)=0. + `f(x)=0`. - If one of the iterates is a critical point of f then a - ZeroDivisionError exception is raised. + If one of the iterates is a critical point of `f`, a + :class:`ZeroDivisionError` exception is raised. EXAMPLES:: - sage: x = PolynomialRing(RealField(), 'x').gen() - sage: f = x^2 - 2 - sage: f.newton_raphson(4, 1) + sage: x = PolynomialRing(RealField(), 'x').gen() # needs sage.rings.real_mpfr + sage: f = x^2 - 2 # needs sage.rings.real_mpfr + sage: f.newton_raphson(4, 1) # needs sage.rings.real_mpfr [1.50000000000000, 1.41666666666667, 1.41421568627451, 1.41421356237469] AUTHORS: @@ -6189,17 +6385,17 @@ cdef class Polynomial(CommutativeAlgebraElement): def polynomial(self, var): r""" - Let var be one of the variables of the parent of self. This returns - self viewed as a univariate polynomial in var over the polynomial + Let ``var`` be one of the variables of the parent of ``self``. This returns + ``self`` viewed as a univariate polynomial in ``var`` over the polynomial ring generated by all the other variables of the parent. - For univariate polynomials, if var is the generator of the parent + For univariate polynomials, if ``var`` is the generator of the parent ring, we return this polynomial, otherwise raise an error. EXAMPLES:: sage: R.<x> = QQ[] - sage: (x+1).polynomial(x) + sage: (x + 1).polynomial(x) x + 1 TESTS:: @@ -6217,31 +6413,31 @@ cdef class Polynomial(CommutativeAlgebraElement): def newton_slopes(self, p, lengths=False): """ - Return the `p`-adic slopes of the Newton polygon of self, + Return the `p`-adic slopes of the Newton polygon of ``self``, when this makes sense. OUTPUT: - If `lengths` is `False`, a list of rational numbers. If `lengths` is - `True`, a list of couples `(s,l)` where `s` is the slope and `l` the + If ``lengths`` is ``False``, a list of rational numbers. If ``lengths`` is + ``True``, a list of couples `(s,l)` where `s` is the slope and `l` the length of the corresponding segment in the Newton polygon. EXAMPLES:: sage: x = QQ['x'].0 sage: f = x^3 + 2 - sage: f.newton_slopes(2) + sage: f.newton_slopes(2) # needs sage.libs.pari [1/3, 1/3, 1/3] sage: R.<x> = PolynomialRing(ZZ, sparse=True) sage: p = x^5 + 6*x^2 + 4 - sage: p.newton_slopes(2) + sage: p.newton_slopes(2) # needs sage.libs.pari [1/2, 1/2, 1/3, 1/3, 1/3] sage: p.newton_slopes(2, lengths=True) [(1/2, 2), (1/3, 3)] sage: (x^2^100 + 27).newton_slopes(3, lengths=True) [(3/1267650600228229401496703205376, 1267650600228229401496703205376)] - ALGORITHM: Uses PARI if `lengths` is `False`. + ALGORITHM: Uses PARI if ``lengths`` is ``False``. """ if not lengths: f = self.__pari__() @@ -6291,13 +6487,13 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: Pol.<x> = QQ[] - sage: x.dispersion_set(x + 1) + sage: x.dispersion_set(x + 1) # needs sage.libs.pari [1] - sage: (x + 1).dispersion_set(x) + sage: (x + 1).dispersion_set(x) # needs sage.libs.pari [] sage: pol = x^3 + x - 7 - sage: (pol*pol(x+3)^2).dispersion_set() + sage: (pol*pol(x+3)^2).dispersion_set() # needs sage.libs.pari [0, 3] """ other = self if other is None else self._parent.coerce(other) @@ -6338,11 +6534,12 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: Pol.<x> = QQ[] - sage: x.dispersion(x + 1) + sage: x.dispersion(x + 1) # needs sage.libs.pari 1 - sage: (x + 1).dispersion(x) + sage: (x + 1).dispersion(x) # needs sage.libs.pari -Infinity + sage: # needs sage.libs.pari sage.rings.number_field sage.symbolic sage: Pol.<x> = QQbar[] sage: pol = Pol([sqrt(5), 1, 3/2]) sage: pol.dispersion() @@ -6368,7 +6565,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: f = QQ['x']([0,1,2/3,3]) - sage: pari(f) + sage: pari(f) # needs sage.libs.pari 3*x^3 + 2/3*x^2 + x :: @@ -6376,19 +6573,21 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: S.<a> = QQ['a'] sage: R.<x> = S['x'] sage: f = R([0, a]) + R([0, 0, 2/3]) - sage: pari(f) + sage: pari(f) # needs sage.libs.pari 2/3*x^2 + a*x Polynomials over a number field work, provided that the variable is called 'x':: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) sage: K.<b> = NumberField(x^2 + x + 1) sage: R.<x> = PolynomialRing(K) sage: pol = (b + x)^3; pol x^3 + 3*b*x^2 + (-3*b - 3)*x + 1 - sage: pari(pol) - Mod(1, y^2 + y + 1)*x^3 + Mod(3*y, y^2 + y + 1)*x^2 + Mod(-3*y - 3, y^2 + y + 1)*x + Mod(1, y^2 + y + 1) + sage: pari(pol) # needs sage.libs.pari + Mod(1, y^2 + y + 1)*x^3 + Mod(3*y, y^2 + y + 1)*x^2 + + Mod(-3*y - 3, y^2 + y + 1)*x + Mod(1, y^2 + y + 1) TESTS: @@ -6397,7 +6596,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x, y> = QQ[] sage: S.<a> = R[] sage: f = x^2 + a; g = y^3 + a - sage: pari(f) + sage: pari(f) # needs sage.libs.pari Traceback (most recent call last): ... PariError: incorrect priority in gtopoly: variable x <= a @@ -6407,9 +6606,9 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: S.<a> = QQ['a'] sage: R.<x> = S['x'] - sage: pari(x^2 + 2*x) + sage: pari(x^2 + 2*x) # needs sage.libs.pari x^2 + 2*x - sage: pari(a*x + 2*x^3) + sage: pari(a*x + 2*x^3) # needs sage.libs.pari 2*x^3 + a*x Stacked polynomial rings, second with a multivariate ring on the @@ -6417,27 +6616,27 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: S.<a, b> = ZZ['a', 'b'] sage: R.<x> = S['x'] - sage: pari(x^2 + 2*x) + sage: pari(x^2 + 2*x) # needs sage.libs.pari x^2 + 2*x - sage: pari(a*x + 2*b*x^3) + sage: pari(a*x + 2*b*x^3) # needs sage.libs.pari 2*b*x^3 + a*x Stacked polynomial rings with exotic base rings:: sage: S.<a, b> = GF(7)['a', 'b'] sage: R.<x> = S['x'] - sage: pari(x^2 + 9*x) + sage: pari(x^2 + 9*x) # needs sage.libs.pari x^2 + 2*x - sage: pari(a*x + 9*b*x^3) + sage: pari(a*x + 9*b*x^3) # needs sage.libs.pari 2*b*x^3 + a*x :: sage: S.<a> = Integers(8)['a'] sage: R.<x> = S['x'] - sage: pari(x^2 + 2*x) + sage: pari(x^2 + 2*x) # needs sage.libs.pari Mod(1, 8)*x^2 + Mod(2, 8)*x - sage: pari(a*x + 10*x^3) + sage: pari(a*x + 10*x^3) # needs sage.libs.pari Mod(2, 8)*x^3 + Mod(1, 8)*a*x """ return self._pari_with_name(self._parent.variable_name()) @@ -6456,6 +6655,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: R.<x> = PolynomialRing(ZZ) sage: pol = 2*x^2 + 7*x - 5 sage: pol._pari_or_constant() @@ -6488,9 +6688,9 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: R.<a> = PolynomialRing(ZZ) - sage: (2*a^2 + a)._pari_with_name() + sage: (2*a^2 + a)._pari_with_name() # needs sage.libs.pari 2*x^2 + x - sage: (2*a^2 + a)._pari_with_name('y') + sage: (2*a^2 + a)._pari_with_name('y') # needs sage.libs.pari 2*y^2 + y """ vals = [x.__pari__() for x in self.list()] @@ -6505,12 +6705,13 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: + sage: # optional - magma sage: magma = Magma() # new session sage: R.<y> = ZZ[] sage: f = y^3 - 17*y + 5 - sage: f._magma_init_(magma) # optional - magma + sage: f._magma_init_(magma) '_sage_[...]![5,-17,0,1]' - sage: g = magma(f); g # optional - magma + sage: g = magma(f); g y^3 - 17*y + 5 Note that in Magma there is only one polynomial ring over each @@ -6519,20 +6720,21 @@ cdef class Polynomial(CommutativeAlgebraElement): we already defined:: sage: R.<z> = ZZ[] - sage: magma(R) # optional - magma + sage: magma(R) # optional - magma Univariate Polynomial Ring in z over Integer Ring - sage: g # optional - magma + sage: g # optional - magma z^3 - 17*z + 5 In Sage the variable name does not change:: - sage: f + sage: f # optional - magma y^3 - 17*y + 5 A more complicated nested example:: + sage: # optional - magma, needs sage.rings.finite_rings sage: k.<a> = GF(9); R.<s,t> = k[]; S.<W> = R[] - sage: magma(a*W^20 + s*t/a) # optional - magma + sage: magma(a*W^20 + s*t/a) a*W^20 + a^7*s*t """ # Get a reference to Magma version of parent. @@ -6551,6 +6753,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: + sage: # needs sage.libs.gap sage: R.<y> = ZZ[] sage: f = y^3 - 17*y + 5 sage: g = gap(f); g # indirect doctest @@ -6569,6 +6772,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Coefficients in a finite field:: + sage: # needs sage.libs.gap sage: R.<y> = GF(7)[] sage: f = y^3 - 17*y + 5 sage: g = gap(f); g @@ -6591,9 +6795,9 @@ cdef class Polynomial(CommutativeAlgebraElement): TESTS:: sage: R.<x> = ZZ[] - sage: libgap(-x^3 + 3*x) # indirect doctest + sage: libgap(-x^3 + 3*x) # indirect doctest # needs sage.libs.gap -x^3+3*x - sage: libgap(R.zero()) # indirect doctest + sage: libgap(R.zero()) # indirect doctest # needs sage.libs.gap 0 """ from sage.libs.gap.libgap import libgap @@ -6605,6 +6809,7 @@ cdef class Polynomial(CommutativeAlgebraElement): TESTS:: + sage: # needs sage.libs.giac sage: R.<x> = GF(101)['e,i'][] sage: f = R('e*i') * x + x^2 sage: f._giac_init_() @@ -6634,7 +6839,7 @@ cdef class Polynomial(CommutativeAlgebraElement): ALGORITHM: - Uses PARI's ``polresultant`` function. For base rings that + Uses PARI's function :pari:`polresultant`. For base rings that are not supported by PARI, the resultant is computed as the determinant of the Sylvester matrix. @@ -6642,9 +6847,9 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = QQ[] sage: f = x^3 + x + 1; g = x^3 - x - 1 - sage: r = f.resultant(g); r + sage: r = f.resultant(g); r # needs sage.libs.pari -8 - sage: r.parent() is QQ + sage: r.parent() is QQ # needs sage.libs.pari True We can compute resultants over univariate and multivariate @@ -6653,9 +6858,9 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<a> = QQ[] sage: S.<x> = R[] sage: f = x^2 + a; g = x^3 + a - sage: r = f.resultant(g); r + sage: r = f.resultant(g); r # needs sage.libs.pari a^3 + a^2 - sage: r.parent() is R + sage: r.parent() is R # needs sage.libs.pari True :: @@ -6663,9 +6868,9 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<a, b> = QQ[] sage: S.<x> = R[] sage: f = x^2 + a; g = x^3 + b - sage: r = f.resultant(g); r + sage: r = f.resultant(g); r # needs sage.libs.pari a^3 + b^2 - sage: r.parent() is R + sage: r.parent() is R # needs sage.libs.pari True TESTS:: @@ -6673,9 +6878,9 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x, y> = QQ[] sage: S.<a> = R[] sage: f = x^2 + a; g = y^3 + a - sage: h = f.resultant(g); h + sage: h = f.resultant(g); h # needs sage.libs.pari y^3 - x^2 - sage: h.parent() is R + sage: h.parent() is R # needs sage.libs.pari True Check that :trac:`13672` is fixed:: @@ -6684,7 +6889,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: S.<x> = R[] sage: f = (t^2 + t)*x + t^2 + t sage: g = (t + 1)*x + t^2 - sage: f.resultant(g) + sage: f.resultant(g) # needs sage.libs.pari t^4 + t Check that :trac:`15061` is fixed:: @@ -6693,23 +6898,24 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: F = R([1,1],2) sage: RP.<x> = PolynomialRing(R) sage: P = x^2 - F - sage: P.resultant(P.derivative()) + sage: P.resultant(P.derivative()) # needs sage.libs.pari -4 - 4*T + O(T^2) Check that :trac:`16360` is fixed:: sage: K.<x> = FunctionField(QQ) sage: R.<y> = K[] - sage: y.resultant(y+x) + sage: y.resultant(y + x) # needs sage.libs.pari x + sage: # needs sage.libs.singular sage: K.<a> = FunctionField(QQ) sage: R.<b> = K[] - sage: L.<b> = K.extension(b^2-a) + sage: L.<b> = K.extension(b^2 - a) sage: R.<x> = L[] - sage: f=x^2-a - sage: g=x-b - sage: f.resultant(g) + sage: f = x^2 - a + sage: g = x - b + sage: f.resultant(g) # needs sage.libs.pari 0 Check that :trac:`17817` is fixed:: @@ -6720,12 +6926,15 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: S.<y> = PolynomialRing(R,'y') sage: p = ((1/b^2*d^2+1/a)*x*y^2+a*b/c*y+e+x^2) sage: q = -4*c^2*y^3+1 - sage: p.resultant(q) - (16*c^4)*x^6 + (48*c^4)*e*x^4 + (1/(b^6)*d^6 + 3/(a*b^4)*d^4 + (-12*a^3*b*c + 3)/(a^2*b^2)*d^2 + (-12*a^3*b*c + 1)/(a^3))*x^3 + (48*c^4)*e^2*x^2 + ((-12*a*c)/b*d^2*e + (-12*b*c)*e)*x + (16*c^4)*e^3 + (4*a^3*b^3)/c + sage: p.resultant(q) # needs sage.libs.pari + (16*c^4)*x^6 + (48*c^4)*e*x^4 + (1/(b^6)*d^6 + 3/(a*b^4)*d^4 + + (-12*a^3*b*c + 3)/(a^2*b^2)*d^2 + (-12*a^3*b*c + 1)/(a^3))*x^3 + + (48*c^4)*e^2*x^2 + ((-12*a*c)/b*d^2*e + (-12*b*c)*e)*x + (16*c^4)*e^3 + (4*a^3*b^3)/c Test for :trac:`10978`:: + sage: # needs sage.libs.pari sage.rings.complex_double sage.symbolic sage: R.<x> = PolynomialRing(CDF) sage: f = R(1 - I*x + (0.5)*x^2 + (1.7)*x^3) sage: g = f.derivative() @@ -6753,8 +6962,8 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: R.<x> = ZZ[] - sage: f = x^8 + x^6 -3*x^4 -3*x^3 +8*x^2 +2*x -5 - sage: g = 3*x^6 +5*x^4 -4*x^2 -9*x +21 + sage: f = x^8 + x^6 - 3*x^4 - 3*x^3 + 8*x^2 + 2*x - 5 + sage: g = 3*x^6 + 5*x^4 - 4*x^2 - 9*x + 21 sage: f.subresultants(g) [260708, 9326*x - 12300, @@ -6832,8 +7041,8 @@ cdef class Polynomial(CommutativeAlgebraElement): where the roots `a` and `b` are to be considered in the algebraic closure of the fraction field of the coefficients and counted with multiplicities. If the polynomials are not monic this quantity is - multiplied by `\\alpha_1^{deg(p_2)} \\alpha_2^{deg(p_1)}` where - `\\alpha_1` and `\\alpha_2` are the leading coefficients of `p_1` and + multiplied by `\alpha_1^{\deg(p_2)} \alpha_2^{\deg(p_1)}` where + `\alpha_1` and `\alpha_2` are the leading coefficients of `p_1` and `p_2` respectively. INPUT: @@ -6844,7 +7053,7 @@ cdef class Polynomial(CommutativeAlgebraElement): - ``op`` -- ``operator.OP`` where ``OP=add`` or ``sub`` or ``mul`` or ``truediv``. - - ``algorithm`` -- can be "resultant" or "BFSS"; + - ``algorithm`` -- can be ``"resultant"`` or ``"BFSS"``; by default the former is used when the polynomials have few nonzero coefficients and small degrees or if the base ring is not `\ZZ` or `\QQ`. Otherwise the latter is used. @@ -6856,7 +7065,7 @@ cdef class Polynomial(CommutativeAlgebraElement): ALGORITHM: The computation is straightforward using resultants. Indeed for the - composed sum it would be `Res_y(p1(x-y), p2(y))`. However, the method + composed sum it would be `Res_y(p_1(x-y), p_2(y))`. However, the method from [BFSS2006]_ using series expansions is asymptotically much faster. Note that the algorithm ``BFSS`` with polynomials with coefficients in @@ -6879,48 +7088,47 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: x = polygen(ZZ) sage: p1 = x^2 - 1 sage: p2 = x^4 - 1 - sage: p1.composed_op(p2, operator.add) + sage: p1.composed_op(p2, operator.add) # needs sage.libs.singular x^8 - 4*x^6 + 4*x^4 - 16*x^2 - sage: p1.composed_op(p2, operator.mul) + sage: p1.composed_op(p2, operator.mul) # needs sage.libs.singular x^8 - 2*x^4 + 1 - sage: p1.composed_op(p2, operator.truediv) + sage: p1.composed_op(p2, operator.truediv) # needs sage.libs.singular x^8 - 2*x^4 + 1 This function works over any field. However for base rings other than `\ZZ` and `\QQ` only the resultant algorithm is available:: + sage: # needs sage.rings.number_field sage: x = polygen(QQbar) sage: p1 = x**2 - AA(2).sqrt() sage: p2 = x**3 - AA(3).sqrt() sage: r1 = p1.roots(multiplicities=False) sage: r2 = p2.roots(multiplicities=False) - sage: p = p1.composed_op(p2, operator.add) - sage: p - x^6 - 4.242640687119285?*x^4 - 3.464101615137755?*x^3 + 6*x^2 - 14.69693845669907?*x + 0.1715728752538099? + sage: p = p1.composed_op(p2, operator.add); p + x^6 - 4.242640687119285?*x^4 - 3.464101615137755?*x^3 + 6*x^2 + - 14.69693845669907?*x + 0.1715728752538099? sage: all(p(x+y).is_zero() for x in r1 for y in r2) True sage: x = polygen(GF(2)) sage: p1 = x**2 + x - 1 sage: p2 = x**3 + x - 1 - sage: p_add = p1.composed_op(p2, operator.add) - sage: p_add + sage: p_add = p1.composed_op(p2, operator.add); p_add # needs sage.libs.singular x^6 + x^5 + x^3 + x^2 + 1 - sage: p_mul = p1.composed_op(p2, operator.mul) - sage: p_mul + sage: p_mul = p1.composed_op(p2, operator.mul); p_mul # needs sage.libs.singular x^6 + x^4 + x^2 + x + 1 - sage: p_div = p1.composed_op(p2, operator.truediv) - sage: p_div + sage: p_div = p1.composed_op(p2, operator.truediv); p_div # needs sage.libs.singular x^6 + x^5 + x^4 + x^2 + 1 + sage: # needs sage.rings.finite_rings sage: K = GF(2**6, 'a') sage: r1 = p1.roots(K, multiplicities=False) sage: r2 = p2.roots(K, multiplicities=False) - sage: all(p_add(x1+x2).is_zero() for x1 in r1 for x2 in r2) + sage: all(p_add(x1+x2).is_zero() for x1 in r1 for x2 in r2) # needs sage.libs.singular True - sage: all(p_mul(x1*x2).is_zero() for x1 in r1 for x2 in r2) + sage: all(p_mul(x1*x2).is_zero() for x1 in r1 for x2 in r2) # needs sage.libs.singular True - sage: all(p_div(x1/x2).is_zero() for x1 in r1 for x2 in r2) + sage: all(p_div(x1/x2).is_zero() for x1 in r1 for x2 in r2) # needs sage.libs.singular True TESTS: @@ -6928,7 +7136,7 @@ cdef class Polynomial(CommutativeAlgebraElement): :: sage: y = polygen(ZZ) - sage: for p1 in [2*y^3 - y + 3, -y^5 - 2, 4*y - 3]: + sage: for p1 in [2*y^3 - y + 3, -y^5 - 2, 4*y - 3]: # needs sage.libs.singular ....: for p2 in [5*y^2 - 7, -3*y - 1]: ....: for monic in [True,False]: ....: for op in [operator.add, operator.sub, operator.mul, operator.truediv]: @@ -7069,28 +7277,29 @@ cdef class Polynomial(CommutativeAlgebraElement): The polynomial of degree `d^k` where `d` is the degree, whose roots are all `k`-fold products of roots of this polynomial. That is, `f*f*\dots*f` where this is `f` and - `f*f=` f.composed_op(f,operator.mul). + `f*f=` ``f.composed_op(f, operator.mul)``. EXAMPLES:: sage: R.<a,b,c> = ZZ[] sage: x = polygen(R) - sage: f = (x-a)*(x-b)*(x-c) - sage: f.compose_power(2).factor() + sage: f = (x - a) * (x - b) * (x - c) + sage: f.compose_power(2).factor() # needs sage.libs.singular sage.modules (x - c^2) * (x - b^2) * (x - a^2) * (x - b*c)^2 * (x - a*c)^2 * (x - a*b)^2 + sage: # needs sage.libs.singular sage.modules sage: x = polygen(QQ) - sage: f = x^2-2*x+2 + sage: f = x^2 - 2*x + 2 sage: f2 = f.compose_power(2); f2 x^4 - 4*x^3 + 8*x^2 - 16*x + 16 - sage: f2 == f.composed_op(f,operator.mul) + sage: f2 == f.composed_op(f, operator.mul) True sage: f3 = f.compose_power(3); f3 x^8 - 8*x^7 + 32*x^6 - 64*x^5 + 128*x^4 - 512*x^3 + 2048*x^2 - 4096*x + 4096 - sage: f3 == f2.composed_op(f,operator.mul) + sage: f3 == f2.composed_op(f, operator.mul) True sage: f4 = f.compose_power(4) - sage: f4 == f3.composed_op(f,operator.mul) + sage: f4 == f3.composed_op(f, operator.mul) True """ try: @@ -7130,6 +7339,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: f = cyclotomic_polynomial(30) sage: f.adams_operator(7)==f True @@ -7143,23 +7353,25 @@ cdef class Polynomial(CommutativeAlgebraElement): True sage: x = polygen(QQ) - sage: f = x^2-2*x+2 - sage: f.adams_operator(10) + sage: f = x^2 - 2*x + 2 + sage: f.adams_operator(10) # needs sage.libs.singular x^2 + 1024 - When f is monic the output will have leading coefficient + When ``self`` is monic, the output will have leading coefficient `\pm1` depending on the degree, but we can force it to be monic:: sage: R.<a,b,c> = ZZ[] sage: x = polygen(R) - sage: f = (x-a)*(x-b)*(x-c) - sage: f.adams_operator(3).factor() + sage: f = (x - a) * (x - b) * (x - c) + sage: f.adams_operator(3).factor() # needs sage.libs.singular (-1) * (x - c^3) * (x - b^3) * (x - a^3) - sage: f.adams_operator(3,monic=True).factor() + sage: f.adams_operator(3, monic=True).factor() # needs sage.libs.singular (x - c^3) * (x - b^3) * (x - a^3) """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + u, v = PolynomialRing(self._parent.base_ring(), ['u', 'v']).gens() R = (u - v**n).resultant(self(v), v) R = R([self.variables()[0], 0]) @@ -7175,12 +7387,12 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: x = polygen(QQ) - sage: f = x^4-x+2 - sage: [f.symmetric_power(k) for k in range(5)] + sage: f = x^4 - x + 2 + sage: [f.symmetric_power(k) for k in range(5)] # needs sage.libs.singular [x - 1, x^4 - x + 2, x^6 - 2*x^4 - x^3 - 4*x^2 + 8, x^4 - x^3 + 8, x - 2] - sage: f = x^5-2*x+2 - sage: [f.symmetric_power(k) for k in range(6)] + sage: f = x^5 - 2*x + 2 + sage: [f.symmetric_power(k) for k in range(6)] # needs sage.libs.singular [x - 1, x^5 - 2*x + 2, x^10 + 2*x^8 - 4*x^6 - 8*x^5 - 8*x^4 - 8*x^3 + 16, @@ -7190,8 +7402,8 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<a,b,c,d> = ZZ[] sage: x = polygen(R) - sage: f = (x-a)*(x-b)*(x-c)*(x-d) - sage: [f.symmetric_power(k).factor() for k in range(5)] + sage: f = (x - a) * (x - b) * (x - c) * (x - d) + sage: [f.symmetric_power(k).factor() for k in range(5)] # needs sage.libs.singular [x - 1, (-x + d) * (-x + c) * (-x + b) * (-x + a), (x - c*d) * (x - b*d) * (x - a*d) * (x - b*c) * (x - a*c) * (x - a*b), @@ -7266,8 +7478,8 @@ cdef class Polynomial(CommutativeAlgebraElement): R_n := a_n^{2 n-2} \prod_{1<i<j<n} (r_i-r_j)^2, - where `n` is the degree of self, `a_n` is the - leading coefficient of self and the roots of self are + where `n` is the degree of ``self``, `a_n` is the + leading coefficient of ``self``, and the roots of ``self`` are `r_1, \ldots, r_n`. OUTPUT: An element of the base ring of the polynomial ring. @@ -7275,8 +7487,8 @@ cdef class Polynomial(CommutativeAlgebraElement): ALGORITHM: Uses the identity `R_n(f) := (-1)^{n (n-1)/2} R(f, f') - a_n^{n-k-2}`, where `n` is the degree of self, `a_n` is the - leading coefficient of self, `f'` is the derivative of `f`, + a_n^{n-k-2}`, where `n` is the degree of ``self``, `a_n` is the + leading coefficient of ``self``, `f'` is the derivative of `f`, and `k` is the degree of `f'`. Calls :meth:`.resultant`. EXAMPLES: @@ -7286,18 +7498,18 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = QQ[] sage: f = x^3 + x + 1 - sage: d = f.discriminant(); d + sage: d = f.discriminant(); d # needs sage.libs.pari -31 - sage: d.parent() is QQ + sage: d.parent() is QQ # needs sage.libs.pari True - sage: EllipticCurve([1, 1]).discriminant()/16 + sage: EllipticCurve([1, 1]).discriminant()/16 # needs sage.libs.pari -31 :: sage: R.<x> = QQ[] sage: f = 2*x^3 + x + 1 - sage: d = f.discriminant(); d + sage: d = f.discriminant(); d # needs sage.libs.pari -116 We can compute discriminants over univariate and multivariate @@ -7306,9 +7518,9 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<a> = QQ[] sage: S.<x> = R[] sage: f = a*x + x + a + 1 - sage: d = f.discriminant(); d + sage: d = f.discriminant(); d # needs sage.libs.pari 1 - sage: d.parent() is R + sage: d.parent() is R # needs sage.libs.pari True :: @@ -7316,9 +7528,9 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<a, b> = QQ[] sage: S.<x> = R[] sage: f = x^2 + a + b - sage: d = f.discriminant(); d + sage: d = f.discriminant(); d # needs sage.libs.pari -4*a - 4*b - sage: d.parent() is R + sage: d.parent() is R # needs sage.libs.pari True TESTS:: @@ -7326,7 +7538,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x, y> = QQ[] sage: S.<a> = R[] sage: f = x^2 + a - sage: f.discriminant() + sage: f.discriminant() # needs sage.libs.pari 1 Check that :trac:`13672` is fixed:: @@ -7334,33 +7546,34 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<t> = GF(5)[] sage: S.<x> = R[] sage: f = x^10 + 2*x^6 + 2*x^5 + x + 2 - sage: (f-t).discriminant() + sage: (f - t).discriminant() # needs sage.rings.finite_rings 4*t^5 The following examples show that :trac:`11782` has been fixed:: - sage: var('x') + sage: var('x') # needs sage.symbolic x - sage: ZZ.quo(81)['x'](3*x^2 + 3*x + 3).discriminant() + sage: ZZ.quo(81)['x'](3*x^2 + 3*x + 3).discriminant() # needs sage.libs.pari sage.symbolic 54 - sage: ZZ.quo(9)['x'](2*x^3 + x^2 + x).discriminant() + sage: ZZ.quo(9)['x'](2*x^3 + x^2 + x).discriminant() # needs sage.libs.pari sage.symbolic 2 This was fixed by :trac:`15422`:: - sage: R.<s> = PolynomialRing(Qp(2)) - sage: (s^2).discriminant() + sage: R.<s> = PolynomialRing(Qp(2)) # needs sage.rings.padics + sage: (s^2).discriminant() # needs sage.rings.padics 0 This was fixed by :trac:`16014`:: + sage: # needs sage.modules sage: PR.<b,t1,t2,x1,y1,x2,y2> = QQ[] sage: PRmu.<mu> = PR[] sage: E1 = diagonal_matrix(PR, [1, b^2, -b^2]) - sage: M = matrix(PR, [[1,-t1,x1-t1*y1],[t1,1,y1+t1*x1],[0,0,1]]) + sage: M = matrix(PR, [[1,-t1,x1-t1*y1], [t1,1,y1+t1*x1], [0,0,1]]) sage: E1 = M.transpose()*E1*M sage: E2 = E1.subs(t1=t2, x1=x2, y1=y2) - sage: det(mu*E1 + E2).discriminant().degrees() + sage: det(mu*E1 + E2).discriminant().degrees() # needs sage.libs.pari (24, 12, 12, 8, 8, 8, 8) This addresses an issue raised by :trac:`15061`:: @@ -7369,7 +7582,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: F = R([1,1],2) sage: RP.<x> = PolynomialRing(R) sage: P = x^2 - F - sage: P.discriminant() + sage: P.discriminant() # needs sage.libs.pari 4 + 4*T + O(T^2) """ # Late import to avoid cyclic dependencies: @@ -7408,7 +7621,7 @@ cdef class Polynomial(CommutativeAlgebraElement): """ Return polynomial but with the coefficients reversed. - If an optional degree argument is given the coefficient list will be + If an optional ``degree`` argument is given, the coefficient list will be truncated or zero padded as necessary before reversing it. Assuming that the constant coefficient of ``self`` is nonzero, the reverse polynomial will have the specified degree. @@ -7416,7 +7629,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: R.<x> = ZZ[]; S.<y> = R[] - sage: f = y^3 + x*y -3*x; f + sage: f = y^3 + x*y - 3*x; f y^3 + x*y - 3*x sage: f.reverse() -3*x*y^3 + x*y^2 + 1 @@ -7467,9 +7680,9 @@ cdef class Polynomial(CommutativeAlgebraElement): - ``ring`` - the ring to find roots in - - ``multiplicities`` - bool (default: True) if True - return list of pairs (r, n), where r is the root and n is the - multiplicity. If False, just return the unique roots, with no + - ``multiplicities`` - bool (default: ``True``) if ``True`` + return list of pairs `(r, n)`, where `r` is the root and `n` is the + multiplicity. If ``False``, just return the unique roots, with no information about multiplicities. - ``algorithm`` - the root-finding algorithm to use. @@ -7498,7 +7711,7 @@ cdef class Polynomial(CommutativeAlgebraElement): always ill-conditioned; there's a footnote at the end of the docstring about this. - If the output ring is a RealIntervalField or ComplexIntervalField + If the output ring is a :class:`RealIntervalField` or :class:`ComplexIntervalField` of a given precision, then the answer will always be correct (or an exception will be raised, if a case is not implemented). Each root will be contained in one of the returned intervals, and the @@ -7507,23 +7720,23 @@ cdef class Polynomial(CommutativeAlgebraElement): At the end of this docstring (after the examples) is a description of all the cases implemented in this function, and the algorithms - used. That section also describes the possibilities for - "algorithm=", for the cases where multiple algorithms exist. + used. That section also describes the possibilities for the + ``algorithm`` keyword, for the cases where multiple algorithms exist. EXAMPLES:: + sage: # needs sage.libs.pari sage: x = QQ['x'].0 sage: f = x^3 - 1 sage: f.roots() [(1, 1)] - sage: f.roots(ring=CC) # note -- low order bits slightly different on ppc. - [(1.00000000000000, 1), (-0.500000000000000 - 0.86602540378443...*I, 1), (-0.500000000000000 + 0.86602540378443...*I, 1)] + sage: f.roots(ring=CC) # ... - low order bits slightly different on ppc + [(1.00000000000000, 1), + (-0.500000000000000 - 0.86602540378443...*I, 1), + (-0.500000000000000 + 0.86602540378443...*I, 1)] sage: f = (x^3 - 1)^2 sage: f.roots() [(1, 2)] - - :: - sage: f = -19*x + 884736 sage: f.roots() [(884736/19, 1)] @@ -7532,6 +7745,7 @@ cdef class Polynomial(CommutativeAlgebraElement): :: + sage: # needs sage.rings.number_field sage: K.<z> = CyclotomicField(3) sage: f = K.defining_polynomial() sage: f.roots(ring=GF(7)) @@ -7543,80 +7757,88 @@ cdef class Polynomial(CommutativeAlgebraElement): [4, 2] A new ring. In the example below, we add the special method - _roots_univariate_polynomial to the base ring, and observe + :meth:`_roots_univariate_polynomial` to the base ring, and observe that this method is called instead to find roots of polynomials over this ring. This facility can be used to easily extend root finding to work over new rings you introduce:: sage: R.<x> = QQ[] - sage: (x^2 + 1).roots() + sage: (x^2 + 1).roots() # needs sage.libs.pari [] - sage: g = lambda f, *args, **kwds: f.change_ring(CDF).roots() - sage: QQ._roots_univariate_polynomial = g - sage: (x^2 + 1).roots() # abs tol 1e-14 + sage: def my_roots(f, *args, **kwds): + ....: return f.change_ring(CDF).roots() + sage: QQ._roots_univariate_polynomial = my_roots + sage: (x^2 + 1).roots() # abs tol 1e-14 # needs numpy [(2.7755575615628914e-17 - 1.0*I, 1), (0.9999999999999997*I, 1)] sage: del QQ._roots_univariate_polynomial An example over RR, which illustrates that only the roots in RR are returned:: + sage: # needs numpy sage.rings.real_mpfr sage: x = RR['x'].0 - sage: f = x^3 -2 + sage: f = x^3 - 2 sage: f.roots() [(1.25992104989487, 1)] sage: f.factor() (x - 1.25992104989487) * (x^2 + 1.25992104989487*x + 1.58740105196820) sage: x = RealField(100)['x'].0 - sage: f = x^3 -2 + sage: f = x^3 - 2 sage: f.roots() [(1.2599210498948731647672106073, 1)] :: sage: x = CC['x'].0 - sage: f = x^3 -2 - sage: f.roots() - [(1.25992104989487, 1), (-0.62996052494743... - 1.09112363597172*I, 1), (-0.62996052494743... + 1.09112363597172*I, 1)] - sage: f.roots(algorithm='pari') - [(1.25992104989487, 1), (-0.629960524947437 - 1.09112363597172*I, 1), (-0.629960524947437 + 1.09112363597172*I, 1)] + sage: f = x^3 - 2 + sage: f.roots() # needs numpy + [(1.25992104989487, 1), + (-0.62996052494743... - 1.09112363597172*I, 1), + (-0.62996052494743... + 1.09112363597172*I, 1)] + sage: f.roots(algorithm='pari') # needs sage.libs.pari + [(1.25992104989487, 1), + (-0.629960524947437 - 1.09112363597172*I, 1), + (-0.629960524947437 + 1.09112363597172*I, 1)] Another example showing that only roots in the base ring are returned:: sage: x = polygen(ZZ) - sage: f = (2*x-3) * (x-1) * (x+1) - sage: f.roots() + sage: f = (2*x - 3) * (x - 1) * (x + 1) + sage: f.roots() # needs sage.libs.pari [(1, 1), (-1, 1)] - sage: f.roots(ring=QQ) + sage: f.roots(ring=QQ) # needs sage.libs.pari [(3/2, 1), (1, 1), (-1, 1)] An example where we compute the roots lying in a subring of the base ring:: sage: Pols.<n> = QQ[] - sage: pol = (n - 1/2)^2*(n - 1)^2*(n-2) - sage: pol.roots(ZZ) + sage: pol = (n - 1/2)^2 * (n - 1)^2 * (n - 2) + sage: pol.roots(ZZ) # needs sage.libs.pari [(2, 1), (1, 2)] An example involving large numbers:: + sage: # needs numpy sage.rings.real_mpfr sage: x = RR['x'].0 sage: f = x^2 - 1e100 sage: f.roots() [(-1.00000000000000e50, 1), (1.00000000000000e50, 1)] - sage: f = x^10 - 2*(5*x-1)^2 + sage: f = x^10 - 2 * (5*x - 1)^2 sage: f.roots(multiplicities=False) [-1.6772670339941..., 0.19995479628..., 0.20004530611..., 1.5763035161844...] :: + sage: # needs numpy sage.rings.real_mpfr sage: x = CC['x'].0 sage: i = CC.0 - sage: f = (x - 1)*(x - i) + sage: f = (x - 1) * (x - i) sage: f.roots(multiplicities=False) [1.00000000000000, 1.00000000000000*I] - sage: g=(x-1.33+1.33*i)*(x-2.66-2.66*i) + sage: g = (x - 1.33 + 1.33*i) * (x - 2.66 - 2.66*i) sage: g.roots(multiplicities=False) [1.33000000000000 - 1.33000000000000*I, 2.66000000000000 + 2.66000000000000*I] @@ -7624,15 +7846,15 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: x = QQ['x'].0 sage: f = x^2 + 2 - sage: f.roots(SR) + sage: f.roots(SR) # needs sage.symbolic [(-I*sqrt(2), 1), (I*sqrt(2), 1)] - sage: f.roots(SR, multiplicities=False) + sage: f.roots(SR, multiplicities=False) # needs sage.symbolic [-I*sqrt(2), I*sqrt(2)] The roots of some polynomials cannot be described using radical expressions:: - sage: (x^5 - x + 1).roots(SR) + sage: (x^5 - x + 1).roots(SR) # needs sage.symbolic [] For some other polynomials, no roots can be found at the moment @@ -7640,24 +7862,28 @@ cdef class Polynomial(CommutativeAlgebraElement): these defects. Until that gets implemented, one such example is the following:: - sage: f = x^6-300*x^5+30361*x^4-1061610*x^3+1141893*x^2-915320*x+101724 - sage: f.roots() + sage: f = x^6 - 300*x^5 + 30361*x^4 - 1061610*x^3 + 1141893*x^2 - 915320*x + 101724 + sage: f.roots() # needs sage.libs.pari [] A purely symbolic roots example:: + sage: # needs sage.symbolic sage: X = var('X') - sage: f = expand((X-1)*(X-I)^3*(X^2 - sqrt(2))); f - X^6 - (3*I + 1)*X^5 - sqrt(2)*X^4 + (3*I - 3)*X^4 + (3*I + 1)*sqrt(2)*X^3 + (I + 3)*X^3 - (3*I - 3)*sqrt(2)*X^2 - I*X^2 - (I + 3)*sqrt(2)*X + I*sqrt(2) + sage: f = expand((X - 1) * (X - I)^3 * (X^2 - sqrt(2))); f + X^6 - (3*I + 1)*X^5 - sqrt(2)*X^4 + (3*I - 3)*X^4 + (3*I + 1)*sqrt(2)*X^3 + + (I + 3)*X^3 - (3*I - 3)*sqrt(2)*X^2 - I*X^2 - (I + 3)*sqrt(2)*X + I*sqrt(2) sage: f.roots() [(I, 3), (-2^(1/4), 1), (2^(1/4), 1), (1, 1)] The same operation, performed over a polynomial ring with symbolic coefficients:: + sage: # needs sage.symbolic sage: X = SR['X'].0 - sage: f = (X-1)*(X-I)^3*(X^2 - sqrt(2)); f - X^6 + (-3*I - 1)*X^5 + (-sqrt(2) + 3*I - 3)*X^4 + ((3*I + 1)*sqrt(2) + I + 3)*X^3 + (-(3*I - 3)*sqrt(2) - I)*X^2 + (-(I + 3)*sqrt(2))*X + I*sqrt(2) + sage: f = (X - 1) * (X - I)^3 * (X^2 - sqrt(2)); f + X^6 + (-3*I - 1)*X^5 + (-sqrt(2) + 3*I - 3)*X^4 + ((3*I + 1)*sqrt(2) + I + 3)*X^3 + + (-(3*I - 3)*sqrt(2) - I)*X^2 + (-(I + 3)*sqrt(2))*X + I*sqrt(2) sage: f.roots() [(I, 3), (-2^(1/4), 1), (2^(1/4), 1), (1, 1)] sage: f.roots(multiplicities=False) @@ -7669,30 +7895,34 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R = Integers(6) sage: S.<x> = R['x'] - sage: p = x^2-1 + sage: p = x^2 - 1 sage: p.roots() Traceback (most recent call last): ... - NotImplementedError: root finding with multiplicities for this polynomial not implemented (try the multiplicities=False option) - sage: p.roots(multiplicities=False) + NotImplementedError: root finding with multiplicities for this polynomial + not implemented (try the multiplicities=False option) + sage: p.roots(multiplicities=False) # needs sage.libs.pari [5, 1] sage: R = Integers(9) sage: A = PolynomialRing(R, 'y') sage: y = A.gen() sage: f = 10*y^2 - y^3 - 9 - sage: f.roots(multiplicities=False) + sage: f.roots(multiplicities=False) # needs sage.libs.pari [1, 0, 3, 6] An example over the complex double field (where root finding is fast, thanks to NumPy):: + sage: # needs numpy sage.rings.complex_double sage: R.<x> = CDF[] sage: f = R.cyclotomic_polynomial(5); f x^4 + x^3 + x^2 + x + 1.0 sage: f.roots(multiplicities=False) # abs tol 1e-9 - [-0.8090169943749469 - 0.5877852522924724*I, -0.8090169943749473 + 0.5877852522924724*I, 0.30901699437494773 - 0.951056516295154*I, 0.30901699437494756 + 0.9510565162951525*I] + [-0.8090169943749469 - 0.5877852522924724*I, -0.8090169943749473 + 0.5877852522924724*I, + 0.30901699437494773 - 0.951056516295154*I, 0.30901699437494756 + 0.9510565162951525*I] sage: [z^5 for z in f.roots(multiplicities=False)] # abs tol 2e-14 - [0.9999999999999957 - 1.2864981197413038e-15*I, 0.9999999999999976 + 3.062854959141552e-15*I, 1.0000000000000024 + 1.1331077795295987e-15*I, 0.9999999999999953 - 2.0212861992297117e-15*I] + [0.9999999999999957 - 1.2864981197413038e-15*I, 0.9999999999999976 + 3.062854959141552e-15*I, + 1.0000000000000024 + 1.1331077795295987e-15*I, 0.9999999999999953 - 2.0212861992297117e-15*I] sage: f = CDF['x']([1,2,3,4]); f 4.0*x^3 + 3.0*x^2 + 2.0*x + 1.0 sage: r = f.roots(multiplicities=False) @@ -7702,27 +7932,33 @@ cdef class Polynomial(CommutativeAlgebraElement): Another example over RDF:: sage: x = RDF['x'].0 - sage: ((x^3 -1)).roots() # abs tol 4e-16 + sage: ((x^3 - 1)).roots() # abs tol 4e-16 # needs numpy [(1.0000000000000002, 1)] - sage: ((x^3 -1)).roots(multiplicities=False) # abs tol 4e-16 + sage: ((x^3 - 1)).roots(multiplicities=False) # abs tol 4e-16 # needs numpy [1.0000000000000002] More examples involving the complex double field:: + sage: # needs numpy sage.rings.complex_double sage.rings.real_mpfr sage: x = CDF['x'].0 sage: i = CDF.0 sage: f = x^3 + 2*i; f x^3 + 2.0*I sage: f.roots() - [(-1.09112363597172... - 0.62996052494743...*I, 1), (...1.25992104989487...*I, 1), (1.09112363597172... - 0.62996052494743...*I, 1)] + [(-1.09112363597172... - 0.62996052494743...*I, 1), + (...1.25992104989487...*I, 1), + (1.09112363597172... - 0.62996052494743...*I, 1)] sage: f.roots(multiplicities=False) - [-1.09112363597172... - 0.62996052494743...*I, ...1.25992104989487...*I, 1.09112363597172... - 0.62996052494743...*I] + [-1.09112363597172... - 0.62996052494743...*I, ...1.25992104989487...*I, + 1.09112363597172... - 0.62996052494743...*I] sage: [abs(f(z)) for z in f.roots(multiplicities=False)] # abs tol 1e-14 [8.95090418262362e-16, 8.728374398092689e-16, 1.0235750533041806e-15] sage: f = i*x^3 + 2; f I*x^3 + 2.0 sage: f.roots() - [(-1.09112363597172... + 0.62996052494743...*I, 1), (...1.25992104989487...*I, 1), (1.09112363597172... + 0.62996052494743...*I, 1)] + [(-1.09112363597172... + 0.62996052494743...*I, 1), + (...1.25992104989487...*I, 1), + (1.09112363597172... + 0.62996052494743...*I, 1)] sage: abs(f(f.roots()[0][0])) # abs tol 1e-13 1.1102230246251565e-16 @@ -7730,45 +7966,69 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: x = polygen(ZZ) sage: f = x^2 - x - 1 - sage: f.roots() + sage: f.roots() # needs sage.libs.pari [] + sage: f.roots(ring=AA) # needs sage.rings.number_field + [(-0.618033988749895?, 1), (1.618033988749895?, 1)] + + sage: # needs sage.rings.real_interval_field sage: f.roots(ring=RIF) [(-0.6180339887498948482045868343657?, 1), (1.6180339887498948482045868343657?, 1)] sage: f.roots(ring=RIF, multiplicities=False) [-0.6180339887498948482045868343657?, 1.6180339887498948482045868343657?] sage: f.roots(ring=RealIntervalField(150)) - [(-0.6180339887498948482045868343656381177203091798057628621354486227?, 1), (1.618033988749894848204586834365638117720309179805762862135448623?, 1)] - sage: f.roots(ring=AA) - [(-0.618033988749895?, 1), (1.618033988749895?, 1)] + [(-0.6180339887498948482045868343656381177203091798057628621354486227?, 1), + (1.618033988749894848204586834365638117720309179805762862135448623?, 1)] sage: f = f^2 * (x - 1) sage: f.roots(ring=RIF) - [(-0.6180339887498948482045868343657?, 2), (1.0000000000000000000000000000000?, 1), (1.6180339887498948482045868343657?, 2)] + [(-0.6180339887498948482045868343657?, 2), + (1.0000000000000000000000000000000?, 1), + (1.6180339887498948482045868343657?, 2)] sage: f.roots(ring=RIF, multiplicities=False) - [-0.6180339887498948482045868343657?, 1.0000000000000000000000000000000?, 1.6180339887498948482045868343657?] + [-0.6180339887498948482045868343657?, + 1.0000000000000000000000000000000?, + 1.6180339887498948482045868343657?] Examples using complex root isolation:: sage: x = polygen(ZZ) sage: p = x^5 - x - 1 - sage: p.roots() + sage: p.roots() # needs sage.libs.pari [] - sage: p.roots(ring=CIF) - [(1.167303978261419?, 1), (-0.764884433600585? - 0.352471546031727?*I, 1), (-0.764884433600585? + 0.352471546031727?*I, 1), (0.181232444469876? - 1.083954101317711?*I, 1), (0.181232444469876? + 1.083954101317711?*I, 1)] - sage: p.roots(ring=ComplexIntervalField(200)) - [(1.167303978261418684256045899854842180720560371525489039140082?, 1), (-0.76488443360058472602982318770854173032899665194736756700778? - 0.35247154603172624931794709140258105439420648082424733283770?*I, 1), (-0.76488443360058472602982318770854173032899665194736756700778? + 0.35247154603172624931794709140258105439420648082424733283770?*I, 1), (0.18123244446987538390180023778112063996871646618462304743774? - 1.08395410131771066843034449298076657427364024315511565430114?*I, 1), (0.18123244446987538390180023778112063996871646618462304743774? + 1.08395410131771066843034449298076657427364024315511565430114?*I, 1)] - sage: rts = p.roots(ring=QQbar); rts - [(1.167303978261419?, 1), (-0.7648844336005847? - 0.3524715460317263?*I, 1), (-0.7648844336005847? + 0.3524715460317263?*I, 1), (0.1812324444698754? - 1.083954101317711?*I, 1), (0.1812324444698754? + 1.083954101317711?*I, 1)] - sage: p.roots(ring=AA) + sage: p.roots(ring=CIF) # needs sage.rings.complex_interval_field + [(1.167303978261419?, 1), + (-0.764884433600585? - 0.352471546031727?*I, 1), + (-0.764884433600585? + 0.352471546031727?*I, 1), + (0.181232444469876? - 1.083954101317711?*I, 1), + (0.181232444469876? + 1.083954101317711?*I, 1)] + sage: p.roots(ring=ComplexIntervalField(200)) # needs sage.rings.complex_interval_field + [(1.167303978261418684256045899854842180720560371525489039140082?, 1), + (-0.76488443360058472602982318770854173032899665194736756700778? - 0.35247154603172624931794709140258105439420648082424733283770?*I, 1), + (-0.76488443360058472602982318770854173032899665194736756700778? + 0.35247154603172624931794709140258105439420648082424733283770?*I, 1), + (0.18123244446987538390180023778112063996871646618462304743774? - 1.08395410131771066843034449298076657427364024315511565430114?*I, 1), + (0.18123244446987538390180023778112063996871646618462304743774? + 1.08395410131771066843034449298076657427364024315511565430114?*I, 1)] + sage: rts = p.roots(ring=QQbar); rts # needs sage.rings.number_field + [(1.167303978261419?, 1), + (-0.7648844336005847? - 0.3524715460317263?*I, 1), + (-0.7648844336005847? + 0.3524715460317263?*I, 1), + (0.1812324444698754? - 1.083954101317711?*I, 1), + (0.1812324444698754? + 1.083954101317711?*I, 1)] + sage: p.roots(ring=AA) # needs sage.rings.number_field [(1.167303978261419?, 1)] - sage: p = (x - rts[4][0])^2 * (3*x^2 + x + 1) - sage: p.roots(ring=QQbar) - [(-0.1666666666666667? - 0.552770798392567?*I, 1), (-0.1666666666666667? + 0.552770798392567?*I, 1), (0.1812324444698754? + 1.083954101317711?*I, 2)] - sage: p.roots(ring=CIF) - [(-0.1666666666666667? - 0.552770798392567?*I, 1), (-0.1666666666666667? + 0.552770798392567?*I, 1), (0.1812324444698754? + 1.083954101317711?*I, 2)] + sage: p = (x - rts[4][0])^2 * (3*x^2 + x + 1) # needs sage.rings.number_field + sage: p.roots(ring=QQbar) # needs sage.rings.number_field + [(-0.1666666666666667? - 0.552770798392567?*I, 1), + (-0.1666666666666667? + 0.552770798392567?*I, 1), + (0.1812324444698754? + 1.083954101317711?*I, 2)] + sage: p.roots(ring=CIF) # needs sage.rings.complex_interval_field + [(-0.1666666666666667? - 0.552770798392567?*I, 1), + (-0.1666666666666667? + 0.552770798392567?*I, 1), + (0.1812324444698754? + 1.083954101317711?*I, 2)] In some cases, it is possible to isolate the roots of polynomials over complex ball fields:: + sage: # needs sage.libs.flint sage: Pol.<x> = CBF[] sage: (x^2 + 2).roots(multiplicities=False) [[+/- ...e-19] + [-1.414213562373095 +/- ...e-17]*I, @@ -7783,35 +8043,46 @@ cdef class Polynomial(CommutativeAlgebraElement): Note that coefficients in a number field with defining polynomial `x^2 + 1` are considered to be Gaussian rationals (with the - generator mapping to +I), if you ask for complex roots. + generator mapping to `+I`), if you ask for complex roots. :: + sage: # needs sage.rings.number_field sage: K.<im> = QuadraticField(-1) sage: y = polygen(K) sage: p = y^4 - 2 - im sage: p.roots(ring=CC) - [(-1.2146389322441... - 0.14142505258239...*I, 1), (-0.14142505258239... + 1.2146389322441...*I, 1), (0.14142505258239... - 1.2146389322441...*I, 1), (1.2146389322441... + 0.14142505258239...*I, 1)] + [(-1.2146389322441... - 0.14142505258239...*I, 1), + (-0.14142505258239... + 1.2146389322441...*I, 1), + (0.14142505258239... - 1.2146389322441...*I, 1), + (1.2146389322441... + 0.14142505258239...*I, 1)] sage: p = p^2 * (y^2 - 2) sage: p.roots(ring=CIF) - [(-1.414213562373095?, 1), (1.414213562373095?, 1), (-1.214638932244183? - 0.141425052582394?*I, 2), (-0.141425052582394? + 1.214638932244183?*I, 2), (0.141425052582394? - 1.214638932244183?*I, 2), (1.214638932244183? + 0.141425052582394?*I, 2)] + [(-1.414213562373095?, 1), (1.414213562373095?, 1), + (-1.214638932244183? - 0.141425052582394?*I, 2), + (-0.141425052582394? + 1.214638932244183?*I, 2), + (0.141425052582394? - 1.214638932244183?*I, 2), + (1.214638932244183? + 0.141425052582394?*I, 2)] Note that one should not use NumPy when wanting high precision output as it does not support any of the high precision types:: + sage: # needs numpy sage.rings.real_mpfr sage.symbolic sage: R.<x> = RealField(200)[] sage: f = x^2 - R(pi) sage: f.roots() - [(-1.7724538509055160272981674833411451827975494561223871282138, 1), (1.7724538509055160272981674833411451827975494561223871282138, 1)] + [(-1.7724538509055160272981674833411451827975494561223871282138, 1), + (1.7724538509055160272981674833411451827975494561223871282138, 1)] sage: f.roots(algorithm='numpy') - doctest... UserWarning: NumPy does not support arbitrary precision arithmetic. The roots found will likely have less precision than you expect. + doctest... UserWarning: NumPy does not support arbitrary precision arithmetic. + The roots found will likely have less precision than you expect. [(-1.77245385090551..., 1), (1.77245385090551..., 1)] We can also find roots over number fields:: - sage: K.<z> = CyclotomicField(15) - sage: R.<x> = PolynomialRing(K) - sage: (x^2 + x + 1).roots() + sage: K.<z> = CyclotomicField(15) # needs sage.rings.number_field + sage: R.<x> = PolynomialRing(K) # needs sage.rings.number_field + sage: (x^2 + x + 1).roots() # needs sage.rings.number_field [(z^5, 1), (-z^5 - 1, 1)] There are many combinations of floating-point input and output @@ -7820,6 +8091,7 @@ cdef class Polynomial(CommutativeAlgebraElement): :: + sage: # needs sage.rings.complex_double sage.rings.real_mpfr sage: rflds = (RR, RDF, RealField(100)) sage: cflds = (CC, CDF, ComplexField(100)) sage: def cross(a, b): @@ -7847,27 +8119,29 @@ cdef class Polynomial(CommutativeAlgebraElement): Note that we can find the roots of a polynomial with algebraic coefficients:: + sage: # needs sage.rings.number_field sage: rt2 = sqrt(AA(2)) sage: rt3 = sqrt(AA(3)) sage: x = polygen(AA) sage: f = (x - rt2) * (x - rt3); f - x^2 - 3.146264369941973?*x + 2.449489742783178? + x^2 - 3.146264369941973?*x + 2.449489742783178? sage: rts = f.roots(); rts [(1.414213562373095?, 1), (1.732050807568878?, 1)] sage: rts[0][0] == rt2 True sage: f.roots(ring=RealIntervalField(150)) - [(1.414213562373095048801688724209698078569671875376948073176679738?, 1), (1.732050807568877293527446341505872366942805253810380628055806980?, 1)] + [(1.414213562373095048801688724209698078569671875376948073176679738?, 1), + (1.732050807568877293527446341505872366942805253810380628055806980?, 1)] We can handle polynomials with huge coefficients. This number doesn't even fit in an IEEE double-precision float, but - RR and CC allow a much larger range of floating-point numbers:: + ``RR`` and ``CC`` allow a much larger range of floating-point numbers:: sage: bigc = 2^1500 - sage: CDF(bigc) + sage: CDF(bigc) # needs sage.rings.complex_double +infinity - sage: CC(bigc) + sage: CC(bigc) # needs sage.rings.real_mpfr 3.50746621104340e451 Polynomials using such large coefficients can't be handled by @@ -7875,62 +8149,62 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: x = polygen(QQ) sage: p = x + bigc - sage: p.roots(ring=RR, algorithm='numpy') + sage: p.roots(ring=RR, algorithm='numpy') # needs numpy Traceback (most recent call last): ... LinAlgError: Array must not contain infs or NaNs - sage: p.roots(ring=RR, algorithm='pari') + sage: p.roots(ring=RR, algorithm='pari') # needs sage.libs.pari [(-3.50746621104340e451, 1)] - sage: p.roots(ring=AA) + sage: p.roots(ring=AA) # needs sage.rings.number_field [(-3.5074662110434039?e451, 1)] - sage: p.roots(ring=QQbar) + sage: p.roots(ring=QQbar) # needs sage.rings.number_field [(-3.5074662110434039?e451, 1)] sage: p = bigc*x + 1 - sage: p.roots(ring=RR) + sage: p.roots(ring=RR) # needs numpy [(-2.85106096489671e-452, 1)] - sage: p.roots(ring=AA) + sage: p.roots(ring=AA) # needs sage.rings.number_field [(-2.8510609648967059?e-452, 1)] - sage: p.roots(ring=QQbar) + sage: p.roots(ring=QQbar) # needs sage.rings.number_field [(-2.8510609648967059?e-452, 1)] sage: p = x^2 - bigc - sage: p.roots(ring=RR) + sage: p.roots(ring=RR) # needs numpy [(-5.92238652153286e225, 1), (5.92238652153286e225, 1)] - sage: p.roots(ring=QQbar) + sage: p.roots(ring=QQbar) # needs sage.rings.number_field [(-5.9223865215328558?e225, 1), (5.9223865215328558?e225, 1)] Check that :trac:`30522` is fixed:: - sage: PolynomialRing(SR, names="x")("x^2").roots() + sage: PolynomialRing(SR, names="x")("x^2").roots() # needs sage.symbolic [(0, 2)] Check that :trac:`30523` is fixed:: - sage: PolynomialRing(SR, names="x")("x^2 + q").roots() + sage: PolynomialRing(SR, names="x")("x^2 + q").roots() # needs sage.symbolic [(-sqrt(-q), 1), (sqrt(-q), 1)] - Algorithms used: + ALGORITHM: - For brevity, we will use RR to mean any RealField of any precision; - similarly for RIF, CC, and CIF. Since Sage has no specific + For brevity, we will use ``RR`` to mean any :class:`RealField` of any precision; + similarly for ``RIF``, ``CC``, and ``CIF``. Since Sage has no specific implementation of Gaussian rationals (or of number fields with embedding, at all), when we refer to Gaussian rationals below we will accept any number field with defining polynomial `x^2+1`, mapping the field generator to +I. - We call the base ring of the polynomial K, and the ring given by - the ring= argument L. (If ring= is not specified, then L is the - same as K.) - - If K and L are floating-point (RDF, CDF, RR, or CC), then a - floating-point root-finder is used. If L is RDF or CDF then we - default to using NumPy's roots(); otherwise, we use PARI's - polroots(). This choice can be overridden with - algorithm='pari' or algorithm='numpy'. If the algorithm is - unspecified and NumPy's roots() algorithm fails, then we fall - back to pari (numpy will fail if some coefficient is infinite, + We call the base ring of the polynomial `K`, and the ring given by + the ``ring`` argument `L`. (If ``ring`` is not specified, then `L` is the + same as `K`.) + + If `K` and `L` are floating-point (``RDF``, ``CDF``, ``RR``, or ``CC``), then a + floating-point root-finder is used. If `L` is ``RDF`` or ``CDF``, then we + default to using NumPy's :func:`roots`; otherwise, we use PARI's + function :pari:`polroots`. This choice can be overridden with + ``algorithm='pari'`` or ``algorithm='numpy'``. If the algorithm is + unspecified and NumPy's :func:`roots` algorithm fails, then we fall + back to PARI (NumPy will fail if some coefficient is infinite, for instance). - If L is SR (or one of its subrings), then the roots will be radical + If `L` is ``SR`` (or one of its subrings), then the roots will be radical expressions, computed as the solutions of a symbolic polynomial expression. At the moment this delegates to :meth:`sage.symbolic.expression.Expression.solve` @@ -7939,47 +8213,47 @@ cdef class Polynomial(CommutativeAlgebraElement): Once :trac:`17516` gets implemented, all possible radical solutions should become available. - If L is AA or RIF, and K is ZZ, QQ, or AA, then the root isolation - algorithm sage.rings.polynomial.real_roots.real_roots() is used. - (You can call real_roots() directly to get more control than this + If `L` is ``AA`` or ``RIF``, and `K` is ``ZZ``, ``QQ``, or ``AA``, then the root isolation + algorithm :func:`sage.rings.polynomial.real_roots.real_roots` is used. + (You can call :func:`real_roots` directly to get more control than this method gives.) - If L is QQbar or CIF, and K is ZZ, QQ, AA, QQbar, or the Gaussian + If `L` is ``QQbar`` or ``CIF``, and `K` is ``ZZ``, ``QQ``, ``AA``, ``QQbar``, or the Gaussian rationals, then the root isolation algorithm - sage.rings.polynomial.complex_roots.complex_roots() is used. (You - can call complex_roots() directly to get more control than this + :func:`sage.rings.polynomial.complex_roots.complex_roots` is used. (You + can call :func:`complex_roots` directly to get more control than this method gives.) - If L is AA and K is QQbar or the Gaussian rationals, then - complex_roots() is used (as above) to find roots in QQbar, then + If `L` is ``AA`` and `K` is ``QQbar`` or the Gaussian rationals, then + :func:`complex_roots` is used (as above) to find roots in ``QQbar``, then these roots are filtered to select only the real roots. - If L is floating-point and K is not, then we attempt to change the - polynomial ring to L (using .change_ring()) (or, if L is complex - and K is not, to the corresponding real field). Then we use either - PARI or numpy as specified above. + If `L` is floating-point and `K` is not, then we attempt to change the + polynomial ring to `L` (using :meth:`change_ring`) (or, if `L` is complex + and `K` is not, to the corresponding real field). Then we use either + PARI or NumPy as specified above. - For all other cases where K is different than L, we attempt to use - .change_ring(L). When that fails but L is a subring of K, we also - attempt to compute the roots over K and filter the ones belonging - toย L. + For all other cases where `K` is different from `L`, we attempt to use + ``.change_ring(L)``. When that fails but `L` is a subring of `K`, we also + attempt to compute the roots over `K` and filter the ones belonging + to `L`. - The next method, which is used if K is an integral domain, is to + The next method, which is used if `K` is an integral domain, is to attempt to factor the polynomial. If this succeeds, then for every - degree-one factor a\*x+b, we add -b/a as a root (as long as this + degree-one factor `ax+b`, we add `-b/a` as a root (as long as this quotient is actually in the desired ring). - If factoring over K is not implemented (or K is not an integral - domain), and K is finite, then we find the roots by enumerating all - elements of K and checking whether the polynomial evaluates to zero + If factoring over `K` is not implemented (or `K` is not an integral + domain), and `K` is finite, then we find the roots by enumerating all + elements of `K` and checking whether the polynomial evaluates to zero at that value. .. NOTE:: We mentioned above that polynomials with multiple roots are - always ill-conditioned; if your input is given to n bits of - precision, you should not expect more than n/k good bits - for a k-fold root. (You can get solutions that make the + always ill-conditioned; if your input is given to `n` bits of + precision, you should not expect more than `n/k` good bits + for a `k`-fold root. (You can get solutions that make the polynomial evaluate to a number very close to zero; basically the problem is that with a multiple root, there are many such numbers, and it's difficult to choose between @@ -7997,65 +8271,68 @@ cdef class Polynomial(CommutativeAlgebraElement): TESTS:: - sage: K.<zeta> = CyclotomicField(2) - sage: R.<x> = K[] - sage: factor(x^3-1) + sage: K.<zeta> = CyclotomicField(2) # needs sage.rings.number_field + sage: R.<x> = K[] # needs sage.rings.number_field + sage: factor(x^3 - 1) # needs sage.rings.number_field (x - 1) * (x^2 + x + 1) This shows that the issue from :trac:`6237` is fixed:: sage: R.<u> = QQ[] sage: g = -27*u^14 - 32*u^9 - sage: g.roots(CDF, multiplicities=False) # abs tol 2e-15 - [-1.0345637159435719, 0.0, -0.3196977699902601 - 0.9839285635706636*I, -0.3196977699902601 + 0.9839285635706636*I, 0.8369796279620465 - 0.6081012947885318*I, 0.8369796279620465 + 0.6081012947885318*I] - sage: g.roots(CDF) # abs tol 2e-15 - [(-1.0345637159435719, 1), (0.0, 9), (-0.3196977699902601 - 0.9839285635706636*I, 1), (-0.3196977699902601 + 0.9839285635706636*I, 1), (0.8369796279620465 - 0.6081012947885318*I, 1), (0.8369796279620465 + 0.6081012947885318*I, 1)] + sage: g.roots(CDF, multiplicities=False) # abs tol 2e-15 # needs numpy + [-1.0345637159435719, 0.0, -0.3196977699902601 - 0.9839285635706636*I, -0.3196977699902601 + 0.9839285635706636*I, + 0.8369796279620465 - 0.6081012947885318*I, 0.8369796279620465 + 0.6081012947885318*I] + sage: g.roots(CDF) # abs tol 2e-15 # needs numpy + [(-1.0345637159435719, 1), (0.0, 9), (-0.3196977699902601 - 0.9839285635706636*I, 1), (-0.3196977699902601 + 0.9839285635706636*I, 1), + (0.8369796279620465 - 0.6081012947885318*I, 1), (0.8369796279620465 + 0.6081012947885318*I, 1)] This shows that the issue at :trac:`2418` is fixed:: sage: x = polygen(QQ) - sage: p = (x^50/2^100 + x^10 + x + 1).change_ring(ComplexField(106)) - sage: rts = (p/2^100).roots(multiplicities=False) + sage: p = (x^50/2^100 + x^10 + x + 1).change_ring(ComplexField(106)) # needs sage.rings.real_mpfr + sage: rts = (p/2^100).roots(multiplicities=False) # needs sage.libs.pari sage: eps = 2^(-50) # we test the roots numerically - sage: [abs(p(rt)) < eps for rt in rts] == [True]*50 + sage: [abs(p(rt)) < eps for rt in rts] == [True]*50 # needs sage.rings.number_field True This shows that the issue at :trac:`10901` is fixed:: + sage: # needs sage.symbolic sage: a = var('a'); R.<x> = SR[] sage: f = x - a sage: f.roots(RR) Traceback (most recent call last): ... - TypeError: Cannot evaluate symbolic expression to a numeric value. + TypeError: cannot evaluate symbolic expression to a numeric value sage: f.roots(CC) Traceback (most recent call last): ... - TypeError: Cannot evaluate symbolic expression to a numeric value. + TypeError: cannot evaluate symbolic expression to a numeric value We can find roots of polynomials defined over `\ZZ` or `\QQ` over the `p`-adics, see :trac:`15422`:: sage: R.<x> = ZZ[] sage: pol = (x - 1)^2 - sage: pol.roots(Qp(3,5)) + sage: pol.roots(Qp(3, 5)) # needs sage.rings.padics [(1 + O(3^5), 2)] We lose precision if we first change coefficients to `\QQ_p`:: - sage: pol.change_ring(Qp(3,5)).roots() + sage: # needs sage.rings.padics + sage: pol.change_ring(Qp(3, 5)).roots() [(1 + O(3^3), 2)] - - sage: (pol - 3^6).roots(Qp(3,5)) + sage: (pol - 3^6).roots(Qp(3, 5)) [(1 + 2*3^3 + 2*3^4 + O(3^5), 1), (1 + 3^3 + O(3^5), 1)] - sage: r = pol.roots(Zp(3,5), multiplicities=False); r + sage: r = pol.roots(Zp(3, 5), multiplicities=False); r [1 + O(3^5)] sage: parent(r[0]) 3-adic Ring with capped relative precision 5 Spurious crash with pari-2.5.5, see :trac:`16165`:: - sage: f=(1+x+x^2)^3 + sage: f = (1+x+x^2)^3 sage: f.roots(ring=CC) [(-0.500000000000000 - 0.866025403784439*I, 3), (-0.500000000000000 + 0.866025403784439*I, 3)] @@ -8072,14 +8349,14 @@ cdef class Polynomial(CommutativeAlgebraElement): Test that some large finite rings can be handled (:trac:`13825`):: - sage: R.<x> = IntegerModRing(20000009)[] + sage: R.<x> = IntegerModRing(20000009)[] # needs sage.libs.pari sage: eq = x^6+x-17 - sage: eq.roots(multiplicities=False) + sage: eq.roots(multiplicities=False) # needs sage.libs.pari [3109038, 17207405] Test that roots in fixed modulus p-adic fields work (:trac:`17598`):: - sage: len(cyclotomic_polynomial(3).roots(ZpFM(739, 566))) + sage: len(cyclotomic_polynomial(3).roots(ZpFM(739, 566))) # needs sage.rings.padics 2 Check that :trac:`26421` is fixed:: @@ -8093,15 +8370,16 @@ cdef class Polynomial(CommutativeAlgebraElement): Check that :trac:`31040` is fixed:: sage: R.<x> = QQ[] - sage: K.<a> = Qq(3).extension(x^2 + 1) - sage: (x^2 + 1).roots(K) + sage: K.<a> = Qq(3).extension(x^2 + 1) # needs sage.rings.padics + sage: (x^2 + 1).roots(K) # needs sage.rings.padics [(a + O(3^20), 1), - (2*a + 2*a*3 + 2*a*3^2 + 2*a*3^3 + 2*a*3^4 + 2*a*3^5 + 2*a*3^6 + 2*a*3^7 + 2*a*3^8 + 2*a*3^9 + 2*a*3^10 + 2*a*3^11 + 2*a*3^12 + 2*a*3^13 + 2*a*3^14 + 2*a*3^15 + 2*a*3^16 + 2*a*3^17 + 2*a*3^18 + 2*a*3^19 + O(3^20), + (2*a + 2*a*3 + 2*a*3^2 + 2*a*3^3 + 2*a*3^4 + 2*a*3^5 + 2*a*3^6 + 2*a*3^7 + 2*a*3^8 + 2*a*3^9 + 2*a*3^10 + + 2*a*3^11 + 2*a*3^12 + 2*a*3^13 + 2*a*3^14 + 2*a*3^15 + 2*a*3^16 + 2*a*3^17 + 2*a*3^18 + 2*a*3^19 + O(3^20), 1)] Check that :trac:`31710` is fixed:: - sage: CBF['x'].zero().roots(multiplicities=False) + sage: CBF['x'].zero().roots(multiplicities=False) # needs sage.libs.flint Traceback (most recent call last): ... ArithmeticError: taking the roots of the zero polynomial @@ -8114,7 +8392,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: a = randint(0, n - 1) sage: b = randint(0, n - 1) sage: f = (x - a) * (x - b) - sage: all(r.parent() is K for r in f.roots(multiplicities=False)) + sage: all(r.parent() is K for r in f.roots(multiplicities=False)) # needs sage.rings.finite_rings True """ from sage.rings.finite_rings.finite_field_constructor import GF @@ -8175,6 +8453,8 @@ cdef class Polynomial(CommutativeAlgebraElement): import numpy from numpy.linalg.linalg import LinAlgError + from sage.rings.complex_double import CDF + numpy_dtype = ('complex' if input_complex else 'double') ty = (complex if input_complex else float) coeffs = self.list() @@ -8194,6 +8474,8 @@ cdef class Polynomial(CommutativeAlgebraElement): if algorithm == 'pari': if not input_arbprec: + from sage.rings.real_mpfr import RR + from sage.rings.cc import CC self = self.change_ring(CC if input_complex else RR) ext_rts = self.__pari__().polroots(precision=L.prec()) @@ -8218,7 +8500,7 @@ cdef class Polynomial(CommutativeAlgebraElement): if isinstance(L, sage.rings.abc.SymbolicRing): if self.degree() == 2: from sage.misc.functional import sqrt - from sage.symbolic.expression import I + from sage.symbolic.constants import I coeffs = self.list() D = coeffs[1]*coeffs[1] - 4*coeffs[0]*coeffs[2] l = None @@ -8305,6 +8587,7 @@ cdef class Polynomial(CommutativeAlgebraElement): if isinstance(L, sage.rings.abc.ComplexDoubleField): real_field = RDF else: + from sage.rings.real_mpfr import RealField real_field = RealField(L.prec()) return self.change_ring(real_field).roots(ring=L, multiplicities=multiplicities, algorithm=algorithm) @@ -8379,11 +8662,11 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = ZZ[] sage: pol = 20*x^3 - 50*x^2 + 20*x - sage: F = pol.factor(); F + sage: F = pol.factor(); F # needs sage.libs.pari 2 * 5 * (x - 2) * x * (2*x - 1) - sage: pol._roots_from_factorization(F, multiplicities=True) + sage: pol._roots_from_factorization(F, multiplicities=True) # needs sage.libs.pari [(2, 1), (0, 1)] - sage: pol.change_ring(QQ)._roots_from_factorization(F, multiplicities=False) + sage: pol.change_ring(QQ)._roots_from_factorization(F, multiplicities=False) # needs sage.libs.pari [2, 0, 1/2] """ seq = [] @@ -8412,15 +8695,15 @@ cdef class Polynomial(CommutativeAlgebraElement): TESTS:: sage: Pols.<n> = QQ[] - sage: pol = (n - 1/2)^2*(n - 1)^2*(n-2) - sage: rts = pol.roots(ZZ, multiplicities=False); rts + sage: pol = (n - 1/2)^2 * (n - 1)^2 * (n - 2) + sage: rts = pol.roots(ZZ, multiplicities=False); rts # needs sage.libs.pari [2, 1] - sage: rts[0].parent() + sage: rts[0].parent() # needs sage.libs.pari Integer Ring sage: Pols_x.<x> = QQ[] sage: Pols_xy.<y> = Pols_x[] - sage: ((y - 1)*(y - x))._roots_in_subring(QQ, True, None) + sage: ((y - 1)*(y - x))._roots_in_subring(QQ, True, None) # needs sage.libs.singular [(1, 1)] """ K = self._parent.base_ring() @@ -8446,33 +8729,35 @@ cdef class Polynomial(CommutativeAlgebraElement): """ Return the real roots of this polynomial, without multiplicities. - Calls self.roots(ring=RR), unless this is a polynomial with + Calls ``self.roots(ring=RR)``, unless this is a polynomial with floating-point real coefficients, in which case it calls - self.roots(). + ``self.roots()``. EXAMPLES:: sage: x = polygen(ZZ) - sage: (x^2 - x - 1).real_roots() + sage: (x^2 - x - 1).real_roots() # needs sage.rings.real_mpfr [-0.618033988749895, 1.61803398874989] TESTS:: - sage: x = polygen(RealField(100)) - sage: (x^2 - x - 1).real_roots()[0].parent() + sage: x = polygen(RealField(100)) # needs sage.rings.real_mpfr + sage: (x^2 - x - 1).real_roots()[0].parent() # needs sage.rings.real_mpfr Real Field with 100 bits of precision sage: x = polygen(RDF) - sage: (x^2 - x - 1).real_roots()[0].parent() + sage: (x^2 - x - 1).real_roots()[0].parent() # needs numpy Real Double Field - sage: x=polygen(ZZ,'x'); v=(x^2-x-1).real_roots() - sage: v[0].parent() is RR + sage: x = polygen(ZZ,'x'); v = (x^2 - x - 1).real_roots() # needs sage.rings.real_mpfr + sage: v[0].parent() is RR # needs sage.rings.real_mpfr True """ K = self.base_ring() if isinstance(K, (sage.rings.abc.RealField, sage.rings.abc.RealDoubleField)): return self.roots(multiplicities=False) + from sage.rings.real_mpfr import RR + return self.roots(ring=RR, multiplicities=False) def complex_roots(self): @@ -8480,65 +8765,76 @@ cdef class Polynomial(CommutativeAlgebraElement): Return the complex roots of this polynomial, without multiplicities. - Calls self.roots(ring=CC), unless this is a polynomial with + Calls ``self.roots(ring=CC)``, unless this is a polynomial with floating-point coefficients, in which case it is uses the appropriate precision from the input coefficients. EXAMPLES:: sage: x = polygen(ZZ) - sage: (x^3 - 1).complex_roots() # note: low order bits slightly different on ppc. - [1.00000000000000, -0.500000000000000 - 0.86602540378443...*I, -0.500000000000000 + 0.86602540378443...*I] + sage: (x^3 - 1).complex_roots() # note: low order bits slightly different on ppc. # needs sage.rings.real_mpfr + [1.00000000000000, + -0.500000000000000 - 0.86602540378443...*I, + -0.500000000000000 + 0.86602540378443...*I] TESTS:: - sage: x = polygen(RR) - sage: (x^3 - 1).complex_roots()[0].parent() + sage: x = polygen(RR) # needs sage.rings.real_mpfr + sage: (x^3 - 1).complex_roots()[0].parent() # needs sage.rings.real_mpfr Complex Field with 53 bits of precision + sage: x = polygen(RDF) - sage: (x^3 - 1).complex_roots()[0].parent() + sage: (x^3 - 1).complex_roots()[0].parent() # needs numpy Complex Double Field - sage: x = polygen(RealField(200)) - sage: (x^3 - 1).complex_roots()[0].parent() + + sage: x = polygen(RealField(200)) # needs sage.rings.real_mpfr + sage: (x^3 - 1).complex_roots()[0].parent() # needs sage.rings.real_mpfr Complex Field with 200 bits of precision - sage: x = polygen(CDF) - sage: (x^3 - 1).complex_roots()[0].parent() + + sage: x = polygen(CDF) # needs sage.rings.complex_double + sage: (x^3 - 1).complex_roots()[0].parent() # needs numpy sage.rings.complex_double Complex Double Field + + + sage: # needs sage.rings.real_mpfr sage: x = polygen(ComplexField(200)) sage: (x^3 - 1).complex_roots()[0].parent() Complex Field with 200 bits of precision - sage: x=polygen(ZZ,'x'); v=(x^2-x-1).complex_roots() + sage: x = polygen(ZZ,'x'); v=(x^2-x-1).complex_roots() sage: v[0].parent() is CC True """ K = self.base_ring() if isinstance(K, sage.rings.abc.RealField): + from sage.rings.complex_mpfr import ComplexField return self.roots(ring=ComplexField(K.prec()), multiplicities=False) if isinstance(K, sage.rings.abc.RealDoubleField): + from sage.rings.complex_double import CDF return self.roots(ring=CDF, multiplicities=False) if isinstance(K, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)): return self.roots(multiplicities=False) - + from sage.rings.cc import CC return self.roots(ring=CC, multiplicities=False) def number_of_roots_in_interval(self, a=None, b=None): r""" Return the number of roots of this polynomial in the interval - [a,b], counted without multiplicity. The endpoints a, b default to - -Infinity, Infinity (which are also valid input values). + `[a,b]`, counted without multiplicity. The endpoints `a`, `b` default to + ``-Infinity``, ``Infinity`` (which are also valid input values). Calls the PARI routine :pari:`polsturm`. Note that as of version 2.8, PARI includes the left endpoint of the interval (and no longer uses Sturm's algorithm on exact - inputs). polsturm requires a polynomial with real + inputs). :pari:`polsturm` requires a polynomial with real coefficients; in case PARI returns an error, we try again - after taking the GCD of `self` with its complex conjugate. + after taking the GCD of ``self`` with its complex conjugate. EXAMPLES:: + sage: # needs sage.libs.pari sage: R.<x> = PolynomialRing(ZZ) - sage: pol = (x-1)^2 * (x-2)^2 * (x-3) + sage: pol = (x - 1)^2 * (x - 2)^2 * (x - 3) sage: pol.number_of_roots_in_interval(1, 2) 2 sage: pol.number_of_roots_in_interval(1.01, 2) @@ -8549,25 +8845,28 @@ cdef class Polynomial(CommutativeAlgebraElement): 3 sage: pol.number_of_roots_in_interval() 3 - sage: pol = (x-1)*(x-2)*(x-3) + sage: pol = (x - 1) * (x - 2) * (x - 3) + + sage: # needs sage.libs.pari sage.rings.real_mpfr sage: pol2 = pol.change_ring(CC) sage: pol2.number_of_roots_in_interval() 3 sage: R.<x> = PolynomialRing(CC) - sage: pol = (x-1)*(x-CC(I)) - sage: pol.number_of_roots_in_interval(0,2) + sage: pol = (x - 1) * (x - CC(I)) + sage: pol.number_of_roots_in_interval(0, 2) 1 TESTS:: + sage: # needs sage.libs.pari sage: R.<x> = PolynomialRing(ZZ) - sage: pol = (x-1)^2 * (x-2)^2 * (x-3) + sage: pol = (x - 1)^2 * (x - 2)^2 * (x - 3) sage: pol.number_of_roots_in_interval(1, 2) 2 sage: pol = chebyshev_T(5,x) - sage: pol.number_of_roots_in_interval(-1,2) + sage: pol.number_of_roots_in_interval(-1, 2) 5 - sage: pol.number_of_roots_in_interval(0,2) + sage: pol.number_of_roots_in_interval(0, 2) 3 """ @@ -8595,16 +8894,19 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: R.<x> = PolynomialRing(ZZ) - sage: pol = (x-1)^2 * (x-2)^2 * (x-3) + sage: pol = (x - 1)^2 * (x - 2)^2 * (x - 3) sage: pol.number_of_real_roots() 3 - sage: pol = (x-1)*(x-2)*(x-3) + sage: pol = (x - 1) * (x - 2) * (x - 3) + + sage: # needs sage.libs.pari sage.rings.real_mpfr sage: pol2 = pol.change_ring(CC) sage: pol2.number_of_real_roots() 3 sage: R.<x> = PolynomialRing(CC) - sage: pol = (x-1)*(x-CC(I)) + sage: pol = (x - 1) * (x - CC(I)) sage: pol.number_of_real_roots() 1 """ @@ -8612,22 +8914,23 @@ cdef class Polynomial(CommutativeAlgebraElement): def all_roots_in_interval(self, a=None, b=None): r""" - Return True if the roots of this polynomial are all real and + Return ``True`` if the roots of this polynomial are all real and contained in the given interval. EXAMPLES:: + sage: # needs sage.libs.pari sage: R.<x> = PolynomialRing(ZZ) - sage: pol = (x-1)^2 * (x-2)^2 * (x-3) + sage: pol = (x - 1)^2 * (x - 2)^2 * (x - 3) sage: pol.all_roots_in_interval(1, 3) True sage: pol.all_roots_in_interval(1.01, 3) False - sage: pol = chebyshev_T(5,x) - sage: pol.all_roots_in_interval(-1,1) + sage: pol = chebyshev_T(5, x) + sage: pol.all_roots_in_interval(-1, 1) True - sage: pol = chebyshev_T(5,x/2) - sage: pol.all_roots_in_interval(-1,1) + sage: pol = chebyshev_T(5, x/2) + sage: pol.all_roots_in_interval(-1, 1) False sage: pol.all_roots_in_interval() True @@ -8637,10 +8940,11 @@ cdef class Polynomial(CommutativeAlgebraElement): def is_real_rooted(self): r""" - Return True if the roots of this polynomial are all real. + Return ``True`` if the roots of this polynomial are all real. EXAMPLES:: + sage: # needs sage.libs.pari sage: R.<x> = PolynomialRing(ZZ) sage: pol = chebyshev_T(5, x) sage: pol.is_real_rooted() @@ -8677,7 +8981,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: pol.<x> = PolynomialRing(Rationals()) - sage: u = x^2+x-1 + sage: u = x^2 + x - 1 sage: u.reciprocal_transform() x^4 + x^3 + x^2 + x + 1 sage: u.reciprocal_transform(R=x-1) @@ -8727,7 +9031,8 @@ cdef class Polynomial(CommutativeAlgebraElement): We check that this function works for rings that have a coercion to the reals:: - sage: K.<a> = NumberField(x^2-2,embedding=1.4) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^2 - 2, embedding=1.4) sage: u = x^4 + a*x^3 + 3*x^2 + 2*a*x + 4 sage: u.trace_polynomial() (x^2 + a*x - 1, 1, 2) @@ -8789,7 +9094,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def is_weil_polynomial(self, return_q=False): r""" - Return True if this is a Weil polynomial. + Return ``True`` if this is a Weil polynomial. This polynomial must have rational or integer coefficients. @@ -8798,8 +9103,8 @@ cdef class Polynomial(CommutativeAlgebraElement): - ``self`` -- polynomial with rational or integer coefficients - ``return_q`` -- (default ``False``) if ``True``, return a second value `q` - which is the prime power with respect to which this is `q`-Weil, - or 0 if there is no such value. + which is the prime power with respect to which this is `q`-Weil, + or 0 if there is no such value. EXAMPLES:: @@ -8807,20 +9112,20 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: P0 = x^4 + 5*x^3 + 15*x^2 + 25*x + 25 sage: P1 = x^4 + 25*x^3 + 15*x^2 + 5*x + 25 sage: P2 = x^4 + 5*x^3 + 25*x^2 + 25*x + 25 - sage: P0.is_weil_polynomial(return_q=True) + sage: P0.is_weil_polynomial(return_q=True) # needs sage.libs.pari (True, 5) - sage: P0.is_weil_polynomial(return_q=False) + sage: P0.is_weil_polynomial(return_q=False) # needs sage.libs.pari True sage: P1.is_weil_polynomial(return_q=True) (False, 0) sage: P1.is_weil_polynomial(return_q=False) False - sage: P2.is_weil_polynomial() + sage: P2.is_weil_polynomial() # needs sage.libs.pari False .. SEEALSO:: - Polynomial rings have a method `weil_polynomials` to compute sets of Weil + Polynomial rings have a method :meth:`weil_polynomials` to compute sets of Weil polynomials. This computation uses the iterator :class:`sage.rings.polynomial.weil.weil_polynomials.WeilPolynomials`. @@ -8830,7 +9135,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: P.<t> = QQ[] sage: u = t^10 + 4*t^9 + 8*t^8 + 18*t^7 + 81*t^6 + 272*t^5 + 567*t^4 + 882*t^3 + 2744*t^2 + 9604*t + 16807 - sage: u.is_weil_polynomial() + sage: u.is_weil_polynomial() # needs sage.libs.pari True AUTHORS: @@ -8856,6 +9161,63 @@ cdef class Polynomial(CommutativeAlgebraElement): else: return b + def is_lorentzian(self, explain=False): + r""" + Return ``True`` if this is a Lorentzian polynomial. + + A univariate real polynomial is Lorentzian if and only if it is a + monomial with positive coefficient, or zero. The definition is more + involved for multivariate real polynomials. + + INPUT: + + - ``explain`` -- boolean (default: ``False``); if ``True`` + return a tuple whose first element is the boolean result of the test, + and the second element is a string describing the reason the test failed, + or ``None`` if the test succeeded + + EXAMPLES:: + + sage: P.<x> = QQ[] + sage: p1 = x^2 + sage: p1.is_lorentzian() + True + sage: p2 = 1 + x^2 + sage: p2.is_lorentzian() + False + sage: p3 = P.zero() + sage: p3.is_lorentzian() + True + sage: p4 = -2*x^3 + sage: p4.is_lorentzian() + False + + It is an error to check if a polynomial is Lorentzian if its base ring + is not a subring of the real numbers, as the notion is not defined in + this case:: + + sage: Q.<y> = CC[] + sage: q = y^2 + sage: q.is_lorentzian() + Traceback (most recent call last): + ... + NotImplementedError: is_lorentzian only implemented for real polynomials + + The method can give a reason for a polynomial failing to be Lorentzian:: + + sage: p = x^2 + 2*x + sage: p.is_lorentzian(explain=True) + (False, 'inhomogeneous') + + REFERENCES: + + For full definitions and related discussion, see [BrHu2019]_ and + [HMMS2019]_. + """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + + R = PolynomialRing(self.base_ring(), 1, [self.variable_name()]) + return R(self).is_lorentzian(explain=explain) def variable_name(self): """ @@ -8891,11 +9253,12 @@ cdef class Polynomial(CommutativeAlgebraElement): The actual algorithm for computing the extended gcd depends on the base ring underlying the polynomial ring. If the base ring defines - a method ``_xgcd_univariate_polynomial``, then this method will be + a method :meth:`_xgcd_univariate_polynomial`, then this method will be called (see examples below). EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = QQbar[] sage: (2*x^2).gcd(2*x) x @@ -8905,7 +9268,7 @@ cdef class Polynomial(CommutativeAlgebraElement): x One can easily add xgcd functionality to new rings by providing a - method ``_xgcd_univariate_polynomial``:: + method :meth:`_xgcd_univariate_polynomial`:: sage: R.<x> = QQ[] sage: S.<y> = R[] @@ -8914,12 +9277,13 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: h1.xgcd(h2) Traceback (most recent call last): ... - NotImplementedError: Univariate Polynomial Ring in x over Rational Field does not provide an xgcd implementation for univariate polynomials + NotImplementedError: Univariate Polynomial Ring in x over Rational Field + does not provide an xgcd implementation for univariate polynomials sage: T.<x,y> = QQ[] - sage: def poor_xgcd(f,g): + sage: def poor_xgcd(f, g): ....: ret = S(T(f).gcd(g)) - ....: if ret == f: return ret,S.one(),S.zero() - ....: if ret == g: return ret,S.zero(),S.one() + ....: if ret == f: return ret, S.one(), S.zero() + ....: if ret == g: return ret, S.zero(), S.one() ....: raise NotImplementedError sage: R._xgcd_univariate_polynomial = poor_xgcd sage: h1.xgcd(h2) @@ -8957,10 +9321,10 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: z = PolynomialRing(QQ, 'z').gen() sage: p = -z**16 - z**15 - z**14 + z**13 + z**12 + z**11 - z**5 - z**4 - z**3 + z**2 + z + 1 sage: m = z**21 - sage: n, d = p.rational_reconstruction(m) - sage: print((n ,d)) - (z^4 + 2*z^3 + 3*z^2 + 2*z + 1, z^10 + z^9 + z^8 + z^7 + z^6 + z^5 + z^4 + z^3 + z^2 + z + 1) - sage: print(((p*d - n) % m ).is_zero()) + sage: n, d = p.rational_reconstruction(m); n, d + (z^4 + 2*z^3 + 3*z^2 + 2*z + 1, + z^10 + z^9 + z^8 + z^7 + z^6 + z^5 + z^4 + z^3 + z^2 + z + 1) + sage: ((p*d - n) % m).is_zero() True Over `\ZZ[z]`:: @@ -8968,27 +9332,25 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: z = PolynomialRing(ZZ, 'z').gen() sage: p = -z**16 - z**15 - z**14 + z**13 + z**12 + z**11 - z**5 - z**4 - z**3 + z**2 + z + 1 sage: m = z**21 - sage: n, d = p.rational_reconstruction(m) - sage: print((n ,d)) - (z^4 + 2*z^3 + 3*z^2 + 2*z + 1, z^10 + z^9 + z^8 + z^7 + z^6 + z^5 + z^4 + z^3 + z^2 + z + 1) - sage: print(((p*d - n) % m ).is_zero()) + sage: n, d = p.rational_reconstruction(m); n, d + (z^4 + 2*z^3 + 3*z^2 + 2*z + 1, + z^10 + z^9 + z^8 + z^7 + z^6 + z^5 + z^4 + z^3 + z^2 + z + 1) + sage: ((p*d - n) % m).is_zero() True - Over an integral domain ``d`` might not be monic:: + Over an integral domain, ``d`` might not be monic:: - sage: P = PolynomialRing(ZZ,'x') + sage: P = PolynomialRing(ZZ, 'x') sage: x = P.gen() sage: p = 7*x^5 - 10*x^4 + 16*x^3 - 32*x^2 + 128*x + 256 sage: m = x^5 - sage: n, d = p.rational_reconstruction(m, 3, 2) - sage: print((n ,d)) + sage: n, d = p.rational_reconstruction(m, 3, 2); n, d (-32*x^3 + 384*x^2 + 2304*x + 2048, 5*x + 8) - sage: print(((p*d - n) % m ).is_zero()) + sage: ((p*d - n) % m).is_zero() True - sage: n, d = p.rational_reconstruction(m, 4, 0) - sage: print((n ,d)) + sage: n, d = p.rational_reconstruction(m, 4, 0); n, d (-10*x^4 + 16*x^3 - 32*x^2 + 128*x + 256, 1) - sage: print(((p*d - n) % m ).is_zero()) + sage: ((p*d - n) % m).is_zero() True Over `\QQ(t)[z]`:: @@ -9000,17 +9362,17 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: # p = (1 + t^2*z + z^4) / (1 - t*z) sage: p = (1 + t^2*z + z^4)*(1 - t*z).inverse_mod(z^9) sage: m = z^9 - sage: n, d = p.rational_reconstruction(m) - sage: print((n ,d)) + sage: n, d = p.rational_reconstruction(m); n, d (-1/t*z^4 - t*z - 1/t, z - 1/t) - sage: print(((p*d - n) % m ).is_zero()) + sage: ((p*d - n) % m).is_zero() True sage: w = PowerSeriesRing(P.fraction_field(), 'w').gen() sage: n = -10*t^2*z^4 + (-t^2 + t - 1)*z^3 + (-t - 8)*z^2 + z + 2*t^2 - t sage: d = z^4 + (2*t + 4)*z^3 + (-t + 5)*z^2 + (t^2 + 2)*z + t^2 + 2*t + 1 sage: prec = 9 - sage: nc, dc = Pz((n.subs(z = w)/d.subs(z = w) + O(w^prec)).list()).rational_reconstruction(z^prec) - sage: print( (nc, dc) == (n, d) ) + sage: x = n.subs(z=w)/d.subs(z=w) + O(w^prec) + sage: nc, dc = Pz(x.list()).rational_reconstruction(z^prec) + sage: (nc, dc) == (n, d) True Over `\QQ[t][z]`:: @@ -9021,70 +9383,64 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: # p = (1 + t^2*z + z^4) / (1 - t*z) mod z^9 sage: p = (1 + t^2*z + z^4) * sum((t*z)**i for i in range(9)) sage: m = z^9 - sage: n, d = p.rational_reconstruction(m,) - sage: print((n ,d)) + sage: n, d = p.rational_reconstruction(m,); n, d (-z^4 - t^2*z - 1, t*z - 1) - sage: print(((p*d - n) % m ).is_zero()) + sage: ((p*d - n) % m).is_zero() True Over `\QQ_5`:: - sage: x = PolynomialRing(Qp(5),'x').gen() + sage: # needs sage.rings.padics + sage: x = PolynomialRing(Qp(5), 'x').gen() sage: p = 4*x^5 + 3*x^4 + 2*x^3 + 2*x^2 + 4*x + 2 sage: m = x^6 sage: n, d = p.rational_reconstruction(m, 3, 2) - sage: print(((p*d - n) % m ).is_zero()) + sage: ((p*d - n) % m).is_zero() True Can also be used to obtain known Padรฉ approximations:: sage: z = PowerSeriesRing(QQ, 'z').gen() - sage: P = PolynomialRing(QQ,'x') + sage: P = PolynomialRing(QQ, 'x') sage: x = P.gen() - sage: p = P(exp(z).list()) + sage: p = P(z.exp().list()) sage: m = x^5 - sage: n, d = p.rational_reconstruction(m, 4, 0) - sage: print((n ,d)) + sage: n, d = p.rational_reconstruction(m, 4, 0); n, d (1/24*x^4 + 1/6*x^3 + 1/2*x^2 + x + 1, 1) - sage: print(((p*d - n) % m ).is_zero()) + sage: ((p*d - n) % m).is_zero() True sage: m = x^3 - sage: n, d = p.rational_reconstruction(m, 1, 1) - sage: print((n ,d)) + sage: n, d = p.rational_reconstruction(m, 1, 1); n, d (-x - 2, x - 2) - sage: print(((p*d - n) % m ).is_zero()) + sage: ((p*d - n) % m).is_zero() True sage: p = P(log(1-z).list()) sage: m = x^9 - sage: n, d = p.rational_reconstruction(m, 4, 4) - sage: print((n ,d)) + sage: n, d = p.rational_reconstruction(m, 4, 4); n, d (25/6*x^4 - 130/3*x^3 + 105*x^2 - 70*x, x^4 - 20*x^3 + 90*x^2 - 140*x + 70) - sage: print(((p*d - n) % m ).is_zero()) + sage: ((p*d - n) % m).is_zero() True sage: p = P(sqrt(1+z).list()) sage: m = x^6 - sage: n, d = p.rational_reconstruction(m, 3, 2) - sage: print((n ,d)) + sage: n, d = p.rational_reconstruction(m, 3, 2); n, d (1/6*x^3 + 3*x^2 + 8*x + 16/3, x^2 + 16/3*x + 16/3) - sage: print(((p*d - n) % m ).is_zero()) + sage: ((p*d - n) % m).is_zero() True - sage: p = P(exp(2*z).list()) + sage: p = P((2*z).exp().list()) sage: m = x^7 - sage: n, d = p.rational_reconstruction(m, 3, 3) - sage: print((n ,d)) + sage: n, d = p.rational_reconstruction(m, 3, 3); n, d (-x^3 - 6*x^2 - 15*x - 15, x^3 - 6*x^2 + 15*x - 15) - sage: print(((p*d - n) % m ).is_zero()) + sage: ((p*d - n) % m).is_zero() True Over `\RR[z]`:: sage: z = PowerSeriesRing(RR, 'z').gen() - sage: P = PolynomialRing(RR,'x') + sage: P = PolynomialRing(RR, 'x') sage: x = P.gen() - sage: p = P(exp(2*z).list()) + sage: p = P((2*z).exp().list()) sage: m = x^7 - sage: n, d = p.rational_reconstruction(m, 3, 3) - sage: print((n ,d)) # absolute tolerance 1e-10 + sage: n, d = p.rational_reconstruction(m, 3, 3); n, d # absolute tolerance 1e-10 (-x^3 - 6.0*x^2 - 15.0*x - 15.0, x^3 - 6.0*x^2 + 15.0*x - 15.0) .. SEEALSO:: @@ -9106,7 +9462,7 @@ cdef class Polynomial(CommutativeAlgebraElement): l = lcm([n.denominator(), d.denominator()]) n *= l d *= l - return P(n), P(d) + return P(n), P(d) # n and d are unique if m.degree() > (n.degree() + d.degree()) if n_deg is None: @@ -9195,20 +9551,20 @@ cdef class Polynomial(CommutativeAlgebraElement): `\infty`. If a prime (or non-prime) `p` is given, then the valuation - is the largest power of `p` which divides self. + is the largest power of `p` which divides ``self``. - The valuation at `\infty` is -self.degree(). + The valuation at `\infty` is ``-self.degree()``. EXAMPLES:: sage: P.<x> = ZZ[] - sage: (x^2+x).valuation() + sage: (x^2 + x).valuation() 1 - sage: (x^2+x).valuation(x+1) + sage: (x^2 + x).valuation(x + 1) 1 - sage: (x^2+1).valuation() + sage: (x^2 + 1).valuation() 0 - sage: (x^3+1).valuation(infinity) + sage: (x^3 + 1).valuation(infinity) -3 sage: P(0).valuation() +Infinity @@ -9250,21 +9606,21 @@ cdef class Polynomial(CommutativeAlgebraElement): def ord(self, p=None): r""" - This is the same as the valuation of self at p. See the - documentation for ``self.valuation``. + This is the same as the valuation of ``self`` at `p`. See the + documentation for :meth:`valuation`. EXAMPLES:: sage: R.<x> = ZZ[] - sage: (x^2+x).ord(x+1) + sage: (x^2 + x).ord(x + 1) 1 """ return self.valuation(p) def add_bigoh(self, prec): r""" - Return the power series of precision at most prec got by adding - `O(q^\text{prec})` to self, where q is its variable. + Return the power series of precision at most ``prec`` got by adding + `O(q^\text{prec})` to self, where `q` is its variable. EXAMPLES:: @@ -9287,11 +9643,11 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: R.<x> = ZZ[] - sage: (x^3 + 1).is_irreducible() + sage: (x^3 + 1).is_irreducible() # needs sage.libs.pari False - sage: (x^2 - 1).is_irreducible() + sage: (x^2 - 1).is_irreducible() # needs sage.libs.pari False - sage: (x^3 + 2).is_irreducible() + sage: (x^3 + 2).is_irreducible() # needs sage.libs.pari True sage: R(0).is_irreducible() False @@ -9300,15 +9656,16 @@ cdef class Polynomial(CommutativeAlgebraElement): polynomial in `\QQ[x]`, but not in `\ZZ[x]`:: sage: R.<x> = ZZ[] - sage: R(2*x).is_irreducible() + sage: R(2*x).is_irreducible() # needs sage.libs.pari False sage: R.<x> = QQ[] - sage: R(2*x).is_irreducible() + sage: R(2*x).is_irreducible() # needs sage.libs.pari True TESTS:: - sage: F.<t> = NumberField(x^2-5) + sage: # needs sage.rings.number_field + sage: F.<t> = NumberField(x^2 - 5) sage: Fx.<xF> = PolynomialRing(F) sage: f = Fx([2*t - 5, 5*t - 10, 3*t - 6, -t, -t + 2, 1]) sage: f.is_irreducible() @@ -9321,10 +9678,10 @@ cdef class Polynomial(CommutativeAlgebraElement): then this method gets used instead of the generic algorithm which just factors the input:: - sage: R.<x> = QQbar[] - sage: hasattr(QQbar, "_is_irreducible_univariate_polynomial") + sage: R.<x> = QQbar[] # needs sage.rings.number_field + sage: hasattr(QQbar, "_is_irreducible_univariate_polynomial") # needs sage.rings.number_field True - sage: (x^2 + 1).is_irreducible() + sage: (x^2 + 1).is_irreducible() # needs sage.rings.number_field False Constants can be irreducible if they are not units:: @@ -9340,9 +9697,9 @@ cdef class Polynomial(CommutativeAlgebraElement): Check that caching works:: sage: R.<x> = ZZ[] - sage: x.is_irreducible() + sage: x.is_irreducible() # needs sage.libs.pari True - sage: x.is_irreducible.cache + sage: x.is_irreducible.cache # needs sage.libs.pari True @@ -9442,13 +9799,13 @@ cdef class Polynomial(CommutativeAlgebraElement): cpdef Polynomial truncate(self, long n): r""" - Return the polynomial of degree ` < n` which is equivalent + Return the polynomial of degree `< n` which is equivalent to self modulo `x^n`. EXAMPLES:: sage: R.<x> = ZZ[]; S.<y> = PolynomialRing(R, sparse=True) - sage: f = y^3 + x*y -3*x; f + sage: f = y^3 + x*y - 3*x; f y^3 + x*y - 3*x sage: f.truncate(2) x*y - 3*x @@ -9458,7 +9815,7 @@ cdef class Polynomial(CommutativeAlgebraElement): 0 """ # __getitem__ already returns a polynomial!! - # We must not have check=False, since 0 must not have __coeffs = [0]. + # We must not have check=False, since 0 must not have _coeffs = [0]. return <Polynomial>self._parent(self[:n])#, check=False) cdef _inplace_truncate(self, long prec): @@ -9467,7 +9824,7 @@ cdef class Polynomial(CommutativeAlgebraElement): @cached_method def is_squarefree(self): """ - Return False if this polynomial is not square-free, i.e., if there is a + Return ``False`` if this polynomial is not square-free, i.e., if there is a non-unit `g` in the polynomial ring such that `g^2` divides ``self``. .. WARNING:: @@ -9479,16 +9836,17 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: R.<x> = QQ[] - sage: f = (x-1)*(x-2)*(x^2-5)*(x^17-3); f + sage: f = (x-1) * (x-2) * (x^2-5) * (x^17-3); f x^21 - 3*x^20 - 3*x^19 + 15*x^18 - 10*x^17 - 3*x^4 + 9*x^3 + 9*x^2 - 45*x + 30 sage: f.is_squarefree() True - sage: (f*(x^2-5)).is_squarefree() + sage: (f * (x^2-5)).is_squarefree() False A generic implementation is available, which relies on gcd computations:: + sage: # needs sage.libs.pari sage: R.<x> = ZZ[] sage: (2*x).is_squarefree() True @@ -9498,6 +9856,7 @@ cdef class Polynomial(CommutativeAlgebraElement): False sage: R(0).is_squarefree() False + sage: S.<y> = QQ[] sage: R.<x> = S[] sage: (2*x*y).is_squarefree() @@ -9511,13 +9870,13 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: K.<t> = FunctionField(GF(3)) sage: R.<x> = K[] - sage: (x^3-x).is_squarefree() + sage: (x^3 - x).is_squarefree() True - sage: (x^3-1).is_squarefree() + sage: (x^3 - 1).is_squarefree() # needs sage.libs.pari False - sage: (x^3+t).is_squarefree() + sage: (x^3 + t).is_squarefree() # needs sage.libs.pari True - sage: (x^3+t^3).is_squarefree() + sage: (x^3 + t^3).is_squarefree() # needs sage.libs.pari False In the following example, `t^2` is a unit in the base field:: @@ -9529,28 +9888,29 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = ZZ[] sage: f = 4 * x - sage: f.is_squarefree() + sage: f.is_squarefree() # needs sage.libs.pari False - sage: f.squarefree_decomposition() + sage: f.squarefree_decomposition() # needs sage.libs.pari (4) * x If you want this method equally not to consider the content, you can remove it as in the following example:: sage: c = f.content() - sage: (f/c).is_squarefree() + sage: (f/c).is_squarefree() # needs sage.libs.pari True If the base ring is not an integral domain, the question is not mathematically well-defined:: sage: R.<x> = IntegerModRing(9)[] - sage: pol = (x + 3)*(x + 6); pol + sage: pol = (x + 3) * (x + 6); pol x^2 sage: pol.is_squarefree() Traceback (most recent call last): ... - TypeError: is_squarefree() is not defined for polynomials over Ring of integers modulo 9 + TypeError: is_squarefree() is not defined for + polynomials over Ring of integers modulo 9 TESTS: @@ -9558,7 +9918,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.<x> = ZZ[] sage: f = x^2 - sage: f.is_squarefree() + sage: f.is_squarefree() # needs sage.libs.pari False sage: f.is_squarefree.cache False @@ -9567,6 +9927,7 @@ cdef class Polynomial(CommutativeAlgebraElement): then this method gets used instead of the generic algorithm in :meth:`_is_squarefree_generic`:: + sage: # needs sage.rings.number_field sage: R.<x> = QQbar[] sage: (x^2).is_squarefree() False @@ -9595,10 +9956,10 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: R.<x> = QQbar[] - sage: (x^2*(x + 1)).is_squarefree() # indirect doctest + sage: R.<x> = QQbar[] # needs sage.rings.number_field + sage: (x^2*(x + 1)).is_squarefree() # indirect doctest # needs sage.rings.number_field False - sage: (x*(x+1)).is_squarefree() # indirect doctest + sage: (x*(x+1)).is_squarefree() # indirect doctest # needs sage.rings.number_field True """ @@ -9630,12 +9991,12 @@ cdef class Polynomial(CommutativeAlgebraElement): def radical(self): """ - Return the radical of self. + Return the radical of ``self``. Over a field, this is the product of - the distinct irreducible factors of self. (This is also sometimes - called the "square-free part" of self, but that term is ambiguous; - it is sometimes used to mean the quotient of self by its maximal + the distinct irreducible factors of ``self``. (This is also sometimes + called the "square-free part" of ``self``, but that term is ambiguous; + it is sometimes used to mean the quotient of ``self`` by its maximal square factor.) EXAMPLES:: @@ -9650,7 +10011,7 @@ cdef class Polynomial(CommutativeAlgebraElement): If self has a factor of multiplicity divisible by the characteristic (see :trac:`8736`):: sage: P.<x> = GF(2)[] - sage: (x^3 + x^2).radical() + sage: (x^3 + x^2).radical() # needs sage.rings.finite_rings x^2 + x """ P = self._parent @@ -9709,38 +10070,39 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: R.<x> = RR[] sage: f = x^6 + x^2 + -x^4 - 2*x^3 sage: f.norm(2) 2.64575131106459 - sage: (sqrt(1^2 + 1^2 + (-1)^2 + (-2)^2)).n() + sage: (sqrt(1^2 + 1^2 + (-1)^2 + (-2)^2)).n() # needs sage.symbolic 2.64575131106459 :: - sage: f.norm(1) + sage: f.norm(1) # needs sage.rings.real_mpfr 5.00000000000000 - sage: f.norm(infinity) + sage: f.norm(infinity) # needs sage.rings.real_mpfr 2.00000000000000 :: - sage: f.norm(-1) + sage: f.norm(-1) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: The degree of the norm must be positive TESTS:: - sage: R.<x> = RR[] - sage: f = x^6 + x^2 + -x^4 -x^3 - sage: f.norm(int(2)) + sage: R.<x> = RR[] # needs sage.rings.real_mpfr + sage: f = x^6 + x^2 + -x^4 -x^3 # needs sage.rings.real_mpfr + sage: f.norm(int(2)) # needs sage.rings.real_mpfr 2.00000000000000 Check that :trac:`18600` is fixed:: sage: R.<x> = PolynomialRing(ZZ, sparse=True) - sage: (x^2^100 + 1).norm(1) + sage: (x^2^100 + 1).norm(1) # needs sage.rings.real_mpfr 2.00000000000000 AUTHORS: @@ -9748,7 +10110,9 @@ cdef class Polynomial(CommutativeAlgebraElement): - Didier Deshommes - William Stein: fix bugs, add definition, etc. """ - if p <= 0 : + from sage.rings.real_mpfr import RR + + if p <= 0: raise ValueError("The degree of the norm must be positive") coeffs = self.coefficients() @@ -9776,7 +10140,7 @@ cdef class Polynomial(CommutativeAlgebraElement): 2 sage: R(0).number_of_terms() 0 - sage: f = (x+1)^100 + sage: f = (x + 1)^100 sage: f.number_of_terms() 101 sage: S = GF(5)['y'] @@ -9806,53 +10170,55 @@ cdef class Polynomial(CommutativeAlgebraElement): If ``f`` is a :class:`sage.categories.map.Map`, then the resulting polynomial will be defined over the codomain of ``f``. Otherwise, the - resulting polynomial will be over the same ring as self. Set + resulting polynomial will be over the same ring as ``self``. Set ``new_base_ring`` to override this behaviour. INPUT: - - ``f`` -- a callable that will be applied to the coefficients of self. + - ``f`` -- a callable that will be applied to the coefficients of ``self``. - ``new_base_ring`` (optional) -- if given, the resulting polynomial will be defined over this ring. EXAMPLES:: - sage: R.<x> = SR[] - sage: f = (1+I)*x^2 + 3*x - I - sage: f.map_coefficients(lambda z: z.conjugate()) - (-I + 1)*x^2 + 3*x + I sage: R.<x> = ZZ[] sage: f = x^2 + 2 sage: f.map_coefficients(lambda a: a + 42) 43*x^2 + 44 - sage: R.<x> = PolynomialRing(SR, sparse=True) - sage: f = (1+I)*x^(2^32) - I - sage: f.map_coefficients(lambda z: z.conjugate()) - (-I + 1)*x^4294967296 + I sage: R.<x> = PolynomialRing(ZZ, sparse=True) sage: f = x^(2^32) + 2 sage: f.map_coefficients(lambda a: a + 42) 43*x^4294967296 + 44 + sage: # needs sage.symbolic + sage: R.<x> = SR[] + sage: f = (1+I)*x^2 + 3*x - I + sage: f.map_coefficients(lambda z: z.conjugate()) + (-I + 1)*x^2 + 3*x + I + sage: R.<x> = PolynomialRing(SR, sparse=True) + sage: f = (1+I)*x^(2^32) - I + sage: f.map_coefficients(lambda z: z.conjugate()) + (-I + 1)*x^4294967296 + I + Examples with different base ring:: sage: R.<x> = ZZ[] sage: k = GF(2) sage: residue = lambda x: k(x) - sage: f = 4*x^2+x+3 + sage: f = 4*x^2 + x + 3 sage: g = f.map_coefficients(residue); g x + 1 sage: g.parent() Univariate Polynomial Ring in x over Integer Ring - sage: g = f.map_coefficients(residue, new_base_ring = k); g + sage: g = f.map_coefficients(residue, new_base_ring=k); g x + 1 - sage: g.parent() + sage: g.parent() # needs sage.libs.ntl Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) sage: residue = k.coerce_map_from(ZZ) sage: g = f.map_coefficients(residue); g x + 1 - sage: g.parent() + sage: g.parent() # needs sage.libs.ntl Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) """ R = self._parent @@ -9860,7 +10226,7 @@ cdef class Polynomial(CommutativeAlgebraElement): R = R.change_ring(new_base_ring) elif isinstance(f, Map): R = R.change_ring(f.codomain()) - return R({k: f(v) for (k,v) in self.dict().items()}) + return R({k: f(v) for k, v in self.dict().items()}) def is_cyclotomic(self, certificate=False, algorithm="pari"): r""" @@ -9883,14 +10249,14 @@ cdef class Polynomial(CommutativeAlgebraElement): INPUT: - ``certificate`` -- boolean, default to ``False``. Only works with - ``algorithm`` set to "pari". + ``algorithm`` set to ``"pari"``. - - ``algorithm`` -- either "pari" or "sage" (default is "pari") + - ``algorithm`` -- either ``"pari"`` or ``"sage"`` (default is ``"pari"``) ALGORITHM: The native algorithm implemented in Sage uses the first - algorithm of [BD1989]_. The algorithm in pari (using + algorithm of [BD1989]_. The algorithm in PARI (using :pari:`poliscyclo`) is more subtle since it does compute the inverse of the Euler `\phi` function to determine the `n` such that the polynomial is the `n`-th cyclotomic polynomial. @@ -9899,6 +10265,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Quick tests:: + sage: # needs sage.libs.pari sage: P.<x> = ZZ['x'] sage: (x - 1).is_cyclotomic() True @@ -9913,30 +10280,32 @@ cdef class Polynomial(CommutativeAlgebraElement): Test first 100 cyclotomic polynomials:: - sage: all(cyclotomic_polynomial(i).is_cyclotomic() for i in range(1,101)) + sage: all(cyclotomic_polynomial(i).is_cyclotomic() for i in range(1, 101)) # needs sage.libs.pari True Some more tests:: - sage: (x^16 + x^14 - x^10 + x^8 - x^6 + x^2 + 1).is_cyclotomic(algorithm="pari") + sage: # needs sage.libs.pari + sage: f = x^16 + x^14 - x^10 + x^8 - x^6 + x^2 + 1 + sage: f.is_cyclotomic(algorithm="pari") False - sage: (x^16 + x^14 - x^10 + x^8 - x^6 + x^2 + 1).is_cyclotomic(algorithm="sage") + sage: f.is_cyclotomic(algorithm="sage") False - - sage: (x^16 + x^14 - x^10 - x^8 - x^6 + x^2 + 1).is_cyclotomic(algorithm="pari") + sage: g = x^16 + x^14 - x^10 - x^8 - x^6 + x^2 + 1 + sage: g.is_cyclotomic(algorithm="pari") True - sage: (x^16 + x^14 - x^10 - x^8 - x^6 + x^2 + 1).is_cyclotomic(algorithm="sage") + sage: g.is_cyclotomic(algorithm="sage") True sage: y = polygen(QQ) sage: (y/2 - 1/2).is_cyclotomic() False - sage: (2*(y/2 - 1/2)).is_cyclotomic() + sage: (2*(y/2 - 1/2)).is_cyclotomic() # needs sage.libs.pari True Invalid arguments:: - sage: (x - 3).is_cyclotomic(algorithm="sage", certificate=True) + sage: (x - 3).is_cyclotomic(algorithm="sage", certificate=True) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: no implementation of the certificate within Sage @@ -9952,28 +10321,28 @@ cdef class Polynomial(CommutativeAlgebraElement): TESTS:: sage: R = ZZ['x'] - sage: for _ in range(20): + sage: for _ in range(20): # needs sage.libs.pari ....: p = R.random_element(degree=randint(10,20)) ....: ans_pari = p.is_cyclotomic(algorithm="pari") ....: ans_sage = p.is_cyclotomic(algorithm="sage") ....: assert ans_pari == ans_sage, "problem with p={}".format(p) - sage: for d in range(2,20): + sage: for d in range(2, 20): # needs sage.libs.pari ....: p = cyclotomic_polynomial(d) ....: assert p.is_cyclotomic(algorithm="pari"), "pari problem with p={}".format(p) ....: assert p.is_cyclotomic(algorithm="sage"), "sage problem with p={}".format(p) Test the output type when ``certificate=True``:: - sage: type((x^2 - 2).is_cyclotomic(certificate=True)) + sage: type((x^2 - 2).is_cyclotomic(certificate=True)) # needs sage.libs.pari <class 'sage.rings.integer.Integer'> - sage: type((x -1).is_cyclotomic(certificate=True)) + sage: type((x - 1).is_cyclotomic(certificate=True)) # needs sage.libs.pari <class 'sage.rings.integer.Integer'> Check that the arguments are forwarded when the input is not a polynomial with coefficients in `\ZZ`:: sage: x = polygen(QQ) - sage: (x-1).is_cyclotomic(certificate=True) + sage: (x - 1).is_cyclotomic(certificate=True) # needs sage.libs.pari 1 """ S = self.base_ring() @@ -10050,20 +10419,20 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: x = polygen(ZZ) - sage: (x^5 - 1).is_cyclotomic_product() + sage: (x^5 - 1).is_cyclotomic_product() # needs sage.libs.pari True - sage: (x^5 + x^4 - x^2 + 1).is_cyclotomic_product() + sage: (x^5 + x^4 - x^2 + 1).is_cyclotomic_product() # needs sage.libs.pari False - sage: p = prod(cyclotomic_polynomial(i) for i in [2,5,7,12]) - sage: p.is_cyclotomic_product() + sage: p = prod(cyclotomic_polynomial(i) for i in [2, 5, 7, 12]) + sage: p.is_cyclotomic_product() # needs sage.libs.pari True sage: (x^5 - 1/3).is_cyclotomic_product() False sage: x = polygen(Zmod(5)) - sage: (x-1).is_cyclotomic_product() + sage: (x - 1).is_cyclotomic_product() Traceback (most recent call last): ... NotImplementedError: not implemented in non-zero characteristic @@ -10164,12 +10533,12 @@ cdef class Polynomial(CommutativeAlgebraElement): def has_cyclotomic_factor(self): r""" - Return True if the given polynomial has a nontrivial cyclotomic factor. + Return ``True`` if the given polynomial has a nontrivial cyclotomic factor. The algorithm assumes that the polynomial has rational coefficients. If the polynomial is known to be irreducible, it may be slightly more - efficient to call `is_cyclotomic` instead. + efficient to call :meth:`is_cyclotomic` instead. .. SEEALSO:: @@ -10180,12 +10549,12 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: sage: pol.<x> = PolynomialRing(Rationals()) - sage: u = x^5-1; u.has_cyclotomic_factor() + sage: u = x^5 - 1; u.has_cyclotomic_factor() True - sage: u = x^5-2; u.has_cyclotomic_factor() + sage: u = x^5 - 2; u.has_cyclotomic_factor() False - sage: u = pol(cyclotomic_polynomial(7)) * pol.random_element() #random - sage: u.has_cyclotomic_factor() # random + sage: u = pol(cyclotomic_polynomial(7)) * pol.random_element() # random + sage: u.has_cyclotomic_factor() # random True """ if not QQ.has_coerce_map_from(self.base_ring()): @@ -10307,6 +10676,8 @@ cdef class Polynomial(CommutativeAlgebraElement): if var == x_name: return sum(self.coefficients())*x**self.degree() + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + P = PolynomialRing(self.base_ring(), [x_name, var]) return P(self)._homogenize(1) @@ -10321,7 +10692,7 @@ cdef class Polynomial(CommutativeAlgebraElement): True sage: P(0).is_homogeneous() True - sage: (x+1).is_homogeneous() + sage: (x + 1).is_homogeneous() False """ return len(self.exponents()) < 2 @@ -10334,7 +10705,7 @@ cdef class Polynomial(CommutativeAlgebraElement): series. This method works only when the base ring is an integral domain. Moreover, for polynomial whose coefficient of lower degree is different from 1, the elements of the base - ring should have a method ``nth_root`` implemented. + ring should have a method :meth:`nth_root` implemented. EXAMPLES:: @@ -10355,6 +10726,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: a.nth_root(2) 1/56*x^3 + 103/336*x^2 + 365/252*x + 25/12 + sage: # needs sage.rings.number_field sage: K.<sqrt2> = QuadraticField(2) sage: R.<x> = K[] sage: a = (x + sqrt2)^3 * ((1+sqrt2)*x - 1/sqrt2)^6 @@ -10363,6 +10735,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: b^3 == a True + sage: # needs sage.rings.number_field sage: R.<x> = QQbar[] sage: p = x**3 + QQbar(2).sqrt() * x - QQbar(3).sqrt() sage: r = (p**5).nth_root(5) @@ -10374,6 +10747,7 @@ cdef class Polynomial(CommutativeAlgebraElement): ... ValueError: not a 20th power + sage: # needs sage.rings.finite_rings sage: z = GF(4).gen() sage: R.<x> = GF(4)[] sage: p = z*x**4 + 2*x - 1 @@ -10407,6 +10781,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Here we consider a base ring without ``nth_root`` method. The third example with a non-trivial coefficient of lowest degree raises an error:: + sage: # needs sage.libs.pari sage: R.<x> = QQ[] sage: R2 = R.quotient(x**2 + 1) sage: x = R2.gen() @@ -10451,7 +10826,7 @@ cdef class Polynomial(CommutativeAlgebraElement): Some random tests:: - sage: for R in [QQ['x'], GF(4)['x']]: + sage: for R in [QQ['x'], GF(4)['x']]: # needs sage.rings.finite_rings ....: for _ in range(30): ....: p = R.random_element(degree=randint(10,20)) ....: n = ZZ.random_element(2,20) @@ -10535,6 +10910,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R.one()._nth_root_series(3, 5) 1 + sage: # needs sage.rings.number_field sage: R.<x> = QQbar[] sage: p = 2 + 3*x^2 sage: q = p._nth_root_series(3, 20) @@ -10644,7 +11020,7 @@ cdef class Polynomial(CommutativeAlgebraElement): @coerce_binop def divides(self, p): r""" - Return `True` if this polynomial divides `p`. + Return ``True`` if this polynomial divides `p`. This method is only implemented for polynomials over an integral domain. @@ -10678,9 +11054,11 @@ cdef class Polynomial(CommutativeAlgebraElement): TESTS:: - sage: R.<x> = PolynomialRing(ZZ, implementation="NTL") - sage: (2*x + 1).divides(4*x**2 + 1) + sage: R.<x> = PolynomialRing(ZZ, implementation="NTL") # needs sage.libs.ntl + sage: (2*x + 1).divides(4*x**2 + 1) # needs sage.libs.ntl False + + sage: # needs sage.rings.finite_rings sage: K.<z> = GF(4) sage: R.<x> = K[] sage: S.<y> = R[] @@ -10688,11 +11066,12 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: q = y^2 + z*y*x + 2*y + z sage: p.divides(q), p.divides(p*q) (False, True) + sage: R.<x,y> = GF(2)[] sage: S.<z> = R[] sage: p = (x+y+1) * z + x*y sage: q = (y^2-x^2) * z^2 + z + x-y - sage: p.divides(q), p.divides(p*q) + sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) """ if not self.base_ring().is_integral_domain(): @@ -10728,7 +11107,7 @@ cdef class Polynomial(CommutativeAlgebraElement): - ``D`` -- dictionary (optional) - - ``phi`` -- SpecializationMorphism (optional) + - ``phi`` -- :class:`SpecializationMorphism` (optional) OUTPUT: a new polynomial @@ -10766,8 +11145,8 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: Pol.<x> = CBF[] - sage: (1 + x)._log_series(3) + sage: Pol.<x> = CBF[] # needs sage.libs.flint + sage: (1 + x)._log_series(3) # needs sage.libs.flint -0.5000000000000000*x^2 + x """ raise NotImplementedError @@ -10779,8 +11158,8 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: Pol.<x> = CBF[] - sage: x._exp_series(3) + sage: Pol.<x> = CBF[] # needs sage.libs.flint + sage: x._exp_series(3) # needs sage.libs.flint 0.5000000000000000*x^2 + x + 1.000000000000000 """ raise NotImplementedError @@ -10931,8 +11310,8 @@ cdef list do_schoolbook_product(list x, list y, Py_ssize_t deg): INPUT: - - ``x``, ``y``: lists of coefficients - - ``deg``: degree at which the output should be truncated, + - ``x``, ``y`` -- lists of coefficients + - ``deg`` -- degree at which the output should be truncated, negative values mean not to truncate at all TESTS: @@ -11161,6 +11540,7 @@ cdef class Polynomial_generic_dense(Polynomial): TESTS:: + sage: # needs sage.rings.real_mpfr sage: from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_dense sage: isinstance(f, Polynomial_generic_dense) True @@ -11170,22 +11550,22 @@ cdef class Polynomial_generic_dense(Polynomial): sage: R.<x> = QQ[] sage: S = R['y'] - sage: S((x^2, 2, 1+x)) + sage: S((x^2, 2, 1 + x)) (x + 1)*y^2 + 2*y + x^2 """ def __init__(self, parent, x=None, int check=1, is_gen=False, int construct=0, **kwds): Polynomial.__init__(self, parent, is_gen=is_gen) if x is None: - self.__coeffs = [] + self._coeffs = [] return R = parent.base_ring() if isinstance(x, (list, tuple)): if check: - self.__coeffs = [R(t) for t in x] - self.__normalize() + self._coeffs = [R(t) for t in x] + self._normalize() else: - self.__coeffs = x + self._coeffs = x return if sage.rings.fraction_field_element.is_FractionFieldElement(x): @@ -11200,19 +11580,19 @@ cdef class Polynomial_generic_dense(Polynomial): elif R.has_coerce_map_from((<Element>x)._parent):# is R or (<Element>x)._parent == R: try: if x.is_zero(): - self.__coeffs = [] + self._coeffs = [] return except (AttributeError, TypeError): pass x = [x] else: - self.__coeffs = [R(a, **kwds) for a in x.list(copy=False)] + self._coeffs = [R(a, **kwds) for a in x.list(copy=False)] if check: - self.__normalize() + self._normalize() return elif isinstance(x, int) and x == 0: - self.__coeffs = [] + self._coeffs = [] return elif isinstance(x, dict): @@ -11228,16 +11608,16 @@ cdef class Polynomial_generic_dense(Polynomial): # else: # x = [] # zero polynomial if check: - self.__coeffs = [R(z, **kwds) for z in x] - self.__normalize() + self._coeffs = [R(z, **kwds) for z in x] + self._normalize() else: - self.__coeffs = x + self._coeffs = x cdef Polynomial_generic_dense _new_c(self, list coeffs, Parent P): cdef type t = type(self) cdef Polynomial_generic_dense f = <Polynomial_generic_dense>t.__new__(t) f._parent = P - f.__coeffs = coeffs + f._coeffs = coeffs return f cpdef Polynomial _new_constant_poly(self, a, Parent P): @@ -11279,10 +11659,10 @@ cdef class Polynomial_generic_dense(Polynomial): sage: type(f) <class 'sage.rings.polynomial.polynomial_element.Polynomial_generic_dense'> """ - return make_generic_polynomial, (self._parent, self.__coeffs) + return make_generic_polynomial, (self._parent, self._coeffs) def __bool__(self): - return bool(self.__coeffs) + return bool(self._coeffs) cpdef bint is_term(self) except -1: """ @@ -11291,6 +11671,7 @@ cdef class Polynomial_generic_dense(Polynomial): EXAMPLES:: + sage: # needs sage.symbolic sage: R.<x> = SR[] sage: R(0).is_term() False @@ -11298,13 +11679,13 @@ cdef class Polynomial_generic_dense(Polynomial): True sage: (3*x^5).is_term() True - sage: (1+3*x^5).is_term() + sage: (1 + 3*x^5).is_term() False """ - if not self.__coeffs: + if not self._coeffs: return False - for c in self.__coeffs[:-1]: + for c in self._coeffs[:-1]: if c: return False return True @@ -11316,9 +11697,9 @@ cdef class Polynomial_generic_dense(Polynomial): Return the product ``self * term``, where ``term`` is a polynomial with a single term. """ - cdef Py_ssize_t d = len( (<Polynomial_generic_dense> term).__coeffs ) - 1 + cdef Py_ssize_t d = len( (<Polynomial_generic_dense> term)._coeffs ) - 1 cdef Py_ssize_t i - cdef list x = self.__coeffs + cdef list x = self._coeffs cdef Py_ssize_t ell = len(x) c = term.get_unsafe(d) cdef list v = [self.base_ring().zero()] * (d + ell) @@ -11331,10 +11712,10 @@ cdef class Polynomial_generic_dense(Polynomial): cdef Polynomial_generic_dense res = self._new_c(v, self._parent) #if not v[len(v)-1]: # "normalize" checks this anyway... - res.__normalize() + res._normalize() return res - cdef int __normalize(self) except -1: + cdef int _normalize(self) except -1: """ TESTS: @@ -11352,7 +11733,7 @@ cdef class Polynomial_generic_dense(Polynomial): ... NotImplementedError: cannot check whether number is non-zero """ - cdef list x = self.__coeffs + cdef list x = self._coeffs cdef Py_ssize_t n = len(x) - 1 while n >= 0 and not x[n]: del x[n] @@ -11381,7 +11762,7 @@ cdef class Polynomial_generic_dense(Polynomial): sage: f[:3] 40.0*x^2 + 10.0*x + 1.0 """ - return self.__coeffs[n] + return self._coeffs[n] def _unsafe_mutate(self, n, value): """ @@ -11404,17 +11785,17 @@ cdef class Polynomial_generic_dense(Polynomial): """ n = int(n) value = self.base_ring()(value) - if n >= 0 and n < len(self.__coeffs): - self.__coeffs[n] = value - if n == len(self.__coeffs) and value == 0: - self.__normalize() + if n >= 0 and n < len(self._coeffs): + self._coeffs[n] = value + if n == len(self._coeffs) and value == 0: + self._normalize() elif n < 0: raise IndexError("polynomial coefficient index must be nonnegative") elif value != 0: zero = self.base_ring().zero() - for _ in xrange(len(self.__coeffs), n): - self.__coeffs.append(zero) - self.__coeffs.append(value) + for _ in range(len(self._coeffs), n): + self._coeffs.append(zero) + self._coeffs.append(value) def __floordiv__(self, right): """ @@ -11422,6 +11803,7 @@ cdef class Polynomial_generic_dense(Polynomial): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = QQbar[] sage: f = (1+2*x)^3 + 3*x; f 8*x^3 + 12*x^2 + 9*x + 1 @@ -11436,6 +11818,7 @@ cdef class Polynomial_generic_dense(Polynomial): Check that :trac:`13048` and :trac:`2034` are fixed:: + sage: # needs sage.rings.number_field sage: R.<x> = QQbar[] sage: x // x 1 @@ -11454,8 +11837,8 @@ cdef class Polynomial_generic_dense(Polynomial): return (<Polynomial_generic_dense>self)._floordiv_(<Polynomial_generic_dense>right) P = parent(self) d = P.base_ring()(right) - cdef Polynomial_generic_dense res = (<Polynomial_generic_dense>self)._new_c([c // d for c in (<Polynomial_generic_dense>self).__coeffs], P) - res.__normalize() + cdef Polynomial_generic_dense res = (<Polynomial_generic_dense>self)._new_c([c // d for c in (<Polynomial_generic_dense>self)._coeffs], P) + res._normalize() return res cpdef _add_(self, right): @@ -11471,8 +11854,8 @@ cdef class Polynomial_generic_dense(Polynomial): """ cdef Polynomial_generic_dense res cdef Py_ssize_t check=0, i, min - x = (<Polynomial_generic_dense>self).__coeffs - y = (<Polynomial_generic_dense>right).__coeffs + x = (<Polynomial_generic_dense>self)._coeffs + y = (<Polynomial_generic_dense>right)._coeffs if len(x) > len(y): min = len(y) high = x[min:] @@ -11484,7 +11867,7 @@ cdef class Polynomial_generic_dense(Polynomial): cdef list low = [x[i] + y[i] for i from 0 <= i < min] if len(x) == len(y): res = self._new_c(low, self._parent) - res.__normalize() + res._normalize() return res else: return self._new_c(low + high, self._parent) @@ -11492,8 +11875,8 @@ cdef class Polynomial_generic_dense(Polynomial): cpdef _sub_(self, right): cdef Polynomial_generic_dense res cdef Py_ssize_t check=0, i, min - x = (<Polynomial_generic_dense>self).__coeffs - y = (<Polynomial_generic_dense>right).__coeffs + x = (<Polynomial_generic_dense>self)._coeffs + y = (<Polynomial_generic_dense>right)._coeffs if len(x) > len(y): min = len(y) high = x[min:] @@ -11505,41 +11888,40 @@ cdef class Polynomial_generic_dense(Polynomial): low = [x[i] - y[i] for i from 0 <= i < min] if len(x) == len(y): res = self._new_c(low, self._parent) - res.__normalize() + res._normalize() return res else: return self._new_c(low + high, self._parent) cpdef _rmul_(self, Element c): - if not self.__coeffs: + if not self._coeffs: return self - if c._parent is not (<Element>self.__coeffs[0])._parent: - c = (<Element>self.__coeffs[0])._parent.coerce(c) - v = [c * a for a in self.__coeffs] + if c._parent is not (<Element>self._coeffs[0])._parent: + c = (<Element>self._coeffs[0])._parent.coerce(c) + v = [c * a for a in self._coeffs] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) #if not v[len(v)-1]: # "normalize" checks this anyway... - res.__normalize() + res._normalize() return res cpdef _lmul_(self, Element c): - if not self.__coeffs: + if not self._coeffs: return self - if c._parent is not (<Element>self.__coeffs[0])._parent: - c = (<Element>self.__coeffs[0])._parent.coerce(c) - v = [a * c for a in self.__coeffs] + if c._parent is not (<Element>self._coeffs[0])._parent: + c = (<Element>self._coeffs[0])._parent.coerce(c) + v = [a * c for a in self._coeffs] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) #if not v[len(v)-1]: # "normalize" checks this anyway... - res.__normalize() + res._normalize() return res cpdef constant_coefficient(self): """ Return the constant coefficient of this polynomial. - OUTPUT: - element of base ring + OUTPUT: element of base ring EXAMPLES:: @@ -11549,10 +11931,10 @@ cdef class Polynomial_generic_dense(Polynomial): sage: f.constant_coefficient() t """ - if not self.__coeffs: + if not self._coeffs: return self.base_ring().zero() else: - return self.__coeffs[0] + return self._coeffs[0] cpdef list list(self, bint copy=True): """ @@ -11567,9 +11949,9 @@ cdef class Polynomial_generic_dense(Polynomial): [1, 9, 12, 8] """ if copy: - return list(self.__coeffs) + return list(self._coeffs) else: - return self.__coeffs + return self._coeffs def degree(self, gen=None): """ @@ -11588,7 +11970,7 @@ cdef class Polynomial_generic_dense(Polynomial): <class 'sage.rings.integer.Integer'> """ - return smallInteger(len(self.__coeffs) - 1) + return smallInteger(len(self._coeffs) - 1) def shift(self, Py_ssize_t n): r""" @@ -11626,13 +12008,13 @@ cdef class Polynomial_generic_dense(Polynomial): return self if n > 0: output = [self.base_ring().zero()] * n - output.extend(self.__coeffs) + output.extend(self._coeffs) return self._new_c(output, self._parent) if n < 0: - if n > len(self.__coeffs) - 1: + if n > len(self._coeffs) - 1: return self._parent([]) else: - return self._new_c(self.__coeffs[-int(n):], self._parent) + return self._new_c(self._coeffs[-int(n):], self._parent) @coerce_binop def quo_rem(self, other): @@ -11640,8 +12022,8 @@ cdef class Polynomial_generic_dense(Polynomial): Return the quotient and remainder of the Euclidean division of ``self`` and ``other``. - Raises a ``ZerodivisionError`` if ``other`` is zero. Raises an - ``ArithmeticError`` if the division is not exact. + Raises a :class:`ZeroDivisionError` if ``other`` is zero. Raises an + :class:`ArithmeticError` if the division is not exact. EXAMPLES:: @@ -11656,7 +12038,8 @@ cdef class Polynomial_generic_dense(Polynomial): sage: f.quo_rem(g) Traceback (most recent call last): ... - ArithmeticError: division non exact (consider coercing to polynomials over the fraction field) + ArithmeticError: division non exact (consider coercing + to polynomials over the fraction field) sage: g = 0 sage: f.quo_rem(g) Traceback (most recent call last): @@ -11666,6 +12049,7 @@ cdef class Polynomial_generic_dense(Polynomial): Polynomials over noncommutative rings are also allowed (after :trac:`34733`):: + sage: # needs sage.combinat sage.modules sage: HH = QuaternionAlgebra(QQ, -1, -1) sage: P.<x> = HH[] sage: f = P.random_element(5) @@ -11704,8 +12088,8 @@ cdef class Polynomial_generic_dense(Polynomial): return self, self R = self._parent.base_ring() - cdef list x = list((<Polynomial_generic_dense>self).__coeffs) # make a copy - cdef list y = (<Polynomial_generic_dense>other).__coeffs + cdef list x = list((<Polynomial_generic_dense>self)._coeffs) # make a copy + cdef list y = (<Polynomial_generic_dense>other)._coeffs cdef Py_ssize_t m = len(x) # deg(self)=m-1 cdef Py_ssize_t n = len(y) # deg(other)=n-1 if m < n: @@ -11741,19 +12125,19 @@ cdef class Polynomial_generic_dense(Polynomial): cpdef Polynomial truncate(self, long n): r""" - Return the polynomial of degree ` < n` which is equivalent + Return the polynomial of degree `< n` which is equivalent to self modulo `x^n`. EXAMPLES:: sage: S.<q> = QQ['t']['q'] - sage: f = (1+q^10+q^11+q^12).truncate(11); f + sage: f = (1 + q^10 + q^11 + q^12).truncate(11); f q^10 + 1 - sage: f = (1+q^10+q^100).truncate(50); f + sage: f = (1 + q^10 + q^100).truncate(50); f q^10 + 1 sage: f.degree() 10 - sage: f = (1+q^10+q^100).truncate(500); f + sage: f = (1 + q^10 + q^100).truncate(500); f q^100 + q^10 + 1 TESTS: @@ -11766,18 +12150,18 @@ cdef class Polynomial_generic_dense(Polynomial): sage: type(f) <class 'sage.rings.polynomial.polynomial_element.Polynomial_generic_dense'> """ - l = len(self.__coeffs) + l = len(self._coeffs) if n > l: n = l - while n > 0 and not self.__coeffs[n-1]: + while n > 0 and not self._coeffs[n-1]: n -= 1 - return self._new_c(self.__coeffs[:n], self._parent) + return self._new_c(self._coeffs[:n], self._parent) cdef _inplace_truncate(self, long n): - if n < len(self.__coeffs): - while n > 0 and not self.__coeffs[n-1]: + if n < len(self._coeffs): + while n > 0 and not self._coeffs[n-1]: n -= 1 - self.__coeffs = self.__coeffs[:n] + self._coeffs = self._coeffs[:n] return self def make_generic_polynomial(parent, coeffs): @@ -11802,6 +12186,7 @@ def universal_discriminant(n): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.rings.polynomial.polynomial_element import universal_discriminant sage: universal_discriminant(1) 1 @@ -11815,6 +12200,8 @@ def universal_discriminant(n): .. SEEALSO:: :meth:`Polynomial.discriminant` """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + pr1 = PolynomialRing(ZZ, n + 1, 'a') pr2 = PolynomialRing(pr1, 'x') p = pr2(list(pr1.gens())) @@ -11831,7 +12218,7 @@ cpdef Polynomial generic_power_trunc(Polynomial p, Integer n, long prec): - ``n`` - an integer (of type :class:`sage.rings.integer.Integer`) - - ``prec`` - a precision (should fit into a C long) + - ``prec`` - a precision (should fit into a C ``long``) TESTS: @@ -11839,7 +12226,7 @@ cpdef Polynomial generic_power_trunc(Polynomial p, Integer n, long prec): sage: from sage.rings.polynomial.polynomial_element import generic_power_trunc - sage: for S in [ZZ, GF(3)]: # known bug # not tested (see :trac:`32075`) + sage: for S in [ZZ, GF(3)]: # known bug, not tested (see :trac:`32075`) ....: R = PolynomialRing(S, 'x') ....: for _ in range(100): ....: p = R.random_element() @@ -11933,18 +12320,18 @@ cdef class Polynomial_generic_dense_inexact(Polynomial_generic_dense): - Xavier Caruso (2013-03) """ - cdef int __normalize(self) except -1: + cdef int _normalize(self) except -1: r""" TESTS:: Coefficients indistinguishable from 0 are not removed. - sage: R = Zp(5) - sage: S.<x> = R[] - sage: S([1,R(0,20)]) + sage: R = Zp(5) # needs sage.rings.padics + sage: S.<x> = R[] # needs sage.rings.padics + sage: S([1, R(0, 20)]) # needs sage.rings.padics O(5^20)*x + 1 + O(5^20) """ - cdef list x = self.__coeffs + cdef list x = self._coeffs cdef Py_ssize_t n = len(x) - 1 cdef RingElement c while n >= 0: @@ -11959,35 +12346,35 @@ cdef class Polynomial_generic_dense_inexact(Polynomial_generic_dense): r""" INPUT: - - secure -- a boolean (default: False) + - ``secure`` -- a boolean (default: ``False``) - OUTPUT: - - The degree of self. + OUTPUT: The degree of ``self``. - If ``secure`` is True and the degree of this polynomial + If ``secure`` is ``True`` and the degree of this polynomial is not determined (because the leading coefficient is indistinguishable from 0), an error is raised - If ``secure`` is False, the returned value is the largest + If ``secure`` is ``False``, the returned value is the largest `n` so that the coefficient of `x^n` does not compare equal to `0`. EXAMPLES:: - sage: K = Qp(3,10) + sage: # needs sage.rings.padics + sage: K = Qp(3, 10) sage: R.<T> = K[] sage: f = T + 2; f (1 + O(3^10))*T + 2 + O(3^10) sage: f.degree() 1 - sage: (f-T).degree() + sage: (f - T).degree() 0 - sage: (f-T).degree(secure=True) + sage: (f - T).degree(secure=True) Traceback (most recent call last): ... PrecisionError: the leading coefficient is indistinguishable from 0 + sage: # needs sage.rings.padics sage: x = O(3^5) sage: li = [3^i * x for i in range(0,5)]; li [O(3^5), O(3^6), O(3^7), O(3^8), O(3^9)] @@ -12004,7 +12391,7 @@ cdef class Polynomial_generic_dense_inexact(Polynomial_generic_dense): - Xavier Caruso (2013-03) """ - coeffs = self.__coeffs + coeffs = self._coeffs d = len(coeffs) - 1 while d >= 0: c = coeffs[d] @@ -12027,7 +12414,8 @@ cdef class Polynomial_generic_dense_inexact(Polynomial_generic_dense): EXAMPLES:: - sage: K = Qp(3,10) + sage: # needs sage.rings.padics + sage: K = Qp(3, 10) sage: R.<T> = K[] sage: f = T + 2; f (1 + O(3^10))*T + 2 + O(3^10) @@ -12036,32 +12424,32 @@ cdef class Polynomial_generic_dense_inexact(Polynomial_generic_dense): sage: f.prec_degree() 1 - sage: g = f - T; g + sage: g = f - T; g # needs sage.rings.padics O(3^10)*T + 2 + O(3^10) - sage: g.degree() + sage: g.degree() # needs sage.rings.padics 0 - sage: g.prec_degree() + sage: g.prec_degree() # needs sage.rings.padics 1 AUTHOR: - Xavier Caruso (2013-03) """ - return len(self.__coeffs) - 1 + return len(self._coeffs) - 1 cdef class ConstantPolynomialSection(Map): """ This class is used for conversion from a polynomial ring to its base ring. - Since :trac:`9944`, it calls the ``constant_coefficient`` method, + Since :trac:`9944`, it calls the :meth:`constant_coefficient` method, which can be optimized for a particular polynomial type. EXAMPLES:: sage: P0.<y_1> = GF(3)[] sage: P1.<y_2,y_1,y_0> = GF(3)[] - sage: P0(-y_1) # indirect doctest + sage: P0(-y_1) 2*y_1 sage: phi = GF(3).convert_map_from(P0); phi @@ -12087,7 +12475,7 @@ cdef class ConstantPolynomialSection(Map): Generic map: From: Univariate Polynomial Ring in x over Rational Field To: Rational Field - sage: m(x-x+1/2) # implicit + sage: m(x-x+1/2) # implicit 1/2 sage: m(x-x) 0 @@ -12109,12 +12497,12 @@ cdef class PolynomialBaseringInjection(Morphism): This class is used for conversion from a ring to a polynomial over that ring. - It calls the _new_constant_poly method on the generator, + It calls the :meth:`_new_constant_poly` method on the generator, which should be optimized for a particular polynomial type. Technically, it should be a method of the polynomial ring, but - few polynomial rings are cython classes, and so, as a method - of a cython polynomial class, it is faster. + few polynomial rings are Cython classes, and so, as a method + of a Cython polynomial class, it is faster. EXAMPLES: @@ -12123,16 +12511,20 @@ cdef class PolynomialBaseringInjection(Morphism): supposed to be the fastest maps for that purpose. See :trac:`9944`. :: + sage: # needs sage.rings.padics sage: R.<x> = Qp(3)[] sage: R.coerce_map_from(R.base_ring()) Polynomial base injection morphism: From: 3-adic Field with capped relative precision 20 - To: Univariate Polynomial Ring in x over 3-adic Field with capped relative precision 20 + To: Univariate Polynomial Ring in x over + 3-adic Field with capped relative precision 20 sage: R.<x,y> = Qp(3)[] sage: R.coerce_map_from(R.base_ring()) Polynomial base injection morphism: From: 3-adic Field with capped relative precision 20 - To: Multivariate Polynomial Ring in x, y over 3-adic Field with capped relative precision 20 + To: Multivariate Polynomial Ring in x, y over + 3-adic Field with capped relative precision 20 + sage: R.<x,y> = QQ[] sage: R.coerce_map_from(R.base_ring()) Polynomial base injection morphism: @@ -12171,6 +12563,7 @@ cdef class PolynomialBaseringInjection(Morphism): :: + sage: # needs sage.rings.padics sage: R.<t> = Qp(2)[] sage: f = R.convert_map_from(R.base_ring()) # indirect doctest sage: f(Qp(2).one()*3) @@ -12227,7 +12620,7 @@ cdef class PolynomialBaseringInjection(Morphism): Polynomial base injection morphism: From: Integer Ring To: Univariate Polynomial Ring in x over Integer Ring - sage: m(2) # indirect doctest + sage: m(2) # indirect doctest 2 sage: parent(m(2)) Univariate Polynomial Ring in x over Integer Ring @@ -12239,8 +12632,8 @@ cdef class PolynomialBaseringInjection(Morphism): TESTS:: sage: from sage.rings.polynomial.polynomial_element import PolynomialBaseringInjection - sage: m = PolynomialBaseringInjection(Qp(5), Qp(5)['x']) - sage: m(1 + O(5^11), absprec = 5) # indirect doctest + sage: m = PolynomialBaseringInjection(Qp(5), Qp(5)['x']) # needs sage.rings.padics + sage: m(1 + O(5^11), absprec=5) # indirect doctest # needs sage.rings.padics 1 + O(5^11) """ try: @@ -12278,7 +12671,7 @@ cdef class PolynomialBaseringInjection(Morphism): Check that :trac:`23203` has been resolved:: - sage: R.is_subring(S) # indirect doctest + sage: R.is_subring(S) # indirect doctest True """ diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index f5c38b31cac..1f447fc1287 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -12,12 +12,12 @@ We test coercion in a particularly complicated situation:: - sage: W.<w>=QQ['w'] - sage: WZ.<z>=W['z'] - sage: m = matrix(WZ,2,2,[1,z,z,z^2]) - sage: a = m.charpoly() + sage: W.<w> = QQ['w'] + sage: WZ.<z> = W['z'] + sage: m = matrix(WZ, 2, 2, [1, z, z, z^2]) # needs sage.modules + sage: a = m.charpoly() # needs sage.modules sage: R.<x> = WZ[] - sage: R(a) + sage: R(a) # needs sage.modules x^2 + (-z^2 - 1)*x """ @@ -34,7 +34,11 @@ from sage.rings.polynomial.polynomial_singular_interface import Polynomial_singular_repr -from sage.libs.pari.all import pari_gen +try: + from sage.libs.pari.all import pari_gen +except ImportError: + pari_gen = () + from sage.structure.richcmp import richcmp, richcmp_item, rich_to_bool, rich_to_bool_sgn from sage.structure.element import coerce_binop, parent @@ -65,10 +69,13 @@ class Polynomial_generic_sparse(Polynomial): A more extensive example:: - sage: A.<T> = PolynomialRing(Integers(5),sparse=True) ; f = T^2+1 ; B = A.quo(f) + sage: # needs sage.libs.pari + sage: A.<T> = PolynomialRing(Integers(5), sparse=True) + sage: f = T^2 + 1; B = A.quo(f) sage: C.<s> = PolynomialRing(B) sage: C - Univariate Polynomial Ring in s over Univariate Quotient Polynomial Ring in Tbar over Ring of integers modulo 5 with modulus T^2 + 1 + Univariate Polynomial Ring in s over Univariate Quotient Polynomial Ring in Tbar + over Ring of integers modulo 5 with modulus T^2 + 1 sage: s + T s + Tbar sage: (s + T)**2 @@ -79,11 +86,11 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): """ TESTS:: - sage: PolynomialRing(RIF, 'z', sparse=True)([RIF(-1, 1), RIF(-1,1)]) + sage: PolynomialRing(RIF, 'z', sparse=True)([RIF(-1, 1), RIF(-1,1)]) # needs sage.rings.real_interval_field 0.?*z + 0.? - sage: PolynomialRing(RIF, 'z', sparse=True)((RIF(-1, 1), RIF(-1,1))) + sage: PolynomialRing(RIF, 'z', sparse=True)((RIF(-1, 1), RIF(-1,1))) # needs sage.rings.real_interval_field 0.?*z + 0.? - sage: PolynomialRing(CIF, 'z', sparse=True)([CIF(RIF(-1,1), RIF(-1,1)), RIF(-1,1)]) + sage: PolynomialRing(CIF, 'z', sparse=True)([CIF(RIF(-1,1), RIF(-1,1)), RIF(-1,1)]) # needs sage.rings.complex_interval_field 0.?*z + 0.? + 0.?*I """ Polynomial.__init__(self, parent, is_gen=is_gen) @@ -188,7 +195,8 @@ def valuation(self, p=None): EXAMPLES:: - sage: R.<w> = PolynomialRing(GF(9,'a'), sparse=True) + sage: # needs sage.rings.finite_rings + sage: R.<w> = PolynomialRing(GF(9, 'a'), sparse=True) sage: f = w^1997 - w^10000 sage: f.valuation() 1997 @@ -243,10 +251,10 @@ def _derivative(self, var=None): Check that :trac:`28187` is fixed:: sage: R = PolynomialRing(ZZ, 't', sparse=True) - sage: t, u = var('t, u') - sage: R.gen()._derivative(t) + sage: t, u = var('t, u') # needs sage.symbolic + sage: R.gen()._derivative(t) # needs sage.symbolic 1 - sage: R.gen()._derivative(u) + sage: R.gen()._derivative(u) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate with respect to u @@ -260,7 +268,6 @@ def _derivative(self, var=None): except AttributeError: raise ValueError('cannot differentiate with respect to {}'.format(var)) - # compute formal derivative with respect to generator d = {} for n, c in self.__coeffs.items(): @@ -355,6 +362,7 @@ def _repr(self, name=None): r""" EXAMPLES:: + sage: # needs sage.rings.complex_double sage.symbolic sage: R.<w> = PolynomialRing(CDF, sparse=True) sage: f = CDF(1,2) + w^5 - CDF(pi)*w + CDF(e) sage: f._repr() # abs tol 1e-15 @@ -364,8 +372,8 @@ def _repr(self, name=None): TESTS:: - sage: pol = RIF['x']([0, 0, (-1,1)]) - sage: PolynomialRing(RIF, 'x', sparse=True)(pol) + sage: pol = RIF['x']([0, 0, (-1,1)]) # needs sage.rings.real_interval_field + sage: PolynomialRing(RIF, 'x', sparse=True)(pol) # needs sage.rings.real_interval_field 0.?*x^2 AUTHOR: @@ -387,18 +395,18 @@ def _repr(self, name=None): if y.find("-") == 0: y = y[1:] if not atomic_repr and n > 0 and (y.find("+") != -1 or y.find("-") != -1): - x = "(%s)"%x + x = "(%s)" % x if n > 1: - var = "*%s^%s"%(name,n) - elif n==1: - var = "*%s"%name + var = "*%s^%s" % (name,n) + elif n == 1: + var = "*%s" % name else: var = "" - s += "%s%s"%(x,var) + s += "%s%s" % (x,var) s = s.replace(" + -", " - ") s = s.replace(" 1*"," ") s = s.replace(" -1*", " -") - if s==" ": + if s == " ": return "0" return s[1:] @@ -408,7 +416,7 @@ def __normalize(self): for n in D: del x[n] - def __getitem__(self,n): + def __getitem__(self, n): """ Return the `n`-th coefficient of this polynomial. @@ -417,6 +425,7 @@ def __getitem__(self,n): EXAMPLES:: + sage: # needs sage.symbolic sage: R.<w> = PolynomialRing(RDF, sparse=True) sage: e = RDF(e) sage: f = sum(e^n*w^n for n in range(4)); f # abs tol 1.1e-14 @@ -427,46 +436,46 @@ def __getitem__(self,n): 0.0 sage: f[-1] 0.0 - sage: R.<x> = PolynomialRing(RealField(19), sparse=True) - sage: f = (2-3.5*x)^3; f + + sage: R.<x> = PolynomialRing(RealField(19), sparse=True) # needs sage.rings.real_mpfr + sage: f = (2-3.5*x)^3; f # needs sage.rings.real_mpfr -42.875*x^3 + 73.500*x^2 - 42.000*x + 8.0000 Using slices, we can truncate polynomials:: - sage: f[:2] + sage: f[:2] # needs sage.rings.real_mpfr -42.000*x + 8.0000 - Any other kind of slicing is deprecated or an error:: + Any other kind of slicing is an error, see :trac:`18940`:: - sage: f[1:3] - doctest:...: DeprecationWarning: polynomial slicing with a start index is deprecated, use list() and slice the resulting list instead - See https://github.com/sagemath/sage/issues/18940 for details. - 73.500*x^2 - 42.000*x - sage: f[1:3:2] + sage: f[1:3] # needs sage.rings.real_mpfr Traceback (most recent call last): ... - NotImplementedError: polynomial slicing with a step is not defined - sage: f["hello"] + IndexError: polynomial slicing with a start is not defined + + sage: f[1:3:2] # needs sage.rings.real_mpfr + Traceback (most recent call last): + ... + IndexError: polynomial slicing with a step is not defined + + TESTS:: + + sage: f["hello"] # needs sage.rings.real_mpfr Traceback (most recent call last): ... TypeError: list indices must be integers, not str """ if isinstance(n, slice): - d = self.degree() + 1 start, stop, step = n.start, n.stop, n.step if step is not None: - raise NotImplementedError("polynomial slicing with a step is not defined") - if start is None: - start = 0 - else: - if start < 0: - start = 0 - from sage.misc.superseded import deprecation - deprecation(18940, "polynomial slicing with a start index is deprecated, use list() and slice the resulting list instead") + raise IndexError("polynomial slicing with a step is not defined") + if start is not None: + raise IndexError("polynomial slicing with a start is not defined") + d = self.degree() + 1 if stop is None or stop > d: stop = d - x = self.__coeffs - v = {k: x[k] for k in x.keys() if start <= k < stop} + v = {key: val for key, val in self.__coeffs.items() + if key < stop} return self.parent()(v) try: @@ -486,6 +495,7 @@ def _unsafe_mutate(self, n, value): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: R.<z> = PolynomialRing(CC, sparse=True) sage: f = z^2 + CC.0; f 1.00000000000000*z^2 + 1.00000000000000*I @@ -495,8 +505,8 @@ def _unsafe_mutate(self, n, value): Much more nasty:: - sage: z._unsafe_mutate(1, 0) - sage: z + sage: z._unsafe_mutate(1, 0) # needs sage.rings.real_mpfr + sage: z # needs sage.rings.real_mpfr 0 """ n = int(n) @@ -549,6 +559,7 @@ def __floordiv__(self, right): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQbar, sparse=True) sage: f = (1+2*x)^3 + 3*x; f 8*x^3 + 12*x^2 + 9*x + 1 @@ -736,7 +747,7 @@ def _richcmp_(self, other, op): def shift(self, n): r""" - Returns this polynomial multiplied by the power `x^n`. + Return this polynomial multiplied by the power `x^n`. If `n` is negative, terms below `x^n` will be discarded. Does not change this polynomial. @@ -787,12 +798,12 @@ def shift(self, n): @coerce_binop def quo_rem(self, other): """ - Returns the quotient and remainder of the Euclidean division of + Return the quotient and remainder of the Euclidean division of ``self`` and ``other``. - Raises ZerodivisionError if ``other`` is zero. + Raises :class:`ZeroDivisionError` if ``other`` is zero. - Raises ArithmeticError if ``other`` has a nonunit leading coefficient + Raises :class:`ArithmeticError` if ``other`` has a nonunit leading coefficient and this causes the Euclidean division to fail. EXAMPLES:: @@ -810,7 +821,8 @@ def quo_rem(self, other): sage: f.quo_rem(g) Traceback (most recent call last): ... - ArithmeticError: Division non exact (consider coercing to polynomials over the fraction field) + ArithmeticError: Division non exact + (consider coercing to polynomials over the fraction field) sage: g = 0 sage: f.quo_rem(g) Traceback (most recent call last): @@ -826,6 +838,7 @@ def quo_rem(self, other): Polynomials over noncommutative rings are also allowed:: + sage: # needs sage.combinat sage.modules sage: HH = QuaternionAlgebra(QQ, -1, -1) sage: P.<x> = PolynomialRing(HH, sparse=True) sage: f = P.random_element(5) @@ -894,7 +907,7 @@ def quo_rem(self, other): @coerce_binop def gcd(self,other,algorithm=None): - """ + r""" Return the gcd of this polynomial and ``other`` INPUT: @@ -906,27 +919,27 @@ def gcd(self,other,algorithm=None): Two algorithms are provided: - - ``generic``: Uses the generic implementation, which depends on the + - ``generic`` -- Uses the generic implementation, which depends on the base ring being a UFD or a field. - - ``dense``: The polynomials are converted to the dense representation, + - ``dense`` -- The polynomials are converted to the dense representation, their gcd is computed and is converted back to the sparse representation. - Default is ``dense`` for polynomials over ZZ and ``generic`` in the + Default is ``dense`` for polynomials over `\ZZ` and ``generic`` in the other cases. EXAMPLES:: - sage: R.<x> = PolynomialRing(ZZ,sparse=True) + sage: R.<x> = PolynomialRing(ZZ, sparse=True) sage: p = x^6 + 7*x^5 + 8*x^4 + 6*x^3 + 2*x^2 + x + 2 sage: q = 2*x^4 - x^3 - 2*x^2 - 4*x - 1 - sage: gcd(p,q) + sage: gcd(p, q) x^2 + x + 1 - sage: gcd(p, q, algorithm = "dense") + sage: gcd(p, q, algorithm="dense") x^2 + x + 1 - sage: gcd(p, q, algorithm = "generic") + sage: gcd(p, q, algorithm="generic") x^2 + x + 1 - sage: gcd(p, q, algorithm = "foobar") + sage: gcd(p, q, algorithm="foobar") Traceback (most recent call last): ... ValueError: Unknown algorithm 'foobar' @@ -949,22 +962,22 @@ def gcd(self,other,algorithm=None): algorithm = "dense" else: algorithm = "generic" - if algorithm=="dense": + if algorithm == "dense": S = self.parent() # FLINT is faster but a bug makes the conversion extremely slow, # so NTL is used in those cases where the conversion is too slow. Cf # <https://groups.google.com/d/msg/sage-devel/6qhW90dgd1k/Hoq3N7fWe4QJ> sd = self.degree() od = other.degree() - if max(sd,od)<100 or \ - min(len(self.__coeffs)/sd, len(other.__coeffs)/od)>.06: - implementation="FLINT" + if max(sd,od) < 100 or \ + min(len(self.__coeffs)/sd, len(other.__coeffs)/od) > .06: + implementation = "FLINT" else: - implementation="NTL" + implementation = "NTL" D = PolynomialRing(S.base_ring(),'x',implementation=implementation) g = D(self).gcd(D(other)) return S(g) - elif algorithm=="generic": + elif algorithm == "generic": return Polynomial.gcd(self,other) else: raise ValueError("Unknown algorithm '%s'" % algorithm) @@ -973,7 +986,7 @@ def reverse(self, degree=None): """ Return this polynomial but with the coefficients reversed. - If an optional degree argument is given the coefficient list will be + If an optional degree argument is given, the coefficient list will be truncated or zero padded as necessary and the reverse polynomial will have the specified degree. @@ -989,13 +1002,13 @@ def reverse(self, degree=None): if degree is None: degree = self.degree() if not isinstance(degree, (int,Integer)): - raise ValueError("degree argument must be a nonnegative integer, got %s"%degree) + raise ValueError("degree argument must be a nonnegative integer, got %s" % degree) d = {degree-k: v for k,v in self.__coeffs.items() if degree >= k} return self.parent()(d, check=False) def truncate(self, n): """ - Return the polynomial of degree `< n` equal to `self` modulo `x^n`. + Return the polynomial of degree `< n` equal to ``self`` modulo `x^n`. EXAMPLES:: @@ -1013,7 +1026,7 @@ def number_of_terms(self): EXAMPLES:: - sage: R.<x> = PolynomialRing(ZZ,sparse=True) + sage: R.<x> = PolynomialRing(ZZ, sparse=True) sage: p = x^100 - 3*x^10 + 12 sage: p.number_of_terms() 3 @@ -1060,11 +1073,12 @@ class Polynomial_generic_field(Polynomial_singular_repr, @coerce_binop def quo_rem(self, other): """ - Returns a tuple (quotient, remainder) where - self = quotient * other + remainder. + Return a tuple ``(quotient, remainder)`` where + ``self = quotient * other + remainder``. EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<y> = PolynomialRing(QQ) sage: K.<t> = NumberField(y^2 - 2) sage: P.<x> = PolynomialRing(K) @@ -1084,7 +1098,7 @@ def quo_rem(self, other): Q = P.zero() while R.degree() >= B.degree(): aaa = R.leading_coefficient()/B.leading_coefficient() - diff_deg=R.degree()-B.degree() + diff_deg = R.degree()-B.degree() Q += P(aaa).shift(diff_deg) # We know that S*B exactly cancels the leading coefficient of R. # Thus, we skip the computation of this leading coefficient. @@ -1107,12 +1121,12 @@ class Polynomial_generic_sparse_field(Polynomial_generic_sparse, Polynomial_gene sage: loads(f.dumps()) == f True """ - def __init__(self, parent, x=None, check=True, is_gen = False, construct=False): + def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): Polynomial_generic_sparse.__init__(self, parent, x, check, is_gen) class Polynomial_generic_dense_field(Polynomial_generic_dense, Polynomial_generic_field): - def __init__(self, parent, x=None, check=True, is_gen = False, construct=False): + def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): Polynomial_generic_dense.__init__(self, parent, x, check, is_gen) @@ -1131,7 +1145,7 @@ class Polynomial_generic_cdv(Polynomial_generic_domain): """ def newton_slopes(self, repetition=True): """ - Returns a list of the Newton slopes of this polynomial. + Return a list of the Newton slopes of this polynomial. These are the valuations of the roots of this polynomial. @@ -1141,6 +1155,7 @@ def newton_slopes(self, repetition=True): EXAMPLES:: + sage: # needs sage.rings.padics sage: K = Qp(5) sage: R.<t> = K[] sage: f = 5 + 3*t + t^4 + 25*t^10 @@ -1149,7 +1164,7 @@ def newton_slopes(self, repetition=True): sage: f.newton_slopes() [1, 0, 0, 0, -1/3, -1/3, -1/3, -1/3, -1/3, -1/3] - sage: f.newton_slopes(repetition=False) + sage: f.newton_slopes(repetition=False) # needs sage.rings.padics [1, 0, -1/3] AUTHOR: @@ -1161,7 +1176,7 @@ def newton_slopes(self, repetition=True): def newton_polygon(self): r""" - Returns a list of vertices of the Newton polygon of this polynomial. + Return a list of vertices of the Newton polygon of this polynomial. .. NOTE:: @@ -1169,15 +1184,16 @@ def newton_polygon(self): EXAMPLES:: + sage: # needs sage.rings.padics sage: K = Qp(5) sage: R.<t> = K[] sage: f = 5 + 3*t + t^4 + 25*t^10 sage: f.newton_polygon() Finite Newton polygon with 4 vertices: (0, 1), (1, 0), (4, 0), (10, 2) - sage: g = f + K(0,0)*t^4; g + sage: g = f + K(0,0)*t^4; g # needs sage.rings.padics (5^2 + O(5^22))*t^10 + O(5^0)*t^4 + (3 + O(5^20))*t + 5 + O(5^21) - sage: g.newton_polygon() + sage: g.newton_polygon() # needs sage.rings.padics Traceback (most recent call last): ... PrecisionError: The coefficient of t^4 has not enough precision @@ -1188,8 +1204,8 @@ def newton_polygon(self): sage: S.<x> = PowerSeriesRing(GF(5)) sage: R.<y> = S[] - sage: p = x^2+y+x*y^2 - sage: p.newton_polygon() + sage: p = x^2 + y + x*y^2 + sage: p.newton_polygon() # needs sage.geometry.polyhedron Finite Newton polygon with 3 vertices: (0, 2), (1, 0), (2, 1) AUTHOR: @@ -1224,6 +1240,7 @@ def hensel_lift(self, a): EXAMPLES:: + sage: # needs sage.rings.padics sage: K = Qp(5, 10) sage: P.<x> = PolynomialRing(K) sage: f = x^2 + 1 @@ -1232,8 +1249,8 @@ def hensel_lift(self, a): sage: f(root) O(5^10) - sage: g = (x^2 + 1)*(x - 7) - sage: g.hensel_lift(2) # here, 2 is a multiple root modulo p + sage: g = (x^2 + 1) * (x - 7) # needs sage.rings.padics + sage: g.hensel_lift(2) # here, 2 is a multiple root modulo p # needs sage.rings.padics Traceback (most recent call last): ... ValueError: a is not close enough to a root of this polynomial @@ -1272,17 +1289,18 @@ def _factor_of_degree(self, deg): EXAMPLES:: + sage: # needs sage.rings.padics sage: K = Qp(5) sage: R.<x> = K[] sage: K = Qp(5) sage: R.<t> = K[] sage: f = 5 + 3*t + t^4 + 25*t^10 - sage: g = f._factor_of_degree(4) - sage: (f % g).is_zero() + sage: g = f._factor_of_degree(4) # needs sage.rings.padics + sage: (f % g).is_zero() # needs sage.rings.padics True - sage: g = f._factor_of_degree(3) # not tested + sage: g = f._factor_of_degree(3) # not tested # needs sage.rings.padics Traceback (most recent call last) ... KeyboardInterrupt: @@ -1291,7 +1309,7 @@ def _factor_of_degree(self, deg): sage: S.<x> = PowerSeriesRing(GF(5)) sage: R.<y> = S[] - sage: p = x^2+y+x*y^2 + sage: p = x^2 + y + x*y^2 sage: p._factor_of_degree(1) (1 + O(x^20))*y + x^2 + x^5 + 2*x^8 + 4*x^14 + 2*x^17 + 2*x^20 + O(x^22) @@ -1325,7 +1343,7 @@ def factor_of_slope(self, slope=None): """ INPUT: - - slope -- a rational number (default: the first slope + - ``slope`` -- a rational number (default: the first slope in the Newton polygon of ``self``) OUTPUT: @@ -1336,6 +1354,7 @@ def factor_of_slope(self, slope=None): EXAMPLES:: + sage: # needs sage.rings.padics sage: K = Qp(5) sage: R.<x> = K[] sage: K = Qp(5) @@ -1344,22 +1363,22 @@ def factor_of_slope(self, slope=None): sage: f.newton_slopes() [1, 0, 0, 0, -1/3, -1/3, -1/3, -1/3, -1/3, -1/3] - sage: g = f.factor_of_slope(0) - sage: g.newton_slopes() + sage: g = f.factor_of_slope(0) # needs sage.rings.padics + sage: g.newton_slopes() # needs sage.rings.padics [0, 0, 0] - sage: (f % g).is_zero() + sage: (f % g).is_zero() # needs sage.rings.padics True - sage: h = f.factor_of_slope() - sage: h.newton_slopes() + sage: h = f.factor_of_slope() # needs sage.rings.padics + sage: h.newton_slopes() # needs sage.rings.padics [1] - sage: (f % h).is_zero() + sage: (f % h).is_zero() # needs sage.rings.padics True If ``slope`` is not a slope of ``self``, the corresponding factor is `1`:: - sage: f.factor_of_slope(-1) + sage: f.factor_of_slope(-1) # needs sage.rings.padics 1 + O(5^20) AUTHOR: @@ -1405,6 +1424,7 @@ def slope_factorization(self): EXAMPLES:: + sage: # needs sage.rings.padics sage: K = Qp(5) sage: R.<x> = K[] sage: K = Qp(5) @@ -1413,10 +1433,10 @@ def slope_factorization(self): sage: f.newton_slopes() [1, 0, 0, 0, -1/3, -1/3, -1/3, -1/3, -1/3, -1/3] - sage: F = f.slope_factorization() - sage: F.prod() == f + sage: F = f.slope_factorization() # needs sage.rings.padics + sage: F.prod() == f # needs sage.rings.padics True - sage: for (f,_) in F: + sage: for (f,_) in F: # needs sage.rings.padics ....: print(f.newton_slopes()) [-1/3, -1/3, -1/3, -1/3, -1/3, -1/3] [0, 0, 0] @@ -1426,9 +1446,11 @@ def slope_factorization(self): sage: S.<x> = PowerSeriesRing(GF(5)) sage: R.<y> = S[] - sage: p = x^2+y+x*y^2 - sage: p.slope_factorization() - (x) * ((x + O(x^22))*y + 1 + 4*x^3 + 4*x^6 + 3*x^9 + x^15 + 3*x^18 + O(x^21)) * ((x^-1 + O(x^20))*y + x + x^4 + 2*x^7 + 4*x^13 + 2*x^16 + 2*x^19 + O(x^22)) + sage: p = x^2 + y + x*y^2 + sage: p.slope_factorization() # needs sage.geometry.polyhedron + (x) + * ((x + O(x^22))*y + 1 + 4*x^3 + 4*x^6 + 3*x^9 + x^15 + 3*x^18 + O(x^21)) + * ((x^-1 + O(x^20))*y + x + x^4 + 2*x^7 + 4*x^13 + 2*x^16 + 2*x^19 + O(x^22)) AUTHOR: @@ -1480,6 +1502,7 @@ def _roots(self, secure, minval, hint): TESTS:: + sage: # needs sage.rings.padics sage: R = Zp(2) sage: S.<x> = R[] sage: P = (x-1) * (x-2) * (x-4) * (x-8) * (x-16) @@ -1554,7 +1577,6 @@ def _roots(self, secure, minval, hint): return roots - class Polynomial_generic_dense_cdv(Polynomial_generic_dense_inexact, Polynomial_generic_cdv): pass @@ -1565,9 +1587,11 @@ class Polynomial_generic_sparse_cdv(Polynomial_generic_sparse, Polynomial_generi class Polynomial_generic_cdvr(Polynomial_generic_cdv): pass + class Polynomial_generic_dense_cdvr(Polynomial_generic_dense_cdv, Polynomial_generic_cdvr): pass + class Polynomial_generic_sparse_cdvr(Polynomial_generic_sparse_cdv, Polynomial_generic_cdvr): pass @@ -1575,19 +1599,24 @@ class Polynomial_generic_sparse_cdvr(Polynomial_generic_sparse_cdv, Polynomial_g class Polynomial_generic_cdvf(Polynomial_generic_cdv, Polynomial_generic_field): pass + class Polynomial_generic_dense_cdvf(Polynomial_generic_dense_cdv, Polynomial_generic_cdvf): pass + class Polynomial_generic_sparse_cdvf(Polynomial_generic_sparse_cdv, Polynomial_generic_cdvf): pass + ############################################################################ # XXX: Ensures that the generic polynomials implemented in Sage via PARI # # until at least until 4.5.0 unpickle correctly as polynomials implemented # # via FLINT. # -from sage.misc.persist import register_unpickle_override -from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint - -register_unpickle_override( \ - 'sage.rings.polynomial.polynomial_element_generic', \ - 'Polynomial_rational_dense', Polynomial_rational_flint) +try: + from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint +except ImportError: + pass +else: + from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.rings.polynomial.polynomial_element_generic', + 'Polynomial_rational_dense', Polynomial_rational_flint) diff --git a/src/sage/rings/polynomial/polynomial_gf2x.pyx b/src/sage/rings/polynomial/polynomial_gf2x.pyx index 284e319be99..9dd344ca681 100644 --- a/src/sage/rings/polynomial/polynomial_gf2x.pyx +++ b/src/sage/rings/polynomial/polynomial_gf2x.pyx @@ -34,8 +34,8 @@ from sage.matrix.matrix_mod2_dense cimport Matrix_mod2_dense from sage.misc.cachefunc import cached_method cdef class Polynomial_GF2X(Polynomial_template): - """ - Univariate Polynomials over GF(2) via NTL's GF2X. + r""" + Univariate Polynomials over `\GF{2}` via NTL's GF2X. EXAMPLES:: @@ -44,8 +44,8 @@ cdef class Polynomial_GF2X(Polynomial_template): x^3 + x^2 + 1 """ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): - """ - Create a new univariate polynomials over GF(2). + r""" + Create a new univariate polynomials over `\GF{2}`. EXAMPLES:: @@ -117,7 +117,7 @@ cdef class Polynomial_GF2X(Polynomial_template): - ``g`` -- a polynomial - ``h`` -- a polynomial - - ``algorithm`` -- either 'native' or 'ntl' (default: 'native') + - ``algorithm`` -- either ``'native'`` or ``'ntl'`` (default: ``'native'``) EXAMPLES:: @@ -132,7 +132,7 @@ cdef class Polynomial_GF2X(Polynomial_template): sage: f = x^29 + x^24 + x^22 + x^21 + x^20 + x^16 + x^15 + x^14 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^2 sage: g = x^31 + x^30 + x^28 + x^26 + x^24 + x^21 + x^19 + x^18 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 sage: h = x^30 + x^28 + x^26 + x^25 + x^24 + x^22 + x^21 + x^18 + x^17 + x^15 + x^13 + x^12 + x^11 + x^10 + x^9 + x^4 - sage: f.modular_composition(g,h) == f(g) % h + sage: f.modular_composition(g, h) == f(g) % h True AUTHORS: @@ -143,9 +143,9 @@ cdef class Polynomial_GF2X(Polynomial_template): if g.parent() is not self.parent() or h.parent() is not self.parent(): raise TypeError("Parents of the first three parameters must match.") - from sage.misc.misc import cputime + from sage.misc.timing import cputime from sage.misc.verbose import verbose - from sage.functions.all import ceil + from sage.arith.misc import integer_ceil as ceil from sage.matrix.constructor import Matrix from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF @@ -259,7 +259,7 @@ cdef class Polynomial_GF2X(Polynomial_template): @cached_method def is_irreducible(self): r""" - Return whether this polynomial is irreducible over `\GF{2}`.` + Return whether this polynomial is irreducible over `\GF{2}`. EXAMPLES:: @@ -308,7 +308,7 @@ def GF2X_BuildIrred_list(n): cdef GF2X_c f GF2 = FiniteField(2) GF2X_BuildIrred(f, int(n)) - return [GF2(not GF2_IsZero(GF2X_coeff(f, i))) for i in xrange(n + 1)] + return [GF2(not GF2_IsZero(GF2X_coeff(f, i))) for i in range(n + 1)] def GF2X_BuildSparseIrred_list(n): """ @@ -328,7 +328,7 @@ def GF2X_BuildSparseIrred_list(n): cdef GF2X_c f GF2 = FiniteField(2) GF2X_BuildSparseIrred(f, int(n)) - return [GF2(not GF2_IsZero(GF2X_coeff(f, i))) for i in xrange(n + 1)] + return [GF2(not GF2_IsZero(GF2X_coeff(f, i))) for i in range(n + 1)] def GF2X_BuildRandomIrred_list(n): """ @@ -350,4 +350,4 @@ def GF2X_BuildRandomIrred_list(n): current_randstate().set_seed_ntl(False) GF2X_BuildSparseIrred(tmp, int(n)) GF2X_BuildRandomIrred(f, tmp) - return [GF2(not GF2_IsZero(GF2X_coeff(f, i))) for i in xrange(n + 1)] + return [GF2(not GF2_IsZero(GF2X_coeff(f, i))) for i in range(n + 1)] diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pxd b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pxd index 03c5cebbf09..b1b593d6a26 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pxd +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pxd @@ -5,7 +5,7 @@ from sage.rings.integer cimport Integer from sage.structure.parent cimport Parent cdef class Polynomial_integer_dense_flint(Polynomial): - cdef fmpz_poly_t __poly + cdef fmpz_poly_t _poly cdef Polynomial_integer_dense_flint _new(self) cpdef _unsafe_mutate(self, long n, value) diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx index 1d5a863e899..7bb023e8452 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx @@ -42,12 +42,12 @@ from cysignals.signals cimport sig_on, sig_off include "sage/libs/ntl/decl.pxi" -from cpython.int cimport PyInt_AS_LONG +from cpython.long cimport PyLong_AsLong from sage.libs.gmp.mpz cimport * from sage.arith.long cimport pyobject_to_long, is_small_python_int from sage.rings.polynomial.polynomial_element cimport Polynomial -from sage.structure.element cimport ModuleElement, Element +from sage.structure.element cimport Element from sage.structure.element import coerce_binop from sage.libs.ntl.ntl_ZZX cimport ntl_ZZX @@ -70,7 +70,7 @@ from sage.libs.ntl.ZZX cimport * from sage.rings.complex_arb cimport ComplexBall from sage.rings.integer cimport Integer, smallInteger from sage.rings.real_arb cimport RealBall -from sage.rings.real_mpfr cimport RealNumber, RealField_class +from sage.rings.real_mpfr cimport RealNumber from sage.rings.real_mpfi cimport RealIntervalFieldElement from sage.rings.polynomial.evaluation_flint cimport fmpz_poly_evaluation_mpfr, fmpz_poly_evaluation_mpfi @@ -99,14 +99,14 @@ cdef class Polynomial_integer_dense_flint(Polynomial): r""" This calls the underlying FLINT fmpz_poly constructor """ - fmpz_poly_init(self.__poly) + fmpz_poly_init(self._poly) def __dealloc__(self): r""" calls the underlying FLINT fmpz_poly destructor """ - fmpz_poly_clear(self.__poly) + fmpz_poly_clear(self._poly) cdef Polynomial_integer_dense_flint _new(self): r""" @@ -139,7 +139,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): x._is_gen = 0 if not isinstance(a, Integer): a = ZZ(a) - fmpz_poly_set_coeff_mpz(x.__poly, 0, (<Integer>a).value) + fmpz_poly_set_coeff_mpz(x._poly, 0, (<Integer>a).value) return x def __init__(self, parent, x=None, check=True, is_gen=False, @@ -224,8 +224,8 @@ cdef class Polynomial_integer_dense_flint(Polynomial): if isinstance(x, Polynomial): if x.parent() is self.parent(): sig_on() - fmpz_poly_set(self.__poly, \ - (<Polynomial_integer_dense_flint>x).__poly) + fmpz_poly_set(self._poly, + (<Polynomial_integer_dense_flint>x)._poly) sig_off() return else: @@ -246,7 +246,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): degree = i try: sig_on() - fmpz_poly_realloc(self.__poly, degree + 1) + fmpz_poly_realloc(self._poly, degree + 1) sig_off() except RuntimeError: raise OverflowError("Cannot allocate memory!") @@ -255,13 +255,13 @@ cdef class Polynomial_integer_dense_flint(Polynomial): i = ii[0] if type(ii) is tuple else ii if is_small_python_int(a): sig_on() - fmpz_poly_set_coeff_si(self.__poly, i, a) + fmpz_poly_set_coeff_si(self._poly, i, a) sig_off() else: if not isinstance(a, Integer): a = ZZ(a) sig_on() - fmpz_poly_set_coeff_mpz(self.__poly, i, (<Integer>a).value) + fmpz_poly_set_coeff_mpz(self._poly, i, (<Integer>a).value) sig_off() return @@ -270,7 +270,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): check = False elif isinstance(x, ntl_ZZX): # coercion from ntl.pyx object - fmpz_poly_set_ZZX(self.__poly, (<ntl_ZZX>x).x) + fmpz_poly_set_ZZX(self._poly, (<ntl_ZZX>x).x) return elif isinstance(x, FractionFieldElement) and \ @@ -278,8 +278,8 @@ cdef class Polynomial_integer_dense_flint(Polynomial): if x.denominator() == 1: # fraction of the form f(x)/1 sig_on() - fmpz_poly_set(self.__poly, - (<Polynomial_integer_dense_flint>x.numerator()).__poly) + fmpz_poly_set(self._poly, + (<Polynomial_integer_dense_flint>x.numerator())._poly) sig_off() return @@ -287,19 +287,19 @@ cdef class Polynomial_integer_dense_flint(Polynomial): x = [x] # constant polynomials sig_on() - fmpz_poly_realloc(self.__poly, len(x)) + fmpz_poly_realloc(self._poly, len(x)) sig_off() for i from 0 <= i < len(x): a = x[i] if is_small_python_int(a): sig_on() - fmpz_poly_set_coeff_si(self.__poly, i, a) + fmpz_poly_set_coeff_si(self._poly, i, a) sig_off() else: if not isinstance(a, Integer): a = ZZ(a) sig_on() - fmpz_poly_set_coeff_mpz(self.__poly, i, (<Integer>a).value) + fmpz_poly_set_coeff_mpz(self._poly, i, (<Integer>a).value) sig_off() def _eval_mpfr_(self, RealNumber a): @@ -327,7 +327,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): """ cdef RealNumber res = a._new() sig_on() - fmpz_poly_evaluation_mpfr(res.value, self.__poly, a.value) + fmpz_poly_evaluation_mpfr(res.value, self._poly, a.value) sig_off() return res @@ -357,7 +357,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): """ cdef RealIntervalFieldElement res = a._new() sig_on() - fmpz_poly_evaluation_mpfi(res.value, self.__poly, a.value) + fmpz_poly_evaluation_mpfi(res.value, self._poly, a.value) sig_off() return res @@ -412,8 +412,8 @@ cdef class Polynomial_integer_dense_flint(Polynomial): if isinstance(x, Polynomial_integer_dense_flint): f = self._new() sig_on() - fmpz_poly_compose(f.__poly, self.__poly, \ - (<Polynomial_integer_dense_flint> x0).__poly) + fmpz_poly_compose(f._poly, self._poly, + (<Polynomial_integer_dense_flint> x0)._poly) sig_off() return f if is_small_python_int(x0): @@ -421,8 +421,8 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sig_on() fmpz_init(a_fmpz) fmpz_init(z_fmpz) - fmpz_set_si(a_fmpz, PyInt_AS_LONG(x0)) - fmpz_poly_evaluate_fmpz(z_fmpz, self.__poly, a_fmpz) + fmpz_set_si(a_fmpz, PyLong_AsLong(x0)) + fmpz_poly_evaluate_fmpz(z_fmpz, self._poly, a_fmpz) fmpz_get_mpz(z.value, z_fmpz) fmpz_clear(a_fmpz) fmpz_clear(z_fmpz) @@ -433,7 +433,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): if isinstance(x0, Integer): a = <Integer> x0 - if fmpz_poly_length(self.__poly) == 0: + if fmpz_poly_length(self._poly) == 0: return ZZ.zero() if mpz_sgn(a.value) == 0: return self[0] @@ -444,7 +444,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): fmpz_init(a_fmpz) fmpz_init(z_fmpz) fmpz_set_mpz(a_fmpz, a.value) - fmpz_poly_evaluate_fmpz(z_fmpz, self.__poly, a_fmpz) + fmpz_poly_evaluate_fmpz(z_fmpz, self._poly, a_fmpz) fmpz_get_mpz(z.value, z_fmpz) fmpz_clear(a_fmpz) fmpz_clear(z_fmpz) @@ -460,14 +460,14 @@ cdef class Polynomial_integer_dense_flint(Polynomial): arb_a = <RealBall> x0 arb_z = arb_a._new() sig_on() - arb_fmpz_poly_evaluate_arb(arb_z.value, self.__poly, arb_a.value, arb_a._parent._prec) + arb_fmpz_poly_evaluate_arb(arb_z.value, self._poly, arb_a.value, arb_a._parent._prec) sig_off() return arb_z if isinstance(x0, ComplexBall): acb_a = <ComplexBall> x0 acb_z = acb_a._new() sig_on() - arb_fmpz_poly_evaluate_acb(acb_z.value, self.__poly, acb_a.value, acb_a._parent._prec) + arb_fmpz_poly_evaluate_acb(acb_z.value, self._poly, acb_a.value, acb_a._parent._prec) sig_off() return acb_z @@ -510,10 +510,10 @@ cdef class Polynomial_integer_dense_flint(Polynomial): cdef fmpz_t c fmpz_init(c) - fmpz_poly_get_coeff_fmpz(c, self.__poly, fmpz_poly_degree(self.__poly)) + fmpz_poly_get_coeff_fmpz(c, self._poly, fmpz_poly_degree(self._poly)) cdef int sign = fmpz_sgn(c) - fmpz_poly_content(c, self.__poly) + fmpz_poly_content(c, self._poly) cdef Integer z = Integer.__new__(Integer) fmpz_get_mpz(z.value, c) @@ -561,7 +561,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): 5*x^5 + 4*x^4 + 3*x^3 + 2*x^2 + x + 1 """ cdef Integer z = Integer.__new__(Integer) - fmpz_poly_get_coeff_mpz(z.value, self.__poly, n) + fmpz_poly_get_coeff_mpz(z.value, self._poly, n) return z def _repr(self, name=None, bint latex=False): @@ -583,8 +583,8 @@ cdef class Polynomial_integer_dense_flint(Polynomial): cdef long i cdef Integer coef = Integer.__new__(Integer) cdef list all = [] - for i from fmpz_poly_degree(self.__poly) >= i >= 0: - fmpz_poly_get_coeff_mpz(coef.value, self.__poly, i) + for i from fmpz_poly_degree(self._poly) >= i >= 0: + fmpz_poly_get_coeff_mpz(coef.value, self._poly, i) if coef: if coef > 0: sign_str = '+' @@ -637,7 +637,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): cpdef _add_(self, right): r""" - Returns self plus right. + Return ``self`` plus ``right``. EXAMPLES:: @@ -649,15 +649,15 @@ cdef class Polynomial_integer_dense_flint(Polynomial): """ cdef Polynomial_integer_dense_flint x = self._new() sig_on() - fmpz_poly_add(x.__poly, self.__poly, - (<Polynomial_integer_dense_flint>right).__poly) + fmpz_poly_add(x._poly, self._poly, + (<Polynomial_integer_dense_flint>right)._poly) sig_off() return x cpdef _sub_(self, right): r""" - Return self minus right. + Return ``self`` minus ``right``. EXAMPLES:: @@ -669,15 +669,15 @@ cdef class Polynomial_integer_dense_flint(Polynomial): """ cdef Polynomial_integer_dense_flint x = self._new() sig_on() - fmpz_poly_sub(x.__poly, self.__poly, - (<Polynomial_integer_dense_flint>right).__poly) + fmpz_poly_sub(x._poly, self._poly, + (<Polynomial_integer_dense_flint>right)._poly) sig_off() return x cpdef _neg_(self): r""" - Returns negative of self. + Return negative of ``self``. EXAMPLES:: @@ -688,14 +688,14 @@ cdef class Polynomial_integer_dense_flint(Polynomial): """ cdef Polynomial_integer_dense_flint x = self._new() sig_on() - fmpz_poly_neg(x.__poly, self.__poly) + fmpz_poly_neg(x._poly, self._poly) sig_off() return x @coerce_binop def quo_rem(self, Polynomial_integer_dense_flint right): r""" - Attempts to divide self by right, and return a quotient and remainder. + Attempts to divide ``self`` by ``right``, and return a quotient and remainder. EXAMPLES:: @@ -758,13 +758,13 @@ cdef class Polynomial_integer_dense_flint(Polynomial): cdef Polynomial_integer_dense_flint rr = self._new() sig_on() - fmpz_poly_divrem(qq.__poly, rr.__poly, self.__poly, right.__poly) + fmpz_poly_divrem(qq._poly, rr._poly, self._poly, right._poly) sig_off() return qq, rr cpdef bint is_zero(self) except -1: """ - Returns True if self is equal to zero. + Return ``True`` if ``self`` is equal to zero. EXAMPLES:: @@ -776,11 +776,11 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sage: x.is_zero() False """ - return (fmpz_poly_degree(self.__poly) == -1) + return (fmpz_poly_degree(self._poly) == -1) cpdef bint is_one(self) except -1: """ - Returns True if self is equal to one. + Return ``True`` if ``self`` is equal to one. EXAMPLES:: @@ -792,11 +792,11 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sage: x.is_one() False """ - return fmpz_poly_is_one(self.__poly) + return fmpz_poly_is_one(self._poly) def __bool__(self): """ - Check if self is not zero. + Check if ``self`` is not zero. EXAMPLES:: @@ -808,19 +808,19 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sage: bool(x) True """ - return not (fmpz_poly_degree(self.__poly) == -1) + return not (fmpz_poly_degree(self._poly) == -1) @coerce_binop def gcd(self, right): r""" - Return the GCD of self and right. The leading + Return the GCD of ``self`` and ``right``. The leading coefficient need not be 1. EXAMPLES:: sage: R.<x> = PolynomialRing(ZZ) - sage: f = (6*x + 47)*(7*x^2 - 2*x + 38) - sage: g = (6*x + 47)*(3*x^3 + 2*x + 1) + sage: f = (6*x + 47) * (7*x^2 - 2*x + 38) + sage: g = (6*x + 47) * (3*x^3 + 2*x + 1) sage: f.gcd(g) 6*x + 47 """ @@ -831,8 +831,8 @@ cdef class Polynomial_integer_dense_flint(Polynomial): return self cdef Polynomial_integer_dense_flint x = self._new() sig_on() - fmpz_poly_gcd(x.__poly, self.__poly, - (<Polynomial_integer_dense_flint>right).__poly) + fmpz_poly_gcd(x._poly, self._poly, + (<Polynomial_integer_dense_flint>right)._poly) sig_off() return x @@ -840,16 +840,16 @@ cdef class Polynomial_integer_dense_flint(Polynomial): @coerce_binop def lcm(self, right): """ - Return the LCM of self and right. + Return the LCM of ``self`` and ``right``. EXAMPLES:: sage: R.<x> = PolynomialRing(ZZ) - sage: f = (6*x + 47)*(7*x^2 - 2*x + 38) - sage: g = (6*x + 47)*(3*x^3 + 2*x + 1) + sage: f = (6*x + 47) * (7*x^2 - 2*x + 38) + sage: g = (6*x + 47) * (3*x^3 + 2*x + 1) sage: h = f.lcm(g); h 126*x^6 + 951*x^5 + 486*x^4 + 6034*x^3 + 585*x^2 + 3706*x + 1786 - sage: h == (6*x + 47)*(7*x^2 - 2*x + 38)*(3*x^3 + 2*x + 1) + sage: h == (6*x + 47) * (7*x^2 - 2*x + 38) * (3*x^3 + 2*x + 1) True TESTS: @@ -868,9 +868,9 @@ cdef class Polynomial_integer_dense_flint(Polynomial): @coerce_binop def xgcd(self, right): - """ - Return a triple ``(g,s,t)`` such that `g = s*self + t*right` and such - that `g` is the `gcd` of ``self`` and ``right`` up to a divisor of the + r""" + Return a triple `(g,s,t)` such that `g = s\cdot{}` ``self`` + `t\cdot{}` ``right`` and such + that `g` is the gcd of ``self`` and ``right`` up to a divisor of the resultant of ``self`` and ``other``. As integer polynomials do not form a principal ideal domain, it is not @@ -886,14 +886,14 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sage: P.<x> = PolynomialRing(ZZ) - sage: (x+2).xgcd(x+4) + sage: (x + 2).xgcd(x + 4) (2, -1, 1) - sage: (x+2).resultant(x+4) + sage: (x + 2).resultant(x + 4) 2 - sage: (x+2).gcd(x+4) + sage: (x + 2).gcd(x + 4) 1 - sage: F = (x^2 + 2)*x^3; G = (x^2+2)*(x-3) + sage: F = (x^2 + 2)*x^3; G = (x^2 + 2) * (x - 3) sage: g, u, v = F.xgcd(G) sage: g, u, v (27*x^2 + 54, 1, -x^2 - 3*x - 9) @@ -906,7 +906,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sage: zero.xgcd(x) (x, 0, 1) - sage: F = (x-3)^3; G = (x-15)^2 + sage: F = (x - 3)^3; G = (x - 15)^2 sage: g, u, v = F.xgcd(G) sage: g, u, v (2985984, -432*x + 8208, 432*x^2 + 864*x + 14256) @@ -941,8 +941,8 @@ cdef class Polynomial_integer_dense_flint(Polynomial): fmpz_init(r) sig_on() - fmpz_poly_xgcd(r, ss.__poly, tt.__poly, self.__poly, - (<Polynomial_integer_dense_flint>right).__poly) + fmpz_poly_xgcd(r, ss._poly, tt._poly, self._poly, + (<Polynomial_integer_dense_flint>right)._poly) sig_off() cdef Integer rr = Integer.__new__(Integer) fmpz_get_mpz(rr.value, r) @@ -960,7 +960,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): cpdef _mul_(self, right): r""" - Returns self multiplied by right. + Return ``self`` multiplied by ``right``. EXAMPLES:: @@ -970,8 +970,8 @@ cdef class Polynomial_integer_dense_flint(Polynomial): """ cdef Polynomial_integer_dense_flint x = self._new() sig_on() - fmpz_poly_mul(x.__poly, self.__poly, - (<Polynomial_integer_dense_flint>right).__poly) + fmpz_poly_mul(x._poly, self._poly, + (<Polynomial_integer_dense_flint>right)._poly) sig_off() return x @@ -1000,15 +1000,15 @@ cdef class Polynomial_integer_dense_flint(Polynomial): cdef Polynomial_integer_dense_flint x = self._new() sig_on() - fmpz_poly_mullow(x.__poly, self.__poly, - (<Polynomial_integer_dense_flint>right).__poly, + fmpz_poly_mullow(x._poly, self._poly, + (<Polynomial_integer_dense_flint>right)._poly, n) sig_off() return x cpdef _lmul_(self, Element right): r""" - Returns self multiplied by right, where right is a scalar (integer). + Return ``self`` multiplied by ``right``, where ``right`` is a scalar (integer). EXAMPLES:: @@ -1020,13 +1020,13 @@ cdef class Polynomial_integer_dense_flint(Polynomial): """ cdef Polynomial_integer_dense_flint x = self._new() sig_on() - fmpz_poly_scalar_mul_mpz(x.__poly, self.__poly, (<Integer>right).value) + fmpz_poly_scalar_mul_mpz(x._poly, self._poly, (<Integer>right).value) sig_off() return x cpdef _rmul_(self, Element right): r""" - Returns self multiplied by right, where right is a scalar (integer). + Return ``self`` multiplied by ``right``, where right is a scalar (integer). EXAMPLES:: @@ -1038,7 +1038,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): """ cdef Polynomial_integer_dense_flint x = self._new() sig_on() - fmpz_poly_scalar_mul_mpz(x.__poly, self.__poly, (<Integer>right).value) + fmpz_poly_scalar_mul_mpz(x._poly, self._poly, (<Integer>right).value) sig_off() return x @@ -1132,7 +1132,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): num = n.numerator() den = n.denominator() - if fmpz_poly_degree(self.__poly) == 0: + if fmpz_poly_degree(self._poly) == 0: return self.parent()(self[0].nth_root(den) ** num) return self.nth_root(den) ** num @@ -1142,7 +1142,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): if self.is_zero(): if nn == 0: - fmpz_poly_set_coeff_si(res.__poly, 0, 1) + fmpz_poly_set_coeff_si(res._poly, 0, 1) return res elif nn < 0: raise ZeroDivisionError("negative exponent in power of zero") @@ -1150,17 +1150,17 @@ cdef class Polynomial_integer_dense_flint(Polynomial): return res if nn < 0: sig_on() - fmpz_poly_pow(res.__poly, self.__poly, -nn) + fmpz_poly_pow(res._poly, self._poly, -nn) sig_off() return ~res else: if self is self._parent.gen(): sig_on() - fmpz_poly_set_coeff_ui(res.__poly, nn, 1) + fmpz_poly_set_coeff_ui(res._poly, nn, 1) sig_off() else: sig_on() - fmpz_poly_pow(res.__poly, self.__poly, nn) + fmpz_poly_pow(res._poly, self._poly, nn) sig_off() return res @@ -1187,7 +1187,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): cdef Polynomial_integer_dense_flint res res = self._new() - fmpz_poly_pow_trunc(res.__poly, self.__poly, n, prec) + fmpz_poly_pow_trunc(res._poly, self._poly, n, prec) return res def __floordiv__(Polynomial_integer_dense_flint self, right): @@ -1226,14 +1226,14 @@ cdef class Polynomial_integer_dense_flint(Polynomial): else: res = self._new() sig_on() - fmpz_poly_scalar_fdiv_mpz(res.__poly, self.__poly, + fmpz_poly_scalar_fdiv_mpz(res._poly, self._poly, (<Integer> right).value) sig_off() return res elif right in ZZ: res = self._new() sig_on() - fmpz_poly_scalar_fdiv_mpz(res.__poly, self.__poly, + fmpz_poly_scalar_fdiv_mpz(res._poly, self._poly, (<Integer>ZZ(right)).value) sig_off() return res @@ -1248,7 +1248,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): else: res = self._new() sig_on() - fmpz_poly_div(res.__poly, self.__poly, _right.__poly) + fmpz_poly_div(res._poly, self._poly, _right._poly) sig_off() return res @@ -1260,7 +1260,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): EXAMPLES:: sage: x = polygen(ZZ) - sage: p = 1+x+2*x^2 + sage: p = 1 + x + 2*x^2 sage: q5 = p.inverse_series_trunc(5) sage: q5 -x^4 + 3*x^3 - x^2 - x + 1 @@ -1293,9 +1293,9 @@ cdef class Polynomial_integer_dense_flint(Polynomial): if prec <= 0: raise ValueError("the precision must be positive, got {}".format(prec)) - if fmpz_poly_degree(self.__poly) == -1: + if fmpz_poly_degree(self._poly) == -1: raise ValueError("constant term is zero") - cdef fmpz_t c = fmpz_poly_get_coeff_ptr(self.__poly, 0) + cdef fmpz_t c = fmpz_poly_get_coeff_ptr(self._poly, 0) if fmpz_cmp_si(c, 1) and fmpz_cmp_si(c, -1): raise ValueError("constant term {} is not a unit".format(self[0])) @@ -1303,7 +1303,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): if prec <= 0: return res sig_on() - fmpz_poly_inv_series(res.__poly, self.__poly, prec) + fmpz_poly_inv_series(res._poly, self._poly, prec) sig_off() return res @@ -1331,21 +1331,21 @@ cdef class Polynomial_integer_dense_flint(Polynomial): raise IndexError("n must be >= 0") if isinstance(value, int): sig_on() - fmpz_poly_set_coeff_si(self.__poly, n, value) + fmpz_poly_set_coeff_si(self._poly, n, value) sig_off() elif isinstance(value, Integer): sig_on() - fmpz_poly_set_coeff_mpz(self.__poly, n, (<Integer>value).value) + fmpz_poly_set_coeff_mpz(self._poly, n, (<Integer>value).value) sig_off() else: value = Integer(value) sig_on() - fmpz_poly_set_coeff_mpz(self.__poly, n, (<Integer>value).value) + fmpz_poly_set_coeff_mpz(self._poly, n, (<Integer>value).value) sig_off() def real_root_intervals(self): """ - Returns isolating intervals for the real roots of this + Return isolating intervals for the real roots of this polynomial. EXAMPLES: @@ -1364,7 +1364,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): ## def __copy__(self): ## f = Polynomial_integer_dense(self.parent()) -## f.__poly = self.__poly.copy() +## f._poly = self._poly.copy() ## return f @@ -1372,7 +1372,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): """ Return the degree of this polynomial. - The zero polynomial has degree -1. + The zero polynomial has degree `-1`. EXAMPLES:: @@ -1391,7 +1391,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sage: type(x.degree()) <class 'sage.rings.integer.Integer'> """ - return smallInteger(fmpz_poly_degree(self.__poly)) + return smallInteger(fmpz_poly_degree(self._poly)) def pseudo_divrem(self, B): r""" @@ -1426,12 +1426,12 @@ cdef class Polynomial_integer_dense_flint(Polynomial): """ cdef Polynomial_integer_dense_flint Q = self._new(), R = self._new(), _B = B cdef ulong d - fmpz_poly_pseudo_divrem(Q.__poly, R.__poly, &d, self.__poly, _B.__poly) + fmpz_poly_pseudo_divrem(Q._poly, R._poly, &d, self._poly, _B._poly) return Q, R, Integer(d) def discriminant(self, proof=True): r""" - Return the discriminant of self, which is by definition + Return the discriminant of ``self``, which is by definition .. MATH:: @@ -1460,7 +1460,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): """ cdef ZZX_c ntl_poly cdef ZZ_c* temp - fmpz_poly_get_ZZX(ntl_poly, self.__poly) + fmpz_poly_get_ZZX(ntl_poly, self._poly) temp = ZZX_discriminant(&ntl_poly, proof) cdef Integer x = Integer.__new__(Integer) @@ -1490,11 +1490,11 @@ cdef class Polynomial_integer_dense_flint(Polynomial): def squarefree_decomposition(Polynomial_integer_dense_flint self): """ - Return the square-free decomposition of self. This is - a partial factorization of self into square-free, relatively + Return the square-free decomposition of ``self``. This is + a partial factorization of ``self`` into square-free, relatively prime polynomials. - This is a wrapper for the NTL function SquareFreeDecomp. + This is a wrapper for the NTL function ``SquareFreeDecomp``. EXAMPLES:: @@ -1531,12 +1531,12 @@ cdef class Polynomial_integer_dense_flint(Polynomial): # the primitive part returned by FLINT has positive leading # coefficient - fmpz_poly_primitive_part(ppart, self.__poly) + fmpz_poly_primitive_part(ppart, self._poly) fmpz_poly_get_ZZX(ntl_poly, ppart) fmpz_poly_clear(ppart) else: - fmpz_poly_get_ZZX(ntl_poly, self.__poly) + fmpz_poly_get_ZZX(ntl_poly, self._poly) # input is primitive, with positive leading coefficient ZZX_squarefree_decomposition(&v, &e, &n, &ntl_poly) @@ -1544,7 +1544,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): F = [] for i from 0 <= i < n: fac = self._new() - fmpz_poly_set_ZZX(fac.__poly, v[i][0]) + fmpz_poly_set_ZZX(fac._poly, v[i][0]) F.append( (fac,e[i]) ) del v[i] sig_free(v) @@ -1582,9 +1582,9 @@ cdef class Polynomial_integer_dense_flint(Polynomial): cdef ZZ_c content cdef vec_pair_ZZX_long_c factors cdef long i - cdef int sig_me = fmpz_poly_degree(self.__poly) + cdef int sig_me = fmpz_poly_degree(self._poly) - fmpz_poly_get_ZZX(ntl_poly, self.__poly) + fmpz_poly_get_ZZX(ntl_poly, self._poly) if sig_me > 10: sig_on() @@ -1603,20 +1603,20 @@ cdef class Polynomial_integer_dense_flint(Polynomial): fac_py = self._new() fmpz_init(tcontent) fmpz_set_ZZ(tcontent, content) - fmpz_poly_set_coeff_fmpz(fac_py.__poly, 0, tcontent) + fmpz_poly_set_coeff_fmpz(fac_py._poly, 0, tcontent) results.append( (fac_py,1) ) fmpz_clear(tcontent) for i from 0 <= i < factors.length(): fac_py = self._new() - fmpz_poly_set_ZZX(fac_py.__poly, factors.RawGet(i).a) + fmpz_poly_set_ZZX(fac_py._poly, factors.RawGet(i).a) results.append( (fac_py,factors.RawGet(i).b) ) return Factorization(results, unit = unit) def factor(self): """ This function overrides the generic polynomial factorization to - make a somewhat intelligent decision to use Pari or NTL based on + make a somewhat intelligent decision to use PARI or NTL based on some benchmarking. Note: This function factors the content of the polynomial, @@ -1626,11 +1626,11 @@ cdef class Polynomial_integer_dense_flint(Polynomial): EXAMPLES:: - sage: R.<x>=ZZ[] - sage: f=x^4-1 + sage: R.<x> = ZZ[] + sage: f = x^4 - 1 sage: f.factor() (x - 1) * (x + 1) * (x^2 + 1) - sage: f=1-x + sage: f = 1 - x sage: f.factor() (-1) * (x - 1) sage: f.factor().unit() @@ -1639,7 +1639,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): (-1) * 2 * 3 * 5 * x """ cdef int i - cdef long deg = fmpz_poly_degree(self.__poly) + cdef long deg = fmpz_poly_degree(self._poly) # it appears that pari has a window from about degrees 30 and 300 # in which it beats NTL. c = self.content() @@ -1651,15 +1651,13 @@ cdef class Polynomial_integer_dense_flint(Polynomial): def factor_mod(self, p): """ - Return the factorization of self modulo the prime `p`. + Return the factorization of ``self`` modulo the prime `p`. INPUT: - ``p`` -- prime - OUTPUT: - - factorization of self reduced modulo p. + OUTPUT: factorization of ``self`` reduced modulo `p`. EXAMPLES:: @@ -1667,13 +1665,13 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sage: f = -3*x*(x-2)*(x-9) + x sage: f.factor_mod(3) x - sage: f = -3*x*(x-2)*(x-9) + sage: f = -3 * x * (x - 2) * (x - 9) sage: f.factor_mod(3) Traceback (most recent call last): ... ArithmeticError: factorization of 0 is not defined - sage: f = 2*x*(x-2)*(x-9) + sage: f = 2 * x * (x - 2) * (x - 9) sage: f.factor_mod(7) (2) * x * (x + 5)^2 """ @@ -1691,7 +1689,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): def factor_padic(self, p, prec=10): """ - Return `p`-adic factorization of self to given precision. + Return `p`-adic factorization of ``self`` to given precision. INPUT: @@ -1699,22 +1697,22 @@ cdef class Polynomial_integer_dense_flint(Polynomial): - ``prec`` -- integer; the precision - OUTPUT: - - - factorization of ``self`` over the completion at `p`. + OUTPUT: factorization of ``self`` over the completion at `p`. EXAMPLES:: sage: R.<x> = PolynomialRing(ZZ) sage: f = x^2 + 1 sage: f.factor_padic(5, 4) - ((1 + O(5^4))*x + 2 + 5 + 2*5^2 + 5^3 + O(5^4)) * ((1 + O(5^4))*x + 3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4)) + ((1 + O(5^4))*x + 2 + 5 + 2*5^2 + 5^3 + O(5^4)) + * ((1 + O(5^4))*x + 3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4)) A more difficult example:: sage: f = 100 * (5*x + 1)^2 * (x + 5)^2 sage: f.factor_padic(5, 10) - (4 + O(5^10)) * (5 + O(5^11))^2 * ((1 + O(5^10))*x + 5 + O(5^10))^2 * ((5 + O(5^10))*x + 1 + O(5^10))^2 + (4 + O(5^10)) * (5 + O(5^11))^2 * ((1 + O(5^10))*x + 5 + O(5^10))^2 + * ((5 + O(5^10))*x + 1 + O(5^10))^2 """ from sage.rings.padics.factory import Zp @@ -1753,20 +1751,18 @@ cdef class Polynomial_integer_dense_flint(Polynomial): @coerce_binop def resultant(self, other, proof=True): """ - Returns the resultant of self and other, which must lie in the same + Return the resultant of ``self`` and ``other``, which must lie in the same polynomial ring. - If ``proof = False`` (the default is ``proof=True``), then this function may + If ``proof=False`` (the default is ``proof=True``), then this function may use a randomized strategy that errors with probability no more than `2^{-80}`. INPUT: - - other -- a polynomial - - OUTPUT: + - ``other`` -- a polynomial - an element of the base ring of the polynomial ring + OUTPUT: an element of the base ring of the polynomial ring EXAMPLES:: @@ -1787,8 +1783,8 @@ cdef class Polynomial_integer_dense_flint(Polynomial): cdef Integer x = Integer.__new__(Integer) sig_on() - fmpz_poly_resultant(res, self.__poly, - (<Polynomial_integer_dense_flint>other).__poly) + fmpz_poly_resultant(res, self._poly, + (<Polynomial_integer_dense_flint>other)._poly) sig_off() fmpz_get_mpz(x.value, res) fmpz_clear(res) @@ -1834,15 +1830,15 @@ cdef class Polynomial_integer_dense_flint(Polynomial): if d != degree: raise ValueError("degree argument must be a non-negative integer, got %s" % degree) # FLINT expects length - fmpz_poly_reverse(res.__poly, self.__poly, d+1) + fmpz_poly_reverse(res._poly, self._poly, d+1) else: - fmpz_poly_reverse(res.__poly, self.__poly, - fmpz_poly_length(self.__poly)) + fmpz_poly_reverse(res._poly, self._poly, + fmpz_poly_length(self._poly)) return res def revert_series(self, n): r""" - Return a polynomial `f` such that `f(self(x)) = self(f(x)) = x mod x^n`. + Return a polynomial `f` such that `f(` ``self`` `(x)) =` ``self`` `(f(x)) = x` (mod `x^n`). EXAMPLES:: @@ -1871,7 +1867,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): raise ValueError("self must have constant coefficient 0 and a unit for coefficient {}^1".format(self.parent().gen())) sig_on() - fmpz_poly_revert_series(res.__poly, self.__poly, m) + fmpz_poly_revert_series(res._poly, self._poly, m) sig_off() return res diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pxd b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pxd index a7c380b49a2..fcd907e1abe 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pxd +++ b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pxd @@ -2,6 +2,6 @@ from sage.libs.ntl.types cimport ZZX_c from sage.rings.polynomial.polynomial_element cimport Polynomial cdef class Polynomial_integer_dense_ntl(Polynomial): - cdef ZZX_c __poly + cdef ZZX_c _poly cdef Polynomial_integer_dense_ntl _new(self) diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx index c2db35e0bf7..80a1726bb4e 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx @@ -27,7 +27,6 @@ do:: sage: K Univariate Polynomial Ring in x over Integer Ring (using NTL) """ - #***************************************************************************** # Copyright (C) 2007 William Stein <wstein@gmail.com> # @@ -35,7 +34,7 @@ do:: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from cysignals.memory cimport sig_free @@ -45,21 +44,18 @@ from sage.ext.cplusplus cimport ccrepr include "sage/libs/ntl/decl.pxi" from sage.rings.polynomial.polynomial_element cimport Polynomial -from sage.structure.element cimport ModuleElement, Element +from sage.structure.element cimport Element from sage.rings.integer_ring import IntegerRing -from sage.rings.integer_ring cimport IntegerRing_class ZZ_sage = IntegerRing() -from sage.rings.polynomial.polynomial_element import is_Polynomial - from sage.libs.ntl.ntl_ZZX cimport ntl_ZZX from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.integer import Integer from sage.rings.integer cimport Integer -from sage.rings.real_mpfr cimport RealNumber, RealField_class +from sage.rings.real_mpfr cimport RealNumber from sage.rings.real_mpfi cimport RealIntervalFieldElement from sage.libs.pari.all import pari, pari_gen @@ -68,7 +64,6 @@ from sage.structure.element import coerce_binop from sage.rings.fraction_field_element import FractionFieldElement from sage.arith.functions import lcm -import sage.rings.polynomial.polynomial_ring from sage.libs.ntl.ZZX cimport * @@ -177,7 +172,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): if isinstance(x, Polynomial): if x.parent() is self.parent(): # copy with NTL assignment operator - self.__poly = (<Polynomial_integer_dense_ntl>x).__poly + self._poly = (<Polynomial_integer_dense_ntl>x)._poly return else: # coerce coefficients into Sage integers @@ -196,17 +191,17 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): degree = i if degree >= NTL_OVFBND: raise OverflowError("Dense NTL integer polynomials have a maximum degree of %s" % (NTL_OVFBND-1)) - ZZX_SetCoeff_long(self.__poly, degree, 1) + ZZX_SetCoeff_long(self._poly, degree, 1) # now fill them in for ii, a in x: i = ii[0] if type(ii) is tuple else ii if type(a) is int: - ZZX_SetCoeff_long(self.__poly, i, a) + ZZX_SetCoeff_long(self._poly, i, a) else: if not isinstance(a, Integer): a = ZZ(a) mpz_to_ZZ(&y, (<Integer>a).value) - ZZX_SetCoeff(self.__poly, i, y) + ZZX_SetCoeff(self._poly, i, y) return elif isinstance(x, pari_gen): @@ -215,14 +210,14 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): elif isinstance(x, ntl_ZZX): # coercion from ntl.pyx object # copy with NTL assignment operator - self.__poly = (<ntl_ZZX>x).x + self._poly = (<ntl_ZZX>x).x return elif isinstance(x, FractionFieldElement) and \ isinstance(x.numerator(), Polynomial_integer_dense_ntl): if x.denominator() == 1: # fraction of the form f(x)/1 - self.__poly = (<Polynomial_integer_dense_ntl>x.numerator()).__poly + self._poly = (<Polynomial_integer_dense_ntl>x.numerator())._poly return elif not isinstance(x, (list, tuple)): @@ -234,12 +229,12 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): for i from 0 <= i < len(x): a = x[i] if type(a) is int: - ZZX_SetCoeff_long(self.__poly, i, a) + ZZX_SetCoeff_long(self._poly, i, a) else: if not isinstance(a, Integer): a = ZZ(a) mpz_to_ZZ(&y, (<Integer>a).value) - ZZX_SetCoeff(self.__poly, i, y) + ZZX_SetCoeff(self._poly, i, y) def content(self): @@ -264,7 +259,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): """ cdef ZZ_c y cdef Integer z = Integer.__new__(Integer) - ZZX_content(y, self.__poly) + ZZX_content(y, self._poly) ZZ_to_mpz(z.value, &y) return z @@ -293,7 +288,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): """ cdef RealNumber res = a._new() sig_on() - ZZX_evaluation_mpfr(res.value, self.__poly, a.value) + ZZX_evaluation_mpfr(res.value, self._poly, a.value) sig_off() return res @@ -323,7 +318,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): """ cdef RealIntervalFieldElement res = a._new() sig_on() - ZZX_evaluation_mpfi(res.value, self.__poly, a.value) + ZZX_evaluation_mpfi(res.value, self._poly, a.value) sig_off() return res @@ -368,7 +363,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): 5*x^5 + 4*x^4 + 3*x^3 + 2*x^2 + x + 1 """ cdef Integer z = Integer.__new__(Integer) - ZZ_to_mpz(z.value, &self.__poly.rep.elts()[n]) + ZZ_to_mpz(z.value, &self._poly.rep.elts()[n]) return z def _repr(self, name=None, bint latex=False): @@ -385,15 +380,15 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): name = self.parent().variable_name() cdef long i cdef list all = [] - for i from ZZX_deg(self.__poly) >= i >= 0: - sign = ZZ_sign(ZZX_coeff(self.__poly, i)) + for i from ZZX_deg(self._poly) >= i >= 0: + sign = ZZ_sign(ZZX_coeff(self._poly, i)) if sign: if sign > 0: sign_str = '+' - coeff_str = ccrepr(self.__poly.rep.elts()[i]) + coeff_str = ccrepr(self._poly.rep.elts()[i]) else: sign_str = '-' - coeff_str = ccrepr(self.__poly.rep.elts()[i])[1:] + coeff_str = ccrepr(self._poly.rep.elts()[i])[1:] if i > 0: if coeff_str == '1': coeff_str = '' @@ -446,8 +441,8 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): -3*x^2 + 2*x + 7 """ cdef Polynomial_integer_dense_ntl x = self._new() - ZZX_add(x.__poly, self.__poly, - (<Polynomial_integer_dense_ntl>right).__poly) + ZZX_add(x._poly, self._poly, + (<Polynomial_integer_dense_ntl>right)._poly) return x @@ -464,14 +459,14 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): 3*x^2 + 2*x - 5 """ cdef Polynomial_integer_dense_ntl x = self._new() - ZZX_sub(x.__poly, self.__poly, - (<Polynomial_integer_dense_ntl>right).__poly) + ZZX_sub(x._poly, self._poly, + (<Polynomial_integer_dense_ntl>right)._poly) return x cpdef _neg_(self): r""" - Returns negative of self. + Returns negative of ``self``. EXAMPLES:: @@ -481,20 +476,20 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): -2*x + 1 """ cdef Polynomial_integer_dense_ntl x = self._new() - ZZX_negate(x.__poly, self.__poly) + ZZX_negate(x._poly, self._poly) return x @coerce_binop def quo_rem(self, right): r""" - Attempts to divide self by right, and return a quotient and remainder. + Attempt to divide ``self`` by ``right``, and return a quotient and remainder. - If right is monic, then it returns ``(q, r)`` where `self = q * right + r` - and `deg(r) < deg(right)`. + If right is monic, then it returns ``(q, r)`` where ``self = q * right + r`` + and ``deg(r) < deg(right)``. - If right is not monic, then it returns `(q, 0)` where q = self/right if - right exactly divides self, otherwise it raises an exception. + If right is not monic, then it returns `(q, 0)` where ``q = self/right`` if + ``right`` exactly divides ``self``, otherwise it raises an exception. EXAMPLES:: @@ -538,10 +533,10 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): """ cdef Polynomial_integer_dense_ntl _right = <Polynomial_integer_dense_ntl> right - if ZZX_IsZero(_right.__poly): + if ZZX_IsZero(_right._poly): raise ArithmeticError("division by zero polynomial") - if ZZX_IsZero(self.__poly): + if ZZX_IsZero(self._poly): return self, self cdef ZZX_c *q @@ -550,19 +545,19 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): cdef Polynomial_integer_dense_ntl rr = self._new() cdef int divisible - if ZZ_IsOne(ZZX_LeadCoeff(_right.__poly)): + if ZZ_IsOne(ZZX_LeadCoeff(_right._poly)): # divisor is monic. Just do the division and remainder - ZZX_quo_rem(&self.__poly, &_right.__poly, &r, &q) - ZZX_swap(qq.__poly, q[0]) - ZZX_swap(rr.__poly, r[0]) + ZZX_quo_rem(&self._poly, &_right._poly, &r, &q) + ZZX_swap(qq._poly, q[0]) + ZZX_swap(rr._poly, r[0]) del q del r else: # Non-monic divisor. Check whether it divides exactly. - q = ZZX_div(&self.__poly, &_right.__poly, &divisible) + q = ZZX_div(&self._poly, &_right._poly, &divisible) if divisible: # exactly divisible - ZZX_swap(q[0], qq.__poly) + ZZX_swap(q[0], qq._poly) del q else: # division failed: clean up and raise exception @@ -576,21 +571,21 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): @coerce_binop def gcd(self, right): r""" - Return the GCD of self and right. The leading + Return the GCD of ``self`` and ``right``. The leading coefficient need not be 1. EXAMPLES:: sage: R.<x> = PolynomialRing(ZZ, implementation='NTL') - sage: f = (6*x + 47)*(7*x^2 - 2*x + 38) - sage: g = (6*x + 47)*(3*x^3 + 2*x + 1) + sage: f = (6*x + 47) * (7*x^2 - 2*x + 38) + sage: g = (6*x + 47) * (3*x^3 + 2*x + 1) sage: f.gcd(g) 6*x + 47 """ # todo: we're doing an unnecessary copy here cdef Polynomial_integer_dense_ntl x = self._new() - cdef ZZX_c* temp = ZZX_gcd(&self.__poly, &(<Polynomial_integer_dense_ntl>right).__poly) - x.__poly = temp[0] + cdef ZZX_c* temp = ZZX_gcd(&self._poly, &(<Polynomial_integer_dense_ntl>right)._poly) + x._poly = temp[0] del temp return x @@ -598,16 +593,16 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): @coerce_binop def lcm(self, right): """ - Return the LCM of self and right. + Return the LCM of ``self`` and ``right``. EXAMPLES:: sage: R.<x> = PolynomialRing(ZZ, implementation='NTL') - sage: f = (6*x + 47)*(7*x^2 - 2*x + 38) - sage: g = (6*x + 47)*(3*x^3 + 2*x + 1) + sage: f = (6*x + 47) * (7*x^2 - 2*x + 38) + sage: g = (6*x + 47) * (3*x^3 + 2*x + 1) sage: h = f.lcm(g); h 126*x^6 + 951*x^5 + 486*x^4 + 6034*x^3 + 585*x^2 + 3706*x + 1786 - sage: h == (6*x + 47)*(7*x^2 - 2*x + 38)*(3*x^3 + 2*x + 1) + sage: h == (6*x + 47) * (7*x^2 - 2*x + 38) * (3*x^3 + 2*x + 1) True TESTS: @@ -627,7 +622,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): @coerce_binop def xgcd(self, right): """ - This function can't in general return ``(g,s,t)`` as above, + This function can't in general return `(g,s,t)` as above, since they need not exist. Instead, over the integers, we first multiply `g` by a divisor of the resultant of `a/g` and `b/g`, up to sign, and return ``g, u, v`` such that @@ -636,7 +631,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): If ``self`` and ``right`` are coprime as polynomials over the rationals, then ``g`` is guaranteed to be the resultant of - self and right, as a constant polynomial. + ``self`` and ``right``, as a constant polynomial. EXAMPLES:: @@ -663,13 +658,13 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): cdef ZZX_c *t cdef ZZ_c *r - ZZX_xgcd(&self.__poly, &(<Polynomial_integer_dense_ntl>right).__poly, &r, &s, &t, 1) # proof = 1 + ZZX_xgcd(&self._poly, &(<Polynomial_integer_dense_ntl>right)._poly, &r, &s, &t, 1) # proof = 1 cdef Integer rr = Integer.__new__(Integer) ZZ_to_mpz(rr.value, r) cdef Polynomial_integer_dense_ntl ss = self._new() cdef Polynomial_integer_dense_ntl tt = self._new() - ss.__poly = s[0] - tt.__poly = t[0] + ss._poly = s[0] + tt._poly = t[0] del r del s del t @@ -696,8 +691,8 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): x^3 - 10*x^2 + 32*x - 32 """ cdef Polynomial_integer_dense_ntl x = self._new() - ZZX_mul(x.__poly, self.__poly, - (<Polynomial_integer_dense_ntl>right).__poly) + ZZX_mul(x._poly, self._poly, + (<Polynomial_integer_dense_ntl>right)._poly) return x cpdef _lmul_(self, Element right): @@ -716,7 +711,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): cdef ZZ_c _right mpz_to_ZZ(&_right, (<Integer>right).value) - ZZX_mul_ZZ(x.__poly, self.__poly, _right) + ZZX_mul_ZZ(x._poly, self._poly, _right) return x cpdef _rmul_(self, Element right): @@ -735,7 +730,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): cdef ZZ_c _right mpz_to_ZZ(&_right, (<Integer>right).value) - ZZX_mul_ZZ(x.__poly, self.__poly, _right) + ZZX_mul_ZZ(x._poly, self._poly, _right) return x @@ -757,7 +752,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): sage: g // f x - 6 """ - if is_Polynomial(right) and right.is_constant() and right[0] in ZZ: + if isinstance(right, Polynomial) and right.is_constant() and right[0] in ZZ: d = ZZ(right[0]) return self.parent()([c // d for c in self.list()], construct=True) elif (right in self.parent().base_ring()): @@ -788,7 +783,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): value = Integer(value) cdef ZZ_c y mpz_to_ZZ(&y, (<Integer>value).value) - ZZX_SetCoeff(self.__poly, n, y) + ZZX_SetCoeff(self._poly, n, y) def real_root_intervals(self): @@ -810,14 +805,14 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): ## def __copy__(self): ## f = Polynomial_integer_dense(self.parent()) -## f.__poly = self.__poly.copy() +## f._poly = self._poly.copy() ## return f def degree(self, gen=None): """ Return the degree of this polynomial. The zero polynomial has - degree -1. + degree `-1`. EXAMPLES:: @@ -831,15 +826,15 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): sage: R(0).degree() -1 """ - return ZZX_deg(self.__poly) + return ZZX_deg(self._poly) def discriminant(self, proof=True): r""" - Return the discriminant of self, which is by definition + Return the discriminant of ``self``, which is by definition .. MATH:: - (-1)^{m(m-1)/2} {\mbox{\tt resultant}}(a, a')/lc(a), + (-1)^{m(m-1)/2} \text{resultant}(a, a')/lc(a), where `m = deg(a)`, and `lc(a)` is the leading coefficient of a. If ``proof`` is False (the default is True), then this function @@ -854,7 +849,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): sage: f.discriminant(proof=False) -339 """ - cdef ZZ_c* temp = ZZX_discriminant(&self.__poly, proof) + cdef ZZ_c* temp = ZZX_discriminant(&self._poly, proof) cdef Integer x = Integer.__new__(Integer) ZZ_to_mpz(x.value, temp) del temp @@ -865,7 +860,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): """ EXAMPLES:: - sage: t = PolynomialRing(ZZ,"t",implementation='NTL').gen() + sage: t = PolynomialRing(ZZ, "t", implementation='NTL').gen() sage: f = t^3 + 3*t - 17 sage: pari(f) t^3 + 3*t - 17 @@ -877,11 +872,11 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): def squarefree_decomposition(self): """ - Return the square-free decomposition of self. This is - a partial factorization of self into square-free, relatively + Return the square-free decomposition of ``self``. This is + a partial factorization of ``self`` into square-free, relatively prime polynomials. - This is a wrapper for the NTL function SquareFreeDecomp. + This is a wrapper for the NTL function ``SquareFreeDecomp``. EXAMPLES:: @@ -895,7 +890,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): Verify that :trac:`13053` has been resolved:: sage: R.<x> = PolynomialRing(ZZ, implementation='NTL') - sage: f=-x^2 + sage: f = -x^2 sage: f.squarefree_decomposition() (-1) * x^2 @@ -909,11 +904,11 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): cdef long* e cdef long i, n cdef Polynomial_integer_dense_ntl z - ZZX_squarefree_decomposition(&v, &e, &n, &p.__poly) + ZZX_squarefree_decomposition(&v, &e, &n, &p._poly) F = [] for i from 0 <= i < n: z = self._new() - z.__poly = v[i][0] + z._poly = v[i][0] F.append((z, e[i])) del v[i] sig_free(v) @@ -955,31 +950,31 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): cdef ZZ_c content cdef vec_pair_ZZX_long_c factors cdef long i - cdef int sig_me = ZZX_deg(self.__poly) + cdef int sig_me = ZZX_deg(self._poly) if sig_me > 10: sig_on() - ZZX_factor(content, factors, self.__poly, 0, 0) + ZZX_factor(content, factors, self._poly, 0, 0) if sig_me > 10: sig_off() results = [] unit = None if not ZZ_IsOne(content): fac_py = self._new() - ZZX_SetCoeff(fac_py.__poly, 0, content) - if ZZX_deg(fac_py.__poly) == 0 and ZZ_to_int(fac_py.__poly.rep.elts())==-1: + ZZX_SetCoeff(fac_py._poly, 0, content) + if ZZX_deg(fac_py._poly) == 0 and ZZ_to_int(fac_py._poly.rep.elts())==-1: unit = fac_py else: results.append( (fac_py,1) ) for i from 0 <= i < factors.length(): fac_py = self._new() - fac_py.__poly = factors.RawGet(i).a + fac_py._poly = factors.RawGet(i).a results.append( (fac_py,factors.RawGet(i).b) ) return Factorization(results, unit = unit) def factor(self): """ This function overrides the generic polynomial factorization to - make a somewhat intelligent decision to use Pari or NTL based on + make a somewhat intelligent decision to use PARI or NTL based on some benchmarking. Note: This function factors the content of the polynomial, @@ -989,11 +984,11 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): EXAMPLES:: - sage: R.<x>=ZZ[] - sage: f=x^4-1 + sage: R.<x> = ZZ[] + sage: f = x^4 - 1 sage: f.factor() (x - 1) * (x + 1) * (x^2 + 1) - sage: f=1-x + sage: f = 1 - x sage: f.factor() (-1) * (x - 1) sage: f.factor().unit() @@ -1001,25 +996,24 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): sage: f = -30*x; f.factor() (-1) * 2 * 3 * 5 * x """ - cdef int i - cdef int deg = ZZX_deg(self.__poly) - # it appears that pari has a window from about degrees 30 and 300 in which it beats NTL. + cdef int deg = ZZX_deg(self._poly) + # it appears that pari has a window from about degrees 30 and 300 + # in which it beats NTL. c = self.content() - g = self//c + g = self // c if deg < 30 or deg > 300: - return c.factor()*g._factor_ntl() - else: - return c.factor()*g._factor_pari() + return c.factor() * g._factor_ntl() + return c.factor() * g._factor_pari() def factor_mod(self, p): """ - Return the factorization of self modulo the prime p. + Return the factorization of ``self`` modulo the prime `p`. INPUT: - ``p`` -- prime - OUTPUT: factorization of self reduced modulo p. + OUTPUT: factorization of ``self`` reduced modulo `p`. EXAMPLES:: @@ -1051,7 +1045,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): def factor_padic(self, p, prec=10): """ - Return `p`-adic factorization of self to given precision. + Return `p`-adic factorization of ``self`` to given precision. INPUT: @@ -1068,13 +1062,15 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): sage: R.<x> = PolynomialRing(ZZ, implementation='NTL') sage: f = x^2 + 1 sage: f.factor_padic(5, 4) - ((1 + O(5^4))*x + 2 + 5 + 2*5^2 + 5^3 + O(5^4)) * ((1 + O(5^4))*x + 3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4)) + ((1 + O(5^4))*x + 2 + 5 + 2*5^2 + 5^3 + O(5^4)) + * ((1 + O(5^4))*x + 3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4)) A more difficult example:: sage: f = 100 * (5*x + 1)^2 * (x + 5)^2 sage: f.factor_padic(5, 10) - (4 + O(5^10)) * (5 + O(5^11))^2 * ((1 + O(5^10))*x + 5 + O(5^10))^2 * ((5 + O(5^10))*x + 1 + O(5^10))^2 + (4 + O(5^10)) * (5 + O(5^11))^2 * ((1 + O(5^10))*x + 5 + O(5^10))^2 + * ((5 + O(5^10))*x + 1 + O(5^10))^2 """ from sage.rings.padics.factory import Zp @@ -1099,11 +1095,11 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): EXAMPLES:: - sage: x = PolynomialRing(ZZ,'x',implementation='NTL').0 + sage: x = PolynomialRing(ZZ, 'x', implementation='NTL').0 sage: f = x^3 + 3*x - 17 sage: f.list() [-17, 3, 0, 1] - sage: f = PolynomialRing(ZZ,'x',implementation='NTL')(0) + sage: f = PolynomialRing(ZZ, 'x', implementation='NTL')(0) sage: f.list() [] """ @@ -1113,23 +1109,21 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): @coerce_binop def resultant(self, other, proof=True): """ - Returns the resultant of self and other, which must lie in the same + Returns the resultant of ``self`` and ``other``, which must lie in the same polynomial ring. - If proof = False (the default is proof=True), then this function may use a + If ``proof=False`` (the default is ``proof=True``), then this function may use a randomized strategy that errors with probability no more than `2^{-80}`. INPUT: - - other -- a polynomial - - OUTPUT: + - ``other`` -- a polynomial - an element of the base ring of the polynomial ring + OUTPUT: an element of the base ring of the polynomial ring EXAMPLES:: - sage: x = PolynomialRing(ZZ,'x',implementation='NTL').0 + sage: x = PolynomialRing(ZZ, 'x', implementation='NTL').0 sage: f = x^3 + x + 1; g = x^3 - x - 1 sage: r = f.resultant(g); r -8 @@ -1137,7 +1131,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): True """ cdef Polynomial_integer_dense_ntl _other = <Polynomial_integer_dense_ntl>(self.parent().coerce(other)) - cdef ZZ_c* temp = ZZX_resultant(&self.__poly, &_other.__poly, proof) + cdef ZZ_c* temp = ZZX_resultant(&self._poly, &_other._poly, proof) cdef Integer x = Integer.__new__(Integer) ZZ_to_mpz(x.value, temp) del temp diff --git a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pxd b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pxd index 264f05f3c0d..6934acfee8d 100644 --- a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pxd +++ b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pxd @@ -16,7 +16,7 @@ from sage.libs.ntl.lzz_pX cimport * cdef class Polynomial_dense_mod_n(Polynomial): - cdef object __poly + cdef object _poly cdef object __singular cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): diff --git a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx index 2b55a681a32..a8f08f5bc6c 100644 --- a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx @@ -32,7 +32,6 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_on, sig_off from sage.rings.polynomial.polynomial_element cimport Polynomial, _dict_to_list @@ -41,17 +40,13 @@ from sage.libs.pari.all import pari, pari_gen from sage.rings.integer cimport smallInteger -from sage.libs.ntl.all import ZZ as ntl_ZZ, ZZX, zero_ZZX, ZZ_p, ZZ_pX -from sage.rings.rational_field import QQ +from sage.libs.ntl.all import ZZX, ZZ_pX from sage.rings.integer_ring import ZZ -from sage.rings.finite_rings.integer_mod import IntegerMod_abstract from sage.rings.fraction_field_element import FractionFieldElement -import sage.rings.polynomial.polynomial_ring from sage.rings.infinity import infinity -from . import polynomial_singular_interface from sage.interfaces.singular import singular as singular_default from sage.structure.element import coerce_binop @@ -85,7 +80,7 @@ cdef class Polynomial_dense_mod_n(Polynomial): sage: R.<x> = PolynomialRing(Integers(100), implementation='NTL') sage: p = 3*x sage: q = 7*x - sage: p+q + sage: p + q 10*x sage: R.<x> = PolynomialRing(Integers(8), implementation='NTL') sage: parent(p) @@ -110,19 +105,19 @@ cdef class Polynomial_dense_mod_n(Polynomial): if construct: if isinstance(x, ZZ_pX): - self.__poly = x + self._poly = x return - self.__poly = ZZ_pX(x, parent.modulus()) + self._poly = ZZ_pX(x, parent.modulus()) return - self.__poly = ZZ_pX([], parent.modulus()) + self._poly = ZZ_pX([], parent.modulus()) if x is None: return # leave initialized to 0 polynomial. if isinstance(x, Polynomial): if x.parent() == self.parent(): - self.__poly = (<Polynomial_dense_modn_ntl_zz>x).__poly.__copy__() + self._poly = (<Polynomial_dense_modn_ntl_zz>x)._poly.__copy__() return else: R = parent.base_ring() @@ -135,7 +130,7 @@ cdef class Polynomial_dense_mod_n(Polynomial): elif isinstance(x, ZZX): - self.__poly = x.copy() + self._poly = x.copy() return elif isinstance(x, pari_gen): @@ -147,7 +142,7 @@ cdef class Polynomial_dense_mod_n(Polynomial): if x.denominator().is_unit(): numer = x.numerator() denom = x.denominator().inverse_of_unit() - x = numer.__poly * denom.__poly + x = numer._poly * denom._poly check = False else: raise TypeError("Denominator not a unit.") @@ -159,20 +154,19 @@ cdef class Polynomial_dense_mod_n(Polynomial): R = parent.base_ring() x = [ZZ(R(a)) for a in x] - self.__poly = ZZ_pX(x, parent.modulus()) - + self._poly = ZZ_pX(x, parent.modulus()) def __reduce__(self): return make_element, (self.parent(), (self.list(), False, self.is_gen())) def int_list(self): - return eval(str(self.__poly).replace(' ',',')) + return eval(str(self._poly).replace(' ',',')) def __pari__(self, variable=None): """ EXAMPLES:: - sage: t = PolynomialRing(IntegerModRing(17),"t", implementation='NTL').gen() + sage: t = PolynomialRing(IntegerModRing(17), "t", implementation='NTL').gen() sage: f = t^3 + 3*t - 17 sage: pari(f) Mod(1, 17)*t^3 + Mod(3, 17)*t @@ -192,7 +186,7 @@ cdef class Polynomial_dense_mod_n(Polynomial): You must call ``ntl.set_modulus(ntl.ZZ(n))`` before doing arithmetic with this object! """ - return self.__poly + return self._poly cdef get_unsafe(self, Py_ssize_t n): """ @@ -202,20 +196,20 @@ cdef class Polynomial_dense_mod_n(Polynomial): sage: R.<x> = PolynomialRing(Integers(100), implementation='NTL') sage: from sage.rings.polynomial.polynomial_modn_dense_ntl import Polynomial_dense_mod_n - sage: f = Polynomial_dense_mod_n(R,[5,10,13,1,4]); f + sage: f = Polynomial_dense_mod_n(R, [5,10,13,1,4]); f 4*x^4 + x^3 + 13*x^2 + 10*x + 5 sage: f[2] 13 sage: f[:3] 13*x^2 + 10*x + 5 """ - return self._parent._base(self.__poly[n]._sage_()) + return self._parent._base((<ntl_ZZ_pX> self._poly)[n]._integer_()) def _unsafe_mutate(self, n, value): n = int(n) if n < 0: raise IndexError("n must be >= 0") - self.__poly[n] = int(value) + self._poly[n] = int(value) def _pow(self, n): n = int(n) @@ -224,10 +218,10 @@ cdef class Polynomial_dense_mod_n(Polynomial): return self.parent()(self[0]**n) if n < 0: return (~self)**(-n) - return self.parent()(self.__poly**n, construct=True) + return self.parent()(self._poly**n, construct=True) cpdef _add_(self, right): - return self.parent()(self.__poly + (<Polynomial_dense_mod_n>right).__poly, construct=True) + return self.parent()(self._poly + (<Polynomial_dense_mod_n>right)._poly, construct=True) cpdef _mul_(self, right): """ @@ -237,27 +231,27 @@ cdef class Polynomial_dense_mod_n(Polynomial): sage: (x - 2)*(x^2 - 8*x + 16) x^3 + 90*x^2 + 32*x + 68 """ - return self.parent()(self.__poly * (<Polynomial_dense_mod_n>right).__poly, construct=True) + return self.parent()(self._poly * (<Polynomial_dense_mod_n>right)._poly, construct=True) cpdef _lmul_(self, Element c): try: - return self.parent()(ZZ_pX([c], self.parent().modulus()) * self.__poly, construct=True) + return self.parent()(ZZ_pX([c], self.parent().modulus()) * self._poly, construct=True) except RuntimeError as msg: # should this really be a TypeError raise TypeError(msg) @coerce_binop def quo_rem(self, right): """ - Returns a tuple (quotient, remainder) where self = quotient*other + - remainder. + Return a tuple ``(quotient, remainder)`` where ``self = quotient*other + + remainder``. """ - v = self.__poly.quo_rem((<Polynomial_dense_mod_n>right).__poly) + v = self._poly.quo_rem((<Polynomial_dense_mod_n>right)._poly) P = self.parent() return (P(v[0], construct=True), P(v[1], construct=True) ) def shift(self, n): r""" - Returns this polynomial multiplied by the power `x^n`. If `n` is negative, + Return this polynomial multiplied by the power `x^n`. If `n` is negative, terms below `x^n` will be discarded. Does not change this polynomial. EXAMPLES:: @@ -287,11 +281,11 @@ cdef class Polynomial_dense_mod_n(Polynomial): """ if n == 0 or self.degree() < 0: return self - return self.parent()(self.__poly.left_shift(n), + return self.parent()(self._poly.left_shift(n), construct=True) cpdef _sub_(self, right): - return self.parent()(self.__poly - (<Polynomial_dense_mod_n>right).__poly, construct=True) + return self.parent()(self._poly - (<Polynomial_dense_mod_n>right)._poly, construct=True) def __floordiv__(self, right): q, _ = self.quo_rem(right) @@ -320,7 +314,7 @@ cdef class Polynomial_dense_mod_n(Polynomial): sage: isinstance(x.degree(), Integer) True """ - return smallInteger(max(self.__poly.degree(), -1)) + return smallInteger(max(self._poly.degree(), -1)) cpdef list list(self, bint copy=True): """ @@ -364,7 +358,7 @@ cdef class Polynomial_dense_mod_n(Polynomial): """ if self.is_gen(): raise TypeError("Cannot change the value of the generator.") - self.__poly = ZZ_pX(v, self.parent().modulus()) + self._poly = ZZ_pX(v, self.parent().modulus()) # Polynomial_singular_repr stuff, copied due to lack of multiple inheritance def _singular_(self, singular=singular_default, force=False): @@ -383,6 +377,41 @@ cdef class Polynomial_dense_mod_n(Polynomial): self.__singular = singular(str(self)) return self.__singular + @coerce_binop + def minpoly_mod(self, other): + r""" + Compute the minimal polynomial of this polynomial modulo another + polynomial in the same ring. + + ALGORITHM: + + NTL's ``MinPolyMod()``, which uses Shoup's algorithm [Sho1999]_. + + EXAMPLES:: + + sage: R.<x> = PolynomialRing(GF(101), implementation='NTL') + sage: f = x^17 + x^2 - 1 + sage: (x^2).minpoly_mod(f) + x^17 + 100*x^2 + 2*x + 100 + + TESTS: + + Random testing:: + + sage: p = random_prime(2^99) + sage: R.<x> = PolynomialRing(GF(p), implementation='NTL') + sage: d = randrange(1,50) + sage: f = R.random_element(d) + sage: g = R.random_element((-1,5*d)) + sage: poly = g.minpoly_mod(f) + sage: poly(R.quotient(f)(g)) + 0 + """ + mod = other.ntl_ZZ_pX() + elt = self.ntl_ZZ_pX() % mod + res = elt.minpoly_mod(mod) + return self.parent()(res, construct=True) + def small_roots(self, *args, **kwds): r""" See :func:`sage.rings.polynomial.polynomial_modn_dense_ntl.small_roots` @@ -440,7 +469,7 @@ def small_roots(self, X=None, beta=1.0, epsilon=None, **kwds): To compute its roots we need to factor the modulus `N` and use the Chinese remainder theorem:: - sage: p,q = N.prime_divisors() + sage: p, q = N.prime_divisors() sage: f.change_ring(GF(p)).roots() [(4, 1)] sage: f.change_ring(GF(q)).roots() @@ -475,7 +504,7 @@ def small_roots(self, X=None, beta=1.0, epsilon=None, **kwds): sage: K = ZZ.random_element(0, 2^Kbits) - and pad it with 512-56=456 1s:: + and pad it with `512-56=456` 1s:: sage: Kdigits = K.digits(2) sage: M = [0]*Kbits + [1]*(Nbits-Kbits) @@ -507,30 +536,30 @@ def small_roots(self, X=None, beta=1.0, epsilon=None, **kwds): sage: length = 512 sage: hidden = 110 sage: p = next_prime(2^int(round(length/2))) - sage: q = next_prime( round(pi.n()*p) ) - sage: N = p*q + sage: q = next_prime(round(pi.n()*p)) # needs sage.symbolic + sage: N = p*q # needs sage.symbolic Now we disturb the low 110 bits of `q`:: - sage: qbar = q + ZZ.random_element(0,2^hidden-1) + sage: qbar = q + ZZ.random_element(0, 2^hidden - 1) # needs sage.symbolic And try to recover `q` from it:: - sage: F.<x> = PolynomialRing(Zmod(N), implementation='NTL') - sage: f = x - qbar + sage: F.<x> = PolynomialRing(Zmod(N), implementation='NTL') # needs sage.symbolic + sage: f = x - qbar # needs sage.symbolic We know that the error is `\le 2^{\text{hidden}}-1` and that the modulus we are looking for is `\ge \sqrt{N}`:: sage: from sage.misc.verbose import set_verbose sage: set_verbose(2) - sage: d = f.small_roots(X=2^hidden-1, beta=0.5)[0] # time random + sage: d = f.small_roots(X=2^hidden-1, beta=0.5)[0] # time random # needs sage.symbolic verbose 2 (<module>) m = 4 verbose 2 (<module>) t = 4 verbose 2 (<module>) X = 1298074214633706907132624082305023 verbose 1 (<module>) LLL of 8x8 matrix (algorithm fpLLL:wrapper) verbose 1 (<module>) LLL finished (time = 0.006998) - sage: q == qbar - d + sage: q == qbar - d # needs sage.symbolic True REFERENCES: @@ -625,8 +654,8 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): return Polynomial_dense_mod_n.__init__(self, parent, v, check=check, is_gen=is_gen, construct=construct) - v = [a for a in self.__poly.list()] - self.__poly = None # this will eventually go away + v = [a for a in self._poly.list()] + self._poly = None # this will eventually go away cdef ntl_zz_pX ntl = ntl_zz_pX(v, parent.modulus()) # let it handle the hard work self.x = ntl.x self.c = ntl.c @@ -639,8 +668,8 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): # TODO: Get rid of this Polynomial_dense_mod_n.ntl_set_directly(self, v) # verbatim from __init__ - v = [int(a) for a in self.__poly.list()] - self.__poly = None # this will eventually go away + v = [int(a) for a in self._poly.list()] + self._poly = None # this will eventually go away cdef ntl_zz_pX ntl = ntl_zz_pX(v, self._parent.modulus()) # let it handle the hard work self.x = ntl.x self.c = ntl.c @@ -653,7 +682,7 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): def int_list(self): """ - Returns the coefficients of self as efficiently as possible as a + Return the coefficients of ``self`` as efficiently as possible as a list of python ints. EXAMPLES:: @@ -696,7 +725,7 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): TESTS:: sage: R.<x> = PolynomialRing(Integers(100), implementation='NTL') - sage: (x+5) + (x^2 - 6) + sage: (x + 5) + (x^2 - 6) x^2 + x + 99 """ cdef Polynomial_dense_modn_ntl_zz right = <Polynomial_dense_modn_ntl_zz>_right @@ -713,7 +742,7 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): TESTS:: sage: R.<x> = PolynomialRing(Integers(100), implementation='NTL') - sage: (x+5) - (x^2 - 6) + sage: (x + 5) - (x^2 - 6) 99*x^2 + x + 11 """ cdef Polynomial_dense_modn_ntl_zz right = <Polynomial_dense_modn_ntl_zz>_right @@ -730,7 +759,7 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): TESTS:: sage: R.<x> = PolynomialRing(Integers(100), implementation='NTL') - sage: (x+5) * (x^2 - 1) + sage: (x + 5) * (x^2 - 1) x^3 + 5*x^2 + 99*x + 95 """ cdef Polynomial_dense_modn_ntl_zz right = <Polynomial_dense_modn_ntl_zz>_right @@ -884,9 +913,9 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): @coerce_binop def quo_rem(self, right): - """ - Returns `q` and `r`, with the degree of `r` less than the degree of `right`, - such that `q * right + r = self`. + r""" + Return `q` and `r`, with the degree of `r` less than the degree of ``right``, + such that `q \cdot` ``right`` `{}+ r =` ``self``. EXAMPLES:: @@ -911,7 +940,7 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): cpdef _floordiv_(self, right): """ - Returns the whole part of self/right, without remainder. + Return the whole part of ``self``/``right``, without remainder. For q = n // d, we have deg(n - q*d) < deg(d) @@ -1008,7 +1037,7 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): def _derivative(self, var=None): r""" - Return the formal derivative of self with respect to ``var``. + Return the formal derivative of ``self`` with respect to ``var``. ``var`` must be either the generator of the polynomial ring to which this polynomial belongs, or ``None`` (either way the behaviour is the @@ -1032,8 +1061,8 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): TESTS:: - sage: y = var("y") - sage: f._derivative(y) + sage: y = var("y") # needs sage.symbolic + sage: f._derivative(y) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y @@ -1105,8 +1134,8 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): def valuation(self): """ - Returns the valuation of self, that is, the power of the - lowest non-zero monomial of self. + Return the valuation of ``self``, that is, the power of the + lowest non-zero monomial of ``self``. EXAMPLES:: @@ -1142,7 +1171,7 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): cpdef Polynomial truncate(self, long n): """ - Returns this polynomial mod `x^n`. + Return this polynomial mod `x^n`. EXAMPLES:: @@ -1158,14 +1187,14 @@ cdef class Polynomial_dense_modn_ntl_zz(Polynomial_dense_mod_n): def __call__(self, *args, **kwds): """ - Evaluate self at x. If x is a single argument coercible into - the base ring of self, this is done directly in NTL, otherwise + Evaluate self at ``x``. If ``x`` is a single argument coercible into + the base ring of ``self``, this is done directly in NTL, otherwise the generic Polynomial call code is used. EXAMPLES:: sage: R.<x> = PolynomialRing(Integers(100), implementation='NTL') - sage: f = x^3+7 + sage: f = x^3 + 7 sage: f(5) 32 sage: f(5r) @@ -1212,8 +1241,8 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): return Polynomial_dense_mod_n.__init__(self, parent, v, check=check, is_gen=is_gen, construct=construct) - cdef ntl_ZZ_pX ntl = self.__poly - self.__poly = None # this will eventually go away + cdef ntl_ZZ_pX ntl = self._poly + self._poly = None # this will eventually go away self.x = ntl.x self.c = ntl.c @@ -1268,7 +1297,7 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): TESTS:: sage: R.<x> = PolynomialRing(Integers(10^30), implementation='NTL') - sage: (x+5) + (x^2 - 6) + sage: (x + 5) + (x^2 - 6) x^2 + x + 999999999999999999999999999999 """ cdef Polynomial_dense_modn_ntl_ZZ right = <Polynomial_dense_modn_ntl_ZZ>_right @@ -1285,7 +1314,7 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): TESTS:: sage: R.<x> = PolynomialRing(Integers(10^30), implementation='NTL') - sage: (x+5) - (x^2 - 6) + sage: (x + 5) - (x^2 - 6) 999999999999999999999999999999*x^2 + x + 11 """ cdef Polynomial_dense_modn_ntl_ZZ right = <Polynomial_dense_modn_ntl_ZZ>_right @@ -1441,9 +1470,9 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): @coerce_binop def quo_rem(self, right): - """ - Returns `q` and `r`, with the degree of `r` less than the degree of `right`, - such that `q * right + r = self`. + r""" + Return `q` and `r`, with the degree of `r` less than the degree of ``right``, + such that `q \cdot` ``right`` `+ r =` ``self``. EXAMPLES:: @@ -1468,7 +1497,7 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): cpdef _floordiv_(self, right): """ - Returns the whole part of self/right, without remainder. + Return the whole part of ``self`` / ``right``, without remainder. For q = n // d, we have deg(n - q*d) < deg(d) @@ -1566,7 +1595,7 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): def _derivative(self, var=None): r""" - Return the formal derivative of self with respect to ``var``. + Return the formal derivative of ``self`` with respect to ``var``. ``var`` must be either the generator of the polynomial ring to which this polynomial belongs, or None (either way the behaviour is the @@ -1590,8 +1619,8 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): TESTS:: - sage: y = var("y") - sage: f._derivative(y) + sage: y = var("y") # needs sage.symbolic + sage: f._derivative(y) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y @@ -1651,19 +1680,19 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): def valuation(self): """ - Returns the valuation of self, that is, the power of the - lowest non-zero monomial of self. + Return the valuation of ``self``, that is, the power of the + lowest non-zero monomial of ``self``. EXAMPLES:: sage: R.<x> = PolynomialRing(Integers(10^50), implementation='NTL') sage: x.valuation() 1 - sage: f = x-3; f.valuation() + sage: f = x - 3; f.valuation() 0 sage: f = x^99; f.valuation() 99 - sage: f = x-x; f.valuation() + sage: f = x - x; f.valuation() +Infinity """ cdef long n @@ -1703,7 +1732,7 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): cpdef Polynomial truncate(self, long n): """ - Returns this polynomial mod `x^n`. + Return this polynomial mod `x^n`. EXAMPLES:: @@ -1719,14 +1748,14 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): def __call__(self, *args, **kwds): """ - Evaluate self at x. If x is a single argument coercible into - the base ring of self, this is done directly in NTL, otherwise + Evaluate ``self`` at ``x``. If ``x`` is a single argument coercible into + the base ring of ``self``, this is done directly in NTL, otherwise the generic Polynomial call code is used. EXAMPLES:: sage: R.<x> = PolynomialRing(Integers(10^30), implementation='NTL') - sage: f = x^3+7 + sage: f = x^3 + 7 sage: f(5) 132 sage: f(5r) @@ -1761,7 +1790,7 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): cdef class Polynomial_dense_mod_p(Polynomial_dense_mod_n): """ - A dense polynomial over the integers modulo p, where p is prime. + A dense polynomial over the integers modulo `p`, where `p` is prime. """ @coerce_binop @@ -1776,8 +1805,8 @@ cdef class Polynomial_dense_mod_p(Polynomial_dense_mod_n): EXAMPLES:: - sage: R.<x> = PolynomialRing(GF(3),implementation="NTL") - sage: f,g = x + 2, x^2 - 1 + sage: R.<x> = PolynomialRing(GF(3), implementation="NTL") + sage: f, g = x + 2, x^2 - 1 sage: f.gcd(g) x + 2 @@ -1801,7 +1830,7 @@ cdef class Polynomial_dense_mod_p(Polynomial_dense_mod_n): EXAMPLES:: - sage: R.<x> = PolynomialRing(GF(3),implementation='NTL') + sage: R.<x> = PolynomialRing(GF(3), implementation='NTL') sage: x.xgcd(x) (x, 0, 1) sage: (x^2 - 1).xgcd(x - 1) @@ -1820,7 +1849,7 @@ cdef class Polynomial_dense_mod_p(Polynomial_dense_mod_n): @coerce_binop def resultant(self, other): """ - Returns the resultant of self and other, which must lie in the same + Return the resultant of ``self`` and ``other``, which must lie in the same polynomial ring. INPUT: @@ -1831,7 +1860,7 @@ cdef class Polynomial_dense_mod_p(Polynomial_dense_mod_n): EXAMPLES:: - sage: R.<x> = PolynomialRing(GF(19),implementation='NTL') + sage: R.<x> = PolynomialRing(GF(19), implementation='NTL') sage: f = x^3 + x + 1; g = x^3 - x - 1 sage: r = f.resultant(g); r 11 @@ -1845,7 +1874,7 @@ cdef class Polynomial_dense_mod_p(Polynomial_dense_mod_n): """ EXAMPLES:: - sage: _.<x> = PolynomialRing(GF(19),implementation='NTL') + sage: _.<x> = PolynomialRing(GF(19), implementation='NTL') sage: f = x^3 + 3*x - 17 sage: f.discriminant() 12 diff --git a/src/sage/rings/polynomial/polynomial_number_field.pyx b/src/sage/rings/polynomial/polynomial_number_field.pyx index 82c3d467bea..96f1c002e99 100644 --- a/src/sage/rings/polynomial/polynomial_number_field.pyx +++ b/src/sage/rings/polynomial/polynomial_number_field.pyx @@ -1,5 +1,5 @@ r""" -Univariate polynomials over number fields. +Univariate polynomials over number fields AUTHOR: @@ -10,11 +10,12 @@ EXAMPLES: Define a polynomial over an absolute number field and perform basic operations with them:: - sage: N.<a> = NumberField(x^2-2) + sage: x = polygen(ZZ, 'x') + sage: N.<a> = NumberField(x^2 - 2) sage: K.<x> = N[] sage: f = x - a sage: g = x^3 - 2*a + 1 - sage: f*(x + a) + sage: f * (x + a) x^2 - 2 sage: f + g x^3 + x - 3*a + 1 @@ -29,24 +30,26 @@ operations with them:: Polynomials are aware of embeddings of the underlying field:: - sage: x = var('x') + sage: # needs sage.rings.padics + sage: x = polygen(ZZ, 'x') sage: Q7 = Qp(7) - sage: r1 = Q7(3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 +\ - 6*7^9 + 6*7^10 + 2*7^11 + 7^12 + 7^13 + 2*7^15 + 7^16 + 7^17 +\ - 4*7^18 + 6*7^19) - sage: N.<b> = NumberField(x^2-2, embedding = r1) + sage: r1 = Q7(3 + 7 + 2*7^2 + 6*7^3 + 7^4 + 2*7^5 + 7^6 + 2*7^7 + 4*7^8 + ....: + 6*7^9 + 6*7^10 + 2*7^11 + 7^12 + 7^13 + 2*7^15 + 7^16 + 7^17 + ....: + 4*7^18 + 6*7^19) + sage: N.<b> = NumberField(x^2 - 2, embedding=r1) sage: K.<t> = N[] - sage: f = t^3-2*t+1 + sage: f = t^3 - 2*t + 1 sage: f(r1) 1 + O(7^20) We can also construct polynomials over relative number fields:: + sage: # needs sage.symbolic sage: N.<i, s2> = QQ[I, sqrt(2)] sage: K.<x> = N[] sage: f = x - s2 sage: g = x^3 - 2*i*x^2 + s2*x - sage: f*(x + s2) + sage: f * (x + s2) x^2 - 2 sage: f + g x^3 - 2*I*x^2 + (sqrt2 + 1)*x - sqrt2 @@ -56,7 +59,7 @@ We can also construct polynomials over relative number fields:: -4*I + 2*sqrt2 + 2 sage: factor(i*x^4 - 2*i*x^2 + 9*i) (I) * (x - I + sqrt2) * (x + I - sqrt2) * (x - I - sqrt2) * (x + I + sqrt2) - sage: gcd(f, x-i) + sage: gcd(f, x - i) 1 """ @@ -122,13 +125,12 @@ class Polynomial_absolute_number_field_dense(Polynomial_generic_dense_field): - ``other`` -- a polynomial with the same parent as ``self``. - OUTPUT: - - - The monic gcd of ``self`` and ``other``. + OUTPUT: The monic gcd of ``self`` and ``other``. EXAMPLES:: - sage: N.<a> = NumberField(x^3-1/2, 'a') + sage: x = polygen(ZZ, 'x') + sage: N.<a> = NumberField(x^3 - 1/2, 'a') sage: R.<r> = N['r'] sage: f = (5/4*a^2 - 2*a + 4)*r^2 + (5*a^2 - 81/5*a - 17/2)*r + 4/5*a^2 + 24*a + 6 sage: g = (5/4*a^2 - 2*a + 4)*r^2 + (-11*a^2 + 79/5*a - 7/2)*r - 4/5*a^2 - 24*a - 6 @@ -138,8 +140,8 @@ class Polynomial_absolute_number_field_dense(Polynomial_generic_dense_field): sage: f = R.random_element(2) sage: g = f + 1 sage: h = R.random_element(2).monic() - sage: f *=h - sage: g *=h + sage: f *= h + sage: g *= h sage: gcd(f, g) - h 0 sage: f.gcd(g) - h @@ -149,8 +151,8 @@ class Polynomial_absolute_number_field_dense(Polynomial_generic_dense_field): Test for degree one extensions:: - sage: x = var('x') - sage: N = NumberField(x-3, 'a') + sage: x = polygen(ZZ, 'x') + sage: N = NumberField(x - 3, 'a') sage: a = N.gen() sage: R = N['x'] sage: f = R._random_nonzero_element() @@ -167,7 +169,7 @@ class Polynomial_absolute_number_field_dense(Polynomial_generic_dense_field): Test for coercion with other rings and force weird variables to test PARI behavior:: - sage: r = var('r') + sage: r = polygen(ZZ, 'r') sage: N = NumberField(r^2 - 2, 'r') sage: a = N.gen() sage: R = N['r'] @@ -180,8 +182,9 @@ class Polynomial_absolute_number_field_dense(Polynomial_generic_dense_field): sage: h = f.gcd(g); h 1 sage: h.parent() - Univariate Polynomial Ring in r over Number Field in r with defining polynomial r^2 - 2 - sage: gcd([a*r+2, r^2-2]) + Univariate Polynomial Ring in r over + Number Field in r with defining polynomial r^2 - 2 + sage: gcd([a*r + 2, r^2 - 2]) r + r """ if self.is_zero(): @@ -221,22 +224,23 @@ class Polynomial_relative_number_field_dense(Polynomial_generic_dense_field): - ``parent`` -- polynomial ring in which to construct the element. - - ``x`` -- (default: None) an object representing the + - ``x`` -- (default: ``None``) an object representing the polynomial, e.g. a list of coefficients. See :meth:`sage.rings.polynomial.polynomial_element_generic.Polynomial_generic_dense_field.__init__` for more details. - - ``check`` -- boolean (default: True) if True, make sure that + - ``check`` -- boolean (default: ``True``) if ``True``, make sure that the coefficients of the polynomial are in the base ring. - - ``is_gen`` -- boolean (default: False) if True, ``x`` is the + - ``is_gen`` -- boolean (default: ``False``) if ``True``, ``x`` is the distinguished generator of the polynomial ring. - - ``construct`` -- (default: False) boolean, unused. + - ``construct`` -- (default: ``False``) boolean, unused. EXAMPLES:: - sage: f = NumberField([x^2-2, x^2-3], 'a')['x'].random_element() + sage: x = polygen(ZZ, 'x') + sage: f = NumberField([x^2 - 2, x^2 - 3], 'a')['x'].random_element() sage: from sage.rings.polynomial.polynomial_number_field import Polynomial_relative_number_field_dense sage: isinstance(f, Polynomial_relative_number_field_dense) True @@ -258,17 +262,18 @@ class Polynomial_relative_number_field_dense(Polynomial_generic_dense_field): OUTPUT: - - The monic gcd of ``self`` and ``other``. + The monic gcd of ``self`` and ``other``. See :meth:`Polynomial_absolute_number_field_dense.gcd` for more details. EXAMPLES:: + sage: # needs sage.symbolic sage: N = QQ[sqrt(2), sqrt(3)] sage: s2, s3 = N.gens() sage: x = polygen(N) - sage: f = x^4 - 5*x^2 +6 + sage: f = x^4 - 5*x^2 + 6 sage: g = x^3 + (-2*s2 + s3)*x^2 + (-2*s3*s2 + 2)*x + 2*s3 sage: gcd(f, g) x^2 + (-sqrt2 + sqrt3)*x - sqrt3*sqrt2 @@ -277,11 +282,11 @@ class Polynomial_relative_number_field_dense(Polynomial_generic_dense_field): TESTS:: - sage: x = var('x') - sage: R = NumberField([x^2-2, x^2-3], 'a')['x'] + sage: x = polygen(ZZ, 'x') + sage: R = NumberField([x^2 - 2, x^2 - 3], 'a')['x'] sage: f = R._random_nonzero_element() sage: g1 = R.random_element() - sage: g2 = R.random_element()*g1+1 + sage: g2 = R.random_element()*g1 + 1 sage: g1 *= f sage: g2 *= f sage: f.monic() - g1.gcd(g2) @@ -289,10 +294,10 @@ class Polynomial_relative_number_field_dense(Polynomial_generic_dense_field): Test for degree one extensions:: - sage: R = NumberField([x-2,x+1,x-3],'a')['x'] + sage: R = NumberField([x - 2, x + 1, x - 3], 'a')['x'] sage: f = R.random_element(2) sage: g1 = R.random_element(2) - sage: g2 = R.random_element(2)*g1+1 + sage: g2 = R.random_element(2)*g1 + 1 sage: g1 *= f sage: g2 *= f sage: d = gcd(g1, g2) @@ -303,6 +308,7 @@ class Polynomial_relative_number_field_dense(Polynomial_generic_dense_field): Test for hardcoded variables:: + sage: # needs sage.symbolic sage: R = N['sqrt2sqrt3'] sage: x = R.gen() sage: f = x^2 - 2 diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index ab35434ca30..e372be888ee 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -1,11 +1,11 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.libs.pari """ Quotients of Univariate Polynomial Rings EXAMPLES:: sage: R.<x> = QQ[] - sage: S = R.quotient(x**3-3*x+1, 'alpha') + sage: S = R.quotient(x**3 - 3*x + 1, 'alpha') sage: S.gen()**2 in S True sage: x in S @@ -17,6 +17,7 @@ TESTS:: + sage: # needs sage.libs.flint sage: Pol.<y> = CBF[] sage: Quo.<y> = Pol.quotient(y^3) sage: CBF.zero()*y @@ -37,10 +38,8 @@ #***************************************************************************** -import sage.rings.number_field.all from . import polynomial_element import sage.rings.rational_field -import sage.rings.complex_mpfr from sage.rings.ring import Field, IntegralDomain, CommutativeRing @@ -54,12 +53,14 @@ from sage.rings.quotient_ring import QuotientRing_generic from sage.structure.category_object import normalize_names +from sage.structure.coerce_maps import DefaultConvertMap_unique from sage.structure.factory import UniqueFactory from sage.rings.polynomial.infinite_polynomial_ring import GenDictWithBasering from sage.structure.richcmp import richcmp + class PolynomialQuotientRingFactory(UniqueFactory): r""" Create a quotient of a polynomial ring. @@ -81,10 +82,11 @@ class PolynomialQuotientRingFactory(UniqueFactory): demonstrate many basic functions with it:: sage: Z = IntegerRing() - sage: R = PolynomialRing(Z,'x'); x = R.gen() + sage: R = PolynomialRing(Z, 'x'); x = R.gen() sage: S = R.quotient(x^3 + 7, 'a'); a = S.gen() sage: S - Univariate Quotient Polynomial Ring in a over Integer Ring with modulus x^3 + 7 + Univariate Quotient Polynomial Ring in a + over Integer Ring with modulus x^3 + 7 sage: a^3 -7 sage: S.is_field() @@ -110,22 +112,29 @@ class PolynomialQuotientRingFactory(UniqueFactory): :: + sage: # needs sage.libs.ntl sage: A.<y> = PolynomialRing(GF(2)); A Univariate Polynomial Ring in y over Finite Field of size 2 (using GF2X) sage: B = A.quotient(y^2 + y + 1, 'y2'); B - Univariate Quotient Polynomial Ring in y2 over Finite Field of size 2 with modulus y^2 + y + 1 - sage: C = PolynomialRing(B, 'x'); x=C.gen(); C - Univariate Polynomial Ring in x over Univariate Quotient Polynomial Ring in y2 over Finite Field of size 2 with modulus y^2 + y + 1 + Univariate Quotient Polynomial Ring in y2 over Finite Field of size 2 + with modulus y^2 + y + 1 + sage: C = PolynomialRing(B, 'x'); x = C.gen(); C + Univariate Polynomial Ring in x + over Univariate Quotient Polynomial Ring in y2 + over Finite Field of size 2 with modulus y^2 + y + 1 sage: R = C.quotient(x^3 - 5); R - Univariate Quotient Polynomial Ring in xbar over Univariate Quotient Polynomial Ring in y2 over Finite Field of size 2 with modulus y^2 + y + 1 with modulus x^3 + 1 + Univariate Quotient Polynomial Ring in xbar + over Univariate Quotient Polynomial Ring in y2 + over Finite Field of size 2 with modulus y^2 + y + 1 + with modulus x^3 + 1 Next we create a number field, but viewed as a quotient of a polynomial ring over `\QQ`:: sage: R = PolynomialRing(RationalField(), 'x'); x = R.gen() - sage: S = R.quotient(x^3 + 2*x - 5, 'a') - sage: S - Univariate Quotient Polynomial Ring in a over Rational Field with modulus x^3 + 2*x - 5 + sage: S = R.quotient(x^3 + 2*x - 5, 'a'); S + Univariate Quotient Polynomial Ring in a over Rational Field + with modulus x^3 + 2*x - 5 sage: S.is_field() True sage: S.degree() @@ -135,10 +144,11 @@ class PolynomialQuotientRingFactory(UniqueFactory): between quotients of polynomial rings over `\QQ` and number fields:: - sage: K = S.number_field(); K + sage: K = S.number_field(); K # needs sage.rings.number_field Number Field in a with defining polynomial x^3 + 2*x - 5 - sage: K.polynomial_quotient_ring() - Univariate Quotient Polynomial Ring in a over Rational Field with modulus x^3 + 2*x - 5 + sage: K.polynomial_quotient_ring() # needs sage.rings.number_field + Univariate Quotient Polynomial Ring in a + over Rational Field with modulus x^3 + 2*x - 5 The leading coefficient must be a unit (but need not be 1). @@ -161,7 +171,7 @@ class PolynomialQuotientRingFactory(UniqueFactory): This shows that the issue at :trac:`5482` is solved:: sage: R.<x> = PolynomialRing(QQ) - sage: f = x^2-1 + sage: f = x^2 - 1 sage: R.quotient_by_principal_ideal(f) Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 - 1 @@ -228,7 +238,8 @@ def create_object(self, version, key): EXAMPLES:: sage: R.<x> = QQ[] - sage: PolynomialQuotientRing.create_object((8, 0, 0), (R, x^2 - 1, ('xbar'))) + sage: PolynomialQuotientRing.create_object((8, 0, 0), + ....: (R, x^2 - 1, ('xbar'))) Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 - 1 """ @@ -266,7 +277,8 @@ class PolynomialQuotientRing_generic(QuotientRing_generic): sage: R.<x> = PolynomialRing(Integers(8)); R Univariate Polynomial Ring in x over Ring of integers modulo 8 sage: S.<xbar> = R.quotient(x^2 + 1); S - Univariate Quotient Polynomial Ring in xbar over Ring of integers modulo 8 with modulus x^2 + 1 + Univariate Quotient Polynomial Ring in xbar over Ring of integers modulo 8 + with modulus x^2 + 1 We demonstrate object persistence. @@ -282,11 +294,12 @@ class PolynomialQuotientRing_generic(QuotientRing_generic): :: sage: R.<x> = PolynomialRing(ZZ) - sage: S = R.quo(x^2-4) + sage: S = R.quo(x^2 - 4) sage: f = S.hom([2]) sage: f Ring morphism: - From: Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 - 4 + From: Univariate Quotient Polynomial Ring in xbar over Integer Ring + with modulus x^2 - 4 To: Integer Ring Defn: xbar |--> 2 sage: f(x) @@ -309,7 +322,7 @@ class of the quotient ring and its newly created elements. Thus, in order to document that this works fine, we go into some detail:: sage: P.<x> = QQ[] - sage: Q = P.quotient(x^2+2) + sage: Q = P.quotient(x^2 + 2) sage: Q.category() Category of commutative no zero divisors quotients of algebras over (number fields and quotient fields and metric spaces) @@ -319,10 +332,11 @@ class of the quotient ring and its newly created elements. class of the category, and store the current class of the quotient ring:: - sage: isinstance(Q.an_element(),Q.element_class) + sage: isinstance(Q.an_element(), Q.element_class) True sage: [s for s in dir(Q.category().element_class) if not s.startswith('_')] - ['cartesian_product', 'inverse', 'inverse_of_unit', 'is_idempotent', 'is_one', 'is_unit', 'lift', 'powers'] + ['cartesian_product', 'inverse', 'inverse_of_unit', 'is_idempotent', + 'is_one', 'is_unit', 'lift', 'powers'] sage: first_class = Q.__class__ We try to find out whether `Q` is a field. Indeed it is, and thus its category, @@ -362,14 +376,14 @@ class of the category, and store the current class of the quotient sage: e = Q.an_element() sage: isinstance(e, Q.element_class) False - sage: e.gcd(e+1) + sage: e.gcd(e + 1) 1 The test suite passes. However, we have to skip the test for its elements, since `an_element` has been cached in the call above and its class does not match the new category's element class anymore:: - sage: TestSuite(Q).run(skip=['_test_elements']) + sage: TestSuite(Q).run(skip=['_test_elements']) # needs sage.rings.number_field Newly created elements are fine, though, and their test suite passes:: @@ -384,18 +398,18 @@ def __init__(self, ring, polynomial, name=None, category=None): TESTS:: sage: R.<x> = PolynomialRing(ZZ) - sage: S = R.quo(x^2-4) + sage: S = R.quo(x^2 - 4) sage: from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic - sage: S == PolynomialQuotientRing_generic(R,x^2-4,'xbar') + sage: S == PolynomialQuotientRing_generic(R, x^2 - 4, 'xbar') True Check that :trac:`26161` has been resolved:: sage: R.<x> = GF(2)[] - sage: S = R.quo(x) - sage: S in FiniteFields() + sage: S = R.quo(x) # needs sage.rings.finite_rings + sage: S in FiniteFields() # needs sage.rings.finite_rings True - sage: type(S).mro() + sage: type(S).mro() # needs sage.rings.finite_rings [<class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_field_with_category'>, ... <class 'sage.categories.finite_fields.FiniteFields.parent_class'>, @@ -441,7 +455,7 @@ def _element_constructor_(self, x): EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: S.<alpha> = R.quotient(x^3-3*x+1) + sage: S.<alpha> = R.quotient(x^3 - 3*x + 1) sage: S(x) alpha sage: S(x^3) @@ -477,7 +491,8 @@ def _element_constructor_(self, x): sage: p 2*xbar sage: p.parent() - Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^4 + 2*x^2 + 1 + Univariate Quotient Polynomial Ring in xbar over Rational Field + with modulus x^4 + 2*x^2 + 1 sage: p.parent()('xbar') xbar @@ -533,7 +548,7 @@ def _element_constructor_(self, x): try: return self.element_class(self, self.__ring(x), check=False) except TypeError: - raise TypeError("unable to convert %r to an element of %s"%(x, self)) + raise TypeError("unable to convert %r to an element of %s" % (x, self)) def _coerce_map_from_(self, R): r""" @@ -566,7 +581,7 @@ def _coerce_map_from_(self, R): sage: P.<x> = QQ[] sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)]) sage: R.<y> = P[] - sage: Q2 = R.quo([(y^2+1)]) + sage: Q2 = R.quo([(y^2 + 1)]) sage: Q2.has_coerce_map_from(Q1) False @@ -587,6 +602,7 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): """ EXAMPLES:: + sage: # needs sage.rings.number_field sage: T.<t> = ZZ[] sage: K.<i> = NumberField(t^2 + 1) sage: R.<x> = K[] @@ -646,7 +662,7 @@ def lift(self, x): EXAMPLES:: sage: P.<x> = QQ[] - sage: Q = P.quotient(x^2+2) + sage: Q = P.quotient(x^2 + 2) sage: Q.lift(Q.0^3) -2*x sage: Q(-2*x) @@ -667,13 +683,13 @@ def __eq__(self, other): sage: Ry.<y> = PolynomialRing(QQ) sage: Rx == Ry False - sage: Qx = Rx.quotient(x^2+1) - sage: Qy = Ry.quotient(y^2+1) + sage: Qx = Rx.quotient(x^2 + 1) + sage: Qy = Ry.quotient(y^2 + 1) sage: Qx == Qy False sage: Qx == Qx True - sage: Qz = Rx.quotient(x^2+1) + sage: Qz = Rx.quotient(x^2 + 1) sage: Qz == Qx True """ @@ -692,13 +708,13 @@ def __ne__(self, other): sage: Ry.<y> = PolynomialRing(QQ) sage: Rx != Ry True - sage: Qx = Rx.quotient(x^2+1) - sage: Qy = Ry.quotient(y^2+1) + sage: Qx = Rx.quotient(x^2 + 1) + sage: Qy = Ry.quotient(y^2 + 1) sage: Qx != Qy True sage: Qx != Qx False - sage: Qz = Rx.quotient(x^2+1) + sage: Qz = Rx.quotient(x^2 + 1) sage: Qz != Qx False """ @@ -714,13 +730,13 @@ def __hash__(self): sage: Ry.<y> = PolynomialRing(QQ) sage: hash(Rx) == hash(Ry) False - sage: Qx = Rx.quotient(x^2+1) - sage: Qy = Ry.quotient(y^2+1) + sage: Qx = Rx.quotient(x^2 + 1) + sage: Qy = Ry.quotient(y^2 + 1) sage: hash(Qx) == hash(Qy) False sage: hash(Qx) == hash(Qx) True - sage: Qz = Rx.quotient(x^2+1) + sage: Qz = Rx.quotient(x^2 + 1) sage: hash(Qz) == hash(Qx) True """ @@ -733,8 +749,8 @@ def _singular_init_(self, S=None): TESTS:: sage: P.<x> = QQ[] - sage: Q = P.quo([(x^2+1)]) - sage: singular(Q) # indirect doctest + sage: Q = P.quo([(x^2 + 1)]) + sage: singular(Q) # indirect doctest # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 @@ -743,7 +759,7 @@ def _singular_init_(self, S=None): // block 2 : ordering C // quotient ring from ideal _[1]=xbar^2+1 - sage: singular(Q.gen()) + sage: singular(Q.gen()) # needs sage.libs.singular xbar """ @@ -754,11 +770,11 @@ def _singular_init_(self, S=None): modulus = S(self.modulus()) # should live in Rpoly Rtmp = S(self.polynomial_ring().change_var(self.variable_name())) Rtmp.set_ring() - self.__singular = S("ideal(fetch(%s,%s))"%(Rpoly.name(),modulus.name()),"qring") + self.__singular = S("ideal(fetch(%s,%s))" % (Rpoly.name(),modulus.name()),"qring") return self.__singular def _repr_(self): - return "Univariate Quotient Polynomial Ring in %s over %s with modulus %s"%( + return "Univariate Quotient Polynomial Ring in %s over %s with modulus %s" % ( self.variable_name(), self.base_ring(), self.modulus()) def construction(self): @@ -767,13 +783,13 @@ def construction(self): EXAMPLES:: - sage: P.<t>=ZZ[] - sage: Q = P.quo(5+t^2) + sage: P.<t> = ZZ[] + sage: Q = P.quo(5 + t^2) sage: F, R = Q.construction() sage: F(R) == Q True sage: P.<t> = GF(3)[] - sage: Q = P.quo([2+t^2]) + sage: Q = P.quo([2 + t^2]) sage: F, R = Q.construction() sage: F(R) == Q True @@ -816,7 +832,8 @@ def base_ring(self): sage: T.<t> = PolynomialRing(S) sage: W = T.quotient(t^99 + 99) sage: W.base_ring() - Univariate Quotient Polynomial Ring in beta over Integer Ring with modulus z^3 + z^2 + z + 1 + Univariate Quotient Polynomial Ring in beta + over Integer Ring with modulus z^3 + z^2 + z + 1 """ return self.__ring.base_ring() @@ -831,20 +848,21 @@ def cardinality(self): sage: R.<x> = ZZ[] sage: R.quo(1).cardinality() 1 - sage: R.quo(x^3-2).cardinality() + sage: R.quo(x^3 - 2).cardinality() +Infinity sage: R.quo(1).order() 1 - sage: R.quo(x^3-2).order() + sage: R.quo(x^3 - 2).order() +Infinity :: - sage: R.<x> = GF(9,'a')[] - sage: R.quo(2*x^3+x+1).cardinality() + sage: # needs sage.rings.finite_rings + sage: R.<x> = GF(9, 'a')[] + sage: R.quo(2*x^3 + x + 1).cardinality() 729 - sage: GF(9,'a').extension(2*x^3+x+1).cardinality() + sage: GF(9, 'a').extension(2*x^3 + x + 1).cardinality() 729 sage: R.quo(2).cardinality() 1 @@ -880,21 +898,21 @@ def is_finite(self): sage: R.<x> = ZZ[] sage: R.quo(1).is_finite() True - sage: R.quo(x^3-2).is_finite() + sage: R.quo(x^3 - 2).is_finite() False :: - sage: R.<x> = GF(9,'a')[] - sage: R.quo(2*x^3+x+1).is_finite() + sage: R.<x> = GF(9, 'a')[] # needs sage.rings.finite_rings + sage: R.quo(2*x^3 + x + 1).is_finite() # needs sage.rings.finite_rings True - sage: R.quo(2).is_finite() + sage: R.quo(2).is_finite() # needs sage.rings.finite_rings True :: sage: P.<v> = GF(2)[] - sage: P.quotient(v^2-v).is_finite() + sage: P.quotient(v^2 - v).is_finite() True """ f = self.modulus() @@ -947,9 +965,9 @@ def characteristic(self): sage: S.<a> = R.quo(z - 19) sage: S.characteristic() 0 - sage: R.<x> = PolynomialRing(GF(9,'a')) - sage: S = R.quotient(x^3 + 1) - sage: S.characteristic() + sage: R.<x> = PolynomialRing(GF(9, 'a')) # needs sage.rings.finite_rings + sage: S = R.quotient(x^3 + 1) # needs sage.rings.finite_rings + sage: S.characteristic() # needs sage.rings.finite_rings 3 """ return self.base_ring().characteristic() @@ -990,7 +1008,7 @@ def discriminant(self, v=None): the ring of integers of the number field:: sage: S = R.quotient(x^2 - 8) - sage: S.number_field().discriminant() + sage: S.number_field().discriminant() # needs sage.rings.number_field 8 sage: S.discriminant() 32 @@ -1017,14 +1035,14 @@ class of the image of the generator of the polynomial ring. self.__gen = self(self.polynomial_ring().gen()) return self.__gen - def is_field(self, proof = True): + def is_field(self, proof=True): """ Return whether or not this quotient ring is a field. EXAMPLES:: sage: R.<z> = PolynomialRing(ZZ) - sage: S = R.quo(z^2-2) + sage: S = R.quo(z^2 - 2) sage: S.is_field() False sage: R.<x> = PolynomialRing(QQ) @@ -1035,14 +1053,17 @@ def is_field(self, proof = True): If proof is ``True``, requires the ``is_irreducible`` method of the modulus to be implemented:: + sage: # needs sage.rings.padics sage: R1.<x> = Qp(2)[] - sage: F1 = R1.quotient_ring(x^2+x+1) + sage: F1 = R1.quotient_ring(x^2 + x + 1) sage: R2.<x> = F1[] - sage: F2 = R2.quotient_ring(x^2+x+1) + sage: F2 = R2.quotient_ring(x^2 + x + 1) sage: F2.is_field() Traceback (most recent call last): ... - NotImplementedError: cannot rewrite Univariate Quotient Polynomial Ring in xbar over 2-adic Field with capped relative precision 20 with modulus (1 + O(2^20))*x^2 + (1 + O(2^20))*x + 1 + O(2^20) as an isomorphic ring + NotImplementedError: cannot rewrite Univariate Quotient Polynomial Ring in + xbar over 2-adic Field with capped relative precision 20 with modulus + (1 + O(2^20))*x^2 + (1 + O(2^20))*x + 1 + O(2^20) as an isomorphic ring sage: F2.is_field(proof = False) False @@ -1061,7 +1082,7 @@ def is_field(self, proof = True): self._refine_category_(Fields()) return ret - def is_integral_domain(self, proof = True): + def is_integral_domain(self, proof=True): """ Return whether or not this quotient ring is an integral domain. @@ -1079,14 +1100,14 @@ def is_integral_domain(self, proof = True): False sage: R2.<y> = PolynomialRing(R) sage: S2 = R2.quotient(z^2 - y^3) - sage: S2.is_integral_domain() + sage: S2.is_integral_domain() # needs sage.libs.singular True sage: S3 = R2.quotient(z^2 - 2*y*z + y^2) - sage: S3.is_integral_domain() + sage: S3.is_integral_domain() # needs sage.libs.singular False sage: R.<z> = PolynomialRing(ZZ.quotient(4)) - sage: S = R.quotient(z-1) + sage: S = R.quotient(z - 1) sage: S.is_integral_domain() False @@ -1096,6 +1117,8 @@ def is_integral_domain(self, proof = True): domain, even though the base ring is integral and the modulus is irreducible:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: B = ZZ.extension(x^2 - 5, 'a') sage: R.<y> = PolynomialRing(B) sage: S = R.quotient(y^2 - y - 1) @@ -1103,10 +1126,10 @@ def is_integral_domain(self, proof = True): Traceback (most recent call last): ... NotImplementedError - sage: S.is_integral_domain(proof = False) + sage: S.is_integral_domain(proof=False) False - The reason that the modulus y^2 - y -1 is not prime is that it + The reason that the modulus y^2 - y - 1 is not prime is that it divides the product (2*y-(1+a))*(2*y-(1-a)) = 4*y^2 - 4*y - 4. @@ -1151,10 +1174,11 @@ def krull_dimension(self): EXAMPLES:: - sage: R = PolynomialRing(ZZ,'x').quotient(x**6-1) + sage: x = polygen(ZZ, 'x') + sage: R = PolynomialRing(ZZ, 'x').quotient(x**6 - 1) sage: R.krull_dimension() 1 - sage: R = PolynomialRing(ZZ,'x').quotient(1) + sage: R = PolynomialRing(ZZ, 'x').quotient(1) sage: R.krull_dimension() -1 """ @@ -1186,7 +1210,8 @@ def ngens(self): sage: S.<y> = PolynomialRing(R) sage: T.<z> = S.quotient(y + x) sage: T - Univariate Quotient Polynomial Ring in z over Univariate Polynomial Ring in x over Rational Field with modulus y + x + Univariate Quotient Polynomial Ring in z over + Univariate Polynomial Ring in x over Rational Field with modulus y + x sage: T.ngens() 1 """ @@ -1199,10 +1224,10 @@ def number_field(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) sage: S.<alpha> = R.quotient(x^29 - 17*x - 1) - sage: K = S.number_field() - sage: K + sage: K = S.number_field(); K Number Field in alpha with defining polynomial x^29 - 17*x - 1 sage: alpha = K.gen() sage: alpha^29 @@ -1213,7 +1238,8 @@ def number_field(self): if not isinstance(self.base_ring(), sage.rings.rational_field.RationalField): raise NotImplementedError("Computation of number field only implemented for quotients of the polynomial ring over the rational field.") - return sage.rings.number_field.all.NumberField(self.modulus(), self.variable_name()) + from sage.rings.number_field.number_field import NumberField + return NumberField(self.modulus(), self.variable_name()) def polynomial_ring(self): """ @@ -1222,7 +1248,7 @@ def polynomial_ring(self): EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: S = R.quotient(x^2-2) + sage: S = R.quotient(x^2 - 2) sage: S.polynomial_ring() Univariate Polynomial Ring in x over Rational Field """ @@ -1242,18 +1268,19 @@ def random_element(self, *args, **kwds): OUTPUT: - - Element of this quotient ring + Element of this quotient ring EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F1.<a> = GF(2^7) sage: P1.<x> = F1[] - sage: F2 = F1.extension(x^2+x+1, 'u') + sage: F2 = F1.extension(x^2 + x + 1, 'u') sage: F2.random_element().parent() is F2 True """ - return self(self.polynomial_ring().random_element( \ - degree=self.degree()-1, *args, **kwds)) + return self(self.polynomial_ring().random_element( + degree=self.degree() - 1, *args, **kwds)) @cached_method def _S_decomposition(self, S): @@ -1265,22 +1292,23 @@ def _S_decomposition(self, S): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-5) sage: R.<x> = K[] - sage: S.<xbar> = R.quotient((x^2 + 23)*(x^2 + 31)) + sage: S.<xbar> = R.quotient((x^2 + 23) * (x^2 + 31)) sage: fields, isos, iso_classes = S._S_decomposition(tuple(K.primes_above(3))) Representatives of the number fields up to isomorphism that occur in the decomposition:: - sage: fields + sage: fields # needs sage.rings.number_field [Number Field in x0 with defining polynomial x^2 + 23 over its base field, Number Field in x1 with defining polynomial x^2 + 31 over its base field] In this case, the isomorphisms of these representatives to the components are the identity maps:: - sage: isos + sage: isos # needs sage.rings.number_field [(Ring endomorphism of Number Field in y0 with defining polynomial x^4 + 56*x^2 + 324 Defn: y0 |--> y0, 0), @@ -1291,14 +1319,14 @@ def _S_decomposition(self, S): There are four primes above 3 in the first component and two in the second component:: - sage: len(iso_classes[0][1]) + sage: len(iso_classes[0][1]) # needs sage.rings.number_field 4 - sage: len(iso_classes[1][1]) + sage: len(iso_classes[1][1]) # needs sage.rings.number_field 2 """ - from sage.rings.number_field.number_field_base import is_NumberField + from sage.rings.number_field.number_field_base import NumberField K = self.base_ring() - if not is_NumberField(K) or not self.__polynomial.is_squarefree(): + if not isinstance(K, NumberField) or not self.__polynomial.is_squarefree(): raise NotImplementedError from sage.rings.ideal import is_Ideal @@ -1340,7 +1368,7 @@ def _S_decomposition(self, S): def S_class_group(self, S, proof=True): r""" - If self is an รฉtale algebra `D` over a number field `K` (i.e. + If ``self`` is an รฉtale algebra `D` over a number field `K` (i.e. a quotient of `K[x]` by a squarefree polynomial) and `S` is a finite set of places of `K`, return a list of generators of the `S`-class group of `D`. @@ -1372,6 +1400,7 @@ def S_class_group(self, S, proof=True): A trivial algebra over `\QQ(\sqrt{-5})` has the same class group as its base:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-5) sage: R.<x> = K[] sage: S.<xbar> = R.quotient(x) @@ -1381,15 +1410,17 @@ def S_class_group(self, S, proof=True): When we include the prime `(2, -a+1)`, the `S`-class group becomes trivial:: - sage: S.S_class_group([K.ideal(2, -a+1)]) + sage: S.S_class_group([K.ideal(2, -a+1)]) # needs sage.rings.number_field [] Here is an example where the base and the extension both contribute to the class group:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-5) sage: K.class_group() - Class group of order 2 with structure C2 of Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I + Class group of order 2 with structure C2 of Number Field in a + with defining polynomial x^2 + 5 with a = 2.236067977499790?*I sage: R.<x> = K[] sage: S.<xbar> = R.quotient(x^2 + 23) sage: S.S_class_group([]) @@ -1404,10 +1435,11 @@ def S_class_group(self, S, proof=True): Now we take an example over a nontrivial base with two factors, each contributing to the class group:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-5) sage: R.<x> = K[] - sage: S.<xbar> = R.quotient((x^2 + 23)*(x^2 + 31)) - sage: S.S_class_group([]) # representation varies, not tested + sage: S.<xbar> = R.quotient((x^2 + 23) * (x^2 + 31)) + sage: S.S_class_group([]) # not tested [((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, @@ -1428,11 +1460,19 @@ def S_class_group(self, S, proof=True): `x^2 + 31` from 12 to 2, i.e. we lose a generator of order 6 (this was fixed in :trac:`14489`):: - sage: S.S_class_group([K.ideal(a)]) # representation varies, not tested - [((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, -1/16*a*xbar^3 + (1/16*a + 1/8)*xbar^2 - 31/16*a*xbar + 31/16*a + 31/8), 6), ((-1/4*xbar^2 - 23/4, (1/8*a - 1/8)*xbar^2 + 23/8*a - 23/8, -1/16*xbar^3 - 1/16*xbar^2 - 23/16*xbar - 23/16, 1/16*a*xbar^3 + (-1/16*a - 1/8)*xbar^2 + 23/16*a*xbar - 23/16*a - 23/8), 2)] + sage: S.S_class_group([K.ideal(a)]) # representation varies # not tested, needs sage.rings.number_field + [((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, + 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, + -1/16*a*xbar^3 + (1/16*a + 1/8)*xbar^2 - 31/16*a*xbar + 31/16*a + 31/8), + 6), + ((-1/4*xbar^2 - 23/4, (1/8*a - 1/8)*xbar^2 + 23/8*a - 23/8, + -1/16*xbar^3 - 1/16*xbar^2 - 23/16*xbar - 23/16, + 1/16*a*xbar^3 + (-1/16*a - 1/8)*xbar^2 + 23/16*a*xbar - 23/16*a - 23/8), + 2)] Note that all the returned values live where we expect them to:: + sage: # needs sage.rings.number_field sage: CG = S.S_class_group([]) sage: type(CG[0][0][1]) <class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_generic_with_category.element_class'> @@ -1443,9 +1483,10 @@ def S_class_group(self, S, proof=True): We verify the above test, where the representation depends on the PARI version:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-5) sage: R.<x> = K[] - sage: S.<xbar> = R.quotient((x^2 + 23)*(x^2 + 31)) + sage: S.<xbar> = R.quotient((x^2 + 23) * (x^2 + 31)) sage: C = S.S_class_group([]) sage: C[:2] [((1/4*xbar^2 + 31/4, @@ -1503,7 +1544,7 @@ def S_class_group(self, S, proof=True): def class_group(self, proof=True): r""" - If self is a quotient ring of a polynomial ring over a number + If ``self`` is a quotient ring of a polynomial ring over a number field `K`, by a polynomial of nonzero discriminant, return a list of generators of the class group. @@ -1527,9 +1568,12 @@ def class_group(self, proof=True): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-3) sage: K.class_group() - Class group of order 1 of Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + Class group of order 1 of Number Field in a + with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + sage: x = polygen(QQ, 'x') sage: K.<a> = QQ['x'].quotient(x^2 + 3) sage: K.class_group() [] @@ -1537,6 +1581,7 @@ def class_group(self, proof=True): A trivial algebra over `\QQ(\sqrt{-5})` has the same class group as its base:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-5) sage: R.<x> = K[] sage: S.<xbar> = R.quotient(x) @@ -1545,16 +1590,19 @@ def class_group(self, proof=True): The same algebra constructed in a different way:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = QQ['x'].quotient(x^2 + 5) - sage: K.class_group(()) + sage: K.class_group(()) # needs sage.rings.number_field [((2, a + 1), 2)] Here is an example where the base and the extension both contribute to the class group:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-5) sage: K.class_group() - Class group of order 2 with structure C2 of Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I + Class group of order 2 with structure C2 of Number Field in a + with defining polynomial x^2 + 5 with a = 2.236067977499790?*I sage: R.<x> = K[] sage: S.<xbar> = R.quotient(x^2 + 23) sage: S.class_group() @@ -1563,18 +1611,25 @@ def class_group(self, proof=True): Here is an example of a product of number fields, both of which contribute to the class group:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: S.<xbar> = R.quotient((x^2 + 23)*(x^2 + 47)) + sage: S.<xbar> = R.quotient((x^2 + 23) * (x^2 + 47)) sage: S.class_group() - [((1/12*xbar^2 + 47/12, 1/48*xbar^3 - 1/48*xbar^2 + 47/48*xbar - 47/48), 3), ((-1/12*xbar^2 - 23/12, -1/48*xbar^3 - 1/48*xbar^2 - 23/48*xbar - 23/48), 5)] + [((1/12*xbar^2 + 47/12, + 1/48*xbar^3 - 1/48*xbar^2 + 47/48*xbar - 47/48), + 3), + ((-1/12*xbar^2 - 23/12, + -1/48*xbar^3 - 1/48*xbar^2 - 23/48*xbar - 23/48), + 5)] Now we take an example over a nontrivial base with two factors, each contributing to the class group:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-5) sage: R.<x> = K[] - sage: S.<xbar> = R.quotient((x^2 + 23)*(x^2 + 31)) - sage: S.class_group() # representation varies, not tested + sage: S.<xbar> = R.quotient((x^2 + 23) * (x^2 + 31)) + sage: S.class_group() # not tested [((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, @@ -1593,6 +1648,7 @@ def class_group(self, proof=True): Note that all the returned values live where we expect them to:: + sage: # needs sage.rings.number_field sage: CG = S.class_group() sage: type(CG[0][0][1]) <class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_generic_with_category.element_class'> @@ -1622,11 +1678,15 @@ def S_units(self, S, proof=True): EXAMPLES:: - sage: K.<a> = QuadraticField(-3) - sage: K.unit_group() - Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + sage: K.<a> = QuadraticField(-3) # needs sage.rings.number_field + sage: K.unit_group() # needs sage.rings.number_field + Unit group with structure C6 of Number Field in a + with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = QQ['x'].quotient(x^2 + 3) - sage: u,o = K.S_units([])[0]; o + sage: u, o = K.S_units([])[0]; o 6 sage: 2*u - 1 in {a, -a} True @@ -1639,14 +1699,18 @@ def S_units(self, S, proof=True): :: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-3) sage: y = polygen(K) sage: L.<b> = K['y'].quotient(y^3 + 5); L - Univariate Quotient Polynomial Ring in b over Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I with modulus y^3 + 5 + Univariate Quotient Polynomial Ring in b over Number Field in a + with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + with modulus y^3 + 5 sage: [u for u, o in L.S_units([]) if o is Infinity] [(-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, 2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2] - sage: [u for u, o in L.S_units([K.ideal(1/2*a - 3/2)]) if o is Infinity] + sage: [u for u, o in L.S_units([K.ideal(1/2*a - 3/2)]) + ....: if o is Infinity] [(-1/6*a - 1/2)*b^2 + (1/3*a - 1)*b + 4/3*a, (-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, 2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2] @@ -1659,6 +1723,7 @@ def S_units(self, S, proof=True): Note that all the returned values live where we expect them to:: + sage: # needs sage.rings.number_field sage: U = L.S_units([]) sage: type(U[0][0]) <class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_field_with_category.element_class'> @@ -1708,9 +1773,13 @@ def units(self, proof=True): EXAMPLES:: - sage: K.<a> = QuadraticField(-3) - sage: K.unit_group() - Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + sage: K.<a> = QuadraticField(-3) # needs sage.rings.number_field + sage: K.unit_group() # needs sage.rings.number_field + Unit group with structure C6 of + Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = QQ['x'].quotient(x^2 + 3) sage: u = K.units()[0][0] sage: 2*u - 1 in {a, -a} @@ -1721,29 +1790,36 @@ def units(self, proof=True): -1 sage: 2*u^2 + 1 in {a, -a} True + sage: x = polygen(ZZ, 'x') sage: K.<a> = QQ['x'].quotient(x^2 + 5) sage: K.units(()) [(-1, 2)] :: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-3) sage: y = polygen(K) sage: L.<b> = K['y'].quotient(y^3 + 5); L - Univariate Quotient Polynomial Ring in b over Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I with modulus y^3 + 5 + Univariate Quotient Polynomial Ring in b over Number Field in a + with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + with modulus y^3 + 5 sage: [u for u, o in L.units() if o is Infinity] [(-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, 2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2] sage: L.<b> = K.extension(y^3 + 5) sage: L.unit_group() - Unit group with structure C6 x Z x Z of Number Field in b with defining polynomial x^3 + 5 over its base field + Unit group with structure C6 x Z x Z of + Number Field in b with defining polynomial x^3 + 5 over its base field sage: L.unit_group().gens() # abstract generators (u0, u1, u2) sage: L.unit_group().gens_values()[1:] - [(-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, 2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2] + [(-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, + 2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2] Note that all the returned values live where we expect them to:: + sage: # needs sage.rings.number_field sage: L.<b> = K['y'].quotient(y^3 + 5) sage: U = L.units() sage: type(U[0][0]) @@ -1779,22 +1855,25 @@ def selmer_generators(self, S, m, proof=True): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-5) sage: R.<x> = K[] sage: D.<T> = R.quotient(x) sage: D.selmer_generators((), 2) [-1, 2] - sage: D.selmer_generators([K.ideal(2, -a+1)], 2) + sage: D.selmer_generators([K.ideal(2, -a + 1)], 2) [2, -1] - sage: D.selmer_generators([K.ideal(2, -a+1), K.ideal(3, a+1)], 2) + sage: D.selmer_generators([K.ideal(2, -a + 1), K.ideal(3, a + 1)], 2) [2, a + 1, -1] - sage: D.selmer_generators((K.ideal(2, -a+1),K.ideal(3, a+1)), 4) + sage: D.selmer_generators((K.ideal(2, -a + 1), K.ideal(3, a + 1)), 4) [2, a + 1, -1] - sage: D.selmer_generators([K.ideal(2, -a+1)], 3) + sage: D.selmer_generators([K.ideal(2, -a + 1)], 3) [2] - sage: D.selmer_generators([K.ideal(2, -a+1), K.ideal(3, a+1)], 3) + sage: D.selmer_generators([K.ideal(2, -a + 1), K.ideal(3, a + 1)], 3) [2, a + 1] - sage: D.selmer_generators([K.ideal(2, -a+1), K.ideal(3, a+1), K.ideal(a)], 3) + sage: D.selmer_generators([K.ideal(2, -a + 1), + ....: K.ideal(3, a + 1), + ....: K.ideal(a)], 3) [2, a + 1, -a] """ @@ -1829,12 +1908,13 @@ def _factor_multivariate_polynomial(self, f, proof=True): TESTS:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(4) sage: R.<b> = k[] sage: l.<b> = k.extension(b^2 + b + a) sage: K.<x> = FunctionField(l) sage: R.<t> = K[] - sage: F = t*x + sage: F = t * x sage: F.factor(proof=False) (x) * t @@ -1856,17 +1936,18 @@ def _factor_univariate_polynomial(self, f): TESTS:: + sage: # needs sage.rings.finite_rings sage: K = GF(2) sage: R.<x> = K[] sage: L.<x> = K.extension(x^2 + x + 1) sage: R.<y> = L[] sage: M.<y> = L.extension(y^2 + y + x) sage: R.<T> = M[] - sage: R(y).factor() # indirect doctest + sage: R(y).factor() # indirect doctest y - sage: (T^2 + T + x).factor() # indirect doctest + sage: (T^2 + T + x).factor() # indirect doctest (T + y) * (T + y + 1) - sage: (y*T^2 + y*T + y*x).factor() # indirect doctest + sage: (y*T^2 + y*T + y*x).factor() # indirect doctest (y) * (T + y) * (T + y + 1) """ @@ -1907,32 +1988,37 @@ def _isomorphic_ring(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(4) sage: R.<b> = K[] - sage: L.<b> = K.extension(b^2+b+a); L - Univariate Quotient Polynomial Ring in b over Finite Field in a of size 2^2 with modulus b^2 + b + a + sage: L.<b> = K.extension(b^2 + b + a); L + Univariate Quotient Polynomial Ring in b + over Finite Field in a of size 2^2 with modulus b^2 + b + a sage: from_M, to_M, M = L._isomorphic_ring(); M Finite Field in z4 of size 2^4 - sage: R.<c> = L[] - sage: M.<c> = L.extension(c^2+b*c+b); M - Univariate Quotient Polynomial Ring in c over Univariate Quotient Polynomial Ring in b over Finite Field in a of size 2^2 with modulus b^2 + b + a with modulus c^2 + b*c + b - sage: from_N, to_N, N = M._isomorphic_ring(); N + sage: R.<c> = L[] # needs sage.rings.finite_rings + sage: M.<c> = L.extension(c^2 + b*c + b); M # needs sage.rings.finite_rings + Univariate Quotient Polynomial Ring in c + over Univariate Quotient Polynomial Ring in b + over Finite Field in a of size 2^2 with modulus b^2 + b + a + with modulus c^2 + b*c + b + sage: from_N, to_N, N = M._isomorphic_ring(); N # needs sage.rings.finite_rings Finite Field in z8 of size 2^8 sage: R.<x> = QQ[] sage: K = R.quo(x^2 + 1) - sage: from_L, to_L, L = K._isomorphic_ring() - sage: L + sage: from_L, to_L, L = K._isomorphic_ring() # needs sage.rings.number_field + sage: L # needs sage.rings.number_field Number Field in xbar with defining polynomial x^2 + 1 TESTS: Verify that this works for trivial extensions:: - sage: K.<a> = GF(4) - sage: R.<b> = K[] - sage: from_L, to_L, L = R.quo(b)._isomorphic_ring(); L + sage: K.<a> = GF(4) # needs sage.rings.finite_rings + sage: R.<b> = K[] # needs sage.rings.finite_rings + sage: from_L, to_L, L = R.quo(b)._isomorphic_ring(); L # needs sage.rings.finite_rings Finite Field in a of size 2^2 """ @@ -1964,7 +2050,7 @@ def _isomorphic_ring(self): lambda f: f.lift().map_coefficients(base_to_isomorphic_base)(isomorphic_quotient.gen())) return (from_isomorphic_quotient * isomorphic_ring_to_isomorphic_quotient, - isomorphic_quotient_to_isomorphic_ring * to_isomorphic_quotient, + isomorphic_quotient_to_isomorphic_ring * to_isomorphic_quotient, isomorphic_ring) if self.modulus().degree() == 1: @@ -2041,7 +2127,7 @@ def _isomorphic_ring(self): to_isomorphic_ring = self.hom([isomorphic_ring.gen()]) return from_isomorphic_ring, to_isomorphic_ring, isomorphic_ring - raise NotImplementedError("cannot rewrite %r as an isomorphic ring"%(self,)) + raise NotImplementedError("cannot rewrite %r as an isomorphic ring" % (self,)) def _test_isomorphic_ring(self, **options): r""" @@ -2049,12 +2135,13 @@ def _test_isomorphic_ring(self, **options): TESTS:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(4) sage: R.<b> = K[] - sage: L.<b> = K.extension(b^2+b+a) + sage: L.<b> = K.extension(b^2 + b + a) sage: L._test_isomorphic_ring() sage: R.<c> = L[] - sage: M.<c> = L.extension(c^2+b*c+b) + sage: M.<c> = L.extension(c^2 + b*c + b) sage: M._test_isomorphic_ring() """ @@ -2082,7 +2169,7 @@ def _test_isomorphic_ring(self, **options): tester.assertIn(y, ring) tester.assertEqual(from_isomorphic_ring(y), x) -from sage.structure.coerce_maps import DefaultConvertMap_unique + class PolynomialQuotientRing_coercion(DefaultConvertMap_unique): r""" A coercion map from a :class:`PolynomialQuotientRing` to a @@ -2095,8 +2182,10 @@ class PolynomialQuotientRing_coercion(DefaultConvertMap_unique): sage: S.<x> = QQ[] sage: f = S.quo(x^2 + 1).coerce_map_from(R.quo(x^2 + 1)); f Coercion map: - From: Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1 - To: Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 + 1 + From: Univariate Quotient Polynomial Ring in xbar over Integer Ring + with modulus x^2 + 1 + To: Univariate Quotient Polynomial Ring in xbar over Rational Field + with modulus x^2 + 1 TESTS:: @@ -2158,6 +2247,7 @@ def is_surjective(self): If the modulus of the domain and the codomain is the same, then the map is surjective iff the underlying map on the constants is:: + sage: # needs sage.rings.padics sage: A.<a> = ZqCA(9) sage: R.<x> = A[] sage: S.<x> = A.fraction_field()[] @@ -2189,10 +2279,11 @@ def _richcmp_(self, other, op): True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp(self.parent(), other.parent(), op) + class PolynomialQuotientRing_domain(PolynomialQuotientRing_generic, IntegralDomain): """ EXAMPLES:: @@ -2200,7 +2291,8 @@ class PolynomialQuotientRing_domain(PolynomialQuotientRing_generic, IntegralDoma sage: R.<x> = PolynomialRing(ZZ) sage: S.<xbar> = R.quotient(x^2 + 1) sage: S - Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1 + Univariate Quotient Polynomial Ring in xbar + over Integer Ring with modulus x^2 + 1 sage: loads(S.dumps()) == S True sage: loads(xbar.dumps()) == xbar @@ -2224,7 +2316,7 @@ def __init__(self, ring, polynomial, name=None, category=None): Check that :trac:`29017` is fixed:: sage: R.<x> = ZZ[] - sage: Q = R.quo(x-1) + sage: Q = R.quo(x - 1) sage: H = R.Hom(Q) sage: h = R.hom(Q) sage: h.parent() is H @@ -2235,24 +2327,25 @@ def __init__(self, ring, polynomial, name=None, category=None): def field_extension(self, names): r""" - Takes a polynomial quotient ring, and returns a tuple with three - elements: the NumberField defined by the same polynomial quotient - ring, a homomorphism from its parent to the NumberField sending the + Take a polynomial quotient ring, and return a tuple with three + elements: the :class:`NumberField` defined by the same polynomial quotient + ring, a homomorphism from its parent to the :class:`NumberField` sending the generators to one another, and the inverse isomorphism. OUTPUT: - field - - homomorphism from self to field + - homomorphism from ``self`` to field - - homomorphism from field to self + - homomorphism from field to ``self`` EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(Rationals()) - sage: S.<alpha> = R.quotient(x^3-2) + sage: S.<alpha> = R.quotient(x^3 - 2) sage: F.<b>, f, g = S.field_extension() sage: F Number Field in b with defining polynomial x^3 - 2 @@ -2264,9 +2357,9 @@ def field_extension(self, names): Note that the parent ring must be an integral domain:: - sage: R.<x> = GF(25,'f25')['x'] - sage: S.<a> = R.quo(x^3 - 2) - sage: F, g, h = S.field_extension('b') + sage: R.<x> = GF(25, 'f25')['x'] # needs sage.rings.finite_rings + sage: S.<a> = R.quo(x^3 - 2) # needs sage.rings.finite_rings + sage: F, g, h = S.field_extension('b') # needs sage.rings.finite_rings Traceback (most recent call last): ... AttributeError: 'PolynomialQuotientRing_generic_with_category' object has no attribute 'field_extension' @@ -2274,6 +2367,7 @@ def field_extension(self, names): Over a finite field, the corresponding field extension is not a number field:: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(25, 'a')['x'] sage: S.<a> = R.quo(x^3 + 2*x + 1) sage: F, g, h = S.field_extension('b') @@ -2284,6 +2378,7 @@ def field_extension(self, names): We do an example involving a relative number field:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ['x'] sage: K.<a> = NumberField(x^3 - 2) sage: S.<X> = K['X'] @@ -2300,6 +2395,7 @@ def field_extension(self, names): :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ['x'] sage: K.<a> = NumberField(x^3 - 2) sage: S.<X> = K['X'] @@ -2326,16 +2422,16 @@ def field_extension(self, names): return self.gen().field_extension(names) - - class PolynomialQuotientRing_field(PolynomialQuotientRing_domain, Field): """ EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) sage: S.<xbar> = R.quotient(x^2 + 1) sage: S - Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 + 1 + Univariate Quotient Polynomial Ring in xbar over Rational Field + with modulus x^2 + 1 sage: loads(S.dumps()) == S True sage: loads(xbar.dumps()) == xbar @@ -2346,24 +2442,30 @@ def __init__(self, ring, polynomial, name=None, category=None): def base_field(self): r""" - Alias for base_ring, when we're defined over a field. + Alias for :meth:`base_ring`, when we're defined over a field. """ return self.base_ring() def complex_embeddings(self, prec=53): r""" Return all homomorphisms of this ring into the approximate complex - field with precision prec. + field with precision ``prec``. EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: f = x^5 + x + 17 sage: k = R.quotient(f) sage: v = k.complex_embeddings(100) sage: [phi(k.0^2) for phi in v] - [2.9757207403766761469671194565, -2.4088994371613850098316292196 + 1.9025410530350528612407363802*I, -2.4088994371613850098316292196 - 1.9025410530350528612407363802*I, 0.92103906697304693634806949137 - 3.0755331188457794473265418086*I, 0.92103906697304693634806949137 + 3.0755331188457794473265418086*I] - """ - CC = sage.rings.complex_mpfr.ComplexField(prec) + [2.9757207403766761469671194565, + -2.4088994371613850098316292196 + 1.9025410530350528612407363802*I, + -2.4088994371613850098316292196 - 1.9025410530350528612407363802*I, + 0.92103906697304693634806949137 - 3.0755331188457794473265418086*I, + 0.92103906697304693634806949137 + 3.0755331188457794473265418086*I] + """ + from sage.rings.complex_mpfr import ComplexField + CC = ComplexField(prec) v = self.modulus().roots(multiplicities=False, ring=CC) return [self.hom([a], check=False) for a in v] diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index be05a312725..4185f0d1455 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari r""" Elements of Quotients of Univariate Polynomial Rings @@ -7,7 +8,7 @@ :: sage: R.<x> = ZZ[] - sage: S.<a> = R.quotient(x^3 + 3*x -1) + sage: S.<a> = R.quotient(x^3 + 3*x - 1) sage: 2 * a^3 -6*a + 2 @@ -22,7 +23,7 @@ :: - sage: T.<z> = S1.quotient(y^2+a) + sage: T.<z> = S1.quotient(y^2 + a) In the quotient `z^2` is `-a`. @@ -46,7 +47,7 @@ :: sage: R.<x> = PolynomialRing(QQ) - sage: S.<a> = R.quotient(x^3-2) + sage: S.<a> = R.quotient(x^3 - 2) sage: a a sage: a^3 @@ -96,12 +97,12 @@ class PolynomialQuotientRingElement(polynomial_singular_interface.Polynomial_sin EXAMPLES:: sage: P.<x> = QQ[] - sage: Q.<xi> = P.quo([(x^2+1)]) + sage: Q.<xi> = P.quo([(x^2 + 1)]) sage: xi^2 -1 - sage: singular(xi) + sage: singular(xi) # needs sage.libs.singular xi - sage: (singular(xi)*singular(xi)).NF('std(0)') + sage: (singular(xi)*singular(xi)).NF('std(0)') # needs sage.libs.singular -1 """ @@ -160,6 +161,7 @@ def _im_gens_(self, codomain, im_gens, base_map=None): EXAMPLES:: + sage: # needs sage.rings.number_field sage: Zx.<x> = ZZ[] sage: K.<i> = NumberField(x^2 + 1) sage: cc = K.hom([-i]) @@ -270,7 +272,7 @@ def _add_(self, right): EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: S.<a> = R.quotient(x^3-2) + sage: S.<a> = R.quotient(x^3 - 2) sage: (a^2 - 4) + (a+2) a^2 + a - 2 sage: int(1) + a @@ -286,7 +288,7 @@ def _div_(self, right): EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: S.<a> = R.quotient(x^3-2) + sage: S.<a> = R.quotient(x^3 - 2) sage: (a^2 - 4) / (a+2) a - 2 """ @@ -303,7 +305,7 @@ def _richcmp_(self, other, op): EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: S.<a> = R.quotient(x^3-2) + sage: S.<a> = R.quotient(x^3 - 2) sage: (a^2 - 4) / (a+2) == a - 2 True sage: a^2 - 4 == a @@ -321,7 +323,7 @@ def __int__(self): EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: S.<a> = R.quotient(x^3-2) + sage: S.<a> = R.quotient(x^3 - 2) sage: int(S(10)) 10 sage: int(a) @@ -345,7 +347,7 @@ def is_unit(self): sage: S.<y> = R.quotient(x^2 + 2*x + 1) sage: (2*y).is_unit() True - sage: (y+1).is_unit() + sage: (y + 1).is_unit() False TESTS: @@ -422,7 +424,7 @@ def __invert__(self): 11 """ if self._polynomial.is_zero(): - raise ZeroDivisionError("element %s of quotient polynomial ring not invertible"%self) + raise ZeroDivisionError("element %s of quotient polynomial ring not invertible" % self) if self._polynomial.is_one(): return self @@ -440,7 +442,7 @@ def __invert__(self): raise NotImplementedError("The base ring (=%s) is not a field" % base) g, _, a = parent.modulus().xgcd(self._polynomial) if g.degree() != 0: - raise ZeroDivisionError("element %s of quotient polynomial ring not invertible"%self) + raise ZeroDivisionError("element %s of quotient polynomial ring not invertible" % self) c = g[0] return self.__class__(self.parent(), (~c)*a, check=False) @@ -460,15 +462,16 @@ def field_extension(self, names): - field - - homomorphism from self to field + - homomorphism from ``self`` to field - - homomorphism from field to self + - homomorphism from field to ``self`` EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) - sage: S.<alpha> = R.quotient(x^3-2) + sage: S.<alpha> = R.quotient(x^3 - 2) sage: F.<a>, f, g = alpha.field_extension() sage: F Number Field in a with defining polynomial x^3 - 2 @@ -481,6 +484,7 @@ def field_extension(self, names): Over a finite field, the corresponding field extension is not a number field:: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(25,'b')['x'] sage: S.<a> = R.quo(x^3 + 2*x + 1) sage: F.<b>, g, h = a.field_extension() @@ -491,16 +495,18 @@ def field_extension(self, names): We do an example involving a relative number field:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ['x'] - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: S.<X> = K['X'] sage: Q.<b> = S.quo(X^3 + 2*X + 1) sage: F, g, h = b.field_extension('c') Another more awkward example:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ['x'] - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: S.<X> = K['X'] sage: f = (X+a)^3 + 2*(X+a) + 1 sage: f @@ -693,27 +699,29 @@ def minpoly(self): sage: R.<x> = PolynomialRing(QQ) sage: S.<a> = R.quotient(x^3 + 2*x - 5) - sage: (a+123).minpoly() + sage: (a + 123).minpoly() x^3 - 369*x^2 + 45389*x - 1861118 - sage: (a+123).matrix().minpoly() + sage: (a + 123).matrix().minpoly() x^3 - 369*x^2 + 45389*x - 1861118 One useful application of this function is to compute a minimal polynomial of a finite-field element over an intermediate extension, rather than the absolute minimal polynomial over the prime field:: + sage: # needs sage.rings.finite_rings sage: F2.<i> = GF((431,2), modulus=[1,0,1]) sage: F6.<u> = F2.extension(3) - sage: (u+1).minpoly() + sage: (u + 1).minpoly() x^6 + 425*x^5 + 19*x^4 + 125*x^3 + 189*x^2 + 239*x + 302 sage: ext = F6.over(F2) - sage: ext(u+1).minpoly() # indirect doctest + sage: ext(u + 1).minpoly() # indirect doctest x^3 + (396*i + 428)*x^2 + (80*i + 39)*x + 9*i + 178 TESTS: We make sure that the previous example works on random examples:: + sage: # needs sage.rings.finite_rings sage: p = random_prime(50) sage: K.<u> = GF((p, randrange(1,20))) sage: L.<v> = K.extension(randrange(2,20)) @@ -741,7 +749,7 @@ def norm(self): EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) - sage: S.<a> = R.quotient(x^3 -389*x^2 + 2*x - 5) + sage: S.<a> = R.quotient(x^3 - 389*x^2 + 2*x - 5) sage: a.norm() 5 """ @@ -771,9 +779,13 @@ def rational_reconstruction(self, *args, **kwargs): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(65537)[] - sage: m = x^11 + 25345*x^10 + 10956*x^9 + 13873*x^8 + 23962*x^7 + 17496*x^6 + 30348*x^5 + 7440*x^4 + 65438*x^3 + 7676*x^2 + 54266*x + 47805 - sage: f = 20437*x^10 + 62630*x^9 + 63241*x^8 + 12820*x^7 + 42171*x^6 + 63091*x^5 + 15288*x^4 + 32516*x^3 + 2181*x^2 + 45236*x + 2447 + sage: m = (x^11 + 25345*x^10 + 10956*x^9 + 13873*x^8 + 23962*x^7 + ....: + 17496*x^6 + 30348*x^5 + 7440*x^4 + 65438*x^3 + 7676*x^2 + ....: + 54266*x + 47805) + sage: f = (20437*x^10 + 62630*x^9 + 63241*x^8 + 12820*x^7 + 42171*x^6 + ....: + 63091*x^5 + 15288*x^4 + 32516*x^3 + 2181*x^2 + 45236*x + 2447) sage: f_mod_m = R.quotient(m)(f) sage: f_mod_m.rational_reconstruction() (51388*x^5 + 29141*x^4 + 59341*x^3 + 7034*x^2 + 14152*x + 23746, diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pxd b/src/sage/rings/polynomial/polynomial_rational_flint.pxd index 055d7842668..f4644f19d04 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pxd +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pxd @@ -11,7 +11,7 @@ from sage.libs.flint.types cimport fmpq_poly_t from sage.rings.polynomial.polynomial_element cimport Polynomial cdef class Polynomial_rational_flint(Polynomial): - cdef fmpq_poly_t __poly + cdef fmpq_poly_t _poly cdef Polynomial_rational_flint _new(self) cpdef _mod_(self, right) diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pyx b/src/sage/rings/polynomial/polynomial_rational_flint.pyx index 0e6970217ab..b888b31d214 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pyx @@ -22,10 +22,10 @@ AUTHOR: # http://www.gnu.org/licenses/ #***************************************************************************** -from cysignals.memory cimport check_allocarray, check_malloc, sig_free +from cysignals.memory cimport check_allocarray, sig_free from cysignals.signals cimport sig_on, sig_str, sig_off -from cpython.int cimport PyInt_AS_LONG +from cpython.long cimport PyLong_AsLong from sage.arith.long cimport pyobject_to_long from sage.libs.arb.acb cimport acb_div_fmpz @@ -53,7 +53,7 @@ from sage.rings.polynomial.polynomial_element cimport Polynomial from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint from sage.structure.parent cimport Parent -from sage.structure.element cimport Element, ModuleElement, RingElement +from sage.structure.element cimport Element from sage.structure.element import coerce_binop from sage.misc.cachefunc import cached_method @@ -155,16 +155,16 @@ cdef class Polynomial_rational_flint(Polynomial): res._parent = P res._is_gen = <char>0 if isinstance(x, int): - fmpq_poly_set_si(res.__poly, <int> x) + fmpq_poly_set_si(res._poly, <int> x) elif isinstance(x, Integer): - fmpq_poly_set_mpz(res.__poly, (<Integer> x).value) + fmpq_poly_set_mpz(res._poly, (<Integer> x).value) elif isinstance(x, Rational): - fmpq_poly_set_mpq(res.__poly, (<Rational> x).value) + fmpq_poly_set_mpq(res._poly, (<Rational> x).value) else: - fmpq_poly_set_si(res.__poly, int(x)) + fmpq_poly_set_si(res._poly, int(x)) return res @@ -177,7 +177,7 @@ cdef class Polynomial_rational_flint(Polynomial): sage: R.<t> = QQ[] sage: f = 2/3 * t - 7 #indirect doctest """ - fmpq_poly_init(self.__poly) + fmpq_poly_init(self._poly) def __dealloc__(self): """ @@ -189,15 +189,15 @@ cdef class Polynomial_rational_flint(Polynomial): sage: f = 1/3 * t sage: del f """ - fmpq_poly_clear(self.__poly) + fmpq_poly_clear(self._poly) def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): """ - Initialises the associated data for the polynomial self. + Initialises the associated data for the polynomial ``self``. INPUT: - - ``parent`` - Polynomial ring, the parent of self + - ``parent`` - Polynomial ring, the parent of ``self`` - ``x`` - Data for the new polynomial self, e.g. a polynomial, an integer, a rational, a list of rationals, a dictionary with keys the degrees and the rational coefficients, etc (default: ``None``) @@ -227,19 +227,19 @@ cdef class Polynomial_rational_flint(Polynomial): Polynomial.__init__(self, parent, is_gen=is_gen) if is_gen: - fmpq_poly_set_coeff_si(self.__poly, 1, 1) + fmpq_poly_set_coeff_si(self._poly, 1, 1) elif isinstance(x, Polynomial_rational_flint): - fmpq_poly_set(self.__poly, (<Polynomial_rational_flint> x).__poly) + fmpq_poly_set(self._poly, (<Polynomial_rational_flint> x)._poly) elif isinstance(x, int): - fmpq_poly_set_si(self.__poly, <int> x) + fmpq_poly_set_si(self._poly, <int> x) elif isinstance(x, Integer): - fmpq_poly_set_mpz(self.__poly, (<Integer> x).value) + fmpq_poly_set_mpz(self._poly, (<Integer> x).value) elif isinstance(x, Rational): - fmpq_poly_set_mpq(self.__poly, (<Rational> x).value) + fmpq_poly_set_mpq(self._poly, (<Rational> x).value) elif isinstance(x, list) or isinstance(x, tuple): @@ -257,7 +257,7 @@ cdef class Polynomial_rational_flint(Polynomial): for deg from 0 <= deg < n: mpq_init(L2[deg]) mpq_set(L2[deg], (<Rational> L1[deg]).value) - fmpq_poly_set_array_mpq(self.__poly, L2, n) + fmpq_poly_set_array_mpq(self._poly, L2, n) for deg from 0 <= deg < n: mpq_clear(L2[deg]) sig_free(L2) @@ -266,13 +266,13 @@ cdef class Polynomial_rational_flint(Polynomial): # deg = 0 # for e in x: # c = Rational(e) -# fmpq_poly_set_coeff_mpq(self.__poly, deg, c.value) +# fmpq_poly_set_coeff_mpq(self._poly, deg, c.value) # deg += 1 elif isinstance(x, dict): for deg, e in x.iteritems(): c = Rational(e) - fmpq_poly_set_coeff_mpq(self.__poly, deg, c.value) + fmpq_poly_set_coeff_mpq(self._poly, deg, c.value) elif isinstance(x, pari_gen): k = self._parent.base_ring() @@ -281,7 +281,7 @@ cdef class Polynomial_rational_flint(Polynomial): is_gen=False, construct=construct) elif isinstance(x, Polynomial_integer_dense_flint): - fmpq_poly_set_fmpz_poly(self.__poly, (<Polynomial_integer_dense_flint>x).__poly) + fmpq_poly_set_fmpz_poly(self._poly, (<Polynomial_integer_dense_flint>x)._poly) elif isinstance(x, Polynomial): k = self._parent.base_ring() @@ -319,7 +319,7 @@ cdef class Polynomial_rational_flint(Polynomial): def __copy__(self): """ - Return a copy of self. + Return a copy of ``self``. TESTS:: @@ -329,12 +329,12 @@ cdef class Polynomial_rational_flint(Polynomial): True """ cdef Polynomial_rational_flint res = self._new() - fmpq_poly_set(res.__poly, self.__poly) + fmpq_poly_set(res._poly, self._poly) return res def _singular_(self, singular=singular_default): """ - Return a Singular representation of self. + Return a Singular representation of ``self``. INPUT: @@ -364,7 +364,7 @@ cdef class Polynomial_rational_flint(Polynomial): sage: g.list() [] """ - cdef unsigned long length = fmpq_poly_length(self.__poly) + cdef unsigned long length = fmpq_poly_length(self._poly) return [self.get_unsafe(n) for n in range(length)] ########################################################################### @@ -375,7 +375,7 @@ cdef class Polynomial_rational_flint(Polynomial): """ Return the degree of ``self``. - By convention, the degree of the zero polynomial is -1. + By convention, the degree of the zero polynomial is `-1`. EXAMPLES:: @@ -392,7 +392,7 @@ cdef class Polynomial_rational_flint(Polynomial): sage: type(f.degree()) <class 'sage.rings.integer.Integer'> """ - return smallInteger(fmpq_poly_degree(self.__poly)) + return smallInteger(fmpq_poly_degree(self._poly)) cdef get_unsafe(self, Py_ssize_t n): """ @@ -413,12 +413,12 @@ cdef class Polynomial_rational_flint(Polynomial): 1/2*t^2 + t + 1 """ cdef Rational z = Rational.__new__(Rational) - fmpq_poly_get_coeff_mpq(z.value, self.__poly, n) + fmpq_poly_get_coeff_mpq(z.value, self._poly, n) return z cpdef _unsafe_mutate(self, unsigned long n, value): """ - Sets the `n`-th coefficient of self to value. + Sets the `n`-th coefficient of ``self`` to value. TESTS:: @@ -434,24 +434,24 @@ cdef class Polynomial_rational_flint(Polynomial): rely on this convention. This method should be used only with the utmost care. """ - cdef bint do_sig = _do_sig(self.__poly) + cdef bint do_sig = _do_sig(self._poly) if isinstance(value, int): if do_sig: sig_str("FLINT exception") - fmpq_poly_set_coeff_si(self.__poly, n, value) + fmpq_poly_set_coeff_si(self._poly, n, value) if do_sig: sig_off() elif isinstance(value, Integer): if do_sig: sig_str("FLINT exception") - fmpq_poly_set_coeff_mpz(self.__poly, n, (<Integer> value).value) + fmpq_poly_set_coeff_mpz(self._poly, n, (<Integer> value).value) if do_sig: sig_off() elif isinstance(value, Rational): if do_sig: sig_str("FLINT exception") - fmpq_poly_set_coeff_mpq(self.__poly, n, (<Rational> value).value) + fmpq_poly_set_coeff_mpq(self._poly, n, (<Rational> value).value) if do_sig: sig_off() else: value = Rational(value) if do_sig: sig_str("FLINT exception") - fmpq_poly_set_coeff_mpq(self.__poly, n, (<Rational> value).value) + fmpq_poly_set_coeff_mpq(self._poly, n, (<Rational> value).value) if do_sig: sig_off() def __call__(self, *x, **kwds): @@ -491,7 +491,6 @@ cdef class Polynomial_rational_flint(Polynomial): """ cdef Polynomial_rational_flint f cdef Rational r - cdef mpz_t tmpz cdef fmpz_t tmpfz cdef fmpq_t tmpfq cdef RealBall arb_a, arb_z @@ -502,20 +501,20 @@ cdef class Polynomial_rational_flint(Polynomial): if isinstance(a, Polynomial_rational_flint): f = (<Polynomial_rational_flint> a)._new() sig_str("FLINT exception") - fmpq_poly_compose(f.__poly, self.__poly, - (<Polynomial_rational_flint> a).__poly) + fmpq_poly_compose(f._poly, self._poly, + (<Polynomial_rational_flint> a)._poly) sig_off() return f elif isinstance(a, Rational): r = Rational.__new__(Rational) sig_str("FLINT exception") - fmpq_poly_evaluate_mpq(r.value, self.__poly, (<Rational> a).value) + fmpq_poly_evaluate_mpq(r.value, self._poly, (<Rational> a).value) sig_off() return r elif isinstance(a, Integer): r = Rational.__new__(Rational) sig_str("FLINT exception") - fmpq_poly_evaluate_mpz(r.value, self.__poly, (<Integer> a).value) + fmpq_poly_evaluate_mpz(r.value, self._poly, (<Integer> a).value) sig_off() return r elif isinstance(a, int): @@ -523,8 +522,8 @@ cdef class Polynomial_rational_flint(Polynomial): sig_str("FLINT exception") fmpz_init(tmpfz) fmpq_init(tmpfq) - fmpz_set_si(tmpfz, PyInt_AS_LONG(a)) - fmpq_poly_evaluate_fmpz(tmpfq, self.__poly, tmpfz) + fmpz_set_si(tmpfz, PyLong_AsLong(a)) + fmpq_poly_evaluate_fmpz(tmpfq, self._poly, tmpfz) fmpq_get_mpq(r.value, tmpfq) fmpq_clear(tmpfq) fmpz_clear(tmpfz) @@ -534,18 +533,18 @@ cdef class Polynomial_rational_flint(Polynomial): arb_a = <RealBall> a arb_z = arb_a._new() sig_on() - _arb_fmpz_poly_evaluate_arb(arb_z.value, fmpq_poly_numref(self.__poly), - fmpq_poly_length(self.__poly), arb_a.value, arb_a._parent._prec) - arb_div_fmpz(arb_z.value, arb_z.value, fmpq_poly_denref(self.__poly), arb_a._parent._prec) + _arb_fmpz_poly_evaluate_arb(arb_z.value, fmpq_poly_numref(self._poly), + fmpq_poly_length(self._poly), arb_a.value, arb_a._parent._prec) + arb_div_fmpz(arb_z.value, arb_z.value, fmpq_poly_denref(self._poly), arb_a._parent._prec) sig_off() return arb_z if isinstance(a, ComplexBall): acb_a = <ComplexBall> a acb_z = acb_a._new() sig_on() - _arb_fmpz_poly_evaluate_acb(acb_z.value, fmpq_poly_numref(self.__poly), - fmpq_poly_length(self.__poly), acb_a.value, acb_a._parent._prec) - acb_div_fmpz(acb_z.value, acb_z.value, fmpq_poly_denref(self.__poly), acb_a._parent._prec) + _arb_fmpz_poly_evaluate_acb(acb_z.value, fmpq_poly_numref(self._poly), + fmpq_poly_length(self._poly), acb_a.value, acb_a._parent._prec) + acb_div_fmpz(acb_z.value, acb_z.value, fmpq_poly_denref(self._poly), acb_a._parent._prec) sig_off() return acb_z @@ -557,7 +556,7 @@ cdef class Polynomial_rational_flint(Polynomial): INPUT: - - ``n`` - The power of `t` modulo which self is truncated + - ``n`` - The power of `t` modulo which ``self`` is truncated EXAMPLES:: @@ -571,14 +570,14 @@ cdef class Polynomial_rational_flint(Polynomial): cdef Polynomial_rational_flint res cdef bint do_sig - if (n >= fmpq_poly_length(self.__poly)): + if (n >= fmpq_poly_length(self._poly)): return self else: res = self._new() if n > 0: - do_sig = _do_sig(self.__poly) + do_sig = _do_sig(self._poly) if do_sig: sig_str("FLINT exception") - fmpq_poly_get_slice(res.__poly, self.__poly, 0, n) + fmpq_poly_get_slice(res._poly, self._poly, 0, n) if do_sig: sig_off() return res @@ -603,7 +602,7 @@ cdef class Polynomial_rational_flint(Polynomial): sage: f.reverse() t^4 + t^3 + 1/2*t^2 + 1/3*t + 1/4 - Next, an example we the returned polynomial has lower degree because + Next, an example where the returned polynomial has lower degree because the original polynomial has low coefficients equal to zero:: sage: R.<t> = QQ[] @@ -612,7 +611,7 @@ cdef class Polynomial_rational_flint(Polynomial): 3/4*t^5 + 6 The next example illustrates the passing of a value for ``degree`` less - than the length of self, notationally resulting in truncation prior to + than the length of ``self``, notationally resulting in truncation prior to reversing:: sage: R.<t> = QQ[] @@ -621,7 +620,7 @@ cdef class Polynomial_rational_flint(Polynomial): t^2 + t + 1/2 Now we illustrate the passing of a value for ``degree`` greater than - the length of self, notationally resulting in zero padding at the top + the length of ``self``, notationally resulting in zero padding at the top end prior to reversing:: sage: R.<t> = QQ[] @@ -665,7 +664,7 @@ cdef class Polynomial_rational_flint(Polynomial): cdef bint do_sig if degree is None: - len = fmpq_poly_length(self.__poly) + len = fmpq_poly_length(self._poly) else: try: len = <unsigned long> (degree + 1) @@ -673,15 +672,15 @@ cdef class Polynomial_rational_flint(Polynomial): raise ValueError('degree must be convertible to long') res = self._new() - do_sig = _do_sig(self.__poly) + do_sig = _do_sig(self._poly) if do_sig: sig_str("FLINT exception") - fmpq_poly_reverse(res.__poly, self.__poly, len) + fmpq_poly_reverse(res._poly, self._poly, len) if do_sig: sig_off() return res def revert_series(self, n): r""" - Return a polynomial `f` such that `f(self(x)) = self(f(x)) = x mod x^n`. + Return a polynomial `f` such that ``f(self(x)) = self(f(x)) = x mod x^n``. EXAMPLES:: @@ -710,7 +709,7 @@ cdef class Polynomial_rational_flint(Polynomial): raise ValueError("self must have constant coefficient 0 and a unit for coefficient {}^1".format(self.parent().gen())) sig_str("FLINT exception") - fmpq_poly_revert_series(res.__poly, self.__poly, m) + fmpq_poly_revert_series(res._poly, self._poly, m) sig_off() return res @@ -721,7 +720,7 @@ cdef class Polynomial_rational_flint(Polynomial): cpdef bint is_zero(self) except -1: """ - Return whether or not self is the zero polynomial. + Return whether or not ``self`` is the zero polynomial. EXAMPLES:: @@ -732,7 +731,7 @@ cdef class Polynomial_rational_flint(Polynomial): sage: R(0).is_zero() True """ - return fmpq_poly_is_zero(self.__poly) + return fmpq_poly_is_zero(self._poly) cpdef bint is_one(self) except -1: r""" @@ -752,11 +751,11 @@ cdef class Polynomial_rational_flint(Polynomial): sage: R([1,1]).is_one() False """ - return fmpq_poly_is_one(self.__poly) + return fmpq_poly_is_one(self._poly) def __bool__(self): """ - Return whether or not self is non-zero. + Return whether or not ``self`` is non-zero. EXAMPLES:: @@ -767,7 +766,7 @@ cdef class Polynomial_rational_flint(Polynomial): sage: bool(R(0)) False """ - return not fmpq_poly_is_zero(self.__poly) + return not fmpq_poly_is_zero(self._poly) ########################################################################### # Shifting # @@ -795,20 +794,20 @@ cdef class Polynomial_rational_flint(Polynomial): cdef Polynomial_rational_flint res cdef bint do_sig - if k == 0 or fmpq_poly_is_zero(f.__poly): + if k == 0 or fmpq_poly_is_zero(f._poly): return self else: res = f._new() - do_sig = fmpq_poly_length(f.__poly) > 5000 or n > 5000 + do_sig = fmpq_poly_length(f._poly) > 5000 or n > 5000 if do_sig: sig_str("FLINT exception") - fmpq_poly_shift_left(res.__poly, f.__poly, k) + fmpq_poly_shift_left(res._poly, f._poly, k) if do_sig: sig_off() return res def __rshift__(self, n): """ - Notationally returns the quotient of Euclidean division of self + Notationally returns the quotient of Euclidean division of ``self`` by `t^n`. EXAMPLES:: @@ -823,14 +822,14 @@ cdef class Polynomial_rational_flint(Polynomial): cdef Polynomial_rational_flint res cdef bint do_sig - if k == 0 or fmpq_poly_is_zero(f.__poly): + if k == 0 or fmpq_poly_is_zero(f._poly): return self else: res = f._new() - do_sig = _do_sig(f.__poly) + do_sig = _do_sig(f._poly) if do_sig: sig_str("FLINT exception") - fmpq_poly_shift_right(res.__poly, f.__poly, k) + fmpq_poly_shift_right(res._poly, f._poly, k) if do_sig: sig_off() return res @@ -859,10 +858,10 @@ cdef class Polynomial_rational_flint(Polynomial): """ cdef Polynomial_rational_flint op2 = <Polynomial_rational_flint> right cdef Polynomial_rational_flint res = self._new() - cdef bint do_sig = _do_sig(self.__poly) or _do_sig(op2.__poly) + cdef bint do_sig = _do_sig(self._poly) or _do_sig(op2._poly) if do_sig: sig_str("FLINT exception") - fmpq_poly_add(res.__poly, self.__poly, op2.__poly) + fmpq_poly_add(res._poly, self._poly, op2._poly) if do_sig: sig_off() return res @@ -887,10 +886,10 @@ cdef class Polynomial_rational_flint(Polynomial): """ cdef Polynomial_rational_flint op2 = <Polynomial_rational_flint> right cdef Polynomial_rational_flint res = self._new() - cdef bint do_sig = _do_sig(self.__poly) or _do_sig(op2.__poly) + cdef bint do_sig = _do_sig(self._poly) or _do_sig(op2._poly) if do_sig: sig_str("FLINT exception") - fmpq_poly_sub(res.__poly, self.__poly, op2.__poly) + fmpq_poly_sub(res._poly, self._poly, op2._poly) if do_sig: sig_off() return res @@ -913,20 +912,20 @@ cdef class Polynomial_rational_flint(Polynomial): True """ cdef Polynomial_rational_flint res = self._new() - cdef bint do_sig = _do_sig(self.__poly) + cdef bint do_sig = _do_sig(self._poly) if do_sig: sig_str("FLINT exception") - fmpq_poly_neg(res.__poly, self.__poly) + fmpq_poly_neg(res._poly, self._poly) if do_sig: sig_off() return res @coerce_binop def quo_rem(self, right): - """ + r""" Return the quotient and remainder of the Euclidean division of - self and right. + ``self`` and ``right``. - Raises a ZerodivisionError if right is zero. + Raises a :class:`ZeroDivisionError` if ``right`` is zero. EXAMPLES:: @@ -946,17 +945,17 @@ cdef class Polynomial_rational_flint(Polynomial): cdef Polynomial_rational_flint rr = self._new() sig_str("FLINT exception") - fmpq_poly_divrem(qq.__poly, rr.__poly, self.__poly, - (<Polynomial_rational_flint> right).__poly) + fmpq_poly_divrem(qq._poly, rr._poly, self._poly, + (<Polynomial_rational_flint> right)._poly) sig_off() return qq, rr @coerce_binop def gcd(self, right): - """ - Return the (monic) greatest common divisor of self and right. + r""" + Return the (monic) greatest common divisor of ``self`` and ``right``. - Corner cases: if self and right are both zero, returns zero. If + Corner cases: if ``self`` and ``right`` are both zero, returns zero. If only one of them is zero, returns the other polynomial, up to normalisation. @@ -975,18 +974,18 @@ cdef class Polynomial_rational_flint(Polynomial): cdef Polynomial_rational_flint res = self._new() sig_str("FLINT exception") - fmpq_poly_gcd(res.__poly, self.__poly, - (<Polynomial_rational_flint> right).__poly) + fmpq_poly_gcd(res._poly, self._poly, + (<Polynomial_rational_flint> right)._poly) sig_off() return res @coerce_binop def lcm(self, right): - """ - Return the monic (or zero) least common multiple of self and right. + r""" + Return the monic (or zero) least common multiple of ``self`` and ``right``. - Corner cases: if either of self and right are zero, returns zero. - This behaviour is ensures that the relation lcm(a,b) gcd(a,b) == a b + Corner cases: if either of ``self`` and ``right`` are zero, returns zero. + This behaviour is ensures that the relation `\lcm(a,b)\cdot \gcd(a,b) = a\cdot b` holds up to multiplication by rationals. EXAMPLES:: @@ -1002,21 +1001,21 @@ cdef class Polynomial_rational_flint(Polynomial): cdef Polynomial_rational_flint res = self._new() sig_str("FLINT exception") - fmpq_poly_lcm(res.__poly, self.__poly, - (<Polynomial_rational_flint> right).__poly) + fmpq_poly_lcm(res._poly, self._poly, + (<Polynomial_rational_flint> right)._poly) sig_off() return res @coerce_binop def xgcd(self, right): - """ - Return polynomials d, s, and t such that d == s * self + t * right, - where d is the (monic) greatest common divisor of self and right. - The choice of s and t is not specified any further. + r""" + Return polynomials `d`, `s`, and `t` such that ``d == s * self + t * right``, + where `d` is the (monic) greatest common divisor of ``self`` and ``right``. + The choice of `s` and `t` is not specified any further. - Corner cases: if self and right are zero, returns zero polynomials. - Otherwise, if only self is zero, returns (d, s, t) = (right, 0, 1) up - to normalisation, and similarly if only right is zero. + Corner cases: if ``self`` and ``right`` are zero, returns zero polynomials. + Otherwise, if only ``self`` is zero, returns ``(d, s, t) = (right, 0, 1)`` up + to normalisation, and similarly if only ``right`` is zero. EXAMPLES:: @@ -1044,13 +1043,13 @@ cdef class Polynomial_rational_flint(Polynomial): cdef Polynomial_rational_flint t = self._new() sig_str("FLINT exception") - fmpq_poly_xgcd(d.__poly, s.__poly, t.__poly, self.__poly, (<Polynomial_rational_flint>right).__poly) + fmpq_poly_xgcd(d._poly, s._poly, t._poly, self._poly, (<Polynomial_rational_flint>right)._poly) sig_off() return d, s, t cpdef _mul_(self, right): """ - Return the product of self and right. + Return the product of ``self`` and ``right``. EXAMPLES:: @@ -1070,10 +1069,10 @@ cdef class Polynomial_rational_flint(Polynomial): """ cdef Polynomial_rational_flint op2 = <Polynomial_rational_flint> right cdef Polynomial_rational_flint res = self._new() - cdef bint do_sig = _do_sig(self.__poly) or _do_sig(op2.__poly) + cdef bint do_sig = _do_sig(self._poly) or _do_sig(op2._poly) if do_sig: sig_str("FLINT exception") - fmpq_poly_mul(res.__poly, self.__poly, op2.__poly) + fmpq_poly_mul(res._poly, self._poly, op2._poly) if do_sig: sig_off() return res @@ -1104,19 +1103,19 @@ cdef class Polynomial_rational_flint(Polynomial): """ cdef Polynomial_rational_flint op2 = <Polynomial_rational_flint> right cdef Polynomial_rational_flint res = self._new() - cdef bint do_sig = _do_sig(self.__poly) or _do_sig(op2.__poly) + cdef bint do_sig = _do_sig(self._poly) or _do_sig(op2._poly) if n <= 0: raise ValueError("n must be > 0") if do_sig: sig_str("FLINT exception") - fmpq_poly_mullow(res.__poly, self.__poly, op2.__poly, n) + fmpq_poly_mullow(res._poly, self._poly, op2._poly, n) if do_sig: sig_off() return res cpdef _rmul_(self, Element left): r""" - Return left * self, where left is a rational number. + Return ``left * self``, where ``left`` is a rational number. EXAMPLES:: @@ -1126,17 +1125,17 @@ cdef class Polynomial_rational_flint(Polynomial): 9*t^3 - 6*t + 2 """ cdef Polynomial_rational_flint res = self._new() - cdef bint do_sig = _do_sig(self.__poly) + cdef bint do_sig = _do_sig(self._poly) if do_sig: sig_str("FLINT exception") - fmpq_poly_scalar_mul_mpq(res.__poly, self.__poly, + fmpq_poly_scalar_mul_mpq(res._poly, self._poly, (<Rational> left).value) if do_sig: sig_off() return res cpdef _lmul_(self, Element right): r""" - Return self * right, where right is a rational number. + Return ``self * right``, where ``right`` is a rational number. EXAMPLES:: @@ -1146,10 +1145,10 @@ cdef class Polynomial_rational_flint(Polynomial): 9*t^3 - 6*t + 2 """ cdef Polynomial_rational_flint res = self._new() - cdef bint do_sig = _do_sig(self.__poly) + cdef bint do_sig = _do_sig(self._poly) if do_sig: sig_str("FLINT exception") - fmpq_poly_scalar_mul_mpq(res.__poly, self.__poly, + fmpq_poly_scalar_mul_mpq(res._poly, self._poly, (<Rational> right).value) if do_sig: sig_off() return res @@ -1273,33 +1272,33 @@ cdef class Polynomial_rational_flint(Polynomial): num = r.numerator() den = r.denominator() - if fmpq_poly_degree(self.__poly) == 0: + if fmpq_poly_degree(self._poly) == 0: return self.parent()(self[0].nth_root(den) ** num) return self.nth_root(den) ** num else: if n < 0: - if fmpq_poly_is_zero(self.__poly): + if fmpq_poly_is_zero(self._poly): raise ZeroDivisionError("negative exponent in power of zero") res = self._new() sig_str("FLINT exception") - fmpq_poly_pow(res.__poly, self.__poly, -n) + fmpq_poly_pow(res._poly, self._poly, -n) sig_off() return ~res else: res = self._new() sig_str("FLINT exception") if self._is_gen: - fmpq_poly_set_coeff_si(res.__poly, n, 1) + fmpq_poly_set_coeff_si(res._poly, n, 1) else: - fmpq_poly_pow(res.__poly, self.__poly, n) + fmpq_poly_pow(res._poly, self._poly, n) sig_off() return res def __floordiv__(Polynomial_rational_flint self, right): """ - Return the quotient of self and right obtain by Euclidean division. + Return the quotient of ``self`` and ``right`` obtained by Euclidean division. EXAMPLES:: @@ -1329,10 +1328,10 @@ cdef class Polynomial_rational_flint(Polynomial): if not isinstance(right, Polynomial_rational_flint): if right in QQ: res = self._new() - do_sig = _do_sig(self.__poly) + do_sig = _do_sig(self._poly) if do_sig: sig_str("FLINT exception") - fmpq_poly_scalar_div_mpq(res.__poly, self.__poly, + fmpq_poly_scalar_div_mpq(res._poly, self._poly, (<Rational> QQ(right)).value) if do_sig: sig_off() return res @@ -1341,8 +1340,8 @@ cdef class Polynomial_rational_flint(Polynomial): res = self._new() sig_str("FLINT exception") - fmpq_poly_div(res.__poly, self.__poly, - (<Polynomial_rational_flint>right).__poly) + fmpq_poly_div(res._poly, self._poly, + (<Polynomial_rational_flint>right)._poly) sig_off() return res @@ -1382,21 +1381,21 @@ cdef class Polynomial_rational_flint(Polynomial): """ if prec <= 0: raise ValueError("the precision must be positive, got {}".format(prec)) - if fmpq_poly_degree(self.__poly) == -1 or \ - fmpz_is_zero(fmpq_poly_numref(self.__poly)): + if fmpq_poly_degree(self._poly) == -1 or \ + fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term is zero") cdef Polynomial_rational_flint res = self._new() if prec <= 0: return res sig_on() - fmpq_poly_inv_series(res.__poly, self.__poly, prec) + fmpq_poly_inv_series(res._poly, self._poly, prec) sig_off() return res cpdef _mod_(self, right): """ - Return the remainder of self and right obtain by Euclidean division. + Return the remainder of ``self`` and ``right`` obtain by Euclidean division. EXAMPLES:: @@ -1424,8 +1423,8 @@ cdef class Polynomial_rational_flint(Polynomial): res = self._new() sig_str("FLINT exception") - fmpq_poly_rem(res.__poly, self.__poly, - (<Polynomial_rational_flint>right).__poly) + fmpq_poly_rem(res._poly, self._poly, + (<Polynomial_rational_flint>right)._poly) sig_off() return res @@ -1435,7 +1434,7 @@ cdef class Polynomial_rational_flint(Polynomial): def numerator(self): """ - Return the numerator of self. + Return the numerator of ``self``. Representing self as the quotient of an integer polynomial and a positive integer denominator (coprime to the content of the @@ -1454,13 +1453,13 @@ cdef class Polynomial_rational_flint(Polynomial): Polynomial_integer_dense_flint.__init__(num, parent, x=None, check=False, is_gen=False, construct=False) sig_str("FLINT exception") - fmpq_poly_get_numerator(num.__poly, self.__poly) + fmpq_poly_get_numerator(num._poly, self._poly) sig_off() return num def denominator(self): """ - Return the denominator of self. + Return the denominator of ``self``. EXAMPLES:: @@ -1470,10 +1469,10 @@ cdef class Polynomial_rational_flint(Polynomial): 3 """ cdef Integer den = Integer.__new__(Integer) - if fmpq_poly_denref(self.__poly) is NULL: + if fmpq_poly_denref(self._poly) is NULL: mpz_set_ui(den.value, 1) else: - fmpz_get_mpz(den.value, <fmpz *> fmpq_poly_denref(self.__poly)) + fmpz_get_mpz(den.value, <fmpz *> fmpq_poly_denref(self._poly)) return den def _derivative(self, var = None): @@ -1507,8 +1506,8 @@ cdef class Polynomial_rational_flint(Polynomial): Check that :trac:`28187` is fixed:: - sage: x = var("x") - sage: f._derivative(x) + sage: x = var("x") # needs sage.symbolic + sage: f._derivative(x) # needs sage.symbolic 4*x^3 - 1 """ cdef Polynomial_rational_flint der @@ -1518,16 +1517,16 @@ cdef class Polynomial_rational_flint(Polynomial): raise ValueError("cannot differentiate with respect to {}".format(var)) der = self._new() - do_sig = _do_sig(self.__poly) + do_sig = _do_sig(self._poly) if do_sig: sig_str("FLINT exception") - fmpq_poly_derivative(der.__poly, self.__poly) + fmpq_poly_derivative(der._poly, self._poly) if do_sig: sig_off() return der def real_root_intervals(self): """ - Return isolating intervals for the real roots of self. + Return isolating intervals for the real roots of ``self``. EXAMPLES: @@ -1545,10 +1544,10 @@ cdef class Polynomial_rational_flint(Polynomial): @coerce_binop def resultant(Polynomial_rational_flint self, right): r""" - Return the resultant of self and right. + Return the resultant of ``self`` and ``right``. - Enumerating the roots over `\QQ` as `r_1, \cdots, r_m` and - `s_1, \cdots, s_n` and letting `x` and `y` denote the leading + Enumerating the roots over `\QQ` as `r_1, \dots, r_m` and + `s_1, \dots, s_n` and letting `x` and `y` denote the leading coefficients of `f` and `g`, the resultant of the two polynomials is defined by @@ -1575,8 +1574,8 @@ cdef class Polynomial_rational_flint(Polynomial): cdef fmpq_t t fmpq_init(t) sig_str("FLINT exception") - fmpq_poly_resultant(t, self.__poly, - (<Polynomial_rational_flint>right).__poly) + fmpq_poly_resultant(t, self._poly, + (<Polynomial_rational_flint>right)._poly) fmpq_get_mpq(res.value, t) sig_off() fmpq_clear(t) @@ -1610,7 +1609,7 @@ cdef class Polynomial_rational_flint(Polynomial): False sage: R(-1/2).is_irreducible() False - sage: (t+1).is_irreducible() + sage: (t + 1).is_irreducible() True Test that caching works:: @@ -1624,7 +1623,7 @@ cdef class Polynomial_rational_flint(Polynomial): """ cdef Polynomial_integer_dense_flint primitive - cdef unsigned long length = fmpq_poly_length(self.__poly) + cdef unsigned long length = fmpq_poly_length(self._poly) if length < 2: return False @@ -1637,8 +1636,8 @@ cdef class Polynomial_rational_flint(Polynomial): x=None, check=True, is_gen=False, construct=False) sig_str("FLINT exception") - fmpq_poly_get_numerator(primitive.__poly, self.__poly) - fmpz_poly_primitive_part(primitive.__poly, primitive.__poly) + fmpq_poly_get_numerator(primitive._poly, self._poly) + fmpz_poly_primitive_part(primitive._poly, primitive._poly) sig_off() return primitive.is_irreducible() @@ -1670,14 +1669,14 @@ cdef class Polynomial_rational_flint(Polynomial): ... ValueError: constant term should be 1 in order to take logarithm """ - if fmpq_poly_degree(self.__poly) == -1 or \ - fmpz_cmp(fmpq_poly_numref(self.__poly), - fmpq_poly_denref(self.__poly)): + if fmpq_poly_degree(self._poly) == -1 or \ + fmpz_cmp(fmpq_poly_numref(self._poly), + fmpq_poly_denref(self._poly)): raise ValueError("constant term should be 1 in order to take logarithm") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_log_series(res.__poly, self.__poly, prec) + fmpq_poly_log_series(res._poly, self._poly, prec) sig_off() return res @@ -1704,14 +1703,14 @@ cdef class Polynomial_rational_flint(Polynomial): sage: _.parent() Univariate Polynomial Ring in x over Rational Field """ - if fmpq_poly_degree(self.__poly) == -1: + if fmpq_poly_degree(self._poly) == -1: return self._parent.one() - elif not fmpz_is_zero(fmpq_poly_numref(self.__poly)): + elif not fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term should be 0 in order to take exponential") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_exp_series(res.__poly, self.__poly, prec) + fmpq_poly_exp_series(res._poly, self._poly, prec) sig_off() return res @@ -1738,14 +1737,14 @@ cdef class Polynomial_rational_flint(Polynomial): sage: _.parent() Univariate Polynomial Ring in x over Rational Field """ - if fmpq_poly_degree(self.__poly) == -1: + if fmpq_poly_degree(self._poly) == -1: return self._parent.zero() - elif not fmpz_is_zero(fmpq_poly_numref(self.__poly)): + elif not fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term should be 0 in order to take arctangent") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_atan_series(res.__poly, self.__poly, prec) + fmpq_poly_atan_series(res._poly, self._poly, prec) sig_off() return res @@ -1769,14 +1768,14 @@ cdef class Polynomial_rational_flint(Polynomial): sage: _.parent() Univariate Polynomial Ring in x over Rational Field """ - if fmpq_poly_degree(self.__poly) == -1: + if fmpq_poly_degree(self._poly) == -1: return self._parent.zero() - elif not fmpz_is_zero(fmpq_poly_numref(self.__poly)): + elif not fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term should be 0 in order to take hyperbolic arctangent") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_atanh_series(res.__poly, self.__poly, prec) + fmpq_poly_atanh_series(res._poly, self._poly, prec) sig_off() return res @@ -1803,14 +1802,14 @@ cdef class Polynomial_rational_flint(Polynomial): sage: _.parent() Univariate Polynomial Ring in x over Rational Field """ - if fmpq_poly_degree(self.__poly) == -1: + if fmpq_poly_degree(self._poly) == -1: return self._parent.zero() - elif not fmpz_is_zero(fmpq_poly_numref(self.__poly)): + elif not fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term should be 0 in order to take arcsine") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_asin_series(res.__poly, self.__poly, prec) + fmpq_poly_asin_series(res._poly, self._poly, prec) sig_off() return res @@ -1838,14 +1837,14 @@ cdef class Polynomial_rational_flint(Polynomial): sage: _.parent() Univariate Polynomial Ring in x over Rational Field """ - if fmpq_poly_degree(self.__poly) == -1: + if fmpq_poly_degree(self._poly) == -1: return self._parent.zero() - elif not fmpz_is_zero(fmpq_poly_numref(self.__poly)): + elif not fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term should be 0 in order to take hyperbolic arcsine") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_asinh_series(res.__poly, self.__poly, prec) + fmpq_poly_asinh_series(res._poly, self._poly, prec) sig_off() return res @@ -1872,14 +1871,14 @@ cdef class Polynomial_rational_flint(Polynomial): sage: _.parent() Univariate Polynomial Ring in x over Rational Field """ - if fmpq_poly_degree(self.__poly) == -1: + if fmpq_poly_degree(self._poly) == -1: return self._parent.zero() - elif not fmpz_is_zero(fmpq_poly_numref(self.__poly)): + elif not fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term should be 0 in order to take tangent") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_tan_series(res.__poly, self.__poly, prec) + fmpq_poly_tan_series(res._poly, self._poly, prec) sig_off() return res @@ -1906,14 +1905,14 @@ cdef class Polynomial_rational_flint(Polynomial): sage: _.parent() Univariate Polynomial Ring in x over Rational Field """ - if fmpq_poly_degree(self.__poly) == -1: + if fmpq_poly_degree(self._poly) == -1: return self._parent.zero() - elif not fmpz_is_zero(fmpq_poly_numref(self.__poly)): + elif not fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term should be 0 in order to take sine") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_sin_series(res.__poly, self.__poly, prec) + fmpq_poly_sin_series(res._poly, self._poly, prec) sig_off() return res @@ -1938,14 +1937,14 @@ cdef class Polynomial_rational_flint(Polynomial): sage: _.parent() Univariate Polynomial Ring in x over Rational Field """ - if fmpq_poly_degree(self.__poly) == -1: + if fmpq_poly_degree(self._poly) == -1: return self._parent.zero() - elif not fmpz_is_zero(fmpq_poly_numref(self.__poly)): + elif not fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term should be 0 in order to take cosine") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_cos_series(res.__poly, self.__poly, prec) + fmpq_poly_cos_series(res._poly, self._poly, prec) sig_off() return res @@ -1970,14 +1969,14 @@ cdef class Polynomial_rational_flint(Polynomial): sage: _.parent() Univariate Polynomial Ring in x over Rational Field """ - if fmpq_poly_degree(self.__poly) == -1: + if fmpq_poly_degree(self._poly) == -1: return self._parent.zero() - elif not fmpz_is_zero(fmpq_poly_numref(self.__poly)): + elif not fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term should be 0 in order to take hyperbolic sine") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_sinh_series(res.__poly, self.__poly, prec) + fmpq_poly_sinh_series(res._poly, self._poly, prec) sig_off() return res @@ -2008,14 +2007,14 @@ cdef class Polynomial_rational_flint(Polynomial): sage: _.parent() Univariate Polynomial Ring in x over Rational Field """ - if fmpq_poly_degree(self.__poly) == -1: + if fmpq_poly_degree(self._poly) == -1: return self._parent.one() - elif not fmpz_is_zero(fmpq_poly_numref(self.__poly)): + elif not fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term should be 0 in order to take hyperbolic cosine") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_cosh_series(res.__poly, self.__poly, prec) + fmpq_poly_cosh_series(res._poly, self._poly, prec) sig_off() return res @@ -2041,14 +2040,14 @@ cdef class Polynomial_rational_flint(Polynomial): sage: _.parent() Univariate Polynomial Ring in x over Rational Field """ - if fmpq_poly_degree(self.__poly) == -1: + if fmpq_poly_degree(self._poly) == -1: return self._parent.zero() - elif not fmpz_is_zero(fmpq_poly_numref(self.__poly)): + elif not fmpz_is_zero(fmpq_poly_numref(self._poly)): raise ValueError("constant term should be 0 in order to take hyperbolic tangent") cdef Polynomial_rational_flint res = self._new() sig_on() - fmpq_poly_tanh_series(res.__poly, self.__poly, prec) + fmpq_poly_tanh_series(res._poly, self._poly, prec) sig_off() return res @@ -2067,7 +2066,7 @@ cdef class Polynomial_rational_flint(Polynomial): - ``pari_group`` - bool (default: ``False``); if ``True`` instead return the Galois group as a PARI group. This has a useful label in it, and may be slightly faster since it doesn't require looking - up a group in Gap. To get a permutation group from a PARI + up a group in GAP. To get a permutation group from a PARI group ``P``, type ``PermutationGroup(P)``. - ``algorithm`` - ``'pari'``, ``'gap'``, ``'kash'``, ``'magma'`` (default: @@ -2075,9 +2074,7 @@ cdef class Polynomial_rational_flint(Polynomial): ``'gap'``, for degrees from 12 to 15; ``'kash'``, for degrees from 16 or more). - OUTPUT: - - - Galois group + OUTPUT: Galois group ALGORITHM: @@ -2163,7 +2160,9 @@ cdef class Polynomial_rational_flint(Polynomial): sage: (zeta^2 + zeta + 1).galois_group(pari_group=True) PARI group [2, -1, 1, "S2"] of degree 2 """ - from sage.groups.all import PariGroup, PermutationGroup, TransitiveGroup + from sage.groups.pari_group import PariGroup + from sage.groups.perm_gps.permgroup import PermutationGroup + from sage.groups.perm_gps.permgroup_named import TransitiveGroup if not self.is_irreducible(): raise ValueError("The polynomial must be irreducible") @@ -2232,23 +2231,21 @@ cdef class Polynomial_rational_flint(Polynomial): def factor_mod(self, p): """ - Return the factorization of self modulo the prime ``p``. + Return the factorization of ``self`` modulo the prime `p`. Assumes that the degree of this polynomial is at least one, and raises - a ``ValueError`` otherwise. + a :class:`ValueError` otherwise. INPUT: - ``p`` - Prime number - OUTPUT: - - - Factorization of this polynomial modulo ``p`` + OUTPUT: Factorization of this polynomial modulo `p` EXAMPLES:: sage: R.<x> = QQ[] - sage: (x^5 + 17*x^3 + x+ 3).factor_mod(3) + sage: (x^5 + 17*x^3 + x + 3).factor_mod(3) x * (x^2 + 1)^2 sage: (x^5 + 2).factor_mod(5) (x + 2)^5 @@ -2276,7 +2273,7 @@ cdef class Polynomial_rational_flint(Polynomial): return R(1)._factor_pari_helper(G, unit=R(self).leading_coefficient()) def factor_padic(self, p, prec=10): - """ + r""" Return the `p`-adic factorization of this polynomial to the given precision. @@ -2286,47 +2283,53 @@ cdef class Polynomial_rational_flint(Polynomial): - ``prec`` - Integer; the precision - OUTPUT: - - - factorization of ``self`` viewed as a `p`-adic polynomial + OUTPUT: factorization of ``self`` viewed as a `p`-adic polynomial EXAMPLES:: sage: R.<x> = QQ[] sage: f = x^3 - 2 sage: f.factor_padic(2) - (1 + O(2^10))*x^3 + O(2^10)*x^2 + O(2^10)*x + 2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + O(2^10) + (1 + O(2^10))*x^3 + O(2^10)*x^2 + O(2^10)*x + + 2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + O(2^10) sage: f.factor_padic(3) - (1 + O(3^10))*x^3 + O(3^10)*x^2 + O(3^10)*x + 1 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + O(3^10) + (1 + O(3^10))*x^3 + O(3^10)*x^2 + O(3^10)*x + + 1 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + O(3^10) sage: f.factor_padic(5) - ((1 + O(5^10))*x + 2 + 4*5 + 2*5^2 + 2*5^3 + 5^4 + 3*5^5 + 4*5^7 + 2*5^8 + 5^9 + O(5^10)) * ((1 + O(5^10))*x^2 + (3 + 2*5^2 + 2*5^3 + 3*5^4 + 5^5 + 4*5^6 + 2*5^8 + 3*5^9 + O(5^10))*x + 4 + 5 + 2*5^2 + 4*5^3 + 4*5^4 + 3*5^5 + 3*5^6 + 4*5^7 + 4*5^9 + O(5^10)) + ((1 + O(5^10))*x + + 2 + 4*5 + 2*5^2 + 2*5^3 + 5^4 + 3*5^5 + 4*5^7 + 2*5^8 + 5^9 + O(5^10)) + * ((1 + O(5^10))*x^2 + + (3 + 2*5^2 + 2*5^3 + 3*5^4 + 5^5 + 4*5^6 + 2*5^8 + 3*5^9 + O(5^10))*x + + 4 + 5 + 2*5^2 + 4*5^3 + 4*5^4 + 3*5^5 + 3*5^6 + 4*5^7 + 4*5^9 + O(5^10)) The input polynomial is considered to have "infinite" precision, therefore the `p`-adic factorization of the polynomial is not - the same as first coercing to `Q_p` and then factoring + the same as first coercing to `\QQ_p` and then factoring (see also :trac:`15422`):: sage: f = x^2 - 3^6 - sage: f.factor_padic(3,5) + sage: f.factor_padic(3, 5) ((1 + O(3^5))*x + 3^3 + O(3^5)) * ((1 + O(3^5))*x + 2*3^3 + 2*3^4 + O(3^5)) sage: f.change_ring(Qp(3,5)).factor() Traceback (most recent call last): ... - PrecisionError: p-adic factorization not well-defined since the discriminant is zero up to the requestion p-adic precision + PrecisionError: p-adic factorization not well-defined since + the discriminant is zero up to the requestion p-adic precision A more difficult example:: sage: f = 100 * (5*x + 1)^2 * (x + 5)^2 sage: f.factor_padic(5, 10) - (4*5^4 + O(5^14)) * ((1 + O(5^9))*x + 5^-1 + O(5^9))^2 * ((1 + O(5^10))*x + 5 + O(5^10))^2 + (4*5^4 + O(5^14)) * ((1 + O(5^9))*x + 5^-1 + O(5^9))^2 + * ((1 + O(5^10))*x + 5 + O(5^10))^2 Try some bogus inputs:: - sage: f.factor_padic(3,-1) + sage: f.factor_padic(3, -1) Traceback (most recent call last): ... ValueError: prec_cap must be non-negative - sage: f.factor_padic(6,10) + sage: f.factor_padic(6, 10) Traceback (most recent call last): ... ValueError: p must be prime @@ -2360,12 +2363,10 @@ cdef class Polynomial_rational_flint(Polynomial): INPUT: - - ``p`` - Prime number; coerceable to ``Integer`` - - ``e`` - Exponent; coerceable to ``Integer`` - - OUTPUT: + - ``p`` - Prime number; coerceable to :class:`Integer` + - ``e`` - Exponent; coerceable to :class:`Integer` - - Hensel lifts; list of polynomials over `\ZZ / p^e \ZZ` + OUTPUT: Hensel lifts; list of polynomials over `\ZZ / p^e \ZZ` EXAMPLES:: @@ -2386,7 +2387,7 @@ cdef class Polynomial_rational_flint(Polynomial): [] sage: R(x).hensel_lift(7, 2) [x] - sage: R(x-1).hensel_lift(7, 2) + sage: R(x - 1).hensel_lift(7, 2) [x + 48] Variable names that are reserved in PARI, such as ``I``, are @@ -2444,16 +2445,14 @@ cdef class Polynomial_rational_flint(Polynomial): The discriminant of constant polynomials is defined to be 0. - OUTPUT: - - - Discriminant, an element of the base ring of the polynomial ring + OUTPUT: Discriminant, an element of the base ring of the polynomial ring .. NOTE:: - Note the identity `R_n(f) := (-1)^(n (n-1)/2) R(f,f') a_n^(n-k-2)`, + Note the identity `R_n(f) := (-1)^{(n (n-1)/2)} R(f,f') a_n^{(n-k-2)}`, where `n` is the degree of this polynomial, `a_n` is the leading coefficient, `f'` is the derivative of `f`, and `k` is the degree - of `f'`. Calls :meth:`.resultant`. + of `f'`. Calls :meth:`resultant`. ALGORITHM: @@ -2512,14 +2511,14 @@ cdef class Polynomial_rational_flint(Polynomial): def galois_group_davenport_smith_test(self, num_trials=50, assume_irreducible=False): """ - Use the Davenport-Smith test to attempt to certify that `f` has Galois group A_n or S_n. + Use the Davenport-Smith test to attempt to certify that `f` has Galois group `A_n` or `S_n`. - Return 1 if the Galois group is certified as S_n, 2 if A_n, or 0 if no conclusion is reached. + Return 1 if the Galois group is certified as `S_n`, 2 if `A_n`, or 0 if no conclusion is reached. By default, we first check that `f` is irreducible. For extra efficiency, one can override this - by specifying `assume_irreducible=True`; this yields undefined results if `f` is not irreducible. + by specifying ``assume_irreducible=True``; this yields undefined results if `f` is not irreducible. - A corresponding function in Magma is `IsEasySnAn`. + A corresponding function in Magma is ``IsEasySnAn``. EXAMPLES:: diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index 8fa744ff668..da5462cddd4 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -6,6 +6,7 @@ TESTS: Check that operations with numpy elements work well (see :trac:`18076` and :trac:`8426`):: + sage: # needs numpy sage: import numpy sage: x = polygen(RR) sage: x * numpy.int32('1') @@ -25,7 +26,7 @@ Check that operations with numpy elements work well (see :trac:`18076` and from cysignals.memory cimport check_allocarray, check_reallocarray, sig_free from cysignals.signals cimport sig_on, sig_off -from cpython.int cimport PyInt_AS_LONG +from cpython.long cimport PyLong_AsLong from cpython.float cimport PyFloat_AS_DOUBLE from sage.structure.parent cimport Parent @@ -34,12 +35,16 @@ from sage.rings.real_mpfr cimport RealField_class, RealNumber from sage.rings.integer cimport Integer, smallInteger from sage.rings.rational cimport Rational -from sage.structure.element cimport Element, ModuleElement, RingElement +from sage.structure.element cimport Element from sage.structure.element cimport parent from sage.structure.element import coerce_binop from sage.libs.mpfr cimport * -from sage.libs.pari.all import pari_gen +try: + from sage.libs.pari.all import pari_gen +except ImportError: + pari_gen = () + cdef class PolynomialRealDense(Polynomial): r""" @@ -72,7 +77,7 @@ cdef class PolynomialRealDense(Polynomial): EXAMPLES:: sage: from sage.rings.polynomial.polynomial_real_mpfr_dense import PolynomialRealDense - sage: PolynomialRealDense(RR['x'], [1, int(2), RR(3), 4/1, pi]) + sage: PolynomialRealDense(RR['x'], [1, int(2), RR(3), 4/1, pi]) # needs sage.symbolic 3.14159265358979*x^4 + 4.00000000000000*x^3 + 3.00000000000000*x^2 + 2.00000000000000*x + 1.00000000000000 sage: PolynomialRealDense(RR['x'], None) 0 @@ -81,24 +86,24 @@ cdef class PolynomialRealDense(Polynomial): Check that errors and interrupts are handled properly (see :trac:`10100`):: - sage: a = var('a') - sage: PolynomialRealDense(RR['x'], [1,a]) + sage: a = var('a') # needs sage.symbolic + sage: PolynomialRealDense(RR['x'], [1,a]) # needs sage.symbolic Traceback (most recent call last): ... - TypeError: Cannot evaluate symbolic expression to a numeric value. - sage: R.<x> = SR[] - sage: (x-a).change_ring(RR) + TypeError: cannot evaluate symbolic expression to a numeric value + sage: R.<x> = SR[] # needs sage.symbolic + sage: (x-a).change_ring(RR) # needs sage.symbolic Traceback (most recent call last): ... - TypeError: Cannot evaluate symbolic expression to a numeric value. + TypeError: cannot evaluate symbolic expression to a numeric value sage: sig_on_count() 0 Test that we don't clean up uninitialized coefficients (:trac:`9826`):: - sage: k.<a> = GF(7^3) - sage: P.<x> = PolynomialRing(k) - sage: (a*x).complex_roots() + sage: k.<a> = GF(7^3) # needs sage.rings.finite_rings + sage: P.<x> = PolynomialRing(k) # needs sage.rings.finite_rings + sage: (a*x).complex_roots() # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: unable to convert 'a' to a real number @@ -111,7 +116,7 @@ cdef class PolynomialRealDense(Polynomial): Polynomial.__init__(self, parent, is_gen=is_gen) self._base_ring = parent._base cdef Py_ssize_t i, degree - cdef int prec = self._base_ring.__prec + cdef int prec = self._base_ring._prec cdef mpfr_rnd_t rnd = self._base_ring.rnd if x is None: self._coeffs = <mpfr_t*>check_allocarray(1, sizeof(mpfr_t)) # degree zero @@ -146,7 +151,7 @@ cdef class PolynomialRealDense(Polynomial): if type(a) is RealNumber: mpfr_set(coeffs[i], (<RealNumber>a).value, rnd) elif type(a) is int: - mpfr_set_si(coeffs[i], PyInt_AS_LONG(a), rnd) + mpfr_set_si(coeffs[i], PyLong_AsLong(a), rnd) elif type(a) is float: mpfr_set_d(coeffs[i], PyFloat_AS_DOUBLE(a), rnd) elif type(a) is Integer: @@ -222,7 +227,7 @@ cdef class PolynomialRealDense(Polynomial): cdef PolynomialRealDense _new(self, Py_ssize_t degree): cdef Py_ssize_t i - cdef int prec = self._base_ring.__prec + cdef int prec = self._base_ring._prec cdef PolynomialRealDense f = <PolynomialRealDense>PolynomialRealDense.__new__(PolynomialRealDense) f._parent = self._parent f._base_ring = self._base_ring @@ -283,14 +288,15 @@ cdef class PolynomialRealDense(Polynomial): def truncate_abs(self, RealNumber bound): """ - Truncate all high order coefficients below bound. + Truncate all high order coefficients below ``bound``. EXAMPLES:: sage: from sage.rings.polynomial.polynomial_real_mpfr_dense import PolynomialRealDense sage: f = PolynomialRealDense(RealField(10)['x'], [10^-k for k in range(10)]) sage: f - 1.0e-9*x^9 + 1.0e-8*x^8 + 1.0e-7*x^7 + 1.0e-6*x^6 + 0.000010*x^5 + 0.00010*x^4 + 0.0010*x^3 + 0.010*x^2 + 0.10*x + 1.0 + 1.0e-9*x^9 + 1.0e-8*x^8 + 1.0e-7*x^7 + 1.0e-6*x^6 + 0.000010*x^5 + + 0.00010*x^4 + 0.0010*x^3 + 0.010*x^2 + 0.10*x + 1.0 sage: f.truncate_abs(0.5e-6) 1.0e-6*x^6 + 0.000010*x^5 + 0.00010*x^4 + 0.0010*x^3 + 0.010*x^2 + 0.10*x + 1.0 sage: f.truncate_abs(10.0) @@ -495,7 +501,7 @@ cdef class PolynomialRealDense(Polynomial): else: f = left._new(left._degree + right._degree) sig_on() - mpfr_init2(tmp, left._base_ring.__prec) + mpfr_init2(tmp, left._base_ring._prec) for i from 0 <= i <= f._degree: # Yes, we could make this more efficient by initializing with # a multiple of left rather than all zeros... @@ -513,16 +519,16 @@ cdef class PolynomialRealDense(Polynomial): EXAMPLES:: sage: from sage.rings.polynomial.polynomial_real_mpfr_dense import PolynomialRealDense - sage: f = PolynomialRealDense(RR['x'], [pi, 0, 2, 1]) - sage: f.derivative() + sage: f = PolynomialRealDense(RR['x'], [pi, 0, 2, 1]) # needs sage.symbolic + sage: f.derivative() # needs sage.symbolic 3.00000000000000*x^2 + 4.00000000000000*x TESTS:: - sage: x, y = var('x,y') - sage: f.derivative(x) + sage: x, y = var('x,y') # needs sage.symbolic + sage: f.derivative(x) # needs sage.symbolic 3.00000000000000*x^2 + 4.00000000000000*x - sage: f.derivative(y) + sage: f.derivative(y) # needs sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y @@ -541,8 +547,8 @@ cdef class PolynomialRealDense(Polynomial): EXAMPLES:: sage: from sage.rings.polynomial.polynomial_real_mpfr_dense import PolynomialRealDense - sage: f = PolynomialRealDense(RR['x'], [3, pi, 1]) - sage: f.integral() + sage: f = PolynomialRealDense(RR['x'], [3, pi, 1]) # needs sage.symbolic + sage: f.integral() # needs sage.symbolic 0.333333333333333*x^3 + 1.57079632679490*x^2 + 3.00000000000000*x """ cdef mpfr_rnd_t rnd = self._base_ring.rnd @@ -566,6 +572,7 @@ cdef class PolynomialRealDense(Polynomial): EXAMPLES:: + sage: # needs sage.symbolic sage: f = RR['x']([-3, pi, 0, 1]) sage: f.reverse() -3.00000000000000*x^3 + 3.14159265358979*x^2 + 1.00000000000000 @@ -578,7 +585,7 @@ cdef class PolynomialRealDense(Polynomial): We check that this implementation is compatible with the generic one:: - sage: all(f.reverse(d) == Polynomial.reverse(f, d) + sage: all(f.reverse(d) == Polynomial.reverse(f, d) # needs sage.symbolic ....: for d in [None, 0, 1, 2, 3, 4, 5]) True """ @@ -618,6 +625,7 @@ cdef class PolynomialRealDense(Polynomial): sage: fg.quo_rem(g) (x^2 - 2.00000000000000, 0) + sage: # needs sage.symbolic sage: f = PolynomialRealDense(RR['x'], range(5)) sage: g = PolynomialRealDense(RR['x'], [pi,3000,4]) sage: q, r = f.quo_rem(g) @@ -653,7 +661,7 @@ cdef class PolynomialRealDense(Polynomial): q = self._new(self._degree - other._degree) # This is the standard division algorithm sig_on() - mpfr_init2(tmp, self._base_ring.__prec) + mpfr_init2(tmp, self._base_ring._prec) for i from self._degree >= i >= other._degree: mpfr_set(q._coeffs[i-other._degree], r._coeffs[i], rnd) for j from 0 <= j < other._degree: @@ -680,7 +688,7 @@ cdef class PolynomialRealDense(Polynomial): 2.00000000000000 sage: f(RealField(10)(2)) 2.0 - sage: f(pi) + sage: f(pi) # needs sage.symbolic 1.00000000000000*pi^2 - 2.00000000000000 @@ -717,7 +725,7 @@ cdef class PolynomialRealDense(Polynomial): cdef RealNumber x = <RealNumber>xx cdef RealNumber res - if (<RealField_class>x._parent).__prec < self._base_ring.__prec: + if (<RealField_class>x._parent)._prec < self._base_ring._prec: res = RealNumber(x._parent) else: res = RealNumber(self._base_ring) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index c7e9a7f9dbf..0b2daea1e0b 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -47,8 +47,9 @@ We create a polynomial ring over a quaternion algebra:: + sage: # needs sage.combinat sage.modules sage: A.<i,j,k> = QuaternionAlgebra(QQ, -1,-1) - sage: R.<w> = PolynomialRing(A,sparse=True) + sage: R.<w> = PolynomialRing(A, sparse=True) sage: f = w^3 + (i+j)*w + 1 sage: f w^3 + (i + j)*w + 1 @@ -63,7 +64,7 @@ :trac:`9944` introduced some changes related with coercion. Previously, a dense and a sparse polynomial ring with the same variable name over the same base ring evaluated equal, but of -course they were not identical.Coercion maps are cached - but if a +course they were not identical. Coercion maps are cached - but if a coercion to a dense ring is requested and a coercion to a sparse ring is returned instead (since the cache keys are equal!), all hell breaks loose. @@ -79,9 +80,9 @@ True sage: R.has_coerce_map_from(S) False - sage: (R.0+S.0).parent() + sage: (R.0 + S.0).parent() Univariate Polynomial Ring in x over Rational Field - sage: (S.0+R.0).parent() + sage: (S.0 + R.0).parent() Univariate Polynomial Ring in x over Rational Field It may be that one has rings of dense or sparse polynomials over @@ -105,16 +106,16 @@ implementation for univariate polynomials over the integers to the default FLINT implementation, but not vice versa:: - sage: R.<x> = PolynomialRing(ZZ, implementation = 'NTL') - sage: S.<x> = PolynomialRing(ZZ, implementation = 'FLINT') - sage: (S.0+R.0).parent() is S + sage: R.<x> = PolynomialRing(ZZ, implementation='NTL') # needs sage.libs.ntl + sage: S.<x> = PolynomialRing(ZZ, implementation='FLINT') + sage: (S.0 + R.0).parent() is S # needs sage.libs.flint sage.libs.ntl True - sage: (R.0+S.0).parent() is S + sage: (R.0 + S.0).parent() is S # needs sage.libs.flint sage.libs.ntl True TESTS:: - sage: K.<x>=FractionField(QQ['x']) + sage: K.<x> = FractionField(QQ['x']) sage: V.<z> = K[] sage: x+z z + x @@ -122,9 +123,9 @@ Check that :trac:`5562` has been fixed:: sage: R.<u> = PolynomialRing(RDF, 1) - sage: v1 = vector([u]) - sage: v2 = vector([CDF(2)]) - sage: v1 * v2 + sage: v1 = vector([u]) # needs sage.modules + sage: v2 = vector([CDF(2)]) # needs sage.modules + sage: v1 * v2 # needs sage.modules 2.0*u """ @@ -149,13 +150,17 @@ import sage.rings.ring as ring from sage.structure.element import is_RingElement -import sage.rings.polynomial.polynomial_element_generic as polynomial_element_generic import sage.rings.rational_field as rational_field from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer -from sage.rings.number_field.number_field_base import is_NumberField -from sage.libs.pari.all import pari_gen +from sage.rings.number_field.number_field_base import NumberField + +try: + from sage.libs.pari.all import pari_gen +except ImportError: + pari_gen = () + from sage.rings.polynomial.polynomial_ring_constructor import polynomial_default_category import sage.misc.latex as latex @@ -166,23 +171,18 @@ import sage.rings.abc from sage.rings.fraction_field_element import FractionFieldElement from sage.rings.finite_rings.element_base import FiniteRingElement - -from .polynomial_element import PolynomialBaseringInjection -from .polynomial_real_mpfr_dense import PolynomialRealDense -from .polynomial_integer_dense_flint import Polynomial_integer_dense_flint from sage.rings.polynomial.polynomial_singular_interface import PolynomialRing_singular_repr from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular +from sage.rings.power_series_ring_element import PowerSeries _CommutativeRings = categories.commutative_rings.CommutativeRings() -from . import cyclotomic - import sage.interfaces.abc def is_PolynomialRing(x): """ - Return True if x is a *univariate* polynomial ring (and not a + Return ``True`` if ``x`` is a *univariate* polynomial ring (and not a sparse multivariate polynomial ring in one variable). EXAMPLES:: @@ -212,6 +212,7 @@ def is_PolynomialRing(x): :: + sage: # needs sage.libs.singular sage: R.<w> = PolynomialRing(ZZ, implementation="singular"); R Multivariate Polynomial Ring in w over Integer Ring sage: is_PolynomialRing(R) @@ -229,7 +230,8 @@ class PolynomialRing_general(ring.Algebra): Univariate polynomial ring over a ring. """ - def __init__(self, base_ring, name=None, sparse=False, element_class=None, category=None): + def __init__(self, base_ring, name=None, sparse=False, implementation=None, + element_class=None, category=None): """ EXAMPLES:: @@ -291,10 +293,11 @@ def __init__(self, base_ring, name=None, sparse=False, element_class=None, categ self._polynomial_class = element_class else: if sparse: - self._polynomial_class = polynomial_element_generic.Polynomial_generic_sparse + from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_sparse + self._polynomial_class = Polynomial_generic_sparse else: - from sage.rings.polynomial import polynomial_element - self._polynomial_class = polynomial_element.Polynomial_generic_dense + from sage.rings.polynomial.polynomial_element import Polynomial_generic_dense + self._polynomial_class = Polynomial_generic_dense self.Element = self._polynomial_class self.__cyclopoly_cache = {} self._has_singular = False @@ -358,9 +361,9 @@ def _element_constructor_(self, x=None, check=True, is_gen=False, Coercing in pari elements:: - sage: QQ['x'](pari('[1,2,3/5]')) + sage: QQ['x'](pari('[1,2,3/5]')) # needs sage.libs.pari 3/5*x^2 + 2*x + 1 - sage: QQ['x'](pari('(-1/3)*x^10 + (2/3)*x - 1/5')) + sage: QQ['x'](pari('(-1/3)*x^10 + (2/3)*x - 1/5')) # needs sage.libs.pari -1/3*x^10 + 2/3*x - 1/5 Coercing strings:: @@ -378,22 +381,24 @@ def _element_constructor_(self, x=None, check=True, is_gen=False, This shows that the issue at :trac:`4106` is fixed:: + sage: # needs sage.symbolic sage: x = var('x') sage: R = IntegerModRing(4) sage: S = R['x'] sage: S(x) x - Throw a TypeError if any of the coefficients cannot be coerced + Throw a :class:`TypeError` if any of the coefficients cannot be coerced into the base ring (:trac:`6777`):: - sage: RealField(300)['x']( [ 1, ComplexField(300).gen(), 0 ]) + sage: RealField(300)['x']( [ 1, ComplexField(300).gen(), 0 ]) # needs sage.rings.real_mpfr Traceback (most recent call last): ... TypeError: unable to convert '1.00...00*I' to a real number Check that the bug in :trac:`11239` is fixed:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^2, prefix='z') sage: L.<b> = GF(5^4, prefix='z') sage: f = K['x'].gen() + a @@ -402,8 +407,8 @@ def _element_constructor_(self, x=None, check=True, is_gen=False, A test from :trac:`14485` :: - sage: x = SR.var('x') - sage: QQbar[x](x^6+x^5+x^4-x^3+x^2-x+2/5) + sage: x = SR.var('x') # needs sage.symbolic + sage: QQbar[x](x^6 + x^5 + x^4 - x^3 + x^2 - x + 2/5) # needs sage.rings.number_field sage.symbolic x^6 + x^5 + x^4 - x^3 + x^2 - x + 2/5 Check support for unicode characters (:trac:`29280`):: @@ -464,7 +469,7 @@ def _element_constructor_(self, x=None, check=True, is_gen=False, return self(x.polynomial()) except AttributeError: pass - elif isinstance(x, sage.rings.power_series_ring_element.PowerSeries): + elif isinstance(x, PowerSeries): x = x.truncate() return C(self, x, check, is_gen, construct=construct, **kwds) @@ -542,7 +547,7 @@ def _implementation_names_impl(implementation, base_ring, sparse): return [None, "generic"] return NotImplemented - def is_integral_domain(self, proof = True): + def is_integral_domain(self, proof=True): """ EXAMPLES:: @@ -553,7 +558,7 @@ def is_integral_domain(self, proof = True): """ return self.base_ring().is_integral_domain(proof) - def is_unique_factorization_domain(self, proof = True): + def is_unique_factorization_domain(self, proof=True): """ EXAMPLES:: @@ -604,7 +609,8 @@ def flattening_morphism(self): sage: QQ['a','b']['x'].flattening_morphism() Flattening morphism: - From: Univariate Polynomial Ring in x over Multivariate Polynomial Ring in a, b over Rational Field + From: Univariate Polynomial Ring in x over + Multivariate Polynomial Ring in a, b over Rational Field To: Multivariate Polynomial Ring in a, b, x over Rational Field sage: QQ['x'].flattening_morphism() @@ -624,36 +630,54 @@ def construction(self): """ return categories.pushout.PolynomialFunctor(self.variable_name(), sparse=self.__is_sparse), self.base_ring() - def completion(self, p, prec=20, extras=None): - """ - Return the completion of self with respect to the irreducible - polynomial p. Currently only implemented for p=self.gen(), i.e. you - can only complete R[x] with respect to x, the result being a ring - of power series in x. The prec variable controls the precision used - in the power series ring. + def completion(self, p=None, prec=20, extras=None): + r""" + Return the completion of ``self`` with respect to the irreducible + polynomial ``p``. + + Currently only implemented for ``p=self.gen()`` (the default), i.e. you + can only complete `R[x]` with respect to `x`, the result being a ring + of power series in `x`. The ``prec`` variable controls the precision + used in the power series ring. If ``prec`` is `\infty`, then this + returns a :class:`LazyPowerSeriesRing`. EXAMPLES:: - sage: P.<x>=PolynomialRing(QQ) + sage: P.<x> = PolynomialRing(QQ) sage: P Univariate Polynomial Ring in x over Rational Field - sage: PP=P.completion(x) + sage: PP = P.completion(x) sage: PP Power Series Ring in x over Rational Field - sage: f=1-x + sage: f = 1 - x sage: PP(f) 1 - x - sage: 1/f + sage: 1 / f -1/(x - 1) - sage: 1/PP(f) - 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8 + x^9 + x^10 + x^11 + x^12 + x^13 + x^14 + x^15 + x^16 + x^17 + x^18 + x^19 + O(x^20) + sage: g = 1 / PP(f); g + 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8 + x^9 + x^10 + x^11 + + x^12 + x^13 + x^14 + x^15 + x^16 + x^17 + x^18 + x^19 + O(x^20) + sage: 1 / g + 1 - x + O(x^20) + + sage: # needs sage.combinat + sage: PP = P.completion(x, prec=oo); PP + Lazy Taylor Series Ring in x over Rational Field + sage: g = 1 / PP(f); g + 1 + x + x^2 + O(x^3) + sage: 1 / g == f + True """ - if str(p) == self._names[0]: + if p is None or str(p) == self._names[0]: + if prec == float('inf'): + from sage.rings.lazy_series_ring import LazyPowerSeriesRing + return LazyPowerSeriesRing(self.base_ring(), names=(self._names[0],), + sparse=self.is_sparse()) from sage.rings.power_series_ring import PowerSeriesRing return PowerSeriesRing(self.base_ring(), name=self._names[0], default_prec=prec, sparse=self.is_sparse()) - else: - raise TypeError("Cannot complete %s with respect to %s" % (self, p)) + + raise NotImplementedError("cannot complete %s with respect to %s" % (self, p)) def _coerce_map_from_base_ring(self): """ @@ -679,6 +703,8 @@ def _coerce_map_from_base_ring(self): To: Univariate Polynomial Ring in x over Rational Field sage: R.coerce_map_from(GF(7)) """ + from .polynomial_element import PolynomialBaseringInjection + return PolynomialBaseringInjection(self.base_ring(), self) def _coerce_map_from_(self, P): @@ -714,9 +740,9 @@ def _coerce_map_from_(self, P): sage: R.<x> = PolynomialRing(QQ, sparse=True) sage: S.<x> = QQ[] - sage: (R.0+S.0).parent() + sage: (R.0 + S.0).parent() Univariate Polynomial Ring in x over Rational Field - sage: (S.0+R.0).parent() + sage: (S.0 + R.0).parent() Univariate Polynomial Ring in x over Rational Field Here we test a feature that was implemented in :trac:`813`:: @@ -725,7 +751,7 @@ def _coerce_map_from_(self, P): sage: Q = Frac(QQ['x'])['y'] sage: Q.has_coerce_map_from(P) True - sage: P.0+Q.0 + sage: P.0 + Q.0 y + x In order to avoid bidirectional coercions (which are generally @@ -743,20 +769,21 @@ def _coerce_map_from_(self, P): Over the integers, there is a coercion from the NTL and generic implementation to the default FLINT implementation:: - sage: R = PolynomialRing(ZZ, 't', implementation="NTL") - sage: S = PolynomialRing(ZZ, 't', implementation="FLINT") + sage: del R, S # clear values from doctests above + sage: R = PolynomialRing(ZZ, 't', implementation="NTL") # needs sage.libs.ntl + sage: S = PolynomialRing(ZZ, 't', implementation="FLINT") # needs sage.libs.flint sage: T = PolynomialRing(ZZ, 't', implementation="generic") - sage: R.has_coerce_map_from(S) + sage: R.has_coerce_map_from(S) # needs sage.libs.flint sage.libs.ntl False - sage: R.has_coerce_map_from(T) + sage: R.has_coerce_map_from(T) # needs sage.libs.ntl False - sage: S.has_coerce_map_from(T) + sage: S.has_coerce_map_from(T) # needs sage.libs.flint True - sage: S.has_coerce_map_from(R) + sage: S.has_coerce_map_from(R) # needs sage.libs.flint sage.libs.ntl True - sage: T.has_coerce_map_from(R) + sage: T.has_coerce_map_from(R) # needs sage.libs.ntl False - sage: T.has_coerce_map_from(S) + sage: T.has_coerce_map_from(S) # needs sage.libs.flint False """ base_ring = self.base_ring() @@ -794,6 +821,10 @@ def _coerce_map_from_(self, P): elif base_ring is ZZ: # Over ZZ, only allow coercion from any ZZ['x'] # implementation to the default FLINT implementation + try: + from .polynomial_integer_dense_flint import Polynomial_integer_dense_flint + except ImportError: + return None if self.element_class is not Polynomial_integer_dense_flint: return None # Other rings: always allow coercion @@ -809,7 +840,7 @@ def _coerce_map_from_(self, P): from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing if is_MPolynomialRing(P) and self.variable_name() in P.variable_names(): P_ = P.remove_var(self.variable_name()) - return self.base_ring()!=P_ and self.base_ring().has_coerce_map_from(P_) + return self.base_ring() != P_ and self.base_ring().has_coerce_map_from(P_) def _magma_init_(self, magma): """ @@ -817,19 +848,20 @@ def _magma_init_(self, magma): EXAMPLES:: + sage: # optional - magma sage: R = QQ['y'] - sage: R._magma_init_(magma) # optional - magma + sage: R._magma_init_(magma) 'SageCreateWithNames(PolynomialRing(_sage_ref...),["y"])' - sage: S = magma(R) # optional - magma - sage: S # optional - magma + sage: S = magma(R) + sage: S Univariate Polynomial Ring in y over Rational Field - sage: S.1 # optional - magma + sage: S.1 y - sage: magma(PolynomialRing(GF(7), 'x')) # optional - magma + sage: magma(PolynomialRing(GF(7), 'x')) # needs sage.rings.finite_rings Univariate Polynomial Ring in x over GF(7) - sage: magma(PolynomialRing(GF(49,'a'), 'x')) # optional - magma + sage: magma(PolynomialRing(GF(49,'a'), 'x')) # needs sage.rings.finite_rings Univariate Polynomial Ring in x over GF(7^2) - sage: magma(PolynomialRing(PolynomialRing(ZZ,'w'), 'x')) # optional - magma + sage: magma(PolynomialRing(PolynomialRing(ZZ,'w'), 'x')) Univariate Polynomial Ring in x over Univariate Polynomial Ring in w over Integer Ring Watch out, Magma has different semantics from Sage, i.e., in Magma @@ -839,24 +871,25 @@ def _magma_init_(self, magma): :: - sage: m = Magma() # new magma session; optional - magma - sage: m(QQ['w']) # optional - magma + sage: # optional - magma + sage: m = Magma() + sage: m(QQ['w']) Univariate Polynomial Ring in w over Rational Field - sage: m(QQ['x']) # optional - magma + sage: m(QQ['x']) Univariate Polynomial Ring in x over Rational Field - sage: m(QQ['w']) # same magma object, now prints as x; optional - magma + sage: m(QQ['w']) Univariate Polynomial Ring in x over Rational Field A nested example over a Givaro finite field:: - sage: k.<a> = GF(9) - sage: R.<x> = k[] - sage: magma(a^2*x^3 + (a+1)*x + a) # optional - magma + sage: k.<a> = GF(9) # needs sage.rings.finite_rings + sage: R.<x> = k[] # needs sage.rings.finite_rings + sage: magma(a^2*x^3 + (a+1)*x + a) # optional - magma # needs sage.rings.finite_rings a^2*x^3 + a^2*x + a """ B = magma(self.base_ring()) Bref = B._ref() - s = 'PolynomialRing(%s)'%(Bref) + s = 'PolynomialRing(%s)' % (Bref) return magma._with_names(s, self.variable_names()) def _gap_init_(self, gap=None): @@ -870,30 +903,31 @@ def _gap_init_(self, gap=None): EXAMPLES:: sage: R.<z> = ZZ[] - sage: gap(R) + sage: gap(R) # needs sage.libs.gap PolynomialRing( Integers, ["z"] ) - sage: gap(R) is gap(R) + sage: gap(R) is gap(R) # needs sage.libs.gap True - sage: gap(z^2 + z) + sage: gap(z^2 + z) # needs sage.libs.gap z^2+z A univariate polynomial ring over a multivariate polynomial ring over a number field:: + sage: # needs sage.rings.number_field sage: Q.<t> = QQ[] - sage: K.<tau> = NumberField(t^2+t+1) + sage: K.<tau> = NumberField(t^2 + t + 1) sage: P.<x,y> = K[] sage: S.<z> = P[] - sage: gap(S) + sage: gap(S) # needs sage.libs.gap PolynomialRing( PolynomialRing( <algebraic extension over the Rationals of degree 2>, ["x", "y"] ), ["z"] ) - sage: gap(S) is gap(S) + sage: gap(S) is gap(S) # needs sage.libs.gap True """ if gap is not None: base_ring = gap(self.base_ring()).name() else: base_ring = self.base_ring()._gap_init_() - return 'PolynomialRing(%s, ["%s"])'%(base_ring, self.variable_name()) + return 'PolynomialRing(%s, ["%s"])' % (base_ring, self.variable_name()) def _sage_input_(self, sib, coerced): r""" @@ -940,7 +974,6 @@ def _macaulay2_init_(self, macaulay2=None): macaulay2 = m2_default return macaulay2._macaulay2_input_ring(self.base_ring(), self.gens()) - def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): """ EXAMPLES:: @@ -948,7 +981,7 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): sage: R.<x> = QQ[] sage: R._is_valid_homomorphism_(GF(7), [5]) False - sage: R._is_valid_homomorphism_(Qp(7), [5]) + sage: R._is_valid_homomorphism_(Qp(7), [5]) # needs sage.rings.padics True """ # Since poly rings are free, any image of the gen @@ -976,7 +1009,7 @@ def _repr_(self): return self._cached_repr except AttributeError: pass - s = "Univariate Polynomial Ring in %s over %s"%( + s = "Univariate Polynomial Ring in %s over %s" % ( self.variable_name(), self.base_ring()) if self.is_sparse(): s = "Sparse " + s @@ -987,18 +1020,19 @@ def _latex_(self): r""" EXAMPLES:: - sage: S.<alpha12>=ZZ[] + sage: S.<alpha12> = ZZ[] sage: latex(S) \Bold{Z}[\alpha_{12}] """ - return "%s[%s]"%(latex.latex(self.base_ring()), self.latex_variable_names()[0]) + return "%s[%s]" % (latex.latex(self.base_ring()), self.latex_variable_names()[0]) def base_extend(self, R): """ - Return the base extension of this polynomial ring to R. + Return the base extension of this polynomial ring to `R`. EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: R.<x> = RR[]; R Univariate Polynomial Ring in x over Real Field with 53 bits of precision sage: R.base_extend(CC) @@ -1019,13 +1053,14 @@ def base_extend(self, R): def change_ring(self, R): """ - Return the polynomial ring in the same variable as self over R. + Return the polynomial ring in the same variable as ``self`` over `R`. EXAMPLES:: - sage: R.<ZZZ> = RealIntervalField() []; R - Univariate Polynomial Ring in ZZZ over Real Interval Field with 53 bits of precision - sage: R.change_ring(GF(19^2,'b')) + sage: R.<ZZZ> = RealIntervalField()[]; R + Univariate Polynomial Ring in ZZZ over + Real Interval Field with 53 bits of precision + sage: R.change_ring(GF(19^2, 'b')) # needs sage.rings.finite_rings Univariate Polynomial Ring in ZZZ over Finite Field in b of size 19^2 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -1034,7 +1069,7 @@ def change_ring(self, R): def change_var(self, var): r""" - Return the polynomial ring in variable var over the same base + Return the polynomial ring in variable ``var`` over the same base ring. EXAMPLES:: @@ -1046,12 +1081,12 @@ def change_var(self, var): """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - return PolynomialRing(self.base_ring(), names = var, sparse=self.is_sparse()) + return PolynomialRing(self.base_ring(), names=var, sparse=self.is_sparse()) - def extend_variables(self, added_names, order = 'degrevlex'): + def extend_variables(self, added_names, order='degrevlex'): r""" - Returns a multivariate polynomial ring with the same base ring but - with added_names as additional variables. + Return a multivariate polynomial ring with the same base ring but + with ``added_names`` as additional variables. EXAMPLES:: @@ -1066,7 +1101,7 @@ def extend_variables(self, added_names, order = 'degrevlex'): if isinstance(added_names, str): added_names = added_names.split(',') - return PolynomialRing(self.base_ring(), names = self.variable_names() + tuple(added_names), order = order) + return PolynomialRing(self.base_ring(), names=self.variable_names() + tuple(added_names), order=order) def variable_names_recursive(self, depth=sage.rings.infinity.infinity): r""" @@ -1125,13 +1160,13 @@ def characteristic(self): EXAMPLES:: - sage: R.<ZZZ> = RealIntervalField() []; R + sage: R.<ZZZ> = RealIntervalField()[]; R Univariate Polynomial Ring in ZZZ over Real Interval Field with 53 bits of precision sage: R.characteristic() 0 - sage: S = R.change_ring(GF(19^2,'b')); S + sage: S = R.change_ring(GF(19^2, 'b')); S # needs sage.rings.finite_rings Univariate Polynomial Ring in ZZZ over Finite Field in b of size 19^2 - sage: S.characteristic() + sage: S.characteristic() # needs sage.rings.finite_rings 19 """ return self.base_ring().characteristic() @@ -1150,6 +1185,7 @@ def cyclotomic_polynomial(self, n): x^4 + 1 sage: R.cyclotomic_polynomial(12) x^4 - x^2 + 1 + sage: S = PolynomialRing(FiniteField(7), 'x') sage: S.cyclotomic_polynomial(12) x^4 + 6*x^2 + 1 @@ -1162,15 +1198,16 @@ def cyclotomic_polynomial(self, n): sage: ZZ['x'].cyclotomic_polynomial(1) x - 1 - sage: gp('polcyclo(1)') + sage: gp('polcyclo(1)') # needs sage.libs.pari x - 1 """ if n <= 0: - raise ArithmeticError("n=%s must be positive"%n) + raise ArithmeticError("n=%s must be positive" % n) elif n == 1: return self.gen() - 1 else: - return self(cyclotomic.cyclotomic_coeffs(n), check=True) + from .cyclotomic import cyclotomic_coeffs + return self(cyclotomic_coeffs(n), check=True) @cached_method def gen(self, n=0): @@ -1227,12 +1264,13 @@ def parameter(self): def is_exact(self): return self.base_ring().is_exact() - def is_field(self, proof = True): + def is_field(self, proof=True): """ - Return False, since polynomial rings are never fields. + Return ``False``, since polynomial rings are never fields. EXAMPLES:: + sage: # needs sage.libs.ntl sage: R.<z> = Integers(2)[]; R Univariate Polynomial Ring in z over Ring of integers modulo 2 (using GF2X) sage: R.is_field() @@ -1242,7 +1280,7 @@ def is_field(self, proof = True): def is_sparse(self): """ - Return true if elements of this polynomial ring have a sparse + Return ``True`` if elements of this polynomial ring have a sparse representation. EXAMPLES:: @@ -1290,7 +1328,9 @@ def krull_dimension(self): sage: R.<x> = QQ[] sage: R.krull_dimension() 1 - sage: R.<z> = GF(9,'a')[]; R + + sage: # needs sage.rings.finite_rings + sage: R.<z> = GF(9, 'a')[]; R Univariate Polynomial Ring in z over Finite Field in a of size 3^2 sage: R.krull_dimension() 1 @@ -1298,7 +1338,7 @@ def krull_dimension(self): sage: S.krull_dimension() 2 sage: for n in range(10): - ....: S = PolynomialRing(S,'w') + ....: S = PolynomialRing(S, 'w') sage: S.krull_dimension() 12 """ @@ -1344,7 +1384,7 @@ def random_element(self, degree=(-1,2), *args, **kwds): sage: R.random_element(6).degree() 6 - If a tuple of two integers is given for the degree argument, a degree + If a tuple of two integers is given for the ``degree`` argument, a degree is first uniformly chosen, then a polynomial of that degree is given:: sage: R.random_element(degree=(0, 8)).degree() in range(0, 9) @@ -1353,10 +1393,10 @@ def random_element(self, degree=(-1,2), *args, **kwds): sage: while not all(found): ....: found[R.random_element(degree=(0, 8)).degree()] = True - Note that the zero polynomial has degree ``-1``, so if you want to - consider it set the minimum degree to ``-1``:: + Note that the zero polynomial has degree `-1`, so if you want to + consider it set the minimum degree to `-1`:: - sage: while R.random_element(degree=(-1,2),x=-1,y=1) != R.zero(): + sage: while R.random_element(degree=(-1,2), x=-1, y=1) != R.zero(): ....: pass TESTS:: @@ -1425,7 +1465,7 @@ def random_element(self, degree=(-1,2), *args, **kwds): return p - def _monics_degree( self, of_degree ): + def _monics_degree(self, of_degree): """ Refer to monics() for full documentation. """ @@ -1436,15 +1476,14 @@ def _monics_degree( self, of_degree ): coeffs.reverse() yield self(coeffs) - def _monics_max( self, max_degree ): + def _monics_max(self, max_degree): """ Refer to monics() for full documentation. """ for degree in range(max_degree + 1): - for m in self._monics_degree( degree ): - yield m + yield from self._monics_degree(degree) - def _polys_degree( self, of_degree ): + def _polys_degree(self, of_degree): """ Refer to polynomials() for full documentation. """ @@ -1477,20 +1516,24 @@ def _Karatsuba_threshold(self): EXAMPLES:: - sage: R.<x> = QQbar[] - sage: R._Karatsuba_threshold + sage: R.<x> = QQbar[] # needs sage.rings.number_field + sage: R._Karatsuba_threshold # needs sage.rings.number_field 8 - sage: MS = MatrixSpace(ZZ, 2, 2) - sage: R.<x> = MS[] - sage: R._Karatsuba_threshold + sage: MS = MatrixSpace(ZZ, 2, 2) # needs sage.modules + sage: R.<x> = MS[] # needs sage.modules + sage: R._Karatsuba_threshold # needs sage.modules 0 """ base_ring = self.base_ring() if is_PolynomialRing(base_ring): return 0 - from sage.matrix.matrix_space import MatrixSpace - if isinstance(base_ring, MatrixSpace): - return 0 + try: + from sage.matrix.matrix_space import MatrixSpace + except ImportError: + pass + else: + if isinstance(base_ring, MatrixSpace): + return 0 from sage.rings.fraction_field import FractionField_generic if isinstance(base_ring, FractionField_generic): return 1 << 60 @@ -1500,7 +1543,7 @@ def _Karatsuba_threshold(self): def karatsuba_threshold(self): """ Return the Karatsuba threshold used for this ring by the method - _mul_karatsuba to fall back to the schoolbook algorithm. + :meth:`_mul_karatsuba` to fall back to the schoolbook algorithm. EXAMPLES:: @@ -1515,7 +1558,7 @@ def karatsuba_threshold(self): def set_karatsuba_threshold(self, Karatsuba_threshold): """ - Changes the default threshold for this ring in the method _mul_karatsuba + Changes the default threshold for this ring in the method :meth:`_mul_karatsuba` to fall back to the schoolbook algorithm. .. warning:: @@ -1534,27 +1577,25 @@ def set_karatsuba_threshold(self, Karatsuba_threshold): """ self._Karatsuba_threshold = int(Karatsuba_threshold) - def polynomials( self, of_degree = None, max_degree = None ): + def polynomials( self, of_degree=None, max_degree=None ): """ Return an iterator over the polynomials of specified degree. INPUT: Pass exactly one of: - - ``max_degree`` - an int; the iterator will generate all polynomials which have degree less than or equal to - max_degree + ``max_degree`` - ``of_degree`` - an int; the iterator will generate - all polynomials which have degree of_degree - + all polynomials which have degree ``of_degree`` OUTPUT: an iterator EXAMPLES:: - sage: P = PolynomialRing(GF(3),'y') - sage: for p in P.polynomials( of_degree = 2 ): print(p) + sage: P = PolynomialRing(GF(3), 'y') + sage: for p in P.polynomials(of_degree=2): print(p) y^2 y^2 + 1 y^2 + 2 @@ -1573,7 +1614,7 @@ def polynomials( self, of_degree = None, max_degree = None ): 2*y^2 + 2*y 2*y^2 + 2*y + 1 2*y^2 + 2*y + 2 - sage: for p in P.polynomials( max_degree = 1 ): print(p) + sage: for p in P.polynomials(max_degree=1): print(p) 0 1 2 @@ -1583,7 +1624,7 @@ def polynomials( self, of_degree = None, max_degree = None ): 2*y 2*y + 1 2*y + 2 - sage: for p in P.polynomials( max_degree = 1, of_degree = 3 ): print(p) + sage: for p in P.polynomials(max_degree=1, of_degree=3): print(p) Traceback (most recent call last): ... ValueError: you should pass exactly one of of_degree and max_degree @@ -1601,7 +1642,7 @@ def polynomials( self, of_degree = None, max_degree = None ): return self._polys_max( max_degree ) raise ValueError("you should pass exactly one of of_degree and max_degree") - def monics( self, of_degree = None, max_degree = None ): + def monics( self, of_degree=None, max_degree=None ): """ Return an iterator over the monic polynomials of specified degree. @@ -1610,18 +1651,19 @@ def monics( self, of_degree = None, max_degree = None ): - ``max_degree`` - an int; the iterator will generate all monic polynomials which have degree less than or equal to - max_degree + ``max_degree`` - ``of_degree`` - an int; the iterator will generate - all monic polynomials which have degree of_degree + all monic polynomials which have degree ``of_degree`` OUTPUT: an iterator EXAMPLES:: - sage: P = PolynomialRing(GF(4,'a'),'y') - sage: for p in P.monics( of_degree = 2 ): print(p) + sage: # needs sage.rings.finite_rings + sage: P = PolynomialRing(GF(4, 'a'), 'y') + sage: for p in P.monics(of_degree=2): print(p) y^2 y^2 + a y^2 + a + 1 @@ -1638,13 +1680,13 @@ def monics( self, of_degree = None, max_degree = None ): y^2 + y + a y^2 + y + a + 1 y^2 + y + 1 - sage: for p in P.monics( max_degree = 1 ): print(p) + sage: for p in P.monics(max_degree=1): print(p) 1 y y + a y + a + 1 y + 1 - sage: for p in P.monics( max_degree = 1, of_degree = 3 ): print(p) + sage: for p in P.monics(max_degree=1, of_degree=3): print(p) Traceback (most recent call last): ... ValueError: you should pass exactly one of of_degree and max_degree @@ -1667,9 +1709,10 @@ class PolynomialRing_commutative(PolynomialRing_general, ring.CommutativeAlgebra """ Univariate polynomial ring over a commutative ring. """ - def __init__(self, base_ring, name=None, sparse=False, element_class=None, category=None): + def __init__(self, base_ring, name=None, sparse=False, implementation=None, + element_class=None, category=None): if base_ring not in _CommutativeRings: - raise TypeError("Base ring %s must be a commutative ring."%repr(base_ring)) + raise TypeError("Base ring %s must be a commutative ring." % repr(base_ring)) # We trust that, if a category is given, that it is useful. if category is None: if base_ring.is_zero(): @@ -1677,7 +1720,8 @@ def __init__(self, base_ring, name=None, sparse=False, element_class=None, categ else: category = polynomial_default_category(base_ring.category(), 1) PolynomialRing_general.__init__(self, base_ring, name=name, - sparse=sparse, element_class=element_class, category=category) + sparse=sparse, implementation=implementation, + element_class=element_class, category=category) def quotient_by_principal_ideal(self, f, names=None, **kwds): """ @@ -1693,16 +1737,18 @@ def quotient_by_principal_ideal(self, f, names=None, **kwds): EXAMPLES:: sage: R.<x> = QQ[] - sage: I = (x^2-1)*R - sage: R.quotient_by_principal_ideal(I) - Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 - 1 + sage: I = (x^2 - 1) * R + sage: R.quotient_by_principal_ideal(I) # needs sage.libs.pari + Univariate Quotient Polynomial Ring in xbar + over Rational Field with modulus x^2 - 1 The same example, using the polynomial instead of the ideal, and customizing the variable name:: sage: R.<x> = QQ[] - sage: R.quotient_by_principal_ideal(x^2-1, names=('foo',)) - Univariate Quotient Polynomial Ring in foo over Rational Field with modulus x^2 - 1 + sage: R.quotient_by_principal_ideal(x^2 - 1, names=('foo',)) # needs sage.libs.pari + Univariate Quotient Polynomial Ring in foo + over Rational Field with modulus x^2 - 1 TESTS: @@ -1729,9 +1775,9 @@ def weyl_algebra(self): EXAMPLES:: sage: R = QQ['x'] - sage: W = R.weyl_algebra(); W + sage: W = R.weyl_algebra(); W # needs sage.modules Differential Weyl algebra of polynomials in x over Rational Field - sage: W.polynomial_ring() == R + sage: W.polynomial_ring() == R # needs sage.modules True """ from sage.algebras.weyl_algebra import DifferentialWeylAlgebra @@ -1772,8 +1818,8 @@ def _roots_univariate_polynomial(self, p, ring=None, multiplicities=True, algori if ring is not None and ring is not self: p = p.change_ring(ring) if degree_bound is None: - return p.roots(multiplicities = multiplicities, algorithm = algorithm) - return p.roots(multiplicities = multiplicities, algorithm = algorithm, degree_bound = degree_bound) + return p.roots(multiplicities=multiplicities, algorithm=algorithm) + return p.roots(multiplicities=multiplicities, algorithm=algorithm, degree_bound=degree_bound) roots = p._roots_from_factorization(p.factor(), multiplicities) if degree_bound is not None: @@ -1794,26 +1840,40 @@ def __init__(self, base_ring, name="x", sparse=False, implementation=None, sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_integral_domain as PRing sage: R = PRing(ZZ, 'x'); R Univariate Polynomial Ring in x over Integer Ring - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.libs.flint <class 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'> - sage: R = PRing(ZZ, 'x', implementation='NTL'); R + sage: R = PRing(ZZ, 'x', implementation='NTL'); R # needs sage.libs.ntl Univariate Polynomial Ring in x over Integer Ring (using NTL) - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.libs.ntl <class 'sage.rings.polynomial.polynomial_integer_dense_ntl.Polynomial_integer_dense_ntl'> """ self._implementation_repr = '' if element_class is None: - implementation = self._implementation_names(implementation, base_ring, sparse)[0] - if base_ring is ZZ: - if implementation == 'NTL': - from sage.rings.polynomial.polynomial_integer_dense_ntl \ - import Polynomial_integer_dense_ntl as element_class - self._implementation_repr = ' (using NTL)' - elif implementation == 'FLINT': - element_class = Polynomial_integer_dense_flint + given_implementation = implementation + for implementation in self._implementation_names(implementation, base_ring, sparse): + if base_ring is ZZ: + if implementation == 'NTL': + try: + from sage.rings.polynomial.polynomial_integer_dense_ntl \ + import Polynomial_integer_dense_ntl as element_class + except ImportError: + if given_implementation: + raise + continue + self._implementation_repr = ' (using NTL)' + elif implementation == 'FLINT': + try: + from .polynomial_integer_dense_flint \ + import Polynomial_integer_dense_flint as element_class + except ImportError: + if given_implementation: + raise + continue + break PolynomialRing_commutative.__init__(self, base_ring, name=name, - sparse=sparse, element_class=element_class, category=category) + sparse=sparse, implementation=implementation, + element_class=element_class, category=category) self._has_singular = can_convert_to_singular(self) @cached_method(key=lambda self, d, q, sign, lead: (d, q, sign, tuple([x if isinstance(x, (tuple, list)) else (x, 0) for x in lead]) if isinstance(lead, (tuple, list)) else ((lead, 0)))) @@ -1839,20 +1899,21 @@ def weil_polynomials(self, d, q, sign=1, lead=1): - ``sign`` -- integer (default `1`), the sign `s` of the functional equation - ``lead`` -- integer, list of integers or list of pairs of integers (default `1`), - constraints on the leading few coefficients of the generated polynomials. - If pairs `(a, b)` of integers are given, they are treated as a constraint - of the form `\equiv a \pmod{b}`; the moduli must be in decreasing order by - divisibility, and the modulus of the leading coefficient must be 0. + constraints on the leading few coefficients of the generated polynomials. + If pairs `(a, b)` of integers are given, they are treated as a constraint + of the form `\equiv a \pmod{b}`; the moduli must be in decreasing order by + divisibility, and the modulus of the leading coefficient must be 0. .. SEEALSO:: More documentation and additional options are available using the iterator :class:`sage.rings.polynomial.weil.weil_polynomials.WeilPolynomials` - directly. In addition, polynomials have a method `is_weil_polynomial` to + directly. In addition, polynomials have a method :meth:`is_weil_polynomial` to test whether or not the given polynomial is a Weil polynomial. EXAMPLES:: + sage: # needs sage.libs.flint sage: R.<T> = ZZ[] sage: L = R.weil_polynomials(4, 2) sage: len(L) @@ -1862,54 +1923,56 @@ def weil_polynomials(self, d, q, sign=1, lead=1): sage: all(p.is_weil_polynomial() for p in L) True - Setting multiple leading coefficients: + Setting multiple leading coefficients:: sage: R.<T> = QQ[] - sage: l = R.weil_polynomials(4,2,lead=((1,0),(2,4),(1,2))) - sage: l + sage: l = R.weil_polynomials(4, 2, lead=((1,0), (2,4), (1,2))); l # needs sage.libs.flint [T^4 + 2*T^3 + 5*T^2 + 4*T + 4, - T^4 + 2*T^3 + 3*T^2 + 4*T + 4, - T^4 - 2*T^3 + 5*T^2 - 4*T + 4, - T^4 - 2*T^3 + 3*T^2 - 4*T + 4] + T^4 + 2*T^3 + 3*T^2 + 4*T + 4, + T^4 - 2*T^3 + 5*T^2 - 4*T + 4, + T^4 - 2*T^3 + 3*T^2 - 4*T + 4] We do not require Weil polynomials to be monic. This example generates Weil - polynomials associated to K3 surfaces over `GF(2)` of Picard number at least 12:: + polynomials associated to K3 surfaces over `\GF{2}` of Picard number at least 12:: sage: R.<T> = QQ[] - sage: l = R.weil_polynomials(10,1,lead=2) - sage: len(l) + sage: l = R.weil_polynomials(10, 1, lead=2) # needs sage.libs.flint + sage: len(l) # needs sage.libs.flint 4865 - sage: l[len(l)//2] + sage: l[len(l)//2] # needs sage.libs.flint 2*T^10 + T^8 + T^6 + T^4 + T^2 + 2 TESTS: We check that products of Weil polynomials are also listed as Weil polynomials:: - sage: all((f * g) in R.weil_polynomials(6, q) for q in [3,4] for f in R.weil_polynomials(2, q) for g in R.weil_polynomials(4, q)) + sage: all((f * g) in R.weil_polynomials(6, q) for q in [3, 4] # needs sage.libs.flint + ....: for f in R.weil_polynomials(2, q) for g in R.weil_polynomials(4, q)) True We check that irreducible Weil polynomials of degree 6 are CM:: - sage: simples = [f for f in R.weil_polynomials(6, 3) if f.is_irreducible()] - sage: len(simples) + sage: simples = [f for f in R.weil_polynomials(6, 3) if f.is_irreducible()] # needs sage.libs.flint + sage: len(simples) # needs sage.libs.flint 348 - sage: reals = [R([f[3+i] + sum((-3)^j * (i+2*j)/(i+j) * binomial(i+j,j) * f[3+i+2*j] for j in range(1,(3+i)//2+1)) for i in range(4)]) for f in simples] + sage: reals = [R([f[3+i] + sum((-3)^j * (i+2*j)/(i+j) * binomial(i+j,j) * f[3+i+2*j] # needs sage.libs.flint + ....: for j in range(1, (3+i)//2 + 1)) + ....: for i in range(4)]) for f in simples] Check that every polynomial in this list has 3 real roots between `-2 \sqrt{3}` and `2 \sqrt{3}`:: - sage: roots = [f.roots(RR, multiplicities=False) for f in reals] - sage: all(len(L) == 3 and all(x^2 <= 12 for x in L) for L in roots) + sage: roots = [f.roots(RR, multiplicities=False) for f in reals] # needs sage.libs.flint + sage: all(len(L) == 3 and all(x^2 <= 12 for x in L) for L in roots) # needs sage.libs.flint True Finally, check that the original polynomials are reconstructed as CM polynomials:: - sage: all(f == T^3*r(T + 3/T) for (f, r) in zip(simples, reals)) + sage: all(f == T^3*r(T + 3/T) for (f, r) in zip(simples, reals)) # needs sage.libs.flint True A simple check (not sufficient):: - sage: all(f.number_of_real_roots() == 0 for f in simples) + sage: all(f.number_of_real_roots() == 0 for f in simples) # needs sage.libs.flint True """ R = self.base_ring() @@ -1948,7 +2011,7 @@ def _repr_(self): TESTS:: sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_integral_domain as PRing - sage: R = PRing(ZZ, 'x', implementation='NTL'); R + sage: R = PRing(ZZ, 'x', implementation='NTL'); R # needs sage.libs.ntl Univariate Polynomial Ring in x over Integer Ring (using NTL) """ s = PolynomialRing_commutative._repr_(self) @@ -1968,6 +2031,7 @@ def construction(self): sage: functor.implementation is None True + sage: # needs sage.libs.ntl sage: R = PRing(ZZ, 'x', implementation='NTL'); R Univariate Polynomial Ring in x over Integer Ring (using NTL) sage: functor, arg = R.construction(); functor, arg @@ -1989,54 +2053,68 @@ def construction(self): class PolynomialRing_field(PolynomialRing_integral_domain, ring.PrincipalIdealDomain): - def __init__(self, base_ring, name="x", sparse=False, element_class=None, category=None): + def __init__(self, base_ring, name="x", sparse=False, implementation=None, + element_class=None, category=None): """ TESTS:: sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_field as PRing sage: R = PRing(QQ, 'x'); R Univariate Polynomial Ring in x over Rational Field - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.libs.flint <class 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'> sage: R = PRing(QQ, 'x', sparse=True); R Sparse Univariate Polynomial Ring in x over Rational Field sage: type(R.gen()) <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category.element_class'> - sage: R = PRing(CC, 'x'); R + sage: R = PRing(CC, 'x'); R # needs sage.rings.real_mpfr Univariate Polynomial Ring in x over Complex Field with 53 bits of precision - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.rings.real_mpfr <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category.element_class'> Demonstrate that :trac:`8762` is fixed:: - sage: R.<x> = PolynomialRing(GF(next_prime(10^20)), sparse=True) - sage: x^(10^20) # this should be fast + sage: R.<x> = PolynomialRing(GF(next_prime(10^20)), sparse=True) # needs sage.rings.finite_rings + sage: x^(10^20) # this should be fast # needs sage.rings.finite_rings x^100000000000000000000 """ - import sage.rings.complex_arb - - if not element_class: + def _element_class(): + if element_class: + return element_class if sparse: - element_class = polynomial_element_generic.Polynomial_generic_sparse_field - elif isinstance(base_ring, rational_field.RationalField): - from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint - element_class = Polynomial_rational_flint - elif is_NumberField(base_ring): + from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_sparse_field + return Polynomial_generic_sparse_field + if isinstance(base_ring, rational_field.RationalField): + try: + from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint + return Polynomial_rational_flint + except ImportError: + pass + elif isinstance(base_ring, NumberField): if base_ring.is_absolute(): from sage.rings.polynomial.polynomial_number_field import Polynomial_absolute_number_field_dense - element_class = Polynomial_absolute_number_field_dense + return Polynomial_absolute_number_field_dense else: from sage.rings.polynomial.polynomial_number_field import Polynomial_relative_number_field_dense - element_class = Polynomial_relative_number_field_dense + return Polynomial_relative_number_field_dense elif isinstance(base_ring, sage.rings.abc.RealField): - element_class = PolynomialRealDense + try: + from .polynomial_real_mpfr_dense import PolynomialRealDense + return PolynomialRealDense + except ImportError: + pass elif isinstance(base_ring, sage.rings.abc.ComplexBallField): - from sage.rings.polynomial.polynomial_complex_arb import Polynomial_complex_arb - element_class = Polynomial_complex_arb - else: - element_class = polynomial_element_generic.Polynomial_generic_dense_field + try: + from sage.rings.polynomial.polynomial_complex_arb import Polynomial_complex_arb + return Polynomial_complex_arb + except ImportError: + pass + from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_dense_field + return Polynomial_generic_dense_field - PolynomialRing_integral_domain.__init__(self, base_ring, name=name, sparse=sparse, element_class=element_class, category=category) + PolynomialRing_integral_domain.__init__(self, base_ring, name=name, + sparse=sparse, implementation=implementation, + element_class=_element_class(), category=category) def _ideal_class_(self, n=0): """ @@ -2061,7 +2139,7 @@ def divided_difference(self, points, full_table=False): - ``points`` -- a list of pairs `(x_0, y_0), (x_1, y_1), \dots, (x_n, y_n)` of elements of the base ring of ``self``, where `x_i - x_j` is invertible for `i \neq j`. This method - converts the `x_i` and `y_i` into the base ring of `self`. + converts the `x_i` and `y_i` into the base ring of ``self``. - ``full_table`` -- boolean (default: ``False``): If ``True``, return the full divided-difference table. If ``False``, @@ -2073,7 +2151,7 @@ def divided_difference(self, points, full_table=False): The Newton divided-difference coefficients of the `n`-th Lagrange interpolation polynomial `P_n(x)` that passes through the points in ``points`` (see :meth:`lagrange_polynomial`). - These are the coefficients `F_{0,0}, F_{1,1}, \dots, `F_{n,n}` + These are the coefficients `F_{0,0}, F_{1,1}, \dots, F_{n,n}` in the base ring of ``self`` such that .. MATH:: @@ -2085,32 +2163,29 @@ def divided_difference(self, points, full_table=False): Only return the divided-difference coefficients `F_{i,i}`. This example is taken from Example 1, page 121 of [BF2005]_:: - sage: points = [(1.0, 0.7651977), (1.3, 0.6200860), (1.6, 0.4554022), (1.9, 0.2818186), (2.2, 0.1103623)] + sage: points = [(1.0, 0.7651977), (1.3, 0.6200860), (1.6, 0.4554022), + ....: (1.9, 0.2818186), (2.2, 0.1103623)] sage: R = PolynomialRing(RR, "x") sage: R.divided_difference(points) [0.765197700000000, - -0.483705666666666, - -0.108733888888889, - 0.0658783950617283, - 0.00182510288066044] + -0.483705666666666, + -0.108733888888889, + 0.0658783950617283, + 0.00182510288066044] Now return the full divided-difference table:: - sage: points = [(1.0, 0.7651977), (1.3, 0.6200860), (1.6, 0.4554022), (1.9, 0.2818186), (2.2, 0.1103623)] + sage: points = [(1.0, 0.7651977), (1.3, 0.6200860), (1.6, 0.4554022), + ....: (1.9, 0.2818186), (2.2, 0.1103623)] sage: R = PolynomialRing(RR, "x") sage: R.divided_difference(points, full_table=True) [[0.765197700000000], - [0.620086000000000, -0.483705666666666], - [0.455402200000000, -0.548946000000000, -0.108733888888889], - [0.281818600000000, - -0.578612000000000, - -0.0494433333333339, - 0.0658783950617283], - [0.110362300000000, - -0.571520999999999, - 0.0118183333333349, - 0.0680685185185209, - 0.00182510288066044]] + [0.620086000000000, -0.483705666666666], + [0.455402200000000, -0.548946000000000, -0.108733888888889], + [0.281818600000000, -0.578612000000000, + -0.0494433333333339, 0.0658783950617283], + [0.110362300000000, -0.571520999999999, 0.0118183333333349, + 0.0680685185185209, 0.00182510288066044]] The following example is taken from Example 4.12, page 225 of [MF1999]_:: @@ -2121,11 +2196,11 @@ def divided_difference(self, points, full_table=False): [-3, 3, 6, 1, 0, 0] sage: R.divided_difference(points, full_table=True) [[-3], - [0, 3], - [15, 15, 6], - [48, 33, 9, 1], - [105, 57, 12, 1, 0], - [192, 87, 15, 1, 0, 0]] + [0, 3], + [15, 15, 6], + [48, 33, 9, 1], + [105, 57, 12, 1, 0], + [192, 87, 15, 1, 0, 0]] """ to_base_ring = self.base_ring() points = [tuple(to_base_ring(c) for c in p) for p in points] @@ -2151,7 +2226,7 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r - ``points`` -- a list of pairs `(x_0, y_0), (x_1, y_1), \dots, (x_n, y_n)` of elements of the base ring of ``self``, where `x_i - x_j` is invertible for `i \neq j`. This method - converts the `x_i` and `y_i` into the base ring of `self`. + converts the `x_i` and `y_i` into the base ring of ``self``. - ``algorithm`` -- (default: ``'divided_difference'``): one of the following: @@ -2159,7 +2234,7 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r - ``'divided_difference'``: use the method of divided differences. - - ``algorithm='neville'``: adapt Neville's method as + - ``'neville'``: adapt Neville's method as described on page 144 of [BF2005]_ to recursively generate the Lagrange interpolation polynomial. Neville's method generates a table of approximating polynomials, where the @@ -2190,7 +2265,7 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r By default, we use the method of divided differences:: sage: R = PolynomialRing(QQ, 'x') - sage: f = R.lagrange_polynomial([(0,1),(2,2),(3,-2),(-4,9)]); f + sage: f = R.lagrange_polynomial([(0,1), (2,2), (3,-2), (-4,9)]); f -23/84*x^3 - 11/84*x^2 + 13/7*x + 1 sage: f(0) 1 @@ -2200,11 +2275,13 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r -2 sage: f(-4) 9 - sage: R = PolynomialRing(GF(2**3,'a'), 'x') + + sage: # needs sage.rings.finite_rings + sage: R = PolynomialRing(GF(2**3, 'a'), 'x') sage: a = R.base_ring().gen() - sage: f = R.lagrange_polynomial([(a^2+a,a),(a,1),(a^2,a^2+a+1)]); f + sage: f = R.lagrange_polynomial([(a^2+a, a), (a, 1), (a^2, a^2+a+1)]); f a^2*x^2 + a^2*x + a^2 - sage: f(a^2+a) + sage: f(a^2 + a) a sage: f(a) 1 @@ -2214,27 +2291,35 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r Now use a memory efficient version of Neville's method:: sage: R = PolynomialRing(QQ, 'x') - sage: R.lagrange_polynomial([(0,1),(2,2),(3,-2),(-4,9)], algorithm="neville") + sage: R.lagrange_polynomial([(0,1), (2,2), (3,-2), (-4,9)], + ....: algorithm="neville") [9, -11/7*x + 19/7, -17/42*x^2 - 83/42*x + 53/7, -23/84*x^3 - 11/84*x^2 + 13/7*x + 1] - sage: R = PolynomialRing(GF(2**3,'a'), 'x') + + sage: # needs sage.rings.finite_rings + sage: R = PolynomialRing(GF(2**3, 'a'), 'x') sage: a = R.base_ring().gen() - sage: R.lagrange_polynomial([(a^2+a,a),(a,1),(a^2,a^2+a+1)], algorithm="neville") + sage: R.lagrange_polynomial([(a^2+a, a), (a, 1), (a^2, a^2+a+1)], + ....: algorithm="neville") [a^2 + a + 1, x + a + 1, a^2*x^2 + a^2*x + a^2] Repeated use of Neville's method to get better Lagrange interpolation polynomials:: sage: R = PolynomialRing(QQ, 'x') - sage: p = R.lagrange_polynomial([(0,1),(2,2)], algorithm="neville") - sage: R.lagrange_polynomial([(0,1),(2,2),(3,-2),(-4,9)], algorithm="neville", previous_row=p)[-1] + sage: p = R.lagrange_polynomial([(0,1), (2,2)], algorithm="neville") + sage: R.lagrange_polynomial([(0,1), (2,2), (3,-2), (-4,9)], + ....: algorithm="neville", previous_row=p)[-1] -23/84*x^3 - 11/84*x^2 + 13/7*x + 1 - sage: R = PolynomialRing(GF(2**3,'a'), 'x') + + sage: # needs sage.rings.finite_rings + sage: R = PolynomialRing(GF(2**3, 'a'), 'x') sage: a = R.base_ring().gen() - sage: p = R.lagrange_polynomial([(a^2+a,a),(a,1)], algorithm="neville") - sage: R.lagrange_polynomial([(a^2+a,a),(a,1),(a^2,a^2+a+1)], algorithm="neville", previous_row=p)[-1] + sage: p = R.lagrange_polynomial([(a^2+a, a), (a, 1)], algorithm="neville") + sage: R.lagrange_polynomial([(a^2+a, a), (a, 1), (a^2, a^2+a+1)], + ....: algorithm="neville", previous_row=p)[-1] a^2*x^2 + a^2*x + a^2 TESTS: @@ -2367,18 +2452,21 @@ def fraction_field(self): sage: R.<t> = GF(5)[] sage: R.fraction_field() - Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 + Fraction Field of Univariate Polynomial Ring in t + over Finite Field of size 5 TESTS: Check that :trac:`25449` has been resolved:: + sage: # needs sage.rings.finite_rings sage: k = GF(25453) sage: F.<x> = FunctionField(k) sage: R.<t> = k[] sage: t(x) x + sage: # needs sage.rings.finite_rings sage: k = GF(55667) sage: F.<x> = FunctionField(k) sage: R.<t> = k[] @@ -2389,9 +2477,13 @@ def fraction_field(self): R = self.base_ring() p = R.characteristic() if p != 0 and R.is_prime_field(): - from sage.rings.fraction_field_FpT import FpT - if 2 < p and p < FpT.INTEGER_LIMIT: - return FpT(self) + try: + from sage.rings.fraction_field_FpT import FpT + except ImportError: + pass + else: + if 2 < p and p < FpT.INTEGER_LIMIT: + return FpT(self) from sage.rings.fraction_field import FractionField_1poly_field return FractionField_1poly_field(self) @@ -2402,8 +2494,8 @@ class PolynomialRing_dense_finite_field(PolynomialRing_field): EXAMPLES:: - sage: R = PolynomialRing(GF(27, 'a'), 'x') - sage: type(R) + sage: R = PolynomialRing(GF(27, 'a'), 'x') # needs sage.rings.finite_rings + sage: type(R) # needs sage.rings.finite_rings <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_finite_field_with_category'> """ def __init__(self, base_ring, name="x", element_class=None, implementation=None): @@ -2415,32 +2507,40 @@ def __init__(self, base_ring, name="x", element_class=None, implementation=None) sage: type(R(0)) <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_finite_field_with_category.element_class'> - sage: S = PolynomialRing_dense_finite_field(GF(25, 'a'), implementation='NTL') - sage: type(S(0)) + sage: S = PolynomialRing_dense_finite_field(GF(25, 'a'), implementation='NTL') # needs sage.libs.ntl sage.rings.finite_rings + sage: type(S(0)) # needs sage.libs.ntl sage.rings.finite_rings <class 'sage.rings.polynomial.polynomial_zz_pex.Polynomial_ZZ_pEX'> - sage: S = PolynomialRing_dense_finite_field(GF(64), implementation='superfast') + sage: S = PolynomialRing_dense_finite_field(GF(64), implementation='superfast') # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: unknown implementation 'superfast' for dense polynomial rings over Finite Field in z6 of size 2^6 """ - implementation = self._implementation_names(implementation, base_ring)[0] - if implementation == "NTL": - from sage.libs.ntl.ntl_ZZ_pEContext import ntl_ZZ_pEContext - from sage.libs.ntl.ntl_ZZ_pX import ntl_ZZ_pX - from sage.rings.polynomial.polynomial_zz_pex import Polynomial_ZZ_pEX - - p = base_ring.characteristic() - self._modulus = ntl_ZZ_pEContext(ntl_ZZ_pX(list(base_ring.modulus()), p)) - element_class = Polynomial_ZZ_pEX + if element_class is None: + given_implementation = implementation + for implementation in self._implementation_names(implementation, base_ring): + if implementation == "NTL": + try: + from sage.libs.ntl.ntl_ZZ_pEContext import ntl_ZZ_pEContext + from sage.libs.ntl.ntl_ZZ_pX import ntl_ZZ_pX + from sage.rings.polynomial.polynomial_zz_pex import Polynomial_ZZ_pEX + except ImportError: + if given_implementation: + raise + continue + p = base_ring.characteristic() + self._modulus = ntl_ZZ_pEContext(ntl_ZZ_pX(list(base_ring.modulus()), p)) + element_class = Polynomial_ZZ_pEX + break PolynomialRing_field.__init__(self, base_ring, sparse=False, name=name, - element_class=element_class) + implementation=implementation, element_class=element_class) @staticmethod def _implementation_names_impl(implementation, base_ring, sparse): """ TESTS:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_finite_field sage: PolynomialRing_dense_finite_field._implementation_names_impl("NTL", GF(4), False) ['NTL', None] @@ -2485,14 +2585,17 @@ def irreducible_element(self, n, algorithm=None): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: f = GF(5^3, 'a')['x'].irreducible_element(2) sage: f.degree() 2 sage: f.is_irreducible() True - sage: GF(19)['x'].irreducible_element(21, algorithm="first_lexicographic") + sage: R = GF(19)['x'] + sage: R.irreducible_element(21, algorithm="first_lexicographic") x^21 + x + 5 - sage: GF(5**2, 'a')['x'].irreducible_element(17, algorithm="first_lexicographic") + sage: R = GF(5**2, 'a')['x'] + sage: R.irreducible_element(17, algorithm="first_lexicographic") x^17 + a*x + 4*a + 3 AUTHORS: @@ -2553,6 +2656,7 @@ def _roth_ruckenstein(self, p, degree_bound, precision): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(17) sage: Px.<x> = F[] sage: Pxy.<y> = Px[] @@ -2652,6 +2756,7 @@ def _alekhnovich(self, p, degree_bound, precision=None, dc_threshold=None): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(17)[] sage: S.<y> = R[] sage: p = (y - 2*x^2 - 3*x - 14) * (y - 3*x + 2) * (y - 1) @@ -2659,21 +2764,23 @@ def _alekhnovich(self, p, degree_bound, precision=None, dc_threshold=None): [3*x + 15, 2*x^2 + 3*x + 14, 1] sage: R._alekhnovich(p, 1) [3*x + 15, 1] - sage: R._alekhnovich(p, 1, precision = 2) + sage: R._alekhnovich(p, 1, precision=2) [(3*x + 15, 2), (3*x + 14, 2), (1, 2)] Example of benchmark to check that `dc_threshold = None` is better:: - sage: p = prod(y - R.random_element(20) for _ in range(10)) * S.random_element(10,10) # not tested - sage: %timeit _alekhnovich(R, p, 20, dc_threshold = None) # not tested + sage: # not tested, needs sage.rings.finite_rings + sage: p = prod(y - R.random_element(20) + ....: for _ in range(10)) * S.random_element(10,10) + sage: %timeit _alekhnovich(R, p, 20, dc_threshold = None) 1 loop, best of 3: 418 ms per loop - sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 1) # not tested + sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 1) 1 loop, best of 3: 416 ms per loop - sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 2) # not tested + sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 2) 1 loop, best of 3: 418 ms per loop - sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 3) # not tested + sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 3) 1 loop, best of 3: 454 ms per loop - sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 4) # not tested + sage: %timeit _alekhnovich(R, p, 20, dc_threshold = 4) 1 loop, best of 3: 519 ms per loop AUTHORS: @@ -2692,7 +2799,7 @@ def alekh_rec(p, k, degree_bound, lvl): - ``degree_bound`` -- the current degree bound - ``lvl`` -- the level in the recursion tree """ - if k<=0: + if k <= 0: return [ (self.zero(),0) ] elif degree_bound < 0: # The only possible root of (current) p, if any, is y = 0 @@ -2763,6 +2870,7 @@ def _roots_univariate_polynomial(self, p, ring=None, multiplicities=False, algor EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(13)[] sage: S.<y> = R[] sage: p = y^2 + (12*x^2 + x + 11)*y + x^3 + 12*x^2 + 12*x + 1 @@ -2814,7 +2922,8 @@ class PolynomialRing_cdvr(PolynomialRing_integral_domain): r""" A class for polynomial ring over complete discrete valuation rings """ - def __init__(self, base_ring, name=None, sparse=False, element_class=None, category=None): + def __init__(self, base_ring, name=None, sparse=False, implementation=None, + element_class=None, category=None): r""" TESTS:: @@ -2824,6 +2933,7 @@ def __init__(self, base_ring, name=None, sparse=False, element_class=None, categ sage: isinstance(S, PolynomialRing_cdvr) False + sage: # needs sage.rings.padics sage: S.<x> = Zp(5)[] sage: isinstance(S, PolynomialRing_cdvr) True @@ -2835,14 +2945,17 @@ def __init__(self, base_ring, name=None, sparse=False, element_class=None, categ else: from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_dense_cdvr element_class = Polynomial_generic_dense_cdvr - PolynomialRing_integral_domain.__init__(self, base_ring, name, sparse, element_class=element_class, category=category) + PolynomialRing_integral_domain.__init__(self, base_ring, name, sparse, + implementation=implementation, + element_class=element_class, category=category) class PolynomialRing_cdvf(PolynomialRing_cdvr, PolynomialRing_field): """ A class for polynomial ring over complete discrete valuation fields """ - def __init__(self, base_ring, name=None, sparse=False, element_class=None, category=None): + def __init__(self, base_ring, name=None, sparse=False, implementation=None, + element_class=None, category=None): r""" TESTS:: @@ -2852,8 +2965,8 @@ def __init__(self, base_ring, name=None, sparse=False, element_class=None, categ sage: isinstance(S, PolynomialRing_cdvf) False - sage: S.<x> = Qp(5)[] - sage: isinstance(S, PolynomialRing_cdvf) + sage: S.<x> = Qp(5)[] # needs sage.rings.padics + sage: isinstance(S, PolynomialRing_cdvf) # needs sage.rings.padics True """ if element_class is None: @@ -2863,15 +2976,19 @@ def __init__(self, base_ring, name=None, sparse=False, element_class=None, categ else: from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_dense_cdvf element_class = Polynomial_generic_dense_cdvf - PolynomialRing_field.__init__(self, base_ring, name, sparse, element_class=element_class, category=category) + PolynomialRing_field.__init__(self, base_ring, name, sparse, + implementation=implementation, element_class=element_class, + category=category) class PolynomialRing_dense_padic_ring_generic(PolynomialRing_cdvr): r""" - A class for dense polynomial ring over padic rings + A class for dense polynomial ring over p-adic rings """ - def __init__(self, base_ring, name=None, element_class=None, category=None): - PolynomialRing_cdvr.__init__(self, base_ring, sparse=False, name=name, element_class=element_class, category=category) + def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None): + PolynomialRing_cdvr.__init__(self, base_ring, sparse=False, name=name, + implementation=implementation, element_class=element_class, + category=category) @staticmethod def _implementation_names_impl(implementation, base_ring, sparse): @@ -2881,11 +2998,11 @@ def _implementation_names_impl(implementation, base_ring, sparse): TESTS:: sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_ring_generic - sage: PolynomialRing_dense_padic_ring_generic._implementation_names_impl(None, Zp(2), False) + sage: PolynomialRing_dense_padic_ring_generic._implementation_names_impl(None, Zp(2), False) # needs sage.rings.padics [None] - sage: PolynomialRing_dense_padic_ring_generic._implementation_names_impl(None, Zp(2), True) + sage: PolynomialRing_dense_padic_ring_generic._implementation_names_impl(None, Zp(2), True) # needs sage.rings.padics NotImplemented - sage: PolynomialRing_dense_padic_ring_generic._implementation_names_impl("generic", Zp(2), False) + sage: PolynomialRing_dense_padic_ring_generic._implementation_names_impl("generic", Zp(2), False) # needs sage.rings.padics NotImplemented """ if implementation is None and not sparse: @@ -2895,10 +3012,12 @@ def _implementation_names_impl(implementation, base_ring, sparse): class PolynomialRing_dense_padic_field_generic(PolynomialRing_cdvf): r""" - A class for dense polynomial ring over padic fields + A class for dense polynomial ring over p-adic fields """ - def __init__(self, base_ring, name=None, element_class=None, category=None): - PolynomialRing_cdvf.__init__(self, base_ring, sparse=False, name=name, element_class=element_class, category=category) + def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None): + PolynomialRing_cdvf.__init__(self, base_ring, sparse=False, name=name, + implementation=implementation, element_class=element_class, + category=category) @staticmethod def _implementation_names_impl(implementation, base_ring, sparse): @@ -2908,11 +3027,11 @@ def _implementation_names_impl(implementation, base_ring, sparse): TESTS:: sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_field_generic - sage: PolynomialRing_dense_padic_field_generic._implementation_names_impl(None, Qp(2), False) + sage: PolynomialRing_dense_padic_field_generic._implementation_names_impl(None, Qp(2), False) # needs sage.rings.padics [None] - sage: PolynomialRing_dense_padic_field_generic._implementation_names_impl(None, Qp(2), True) + sage: PolynomialRing_dense_padic_field_generic._implementation_names_impl(None, Qp(2), True) # needs sage.rings.padics NotImplemented - sage: PolynomialRing_dense_padic_field_generic._implementation_names_impl("generic", Qp(2), False) + sage: PolynomialRing_dense_padic_field_generic._implementation_names_impl("generic", Qp(2), False) # needs sage.rings.padics NotImplemented """ if implementation is None and not sparse: @@ -2921,14 +3040,14 @@ def _implementation_names_impl(implementation, base_ring, sparse): class PolynomialRing_dense_padic_ring_capped_relative(PolynomialRing_dense_padic_ring_generic): - def __init__(self, base_ring, name=None, element_class=None, category=None): + def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None): """ TESTS:: sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_ring_capped_relative as PRing - sage: R = PRing(Zp(13), name='t'); R + sage: R = PRing(Zp(13), name='t'); R # needs sage.rings.padics Univariate Polynomial Ring in t over 13-adic Ring with capped relative precision 20 - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.rings.padics <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_padic_ring_capped_relative_with_category.element_class'> """ if element_class is None: @@ -2936,58 +3055,61 @@ def __init__(self, base_ring, name=None, element_class=None, category=None): polynomial_padic_capped_relative_dense import \ Polynomial_padic_capped_relative_dense element_class = Polynomial_padic_capped_relative_dense - PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, - name=name, element_class=element_class, category=category) + PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name, + implementation=implementation, + element_class=element_class, category=category) class PolynomialRing_dense_padic_ring_capped_absolute(PolynomialRing_dense_padic_ring_generic): - def __init__(self, base_ring, name=None, element_class=None, category=None): + def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None): """ TESTS:: sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_ring_capped_absolute as PRing - sage: R = PRing(Zp(13, type='capped-abs'), name='t'); R + sage: R = PRing(Zp(13, type='capped-abs'), name='t'); R # needs sage.rings.padics Univariate Polynomial Ring in t over 13-adic Ring with capped absolute precision 20 - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.rings.padics <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_padic_ring_capped_absolute_with_category.element_class'> """ if element_class is None: from sage.rings.polynomial.padics.polynomial_padic_flat import \ Polynomial_padic_flat element_class = Polynomial_padic_flat - PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, - name=name, element_class=element_class, category=category) + PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name, + implementation=implementation, + element_class=element_class, category=category) class PolynomialRing_dense_padic_ring_fixed_mod(PolynomialRing_dense_padic_ring_generic): - def __init__(self, base_ring, name=None, element_class=None, category=None): + def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None): """ TESTS:: sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_ring_fixed_mod as PRing - sage: R = PRing(Zp(13, type='fixed-mod'), name='t'); R + sage: R = PRing(Zp(13, type='fixed-mod'), name='t'); R # needs sage.rings.padics Univariate Polynomial Ring in t over 13-adic Ring of fixed modulus 13^20 - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.rings.padics <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_padic_ring_fixed_mod_with_category.element_class'> """ if element_class is None: from sage.rings.polynomial.padics.polynomial_padic_flat import \ Polynomial_padic_flat element_class = Polynomial_padic_flat - PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, - name=name, element_class=element_class, category=category) + PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name, + implementation=implementation, + element_class=element_class, category=category) class PolynomialRing_dense_padic_field_capped_relative(PolynomialRing_dense_padic_field_generic): - def __init__(self, base_ring, name=None, element_class=None, category=None): + def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None): """ TESTS:: sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_padic_field_capped_relative as PRing - sage: R = PRing(Qp(13), name='t'); R + sage: R = PRing(Qp(13), name='t'); R # needs sage.rings.padics Univariate Polynomial Ring in t over 13-adic Field with capped relative precision 20 - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.rings.padics <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_padic_field_capped_relative_with_category.element_class'> """ if element_class is None: @@ -2995,8 +3117,9 @@ def __init__(self, base_ring, name=None, element_class=None, category=None): polynomial_padic_capped_relative_dense import \ Polynomial_padic_capped_relative_dense element_class = Polynomial_padic_capped_relative_dense - PolynomialRing_dense_padic_field_generic.__init__(self, base_ring, - name=name, element_class=element_class, category=category) + PolynomialRing_dense_padic_field_generic.__init__(self, base_ring, name=name, + implementation=implementation, + element_class=element_class, category=category) class PolynomialRing_dense_mod_n(PolynomialRing_commutative): @@ -3008,17 +3131,17 @@ def __init__(self, base_ring, name=None, element_class=None, sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_mod_n as PRing sage: R = PRing(Zmod(15), 'x'); R Univariate Polynomial Ring in x over Ring of integers modulo 15 - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.libs.flint <class 'sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint'> - sage: R = PRing(Zmod(15), 'x', implementation='NTL'); R + sage: R = PRing(Zmod(15), 'x', implementation='NTL'); R # needs sage.libs.ntl Univariate Polynomial Ring in x over Ring of integers modulo 15 (using NTL) - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.libs.ntl <class 'sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_modn_ntl_zz'> - sage: R = PRing(Zmod(2**63*3), 'x', implementation='NTL'); R + sage: R = PRing(Zmod(2**63*3), 'x', implementation='NTL'); R # needs sage.libs.ntl Univariate Polynomial Ring in x over Ring of integers modulo 27670116110564327424 (using NTL) - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.libs.ntl <class 'sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_modn_ntl_ZZ'> sage: R = PRing(Zmod(2**63*3), 'x', implementation='FLINT') @@ -3026,27 +3149,40 @@ def __init__(self, base_ring, name=None, element_class=None, ... ValueError: FLINT does not support modulus 27670116110564327424 - sage: R = PRing(Zmod(2**63*3), 'x'); R + sage: R = PRing(Zmod(2**63*3), 'x'); R # needs sage.libs.ntl Univariate Polynomial Ring in x over Ring of integers modulo 27670116110564327424 (using NTL) - sage: type(R.gen()) + sage: type(R.gen()) # needs sage.libs.ntl <class 'sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_modn_ntl_ZZ'> """ if element_class is None: - implementation = self._implementation_names(implementation, base_ring)[0] - if implementation == "FLINT": - from .polynomial_zmod_flint import \ - Polynomial_zmod_flint as element_class - self._implementation_repr = '' - elif implementation == "NTL": - modulus = base_ring.order() - from . import polynomial_modn_dense_ntl as modn_dense_ntl - if modulus < ZZ(modn_dense_ntl.zz_p_max): - element_class = modn_dense_ntl.Polynomial_dense_modn_ntl_zz - else: - element_class = modn_dense_ntl.Polynomial_dense_modn_ntl_ZZ - self._implementation_repr = ' (using NTL)' - PolynomialRing_commutative.__init__(self, base_ring, name=name, - element_class=element_class, category=category) + self._implementation_repr = '' + given_implementation = implementation + for implementation in self._implementation_names(implementation, base_ring): + if implementation == "FLINT": + try: + from .polynomial_zmod_flint import Polynomial_zmod_flint as element_class + except ImportError: + if given_implementation: + raise + continue + self._implementation_repr = '' + elif implementation == "NTL": + modulus = base_ring.order() + try: + from . import polynomial_modn_dense_ntl as modn_dense_ntl + except ImportError: + if given_implementation: + raise + continue + if modulus < ZZ(modn_dense_ntl.zz_p_max): + element_class = modn_dense_ntl.Polynomial_dense_modn_ntl_zz + else: + element_class = modn_dense_ntl.Polynomial_dense_modn_ntl_ZZ + self._implementation_repr = ' (using NTL)' + break + + PolynomialRing_commutative.__init__(self, base_ring, name=name, implementation=implementation, + element_class=element_class, category=category) @staticmethod def _implementation_names_impl(implementation, base_ring, sparse): @@ -3106,7 +3242,7 @@ def _repr_(self): TESTS:: sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_integral_domain as PRing - sage: R = PRing(ZZ, 'x', implementation='NTL'); R + sage: R = PRing(ZZ, 'x', implementation='NTL'); R # needs sage.libs.ntl Univariate Polynomial Ring in x over Integer Ring (using NTL) """ s = PolynomialRing_commutative._repr_(self) @@ -3118,23 +3254,31 @@ def residue_field(self, ideal, names=None): EXAMPLES:: + sage: # needs sage.libs.ntl sage: R.<t> = GF(2)[] - sage: k.<a> = R.residue_field(t^3+t+1); k - Residue field in a of Principal ideal (t^3 + t + 1) of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + sage: k.<a> = R.residue_field(t^3 + t + 1); k + Residue field in a + of Principal ideal (t^3 + t + 1) of Univariate Polynomial Ring in t + over Finite Field of size 2 (using GF2X) sage: k.list() [0, a, a^2, a + 1, a^2 + a, a^2 + a + 1, a^2 + 1, 1] sage: R.residue_field(t) - Residue field of Principal ideal (t) of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + Residue field of Principal ideal (t) of Univariate Polynomial Ring in t + over Finite Field of size 2 (using GF2X) sage: P = R.irreducible_element(8) * R sage: P - Principal ideal (t^8 + t^4 + t^3 + t^2 + 1) of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + Principal ideal (t^8 + t^4 + t^3 + t^2 + 1) of Univariate Polynomial Ring in t + over Finite Field of size 2 (using GF2X) sage: k.<a> = R.residue_field(P); k - Residue field in a of Principal ideal (t^8 + t^4 + t^3 + t^2 + 1) of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) + Residue field in a + of Principal ideal (t^8 + t^4 + t^3 + t^2 + 1) of Univariate Polynomial Ring in t + over Finite Field of size 2 (using GF2X) sage: k.cardinality() 256 Non-maximal ideals are not accepted:: + sage: # needs sage.libs.ntl sage: R.residue_field(t^2 + 1) Traceback (most recent call last): ... @@ -3157,34 +3301,35 @@ def residue_field(self, ideal, names=None): class PolynomialRing_dense_mod_p(PolynomialRing_dense_finite_field, PolynomialRing_dense_mod_n, PolynomialRing_singular_repr): - def __init__(self, base_ring, name="x", implementation=None, category=None): + def __init__(self, base_ring, name="x", implementation=None, element_class=None, category=None): """ TESTS:: - sage: P = GF(2)['x']; P + sage: P = GF(2)['x']; P # needs sage.libs.ntl Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) - sage: type(P.gen()) + sage: type(P.gen()) # needs sage.libs.ntl <class 'sage.rings.polynomial.polynomial_gf2x.Polynomial_GF2X'> sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_mod_p sage: P = PolynomialRing_dense_mod_p(GF(5), 'x'); P Univariate Polynomial Ring in x over Finite Field of size 5 - sage: type(P.gen()) + sage: type(P.gen()) # needs sage.libs.flint <class 'sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint'> + sage: # needs sage.libs.ntl sage: P = PolynomialRing_dense_mod_p(GF(5), 'x', implementation='NTL'); P Univariate Polynomial Ring in x over Finite Field of size 5 (using NTL) sage: type(P.gen()) <class 'sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_mod_p'> - sage: P = PolynomialRing_dense_mod_p(GF(9223372036854775837), 'x') - sage: P + sage: P = PolynomialRing_dense_mod_p(GF(9223372036854775837), 'x'); P # needs sage.libs.ntl sage.rings.finite_rings Univariate Polynomial Ring in x over Finite Field of size 9223372036854775837 (using NTL) - sage: type(P.gen()) + sage: type(P.gen()) # needs sage.libs.ntl sage.rings.finite_rings <class 'sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_mod_p'> This caching bug was fixed in :trac:`24264`:: + sage: # needs sage.rings.finite_rings sage: p = 2^64 + 13 sage: A = GF(p^2) sage: B = GF(p^3) @@ -3193,21 +3338,37 @@ def __init__(self, base_ring, name="x", implementation=None, category=None): sage: R is S True """ - implementation = self._implementation_names(implementation, base_ring)[0] - if implementation == "FLINT": - from .polynomial_zmod_flint import \ - Polynomial_zmod_flint as element_class - self._implementation_repr = '' - elif implementation == "NTL": - from .polynomial_modn_dense_ntl import \ - Polynomial_dense_mod_p as element_class - self._implementation_repr = ' (using NTL)' - elif implementation == "GF2X": - from .polynomial_gf2x import \ - Polynomial_GF2X as element_class - self._implementation_repr = ' (using GF2X)' - PolynomialRing_dense_mod_n.__init__(self, base_ring, name=name, - element_class=element_class, category=category) + if element_class is None: + given_implementation = implementation + for implementation in self._implementation_names(implementation, base_ring): + if implementation == "FLINT": + try: + from .polynomial_zmod_flint import Polynomial_zmod_flint as element_class + except ImportError: + if given_implementation: + raise + continue + self._implementation_repr = '' + elif implementation == "NTL": + try: + from .polynomial_modn_dense_ntl import Polynomial_dense_mod_p as element_class + except ImportError: + if given_implementation: + raise + continue + self._implementation_repr = ' (using NTL)' + elif implementation == "GF2X": + try: + from .polynomial_gf2x import Polynomial_GF2X as element_class + except ImportError: + if given_implementation: + raise + continue + self._implementation_repr = ' (using GF2X)' + break + + PolynomialRing_dense_mod_n.__init__(self, base_ring, name=name, implementation=implementation, + element_class=element_class, category=category) self._has_singular = can_convert_to_singular(self) @@ -3216,18 +3377,20 @@ def _implementation_names_impl(implementation, base_ring, sparse): """ TESTS:: + sage: # needs sage.libs.ntl sage: PolynomialRing(GF(2), 'x', implementation="GF2X") Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) sage: PolynomialRing(GF(2), 'x', implementation="NTL") Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) sage: PolynomialRing(GF(2), 'x', implementation=None) Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) - sage: PolynomialRing(GF(2), 'x', implementation="FLINT") - Univariate Polynomial Ring in x over Finite Field of size 2 sage: PolynomialRing(GF(3), 'x', implementation="GF2X") Traceback (most recent call last): ... ValueError: GF2X only supports modulus 2 + + sage: PolynomialRing(GF(2), 'x', implementation="FLINT") # needs sage.libs.flint + Univariate Polynomial Ring in x over Finite Field of size 2 """ if sparse: return NotImplemented @@ -3260,13 +3423,13 @@ def irreducible_element(self, n, algorithm=None): Currently available options are: - ``'adleman-lenstra'``: a variant of the Adleman--Lenstra - algorithm as implemented in PARI. + algorithm as implemented in PARI. - ``'conway'``: look up the Conway polynomial of degree `n` over the field of `p` elements in the database; raise a ``RuntimeError`` if it is not found. - - ``'ffprimroot'``: use the ``ffprimroot()`` function from + - ``'ffprimroot'``: use the :pari:`ffprimroot` function from PARI. - ``'first_lexicographic'``: return the lexicographically @@ -3279,7 +3442,7 @@ def irreducible_element(self, n, algorithm=None): - ``'primitive'``: return a polynomial `f` such that a root of `f` generates the multiplicative group of the finite field extension defined by `f`. This uses the Conway polynomial if - possible, otherwise it uses ``ffprimroot``. + possible, otherwise it uses ``'ffprimroot'``. - ``'random'``: try random polynomials until an irreducible one is found. @@ -3287,7 +3450,7 @@ def irreducible_element(self, n, algorithm=None): If ``algorithm`` is ``None``, use `x - 1` in degree 1. In degree > 1, the Conway polynomial is used if it is found in the database. Otherwise, the algorithm ``minimal_weight`` - is used if `p = 2`, and the algorithm ``adleman-lenstra`` if + is used if `p = 2`, and the algorithm ``'adleman-lenstra'`` if `p > 2`. OUTPUT: @@ -3296,6 +3459,7 @@ def irreducible_element(self, n, algorithm=None): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: GF(5)['x'].irreducible_element(2) x^2 + 4*x + 2 sage: GF(5)['x'].irreducible_element(2, algorithm="adleman-lenstra") @@ -3313,18 +3477,18 @@ def irreducible_element(self, n, algorithm=None): In characteristic 2:: - sage: GF(2)['x'].irreducible_element(33) + sage: GF(2)['x'].irreducible_element(33) # needs sage.rings.finite_rings x^33 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^3 + 1 - sage: GF(2)['x'].irreducible_element(33, algorithm="minimal_weight") + sage: GF(2)['x'].irreducible_element(33, algorithm="minimal_weight") # needs sage.rings.finite_rings x^33 + x^10 + 1 In degree 1:: - sage: GF(97)['x'].irreducible_element(1) + sage: GF(97)['x'].irreducible_element(1) # needs sage.rings.finite_rings x + 96 - sage: GF(97)['x'].irreducible_element(1, algorithm="conway") + sage: GF(97)['x'].irreducible_element(1, algorithm="conway") # needs sage.rings.finite_rings x + 92 - sage: GF(97)['x'].irreducible_element(1, algorithm="adleman-lenstra") + sage: GF(97)['x'].irreducible_element(1, algorithm="adleman-lenstra") # needs sage.rings.finite_rings x AUTHORS: @@ -3337,9 +3501,6 @@ def irreducible_element(self, n, algorithm=None): from sage.libs.pari.all import pari from sage.rings.finite_rings.conway_polynomials import (conway_polynomial, exists_conway_polynomial) - from .polynomial_gf2x import (GF2X_BuildIrred_list, - GF2X_BuildSparseIrred_list, - GF2X_BuildRandomIrred_list) p = self.characteristic() n = int(n) @@ -3352,7 +3513,12 @@ def irreducible_element(self, n, algorithm=None): elif exists_conway_polynomial(p, n): algorithm = "conway" elif p == 2: - algorithm = "minimal_weight" + try: + from .polynomial_gf2x import GF2X_BuildSparseIrred_list + except ImportError: + algorithm = "adleman-lenstra" + else: + algorithm = "minimal_weight" else: algorithm = "adleman-lenstra" elif algorithm == "primitive": @@ -3367,6 +3533,7 @@ def irreducible_element(self, n, algorithm=None): return self(conway_polynomial(p, n)) elif algorithm == "first_lexicographic": if p == 2: + from .polynomial_gf2x import GF2X_BuildIrred_list return self(GF2X_BuildIrred_list(n)) else: # Fallback to PolynomialRing_dense_finite_field.irreducible_element @@ -3375,11 +3542,13 @@ def irreducible_element(self, n, algorithm=None): return self(pari(p).ffinit(n).ffgen().ffprimroot().charpoly()) elif algorithm == "minimal_weight": if p == 2: + from .polynomial_gf2x import GF2X_BuildSparseIrred_list return self(GF2X_BuildSparseIrred_list(n)) else: raise NotImplementedError("'minimal_weight' option only implemented for p = 2") elif algorithm == "random": if p == 2: + from .polynomial_gf2x import GF2X_BuildRandomIrred_list return self(GF2X_BuildRandomIrred_list(n)) else: pass @@ -3393,9 +3562,9 @@ def polygen(ring_or_element, name="x"): INPUT: - - polygen(base_ring, name="x") + - ``polygen(base_ring, name="x")`` - - polygen(ring_element, name="x") + - ``polygen(ring_element, name="x")`` If the first input is a ring, return a polynomial generator over that ring. If it is a ring element, return a polynomial generator @@ -3403,7 +3572,7 @@ def polygen(ring_or_element, name="x"): EXAMPLES:: - sage: z = polygen(QQ,'z') + sage: z = polygen(QQ, 'z') sage: z^3 + z +1 z^3 + z + 1 sage: parent(z) @@ -3411,9 +3580,9 @@ def polygen(ring_or_element, name="x"): .. note:: - If you give a list or comma separated string to polygen, you'll + If you give a list or comma-separated string to :func:`polygen`, you'll get a tuple of indeterminates, exactly as if you called - polygens. + :func:`polygens`. """ if is_RingElement(ring_or_element): base_ring = ring_or_element.parent() @@ -3440,7 +3609,7 @@ def polygens(base_ring, names="x", *args): x^2 + 2*x*y + y^2 + 2*x*z + 2*y*z + z^2 sage: parent(x) Multivariate Polynomial Ring in x, y, z over Rational Field - sage: t = polygens(QQ,['x','yz','abc']) + sage: t = polygens(QQ, ['x','yz','abc']) sage: t (x, yz, abc) diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index 65e67cc3527..ecccc51519e 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -22,11 +22,19 @@ # **************************************************************************** from sage.structure.category_object import normalize_names import sage.rings.ring as ring -import sage.rings.padics.padic_base_leaves as padic_base_leaves + +try: + import sage.rings.padics.padic_base_leaves as padic_base_leaves +except ImportError: + class padic_base_leaves: + pAdicFieldCappedRelative = () + pAdicRingCappedRelative = () + pAdicRingCappedAbsolute = () + pAdicRingFixedMod = () import sage.rings.abc from sage.rings.integer import Integer -from sage.rings.finite_rings.finite_field_base import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.misc.cachefunc import weak_cached_function import sage.misc.weak_dict @@ -114,7 +122,7 @@ def PolynomialRing(base_ring, *args, **kwds): one multivariate polynomial ring over each base ring for each choice of names of variables and term order. The names of the generators can only be temporarily changed after the ring has been - created. Do this using the localvars context: + created. Do this using the :func:`localvars` context. EXAMPLES: @@ -145,7 +153,8 @@ def PolynomialRing(base_ring, *args, **kwds): Sparse Univariate Polynomial Ring in abc over Rational Field sage: R.<w> = PolynomialRing(PolynomialRing(GF(7),'k')); R - Univariate Polynomial Ring in w over Univariate Polynomial Ring in k over Finite Field of size 7 + Univariate Polynomial Ring in w over + Univariate Polynomial Ring in k over Finite Field of size 7 The square bracket notation:: @@ -164,7 +173,7 @@ def PolynomialRing(base_ring, *args, **kwds): This is exactly the same ring as what PolynomialRing returns:: - sage: R is PolynomialRing(QQ,'zz') + sage: R is PolynomialRing(QQ, 'zz') True However, rings with different variables are different:: @@ -179,32 +188,32 @@ def PolynomialRing(base_ring, *args, **kwds): like 2^1000000 * x^1000000 in FLINT may be unwise. :: - sage: ZxNTL = PolynomialRing(ZZ, 'x', implementation='NTL'); ZxNTL + sage: ZxNTL = PolynomialRing(ZZ, 'x', implementation='NTL'); ZxNTL # needs sage.libs.ntl Univariate Polynomial Ring in x over Integer Ring (using NTL) - sage: ZxFLINT = PolynomialRing(ZZ, 'x', implementation='FLINT'); ZxFLINT + sage: ZxFLINT = PolynomialRing(ZZ, 'x', implementation='FLINT'); ZxFLINT # needs sage.libs.flint Univariate Polynomial Ring in x over Integer Ring - sage: ZxFLINT is ZZ['x'] + sage: ZxFLINT is ZZ['x'] # needs sage.libs.flint True - sage: ZxFLINT is PolynomialRing(ZZ, 'x') + sage: ZxFLINT is PolynomialRing(ZZ, 'x') # needs sage.libs.flint True - sage: xNTL = ZxNTL.gen() - sage: xFLINT = ZxFLINT.gen() - sage: xNTL.parent() + sage: xNTL = ZxNTL.gen() # needs sage.libs.ntl + sage: xFLINT = ZxFLINT.gen() # needs sage.libs.flint + sage: xNTL.parent() # needs sage.libs.ntl Univariate Polynomial Ring in x over Integer Ring (using NTL) - sage: xFLINT.parent() + sage: xFLINT.parent() # needs sage.libs.flint Univariate Polynomial Ring in x over Integer Ring There is a coercion from the non-default to the default implementation, so the values can be mixed in a single expression:: - sage: (xNTL + xFLINT^2) + sage: (xNTL + xFLINT^2) # needs sage.libs.flint sage.libs.ntl x^2 + x The result of such an expression will use the default, i.e., the FLINT implementation:: - sage: (xNTL + xFLINT^2).parent() + sage: (xNTL + xFLINT^2).parent() # needs sage.libs.flint sage.libs.ntl Univariate Polynomial Ring in x over Integer Ring The generic implementation uses neither NTL nor FLINT:: @@ -259,9 +268,9 @@ def PolynomialRing(base_ring, *args, **kwds): The Singular implementation always returns a multivariate ring, even for 1 variable:: - sage: PolynomialRing(QQ, "x", implementation="singular") + sage: PolynomialRing(QQ, "x", implementation="singular") # needs sage.libs.singular Multivariate Polynomial Ring in x over Rational Field - sage: P.<x> = PolynomialRing(QQ, implementation="singular"); P + sage: P.<x> = PolynomialRing(QQ, implementation="singular"); P # needs sage.libs.singular Multivariate Polynomial Ring in x over Rational Field **3. PolynomialRing(base_ring, n, names, ...)** (where the arguments @@ -298,16 +307,19 @@ def PolynomialRing(base_ring, *args, **kwds): example, here is a ring with generators labeled by the primes less than 100:: - sage: R = PolynomialRing(ZZ, ['x%s'%p for p in primes(100)]); R - Multivariate Polynomial Ring in x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, x31, x37, x41, x43, x47, x53, x59, x61, x67, x71, x73, x79, x83, x89, x97 over Integer Ring + sage: R = PolynomialRing(ZZ, ['x%s'%p for p in primes(100)]); R # needs sage.libs.pari + Multivariate Polynomial Ring in x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, + x31, x37, x41, x43, x47, x53, x59, x61, x67, x71, x73, x79, x83, x89, x97 + over Integer Ring By calling the :meth:`~sage.structure.category_object.CategoryObject.inject_variables` method, all those variable names are available for interactive use:: - sage: R.inject_variables() - Defining x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, x31, x37, x41, x43, x47, x53, x59, x61, x67, x71, x73, x79, x83, x89, x97 - sage: (x2 + x41 + x71)^2 + sage: R.inject_variables() # needs sage.libs.pari + Defining x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, x31, x37, x41, x43, + x47, x53, x59, x61, x67, x71, x73, x79, x83, x89, x97 + sage: (x2 + x41 + x71)^2 # needs sage.libs.pari x2^2 + 2*x2*x41 + x41^2 + 2*x2*x71 + 2*x41*x71 + x71^2 **4. PolynomialRing(base_ring, n, ..., var_array=var_array, ...)** @@ -323,9 +335,13 @@ def PolynomialRing(base_ring, *args, **kwds): It is possible to create higher-dimensional arrays:: sage: PolynomialRing(ZZ, 2, 3, var_array=('p', 'q')) - Multivariate Polynomial Ring in p00, q00, p01, q01, p02, q02, p10, q10, p11, q11, p12, q12 over Integer Ring + Multivariate Polynomial Ring + in p00, q00, p01, q01, p02, q02, p10, q10, p11, q11, p12, q12 + over Integer Ring sage: PolynomialRing(ZZ, 2, 3, 4, var_array='m') - Multivariate Polynomial Ring in m000, m001, m002, m003, m010, m011, m012, m013, m020, m021, m022, m023, m100, m101, m102, m103, m110, m111, m112, m113, m120, m121, m122, m123 over Integer Ring + Multivariate Polynomial Ring in m000, m001, m002, m003, m010, m011, + m012, m013, m020, m021, m022, m023, m100, m101, m102, m103, m110, + m111, m112, m113, m120, m121, m122, m123 over Integer Ring The array is always at least 2-dimensional. So, if ``var_array`` is a single string and only a single number `n` @@ -339,6 +355,7 @@ def PolynomialRing(base_ring, *args, **kwds): You can alternatively create a polynomial ring over a ring `R` with square brackets:: + sage: # needs sage.rings.real_mpfr sage: RR["x"] Univariate Polynomial Ring in x over Real Field with 53 bits of precision sage: RR["x,y"] @@ -352,7 +369,7 @@ def PolynomialRing(base_ring, *args, **kwds): Consider :: - sage: R.<x,y> = PolynomialRing(QQ,2); R + sage: R.<x,y> = PolynomialRing(QQ, 2); R Multivariate Polynomial Ring in x, y over Rational Field sage: f = x^2 - 2*y^2 @@ -391,9 +408,9 @@ def PolynomialRing(base_ring, *args, **kwds): Check uniqueness if the same implementation is used for different values of the ``"implementation"`` keyword:: - sage: R = PolynomialRing(QQbar, 'j', implementation="generic") - sage: S = PolynomialRing(QQbar, 'j', implementation=None) - sage: R is S + sage: R = PolynomialRing(QQbar, 'j', implementation="generic") # needs sage.rings.number_field + sage: S = PolynomialRing(QQbar, 'j', implementation=None) # needs sage.rings.number_field + sage: R is S # needs sage.rings.number_field True sage: R = PolynomialRing(ZZ['t'], 'j', implementation="generic") @@ -401,11 +418,13 @@ def PolynomialRing(base_ring, *args, **kwds): sage: R is S True + sage: # needs sage.rings.number_field sage: R = PolynomialRing(QQbar, 'j,k', implementation="generic") sage: S = PolynomialRing(QQbar, 'j,k', implementation=None) sage: R is S True + sage: # needs sage.libs.singular sage: R = PolynomialRing(ZZ, 'j,k', implementation="singular") sage: S = PolynomialRing(ZZ, 'j,k', implementation=None) sage: R is S @@ -423,9 +442,9 @@ def PolynomialRing(base_ring, *args, **kwds): sage: S = PolynomialRing(GF(2), 'j'); TestSuite(S).run(); type(S) <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_mod_p_with_category'> - sage: R = PolynomialRing(ZZ, 'x,y', implementation="generic"); TestSuite(R).run(skip=['_test_elements', '_test_elements_eq_transitive']); type(R) + sage: R = PolynomialRing(ZZ, 'x,y', implementation="generic"); TestSuite(R).run(skip=['_test_elements', '_test_elements_eq_transitive']); type(R) # needs sage.libs.singular <class 'sage.rings.polynomial.multi_polynomial_ring.MPolynomialRing_polydict_domain_with_category'> - sage: S = PolynomialRing(ZZ, 'x,y'); TestSuite(S).run(skip='_test_elements'); type(S) + sage: S = PolynomialRing(ZZ, 'x,y'); TestSuite(S).run(skip='_test_elements'); type(S) # needs sage.libs.singular <class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomialRing_libsingular'> Sparse univariate polynomials only support a generic @@ -433,7 +452,7 @@ def PolynomialRing(base_ring, *args, **kwds): sage: R = PolynomialRing(ZZ, 'j', sparse=True); TestSuite(R).run(); type(R) <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_integral_domain_with_category'> - sage: R = PolynomialRing(GF(49), 'j', sparse=True); TestSuite(R).run(); type(R) + sage: R = PolynomialRing(GF(49), 'j', sparse=True); TestSuite(R).run(); type(R) # needs sage.rings.finite_rings <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category'> If the requested implementation is not known or not supported for @@ -451,7 +470,7 @@ def PolynomialRing(base_ring, *args, **kwds): Traceback (most recent call last): ... ValueError: unknown implementation 'FLINT' for multivariate polynomial rings - sage: R.<x> = PolynomialRing(QQbar, implementation="whatever") + sage: R.<x> = PolynomialRing(QQbar, implementation="whatever") # needs sage.rings.number_field Traceback (most recent call last): ... ValueError: unknown implementation 'whatever' for dense polynomial rings over Algebraic Field @@ -463,7 +482,7 @@ def PolynomialRing(base_ring, *args, **kwds): Traceback (most recent call last): ... ValueError: unknown implementation 'whatever' for multivariate polynomial rings - sage: PolynomialRing(RR, name="x", implementation="singular") + sage: PolynomialRing(RR, name="x", implementation="singular") # needs sage.libs.singular Traceback (most recent call last): ... NotImplementedError: polynomials over Real Field with 53 bits of precision are not supported in Singular @@ -478,18 +497,20 @@ def PolynomialRing(base_ring, *args, **kwds): We verify that :trac:`13187` is fixed:: - sage: var('t') + sage: var('t') # needs sage.symbolic t - sage: PolynomialRing(ZZ, name=t) == PolynomialRing(ZZ, name='t') + sage: PolynomialRing(ZZ, name=t) == PolynomialRing(ZZ, name='t') # needs sage.symbolic True We verify that polynomials with interval coefficients from :trac:`7712` and :trac:`13760` are fixed:: + sage: # needs sage.rings.real_interval_field sage: P.<y,z> = PolynomialRing(RealIntervalField(2)) sage: TestSuite(P).run(skip=['_test_elements', '_test_elements_eq_transitive']) sage: Q.<x> = PolynomialRing(P) - sage: TestSuite(Q).run(skip=['_test_additive_associativity', '_test_associativity', '_test_distributivity', '_test_prod']) + sage: TestSuite(Q).run(skip=['_test_additive_associativity', '_test_associativity', + ....: '_test_distributivity', '_test_prod']) sage: C = (y-x)^3 sage: C(y/2) 1.?*y^3 @@ -557,7 +578,7 @@ def PolynomialRing(base_ring, *args, **kwds): sage: R.<w> = PolynomialRing(PolynomialRing(GF(7),'k')); TestSuite(R).run(); R Univariate Polynomial Ring in w over Univariate Polynomial Ring in k over Finite Field of size 7 - sage: ZxNTL = PolynomialRing(ZZ, 'x', implementation='NTL'); TestSuite(ZxNTL).run(skip='_test_pickling'); ZxNTL + sage: ZxNTL = PolynomialRing(ZZ, 'x', implementation='NTL'); TestSuite(ZxNTL).run(skip='_test_pickling'); ZxNTL # needs sage.libs.ntl Univariate Polynomial Ring in x over Integer Ring (using NTL) sage: ZxFLINT = PolynomialRing(ZZ, 'x', implementation='FLINT'); TestSuite(ZxFLINT).run(); ZxFLINT Univariate Polynomial Ring in x over Integer Ring @@ -571,7 +592,8 @@ def PolynomialRing(base_ring, *args, **kwds): Multivariate Polynomial Ring in x, y, z over Rational Field sage: Q0 = PolynomialRing(QQ,[]); TestSuite(Q0).run(skip=['_test_elements', '_test_elements_eq_transitive', '_test_gcd_vs_xgcd', '_test_quo_rem']); Q0 Multivariate Polynomial Ring in no variables over Rational Field - sage: P.<x> = PolynomialRing(QQ, implementation="singular"); TestSuite(P).run(skip=['_test_construction', '_test_elements', '_test_euclidean_degree', '_test_quo_rem']); P + sage: P.<x> = PolynomialRing(QQ, implementation="singular"); TestSuite(P).run(skip=['_test_construction', '_test_elements', # needs sage.libs.singular + ....: '_test_euclidean_degree', '_test_quo_rem']); P Multivariate Polynomial Ring in x over Rational Field sage: Q1 = PolynomialRing(QQ,"x",1); TestSuite(Q1).run(skip=['_test_construction', '_test_elements', '_test_euclidean_degree', '_test_quo_rem']); Q1 Multivariate Polynomial Ring in x over Rational Field @@ -583,11 +605,11 @@ def PolynomialRing(base_ring, *args, **kwds): <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_mod_p_with_category'> sage: R = PolynomialRing(ZZ, 'x,y', implementation="generic"); TestSuite(R).run(skip=['_test_elements', '_test_elements_eq_transitive']); type(R) <class 'sage.rings.polynomial.multi_polynomial_ring.MPolynomialRing_polydict_domain_with_category'> - sage: S = PolynomialRing(ZZ, 'x,y'); TestSuite(S).run(skip='_test_elements'); type(S) + sage: S = PolynomialRing(ZZ, 'x,y'); TestSuite(S).run(skip='_test_elements'); type(S) # needs sage.libs.singular <class 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomialRing_libsingular'> sage: R = PolynomialRing(ZZ, 'j', sparse=True); TestSuite(R).run(); type(R) <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_integral_domain_with_category'> - sage: R = PolynomialRing(GF(49), 'j', sparse=True); TestSuite(R).run(); type(R) + sage: R = PolynomialRing(GF(49), 'j', sparse=True); TestSuite(R).run(); type(R) # needs sage.rings.finite_rings <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category'> sage: P.<y,z> = PolynomialRing(RealIntervalField(2)) sage: TestSuite(P).run(skip=['_test_elements', '_test_elements_eq_transitive']) @@ -747,7 +769,7 @@ def _single_variate(base_ring, name, sparse=None, implementation=None, order=Non specialized = polynomial_ring.PolynomialRing_dense_mod_p elif n > 1: # Specialized code breaks for n == 1 specialized = polynomial_ring.PolynomialRing_dense_mod_n - elif is_FiniteField(base_ring): + elif isinstance(base_ring, FiniteField): specialized = polynomial_ring.PolynomialRing_dense_finite_field elif isinstance(base_ring, padic_base_leaves.pAdicFieldCappedRelative): specialized = polynomial_ring.PolynomialRing_dense_padic_field_capped_relative @@ -762,7 +784,6 @@ def _single_variate(base_ring, name, sparse=None, implementation=None, order=Non if specialized is not None: implementation_names = specialized._implementation_names_impl(implementation, base_ring, sparse) if implementation_names is not NotImplemented: - implementation = implementation_names[0] constructor = specialized # Generic implementations @@ -780,7 +801,6 @@ def _single_variate(base_ring, name, sparse=None, implementation=None, order=Non else: constructor = polynomial_ring.PolynomialRing_commutative implementation_names = constructor._implementation_names(implementation, base_ring, sparse) - implementation = implementation_names[0] # Only use names which are not supported by the specialized class. if specialized is not None: @@ -819,10 +839,10 @@ def _multi_variate(base_ring, names, sparse=None, order="degrevlex", implementat implementation_names = set([implementation]) if implementation is None or implementation == "singular": - from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular try: + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular R = MPolynomialRing_libsingular(base_ring, n, names, order) - except (TypeError, NotImplementedError): + except (ImportError, TypeError, NotImplementedError): if implementation is not None: raise else: @@ -932,44 +952,43 @@ def BooleanPolynomialRing_constructor(n=None, names=None, order="lex"): - ``n`` -- number of variables (an integer > 1) - ``names`` -- names of ring variables, may be a string or list/tuple of strings - - ``order`` -- term order (default: lex) + - ``order`` -- term order (default: ``'lex'``) EXAMPLES:: - sage: R.<x, y, z> = BooleanPolynomialRing() # indirect doctest - sage: R + sage: # needs sage.rings.polynomial.pbori + sage: R.<x, y, z> = BooleanPolynomialRing(); R # indirect doctest Boolean PolynomialRing in x, y, z - sage: p = x*y + x*z + y*z sage: x*p x*y*z + x*y + x*z - sage: R.term_order() Lexicographic term order - sage: R = BooleanPolynomialRing(5,'x',order='deglex(3),deglex(2)') - sage: R.term_order() + sage: R = BooleanPolynomialRing(5, 'x', order='deglex(3),deglex(2)') # needs sage.rings.polynomial.pbori + sage: R.term_order() # needs sage.rings.polynomial.pbori Block term order with blocks: (Degree lexicographic term order of length 3, Degree lexicographic term order of length 2) - sage: R = BooleanPolynomialRing(3,'x',order='degneglex') - sage: R.term_order() + sage: R = BooleanPolynomialRing(3, 'x', order='degneglex') # needs sage.rings.polynomial.pbori + sage: R.term_order() # needs sage.rings.polynomial.pbori Degree negative lexicographic term order - sage: BooleanPolynomialRing(names=('x','y')) + sage: BooleanPolynomialRing(names=('x','y')) # needs sage.rings.polynomial.pbori Boolean PolynomialRing in x, y - sage: BooleanPolynomialRing(names='x,y') + sage: BooleanPolynomialRing(names='x,y') # needs sage.rings.polynomial.pbori Boolean PolynomialRing in x, y TESTS:: - sage: P.<x,y> = BooleanPolynomialRing(2,order='deglex') - sage: x > y + sage: P.<x,y> = BooleanPolynomialRing(2, order='deglex') # needs sage.rings.polynomial.pbori + sage: x > y # needs sage.rings.polynomial.pbori True - sage: P.<x0, x1, x2, x3> = BooleanPolynomialRing(4,order='deglex(2),deglex(2)') + sage: # needs sage.rings.polynomial.pbori + sage: P.<x0, x1, x2, x3> = BooleanPolynomialRing(4, order='deglex(2),deglex(2)') sage: x0 > x1 True sage: x2 > x3 diff --git a/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx b/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx index 18140a24981..7e3e27dd520 100644 --- a/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx +++ b/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx @@ -55,7 +55,7 @@ cdef class PolynomialRingHomomorphism_from_base(RingHomomorphism_from_base): sage: g = QQ.hom(RR) sage: G = PolynomialRingHomomorphism_from_base(A.Hom(B), g) sage: G(A.gen()^1000000) - 1.00000000000000*x^1000000 + 1.0...*x^1000000 """ P = self.codomain() @@ -76,9 +76,10 @@ cdef class PolynomialRingHomomorphism_from_base(RingHomomorphism_from_base): sage: S = GF(5)['x'] sage: f = ZZ.hom(GF(5)) sage: F = PolynomialRingHomomorphism_from_base(R.Hom(S), f) - sage: F(2*x, check=True) + sage: F(2 * x, check=True) 2*x + sage: # needs sage.rings.finite_rings sage: k = GF(49, 'z') sage: A = PolynomialRing(GF(7), 'x', sparse=True) sage: B = PolynomialRing(k, 'x', sparse=True) diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index 2b5bfd4bf94..257eaf4c267 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -5,13 +5,13 @@ - Martin Albrecht <malb@informatik.uni-bremen.de> (2006-04-21) - Robert Bradshaw: Re-factor to avoid multiple inheritance vs. Cython (2007-09) -- Syed Ahmad Lavasani: Added function field to _singular_init_ (2011-12-16) - Added non-prime finite fields to _singular_init_ (2012-1-22) +- Syed Ahmad Lavasani: Added function field to _singular_init_ (2011-12-16); + Added non-prime finite fields to _singular_init_ (2012-1-22) TESTS:: - sage: R = PolynomialRing(GF(2**8,'a'),10,'x', order='invlex') - sage: R == loads(dumps(R)) + sage: R = PolynomialRing(GF(2**8,'a'), 10, 'x', order='invlex') # needs sage.rings.finite_rings + sage: R == loads(dumps(R)) # needs sage.rings.finite_rings True sage: P.<a,b> = PolynomialRing(GF(7), 2) sage: f = (a^3 + 2*b^2*a)^7; f @@ -41,11 +41,16 @@ import sage.rings.abc import sage.rings.number_field as number_field -from sage.interfaces.singular import singular +try: + from sage.interfaces.singular import singular +except ImportError: + singular = None + from sage.rings.rational_field import is_RationalField -from sage.rings.function_field.function_field import RationalFunctionField -from sage.rings.finite_rings.finite_field_base import is_FiniteField +from sage.rings.function_field.function_field_rational import RationalFunctionField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field_base import NumberField import sage.rings.finite_rings.finite_field_constructor @@ -60,7 +65,7 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): TESTS:: sage: from sage.rings.polynomial.polynomial_singular_interface import _do_singular_init_ - sage: _do_singular_init_(singular, ZZ, 0, 'X', 'dp') + sage: _do_singular_init_(singular, ZZ, 0, 'X', 'dp') # needs sage.libs.singular (polynomial ring, over a domain, global ordering // coefficients: ZZ // number of vars : 1 @@ -103,13 +108,13 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): elif isinstance(base_ring, sage.rings.abc.IntegerModRing): char = base_ring.characteristic() - if sage.rings.finite_rings.finite_field_constructor.is_FiniteField(base_ring) and char <= 2147483647: + if isinstance(base_ring, FiniteField) and char <= 2147483647: return make_ring(str(char)), None if char.is_power_of(2): return make_ring(f"(integer,2,{char.nbits()-1})"), None return make_ring(f"(integer,{char})"), None - elif sage.rings.finite_rings.finite_field_constructor.is_FiniteField(base_ring): + elif isinstance(base_ring, FiniteField): # not the prime field! gen = str(base_ring.gen()) R = make_ring(f"({char},{gen})") @@ -121,7 +126,7 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): return R, minpoly - elif number_field.number_field_base.is_NumberField(base_ring) and base_ring.is_absolute(): + elif isinstance(base_ring, NumberField) and base_ring.is_absolute(): # not the rationals! gen = str(base_ring.gen()) poly = base_ring.polynomial() @@ -148,7 +153,7 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): if B.is_prime_field() or B is ZZ: return make_ring(f"({base_char},{gens})"), None - if is_FiniteField(B) and B.characteristic() <= 2147483647: + if isinstance(B, FiniteField) and B.characteristic() <= 2147483647: ext_gen = str(B.gen()) _vars = '(' + ext_gen + ', ' + _vars[1:] @@ -162,7 +167,7 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): return singular(f"std(ideal({base_ring.__minpoly}))", type='qring'), None - elif isinstance(base_ring, sage.rings.function_field.function_field.RationalFunctionField) \ + elif isinstance(base_ring, RationalFunctionField) \ and base_ring.constant_field().is_prime_field(): gen = str(base_ring.gen()) return make_ring(f"({base_ring.characteristic()},{gen})"), None @@ -193,8 +198,8 @@ def _singular_(self, singular=singular): EXAMPLES:: - sage: R.<x,y> = PolynomialRing(CC) - sage: singular(R) + sage: R.<x,y> = PolynomialRing(CC) # needs sage.rings.real_mpfr + sage: singular(R) # needs sage.libs.singular sage.rings.real_mpfr polynomial ring, over a field, global ordering // coefficients: real[I](complex:15 digits, additional 0 digits)/(I^2+1) // number of vars : 2 @@ -202,8 +207,8 @@ def _singular_(self, singular=singular): // : names x y // block 2 : ordering C - sage: R.<x,y> = PolynomialRing(RealField(100)) - sage: singular(R) + sage: R.<x,y> = PolynomialRing(RealField(100)) # needs sage.rings.real_mpfr + sage: singular(R) # needs sage.libs.singular sage.rings.real_mpfr polynomial ring, over a field, global ordering // coefficients: Float() // number of vars : 2 @@ -211,10 +216,9 @@ def _singular_(self, singular=singular): // : names x y // block 2 : ordering C - sage: w = var('w') - - sage: R.<x> = PolynomialRing(NumberField(w^2+1,'s')) - sage: singular(R) + sage: w = polygen(ZZ, 'w') + sage: R.<x> = PolynomialRing(NumberField(w^2 + 1, 's')) # needs sage.rings.number_field + sage: singular(R) # needs sage.libs.singular sage.rings.number_field polynomial ring, over a field, global ordering // coefficients: QQ[s]/(s^2+1) // number of vars : 1 @@ -222,8 +226,8 @@ def _singular_(self, singular=singular): // : names x // block 2 : ordering C - sage: R = PolynomialRing(GF(127), 'x', implementation="singular") - sage: singular(R) + sage: R = PolynomialRing(GF(127), 'x', implementation="singular") # needs sage.libs.singular + sage: singular(R) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 1 @@ -231,8 +235,8 @@ def _singular_(self, singular=singular): // : names x // block 2 : ordering C - sage: R = PolynomialRing(QQ, 'x', implementation="singular") - sage: singular(R) + sage: R = PolynomialRing(QQ, 'x', implementation="singular") # needs sage.libs.singular + sage: singular(R) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 @@ -241,7 +245,7 @@ def _singular_(self, singular=singular): // block 2 : ordering C sage: R = PolynomialRing(QQ,'x') - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 @@ -249,8 +253,8 @@ def _singular_(self, singular=singular): // : names x // block 2 : ordering C - sage: R = PolynomialRing(GF(127),'x') - sage: singular(R) + sage: R = PolynomialRing(GF(127), 'x') + sage: singular(R) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 1 @@ -259,7 +263,7 @@ def _singular_(self, singular=singular): // block 2 : ordering C sage: R = Frac(ZZ['a,b'])['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ(a, b) // number of vars : 2 @@ -269,7 +273,7 @@ def _singular_(self, singular=singular): sage: R = IntegerModRing(1024)['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a ring (with zero-divisors), global ordering // coefficients: ZZ/(2^10) // number of vars : 2 @@ -278,7 +282,7 @@ def _singular_(self, singular=singular): // block 2 : ordering C sage: R = IntegerModRing(15)['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a ring (with zero-divisors), global ordering // coefficients: ZZ/...(15) // number of vars : 2 @@ -287,7 +291,7 @@ def _singular_(self, singular=singular): // block 2 : ordering C sage: R = ZZ['x,y'] - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a domain, global ordering // coefficients: ZZ // number of vars : 2 @@ -296,7 +300,7 @@ def _singular_(self, singular=singular): // block 2 : ordering C sage: R = ZZ['x'] - sage: singular(R) + sage: singular(R) # needs sage.libs.singular polynomial ring, over a domain, global ordering // coefficients: ZZ // number of vars : 1 @@ -304,11 +308,12 @@ def _singular_(self, singular=singular): // : names x // block 2 : ordering C + sage: # needs sage.rings.finite_rings sage: k.<a> = FiniteField(25) sage: R = k['x'] sage: K = R.fraction_field() sage: S = K['y'] - sage: singular(S) + sage: singular(S) # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: ZZ/5(x) // number of vars : 2 @@ -333,8 +338,8 @@ def _singular_(self, singular=singular): R._check_valid() if self.base_ring() is ZZ or self.base_ring().is_prime_field(): return R - if sage.rings.finite_rings.finite_field_constructor.is_FiniteField(self.base_ring()) or \ - (number_field.number_field_base.is_NumberField(self.base_ring()) and self.base_ring().is_absolute()): + if isinstance(self.base_ring(), FiniteField) or \ + (isinstance(self.base_ring(), NumberField) and self.base_ring().is_absolute()): R.set_ring() # sorry for that, but needed for minpoly if singular.eval('minpoly') != f"({self.__minpoly})": singular.eval(f"minpoly={self.__minpoly}") @@ -349,7 +354,7 @@ def _singular_init_(self, singular=singular): EXAMPLES:: - sage: PolynomialRing(QQ,'u_ba')._singular_init_() + sage: PolynomialRing(QQ,'u_ba')._singular_init_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 @@ -398,22 +403,25 @@ def can_convert_to_singular(R): Avoid non absolute number fields (see :trac:`23535`):: - sage: K.<a,b> = NumberField([x^2-2,x^2-5]) - sage: can_convert_to_singular(K['s,t']) + sage: x = polygen(ZZ, 'x') + sage: K.<a,b> = NumberField([x^2 - 2, x^2 - 5]) # needs sage.rings.number_field + sage: can_convert_to_singular(K['s,t']) # needs sage.rings.number_field False Check for :trac:`33319`:: + sage: # needs sage.rings.finite_rings sage: R.<x,y> = GF((2^31-1)^3)[] sage: R._has_singular True sage: R.<x,y> = GF((2^31+11)^2)[] sage: R._has_singular False - sage: R.<x,y> = GF(10^20-11)[] + sage: R.<x,y> = GF(10^20 - 11)[] sage: R._has_singular True - sage: R.<x,y> = Zmod(10^20+1)[] + + sage: R.<x,y> = Zmod(10^20 + 1)[] sage: R._has_singular True """ @@ -427,14 +435,14 @@ def can_convert_to_singular(R): sage.rings.abc.RealField, sage.rings.abc.ComplexField, sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField))): return True - elif sage.rings.finite_rings.finite_field_constructor.is_FiniteField(base_ring): + elif isinstance(base_ring, FiniteField): return base_ring.characteristic() <= 2147483647 - elif number_field.number_field_base.is_NumberField(base_ring): + elif isinstance(base_ring, NumberField): return base_ring.is_absolute() elif sage.rings.fraction_field.is_FractionField(base_ring): B = base_ring.base_ring() return (B.is_prime_field() or B is ZZ - or (is_FiniteField(B) and B.characteristic() <= 2147483647)) + or (isinstance(B, FiniteField) and B.characteristic() <= 2147483647)) elif isinstance(base_ring, RationalFunctionField): return base_ring.constant_field().is_prime_field() else: @@ -469,6 +477,7 @@ def _singular_func(self, singular=singular): EXAMPLES:: + sage: # needs sage.libs.singular sage: P.<a,b> = PolynomialRing(GF(7), 2) sage: f = (a^3 + 2*b^2*a)^7; f a^21 + 2*a^7*b^14 @@ -479,6 +488,7 @@ def _singular_func(self, singular=singular): sage: P(h^20) == f^20 True + sage: # needs sage.libs.singular sage: R.<x> = PolynomialRing(GF(7)) sage: f = (x^3 + 2*x^2*x)^7 sage: f diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index 7419e9ebb4a..ada39527536 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -214,6 +214,7 @@ cdef class Polynomial_template(Polynomial): The following has been a problem in a preliminary version of :trac:`12313`:: + sage: # needs sage.rings.finite_rings sage: K.<z> = GF(4) sage: P.<x> = K[] sage: del P @@ -778,7 +779,7 @@ cdef class Polynomial_template(Polynomial): sage: P.<x> = PolynomialRing(GF(7)) sage: f = 3*x^2 + 2*x + 5 - sage: singular(f) + sage: singular(f) # needs sage.libs.singular 3*x^2+2*x-2 """ self.parent()._singular_(singular).set_ring() # this is expensive diff --git a/src/sage/rings/polynomial/polynomial_zmod_flint.pyx b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx index 15958758d18..4c480673861 100644 --- a/src/sage/rings/polynomial/polynomial_zmod_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx @@ -30,17 +30,16 @@ AUTHORS: - Burcin Erocal (2008-11) initial implementation - Martin Albrecht (2009-01) another initial implementation """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009-2010 Burcin Erocal <burcin@erocal.org> # Copyright (C) 2009 Martin Albrecht <M.R.Albrecht@rhul.ac.uk> # # Distributed under the terms of the GNU General Public License (GPL), # version 2 or any later version. The full text of the GPL is available at: -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.libs.ntl.ntl_lzz_pX import ntl_zz_pX -from sage.structure.factorization import Factorization from sage.structure.element cimport parent from sage.structure.element import coerce_binop from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint @@ -111,7 +110,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): return elif isinstance(x, Polynomial_integer_dense_flint): Polynomial_template.__init__(self, parent, 0, check, is_gen, construct) - self._set_fmpz_poly((<Polynomial_integer_dense_flint>x).__poly) + self._set_fmpz_poly((<Polynomial_integer_dense_flint>x)._poly) return else: if isinstance(x, ntl_zz_pX): @@ -182,7 +181,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): EXAMPLES:: - sage: P.<a>=GF(7)[] + sage: P.<a> = GF(7)[] sage: P([2^60,0,1]) a^2 + 1 sage: P([]) @@ -329,12 +328,12 @@ cdef class Polynomial_zmod_flint(Polynomial_template): @coerce_binop def resultant(self, Polynomial_zmod_flint other): """ - Returns the resultant of self and other, which must lie in the same + Return the resultant of ``self`` and ``other``, which must lie in the same polynomial ring. INPUT: - - other -- a polynomial + - ``other`` -- a polynomial OUTPUT: an element of the base ring of the polynomial ring @@ -388,8 +387,8 @@ cdef class Polynomial_zmod_flint(Polynomial_template): INPUT: - - n -- degree - - value -- coefficient + - ``n`` -- degree + - ``value`` -- coefficient .. warning:: @@ -425,7 +424,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): EXAMPLES:: - sage: P.<a>=GF(7)[] + sage: P.<a> = GF(7)[] sage: a = P(range(10)); b = P(range(5, 15)) sage: a._mul_trunc_(b, 5) 4*a^4 + 6*a^3 + 2*a^2 + 5*a @@ -457,7 +456,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): EXAMPLES:: - sage: P.<a>=GF(7)[] + sage: P.<a> = GF(7)[] sage: b = P(range(10)); c = P(range(5, 15)) sage: b._mul_trunc_opposite(c, 10) 5*a^17 + 2*a^16 + 6*a^15 + 4*a^14 + 4*a^13 + 5*a^10 + 2*a^9 + 5*a^8 + 4*a^5 + 4*a^4 + 6*a^3 + 2*a^2 + 5*a @@ -522,7 +521,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): cpdef rational_reconstruction(self, m, n_deg=0, d_deg=0): """ - Construct a rational function n/d such that `p*d` is equivalent to `n` + Construct a rational function `n/d` such that `p*d` is equivalent to `n` modulo `m` where `p` is this polynomial. EXAMPLES:: @@ -594,7 +593,8 @@ cdef class Polynomial_zmod_flint(Polynomial_template): sage: (s^2).is_irreducible() Traceback (most recent call last): ... - NotImplementedError: checking irreducibility of polynomials over rings with composite characteristic is not implemented + NotImplementedError: checking irreducibility of polynomials + over rings with composite characteristic is not implemented TESTS:: @@ -610,7 +610,8 @@ cdef class Polynomial_zmod_flint(Polynomial_template): sage: S(2).is_irreducible() Traceback (most recent call last): ... - NotImplementedError: checking irreducibility of polynomials over rings with composite characteristic is not implemented + NotImplementedError: checking irreducibility of polynomials + over rings with composite characteristic is not implemented Test that caching works:: @@ -639,7 +640,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): def squarefree_decomposition(self): """ - Returns the squarefree decomposition of this polynomial. + Return the squarefree decomposition of this polynomial. EXAMPLES:: @@ -665,7 +666,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): def factor(self): """ - Returns the factorization of the polynomial. + Return the factorization of the polynomial. EXAMPLES:: @@ -689,6 +690,16 @@ cdef class Polynomial_zmod_flint(Polynomial_template): Traceback (most recent call last): ... NotImplementedError: factorization of polynomials over rings with composite characteristic is not implemented + + Test that factorization can be interrupted:: + + sage: R.<x> = PolynomialRing(GF(65537), implementation="FLINT") + sage: f = R.random_element(9973) * R.random_element(10007) + sage: alarm(0.5); f.factor() + Traceback (most recent call last): + ... + AlarmInterrupt + """ R = self.base_ring() @@ -710,13 +721,13 @@ cdef class Polynomial_zmod_flint(Polynomial_template): """ Return this polynomial divided by its leading coefficient. - Raises ValueError if the leading coefficient is not invertible in the + Raises :class:`ValueError` if the leading coefficient is not invertible in the base ring. EXAMPLES:: sage: R.<x> = GF(5)[] - sage: (2*x^2+1).monic() + sage: (2*x^2 + 1).monic() x^2 + 3 TESTS:: @@ -727,7 +738,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): ... ValueError: leading coefficient must be invertible """ - if self.base_ring().characteristic().gcd(\ + if self.base_ring().characteristic().gcd( self.leading_coefficient().lift()) != 1: raise ValueError("leading coefficient must be invertible") cdef Polynomial_zmod_flint res = self._new() @@ -738,7 +749,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): """ Return a polynomial with the coefficients of this polynomial reversed. - If an optional degree argument is given the coefficient list will be + If the optional argument ``degree`` is given, the coefficient list will be truncated or zero padded as necessary before computing the reverse. EXAMPLES:: @@ -809,7 +820,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): def revert_series(self, n): r""" - Return a polynomial `f` such that `f(self(x)) = self(f(x)) = x mod x^n`. + Return a polynomial `f` such that ``f(self(x)) = self(f(x)) = x`` (mod `x^n`). EXAMPLES:: @@ -850,3 +861,23 @@ cdef class Polynomial_zmod_flint(Polynomial_template): sig_off() return res + + @coerce_binop + def minpoly_mod(self, other): + r""" + Thin wrapper for + :meth:`sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_mod_n.minpoly_mod`. + + EXAMPLES:: + + sage: R.<x> = GF(127)[] + sage: type(x) + <class 'sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint'> + sage: (x^5 - 3).minpoly_mod(x^3 + 5*x - 1) + x^3 + 34*x^2 + 125*x + 95 + """ + parent = self.parent() + name, = parent.variable_names() + from sage.rings.polynomial.polynomial_ring_constructor import _single_variate + R = _single_variate(parent.base_ring(), name=name, implementation='NTL') + return parent(R(self % other).minpoly_mod(R(other))) diff --git a/src/sage/rings/polynomial/polynomial_zz_pex.pxd b/src/sage/rings/polynomial/polynomial_zz_pex.pxd index b8acbafba13..ca60398ef68 100644 --- a/src/sage/rings/polynomial/polynomial_zz_pex.pxd +++ b/src/sage/rings/polynomial/polynomial_zz_pex.pxd @@ -6,6 +6,6 @@ ctypedef ZZ_pEContext_ptrs *cparent include "polynomial_template_header.pxi" -cdef class Polynomial_ZZ_pX(Polynomial_template): +cdef class Polynomial_ZZ_pEX(Polynomial_template): pass diff --git a/src/sage/rings/polynomial/polynomial_zz_pex.pyx b/src/sage/rings/polynomial/polynomial_zz_pex.pyx index 0d885e522ef..3cae5e13a48 100644 --- a/src/sage/rings/polynomial/polynomial_zz_pex.pyx +++ b/src/sage/rings/polynomial/polynomial_zz_pex.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.ntl sage.rings.finite_rings # distutils: libraries = NTL_LIBRARIES gmp # distutils: extra_compile_args = NTL_CFLAGS # distutils: include_dirs = NTL_INCDIR @@ -11,17 +12,14 @@ AUTHOR: - Yann Laigle-Chapuy (2010-01) initial implementation - Lorenz Panny (2023-01): :meth:`minpoly_mod` +- Giacomo Pope (2023-08): :meth:`reverse`, :meth:`inverse_series_trunc` """ - -from sage.rings.integer_ring import ZZ -from sage.rings.integer_ring cimport IntegerRing_class +from cysignals.signals cimport sig_on, sig_off from sage.libs.ntl.ntl_ZZ_pEContext cimport ntl_ZZ_pEContext_class from sage.libs.ntl.ZZ_pE cimport ZZ_pE_to_ZZ_pX from sage.libs.ntl.ZZ_pX cimport ZZ_pX_deg, ZZ_pX_coeff -from sage.libs.ntl.ntl_ZZ_pX cimport ntl_ZZ_pX from sage.libs.ntl.ZZ_p cimport ZZ_p_rep -from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class from sage.libs.ntl.convert cimport ZZ_to_mpz # We need to define this stuff before including the templating stuff @@ -44,7 +42,6 @@ include "sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi" # and then the interface include "polynomial_template.pxi" -from sage.libs.pari.all import pari from sage.libs.ntl.ntl_ZZ_pE cimport ntl_ZZ_pE cdef inline ZZ_pE_c_to_list(ZZ_pE_c x): @@ -67,24 +64,24 @@ cdef inline ZZ_pE_c_to_list(ZZ_pE_c x): cdef class Polynomial_ZZ_pEX(Polynomial_template): - """ - Univariate Polynomials over GF(p^n) via NTL's ZZ_pEX. + r""" + Univariate Polynomials over `\GF{p^n}` via NTL's ``ZZ_pEX``. EXAMPLES:: - sage: K.<a>=GF(next_prime(2**60)**3) - sage: R.<x> = PolynomialRing(K,implementation='NTL') + sage: K.<a> = GF(next_prime(2**60)**3) + sage: R.<x> = PolynomialRing(K, implementation='NTL') sage: (x^3 + a*x^2 + 1) * (x + a) x^4 + 2*a*x^3 + a^2*x^2 + x + a """ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): - """ - Create a new univariate polynomials over GF(p^n). + r""" + Create a new univariate polynomials over `\GF{p^n}`. EXAMPLES:: - sage: K.<a>=GF(next_prime(2**60)**3) - sage: R.<x> = PolynomialRing(K,implementation='NTL') + sage: K.<a> = GF(next_prime(2**60)**3) + sage: R.<x> = PolynomialRing(K, implementation='NTL') sage: x^2+a x^2 + a @@ -156,14 +153,14 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): Polynomial_template.__init__(self, parent, x, check, is_gen, construct) cdef get_unsafe(self, Py_ssize_t i): - """ + r""" Return the `i`-th coefficient of ``self``. EXAMPLES:: - sage: K.<a>=GF(next_prime(2**60)**3) - sage: R.<x> = PolynomialRing(K,implementation='NTL') - sage: f = x^3+(2*a+1)*x+a + sage: K.<a> = GF(next_prime(2**60)**3) + sage: R.<x> = PolynomialRing(K, implementation='NTL') + sage: f = x^3 + (2*a+1)*x + a sage: f[0] a sage: f[1] @@ -180,7 +177,7 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): return self._parent._base(ZZ_pE_c_to_list(c_pE)) cpdef list list(self, bint copy=True): - """ + r""" Return the list of coefficients. EXAMPLES:: @@ -188,7 +185,7 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): sage: K.<a> = GF(5^3) sage: P = PolynomialRing(K, 'x') sage: f = P.random_element(100) - sage: f.list() == [f[i] for i in range(f.degree()+1)] + sage: f.list() == [f[i] for i in range(f.degree()+1)] True sage: P.0.list() [0, 1] @@ -202,11 +199,11 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): for i in range(celement_len(&self.x, (<Polynomial_template>self)._cparent))] cpdef _lmul_(self, Element left): - """ + r""" EXAMPLES:: - sage: K.<a>=GF(next_prime(2**60)**3) - sage: R.<x> = PolynomialRing(K,implementation='NTL') + sage: K.<a> = GF(next_prime(2**60)**3) + sage: R.<x> = PolynomialRing(K, implementation='NTL') sage: (2*a+1)*x # indirect doctest (2*a + 1)*x sage: x*(2*a+1) # indirect doctest @@ -223,13 +220,13 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): return r def __call__(self, *x, **kwds): - """ + r""" Evaluate polynomial at `a`. EXAMPLES:: - sage: K.<u>=GF(next_prime(2**60)**3) - sage: R.<x> = PolynomialRing(K,implementation='NTL') + sage: K.<u> = GF(next_prime(2**60)**3) + sage: R.<x> = PolynomialRing(K, implementation='NTL') sage: P = (x-u)*(x+u+1) sage: P(u) 0 @@ -243,7 +240,7 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): sage: F.<x> = GF(4) sage: P.<y> = F[] sage: p = y^4 + x*y^3 + y^2 + (x + 1)*y + x + 1 - sage: SR(p) + sage: SR(p) # needs sage.symbolic Traceback (most recent call last): ... TypeError: positive characteristic not allowed in symbolic computations @@ -288,24 +285,24 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): return K(ZZ_pE_c_to_list(c_b)) def resultant(self, other): - """ - Returns the resultant of self and other, which must lie in the same + r""" + Return the resultant of ``self`` and ``other``, which must lie in the same polynomial ring. INPUT: - :argument other: a polynomial + - ``other`` -- a polynomial OUTPUT: an element of the base ring of the polynomial ring EXAMPLES:: - sage: K.<a>=GF(next_prime(2**60)**3) - sage: R.<x> = PolynomialRing(K,implementation='NTL') - sage: f=(x-a)*(x-a**2)*(x+1) - sage: g=(x-a**3)*(x-a**4)*(x+a) + sage: K.<a> = GF(next_prime(2**60)**3) + sage: R.<x> = PolynomialRing(K, implementation='NTL') + sage: f = (x-a)*(x-a**2)*(x+1) + sage: g = (x-a**3)*(x-a**4)*(x+a) sage: r = f.resultant(g) - sage: r == prod(u-v for (u,eu) in f.roots() for (v,ev) in g.roots()) + sage: r == prod(u - v for (u,eu) in f.roots() for (v,ev) in g.roots()) True """ cdef ZZ_pE_c r @@ -320,23 +317,24 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): return K(K.polynomial_ring()(ZZ_pE_c_to_list(r))) def is_irreducible(self, algorithm="fast_when_false", iter=1): - """ - Returns `True` precisely when self is irreducible over its base ring. + r""" + Return ``True`` precisely when ``self`` is irreducible over its base ring. INPUT: - :argument algorithm: a string (default "fast_when_false"), - there are 3 available algorithms: - "fast_when_true", "fast_when_false" and "probabilistic". - :argument iter: (default: 1) if the algorithm is "probabilistic" - defines the number of iterations. The error probability is bounded - by `q**-iter` for polynomials in `GF(q)[x]`. + - ``algorithm`` -- a string (default ``"fast_when_false"``), + there are 3 available algorithms: + ``"fast_when_true"``, ``"fast_when_false"``, and ``"probabilistic".`` + + - ``iter`` -- (default: 1) if the algorithm is ``"probabilistic"``, + defines the number of iterations. The error probability is bounded + by `q^{\text{-iter}}` for polynomials in `\GF{q}[x]`. EXAMPLES:: - sage: K.<a>=GF(next_prime(2**60)**3) - sage: R.<x> = PolynomialRing(K,implementation='NTL') - sage: P = x^3+(2-a)*x+1 + sage: K.<a> = GF(next_prime(2**60)**3) + sage: R.<x> = PolynomialRing(K, implementation='NTL') + sage: P = x^3 + (2-a)*x + 1 sage: P.is_irreducible(algorithm="fast_when_false") True sage: P.is_irreducible(algorithm="fast_when_true") @@ -350,7 +348,7 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): False sage: Q.is_irreducible(algorithm="probabilistic") False - """ + """ self._parent._modulus.restore() if algorithm=="fast_when_false": sig_on() @@ -413,20 +411,20 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): return r cpdef _richcmp_(self, other, int op): - """ + r""" EXAMPLES:: - sage: K.<a>=GF(next_prime(2**60)**3) - sage: R.<x> = PolynomialRing(K,implementation='NTL') - sage: P1 = (a**2+a+1)*x^2+a*x+1 - sage: P2 = ( a+1)*x^2+a*x+1 + sage: K.<a> = GF(next_prime(2**60)**3) + sage: R.<x> = PolynomialRing(K, implementation='NTL') + sage: P1 = (a**2+a+1)*x^2 + a*x + 1 + sage: P2 = ( a+1)*x^2 + a*x + 1 sage: P1 < P2 # indirect doctests False TESTS:: - sage: P3 = (a**2+a+1)*x^2+ x+1 - sage: P4 = x+1 + sage: P3 = (a**2+a+1)*x^2 + x + 1 + sage: P4 = x + 1 sage: P1 < P3 False sage: P1 < P4 @@ -441,11 +439,11 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): return Polynomial._richcmp_(self, other, op) def shift(self, int n): - """ + r""" EXAMPLES:: - sage: K.<a>=GF(next_prime(2**60)**3) - sage: R.<x> = PolynomialRing(K,implementation='NTL') + sage: K.<a> = GF(next_prime(2**60)**3) + sage: R.<x> = PolynomialRing(K, implementation='NTL') sage: f = x^3 + x^2 + 1 sage: f.shift(1) x^4 + x^3 + x @@ -462,11 +460,11 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): return r def __lshift__(self, int n): - """ + r""" EXAMPLES:: - sage: K.<a>=GF(next_prime(2**60)**3) - sage: R.<x> = PolynomialRing(K,implementation='NTL') + sage: K.<a> = GF(next_prime(2**60)**3) + sage: R.<x> = PolynomialRing(K, implementation='NTL') sage: f = x^3 + x^2 + 1 sage: f << 1 x^4 + x^3 + x @@ -476,11 +474,11 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): return self.shift(n) def __rshift__(self, int n): - """ + r""" EXAMPLES:: - sage: K.<a>=GF(next_prime(2**60)**3) - sage: R.<x> = PolynomialRing(K,implementation='NTL') + sage: K.<a> = GF(next_prime(2**60)**3) + sage: R.<x> = PolynomialRing(K, implementation='NTL') sage: f = x^3 + x^2 + 1 sage: f >> 1 x^2 + x @@ -488,3 +486,129 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): x^4 + x^3 + x """ return self.shift(-n) + + def reverse(self, degree=None): + r""" + Return the polynomial obtained by reversing the coefficients + of this polynomial. If degree is set then this function behaves + as if this polynomial has degree ``degree``. + + EXAMPLES:: + + sage: R.<x> = GF(101^2)[] + sage: f = x^13 + 11*x^10 + 32*x^6 + 4 + sage: f.reverse() + 4*x^13 + 32*x^7 + 11*x^3 + 1 + sage: f.reverse(degree=15) + 4*x^15 + 32*x^9 + 11*x^5 + x^2 + sage: f.reverse(degree=2) + 4*x^2 + + TESTS:: + + sage: R.<x> = GF(163^2)[] + sage: f = R([p for p in primes(20)]) + sage: f.reverse() + 2*x^7 + 3*x^6 + 5*x^5 + 7*x^4 + 11*x^3 + 13*x^2 + 17*x + 19 + sage: f.reverse(degree=200) + 2*x^200 + 3*x^199 + 5*x^198 + 7*x^197 + 11*x^196 + 13*x^195 + 17*x^194 + 19*x^193 + sage: f.reverse(degree=0) + Traceback (most recent call last): + ... + ValueError: degree argument must be a non-negative integer, got 0 + sage: f.reverse(degree=-5) + Traceback (most recent call last): + ... + ValueError: degree argument must be a non-negative integer, got -5 + """ + self._parent._modulus.restore() + + # Construct output polynomial + cdef Polynomial_ZZ_pEX r + r = Polynomial_ZZ_pEX.__new__(Polynomial_ZZ_pEX) + celement_construct(&r.x, (<Polynomial_template>self)._cparent) + r._parent = (<Polynomial_template>self)._parent + r._cparent = (<Polynomial_template>self)._cparent + + # When a degree has been supplied, ensure it is a valid input + cdef unsigned long d + if degree is not None: + if degree <= 0: + raise ValueError("degree argument must be a non-negative integer, got %s" % (degree)) + try: + d = degree + except ValueError: + raise ValueError("degree argument must be a non-negative integer, got %s" % (degree)) + ZZ_pEX_reverse_hi(r.x, (<Polynomial_ZZ_pEX> self).x, d) + else: + ZZ_pEX_reverse(r.x, (<Polynomial_ZZ_pEX> self).x) + return r + + def inverse_series_trunc(self, prec): + r""" + Compute and return the inverse of ``self`` modulo `x^{prec}`. + + The constant term of ``self`` must be invertible. + + EXAMPLES:: + + sage: R.<x> = GF(101^2)[] + sage: z2 = R.base_ring().gen() + sage: f = (3*z2 + 57)*x^3 + (13*z2 + 94)*x^2 + (7*z2 + 2)*x + 66*z2 + 15 + sage: f.inverse_series_trunc(1) + 51*z2 + 92 + sage: f.inverse_series_trunc(2) + (30*z2 + 30)*x + 51*z2 + 92 + sage: f.inverse_series_trunc(3) + (42*z2 + 94)*x^2 + (30*z2 + 30)*x + 51*z2 + 92 + sage: f.inverse_series_trunc(4) + (99*z2 + 96)*x^3 + (42*z2 + 94)*x^2 + (30*z2 + 30)*x + 51*z2 + 92 + + TESTS:: + + sage: R.<x> = GF(163^2)[] + sage: f = R([p for p in primes(20)]) + sage: f.inverse_series_trunc(1) + 82 + sage: f.inverse_series_trunc(2) + 40*x + 82 + sage: f.inverse_series_trunc(3) + 61*x^2 + 40*x + 82 + sage: f.inverse_series_trunc(0) + Traceback (most recent call last): + ... + ValueError: the precision must be positive, got 0 + sage: f.inverse_series_trunc(-1) + Traceback (most recent call last): + ... + ValueError: the precision must be positive, got -1 + sage: f = x + x^2 + x^3 + sage: f.inverse_series_trunc(5) + Traceback (most recent call last): + ... + ValueError: constant term 0 is not a unit + """ + self._parent._modulus.restore() + + # Ensure precision is non-negative + if prec <= 0: + raise ValueError("the precision must be positive, got {}".format(prec)) + + # Ensure we can invert the constant term + const_term = self.get_coeff_c(0) + if not const_term.is_unit(): + raise ValueError("constant term {} is not a unit".format(const_term)) + + # Construct output polynomial + cdef Polynomial_ZZ_pEX r + r = Polynomial_ZZ_pEX.__new__(Polynomial_ZZ_pEX) + celement_construct(&r.x, (<Polynomial_template>self)._cparent) + r._parent = (<Polynomial_template>self)._parent + r._cparent = (<Polynomial_template>self)._cparent + + # Call to NTL for the inverse truncation + if prec > 0: + sig_on() + ZZ_pEX_InvTrunc(r.x, self.x, prec) + sig_off() + return r diff --git a/src/sage/rings/polynomial/real_roots.pyx b/src/sage/rings/polynomial/real_roots.pyx index b939908ef92..4b5ebac6d8e 100644 --- a/src/sage/rings/polynomial/real_roots.pyx +++ b/src/sage/rings/polynomial/real_roots.pyx @@ -143,10 +143,10 @@ from sage.rings.real_mpfi import RealIntervalField, RIF from sage.rings.real_mpfr import RR, RealField from sage.arith.misc import binomial, factorial from sage.misc.randstate import randstate -from sage.modules.all import vector, FreeModule +from sage.modules.free_module_element import free_module_element as vector +from sage.modules.free_module import FreeModule from sage.matrix.matrix_space import MatrixSpace from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.polynomial.polynomial_ring import polygen from sage.misc.functional import numerator, denominator from sage.misc.misc_c import prod @@ -435,7 +435,7 @@ dr_cache = {} cdef class interval_bernstein_polynomial_integer(interval_bernstein_polynomial): """ - This is the subclass of interval_bernstein_polynomial where + This is the subclass of :class:`interval_bernstein_polynomial` where polynomial coefficients are represented using integers. In this integer representation, each coefficient is represented by @@ -443,8 +443,8 @@ cdef class interval_bernstein_polynomial_integer(interval_bernstein_polynomial): E (which is a machine integer). These represent the coefficients A*2^n <= c < (A+E)*2^n. - (Note that mk_ibpi is a simple helper function for creating - elements of interval_bernstein_polynomial_integer in doctests.) + (Note that :func:`mk_ibpi is a simple helper` function for creating + elements of :class:`interval_bernstein_polynomial_integer` in doctests.) EXAMPLES:: @@ -455,11 +455,13 @@ cdef class interval_bernstein_polynomial_integer(interval_bernstein_polynomial): <IBP: (1, 2, 3) + [0 .. 5)> sage: bp.variations() (0, 0) - sage: bp = mk_ibpi([-3, -1, 1, -1, -3, -1], lower=1, upper=5/4, usign=1, error=2, scale_log2=-3, level=2, slope_err=RIF(pi)); print(bp) + sage: bp = mk_ibpi([-3, -1, 1, -1, -3, -1], lower=1, upper=5/4, usign=1, # needs sage.symbolic + ....: error=2, scale_log2=-3, level=2, slope_err=RIF(pi)); print(bp) degree 5 IBP with 2-bit coefficients - sage: bp - <IBP: ((-3, -1, 1, -1, -3, -1) + [0 .. 2)) * 2^-3 over [1 .. 5/4]; usign 1; level 2; slope_err 3.141592653589794?> - sage: bp.variations() + sage: bp # needs sage.symbolic + <IBP: ((-3, -1, 1, -1, -3, -1) + [0 .. 2)) * 2^-3 over [1 .. 5/4]; usign 1; + level 2; slope_err 3.141592653589794?> + sage: bp.variations() # needs sage.symbolic (3, 3) """ @@ -874,7 +876,7 @@ cdef class interval_bernstein_polynomial_integer(interval_bernstein_polynomial): indicator = '=' if bitsize(err) > 17: shift = bitsize(err) - 15 - for i in xrange(len(ribp)): + for i in range(len(ribp)): ribp[i] = ribp[i] >> shift max_err = max_err >> shift err = -((-err) >> shift) @@ -943,7 +945,7 @@ cdef class interval_bernstein_polynomial_integer(interval_bernstein_polynomial): <IBP: ((0, 3, 12, 28) + [0 .. 1)) * 2^5> """ p = self.coeffs.__copy__() - for i in xrange(len(p)): + for i in range(len(p)): p[i] = p[i] >> bits return interval_bernstein_polynomial_integer(p, self.lower, self.upper, self.lsign, self.usign, -((-self.error) >> bits), self.scale_log2 + bits, self.level, self.slope_err) @@ -1330,7 +1332,7 @@ def intvec_to_doublevec(Vector_integer_dense b, long err): cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial): """ - This is the subclass of interval_bernstein_polynomial where + This is the subclass of :class:`interval_bernstein_polynomial` where polynomial coefficients are represented using floating-point numbers. In the floating-point representation, each coefficient is represented @@ -1341,8 +1343,8 @@ cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial): Note that we always have E1 <= 0 <= E2. Also, each floating-point coefficient has absolute value less than one. - (Note that mk_ibpf is a simple helper function for creating - elements of interval_bernstein_polynomial_float in doctests.) + (Note that :func:`mk_ibpf` is a simple helper function for creating + elements of :class:`interval_bernstein_polynomial_float` in doctests.) EXAMPLES:: @@ -1353,11 +1355,14 @@ cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial): <IBP: (0.1, 0.2, 0.3) + [0.0 .. 0.5]> sage: bp.variations() (0, 0) - sage: bp = mk_ibpf([-0.3, -0.1, 0.1, -0.1, -0.3, -0.1], lower=1, upper=5/4, usign=1, pos_err=0.2, scale_log2=-3, level=2, slope_err=RIF(pi)); print(bp) + sage: bp = mk_ibpf([-0.3, -0.1, 0.1, -0.1, -0.3, -0.1], # needs sage.symbolic + ....: lower=1, upper=5/4, usign=1, pos_err=0.2, + ....: scale_log2=-3, level=2, slope_err=RIF(pi)); print(bp) degree 5 IBP with floating-point coefficients - sage: bp - <IBP: ((-0.3, -0.1, 0.1, -0.1, -0.3, -0.1) + [0.0 .. 0.2]) * 2^-3 over [1 .. 5/4]; usign 1; level 2; slope_err 3.141592653589794?> - sage: bp.variations() + sage: bp # needs sage.symbolic + <IBP: ((-0.3, -0.1, 0.1, -0.1, -0.3, -0.1) + [0.0 .. 0.2]) * 2^-3 + over [1 .. 5/4]; usign 1; level 2; slope_err 3.141592653589794?> + sage: bp.variations() # needs sage.symbolic (3, 3) """ @@ -1560,13 +1565,13 @@ cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial): INPUT: - - ``mid`` -- where to split the Bernstein basis region; 0 < mid < 1 - - ``msign`` -- default 0 (unknown); the sign of this polynomial at mid + - ``mid`` -- where to split the Bernstein basis region; ``0 < mid < 1`` + - ``msign`` -- default 0 (unknown); the sign of this polynomial at ``mid`` OUTPUT: - ``bp1``, ``bp2`` -- the new interval Bernstein polynomials - - ``ok`` -- a boolean; True if the sign of the original polynomial at mid is known + - ``ok`` -- a boolean; ``True`` if the sign of the original polynomial at ``mid`` is known EXAMPLES:: @@ -1679,7 +1684,7 @@ cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial): def mk_ibpf(coeffs, lower=0, upper=1, lsign=0, usign=0, neg_err=0, pos_err=0, scale_log2=0, level=0, slope_err=RIF(0)): """ - A simple wrapper for creating interval_bernstein_polynomial_float + A simple wrapper for creating :class:`interval_bernstein_polynomial_float` objects with coercions, defaults, etc. For use in doctests. @@ -2038,7 +2043,7 @@ def precompute_degree_reduction_cache(n): # polynomial, and be fairly certain (absolutely certain?) that # the error in the reduced polynomial will be no better # than this product. - expected_err = max([sum([abs(x) for x in bd.row(k)]) for k in xrange(next+1)]) + expected_err = max([sum([abs(x) for x in bd.row(k)]) for k in range(next+1)]) # bdd = bd.denominator() # bdi = MatrixSpace(ZZ, next+1, samps, sparse=False)(bd * bdd) @@ -2207,7 +2212,7 @@ def cl_maximum_root_first_lambda(cl): negCounter = 0 pos = [] neg = [] - for j in xrange(n-1, -2, -1): + for j in range(n-1, -2, -1): if j < 0: coeff = 1 else: @@ -2231,7 +2236,7 @@ def cl_maximum_root_first_lambda(cl): return RIF.upper_field().zero() max_ub_log = RIF('-infinity') - for j in xrange(len(neg)): + for j in range(len(neg)): cur_ub_log = (-neg[j][0] / pos[j][0]).log() / (pos[j][1] - neg[j][1]) max_ub_log = max_ub_log.union(cur_ub_log) @@ -2283,7 +2288,7 @@ def cl_maximum_root_local_max(cl): max_pos_uses = 0 max_ub_log = RIF('-infinity') - for j in xrange(n-1, -1, -1): + for j in range(n-1, -1, -1): if cl[j] < 0: max_pos_uses = max_pos_uses+1 cur_ub_log = (-cl[j] / (max_pos_coeff >> max_pos_uses)).log() / (max_pos_exp - j) @@ -2362,7 +2367,7 @@ def root_bounds(p): ub = cl_maximum_root(cl) neg_cl = copy(cl) - for j in xrange(n-1, -1, -2): + for j in range(n-1, -1, -2): neg_cl[j] = -neg_cl[j] lb = -cl_maximum_root(neg_cl) @@ -3128,7 +3133,7 @@ cdef class ocean: def all_done(self): """ - Returns true iff all islands are known to contain exactly one root. + Return ``True`` iff all islands are known to contain exactly one root. EXAMPLES:: diff --git a/src/sage/rings/polynomial/refine_root.pyx b/src/sage/rings/polynomial/refine_root.pyx index 082bf810881..32a9ce8c8e4 100644 --- a/src/sage/rings/polynomial/refine_root.pyx +++ b/src/sage/rings/polynomial/refine_root.pyx @@ -38,6 +38,7 @@ def refine_root(ip, ipd, irt, fld): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.rings.polynomial.refine_root import refine_root sage: x = polygen(ZZ) sage: p = x^9 - 1 diff --git a/src/sage/rings/polynomial/skew_polynomial_element.pyx b/src/sage/rings/polynomial/skew_polynomial_element.pyx index 9cd4c821f49..539e924a968 100644 --- a/src/sage/rings/polynomial/skew_polynomial_element.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_element.pyx @@ -45,26 +45,13 @@ AUTHORS: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #**************************************************************************** - -import re from cysignals.signals cimport sig_check -from sage.rings.infinity import infinity -from sage.structure.factorization import Factorization -from sage.structure.element cimport Element, RingElement, AlgebraElement, ModuleElement -from sage.structure.parent cimport Parent -from sage.structure.parent_gens cimport ParentWithGens -from sage.misc.abstract_method import abstract_method -from sage.categories.homset import Hom -from sage.categories.fields import Fields +from sage.structure.element cimport Element, RingElement, ModuleElement from sage.rings.integer cimport Integer -from cpython.object cimport PyObject_RichCompare -from sage.categories.map cimport Map -from sage.rings.morphism cimport Morphism, RingHomomorphism -from sage.rings.polynomial.polynomial_element cimport _dict_to_list -from sage.structure.element import coerce_binop +from sage.rings.morphism cimport RingHomomorphism from sage.misc.superseded import experimental from sage.rings.polynomial.ore_polynomial_element cimport OrePolynomial diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx index 107077623d6..c6b67cba5fb 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx @@ -22,11 +22,10 @@ AUTHOR:: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #**************************************************************************** from sage.structure.element cimport parent -from sage.rings.ring cimport Ring from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer from sage.matrix.matrix_space import MatrixSpace @@ -34,11 +33,8 @@ from sage.matrix.matrix2 import NotFullRankError from sage.rings.polynomial.polynomial_element cimport Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.polynomial.ore_polynomial_element cimport OrePolynomial as SkewPolynomial from sage.rings.polynomial.skew_polynomial_finite_order cimport SkewPolynomial_finite_order_dense -from sage.combinat.permutation import Permutation, Permutations -from sage.combinat.partition import Partition from sage.structure.factorization import Factorization from sage.misc.mrange import xmrange_iter from sage.misc.prandom import sample @@ -633,7 +629,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): sage: S.<x> = k['x',Frob] sage: a = x^4 + 2*t*x^3 + 3*t^2*x^2 + (t^2 + t + 1)*x + 4*t + 3 sage: iter = a.right_irreducible_divisors(); iter - <generator object at 0x...> + <...generator object at 0x...> sage: next(iter) # random x + 2*t^2 + 4*t + 4 sage: next(iter) # random @@ -668,7 +664,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): sage: S.<x> = k['x',Frob] sage: a = x^4 + 2*t*x^3 + 3*t^2*x^2 + (t^2 + t + 1)*x + 4*t + 3 sage: iter = a.left_irreducible_divisors(); iter - <generator object at 0x...> + <...generator object at 0x...> sage: next(iter) # random x + 3*t + 3 sage: next(iter) # random @@ -1040,9 +1036,9 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): count /= factorial(m) return count * factorial(summ) - # Not optimized: # many calls to reduced_norm, reduced_norm_factor, _rdivisor_c, which are slow + def factorizations(self): r""" Return an iterator over all factorizations (as a product @@ -1056,7 +1052,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): sage: S.<x> = k['x',Frob] sage: a = x^3 + (t^2 + 1)*x^2 + (2*t + 3)*x + t^2 + t + 2 sage: iter = a.factorizations(); iter - <generator object at 0x...> + <...generator object at 0x...> sage: next(iter) # random (x + 3*t^2 + 4*t) * (x + 2*t^2) * (x + 4*t^2 + 4*t + 2) sage: next(iter) # random diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx index f3ff0617484..6ab57e1f7c5 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Univariate dense skew polynomials over a field with a finite order automorphism @@ -18,12 +19,7 @@ AUTHOR:: # (at your option) any later version. # https://www.gnu.org/licenses/ # *************************************************************************** - -import copy -import cysignals from sage.rings.ring cimport Ring -from sage.rings.polynomial.polynomial_element cimport Polynomial -from sage.rings.integer cimport Integer from sage.structure.element cimport RingElement from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.skew_polynomial_element cimport SkewPolynomial_generic_dense diff --git a/src/sage/rings/polynomial/skew_polynomial_ring.py b/src/sage/rings/polynomial/skew_polynomial_ring.py index a71a217719b..2ae48556880 100644 --- a/src/sage/rings/polynomial/skew_polynomial_ring.py +++ b/src/sage/rings/polynomial/skew_polynomial_ring.py @@ -78,7 +78,7 @@ def _base_ring_to_fraction_field(S): sage: from sage.rings.polynomial.skew_polynomial_ring import _base_ring_to_fraction_field sage: R.<t> = ZZ[] - sage: sigma = R.hom([t+1]) + sage: sigma = R.hom([t + 1]) sage: S.<x> = R['x', sigma] sage: _base_ring_to_fraction_field(S) Ore Polynomial Ring in x over Fraction Field of Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 @@ -116,6 +116,7 @@ def _minimal_vanishing_polynomial(R, eval_pts): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.skew_polynomial_ring import _minimal_vanishing_polynomial sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() @@ -171,12 +172,13 @@ def _lagrange_polynomial(R, eval_pts, values): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.rings.polynomial.skew_polynomial_ring import _lagrange_polynomial sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() - sage: S.<x> = k['x',Frob] - sage: eval_pts = [ t , t^2 ] - sage: values = [ 3*t^2 + 4*t + 4 , 4*t ] + sage: S.<x> = k['x', Frob] + sage: eval_pts = [t , t^2] + sage: values = [3*t^2 + 4*t + 4, 4*t] sage: d = _lagrange_polynomial(S, eval_pts, values); d x + t sage: d.multi_point_evaluation(eval_pts) == values @@ -186,9 +188,9 @@ def _lagrange_polynomial(R, eval_pts, values): points are linearly dependent over the fixed field of the twisting morphism, and the corresponding values do not match:: - sage: eval_pts = [ t, 2*t ] - sage: values = [ 1, 3 ] - sage: _lagrange_polynomial(S, eval_pts, values) + sage: eval_pts = [t, 2*t] # needs sage.rings.finite_rings + sage: values = [1, 3] + sage: _lagrange_polynomial(S, eval_pts, values) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: the given evaluation points are linearly dependent over the fixed field of the twisting morphism, @@ -240,7 +242,7 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) EXAMPLES:: sage: R.<t> = ZZ[] - sage: sigma = R.hom([t+1]) + sage: sigma = R.hom([t + 1]) sage: S.<x> = SkewPolynomialRing(R,sigma) sage: S.category() Category of algebras over Univariate Polynomial Ring in t over Integer Ring @@ -275,9 +277,10 @@ def minimal_vanishing_polynomial(self, eval_pts): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() - sage: S.<x> = k['x',Frob] + sage: S.<x> = k['x', Frob] sage: eval_pts = [1, t, t^2] sage: b = S.minimal_vanishing_polynomial(eval_pts); b x^3 + 4 @@ -285,16 +288,16 @@ def minimal_vanishing_polynomial(self, eval_pts): The minimal vanishing polynomial evaluates to 0 at each of the evaluation points:: - sage: eval = b.multi_point_evaluation(eval_pts); eval + sage: eval = b.multi_point_evaluation(eval_pts); eval # needs sage.rings.finite_rings [0, 0, 0] If the evaluation points are linearly dependent over the fixed field of the twisting morphism, then the returned polynomial has lower degree than the number of evaluation points:: - sage: S.minimal_vanishing_polynomial([t]) + sage: S.minimal_vanishing_polynomial([t]) # needs sage.rings.finite_rings x + 3*t^2 + 3*t - sage: S.minimal_vanishing_polynomial([t, 3*t]) + sage: S.minimal_vanishing_polynomial([t, 3*t]) # needs sage.rings.finite_rings x + 3*t^2 + 3*t """ return _minimal_vanishing_polynomial(_base_ring_to_fraction_field(self), eval_pts) @@ -328,26 +331,28 @@ def lagrange_polynomial(self, points): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() - sage: S.<x> = k['x',Frob] + sage: S.<x> = k['x', Frob] sage: points = [(t, 3*t^2 + 4*t + 4), (t^2, 4*t)] sage: d = S.lagrange_polynomial(points); d x + t sage: R.<t> = ZZ[] - sage: sigma = R.hom([t+1]) + sage: sigma = R.hom([t + 1]) sage: T.<x> = R['x', sigma] - sage: points = [ (1, t^2 + 3*t + 4), (t, 2*t^2 + 3*t + 1), (t^2, t^2 + 3*t + 4) ] + sage: points = [(1, t^2 + 3*t + 4), (t, 2*t^2 + 3*t + 1), (t^2, t^2 + 3*t + 4)] sage: p = T.lagrange_polynomial(points); p - ((-t^4 - 2*t - 3)/-2)*x^2 + (-t^4 - t^3 - t^2 - 3*t - 2)*x + (-t^4 - 2*t^3 - 4*t^2 - 10*t - 9)/-2 - sage: p.multi_point_evaluation([1, t, t^2]) == [ t^2 + 3*t + 4, 2*t^2 + 3*t + 1, t^2 + 3*t + 4 ] + ((-t^4 - 2*t - 3)/-2)*x^2 + (-t^4 - t^3 - t^2 - 3*t - 2)*x + + (-t^4 - 2*t^3 - 4*t^2 - 10*t - 9)/-2 + sage: p.multi_point_evaluation([1, t, t^2]) == [t^2 + 3*t + 4, 2*t^2 + 3*t + 1, t^2 + 3*t + 4] True If the `x_i` are linearly dependent over the fixed field of ``self.twisting_morphism()``, then an error is raised:: - sage: T.lagrange_polynomial([ (t, 1), (2*t, 3) ]) + sage: T.lagrange_polynomial([(t, 1), (2*t, 3)]) Traceback (most recent call last): ... ValueError: the given evaluation points are linearly dependent over the fixed field of the twisting morphism, @@ -378,6 +383,7 @@ class SectionSkewPolynomialCenterInjection(Section): TESTS:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z = S.center() @@ -391,6 +397,7 @@ def _call_(self, x): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z = S.center() @@ -425,12 +432,14 @@ def _richcmp_(self, right, op): TESTS:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z = S.center() sage: iota = S.convert_map_from(Z) sage: sigma = iota.section() + sage: # needs sage.rings.finite_rings sage: s = loads(dumps(sigma)) sage: s == sigma True @@ -453,6 +462,7 @@ class SkewPolynomialCenterInjection(RingHomomorphism): TESTS:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z = S.center() @@ -465,6 +475,7 @@ def __init__(self, domain, codomain, embed, order): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z = S.center() @@ -483,6 +494,7 @@ def _repr_(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z = S.center() @@ -500,12 +512,13 @@ def _call_(self, x): TESTS:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z.<z> = S.center() sage: iota = S.convert_map_from(Z) - sage: iota(z) + sage: iota(z) # needs sage.rings.finite_rings x^3 """ k = self._codomain.base_ring() @@ -521,11 +534,13 @@ def _richcmp_(self, right, op): TESTS:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z = S.center() sage: iota = S.convert_map_from(Z) + sage: # needs sage.rings.finite_rings sage: i = loads(dumps(iota)) sage: i == iota True @@ -546,6 +561,7 @@ def section(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z = S.center() @@ -573,6 +589,7 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) TESTS:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x', Frob]; S @@ -580,12 +597,13 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) sage: S.category() Category of algebras over Finite Field in t of size 5^3 - sage: TestSuite(S).run() + sage: TestSuite(S).run() # needs sage.rings.finite_rings We check that a call to the method :meth:`sage.rings.polynomial.skew_polynomial_finite_order.SkewPolynomial_finite_order.is_central` does not affect the behaviour of default central variable names:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(7^4) sage: phi = k.frobenius_endomorphism() sage: S.<x> = k['x', phi] @@ -638,11 +656,12 @@ def center(self, name=None, names=None, default=False): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob]; S - Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 - + Ore Polynomial Ring in x over Finite Field in t of size 5^3 + twisted by t |--> t^5 sage: Z = S.center(); Z Univariate Polynomial Ring in z over Finite Field of size 5 sage: Z.gen() @@ -650,43 +669,44 @@ def center(self, name=None, names=None, default=False): We can pass in another variable name:: - sage: S.center(name='y') + sage: S.center(name='y') # needs sage.rings.finite_rings Univariate Polynomial Ring in y over Finite Field of size 5 or use the bracket notation:: - sage: Zy.<y> = S.center(); Zy + sage: Zy.<y> = S.center(); Zy # needs sage.rings.finite_rings Univariate Polynomial Ring in y over Finite Field of size 5 - sage: y.parent() is Zy + sage: y.parent() is Zy # needs sage.rings.finite_rings True A coercion map from the center to the skew polynomial ring is set:: + sage: # needs sage.rings.finite_rings sage: S.has_coerce_map_from(Zy) True - sage: P = y + x; P x^3 + x sage: P.parent() - Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + Ore Polynomial Ring in x over Finite Field in t of size 5^3 + twisted by t |--> t^5 sage: P.parent() is S True together with a conversion map in the reverse direction:: - sage: Zy(x^6 + 2*x^3 + 3) + sage: Zy(x^6 + 2*x^3 + 3) # needs sage.rings.finite_rings y^2 + 2*y + 3 - sage: Zy(x^2) + sage: Zy(x^2) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: x^2 is not in the center Two different skew polynomial rings can share the same center:: - sage: S1.<x1> = k['x1', Frob] - sage: S2.<x2> = k['x2', Frob] - sage: S1.center() is S2.center() + sage: S1.<x1> = k['x1', Frob] # needs sage.rings.finite_rings + sage: S2.<x2> = k['x2', Frob] # needs sage.rings.finite_rings + sage: S1.center() is S2.center() # needs sage.rings.finite_rings True .. RUBRIC:: About the default name of the central variable @@ -696,10 +716,10 @@ def center(self, name=None, names=None, default=False): However, a variable name is given the first time this method is called, the given name become the default for the next calls:: + sage: # needs sage.rings.finite_rings sage: K.<t> = GF(11^3) sage: phi = K.frobenius_endomorphism() sage: A.<X> = K['X', phi] - sage: C.<u> = A.center() # first call sage: C Univariate Polynomial Ring in u over Finite Field of size 11 @@ -711,6 +731,7 @@ def center(self, name=None, names=None, default=False): We can update the default variable name by passing in the argument ``default=True``:: + sage: # needs sage.rings.finite_rings sage: D.<v> = A.center(default=True) sage: D Univariate Polynomial Ring in v over Finite Field of size 11 @@ -721,7 +742,7 @@ def center(self, name=None, names=None, default=False): TESTS:: - sage: C.<a,b> = S.center() + sage: C.<a,b> = S.center() # needs sage.rings.finite_rings Traceback (most recent call last): ... IndexError: the number of names must equal the number of generators @@ -793,9 +814,9 @@ def __init__(self, base_ring, morphism, derivation, names, sparse, category=None EXAMPLES:: - sage: k.<t> = GF(5^3) - sage: Frob = k.frobenius_endomorphism() - sage: T.<x> = k['x', Frob]; T + sage: k.<t> = GF(5^3) # needs sage.rings.finite_rings + sage: Frob = k.frobenius_endomorphism() # needs sage.rings.finite_rings + sage: T.<x> = k['x', Frob]; T # needs sage.rings.finite_rings Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 """ if self.Element is None: @@ -820,16 +841,17 @@ def _new_retraction_map(self, seed=None): TESTS:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(11^4) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x', Frob] - sage: S._new_retraction_map() sage: S._matrix_retraction # random [ 9 4 10 4] We can specify a seed:: + sage: # needs sage.rings.finite_rings sage: S._new_retraction_map(seed=a) sage: S._matrix_retraction [ 0 6 3 10] @@ -872,27 +894,27 @@ def _retraction(self, x, newmap=False, seed=None): TESTS:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(11^4) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x', Frob] - sage: S._retraction(a) # random 6 Note that a retraction map has been automatically created:: - sage: S._matrix_retraction # random + sage: S._matrix_retraction # random # needs sage.rings.finite_rings [ 0 6 3 10] If we call again the method :meth:`_retraction`, the same retraction map is used:: - sage: S._retraction(a) # random + sage: S._retraction(a) # random # needs sage.rings.finite_rings 6 We can specify a seed:: - sage: S._retraction(a^2, seed=a) # random + sage: S._retraction(a^2, seed=a) # random # needs sage.rings.finite_rings 10 """ # Better to return the retraction map but more difficult diff --git a/src/sage/rings/polynomial/symmetric_ideal.py b/src/sage/rings/polynomial/symmetric_ideal.py index dfe66e9f2f5..12a629ad741 100644 --- a/src/sage/rings/polynomial/symmetric_ideal.py +++ b/src/sage/rings/polynomial/symmetric_ideal.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular """ Symmetric Ideals of Infinite Polynomial Rings @@ -23,11 +24,13 @@ Note that ``I`` is not a symmetric Groebner basis:: - sage: G = R*I.groebner_basis() + sage: # needs sage.combinat + sage: G = R * I.groebner_basis() sage: G - Symmetric Ideal (x_1^2 + x_1, x_2 - x_1) of Infinite polynomial ring in x over Rational Field + Symmetric Ideal (x_1^2 + x_1, x_2 - x_1) of + Infinite polynomial ring in x over Rational Field sage: Q = R.quotient(G) - sage: p = x[3]*x[1]+x[2]^2+3 + sage: p = x[3]*x[1] + x[2]^2 + 3 sage: Q(p) -2*x_1 + 3 @@ -36,7 +39,7 @@ equal to `x_1` in ``Q``. Indeed, we have :: - sage: Q(p)*x[2] == Q(p)*x[1]*x[3]*x[5] + sage: Q(p)*x[2] == Q(p)*x[1]*x[3]*x[5] # needs sage.combinat True """ @@ -109,7 +112,7 @@ class SymmetricIdeal(Ideal_generic): EXAMPLES:: sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: I = [x[1]*y[2]*y[1] + 2*x[1]*y[2]]*X + sage: I = [x[1]*y[2]*y[1] + 2*x[1]*y[2]] * X sage: I == loads(dumps(I)) True sage: latex(I) @@ -117,20 +120,22 @@ class SymmetricIdeal(Ideal_generic): The default ordering is lexicographic. We now compute a Groebner basis:: - sage: J = I.groebner_basis() ; J # about 3 seconds - [x_1*y_2*y_1 + 2*x_1*y_2, x_2*y_2*y_1 + 2*x_2*y_1, x_2*x_1*y_1^2 + 2*x_2*x_1*y_1, x_2*x_1*y_2 - x_2*x_1*y_1] + sage: J = I.groebner_basis(); J # about 3 seconds # needs sage.combinat + [x_1*y_2*y_1 + 2*x_1*y_2, x_2*y_2*y_1 + 2*x_2*y_1, + x_2*x_1*y_1^2 + 2*x_2*x_1*y_1, x_2*x_1*y_2 - x_2*x_1*y_1] Note that even though the symmetric ideal can be generated by a single polynomial, its reduced symmetric Groebner basis comprises four elements. Ideal membership in ``I`` can now be tested by commuting symmetric reduction modulo ``J``:: - sage: I.reduce(J) + sage: I.reduce(J) # needs sage.combinat Symmetric Ideal (0) of Infinite polynomial ring in x, y over Rational Field The Groebner basis is not point-wise invariant under permutation:: - sage: P=Permutation([2, 1]) + sage: # needs sage.combinat + sage: P = Permutation([2, 1]) sage: J[2] x_2*x_1*y_1^2 + 2*x_2*x_1*y_1 sage: J[2]^P @@ -143,13 +148,13 @@ class SymmetricIdeal(Ideal_generic): permutations involve higher variable indices than the ones occurring in ``J``:: - sage: [[(p^P).reduce(J) for p in J] for P in Permutations(3)] + sage: [[(p^P).reduce(J) for p in J] for P in Permutations(3)] # needs sage.combinat [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] Since ``I`` is not a Groebner basis, it is no surprise that it cannot detect ideal membership:: - sage: [p.reduce(I) for p in J] + sage: [p.reduce(I) for p in J] # needs sage.combinat [0, x_2*y_2*y_1 + 2*x_2*y_1, x_2*x_1*y_1^2 + 2*x_2*x_1*y_1, x_2*x_1*y_2 - x_2*x_1*y_1] Note that we give no guarantee that the computation of a symmetric @@ -161,12 +166,14 @@ class SymmetricIdeal(Ideal_generic): product is indeed the product of ideals in the mathematical sense. :: - sage: I=X*(x[1]) - sage: I*I - Symmetric Ideal (x_1^2, x_2*x_1) of Infinite polynomial ring in x, y over Rational Field - sage: I^3 - Symmetric Ideal (x_1^3, x_2*x_1^2, x_2^2*x_1, x_3*x_2*x_1) of Infinite polynomial ring in x, y over Rational Field - sage: I*I == X*(x[1]^2) + sage: I = X * (x[1]) + sage: I * I # needs sage.combinat + Symmetric Ideal (x_1^2, x_2*x_1) of + Infinite polynomial ring in x, y over Rational Field + sage: I^3 # needs sage.combinat + Symmetric Ideal (x_1^3, x_2*x_1^2, x_2^2*x_1, x_3*x_2*x_1) of + Infinite polynomial ring in x, y over Rational Field + sage: I * I == X * (x[1]^2) # needs sage.combinat False """ @@ -182,12 +189,12 @@ def __init__(self, ring, gens, coerce=True): EXAMPLES:: sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: I=X*(x[1]^2+y[2]^2,x[1]*x[2]*y[3]+x[1]*y[4]) # indirect doctest + sage: I = X * (x[1]^2 + y[2]^2, x[1]*x[2]*y[3] + x[1]*y[4]) # indirect doctest sage: I Symmetric Ideal (x_1^2 + y_2^2, x_2*x_1*y_3 + x_1*y_4) of Infinite polynomial ring in x, y over Rational Field sage: from sage.rings.polynomial.symmetric_ideal import SymmetricIdeal - sage: J=SymmetricIdeal(X,[x[1]^2+y[2]^2,x[1]*x[2]*y[3]+x[1]*y[4]]) - sage: I==J + sage: J = SymmetricIdeal(X, [x[1]^2 + y[2]^2, x[1]*x[2]*y[3] + x[1]*y[4]]) + sage: I == J True """ @@ -198,12 +205,12 @@ def __repr__(self): EXAMPLES:: sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: I=X*(x[1]^2+y[2]^2,x[1]*x[2]*y[3]+x[1]*y[4]) + sage: I = X * (x[1]^2 + y[2]^2, x[1]*x[2]*y[3] + x[1]*y[4]) sage: I # indirect doctest Symmetric Ideal (x_1^2 + y_2^2, x_2*x_1*y_3 + x_1*y_4) of Infinite polynomial ring in x, y over Rational Field """ - return "Symmetric Ideal %s of %s"%(self._repr_short(), self.ring()) + return "Symmetric Ideal %s of %s" % (self._repr_short(), self.ring()) def _latex_(self): r""" @@ -211,7 +218,7 @@ def _latex_(self): sage: from sage.misc.latex import latex sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: I=X*(x[1]*y[2]) + sage: I = X * (x[1]*y[2]) sage: latex(I) # indirect doctest \left(x_{1} y_{2}\right)\Bold{Q}[x_{\ast}, y_{\ast}][\mathfrak{S}_{\infty}] @@ -231,10 +238,11 @@ def _contains_(self, p): sage: R.<x> = InfinitePolynomialRing(QQ) sage: I = R.ideal([x[1]*x[2] + x[3]]) - sage: I = R*I.groebner_basis() - sage: I - Symmetric Ideal (x_1^2 + x_1, x_2 - x_1) of Infinite polynomial ring in x over Rational Field - sage: x[2]^2 + x[3] in I # indirect doctest + sage: I = R * I.groebner_basis() # needs sage.combinat + sage: I # needs sage.combinat + Symmetric Ideal (x_1^2 + x_1, x_2 - x_1) of + Infinite polynomial ring in x over Rational Field + sage: x[2]^2 + x[3] in I # indirect doctest # needs sage.combinat True """ try: @@ -254,14 +262,14 @@ def __mul__(self, other): EXAMPLES:: sage: X.<x> = InfinitePolynomialRing(QQ) - sage: I=X*(x[1]) - sage: I*I # indirect doctest + sage: I = X * (x[1]) + sage: I*I # indirect doctest # needs sage.combinat Symmetric Ideal (x_1^2, x_2*x_1) of Infinite polynomial ring in x over Rational Field """ # determine maximal generator index PARENT = self.ring() - if (not isinstance(other, self.__class__)) or self.ring()!=other.ring(): + if (not isinstance(other, self.__class__)) or self.ring() != other.ring(): if hasattr(other,'gens'): other = SymmetricIdeal(PARENT, other.gens(), coerce=True) other = other.symmetrisation() @@ -283,7 +291,7 @@ def __mul__(self, other): def __pow__(self, n): """ - Raise self to some power. + Raise ``self`` to some power. Since the generators of a symmetric ideal are subject to a permutation action, they in fact stand for a set of @@ -294,8 +302,8 @@ def __pow__(self, n): EXAMPLES:: sage: X.<x> = InfinitePolynomialRing(QQ) - sage: I=X*(x[1]) - sage: I^2 # indirect doctest + sage: I = X * (x[1]) + sage: I^2 # indirect doctest # needs sage.combinat Symmetric Ideal (x_1^2, x_2*x_1) of Infinite polynomial ring in x over Rational Field """ @@ -306,7 +314,7 @@ def __pow__(self, n): def is_maximal(self): """ - Answers whether self is a maximal ideal. + Answer whether ``self`` is a maximal ideal. ASSUMPTION: @@ -314,30 +322,30 @@ def is_maximal(self): NOTE: - It is not checked whether self is in fact a symmetric Groebner + It is not checked whether ``self`` is in fact a symmetric Groebner basis. A wrong answer can result if this assumption does not - hold. A ``NotImplementedError`` is raised if the base ring is not + hold. A :class:`NotImplementedError` is raised if the base ring is not a field, since symmetric Groebner bases are not implemented in this setting. EXAMPLES:: sage: R.<x,y> = InfinitePolynomialRing(QQ) - sage: I = R.ideal([x[1]+y[2], x[2]-y[1]]) - sage: I = R*I.groebner_basis() - sage: I - Symmetric Ideal (y_1, x_1) of Infinite polynomial ring in x, y over Rational Field - sage: I = R.ideal([x[1]+y[2], x[2]-y[1]]) - sage: I.is_maximal() + sage: I = R.ideal([x[1] + y[2], x[2] - y[1]]) + sage: I = R * I.groebner_basis(); I # needs sage.combinat + Symmetric Ideal (y_1, x_1) of + Infinite polynomial ring in x, y over Rational Field + sage: I = R.ideal([x[1] + y[2], x[2] - y[1]]) # needs sage.combinat + sage: I.is_maximal() # needs sage.combinat False The preceding answer is wrong, since it is not the case that ``I`` is given by a symmetric Groebner basis:: - sage: I = R*I.groebner_basis() - sage: I - Symmetric Ideal (y_1, x_1) of Infinite polynomial ring in x, y over Rational Field - sage: I.is_maximal() + sage: I = R * I.groebner_basis(); I # needs sage.combinat + Symmetric Ideal (y_1, x_1) of + Infinite polynomial ring in x, y over Rational Field + sage: I.is_maximal() # needs sage.combinat True """ @@ -347,14 +355,14 @@ def is_maximal(self): if self.is_trivial() and not self.is_zero(): return True V = [p.variables() for p in self.gens()] - V = [x for x in V if len(x)==1] + V = [x for x in V if len(x) == 1] V = [str(x[0]).split('_')[0] for x in V] return set(V) == set(self.ring().variable_names()) def reduce(self, I, tailreduce=False): r""" - Symmetric reduction of self by another Symmetric Ideal or list of Infinite Polynomials, - or symmetric reduction of a given Infinite Polynomial by self. + Symmetric reduction of ``self`` by another Symmetric Ideal or list of Infinite Polynomials, + or symmetric reduction of a given Infinite Polynomial by ``self``. INPUT: @@ -377,14 +385,15 @@ def reduce(self, I, tailreduce=False): not diminish the variable indices occurring in `N` and preserves their order, so that there is some term `T\in X` with `T N^P = M`. If there is no such permutation, return `p` - 3. Replace `p` by `p-T q^P` and continue with step 1. + 3. Replace `p` by `p - T q^P` and continue with step 1. EXAMPLES:: sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: I = X*(y[1]^2*y[3]+y[1]*x[3]^2) + sage: I = X * (y[1]^2*y[3] + y[1]*x[3]^2) sage: I.reduce([x[1]^2*y[2]]) - Symmetric Ideal (x_3^2*y_1 + y_3*y_1^2) of Infinite polynomial ring in x, y over Rational Field + Symmetric Ideal (x_3^2*y_1 + y_3*y_1^2) of + Infinite polynomial ring in x, y over Rational Field The preceding is correct, since any permutation that turns ``x[1]^2*y[2]`` into a factor of ``x[3]^2*y[2]`` interchanges @@ -392,18 +401,21 @@ def reduce(self, I, tailreduce=False): reduction by ``x[2]^2*y[1]`` works, since one can change variable index 1 into 2 and 2 into 3:: - sage: I.reduce([x[2]^2*y[1]]) - Symmetric Ideal (y_3*y_1^2) of Infinite polynomial ring in x, y over Rational Field + sage: I.reduce([x[2]^2*y[1]]) # needs sage.combinat + Symmetric Ideal (y_3*y_1^2) of + Infinite polynomial ring in x, y over Rational Field The next example shows that tail reduction is not done, unless it is explicitly advised. The input can also be a symmetric ideal:: - sage: J = (y[2])*X + sage: J = (y[2]) * X sage: I.reduce(J) - Symmetric Ideal (x_3^2*y_1 + y_3*y_1^2) of Infinite polynomial ring in x, y over Rational Field - sage: I.reduce(J, tailreduce=True) - Symmetric Ideal (x_3^2*y_1) of Infinite polynomial ring in x, y over Rational Field + Symmetric Ideal (x_3^2*y_1 + y_3*y_1^2) of + Infinite polynomial ring in x, y over Rational Field + sage: I.reduce(J, tailreduce=True) # needs sage.combinat + Symmetric Ideal (x_3^2*y_1) of + Infinite polynomial ring in x, y over Rational Field """ if I in self.ring(): # we want to reduce a polynomial by self @@ -419,15 +431,15 @@ def reduce(self, I, tailreduce=False): def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None): """ - Return symmetrically interreduced form of self + Return symmetrically interreduced form of ``self``. INPUT: - - ``tailreduce`` -- (bool, default ``True``) If True, the + - ``tailreduce`` -- (bool, default ``True``) If ``True``, the interreduction is also performed on the non-leading monomials. - - ``sorted`` -- (bool, default ``False``) If True, it is assumed that the - generators of self are already increasingly sorted. - - ``report`` -- (object, default ``None``) If not None, some information on the + - ``sorted`` -- (bool, default ``False``) If ``True``, it is assumed that the + generators of ``self`` are already increasingly sorted. + - ``report`` -- (object, default ``None``) If not ``None``, some information on the progress of computation is printed - ``RStrat`` -- (:class:`~sage.rings.polynomial.symmetric_reduction.SymmetricReductionStrategy`, default ``None``) A reduction strategy to which the polynomials resulting @@ -437,28 +449,30 @@ def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None OUTPUT: - A Symmetric Ideal J (sorted list of generators) coinciding - with self as an ideal, so that any generator is symmetrically + A Symmetric Ideal `J` (sorted list of generators) coinciding + with ``self`` as an ideal, so that any generator is symmetrically reduced w.r.t. the other generators. Note that the leading coefficients of the result are not necessarily 1. EXAMPLES:: sage: X.<x> = InfinitePolynomialRing(QQ) - sage: I=X*(x[1]+x[2],x[1]*x[2]) - sage: I.interreduction() - Symmetric Ideal (-x_1^2, x_2 + x_1) of Infinite polynomial ring in x over Rational Field + sage: I = X * (x[1] + x[2], x[1]*x[2]) + sage: I.interreduction() # needs sage.combinat + Symmetric Ideal (-x_1^2, x_2 + x_1) of + Infinite polynomial ring in x over Rational Field Here, we show the ``report`` option:: - sage: I.interreduction(report=True) + sage: I.interreduction(report=True) # needs sage.combinat Symmetric interreduction [1/2] > [2/2] :> [1/2] > [2/2] T[1]> > - Symmetric Ideal (-x_1^2, x_2 + x_1) of Infinite polynomial ring in x over Rational Field + Symmetric Ideal (-x_1^2, x_2 + x_1) of + Infinite polynomial ring in x over Rational Field ``[m/n]`` indicates that polynomial number ``m`` is considered and the total number of polynomials under consideration is @@ -469,17 +483,19 @@ def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None Last, we demonstrate the use of the optional parameter ``RStrat``:: sage: from sage.rings.polynomial.symmetric_reduction import SymmetricReductionStrategy - sage: R = SymmetricReductionStrategy(X) - sage: R - Symmetric Reduction Strategy in Infinite polynomial ring in x over Rational Field - sage: I.interreduction(RStrat=R) - Symmetric Ideal (-x_1^2, x_2 + x_1) of Infinite polynomial ring in x over Rational Field - sage: R - Symmetric Reduction Strategy in Infinite polynomial ring in x over Rational Field, modulo + sage: R = SymmetricReductionStrategy(X); R + Symmetric Reduction Strategy in + Infinite polynomial ring in x over Rational Field + sage: I.interreduction(RStrat=R) # needs sage.combinat + Symmetric Ideal (-x_1^2, x_2 + x_1) of + Infinite polynomial ring in x over Rational Field + sage: R # needs sage.combinat + Symmetric Reduction Strategy in + Infinite polynomial ring in x over Rational Field, modulo x_1^2, x_2 + x_1 - sage: R = SymmetricReductionStrategy(X,[x[1]^2]) - sage: I.interreduction(RStrat=R) + sage: R = SymmetricReductionStrategy(X, [x[1]^2]) + sage: I.interreduction(RStrat=R) # needs sage.combinat Symmetric Ideal (x_2 + x_1) of Infinite polynomial ring in x over Rational Field """ @@ -539,11 +555,11 @@ def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None if DONE == TODO: break else: - if len(TODO)==len(DONE): + if len(TODO) == len(DONE): import copy bla = copy.copy(TODO) bla.sort() - if bla==DONE: + if bla == DONE: break TODO = DONE return SymmetricIdeal(self.ring(),DONE, coerce=False) @@ -560,8 +576,8 @@ def interreduced_basis(self): EXAMPLES:: sage: X.<x> = InfinitePolynomialRing(QQ) - sage: I=X*(x[1]+x[2],x[1]*x[2]) - sage: I.interreduced_basis() + sage: I = X * (x[1] + x[2], x[1]*x[2]) + sage: I.interreduced_basis() # needs sage.combinat [-x_1^2, x_2 + x_1] """ @@ -569,7 +585,7 @@ def interreduced_basis(self): def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=False): """ - Apply permutations to the generators of self and interreduce + Apply permutations to the generators of ``self`` and interreduce. INPUT: @@ -581,8 +597,8 @@ def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=F tail reductions. - ``report`` -- (object, default ``None``) If not ``None``, report on the progress of computations. - - ``use_full_group`` (optional) -- If True, apply *all* elements of - `Sym(N)` to the generators of self (this is what [AB2008]_ + - ``use_full_group`` (optional) -- If ``True``, apply *all* elements of + `Sym(N)` to the generators of ``self`` (this is what [AB2008]_ originally suggests). The default is to apply all elementary transpositions to the generators of ``self.squeezed()``, interreduce, and repeat until the result stabilises, which is @@ -592,7 +608,7 @@ def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=F OUTPUT: A symmetrically interreduced symmetric ideal with respect to - which any `Sym(N)`-translate of a generator of self is + which any `Sym(N)`-translate of a generator of ``self`` is symmetrically reducible, where by default ``N`` is the maximal variable index that occurs in the generators of ``self.interreduction().squeezed()``. @@ -607,12 +623,13 @@ def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=F EXAMPLES:: sage: X.<x> = InfinitePolynomialRing(QQ) - sage: I = X*(x[1]+x[2], x[1]*x[2]) - sage: I.symmetrisation() - Symmetric Ideal (-x_1^2, x_2 + x_1) of Infinite polynomial ring in x over Rational Field - sage: I.symmetrisation(N=3) + sage: I = X * (x[1] + x[2], x[1]*x[2]) + sage: I.symmetrisation() # needs sage.combinat + Symmetric Ideal (-x_1^2, x_2 + x_1) of + Infinite polynomial ring in x over Rational Field + sage: I.symmetrisation(N=3) # needs sage.combinat Symmetric Ideal (-2*x_1) of Infinite polynomial ring in x over Rational Field - sage: I.symmetrisation(N=3, use_full_group=True) + sage: I.symmetrisation(N=3, use_full_group=True) # needs sage.combinat Symmetric Ideal (-2*x_1) of Infinite polynomial ring in x over Rational Field """ @@ -623,7 +640,7 @@ def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=F N = max([Y.max_index() for Y in newOUT.gens()]+[1]) else: N = Integer(N) - if hasattr(R,'_max') and R._max<N: + if hasattr(R,'_max') and R._max < N: R.gen()[N] if report is not None: print("Symmetrise %d polynomials at level %d" % @@ -638,7 +655,7 @@ def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=F from sage.combinat.permutation import Permutation from sage.rings.polynomial.symmetric_reduction import SymmetricReductionStrategy RStrat = SymmetricReductionStrategy(self.ring(),OUT.gens(),tailreduce=tailreduce) - while (OUT!=newOUT): + while (OUT != newOUT): OUT = newOUT PermutedGens = list(OUT.gens()) if not (report is None): @@ -648,7 +665,7 @@ def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=F P = Permutation(((i,j))) for X in OUT.gens(): p = RStrat.reduce(X**P,report=report) - if p._p !=0: + if p._p != 0: PermutedGens.append(p) RStrat.add_generator(p,good_input=True) newOUT = (PermutedGens * R).interreduction(tailreduce=tailreduce,report=report) @@ -656,18 +673,18 @@ def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=F def symmetric_basis(self): """ - A symmetrised generating set (type :class:`~sage.structure.sequence.Sequence`) of self. + A symmetrised generating set (type :class:`~sage.structure.sequence.Sequence`) of ``self``. This does essentially the same as :meth:`symmetrisation` with - the option 'tailreduce', and it returns a + the option ``tailreduce``, and it returns a :class:`~sage.structure.sequence.Sequence` rather than a :class:`~sage.rings.polynomial.symmetric_ideal.SymmetricIdeal`. EXAMPLES:: sage: X.<x> = InfinitePolynomialRing(QQ) - sage: I = X*(x[1]+x[2], x[1]*x[2]) - sage: I.symmetric_basis() + sage: I = X * (x[1] + x[2], x[1]*x[2]) + sage: I.symmetric_basis() # needs sage.combinat [x_1^2, x_2 + x_1] """ @@ -675,19 +692,20 @@ def symmetric_basis(self): def normalisation(self): """ - Return an ideal that coincides with self, so that all generators have leading coefficient 1. + Return an ideal that coincides with ``self``, so that all generators have leading coefficient 1. Possibly occurring zeroes are removed from the generator list. EXAMPLES:: sage: X.<x> = InfinitePolynomialRing(QQ) - sage: I = X*(1/2*x[1]+2/3*x[2], 0, 4/5*x[1]*x[2]) + sage: I = X*(1/2*x[1] + 2/3*x[2], 0, 4/5*x[1]*x[2]) sage: I.normalisation() - Symmetric Ideal (x_2 + 3/4*x_1, x_2*x_1) of Infinite polynomial ring in x over Rational Field + Symmetric Ideal (x_2 + 3/4*x_1, x_2*x_1) of + Infinite polynomial ring in x over Rational Field """ - return SymmetricIdeal(self.ring(), [X/X.lc() for X in self.gens() if X._p!=0]) + return SymmetricIdeal(self.ring(), [X/X.lc() for X in self.gens() if X._p != 0]) def squeezed(self): """ @@ -705,10 +723,11 @@ def squeezed(self): EXAMPLES:: - sage: X.<x,y> = InfinitePolynomialRing(QQ,implementation='sparse') - sage: I = X*(x[1000]*y[100],x[50]*y[1000]) + sage: X.<x,y> = InfinitePolynomialRing(QQ, implementation='sparse') + sage: I = X * (x[1000]*y[100], x[50]*y[1000]) sage: I.squeezed() - Symmetric Ideal (x_2*y_1, x_1*y_2) of Infinite polynomial ring in x, y over Rational Field + Symmetric Ideal (x_2*y_1, x_1*y_2) of + Infinite polynomial ring in x, y over Rational Field """ return SymmetricIdeal(self.ring(), [X.squeezed() for X in self.gens()]) @@ -720,7 +739,7 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= INPUT: - - ``tailreduce`` -- (bool, default ``False``) If True, use tail reduction + - ``tailreduce`` -- (bool, default ``False``) If ``True``, use tail reduction in intermediate computations - ``reduced`` -- (bool, default ``True``) If ``True``, return the reduced normalised symmetric Groebner basis. @@ -730,7 +749,7 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= progress of computation. - ``use_full_group`` -- (bool, default ``False``) If ``True`` then proceed as originally suggested by [AB2008]_. Our default method should be faster; see - :meth:`.symmetrisation` for more details. + :meth:`symmetrisation` for more details. The computation of symmetric Groebner bases also involves the computation of *classical* Groebner bases, i.e., of Groebner @@ -791,11 +810,11 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= EXAMPLES:: sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: I1 = X*(x[1]+x[2],x[1]*x[2]) - sage: I1.groebner_basis() + sage: I1 = X * (x[1] + x[2], x[1]*x[2]) + sage: I1.groebner_basis() # needs sage.combinat [x_1] - sage: I2 = X*(y[1]^2*y[3]+y[1]*x[3]) - sage: I2.groebner_basis() + sage: I2 = X * (y[1]^2*y[3] + y[1]*x[3]) + sage: I2.groebner_basis() # needs sage.combinat [x_1*y_2 + y_2^2*y_1, x_2*y_1 + y_2*y_1^2] Note that a symmetric Groebner basis of a principal ideal is @@ -805,13 +824,13 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= and Hillar, the result is the same, but the computation takes much longer:: - sage: I2.groebner_basis(use_full_group=True) + sage: I2.groebner_basis(use_full_group=True) # needs sage.combinat [x_1*y_2 + y_2^2*y_1, x_2*y_1 + y_2*y_1^2] Last, we demonstrate how the report on the progress of computations looks like:: - sage: I1.groebner_basis(report=True, reduced=True) + sage: I1.groebner_basis(report=True, reduced=True) # needs sage.combinat Symmetric interreduction [1/2] > [2/2] :> @@ -879,12 +898,12 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= [x_1] The Aschenbrenner-Hillar algorithm is only guaranteed to work - if the base ring is a field. So, we raise a TypeError if this + if the base ring is a field. So, we raise a :class:`TypeError` if this is not the case:: sage: R.<x,y> = InfinitePolynomialRing(ZZ) - sage: I = R*[x[1]+x[2],y[1]] - sage: I.groebner_basis() + sage: I = R * [x[1] + x[2], y[1]] + sage: I.groebner_basis() # needs sage.combinat Traceback (most recent call last): ... TypeError: The base ring (= Integer Ring) must be a field @@ -893,30 +912,35 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= In an earlier version, the following examples failed:: - sage: X.<y,z> = InfinitePolynomialRing(GF(5),order='degrevlex') - sage: I = ['-2*y_0^2 + 2*z_0^2 + 1', '-y_0^2 + 2*y_0*z_0 - 2*z_0^2 - 2*z_0 - 1', 'y_0*z_0 + 2*z_0^2 - 2*z_0 - 1', 'y_0^2 + 2*y_0*z_0 - 2*z_0^2 + 2*z_0 - 2', '-y_0^2 - 2*y_0*z_0 - z_0^2 + y_0 - 1']*X - sage: I.groebner_basis() + sage: X.<y,z> = InfinitePolynomialRing(GF(5), order='degrevlex') + sage: I = ['-2*y_0^2 + 2*z_0^2 + 1', + ....: '-y_0^2 + 2*y_0*z_0 - 2*z_0^2 - 2*z_0 - 1', + ....: 'y_0*z_0 + 2*z_0^2 - 2*z_0 - 1', + ....: 'y_0^2 + 2*y_0*z_0 - 2*z_0^2 + 2*z_0 - 2', + ....: '-y_0^2 - 2*y_0*z_0 - z_0^2 + y_0 - 1'] * X + sage: I.groebner_basis() # needs sage.combinat [1] - sage: Y.<x,y> = InfinitePolynomialRing(GF(3), order='degrevlex', implementation='sparse') - sage: I = ['-y_3']*Y - sage: I.groebner_basis() + sage: Y.<x,y> = InfinitePolynomialRing(GF(3), order='degrevlex', + ....: implementation='sparse') + sage: I = ['-y_3'] * Y + sage: I.groebner_basis() # needs sage.combinat [y_1] """ # determine maximal generator index # and construct a common parent for the generators of self if algorithm is None: - algorithm='' + algorithm = '' PARENT = self.ring() if not (hasattr(PARENT.base_ring(),'is_field') and PARENT.base_ring().is_field()): - raise TypeError("The base ring (= %s) must be a field"%PARENT.base_ring()) + raise TypeError("The base ring (= %s) must be a field" % PARENT.base_ring()) OUT = self.symmetrisation(tailreduce=tailreduce,report=report,use_full_group=use_full_group) if not (report is None): print("Symmetrisation done") VarList = set() for P in OUT.gens(): - if P._p!=0: + if P._p != 0: if P.is_unit(): return Sequence([PARENT(1)], PARENT, check=False) VarList = VarList.union([str(X) for X in P.variables()]) @@ -933,7 +957,7 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= else: VarList = set() for P in OUT.gens(): - if P._p!=0: + if P._p != 0: if P.is_unit(): return Sequence([PARENT(1)], PARENT, check=False) VarList = VarList.union([str(X) for X in P.variables()]) @@ -942,7 +966,7 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= CommonR = PolynomialRing(PARENT._base, VarList, order=PARENT._order) try: # working around one libsingular bug and one libsingular oddity - DenseIdeal = [CommonR(P._p) if ((CommonR is P._p.parent()) or CommonR.ngens()!=P._p.parent().ngens()) else CommonR(repr(P._p)) for P in OUT.gens()]*CommonR + DenseIdeal = [CommonR(P._p) if ((CommonR is P._p.parent()) or CommonR.ngens() != P._p.parent().ngens()) else CommonR(repr(P._p)) for P in OUT.gens()]*CommonR except Exception: if report is not None: print("working around a libsingular bug") @@ -950,7 +974,7 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= if report is not None: print("Classical Groebner basis") - if algorithm!='': + if algorithm != '': print("(using %s)" % algorithm) newOUT = (DenseIdeal.groebner_basis(algorithm)*PARENT) if report is not None: diff --git a/src/sage/rings/polynomial/symmetric_reduction.pyx b/src/sage/rings/polynomial/symmetric_reduction.pyx index 25213e1318a..6cc00047de8 100644 --- a/src/sage/rings/polynomial/symmetric_reduction.pyx +++ b/src/sage/rings/polynomial/symmetric_reduction.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular r""" Symmetric Reduction of Infinite Polynomials @@ -51,7 +52,7 @@ EXAMPLES: First, we create an infinite polynomial ring and one of its elements:: sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: p = y[1]*y[3]+y[1]^2*x[3] + sage: p = y[1]*y[3] + y[1]^2*x[3] We want to symmetrically reduce it by another polynomial. So, we put this other polynomial into a list and create a Symmetric Reduction @@ -60,7 +61,8 @@ Strategy object:: sage: from sage.rings.polynomial.symmetric_reduction import SymmetricReductionStrategy sage: S = SymmetricReductionStrategy(X, [y[2]^2*x[1]]) sage: S - Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo + Symmetric Reduction Strategy in + Infinite polynomial ring in x, y over Rational Field, modulo x_1*y_2^2 sage: S.reduce(p) x_3*y_1^2 + y_3*y_1 @@ -74,18 +76,19 @@ change variable index 1 into 2 and 2 into 3. So, we add this to sage: S.add_generator(y[1]^2*x[2]) sage: S - Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo + Symmetric Reduction Strategy in + Infinite polynomial ring in x, y over Rational Field, modulo x_2*y_1^2, x_1*y_2^2 - sage: S.reduce(p) + sage: S.reduce(p) # needs sage.combinat y_3*y_1 The next example shows that tail reduction is not done, unless it is explicitly advised:: - sage: S.reduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) + sage: S.reduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) # needs sage.combinat x_3 + 2*x_2*y_1^2 + 3*x_1*y_2^2 - sage: S.tailreduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) + sage: S.tailreduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) # needs sage.combinat x_3 However, it is possible to ask for tailreduction already when the @@ -93,11 +96,12 @@ Symmetric Reduction Strategy is created:: sage: S2 = SymmetricReductionStrategy(X, [y[2]^2*x[1],y[1]^2*x[2]], tailreduce=True) sage: S2 - Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo + Symmetric Reduction Strategy in + Infinite polynomial ring in x, y over Rational Field, modulo x_2*y_1^2, x_1*y_2^2 with tailreduction - sage: S2.reduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) + sage: S2.reduce(x[3] + 2*x[2]*y[1]^2 + 3*y[2]^2*x[1]) # needs sage.combinat x_3 """ @@ -116,8 +120,6 @@ Symmetric Reduction Strategy is created:: # # https://www.gnu.org/licenses/ # **************************************************************************** -import copy -import operator import sys from sage.structure.richcmp cimport richcmp, Py_NE, Py_EQ @@ -144,7 +146,7 @@ cdef class SymmetricReductionStrategy: sage: S = SymmetricReductionStrategy(X, [y[2]^2*y[1],y[1]^2*y[2]], good_input=True) sage: S.reduce(y[3] + 2*y[2]*y[1]^2 + 3*y[2]^2*y[1]) y_3 + 3*y_2^2*y_1 + 2*y_2*y_1^2 - sage: S.tailreduce(y[3] + 2*y[2]*y[1]^2 + 3*y[2]^2*y[1]) + sage: S.tailreduce(y[3] + 2*y[2]*y[1]^2 + 3*y[2]^2*y[1]) # needs sage.combinat y_3 """ @@ -265,7 +267,8 @@ cdef class SymmetricReductionStrategy: sage: from sage.rings.polynomial.symmetric_reduction import SymmetricReductionStrategy sage: S = SymmetricReductionStrategy(X, [y[2]^2*y[1],y[1]^2*y[2]]) sage: S - Symmetric Reduction Strategy in Infinite polynomial ring in y over Rational Field, modulo + Symmetric Reduction Strategy in + Infinite polynomial ring in y over Rational Field, modulo y_2*y_1^2, y_2^2*y_1 sage: S.gens() @@ -295,7 +298,8 @@ cdef class SymmetricReductionStrategy: sage: R = SymmetricReductionStrategy(X) sage: R.setgens(S.gens()) sage: R - Symmetric Reduction Strategy in Infinite polynomial ring in y over Rational Field, modulo + Symmetric Reduction Strategy in + Infinite polynomial ring in y over Rational Field, modulo y_2*y_1^2, y_2^2*y_1 sage: R.gens() is S.gens() @@ -316,7 +320,8 @@ cdef class SymmetricReductionStrategy: sage: from sage.rings.polynomial.symmetric_reduction import SymmetricReductionStrategy sage: S = SymmetricReductionStrategy(X, [y[2]^2*y[1],y[1]^2*y[2]]) sage: S - Symmetric Reduction Strategy in Infinite polynomial ring in y over Rational Field, modulo + Symmetric Reduction Strategy in + Infinite polynomial ring in y over Rational Field, modulo y_2*y_1^2, y_2^2*y_1 sage: S.reset() @@ -336,7 +341,7 @@ cdef class SymmetricReductionStrategy: sage: from sage.rings.polynomial.symmetric_reduction import SymmetricReductionStrategy sage: X.<x,y> = InfinitePolynomialRing(QQ) - sage: S = SymmetricReductionStrategy(X, [y[2]^2*y[1],y[1]^2*y[2]], tailreduce=True) + sage: S = SymmetricReductionStrategy(X, [y[2]^2*y[1], y[1]^2*y[2]], tailreduce=True) sage: S # indirect doctest Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo y_2*y_1^2, @@ -424,18 +429,21 @@ cdef class SymmetricReductionStrategy: sage: X.<x,y> = InfinitePolynomialRing(QQ) sage: S = SymmetricReductionStrategy(X) sage: S - Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field + Symmetric Reduction Strategy in + Infinite polynomial ring in x, y over Rational Field sage: S.add_generator(y[3] + y[1]*(x[3]+x[1])) sage: S - Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo + Symmetric Reduction Strategy in + Infinite polynomial ring in x, y over Rational Field, modulo x_3*y_1 + x_1*y_1 + y_3 Note that the first added polynomial will be simplified when adding a suitable second polynomial:: - sage: S.add_generator(x[2]+x[1]) - sage: S - Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo + sage: S.add_generator(x[2] + x[1]) # needs sage.combinat + sage: S # needs sage.combinat + Symmetric Reduction Strategy in + Infinite polynomial ring in x, y over Rational Field, modulo y_3, x_2 + x_1 @@ -443,17 +451,20 @@ cdef class SymmetricReductionStrategy: polynomial. This can be avoided by specifying the optional parameter 'good_input':: - sage: S.add_generator(y[2]+y[1]*x[2]) + sage: # needs sage.combinat + sage: S.add_generator(y[2] + y[1]*x[2]) sage: S - Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo + Symmetric Reduction Strategy in + Infinite polynomial ring in x, y over Rational Field, modulo y_3, x_1*y_1 - y_2, x_2 + x_1 - sage: S.reduce(x[3]+x[2]) + sage: S.reduce(x[3] + x[2]) -2*x_1 - sage: S.add_generator(x[3]+x[2], good_input=True) + sage: S.add_generator(x[3] + x[2], good_input=True) sage: S - Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo + Symmetric Reduction Strategy in + Infinite polynomial ring in x, y over Rational Field, modulo y_3, x_3 + x_2, x_1*y_1 - y_2, @@ -528,7 +539,7 @@ cdef class SymmetricReductionStrategy: .. NOTE:: - If tail reduction shall be forced, use :meth:`.tailreduce`. + If tail reduction shall be forced, use :meth:`tailreduce`. EXAMPLES:: @@ -540,15 +551,18 @@ cdef class SymmetricReductionStrategy: sage: S.reduce(y[4]*x[1] + y[1]*x[4], notail=True) x_4*y_1 + x_1*y_4 - Last, we demonstrate the 'report' option:: + Last, we demonstrate the ``report`` option:: - sage: S = SymmetricReductionStrategy(X, [x[2]+y[1],x[2]*y[3]+x[1]*y[2]+y[4],y[3]+y[2]]) + sage: S = SymmetricReductionStrategy(X, [x[2] + y[1], + ....: x[2]*y[3] + x[1]*y[2] + y[4], + ....: y[3] + y[2]]) sage: S - Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo + Symmetric Reduction Strategy in + Infinite polynomial ring in x, y over Rational Field, modulo y_3 + y_2, x_2 + y_1, x_1*y_2 + y_4 - y_3*y_1 - sage: S.reduce(x[3] + x[1]*y[3] + x[1]*y[1],report=True) + sage: S.reduce(x[3] + x[1]*y[3] + x[1]*y[1], report=True) :::> x_1*y_1 + y_4 - y_3*y_1 - y_1 @@ -571,8 +585,8 @@ cdef class SymmetricReductionStrategy: while True: REDUCTOR = [] for q in lml: - c, P, w = q.symmetric_cancellation_order(p) - if (c is not None) and (c <= 0): + c, P, _ = q.symmetric_cancellation_order(p) + if c is not None and c <= 0: REDUCTOR = [self(q ** P)] break if not REDUCTOR: @@ -625,18 +639,21 @@ cdef class SymmetricReductionStrategy: sage: S = SymmetricReductionStrategy(X, [y[3]]) sage: S.reduce(y[4]*x[1] + y[1]*x[4]) x_4*y_1 + x_1*y_4 - sage: S.tailreduce(y[4]*x[1] + y[1]*x[4]) + sage: S.tailreduce(y[4]*x[1] + y[1]*x[4]) # needs sage.combinat x_4*y_1 Last, we demonstrate the 'report' option:: - sage: S = SymmetricReductionStrategy(X, [x[2]+y[1],x[2]*x[3]+x[1]*y[2]+y[4],y[3]+y[2]]) + sage: S = SymmetricReductionStrategy(X, [x[2] + y[1], + ....: x[2]*x[3] + x[1]*y[2] + y[4], + ....: y[3] + y[2]]) sage: S - Symmetric Reduction Strategy in Infinite polynomial ring in x, y over Rational Field, modulo + Symmetric Reduction Strategy in + Infinite polynomial ring in x, y over Rational Field, modulo y_3 + y_2, x_2 + y_1, x_1*y_2 + y_4 + y_1^2 - sage: S.tailreduce(x[3] + x[1]*y[3] + x[1]*y[1],report=True) + sage: S.tailreduce(x[3] + x[1]*y[3] + x[1]*y[1], report=True) # needs sage.combinat T[3]:::> T[3]:> x_1*y_1 - y_2 + y_1^2 - y_1 diff --git a/src/sage/rings/polynomial/term_order.py b/src/sage/rings/polynomial/term_order.py index 212f5cb0d73..687545c0c39 100644 --- a/src/sage/rings/polynomial/term_order.py +++ b/src/sage/rings/polynomial/term_order.py @@ -272,14 +272,15 @@ EXAMPLES:: - sage: m = matrix(2,[2,3,0,1]); m + sage: # needs sage.modules + sage: m = matrix(2, [2,3,0,1]); m [2 3] [0 1] sage: T = TermOrder(m); T Matrix term order with matrix [2 3] [0 1] - sage: P.<a,b> = PolynomialRing(QQ,2,order=T) + sage: P.<a,b> = PolynomialRing(QQ, 2, order=T) sage: P Multivariate Polynomial Ring in a, b over Rational Field sage: a > b @@ -313,7 +314,7 @@ :: - sage: P.<a,b,c,d,e,f> = PolynomialRing(QQ, 6,order='degrevlex(4),neglex(2)') + sage: P.<a,b,c,d,e,f> = PolynomialRing(QQ, 6, order='degrevlex(4),neglex(2)') sage: a > c^4 False sage: a > e^4 @@ -341,7 +342,7 @@ Traceback (most recent call last): ... ValueError: unknown term order 'royalorder' - sage: T = TermOrder("royalorder",force=True) + sage: T = TermOrder("royalorder", force=True) sage: T royalorder term order sage: T.singular_str() @@ -647,7 +648,7 @@ def __init__(self, name='lex', n=0, force=False): :trac:`12748`):: sage: T = TermOrder('degrevlex', 6) + TermOrder('degrevlex',10) - sage: R.<x0,y0,z0,x1,y1,z1,a0,a1,a2,a3,a4,a5,a6,a7,a8> = PolynomialRing(QQ,order=T) + sage: R.<x0,y0,z0,x1,y1,z1,a0,a1,a2,a3,a4,a5,a6,a7,a8> = PolynomialRing(QQ, order=T) Traceback (most recent call last): ... ValueError: the length of the given term order (16) differs from the number of variables (15) @@ -657,7 +658,7 @@ def __init__(self, name='lex', n=0, force=False): sage: T = TermOrder('degrevlex') sage: R.<x,y,z> = PolynomialRing(QQ, order=T) - sage: R._singular_() + sage: R._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 3 @@ -673,7 +674,7 @@ def __init__(self, name='lex', n=0, force=False): sage: S = R.change_ring(order=T2) sage: S == T False - sage: S._singular_() + sage: S._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 3 @@ -683,10 +684,11 @@ def __init__(self, name='lex', n=0, force=False): Check that :trac:`29635` is fixed:: - sage: T = PolynomialRing(GF(101^5), 'u,v,w', order=TermOrder('degneglex')).term_order() - sage: T.singular_str() + sage: T = PolynomialRing(GF(101^5), 'u,v,w', # needs sage.rings.finite_rings + ....: order=TermOrder('degneglex')).term_order() + sage: T.singular_str() # needs sage.rings.finite_rings '(a(1:3),ls(3))' - sage: (T + T).singular_str() + sage: (T + T).singular_str() # needs sage.rings.finite_rings '(a(1:3),ls(3),a(1:3),ls(3))' """ if isinstance(name, TermOrder): @@ -744,19 +746,19 @@ def __init__(self, name='lex', n=0, force=False): t = TermOrder(t, force=True) if t.name() == 'block': blocks = blocks + list(t.blocks()) - singular_str.append("%s"%(t.singular_str()[1:-1],)) # [1:-1] is needed to remove parenthesis - macaulay2_str.append("%s"%(t.macaulay2_str()[1:-1],)) + singular_str.append("%s" % (t.singular_str()[1:-1],)) # [1:-1] is needed to remove parenthesis + macaulay2_str.append("%s" % (t.macaulay2_str()[1:-1],)) else: if len(t) == 0: raise ArithmeticError("Can only concatenate term orders with length attribute.") blocks.append(t) if t.is_weighted_degree_order(): # true if t is a matrix order as well - singular_str.append("%s"%(t.singular_str(),)) + singular_str.append("%s" % (t.singular_str(),)) elif t.name() == 'degneglex': - singular_str.append("%s"%(t.singular_str()[1:-1],)) # [1:-1] to remove (,) + singular_str.append("%s" % (t.singular_str()[1:-1],)) # [1:-1] to remove (,) else: - singular_str.append("%s(%d)"%(t.singular_str(), len(t))) - macaulay2_str.append("%s => %d"%(t.macaulay2_str(), len(t))) + singular_str.append("%s(%d)" % (t.singular_str(), len(t))) + macaulay2_str.append("%s => %d" % (t.macaulay2_str(), len(t))) length += len(t) self._singular_moreblocks += t.singular_moreblocks() @@ -807,8 +809,8 @@ def __init__(self, name='lex', n=0, force=False): block_length = int(block_length) if block_length > 0: # ignore blocks with length 0 blocks.append( TermOrder(block_name, block_length, force=force) ) - singular_str.append("%s(%d)"%(singular_name_mapping.get(block_name, block_name), block_length)) - macaulay2_str.append("%s => %d"%(macaulay2_name_mapping.get(block_name, block_name), block_length)) + singular_str.append("%s(%d)" % (singular_name_mapping.get(block_name, block_name), block_length)) + macaulay2_str.append("%s => %d" % (macaulay2_name_mapping.get(block_name, block_name), block_length)) length += block_length except ValueError: block_name = block.strip() @@ -845,7 +847,7 @@ def __init__(self, name='lex', n=0, force=False): self._name = "matrix" self._singular_str = "M(%s)" % (int_str,) self._macaulay2_str = "" # Macaulay2 does not support matrix term order directly - self._magma_str = '"weight",[%s]'%(int_str,) + self._magma_str = '"weight",[%s]' % (int_str,) from sage.matrix.constructor import matrix self._matrix = matrix(n,name) # defined only for matrix term order @@ -855,7 +857,7 @@ def __init__(self, name='lex', n=0, force=False): raise ValueError("{!r} is not a valid term order".format(name)) if self._length != 0: - self._singular_str = self._singular_str%dict(ngens=self._length) + self._singular_str = self._singular_str % dict(ngens=self._length) if self._name == 'degneglex': self._singular_moreblocks += 1 @@ -929,10 +931,10 @@ def sortkey_matrix(self, f): EXAMPLES:: - sage: P.<x,y> = PolynomialRing(QQbar, 2, order='m(1,3,1,0)') - sage: y > x^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order='m(1,3,1,0)') # needs sage.rings.number_field + sage: y > x^2 # indirect doctest # needs sage.rings.number_field True - sage: y > x^3 + sage: y > x^3 # needs sage.rings.number_field False """ return tuple(sum(l * r for l, r in zip(row, f)) @@ -949,10 +951,10 @@ def sortkey_lex(self, f): EXAMPLES:: - sage: P.<x,y> = PolynomialRing(QQbar, 2, order='lex') - sage: x > y^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order='lex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field True - sage: x > 1 + sage: x > 1 # needs sage.rings.number_field True """ return f @@ -968,10 +970,10 @@ def sortkey_invlex(self, f): EXAMPLES:: - sage: P.<x,y> = PolynomialRing(QQbar, 2, order='invlex') - sage: x > y^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order='invlex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x > 1 + sage: x > 1 # needs sage.rings.number_field True """ return f.reversed() @@ -987,10 +989,10 @@ def sortkey_deglex(self, f): EXAMPLES:: - sage: P.<x,y> = PolynomialRing(QQbar, 2, order='deglex') - sage: x > y^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order='deglex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x > 1 + sage: x > 1 # needs sage.rings.number_field True """ @@ -1007,10 +1009,10 @@ def sortkey_degrevlex(self, f): EXAMPLES:: - sage: P.<x,y> = PolynomialRing(QQbar, 2, order='degrevlex') - sage: x > y^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order='degrevlex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x > 1 + sage: x > 1 # needs sage.rings.number_field True """ @@ -1029,10 +1031,10 @@ def sortkey_neglex(self, f): EXAMPLES:: - sage: P.<x,y> = PolynomialRing(QQbar, 2, order='neglex') - sage: x > y^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order='neglex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x > 1 + sage: x > 1 # needs sage.rings.number_field False """ return tuple(-v for v in f) @@ -1048,10 +1050,10 @@ def sortkey_negdegrevlex(self, f): EXAMPLES:: - sage: P.<x,y> = PolynomialRing(QQbar, 2, order='negdegrevlex') - sage: x > y^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order='negdegrevlex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field True - sage: x > 1 + sage: x > 1 # needs sage.rings.number_field False """ return (-sum(f.nonzero_values(sort=False)), @@ -1068,10 +1070,10 @@ def sortkey_negdeglex(self, f): EXAMPLES:: - sage: P.<x,y> = PolynomialRing(QQbar, 2, order='negdeglex') - sage: x > y^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order='negdeglex') # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field True - sage: x > 1 + sage: x > 1 # needs sage.rings.number_field False """ return (-sum(f.nonzero_values(sort=False)), f) @@ -1087,10 +1089,10 @@ def sortkey_degneglex(self, f): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='degneglex') - sage: x*y > y*z # indirect doctest + sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='degneglex') # needs sage.rings.number_field + sage: x*y > y*z # indirect doctest # needs sage.rings.number_field False - sage: x*y > x + sage: x*y > x # needs sage.rings.number_field True """ return (sum(f.nonzero_values(sort=False)), tuple(-v for v in f)) @@ -1107,10 +1109,10 @@ def sortkey_wdegrevlex(self, f): EXAMPLES:: sage: t = TermOrder('wdegrevlex',(3,2)) - sage: P.<x,y> = PolynomialRing(QQbar, 2, order=t) - sage: x > y^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order=t) # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x^2 > y^3 + sage: x^2 > y^3 # needs sage.rings.number_field True """ return (sum(l * r for (l, r) in zip(f, self._weights)), @@ -1128,10 +1130,10 @@ def sortkey_wdeglex(self, f): EXAMPLES:: sage: t = TermOrder('wdeglex',(3,2)) - sage: P.<x,y> = PolynomialRing(QQbar, 2, order=t) - sage: x > y^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order=t) # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field False - sage: x > y + sage: x > y # needs sage.rings.number_field True """ return (sum(l * r for (l, r) in zip(f, self._weights)), f) @@ -1148,10 +1150,10 @@ def sortkey_negwdeglex(self, f): EXAMPLES:: sage: t = TermOrder('negwdeglex',(3,2)) - sage: P.<x,y> = PolynomialRing(QQbar, 2, order=t) - sage: x > y^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order=t) # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field True - sage: x^2 > y^3 + sage: x^2 > y^3 # needs sage.rings.number_field True """ return (-sum(l * r for (l, r) in zip(f, self._weights)), f) @@ -1168,10 +1170,10 @@ def sortkey_negwdegrevlex(self, f): EXAMPLES:: sage: t = TermOrder('negwdegrevlex',(3,2)) - sage: P.<x,y> = PolynomialRing(QQbar, 2, order=t) - sage: x > y^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order=t) # needs sage.rings.number_field + sage: x > y^2 # indirect doctest # needs sage.rings.number_field True - sage: x^2 > y^3 + sage: x^2 > y^3 # needs sage.rings.number_field True """ return (-sum(l * r for (l, r) in zip(f, self._weights)), @@ -1188,18 +1190,19 @@ def sortkey_block(self, f): EXAMPLES:: - sage: P.<a,b,c,d,e,f>=PolynomialRing(QQbar, 6, order='degrevlex(3),degrevlex(3)') - sage: a > c^4 # indirect doctest + sage: P.<a,b,c,d,e,f> = PolynomialRing(QQbar, 6, # needs sage.rings.number_field + ....: order='degrevlex(3),degrevlex(3)') + sage: a > c^4 # indirect doctest # needs sage.rings.number_field False - sage: a > e^4 + sage: a > e^4 # needs sage.rings.number_field True TESTS: Check that the issue in :trac:`27139` is fixed:: - sage: R.<x,y,z,t> = PolynomialRing(AA, order='lex(2),lex(2)') - sage: x > y + sage: R.<x,y,z,t> = PolynomialRing(AA, order='lex(2),lex(2)') # needs sage.rings.number_field + sage: x > y # needs sage.rings.number_field True """ key = tuple() @@ -1223,10 +1226,10 @@ def greater_tuple_matrix(self,f,g): EXAMPLES:: - sage: P.<x,y> = PolynomialRing(QQbar, 2, order='m(1,3,1,0)') - sage: y > x^2 # indirect doctest + sage: P.<x,y> = PolynomialRing(QQbar, 2, order='m(1,3,1,0)') # needs sage.rings.number_field + sage: y > x^2 # indirect doctest # needs sage.rings.number_field True - sage: y > x^3 + sage: y > x^3 # needs sage.rings.number_field False """ for row in self._matrix: @@ -1252,8 +1255,8 @@ def greater_tuple_lex(self,f,g): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='lex') - sage: f = x + y^2; f.lm() # indirect doctest + sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='lex') # needs sage.rings.number_field + sage: f = x + y^2; f.lm() # indirect doctest # needs sage.rings.number_field x This method is called by the lm/lc/lt methods of @@ -1274,10 +1277,10 @@ def greater_tuple_invlex(self,f,g): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='invlex') - sage: f = x + y; f.lm() # indirect doctest + sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='invlex') # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field y - sage: f = y + x^2; f.lm() + sage: f = y + x^2; f.lm() # needs sage.rings.number_field y This method is called by the lm/lc/lt methods of @@ -1298,10 +1301,10 @@ def greater_tuple_deglex(self,f,g): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='deglex') - sage: f = x + y; f.lm() # indirect doctest + sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='deglex') # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field x - sage: f = x + y^2*z; f.lm() + sage: f = x + y^2*z; f.lm() # needs sage.rings.number_field y^2*z This method is called by the lm/lc/lt methods of @@ -1324,10 +1327,10 @@ def greater_tuple_degrevlex(self,f,g): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='degrevlex') - sage: f = x + y; f.lm() # indirect doctest + sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='degrevlex') # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field x - sage: f = x + y^2*z; f.lm() + sage: f = x + y^2*z; f.lm() # needs sage.rings.number_field y^2*z This method is called by the lm/lc/lt methods of @@ -1350,6 +1353,7 @@ def greater_tuple_negdegrevlex(self,f,g): EXAMPLES:: + sage: # needs sage.rings.number_field sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='negdegrevlex') sage: f = x + y; f.lm() # indirect doctest x @@ -1378,6 +1382,7 @@ def greater_tuple_negdeglex(self,f,g): EXAMPLES:: + sage: # needs sage.rings.number_field sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='negdeglex') sage: f = x + y; f.lm() # indirect doctest x @@ -1406,10 +1411,10 @@ def greater_tuple_degneglex(self,f,g): EXAMPLES:: - sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='degneglex') - sage: f = x + y; f.lm() # indirect doctest + sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order='degneglex') # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field y - sage: f = x + y^2*z; f.lm() + sage: f = x + y^2*z; f.lm() # needs sage.rings.number_field y^2*z This method is called by the lm/lc/lt methods of @@ -1435,10 +1440,11 @@ def greater_tuple_neglex(self,f,g): EXAMPLES:: - sage: P.<a,b,c,d,e,f>=PolynomialRing(QQbar, 6, order='degrevlex(3),degrevlex(3)') - sage: f = a + c^4; f.lm() # indirect doctest + sage: P.<a,b,c,d,e,f> = PolynomialRing(QQbar, 6, # needs sage.rings.number_field + ....: order='degrevlex(3),degrevlex(3)') + sage: f = a + c^4; f.lm() # indirect doctest # needs sage.rings.number_field c^4 - sage: g = a + e^4; g.lm() + sage: g = a + e^4; g.lm() # needs sage.rings.number_field a """ return (f < g) and f or g @@ -1457,10 +1463,10 @@ def greater_tuple_wdeglex(self,f,g): EXAMPLES:: sage: t = TermOrder('wdeglex',(1,2,3)) - sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order=t) - sage: f = x + y; f.lm() # indirect doctest + sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order=t) # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field y - sage: f = x*y + z; f.lm() + sage: f = x*y + z; f.lm() # needs sage.rings.number_field x*y This method is called by the lm/lc/lt methods of @@ -1484,10 +1490,10 @@ def greater_tuple_wdegrevlex(self,f,g): EXAMPLES:: sage: t = TermOrder('wdegrevlex',(1,2,3)) - sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order=t) - sage: f = x + y; f.lm() # indirect doctest + sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order=t) # needs sage.rings.number_field + sage: f = x + y; f.lm() # indirect doctest # needs sage.rings.number_field y - sage: f = x + y^2*z; f.lm() + sage: f = x + y^2*z; f.lm() # needs sage.rings.number_field y^2*z This method is called by the lm/lc/lt methods of @@ -1510,6 +1516,7 @@ def greater_tuple_negwdeglex(self,f,g): EXAMPLES:: + sage: # needs sage.rings.number_field sage: t = TermOrder('negwdeglex',(1,2,3)) sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order=t) sage: f = x + y; f.lm() # indirect doctest @@ -1539,6 +1546,7 @@ def greater_tuple_negwdegrevlex(self,f,g): EXAMPLES:: + sage: # needs sage.rings.number_field sage: t = TermOrder('negwdegrevlex',(1,2,3)) sage: P.<x,y,z> = PolynomialRing(QQbar, 3, order=t) sage: f = x + y; f.lm() # indirect doctest @@ -1571,10 +1579,11 @@ def greater_tuple_block(self, f,g): EXAMPLES:: - sage: P.<a,b,c,d,e,f>=PolynomialRing(QQbar, 6, order='degrevlex(3),degrevlex(3)') - sage: f = a + c^4; f.lm() # indirect doctest + sage: P.<a,b,c,d,e,f> = PolynomialRing(QQbar, 6, # needs sage.rings.number_field + ....: order='degrevlex(3),degrevlex(3)') + sage: f = a + c^4; f.lm() # indirect doctest # needs sage.rings.number_field c^4 - sage: g = a + e^4; g.lm() + sage: g = a + e^4; g.lm() # needs sage.rings.number_field a """ n = 0 @@ -1600,9 +1609,9 @@ def tuple_weight(self, f): EXAMPLES:: - sage: t=TermOrder('wdeglex',(1,2,3)) - sage: P.<a,b,c>=PolynomialRing(QQbar, order=t) - sage: P.term_order().tuple_weight([3,2,1]) + sage: t = TermOrder('wdeglex',(1,2,3)) + sage: P.<a,b,c> = PolynomialRing(QQbar, order=t) # needs sage.rings.number_field + sage: P.term_order().tuple_weight([3,2,1]) # needs sage.rings.number_field 10 """ return sum(l*r for (l,r) in zip(f,self._weights)) @@ -1624,34 +1633,35 @@ def _repr_(self): Lexicographic term order """ if self._name == 'matrix': - return 'Matrix term order with matrix\n%s'%(self._matrix,) + return 'Matrix term order with matrix\n%s' % (self._matrix,) elif self._name == 'block': s = [] for t in self._blocks: if not t.is_weighted_degree_order(): - s.append('%s of length %d'%(t,len(t))) + s.append('%s of length %d' % (t,len(t))) else: # includes matrix order - s.append('%s'%(t,)) - return 'Block term order with blocks:\n(%s)'%(',\n '.join(s),) + s.append('%s' % (t,)) + return 'Block term order with blocks:\n(%s)' % (',\n '.join(s),) else: s = print_name_mapping.get(self._name,self._name) + ' term order' if self.is_weighted_degree_order(): - s = s + ' with weights %s'%(self._weights,) + s = s + ' with weights %s' % (self._weights,) return s def singular_str(self): """ - Return a SINGULAR representation of self. + Return a SINGULAR representation of ``self``. Used to convert polynomial rings to their SINGULAR representation. EXAMPLES:: - sage: P = PolynomialRing(GF(127),10,names='x',order='lex(3),deglex(5),lex(2)') + sage: P = PolynomialRing(GF(127), 10, names='x', + ....: order='lex(3),deglex(5),lex(2)') sage: T = P.term_order() sage: T.singular_str() '(lp(3),Dp(5),lp(2))' - sage: P._singular_() + sage: P._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 10 @@ -1677,7 +1687,7 @@ def singular_str(self): sage: T = P.term_order() sage: T.singular_str() '(a(1:2),ls(2),a(1:2),ls(2))' - sage: P._singular_() + sage: P._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 4 @@ -1699,7 +1709,7 @@ def singular_str(self): sage: T = TermOrder("degneglex", 2) + TermOrder("degneglex", 2) sage: T._singular_ringorder_column = 0 sage: P = PolynomialRing(QQ, 4, names='x', order=T) - sage: P._singular_() + sage: P._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 4 @@ -1717,7 +1727,7 @@ def singular_str(self): sage: T._singular_ringorder_column = 1 sage: P = PolynomialRing(QQ, 4, names='y', order=T) - sage: P._singular_() + sage: P._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 4 @@ -1735,7 +1745,7 @@ def singular_str(self): sage: T._singular_ringorder_column = 2 sage: P = PolynomialRing(QQ, 4, names='z', order=T) - sage: P._singular_() + sage: P._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 4 @@ -1770,19 +1780,22 @@ def singular_str(self): def singular_moreblocks(self): """ Return a the number of additional blocks SINGULAR needs to allocate - for handling non-native orderings like `degneglex`. + for handling non-native orderings like ``degneglex``. EXAMPLES:: - sage: P = PolynomialRing(GF(127),10,names='x',order='lex(3),deglex(5),lex(2)') + sage: P = PolynomialRing(GF(127), 10, names='x', + ....: order='lex(3),deglex(5),lex(2)') sage: T = P.term_order() sage: T.singular_moreblocks() 0 - sage: P = PolynomialRing(GF(127),10,names='x',order='lex(3),degneglex(5),lex(2)') + sage: P = PolynomialRing(GF(127), 10, names='x', + ....: order='lex(3),degneglex(5),lex(2)') sage: T = P.term_order() sage: T.singular_moreblocks() 1 - sage: P = PolynomialRing(GF(127),10,names='x',order='degneglex(5),degneglex(5)') + sage: P = PolynomialRing(GF(127), 10, names='x', + ....: order='degneglex(5),degneglex(5)') sage: T = P.term_order() sage: T.singular_moreblocks() 2 @@ -1790,7 +1803,7 @@ def singular_moreblocks(self): TESTS: The 'degneglex' ordering is somehow special: SINGULAR handles it - using an extra weight vector block. + using an extra weight vector block. :: sage: T = TermOrder("degneglex", 2) sage: P = PolynomialRing(QQ,2, names='x', order=T) @@ -1807,18 +1820,18 @@ def singular_moreblocks(self): def macaulay2_str(self): """ - Return a Macaulay2 representation of self. + Return a Macaulay2 representation of ``self``. Used to convert polynomial rings to their Macaulay2 representation. EXAMPLES:: - sage: P = PolynomialRing(GF(127), 8,names='x',order='degrevlex(3),lex(5)') + sage: P = PolynomialRing(GF(127), 8, names='x', order='degrevlex(3),lex(5)') sage: T = P.term_order() sage: T.macaulay2_str() '{GRevLex => 3,Lex => 5}' - sage: P._macaulay2_().options()['MonomialOrder'] # optional - macaulay2 + sage: P._macaulay2_().options()['MonomialOrder'] # optional - macaulay2 {MonomialSize => 16 } {GRevLex => {1, 1, 1}} {Lex => 5 } @@ -1828,14 +1841,14 @@ def macaulay2_str(self): def magma_str(self): """ - Return a MAGMA representation of self. + Return a MAGMA representation of ``self``. Used to convert polynomial rings to their MAGMA representation. EXAMPLES:: - sage: P = PolynomialRing(GF(127), 10,names='x',order='degrevlex') - sage: magma(P) # optional - magma + sage: P = PolynomialRing(GF(127), 10, names='x', order='degrevlex') + sage: magma(P) # optional - magma Polynomial ring of rank 10 over GF(127) Order: Graded Reverse Lexicographical Variables: x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 @@ -1850,7 +1863,7 @@ def magma_str(self): def blocks(self): """ - Return the term order blocks of self. + Return the term order blocks of ``self``. NOTE: @@ -1860,7 +1873,7 @@ def blocks(self): EXAMPLES:: - sage: t=TermOrder('deglex',2)+TermOrder('lex',2) + sage: t = TermOrder('deglex',2) + TermOrder('lex',2) sage: t.blocks() (Degree lexicographic term order, Lexicographic term order) """ @@ -1875,8 +1888,8 @@ def matrix(self): EXAMPLES:: - sage: t = TermOrder("M(1,2,0,1)") - sage: t.matrix() + sage: t = TermOrder("M(1,2,0,1)") # needs sage.modules + sage: t.matrix() # needs sage.modules [1 2] [0 1] @@ -1889,7 +1902,7 @@ def weights(self): EXAMPLES:: - sage: t=TermOrder('wdeglex',(2,3)) + sage: t = TermOrder('wdeglex',(2,3)) sage: t.weights() (2, 3) """ @@ -1897,7 +1910,7 @@ def weights(self): def __eq__(self, other): """ - Return true if self and other are equal. + Return ``True`` if ``self`` and ``other`` are equal. EXAMPLES:: @@ -1911,15 +1924,15 @@ def __eq__(self, other): :: - sage: T1 = TermOrder('lex',2)+TermOrder('lex',3) - sage: T2 = TermOrder('lex',3)+TermOrder('lex',2) + sage: T1 = TermOrder('lex',2) + TermOrder('lex',3) + sage: T2 = TermOrder('lex',3) + TermOrder('lex',2) sage: T1 == T2 False :: - sage: T1 = TermOrder('lex',2)+TermOrder('neglex',3) - sage: T2 = TermOrder('lex',2)+TermOrder('neglex',3) + sage: T1 = TermOrder('lex',2) + TermOrder('neglex',3) + sage: T2 = TermOrder('lex',2) + TermOrder('neglex',3) sage: T1 == T2 True @@ -1953,12 +1966,12 @@ def __eq__(self, other): def __ne__(self, other): """ - Return true if self and other are not equal. + Return ``True`` if ``self`` and ``other`` are not equal. EXAMPLES:: - sage: T1 = TermOrder('lex',2)+TermOrder('lex',3) - sage: T2 = TermOrder('lex',3)+TermOrder('lex',2) + sage: T1 = TermOrder('lex',2) + TermOrder('lex',3) + sage: T2 = TermOrder('lex',3) + TermOrder('lex',2) sage: T1 != T2 True """ @@ -2063,7 +2076,7 @@ def __iter__(self): def is_global(self): r""" - Return true if this term order is definitely + Return ``True`` if this term order is definitely global. Return false otherwise, which includes unknown term orders. @@ -2095,7 +2108,7 @@ def is_global(self): def is_local(self): r""" - Return true if this term order is definitely + Return ``True`` if this term order is definitely local. Return false otherwise, which includes unknown term orders. @@ -2122,11 +2135,11 @@ def is_local(self): def is_block_order(self): """ - Return true if self is a block term order. + Return ``True`` if ``self`` is a block term order. EXAMPLES:: - sage: t=TermOrder('deglex',2)+TermOrder('lex',2) + sage: t = TermOrder('deglex',2) + TermOrder('lex',2) sage: t.is_block_order() True """ @@ -2134,11 +2147,11 @@ def is_block_order(self): def is_weighted_degree_order(self): """ - Return true if self is a weighted degree term order. + Return ``True`` if ``self`` is a weighted degree term order. EXAMPLES:: - sage: t=TermOrder('wdeglex',(2,3)) + sage: t = TermOrder('wdeglex',(2,3)) sage: t.is_weighted_degree_order() True """ @@ -2156,13 +2169,13 @@ def termorder_from_singular(S): EXAMPLES:: sage: from sage.rings.polynomial.term_order import termorder_from_singular - sage: singular.eval('ring r1 = (9,x),(a,b,c,d,e,f),(M((1,2,3,0)),wp(2,3),lp)') + sage: singular.eval('ring r1 = (9,x),(a,b,c,d,e,f),(M((1,2,3,0)),wp(2,3),lp)') # needs sage.libs.singular '' - sage: termorder_from_singular(singular) + sage: termorder_from_singular(singular) # needs sage.libs.singular Block term order with blocks: (Matrix term order with matrix - [1 2] - [3 0], + [1 2] + [3 0], Weighted degree reverse lexicographic term order with weights (2, 3), Lexicographic term order of length 2) @@ -2170,6 +2183,7 @@ def termorder_from_singular(S): This information is reflected in ``_singular_ringorder_column`` attribute of the term order. :: + sage: # needs sage.libs.singular sage: singular.ring(0, '(x,y,z,w)', '(C,dp(2),lp(2))') polynomial ring, over a field, global ordering // coefficients: QQ @@ -2187,6 +2201,7 @@ def termorder_from_singular(S): sage: T._singular_ringorder_column 0 + sage: # needs sage.libs.singular sage: singular.ring(0, '(x,y,z,w)', '(c,dp(2),lp(2))') polynomial ring, over a field, global ordering // coefficients: QQ @@ -2209,6 +2224,7 @@ def termorder_from_singular(S): Check that ``degneglex`` term orders are converted correctly (:trac:`29635`):: + sage: # needs sage.libs.singular sage: _ = singular.ring(0, '(x,y,z,w)', '(a(1:4),ls(4))') sage: termorder_from_singular(singular).singular_str() '(a(1:4),ls(4))' @@ -2228,7 +2244,7 @@ def termorder_from_singular(S): ringorder_column = None weights_one_block = False for idx, block in enumerate(T): - blocktype = singular.eval('%s[1]'%block.name()) + blocktype = singular.eval('%s[1]' % block.name()) if blocktype in ['a']: weights = list(block[2].sage()) weights_one_block = all(w == 1 for w in weights) @@ -2250,7 +2266,7 @@ def termorder_from_singular(S): elif blocktype[0] in ['w','W']: order.append(TermOrder(inv_singular_name_mapping[blocktype], list(block[2].sage()))) else: - order.append(TermOrder(inv_singular_name_mapping[blocktype], ZZ(singular.eval("size(%s[2])"%block.name())))) + order.append(TermOrder(inv_singular_name_mapping[blocktype], ZZ(singular.eval("size(%s[2])" % block.name())))) weights_one_block = False if not order: diff --git a/src/sage/rings/polynomial/toy_buchberger.py b/src/sage/rings/polynomial/toy_buchberger.py index 2f02ca65e05..4edd2491b6d 100644 --- a/src/sage/rings/polynomial/toy_buchberger.py +++ b/src/sage/rings/polynomial/toy_buchberger.py @@ -23,16 +23,17 @@ Consider Katsura-6 with respect to a ``degrevlex`` ordering. :: + sage: # needs sage.libs.singular sage.rings.finite_rings sage: from sage.rings.polynomial.toy_buchberger import * sage: P.<a,b,c,e,f,g,h,i,j,k> = PolynomialRing(GF(32003)) sage: I = sage.rings.ideal.Katsura(P, 6) - sage: g1 = buchberger(I) sage: g2 = buchberger_improved(I) sage: g3 = I.groebner_basis() All algorithms actually compute a Groebner basis:: + sage: # needs sage.libs.singular sage.rings.finite_rings sage: Ideal(g1).basis_is_groebner() True sage: Ideal(g2).basis_is_groebner() @@ -42,20 +43,21 @@ The results are correct:: + sage: # needs sage.libs.singular sage.rings.finite_rings sage: Ideal(g1) == Ideal(g2) == Ideal(g3) True If ``get_verbose()`` is `\ge 1`, a protocol is provided:: + sage: # needs sage.libs.singular sage.rings.finite_rings sage: from sage.misc.verbose import set_verbose sage: set_verbose(1) sage: P.<a,b,c> = PolynomialRing(GF(127)) sage: I = sage.rings.ideal.Katsura(P) // sage... ideal - sage: I - Ideal (a + 2*b + 2*c - 1, a^2 + 2*b^2 + 2*c^2 - a, 2*a*b + 2*b*c - b) of Multivariate Polynomial Ring in a, b, c over Finite Field of size 127 - + Ideal (a + 2*b + 2*c - 1, a^2 + 2*b^2 + 2*c^2 - a, 2*a*b + 2*b*c - b) + of Multivariate Polynomial Ring in a, b, c over Finite Field of size 127 sage: buchberger(I) # random (a + 2*b + 2*c - 1, a^2 + 2*b^2 + 2*c^2 - a) => -2*b^2 - 6*b*c - 6*c^2 + b + 2*c G: set([a + 2*b + 2*c - 1, 2*a*b + 2*b*c - b, a^2 + 2*b^2 + 2*c^2 - a, -2*b^2 - 6*b*c - 6*c^2 + b + 2*c]) @@ -117,6 +119,7 @@ The original Buchberger algorithm performs 15 useless reductions to zero for this example:: + sage: # needs sage.libs.singular sage.rings.finite_rings sage: gb = buchberger(I) ... 15 reductions to zero. @@ -124,11 +127,13 @@ The 'improved' Buchberger algorithm in contrast only performs 1 reduction to zero:: + sage: # needs sage.libs.singular sage.rings.finite_rings sage: gb = buchberger_improved(I) ... 1 reductions to zero. sage: sorted(gb) - [a + 2*b + 2*c - 1, b*c + 52*c^2 + 38*b + 25*c, b^2 - 26*c^2 - 51*b + 51*c, c^3 + 22*c^2 - 55*b + 49*c] + [a + 2*b + 2*c - 1, b*c + 52*c^2 + 38*b + 25*c, + b^2 - 26*c^2 - 51*b + 51*c, c^3 + 22*c^2 - 55*b + 49*c] AUTHORS: @@ -191,10 +196,10 @@ def buchberger(F): sage: R.<x,y,z> = PolynomialRing(QQ) sage: I = R.ideal([x^2 - z - 1, z^2 - y - 1, x*y^2 - x - 1]) sage: set_verbose(0) - sage: gb = buchberger(I) - sage: gb.is_groebner() + sage: gb = buchberger(I) # needs sage.libs.singular + sage: gb.is_groebner() # needs sage.libs.singular True - sage: gb.ideal() == I + sage: gb.ideal() == I # needs sage.libs.singular True """ G = set(F.gens()) @@ -249,7 +254,7 @@ def buchberger_improved(F): sage: from sage.rings.polynomial.toy_buchberger import buchberger_improved sage: R.<x,y,z> = PolynomialRing(QQ) sage: set_verbose(0) - sage: sorted(buchberger_improved(R.ideal([x^4 - y - z, x*y*z - 1]))) + sage: sorted(buchberger_improved(R.ideal([x^4 - y - z, x*y*z - 1]))) # needs sage.libs.singular [x*y*z - 1, x^3 - y^2*z - y*z^2, y^3*z^2 + y^2*z^3 - x^2] """ F = inter_reduction(F.gens()) @@ -382,8 +387,8 @@ def select(P): sage: from sage.rings.polynomial.toy_buchberger import select sage: R.<x,y,z> = PolynomialRing(QQ, order='lex') - sage: ps = [x^3 - z -1, z^3 - y - 1, x^5 - y - 2] - sage: pairs = [[ps[i], ps[j]] for i in range(3) for j in range(i+1, 3)] + sage: ps = [x^3 - z - 1, z^3 - y - 1, x^5 - y - 2] + sage: pairs = [[ps[i], ps[j]] for i in range(3) for j in range(i + 1, 3)] sage: select(pairs) [x^3 - z - 1, -y + z^3 - 1] """ @@ -401,10 +406,10 @@ def inter_reduction(Q): OUTPUT: - if ``Q`` is the set `(f_1, ..., f_n)`, this method returns `(g_1, - ..., g_s)` such that: + if ``Q`` is the set `f_1, ..., f_n`, this method returns `g_1, + ..., g_s` such that: - - `<f_1,...,f_n> = <g_1,...,g_s>` + - `(f_1,...,f_n) = (g_1,...,g_s)` - `LM(g_i) \neq LM(g_j)` for all `i \neq j` - `LM(g_i)` does not divide `m` for all monomials `m` of `\{g_1,...,g_{i-1}, g_{i+1},...,g_s\}` @@ -419,10 +424,10 @@ def inter_reduction(Q): :: sage: P.<x,y> = QQ[] - sage: reduced = inter_reduction(set([x^2 - 5*y^2, x^3])) - sage: reduced == set([x*y^2, x^2-5*y^2]) + sage: reduced = inter_reduction(set([x^2 - 5*y^2, x^3])) # needs sage.libs.singular + sage: reduced == set([x*y^2, x^2 - 5*y^2]) # needs sage.libs.singular True - sage: reduced == inter_reduction(set([2*(x^2 - 5*y^2), x^3])) + sage: reduced == inter_reduction(set([2*(x^2 - 5*y^2), x^3])) # needs sage.libs.singular True """ if not Q: diff --git a/src/sage/rings/polynomial/toy_d_basis.py b/src/sage/rings/polynomial/toy_d_basis.py index 07f83100df7..393eb0452b2 100644 --- a/src/sage/rings/polynomial/toy_d_basis.py +++ b/src/sage/rings/polynomial/toy_d_basis.py @@ -20,12 +20,12 @@ First, consider an example from arithmetic geometry:: sage: A.<x,y> = PolynomialRing(ZZ, 2) - sage: B.<X,Y> = PolynomialRing(Rationals(),2) + sage: B.<X,Y> = PolynomialRing(Rationals(), 2) sage: f = -y^2 - y + x^3 + 7*x + 1 sage: fx = f.derivative(x) sage: fy = f.derivative(y) - sage: I = B.ideal([B(f),B(fx),B(fy)]) - sage: I.groebner_basis() + sage: I = B.ideal([B(f), B(fx), B(fy)]) + sage: I.groebner_basis() # needs sage.libs.singular [1] Since the output is 1, we know that there are no generic @@ -34,7 +34,7 @@ To look at the singularities of the arithmetic surface, we need to do the corresponding computation over `\ZZ`:: - sage: I = A.ideal([f,fx,fy]) + sage: I = A.ideal([f, fx, fy]) sage: gb = d_basis(I); gb [x - 2020, y - 11313, 22627] @@ -52,7 +52,7 @@ Another example. This one is from the Magma Handbook:: sage: P.<x, y, z> = PolynomialRing(IntegerRing(), 3, order='lex') - sage: I = ideal( x^2 - 1, y^2 - 1, 2*x*y - z) + sage: I = ideal(x^2 - 1, y^2 - 1, 2*x*y - z) sage: I = Ideal(d_basis(I)) sage: x.reduce(I) x @@ -61,7 +61,7 @@ To compute modulo 4, we can add the generator 4 to our basis.:: - sage: I = ideal( x^2 - 1, y^2 - 1, 2*x*y - z, 4) + sage: I = ideal(x^2 - 1, y^2 - 1, 2*x*y - z, 4) sage: gb = d_basis(I) sage: R = P.change_ring(IntegerModRing(4)) sage: gb = [R(f) for f in gb if R(f)]; gb @@ -79,7 +79,7 @@ there are 4 equations in 3 unknowns). :: sage: P.<x, y, z> = PolynomialRing(IntegerRing(), 3, order='degneglex') - sage: I = ideal( x^2 - 3*y, y^3 - x*y, z^3 - x, x^4 - y*z + 1 ) + sage: I = ideal(x^2 - 3*y, y^3 - x*y, z^3 - x, x^4 - y*z + 1) sage: I.change_ring(P.change_ring(RationalField())).groebner_basis() [1] @@ -96,19 +96,19 @@ sage: factor(282687803443) 101 * 103 * 27173681 - sage: I.change_ring( P.change_ring( GF(101) ) ).groebner_basis() + sage: I.change_ring(P.change_ring(GF(101))).groebner_basis() [z - 33, y + 48, x + 19] - sage: I.change_ring( P.change_ring( GF(103) ) ).groebner_basis() + sage: I.change_ring(P.change_ring(GF(103))).groebner_basis() [z - 18, y + 8, x + 39] - sage: I.change_ring( P.change_ring( GF(27173681) ) ).groebner_basis() + sage: I.change_ring( P.change_ring(GF(27173681))).groebner_basis() # needs sage.libs.pari [z + 10380032, y + 3186055, x - 536027] Of course, modulo any other prime the Groebner basis is trivial so there are no other solutions. For example:: - sage: I.change_ring( P.change_ring( GF(3) ) ).groebner_basis() + sage: I.change_ring(P.change_ring(GF(3))).groebner_basis() [1] AUTHOR: diff --git a/src/sage/rings/polynomial/toy_variety.py b/src/sage/rings/polynomial/toy_variety.py index 3f2a1705989..5b51dc5eb00 100644 --- a/src/sage/rings/polynomial/toy_variety.py +++ b/src/sage/rings/polynomial/toy_variety.py @@ -100,7 +100,7 @@ def coefficient_matrix(polys): sage: from sage.rings.polynomial.toy_variety import coefficient_matrix sage: R.<x,y> = PolynomialRing(QQ) - sage: coefficient_matrix([x^2 + 1, y^2 + 1, x*y + 1]) + sage: coefficient_matrix([x^2 + 1, y^2 + 1, x*y + 1]) # needs sage.modules [1 0 0 1] [0 0 1 1] [0 1 0 1] @@ -159,12 +159,12 @@ def is_linearly_dependent(polys) -> bool: sage: R.<x,y> = PolynomialRing(QQ) sage: B = [x^2 + 1, y^2 + 1, x*y + 1] sage: p = 3*B[0] - 2*B[1] + B[2] - sage: is_linearly_dependent(B + [p]) + sage: is_linearly_dependent(B + [p]) # needs sage.modules True sage: p = x*B[0] - sage: is_linearly_dependent(B + [p]) + sage: is_linearly_dependent(B + [p]) # needs sage.modules False - sage: is_linearly_dependent([]) + sage: is_linearly_dependent([]) # needs sage.modules False """ if not polys: @@ -203,6 +203,7 @@ def linear_representation(p, polys): EXAMPLES:: + sage: # needs sage.modules sage.rings.finite_rings sage: from sage.rings.polynomial.toy_variety import linear_representation sage: R.<x,y> = PolynomialRing(GF(32003)) sage: B = [x^2 + 1, y^2 + 1, x*y + 1] @@ -240,6 +241,7 @@ def triangular_factorization(B, n=-1): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.misc.verbose import set_verbose sage: set_verbose(0) sage: from sage.rings.polynomial.toy_variety import triangular_factorization @@ -248,7 +250,7 @@ def triangular_factorization(B, n=-1): sage: p2 = z^2 - z sage: p3 = (x-2)^2*(y-1)^3 sage: I = R.ideal(p1,p2,p3) - sage: triangular_factorization(I.groebner_basis()) + sage: triangular_factorization(I.groebner_basis()) # needs sage.libs.singular [[x^2 - 4*x + 4, y, z], [x^5 - 3*x^4 + 3*x^3 - x^2, y - 1, z], [x^2 - 4*x + 4, y, z - 1], @@ -314,6 +316,7 @@ def elim_pol(B, n=-1): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.misc.verbose import set_verbose sage: set_verbose(0) sage: from sage.rings.polynomial.toy_variety import elim_pol @@ -322,7 +325,7 @@ def elim_pol(B, n=-1): sage: p2 = z^2 - z sage: p3 = (x-2)^2*(y-1)^3 sage: I = R.ideal(p1,p2,p3) - sage: elim_pol(I.groebner_basis()) + sage: elim_pol(I.groebner_basis()) # needs sage.libs.singular z^2 - z """ # type checking in a probably vain attempt to avoid stupid errors diff --git a/src/sage/rings/polynomial/weil/__init__.py b/src/sage/rings/polynomial/weil/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/rings/power_series_mpoly.pxd b/src/sage/rings/power_series_mpoly.pxd index f822ecc1227..d358ada1356 100644 --- a/src/sage/rings/power_series_mpoly.pxd +++ b/src/sage/rings/power_series_mpoly.pxd @@ -3,6 +3,6 @@ from .power_series_ring_element cimport PowerSeries cdef class PowerSeries_mpoly(PowerSeries): cdef ModuleElement __f - cdef object __poly + cdef object _poly cdef object __list cdef bint _truncated diff --git a/src/sage/rings/power_series_mpoly.pyx b/src/sage/rings/power_series_mpoly.pyx index 2c5b5a7ec0e..be59294e75b 100644 --- a/src/sage/rings/power_series_mpoly.pyx +++ b/src/sage/rings/power_series_mpoly.pyx @@ -1,14 +1,12 @@ # NOT ready to be used -- possibly should be deleted. from .power_series_ring_element cimport PowerSeries -from sage.structure.element cimport Element, ModuleElement, RingElement -from .infinity import infinity, is_Infinite -from sage.libs.pari.all import PariError -from .power_series_ring_element import is_PowerSeries -from . import rational_field +from sage.structure.element cimport Element +from .infinity import infinity from .polynomial.multi_polynomial_ring_base import is_MPolynomialRing from . import power_series_poly + cdef class PowerSeries_mpoly(PowerSeries): def __init__(self, parent, f=0, prec=infinity, int check=1, is_gen=0): @@ -67,7 +65,7 @@ cdef class PowerSeries_mpoly(PowerSeries): def __reduce__(self): # do *not* delete old versions. - return make_powerseries_mpoly_v0, (self._parent, self.__f, self._prec, self.__is_gen) + return make_powerseries_mpoly_v0, (self._parent, self.__f, self._prec, self._is_gen) def __call__(self, *args, **kwds): if len(kwds) == 0 and len(args) == 1: @@ -94,10 +92,10 @@ cdef class PowerSeries_mpoly(PowerSeries): return self.__list def polynomial(self): - if self.__poly is None: + if self._poly is None: S = self.parent()._mpoly_ring() - self.__poly = self.__f.polynomial(S.gens()[-1]) - return self.__poly + self._poly = self.__f.polynomial(S.gens()[-1]) + return self._poly def _mpoly(self): return self.__f @@ -131,8 +129,8 @@ cdef class PowerSeries_mpoly(PowerSeries): EXAMPLES: """ cdef PowerSeries_mpoly right = <PowerSeries_mpoly>right_m - return PowerSeries_mpoly(self._parent, self.__f + right.__f, \ - self.common_prec_c(right), check=True) + return PowerSeries_mpoly(self._parent, self.__f + right.__f, + self.common_prec_c(right), check=True) cpdef _sub_(self, right_m): """ @@ -141,14 +139,16 @@ cdef class PowerSeries_mpoly(PowerSeries): EXAMPLES: """ cdef PowerSeries_mpoly right = <PowerSeries_mpoly>right_m - return PowerSeries_mpoly(self._parent, self.__f - right.__f, \ - self.common_prec_c(right), check=True) + return PowerSeries_mpoly(self._parent, self.__f - right.__f, + self.common_prec_c(right), check=True) cpdef _rmul_(self, Element c): - return PowerSeries_mpoly(self._parent, self.__f._rmul_(c), self._prec, check=False) + return PowerSeries_mpoly(self._parent, self.__f._rmul_(c), + self._prec, check=False) cpdef _lmul_(self, Element c): - return PowerSeries_mpoly(self._parent, self.__f._lmul_(c), self._prec, check=False) + return PowerSeries_mpoly(self._parent, self.__f._lmul_(c), + self._prec, check=False) def make_powerseries_mpoly_v0(parent, f, prec, is_gen): diff --git a/src/sage/rings/power_series_pari.pyx b/src/sage/rings/power_series_pari.pyx index 7b9c2b5c783..94a6d1baacb 100644 --- a/src/sage/rings/power_series_pari.pyx +++ b/src/sage/rings/power_series_pari.pyx @@ -76,7 +76,7 @@ from sage.libs.pari.all import pari from sage.rings.polynomial.polynomial_element cimport Polynomial from sage.rings.power_series_ring_element cimport PowerSeries -from sage.structure.element cimport Element, RingElement +from sage.structure.element cimport Element from sage.structure.parent cimport Parent from sage.rings.infinity import infinity @@ -347,16 +347,14 @@ cdef class PowerSeries_pari(PowerSeries): Substituting `p`-adic numbers:: + sage: # needs sage.rings.padics sage: f(100 + O(5^7)) 5^4 + 3*5^5 + 4*5^6 + 2*5^7 + 2*5^8 + O(5^9) - sage: ff = PowerSeriesRing(pAdicRing(5), 't', implementation='pari')(f) sage: ff (1 + O(5^20))*t^2 + (1 + O(5^20))*t^3 + O(t^6) - sage: ff(100 + O(5^7)) 5^4 + 3*5^5 + 4*5^6 + 2*5^7 + 2*5^8 + O(5^9) - sage: ff(100 + O(2^7)) Traceback (most recent call last): ... @@ -373,17 +371,14 @@ cdef class PowerSeries_pari(PowerSeries): Traceback (most recent call last): ... ValueError: can only substitute elements of positive valuation - sage: f(t^-2) Traceback (most recent call last): ... ValueError: can only substitute elements of positive valuation - - sage: f(2 + O(5^3)) + sage: f(2 + O(5^3)) # needs sage.rings.padics Traceback (most recent call last): ... ValueError: can only substitute elements of positive valuation - sage: g = t^2 + t^3 sage: g(1 + t + O(t^2)) 2 + 5*t + O(t^2) @@ -492,7 +487,7 @@ cdef class PowerSeries_pari(PowerSeries): sage: f[:4] 32 - 80*t + 80*t^2 - 40*t^3 - sage: f = 1 + t^3 - 4*t^4 + O(t^7) ; f + sage: f = 1 + t^3 - 4*t^4 + O(t^7); f 1 + t^3 - 4*t^4 + O(t^7) sage: f[:4] 1 + t^3 + O(t^7) diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index 987e2d3fc65..c7cd78db093 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -5,8 +5,8 @@ Power Series Methods The class ``PowerSeries_poly`` provides additional methods for univariate power series. """ from .power_series_ring_element cimport PowerSeries -from sage.structure.element cimport Element, ModuleElement, RingElement -from .infinity import infinity, is_Infinite +from sage.structure.element cimport Element +from .infinity import infinity from sage.libs.pari.all import pari_gen, PariError @@ -16,10 +16,9 @@ cdef class PowerSeries_poly(PowerSeries): """ EXAMPLES:: - sage: R.<q> = PowerSeriesRing(CC) - sage: R + sage: R.<q> = PowerSeriesRing(CC); R # needs sage.rings.real_mpfr Power Series Ring in q over Complex Field with 53 bits of precision - sage: loads(q.dumps()) == q + sage: loads(q.dumps()) == q # needs sage.rings.real_mpfr True sage: R.<t> = QQ[[]] @@ -34,9 +33,9 @@ cdef class PowerSeries_poly(PowerSeries): Check that :trac:`22216` is fixed:: sage: R.<T> = PowerSeriesRing(QQ) - sage: R(pari('1 + O(T)')) + sage: R(pari('1 + O(T)')) # needs sage.libs.pari 1 + O(T) - sage: R(pari('1/T + O(T)')) + sage: R(pari('1/T + O(T)')) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: series has negative valuation @@ -97,7 +96,7 @@ cdef class PowerSeries_poly(PowerSeries): sage: f == loads(dumps(f)) # indirect doctest True """ - return self.__class__, (self._parent, self.__f, self._prec, self.__is_gen) + return self.__class__, (self._parent, self.__f, self._prec, self._is_gen) def polynomial(self): """ @@ -231,11 +230,11 @@ cdef class PowerSeries_poly(PowerSeries): As can a p-adic integer as long as the coefficient ring is compatible:: - sage: f(100 + O(5^7)) + sage: f(100 + O(5^7)) # needs sage.rings.padics 5^4 + 3*5^5 + 4*5^6 + 2*5^7 + 2*5^8 + O(5^9) - sage: f.change_ring(Zp(5))(100 + O(5^7)) + sage: f.change_ring(Zp(5))(100 + O(5^7)) # needs sage.rings.padics 5^4 + 3*5^5 + 4*5^6 + 2*5^7 + 2*5^8 + O(5^9) - sage: f.change_ring(Zp(5))(100 + O(2^7)) + sage: f.change_ring(Zp(5))(100 + O(2^7)) # needs sage.rings.padics Traceback (most recent call last): ... ValueError: Cannot substitute this value @@ -248,7 +247,7 @@ cdef class PowerSeries_poly(PowerSeries): Traceback (most recent call last): ... ValueError: Can only substitute elements of positive valuation - sage: f(2 + O(5^3)) + sage: f(2 + O(5^3)) # needs sage.rings.padics Traceback (most recent call last): ... ValueError: Can only substitute elements of positive valuation @@ -380,22 +379,22 @@ cdef class PowerSeries_poly(PowerSeries): sage: f._unsafe_mutate(0, 5) sage: f 5 + 6*t^3 + O(t^5) - sage: f._unsafe_mutate(2, 1) ; f + sage: f._unsafe_mutate(2, 1); f 5 + t^2 + 6*t^3 + O(t^5) - Mutating can even bump up the precision:: - sage: f._unsafe_mutate(6, 1) ; f + sage: f._unsafe_mutate(6, 1); f 5 + t^2 + 6*t^3 + t^6 + O(t^7) - sage: f._unsafe_mutate(0, 0) ; f + sage: f._unsafe_mutate(0, 0); f t^2 + 6*t^3 + t^6 + O(t^7) - sage: f._unsafe_mutate(1, 0) ; f + sage: f._unsafe_mutate(1, 0); f t^2 + 6*t^3 + t^6 + O(t^7) - sage: f._unsafe_mutate(11,0) ; f + sage: f._unsafe_mutate(11,0); f t^2 + 6*t^3 + t^6 + O(t^12) sage: g = t + O(t^7) - sage: g._unsafe_mutate(1,0) ; g + sage: g._unsafe_mutate(1,0); g O(t^7) """ self.__f._unsafe_mutate(i, value) @@ -405,13 +404,14 @@ cdef class PowerSeries_poly(PowerSeries): """ Return the ``n``-th coefficient of ``self``. - If ``n`` is a slice object, this will return a power series of the - same precision, whose coefficients are the same as ``self`` for - those indices in the slice, and 0 otherwise. - This returns 0 for negative coefficients and raises an ``IndexError`` if trying to access beyond known coefficients. + If ``n`` is a slice object ``[:k]``, this will return a power + series of the same precision, whose coefficients are the same + as ``self`` for those indices in the slice, and 0 otherwise. + Other kinds of slicing are not allowed. + EXAMPLES:: sage: R.<t> = QQ[[]] @@ -426,20 +426,25 @@ cdef class PowerSeries_poly(PowerSeries): Traceback (most recent call last): ... IndexError: coefficient not known - sage: f[1:4] - doctest:...: DeprecationWarning: polynomial slicing with a start index is deprecated, use list() and slice the resulting list instead - See https://github.com/sagemath/sage/issues/18940 for details. - -17/5*t^3 + O(t^5) + + Using slices:: sage: R.<t> = ZZ[[]] sage: f = (2-t)^5; f 32 - 80*t + 80*t^2 - 40*t^3 + 10*t^4 - t^5 sage: f[:4] 32 - 80*t + 80*t^2 - 40*t^3 - sage: f = 1 + t^3 - 4*t^4 + O(t^7) ; f + sage: f = 1 + t^3 - 4*t^4 + O(t^7); f 1 + t^3 - 4*t^4 + O(t^7) sage: f[:4] 1 + t^3 + O(t^7) + + TESTS:: + + sage: f[1:4] + Traceback (most recent call last): + ... + IndexError: polynomial slicing with a start is not defined """ if isinstance(n, slice): return PowerSeries_poly(self._parent, self.polynomial()[n], @@ -508,8 +513,8 @@ cdef class PowerSeries_poly(PowerSeries): 1.00000000000000 + O(t^4) """ cdef PowerSeries_poly right = <PowerSeries_poly>right_m - return PowerSeries_poly(self._parent, self.__f + right.__f, \ - self.common_prec_c(right), check=True) + return PowerSeries_poly(self._parent, self.__f + right.__f, + self.common_prec_c(right), check=True) cpdef _sub_(self, right_m): """ @@ -523,8 +528,8 @@ cdef class PowerSeries_poly(PowerSeries): 13 - 2*w*t """ cdef PowerSeries_poly right = <PowerSeries_poly>right_m - return PowerSeries_poly(self._parent, self.__f - right.__f, \ - self.common_prec_c(right), check=True) + return PowerSeries_poly(self._parent, self.__f - right.__f, + self.common_prec_c(right), check=True) cpdef _mul_(self, right_r): """ @@ -591,6 +596,7 @@ cdef class PowerSeries_poly(PowerSeries): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: R.<t> = GF(2)[[]] sage: f = t + t^4 + O(t^7) sage: f >> 1 @@ -839,7 +845,7 @@ cdef class PowerSeries_poly(PowerSeries): TESTS:: sage: R.<t> = PowerSeriesRing(QQ, sparse=True) - sage: x = var('x') + sage: x = var('x') # needs sage.symbolic sage: t.derivative(x) Traceback (most recent call last): ... @@ -865,7 +871,7 @@ cdef class PowerSeries_poly(PowerSeries): By default, the integration variable is the variable of the power series. - Otherwise, the integration variable is the optional parameter ``var`` + Otherwise, the integration variable is the optional parameter ``var``. .. NOTE:: @@ -885,7 +891,7 @@ cdef class PowerSeries_poly(PowerSeries): sage: t = PowerSeriesRing(QQ,'t').gen() sage: f = t + 5*t^2 + 21*t^3 - sage: g = f.integral() ; g + sage: g = f.integral(); g 1/2*t^2 + 5/3*t^3 + 21/4*t^4 sage: g.parent() Power Series Ring in t over Rational Field @@ -903,15 +909,15 @@ cdef class PowerSeries_poly(PowerSeries): def reverse(self, precision=None): """ - Return the reverse of f, i.e., the series g such that g(f(x)) = x. + Return the reverse of `f`, i.e., the series `g` such that `g(f(x)) = x`. Given an optional argument ``precision``, return the reverse with given precision (note that the reverse can have precision at most - ``f.prec()``). If ``f`` has infinite precision, and the argument + ``f.prec()``). If `f` has infinite precision, and the argument ``precision`` is not given, then the precision of the reverse defaults to the default precision of ``f.parent()``. - Note that this is only possible if the valuation of self is exactly + Note that this is only possible if the valuation of ``self`` is exactly 1. ALGORITHM: @@ -1013,7 +1019,10 @@ cdef class PowerSeries_poly(PowerSeries): sage: R.<x> = PowerSeriesRing(QQ, default_prec=20) sage: (x - x^2).reverse() # get some Catalan numbers - x + x^2 + 2*x^3 + 5*x^4 + 14*x^5 + 42*x^6 + 132*x^7 + 429*x^8 + 1430*x^9 + 4862*x^10 + 16796*x^11 + 58786*x^12 + 208012*x^13 + 742900*x^14 + 2674440*x^15 + 9694845*x^16 + 35357670*x^17 + 129644790*x^18 + 477638700*x^19 + O(x^20) + x + x^2 + 2*x^3 + 5*x^4 + 14*x^5 + 42*x^6 + 132*x^7 + 429*x^8 + 1430*x^9 + + 4862*x^10 + 16796*x^11 + 58786*x^12 + 208012*x^13 + 742900*x^14 + + 2674440*x^15 + 9694845*x^16 + 35357670*x^17 + 129644790*x^18 + + 477638700*x^19 + O(x^20) sage: (x - x^2).reverse(precision=3) x + x^2 + O(x^3) @@ -1026,11 +1035,10 @@ cdef class PowerSeries_poly(PowerSeries): ... ValueError: Series must have valuation one for reversion. - sage: Series = PowerSeriesRing(SR, 'x') - sage: ser = Series([0, pi]) - sage: ser + sage: Series = PowerSeriesRing(SR, 'x') # needs sage.symbolic + sage: ser = Series([0, pi]); ser # needs sage.symbolic pi*x - sage: ser.reverse() + sage: ser.reverse() # needs sage.symbolic 1/pi*x + O(x^20) """ if self.valuation() != 1: @@ -1114,11 +1122,6 @@ cdef class PowerSeries_poly(PowerSeries): a ratio of two polynomials - .. WARNING:: - - The current implementation uses a very slow algorithm and is not - suitable for high orders. - ALGORITHM: This method uses the formula as a quotient of two determinants. @@ -1188,8 +1191,9 @@ cdef class PowerSeries_poly(PowerSeries): EXAMPLES:: + sage: # needs sage.symbolic sage: R.<x> = PowerSeriesRing(QQ) - sage: s = R([1,2,3,4,5],prec=10); s + sage: s = R([1,2,3,4,5], prec=10); s 1 + 2*x + 3*x^2 + 4*x^3 + 5*x^4 + O(x^10) sage: SR(s) 1 + 2*x + 3*x^2 + 4*x^3 + 5*x^4 + Order(x^10) @@ -1209,13 +1213,11 @@ cdef class PowerSeries_poly(PowerSeries): Check that :trac:`18094` is fixed:: sage: R.<x> = PolynomialRing(ZZ) - sage: SR(R(0).add_bigoh(20)) + sage: SR(R(0).add_bigoh(20)) # needs sage.symbolic Order(x^20) """ from sage.symbolic.ring import SR - from sage.rings.infinity import PlusInfinity - poly = self.polynomial() - pex = SR(poly) + pex = SR(self.polynomial()) var = SR.var(self.variable()) return pex.series(var, self.prec()) diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 290a4e316b9..b43306adb36 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -59,6 +59,7 @@ :: + sage: # needs sage.symbolic sage: K.<t> = PowerSeriesRing(SR, default_prec=5) sage: a, b, c = var('a,b,c') sage: f = a + b*t + c*t^2 + O(t^3) @@ -97,10 +98,10 @@ Choose another implementation of the attached polynomial ring:: sage: R.<t> = PowerSeriesRing(ZZ) - sage: type(t.polynomial()) + sage: type(t.polynomial()) # needs sage.libs.flint <... 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'> - sage: S.<s> = PowerSeriesRing(ZZ, implementation='NTL') - sage: type(s.polynomial()) + sage: S.<s> = PowerSeriesRing(ZZ, implementation='NTL') # needs sage.libs.ntl + sage: type(s.polynomial()) # needs sage.libs.ntl <... 'sage.rings.polynomial.polynomial_integer_dense_ntl.Polynomial_integer_dense_ntl'> AUTHORS: @@ -176,21 +177,21 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, INPUT: - - ``base_ring`` - a commutative ring + - ``base_ring`` -- a commutative ring - - ``name``, ``names`` - name(s) of the indeterminate + - ``name``, ``names`` -- name(s) of the indeterminate - - ``default_prec`` - the default precision used if an exact object must + - ``default_prec`` -- the default precision used if an exact object must be changed to an approximate object in order to do an arithmetic operation. If left as ``None``, it will be set to the global default (20) in the univariate case, and 12 in the multivariate case. - - ``sparse`` - (default: ``False``) whether power series + - ``sparse`` -- (default: ``False``) whether power series are represented as sparse objects. - - ``order`` - (default: ``negdeglex``) term ordering, for multivariate case + - ``order`` -- (default: ``negdeglex``) term ordering, for multivariate case - - ``num_gens`` - number of generators, for multivariate case + - ``num_gens`` -- number of generators, for multivariate case There is a unique power series ring over each base ring with given @@ -216,7 +217,7 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, :: - sage: S = PowerSeriesRing(QQ, 'x', default_prec = 15); S + sage: S = PowerSeriesRing(QQ, 'x', default_prec=15); S Power Series Ring in x over Rational Field sage: S.default_prec() 15 @@ -252,19 +253,19 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, Power series ring over polynomial ring:: - sage: H = PowerSeriesRing(PolynomialRing(ZZ,3,'z'),4,'f'); H + sage: H = PowerSeriesRing(PolynomialRing(ZZ,3,'z'), 4, 'f'); H Multivariate Power Series Ring in f0, f1, f2, f3 over Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring Power series ring over finite field:: - sage: S = PowerSeriesRing(GF(65537),'x,y'); S + sage: S = PowerSeriesRing(GF(65537),'x,y'); S # needs sage.rings.finite_rings Multivariate Power Series Ring in x, y over Finite Field of size 65537 Power series ring with many variables:: - sage: R = PowerSeriesRing(ZZ, ['x%s'%p for p in primes(100)]); R + sage: R = PowerSeriesRing(ZZ, ['x%s'%p for p in primes(100)]); R # needs sage.libs.pari Multivariate Power Series Ring in x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, x31, x37, x41, x43, x47, x53, x59, x61, x67, x71, x73, x79, x83, x89, x97 over Integer Ring @@ -274,12 +275,12 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, :: - sage: R.inject_variables() + sage: R.inject_variables() # needs sage.libs.pari Defining x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, x31, x37, x41, x43, x47, x53, x59, x61, x67, x71, x73, x79, x83, x89, x97 - sage: f = x47 + 3*x11*x29 - x19 + R.O(3) - sage: f in R + sage: f = x47 + 3*x11*x29 - x19 + R.O(3) # needs sage.libs.pari + sage: f in R # needs sage.libs.pari True @@ -365,7 +366,6 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, return _multi_variate(base_ring, num_gens=names, names=arg2, order=order, default_prec=default_prec, sparse=sparse) - # univariate case: the arguments to PowerSeriesRing used to be # (base_ring, name=None, default_prec=20, names=None, sparse=False), # and thus that is what the code below expects; this behavior is being @@ -451,7 +451,7 @@ def _single_variate(): def is_PowerSeriesRing(R): """ - Return True if this is a *univariate* power series ring. This is in + Return ``True`` if this is a *univariate* power series ring. This is in keeping with the behavior of ``is_PolynomialRing`` versus ``is_MPolynomialRing``. @@ -481,13 +481,13 @@ def __init__(self, base_ring, name=None, default_prec=None, sparse=False, INPUT: - - ``base_ring`` - a commutative ring + - ``base_ring`` -- a commutative ring - - ``name`` - name of the indeterminate + - ``name`` -- name of the indeterminate - - ``default_prec`` - the default precision + - ``default_prec`` -- the default precision - - ``sparse`` - whether or not power series are + - ``sparse`` -- whether or not power series are sparse - ``implementation`` -- either ``'poly'``, ``'mpoly'``, or @@ -625,7 +625,7 @@ def _repr_(self): sage: R my power series ring """ - s = "Power Series Ring in %s over %s"%(self.variable_name(), self.base_ring()) + s = "Power Series Ring in %s over %s" % (self.variable_name(), self.base_ring()) if self.is_sparse(): s = 'Sparse ' + s return s @@ -669,7 +669,7 @@ def _latex_(self): sage: latex(R) \Bold{F}_{17}[[y_{12}]] """ - return "%s[[%s]]"%(latex.latex(self.base_ring()), self.latex_variable_names()[0]) + return "%s[[%s]]" % (latex.latex(self.base_ring()), self.latex_variable_names()[0]) def _coerce_map_from_(self, S): """ @@ -694,7 +694,7 @@ def _coerce_map_from_(self, S): if self.base_ring().has_coerce_map_from(S): return True if (is_PolynomialRing(S) or is_PowerSeriesRing(S)) and self.base_ring().has_coerce_map_from(S.base_ring()) \ - and self.variable_names()==S.variable_names(): + and self.variable_names() == S.variable_names(): return True def _element_constructor_(self, f, prec=infinity, check=True): @@ -707,12 +707,12 @@ def _element_constructor_(self, f, prec=infinity, check=True): INPUT: - - ``f`` - object, e.g., a power series ring element + - ``f`` -- object, e.g., a power series ring element - - ``prec`` - (default: infinity); truncation precision + - ``prec`` -- (default: infinity); truncation precision for coercion - - ``check`` - bool (default: True), whether to verify + - ``check`` -- bool (default: ``True``), whether to verify that the coefficients, etc., coerce in correctly. @@ -760,13 +760,14 @@ def _element_constructor_(self, f, prec=infinity, check=True): Conversion from symbolic series:: + sage: # needs sage.symbolic sage: x,y = var('x,y') - sage: s=(1/(1-x)).series(x,3); s + sage: s = (1/(1-x)).series(x,3); s 1 + 1*x + 1*x^2 + Order(x^3) sage: R.<x> = PowerSeriesRing(QQ) sage: R(s) 1 + x + x^2 + O(x^3) - sage: ex=(gamma(1-y)).series(y,3) + sage: ex = (gamma(1-y)).series(y,3) sage: R.<y> = PowerSeriesRing(SR) sage: R(ex) 1 + euler_gamma*y + (1/2*euler_gamma^2 + 1/12*pi^2)*y^2 + O(y^3) @@ -824,7 +825,7 @@ def _element_constructor_(self, f, prec=infinity, check=True): def construction(self): """ - Return the functorial construction of self, namely, completion of + Return the functorial construction of ``self``, namely, completion of the univariate polynomial ring with respect to the indeterminate (to a given precision). @@ -899,11 +900,14 @@ def _coerce_impl(self, x): sage: g = R.coerce(f); g 1 + 2*t + 3*t^2 + 4*t^3 sage: parent(g) - Power Series Ring in t over Univariate Polynomial Ring in w over Finite Field of size 7 + Power Series Ring in t over + Univariate Polynomial Ring in w over Finite Field of size 7 sage: S.coerce(g) Traceback (most recent call last): ... - TypeError: no canonical coercion from Power Series Ring in t over Univariate Polynomial Ring in w over Finite Field of size 7 to Power Series Ring in t over Integer Ring + TypeError: no canonical coercion + from Power Series Ring in t over Univariate Polynomial Ring in w over Finite Field of size 7 + to Power Series Ring in t over Integer Ring """ try: P = x.parent() @@ -925,7 +929,7 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): EXAMPLES:: - sage: S = RationalField(); R.<t>=PowerSeriesRing(S) + sage: S = RationalField(); R.<t> = PowerSeriesRing(S) sage: f = R.hom([0]) sage: f(3) 3 @@ -973,9 +977,9 @@ def _poly_ring(self): def base_extend(self, R): """ - Return the power series ring over R in the same variable as self, - assuming there is a canonical coerce map from the base ring of self - to R. + Return the power series ring over `R` in the same variable as ``self``, + assuming there is a canonical coerce map from the base ring of ``self`` + to `R`. EXAMPLES:: @@ -995,7 +999,7 @@ def base_extend(self, R): def change_ring(self, R): """ - Return the power series ring over R in the same variable as self. + Return the power series ring over `R` in the same variable as ``self``. EXAMPLES:: @@ -1007,10 +1011,11 @@ def change_ring(self, R): Traceback (most recent call last): ... TypeError: no base extension defined - sage: R.base_extend(QuadraticField(3,'a')) - Power Series Ring in T over Number Field in a with defining polynomial x^2 - 3 with a = 1.732050807568878? + sage: R.base_extend(QuadraticField(3,'a')) # needs sage.rings.number_field + Power Series Ring in T over Number Field in a + with defining polynomial x^2 - 3 with a = 1.732050807568878? """ - return PowerSeriesRing(R, name = self.variable_name(), default_prec = self.default_prec()) + return PowerSeriesRing(R, name=self.variable_name(), default_prec=self.default_prec()) def change_var(self, var): """ @@ -1023,11 +1028,11 @@ def change_var(self, var): sage: R.change_var('D') Power Series Ring in D over Rational Field """ - return PowerSeriesRing(self.base_ring(), names = var, sparse=self.is_sparse()) + return PowerSeriesRing(self.base_ring(), names=var, sparse=self.is_sparse()) def is_exact(self): """ - Return False since the ring of power series over any ring is not + Return ``False`` since the ring of power series over any ring is not exact. EXAMPLES:: @@ -1097,13 +1102,12 @@ def random_element(self, prec=None, *args, **kwds): r""" Return a random power series. - INPUT: - - ``prec`` - Integer specifying precision of output (default: - default precision of self) + - ``prec`` -- Integer specifying precision of output (default: + default precision of ``self``) - - ``*args, **kwds`` - Passed on to the ``random_element`` method for + - ``*args``, ``**kwds`` -- Passed on to the ``random_element`` method for the base ring OUTPUT: @@ -1112,7 +1116,6 @@ def random_element(self, prec=None, *args, **kwds): random elements from the base ring, randomized subject to the arguments ``*args`` and ``**kwds`` - ALGORITHM: Call the ``random_element`` method on the underlying polynomial @@ -1132,7 +1135,8 @@ def random_element(self, prec=None, *args, **kwds): sage: T.default_prec() 20 sage: T.random_element() # random - 4 + 2*t - t^2 - t^3 + 2*t^4 + t^5 + t^6 - 2*t^7 - t^8 - t^9 + t^11 - 6*t^12 + 2*t^14 + 2*t^16 - t^17 - 3*t^18 + O(t^20) + 4 + 2*t - t^2 - t^3 + 2*t^4 + t^5 + t^6 - 2*t^7 - t^8 - t^9 + t^11 + - 6*t^12 + 2*t^14 + 2*t^16 - t^17 - 3*t^18 + O(t^20) sage: S = PowerSeriesRing(ZZ,'t', default_prec=4) sage: S.random_element() # random 2 - t - 5*t^2 + t^3 + O(t^4) @@ -1145,7 +1149,9 @@ def random_element(self, prec=None, *args, **kwds): sage: SR = PowerSeriesRing(RR,'v') sage: SZ.random_element(x=4, y=6) # random - 4 + 5*v + 5*v^2 + 5*v^3 + 4*v^4 + 5*v^5 + 5*v^6 + 5*v^7 + 4*v^8 + 5*v^9 + 4*v^10 + 4*v^11 + 5*v^12 + 5*v^13 + 5*v^14 + 5*v^15 + 5*v^16 + 5*v^17 + 4*v^18 + 5*v^19 + O(v^20) + 4 + 5*v + 5*v^2 + 5*v^3 + 4*v^4 + 5*v^5 + 5*v^6 + 5*v^7 + 4*v^8 + + 5*v^9 + 4*v^10 + 4*v^11 + 5*v^12 + 5*v^13 + 5*v^14 + 5*v^15 + + 5*v^16 + 5*v^17 + 4*v^18 + 5*v^19 + O(v^20) sage: SZ.random_element(3, x=4, y=6) # random 5 + 4*v + 5*v^2 + O(v^3) sage: SQ.random_element(3, num_bound=3, den_bound=100) # random @@ -1160,7 +1166,7 @@ def random_element(self, prec=None, *args, **kwds): def __contains__(self, x): """ - Return True if x is an element of this power series ring or + Return ``True`` if x is an element of this power series ring or canonically coerces to this ring. EXAMPLES:: @@ -1180,9 +1186,9 @@ def __contains__(self, x): """ return self.has_coerce_map_from(parent(x)) - def is_field(self, proof = True): + def is_field(self, proof=True): """ - Return False since the ring of power series over any ring is never + Return ``False`` since the ring of power series over any ring is never a field. EXAMPLES:: @@ -1195,7 +1201,7 @@ def is_field(self, proof = True): def is_finite(self): """ - Return False since the ring of power series over any ring is never + Return ``False`` since the ring of power series over any ring is never finite. EXAMPLES:: @@ -1233,8 +1239,8 @@ def residue_field(self): sage: R.<x> = PowerSeriesRing(GF(17)) sage: R.residue_field() Finite Field of size 17 - sage: R.<x> = PowerSeriesRing(Zp(5)) - sage: R.residue_field() + sage: R.<x> = PowerSeriesRing(Zp(5)) # needs sage.rings.padics + sage: R.residue_field() # needs sage.rings.padics Finite Field of size 5 """ if self.base_ring().is_field(): @@ -1249,12 +1255,12 @@ def laurent_series_ring(self): EXAMPLES:: - sage: R.<t> = PowerSeriesRing(ZZ,default_prec=5) + sage: R.<t> = PowerSeriesRing(ZZ, default_prec=5) sage: S = R.laurent_series_ring(); S Laurent Series Ring in t over Integer Ring sage: S.default_prec() 5 - sage: f = 1+t; g=1/f; g + sage: f = 1 + t; g = 1/f; g 1 - t + t^2 - t^3 + t^4 + O(t^5) """ try: @@ -1344,7 +1350,7 @@ def unpickle_power_series_ring_v0(base_ring, name, default_prec, sparse): EXAMPLES:: sage: P.<x> = PowerSeriesRing(QQ) - sage: loads(dumps(P)) == P # indirect doctest + sage: loads(dumps(P)) == P # indirect doctest True """ - return PowerSeriesRing(base_ring, name=name, default_prec = default_prec, sparse=sparse) + return PowerSeriesRing(base_ring, name=name, default_prec=default_prec, sparse=sparse) diff --git a/src/sage/rings/power_series_ring_element.pxd b/src/sage/rings/power_series_ring_element.pxd index 067c4f3c6d4..e5c031ee147 100644 --- a/src/sage/rings/power_series_ring_element.pxd +++ b/src/sage/rings/power_series_ring_element.pxd @@ -1,7 +1,7 @@ from sage.structure.element cimport AlgebraElement, RingElement cdef class PowerSeries(AlgebraElement): - cdef char __is_gen + cdef char _is_gen cdef _prec cdef common_prec_c(self, PowerSeries other) #_prec(self, RingElement right_r) diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 2422521fba8..8bfabb73701 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -95,53 +95,44 @@ With power series the behavior is the same. # https://www.gnu.org/licenses/ # **************************************************************************** -import operator - from cpython.object cimport Py_EQ, Py_NE from .infinity import infinity, is_Infinite from sage.rings.rational_field import QQ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -import sage.rings.polynomial.polynomial_element import sage.misc.misc import sage.arith.all as arith import sage.misc.latex -from . import rational_field -from . import integer_ring from .integer import Integer from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from warnings import warn from sage.categories.fields import Fields _Fields = Fields() from sage.misc.derivative import multi_derivative - -Polynomial = sage.rings.polynomial.polynomial_element.Polynomial_generic_dense - -from sage.structure.element cimport AlgebraElement, RingElement, ModuleElement, Element +from sage.structure.element cimport AlgebraElement, RingElement from sage.structure.richcmp cimport richcmp def is_PowerSeries(x): """ - Return True if ``x`` is an instance of a univariate + Return ``True`` if ``x`` is an instance of a univariate or multivariate power series. EXAMPLES:: sage: R.<x> = PowerSeriesRing(ZZ) sage: from sage.rings.power_series_ring_element import is_PowerSeries - sage: is_PowerSeries(1+x^2) + sage: is_PowerSeries(1 + x^2) True - sage: is_PowerSeries(x-x) + sage: is_PowerSeries(x - x) True sage: is_PowerSeries(0) False - sage: var('x') + sage: var('x') # needs sage.symbolic x - sage: is_PowerSeries(1+x^2) + sage: is_PowerSeries(1 + x^2) # needs sage.symbolic False """ return isinstance(x, PowerSeries) @@ -161,14 +152,14 @@ cdef class PowerSeries(AlgebraElement): EXAMPLES:: - sage: PowerSeriesRing(CC, 'q') + sage: PowerSeriesRing(CC, 'q') # needs sage.rings.real_mpfr Power Series Ring in q over Complex Field with 53 bits of precision - sage: T = PowerSeriesRing(GF(3),5,'t'); T - Multivariate Power Series Ring in t0, t1, t2, t3, t4 over Finite - Field of size 3 + sage: T = PowerSeriesRing(GF(3), 5, 't'); T + Multivariate Power Series Ring in t0, t1, t2, t3, t4 + over Finite Field of size 3 """ AlgebraElement.__init__(self, parent) - self.__is_gen = is_gen + self._is_gen = is_gen self._prec = prec def __hash__(self): @@ -222,7 +213,7 @@ cdef class PowerSeries(AlgebraElement): def is_gen(self): """ - Return True if this is the generator (the variable) of the power + Return ``True`` if this is the generator (the variable) of the power series ring. EXAMPLES:: @@ -243,7 +234,7 @@ cdef class PowerSeries(AlgebraElement): sage: 1*t == t True """ - return bool(self.__is_gen) + return bool(self._is_gen) def _im_gens_(self, codomain, im_gens, base_map=None): """ @@ -301,18 +292,18 @@ cdef class PowerSeries(AlgebraElement): :: - sage: K.<a> = NumberField(cyclotomic_polynomial(3), 'a') - sage: R.<t> = K[['t']] - sage: (4*t).change_ring(ZZ) + sage: K.<a> = NumberField(cyclotomic_polynomial(3), 'a') # needs sage.rings.number_field + sage: R.<t> = K[['t']] # needs sage.rings.number_field + sage: (4*t).change_ring(ZZ) # needs sage.rings.number_field 4*t This does not succeed because ``ZZ(K(a+1))`` is not defined. :: - sage: K.<a> = NumberField(cyclotomic_polynomial(3), 'a') - sage: R.<t> = K[['t']] - sage: ((a+1)*t).change_ring(ZZ) + sage: K.<a> = NumberField(cyclotomic_polynomial(3), 'a') # needs sage.rings.number_field + sage: R.<t> = K[['t']] # needs sage.rings.number_field + sage: ((a+1)*t).change_ring(ZZ) # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: Unable to coerce a + 1 to an integer @@ -451,8 +442,9 @@ cdef class PowerSeries(AlgebraElement): EXAMPLES:: + sage: from sage.rings.power_series_ring_element import PowerSeries sage: R.<x> = PowerSeriesRing(ZZ) - sage: PowerSeries.list(1+x^2) + sage: PowerSeries.list(1 + x^2) Traceback (most recent call last): ... NotImplementedError @@ -471,8 +463,9 @@ cdef class PowerSeries(AlgebraElement): EXAMPLES:: + sage: from sage.rings.power_series_ring_element import PowerSeries sage: R.<x> = PowerSeriesRing(ZZ) - sage: PowerSeries.polynomial(1+x^2) + sage: PowerSeries.polynomial(1 + x^2) Traceback (most recent call last): ... NotImplementedError @@ -530,8 +523,8 @@ cdef class PowerSeries(AlgebraElement): EXAMPLES:: - sage: R.<t> = GF(49,'alpha')[[]] - sage: (t^2 + O(t^3)).base_ring() + sage: R.<t> = GF(49,'alpha')[[]] # needs sage.rings.finite_rings + sage: (t^2 + O(t^3)).base_ring() # needs sage.rings.finite_rings Finite Field in alpha of size 7^2 """ return self._parent.base_ring() @@ -702,7 +695,7 @@ cdef class PowerSeries(AlgebraElement): v = self.list() m = len(v) first = True - for n in xrange(m): + for n in range(m): x = v[n] x = repr(x) if x != '0': @@ -765,7 +758,7 @@ cdef class PowerSeries(AlgebraElement): X = self._parent.latex_variable_names()[0] atomic_repr = self._parent.base_ring()._repr_option('element_is_atomic') first = True - for n in xrange(m): + for n in range(m): x = v[n] x = sage.misc.latex.latex(x) if x != '0': @@ -854,6 +847,7 @@ cdef class PowerSeries(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.complex_double sage.symbolic sage: R.<m> = CDF[[]] sage: f = CDF(pi)^2 + m^3 + CDF(e)*m^4 + O(m^10); f # abs tol 5e-16 9.869604401089358 + 0.0*m + 0.0*m^2 + 1.0*m^3 + 2.718281828459045*m^4 + O(m^10) @@ -952,7 +946,7 @@ cdef class PowerSeries(AlgebraElement): def __bool__(self): """ - Return True if this power series is not equal to 0. + Return ``True`` if this power series is not equal to 0. EXAMPLES:: @@ -972,7 +966,7 @@ cdef class PowerSeries(AlgebraElement): def is_unit(self): """ - Return True if this power series is invertible. + Return ``True`` if this power series is invertible. A power series is invertible precisely when the constant term is invertible. @@ -1113,9 +1107,9 @@ cdef class PowerSeries(AlgebraElement): """ EXAMPLES:: - sage: R.<T> = Qp(7)[[]] - sage: f = (48*67 + 46*67^2)*T + (1 + 42*67 + 5*67^3)*T^2 + O(T^3) - sage: f % 67 + sage: R.<T> = Qp(7)[[]] # needs sage.rings.padics + sage: f = (48*67 + 46*67^2)*T + (1 + 42*67 + 5*67^3)*T^2 + O(T^3) # needs sage.rings.padics + sage: f % 67 # needs sage.rings.padics T^2 + O(T^3) """ from sage.rings.power_series_ring import PowerSeriesRing @@ -1203,6 +1197,7 @@ cdef class PowerSeries(AlgebraElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: R.<x> = PowerSeriesRing(QQ, implementation='pari') sage: f = exp(x) + O(x^7); f 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + 1/720*x^6 + O(x^7) @@ -1221,6 +1216,7 @@ cdef class PowerSeries(AlgebraElement): EXAMPLES:: + sage: # needs sage.libs.pari sage: R.<x> = PowerSeriesRing(QQ, implementation='pari') sage: f = exp(x) + O(x^7) sage: f >> 3 @@ -1236,7 +1232,7 @@ cdef class PowerSeries(AlgebraElement): def is_monomial(self): """ - Return True if this element is a monomial. That is, if self is + Return ``True`` if this element is a monomial. That is, if self is `x^n` for some non-negative integer `n`. EXAMPLES:: @@ -1275,9 +1271,9 @@ cdef class PowerSeries(AlgebraElement): EXAMPLES:: - sage: R.<x> = SR[[]] - sage: f = (1+I)*x^2 + 3*x - I - sage: f.map_coefficients(lambda z: z.conjugate()) + sage: R.<x> = SR[[]] # needs sage.symbolic + sage: f = (1+I)*x^2 + 3*x - I # needs sage.symbolic + sage: f.map_coefficients(lambda z: z.conjugate()) # needs sage.symbolic I + 3*x + (-I + 1)*x^2 sage: R.<x> = ZZ[[]] sage: f = x^2 + 2 @@ -1294,7 +1290,7 @@ cdef class PowerSeries(AlgebraElement): 1 + x sage: g.parent() Power Series Ring in x over Integer Ring - sage: g = f.map_coefficients(residue, new_base_ring = k); g + sage: g = f.map_coefficients(residue, new_base_ring=k); g 1 + x sage: g.parent() Power Series Ring in x over Finite Field of size 2 @@ -1345,8 +1341,8 @@ cdef class PowerSeries(AlgebraElement): EXAMPLES:: sage: t = PowerSeriesRing(QQ, 't').gen() - sage: s = sum(factorial(k) * t**k for k in range(12)).O(12) - sage: s.jacobi_continued_fraction() + sage: s = sum(factorial(k) * t**k for k in range(12)).O(12) # needs sage.rings.complex_double + sage: s.jacobi_continued_fraction() # needs sage.rings.complex_double ((-1, -1), (-3, -4), (-5, -9), (-7, -16), (-9, -25)) Another example:: @@ -1464,7 +1460,7 @@ cdef class PowerSeries(AlgebraElement): def is_square(self): """ - Return True if this function has a square root in this ring, e.g., + Return ``True`` if this function has a square root in this ring, e.g., there is an element `y` in ``self.parent()`` such that `y^2` equals ``self``. @@ -1566,7 +1562,7 @@ cdef class PowerSeries(AlgebraElement): :: - sage: K.<t> = PowerSeriesRing(CDF, 5) + sage: K.<t> = PowerSeriesRing(CDF, 5) # needs sage.rings.complex_double sage: v = sqrt(-1 + t + t^3, all=True); v [1.0*I - 0.5*I*t - 0.125*I*t^2 - 0.5625*I*t^3 - 0.2890625*I*t^4 + O(t^5), -1.0*I + 0.5*I*t + 0.125*I*t^2 + 0.5625*I*t^3 + 0.2890625*I*t^4 + O(t^5)] @@ -2036,7 +2032,7 @@ cdef class PowerSeries(AlgebraElement): If the power series has a non-zero constant coefficient `c`, one raises an error:: - sage: g = 2+f + sage: g = 2 + f sage: tan(g) Traceback (most recent call last): ... @@ -2090,7 +2086,7 @@ cdef class PowerSeries(AlgebraElement): sage: T.<a,b> = PowerSeriesRing(ZZ,2) sage: f = a + b + a*b + T.O(3) - sage: sin(f) + sage: sinh(f) a + b + a*b + O(a, b)^3 sage: f.sinh() a + b + a*b + O(a, b)^3 @@ -2100,7 +2096,7 @@ cdef class PowerSeries(AlgebraElement): If the power series has a non-zero constant coefficient `c`, one raises an error:: - sage: g = 2+f + sage: g = 2 + f sage: sinh(g) Traceback (most recent call last): ... @@ -2189,7 +2185,7 @@ cdef class PowerSeries(AlgebraElement): If the power series has a non-zero constant coefficient `c`, one raises an error:: - sage: g = 2+f + sage: g = 2 + f sage: cosh(g) Traceback (most recent call last): ... @@ -2277,7 +2273,7 @@ cdef class PowerSeries(AlgebraElement): If the power series has a non-zero constant coefficient `c`, one raises an error:: - sage: g = 2+f + sage: g = 2 + f sage: tanh(g) Traceback (most recent call last): ... @@ -2520,7 +2516,7 @@ cdef class PowerSeries(AlgebraElement): :: sage: R.<x> = PowerSeriesRing(ZZ) - sage: (1 + x + O(x^2)).exp() + sage: (1 + x + O(x^2)).exp() # needs sage.symbolic Traceback (most recent call last): ... ArithmeticError: exponential of constant term does not belong to coefficient ring (consider working in a larger ring) @@ -2578,7 +2574,7 @@ cdef class PowerSeries(AlgebraElement): sage: t.exp().log() t + O(t^10) - sage: (1+t).log().exp() + sage: (1 + t).log().exp() 1 + t + O(t^10) sage: (-1 + t + O(t^10)).log() @@ -2617,7 +2613,7 @@ cdef class PowerSeries(AlgebraElement): 1 + x^2 + x^10 sage: p.V(3) 1 + x^6 + x^30 - sage: (p+O(x^20)).V(3) + sage: (p + O(x^20)).V(3) 1 + x^6 + x^30 + O(x^60) """ v = self.list() @@ -2652,7 +2648,7 @@ cdef class PowerSeries(AlgebraElement): Dense examples:: sage: R.<t> = PowerSeriesRing(ZZ) - sage: f = 17*t^100 +O(t^110) + sage: f = 17*t^100 + O(t^110) sage: f.valuation() 100 sage: t.valuation() @@ -2744,7 +2740,7 @@ cdef class PowerSeries(AlgebraElement): EXAMPLES:: sage: k.<w> = QQ[[]] - sage: f = 1+17*w+15*w^3+O(w^5) + sage: f = 1 + 17*w + 15*w^3 + O(w^5) sage: parent(f) Power Series Ring in w over Rational Field sage: g = f.laurent_series(); g @@ -2790,27 +2786,27 @@ cdef class PowerSeries(AlgebraElement): There are currently limits to the possible base rings over which this function works. See the documentation for - ``sage.rings.polynomial.polynomial_element.Polynomial.__pari__`` + :meth:`~sage.rings.polynomial.polynomial_element.Polynomial.__pari__` EXAMPLES:: sage: k.<w> = QQ[[]] - sage: f = 1+17*w+15*w^3+O(w^5) - sage: pari(f) # indirect doctest + sage: f = 1 + 17*w + 15*w^3 + O(w^5) + sage: pari(f) # indirect doctest # needs sage.libs.pari 1 + 17*w + 15*w^3 + O(w^5) - sage: pari(1 - 19*w + w^5) # indirect doctest + sage: pari(1 - 19*w + w^5) # indirect doctest # needs sage.libs.pari w^5 - 19*w + 1 sage: R.<x> = Zmod(6)[[]] - sage: pari(1 + x + 8*x^3 + O(x^8)) # indirect doctest + sage: pari(1 + x + 8*x^3 + O(x^8)) # indirect doctest # needs sage.libs.pari Mod(1, 6) + Mod(1, 6)*x + Mod(2, 6)*x^3 + O(x^8) TESTS:: - sage: pari(1 + O(x^1)) + sage: pari(1 + O(x^1)) # needs sage.libs.pari Mod(1, 6) + O(x) - sage: pari(O(x^1)) + sage: pari(O(x^1)) # needs sage.libs.pari O(x) - sage: pari(O(x^0)) + sage: pari(O(x^0)) # needs sage.libs.pari O(x^0) """ n = self.prec() diff --git a/src/sage/rings/puiseux_series_ring.py b/src/sage/rings/puiseux_series_ring.py index 27a91d6a187..2f761c51925 100644 --- a/src/sage/rings/puiseux_series_ring.py +++ b/src/sage/rings/puiseux_series_ring.py @@ -111,7 +111,7 @@ def _repr_(self): EXAMPLES:: - sage: PuiseuxSeriesRing(AA, 'y') + sage: PuiseuxSeriesRing(AA, 'y') # needs sage.rings.number_field Puiseux Series Ring in y over Algebraic Real Field """ s = "Puiseux Series Ring in {} over {}".format(self.variable_name(), @@ -302,8 +302,8 @@ def _element_constructor_(self, x, e=1, prec=infinity): sage: P(z) + y**(1/2) 3 + y^(1/2) + 2*y + y^2 + 2*y^3 + O(y^5) - sage: from sage.modular.etaproducts import qexp_eta - sage: y^(1/24)*qexp_eta(P, prec=30) + sage: from sage.modular.etaproducts import qexp_eta # needs sage.modular + sage: y^(1/24)*qexp_eta(P, prec=30) # needs sage.modular y^(1/24) - y^(25/24) - y^(49/24) + y^(121/24) + y^(169/24) - y^(289/24) - y^(361/24) + y^(529/24) + y^(625/24) + O(y^(721/24)) """ P = parent(x) @@ -395,8 +395,8 @@ def gen(self, n=0): EXAMPLES:: - sage: A = PuiseuxSeriesRing(AA, 'z') - sage: A.gen() + sage: A = PuiseuxSeriesRing(AA, 'z') # needs sage.rings.number_field + sage: A.gen() # needs sage.rings.number_field z """ if n != 0: @@ -409,8 +409,8 @@ def ngens(self): EXAMPLES:: - sage: A = PuiseuxSeriesRing(AA, 'z') - sage: A.ngens() + sage: A = PuiseuxSeriesRing(AA, 'z') # needs sage.rings.number_field + sage: A.ngens() # needs sage.rings.number_field 1 """ return 1 @@ -421,8 +421,8 @@ def laurent_series_ring(self): EXAMPLES:: - sage: A = PuiseuxSeriesRing(AA, 'z') - sage: A.laurent_series_ring() + sage: A = PuiseuxSeriesRing(AA, 'z') # needs sage.rings.number_field + sage: A.laurent_series_ring() # needs sage.rings.number_field Laurent Series Ring in z over Algebraic Real Field """ return self._laurent_series_ring @@ -433,8 +433,8 @@ def default_prec(self): EXAMPLES:: - sage: A = PuiseuxSeriesRing(AA, 'z') - sage: A.default_prec() + sage: A = PuiseuxSeriesRing(AA, 'z') # needs sage.rings.number_field + sage: A.default_prec() # needs sage.rings.number_field 20 """ return self.laurent_series_ring().default_prec() diff --git a/src/sage/rings/puiseux_series_ring_element.pyx b/src/sage/rings/puiseux_series_ring_element.pyx index 7fe08d1b46d..503d11ee975 100644 --- a/src/sage/rings/puiseux_series_ring_element.pyx +++ b/src/sage/rings/puiseux_series_ring_element.pyx @@ -46,7 +46,7 @@ Other arithmetic can be performed with Puiseux Series:: Mind the base ring. However, the base ring can be changed:: - sage: I*q + sage: I*q # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for *: 'Number Field in I with defining polynomial x^2 + 1 with I = 1*I' and 'Puiseux Series Ring in x over Rational Field' @@ -104,17 +104,12 @@ REFERENCES: from sage.arith.functions import lcm from sage.arith.misc import gcd -from sage.ext.fast_callable import fast_callable -from sage.rings.big_oh import O from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.complex_mpfr import ComplexField from sage.rings.infinity import infinity from sage.rings.laurent_series_ring_element cimport LaurentSeries -from sage.rings.laurent_series_ring import LaurentSeriesRing -from sage.rings.power_series_ring_element cimport PowerSeries -from sage.structure.element cimport (Element, ModuleElement, - RingElement, AlgebraElement) +from sage.structure.element cimport (Element, AlgebraElement) from sage.structure.richcmp cimport richcmp @@ -223,10 +218,11 @@ cdef class PuiseuxSeries(AlgebraElement): """ EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = PuiseuxSeriesRing(ZZ) sage: p = x^(1/3) + x**3 sage: t = p._im_gens_(QQbar, [2]) - sage: t in QQbar + sage: t in QQbar True sage: f = R.hom([QQbar(2)], check=False) sage: t == f(p) @@ -246,8 +242,8 @@ cdef class PuiseuxSeries(AlgebraElement): sage: R.zero() 0 - sage: S.<t> = PuiseuxSeriesRing(Zp(5)) - sage: t**(1/2) + 5 * t^(1/3) + sage: S.<t> = PuiseuxSeriesRing(Zp(5)) # needs sage.rings.padics + sage: t**(1/2) + 5 * t^(1/3) # needs sage.rings.padics (5 + O(5^21))*t^(1/3) + (1 + O(5^20))*t^(1/2) """ laurent = self.laurent_part() @@ -305,7 +301,7 @@ cdef class PuiseuxSeries(AlgebraElement): sage: p = x^(1/2) + x**3-x**(-1/4) sage: p(16) 8199/2 - sage: p(pi.n()) + sage: p(pi.n()) # needs sage.symbolic 32.0276049867404 """ # use x.nth_root since x**(1/self._e) returns oo when x = 0 @@ -443,9 +439,9 @@ cdef class PuiseuxSeries(AlgebraElement): EXAMPLES:: - sage: P.<y> = PuiseuxSeriesRing(Zp(3)) - sage: t = y^(2/5) + O(y) - sage: 5*t # indirect doctest + sage: P.<y> = PuiseuxSeriesRing(Zp(3)) # needs sage.rings.padics + sage: t = y^(2/5) + O(y) # needs sage.rings.padics + sage: 5*t # indirect doctest # needs sage.rings.padics (2 + 3 + O(3^20))*y^(2/5) + O(y) """ return type(self)(self._parent, self._l._lmul_(c), self._e) @@ -1023,6 +1019,7 @@ cdef class PuiseuxSeries(AlgebraElement): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = PuiseuxSeriesRing(QQbar) sage: p = x**(3/2) - QQbar(I)*x**(1/2) sage: p.power_series() diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index d9eee8fd318..9602d569984 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -68,7 +68,7 @@ True sage: (sqrt(5 + 2*sqrt(QQbar(6))) - sqrt(QQbar(3)))^2 == 2 True - sage: AA((sqrt(5 + 2*sqrt(6)) - sqrt(3))^2) == 2 + sage: AA((sqrt(5 + 2*sqrt(6)) - sqrt(3))^2) == 2 # needs sage.symbolic True For a monic cubic polynomial `x^3 + bx^2 + cx + d` with roots `s1`, @@ -109,6 +109,7 @@ We can convert from symbolic expressions:: + sage: # needs sage.symbolic sage: QQbar(sqrt(-5)) 2.236067977499790?*I sage: AA(sqrt(2) + sqrt(3)) @@ -133,9 +134,9 @@ The coercion, however, goes in the other direction, since not all symbolic expressions are algebraic numbers:: - sage: QQbar(sqrt(2)) + sqrt(3) + sage: QQbar(sqrt(2)) + sqrt(3) # needs sage.symbolic sqrt(3) + 1.414213562373095? - sage: QQbar(sqrt(2) + QQbar(sqrt(3))) + sage: QQbar(sqrt(2) + QQbar(sqrt(3))) # needs sage.symbolic 3.146264369941973? Note the different behavior in taking roots: for ``AA`` we prefer real @@ -202,10 +203,11 @@ The Sage rings ``AA`` and ``QQbar`` can decide equalities between radical expressions (over the reals and complex numbers respectively):: - sage: a = AA((2/(3*sqrt(3)) + 10/27)^(1/3) - 2/(9*(2/(3*sqrt(3)) + 10/27)^(1/3)) + 1/3) - sage: a + sage: a = AA((2/(3*sqrt(3)) + 10/27)^(1/3) # needs sage.symbolic + ....: - 2/(9*(2/(3*sqrt(3)) + 10/27)^(1/3)) + 1/3) + sage: a # needs sage.symbolic 1.000000000000000? - sage: a == 1 + sage: a == 1 # needs sage.symbolic True Algebraic numbers which are known to be rational print as rationals; @@ -261,9 +263,9 @@ We can compute the multiplicative order of an algebraic number:: - sage: QQbar(-1/2 + I*sqrt(3)/2).multiplicative_order() + sage: QQbar(-1/2 + I*sqrt(3)/2).multiplicative_order() # needs sage.symbolic 3 - sage: QQbar(-sqrt(3)/2 + I/2).multiplicative_order() + sage: QQbar(-sqrt(3)/2 + I/2).multiplicative_order() # needs sage.symbolic 12 sage: (QQbar.zeta(23)**5).multiplicative_order() 23 @@ -332,6 +334,7 @@ on ``n`` will also trigger exact computation on ``rt2``, as you can see by the fact that the third output is different than the first:: + sage: # needs sage.symbolic sage: rt2 = AA(sqrt(2)) sage: n = rt2^2 sage: sage_input(n, verify=True) @@ -383,21 +386,19 @@ sage: loads(dumps(QQbar.zeta(5))) == QQbar.zeta(5) True + sage: # needs sage.symbolic sage: t = QQbar(sqrt(2)); type(t._descr) <class 'sage.rings.qqbar.ANRoot'> sage: loads(dumps(t)) == QQbar(sqrt(2)) True - sage: t.exactify(); type(t._descr) <class 'sage.rings.qqbar.ANExtensionElement'> sage: loads(dumps(t)) == QQbar(sqrt(2)) True - sage: t = ~QQbar(sqrt(2)); type(t._descr) <class 'sage.rings.qqbar.ANUnaryExpr'> sage: loads(dumps(t)) == 1/QQbar(sqrt(2)) True - sage: t = QQbar(sqrt(2)) + QQbar(sqrt(3)); type(t._descr) <class 'sage.rings.qqbar.ANBinaryExpr'> sage: loads(dumps(t)) == QQbar(sqrt(2)) + QQbar(sqrt(3)) @@ -418,7 +419,9 @@ Here are examples of all of these conversions:: - sage: all_vals = [AA(42), AA(22/7), AA(golden_ratio), QQbar(-13), QQbar(89/55), QQbar(-sqrt(7)), QQbar.zeta(5)] + sage: # needs sage.symbolic + sage: all_vals = [AA(42), AA(22/7), AA(golden_ratio), + ....: QQbar(-13), QQbar(89/55), QQbar(-sqrt(7)), QQbar.zeta(5)] sage: def convert_test_all(ty): ....: def convert_test(v): ....: try: @@ -560,6 +563,7 @@ from sage.misc.fast_methods import Singleton from sage.misc.cachefunc import cached_method from sage.misc.lazy_string import lazy_string +from sage.misc.misc import increase_recursion_limit from sage.structure.coerce import parent_is_numerical, parent_is_real_numerical from sage.structure.sage_object import SageObject from sage.structure.richcmp import (richcmp, richcmp_method, @@ -572,8 +576,8 @@ from sage.rings.cif import CIF from sage.rings.complex_interval_field import ComplexIntervalField from sage.rings.complex_interval import is_ComplexIntervalFieldElement -from sage.rings.polynomial.all import PolynomialRing -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.number_field.number_field import NumberField, GaussianField, CyclotomicField @@ -645,12 +649,12 @@ def order(self): def common_polynomial(self, poly): """ - Given a polynomial with algebraic coefficients, returns a + Given a polynomial with algebraic coefficients, return a wrapper that caches high-precision calculations and - factorizations. This wrapper can be passed to ``polynomial_root`` + factorizations. This wrapper can be passed to :meth:`polynomial_root` in place of the polynomial. - Using ``common_polynomial`` makes no semantic difference, but will + Using :meth:`common_polynomial` makes no semantic difference, but will improve efficiency if you are dealing with multiple roots of a single polynomial. @@ -665,6 +669,7 @@ def common_polynomial(self, poly): sage: phi * tau == -1 True + sage: # needs sage.symbolic sage: x = polygen(SR) sage: p = (x - sqrt(-5)) * (x - sqrt(3)); p x^2 + (-sqrt(3) - sqrt(-5))*x + sqrt(3)*sqrt(-5) @@ -784,6 +789,7 @@ def _factor_multivariate_polynomial(self, f, proof=True): A test requiring us to further extend a number field that was used to specify the polynomial:: + sage: # needs sage.symbolic sage: p = x^2 + QQbar(sqrt(2))*y^2 sage: F = QQbar._factor_multivariate_polynomial(p) sage: F @@ -791,6 +797,7 @@ def _factor_multivariate_polynomial(self, f, proof=True): sage: F.value() == p True + sage: # needs sage.symbolic sage: p = u^2 + AA(sqrt(2))*v^2 sage: F = AA._factor_multivariate_polynomial(p) sage: F @@ -801,6 +808,7 @@ def _factor_multivariate_polynomial(self, f, proof=True): A test requiring a number field different from the number field used to specify the polynomial:: + sage: # needs sage.symbolic sage: p = QQbar(sqrt(2))*(x^2+y^2) sage: F = QQbar._factor_multivariate_polynomial(p) sage: F @@ -808,6 +816,7 @@ def _factor_multivariate_polynomial(self, f, proof=True): sage: F.value() == p True + sage: # needs sage.symbolic sage: p = AA(sqrt(2))*(u^2+v^2) sage: F = AA._factor_multivariate_polynomial(p) sage: F @@ -818,6 +827,7 @@ def _factor_multivariate_polynomial(self, f, proof=True): A test where a factor introduces a number field that was already used to specify the polynomial:: + sage: # needs sage.symbolic sage: p = QQbar(sqrt(2))*(x^2-2*y^2)^2 sage: F = QQbar._factor_multivariate_polynomial(p) sage: F @@ -826,6 +836,7 @@ def _factor_multivariate_polynomial(self, f, proof=True): sage: F.value() == p True + sage: # needs sage.symbolic sage: p = AA(sqrt(2))*(u^2-2*v^2)^2 sage: F = AA._factor_multivariate_polynomial(p) sage: F @@ -836,6 +847,7 @@ def _factor_multivariate_polynomial(self, f, proof=True): A test where two factors produce the same factor in the norm:: + sage: # needs sage.symbolic sage: p = (x^2+QQbar(sqrt(2))*y^2)*(x^4-2*y^4) sage: F = QQbar._factor_multivariate_polynomial(p) sage: F @@ -844,6 +856,7 @@ def _factor_multivariate_polynomial(self, f, proof=True): sage: F.value() == p True + sage: # needs sage.symbolic sage: p = (u^2+AA(sqrt(2))*v^2)*(u^4-2*v^4) sage: F = AA._factor_multivariate_polynomial(p) sage: F @@ -867,9 +880,9 @@ def _factor_multivariate_polynomial(self, f, proof=True): number field generator:: sage: S.<a,b> = QQbar[] - sage: p = a^2 + QQbar(sqrt(2))*b^2 - sage: F = QQbar._factor_multivariate_polynomial(p) - sage: F + sage: p = a^2 + QQbar(sqrt(2))*b^2 # needs sage.symbolic + sage: F = QQbar._factor_multivariate_polynomial(p) # needs sage.symbolic + sage: F # needs sage.symbolic (a + (-1.189207115002722?*I)*b) * (a + 1.189207115002722?*I*b) A test that led to :trac:`26898`:: @@ -1012,7 +1025,7 @@ def NF_elem_map(e): trial = Factorization(factorization).value() - return Factorization(factorization, unit = f.lc() / trial.lc()) + return Factorization(factorization, unit=f.lc() / trial.lc()) class AlgebraicRealField(Singleton, AlgebraicField_common, sage.rings.abc.AlgebraicRealField): @@ -1087,7 +1100,7 @@ def _element_constructor_(self, x): EXAMPLES:: - sage: QQbar(sqrt(2)) in AA # indirect doctest + sage: QQbar(sqrt(2)) in AA # indirect doctest # needs sage.symbolic True sage: QQbar(I) in AA False @@ -1096,7 +1109,7 @@ def _element_constructor_(self, x): The following should both return ``True`` (this is a bug). :: - sage: sqrt(2) in AA # known bug + sage: sqrt(2) in AA # known bug # needs sage.symbolic False sage: K.<z> = CyclotomicField(5); z + 1/z in AA # known bug False @@ -1177,9 +1190,10 @@ def _coerce_map_from_(self, from_par): True sage: a + AA(3) 5.645751311064590? - sage: AA.has_coerce_map_from(SR) + sage: AA.has_coerce_map_from(SR) # needs sage.symbolic False + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^3 - 2, 'a', embedding=2.**(1/3)) sage: AA.has_coerce_map_from(K) True @@ -1621,11 +1635,11 @@ def _element_constructor_(self, x): EXAMPLES:: - sage: sqrt(2) in QQbar # indirect doctest + sage: sqrt(2) in QQbar # indirect doctest # needs sage.symbolic True sage: 22/7 in QQbar True - sage: pi in QQbar + sage: pi in QQbar # needs sage.symbolic False """ if isinstance(x, AlgebraicNumber): @@ -1683,7 +1697,7 @@ def _coerce_map_from_(self, from_par): True sage: QQbar.has_coerce_map_from(CC) False - sage: QQbar.has_coerce_map_from(SR) + sage: QQbar.has_coerce_map_from(SR) # needs sage.symbolic False sage: i + QQbar(2) @@ -2099,28 +2113,6 @@ def is_AlgebraicField(F): QQbar = AlgebraicField() -def is_AlgebraicField_common(F): - r""" - Check whether ``F`` is an :class:`~AlgebraicField_common` instance. - - This function is deprecated. Use :func:`isinstance` with - :class:`~sage.rings.abc.AlgebraicField_common` instead. - - EXAMPLES:: - - sage: from sage.rings.qqbar import is_AlgebraicField_common - sage: [is_AlgebraicField_common(x) for x in [AA, QQbar, None, 0, "spam"]] - doctest:warning... - DeprecationWarning: is_AlgebraicField_common is deprecated; - use isinstance(..., sage.rings.abc.AlgebraicField_common) instead - See https://github.com/sagemath/sage/issues/32610 for details. - [True, True, False, False, False] - """ - from sage.misc.superseded import deprecation - deprecation(32610, 'is_AlgebraicField_common is deprecated; use isinstance(..., sage.rings.abc.AlgebraicField_common) instead') - return isinstance(F, AlgebraicField_common) - - def prec_seq(): r""" Return a generator object which iterates over an infinite increasing @@ -2230,30 +2222,76 @@ def clear_denominators(poly): (2, x + 3) sage: clear_denominators(x^2 + x/2 + 1/4) (2, x^2 + x + 1) - """ - # This algorithm factors the polynomial denominators. - # We should check the size of the denominators and switch to - # an alternate, less precise algorithm if we decide factoring - # would be too slow. + TESTS:: + + sage: R.<y> = QQ[] + sage: coefficients_as_integer_ratios = [ + ....: (-2774600080567517563395913264491323241652779066919616441429094563840, + ....: 4143301981494946291120265789013000494010735992517219217956448435626412078440663802209333), + ....: (-24216324060414384566983400245979288839929814383090701293489050615808, + ....: 4143301981494946291120265789013000494010735992517219217956448435626412078440663802209333), + ....: (325579773864372490083706670433410006284520887405882567940047555526656, + ....: 180143564412823751787837643000565238870031999674661705128541236331583133845246252269971), + ....: (-86736048492777879473586471630941922517134071457946320753641122078523392, + ....: 4143301981494946291120265789013000494010735992517219217956448435626412078440663802209333), + ....: (-2338058278498910195688689352766977573607428722429118859280880481590329344, + ....: 4143301981494946291120265789013000494010735992517219217956448435626412078440663802209333), + ....: (105830270645785996318880019945503938356315302592627229453391693256551317504, + ....: 1381100660498315430373421929671000164670245330839073072652149478542137359480221267403111), + ....: (1110926147990548796149597141538460730252912439930561079348611699181798425600, + ....: 4143301981494946291120265789013000494010735992517219217956448435626412078440663802209333), + ....: (-89705438380888704653335165590083767769953879654958783855317882966200828559360, + ....: 4143301981494946291120265789013000494010735992517219217956448435626412078440663802209333), + ....: (1151092895747371986483047191334923516591005329489629755485810229546333821625856, + ....: 1381100660498315430373421929671000164670245330839073072652149478542137359480221267403111), + ....: (24725641793859400310483886670136079788266826658111372723121573233077840328938576, + ....: 4143301981494946291120265789013000494010735992517219217956448435626412078440663802209333), + ....: (-31051495080139473677925068000403254349133134904365702868216464107777210775457136, + ....: 153455628944257270041491325519000018296693925648785896961349942060237484386691251933679), + ....: (9431591461895130351865642769482226964622378075329823505708119342634182162193000560, + ....: 4143301981494946291120265789013000494010735992517219217956448435626412078440663802209333), + ....: (1721694880863483428337378731387732043714427651970488363462560317808769716807148992, + ....: 153455628944257270041491325519000018296693925648785896961349942060237484386691251933679), + ....: (255327752077837584624694974814916395144764296822788813014081161094149724325120096, + ....: 27080405107810106477910233915117650287651869232138687699061754481218379597651397400061), + ....: (238105337335596176836773151768694069523377650990453522899627157538495252117232992338, + ....: 27080405107810106477910233915117650287651869232138687699061754481218379597651397400061), + ....: (1255826892296350234297164500548658984205287902407560187136301197703464130999349114638, + ....: 14336685057075938723599535602121108975815695475838128781856222960645024492874269211797), + ....: (1, 1)] + sage: p = R(coefficients_as_integer_ratios) + sage: a = QQbar.polynomial_root( + ....: AA.common_polynomial(p), + ....: CIF(RIF(-RR(0.036151142425748496), -RR(0.036151142425748489)), + ....: RIF(-RR(0.011298617187916445), -RR(0.011298617187916443)))) + sage: a.exactify() + sage: a + -0.03615114242574849? - 0.011298617187916444?*I + """ d = poly.denominator() if d == 1: return d, poly deg = poly.degree() - factors = {} - for i in range(deg): - d = poly[i].denominator() - df = factor(d) - for f, e in df: - oe = 0 - if f in factors: - oe = factors[f] - min_e = (e + (deg - i) - 1) // (deg - i) - factors[f] = max(oe, min_e) - change = 1 - for f, e in factors.items(): - change = change * f**e + denoms = [c.denominator() for c in poly] + if all(d.nbits() < 128 for d in denoms): + # Factor the polynomial denominators. + factors = {} + for i, d in enumerate(denoms): + df = factor(d) + for f, e in df: + oe = 0 + if f in factors: + oe = factors[f] + min_e = (e + (deg - i) - 1) // (deg - i) + factors[f] = max(oe, min_e) + change = 1 + for f, e in factors.items(): + change = change * f**e + else: + # Factoring would be too slow. + change = poly.monic().denominator() poly = poly * (change**deg) poly = poly(poly.parent().gen() / change) return change, poly @@ -2519,7 +2557,11 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal sage: splitting = number_field_elements_from_algebraics(rts)[0]; splitting Number Field in a with defining polynomial y^6 - 40*y^4 - 22*y^3 + 873*y^2 + 1386*y + 594 sage: p.roots(ring=splitting) - [(361/29286*a^5 - 19/3254*a^4 - 14359/29286*a^3 + 401/29286*a^2 + 18183/1627*a + 15930/1627, 1), (49/117144*a^5 - 179/39048*a^4 - 3247/117144*a^3 + 22553/117144*a^2 + 1744/4881*a - 17195/6508, 1), (-1493/117144*a^5 + 407/39048*a^4 + 60683/117144*a^3 - 24157/117144*a^2 - 56293/4881*a - 53033/6508, 1)] + [(361/29286*a^5 - 19/3254*a^4 - 14359/29286*a^3 + 401/29286*a^2 + 18183/1627*a + 15930/1627, 1), + (49/117144*a^5 - 179/39048*a^4 - 3247/117144*a^3 + 22553/117144*a^2 + 1744/4881*a - 17195/6508, 1), + (-1493/117144*a^5 + 407/39048*a^4 + 60683/117144*a^3 - 24157/117144*a^2 - 56293/4881*a - 53033/6508, 1)] + + sage: # needs sage.symbolic sage: rt2 = AA(sqrt(2)); rt2 1.414213562373095? sage: rt3 = AA(sqrt(3)); rt3 @@ -2534,15 +2576,15 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal 1.414213562373095? sage: rt2c = z3 + rt2 - z3; rt2c 1.414213562373095? + 0.?e-19*I - sage: number_field_elements_from_algebraics(rt2) - (Number Field in a with defining polynomial y^2 - 2, a, Ring morphism: + (Number Field in a with defining polynomial y^2 - 2, a, + Ring morphism: From: Number Field in a with defining polynomial y^2 - 2 To: Algebraic Real Field Defn: a |--> 1.414213562373095?) - sage: number_field_elements_from_algebraics((rt2,rt3)) - (Number Field in a with defining polynomial y^4 - 4*y^2 + 1, [-a^3 + 3*a, a^2 - 2], Ring morphism: + (Number Field in a with defining polynomial y^4 - 4*y^2 + 1, [-a^3 + 3*a, a^2 - 2], + Ring morphism: From: Number Field in a with defining polynomial y^4 - 4*y^2 + 1 To: Algebraic Real Field Defn: a |--> -1.931851652578137?) @@ -2551,14 +2593,16 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal to ``AA`` (because all elements are real), but if we specify ``same_field=True``, we'll get a homomorphism back to ``QQbar``:: - sage: number_field_elements_from_algebraics(rt3a) - (Number Field in a with defining polynomial y^2 - 3, a, Ring morphism: + sage: number_field_elements_from_algebraics(rt3a) # needs sage.symbolic + (Number Field in a with defining polynomial y^2 - 3, a, + Ring morphism: From: Number Field in a with defining polynomial y^2 - 3 To: Algebraic Real Field Defn: a |--> 1.732050807568878?) - sage: number_field_elements_from_algebraics(rt3a, same_field=True) - (Number Field in a with defining polynomial y^2 - 3, a, Ring morphism: + sage: number_field_elements_from_algebraics(rt3a, same_field=True) # needs sage.symbolic + (Number Field in a with defining polynomial y^2 - 3, a, + Ring morphism: From: Number Field in a with defining polynomial y^2 - 3 To: Algebraic Field Defn: a |--> 1.732050807568878?) @@ -2566,15 +2610,16 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal We've created ``rt2b`` in such a way that \sage does not initially know that it's in a degree-2 extension of `\QQ`:: - sage: number_field_elements_from_algebraics(rt2b) - (Number Field in a with defining polynomial y^4 - 4*y^2 + 1, -a^3 + 3*a, Ring morphism: + sage: number_field_elements_from_algebraics(rt2b) # needs sage.symbolic + (Number Field in a with defining polynomial y^4 - 4*y^2 + 1, -a^3 + 3*a, + Ring morphism: From: Number Field in a with defining polynomial y^4 - 4*y^2 + 1 To: Algebraic Real Field Defn: a |--> -1.931851652578137?) We can specify ``minimal=True`` if we want the smallest number field:: - sage: number_field_elements_from_algebraics(rt2b, minimal=True) + sage: number_field_elements_from_algebraics(rt2b, minimal=True) # needs sage.symbolic (Number Field in a with defining polynomial y^2 - 2, a, Ring morphism: From: Number Field in a with defining polynomial y^2 - 2 To: Algebraic Real Field @@ -2591,8 +2636,10 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal Or we can just pass in symbolic expressions, as long as they can be coerced into ``QQbar``:: - sage: number_field_elements_from_algebraics((sqrt(7), sqrt(9), sqrt(11))) - (Number Field in a with defining polynomial y^4 - 9*y^2 + 1, [-a^3 + 8*a, 3, -a^3 + 10*a], Ring morphism: + sage: number_field_elements_from_algebraics((sqrt(7), sqrt(9), sqrt(11))) # needs sage.symbolic + (Number Field in a with defining polynomial y^4 - 9*y^2 + 1, + [-a^3 + 8*a, 3, -a^3 + 10*a], + Ring morphism: From: Number Field in a with defining polynomial y^4 - 9*y^2 + 1 To: Algebraic Real Field Defn: a |--> 0.3354367396454047?) @@ -2600,12 +2647,16 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal Here we see an example of doing some computations with number field elements, and then mapping them back into ``QQbar``:: - sage: (fld,nums,hom) = number_field_elements_from_algebraics((rt2, rt3, qqI, z3)) + sage: # needs sage.symbolic + sage: algebraics = (rt2, rt3, qqI, z3) + sage: fld,nums,hom = number_field_elements_from_algebraics(algebraics) sage: fld,nums,hom # random - (Number Field in a with defining polynomial y^8 - y^4 + 1, [-a^5 + a^3 + a, a^6 - 2*a^2, a^6, -a^4], Ring morphism: - From: Number Field in a with defining polynomial y^8 - y^4 + 1 - To: Algebraic Field - Defn: a |--> -0.2588190451025208? - 0.9659258262890683?*I) + (Number Field in a with defining polynomial y^8 - y^4 + 1, + [-a^5 + a^3 + a, a^6 - 2*a^2, a^6, -a^4], + Ring morphism: + From: Number Field in a with defining polynomial y^8 - y^4 + 1 + To: Algebraic Field + Defn: a |--> -0.2588190451025208? - 0.9659258262890683?*I) sage: (nfrt2, nfrt3, nfI, nfz3) = nums sage: hom(nfrt2) 1.414213562373095? + 0.?e-18*I @@ -2641,38 +2692,50 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal :: - sage: nf,nums,hom = number_field_elements_from_algebraics([2^(1/3),3^(1/5)],embedded=True) + sage: # needs sage.symbolic + sage: elems = [2^(1/3), 3^(1/5)] + sage: nf, nums, hom = number_field_elements_from_algebraics(elems, + ....: embedded=True) sage: nf - Number Field in a with defining polynomial y^15 - 9*y^10 + 21*y^5 - 3 with a = 0.6866813218928813? + Number Field in a with defining polynomial y^15 - 9*y^10 + 21*y^5 - 3 + with a = 0.6866813218928813? sage: nums [a^10 - 5*a^5 + 2, -a^8 + 4*a^3] sage: hom Ring morphism: - From: Number Field in a with defining polynomial y^15 - 9*y^10 + 21*y^5 - 3 with a = 0.6866813218928813? + From: Number Field in a with defining polynomial y^15 - 9*y^10 + 21*y^5 - 3 + with a = 0.6866813218928813? To: Algebraic Real Field Defn: a |--> 0.6866813218928813? Complex embeddings are possible as well:: + sage: # needs sage.symbolic sage: elems = [sqrt(5), 2^(1/3)+sqrt(3)*I, 3/4] - sage: nf, nums, hom = number_field_elements_from_algebraics(elems, embedded=True) - sage: nf # random (polynomial and root not unique) + sage: nf, nums, hom = number_field_elements_from_algebraics(elems, + ....: embedded=True) + sage: nf # random (polynomial and root not unique) Number Field in a with defining polynomial y^24 - 6*y^23 ...- 9*y^2 + 1 with a = 0.2598679? + 0.0572892?*I - sage: nf.is_isomorphic(NumberField(x^24 - 9*x^22 + 135*x^20 - 720*x^18 + 1821*x^16 - 3015*x^14 + 3974*x^12 - 3015*x^10 + 1821*x^8 - 720*x^6 + 135*x^4 - 9*x^2 + 1, 'a')) + sage: nf.is_isomorphic(NumberField( + ....: x^24 - 9*x^22 + 135*x^20 - 720*x^18 + 1821*x^16 + ....: - 3015*x^14 + 3974*x^12 - 3015*x^10 + 1821*x^8 + ....: - 720*x^6 + 135*x^4 - 9*x^2 + 1, 'a')) True sage: list(map(QQbar, nums)) == elems == list(map(hom, nums)) True TESTS:: - sage: number_field_elements_from_algebraics(rt3) - (Number Field in a with defining polynomial y^2 - 3, a, Ring morphism: + sage: number_field_elements_from_algebraics(rt3) # needs sage.symbolic + (Number Field in a with defining polynomial y^2 - 3, a, + Ring morphism: From: Number Field in a with defining polynomial y^2 - 3 To: Algebraic Real Field Defn: a |--> 1.732050807568878?) - sage: number_field_elements_from_algebraics((rt2,qqI)) - (Number Field in a with defining polynomial y^4 + 1, [-a^3 + a, a^2], Ring morphism: + sage: number_field_elements_from_algebraics((rt2,qqI)) # needs sage.symbolic + (Number Field in a with defining polynomial y^4 + 1, [-a^3 + a, a^2], + Ring morphism: From: Number Field in a with defining polynomial y^4 + 1 To: Algebraic Field Defn: a |--> 0.7071067811865475? + 0.7071067811865475?*I) @@ -2680,16 +2743,18 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal Note that for the first example, where \sage does not realize that the number is real, we get a homomorphism to ``QQbar``:: - sage: number_field_elements_from_algebraics(rt2c) # random - (Number Field in a with defining polynomial y^4 + 2*y^2 + 4, 1/2*a^3, Ring morphism: + sage: number_field_elements_from_algebraics(rt2c) # random # needs sage.symbolic + (Number Field in a with defining polynomial y^4 + 2*y^2 + 4, 1/2*a^3, + Ring morphism: From: Number Field in a with defining polynomial y^4 + 2*y^2 + 4 To: Algebraic Field Defn: a |--> -0.7071067811865475? - 1.224744871391589?*I) But with ``minimal=True``, we get a homomorphism to ``AA``:: - sage: number_field_elements_from_algebraics(rt2c, minimal=True) - (Number Field in a with defining polynomial y^2 - 2, a, Ring morphism: + sage: number_field_elements_from_algebraics(rt2c, minimal=True) # needs sage.symbolic + (Number Field in a with defining polynomial y^2 - 2, a, + Ring morphism: From: Number Field in a with defining polynomial y^2 - 2 To: Algebraic Real Field Defn: a |--> 1.414213562373095?) @@ -2697,8 +2762,10 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal If we specify both ``minimal=True`` and ``same_field=True``, we get a second degree extension (minimal) that maps back to ``QQbar``:: - sage: number_field_elements_from_algebraics(rt2c, minimal=True, same_field=True) - (Number Field in a with defining polynomial y^2 - 2, a, Ring morphism: + sage: number_field_elements_from_algebraics(rt2c, minimal=True, # needs sage.symbolic + ....: same_field=True) + (Number Field in a with defining polynomial y^2 - 2, a, + Ring morphism: From: Number Field in a with defining polynomial y^2 - 2 To: Algebraic Field Defn: a |--> 1.414213562373095?) @@ -2722,12 +2789,13 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal sage: E = UCF.gen(5) sage: L.<b> = NumberField(x^2-189*x+16, embedding=200) sage: x = polygen(ZZ) - sage: my_nums = [-52*E - 136*E^2 - 136*E^3 - 52*E^4, \ - L.gen()._algebraic_(AA), \ - sqrt(2), AA.polynomial_root(x^3-3, RIF(0,3)), 11/9, 1] - sage: res = number_field_elements_from_algebraics(my_nums, embedded=True) - sage: res[0] - Number Field in a with defining polynomial y^24 - 107010*y^22 - 24*y^21 + ... + 250678447193040618624307096815048024318853254384 with a = 93.32530798172420? + sage: my_nums = [-52*E - 136*E^2 - 136*E^3 - 52*E^4, # needs sage.symbolic + ....: L.gen()._algebraic_(AA), + ....: sqrt(2), AA.polynomial_root(x^3 - 3, RIF(0,3)), 11/9, 1] + sage: res = number_field_elements_from_algebraics(my_nums, embedded=True) # needs sage.symbolic + sage: res[0] # needs sage.symbolic + Number Field in a with defining polynomial y^24 - 107010*y^22 - 24*y^21 + ... + + 250678447193040618624307096815048024318853254384 with a = 93.32530798172420? """ gen = qq_generator @@ -2982,6 +3050,7 @@ def __reduce__(self): EXAMPLES:: + sage: # needs sage.symbolic sage: t = QQbar(sqrt(2)) + QQbar(sqrt(3)) sage: t.exactify() sage: type(t._descr._generator) @@ -3088,7 +3157,7 @@ def root_as_algebraic(self): def is_trivial(self): """ - Return true iff this is the trivial generator (alpha == 1), which + Return ``True`` iff this is the trivial generator (alpha == 1), which does not actually extend the rationals. EXAMPLES:: @@ -3408,6 +3477,8 @@ def is_simple(self): sage: from sage.rings.qqbar import ANRational sage: ANRational(1/2).is_simple() True + + sage: # needs sage.symbolic sage: rt2 = AA(sqrt(2)) sage: rt3 = AA(sqrt(3)) sage: rt2b = rt3 + rt2 - rt3 @@ -3432,9 +3503,9 @@ def neg(self, n): EXAMPLES:: - sage: a = QQbar(sqrt(2)) - sage: b = a._descr - sage: b.neg(a) + sage: a = QQbar(sqrt(2)) # needs sage.symbolic + sage: b = a._descr # needs sage.symbolic + sage: b.neg(a) # needs sage.symbolic <sage.rings.qqbar.ANUnaryExpr object at ...> """ return ANUnaryExpr(n, '-') @@ -3445,9 +3516,9 @@ def invert(self, n): EXAMPLES:: - sage: a = QQbar(sqrt(2)) - sage: b = a._descr - sage: b.invert(a) + sage: a = QQbar(sqrt(2)) # needs sage.symbolic + sage: b = a._descr # needs sage.symbolic + sage: b.invert(a) # needs sage.symbolic <sage.rings.qqbar.ANUnaryExpr object at ...> """ return ANUnaryExpr(n, '~') @@ -3458,9 +3529,9 @@ def abs(self, n): EXAMPLES:: - sage: a = QQbar(sqrt(2)) - sage: b = a._descr - sage: b.abs(a) + sage: a = QQbar(sqrt(2)) # needs sage.symbolic + sage: b = a._descr # needs sage.symbolic + sage: b.abs(a) # needs sage.symbolic <sage.rings.qqbar.ANUnaryExpr object at ...> """ return ANUnaryExpr(n, 'abs') @@ -3471,9 +3542,9 @@ def real(self, n): EXAMPLES:: - sage: a = QQbar(sqrt(-7)) - sage: b = a._descr - sage: b.real(a) + sage: a = QQbar(sqrt(-7)) # needs sage.symbolic + sage: b = a._descr # needs sage.symbolic + sage: b.real(a) # needs sage.symbolic <sage.rings.qqbar.ANUnaryExpr object at ...> """ if self.is_complex(): @@ -3487,9 +3558,9 @@ def imag(self, n): EXAMPLES:: - sage: a = QQbar(sqrt(-7)) - sage: b = a._descr - sage: b.imag(a) + sage: a = QQbar(sqrt(-7)) # needs sage.symbolic + sage: b = a._descr # needs sage.symbolic + sage: b.imag(a) # needs sage.symbolic <sage.rings.qqbar.ANUnaryExpr object at ...> """ if self.is_complex(): @@ -3503,9 +3574,9 @@ def conjugate(self, n): EXAMPLES:: - sage: a = QQbar(sqrt(-7)) - sage: b = a._descr - sage: b.conjugate(a) + sage: a = QQbar(sqrt(-7)) # needs sage.symbolic + sage: b = a._descr # needs sage.symbolic + sage: b.conjugate(a) # needs sage.symbolic <sage.rings.qqbar.ANUnaryExpr object at ...> """ if self.is_complex(): @@ -3520,9 +3591,9 @@ def norm(self, n): EXAMPLES:: - sage: a = QQbar(sqrt(-7)) - sage: b = a._descr - sage: b.norm(a) + sage: a = QQbar(sqrt(-7)) # needs sage.symbolic + sage: b = a._descr # needs sage.symbolic + sage: b.norm(a) # needs sage.symbolic <sage.rings.qqbar.ANUnaryExpr object at ...> """ if self.is_complex(): @@ -3587,7 +3658,7 @@ class AlgebraicNumber_base(sage.structure.element.FieldElement): 1.618033988749895? sage: phi^2 == phi+1 True - sage: AA(sqrt(65537)) + sage: AA(sqrt(65537)) # needs sage.symbolic 256.0019531175495? """ @@ -3647,9 +3718,9 @@ def _repr_(self): sage: AA(19).sqrt() 4.358898943540674? sage: AA.options.display_format = 'radical' - sage: AA(19).sqrt() + sage: AA(19).sqrt() # needs sage.symbolic sqrt(19) - sage: QQbar.zeta(6) + sage: QQbar.zeta(6) # needs sage.symbolic 1/2*I*sqrt(3) + 1/2 sage: QQbar.zeta(17) 0.9324722294043558? + 0.3612416661871530?*I @@ -3765,7 +3836,7 @@ def _mul_(self, other): """ TESTS:: - sage: AA(sqrt(2)) * AA(sqrt(8)) # indirect doctest + sage: AA(sqrt(2)) * AA(sqrt(8)) # indirect doctest # needs sage.symbolic 4.000000000000000? """ sk = type(self._descr) @@ -3776,7 +3847,7 @@ def _div_(self, other): """ TESTS:: - sage: AA(sqrt(2)) / AA(sqrt(8)) # indirect doctest + sage: AA(sqrt(2)) / AA(sqrt(8)) # indirect doctest # needs sage.symbolic 0.500000000000000? sage: z = QQbar(I).real() @@ -3795,7 +3866,7 @@ def __invert__(self): """ TESTS:: - sage: ~AA(sqrt(~2)) + sage: ~AA(sqrt(~2)) # needs sage.symbolic 1.414213562373095? sage: z = QQbar(I).real() @@ -3825,7 +3896,7 @@ def _sub_(self, other): """ TESTS:: - sage: AA(golden_ratio) * 2 - AA(5).sqrt() # indirect doctest + sage: AA(golden_ratio) * 2 - AA(5).sqrt() # indirect doctest # needs sage.symbolic 1.000000000000000? """ sk = type(self._descr) @@ -3845,7 +3916,7 @@ def __abs__(self): """ TESTS:: - sage: abs(AA(sqrt(2) - sqrt(3))) + sage: abs(AA(sqrt(2) - sqrt(3))) # needs sage.symbolic 0.3178372451957823? sage: abs(QQbar(3+4*I)) 5 @@ -3881,8 +3952,8 @@ def __hash__(self): True sage: h1 = hash(QQbar.zeta(6)) - sage: h2 = hash(QQbar(1/2 + I*sqrt(3)/2)) - sage: h1 == h2 + sage: h2 = hash(QQbar(1/2 + I*sqrt(3)/2)) # needs sage.symbolic + sage: h1 == h2 # needs sage.symbolic True Unfortunately, the hash code for algebraic numbers which are close @@ -3955,6 +4026,8 @@ def __bool__(self): sage: a = QQbar(2).sqrt() - 16616132878186749607/11749380235262596085 sage: b = QQbar(2).sqrt() - 6882627592338442563/4866752642924153522 sage: c = QQbar(3).sqrt() - 142437039878091970439/82236063316189858921 + + sage: # needs sage.symbolic sage: d = (59/2)**(1000/7) sage: e = (a + b + c) * (a + b - c) * (a - b) * (a - b - c) / d sage: bool(e) @@ -4061,8 +4134,6 @@ def __bool__(self): self.exactify() return bool(self) - - def is_square(self): """ Return whether or not this number is square. @@ -4269,8 +4340,9 @@ def as_number_field_element(self, minimal=False, embedded=False, prec=53): EXAMPLES:: - sage: QQbar(sqrt(8)).as_number_field_element() - (Number Field in a with defining polynomial y^2 - 2, 2*a, Ring morphism: + sage: QQbar(sqrt(8)).as_number_field_element() # needs sage.symbolic + (Number Field in a with defining polynomial y^2 - 2, 2*a, + Ring morphism: From: Number Field in a with defining polynomial y^2 - 2 To: Algebraic Real Field Defn: a |--> 1.414213562373095?) @@ -4322,6 +4394,7 @@ def as_number_field_element(self, minimal=False, embedded=False, prec=53): A complex algebraic number as an element of an embedded number field:: + sage: # needs sage.symbolic sage: num = QQbar(sqrt(2) + 3^(1/3)*I) sage: nf, elt, hom = num.as_number_field_element(embedded=True) sage: hom(elt).parent() is QQbar @@ -4334,16 +4407,19 @@ def as_number_field_element(self, minimal=False, embedded=False, prec=53): We see an example where we do not get the minimal number field unless we specify ``minimal=True``:: + sage: # needs sage.symbolic sage: rt2 = AA(sqrt(2)) sage: rt3 = AA(sqrt(3)) sage: rt3b = rt2 + rt3 - rt2 sage: rt3b.as_number_field_element() - (Number Field in a with defining polynomial y^4 - 4*y^2 + 1, a^2 - 2, Ring morphism: + (Number Field in a with defining polynomial y^4 - 4*y^2 + 1, a^2 - 2, + Ring morphism: From: Number Field in a with defining polynomial y^4 - 4*y^2 + 1 To: Algebraic Real Field Defn: a |--> -1.931851652578137?) sage: rt3b.as_number_field_element(minimal=True) - (Number Field in a with defining polynomial y^2 - 3, a, Ring morphism: + (Number Field in a with defining polynomial y^2 - 3, a, + Ring morphism: From: Number Field in a with defining polynomial y^2 - 3 To: Algebraic Real Field Defn: a |--> 1.732050807568878?) @@ -4398,6 +4474,7 @@ def simplify(self): EXAMPLES:: + sage: # needs sage.symbolic sage: rt2 = AA(sqrt(2)) sage: rt3 = AA(sqrt(3)) sage: rt2b = rt3 + rt2 - rt3 @@ -4651,18 +4728,20 @@ def radical_expression(self): EXAMPLES:: + sage: # needs sage.symbolic sage: AA(1/sqrt(5)).radical_expression() sqrt(1/5) sage: AA(sqrt(5 + sqrt(5))).radical_expression() sqrt(sqrt(5) + 5) sage: QQbar.zeta(5).radical_expression() 1/4*sqrt(5) + 1/2*sqrt(-1/2*sqrt(5) - 5/2) - 1/4 - sage: a = QQ[x](x^7 - x - 1).roots(AA, False)[0] + sage: x = polygen(QQ, 'x') + sage: a = (x^7 - x - 1).roots(AA, False)[0] sage: a.radical_expression() 1.112775684278706? sage: a.radical_expression().parent() == SR False - sage: a = sorted(QQ[x](x^7-x-1).roots(QQbar, False), key=imag)[0] + sage: a = sorted((x^7-x-1).roots(QQbar, False), key=imag)[0] sage: a.radical_expression() -0.3636235193291805? - 0.9525611952610331?*I sage: QQbar.zeta(5).imag().radical_expression() @@ -4682,10 +4761,13 @@ def radical_expression(self): :: + sage: # needs sage.symbolic sage: a = AA(sqrt(2) + 10^25) sage: p = a.minpoly() sage: v = a._value sage: f = ComplexIntervalField(v.prec()) + sage: var('x') + x sage: [f(b.rhs()).overlaps(f(v)) for b in SR(p).solve(x)] [True, True] sage: a.radical_expression() @@ -4716,6 +4798,7 @@ def _maxima_init_(self, I=None): r""" EXAMPLES:: + sage: # needs sage.symbolic sage: maxima(AA(7)) 7 sage: maxima(QQbar(sqrt(5/2))) @@ -4745,7 +4828,7 @@ class AlgebraicNumber(AlgebraicNumber_base): r""" The class for algebraic numbers (complex numbers which are the roots of a polynomial with integer coefficients). Much of its functionality - is inherited from ``AlgebraicNumber_base``. + is inherited from :class:`AlgebraicNumber_base`. .. automethod:: _richcmp_ """ @@ -4840,7 +4923,7 @@ def _richcmp_(self, other, op): TESTS:: - sage: QQbar.zeta(6) == QQbar(1/2 + I*sqrt(3)/2) + sage: QQbar.zeta(6) == QQbar(1/2 + I*sqrt(3)/2) # needs sage.symbolic True sage: QQbar(I) == QQbar(I * (2^100+1)/(2^100)) False @@ -4851,7 +4934,7 @@ def _richcmp_(self, other, op): sage: GF(7)(2) in QQbar False - sage: QQbar.zeta(6) != QQbar(1/2 + I*sqrt(3)/2) + sage: QQbar.zeta(6) != QQbar(1/2 + I*sqrt(3)/2) # needs sage.symbolic False sage: QQbar(I) != QQbar(I * (2^100+1)/(2^100)) True @@ -4877,13 +4960,13 @@ def _richcmp_(self, other, op): Check that :trac:`29220` is fixed:: + sage: # needs sage.symbolic sage: a = AA(2**(1/2) - 2**(1/3)) sage: b = 808620184/5240825825 sage: a < b True sage: a < b True - sage: a = AA(2^(1/3)) sage: r = 3085094589/2448641198 sage: a < r @@ -4951,7 +5034,7 @@ def _mpfr_(self, field): EXAMPLES:: - sage: QQbar(sqrt(2))._mpfr_(RR) + sage: QQbar(sqrt(2))._mpfr_(RR) # needs sage.symbolic 1.41421356237309 sage: QQbar(-22/7)._mpfr_(RR) -3.14285714285714 @@ -4970,7 +5053,7 @@ def __float__(self): EXAMPLES:: - sage: QQbar(sqrt(2)).__float__() + sage: QQbar(sqrt(2)).__float__() # needs sage.symbolic 1.414213562373095 sage: float(QQbar(-22/7)) -3.1428571428571432 @@ -4987,7 +5070,7 @@ def __complex__(self): EXAMPLES:: - sage: QQbar(sqrt(2)).__complex__() + sage: QQbar(sqrt(2)).__complex__() # needs sage.symbolic (1.414213562373095+0j) sage: complex(QQbar.zeta(3)) (-0.5+0.8660254037844386j) @@ -5000,7 +5083,7 @@ def _complex_double_(self, cdf): EXAMPLES:: - sage: QQbar(sqrt(-5))._complex_double_(CDF) + sage: QQbar(sqrt(-5))._complex_double_(CDF) # needs sage.symbolic 2.23606797749979*I sage: CDF(QQbar.zeta(12)) 0.8660254037844386 + 0.5*I @@ -5013,7 +5096,7 @@ def _interval_fast(self, prec): EXAMPLES:: - sage: QQbar(sqrt(-5))._interval_fast(100) + sage: QQbar(sqrt(-5))._interval_fast(100) # needs sage.symbolic 2.236067977499789696409173...?*I """ return self.interval_fast(ComplexIntervalField(prec)) @@ -5032,6 +5115,8 @@ def _integer_(self, ZZ=None): Traceback (most recent call last): ... ValueError: Cannot coerce algebraic number with non-zero imaginary part to algebraic real + + sage: # needs sage.symbolic sage: QQbar(sqrt(17))._integer_() Traceback (most recent call last): ... @@ -5059,6 +5144,8 @@ def _rational_(self): Traceback (most recent call last): ... ValueError: Cannot coerce algebraic number with non-zero imaginary part to algebraic real + + sage: # needs sage.symbolic sage: QQbar(sqrt(2))._rational_() Traceback (most recent call last): ... @@ -5074,7 +5161,7 @@ def _rational_(self): def real(self): r""" - Return the real part of self. + Return the real part of ``self``. EXAMPLES:: @@ -5085,7 +5172,7 @@ def real(self): def imag(self): r""" - Return the imaginary part of self. + Return the imaginary part of ``self``. EXAMPLES:: @@ -5129,7 +5216,7 @@ def norm(self): def interval_exact(self, field): r""" - Given a ``ComplexIntervalField``, compute the best possible + Given a :class:`ComplexIntervalField`, compute the best possible approximation of this number in that field. Note that if either the real or imaginary parts of this number are sufficiently close to some floating-point number (and, in @@ -5142,10 +5229,10 @@ def interval_exact(self, field): 0.7071067811865475? + 0.7071067811865475?*I sage: a.interval_exact(CIF) 0.7071067811865475? + 0.7071067811865475?*I - sage: b = QQbar((1+I)*sqrt(2)/2) - sage: (a - b).interval(CIF) + sage: b = QQbar((1+I)*sqrt(2)/2) # needs sage.symbolic + sage: (a - b).interval(CIF) # needs sage.symbolic 0.?e-19 + 0.?e-18*I - sage: (a - b).interval_exact(CIF) + sage: (a - b).interval_exact(CIF) # needs sage.symbolic 0 """ if not isinstance(field, sage.rings.abc.ComplexIntervalField): @@ -5172,12 +5259,12 @@ def _complex_mpfr_field_(self, field): def complex_number(self, field): r""" - Given the complex field ``field`` compute an accurate approximation of + Given the complex field ``field``, compute an accurate approximation of this element in that field. The approximation will be off by at most two ulp's in each component, except for components which are very close to zero, which will have an - absolute error at most `2^{-prec+1}` where `prec` is the precision of + absolute error at most `2^{-prec+1}` where ``prec`` is the precision of the field. EXAMPLES:: @@ -5195,10 +5282,10 @@ def complex_number(self, field): def complex_exact(self, field): r""" - Given a ``ComplexField``, return the best possible approximation of + Given a :class:`ComplexField`, return the best possible approximation of this number in that field. Note that if either component is sufficiently close to the halfway point between two floating-point - numbers in the corresponding ``RealField``, then this will trigger + numbers in the corresponding :class:`RealField`, then this will trigger exact computation, which may be very slow. EXAMPLES:: @@ -5225,7 +5312,7 @@ def multiplicative_order(self): EXAMPLES:: - sage: QQbar(-sqrt(3)/2 - I/2).multiplicative_order() + sage: QQbar(-sqrt(3)/2 - I/2).multiplicative_order() # needs sage.symbolic 12 sage: QQbar(1).multiplicative_order() 1 @@ -5251,11 +5338,11 @@ def rational_argument(self): EXAMPLES:: - sage: QQbar((1+I)*(sqrt(2)+sqrt(5))).rational_argument() + sage: QQbar((1+I)*(sqrt(2)+sqrt(5))).rational_argument() # needs sage.symbolic 1/8 - sage: QQbar(-1 + I*sqrt(3)).rational_argument() + sage: QQbar(-1 + I*sqrt(3)).rational_argument() # needs sage.symbolic 1/3 - sage: QQbar(-1 - I*sqrt(3)).rational_argument() + sage: QQbar(-1 - I*sqrt(3)).rational_argument() # needs sage.symbolic -1/3 sage: QQbar(3+4*I).rational_argument() is None True @@ -5285,9 +5372,9 @@ def _pow_(self, other): EXAMPLES:: - sage: QQbar(1) ^ QQbar(sqrt(2)) + sage: QQbar(1) ^ QQbar(sqrt(2)) # needs sage.symbolic 1 - sage: 1 ^ QQbar(sqrt(2)) + sage: 1 ^ QQbar(sqrt(2)) # needs sage.symbolic 1 sage: QQbar(2) ^ QQbar(2) Traceback (most recent call last): @@ -5322,8 +5409,9 @@ def __init__(self, x): sometimes a very small (e.g., 1e-17) complex part appears in a complex interval used to create an AlgebraicReal.:: - sage: a = QQbar((-1)^(1/4)); b = AA(a^3-a); t = b.as_number_field_element() - sage: b*1 + sage: a = QQbar((-1)^(1/4)); b = AA(a^3-a) # needs sage.symbolic + sage: t = b.as_number_field_element() # needs sage.symbolic + sage: b*1 # needs sage.symbolic -1.414213562373095? """ AlgebraicNumber_base.__init__(self, AA, x) @@ -5337,6 +5425,7 @@ def _ensure_real(self): EXAMPLES:: + sage: # needs sage.symbolic sage: a = QQbar((-1)^(1/4)); b = AA(a^3-a); b._value -1.4142135623730950488? sage: b._value = a._value; b._value @@ -5357,8 +5446,8 @@ def _more_precision(self): EXAMPLES:: - sage: a = QQbar(sqrt(2)) - sage: a._more_precision() + sage: a = QQbar(sqrt(2)) # needs sage.symbolic + sage: a._more_precision() # needs sage.symbolic TESTS: @@ -5366,7 +5455,8 @@ def _more_precision(self): real which is not the case without calling _ensure_real (see :trac:`11728`):: - sage: P = AA['x'](1+x^4); a1,a2 = P.factor()[0][0],P.factor()[1][0]; a1*a2 + sage: x = polygen(ZZ, 'x') + sage: P = AA['x'](1 + x^4); a1,a2 = P.factor()[0][0], P.factor()[1][0]; a1*a2 x^4 + 1.000000000000000? sage: a1,a2 (x^2 - 1.414213562373095?*x + 1, x^2 + 1.414213562373095?*x + 1) @@ -5382,8 +5472,8 @@ def __reduce__(self): EXAMPLES:: - sage: t = AA(sqrt(2)) - sage: loads(dumps(t)) == t + sage: t = AA(sqrt(2)) # needs sage.symbolic + sage: loads(dumps(t)) == t # needs sage.symbolic True """ return (AlgebraicReal, (self._descr, )) @@ -5403,15 +5493,16 @@ def _richcmp_(self, other, op): TESTS:: - sage: AA(golden_ratio) < AA(sqrt(5)) + sage: AA(golden_ratio) < AA(sqrt(5)) # needs sage.symbolic True - sage: AA(golden_ratio) == AA((sqrt(5)+1)/2) + sage: AA(golden_ratio) == AA((sqrt(5)+1)/2) # needs sage.symbolic True sage: AA(7) >= AA(50/7) False Check for trivial equality with identical elements:: + sage: # needs sage.symbolic sage: x1 = AA(2^(1/50)) sage: x2 = AA(2^(1/50)) sage: y = x1 - x2 @@ -5421,11 +5512,9 @@ def _richcmp_(self, other, op): True sage: y < y False - sage: z = x1 - x2 sage: z == 0 True - sage: a = x1 - x2 sage: b = x1 - x2 sage: a == b @@ -5502,11 +5591,11 @@ def _integer_(self, Z=None): 42 sage: AA(42)._integer_().parent() Integer Ring - sage: AA(golden_ratio)._integer_() + sage: AA(golden_ratio)._integer_() # needs sage.symbolic Traceback (most recent call last): ... ValueError: Cannot coerce non-integral Algebraic Real 1.618033988749895? to Integer - sage: (AA(golden_ratio)^10 + AA(1-golden_ratio)^10)._integer_() + sage: (AA(golden_ratio)^10 + AA(1-golden_ratio)^10)._integer_() # needs sage.symbolic 123 sage: AA(-22/7)._integer_() Traceback (most recent call last): @@ -5564,9 +5653,9 @@ def floor(self): EXAMPLES:: - sage: AA(sqrt(2)).floor() + sage: AA(sqrt(2)).floor() # needs sage.symbolic 1 - sage: AA(-sqrt(2)).floor() + sage: AA(-sqrt(2)).floor() # needs sage.symbolic -2 sage: AA(42).floor() 42 @@ -5575,8 +5664,8 @@ def floor(self): Check that :trac:`15501` is fixed:: - sage: a = QQbar((-1)^(1/4)).real() - sage: (floor(a-a) + a).parent() + sage: a = QQbar((-1)^(1/4)).real() # needs sage.symbolic + sage: (floor(a-a) + a).parent() # needs sage.symbolic Algebraic Real Field """ return self._floor_ceil(lambda x: x.floor()) @@ -5587,9 +5676,9 @@ def ceil(self): EXAMPLES:: - sage: AA(sqrt(2)).ceil() + sage: AA(sqrt(2)).ceil() # needs sage.symbolic 2 - sage: AA(-sqrt(2)).ceil() + sage: AA(-sqrt(2)).ceil() # needs sage.symbolic -1 sage: AA(42).ceil() 42 @@ -5602,7 +5691,7 @@ def round(self): EXAMPLES:: - sage: AA(sqrt(2)).round() + sage: AA(sqrt(2)).round() # needs sage.symbolic 1 sage: AA(1/2).round() 1 @@ -5617,9 +5706,9 @@ def trunc(self): EXAMPLES:: - sage: AA(sqrt(2)).trunc() + sage: AA(sqrt(2)).trunc() # needs sage.symbolic 1 - sage: AA(-sqrt(2)).trunc() + sage: AA(-sqrt(2)).trunc() # needs sage.symbolic -1 sage: AA(1).trunc() 1 @@ -5638,13 +5727,13 @@ def _rational_(self): Rational Field sage: AA(-22/7)._rational_() -22/7 - sage: AA(sqrt(7))._rational_() + sage: AA(sqrt(7))._rational_() # needs sage.symbolic Traceback (most recent call last): ... ValueError: Cannot coerce irrational Algebraic Real 2.645751311064591? to Rational - sage: v = AA(1/2 + sqrt(2))^3 - AA(11/4*sqrt(2)); v + sage: v = AA(1/2 + sqrt(2))^3 - AA(11/4*sqrt(2)); v # needs sage.symbolic 3.125000000000000? - sage: v._rational_() + sage: v._rational_() # needs sage.symbolic 25/8 """ self.exactify() @@ -5661,10 +5750,10 @@ def real(self): EXAMPLES:: - sage: a = AA(sqrt(2) + sqrt(3)) - sage: a.real() + sage: a = AA(sqrt(2) + sqrt(3)) # needs sage.symbolic + sage: a.real() # needs sage.symbolic 3.146264369941973? - sage: a.real() is a + sage: a.real() is a # needs sage.symbolic True """ return self @@ -5677,10 +5766,10 @@ def imag(self): EXAMPLES:: - sage: a = AA(sqrt(2) + sqrt(3)) - sage: a.imag() + sage: a = AA(sqrt(2) + sqrt(3)) # needs sage.symbolic + sage: a.imag() # needs sage.symbolic 0 - sage: parent(a.imag()) + sage: parent(a.imag()) # needs sage.symbolic Algebraic Real Field """ return AA_0 @@ -5691,10 +5780,10 @@ def conjugate(self): EXAMPLES:: - sage: a = AA(sqrt(2) + sqrt(3)) - sage: a.conjugate() + sage: a = AA(sqrt(2) + sqrt(3)) # needs sage.symbolic + sage: a.conjugate() # needs sage.symbolic 3.146264369941973? - sage: a.conjugate() is a + sage: a.conjugate() is a # needs sage.symbolic True """ return self @@ -5707,7 +5796,7 @@ def multiplicative_order(self): that `x^n = 1`. If there is no such `n`, returns ``+Infinity``. We first check that ``abs(x)`` is very close to 1. If so, we compute - `x` exactly and compare it to 1 and -1. + `x` exactly and compare it to `1` and `-1`. EXAMPLES:: @@ -5729,8 +5818,8 @@ def multiplicative_order(self): def sign(self): """ - Compute the sign of this algebraic number (return -1 if negative, - 0 if zero, or 1 if positive). + Compute the sign of this algebraic number (return `-1` if negative, + `0` if zero, or `1` if positive). This computes an interval enclosing this number using 128-bit interval arithmetic; if this interval includes 0, then fall back to @@ -5767,9 +5856,9 @@ def sign(self): sage: (a*b - b*a).sign() 0 - sage: a = AA(sqrt(1/2)) - sage: b = AA(-sqrt(1/2)) - sage: (a + b).sign() + sage: a = AA(sqrt(1/2)) # needs sage.symbolic + sage: b = AA(-sqrt(1/2)) # needs sage.symbolic + sage: (a + b).sign() # needs sage.symbolic 0 TESTS: @@ -5778,6 +5867,7 @@ def sign(self): following example will take a long time (more than 5 seconds) when calling ``y.exactify()``:: + sage: # needs sage.symbolic sage: x1 = AA(2^(1/50)) sage: x2 = AA(2^(1/50)) sage: y = x1 - x2 @@ -5786,9 +5876,9 @@ def sign(self): Simplify to rationals for binary operations when computing the sign:: - sage: a = AA(2^(1/60)) - sage: b = a - (a + 1) - sage: (b + 1).sign() + sage: a = AA(2^(1/60)) # needs sage.symbolic + sage: b = a - (a + 1) # needs sage.symbolic + sage: (b + 1).sign() # needs sage.symbolic 0 """ if not self._value.contains_zero(): @@ -5884,15 +5974,15 @@ def _interval_fast(self, prec): EXAMPLES:: - sage: t = AA(sqrt(7)) - sage: t._interval_fast(100) + sage: t = AA(sqrt(7)) # needs sage.symbolic + sage: t._interval_fast(100) # needs sage.symbolic 2.64575131106459059050161575364? """ return self.interval_fast(RealIntervalField(prec)) def interval_exact(self, field): """ - Given a ``RealIntervalField``, compute the best possible + Given a :class:`RealIntervalField`, compute the best possible approximation of this number in that field. Note that if this number is sufficiently close to some floating-point number (and, in particular, if this number is exactly representable in @@ -5966,7 +6056,7 @@ def interval_exact(self, field): def real_number(self, field): """ - Given a ``RealField``, compute a good approximation to self in + Given a :class:`RealField`, compute a good approximation to ``self`` in that field. The approximation will be off by at most two ulp's, except for numbers which are very close to 0, which will have an absolute error at most @@ -6021,9 +6111,9 @@ def __float__(self): EXAMPLES:: - sage: AA(golden_ratio).__float__() + sage: AA(golden_ratio).__float__() # needs sage.symbolic 1.618033988749895 - sage: float(AA(sqrt(11))) + sage: float(AA(sqrt(11))) # needs sage.symbolic 3.3166247903554 """ return float(RR(self)) @@ -6040,9 +6130,9 @@ def _complex_mpfr_field_(self, field): EXAMPLES:: - sage: AA(golden_ratio)._complex_mpfr_field_(ComplexIntervalField(100)) + sage: AA(golden_ratio)._complex_mpfr_field_(ComplexIntervalField(100)) # needs sage.symbolic 1.618033988749894848204586834365? - sage: AA(golden_ratio)._complex_mpfr_field_(ComplexField(100)) + sage: AA(golden_ratio)._complex_mpfr_field_(ComplexField(100)) # needs sage.symbolic 1.6180339887498948482045868344 """ if isinstance(field, sage.rings.abc.ComplexIntervalField): @@ -6052,7 +6142,7 @@ def _complex_mpfr_field_(self, field): def real_exact(self, field): r""" - Given a ``RealField``, compute the best possible approximation of + Given a :class:`RealField`, compute the best possible approximation of this number in that field. Note that if this number is sufficiently close to the halfway point between two floating-point numbers in the field (for the default @@ -6369,7 +6459,7 @@ def _repr_name_(self): class ANRational(ANDescr): r""" - The subclass of ``ANDescr`` that represents an arbitrary + The subclass of :class:`ANDescr` that represents an arbitrary rational. This class is private, and should not be used directly. """ @@ -6466,7 +6556,7 @@ def generator(self): def is_complex(self): r""" - Return False, since rational numbers are real + Return ``False``, since rational numbers are real EXAMPLES:: @@ -6477,7 +6567,7 @@ def is_complex(self): def exactify(self): r""" - Calculate self exactly. Since self is a rational number, return self. + Calculate ``self`` exactly. Since ``self`` is a rational number, return ``self``. EXAMPLES:: @@ -6503,7 +6593,7 @@ def is_simple(self): def minpoly(self): r""" - Return the min poly of self over `\QQ`. + Return the min poly of ``self`` over `\QQ`. EXAMPLES:: @@ -6514,7 +6604,7 @@ def minpoly(self): def neg(self, n): r""" - Negation of self. + Negation of ``self``. EXAMPLES:: @@ -6529,7 +6619,7 @@ def neg(self, n): def invert(self, n): r""" - 1/self. + 1/``self``. EXAMPLES:: @@ -6542,7 +6632,7 @@ def invert(self, n): def abs(self, n): r""" - Absolute value of self. + Absolute value of ``self``. EXAMPLES:: @@ -6592,7 +6682,7 @@ def angle(self): def scale(self): r""" Return a rational number `r` such that ``self`` is equal to `r e^{2 \pi - i q}` for some `q \in (-1/2, 1/2]`. In other words, just return self + i q}` for some `q \in (-1/2, 1/2]`. In other words, just return ``self`` as a rational number. EXAMPLES:: @@ -6610,9 +6700,9 @@ def is_AlgebraicReal(x): EXAMPLES:: sage: from sage.rings.qqbar import is_AlgebraicReal - sage: is_AlgebraicReal(AA(sqrt(2))) + sage: is_AlgebraicReal(AA(sqrt(2))) # needs sage.symbolic True - sage: is_AlgebraicReal(QQbar(sqrt(2))) + sage: is_AlgebraicReal(QQbar(sqrt(2))) # needs sage.symbolic False sage: is_AlgebraicReal("spam") False @@ -6627,9 +6717,9 @@ def is_AlgebraicNumber(x): EXAMPLES:: sage: from sage.rings.qqbar import is_AlgebraicNumber - sage: is_AlgebraicNumber(AA(sqrt(2))) + sage: is_AlgebraicNumber(AA(sqrt(2))) # needs sage.symbolic False - sage: is_AlgebraicNumber(QQbar(sqrt(2))) + sage: is_AlgebraicNumber(QQbar(sqrt(2))) # needs sage.symbolic True sage: is_AlgebraicNumber("spam") False @@ -6678,7 +6768,7 @@ def __init__(self, poly): sage: type(P) # indirect doctest <class 'sage.rings.qqbar.AlgebraicPolynomialTracker'> """ - if not is_Polynomial(poly): + if not isinstance(poly, Polynomial): raise ValueError("Trying to create AlgebraicPolynomialTracker on non-Polynomial") B = poly.base_ring() @@ -6757,7 +6847,7 @@ def _repr_(self): def poly(self): r""" - Return the underlying polynomial of self. + Return the underlying polynomial of ``self``. EXAMPLES:: @@ -6794,7 +6884,7 @@ def complex_roots(self, prec, multiplicity): sage: cp = AA.common_polynomial(x^4 - 2) Note that the precision is not guaranteed to find the tightest - possible interval since ``complex_roots()`` depends on the + possible interval since :meth:`complex_roots` depends on the underlying BLAS implementation. :: sage: cp.complex_roots(30, 1) @@ -6879,7 +6969,7 @@ def factors(self): def generator(self): r""" Return an :class:`AlgebraicGenerator` for a number field containing all - the coefficients of self. + the coefficients of ``self``. EXAMPLES:: @@ -6887,7 +6977,8 @@ def generator(self): sage: p = sqrt(AA(2)) * x^2 - sqrt(AA(3)) sage: cp = AA.common_polynomial(p) sage: cp.generator() - Number Field in a with defining polynomial y^4 - 4*y^2 + 1 with a in -0.5176380902050415? + Number Field in a with defining polynomial y^4 - 4*y^2 + 1 + with a in -0.5176380902050415? """ self.exactify() return self._gen @@ -6895,7 +6986,7 @@ def generator(self): class ANRoot(ANDescr): """ - The subclass of ``ANDescr`` that represents a particular + The subclass of :class:`ANDescr` that represents a particular root of a polynomial with algebraic coefficients. This class is private, and should not be used directly. """ @@ -6948,8 +7039,8 @@ def _repr_(self): def handle_sage_input(self, sib, coerce, is_qqbar): r""" Produce an expression which will reproduce this value when evaluated, - and an indication of whether this value is worth sharing (always True, - for ``ANRoot``). + and an indication of whether this value is worth sharing (always ``True`` + for :class:`ANRoot`). EXAMPLES:: @@ -7030,10 +7121,11 @@ def is_complex(self): def conjugate(self, n): r""" - Complex conjugate of this ANRoot object. + Complex conjugate of this :class:`ANRoot` object. EXAMPLES:: + sage: # needs sage.symbolic sage: a = (x^2 + 23).roots(ring=QQbar, multiplicities=False)[0] sage: b = a._descr sage: type(b) @@ -7417,8 +7509,8 @@ def _complex_isolate_interval(self, interval, prec): def exactify(self): """ - Return either an ``ANRational`` or an - ``ANExtensionElement`` with the same value as this number. + Return either an :class:`ANRational` or an + :class:`ANExtensionElement` with the same value as this number. EXAMPLES:: @@ -7435,10 +7527,10 @@ def exactify(self): Verify that :trac:`12727` is fixed:: - sage: m = sqrt(sin(pi/5)); a = QQbar(m); b = AA(m) - sage: a.minpoly() + sage: m = sqrt(sin(pi/5)); a = QQbar(m); b = AA(m) # needs sage.symbolic + sage: a.minpoly() # needs sage.symbolic x^8 - 5/4*x^4 + 5/16 - sage: b.minpoly() + sage: b.minpoly() # needs sage.symbolic x^8 - 5/4*x^4 + 5/16 """ gen = self._poly.generator() @@ -7580,10 +7672,10 @@ def _interval_fast(self, prec): class ANExtensionElement(ANDescr): r""" - The subclass of ``ANDescr`` that represents a number field + The subclass of :class:`ANDescr` that represents a number field element in terms of a specific generator. Consists of a polynomial with rational coefficients in terms of the generator, and the - generator itself, an ``AlgebraicGenerator``. + generator itself, an :class:`AlgebraicGenerator`. """ def __new__(self, generator, value): @@ -7624,8 +7716,8 @@ def _repr_(self): def handle_sage_input(self, sib, coerce, is_qqbar): r""" Produce an expression which will reproduce this value when evaluated, - and an indication of whether this value is worth sharing (always True, - for ``ANExtensionElement``). + and an indication of whether this value is worth sharing (always ``True`` + for :class:`ANExtensionElement`). EXAMPLES:: @@ -7693,13 +7785,14 @@ def handle_sage_input(self, sib, coerce, is_qqbar): def is_complex(self): r""" - Return True if the number field that defines this element is not real. + Return ``True`` if the number field that defines this element is not real. This does not imply that the element itself is definitely non-real, as in the example below. EXAMPLES:: + sage: # needs sage.symbolic sage: rt2 = QQbar(sqrt(2)) sage: rtm3 = QQbar(sqrt(-3)) sage: x = rtm3 + rt2 - rtm3 @@ -7719,12 +7812,13 @@ def is_simple(self): Check whether this descriptor represents a value with the same algebraic degree as the number field associated with the descriptor. - For ``ANExtensionElement`` elements, we check this by + For :class:`ANExtensionElement` elements, we check this by comparing the degree of the minimal polynomial to the degree of the field. EXAMPLES:: + sage: # needs sage.symbolic sage: rt2 = AA(sqrt(2)) sage: rt3 = AA(sqrt(3)) sage: rt2b = rt3 + rt2 - rt3 @@ -7734,10 +7828,10 @@ def is_simple(self): sage: rt2._descr.is_simple() True - sage: rt2b.exactify() - sage: rt2b._descr + sage: rt2b.exactify() # needs sage.symbolic + sage: rt2b._descr # needs sage.symbolic a^3 - 3*a where a^4 - 4*a^2 + 1 = 0 and a in -0.5176380902050415? - sage: rt2b._descr.is_simple() + sage: rt2b._descr.is_simple() # needs sage.symbolic False """ try: @@ -7748,10 +7842,11 @@ def is_simple(self): def generator(self): r""" - Return the :class:`~AlgebraicGenerator` object corresponding to self. + Return the :class:`~AlgebraicGenerator` object corresponding to ``self``. EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: v = (x^2 - x - 1).roots(ring=AA, multiplicities=False)[1]._descr.exactify() sage: v.generator() Number Field in a with defining polynomial y^2 - y - 1 with a in 1.618033988749895? @@ -7766,6 +7861,7 @@ def exactify(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: v = (x^2 - x - 1).roots(ring=AA, multiplicities=False)[1]._descr.exactify() sage: type(v) <class 'sage.rings.qqbar.ANExtensionElement'> @@ -7780,6 +7876,7 @@ def field_element_value(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: v = (x^2 - x - 1).roots(ring=AA, multiplicities=False)[1]._descr.exactify() sage: v.field_element_value() a @@ -7792,6 +7889,7 @@ def minpoly(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: v = (x^2 - x - 1).roots(ring=AA, multiplicities=False)[1]._descr.exactify() sage: type(v) <class 'sage.rings.qqbar.ANExtensionElement'> @@ -7816,6 +7914,7 @@ def simplify(self, n): EXAMPLES:: + sage: # needs sage.symbolic sage: rt2 = AA(sqrt(2)) sage: rt3 = AA(sqrt(3)) sage: rt2b = rt3 + rt2 - rt3 @@ -7850,75 +7949,87 @@ def _interval_fast(self, prec): def neg(self, n): r""" - Negation of self. + Negation of ``self``. EXAMPLES:: + sage: # needs sage.symbolic sage: a = QQbar(sqrt(-2)) + QQbar(sqrt(-3)) sage: a.exactify() sage: b = a._descr sage: type(b) <class 'sage.rings.qqbar.ANExtensionElement'> - sage: c = b.neg(None); c # random (not uniquely represented) - -1/3*a^3 + 1/3*a^2 - a - 1 where a^4 - 2*a^3 + a^2 + 6*a + 3 = 0 and a in 1.724744871391589? + 1.573132184970987?*I - sage: c.generator() == b.generator() and c.field_element_value() + b.field_element_value() == 0 + sage: c = b.neg(None); c # random (not uniquely represented) + -1/3*a^3 + 1/3*a^2 - a - 1 where a^4 - 2*a^3 + a^2 + 6*a + 3 = 0 + and a in 1.724744871391589? + 1.573132184970987?*I + sage: (c.generator() == b.generator() + ....: and c.field_element_value() + b.field_element_value() == 0) True The parameter is ignored:: - sage: b.neg("random").generator() == c.generator() and b.neg("random").field_element_value() == c.field_element_value() + sage: (b.neg("random").generator() == c.generator() # needs sage.symbolic + ....: and b.neg("random").field_element_value() == c.field_element_value()) True """ return ANExtensionElement(self._generator, -self._value) def invert(self, n): r""" - Reciprocal of self. + Reciprocal of ``self``. EXAMPLES:: + sage: # needs sage.symbolic sage: a = QQbar(sqrt(-2)) + QQbar(sqrt(-3)) sage: a.exactify() sage: b = a._descr sage: type(b) <class 'sage.rings.qqbar.ANExtensionElement'> - sage: c = b.invert(None); c # random (not uniquely represented) - -7/3*a^3 + 19/3*a^2 - 7*a - 9 where a^4 - 2*a^3 + a^2 + 6*a + 3 = 0 and a in 1.724744871391589? + 1.573132184970987?*I - sage: c.generator() == b.generator() and c.field_element_value() * b.field_element_value() == 1 + sage: c = b.invert(None); c # random (not uniquely represented) + -7/3*a^3 + 19/3*a^2 - 7*a - 9 where a^4 - 2*a^3 + a^2 + 6*a + 3 = 0 + and a in 1.724744871391589? + 1.573132184970987?*I + sage: (c.generator() == b.generator() + ....: and c.field_element_value() * b.field_element_value() == 1) True The parameter is ignored:: - sage: b.invert("random").generator() == c.generator() and b.invert("random").field_element_value() == c.field_element_value() + sage: (b.invert("random").generator() == c.generator() # needs sage.symbolic + ....: and b.invert("random").field_element_value() == c.field_element_value()) True """ return ANExtensionElement(self._generator, ~self._value) def conjugate(self, n): - r"""Complex conjugate of self. + r""" + Complex conjugate of ``self``. EXAMPLES:: + sage: # needs sage.symbolic sage: a = QQbar(sqrt(-2)) + QQbar(sqrt(-3)) sage: a.exactify() sage: b = a._descr sage: type(b) <class 'sage.rings.qqbar.ANExtensionElement'> - sage: c = b.conjugate(None); c # random (not uniquely represented) - 1/3*a^3 - 1/3*a^2 + a + 1 where a^4 - 2*a^3 + a^2 + 6*a + 3 = 0 and a in 1.724744871391589? - 1.573132184970987?*I + sage: c = b.conjugate(None); c # random (not uniquely represented) + 1/3*a^3 - 1/3*a^2 + a + 1 where a^4 - 2*a^3 + a^2 + 6*a + 3 = 0 + and a in 1.724744871391589? - 1.573132184970987?*I Internally, complex conjugation is implemented by taking the same abstract field element but conjugating the complex embedding of the field:: - sage: c.generator() == b.generator().conjugate() + sage: c.generator() == b.generator().conjugate() # needs sage.symbolic True - sage: c.field_element_value() == b.field_element_value() + sage: c.field_element_value() == b.field_element_value() # needs sage.symbolic True The parameter is ignored:: - sage: b.conjugate("random").generator() == c.generator() and b.conjugate("random").field_element_value() == c.field_element_value() + sage: (b.conjugate("random").generator() == c.generator() # needs sage.symbolic + ....: and b.conjugate("random").field_element_value() == c.field_element_value()) True """ @@ -7932,10 +8043,11 @@ def conjugate(self, n): def norm(self, n): r""" - Norm of self (square of complex absolute value) + Norm of ``self`` (square of complex absolute value) EXAMPLES:: + sage: # needs sage.symbolic sage: a = QQbar(sqrt(-2)) + QQbar(sqrt(-3)) sage: a.exactify() sage: b = a._descr @@ -7953,10 +8065,11 @@ def norm(self, n): def abs(self, n): r""" - Return the absolute value of self (square root of the norm). + Return the absolute value of ``self`` (square root of the norm). EXAMPLES:: + sage: # needs sage.symbolic sage: a = QQbar(sqrt(-2)) + QQbar(sqrt(-3)) sage: a.exactify() sage: b = a._descr @@ -7969,11 +8082,12 @@ def abs(self, n): def rational_argument(self, n): r""" - If the argument of self is `2\pi` times some rational number in `[1/2, + If the argument of ``self`` is `2\pi` times some rational number in `[1/2, -1/2)`, return that rational; otherwise, return ``None``. EXAMPLES:: + sage: # needs sage.symbolic sage: a = QQbar(sqrt(-2)) + QQbar(sqrt(3)) sage: a.exactify() sage: b = a._descr @@ -7981,6 +8095,7 @@ def rational_argument(self, n): <class 'sage.rings.qqbar.ANExtensionElement'> sage: b.rational_argument(a) is None True + sage: x = polygen(QQ) sage: a = (x^4 + 1).roots(QQbar, multiplicities=False)[0] sage: a.exactify() @@ -8030,7 +8145,7 @@ def __init__(self, arg, op): EXAMPLES:: - sage: t = ~QQbar(sqrt(2)); type(t._descr) # indirect doctest + sage: t = ~QQbar(sqrt(2)); type(t._descr) # indirect doctest # needs sage.symbolic <class 'sage.rings.qqbar.ANUnaryExpr'> """ self._arg = arg @@ -8043,9 +8158,9 @@ def __reduce__(self): EXAMPLES:: - sage: t = ~QQbar(sqrt(2)); type(t._descr) + sage: t = ~QQbar(sqrt(2)); type(t._descr) # needs sage.symbolic <class 'sage.rings.qqbar.ANUnaryExpr'> - sage: loads(dumps(t)) == 1/QQbar(sqrt(2)) + sage: loads(dumps(t)) == 1/QQbar(sqrt(2)) # needs sage.symbolic True """ return (ANUnaryExpr, (self._arg, self._op)) @@ -8054,7 +8169,7 @@ def handle_sage_input(self, sib, coerce, is_qqbar): r""" Produce an expression which will reproduce this value when evaluated, and an indication of whether this value is worth sharing (always - True for ``ANUnaryExpr``). + ``True`` for :class:`ANUnaryExpr`). EXAMPLES:: @@ -8139,11 +8254,12 @@ def handle_sage_input(self, sib, coerce, is_qqbar): def is_complex(self): r""" Return whether or not this element is complex. Note that this is a data - type check, and triggers no computations -- if it returns False, the + type check, and triggers no computations -- if it returns ``False``, the element might still be real, it just doesn't know it yet. EXAMPLES:: + sage: # needs sage.symbolic sage: t = AA(sqrt(2)) sage: s = (-t)._descr sage: s @@ -8161,6 +8277,7 @@ def _interval_fast(self, prec): EXAMPLES:: + sage: # needs sage.symbolic sage: t = AA(sqrt(2)) sage: s = (-t)._descr sage: s @@ -8214,14 +8331,14 @@ def _interval_fast(self, prec): def exactify(self): r""" - Trigger exact computation of self. + Trigger exact computation of ``self``. EXAMPLES:: - sage: v = (-QQbar(sqrt(2)))._descr - sage: type(v) + sage: v = (-QQbar(sqrt(2)))._descr # needs sage.symbolic + sage: type(v) # needs sage.symbolic <class 'sage.rings.qqbar.ANUnaryExpr'> - sage: v.exactify() + sage: v.exactify() # needs sage.symbolic -a where a^2 - 2 = 0 and a in 1.414213562373095? """ op = self._op @@ -8285,7 +8402,7 @@ def __init__(self, left, right, op): EXAMPLES:: - sage: t = QQbar(sqrt(2)) + QQbar(sqrt(3)); type(t._descr) # indirect doctest + sage: t = QQbar(sqrt(2)) + QQbar(sqrt(3)); type(t._descr) # indirect doctest # needs sage.symbolic <class 'sage.rings.qqbar.ANBinaryExpr'> """ self._left = left @@ -8299,9 +8416,9 @@ def __reduce__(self): EXAMPLES:: - sage: t = QQbar(sqrt(2)) + QQbar(sqrt(3)); type(t._descr) + sage: t = QQbar(sqrt(2)) + QQbar(sqrt(3)); type(t._descr) # needs sage.symbolic <class 'sage.rings.qqbar.ANBinaryExpr'> - sage: loads(dumps(t)) == QQbar(sqrt(2)) + QQbar(sqrt(3)) + sage: loads(dumps(t)) == QQbar(sqrt(2)) + QQbar(sqrt(3)) # needs sage.symbolic True """ return (ANBinaryExpr, (self._left, self._right, self._op)) @@ -8310,7 +8427,7 @@ def handle_sage_input(self, sib, coerce, is_qqbar): r""" Produce an expression which will reproduce this value when evaluated, and an indication of whether this value is worth sharing (always - True for ``ANBinaryExpr``). + ``True`` for :class:`ANBinaryExpr`). EXAMPLES:: @@ -8349,10 +8466,10 @@ def handle_sage_input(self, sib, coerce, is_qqbar): True sage: sage_input(n) 1 + AA(3) - sage: rt3 = QQbar(sqrt(3)) - sage: one = rt3/rt3 - sage: n = sqrt(AA(2))+one - sage: one == 1 + sage: rt3 = QQbar(sqrt(3)) # needs sage.symbolic + sage: one = rt3/rt3 # needs sage.symbolic + sage: n = sqrt(AA(2)) + one + sage: one == 1 # needs sage.symbolic True sage: sage_input(n) R.<x> = AA[] @@ -8419,12 +8536,12 @@ def handle_sage_input(self, sib, coerce, is_qqbar): def is_complex(self): r""" Whether this element is complex. Does not trigger exact computation, so - may return True even if the element is real. + may return ``True`` even if the element is real. EXAMPLES:: - sage: x = (QQbar(sqrt(-2)) / QQbar(sqrt(-5)))._descr - sage: x.is_complex() + sage: x = (QQbar(sqrt(-2)) / QQbar(sqrt(-5)))._descr # needs sage.symbolic + sage: x.is_complex() # needs sage.symbolic True """ return self._complex @@ -8435,10 +8552,10 @@ def _interval_fast(self, prec): EXAMPLES:: - sage: x = (QQbar(sqrt(-2)) / QQbar(sqrt(-5)))._descr - sage: y= x._interval_fast(64); y + sage: x = (QQbar(sqrt(-2)) / QQbar(sqrt(-5)))._descr # needs sage.symbolic + sage: y= x._interval_fast(64); y # needs sage.symbolic 0.632455532033675867? - sage: y.parent() + sage: y.parent() # needs sage.symbolic Complex Interval Field with 64 bits of precision """ op = self._op @@ -8455,8 +8572,8 @@ def exactify(self): """ TESTS:: - sage: rt2c = QQbar.zeta(3) + AA(sqrt(2)) - QQbar.zeta(3) - sage: rt2c.exactify() + sage: rt2c = QQbar.zeta(3) + AA(sqrt(2)) - QQbar.zeta(3) # needs sage.symbolic + sage: rt2c.exactify() # needs sage.symbolic We check to make sure that this method still works even. We do this by increasing the recursion level at each step and @@ -8480,9 +8597,7 @@ def exactify(self): sage: sys.setrecursionlimit(old_recursion_limit) """ import sys - old_recursion_limit = sys.getrecursionlimit() - sys.setrecursionlimit(old_recursion_limit + 10) - try: + with increase_recursion_limit(10): left = self._left right = self._right left.exactify() @@ -8497,8 +8612,7 @@ def exactify(self): return ANRational(value) else: return ANExtensionElement(gen, value) - finally: - sys.setrecursionlimit(old_recursion_limit) + # These are the functions used to add, subtract, multiply, and divide # algebraic numbers. Basically, we try to compute exactly if both @@ -8544,6 +8658,7 @@ def an_binop_expr(a, b, op): EXAMPLES:: + sage: # needs sage.symbolic sage: a = QQbar(sqrt(2)) + QQbar(sqrt(3)) sage: b = QQbar(sqrt(3)) + QQbar(sqrt(5)) sage: type(a._descr); type(b._descr) @@ -8553,8 +8668,10 @@ def an_binop_expr(a, b, op): sage: x = an_binop_expr(a, b, operator.add); x <sage.rings.qqbar.ANBinaryExpr object at ...> sage: x.exactify() - 6/7*a^7 - 2/7*a^6 - 71/7*a^5 + 26/7*a^4 + 125/7*a^3 - 72/7*a^2 - 43/7*a + 47/7 where a^8 - 12*a^6 + 23*a^4 - 12*a^2 + 1 = 0 and a in -0.3199179336182997? + 6/7*a^7 - 2/7*a^6 - 71/7*a^5 + 26/7*a^4 + 125/7*a^3 - 72/7*a^2 - 43/7*a + 47/7 + where a^8 - 12*a^6 + 23*a^4 - 12*a^2 + 1 = 0 and a in -0.3199179336182997? + sage: # needs sage.symbolic sage: a = QQbar(sqrt(2)) + QQbar(sqrt(3)) sage: b = QQbar(sqrt(3)) + QQbar(sqrt(5)) sage: type(a._descr) @@ -8562,7 +8679,8 @@ def an_binop_expr(a, b, op): sage: x = an_binop_expr(a, b, operator.mul); x <sage.rings.qqbar.ANBinaryExpr object at ...> sage: x.exactify() - 2*a^7 - a^6 - 24*a^5 + 12*a^4 + 46*a^3 - 22*a^2 - 22*a + 9 where a^8 - 12*a^6 + 23*a^4 - 12*a^2 + 1 = 0 and a in -0.3199179336182997? + 2*a^7 - a^6 - 24*a^5 + 12*a^4 + 46*a^3 - 22*a^2 - 22*a + 9 + where a^8 - 12*a^6 + 23*a^4 - 12*a^2 + 1 = 0 and a in -0.3199179336182997? """ return ANBinaryExpr(a, b, op) @@ -8694,7 +8812,7 @@ def get_AA_golden_ratio(): EXAMPLES:: - sage: AA(golden_ratio) # indirect doctest + sage: AA(golden_ratio) # indirect doctest # needs sage.symbolic 1.618033988749895? """ global AA_golden_ratio diff --git a/src/sage/rings/qqbar_decorators.py b/src/sage/rings/qqbar_decorators.py index e18fac73cdc..c0505b11e8b 100644 --- a/src/sage/rings/qqbar_decorators.py +++ b/src/sage/rings/qqbar_decorators.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.number_field """ QQbar decorators @@ -36,7 +37,6 @@ def handle_AA_and_QQbar(func): @sage_wraps(func) def wrapper(*args, **kwds): - """ TESTS:: @@ -87,7 +87,7 @@ def wrapper(*args, **kwds): from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence, is_PolynomialSequence from sage.rings.ideal import Ideal, Ideal_generic - from sage.rings.qqbar import AlgebraicField_common, number_field_elements_from_algebraics + from sage.rings.abc import AlgebraicField_common if not any(isinstance(a, (Polynomial, MPolynomial, Ideal_generic)) and isinstance(a.base_ring(), AlgebraicField_common) @@ -110,6 +110,7 @@ def wrapper(*args, **kwds): # We need minimal=True if these elements are over AA, because # same_field=True might trigger an exception otherwise. + from sage.rings.qqbar import number_field_elements_from_algebraics numfield, new_elems, morphism = number_field_elements_from_algebraics(orig_elems, same_field=True, minimal=True) elem_dict = dict(zip(orig_elems, new_elems)) diff --git a/src/sage/rings/quotient_ring.py b/src/sage/rings/quotient_ring.py index 8f9bf928cc5..7dc4e0803c8 100644 --- a/src/sage/rings/quotient_ring.py +++ b/src/sage/rings/quotient_ring.py @@ -38,8 +38,8 @@ ....: def reduce(self,x): ....: R = self.ring() ....: return add([c*R(m) for m,c in x if len(m)<self._power],R(0)) - sage: F.<x,y,z> = FreeAlgebra(QQ, 3) - sage: I3 = PowerIdeal(F,3); I3 + sage: F.<x,y,z> = FreeAlgebra(QQ, 3) # needs sage.combinat sage.modules + sage: I3 = PowerIdeal(F,3); I3 # needs sage.combinat sage.modules Twosided Ideal (x^3, x^2*y, x^2*z, x*y*x, x*y^2, x*y*z, x*z*x, x*z*y, x*z^2, y*x^2, y*x*y, y*x*z, y^2*x, y^3, y^2*z, y*z*x, y*z*y, y*z^2, z*x^2, z*x*y, z*x*z, z*y*x, z*y^2, z*y*z, z^2*x, z^2*y, z^3) of @@ -49,6 +49,7 @@ finite dimensional quotients defined by multiplication matrices. We are bypassing it, so that we obtain the default quotient:: + sage: # needs sage.combinat sage.modules sage: Q3.<a,b,c> = F.quotient(I3) sage: Q3 Quotient of Free Algebra on 3 generators (x, y, z) over Rational Field by @@ -63,12 +64,13 @@ Even though `Q_3` is not commutative, there is commutativity for products of degree three:: - sage: a*(b*c)-(b*c)*a==F.zero() + sage: a*(b*c)-(b*c)*a==F.zero() # needs sage.combinat sage.modules True If we quotient out all terms of degree two then of course the resulting quotient ring is commutative:: + sage: # needs sage.combinat sage.modules sage: I2 = PowerIdeal(F,2); I2 Twosided Ideal (x^2, x*y, x*z, y*x, y^2, y*z, z*x, z*y, z^2) of Free Algebra on 3 generators (x, y, z) over Rational Field @@ -83,14 +85,18 @@ letterplace wrapper allows to provide the above toy example more easily:: + sage: # needs sage.combinat sage.libs.singular sage.modules sage: from itertools import product sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') sage: Q3 = F.quo(F*[F.prod(m) for m in product(F.gens(), repeat=3)]*F) sage: Q3 - Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*x*x, x*x*y, x*x*z, x*y*x, x*y*y, x*y*z, x*z*x, x*z*y, x*z*z, y*x*x, y*x*y, y*x*z, y*y*x, y*y*y, y*y*z, y*z*x, y*z*y, y*z*z, z*x*x, z*x*y, z*x*z, z*y*x, z*y*y, z*y*z, z*z*x, z*z*y, z*z*z) - sage: Q3.0*Q3.1-Q3.1*Q3.0 + Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) + over Rational Field by the ideal (x*x*x, x*x*y, x*x*z, x*y*x, x*y*y, x*y*z, + x*z*x, x*z*y, x*z*z, y*x*x, y*x*y, y*x*z, y*y*x, y*y*y, y*y*z, y*z*x, y*z*y, + y*z*z, z*x*x, z*x*y, z*x*z, z*y*x, z*y*y, z*y*z, z*z*x, z*z*y, z*z*z) + sage: Q3.0*Q3.1 - Q3.1*Q3.0 xbar*ybar - ybar*xbar - sage: Q3.0*(Q3.1*Q3.2)-(Q3.1*Q3.2)*Q3.0 + sage: Q3.0*(Q3.1*Q3.2) - (Q3.1*Q3.2)*Q3.0 0 sage: Q2 = F.quo(F*[F.prod(m) for m in product(F.gens(), repeat=2)]*F) sage: Q2.is_commutative() @@ -157,7 +163,7 @@ def QuotientRing(R, I, names=None, **kwds): Some simple quotient rings with the integers:: - sage: R = QuotientRing(ZZ,7*ZZ); R + sage: R = QuotientRing(ZZ, 7*ZZ); R Quotient of Integer Ring by the ideal (7) sage: R.gens() (1,) @@ -176,10 +182,12 @@ def QuotientRing(R, I, names=None, **kwds): With polynomial rings (note that the variable name of the quotient ring can be specified as shown below):: + sage: # needs sage.libs.pari sage: P.<x> = QQ[] sage: R.<xx> = QuotientRing(P, P.ideal(x^2 + 1)) sage: R - Univariate Quotient Polynomial Ring in xx over Rational Field with modulus x^2 + 1 + Univariate Quotient Polynomial Ring in xx over Rational Field + with modulus x^2 + 1 sage: R.gens(); R.gen() (xx,) xx @@ -191,11 +199,12 @@ def QuotientRing(R, I, names=None, **kwds): :: + sage: # needs sage.libs.pari sage: P.<x> = QQ[] sage: S = QuotientRing(P, P.ideal(x^2 - 2)) sage: S - Univariate Quotient Polynomial Ring in xbar over Rational Field with - modulus x^2 - 2 + Univariate Quotient Polynomial Ring in xbar over Rational Field + with modulus x^2 - 2 sage: xbar = S.gen(); S.gen() xbar sage: for n in range(3): xbar^n @@ -206,20 +215,22 @@ def QuotientRing(R, I, names=None, **kwds): Sage coerces objects into ideals when possible:: sage: P.<x> = QQ[] - sage: R = QuotientRing(P, x^2 + 1); R - Univariate Quotient Polynomial Ring in xbar over Rational Field with - modulus x^2 + 1 + sage: R = QuotientRing(P, x^2 + 1); R # needs sage.libs.pari + Univariate Quotient Polynomial Ring in xbar over Rational Field + with modulus x^2 + 1 By Noether's homomorphism theorems, the quotient of a quotient ring of `R` is just the quotient of `R` by the sum of the ideals. In this example, we end up modding out the ideal `(x)` from the ring `\QQ[x,y]`:: - sage: R.<x,y> = PolynomialRing(QQ,2) - sage: S.<a,b> = QuotientRing(R,R.ideal(1 + y^2)) - sage: T.<c,d> = QuotientRing(S,S.ideal(a)) + sage: # needs sage.libs.pari sage.libs.singular + sage: R.<x,y> = PolynomialRing(QQ, 2) + sage: S.<a,b> = QuotientRing(R, R.ideal(1 + y^2)) + sage: T.<c,d> = QuotientRing(S, S.ideal(a)) sage: T - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y^2 + 1) + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x, y^2 + 1) sage: R.gens(); S.gens(); T.gens() (x, y) (a, b) @@ -243,17 +254,21 @@ def QuotientRing(R, I, names=None, **kwds): Here is an example of the quotient of a free algebra by a twosided homogeneous ideal (see :trac:`7797`):: + sage: # needs sage.combinat sage.libs.singular sage.modules sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') - sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F + sage: I = F * [x*y + y*z, x^2 + x*y - y*x - y^2] * F sage: Q.<a,b,c> = F.quo(I); Q - Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) + Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) + over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) sage: a*b -b*c sage: a^3 -b*c*a - b*c*b - b*c*c - sage: J = Q*[a^3-b^3]*Q + sage: J = Q * [a^3 - b^3] * Q sage: R.<i,j,k> = Q.quo(J); R - Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (-y*y*z - y*z*x - 2*y*z*z, x*y + y*z, x*x + x*y - y*x - y*y) + Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) + over Rational Field by the ideal + (-y*y*z - y*z*x - 2*y*z*z, x*y + y*z, x*x + x*y - y*x - y*y) sage: i^3 -j*k*i - j*k*j - j*k*k sage: j^3 @@ -290,7 +305,13 @@ def QuotientRing(R, I, names=None, **kwds): from sage.rings.polynomial.polynomial_ring_constructor import BooleanPolynomialRing_constructor as BooleanPolynomialRing kwds.pop('implementation') return BooleanPolynomialRing(R.ngens(), names=names, **kwds) - if not isinstance(I, ideal.Ideal_generic) or I.ring() != R: + # workaround to silence warning from #34806 + from sage.rings.number_field.order import Order + if isinstance(R, Order): + if not R.is_maximal(): + raise NotImplementedError('only implemented for maximal orders') + I = R.number_field().ideal(I) + elif not isinstance(I, ideal.Ideal_generic) or I.ring() != R: I = R.ideal(I) if I.is_zero(): return R @@ -336,8 +357,9 @@ def is_QuotientRing(x): :: + sage: # needs sage.combinat sage.libs.singular sage.modules sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') - sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F + sage: I = F * [x*y + y*z, x^2 + x*y - y*x - y^2] * F sage: Q = F.quo(I) sage: is_QuotientRing(Q) True @@ -364,10 +386,12 @@ class QuotientRing_nc(ring.Ring, sage.structure.parent_gens.ParentWithGens): Here is a quotient of a free algebra by a twosided homogeneous ideal:: + sage: # needs sage.combinat sage.libs.singular sage.modules sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') - sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F + sage: I = F * [x*y + y*z, x^2 + x*y - y*x - y^2]*F sage: Q.<a,b,c> = F.quo(I); Q - Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) + Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field + by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) sage: a*b -b*c sage: a^3 @@ -376,9 +400,12 @@ class QuotientRing_nc(ring.Ring, sage.structure.parent_gens.ParentWithGens): A quotient of a quotient is just the quotient of the original top ring by the sum of two ideals:: - sage: J = Q*[a^3-b^3]*Q + sage: # needs sage.combinat sage.libs.singular sage.modules + sage: J = Q * [a^3 - b^3] * Q sage: R.<i,j,k> = Q.quo(J); R - Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (-y*y*z - y*z*x - 2*y*z*z, x*y + y*z, x*x + x*y - y*x - y*y) + Quotient of + Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field + by the ideal (-y*y*z - y*z*x - 2*y*z*z, x*y + y*z, x*x + x*y - y*x - y*y) sage: i^3 -j*k*i - j*k*j - j*k*k sage: j^3 @@ -393,15 +420,16 @@ class QuotientRing_nc(ring.Ring, sage.structure.parent_gens.ParentWithGens): sage: R.<x> = PolynomialRing(ZZ,'x') sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: S = R.quotient_ring(I); S - Quotient of Univariate Polynomial Ring in x over Integer Ring by the ideal (x^2 + 3*x + 4, x^2 + 1) + Quotient of Univariate Polynomial Ring in x over Integer Ring + by the ideal (x^2 + 3*x + 4, x^2 + 1) :: sage: R.<x,y> = PolynomialRing(QQ) - sage: S.<a,b> = R.quo(x^2 + y^2) - sage: a^2 + b^2 == 0 + sage: S.<a,b> = R.quo(x^2 + y^2) # needs sage.libs.singular + sage: a^2 + b^2 == 0 # needs sage.libs.singular True - sage: S(0) == a^2 + b^2 + sage: S(0) == a^2 + b^2 # needs sage.libs.singular True Again, a quotient of a quotient is just the quotient of the original top @@ -409,15 +437,18 @@ class QuotientRing_nc(ring.Ring, sage.structure.parent_gens.ParentWithGens): :: - sage: R.<x,y> = PolynomialRing(QQ,2) + sage: # needs sage.libs.singular + sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S.<a,b> = R.quo(1 + y^2) sage: T.<c,d> = S.quo(a) sage: T - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y^2 + 1) + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x, y^2 + 1) sage: T.gens() (0, d) """ Element = quotient_ring_element.QuotientRingElement + def __init__(self, R, I, names, category=None): """ Create the quotient ring of `R` by the twosided ideal `I`. @@ -432,10 +463,13 @@ def __init__(self, R, I, names, category=None): EXAMPLES:: + sage: # needs sage.combinat sage.libs.singular sage.modules sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') - sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F + sage: I = F * [x*y + y*z, x^2 + x*y - y*x - y^2] * F sage: Q.<a,b,c> = F.quo(I); Q - Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) + Quotient of + Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field + by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) sage: a*b -b*c sage: a^3 @@ -443,9 +477,15 @@ def __init__(self, R, I, names, category=None): """ if R not in _Rings: - raise TypeError("The first argument must be a ring, but %s is not"%R) - if I not in R.ideal_monoid(): - raise TypeError("The second argument must be an ideal of the given ring, but %s is not"%I) + raise TypeError("The first argument must be a ring, but %s is not" % R) + # workaround to silence warning from #34806 + from sage.rings.number_field.order import Order + if isinstance(R, Order): + M = R.number_field().ideal_monoid() + else: + M = R.ideal_monoid() + if I not in M: + raise TypeError("The second argument must be an ideal of the given ring, but %s is not" % I) self.__R = R self.__I = I #sage.structure.parent_gens.ParentWithGens.__init__(self, R.base_ring(), names) @@ -479,11 +519,14 @@ def construction(self): sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: R.quotient_ring(I).construction() (QuotientFunctor, Univariate Polynomial Ring in x over Integer Ring) + + sage: # needs sage.combinat sage.libs.singular sage.modules sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') - sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F + sage: I = F * [x*y + y*z, x^2 + x*y - y*x - y^2] * F sage: Q = F.quo(I) sage: Q.construction() - (QuotientFunctor, Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field) + (QuotientFunctor, + Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field) TESTS:: @@ -523,7 +566,7 @@ def _repr_(self): sage: R.quotient_ring(I)._repr_() 'Quotient of Univariate Polynomial Ring in x over Integer Ring by the ideal (x^2 + 3*x + 4, x^2 + 1)' """ - return "Quotient of %s by the ideal %s"%(self.cover_ring(), self.defining_ideal()._repr_short()) + return "Quotient of %s by the ideal %s" % (self.cover_ring(), self.defining_ideal()._repr_short()) def _latex_(self): """ @@ -536,7 +579,7 @@ def _latex_(self): sage: R.quotient_ring(I)._latex_() '\\Bold{Z}[x]/\\left(x^{2} + 3x + 4, x^{2} + 1\\right)\\Bold{Z}[x]' """ - return "%s/%s"%(latex.latex(self.cover_ring()), latex.latex(self.defining_ideal())) + return "%s/%s" % (latex.latex(self.cover_ring()), latex.latex(self.defining_ideal())) def is_commutative(self): """ @@ -563,17 +606,19 @@ def is_commutative(self): The non-commutative case is more interesting:: + sage: # needs sage.combinat sage.libs.singular sage.modules sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') - sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F + sage: I = F * [x*y + y*z, x^2 + x*y - y*x - y^2] * F sage: Q = F.quo(I) sage: Q.is_commutative() False - sage: Q.1*Q.2==Q.2*Q.1 + sage: Q.1*Q.2 == Q.2*Q.1 False In the next example, the generators apparently commute:: - sage: J = F*[x*y-y*x,x*z-z*x,y*z-z*y,x^3-y^3]*F + sage: # needs sage.combinat sage.libs.singular sage.modules + sage: J = F * [x*y - y*x, x*z - z*x, y*z - z*y, x^3 - y^3] * F sage: R = F.quo(J) sage: R.is_commutative() True @@ -598,12 +643,11 @@ def is_commutative(self): @cached_method def cover(self): r""" - The covering ring homomorphism `R \to R/I`, equipped with a - section. + The covering ring homomorphism `R \to R/I`, equipped with a section. EXAMPLES:: - sage: R = ZZ.quo(3*ZZ) + sage: R = ZZ.quo(3 * ZZ) sage: pi = R.cover() sage: pi Ring morphism: @@ -616,20 +660,22 @@ def cover(self): :: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ) - sage: Q = R.quo( (x^2,y^2) ) + sage: Q = R.quo((x^2, y^2)) sage: pi = Q.cover() - sage: pi(x^3+y) + sage: pi(x^3 + y) ybar - sage: l = pi.lift(x+y^3) + sage: l = pi.lift(x + y^3) sage: l x sage: l = pi.lift(); l Set-theoretic ring morphism: - From: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y^2) + From: Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2, y^2) To: Multivariate Polynomial Ring in x, y over Rational Field Defn: Choice of lifting map - sage: l(x+y^3) + sage: l(x + y^3) x """ try: @@ -649,16 +695,19 @@ def lifting_map(self): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S = R.quotient(x^2 + y^2) sage: pi = S.cover(); pi Ring morphism: From: Multivariate Polynomial Ring in x, y over Rational Field - To: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) + To: Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2 + y^2) Defn: Natural quotient map sage: L = S.lifting_map(); L Set-theoretic ring morphism: - From: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) + From: Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2 + y^2) To: Multivariate Polynomial Ring in x, y over Rational Field Defn: Choice of lifting map sage: L(S.0) @@ -669,22 +718,24 @@ def lifting_map(self): Note that some reduction may be applied so that the lift of a reduction need not equal the original element:: - sage: z = pi(x^3 + 2*y^2); z + sage: z = pi(x^3 + 2*y^2); z # needs sage.libs.singular -xbar*ybar^2 + 2*ybar^2 - sage: L(z) + sage: L(z) # needs sage.libs.singular -x*y^2 + 2*y^2 - sage: L(z) == x^3 + 2*y^2 + sage: L(z) == x^3 + 2*y^2 # needs sage.libs.singular False Test that there also is a lift for rings that are no instances of :class:`~sage.rings.ring.Ring` (see :trac:`11068`):: - sage: MS = MatrixSpace(GF(5),2,2) - sage: I = MS*[MS.0*MS.1,MS.2+MS.3]*MS + sage: # needs sage.modules + sage: MS = MatrixSpace(GF(5), 2, 2) + sage: I = MS * [MS.0*MS.1, MS.2 + MS.3] * MS sage: Q = MS.quo(I) sage: Q.lift() Set-theoretic ring morphism: - From: Quotient of Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5 by the ideal + From: Quotient of Full MatrixSpace of 2 by 2 dense matrices + over Finite Field of size 5 by the ideal ( [0 1] [0 0], @@ -707,7 +758,7 @@ def lifting_map(self): return m # The following is to make the category framework happy. - def lift(self,x=None): + def lift(self, x=None): """ Return the lifting map to the cover, or the image of an element under the lifting map. @@ -723,12 +774,13 @@ def lift(self,x=None): sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S = R.quotient(x^2 + y^2) - sage: S.lift() + sage: S.lift() # needs sage.libs.singular Set-theoretic ring morphism: - From: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) + From: Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2 + y^2) To: Multivariate Polynomial Ring in x, y over Rational Field Defn: Choice of lifting map - sage: S.lift(S.0) == x + sage: S.lift(S.0) == x # needs sage.libs.singular True """ @@ -752,7 +804,7 @@ def retract(self,x): sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S = R.quotient(x^2 + y^2) - sage: S.retract((x+y)^2) + sage: S.retract((x+y)^2) # needs sage.libs.singular 2*xbar*ybar """ @@ -792,9 +844,10 @@ def defining_ideal(self): homomorphism theorems, this is actually a quotient by a sum of two ideals:: - sage: R.<x,y> = PolynomialRing(QQ,2) - sage: S.<a,b> = QuotientRing(R,R.ideal(1 + y^2)) - sage: T.<c,d> = QuotientRing(S,S.ideal(a)) + sage: # needs sage.libs.singular + sage: R.<x,y> = PolynomialRing(QQ, 2) + sage: S.<a,b> = QuotientRing(R, R.ideal(1 + y^2)) + sage: T.<c,d> = QuotientRing(S, S.ideal(a)) sage: S.defining_ideal() Ideal (y^2 + 1) of Multivariate Polynomial Ring in x, y over Rational Field sage: T.defining_ideal() @@ -803,14 +856,14 @@ def defining_ideal(self): return self.__I @cached_method - def is_field(self, proof = True): + def is_field(self, proof=True): r""" Returns ``True`` if the quotient ring is a field. Checks to see if the defining ideal is maximal. TESTS:: - sage: Q = QuotientRing(ZZ,7*ZZ) + sage: Q = QuotientRing(ZZ, 7*ZZ) sage: Q.is_field() True @@ -818,7 +871,7 @@ def is_field(self, proof = True): implemented:: sage: R.<x, y> = ZZ[] - sage: R.quotient_ring(R.ideal([2, 4 +x])).is_field() + sage: R.quotient_ring(R.ideal([2, 4 + x])).is_field() Traceback (most recent call last): ... NotImplementedError @@ -845,11 +898,11 @@ def is_integral_domain(self, proof=True): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: R.quo(x^2 - y).is_integral_domain() + sage: R.quo(x^2 - y).is_integral_domain() # needs sage.libs.singular True - sage: R.quo(x^2 - y^2).is_integral_domain() + sage: R.quo(x^2 - y^2).is_integral_domain() # needs sage.libs.singular False - sage: R.quo(x^2 - y^2).is_integral_domain(proof=False) + sage: R.quo(x^2 - y^2).is_integral_domain(proof=False) # needs sage.libs.singular False sage: R.<a,b,c> = ZZ[] sage: Q = R.quotient_ring([a, b]) @@ -874,12 +927,12 @@ def is_noetherian(self): EXAMPLES:: - sage: R = QuotientRing(ZZ, 102*ZZ) + sage: R = QuotientRing(ZZ, 102 * ZZ) sage: R.is_noetherian() True sage: P.<x> = QQ[] - sage: R = QuotientRing(P, x^2+1) + sage: R = QuotientRing(P, x^2 + 1) # needs sage.libs.pari sage: R.is_noetherian() True @@ -911,15 +964,15 @@ def cover_ring(self): EXAMPLES:: - sage: Q = QuotientRing(ZZ,7*ZZ) + sage: Q = QuotientRing(ZZ, 7 * ZZ) sage: Q.cover_ring() Integer Ring :: sage: P.<x> = QQ[] - sage: Q = QuotientRing(P, x^2 + 1) - sage: Q.cover_ring() + sage: Q = QuotientRing(P, x^2 + 1) # needs sage.libs.pari + sage: Q.cover_ring() # needs sage.libs.pari Univariate Polynomial Ring in x over Rational Field """ return self.__R @@ -934,11 +987,13 @@ def ideal(self, *gens, **kwds): EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ) - sage: S = R.quotient_ring(x^2+y^2) - sage: S.ideal() - Ideal (0) of Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) - sage: S.ideal(x+y+1) - Ideal (xbar + ybar + 1) of Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) + sage: S = R.quotient_ring(x^2 + y^2) + sage: S.ideal() # needs sage.libs.singular + Ideal (0) of Quotient of Multivariate Polynomial Ring in x, y + over Rational Field by the ideal (x^2 + y^2) + sage: S.ideal(x + y + 1) # needs sage.libs.singular + Ideal (xbar + ybar + 1) of Quotient of Multivariate Polynomial Ring in x, y + over Rational Field by the ideal (x^2 + y^2) TESTS: @@ -974,10 +1029,10 @@ def _element_constructor_(self, x, coerce=True): EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ) - sage: S = R.quotient_ring(x^2+y^2) - sage: S(x) # indirect doctest + sage: S = R.quotient_ring(x^2 + y^2) + sage: S(x) # indirect doctest # needs sage.libs.singular xbar - sage: S(x^2 + y^2) + sage: S(x^2 + y^2) # needs sage.libs.singular 0 The rings that coerce into the quotient ring canonically, are: @@ -989,6 +1044,7 @@ def _element_constructor_(self, x, coerce=True): :: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S.<a,b> = R.quotient(x^2 + y^2) sage: S.coerce(0) @@ -1000,11 +1056,12 @@ def _element_constructor_(self, x, coerce=True): sage: S.coerce(GF(7)(3)) Traceback (most recent call last): ... - TypeError: no canonical coercion from Finite Field of size 7 to Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) + TypeError: no canonical coercion from Finite Field of size 7 + to Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) TESTS:: - sage: S(x, coerce=False) + sage: S(x, coerce=False) # needs sage.libs.singular a """ if isinstance(x, quotient_ring_element.QuotientRingElement): @@ -1027,15 +1084,15 @@ def _coerce_map_from_(self, R): EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ) - sage: S = R.quotient_ring(x^2+y^2) - sage: S.has_coerce_map_from(R) # indirect doctest + sage: S = R.quotient_ring(x^2 + y^2) + sage: S.has_coerce_map_from(R) # indirect doctest True sage: S.has_coerce_map_from(QQ) True - sage: T = S.quotient_ring(x^3 - y) - sage: S.has_coerce_map_from(T) + sage: T = S.quotient_ring(x^3 - y) # needs sage.libs.singular + sage: S.has_coerce_map_from(T) # needs sage.libs.singular False - sage: T.has_coerce_map_from(R) + sage: T.has_coerce_map_from(R) # needs sage.libs.singular True TESTS: @@ -1043,15 +1100,17 @@ def _coerce_map_from_(self, R): We check that :trac:`13682` is fixed:: sage: R.<x,y> = PolynomialRing(QQ) - sage: I = R.ideal(x^2+y^2) - sage: J = R.ideal(x^2+y^2, x^3 - y) - sage: I < J - True + sage: I = R.ideal(x^2 + y^2) + sage: J = R.ideal(x^2 + y^2, x^3 - y) sage: S = R.quotient(I) sage: T = R.quotient(J) + + sage: # needs sage.libs.singular + sage: I < J + True sage: T.has_coerce_map_from(S) True - sage: S.quotient_ring(x^4-x*y+1).has_coerce_map_from(S) + sage: S.quotient_ring(x^4 - x*y + 1).has_coerce_map_from(S) True sage: S.has_coerce_map_from(T) False @@ -1059,17 +1118,17 @@ def _coerce_map_from_(self, R): We also allow coercions with the cover rings:: sage: Rp.<x,y> = PolynomialRing(ZZ) - sage: Ip = Rp.ideal(x^2+y^2) - sage: Jp = Rp.ideal(x^2+y^2, x^3 - y) + sage: Ip = Rp.ideal(x^2 + y^2) + sage: Jp = Rp.ideal(x^2 + y^2, x^3 - y) sage: Sp = Rp.quotient(Ip) sage: Tp = Rp.quotient(Jp) sage: R.has_coerce_map_from(Rp) True sage: Sp.has_coerce_map_from(Sp) True - sage: T.has_coerce_map_from(Sp) + sage: T.has_coerce_map_from(Sp) # needs sage.libs.singular True - sage: Sp.has_coerce_map_from(T) + sage: Sp.has_coerce_map_from(T) # needs sage.libs.singular False """ C = self.cover_ring() @@ -1101,7 +1160,7 @@ def __richcmp__(self, other, op): equal, but since the generators are different, the corresponding quotient rings are not equal:: - sage: R.ideal(x^2+y^2) == R.ideal(-x^2 - y^2) + sage: R.ideal(x^2 + y^2) == R.ideal(-x^2 - y^2) # needs sage.libs.singular True sage: R.quotient_ring(x^2 + y^2) == R.quotient_ring(-x^2 - y^2) False @@ -1125,18 +1184,20 @@ def ngens(self): EXAMPLES:: - sage: R = QuotientRing(ZZ,7*ZZ) + sage: R = QuotientRing(ZZ, 7*ZZ) sage: R.gens(); R.ngens() (1,) 1 :: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ,2) - sage: S.<a,b> = QuotientRing(R,R.ideal(1 + y^2)) - sage: T.<c,d> = QuotientRing(S,S.ideal(a)) + sage: S.<a,b> = QuotientRing(R, R.ideal(1 + y^2)) + sage: T.<c,d> = QuotientRing(S, S.ideal(a)) sage: T - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y^2 + 1) + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x, y^2 + 1) sage: R.gens(); S.gens(); T.gens() (x, y) (a, b) @@ -1154,17 +1215,19 @@ def gen(self, i=0): EXAMPLES:: - sage: R = QuotientRing(ZZ,7*ZZ) + sage: R = QuotientRing(ZZ, 7*ZZ) sage: R.gen(0) 1 :: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ,2) - sage: S.<a,b> = QuotientRing(R,R.ideal(1 + y^2)) - sage: T.<c,d> = QuotientRing(S,S.ideal(a)) + sage: S.<a,b> = QuotientRing(R, R.ideal(1 + y^2)) + sage: T.<c,d> = QuotientRing(S, S.ideal(a)) sage: T - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y^2 + 1) + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x, y^2 + 1) sage: R.gen(0); R.gen(1) x y @@ -1197,8 +1260,8 @@ def _singular_(self, singular=None): EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ) - sage: S = R.quotient_ring(x^2+y^2) - sage: S._singular_() + sage: S = R.quotient_ring(x^2 + y^2) + sage: S._singular_() # needs sage.libs.singular polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 2 @@ -1231,17 +1294,17 @@ def _singular_init_(self, singular=None): EXAMPLES:: sage: R.<x,y> = PolynomialRing(QQ) - sage: S = R.quotient_ring(x^2+y^2) - sage: T = S._singular_init_() + sage: S = R.quotient_ring(x^2 + y^2) + sage: T = S._singular_init_() # needs sage.libs.singular sage: parent(S) <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category'> - sage: parent(T) + sage: parent(T) # needs sage.libs.singular Singular """ if singular is None: from sage.interfaces.singular import singular self.__R._singular_().set_ring() - self.__singular = singular("%s"%self.__I._singular_().name(),"qring") + self.__singular = singular("%s" % self.__I._singular_().name(),"qring") return self.__singular def _magma_init_(self, magma): @@ -1257,7 +1320,7 @@ def _magma_init_(self, magma): sage: P.<x,y> = PolynomialRing(GF(2)) sage: Q = P.quotient(sage.rings.ideal.FieldIdeal(P)) - sage: magma(Q) # optional - magma # indirect doctest + sage: magma(Q) # indirect doctest # optional - magma Affine Algebra of rank 2 over GF(2) Graded Reverse Lexicographical Order Variables: x, y @@ -1269,7 +1332,7 @@ def _magma_init_(self, magma): """ R = magma(self.__R) I = magma(self.__I.gens()) - return "quo<%s|%s>"%(R.name(), I._ref()) + return "quo<%s|%s>" % (R.name(), I._ref()) def term_order(self): """ @@ -1295,7 +1358,8 @@ class QuotientRing_generic(QuotientRing_nc, ring.CommutativeRing): sage: R.<x> = PolynomialRing(ZZ) sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: S = R.quotient_ring(I); S - Quotient of Univariate Polynomial Ring in x over Integer Ring by the ideal (x^2 + 3*x + 4, x^2 + 1) + Quotient of Univariate Polynomial Ring in x over Integer Ring + by the ideal (x^2 + 3*x + 4, x^2 + 1) """ def __init__(self, R, I, names, category=None): @@ -1340,7 +1404,7 @@ def _macaulay2_init_(self, macaulay2=None): x - y sage: R.<x,y,z,w> = PolynomialRing(ZZ, 4) - sage: I = R.ideal([x*y-z^2, y^2-w^2]) + sage: I = R.ideal([x*y - z^2, y^2 - w^2]) sage: Q = R.quotient(I); Q Quotient of Multivariate Polynomial Ring in x, y, z, w over Integer Ring by the ideal (x*y - z^2, y^2 - w^2) sage: Q._macaulay2_init_() # optional - macaulay2 @@ -1352,7 +1416,8 @@ def _macaulay2_init_(self, macaulay2=None): sage: R.<x,y> = PolynomialRing(GF(101), 2) sage: I = R.ideal([x^2 + x, y^2 + y]) sage: Q = R.quotient_ring(I); Q - Quotient of Multivariate Polynomial Ring in x, y over Finite Field of size 101 by the ideal (x^2 + x, y^2 + y) + Quotient of Multivariate Polynomial Ring in x, y over + Finite Field of size 101 by the ideal (x^2 + x, y^2 + y) sage: Q._macaulay2_init_() # optional - macaulay2 ZZ ---[x...y] @@ -1426,13 +1491,14 @@ def _contains_(self, other): :: + sage: # needs sage.libs.pari sage: R.<T> = QQ[] - sage: S.<t> = R.quotient(T^3-1) - sage: 1 in S.ideal(t^2-1) + sage: S.<t> = R.quotient(T^3 - 1) + sage: 1 in S.ideal(t^2 - 1) False - sage: 7 in S.ideal(t^2+1) + sage: 7 in S.ideal(t^2 + 1) True - sage: 5-5*t in S.ideal(t^2-1) + sage: 5-5*t in S.ideal(t^2 - 1) True """ R = self.ring() diff --git a/src/sage/rings/quotient_ring_element.py b/src/sage/rings/quotient_ring_element.py index e2f190a4b1c..f67c7192f11 100644 --- a/src/sage/rings/quotient_ring_element.py +++ b/src/sage/rings/quotient_ring_element.py @@ -45,7 +45,8 @@ class QuotientRingElement(RingElement): sage: R.<x> = PolynomialRing(ZZ) sage: S.<xbar> = R.quo((4 + 3*x + x^2, 1 + x^2)); S - Quotient of Univariate Polynomial Ring in x over Integer Ring by the ideal (x^2 + 3*x + 4, x^2 + 1) + Quotient of Univariate Polynomial Ring in x over Integer Ring + by the ideal (x^2 + 3*x + 4, x^2 + 1) sage: v = S.gens(); v (xbar,) @@ -58,14 +59,16 @@ class QuotientRingElement(RingElement): sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S = R.quo(x^2 + y^2); S - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) - sage: S.gens() + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2 + y^2) + sage: S.gens() # needs sage.libs.singular (xbar, ybar) We name each of the generators. :: + sage: # needs sage.libs.singular sage: S.<a,b> = R.quotient(x^2 + y^2) sage: a a @@ -87,7 +90,8 @@ def __init__(self, parent, rep, reduce=True): sage: R.<x> = PolynomialRing(ZZ) sage: S.<xbar> = R.quo((4 + 3*x + x^2, 1 + x^2)); S - Quotient of Univariate Polynomial Ring in x over Integer Ring by the ideal (x^2 + 3*x + 4, x^2 + 1) + Quotient of Univariate Polynomial Ring in x over Integer Ring + by the ideal (x^2 + 3*x + 4, x^2 + 1) sage: v = S.gens(); v (xbar,) """ @@ -106,10 +110,10 @@ def _reduce_(self): TESTS:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: a._reduce_() - sage: a._QuotientRingElement__rep + sage: a._reduce_() # needs sage.libs.singular + sage: a._QuotientRingElement__rep # needs sage.libs.singular x """ I = self.parent().defining_ideal() @@ -122,57 +126,55 @@ def lift(self): EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: a.lift() + sage: a.lift() # needs sage.libs.singular x - sage: (3/5*(a + a^2 + b^2)).lift() + sage: (3/5*(a + a^2 + b^2)).lift() # needs sage.libs.singular 3/5*x """ return self.__rep def __bool__(self): """ - Return True if quotient ring element is non-zero in the + Return ``True`` if quotient ring element is non-zero in the quotient ring `R/I`, by determining whether the element is in `I`. EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: bool(a) # indirect doctest + sage: bool(a) # indirect doctest # needs sage.libs.singular True - sage: bool(S(0)) + sage: bool(S(0)) # needs sage.libs.singular False TESTS:: - sage: bool(a - a) + sage: bool(a - a) # needs sage.libs.singular False """ return self.__rep not in self.parent().defining_ideal() - - def is_unit(self): """ - Return True if self is a unit in the quotient ring. + Return ``True`` if self is a unit in the quotient ring. EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(1 - x*y); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(1 - x*y); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: a*b + sage: a*b # needs sage.libs.singular 1 - sage: S(2).is_unit() + sage: S(2).is_unit() # needs sage.libs.singular True Check that :trac:`29469` is fixed:: - sage: a.is_unit() + sage: a.is_unit() # needs sage.libs.singular True - sage: (a+b).is_unit() + sage: (a+b).is_unit() # needs sage.libs.singular False """ if self.__rep.is_unit(): @@ -193,16 +195,17 @@ def _repr_(self): TESTS:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: a-2*a*b # indirect doctest + sage: a-2*a*b # indirect doctest # needs sage.libs.singular -2*a*b + a In :trac:`11068`, the case of quotient rings without assigned names has been covered as well:: + sage: # needs sage.libs.singular sage: S = SteenrodAlgebra(2) - sage: I = S*[S.0+S.1]*S + sage: I = S * [S.0 + S.1] * S sage: Q = S.quo(I) sage: Q.0 Sq(1) @@ -234,7 +237,7 @@ def _latex_(self): sage: a = R.gen(0) sage: I = R.ideal(a**2 + a + 1) sage: S = R.quotient(I, names=R.variable_names()) - sage: a = S.gen(0) + sage: a = S.gen(0) # needs sage.libs.singular sage: latex(a) a """ @@ -259,20 +262,20 @@ def __pari__(self): EXAMPLES:: sage: R.<x,y> = QQ[] - sage: I = R.ideal(x^3,y^3) - sage: S.<xb,yb> = R.quo(I) - sage: pari(xb) + sage: I = R.ideal(x^3, y^3) + sage: S.<xb,yb> = R.quo(I) # needs sage.libs.singular + sage: pari(xb) # needs sage.libs.pari sage.libs.singular Traceback (most recent call last): ... ValueError: Pari does not support quotients by non-principal ideals Note that the quotient does work in the case that the ideal is principal:: - sage: I = R.ideal(x^3+y^3) - sage: S.<xb,yb> = R.quo(I) - sage: pari(xb)^4 + sage: I = R.ideal(x^3 + y^3) + sage: S.<xb,yb> = R.quo(I) # needs sage.libs.singular + sage: pari(xb)^4 # needs sage.libs.pari sage.libs.singular Mod(-y^3*x, x^3 + y^3) - sage: pari(yb)^4 + sage: pari(yb)^4 # needs sage.libs.pari sage.libs.singular Mod(y^4, x^3 + y^3) """ gens = self.parent().defining_ideal().gens() @@ -288,14 +291,14 @@ def _add_(self, right): EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: a + b + sage: a + b # needs sage.libs.singular a + b TESTS:: - sage: a._add_(b) + sage: a._add_(b) # needs sage.libs.singular a + b """ return self.__class__(self.parent(), self.__rep + right.__rep) @@ -308,14 +311,14 @@ def _sub_(self, right): EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: a - b + sage: a - b # needs sage.libs.singular a - b TESTS:: - sage: a._sub_(b) + sage: a._sub_(b) # needs sage.libs.singular a - b """ return self.__class__(self.parent(), self.__rep - right.__rep) @@ -328,16 +331,16 @@ def _mul_(self, right): EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: a * b + sage: a * b # needs sage.libs.singular a*b TESTS:: - sage: a._mul_(b) + sage: a._mul_(b) # needs sage.libs.singular a*b - sage: a._mul_(a) + sage: a._mul_(a) # needs sage.libs.singular -b^2 """ return self.__class__(self.parent(), self.__rep * right.__rep) @@ -352,30 +355,30 @@ def _div_(self, right): sage: R.<x,y> = QQ[] sage: I = R.ideal([x^2 + 1, y^3 - 2]) - sage: S.<i,cuberoot> = R.quotient(I) - sage: 1/(1+i) + sage: S.<i,cuberoot> = R.quotient(I) # needs sage.libs.singular + sage: 1/(1+i) # needs sage.libs.singular -1/2*i + 1/2 Confirm via symbolic computation:: - sage: 1/(1+sqrt(-1)) + sage: 1/(1+sqrt(-1)) # needs sage.symbolic -1/2*I + 1/2 Another more complicated quotient:: - sage: b = 1/(i+cuberoot); b + sage: b = 1/(i+cuberoot); b # needs sage.libs.singular 1/5*i*cuberoot^2 - 2/5*i*cuberoot + 2/5*cuberoot^2 - 1/5*i + 1/5*cuberoot - 2/5 - sage: b*(i+cuberoot) + sage: b*(i+cuberoot) # needs sage.libs.singular 1 Another really easy example:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: a / S(2) + sage: a / S(2) # needs sage.libs.singular 1/2*a - sage: (a*b)._div_(b) + sage: (a*b)._div_(b) # needs sage.libs.singular a An example in which we try to divide in a ring that is not a @@ -383,10 +386,10 @@ def _div_(self, right): sage: R.<x,y> = QQ[] sage: I = R.ideal([x^2 - 1, y^3 - 2]) - sage: S.<a,cuberoot> = R.quotient(I) - sage: 1/cuberoot + sage: S.<a,cuberoot> = R.quotient(I) # needs sage.libs.singular + sage: 1/cuberoot # needs sage.libs.singular 1/2*cuberoot^2 - sage: 1/a + sage: 1/a # needs sage.libs.singular a Check that :trac:`13670` is fixed (i.e. that the error message @@ -394,7 +397,7 @@ def _div_(self, right): sage: R.<x1,x2> = QQ[] sage: S = R.quotient_ring( R.ideal(x2**2 + x1 - 2, x1**2 - 1) ) - sage: 1 / S(x1 + x2) + sage: 1 / S(x1 + x2) # needs sage.libs.singular Traceback (most recent call last): ... ArithmeticError: Division failed. The numerator is not a multiple of the denominator. @@ -406,7 +409,7 @@ def _div_(self, right): sage: R.<x> = QQ[] sage: S.<y,z> = R[] - sage: Z.<ybar,zbar> = S.quotient([y^2 - 2, z^2 - 3]) + sage: Z.<ybar,zbar> = S.quotient([y^2 - 2, z^2 - 3]) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: Can only reduce polynomials over fields. @@ -473,6 +476,7 @@ def _im_gens_(self, codomain, im_gens, base_map=None): Ring homomorphisms whose domain is the fraction field of a quotient ring work correctly (see :trac:`16135`):: + sage: # needs sage.libs.singular sage: R.<x, y> = QQ[] sage: K = R.quotient(x^2 - y^3).fraction_field() sage: L.<t> = FunctionField(QQ) @@ -495,6 +499,7 @@ def __int__(self): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> sage: int(S(-3)) # indirect doctest @@ -512,14 +517,14 @@ def _integer_(self, Z): """ EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: ZZ(S(-3)) + sage: ZZ(S(-3)) # needs sage.libs.singular -3 TESTS:: - sage: type(ZZ(S(-3))) + sage: type(ZZ(S(-3))) # needs sage.libs.singular <class 'sage.rings.integer.Integer'> """ return Z(self.lift()) @@ -528,14 +533,14 @@ def _rational_(self): """ EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: QQ(S(-2/3)) + sage: QQ(S(-2/3)) # needs sage.libs.singular -2/3 TESTS:: - sage: type(S(-2/3)._rational_()) + sage: type(S(-2/3)._rational_()) # needs sage.libs.singular <class 'sage.rings.rational.Rational'> """ from sage.rings.rational_field import QQ @@ -545,11 +550,11 @@ def __neg__(self): """ EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: -a # indirect doctest + sage: -a # indirect doctest # needs sage.libs.singular -a - sage: -(a+b) + sage: -(a+b) # needs sage.libs.singular -a - b """ return self.__class__(self.parent(), -self.__rep) @@ -558,11 +563,11 @@ def __pos__(self): """ TESTS:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: (a+b).__pos__() + sage: (a+b).__pos__() # needs sage.libs.singular a + b - sage: c = a+b; c.__pos__() is c + sage: c = a+b; c.__pos__() is c # needs sage.libs.singular True """ return self @@ -571,19 +576,19 @@ def __invert__(self): """ EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: ~S(2/3) + sage: ~S(2/3) # needs sage.libs.singular 3/2 TESTS:: - sage: S(2/3).__invert__() + sage: S(2/3).__invert__() # needs sage.libs.singular 3/2 Note that a is not invertible as an element of R:: - sage: a.__invert__() + sage: a.__invert__() # needs sage.libs.singular Traceback (most recent call last): ... ArithmeticError: element is non-invertible @@ -598,11 +603,11 @@ def __float__(self): """ EXAMPLES:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: float(S(2/3)) + sage: float(S(2/3)) # needs sage.libs.singular 0.6666666666666666 - sage: float(a) + sage: float(a) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: unable to convert non-constant polynomial x to <class 'float'> @@ -613,6 +618,7 @@ def __hash__(self): r""" TESTS:: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ[] sage: S.<a,b> = R.quo(x^2 + y^2) sage: c = a*a + b @@ -625,6 +631,7 @@ def _richcmp_(self, other, op): """ EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> sage: a > b # indirect doctest @@ -636,15 +643,16 @@ def _richcmp_(self, other, op): TESTS:: - sage: a == (a+1-1) + sage: a == (a+1-1) # needs sage.libs.singular True - sage: a > b + sage: a > b # needs sage.libs.singular True See :trac:`7797`:: + sage: # needs sage.combinat sage.libs.singular sage.modules sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') - sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F + sage: I = F * [x*y + y*z, x^2 + x*y - y*x - y^2] * F sage: Q = F.quo(I) sage: Q.0^4 # indirect doctest ybar*zbar*zbar*xbar + ybar*zbar*zbar*ybar + ybar*zbar*zbar*zbar @@ -652,10 +660,11 @@ def _richcmp_(self, other, op): The issue from :trac:`8005` was most likely fixed as part of :trac:`9138`:: + sage: # needs sage.libs.singular sage: F = GF(5) - sage: R.<x,y>=F[] - sage: I=Ideal(R, [x, y]) - sage: S.<x1,y1>=QuotientRing(R,I) + sage: R.<x,y> = F[] + sage: I = Ideal(R, [x, y]) + sage: S.<x1,y1> = QuotientRing(R, I) sage: x1^4 0 """ @@ -679,18 +688,19 @@ def lt(self): EXAMPLES:: - sage: R.<x,y,z>=PolynomialRing(GF(7),3,order='lex') + sage: # needs sage.libs.singular + sage: R.<x,y,z> = PolynomialRing(GF(7), 3, order='lex') sage: I = sage.rings.ideal.FieldIdeal(R) - sage: Q = R.quo( I ) - sage: f = Q( z*y + 2*x ) + sage: Q = R.quo(I) + sage: f = Q(z*y + 2*x) sage: f.lt() 2*xbar TESTS:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: (a+3*a*b+b).lt() + sage: (a + 3*a*b + b).lt() # needs sage.libs.singular 3*a*b """ return self.__class__(self.parent(), self.__rep.lt()) @@ -701,18 +711,19 @@ def lm(self): EXAMPLES:: - sage: R.<x,y,z>=PolynomialRing(GF(7),3,order='lex') + sage: # needs sage.libs.singular + sage: R.<x,y,z> = PolynomialRing(GF(7), 3, order='lex') sage: I = sage.rings.ideal.FieldIdeal(R) - sage: Q = R.quo( I ) - sage: f = Q( z*y + 2*x ) + sage: Q = R.quo(I) + sage: f = Q(z*y + 2*x) sage: f.lm() xbar TESTS:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: (a+3*a*b+b).lm() + sage: (a+3*a*b+b).lm() # needs sage.libs.singular a*b """ @@ -724,18 +735,19 @@ def lc(self): EXAMPLES:: - sage: R.<x,y,z>=PolynomialRing(GF(7),3,order='lex') + sage: # needs sage.libs.singular + sage: R.<x,y,z> = PolynomialRing(GF(7), 3, order='lex') sage: I = sage.rings.ideal.FieldIdeal(R) - sage: Q = R.quo( I ) - sage: f = Q( z*y + 2*x ) + sage: Q = R.quo(I) + sage: f = Q(z*y + 2*x) sage: f.lc() 2 TESTS:: - sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) + sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) # needs sage.libs.singular <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: (a+3*a*b+b).lc() + sage: (a + 3*a*b + b).lc() # needs sage.libs.singular 3 """ return self.__rep.lc() @@ -751,6 +763,7 @@ def variables(self): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> sage: a.variables() @@ -761,7 +774,7 @@ def variables(self): 1 sage: s.variables() () - sage: (a+b).variables() + sage: (a + b).variables() (a, b) """ return tuple(self.__class__(self.parent(), v) for v in self.__rep.variables()) @@ -776,11 +789,12 @@ def monomials(self): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> sage: a.monomials() [a] - sage: (a+a*b).monomials() + sage: (a + a*b).monomials() [a*b, a] sage: R.zero().monomials() [] @@ -798,7 +812,8 @@ def _singular_(self, singular=singular_default): EXAMPLES:: - sage: P.<x,y> = PolynomialRing(GF(2),2) + sage: # needs sage.libs.singular + sage: P.<x,y> = PolynomialRing(GF(2), 2) sage: I = sage.rings.ideal.FieldIdeal(P) sage: Q = P.quo(I) sage: Q._singular_() @@ -820,11 +835,12 @@ def _singular_(self, singular=singular_default): TESTS:: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ[]; S.<a,b> = R.quo(x^2 + y^2); type(a) <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category.element_class'> - sage: (a-2/3*b)._singular_() + sage: (a - 2/3*b)._singular_() x-2/3*y - sage: S((a-2/3*b)._singular_()) + sage: S((a - 2/3*b)._singular_()) a - 2/3*b """ if singular is None: @@ -837,12 +853,13 @@ def _magma_init_(self, magma): EXAMPLES:: + sage: # needs sage.libs.singular sage: P.<x,y> = PolynomialRing(GF(2)) sage: Q = P.quotient(sage.rings.ideal.FieldIdeal(P)) sage: xbar, ybar = Q.gens() - sage: magma(xbar) # optional -- magma + sage: magma(xbar) # optional - magma x - sage: xbar._magma_init_(magma) # optional -- magma + sage: xbar._magma_init_(magma) # optional - magma '_sage_[...]!_sage_ref...' """ g = magma(self.__rep) @@ -855,19 +872,20 @@ def _macaulay2_(self, macaulay2=None): EXAMPLES:: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(GF(7), 2) sage: Q = R.quotient([x^2 - y]) sage: x, y = Q.gens() sage: f = (x^3 + 2*y^2*x)^7; f 2*xbar*ybar^17 + xbar*ybar^10 - sage: mf = macaulay2(f); mf # optional - macaulay2 + sage: mf = macaulay2(f); mf # optional - macaulay2 17 10 2x*y + x*y - sage: mf.sage() # optional - macaulay2 + sage: mf.sage() # optional - macaulay2 2*x*y^17 + x*y^10 - sage: mf.sage() == f # optional - macaulay2 + sage: mf.sage() == f # optional - macaulay2 True - sage: Q(mf) # optional - macaulay2 + sage: Q(mf) # optional - macaulay2 2*xbar*ybar^17 + xbar*ybar^10 In Macaulay2, the variable names for a quotient ring are inherited from @@ -879,15 +897,16 @@ def _macaulay2_(self, macaulay2=None): :: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(GF(7), 2) sage: Q = R.quotient([x^2 - y], names=R.gens()) sage: x, y = Q.gens() sage: f = (x^3 + 2*y^2*x)^7; f 2*x*y^17 + x*y^10 - sage: macaulay2(f) # optional - macaulay2 + sage: macaulay2(f) # optional - macaulay2 17 10 2x*y + x*y - sage: _.sage() # optional - macaulay2 + sage: _.sage() # optional - macaulay2 2*x*y^17 + x*y^10 TESTS: @@ -895,15 +914,16 @@ def _macaulay2_(self, macaulay2=None): Check that changing the currently defined global variables (`x`, `y`, ...) in Macaulay2 does not affect the result of this conversion:: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(GF(7), 2) sage: Q = R.quotient([x^2 - y], names=R.gens()) sage: x, y = Q.gens() sage: f = (x^3 + 2*y^2*x)^7 - sage: macaulay2(f) # optional - macaulay2 + sage: macaulay2(f) # optional - macaulay2 17 10 2x*y + x*y - sage: macaulay2.use(R.quotient([x, y])) # optional - macaulay2 - sage: macaulay2(f) # optional - macaulay2 + sage: macaulay2.use(R.quotient([x, y])) # optional - macaulay2 + sage: macaulay2(f) # optional - macaulay2 17 10 2x*y + x*y """ @@ -932,9 +952,11 @@ def reduce(self, G): EXAMPLES:: + sage: # needs sage.libs.singular sage: P.<a,b,c,d,e> = PolynomialRing(GF(2), 5, order='lex') - sage: I1 = ideal([a*b + c*d + 1, a*c*e + d*e, a*b*e + c*e, b*c + c*d*e + 1]) - sage: Q = P.quotient( sage.rings.ideal.FieldIdeal(P) ) + sage: I1 = ideal([a*b + c*d + 1, a*c*e + d*e, + ....: a*b*e + c*e, b*c + c*d*e + 1]) + sage: Q = P.quotient(sage.rings.ideal.FieldIdeal(P)) sage: I2 = ideal([Q(f) for f in I1.gens()]) sage: f = Q((a*b + c*d + 1)^2 + e) sage: f.reduce(I2.gens()) @@ -942,7 +964,7 @@ def reduce(self, G): Notice that the result above is not minimal:: - sage: I2.reduce(f) + sage: I2.reduce(f) # needs sage.libs.singular 0 """ try: diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 72ee560677c..f8843a2cee7 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -65,11 +65,9 @@ from cysignals.signals cimport sig_on, sig_off import operator import fractions -from sage.arith.long cimport pyobject_to_long, integer_check_long_py +from sage.arith.long cimport integer_check_long_py from sage.cpython.string cimport char_to_str, str_to_bytes -import sage.misc.misc as misc -from sage.structure.sage_object cimport SageObject from sage.structure.richcmp cimport rich_to_bool_sgn import sage.rings.rational_field @@ -77,7 +75,6 @@ cimport sage.rings.integer as integer from .integer cimport Integer from .integer_ring import ZZ -from sage.arith.rational_reconstruction cimport mpq_rational_reconstruction from sage.structure.coerce cimport is_numpy_type @@ -85,22 +82,18 @@ from sage.libs.gmp.pylong cimport mpz_set_pylong from sage.structure.coerce cimport coercion_model from sage.structure.element cimport Element -from sage.structure.element import coerce_binop from sage.structure.parent cimport Parent from sage.categories.morphism cimport Morphism from sage.categories.map cimport Map - import sage.rings.real_mpfr import sage.rings.real_double from libc.stdint cimport uint64_t from sage.libs.gmp.binop cimport mpq_add_z, mpq_mul_z, mpq_div_zz -from cpython.int cimport PyInt_AS_LONG - cimport sage.rings.fast_arith -import sage.rings.fast_arith +import sage.rings.fast_arith try: @@ -300,30 +293,33 @@ cpdef rational_power_parts(a, Rational b, factor_limit=10**5): sage: rational_power_parts(3/4, -1/2) (2, 3) - sage: t = (3/4)^(-1/2); t + sage: t = (3/4)^(-1/2); t # needs sage.symbolic 2/3*sqrt(3) - sage: t^2 + sage: t^2 # needs sage.symbolic 4/3 Check if :trac:`15605` is fixed:: sage: rational_power_parts(-1, -1/3) (1, -1) + sage: rational_power_parts(-1, 2/3) + (1, -1) + sage: all(rational_power_parts(-1, i/77) == (1,-1) for i in range(1,9)) + True + + sage: # needs sage.symbolic sage: (-1)^(-1/3) -(-1)^(2/3) sage: 1 / ((-1)^(1/3)) -(-1)^(2/3) - sage: rational_power_parts(-1, 2/3) - (1, -1) sage: (-1)^(2/3) (-1)^(2/3) - sage: all(rational_power_parts(-1, i/77) == (1,-1) for i in range(1,9)) - True sage: (-1)^(1/3)*(-1)^(1/5) (-1)^(8/15) sage: bool((-1)^(2/3) == -1/2 + sqrt(3)/2*I) True - sage: all((-1)^(p/q) == cos(p*pi/q) + I * sin(p*pi/q) for p in srange(1,6) for q in srange(1,6)) + sage: all((-1)^(p/q) == cos(p*pi/q) + I * sin(p*pi/q) + ....: for p in srange(1, 6) for q in srange(1, 6)) True A few more tests added in :trac:`26414`:: @@ -380,7 +376,7 @@ cpdef rational_power_parts(a, Rational b, factor_limit=10**5): def is_Rational(x): """ - Return true if x is of the Sage rational number type. + Return ``True`` if ``x`` is of the Sage :class:`Rational` type. EXAMPLES:: @@ -422,9 +418,10 @@ cdef class Rational(sage.structure.element.FieldElement): 1/2 sage: Rational(("2", "10"), 16) 1/8 - sage: Rational(QQbar(125/8).nth_root(3)) + sage: Rational(QQbar(125/8).nth_root(3)) # needs sage.rings.number_field 5/2 - sage: Rational(AA(209735/343 - 17910/49*golden_ratio).nth_root(3) + 3*AA(golden_ratio)) + sage: Rational(AA(209735/343 - 17910/49*golden_ratio).nth_root(3) # needs sage.rings.number_field sage.symbolic + ....: + 3*AA(golden_ratio)) 53/7 sage: QQ(float(1.5)) 3/2 @@ -440,13 +437,14 @@ cdef class Rational(sage.structure.element.FieldElement): Conversion from PARI:: - sage: Rational(pari('-939082/3992923')) + sage: Rational(pari('-939082/3992923')) # needs sage.libs.pari -939082/3992923 - sage: Rational(pari('Pol([-1/2])')) #9595 + sage: Rational(pari('Pol([-1/2])')) #9595 # needs sage.libs.pari -1/2 Conversions from numpy:: + sage: # needs numpy sage: import numpy as np sage: QQ(np.int8('-15')) -15 @@ -457,7 +455,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: QQ(np.uint32('1412')) 1412 - sage: QQ(np.float16('12')) + sage: QQ(np.float16('12')) # needs numpy 12 Conversions from gmpy2:: @@ -512,7 +510,7 @@ cdef class Rational(sage.structure.element.FieldElement): 7 sage: a.__init__('70', base=8); a 56 - sage: a.__init__(pari('2/3')); a + sage: a.__init__(pari('2/3')); a # needs sage.libs.pari 2/3 sage: a.__init__('-h/3ki', 32); a -17/3730 @@ -723,7 +721,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: 1 + 1/(2 + 1/(3 + 1/(4 + 1/5))) 225/157 - sage: (fibonacci(20)/fibonacci(19)).continued_fraction_list() + sage: (fibonacci(20)/fibonacci(19)).continued_fraction_list() # needs sage.libs.pari [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2] sage: (-1/3).continued_fraction_list() @@ -810,9 +808,9 @@ cdef class Rational(sage.structure.element.FieldElement): sage: a = (355/113).continued_fraction(); a [3; 7, 16] - sage: a.n(digits=10) + sage: a.n(digits=10) # needs sage.rings.real_mpfr 3.141592920 - sage: pi.n(digits=10) + sage: pi.n(digits=10) # needs sage.rings.real_mpfr sage.symbolic 3.141592654 It's almost pi! @@ -918,7 +916,7 @@ cdef class Rational(sage.structure.element.FieldElement): # immutable return self - def __dealloc__(self): + def __dealloc__(self): """ Free memory occupied by this rational number. @@ -963,9 +961,9 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: - sage: ex = SR(QQ(7)/3); ex + sage: ex = SR(QQ(7)/3); ex # needs sage.symbolic 7/3 - sage: parent(ex) + sage: parent(ex) # needs sage.symbolic Symbolic Ring """ return sring._force_pyobject(self, force=True) @@ -976,12 +974,13 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: + sage: # needs sympy sage: n = 1/2; n._sympy_() 1/2 sage: n = -1/5; n._sympy_() -1/5 sage: from sympy import Symbol - sage: QQ(1)+Symbol('x')*QQ(2) + sage: QQ(1) + Symbol('x')*QQ(2) 2*x + 1 """ import sympy @@ -1035,7 +1034,7 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: sage: n = -485/82847 - sage: n._magma_init_(magma) # optional - magma + sage: n._magma_init_(magma) # optional - magma '-485/82847' """ return self.numerator()._magma_init_(magma) + '/' + self.denominator()._magma_init_(magma) @@ -1049,15 +1048,14 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: + sage: # needs numpy sage: import numpy sage: numpy.array([1, 2, 3/1]) array([1, 2, 3]) - sage: numpy.array(QQ(2**40)).dtype dtype('int64') sage: numpy.array(QQ(2**400)).dtype dtype('O') - sage: numpy.array([1, 1/2, 3/4]) array([1. , 0.5 , 0.75]) """ @@ -1114,7 +1112,7 @@ cdef class Rational(sage.structure.element.FieldElement): def content(self, other): """ - Return the content of ``self`` and ``other``, i.e. the unique positive + Return the content of ``self`` and ``other``, i.e., the unique positive rational number `c` such that ``self/c`` and ``other/c`` are coprime integers. @@ -1191,7 +1189,7 @@ cdef class Rational(sage.structure.element.FieldElement): - ``p`` -- a prime number - ``prec`` (int) -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). OUTPUT: @@ -1201,11 +1199,11 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: sage: a = QQ(25/6) - sage: a.local_height(2) + sage: a.local_height(2) # needs sage.rings.real_mpfr 0.693147180559945 - sage: a.local_height(3) + sage: a.local_height(3) # needs sage.rings.real_mpfr 1.09861228866811 - sage: a.local_height(5) + sage: a.local_height(5) # needs sage.rings.real_mpfr 0.000000000000000 """ from sage.rings.real_mpfr import RealField @@ -1228,7 +1226,7 @@ cdef class Rational(sage.structure.element.FieldElement): INPUT: - ``prec`` (int) -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). OUTPUT: @@ -1239,11 +1237,11 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: sage: a = QQ(6/25) - sage: a.local_height_arch() + sage: a.local_height_arch() # needs sage.rings.real_mpfr 0.000000000000000 - sage: (1/a).local_height_arch() + sage: (1/a).local_height_arch() # needs sage.rings.real_mpfr 1.42711635564015 - sage: (1/a).local_height_arch(100) + sage: (1/a).local_height_arch(100) # needs sage.rings.real_mpfr 1.4271163556401457483890413081 """ from sage.rings.real_mpfr import RealField @@ -1264,7 +1262,7 @@ cdef class Rational(sage.structure.element.FieldElement): INPUT: - ``prec`` (int) -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). OUTPUT: @@ -1282,11 +1280,11 @@ cdef class Rational(sage.structure.element.FieldElement): sage: a = QQ(5/6) sage: a.support() [2, 3, 5] - sage: a.global_height_non_arch() + sage: a.global_height_non_arch() # needs sage.rings.real_mpfr 1.79175946922805 - sage: [a.local_height(p) for p in a.support()] + sage: [a.local_height(p) for p in a.support()] # needs sage.rings.real_mpfr [0.693147180559945, 1.09861228866811, 0.000000000000000] - sage: sum([a.local_height(p) for p in a.support()]) + sage: sum([a.local_height(p) for p in a.support()]) # needs sage.rings.real_mpfr 1.79175946922805 """ from sage.rings.real_mpfr import RealField @@ -1307,7 +1305,7 @@ cdef class Rational(sage.structure.element.FieldElement): INPUT: - ``prec`` (int) -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). OUTPUT: @@ -1323,11 +1321,11 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: sage: a = QQ(6/25) - sage: a.global_height_arch() + sage: a.global_height_arch() # needs sage.rings.real_mpfr 0.000000000000000 - sage: (1/a).global_height_arch() + sage: (1/a).global_height_arch() # needs sage.rings.real_mpfr 1.42711635564015 - sage: (1/a).global_height_arch(100) + sage: (1/a).global_height_arch(100) # needs sage.rings.real_mpfr 1.4271163556401457483890413081 """ return self.local_height_arch(prec) @@ -1339,7 +1337,7 @@ cdef class Rational(sage.structure.element.FieldElement): INPUT: - ``prec`` (int) -- desired floating point precision (default: - default RealField precision). + default :class:`RealField` precision). OUTPUT: @@ -1354,6 +1352,7 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: a = QQ(6/25) sage: a.global_height_arch() + a.global_height_non_arch() 3.21887582486820 @@ -1402,11 +1401,11 @@ cdef class Rational(sage.structure.element.FieldElement): INPUT: - - ``L`` -- a number field - - ``element`` -- (default: ``False``) boolean whether to also output - an element of which ``self`` is a norm - - proof -- If ``True``, then the output is correct unconditionally. - If ``False``, then the output assumes GRH. + - ``L`` -- a number field + - ``element`` -- (default: ``False``) boolean whether to also output + an element of which ``self`` is a norm + - ``proof`` -- If ``True``, then the output is correct unconditionally. + If ``False``, then the output assumes GRH. OUTPUT: @@ -1418,10 +1417,12 @@ cdef class Rational(sage.structure.element.FieldElement): ALGORITHM: - Uses PARI's bnfisnorm. See ``_bnfisnorm()``. + Uses the PARI function :pari:`bnfisnorm`. See :meth:`_bnfisnorm()`. EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(QQ, 'x') sage: K = NumberField(x^2 - 2, 'beta') sage: (1/7).is_norm(K) True @@ -1439,24 +1440,25 @@ cdef class Rational(sage.structure.element.FieldElement): The number field doesn't have to be defined by an integral polynomial:: - sage: B, e = (1/5).is_norm(QuadraticField(5/4, 'a'), element=True) - sage: B + sage: B, e = (1/5).is_norm(QuadraticField(5/4, 'a'), element=True) # needs sage.rings.number_field + sage: B # needs sage.rings.number_field True - sage: e.norm() + sage: e.norm() # needs sage.rings.number_field 1/5 A non-Galois number field:: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^3 - 2) sage: B, e = (3/5).is_norm(K, element=True); B True sage: e.norm() 3/5 - sage: 7.is_norm(K) Traceback (most recent call last): ... - NotImplementedError: is_norm is not implemented unconditionally for norms from non-Galois number fields + NotImplementedError: is_norm is not implemented unconditionally + for norms from non-Galois number fields sage: 7.is_norm(K, proof=False) False @@ -1469,8 +1471,8 @@ cdef class Rational(sage.structure.element.FieldElement): if not element: return self.is_norm(L, element=True, proof=proof)[0] - from sage.rings.number_field.number_field_base import is_NumberField - if not is_NumberField(L): + from sage.rings.number_field.number_field_base import NumberField + if not isinstance(L, NumberField): raise ValueError("L (=%s) must be a NumberField in is_norm" % L) if L.degree() == 1 or self.is_zero(): return True, L(self) @@ -1540,9 +1542,10 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: - sage: QQ(2)._bnfisnorm(QuadraticField(-1, 'i')) + sage: QQ(2)._bnfisnorm(QuadraticField(-1, 'i')) # needs sage.rings.number_field (i + 1, 1) - sage: 7._bnfisnorm(NumberField(x^3-2, 'b')) + sage: x = polygen(QQ, 'x') + sage: 7._bnfisnorm(NumberField(x^3 - 2, 'b')) # needs sage.rings.number_field (1, 7) AUTHORS: @@ -1551,8 +1554,8 @@ cdef class Rational(sage.structure.element.FieldElement): - Marco Streng (2010-12-03) """ - from sage.rings.number_field.number_field_base import is_NumberField - if not is_NumberField(K): + from sage.rings.number_field.number_field_base import NumberField + if not isinstance(K, NumberField): raise ValueError("K must be a NumberField in bnfisnorm") a, b = K.pari_bnf(proof=proof).bnfisnorm(self, flag=extra_primes) @@ -1609,9 +1612,9 @@ cdef class Rational(sage.structure.element.FieldElement): This test makes sure we workaround a bug in GMP (see :trac:`4612`):: - sage: [ -a for a in srange(100) if not QQ(-a^3).is_perfect_power() ] + sage: [-a for a in srange(100) if not QQ(-a^3).is_perfect_power()] [] - sage: [ -a for a in srange(100) if not QQ(-a^3).is_perfect_power(True) ] + sage: [-a for a in srange(100) if not QQ(-a^3).is_perfect_power(True)] [] """ cdef int s @@ -1694,7 +1697,7 @@ cdef class Rational(sage.structure.element.FieldElement): def squarefree_part(self): """ - Return the square free part of `x`, i.e., an integer z such + Return the square free part of `x`, i.e., an integer `z` such that `x = z y^2`, for a perfect square `y^2`. EXAMPLES:: @@ -1901,17 +1904,19 @@ cdef class Rational(sage.structure.element.FieldElement): sage: x.sqrt(all=True) [10, -10] sage: x = 81/5 - sage: x.sqrt() + sage: x.sqrt() # needs sage.symbolic 9*sqrt(1/5) sage: x = -81/3 - sage: x.sqrt() + sage: x.sqrt() # needs sage.symbolic 3*sqrt(-3) :: sage: n = 2/3 - sage: n.sqrt() + sage: n.sqrt() # needs sage.symbolic sqrt(2/3) + + sage: # needs sage.rings.real_mpfr sage: n.sqrt(prec=10) 0.82 sage: n.sqrt(prec=100) @@ -1920,16 +1925,17 @@ cdef class Rational(sage.structure.element.FieldElement): 0.66666666666666666666666666667 sage: n.sqrt(prec=53, all=True) [0.816496580927726, -0.816496580927726] + sage: sqrt(-2/3, prec=53) + 0.816496580927726*I + sage: sqrt(-2/3, prec=53, all=True) + [0.816496580927726*I, -0.816496580927726*I] + sage: n.sqrt(extend=False, all=True) Traceback (most recent call last): ... ValueError: square root of 2/3 not a rational number - sage: sqrt(-2/3, all=True) + sage: sqrt(-2/3, all=True) # needs sage.symbolic [sqrt(-2/3), -sqrt(-2/3)] - sage: sqrt(-2/3, prec=53) - 0.816496580927726*I - sage: sqrt(-2/3, prec=53, all=True) - [0.816496580927726*I, -0.816496580927726*I] AUTHORS: @@ -1990,22 +1996,22 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: - sage: (1/7).period() + sage: (1/7).period() # needs sage.libs.pari 6 - sage: RR(1/7) + sage: RR(1/7) # needs sage.rings.real_mpfr 0.142857142857143 - sage: (1/8).period() + sage: (1/8).period() # needs sage.libs.pari 1 - sage: RR(1/8) + sage: RR(1/8) # needs sage.rings.real_mpfr 0.125000000000000 - sage: RR(1/6) + sage: RR(1/6) # needs sage.rings.real_mpfr 0.166666666666667 - sage: (1/6).period() + sage: (1/6).period() # needs sage.libs.pari 1 sage: x = 333/106 - sage: x.period() + sage: x.period() # needs sage.libs.pari 13 - sage: RealField(200)(x) + sage: RealField(200)(x) # needs sage.rings.real_mpfr 3.1415094339622641509433962264150943396226415094339622641509 """ cdef unsigned int alpha, beta @@ -2022,7 +2028,7 @@ cdef class Rational(sage.structure.element.FieldElement): INPUT: - - ``n`` - integer (must fit in C int type) + - ``n`` - integer (must fit in C ``int`` type) AUTHORS: @@ -2085,7 +2091,7 @@ cdef class Rational(sage.structure.element.FieldElement): INPUT: - - ``n`` - integer (must fit in C int type) + - ``n`` - integer (must fit in C ``int`` type) .. NOTE:: @@ -2200,22 +2206,22 @@ cdef class Rational(sage.structure.element.FieldElement): Test that the conversion has correct rounding on simple rationals:: - sage: for p in [-100..100]: + sage: for p in [-100..100]: # needs sage.rings.real_mpfr ....: for q in [1..100]: ....: r = RDF(p/q) ....: assert (RR(r).exact_rational() - p/q) <= r.ulp()/2 Test larger rationals:: - sage: Q = continued_fraction(pi).convergents()[:100] + sage: Q = continued_fraction(pi).convergents()[:100] # needs sage.symbolic sage: all(RDF(q) == RR(q) for q in Q) True At some point, the continued fraction and direct conversion to ``RDF`` should agree:: - sage: RDFpi = RDF(pi) - sage: all(RDF(q) == RDFpi for q in Q[20:]) + sage: RDFpi = RDF(pi) # needs sage.symbolic + sage: all(RDF(q) == RDFpi for q in Q[20:]) # needs sage.symbolic True """ return mpq_get_d_nearest(self.value) @@ -2515,9 +2521,9 @@ cdef class Rational(sage.structure.element.FieldElement): sage: (2/3)^5 32/243 - sage: (-1/1)^(1/3) + sage: (-1/1)^(1/3) # needs sage.symbolic (-1)^(1/3) - sage: (2/3)^(3/4) + sage: (2/3)^(3/4) # needs sage.symbolic (2/3)^(3/4) sage: (-1/3)^0 1 @@ -2532,18 +2538,18 @@ cdef class Rational(sage.structure.element.FieldElement): 2/3 sage: parent(a) Rational Field - sage: (-27/125)^(1/3) + sage: (-27/125)^(1/3) # needs sage.symbolic 3/5*(-1)^(1/3) - sage: (-27/125)^(1/2) + sage: (-27/125)^(1/2) # needs sage.symbolic 3/5*sqrt(-3/5) The result is normalized to have the rational power in the numerator:: - sage: 2^(-1/2) + sage: 2^(-1/2) # needs sage.symbolic 1/2*sqrt(2) - sage: 8^(-1/5) + sage: 8^(-1/5) # needs sage.symbolic 1/8*8^(4/5) - sage: 3^(-3/2) + sage: 3^(-3/2) # needs sage.symbolic 1/9*sqrt(3) TESTS:: @@ -2555,14 +2561,14 @@ cdef class Rational(sage.structure.element.FieldElement): This works even if the base is a Python integer:: - sage: int(2)^(1/2) + sage: int(2)^(1/2) # needs sage.symbolic sqrt(2) sage: a = int(2)^(3/1); a 8 sage: type(a) <class 'sage.rings.rational.Rational'> - The exponent must fit in a long unless the base is -1, 0, or 1:: + The exponent must fit in a ``long`` unless the base is -1, 0, or 1:: sage: (1/2)^(2^100) Traceback (most recent call last): @@ -2574,7 +2580,7 @@ cdef class Rational(sage.structure.element.FieldElement): ... OverflowError: exponent must be at most 2147483647 # 32-bit OverflowError: exponent must be at most 9223372036854775807 # 64-bit - sage: QQ(-1)^(2^100) + sage: QQ(-1)^(2^100) # needs sage.symbolic 1 """ n = <Rational?>other @@ -2821,7 +2827,7 @@ cdef class Rational(sage.structure.element.FieldElement): def norm(self): r""" Return the norm from `\QQ` to `\QQ` of `x` (which is just `x`). This - was added for compatibility with :class:`NumberFields`. + was added for compatibility with :class:`NumberField`. OUTPUT: @@ -2904,7 +2910,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: (1/3).charpoly('x') x - 1/3 - The default is var='x'. (:trac:`20967`):: + The default is ``var='x'``. (:trac:`20967`):: sage: a = QQ(2); a.charpoly('x') x - 2 @@ -2968,7 +2974,7 @@ cdef class Rational(sage.structure.element.FieldElement): def numerator(self): """ Return the numerator of this rational number. - numer is an alias of numerator. + :meth:`numer` is an alias of :meth:`numerator`. EXAMPLES:: @@ -3018,7 +3024,7 @@ cdef class Rational(sage.structure.element.FieldElement): def denominator(self): """ Return the denominator of this rational number. - denom is an alias of denominator. + :meth:`denom` is an alias of :meth:`denominator`. EXAMPLES:: @@ -3121,15 +3127,15 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: - sage: (124/345).log(5) + sage: (124/345).log(5) # needs sage.symbolic log(124/345)/log(5) - sage: (124/345).log(5,100) + sage: (124/345).log(5, 100) # needs sage.rings.real_mpfr -0.63578895682825611710391773754 - sage: log(QQ(125)) + sage: log(QQ(125)) # needs sage.symbolic 3*log(5) sage: log(QQ(125), 5) 3 - sage: log(QQ(125), 3) + sage: log(QQ(125), 3) # needs sage.symbolic 3*log(5)/log(3) sage: QQ(8).log(1/2) -3 @@ -3139,24 +3145,24 @@ cdef class Rational(sage.structure.element.FieldElement): 1/3 sage: (1/2).log(8) -1/3 - sage: (16/81).log(8/27) + sage: (16/81).log(8/27) # needs sage.libs.pari 4/3 - sage: (8/27).log(16/81) + sage: (8/27).log(16/81) # needs sage.libs.pari 3/4 - sage: log(27/8, 16/81) + sage: log(27/8, 16/81) # needs sage.libs.pari -3/4 - sage: log(16/81, 27/8) + sage: log(16/81, 27/8) # needs sage.libs.pari -4/3 - sage: (125/8).log(5/2) + sage: (125/8).log(5/2) # needs sage.libs.pari 3 - sage: (125/8).log(5/2,prec=53) + sage: (125/8).log(5/2, prec=53) # needs sage.rings.real_mpfr 3.00000000000000 TESTS:: - sage: (25/2).log(5/2) + sage: (25/2).log(5/2) # needs sage.symbolic log(25/2)/log(5/2) - sage: (-1/2).log(3) + sage: (-1/2).log(3) # needs sage.symbolic (I*pi + log(1/2))/log(3) """ cdef int self_sgn @@ -3225,6 +3231,7 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: + sage: # needs sage.symbolic sage: gamma(1/2) sqrt(pi) sage: gamma(7/2) @@ -3238,9 +3245,9 @@ cdef class Rational(sage.structure.element.FieldElement): This function accepts an optional precision argument:: - sage: (1/3).gamma(prec=100) + sage: (1/3).gamma(prec=100) # needs sage.rings.real_mpfr 2.6789385347077476336556929410 - sage: (1/2).gamma(prec=100) + sage: (1/2).gamma(prec=100) # needs sage.rings.real_mpfr 1.7724538509055160272981674833 TESTS: @@ -3338,10 +3345,11 @@ cdef class Rational(sage.structure.element.FieldElement): mpz_tdiv_q(n.value, mpq_numref(self.value), mpq_denref(self.value)) return n - def round(Rational self, mode="away"): + def round(Rational self, mode=None): """ - Return the nearest integer to ``self``, rounding away from 0 by - default, for consistency with the builtin Python round. + Return the nearest integer to ``self``, rounding away by default. + Deprecation: in the future the default will be changed to rounding to + even, for consistency with the builtin Python :func:`round`. INPUT: @@ -3356,12 +3364,13 @@ cdef class Rational(sage.structure.element.FieldElement): - 'even' rounds toward the even integer - 'odd' rounds toward the odd integer - OUTPUT: Integer EXAMPLES:: sage: (9/2).round() + doctest:...: DeprecationWarning: the default rounding for rationals, currently `away`, will be changed to `even`. + See https://github.com/sagemath/sage/issues/35473 for details. 5 sage: n = 4/3; n.round() 1 @@ -3380,6 +3389,12 @@ cdef class Rational(sage.structure.element.FieldElement): sage: n.round("odd") -3 """ + if mode is None: + if self.denominator() == 2: + from sage.misc.superseded import deprecation + deprecation(35473, + "the default rounding for rationals, currently `away`, will be changed to `even`.") + mode = "away" if not (mode in ['toward', 'away', 'up', 'down', 'even', 'odd']): raise ValueError("rounding mode must be one of 'toward', 'away', 'up', 'down', 'even', or 'odd'") if self.denominator() == 1: @@ -3554,7 +3569,7 @@ cdef class Rational(sage.structure.element.FieldElement): def is_integral(self): r""" - Determine if a rational number is integral (i.e is in + Determine if a rational number is integral (i.e., is in `\ZZ`). OUTPUT: bool @@ -3768,11 +3783,11 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: sage: n = 9390823/17 - sage: m = n.__pari__(); m + sage: m = n.__pari__(); m # needs sage.libs.pari 9390823/17 - sage: type(m) + sage: type(m) # needs sage.libs.pari <class 'cypari2.gen.Gen'> - sage: m.type() + sage: m.type() # needs sage.libs.pari 't_FRAC' """ global new_gen_from_rational @@ -4124,7 +4139,8 @@ cdef class Z_to_Q(Morphism): maps (see :trac:`15618`):: sage: f.parent() - Set of Morphisms from Rational Field to Integer Ring in Category of sets with partial maps + Set of Morphisms from Rational Field to Integer Ring + in Category of sets with partial maps """ from sage.categories.sets_with_partial_maps import SetsWithPartialMaps return Q_to_Z(self._codomain.Hom(self.domain(), category=SetsWithPartialMaps())) @@ -4186,7 +4202,7 @@ cdef class Q_to_Z(Map): cdef class int_to_Q(Morphism): r""" - A morphism from Python 2 ``int`` to `\QQ`. + A morphism from Python 3 ``int`` to `\QQ`. """ def __init__(self): """ @@ -4202,57 +4218,6 @@ cdef class int_to_Q(Morphism): from . import rational_field import sage.categories.homset from sage.sets.pythonclass import Set_PythonType - Morphism.__init__(self, sage.categories.homset.Hom(Set_PythonType(int), rational_field.QQ)) - - cpdef Element _call_(self, a): - """ - Return the image of the morphism on ``a``. - - EXAMPLES:: - - sage: f = sage.rings.rational.int_to_Q() - sage: f(int(4)) # indirect doctest - 4 - """ - cdef Rational rat - - if type(a) is not int: - raise TypeError("must be a Python int object") - - rat = <Rational> Rational.__new__(Rational) - mpq_set_si(rat.value, PyInt_AS_LONG(a), 1) - return rat - - def _repr_type(self): - """ - Return string that describes the type of morphism. - - EXAMPLES:: - - sage: sage.rings.rational.int_to_Q()._repr_type() - 'Native' - """ - return "Native" - - -cdef class long_to_Q(Morphism): - r""" - A morphism from Python 2 ``long``/Python 3 ``int`` to `\QQ`. - """ - def __init__(self): - """ - Initialize ``self``. - - EXAMPLES:: - - sage: sage.rings.rational.long_to_Q() - Native morphism: - From: Set of Python objects of class 'int' - To: Rational Field - """ - from . import rational_field - import sage.categories.homset - from sage.sets.pythonclass import Set_PythonType Morphism.__init__(self, sage.categories.homset.Hom( Set_PythonType(long), rational_field.QQ)) @@ -4262,7 +4227,7 @@ cdef class long_to_Q(Morphism): EXAMPLES:: - sage: f = sage.rings.rational.long_to_Q() + sage: f = sage.rings.rational.int_to_Q() sage: f(4^100) 1606938044258990275541962092341162602522202993782792835301376 """ @@ -4288,7 +4253,7 @@ cdef class long_to_Q(Morphism): EXAMPLES:: - sage: sage.rings.rational.long_to_Q()._repr_type() + sage: sage.rings.rational.int_to_Q()._repr_type() 'Native' """ return "Native" diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 28a4d3b65c0..104c5463bf5 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -11,22 +11,22 @@ Rational Field Values of various types can be converted to rational numbers by using the -``__call__`` method of ``RationalField`` (that is, by treating ``QQ`` as a +:meth:`__call__` method of :class:`RationalField` (that is, by treating ``QQ`` as a function). :: - sage: RealField(9).pi() + sage: RealField(9).pi() # needs sage.rings.real_mpfr 3.1 - sage: QQ(RealField(9).pi()) + sage: QQ(RealField(9).pi()) # needs sage.rings.real_mpfr 22/7 - sage: QQ(RealField().pi()) + sage: QQ(RealField().pi()) # needs sage.rings.real_mpfr 245850922/78256779 sage: QQ(35) 35 sage: QQ('12/347') 12/347 - sage: QQ(exp(pi*I)) + sage: QQ(exp(pi*I)) # needs sage.symbolic -1 sage: x = polygen(ZZ) sage: QQ((3*x)/(4*x)) @@ -86,7 +86,7 @@ class RationalField(Singleton, number_field_base.NumberField): -930482/9320842317 sage: QQ([9320842317]) 9320842317 - sage: QQ(pari(39029384023840928309482842098430284398243982394)) + sage: QQ(pari(39029384023840928309482842098430284398243982394)) # needs sage.libs.pari 39029384023840928309482842098430284398243982394 sage: QQ('sage') Traceback (most recent call last): @@ -102,14 +102,15 @@ class RationalField(Singleton, number_field_base.NumberField): 3929329/32 sage: QQ(-RR(3929329/32)) -3929329/32 - sage: QQ(RR(1/7)) - 1/7 + sage: QQ(RR(1/7)) - 1/7 # needs sage.rings.real_mpfr 0 - If you specify an optional second base argument, then the string + If you specify the optional second argument ``base``, then the string representation of the float is used. :: + sage: # needs sage.rings.real_mpfr sage: QQ(23.2, 2) 6530219459687219/281474976710656 sage: 6530219459687219.0/281474976710656 @@ -121,6 +122,7 @@ class RationalField(Singleton, number_field_base.NumberField): Here's a nice example involving elliptic curves:: + sage: # needs sage.rings.real_mpfr sage.schemes sage: E = EllipticCurve('11a') sage: L = E.lseries().at1(300)[0]; L 0.2538418608559106843377589233... @@ -304,7 +306,7 @@ def __len__(self): def construction(self): r""" - Returns a pair ``(functor, parent)`` such that ``functor(parent)`` + Return a pair ``(functor, parent)`` such that ``functor(parent)`` returns ``self``. This is the construction of `\QQ` as the fraction field of `\ZZ`. @@ -318,15 +320,15 @@ def construction(self): from . import integer_ring return FractionField(), integer_ring.ZZ - def completion(self, p, prec, extras = {}): + def completion(self, p, prec, extras={}): r""" Return the completion of `\QQ` at `p`. EXAMPLES:: - sage: QQ.completion(infinity, 53) + sage: QQ.completion(infinity, 53) # needs sage.rings.real_mpfr Real Field with 53 bits of precision - sage: QQ.completion(5, 15, {'print_mode': 'bars'}) + sage: QQ.completion(5, 15, {'print_mode': 'bars'}) # needs sage.rings.padics 5-adic Field with capped relative precision 15 """ from sage.rings.infinity import Infinity @@ -374,7 +376,7 @@ def _coerce_map_from_(self, S): if S is ZZ: return rational.Z_to_Q() elif S is int: - return rational.long_to_Q() + return rational.int_to_Q() elif ZZ.has_coerce_map_from(S): return rational.Z_to_Q() * ZZ._internal_coerce_map_from(S) from sage.rings.localization import Localization @@ -383,7 +385,6 @@ def _coerce_map_from_(self, S): from sage.structure.coerce_maps import CallableConvertMap return CallableConvertMap(S, self, lambda x: x._value, parent_as_first_arg=False) - def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): """ Check to see if the map into ``codomain`` determined by ``im_gens`` is @@ -442,7 +443,7 @@ def __truediv__(self, I): EXAMPLES:: - sage: QQ / ZZ + sage: QQ / ZZ # needs sage.modules Q/Z """ from sage.rings.ideal import Ideal_generic @@ -460,9 +461,9 @@ def range_by_height(self, start, end=None): Returns a Python generator for the list of rational numbers with heights in ``range(start, end)``. Follows the same - convention as Python range, see ``range?`` for details. + convention as Python :func:`range`, type ``range?`` for details. - See also ``__iter__()``. + See also :meth:`__iter__`. EXAMPLES: @@ -527,7 +528,7 @@ def primes_of_bounded_norm_iter(self, B): EXAMPLES:: sage: it = QQ.primes_of_bounded_norm_iter(10) - sage: list(it) + sage: list(it) # needs sage.libs.pari [2, 3, 5, 7] sage: list(QQ.primes_of_bounded_norm_iter(1)) [] @@ -541,8 +542,7 @@ def primes_of_bounded_norm_iter(self, B): return from sage.arith.misc import primes - for p in primes(B+1): - yield p + yield from primes(B + 1) def discriminant(self): """ @@ -608,7 +608,7 @@ def embeddings(self, K): sage: QQ.embeddings(QQ) [Identity endomorphism of Rational Field] - sage: QQ.embeddings(CyclotomicField(5)) + sage: QQ.embeddings(CyclotomicField(5)) # needs sage.rings.number_field [Coercion map: From: Rational Field To: Cyclotomic Field of order 5 and degree 4] @@ -628,9 +628,7 @@ def automorphisms(self): r""" Return all Galois automorphisms of ``self``. - OUTPUT: - - - a sequence containing just the identity morphism + OUTPUT: a sequence containing just the identity morphism EXAMPLES:: @@ -645,15 +643,15 @@ def automorphisms(self): def places(self, all_complex=False, prec=None): r""" - Return the collection of all infinite places of self, which - in this case is just the embedding of self into `\RR`. + Return the collection of all infinite places of ``self``, which + in this case is just the embedding of ``self`` into `\RR`. By default, this returns homomorphisms into ``RR``. If ``prec`` is not None, we simply return homomorphisms into ``RealField(prec)`` (or ``RDF`` if ``prec=53``). There is an optional flag ``all_complex``, which defaults to - False. If ``all_complex`` is True, then the real embeddings + ``False``. If ``all_complex`` is ``True``, then the real embeddings are returned as embeddings into the corresponding complex field. @@ -661,7 +659,7 @@ def places(self, all_complex=False, prec=None): EXAMPLES:: - sage: QQ.places() + sage: QQ.places() # needs sage.rings.real_mpfr [Ring morphism: From: Rational Field To: Real Field with 53 bits of precision @@ -671,7 +669,7 @@ def places(self, all_complex=False, prec=None): From: Rational Field To: Real Double Field Defn: 1 |--> 1.0] - sage: QQ.places(prec=200, all_complex=True) + sage: QQ.places(prec=200, all_complex=True) # needs sage.rings.real_mpfr [Ring morphism: From: Rational Field To: Complex Field with 200 bits of precision @@ -679,19 +677,27 @@ def places(self, all_complex=False, prec=None): """ from sage.rings.infinity import Infinity if prec is None: - from sage.rings.real_mpfr import RR as R - from sage.rings.cc import CC as C + if all_complex: + from sage.rings.cc import CC as domain + else: + from sage.rings.real_mpfr import RR as domain elif prec == 53: - from sage.rings.real_double import RDF as R - from sage.rings.complex_double import CDF as C + if all_complex: + from sage.rings.complex_double import CDF as domain + else: + from sage.rings.real_double import RDF as domain elif prec == Infinity: - from sage.rings.qqbar import AA as R, QQbar as C + if all_complex: + from sage.rings.qqbar import QQbar as domain + else: + from sage.rings.qqbar import AA as domain else: - from sage.rings.real_mpfr import RealField - from sage.rings.complex_mpfr import ComplexField - R = RealField(prec) - C = ComplexField(prec) - domain = C if all_complex else R + if all_complex: + from sage.rings.complex_mpfr import ComplexField + domain = ComplexField(prec) + else: + from sage.rings.real_mpfr import RealField + domain = RealField(prec) return [self.hom([domain(1)])] def complex_embedding(self, prec=53): @@ -700,12 +706,12 @@ def complex_embedding(self, prec=53): EXAMPLES:: - sage: QQ.complex_embedding() + sage: QQ.complex_embedding() # needs sage.rings.real_mpfr Ring morphism: From: Rational Field To: Complex Field with 53 bits of precision Defn: 1 |--> 1.00000000000000 - sage: QQ.complex_embedding(20) + sage: QQ.complex_embedding(20) # needs sage.rings.real_mpfr Ring morphism: From: Rational Field To: Complex Field with 20 bits of precision @@ -722,9 +728,9 @@ def residue_field(self, p, check=True): INPUT: - - ``p`` - a prime integer. + - ``p`` -- a prime integer. - - ``check`` (default True) - if True check the primality of + - ``check`` (default ``True``) -- if ``True``, check the primality of `p`, else do not. OUTPUT: The residue field at this prime. @@ -733,7 +739,7 @@ def residue_field(self, p, check=True): sage: QQ.residue_field(5) Residue field of Integers modulo 5 - sage: QQ.residue_field(next_prime(10^9)) + sage: QQ.residue_field(next_prime(10^9)) # needs sage.rings.finite_rings Residue field of Integers modulo 1000000007 """ from sage.rings.finite_rings.residue_field import ResidueField @@ -741,7 +747,7 @@ def residue_field(self, p, check=True): def hilbert_symbol_negative_at_S(self, S, b, check=True): r""" - Returns an integer that has a negative Hilbert symbol with respect + Return an integer that has a negative Hilbert symbol with respect to a given rational number and a given set of primes (or places). The function is algorithm 3.4.1 in [Kir2016]_. It finds an integer `a` @@ -751,10 +757,10 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): INPUT: - ``S`` -- a list of rational primes, the infinite place as real - embedding of `\QQ` or as -1 + embedding of `\QQ` or as `-1` - ``b`` -- a non-zero rational number which is a non-square locally at every prime in ``S``. - - ``check`` -- ``bool`` (default:``True``) perform additional checks on + - ``check`` -- ``bool`` (default: ``True``) perform additional checks on input and confirm the output. OUTPUT: @@ -764,37 +770,37 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): EXAMPLES:: - sage: QQ.hilbert_symbol_negative_at_S([-1,5,3,2,7,11,13,23], -10/7) + sage: QQ.hilbert_symbol_negative_at_S([-1,5,3,2,7,11,13,23], -10/7) # needs sage.rings.padics -9867 - sage: QQ.hilbert_symbol_negative_at_S([3, 5, QQ.places()[0], 11], -15) + sage: QQ.hilbert_symbol_negative_at_S([3, 5, QQ.places()[0], 11], -15) # needs sage.rings.padics -33 - sage: QQ.hilbert_symbol_negative_at_S([3, 5], 2) + sage: QQ.hilbert_symbol_negative_at_S([3, 5], 2) # needs sage.rings.padics 15 TESTS:: - sage: QQ.hilbert_symbol_negative_at_S(5/2, -2) + sage: QQ.hilbert_symbol_negative_at_S(5/2, -2) # needs sage.modules Traceback (most recent call last): ... TypeError: first argument must be a list or integer :: - sage: QQ.hilbert_symbol_negative_at_S([1, 3], 0) + sage: QQ.hilbert_symbol_negative_at_S([1, 3], 0) # needs sage.modules Traceback (most recent call last): ... ValueError: second argument must be nonzero :: - sage: QQ.hilbert_symbol_negative_at_S([-1, 3, 5], 2) + sage: QQ.hilbert_symbol_negative_at_S([-1, 3, 5], 2) # needs sage.modules Traceback (most recent call last): ... ValueError: list should be of even cardinality :: - sage: QQ.hilbert_symbol_negative_at_S([1, 3], 2) + sage: QQ.hilbert_symbol_negative_at_S([1, 3], 2) # needs sage.modules Traceback (most recent call last): ... ValueError: all entries in list must be prime or -1 for @@ -802,7 +808,7 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): :: - sage: QQ.hilbert_symbol_negative_at_S([5, 7], 2) + sage: QQ.hilbert_symbol_negative_at_S([5, 7], 2) # needs sage.libs.pari sage.modules Traceback (most recent call last): ... ValueError: second argument must be a nonsquare with @@ -810,14 +816,14 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): :: - sage: QQ.hilbert_symbol_negative_at_S([1, 3], sqrt(2)) + sage: QQ.hilbert_symbol_negative_at_S([1, 3], sqrt(2)) # needs sage.libs.pari sage.modules sage.symbolic Traceback (most recent call last): ... TypeError: second argument must be a rational number :: - sage: QQ.hilbert_symbol_negative_at_S([-1, 3], 2) + sage: QQ.hilbert_symbol_negative_at_S([-1, 3], 2) # needs sage.modules Traceback (most recent call last): ... ValueError: if the infinite place is in the list, the second @@ -891,7 +897,6 @@ def phi(x): v = [(1-hilbert_symbol(x, b, p))//2 for p in P] return V(v) - M = matrix(GF(2), [phi(p) for p in P+[-1]]) # We search through all the primes for q in Primes(): @@ -915,7 +920,7 @@ def phi(x): def gens(self): r""" - Return a tuple of generators of `\QQ` which is only ``(1,)``. + Return a tuple of generators of `\QQ`, which is only ``(1,)``. EXAMPLES:: @@ -928,7 +933,7 @@ def gen(self, n=0): r""" Return the ``n``-th generator of `\QQ`. - There is only the 0-th generator which is 1. + There is only the 0-th generator, which is 1. EXAMPLES:: @@ -942,7 +947,7 @@ def gen(self, n=0): def degree(self): r""" - Return the degree of `\QQ` which is 1. + Return the degree of `\QQ`, which is 1. EXAMPLES:: @@ -953,7 +958,7 @@ def degree(self): def absolute_degree(self): r""" - Return the absolute degree of `\QQ` which is 1. + Return the absolute degree of `\QQ`, which is 1. EXAMPLES:: @@ -964,7 +969,7 @@ def absolute_degree(self): def ngens(self): r""" - Return the number of generators of `\QQ` which is 1. + Return the number of generators of `\QQ`, which is 1. EXAMPLES:: @@ -1058,16 +1063,17 @@ def extension(self, poly, names, **kwds): We make a single absolute extension:: - sage: K.<a> = QQ.extension(x^3 + 5); K + sage: x = polygen(QQ, 'x') + sage: K.<a> = QQ.extension(x^3 + 5); K # needs sage.rings.number_field Number Field in a with defining polynomial x^3 + 5 We make an extension generated by roots of two polynomials:: - sage: K.<a,b> = QQ.extension([x^3 + 5, x^2 + 3]); K + sage: K.<a,b> = QQ.extension([x^3 + 5, x^2 + 3]); K # needs sage.rings.number_field Number Field in a with defining polynomial x^3 + 5 over its base field - sage: b^2 + sage: b^2 # needs sage.rings.number_field -3 - sage: a^3 + sage: a^3 # needs sage.rings.number_field -5 """ from sage.rings.number_field.number_field import NumberField @@ -1075,11 +1081,11 @@ def extension(self, poly, names, **kwds): def algebraic_closure(self): r""" - Return the algebraic closure of self (which is `\QQbar`). + Return the algebraic closure of ``self`` (which is `\QQbar`). EXAMPLES:: - sage: QQ.algebraic_closure() + sage: QQ.algebraic_closure() # needs sage.rings.number_field Algebraic Field """ from sage.rings.qqbar import QQbar @@ -1087,7 +1093,7 @@ def algebraic_closure(self): def order(self): r""" - Return the order of `\QQ` which is `\infty`. + Return the order of `\QQ`, which is `\infty`. EXAMPLES:: @@ -1101,8 +1107,8 @@ def polynomial(self): r""" Return a defining polynomial of `\QQ`, as for other number fields. - This is also aliased to :meth:`self.defining_polynomial()` - and :meth:`self.absolute_polynomial()`. + This is also aliased to :meth:`defining_polynomial` + and :meth:`absolute_polynomial`. EXAMPLES:: @@ -1133,9 +1139,7 @@ def some_elements(self): See :func:`TestSuite` for a typical use case. - OUTPUT: - - An iterator over 100 elements of `\QQ`. + OUTPUT: An iterator over 100 elements of `\QQ`. EXAMPLES:: @@ -1174,7 +1178,7 @@ def some_elements(self): def random_element(self, num_bound=None, den_bound=None, *args, **kwds): r""" - Return an random element of `\QQ`. + Return a random element of `\QQ`. Elements are constructed by randomly choosing integers for the numerator and denominator, not necessarily coprime. @@ -1272,7 +1276,6 @@ def zeta(self, n=2): else: raise ValueError("no n-th root of unity in rational field") - def selmer_generators(self, S, m, proof=True, orders=False): r""" Return generators of the group `\QQ(S,m)`. @@ -1285,7 +1288,7 @@ def selmer_generators(self, S, m, proof=True, orders=False): - ``proof`` -- ignored - - ``orders`` (default False) -- if True, output two lists, the + - ``orders`` (default ``False``) -- if ``True``, output two lists, the generators and their orders OUTPUT: @@ -1304,7 +1307,7 @@ def selmer_generators(self, S, m, proof=True, orders=False): :meth:`RationalField.selmer_space`, which gives additional output when `m=p` is prime: as well as generators, it gives an - abstract vector space over `GF(p)` isomorphic to `\QQ(S,p)` + abstract vector space over `\GF{p}` isomorphic to `\QQ(S,p)` and maps implementing the isomorphism between this space and `\QQ(S,p)` as a subgroup of `\QQ^*/(\QQ^*)^p`. @@ -1391,7 +1394,7 @@ def selmer_space(self, S, p, proof=None): (tuple) ``QSp``, ``QSp_gens``, ``from_QSp``, ``to_QSp`` where - - ``QSp`` is an abstract vector space over `GF(p)` isomorphic to `\QQ(S,p)`; + - ``QSp`` is an abstract vector space over `\GF{p}` isomorphic to `\QQ(S,p)`; - ``QSp_gens`` is a list of elements of `\QQ^*` generating `\QQ(S,p)`; @@ -1415,18 +1418,20 @@ def selmer_space(self, S, p, proof=None): When `S` is empty, `\QQ(S,p)` is only nontrivial for `p=2`:: - sage: QS2, QS2gens, fromQS2, toQS2 = QQ.selmer_space([], 2) - sage: QS2 + sage: QS2, QS2gens, fromQS2, toQS2 = QQ.selmer_space([], 2) # needs sage.rings.number_field + sage: QS2 # needs sage.rings.number_field Vector space of dimension 1 over Finite Field of size 2 - sage: QS2gens + sage: QS2gens # needs sage.rings.number_field [-1] - sage: all(QQ.selmer_space([], p)[0].dimension() == 0 for p in primes(3,10)) + sage: all(QQ.selmer_space([], p)[0].dimension() == 0 # needs sage.libs.pari + ....: for p in primes(3, 10)) True In general there is one generator for each `p\in S`, and an additional generator of `-1` when `p=2`:: + sage: # needs sage.modules sage.rings.number_field sage: QS2, QS2gens, fromQS2, toQS2 = QQ.selmer_space([5,7], 2) sage: QS2 Vector space of dimension 3 over Finite Field of size 2 @@ -1440,9 +1445,9 @@ def selmer_space(self, S, p, proof=None): The map ``fromQS2`` is only well-defined modulo `p`'th powers (in this case, modulo squares):: - sage: toQS2(-5/7) + sage: toQS2(-5/7) # needs sage.modules sage.rings.number_field (1, 1, 1) - sage: fromQS2((1,1,1)) + sage: fromQS2((1,1,1)) # needs sage.modules sage.rings.number_field -35 sage: ((-5/7)/(-35)).is_square() True @@ -1450,10 +1455,11 @@ def selmer_space(self, S, p, proof=None): The map ``toQS2`` is not defined on all of `\QQ^*`, only on those numbers which are squares away from `5` and `7`:: - sage: toQS2(210) + sage: toQS2(210) # needs sage.modules sage.rings.number_field Traceback (most recent call last): ... - ValueError: argument 210 should have valuations divisible by 2 at all primes in [5, 7] + ValueError: argument 210 should have valuations divisible by 2 + at all primes in [5, 7] """ from sage.rings.number_field.selmer_group import pSelmerGroup @@ -1519,7 +1525,7 @@ def _gap_init_(self): EXAMPLES:: - sage: gap(QQ) # indirect doctest + sage: gap(QQ) # indirect doctest # needs sage.libs.gap Rationals """ return 'Rationals' @@ -1587,7 +1593,7 @@ def _sympy_(self): EXAMPLES:: - sage: QQ._sympy_() + sage: QQ._sympy_() # needs sympy Rationals """ from sympy import Rationals @@ -1632,21 +1638,22 @@ def _factor_univariate_polynomial(self, f): TESTS:: + sage: # needs sage.libs.pari sage: R.<x> = QQ[] - sage: QQ._factor_univariate_polynomial( x ) + sage: QQ._factor_univariate_polynomial(x) x - sage: QQ._factor_univariate_polynomial( 2*x ) + sage: QQ._factor_univariate_polynomial(2*x) (2) * x - sage: QQ._factor_univariate_polynomial( (x^2 - 1/4)^4 ) + sage: QQ._factor_univariate_polynomial((x^2 - 1/4)^4) (x - 1/2)^4 * (x + 1/2)^4 - sage: QQ._factor_univariate_polynomial( (2*x + 1) * (3*x^2 - 5)^2 ) + sage: QQ._factor_univariate_polynomial((2*x + 1) * (3*x^2 - 5)^2) (18) * (x + 1/2) * (x^2 - 5/3)^2 sage: f = prod((k^2*x^k + k)^(k-1) for k in primes(10)) sage: QQ._factor_univariate_polynomial(f) (1751787911376562500) * (x^2 + 1/2) * (x^3 + 1/3)^2 * (x^5 + 1/5)^4 * (x^7 + 1/7)^6 - sage: QQ._factor_univariate_polynomial( 10*x^5 - 1 ) + sage: QQ._factor_univariate_polynomial(10*x^5 - 1) (10) * (x^5 - 1/10) - sage: QQ._factor_univariate_polynomial( 10*x^5 - 10 ) + sage: QQ._factor_univariate_polynomial(10*x^5 - 10) (10) * (x - 1) * (x^4 + x^3 + x^2 + x + 1) """ @@ -1664,9 +1671,9 @@ def valuation(self, p): EXAMPLES:: - sage: v = QQ.valuation(3); v + sage: v = QQ.valuation(3); v # needs sage.rings.padics 3-adic valuation - sage: v(1/3) + sage: v(1/3) # needs sage.rings.padics -1 .. SEEALSO:: @@ -1678,10 +1685,12 @@ def valuation(self, p): from sage.rings.padics.padic_valuation import pAdicValuation return pAdicValuation(self, p) + QQ = RationalField() Q = QQ -def is_RationalField(x): + +def is_RationalField(x) -> bool: """ Check to see if ``x`` is the rational field. @@ -1695,7 +1704,8 @@ def is_RationalField(x): """ return isinstance(x, RationalField) -def frac(n,d): + +def frac(n, d): """ Return the fraction ``n/d``. diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 23a41c2bf6a..17859068273 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -28,9 +28,9 @@ Sage :class:`RealBall` objects wrap Arb objects of type ``arb_t``. A real ball represents a ball over the real numbers, that is, an interval `[m-r,m+r]` where the midpointย `m` and the radiusย `r` are (extended) real numbers:: - sage: RBF(pi) + sage: RBF(pi) # needs sage.symbolic [3.141592653589793 +/- ...e-16] - sage: RBF(pi).mid(), RBF(pi).rad() + sage: RBF(pi).mid(), RBF(pi).rad() # needs sage.symbolic (3.14159265358979, ...e-16) The midpoint is represented as an arbitrary-precision floating-point number @@ -147,7 +147,7 @@ Comparisons with Sage symbolic infinities work with some limitations:: True sage: RBF(infinity) < infinity False - sage: RBF(NaN) < infinity + sage: RBF(NaN) < infinity # needs sage.symbolic Traceback (most recent call last): ... ValueError: infinite but not with +/- phase @@ -159,14 +159,14 @@ Comparisons with Sage symbolic infinities work with some limitations:: Comparisons between elements of real ball fields, however, support special values and should be preferred:: - sage: RBF(NaN) < RBF(infinity) + sage: RBF(NaN) < RBF(infinity) # needs sage.symbolic False sage: RBF(0).add_error(infinity) <= RBF(infinity) True TESTS:: - sage: (RBF(pi) * identity_matrix(QQ, 3)).parent() + sage: (RBF(pi) * identity_matrix(QQ, 3)).parent() # needs sage.symbolic Full MatrixSpace of 3 by 3 dense matrices over Real ball field with 53 bits of precision @@ -175,11 +175,11 @@ TESTS:: :: - sage: SR.coerce(RBF(0.42)) + sage: SR.coerce(RBF(0.42)) # needs sage.symbolic [0.4200000000000000 +/- ...e-17] - sage: RBF(0.42) + SR(1) + sage: RBF(0.42) + SR(1) # needs sage.symbolic [1.420000000000000 +/- ...e-16] - sage: _.parent() + sage: _.parent() # needs sage.symbolic Symbolic Ring Classes and Methods @@ -200,7 +200,7 @@ Classes and Methods from cysignals.signals cimport sig_on, sig_str, sig_off from cpython.float cimport PyFloat_AS_DOUBLE -from cpython.int cimport PyInt_AS_LONG +from cpython.long cimport PyLong_AsLong from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE from libc.stdlib cimport abort @@ -217,12 +217,11 @@ from sage.libs.mpfi cimport * from sage.libs.mpfr cimport * from sage.libs.mpfr cimport MPFR_RNDN, MPFR_RNDU, MPFR_RNDD, MPFR_RNDZ -from sage.structure.element cimport Element, ModuleElement, RingElement +from sage.structure.element cimport Element, RingElement from sage.rings.ring cimport Field import sage.rings.abc from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational -from sage.rings.real_double cimport RealDoubleElement from sage.rings.real_mpfr cimport RealField_class, RealField, RealNumber from sage.arith.long cimport is_small_python_int @@ -339,7 +338,7 @@ class RealBallField(UniqueRepresentation, sage.rings.abc.RealBallField): :: - sage: (1/2*RBF(1)) + AA(sqrt(2)) - 1 + polygen(QQ, 'x') + sage: (1/2*RBF(1)) + AA(sqrt(2)) - 1 + polygen(QQ, 'x') # needs sage.symbolic x + [0.914213562373095 +/- ...e-16] TESTS:: @@ -363,9 +362,9 @@ class RealBallField(UniqueRepresentation, sage.rings.abc.RealBallField): sage: RBF.zero() 0 - sage: NF.<sqrt2> = QuadraticField(2, embedding=AA(2).sqrt()) - sage: a = (sqrt2 - 1)^1000 - sage: RBF(a) + sage: NF.<sqrt2> = QuadraticField(2, embedding=AA(2).sqrt()) # needs sage.rings.number_field + sage: a = (sqrt2 - 1)^1000 # needs sage.rings.number_field + sage: RBF(a) # needs sage.rings.number_field [1.676156872756536e-383 +/- ...e-399] sage: RealBallField().is_finite() @@ -457,7 +456,7 @@ class RealBallField(UniqueRepresentation, sage.rings.abc.RealBallField): False sage: RealBallField().has_coerce_map_from(RIF) False - sage: RealBallField().has_coerce_map_from(SR) + sage: RealBallField().has_coerce_map_from(SR) # needs sage.symbolic False sage: RealBallField().has_coerce_map_from(RR) False @@ -492,8 +491,8 @@ class RealBallField(UniqueRepresentation, sage.rings.abc.RealBallField): if other in [AA, RLF]: return True - from sage.rings.number_field.number_field_base import is_NumberField - if is_NumberField(other): + from sage.rings.number_field.number_field_base import NumberField + if isinstance(other, NumberField): emb = other.coerce_embedding() return emb is not None and self.has_coerce_map_from(emb.codomain()) @@ -510,34 +509,34 @@ class RealBallField(UniqueRepresentation, sage.rings.abc.RealBallField): [+/- 1.01] sage: RBF(1) 1.000000000000000 - sage: RBF(x) + sage: RBF(x) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to convert x to a RealBall Various symbolic constants are supported:: - sage: RBF(e) + sage: RBF(e) # needs sage.symbolic [2.718281828459045 +/- ...e-16] - sage: RBF(pi) + sage: RBF(pi) # needs sage.symbolic [3.141592653589793 +/- ...e-16] Symbolic expressions are parsed :: - sage: RBF(4*zeta(3)) + sage: RBF(4*zeta(3)) # needs sage.symbolic [4.8082276126383...] - sage: RBF(exp(1), 0.01) + sage: RBF(exp(1), 0.01) # needs sage.symbolic [2.7 +/- ...] TESTS: The following conversions used to yield incorrect results:: - sage: RBF(airy_ai(1)) + sage: RBF(airy_ai(1)) # needs sage.symbolic [0.135292416312881...] - sage: v = RBF(zetaderiv(1, 3/2)); v + sage: v = RBF(zetaderiv(1, 3/2)); v # needs sage.symbolic [-3.932239737431101 +/- 5.58e-16] - sage: v.overlaps(RealBallField(100)(3/2).zetaderiv(1)) + sage: v.overlaps(RealBallField(100)(3/2).zetaderiv(1)) # needs sage.symbolic True """ @@ -817,7 +816,7 @@ class RealBallField(UniqueRepresentation, sage.rings.abc.RealBallField): TESTS:: - sage: RBF.sinpi(RLF(sqrt(2))) + sage: RBF.sinpi(RLF(sqrt(2))) # needs sage.symbolic [-0.963902532849877 +/- ...e-16] """ cdef RealBall res, x_as_ball @@ -861,7 +860,7 @@ class RealBallField(UniqueRepresentation, sage.rings.abc.RealBallField): TESTS:: - sage: RBF.cospi(RLF(sqrt(2))) + sage: RBF.cospi(RLF(sqrt(2))) # needs sage.symbolic [-0.26625534204142 +/- ...e-15] """ cdef RealBall res, x_as_ball @@ -909,7 +908,7 @@ class RealBallField(UniqueRepresentation, sage.rings.abc.RealBallField): TESTS:: - sage: RBF.gamma(RLF(pi)) # abs tol 1e-13 + sage: RBF.gamma(RLF(pi)) # abs tol 1e-13 # needs sage.symbolic [2.28803779534003 +/- 4.12e-15] """ cdef RealBall res @@ -1259,7 +1258,7 @@ cdef class RealBall(RingElement): sage: RBF(3, 0.125) [3e+0 +/- 0.126] - sage: RBF(pi, 0.125r) + sage: RBF(pi, 0.125r) # needs sage.symbolic [3e+0 +/- 0.267] sage: RBF(3, 1/8) [3e+0 +/- 0.126] @@ -1268,8 +1267,8 @@ cdef class RealBall(RingElement): :: - sage: NF.<sqrt2> = QuadraticField(2) - sage: RBF(1/5 + sqrt2/2) + sage: NF.<sqrt2> = QuadraticField(2) # needs sage.rings.number_field + sage: RBF(1/5 + sqrt2/2) # needs sage.rings.number_field [0.907106781186547 +/- ...e-16] Note that integers and floating-point numbers are ''not'' rounded to @@ -1386,7 +1385,7 @@ cdef class RealBall(RingElement): elif isinstance(mid, RealBall): arb_set(self.value, (<RealBall> mid).value) # no rounding! elif is_small_python_int(mid): - arb_set_si(self.value, PyInt_AS_LONG(mid)) # no rounding! + arb_set_si(self.value, PyLong_AsLong(mid)) # no rounding! elif isinstance(mid, Integer): if _do_sig(prec(self)): sig_on() fmpz_init(tmpz) @@ -1536,9 +1535,11 @@ cdef class RealBall(RingElement): TESTS:: - sage: [loads(dumps(b)).identical(b) for b in - ....: [RealBallField(60).pi(), RBF(infinity), RBF(NaN)]] - [True, True, True] + sage: [loads(dumps(b)).identical(b) + ....: for b in [RealBallField(60).pi(), RBF(infinity)]] + [True, True] + sage: b = RBF(NaN); loads(dumps(b)).identical(b) # needs sage.symbolic + True """ cdef bytes py_val sig_on() @@ -1583,7 +1584,7 @@ cdef class RealBall(RingElement): Traceback (most recent call last): ... ValueError: [+/- 2.01] does not contain a unique integer - sage: ZZ(RBF(pi)) + sage: ZZ(RBF(pi)) # needs sage.symbolic Traceback (most recent call last): ... ValueError: [3.141592653589793 +/- ...e-16] does not contain a unique integer @@ -1630,6 +1631,7 @@ cdef class RealBall(RingElement): EXAMPLES:: + sage: # needs sage.symbolic sage: mypi = RBF(pi) sage: RR(mypi) 3.14159265358979 @@ -1657,7 +1659,6 @@ cdef class RealBall(RingElement): 0.250000000000000 """ cdef RealNumber left, mid, right - cdef long prec = field.precision() cdef int sl, sr if (field.rnd == MPFR_RNDN or field.rnd == MPFR_RNDZ and arb_contains_zero(self.value)): @@ -2067,17 +2068,17 @@ cdef class RealBall(RingElement): EXAMPLES: - It is possible to create balls whose midpoint is more precise that + It is possible to create balls whose midpoint is more precise than their parent's nominal precision (see :mod:`~sage.rings.real_arb` for more information):: - sage: b = RBF(pi.n(100)) - sage: b.mid() + sage: b = RBF(pi.n(100)) # needs sage.symbolic + sage: b.mid() # needs sage.symbolic 3.141592653589793238462643383 The ``round()`` method rounds such a ball to its parent's precision:: - sage: b.round().mid() + sage: b.round().mid() # needs sage.symbolic 3.14159265358979 .. SEEALSO:: :meth:`trim` @@ -2099,11 +2100,11 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: RBF(pi).accuracy() + sage: RBF(pi).accuracy() # needs sage.symbolic 52 sage: RBF(1).accuracy() == RBF.maximal_accuracy() True - sage: RBF(NaN).accuracy() == -RBF.maximal_accuracy() + sage: RBF(NaN).accuracy() == -RBF.maximal_accuracy() # needs sage.symbolic True .. SEEALSO:: :meth:`~RealBallField.maximal_accuracy` @@ -2206,7 +2207,7 @@ cdef class RealBall(RingElement): EXAMPLES:: sage: RBF = RealBallField() - sage: RBF(pi).is_nonzero() + sage: RBF(pi).is_nonzero() # needs sage.symbolic True sage: RBF(RIF(-0.5, 0.5)).is_nonzero() False @@ -2429,22 +2430,21 @@ cdef class RealBall(RingElement): False """ cdef RealBall lt, rt - cdef arb_t difference lt = left rt = right if op == Py_EQ: return arb_eq(lt.value, rt.value) - elif op == Py_NE: + if op == Py_NE: return arb_ne(lt.value, rt.value) - elif op == Py_GT: + if op == Py_GT: return arb_gt(lt.value, rt.value) - elif op == Py_LT: + if op == Py_LT: return arb_lt(lt.value, rt.value) - elif op == Py_GE: + if op == Py_GE: return arb_ge(lt.value, rt.value) - elif op == Py_LE: + if op == Py_LE: return arb_le(lt.value, rt.value) def min(self, *others): @@ -2521,7 +2521,7 @@ cdef class RealBall(RingElement): def is_finite(self): """ - Return True iff the midpoint and radius of this ball are both + Return ``True`` iff the midpoint and radius of this ball are both finite floating-point numbers, i.e. not infinities or NaN. EXAMPLES:: @@ -2535,7 +2535,7 @@ cdef class RealBall(RingElement): def identical(self, RealBall other): """ - Return True iff ``self`` and ``other`` are equal as balls, i.e. + Return ``True`` iff ``self`` and ``other`` are equal as balls, i.e. have both the same midpoint and radius. Note that this is not the same thing as testing whether both ``self`` @@ -2558,7 +2558,7 @@ cdef class RealBall(RingElement): def overlaps(self, RealBall other): """ - Return True iff ``self`` and ``other`` have some point in common. + Return ``True`` iff ``self`` and ``other`` have some point in common. If either ``self`` or ``other`` contains NaN, this method always returns nonzero (as a NaN could be anything, it could in particular @@ -2566,9 +2566,9 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: RBF(pi).overlaps(RBF(pi) + 2**(-100)) + sage: RBF(pi).overlaps(RBF(pi) + 2**(-100)) # needs sage.symbolic True - sage: RBF(pi).overlaps(RBF(3)) + sage: RBF(pi).overlaps(RBF(3)) # needs sage.symbolic False """ return arb_overlaps(self.value, other.value) @@ -2602,7 +2602,7 @@ cdef class RealBall(RingElement): sage: RBF(1/3).contains_exact(1/3) True - sage: RBF(sqrt(2)).contains_exact(sqrt(2)) + sage: RBF(sqrt(2)).contains_exact(sqrt(2)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unsupported type: <class 'sage.symbolic.expression.Expression'> @@ -2620,7 +2620,7 @@ cdef class RealBall(RingElement): if isinstance(other, RealBall): res = arb_contains(self.value, (<RealBall> other).value) elif is_small_python_int(other): - res = arb_contains_si(self.value, PyInt_AS_LONG(other)) + res = arb_contains_si(self.value, PyLong_AsLong(other)) elif isinstance(other, Integer): fmpz_init(tmpz) fmpz_set_mpz(tmpz, (<Integer> other).value) @@ -2641,19 +2641,19 @@ cdef class RealBall(RingElement): def __contains__(self, other): """ - Return True if ``other`` can be verified to be contained in ``self``. + Return ``True`` if ``other`` can be verified to be contained in ``self``. The test is done using interval arithmetic with a precision determined by the parent of ``self`` and may return false negatives. EXAMPLES:: - sage: sqrt(2) in RBF(sqrt(2)) + sage: sqrt(2) in RBF(sqrt(2)) # needs sage.symbolic True A false negative:: - sage: sqrt(2) in RBF(RealBallField(100)(sqrt(2))) + sage: sqrt(2) in RBF(RealBallField(100)(sqrt(2))) # needs sage.symbolic False .. SEEALSO:: :meth:`contains_exact` @@ -2733,7 +2733,7 @@ cdef class RealBall(RingElement): True sage: RBF(-infinity).is_infinity() True - sage: RBF(NaN).is_infinity() + sage: RBF(NaN).is_infinity() # needs sage.symbolic True sage: (~RBF(0)).is_infinity() True @@ -2748,7 +2748,7 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: RBF(NaN).is_NaN() + sage: RBF(NaN).is_NaN() # needs sage.symbolic True sage: RBF(-5).gamma().is_NaN() True @@ -2863,7 +2863,7 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: RBF(pi)/RBF(e) + sage: RBF(pi)/RBF(e) # needs sage.symbolic [1.155727349790922 +/- ...e-16] sage: RBF(2)/RBF(0) nan @@ -2878,6 +2878,7 @@ cdef class RealBall(RingElement): """ EXAMPLES:: + sage: # needs sage.symbolic sage: RBF(e)^17 [24154952.7535753 +/- ...e-8] sage: RBF(e)^(-1) @@ -2893,14 +2894,14 @@ cdef class RealBall(RingElement): nan sage: RBF(0)^(-1) nan - sage: RBF(-e)**RBF(pi) + sage: RBF(-e)**RBF(pi) # needs sage.symbolic nan TESTS:: - sage: RBF(e)**(2r) + sage: RBF(e)**(2r) # needs sage.symbolic [7.38905609893065 +/- ...e-15] - sage: RBF(e)**(-1r) + sage: RBF(e)**(-1r) # needs sage.symbolic [0.367879441171442 +/- ...e-16] """ cdef fmpz_t tmpz @@ -2910,7 +2911,7 @@ cdef class RealBall(RingElement): cdef RealBall res = self._new() if is_small_python_int(expo) and expo > 0: if _do_sig(prec(self)): sig_on() - arb_pow_ui(res.value, self.value, PyInt_AS_LONG(expo), prec(self)) + arb_pow_ui(res.value, self.value, PyLong_AsLong(expo), prec(self)) if _do_sig(prec(self)): sig_off() elif isinstance(expo, Integer): if _do_sig(prec(self)): sig_on() @@ -3077,7 +3078,7 @@ cdef class RealBall(RingElement): cdef RealBall self = val cdef RealBall res = self._new() if is_small_python_int(shift): - arb_mul_2exp_si(res.value, self.value, PyInt_AS_LONG(shift)) + arb_mul_2exp_si(res.value, self.value, PyLong_AsLong(shift)) elif isinstance(shift, Integer): sig_on() fmpz_init(tmpz) @@ -3219,7 +3220,7 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: RBF(pi).sin() + sage: RBF(pi).sin() # needs sage.symbolic [+/- ...e-16] .. SEEALSO:: :meth:`~sage.rings.real_arb.RealBallField.sinpi` @@ -3236,7 +3237,7 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: RBF(pi).cos() + sage: RBF(pi).cos() # needs sage.symbolic [-1.00000000000000 +/- ...e-16] .. SEEALSO:: :meth:`~sage.rings.real_arb.RealBallField.cospi` @@ -3255,7 +3256,7 @@ cdef class RealBall(RingElement): sage: RBF(1).tan() [1.557407724654902 +/- ...e-16] - sage: RBF(pi/2).tan() + sage: RBF(pi/2).tan() # needs sage.symbolic nan """ cdef RealBall res = self._new() @@ -3272,7 +3273,7 @@ cdef class RealBall(RingElement): sage: RBF(1).cot() [0.642092615934331 +/- ...e-16] - sage: RBF(pi).cot() + sage: RBF(pi).cot() # needs sage.symbolic nan """ cdef RealBall res = self._new() @@ -3550,7 +3551,7 @@ cdef class RealBall(RingElement): TESTS:: - sage: RBF(Ei(1)) # abs tol 5e-16 + sage: RBF(Ei(1)) # abs tol 5e-16 # needs sage.symbolic [1.89511781635594 +/- 4.94e-15] """ cdef RealBall res = self._new() @@ -3570,7 +3571,7 @@ cdef class RealBall(RingElement): TESTS:: - sage: RBF(Si(1)) # abs tol 1e-15 + sage: RBF(Si(1)) # abs tol 1e-15 # needs sage.symbolic [0.946083070367183 +/- 9.22e-16] """ cdef RealBall res = self._new() @@ -3592,7 +3593,7 @@ cdef class RealBall(RingElement): TESTS:: - sage: RBF(Ci(1)) # abs tol 5e-16 + sage: RBF(Ci(1)) # abs tol 5e-16 # needs sage.symbolic [0.337403922900968 +/- 3.25e-16] """ cdef RealBall res = self._new() @@ -3614,7 +3615,7 @@ cdef class RealBall(RingElement): TESTS:: - sage: RBF(Shi(1)) + sage: RBF(Shi(1)) # needs sage.symbolic [1.05725087537573 +/- 2.77e-15] """ cdef RealBall res = self._new() @@ -3636,7 +3637,7 @@ cdef class RealBall(RingElement): TESTS:: - sage: RBF(Chi(1)) # abs tol 1e-17 + sage: RBF(Chi(1)) # abs tol 1e-17 # needs sage.symbolic [0.837866940980208 +/- 4.72e-16] """ cdef RealBall res = self._new() @@ -3658,9 +3659,9 @@ cdef class RealBall(RingElement): TESTS:: - sage: RBF(li(0)) + sage: RBF(li(0)) # needs sage.symbolic 0 - sage: RBF(Li(0)) + sage: RBF(Li(0)) # needs sage.symbolic [-1.04516378011749 +/- 4.23e-15] """ cdef RealBall res = self._new() @@ -3704,7 +3705,7 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: RBF(sin(3)).beta(RBF(2/3).sqrt()) # abs tol 1e-13 + sage: RBF(sin(3)).beta(RBF(2/3).sqrt()) # abs tol 1e-13 # needs sage.symbolic [7.407661629415 +/- 1.07e-13] sage: RealBallField(100)(7/2).beta(1) # abs tol 1e-30 [0.28571428571428571428571428571 +/- 5.23e-30] @@ -3939,11 +3940,11 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: polylog(0, -1) + sage: polylog(0, -1) # needs sage.symbolic -1/2 sage: RBF(-1).polylog(0) [-0.50000000000000 +/- ...e-16] - sage: polylog(1, 1/2) + sage: polylog(1, 1/2) # needs sage.symbolic -log(1/2) sage: RBF(1/2).polylog(1) [0.69314718055995 +/- ...e-15] @@ -3982,6 +3983,7 @@ cdef class RealBall(RingElement): EXAMPLES:: + sage: # needs sage.symbolic sage: RBF(pi).chebyshev_T(0) 1.000000000000000 sage: RBF(pi).chebyshev_T(1) @@ -4014,6 +4016,7 @@ cdef class RealBall(RingElement): EXAMPLES:: + sage: # needs sage.symbolic sage: RBF(pi).chebyshev_U(0) 1.000000000000000 sage: RBF(pi).chebyshev_U(1) @@ -4047,7 +4050,7 @@ cdef class RealBall(RingElement): sage: RBF(1).agm(1) 1.000000000000000 - sage: RBF(sqrt(2)).agm(1)^(-1) + sage: RBF(sqrt(2)).agm(1)^(-1) # needs sage.symbolic [0.8346268416740...] """ cdef RealBall other_as_ball diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index 1341d2f65ff..dea1633dd15 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -5,21 +5,21 @@ EXAMPLES: We create the real double vector space of dimension `3`:: - sage: V = RDF^3; V + sage: V = RDF^3; V # needs sage.modules Vector space of dimension 3 over Real Double Field Notice that this space is unique:: - sage: V is RDF^3 + sage: V is RDF^3 # needs sage.modules True - sage: V is FreeModule(RDF, 3) + sage: V is FreeModule(RDF, 3) # needs sage.modules True - sage: V is VectorSpace(RDF, 3) + sage: V is VectorSpace(RDF, 3) # needs sage.modules True Also, you can instantly create a space of large dimension:: - sage: V = RDF^10000 + sage: V = RDF^10000 # needs sage.modules TESTS: @@ -27,8 +27,8 @@ Test NumPy conversions:: sage: RDF(1).__array_interface__ {'typestr': '=f8'} - sage: import numpy - sage: numpy.array([RDF.pi()]).dtype + sage: import numpy # needs numpy + sage: numpy.array([RDF.pi()]).dtype # needs numpy dtype('float64') """ @@ -45,13 +45,10 @@ from libc.string cimport memcpy from cpython.object cimport * from cpython.float cimport * -from cysignals.signals cimport sig_on, sig_off - from sage.ext.stdsage cimport PY_NEW from sage.cpython.python_debug cimport if_Py_TRACE_REFS_then_PyObject_INIT import math -import operator import sage.rings.integer import sage.rings.rational @@ -71,30 +68,6 @@ cimport gmpy2 new_gen_from_real_double_element = None -def is_RealDoubleField(x): - """ - Returns ``True`` if ``x`` is the field of real double precision numbers. - - This function is deprecated. Use :func:`isinstance` with - :class:`~sage.rings.abc.RealDoubleField` instead. - - EXAMPLES:: - - sage: from sage.rings.real_double import is_RealDoubleField - sage: is_RealDoubleField(RDF) - doctest:warning... - DeprecationWarning: is_RealDoubleField is deprecated; - use isinstance(..., sage.rings.abc.RealDoubleField) instead - See https://github.com/sagemath/sage/issues/32610 for details. - True - sage: is_RealDoubleField(RealField(53)) - False - """ - from sage.misc.superseded import deprecation - deprecation(32610, 'is_RealDoubleField is deprecated; use isinstance(..., sage.rings.abc.RealDoubleField) instead') - return isinstance(x, RealDoubleField_class) - - cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): """ An approximation to the field of real numbers using double @@ -106,7 +79,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): EXAMPLES:: - sage: RR == RDF + sage: RR == RDF # needs sage.rings.real_mpfr False sage: RDF == RealDoubleField() # RDF is the shorthand True @@ -131,6 +104,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): numbers and higher-precision ones, though of course there may be loss of precision:: + sage: # needs sage.rings.real_mpfr sage: a = RealField(200)(2).sqrt(); a 1.4142135623730950488016887242096980785696718753769480731767 sage: b = RDF(a); b @@ -191,7 +165,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): EXAMPLES:: - sage: latex(RDF) # indirect doctest + sage: latex(RDF) # indirect doctest \Bold{R} """ return "\\Bold{R}" @@ -217,7 +191,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): EXAMPLES:: - sage: RealDoubleField() # indirect doctest + sage: RealDoubleField() # indirect doctest Real Double Field sage: RDF Real Double Field @@ -284,7 +258,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): EXAMPLES:: - sage: RDF.complex_field() + sage: RDF.complex_field() # needs sage.rings.complex_double Complex Double Field """ from sage.rings.complex_double import CDF @@ -297,7 +271,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): EXAMPLES:: - sage: RDF.algebraic_closure() + sage: RDF.algebraic_closure() # needs sage.rings.complex_double Complex Double Field """ from sage.rings.complex_double import CDF @@ -317,37 +291,37 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): EXAMPLES:: - sage: RDF.coerce(5) # indirect doctest + sage: RDF.coerce(5) # indirect doctest 5.0 sage: RDF.coerce(9499294r) 9499294.0 sage: RDF.coerce(61/3) 20.333333333333332 - sage: parent(RDF(3) + CDF(5)) + sage: parent(RDF(3) + CDF(5)) # needs sage.rings.complex_double Complex Double Field - sage: parent(CDF(5) + RDF(3)) + sage: parent(CDF(5) + RDF(3)) # needs sage.rings.complex_double Complex Double Field - sage: CDF.gen(0) + 5.0 + sage: CDF.gen(0) + 5.0 # needs sage.rings.complex_double 5.0 + 1.0*I sage: RLF(2/3) + RDF(1) 1.6666666666666665 - sage: import numpy - sage: RDF.coerce(numpy.int8('1')) + sage: import numpy # needs numpy + sage: RDF.coerce(numpy.int8('1')) # needs numpy 1.0 - sage: RDF.coerce(numpy.float64('1')) + sage: RDF.coerce(numpy.float64('1')) # needs numpy 1.0 - sage: RDF.coerce(pi) + sage: RDF.coerce(pi) # needs sage.symbolic Traceback (most recent call last): ... TypeError: no canonical coercion from Symbolic Ring to Real Double Field Test that :trac:`15695` is fixed (see also :trac:`18076`):: - sage: 1j + numpy.float64(2) + sage: 1j + numpy.float64(2) # needs numpy 2.00000000000000 + 1.00000000000000*I - sage: parent(_) + sage: parent(_) # needs numpy Complex Field with 53 bits of precision """ if S is int or S is float: @@ -391,7 +365,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): Magma handles precision in decimal digits, so we lose a bit:: - sage: magma(RDF) # optional - magma # indirect doctest + sage: magma(RDF) # indirect doctest # optional - magma Real field of precision 15 sage: 10^15 < 2^53 < 10^16 True @@ -399,7 +373,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): When we convert back from Magma, we convert to a generic real field that has 53 bits of precision:: - sage: magma(RDF).sage() # optional - magma + sage: magma(RDF).sage() # optional - magma Real Field with 53 bits of precision """ return "RealField(%s : Bits := true)" % self.prec() @@ -410,7 +384,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): EXAMPLES:: - sage: fricas(RDF) # indirect doctest, optional - fricas + sage: fricas(RDF) # indirect doctest # optional - fricas DoubleFloat """ return "DoubleFloat" @@ -421,7 +395,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): EXAMPLES:: - sage: polymake(RDF) #optional - jupymake # indirect doctest + sage: polymake(RDF) # indirect doctest # optional - jupymake Float """ return '"Float"' @@ -449,7 +423,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): EXAMPLES:: - sage: RDF.to_prec(52) + sage: RDF.to_prec(52) # needs sage.rings.real_mpfr Real Field with 52 bits of precision sage: RDF.to_prec(53) Real Double Field @@ -652,6 +626,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): TESTS:: + sage: # needs numpy sage: R.<x> = RDF[] sage: RDF._factor_univariate_polynomial(x) x @@ -667,18 +642,19 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): The implementation relies on the ``roots()`` method which often reports roots not to be real even though they are:: - sage: f = (x-1)^3 - sage: f.roots(ring=CDF) # abs tol 2e-5 + sage: f = (x-1)^3 # needs numpy + sage: f.roots(ring=CDF) # abs tol 2e-5 # needs numpy [(1.0000065719436413, 1), (0.9999967140281792 - 5.691454546815028e-06*I, 1), (0.9999967140281792 + 5.691454546815028e-06*I, 1)] This leads to the following incorrect factorization:: - sage: f.factor() # abs tol 2e-5 + sage: f.factor() # abs tol 2e-5 # needs numpy (x - 1.0000065719436413) * (x^2 - 1.9999934280563585*x + 0.9999934280995487) """ - roots = f.roots(sage.rings.complex_double.CDF) + from sage.rings.complex_double import CDF + roots = f.roots(CDF) # collect real roots and conjugate pairs of non-real roots real_roots = [(r, e) for r, e in roots if r.imag().is_zero()] @@ -713,7 +689,7 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: RDF(2.3) # indirect doctest + sage: RDF(2.3) # indirect doctest 2.3 """ (<Element>self)._parent = _RDF @@ -747,7 +723,7 @@ cdef class RealDoubleElement(FieldElement): sage: RDF(10.5) 10.5 - sage: magma(RDF(10.5)) # optional - magma # indirect doctest + sage: magma(RDF(10.5)) # indirect doctest # optional - magma 10.5000000000000 """ return "%s!%s" % (self.parent()._magma_init_(magma), self) @@ -793,13 +769,14 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: a = RDF(pi) - sage: a.ulp() + sage: a = RDF(pi) # needs sage.symbolic + sage: a.ulp() # needs sage.symbolic 4.440892098500626e-16 - sage: b = a + a.ulp() + sage: b = a + a.ulp() # needs sage.symbolic Adding or subtracting an ulp always gives a different number:: + sage: # needs sage.symbolic sage: a + a.ulp() == a False sage: a - a.ulp() == a @@ -815,6 +792,7 @@ cdef class RealDoubleElement(FieldElement): can only happen if the input number is (up to sign) exactly a power of 2:: + sage: # needs sage.symbolic sage: a - a.ulp()/3 == a True sage: a + a.ulp()/3 == a @@ -823,6 +801,7 @@ cdef class RealDoubleElement(FieldElement): True sage: b + b.ulp()/3 == b True + sage: c = RDF(1) sage: c - c.ulp()/3 == c False @@ -930,7 +909,7 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: ZZ(RDF(237.0)) # indirect doctest + sage: ZZ(RDF(237.0)) # indirect doctest 237 sage: ZZ(RDF(0.0/0.0)) Traceback (most recent call last): @@ -947,7 +926,7 @@ cdef class RealDoubleElement(FieldElement): sage: ZZ(RDF(-2345.67)) Traceback (most recent call last): ... - TypeError: Cannot convert non-integral float to integer + TypeError: cannot convert non-integral float to integer """ return Integer(self._value) @@ -980,11 +959,11 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: s1 = RDF(sin(1)); s1 + sage: s1 = RDF(sin(1)); s1 # needs sage.symbolic 0.8414709848078965 - sage: s1._interface_init_() + sage: s1._interface_init_() # needs sage.symbolic '0.8414709848078965' - sage: s1 == RDF(gp(s1)) + sage: s1 == RDF(gp(s1)) # needs sage.libs.pari sage.symbolic True """ return repr(self._value) @@ -1009,7 +988,7 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: sage_input(RDF(NaN)) + sage: sage_input(RDF(NaN)) # needs sage.symbolic RDF(NaN) sage: sage_input(RDF(-infinity), verify=True) # Verified @@ -1017,22 +996,22 @@ cdef class RealDoubleElement(FieldElement): sage: sage_input(RDF(-infinity)*polygen(RDF)) R.<x> = RDF[] -RDF(infinity)*x + RDF(NaN) - sage: sage_input(RDF(pi), verify=True) + sage: sage_input(RDF(pi), verify=True) # needs sage.symbolic # Verified RDF(3.1415926535897931) - sage: sage_input(RDF(-e), verify=True, preparse=False) + sage: sage_input(RDF(-e), verify=True, preparse=False) # needs sage.symbolic # Verified -RDF(2.718281828459045...) - sage: sage_input(RDF(pi)*polygen(RDF), verify=True, preparse=None) + sage: sage_input(RDF(pi)*polygen(RDF), verify=True, preparse=None) # needs sage.symbolic # Verified R = RDF['x'] x = R.gen() 3.1415926535897931*x sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() - sage: RDF(22/7)._sage_input_(sib, True) + sage: RDF(22/7)._sage_input_(sib, True) # needs sage.sage.rings.real_mpfr {atomic:3.1428571428571428} - sage: RDF(22/7)._sage_input_(sib, False) + sage: RDF(22/7)._sage_input_(sib, False) # needs sage.sage.rings.real_mpfr {call: {atomic:RDF}({atomic:3.1428571428571428})} """ cdef bint isinf = libc.math.isinf(self._value) @@ -1133,9 +1112,9 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: latex(RDF(3.4)) # indirect doctest + sage: latex(RDF(3.4)) # indirect doctest 3.4 - sage: latex(RDF(2e-100)) # indirect doctest + sage: latex(RDF(2e-100)) # indirect doctest 2 \times 10^{-100} """ s = self.str() @@ -1170,8 +1149,8 @@ cdef class RealDoubleElement(FieldElement): sage: RDF(2.1)._im_gens_(RR, [RR(1)]) 2.10000000000000 - sage: R = RealField(20) - sage: RDF(2.1)._im_gens_(R, [R(1)]) + sage: R = RealField(20) # needs sage.rings.real_mpfr + sage: RDF(2.1)._im_gens_(R, [R(1)]) # needs sage.rings.real_mpfr 2.1000 """ return codomain(self) # since 1 |--> 1 @@ -1268,24 +1247,25 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: + sage: # needs sage.symbolic sage: a = RDF(exp(1.0)); a 2.718281828459045 - sage: sign,mantissa,exponent = RDF(exp(1.0)).sign_mantissa_exponent() - sage: sign,mantissa,exponent + sage: sign, mantissa, exponent = RDF(exp(1.0)).sign_mantissa_exponent() + sage: sign, mantissa, exponent (1, 6121026514868073, -51) sage: sign*mantissa*(2**exponent) == a True The mantissa is always a nonnegative number:: - sage: RDF(-1).sign_mantissa_exponent() + sage: RDF(-1).sign_mantissa_exponent() # needs sage.rings.real_mpfr (-1, 4503599627370496, -52) TESTS:: - sage: RDF('+0').sign_mantissa_exponent() + sage: RDF('+0').sign_mantissa_exponent() # needs sage.rings.real_mpfr (1, 0, 0) - sage: RDF('-0').sign_mantissa_exponent() + sage: RDF('-0').sign_mantissa_exponent() # needs sage.rings.real_mpfr (-1, 0, 0) """ from sage.rings.real_mpfr import RR @@ -1335,7 +1315,7 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: RDF('-1.5') + RDF('2.5') # indirect doctest + sage: RDF('-1.5') + RDF('2.5') # indirect doctest 1.0 """ cdef RealDoubleElement x = <RealDoubleElement>PY_NEW(RealDoubleElement) @@ -1348,7 +1328,7 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: RDF('-1.5') - RDF('2.5') # indirect doctest + sage: RDF('-1.5') - RDF('2.5') # indirect doctest -4.0 """ cdef RealDoubleElement x = <RealDoubleElement>PY_NEW(RealDoubleElement) @@ -1361,7 +1341,7 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: RDF('-1.5') * RDF('2.5') # indirect doctest + sage: RDF('-1.5') * RDF('2.5') # indirect doctest -3.75 """ cdef RealDoubleElement x = <RealDoubleElement>PY_NEW(RealDoubleElement) @@ -1374,7 +1354,7 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: RDF('-1.5') / RDF('2.5') # indirect doctest + sage: RDF('-1.5') / RDF('2.5') # indirect doctest -0.6 sage: RDF(1)/RDF(0) +infinity @@ -1514,15 +1494,17 @@ cdef class RealDoubleElement(FieldElement): return 1 return -1 - ################### # Rounding etc ################### def round(self): """ - Given real number `x`, rounds up if fractional part is greater than - `0.5`, rounds down if fractional part is less than `0.5`. + Round ``self`` to the nearest integer. + + This uses the convention of rounding half to even + (i.e., if the fractional part of ``self`` is `0.5`, then it + is rounded to the nearest even integer). EXAMPLES:: @@ -1530,6 +1512,10 @@ cdef class RealDoubleElement(FieldElement): 0 sage: a=RDF(0.51).round(); a 1 + sage: RDF(0.5).round() + 0 + sage: RDF(1.5).round() + 2 """ return Integer(round(self._value)) @@ -1646,9 +1632,9 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: sage: a = RDF(1/3) - sage: CC(a) + sage: CC(a) # needs sage.rings.real_mpfr 0.333333333333333 - sage: a._complex_mpfr_field_(CC) + sage: a._complex_mpfr_field_(CC) # needs sage.rings.real_mpfr 0.333333333333333 If we coerce to a higher-precision field the extra bits appear @@ -1656,9 +1642,9 @@ cdef class RealDoubleElement(FieldElement): :: - sage: a._complex_mpfr_field_(ComplexField(100)) + sage: a._complex_mpfr_field_(ComplexField(100)) # needs sage.rings.real_mpfr 0.33333333333333331482961625625 - sage: a._complex_mpfr_field_(ComplexField(100)).str(2) + sage: a._complex_mpfr_field_(ComplexField(100)).str(2) # needs sage.rings.real_mpfr '0.01010101010101010101010101010101010101010101010101010100000000000000000000000000000000000000000000000' """ return CC(self._value) @@ -1669,7 +1655,7 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: CDF(RDF(1/3)) # indirect doctest + sage: CDF(RDF(1/3)) # indirect doctest # needs sage.rings.complex_double 0.3333333333333333 """ return CDF(self._value) @@ -1680,7 +1666,7 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: RDF(1.5).__pari__() + sage: RDF(1.5).__pari__() # needs sage.libs.pari 1.50000000000000 """ global new_gen_from_real_double_element @@ -1688,7 +1674,6 @@ cdef class RealDoubleElement(FieldElement): from sage.libs.pari.convert_sage_real_double import new_gen_from_real_double_element return new_gen_from_real_double_element(self) - ########################################### # Comparisons: ==, !=, <, <=, >, >= ########################################### @@ -1795,7 +1780,6 @@ cdef class RealDoubleElement(FieldElement): else: return x >= y - ############################ # Special Functions ############################ @@ -1845,7 +1829,7 @@ cdef class RealDoubleElement(FieldElement): :: sage: r = RDF(-2.0) - sage: r.sqrt() + sage: r.sqrt() # needs sage.rings.complex_double 1.4142135623730951*I :: @@ -1854,7 +1838,7 @@ cdef class RealDoubleElement(FieldElement): [1.4142135623730951, -1.4142135623730951] sage: RDF(0).sqrt(all=True) [0.0] - sage: RDF(-2).sqrt(all=True) + sage: RDF(-2).sqrt(all=True) # needs sage.rings.complex_double [1.4142135623730951*I, -1.4142135623730951*I] """ if self._value >= 0: @@ -1890,7 +1874,7 @@ cdef class RealDoubleElement(FieldElement): def is_integer(self): """ - Return True if this number is a integer + Return ``True`` if this number is a integer EXAMPLES:: @@ -1968,7 +1952,7 @@ cdef class RealDoubleElement(FieldElement): sage: r = sqrt(RDF(2)); r 1.4142135623730951 - sage: r.algebraic_dependency(5) + sage: r.algebraic_dependency(5) # needs sage.libs.pari x^2 - 2 """ return sage.arith.all.algdep(self,n) @@ -2021,7 +2005,7 @@ cdef class ToRDF(Morphism): EXAMPLES:: sage: f = RDF.coerce_map_from(float) - sage: f(3.5) # indirect doctest + sage: f(3.5) # indirect doctest 3.5 """ cdef RealDoubleElement r = <RealDoubleElement>PY_NEW(RealDoubleElement) @@ -2070,7 +2054,7 @@ def is_RealDoubleElement(x): sage: from sage.rings.real_double import is_RealDoubleElement sage: is_RealDoubleElement(RDF(3)) True - sage: is_RealDoubleElement(RIF(3)) + sage: is_RealDoubleElement(RIF(3)) # needs sage.rings.real_interval_field False """ return isinstance(x, RealDoubleElement) diff --git a/src/sage/rings/real_double_element_gsl.pyx b/src/sage/rings/real_double_element_gsl.pyx index d03c0271d1a..8b6b3671605 100644 --- a/src/sage/rings/real_double_element_gsl.pyx +++ b/src/sage/rings/real_double_element_gsl.pyx @@ -249,7 +249,7 @@ cdef class RealDoubleElement_gsl(RealDoubleElement): 0.6931471805599453 sage: RDF(2).log(2) 1.0 - sage: RDF(2).log(pi) + sage: RDF(2).log(pi) # needs sage.symbolic 0.6055115613982801 sage: RDF(2).log(10) 0.30102999566398114 @@ -334,7 +334,7 @@ cdef class RealDoubleElement_gsl(RealDoubleElement): sage: r = RDF('16.0'); r.log10() 1.2041199826559248 - sage: r.log() / RDF(log(10)) + sage: r.log() / RDF(log(10)) # needs sage.symbolic 1.2041199826559246 sage: r = RDF('39.9'); r.log10() 1.6009728956867482 @@ -355,7 +355,7 @@ cdef class RealDoubleElement_gsl(RealDoubleElement): sage: r = RDF(16); r.logpi() 2.4220462455931204 - sage: r.log() / RDF(log(pi)) + sage: r.log() / RDF(log(pi)) # needs sage.symbolic 2.4220462455931204 sage: r = RDF('39.9'); r.logpi() 3.2203023346075152 @@ -508,11 +508,11 @@ cdef class RealDoubleElement_gsl(RealDoubleElement): EXAMPLES:: - sage: RDF(pi).restrict_angle() + sage: RDF(pi).restrict_angle() # needs sage.symbolic 3.141592653589793 - sage: RDF(pi + 1e-10).restrict_angle() + sage: RDF(pi + 1e-10).restrict_angle() # needs sage.symbolic -3.1415926534897936 - sage: RDF(1+10^10*pi).restrict_angle() + sage: RDF(1+10^10*pi).restrict_angle() # needs sage.symbolic 0.9999977606... """ return self._new_c(gsl_sf_angle_restrict_symm(self._value)) diff --git a/src/sage/rings/real_interval_absolute.pyx b/src/sage/rings/real_interval_absolute.pyx index fb505b5205b..5caf4ac40f1 100644 --- a/src/sage/rings/real_interval_absolute.pyx +++ b/src/sage/rings/real_interval_absolute.pyx @@ -1,3 +1,4 @@ +# sage.doctest: # needs sage.symbolic """ Real intervals with a fixed absolute precision """ @@ -7,7 +8,7 @@ from sage.ext.stdsage cimport PY_NEW from sage.libs.gmp.mpz cimport * from sage.structure.factory import UniqueFactory -from sage.structure.element cimport RingElement, ModuleElement, Element, FieldElement +from sage.structure.element cimport Element, FieldElement from sage.rings.ring cimport Field from sage.rings.integer cimport Integer import sage.rings.abc diff --git a/src/sage/rings/real_interval_field.py b/src/sage/rings/real_interval_field.py deleted file mode 100644 index 7b707cbc1ad..00000000000 --- a/src/sage/rings/real_interval_field.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Field of Arbitrary Precision Real Number Intervals -""" - -from sage.misc.superseded import deprecation -deprecation(24371, "sage.rings.real_interval_field is deprecated") - -from sage.rings.real_mpfi import RealIntervalField_class, RealIntervalFieldElement - -def is_RealIntervalField(x): - """ - Check if ``x`` is a :class:`RealIntervalField_class`. - - EXAMPLES:: - - sage: from sage.rings.real_interval_field import is_RealIntervalField as is_RIF - doctest:...: DeprecationWarning: sage.rings.real_interval_field is deprecated - See https://github.com/sagemath/sage/issues/24371 for details. - sage: is_RIF(RIF) - True - """ - return isinstance(x, RealIntervalField_class) - -def is_RealIntervalFieldElement(x): - """ - Check if ``x`` is a :class:`RealIntervalFieldElement`. - - EXAMPLES:: - - sage: from sage.rings.real_interval_field import is_RealIntervalFieldElement as is_RIFE - sage: is_RIFE(RIF(2.5)) - True - """ - return isinstance(x, RealIntervalFieldElement) - -def __reduce__RealIntervalField(prec, sci_not): - """ - For pickling. - - EXAMPLES:: - - sage: from sage.rings.real_interval_field import __reduce__RealIntervalField - sage: R = RealIntervalField(sci_not=1, prec=200) - sage: __reduce__RealIntervalField(200, 1) == R - True - """ - return RealIntervalField_class(prec, sci_not) - -def __reduce__RealIntervalFieldElement(parent, x, base=10): - """ - For pickling. - - EXAMPLES:: - - sage: from sage.rings.real_interval_field import __reduce__RealIntervalFieldElement - sage: R = RealIntervalField(sci_not=1, prec=200) - sage: elt = R(2.5) - sage: __reduce__RealIntervalFieldElement(R, 2.5) == elt - True - """ - return RealIntervalFieldElement(parent, x, base=base) diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index 3d779b359ce..fb96ae89407 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.real_mpfr """ Lazy real and complex numbers @@ -14,9 +15,9 @@ TESTS: Bug :trac:`21991`:: - sage: a = QuadraticField(5).gen() - sage: u = -573147844013817084101/2*a + 1281597540372340914251/2 - sage: RealIntervalField(128)(RLF(u)).is_exact() + sage: a = QuadraticField(5).gen() # needs sage.rings.number_field + sage: u = -573147844013817084101/2*a + 1281597540372340914251/2 # needs sage.rings.number_field + sage: RealIntervalField(128)(RLF(u)).is_exact() # needs sage.rings.number_field False """ @@ -149,16 +150,16 @@ cdef class LazyField(Field): True sage: RLF.has_coerce_map_from(QQ) True - sage: RLF.has_coerce_map_from(AA) + sage: RLF.has_coerce_map_from(AA) # needs sage.rings.number_field True - sage: CLF.has_coerce_map_from(QQbar) + sage: CLF.has_coerce_map_from(QQbar) # needs sage.rings.number_field True sage: RLF.has_coerce_map_from(RDF) False sage: CLF.has_coerce_map_from(QQ) True - sage: CLF.has_coerce_map_from(QQbar) + sage: CLF.has_coerce_map_from(QQbar) # needs sage.rings.number_field True sage: CLF.has_coerce_map_from(CC) False @@ -406,7 +407,7 @@ class ComplexLazyField_class(LazyField): sage: CLF.interval_field() Complex Interval Field with 53 bits of precision - sage: CLF.interval_field(333) + sage: CLF.interval_field(333) # needs sage.rings.complex_interval_field Complex Interval Field with 333 bits of precision sage: CLF.interval_field() is CIF True @@ -426,7 +427,7 @@ class ComplexLazyField_class(LazyField): sage: CLF.gen() 1*I - sage: ComplexField(100)(CLF.gen()) + sage: ComplexField(100)(CLF.gen()) # needs sage.rings.number_field 1.0000000000000000000000000000*I """ if i == 0: @@ -746,6 +747,7 @@ cdef class LazyFieldElement(FieldElement): When the absolute value is involved, the result might be real:: + sage: # needs sage.symbolic sage: z = exp(CLF(1 + I/2)); z 2.38551673095914? + 1.303213729686996?*I sage: r = z.abs(); r @@ -853,7 +855,7 @@ cdef class LazyFieldElement(FieldElement): TESTS:: - sage: "log" in RLF(sqrt(8)).__dir__() + sage: "log" in RLF(sqrt(8)).__dir__() # needs sage.symbolic True """ @@ -868,7 +870,7 @@ cdef class LazyFieldElement(FieldElement): sage: a = RLF(3) sage: a.sqrt() 1.732050807568878? - sage: sin(a) + sage: sin(a) # needs sage.symbolic 0.1411200080598673? sage: RealField(160)(tanh(RLF(3))) 0.99505475368673045133188018525548847509781385470 @@ -884,6 +886,7 @@ cdef class LazyFieldElement(FieldElement): EXAMPLES:: + sage: # needs sage.symbolic sage: a = RLF(sqrt(2)) + RLF(sqrt(3)) sage: cf = a.continued_fraction() sage: cf @@ -901,8 +904,8 @@ def make_element(parent, *args): EXAMPLES:: - sage: a = RLF(pi) + RLF(sqrt(1/2)) # indirect doctest - sage: bool(loads(dumps(a)) == a) + sage: a = RLF(pi) + RLF(sqrt(1/2)) # indirect doctest # needs sage.symbolic + sage: bool(loads(dumps(a)) == a) # needs sage.symbolic True """ return parent(*args) @@ -1041,8 +1044,8 @@ cdef class LazyWrapper(LazyFieldElement): EXAMPLES:: - sage: a = RLF(sqrt(2)) - sage: a.continued_fraction() + sage: a = RLF(sqrt(2)) # needs sage.symbolic + sage: a.continued_fraction() # needs sage.symbolic [1; 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ...] """ from sage.rings.continued_fraction import ContinuedFraction_real, ContinuedFraction_infinite @@ -1244,7 +1247,7 @@ cdef class LazyUnop(LazyFieldElement): sage: from sage.rings.real_lazy import LazyUnop sage: a = LazyUnop(RLF, 3, sqrt) - sage: a.eval(ZZ) + sage: a.eval(ZZ) # needs sage.symbolic sqrt(3) """ arg = self._arg.eval(R) @@ -1260,7 +1263,7 @@ cdef class LazyUnop(LazyFieldElement): EXAMPLES:: - sage: hash(RLF(sin(1))) == hash(RLF(sin(1))) + sage: hash(RLF(sin(1))) == hash(RLF(sin(1))) # needs sage.symbolic True """ return hash(self._op(hash(self._arg))) @@ -1623,13 +1626,13 @@ cdef class LazyAlgebraic(LazyFieldElement): sage: a = LazyAlgebraic(CLF, QQ['x'].cyclotomic_polynomial(7), 0.6+0.8*CC.0) sage: a 0.6234898018587335? + 0.7818314824680299?*I - sage: ComplexField(150)(a) # indirect doctest + sage: ComplexField(150)(a) # indirect doctest # needs sage.rings.number_field 0.62348980185873353052500488400423981063227473 + 0.78183148246802980870844452667405775023233452*I sage: a = LazyAlgebraic(CLF, QQ['x'].0^2-7, -2.0) - sage: RR(a) + sage: RR(a) # needs sage.rings.number_field -2.64575131106459 - sage: RR(a)^2 + sage: RR(a)^2 # needs sage.rings.number_field 7.00000000000000 """ if isinstance(R, type): @@ -1689,7 +1692,8 @@ cdef class LazyAlgebraic(LazyFieldElement): TESTS:: sage: from sage.rings.real_lazy import LazyAlgebraic - sage: a = LazyAlgebraic(RLF, x^2-2, 1.5) + sage: x = polygen(QQ) + sage: a = LazyAlgebraic(RLF, x^2 - 2, 1.5) sage: float(loads(dumps(a))) == float(a) True """ diff --git a/src/sage/rings/real_mpfi.pxd b/src/sage/rings/real_mpfi.pxd index 959a650aafc..4201788d198 100644 --- a/src/sage/rings/real_mpfi.pxd +++ b/src/sage/rings/real_mpfi.pxd @@ -11,7 +11,7 @@ from .real_mpfr cimport RealField_class cdef class RealIntervalFieldElement(RingElement) # forward decl cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): - cdef mpfr_prec_t __prec + cdef mpfr_prec_t _prec cdef bint sci_not # Cache RealField instances for the lower, upper, and middle bounds. # These have the same precision as the interval field; diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 1f7d7d7f4f8..461b87db869 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -47,7 +47,7 @@ preceding digit is possibly wrong by `\pm 1`. :: - sage: RIF(sqrt(2)) + sage: RIF(sqrt(2)) # needs sage.symbolic 1.414213562373095? However, if the interval is precise (its lower bound is equal to @@ -81,11 +81,11 @@ it is taken to be 1. '125.?2' sage: RIF(123, 127).str(error_digits=1) '125.?2' - sage: v = RIF(-e, pi); v + sage: v = RIF(-e, pi); v # needs sage.symbolic 0.?e1 - sage: v.str(error_digits=1) + sage: v.str(error_digits=1) # needs sage.symbolic '1.?4' - sage: v.str(error_digits=5) + sage: v.str(error_digits=5) # needs sage.symbolic '0.2117?29300' Error digits also sometimes let us indicate that the interval is @@ -230,10 +230,10 @@ specified if given a non-interval and an interval:: TESTS:: - sage: import numpy - sage: RIF(2) == numpy.int8('2') + sage: import numpy # needs numpy + sage: RIF(2) == numpy.int8('2') # needs numpy True - sage: numpy.int8('2') == RIF(2) + sage: numpy.int8('2') == RIF(2) # needs numpy True sage: RIF(0,1) < float('2') Traceback (most recent call last): @@ -264,7 +264,7 @@ from sage.libs.mpfi cimport * from sage.arith.constants cimport LOG_TEN_TWO_PLUS_EPSILON cimport sage.structure.element -from sage.structure.element cimport RingElement, Element, ModuleElement +from sage.structure.element cimport RingElement, Element from sage.structure.element cimport have_same_parent from sage.structure.parent cimport Parent from sage.structure.richcmp cimport richcmp @@ -272,14 +272,10 @@ from sage.structure.richcmp cimport richcmp from .convert.mpfi cimport mpfi_set_sage from .real_mpfr cimport RealField_class, RealNumber, RealField from .integer cimport Integer -from .real_double cimport RealDoubleElement -from .real_double import RDF from .integer_ring import ZZ from .rational_field import QQ -from sage.categories.morphism cimport Map cimport sage.rings.abc -cimport sage.rings.real_mpfr as real_mpfr import math # for log import sys @@ -393,7 +389,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): 3 sage: RIF(RIF(3)) 3 - sage: RIF(pi) + sage: RIF(pi) # needs sage.symbolic 3.141592653589794? sage: RIF(RealField(53)('1.5')) 1.5000000000000000? @@ -456,9 +452,9 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): sage: def check(x): ....: return (x, x.lower() == x.upper()) - sage: check(RIF(pi)) + sage: check(RIF(pi)) # needs sage.symbolic (3.141592653589794?, False) - sage: check(RIF(RR(pi))) + sage: check(RIF(RR(pi))) # needs sage.symbolic (3.1415926535897932?, True) sage: check(RIF(1.5)) (1.5000000000000000?, True) @@ -490,11 +486,11 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): 3 sage: R(R(3)) 3 - sage: R(pi) + sage: R(pi) # needs sage.symbolic 3.14159265358979323846264338328? sage: R(-2/19) -0.1052631578947368421052631578948? - sage: R(e,pi).str(style='brackets') + sage: R(e,pi).str(style='brackets') # needs sage.symbolic '[2.7182818284590452353602874713512 .. 3.1415926535897932384626433832825]' TESTS:: @@ -530,7 +526,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): if prec < MPFR_PREC_MIN or prec > MPFR_PREC_MAX: raise ValueError("prec (=%s) must be >= %s and <= %s." % ( prec, MPFR_PREC_MIN, MPFR_PREC_MAX)) - self.__prec = prec + self._prec = prec self.sci_not = sci_not self.__lower_field = RealField(prec, sci_not, "RNDD") self.__middle_field = RealField(prec, sci_not, "RNDN") @@ -602,7 +598,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): elif rnd == "RNDU": return self.upper_field() else: - return RealField(self.__prec, self.sci_not, rnd) + return RealField(self._prec, self.sci_not, rnd) def _repr_(self): """ @@ -615,7 +611,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): sage: RealIntervalField(200) # indirect doctest Real Interval Field with 200 bits of precision """ - s = "Real Interval Field with %s bits of precision"%self.__prec + s = "Real Interval Field with %s bits of precision"%self._prec return s def _latex_(self): @@ -806,7 +802,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): sage: RIF.has_coerce_map_from(float) False """ - prec = self.__prec + prec = self._prec # Direct and efficient conversions if S is ZZ or S is QQ: @@ -814,7 +810,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): if S is int or S is long: return True if isinstance(S, RealIntervalField_class): - return (<RealIntervalField_class>S).__prec >= prec + return (<RealIntervalField_class>S)._prec >= prec if isinstance(S, sage.rings.abc.NumberField_quadratic): return S.discriminant() > 0 @@ -848,7 +844,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): cdef RealIntervalField_class right left = self right = other # to access C structure - return richcmp(left.__prec, right.__prec, op) + return richcmp(left._prec, right._prec, op) def __reduce__(self): """ @@ -860,7 +856,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): sage: loads(dumps(R)) == R True """ - return __create__RealIntervalField_version0, (self.__prec, self.sci_not) + return __create__RealIntervalField_version0, (self._prec, self.sci_not) def random_element(self, *args, **kwds): """ @@ -1001,7 +997,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): sage: RealIntervalField(200).name() 'IntervalRealIntervalField200' """ - return "IntervalRealIntervalField%s"%(self.__prec) + return "IntervalRealIntervalField%s"%(self._prec) def __hash__(self): """ @@ -1027,7 +1023,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): sage: RealIntervalField(200).precision() 200 """ - return self.__prec + return self._prec prec = precision @@ -1054,7 +1050,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): sage: magma(RealIntervalField(80)) # optional - magma # indirect doctest Real field of precision 24 - sage: floor(RR(log(2**80, 10))) + sage: floor(RR(log(2**80, 10))) # needs sage.symbolic 24 """ return "RealField(%s : Bits := true)" % self.prec() @@ -1191,7 +1187,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: TestSuite(x).run(skip=["_test_eq", "_test_pickling"]) """ cdef RealIntervalField_class p = <RealIntervalField_class?>parent - mpfi_init2(self.value, p.__prec) + mpfi_init2(self.value, p._prec) self._parent = p def __init__(self, parent, x, int base=10): @@ -1284,7 +1280,7 @@ cdef class RealIntervalFieldElement(RingElement): """ return (__create__RealIntervalFieldElement_version1, (self._parent, self.upper(), self.lower())) - def __dealloc__(self): + def __dealloc__(self): """ Deallocate ``self``. @@ -1360,7 +1356,7 @@ cdef class RealIntervalFieldElement(RingElement): error:: sage: a = RealInterval('2.3') - sage: maxima(a) + sage: maxima(a) # needs sage.symbolic Traceback (most recent call last): ... TypeError @@ -1374,10 +1370,11 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: - sage: sage_input(RIF(e, pi), verify=True) + sage: sage_input(RIF(e, pi), verify=True) # needs sage.symbolic # Verified RIF(RR(2.7182818284590451), RR(3.1415926535897936)) - sage: sage_input(RealIntervalField(64)(sqrt(2)), preparse=False, verify=True) + sage: sage_input(RealIntervalField(64)(sqrt(2)), # needs sage.symbolic + ....: preparse=False, verify=True) # Verified RR64 = RealField(64) RealIntervalField(64)(RR64('1.41421356237309504876'), RR64('1.41421356237309504887')) @@ -1390,8 +1387,9 @@ cdef class RealIntervalFieldElement(RingElement): RealIntervalField(2)(RR2(12.), RR2(16.)) sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() - sage: RIF(-sqrt(3), -sqrt(2))._sage_input_(sib, False) - {call: {atomic:RIF}({unop:- {call: {atomic:RR}({atomic:1.7320508075688774})}}, {unop:- {call: {atomic:RR}({atomic:1.4142135623730949})}})} + sage: RIF(-sqrt(3), -sqrt(2))._sage_input_(sib, False) # needs sage.symbolic + {call: {atomic:RIF}({unop:- {call: {atomic:RR}({atomic:1.7320508075688774})}}, + {unop:- {call: {atomic:RR}({atomic:1.4142135623730949})}})} """ # Interval printing could often be much prettier, # but I'm feeling lazy :) @@ -1410,7 +1408,7 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: - sage: hash(RIF(e)) == hash(RIF(e)) # indirect doctest + sage: hash(RIF(e)) == hash(RIF(e)) # indirect doctest # needs sage.symbolic True """ return hash(self.str(16)) @@ -1495,11 +1493,11 @@ cdef class RealIntervalFieldElement(RingElement): ``'brackets'`` style. In question style (the default), we print the "known correct" part of the number, followed by a question mark:: - sage: RIF(pi).str() + sage: RIF(pi).str() # needs sage.symbolic '3.141592653589794?' - sage: RIF(pi, 22/7).str() + sage: RIF(pi, 22/7).str() # needs sage.symbolic '3.142?' - sage: RIF(pi, 22/7).str(style='question') + sage: RIF(pi, 22/7).str(style='question') # needs sage.symbolic '3.142?' However, if the interval is precisely equal to some integer that's @@ -1549,9 +1547,9 @@ cdef class RealIntervalFieldElement(RingElement): We always use brackets style for ``NaN`` and infinities:: - sage: RIF(pi, infinity) + sage: RIF(pi, infinity) # needs sage.symbolic [3.1415926535897931 .. +infinity] - sage: RIF(NaN) + sage: RIF(NaN) # needs sage.symbolic [.. NaN ..] Let's take a closer, formal look at the question style. In its full @@ -1624,11 +1622,11 @@ cdef class RealIntervalFieldElement(RingElement): '3.14223?64' sage: pi_appr.str(base=36) '3.6?' - sage: RIF(NaN) + sage: RIF(NaN) # needs sage.symbolic [.. NaN ..] - sage: RIF(pi, infinity) + sage: RIF(pi, infinity) # needs sage.symbolic [3.1415926535897931 .. +infinity] - sage: RIF(-infinity, pi) + sage: RIF(-infinity, pi) # needs sage.symbolic [-infinity .. 3.1415926535897936] sage: RealIntervalField(210)(3).sqrt() 1.732050807568877293527446341505872366942805253810380628055806980? @@ -1636,7 +1634,7 @@ cdef class RealIntervalFieldElement(RingElement): 1.732050807568878? sage: RIF(3).sqrt() 1.732050807568878? - sage: RIF(0, 3^-150) + sage: RIF(0, 3^-150) # needs sage.symbolic 1.?e-71 TESTS: @@ -1868,7 +1866,7 @@ cdef class RealIntervalFieldElement(RingElement): cdef mp_exp_t self_exp cdef mpz_t self_zz - cdef mpfr_prec_t prec = (<RealIntervalField_class>self._parent).__prec + cdef mpfr_prec_t prec = (<RealIntervalField_class>self._parent)._prec cdef char *zz_str cdef size_t zz_str_maxlen @@ -2315,7 +2313,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: RIF(1,2).endpoints() (1.00000000000000, 2.00000000000000) - sage: RIF(pi).endpoints() + sage: RIF(pi).endpoints() # needs sage.symbolic (3.14159265358979, 3.14159265358980) sage: a = CIF(RIF(1,2), RIF(3,4)) sage: a.real().endpoints() @@ -2346,7 +2344,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: RIF(1,2).edges() (1, 2) - sage: RIF(pi).edges() + sage: RIF(pi).edges() # needs sage.symbolic (3.1415926535897932?, 3.1415926535897936?) """ left = self._new() @@ -2367,7 +2365,7 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: - sage: RIF(1, pi).absolute_diameter() + sage: RIF(1, pi).absolute_diameter() # needs sage.symbolic 2.14159265358979 """ cdef RealNumber x @@ -2382,7 +2380,7 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: - sage: RIF(1, pi).relative_diameter() + sage: RIF(1, pi).relative_diameter() # needs sage.symbolic 1.03418797197910 """ cdef RealNumber x @@ -2403,6 +2401,8 @@ cdef class RealIntervalFieldElement(RingElement): 1.00000000000000 sage: RIF(1, 2).relative_diameter() 0.666666666666667 + + sage: # needs sage.symbolic sage: RIF(pi).diameter() 1.41357985842823e-16 sage: RIF(pi).absolute_diameter() @@ -2435,16 +2435,18 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: - sage: RIF(pi).fp_rank_diameter() - 1 sage: RIF(12345).fp_rank_diameter() 0 - sage: RIF(-sqrt(2)).fp_rank_diameter() - 1 sage: RIF(5/8).fp_rank_diameter() 0 sage: RIF(5/7).fp_rank_diameter() 1 + + sage: # needs sage.symbolic + sage: RIF(pi).fp_rank_diameter() + 1 + sage: RIF(-sqrt(2)).fp_rank_diameter() + 1 sage: a = RIF(pi)^12345; a 2.06622879260?e6137 sage: a.fp_rank_diameter() @@ -2456,10 +2458,10 @@ cdef class RealIntervalFieldElement(RingElement): Just because we have the best possible interval, doesn't mean the interval is actually small:: - sage: a = RIF(pi)^12345678901234567890; a + sage: a = RIF(pi)^12345678901234567890; a # needs sage.symbolic [2.0985787164673874e323228496 .. +infinity] # 32-bit [5.8756537891115869e1388255822130839282 .. +infinity] # 64-bit - sage: a.fp_rank_diameter() + sage: a.fp_rank_diameter() # needs sage.symbolic 1 """ return self.lower().fp_rank_delta(self.upper()) @@ -2473,7 +2475,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: RIF(3).is_exact() True - sage: RIF(2*pi).is_exact() + sage: RIF(2*pi).is_exact() # needs sage.symbolic False """ return mpfr_equal_p(&self.value.left, &self.value.right) @@ -2547,6 +2549,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: b.lower(), b.upper() (1.50000000000000, 2.00000000000000) + sage: # needs sage.symbolic sage: I = RIF(e, pi) sage: a, b = I.bisection() sage: a.intersection(b) == RIF(I.center()) @@ -2935,8 +2938,9 @@ cdef class RealIntervalFieldElement(RingElement): def __rshift__(x, y): """ - Returns `x / 2^y`, for `y` an integer. Much faster - than an ordinary division. + Return `x / 2^y`, for `y` an integer. + + Much faster than an ordinary division. EXAMPLES:: @@ -2980,7 +2984,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: RealIntervalField(200)(2.1).precision() 200 """ - return (<RealIntervalField_class>self._parent).__prec + return (<RealIntervalField_class>self._parent)._prec prec = precision @@ -3375,9 +3379,9 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: - sage: RIF(pi).unique_floor() + sage: RIF(pi).unique_floor() # needs sage.symbolic 3 - sage: RIF(100*pi).unique_floor() + sage: RIF(100*pi).unique_floor() # needs sage.symbolic 314 sage: RIF(100, 200).unique_floor() Traceback (most recent call last): @@ -3406,9 +3410,9 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: - sage: RIF(pi).unique_ceil() + sage: RIF(pi).unique_ceil() # needs sage.symbolic 4 - sage: RIF(100*pi).unique_ceil() + sage: RIF(100*pi).unique_ceil() # needs sage.symbolic 315 sage: RIF(100, 200).unique_ceil() Traceback (most recent call last): @@ -3437,9 +3441,9 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: - sage: RIF(pi).unique_round() + sage: RIF(pi).unique_round() # needs sage.symbolic 3 - sage: RIF(1000*pi).unique_round() + sage: RIF(1000*pi).unique_round() # needs sage.symbolic 3142 sage: RIF(100, 200).unique_round() Traceback (most recent call last): @@ -3451,7 +3455,7 @@ cdef class RealIntervalFieldElement(RingElement): ValueError: interval does not have a unique round (nearest integer) sage: RIF(0.7, 1.2).unique_round() 1 - sage: RIF(-pi).unique_round() + sage: RIF(-pi).unique_round() # needs sage.symbolic -3 sage: (RIF(4.5).unique_round(), RIF(-4.5).unique_round()) (5, -5) @@ -3524,13 +3528,13 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: - sage: RIF(pi).unique_integer() + sage: RIF(pi).unique_integer() # needs sage.symbolic Traceback (most recent call last): ... ValueError: interval contains no integer - sage: RIF(pi, pi+1).unique_integer() + sage: RIF(pi, pi+1).unique_integer() # needs sage.symbolic 4 - sage: RIF(pi, pi+2).unique_integer() + sage: RIF(pi, pi+2).unique_integer() # needs sage.symbolic Traceback (most recent call last): ... ValueError: interval contains more than one integer @@ -3580,9 +3584,9 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: - sage: RealIntervalField(10)(pi).simplest_rational() + sage: RealIntervalField(10)(pi).simplest_rational() # needs sage.symbolic 22/7 - sage: RealIntervalField(20)(pi).simplest_rational() + sage: RealIntervalField(20)(pi).simplest_rational() # needs sage.symbolic 355/113 sage: RIF(0.123, 0.567).simplest_rational() 1/2 @@ -3831,7 +3835,7 @@ cdef class RealIntervalFieldElement(RingElement): True sage: RIF(0) == RIF(0) True - sage: RIF(pi) == RIF(pi) + sage: RIF(pi) == RIF(pi) # needs sage.symbolic False sage: RIF(0, 1) == RIF(1, 2) False @@ -3855,7 +3859,7 @@ cdef class RealIntervalFieldElement(RingElement): False sage: RIF(0) != RIF(0) False - sage: RIF(pi) != RIF(pi) + sage: RIF(pi) != RIF(pi) # needs sage.symbolic False sage: RIF(0, 1) != RIF(1, 2) False @@ -3986,7 +3990,7 @@ cdef class RealIntervalFieldElement(RingElement): True sage: 1.0 in RIF(0, 2) True - sage: pi in RIF(3.1415, 3.1416) + sage: pi in RIF(3.1415, 3.1416) # needs sage.symbolic True sage: 22/7 in RIF(3.1415, 3.1416) False @@ -4118,7 +4122,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: a = RIF(-1, 1).min(0).endpoints() sage: a[0] == -1.0 and a[1].abs() == 0.0 # in MPFI, the sign of 0.0 is not specified True - sage: RIF(-1, 1).min(pi).endpoints() + sage: RIF(-1, 1).min(pi).endpoints() # needs sage.symbolic (-1.00000000000000, 1.00000000000000) sage: RIF(-1, 1).min(RIF(-100, 100)).endpoints() (-100.000000000000, 1.00000000000000) @@ -4403,10 +4407,10 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: sage: R = RealIntervalField(17) - sage: x = R((-e,pi)) - sage: x2 = x^2; x2.lower(), x2.upper() + sage: x = R((-e, pi)) # needs sage.symbolic + sage: x2 = x^2; x2.lower(), x2.upper() # needs sage.symbolic (0.0000, 9.870) - sage: x3 = x^3; x3.lower(), x3.upper() + sage: x3 = x^3; x3.lower(), x3.upper() # needs sage.symbolic (-26.83, 31.01) """ if exponent == 2: @@ -4619,7 +4623,8 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: - sage: t=RIF(pi)/2 + sage: # needs sage.symbolic + sage: t = RIF(pi)/2 sage: t.cos() 0.?e-15 sage: t.cos().str(style='brackets') @@ -5073,7 +5078,7 @@ cdef class RealIntervalFieldElement(RingElement): (2.00000000000000, 6.00000000000000) sage: RIF(-1/2).gamma() -3.54490770181104? - sage: gamma(-1/2).n(100) in RIF(-1/2).gamma() + sage: gamma(-1/2).n(100) in RIF(-1/2).gamma() # needs sage.symbolic True sage: RIF1000 = RealIntervalField(1000) sage: 0 in (RIF1000(RealField(2000)(-19/3).gamma()) - RIF1000(-19/3).gamma()) @@ -5356,7 +5361,8 @@ def __create__RealIntervalField_version0(prec, sci_not): """ return RealIntervalField(prec, sci_not) -## Keep all old versions!!! + +# Keep all old versions!!! def __create__RealIntervalFieldElement_version0(parent, x, base=10): """ For pickling. @@ -5368,6 +5374,7 @@ def __create__RealIntervalFieldElement_version0(parent, x, base=10): """ return RealIntervalFieldElement(parent, x, base=base) + def __create__RealIntervalFieldElement_version1(parent, lower, upper): """ For pickling. diff --git a/src/sage/rings/real_mpfr.pxd b/src/sage/rings/real_mpfr.pxd index 3549eccfd03..dd18e87715b 100644 --- a/src/sage/rings/real_mpfr.pxd +++ b/src/sage/rings/real_mpfr.pxd @@ -9,7 +9,7 @@ from sage.libs.mpfr.types cimport mpfr_prec_t cdef class RealNumber(sage.structure.element.RingElement) # forward decl cdef class RealField_class(sage.rings.abc.RealField): - cdef mpfr_prec_t __prec + cdef mpfr_prec_t _prec cdef bint sci_not cdef mpfr_rnd_t rnd cdef object rnd_str diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index 421f489a559..a78680d0ee2 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -132,9 +132,9 @@ from sage.misc.randstate cimport randstate, current_randstate from sage.cpython.string cimport char_to_str, str_to_bytes from sage.misc.superseded import deprecation_cython as deprecation -from sage.structure.element cimport RingElement, Element, ModuleElement +from sage.structure.element cimport Element from sage.structure.element cimport have_same_parent -from sage.structure.richcmp cimport rich_to_bool_sgn, rich_to_bool +from sage.structure.richcmp cimport rich_to_bool_sgn cdef bin_op from sage.structure.element import bin_op @@ -153,10 +153,6 @@ from .rational cimport Rational from sage.categories.map cimport Map -cdef ZZ, QQ, RDF -from .integer_ring import ZZ -from .rational_field import QQ -from .real_double import RDF from .real_double cimport RealDoubleElement import sage.rings.rational_field @@ -528,7 +524,7 @@ cdef class RealField_class(sage.rings.abc.RealField): if prec < MPFR_PREC_MIN or prec > MPFR_PREC_MAX: raise ValueError("prec (=%s) must be >= %s and <= %s" % ( prec, MPFR_PREC_MIN, MPFR_PREC_MAX)) - self.__prec = prec + self._prec = prec self.sci_not = sci_not self.rnd = <mpfr_rnd_t>rnd @@ -565,7 +561,7 @@ cdef class RealField_class(sage.rings.abc.RealField): sage: RealField(17,rnd='RNDD') # indirect doctest Real Field with 17 bits of precision and rounding RNDD """ - s = "Real Field with %s bits of precision"%self.__prec + s = "Real Field with %s bits of precision"%self._prec if self.rnd != MPFR_RNDN: s = s + " and rounding %s"%(self.rnd_str) return s @@ -658,7 +654,7 @@ cdef class RealField_class(sage.rings.abc.RealField): Traceback (most recent call last): ... ValueError: can only convert signed infinity to RR - sage: R(CIF(NaN)) + sage: R(CIF(NaN)) # needs sage.symbolic NaN sage: R(complex(1.7)) 1.7000 @@ -723,23 +719,27 @@ cdef class RealField_class(sage.rings.abc.RealField): TESTS:: - sage: 1.0 - ZZ(1) - int(1) - 1 - QQ(1) - RealField(100)(1) - AA(1) - RLF(1) + sage: 1.0 - ZZ(1) - int(1) - 1 - QQ(1) - RealField(100)(1) - AA(1) - RLF(1) # needs sage.rings.number_field -6.00000000000000 sage: R = RR['x'] # Hold reference to avoid garbage collection, see Issue #24709 sage: R.get_action(ZZ) Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Real Field with 53 bits of precision """ + from .integer_ring import ZZ + from .rational_field import QQ + from .real_double import RDF + if S is ZZ: return ZZtoRR(ZZ, self) elif S is QQ: return QQtoRR(QQ, self) - elif (S is RDF or S is float) and self.__prec <= 53: + elif (S is RDF or S is float) and self._prec <= 53: return double_toRR(S, self) elif S is long: return int_toRR(long, self) elif S is int: return int_toRR(int, self) - elif isinstance(S, RealField_class) and S.prec() >= self.__prec: + elif isinstance(S, RealField_class) and S.prec() >= self._prec: return RRtoRR(S, self) elif QQ.has_coerce_map_from(S): return QQtoRR(QQ, self) * QQ._internal_coerce_map_from(S) @@ -786,7 +786,7 @@ cdef class RealField_class(sage.rings.abc.RealField): return NotImplemented _other = <RealField_class>other # to access C structure - return (self.__prec == _other.__prec and + return (self._prec == _other._prec and self.rnd == _other.rnd) == (op == Py_EQ) def __reduce__(self): @@ -799,7 +799,7 @@ cdef class RealField_class(sage.rings.abc.RealField): sage: loads(dumps(R)) == R True """ - return __create__RealField_version0, (self.__prec, self.sci_not, self.rnd_str) + return __create__RealField_version0, (self._prec, self.sci_not, self.rnd_str) def construction(self): r""" @@ -968,7 +968,7 @@ cdef class RealField_class(sage.rings.abc.RealField): sage: RealField(100,rnd='RNDU').name() 'RealField100_2' """ - return "RealField%s_%s"%(self.__prec,self.rnd) + return "RealField%s_%s"%(self._prec,self.rnd) def __hash__(self): """ @@ -995,7 +995,7 @@ cdef class RealField_class(sage.rings.abc.RealField): sage: RealField(20).precision() 20 """ - return Integer(self.__prec) + return Integer(self._prec) prec=precision # an alias @@ -1031,7 +1031,7 @@ cdef class RealField_class(sage.rings.abc.RealField): sage: R.to_prec(300) Real Field with 300 bits of precision and rounding RNDZ """ - if prec == self.__prec: + if prec == self._prec: return self else: return RealField(prec, self.sci_not, self.rnd) @@ -1052,7 +1052,7 @@ cdef class RealField_class(sage.rings.abc.RealField): 0.88622692545275801364908374167057259139877473 """ cdef RealNumber x = self._new() - if self.__prec > SIG_PREC_THRESHOLD: sig_on() + if self._prec > SIG_PREC_THRESHOLD: sig_on() # The docs for mpfr_free_cache say "Free the cache used by # the functions computing constants if needed (currently # mpfr_const_log2, mpfr_const_pi and mpfr_const_euler)", so @@ -1062,7 +1062,7 @@ cdef class RealField_class(sage.rings.abc.RealField): # functions, but this free is needed for them too! mpfr_free_cache() mpfr_const_pi(x.value, self.rnd) - if self.__prec > SIG_PREC_THRESHOLD: sig_off() + if self._prec > SIG_PREC_THRESHOLD: sig_off() return x def euler_constant(self): @@ -1091,10 +1091,10 @@ cdef class RealField_class(sage.rings.abc.RealField): 0.91596559417721901505460351493 """ cdef RealNumber x = self._new() - if self.__prec > SIG_PREC_THRESHOLD: sig_on() + if self._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_free_cache() mpfr_const_catalan(x.value, self.rnd) - if self.__prec > SIG_PREC_THRESHOLD: sig_off() + if self._prec > SIG_PREC_THRESHOLD: sig_off() return x def log2(self): @@ -1111,10 +1111,10 @@ cdef class RealField_class(sage.rings.abc.RealField): 0.69314718055994530941723212146 """ cdef RealNumber x = self._new() - if self.__prec > SIG_PREC_THRESHOLD: sig_on() + if self._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_free_cache() mpfr_const_log2(x.value, self.rnd) - if self.__prec > SIG_PREC_THRESHOLD: sig_off() + if self._prec > SIG_PREC_THRESHOLD: sig_off() return x def random_element(self, min=-1, max=1, distribution=None): @@ -1181,9 +1181,9 @@ cdef class RealField_class(sage.rings.abc.RealField): if n < 0: raise ArithmeticError("n must be nonnegative") x = self._new() - if self.__prec > SIG_PREC_THRESHOLD and n < SIG_PREC_THRESHOLD: sig_on() + if self._prec > SIG_PREC_THRESHOLD and n < SIG_PREC_THRESHOLD: sig_on() mpfr_fac_ui(x.value, n, self.rnd) - if self.__prec > SIG_PREC_THRESHOLD and n < SIG_PREC_THRESHOLD: sig_off() + if self._prec > SIG_PREC_THRESHOLD and n < SIG_PREC_THRESHOLD: sig_off() return x def rounding_mode(self): @@ -1346,7 +1346,7 @@ cdef class RealNumber(sage.structure.element.RingElement): NaN """ cdef RealField_class p = <RealField_class?>parent - mpfr_init2(self.value, p.__prec) + mpfr_init2(self.value, p._prec) self._parent = p def __init__(self, parent, x=0, int base=10): @@ -1438,6 +1438,7 @@ cdef class RealNumber(sage.structure.element.RingElement): EXAMPLES:: + sage: # needs numpy sage: import numpy sage: numpy.arange(10.0) array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]) @@ -1446,7 +1447,7 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: numpy.array([1.000000000000000000000000000000000000]).dtype dtype('O') """ - if (<RealField_class>self._parent).__prec <= 53: + if (<RealField_class>self._parent)._prec <= 53: return numpy_double_interface else: return numpy_object_interface @@ -1570,7 +1571,7 @@ cdef class RealNumber(sage.structure.element.RingElement): s = self.str(32, no_sci=False, e='@') return (__create__RealNumber_version0, (self._parent, s, 32)) - def __dealloc__(self): + def __dealloc__(self): if self._parent is not None: mpfr_clear(self.value) @@ -1604,7 +1605,7 @@ cdef class RealNumber(sage.structure.element.RingElement): 'Infinity' sage: format(RR(-oo), '.4') '-Infinity' - sage: format(RR(NaN), '.4') + sage: format(RR(NaN), '.4') # needs sage.symbolic 'NaN' sage: '{}'.format(RR(oo)) '+infinity' @@ -1652,11 +1653,11 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: n = 1.3939494594 sage: n._interface_init_() '1.3939494593999999' - sage: s1 = RR(sin(1)); s1 + sage: s1 = RR(sin(1)); s1 # needs sage.symbolic 0.841470984807897 - sage: s1._interface_init_() + sage: s1._interface_init_() # needs sage.symbolic '0.84147098480789650' - sage: s1 == RR(gp(s1)) + sage: s1 == RR(gp(s1)) # needs sage.symbolic True """ return self.str(10, no_sci=True) @@ -1680,6 +1681,8 @@ cdef class RealNumber(sage.structure.element.RingElement): EXAMPLES:: + sage: values = [-infinity, -20, 0, 1, 2^500, -2^4000, -2^-500, 2^-4000] + sage: values += [NaN, -e] # needs sage.symbolic sage: for prec in (2, 53, 200): ....: for rnd_dir in ('RNDN', 'RNDD', 'RNDU', 'RNDZ'): ....: fld = RealField(prec, rnd=rnd_dir) @@ -1694,7 +1697,7 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: RR60 = RealField(60) sage: RR(-infinity)._sage_input_(sib, True) {unop:- {call: {atomic:RR}({atomic:Infinity})}} - sage: RR(NaN)._sage_input_(sib, True) + sage: RR(NaN)._sage_input_(sib, True) # needs sage.symbolic {call: {atomic:RR}({atomic:NaN})} sage: RR(12345)._sage_input_(sib, True) {atomic:12345} @@ -1712,9 +1715,9 @@ cdef class RealNumber(sage.structure.element.RingElement): {call: {atomic:RR}({atomic:1.579})} sage: RR(1.579)._sage_input_(sib_np, 2) {atomic:1.579} - sage: RealField(150)(pi)._sage_input_(sib, True) + sage: RealField(150)(pi)._sage_input_(sib, True) # needs sage.symbolic {atomic:3.1415926535897932384626433832795028841971694008} - sage: RealField(150)(pi)._sage_input_(sib_np, True) + sage: RealField(150)(pi)._sage_input_(sib_np, True) # needs sage.symbolic {call: {call: {atomic:RealField}({atomic:150})}({atomic:'3.1415926535897932384626433832795028841971694008'})} """ # We have a bewildering array of conditions to deal with: @@ -1872,6 +1875,8 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: RealField(100)(2).imag() 0 """ + from .integer_ring import ZZ + return ZZ(0) def str(self, int base=10, size_t digits=0, *, no_sci=None, @@ -2073,7 +2078,7 @@ cdef class RealNumber(sage.structure.element.RingElement): # This avoids the confusion a lot of people have with the last # 1-2 binary digits being wrong due to rounding coming from # representing numbers in binary. - digits = <size_t>(((<RealField_class>self._parent).__prec - 1) * M_LN2_LN10) + digits = <size_t>(((<RealField_class>self._parent)._prec - 1) * M_LN2_LN10) if digits < 2: digits = 2 @@ -2247,7 +2252,7 @@ cdef class RealNumber(sage.structure.element.RingElement): 100000000000000000 """ if not mpfr_number_p(self.value): - raise ValueError('Cannot convert infinity or NaN to Sage Integer') + raise ValueError('cannot convert infinity or NaN to Sage Integer') cdef Integer z = Integer() mpfr_get_z(z.value, self.value, MPFR_RNDZ) @@ -2301,7 +2306,7 @@ cdef class RealNumber(sage.structure.element.RingElement): if sgn == 0: return z - cdef mpfr_prec_t prec = (<RealField_class>self._parent).__prec + cdef mpfr_prec_t prec = (<RealField_class>self._parent)._prec if mpfr_inf_p(self.value): mpz_set_ui(z.value, EXP_MAX+1-EXP_MIN) @@ -2334,7 +2339,7 @@ cdef class RealNumber(sage.structure.element.RingElement): EXAMPLES:: - sage: [x.fp_rank_delta(x.nextabove()) for x in + sage: [x.fp_rank_delta(x.nextabove()) for x in # needs sage.symbolic ....: (RR(-infinity), -1.0, 0.0, 1.0, RR(pi), RR(infinity))] [1, 1, 1, 1, 1, 0] @@ -2383,7 +2388,10 @@ cdef class RealNumber(sage.structure.element.RingElement): """ if have_same_parent(left, right): return (<RealNumber> left)._add_(right) - from .real_mpfi import RealIntervalFieldElement + try: + from .real_mpfi import RealIntervalFieldElement + except ImportError: + RealIntervalFieldElement = None if type(right) is RealIntervalFieldElement: return right.__add__(left) elif isinstance(left, RealNumber): @@ -2404,7 +2412,10 @@ cdef class RealNumber(sage.structure.element.RingElement): """ if have_same_parent(left, right): return (<RealNumber> left)._sub_(right) - from .real_mpfi import RealIntervalFieldElement + try: + from .real_mpfi import RealIntervalFieldElement + except ImportError: + RealIntervalFieldElement = None if type(right) is RealIntervalFieldElement: return (-right).__add__(left) elif isinstance(left, RealNumber): @@ -2425,7 +2436,10 @@ cdef class RealNumber(sage.structure.element.RingElement): """ if have_same_parent(left, right): return (<RealNumber> left)._mul_(right) - from .real_mpfi import RealIntervalFieldElement + try: + from .real_mpfi import RealIntervalFieldElement + except ImportError: + RealIntervalFieldElement = None if type(right) is RealIntervalFieldElement: return right.__mul__(left) elif isinstance(left, RealNumber): @@ -2446,7 +2460,10 @@ cdef class RealNumber(sage.structure.element.RingElement): """ if have_same_parent(left, right): return (<RealNumber> left)._div_(right) - from .real_mpfi import RealIntervalFieldElement + try: + from .real_mpfi import RealIntervalFieldElement + except ImportError: + RealIntervalFieldElement = None if type(right) is RealIntervalFieldElement: return right.__rtruediv__(left) elif isinstance(left, RealNumber): @@ -2503,22 +2520,22 @@ cdef class RealNumber(sage.structure.element.RingElement): EXAMPLES:: - sage: RealField(100)(1/7)._sympy_() + sage: RealField(100)(1/7)._sympy_() # needs sympy 0.14285714285714285714285714286 - sage: type(_) + sage: type(_) # needs sympy <class 'sympy.core.numbers.Float'> TESTS: An indirect doctest to check this (see :trac:`14915`):: - sage: x,y = var('x, y') - sage: integrate(y, y, 0.5, 8*log(x), algorithm='sympy') + sage: x,y = var('x, y') # needs sage.symbolic + sage: integrate(y, y, 0.5, 8*log(x), algorithm='sympy') # needs sympy sage.symbolic 32*log(x)^2 - 0.125000000000000 Check that :trac:`28903` is fixed:: - sage: (10.0^400)._sympy_() + sage: (10.0^400)._sympy_() # needs sympy 1.00000000000000e+400 """ import sympy @@ -2755,7 +2772,7 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: RealField(101)(-1).precision() 101 """ - return Integer((<RealField_class>self._parent).__prec) + return Integer((<RealField_class>self._parent)._prec) prec = precision # alias @@ -2990,8 +3007,12 @@ cdef class RealNumber(sage.structure.element.RingElement): def round(self): """ - Rounds ``self`` to the nearest integer. The rounding mode of the - parent field has no effect on this function. + Round ``self`` to the nearest representable integer, rounding halfway + cases away from zero. + + .. NOTE:: + + The rounding mode of the parent field does not affect the result. EXAMPLES:: @@ -3120,11 +3141,11 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: RR(infinity).nexttoward(0) 2.09857871646739e323228496 # 32-bit 5.87565378911159e1388255822130839282 # 64-bit - sage: RR(pi).str() + sage: RR(pi).str() # needs sage.symbolic '3.1415926535897931' - sage: RR(pi).nexttoward(22/7).str() + sage: RR(pi).nexttoward(22/7).str() # needs sage.symbolic '3.1415926535897936' - sage: RR(pi).nexttoward(21/7).str() + sage: RR(pi).nexttoward(21/7).str() # needs sage.symbolic '3.1415926535897927' """ cdef RealNumber other_rn @@ -3154,9 +3175,9 @@ cdef class RealNumber(sage.structure.element.RingElement): 8.50969131174084e-1388255822130839284 # 64-bit sage: RR('+infinity').nextabove() +infinity - sage: RR(-sqrt(2)).str() + sage: RR(-sqrt(2)).str() # needs sage.symbolic '-1.4142135623730951' - sage: RR(-sqrt(2)).nextabove().str() + sage: RR(-sqrt(2)).nextabove().str() # needs sage.symbolic '-1.4142135623730949' """ @@ -3180,9 +3201,9 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: RR('+infinity').nextbelow() 2.09857871646739e323228496 # 32-bit 5.87565378911159e1388255822130839282 # 64-bit - sage: RR(-sqrt(2)).str() + sage: RR(-sqrt(2)).str() # needs sage.symbolic '-1.4142135623730951' - sage: RR(-sqrt(2)).nextbelow().str() + sage: RR(-sqrt(2)).nextbelow().str() # needs sage.symbolic '-1.4142135623730954' """ @@ -3202,9 +3223,9 @@ cdef class RealNumber(sage.structure.element.RingElement): EXAMPLES:: - sage: RR(pi).__float__() + sage: RR(pi).__float__() # needs sage.symbolic 3.141592653589793 - sage: type(RR(pi).__float__()) + sage: type(RR(pi).__float__()) # needs sage.symbolic <... 'float'> """ return mpfr_get_d(self.value, (<RealField_class>self._parent).rnd) @@ -3230,13 +3251,13 @@ cdef class RealNumber(sage.structure.element.RingElement): EXAMPLES:: - sage: RR(pi).__int__() + sage: RR(pi).__int__() # needs sage.symbolic 3 - sage: type(RR(pi).__int__()) + sage: type(RR(pi).__int__()) # needs sage.symbolic <... 'int'> """ if not mpfr_number_p(self.value): - raise ValueError('Cannot convert infinity or NaN to Python int') + raise ValueError('cannot convert infinity or NaN to Python int') cdef Integer z = Integer() mpfr_get_z(z.value, self.value, MPFR_RNDZ) @@ -3248,9 +3269,9 @@ cdef class RealNumber(sage.structure.element.RingElement): EXAMPLES:: - sage: RR(pi).__complex__() + sage: RR(pi).__complex__() # needs sage.symbolic (3.141592653589793+0j) - sage: type(RR(pi).__complex__()) + sage: type(RR(pi).__complex__()) # needs sage.symbolic <... 'complex'> """ @@ -3262,9 +3283,9 @@ cdef class RealNumber(sage.structure.element.RingElement): EXAMPLES:: - sage: RR(pi)._complex_number_() + sage: RR(pi)._complex_number_() # needs sage.symbolic 3.14159265358979 - sage: parent(RR(pi)._complex_number_()) + sage: parent(RR(pi)._complex_number_()) # needs sage.symbolic Complex Field with 53 bits of precision """ from sage.rings.complex_mpfr import ComplexField @@ -3276,12 +3297,13 @@ cdef class RealNumber(sage.structure.element.RingElement): EXAMPLES:: + sage: # needs sage.symbolic sage: R = RealField(100) sage: R(pi) 3.1415926535897932384626433833 - sage: axiom(R(pi)) # optional - axiom # indirect doctest + sage: axiom(R(pi)) # indirect doctest # optional - axiom 3.1415926535 8979323846 26433833 - sage: fricas(R(pi)) # optional - fricas + sage: fricas(R(pi)) # optional - fricas 3.1415926535_8979323846_26433833 """ @@ -3302,13 +3324,14 @@ cdef class RealNumber(sage.structure.element.RingElement): EXAMPLES:: - sage: RR(2.0).__pari__() + sage: RR(2.0).__pari__() # needs sage.libs.pari 2.00000000000000 The current Pari precision affects the printing of this number, but Pari does maintain the same 250-bit number on both 32-bit and 64-bit platforms:: + sage: # needs sage.libs.pari sage: RealField(250).pi().__pari__() 3.14159265358979 sage: RR(0.0).__pari__() @@ -3321,7 +3344,7 @@ cdef class RealNumber(sage.structure.element.RingElement): 1.41421356237309515 sage: RR(2.0).sqrt().__pari__().sage().prec() 64 - sage: RealField(70)(pi).__pari__().sage().prec() + sage: RealField(70)(pi).__pari__().sage().prec() # needs sage.symbolic 96 # 32-bit 128 # 64-bit sage: for i in range(100, 200): @@ -3331,14 +3354,15 @@ cdef class RealNumber(sage.structure.element.RingElement): Check that we create real zeros without mantissa:: - sage: RDF(0).__pari__().sizeword() + sage: RDF(0).__pari__().sizeword() # needs sage.libs.pari 2 - sage: RealField(100)(0.0).__pari__().sizeword() + sage: RealField(100)(0.0).__pari__().sizeword() # needs sage.libs.pari 2 Check that the largest and smallest exponents representable by PARI convert correctly:: + sage: # needs sage.libs.pari sage: a = pari(0.5) << (sys.maxsize+1)/4 sage: RR(a) >> (sys.maxsize+1)/4 0.500000000000000 @@ -3352,13 +3376,13 @@ cdef class RealNumber(sage.structure.element.RingElement): # as subject-to-change. if mpfr_nan_p(self.value) or mpfr_inf_p(self.value): - raise ValueError('Cannot convert NaN or infinity to Pari float') + raise ValueError('cannot convert NaN or infinity to Pari float') # wordsize for PARI cdef unsigned long wordsize = sizeof(long)*8 cdef mpfr_prec_t prec - prec = (<RealField_class>self._parent).__prec + prec = (<RealField_class>self._parent)._prec # We round up the precision to the nearest multiple of wordsize. cdef int rounded_prec @@ -3498,7 +3522,7 @@ cdef class RealNumber(sage.structure.element.RingElement): 42391158275216203520420085760 sage: RR(3^60).exact_rational() - 3^60 6125652559 - sage: RealField(5)(-pi).exact_rational() + sage: RealField(5)(-pi).exact_rational() # needs sage.symbolic -25/8 TESTS:: @@ -3602,9 +3626,9 @@ cdef class RealNumber(sage.structure.element.RingElement): -1/3 sage: check(RR(-1/3)) -1/3 - sage: check(RealField(20)(pi)) + sage: check(RealField(20)(pi)) # needs sage.symbolic 355/113 - sage: check(RR(pi)) + sage: check(RR(pi)) # needs sage.symbolic 245850922/78256779 sage: check(RR(2).sqrt()) 131836323/93222358 @@ -3678,14 +3702,14 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: RR('nan').simplest_rational() Traceback (most recent call last): ... - ValueError: Cannot convert NaN or infinity to rational number + ValueError: cannot convert NaN or infinity to rational number sage: RR('-infinity').simplest_rational() Traceback (most recent call last): ... - ValueError: Cannot convert NaN or infinity to rational number + ValueError: cannot convert NaN or infinity to rational number """ if not mpfr_number_p(self.value): - raise ValueError('Cannot convert NaN or infinity to rational number') + raise ValueError('cannot convert NaN or infinity to rational number') if mpfr_zero_p(self.value): return Rational(0) @@ -3693,7 +3717,7 @@ cdef class RealNumber(sage.structure.element.RingElement): from .real_mpfi import RealIntervalField cdef mpfr_rnd_t rnd = (<RealField_class>self._parent).rnd - cdef mpfr_prec_t prec = (<RealField_class>self._parent).__prec + cdef mpfr_prec_t prec = (<RealField_class>self._parent)._prec cdef RealNumber low, high cdef int odd @@ -3768,6 +3792,8 @@ cdef class RealNumber(sage.structure.element.RingElement): -333/1000 sage: RR(3/4).nearby_rational(max_denominator=2) 1 + + sage: # needs sage.symbolic sage: RR(pi).nearby_rational(max_denominator=120) 355/113 sage: RR(pi).nearby_rational(max_denominator=10000) @@ -3776,6 +3802,7 @@ cdef class RealNumber(sage.structure.element.RingElement): 312689/99532 sage: RR(pi).nearby_rational(max_denominator=1) 3 + sage: RR(-3.5).nearby_rational(max_denominator=1) -3 @@ -3784,23 +3811,23 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: RR('nan').nearby_rational(max_denominator=1000) Traceback (most recent call last): ... - ValueError: Cannot convert NaN or infinity to rational number + ValueError: cannot convert NaN or infinity to rational number sage: RR('nan').nearby_rational(max_error=0.01) Traceback (most recent call last): ... - ValueError: Cannot convert NaN or infinity to rational number + ValueError: cannot convert NaN or infinity to rational number sage: RR(oo).nearby_rational(max_denominator=1000) Traceback (most recent call last): ... - ValueError: Cannot convert NaN or infinity to rational number + ValueError: cannot convert NaN or infinity to rational number sage: RR(oo).nearby_rational(max_error=0.01) Traceback (most recent call last): ... - ValueError: Cannot convert NaN or infinity to rational number + ValueError: cannot convert NaN or infinity to rational number """ if not mpfr_number_p(self.value): - raise ValueError('Cannot convert NaN or infinity to rational number') + raise ValueError('cannot convert NaN or infinity to rational number') if ((max_error is None and max_denominator is None) or (max_error is not None and max_denominator is not None)): @@ -4078,7 +4105,7 @@ cdef class RealNumber(sage.structure.element.RingElement): True sage: RR('-100').is_real() True - sage: RR(NaN).is_real() + sage: RR(NaN).is_real() # needs sage.symbolic False """ return not mpfr_nan_p(self.value) @@ -4223,7 +4250,7 @@ cdef class RealNumber(sage.structure.element.RingElement): :: sage: r = 4344 - sage: r.sqrt() + sage: r.sqrt() # needs sage.symbolic 2*sqrt(1086) :: @@ -4243,9 +4270,9 @@ cdef class RealNumber(sage.structure.element.RingElement): cdef RealNumber x if mpfr_cmp_ui(self.value, 0) >= 0: x = self._new() - if (<RealField_class>self._parent).__prec > 10*SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > 10*SIG_PREC_THRESHOLD: sig_on() mpfr_sqrt(x.value, self.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > 10*SIG_PREC_THRESHOLD: sig_off() + if (<RealField_class>self._parent)._prec > 10*SIG_PREC_THRESHOLD: sig_off() if all: if x.is_zero(): return [x] @@ -4289,12 +4316,12 @@ cdef class RealNumber(sage.structure.element.RingElement): -1.42108547152020e-14 """ cdef RealNumber x = self._new() - if (<RealField_class>self._parent).__prec > 10*SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > 10*SIG_PREC_THRESHOLD: sig_on() mpfr_cbrt(x.value, self.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > 10*SIG_PREC_THRESHOLD: sig_off() + if (<RealField_class>self._parent)._prec > 10*SIG_PREC_THRESHOLD: sig_off() return x - def __pow(self, RealNumber exponent): + def _pow(self, RealNumber exponent): """ Compute ``self`` raised to the power of exponent, rounded in the direction specified by the parent of ``self``. @@ -4303,7 +4330,7 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: R = RealField(30) sage: a = R('1.23456') - sage: a.__pow(20.0) + sage: a._pow(20.0) 67.646297 """ cdef RealNumber x @@ -4339,10 +4366,10 @@ cdef class RealNumber(sage.structure.element.RingElement): We raise a real number to a symbolic object:: - sage: x, y = var('x,y') - sage: 1.5^x + sage: x, y = var('x,y') # needs sage.symbolic + sage: 1.5^x # needs sage.symbolic 1.50000000000000^x - sage: -2.3^(x+y^3+sin(x)) + sage: -2.3^(x+y^3+sin(x)) # needs sage.symbolic -2.30000000000000^(y^3 + x + sin(x)) TESTS: @@ -4400,21 +4427,21 @@ cdef class RealNumber(sage.structure.element.RingElement): 0.693147180559945 sage: log(RR(2), "e") 0.693147180559945 - sage: log(RR(2), e) + sage: log(RR(2), e) # needs sage.symbolic 0.693147180559945 :: sage: r = R(-1); r.log() 3.14159265358979*I - sage: log(RR(-1),e) + sage: log(RR(-1), e) # needs sage.symbolic 3.14159265358979*I sage: r.log(2) 4.53236014182719*I For the error value NaN (Not A Number), log will return NaN:: - sage: r = R(NaN); r.log() + sage: r = R(NaN); r.log() # needs sage.symbolic NaN """ @@ -4429,9 +4456,9 @@ cdef class RealNumber(sage.structure.element.RingElement): return self._complex_number_().log(base) if base is None or base == 'e': x = self._new() - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_log(x.value, self.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_off() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_off() return x elif base == 10: return self.log10() @@ -4470,9 +4497,9 @@ cdef class RealNumber(sage.structure.element.RingElement): if self < 0: return self._complex_number_().log(2) x = self._new() - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_log2(x.value, self.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_off() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_off() return x def log10(self): @@ -4507,9 +4534,9 @@ cdef class RealNumber(sage.structure.element.RingElement): if self < 0: return self._complex_number_().log(10) x = self._new() - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_log10(x.value, self.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_off() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_off() return x def log1p(self): @@ -4556,9 +4583,9 @@ cdef class RealNumber(sage.structure.element.RingElement): if self < -1: return (self+1.0)._complex_number_().log() x = self._new() - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_log1p(x.value, self.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_off() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_off() return x def exp(self): @@ -4614,9 +4641,9 @@ cdef class RealNumber(sage.structure.element.RingElement): 1.89117248253021e-10 """ cdef RealNumber x = self._new() - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_exp2(x.value, self.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_off() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_off() return x def exp10(self): @@ -4642,9 +4669,9 @@ cdef class RealNumber(sage.structure.element.RingElement): 5.01187233627276e-33 """ cdef RealNumber x = self._new() - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_exp10(x.value, self.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_off() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_off() return x def expm1(self): @@ -4666,9 +4693,9 @@ cdef class RealNumber(sage.structure.element.RingElement): 1.00000000000000e-16 """ cdef RealNumber x = self._new() - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_expm1(x.value, self.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_off() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_off() return x def eint(self): @@ -4688,9 +4715,9 @@ cdef class RealNumber(sage.structure.element.RingElement): -0.219383934395520 """ cdef RealNumber x = self._new() - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_eint(x.value, self.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_on() return x def cos(self): @@ -5103,8 +5130,8 @@ cdef class RealNumber(sage.structure.element.RingElement): :: sage: m = (a-b)^2/(a+b)^2 - sage: E = numerical_integral(1/sqrt(1-m*sin(x)^2), 0, RR.pi()/2)[0] - sage: RR.pi()/4 * (a+b)/E + sage: E = numerical_integral(1/sqrt(1-m*sin(x)^2), 0, RR.pi()/2)[0] # needs sage.symbolic + sage: RR.pi()/4 * (a+b)/E # needs sage.symbolic 1.96811775182478 TESTS:: @@ -5119,9 +5146,9 @@ cdef class RealNumber(sage.structure.element.RingElement): _other = self._parent(other) x = self._new() - if (<RealField_class>self._parent).__prec > 10000: sig_on() + if (<RealField_class>self._parent)._prec > 10000: sig_on() mpfr_agm(x.value, self.value, _other.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > 10000: sig_off() + if (<RealField_class>self._parent)._prec > 10000: sig_off() return x def erf(self): @@ -5274,9 +5301,9 @@ cdef class RealNumber(sage.structure.element.RingElement): 0.886226925452758 """ cdef RealNumber x = self._new() - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_on() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_gamma(x.value, self.value, (<RealField_class>self._parent).rnd) - if (<RealField_class>self._parent).__prec > SIG_PREC_THRESHOLD: sig_off() + if (<RealField_class>self._parent)._prec > SIG_PREC_THRESHOLD: sig_off() return x def log_gamma(self): @@ -5300,10 +5327,10 @@ cdef class RealNumber(sage.structure.element.RingElement): cdef RealNumber x = self._new() parent = (<RealField_class>self._parent) if not mpfr_sgn(self.value) < 0: - if parent.__prec > SIG_PREC_THRESHOLD: + if parent._prec > SIG_PREC_THRESHOLD: sig_on() mpfr_lngamma(x.value, self.value, parent.rnd) - if parent.__prec > SIG_PREC_THRESHOLD: + if parent._prec > SIG_PREC_THRESHOLD: sig_off() return x from sage.libs.mpmath.utils import call @@ -5334,11 +5361,11 @@ cdef class RealNumber(sage.structure.element.RingElement): Computing zeta using PARI is much more efficient in difficult cases. Here's how to compute zeta with at least a given precision:: - sage: z = pari(2).zeta(precision=53); z + sage: z = pari(2).zeta(precision=53); z # needs sage.libs.pari 1.64493406684823 - sage: pari(2).zeta(precision=128).sage().prec() + sage: pari(2).zeta(precision=128).sage().prec() # needs sage.libs.pari 128 - sage: pari(2).zeta(precision=65).sage().prec() + sage: pari(2).zeta(precision=65).sage().prec() # needs sage.libs.pari 128 # 64-bit 96 # 32-bit @@ -5350,9 +5377,9 @@ cdef class RealNumber(sage.structure.element.RingElement): :: - sage: type(z) + sage: type(z) # needs sage.libs.pari <class 'cypari2.gen.Gen'> - sage: R(z) + sage: R(z) # needs sage.libs.pari 1.64493406684823 """ cdef RealNumber x = self._new() @@ -5505,8 +5532,11 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: check(RealField(20)(22/7), 19) [1.0621, 1.0621, 1.0622, 1.0621] - sage: check(RealField(200)(e), 4) - [1.2840254166877414840734205680624364583362808652814630892175, 1.2840254166877414840734205680624364583362808652814630892175, 1.2840254166877414840734205680624364583362808652814630892176, 1.2840254166877414840734205680624364583362808652814630892175] + sage: check(RealField(200)(e), 4) # needs sage.symbolic + [1.2840254166877414840734205680624364583362808652814630892175, + 1.2840254166877414840734205680624364583362808652814630892175, + 1.2840254166877414840734205680624364583362808652814630892176, + 1.2840254166877414840734205680624364583362808652814630892175] Check that :trac:`12105` is fixed:: @@ -5528,7 +5558,7 @@ cdef class RealNumber(sage.structure.element.RingElement): cdef RealField_class fld = <RealField_class>self._parent - if algorithm == 0 and n <= 10000 / fld.__prec: + if algorithm == 0 and n <= 10000 / fld._prec: # This is a rough estimate for when it is probably # faster to call mpfr directly. (This is a pretty # good estimate on one particular machine, a @@ -5633,7 +5663,7 @@ cdef class RealNumber(sage.structure.element.RingElement): from .real_mpfi import RealIntervalField - cdef mpfr_prec_t prec = fld.__prec + 10 + cdef mpfr_prec_t prec = fld._prec + 10 cdef RealNumber lower cdef RealNumber upper @@ -5854,21 +5884,20 @@ def create_RealNumber(s, int base=10, int pad=0, rnd="RNDN", int min_prec=53): # Check for a valid base if base < 2 or base > 62: - raise ValueError("base (=%s) must be an integer between 2 and 62"%base) + raise ValueError(f"base (={base}) must be an integer between 2 and 62") if base == 10 and min_prec == 53 and len(s) <= 15 and rnd == "RNDN": R = RR else: # For bases 15 and up, treat 'e' as digit if base <= 14 and ('e' in s or 'E' in s): - #Figure out the exponent - index = max( s.find('e'), s.find('E') ) - exponent = int(s[index+1:]) + # Figure out the exponent + index = max(s.find('e'), s.find('E')) mantissa = s[:index] else: mantissa = s - #Find the first nonzero entry in rest + # Find the first nonzero entry in rest sigfig_mantissa = mantissa.lstrip('-0.') sigfigs = len(sigfig_mantissa) - ('.' in sigfig_mantissa) @@ -5883,29 +5912,6 @@ def create_RealNumber(s, int base=10, int pad=0, rnd="RNDN", int min_prec=53): return RealLiteral(R, s, base) -def is_RealField(x): - """ - Returns ``True`` if ``x`` is technically of a Python real field type. - - This function is deprecated. Use :func:`isinstance` with - :class:`~sage.rings.abc.RealField` instead. - - EXAMPLES:: - - sage: sage.rings.real_mpfr.is_RealField(RR) - doctest:warning... - DeprecationWarning: is_RealField is deprecated; - use isinstance(..., sage.rings.abc.RealField) instead - See https://github.com/sagemath/sage/issues/32610 for details. - True - sage: sage.rings.real_mpfr.is_RealField(CC) - False - """ - from sage.misc.superseded import deprecation - deprecation(32610, 'is_RealField is deprecated; use isinstance(..., sage.rings.abc.RealField) instead') - return isinstance(x, RealField_class) - - def is_RealNumber(x): """ Return ``True`` if ``x`` is of type :class:`RealNumber`, meaning that it @@ -5920,7 +5926,7 @@ def is_RealNumber(x): False sage: is_RealNumber(RDF(2)) False - sage: is_RealNumber(pi) + sage: is_RealNumber(pi) # needs sage.symbolic False """ return isinstance(x, RealNumber) @@ -6093,24 +6099,6 @@ cdef class int_toRR(Map): return y -def create_RealField(*args, **kwds): - r""" - Deprecated function moved to :mod:`sage.rings.real_field`. - - TESTS:: - - sage: from sage.rings.real_mpfr import create_RealField - sage: create_RealField() - doctest:...: DeprecationWarning: Please import create_RealField from sage.rings.real_field - See https://github.com/sagemath/sage/issues/24511 for details. - Real Field with 53 bits of precision - """ - #deprecation has already been imported in this file - deprecation(24511, "Please import create_RealField from sage.rings.real_field") - from sage.rings.real_field import create_RealField as cr - return cr(*args, **kwds) - - # Support Python's numbers abstract base class import numbers numbers.Real.register(RealNumber) diff --git a/src/sage/rings/ring.pxd b/src/sage/rings/ring.pxd index 9384f39f258..1322697688f 100644 --- a/src/sage/rings/ring.pxd +++ b/src/sage/rings/ring.pxd @@ -7,7 +7,7 @@ cdef class Ring(ParentWithGens): cdef public object _one_element cdef public object _zero_ideal cdef public object _unit_ideal - cdef public object __ideal_monoid + cdef public object _ideal_monoid cdef class CommutativeRing(Ring): diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index e806637c38a..5273891a5b0 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -132,9 +132,9 @@ cdef class Ring(ParentWithGens): running ._test_some_elements() . . . pass running ._test_zero() . . . pass running ._test_zero_divisors() . . . pass - sage: TestSuite(QQ['x','y']).run(skip='_test_elements') - sage: TestSuite(ZZ['x','y']).run(skip='_test_elements') - sage: TestSuite(ZZ['x','y']['t']).run() + sage: TestSuite(QQ['x','y']).run(skip='_test_elements') # needs sage.libs.singular + sage: TestSuite(ZZ['x','y']).run(skip='_test_elements') # needs sage.libs.singular + sage: TestSuite(ZZ['x','y']['t']).run() # needs sage.libs.singular Test against another bug fixed in :trac:`9944`:: @@ -142,36 +142,38 @@ cdef class Ring(ParentWithGens): Join of Category of euclidean domains and Category of commutative algebras over (number fields and quotient fields and metric spaces) and Category of infinite sets sage: QQ['x','y'].category() - Join of Category of unique factorization domains and Category of commutative algebras over - (number fields and quotient fields and metric spaces) and Category of infinite sets - sage: PolynomialRing(MatrixSpace(QQ,2),'x').category() + Join of Category of unique factorization domains + and Category of commutative algebras + over (number fields and quotient fields and metric spaces) + and Category of infinite sets + sage: PolynomialRing(MatrixSpace(QQ, 2),'x').category() # needs sage.modules Category of infinite algebras over (finite dimensional algebras with basis over (number fields and quotient fields and metric spaces) and infinite sets) - sage: PolynomialRing(SteenrodAlgebra(2),'x').category() + sage: PolynomialRing(SteenrodAlgebra(2),'x').category() # needs sage.combinat sage.modules Category of infinite algebras over (super hopf algebras with basis over Finite Field of size 2 and supercocommutative super coalgebras over Finite Field of size 2) TESTS:: - sage: Zp(7)._repr_option('element_is_atomic') + sage: Zp(7)._repr_option('element_is_atomic') # needs sage.rings.padics False sage: QQ._repr_option('element_is_atomic') True - sage: CDF._repr_option('element_is_atomic') + sage: CDF._repr_option('element_is_atomic') # needs sage.rings.complex_double False Check that categories correctly implement `is_finite` and `cardinality`:: sage: QQ.is_finite() False - sage: GF(2^10,'a').is_finite() + sage: GF(2^10, 'a').is_finite() # needs sage.rings.finite_rings True sage: R.<x> = GF(7)[] sage: R.is_finite() False - sage: S.<y> = R.quo(x^2+1) - sage: S.is_finite() + sage: S.<y> = R.quo(x^2 + 1) # needs sage.rings.finite_rings + sage: S.is_finite() # needs sage.rings.finite_rings True sage: Integers(7).cardinality() @@ -280,7 +282,7 @@ cdef class Ring(ParentWithGens): EXAMPLES:: - sage: FreeAlgebra(QQ, 3, 'x').category() # todo: use a ring which is not an algebra! + sage: FreeAlgebra(QQ, 3, 'x').category() # todo: use a ring which is not an algebra! # needs sage.combinat sage.modules Category of algebras with basis over Rational Field Since a quotient of the integers is its own base ring, and during @@ -310,24 +312,28 @@ cdef class Ring(ParentWithGens): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: F.<x,y,z> = FreeAlgebra(ZZ, 3) - sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F + sage: I = F * [x*y + y*z, x^2 + x*y - y*x - y^2] * F sage: Q = F.quotient(I) sage: Q.ideal_monoid() - Monoid of ideals of Quotient of Free Algebra on 3 generators (x, y, z) over Integer Ring by the ideal (x*y + y*z, x^2 + x*y - y*x - y^2) + Monoid of ideals of Quotient of Free Algebra on 3 generators (x, y, z) + over Integer Ring by the ideal (x*y + y*z, x^2 + x*y - y*x - y^2) sage: F.<x,y,z> = FreeAlgebra(ZZ, implementation='letterplace') - sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F + sage: I = F * [x*y + y*z, x^2 + x*y - y*x - y^2] * F sage: Q = F.quo(I) sage: Q.ideal_monoid() - Monoid of ideals of Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Integer Ring by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) + Monoid of ideals of Quotient of Free Associative Unital Algebra + on 3 generators (x, y, z) over Integer Ring + by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) """ - if self.__ideal_monoid is not None: - return self.__ideal_monoid + if self._ideal_monoid is not None: + return self._ideal_monoid else: from sage.rings.noncommutative_ideals import IdealMonoid_nc M = IdealMonoid_nc(self) - self.__ideal_monoid = M + self._ideal_monoid = M return M def ideal(self, *args, **kwds): @@ -363,10 +369,10 @@ cdef class Ring(ParentWithGens): Here is an example over a non-commutative ring:: - sage: A = SteenrodAlgebra(2) - sage: A.ideal(A.1,A.2^2) + sage: A = SteenrodAlgebra(2) # needs sage.combinat sage.modules + sage: A.ideal(A.1, A.2^2) # needs sage.combinat sage.modules Twosided Ideal (Sq(2), Sq(2,2)) of mod 2 Steenrod algebra, milnor basis - sage: A.ideal(A.1,A.2^2,side='left') + sage: A.ideal(A.1, A.2^2, side='left') # needs sage.combinat sage.modules Left Ideal (Sq(2), Sq(2,2)) of mod 2 Steenrod algebra, milnor basis TESTS: @@ -446,19 +452,22 @@ cdef class Ring(ParentWithGens): EXAMPLES:: sage: R.<x,y,z> = GF(7)[] - sage: (x+y)*R - Ideal (x + y) of Multivariate Polynomial Ring in x, y, z over Finite Field of size 7 - sage: (x+y,z+y^3)*R - Ideal (x + y, y^3 + z) of Multivariate Polynomial Ring in x, y, z over Finite Field of size 7 + sage: (x + y) * R + Ideal (x + y) of Multivariate Polynomial Ring in x, y, z + over Finite Field of size 7 + sage: (x + y, z + y^3) * R + Ideal (x + y, y^3 + z) of Multivariate Polynomial Ring in x, y, z + over Finite Field of size 7 The following was implemented in :trac:`7797`:: + sage: # needs sage.combinat sage.modules sage: A = SteenrodAlgebra(2) - sage: A*[A.1+A.2,A.1^2] + sage: A * [A.1 + A.2, A.1^2] Left Ideal (Sq(2) + Sq(4), Sq(1,1)) of mod 2 Steenrod algebra, milnor basis - sage: [A.1+A.2,A.1^2]*A + sage: [A.1 + A.2, A.1^2] * A Right Ideal (Sq(2) + Sq(4), Sq(1,1)) of mod 2 Steenrod algebra, milnor basis - sage: A*[A.1+A.2,A.1^2]*A + sage: A * [A.1 + A.2, A.1^2] * A Twosided Ideal (Sq(2) + Sq(4), Sq(1,1)) of mod 2 Steenrod algebra, milnor basis """ @@ -519,21 +528,21 @@ cdef class Ring(ParentWithGens): sage: R.<x,y> = GF(5)[] sage: R._ideal_class_(1) <class 'sage.rings.polynomial.multi_polynomial_ideal.MPolynomialIdeal'> - sage: S = R.quo(x^3-y^2) + sage: S = R.quo(x^3 - y^2) sage: S._ideal_class_(1) <class 'sage.rings.quotient_ring.QuotientRingIdeal_principal'> sage: S._ideal_class_(2) <class 'sage.rings.quotient_ring.QuotientRingIdeal_generic'> - sage: T.<z> = S[] - sage: T._ideal_class_(5) + sage: T.<z> = S[] # needs sage.rings.finite_rings + sage: T._ideal_class_(5) # needs sage.rings.finite_rings <class 'sage.rings.ideal.Ideal_generic'> - sage: T._ideal_class_(1) + sage: T._ideal_class_(1) # needs sage.rings.finite_rings <class 'sage.rings.ideal.Ideal_principal'> Since :trac:`7797`, non-commutative rings have ideals as well:: - sage: A = SteenrodAlgebra(2) - sage: A._ideal_class_() + sage: A = SteenrodAlgebra(2) # needs sage.combinat sage.modules + sage: A._ideal_class_() # needs sage.combinat sage.modules <class 'sage.rings.noncommutative_ideals.Ideal_nc'> """ @@ -571,7 +580,7 @@ cdef class Ring(ParentWithGens): EXAMPLES:: - sage: Zp(7).unit_ideal() + sage: Zp(7).unit_ideal() # needs sage.rings.padics Principal ideal (1 + O(7^20)) of 7-adic Ring with capped relative precision 20 """ if self._unit_ideal is None: @@ -602,6 +611,7 @@ cdef class Ring(ParentWithGens): Make sure that :trac:`13644` is fixed:: + sage: # needs sage.rings.padics sage: K = Qp(3) sage: R.<a> = K[] sage: L.<a> = K.extension(a^2-3) @@ -673,8 +683,8 @@ cdef class Ring(ParentWithGens): True sage: QQ['x,y,z'].is_commutative() True - sage: Q.<i,j,k> = QuaternionAlgebra(QQ, -1,-1) - sage: Q.is_commutative() + sage: Q.<i,j,k> = QuaternionAlgebra(QQ, -1, -1) # needs sage.combinat sage.modules + sage: Q.is_commutative() # needs sage.combinat sage.modules False """ if self.is_zero(): @@ -701,7 +711,7 @@ cdef class Ring(ParentWithGens): sage: QQ.is_field() True - sage: GF(9,'a').is_field() + sage: GF(9, 'a').is_field() # needs sage.rings.finite_rings True sage: ZZ.is_field() False @@ -713,12 +723,12 @@ cdef class Ring(ParentWithGens): This illustrates the use of the ``proof`` parameter:: sage: R.<a,b> = QQ[] - sage: S.<x,y> = R.quo((b^3)) - sage: S.is_field(proof = True) + sage: S.<x,y> = R.quo((b^3)) # needs sage.libs.singular + sage: S.is_field(proof=True) # needs sage.libs.singular Traceback (most recent call last): ... NotImplementedError - sage: S.is_field(proof = False) + sage: S.is_field(proof=False) # needs sage.libs.singular False """ if self.is_zero(): @@ -745,9 +755,9 @@ cdef class Ring(ParentWithGens): True sage: ZZ.is_exact() True - sage: Qp(7).is_exact() + sage: Qp(7).is_exact() # needs sage.rings.padics False - sage: Zp(7, type='capped-abs').is_exact() + sage: Zp(7, type='capped-abs').is_exact() # needs sage.rings.padics False """ return True @@ -772,21 +782,22 @@ cdef class Ring(ParentWithGens): True sage: QQ.is_subring(GF(7)) False - sage: QQ.is_subring(CyclotomicField(7)) + sage: QQ.is_subring(CyclotomicField(7)) # needs sage.rings.number_field True sage: QQ.is_subring(ZZ) False Every ring is a subring of itself, :trac:`17287`:: - sage: QQbar.is_subring(QQbar) + sage: QQbar.is_subring(QQbar) # needs sage.rings.number_field True sage: RR.is_subring(RR) True - sage: CC.is_subring(CC) + sage: CC.is_subring(CC) # needs sage.rings.real_mpfr True - sage: K.<a> = NumberField(x^3-x+1/10) - sage: K.is_subring(K) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - x + 1/10) # needs sage.rings.number_field + sage: K.is_subring(K) # needs sage.rings.number_field True sage: R.<x> = RR[] sage: R.is_subring(R) @@ -810,13 +821,13 @@ cdef class Ring(ParentWithGens): True sage: GF(3).is_prime_field() True - sage: GF(9,'a').is_prime_field() + sage: GF(9, 'a').is_prime_field() # needs sage.rings.finite_rings False sage: ZZ.is_prime_field() False sage: QQ['x'].is_prime_field() False - sage: Qp(19).is_prime_field() + sage: Qp(19).is_prime_field() # needs sage.rings.padics False """ return False @@ -847,46 +858,46 @@ cdef class Ring(ParentWithGens): True sage: Integers(8).is_integral_domain() False - sage: Zp(7).is_integral_domain() + sage: Zp(7).is_integral_domain() # needs sage.rings.padics True - sage: Qp(7).is_integral_domain() + sage: Qp(7).is_integral_domain() # needs sage.rings.padics True sage: R.<a,b> = QQ[] - sage: S.<x,y> = R.quo((b^3)) - sage: S.is_integral_domain() + sage: S.<x,y> = R.quo((b^3)) # needs sage.libs.singular + sage: S.is_integral_domain() # needs sage.libs.singular False This illustrates the use of the ``proof`` parameter:: sage: R.<a,b> = ZZ[] - sage: S.<x,y> = R.quo((b^3)) - sage: S.is_integral_domain(proof = True) + sage: S.<x,y> = R.quo((b^3)) # needs sage.libs.singular + sage: S.is_integral_domain(proof=True) # needs sage.libs.singular Traceback (most recent call last): ... NotImplementedError - sage: S.is_integral_domain(proof = False) + sage: S.is_integral_domain(proof=False) # needs sage.libs.singular False TESTS: Make sure :trac:`10481` is fixed:: - sage: var('x') - x - sage: R.<a> = ZZ['x'].quo(x^2) - sage: R.fraction_field() + sage: x = polygen(ZZ, 'x') + sage: R.<a> = ZZ['x'].quo(x^2) # needs sage.libs.pari + sage: R.fraction_field() # needs sage.libs.pari Traceback (most recent call last): ... TypeError: self must be an integral domain. - sage: R.is_integral_domain() + sage: R.is_integral_domain() # needs sage.libs.pari False Forward the proof flag to ``is_field``, see :trac:`22910`:: + sage: # needs sage.libs.singular sage: R1.<x> = GF(5)[] - sage: F1 = R1.quotient_ring(x^2+x+1) + sage: F1 = R1.quotient_ring(x^2 + x + 1) sage: R2.<x> = F1[] - sage: F2 = R2.quotient_ring(x^2+x+1) + sage: F2 = R2.quotient_ring(x^2 + x + 1) sage: F2.is_integral_domain(False) False """ @@ -952,12 +963,14 @@ cdef class Ring(ParentWithGens): -1 sage: QQ.zeta(1) 1 - sage: CyclotomicField(6).zeta(6) + sage: CyclotomicField(6).zeta(6) # needs sage.rings.number_field zeta6 - sage: CyclotomicField(3).zeta(3) + sage: CyclotomicField(3).zeta(3) # needs sage.rings.number_field zeta3 - sage: CyclotomicField(3).zeta(3).multiplicative_order() + sage: CyclotomicField(3).zeta(3).multiplicative_order() # needs sage.rings.number_field 3 + + sage: # needs sage.rings.finite_rings sage: a = GF(7).zeta(); a 3 sage: a.multiplicative_order() @@ -970,11 +983,12 @@ cdef class Ring(ParentWithGens): 6 sage: a.multiplicative_order() 2 + sage: QQ.zeta(3) Traceback (most recent call last): ... ValueError: no n-th root of unity in rational field - sage: Zp(7, prec=8).zeta() + sage: Zp(7, prec=8).zeta() # needs sage.rings.padics 3 + 4*7 + 6*7^2 + 3*7^3 + 2*7^5 + 6*7^6 + 2*7^7 + O(7^8) TESTS:: @@ -984,7 +998,7 @@ cdef class Ring(ParentWithGens): 1 sage: Ring.zeta(QQ, 2) -1 - sage: Ring.zeta(QQ, 3) + sage: Ring.zeta(QQ, 3) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: no 3rd root of unity in Rational Field @@ -1021,13 +1035,13 @@ cdef class Ring(ParentWithGens): EXAMPLES:: - sage: CyclotomicField(19).zeta_order() + sage: CyclotomicField(19).zeta_order() # needs sage.rings.number_field 38 sage: GF(19).zeta_order() 18 - sage: GF(5^3,'a').zeta_order() + sage: GF(5^3,'a').zeta_order() # needs sage.rings.finite_rings 124 - sage: Zp(7, prec=8).zeta_order() + sage: Zp(7, prec=8).zeta_order() # needs sage.rings.padics 6 """ return self.zeta().multiplicative_order() @@ -1101,12 +1115,12 @@ cdef class Ring(ParentWithGens): sage: R.<x>=QQ[]; R.ideal_monoid() Monoid of ideals of Univariate Polynomial Ring in x over Rational Field """ - if self.__ideal_monoid is not None: - return self.__ideal_monoid + if self._ideal_monoid is not None: + return self._ideal_monoid else: from sage.rings.ideal_monoid import IdealMonoid M = IdealMonoid(self) - self.__ideal_monoid = M + self._ideal_monoid = M return M @cached_method @@ -1118,9 +1132,9 @@ cdef class Ring(ParentWithGens): sage: RDF.epsilon() 2.220446049250313e-16 - sage: ComplexField(53).epsilon() + sage: ComplexField(53).epsilon() # needs sage.rings.real_mpfr 2.22044604925031e-16 - sage: RealField(10).epsilon() + sage: RealField(10).epsilon() # needs sage.rings.real_mpfr 0.0020 For exact rings, zero is returned:: @@ -1130,14 +1144,14 @@ cdef class Ring(ParentWithGens): This also works over derived rings:: - sage: RR['x'].epsilon() + sage: RR['x'].epsilon() # needs sage.rings.real_mpfr 2.22044604925031e-16 sage: QQ['x'].epsilon() 0 For the symbolic ring, there is no reasonable answer:: - sage: SR.epsilon() + sage: SR.epsilon() # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError @@ -1196,9 +1210,10 @@ cdef class CommutativeRing(Ring): EXAMPLES:: sage: R.<x, y> = GF(3)[] - sage: R.localization((x*y, x**2+y**2)) - Multivariate Polynomial Ring in x, y over Finite Field of size 3 localized at (y, x, x^2 + y^2) - sage: ~y in _ + sage: R.localization((x*y, x**2 + y**2)) # needs sage.rings.finite_rings + Multivariate Polynomial Ring in x, y over Finite Field of size 3 + localized at (y, x, x^2 + y^2) + sage: ~y in _ # needs sage.rings.finite_rings True """ if not self.is_integral_domain(): @@ -1272,11 +1287,11 @@ cdef class CommutativeRing(Ring): sage: QQ.is_commutative() True - sage: ZpCA(7).is_commutative() + sage: ZpCA(7).is_commutative() # needs sage.rings.padics True - sage: A = QuaternionAlgebra(QQ, -1, -3, names=('i','j','k')); A + sage: A = QuaternionAlgebra(QQ, -1, -3, names=('i','j','k')); A # needs sage.combinat sage.modules Quaternion Algebra (-1, -3) with base ring Rational Field - sage: A.is_commutative() + sage: A.is_commutative() # needs sage.combinat sage.modules False """ return True @@ -1312,13 +1327,16 @@ cdef class CommutativeRing(Ring): All orders in number fields have Krull dimension 1, including non-maximal orders:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: R = K.maximal_order(); R - Gaussian Integers in Number Field in i with defining polynomial x^2 + 1 with i = 1*I + Gaussian Integers in Number Field in i + with defining polynomial x^2 + 1 with i = 1*I sage: R.krull_dimension() 1 sage: R = K.order(2*i); R - Order in Number Field in i with defining polynomial x^2 + 1 with i = 1*I + Order in Number Field in i + with defining polynomial x^2 + 1 with i = 1*I sage: R.is_maximal() False sage: R.krull_dimension() @@ -1337,12 +1355,12 @@ cdef class CommutativeRing(Ring): sage: R.<x>=QQ[]; R.ideal_monoid() Monoid of ideals of Univariate Polynomial Ring in x over Rational Field """ - if self.__ideal_monoid is not None: - return self.__ideal_monoid + if self._ideal_monoid is not None: + return self._ideal_monoid else: from sage.rings.ideal_monoid import IdealMonoid M = IdealMonoid(self) - self.__ideal_monoid = M + self._ideal_monoid = M return M def extension(self, poly, name=None, names=None, **kwds): @@ -1366,16 +1384,19 @@ cdef class CommutativeRing(Ring): sage: R = QQ['x'] sage: y = polygen(R) - sage: R.extension(y^2 - 5, 'a') - Univariate Quotient Polynomial Ring in a over Univariate Polynomial Ring in x over Rational Field with modulus a^2 - 5 + sage: R.extension(y^2 - 5, 'a') # needs sage.libs.pari + Univariate Quotient Polynomial Ring in a over + Univariate Polynomial Ring in x over Rational Field with modulus a^2 - 5 :: + sage: # needs sage.rings.finite_rings sage: P.<x> = PolynomialRing(GF(5)) sage: F.<a> = GF(5).extension(x^2 - 2) sage: P.<t> = F[] sage: R.<b> = F.extension(t^2 - a); R - Univariate Quotient Polynomial Ring in b over Finite Field in a of size 5^2 with modulus b^2 + 4*a + Univariate Quotient Polynomial Ring in b over + Finite Field in a of size 5^2 with modulus b^2 + 4*a """ from sage.rings.polynomial.polynomial_element import Polynomial if not isinstance(poly, Polynomial): @@ -1413,14 +1434,16 @@ cdef class CommutativeRing(Ring): sage: K.<u> = PowerSeriesRing(GF(5)) sage: Frob = K.frobenius_endomorphism(); Frob - Frobenius endomorphism x |--> x^5 of Power Series Ring in u over Finite Field of size 5 + Frobenius endomorphism x |--> x^5 of Power Series Ring in u + over Finite Field of size 5 sage: Frob(u) u^5 We can specify a power:: sage: f = K.frobenius_endomorphism(2); f - Frobenius endomorphism x |--> x^(5^2) of Power Series Ring in u over Finite Field of size 5 + Frobenius endomorphism x |--> x^(5^2) of Power Series Ring in u + over Finite Field of size 5 sage: f(1+u) 1 + u^25 """ @@ -1456,18 +1479,21 @@ cdef class CommutativeRing(Ring): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: M = R.derivation_module(); M - Module of derivations over Multivariate Polynomial Ring in x, y, z over Rational Field - sage: M.gens() + sage: M = R.derivation_module(); M # needs sage.modules + Module of derivations over + Multivariate Polynomial Ring in x, y, z over Rational Field + sage: M.gens() # needs sage.modules (d/dx, d/dy, d/dz) We can specify a different codomain:: sage: K = R.fraction_field() - sage: M = R.derivation_module(K); M - Module of derivations from Multivariate Polynomial Ring in x, y, z over - Rational Field to Fraction Field of Multivariate Polynomial Ring in x, y, z over Rational Field - sage: M.gen() / x + sage: M = R.derivation_module(K); M # needs sage.modules + Module of derivations + from Multivariate Polynomial Ring in x, y, z over Rational Field + to Fraction Field of + Multivariate Polynomial Ring in x, y, z over Rational Field + sage: M.gen() / x # needs sage.modules 1/x*d/dx Here is an example with a non-canonical defining morphism:: @@ -1480,12 +1506,15 @@ cdef class CommutativeRing(Ring): Defn: x |--> 0 y |--> 1 z |--> 2 - sage: M = R.derivation_module(ev) - sage: M - Module of derivations from Multivariate Polynomial Ring in x, y, z over Rational Field to Rational Field + sage: M = R.derivation_module(ev) # needs sage.modules + sage: M # needs sage.modules + Module of derivations + from Multivariate Polynomial Ring in x, y, z over Rational Field + to Rational Field Elements in `M` acts as derivations at `(0,1,2)`:: + sage: # needs sage.modules sage: Dx = M.gen(0); Dx d/dx sage: Dy = M.gen(1); Dy @@ -1503,7 +1532,7 @@ cdef class CommutativeRing(Ring): An example with a twisting homomorphism:: sage: theta = R.hom([x^2, y^2, z^2]) - sage: M = R.derivation_module(twist=theta); M + sage: M = R.derivation_module(twist=theta); M # needs sage.modules Module of twisted derivations over Multivariate Polynomial Ring in x, y, z over Rational Field (twisting morphism: x |--> x^2, y |--> y^2, z |--> z^2) @@ -1542,23 +1571,23 @@ cdef class CommutativeRing(Ring): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: R.derivation() + sage: R.derivation() # needs sage.modules d/dx In that case, ``arg`` could be a generator:: - sage: R.derivation(y) + sage: R.derivation(y) # needs sage.modules d/dy or a list of coefficients:: - sage: R.derivation([1,2,3]) + sage: R.derivation([1,2,3]) # needs sage.modules d/dx + 2*d/dy + 3*d/dz It is not possible to define derivations with respect to a polynomial which is not a variable:: - sage: R.derivation(x^2) + sage: R.derivation(x^2) # needs sage.modules Traceback (most recent call last): ... ValueError: unable to create the derivation @@ -1567,18 +1596,18 @@ cdef class CommutativeRing(Ring): sage: R.<x,y,z> = QQ[] sage: theta = R.hom([x^2, y^2, z^2]) - sage: f = R.derivation(twist=theta); f + sage: f = R.derivation(twist=theta); f # needs sage.modules 0 - sage: f.parent() + sage: f.parent() # needs sage.modules Module of twisted derivations over Multivariate Polynomial Ring in x, y, z over Rational Field (twisting morphism: x |--> x^2, y |--> y^2, z |--> z^2) Specifying a scalar, the returned twisted derivation is the corresponding multiple of `\theta - id`:: - sage: R.derivation(1, twist=theta) + sage: R.derivation(1, twist=theta) # needs sage.modules [x |--> x^2, y |--> y^2, z |--> z^2] - id - sage: R.derivation(x, twist=theta) + sage: R.derivation(x, twist=theta) # needs sage.modules x*([x |--> x^2, y |--> y^2, z |--> z^2] - id) """ @@ -1696,7 +1725,7 @@ cdef class IntegralDomain(CommutativeRing): True sage: QQ.is_integrally_closed() True - sage: QQbar.is_integrally_closed() + sage: QQbar.is_integrally_closed() # needs sage.rings.number_field True sage: GF(5).is_integrally_closed() True @@ -1785,9 +1814,10 @@ cdef class DedekindDomain(IntegralDomain): sage: ZZ.krull_dimension() 1 - sage: K = NumberField(x^2 + 1, 's') - sage: OK = K.ring_of_integers() - sage: OK.krull_dimension() + sage: x = polygen(ZZ, 'x') + sage: K = NumberField(x^2 + 1, 's') # needs sage.rings.number_field + sage: OK = K.ring_of_integers() # needs sage.rings.number_field + sage: OK.krull_dimension() # needs sage.rings.number_field 1 The following are not Dedekind domains but have @@ -1804,9 +1834,11 @@ cdef class DedekindDomain(IntegralDomain): sage: U.krull_dimension() 4 + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: R = K.order(2*i); R - Order in Number Field in i with defining polynomial x^2 + 1 with i = 1*I + Order in Number Field in i + with defining polynomial x^2 + 1 with i = 1*I sage: R.is_maximal() False sage: R.krull_dimension() @@ -1828,18 +1860,19 @@ cdef class DedekindDomain(IntegralDomain): sage: ZZ.is_integrally_closed() True - sage: K = NumberField(x^2 + 1, 's') - sage: OK = K.ring_of_integers() - sage: OK.is_integrally_closed() + sage: x = polygen(ZZ, 'x') + sage: K = NumberField(x^2 + 1, 's') # needs sage.rings.number_field + sage: OK = K.ring_of_integers() # needs sage.rings.number_field + sage: OK.is_integrally_closed() # needs sage.rings.number_field True These, however, are not Dedekind domains:: sage: QQ.is_integrally_closed() True - sage: S = ZZ[sqrt(5)]; S.is_integrally_closed() + sage: S = ZZ[sqrt(5)]; S.is_integrally_closed() # needs sage.rings.number_field sage.symbolic False - sage: T.<x,y> = PolynomialRing(QQ,2); T + sage: T.<x,y> = PolynomialRing(QQ, 2); T Multivariate Polynomial Ring in x, y over Rational Field sage: T.is_integral_domain() True @@ -1852,10 +1885,13 @@ cdef class DedekindDomain(IntegralDomain): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x^2 + 1, 's') sage: OK = K.ring_of_integers() sage: OK.integral_closure() - Gaussian Integers in Number Field in s with defining polynomial x^2 + 1 + Gaussian Integers in Number Field in s + with defining polynomial x^2 + 1 sage: OK.integral_closure() == OK True @@ -1875,9 +1911,10 @@ cdef class DedekindDomain(IntegralDomain): sage: ZZ.is_noetherian() True - sage: K = NumberField(x^2 + 1, 's') - sage: OK = K.ring_of_integers() - sage: OK.is_noetherian() + sage: x = polygen(ZZ, 'x') + sage: K = NumberField(x^2 + 1, 's') # needs sage.rings.number_field + sage: OK = K.ring_of_integers() # needs sage.rings.number_field + sage: OK.is_noetherian() # needs sage.rings.number_field True sage: QQ.is_noetherian() True @@ -1901,7 +1938,7 @@ cdef class PrincipalIdealDomain(IntegralDomain): EXAMPLES:: - sage: Zp(5).is_noetherian() + sage: Zp(5).is_noetherian() # needs sage.rings.padics True """ return True @@ -1912,7 +1949,7 @@ cdef class PrincipalIdealDomain(IntegralDomain): EXAMPLES:: - sage: QQ.class_group() + sage: QQ.class_group() # needs sage.groups Trivial Abelian group """ from sage.groups.abelian_gps.abelian_group import AbelianGroup @@ -1957,6 +1994,7 @@ cdef class PrincipalIdealDomain(IntegralDomain): over an extension ring. Note that ``gcd`` requires x and y to be coercible:: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) sage: S.<a> = NumberField(x^2 - 2, 'a') sage: f = (x - a)*(x + a); g = (x - a)*(x^2 - 2) @@ -1967,7 +2005,7 @@ cdef class PrincipalIdealDomain(IntegralDomain): True sage: g in R False - sage: R.gcd(f,g) + sage: R.gcd(f, g) Traceback (most recent call last): ... TypeError: Unable to coerce 2*a to a rational @@ -2066,7 +2104,7 @@ cpdef bint _is_Field(x) except -2: True sage: _is_Field(ZZ) False - sage: _is_Field(pAdicField(2)) + sage: _is_Field(pAdicField(2)) # needs sage.rings.padics True sage: _is_Field(5) False @@ -2108,13 +2146,14 @@ cdef class Field(PrincipalIdealDomain): sage: QQ.fraction_field() Rational Field - sage: RR.fraction_field() + sage: RR.fraction_field() # needs sage.rings.real_mpfr Real Field with 53 bits of precision - sage: CC.fraction_field() + sage: CC.fraction_field() # needs sage.rings.real_mpfr Complex Field with 53 bits of precision - sage: F = NumberField(x^2 + 1, 'i') - sage: F.fraction_field() + sage: x = polygen(ZZ, 'x') + sage: F = NumberField(x^2 + 1, 'i') # needs sage.rings.number_field + sage: F.fraction_field() # needs sage.rings.number_field Number Field in i with defining polynomial x^2 + 1 """ return self @@ -2242,8 +2281,8 @@ cdef class Field(PrincipalIdealDomain): EXAMPLES:: - sage: k = GF(9, 'a') - sage: k.prime_subfield() + sage: k = GF(9, 'a') # needs sage.rings.finite_rings + sage: k.prime_subfield() # needs sage.rings.finite_rings Finite Field of size 3 """ if self.characteristic() == 0: @@ -2283,7 +2322,7 @@ cdef class Algebra(Ring): EXAMPLES:: - sage: A = Algebra(ZZ); A + sage: A = Algebra(ZZ); A # needs sage.modules <sage.rings.ring.Algebra object at ...> """ # This is a low-level class. For performance, we trust that the category @@ -2303,12 +2342,13 @@ cdef class Algebra(Ring): EXAMPLES:: + sage: # needs sage.modules sage: A = Algebra(ZZ); A <sage.rings.ring.Algebra object at ...> sage: A.characteristic() 0 - sage: A = Algebra(GF(7^3, 'a')) - sage: A.characteristic() + sage: A = Algebra(GF(7^3, 'a')) # needs sage.rings.finite_rings + sage: A.characteristic() # needs sage.rings.finite_rings 7 """ return self.base_ring().characteristic() @@ -2323,15 +2363,16 @@ cdef class Algebra(Ring): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: B = QuaternionAlgebra(2) sage: B.has_standard_involution() True sage: R.<x> = PolynomialRing(QQ) - sage: K.<u> = NumberField(x**2 - 2) - sage: A = QuaternionAlgebra(K,-2,5) - sage: A.has_standard_involution() + sage: K.<u> = NumberField(x**2 - 2) # needs sage.rings.number_field + sage: A = QuaternionAlgebra(K, -2, 5) # needs sage.rings.number_field + sage: A.has_standard_involution() # needs sage.rings.number_field True - sage: L.<a,b> = FreeAlgebra(QQ,2) + sage: L.<a,b> = FreeAlgebra(QQ, 2) sage: L.has_standard_involution() Traceback (most recent call last): ... @@ -2386,7 +2427,7 @@ cdef class CommutativeAlgebra(CommutativeRing): sage: sage.rings.ring.CommutativeAlgebra(QQ) <sage.rings.ring.CommutativeAlgebra object at ...> - sage: sage.rings.ring.CommutativeAlgebra(QuaternionAlgebra(QQ,-1,-1)) + sage: sage.rings.ring.CommutativeAlgebra(QuaternionAlgebra(QQ, -1, -1)) # needs sage.combinat sage.modules Traceback (most recent call last): ... TypeError: base ring must be a commutative ring @@ -2433,8 +2474,8 @@ def is_Ring(x): sage: from sage.rings.ring import is_Ring sage: is_Ring(ZZ) True - sage: MS = MatrixSpace(QQ,2) - sage: is_Ring(MS) + sage: MS = MatrixSpace(QQ, 2) # needs sage.modules + sage: is_Ring(MS) # needs sage.modules True """ return x in _Rings diff --git a/src/sage/rings/ring_extension.pxd b/src/sage/rings/ring_extension.pxd index 1607dd6fc2e..9115f8d26f8 100644 --- a/src/sage/rings/ring_extension.pxd +++ b/src/sage/rings/ring_extension.pxd @@ -1,6 +1,5 @@ from sage.categories.map cimport Map from sage.rings.ring cimport CommutativeRing, CommutativeAlgebra -from sage.rings.ring_extension cimport RingExtension_generic cdef class RingExtension_generic(CommutativeAlgebra): diff --git a/src/sage/rings/ring_extension.pyx b/src/sage/rings/ring_extension.pyx index fa8c836fb80..d9438aaa648 100644 --- a/src/sage/rings/ring_extension.pyx +++ b/src/sage/rings/ring_extension.pyx @@ -11,41 +11,40 @@ that is `L`. For example, the following line constructs the extension of finite fields `\mathbf{F}_{5^4}/\mathbf{F}_{5^2}`:: - sage: GF(5^4).over(GF(5^2)) + sage: GF(5^4).over(GF(5^2)) # needs sage.rings.finite_rings Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base By default, Sage reuses the canonical generator of the top ring (here `z_4 \in \mathbf{F}_{5^4}`), together with its name. However, the user can customize them by passing in appropriate arguments:: + sage: # needs sage.rings.finite_rings sage: F = GF(5^2) sage: k = GF(5^4) sage: z4 = k.gen() - sage: K.<a> = k.over(F, gen = 1-z4) - sage: K + sage: K.<a> = k.over(F, gen=1-z4); K Field in a with defining polynomial x^2 + z2*x + 4 over its base The base of the extension is available via the method :meth:`base` (or equivalently :meth:`base_ring`):: - sage: K.base() + sage: K.base() # needs sage.rings.finite_rings Finite Field in z2 of size 5^2 It is also possible to build an extension on top of another extension, obtaining this way a tower of extensions:: - sage: L.<b> = GF(5^8).over(K) - sage: L + sage: L.<b> = GF(5^8).over(K); L # needs sage.rings.finite_rings Field in b with defining polynomial x^2 + (4*z2 + 3*a)*x + 1 - a over its base - sage: L.base() + sage: L.base() # needs sage.rings.finite_rings Field in a with defining polynomial x^2 + z2*x + 4 over its base - sage: L.base().base() + sage: L.base().base() # needs sage.rings.finite_rings Finite Field in z2 of size 5^2 The method :meth:`bases` gives access to the complete list of rings in a tower:: - sage: L.bases() + sage: L.bases() # needs sage.rings.finite_rings [Field in b with defining polynomial x^2 + (4*z2 + 3*a)*x + 1 - a over its base, Field in a with defining polynomial x^2 + z2*x + 4 over its base, Finite Field in z2 of size 5^2] @@ -54,34 +53,34 @@ Once we have constructed an extension (or a tower of extensions), we have interesting methods attached to it. As a basic example, one can compute a basis of the top ring over any base in the tower:: - sage: L.basis_over(K) + sage: L.basis_over(K) # needs sage.rings.finite_rings [1, b] - sage: L.basis_over(F) + sage: L.basis_over(F) # needs sage.rings.finite_rings [1, a, b, a*b] When the base is omitted, the default is the natural base of the extension:: - sage: L.basis_over() + sage: L.basis_over() # needs sage.rings.finite_rings [1, b] The method :meth:`sage.rings.ring_extension_element.RingExtensionWithBasis.vector` computes the coordinates of an element according to the above basis:: - sage: u = a + 2*b + 3*a*b - sage: u.vector() # over K + sage: u = a + 2*b + 3*a*b # needs sage.rings.finite_rings + sage: u.vector() # over K # needs sage.rings.finite_rings (a, 2 + 3*a) - sage: u.vector(F) + sage: u.vector(F) # needs sage.rings.finite_rings (0, 1, 2, 3) One can also compute traces and norms with respect to any base of the tower:: + sage: # needs sage.rings.finite_rings sage: u.trace() # over K (2*z2 + 1) + (2*z2 + 1)*a sage: u.trace(F) z2 + 1 sage: u.trace().trace() # over K, then over F z2 + 1 - sage: u.norm() # over K (z2 + 1) + (4*z2 + 2)*a sage: u.norm(F) @@ -89,9 +88,9 @@ One can also compute traces and norms with respect to any base of the tower:: And minimal polynomials:: - sage: u.minpoly() + sage: u.minpoly() # needs sage.rings.finite_rings x^2 + ((3*z2 + 4) + (3*z2 + 4)*a)*x + (z2 + 1) + (4*z2 + 2)*a - sage: u.minpoly(F) + sage: u.minpoly(F) # needs sage.rings.finite_rings x^4 + (4*z2 + 4)*x^3 + x^2 + (z2 + 1)*x + 2*z2 + 2 @@ -100,15 +99,15 @@ AUTHOR: - Xavier Caruso (2019) """ -############################################################################# +# ########################################################################### # Copyright (C) 2019 Xavier Caruso <xavier.caruso@normalesup.org> # # This program is free softwGare: 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. -# http://www.gnu.org/licenses/ -#**************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from sage.misc.fast_methods cimport hash_by_id @@ -118,12 +117,10 @@ from sage.cpython.getattr import dir_with_other_class from sage.misc.latex import latex, latex_variable_name from sage.structure.factory import UniqueFactory -from sage.structure.parent cimport Parent from sage.structure.element cimport Element from sage.structure.category_object import normalize_names from sage.categories.map cimport Map from sage.categories.commutative_rings import CommutativeRings -from sage.categories.commutative_algebras import CommutativeAlgebras from sage.categories.fields import Fields from sage.rings.ring cimport CommutativeRing, CommutativeAlgebra from sage.rings.integer_ring import ZZ @@ -159,17 +156,19 @@ def tower_bases(ring, degree): sage: S.<x> = QQ[] sage: T.<y> = S[] sage: tower_bases(T, False) - ([Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field, + ([Univariate Polynomial Ring in y over + Univariate Polynomial Ring in x over Rational Field, Univariate Polynomial Ring in x over Rational Field, Rational Field], []) sage: tower_bases(T, True) - ([Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field], + ([Univariate Polynomial Ring in y over + Univariate Polynomial Ring in x over Rational Field], [1]) - sage: K.<a> = Qq(5^2) - sage: L.<w> = K.extension(x^3 - 5) - sage: tower_bases(L, True) + sage: K.<a> = Qq(5^2) # needs sage.rings.padics + sage: L.<w> = K.extension(x^3 - 5) # needs sage.rings.padics + sage: tower_bases(L, True) # needs sage.rings.padics ([5-adic Eisenstein Extension Field in w defined by x^3 - 5 over its base field, 5-adic Unramified Extension Field in a defined by x^2 + 4*x + 2, 5-adic Field with capped relative precision 20], @@ -215,12 +214,12 @@ def common_base(K, L, degree): sage: from sage.rings.ring_extension import common_base - sage: common_base(GF(5^3), GF(5^7), False) + sage: common_base(GF(5^3), GF(5^7), False) # needs sage.rings.finite_rings Finite Field of size 5 - sage: common_base(GF(5^3), GF(5^7), True) + sage: common_base(GF(5^3), GF(5^7), True) # needs sage.rings.finite_rings (Finite Field of size 5, 3, 7) - sage: common_base(GF(5^3), GF(7^5), False) + sage: common_base(GF(5^3), GF(7^5), False) # needs sage.rings.finite_rings Traceback (most recent call last): ... NotImplementedError: unable to find a common base @@ -337,13 +336,13 @@ class RingExtensionFactory(UniqueFactory): sage: QQ.over(ZZ) is E True - sage: K.<a> = QQ.extension(x^2 - 2) - sage: E = K.over(QQ) - sage: E + sage: x = polygen(ZZ, 'x') + sage: K.<a> = QQ.extension(x^2 - 2) # needs sage.rings.number_field + sage: E = K.over(QQ); E # needs sage.rings.number_field Field in a with defining polynomial x^2 - 2 over its base - sage: E2.<b> = K.over(QQ) - sage: E2 is E + sage: E2.<b> = K.over(QQ) # needs sage.rings.number_field + sage: E2 is E # needs sage.rings.number_field False """ def create_key_and_extra_args(self, ring, defining_morphism=None, gens=None, names=None, constructors=None): @@ -379,16 +378,18 @@ class RingExtensionFactory(UniqueFactory): To: Rational Field Defn: 1 |--> 1, (), ()), {'constructors': [(<class 'sage.rings.ring_extension.RingExtension_generic'>, - {'is_backend_exposed': True, - 'print_options': {'print_elements_as': None, 'print_parent_as': None}})]}) + {'is_backend_exposed': True, + 'print_options': {'print_elements_as': None, + 'print_parent_as': None}})]}) - sage: RingExtension.create_key_and_extra_args(GF(5^4), GF(5^2), names=('a',)) + sage: RingExtension.create_key_and_extra_args(GF(5^4), GF(5^2), # needs sage.rings.finite_rings + ....: names=('a',)) ((Ring morphism: From: Finite Field in z2 of size 5^2 To: Finite Field in z4 of size 5^4 Defn: z2 |--> z4^3 + z4^2 + z4 + 3, (z4,), ('a',)), {'constructors': [(<class 'sage.rings.ring_extension.RingExtensionWithGen'>, - {'gen': z4, 'is_backend_exposed': True, 'names': ('a',)})]}) + {'gen': z4, 'is_backend_exposed': True, 'names': ('a',)})]}) """ use_generic_constructor = True is_backend_exposed = True @@ -429,6 +430,7 @@ class RingExtensionFactory(UniqueFactory): else: use_generic_constructor = False is_backend_exposed = False + ring = (<RingExtension_generic>ring)._backend # We normalize other attributes if gens is not None: @@ -536,9 +538,9 @@ cdef class RingExtension_generic(CommutativeAlgebra): .. NOTE: - The attribute `is_backend_exposed` is only used for printing; + The attribute ``is_backend_exposed`` is only used for printing; when it is ``False``, printing an element like its backend is - disabled (and a ``RuntimeError`` is raised when it would occur). + disabled (and a :class:`RuntimeError` is raised when it would occur). OUTPUT: @@ -560,8 +562,8 @@ cdef class RingExtension_generic(CommutativeAlgebra): ... TypeError: only commutative rings are accepted - sage: K = GF(5^3) - sage: K.over(K.frobenius_endomorphism()) + sage: K = GF(5^3) # needs sage.rings.finite_rings + sage: K.over(K.frobenius_endomorphism()) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: exotic defining morphism between two rings in the tower; consider using another variable name @@ -623,9 +625,10 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = QQ.extension(x^2 - 2) sage: E = K.over() # over QQ - sage: hasattr(E, 'automorphisms') True sage: E.automorphisms() @@ -659,10 +662,11 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: - sage: A.<a> = QQ.extension(x^2 - 2) - sage: K.<a> = A.over() + sage: x = polygen(ZZ, 'x') + sage: A.<a> = QQ.extension(x^2 - 2) # needs sage.rings.number_field + sage: K.<a> = A.over() # needs sage.rings.number_field - sage: dir(K) + sage: dir(K) # needs sage.rings.number_field ['CartesianProduct', 'Element', 'Hom', @@ -691,8 +695,8 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES: - sage: E = GF(5^3).over() - sage: hash(E) # random + sage: E = GF(5^3).over() # needs sage.rings.finite_rings + sage: hash(E) # random # needs sage.rings.finite_rings 140257667982632 """ return hash_by_id(<void *>self) @@ -704,10 +708,10 @@ cdef class RingExtension_generic(CommutativeAlgebra): TESTS:: - sage: K = GF(7^3).over() - sage: type(K) + sage: K = GF(7^3).over() # needs sage.rings.finite_rings + sage: type(K) # needs sage.rings.finite_rings <class 'sage.rings.ring_extension.RingExtensionWithGen'> - sage: loads(dumps(K)) is K + sage: loads(dumps(K)) is K # needs sage.rings.finite_rings True """ (defining_morphism, gens, names) = self._factory_data[2] @@ -720,13 +724,39 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: - sage: E = GF(5^3).over() - sage: E.construction() + sage: E = GF(5^3).over() # needs sage.rings.finite_rings + sage: E.construction() # needs sage.rings.finite_rings """ # One could define a construction functor K' -> K' otimes_K L, but we leave this to another issue pass + def backend(self, force=False): + """ + Return the backend of this extension. + + INPUT: + + - ``force`` -- a boolean (default: ``False``); if ``False``, + raise an error if the backend is not exposed + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: K = GF(5^3) + sage: E = K.over() + sage: E + Field in z3 with defining polynomial x^3 + 3*x + 3 over its base + sage: E.backend() + Finite Field in z3 of size 5^3 + sage: E.backend() is K + True + + """ + if force or self._is_backend_exposed: + return self._backend + raise ValueError("backend is not exposed; try force=True") + def from_base_ring(self, r): r""" Return the canonical embedding of ``r`` into this extension. @@ -737,15 +767,14 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k = GF(5) sage: K.<u> = GF(5^2).over(k) sage: L.<v> = GF(5^4).over(K) - sage: x = L.from_base_ring(k(2)); x 2 sage: x.parent() Field in v with defining polynomial x^2 + (3 - u)*x + u over its base - sage: x = L.from_base_ring(u); x u sage: x.parent() @@ -770,6 +799,7 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A.<a> = GF(5^2).over() # over GF(5) sage: B.<b> = GF(5^4).over(A) sage: C.<c> = GF(5^12).over(B) @@ -777,15 +807,15 @@ cdef class RingExtension_generic(CommutativeAlgebra): Observe what happens when we modify the option ``over``:: + sage: # needs sage.rings.finite_rings sage: D - Field in d with defining polynomial x^2 + ((1 - a) + ((1 + 2*a) - b)*c + ((2 + a) + (1 - a)*b)*c^2)*x + c over its base - + Field in d with defining polynomial + x^2 + ((1 - a) + ((1 + 2*a) - b)*c + ((2 + a) + (1 - a)*b)*c^2)*x + c over its base sage: D.print_options(over=2) sage: D Field in d with defining polynomial x^2 + ((1 - a) + ((1 + 2*a) - b)*c + ((2 + a) + (1 - a)*b)*c^2)*x + c over Field in c with defining polynomial x^3 + (1 + (2 - a)*b)*x^2 + (2 + 2*b)*x - b over Field in b with defining polynomial x^2 + (3 - a)*x + a over its base - sage: D.print_options(over=Infinity) sage: D Field in d with defining polynomial x^2 + ((1 - a) + ((1 + 2*a) - b)*c + ((2 + a) + (1 - a)*b)*c^2)*x + c over @@ -796,15 +826,14 @@ cdef class RingExtension_generic(CommutativeAlgebra): Now the option ``base``:: + sage: # needs sage.rings.finite_rings sage: d^2 -c + ((-1 + a) + ((-1 + 3*a) + b)*c + ((3 - a) + (-1 + a)*b)*c^2)*d - sage: D.basis_over(B) [1, c, c^2, d, c*d, c^2*d] sage: D.print_options(base=B) sage: d^2 -c + (-1 + a)*d + ((-1 + 3*a) + b)*c*d + ((3 - a) + (-1 + a)*b)*c^2*d - sage: D.basis_over(A) [1, b, c, b*c, c^2, b*c^2, d, b*d, c*d, b*c*d, c^2*d, b*c^2*d] sage: D.print_options(base=A) @@ -1012,19 +1041,18 @@ cdef class RingExtension_generic(CommutativeAlgebra): TESTS:: + sage: # needs sage.rings.finite_rings sage: E1 = GF(3^6).over(GF(3^3)) sage: E1.coerce_map_from(GF(3^3)) # indirect doctest Ring morphism: From: Finite Field in z3 of size 3^3 To: Field in z6 with defining polynomial x^2 + (2*z3 + 1)*x + z3 over its base Defn: z3 |--> z3 - sage: E1.coerce_map_from(GF(3)) # indirect doctest Ring morphism: From: Finite Field of size 3 To: Field in z6 with defining polynomial x^2 + (2*z3 + 1)*x + z3 over its base Defn: 1 |--> 1 - sage: E2 = GF(3^18).over(GF(3^9)) sage: E2.coerce_map_from(E1) # indirect doctest Ring morphism: @@ -1034,6 +1062,7 @@ cdef class RingExtension_generic(CommutativeAlgebra): A test with iterated extensions:: + sage: # needs sage.rings.finite_rings sage: A = GF(3^18).over(GF(3^3)) # simple extension GF(3^3) -> GF(3^18) sage: B = GF(3^18).over(E1) # iterated extension GF(3^3) -> GF(3^6) -> GF(3^18) sage: A.has_coerce_map_from(B) @@ -1058,17 +1087,17 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: - sage: F = GF(5^2) - sage: K = GF(5^4).over(F) - sage: K.base() + sage: F = GF(5^2) # needs sage.rings.finite_rings + sage: K = GF(5^4).over(F) # needs sage.rings.finite_rings + sage: K.base() # needs sage.rings.finite_rings Finite Field in z2 of size 5^2 In case of iterated extensions, the base is itself an extension:: - sage: L = GF(5^8).over(K) - sage: L.base() + sage: L = GF(5^8).over(K) # needs sage.rings.finite_rings + sage: L.base() # needs sage.rings.finite_rings Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base - sage: L.base() is K + sage: L.base() is K # needs sage.rings.finite_rings True .. SEEALSO:: @@ -1084,21 +1113,20 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5^2).over() # over GF(5) sage: K = GF(5^4).over(F) sage: L = GF(5^12).over(K) - sage: F.bases() [Field in z2 with defining polynomial x^2 + 4*x + 2 over its base, Finite Field of size 5] - sage: K.bases() [Field in z4 with defining polynomial x^2 + (3 - z2)*x + z2 over its base, Field in z2 with defining polynomial x^2 + 4*x + 2 over its base, Finite Field of size 5] - sage: L.bases() - [Field in z12 with defining polynomial x^3 + (1 + (2 - z2)*z4)*x^2 + (2 + 2*z4)*x - z4 over its base, + [Field in z12 with defining polynomial + x^3 + (1 + (2 - z2)*z4)*x^2 + (2 + 2*z4)*x - z4 over its base, Field in z4 with defining polynomial x^2 + (3 - z2)*x + z2 over its base, Field in z2 with defining polynomial x^2 + 4*x + 2 over its base, Finite Field of size 5] @@ -1123,10 +1151,10 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5^2).over() # over GF(5) sage: K = GF(5^4).over(F) sage: L = GF(5^12).over(K) - sage: F.absolute_base() Finite Field of size 5 sage: K.absolute_base() @@ -1152,14 +1180,15 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A = GF(5^4).over(GF(5^2)) sage: B = GF(5^12).over(A) - sage: A.is_defined_over(GF(5^2)) True sage: A.is_defined_over(GF(5)) False + sage: # needs sage.rings.finite_rings sage: B.is_defined_over(A) True sage: B.is_defined_over(GF(5^4)) @@ -1171,9 +1200,9 @@ cdef class RingExtension_generic(CommutativeAlgebra): Note that an extension is defined over itself:: - sage: A.is_defined_over(A) + sage: A.is_defined_over(A) # needs sage.rings.finite_rings True - sage: A.is_defined_over(GF(5^4)) + sage: A.is_defined_over(GF(5^4)) # needs sage.rings.finite_rings True .. SEEALSO:: @@ -1204,6 +1233,7 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5^2) sage: K = GF(5^4).over(F) sage: L = GF(5^12).over(K) @@ -1211,7 +1241,6 @@ cdef class RingExtension_generic(CommutativeAlgebra): [Field in z12 with defining polynomial x^3 + (1 + (4*z2 + 2)*z4)*x^2 + (2 + 2*z4)*x - z4 over its base, Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base, Finite Field in z2 of size 5^2] - sage: L._check_base(K) Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base sage: L._check_base(GF(5^4)) @@ -1221,9 +1250,9 @@ cdef class RingExtension_generic(CommutativeAlgebra): When ``base`` is ``None``, the base of the extension is returned:: - sage: L._check_base(None) + sage: L._check_base(None) # needs sage.rings.finite_rings Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base - sage: L._check_base(None) is L.base() + sage: L._check_base(None) is L.base() # needs sage.rings.finite_rings True """ @@ -1249,32 +1278,32 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5^2) sage: K = GF(5^4).over(F) sage: L = GF(5^12).over(K) - sage: K.defining_morphism() Ring morphism: From: Finite Field in z2 of size 5^2 To: Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base Defn: z2 |--> z2 - sage: L.defining_morphism() Ring morphism: From: Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base - To: Field in z12 with defining polynomial x^3 + (1 + (4*z2 + 2)*z4)*x^2 + (2 + 2*z4)*x - z4 over its base + To: Field in z12 with defining polynomial + x^3 + (1 + (4*z2 + 2)*z4)*x^2 + (2 + 2*z4)*x - z4 over its base Defn: z4 |--> z4 One can also pass in a base over which the extension is explicitly defined (see also :meth:`is_defined_over`):: - sage: L.defining_morphism(F) + sage: L.defining_morphism(F) # needs sage.rings.finite_rings Ring morphism: From: Finite Field in z2 of size 5^2 - To: Field in z12 with defining polynomial x^3 + (1 + (4*z2 + 2)*z4)*x^2 + (2 + 2*z4)*x - z4 over its base + To: Field in z12 with defining polynomial + x^3 + (1 + (4*z2 + 2)*z4)*x^2 + (2 + 2*z4)*x - z4 over its base Defn: z2 |--> z2 - - sage: L.defining_morphism(GF(5)) + sage: L.defining_morphism(GF(5)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field of size 5 @@ -1311,6 +1340,7 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^2).over() # over GF(5) sage: K.gens() (a,) @@ -1341,12 +1371,12 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K = GF(5^2).over() # over GF(5) sage: K.gens() (z2,) sage: K.ngens() 1 - sage: L = GF(5^4).over(K) sage: L.gens(GF(5)) (z4, z2) @@ -1361,15 +1391,15 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: - sage: K = GF(5^2).over() # over GF(5) - sage: x =K.gen(); x + sage: K = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: x = K.gen(); x # needs sage.rings.finite_rings z2 Observe that the generator lives in the extension:: - sage: x.parent() + sage: x.parent() # needs sage.rings.finite_rings Field in z2 with defining polynomial x^2 + 4*x + 2 over its base - sage: x.parent() is K + sage: x.parent() is K # needs sage.rings.finite_rings True """ return self.gens()[0] @@ -1380,10 +1410,10 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K = GF(5^2).over() # over GF(5) sage: x = K.random_element(); x # random 3 + z2 - sage: x.parent() Field in z2 with defining polynomial x^2 + 4*x + 2 over its base sage: x.parent() is K @@ -1403,10 +1433,10 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5^2) sage: K = GF(5^4).over(F) sage: L = GF(5^12).over(K) - sage: K.degree_over(F) 2 sage: L.degree_over(K) @@ -1417,15 +1447,15 @@ cdef class RingExtension_generic(CommutativeAlgebra): If ``base`` is omitted, the degree is computed over the base of the extension:: - sage: K.degree_over() + sage: K.degree_over() # needs sage.rings.finite_rings 2 - sage: L.degree_over() + sage: L.degree_over() # needs sage.rings.finite_rings 3 Note that ``base`` must be an explicit base over which the extension has been defined (as listed by the method :meth:`bases`):: - sage: K.degree_over(GF(5)) + sage: K.degree_over(GF(5)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field of size 5 @@ -1446,6 +1476,8 @@ cdef class RingExtension_generic(CommutativeAlgebra): TESTS:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = QQ.extension(x^2 - 2) sage: B.<b> = QQ.extension(x^6 - 2) sage: f = A.hom([b^3]) @@ -1468,9 +1500,9 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A = GF(5^4).over(GF(5^2)) sage: B = GF(5^12).over(A) - sage: A.degree(GF(5^2)) 2 sage: B.degree(A) @@ -1481,7 +1513,7 @@ cdef class RingExtension_generic(CommutativeAlgebra): Note that ``base`` must be an explicit base over which the extension has been defined (as listed by the method :meth:`bases`):: - sage: A.degree(GF(5)) + sage: A.degree(GF(5)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field of size 5 @@ -1498,8 +1530,8 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: - sage: A = GF(5^4).over(GF(5^2)) - sage: A.relative_degree() + sage: A = GF(5^4).over(GF(5^2)) # needs sage.rings.finite_rings + sage: A.relative_degree() # needs sage.rings.finite_rings 2 .. SEEALSO:: @@ -1514,9 +1546,9 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A = GF(5^4).over(GF(5^2)) sage: B = GF(5^12).over(A) - sage: A.absolute_degree() 2 sage: B.absolute_degree() @@ -1539,9 +1571,9 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K = GF(5^2).over() # over GF(5) sage: L = GF(5^4).over(K) - sage: L.is_finite_over(K) True sage: L.is_finite_over(GF(5)) @@ -1550,7 +1582,7 @@ cdef class RingExtension_generic(CommutativeAlgebra): If ``base`` is omitted, it is set to its default which is the base of the extension:: - sage: L.is_finite_over() + sage: L.is_finite_over() # needs sage.rings.finite_rings True """ cdef CommutativeRing b @@ -1584,8 +1616,8 @@ cdef class RingExtension_generic(CommutativeAlgebra): TESTS:: - sage: K = GF(5^2).over() # over GF(5) - sage: K.is_finite_over() # indirect doctest + sage: K = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: K.is_finite_over() # indirect doctest # needs sage.rings.finite_rings True """ raise NotImplementedError @@ -1602,9 +1634,9 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K = GF(5^2).over() # over GF(5) sage: L = GF(5^4).over(K) - sage: L.is_free_over(K) True sage: L.is_free_over(GF(5)) @@ -1613,7 +1645,7 @@ cdef class RingExtension_generic(CommutativeAlgebra): If ``base`` is omitted, it is set to its default which is the base of the extension:: - sage: L.is_free_over() + sage: L.is_free_over() # needs sage.rings.finite_rings True """ cdef CommutativeRing b @@ -1647,8 +1679,8 @@ cdef class RingExtension_generic(CommutativeAlgebra): TESTS:: - sage: K = GF(5^2).over() # over GF(5) - sage: K.is_free_over() # indirect doctest + sage: K = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: K.is_free_over() # indirect doctest # needs sage.rings.finite_rings True """ raise NotImplementedError @@ -1663,8 +1695,8 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: - sage: K = GF(5^5).over() # over GF(5) - sage: K.is_field() + sage: K = GF(5^5).over() # over GF(5) # needs sage.rings.finite_rings + sage: K.is_field() # needs sage.rings.finite_rings True sage: S.<x> = QQ[] @@ -1699,38 +1731,40 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = ZZ.extension(x^2 - 5) sage: OK = A.over() # over ZZ sage: OK Order in Number Field in a with defining polynomial x^2 - 5 over its base - - sage: K1 = OK.fraction_field() - sage: K1 - Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base + sage: K1 = OK.fraction_field(); K1 + Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base sage: K1.bases() - [Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base, + [Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base, Order in Number Field in a with defining polynomial x^2 - 5 over its base, Integer Ring] - - sage: K2 = OK.fraction_field(extend_base=True) - sage: K2 - Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base + sage: K2 = OK.fraction_field(extend_base=True); K2 + Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base sage: K2.bases() - [Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base, + [Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base, Rational Field] Note that there is no coercion between `K_1` and `K_2`:: - sage: K1.has_coerce_map_from(K2) + sage: K1.has_coerce_map_from(K2) # needs sage.rings.number_field False - sage: K2.has_coerce_map_from(K1) + sage: K2.has_coerce_map_from(K1) # needs sage.rings.number_field False We check that when the extension is a field, its fraction field does not change:: - sage: K1.fraction_field() is K1 + sage: K1.fraction_field() is K1 # needs sage.rings.number_field True - sage: K2.fraction_field() is K2 + sage: K2.fraction_field() is K2 # needs sage.rings.number_field True TESTS:: @@ -1761,8 +1795,8 @@ cdef class RingExtension_generic(CommutativeAlgebra): TESTS:: - sage: K = GF(5^2).over() - sage: K.fraction_field() # indirect doctest + sage: K = GF(5^2).over() # needs sage.rings.finite_rings + sage: K.fraction_field() # indirect doctest # needs sage.rings.finite_rings Field in z2 with defining polynomial x^2 + 4*x + 2 over its base sage: K = QQ.over(ZZ) @@ -1796,18 +1830,21 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5^2) sage: K = GF(5^4).over(F) sage: L = GF(5^12).over(F) - sage: K.Hom(L) # indirect doctest - Set of Homomorphisms from Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base - to Field in z12 with defining polynomial x^6 + (4*z2 + 3)*x^5 + x^4 + (3*z2 + 1)*x^3 + x^2 + (4*z2 + 1)*x + z2 over its base - + Set of Homomorphisms + from Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base + to Field in z12 with defining polynomial x^6 + (4*z2 + 3)*x^5 + x^4 + + (3*z2 + 1)*x^3 + x^2 + (4*z2 + 1)*x + z2 over its base sage: K.Hom(L, category=Sets()) - Set of Morphisms from Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base - to Field in z12 with defining polynomial x^6 + (4*z2 + 3)*x^5 + x^4 + (3*z2 + 1)*x^3 + x^2 + (4*z2 + 1)*x + z2 over its base - in Category of sets + Set of Morphisms + from Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base + to Field in z12 with defining polynomial x^6 + (4*z2 + 3)*x^5 + x^4 + + (3*z2 + 1)*x^3 + x^2 + (4*z2 + 1)*x + z2 over its base + in Category of sets """ from sage.rings.ring_extension_homset import RingExtensionHomset @@ -1840,43 +1877,44 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: - sage: K.<a> = GF(5^2).over() # over GF(5) - sage: L.<b> = GF(5^6).over(K) + sage: K.<a> = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: L.<b> = GF(5^6).over(K) # needs sage.rings.finite_rings We define (by hand) the relative Frobenius endomorphism of the extension `L/K`:: - sage: L.hom([b^25]) - Ring endomorphism of Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base + sage: L.hom([b^25]) # needs sage.rings.finite_rings + Ring endomorphism of + Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base Defn: b |--> 2 + 2*a*b + (2 - a)*b^2 Defining the absolute Frobenius of `L` is a bit more complicated because it is not a homomorphism of `K`-algebras. For this reason, the construction ``L.hom([b^5])`` fails:: - sage: L.hom([b^5]) + sage: L.hom([b^5]) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: images do not define a valid homomorphism What we need is to specify a base map:: - sage: FrobK = K.hom([a^5]) - sage: FrobL = L.hom([b^5], base_map=FrobK) - sage: FrobL - Ring endomorphism of Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base + sage: FrobK = K.hom([a^5]) # needs sage.rings.finite_rings + sage: FrobL = L.hom([b^5], base_map=FrobK); FrobL # needs sage.rings.finite_rings + Ring endomorphism of + Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base Defn: b |--> (-1 + a) + (1 + 2*a)*b + a*b^2 with map on base ring: a |--> 1 - a As a shortcut, we may use the following construction:: - sage: phi = L.hom([b^5, a^5]) - sage: phi - Ring endomorphism of Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base + sage: phi = L.hom([b^5, a^5]); phi # needs sage.rings.finite_rings + Ring endomorphism of + Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base Defn: b |--> (-1 + a) + (1 + 2*a)*b + a*b^2 with map on base ring: a |--> 1 - a - sage: phi == FrobL + sage: phi == FrobL # needs sage.rings.finite_rings True """ if codomain is None: @@ -1895,6 +1933,7 @@ cdef class RingExtension_generic(CommutativeAlgebra): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5^2).over() # over GF(5) sage: K = GF(5^4).over(F) sage: L = GF(5^12).over(K) @@ -1934,7 +1973,9 @@ cdef class RingExtension_generic(CommutativeAlgebra): sage: k = Frac(FqX) sage: K = k.over(FqX) sage: K.frobenius_endomorphism() - Frobenius endomorphism x |--> x^11 of Fraction Field of Univariate Polynomial Ring in X over Finite Field of size 11 over its base + Frobenius endomorphism x |--> x^11 of + Fraction Field of Univariate Polynomial Ring in X over + Finite Field of size 11 over its base """ return self._backend.characteristic() @@ -1974,12 +2015,13 @@ cdef class RingExtensionFractionField(RingExtension_generic): TESTS:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = ZZ.extension(x^2 - 2) sage: OK = A.over() - sage: K = OK.fraction_field() - sage: K - Fraction Field of Order in Number Field in a with defining polynomial x^2 - 2 over its base - + sage: K = OK.fraction_field(); K + Fraction Field of + Order in Number Field in a with defining polynomial x^2 - 2 over its base sage: TestSuite(K).run() """ @@ -1995,12 +2037,13 @@ cdef class RingExtensionFractionField(RingExtension_generic): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = ZZ.extension(x^2 - 2) sage: OK = A.over() - sage: K = OK.fraction_field() - sage: K - Fraction Field of Order in Number Field in a with defining polynomial x^2 - 2 over its base - + sage: K = OK.fraction_field(); K + Fraction Field of + Order in Number Field in a with defining polynomial x^2 - 2 over its base sage: K.ring() Order in Number Field in a with defining polynomial x^2 - 2 over its base sage: K.ring() is OK @@ -2014,10 +2057,11 @@ cdef class RingExtensionFractionField(RingExtension_generic): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = ZZ.extension(x^2 - 2) sage: OK = A.over() sage: K = OK.fraction_field() - sage: K._repr_topring() 'Fraction Field of Order in Number Field in a with defining polynomial x^2 - 2' """ @@ -2058,11 +2102,10 @@ cdef class RingExtensionWithBasis(RingExtension_generic): TESTS:: - sage: E = GF(5^4).over(GF(5^2)) - sage: E + sage: E = GF(5^4).over(GF(5^2)); E # needs sage.rings.finite_rings Field in z4 with defining polynomial x^2 + (4*z2 + 3)*x + z2 over its base - sage: TestSuite(E).run() + sage: TestSuite(E).run() # needs sage.rings.finite_rings """ Element = RingExtensionWithBasisElement @@ -2084,12 +2127,12 @@ cdef class RingExtensionWithBasis(RingExtension_generic): TESTS:: - sage: K.<a> = QQ.extension(x^3 - 2) - sage: E = K.over() - sage: E + sage: x = polygen(ZZ, 'x') + sage: K.<a> = QQ.extension(x^3 - 2) # needs sage.rings.number_field + sage: E = K.over(); E # needs sage.rings.number_field Field in a with defining polynomial x^3 - 2 over its base - sage: TestSuite(E).run() + sage: TestSuite(E).run() # needs sage.rings.number_field """ RingExtension_generic.__init__(self, defining_morphism, **kwargs) self._basis = [ self(b) for b in basis ] @@ -2129,29 +2172,27 @@ cdef class RingExtensionWithBasis(RingExtension_generic): TESTS:: + sage: # needs sage.rings.finite_rings sage: F = GF(5) sage: K = GF(5^2).over(F) sage: L = GF(5^4).over(K) - sage: L._print_option_base(F) is F True sage: L._print_option_base(K) is K True sage: L._print_option_base(GF(5^2)) is K True - sage: L._print_option_base(None) is K True - sage: L._print_option_base(L) Traceback (most recent call last): ... ValueError: base must be strict - sage: K._print_option_base(L) Traceback (most recent call last): ... - ValueError: not (explicitly) defined over Field in z4 with defining polynomial x^2 + (3 - z2)*x + z2 over its base + ValueError: not (explicitly) defined over Field in z4 + with defining polynomial x^2 + (3 - z2)*x + z2 over its base """ if 'print_elements_as' in self._print_options: @@ -2177,6 +2218,8 @@ cdef class RingExtensionWithBasis(RingExtension_generic): TESTS:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = QQ.extension(x^2 - 2) sage: B.<b> = QQ.extension(x^6 - 2) sage: f = A.hom([b^3]) @@ -2202,8 +2245,8 @@ cdef class RingExtensionWithBasis(RingExtension_generic): TESTS:: - sage: K = GF(5^2).over() # over GF(5) - sage: K.is_finite_over() # indirect doctest + sage: K = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: K.is_finite_over() # indirect doctest # needs sage.rings.finite_rings True """ if base is self or base is self._base: @@ -2221,8 +2264,8 @@ cdef class RingExtensionWithBasis(RingExtension_generic): TESTS:: - sage: K = GF(5^2).over() # over GF(5) - sage: K.is_free_over() # indirect doctest + sage: K = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: K.is_free_over() # indirect doctest # needs sage.rings.finite_rings True """ if base is self or base is self._base: @@ -2240,32 +2283,30 @@ cdef class RingExtensionWithBasis(RingExtension_generic): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(5^2).over() # over GF(5) sage: K.<b> = GF(5^4).over(F) sage: L.<c> = GF(5^12).over(K) - sage: L.basis_over(K) [1, c, c^2] - sage: L.basis_over(F) [1, b, c, b*c, c^2, b*c^2] - sage: L.basis_over(GF(5)) [1, a, b, a*b, c, a*c, b*c, a*b*c, c^2, a*c^2, b*c^2, a*b*c^2] If ``base`` is omitted, it is set to its default which is the base of the extension:: - sage: L.basis_over() + sage: L.basis_over() # needs sage.rings.finite_rings [1, c, c^2] - sage: K.basis_over() + sage: K.basis_over() # needs sage.rings.finite_rings [1, b] Note that ``base`` must be an explicit base over which the extension has been defined (as listed by the method :meth:`bases`):: - sage: L.degree_over(GF(5^6)) + sage: L.degree_over(GF(5^6)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field in z6 of size 5^6 @@ -2284,9 +2325,10 @@ cdef class RingExtensionWithBasis(RingExtension_generic): TESTS:: - sage: A.<a> = QQ.extension(x^3 - 2) - sage: K.<u> = A.over() - sage: K.basis_over() + sage: x = polygen(ZZ, 'x') + sage: A.<a> = QQ.extension(x^3 - 2) # needs sage.rings.number_field + sage: K.<u> = A.over() # needs sage.rings.number_field + sage: K.basis_over() # needs sage.rings.number_field [1, u, u^2] """ if base is self: @@ -2324,25 +2366,30 @@ cdef class RingExtensionWithBasis(RingExtension_generic): EXAMPLES:: sage: F = GF(11) - sage: K.<a> = GF(11^2).over() - sage: L.<b> = GF(11^6).over(K) + sage: K.<a> = GF(11^2).over() # needs sage.rings.finite_rings + sage: L.<b> = GF(11^6).over(K) # needs sage.rings.finite_rings Forgetting a part of the multiplicative structure, the field L can be viewed as a vector space of dimension 3 over K, equipped with a distinguished basis, namely `(1, b, b^2)`:: + sage: # needs sage.rings.finite_rings sage: V, i, j = L.free_module(K) sage: V - Vector space of dimension 3 over Field in a with defining polynomial x^2 + 7*x + 2 over its base + Vector space of dimension 3 over + Field in a with defining polynomial x^2 + 7*x + 2 over its base sage: i Generic map: - From: Vector space of dimension 3 over Field in a with defining polynomial x^2 + 7*x + 2 over its base - To: Field in b with defining polynomial x^3 + (7 + 2*a)*x^2 + (2 - a)*x - a over its base + From: Vector space of dimension 3 over + Field in a with defining polynomial x^2 + 7*x + 2 over its base + To: Field in b with defining polynomial + x^3 + (7 + 2*a)*x^2 + (2 - a)*x - a over its base sage: j Generic map: - From: Field in b with defining polynomial x^3 + (7 + 2*a)*x^2 + (2 - a)*x - a over its base - To: Vector space of dimension 3 over Field in a with defining polynomial x^2 + 7*x + 2 over its base - + From: Field in b with defining polynomial + x^3 + (7 + 2*a)*x^2 + (2 - a)*x - a over its base + To: Vector space of dimension 3 over + Field in a with defining polynomial x^2 + 7*x + 2 over its base sage: j(b) (0, 1, 0) sage: i((1, a, a+1)) @@ -2350,27 +2397,28 @@ cdef class RingExtensionWithBasis(RingExtension_generic): Similarly, one can view L as a F-vector space of dimension 6:: - sage: V, i, j, = L.free_module(F) - sage: V + sage: V, i, j, = L.free_module(F) # needs sage.rings.finite_rings + sage: V # needs sage.rings.finite_rings Vector space of dimension 6 over Finite Field of size 11 In this case, the isomorphisms between `V` and `L` are given by the basis `(1, a, b, ab, b^2, ab^2)`: - sage: j(a*b) + sage: j(a*b) # needs sage.rings.finite_rings (0, 0, 0, 1, 0, 0) - sage: i((1,2,3,4,5,6)) + sage: i((1,2,3,4,5,6)) # needs sage.rings.finite_rings (1 + 2*a) + (3 + 4*a)*b + (5 + 6*a)*b^2 When ``base`` is omitted, the default is the base of this extension:: - sage: L.free_module(map=False) - Vector space of dimension 3 over Field in a with defining polynomial x^2 + 7*x + 2 over its base + sage: L.free_module(map=False) # needs sage.rings.finite_rings + Vector space of dimension 3 over + Field in a with defining polynomial x^2 + 7*x + 2 over its base Note that ``base`` must be an explicit base over which the extension has been defined (as listed by the method :meth:`bases`):: - sage: L.degree(GF(11^3)) + sage: L.degree(GF(11^3)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field in z3 of size 11^3 @@ -2406,9 +2454,9 @@ cdef class RingExtensionWithBasis(RingExtension_generic): TESTS:: - sage: K = GF(7^5).over() - sage: L = GF(7^15).over(K) - sage: for base in L.bases(): + sage: K = GF(7^5).over() # needs sage.rings.finite_rings + sage: L = GF(7^15).over(K) # needs sage.rings.finite_rings + sage: for base in L.bases(): # needs sage.rings.finite_rings ....: V, i, j = L.free_module(base) ....: assert([ i(v) for v in V.basis() ] == L.basis_over(base)) ....: assert([ j(x) for x in L.basis_over(base) ] == V.basis()) @@ -2441,38 +2489,40 @@ cdef class RingExtensionWithBasis(RingExtension_generic): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = ZZ.extension(x^2 - 5) sage: OK = A.over() # over ZZ sage: OK Order in Number Field in a with defining polynomial x^2 - 5 over its base - - sage: K1 = OK.fraction_field() - sage: K1 - Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base + sage: K1 = OK.fraction_field(); K1 + Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base sage: K1.bases() - [Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base, + [Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base, Order in Number Field in a with defining polynomial x^2 - 5 over its base, Integer Ring] - - sage: K2 = OK.fraction_field(extend_base=True) - sage: K2 - Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base + sage: K2 = OK.fraction_field(extend_base=True); K2 + Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base sage: K2.bases() - [Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base, + [Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base, Rational Field] Note that there is no coercion map between `K_1` and `K_2`:: - sage: K1.has_coerce_map_from(K2) + sage: K1.has_coerce_map_from(K2) # needs sage.rings.number_field False - sage: K2.has_coerce_map_from(K1) + sage: K2.has_coerce_map_from(K1) # needs sage.rings.number_field False We check that when the extension is a field, its fraction field does not change:: - sage: K1.fraction_field() is K1 + sage: K1.fraction_field() is K1 # needs sage.rings.number_field True - sage: K2.fraction_field() is K2 + sage: K2.fraction_field() is K2 # needs sage.rings.number_field True TESTS:: @@ -2507,12 +2557,12 @@ cdef class RingExtensionWithGen(RingExtensionWithBasis): TESTS:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = QQ.extension(x^3 - 7) sage: K = A.over() - sage: type(K) <class 'sage.rings.ring_extension.RingExtensionWithGen'> - sage: TestSuite(K).run() """ @@ -2534,12 +2584,12 @@ cdef class RingExtensionWithGen(RingExtensionWithBasis): TESTS:: - sage: K.<a> = QQ.extension(x^3 + 3*x + 1) - sage: E = K.over() - sage: E + sage: x = polygen(ZZ, 'x') + sage: K.<a> = QQ.extension(x^3 + 3*x + 1) # needs sage.rings.number_field + sage: E = K.over(); E # needs sage.rings.number_field Field in a with defining polynomial x^3 + 3*x + 1 over its base - sage: TestSuite(E).run() + sage: TestSuite(E).run() # needs sage.rings.number_field """ self._name = names[0] backend_base = backend_parent(defining_morphism.domain()) @@ -2566,10 +2616,10 @@ cdef class RingExtensionWithGen(RingExtensionWithBasis): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^3).over() sage: K._repr_topring() 'Field in a with defining polynomial x^3 + 3*x + 3' - sage: L.<b> = GF(5^9).over(K) sage: L._repr_topring() 'Field in b with defining polynomial x^3 + (1 + 3*a^2)*x^2 + (3 + 2*a + 2*a^2)*x - a' @@ -2584,10 +2634,10 @@ cdef class RingExtensionWithGen(RingExtensionWithBasis): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^3).over() sage: K._latex_topring() '\\Bold{F}_{5}[a]' - sage: L.<b> = GF(5^9).over(K) sage: L._latex_topring() '\\Bold{F}_{5}[a][b]' @@ -2610,10 +2660,10 @@ cdef class RingExtensionWithGen(RingExtensionWithBasis): EXAMPLES:: - sage: K.<u> = GF(7^10).over(GF(7^2)) - sage: K - Field in u with defining polynomial x^5 + (6*z2 + 4)*x^4 + (3*z2 + 5)*x^3 + (2*z2 + 2)*x^2 + 4*x + 6*z2 over its base - + sage: # needs sage.rings.finite_rings + sage: K.<u> = GF(7^10).over(GF(7^2)); K + Field in u with defining polynomial x^5 + (6*z2 + 4)*x^4 + + (3*z2 + 5)*x^3 + (2*z2 + 2)*x^2 + 4*x + 6*z2 over its base sage: P = K.modulus(); P x^5 + (6*z2 + 4)*x^4 + (3*z2 + 5)*x^3 + (2*z2 + 2)*x^2 + 4*x + 6*z2 sage: P(u) @@ -2621,7 +2671,7 @@ cdef class RingExtensionWithGen(RingExtensionWithBasis): We can use a different variable name:: - sage: K.modulus('y') + sage: K.modulus('y') # needs sage.rings.finite_rings y^5 + (6*z2 + 4)*y^4 + (3*z2 + 5)*y^3 + (2*z2 + 2)*y^2 + 4*y + 6*z2 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -2642,10 +2692,10 @@ cdef class RingExtensionWithGen(RingExtensionWithBasis): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^2).over() # over GF(5) sage: K.gens() (a,) - sage: L.<b> = GF(5^4).over(K) sage: L.gens() (b,) @@ -2683,38 +2733,40 @@ cdef class RingExtensionWithGen(RingExtensionWithBasis): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = ZZ.extension(x^2 - 5) sage: OK = A.over() # over ZZ sage: OK Order in Number Field in a with defining polynomial x^2 - 5 over its base - - sage: K1 = OK.fraction_field() - sage: K1 - Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base + sage: K1 = OK.fraction_field(); K1 + Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base sage: K1.bases() - [Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base, + [Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base, Order in Number Field in a with defining polynomial x^2 - 5 over its base, Integer Ring] - - sage: K2 = OK.fraction_field(extend_base=True) - sage: K2 - Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base + sage: K2 = OK.fraction_field(extend_base=True); K2 + Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base sage: K2.bases() - [Fraction Field of Order in Number Field in a with defining polynomial x^2 - 5 over its base, + [Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 5 over its base, Rational Field] Note that there is no coercion map between `K_1` and `K_2`:: - sage: K1.has_coerce_map_from(K2) + sage: K1.has_coerce_map_from(K2) # needs sage.rings.number_field False - sage: K2.has_coerce_map_from(K1) + sage: K2.has_coerce_map_from(K1) # needs sage.rings.number_field False We check that when the extension is a field, its fraction field does not change:: - sage: K1.fraction_field() is K1 + sage: K1.fraction_field() is K1 # needs sage.rings.number_field True - sage: K2.fraction_field() is K2 + sage: K2.fraction_field() is K2 # needs sage.rings.number_field True TESTS:: diff --git a/src/sage/rings/ring_extension_conversion.pyx b/src/sage/rings/ring_extension_conversion.pyx index 9d94fb7567d..eeb6077cd0a 100644 --- a/src/sage/rings/ring_extension_conversion.pyx +++ b/src/sage/rings/ring_extension_conversion.pyx @@ -1,3 +1,5 @@ +# sage.doctest: needs sage.rings.finite_rings + ############################################################################# # Copyright (C) 2019 Xavier Caruso <xavier.caruso@normalesup.org> # diff --git a/src/sage/rings/ring_extension_element.pyx b/src/sage/rings/ring_extension_element.pyx index 134cd1a1174..fb80ba84e6e 100644 --- a/src/sage/rings/ring_extension_element.pyx +++ b/src/sage/rings/ring_extension_element.pyx @@ -6,32 +6,30 @@ AUTHOR: - Xavier Caruso (2019) """ -############################################################################# +# ########################################################################### # Copyright (C) 2019 Xavier Caruso <xavier.caruso@normalesup.org> # # 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. -# http://www.gnu.org/licenses/ -#**************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from sage.ext.stdsage cimport PY_NEW -from sage.misc.cachefunc import cached_method from sage.cpython.getattr cimport AttributeErrorMessage from sage.cpython.getattr import dir_with_other_class from sage.misc.latex import latex from sage.structure.category_object import normalize_names from sage.structure.element cimport CommutativeAlgebraElement -from sage.structure.element cimport Element from sage.rings.integer_ring import ZZ from sage.categories.fields import Fields from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.ring_extension cimport RingExtension_generic, RingExtensionWithGen, RingExtensionFractionField -from sage.rings.ring_extension_morphism cimport MapRelativeRingToFreeModule +from sage.rings.ring_extension_morphism cimport MapRelativeRingToFreeModule, are_equal_morphisms from sage.rings.ring_extension_conversion cimport backend_parent, backend_element from sage.rings.ring_extension_conversion cimport to_backend, from_backend @@ -45,9 +43,9 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): TESTS:: - sage: K = GF(5^4).over() - sage: x = K.random_element() - sage: TestSuite(x).run() + sage: K = GF(5^4).over() # needs sage.rings.finite_rings + sage: x = K.random_element() # needs sage.rings.finite_rings + sage: TestSuite(x).run() # needs sage.rings.finite_rings """ def __init__(self, RingExtension_generic parent, x, *args, **kwds): @@ -88,6 +86,7 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): TESTS:: + sage: # needs sage.rings.finite_rings sage: K = GF(5^3).over() sage: x = K.random_element() sage: type(x) @@ -105,9 +104,10 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = QQ.extension(x^2 - 2) sage: K.<a> = A.over() # over QQ - sage: hasattr(a, 'continued_fraction') True sage: a.continued_fraction() @@ -138,9 +138,10 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = QQ.extension(x^2 - 2) sage: K.<a> = A.over() - sage: dir(a) ['__abs__', '__add__', @@ -173,8 +174,8 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): EXAMPLES: - sage: E.<a> = GF(5^3).over() - sage: hash(a) + sage: E.<a> = GF(5^3).over() # needs sage.rings.finite_rings + sage: hash(a) # needs sage.rings.finite_rings 5 """ return hash(self._backend) @@ -188,9 +189,9 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): TESTS:: - sage: K.<a> = GF(5^2).over() - sage: L.<b> = GF(5^4).over(K) - sage: b._repr_() + sage: K.<a> = GF(5^2).over() # needs sage.rings.finite_rings + sage: L.<b> = GF(5^4).over(K) # needs sage.rings.finite_rings + sage: b._repr_() # needs sage.rings.finite_rings 'b' """ cdef RingExtension_generic parent = self._parent @@ -232,9 +233,9 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): TESTS:: - sage: K.<a> = GF(5^2).over() - sage: L.<b> = GF(5^4).over(K) - sage: b._latex_() + sage: K.<a> = GF(5^2).over() # needs sage.rings.finite_rings + sage: L.<b> = GF(5^4).over(K) # needs sage.rings.finite_rings + sage: b._latex_() # needs sage.rings.finite_rings 'b' """ cdef RingExtension_generic parent = self._parent @@ -267,6 +268,96 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): """ return latex(self._backend) + def backend(self, force=False): + """ + Return the backend of this element. + + INPUT: + + - ``force`` -- a boolean (default: ``False``); if ``False``, + raise an error if the backend is not exposed + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: F = GF(5^2) + sage: K.<z> = GF(5^4).over(F) + sage: x = z^10 + sage: x + (z2 + 2) + (3*z2 + 1)*z + sage: y = x.backend() + sage: y + 4*z4^3 + 2*z4^2 + 4*z4 + 4 + sage: y.parent() + Finite Field in z4 of size 5^4 + + """ + if force or (<RingExtension_generic>(self._parent))._is_backend_exposed: + return self._backend + raise ValueError("backend is not exposed; try force=True") + + def in_base(self): + r""" + Return this element as an element of the base. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: F = GF(5^2) + sage: K.<z> = GF(5^4).over(F) + sage: x = z^3 + z^2 + z + 4 + sage: y = x.in_base() + sage: y + z2 + 1 + sage: y.parent() + Finite Field in z2 of size 5^2 + + When the element is not in the base, an error is raised:: + + sage: z.in_base() # needs sage.rings.finite_rings + Traceback (most recent call last): + ... + ValueError: z is not in the base + + :: + + sage: # needs sage.rings.finite_rings + sage: S.<X> = F[] + sage: E = S.over(F) + sage: f = E(1) + sage: g = f.in_base(); g + 1 + sage: g.parent() + Finite Field in z2 of size 5^2 + + TESTS:: + + We check the case of a tower of extensions:: + + sage: # needs sage.rings.finite_rings + sage: F = GF(5^2) + sage: K.<u> = GF(5^4).over(F) + sage: L.<v> = GF(5^8).over(K) + sage: x = 4*v^7 + v^6 + 3*v^4 + v^3 + v^2 + 4 + sage: x.in_base() + u + + """ + cdef RingExtension_generic parent = <RingExtension_generic>self._parent + if isinstance(parent, RingExtensionWithGen): + v = self.vector() + for i in range(1, len(v)): + if v[i]: + raise ValueError("%s is not in the base" % self) + return v[0] + else: + f = parent._backend_defining_morphism + base = f.domain() + ring = f.codomain() + if ring.has_coerce_map_from(base) and are_equal_morphisms(f, None): + return parent.base()(base(self._backend)) + raise NotImplementedError("cannot cast %s to the base" % self) + cpdef _richcmp_(left, right, int op): r""" Compare this element with ``right`` according to @@ -283,6 +374,7 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^2).over() sage: x = K.random_element() sage: x == x @@ -300,10 +392,10 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): TESTS:: + sage: # needs sage.rings.finite_rings sage: K = GF(5^4).over(GF(5^2)) sage: x = K.random_element() sage: y = K.random_element() - sage: (x+y).parent() is K True sage: x + y == y + x @@ -320,9 +412,9 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): TESTS:: + sage: # needs sage.rings.finite_rings sage: K = GF(5^4).over(GF(5^2)) sage: x = K.random_element() - sage: y = -x sage: y.parent() is K True @@ -340,11 +432,11 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): TESTS:: + sage: # needs sage.rings.finite_rings sage: K = GF(5^4).over(GF(5^2)) sage: x = K.random_element() sage: y = K.random_element() - - sage: (x-y).parent() is K + sage: (x - y).parent() is K True sage: x - y == x + (-y) True @@ -360,10 +452,10 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): TESTS:: + sage: # needs sage.rings.finite_rings sage: K = GF(5^4).over(GF(5^2)) sage: x = K.random_element() sage: y = K.random_element() - sage: (x*y).parent() is K True sage: x * y == y * x @@ -381,14 +473,16 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): TESTS:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = ZZ.extension(x^2 - 2) sage: OK = A.over() sage: a = OK(a) - sage: b = 1/a; b a/2 sage: b.parent() - Fraction Field of Order in Number Field in a with defining polynomial x^2 - 2 over its base + Fraction Field of + Order in Number Field in a with defining polynomial x^2 - 2 over its base sage: a*b 1 """ @@ -408,8 +502,8 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): EXAMPLES:: - sage: K.<a> = GF(5^4).over(GF(5^2)) - sage: a.additive_order() + sage: K.<a> = GF(5^4).over(GF(5^2)) # needs sage.rings.finite_rings + sage: a.additive_order() # needs sage.rings.finite_rings 5 """ return self._backend.additive_order() @@ -420,8 +514,8 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): EXAMPLES:: - sage: K.<a> = GF(5^4).over(GF(5^2)) - sage: a.multiplicative_order() + sage: K.<a> = GF(5^4).over(GF(5^2)) # needs sage.rings.finite_rings + sage: a.multiplicative_order() # needs sage.rings.finite_rings 624 """ return self._backend.multiplicative_order() @@ -464,9 +558,9 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): sage: A.<x> = PolynomialRing(QQ) sage: E = A.over(QQ) - sage: E(x^2+1).is_prime() + sage: E(x^2 + 1).is_prime() # needs sage.libs.pari True - sage: E(x^2-1).is_prime() + sage: E(x^2 - 1).is_prime() # needs sage.libs.pari False """ return self._backend.is_prime() @@ -482,12 +576,12 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^3).over() sage: a.is_square() False sage: a.is_square(root=True) (False, None) - sage: b = a + 1 sage: b.is_square() True @@ -511,7 +605,7 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): - ``extend`` -- a boolean (default: ``True``); if "True", return a square root in an extension ring, if necessary. - Otherwise, raise a ``ValueError`` if the root is not in + Otherwise, raise a :class:`ValueError` if the root is not in the ring - ``all`` -- a boolean (default: ``False``); if ``True``, @@ -522,10 +616,11 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): .. NOTE:: - The option `extend=True` is often not implemented. + The option ``extend=True`` is often not implemented. EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^3).over() sage: b = a + 1 sage: b.sqrt() @@ -576,8 +671,8 @@ cdef class RingExtensionFractionFieldElement(RingExtensionElement): EXAMPLES: - sage: E.<a> = GF(5^3).over() - sage: hash(a) + sage: E.<a> = GF(5^3).over() # needs sage.rings.finite_rings + sage: hash(a) # needs sage.rings.finite_rings 5 """ return hash(self._backend) @@ -656,12 +751,13 @@ cdef class RingExtensionFractionFieldElement(RingExtensionElement): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<a> = ZZ.extension(x^2 - 2) sage: OK = A.over() # over ZZ - sage: K = OK.fraction_field() - sage: K - Fraction Field of Order in Number Field in a with defining polynomial x^2 - 2 over its base - + sage: K = OK.fraction_field(); K + Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 2 over its base sage: x = K(1/a); x a/2 sage: num = x.numerator(); num @@ -670,13 +766,14 @@ cdef class RingExtensionFractionFieldElement(RingExtensionElement): The numerator is an element of the ring which was used to construct the fraction field:: - sage: num.parent() + sage: num.parent() # needs sage.rings.number_field Order in Number Field in a with defining polynomial x^2 - 2 over its base - sage: num.parent() is OK + sage: num.parent() is OK # needs sage.rings.number_field True TESTS:: + sage: # needs sage.rings.number_field sage: x = K.random_element() sage: x == x.numerator() / x.denominator() True @@ -691,13 +788,13 @@ cdef class RingExtensionFractionFieldElement(RingExtensionElement): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = ZZ[] sage: A.<a> = ZZ.extension(x^2 - 2) sage: OK = A.over() # over ZZ - sage: K = OK.fraction_field() - sage: K - Fraction Field of Order in Number Field in a with defining polynomial x^2 - 2 over its base - + sage: K = OK.fraction_field(); K + Fraction Field of Order in Number Field in a + with defining polynomial x^2 - 2 over its base sage: x = K(1/a); x a/2 sage: denom = x.denominator(); denom @@ -706,13 +803,14 @@ cdef class RingExtensionFractionFieldElement(RingExtensionElement): The denominator is an element of the ring which was used to construct the fraction field:: - sage: denom.parent() + sage: denom.parent() # needs sage.rings.number_field Order in Number Field in a with defining polynomial x^2 - 2 over its base - sage: denom.parent() is OK + sage: denom.parent() is OK # needs sage.rings.number_field True TESTS:: + sage: # needs sage.rings.number_field sage: x = K.random_element() sage: x == x.numerator() / x.denominator() True @@ -731,6 +829,7 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): TESTS:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^3).over() sage: L.<b> = GF(5^9).over(K) sage: type(b) @@ -743,8 +842,8 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): EXAMPLES: - sage: E.<a> = GF(5^3).over() - sage: hash(a) + sage: E.<a> = GF(5^3).over() # needs sage.rings.finite_rings + sage: hash(a) # needs sage.rings.finite_rings 5 """ return hash(self._backend) @@ -762,10 +861,10 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^3).over() sage: L.<b> = GF(5^9).over(K) sage: u = 1/(a+b) - sage: u._repr_extension(base=K) '(2 + 2*a) + (-1 + a - a^2)*b + (2 + 3*a + 3*a^2)*b^2' sage: u._repr_extension(base=GF(5)) @@ -840,10 +939,10 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^3).over() sage: L.<b> = GF(5^9).over(K) sage: u = 1/(a+b) - sage: u._latex_extension(base=K) \left( 2 + 2 a \right) + \left( -1 + a - a^{2} \right) b + \left( 2 + 3 a + 3 a^{2} \right) b^{2} sage: u._latex_extension(base=GF(5)) @@ -906,28 +1005,27 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5) sage: K.<a> = GF(5^2).over() # over F sage: L.<b> = GF(5^6).over(K) sage: x = (a+b)^4; x (-1 + a) + (3 + a)*b + (1 - a)*b^2 - - sage: x.vector(K) # basis is (1, b, b^2) + sage: x.vector(K) # basis is (1, b, b^2) (-1 + a, 3 + a, 1 - a) - - sage: x.vector(F) # basis is (1, a, b, a*b, b^2, a*b^2) + sage: x.vector(F) # basis is (1, a, b, a*b, b^2, a*b^2) (4, 1, 3, 1, 1, 4) If ``base`` is omitted, it is set to its default which is the base of the extension:: - sage: x.vector() + sage: x.vector() # needs sage.rings.finite_rings (-1 + a, 3 + a, 1 - a) Note that ``base`` must be an explicit base over which the extension has been defined (as listed by the method :meth:`bases`):: - sage: x.vector(GF(5^3)) + sage: x.vector(GF(5^3)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field in z3 of size 5^3 @@ -947,6 +1045,7 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): TESTS:: + sage: # needs sage.rings.finite_rings sage: K = GF(11^10).over(GF(11^2)) sage: x = K.random_element() sage: coeffs = x.vector() @@ -970,12 +1069,12 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(5^2).over() # over GF(5) sage: K.<b> = GF(5^4).over(F) sage: L.<c> = GF(5^12).over(K) sage: u = 1/(a + b + c); u (2 + (-1 - a)*b) + ((2 + 3*a) + (1 - a)*b)*c + ((-1 - a) - a*b)*c^2 - sage: P = u.polynomial(K); P ((-1 - a) - a*b)*x^2 + ((2 + 3*a) + (1 - a)*b)*x + 2 + (-1 - a)*b sage: P.base_ring() is K @@ -985,40 +1084,40 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): When the base is `F`, we obtain a bivariate polynomial:: - sage: P = u.polynomial(F); P + sage: P = u.polynomial(F); P # needs sage.rings.finite_rings (-a)*x0^2*x1 + (-1 - a)*x0^2 + (1 - a)*x0*x1 + (2 + 3*a)*x0 + (-1 - a)*x1 + 2 We check that its value at the generators is the element we started with:: - sage: L.gens(F) + sage: L.gens(F) # needs sage.rings.finite_rings (c, b) - sage: P(c, b) == u + sage: P(c, b) == u # needs sage.rings.finite_rings True Similarly, when the base is ``GF(5)``, we get a trivariate polynomial: - sage: P = u.polynomial(GF(5)); P + sage: P = u.polynomial(GF(5)); P # needs sage.rings.finite_rings -x0^2*x1*x2 - x0^2*x2 - x0*x1*x2 - x0^2 + x0*x1 - 2*x0*x2 - x1*x2 + 2*x0 - x1 + 2 - sage: P(c, b, a) == u + sage: P(c, b, a) == u # needs sage.rings.finite_rings True Different variable names can be specified:: - sage: u.polynomial(GF(5), var='y') + sage: u.polynomial(GF(5), var='y') # needs sage.rings.finite_rings -y0^2*y1*y2 - y0^2*y2 - y0*y1*y2 - y0^2 + y0*y1 - 2*y0*y2 - y1*y2 + 2*y0 - y1 + 2 - sage: u.polynomial(GF(5), var=['x','y','z']) + sage: u.polynomial(GF(5), var=['x','y','z']) # needs sage.rings.finite_rings -x^2*y*z - x^2*z - x*y*z - x^2 + x*y - 2*x*z - y*z + 2*x - y + 2 If ``base`` is omitted, it is set to its default which is the base of the extension:: - sage: u.polynomial() + sage: u.polynomial() # needs sage.rings.finite_rings ((-1 - a) - a*b)*x^2 + ((2 + 3*a) + (1 - a)*b)*x + 2 + (-1 - a)*b Note that ``base`` must be an explicit base over which the extension has been defined (as listed by the method :meth:`bases`):: - sage: u.polynomial(GF(5^3)) + sage: u.polynomial(GF(5^3)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field in z3 of size 5^3 @@ -1059,10 +1158,10 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^3).over() # over GF(5) sage: L.<b> = GF(5^6).over(K) sage: u = a/(1+b) - sage: u (2 + a + 3*a^2) + (3 + 3*a + a^2)*b sage: b*u @@ -1070,7 +1169,6 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): sage: u.matrix(K) [2 + a + 3*a^2 3 + 3*a + a^2] [ 3 + 2*a^2 2 + 2*a - a^2] - sage: u.matrix(GF(5)) [2 1 3 3 3 1] [1 3 1 2 0 3] @@ -1082,14 +1180,14 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): If ``base`` is omitted, it is set to its default which is the base of the extension:: - sage: u.matrix() + sage: u.matrix() # needs sage.rings.finite_rings [2 + a + 3*a^2 3 + 3*a + a^2] [ 3 + 2*a^2 2 + 2*a - a^2] Note that ``base`` must be an explicit base over which the extension has been defined (as listed by the method :meth:`bases`):: - sage: u.matrix(GF(5^2)) + sage: u.matrix(GF(5^2)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field in z2 of size 5^2 @@ -1115,10 +1213,10 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): TESTS:: + sage: # needs sage.rings.finite_rings sage: F = GF(11^2) sage: K = GF(11^6).over(F) sage: L = GF(11^18).over(K) - sage: for base in L.bases(): ....: x = L.random_element() ....: y = L.random_element() @@ -1143,41 +1241,41 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5) sage: K.<a> = GF(5^3).over(F) sage: L.<b> = GF(5^6).over(K) sage: u = a/(1+b) - sage: tr = u.trace(K); tr -1 + 3*a + 2*a^2 We check that the trace lives in the base ring:: - sage: tr.parent() + sage: tr.parent() # needs sage.rings.finite_rings Field in a with defining polynomial x^3 + 3*x + 3 over its base - sage: tr.parent() is K + sage: tr.parent() is K # needs sage.rings.finite_rings True Similarly, one can compute the trace over F:: - sage: u.trace(F) + sage: u.trace(F) # needs sage.rings.finite_rings 0 We check the transitivity of the trace:: - sage: u.trace(F) == tr.trace(F) + sage: u.trace(F) == tr.trace(F) # needs sage.rings.finite_rings True If ``base`` is omitted, it is set to its default which is the base of the extension:: - sage: u.trace() + sage: u.trace() # needs sage.rings.finite_rings -1 + 3*a + 2*a^2 Note that ``base`` must be an explicit base over which the extension has been defined (as listed by the method :meth:`bases`):: - sage: u.trace(GF(5^2)) + sage: u.trace(GF(5^2)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field in z2 of size 5^2 @@ -1202,14 +1300,13 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): TESTS:: + sage: # needs sage.rings.finite_rings sage: F = GF(11^2) sage: K = GF(11^6).over(F) sage: L = GF(11^18).over(K) - sage: x = L.random_element() sage: x.trace(F) == x.trace().trace() True - sage: for base in L.bases(): ....: x = L.random_element() ....: y = L.random_element() @@ -1237,41 +1334,41 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5) sage: K.<a> = GF(5^3).over(F) sage: L.<b> = GF(5^6).over(K) sage: u = a/(1+b) - sage: nr = u.norm(K); nr 3 + 2*a^2 We check that the norm lives in the base ring:: - sage: nr.parent() + sage: nr.parent() # needs sage.rings.finite_rings Field in a with defining polynomial x^3 + 3*x + 3 over its base - sage: nr.parent() is K + sage: nr.parent() is K # needs sage.rings.finite_rings True Similarly, one can compute the norm over F:: - sage: u.norm(F) + sage: u.norm(F) # needs sage.rings.finite_rings 4 We check the transitivity of the norm:: - sage: u.norm(F) == nr.norm(F) + sage: u.norm(F) == nr.norm(F) # needs sage.rings.finite_rings True If ``base`` is omitted, it is set to its default which is the base of the extension:: - sage: u.norm() + sage: u.norm() # needs sage.rings.finite_rings 3 + 2*a^2 Note that ``base`` must be an explicit base over which the extension has been defined (as listed by the method :meth:`bases`):: - sage: u.norm(GF(5^2)) + sage: u.norm(GF(5^2)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field in z2 of size 5^2 @@ -1296,14 +1393,13 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): TESTS:: + sage: # needs sage.rings.finite_rings sage: F = GF(11^2) sage: K = GF(11^6).over(F) sage: L = GF(11^18).over(K) - sage: x = L.random_element() sage: x.norm(F) == x.norm().norm() True - sage: for base in L.bases(): ....: x = L.random_element() ....: y = L.random_element() @@ -1331,46 +1427,46 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5) sage: K.<a> = GF(5^3).over(F) sage: L.<b> = GF(5^6).over(K) sage: u = a/(1+b) - sage: chi = u.charpoly(K); chi x^2 + (1 + 2*a + 3*a^2)*x + 3 + 2*a^2 We check that the charpoly has coefficients in the base ring:: - sage: chi.base_ring() + sage: chi.base_ring() # needs sage.rings.finite_rings Field in a with defining polynomial x^3 + 3*x + 3 over its base - sage: chi.base_ring() is K + sage: chi.base_ring() is K # needs sage.rings.finite_rings True and that it annihilates u:: - sage: chi(u) + sage: chi(u) # needs sage.rings.finite_rings 0 Similarly, one can compute the characteristic polynomial over F:: - sage: u.charpoly(F) + sage: u.charpoly(F) # needs sage.rings.finite_rings x^6 + x^4 + 2*x^3 + 3*x + 4 A different variable name can be specified:: - sage: u.charpoly(F, var='t') + sage: u.charpoly(F, var='t') # needs sage.rings.finite_rings t^6 + t^4 + 2*t^3 + 3*t + 4 If ``base`` is omitted, it is set to its default which is the base of the extension:: - sage: u.charpoly() + sage: u.charpoly() # needs sage.rings.finite_rings x^2 + (1 + 2*a + 3*a^2)*x + 3 + 2*a^2 Note that ``base`` must be an explicit base over which the extension has been defined (as listed by the method :meth:`bases`):: - sage: u.charpoly(GF(5^2)) + sage: u.charpoly(GF(5^2)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field in z2 of size 5^2 @@ -1380,9 +1476,9 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): We check that the characteristic polynomial of an element in the base ring is a power of a polynomial of degree 1:: - sage: S.<x> = K[] - sage: u = K.random_element() - sage: L(u).charpoly() == (x - u)^2 + sage: S.<x> = K[] # needs sage.rings.finite_rings + sage: u = K.random_element() # needs sage.rings.finite_rings + sage: L(u).charpoly() == (x - u)^2 # needs sage.rings.finite_rings True """ return self.matrix(base).charpoly(var) @@ -1398,46 +1494,46 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(5) sage: K.<a> = GF(5^3).over(F) sage: L.<b> = GF(5^6).over(K) sage: u = 1 / (a+b) - sage: chi = u.minpoly(K); chi x^2 + (2*a + a^2)*x - 1 + a We check that the minimal polynomial has coefficients in the base ring:: - sage: chi.base_ring() + sage: chi.base_ring() # needs sage.rings.finite_rings Field in a with defining polynomial x^3 + 3*x + 3 over its base - sage: chi.base_ring() is K + sage: chi.base_ring() is K # needs sage.rings.finite_rings True and that it annihilates u:: - sage: chi(u) + sage: chi(u) # needs sage.rings.finite_rings 0 Similarly, one can compute the minimal polynomial over F:: - sage: u.minpoly(F) + sage: u.minpoly(F) # needs sage.rings.finite_rings x^6 + 4*x^5 + x^4 + 2*x^2 + 3 A different variable name can be specified:: - sage: u.minpoly(F, var='t') + sage: u.minpoly(F, var='t') # needs sage.rings.finite_rings t^6 + 4*t^5 + t^4 + 2*t^2 + 3 If ``base`` is omitted, it is set to its default which is the base of the extension:: - sage: u.minpoly() + sage: u.minpoly() # needs sage.rings.finite_rings x^2 + (2*a + a^2)*x - 1 + a Note that ``base`` must be an explicit base over which the extension has been defined (as listed by the method :meth:`bases`):: - sage: u.minpoly(GF(5^2)) + sage: u.minpoly(GF(5^2)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: not (explicitly) defined over Finite Field in z2 of size 5^2 @@ -1447,15 +1543,15 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): We check that the minimal polynomial of an element in the base ring has degree 1:: - sage: S.<x> = K[] - sage: u = K.random_element() - sage: L(u).minpoly() == x - u + sage: S.<x> = K[] # needs sage.rings.finite_rings + sage: u = K.random_element() # needs sage.rings.finite_rings + sage: L(u).minpoly() == x - u # needs sage.rings.finite_rings True In a similar fashion, the minimal polynomial over `F` of an element of `K` should have degree 1 or 3:: - sage: L(u).minpoly(F).degree() in [ 1, 3 ] + sage: L(u).minpoly(F).degree() in [ 1, 3 ] # needs sage.rings.finite_rings True """ cdef RingExtensionWithBasis parent = self._parent diff --git a/src/sage/rings/ring_extension_homset.py b/src/sage/rings/ring_extension_homset.py index 28b2b736dd8..d2c13a11f0e 100644 --- a/src/sage/rings/ring_extension_homset.py +++ b/src/sage/rings/ring_extension_homset.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Homset between extensions of rings @@ -29,7 +30,9 @@ class RingExtensionHomset(RingHomset_generic): sage: L = GF(5^8).over(K) sage: H = Hom(K,L) sage: H - Set of Homomorphisms from Field in z2 with defining polynomial x^2 + 4*x + 2 over its base to Field in z8 with defining polynomial x^4 + (3 - z2)*x + z2 over its base + Set of Homomorphisms + from Field in z2 with defining polynomial x^2 + 4*x + 2 over its base + to Field in z8 with defining polynomial x^4 + (3 - z2)*x + z2 over its base sage: type(H) <... 'sage.rings.ring_extension_homset.RingExtensionHomset_with_category'> @@ -44,7 +47,8 @@ def __call__(self, *args, **kwargs): sage: K.<a> = GF(5^2).over() sage: L.<b> = GF(5^4).over(K) sage: Hom(L,L)([b^5, a^5]) - Ring endomorphism of Field in b with defining polynomial x^2 + (3 - a)*x + a over its base + Ring endomorphism of + Field in b with defining polynomial x^2 + (3 - a)*x + a over its base Defn: b |--> (2 + a) + 2*b with map on base ring: a |--> 1 - a diff --git a/src/sage/rings/ring_extension_morphism.pyx b/src/sage/rings/ring_extension_morphism.pyx index 2cde5d9502d..f861d015a35 100644 --- a/src/sage/rings/ring_extension_morphism.pyx +++ b/src/sage/rings/ring_extension_morphism.pyx @@ -83,20 +83,18 @@ cdef class RingExtensionHomomorphism(RingMap): TESTS:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^2).over() sage: L.<b> = GF(5^4).over(K) - sage: phi = L.hom([b^5, a^5]) - sage: phi - Ring endomorphism of Field in b with defining polynomial x^2 + (3 - a)*x + a over its base + sage: phi = L.hom([b^5, a^5]); phi + Ring endomorphism of Field in b + with defining polynomial x^2 + (3 - a)*x + a over its base Defn: b |--> (2 + a) + 2*b with map on base ring: a |--> 1 - a - sage: type(phi) <class 'sage.rings.ring_extension_morphism.RingExtensionHomomorphism'> - sage: TestSuite(phi).run() - """ def __init__(self, parent, defn, base_map=None, check=True): r""" @@ -117,8 +115,7 @@ cdef class RingExtensionHomomorphism(RingMap): sage: S.<x> = QQ[] sage: T.<x,y> = QQ[] - sage: f = T.hom([x^2, y^2]) - sage: f + sage: f = T.hom([x^2, y^2]); f Ring endomorphism of Multivariate Polynomial Ring in x, y over Rational Field Defn: x |--> x^2 y |--> y^2 @@ -220,13 +217,12 @@ cdef class RingExtensionHomomorphism(RingMap): EXAMPLES:: - sage: K.<a> = GF(5^2).over() # over GF(5) - sage: f = K.hom([a^5]) - sage: f + sage: K.<a> = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: f = K.hom([a^5]); f # needs sage.rings.finite_rings Ring endomorphism of Field in a with defining polynomial x^2 + 4*x + 2 over its base Defn: a |--> 1 - a - sage: f._repr_type() + sage: f._repr_type() # needs sage.rings.finite_rings 'Ring' """ return "Ring" @@ -241,10 +237,11 @@ cdef class RingExtensionHomomorphism(RingMap): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(QQ, 'x') sage: A.<sqrt2> = QQ.extension(x^2 - 2) sage: K.<sqrt2> = A.over() - sage: f = K.hom([-sqrt2]) - sage: f + sage: f = K.hom([-sqrt2]); f Ring endomorphism of Field in sqrt2 with defining polynomial x^2 - 2 over its base Defn: sqrt2 |--> -sqrt2 sage: f(sqrt2) @@ -254,7 +251,7 @@ cdef class RingExtensionHomomorphism(RingMap): sage: a = QQ.random_element() sage: b = QQ.random_element() - sage: f(a + b*sqrt2) == a - b*sqrt2 + sage: f(a + b*sqrt2) == a - b*sqrt2 # needs sage.rings.number_field True """ y = self._backend(backend_element(x)) @@ -271,18 +268,18 @@ cdef class RingExtensionHomomorphism(RingMap): EXAMPLES:: sage: F = GF(5) - sage: K.<a> = GF(5^2).over(F) - sage: L.<b> = GF(5^6).over(K) + sage: K.<a> = GF(5^2).over(F) # needs sage.rings.finite_rings + sage: L.<b> = GF(5^6).over(K) # needs sage.rings.finite_rings We define the absolute Frobenius of L:: - sage: FrobL = L.hom([b^5, a^5]) - sage: FrobL - Ring endomorphism of Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base + sage: FrobL = L.hom([b^5, a^5]); FrobL # needs sage.rings.finite_rings + Ring endomorphism of + Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base Defn: b |--> (-1 + a) + (1 + 2*a)*b + a*b^2 with map on base ring: a |--> 1 - a - sage: FrobL.base_map() + sage: FrobL.base_map() # needs sage.rings.finite_rings Ring morphism: From: Field in a with defining polynomial x^2 + 4*x + 2 over its base To: Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base @@ -291,11 +288,11 @@ cdef class RingExtensionHomomorphism(RingMap): The square of ``FrobL`` acts trivially on K; in other words, it has a trivial base map:: - sage: phi = FrobL^2 - sage: phi - Ring endomorphism of Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base + sage: phi = FrobL^2; phi # needs sage.rings.finite_rings + Ring endomorphism of + Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base Defn: b |--> 2 + 2*a*b + (2 - a)*b^2 - sage: phi.base_map() + sage: phi.base_map() # needs sage.rings.finite_rings """ domain = self.domain() @@ -334,12 +331,11 @@ cdef class RingExtensionHomomorphism(RingMap): TESTS:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^2).over() # over GF(5) sage: L.<b> = GF(5^6).over(K) - sage: FrobK = K.hom([a^5]) sage: FrobL = L.hom([b^5], base_map=FrobK) - sage: FrobK^2 == End(K).identity() True sage: FrobL^6 == End(L).identity() @@ -358,6 +354,7 @@ cdef class RingExtensionHomomorphism(RingMap): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^2).over() # over GF(5) sage: FrobK = K.hom([a^5]) sage: FrobK.is_identity() @@ -367,9 +364,9 @@ cdef class RingExtensionHomomorphism(RingMap): Coercion maps are not considered as identity morphisms:: + sage: # needs sage.rings.finite_rings sage: L.<b> = GF(5^6).over(K) - sage: iota = L.defining_morphism() - sage: iota + sage: iota = L.defining_morphism(); iota Ring morphism: From: Field in a with defining polynomial x^2 + 4*x + 2 over its base To: Field in b with defining polynomial x^3 + (2 + 2*a)*x - a over its base @@ -387,19 +384,19 @@ cdef class RingExtensionHomomorphism(RingMap): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K = GF(5^10).over(GF(5^5)) - sage: iota = K.defining_morphism() - sage: iota + sage: iota = K.defining_morphism(); iota Ring morphism: From: Finite Field in z5 of size 5^5 - To: Field in z10 with defining polynomial x^2 + (2*z5^3 + 2*z5^2 + 4*z5 + 4)*x + z5 over its base + To: Field in z10 with defining polynomial + x^2 + (2*z5^3 + 2*z5^2 + 4*z5 + 4)*x + z5 over its base Defn: z5 |--> z5 sage: iota.is_injective() True sage: K = GF(7).over(ZZ) - sage: iota = K.defining_morphism() - sage: iota + sage: iota = K.defining_morphism(); iota Ring morphism: From: Integer Ring To: Finite Field of size 7 over its base @@ -415,19 +412,19 @@ cdef class RingExtensionHomomorphism(RingMap): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K = GF(5^10).over(GF(5^5)) - sage: iota = K.defining_morphism() - sage: iota + sage: iota = K.defining_morphism(); iota Ring morphism: From: Finite Field in z5 of size 5^5 - To: Field in z10 with defining polynomial x^2 + (2*z5^3 + 2*z5^2 + 4*z5 + 4)*x + z5 over its base + To: Field in z10 with defining polynomial + x^2 + (2*z5^3 + 2*z5^2 + 4*z5 + 4)*x + z5 over its base Defn: z5 |--> z5 sage: iota.is_surjective() False sage: K = GF(7).over(ZZ) - sage: iota = K.defining_morphism() - sage: iota + sage: iota = K.defining_morphism(); iota Ring morphism: From: Integer Ring To: Finite Field of size 7 over its base @@ -446,10 +443,10 @@ cdef class RingExtensionHomomorphism(RingMap): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^2).over() # over GF(5) sage: L.<b> = GF(5^6).over(K) sage: FrobL = L.hom([b^5, a^5]) # absolute Frobenius - sage: print(FrobL._repr_defn()) b |--> (-1 + a) + (1 + 2*a)*b + a*b^2 with map on base ring: @@ -477,13 +474,13 @@ cdef class RingExtensionHomomorphism(RingMap): TESTS:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: A.<sqrt5> = QQ.extension(x^2 - 5) sage: K.<sqrt5> = A.over() - sage: f = K.hom([-sqrt5]) - sage: f + sage: f = K.hom([-sqrt5]); f Ring endomorphism of Field in sqrt5 with defining polynomial x^2 - 5 over its base Defn: sqrt5 |--> -sqrt5 - sage: f^2 # indirect doctest Ring endomorphism of Field in sqrt5 with defining polynomial x^2 - 5 over its base Defn: sqrt5 |--> sqrt5 @@ -503,9 +500,9 @@ cdef class RingExtensionHomomorphism(RingMap): TESTS:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF(5^2).over() # over GF(5) sage: f = K.hom([a^5]) - sage: g = copy(f) # indirect doctest sage: f == g True @@ -521,9 +518,9 @@ cdef class RingExtensionHomomorphism(RingMap): TESTS:: - sage: K.<a> = GF(5^2).over() # over GF(5) - sage: f = K.hom([a^5]) - sage: loads(dumps(f)) == f + sage: K.<a> = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: f = K.hom([a^5]) # needs sage.rings.finite_rings + sage: loads(dumps(f)) == f # needs sage.rings.finite_rings True """ slots = RingMap._extra_slots(self) @@ -538,16 +535,15 @@ cdef class RingExtensionBackendIsomorphism(RingExtensionHomomorphism): TESTS:: + sage: # needs sage.rings.finite_rings sage: K = GF(11^9).over(GF(11^3)) - sage: f = K.coerce_map_from(GF(11^9)) - sage: f + sage: f = K.coerce_map_from(GF(11^9)); f Coercion morphism: From: Finite Field in z9 of size 11^9 - To: Field in z9 with defining polynomial x^3 + (9*z3^2 + 5*z3 + 1)*x^2 + (4*z3 + 3)*x + 10*z3 over its base - + To: Field in z9 with defining polynomial + x^3 + (9*z3^2 + 5*z3 + 1)*x^2 + (4*z3 + 3)*x + 10*z3 over its base sage: type(f) <class 'sage.rings.ring_extension_morphism.RingExtensionBackendIsomorphism'> - sage: TestSuite(f).run() """ def __init__(self, parent): @@ -556,9 +552,10 @@ cdef class RingExtensionBackendIsomorphism(RingExtensionHomomorphism): TESTS:: - sage: A.<a> = QQ.extension(x^2 - 5) - sage: K = A.over() - sage: K.coerce_map_from(A) + sage: x = polygen(ZZ, 'x') + sage: A.<a> = QQ.extension(x^2 - 5) # needs sage.rings.number_field + sage: K = A.over() # needs sage.rings.number_field + sage: K.coerce_map_from(A) # needs sage.rings.number_field Coercion morphism: From: Number Field in a with defining polynomial x^2 - 5 To: Field in a with defining polynomial x^2 - 5 over its base @@ -573,14 +570,13 @@ cdef class RingExtensionBackendIsomorphism(RingExtensionHomomorphism): EXAMPLES:: - sage: K.<a> = GF(5^2).over() # over GF(5) - sage: f = K.coerce_map_from(GF(5^2)) - sage: f + sage: K.<a> = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: f = K.coerce_map_from(GF(5^2)); f # needs sage.rings.finite_rings Coercion morphism: From: Finite Field in z2 of size 5^2 To: Field in a with defining polynomial x^2 + 4*x + 2 over its base - sage: f._repr_type() + sage: f._repr_type() # needs sage.rings.finite_rings 'Coercion' """ return "Coercion" @@ -591,14 +587,13 @@ cdef class RingExtensionBackendIsomorphism(RingExtensionHomomorphism): EXAMPLES:: - sage: K.<a> = GF(5^2).over() # over GF(5) - sage: f = K.coerce_map_from(GF(5^2)) - sage: f + sage: K.<a> = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: f = K.coerce_map_from(GF(5^2)); f # needs sage.rings.finite_rings Coercion morphism: From: Finite Field in z2 of size 5^2 To: Field in a with defining polynomial x^2 + 4*x + 2 over its base - sage: f._repr_defn() + sage: f._repr_defn() # needs sage.rings.finite_rings '' """ return "" @@ -613,9 +608,9 @@ cdef class RingExtensionBackendIsomorphism(RingExtensionHomomorphism): EXAMPLES:: - sage: K.<a> = GF(5^2).over() # over GF(5) - sage: f = K.coerce_map_from(GF(5^2)) - sage: f(GF(5^2).gen()) + sage: K.<a> = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: f = K.coerce_map_from(GF(5^2)) # needs sage.rings.finite_rings + sage: f(GF(5^2).gen()) # needs sage.rings.finite_rings a """ codomain = self.codomain() @@ -629,16 +624,15 @@ cdef class RingExtensionBackendReverseIsomorphism(RingExtensionHomomorphism): TESTS:: + sage: # needs sage.rings.finite_rings sage: K = GF(11^9).over(GF(11^3)) - sage: f = GF(11^9).convert_map_from(K) - sage: f + sage: f = GF(11^9).convert_map_from(K); f Canonical morphism: - From: Field in z9 with defining polynomial x^3 + (9*z3^2 + 5*z3 + 1)*x^2 + (4*z3 + 3)*x + 10*z3 over its base + From: Field in z9 with defining polynomial + x^3 + (9*z3^2 + 5*z3 + 1)*x^2 + (4*z3 + 3)*x + 10*z3 over its base To: Finite Field in z9 of size 11^9 - sage: type(f) <class 'sage.rings.ring_extension_morphism.RingExtensionBackendReverseIsomorphism'> - sage: TestSuite(f).run() """ @@ -648,9 +642,10 @@ cdef class RingExtensionBackendReverseIsomorphism(RingExtensionHomomorphism): TESTS:: - sage: A.<a> = QQ.extension(x^2 - 5) - sage: K = A.over() - sage: A.convert_map_from(K) + sage: x = polygen(ZZ, 'x') + sage: A.<a> = QQ.extension(x^2 - 5) # needs sage.rings.number_field + sage: K = A.over() # needs sage.rings.number_field + sage: A.convert_map_from(K) # needs sage.rings.number_field Canonical morphism: From: Field in a with defining polynomial x^2 - 5 over its base To: Number Field in a with defining polynomial x^2 - 5 @@ -665,14 +660,13 @@ cdef class RingExtensionBackendReverseIsomorphism(RingExtensionHomomorphism): EXAMPLES:: - sage: K.<a> = GF(5^2).over() # over GF(5) - sage: f = GF(5^2).convert_map_from(K) - sage: f + sage: K.<a> = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: f = GF(5^2).convert_map_from(K); f # needs sage.rings.finite_rings Canonical morphism: From: Field in a with defining polynomial x^2 + 4*x + 2 over its base To: Finite Field in z2 of size 5^2 - sage: f._repr_type() + sage: f._repr_type() # needs sage.rings.finite_rings 'Canonical' """ return "Canonical" @@ -683,14 +677,13 @@ cdef class RingExtensionBackendReverseIsomorphism(RingExtensionHomomorphism): EXAMPLES:: - sage: K.<a> = GF(5^2).over() # over GF(5) - sage: f = GF(5^2).convert_map_from(K) - sage: f + sage: K.<a> = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: f = GF(5^2).convert_map_from(K); f # needs sage.rings.finite_rings Canonical morphism: From: Field in a with defining polynomial x^2 + 4*x + 2 over its base To: Finite Field in z2 of size 5^2 - sage: f._repr_defn() + sage: f._repr_defn() # needs sage.rings.finite_rings '' """ return "" @@ -705,9 +698,9 @@ cdef class RingExtensionBackendReverseIsomorphism(RingExtensionHomomorphism): EXAMPLES:: - sage: K.<a> = GF(5^2).over() # over GF(5) - sage: f = GF(5^2).convert_map_from(K) - sage: f(a) + sage: K.<a> = GF(5^2).over() # over GF(5) # needs sage.rings.finite_rings + sage: f = GF(5^2).convert_map_from(K) # needs sage.rings.finite_rings + sage: f(a) # needs sage.rings.finite_rings z2 """ return (<RingExtensionElement>x)._backend @@ -720,9 +713,9 @@ cdef class MapFreeModuleToRelativeRing(Map): TESTS:: - sage: K = GF(5^2).over() - sage: V, i, j = K.free_module() - sage: type(i) + sage: K = GF(5^2).over() # needs sage.rings.finite_rings + sage: V, i, j = K.free_module() # needs sage.rings.finite_rings + sage: type(i) # needs sage.rings.finite_rings <class 'sage.rings.ring_extension_morphism.MapFreeModuleToRelativeRing'> """ @@ -738,9 +731,9 @@ cdef class MapFreeModuleToRelativeRing(Map): TESTS:: - sage: K = GF(11^6).over(GF(11^3)) - sage: V, i, j = K.free_module() - sage: i + sage: K = GF(11^6).over(GF(11^3)) # needs sage.rings.finite_rings + sage: V, i, j = K.free_module() # needs sage.rings.finite_rings + sage: i # needs sage.rings.finite_rings Generic map: From: Vector space of dimension 2 over Finite Field in z3 of size 11^3 To: Field in z6 with defining polynomial x^2 + (10*z3^2 + z3 + 6)*x + z3 over its base @@ -758,9 +751,9 @@ cdef class MapFreeModuleToRelativeRing(Map): EXAMPLES:: - sage: K = GF(11^6).over(GF(11^3)) - sage: V, i, j = K.free_module() - sage: i.is_injective() + sage: K = GF(11^6).over(GF(11^3)) # needs sage.rings.finite_rings + sage: V, i, j = K.free_module() # needs sage.rings.finite_rings + sage: i.is_injective() # needs sage.rings.finite_rings True """ return True @@ -771,9 +764,9 @@ cdef class MapFreeModuleToRelativeRing(Map): EXAMPLES:: - sage: K = GF(11^6).over(GF(11^3)) - sage: V, i, j = K.free_module() - sage: i.is_surjective() + sage: K = GF(11^6).over(GF(11^3)) # needs sage.rings.finite_rings + sage: V, i, j = K.free_module() # needs sage.rings.finite_rings + sage: i.is_surjective() # needs sage.rings.finite_rings True """ return True @@ -788,9 +781,9 @@ cdef class MapFreeModuleToRelativeRing(Map): EXAMPLES:: - sage: K.<a> = GF(11^6).over(GF(11^3)) - sage: V, i, j = K.free_module() - sage: i((0,1)) + sage: K.<a> = GF(11^6).over(GF(11^3)) # needs sage.rings.finite_rings + sage: V, i, j = K.free_module() # needs sage.rings.finite_rings + sage: i((0,1)) # needs sage.rings.finite_rings a """ cdef Element elt @@ -807,9 +800,9 @@ cdef class MapRelativeRingToFreeModule(Map): TESTS:: - sage: K = GF(5^2).over() - sage: V, i, j = K.free_module() - sage: type(j) + sage: K = GF(5^2).over() # needs sage.rings.finite_rings + sage: V, i, j = K.free_module() # needs sage.rings.finite_rings + sage: type(j) # needs sage.rings.finite_rings <class 'sage.rings.ring_extension_morphism.MapRelativeRingToFreeModule'> """ @@ -825,9 +818,9 @@ cdef class MapRelativeRingToFreeModule(Map): TESTS:: - sage: K = GF(11^6).over(GF(11^3)) - sage: V, i, j = K.free_module() - sage: j + sage: K = GF(11^6).over(GF(11^3)) # needs sage.rings.finite_rings + sage: V, i, j = K.free_module() # needs sage.rings.finite_rings + sage: j # needs sage.rings.finite_rings Generic map: From: Field in z6 with defining polynomial x^2 + (10*z3^2 + z3 + 6)*x + z3 over its base To: Vector space of dimension 2 over Finite Field in z3 of size 11^3 @@ -867,9 +860,9 @@ cdef class MapRelativeRingToFreeModule(Map): EXAMPLES:: - sage: K = GF(11^6).over(GF(11^3)) - sage: V, i, j = K.free_module() - sage: j.is_injective() + sage: K = GF(11^6).over(GF(11^3)) # needs sage.rings.finite_rings + sage: V, i, j = K.free_module() # needs sage.rings.finite_rings + sage: j.is_injective() # needs sage.rings.finite_rings True """ return True @@ -880,9 +873,9 @@ cdef class MapRelativeRingToFreeModule(Map): EXAMPLES:: - sage: K = GF(11^6).over(GF(11^3)) - sage: V, i, j = K.free_module() - sage: j.is_surjective() + sage: K = GF(11^6).over(GF(11^3)) # needs sage.rings.finite_rings + sage: V, i, j = K.free_module() # needs sage.rings.finite_rings + sage: j.is_surjective() # needs sage.rings.finite_rings True """ return True @@ -897,9 +890,9 @@ cdef class MapRelativeRingToFreeModule(Map): EXAMPLES:: - sage: K.<a> = GF(11^6).over(GF(11^3)) - sage: V, i, j = K.free_module() - sage: j(a) + sage: K.<a> = GF(11^6).over(GF(11^3)) # needs sage.rings.finite_rings + sage: V, i, j = K.free_module() # needs sage.rings.finite_rings + sage: j(a) # needs sage.rings.finite_rings (0, 1) """ coeffs = self.backend_coefficients(x) @@ -916,9 +909,9 @@ cdef class MapRelativeRingToFreeModule(Map): TESTS:: - sage: K.<a> = GF(11^9).over(GF(11^3)) - sage: V, i, j = K.free_module() - sage: j(a + 2*a^2) # indirect doctest + sage: K.<a> = GF(11^9).over(GF(11^3)) # needs sage.rings.finite_rings + sage: V, i, j = K.free_module() # needs sage.rings.finite_rings + sage: j(a + 2*a^2) # indirect doctest # needs sage.rings.finite_rings (0, 1, 2) """ cdef list coeffs = [ ] diff --git a/src/sage/rings/semirings/__init__.py b/src/sage/rings/semirings/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/rings/semirings/non_negative_integer_semiring.py b/src/sage/rings/semirings/non_negative_integer_semiring.py index ea3bce495d9..1c01fc47eb5 100644 --- a/src/sage/rings/semirings/non_negative_integer_semiring.py +++ b/src/sage/rings/semirings/non_negative_integer_semiring.py @@ -37,15 +37,15 @@ class NonNegativeIntegerSemiring(NonNegativeIntegers): Here is a piece of the Cayley graph for the multiplicative structure:: - sage: G = NN.cayley_graph(elements=range(9), generators=[0,1,2,3,5,7]) - sage: G + sage: G = NN.cayley_graph(elements=range(9), generators=[0,1,2,3,5,7]) # needs sage.graphs + sage: G # needs sage.graphs Looped multi-digraph on 9 vertices - sage: G.plot() + sage: G.plot() # needs sage.graphs sage.plot Graphics object consisting of 48 graphics primitives This is the Hasse diagram of the divisibility order on ``NN``. - sage: Poset(NN.cayley_graph(elements=[1..12], generators=[2,3,5,7,11])).show() + sage: Poset(NN.cayley_graph(elements=[1..12], generators=[2,3,5,7,11])).show() # needs sage.combinat sage.graphs sage.plot Note: as for :class:`NonNegativeIntegers <sage.sets.non_negative_integers.NonNegativeIntegers>`, ``NN`` is @@ -101,4 +101,5 @@ def _latex_(self): """ return '\\Bold{N}' + NN = NonNegativeIntegerSemiring() diff --git a/src/sage/rings/semirings/tropical_semiring.pyx b/src/sage/rings/semirings/tropical_semiring.pyx index 73c3b8820ec..2922298e286 100644 --- a/src/sage/rings/semirings/tropical_semiring.pyx +++ b/src/sage/rings/semirings/tropical_semiring.pyx @@ -5,7 +5,7 @@ AUTHORS: - Travis Scrimshaw (2013-04-28) - Initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Travis Scrimshaw <tscrim@ucdavis.edu> # # Distributed under the terms of the GNU General Public License (GPL) @@ -17,8 +17,8 @@ AUTHORS: # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.cachefunc import cached_method from sage.structure.parent import Parent @@ -27,10 +27,8 @@ from sage.structure.element cimport Element, ModuleElement from sage.structure.richcmp cimport rich_to_bool from sage.categories.semirings import Semirings from sage.categories.map cimport Map -from sage.sets.family import Family from sage.rings.integer_ring import ZZ -import operator cdef class TropicalSemiringElement(Element): r""" @@ -557,17 +555,19 @@ class TropicalSemiring(Parent, UniqueRepresentation): EXAMPLES:: + sage: TQ = TropicalSemiring(QQ) + sage: TQ.has_coerce_map_from(TQ) + True + sage: TQ.has_coerce_map_from(TropicalSemiring(ZZ)) + True + + sage: # needs sage.rings.real_mpfr sage: TR = TropicalSemiring(RR) sage: T60 = TropicalSemiring(RealField(60)) sage: TR.has_coerce_map_from(T60) True - sage: TQ = TropicalSemiring(QQ) - sage: TQ.has_coerce_map_from(TropicalSemiring(ZZ)) - True sage: TR.has_coerce_map_from(TR) True - sage: TQ.has_coerce_map_from(TQ) - True sage: TR.has_coerce_map_from(TQ) True sage: TR.has_coerce_map_from(float) diff --git a/src/sage/rings/sum_of_squares.pyx b/src/sage/rings/sum_of_squares.pyx index a1d3edcedef..b8f719d4dac 100644 --- a/src/sage/rings/sum_of_squares.pyx +++ b/src/sage/rings/sum_of_squares.pyx @@ -140,7 +140,7 @@ def two_squares_pyx(uint32_t n): .. SEEALSO:: - :func:`~sage.arith.all.two_squares` is much more suited for large inputs + :func:`~sage.arith.misc.two_squares` is much more suited for large inputs EXAMPLES:: @@ -166,7 +166,7 @@ def two_squares_pyx(uint32_t n): TESTS:: sage: s = lambda t: sum(i^2 for i in t) - sage: for ij in Subsets(Subsets(45000,15).random_element(),2): + sage: for ij in Subsets(Subsets(45000, 15).random_element(), 2): # needs sage.combinat ....: if s(two_squares_pyx(s(ij))) != s(ij): ....: print("hey") @@ -254,7 +254,7 @@ def three_squares_pyx(uint32_t n): TESTS:: sage: s = lambda t: sum(i^2 for i in t) - sage: for ijk in Subsets(Subsets(35000,15).random_element(),3): + sage: for ijk in Subsets(Subsets(35000,15).random_element(),3): # needs sage.combinat ....: if s(three_squares_pyx(s(ijk))) != s(ijk): ....: print("hey") """ @@ -278,7 +278,7 @@ def four_squares_pyx(uint32_t n): .. SEEALSO:: - :func:`~sage.arith.all.four_squares` is much more suited for large input + :func:`~sage.arith.misc.four_squares` is much more suited for large input EXAMPLES:: @@ -307,7 +307,7 @@ def four_squares_pyx(uint32_t n): sage: all(s(four_squares_pyx(n)) == n for n in range(5000,10000)) True """ - cdef uint_fast32_t fac, j, nn + cdef uint_fast32_t fac, j cdef uint_fast32_t i[3] if n == 0: @@ -315,7 +315,7 @@ def four_squares_pyx(uint32_t n): # division by power of 4 fac = 0 - while n%4 == 0: + while n % 4 == 0: n >>= 2 fac += 1 diff --git a/src/sage/rings/tate_algebra.py b/src/sage/rings/tate_algebra.py index 877f2a2703e..993f1a95aa1 100644 --- a/src/sage/rings/tate_algebra.py +++ b/src/sage/rings/tate_algebra.py @@ -91,8 +91,7 @@ sage: f(a^2, 2*a) 1 + 2^2 + a*2^4 + O(2^5) - sage: var('u') - u + sage: u = polygen(ZZ, 'u') sage: L.<pi> = K.change(print_mode="series").extension(u^3 - 2) sage: g(pi, 2*pi) pi^7 + pi^8 + pi^19 + pi^20 + O(pi^21) @@ -330,6 +329,7 @@ def create_object(self, version, key): (base, prec, log_radii, names, order) = key return TateAlgebra_generic(base, prec, log_radii, names, order) + TateAlgebra = TateAlgebraFactory("TateAlgebra") @@ -683,7 +683,6 @@ def some_elements(self): return elts - # Tate algebras ############### @@ -842,6 +841,7 @@ def _pushout_(self, R): sage: from sage.categories.pushout import pushout sage: R = Zp(2) sage: R1.<a> = Zq(4) + sage: x = polygen(ZZ, 'x') sage: R2.<pi> = R.extension(x^2 - 2) sage: A.<u,v> = TateAlgebra(R, log_radii=[1,2]) @@ -1197,6 +1197,7 @@ def absolute_e(self): sage: A.absolute_e() 1 + sage: x = polygen(ZZ, 'x') sage: S.<a> = R.extension(x^2 - 2) sage: A.<u,v> = TateAlgebra(S) sage: A.absolute_e() diff --git a/src/sage/rings/tate_algebra_element.pyx b/src/sage/rings/tate_algebra_element.pyx index 0ef1f8d86fe..b9be89b99b6 100644 --- a/src/sage/rings/tate_algebra_element.pyx +++ b/src/sage/rings/tate_algebra_element.pyx @@ -20,14 +20,13 @@ AUTHOR: # https://www.gnu.org/licenses/ # *************************************************************************** -from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE +from cpython.object cimport Py_EQ, Py_NE from sage.structure.richcmp cimport rich_to_bool_sgn from sage.structure.element import coerce_binop from sage.structure.element cimport Element from sage.structure.element cimport MonoidElement from sage.structure.element cimport CommutativeAlgebraElement -from sage.structure.sequence import Sequence from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ @@ -258,9 +257,7 @@ cdef class TateAlgebraTerm(MonoidElement): ...00000000010*x*y sage: T(2*x*y)._latex_() '...00000000010xy' - """ - from sage.misc.latex import latex parent = self._parent s = "" if self._coeff._is_atomic() or (-self._coeff)._is_atomic(): @@ -1255,9 +1252,7 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): ...0000000001*x^3 + ...0000000001*x + ...00000000010*x^2 sage: f._latex_() '...0000000001x^{3} + ...0000000001x + ...00000000010x^{2}' - """ - from sage.misc.latex import latex base = self._parent.base_ring() nvars = self._parent.ngens() vars = self._parent.variable_names() @@ -1884,6 +1879,7 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): sage: f(a, 2) a^2 + 2^2 + O(2^20) + sage: x = polygen(ZZ, 'x') sage: T.<pi> = S.extension(x^2 - 2) sage: f(pi, 2) pi^2 + pi^4 + O(pi^42) @@ -2667,7 +2663,7 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): while True: # we compute the sum for the possible values for u using Horner's method inner_sum = R.zero() - for u in xrange(upper_u,0,-1): + for u in range(upper_u,0,-1): # We want u to be a p-adic unit if u % p==0: new_term = R.zero() @@ -2750,7 +2746,7 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): sage: f(x0, y0).exp() == expf(x0, y0) True - sage: expf.log() == f + sage: expf.log() == f # long time True """ @@ -3268,6 +3264,7 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): sage: f % [2,u] # indirect doctest O(2^10 * <u, v>) + sage: x = polygen(ZZ, 'x') sage: S.<pi> = R.extension(x^2 - 2) sage: f % (pi*u) # indirect doctest (pi^2 + O(pi^20))*v^2 + O(pi^20 * <u, v>) diff --git a/src/sage/rings/tate_algebra_ideal.pyx b/src/sage/rings/tate_algebra_ideal.pyx index 17031adcec2..e230a411397 100644 --- a/src/sage/rings/tate_algebra_ideal.pyx +++ b/src/sage/rings/tate_algebra_ideal.pyx @@ -20,15 +20,13 @@ AUTHORS: # 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. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # *************************************************************************** from sage.rings.ideal import Ideal_generic -from sage.misc.cachefunc import cached_method from sage.structure.richcmp import op_EQ, op_NE, op_LT, op_GT, op_LE, op_GE -from sage.structure.element cimport Element from sage.rings.polynomial.polydict cimport PolyDict from sage.rings.tate_algebra_element cimport TateAlgebraTerm @@ -625,7 +623,8 @@ cdef TateAlgebraElement regular_reduce(sgb, TateAlgebraTerm s, TateAlgebraElemen TESTS:: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' ....: from sage.rings.tate_algebra_ideal cimport regular_reduce ....: def python_regular_reduce(gb, s, v, stopval): ....: return regular_reduce(gb, s, v, stopval) @@ -639,11 +638,12 @@ cdef TateAlgebraElement regular_reduce(sgb, TateAlgebraTerm s, TateAlgebraElemen sage: p1 = (tx, x^3 + 9*x*y) sage: p2 = (ty, x*y + 3*x^2*y) - sage: python_regular_reduce([p1,p2], tx*ty, v, 8) # indirect doctest + sage: python_regular_reduce([p1,p2], tx*ty, v, 8) # indirect doctest # needs sage.misc.cython (2 + O(3^8))*x^2*y + (1 + O(3^8))*x + (1 + O(3^8))*y + O(3^8 * <x, y>) - sage: python_regular_reduce([p1,p2], tx, v, 8) # indirect doctest - (2 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + O(3^8))*x^3 + (2 + O(3^8))*x^2*y + (1 + O(3^8))*x + (1 + O(3^8))*y + O(3^8 * <x, y>) + sage: python_regular_reduce([p1,p2], tx, v, 8) # indirect doctest # needs sage.misc.cython + (2 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + O(3^8))*x^3 + + (2 + O(3^8))*x^2*y + (1 + O(3^8))*x + (1 + O(3^8))*y + O(3^8 * <x, y>) """ # We assume that the elements of the sgb are such that lt(g) = p^v lm(g) to # avoid performing divisions @@ -714,11 +714,12 @@ cdef TateAlgebraElement reduce(gb, TateAlgebraElement v, stopval): sage: v = (x + y + 2*x^2*y - x^3*y^2).add_bigoh(8) sage: g1 = x*y + 3*x^2*y sage: g2 = x^3 + 9*y - sage: python_reduce([g1,g2], v, 8) # indirect doctest + sage: python_reduce([g1,g2], v, 8) # indirect doctest # needs sage.misc.cython (1 + O(3^8))*x + (1 + O(3^8))*y + O(3^8 * <x, y>) - sage: python_reduce([g1,g2], v, 5) # indirect doctest - (1 + O(3^8))*x + (1 + O(3^8))*y + (3^5 + O(3^8))*x^8*y^2 + (3^5 + 2*3^6 + 2*3^7 + O(3^8))*x^7*y + O(3^8 * <x, y>) + sage: python_reduce([g1,g2], v, 5) # indirect doctest # needs sage.misc.cython + (1 + O(3^8))*x + (1 + O(3^8))*y + (3^5 + O(3^8))*x^8*y^2 + + (3^5 + 2*3^6 + 2*3^7 + O(3^8))*x^7*y + O(3^8 * <x, y>) """ cdef dict coeffs = { } cdef TateAlgebraElement f @@ -857,7 +858,7 @@ def groebner_basis_pote(I, prec, verbose=0): sage: I.groebner_basis(algorithm="PoTe", prec=100) # indirect doctest [...0000000001*x^3 + ...2222222222*y + ...000000000*x^2*y^2 + O(3^99 * <x, y>), ...0000000001*x^2*y + ...01210121020 + O(3^100 * <x, y>), - ...0000000001*y^2 + ...01210121020*x + ...000000000*x^2*y^3 + ...0000000000*x^3*y + O(3^99 * <x, y>)] + ...0000000001*y^2 + ...01210121020*x + ...0000000000*x^3*y + O(3^99 * <x, y>)] """ cdef TateAlgebraElement g, v cdef TateAlgebraTerm s, sv, S, ti, tj @@ -1103,7 +1104,7 @@ def groebner_basis_vapote(I, prec, verbose=0, interrupt_red_with_val=False, inte sage: I.groebner_basis(algorithm="VaPoTe", prec=100) # indirect doctest [...0000000001*x^3 + ...2222222222*y + ...000000000*x^2*y^2 + O(3^99 * <x, y>), ...0000000001*x^2*y + ...01210121020 + O(3^100 * <x, y>), - ...0000000001*y^2 + ...01210121020*x + ...000000000*x^2*y^3 + ...0000000000*x^3*y + O(3^99 * <x, y>)] + ...0000000001*y^2 + ...01210121020*x + ...0000000000*x^3*y + O(3^99 * <x, y>)] """ cdef TateAlgebraElement g, v cdef TateAlgebraTerm s, S, sv, ti, tj diff --git a/src/sage/rings/tests.py b/src/sage/rings/tests.py index c6f1a9ecbbf..13a205195d5 100644 --- a/src/sage/rings/tests.py +++ b/src/sage/rings/tests.py @@ -23,9 +23,9 @@ def prime_finite_field(): EXAMPLES:: sage: import sage.rings.tests - sage: K = sage.rings.tests.prime_finite_field(); K + sage: K = sage.rings.tests.prime_finite_field(); K # needs sage.rings.finite_rings Finite Field of size ... - sage: K.cardinality().is_prime() + sage: K.cardinality().is_prime() # needs sage.rings.finite_rings True """ from sage.rings.integer_ring import ZZ @@ -42,11 +42,11 @@ def finite_field(): EXAMPLES:: sage: import sage.rings.tests - sage: K = sage.rings.tests.finite_field(); K + sage: K = sage.rings.tests.finite_field(); K # needs sage.rings.finite_rings Finite Field...of size ... - sage: K.cardinality().is_prime_power() + sage: K.cardinality().is_prime_power() # needs sage.rings.finite_rings True - sage: while K.cardinality().is_prime(): + sage: while K.cardinality().is_prime(): # needs sage.rings.finite_rings ....: K = sage.rings.tests.finite_field() """ from sage.rings.integer_ring import ZZ @@ -64,6 +64,7 @@ def small_finite_field(): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: import sage.rings.tests sage: K = sage.rings.tests.small_finite_field(); K Finite Field...of size ... @@ -107,7 +108,7 @@ def padic_field(): EXAMPLES:: sage: import sage.rings.tests - sage: sage.rings.tests.padic_field() + sage: sage.rings.tests.padic_field() # needs sage.rings.padics ...-adic Field with capped relative precision ... """ from sage.rings.integer_ring import ZZ @@ -124,7 +125,7 @@ def quadratic_number_field(): EXAMPLES:: sage: import sage.rings.tests - sage: K = sage.rings.tests.quadratic_number_field(); K + sage: K = sage.rings.tests.quadratic_number_field(); K # needs sage.rings.number_field Number Field in a with defining polynomial x^2 ... with a = ... """ from sage.rings.integer_ring import ZZ @@ -142,9 +143,9 @@ def absolute_number_field(maxdeg=10): EXAMPLES:: sage: import sage.rings.tests - sage: K = sage.rings.tests.absolute_number_field(); K + sage: K = sage.rings.tests.absolute_number_field(); K # needs sage.rings.number_field Number Field in a with defining polynomial ... - sage: K.degree() <= 10 + sage: K.degree() <= 10 # needs sage.rings.number_field True """ from sage.rings.integer_ring import ZZ @@ -166,6 +167,7 @@ def relative_number_field(n=2, maxdeg=2): EXAMPLES:: + sage: # needs sage.rings.number_field sage: import sage.rings.tests sage: K = sage.rings.tests.relative_number_field(3); K Number Field in aaa with defining polynomial x^2 ... over its base field @@ -186,7 +188,7 @@ def relative_number_field(n=2, maxdeg=2): sage: set_random_seed(3030) sage: from sage.rings.tests import relative_number_field - sage: _ = relative_number_field(3) + sage: _ = relative_number_field(3) # needs sage.rings.number_field """ from sage.rings.integer_ring import ZZ K = absolute_number_field(maxdeg) @@ -333,7 +335,7 @@ def test_random_elements(level=MAX_LEVEL, trials=1): EXAMPLES:: sage: import sage.rings.tests - sage: sage.rings.tests.test_random_elements(trials=2, seed=0) + sage: sage.rings.tests.test_random_elements(trials=2, seed=0) # needs sage.rings.number_field survived 0 tests Rational Field -1/2 @@ -343,6 +345,7 @@ def test_random_elements(level=MAX_LEVEL, trials=1): -12 ---- + sage: # needs sage.rings.finite_rings sage.rings.number_field sage.rings.padics sage: sage.rings.tests.test_random_elements(trials=10) survived 0 tests... sage: sage.rings.tests.test_random_elements(trials=1000) # long time (5 seconds) @@ -363,8 +366,9 @@ def test_random_elements(level=MAX_LEVEL, trials=1): @random_testing def test_random_arith(level=MAX_LEVEL, trials=1): """ - Create random elements of random rings and does some arithmetic - with them, until a crash occurs, in which case an exception is + Create random elements of random rings and do some arithmetic with them. + + Repeats until a crash occurs, in which case an exception is raised. Defaults to running a single trial, but more can be specified. To run tests in an infinite loop, you could use:: @@ -372,15 +376,16 @@ def test_random_arith(level=MAX_LEVEL, trials=1): INPUT: - - level -- (default: MAX_LEVEL); controls the types of rings to use - - trials -- A positive integer (default 1); the number of trials + - ``level`` -- (default: ``MAX_LEVEL``); controls the types of rings to use + - ``trials`` -- A positive integer (default: 1); the number of trials to run. - - seed -- the random seed to use; if not specified, uses a truly + - ``seed`` -- the random seed to use; if not specified, uses a truly random seed. - - print_seed -- If True (default False), prints the random seed chosen. + - ``print_seed`` -- If ``True`` (default: ``False``), prints the random seed chosen. EXAMPLES:: + sage: # needs sage.rings.finite_rings sage.rings.number_field sage.rings.padics sage: import sage.rings.tests sage: sage.rings.tests.test_random_arith(trials=2, seed=0) survived 0 tests @@ -391,7 +396,6 @@ def test_random_arith(level=MAX_LEVEL, trials=1): Number Field in a with defining polynomial x^2 - 15083 with a = 122.81286577553673? a -2*a - 1 2*a - 30164 - sage: sage.rings.tests.test_random_arith(trials=10) survived 0 tests... sage: sage.rings.tests.test_random_arith(trials=1000) # long time (5 seconds?) @@ -421,8 +425,8 @@ def test_karatsuba_multiplication(base_ring, maxdeg1, maxdeg2, First check that random tests are reproducible:: - sage: import sage.rings.tests - sage: sage.rings.tests.test_karatsuba_multiplication(ZZ, 6, 5, verbose=True, seed=42) + sage: from sage.rings.tests import test_karatsuba_multiplication + sage: test_karatsuba_multiplication(ZZ, 6, 5, verbose=True, seed=42) test_karatsuba_multiplication: ring=Univariate Polynomial Ring in x over Integer Ring, threshold=2 (2*x^6 - x^5 - x^4 - 3*x^3 + 4*x^2 + 4*x + 1)*(4*x^4 + x^3 - 2*x^2 - 20*x + 3) (16*x^2)*(-41*x + 1) @@ -437,22 +441,31 @@ def test_karatsuba_multiplication(base_ring, maxdeg1, maxdeg2, Test Karatsuba multiplication of polynomials of small degree over some common rings:: - sage: for C in [QQ, ZZ[I], ZZ[I, sqrt(2)], GF(49, 'a'), MatrixSpace(GF(17), 3)]: - ....: sage.rings.tests.test_karatsuba_multiplication(C, 10, 10) + sage: rings = [QQ] + sage: rings += [ZZ[I], ZZ[I, sqrt(2)]] # needs sage.rings.number_field sage.symbolic + sage: rings += [GF(49, 'a')] # needs sage.rings.finite_rings + sage: rings += [MatrixSpace(GF(17), 3)] # needs sage.modules + sage: for C in rings: + ....: test_karatsuba_multiplication(C, 10, 10) Zero-tests over ``QQbar`` are currently very slow, so we test only very small examples:: - sage.rings.tests.test_karatsuba_multiplication(QQbar, 3, 3, numtests=2) + sage: test_karatsuba_multiplication(QQbar, 3, 3, numtests=2) # long time, needs sage.rings.number_field Larger degrees (over ``ZZ``, using FLINT):: - sage: sage.rings.tests.test_karatsuba_multiplication(ZZ, 1000, 1000, ref_mul=lambda f,g: f*g, base_ring_random_elt_args=[1000]) + sage: test_karatsuba_multiplication(ZZ, 1000, 1000, + ....: ref_mul=lambda f,g: f*g, + ....: base_ring_random_elt_args=[1000]) Some more aggressive tests:: - sage: for C in [QQ, ZZ[I], ZZ[I, sqrt(2)], GF(49, 'a'), MatrixSpace(GF(17), 3)]: - ....: sage.rings.tests.test_karatsuba_multiplication(C, 10, 10) # long time - sage: sage.rings.tests.test_karatsuba_multiplication(ZZ, 10000, 10000, ref_mul=lambda f,g: f*g, base_ring_random_elt_args=[100000]) + sage: testrings = [ZZ[I, sqrt(2)], ZZ[I, sqrt(2), sqrt(3)]] # long time + sage: for C in testrings: # long time + ....: test_karatsuba_multiplication(C, 100, 100) + sage: test_karatsuba_multiplication(ZZ, 10000, 10000, # long time + ....: ref_mul=lambda f,g: f*g, + ....: base_ring_random_elt_args=[100000]) """ from sage.misc.prandom import randint diff --git a/src/sage/rings/universal_cyclotomic_field.py b/src/sage/rings/universal_cyclotomic_field.py index d238bce3450..8afd960006c 100644 --- a/src/sage/rings/universal_cyclotomic_field.py +++ b/src/sage/rings/universal_cyclotomic_field.py @@ -163,11 +163,14 @@ - Sebastian Oehms (2019): add :meth:`_factor_univariate_polynomial` (see :trac:`28631`) """ +import sage.rings.abc + from sage.misc.cachefunc import cached_method from sage.structure.richcmp import rich_to_bool from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element import FieldElement, parent + from sage.structure.coerce import py_scalar_to_element from sage.categories.morphism import Morphism from sage.rings.ring import Field @@ -176,6 +179,7 @@ from sage.rings.rational import Rational from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field_element_base import NumberFieldElement_base from sage.rings.rational_field import QQ from sage.rings.infinity import Infinity from sage.rings.qqbar import AA, QQbar @@ -332,8 +336,6 @@ def __bool__(self): """ return bool(self._obj) - - def __reduce__(self): r""" TESTS:: @@ -521,14 +523,14 @@ def _symbolic_(self, R): r""" TESTS:: - sage: SR(E(7)) + sage: SR(E(7)) # needs sage.symbolic e^(2/7*I*pi) - sage: SR(E(5) + 2*E(5,2) + 3*E(5,3)) + sage: SR(E(5) + 2*E(5,2) + 3*E(5,3)) # needs sage.symbolic -sqrt(5) + 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4*I*sqrt(-2*sqrt(5) + 10) - 3/2 Test that the bug reported in :trac:`19912` has been fixed:: - sage: SR(1+E(4)) + sage: SR(1+E(4)) # needs sage.symbolic I + 1 """ from sage.symbolic.constants import pi, I @@ -561,7 +563,7 @@ def to_cyclotomic_field(self, R=None): sage: CF(E(5)) # indirect doctest Traceback (most recent call last): ... - TypeError: Cannot coerce zeta5 into Cyclotomic Field of order 7 and + TypeError: cannot coerce zeta5 into Cyclotomic Field of order 7 and degree 6 sage: CF = CyclotomicField(10) @@ -580,7 +582,8 @@ def to_cyclotomic_field(self, R=None): Using a non-standard embedding:: - sage: CF = CyclotomicField(5,embedding=CC(exp(4*pi*i/5))) + sage: # needs sage.symbolic + sage: CF = CyclotomicField(5, embedding=CC(exp(4*pi*i/5))) sage: x = E(5) sage: CC(x) 0.309016994374947 + 0.951056516295154*I @@ -721,7 +724,7 @@ def _eval_real_(self, R): sage: RR(E(7) + E(7,6)) 1.24697960371747 - sage: 2*cos(2*pi/7).n() + sage: 2*cos(2*pi/7).n() # needs sage.symbolic 1.24697960371747 Check that units are evaluated correctly (:trac:`23775`):: @@ -1281,7 +1284,7 @@ def minpoly(self, var='x'): return QQ[var](QQ['x_1'](str(gap_p))) -class UniversalCyclotomicField(UniqueRepresentation, Field): +class UniversalCyclotomicField(UniqueRepresentation, sage.rings.abc.UniversalCyclotomicField): r""" The universal cyclotomic field. @@ -1483,7 +1486,7 @@ def _element_constructor_(self, elt): Some conversions from symbolic functions are possible:: sage: UCF = UniversalCyclotomicField() - sage: [UCF(sin(pi/k, hold=True)) for k in range(1,10)] + sage: [UCF(sin(pi/k, hold=True)) for k in range(1,10)] # needs sage.symbolic [0, 1, -1/2*E(12)^7 + 1/2*E(12)^11, @@ -1493,7 +1496,7 @@ def _element_constructor_(self, elt): -1/2*E(28)^19 + 1/2*E(28)^23, 1/2*E(16)^3 - 1/2*E(16)^5, -1/2*E(36)^25 + 1/2*E(36)^29] - sage: [UCF(cos(pi/k, hold=True)) for k in range(1,10)] + sage: [UCF(cos(pi/k, hold=True)) for k in range(1,10)] # needs sage.symbolic [-1, 0, 1/2, @@ -1504,8 +1507,9 @@ def _element_constructor_(self, elt): 1/2*E(16) - 1/2*E(16)^7, -1/2*E(9)^4 - 1/2*E(9)^5] - sage: UCF(1 + sqrt(-3/5)) - 4/5*E(15) + 4/5*E(15)^2 + 4/5*E(15)^4 + 6/5*E(15)^7 + 4/5*E(15)^8 + 6/5*E(15)^11 + 6/5*E(15)^13 + 6/5*E(15)^14 + sage: UCF(1 + sqrt(-3/5)) # needs sage.symbolic + 4/5*E(15) + 4/5*E(15)^2 + 4/5*E(15)^4 + 6/5*E(15)^7 + 4/5*E(15)^8 + + 6/5*E(15)^11 + 6/5*E(15)^13 + 6/5*E(15)^14 .. TODO:: @@ -1537,8 +1541,7 @@ def _element_constructor_(self, elt): import sage.rings.abc P = parent(elt) if isinstance(P, sage.rings.abc.NumberField_cyclotomic): - from sage.rings.number_field.number_field_element import NumberFieldElement - if isinstance(elt, NumberFieldElement): + if isinstance(elt, NumberFieldElement_base): from sage.rings.number_field.number_field import CyclotomicField n = P.gen().multiplicative_order() elt = CyclotomicField(n)(elt) @@ -1617,7 +1620,8 @@ def _factor_univariate_polynomial(self, f): sage: (x^3 - 8).factor() (x - 2) * (x - 2*E(3)) * (x - 2*E(3)^2) - In most situations, the factorization will fail with a ``NotImplementedError``:: + In most situations, the factorization will fail with a + :class:`NotImplementedError`:: sage: (x^3 - 2).factor() Traceback (most recent call last): diff --git a/src/sage/rings/valuation/__init__.py b/src/sage/rings/valuation/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/rings/valuation/augmented_valuation.py b/src/sage/rings/valuation/augmented_valuation.py index e4834e38f0b..37fda19d7dc 100644 --- a/src/sage/rings/valuation/augmented_valuation.py +++ b/src/sage/rings/valuation/augmented_valuation.py @@ -1109,7 +1109,7 @@ def lift(self, F): # We only have to do that if psi is non-trivial if self.psi().degree() > 1: from sage.rings.polynomial.polynomial_quotient_ring_element import PolynomialQuotientRingElement - from sage.rings.function_field.element import FunctionFieldElement_polymod + from sage.rings.function_field.element_polymod import FunctionFieldElement_polymod from sage.rings.number_field.number_field_element import NumberFieldElement_relative from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing if isinstance(F, PolynomialQuotientRingElement): diff --git a/src/sage/rings/valuation/valuation.py b/src/sage/rings/valuation/valuation.py index 40425b3dbe8..ec39b0d98ea 100644 --- a/src/sage/rings/valuation/valuation.py +++ b/src/sage/rings/valuation/valuation.py @@ -12,6 +12,7 @@ Discrete valuations can be created on a variety of rings:: + sage: # needs sage.rings.padics sage: ZZ.valuation(2) 2-adic valuation sage: GaussianIntegers().valuation(3) @@ -34,15 +35,15 @@ :: sage: R.<x> = QQ[] - sage: v = QQ.valuation(2) - sage: w = GaussValuation(R, v) - sage: w.augmentation(x, 3) + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: w = GaussValuation(R, v) # needs sage.rings.padics + sage: w.augmentation(x, 3) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x) = 3 ] We can also define discrete pseudo-valuations, i.e., discrete valuations that send more than just zero to infinity:: - sage: w.augmentation(x, infinity) + sage: w.augmentation(x, infinity) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x) = +Infinity ] """ # **************************************************************************** @@ -71,12 +72,12 @@ class DiscretePseudoValuation(Morphism): EXAMPLES:: - sage: v = ZZ.valuation(2); v # indirect doctest + sage: v = ZZ.valuation(2); v # indirect doctest 2-adic valuation TESTS:: - sage: TestSuite(v).run() # long time + sage: TestSuite(v).run() # long time """ def __init__(self, parent): @@ -84,7 +85,7 @@ def __init__(self, parent): TESTS:: sage: from sage.rings.valuation.valuation import DiscretePseudoValuation - sage: isinstance(ZZ.valuation(2), DiscretePseudoValuation) + sage: isinstance(ZZ.valuation(2), DiscretePseudoValuation) # needs sage.rings.padics True """ @@ -96,6 +97,7 @@ def is_equivalent(self, f, g): EXAMPLES:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(2) sage: v.is_equivalent(2, 1) False @@ -124,8 +126,8 @@ def __hash__(self): EXAMPLES:: - sage: v = QQ.valuation(2) - sage: hash(v) == hash(v) # indirect doctest + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: hash(v) == hash(v) # indirect doctest # needs sage.rings.padics True """ @@ -145,8 +147,8 @@ def _hash_(self): EXAMPLES:: - sage: v = QQ.valuation(2) - sage: hash(v) == hash(v) # indirect doctest + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: hash(v) == hash(v) # indirect doctest # needs sage.rings.padics True """ @@ -167,6 +169,7 @@ def _richcmp_(self, other, op): EXAMPLES:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(2) sage: v == v True @@ -227,8 +230,8 @@ def _le_(self, other): EXAMPLES:: sage: v = valuations.TrivialValuation(QQ) - sage: w = QQ.valuation(2) - sage: v <= w + sage: w = QQ.valuation(2) # needs sage.rings.padics + sage: v <= w # needs sage.rings.padics True """ return other >= self @@ -244,8 +247,8 @@ def _ge_(self, other): EXAMPLES:: sage: v = valuations.TrivialValuation(QQ) - sage: w = QQ.valuation(2) - sage: v >= w + sage: w = QQ.valuation(2) # needs sage.rings.padics + sage: v >= w # needs sage.rings.padics False """ if self == other: @@ -269,7 +272,7 @@ def _test_valuation_inheritance(self, **options): EXAMPLES:: - sage: QQ.valuation(2)._test_valuation_inheritance() + sage: QQ.valuation(2)._test_valuation_inheritance() # needs sage.rings.padics """ tester = self._tester(**options) tester.assertNotEqual(isinstance(self, InfiniteDiscretePseudoValuation), @@ -283,18 +286,18 @@ class InfiniteDiscretePseudoValuation(DiscretePseudoValuation): EXAMPLES:: - sage: v = QQ.valuation(2) + sage: v = QQ.valuation(2) # needs sage.rings.padics sage: R.<x> = QQ[] - sage: v = GaussValuation(R, v) - sage: w = v.augmentation(x, infinity); w # indirect doctest + sage: v = GaussValuation(R, v) # needs sage.rings.padics + sage: w = v.augmentation(x, infinity); w # indirect doctest # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x) = +Infinity ] TESTS:: sage: from sage.rings.valuation.valuation import InfiniteDiscretePseudoValuation - sage: isinstance(w, InfiniteDiscretePseudoValuation) + sage: isinstance(w, InfiniteDiscretePseudoValuation) # needs sage.rings.padics True - sage: TestSuite(w).run() # long time + sage: TestSuite(w).run() # long time # needs sage.rings.padics """ def is_discrete_valuation(self): @@ -303,6 +306,7 @@ def is_discrete_valuation(self): EXAMPLES:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(2) sage: R.<x> = QQ[] sage: v = GaussValuation(R, v) @@ -341,7 +345,8 @@ def is_negative_pseudo_valuation(self): EXAMPLES:: sage: R.<x> = QQ[] - sage: v = GaussValuation(R, valuations.TrivialValuation(QQ)).augmentation(x, infinity) + sage: u = GaussValuation(R, valuations.TrivialValuation(QQ)) + sage: v = u.augmentation(x, infinity) sage: v.is_negative_pseudo_valuation() False sage: K.<x> = FunctionField(QQ) @@ -359,18 +364,18 @@ class DiscreteValuation(DiscretePseudoValuation): EXAMPLES:: - sage: v = QQ.valuation(2) + sage: v = QQ.valuation(2) # needs sage.rings.padics sage: R.<x> = QQ[] - sage: v = GaussValuation(R, v) - sage: w = v.augmentation(x, 1337); w # indirect doctest + sage: v = GaussValuation(R, v) # needs sage.rings.padics + sage: w = v.augmentation(x, 1337); w # indirect doctest # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x) = 1337 ] TESTS:: sage: from sage.rings.valuation.valuation import DiscreteValuation - sage: isinstance(w, DiscreteValuation) + sage: isinstance(w, DiscreteValuation) # needs sage.rings.padics True - sage: TestSuite(w).run() # long time + sage: TestSuite(w).run() # long time # needs sage.rings.padics """ def is_discrete_valuation(self): @@ -431,12 +436,14 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru EXAMPLES:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(2) sage: R.<x> = QQ[] sage: v.mac_lane_approximants(x^2 + 1) [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ]] sage: v.mac_lane_approximants(x^2 + 1, required_precision=infinity) - [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2, v(x^2 + 1) = +Infinity ]] + [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2, + v(x^2 + 1) = +Infinity ]] sage: v.mac_lane_approximants(x^2 + x + 1) [[ Gauss valuation induced by 2-adic valuation, v(x^2 + x + 1) = +Infinity ]] @@ -444,13 +451,13 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru factor `x + 1` and an approximate factor `x + 1` (which is an approximation to `x - 1`):: - sage: v.mac_lane_approximants(x^2 - 1) + sage: v.mac_lane_approximants(x^2 - 1) # needs sage.rings.padics [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = +Infinity ], [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1 ]] However, it needs to be squarefree:: - sage: v.mac_lane_approximants(x^2) + sage: v.mac_lane_approximants(x^2) # needs sage.rings.padics Traceback (most recent call last): ... ValueError: G must be squarefree @@ -459,19 +466,20 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru Some difficult cases provided by Mark van Hoeij:: + sage: # needs sage.rings.finite_rings sage: k = GF(2) sage: K.<x> = FunctionField(k) sage: R.<y> = K[] sage: F = y^21 + x*y^20 + (x^3 + x + 1)*y^18 + (x^3 + 1)*y^17 + (x^4 + x)*y^16 + (x^7 + x^6 + x^3 + x + 1)*y^15 + x^7*y^14 + (x^8 + x^7 + x^6 + x^4 + x^3 + 1)*y^13 + (x^9 + x^8 + x^4 + 1)*y^12 + (x^11 + x^9 + x^8 + x^5 + x^4 + x^3 + x^2)*y^11 + (x^12 + x^9 + x^8 + x^7 + x^5 + x^3 + x + 1)*y^10 + (x^14 + x^13 + x^10 + x^9 + x^8 + x^7 + x^6 + x^3 + x^2 + 1)*y^9 + (x^13 + x^9 + x^8 + x^6 + x^4 + x^3 + x)*y^8 + (x^16 + x^15 + x^13 + x^12 + x^11 + x^7 + x^3 + x)*y^7 + (x^17 + x^16 + x^13 + x^9 + x^8 + x)*y^6 + (x^17 + x^16 + x^12 + x^7 + x^5 + x^2 + x + 1)*y^5 + (x^19 + x^16 + x^15 + x^12 + x^6 + x^5 + x^3 + 1)*y^4 + (x^18 + x^15 + x^12 + x^10 + x^9 + x^7 + x^4 + x)*y^3 + (x^22 + x^21 + x^20 + x^18 + x^13 + x^12 + x^9 + x^8 + x^7 + x^5 + x^4 + x^3)*y^2 + (x^23 + x^22 + x^20 + x^17 + x^15 + x^14 + x^12 + x^9)*y + x^25 + x^23 + x^19 + x^17 + x^15 + x^13 + x^11 + x^5 sage: x = K._ring.gen() sage: v0 = K.valuation(GaussValuation(K._ring, valuations.TrivialValuation(k)).augmentation(x,1)) - sage: v0.mac_lane_approximants(F, assume_squarefree=True) # assumes squarefree for speed + sage: v0.mac_lane_approximants(F, assume_squarefree=True) # assumes squarefree for speed [[ Gauss valuation induced by (x)-adic valuation, v(y + x + 1) = 3/2 ], [ Gauss valuation induced by (x)-adic valuation, v(y) = 1 ], [ Gauss valuation induced by (x)-adic valuation, v(y) = 4/3 ], [ Gauss valuation induced by (x)-adic valuation, v(y^15 + y^13 + y^12 + y^10 + y^9 + y^8 + y^4 + y^3 + y^2 + y + 1) = 1 ]] sage: v0 = K.valuation(GaussValuation(K._ring, valuations.TrivialValuation(k)).augmentation(x+1,1)) - sage: v0.mac_lane_approximants(F, assume_squarefree=True) # assumes squarefree for speed + sage: v0.mac_lane_approximants(F, assume_squarefree=True) # assumes squarefree for speed [[ Gauss valuation induced by (x + 1)-adic valuation, v(y + x^2 + 1) = 7/2 ], [ Gauss valuation induced by (x + 1)-adic valuation, v(y) = 3/4 ], [ Gauss valuation induced by (x + 1)-adic valuation, v(y) = 7/2 ], @@ -487,6 +495,7 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru Cases with trivial residue field extensions:: + sage: # needs sage.rings.padics sage: K.<x> = FunctionField(QQ) sage: S.<y> = K[] sage: F = y^2 - x^2 - x^3 - 3 @@ -499,46 +508,49 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru Over a complete base field:: - sage: k=Qp(2,10) - sage: v = k.valuation() + sage: k = Qp(2,10) # needs sage.rings.padics + sage: v = k.valuation() # needs sage.rings.padics - sage: R.<x>=k[] + sage: # needs sage.rings.padics + sage: R.<x> = k[] sage: G = x sage: v.mac_lane_approximants(G) [Gauss valuation induced by 2-adic valuation] - sage: v.mac_lane_approximants(G, required_precision = infinity) + sage: v.mac_lane_approximants(G, required_precision=infinity) [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = +Infinity ]] - sage: G = x^2 + 1 - sage: v.mac_lane_approximants(G) + sage: G = x^2 + 1 # needs sage.rings.padics + sage: v.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x + 1 + O(2^10)) = 1/2 ]] - sage: v.mac_lane_approximants(G, required_precision = infinity) - [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x + 1 + O(2^10)) = 1/2, v((1 + O(2^10))*x^2 + 1 + O(2^10)) = +Infinity ]] + sage: v.mac_lane_approximants(G, required_precision=infinity) # needs sage.rings.padics + [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x + 1 + O(2^10)) = 1/2, + v((1 + O(2^10))*x^2 + 1 + O(2^10)) = +Infinity ]] - sage: G = x^4 + 2*x^3 + 2*x^2 - 2*x + 2 - sage: v.mac_lane_approximants(G) + sage: G = x^4 + 2*x^3 + 2*x^2 - 2*x + 2 # needs sage.rings.padics + sage: v.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = 1/4 ]] - sage: v.mac_lane_approximants(G, required_precision=infinity) - [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = 1/4, v((1 + O(2^10))*x^4 + (2 + O(2^11))*x^3 + (2 + O(2^11))*x^2 + (2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + 2^10 + O(2^11))*x + 2 + O(2^11)) = +Infinity ]] + sage: v.mac_lane_approximants(G, required_precision=infinity) # needs sage.rings.padics + [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = 1/4, + v((1 + O(2^10))*x^4 + (2 + O(2^11))*x^3 + (2 + O(2^11))*x^2 + (2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + 2^10 + O(2^11))*x + 2 + O(2^11)) = +Infinity ]] The factorization of primes in the Gaussian integers can be read off the Mac Lane approximants:: - sage: v0 = QQ.valuation(2) + sage: v0 = QQ.valuation(2) # needs sage.rings.padics sage: R.<x> = QQ[] sage: G = x^2 + 1 - sage: v0.mac_lane_approximants(G) + sage: v0.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ]] - sage: v0 = QQ.valuation(3) - sage: v0.mac_lane_approximants(G) + sage: v0 = QQ.valuation(3) # needs sage.rings.padics + sage: v0.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 3-adic valuation, v(x^2 + 1) = +Infinity ]] - sage: v0 = QQ.valuation(5) - sage: v0.mac_lane_approximants(G) + sage: v0 = QQ.valuation(5) # needs sage.rings.padics + sage: v0.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 5-adic valuation, v(x + 2) = 1 ], [ Gauss valuation induced by 5-adic valuation, v(x + 3) = 1 ]] - sage: v0.mac_lane_approximants(G, required_precision = 10) + sage: v0.mac_lane_approximants(G, required_precision=10) # needs sage.rings.padics [[ Gauss valuation induced by 5-adic valuation, v(x + 3116/237) = 10 ], [ Gauss valuation induced by 5-adic valuation, v(x - 3116/237) = 10 ]] @@ -546,9 +558,10 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru `\QQ[x]/(x^2+1)`, 5 factors `-(x - 2)(x + 2)`, this behaviour can be read off the Mac Lane approximants:: - sage: k=Qp(5,4) + sage: # needs sage.rings.padics + sage: k = Qp(5,4) sage: v = k.valuation() - sage: R.<x>=k[] + sage: R.<x> = k[] sage: G = x^2 + 1 sage: v1,v2 = v.mac_lane_approximants(G); v1,v2 ([ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 2 + O(5^4)) = 1 ], @@ -559,22 +572,23 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru Note how the latter give a better approximation to the factors of `x^2 + 1`:: - sage: v1.phi() * v2.phi() - G + sage: v1.phi() * v2.phi() - G # needs sage.rings.padics O(5^4)*x^2 + (5 + O(5^4))*x + 5 + O(5^4) - sage: w1.phi() * w2.phi() - G + sage: w1.phi() * w2.phi() - G # needs sage.rings.padics O(5^4)*x^2 + (5^2 + O(5^4))*x + 5^3 + O(5^4) In this example, the process stops with a factorization of `x^2 + 1`:: - sage: v.mac_lane_approximants(G, required_precision=infinity) + sage: v.mac_lane_approximants(G, required_precision=infinity) # needs sage.rings.padics [[ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 2 + 5 + 2*5^2 + 5^3 + O(5^4)) = +Infinity ], [ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4)) = +Infinity ]] This obviously cannot happen over the rationals where we only get an approximate factorization:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(5) - sage: R.<x>=QQ[] + sage: R.<x> = QQ[] sage: G = x^2 + 1 sage: v.mac_lane_approximants(G) [[ Gauss valuation induced by 5-adic valuation, v(x + 2) = 1 ], @@ -586,9 +600,10 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru Initial versions ran into problems with the trivial residue field extensions in this case:: - sage: K = Qp(3, 20, print_mode='digits') - sage: R.<T> = K[] + sage: K = Qp(3, 20, print_mode='digits') # needs sage.rings.padics + sage: R.<T> = K[] # needs sage.rings.padics + sage: # needs sage.rings.padics sage: alpha = T^3/4 sage: G = 3^3*T^3*(alpha^4 - alpha)^2 - (4*alpha^3 - 1)^3 sage: G = G/G.leading_coefficient() @@ -598,13 +613,14 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru A similar example:: sage: R.<x> = QQ[] - sage: v = QQ.valuation(3) - sage: G = (x^3 + 3)^3 - 81 - sage: v.mac_lane_approximants(G) + sage: v = QQ.valuation(3) # needs sage.rings.padics + sage: G = (x^3 + 3)^3 - 81 # needs sage.rings.padics + sage: v.mac_lane_approximants(G) # needs sage.rings.padics [[ Gauss valuation induced by 3-adic valuation, v(x) = 1/3, v(x^3 + 3*x + 3) = 13/9 ]] Another problematic case:: + sage: # needs sage.rings.number_field sage.rings.padics sage: R.<x> = QQ[] sage: Delta = x^12 + 20*x^11 + 154*x^10 + 664*x^9 + 1873*x^8 + 3808*x^7 + 5980*x^6 + 7560*x^5 + 7799*x^4 + 6508*x^3 + 4290*x^2 + 2224*x + 887 sage: K.<theta> = NumberField(x^6 + 108) @@ -615,7 +631,7 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru 1 sage: vK(theta) 1/3 - sage: G=Delta.change_ring(K) + sage: G = Delta.change_ring(K) sage: vK.mac_lane_approximants(G) [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/4, v(x^4 + 1/2*theta^4 + 3*theta + 1) = 3/2 ], [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/4, v(x^4 + 1/2*theta^4 + theta + 1) = 3/2 ], @@ -624,8 +640,8 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru An easy case that produced the wrong error at some point:: sage: R.<x> = QQ[] - sage: v = QQ.valuation(2) - sage: v.mac_lane_approximants(x^2 - 1/2) + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: v.mac_lane_approximants(x^2 - 1/2) # needs sage.rings.padics Traceback (most recent call last): ... ValueError: G must be integral @@ -634,24 +650,29 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru :: + sage: # needs sage.rings.padics sage: R = ZpFM(3, 7, print_mode='terse') sage: S.<x> = R[] sage: v = R.valuation() sage: f = x^4 + 234 - sage: len(v.mac_lane_approximants(f, assume_squarefree=True)) # is_squarefree() is not properly implemented yet + sage: len(v.mac_lane_approximants(f, # is_squarefree() is not properly implemented yet + ....: assume_squarefree=True)) 2 :: + sage: # needs sage.rings.padics sage: R = ZpFM(2, 50, print_mode='terse') sage: S.<x> = R[] sage: f = (x^32 + 16)*(x^32 + 16 + 2^16*x^2) + 2^34 sage: v = R.valuation() - sage: len(v.mac_lane_approximants(f, assume_squarefree=True)) # is_squarefree() is not properly implemented yet + sage: len(v.mac_lane_approximants(f, # is_squarefree() is not properly implemented yet + ....: assume_squarefree=True)) 2 A case that triggered an assertion at some point:: + sage: # needs sage.rings.padics sage: v = QQ.valuation(3) sage: R.<x> = QQ[] sage: f = x^36 + 60552000*x^33 + 268157412*x^30 + 173881701*x^27 + 266324841*x^24 + 83125683*x^21 + 111803814*x^18 + 31925826*x^15 + 205726716*x^12 +17990262*x^9 + 351459648*x^6 + 127014399*x^3 + 359254116 @@ -784,10 +805,10 @@ def _pow(self, x, e, error): EXAMPLES:: - sage: v = QQ.valuation(2) - sage: v._pow(2, 2, error=4) + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: v._pow(2, 2, error=4) # needs sage.rings.padics 4 - sage: v._pow(2, 1000, error=4) + sage: v._pow(2, 1000, error=4) # needs sage.rings.padics 0 """ @@ -817,58 +838,66 @@ def mac_lane_approximant(self, G, valuation, approximants=None): EXAMPLES:: - sage: v = QQ.valuation(2) - sage: R.<x> = QQ[] - sage: G = x^2 + 1 + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: R.<x> = QQ[] # needs sage.rings.padics + sage: G = x^2 + 1 # needs sage.rings.padics We can select an approximant by approximating it:: - sage: w = GaussValuation(R, v).augmentation(x + 1, 1/2) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x + 1, 1/2) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ] As long as this is the only matching approximant, the approximation can be very coarse:: - sage: w = GaussValuation(R, v) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ] Or it can be very specific:: - sage: w = GaussValuation(R, v).augmentation(x + 1, 1/2).augmentation(G, infinity) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x + 1, 1/2).augmentation(G, infinity) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ] But it must be an approximation of an approximant:: - sage: w = GaussValuation(R, v).augmentation(x, 1/2) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x, 1/2) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics Traceback (most recent call last): ... - ValueError: The valuation [ Gauss valuation induced by 2-adic valuation, v(x) = 1/2 ] is not an approximant for a valuation which extends 2-adic valuation with respect to x^2 + 1 since the valuation of x^2 + 1 does not increase in every step + ValueError: The valuation + [ Gauss valuation induced by 2-adic valuation, v(x) = 1/2 ] is + not an approximant for a valuation which extends 2-adic valuation + with respect to x^2 + 1 since the valuation of x^2 + 1 + does not increase in every step The ``valuation`` must single out one approximant:: - sage: G = x^2 - 1 - sage: w = GaussValuation(R, v) - sage: v.mac_lane_approximant(G, w) + sage: G = x^2 - 1 # needs sage.rings.padics + sage: w = GaussValuation(R, v) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics Traceback (most recent call last): ... - ValueError: The valuation Gauss valuation induced by 2-adic valuation does not approximate a unique extension of 2-adic valuation with respect to x^2 - 1 + ValueError: The valuation Gauss valuation induced by 2-adic valuation + does not approximate a unique extension of 2-adic valuation + with respect to x^2 - 1 - sage: w = GaussValuation(R, v).augmentation(x + 1, 1) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x + 1, 1) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics Traceback (most recent call last): ... - ValueError: The valuation [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1 ] does not approximate a unique extension of 2-adic valuation with respect to x^2 - 1 + ValueError: The valuation + [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1 ] does not + approximate a unique extension of 2-adic valuation with respect to x^2 - 1 - sage: w = GaussValuation(R, v).augmentation(x + 1, 2) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x + 1, 2) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x + 1) = +Infinity ] - sage: w = GaussValuation(R, v).augmentation(x + 3, 2) - sage: v.mac_lane_approximant(G, w) + sage: w = GaussValuation(R, v).augmentation(x + 3, 2) # needs sage.rings.padics + sage: v.mac_lane_approximant(G, w) # needs sage.rings.padics [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1 ] """ @@ -882,7 +911,7 @@ def mac_lane_approximant(self, G, valuation, approximants=None): v = valuation while not v.is_gauss_valuation(): if v(G) <= v._base_valuation(G): - raise ValueError("The valuation %r is not an approximant for a valuation which extends %r with respect to %r since the valuation of %r does not increase in every step"%(valuation, self, G, G)) + raise ValueError("The valuation %r is not an approximant for a valuation which extends %r with respect to %r since the valuation of %r does not increase in every step" % (valuation, self, G, G)) v = v._base_valuation if approximants is None: @@ -892,15 +921,15 @@ def mac_lane_approximant(self, G, valuation, approximants=None): greater_approximants = [w for w in approximants if w >= valuation] if len(greater_approximants) > 1: - raise ValueError("The valuation %r does not approximate a unique extension of %r with respect to %r"%(valuation, self, G)) + raise ValueError("The valuation %r does not approximate a unique extension of %r with respect to %r" % (valuation, self, G)) if len(greater_approximants) == 1: return greater_approximants[0] smaller_approximants = [w for w in approximants if w <= valuation] if len(smaller_approximants) > 1: - raise ValueError("The valuation %r is not approximated by a unique extension of %r with respect to %r"%(valuation, self, G)) + raise ValueError("The valuation %r is not approximated by a unique extension of %r with respect to %r" % (valuation, self, G)) if len(smaller_approximants) == 0: - raise ValueError("The valuation %r is not related to an extension of %r with respect to %r"%(valuation, self, G)) + raise ValueError("The valuation %r is not related to an extension of %r with respect to %r" % (valuation, self, G)) return smaller_approximants[0] def montes_factorization(self, G, assume_squarefree=False, required_precision=None): @@ -928,24 +957,26 @@ def montes_factorization(self, G, assume_squarefree=False, required_precision=No EXAMPLES:: - sage: k=Qp(5,4) + sage: # needs sage.rings.padics + sage: k = Qp(5,4) sage: v = k.valuation() - sage: R.<x>=k[] + sage: R.<x> = k[] sage: G = x^2 + 1 sage: v.montes_factorization(G) - ((1 + O(5^4))*x + 2 + 5 + 2*5^2 + 5^3 + O(5^4)) * ((1 + O(5^4))*x + 3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4)) + ((1 + O(5^4))*x + 2 + 5 + 2*5^2 + 5^3 + O(5^4)) + * ((1 + O(5^4))*x + 3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4)) The computation might not terminate over incomplete fields (in particular because the factors can not be represented there):: sage: R.<x> = QQ[] - sage: v = QQ.valuation(2) - sage: v.montes_factorization(x^6 - 1) + sage: v = QQ.valuation(2) # needs sage.rings.padics + sage: v.montes_factorization(x^6 - 1) # needs sage.rings.padics (x - 1) * (x + 1) * (x^2 - x + 1) * (x^2 + x + 1) - sage: v.montes_factorization(x^7 - 1) # not tested, does not terminate + sage: v.montes_factorization(x^7 - 1) # not tested # needs sage.rings.padics - sage: v.montes_factorization(x^7 - 1, required_precision=5) + sage: v.montes_factorization(x^7 - 1, required_precision=5) # needs sage.rings.padics (x - 1) * (x^3 - 5*x^2 - 6*x - 1) * (x^3 + 6*x^2 + 5*x - 1) TESTS: @@ -955,6 +986,7 @@ def montes_factorization(self, G, assume_squarefree=False, required_precision=No In this example, ``f`` factors as three factors of degree 50 over an unramified extension:: + sage: # needs sage.rings.padics sage: R.<u> = ZqFM(125) sage: S.<x> = R[] sage: f = (x^6+2)^25 + 5 @@ -964,6 +996,7 @@ def montes_factorization(self, G, assume_squarefree=False, required_precision=No In this case, ``f`` factors into degrees 1, 2, and 5 over a totally ramified extension:: + sage: # needs sage.rings.padics sage: R = Zp(5) sage: S.<w> = R[] sage: R.<w> = R.extension(w^3 + 5) @@ -1033,8 +1066,8 @@ class MacLaneApproximantNode(): TESTS:: - sage: v = ZZ.valuation(3) - sage: v.extension(GaussianIntegers()) # indirect doctest + sage: v = ZZ.valuation(3) # needs sage.rings.padics + sage: v.extension(GaussianIntegers()) # indirect doctest # needs sage.rings.padics 3-adic valuation """ @@ -1043,8 +1076,8 @@ def __init__(self, valuation, parent, ef, principal_part_bound, coefficients, va TESTS:: sage: from sage.rings.valuation.valuation import MacLaneApproximantNode - sage: node = MacLaneApproximantNode(QQ.valuation(2), None, 1, None, None, None) - sage: TestSuite(node).run() + sage: node = MacLaneApproximantNode(QQ.valuation(2), None, 1, None, None, None) # needs sage.rings.padics + sage: TestSuite(node).run() # needs sage.rings.padics """ self.valuation = valuation @@ -1061,6 +1094,7 @@ def __eq__(self, other): EXAMPLES:: + sage: # needs sage.rings.padics sage: from sage.rings.valuation.valuation import MacLaneApproximantNode sage: n = MacLaneApproximantNode(QQ.valuation(2), None, 1, None, None, None) sage: m = MacLaneApproximantNode(QQ.valuation(3), None, 1, None, None, None) @@ -1070,7 +1104,7 @@ def __eq__(self, other): True """ - if type(self) != type(other): + if type(self) is not type(other): return False return (self.valuation, self.parent, self.ef, self.principal_part_bound, self.coefficients, self.valuations, self.forced_leaf) == (other.valuation, other.parent, other.ef, other.principal_part_bound, other.coefficients, other.valuations, other.forced_leaf) @@ -1080,6 +1114,7 @@ def __ne__(self, other): EXAMPLES:: + sage: # needs sage.rings.padics sage: from sage.rings.valuation.valuation import MacLaneApproximantNode sage: n = MacLaneApproximantNode(QQ.valuation(2), None, 1, None, None, None) sage: m = MacLaneApproximantNode(QQ.valuation(3), None, 1, None, None, None) diff --git a/src/sage/rings/valuation/valuation_space.py b/src/sage/rings/valuation/valuation_space.py index ffb13d82917..be0e9192c7c 100644 --- a/src/sage/rings/valuation/valuation_space.py +++ b/src/sage/rings/valuation/valuation_space.py @@ -486,7 +486,7 @@ def element_with_valuation(self, s): return self.domain().one() exp = s / self.value_group().gen() if exp not in ZZ: - raise NotImplementedError("s must be a multiple of %r but %r is not"%(self.value_group().gen(), s)) + raise NotImplementedError("s must be a multiple of %r but %r is not" % (self.value_group().gen(), s)) ret = self.domain()(self.uniformizer() ** ZZ(exp)) return self.simplify(ret, error=s) @@ -540,7 +540,7 @@ def residue_field(self): return ret from sage.rings.polynomial.polynomial_ring import is_PolynomialRing if is_PolynomialRing(ret): - from sage.rings.function_field.all import FunctionField + from sage.rings.function_field.constructor import FunctionField return FunctionField(ret.base_ring().fraction_field(), names=(ret.variable_name(),)) return ret.fraction_field() @@ -594,7 +594,7 @@ def extension(self, ring): extensions = self.extensions(ring) assert(extensions) if len(extensions) > 1: - raise ValueError("there is no unique extension of %r from %r to %r"%(self, self.domain(), ring)) + raise ValueError("there is no unique extension of %r from %r to %r" % (self, self.domain(), ring)) return extensions[0] def extensions(self, ring): @@ -610,7 +610,7 @@ def extensions(self, ring): """ if ring is self.domain(): return [self] - raise NotImplementedError("extending %r from %r to %r not implemented"%(self, self.domain(), ring)) + raise NotImplementedError("extending %r from %r to %r not implemented" % (self, self.domain(), ring)) def restriction(self, ring): r""" @@ -626,7 +626,7 @@ def restriction(self, ring): """ if ring is self.domain(): return self - raise NotImplementedError("restricting %r from %r to %r not implemented"%(self, self.domain(), ring)) + raise NotImplementedError("restricting %r from %r to %r not implemented" % (self, self.domain(), ring)) def change_domain(self, ring): r""" @@ -649,7 +649,7 @@ def change_domain(self, ring): return self.extension(ring) if ring.is_subring(self.domain()): return self.restriction(ring) - raise NotImplementedError("changing %r from %r to %r not implemented"%(self, self.domain(), ring)) + raise NotImplementedError("changing %r from %r to %r not implemented" % (self, self.domain(), ring)) def scale(self, scalar): r""" @@ -732,11 +732,11 @@ def separating_element(self, others): for other in others + [self]: if other.parent() is not self.parent(): - raise ValueError("all valuations must be valuations on %r but %r is a valuation on %r"%(self.domain(), other, other.domain())) + raise ValueError("all valuations must be valuations on %r but %r is a valuation on %r" % (self.domain(), other, other.domain())) if not other.is_discrete_valuation(): raise ValueError("all valuations must be discrete valuations but %r is not" % (other,)) if other.is_trivial(): - raise ValueError("all valuations must be non-trivial but %r is not"%(other,)) + raise ValueError("all valuations must be non-trivial but %r is not" % (other,)) if len(others) == 0: return self.uniformizer() @@ -882,7 +882,7 @@ def _weakly_separating_element(self, other): ret = self.uniformizer() if self(ret) > other(ret): return ret - raise NotImplementedError("weakly separating element for %r and %r"%(self, other)) + raise NotImplementedError("weakly separating element for %r and %r" % (self, other)) def shift(self, x, s): r""" diff --git a/src/sage/rings/valuation/valuations_catalog.py b/src/sage/rings/valuation/valuations_catalog.py index 0d0f3362768..64effaf13a6 100644 --- a/src/sage/rings/valuation/valuations_catalog.py +++ b/src/sage/rings/valuation/valuations_catalog.py @@ -1,5 +1,9 @@ -from sage.rings.padics.padic_valuation import pAdicValuation -from sage.rings.function_field.function_field_valuation import FunctionFieldValuation -from .gauss_valuation import GaussValuation -from .trivial_valuation import TrivialDiscretePseudoValuation, TrivialPseudoValuation, TrivialValuation -from .limit_valuation import LimitValuation +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.rings.padics.padic_valuation', 'pAdicValuation') +lazy_import('sage.rings.function_field.valuation', 'FunctionFieldValuation') +lazy_import('sage.rings.valuation.gauss_valuation', 'GaussValuation') +lazy_import('sage.rings.valuation.trivial_valuation', ['TrivialDiscretePseudoValuation', 'TrivialPseudoValuation', 'TrivialValuation']) +lazy_import('sage.rings.valuation.limit_valuation', 'LimitValuation') + +del lazy_import diff --git a/src/sage/rings/valuation/value_group.py b/src/sage/rings/valuation/value_group.py index 159bb675664..57a6c1b2719 100644 --- a/src/sage/rings/valuation/value_group.py +++ b/src/sage/rings/valuation/value_group.py @@ -399,11 +399,11 @@ def _element_with_valuation(self, subgroup, s): """ if s not in self: - raise ValueError("s must be in the value group but %r is not in %r."%(s, self)) + raise ValueError("s must be in the value group but %r is not in %r." % (s, self)) i = self.index(subgroup) x = s/self.gen() - a = x%i + a = x % i if abs(a-i) < a: a -= i b = (x-a)/i @@ -593,7 +593,7 @@ def _repr_(self): """ if self.is_trivial(): return "Trivial Additive Abelian Semigroup" - return "Additive Abelian Semigroup generated by %s"%(', '.join([repr(g) for g in self._generators]),) + return "Additive Abelian Semigroup generated by %s" % (', '.join([repr(g) for g in self._generators]),) def __add__(self, other): r""" @@ -676,8 +676,7 @@ def some_elements(self): yield self(0) if self.is_trivial(): return - for g in self._generators: - yield g + yield from self._generators from sage.rings.integer_ring import ZZ for x in (ZZ**len(self._generators)).some_elements(): yield QQ.coerce(sum([abs(c) * g diff --git a/src/sage/sandpiles/__init__.py b/src/sage/sandpiles/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/sandpiles/examples.py b/src/sage/sandpiles/examples.py index 9ccc08d314f..6507992cc3c 100644 --- a/src/sage/sandpiles/examples.py +++ b/src/sage/sandpiles/examples.py @@ -139,8 +139,7 @@ def Diamond(self): sage: s.invariant_factors() [1, 1, 8] """ - return Sandpile(graphs.DiamondGraph(),0) - + return Sandpile(graphs.DiamondGraph(), 0) def Fan(self, n, deg_three_verts=False): """ @@ -164,15 +163,15 @@ def Fan(self, n, deg_three_verts=False): True """ f = graphs.WheelGraph(n) - if n>2: + if n > 2: f.delete_edge(1,n-1) if deg_three_verts: f.allow_multiple_edges(True) f.add_edges([(0,1),(0,n-1)]) return Sandpile(f,0) - elif n==1: + elif n == 1: return Sandpile(f,0) - elif n==2: + elif n == 2: if deg_three_verts: return Sandpile({0:{1:3}, 1:{0:3}}) else: @@ -247,4 +246,5 @@ def Wheel(self, n): """ return Sandpile(graphs.WheelGraph(n),0) + sandpiles = SandpileExamples() diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index 2d09a660d65..eca2303fc9f 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -326,7 +326,7 @@ from sage.combinat.set_partition import SetPartitions from sage.combinat.vector_partition import IntegerVectorsIterator from sage.functions.log import exp -from sage.functions.other import binomial +from sage.arith.misc import binomial from sage.geometry.polyhedron.constructor import Polyhedron from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph @@ -2256,14 +2256,14 @@ def markov_chain(self,state, distrib=None): while True: i = X.get_random_element() if V[i] != self.sink(): - st[V[i]]+=1 + st[V[i]] += 1 st = st.stabilize() yield st elif isinstance(st,SandpileDivisor): alive = st.is_alive() while True: i = X.get_random_element() - st[V[i]]+=1 + st[V[i]] += 1 if alive: yield st else: @@ -2493,9 +2493,15 @@ def _set_ideal(self): sage: '_ideal' in S.__dict__ True """ + from sage.libs.singular.function_factory import ff + try: + sat = ff.elim__lib.sat_with_exp + except NameError: + sat = ff.elim__lib.sat R = self.ring() - I = self._unsaturated_ideal._singular_() - self._ideal = R.ideal(I.sat(prod(R.gens())._singular_())[1]) + I = self._unsaturated_ideal + I_sat_gens = sat(I, prod(R.gens()))[0] + self._ideal = R.ideal(I_sat_gens) def unsaturated_ideal(self): r""" @@ -2959,7 +2965,7 @@ def __init__(self, S, c): c.reverse() config = {} for v in S.vertices(sort=True): - if v!=S.sink(): + if v != S.sink(): config[v] = c.pop() dict.__init__(self,config) else: @@ -3039,22 +3045,22 @@ def __getattr__(self, name): 3 """ if name not in self.__dict__: - if name=='_deg': + if name == '_deg': self._set_deg() return self.__dict__[name] - if name=='_stabilize': + if name == '_stabilize': self._set_stabilize() return self.__dict__[name] - if name=='_equivalent_recurrent': + if name == '_equivalent_recurrent': self._set_equivalent_recurrent() return self.__dict__[name] - if name=='_is_recurrent': + if name == '_is_recurrent': self._set_is_recurrent() return self.__dict__[name] - if name=='_equivalent_superstable': + if name == '_equivalent_superstable': self._set_equivalent_superstable() return self.__dict__[name] - if name=='_is_superstable': + if name == '_is_superstable': self._set_is_superstable() return self.__dict__[name] else: @@ -3317,7 +3323,7 @@ def __lt__(self, other): sage: d < c False """ - return self<=other and self!=other + return self <= other and self != other def __ge__(self, other): r""" @@ -3376,7 +3382,7 @@ def __gt__(self, other): sage: c > d False """ - return self>=other and self!=other + return self >= other and self != other # recurrent power def __pow__(self, k): @@ -3413,7 +3419,7 @@ def __pow__(self, k): if k == 0: return self._sandpile.identity() else: - if k<0: + if k < 0: k = -k for i in range(k): result -= self @@ -3593,7 +3599,7 @@ def unstable(self): [2, 3] """ return [v for v in self._vertices if - self[v]>=self._sandpile.out_degree(v)] + self[v] >= self._sandpile.out_degree(v)] def fire_unstable(self): r""" @@ -3641,7 +3647,7 @@ def _set_stabilize(self): firing_vector[v] += dm[0] for e in s.outgoing_edge_iterator(v): if e[1] != s.sink(): - c[e[1]] += dm[0]* e[2] + c[e[1]] += dm[0] * e[2] unstable = c.unstable() self._stabilize = [c, firing_vector] @@ -3715,7 +3721,7 @@ def support(self): sage: c.support() [1, 2] """ - return [i for i in self if self[i] !=0] + return [i for i in self if self[i] != 0] def add_random(self, distrib=None): r""" @@ -3791,7 +3797,7 @@ def add_random(self, distrib=None): X = GeneralDiscreteDistribution(distrib) V = self._sandpile.vertices(sort=True) i = X.get_random_element() - if i!=self._sandpile._sink_ind: # not the sink + if i != self._sandpile._sink_ind: # not the sink c[V[i]] += 1 return c @@ -4111,7 +4117,7 @@ def burst_size(self, v): - [Lev2014]_ """ - if v==self.sandpile().sink(): + if v == self.sandpile().sink(): return 1 else: w = deepcopy(self) @@ -4361,43 +4367,43 @@ def __getattr__(self, name): 6 """ if name not in self.__dict__: - if name=='_deg': + if name == '_deg': self._set_deg() return self.__dict__[name] - if name=='_q_reduced': + if name == '_q_reduced': self._set_q_reduced() return self.__dict__[name] - if name=='_linear_system': + if name == '_linear_system': self._set_linear_system() return self.__dict__[name] - if name=='_effective_div': + if name == '_effective_div': self._set_effective_div() return self.__dict__[name] - if name=='_polytope': + if name == '_polytope': self._set_polytope() return self.__dict__[name] - if name=='_polytope_integer_pts': + if name == '_polytope_integer_pts': self._set_polytope_integer_pts() return self.__dict__[name] - if name=='_rank': + if name == '_rank': self._set_rank() return self.__dict__[name] - if name=='_rank_witness': + if name == '_rank_witness': self._set_rank(True) return self.__dict__[name] - if name=='_r_of_D': + if name == '_r_of_D': self._set_r_of_D() return self.__dict__[name] - if name=='_Dcomplex': + if name == '_Dcomplex': self._set_Dcomplex() return self.__dict__[name] - if name=='_life': + if name == '_life': self._set_life() return self.__dict__[name] - if name=='_stabilize': + if name == '_stabilize': self._set_stabilize() return self.__dict__[name] - if name=='_weierstrass_pts': + if name == '_weierstrass_pts': self._set_weierstrass_pts() return self.__dict__[name] else: @@ -4863,7 +4869,7 @@ def unstable(self): [1, 2] """ return [v for v in self._vertices if - self[v]>=self._sandpile.out_degree(v)] + self[v] >= self._sandpile.out_degree(v)] def fire_unstable(self): r""" @@ -5114,9 +5120,9 @@ def _set_linear_system(self): lin_sys_mat = lin_sys + '.mat' lin_sys_rel = lin_sys + '.rel' lin_sys_rhs = lin_sys + '.rhs' - lin_sys_sign= lin_sys + '.sign' - lin_sys_zhom= lin_sys + '.zhom' - lin_sys_zinhom= lin_sys + '.zinhom' + lin_sys_sign = lin_sys + '.sign' + lin_sys_zhom = lin_sys + '.zhom' + lin_sys_zinhom = lin_sys + '.zinhom' lin_sys_log = lin_sys + '.log' with open(lin_sys_mat, 'w') as mat_file: @@ -5417,11 +5423,11 @@ def _set_rank(self, set_witness=False): while k >= 0: rk += 1 try: - d = next(i for i,j in enumerate(c) if i==j and i!=0) + d = next(i for i,j in enumerate(c) if i == j and i != 0) except Exception: d = n - 1 k = k - d - if k >=0: + if k >= 0: c[0] = n - 1 - d b1 = [c[i] + n - d for i in range(1,d)] b2 = [c[i] - d for i in range(d,n-1)] @@ -5571,7 +5577,7 @@ def weierstrass_rank_seq(self, v='sink'): [(1, 0, -1), (1, 0, -1), (1, 0, -1), (1, 0, -1), (1, 0, 0, -1)] """ s = self.sandpile() - if v=='sink': + if v == 'sink': v = s.sink() try: seq = self._weierstrass_rank_seq[v] @@ -5579,11 +5585,11 @@ def weierstrass_rank_seq(self, v='sink'): D = deepcopy(self) verts = s.vertices(sort=True) Ei = s.zero_div() - Ei[verts.index(v)]=1 + Ei[verts.index(v)] = 1 Ei = SandpileDivisor(s,Ei) r = D.rank() seq = [r] - while r !=-1: + while r != -1: D = D - Ei r = D.rank() seq.append(r) @@ -5770,7 +5776,7 @@ def support(self): sage: S.vertices(sort=True) [0, 1, 2, 3] """ - return [i for i in self if self[i] !=0] + return [i for i in self if self[i] != 0] def _set_Dcomplex(self): r""" @@ -5995,7 +6001,7 @@ def _set_stabilize(self): firing_vector = self._sandpile.zero_div() E = deepcopy(self) unstable = E.unstable() - while unstable!=[]: + while unstable != []: E = E.fire_unstable() for v in unstable: firing_vector[v] += 1 @@ -6168,23 +6174,23 @@ def triangle_sandpile(n): for i in range(n): for j in range(n-i): T[(i,j)] = {} - if i<n-j-1: + if i < n-j-1: T[(i,j)][(i+1,j)] = 1 T[(i,j)][(i,j+1)] = 1 - if i>0: + if i > 0: T[(i,j)][(i-1,j+1)] = 1 T[(i,j)][(i-1,j)] = 1 - if j>0: + if j > 0: T[(i,j)][(i,j-1)] = 1 T[(i,j)][(i+1,j-1)] = 1 d = len(T[(i,j)]) - if d<6: + if d < 6: T[(i,j)][(-1, -1)] = 6-d T = Sandpile(T, (-1, -1)) pos = {} for x in T.nonsink_vertices(): coords = list(x) - coords[0]+=QQ(1)/2*coords[1] + coords[0] += QQ(1)/2*coords[1] pos[x] = coords pos[(-1, -1)] = (-1,-1) T.set_pos(pos) @@ -6362,11 +6368,11 @@ def firing_graph(S, eff): g.add_vertices(range(len(eff))) for i in g.vertices(sort=True): for v in eff[i]: - if eff[i][v]>=S.out_degree(v): + if eff[i][v] >= S.out_degree(v): new_div = deepcopy(eff[i]) new_div[v] -= S.out_degree(v) for oe in S.outgoing_edges(v): - new_div[oe[1]]+=oe[2] + new_div[oe[1]] += oe[2] if new_div in eff: g.add_edge((i,eff.index(new_div))) return g @@ -6400,11 +6406,11 @@ def parallel_firing_graph(S, eff): new_edge = False new_div = deepcopy(eff[i]) for v in eff[i]: - if eff[i][v]>=S.out_degree(v): + if eff[i][v] >= S.out_degree(v): new_edge = True new_div[v] -= S.out_degree(v) for oe in S.outgoing_edges(v): - new_div[oe[1]]+=oe[2] + new_div[oe[1]] += oe[2] if new_edge and (new_div in eff): g.add_edge((i,eff.index(new_div))) return g @@ -6580,16 +6586,16 @@ def wilmes_algorithm(M): U = identity_matrix(ZZ,k).block_sum(smith) L = U*L L[k] = -L[k] - if L[-1][-2]>0: + if L[-1][-2] > 0: L[-1] = -L[-1] for k in range(M.nrows()-2,-1,-1): for i in range(k+2,M.nrows()): - while L[k][i-1]>0: + while L[k][i-1] > 0: L[k] = L[k] + L[i] v = -L[k+1] for i in range(k+2,M.nrows()): v = abs(L[i,i-1])*v + v[i-1]*L[i] - while L[k,k]<=0 or L[k,-1]>0: + while L[k,k] <= 0 or L[k,-1] > 0: L[k] = L[k] + v return L else: diff --git a/src/sage/sat/__init__.py b/src/sage/sat/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/sat/boolean_polynomials.py b/src/sage/sat/boolean_polynomials.py index 0d4abb66d93..2f3e650d70b 100644 --- a/src/sage/sat/boolean_polynomials.py +++ b/src/sage/sat/boolean_polynomials.py @@ -219,7 +219,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): instead of classes is discouraged because these objects are stateful. """ - assert(n>0) + assert n > 0 try: len(F) @@ -234,7 +234,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): target_variables = PolynomialSequence(F).variables() else: target_variables = PolynomialSequence(target_variables).variables() - assert(set(target_variables).issubset(set(P.gens()))) + assert set(target_variables).issubset(set(P.gens())) # instantiate the SAT solver diff --git a/src/sage/sat/converters/polybori.py b/src/sage/sat/converters/polybori.py index a53c4e650e3..ca39def12c1 100644 --- a/src/sage/sat/converters/polybori.py +++ b/src/sage/sat/converters/polybori.py @@ -473,7 +473,7 @@ def split_xor(self, monomial_list, equal_zero): new_variables = [] for j in range(0, nm, step): - m = new_variables + monomial_list[j:j+step] + m = new_variables + monomial_list[j:j+step] if (j + step) < nm: new_variables = [self.var(None)] m += new_variables diff --git a/src/sage/sat/solvers/satsolver.pyx b/src/sage/sat/solvers/satsolver.pyx index ddad2c8b182..c2f41b18f55 100644 --- a/src/sage/sat/solvers/satsolver.pyx +++ b/src/sage/sat/solvers/satsolver.pyx @@ -158,7 +158,7 @@ cdef class SatSolver: if line.startswith("x"): line = line[1:].split(" ") clause = [int(e) for e in line if e] - clause = clause[:-1] # strip trailing zero + clause = clause[:-1] # strip trailing zero try: self.add_xor_clause(clause) except AttributeError: diff --git a/src/sage/schemes/__init__.py b/src/sage/schemes/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/affine/__init__.py b/src/sage/schemes/affine/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/affine/affine_homset.py b/src/sage/schemes/affine/affine_homset.py index 98b3b3a8994..52ea3f83c85 100644 --- a/src/sage/schemes/affine/affine_homset.py +++ b/src/sage/schemes/affine/affine_homset.py @@ -41,10 +41,11 @@ from sage.rings.rational_field import is_RationalField from sage.categories.fields import Fields from sage.categories.number_fields import NumberFields -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.schemes.generic.homset import SchemeHomset_points, SchemeHomset_generic + # ******************************************************************* # Affine varieties # ******************************************************************* @@ -217,7 +218,7 @@ def points(self, **kwds): :: sage: A.<x,y> = ZZ[] - sage: I = A.ideal(x^2-y^2-1) + sage: I = A.ideal(x^2 - y^2 - 1) sage: V = AffineSpace(ZZ, 2) sage: X = V.subscheme(I) sage: M = X(ZZ) @@ -227,33 +228,37 @@ def points(self, **kwds): :: sage: u = QQ['u'].0 - sage: K.<v> = NumberField(u^2 + 3) - sage: A.<x,y> = AffineSpace(K, 2) - sage: len(A(K).points(bound=2)) + sage: K.<v> = NumberField(u^2 + 3) # needs sage.rings.number_field + sage: A.<x,y> = AffineSpace(K, 2) # needs sage.rings.number_field + sage: len(A(K).points(bound=2)) # needs sage.rings.number_field 1849 :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: E = A.subscheme([x^2 + y^2 - 1, y^2 - x^3 + x^2 + x - 1]) - sage: E(A.base_ring()).points() + sage: E(A.base_ring()).points() # needs sage.libs.singular [(-1, 0), (0, -1), (0, 1), (1, 0)] :: - sage: A.<x,y> = AffineSpace(CC, 2) + sage: A.<x,y> = AffineSpace(CC, 2) # needs sage.rings.real_mpfr sage: E = A.subscheme([y^3 - x^3 - x^2, x*y]) - sage: E(A.base_ring()).points() - verbose 0 (...: affine_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. + sage: E(A.base_ring()).points() # needs sage.libs.singular sage.rings.real_mpfr + verbose 0 (...: affine_homset.py, points) + Warning: computations in the numerical fields are inexact;points + may be computed partially or incorrectly. [(-1.00000000000000, 0.000000000000000), - (0.000000000000000, 0.000000000000000)] + (0.000000000000000, 0.000000000000000)] :: - sage: A.<x1,x2> = AffineSpace(CDF, 2) - sage: E = A.subscheme([x1^2 + x2^2 + x1*x2, x1 + x2]) - sage: E(A.base_ring()).points() - verbose 0 (...: affine_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. + sage: A.<x1,x2> = AffineSpace(CDF, 2) # needs sage.rings.complex_double + sage: E = A.subscheme([x1^2 + x2^2 + x1*x2, x1 + x2]) # needs sage.libs.singular sage.rings.complex_double + sage: E(A.base_ring()).points() # needs sage.libs.singular sage.rings.complex_double + verbose 0 (...: affine_homset.py, points) + Warning: computations in the numerical fields are inexact;points + may be computed partially or incorrectly. [(0.0, 0.0)] """ from sage.schemes.affine.affine_space import is_AffineSpace @@ -270,63 +275,63 @@ def points(self, **kwds): numerical = False # Then X must be a subscheme dim_ideal = X.defining_ideal().dimension() - if dim_ideal < 0: # no points + if dim_ideal < 0: # no points return [] - if dim_ideal == 0: # if X zero-dimensional + if dim_ideal == 0: # if X zero-dimensional rat_points = [] AS = X.ambient_space() N = AS.dimension_relative() BR = X.base_ring() - #need a lexicographic ordering for elimination + # need a lexicographic ordering for elimination R = PolynomialRing(BR, N, AS.gens(), order='lex') I = R.ideal(X.defining_polynomials()) I0 = R.ideal(0) - #Determine the points through elimination - #This is much faster than using the I.variety() function on each affine chart. + # Determine the points through elimination + # This is much faster than using the I.variety() function on each affine chart. G = I.groebner_basis() if G != [1]: P = {} points = [P] - #work backwards from solving each equation for the possible - #values of the next coordinate + # work backwards from solving each equation for the possible + # values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: - #substitute in our dictionary entry that has the values - #of coordinates known so far. This results in a single - #variable polynomial (by elimination) + # substitute in our dictionary entry that has the values + # of coordinates known so far. This results in a single + # variable polynomial (by elimination) L = G[i].substitute(P) if R(L).degree() > 0: if numerical: for pol in L.univariate_polynomial().roots(multiplicities=False): r = L.variables()[0] varindex = R.gens().index(r) - P.update({R.gen(varindex):pol}) + P.update({R.gen(varindex): pol}) new_points.append(copy(P)) good = 1 else: L = L.factor() - #the linear factors give the possible rational values of - #this coordinate + # the linear factors give the possible rational values of + # this coordinate for pol, pow in L: if pol.degree() == 1 and len(pol.variables()) == 1: good = 1 r = pol.variables()[0] varindex = R.gens().index(r) - #add this coordinates information to - #each dictionary entry - P.update({R.gen(varindex):-pol.constant_coefficient() / - pol.monomial_coefficient(r)}) + # add this coordinates information to + # each dictionary entry + P.update({R.gen(varindex): + -pol.constant_coefficient() / pol.monomial_coefficient(r)}) new_points.append(copy(P)) else: new_points.append(P) good = 1 if good: points = new_points - #the dictionary entries now have values for all coordinates - #they are the rational solutions to the equations - #make them into affine points + # the dictionary entries now have values for all coordinates + # they are the rational solutions to the equations + # make them into affine points for i in range(len(points)): if numerical: if len(points[i]) == N: @@ -346,19 +351,19 @@ def points(self, **kwds): prec = kwds.pop('precision', 53) if is_RationalField(R) or R == ZZ: if not B > 0: - raise TypeError("a positive bound B (= %s) must be specified"%B) + raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_rational_field - return enum_affine_rational_field(self,B) + return enum_affine_rational_field(self, B) if R in NumberFields(): if not B > 0: - raise TypeError("a positive bound B (= %s) must be specified"%B) + raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_number_field return enum_affine_number_field(self, bound=B, tolerance=tol, precision=prec) - elif is_FiniteField(R): + elif isinstance(R, FiniteField): from sage.schemes.affine.affine_rational_point import enum_affine_finite_field return enum_affine_finite_field(self) else: - raise TypeError("unable to enumerate points over %s"%R) + raise TypeError("unable to enumerate points over %s" % R) def numerical_points(self, F=None, **kwds): """ @@ -388,6 +393,7 @@ def numerical_points(self, F=None, **kwds): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<v> = QuadraticField(3) sage: A.<x,y> = AffineSpace(K, 2) sage: X = A.subscheme([x^3 - v^2*y, y - v*x^2 + 3]) @@ -402,14 +408,14 @@ def numerical_points(self, F=None, **kwds): sage: A.<x,y> = AffineSpace(QQ, 2) sage: X = A.subscheme([y^2 - x^2 - 3*x, x^2 - 10*y]) - sage: len(X(QQ).numerical_points(F=ComplexField(100))) + sage: len(X(QQ).numerical_points(F=ComplexField(100))) # needs sage.libs.singular 4 :: sage: A.<x1, x2> = AffineSpace(QQ, 2) sage: E = A.subscheme([30*x1^100 + 1000*x2^2 + 2000*x1*x2 + 1, x1 + x2]) - sage: len(E(A.base_ring()).numerical_points(F=CDF, zero_tolerance=1e-9)) + sage: len(E(A.base_ring()).numerical_points(F=CDF, zero_tolerance=1e-9)) # needs sage.libs.singular 100 TESTS:: @@ -425,7 +431,7 @@ def numerical_points(self, F=None, **kwds): sage: A.<x,y> = AffineSpace(QQ, 2) sage: X = A.subscheme([y^2 - x^2 - 3*x, x^2 - 10*y]) - sage: X(QQ).numerical_points(F=CC, zero_tolerance=-1) + sage: X(QQ).numerical_points(F=CC, zero_tolerance=-1) # needs sage.libs.singular Traceback (most recent call last): ... ValueError: tolerance must be positive @@ -443,7 +449,7 @@ def numerical_points(self, F=None, **kwds): if not is_AffineSpace(X) and X.base_ring() in Fields(): # Then X must be a subscheme dim_ideal = X.defining_ideal().dimension() - if dim_ideal != 0: # no points + if dim_ideal != 0: # no points return [] else: return [] diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 32c2e47e494..1fc3f207464 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -13,14 +13,12 @@ sage: P2.<x0,x1,x2> = ProjectiveSpace(QQ, 2) sage: A2.hom([x, x + y], A2) Scheme endomorphism of Affine Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (x, x + y) + Defn: Defined on coordinates by sending (x, y) to (x, x + y) sage: A2.hom([1, x, x + y], P2) Scheme morphism: From: Affine Space of dimension 2 over Rational Field To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (1 : x : x + y) + Defn: Defined on coordinates by sending (x, y) to (1 : x : x + y) AUTHORS: @@ -59,15 +57,14 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.arith.all import gcd +from sage.arith.misc import GCD as gcd from sage.rings.integer import Integer -from sage.rings.finite_rings.finite_field_constructor import is_PrimeFiniteField from sage.rings.fraction_field import FractionField from sage.rings.fraction_field_element import FractionFieldElement from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.schemes.generic.morphism import SchemeMorphism_polynomial @@ -96,8 +93,7 @@ class SchemeMorphism_polynomial_affine_space(SchemeMorphism_polynomial): Scheme morphism: From: Affine Space of dimension 2 over Rational Field To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (x : y : 1) + Defn: Defined on coordinates by sending (x, y) to (x : y : 1) """ def __init__(self, parent, polys, check=True): r""" @@ -135,20 +131,17 @@ def __init__(self, parent, polys, check=True): sage: H = Hom(A, A) sage: H([3/2*x^2, y^2]) Scheme endomorphism of Affine Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (3/2*x^2, y^2) + Defn: Defined on coordinates by sending (x, y) to (3/2*x^2, y^2) :: sage: A.<x,y> = AffineSpace(QQ, 2) - sage: X = A.subscheme([x-y^2]) + sage: X = A.subscheme([x - y^2]) sage: H = Hom(X, X) sage: H([9/4*x^2, 3/2*y]) Scheme endomorphism of Closed subscheme of Affine Space of dimension 2 - over Rational Field defined by: - -y^2 + x - Defn: Defined on coordinates by sending (x, y) to - (9/4*x^2, 3/2*y) + over Rational Field defined by: -y^2 + x + Defn: Defined on coordinates by sending (x, y) to (9/4*x^2, 3/2*y) sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: H = Hom(P, P) @@ -158,32 +151,30 @@ def __init__(self, parent, polys, check=True): Defn: Defined on coordinates by sending (x, y) to ((5*x^3 + 3*x*y^2 - y^3)/(x^3 - 1), (x^2*y + 3)/(x^3 - 1)) - If you pass in quotient ring elements, they are reduced:: + If you pass in quotient ring elements, they are reduced:: sage: A.<x,y,z> = AffineSpace(QQ, 3) - sage: X = A.subscheme([x-y]) - sage: H = Hom(X,X) - sage: u,v,w = X.coordinate_ring().gens() - sage: H([u, v, u+v]) + sage: X = A.subscheme([x - y]) + sage: H = Hom(X, X) + sage: u,v,w = X.coordinate_ring().gens() # needs sage.libs.singular + sage: H([u, v, u + v]) # needs sage.libs.singular Scheme endomorphism of Closed subscheme of Affine Space of dimension 3 - over Rational Field defined by: - x - y - Defn: Defined on coordinates by sending (x, y, z) to - (y, y, 2*y) + over Rational Field defined by: x - y + Defn: Defined on coordinates by sending (x, y, z) to (y, y, 2*y) - You must use the ambient space variables to create rational functions:: + You must use the ambient space variables to create rational functions:: sage: A.<x,y,z> = AffineSpace(QQ, 3) - sage: X = A.subscheme([x^2-y^2]) - sage: H = Hom(X,X) - sage: u,v,w = X.coordinate_ring().gens() - sage: H([u, v, (u+1)/v]) + sage: X = A.subscheme([x^2 - y^2]) + sage: H = Hom(X, X) + sage: u,v,w = X.coordinate_ring().gens() # needs sage.libs.singular + sage: H([u, v, (u+1)/v]) # needs sage.libs.singular Traceback (most recent call last): ... ArithmeticError: Division failed. The numerator is not a multiple of the denominator. sage: H([x, y, (x+1)/y]) Scheme endomorphism of Closed subscheme of Affine Space of dimension 3 - over Rational Field defined by: + over Rational Field defined by: x^2 - y^2 Defn: Defined on coordinates by sending (x, y, z) to (x, y, (x + 1)/y) @@ -192,22 +183,22 @@ def __init__(self, parent, polys, check=True): sage: R.<t> = PolynomialRing(QQ) sage: A.<x,y,z> = AffineSpace(R, 3) - sage: X = A.subscheme(x^2-y^2) + sage: X = A.subscheme(x^2 - y^2) sage: H = End(X) sage: H([x^2/(t*y), t*y^2, x*z]) Scheme endomorphism of Closed subscheme of Affine Space of dimension 3 - over Univariate Polynomial Ring in t over Rational Field defined by: + over Univariate Polynomial Ring in t over Rational Field defined by: x^2 - y^2 Defn: Defined on coordinates by sending (x, y, z) to (x^2/(t*y), t*y^2, x*z) """ if check: if not isinstance(polys, (list, tuple)): - raise TypeError("polys (=%s) must be a list or tuple"%polys) + raise TypeError("polys (=%s) must be a list or tuple" % polys) source_ring = parent.domain().ambient_space().coordinate_ring() target = parent.codomain().ambient_space() if len(polys) != target.ngens(): - raise ValueError("there must be %s polynomials"%target.ngens()) + raise ValueError("there must be %s polynomials" % target.ngens()) try: polys = [source_ring(poly) for poly in polys] except TypeError: # maybe given quotient ring elements @@ -216,20 +207,22 @@ def __init__(self, parent, polys, check=True): except (TypeError, AttributeError): # must be a rational function since we cannot have # rational functions for quotient rings + source_field = source_ring.base_ring().fraction_field() try: - if not all(p.base_ring().fraction_field()==source_ring.base_ring().fraction_field() for p in polys): - raise TypeError("polys (=%s) must be rational functions in %s"%(polys, source_ring)) + if not all(p.base_ring().fraction_field() == source_field for p in polys): + raise TypeError("polys (=%s) must be rational functions in %s" % (polys, source_ring)) K = FractionField(source_ring) polys = [K(p) for p in polys] # polys = [source_ring(poly.numerator())/source_ring(poly.denominator()) for poly in polys] - except TypeError: # can't seem to coerce - raise TypeError("polys (=%s) must be rational functions in %s"%(polys, source_ring)) + except TypeError: # can't seem to coerce + raise TypeError("polys (=%s) must be rational functions in %s" % (polys, source_ring)) check = False SchemeMorphism_polynomial.__init__(self, parent, polys, check) # used in _fast_eval and _fastpolys - self._is_prime_finite_field = is_PrimeFiniteField(polys[0].base_ring()) + R = polys[0].base_ring() + self._is_prime_finite_field = isinstance(R, FiniteField) and R.is_prime_field() def __call__(self, x, check=True): """ @@ -239,7 +232,7 @@ def __call__(self, x, check=True): sage: P.<x,y,z> = AffineSpace(QQ, 3) sage: H = Hom(P, P) - sage: f = H([x^2+y^2, y^2, z^2 + y*z]) + sage: f = H([x^2 + y^2, y^2, z^2 + y*z]) sage: f(P([1, 1, 1])) (2, 1, 2) @@ -256,6 +249,7 @@ def __call__(self, x, check=True): Defn: Defined on coordinates by sending (u, v) to (u + v, u*v) + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) sage: P = T(F)(1, a) sage: h(P) @@ -271,7 +265,7 @@ def __call__(self, x, check=True): try: x = self.domain()(x) except (TypeError, NotImplementedError): - raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented"%(x, self.domain())) + raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented" % (x, self.domain())) R = x.domain().coordinate_ring() if R is self.base_ring(): @@ -305,6 +299,7 @@ def __eq__(self, right): :: + sage: # needs sage.rings.real_mpfr sage: A.<x,y,z> = AffineSpace(CC, 3) sage: H = End(A) sage: f = H([x^2 - CC.0*x*y + z*x, 1/z^2 - y^2, 5*x]) @@ -315,7 +310,7 @@ def __eq__(self, right): return False if self.parent() != right.parent(): return False - return all(val == right._polys[i] for i,val in enumerate(self._polys)) + return all(val == right._polys[i] for i, val in enumerate(self._polys)) def __ne__(self, right): """ @@ -331,10 +326,11 @@ def __ne__(self, right): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: A.<x,y> = AffineSpace(RR, 2) sage: H = End(A) sage: f = H([x^2 - y, y^2]) - sage: g = H([x^3-x*y, x*y^2]) + sage: g = H([x^3 - x*y, x*y^2]) sage: f != g True sage: f != f @@ -344,7 +340,7 @@ def __ne__(self, right): return True if self.parent() != right.parent(): return True - return any(val != right._polys[i] for i,val in enumerate(self._polys)) + return any(val != right._polys[i] for i, val in enumerate(self._polys)) @lazy_attribute def _fastpolys(self): @@ -355,7 +351,7 @@ def _fastpolys(self): sage: P.<x,y> = AffineSpace(QQ, 2) sage: H = Hom(P, P) - sage: f = H([x^2+y^2, y^2/(1+x)]) + sage: f = H([x^2 + y^2, y^2/(1+x)]) sage: [t.op_list() for g in f._fastpolys for t in g] [[('load_const', 0), ('load_const', 1), ('load_arg', ...), ('ipow', 2), 'mul', 'add', ('load_const', 1), ('load_arg', ...), ('ipow', 2), 'mul', @@ -385,9 +381,12 @@ def _fastpolys(self): if self._is_prime_finite_field: prime = polys[0].base_ring().characteristic() degree = max(poly_numerator.degree(), poly_denominator.degree()) - height = max([abs(c.lift()) for c in poly_numerator.coefficients()]\ - + [abs(c.lift()) for c in poly_denominator.coefficients()]) - num_terms = max(len(poly_numerator.coefficients()), len(poly_denominator.coefficients())) + height = max([abs(c.lift()) + for c in poly_numerator.coefficients()] + + [abs(c.lift()) + for c in poly_denominator.coefficients()]) + num_terms = max(len(poly_numerator.coefficients()), + len(poly_denominator.coefficients())) largest_value = num_terms * height * (prime - 1) ** degree # If the calculations will not overflow the float data type use domain float # Else use domain integer @@ -410,7 +409,7 @@ def _fast_eval(self, x): sage: P.<x,y,z> = AffineSpace(QQ, 3) sage: H = Hom(P, P) - sage: f = H([x^2+y^2, y^2, z^2 + y*z]) + sage: f = H([x^2 + y^2, y^2, z^2 + y*z]) sage: f._fast_eval([1, 1, 1]) [2, 1, 2] @@ -427,11 +426,11 @@ def _fast_eval(self, x): P = [] for i in range(len(self._fastpolys[0])): # Check if denominator is the identity; - #if not, then must append the fraction evaluated at the point + # if not, then must append the fraction evaluated at the point if self._fastpolys[1][i] is R.one(): P.append(self._fastpolys[0][i](*x)) else: - P.append(self._fastpolys[0][i](*x)/self._fastpolys[1][i](*x)) + P.append(self._fastpolys[0][i](*x) / self._fastpolys[1][i](*x)) return P def homogenize(self, n): @@ -462,60 +461,60 @@ def homogenize(self, n): :: + sage: # needs sage.rings.real_mpfr sage: A.<x,y> = AffineSpace(CC, 2) sage: H = Hom(A, A) - sage: f = H([(x^2-2)/(x*y), y^2-x]) + sage: f = H([(x^2-2)/(x*y), y^2 - x]) sage: f.homogenize((2, 0)) Scheme endomorphism of Projective Space of dimension 2 - over Complex Field with 53 bits of precision - Defn: Defined on coordinates by sending (x0 : x1 : x2) to - (x0*x1*x2^2 : x0^2*x2^2 + (-2.00000000000000)*x2^4 : x0*x1^3 - x0^2*x1*x2) + over Complex Field with 53 bits of precision + Defn: Defined on coordinates by sending (x0 : x1 : x2) to + (x0*x1*x2^2 : x0^2*x2^2 + (-2.00000000000000)*x2^4 : x0*x1^3 - x0^2*x1*x2) :: sage: A.<x,y> = AffineSpace(ZZ, 2) - sage: X = A.subscheme([x-y^2]) + sage: X = A.subscheme([x - y^2]) sage: H = Hom(X, X) sage: f = H([9*y^2, 3*y]) - sage: f.homogenize(2) + sage: f.homogenize(2) # needs sage.libs.singular Scheme endomorphism of Closed subscheme of Projective Space - of dimension 2 over Integer Ring defined by: - x1^2 - x0*x2 - Defn: Defined on coordinates by sending (x0 : x1 : x2) to - (9*x1^2 : 3*x1*x2 : x2^2) + of dimension 2 over Integer Ring defined by: x1^2 - x0*x2 + Defn: Defined on coordinates by sending (x0 : x1 : x2) to + (9*x1^2 : 3*x1*x2 : x2^2) :: sage: R.<t> = PolynomialRing(ZZ) sage: A.<x,y> = AffineSpace(R, 2) sage: H = Hom(A, A) - sage: f = H([(x^2-2)/y, y^2-x]) + sage: f = H([(x^2-2)/y, y^2 - x]) sage: f.homogenize((2, 0)) Scheme endomorphism of Projective Space of dimension 2 - over Univariate Polynomial Ring in t over Integer Ring - Defn: Defined on coordinates by sending (x0 : x1 : x2) to - (x1*x2^2 : x0^2*x2 + (-2)*x2^3 : x1^3 - x0*x1*x2) + over Univariate Polynomial Ring in t over Integer Ring + Defn: Defined on coordinates by sending (x0 : x1 : x2) to + (x1*x2^2 : x0^2*x2 + (-2)*x2^3 : x1^3 - x0*x1*x2) :: sage: A.<x> = AffineSpace(QQ, 1) sage: H = End(A) - sage: f = H([x^2-1]) + sage: f = H([x^2 - 1]) sage: f.homogenize((1, 0)) - Scheme endomorphism of Projective Space of dimension 1 - over Rational Field - Defn: Defined on coordinates by sending (x0 : x1) to - (x1^2 : x0^2 - x1^2) + Scheme endomorphism of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x0 : x1) to + (x1^2 : x0^2 - x1^2) :: + sage: # needs sage.rings.number_field sage: R.<a> = PolynomialRing(QQbar) sage: A.<x,y> = AffineSpace(R, 2) sage: H = End(A) - sage: f = H([QQbar(sqrt(2))*x*y, a*x^2]) - sage: f.homogenize(2) - Scheme endomorphism of Projective Space of dimension 2 over Univariate - Polynomial Ring in a over Algebraic Field + sage: f = H([QQbar(sqrt(2))*x*y, a*x^2]) # needs sage.symbolic + sage: f.homogenize(2) # needs sage.libs.singular sage.symbolic + Scheme endomorphism of Projective Space of dimension 2 + over Univariate Polynomial Ring in a over Algebraic Field Defn: Defined on coordinates by sending (x0 : x1 : x2) to (1.414213562373095?*x0*x1 : a*x0^2 : x2^2) @@ -533,38 +532,41 @@ def homogenize(self, n): sage: A.<x> = AffineSpace(K, 1) sage: f = Hom(A, A)([x^2 + c]) sage: f.homogenize(1) - Scheme endomorphism of Projective Space of - dimension 1 over Rational function field in c over Rational Field + Scheme endomorphism of Projective Space of dimension 1 + over Rational function field in c over Rational Field Defn: Defined on coordinates by sending (x0 : x1) to (x0^2 + c*x1^2 : x1^2) :: + sage: # needs sage.rings.number_field sage: A.<z> = AffineSpace(QQbar, 1) sage: H = End(A) sage: f = H([2*z / (z^2 + 2*z + 3)]) sage: f.homogenize(1) - Scheme endomorphism of Projective Space of dimension 1 over Algebraic - Field - Defn: Defined on coordinates by sending (x0 : x1) to + Scheme endomorphism of Projective Space of dimension 1 + over Algebraic Field + Defn: Defined on coordinates by sending (x0 : x1) to (x0*x1 : 1/2*x0^2 + x0*x1 + 3/2*x1^2) :: + sage: # needs sage.rings.number_field sage: R.<c,d> = QQbar[] sage: A.<x> = AffineSpace(R, 1) sage: H = Hom(A, A) sage: F = H([d*x^2 + c]) sage: F.homogenize(1) - Scheme endomorphism of Projective Space of dimension 1 over Multivariate Polynomial Ring in c, d over Algebraic Field - Defn: Defined on coordinates by sending (x0 : x1) to - (d*x0^2 + c*x1^2 : x1^2) + Scheme endomorphism of Projective Space of dimension 1 + over Multivariate Polynomial Ring in c, d over Algebraic Field + Defn: Defined on coordinates by sending (x0 : x1) to + (d*x0^2 + c*x1^2 : x1^2) TESTS:: sage: A2.<u,v> = AffineSpace(QQ, 2) sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: f = A2.hom([u,v,u*v], P2) + sage: f = A2.hom([u, v, u*v], P2) sage: g = f.homogenize(0) sage: i = A2.projective_embedding(0, g.domain()) sage: g*i == f @@ -603,32 +605,32 @@ def homogenize(self, n): # create dictionary for mapping of coordinate rings R = self.domain().ambient_space().coordinate_ring() S = A.ambient_space().coordinate_ring() - D = dict(zip(R.gens(), [S.gen(i) for i in range(N+1) if i != ind[0]])) + D = dict(zip(R.gens(), [S.gen(i) for i in range(N + 1) if i != ind[0]])) if self.codomain().is_projective(): - L = [self[i].denominator() for i in range(M+1)] - l = [prod(L[:j] + L[j+1:M+1]) for j in range(M+1)] - F = [S(R(self[i].numerator()*l[i]).subs(D)) for i in range(M+1)] + L = [self[i].denominator() for i in range(M + 1)] + l = [prod(L[:j] + L[j + 1:M + 1]) for j in range(M + 1)] + F = [S(R(self[i].numerator() * l[i]).subs(D)) for i in range(M + 1)] else: # clear the denominators if a rational function L = [self[i].denominator() for i in range(M)] - l = [prod(L[:j] + L[j+1:M]) for j in range(M)] - F = [S(R(self[i].numerator()*l[i]).subs(D)) for i in range(M)] + l = [prod(L[:j] + L[j + 1:M]) for j in range(M)] + F = [S(R(self[i].numerator() * l[i]).subs(D)) for i in range(M)] F.insert(ind[1], S(R(prod(L)).subs(D))) # coerce in case l is a constant try: # remove possible gcd of the polynomials g = gcd(F) - F = [S(f/g) for f in F] + F = [S(f / g) for f in F] # remove possible gcd of coefficients gc = gcd([f.content() for f in F]) - F = [S(f/gc) for f in F] - except (AttributeError, ValueError, NotImplementedError, TypeError, ArithmeticError): # no gcd + F = [S(f / gc) for f in F] + except (AttributeError, ValueError, NotImplementedError, TypeError, ArithmeticError): # no gcd pass # homogenize - d = max([F[i].degree() for i in range(M+1)]) - F = [F[i].homogenize(str(newvar))*newvar**(d-F[i].degree()) for i in range(M+1)] + d = max([F[i].degree() for i in range(M + 1)]) + F = [F[i].homogenize(str(newvar)) * newvar**(d - F[i].degree()) for i in range(M + 1)] return H(F) @@ -645,15 +647,15 @@ def as_dynamical_system(self): sage: A.<x,y,z> = AffineSpace(ZZ, 3) sage: H = End(A) sage: f = H([x^2, y^2, z^2]) - sage: type(f.as_dynamical_system()) + sage: type(f.as_dynamical_system()) # needs sage.schemes <class 'sage.dynamics.arithmetic_dynamics.affine_ds.DynamicalSystem_affine'> :: sage: A.<x,y> = AffineSpace(ZZ, 2) sage: H = End(A) - sage: f = H([x^2-y^2, y^2]) - sage: type(f.as_dynamical_system()) + sage: f = H([x^2 - y^2, y^2]) + sage: type(f.as_dynamical_system()) # needs sage.schemes <class 'sage.dynamics.arithmetic_dynamics.affine_ds.DynamicalSystem_affine'> :: @@ -661,15 +663,15 @@ def as_dynamical_system(self): sage: A.<x> = AffineSpace(GF(5), 1) sage: H = End(A) sage: f = H([x^2]) - sage: type(f.as_dynamical_system()) + sage: type(f.as_dynamical_system()) # needs sage.schemes <class 'sage.dynamics.arithmetic_dynamics.affine_ds.DynamicalSystem_affine_finite_field'> :: sage: P.<x,y> = AffineSpace(RR, 2) - sage: f = DynamicalSystem([x^2 + y^2, y^2], P) - sage: g = f.as_dynamical_system() - sage: g is f + sage: f = DynamicalSystem([x^2 + y^2, y^2], P) # needs sage.schemes + sage: g = f.as_dynamical_system() # needs sage.schemes + sage: g is f # needs sage.schemes True """ from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem @@ -683,8 +685,8 @@ def as_dynamical_system(self): R = self.base_ring() if R not in _Fields: return DynamicalSystem_affine(list(self), self.domain()) - if is_FiniteField(R): - return DynamicalSystem_affine_finite_field(list(self), self.domain()) + if isinstance(R, FiniteField): + return DynamicalSystem_affine_finite_field(list(self), self.domain()) return DynamicalSystem_affine_field(list(self), self.domain()) def global_height(self, prec=None): @@ -703,17 +705,18 @@ def global_height(self, prec=None): sage: A.<x> = AffineSpace(QQ, 1) sage: H = Hom(A, A) - sage: f = H([1/1331*x^2 + 4000]); - sage: f.global_height() + sage: f = H([1/1331*x^2 + 4000]) + sage: f.global_height() # needs sage.symbolic 15.4877354584971 :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) sage: k.<w> = NumberField(x^2 + 5) sage: A.<x,y> = AffineSpace(k, 2) sage: H = Hom(A, A) - sage: f = H([13*w*x^2 + 4*y, 1/w*y^2]); + sage: f = H([13*w*x^2 + 4*y, 1/w*y^2]) sage: f.global_height(prec=2) 4.0 @@ -721,8 +724,8 @@ def global_height(self, prec=None): sage: A.<x> = AffineSpace(ZZ, 1) sage: H = Hom(A, A) - sage: f = H([7*x^2 + 1513]); - sage: f.global_height() + sage: f = H([7*x^2 + 1513]) + sage: f.global_height() # needs sage.symbolic 7.32184971378836 :: @@ -731,7 +734,7 @@ def global_height(self, prec=None): sage: B.<y,z> = AffineSpace(QQ, 2) sage: H = Hom(A, B) sage: f = H([1/3*x^2 + 10, 7*x^3]) - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 3.40119738166216 :: @@ -740,7 +743,7 @@ def global_height(self, prec=None): sage: A.<z> = AffineSpace(QQ, 1) sage: H = Hom(P, A) sage: f = H([1/1331*x^2 + 4000*y]) - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 15.4877354584971 """ return self.homogenize(0).global_height(prec=prec) @@ -765,28 +768,29 @@ def local_height(self, v, prec=None): sage: P.<x,y> = AffineSpace(QQ, 2) sage: H = Hom(P, P) - sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]); - sage: f.local_height(1331) + sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]) + sage: f.local_height(1331) # needs sage.rings.real_mpfr 7.19368581839511 :: sage: P.<x,y,z> = AffineSpace(QQ, 3) sage: H = Hom(P, P) - sage: f = H([4*x^2 + 3/100*y^2, 8/210*x*y, 1/10000*z^2]); - sage: f.local_height(2) + sage: f = H([4*x^2 + 3/100*y^2, 8/210*x*y, 1/10000*z^2]) + sage: f.local_height(2) # needs sage.rings.real_mpfr 2.77258872223978 :: sage: P.<x,y,z> = AffineSpace(QQ, 3) sage: H = Hom(P, P) - sage: f = H([4*x^2 + 3/100*y^2, 8/210*x*y, 1/10000*z^2]); - sage: f.local_height(2, prec=2) + sage: f = H([4*x^2 + 3/100*y^2, 8/210*x*y, 1/10000*z^2]) + sage: f.local_height(2, prec=2) # needs sage.rings.real_mpfr 3.0 :: + sage: # needs sage.rings.number_field sage: R.<z> = PolynomialRing(QQ) sage: K.<w> = NumberField(z^2 - 2) sage: P.<x,y> = AffineSpace(K, 2) @@ -821,7 +825,7 @@ def local_height_arch(self, i, prec=None): sage: P.<x,y> = AffineSpace(QQ, 2) sage: H = Hom(P, P) sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]); - sage: f.local_height_arch(0) + sage: f.local_height_arch(0) # needs sage.rings.real_mpfr 5.34710753071747 :: @@ -829,11 +833,12 @@ def local_height_arch(self, i, prec=None): sage: P.<x,y> = AffineSpace(QQ, 2) sage: H = Hom(P, P) sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]); - sage: f.local_height_arch(0, prec=5) + sage: f.local_height_arch(0, prec=5) # needs sage.rings.real_mpfr 5.2 :: + sage: # needs sage.rings.number_field sage: R.<z> = PolynomialRing(QQ) sage: K.<w> = NumberField(z^2 - 2) sage: P.<x,y> = AffineSpace(K, 2) @@ -855,7 +860,7 @@ def jacobian(self): Return the Jacobian matrix of partial derivative of this map. The `(i, j)` entry of the Jacobian matrix is the partial derivative - `diff(functions[i], variables[j])`. + ``diff(functions[i], variables[j])``. OUTPUT: @@ -866,7 +871,7 @@ def jacobian(self): sage: A.<z> = AffineSpace(QQ, 1) sage: H = End(A) sage: f = H([z^2 - 3/4]) - sage: f.jacobian() + sage: f.jacobian() # needs sage.modules [2*z] :: @@ -874,7 +879,7 @@ def jacobian(self): sage: A.<x,y> = AffineSpace(QQ, 2) sage: H = End(A) sage: f = H([x^3 - 25*x + 12*y, 5*y^2*x - 53*y + 24]) - sage: f.jacobian() + sage: f.jacobian() # needs sage.modules [ 3*x^2 - 25 12] [ 5*y^2 10*x*y - 53] @@ -883,7 +888,7 @@ def jacobian(self): sage: A.<x,y> = AffineSpace(ZZ, 2) sage: H = End(A) sage: f = H([(x^2 - x*y)/(1+y), (5+y)/(2+x)]) - sage: f.jacobian() + sage: f.jacobian() # needs sage.modules [ (2*x - y)/(y + 1) (-x^2 - x)/(y^2 + 2*y + 1)] [ (-y - 5)/(x^2 + 4*x + 4) 1/(x + 2)] """ @@ -891,7 +896,7 @@ def jacobian(self): return self.__jacobian except AttributeError: pass - self.__jacobian = jacobian(list(self),self.domain().ambient_space().gens()) + self.__jacobian = jacobian(list(self), self.domain().ambient_space().gens()) return self.__jacobian def _matrix_times_polymap_(self, mat, h): @@ -909,18 +914,18 @@ def _matrix_times_polymap_(self, mat, h): sage: A.<x> = AffineSpace(ZZ, 1) sage: H = Hom(A, A) sage: f = H([x^2 + 1]) - sage: matrix([[1,2], [0,1]]) * f + sage: matrix([[1,2], [0,1]]) * f # needs sage.modules Scheme endomorphism of Affine Space of dimension 1 over Integer Ring Defn: Defined on coordinates by sending (x) to (x^2 + 3) :: - sage: A1 = AffineSpace(ZZ,1) - sage: A2 = AffineSpace(ZZ,2) + sage: A1 = AffineSpace(ZZ, 1) + sage: A2 = AffineSpace(ZZ, 2) sage: H = Hom(A1, A2) - sage: f = H([x^2+1,x^2-1]) - sage: matrix([[1,2,3], [0,1,2], [0,0,1]]) * f + sage: f = H([x^2 + 1, x^2 - 1]) + sage: matrix([[1,2,3], [0,1,2], [0,0,1]]) * f # needs sage.modules Scheme morphism: From: Affine Space of dimension 1 over Integer Ring To: Affine Space of dimension 2 over Integer Ring @@ -953,18 +958,18 @@ def _polymap_times_matrix_(self, mat, h): sage: A.<x> = AffineSpace(ZZ, 1) sage: H = Hom(A, A) sage: f = H([x^2 + 1]) - sage: f * matrix([[1,2], [0,1]]) + sage: f * matrix([[1,2], [0,1]]) # needs sage.modules Scheme endomorphism of Affine Space of dimension 1 over Integer Ring Defn: Defined on coordinates by sending (x) to (x^2 + 4*x + 5) :: - sage: A1 = AffineSpace(ZZ,1) - sage: A2 = AffineSpace(ZZ,2) + sage: A1 = AffineSpace(ZZ, 1) + sage: A2 = AffineSpace(ZZ, 2) sage: H = Hom(A1, A2) - sage: f = H([x^2+1,x^2-1]) - sage: f * matrix([[1,2], [0,1]]) + sage: f = H([x^2 + 1, x^2 - 1]) + sage: f * matrix([[1,2], [0,1]]) # needs sage.modules Scheme morphism: From: Affine Space of dimension 1 over Integer Ring To: Affine Space of dimension 2 over Integer Ring @@ -974,11 +979,11 @@ def _polymap_times_matrix_(self, mat, h): :: sage: P.<x, y> = AffineSpace(QQ, 2) - sage: P2.<u,v,w> = AffineSpace(QQ,3) + sage: P2.<u,v,w> = AffineSpace(QQ, 3) sage: H = Hom(P2, P) sage: f = H([u^2 + v^2, w^2]) - sage: m = matrix([[1,1,1], [1,0,1],[0,0,1]]) - sage: m*f + sage: m = matrix([[1,1,1], [1,0,1], [0,0,1]]) # needs sage.modules + sage: m*f # needs sage.modules Scheme morphism: From: Affine Space of dimension 3 over Rational Field To: Affine Space of dimension 2 over Rational Field @@ -1031,6 +1036,7 @@ def degree(self): max_degree = poly.degree() return max_degree + class SchemeMorphism_polynomial_affine_space_field(SchemeMorphism_polynomial_affine_space): @cached_method @@ -1057,10 +1063,11 @@ def weil_restriction(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<v> = QuadraticField(5) sage: A.<x,y> = AffineSpace(K, 2) sage: H = End(A) - sage: f = H([x^2-y^2, y^2]) + sage: f = H([x^2 - y^2, y^2]) sage: f.weil_restriction() Scheme endomorphism of Affine Space of dimension 4 over Rational Field Defn: Defined on coordinates by sending (z0, z1, z2, z3) to @@ -1068,6 +1075,7 @@ def weil_restriction(self): :: + sage: # needs sage.rings.number_field sage: K.<v> = QuadraticField(5) sage: PS.<x,y> = AffineSpace(K, 2) sage: H = Hom(PS, PS) @@ -1103,65 +1111,68 @@ def reduce_base_field(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<t> = GF(5^4) sage: A.<x> = AffineSpace(K, 1) sage: A2.<a,b> = AffineSpace(K, 2) sage: H = End(A) - sage: H2 = Hom(A,A2) - sage: H3 = Hom(A2,A) + sage: H2 = Hom(A, A2) + sage: H3 = Hom(A2, A) sage: f = H([x^2 + 2*(t^3 + t^2 + t + 3)]) sage: f.reduce_base_field() - Scheme endomorphism of Affine Space of dimension 1 over Finite Field in t2 of size 5^2 - Defn: Defined on coordinates by sending (x) to - (x^2 + (2*t2)) + Scheme endomorphism of Affine Space of dimension 1 + over Finite Field in t2 of size 5^2 + Defn: Defined on coordinates by sending (x) to (x^2 + (2*t2)) sage: f2 = H2([x^2 + 4, 2*x]) sage: f2.reduce_base_field() Scheme morphism: From: Affine Space of dimension 1 over Finite Field of size 5 To: Affine Space of dimension 2 over Finite Field of size 5 - Defn: Defined on coordinates by sending (x) to - (x^2 - 1, 2*x) + Defn: Defined on coordinates by sending (x) to (x^2 - 1, 2*x) sage: f3 = H3([a^2 + t*b]) sage: f3.reduce_base_field() Scheme morphism: From: Affine Space of dimension 2 over Finite Field in t of size 5^4 To: Affine Space of dimension 1 over Finite Field in t of size 5^4 - Defn: Defined on coordinates by sending (a, b) to - (a^2 + t*b) + Defn: Defined on coordinates by sending (a, b) to (a^2 + t*b) :: + sage: # needs sage.rings.number_field sage: K.<v> = CyclotomicField(4) sage: A.<x> = AffineSpace(K, 1) sage: H = End(A) sage: f = H([x^2 + v]) - sage: g = f.reduce_base_field();g - Scheme endomorphism of Affine Space of dimension 1 over Cyclotomic Field of order 4 and degree 2 - Defn: Defined on coordinates by sending (x) to - (x^2 + v) + sage: g = f.reduce_base_field(); g + Scheme endomorphism of Affine Space of dimension 1 + over Cyclotomic Field of order 4 and degree 2 + Defn: Defined on coordinates by sending (x) to (x^2 + v) sage: g.base_ring() is K True :: + sage: # needs sage.rings.number_field sage: A.<x> = AffineSpace(QQbar, 1) sage: H = End(A) - sage: f = H([(QQbar(sqrt(2))*x^2 + 1/QQbar(sqrt(3))) / (5*x)]) - sage: f.reduce_base_field() - Scheme endomorphism of Affine Space of dimension 1 over Number Field in a with defining polynomial y^4 - 4*y^2 + 1 with a = ...? + sage: f = H([(QQbar(sqrt(2))*x^2 + 1/QQbar(sqrt(3))) / (5*x)]) # needs sage.symbolic + sage: f.reduce_base_field() # needs sage.symbolic + Scheme endomorphism of Affine Space of dimension 1 over Number Field in a + with defining polynomial y^4 - 4*y^2 + 1 with a = ...? Defn: Defined on coordinates by sending (x) to (((a^3 - 3*a)*x^2 + (-1/3*a^2 + 2/3))/(5*x)) :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) - sage: A.<x> =AffineSpace(QQbar,1) + sage: A.<x> = AffineSpace(QQbar, 1) sage: H = End(A) - sage: f = H([QQbar(3^(1/3))*x^2 + QQbar(sqrt(-2))]) - sage: f.reduce_base_field() + sage: f = H([QQbar(3^(1/3))*x^2 + QQbar(sqrt(-2))]) # needs sage.symbolic + sage: f.reduce_base_field() # needs sage.symbolic Scheme endomorphism of Affine Space of dimension 1 over Number Field in a with defining polynomial y^6 + 6*y^4 - 6*y^3 + 12*y^2 + 36*y + 17 - with a = 1.442249570307409? + 1.414213562373095?*I + with a = 1.442249570307409? + 1.414213562373095?*I Defn: Defined on coordinates by sending (x) to ((-48/269*a^5 + 27/269*a^4 - 320/269*a^3 + 468/269*a^2 - 772/269*a - 1092/269)*x^2 + (48/269*a^5 - 27/269*a^4 + 320/269*a^3 - 468/269*a^2 @@ -1169,40 +1180,43 @@ def reduce_base_field(self): :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) - sage: K.<a> = NumberField(x^3-x+1, embedding=(x^3+x+1).roots(ring=CC)[0][0]) - sage: A.<x> = AffineSpace(K,1) - sage: A2.<u,v> = AffineSpace(K,2) + sage: K.<a> = NumberField(x^3 - x + 1, + ....: embedding=(x^3 + x + 1).roots(ring=CC)[0][0]) + sage: A.<x> = AffineSpace(K, 1) + sage: A2.<u,v> = AffineSpace(K, 2) sage: H = Hom(A, A2) sage: f = H([x^2 + a*x + 3, 5*x]) sage: f.reduce_base_field() Scheme morphism: - From: Affine Space of dimension 1 over Number Field in a with - defining polynomial x^3 - x + 1 with a = -1.324717957244746? - To: Affine Space of dimension 2 over Number Field in a with - defining polynomial x^3 - x + 1 with a = -1.324717957244746? - Defn: Defined on coordinates by sending (x) to - (x^2 + a*x + 3, 5*x) + From: Affine Space of dimension 1 over Number Field in a with + defining polynomial x^3 - x + 1 with a = -1.324717957244746? + To: Affine Space of dimension 2 over Number Field in a with + defining polynomial x^3 - x + 1 with a = -1.324717957244746? + Defn: Defined on coordinates by sending (x) to (x^2 + a*x + 3, 5*x) :: + sage: # needs sage.rings.number_field sage: K.<v> = QuadraticField(2) - sage: A.<x> =AffineSpace(K,1) + sage: A.<x> = AffineSpace(K, 1) sage: H = End(A) sage: f = H([3*x^2 + x + 1]) sage: f.reduce_base_field() Scheme endomorphism of Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x) to - (3*x^2 + x + 1) + Defn: Defined on coordinates by sending (x) to (3*x^2 + x + 1) :: + sage: # needs sage.rings.finite_rings sage: K.<t> = GF(5^6) sage: A.<x> = AffineSpace(K, 1) sage: H = End(A) sage: f = H([x^2 + x*(t^3 + 2*t^2 + 4*t) + (t^5 + 3*t^4 + t^2 + 4*t)]) sage: f.reduce_base_field() - Scheme endomorphism of Affine Space of dimension 1 over Finite Field in t of size 5^6 + Scheme endomorphism of Affine Space of dimension 1 + over Finite Field in t of size 5^6 Defn: Defined on coordinates by sending (x) to (x^2 + (t^3 + 2*t^2 - t)*x + (t^5 - 2*t^4 + t^2 - t)) """ @@ -1217,7 +1231,7 @@ def reduce_base_field(self): R = new_domain.coordinate_ring() H = Hom(new_domain, new_codomain) if isinstance(g[0], FractionFieldElement): - return H([R(G.numerator())/R(G.denominator()) for G in g]) + return H([R(G.numerator()) / R(G.denominator()) for G in g]) return H([R(G) for G in g]) def indeterminacy_locus(self): @@ -1234,7 +1248,7 @@ def indeterminacy_locus(self): sage: A.<x,y> = AffineSpace(QQ, 2) sage: H = End(A) sage: f = H([x - y, x^2 - y^2]) - sage: f.indeterminacy_locus() + sage: f.indeterminacy_locus() # needs sage.libs.singular Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: 1 @@ -1242,13 +1256,13 @@ def indeterminacy_locus(self): sage: A.<x,y> = AffineSpace(QQ, 2) sage: f = A.hom([x, x/y], A) - sage: f.indeterminacy_locus() + sage: f.indeterminacy_locus() # needs sage.libs.singular Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: y """ A = self.domain() X = A.subscheme(0) # affine space as a subscheme - return (self*X.hom(A.gens(), A)).indeterminacy_locus() + return (self * X.hom(A.gens(), A)).indeterminacy_locus() def indeterminacy_points(self, F=None): r""" @@ -1267,7 +1281,7 @@ def indeterminacy_points(self, F=None): sage: A.<x,y> = AffineSpace(QQ, 2) sage: H = End(A) sage: f = H([x - y, x^2 - y^2]) - sage: f.indeterminacy_points() + sage: f.indeterminacy_points() # needs sage.libs.singular [] :: @@ -1275,7 +1289,7 @@ def indeterminacy_points(self, F=None): sage: A2.<x,y> = AffineSpace(QQ, 2) sage: P2.<x0,x1,x2> = ProjectiveSpace(QQ, 2) sage: f = A2.hom([x*y, y, x], P2) - sage: f.indeterminacy_points() + sage: f.indeterminacy_points() # needs sage.libs.singular [(0, 0)] """ @@ -1301,6 +1315,7 @@ def image(self): EXAMPLES:: + sage: # needs sage.libs.singular sage: A1.<w> = AffineSpace(QQ, 1) sage: A2.<x,y> = AffineSpace(QQ, 2) sage: f = A2.hom([x + y], A1) @@ -1323,7 +1338,7 @@ def image(self): """ X = self.domain().subscheme(0) e = X.embedding_morphism() - return (self*e).image() + return (self * e).image() class SchemeMorphism_polynomial_affine_space_finite_field(SchemeMorphism_polynomial_affine_space_field): @@ -1336,7 +1351,7 @@ def _fast_eval(self, x): sage: P.<x,y,z> = AffineSpace(GF(7), 3) sage: H = Hom(P, P) - sage: f = H([x^2+y^2,y^2, z^2 + y*z]) + sage: f = H([x^2 + y^2,y ^2, z^2 + y*z]) sage: f._fast_eval([1, 1, 1]) [2, 1, 2] @@ -1349,7 +1364,7 @@ def _fast_eval(self, x): [1, 1, 2] """ R = self.domain().ambient_space().coordinate_ring() - P=[] + P = [] for i in range(len(self._fastpolys[0])): r = self._fastpolys[0][i](*x) if self._fastpolys[1][i] is R.one(): @@ -1363,7 +1378,7 @@ def _fast_eval(self, x): p = self.base_ring().characteristic() r = Integer(r) % p s = Integer(s) % p - P.append(r/s) + P.append(r / s) return P @@ -1381,45 +1396,43 @@ def representatives(self): sage: A2.<x,y> = AffineSpace(QQ, 2) sage: X = A2.subscheme(0) sage: f = X.hom([x, x/y], A2) - sage: f.representatives() + sage: f.representatives() # needs sage.libs.singular [Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - 0 + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: 0 To: Affine Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (x, x/y)] + Defn: Defined on coordinates by sending (x, y) to (x, x/y)] :: + sage: # needs sage.libs.singular sage: A2.<x,y> = AffineSpace(QQ, 2) sage: A1.<a> = AffineSpace(QQ, 1) sage: X = A2.subscheme([x^2 - y^2 - y]) sage: f = X.hom([x/y], A1) sage: f.representatives() [Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x^2 - y^2 - y To: Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (x/y), Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y + Defn: Defined on coordinates by sending (x, y) to (x/y), + Scheme morphism: + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x^2 - y^2 - y To: Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - ((y + 1)/x)] + Defn: Defined on coordinates by sending (x, y) to ((y + 1)/x)] sage: g = _[1] sage: g.representatives() [Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x^2 - y^2 - y To: Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (x/y), Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y + Defn: Defined on coordinates by sending (x, y) to (x/y), + Scheme morphism: + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x^2 - y^2 - y To: Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - ((y + 1)/x)] + Defn: Defined on coordinates by sending (x, y) to ((y + 1)/x)] :: @@ -1427,18 +1440,18 @@ def representatives(self): sage: P1.<a,b> = ProjectiveSpace(QQ, 1) sage: X = A2.subscheme([x^2 - y^2 - y]) sage: f = X.hom([x, y], P1) - sage: f.representatives() + sage: f.representatives() # needs sage.libs.singular [Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x^2 - y^2 - y To: Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x, y) to - (x : y), Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y + (x : y), + Scheme morphism: + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x^2 - y^2 - y To: Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (y + 1 : x)] + Defn: Defined on coordinates by sending (x, y) to (y + 1 : x)] """ X = self.domain() Y = self.codomain() @@ -1451,7 +1464,7 @@ def representatives(self): reprs = [] for r in h.representatives(): i = X.projective_embedding(0, h.domain().ambient_space()) - reprs.append(r*i) + reprs.append(r * i) else: reprs = [] for r in h.representatives(): @@ -1473,7 +1486,7 @@ def indeterminacy_locus(self): sage: X = A2.subscheme(0) sage: A1.<x> = AffineSpace(QQ, 1) sage: f = X.hom([x1/x2], A1) - sage: f.indeterminacy_locus() + sage: f.indeterminacy_locus() # needs sage.libs.singular Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: x2 @@ -1483,17 +1496,17 @@ def indeterminacy_locus(self): sage: X = A2.subscheme(0) sage: P1.<a,b> = ProjectiveSpace(QQ, 1) sage: f = X.hom([x1,x2], P1) - sage: L = f.indeterminacy_locus() - sage: L.rational_points() + sage: L = f.indeterminacy_locus() # needs sage.libs.singular + sage: L.rational_points() # needs sage.libs.singular [(0, 0)] :: sage: A2.<x,y> = AffineSpace(QQ, 2) sage: X = A2.subscheme([x^2 - y^2 - y]) - sage: A1.<a> = AffineSpace(QQ,1) + sage: A1.<a> = AffineSpace(QQ, 1) sage: f = X.hom([x/y], A1) - sage: f.indeterminacy_locus() + sage: f.indeterminacy_locus() # needs sage.libs.singular Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: y, x @@ -1504,12 +1517,11 @@ def indeterminacy_locus(self): sage: X = A3.subscheme(x^2 - y*z - x) sage: A2.<a,b> = AffineSpace(QQ, 2) sage: f = X.hom([y, y/x], A2) - sage: L = f.indeterminacy_locus() - sage: L + sage: L = f.indeterminacy_locus(); L # needs sage.libs.singular Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: x, y*z - sage: L.dimension() + sage: L.dimension() # needs sage.libs.singular 1 """ @@ -1537,7 +1549,7 @@ def is_morphism(self): sage: P1.<a,b> = ProjectiveSpace(QQ,1) sage: X = P2.subscheme([x^2 - y^2 - y*z]) sage: f = X.hom([x,y], P1) - sage: f.is_morphism() + sage: f.is_morphism() # needs sage.libs.singular True """ return self.indeterminacy_locus().dimension() < 0 @@ -1554,7 +1566,7 @@ def image(self): sage: A2.<x,y> = AffineSpace(QQ, 2) sage: X = A2.subscheme(0) sage: f = X.hom([x + y], A1) - sage: f.image() + sage: f.image() # needs sage.libs.singular Closed subscheme of Affine Space of dimension 1 over Rational Field defined by: (no polynomials) @@ -1563,7 +1575,7 @@ def image(self): sage: A2.<x,y> = AffineSpace(QQ, 2) sage: X = A2.subscheme([x*y^2 - y^3 - 1]) sage: f = X.hom([y, y/x], A2) - sage: f.image() + sage: f.image() # needs sage.libs.singular Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: -x^3*y + x^3 - y """ @@ -1573,5 +1585,5 @@ def image(self): return self.homogenize(0).image() e = Y.projective_embedding(0) - h = (e*self).homogenize(0) + h = (e * self).homogenize(0) return h.image().affine_patch(0, Y.ambient_space()) diff --git a/src/sage/schemes/affine/affine_point.py b/src/sage/schemes/affine/affine_point.py index d7d50b2d064..a665ba6881a 100644 --- a/src/sage/schemes/affine/affine_point.py +++ b/src/sage/schemes/affine/affine_point.py @@ -18,7 +18,7 @@ # * _point_morphism_class -> _morphism # * _homset_class -> _point_homset -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Volker Braun <vbraun.name@gmail.com> # Copyright (C) 2006 David Kohel <kohel@maths.usyd.edu.au> # Copyright (C) 2006 William Stein <wstein@gmail.com> @@ -26,17 +26,19 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.categories.number_fields import NumberFields -_NumberFields = NumberFields() from sage.rings.integer_ring import ZZ from sage.rings.number_field.order import is_NumberFieldOrder from sage.rings.real_mpfr import RealField from sage.schemes.generic.morphism import (SchemeMorphism_point, SchemeMorphism, is_SchemeMorphism) from sage.structure.sequence import Sequence +_NumberFields = NumberFields() + + ############################################################################ # Rational points on schemes, which we view as morphisms determined # by coordinates. @@ -88,9 +90,9 @@ def __init__(self, X, v, check=True): # Verify that there are the right number of coords d = self.codomain().ambient_space().ngens() if len(v) != d: - raise TypeError("argument v (=%s) must have %s coordinates"%(v, d)) + raise TypeError("argument v (=%s) must have %s coordinates" % (v, d)) if not isinstance(v, (list, tuple)): - raise TypeError("argument v (= %s) must be a scheme point, list, or tuple"%str(v)) + raise TypeError("argument v (= %s) must be a scheme point, list, or tuple" % str(v)) # Make sure the coordinates all lie in the appropriate ring v = Sequence(v, X.value_ring()) # Verify that the point satisfies the equations of X. @@ -113,16 +115,16 @@ def _matrix_times_point_(self, mat, dom): sage: P = AffineSpace(QQ,2) sage: Q = P(1,2) - sage: m = matrix(ZZ, 3, 3, [0,1,1,0,0,1,1,1,1]) - sage: m*Q + sage: m = matrix(ZZ, 3, 3, [0,1,1,0,0,1,1,1,1]) # needs sage.modules + sage: m*Q # needs sage.modules (3/4, 1/4) :: sage: P = AffineSpace(QQ,1) sage: Q = P(0) - sage: m = matrix(RR, 2, 2, [0,1,1,0]) - sage: m*Q + sage: m = matrix(RR, 2, 2, [0,1,1,0]) # needs sage.modules + sage: m*Q # needs sage.modules Traceback (most recent call last): ... ValueError: resulting point not affine @@ -131,15 +133,15 @@ def _matrix_times_point_(self, mat, dom): sage: P = AffineSpace(QQ,2) sage: Q = P(1,1) - sage: m = matrix(RR, 2, 2, [0,1,1,0]) - sage: m*Q + sage: m = matrix(RR, 2, 2, [0,1,1,0]) # needs sage.modules + sage: m*Q # needs sage.modules Traceback (most recent call last): ... ValueError: matrix size is incompatible """ - #input checking done in projective implementation + # input checking done in projective implementation d = self.codomain().ngens() - P = mat*self.homogenize(d) + P = mat * self.homogenize(d) if P[-1] == 0: raise ValueError("resulting point not affine") return P.dehomogenize(d) @@ -156,9 +158,9 @@ def __hash__(self): :: - sage: A.<x,y,z> = AffineSpace(CC, 3) - sage: pt = A([1, 2, -i]) - sage: hash(pt) == hash(tuple(pt)) + sage: A.<x,y,z> = AffineSpace(CC, 3) # needs sage.rings.real_mpfr + sage: pt = A([1, 2, -i]) # needs sage.rings.real_mpfr sage.symbolic + sage: hash(pt) == hash(tuple(pt)) # needs sage.rings.real_mpfr sage.symbolic True """ @@ -181,22 +183,22 @@ def global_height(self, prec=None): sage: P.<x,y> = AffineSpace(QQ, 2) sage: Q = P(41, 1/12) - sage: Q.global_height() + sage: Q.global_height() # needs sage.rings.real_mpfr 3.71357206670431 :: sage: P = AffineSpace(ZZ, 4, 'x') sage: Q = P(3, 17, -51, 5) - sage: Q.global_height() + sage: Q.global_height() # needs sage.rings.real_mpfr 3.93182563272433 :: sage: R.<x> = PolynomialRing(QQ) - sage: k.<w> = NumberField(x^2+5) - sage: A = AffineSpace(k, 2, 'z') - sage: A([3, 5*w+1]).global_height(prec=100) + sage: k.<w> = NumberField(x^2 + 5) # needs sage.rings.number_field + sage: A = AffineSpace(k, 2, 'z') # needs sage.rings.number_field + sage: A([3, 5*w + 1]).global_height(prec=100) # needs sage.rings.number_field sage.rings.real_mpfr 2.4181409534757389986565376694 .. TODO:: @@ -209,7 +211,7 @@ def global_height(self, prec=None): else: R = RealField(prec) H = max([self[i].abs() for i in range(self.codomain().ambient_space().dimension_relative())]) - return R(max(H,1)).log() + return R(max(H, 1)).log() if self.domain().base_ring() in _NumberFields or is_NumberFieldOrder(self.domain().base_ring()): return max([self[i].global_height(prec) for i in range(self.codomain().ambient_space().dimension_relative())]) else: @@ -289,8 +291,9 @@ def weil_restriction(self): EXAMPLES:: + sage: # needs sage.libs.singular sage.rings.finite_rings sage: A.<x,y,z> = AffineSpace(GF(5^3, 't'), 3) - sage: X = A.subscheme([y^2-x*z, z^2+y]) + sage: X = A.subscheme([y^2 - x*z, z^2 + y]) sage: Y = X.weil_restriction() sage: P = X([1, -1, 1]) sage: Q = P.weil_restriction();Q @@ -300,12 +303,13 @@ def weil_restriction(self): :: + sage: # needs sage.libs.singular sage.rings.number_field sage: R.<x> = QQ[] - sage: K.<w> = NumberField(x^5-2) + sage: K.<w> = NumberField(x^5 - 2) sage: R.<x> = K[] - sage: L.<v> = K.extension(x^2+w) + sage: L.<v> = K.extension(x^2 + w) sage: A.<x,y> = AffineSpace(L, 2) - sage: P = A([w^3-v,1+w+w*v]) + sage: P = A([w^3 - v, 1 + w + w*v]) sage: P.weil_restriction() (w^3, -1, w + 1, w) """ @@ -318,20 +322,20 @@ def weil_restriction(self): newP = [] for t in self: c = t.polynomial().coefficients(sparse=False) - c = c + (d-len(c))*[0] + c = c + (d - len(c)) * [0] newP += c else: d = L.relative_degree() if d == 1: return self - #create a CoordinateFunction that gets the relative coordinates in terms of powers + # create a CoordinateFunction that gets the relative coordinates in terms of powers from sage.rings.number_field.number_field_element import CoordinateFunction v = L.gen() V, from_V, to_V = L.relative_vector_space() h = L(1) B = [to_V(h)] f = v.minpoly() - for i in range(f.degree()-1): + for i in range(f.degree() - 1): h *= v B.append(to_V(h)) W = V.span_of_basis(B) @@ -356,6 +360,7 @@ def intersection_multiplicity(self, X): EXAMPLES:: + sage: # needs sage.libs.singular sage: A.<x,y> = AffineSpace(GF(17), 2) sage: X = A.subscheme([y^2 - x^3 + 2*x^2 - x]) sage: Y = A.subscheme([y - 2*x + 2]) @@ -395,10 +400,10 @@ def multiplicity(self): sage: A.<x,y,z> = AffineSpace(QQ, 3) sage: X = A.subscheme([y^2 - x^7*z]) sage: Q1 = X([1,1,1]) - sage: Q1.multiplicity() + sage: Q1.multiplicity() # needs sage.libs.singular 1 sage: Q2 = X([0,0,2]) - sage: Q2.multiplicity() + sage: Q2.multiplicity() # needs sage.libs.singular 2 """ from sage.schemes.affine.affine_space import is_AffineSpace @@ -406,6 +411,7 @@ def multiplicity(self): raise TypeError("this point must be a point on an affine subscheme") return self.codomain().multiplicity(self) + class SchemeMorphism_point_affine_finite_field(SchemeMorphism_point_affine_field): def __hash__(self): @@ -423,7 +429,7 @@ def __hash__(self): :: sage: P.<x,y,z> = AffineSpace(GF(7), 3) - sage: X = P.subscheme(x^2-y^2) + sage: X = P.subscheme(x^2 - y^2) sage: hash(X(1, 1, 2)) 106 @@ -435,10 +441,10 @@ def __hash__(self): :: - sage: P.<x,y> = AffineSpace(GF(13^3, 't'), 2) - sage: hash(P(3, 4)) + sage: P.<x,y> = AffineSpace(GF(13^3, 't'), 2) # needs sage.rings.finite_rings + sage: hash(P(3, 4)) # needs sage.rings.finite_rings 8791 """ p = self.codomain().base_ring().order() N = self.codomain().ambient_space().dimension_relative() - return int(sum(hash(self[i])*p**i for i in range(N))) + return int(sum(hash(self[i]) * p**i for i in range(N))) diff --git a/src/sage/schemes/affine/affine_rational_point.py b/src/sage/schemes/affine/affine_rational_point.py index 73a4c7d0ba6..4ac17a60d79 100644 --- a/src/sage/schemes/affine/affine_rational_point.py +++ b/src/sage/schemes/affine/affine_rational_point.py @@ -17,7 +17,7 @@ sage: from sage.schemes.affine.affine_rational_point import enum_affine_rational_field sage: A.<x,y,z> = AffineSpace(3, QQ) - sage: S = A.subscheme([2*x-3*y]) + sage: S = A.subscheme([2*x - 3*y]) sage: enum_affine_rational_field(S, 2) [(0, 0, -2), (0, 0, -1), (0, 0, -1/2), (0, 0, 0), (0, 0, 1/2), (0, 0, 1), (0, 0, 2)] @@ -41,19 +41,19 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 William Stein, David Kohel, John Cremona, Charlie Turner # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** +from itertools import product from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.misc.mrange import cartesian_product_iterator from sage.schemes.generic.scheme import is_Scheme @@ -77,15 +77,15 @@ def enum_affine_rational_field(X, B): sage: from sage.schemes.affine.affine_rational_point import enum_affine_rational_field sage: enum_affine_rational_field(A(QQ), 1) [(-1, -1, -1), (-1, -1, 0), (-1, -1, 1), (-1, 0, -1), (-1, 0, 0), (-1, 0, 1), - (-1, 1, -1), (-1, 1, 0), (-1, 1, 1), (0, -1, -1), (0, -1, 0), (0, -1, 1), - (0, 0, -1), (0, 0, 0), (0, 0, 1), (0, 1, -1), (0, 1, 0), (0, 1, 1), (1, -1, -1), - (1, -1, 0), (1, -1, 1), (1, 0, -1), (1, 0, 0), (1, 0, 1), (1, 1, -1), (1, 1, 0), - (1, 1, 1)] + (-1, 1, -1), (-1, 1, 0), (-1, 1, 1), (0, -1, -1), (0, -1, 0), (0, -1, 1), + (0, 0, -1), (0, 0, 0), (0, 0, 1), (0, 1, -1), (0, 1, 0), (0, 1, 1), (1, -1, -1), + (1, -1, 0), (1, -1, 1), (1, 0, -1), (1, 0, 0), (1, 0, 1), (1, 1, -1), (1, 1, 0), + (1, 1, 1)] :: sage: A.<w,x,y,z> = AffineSpace(4, QQ) - sage: S = A.subscheme([x^2-y*z+1, w^3+z+y^2]) + sage: S = A.subscheme([x^2 - y*z + 1, w^3 + z + y^2]) sage: enum_affine_rational_field(S(QQ), 1) [(0, 0, -1, -1)] sage: enum_affine_rational_field(S(QQ), 2) @@ -94,11 +94,11 @@ def enum_affine_rational_field(X, B): :: sage: A.<x,y> = AffineSpace(2, QQ) - sage: C = Curve(x^2+y-x) - sage: enum_affine_rational_field(C, 10) # long time (3 s) + sage: C = Curve(x^2 + y - x) # needs sage.libs.singular + sage: enum_affine_rational_field(C, 10) # long time (3 s) # needs sage.libs.singular [(-2, -6), (-1, -2), (-2/3, -10/9), (-1/2, -3/4), (-1/3, -4/9), - (0, 0), (1/3, 2/9), (1/2, 1/4), (2/3, 2/9), (1, 0), - (4/3, -4/9), (3/2, -3/4), (5/3, -10/9), (2, -2), (3, -6)] + (0, 0), (1/3, 2/9), (1/2, 1/4), (2/3, 2/9), (1, 0), + (4/3, -4/9), (3/2, -3/4), (5/3, -10/9), (2, -2), (3, -6)] AUTHORS: @@ -119,10 +119,10 @@ def enum_affine_rational_field(X, B): n = X.codomain().ambient_space().ngens() VR = X.value_ring() if VR is ZZ: - R = [ 0 ] + [ s*k for k in range(1, B+1) for s in [1, -1] ] - iters = [ iter(R) for _ in range(n) ] + R = [0] + [s * k for k in range(1, B + 1) for s in [1, -1]] + iters = [iter(R) for _ in range(n)] else: # rational field - iters = [ QQ.range_by_height(B + 1) for _ in range(n) ] + iters = [QQ.range_by_height(B + 1) for _ in range(n)] pts = [] P = [0] * n try: @@ -141,7 +141,7 @@ def enum_affine_rational_field(X, B): iters[i] = iter(R) else: # rational field iters[i] = QQ.range_by_height(B + 1) - P[i] = next(iters[i]) # reset P[i] to 0 and increment + P[i] = next(iters[i]) # reset P[i] to 0 and increment i += 1 continue P[i] = a @@ -183,31 +183,34 @@ def enum_affine_number_field(X, **kwds): OUTPUT: - - a list containing the affine points of ``X`` of absolute height up to ``B``, - sorted. + - a list containing the affine points of ``X`` of absolute height up to ``B``, + sorted. EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.affine.affine_rational_point import enum_affine_number_field sage: u = QQ['u'].0 sage: K = NumberField(u^2 + 2, 'v') sage: A.<x,y,z> = AffineSpace(K, 3) sage: X = A.subscheme([y^2 - x]) sage: enum_affine_number_field(X(K), bound=2**0.5) - [(0, 0, -1), (0, 0, -v), (0, 0, -1/2*v), (0, 0, 0), (0, 0, 1/2*v), (0, 0, v), (0, 0, 1), - (1, -1, -1), (1, -1, -v), (1, -1, -1/2*v), (1, -1, 0), (1, -1, 1/2*v), (1, -1, v), (1, -1, 1), - (1, 1, -1), (1, 1, -v), (1, 1, -1/2*v), (1, 1, 0), (1, 1, 1/2*v), (1, 1, v), (1, 1, 1)] + [(0, 0, -1), (0, 0, -v), (0, 0, -1/2*v), (0, 0, 0), (0, 0, 1/2*v), + (0, 0, v), (0, 0, 1), (1, -1, -1), (1, -1, -v), (1, -1, -1/2*v), + (1, -1, 0), (1, -1, 1/2*v), (1, -1, v), (1, -1, 1), (1, 1, -1), + (1, 1, -v), (1, 1, -1/2*v), (1, 1, 0), (1, 1, 1/2*v), (1, 1, v), (1, 1, 1)] :: + sage: # needs sage.rings.number_field + sage: from sage.schemes.affine.affine_rational_point import enum_affine_number_field sage: u = QQ['u'].0 sage: K = NumberField(u^2 + 3, 'v') sage: A.<x,y> = AffineSpace(K, 2) - sage: X=A.subscheme(x-y) - sage: from sage.schemes.affine.affine_rational_point import enum_affine_number_field + sage: X = A.subscheme(x - y) sage: enum_affine_number_field(X, bound=3**0.25) - [(-1, -1), (-1/2*v - 1/2, -1/2*v - 1/2), (1/2*v - 1/2, 1/2*v - 1/2), (0, 0), (-1/2*v + 1/2, -1/2*v + 1/2), - (1/2*v + 1/2, 1/2*v + 1/2), (1, 1)] + [(-1, -1), (-1/2*v - 1/2, -1/2*v - 1/2), (1/2*v - 1/2, 1/2*v - 1/2), + (0, 0), (-1/2*v + 1/2, -1/2*v + 1/2), (1/2*v + 1/2, 1/2*v + 1/2), (1, 1)] """ B = kwds.pop('bound') tol = kwds.pop('tolerance', 1e-2) @@ -248,31 +251,31 @@ def enum_affine_finite_field(X): EXAMPLES:: + sage: from sage.schemes.affine.affine_rational_point import enum_affine_finite_field sage: F = GF(7) sage: A.<w,x,y,z> = AffineSpace(4, F) - sage: C = A.subscheme([w^2+x+4, y*z*x-6, z*y+w*x]) - sage: from sage.schemes.affine.affine_rational_point import enum_affine_finite_field + sage: C = A.subscheme([w^2 + x + 4, y*z*x - 6, z*y + w*x]) sage: enum_affine_finite_field(C(F)) [] - sage: C = A.subscheme([w^2+x+4, y*z*x-6]) + sage: C = A.subscheme([w^2 + x + 4, y*z*x - 6]) sage: enum_affine_finite_field(C(F)) [(0, 3, 1, 2), (0, 3, 2, 1), (0, 3, 3, 3), (0, 3, 4, 4), (0, 3, 5, 6), - (0, 3, 6, 5), (1, 2, 1, 3), (1, 2, 2, 5), (1, 2, 3, 1), (1, 2, 4, 6), - (1, 2, 5, 2), (1, 2, 6, 4), (2, 6, 1, 1), (2, 6, 2, 4), (2, 6, 3, 5), - (2, 6, 4, 2), (2, 6, 5, 3), (2, 6, 6, 6), (3, 1, 1, 6), (3, 1, 2, 3), - (3, 1, 3, 2), (3, 1, 4, 5), (3, 1, 5, 4), (3, 1, 6, 1), (4, 1, 1, 6), - (4, 1, 2, 3), (4, 1, 3, 2), (4, 1, 4, 5), (4, 1, 5, 4), (4, 1, 6, 1), - (5, 6, 1, 1), (5, 6, 2, 4), (5, 6, 3, 5), (5, 6, 4, 2), (5, 6, 5, 3), - (5, 6, 6, 6), (6, 2, 1, 3), (6, 2, 2, 5), (6, 2, 3, 1), (6, 2, 4, 6), - (6, 2, 5, 2), (6, 2, 6, 4)] + (0, 3, 6, 5), (1, 2, 1, 3), (1, 2, 2, 5), (1, 2, 3, 1), (1, 2, 4, 6), + (1, 2, 5, 2), (1, 2, 6, 4), (2, 6, 1, 1), (2, 6, 2, 4), (2, 6, 3, 5), + (2, 6, 4, 2), (2, 6, 5, 3), (2, 6, 6, 6), (3, 1, 1, 6), (3, 1, 2, 3), + (3, 1, 3, 2), (3, 1, 4, 5), (3, 1, 5, 4), (3, 1, 6, 1), (4, 1, 1, 6), + (4, 1, 2, 3), (4, 1, 3, 2), (4, 1, 4, 5), (4, 1, 5, 4), (4, 1, 6, 1), + (5, 6, 1, 1), (5, 6, 2, 4), (5, 6, 3, 5), (5, 6, 4, 2), (5, 6, 5, 3), + (5, 6, 6, 6), (6, 2, 1, 3), (6, 2, 2, 5), (6, 2, 3, 1), (6, 2, 4, 6), + (6, 2, 5, 2), (6, 2, 6, 4)] :: sage: A.<x,y,z> = AffineSpace(3, GF(3)) - sage: S = A.subscheme(x+y) + sage: S = A.subscheme(x + y) sage: enum_affine_finite_field(S) [(0, 0, 0), (0, 0, 1), (0, 0, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), - (2, 1, 0), (2, 1, 1), (2, 1, 2)] + (2, 1, 0), (2, 1, 1), (2, 1, 2)] ALGORITHM: @@ -297,7 +300,7 @@ def enum_affine_finite_field(X): n = X.codomain().ambient_space().ngens() F = X.value_ring() pts = [] - for c in cartesian_product_iterator([F]*n): + for c in product(*([F] * n)): try: pts.append(X(c)) except Exception: diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py index ba56ef9fc8d..42de0a0ec16 100644 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -9,6 +9,7 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +from itertools import product from sage.functions.orthogonal_polys import chebyshev_T, chebyshev_U from sage.rings.integer import Integer @@ -17,13 +18,11 @@ from sage.rings.rational_field import is_RationalField from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.categories.map import Map from sage.categories.fields import Fields -from sage.categories.homset import Hom from sage.categories.number_fields import NumberFields from sage.misc.latex import latex -from sage.misc.mrange import cartesian_product_iterator from sage.matrix.constructor import matrix from sage.structure.category_object import normalize_names from sage.schemes.generic.scheme import AffineScheme @@ -36,10 +35,12 @@ from sage.schemes.affine.affine_point import (SchemeMorphism_point_affine, SchemeMorphism_point_affine_field, SchemeMorphism_point_affine_finite_field) +from sage.misc.persist import register_unpickle_override _Fields = Fields() -def is_AffineSpace(x): + +def is_AffineSpace(x) -> bool: r""" Return ``True`` if ``x`` is an affine space. @@ -48,13 +49,14 @@ def is_AffineSpace(x): sage: from sage.schemes.affine.affine_space import is_AffineSpace sage: is_AffineSpace(AffineSpace(5, names='x')) True - sage: is_AffineSpace(AffineSpace(5, GF(9, 'alpha'), names='x')) + sage: is_AffineSpace(AffineSpace(5, GF(9, 'alpha'), names='x')) # needs sage.rings.finite_rings True sage: is_AffineSpace(Spec(ZZ)) False """ return isinstance(x, AffineSpace_generic) + def AffineSpace(n, R=None, names=None, ambient_projective_space=None, default_embedding_index=None): r""" @@ -93,18 +95,16 @@ def AffineSpace(n, R=None, names=None, ambient_projective_space=None, TESTS:: - sage: R.<w> = QQ[] - sage: A.<w> = AffineSpace(R) - sage: A.gens() == R.gens() - True - - :: + sage: R.<w> = QQ[] + sage: A.<w> = AffineSpace(R) + sage: A.gens() == R.gens() + True - sage: R.<x> = QQ[] - sage: A.<z> = AffineSpace(R) - Traceback (most recent call last): - ... - NameError: variable names passed to AffineSpace conflict with names in ring + sage: R.<x> = QQ[] + sage: A.<z> = AffineSpace(R) + Traceback (most recent call last): + ... + NameError: variable names passed to AffineSpace conflict with names in ring """ if (is_MPolynomialRing(n) or is_PolynomialRing(n)) and R is None: R = n @@ -132,7 +132,7 @@ def AffineSpace(n, R=None, names=None, ambient_projective_space=None, from sage.schemes.projective.projective_space import ProjectiveSpace ambient_projective_space = ProjectiveSpace(n, R) if R in _Fields: - if is_FiniteField(R): + if isinstance(R, FiniteField): return AffineSpace_finite_field(n, R, names, ambient_projective_space, default_embedding_index) else: @@ -170,10 +170,10 @@ class AffineSpace_generic(AmbientSpace, AffineScheme): sage: AffineSpace(5, PolynomialRing(QQ, 'z'), 'Z') Affine Space of dimension 5 over Univariate Polynomial Ring in z over Rational Field - sage: AffineSpace(RealField(), 3, 'Z') + sage: AffineSpace(RealField(), 3, 'Z') # needs sage.rings.real_mpfr Affine Space of dimension 3 over Real Field with 53 bits of precision - sage: AffineSpace(Qp(7), 2, 'x') + sage: AffineSpace(Qp(7), 2, 'x') # needs sage.rings.padics Affine Space of dimension 2 over 7-adic Field with capped relative precision 20 Even 0-dimensional affine spaces are supported:: @@ -185,7 +185,7 @@ def __init__(self, n, R, names, ambient_projective_space, default_embedding_inde """ EXAMPLES:: - sage: AffineSpace(3, Zp(5), 'y') + sage: AffineSpace(3, Zp(5), 'y') # needs sage.rings.padics Affine Space of dimension 3 over 5-adic Ring with capped relative precision 20 """ AmbientSpace.__init__(self, n, R) @@ -225,7 +225,7 @@ def __iter__(self): AHom = self.point_homset() C = AHom.codomain() - for v in cartesian_product_iterator([R for _ in range(n)]): + for v in product(*[R for _ in range(n)]): yield C._point(AHom, v, check=False) def ngens(self): @@ -252,7 +252,7 @@ def rational_points(self, F=None): sage: A = AffineSpace(1, GF(3)) sage: A.rational_points() [(0), (1), (2)] - sage: A.rational_points(GF(3^2, 'b')) + sage: A.rational_points(GF(3^2, 'b')) # needs sage.rings.finite_rings [(0), (b), (b + 1), (2*b + 1), (2), (2*b), (2*b + 2), (b + 2), (1)] sage: AffineSpace(2, ZZ).rational_points(GF(2)) @@ -270,12 +270,12 @@ def rational_points(self, F=None): TypeError: second argument (= Integer Ring) must be a finite field """ if F is None: - if not is_FiniteField(self.base_ring()): - raise TypeError("base ring (= %s) must be a finite field"%self.base_ring()) - return [ P for P in self ] - elif not is_FiniteField(F): - raise TypeError("second argument (= %s) must be a finite field"%F) - return [ P for P in self.base_extend(F) ] + if not isinstance(self.base_ring(), FiniteField): + raise TypeError("base ring (= %s) must be a finite field" % self.base_ring()) + return [P for P in self] + elif not isinstance(F, FiniteField): + raise TypeError("second argument (= %s) must be a finite field" % F) + return [P for P in self.base_extend(F)] def __eq__(self, right): """ @@ -315,9 +315,9 @@ def __hash__(self): EXAMPLES:: - sage: hash(AffineSpace(QQ,3,'a')) == hash(AffineSpace(ZZ,3,'a')) + sage: hash(AffineSpace(QQ, 3, 'a')) == hash(AffineSpace(ZZ, 3, 'a')) False - sage: hash(AffineSpace(ZZ,1,'a')) == hash(AffineSpace(ZZ,0,'a')) + sage: hash(AffineSpace(ZZ, 1, 'a')) == hash(AffineSpace(ZZ, 0, 'a')) False """ return hash((self.dimension_relative(), self.coordinate_ring())) @@ -333,10 +333,10 @@ def _latex_(self): TESTS:: - sage: AffineSpace(3, Zp(5), 'y')._latex_() + sage: AffineSpace(3, Zp(5), 'y')._latex_() # needs sage.rings.padics '\\mathbf{A}_{\\Bold{Z}_{5}}^3' """ - return "\\mathbf{A}_{%s}^%s"%(latex(self.base_ring()), self.dimension_relative()) + return "\\mathbf{A}_{%s}^%s" % (latex(self.base_ring()), self.dimension_relative()) def _morphism(self, *args, **kwds): """ @@ -434,10 +434,10 @@ def _repr_(self): TESTS:: - sage: AffineSpace(3, Zp(5), 'y')._repr_() + sage: AffineSpace(3, Zp(5), 'y')._repr_() # needs sage.rings.padics 'Affine Space of dimension 3 over 5-adic Ring with capped relative precision 20' """ - return "Affine Space of dimension %s over %s"%(self.dimension_relative(), self.base_ring()) + return "Affine Space of dimension %s over %s" % (self.dimension_relative(), self.base_ring()) def _repr_generic_point(self, polys=None): """ @@ -450,7 +450,7 @@ def _repr_generic_point(self, polys=None): EXAMPLES:: sage: A.<x, y> = AffineSpace(2, ZZ) - sage: A._repr_generic_point([y-x^2]) + sage: A._repr_generic_point([y - x^2]) '(-x^2 + y)' sage: A._repr_generic_point() '(x, y)' @@ -470,7 +470,7 @@ def _latex_generic_point(self, v=None): EXAMPLES:: sage: A.<x, y> = AffineSpace(2, ZZ) - sage: A._latex_generic_point([y-x^2]) + sage: A._latex_generic_point([y - x^2]) '\\left(-x^{2} + y\\right)' sage: A._latex_generic_point() '\\left(x, y\\right)' @@ -481,8 +481,8 @@ def _latex_generic_point(self, v=None): def _check_satisfies_equations(self, v): """ - Return True if ``v`` defines a point on the scheme self; raise a - TypeError otherwise. + Return ``True`` if ``v`` defines a point on the scheme ``self``; raise a + :class:`TypeError` otherwise. EXAMPLES:: @@ -507,14 +507,14 @@ def _check_satisfies_equations(self, v): TypeError: the argument v=5 must be a list or tuple """ if not isinstance(v, (list, tuple)): - raise TypeError('the argument v=%s must be a list or tuple'%v) + raise TypeError('the argument v=%s must be a list or tuple' % v) n = self.ngens() if not len(v) == n: - raise TypeError('the list v=%s must have %s components'%(v, n)) + raise TypeError('the list v=%s must have %s components' % (v, n)) R = self.base_ring() from sage.structure.sequence import Sequence if not Sequence(v).universe() == R: - raise TypeError('the components of v=%s must be elements of %s'%(v, R)) + raise TypeError('the components of v=%s must be elements of %s' % (v, R)) return True def __pow__(self, m): @@ -598,18 +598,19 @@ def __mul__(self, right): if isinstance(right, AffineSpace_generic): if self is right: return self.__pow__(2) - return AffineSpace(self.dimension_relative() + right.dimension_relative(),\ + return AffineSpace(self.dimension_relative() + right.dimension_relative(), self.base_ring(), self.variable_names() + right.variable_names()) - elif isinstance(right, AlgebraicScheme_subscheme): - AS = self*right.ambient_space() + if isinstance(right, AlgebraicScheme_subscheme): + AS = self * right.ambient_space() CR = AS.coordinate_ring() n = self.ambient_space().coordinate_ring().ngens() phi = self.ambient_space().coordinate_ring().hom(list(CR.gens()[:n]), CR) psi = right.ambient_space().coordinate_ring().hom(list(CR.gens()[n:]), CR) - return AS.subscheme([phi(t) for t in self.defining_polynomials()] + [psi(t) for t in right.defining_polynomials()]) - else: - raise TypeError('%s must be an affine space or affine subscheme'%right) + return AS.subscheme([phi(t) for t in self.defining_polynomials()] + + [psi(t) for t in right.defining_polynomials()]) + + raise TypeError('%s must be an affine space or affine subscheme' % right) def change_ring(self, R): r""" @@ -619,13 +620,11 @@ def change_ring(self, R): - ``R`` -- commutative ring or morphism. - OUTPUT: - - - affine space over ``R``. + OUTPUT: An affine space over ``R``. .. NOTE:: - There is no need to have any relation between `R` and the base ring + There is no need to have any relation between ``R`` and the base ring of this space, if you want to have such a relation, use ``self.base_extend(R)`` instead. @@ -639,9 +638,9 @@ def change_ring(self, R): :: - sage: K.<w> = QuadraticField(5) - sage: A = AffineSpace(K,2,'t') - sage: A.change_ring(K.embeddings(CC)[1]) + sage: K.<w> = QuadraticField(5) # needs sage.rings.number_field + sage: A = AffineSpace(K, 2, 't') # needs sage.rings.number_field + sage: A.change_ring(K.embeddings(CC)[1]) # needs sage.rings.number_field Affine Space of dimension 2 over Complex Field with 53 bits of precision """ if isinstance(R, Map): @@ -655,23 +654,25 @@ def coordinate_ring(self): EXAMPLES:: - sage: R = AffineSpace(2, GF(9,'alpha'), 'z').coordinate_ring(); R + sage: R = AffineSpace(2, GF(9,'alpha'), 'z').coordinate_ring(); R # needs sage.rings.finite_rings Multivariate Polynomial Ring in z0, z1 over Finite Field in alpha of size 3^2 - sage: AffineSpace(3, R, 'x').coordinate_ring() + sage: AffineSpace(3, R, 'x').coordinate_ring() # needs sage.rings.finite_rings Multivariate Polynomial Ring in x0, x1, x2 over Multivariate Polynomial Ring in z0, z1 over Finite Field in alpha of size 3^2 """ try: return self._coordinate_ring except AttributeError: - self._coordinate_ring = PolynomialRing(self.base_ring(), - self.dimension_relative(), names=self.variable_names()) - return self._coordinate_ring + pass + self._coordinate_ring = PolynomialRing(self.base_ring(), + self.dimension_relative(), + names=self.variable_names()) + return self._coordinate_ring def _validate(self, polynomials): """ If ``polynomials`` is a tuple of valid polynomial functions on the affine space, - return ``polynomials``, otherwise raise TypeError. + return ``polynomials``, otherwise raise :class:`TypeError`. Since this is an affine space, all polynomials are valid. @@ -716,8 +717,7 @@ def projective_embedding(self, i=None, PP=None): Scheme morphism: From: Affine Space of dimension 2 over Rational Field To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x0, x1) to - (1 : x0 : x1) + Defn: Defined on coordinates by sending (x0, x1) to (1 : x0 : x1) sage: z = AA(3, 4) sage: pi(z) (1/4 : 3/4 : 1) @@ -727,8 +727,7 @@ def projective_embedding(self, i=None, PP=None): Scheme morphism: From: Affine Space of dimension 2 over Rational Field To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x0, x1) to - (x0 : 1 : x1) + Defn: Defined on coordinates by sending (x0, x1) to (x0 : 1 : x1) sage: pi(z) (3/4 : 1/4 : 1) sage: pi = AA.projective_embedding(2) @@ -762,8 +761,8 @@ def projective_embedding(self, i=None, PP=None): try: phi = self.__projective_embedding[i] - #assume that if you've passed in a new codomain you want to override - #the existing embedding + # assume that if you've passed in a new codomain you want to override + # the existing embedding if PP is None or phi.codomain() == PP: return phi except AttributeError: @@ -771,7 +770,7 @@ def projective_embedding(self, i=None, PP=None): except KeyError: pass - #if no i-th embedding exists, we may still be here with PP==None + # if no i-th embedding exists, we may still be here with PP==None if PP is None: if self._ambient_projective_space is not None: PP = self._ambient_projective_space @@ -779,17 +778,17 @@ def projective_embedding(self, i=None, PP=None): from sage.schemes.projective.projective_space import ProjectiveSpace PP = ProjectiveSpace(n, self.base_ring()) elif PP.dimension_relative() != n: - raise ValueError("projective Space must be of dimension %s"%(n)) + raise ValueError("projective Space must be of dimension %s" % (n)) R = self.coordinate_ring() v = list(R.gens()) if i < 0 or i > n: - raise ValueError("argument i (=%s) must be between 0 and %s, inclusive"%(i,n)) + raise ValueError("argument i (=%s) must be between 0 and %s, inclusive" % (i, n)) v.insert(i, R(1)) phi = self.hom(v, PP) self.__projective_embedding[i] = phi - #make affine patch and projective embedding match - PP.affine_patch(i,self) + # make affine patch and projective embedding match + PP.affine_patch(i, self) return phi def subscheme(self, X, **kwds): @@ -811,6 +810,7 @@ def subscheme(self, X, **kwds): :: + sage: # needs sage.libs.singular sage: X.defining_polynomials () (x, y^2, x*y^2) sage: I = X.defining_ideal(); I @@ -825,10 +825,8 @@ def subscheme(self, X, **kwds): Spectrum of Rational Field sage: X.structure_morphism() Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x, - y^2, - x*y^2 + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x, y^2, x*y^2 To: Spectrum of Rational Field Defn: Structure map sage: X.dimension() @@ -844,7 +842,7 @@ def subscheme(self, X, **kwds): def _an_element_(self): r""" - Return an element of this affine space,used both for illustration and + Return an element of this affine space, used both for illustration and testing purposes. OUTPUT: a point in the affine space @@ -854,7 +852,7 @@ def _an_element_(self): sage: AffineSpace(ZZ, 2, 'x').an_element() (5, 4) - sage: AffineSpace(Qp(5), 2, 'x').an_element() + sage: AffineSpace(Qp(5), 2, 'x').an_element() # needs sage.rings.padics (5^2 + O(5^22), 4*5 + O(5^21)) """ n = self.dimension_relative() @@ -863,7 +861,7 @@ def _an_element_(self): def chebyshev_polynomial(self, n, kind='first', monic=False): """ - Generates an endomorphism of this affine line by a Chebyshev polynomial. + Generate an endomorphism of this affine line by a Chebyshev polynomial. Chebyshev polynomials are a sequence of recursively defined orthogonal polynomials. Chebyshev of the first kind are defined as `T_0(x) = 1`, @@ -886,23 +884,21 @@ def chebyshev_polynomial(self, n, kind='first', monic=False): EXAMPLES:: sage: A.<x> = AffineSpace(QQ, 1) - sage: A.chebyshev_polynomial(5, 'first') + sage: A.chebyshev_polynomial(5, 'first') # needs sage.schemes Dynamical System of Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x) to - (16*x^5 - 20*x^3 + 5*x) + Defn: Defined on coordinates by sending (x) to (16*x^5 - 20*x^3 + 5*x) :: sage: A.<x> = AffineSpace(QQ, 1) - sage: A.chebyshev_polynomial(3, 'second') + sage: A.chebyshev_polynomial(3, 'second') # needs sage.schemes Dynamical System of Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x) to - (8*x^3 - 4*x) + Defn: Defined on coordinates by sending (x) to (8*x^3 - 4*x) :: sage: A.<x> = AffineSpace(QQ, 1) - sage: A.chebyshev_polynomial(3, 2) + sage: A.chebyshev_polynomial(3, 2) # needs sage.schemes Traceback (most recent call last): ... ValueError: keyword 'kind' must have a value of either 'first' or 'second' @@ -926,19 +922,18 @@ def chebyshev_polynomial(self, n, kind='first', monic=False): :: sage: A.<x> = AffineSpace(QQ, 1) - sage: A.chebyshev_polynomial(7, monic=True) + sage: A.chebyshev_polynomial(7, monic=True) # needs sage.schemes Dynamical System of Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x) to - (x^7 - 7*x^5 + 14*x^3 - 7*x) + Defn: Defined on coordinates by sending (x) to (x^7 - 7*x^5 + 14*x^3 - 7*x) :: sage: F.<t> = FunctionField(QQ) - sage: A.<x> = AffineSpace(F,1) - sage: A.chebyshev_polynomial(4, monic=True) - Dynamical System of Affine Space of dimension 1 over Rational function field in t over Rational Field - Defn: Defined on coordinates by sending (x) to - (x^4 + (-4)*x^2 + 2) + sage: A.<x> = AffineSpace(F, 1) + sage: A.chebyshev_polynomial(4, monic=True) # needs sage.schemes + Dynamical System of Affine Space of dimension 1 + over Rational function field in t over Rational Field + Defn: Defined on coordinates by sending (x) to (x^4 + (-4)*x^2 + 2) """ if self.dimension_relative() != 1: raise TypeError("affine space must be of dimension 1") @@ -950,7 +945,7 @@ def chebyshev_polynomial(self, n, kind='first', monic=False): if monic and self.base().characteristic() != 2: f = DynamicalSystem_affine([chebyshev_T(n, self.gen(0))], domain=self) f = f.homogenize(1) - f = f.conjugate(matrix([[1/ZZ(2), 0],[0, 1]])) + f = f.conjugate(matrix([[~ZZ(2), 0], [0, 1]])) f = f.dehomogenize(1) return f return DynamicalSystem_affine([chebyshev_T(n, self.gen(0))], domain=self) @@ -958,7 +953,7 @@ def chebyshev_polynomial(self, n, kind='first', monic=False): if monic and self.base().characteristic() != 2: f = DynamicalSystem_affine([chebyshev_T(n, self.gen(0))], domain=self) f = f.homogenize(1) - f = f.conjugate(matrix([[1/ZZ(2), 0],[0, 1]])) + f = f.conjugate(matrix([[~ZZ(2), 0], [0, 1]])) f = f.dehomogenize(1) return f return DynamicalSystem_affine([chebyshev_U(n, self.gen(0))], domain=self) @@ -976,9 +971,8 @@ def origin(self): (0, 0, 0) sage: _ == A(0,0,0) True - """ - return self([0]*self.ngens()) + return self([0] * self.ngens()) class AffineSpace_field(AffineSpace_generic): @@ -1048,42 +1042,42 @@ def points_of_bounded_height(self, **kwds): sage: A.<x,y> = AffineSpace(QQ, 2) sage: list(A.points_of_bounded_height(bound=3)) [(0, 0), (1, 0), (-1, 0), (1/2, 0), (-1/2, 0), (2, 0), (-2, 0), (0, 1), - (1, 1), (-1, 1), (1/2, 1), (-1/2, 1), (2, 1), (-2, 1), (0, -1), (1, -1), - (-1, -1), (1/2, -1), (-1/2, -1), (2, -1), (-2, -1), (0, 1/2), (1, 1/2), - (-1, 1/2), (1/2, 1/2), (-1/2, 1/2), (2, 1/2), (-2, 1/2), (0, -1/2), (1, -1/2), - (-1, -1/2), (1/2, -1/2), (-1/2, -1/2), (2, -1/2), (-2, -1/2), (0, 2), (1, 2), - (-1, 2), (1/2, 2), (-1/2, 2), (2, 2), (-2, 2), (0, -2), (1, -2), (-1, -2), (1/2, -2), - (-1/2, -2), (2, -2), (-2, -2)] + (1, 1), (-1, 1), (1/2, 1), (-1/2, 1), (2, 1), (-2, 1), (0, -1), (1, -1), + (-1, -1), (1/2, -1), (-1/2, -1), (2, -1), (-2, -1), (0, 1/2), (1, 1/2), + (-1, 1/2), (1/2, 1/2), (-1/2, 1/2), (2, 1/2), (-2, 1/2), (0, -1/2), (1, -1/2), + (-1, -1/2), (1/2, -1/2), (-1/2, -1/2), (2, -1/2), (-2, -1/2), (0, 2), (1, 2), + (-1, 2), (1/2, 2), (-1/2, 2), (2, 2), (-2, 2), (0, -2), (1, -2), (-1, -2), + (1/2, -2), (-1/2, -2), (2, -2), (-2, -2)] :: sage: u = QQ['u'].0 - sage: A.<x,y> = AffineSpace(NumberField(u^2 - 2, 'v'), 2) - sage: len(list(A.points_of_bounded_height(bound=2, tolerance=0.1))) + sage: A.<x,y> = AffineSpace(NumberField(u^2 - 2, 'v'), 2) # needs sage.rings.number_field + sage: len(list(A.points_of_bounded_height(bound=2, tolerance=0.1))) # needs sage.rings.number_field 529 """ - if (is_RationalField(self.base_ring())): - ftype = False # stores whether field is a number field or the rational field - elif (self.base_ring() in NumberFields()): # true for rational field as well, so check is_RationalField first + if is_RationalField(self.base_ring()): + ftype = False # stores whether field is a number field or the rational field + elif self.base_ring() in NumberFields(): # true for rational field as well, so check is_RationalField first ftype = True else: raise NotImplementedError("self must be affine space over a number field.") bound = kwds.pop('bound') - B = bound**self.base_ring().absolute_degree() # convert to relative height + B = bound**self.base_ring().absolute_degree() # convert to relative height n = self.dimension_relative() R = self.base_ring() - zero = R(0) - P = [ zero for _ in range(n) ] + zero = R.zero() + P = [zero] * n yield self(P) if not ftype: - iters = [ R.range_by_height(B) for _ in range(n) ] + iters = [R.range_by_height(B) for _ in range(n)] else: tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) - iters = [ R.elements_of_bounded_height(bound=B, tolerance=tol, precision=prec) for _ in range(n) ] + iters = [R.elements_of_bounded_height(bound=B, tolerance=tol, precision=prec) for _ in range(n)] for x in iters: - next(x) # put at zero + next(x) # put at zero i = 0 while i < n: try: @@ -1092,10 +1086,10 @@ def points_of_bounded_height(self, **kwds): i = 0 except StopIteration: if not ftype: - iters[i] = R.range_by_height(B) # reset + iters[i] = R.range_by_height(B) # reset else: iters[i] = R.elements_of_bounded_height(bound=B, tolerance=tol, precision=prec) - next(iters[i]) # put at zero + next(iters[i]) # put at zero P[i] = zero i += 1 @@ -1108,21 +1102,22 @@ def weil_restriction(self): the Weil restriction to the prime subfield. OUTPUT: Affine space of dimension ``d * self.dimension_relative()`` - over the base field of ``self.base_ring()``. + over the base field of ``self.base_ring()``. EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: K.<w> = NumberField(x^5-2) + sage: K.<w> = NumberField(x^5 - 2) sage: AK.<x,y> = AffineSpace(K, 2) sage: AK.weil_restriction() Affine Space of dimension 10 over Rational Field sage: R.<x> = K[] - sage: L.<v> = K.extension(x^2+1) + sage: L.<v> = K.extension(x^2 + 1) sage: AL.<x,y> = AffineSpace(L, 2) sage: AL.weil_restriction() - Affine Space of dimension 4 over Number Field in w with defining - polynomial x^5 - 2 + Affine Space of dimension 4 over Number Field in w + with defining polynomial x^5 - 2 """ try: X = self.__weil_restriction @@ -1138,11 +1133,11 @@ def weil_restriction(self): if d == 1: X = self else: - X = AffineSpace(K, d*self.dimension_relative(), 'z') + X = AffineSpace(K, d * self.dimension_relative(), 'z') self.__weil_restriction = X return X - def curve(self,F): + def curve(self, F): r""" Return a curve defined by ``F`` in this affine space. @@ -1154,7 +1149,7 @@ def curve(self,F): EXAMPLES:: sage: A.<x,y,z> = AffineSpace(QQ, 3) - sage: A.curve([y - x^4, z - y^5]) + sage: A.curve([y - x^4, z - y^5]) # needs sage.libs.pari Affine Curve over Rational Field defined by -x^4 + y, -y^5 + z """ from sage.schemes.curves.constructor import Curve @@ -1170,13 +1165,13 @@ def line_through(self, p, q): EXAMPLES:: + sage: # needs sage.libs.singular sage.schemes sage: A3.<x,y,z> = AffineSpace(3, QQ) sage: p1 = A3(1, 2, 3) sage: p2 = A3(4, 5, 6) - sage: A3.line_through(p1, p2) + sage: L = A3.line_through(p1, p2); L Affine Curve over Rational Field defined by -1/6*x + 1/6*y - 1/6, - -1/6*x + 1/6*z - 1/3, -1/6*y + 1/6*z - 1/6, -1/6*x + 1/3*y - 1/6*z - sage: L = _ + -1/6*x + 1/6*z - 1/3, -1/6*y + 1/6*z - 1/6, -1/6*x + 1/3*y - 1/6*z sage: L(p1) (1, 2, 3) sage: L(p2) @@ -1185,7 +1180,6 @@ def line_through(self, p, q): Traceback (most recent call last): ... ValueError: not distinct points - """ if p == q: raise ValueError("not distinct points") @@ -1269,7 +1263,6 @@ def _morphism(self, *args, **kwds): # fix the pickles from moving affine_space.py -from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.schemes.generic.affine_space', 'AffineSpace_generic', AffineSpace_generic) diff --git a/src/sage/schemes/affine/affine_subscheme.py b/src/sage/schemes/affine/affine_subscheme.py index 0ba77fd2b6d..ed125a60193 100644 --- a/src/sage/schemes/affine/affine_subscheme.py +++ b/src/sage/schemes/affine/affine_subscheme.py @@ -42,14 +42,14 @@ class AlgebraicScheme_subscheme_affine(AlgebraicScheme_subscheme): EXAMPLES:: sage: A3.<x, y, z> = AffineSpace(QQ, 3) - sage: A3.subscheme([x^2-y*z]) + sage: A3.subscheme([x^2 - y*z]) Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: x^2 - y*z TESTS:: sage: from sage.schemes.affine.affine_subscheme import AlgebraicScheme_subscheme_affine - sage: AlgebraicScheme_subscheme_affine(A3, [x^2-y*z]) + sage: AlgebraicScheme_subscheme_affine(A3, [x^2 - y*z]) Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: x^2 - y*z """ @@ -59,7 +59,7 @@ def __init__(self, A, polynomials, embedding_center=None, EXAMPLES:: sage: A.<x,y,z> = AffineSpace(QQ, 3) - sage: A.subscheme([y^2-x*z-x*y]) + sage: A.subscheme([y^2 - x*z - x*y]) Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: -x*y + y^2 - x*z """ @@ -98,6 +98,7 @@ def dimension(self): EXAMPLES:: + sage: # needs sage.libs.singular sage: A.<x,y> = AffineSpace(2, QQ) sage: A.subscheme([]).dimension() 2 @@ -120,7 +121,7 @@ def dimension(self): x^2*y^2 + z^2, z^2 - w^2, 10*x^2 - z^2 + w^2 - sage: X.dimension() + sage: X.dimension() # needs sage.libs.singular 1 """ try: @@ -151,66 +152,55 @@ def projective_embedding(self, i=None, PP=None): EXAMPLES:: sage: A.<x, y, z> = AffineSpace(3, ZZ) - sage: S = A.subscheme([x*y-z]) - sage: S.projective_embedding() + sage: S = A.subscheme([x*y - z]) + sage: S.projective_embedding() # needs sage.libs.singular Scheme morphism: - From: Closed subscheme of Affine Space of dimension 3 over Integer Ring defined by: - x*y - z - To: Closed subscheme of Projective Space of dimension 3 over Integer Ring defined by: - x0*x1 - x2*x3 - Defn: Defined on coordinates by sending (x, y, z) to - (x : y : z : 1) + From: Closed subscheme of Affine Space of dimension 3 over Integer Ring + defined by: x*y - z + To: Closed subscheme of Projective Space of dimension 3 over Integer Ring + defined by: x0*x1 - x2*x3 + Defn: Defined on coordinates by sending (x, y, z) to (x : y : z : 1) :: sage: A.<x, y, z> = AffineSpace(3, ZZ) - sage: P = ProjectiveSpace(3,ZZ,'u') - sage: S = A.subscheme([x^2-y*z]) - sage: S.projective_embedding(1,P) + sage: P = ProjectiveSpace(3, ZZ, 'u') + sage: S = A.subscheme([x^2 - y*z]) + sage: S.projective_embedding(1, P) # needs sage.libs.singular Scheme morphism: - From: Closed subscheme of Affine Space of dimension 3 over Integer - Ring defined by: - x^2 - y*z - To: Closed subscheme of Projective Space of dimension 3 over Integer - Ring defined by: - u0^2 - u2*u3 - Defn: Defined on coordinates by sending (x, y, z) to - (x : 1 : y : z) + From: Closed subscheme of Affine Space of dimension 3 over Integer Ring + defined by: x^2 - y*z + To: Closed subscheme of Projective Space of dimension 3 over Integer Ring + defined by: u0^2 - u2*u3 + Defn: Defined on coordinates by sending (x, y, z) to (x : 1 : y : z) :: sage: A.<x,y,z> = AffineSpace(QQ, 3) sage: X = A.subscheme([y - x^2, z - x^3]) - sage: X.projective_embedding() + sage: X.projective_embedding() # needs sage.libs.singular Scheme morphism: - From: Closed subscheme of Affine Space of dimension 3 over Rational - Field defined by: - -x^2 + y, - -x^3 + z - To: Closed subscheme of Projective Space of dimension 3 over - Rational Field defined by: - x0^2 - x1*x3, - x0*x1 - x2*x3, - x1^2 - x0*x2 - Defn: Defined on coordinates by sending (x, y, z) to - (x : y : z : 1) + From: Closed subscheme of Affine Space of dimension 3 over Rational Field + defined by: -x^2 + y, -x^3 + z + To: Closed subscheme of Projective Space of dimension 3 over Rational Field + defined by: x0^2 - x1*x3, x0*x1 - x2*x3, x1^2 - x0*x2 + Defn: Defined on coordinates by sending (x, y, z) to (x : y : z : 1) When taking a closed subscheme of an affine space with a projective embedding, the subscheme inherits the embedding:: sage: A.<u,v> = AffineSpace(2, QQ, default_embedding_index=1) - sage: X = A.subscheme(u - v) - sage: X.projective_embedding() + sage: X = A.subscheme(u - v) # needs sage.libs.singular + sage: X.projective_embedding() # needs sage.libs.singular Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - u - v - To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x0 - x2 - Defn: Defined on coordinates by sending (u, v) to - (u : 1 : v) - sage: phi = X.projective_embedding() + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: u - v + To: Closed subscheme of Projective Space of dimension 2 over Rational Field + defined by: x0 - x2 + Defn: Defined on coordinates by sending (u, v) to (u : 1 : v) + sage: phi = X.projective_embedding() # needs sage.libs.singular sage: psi = A.projective_embedding() - sage: phi(X(2, 2)) == psi(A(X(2, 2))) + sage: phi(X(2, 2)) == psi(A(X(2, 2))) # needs sage.libs.singular True """ AA = self.ambient_space() @@ -222,11 +212,11 @@ def projective_embedding(self, i=None, PP=None): i = n i = int(i) if i < 0 or i > n: - raise ValueError("Argument i (=%s) must be between 0 and %s, inclusive"%(i, n)) + raise ValueError("Argument i (=%s) must be between 0 and %s, inclusive" % (i, n)) try: phi = self.__projective_embedding[i] - #assume that if you've passed in a new ambient projective space - #you want to override the existing embedding + # assume that if you've passed in a new ambient projective space + # you want to override the existing embedding if PP is None or phi.codomain().ambient_space() == PP: return phi except AttributeError: @@ -236,7 +226,7 @@ def projective_embedding(self, i=None, PP=None): if PP is None: PP = AA.projective_embedding(i).codomain() elif PP.dimension_relative() != n: - raise ValueError("Projective Space must be of dimension %s"%(n)) + raise ValueError("Projective Space must be of dimension %s" % (n)) PR = PP.coordinate_ring() # Groebner basis w.r.t. a graded monomial order computed here to ensure # after homogenization, the basis elements will generate the defining @@ -245,7 +235,7 @@ def projective_embedding(self, i=None, PP=None): G = self.defining_ideal().groebner_basis() v = list(PP.gens()) z = v.pop(i) - phi = R.hom(v,PR) + phi = R.hom(v, PR) v.append(z) X = PP.subscheme([phi(f).homogenize(i) for f in G]) v = list(R.gens()) @@ -271,11 +261,12 @@ def projective_closure(self, i=None, PP=None): EXAMPLES:: - sage: A.<x,y,z,w> = AffineSpace(QQ,4) - sage: X = A.subscheme([x^2 - y, x*y - z, y^2 - w, x*z - w, y*z - x*w, z^2 - y*w]) - sage: X.projective_closure() + sage: A.<x,y,z,w> = AffineSpace(QQ, 4) + sage: X = A.subscheme([x^2 - y, x*y - z, y^2 - w, + ....: x*z - w, y*z - x*w, z^2 - y*w]) + sage: X.projective_closure() # needs sage.libs.singular Closed subscheme of Projective Space of dimension 4 over Rational Field - defined by: + defined by: x0^2 - x1*x4, x0*x1 - x2*x4, x1^2 - x3*x4, @@ -288,7 +279,7 @@ def projective_closure(self, i=None, PP=None): sage: A.<x,y,z> = AffineSpace(QQ, 3) sage: P.<a,b,c,d> = ProjectiveSpace(QQ, 3) sage: X = A.subscheme([z - x^2 - y^2]) - sage: X.projective_closure(1, P).ambient_space() == P + sage: X.projective_closure(1, P).ambient_space() == P # needs sage.libs.singular True """ return self.projective_embedding(i, PP).codomain() @@ -310,8 +301,8 @@ def is_smooth(self, point=None): EXAMPLES:: - sage: A2.<x,y> = AffineSpace(2,QQ) - sage: cuspidal_curve = A2.subscheme([y^2-x^3]) + sage: A2.<x,y> = AffineSpace(2, QQ) + sage: cuspidal_curve = A2.subscheme([y^2 - x^3]) sage: cuspidal_curve Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: -x^3 + y^2 @@ -321,11 +312,11 @@ def is_smooth(self, point=None): sage: singular_point = cuspidal_curve.point([0,0]) sage: singular_point in cuspidal_curve True - sage: cuspidal_curve.is_smooth(smooth_point) + sage: cuspidal_curve.is_smooth(smooth_point) # needs sage.libs.singular True - sage: cuspidal_curve.is_smooth(singular_point) + sage: cuspidal_curve.is_smooth(singular_point) # needs sage.libs.singular False - sage: cuspidal_curve.is_smooth() + sage: cuspidal_curve.is_smooth() # needs sage.libs.singular False """ R = self.ambient_space().coordinate_ring() @@ -365,21 +356,24 @@ def intersection_multiplicity(self, X, P): EXAMPLES:: sage: A.<x,y> = AffineSpace(QQ, 2) - sage: C = Curve([y^2 - x^3 - x^2], A) - sage: D = Curve([y^2 + x^3], A) + sage: C = Curve([y^2 - x^3 - x^2], A) # needs sage.libs.singular + sage: D = Curve([y^2 + x^3], A) # needs sage.libs.singular sage: Q = A([0,0]) - sage: C.intersection_multiplicity(D, Q) + sage: C.intersection_multiplicity(D, Q) # needs sage.libs.singular 4 :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^6 - 3*a^5 + 5*a^4 - 5*a^3 + 5*a^2 - 3*a + 1) sage: A.<x,y,z,w> = AffineSpace(K, 4) sage: X = A.subscheme([x*y, y*z + 7, w^3 - x^3]) sage: Y = A.subscheme([x - z^3 + z + 1]) - sage: Q = A([0, -7*b^5 + 21*b^4 - 28*b^3 + 21*b^2 - 21*b + 14, -b^5 + 2*b^4 - 3*b^3 \ - + 2*b^2 - 2*b, 0]) + sage: Q = A([0, + ....: -7*b^5 + 21*b^4 - 28*b^3 + 21*b^2 - 21*b + 14, + ....: -b^5 + 2*b^4 - 3*b^3 + 2*b^2 - 2*b, + ....: 0]) sage: X.intersection_multiplicity(Y, Q) 3 @@ -389,7 +383,7 @@ def intersection_multiplicity(self, X, P): sage: X = A.subscheme([z^2 - 1]) sage: Y = A.subscheme([z - 1, y - x^2]) sage: Q = A([1,1,1]) - sage: X.intersection_multiplicity(Y, Q) + sage: X.intersection_multiplicity(Y, Q) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: the intersection of this subscheme and (=Closed subscheme of Affine Space of dimension 3 @@ -401,7 +395,7 @@ def intersection_multiplicity(self, X, P): sage: X = A.subscheme([x*y, t^2*w, w^3*z]) sage: Y = A.subscheme([y*w + z]) sage: Q = A([0,0,0,0,0]) - sage: X.intersection_multiplicity(Y, Q) + sage: X.intersection_multiplicity(Y, Q) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: the intersection of this subscheme and (=Closed subscheme of Affine Space of dimension 5 @@ -409,14 +403,14 @@ def intersection_multiplicity(self, X, P): """ AA = self.ambient_space() if AA != X.ambient_space(): - raise TypeError("this subscheme and (=%s) must be defined in the same ambient space"%X) + raise TypeError("this subscheme and (=%s) must be defined in the same ambient space" % X) W = self.intersection(X) try: W._check_satisfies_equations(P) except TypeError: - raise TypeError("(=%s) must be a point in the intersection of this subscheme and (=%s)"%(P,X)) + raise TypeError("(=%s) must be a point in the intersection of this subscheme and (=%s)" % (P, X)) if AA.dimension() != self.dimension() + X.dimension() or W.dimension() != 0: - raise TypeError("the intersection of this subscheme and (=%s) must be proper and finite"%X) + raise TypeError("the intersection of this subscheme and (=%s) must be proper and finite" % X) I = self.defining_ideal() J = X.defining_ideal() # move P to the origin and localize @@ -430,8 +424,8 @@ def intersection_multiplicity(self, X, P): s = 0 t = sum(singular.Tor(i, Iloc, Jloc).std().hilb(2).sage()) while t != 0: - s = s + ((-1)**i)*t - i = i + 1 + s += (-1)**i * t + i += 1 t = sum(singular.Tor(i, Iloc, Jloc).std().hilb(2).sage()) return s @@ -455,22 +449,23 @@ def multiplicity(self, P): sage: A.<x,y,z,w> = AffineSpace(QQ, 4) sage: X = A.subscheme([z*y - x^7, w - 2*z]) sage: Q1 = A([1,1/3,3,6]) - sage: X.multiplicity(Q1) + sage: X.multiplicity(Q1) # needs sage.libs.singular 1 sage: Q2 = A([0,0,0,0]) - sage: X.multiplicity(Q2) + sage: X.multiplicity(Q2) # needs sage.libs.singular 2 :: sage: A.<x,y,z,w,v> = AffineSpace(GF(23), 5) - sage: C = A.curve([x^8 - y, y^7 - z, z^3 - 1, w^5 - v^3]) + sage: C = A.curve([x^8 - y, y^7 - z, z^3 - 1, w^5 - v^3]) # needs sage.libs.singular sage.schemes sage: Q = A([22,1,1,0,0]) - sage: C.multiplicity(Q) + sage: C.multiplicity(Q) # needs sage.libs.singular sage.schemes 3 :: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-1) sage: A.<x,y,z,w,t> = AffineSpace(K, 5) sage: X = A.subscheme([y^7 - x^2*z^5 + z^3*t^8 - x^2*y^4*z - t^8]) @@ -486,7 +481,7 @@ def multiplicity(self, P): sage: A1.<x> = AffineSpace(QQ, 1) sage: X = A1.subscheme([x^1789 + x]) sage: Q = X([0]) - sage: X.multiplicity(Q) + sage: X.multiplicity(Q) # needs sage.libs.singular 1 """ if not self.base_ring() in Fields(): @@ -496,7 +491,7 @@ def multiplicity(self, P): try: P = self(P) except TypeError: - raise TypeError("(=%s) is not a point on (=%s)"%(P,self)) + raise TypeError("(=%s) is not a point on (=%s)" % (P, self)) # Apply a linear change of coordinates to self so that P is sent to the origin # and then compute the multiplicity of the local ring of the translated subscheme @@ -523,20 +518,18 @@ def _morphism(self, *args, **kwds): sage: H = X.Hom(A2) sage: H([x, x/y]) Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x - y + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x - y To: Affine Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (x, x/y) + Defn: Defined on coordinates by sending (x, y) to (x, x/y) sage: P2 = ProjectiveSpace(QQ, 2) sage: H = X.Hom(P2) sage: H([x*y, x, y]) Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x - y + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x - y To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (x*y : x : y) + Defn: Defined on coordinates by sending (x, y) to (x*y : x : y) """ return SchemeMorphism_polynomial_affine_subscheme_field(*args, **kwds) @@ -553,45 +546,45 @@ def tangent_space(self, p): EXAMPLES:: sage: A3.<x,y,z> = AffineSpace(3, QQ) - sage: X = A3.subscheme(z-x*y) - sage: X.tangent_space(A3.origin()) + sage: X = A3.subscheme(z - x*y) + sage: X.tangent_space(A3.origin()) # needs sage.libs.singular Closed subscheme of Affine Space of dimension 3 over Rational Field - defined by: + defined by: z - sage: X.tangent_space(X(1,1,1)) + sage: X.tangent_space(X(1,1,1)) # needs sage.libs.singular Closed subscheme of Affine Space of dimension 3 over Rational Field - defined by: + defined by: -x - y + z Tangent space at a point may have higher dimension than the dimension of the point. :: + sage: # needs sage.libs.singular sage: C = Curve([x + y + z, x^2 - y^2*z^2 + z^3]) sage: C.singular_points() [(0, 0, 0)] sage: p = C(0,0,0) sage: C.tangent_space(p) Closed subscheme of Affine Space of dimension 3 over Rational Field - defined by: + defined by: x + y + z sage: _.dimension() 2 sage: q = C(1,0,-1) sage: C.tangent_space(q) Closed subscheme of Affine Space of dimension 3 over Rational Field - defined by: + defined by: x + y + z, 2*x + 3*z sage: _.dimension() 1 - """ A = self.ambient_space() R = A.coordinate_ring() gens = R.gens() J = self.Jacobian_matrix() - Jp = J.apply_map( lambda f: f.subs(dict(zip(gens, p))) ) + Jp = J.apply_map(lambda f: f.subs(dict(zip(gens, p)))) I = [f for f in Jp * vector(gens) if f] return A.subscheme(R.ideal(I)) diff --git a/src/sage/schemes/berkovich/__init__.py b/src/sage/schemes/berkovich/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/berkovich/berkovich_cp_element.py b/src/sage/schemes/berkovich/berkovich_cp_element.py index b8cc1887957..bc8307f29e5 100644 --- a/src/sage/schemes/berkovich/berkovich_cp_element.py +++ b/src/sage/schemes/berkovich/berkovich_cp_element.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.padics r""" Elements of Berkovich space. @@ -48,7 +49,7 @@ class Berkovich_Element(Element): """ - The parent class for any element of a Berkovich space + The parent class for any element of a Berkovich space. """ pass @@ -83,7 +84,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= Type I point centered at 4 + O(5^20) """ from sage.rings.function_field.element import is_FunctionFieldElement - from sage.rings.polynomial.polynomial_element import is_Polynomial + from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.fraction_field_element import FractionFieldElement_1poly_field self._type = None @@ -109,17 +110,17 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= # is_FunctionFieldElement calls .parent elif hasattr(center, "parent") and hasattr(radius, 'parent'): - from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial - if is_MPolynomial(center): + from sage.rings.polynomial.multi_polynomial import MPolynomial + if isinstance(center, MPolynomial): try: center = center.univariate_polynomial() except AttributeError: raise TypeError('center was %s, a multivariable polynomial' % center) # check if the radius and the center are functions - center_func_check = is_FunctionFieldElement(center) or is_Polynomial(center) or\ + center_func_check = is_FunctionFieldElement(center) or isinstance(center, Polynomial) or\ isinstance(center, FractionFieldElement_1poly_field) or isinstance(center, Expression) - radius_func_check = is_FunctionFieldElement(radius) or is_Polynomial(radius) or\ + radius_func_check = is_FunctionFieldElement(radius) or isinstance(radius, Polynomial) or\ isinstance(radius, FractionFieldElement_1poly_field) or isinstance(radius, Expression) if center_func_check: @@ -456,9 +457,9 @@ def center_function(self): sage: f = T(1/t) sage: R.<x> = RR[] sage: Y = FractionField(R) - sage: g = (40*pi)/x - sage: Q1 = B(f, g) - sage: Q1.center_function() + sage: g = (40*pi)/x # needs sage.symbolic + sage: Q1 = B(f, g) # needs sage.symbolic + sage: Q1.center_function() # needs sage.symbolic (1 + O(5^20))/((1 + O(5^20))*t) """ if self.type_of_point() != 4: @@ -484,9 +485,9 @@ def radius_function(self): sage: f = T(1/t) sage: R.<x> = RR[] sage: Y = FractionField(R) - sage: g = (40*pi)/x - sage: Q1 = B(f, g) - sage: Q1.radius_function() + sage: g = (40*pi)/x # needs sage.symbolic + sage: Q1 = B(f, g) # needs sage.symbolic + sage: Q1.radius_function() # needs sage.symbolic 40.0000000000000*pi/x """ if self.type_of_point() != 4: @@ -687,7 +688,7 @@ def path_distance_metric(self, other): INPUT: - - ``other`` -- A point of the same Berkovich space as this point. + - ``other`` -- A point of the same Berkovich space as this point. OUTPUT: A finite or infinite real number. @@ -941,6 +942,7 @@ def Hsia_kernel_infinity(self, other): :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: A.<a> = NumberField(x^3 + 20) sage: ideal = A.ideal(-1/2*a^2 + a - 3) @@ -973,6 +975,7 @@ def center(self): :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: A.<a> = NumberField(x^3 + 20) sage: ideal = A.ideal(-1/2*a^2 + a - 3) @@ -1023,6 +1026,7 @@ def __ne__(self, other): EXAMPLES:: + sage: # needs sage.symbolic sage: B = Berkovich_Cp_Affine(3) sage: Q1 = B(3, 3**(1/2)) sage: Q2 = B(3, RR(3**(1/2))) @@ -1144,7 +1148,7 @@ class Berkovich_Element_Cp_Affine(Berkovich_Element_Cp): Type II and III points can be created by specifying a center and a radius:: - sage: B(2, 3**(1/2)) + sage: B(2, 3**(1/2)) # needs sage.symbolic Type II point centered at 2 + O(3^20) of radius 3^1/2 :: @@ -1154,7 +1158,7 @@ class Berkovich_Element_Cp_Affine(Berkovich_Element_Cp): Some type II points may be mistaken for type III points:: - sage: B(3, 3**0.5) #not tested + sage: B(3, 3**0.5) # not tested Type III point centered at 3 + O(3^21) of radius 1.73205080756888 To avoid these errors, specify the power instead of the radius:: @@ -1181,7 +1185,7 @@ class Berkovich_Element_Cp_Affine(Berkovich_Element_Cp): Type IV point of precision 100 with centers given by ((t^2 + 2*t + 1) + O(3^20))*x and radii given by (y + 1.00000000000000)/y - For increased performance, error_check can be set to ``False``. WARNING: with error check set + For increased performance, ``error_check`` can be set to ``False``. WARNING: with error check set to ``False``, any error in the input will lead to incorrect results:: sage: B(f, g, prec=100, error_check=False) @@ -1190,6 +1194,7 @@ class Berkovich_Element_Cp_Affine(Berkovich_Element_Cp): When creating a Berkovich space backed by a number field, points can be created similarly:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: A.<a> = NumberField(x^3 + 20) sage: ideal = A.prime_above(3) @@ -1199,7 +1204,7 @@ class Berkovich_Element_Cp_Affine(Berkovich_Element_Cp): :: - sage: B(a + 1, 3) + sage: B(a + 1, 3) # needs sage.rings.number_field Type II point centered at (a + 1 : 1) of radius 3^1 TESTS:: @@ -1207,37 +1212,27 @@ class Berkovich_Element_Cp_Affine(Berkovich_Element_Cp): sage: A = Berkovich_Cp_Affine(3) sage: Q1 = A(3, 1); Q1 Type II point centered at 3 + O(3^21) of radius 3^0 - sage: Q2 = A(2.5, 1); Q2 Type II point centered at 1 + 2*3 + 3^2 + 3^3 + 3^4 + 3^5 + 3^6 + 3^7 + 3^8 + 3^9 + 3^10 + 3^11 + 3^12 + 3^13 + 3^14 + 3^15 + 3^16 + 3^17 + 3^18 + 3^19 + O(3^20) of radius 3^0 - sage: Q5 = A(3, 0); Q5 Type I point centered at 3 + O(3^21) - sage: A(Zp(3)(2), 2).center().parent() == A(Qp(3)(2), 2).center().parent() True - sage: Q1 == Q2 True - sage: Q1 == Q5 False - sage: Q3 = A(Qp(3)(3), power=0, error_check=False); Q3 Type II point centered at 3 + O(3^21) of radius 3^0 - sage: Q4 = A(3, 3**0); Q4 Type II point centered at 3 + O(3^21) of radius 3^0 - sage: Q5 = A(3, power=1/2); Q5 Type II point centered at 3 + O(3^21) of radius 3^1/2 - - sage: Q6 = A(3, RR(3**(1/2))); Q6 + sage: Q6 = A(3, RR(3**(1/2))); Q6 # needs sage.symbolic Type III point centered at 3 + O(3^21) of radius 1.73205080756888 - - sage: Q5 == Q6 + sage: Q5 == Q6 # needs sage.symbolic True sage: k = Qp(5) @@ -1299,9 +1294,9 @@ def as_projective_point(self): sage: f = T(1/t) sage: R.<x> = RR[] sage: Y = FractionField(R) - sage: g = (40*pi)/x - sage: Q2 = B(f, g) - sage: Q2.as_projective_point() + sage: g = (40*pi)/x # needs sage.symbolic + sage: Q2 = B(f, g) # needs sage.symbolic + sage: Q2.as_projective_point() # needs sage.symbolic Type IV point of precision 20 with centers given by (1 + O(5^20))/((1 + O(5^20))*t) and radii given by 40.0000000000000*pi/x """ @@ -1330,9 +1325,9 @@ def __eq__(self, other): EXAMPLES:: sage: B = Berkovich_Cp_Projective(3) - sage: Q1 = B(1, RR(3**(1/2))) - sage: Q2 = B(1, 3**(1/2)) - sage: Q1 == Q2 + sage: Q1 = B(1, RR(3**(1/2))) # needs sage.symbolic + sage: Q2 = B(1, 3**(1/2)) # needs sage.symbolic + sage: Q1 == Q2 # needs sage.symbolic True :: @@ -1345,12 +1340,12 @@ def __eq__(self, other): :: sage: Q5 = B(1, 4) - sage: Q1 == Q5 + sage: Q1 == Q5 # needs sage.symbolic False :: - sage: Q1 == Q3 + sage: Q1 == Q3 # needs sage.symbolic False """ if other is self: @@ -1380,18 +1375,19 @@ def __hash__(self): EXAMPLES:: sage: B = Berkovich_Cp_Affine(3) - sage: Q1 = B(1, RR(3**(1/2))) - sage: Q2 = B(1, 3**(1/2)) - sage: hash(Q1) == hash(Q2) + sage: Q1 = B(1, RR(3**(1/2))) # needs sage.symbolic + sage: Q2 = B(1, 3**(1/2)) # needs sage.symbolic + sage: hash(Q1) == hash(Q2) # needs sage.symbolic True :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: A.<a> = NumberField(x^3+20) + sage: A.<a> = NumberField(x^3 + 20) sage: ideal = A.ideal(-1/2*a^2 + a - 3) sage: B = Berkovich_Cp_Projective(A, ideal) - sage: Q1 = B(a^2+1, 2) + sage: Q1 = B(a^2 + 1, 2) sage: Q2 = B(0, 2) sage: hash(Q1) == hash(Q2) True @@ -1589,7 +1585,7 @@ def join(self, other, basepoint=Infinity): TESTS:: sage: Q4 = B(1/3**8 + 2, 1) - sage: Q2.join(Q4, basepoint = Q1) + sage: Q2.join(Q4, basepoint=Q1) Type III point centered at 2 + O(3^20) of radius 2.00000000000000 :: @@ -1838,17 +1834,17 @@ class Berkovich_Element_Cp_Projective(Berkovich_Element_Cp): Type II and III points can be created by specifying a center and a radius:: - sage: Q3 = P((0,5), 5**(3/2)); Q3 + sage: Q3 = P((0,5), 5**(3/2)); Q3 # needs sage.symbolic Type II point centered at (0 : 1 + O(5^20)) of radius 5^3/2 :: - sage: Q4 = P(0, 3**(3/2)); Q4 + sage: Q4 = P(0, 3**(3/2)); Q4 # needs sage.symbolic Type III point centered at (0 : 1 + O(5^20)) of radius 5.19615242270663 Type IV points can be created from lists of centers and radii:: - sage: b = S((3,2)) #create centers + sage: b = S((3,2)) # create centers sage: c = S((4,3)) sage: d = S((2,3)) sage: L = [b, c, d] @@ -1870,8 +1866,8 @@ class Berkovich_Element_Cp_Projective(Berkovich_Element_Cp): sage: f = T(1/t) sage: R.<x> = RR[] sage: Y = FractionField(R) - sage: g = (40*pi)/x - sage: Q6 = P(f, g); Q6 + sage: g = (40*pi)/x # needs sage.symbolic + sage: Q6 = P(f, g); Q6 # needs sage.symbolic Type IV point of precision 20 with centers given by (1 + O(5^20))/((1 + O(5^20))*t) and radii given by 40.0000000000000*pi/x @@ -1939,9 +1935,9 @@ def as_affine_point(self): sage: f = T(1/t) sage: R.<x> = RR[] sage: Y = FractionField(R) - sage: g = (40*pi)/x - sage: Q2 = B(f, g) - sage: Q2.as_affine_point() + sage: g = (40*pi)/x # needs sage.symbolic + sage: Q2 = B(f, g) # needs sage.symbolic + sage: Q2.as_affine_point() # needs sage.symbolic Type IV point of precision 20 with centers given by (1 + O(5^20))/((1 + O(5^20))*t) and radii given by 40.0000000000000*pi/x """ @@ -1974,9 +1970,9 @@ def __eq__(self, other): EXAMPLES:: sage: B = Berkovich_Cp_Projective(3) - sage: Q1 = B([2, 2], RR(3**(1/2))) - sage: Q2 = B([1, 1], 3**(1/2)) - sage: Q1 == Q2 + sage: Q1 = B([2, 2], RR(3**(1/2))) # needs sage.symbolic + sage: Q2 = B([1, 1], 3**(1/2)) # needs sage.symbolic + sage: Q1 == Q2 # needs sage.symbolic True :: @@ -1989,12 +1985,12 @@ def __eq__(self, other): :: sage: Q5 = B(1, 4) - sage: Q1 == Q5 + sage: Q1 == Q5 # needs sage.symbolic False :: - sage: Q1 == Q3 + sage: Q1 == Q3 # needs sage.symbolic False """ if other is self: @@ -2027,13 +2023,14 @@ def __hash__(self): sage: B = Berkovich_Cp_Projective(3) sage: P = ProjectiveSpace(B.base_ring(), 1) - sage: Q1 = B(P.point([2, 2], False), RR(3**(1/2))) - sage: Q2 = B([1, 1], 3**(1/2)) - sage: hash(Q1) == hash(Q2) + sage: Q1 = B(P.point([2, 2], False), RR(3**(1/2))) # needs sage.symbolic + sage: Q2 = B([1, 1], 3**(1/2)) # needs sage.symbolic + sage: hash(Q1) == hash(Q2) # needs sage.symbolic True :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: A.<a> = NumberField(x^3 + 20) sage: ideal = A.ideal(-1/2*a^2 + a - 3) @@ -2273,24 +2270,21 @@ def join(self, other, basepoint=Infinity): sage: Q4 = B(1/3**8 + 2, 1) sage: Q2.join(Q4, basepoint=Q1) Type III point centered at (2 + O(3^20) : 1 + O(3^20)) of radius 2.00000000000000 - sage: Q5 = B(2, 1/9) sage: Q6 = B(1, 1/27) sage: Q4.join(Q5, basepoint=Q6) Type II point centered at (1 + O(3^20) : 1 + O(3^20)) of radius 3^0 - sage: Q7 = B(1/27, 1/27) sage: Q1.join(Q7, Q2) Type III point centered at (2 + O(3^20) : 1 + O(3^20)) of radius 2.00000000000000 - sage: Q1.join(Q2, Q7) Type III point centered at (2 + O(3^20) : 1 + O(3^20)) of radius 2.00000000000000 - sage: Q8 = B(0, power=1/3) sage: Q9 = B(0, power=1/2) sage: Q8.join(Q9) Type II point centered at (0 : 1 + O(3^20)) of radius 3^1/2 + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: A.<a> = NumberField(x^3 + 20) sage: ideal = A.prime_above(3) @@ -2300,7 +2294,6 @@ def join(self, other, basepoint=Infinity): Traceback (most recent call last): ... ValueError: other must be a point of the same projective Berkovich line - sage: Q11 = C(0, 1/3) sage: Q11.join(Q10) Type II point centered at (0 : 1) of radius 3^0 @@ -2538,7 +2531,7 @@ def contained_in_interval(self, start, end): :: - sage: Q1 = B(1,3) + sage: Q1 = B(1, 3) sage: infty.contained_in_interval(gauss, Q1) False diff --git a/src/sage/schemes/berkovich/berkovich_space.py b/src/sage/schemes/berkovich/berkovich_space.py index 17eee57dd0a..100c2807b9d 100644 --- a/src/sage/schemes/berkovich/berkovich_space.py +++ b/src/sage/schemes/berkovich/berkovich_space.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.padics r""" Berkovich Space over `\CC_p` @@ -19,17 +20,17 @@ AUTHORS: - - Alexander Galarraga (2020-06-22): initial implementation +- Alexander Galarraga (2020-06-22): initial implementation """ -#***************************************************************************** +# **************************************************************************** # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.schemes.berkovich.berkovich_cp_element import (Berkovich_Element_Cp_Affine, Berkovich_Element_Cp_Projective) @@ -40,14 +41,14 @@ from sage.categories.number_fields import NumberFields import sage.rings.abc from sage.rings.integer_ring import ZZ -from sage.rings.padics.factory import Qp from sage.rings.rational_field import QQ from sage.rings.number_field.number_field_ideal import NumberFieldFractionalIdeal from sage.categories.topological_spaces import TopologicalSpaces -def is_Berkovich(space): + +def is_Berkovich(space) -> bool: """ - Checks if ``space`` is a Berkovich space. + Check if ``space`` is a Berkovich space. OUTPUT: @@ -63,9 +64,10 @@ def is_Berkovich(space): """ return isinstance(space, Berkovich) -def is_Berkovich_Cp(space): + +def is_Berkovich_Cp(space) -> bool: """ - Checks if ``space`` is a Berkovich space over ``Cp``. + Check if ``space`` is a Berkovich space over ``Cp``. OUTPUT: @@ -81,12 +83,14 @@ def is_Berkovich_Cp(space): """ return isinstance(space, Berkovich_Cp) + class Berkovich(UniqueRepresentation, Parent): """ The parent class for any Berkovich space """ pass + class Berkovich_Cp(Berkovich): """ Abstract parent class for Berkovich space over ``Cp``. @@ -104,6 +108,7 @@ def residue_characteristic(self): :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: A.<a> = NumberField(x^3 + 20) sage: ideal = A.ideal(-1/2*a^2 + a - 3) @@ -130,7 +135,7 @@ def is_padic_base(self): sage: B.is_padic_base() True - :: + :: sage: B = Berkovich_Cp_Affine(QQ, 3) sage: B.is_padic_base() @@ -140,7 +145,7 @@ def is_padic_base(self): def is_number_field_base(self): """ - Return ``True`` if this Berkovich space is backed by a p-adic field. + Return ``True`` if this Berkovich space is backed by a number field. OUTPUT: @@ -178,6 +183,7 @@ def ideal(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<z> = QQ[] sage: A.<a> = NumberField(z^2 + 1) sage: ideal = A.prime_above(5) @@ -199,7 +205,7 @@ def ideal(self): """ return self._ideal - def __eq__(self,right): + def __eq__(self, right): """ Equality operator. @@ -213,6 +219,7 @@ def __eq__(self,right): :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: A.<a> = NumberField(x^2 + 1) sage: A_ideal = A.prime_above(2) @@ -225,16 +232,16 @@ def __eq__(self,right): :: - sage: C = Berkovich_Cp_Affine(A, A_ideal) - sage: D = Berkovich_Cp_Affine(B, B_ideal) - sage: C == D + sage: C = Berkovich_Cp_Affine(A, A_ideal) # needs sage.rings.number_field + sage: D = Berkovich_Cp_Affine(B, B_ideal) # needs sage.rings.number_field + sage: C == D # needs sage.rings.number_field False :: - sage: A_ideal_2 = A.prime_above(5) - sage: E = Berkovich_Cp_Affine(A, A_ideal_2) - sage: C == E + sage: A_ideal_2 = A.prime_above(5) # needs sage.rings.number_field + sage: E = Berkovich_Cp_Affine(A, A_ideal_2) # needs sage.rings.number_field + sage: C == E # needs sage.rings.number_field False """ if not isinstance(right, Berkovich_Cp): @@ -246,7 +253,7 @@ def __eq__(self,right): else: return self.base() == right.base() and self.ideal() == right.ideal() - def __ne__(self,right): + def __ne__(self, right): """ Inequality operator. @@ -271,6 +278,7 @@ def __hash__(self): :: + sage: # needs sage.rings.number_field sage: R.<z> = QQ[] sage: A.<a> = NumberField(z^2 + 1) sage: B = Berkovich_Cp_Projective(A, A.primes_above(5)[0]) @@ -282,6 +290,7 @@ def __hash__(self): return hash(self.prime()) return hash(self.ideal()) + class Berkovich_Cp_Affine(Berkovich_Cp): r""" The Berkovich affine line over `\CC_p`. @@ -363,11 +372,11 @@ class Berkovich_Cp_Affine(Berkovich_Cp): For exact computation, a number field can be used:: sage: R.<x> = QQ[] - sage: A.<a> = NumberField(x^3 + 20) - sage: ideal = A.prime_above(3) - sage: B = Berkovich_Cp_Affine(A, ideal); B - Affine Berkovich line over Cp(3), with base Number - Field in a with defining polynomial x^3 + 20 + sage: A.<a> = NumberField(x^3 + 20) # needs sage.rings.number_field + sage: ideal = A.prime_above(3) # needs sage.rings.number_field + sage: B = Berkovich_Cp_Affine(A, ideal); B # needs sage.rings.number_field + Affine Berkovich line over Cp(3), with base + Number Field in a with defining polynomial x^3 + 20 Number fields have a major advantage of exact computation. @@ -382,6 +391,7 @@ class Berkovich_Cp_Affine(Berkovich_Cp): field, any point of a Berkovich space backed by a number field must be centered at a point of that number field:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: A.<a> = NumberField(x^3 + 20) sage: ideal = A.prime_above(3) @@ -418,6 +428,8 @@ def __init__(self, base, ideal=None): """ if base in ZZ: if base.is_prime(): + from sage.rings.padics.factory import Qp + base = Qp(base) # change to Qpbar else: raise ValueError("non-prime passed into Berkovich space") @@ -430,8 +442,8 @@ def __init__(self, base, ideal=None): if not isinstance(ideal, NumberFieldFractionalIdeal): raise ValueError('ideal was not an ideal of a number field') if ideal.number_field() != base: - raise ValueError('passed number field ' + \ - '%s but ideal was an ideal of %s' %(base, ideal.number_field())) + raise ValueError('passed number field ' + + '%s but ideal was an ideal of %s' % (base, ideal.number_field())) prime = ideal.smallest_integer() else: if ideal not in QQ: @@ -445,8 +457,8 @@ def __init__(self, base, ideal=None): ideal = None self._base_type = 'padic field' else: - raise ValueError("base of Berkovich Space must be a padic field " + \ - "or a number field") + raise ValueError("base of Berkovich Space must be a padic field " + "or a number field") self._ideal = ideal self._p = prime Parent.__init__(self, base=base, category=TopologicalSpaces()) @@ -457,24 +469,23 @@ def _repr_(self): EXAMPLES:: - sage: B = Berkovich_Cp_Affine(3) - sage: B + sage: B = Berkovich_Cp_Affine(3); B Affine Berkovich line over Cp(3) of precision 20 :: sage: R.<z> = QQ[] - sage: A.<a> = NumberField(z^2 + 1) - sage: ideal = A.prime_above(3) - sage: Berkovich_Cp_Affine(A, ideal) - Affine Berkovich line over Cp(3), with base Number Field - in a with defining polynomial z^2 + 1 + sage: A.<a> = NumberField(z^2 + 1) # needs sage.rings.number_field + sage: ideal = A.prime_above(3) # needs sage.rings.number_field + sage: Berkovich_Cp_Affine(A, ideal) # needs sage.rings.number_field + Affine Berkovich line over Cp(3), with base + Number Field in a with defining polynomial z^2 + 1 """ if self._base_type == 'padic field': - return "Affine Berkovich line over Cp(%s) of precision %s" %(self.prime(),\ + return "Affine Berkovich line over Cp(%s) of precision %s" % (self.prime(), self.base().precision_cap()) else: - return "Affine Berkovich line over Cp(%s), with base %s" %(self.prime(),\ + return "Affine Berkovich line over Cp(%s), with base %s" % (self.prime(), self.base()) def _latex_(self): @@ -560,11 +571,11 @@ class Berkovich_Cp_Projective(Berkovich_Cp): a number field, as long as an ideal is specified:: sage: R.<x> = QQ[] - sage: A.<a> = NumberField(x^2 + 1) - sage: ideal = A.prime_above(2) - sage: B = Berkovich_Cp_Projective(A, ideal); B + sage: A.<a> = NumberField(x^2 + 1) # needs sage.rings.number_field + sage: ideal = A.prime_above(2) # needs sage.rings.number_field + sage: B = Berkovich_Cp_Projective(A, ideal); B # needs sage.rings.number_field Projective Berkovich line over Cp(2), with base - Number Field in a with defining polynomial x^2 + 1 + Number Field in a with defining polynomial x^2 + 1 Number fields have the benefit that computation is exact, but lack support for all of `\CC_p`. @@ -581,6 +592,7 @@ class Berkovich_Cp_Projective(Berkovich_Cp): field, any point of a Berkovich space backed by a number field must be centered at a point of that number field:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: A.<a> = NumberField(x^3 + 20) sage: ideal = A.prime_above(3) @@ -611,6 +623,8 @@ def __init__(self, base, ideal=None): """ if base in ZZ: if base.is_prime(): + from sage.rings.padics.factory import Qp + base = ProjectiveSpace(Qp(base), 1) else: raise ValueError("non-prime passed into Berkovich space") @@ -623,8 +637,8 @@ def __init__(self, base, ideal=None): raise ValueError("base of projective Berkovich space must be projective space") if not isinstance(base.base_ring(), sage.rings.abc.pAdicField): if base.base_ring() not in NumberFields(): - raise ValueError("base of projective Berkovich space must be " + \ - "projective space over Qp or a number field") + raise ValueError("base of projective Berkovich space must be " + "projective space over Qp or a number field") else: if ideal is None: raise ValueError('passed a number field but not an ideal') @@ -632,8 +646,8 @@ def __init__(self, base, ideal=None): if not isinstance(ideal, NumberFieldFractionalIdeal): raise ValueError('ideal was not a number field ideal') if ideal.number_field() != base.base_ring(): - raise ValueError('passed number field ' + \ - '%s but ideal was an ideal of %s' %(base.base_ring(), ideal.number_field())) + raise ValueError('passed number field ' + + '%s but ideal was an ideal of %s' % (base.base_ring(), ideal.number_field())) prime = ideal.smallest_integer() else: if ideal not in QQ: @@ -673,6 +687,7 @@ def base_ring(self): :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: A.<a> = NumberField(x^3 + 20) sage: ideal = A.prime_above(3) @@ -688,23 +703,23 @@ def _repr_(self): EXAMPLES:: - sage: B = Berkovich_Cp_Projective(3) - sage: B + sage: B = Berkovich_Cp_Projective(3); B Projective Berkovich line over Cp(3) of precision 20 :: sage: R.<x> = QQ[] - sage: A.<a> = NumberField(x^2 + 1) - sage: v = A.ideal(a + 1) - sage: Berkovich_Cp_Projective(A, v) - Projective Berkovich line over Cp(2), with base Number Field in a with defining polynomial x^2 + 1 + sage: A.<a> = NumberField(x^2 + 1) # needs sage.rings.number_field + sage: v = A.ideal(a + 1) # needs sage.rings.number_field + sage: Berkovich_Cp_Projective(A, v) # needs sage.rings.number_field + Projective Berkovich line over Cp(2), + with base Number Field in a with defining polynomial x^2 + 1 """ if self._base_type == 'padic field': - return "Projective Berkovich line over Cp(%s) of precision %s" %(self.prime(),\ + return "Projective Berkovich line over Cp(%s) of precision %s" % (self.prime(), self.base().base_ring().precision_cap()) else: - return "Projective Berkovich line over Cp(%s), with base %s" %(self.prime(),\ + return "Projective Berkovich line over Cp(%s), with base %s" % (self.prime(), self.base().base_ring()) def _latex_(self): @@ -717,4 +732,4 @@ def _latex_(self): sage: latex(B) \text{Projective Berkovich line over } \Bold{C}_{3} """ - return r"\text{Projective Berkovich line over } \Bold{C}_{%s}" %(self.prime()) + return r"\text{Projective Berkovich line over } \Bold{C}_{%s}" % (self.prime()) diff --git a/src/sage/schemes/curves/__init__.py b/src/sage/schemes/curves/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index a329e927d51..326c0d86e77 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular r""" Affine curves @@ -37,6 +38,7 @@ Closed points of arbitrary degree can be computed:: + sage: # long time sage: C.closed_points() [Point (x, y, z), Point (x + 1, y, z)] sage: C.closed_points(2) @@ -50,7 +52,7 @@ The places at infinity correspond to the extra closed points of the curve's projective closure:: - sage: C.places_at_infinity() + sage: C.places_at_infinity() # long time [Place (1/x, 1/x*z)] It is easy to transit to and from the function field of the curve:: @@ -95,10 +97,10 @@ s sage: sy = sy.polynomial(10); sy -7/256*s^10 - 5/128*s^8 - 1/16*s^6 - 1/8*s^4 - 1/2*s^2 + 1 - sage: s = var('s') - sage: P1 = parametric_plot([sx, sy], (s, -1, 1), color='red') - sage: P2 = C.plot((x, -1, 1), (y, 0, 2)) # half circle - sage: P1 + P2 + sage: s = var('s') # needs sage.symbolic + sage: P1 = parametric_plot([sx, sy], (s, -1, 1), color='red') # needs sage.plot sage.symbolic + sage: P2 = C.plot((x, -1, 1), (y, 0, 2)) # half circle # needs sage.plot sage.symbolic + sage: P1 + P2 # needs sage.plot sage.symbolic Graphics object consisting of 2 graphics primitives AUTHORS: @@ -114,14 +116,14 @@ - Kwankyu Lee (2019-05): added integral affine curves """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.lazy_attribute import lazy_attribute from sage.misc.cachefunc import cached_method @@ -168,9 +170,9 @@ class AffineCurve(Curve_generic, AlgebraicScheme_subscheme_affine): EXAMPLES:: sage: R.<v> = QQ[] - sage: K.<u> = NumberField(v^2 + 3) - sage: A.<x,y,z> = AffineSpace(K, 3) - sage: C = Curve([z - u*x^2, y^2], A); C + sage: K.<u> = NumberField(v^2 + 3) # needs sage.rings.number_field + sage: A.<x,y,z> = AffineSpace(K, 3) # needs sage.rings.number_field + sage: C = Curve([z - u*x^2, y^2], A); C # needs sage.rings.number_field Affine Curve over Number Field in u with defining polynomial v^2 + 3 defined by (-u)*x^2 + z, y^2 @@ -180,6 +182,7 @@ class AffineCurve(Curve_generic, AlgebraicScheme_subscheme_affine): sage: C = Curve([x^2 - z, z - 8*x], A); C Affine Curve over Finite Field of size 7 defined by x^2 - z, -x + z """ + def __init__(self, A, X): r""" Initialize. @@ -187,9 +190,9 @@ def __init__(self, A, X): EXAMPLES:: sage: R.<v> = QQ[] - sage: K.<u> = NumberField(v^2 + 3) - sage: A.<x,y,z> = AffineSpace(K, 3) - sage: C = Curve([z - u*x^2, y^2], A); C + sage: K.<u> = NumberField(v^2 + 3) # needs sage.rings.number_field + sage: A.<x,y,z> = AffineSpace(K, 3) # needs sage.rings.number_field + sage: C = Curve([z - u*x^2, y^2], A); C # needs sage.rings.number_field Affine Curve over Number Field in u with defining polynomial v^2 + 3 defined by (-u)*x^2 + z, y^2 @@ -229,9 +232,7 @@ def projective_closure(self, i=0, PP=None): - ``PP`` -- (default: None) ambient projective space to compute the projective closure in. This is constructed if it is not given. - OUTPUT: - - - a curve in projective space. + OUTPUT: A curve in projective space. EXAMPLES:: @@ -273,6 +274,7 @@ class AffinePlaneCurve(AffineCurve): """ Affine plane curves. """ + def __init__(self, A, f): r""" Initialize. @@ -325,17 +327,17 @@ def divisor_of_function(self, r): EXAMPLES:: sage: F = GF(5) - sage: P2 = AffineSpace(2, F, names = 'xy') + sage: P2 = AffineSpace(2, F, names='xy') sage: R = P2.coordinate_ring() sage: x, y = R.gens() sage: f = y^2 - x^9 - x sage: C = Curve(f) sage: K = FractionField(R) sage: r = 1/x - sage: C.divisor_of_function(r) # todo: not implemented (broken) + sage: C.divisor_of_function(r) # not implemented (broken) [[-1, (0, 0, 1)]] sage: r = 1/x^3 - sage: C.divisor_of_function(r) # todo: not implemented (broken) + sage: C.divisor_of_function(r) # not implemented (broken) [[-3, (0, 0, 1)]] """ F = self.base_ring() @@ -380,9 +382,9 @@ def local_coordinates(self, pt, n): sage: F = GF(5) sage: pt = (2,3) - sage: R = PolynomialRing(F,2, names = ['x','y']) + sage: R = PolynomialRing(F, 2, names = ['x','y']) sage: x,y = R.gens() - sage: f = y^2-x^9-x + sage: f = y^2 - x^9 - x sage: C = Curve(f) sage: C.local_coordinates(pt, 9) [t + 2, -2*t^12 - 2*t^11 + 2*t^9 + t^8 - 2*t^7 - 2*t^6 - 2*t^4 + t^3 - 2*t^2 - 2] @@ -393,14 +395,14 @@ def local_coordinates(self, pt, n): p = F.characteristic() x0 = F(pt[0]) y0 = F(pt[1]) - astr = ["a"+str(i) for i in range(1,2*n)] - x,y = R.gens() + astr = ["a" + str(i) for i in range(1, 2 * n)] + x, y = R.gens() R0 = PolynomialRing(F, 2 * n + 2, names=[str(x), str(y), "t"] + astr) vars0 = R0.gens() t = vars0[2] - yt = y0*t**0+add([vars0[i]*t**(i-2) for i in range(3,2*n+2)]) + yt = y0*t**0+add([vars0[i]*t**(i-2) for i in range(3, 2*n+2)]) xt = x0+t - ft = f(xt,yt) + ft = f(xt, yt) S = singular S.eval('ring s = '+str(p)+','+str(R0.gens())+',lp;') S.eval('poly f = '+str(ft) + ';') @@ -421,15 +423,15 @@ def local_coordinates(self, pt, n): if str(y) in x: if x.replace(str(y), ""): i = x.find("-") - if i>0: - vals.append([eval(x[1:i]),x[:i],F(eval(x[i+1:]))]) + if i > 0: + vals.append([eval(x[1:i]), x[:i], F(eval(x[i+1:]))]) i = x.find("+") - if i>0: - vals.append([eval(x[1:i]),x[:i],-F(eval(x[i+1:]))]) + if i > 0: + vals.append([eval(x[1:i]), x[:i], -F(eval(x[i+1:]))]) else: - vals.append([eval(str(y)[1:]),str(y),F(0)]) + vals.append([eval(str(y)[1:]), str(y), F(0)]) vals.sort() - return [x0 + t, y0 + add(v[2] * t**(j+1) for j, v in enumerate(vals))] + return [x0 + t, y0 + add(v[2] * t**(j + 1) for j, v in enumerate(vals))] def plot(self, *args, **kwds): r""" @@ -449,26 +451,27 @@ def plot(self, *args, **kwds): sage: R.<x, y> = QQ[] sage: C = Curve(x^3 - y^2) - sage: C.plot() + sage: C.plot() # needs sage.plot Graphics object consisting of 1 graphics primitive A 5-nodal curve of degree 11. This example also illustrates some of the optional arguments:: sage: R.<x, y> = ZZ[] - sage: C = Curve(32*x^2 - 2097152*y^11 + 1441792*y^9 - 360448*y^7 + 39424*y^5 - 1760*y^3 + 22*y - 1) - sage: C.plot((x, -1, 1), (y, -1, 1), plot_points=400) + sage: C = Curve(32*x^2 - 2097152*y^11 + 1441792*y^9 + ....: - 360448*y^7 + 39424*y^5 - 1760*y^3 + 22*y - 1) + sage: C.plot((x, -1, 1), (y, -1, 1), plot_points=400) # needs sage.plot Graphics object consisting of 1 graphics primitive A line over `\mathbf{RR}`:: sage: R.<x, y> = RR[] - sage: C = Curve(R(y - sqrt(2)*x)) - sage: C.plot() + sage: C = Curve(R(y - sqrt(2)*x)) # needs sage.symbolic + sage: C.plot() # needs sage.plot Graphics object consisting of 1 graphics primitive """ - I = self.defining_ideal() - return I.plot(*args, **kwds) + Id = self.defining_ideal() + return Id.plot(*args, **kwds) def is_transverse(self, C, P): r""" @@ -483,7 +486,7 @@ def is_transverse(self, C, P): - ``P`` -- a point in the intersection of both curves. - OUTPUT: Boolean. + OUTPUT: A boolean. EXAMPLES:: @@ -496,6 +499,7 @@ def is_transverse(self, C, P): :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^3 + 2) sage: A.<x,y> = AffineSpace(K, 2) @@ -538,9 +542,7 @@ def multiplicity(self, P): - ``P`` -- a point in the ambient space of this curve. - OUTPUT: - - An integer. + OUTPUT: An integer. EXAMPLES:: @@ -555,9 +557,11 @@ def multiplicity(self, P): :: + sage: # needs sage.rings.number_field sage: A.<x,y> = AffineSpace(QQbar,2) - sage: C = Curve([-x^7 + (-7)*x^6 + y^6 + (-21)*x^5 + 12*y^5 + (-35)*x^4 + 60*y^4 +\ - (-35)*x^3 + 160*y^3 + (-21)*x^2 + 240*y^2 + (-7)*x + 192*y + 63], A) + sage: C = Curve([-x^7 + (-7)*x^6 + y^6 + (-21)*x^5 + 12*y^5 + ....: + (-35)*x^4 + 60*y^4 + (-35)*x^3 + 160*y^3 + ....: + (-21)*x^2 + 240*y^2 + (-7)*x + 192*y + 63], A) sage: Q = A([-1,-2]) sage: C.multiplicity(Q) 6 @@ -605,25 +609,30 @@ def tangents(self, P, factor=True): curve, or to just return the polynomial corresponding to the union of the tangent lines (which requires fewer computations) - OUTPUT: a list of polynomials in the coordinate ring of the ambient space + OUTPUT: A list of polynomials in the coordinate ring of the ambient space. EXAMPLES:: + sage: # needs sage.rings.number_field sage: set_verbose(-1) sage: A.<x,y> = AffineSpace(QQbar, 2) - sage: C = Curve([x^5*y^3 + 2*x^4*y^4 + x^3*y^5 + 3*x^4*y^3 + 6*x^3*y^4 + 3*x^2*y^5\ - + 3*x^3*y^3 + 6*x^2*y^4 + 3*x*y^5 + x^5 + 10*x^4*y + 40*x^3*y^2 + 81*x^2*y^3 + 82*x*y^4\ - + 33*y^5], A) + sage: C = Curve([x^5*y^3 + 2*x^4*y^4 + x^3*y^5 + 3*x^4*y^3 + ....: + 6*x^3*y^4 + 3*x^2*y^5 + 3*x^3*y^3 + ....: + 6*x^2*y^4 + 3*x*y^5 + x^5 + 10*x^4*y + ....: + 40*x^3*y^2 + 81*x^2*y^3 + 82*x*y^4 + 33*y^5], A) sage: Q = A([0,0]) sage: C.tangents(Q) - [x + 3.425299577684700?*y, x + (1.949159013086856? + 1.179307909383728?*I)*y, - x + (1.949159013086856? - 1.179307909383728?*I)*y, x + (1.338191198070795? + 0.2560234251008043?*I)*y, - x + (1.338191198070795? - 0.2560234251008043?*I)*y] + [x + 3.425299577684700?*y, + x + (1.949159013086856? + 1.179307909383728?*I)*y, + x + (1.949159013086856? - 1.179307909383728?*I)*y, + x + (1.338191198070795? + 0.2560234251008043?*I)*y, + x + (1.338191198070795? - 0.2560234251008043?*I)*y] sage: C.tangents(Q, factor=False) [120*x^5 + 1200*x^4*y + 4800*x^3*y^2 + 9720*x^2*y^3 + 9840*x*y^4 + 3960*y^5] :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^2 - 3) sage: A.<x,y> = AffineSpace(K, 2) @@ -657,9 +666,9 @@ def tangents(self, P, factor=True): vars = self.ambient_space().gens() coords = [vars[0] + P[0], vars[1] + P[1]] f = f(coords) - coords = [vars[0] - P[0], vars[1] - P[1]] # coords to change back with - deriv = [f.derivative(vars[0],i).derivative(vars[1], r-i)([0,0]) for i in range(r+1)] - T = sum([binomial(r,i)*deriv[i]*(vars[0])**i*(vars[1])**(r-i) for i in range(r+1)]) + coords = [vars[0] - P[0], vars[1] - P[1]] # coords to change back with + deriv = [f.derivative(vars[0], i).derivative(vars[1], r-i)([0, 0]) for i in range(r+1)] + T = sum([binomial(r, i)*deriv[i]*(vars[0])**i*(vars[1])**(r-i) for i in range(r+1)]) if not factor: return [T(coords)] if self.base_ring() == QQbar: @@ -670,13 +679,13 @@ def tangents(self, P, factor=True): if t > 0: fact.append(vars[0]) # divide T by that power of vars[0] - T = self.ambient_space().coordinate_ring()(dict([((v[0] - t,v[1]), h) for (v,h) in T.dict().items()])) + T = self.ambient_space().coordinate_ring()(dict([((v[0] - t, v[1]), h) for (v, h) in T.dict().items()])) t = min([e[1] for e in T.exponents()]) # vars[1] divides T if t > 0: fact.append(vars[1]) # divide T by that power of vars[1] - T = self.ambient_space().coordinate_ring()(dict([((v[0],v[1] - t), h) for (v,h) in T.dict().items()])) + T = self.ambient_space().coordinate_ring()(dict([((v[0], v[1] - t), h) for (v, h) in T.dict().items()])) # T is homogeneous in var[0], var[1] if nonconstant, so dehomogenize if T not in self.base_ring(): if T.degree(vars[0]) > 0: @@ -689,7 +698,7 @@ def tangents(self, P, factor=True): fact.extend([vars[1] - roots[i][0]*vars[0] for i in range(len(roots))]) return [ff(coords) for ff in fact] else: - return [l[0](coords) for l in T.factor()] + return [ll[0](coords) for ll in T.factor()] def is_ordinary_singularity(self, P): r""" @@ -720,6 +729,7 @@ def is_ordinary_singularity(self, P): :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^2 - 3) sage: A.<x,y> = AffineSpace(K, 2) @@ -741,7 +751,7 @@ def is_ordinary_singularity(self, P): """ r = self.multiplicity(P) if r < 2: - raise TypeError("(=%s) is not a singular point of (=%s)" % (P,self)) + raise TypeError("(=%s) is not a singular point of (=%s)" % (P, self)) T = self.tangents(P, factor=False)[0] vars = self.ambient_space().gens() @@ -829,9 +839,9 @@ def __init__(self, A, X): EXAMPLES:: sage: R.<v> = QQ[] - sage: K.<u> = NumberField(v^2 + 3) - sage: A.<x,y,z> = AffineSpace(K, 3) - sage: C = Curve([z - u*x^2, y^2], A); C + sage: K.<u> = NumberField(v^2 + 3) # needs sage.rings.number_field + sage: A.<x,y,z> = AffineSpace(K, 3) # needs sage.rings.number_field + sage: C = Curve([z - u*x^2, y^2], A); C # needs sage.rings.number_field Affine Curve over Number Field in u with defining polynomial v^2 + 3 defined by (-u)*x^2 + z, y^2 @@ -870,7 +880,7 @@ def projection(self, indices, AS=None): this curve, and must have dimension equal to the length of ``indices``. This space is constructed if not specified. - OUTPUT: a tuple of + OUTPUT: A tuple of - a scheme morphism from this curve to affine space of dimension equal to the number of coordinates specified in ``indices`` @@ -884,8 +894,8 @@ def projection(self, indices, AS=None): sage: C = Curve([y^7 - x^2 + x^3 - 2*z, z^2 - x^7 - y^2], A) sage: C.projection([0,1]) (Scheme morphism: - From: Affine Curve over Rational Field defined by y^7 + x^3 - x^2 - - 2*z, -x^7 - y^2 + z^2 + From: Affine Curve over Rational Field + defined by y^7 + x^3 - x^2 - 2*z, -x^7 - y^2 + z^2 To: Affine Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x, y, z) to (x, y), @@ -913,13 +923,13 @@ def projection(self, indices, AS=None): :: sage: A.<x,y,z,w,u> = AffineSpace(GF(11), 5) - sage: C = Curve([x^3 - 5*y*z + u^2, x - y^2 + 3*z^2, w^2 + 2*u^3*y, y - u^2 + z*x], A) + sage: C = Curve([x^3 - 5*y*z + u^2, x - y^2 + 3*z^2, + ....: w^2 + 2*u^3*y, y - u^2 + z*x], A) sage: B.<a,b,c> = AffineSpace(GF(11), 3) - sage: proj1 = C.projection([1,2,4], AS=B) - sage: proj1 + sage: proj1 = C.projection([1,2,4], AS=B); proj1 (Scheme morphism: From: Affine Curve over Finite Field of size 11 defined by x^3 - - 5*y*z + u^2, -y^2 + 3*z^2 + x, 2*y*u^3 + w^2, x*z - u^2 + y + 5*y*z + u^2, -y^2 + 3*z^2 + x, 2*y*u^3 + w^2, x*z - u^2 + y To: Affine Space of dimension 3 over Finite Field of size 11 Defn: Defined on coordinates by sending (x, y, z, w, u) to (y, z, u), @@ -946,22 +956,21 @@ def projection(self, indices, AS=None): sage: C = A.curve([x*y - z^3, x*z - w^3, w^2 - x^3]) sage: C.projection([y,z]) (Scheme morphism: - From: Affine Curve over Rational Field defined by -z^3 + x*y, -w^3 + - x*z, -x^3 + w^2 + From: Affine Curve over Rational Field defined by + -z^3 + x*y, -w^3 + x*z, -x^3 + w^2 To: Affine Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y, z, w) to - (y, z), + Defn: Defined on coordinates by sending (x, y, z, w) to (y, z), Affine Plane Curve over Rational Field defined by x1^23 - x0^7*x1^4) sage: B.<x,y,z> = AffineSpace(QQ, 3) sage: C.projection([x,y,z], AS=B) (Scheme morphism: - From: Affine Curve over Rational Field defined by -z^3 + x*y, -w^3 + - x*z, -x^3 + w^2 + From: Affine Curve over Rational Field defined by + -z^3 + x*y, -w^3 + x*z, -x^3 + w^2 To: Affine Space of dimension 3 over Rational Field Defn: Defined on coordinates by sending (x, y, z, w) to (x, y, z), - Affine Curve over Rational Field defined by z^3 - x*y, x^8 - x*z^2, - x^7*z^2 - x*y*z) + Affine Curve over Rational Field defined by + z^3 - x*y, x^8 - x*z^2, x^7*z^2 - x*y*z) sage: C.projection([y,z,z]) Traceback (most recent call last): ... @@ -990,10 +999,11 @@ def projection(self, indices, AS=None): indices = [AA.gens().index(f) for f in indices] indices.sort() else: - indices = [int(i) for i in indices] # type checking + indices = [int(i) for i in indices] # type checking indices.sort() if indices[0] < 0 or indices[-1] > n - 1: - raise ValueError("index values must be between 0 and one minus the dimension of the ambient space " \ + raise ValueError("index values must be between 0 and one " + "minus the dimension of the ambient space " "of this curve") # construct the projection map if AS is None: @@ -1008,10 +1018,10 @@ def projection(self, indices, AS=None): removecoords.pop(indices[i]) J = self.defining_ideal().elimination_ideal(removecoords) K = Hom(AA.coordinate_ring(), AA2.coordinate_ring()) - l = [0]*(n) + ll = [0]*(n) for i in range(len(indices)): - l[indices[i]] = AA2.gens()[i] - phi = K(l) + ll[indices[i]] = AA2.gens()[i] + phi = K(ll) G = [phi(f) for f in J.gens()] try: C = AA2.curve(G) @@ -1031,7 +1041,7 @@ def plane_projection(self, AP=None): curve, and must have dimension two. This space will be constructed if not specified. - OUTPUT: a tuple of + OUTPUT: A tuple of - a scheme morphism from this curve into an affine plane @@ -1043,15 +1053,16 @@ def plane_projection(self, AP=None): sage: C = Curve([x^2 - y*z*w, z^3 - w, w + x*y - 3*z^3], A) sage: C.plane_projection() (Scheme morphism: - From: Affine Curve over Rational Field defined by -y*z*w + x^2, z^3 - - w, -3*z^3 + x*y + w + From: Affine Curve over Rational Field defined by + -y*z*w + x^2, z^3 - w, -3*z^3 + x*y + w To: Affine Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y, z, w) to - (x, y), Affine Plane Curve over Rational Field defined by - x0^2*x1^7 - 16*x0^4) + Defn: Defined on coordinates by sending (x, y, z, w) to (x, y), + Affine Plane Curve over Rational Field defined by + x0^2*x1^7 - 16*x0^4) :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^2 + 2) sage: A.<x,y,z> = AffineSpace(K, 3) @@ -1060,14 +1071,14 @@ def plane_projection(self, AP=None): sage: proj1 = C.plane_projection(AP=B) sage: proj1 (Scheme morphism: - From: Affine Curve over Number Field in b with defining polynomial - a^2 + 2 defined by x + (-b), y - 2 - To: Affine Space of dimension 2 over Number Field in b with - defining polynomial a^2 + 2 + From: Affine Curve over Number Field in b + with defining polynomial a^2 + 2 defined by x + (-b), y - 2 + To: Affine Space of dimension 2 over Number Field in b + with defining polynomial a^2 + 2 Defn: Defined on coordinates by sending (x, y, z) to (x, z), - Affine Plane Curve over Number Field in b with defining polynomial a^2 - + 2 defined by a + (-b)) + Affine Plane Curve over Number Field in b + with defining polynomial a^2 + 2 defined by a + (-b)) sage: proj1[1].ambient_space() is B True sage: proj2 = C.plane_projection() @@ -1078,9 +1089,9 @@ def plane_projection(self, AP=None): # finds a projection that will have a plane curve as its image # the following iterates over all pairs (i,j) with j > i to test all # possible projections - for i in range(0, n - 1): + for i in range(n - 1): for j in range(i + 1, n): - L = self.projection([i,j], AP) + L = self.projection([i, j], AP) if isinstance(L[1], Curve_generic): return L @@ -1095,7 +1106,7 @@ def blowup(self, P=None): - ``P`` -- (default: None) a point on this curve at which to blow up; if ``None``, then ``P`` is taken to be the origin. - OUTPUT: a tuple of + OUTPUT: A tuple of - a tuple of curves in affine space of the same dimension as the ambient space of this curve, which define the blow up in each affine @@ -1114,65 +1125,90 @@ def blowup(self, P=None): sage: C = Curve([y^2 - x^3], A) sage: C.blowup() ((Affine Plane Curve over Rational Field defined by s1^2 - x, - Affine Plane Curve over Rational Field defined by y*s0^3 - 1), - ([Scheme endomorphism of Affine Plane Curve over Rational Field defined by s1^2 - x - Defn: Defined on coordinates by sending (x, s1) to - (x, s1), Scheme morphism: + Affine Plane Curve over Rational Field defined by y*s0^3 - 1), + ([Scheme endomorphism of Affine Plane Curve over Rational Field + defined by s1^2 - x + Defn: Defined on coordinates by sending (x, s1) to (x, s1), + Scheme morphism: From: Affine Plane Curve over Rational Field defined by s1^2 - x To: Affine Plane Curve over Rational Field defined by y*s0^3 - 1 - Defn: Defined on coordinates by sending (x, s1) to - (x*s1, 1/s1)], [Scheme morphism: + Defn: Defined on coordinates by sending (x, s1) to (x*s1, 1/s1)], + [Scheme morphism: From: Affine Plane Curve over Rational Field defined by y*s0^3 - 1 To: Affine Plane Curve over Rational Field defined by s1^2 - x - Defn: Defined on coordinates by sending (y, s0) to - (y*s0, 1/s0), - Scheme endomorphism of Affine Plane Curve over Rational Field defined by y*s0^3 - 1 - Defn: Defined on coordinates by sending (y, s0) to - (y, s0)]), + Defn: Defined on coordinates by sending (y, s0) to (y*s0, 1/s0), + Scheme endomorphism of Affine Plane Curve over Rational Field + defined by y*s0^3 - 1 + Defn: Defined on coordinates by sending (y, s0) to (y, s0)]), (Scheme morphism: From: Affine Plane Curve over Rational Field defined by s1^2 - x To: Affine Plane Curve over Rational Field defined by -x^3 + y^2 - Defn: Defined on coordinates by sending (x, s1) to - (x, x*s1), Scheme morphism: + Defn: Defined on coordinates by sending (x, s1) to (x, x*s1), + Scheme morphism: From: Affine Plane Curve over Rational Field defined by y*s0^3 - 1 To: Affine Plane Curve over Rational Field defined by -x^3 + y^2 - Defn: Defined on coordinates by sending (y, s0) to - (y*s0, y))) + Defn: Defined on coordinates by sending (y, s0) to (y*s0, y))) :: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(2) sage: A.<x,y,z> = AffineSpace(K, 3) sage: C = Curve([y^2 - a*x^5, x - z], A) sage: B = C.blowup() sage: B[0] - (Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by s2 - 1, 2*x^3 + (-a)*s1^2, - Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by s0 - s2, 2*y^3*s2^5 + (-a), - Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by s0 - 1, 2*z^3 + (-a)*s1^2) + (Affine Curve over Number Field in a with defining polynomial x^2 - 2 + with a = 1.414213562373095? defined by s2 - 1, 2*x^3 + (-a)*s1^2, + Affine Curve over Number Field in a with defining polynomial x^2 - 2 + with a = 1.414213562373095? defined by s0 - s2, 2*y^3*s2^5 + (-a), + Affine Curve over Number Field in a with defining polynomial x^2 - 2 + with a = 1.414213562373095? defined by s0 - 1, 2*z^3 + (-a)*s1^2) sage: B[1][0][2] Scheme morphism: - From: Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by s2 - 1, 2*x^3 + (-a)*s1^2 - To: Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by s0 - 1, 2*z^3 + (-a)*s1^2 + From: Affine Curve over Number Field in a + with defining polynomial x^2 - 2 with a = 1.414213562373095? + defined by s2 - 1, 2*x^3 + (-a)*s1^2 + To: Affine Curve over Number Field in a + with defining polynomial x^2 - 2 with a = 1.414213562373095? + defined by s0 - 1, 2*z^3 + (-a)*s1^2 Defn: Defined on coordinates by sending (x, s1, s2) to (x*s2, 1/s2, s1/s2) sage: B[1][2][0] Scheme morphism: - From: Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by s0 - 1, 2*z^3 + (-a)*s1^2 - To: Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by s2 - 1, 2*x^3 + (-a)*s1^2 + From: Affine Curve over Number Field in a + with defining polynomial x^2 - 2 with a = 1.414213562373095? + defined by s0 - 1, 2*z^3 + (-a)*s1^2 + To: Affine Curve over Number Field in a + with defining polynomial x^2 - 2 with a = 1.414213562373095? + defined by s2 - 1, 2*x^3 + (-a)*s1^2 Defn: Defined on coordinates by sending (z, s0, s1) to (z*s0, s1/s0, 1/s0) sage: B[2] (Scheme morphism: - From: Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by s2 - 1, 2*x^3 + (-a)*s1^2 - To: Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by (-a)*x^5 + y^2, x - z + From: Affine Curve over Number Field in a + with defining polynomial x^2 - 2 with a = 1.414213562373095? + defined by s2 - 1, 2*x^3 + (-a)*s1^2 + To: Affine Curve over Number Field in a + with defining polynomial x^2 - 2 with a = 1.414213562373095? + defined by (-a)*x^5 + y^2, x - z Defn: Defined on coordinates by sending (x, s1, s2) to - (x, x*s1, x*s2), Scheme morphism: - From: Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by s0 - s2, 2*y^3*s2^5 + (-a) - To: Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by (-a)*x^5 + y^2, x - z + (x, x*s1, x*s2), + Scheme morphism: + From: Affine Curve over Number Field in a + with defining polynomial x^2 - 2 with a = 1.414213562373095? + defined by s0 - s2, 2*y^3*s2^5 + (-a) + To: Affine Curve over Number Field in a + with defining polynomial x^2 - 2 with a = 1.414213562373095? + defined by (-a)*x^5 + y^2, x - z Defn: Defined on coordinates by sending (y, s0, s2) to - (y*s0, y, y*s2), Scheme morphism: - From: Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by s0 - 1, 2*z^3 + (-a)*s1^2 - To: Affine Curve over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? defined by (-a)*x^5 + y^2, x - z + (y*s0, y, y*s2), + Scheme morphism: + From: Affine Curve over Number Field in a + with defining polynomial x^2 - 2 with a = 1.414213562373095? + defined by s0 - 1, 2*z^3 + (-a)*s1^2 + To: Affine Curve over Number Field in a + with defining polynomial x^2 - 2 with a = 1.414213562373095? + defined by (-a)*x^5 + y^2, x - z Defn: Defined on coordinates by sending (z, s0, s1) to (z*s0, z*s1, z)) @@ -1182,37 +1218,49 @@ def blowup(self, P=None): sage: C = A.curve((y - 3/2)^3 - (x + 2)^5 - (x + 2)^6) sage: Q = A([-2,3/2]) sage: C.blowup(Q) - ((Affine Plane Curve over Rational Field defined by x^3 - s1^3 + 7*x^2 + 16*x + 12, - Affine Plane Curve over Rational Field defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5 + - 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8), - ([Scheme endomorphism of Affine Plane Curve over Rational Field defined by x^3 - s1^3 + 7*x^2 + - 16*x + 12 - Defn: Defined on coordinates by sending (x, s1) to - (x, s1), Scheme morphism: - From: Affine Plane Curve over Rational Field defined by x^3 - s1^3 + 7*x^2 + 16*x + 12 - To: Affine Plane Curve over Rational Field defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5 + - 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8 + ((Affine Plane Curve over Rational Field + defined by x^3 - s1^3 + 7*x^2 + 16*x + 12, + Affine Plane Curve over Rational Field + defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5 + + 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8), + ([Scheme endomorphism of Affine Plane Curve over Rational Field + defined by x^3 - s1^3 + 7*x^2 + 16*x + 12 + Defn: Defined on coordinates by sending (x, s1) to (x, s1), + Scheme morphism: + From: Affine Plane Curve over Rational Field + defined by x^3 - s1^3 + 7*x^2 + 16*x + 12 + To: Affine Plane Curve over Rational Field + defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5 + + 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8 Defn: Defined on coordinates by sending (x, s1) to - (x*s1 + 2*s1 + 3/2, 1/s1)], [Scheme morphism: - From: Affine Plane Curve over Rational Field defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5 + - 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8 - To: Affine Plane Curve over Rational Field defined by x^3 - s1^3 + 7*x^2 + 16*x + 12 + (x*s1 + 2*s1 + 3/2, 1/s1)], + [Scheme morphism: + From: Affine Plane Curve over Rational Field + defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5 + + 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8 + To: Affine Plane Curve over Rational Field + defined by x^3 - s1^3 + 7*x^2 + 16*x + 12 Defn: Defined on coordinates by sending (y, s0) to (y*s0 - 3/2*s0 - 2, 1/s0), - Scheme endomorphism of Affine Plane Curve over Rational Field defined by 8*y^3*s0^6 - 36*y^2*s0^6 + - 8*y^2*s0^5 + 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8 - Defn: Defined on coordinates by sending (y, s0) to - (y, s0)]), + Scheme endomorphism of Affine Plane Curve over Rational Field + defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5 + 54*y*s0^6 + - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8 + Defn: Defined on coordinates by sending (y, s0) to (y, s0)]), (Scheme morphism: - From: Affine Plane Curve over Rational Field defined by x^3 - s1^3 + 7*x^2 + 16*x + 12 - To: Affine Plane Curve over Rational Field defined by -x^6 - 13*x^5 - 70*x^4 - 200*x^3 + y^3 - - 320*x^2 - 9/2*y^2 - 272*x + 27/4*y - 795/8 + From: Affine Plane Curve over Rational Field + defined by x^3 - s1^3 + 7*x^2 + 16*x + 12 + To: Affine Plane Curve over Rational Field + defined by -x^6 - 13*x^5 - 70*x^4 - 200*x^3 + y^3 + - 320*x^2 - 9/2*y^2 - 272*x + 27/4*y - 795/8 Defn: Defined on coordinates by sending (x, s1) to - (x, x*s1 + 2*s1 + 3/2), Scheme morphism: - From: Affine Plane Curve over Rational Field defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5 + - 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8 - To: Affine Plane Curve over Rational Field defined by -x^6 - 13*x^5 - 70*x^4 - 200*x^3 + y^3 - - 320*x^2 - 9/2*y^2 - 272*x + 27/4*y - 795/8 + (x, x*s1 + 2*s1 + 3/2), + Scheme morphism: + From: Affine Plane Curve over Rational Field + defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5 + + 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8 + To: Affine Plane Curve over Rational Field + defined by -x^6 - 13*x^5 - 70*x^4 - 200*x^3 + y^3 + - 320*x^2 - 9/2*y^2 - 272*x + 27/4*y - 795/8 Defn: Defined on coordinates by sending (y, s0) to (y*s0 - 3/2*s0 - 2, y))) @@ -1223,16 +1271,15 @@ def blowup(self, P=None): sage: Q = C([-1,0,0,4]) sage: B = C.blowup(Q) sage: B[0] - (Affine Curve over Rational Field defined by s3, s1 - s2, x^2*s2^6 + - 2*x*s2^6 + 3*x^2*s2^4 + s2^6 + 6*x*s2^4 + 3*x^2*s2^2 + 3*s2^4 + 6*x*s2^2 - + x^2 - s2^2 + 2*x + 1, - Affine Curve over Rational Field defined by s3, s2 - 1, y^2*s0^6 + - 3*y^2*s0^4 + 3*y^2*s0^2 + y^2 - 4*s0^2, - Affine Curve over Rational Field defined by s3, s1 - 1, z^2*s0^6 + - 3*z^2*s0^4 + 3*z^2*s0^2 + z^2 - 4*s0^2, + (Affine Curve over Rational Field defined by s3, s1 - s2, + x^2*s2^6 + 2*x*s2^6 + 3*x^2*s2^4 + s2^6 + 6*x*s2^4 + + 3*x^2*s2^2 + 3*s2^4 + 6*x*s2^2 + x^2 - s2^2 + 2*x + 1, + Affine Curve over Rational Field defined by s3, s2 - 1, + y^2*s0^6 + 3*y^2*s0^4 + 3*y^2*s0^2 + y^2 - 4*s0^2, + Affine Curve over Rational Field defined by s3, s1 - 1, + z^2*s0^6 + 3*z^2*s0^4 + 3*z^2*s0^2 + z^2 - 4*s0^2, Closed subscheme of Affine Space of dimension 4 over Rational Field - defined by: - 1) + defined by: 1) sage: Q = A([6,2,3,1]) sage: B = C.blowup(Q) Traceback (most recent call last): @@ -1241,9 +1288,9 @@ def blowup(self, P=None): :: - sage: A.<x,y> = AffineSpace(QuadraticField(-1), 2) - sage: C = A.curve([y^2 + x^2]) - sage: C.blowup() + sage: A.<x,y> = AffineSpace(QuadraticField(-1), 2) # needs sage.rings.number_field + sage: C = A.curve([y^2 + x^2]) # needs sage.rings.number_field + sage: C.blowup() # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: this curve must be irreducible @@ -1369,7 +1416,7 @@ def resolution_of_singularities(self, extend=False): resolved. However, setting ``extend`` to ``True`` will slow down computations. - OUTPUT: a tuple of + OUTPUT: A tuple of - a tuple of curves in affine space of the same dimension as the ambient space of this curve, which represent affine patches of the @@ -1390,43 +1437,46 @@ def resolution_of_singularities(self, extend=False): sage: C.resolution_of_singularities() ((Affine Plane Curve over Rational Field defined by s1^2 - x, Affine Plane Curve over Rational Field defined by y*s0^3 - 1), - ((Scheme endomorphism of Affine Plane Curve over Rational Field defined by s1^2 - x - Defn: Defined on coordinates by sending (x, s1) to - (x, s1), Scheme morphism: + ((Scheme endomorphism of Affine Plane Curve over Rational Field + defined by s1^2 - x + Defn: Defined on coordinates by sending (x, s1) to (x, s1), + Scheme morphism: From: Affine Plane Curve over Rational Field defined by s1^2 - x To: Affine Plane Curve over Rational Field defined by y*s0^3 - 1 - Defn: Defined on coordinates by sending (x, s1) to - (x*s1, 1/s1)), (Scheme morphism: + Defn: Defined on coordinates by sending (x, s1) to (x*s1, 1/s1)), + (Scheme morphism: From: Affine Plane Curve over Rational Field defined by y*s0^3 - 1 To: Affine Plane Curve over Rational Field defined by s1^2 - x - Defn: Defined on coordinates by sending (y, s0) to - (y*s0, 1/s0), - Scheme endomorphism of Affine Plane Curve over Rational Field defined by y*s0^3 - 1 - Defn: Defined on coordinates by sending (y, s0) to - (y, s0))), + Defn: Defined on coordinates by sending (y, s0) to (y*s0, 1/s0), + Scheme endomorphism of Affine Plane Curve over Rational Field + defined by y*s0^3 - 1 + Defn: Defined on coordinates by sending (y, s0) to (y, s0))), (Scheme morphism: From: Affine Plane Curve over Rational Field defined by s1^2 - x To: Affine Plane Curve over Rational Field defined by -x^3 + y^2 - Defn: Defined on coordinates by sending (x, s1) to - (x, x*s1), Scheme morphism: + Defn: Defined on coordinates by sending (x, s1) to (x, x*s1), + Scheme morphism: From: Affine Plane Curve over Rational Field defined by y*s0^3 - 1 To: Affine Plane Curve over Rational Field defined by -x^3 + y^2 - Defn: Defined on coordinates by sending (y, s0) to - (y*s0, y))) + Defn: Defined on coordinates by sending (y, s0) to (y*s0, y))) :: + sage: # needs sage.rings.number_field sage: set_verbose(-1) sage: K.<a> = QuadraticField(3) sage: A.<x,y> = AffineSpace(K, 2) sage: C = A.curve(x^4 + 2*x^2 + a*y^3 + 1) - sage: C.resolution_of_singularities(extend=True)[0] # long time (2 seconds) - (Affine Plane Curve over Number Field in a0 with defining polynomial y^4 - 4*y^2 + 16 defined by - 24*x^2*ss1^3 + 24*ss1^3 + (a0^3 - 8*a0), - Affine Plane Curve over Number Field in a0 with defining polynomial y^4 - 4*y^2 + 16 defined by - 24*s1^2*ss0 + (a0^3 - 8*a0)*ss0^2 + (-6*a0^3)*s1, - Affine Plane Curve over Number Field in a0 with defining polynomial y^4 - 4*y^2 + 16 defined by - 8*y^2*s0^4 + (4*a0^3)*y*s0^3 - 32*s0^2 + (a0^3 - 8*a0)*y) + sage: C.resolution_of_singularities(extend=True)[0] # long time (2 s) + (Affine Plane Curve over Number Field in a0 + with defining polynomial y^4 - 4*y^2 + 16 + defined by 24*x^2*ss1^3 + 24*ss1^3 + (a0^3 - 8*a0), + Affine Plane Curve over Number Field in a0 + with defining polynomial y^4 - 4*y^2 + 16 + defined by 24*s1^2*ss0 + (a0^3 - 8*a0)*ss0^2 + (-6*a0^3)*s1, + Affine Plane Curve over Number Field in a0 + with defining polynomial y^4 - 4*y^2 + 16 + defined by 8*y^2*s0^4 + (4*a0^3)*y*s0^3 - 32*s0^2 + (a0^3 - 8*a0)*y) :: @@ -1434,27 +1484,32 @@ def resolution_of_singularities(self, extend=False): sage: C = Curve([y - x^3, (z - 2)^2 - y^3 - x^3], A) sage: R = C.resolution_of_singularities() sage: R[0] - (Affine Curve over Finite Field of size 5 defined by x^2 - s1, s1^4 - x*s2^2 + s1, x*s1^3 - s2^2 + x, - Affine Curve over Finite Field of size 5 defined by y*s2^2 - y^2 - 1, s2^4 - s0^3 - y^2 - 2, y*s0^3 - - s2^2 + y, Affine Curve over Finite Field of size 5 defined by s0^3*s1 + z*s1^3 + s1^4 - 2*s1^3 - 1, - z*s0^3 + z*s1^3 - 2*s0^3 - 2*s1^3 - 1, z^2*s1^3 + z*s1^3 - s1^3 - z + s1 + 2) + (Affine Curve over Finite Field of size 5 + defined by x^2 - s1, s1^4 - x*s2^2 + s1, x*s1^3 - s2^2 + x, + Affine Curve over Finite Field of size 5 + defined by y*s2^2 - y^2 - 1, s2^4 - s0^3 - y^2 - 2, y*s0^3 - s2^2 + y, + Affine Curve over Finite Field of size 5 + defined by s0^3*s1 + z*s1^3 + s1^4 - 2*s1^3 - 1, + z*s0^3 + z*s1^3 - 2*s0^3 - 2*s1^3 - 1, + z^2*s1^3 + z*s1^3 - s1^3 - z + s1 + 2) :: sage: A.<x,y,z,w> = AffineSpace(QQ, 4) - sage: C = A.curve([((x - 2)^2 + y^2)^2 - (x - 2)^2 - y^2 + (x - 2)^3, z - y - 7, w - 4]) + sage: C = A.curve([((x - 2)^2 + y^2)^2 - (x - 2)^2 - y^2 + (x - 2)^3, + ....: z - y - 7, w - 4]) sage: B = C.resolution_of_singularities() sage: B[0] - (Affine Curve over Rational Field defined by s3, s1 - s2, x^2*s2^4 - - 4*x*s2^4 + 2*x^2*s2^2 + 4*s2^4 - 8*x*s2^2 + x^2 + 7*s2^2 - 3*x + 1, - Affine Curve over Rational Field defined by s3, s2 - 1, y^2*s0^4 + - 2*y^2*s0^2 + y*s0^3 + y^2 - s0^2 - 1, - Affine Curve over Rational Field defined by s3, s1 - 1, z^2*s0^4 - - 14*z*s0^4 + 2*z^2*s0^2 + z*s0^3 + 49*s0^4 - 28*z*s0^2 - 7*s0^3 + z^2 + - 97*s0^2 - 14*z + 48, + (Affine Curve over Rational Field defined by s3, s1 - s2, + x^2*s2^4 - 4*x*s2^4 + 2*x^2*s2^2 + 4*s2^4 - 8*x*s2^2 + + x^2 + 7*s2^2 - 3*x + 1, + Affine Curve over Rational Field defined by s3, s2 - 1, + y^2*s0^4 + 2*y^2*s0^2 + y*s0^3 + y^2 - s0^2 - 1, + Affine Curve over Rational Field defined by s3, s1 - 1, + z^2*s0^4 - 14*z*s0^4 + 2*z^2*s0^2 + z*s0^3 + 49*s0^4 + - 28*z*s0^2 - 7*s0^3 + z^2 + 97*s0^2 - 14*z + 48, Closed subscheme of Affine Space of dimension 4 over Rational Field - defined by: - 1) + defined by: 1) :: @@ -1476,6 +1531,7 @@ def resolution_of_singularities(self, extend=False): working over a number field use extend=True """ # helper function for extending the base field (in the case of working over a number field) + def extension(self): F = self.base_ring() pts = self.change_ring(F.embeddings(QQbar)[0]).rational_points() @@ -1512,8 +1568,9 @@ def extension(self): if C.is_smooth(): raise TypeError("this curve is already nonsingular") else: - raise TypeError("this curve has no singular points over its base field. If working over"\ - " a number field use extend=True") + raise TypeError("this curve has no singular points over " + "its base field. If working over " + "a number field use extend=True") not_resolved = True t = 0 # loop through the patches and blow up each until no patch has singular points @@ -1588,8 +1645,8 @@ def extension(self): b_data = [B[0][i]] # projection map and its inverse t_pi = B[2][i] - coords = [(BC.ambient_space().gens()[j] - pts[0][j])/(BC.ambient_space().gens()[i] - pts[0][i]) for\ - j in range(n)] + coords = [(BC.ambient_space().gens()[j] - pts[0][j]) / (BC.ambient_space().gens()[i] - pts[0][i]) + for j in range(n)] coords.pop(i) coords.insert(0, BC.ambient_space().gens()[i]) H = Hom(BC, B[0][i]) @@ -1598,7 +1655,7 @@ def extension(self): # with the projection map L = list(t_maps) for j in range(len(t_maps)): - L[j] = L[j]*t_pi + L[j] = L[j] * t_pi for j in range(len(B[1][i])): L.insert(t + j, B[1][i][j]) b_data.append(L) @@ -1653,15 +1710,13 @@ def tangent_line(self, p): sage: Tp = C.tangent_space(p) sage: Tp - Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: - x + y + z, - 2*x + 3*z + Closed subscheme of Affine Space of dimension 3 over Rational Field + defined by: x + y + z, 2*x + 3*z sage: phi = A3.translation(A3.origin(), p) sage: T = phi * Tp.embedding_morphism() sage: T.image() - Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: - -2*y + z + 1, - x + y + z + Closed subscheme of Affine Space of dimension 3 over Rational Field + defined by: -2*y + z + 1, x + y + z sage: _ == C.tangent_line(p) True @@ -1678,11 +1733,11 @@ def tangent_line(self, p): from sage.schemes.curves.constructor import Curve # translate to p - I = [] + I0 = [] for poly in Tp.defining_polynomials(): - I.append(poly.subs({x: x - c for x, c in zip(gens, p)})) + I0.append(poly.subs({x: x - c for x, c in zip(gens, p)})) - return Curve(I, A) + return Curve(I0, A) class AffinePlaneCurve_field(AffinePlaneCurve, AffineCurve_field): @@ -1691,11 +1746,32 @@ class AffinePlaneCurve_field(AffinePlaneCurve, AffineCurve_field): """ _point = AffinePlaneCurvePoint_field - def fundamental_group(self): + @cached_method + def fundamental_group(self, simplified=True, puiseux=False): r""" Return a presentation of the fundamental group of the complement of ``self``. + INPUT: + + - ``simplified`` -- (default: ``True``) boolean to simplify the presentation. + + - ``puiseux`` -- (default: ``False``) boolean to decide if the + presentation is constructed in the classical way or using Puiseux + shortcut. If ``True``, ``simplified`` is set to ``False``. + + OUTPUT: + + A presentation with generators `x_1, \dots, x_d` and relations. If ``puiseux`` + is ``False`` the relations are `(x_j\cdot \tau)\cdot x_j^{-1}` for `1\leq j<d` + and `tau` a braid in the braid monodromy; finally the presentation + is simplified. If ``puiseux`` is ``True``, each + `tau` is decomposed as `\alpha^{-1}\cdot\beta\cdot\alpha`, where `\beta` is + a positive braid; the relations are `((x_j\cdot \beta)\cdot x_j^{-1})\cdot \alpha` + where `j` is an integer of the ``Tietze`` word of `\beta`. This presentation + is not simplified by default since it represents the homotopy type of + the complement of the curve. + .. NOTE:: The curve must be defined over the rationals or a number field @@ -1703,36 +1779,39 @@ def fundamental_group(self): EXAMPLES:: + sage: # optional - sirocco sage: A.<x,y> = AffineSpace(QQ, 2) sage: C = A.curve(y^2 - x^3 - x^2) - sage: C.fundamental_group() # optional - sirocco + sage: C.fundamental_group() + Finitely presented group < x0 | > + sage: bm = C.braid_monodromy() + sage: g = C.fundamental_group(puiseux=True) + sage: g.sorted_presentation() + Finitely presented group < x0, x1 | x1^-1*x0^-1*x1*x0, x1^-1*x0 > + sage: g.simplified() Finitely presented group < x0 | > In the case of number fields, they need to have an embedding to the algebraic field:: - sage: a = QQ[x](x^2+5).roots(QQbar)[0][0] + sage: # needs sage.rings.number_field + sage: a = QQ[x](x^2 + 5).roots(QQbar)[0][0] sage: F = NumberField(a.minpoly(), 'a', embedding=a) sage: F.inject_variables() Defining a sage: A.<x,y> = AffineSpace(F, 2) sage: C = A.curve(y^2 - a*x^3 - x^2) - sage: C.fundamental_group() # optional - sirocco + sage: C.fundamental_group() # optional - sirocco Finitely presented group < x0 | > .. WARNING:: This functionality requires the sirocco package to be installed. """ - from sage.schemes.curves.zariski_vankampen import fundamental_group - F = self.base_ring() - from sage.rings.qqbar import QQbar - if QQbar.coerce_map_from(F) is None: - raise NotImplementedError("the base field must have an embedding" - " to the algebraic field") - f = self.defining_polynomial() - return fundamental_group(f, projective=False) + from sage.schemes.curves.zariski_vankampen import fundamental_group_from_braid_mon + return fundamental_group_from_braid_mon(self.braid_monodromy(), simplified=simplified, puiseux=puiseux) + @cached_method def braid_monodromy(self): r""" Compute the braid monodromy of a projection of the curve. @@ -1741,7 +1820,7 @@ def braid_monodromy(self): A list of braids. The braids correspond to paths based in the same point; each of this paths is the conjugated of a loop around one of the points - in the discriminant of the projection of `self`. + in the discriminant of the projection of ``self``. NOTE: @@ -1752,7 +1831,7 @@ def braid_monodromy(self): sage: A.<x,y> = AffineSpace(QQ, 2) sage: C = A.curve((x^2-y^3)*(x+3*y-5)) - sage: C.braid_monodromy() # optional - sirocco + sage: C.braid_monodromy() # optional - sirocco [s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1, s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1, s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1, @@ -1766,26 +1845,24 @@ def braid_monodromy(self): raise NotImplementedError("the base field must have an embedding" " to the algebraic field") f = self.defining_polynomial() - return braid_monodromy(f) - + return braid_monodromy(f)[0] def riemann_surface(self, **kwargs): r""" Return the complex Riemann surface determined by this curve - OUTPUT: - - - RiemannSurface object + OUTPUT: A :class:`~sage.schemes.riemann_surfaces.riemann_surface.RiemannSurface` object. EXAMPLES:: - sage: R.<x,y>=QQ[] - sage: C = Curve(x^3+3*y^3+5) + sage: R.<x,y> = QQ[] + sage: C = Curve(x^3 + 3*y^3 + 5) sage: C.riemann_surface() - Riemann surface defined by polynomial f = x^3 + 3*y^3 + 5 = 0, with 53 bits of precision + Riemann surface defined by polynomial f = x^3 + 3*y^3 + 5 = 0, + with 53 bits of precision """ from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface - S = RiemannSurface(self.defining_polynomial(),**kwargs) + S = RiemannSurface(self.defining_polynomial(), **kwargs) S._curve = self return S @@ -1815,11 +1892,11 @@ def riemann_roch_basis(self, D): divisor `Div = d_1P_1 + \dots + d_nP_n`, where `X(F) = \{P_1, \dots, P_n\}`. The ordering is that dictated by ``places_on_curve``. - OUTPUT: a basis of `L(Div)` + OUTPUT: A basis of `L(Div)`. EXAMPLES:: - sage: R = PolynomialRing(GF(5),2,names = ["x","y"]) + sage: R = PolynomialRing(GF(5), 2, names=["x","y"]) sage: x, y = R.gens() sage: f = y^2 - x^9 - x sage: C = Curve(f) @@ -1891,17 +1968,19 @@ def rational_points(self, algorithm="enum"): sage: v == w True - sage: A.<x,y> = AffineSpace(2,GF(9,'a')) - sage: C = Curve(x^2 + y^2 - 1) - sage: C - Affine Plane Curve over Finite Field in a of size 3^2 defined by x^2 + y^2 - 1 + sage: # needs sage.rings.finite_rings + sage: A.<x,y> = AffineSpace(2, GF(9,'a')) + sage: C = Curve(x^2 + y^2 - 1); C + Affine Plane Curve over Finite Field in a of size 3^2 + defined by x^2 + y^2 - 1 sage: C.rational_points() - [(0, 1), (0, 2), (1, 0), (2, 0), (a + 1, a + 1), (a + 1, 2*a + 2), (2*a + 2, a + 1), (2*a + 2, 2*a + 2)] + [(0, 1), (0, 2), (1, 0), (2, 0), (a + 1, a + 1), + (a + 1, 2*a + 2), (2*a + 2, a + 1), (2*a + 2, 2*a + 2)] """ if algorithm == "enum": f = self.defining_polynomial() K = f.parent().base_ring() - return sorted((self((x,y)) for x in K for y in K if f(x,y) == 0)) + return sorted(self((x, y)) for x in K for y in K if f(x, y) == 0) F = self.base_ring() if not F.is_prime_field(): @@ -1961,9 +2040,9 @@ def function_field(self): :: - sage: A.<x,y> = AffineSpace(GF(8), 2) - sage: C = Curve(x^5 + y^5 + x*y + 1) - sage: C.function_field() + sage: A.<x,y> = AffineSpace(GF(8), 2) # needs sage.rings.finite_rings + sage: C = Curve(x^5 + y^5 + x*y + 1) # needs sage.rings.finite_rings + sage: C.function_field() # needs sage.rings.finite_rings Function field in y defined by y^5 + x*y + x^5 + 1 """ return self._function_field @@ -1997,6 +2076,7 @@ def __call__(self, *args): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A.<x,y> = AffineSpace(GF(8), 2) sage: C = Curve(x^5 + y^5 + x*y + 1) sage: C(1,1) @@ -2037,6 +2117,7 @@ def function(self, f): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A.<x,y> = AffineSpace(GF(8), 2) sage: C = Curve(x^5 + y^5 + x*y + 1) sage: f = C.function(x/y) @@ -2044,7 +2125,7 @@ def function(self, f): (x/(x^5 + 1))*y^4 + x^2/(x^5 + 1) sage: df = f.differential(); df ((1/(x^10 + 1))*y^4 + x^6/(x^10 + 1)) d(x) - sage: df.divisor() + sage: df.divisor() # long time 2*Place (1/x, 1/x^4*y^4 + 1/x^3*y^3 + 1/x^2*y^2 + 1/x*y + 1) + 2*Place (1/x, 1/x*y + 1) - 2*Place (x + 1, y) @@ -2057,7 +2138,7 @@ def function(self, f): phi = self._lift_to_function_field num = R(f.numerator()) den = R(f.denominator()) - return phi(num)/phi(den) + return phi(num) / phi(den) def coordinate_functions(self): """ @@ -2065,6 +2146,7 @@ def coordinate_functions(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A.<x,y> = AffineSpace(GF(8), 2) sage: C = Curve(x^5 + y^5 + x*y + 1) sage: x, y = C.coordinate_functions() @@ -2088,8 +2170,10 @@ def _nonsingular_model(self): sage: A.<x,y,z> = AffineSpace(GF(11), 3) sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A) sage: C._nonsingular_model - (Function field in z defined by z^3 + 10*x, Ring morphism: - From: Multivariate Polynomial Ring in x, y, z over Finite Field of size 11 + (Function field in z defined by z^3 + 10*x, + Ring morphism: + From: Multivariate Polynomial Ring in x, y, z + over Finite Field of size 11 To: Function field in z defined by z^3 + 10*x Defn: x |--> x y |--> z^2 @@ -2098,18 +2182,18 @@ def _nonsingular_model(self): from sage.rings.function_field.constructor import FunctionField k = self.base_ring() - I = self.defining_ideal() + I0 = self.defining_ideal() # invlex is the lex order with x < y < z for R = k[x,y,z] for instance - R = I.parent().ring().change_ring(order='invlex') - I = I.change_ring(R) + R = I0.parent().ring().change_ring(order='invlex') + I0 = I0.change_ring(R) n = R.ngens() names = R.variable_names() - gbasis = I.groebner_basis() + gbasis = I0.groebner_basis() - if not I.is_prime(): + if not I0.is_prime(): raise TypeError("the curve is not integral") # Suppose the generators of the defining ideal I of the curve is @@ -2179,7 +2263,7 @@ def _nonsingular_model(self): lift_to_function_field = hom(R, M, coordinate_functions) # sanity check - assert all(lift_to_function_field(f).is_zero() for f in I.gens()) + assert all(lift_to_function_field(f).is_zero() for f in I0.gens()) return M, lift_to_function_field @@ -2208,7 +2292,8 @@ def _lift_to_function_field(self): sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A) sage: C._lift_to_function_field Ring morphism: - From: Multivariate Polynomial Ring in x, y, z over Finite Field of size 11 + From: Multivariate Polynomial Ring in x, y, z + over Finite Field of size 11 To: Function field in z defined by z^3 + 10*x Defn: x |--> x y |--> z^2 @@ -2237,9 +2322,9 @@ def _singularities(self): TESTS:: - sage: A.<x,y> = AffineSpace(GF(7^2),2) - sage: C = Curve(x^2 - x^4 - y^4) - sage: C._singularities + sage: A.<x,y> = AffineSpace(GF(7^2), 2) # needs sage.rings.finite_rings + sage: C = Curve(x^2 - x^4 - y^4) # needs sage.rings.finite_rings + sage: C._singularities # long time # needs sage.rings.finite_rings [(Point (x, y), [Place (x, 1/x*y^3 + 1/x*y^2 + 1), Place (x, 1/x*y^3 + 1/x*y^2 + 6)])] """ @@ -2268,7 +2353,7 @@ def _singularities(self): if p == q: places.append(place) break - else: # new singularity + else: # new singularity points.append((p, [place])) return points @@ -2279,9 +2364,9 @@ def singular_closed_points(self): EXAMPLES:: - sage: A.<x,y> = AffineSpace(GF(7^2),2) - sage: C = Curve(x^2 - x^4 - y^4) - sage: C.singular_closed_points() + sage: A.<x,y> = AffineSpace(GF(7^2), 2) # needs sage.rings.finite_rings + sage: C = Curve(x^2 - x^4 - y^4) # needs sage.rings.finite_rings + sage: C.singular_closed_points() # needs sage.rings.finite_rings [Point (x, y)] :: @@ -2304,6 +2389,7 @@ def place_to_closed_point(self, place): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A.<x,y> = AffineSpace(GF(4), 2) sage: C = Curve(x^5 + y^5 + x*y + 1) sage: F = C.function_field() @@ -2329,18 +2415,18 @@ def place_to_closed_point(self, place): # implement an FGLM-like algorithm e = [0 for i in range(R.ngens())] basis = [R.one()] - basis_vecs = [to_V(k.one())] # represent as a vector + basis_vecs = [to_V(k.one())] # represent as a vector gens = [] gens_lts = [] terminate = False - while True: # check FGLM termination condition + while True: # check FGLM termination condition # compute next exponent in degree reverse lexicographical order j = R.ngens() - 1 while j > 0 and not e[j]: j -= 1 - if not j: # j is zero + if not j: # j is zero if terminate: break terminate = True @@ -2349,7 +2435,7 @@ def place_to_closed_point(self, place): e[-1] = d + 1 else: e[j] -= 1 - e[j-1] += 1 + e[j - 1] += 1 m = R.monomial(*e) if any(g.divides(m) for g in gens_lts): @@ -2358,11 +2444,11 @@ def place_to_closed_point(self, place): prod = 1 for i in range(R.ngens()): prod *= coords[i]**e[i] - vec = to_V(to_k(prod)) # represent as a vector + vec = to_V(to_k(prod)) # represent as a vector mat = matrix(basis_vecs) try: s = mat.solve_left(vec) - except ValueError: # no solution + except ValueError: # no solution basis.append(m) basis_vecs.append(vec) terminate = False @@ -2388,6 +2474,7 @@ def places_at_infinity(self): :: + sage: # needs sage.rings.finite_rings sage: F = GF(9) sage: A2.<x,y> = AffineSpace(F, 2) sage: C = A2.curve(y^3 + y - x^4) @@ -2397,7 +2484,7 @@ def places_at_infinity(self): :: sage: A.<x,y,z> = AffineSpace(GF(11), 3) - sage: C = Curve([x*z-y^2,y-z^2,x-y*z], A) + sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A) sage: C.places_at_infinity() [Place (1/x, 1/x*z^2)] """ @@ -2411,7 +2498,7 @@ def places_on(self, point): - ``point`` -- a closed point of the curve - OUTPUT: a list of the places of the function field of the curve + OUTPUT: A list of the places of the function field of the curve. EXAMPLES:: @@ -2425,8 +2512,9 @@ def places_on(self, point): :: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(9) - sage: A.<x,y> = AffineSpace(k,2) + sage: A.<x,y> = AffineSpace(k, 2) sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2) sage: pts = C.closed_points() sage: pts @@ -2450,6 +2538,7 @@ def places_on(self, point): :: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(8) sage: P.<x,y,z> = ProjectiveSpace(F, 2) sage: Cp = Curve(x^3*y + y^3*z + x*z^3) @@ -2487,6 +2576,7 @@ def parametric_representation(self, place, name=None): :: + sage: # needs sage.rings.finite_rings sage: A.<x,y> = AffineSpace(GF(7^2), 2) sage: C = Curve(x^2 - x^4 - y^4) sage: p, = C.singular_closed_points() @@ -2520,7 +2610,8 @@ class IntegralAffineCurve_finite_field(IntegralAffineCurve): sage: A.<x,y,z> = AffineSpace(GF(11), 3) sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A); C - Affine Curve over Finite Field of size 11 defined by -y^2 + x*z, -z^2 + y, -y*z + x + Affine Curve over Finite Field of size 11 + defined by -y^2 + x*z, -z^2 + y, -y*z + x sage: C.function_field() Function field in z defined by z^3 + 10*x """ @@ -2536,6 +2627,7 @@ def places(self, degree=1): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(9) sage: A2.<x,y> = AffineSpace(F, 2) sage: C = A2.curve(y^3 + y - x^4) @@ -2583,7 +2675,7 @@ def closed_points(self, degree=1): EXAMPLES:: - sage: A.<x,y> = AffineSpace(GF(7),2) + sage: A.<x,y> = AffineSpace(GF(7), 2) sage: C = Curve(x^2 - x^4 - y^4) sage: C.closed_points() [Point (x, y), @@ -2610,9 +2702,9 @@ def closed_points(self, degree=1): for place in places_above: try: p = self.place_to_closed_point(place) - except ValueError: # place is at infinity + except ValueError: # place is at infinity continue - assert p.degree() == degree # sanity check + assert p.degree() == degree # sanity check points.append(p) return points @@ -2628,10 +2720,11 @@ class IntegralAffinePlaneCurve_finite_field(AffinePlaneCurve_finite_field, Integ EXAMPLES:: - sage: A.<x,y> = AffineSpace(GF(8), 2) - sage: C = Curve(x^5 + y^5 + x*y + 1); C - Affine Plane Curve over Finite Field in z3 of size 2^3 defined by x^5 + y^5 + x*y + 1 - sage: C.function_field() + sage: A.<x,y> = AffineSpace(GF(8), 2) # needs sage.rings.finite_rings + sage: C = Curve(x^5 + y^5 + x*y + 1); C # needs sage.rings.finite_rings + Affine Plane Curve over Finite Field in z3 of size 2^3 + defined by x^5 + y^5 + x*y + 1 + sage: C.function_field() # needs sage.rings.finite_rings Function field in y defined by y^5 + x*y + x^5 + 1 """ _point = IntegralAffinePlaneCurvePoint_finite_field diff --git a/src/sage/schemes/curves/closed_point.py b/src/sage/schemes/curves/closed_point.py index 9d881016bb7..0b5952559c1 100644 --- a/src/sage/schemes/curves/closed_point.py +++ b/src/sage/schemes/curves/closed_point.py @@ -10,7 +10,7 @@ EXAMPLES:: sage: F.<a> = GF(2) - sage: P.<x,y> = AffineSpace(F, 2); + sage: P.<x,y> = AffineSpace(F, 2) sage: C = Curve(y^2 + y - x^3) sage: C.closed_points() [Point (x, y), Point (x, y + 1)] @@ -99,8 +99,9 @@ class IntegralCurveClosedPoint(CurveClosedPoint): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) - sage: P.<x,y> = AffineSpace(F, 2); + sage: P.<x,y> = AffineSpace(F, 2) sage: C = Curve(y^2 + y - x^3) sage: C.closed_points() [Point (x, y), @@ -118,8 +119,9 @@ def __init__(self, curve, prime_ideal, degree): TESTS:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) - sage: P.<x,y> = AffineSpace(F, 2); + sage: P.<x,y> = AffineSpace(F, 2) sage: C = Curve(y^2 + y - x^3) sage: p = C([0,0]); p (0, 0) @@ -137,15 +139,16 @@ def __hash__(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) - sage: P.<x,y> = AffineSpace(F, 2); + sage: P.<x,y> = AffineSpace(F, 2) sage: C = Curve(y^2 + y - x^3) sage: pts = C.closed_points() sage: p = pts[0] sage: {p: 1} {Point (x, y): 1} """ - return hash((self.parent(),self.prime_ideal())) + return hash((self.parent(), self.prime_ideal())) def _richcmp_(self, other, op): """ @@ -159,8 +162,9 @@ def _richcmp_(self, other, op): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) - sage: P.<x,y> = AffineSpace(F, 2); + sage: P.<x,y> = AffineSpace(F, 2) sage: C = Curve(y^2 + y - x^3) sage: pts = C.closed_points() sage: pts[0] == pts[1] @@ -174,8 +178,9 @@ def _repr_(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) - sage: P.<x,y> = AffineSpace(F, 2); + sage: P.<x,y> = AffineSpace(F, 2) sage: C = Curve(y^2 + y - x^3) sage: pts = C.closed_points() sage: pts[0] @@ -189,8 +194,9 @@ def curve(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) - sage: P.<x,y> = AffineSpace(F, 2); + sage: P.<x,y> = AffineSpace(F, 2) sage: C = Curve(y^2 + y - x^3) sage: pts = C.closed_points() sage: p = pts[0] @@ -205,8 +211,9 @@ def degree(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) - sage: P.<x,y> = AffineSpace(F, 2); + sage: P.<x,y> = AffineSpace(F, 2) sage: C = Curve(y^2 + y - x^3) sage: pts = C.closed_points() sage: p = pts[0] @@ -221,8 +228,9 @@ def places(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) - sage: P.<x,y> = AffineSpace(F, 2); + sage: P.<x,y> = AffineSpace(F, 2) sage: C = Curve(y^2 + y - x^3) sage: pts = C.closed_points() sage: p = pts[0] @@ -239,8 +247,9 @@ def place(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) - sage: P.<x,y> = AffineSpace(F, 2); + sage: P.<x,y> = AffineSpace(F, 2) sage: C = Curve(y^2 + y - x^3) sage: pts = C.closed_points() sage: p = pts[0] @@ -260,8 +269,9 @@ def rational_point(self): EXAMPLES:: - sage: A.<x,y> = AffineSpace(GF(3^2),2) - sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x-2) + sage: # needs sage.rings.finite_rings + sage: A.<x,y> = AffineSpace(GF(3^2), 2) + sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2) sage: C.closed_points() [Point (x, y + (z2 + 1)), Point (x, y + (-z2 - 1)), @@ -349,6 +359,7 @@ def rational_point(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) sage: P.<x,y,z> = ProjectiveSpace(F, 2) sage: C = Curve(x^3*y + y^3*z + x*z^3) diff --git a/src/sage/schemes/curves/constructor.py b/src/sage/schemes/curves/constructor.py index fc3d174de59..6fe15a2efc2 100644 --- a/src/sage/schemes/curves/constructor.py +++ b/src/sage/schemes/curves/constructor.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular """ Curve constructor @@ -14,7 +15,8 @@ sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2) sage: Curve(y^2*z^7 - x^9 - x*z^8) - Projective Plane Curve over Finite Field of size 5 defined by -x^9 + y^2*z^7 - x*z^8 + Projective Plane Curve over Finite Field of size 5 + defined by -x^9 + y^2*z^7 - x*z^8 AUTHORS: @@ -25,20 +27,20 @@ - Grayson Jorgenson (2016-06) """ -#********************************************************************* +# ******************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#********************************************************************* +# https://www.gnu.org/licenses/ +# ******************************************************************** from sage.categories.fields import Fields -from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial +from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.rational_field import QQ @@ -49,9 +51,9 @@ from sage.schemes.generic.algebraic_scheme import is_AlgebraicScheme from sage.schemes.projective.projective_space import is_ProjectiveSpace -from sage.schemes.affine.all import AffineSpace +from sage.schemes.affine.affine_space import AffineSpace -from sage.schemes.projective.all import ProjectiveSpace +from sage.schemes.projective.projective_space import ProjectiveSpace from .projective_curve import (ProjectiveCurve, @@ -77,7 +79,8 @@ from sage.schemes.plane_conics.constructor import Conic -def _is_irreducible_and_reduced(F): + +def _is_irreducible_and_reduced(F) -> bool: """ Check if the polynomial F is irreducible and reduced. @@ -92,6 +95,7 @@ def _is_irreducible_and_reduced(F): factors = F.factor() return len(factors) == 1 and factors[0][1] == 1 + def Curve(F, A=None): """ Return the plane or space curve defined by ``F``, where ``F`` can be either @@ -168,24 +172,25 @@ def Curve(F, A=None): The intersection is not a curve, though it is a scheme. :: sage: X = C.intersection(D); X - Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x^3 + y^3 + z^3, - x^4 + y^4 + z^4 + Closed subscheme of Projective Space of dimension 2 over Rational Field + defined by: x^3 + y^3 + z^3, + x^4 + y^4 + z^4 Note that the intersection has dimension 0. :: sage: X.dimension() 0 sage: I = X.defining_ideal(); I - Ideal (x^3 + y^3 + z^3, x^4 + y^4 + z^4) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (x^3 + y^3 + z^3, x^4 + y^4 + z^4) of + Multivariate Polynomial Ring in x, y, z over Rational Field If only a polynomial in three variables is given, then it must be homogeneous such that a projective curve is constructed. :: sage: x,y,z = QQ['x,y,z'].gens() - sage: Curve(x^2+y^2) + sage: Curve(x^2 + y^2) Projective Conic Curve over Rational Field defined by x^2 + y^2 - sage: Curve(x^2+y^2+z) + sage: Curve(x^2 + y^2 + z) Traceback (most recent call last): ... TypeError: x^2 + y^2 + z is not a homogeneous polynomial @@ -203,7 +208,7 @@ def Curve(F, A=None): The defining polynomial must be nonzero unless the ambient space itself is of dimension 1. :: - sage: P1.<x,y> = ProjectiveSpace(1,GF(5)) + sage: P1.<x,y> = ProjectiveSpace(1, GF(5)) sage: S = P1.coordinate_ring() sage: Curve(S(0), P1) Projective Line over Finite Field of size 5 @@ -237,9 +242,9 @@ def Curve(F, A=None): A._coordinate_ring = P break else: - A = ProjectiveSpace(P.ngens()-1, P.base_ring(), names=P.variable_names()) + A = ProjectiveSpace(P.ngens() - 1, P.base_ring(), names=P.variable_names()) A._coordinate_ring = P - elif is_MPolynomial(F): # define a plane curve + elif isinstance(F, MPolynomial): # define a plane curve P = F.parent() k = F.base_ring() @@ -294,7 +299,7 @@ def Curve(F, A=None): if is_AffineSpace(A): if n != 2: - if is_FiniteField(k): + if isinstance(k, FiniteField): if A.coordinate_ring().ideal(F).is_prime(): return IntegralAffineCurve_finite_field(A, F) if k in Fields(): @@ -307,7 +312,7 @@ def Curve(F, A=None): raise TypeError("need a single nonconstant polynomial to define a plane curve") F = F[0] - if is_FiniteField(k): + if isinstance(k, FiniteField): if _is_irreducible_and_reduced(F): return IntegralAffinePlaneCurve_finite_field(A, F) return AffinePlaneCurve_finite_field(A, F) @@ -321,7 +326,7 @@ def Curve(F, A=None): if n != 2: if not all(f.is_homogeneous() for f in F): raise TypeError("polynomials defining a curve in a projective space must be homogeneous") - if is_FiniteField(k): + if isinstance(k, FiniteField): if A.coordinate_ring().ideal(F).is_prime(): return IntegralProjectiveCurve_finite_field(A, F) if k in Fields(): @@ -339,7 +344,7 @@ def Curve(F, A=None): if not F.is_homogeneous(): raise TypeError("{} is not a homogeneous polynomial".format(F)) - if is_FiniteField(k): + if isinstance(k, FiniteField): if _is_irreducible_and_reduced(F): return IntegralProjectivePlaneCurve_finite_field(A, F) return ProjectivePlaneCurve_finite_field(A, F) diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py index e5576459629..0af6fff803b 100644 --- a/src/sage/schemes/curves/curve.py +++ b/src/sage/schemes/curves/curve.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular """ Base class of curves @@ -20,14 +21,14 @@ - William Stein (2005) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.latex import latex @@ -40,14 +41,15 @@ from sage.rings.integer import Integer + class Curve_generic(AlgebraicScheme_subscheme): r""" Generic curve class. EXAMPLES:: - sage: A.<x,y,z> = AffineSpace(QQ,3) - sage: C = Curve([x-y,z-2]) + sage: A.<x,y,z> = AffineSpace(QQ, 3) + sage: C = Curve([x - y, z - 2]) sage: loads(C.dumps()) == C True """ @@ -57,23 +59,23 @@ def _repr_(self): EXAMPLES:: - sage: A.<x,y,z> = AffineSpace(QQ,3) - sage: C = Curve([x-y,z-2]) + sage: A.<x,y,z> = AffineSpace(QQ, 3) + sage: C = Curve([x - y, z - 2]) sage: C Affine Curve over Rational Field defined by x - y, z - 2 - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: C = Curve(x-y) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: C = Curve(x - y) sage: C Projective Plane Curve over Rational Field defined by x - y """ if self.defining_ideal().is_zero() and self.ambient_space().dimension() == 1: return "{} Line over {}".format(self._repr_type(), self.base_ring()) + polys = ', '.join(str(x) for x in self.defining_polynomials()) return "{} Curve over {} defined by {}".format(self._repr_type(), - self.base_ring(), - ', '.join(str(x) for x in self.defining_polynomials())) + self.base_ring(), polys) - def _repr_type(self): + def _repr_type(self) -> str: r""" Return a string representation of the type of this curve. @@ -219,13 +221,13 @@ def geometric_genus(self): sage: x, y, z = P2.coordinate_ring().gens() sage: C = Curve(y^2*z - x^3 - 17*x*z^2 + y*z^2) sage: C.geometric_genus() - 1 + 1 sage: C = Curve(y^2*z - x^3) sage: C.geometric_genus() - 0 + 0 sage: C = Curve(x^10 + y^7*z^3 + z^10) sage: C.geometric_genus() - 3 + 3 Examples of affine curves. :: @@ -278,7 +280,7 @@ def singular_subscheme(self): sage: C = Curve([y^4 - 2*x^5 - x^2*y], A) sage: C.singular_subscheme() Closed subscheme of Affine Space of dimension 2 over Complex Field - with 53 bits of precision defined by: + with 53 bits of precision defined by: (-2.00000000000000)*x^5 + y^4 - x^2*y, (-10.0000000000000)*x^4 + (-2.00000000000000)*x*y, 4.00000000000000*y^3 - x^2 @@ -288,16 +290,16 @@ def singular_subscheme(self): sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([y^8 - x^2*z*w^5, w^2 - 2*y^2 - x*z], P) sage: C.singular_subscheme() - Closed subscheme of Projective Space of dimension 3 over Rational - Field defined by: + Closed subscheme of Projective Space of dimension 3 + over Rational Field defined by: y^8 - x^2*z*w^5, -2*y^2 - x*z + w^2, -x^3*y*z^4 + 3*x^2*y*z^3*w^2 - 3*x*y*z^2*w^4 + 8*x*y*z*w^5 + y*z*w^6, x^2*z*w^5, -5*x^2*z^2*w^4 - 4*x*z*w^6, x^4*y*z^3 - 3*x^3*y*z^2*w^2 + 3*x^2*y*z*w^4 - 4*x^2*y*w^5 - x*y*w^6, - -2*x^3*y*z^3*w + 6*x^2*y*z^2*w^3 - 20*x^2*y*z*w^4 - 6*x*y*z*w^5 + - 2*y*w^7, + -2*x^3*y*z^3*w + 6*x^2*y*z^2*w^3 - 20*x^2*y*z*w^4 + - 6*x*y*z*w^5 + 2*y*w^7, -5*x^3*z*w^4 - 2*x^2*w^6 """ return self.ambient_space().subscheme(self.Jacobian()) @@ -322,12 +324,13 @@ def singular_points(self, F=None): :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^8 - a^4 + 1) sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: C = Curve([359/12*x*y^2*z^2 + 2*y*z^4 + 187/12*y^3*z^2 + x*z^4\ - + 67/3*x^2*y*z^2 + 117/4*y^5 + 9*x^5 + 6*x^3*z^2 + 393/4*x*y^4\ - + 145*x^2*y^3 + 115*x^3*y^2 + 49*x^4*y], P) + sage: C = Curve([359/12*x*y^2*z^2 + 2*y*z^4 + 187/12*y^3*z^2 + x*z^4 + ....: + 67/3*x^2*y*z^2 + 117/4*y^5 + 9*x^5 + 6*x^3*z^2 + ....: + 393/4*x*y^4 + 145*x^2*y^3 + 115*x^3*y^2 + 49*x^4*y], P) sage: sorted(C.singular_points(K), key=str) [(-1/2*b^5 - 1/2*b^3 + 1/2*b - 1 : 1 : 0), (-2/3*b^4 + 1/3 : 0 : 1), @@ -416,13 +419,13 @@ def intersects_at(self, C, P): False """ if C.ambient_space() != self.ambient_space(): - raise TypeError("(=%s) must be a curve in the same ambient space as (=%s)"%(C,self)) + raise TypeError("(=%s) must be a curve in the same ambient space as (=%s)" % (C, self)) if not isinstance(C, Curve_generic): - raise TypeError("(=%s) must be a curve"%C) + raise TypeError("(=%s) must be a curve" % C) try: P = self.ambient_space()(P) except TypeError: - raise TypeError("(=%s) must be a point in the ambient space of this curve"%P) + raise TypeError("(=%s) must be a point in the ambient space of this curve" % P) try: P = self(P) P = C(P) @@ -450,14 +453,15 @@ def intersection_points(self, C, F=None): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^2 + a + 1) sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([y^2 - w*z, w^3 - y^3], P) sage: D = Curve([x*y - w*z, z^3 - y^3], P) sage: C.intersection_points(D, F=K) - [(-b - 1 : -b - 1 : b : 1), (b : b : -b - 1 : 1), (1 : 0 : 0 : 0), - (1 : 1 : 1 : 1)] + [(-b - 1 : -b - 1 : b : 1), (b : b : -b - 1 : 1), + (1 : 0 : 0 : 0), (1 : 1 : 1 : 1)] :: @@ -465,8 +469,7 @@ def intersection_points(self, C, F=None): sage: C = Curve([y^3 - x^3], A) sage: D = Curve([-x*y^3 + y^4 - 2*x^3 + 2*x^2*y], A) sage: C.intersection_points(D) - [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 3), (5, 5), (5, 6), - (6, 6)] + [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 3), (5, 5), (5, 6), (6, 6)] :: @@ -480,9 +483,9 @@ def intersection_points(self, C, F=None): (=Rational Field) must be a finite field """ if C.ambient_space() != self.ambient_space(): - raise TypeError("(=%s) must be a curve in the same ambient space as (=%s)"%(C,self)) + raise TypeError("(=%s) must be a curve in the same ambient space as (=%s)" % (C, self)) if not isinstance(C, Curve_generic): - raise TypeError("(=%s) must be a curve"%C) + raise TypeError("(=%s) must be a curve" % C) X = self.intersection(C) if F is None: F = self.base_ring() @@ -506,11 +509,13 @@ def change_ring(self, R): sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: C = Curve([x^2 - y^2, z*y - 4/5*w^2], P) - sage: C.change_ring(QuadraticField(-1)) - Projective Curve over Number Field in a with defining polynomial x^2 + 1 with a = 1*I defined by x^2 - y^2, y*z - 4/5*w^2 + sage: C.change_ring(QuadraticField(-1)) # needs sage.rings.number_field + Projective Curve over Number Field in a with defining polynomial x^2 + 1 + with a = 1*I defined by x^2 - y^2, y*z - 4/5*w^2 :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^3 + a^2 - 1) sage: A.<x,y> = AffineSpace(K, 2) @@ -518,8 +523,8 @@ def change_ring(self, R): sage: L = K.embeddings(QQbar) sage: set_verbose(-1) # suppress warnings for slow computation sage: C.change_ring(L[0]) - Affine Plane Curve over Algebraic Field defined by y^3 + - (-0.8774388331233464? - 0.744861766619745?*I)*x^2 - x - 11 + Affine Plane Curve over Algebraic Field defined + by y^3 + (-0.8774388331233464? - 0.744861766619745?*I)*x^2 - x - 11 :: diff --git a/src/sage/schemes/curves/point.py b/src/sage/schemes/curves/point.py index 0ae3ab7e820..dcc78724497 100644 --- a/src/sage/schemes/curves/point.py +++ b/src/sage/schemes/curves/point.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular """ Rational points of curves @@ -7,8 +8,8 @@ sage: C = Curve([x^3 - 2*x*z^2 - y^3, z^3 - w^3 - x*y*z], P) sage: Q = C([1,1,0,0]) sage: Q.parent() - Set of rational points of Projective Curve over Rational Field defined - by x^3 - y^3 - 2*x*z^2, -x*y*z + z^3 - w^3 + Set of rational points of Projective Curve over Rational Field + defined by x^3 - y^3 - 2*x*z^2, -x*y*z + z^3 - w^3 or on affine curves:: @@ -16,27 +17,28 @@ sage: C = Curve([y - y^4 + 17*x^2 - 2*x + 22], A) sage: Q = C([22,21]) sage: Q.parent() - Set of rational points of Affine Plane Curve over Finite Field of size - 23 defined by -y^4 - 6*x^2 - 2*x + y - 1 + Set of rational points of Affine Plane Curve over Finite Field of size 23 + defined by -y^4 - 6*x^2 - 2*x + y - 1 AUTHORS: - Grayson Jorgenson (2016-6): initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.schemes.affine.affine_point import (SchemeMorphism_point_affine_field, SchemeMorphism_point_affine_finite_field) from sage.schemes.projective.projective_point import (SchemeMorphism_point_projective_field, SchemeMorphism_point_projective_finite_field) + class ProjectiveCurvePoint_field(SchemeMorphism_point_projective_field): """ Point of a projective curve over a field. @@ -112,6 +114,7 @@ def is_ordinary_singularity(self): :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^2 - 3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) @@ -188,7 +191,8 @@ def closed_point(self): break ai = hcoords[i] xi = S.gen(i) - hgens = [ai*S.gen(j) - hcoords[j]*xi for j in range(S.ngens()) if j != i] + hgens = [ai * S.gen(j) - hcoords[j] * xi + for j in range(S.ngens()) if j != i] return curve._closed_point(curve, S.ideal(hgens), degree=1) def places(self): @@ -253,6 +257,7 @@ def is_singular(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K = QuadraticField(-1) sage: A.<x,y,z> = AffineSpace(K, 3) sage: C = Curve([(x^4 + 2*z + 2)*y, z - y + 1]) @@ -352,12 +357,13 @@ def is_transverse(self, D): :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^2 - 2) sage: A.<x,y> = AffineSpace(K, 2) sage: C = Curve([y^2 + x^2 - 1], A) sage: D = Curve([y - x], A) - sage: Q = C([-1/2*b,-1/2*b]) + sage: Q = C([-1/2*b, -1/2*b]) sage: Q.is_transverse(D) True """ @@ -381,6 +387,7 @@ def closed_point(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A.<x,y> = AffineSpace(GF(8), 2) sage: C = Curve(x^5 + y^5 + x*y + 1) sage: p = C([1,1]) @@ -409,9 +416,9 @@ def places(self): Point (x + 1, y + 1) sage: _.places() [Place (x + 1, (1/(x^5 + 1))*y^4 + ((x^5 + x^4 + 1)/(x^5 + 1))*y^3 - + ((x^5 + x^3 + 1)/(x^5 + 1))*y^2 + (x^2/(x^5 + 1))*y), Place (x + - 1, (1/(x^5 + 1))*y^4 + ((x^5 + x^4 + 1)/(x^5 + 1))*y^3 + (x^3/(x^5 - + 1))*y^2 + (x^2/(x^5 + 1))*y + x + 1)] + + ((x^5 + x^3 + 1)/(x^5 + 1))*y^2 + (x^2/(x^5 + 1))*y), + Place (x + 1, (1/(x^5 + 1))*y^4 + ((x^5 + x^4 + 1)/(x^5 + 1))*y^3 + + (x^3/(x^5 + 1))*y^2 + (x^2/(x^5 + 1))*y + x + 1)] """ return self.closed_point().places() @@ -429,8 +436,8 @@ def place(self): sage: p.closed_point() Point (x + 1, y + 1) sage: _.place() - Place (x + 1, (1/(x^5 + 1))*y^4 + ((x^5 + x^4 + 1)/(x^5 + 1))*y^3 + - ((x^5 + x^3 + 1)/(x^5 + 1))*y^2 + (x^2/(x^5 + 1))*y) + Place (x + 1, (1/(x^5 + 1))*y^4 + ((x^5 + x^4 + 1)/(x^5 + 1))*y^3 + + ((x^5 + x^3 + 1)/(x^5 + 1))*y^2 + (x^2/(x^5 + 1))*y) """ return self.closed_point().place() @@ -448,6 +455,7 @@ class IntegralAffinePlaneCurvePoint(IntegralAffineCurvePoint, AffinePlaneCurvePo """ pass + class IntegralAffinePlaneCurvePoint_finite_field(AffinePlaneCurvePoint_finite_field, IntegralAffineCurvePoint_finite_field): """ Point of an integral affine plane curve over a finite field. diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index e5a6ba01be1..958a402da19 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.singular r""" Projective curves @@ -173,6 +174,7 @@ IntegralProjectivePlaneCurvePoint_finite_field) from .closed_point import IntegralProjectiveCurveClosedPoint +from sage.misc.persist import register_unpickle_override class ProjectiveCurve(Curve_generic, AlgebraicScheme_subscheme_projective): @@ -189,17 +191,19 @@ class ProjectiveCurve(Curve_generic, AlgebraicScheme_subscheme_projective): sage: P.<x,y,z,w,u> = ProjectiveSpace(GF(7), 4) sage: C = Curve([y*u^2 - x^3, z*u^2 - x^3, w*u^2 - x^3, y^3 - x^3], P); C - Projective Curve over Finite Field of size 7 defined by -x^3 + y*u^2, - -x^3 + z*u^2, -x^3 + w*u^2, -x^3 + y^3 + Projective Curve over Finite Field of size 7 defined + by -x^3 + y*u^2, -x^3 + z*u^2, -x^3 + w*u^2, -x^3 + y^3 :: + sage: # needs sage.rings.number_field sage: K.<u> = CyclotomicField(11) sage: P.<x,y,z,w> = ProjectiveSpace(K, 3) sage: C = Curve([y*w - u*z^2 - x^2, x*w - 3*u^2*z*w], P); C Projective Curve over Cyclotomic Field of order 11 and degree 10 defined - by -x^2 + (-u)*z^2 + y*w, x*w + (-3*u^2)*z*w + by -x^2 + (-u)*z^2 + y*w, x*w + (-3*u^2)*z*w """ + def __init__(self, A, X): """ Initialize. @@ -212,7 +216,7 @@ def __init__(self, A, X): True """ if not is_ProjectiveSpace(A): - raise TypeError("A (=%s) must be a projective space"%A) + raise TypeError("A (=%s) must be a projective space" % A) Curve_generic.__init__(self, A, X) @@ -241,15 +245,15 @@ def affine_patch(self, i, AA=None): - ``AA`` -- (default: None) ambient affine space, this is constructed if it is not given - OUTPUT: a curve in affine space + OUTPUT: A curve in affine space. EXAMPLES:: sage: P.<x,y,z,w> = ProjectiveSpace(CC, 3) sage: C = Curve([y*z - x^2, w^2 - x*y], P) sage: C.affine_patch(0) - Affine Curve over Complex Field with 53 bits of precision defined by - y*z - 1.00000000000000, w^2 - y + Affine Curve over Complex Field with 53 bits of precision defined + by y*z - 1.00000000000000, w^2 - y :: @@ -289,7 +293,7 @@ def projection(self, P=None, PS=None): ambient space of this curve. This space will be constructed if not specified. - OUTPUT: a tuple of + OUTPUT: A tuple of - a scheme morphism from this curve into a projective space of dimension one less than that of the ambient space of this curve @@ -298,6 +302,7 @@ def projection(self, P=None, PS=None): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K.<a> = CyclotomicField(3) sage: P.<x,y,z,w> = ProjectiveSpace(K, 3) sage: C = Curve([y*w - x^2, z*w^2 - a*x^3], P) @@ -306,13 +311,13 @@ def projection(self, P=None, PS=None): sage: proj1 (Scheme morphism: From: Projective Curve over Cyclotomic Field of order 3 and degree 2 - defined by -x^2 + y*w, (-a)*x^3 + z*w^2 - To: Projective Space of dimension 2 over Cyclotomic Field of order - 3 and degree 2 + defined by -x^2 + y*w, (-a)*x^3 + z*w^2 + To: Projective Space of dimension 2 + over Cyclotomic Field of order 3 and degree 2 Defn: Defined on coordinates by sending (x : y : z : w) to (x : y : -z + w), Projective Plane Curve over Cyclotomic Field of order 3 and degree 2 - defined by a^6 + (-a)*a^3*b^3 - a^4*b*c) + defined by a^6 + (-a)*a^3*b^3 - a^4*b*c) sage: proj1[1].ambient_space() is L True sage: proj2 = C.projection() @@ -325,21 +330,21 @@ def projection(self, P=None, PS=None): sage: C = Curve([y - x, z - a - b, w^2 - c^2, z - x - a, x^2 - w*z], P) sage: C.projection() (Scheme morphism: - From: Projective Curve over Rational Field defined by -x + y, z - a - - b, w^2 - c^2, -x + z - a, x^2 - z*w + From: Projective Curve over Rational Field + defined by -x + y, z - a - b, w^2 - c^2, -x + z - a, x^2 - z*w To: Projective Space of dimension 5 over Rational Field Defn: Defined on coordinates by sending (x : y : z : w : a : b : c) - to - (x : y : -z + w : a : b : c), + to (x : y : -z + w : a : b : c), Projective Curve over Rational Field defined by x1 - x4, x0 - x4, x2*x3 - + x3^2 + x2*x4 + 2*x3*x4, x2^2 - x3^2 - 2*x3*x4 + x4^2 - x5^2, x2*x4^2 + - x3*x4^2 + x4^3 - x3*x5^2 - x4*x5^2, x4^4 - x3^2*x5^2 - 2*x3*x4*x5^2 - - x4^2*x5^2) + + x3^2 + x2*x4 + 2*x3*x4, x2^2 - x3^2 - 2*x3*x4 + x4^2 - x5^2, x2*x4^2 + + x3*x4^2 + x4^3 - x3*x5^2 - x4*x5^2, x4^4 - x3^2*x5^2 - 2*x3*x4*x5^2 - + x4^2*x5^2) :: sage: P.<x,y,z,w> = ProjectiveSpace(GF(2), 3) - sage: C = P.curve([(x - y)*(x - z)*(x - w)*(y - z)*(y - w), x*y*z*w*(x+y+z+w)]) + sage: C = P.curve([(x - y)*(x - z)*(x - w)*(y - z)*(y - w), + ....: x*y*z*w*(x + y + z + w)]) sage: C.projection() Traceback (most recent call last): ... @@ -352,19 +357,19 @@ def projection(self, P=None, PS=None): sage: L.<a,b,c,d> = ProjectiveSpace(GF(7), 3) sage: C.projection(PS=L) (Scheme morphism: - From: Projective Curve over Finite Field of size 7 defined by x^3 - - y*z*u, 2*x*z + w^2 - u^2, -y^2 + 3*x*w + From: Projective Curve over Finite Field of size 7 + defined by x^3 - y*z*u, 2*x*z + w^2 - u^2, -y^2 + 3*x*w To: Projective Space of dimension 3 over Finite Field of size 7 Defn: Defined on coordinates by sending (x : y : z : w : u) to (x : y : z : w), Projective Curve over Finite Field of size 7 defined by b^2 - 3*a*d, - a^5*b + a*b*c^3*d - 3*b*c^2*d^3, a^6 + a^2*c^3*d - 3*a*c^2*d^3) + a^5*b + a*b*c^3*d - 3*b*c^2*d^3, a^6 + a^2*c^3*d - 3*a*c^2*d^3) sage: Q.<a,b,c> = ProjectiveSpace(GF(7), 2) sage: C.projection(PS=Q) Traceback (most recent call last): ... - TypeError: (=Projective Space of dimension 2 over Finite Field of size - 7) must have dimension (=3) + TypeError: (=Projective Space of dimension 2 over Finite Field of + size 7) must have dimension (=3) :: @@ -374,19 +379,20 @@ def projection(self, P=None, PS=None): sage: Q = PP([1,0,1,1]) sage: C.projection(P=Q) (Scheme morphism: - From: Projective Curve over Rational Field defined by x^3 - y*z^2, -x*z + w^2 + From: Projective Curve over Rational Field + defined by x^3 - y*z^2, -x*z + w^2 To: Projective Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x : y : z : w) to (y : -x + z : -x + w), Projective Plane Curve over Rational Field defined by x0*x1^5 - - 6*x0*x1^4*x2 + 14*x0*x1^3*x2^2 - 16*x0*x1^2*x2^3 + 9*x0*x1*x2^4 - - 2*x0*x2^5 - x2^6) + 6*x0*x1^4*x2 + 14*x0*x1^3*x2^2 - 16*x0*x1^2*x2^3 + 9*x0*x1*x2^4 - + 2*x0*x2^5 - x2^6) sage: LL.<a,b,c> = ProjectiveSpace(QQ, 2) sage: Q = PP([0,0,0,1]) sage: C.projection(PS=LL, P=Q) (Scheme morphism: - From: Projective Curve over Rational Field defined by x^3 - y*z^2, - -x*z + w^2 + From: Projective Curve over Rational Field + defined by x^3 - y*z^2, -x*z + w^2 To: Projective Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x : y : z : w) to (x : y : z), @@ -502,7 +508,7 @@ def plane_projection(self, PP=None): as this curve, and must have dimension two. This space is constructed if not specified. - OUTPUT: a tuple of + OUTPUT: A tuple of - a scheme morphism from this curve into a projective plane @@ -516,13 +522,13 @@ def plane_projection(self, PP=None): sage: proj1 = C.plane_projection(PP=L) sage: proj1 (Scheme morphism: - From: Projective Curve over Rational Field defined by x*u - z*v, -y + - w, -x^2 + y*w, -w^5 + 2*y^3*z*u + From: Projective Curve over Rational Field + defined by x*u - z*v, -y + w, -x^2 + y*w, -w^5 + 2*y^3*z*u To: Projective Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x : y : z : w : u : v) to (x : -z + u : -z + v), Projective Plane Curve over Rational Field defined by a^8 + 6*a^7*b + - 4*a^5*b^3 - 4*a^7*c - 2*a^6*b*c - 4*a^5*b^2*c + 2*a^6*c^2) + 4*a^5*b^3 - 4*a^7*c - 2*a^6*b*c - 4*a^5*b^2*c + 2*a^6*c^2) sage: proj1[1].ambient_space() is L True sage: proj2 = C.projection() @@ -535,11 +541,14 @@ def plane_projection(self, PP=None): sage: C = P.curve([x^2 - 6*y^2, w*z*u - y^3 + 4*y^2*z, u^2 - x^2]) sage: C.plane_projection() (Scheme morphism: - From: Projective Curve over Finite Field of size 7 defined by x^2 + y^2, -y^3 - 3*y^2*z + z*w*u, -x^2 + u^2 + From: Projective Curve over Finite Field of size 7 + defined by x^2 + y^2, -y^3 - 3*y^2*z + z*w*u, -x^2 + u^2 To: Projective Space of dimension 2 over Finite Field of size 7 Defn: Defined on coordinates by sending (x : y : z : w : u) to (x : z : -y + w), - Projective Plane Curve over Finite Field of size 7 defined by x0^10 + 2*x0^8*x1^2 + 2*x0^6*x1^4 - 3*x0^6*x1^3*x2 + 2*x0^6*x1^2*x2^2 - 2*x0^4*x1^4*x2^2 + x0^2*x1^4*x2^4) + Projective Plane Curve over Finite Field of size 7 + defined by x0^10 + 2*x0^8*x1^2 + 2*x0^6*x1^4 - 3*x0^6*x1^3*x2 + + 2*x0^6*x1^2*x2^2 - 2*x0^4*x1^4*x2^2 + x0^2*x1^4*x2^4) :: @@ -585,18 +594,22 @@ class ProjectivePlaneCurve(ProjectiveCurve): A projective plane curve defined over an algebraic closure of `\QQ`:: + sage: # needs sage.rings.number_field sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) sage: set_verbose(-1) # suppress warnings for slow computation sage: C = Curve([y*z - x^2 - QQbar.gen()*z^2], P); C - Projective Plane Curve over Algebraic Field defined by - -x^2 + y*z + (-I)*z^2 + Projective Plane Curve over Algebraic Field + defined by -x^2 + y*z + (-I)*z^2 A projective plane curve defined over a finite field:: + sage: # needs sage.rings.finite_rings sage: P.<x,y,z> = ProjectiveSpace(GF(5^2, 'v'), 2) sage: C = Curve([y^2*z - x*z^2 - z^3], P); C - Projective Plane Curve over Finite Field in v of size 5^2 defined by y^2*z - x*z^2 - z^3 + Projective Plane Curve over Finite Field in v of size 5^2 + defined by y^2*z - x*z^2 - z^3 """ + def __init__(self, A, f): """ Initialize. @@ -630,18 +643,16 @@ def divisor_of_function(self, r): """ Return the divisor of a function on a curve. - INPUT: r is a rational function on X - - OUTPUT: + INPUT: ``r`` is a rational function on X - - ``list`` -- The divisor of r represented as a list of coefficients and - points. (TODO: This will change to a more structural output in the - future.) + OUTPUT: A list. The divisor of r represented as a list of coefficients and + points. (TODO: This will change to a more structural output in the + future.) EXAMPLES:: sage: FF = FiniteField(5) - sage: P2 = ProjectiveSpace(2, FF, names = ['x','y','z']) + sage: P2 = ProjectiveSpace(2, FF, names=['x','y','z']) sage: R = P2.coordinate_ring() sage: x, y, z = R.gens() sage: f = y^2*z^7 - x^9 - x*z^8 @@ -662,8 +673,8 @@ def divisor_of_function(self, r): for P in pnts: if P[2] != F(0): # What is the '5' in this line and the 'r()' in the next??? - lcs = self.local_coordinates(P,5) - ldg = degree_lowest_rational_function(r(lcs[0],lcs[1]),z) + lcs = self.local_coordinates(P, 5) + ldg = degree_lowest_rational_function(r(lcs[0], lcs[1]), z) if ldg != 0: divf.append([ldg, P]) return divf @@ -687,12 +698,13 @@ def local_coordinates(self, pt, n): EXAMPLES:: sage: FF = FiniteField(5) - sage: P2 = ProjectiveSpace(2, FF, names = ['x','y','z']) + sage: P2 = ProjectiveSpace(2, FF, names=['x','y','z']) sage: x, y, z = P2.coordinate_ring().gens() - sage: C = Curve(y^2*z^7-x^9-x*z^8) + sage: C = Curve(y^2*z^7 - x^9 - x*z^8) sage: pt = C([2,3,1]) sage: C.local_coordinates(pt,9) # todo: not implemented !!!! - [2 + t, 3 + 3*t^2 + t^3 + 3*t^4 + 3*t^6 + 3*t^7 + t^8 + 2*t^9 + 3*t^11 + 3*t^12] + [2 + t, + 3 + 3*t^2 + t^3 + 3*t^4 + 3*t^6 + 3*t^7 + t^8 + 2*t^9 + 3*t^11 + 3*t^12] """ f = self.defining_polynomial() @@ -701,14 +713,14 @@ def local_coordinates(self, pt, n): p = F.characteristic() x0 = F(pt[0]) y0 = F(pt[1]) - astr = ["a"+str(i) for i in range(1,2*n)] - x,y = R.gens() + astr = ["a"+str(i) for i in range(1, 2*n)] + x, y = R.gens() R0 = PolynomialRing(F, 2 * n + 2, names=[str(x), str(y), "t"] + astr) vars0 = R0.gens() t = vars0[2] - yt = y0*t**0 + add([vars0[i]*t**(i-2) for i in range(3,2*n+2)]) + yt = y0*t**0 + add([vars0[i]*t**(i-2) for i in range(3, 2*n+2)]) xt = x0+t - ft = f(xt,yt) + ft = f(xt, yt) S = singular S.eval('ring s = '+str(p)+','+str(R0.gens())+',lp;') S.eval('poly f = '+str(ft)) @@ -729,15 +741,15 @@ def local_coordinates(self, pt, n): if str(y) in x: if x.replace(str(y), ""): i = x.find("-") - if i>0: - vals.append([eval(x[1:i]),x[:i],F(eval(x[i+1:]))]) + if i > 0: + vals.append([eval(x[1:i]), x[:i], F(eval(x[i+1:]))]) i = x.find("+") - if i>0: - vals.append([eval(x[1:i]),x[:i],-F(eval(x[i+1:]))]) + if i > 0: + vals.append([eval(x[1:i]), x[:i], -F(eval(x[i+1:]))]) else: - vals.append([eval(str(y)[1:]),str(y),F(0)]) + vals.append([eval(str(y)[1:]), str(y), F(0)]) vals.sort() - return [x0 + t, y0 + add(v[2] * t**(j+1) for j, v in enumerate(vals))] + return [x0 + t, y0 + add(v[2] * t**(j + 1) for j, v in enumerate(vals))] def plot(self, *args, **kwds): """ @@ -764,25 +776,25 @@ def plot(self, *args, **kwds): sage: R.<x, y, z> = QQ[] sage: C = Curve(x^3 - y^2*z) - sage: C.plot() + sage: C.plot() # needs sage.plot Graphics object consisting of 1 graphics primitive The other affine patches of the same curve:: - sage: C.plot(patch=0) + sage: C.plot(patch=0) # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: C.plot(patch=1) + sage: C.plot(patch=1) # needs sage.plot Graphics object consisting of 1 graphics primitive An elliptic curve:: sage: E = EllipticCurve('101a') sage: C = Curve(E) - sage: C.plot() + sage: C.plot() # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: C.plot(patch=0) + sage: C.plot(patch=0) # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: C.plot(patch=1) + sage: C.plot(patch=1) # needs sage.plot Graphics object consisting of 1 graphics primitive A hyperelliptic curve:: @@ -790,11 +802,11 @@ def plot(self, *args, **kwds): sage: P.<x> = QQ[] sage: f = 4*x^5 - 30*x^3 + 45*x - 22 sage: C = HyperellipticCurve(f) - sage: C.plot() + sage: C.plot() # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: C.plot(patch=0) + sage: C.plot(patch=0) # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: C.plot(patch=1) + sage: C.plot(patch=1) # needs sage.plot Graphics object consisting of 1 graphics primitive """ # if user has not specified a favorite affine patch, take the @@ -826,46 +838,46 @@ def is_singular(self, P=None): Over `\QQ`:: sage: F = QQ - sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) - sage: C = Curve(X^3-Y^2*Z) + sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2) + sage: C = Curve(X^3 - Y^2*Z) sage: C.is_singular() True Over a finite field:: sage: F = GF(19) - sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) - sage: C = Curve(X^3+Y^3+Z^3) + sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2) + sage: C = Curve(X^3 + Y^3 + Z^3) sage: C.is_singular() False - sage: D = Curve(X^4-X*Z^3) + sage: D = Curve(X^4 - X*Z^3) sage: D.is_singular() True - sage: E = Curve(X^5+19*Y^5+Z^5) + sage: E = Curve(X^5 + 19*Y^5 + Z^5) sage: E.is_singular() True - sage: E = Curve(X^5+9*Y^5+Z^5) + sage: E = Curve(X^5 + 9*Y^5 + Z^5) sage: E.is_singular() False Over `\CC`:: sage: F = CC - sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) + sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2) sage: C = Curve(X) - sage: C.is_singular() + sage: C.is_singular() # needs sage.rings.function_field False - sage: D = Curve(Y^2*Z-X^3) - sage: D.is_singular() + sage: D = Curve(Y^2*Z - X^3) + sage: D.is_singular() # needs sage.rings.function_field True - sage: E = Curve(Y^2*Z-X^3+Z^3) - sage: E.is_singular() + sage: E = Curve(Y^2*Z - X^3 + Z^3) + sage: E.is_singular() # needs sage.rings.function_field False Showing that :trac:`12187` is fixed:: sage: F.<X,Y,Z> = GF(2)[] - sage: G = Curve(X^2+Y*Z) + sage: G = Curve(X^2 + Y*Z) sage: G.is_singular() False @@ -874,7 +886,7 @@ def is_singular(self, P=None): sage: P.<x,y,z> = ProjectiveSpace(CC, 2) sage: C = Curve([y^4 - x^3*z], P) sage: Q = P([0,0,1]) - sage: C.is_singular() + sage: C.is_singular() # needs sage.rings.function_field True """ if P is None: @@ -889,7 +901,7 @@ def degree(self): For a plane curve, this is just the degree of its defining polynomial. - OUTPUT: integer. + OUTPUT: An integer. EXAMPLES:: @@ -918,27 +930,31 @@ def tangents(self, P, factor=True): OUTPUT: - a list of polynomials in the coordinate ring of the ambient space of + A list of polynomials in the coordinate ring of the ambient space of this curve. EXAMPLES:: + sage: # needs sage.rings.number_field sage: set_verbose(-1) sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) - sage: C = Curve([x^3*y + 2*x^2*y^2 + x*y^3 + x^3*z + 7*x^2*y*z + 14*x*y^2*z + 9*y^3*z], P) + sage: C = Curve([x^3*y + 2*x^2*y^2 + x*y^3 + x^3*z + ....: + 7*x^2*y*z + 14*x*y^2*z + 9*y^3*z], P) sage: Q = P([0,0,1]) sage: C.tangents(Q) - [x + 4.147899035704788?*y, x + (1.426050482147607? + 0.3689894074818041?*I)*y, - x + (1.426050482147607? - 0.3689894074818041?*I)*y] + [x + 4.147899035704788?*y, + x + (1.426050482147607? + 0.3689894074818041?*I)*y, + x + (1.426050482147607? - 0.3689894074818041?*I)*y] sage: C.tangents(Q, factor=False) [6*x^3 + 42*x^2*y + 84*x*y^2 + 54*y^3] :: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: C = P.curve([x^2*y^3*z^4 - y^6*z^3 - 4*x^2*y^4*z^3 - 4*x^4*y^2*z^3 + 3*y^7*z^2 +\ - 10*x^2*y^5*z^2 + 9*x^4*y^3*z^2 + 5*x^6*y*z^2 - 3*y^8*z - 9*x^2*y^6*z - 11*x^4*y^4*z -\ - 7*x^6*y^2*z - 2*x^8*z + y^9 + 2*x^2*y^7 + 3*x^4*y^5 + 4*x^6*y^3 + 2*x^8*y]) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: C = P.curve([x^2*y^3*z^4 - y^6*z^3 - 4*x^2*y^4*z^3 - 4*x^4*y^2*z^3 + ....: + 3*y^7*z^2 + 10*x^2*y^5*z^2 + 9*x^4*y^3*z^2 + 5*x^6*y*z^2 + ....: - 3*y^8*z - 9*x^2*y^6*z - 11*x^4*y^4*z - 7*x^6*y^2*z + ....: - 2*x^8*z + y^9 + 2*x^2*y^7 + 3*x^4*y^5 + 4*x^6*y^3 + 2*x^8*y]) sage: Q = P([0,1,1]) sage: C.tangents(Q) [-y + z, 3*x^2 - y^2 + 2*y*z - z^2] @@ -1000,12 +1016,15 @@ def is_ordinary_singularity(self, P): :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^2 - 3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) - sage: C = P.curve([x^2*y^3*z^4 - y^6*z^3 - 4*x^2*y^4*z^3 - 4*x^4*y^2*z^3 + 3*y^7*z^2 + 10*x^2*y^5*z^2\ - + 9*x^4*y^3*z^2 + 5*x^6*y*z^2 - 3*y^8*z - 9*x^2*y^6*z - 11*x^4*y^4*z - 7*x^6*y^2*z - 2*x^8*z + y^9 +\ - 2*x^2*y^7 + 3*x^4*y^5 + 4*x^6*y^3 + 2*x^8*y]) + sage: C = P.curve([x^2*y^3*z^4 - y^6*z^3 - 4*x^2*y^4*z^3 - 4*x^4*y^2*z^3 + ....: + 3*y^7*z^2 + 10*x^2*y^5*z^2 + 9*x^4*y^3*z^2 + ....: + 5*x^6*y*z^2 - 3*y^8*z - 9*x^2*y^6*z - 11*x^4*y^4*z + ....: - 7*x^6*y^2*z - 2*x^8*z + y^9 + 2*x^2*y^7 + 3*x^4*y^5 + ....: + 4*x^6*y^3 + 2*x^8*y]) sage: Q = P([0,1,1]) sage: C.is_ordinary_singularity(Q) True @@ -1023,7 +1042,7 @@ def is_ordinary_singularity(self, P): """ r = self.multiplicity(P) if r < 2: - raise TypeError("(=%s) is not a singular point of (=%s)"%(P,self)) + raise TypeError("(=%s) is not a singular point of (=%s)" % (P, self)) # Find an affine chart of the ambient space of self that contains P i = 0 @@ -1051,10 +1070,10 @@ def quadratic_transform(self): sage: C = Curve(x^3*y - z^4 - z^2*x^2, P) sage: C.quadratic_transform() Scheme morphism: - From: Projective Plane Curve over Rational Field defined by x^3*y - - x^2*z^2 - z^4 - To: Projective Plane Curve over Rational Field defined by -x^3*y - - x*y*z^2 + z^4 + From: Projective Plane Curve over Rational Field + defined by x^3*y - x^2*z^2 - z^4 + To: Projective Plane Curve over Rational Field + defined by -x^3*y - x*y*z^2 + z^4 Defn: Defined on coordinates by sending (x : y : z) to (y*z : x*z : x*y) @@ -1064,10 +1083,10 @@ def quadratic_transform(self): sage: C = P.curve([y^7*z^2 - 16*x^9 + x*y*z^7 + 2*z^9]) sage: C.quadratic_transform() Scheme morphism: - From: Projective Plane Curve over Finite Field of size 17 defined by - x^9 + y^7*z^2 + x*y*z^7 + 2*z^9 - To: Projective Plane Curve over Finite Field of size 17 defined by - 2*x^9*y^7 + x^8*y^6*z^2 + x^9*z^7 + y^7*z^9 + From: Projective Plane Curve over Finite Field of size 17 + defined by x^9 + y^7*z^2 + x*y*z^7 + 2*z^9 + To: Projective Plane Curve over Finite Field of size 17 + defined by 2*x^9*y^7 + x^8*y^6*z^2 + x^9*z^7 + y^7*z^9 Defn: Defined on coordinates by sending (x : y : z) to (y*z : x*z : x*y) """ @@ -1119,55 +1138,68 @@ def excellent_position(self, Q): sage: C.excellent_position(Q) Scheme morphism: From: Projective Plane Curve over Rational Field defined by x*y - z^2 - To: Projective Plane Curve over Rational Field defined by -x^2 - - 3*x*y - 4*y^2 - x*z - 3*y*z + To: Projective Plane Curve over Rational Field + defined by -x^2 - 3*x*y - 4*y^2 - x*z - 3*y*z Defn: Defined on coordinates by sending (x : y : z) to (-x + 1/2*y + 1/2*z : -1/2*y + 1/2*z : x + 1/2*y - 1/2*z) :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^2 - 3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) - sage: C = P.curve([z^2*y^3*x^4 - y^6*x^3 - 4*z^2*y^4*x^3 - 4*z^4*y^2*x^3 + 3*y^7*x^2 + 10*z^2*y^5*x^2\ - + 9*z^4*y^3*x^2 + 5*z^6*y*x^2 - 3*y^8*x - 9*z^2*y^6*x - 11*z^4*y^4*x - 7*z^6*y^2*x - 2*z^8*x + y^9 +\ - 2*z^2*y^7 + 3*z^4*y^5 + 4*z^6*y^3 + 2*z^8*y]) + sage: C = P.curve([z^2*y^3*x^4 - y^6*x^3 - 4*z^2*y^4*x^3 - 4*z^4*y^2*x^3 + ....: + 3*y^7*x^2 + 10*z^2*y^5*x^2 + 9*z^4*y^3*x^2 + ....: + 5*z^6*y*x^2 - 3*y^8*x - 9*z^2*y^6*x - 11*z^4*y^4*x + ....: - 7*z^6*y^2*x - 2*z^8*x + y^9 + 2*z^2*y^7 + 3*z^4*y^5 + ....: + 4*z^6*y^3 + 2*z^8*y]) sage: Q = P([1,0,0]) sage: C.excellent_position(Q) Scheme morphism: - From: Projective Plane Curve over Number Field in b with defining - polynomial a^2 - 3 defined by -x^3*y^6 + 3*x^2*y^7 - 3*x*y^8 + y^9 + - x^4*y^3*z^2 - 4*x^3*y^4*z^2 + 10*x^2*y^5*z^2 - 9*x*y^6*z^2 + 2*y^7*z^2 - - 4*x^3*y^2*z^4 + 9*x^2*y^3*z^4 - 11*x*y^4*z^4 + 3*y^5*z^4 + 5*x^2*y*z^6 - - 7*x*y^2*z^6 + 4*y^3*z^6 - 2*x*z^8 + 2*y*z^8 - To: Projective Plane Curve over Number Field in b with defining - polynomial a^2 - 3 defined by 900*x^9 - 7410*x^8*y + 29282*x^7*y^2 - - 69710*x^6*y^3 + 110818*x^5*y^4 - 123178*x^4*y^5 + 96550*x^3*y^6 - - 52570*x^2*y^7 + 18194*x*y^8 - 3388*y^9 - 1550*x^8*z + 9892*x^7*y*z - - 30756*x^6*y^2*z + 58692*x^5*y^3*z - 75600*x^4*y^4*z + 67916*x^3*y^5*z - - 42364*x^2*y^6*z + 16844*x*y^7*z - 3586*y^8*z + 786*x^7*z^2 - - 3958*x^6*y*z^2 + 9746*x^5*y^2*z^2 - 14694*x^4*y^3*z^2 + - 15174*x^3*y^4*z^2 - 10802*x^2*y^5*z^2 + 5014*x*y^6*z^2 - 1266*y^7*z^2 - - 144*x^6*z^3 + 512*x^5*y*z^3 - 912*x^4*y^2*z^3 + 1024*x^3*y^3*z^3 - - 816*x^2*y^4*z^3 + 512*x*y^5*z^3 - 176*y^6*z^3 + 8*x^5*z^4 - 8*x^4*y*z^4 - - 16*x^3*y^2*z^4 + 16*x^2*y^3*z^4 + 8*x*y^4*z^4 - 8*y^5*z^4 + From: Projective Plane Curve over Number Field in b + with defining polynomial a^2 - 3 + defined by -x^3*y^6 + 3*x^2*y^7 - 3*x*y^8 + y^9 + x^4*y^3*z^2 + - 4*x^3*y^4*z^2 + 10*x^2*y^5*z^2 - 9*x*y^6*z^2 + + 2*y^7*z^2 - 4*x^3*y^2*z^4 + 9*x^2*y^3*z^4 + - 11*x*y^4*z^4 + 3*y^5*z^4 + 5*x^2*y*z^6 + - 7*x*y^2*z^6 + 4*y^3*z^6 - 2*x*z^8 + 2*y*z^8 + To: Projective Plane Curve over Number Field in b + with defining polynomial a^2 - 3 + defined by 900*x^9 - 7410*x^8*y + 29282*x^7*y^2 - 69710*x^6*y^3 + + 110818*x^5*y^4 - 123178*x^4*y^5 + 96550*x^3*y^6 + - 52570*x^2*y^7 + 18194*x*y^8 - 3388*y^9 - 1550*x^8*z + + 9892*x^7*y*z - 30756*x^6*y^2*z + 58692*x^5*y^3*z + - 75600*x^4*y^4*z + 67916*x^3*y^5*z - 42364*x^2*y^6*z + + 16844*x*y^7*z - 3586*y^8*z + 786*x^7*z^2 + - 3958*x^6*y*z^2 + 9746*x^5*y^2*z^2 - 14694*x^4*y^3*z^2 + + 15174*x^3*y^4*z^2 - 10802*x^2*y^5*z^2 + + 5014*x*y^6*z^2 - 1266*y^7*z^2 - 144*x^6*z^3 + + 512*x^5*y*z^3 - 912*x^4*y^2*z^3 + 1024*x^3*y^3*z^3 + - 816*x^2*y^4*z^3 + 512*x*y^5*z^3 - 176*y^6*z^3 + + 8*x^5*z^4 - 8*x^4*y*z^4 - 16*x^3*y^2*z^4 + + 16*x^2*y^3*z^4 + 8*x*y^4*z^4 - 8*y^5*z^4 Defn: Defined on coordinates by sending (x : y : z) to (1/4*y + 1/2*z : -1/4*y + 1/2*z : x + 1/4*y - 1/2*z) :: + sage: # needs sage.rings.number_field sage.symbolic sage: set_verbose(-1) sage: a = QQbar(sqrt(2)) sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) - sage: C = Curve([(-1/4*a)*x^3 + (-3/4*a)*x^2*y + (-3/4*a)*x*y^2 + (-1/4*a)*y^3 - 2*x*y*z], P) + sage: C = Curve([(-1/4*a)*x^3 + (-3/4*a)*x^2*y + ....: + (-3/4*a)*x*y^2 + (-1/4*a)*y^3 - 2*x*y*z], P) sage: Q = P([0,0,1]) sage: C.excellent_position(Q) Scheme morphism: - From: Projective Plane Curve over Algebraic Field defined by - (-0.3535533905932738?)*x^3 + (-1.060660171779822?)*x^2*y + - (-1.060660171779822?)*x*y^2 + (-0.3535533905932738?)*y^3 + (-2)*x*y*z - To: Projective Plane Curve over Algebraic Field defined by - (-2.828427124746190?)*x^3 + (-2)*x^2*y + 2*y^3 + (-2)*x^2*z + 2*y^2*z + From: Projective Plane Curve over Algebraic Field defined + by (-0.3535533905932738?)*x^3 + (-1.060660171779822?)*x^2*y + + (-1.060660171779822?)*x*y^2 + (-0.3535533905932738?)*y^3 + + (-2)*x*y*z + To: Projective Plane Curve over Algebraic Field defined + by (-2.828427124746190?)*x^3 + (-2)*x^2*y + 2*y^3 + + (-2)*x^2*z + 2*y^2*z Defn: Defined on coordinates by sending (x : y : z) to (1/2*x + 1/2*y : (-1/2)*x + 1/2*y : 1/2*x + (-1/2)*y + z) """ @@ -1186,13 +1218,13 @@ def excellent_position(self, Q): i += 1 coords = [PP.gens()[j] + Q[j]/Q[i]*PP.gens()[i] for j in range(3)] coords[i] = PP.gens()[i] - accoords = [PP.gens()[j] - Q[j]/Q[i]*PP.gens()[i] for j in range(3)] # coords used in map construction + accoords = [PP.gens()[j] - Q[j]/Q[i]*PP.gens()[i] for j in range(3)] # coords used in map construction accoords[i] = PP.gens()[i] baseC = PP.curve(self.defining_polynomial()(coords)) P = [0]*3 P[i] = 1 P = PP(P) - l = [0,1,2] + l = [0, 1, 2] l.pop(i) # choose points forming a triangle with one vertex at P to map to the coordinate triangle good = False @@ -1243,13 +1275,13 @@ def excellent_position(self, Q): # since (0 : 0 : 1) has multiplicity r, divide out by the highest # shared power of the corresponding variable before doing the resultant computations if j == 0: - div_pow = min([e[1] for e in npoly.exponents()]) - npoly = PP.coordinate_ring()(dict([((v[0],v[1] - div_pow,v[2]),g) for (v,g) in\ - npoly.dict().items()])) + div_pow = min(e[1] for e in npoly.exponents()) + npoly = PP.coordinate_ring()({(v0, v1 - div_pow, v2): g + for (v0, v1, v2), g in npoly.dict().items()}) else: - div_pow = min([e[0] for e in npoly.exponents()]) - npoly = PP.coordinate_ring()(dict([((v[0] - div_pow,v[1],v[2]),g) for (v,g) in\ - npoly.dict().items()])) + div_pow = min(e[0] for e in npoly.exponents()) + npoly = PP.coordinate_ring()({(v0 - div_pow, v1, v2): g + for (v0, v1, v2), g in npoly.dict().items()}) # check the degree again if npoly.degree() != d - r: need_continue = True @@ -1273,7 +1305,7 @@ def excellent_position(self, Q): # at a simple point P of the curve, the tangent at that point is # given by F_x(P)*x + F_y(P)*y + F_z(P)*z where F is the defining polynomial # of the curve - tmp_l = [0,1,2] + tmp_l = [0, 1, 2] tmp_l.pop(j) poly1 = npoly.derivative(PP.gens()[tmp_l[0]]) poly2 = npoly.derivative(PP.gens()[tmp_l[1]]) @@ -1310,40 +1342,54 @@ def ordinary_model(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: set_verbose(-1) sage: K = QuadraticField(3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: C = Curve([x^5 - K.0*y*z^4], P) sage: C.ordinary_model() Scheme morphism: - From: Projective Plane Curve over Number Field in a with defining polynomial x^2 - 3 with a = 1.732050807568878? defined by x^5 + (-a)*y*z^4 - To: Projective Plane Curve over Number Field in a with defining polynomial x^2 - 3 with a = 1.732050807568878? defined by (-a)*x^5*y + (-4*a)*x^4*y^2 + (-6*a)*x^3*y^3 + (-4*a)*x^2*y^4 + (-a)*x*y^5 + (-a - 1)*x^5*z + (-4*a + 5)*x^4*y*z + (-6*a - 10)*x^3*y^2*z + (-4*a + 10)*x^2*y^3*z + (-a - 5)*x*y^4*z + y^5*z + From: Projective Plane Curve over Number Field in a + with defining polynomial x^2 - 3 with a = 1.732050807568878? + defined by x^5 + (-a)*y*z^4 + To: Projective Plane Curve over Number Field in a + with defining polynomial x^2 - 3 with a = 1.732050807568878? + defined by (-a)*x^5*y + (-4*a)*x^4*y^2 + (-6*a)*x^3*y^3 + + (-4*a)*x^2*y^4 + (-a)*x*y^5 + (-a - 1)*x^5*z + + (-4*a + 5)*x^4*y*z + (-6*a - 10)*x^3*y^2*z + + (-4*a + 10)*x^2*y^3*z + (-a - 5)*x*y^4*z + y^5*z Defn: Defined on coordinates by sending (x : y : z) to - (-1/4*x^2 - 1/2*x*y + 1/2*x*z + 1/2*y*z - 1/4*z^2 : 1/4*x^2 + 1/2*x*y + 1/2*y*z - 1/4*z^2 : -1/4*x^2 + 1/4*z^2) + (-1/4*x^2 - 1/2*x*y + 1/2*x*z + 1/2*y*z - 1/4*z^2 : + 1/4*x^2 + 1/2*x*y + 1/2*y*z - 1/4*z^2 : + -1/4*x^2 + 1/4*z^2) :: sage: set_verbose(-1) sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: C = Curve([y^2*z^2 - x^4 - x^3*z], P) - sage: D = C.ordinary_model(); D # long time (2 seconds) + sage: D = C.ordinary_model(); D # long time (2 seconds) Scheme morphism: - From: Projective Plane Curve over Rational Field defined by -x^4 - - x^3*z + y^2*z^2 - To: Projective Plane Curve over Rational Field defined by 4*x^6*y^3 - - 24*x^5*y^4 + 36*x^4*y^5 + 8*x^6*y^2*z - 40*x^5*y^3*z + 24*x^4*y^4*z + - 72*x^3*y^5*z - 4*x^6*y*z^2 + 8*x^5*y^2*z^2 - 56*x^4*y^3*z^2 + - 104*x^3*y^4*z^2 + 44*x^2*y^5*z^2 + 8*x^6*z^3 - 16*x^5*y*z^3 - - 24*x^4*y^2*z^3 + 40*x^3*y^3*z^3 + 48*x^2*y^4*z^3 + 8*x*y^5*z^3 - - 8*x^5*z^4 + 36*x^4*y*z^4 - 56*x^3*y^2*z^4 + 20*x^2*y^3*z^4 + - 40*x*y^4*z^4 - 16*y^5*z^4 + From: Projective Plane Curve over Rational Field defined + by -x^4 - x^3*z + y^2*z^2 + To: Projective Plane Curve over Rational Field defined + by 4*x^6*y^3 - 24*x^5*y^4 + 36*x^4*y^5 + 8*x^6*y^2*z + - 40*x^5*y^3*z + 24*x^4*y^4*z + 72*x^3*y^5*z - 4*x^6*y*z^2 + + 8*x^5*y^2*z^2 - 56*x^4*y^3*z^2 + 104*x^3*y^4*z^2 + + 44*x^2*y^5*z^2 + 8*x^6*z^3 - 16*x^5*y*z^3 + - 24*x^4*y^2*z^3 + 40*x^3*y^3*z^3 + 48*x^2*y^4*z^3 + + 8*x*y^5*z^3 - 8*x^5*z^4 + 36*x^4*y*z^4 - 56*x^3*y^2*z^4 + + 20*x^2*y^3*z^4 + 40*x*y^4*z^4 - 16*y^5*z^4 Defn: Defined on coordinates by sending (x : y : z) to - (-3/64*x^4 + 9/64*x^2*y^2 - 3/32*x*y^3 - 1/16*x^3*z - - 1/8*x^2*y*z + 1/4*x*y^2*z - 1/16*y^3*z - 1/8*x*y*z^2 + 1/16*y^2*z^2 : - -1/64*x^4 + 3/64*x^2*y^2 - 1/32*x*y^3 + 1/16*x*y^2*z - 1/16*y^3*z + - 1/16*y^2*z^2 : 3/64*x^4 - 3/32*x^3*y + 3/64*x^2*y^2 + 1/16*x^3*z - - 3/16*x^2*y*z + 1/8*x*y^2*z - 1/8*x*y*z^2 + 1/16*y^2*z^2) - sage: all(D.codomain().is_ordinary_singularity(Q) for Q in D.codomain().singular_points()) # long time + (-3/64*x^4 + 9/64*x^2*y^2 - 3/32*x*y^3 - 1/16*x^3*z + - 1/8*x^2*y*z + 1/4*x*y^2*z - 1/16*y^3*z - 1/8*x*y*z^2 + + 1/16*y^2*z^2 : + -1/64*x^4 + 3/64*x^2*y^2 - 1/32*x*y^3 + 1/16*x*y^2*z + - 1/16*y^3*z + 1/16*y^2*z^2 : + 3/64*x^4 - 3/32*x^3*y + 3/64*x^2*y^2 + 1/16*x^3*z + - 3/16*x^2*y*z + 1/8*x*y^2*z - 1/8*x*y*z^2 + 1/16*y^2*z^2) + sage: all(D.codomain().is_ordinary_singularity(Q) # long time + ....: for Q in D.codomain().singular_points()) True :: @@ -1353,46 +1399,56 @@ def ordinary_model(self): sage: C = Curve([(x^2 + y^2 - y*z - 2*z^2)*(y*z - x^2 + 2*z^2)*z + y^5], P) sage: C.ordinary_model() # long time (5 seconds) Scheme morphism: - From: Projective Plane Curve over Number Field in a with defining - polynomial y^2 - 2 defined by y^5 - x^4*z - x^2*y^2*z + 2*x^2*y*z^2 + - y^3*z^2 + 4*x^2*z^3 + y^2*z^3 - 4*y*z^4 - 4*z^5 - To: Projective Plane Curve over Number Field in a with defining - polynomial y^2 - 2 defined by (-29*a + 1)*x^8*y^6 + (10*a + 158)*x^7*y^7 - + (-109*a - 31)*x^6*y^8 + (-80*a - 198)*x^8*y^5*z + (531*a + - 272)*x^7*y^6*z + (170*a - 718)*x^6*y^7*z + (19*a - 636)*x^5*y^8*z + - (-200*a - 628)*x^8*y^4*z^2 + (1557*a - 114)*x^7*y^5*z^2 + (2197*a - - 2449)*x^6*y^6*z^2 + (1223*a - 3800)*x^5*y^7*z^2 + (343*a - - 1329)*x^4*y^8*z^2 + (-323*a - 809)*x^8*y^3*z^3 + (1630*a - - 631)*x^7*y^4*z^3 + (4190*a - 3126)*x^6*y^5*z^3 + (3904*a - - 7110)*x^5*y^6*z^3 + (1789*a - 5161)*x^4*y^7*z^3 + (330*a - - 1083)*x^3*y^8*z^3 + (-259*a - 524)*x^8*y^2*z^4 + (720*a - - 605)*x^7*y^3*z^4 + (3082*a - 2011)*x^6*y^4*z^4 + (4548*a - - 5462)*x^5*y^5*z^4 + (2958*a - 6611)*x^4*y^6*z^4 + (994*a - - 2931)*x^3*y^7*z^4 + (117*a - 416)*x^2*y^8*z^4 + (-108*a - 184)*x^8*y*z^5 - + (169*a - 168)*x^7*y^2*z^5 + (831*a - 835)*x^6*y^3*z^5 + (2225*a - - 1725)*x^5*y^4*z^5 + (1970*a - 3316)*x^4*y^5*z^5 + (952*a - - 2442)*x^3*y^6*z^5 + (217*a - 725)*x^2*y^7*z^5 + (16*a - 77)*x*y^8*z^5 + - (-23*a - 35)*x^8*z^6 + (43*a + 24)*x^7*y*z^6 + (21*a - 198)*x^6*y^2*z^6 - + (377*a - 179)*x^5*y^3*z^6 + (458*a - 537)*x^4*y^4*z^6 + (288*a - - 624)*x^3*y^5*z^6 + (100*a - 299)*x^2*y^6*z^6 + (16*a - 67)*x*y^7*z^6 - - 5*y^8*z^6 + From: Projective Plane Curve over Number Field in a + with defining polynomial y^2 - 2 defined + by y^5 - x^4*z - x^2*y^2*z + 2*x^2*y*z^2 + y^3*z^2 + + 4*x^2*z^3 + y^2*z^3 - 4*y*z^4 - 4*z^5 + To: Projective Plane Curve over Number Field in a + with defining polynomial y^2 - 2 defined + by (-29*a + 1)*x^8*y^6 + (10*a + 158)*x^7*y^7 + + (-109*a - 31)*x^6*y^8 + (-80*a - 198)*x^8*y^5*z + + (531*a + 272)*x^7*y^6*z + (170*a - 718)*x^6*y^7*z + + (19*a - 636)*x^5*y^8*z + (-200*a - 628)*x^8*y^4*z^2 + + (1557*a - 114)*x^7*y^5*z^2 + (2197*a - 2449)*x^6*y^6*z^2 + + (1223*a - 3800)*x^5*y^7*z^2 + (343*a - 1329)*x^4*y^8*z^2 + + (-323*a - 809)*x^8*y^3*z^3 + (1630*a - 631)*x^7*y^4*z^3 + + (4190*a - 3126)*x^6*y^5*z^3 + (3904*a - 7110)*x^5*y^6*z^3 + + (1789*a - 5161)*x^4*y^7*z^3 + (330*a - 1083)*x^3*y^8*z^3 + + (-259*a - 524)*x^8*y^2*z^4 + (720*a - 605)*x^7*y^3*z^4 + + (3082*a - 2011)*x^6*y^4*z^4 + (4548*a - 5462)*x^5*y^5*z^4 + + (2958*a - 6611)*x^4*y^6*z^4 + (994*a - 2931)*x^3*y^7*z^4 + + (117*a - 416)*x^2*y^8*z^4 + (-108*a - 184)*x^8*y*z^5 + + (169*a - 168)*x^7*y^2*z^5 + (831*a - 835)*x^6*y^3*z^5 + + (2225*a - 1725)*x^5*y^4*z^5 + (1970*a - 3316)*x^4*y^5*z^5 + + (952*a - 2442)*x^3*y^6*z^5 + (217*a - 725)*x^2*y^7*z^5 + + (16*a - 77)*x*y^8*z^5 + (-23*a - 35)*x^8*z^6 + + (43*a + 24)*x^7*y*z^6 + (21*a - 198)*x^6*y^2*z^6 + + (377*a - 179)*x^5*y^3*z^6 + (458*a - 537)*x^4*y^4*z^6 + + (288*a - 624)*x^3*y^5*z^6 + (100*a - 299)*x^2*y^6*z^6 + + (16*a - 67)*x*y^7*z^6 - 5*y^8*z^6 Defn: Defined on coordinates by sending (x : y : z) to - ((-5/128*a - 5/128)*x^4 + (-5/32*a + 5/32)*x^3*y + (-1/16*a + - 3/32)*x^2*y^2 + (1/16*a - 1/16)*x*y^3 + (1/32*a - 1/32)*y^4 - 1/32*x^3*z - + (3/16*a - 5/8)*x^2*y*z + (1/8*a - 5/16)*x*y^2*z + (1/8*a + - 5/32)*x^2*z^2 + (-3/16*a + 5/16)*x*y*z^2 + (-3/16*a - 1/16)*y^2*z^2 + - 1/16*x*z^3 + (1/4*a + 1/4)*y*z^3 + (-3/32*a - 5/32)*z^4 : (-5/128*a - - 5/128)*x^4 + (5/32*a)*x^3*y + (3/32*a + 3/32)*x^2*y^2 + (-1/16*a)*x*y^3 - + (-1/32*a - 1/32)*y^4 - 1/32*x^3*z + (-11/32*a)*x^2*y*z + (1/8*a + - 5/16)*x*y^2*z + (3/16*a + 1/4)*y^3*z + (1/8*a + 5/32)*x^2*z^2 + (-1/16*a - - 3/8)*x*y*z^2 + (-3/8*a - 9/16)*y^2*z^2 + 1/16*x*z^3 + (5/16*a + - 1/2)*y*z^3 + (-3/32*a - 5/32)*z^4 : (1/64*a + 3/128)*x^4 + (-1/32*a - - 1/32)*x^3*y + (3/32*a - 9/32)*x^2*y^2 + (1/16*a - 3/16)*x*y^3 - 1/32*y^4 - + (3/32*a + 1/8)*x^2*y*z + (-1/8*a + 1/8)*x*y^2*z + (-1/16*a)*y^3*z + - (-1/16*a - 3/32)*x^2*z^2 + (1/16*a + 1/16)*x*y*z^2 + (3/16*a + - 3/16)*y^2*z^2 + (-3/16*a - 1/4)*y*z^3 + (1/16*a + 3/32)*z^4) + ((-5/128*a - 5/128)*x^4 + (-5/32*a + 5/32)*x^3*y + + (-1/16*a + 3/32)*x^2*y^2 + (1/16*a - 1/16)*x*y^3 + + (1/32*a - 1/32)*y^4 - 1/32*x^3*z + (3/16*a - 5/8)*x^2*y*z + + (1/8*a - 5/16)*x*y^2*z + (1/8*a + 5/32)*x^2*z^2 + + (-3/16*a + 5/16)*x*y*z^2 + (-3/16*a - 1/16)*y^2*z^2 + + 1/16*x*z^3 + (1/4*a + 1/4)*y*z^3 + (-3/32*a - 5/32)*z^4 : + (-5/128*a - 5/128)*x^4 + (5/32*a)*x^3*y + + (3/32*a + 3/32)*x^2*y^2 + (-1/16*a)*x*y^3 + + (-1/32*a - 1/32)*y^4 - 1/32*x^3*z + (-11/32*a)*x^2*y*z + + (1/8*a + 5/16)*x*y^2*z + (3/16*a + 1/4)*y^3*z + + (1/8*a + 5/32)*x^2*z^2 + (-1/16*a - 3/8)*x*y*z^2 + + (-3/8*a - 9/16)*y^2*z^2 + 1/16*x*z^3 + (5/16*a + 1/2)*y*z^3 + + (-3/32*a - 5/32)*z^4 : + (1/64*a + 3/128)*x^4 + (-1/32*a - 1/32)*x^3*y + + (3/32*a - 9/32)*x^2*y^2 + (1/16*a - 3/16)*x*y^3 - 1/32*y^4 + + (3/32*a + 1/8)*x^2*y*z + (-1/8*a + 1/8)*x*y^2*z + + (-1/16*a)*y^3*z + (-1/16*a - 3/32)*x^2*z^2 + + (1/16*a + 1/16)*x*y*z^2 + (3/16*a + 3/16)*y^2*z^2 + + (-3/16*a - 1/4)*y*z^3 + (1/16*a + 3/32)*z^4) """ # helper function for extending the base field + def extension(self): F = self.base_ring() pts = self.change_ring(F.embeddings(QQbar)[0]).rational_points() @@ -1477,7 +1533,7 @@ def is_transverse(self, C, P): - ``P`` -- a point in the intersection of both curves. - OUTPUT: Boolean. + OUTPUT: A boolean. EXAMPLES:: @@ -1490,6 +1546,7 @@ def is_transverse(self, C, P): :: + sage: # needs sage.rings.number_field sage: K = QuadraticField(-1) sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: C = Curve([y^2*z - K.0*x^3], P) @@ -1606,7 +1663,8 @@ def tangent_line(self, p): sage: C = Curve([x*y - z*w, x^2 - y*w, y^2*w - x*z*w], P) sage: p = C(1,1,1,1) sage: C.tangent_line(p) - Projective Curve over Rational Field defined by -2*x + y + w, -3*x + z + 2*w + Projective Curve over Rational Field + defined by -2*x + y + w, -3*x + z + 2*w """ for i in range(len(p)): @@ -1638,7 +1696,8 @@ def arithmetic_genus(self): sage: x,y,z = PolynomialRing(GF(5), 3, 'xyz').gens() sage: C = Curve(y^2*z^7 - x^9 - x*z^8); C - Projective Plane Curve over Finite Field of size 5 defined by -x^9 + y^2*z^7 - x*z^8 + Projective Plane Curve over Finite Field of size 5 + defined by -x^9 + y^2*z^7 - x*z^8 sage: C.arithmetic_genus() 28 sage: C.genus() @@ -1668,15 +1727,16 @@ def fundamental_group(self): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: C = P.curve(x^2*z-y^3) - sage: C.fundamental_group() # optional - sirocco + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: C = P.curve(x^2*z - y^3) + sage: C.fundamental_group() # optional - sirocco Finitely presented group < x0 | x0^3 > In the case of number fields, they need to have an embedding into the algebraic field:: - sage: a = QQ[x](x^2+5).roots(QQbar)[0][0] + sage: # needs sage.rings.number_field + sage: a = QQ[x](x^2 + 5).roots(QQbar)[0][0] sage: a -2.236067977499790?*I sage: F = NumberField(a.minpoly(), 'a', embedding=a) @@ -1684,7 +1744,7 @@ def fundamental_group(self): sage: F.inject_variables() Defining a sage: C = P.curve(x^2 + a * y^2) - sage: C.fundamental_group() # optional - sirocco + sage: C.fundamental_group() # optional - sirocco Finitely presented group < x0 | > .. WARNING:: @@ -1693,11 +1753,18 @@ def fundamental_group(self): TESTS:: - sage: P.<x,y,z>=ProjectiveSpace(QQ,2) - sage: f=z^2*y^3-z*(33*x*z+2*x^2+8*z^2)*y^2+(21*z^2+21*x*z-x^2)*(z^2+11*x*z-x^2)*y+(x-18*z)*(z^2+11*x*z-x^2)^2 - sage: C = P.curve(f) - sage: C.fundamental_group() # optional - sirocco - Finitely presented group < x1, x3 | (x3^-1*x1^-1*x3*x1^-1)^2*x3^-1, x3*(x1^-1*x3^-1)^2*x1^-1*(x3*x1)^2 > + sage: F.<x0, x1> = FreeGroup() + sage: G = F / [x1^-1*(x1^-1*x0^-1*x1*x0^-1)^2, (x1^-1*x0^-1)^2*x1^-1*(x0*x1)^2*x0] + sage: G.order() + 320 + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: C = P.curve(z^2*y^3 - z*(33*x*z+2*x^2+8*z^2)*y^2 + ....: + (21*z^2+21*x*z-x^2)*(z^2+11*x*z-x^2)*y + ....: + (x-18*z)*(z^2+11*x*z-x^2)^2) + sage: G0 = C.fundamental_group() # optional - sirocco + sage: G.is_isomorphic(G0) # optional - sirocco + #I Forcing finiteness test + True """ from sage.schemes.curves.zariski_vankampen import fundamental_group @@ -1734,7 +1801,8 @@ def rational_parameterization(self): sage: C.rational_parameterization() Scheme morphism: From: Projective Space of dimension 1 over Rational Field - To: Projective Plane Curve over Rational Field defined by -x^3 + y^2*z + To: Projective Plane Curve over Rational Field + defined by -x^3 + y^2*z Defn: Defined on coordinates by sending (s : t) to (s^2*t : s^3 : t^3) @@ -1745,7 +1813,8 @@ def rational_parameterization(self): sage: C.rational_parameterization() Scheme morphism: From: Projective Space of dimension 1 over Rational Field - To: Projective Plane Curve over Rational Field defined by x^3 - x*y*z + x*z^2 - 4*y*z^2 + To: Projective Plane Curve over Rational Field + defined by x^3 - x*y*z + x*z^2 - 4*y*z^2 Defn: Defined on coordinates by sending (s : t) to (4*s^2*t + s*t^2 : s^2*t + t^3 : 4*s^3 + s^2*t) @@ -1755,9 +1824,10 @@ def rational_parameterization(self): sage: C = Curve([x^2 + y^2 + z^2], P) sage: C.rational_parameterization() Scheme morphism: - From: Projective Space of dimension 1 over Number Field in a with defining polynomial a^2 + 1 - To: Projective Plane Curve over Number Field in a with defining - polynomial a^2 + 1 defined by x^2 + y^2 + z^2 + From: Projective Space of dimension 1 over Number Field in a + with defining polynomial a^2 + 1 + To: Projective Plane Curve over Number Field in a + with defining polynomial a^2 + 1 defined by x^2 + y^2 + z^2 Defn: Defined on coordinates by sending (s : t) to ((-a)*s^2 + (-a)*t^2 : s^2 - t^2 : 2*s*t) """ @@ -1774,20 +1844,19 @@ def rational_parameterization(self): H = Hom(ProjectiveSpace(R.base_ring(), 1, R.gens()), C) return H(param) - def riemann_surface(self,**kwargs): + def riemann_surface(self, **kwargs): r""" Return the complex Riemann surface determined by this curve - OUTPUT: - - - RiemannSurface object + OUTPUT: A :class:`~sage.schemes.riemann_surfaces.riemann_surface.RiemannSurface` object. EXAMPLES:: - sage: R.<x,y,z>=QQ[] - sage: C=Curve(x^3+3*y^3+5*z^3) + sage: R.<x,y,z> = QQ[] + sage: C = Curve(x^3 + 3*y^3 + 5*z^3) sage: C.riemann_surface() - Riemann surface defined by polynomial f = x^3 + 3*y^3 + 5 = 0, with 53 bits of precision + Riemann surface defined by polynomial f = x^3 + 3*y^3 + 5 = 0, + with 53 bits of precision """ return self.affine_patch(2).riemann_surface(**kwargs) @@ -1814,15 +1883,15 @@ def rational_points_iterator(self): EXAMPLES:: sage: F = GF(37) - sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) - sage: C = Curve(X^7+Y*X*Z^5*55+Y^7*12) + sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2) + sage: C = Curve(X^7 + Y*X*Z^5*55 + Y^7*12) sage: len(list(C.rational_points_iterator())) 37 :: sage: F = GF(2) - sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) + sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2) sage: C = Curve(X*Y*Z) sage: a = C.rational_points_iterator() sage: next(a) @@ -1844,9 +1913,10 @@ def rational_points_iterator(self): :: + sage: # needs sage.rings.finite_rings sage: F = GF(3^2,'a') - sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) - sage: C = Curve(X^3+5*Y^2*Z-33*X*Y*X) + sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2) + sage: C = Curve(X^3 + 5*Y^2*Z - 33*X*Y*X) sage: b = C.rational_points_iterator() sage: next(b) (0 : 1 : 0) @@ -1877,7 +1947,7 @@ def rational_points_iterator(self): g = self.defining_polynomial() K = g.parent().base_ring() from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(K,'X') + R = PolynomialRing(K, 'X') X = R.gen() one = K.one() zero = K.zero() @@ -1890,7 +1960,7 @@ def rational_points_iterator(self): pass # points with Z = 0, Y = 1 - g10 = R(g(X,one,zero)) + g10 = R(g(X, one, zero)) if g10.is_zero(): for x in K: yield self.point([x, one, zero]) @@ -1900,7 +1970,7 @@ def rational_points_iterator(self): # points with Z = 1 for y in K: - gy1 = R(g(X,y,one)) + gy1 = R(g(X, y, one)) if gy1.is_zero(): for x in K: yield self.point([x, y, one]) @@ -1931,7 +2001,7 @@ def _points_via_singular(self, sort=True): sage: C._points_via_singular() [(0 : 0 : 1), (0 : 1 : 0), (2 : 2 : 1), (2 : 3 : 1), (3 : 1 : 1), (3 : 4 : 1)] - sage: C._points_via_singular(sort=False) #random + sage: C._points_via_singular(sort=False) # random [(0 : 1 : 0), (3 : 1 : 1), (3 : 4 : 1), (2 : 2 : 1), (0 : 0 : 1), (2 : 3 : 1)] @@ -1970,8 +2040,8 @@ def _points_via_singular(self, sort=True): F = self.defining_polynomial() z = F.parent().gens()[-1] if z.divides(F): - pnts += [self(1,a,0) for a in self.base_ring()] - pnts += [self(0,1,0)] + pnts += [self(1, a, 0) for a in self.base_ring()] + pnts += [self(0, 1, 0)] # remove multiple points pnts = list(set(pnts)) if sort: @@ -1988,8 +2058,8 @@ def riemann_roch_basis(self, D): - ``D`` - a divisor - OUTPUT: a list of function field elements that form a basis of the - Riemann-Roch space + OUTPUT: A list of function field elements that form a basis of the + Riemann-Roch space. EXAMPLES:: @@ -2027,13 +2097,15 @@ def riemann_roch_basis(self, D): raise RuntimeError(str(s) + "\n\n ** Unable to use the Brill-Noether Singular package to compute all points (see above).") X2 = singular.NSplaces(1, X1) # retrieve list of all computed closed points (possibly of degree >1) - v = X2[3].sage_flattened_str_list() # We use sage_flattened_str_list since iterating through - # the entire list through the sage/singular interface directly - # would involve hundreds of calls to singular, and timing issues with - # the expect interface could crop up. Also, this is vastly - # faster (and more robust). - v = [ v[i].partition(',') for i in range(len(v)) ] - pnts = [ ( int(v[i][0]), int(v[i][2])-1 ) for i in range(len(v))] + v = X2[3].sage_flattened_str_list() + # We use sage_flattened_str_list since iterating through + # the entire list through the sage/singular interface directly + # would involve hundreds of calls to singular, and timing issues with + # the expect interface could crop up. Also, this is vastly + # faster (and more robust). + + v = [v[i].partition(',') for i in range(len(v))] + pnts = [(int(v[i][0]), int(v[i][2])-1) for i in range(len(v))] # retrieve coordinates of rational points R = X2[5][1][1] singular.set_ring(R) @@ -2052,8 +2124,8 @@ def riemann_roch_basis(self, D): T.set_ring() LG = G.BrillNoether(X2) LG = [X.split(',\n') for X in LG.sage_structured_str_list()] - x,y,z = self.ambient_space().coordinate_ring().gens() - vars = {'x':x, 'y':y, 'z':z} + x, y, z = self.ambient_space().coordinate_ring().gens() + vars = {'x': x, 'y': y, 'z': z} V = [(sage_eval(a, vars)/sage_eval(b, vars)) for a, b in LG] return V @@ -2073,7 +2145,7 @@ def rational_points(self, algorithm="enum", sort=True): points should be sorted. If False, the order of the output is non-deterministic. - OUTPUT: a list of all the rational points on the curve, possibly sorted. + OUTPUT: A list of all the rational points on the curve, possibly sorted. .. NOTE:: @@ -2085,8 +2157,8 @@ def rational_points(self, algorithm="enum", sort=True): sage: x, y, z = PolynomialRing(GF(5), 3, 'xyz').gens() sage: f = y^2*z^7 - x^9 - x*z^8 sage: C = Curve(f); C - Projective Plane Curve over Finite Field of size 5 defined by - -x^9 + y^2*z^7 - x*z^8 + Projective Plane Curve over Finite Field of size 5 + defined by -x^9 + y^2*z^7 - x*z^8 sage: C.rational_points() [(0 : 0 : 1), (0 : 1 : 0), (2 : 2 : 1), (2 : 3 : 1), (3 : 1 : 1), (3 : 4 : 1)] @@ -2094,7 +2166,7 @@ def rational_points(self, algorithm="enum", sort=True): sage: C.rational_points() [(0 : 1 : 1), (1 : 1 : 0), (1 : 2 : 1), (2 : 3 : 1), (3 : 4 : 1), (4 : 0 : 1)] - sage: C = Curve(x*z+z^2) + sage: C = Curve(x*z + z^2) sage: C.rational_points('all') [(0 : 1 : 0), (1 : 0 : 0), (1 : 1 : 0), (2 : 1 : 0), (3 : 1 : 0), (4 : 0 : 1), (4 : 1 : 0), (4 : 1 : 1), @@ -2103,8 +2175,8 @@ def rational_points(self, algorithm="enum", sort=True): :: sage: F = GF(7) - sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) - sage: C = Curve(X^3+Y^3-Z^3) + sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2) + sage: C = Curve(X^3 + Y^3 - Z^3) sage: C.rational_points() [(0 : 1 : 1), (0 : 2 : 1), (0 : 4 : 1), (1 : 0 : 1), (2 : 0 : 1), (3 : 1 : 0), (4 : 0 : 1), (5 : 1 : 0), (6 : 1 : 0)] @@ -2112,16 +2184,17 @@ def rational_points(self, algorithm="enum", sort=True): :: sage: F = GF(1237) - sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) - sage: C = Curve(X^7+7*Y^6*Z+Z^4*X^2*Y*89) + sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2) + sage: C = Curve(X^7 + 7*Y^6*Z + Z^4*X^2*Y*89) sage: len(C.rational_points()) 1237 :: + sage: # needs sage.rings.finite_rings sage: F = GF(2^6,'a') - sage: P2.<X,Y,Z> = ProjectiveSpace(F,2) - sage: C = Curve(X^5+11*X*Y*Z^3 + X^2*Y^3 - 13*Y^2*Z^3) + sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2) + sage: C = Curve(X^5 + 11*X*Y*Z^3 + X^2*Y^3 - 13*Y^2*Z^3) sage: len(C.rational_points()) 104 @@ -2146,16 +2219,17 @@ def rational_points(self, algorithm="enum", sort=True): if algorithm == "bn": return self._points_via_singular(sort=sort) - elif algorithm == "all": + + if algorithm == "all": S_enum = self.rational_points(algorithm="enum") S_bn = self.rational_points(algorithm="bn") if S_enum != S_bn: raise RuntimeError("Bug in rational_points -- different\ algorithms give different answers for\ - curve %s!"%self) + curve %s!" % self) return S_enum - else: - raise ValueError("No algorithm '{}' known".format(algorithm)) + + raise ValueError(f"No algorithm '{algorithm}' known") class IntegralProjectiveCurve(ProjectiveCurve_field): @@ -2201,6 +2275,7 @@ def function_field(self): :: + sage: # needs sage.rings.finite_rings sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2) sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5) sage: C.function_field() @@ -2215,9 +2290,9 @@ def _genus(self): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2) - sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5) - sage: C.genus() # indirect doctest + sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2) # needs sage.rings.finite_rings + sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5) # needs sage.rings.finite_rings + sage: C.genus() # indirect doctest # needs sage.rings.finite_rings 1 """ return self._open_affine.genus() @@ -2228,6 +2303,7 @@ def __call__(self, *args): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2) sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5) sage: C(1,1,1) @@ -2236,8 +2312,8 @@ def __call__(self, *args): (y/(y^5 + 1))*z^4 + (y^2/(y^5 + 1))*z^2 sage: C(GF(4^2)) Set of rational points of Closed subscheme of Projective Space of - dimension 2 over Finite Field in z4 of size 2^4 defined by: x^5 + - y^5 + x*y*z^3 + z^5 + dimension 2 over Finite Field in z4 of size 2^4 defined by: + x^5 + y^5 + x*y*z^3 + z^5 """ try: return super().__call__(*args) @@ -2253,6 +2329,7 @@ def function(self, f): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2) sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5) sage: f = C.function(x/y); f @@ -2282,6 +2359,7 @@ def coordinate_functions(self, i=None): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2) sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5) sage: C.coordinate_functions(0) @@ -2365,7 +2443,7 @@ def _singularities(self): """ S = self.ambient_space().coordinate_ring() to_F = self._lift_to_function_field - sing = self.singular_subscheme() # singular locus + sing = self.singular_subscheme() # singular locus # for each affine patch, places on which the dehomogenized polynomials # defining the singular locus are collected. @@ -2396,7 +2474,7 @@ def _singularities(self): if p == q: places.append(place) break - else: # new singularity + else: # new singularity points_and_places.append((p, [place])) return points_and_places @@ -2444,7 +2522,7 @@ def place_to_closed_point(self, place): F = self.function_field() A = self.ambient_space() - S = A.coordinate_ring().change_ring(order='degrevlex') # homogeneous coordinate ring + S = A.coordinate_ring().change_ring(order='degrevlex') # homogeneous coordinate ring # prepare coordinates for the affine patch containing the place vals = [f.valuation(place) for f in self._coordinate_functions] @@ -2459,18 +2537,18 @@ def place_to_closed_point(self, place): # implement an FGLM-like algorithm e = [0 for i in range(R.ngens())] basis = [R.one()] - basis_vecs = [to_V(k.one())] # represent as a vector + basis_vecs = [to_V(k.one())] # represent as a vector gens = [] gens_lts = [] terminate = False - while True: # check FGLM termination condition + while True: # check FGLM termination condition # compute next exponent in degree reverse lexicographical order j = R.ngens() - 1 while j > 0 and not e[j]: j -= 1 - if not j: # j is zero + if not j: # j is zero if terminate: break terminate = True @@ -2488,11 +2566,11 @@ def place_to_closed_point(self, place): prod = 1 for i in range(R.ngens()): prod *= coords[i]**e[i] - vec = to_V(to_k(prod)) # represent as a vector + vec = to_V(to_k(prod)) # represent as a vector mat = matrix(basis_vecs) try: s = mat.solve_left(vec) - except ValueError: # no solution + except ValueError: # no solution basis.append(m) basis_vecs.append(vec) terminate = False @@ -2522,7 +2600,8 @@ def places_on(self, point): [Point (x, y)] sage: p, = _ sage: C.places_on(p) - [Place (1/y, 1/y^2*z, 1/y^3*z^2, 1/y^4*z^3), Place (y, y*z, y*z^2, y*z^3)] + [Place (1/y, 1/y^2*z, 1/y^3*z^2, 1/y^4*z^3), + Place (y, y*z, y*z^2, y*z^3)] sage: pl1, pl2 =_ sage: C.place_to_closed_point(pl1) Point (x, y) @@ -2631,6 +2710,7 @@ def closed_points(self, degree=1): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A.<x,y> = AffineSpace(GF(9),2) sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x-2) sage: Cp = C.projective_closure() @@ -2710,6 +2790,7 @@ def number_of_rational_points(self, r=1): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: A.<x,y> = AffineSpace(GF(3), 2) sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2) sage: Cbar = C.projective_closure() @@ -2726,7 +2807,7 @@ def number_of_rational_points(self, r=1): L = self.L_polynomial() Lp = L.derivative() - R = IntegerRing()[[L.parent().gen()]] # power series ring + R = IntegerRing()[[L.parent().gen()]] # power series ring L = R(L) Lp = R(Lp) @@ -2753,8 +2834,9 @@ class IntegralProjectivePlaneCurve_finite_field(IntegralProjectiveCurve_finite_f EXAMPLES:: - sage: A.<x,y> = AffineSpace(GF(9),2) - sage: C = Curve(y^2-x^5-x^4-2*x^3-2*x-2) + sage: # needs sage.rings.finite_rings + sage: A.<x,y> = AffineSpace(GF(9), 2) + sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2) sage: Cb = C.projective_closure() sage: Cb.singular_closed_points() [Point (x0, x1)] @@ -2763,6 +2845,7 @@ class IntegralProjectivePlaneCurve_finite_field(IntegralProjectiveCurve_finite_f """ _point = IntegralProjectivePlaneCurvePoint_finite_field + def Hasse_bounds(q, genus=1): r""" Return the Hasse-Weil bounds for the cardinality of a nonsingular @@ -2774,25 +2857,23 @@ def Hasse_bounds(q, genus=1): - ``genus`` (int, default 1) -- a non-negative integer, - OUTPUT: - - (tuple) The Hasse bounds (lb,ub) for the cardinality of a curve of + OUTPUT: A tuple. The Hasse bounds (lb,ub) for the cardinality of a curve of genus ``genus`` defined over `\GF{q}`. EXAMPLES:: sage: Hasse_bounds(2) (1, 5) - sage: Hasse_bounds(next_prime(10^30)) + sage: Hasse_bounds(next_prime(10^30)) # needs sage.libs.pari (999999999999998000000000000058, 1000000000000002000000000000058) """ if genus == 1: rq = (4*q).isqrt() else: rq = (4*(genus**2)*q).isqrt() - return (q+1-rq,q+1+rq) + return (q+1-rq, q+1+rq) + # Fix pickles from changing class names and plane_curves folder name -from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.schemes.plane_curves.projective_curve', 'ProjectiveCurve_generic', ProjectivePlaneCurve) diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 01e50f43ea0..0940825b9a5 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs sage.groups sage.rings.number_field r""" Zariski-Van Kampen method implementation @@ -22,10 +23,13 @@ EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco - sage: R.<x,y> = QQ[] - sage: f = y^3 + x^3 -1 - sage: fundamental_group(f) # optional - sirocco + sage: # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import fundamental_group, braid_monodromy + sage: R.<x, y> = QQ[] + sage: f = y^3 + x^3 - 1 + sage: braid_monodromy(f) + ([s1*s0, s1*s0, s1*s0], {0: 0, 1: 0, 2: 0}) + sage: fundamental_group(f) Finitely presented group < x0 | > """ # **************************************************************************** @@ -39,25 +43,32 @@ # **************************************************************************** import itertools from copy import copy - +from sage.combinat.combination import Combinations from sage.combinat.permutation import Permutation +from sage.functions.generalized import sign from sage.geometry.voronoi_diagram import VoronoiDiagram from sage.graphs.graph import Graph from sage.groups.braid import BraidGroup +from sage.groups.finitely_presented import wrap_FpGroup from sage.groups.free_group import FreeGroup from sage.groups.perm_gps.permgroup_named import SymmetricGroup +from sage.libs.braiding import leftnormalform, rightnormalform +from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_function from sage.misc.flatten import flatten from sage.misc.misc_c import prod from sage.parallel.decorate import parallel from sage.rings.complex_interval_field import ComplexIntervalField from sage.rings.complex_mpfr import ComplexField +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import NumberField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.qqbar import QQbar from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RealField +# from sage.sets.set import Set - -roots_interval_cache = {} +roots_interval_cache = dict() def braid_from_piecewise(strands): @@ -76,11 +87,12 @@ def braid_from_piecewise(strands): EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import braid_from_piecewise # optional - sirocco + sage: # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import braid_from_piecewise sage: paths = [[(0, 0, 1), (0.2, -1, -0.5), (0.8, -1, 0), (1, 0, -1)], ....: [(0, -1, 0), (0.5, 0, -1), (1, 1, 0)], ....: [(0, 1, 0), (0.5, 1, 1), (1, 0, 1)]] - sage: braid_from_piecewise(paths) # optional - sirocco + sage: braid_from_piecewise(paths) s0*s1 """ L = strands @@ -153,43 +165,63 @@ def sgn(x, y): return B(braid) -def discrim(f): +def discrim(pols): r""" - Return the points in the discriminant of ``f``. + Return the points in the discriminant of the product of the polynomials + of a list or tuple ``pols``. The result is the set of values of the first variable for which two roots in the second variable coincide. INPUT: - - ``f`` -- a polynomial in two variables with coefficients in a - number field with a fixed embedding in `\QQbar` + - ``pols`` -- a list or tuple of polynomials in two variables with + coefficients in a number field with a fixed embedding in `\QQbar` OUTPUT: - A list with the values of the discriminant in `\QQbar`. + A tuple with the roots of the discriminant in `\QQbar`. EXAMPLES:: sage: from sage.schemes.curves.zariski_vankampen import discrim - sage: R.<x,y> = QQ[] - sage: f = (y^3 + x^3 - 1) * (x + y) - sage: discrim(f) - [1, + sage: R.<x, y> = QQ[] + sage: flist = (y^3 + x^3 - 1, 2 * x + y) + sage: discrim(flist) + (1, -0.500000000000000? - 0.866025403784439?*I, - -0.500000000000000? + 0.866025403784439?*I] + -0.500000000000000? + 0.866025403784439?*I, + -0.522757958574711?, + 0.2613789792873551? - 0.4527216721561923?*I, + 0.2613789792873551? + 0.4527216721561923?*I) """ - x, y = f.parent().gens() - F = f.base_ring() - poly = F[x](f.discriminant(y)).radical() - return poly.roots(QQbar, multiplicities=False) + flist = tuple(pols) + x, y = flist[0].parent().gens() + field = flist[0].base_ring() + pol_ring = PolynomialRing(field, (x,)) + + @parallel + def discrim_pairs(f, g): + if g is None: + return pol_ring(f.discriminant(y)) + return pol_ring(f.resultant(g, y)) + + pairs = [(f, None) for f in flist] + [(f, g) for f, g in Combinations(flist, 2)] + fdiscrim = discrim_pairs(pairs) + rts = () + poly = 1 + for u in fdiscrim: + h0 = u[1].radical() + h1 = h0 // h0.gcd(poly) + rts += tuple(h1.roots(QQbar, multiplicities=False)) + poly = poly * h1 + return rts @cached_function def corrected_voronoi_diagram(points): r""" Compute a Voronoi diagram of a set of points with rational coordinates. - The given points are granted to lie one in each bounded region. INPUT: @@ -198,7 +230,7 @@ def corrected_voronoi_diagram(points): OUTPUT: - A VoronoiDiagram constructed from rational approximations of the points, + A Voronoi diagram constructed from rational approximations of the points, with the guarantee that each bounded region contains exactly one of the input points. @@ -243,56 +275,193 @@ def corrected_voronoi_diagram(points): return V -def segments(points): +def orient_circuit(circuit, convex=False, precision=53, verbose=False): + r""" + Reverse a circuit if it goes clockwise; otherwise leave it unchanged. + + INPUT: + + - ``circuit`` -- a circuit in the graph of a Voronoi Diagram, given + by a list of edges + + - ``convex`` -- boolean (default: `False`), if set to ``True`` a simpler + computation is made + + - ``precision`` -- bits of precision (default: 53) + + - ``verbose`` -- boolean (default: ``False``) for testing purposes + + OUTPUT: + + The same circuit if it goes counterclockwise, and its reversed otherwise, + given as the ordered list of vertices with identic extremities. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import orient_circuit + sage: points = [(-4, 0), (4, 0), (0, 4), (0, -4), (0, 0)] + sage: V = VoronoiDiagram(points) + sage: E = Graph() + sage: for reg in V.regions().values(): + ....: if reg.rays() or reg.lines(): + ....: E = E.union(reg.vertex_graph()) + sage: E.vertices(sort=True) + [A vertex at (-2, -2), + A vertex at (-2, 2), + A vertex at (2, -2), + A vertex at (2, 2)] + sage: cir = E.eulerian_circuit() + sage: cir + [(A vertex at (-2, -2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (-2, -2), None)] + sage: cir_oriented = orient_circuit(cir); cir_oriented + (A vertex at (-2, -2), A vertex at (2, -2), A vertex at (2, 2), + A vertex at (-2, 2), A vertex at (-2, -2)) + sage: cirinv = list(reversed([(c[1],c[0],c[2]) for c in cir])) + sage: cirinv + [(A vertex at (-2, -2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (-2, -2), None)] + sage: orient_circuit(cirinv) == cir_oriented + True + sage: cir_oriented == orient_circuit(cir, convex=True) + True + sage: P0=[(1,1/2),(0,1),(1,1)]; P1=[(0,3/2),(-1,0)] + sage: Q=Polyhedron(P0).vertices() + sage: Q = [Q[2], Q[0], Q[1]] + [_ for _ in reversed(Polyhedron(P1).vertices())] + sage: Q + [A vertex at (1, 1/2), A vertex at (0, 1), A vertex at (1, 1), + A vertex at (0, 3/2), A vertex at (-1, 0)] + sage: E = Graph() + sage: for v, w in zip(Q, Q[1:] + [Q[0]]): + ....: E.add_edge((v, w)) + sage: cir = orient_circuit(E.eulerian_circuit(), precision=1, verbose=True) + 2 + sage: cir + (A vertex at (1, 1/2), A vertex at (0, 1), A vertex at (1, 1), + A vertex at (0, 3/2), A vertex at (-1, 0), A vertex at (1, 1/2)) """ - Return the bounded segments of the Voronoi diagram of the given points. + vectors = [v[1].vector() - v[0].vector() for v in circuit] + circuit_vertex = (circuit[0][0],) + tuple(e[1] for e in circuit) + circuit_vertex = tuple(circuit_vertex) + if convex: + pr = matrix([vectors[0], vectors[1]]).determinant() + if pr > 0: + # return circuit + return circuit_vertex + elif pr < 0: + # return list(reversed([(c[1], c[0]) + c[2:] for c in circuit])) + return tuple(reversed(circuit_vertex)) + prec = precision + while True: + CIF = ComplexIntervalField(prec) + totalangle = sum((CIF(*vectors[i]) / CIF(*vectors[i - 1])).argument() + for i in range(len(vectors))) + if totalangle < 0: + # return list(reversed([(c[1], c[0]) + c[2:] for c in circuit])) + return tuple(reversed(circuit_vertex)) + if totalangle > 0: + # return circuit + return circuit_vertex + prec *= 2 + if verbose: + print(prec) + + +def voronoi_cells(V): + r""" + Compute the graph, the boundary graph, a base point, a positive orientation + of the boundary graph, and the dual graph of a corrected Voronoi diagram. INPUT: - - ``points`` -- a list of complex points + - ``V`` -- a corrected Voronoi diagram OUTPUT: - A list of pairs ``(p1, p2)``, where ``p1`` and ``p2`` are the - endpoints of the segments in the Voronoi diagram. + - ``G`` -- the graph of the 1-skeleton of ``V`` + - ``E`` -- the subgraph of the boundary + - ``p`` -- a vertex in ``E`` + - ``EC`` -- a list of vertices (representing a counterclockwise orientation + of ``E``) with identical first and last elements) + - ``DG`` -- the dual graph of ``V``, where the vertices are labelled + by the compact regions of ``V`` and the edges by their dual edges. EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import discrim, segments - sage: R.<x,y> = QQ[] - sage: f = y^3 + x^3 - 1 - sage: disc = discrim(f) - sage: sorted(segments(disc)) - [(-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, - -192951821525958031/90044183378780414), - (-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, - -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), - (192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, - 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), - (-192951821525958031/90044183378780414, - 192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316), - (-192951821525958031/90044183378780414, 1/38590364305191606), - (1/38590364305191606, - -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), - (1/38590364305191606, - 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), - (-5/2*I + 5/2, - -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), - (-5/2*I + 5/2, 5/2*I + 5/2), - (5/2*I + 5/2, - 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326)] + sage: from sage.schemes.curves.zariski_vankampen import corrected_voronoi_diagram, voronoi_cells + sage: points = (2, I, 0.000001, 0, 0.000001*I) + sage: V = corrected_voronoi_diagram(points) + sage: G, E, p, EC, DG = voronoi_cells(V) + sage: Gv = G.vertices(sort=True) + sage: Ge = G.edges(sort=True) + sage: len(Gv), len(Ge) + (12, 16) + sage: Ev = E.vertices(sort=True); Ev + [A vertex at (-4, 4), + A vertex at (-49000001/14000000, 1000001/2000000), + A vertex at (-7/2, -7/2), + A vertex at (-7/2, 1/2000000), + A vertex at (1/2000000, -7/2), + A vertex at (2000001/2000000, -24500001/7000000), + A vertex at (11/4, 4), + A vertex at (9/2, -9/2), + A vertex at (9/2, 9/2)] + sage: Ev.index(p) + 7 + sage: EC + (A vertex at (9/2, -9/2), + A vertex at (9/2, 9/2), + A vertex at (11/4, 4), + A vertex at (-4, 4), + A vertex at (-49000001/14000000, 1000001/2000000), + A vertex at (-7/2, 1/2000000), + A vertex at (-7/2, -7/2), + A vertex at (1/2000000, -7/2), + A vertex at (2000001/2000000, -24500001/7000000), + A vertex at (9/2, -9/2)) + sage: len(DG.vertices(sort=True)), len(DG.edges(sort=True)) + (5, 7) + sage: edg = DG.edges(sort=True)[0]; edg + ((0, + (A vertex at (9/2, -9/2), + A vertex at (9/2, 9/2), + A vertex at (11/4, 4), + A vertex at (2000001/2000000, 500001/1000000), + A vertex at (2000001/2000000, -24500001/7000000), + A vertex at (9/2, -9/2))), + (1, + (A vertex at (-49000001/14000000, 1000001/2000000), + A vertex at (1000001/2000000, 1000001/2000000), + A vertex at (2000001/2000000, 500001/1000000), + A vertex at (11/4, 4), + A vertex at (-4, 4), + A vertex at (-49000001/14000000, 1000001/2000000))), + (A vertex at (2000001/2000000, 500001/1000000), A vertex at (11/4, 4), None)) + sage: edg[-1] in Ge + True """ - V = corrected_voronoi_diagram(tuple(points)) - res = set() - for region in V.regions().values(): - if region.rays(): - continue - for s in region.facets(): - t = tuple((tuple(v.vector()) for v in s.vertices())) - if t not in res and not tuple(reversed(t)) in res: - res.add(t) - return [(r[0] + QQbar.gen() * r[1], - s[0] + QQbar.gen() * s[1]) for r, s in res] + compact_regions = [_ for _ in V.regions().values() if _.is_compact()] + non_compact_regions = [_ for _ in V.regions().values() if not _.is_compact()] + G = Graph([u.vertices() for v in compact_regions for u in v.faces(1)], format='list_of_edges') + E = Graph([u.vertices() for v in non_compact_regions for u in v.faces(1) if u.is_compact()], format='list_of_edges') + p = next(E.vertex_iterator()) + EC = orient_circuit(E.eulerian_circuit()) + # EC = [EC0[0][0]] + [e[1] for e in EC0] + DG = Graph() + for i, reg in enumerate(compact_regions): + Greg0 = orient_circuit(reg.graph().eulerian_circuit(), convex=True) + # Greg = (Greg0[0][0],) + tuple(e[1] for e in Greg0) + DG.add_vertex((i, Greg0)) + for e in G.edges(sort=True): + a, b = e[:2] + regs = [v for v in DG.vertices(sort=True) if a in v[1] and b in v[1]] + if len(regs) == 2: + DG.add_edge(regs[0], regs[1], e) + return (G, E, p, EC, DG) def followstrand(f, factors, x0, x1, y0a, prec=53): @@ -323,18 +492,19 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import followstrand # optional - sirocco - sage: R.<x,y> = QQ[] + sage: # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import followstrand + sage: R.<x, y> = QQ[] sage: f = x^2 + y^3 sage: x0 = CC(1, 0) sage: x1 = CC(1, 0.5) - sage: followstrand(f, [], x0, x1, -1.0) # optional - sirocco # abs tol 1e-15 + sage: followstrand(f, [], x0, x1, -1.0) # abs tol 1e-15 [(0.0, -1.0, 0.0), (0.7500000000000001, -1.015090921153253, -0.24752813818386948), (1.0, -1.026166099551513, -0.32768940253604323)] - sage: fup = f.subs({y:y-1/10}) - sage: fdown = f.subs({y:y+1/10}) - sage: followstrand(f, [fup, fdown], x0, x1, -1.0) # optional - sirocco # abs tol 1e-15 + sage: fup = f.subs({y: y - 1/10}) + sage: fdown = f.subs({y: y + 1/10}) + sage: followstrand(f, [fup, fdown], x0, x1, -1.0) # abs tol 1e-15 [(0.0, -1.0, 0.0), (0.5303300858899107, -1.0076747107983448, -0.17588022709184917), (0.7651655429449553, -1.015686131039112, -0.25243563967299404), @@ -401,7 +571,7 @@ def newton(f, x0, i0): INPUT: - - ``f``` -- a univariate polynomial + - ``f`` -- a univariate polynomial - ``x0`` -- a number - ``I0`` -- an interval @@ -427,6 +597,56 @@ def newton(f, x0, i0): return x0 - f(x0) / f.derivative()(i0) +def fieldI(field): + r""" + Return the (either double or trivial) extension of a number field which contains ``I``. + + INPUT: + + - ``field`` -- a number field with an embedding in ``QQbar``. + + OUTPUT: + + The extension ``F`` of ``field`` containing ``I`` with an embedding in ``QQbar``. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import fieldI + sage: p = QQ[x](x^5 + 2 * x + 1) + sage: a0 = p.roots(QQbar, multiplicities=False)[0] + sage: F0.<a> = NumberField(p, embedding=a0) + sage: fieldI(F0) + Number Field in b with defining polynomial + x^10 + 5*x^8 + 14*x^6 - 2*x^5 - 10*x^4 + 20*x^3 - 11*x^2 - 14*x + 10 + with b = 0.4863890359345430? + 1.000000000000000?*I + + If ``I`` is already in the field, the result is the field itself:: + + sage: from sage.schemes.curves.zariski_vankampen import fieldI + sage: p = QQ[x](x^4 + 1) + sage: a0 = p.roots(QQbar, multiplicities=False)[0] + sage: F0.<a> = NumberField(p, embedding=a0) + sage: F1 = fieldI(F0) + sage: F0 == F1 + True + """ + I0 = QQbar.gen() + if I0 in field: + return field + field_a = field[I0] + field_b = field_a.absolute_field('b0') + b0 = field_b.gen() + q = b0.minpoly() + qembd = field_b.embeddings(QQbar) + for h1 in qembd: + b1 = h1(b0) + b2 = h1(field_b(field_a.gen(0))) + b3 = field.gen(0) + F1 = NumberField(q, 'b', embedding=b1) + if b3 in F1 and b2.imag() > 0: + return F1 + + @parallel def roots_interval(f, x0): """ @@ -436,10 +656,11 @@ def roots_interval(f, x0): INPUT: - ``f`` -- a bivariate squarefree polynomial - - ``x0`` -- a value where the first coordinate will be fixed + - ``x0`` -- a Gauss rational number corresponding to the first coordinate The intervals are taken as big as possible to be able to detect when two - approximate roots of `f(x_0, y)` correspond to the same exact root. + approximate roots of `f(x_0, y)` correspond to the same exact root, where + `f` is the product of the polynomials in `flist`. The result is given as a dictionary, where the keys are approximations to the roots with rational real and imaginary @@ -447,9 +668,11 @@ def roots_interval(f, x0): EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import roots_interval - sage: R.<x,y> = QQ[] + sage: from sage.schemes.curves.zariski_vankampen import roots_interval, fieldI + sage: R.<x, y> = QQ[] + sage: K = fieldI(QQ) sage: f = y^3 - x^2 + sage: f = f.change_ring(K) sage: ri = roots_interval(f, 1) sage: ri {-138907099/160396102*I - 1/2: -1.? - 1.?*I, @@ -469,9 +692,9 @@ def roots_interval(f, x0): -0.933012701892219 + 1.29903810567666*I, -0.0669872981077806 + 0.433012701892219*I)] """ + F1 = f.base_ring() x, y = f.parent().gens() - I = QQbar.gen() - fx = QQbar[y](f.subs({x: QQ(x0.real()) + I * QQ(x0.imag())})) + fx = F1[y](f.subs({x: F1(x0)})) roots = fx.roots(QQbar, multiplicities=False) result = {} for i, r in enumerate(roots): @@ -503,9 +726,11 @@ def roots_interval_cached(f, x0): TESTS:: - sage: from sage.schemes.curves.zariski_vankampen import roots_interval, roots_interval_cached, roots_interval_cache - sage: R.<x,y> = QQ[] + sage: from sage.schemes.curves.zariski_vankampen import roots_interval, roots_interval_cached, roots_interval_cache, fieldI + sage: R.<x, y> = QQ[] + sage: K = fieldI(QQ) sage: f = y^3 - x^2 + sage: f = f.change_ring(K) sage: (f, 1) in roots_interval_cache False sage: ri = roots_interval_cached(f, 1) @@ -532,13 +757,15 @@ def populate_roots_interval_cache(inputs): INPUT: - - ``inputs`` -- a list of tuples (f, x0) + - ``inputs`` -- a list of tuples ``(f, x0)`` EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import populate_roots_interval_cache, roots_interval_cache + sage: from sage.schemes.curves.zariski_vankampen import populate_roots_interval_cache, roots_interval_cache, fieldI sage: R.<x,y> = QQ[] + sage: K=fieldI(QQ) sage: f = y^5 - x^2 + sage: f = f.change_ring(K) sage: (f, 3) in roots_interval_cache False sage: populate_roots_interval_cache([(f, 3)]) @@ -554,22 +781,30 @@ def populate_roots_interval_cache(inputs): """ global roots_interval_cache tocompute = [inp for inp in inputs if inp not in roots_interval_cache] - result = roots_interval(tocompute) - for r in result: - roots_interval_cache[r[0][0]] = r[1] + problem_par = True + while problem_par: # hack to deal with random fails in parallelization + try: + result = roots_interval(tocompute) + for r in result: + roots_interval_cache[r[0][0]] = r[1] + problem_par = False + except TypeError: + pass @parallel -def braid_in_segment(g, x0, x1): +def braid_in_segment(glist, x0, x1, precision=dict()): """ Return the braid formed by the `y` roots of ``f`` when `x` moves from ``x0`` to ``x1``. INPUT: - - ``g`` -- a polynomial factorization in two variables - - ``x0`` -- a complex number - - ``x1`` -- a complex number + - ``glist`` -- a tuple of polynomials in two variables + - ``x0`` -- a Gauss rational + - ``x1`` -- a Gauss rational + - ``precision`` -- a dictionary (default: `dict()`) which assigns a number + precision bits to each element of ``glist`` OUTPUT: @@ -577,182 +812,135 @@ def braid_in_segment(g, x0, x1): EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import braid_in_segment # optional - sirocco - sage: R.<x,y> = QQ[] + sage: # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import braid_in_segment, fieldI + sage: R.<x, y> = QQ[] + sage: K = fieldI(QQ) sage: f = x^2 + y^3 - sage: x0 = CC(1,0) - sage: x1 = CC(1, 0.5) - sage: braid_in_segment(f.factor(), x0, x1) # optional - sirocco + sage: f = f.change_ring(K) + sage: x0 = 1 + sage: x1 = 1 + I / 2 + sage: braid_in_segment(tuple(_[0] for _ in f.factor()), x0, x1) s1 TESTS: Check that :trac:`26503` is fixed:: + sage: # needs sage.rings.real_mpfr sage.symbolic sage: wp = QQ['t']([1, 1, 1]).roots(QQbar)[0][0] sage: Kw.<wp> = NumberField(wp.minpoly(), embedding=wp) sage: R.<x, y> = Kw[] sage: z = -wp - 1 - sage: f = y*(y + z)*x*(x - 1)*(x - y)*(x + z*y - 1)*(x + z*y + wp) - sage: from sage.schemes.curves import zariski_vankampen as zvk - sage: g = f.subs({x: x + 2*y}) + sage: f = y * (y + z) * x * (x - 1) * (x - y) * (x + z * y - 1) * (x + z * y + wp) + sage: from sage.schemes.curves.zariski_vankampen import fieldI, braid_in_segment + sage: Kw1 = fieldI(Kw) + sage: g = f.subs({x: x + 2 * y}) + sage: g = g.change_ring(Kw1) sage: p1 = QQbar(sqrt(-1/3)) - sage: p2 = QQbar(1/2+sqrt(-1/3)/2) - sage: B = zvk.braid_in_segment(g.factor(),CC(p1),CC(p2)) # optional - sirocco - sage: B # optional - sirocco + sage: p1a = CC(p1) + sage: p1b = QQ(p1a.real()) + I*QQ(p1a.imag()) + sage: p2 = QQbar(1/2 + sqrt(-1/3)/2) + sage: p2a = CC(p2) + sage: p2b = QQ(p2a.real()) + I*QQ(p2a.imag()) + sage: glist = tuple([_[0] for _ in g.factor()]) + sage: B = braid_in_segment(glist, p1b, p2b); B # optional - sirocco s5*s3^-1 """ - _, y = g.value().parent().gens() - I = QQbar.gen() - X0 = QQ(x0.real()) + I * QQ(x0.imag()) - X1 = QQ(x1.real()) + I * QQ(x1.imag()) + precision1 = {_: precision[_] for _ in precision.keys()} + g = prod(glist) + F1 = g.base_ring() + x, y = g.parent().gens() + X0 = F1(x0) + X1 = F1(x1) intervals = {} - precision = {} + if not precision1: # new + precision1 = {f: 53 for f in glist} # new y0s = [] - for f, _ in g: + for f in glist: if f.variables() == (y,): - F0 = QQbar[y](f.base_ring()[y](f)) + f0 = F1[y](f) else: - F0 = QQbar[y](f(X0, y)) - y0sf = F0.roots(multiplicities=False) + f0 = F1[y](f.subs({x: X0})) + y0sf = f0.roots(QQbar, multiplicities=False) y0s += list(y0sf) - precision[f] = 53 while True: - CIFp = ComplexIntervalField(precision[f]) + CIFp = ComplexIntervalField(precision1[f]) intervals[f] = [r.interval(CIFp) for r in y0sf] if not any(a.overlaps(b) for a, b in itertools.combinations(intervals[f], 2)): break - precision[f] *= 2 - strands = [followstrand(f[0], [p[0] for p in g if p[0] != f[0]], x0, x1, i.center(), precision[f[0]]) for f in g for i in intervals[f[0]]] + precision1[f] *= 2 + strands = [] + for f in glist: + for i in intervals[f]: + aux = followstrand(f, [p for p in glist if p != f], x0, x1, i.center(), precision1[f]) + strands.append(aux) complexstrands = [[(QQ(a[0]), QQ(a[1]), QQ(a[2])) for a in b] for b in strands] centralbraid = braid_from_piecewise(complexstrands) initialstrands = [] finalstrands = [] - initialintervals = roots_interval_cached(g.value(), X0) - finalintervals = roots_interval_cached(g.value(), X1) + initialintervals = roots_interval_cached(g, X0) + finalintervals = roots_interval_cached(g, X1) + I1 = QQbar.gen() for cs in complexstrands: - ip = cs[0][1] + I * cs[0][2] - fp = cs[-1][1] + I * cs[-1][2] + ip = cs[0][1] + I1 * cs[0][2] + fp = cs[-1][1] + I1 * cs[-1][2] matched = 0 for center, interval in initialintervals.items(): if ip in interval: initialstrands.append([(0, center.real(), center.imag()), (1, cs[0][1], cs[0][2])]) matched += 1 - if matched == 0: - raise ValueError("unable to match braid endpoint with root") - if matched > 1: - raise ValueError("braid endpoint mathes more than one root") + if matched != 1: + precision1 = {f: precision1[f] * 2 for f in glist} # new + return braid_in_segment(glist, x0, x1, precision=precision1) # new + matched = 0 for center, interval in finalintervals.items(): if fp in interval: finalstrands.append([(0, cs[-1][1], cs[-1][2]), (1, center.real(), center.imag())]) matched += 1 - if matched == 0: - raise ValueError("unable to match braid endpoint with root") - if matched > 1: - raise ValueError("braid endpoint matches more than one root") + if matched != 1: + precision1 = {f: precision1[f] * 2 for f in glist} # new + return braid_in_segment(glist, x0, x1, precision=precision1) # new initialbraid = braid_from_piecewise(initialstrands) finalbraid = braid_from_piecewise(finalstrands) return initialbraid * centralbraid * finalbraid -def orient_circuit(circuit): - r""" - Reverse a circuit if it goes clockwise; otherwise leave it unchanged. - - INPUT: - - - ``circuit`` -- a circuit in the graph of a Voronoi Diagram, given - by a list of edges - - OUTPUT: - - The same circuit if it goes counterclockwise, and its reverse otherwise - - EXAMPLES:: - - sage: from sage.schemes.curves.zariski_vankampen import orient_circuit - sage: points = [(-4, 0), (4, 0), (0, 4), (0, -4), (0, 0)] - sage: V = VoronoiDiagram(points) - sage: E = Graph() - sage: for reg in V.regions().values(): - ....: if reg.rays() or reg.lines(): - ....: E = E.union(reg.vertex_graph()) - sage: E.vertices(sort=True) - [A vertex at (-2, -2), - A vertex at (-2, 2), - A vertex at (2, -2), - A vertex at (2, 2)] - sage: cir = E.eulerian_circuit() - sage: cir - [(A vertex at (-2, -2), A vertex at (2, -2), None), - (A vertex at (2, -2), A vertex at (2, 2), None), - (A vertex at (2, 2), A vertex at (-2, 2), None), - (A vertex at (-2, 2), A vertex at (-2, -2), None)] - sage: orient_circuit(cir) - [(A vertex at (-2, -2), A vertex at (2, -2), None), - (A vertex at (2, -2), A vertex at (2, 2), None), - (A vertex at (2, 2), A vertex at (-2, 2), None), - (A vertex at (-2, 2), A vertex at (-2, -2), None)] - sage: cirinv = list(reversed([(c[1],c[0],c[2]) for c in cir])) - sage: cirinv - [(A vertex at (-2, -2), A vertex at (-2, 2), None), - (A vertex at (-2, 2), A vertex at (2, 2), None), - (A vertex at (2, 2), A vertex at (2, -2), None), - (A vertex at (2, -2), A vertex at (-2, -2), None)] - sage: orient_circuit(cirinv) - [(A vertex at (-2, -2), A vertex at (2, -2), None), - (A vertex at (2, -2), A vertex at (2, 2), None), - (A vertex at (2, 2), A vertex at (-2, 2), None), - (A vertex at (-2, 2), A vertex at (-2, -2), None)] - - """ - prec = 53 - vectors = [v[1].vector() - v[0].vector() for v in circuit] - while True: - CIF = ComplexIntervalField(prec) - totalangle = sum((CIF(*vectors[i]) / CIF(*vectors[i - 1])).argument() - for i in range(len(vectors))) - if totalangle < 0: - return list(reversed([(c[1], c[0]) + c[2:] for c in circuit])) - if totalangle > 0: - return circuit - prec *= 2 - - -def geometric_basis(G, E, p): +def geometric_basis(G, E, EC0, p, dual_graph): r""" Return a geometric basis, based on a vertex. INPUT: - - ``G`` -- the graph of the bounded regions of a Voronoi Diagram + - ``G`` -- a graph with the bounded edges of a Voronoi Diagram + + - ``E`` -- a subgraph of ``G`` which is a cycle containing the bounded + edges touching an unbounded region of a Voronoi Diagram - - ``E`` -- the subgraph of ``G`` formed by the edges that touch - an unbounded region + - ``EC0`` -- A counterclockwise orientation of the vertices of ``E`` - ``p`` -- a vertex of ``E`` + - ``dual_graph`` -- a dual graph for a plane embedding of ``G`` such that + ``E`` is the boundary of the non-bounded component of the complement. + The edges are labelled as the dual edges and the vertices are labelled + by a tuple whose first element is the an integer for the position and the + second one is the cyclic ordered list of vertices in the region. + OUTPUT: A geometric basis. It is formed by a list of sequences of paths. - Each path is a list of vertices, that form a closed path in `G`, based at - `p`, that goes to a region, surrounds it, and comes back by the same - path it came. The concatenation of all these paths is equivalent to `E`. + Each path is a list of vertices, that form a closed path in ``G``, based at + ``p``, that goes to a region, surrounds it, and comes back by the same + path it came. The concatenation of all these paths is equivalent to ``E``. EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import geometric_basis + sage: from sage.schemes.curves.zariski_vankampen import geometric_basis, voronoi_cells sage: points = [(-3,0),(3,0),(0,3),(0,-3)]+ [(0,0),(0,-1),(0,1),(1,0),(-1,0)] sage: V = VoronoiDiagram(points) - sage: G = Graph() - sage: for reg in V.regions().values(): - ....: G = G.union(reg.vertex_graph()) - sage: E = Graph() - sage: for reg in V.regions().values(): - ....: if reg.rays() or reg.lines(): - ....: E = E.union(reg.vertex_graph()) - sage: p = E.vertices(sort=True)[0] - sage: geometric_basis(G, E, p) + sage: G, E, p, EC, DG = voronoi_cells(V) + sage: geometric_basis(G, E, EC, p, DG) [[A vertex at (-2, -2), A vertex at (2, -2), A vertex at (2, 2), @@ -789,74 +977,97 @@ def geometric_basis(G, E, p): A vertex at (-2, 2), A vertex at (-2, -2)]] """ - EC = [v[0] for v in orient_circuit(E.eulerian_circuit())] - i = EC.index(p) - EC = EC[i:] + EC[:i + 1] # A counterclockwise eulerian circuit on the boundary, based at p + i = EC0.index(p) + EC = EC0[i:-1] + EC0[:i + 1] # A counterclockwise eulerian circuit on the boundary, starting and ending at p if G.size() == E.size(): if E.is_cycle(): return [EC] - I = Graph() - for e in G.edges(sort=False): - if not E.has_edge(e): - I.add_edge(e) # interior graph - # treat the case where I is empty - if not I: - for v in E: - if len(E.neighbors(v)) > 2: - I.add_vertex(v) - + InternalEdges = [_ for _ in G.edges(sort=True) if _ not in E.edges(sort=True)] + InternalVertices = [v for e in InternalEdges for v in e[:2]] + Internal = G.subgraph(vertices=InternalVertices, edges=InternalEdges) for i, ECi in enumerate(EC): # q and r are the points we will cut through - - if EC[i] in I: - q = EC[i] - connecting_path = EC[:i] - break - if EC[-i] in I: - q = EC[-i] - connecting_path = list(reversed(EC[-i:])) - break - distancequotients = [(E.distance(q, v)**2 / I.distance(q, v), v) for v in E - if v in I.connected_component_containing_vertex(q) and not v == q] + if ECi in Internal: + EI = [v for v in E if v in Internal.connected_component_containing_vertex(ECi, sort=True) and v != ECi] + if len(EI) > 0: + q = ECi + connecting_path = list(EC[:i]) + break + if EC[-i] in Internal: + EI = [v for v in E if v in Internal.connected_component_containing_vertex(EC[-i], sort=True) and v != EC[-i]] + if len(EI) > 0: + q = EC[-i] + connecting_path = list(reversed(EC[-i:])) + break + # Precompute distances from q in E and I + E_dist_q = E.shortest_path_lengths(q) + I_dist_q = Internal.shortest_path_lengths(q) + distancequotients = [(E_dist_q[v]**2 / I_dist_q[v], v) for v in EI] + # distancequotients = [(E.distance(q, v)**2 / Internal.distance(q, v), v) for v in EI] r = max(distancequotients)[1] - cutpath = I.shortest_path(q, r) - Gcut = copy(G) + cutpath = Internal.shortest_path(q, r) + for i, v in enumerate(cutpath): + if i > 0 and v in EC: + r = v + cutpath = cutpath[:i+1] + break + qi = EC.index(q) + ri = EC.index(r) Ecut = copy(E) Ecut.delete_vertices([q, r]) - Gcut.delete_vertices(cutpath) - # I think this cannot happen, but just in case, we check it to raise - # an error instead of giving a wrong answer - if Gcut.connected_components_number() != 2: - raise ValueError("unable to compute a correct path") - G1, G2 = Gcut.connected_components_subgraphs() - - for v in cutpath: - neighs = G.neighbors(v) - for n in neighs: - if n in G1 or n in cutpath: - G1.add_edge(v, n, None) - if n in G2 or n in cutpath: - G2.add_edge(v, n, None) - - if EC[EC.index(q) + 1] in G2: - G1, G2 = G2, G1 - - E1, E2 = Ecut.connected_components_subgraphs() - if EC[EC.index(q) + 1] in E2: - E1, E2 = E2, E1 + subgraphs = Ecut.connected_components_subgraphs() + if len(subgraphs) == 2: + E1, E2 = subgraphs + if EC[qi + 1] in E2: + E1, E2 = E2, E1 + elif len(subgraphs) == 1: + E1 = subgraphs[0] + E2 = Graph() + E2.add_edge(q, r, None) + if r == EC[qi + 1]: + E1, E2 = E2, E1 + for v in [q, r]: + for n in E.neighbor_iterator(v): + if n in E1 and n not in (q, r): + E1.add_edge(v, n, None) + if n in E2 and n not in (q, r): + E2.add_edge(v, n, None) for i in range(len(cutpath) - 1): E1.add_edge(cutpath[i], cutpath[i + 1], None) E2.add_edge(cutpath[i], cutpath[i + 1], None) + Gd = copy(dual_graph) + to_delete = [e for e in Gd.edges(sort=True) if e[2][0] in cutpath and e[2][1] in cutpath] + Gd.delete_edges(to_delete) + Gd1, Gd2 = Gd.connected_components_subgraphs() + edges_2 = [] + vertices_2 = [] + for reg in Gd2.vertices(sort=True): + vertices_2 += reg[1][:-1] + reg_circuit = reg[1] + edges_2 += [(v1, reg_circuit[i + 1]) for i, v1 in enumerate(reg_circuit[:-1])] + edges_2 += [(v1, reg_circuit[i - 1]) for i, v1 in enumerate(reg_circuit[1:])] + G2 = G.subgraph(vertices=vertices_2, edges=edges_2) + edges_1 = [] + vertices_1 = [] + for reg in Gd1.vertices(sort=True): + vertices_1 += reg[1] + reg_circuit = reg[1] + (reg[1][0],) + edges_1 += [(v1, reg_circuit[i + 1]) for i, v1 in enumerate(reg_circuit[:-1])] + edges_1 += [(v1, reg_circuit[i - 1]) for i, v1 in enumerate(reg_circuit[1:])] + G1 = G.subgraph(vertices=vertices_1, edges=edges_1) + if EC[qi + 1] in G2: + G1, G2 = G2, G1 + Gd1, Gd2 = Gd2, Gd1 - for v in [q, r]: - for n in E.neighbors(v): - if n in E1: - E1.add_edge(v, n, None) - if n in E2: - E2.add_edge(v, n, None) + if qi < ri: + EC1 = [EC[j] for j in range(qi, ri)] + list(reversed(cutpath)) + EC2 = cutpath + list(EC[ri + 1: -1] + EC[: qi + 1]) + else: + EC1 = list(EC[qi:] + EC[1:ri]) + list(reversed(cutpath)) + EC2 = cutpath + list(EC[ri + 1:qi + 1]) - gb1 = geometric_basis(G1, E1, q) - gb2 = geometric_basis(G2, E2, q) + gb1 = geometric_basis(G1, E1, EC1, q, Gd1) + gb2 = geometric_basis(G2, E2, EC2, q, Gd2) reverse_connecting = list(reversed(connecting_path)) resul = [connecting_path + path + reverse_connecting @@ -874,82 +1085,165 @@ def geometric_basis(G, E, p): return resul -def braid_monodromy(f): +def strand_components(f, flist, p1): + r""" + Compute only the assignment from strands to elements of ``flist``. + + INPUT: + + - ``f`` -- a reduced polynomial with two variables, over a number field + with an embedding in the complex numbers + + - ``flist`` -- a list of polynomials with two variables whose + product equals ``f`` + + - ``p1`` -- a Gauss rational + + OUTPUT: + + - A list and a dictionary. The first one is an ordered list of pairs + consisting of ``(z,i)`` where ``z`` is a root of ``f(p_1,y)`` and `i` is the position + of the polynomial in the list whose root is ``z``. The second one attaches + a number `i` (strand) to a number `j` (a polynomial in the list). + + EXAMPLES:: + + sage: # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import strand_components + sage: R.<x, y> = QQ[] + sage: flist = [x^2 - y^3, x + 3 * y - 5] + sage: strand_components(prod(flist), flist, 1) + ([(-0.500000000000000? - 0.866025403784439?*I, 0), + (-0.500000000000000? + 0.866025403784439?*I, 0), + (1, 0), (1.333333333333334?, 1)], {0: 0, 1: 0, 2: 0, 3: 1}) + """ + x, y = f.parent().gens() + F = flist[0].base_ring() + strands = {} + roots_base = [] + for i, h in enumerate(flist): + h0 = h.subs({x: p1}) + h1 = F[y](h0) + rt = h1.roots(QQbar, multiplicities=False) + roots_base += [(_, i) for _ in rt] + roots_base.sort() + strands = {i: par[1] for i, par in enumerate(roots_base)} # quitar +1 despues de revision + return (roots_base, strands) + + +def braid_monodromy(f, arrangement=()): r""" - Compute the braid monodromy of a projection of the curve defined by a polynomial. + Compute the braid monodromy of a projection of the curve defined by + a polynomial. INPUT: - ``f`` -- a polynomial with two variables, over a number field with an embedding in the complex numbers + - ``arrangement`` -- an optional tuple of polynomials whose product + equals ``f``. + OUTPUT: - A list of braids. The braids correspond to paths based in the same point; - each of this paths is the conjugated of a loop around one of the points - in the discriminant of the projection of ``f``. + A list of braids and a dictionary. + The braids correspond to paths based in the same point; + each of these paths is the conjugated of a loop around one of the points + in the discriminant of the projection of ``f``. The dictionary assigns each + strand to the index of the corresponding factor in ``arrangement``. .. NOTE:: - The projection over the `x` axis is used if there are no vertical asymptotes. - Otherwise, a linear change of variables is done to fall into the previous case. + The projection over the `x` axis is used if there are no vertical + asymptotes. Otherwise, a linear change of variables is done to fall + into the previous case. + + .. TODO:: + + Create a class ``arrangements_of_curves`` with a ``braid_monodromy`` + method; it can be also a method for affine line arrangements. EXAMPLES:: + sage: # optional - sirocco sage: from sage.schemes.curves.zariski_vankampen import braid_monodromy - sage: R.<x,y> = QQ[] - sage: f = (x^2-y^3)*(x+3*y-5) - sage: braid_monodromy(f) # optional - sirocco - [s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1, - s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1, - s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1, - s1*s0*s2*s0^-1*s2*s1^-1] + sage: R.<x, y> = QQ[] + sage: f = (x^2 - y^3) * (x + 3*y - 5) + sage: bm = braid_monodromy(f); bm + ([s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1, + s1*s0*s2*s0^-1*s2*s1^-1], {0: 0, 1: 0, 2: 0, 3: 0}) + sage: flist = (x^2 - y^3, x + 3*y - 5) + sage: bm1 = braid_monodromy(f, arrangement=flist) + sage: bm1[0] == bm[0] + True + sage: bm1[1] + {0: 0, 1: 1, 2: 0, 3: 0} + sage: braid_monodromy(R(1)) + ([], {}) + sage: braid_monodromy(x*y^2 - 1) + ([s0*s1*s0^-1*s1*s0*s1^-1*s0^-1, s0*s1*s0^-1, s0], {0: 0, 1: 0, 2: 0}) """ global roots_interval_cache + F = fieldI(f.base_ring()) + I1 = F(QQbar.gen()) + f = f.change_ring(F) + if arrangement == (): + arrangement1 = (f,) + else: + arrangement1 = tuple(_.change_ring(F) for _ in arrangement) x, y = f.parent().gens() - F = f.base_ring() - g = f.radical() + glist = tuple(_[0] for f0 in arrangement1 for _ in f0.factor()) + g = f.parent()(prod(glist)) d = g.degree(y) while not g.coefficient(y**d) in F: g = g.subs({x: x + y}) d = g.degree(y) - disc = discrim(g) + arrangement1 = tuple(f1.subs({x: x + y}) for f1 in arrangement1) + glist = tuple(f1.subs({x: x + y}) for f1 in glist) + if d > 0: + disc = discrim(glist) + else: + disc = [] + if len(disc) == 0: + result = [] + p1 = F(0) + roots_base, strands = strand_components(g, arrangement1, p1) + return ([], strands) V = corrected_voronoi_diagram(tuple(disc)) - G = Graph() - for reg in V.regions().values(): - G = G.union(reg.vertex_graph()) - E = Graph() - for reg in V.regions().values(): - if reg.rays() or reg.lines(): - E = E.union(reg.vertex_graph()) - p = next(E.vertex_iterator()) - geombasis = geometric_basis(G, E, p) + G, E, p, EC, DG = voronoi_cells(V) + p0 = (p[0], p[1]) + p1 = p0[0] + I1 * p0[1] + roots_base, strands = strand_components(g, arrangement1, p1) + geombasis = geometric_basis(G, E, EC, p, DG) segs = set() for p in geombasis: for s in zip(p[:-1], p[1:]): if (s[1], s[0]) not in segs: segs.add((s[0], s[1])) - I = QQbar.gen() - segs = [(a[0] + I * a[1], b[0] + I * b[1]) for a, b in segs] + I0 = QQbar.gen() + segs = [(a[0] + I0 * a[1], b[0] + I0 * b[1]) for a, b in segs] vertices = list(set(flatten(segs))) - tocacheverts = [(g, v) for v in vertices] + tocacheverts = tuple([(g, v) for v in vertices]) populate_roots_interval_cache(tocacheverts) - gfac = g.factor() - try: - braidscomputed = (braid_in_segment([(gfac, seg[0], seg[1]) - for seg in segs])) - except ChildProcessError: # hack to deal with random fails first time - braidscomputed = (braid_in_segment([(gfac, seg[0], seg[1]) - for seg in segs])) - segsbraids = {} - for braidcomputed in braidscomputed: - seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) - beginseg = (QQ(seg[0].real()), QQ(seg[0].imag())) - endseg = (QQ(seg[1].real()), QQ(seg[1].imag())) - b = braidcomputed[1] - segsbraids[(beginseg, endseg)] = b - segsbraids[(endseg, beginseg)] = b.inverse() - B = b.parent() + end_braid_computation = False + while not end_braid_computation: + try: + braidscomputed = (braid_in_segment([(glist, seg[0], seg[1]) + for seg in segs])) + segsbraids = {} + for braidcomputed in braidscomputed: + seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) + beginseg = (QQ(seg[0].real()), QQ(seg[0].imag())) + endseg = (QQ(seg[1].real()), QQ(seg[1].imag())) + b = braidcomputed[1] + segsbraids[(beginseg, endseg)] = b + segsbraids[(endseg, beginseg)] = b.inverse() + end_braid_computation = True + except ChildProcessError: # hack to deal with random fails first time + pass + B = BraidGroup(d) result = [] for path in geombasis: braidpath = B.one() @@ -958,10 +1252,258 @@ def braid_monodromy(f): x1 = tuple(path[i + 1].vector()) braidpath = braidpath * segsbraids[(x0, x1)] result.append(braidpath) - return result + return (result, strands) + + +def conjugate_positive_form(braid): + r""" + For a ``braid`` which is conjugate to a product of *disjoint* positive + braids a list of such decompositions is given. + + INPUT: + + - ``braid`` -- a braid ``\sigma``. + + OUTPUT: + + A list of `r` lists. Each such list is another list with two elements, a + positive braid `\alpha_i` and a list of permutation braids + `\gamma_{1}^{i},\dots,\gamma_{r}^{n_i}` such that if + `\gamma_i=\prod_{j=1}^{n_i} \gamma_j^i` then the braids + `\tau_i=\gamma_i\alpha_i\gamma_i^{-1}` pairwise commute + and `\alpha=\prod_{i=1}^{r} \tau_i`. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import conjugate_positive_form + sage: B = BraidGroup(4) + sage: t = B((1, 3, 2, -3, 1, 1)) + sage: conjugate_positive_form(t) + [[(s1*s0)^2, [s2]]] + sage: B = BraidGroup(5) + sage: t = B((1, 2, 3, 4, -1, -2, 3, 3, 2, -4)) + sage: L = conjugate_positive_form(t); L + [[s1^2, [s3*s2]], [s1*s2, [s0]]] + sage: s = B.one() + sage: for a, l in L: + ....: b = prod(l) + ....: s *= b * a / b + sage: s == t + True + sage: s1 = B.gen(1)^3 + sage: conjugate_positive_form(s1) + [[s1^3, []]] + """ + B = braid.parent() + d = B.strands() + braid1 = braid.super_summit_set()[0] + L1 = braid1.Tietze() + sg0 = braid.conjugating_braid(braid1) + gns = set(L1) + cuts = [j for j in range(d + 1) if j not in gns] + blocks = [] + for i in range(len(cuts) - 1): + block = [j for j in L1 if j > cuts[i] and j < cuts[i + 1]] + if len(block) > 0: + blocks.append(block) + shorts = [] + for a in blocks: + A = B(a).super_summit_set() + res = None + for tau in A: + sg = (sg0 * B(a) / sg0).conjugating_braid(tau) + A1 = rightnormalform(sg) + par = A1[-1][0] % 2 + A1 = [B(a) for a in A1[:-1]] + if len(A1) == 0: + b = B.one() + else: + b = prod(A1) + b1 = len(b.Tietze()) / (len(A1) + 1) + if res is None or b1 < res[3]: + res = [tau, A1, par, b1] + if res[2] == 1: + r0 = res[0].Tietze() + res[0] = B([i.sign() * (d - abs(i)) for i in r0]) + res0 = res[:2] + shorts.append(res0) + return shorts -def fundamental_group(f, simplified=True, projective=False): +@parallel +def conjugate_positive_form_p(braid): + return conjugate_positive_form(braid) + + +def braid2rels(L): + r""" + Return a minimal set of relations of the group + ``F / [(b * F([j])) / F([j]) for j in (1..d)]`` where ``F = FreeGroup(d)`` + and ``b`` is a conjugate of a positive braid . One starts from the + non-trivial relations determined by the positive braid and transform + them in relations determined by ``b``. + + INPUT: + + - ``L`` -- a tuple whose first element is a positive braid and the second + element is a list of permutation braids. + + OUTPUT: + + A list of Tietze words for a minimal set of relations of + ``F / [(g * b) / g for g in F.gens()]``. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import braid2rels + sage: B.<s0, s1, s2> = BraidGroup(4) + sage: L = ((s1*s0)^2, [s2]) + sage: braid2rels(L) + [(4, 1, -2, -1), (2, -4, -2, 1)] + """ + br = L[0] + L1 = L[1] + B = br.parent() + d = B.strands() + F = FreeGroup(d) + T = br.Tietze() + T1 = set(T) + m = len(T1) + 1 + k = min(T1) - 1 + B0 = BraidGroup(m) + F0 = FreeGroup(m) + br0 = B0([_-k for _ in T]) + br0_left = leftnormalform(br0) + q, r = ZZ(br0_left[0][0]).quo_rem(2) + br1 = B0.delta()**r * B0(prod(B0(_) for _ in br0_left[1:])) + cox = prod(F0.gens()) + U0 = [cox**q * (f0 * br1) / cox**q / f0 for f0 in F0.gens()[:-1]] + U = [tuple(sign(k1)*(abs(k1) + k) for k1 in _.Tietze()) for _ in U0] + pasos = [B.one()] + [_ for _ in reversed(L1)] + for C in pasos: + U = [(F(a) * C.inverse()).Tietze() for a in U] + ga = F / U + P = ga.gap().PresentationFpGroup() + dic = P.TzOptions().sage() + dic['protected'] = d + dic['printLevel'] = 0 + P.SetTzOptions(dic) + P.TzGoGo() + P.TzGoGo() + gb = wrap_FpGroup(P.FpGroupPresentation()) + U = [_.Tietze() for _ in gb.relations()] + return U + + +@parallel +def braid2rels_p(L): + return braid2rels(L) + + +@parallel +def relation(x, b): + return x * b / x + + +def fundamental_group_from_braid_mon(bm, degree=None, simplified=True, projective=False, puiseux=False, vertical=[]): + r""" + Return a presentation of the fundamental group computed from + a braid monodromy. + + INPUT: + + - ``bm`` -- a list of braids + + - ``degree`` -- integer (default: ``None``); only needed if the braid + monodromy is an empty list. + + - ``simplified`` -- boolean (default: ``True``); if set to ``True`` the + presentation will be simplified (see below) + + - ``projective`` -- boolean (default: ``False``); if set to ``True``, + the fundamental group of the complement of the projective completion + of the curve will be computed, otherwise, the fundamental group of + the complement in the affine plane will be computed + + - ``puiseux`` -- boolean (default: ``False``); if set to ``True``, + ``simplified`` is set to ``False``, and + a presentation of the fundamental group with the homotopy type + of the complement of the affine curve will be computed, adding + one relation if ``projective`` is set to ``True``. + + - ``vertical`` -- list of integers (default: ``[]``); the indices in + ``[1..r]`` of the braids that surround a vertical line + + If ``simplified` and ``projective``` are ``False`` and ``puiseux`` is + ``True``, a Zariski-VanKampen presentation is returned. + + OUTPUT: + + A presentation of the fundamental group of the complement of the + union of the curve with some vertical lines from its braid monodromy. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import fundamental_group_from_braid_mon + sage: B.<s0, s1, s2> = BraidGroup(4) + sage: bm = [s1*s2*s0*s1*s0^-1*s1^-1*s0^-1, + ....: s0*s1^2*s0*s2*s1*(s0^-1*s1^-1)^2*s0^-1, + ....: (s0*s1)^2] + sage: g = fundamental_group_from_braid_mon(bm, projective=True); g + Finitely presented group < x0, x1 | x1*x0^2*x1, x0^-1*x1^-1*x0^-1*x1*x0^-1*x1^-1 > + sage: print (g.order(), g.abelian_invariants()) + 12 (4,) + sage: B2 = BraidGroup(2) + sage: bm = [B2(3 * [1])] + sage: g = fundamental_group_from_braid_mon(bm, vertical=[1]); g + Finitely presented group < x0, x1, x2 | x2*x0*x1*x2^-1*x1^-1*x0^-1, + x2*x0*x1*x0*x1^-1*x0^-1*x2^-1*x1^-1 > + sage: fundamental_group_from_braid_mon([]) is None # optional - sirocco + True + sage: fundamental_group_from_braid_mon([], degree=2) # optional - sirocco + Finitely presented group < x0, x1 | > + """ + vertical0 = sorted(vertical) + v = len(vertical0) + if bm == []: + d = degree + else: + d = bm[0].parent().strands() + if d is None: + return None + F = FreeGroup(d) + Fv = FreeGroup(d + v) + bmh = [br for j, br in enumerate(bm) if j + 1 not in vertical0] + if not puiseux: + relations_h = (relation([(x, b) for x in F.gens() for b in bmh])) + rel_h = [r[1] for r in relations_h] + simplified0 = simplified + else: + simplified0 = False + conjugate_desc = conjugate_positive_form_p(bmh) + trenzas_desc = [b1[-1] for b1 in conjugate_desc] + trenzas_desc_1 = flatten(trenzas_desc, max_level=1) + relations_h = braid2rels_p(trenzas_desc_1) + rel_h = [r[1] for r in relations_h] + rel_h = flatten(rel_h, max_level=1) + rel_v = [] + for j, k in enumerate(vertical0): + l1 = d + j + 1 + br = bm[k - 1] + for gen in F.gens(): + j0 = gen.Tietze()[0] + rl = (l1,) + (gen * br).Tietze() + (-l1, -j0) + rel_v.append(rl) + rel = rel_h + rel_v + if projective: + rel.append(prod(Fv.gens()).Tietze()) + G = Fv / rel + if simplified0: + return G.simplified() + return G + + +def fundamental_group(f, simplified=True, projective=False, puiseux=False): r""" Return a presentation of the fundamental group of the complement of the algebraic set defined by the polynomial ``f``. @@ -979,8 +1521,13 @@ def fundamental_group(f, simplified=True, projective=False): of the curve will be computed, otherwise, the fundamental group of the complement in the affine plane will be computed - If ``simplified`` is ``False``, a Zariski-VanKampen presentation - is returned. + - ``puiseux`` -- boolean (default: ``False``); if set to ``True``, + a presentation of the fundamental group with the homotopy type + of the complement of the affine curve is computed, ``simplified`` is + ignored. One relation is added if ``projective`` is set to ``True``. + + If ``simplified` and ``projective``` are ``False`` and ``puiseux`` is + ``True``, a Zariski-VanKampen presentation is returned. OUTPUT: @@ -989,54 +1536,200 @@ def fundamental_group(f, simplified=True, projective=False): EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco - sage: R.<x,y> = QQ[] + sage: # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import fundamental_group, braid_monodromy + sage: R.<x, y> = QQ[] sage: f = x^2 + y^3 - sage: fundamental_group(f) # optional - sirocco - Finitely presented group < ... > - sage: fundamental_group(f, simplified=False) # optional - sirocco - Finitely presented group < ... > + sage: fundamental_group(f) + Finitely presented group < x1, x2 | x1*x2*x1^-1*x2^-1*x1^-1*x2 > + sage: fundamental_group(f, simplified=False).sorted_presentation() + Finitely presented group < x0, x1, x2 | x2^-1*x1^-1*x0*x1, + x2^-1*x0*x1*x0^-1, + x1^-1*x0^-1*x1^-1*x0*x1*x0 > + sage: fundamental_group(f, projective=True) + Finitely presented group < x0 | x0^3 > + sage: fundamental_group(f).sorted_presentation() + Finitely presented group < x0, x1 | x1^-1*x0^-1*x1^-1*x0*x1*x0 > :: - sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco - sage: R.<x,y> = QQ[] + sage: # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import fundamental_group + sage: R.<x, y> = QQ[] sage: f = y^3 + x^3 - sage: fundamental_group(f) # optional - sirocco - Finitely presented group < ... > + sage: fundamental_group(f) + Finitely presented group < x0, x1, x2 | x0*x1*x2*x0^-1*x2^-1*x1^-1, x2*x0*x1*x2^-1*x1^-1*x0^-1 > It is also possible to have coefficients in a number field with a fixed embedding in `\QQbar`:: - sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco - sage: zeta = QQbar['x']('x^2+x+1').roots(multiplicities=False)[0] + sage: # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import fundamental_group + sage: zeta = QQbar['x']('x^2 + x+ 1').roots(multiplicities=False)[0] sage: zeta -0.50000000000000000? - 0.866025403784439?*I sage: F = NumberField(zeta.minpoly(), 'zeta', embedding=zeta) sage: F.inject_variables() Defining zeta - sage: R.<x,y> = F[] - sage: f = y^3 + x^3 +zeta *x + 1 - sage: fundamental_group(f) # optional - sirocco + sage: R.<x, y> = F[] + sage: f = y^3 + x^3 + zeta * x + 1 + sage: fundamental_group(f) Finitely presented group < x0 | > + + We compute the fundamental group of the complement of a quartic using the ``puiseux`` option:: + + sage: # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import fundamental_group + sage: R.<x, y> = QQ[] + sage: f = x^2 * y^2 + x^2 + y^2 - 2 * x * y * (x + y + 1) + sage: g = fundamental_group(f, puiseux=True); g.sorted_presentation() + Finitely presented group + < x0, x1, x2, x3 | x3^-1*x2^-1*x1^-1*x0^-1*x1*x2*x1^-1*x0*x1*x2, + x3^-1*x2^-1*x1*x2, x2^-1*x1^-1*x0^-1*x1*x2*x1, x2^-1*x0 > + sage: g.simplified().sorted_presentation() + Finitely presented group < x0, x1 | x1^-2*x0^2, (x1^-1*x0)^3 > + sage: g = fundamental_group(f, puiseux=True, projective=True) + sage: g.order(), g.abelian_invariants() + (12, (4,)) + sage: fundamental_group(y * (y - 1)) + Finitely presented group < x0, x1 | > """ g = f + x, y = g.parent().gens() + F = g.parent().base_ring() + d = g.degree(y) + while not g.coefficient(y**d) in F: + g = g.subs({x: x + y}) + d = g.degree(y) if projective: - x, y = g.parent().gens() while g.degree(y) < g.degree(): g = g.subs({x: x + y}) - bm = braid_monodromy(g) - n = bm[0].parent().strands() - F = FreeGroup(n) + bm = braid_monodromy(g)[0] + if bm == []: + d = g.degree(y) + else: + d = bm[0].parent().strands() + return fundamental_group_from_braid_mon(bm, degree=d, simplified=simplified, projective=projective, puiseux=puiseux) - @parallel - def relation(x, b): - return x * b / x - relations = (relation([(x, b) for x in F.gens() for b in bm])) - R = [r[1] for r in relations] + +def fundamental_group_arrangement(flist, simplified=True, projective=False, puiseux=False): + r""" + Compute the fundamental group of the complement of a curve + defined by a list of polynomials with the extra information + about the correspondence of the generators + and meridians of the elements of the list. + + INPUT: + + - ``flist`` -- a tuple of polynomial with two variables, over a number + field with an embedding in the complex numbers + + - ``simplified`` -- boolean (default: ``True``); if set to ``True`` the + presentation will be simplified (see below) + + - ``projective`` -- boolean (default: ``False``); if set to ``True``, + the fundamental group of the complement of the projective completion + of the curve will be computed, otherwise, the fundamental group of + the complement in the affine plane will be computed + + - ``puiseux`` -- boolean (default: ``False``); if set to ``True``, + ``simplified`` is set to ``False``, and + a presentation of the fundamental group with the homotopy type + of the complement of the affine curve will be computed, adding + one relation if ``projective`` is set to ``True``. + + OUTPUT: + + - A list of braids. The braids correspond to paths based in the same point; + each of this paths is the conjugated of a loop around one of the points + in the discriminant of the projection of ``f``. + + - A dictionary attaching a tuple ``(i,)`` (generator) to a number ``j`` + (a polynomial in the list). If ``simplified`` is set to ``True``, + a longer key may appear for either the meridian of the line at infinity, + if ``projective`` is ``True``, or a simplified generator, + if ``projective`` is ``False`` + + EXAMPLES:: + + sage: # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import braid_monodromy + sage: from sage.schemes.curves.zariski_vankampen import fundamental_group_arrangement + sage: R.<x, y> = QQ[] + sage: flist = [x^2 - y^3, x + 3 * y - 5] + sage: g, dic = fundamental_group_arrangement(flist) + sage: g.sorted_presentation() + Finitely presented group + < x0, x1, x2 | x2^-1*x1^-1*x2*x1, x2^-1*x0^-1*x2^-1*x0*x2*x0, x1^-1*x0^-1*x1*x0 > + sage: dic + {0: [x0, x2, x0], 1: [x1], 2: [x0^-1*x2^-1*x1^-1*x0^-1]} + sage: g, dic = fundamental_group_arrangement(flist, simplified=False) + sage: g.sorted_presentation(), dic + (Finitely presented group + < x0, x1, x2, x3 | 1, 1, 1, 1, 1, 1, 1, x3^-1*x2^-1*x1^-1*x2*x3*x2^-1*x1*x2, + x3^-1*x2^-1*x1^-1*x0^-1*x1*x2*x3*x2, + x3^-1*x2^-1*x1^-1*x0^-1*x1*x2*x1^-1*x0*x1*x2, + x3^-1*x2^-1*x1^-1*x2*x3*x2^-1*x1*x2, x3^-1*x1^-1*x0*x1, + x1^-1*x0^-1*x1*x0, x1^-1*x0^-1*x1*x0, x1^-1*x0^-1*x1*x0, + x1^-1*x0^-1*x1*x0 >, + {0: [x0, x2, x3], 1: [x1], 2: [x3^-1*x2^-1*x1^-1*x0^-1]}) + sage: fundamental_group_arrangement(flist, projective=True) + (Finitely presented group < x | >, {0: [x0, x0, x0], 1: [x0^-3]}) + sage: fundamental_group_arrangement([]) + (Finitely presented group < | >, {}) + sage: g, dic = fundamental_group_arrangement([x * y]) + sage: g.sorted_presentation(), dic + (Finitely presented group < x0, x1 | x1^-1*x0^-1*x1*x0 >, + {0: [x0, x1], 1: [x1^-1*x0^-1]}) + sage: fundamental_group_arrangement([y + x^2], projective=True) + (Finitely presented group < x | x^2 >, {0: [x0, x0]}) + + .. TODO:: + + Create a class ``arrangements_of_curves`` with a ``fundamental_group`` + method it can be also a method for affine or projective line + arrangements, even for hyperplane arrangements defined over a number + subfield of ``QQbar`` after applying a generic line section. + """ + if len(flist) > 0: + f = prod(flist) + R = f.parent() + else: + R = PolynomialRing(QQ, ('x', 'y')) + f = R(1) + x, y = R.gens() + F = R.base_ring() + flist1 = [_ for _ in flist] + d = f.degree(y) + while not f.coefficient(y**d) in F: + flist1 = [g.subs({x: x + y}) for g in flist1] + f = prod(flist1) + d = f.degree(y) if projective: - R.append(prod(F.gens())) - G = F / R + while f.degree(y) < f.degree(): + flist1 = [g.subs({x: x + y}) for g in flist] + f = prod(flist1) + if len(flist1) == 0: + bm = [] + dic = dict() + else: + bm, dic = braid_monodromy(f, flist1) + g = fundamental_group_from_braid_mon(bm, degree=d, simplified=False, projective=projective, puiseux=puiseux) if simplified: - return G.simplified() - return G + hom = g.simplification_isomorphism() + else: + hom = g.hom(codomain=g, im_gens=list(g.gens()), check=False) + g1 = hom.codomain() + if len(flist) == 0: + return (g1, dict()) + dic1 = {} + for i in range(len(flist1)): + L = [j1 for j1 in dic.keys() if dic[j1] == i] + dic1[i] = [hom(g.gen(j)) for j in L] + if not projective and f.degree(y) == f.degree(): + t = prod(hom(x) for x in g.gens()).inverse() + dic1[len(flist1)] = [t] + n = g1.ngens() + rels = [_.Tietze() for _ in g1.relations()] + g1 = FreeGroup(n) / rels + return (g1, dic1) diff --git a/src/sage/schemes/cyclic_covers/__init__.py b/src/sage/schemes/cyclic_covers/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/cyclic_covers/charpoly_frobenius.py b/src/sage/schemes/cyclic_covers/charpoly_frobenius.py index 4c63fe44783..e28289e1d84 100644 --- a/src/sage/schemes/cyclic_covers/charpoly_frobenius.py +++ b/src/sage/schemes/cyclic_covers/charpoly_frobenius.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.padics r""" Computation of the Frobenius polynomial using Newton's identities """ @@ -32,7 +33,7 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= OUTPUT: - A list of integers corresponding to the characteristic polynomial of the Frobenius action + A list of integers corresponding to the characteristic polynomial of the Frobenius action. EXAMPLES:: @@ -41,29 +42,33 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= sage: charpoly_frobenius(M, [2, 1, 1], 17, 1, 1) [17, 2, 1] - sage: R = Zq(17**2 , names=('a',)) - sage: M = Matrix(R, [[8*17 + 16*17**2 + O(17**3), 8 + 11*17 + O(17**2)], [7*17**2 + O(17**3), 15 + 8*17 + O(17**2)]]) + sage: R = Zq(17**2, names=('a',)) + sage: M = Matrix(R, [[8*17 + 16*17**2 + O(17**3), 8 + 11*17 + O(17**2)], + ....: [7*17**2 + O(17**3), 15 + 8*17 + O(17**2)]]) sage: charpoly_frobenius(M*M, [3, 2, 2], 17, 1, 2) [289, 30, 1] - sage: M = Matrix([[8*31 + 8*31**2 + O(31**3), O(31**3), O(31**3), O(31**3)], [O(31**3), 23*31 + 22*31**2 + O(31**3), O(31**3), O(31**3)], [O(31**3), O(31**3), 27 + 7*31 + O(31**3), O(31**3)], [O(31**3), O(31**3), O(31**3), 4 + 23*31 + O(31**3)]]) + sage: M = Matrix([[8*31 + 8*31**2 + O(31**3), O(31**3), O(31**3), O(31**3)], + ....: [O(31**3), 23*31 + 22*31**2 + O(31**3), O(31**3), O(31**3)], + ....: [O(31**3), O(31**3), 27 + 7*31 + O(31**3), O(31**3)], + ....: [O(31**3), O(31**3), O(31**3), 4 + 23*31 + O(31**3)]]) sage: charpoly_frobenius(M, [4, 3, 2, 2, 2], 31, 1, 1) [961, 0, 46, 0, 1] sage: M = Matrix([(4*43^2 + O(43^3), 17*43 + 11*43^2 + O(43^3), O(43^3), O(43^3), 17 + 37*43 + O(43^3), O(43^3)), - ....: (30*43 + 23*43^2 + O(43^3), 5*43 + O(43^3), O(43^3), O(43^3), 3 + 38*43 + O(43^3), O(43^3)), - ....: (O(43^3), O(43^3), 9*43 + 32*43^2 + O(43^3), 13 + 25*43 + O(43^3), O(43^3), 17 + 18*43 + O(43^3)), - ....: (O(43^3), O(43^3), 22*43 + 25*43^2 + O(43^3), 11 + 24*43 + O(43^3), O(43^3), 36 + 5*43 + O(43^3)), - ....: (42*43 + 15*43^2 + O(43^3), 22*43 + 8*43^2 + O(43^3), O(43^3), O(43^3), 29 + 4*43 + O(43^3), O(43^3)), - ....: (O(43^3), O(43^3), 6*43 + 19*43^2 + O(43^3), 8 + 24*43 + O(43^3), O(43^3), 31 + 42*43 + O(43^3))]) + ....: (30*43 + 23*43^2 + O(43^3), 5*43 + O(43^3), O(43^3), O(43^3), 3 + 38*43 + O(43^3), O(43^3)), + ....: (O(43^3), O(43^3), 9*43 + 32*43^2 + O(43^3), 13 + 25*43 + O(43^3), O(43^3), 17 + 18*43 + O(43^3)), + ....: (O(43^3), O(43^3), 22*43 + 25*43^2 + O(43^3), 11 + 24*43 + O(43^3), O(43^3), 36 + 5*43 + O(43^3)), + ....: (42*43 + 15*43^2 + O(43^3), 22*43 + 8*43^2 + O(43^3), O(43^3), O(43^3), 29 + 4*43 + O(43^3), O(43^3)), + ....: (O(43^3), O(43^3), 6*43 + 19*43^2 + O(43^3), 8 + 24*43 + O(43^3), O(43^3), 31 + 42*43 + O(43^3))]) sage: charpoly_frobenius(M, [5, 4, 3, 2, 2, 2, 2], 43, 1, 1) [79507, 27735, 6579, 1258, 153, 15, 1] sage: M = Matrix([(1 + O(4999), O(4999), 0, 0), - ....: (O(4999), 4860 + O(4999), 0, 0), - ....: (0, 0, O(4999), O(4999)), - ....: (0, 0, O(4999), 1 + O(4999))]) - sage: charpoly_frobenius(M, [2, 1, 1], 4999, 1, 1, [1, -2 ,1 ]) + ....: (O(4999), 4860 + O(4999), 0, 0), + ....: (0, 0, O(4999), O(4999)), + ....: (0, 0, O(4999), 1 + O(4999))]) + sage: charpoly_frobenius(M, [2, 1, 1], 4999, 1, 1, [1, -2, 1]) [4999, 139, 1] TESTS:: diff --git a/src/sage/schemes/cyclic_covers/constructor.py b/src/sage/schemes/cyclic_covers/constructor.py index 0966b0793d5..99250257121 100644 --- a/src/sage/schemes/cyclic_covers/constructor.py +++ b/src/sage/schemes/cyclic_covers/constructor.py @@ -8,9 +8,10 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.rings.polynomial.polynomial_element import is_Polynomial -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField +from sage.rings.polynomial.polynomial_element import Polynomial from sage.schemes.affine.affine_space import AffineSpace + from .cycliccover_generic import CyclicCover_generic from .cycliccover_finite_field import CyclicCover_finite_field @@ -27,7 +28,7 @@ def CyclicCover(r, f, names=None, check_smooth=True): - ``f`` - univariate polynomial if not given, then it defaults to 0. - ``names`` (default: ``["x","y"]``) - names for the - coordinate functions + coordinate functions - ``check_squarefree`` (default: ``True``) - test if the input defines a unramified cover of the projective line. @@ -63,44 +64,49 @@ def CyclicCover(r, f, names=None, check_smooth=True): sage: CyclicCover(15, x^9 + x + 1) Cyclic Cover of P^1 over Rational Field defined by y^15 = x^9 + x + 1 - sage: k.<a> = GF(9); R.<x> = k[] - sage: CyclicCover(5, x^9 + x + 1) - Cyclic Cover of P^1 over Finite Field in a of size 3^2 defined by y^5 = x^9 + x + 1 - sage: CyclicCover(15, x^9 + x + 1) + sage: k.<a> = GF(9); R.<x> = k[] # needs sage.rings.finite_rings + sage: CyclicCover(5, x^9 + x + 1) # needs sage.rings.finite_rings + Cyclic Cover of P^1 over Finite Field in a of size 3^2 + defined by y^5 = x^9 + x + 1 + sage: CyclicCover(15, x^9 + x + 1) # needs sage.rings.finite_rings Traceback (most recent call last): ... - ValueError: As the characteristic divides the order of the cover, this model is not smooth. + ValueError: As the characteristic divides the order of the cover, + this model is not smooth. We can change the names of the variables in the output:: - sage: k.<a> = GF(9); R.<x> = k[] - sage: CyclicCover(5, x^9 + x + 1, names = ["A","B"]) - Cyclic Cover of P^1 over Finite Field in a of size 3^2 defined by B^5 = A^9 + A + 1 + sage: k.<a> = GF(9); R.<x> = k[] # needs sage.rings.finite_rings + sage: CyclicCover(5, x^9 + x + 1, names=["A","B"]) # needs sage.rings.finite_rings + Cyclic Cover of P^1 over Finite Field in a of size 3^2 + defined by B^5 = A^9 + A + 1 Double roots:: sage: P.<x> = GF(7)[] - sage: CyclicCover(2,(x^3-x+2)^2*(x^6-1)) + sage: CyclicCover(2, (x^3-x+2)^2*(x^6-1)) Traceback (most recent call last): ... ValueError: Not a smooth Cyclic Cover of P^1: singularity in the provided affine patch. - sage: CyclicCover(2, (x^3-x+2)^2*(x^6-1), check_smooth=False) - Cyclic Cover of P^1 over Finite Field of size 7 defined by y^2 = x^12 - 2*x^10 - 3*x^9 + x^8 + 3*x^7 + 3*x^6 + 2*x^4 + 3*x^3 - x^2 - 3*x + 3 + sage: CyclicCover(2, (x^3-x+2)^2*(x^6-1), check_smooth=False) # needs sage.rings.finite_rings + Cyclic Cover of P^1 over Finite Field of size 7 + defined by y^2 = x^12 - 2*x^10 - 3*x^9 + x^8 + 3*x^7 + 3*x^6 + + 2*x^4 + 3*x^3 - x^2 - 3*x + 3 Input with integer coefficients creates objects with the integers as base ring, but only checks smoothness over `\QQ`, not over Spec(`\ZZ`). In other words, it is checked that the discriminant is non-zero, but it is - not checked whether the discriminant is a unit in `\ZZ^*`.:: + not checked whether the discriminant is a unit in `\ZZ^*`:: sage: R.<x> = ZZ[] - sage: CyclicCover(5,(x^3-x+2)*(x^6-1)) + sage: CyclicCover(5, (x^3-x+2)*(x^6-1)) Cyclic Cover of P^1 over Integer Ring defined by y^5 = x^9 - x^7 + 2*x^6 - x^3 + x - 2 """ - if not is_Polynomial(f): + if not isinstance(f, Polynomial): raise TypeError("Arguments f (= %s) must be a polynomial" % (f,)) P = f.parent() f = P(f) @@ -127,7 +133,7 @@ def CyclicCover(r, f, names=None, check_smooth=True): names = ["x", "y"] A2 = AffineSpace(2, R, names=names) - if is_FiniteField(R): + if isinstance(R, FiniteField): return CyclicCover_finite_field(A2, r, f, names=names) else: return CyclicCover_generic(A2, r, f, names=names) diff --git a/src/sage/schemes/cyclic_covers/cycliccover_finite_field.py b/src/sage/schemes/cyclic_covers/cycliccover_finite_field.py index 1ff68f8d4cd..82583c14cfc 100644 --- a/src/sage/schemes/cyclic_covers/cycliccover_finite_field.py +++ b/src/sage/schemes/cyclic_covers/cycliccover_finite_field.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Cyclic covers over a finite field @@ -22,13 +23,14 @@ sage: C.frobenius_polynomial().reverse()(t)/((1-t)*(1-p*t)) + O(t^5) 1 + 8*t + 102*t^2 + 1384*t^3 + 18089*t^4 + O(t^5) - sage: p = 49999 sage: x = PolynomialRing(GF(p),"x").gen() - sage: CyclicCover(5, x^5 + x).frobenius_polynomial() # long time - x^12 + 299994*x^10 + 37498500015*x^8 + 2499850002999980*x^6 + 93742500224997000015*x^4 + 1874812507499850001499994*x^2 + 15623125093747500037499700001 - sage: CyclicCover(5, 2*x^5 + x).frobenius_polynomial() # long time - x^12 + 299994*x^10 + 37498500015*x^8 + 2499850002999980*x^6 + 93742500224997000015*x^4 + 1874812507499850001499994*x^2 + 15623125093747500037499700001 + sage: CyclicCover(5, x^5 + x).frobenius_polynomial() # long time + x^12 + 299994*x^10 + 37498500015*x^8 + 2499850002999980*x^6 + 93742500224997000015*x^4 + + 1874812507499850001499994*x^2 + 15623125093747500037499700001 + sage: CyclicCover(5, 2*x^5 + x).frobenius_polynomial() # long time + x^12 + 299994*x^10 + 37498500015*x^8 + 2499850002999980*x^6 + 93742500224997000015*x^4 + + 1874812507499850001499994*x^2 + 15623125093747500037499700001 sage: p = 107 sage: x = PolynomialRing(GF(p),"x").gen() @@ -88,15 +90,14 @@ def _N0_nodenominators(p, g, n): """ Return the necessary p-adic precision for the Frobenius matrix to deduce the characteristic polynomial of Frobenius using the Newton identities, - using :meth:`charpoly_frobenius`, which assumes that the Frobenius matrix + using :meth:`charpoly_frobenius`, which assumes that the Frobenius matrix is integral, i.e., has no denominators. - INPUT: - - `p` - prime - - `g` - genus - - `n` - degree of residue field + - `p` -- prime + - `g` -- genus + - `n` -- degree of residue field TESTS:: @@ -114,7 +115,7 @@ def __init__(self, AA, r, f, names=None, verbose=0): EXAMPLES:: sage: p = 13 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(4, x^4 + 1) sage: C.frobenius_polynomial() x^6 - 6*x^5 + 3*x^4 + 60*x^3 + 39*x^2 - 1014*x + 2197 @@ -306,7 +307,7 @@ def _divide_vector(self, D, vect, R): TESTS:: sage: p = 4999 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._divide_vector(p, vector(C._Qq, [p, p^2, p^3]), C._Qq) @@ -388,7 +389,7 @@ def _frob_sparse(self, i, j, N0): TESTS:: sage: p = 499 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._frob_sparse(2, 0, 1) @@ -490,7 +491,7 @@ def _horizontal_matrix_reduction(self, s): TESTS:: sage: p = 4999 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._horizontal_matrix_reduction(24995) @@ -559,7 +560,7 @@ def _vertical_matrix_reduction(self, s0): TESTS:: sage: p = 4999 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._vertical_matrix_reduction(1) @@ -592,16 +593,16 @@ def _vertical_matrix_reduction(self, s0): [0 for i in range(d - 2)] + self._flift.list() + [0 for i in range(d - 1)] ) fd_co = ( - [0 for i in range(d - 1)] + self._dflift.list() + [0 for i in range(d - 0)] + [0 for i in range(d - 1)] + self._dflift.list() + [0 for i in range(d)] ) - rows = [f_co[d - 2 - i : -i - 1] for i in range(d - 1)] - rows += [fd_co[d - 1 - i : -i - 1] for i in range(d)] + rows = [f_co[d - 2 - i:-i - 1] for i in range(d - 1)] + rows += [fd_co[d - 1 - i:-i - 1] for i in range(d)] m = matrix(rows).transpose().inverse() a_foo = m[0:d, 0:d] - b_foo = m[d - 1 : 2 * d - 1, 0:d] + b_foo = m[d - 1:2 * d - 1, 0:d] a_foo = matrix(d, d, lambda i, j: 1 if i == j and i != d - 1 else 0) * a_foo foo = matrix(d, d, lambda i, j: j if i == j - 1 else 0) bp_foo = foo * b_foo @@ -627,7 +628,7 @@ def _reduce_vector_horizontal(self, G, e, s, k=1): TESTS:: sage: p = 4999 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._initialize_fat_horizontal(p, 3) @@ -656,7 +657,7 @@ def _reduce_vector_horizontal_BSGS(self, G, e, s): TESTS:: sage: p = 4999 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._initialize_fat_horizontal(p, 3) @@ -715,7 +716,7 @@ def _initialize_fat_horizontal(self, s, L): TESTS:: sage: p = 4999 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._initialize_fat_horizontal(p, 3) @@ -779,7 +780,7 @@ def _reduce_vector_horizontal_plain(self, G, e, s, k=1): TESTS:: sage: p = 4999 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._initialize_fat_horizontal(p, 3) @@ -910,7 +911,7 @@ def _initialize_fat_vertical(self, s0, max_upper_target): TESTS:: sage: p = 4999 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._initialize_fat_vertical(1, p + p // 3) @@ -959,7 +960,7 @@ def _frob(self, i, j, N0): TESTS:: sage: p = 4999 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._frob(2, 0, 1) @@ -1027,7 +1028,7 @@ def frobenius_matrix(self, N=None): EXAMPLES:: sage: p = 107 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: CyclicCover(2, x^5 + x).frobenius_matrix() [ O(107^2) 89*107 + O(107^2) O(107^2) O(107^2)] [ 89*107 + O(107^2) O(107^2) O(107^2) O(107^2)] @@ -1062,10 +1063,9 @@ def _frobenius_matrix_p(N0): for j in range(1, self._r): s0 = (j * self._p) % self._r for i in range(self._d - 1): - m[ - (s0 - 1) * (self._d - 1) : s0 * (self._d - 1), - i + (j - 1) * (self._d - 1), - ] = self._frob(i, j + self._epsilon * self._r, N0) + m[(s0 - 1) * (self._d - 1):s0 * (self._d - 1), + i + (j - 1) * (self._d - 1), + ] = self._frob(i, j + self._epsilon * self._r, N0) return m self._init_frob(N) @@ -1094,7 +1094,7 @@ def frobenius_polynomial(self): Hyperelliptic curves:: sage: p = 11 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: f = x^7 + 4*x^2 + 10*x + 4 sage: CyclicCover(2, f).frobenius_polynomial() == \ ....: HyperellipticCurve(f).frobenius_polynomial() @@ -1108,10 +1108,11 @@ def frobenius_polynomial(self): ....: HyperellipticCurve(f).frobenius_polynomial() True sage: p = 1117 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: f = x^9 + 4*x^2 + 10*x + 4 - sage: CyclicCover(2, f).frobenius_polynomial() == \ - ....: HyperellipticCurve(f).frobenius_polynomial() # long time + sage: P1 = CyclicCover(2, f).frobenius_polynomial() + sage: P2 = HyperellipticCurve(f).frobenius_polynomial() + sage: P1 == P2 # long time True sage: f = 2*x^5 + 4*x^3 + x^2 + 2*x + 1 sage: CyclicCover(2, f).frobenius_polynomial() == \ @@ -1121,7 +1122,7 @@ def frobenius_polynomial(self): Superelliptic curves:: sage: p = 11 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1).frobenius_polynomial() x^6 + 21*x^4 + 231*x^2 + 1331 sage: CyclicCover(4, x^3 + x + 1).frobenius_polynomial() @@ -1133,71 +1134,87 @@ def frobenius_polynomial(self): True sage: CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1).frobenius_polynomial() x^6 + 180*x^5 + 20988*x^4 + 1854349*x^3 + 104919012*x^2 + 4498200180*x + 124925014999 - sage: CyclicCover(4,x^5 + x + 1).frobenius_polynomial() - x^12 - 64*x^11 + 5018*x^10 - 488640*x^9 + 28119583*x^8 - 641791616*x^7 + 124245485932*x^6 - 3208316288384*x^5 + 702708407289583*x^4 - 61043359329111360*x^3 + 3133741752599645018*x^2 - 199800079984001599936*x + 15606259372500374970001 - - sage: CyclicCover(11, PolynomialRing(GF(1129), 'x')([-1] + [0]*(5-1) + [1])).frobenius_polynomial() # long time - x^40 + 7337188909826596*x^30 + 20187877911930897108199045855206*x^20 + 24687045654725446027864774006541463602997309796*x^10 + 11320844849639649951608809973589776933203136765026963553258401 - - sage: CyclicCover(3, PolynomialRing(GF(1009^2), 'x')([-1] + [0]*(5-1) + [1])).frobenius_polynomial() # long time - x^8 + 532*x^7 - 2877542*x^6 - 242628176*x^5 + 4390163797795*x^4 - 247015136050256*x^3 - 2982540407204025062*x^2 + 561382189105547134612*x + 1074309286591662654798721 - + sage: CyclicCover(4, x^5 + x + 1).frobenius_polynomial() + x^12 - 64*x^11 + 5018*x^10 - 488640*x^9 + 28119583*x^8 - 641791616*x^7 + + 124245485932*x^6 - 3208316288384*x^5 + 702708407289583*x^4 - 61043359329111360*x^3 + + 3133741752599645018*x^2 - 199800079984001599936*x + 15606259372500374970001 + + sage: h = PolynomialRing(GF(1129), 'x')([-1] + [0]*(5-1) + [1]) + sage: CyclicCover(11, h).frobenius_polynomial() # long time + x^40 + 7337188909826596*x^30 + 20187877911930897108199045855206*x^20 + + 24687045654725446027864774006541463602997309796*x^10 + + 11320844849639649951608809973589776933203136765026963553258401 + + sage: h = PolynomialRing(GF(1009^2), 'x')([-1] + [0]*(5-1) + [1]) + sage: CyclicCover(3, h).frobenius_polynomial() # long time + x^8 + 532*x^7 - 2877542*x^6 - 242628176*x^5 + 4390163797795*x^4 - 247015136050256*x^3 + - 2982540407204025062*x^2 + 561382189105547134612*x + 1074309286591662654798721 A non-monic example checking that :trac:`29015` is fixed:: sage: a = 3 - sage: K.<s>=GF(83^3); - sage: R.<x>= PolynomialRing(K) - sage: h = s*x^4 +x*3+ 8; - sage: C = CyclicCover(a,h) + sage: K.<s> = GF(83^3); + sage: R.<x> = PolynomialRing(K) + sage: h = s*x^4 + x*3 + 8 + sage: C = CyclicCover(a, h) sage: C.frobenius_polynomial() x^6 + 1563486*x^4 + 893980969482*x^2 + 186940255267540403 Non-superelliptic curves:: sage: p = 13 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: C = CyclicCover(4, x^4 + 1) sage: C.frobenius_polynomial() x^6 - 6*x^5 + 3*x^4 + 60*x^3 + 39*x^2 - 1014*x + 2197 sage: R.<t> = PowerSeriesRing(Integers()) - sage: C.projective_closure().zeta_series(2,t) + sage: C.projective_closure().zeta_series(2, t) 1 + 8*t + 102*t^2 + O(t^3) sage: C.frobenius_polynomial().reverse()(t)/((1-t)*(1-p*t)) + O(t^5) 1 + 8*t + 102*t^2 + 1384*t^3 + 18089*t^4 + O(t^5) - sage: x = PolynomialRing(GF(11),"x").gen() - sage: CyclicCover(4, x^6 - 11*x^3 + 70*x^2 - x + 961).frobenius_polynomial() # long time + sage: x = PolynomialRing(GF(11), "x").gen() + sage: CyclicCover(4, x^6 - 11*x^3 + 70*x^2 - x + 961).frobenius_polynomial() # long time x^14 + 14*x^12 + 287*x^10 + 3025*x^8 + 33275*x^6 + 381997*x^4 + 2254714*x^2 + 19487171 - sage: x = PolynomialRing(GF(4999),"x").gen() - sage: CyclicCover(4, x^6 - 11*x^3 + 70*x^2 - x + 961).frobenius_polynomial() # long time - x^14 - 4*x^13 - 2822*x^12 - 30032*x^11 + 37164411*x^10 - 152369520*x^9 + 54217349361*x^8 - 1021791160888*x^7 + 271032529455639*x^6 - 3807714457169520*x^5 + 4642764601604000589*x^4 - 18754988504199390032*x^3 - 8809934776794570547178*x^2 - 62425037490001499880004*x + 78015690603129374475034999 + sage: x = PolynomialRing(GF(4999), "x").gen() + sage: CyclicCover(4, x^6 - 11*x^3 + 70*x^2 - x + 961).frobenius_polynomial() # long time + x^14 - 4*x^13 - 2822*x^12 - 30032*x^11 + 37164411*x^10 - 152369520*x^9 + + 54217349361*x^8 - 1021791160888*x^7 + 271032529455639*x^6 - 3807714457169520*x^5 + + 4642764601604000589*x^4 - 18754988504199390032*x^3 - 8809934776794570547178*x^2 + - 62425037490001499880004*x + 78015690603129374475034999 sage: p = 11 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: CyclicCover(3, 5*x^3 - 5*x + 13).frobenius_polynomial() x^2 + 11 sage: CyclicCover(3, x^6 + x^4 - x^3 + 2*x^2 - x - 1).frobenius_polynomial() x^8 + 32*x^6 + 462*x^4 + 3872*x^2 + 14641 sage: p = 4999 - sage: x = PolynomialRing(GF(p),"x").gen() + sage: x = PolynomialRing(GF(p), "x").gen() sage: CyclicCover(3, 5*x^3 - 5*x + 13).frobenius_polynomial() x^2 - 47*x + 4999 sage: CyclicCover(3, x^6 + x^4 - x^3 + 2*x^2 - x - 1).frobenius_polynomial() - x^8 + 122*x^7 + 4594*x^6 - 639110*x^5 - 82959649*x^4 - 3194910890*x^3 + 114804064594*x^2 + 15240851829878*x + 624500149980001 + x^8 + 122*x^7 + 4594*x^6 - 639110*x^5 - 82959649*x^4 - 3194910890*x^3 + + 114804064594*x^2 + 15240851829878*x + 624500149980001 sage: p = 11 - sage: x = PolynomialRing(GF(p),"x").gen() - sage: CyclicCover(5, x^5 + x).frobenius_polynomial() # long time - x^12 + 4*x^11 + 22*x^10 + 108*x^9 + 503*x^8 + 1848*x^7 + 5588*x^6 + 20328*x^5 + 60863*x^4 + 143748*x^3 + 322102*x^2 + 644204*x + 1771561 - sage: CyclicCover(5, 2*x^5 + x).frobenius_polynomial() # long time - x^12 - 9*x^11 + 42*x^10 - 108*x^9 - 47*x^8 + 1782*x^7 - 8327*x^6 + 19602*x^5 - 5687*x^4 - 143748*x^3 + 614922*x^2 - 1449459*x + 1771561 + sage: x = PolynomialRing(GF(p), "x").gen() + sage: CyclicCover(5, x^5 + x).frobenius_polynomial() # long time + x^12 + 4*x^11 + 22*x^10 + 108*x^9 + 503*x^8 + 1848*x^7 + 5588*x^6 + 20328*x^5 + + 60863*x^4 + 143748*x^3 + 322102*x^2 + 644204*x + 1771561 + sage: CyclicCover(5, 2*x^5 + x).frobenius_polynomial() # long time + x^12 - 9*x^11 + 42*x^10 - 108*x^9 - 47*x^8 + 1782*x^7 - 8327*x^6 + 19602*x^5 + - 5687*x^4 - 143748*x^3 + 614922*x^2 - 1449459*x + 1771561 sage: p = 49999 - sage: x = PolynomialRing(GF(p),"x").gen() - sage: CyclicCover(5, x^5 + x ).frobenius_polynomial() # long time - x^12 + 299994*x^10 + 37498500015*x^8 + 2499850002999980*x^6 + 93742500224997000015*x^4 + 1874812507499850001499994*x^2 + 15623125093747500037499700001 + sage: x = PolynomialRing(GF(p), "x").gen() + sage: CyclicCover(5, x^5 + x).frobenius_polynomial() # long time + x^12 + 299994*x^10 + 37498500015*x^8 + 2499850002999980*x^6 + + 93742500224997000015*x^4 + 1874812507499850001499994*x^2 + + 15623125093747500037499700001 sage: CyclicCover(5, 2*x^5 + x).frobenius_polynomial() # long time - x^12 + 299994*x^10 + 37498500015*x^8 + 2499850002999980*x^6 + 93742500224997000015*x^4 + 1874812507499850001499994*x^2 + 15623125093747500037499700001 + x^12 + 299994*x^10 + 37498500015*x^8 + 2499850002999980*x^6 + + 93742500224997000015*x^4 + 1874812507499850001499994*x^2 + + 15623125093747500037499700001 TESTS:: diff --git a/src/sage/schemes/cyclic_covers/cycliccover_generic.py b/src/sage/schemes/cyclic_covers/cycliccover_generic.py index 7531d933c0b..9bca8814dad 100644 --- a/src/sage/schemes/cyclic_covers/cycliccover_generic.py +++ b/src/sage/schemes/cyclic_covers/cycliccover_generic.py @@ -17,7 +17,6 @@ ... ValueError: As the characteristic divides the order of the cover, this model is not smooth. - sage: GF7x.<x> = GF(7)[] sage: C = CyclicCover(3, x^9 + x + 1) sage: C @@ -39,13 +38,12 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.rings.polynomial.all import PolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.category_object import normalize_names from sage.arith.misc import GCD from sage.schemes.curves.affine_curve import AffinePlaneCurve - class CyclicCover_generic(AffinePlaneCurve): def __init__(self, AA, r, f, names=None): """ @@ -76,7 +74,8 @@ def __init__(self, AA, r, f, names=None): sage: C.change_ring(GF(5)) Traceback (most recent call last): ... - ValueError: As the characteristic divides the order of the cover, this model is not smooth. + ValueError: As the characteristic divides the order of the cover, + this model is not smooth. sage: GF7x.<x> = GF(7)[] @@ -119,11 +118,13 @@ def change_ring(self, R): sage: C.change_ring(GF(5)) Traceback (most recent call last): ... - ValueError: As the characteristic divides the order of the cover, this model is not smooth. + ValueError: As the characteristic divides the order of the cover, + this model is not smooth. sage: C.change_ring(GF(3)) Traceback (most recent call last): ... - ValueError: Not a smooth Cyclic Cover of P^1: singularity in the provided affine patch. + ValueError: Not a smooth Cyclic Cover of P^1: singularity in the + provided affine patch. sage: C.change_ring(GF(17)) Cyclic Cover of P^1 over Finite Field of size 17 defined by y^5 = x^5 + x + 1 """ diff --git a/src/sage/schemes/elliptic_curves/BSD.py b/src/sage/schemes/elliptic_curves/BSD.py index a9a42ebd84b..85130f0a5f9 100644 --- a/src/sage/schemes/elliptic_curves/BSD.py +++ b/src/sage/schemes/elliptic_curves/BSD.py @@ -2,7 +2,10 @@ "Birch and Swinnerton-Dyer formulas" from sage.arith.misc import prime_divisors -from sage.rings.all import ZZ, Infinity, QuadraticField +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.infinity import Infinity +from sage.rings.number_field.number_field import QuadraticField from sage.functions.other import ceil @@ -19,7 +22,8 @@ class BSD_data: sage: D.curve=EllipticCurve('11a') sage: D.update() sage: D.Sha - Tate-Shafarevich group for the Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Tate-Shafarevich group for the Elliptic Curve + defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field """ def __init__(self): self.curve = None @@ -50,7 +54,8 @@ def update(self): sage: D.curve = EllipticCurve('11a') sage: D.update() sage: D.Sha - Tate-Shafarevich group for the Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Tate-Shafarevich group for the Elliptic Curve + defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field """ self.two_tor_rk = self.curve.two_torsion_rank() self.Sha = self.curve.sha() @@ -85,11 +90,17 @@ def simon_two_descent_work(E, two_tor_rk): sage: from sage.schemes.elliptic_curves.BSD import simon_two_descent_work sage: E = EllipticCurve('14a') sage: simon_two_descent_work(E, E.two_torsion_rank()) + doctest:warning + ... + DeprecationWarning: Use E.rank(algorithm="pari") instead, as this script has been ported over to pari. + See https://github.com/sagemath/sage/issues/35621 for details. (0, 0, 0, 0, []) sage: E = EllipticCurve('37a') sage: simon_two_descent_work(E, E.two_torsion_rank()) (1, 1, 0, 0, [(0 : 0 : 1)]) """ + from sage.misc.superseded import deprecation + deprecation(35621, 'Use the two-descent in pari instead, as this script has been ported over to pari.') rank_lower_bd, two_sel_rk, gens = E.simon_two_descent() rank_upper_bd = two_sel_rk - two_tor_rk gens = [P for P in gens if P.additive_order() == Infinity] @@ -136,6 +147,55 @@ def mwrank_two_descent_work(E, two_tor_rk): sha2_upper_bd = MWRC.selmer_rank() - two_tor_rk - rank_lower_bd return rank_lower_bd, rank_upper_bd, sha2_lower_bd, sha2_upper_bd, gens +def pari_two_descent_work(E): + r""" + Prepare the output from pari by two-isogeny. + + INPUT: + + - ``E`` -- an elliptic curve + + OUTPUT: A tuple of 5 elements with the first 4 being integers. + + - a lower bound on the rank + + - an upper bound on the rank + + - a lower bound on the rank of Sha[2] + + - an upper bound on the rank of Sha[2] + + - a list of the generators found + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.BSD import pari_two_descent_work + sage: E = EllipticCurve('14a') + sage: pari_two_descent_work(E) + (0, 0, 0, 0, []) + sage: E = EllipticCurve('37a') + sage: pari_two_descent_work(E) # random, up to sign + (1, 1, 0, 0, [(0 : -1 : 1)]) + sage: E = EllipticCurve('210e7') + sage: pari_two_descent_work(E) + (0, 2, 0, 2, []) + sage: E = EllipticCurve('66b3') + sage: pari_two_descent_work(E) + (0, 0, 2, 2, []) + + """ + ep = E.pari_curve() + lower, rank_upper_bd, s, pts = ep.ellrank() + gens = sorted([E.point([QQ(x[0]),QQ(x[1])], check=True) for x in pts]) + gens = E.saturation(gens)[0] + # this is explained in the pari-gp documentation: + # s is the dimension of Sha[2]/2Sha[4], + # which is a lower bound for dim Sha[2] + # dim Sha[2] = dim Sel2 - rank E(Q) - dim tors + # rank_upper_bd = dim Sel_2 - dim tors - s + sha_upper_bd = rank_upper_bd - len(gens) + s + return len(gens), rank_upper_bd, s, sha_upper_bd, gens + def native_two_isogeny_descent_work(E, two_tor_rk): """ @@ -245,12 +305,12 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, - ``verbosity`` -- int, how much information about the proof to print. - - 0: print nothing - - 1: print sketch of proof - - 2: print information about remaining primes + - 0: print nothing + - 1: print sketch of proof + - 2: print information about remaining primes - ``two_desc`` -- string (default ``'mwrank'``), what to use for the - two-descent. Options are ``'mwrank', 'simon', 'sage'`` + two-descent. Options are ``'mwrank', 'pari', 'sage'`` - ``proof`` -- bool or None (default: None, see proof.elliptic_curve or sage.structure.proof). If False, this @@ -313,7 +373,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, True for p = 3 by Kolyvagin bound True for p = 5 by Kolyvagin bound [] - sage: E.prove_BSD(two_desc='simon') + sage: E.prove_BSD(two_desc='pari') [] A rank two curve:: @@ -349,13 +409,16 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, sage: E.prove_BSD() Traceback (most recent call last): ... - RuntimeError: It seems that the rank conjecture does not hold for this curve (Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field)! This may be a counterexample to BSD, but is more likely a bug. + RuntimeError: It seems that the rank conjecture does not hold for this curve + (Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field)! + This may be a counterexample to BSD, but is more likely a bug. We test the consistency check for the 2-part of Sha:: sage: E = EllipticCurve('37a') sage: S = E.sha(); S - Tate-Shafarevich group for the Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + Tate-Shafarevich group for the Elliptic Curve defined by y^2 + y = x^3 - x + over Rational Field sage: def foo(use_database): ....: return 4 sage: S.an = foo @@ -426,6 +489,15 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, p = 2: True by 2-descent True for p not in {2} by Kolyvagin. [] + + :: + + sage: E = EllipticCurve('66b3') + sage: E.prove_BSD(two_desc="pari",verbosity=1) + p = 2: True by 2-descent + True for p not in {2} by Kolyvagin. + [] + """ if proof is None: from sage.structure.proof.proof import get_flag @@ -454,8 +526,8 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, if two_desc == 'mwrank': M = mwrank_two_descent_work(BSD.curve, BSD.two_tor_rk) - elif two_desc == 'simon': - M = simon_two_descent_work(BSD.curve, BSD.two_tor_rk) + elif two_desc == 'pari': + M = pari_two_descent_work(BSD.curve) elif two_desc == 'sage': M = native_two_isogeny_descent_work(BSD.curve, BSD.two_tor_rk) else: @@ -480,7 +552,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, # We do not know BSD(E,p) for even a single p, since it's # an open problem to show that L^r(E,1)/(Reg*Omega) is # rational for any curve with r >= 2. - from sage.sets.all import Primes + from sage.sets.primes import Primes BSD.primes = Primes() if return_BSD: BSD.rank = rank_lower_bd diff --git a/src/sage/schemes/elliptic_curves/Qcurves.py b/src/sage/schemes/elliptic_curves/Qcurves.py index 4c9e8f3718a..45fb5c51293 100644 --- a/src/sage/schemes/elliptic_curves/Qcurves.py +++ b/src/sage/schemes/elliptic_curves/Qcurves.py @@ -53,19 +53,19 @@ def is_Q_curve(E, maxp=100, certificate=False, verbose=False): - when the flag is ``True``, so `E` is a `\QQ`-curve: - - either {'CM':`D`} where `D` is a negative discriminant, when - `E` has potential CM with discriminant `D`; - - - otherwise {'CM': `0`, 'core_poly': `f`, 'rho': `\rho`, 'r': - `r`, 'N': `N`}, when `E` is a non-CM `\QQ`-curve, where the - core polynomial `f` is an irreducible monic polynomial over - `QQ` of degree `2^\rho`, all of whose roots are - `j`-invariants of curves isogenous to `E`, the core level - `N` is a square-free integer with `r` prime factors which is - the LCM of the degrees of the isogenies between these - conjugates. For example, if there exists a curve `E'` - isogenous to `E` with `j(E')=j\in\QQ`, then the certificate - is {'CM':0, 'r':0, 'rho':0, 'core_poly': x-j, 'N':1}. + - either {'CM':`D`} where `D` is a negative discriminant, when + `E` has potential CM with discriminant `D`; + + - otherwise {'CM': `0`, 'core_poly': `f`, 'rho': `\rho`, 'r': + `r`, 'N': `N`}, when `E` is a non-CM `\QQ`-curve, where the + core polynomial `f` is an irreducible monic polynomial over + `QQ` of degree `2^\rho`, all of whose roots are + `j`-invariants of curves isogenous to `E`, the core level + `N` is a square-free integer with `r` prime factors which is + the LCM of the degrees of the isogenies between these + conjugates. For example, if there exists a curve `E'` + isogenous to `E` with `j(E')=j\in\QQ`, then the certificate + is {'CM':0, 'r':0, 'rho':0, 'core_poly': x-j, 'N':1}. - when the flag is ``False``, so `E` is not a `\QQ`-curve, the certificate is a prime `p` such that the reductions of `E` at @@ -130,9 +130,10 @@ def is_Q_curve(E, maxp=100, certificate=False, verbose=False): sage: from sage.schemes.elliptic_curves.Qcurves import is_Q_curve sage: R.<x> = PolynomialRing(QQ) - sage: K.<a> = NumberField(R([3, 0, -5, 0, 1])) - sage: E = EllipticCurve([K([-3,-4,1,1]),K([4,-1,-1,0]),K([-2,0,1,0]),K([-621,778,138,-178]),K([9509,2046,-24728,10380])]) - sage: is_Q_curve(E, certificate=True, verbose=True) + sage: K.<a> = NumberField(R([3, 0, -5, 0, 1])) # needs sage.rings.number_field + sage: E = EllipticCurve([K([-3,-4,1,1]), K([4,-1,-1,0]), K([-2,0,1,0]), # needs sage.rings.number_field + ....: K([-621,778,138,-178]), K([9509,2046,-24728,10380])]) + sage: is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field Checking whether Elliptic Curve defined by y^2 + (a^3+a^2-4*a-3)*x*y + (a^2-2)*y = x^3 + (-a^2-a+4)*x^2 + (-178*a^3+138*a^2+778*a-621)*x + (10380*a^3-24728*a^2+2046*a+9509) over Number Field in a with defining polynomial x^4 - 5*x^2 + 3 is a Q-curve No: inconsistency at the 2 primes dividing 3 - potentially multiplicative: [True, False] @@ -142,9 +143,10 @@ def is_Q_curve(E, maxp=100, certificate=False, verbose=False): primes is consistent, but the local test at good primes above `13` is not:: - sage: K.<a> = NumberField(R([-10, 0, 1])) - sage: E = EllipticCurve([K([0,1]),K([-1,-1]),K([0,0]),K([-236,40]),K([-1840,464])]) - sage: is_Q_curve(E, certificate=True, verbose=True) + sage: K.<a> = NumberField(R([-10, 0, 1])) # needs sage.rings.number_field + sage: E = EllipticCurve([K([0,1]), K([-1,-1]), K([0,0]), # needs sage.rings.number_field + ....: K([-236,40]), K([-1840,464])]) + sage: is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field Checking whether Elliptic Curve defined by y^2 + a*x*y = x^3 + (-a-1)*x^2 + (40*a-236)*x + (464*a-1840) over Number Field in a with defining polynomial x^2 - 10 is a Q-curve Applying local tests at good primes above p<=100 No: inconsistency at the 2 ordinary primes dividing 13 @@ -156,9 +158,9 @@ def is_Q_curve(E, maxp=100, certificate=False, verbose=False): sage: from sage.schemes.elliptic_curves.Qcurves import is_Q_curve sage: R.<x> = PolynomialRing(QQ) - sage: K.<a> = NumberField(R([-1, -1, 1])) - sage: E = EllipticCurve([K([1,0]),K([-1,0]),K([0,1]),K([0,-2]),K([0,1])]) - sage: is_Q_curve(E, certificate=True, verbose=True) + sage: K.<a> = NumberField(R([-1, -1, 1])) # needs sage.rings.number_field + sage: E = EllipticCurve([K([1,0]), K([-1,0]), K([0,1]), K([0,-2]), K([0,1])]) # needs sage.rings.number_field + sage: is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field Checking whether Elliptic Curve defined by y^2 + x*y + a*y = x^3 + (-1)*x^2 + (-2*a)*x + a over Number Field in a with defining polynomial x^2 - x - 1 is a Q-curve Yes: E is CM (discriminant -15) (True, {'CM': -15}) @@ -168,8 +170,11 @@ def is_Q_curve(E, maxp=100, certificate=False, verbose=False): in fact there is an isogenous curve with rational `j`, so we have a so-called rational `\QQ`-curve:: + sage: # needs sage.rings.number_field sage: K.<a> = NumberField(R([1, 0, -4, 0, 1])) - sage: E = EllipticCurve([K([-2,-4,1,1]),K([0,1,0,0]),K([0,1,0,0]),K([-4780,9170,1265,-2463]),K([163923,-316598,-43876,84852])]) + sage: E = EllipticCurve([K([-2,-4,1,1]), K([0,1,0,0]), K([0,1,0,0]), + ....: K([-4780,9170,1265,-2463]), + ....: K([163923,-316598,-43876,84852])]) sage: flag, cert = is_Q_curve(E, certificate=True) sage: flag True @@ -183,7 +188,9 @@ def is_Q_curve(E, maxp=100, certificate=False, verbose=False): quadratic conjugate `j`-invariants in `\QQ(\sqrt{3})` (but which are not base-changes from the quadratic subfield):: - sage: E = EllipticCurve([K([0,-3,0,1]),K([1,4,0,-1]),K([0,0,0,0]),K([-2,-16,0,4]),K([-19,-32,4,8])]) + sage: # needs sage.rings.number_field + sage: E = EllipticCurve([K([0,-3,0,1]), K([1,4,0,-1]), K([0,0,0,0]), + ....: K([-2,-16,0,4]), K([-19,-32,4,8])]) sage: flag, cert = is_Q_curve(E, certificate=True) sage: flag True @@ -204,13 +211,13 @@ def is_Q_curve(E, maxp=100, certificate=False, verbose=False): TypeError: Elliptic Curve defined by ... must be an elliptic curve defined over a number field """ - from sage.rings.number_field.number_field_base import is_NumberField + from sage.rings.number_field.number_field_base import NumberField if verbose: print(f"Checking whether {E} is a Q-curve") try: - assert is_NumberField(E.base_field()) + assert isinstance(E.base_field(), NumberField) except (AttributeError, AssertionError): raise TypeError(f"{E} must be an elliptic curve defined over a number field") @@ -400,9 +407,9 @@ def Step4Test(E, B, oldB=0, verbose=False): - `B` (integer): upper bound on primes to test - - `oldB` (integer, default 0): lower bound on primes to test + - ``oldB`` (integer, default 0): lower bound on primes to test - - `verbose` (boolean, default ``False``): verbosity flag + - ``verbose`` (boolean, default ``False``): verbosity flag OUTPUT: @@ -426,9 +433,10 @@ def Step4Test(E, B, oldB=0, verbose=False): sage: from sage.schemes.elliptic_curves.Qcurves import Step4Test sage: R.<x> = PolynomialRing(QQ) - sage: K.<a> = NumberField(R([3, 0, -5, 0, 1])) - sage: E = EllipticCurve([K([-3,-4,1,1]),K([4,-1,-1,0]),K([-2,0,1,0]),K([-621,778,138,-178]),K([9509,2046,-24728,10380])]) - sage: Step4Test(E, 100, verbose=True) + sage: K.<a> = NumberField(R([3, 0, -5, 0, 1])) # needs sage.rings.number_field + sage: E = EllipticCurve([K([-3,-4,1,1]), K([4,-1,-1,0]), K([-2,0,1,0]), # needs sage.rings.number_field + ....: K([-621,778,138,-178]), K([9509,2046,-24728,10380])]) + sage: Step4Test(E, 100, verbose=True) # needs sage.rings.number_field No: inconsistency at the 2 ordinary primes dividing 13 - Frobenius discriminants mod squares: [-3, -1] (False, 13) @@ -438,9 +446,11 @@ def Step4Test(E, B, oldB=0, verbose=False): sage: from sage.schemes.elliptic_curves.Qcurves import Step4Test sage: R.<x> = PolynomialRing(QQ) - sage: K.<a> = NumberField(R([-3, 0, 9, 0, -6, 0, 1])) - sage: E = EllipticCurve([K([1,-3,0,1,0,0]),K([5,-3,-6,1,1,0]),K([1,-3,0,1,0,0]),K([-139,-129,331,277,-76,-63]),K([2466,1898,-5916,-4582,1361,1055])]) - sage: Step4Test(E, 100, verbose=True) + sage: K.<a> = NumberField(R([-3, 0, 9, 0, -6, 0, 1])) # needs sage.rings.number_field + sage: E = EllipticCurve([K([1,-3,0,1,0,0]), K([5,-3,-6,1,1,0]), # needs sage.rings.number_field + ....: K([1,-3,0,1,0,0]), K([-139,-129,331,277,-76,-63]), + ....: K([2466,1898,-5916,-4582,1361,1055])]) + sage: Step4Test(E, 100, verbose=True) # needs sage.rings.number_field (True, 0) """ from sage.arith.misc import primes @@ -487,9 +497,9 @@ def conjugacy_test(jlist, verbose=False): INPUT: - - `jlist` (list): a list of algebraic numbers in the same field + - ``jlist`` (list): a list of algebraic numbers in the same field - - `verbose` (boolean, default ``False``): verbosity flag + - ``verbose`` (boolean, default ``False``): verbosity flag OUTPUT: @@ -498,25 +508,26 @@ def conjugacy_test(jlist, verbose=False): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.Qcurves import conjugacy_test sage: conjugacy_test([3]) [x - 3] sage: K.<a> = QuadraticField(2) sage: conjugacy_test([K(3), a]) [x - 3] - sage: conjugacy_test([K(3), 3+a]) + sage: conjugacy_test([K(3), 3 + a]) [x - 3] - sage: conjugacy_test([3+a]) + sage: conjugacy_test([3 + a]) [] - sage: conjugacy_test([3+a, 3-a]) + sage: conjugacy_test([3 + a, 3 - a]) [x^2 - 6*x + 7] sage: x = polygen(QQ) - sage: f = x^3-3 + sage: f = x^3 - 3 sage: K.<a> = f.splitting_field() sage: js = f.roots(K, multiplicities=False) sage: conjugacy_test(js) [] - sage: f = x^4-3 + sage: f = x^4 - 3 sage: K.<a> = NumberField(f) sage: js = f.roots(K, multiplicities=False) sage: conjugacy_test(js) diff --git a/src/sage/schemes/elliptic_curves/__init__.py b/src/sage/schemes/elliptic_curves/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/elliptic_curves/cardinality.py b/src/sage/schemes/elliptic_curves/cardinality.py index cc93b9ecf74..d871355c20a 100644 --- a/src/sage/schemes/elliptic_curves/cardinality.py +++ b/src/sage/schemes/elliptic_curves/cardinality.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings """ Specific algorithms to compute cardinality of elliptic curves over a finite field @@ -21,7 +22,10 @@ # **************************************************************************** from .constructor import EllipticCurve, EllipticCurve_from_j from sage.schemes.curves.projective_curve import Hasse_bounds -from sage.rings.all import Integer, ZZ, GF, polygen +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.polynomial.polynomial_ring import polygen from sage.groups.generic import order_from_bounds @@ -36,19 +40,22 @@ def _cardinality_with_j_invariant_1728(self): An example with q=p=1 (mod 4):: sage: F = GF(10009) - sage: [_cardinality_with_j_invariant_1728(EllipticCurve(F,[0,0,0,11^i,0])) for i in range(4)] + sage: [_cardinality_with_j_invariant_1728(EllipticCurve(F, [0,0,0,11^i,0])) + ....: for i in range(4)] [10016, 10210, 10004, 9810] An example with q=p=3 (mod 4):: sage: F = GF(10007) - sage: [_cardinality_with_j_invariant_1728(EllipticCurve(F,[0,0,0,5^i,0])) for i in range(4)] + sage: [_cardinality_with_j_invariant_1728(EllipticCurve(F, [0,0,0,5^i,0])) + ....: for i in range(4)] [10008, 10008, 10008, 10008] An example with `q=p^2`, p=3 (mod 4):: sage: F.<a> = GF(10007^2,'a') - sage: [_cardinality_with_j_invariant_1728(EllipticCurve(F,[0,0,0,a^i,0])) for i in range(4)] + sage: [_cardinality_with_j_invariant_1728(EllipticCurve(F,[0,0,0,a^i,0])) + ....: for i in range(4)] [100160064, 100140050, 100120036, 100140050] Examples with `q=2^d`, d odd (3 isomorphism classes):: @@ -65,8 +72,9 @@ def _cardinality_with_j_invariant_1728(self): sage: F.<a> = GF(2**16,'a') sage: b = a^11 # trace 1 - sage: ais = [[0,0,1,0,0],[0,0,1,0,b],[0,0,1,b,0],[0,0,a,0,0],[0,0,a,0,a^2*b],[0,0,a^2,0,0],[0,0,a^2,0,a^4*b]] - sage: curves = [EllipticCurve(F,ai) for ai in ais] + sage: ais = [[0,0,1,0,0], [0,0,1,0,b], [0,0,1,b,0], [0,0,a,0,0], + ....: [0,0,a,0,a^2*b], [0,0,a^2,0,0], [0,0,a^2,0,a^4*b]] + sage: curves = [EllipticCurve(F, ai) for ai in ais] sage: all((e1 == e2 or not e1.is_isomorphic(e2)) for e1 in curves for e2 in curves) True sage: [_cardinality_with_j_invariant_1728(e) for e in curves] @@ -76,8 +84,8 @@ def _cardinality_with_j_invariant_1728(self): sage: F.<a> = GF(3**15,'a') sage: b = a^7 # has trace 1 - sage: ais = [[0,0,0,1,0],[0,0,0,-1,0],[0,0,0,-1,b],[0,0,0,-1,-b]] - sage: curves = [EllipticCurve(F,ai) for ai in ais] + sage: ais = [[0,0,0,1,0], [0,0,0,-1,0], [0,0,0,-1,b], [0,0,0,-1,-b]] + sage: curves = [EllipticCurve(F, ai) for ai in ais] sage: all((e1 == e2 or not e1.is_isomorphic(e2)) for e1 in curves for e2 in curves) True sage: [_cardinality_with_j_invariant_1728(e) for e in curves] @@ -88,8 +96,9 @@ def _cardinality_with_j_invariant_1728(self): sage: F.<g> = GF(3^18,'g') sage: i = F(-1).sqrt() sage: a = g^8 # has trace 1 - sage: ais = [[0,0,0,1,0],[0,0,0,1,i*a],[0,0,0,g,0],[0,0,0,g^3,0],[0,0,0,g^2,0], [0,0,0,g^2,i*a*g^3]] - sage: curves = [EllipticCurve(F,ai) for ai in ais] + sage: ais = [[0,0,0,1,0], [0,0,0,1,i*a], [0,0,0,g,0], + ....: [0,0,0,g^3,0], [0,0,0,g^2,0], [0,0,0,g^2,i*a*g^3]] + sage: curves = [EllipticCurve(F, ai) for ai in ais] sage: all((e1 == e2 or not e1.is_isomorphic(e2)) for e1 in curves for e2 in curves) True sage: [_cardinality_with_j_invariant_1728(e) for e in curves] @@ -371,10 +380,10 @@ def cardinality_exhaustive(self): EXAMPLES:: sage: p = next_prime(10^3) - sage: E = EllipticCurve(GF(p),[3,4]) + sage: E = EllipticCurve(GF(p), [3,4]) sage: E.cardinality_exhaustive() 1020 - sage: E = EllipticCurve(GF(3^4,'a'),[1,1]) + sage: E = EllipticCurve(GF(3^4,'a'), [1,1]) sage: E.cardinality_exhaustive() 64 """ @@ -402,10 +411,10 @@ def cardinality_bsgs(self, verbose=False): EXAMPLES:: sage: p = next_prime(10^3) - sage: E = EllipticCurve(GF(p),[3,4]) + sage: E = EllipticCurve(GF(p), [3,4]) sage: E.cardinality_bsgs() 1020 - sage: E = EllipticCurve(GF(3^4,'a'),[1,1]) + sage: E = EllipticCurve(GF(3^4,'a'), [1,1]) sage: E.cardinality_bsgs() 64 sage: F.<a> = GF(101^3,'a') @@ -540,7 +549,8 @@ def _cardinality_subfield(self, jpol): sage: from sage.schemes.elliptic_curves.cardinality import _cardinality_subfield sage: k.<a> = GF(7^5) sage: E = EllipticCurve(k, [1,2,3,4,5]); E - Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field in a of size 7^5 + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 + over Finite Field in a of size 7^5 sage: _cardinality_subfield(E, E.j_invariant().minimal_polynomial()) 17019 diff --git a/src/sage/schemes/elliptic_curves/cm.py b/src/sage/schemes/elliptic_curves/cm.py index 6d56371ce93..09a6b63f402 100644 --- a/src/sage/schemes/elliptic_curves/cm.py +++ b/src/sage/schemes/elliptic_curves/cm.py @@ -4,11 +4,13 @@ This module implements the functions - ``hilbert_class_polynomial`` +- ``is_HCP`` - ``cm_j_invariants`` - ``cm_orders`` - ``discriminants_with_bounded_class_number`` - ``cm_j_invariants_and_orders`` - ``largest_fundamental_disc_with_class_number`` +- ``is_cm_j_invariant`` AUTHORS: @@ -34,14 +36,16 @@ # **************************************************************************** from sage.interfaces.magma import magma -from sage.rings.all import (Integer, - QQ, - ZZ, - IntegerRing, - is_fundamental_discriminant, - PolynomialRing) +from sage.rings.integer import Integer +from sage.rings.rational_field import QQ +from sage.rings.integer_ring import ZZ +from sage.rings.integer_ring import IntegerRing +from sage.rings.number_field.number_field import is_fundamental_discriminant +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.misc.cachefunc import cached_function +from sage.rings.number_field.number_field_element_base import NumberFieldElement_base + @cached_function def hilbert_class_polynomial(D, algorithm=None): @@ -78,6 +82,7 @@ def hilbert_class_polynomial(D, algorithm=None): EXAMPLES:: + sage: # needs sage.libs.flint sage: hilbert_class_polynomial(-4) x - 1728 sage: hilbert_class_polynomial(-7) @@ -124,7 +129,8 @@ def hilbert_class_polynomial(D, algorithm=None): raise ValueError("%s is not a valid algorithm" % algorithm) from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives - from sage.rings.all import RR, ComplexField + from sage.rings.real_mpfr import RR + from sage.rings.complex_mpfr import ComplexField from sage.functions.all import elliptic_j # get all primitive reduced quadratic forms, (necessary to exclude @@ -152,7 +158,7 @@ def hilbert_class_polynomial(D, algorithm=None): h = len(rqf) # class number c1 = 3.05682737291380 # log(2*10.63) c2 = sum([1/RR(qf[0]) for qf in rqf], RR(0)) - prec = c2*RR(3.142)*RR(D).abs().sqrt() + h*c1 # bound on log + prec = c2 * RR(3.142) * RR(D).abs().sqrt() + h * c1 # bound on log prec = prec * 1.45 # bound on log_2 (1/log(2) = 1.44..) prec = 10 + prec.ceil() # allow for rounding error @@ -171,6 +177,164 @@ def hilbert_class_polynomial(D, algorithm=None): return IntegerRing()['x'](coeffs) +def is_HCP(f, check_monic_irreducible=True): + r""" + Determine whether a polynomial is a Hilbert Class Polynomial. + + INPUT: + + - ``f`` -- a polynomial in `\ZZ[X]`. + - ``check_monic_irreducible`` (boolean, default ``True``) -- if + ``True``, check that ``f`` is a monic, irreducible, integer + polynomial. + + OUTPUT: + + (integer) -- either `D` if ``f`` is the Hilbert Class Polynomial + `H_D` for discriminant `D`, or `0` if not an HCP. + + ALGORITHM: + + Cremona and Sutherland: Algorithm 2 of [CreSuth2023]_. + + EXAMPLES: + + Even for large degrees this is fast. We test the largest + discriminant of class number 100, for which the HCP has coefficients + with thousands of digits:: + + sage: from sage.schemes.elliptic_curves.cm import is_HCP + sage: D = -1856563 + sage: D.class_number() # needs sage.libs.pari + 100 + + sage: # needs sage.libs.flint + sage: H = hilbert_class_polynomial(D) + sage: H.degree() + 100 + sage: max(H).ndigits() + 2774 + sage: is_HCP(H) + -1856563 + + Testing polynomials which are not HCPs is faster:: + + sage: is_HCP(H+1) # needs sage.libs.flint + 0 + + + TESTS:: + + sage: # needs sage.libs.flint + sage: from sage.schemes.elliptic_curves.cm import is_HCP + sage: all(is_HCP(hilbert_class_polynomial(D)) == D + ....: for D in srange(-4,-100,-1) if D.is_discriminant()) + True + sage: all(not is_HCP(hilbert_class_polynomial(D) + 1) + ....: for D in srange(-4,-100,-1) if D.is_discriminant()) + True + """ + zero = ZZ(0) + # optional check that input is monic and irreducible + if check_monic_irreducible: + try: + if not (all(c in ZZ for c in f) and f.is_monic()): + return zero + f = f.change_ring(ZZ) + except AttributeError: + return zero + + from sage.rings.real_mpfr import RR + from sage.rings.finite_rings.finite_field_constructor import GF + + h = f.degree() + h2list = [d for d in h.divisors() + if (d-h) % 2 == 0 and d.prime_to_m_part(2) == 1] + pmin = 33 * (h**2 * (RR(h+2).log().log()+2)**2).ceil() + # Guarantees 4*p > |D| for fundamental D under GRH + p = pmin-1 + n = 0 + from sage.arith.misc import next_prime + from sage.schemes.elliptic_curves.constructor import EllipticCurve + + while True: + p = next_prime(p) + n += 1 + fp = f.change_ring(GF(p)) + # Compute X^p-X mod fp + z = fp.parent().gen() + r = pow(z, p, fp) - z + d = r.gcd(fp).degree() # number of roots mod p + if d == 0: + continue + if not fp.is_squarefree(): + continue + if d < h and d not in h2list: + return zero + jp = fp.any_root(degree=-1, assume_squarefree=True) + E = EllipticCurve(j=jp) + if E.is_supersingular(): + continue + try: + D = E.endomorphism_discriminant_from_class_number(h) + except ValueError: + return zero + return D if f == hilbert_class_polynomial(D) else zero + +def OrderClassNumber(D0,h0,f): + r""" + Return the class number h(f**2 * D0), given h(D0)=h0. + + INPUT: + + - ``D0`` (integer) -- a negative fundamental discriminant + - ``h0`` (integer) -- the class number of the (maximal) imaginary quadratic order of discriminant ``D0`` + - ``f`` (integer) -- a positive integer + + OUTPUT: + + (integer) the class number of the imaginary quadratic order of discriminant ``D0*f**2`` + + ALGORITHM: + + We use the formula for the class number of the order `\mathcal{O}_{D}` in terms of the class number of the + maximal order `\mathcal{O}_{D_0}`; see [Cox1989]_ Theorem 7.24: + + .. MATH:: + + h(D) = \frac{h(D_0)f}{[\mathcal{O}_{D_0}^\times:\mathcal{O}_{D}^\times]}\prod_{p\,|\,f}\left(1-\left(\frac{D_0}{p}\right)\frac{1}{p}\right) + + EXAMPLES:: + + sage: # needs sage.libs.pari + sage: from sage.schemes.elliptic_curves.cm import OrderClassNumber + sage: D0 = -4 + sage: h = D0.class_number() + sage: [OrderClassNumber(D0,h,f) for f in srange(1,20)] + [1, 1, 2, 2, 2, 4, 4, 4, 6, 4, 6, 8, 6, 8, 8, 8, 8, 12, 10] + sage: all([OrderClassNumber(D0,h,f) == (D0*f**2).class_number() for f in srange(1,20)]) + True + + """ + if not D0.is_fundamental_discriminant(): + raise ValueError("{} is not a fundamental discriminant".format(D0)) + if f <= 0: + raise ValueError("{} is not a positive integer".format(f)) + if f == 1: + return h0 + ps = f.prime_divisors() + from sage.misc.misc_c import prod + from sage.arith.misc import kronecker as kronecker_symbol + n = (f // prod(ps)) * prod(p - kronecker_symbol(D0, p) for p in ps) + if D0 == -3: + # assert h0 == 1 and n % 3 == 0 + return n // 3 + if D0 == -4: + # assert h0 == 1 and n % 2 == 0 + return n // 2 + return n * h0 + + @cached_function def cm_j_invariants(K, proof=None): r""" @@ -188,25 +352,28 @@ def cm_j_invariants(K, proof=None): EXAMPLES:: sage: cm_j_invariants(QQ) - [-262537412640768000, -147197952000, -884736000, -12288000, -884736, -32768, -3375, 0, 1728, 8000, 54000, 287496, 16581375] + [-262537412640768000, -147197952000, -884736000, -12288000, -884736, + -32768, -3375, 0, 1728, 8000, 54000, 287496, 16581375] Over imaginary quadratic fields there are no more than over `QQ`:: - sage: cm_j_invariants(QuadraticField(-1, 'i')) - [-262537412640768000, -147197952000, -884736000, -12288000, -884736, -32768, -3375, 0, 1728, 8000, 54000, 287496, 16581375] + sage: cm_j_invariants(QuadraticField(-1, 'i')) # needs sage.rings.number_field + [-262537412640768000, -147197952000, -884736000, -12288000, -884736, + -32768, -3375, 0, 1728, 8000, 54000, 287496, 16581375] Over real quadratic fields there may be more, for example:: - sage: len(cm_j_invariants(QuadraticField(5, 'a'))) + sage: len(cm_j_invariants(QuadraticField(5, 'a'))) # needs sage.rings.number_field 31 Over number fields K of many higher degrees this also works:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: cm_j_invariants(K) - [-262537412640768000, -147197952000, -884736000, - -884736, -32768, 8000, -3375, 16581375, 1728, 287496, 0, - 54000, -12288000, + [-262537412640768000, -147197952000, -884736000, -884736, -32768, + 8000, -3375, 16581375, 1728, 287496, 0, 54000, -12288000, 31710790944000*a^2 + 39953093016000*a + 50337742902000] sage: K.<a> = NumberField(x^4 - 2) sage: len(cm_j_invariants(K)) @@ -234,11 +401,14 @@ def cm_j_invariants_and_orders(K, proof=None): EXAMPLES:: sage: cm_j_invariants_and_orders(QQ) - [(-3, 3, -12288000), (-3, 2, 54000), (-3, 1, 0), (-4, 2, 287496), (-4, 1, 1728), (-7, 2, 16581375), (-7, 1, -3375), (-8, 1, 8000), (-11, 1, -32768), (-19, 1, -884736), (-43, 1, -884736000), (-67, 1, -147197952000), (-163, 1, -262537412640768000)] + [(-3, 3, -12288000), (-3, 2, 54000), (-3, 1, 0), (-4, 2, 287496), (-4, 1, 1728), + (-7, 2, 16581375), (-7, 1, -3375), (-8, 1, 8000), (-11, 1, -32768), + (-19, 1, -884736), (-43, 1, -884736000), (-67, 1, -147197952000), + (-163, 1, -262537412640768000)] Over an imaginary quadratic field there are no more than over `QQ`:: - sage: cm_j_invariants_and_orders(QuadraticField(-1, 'i')) + sage: cm_j_invariants_and_orders(QuadraticField(-1, 'i')) # needs sage.rings.number_field [(-163, 1, -262537412640768000), (-67, 1, -147197952000), (-43, 1, -884736000), (-19, 1, -884736), (-11, 1, -32768), (-8, 1, 8000), (-7, 1, -3375), (-7, 2, 16581375), (-4, 1, 1728), @@ -246,17 +416,18 @@ def cm_j_invariants_and_orders(K, proof=None): Over real quadratic fields there may be more:: - sage: v = cm_j_invariants_and_orders(QuadraticField(5,'a')); len(v) + sage: v = cm_j_invariants_and_orders(QuadraticField(5,'a')); len(v) # needs sage.rings.number_field 31 - sage: [(D, f) for D, f, j in v if j not in QQ] + sage: [(D, f) for D, f, j in v if j not in QQ] # needs sage.rings.number_field [(-235, 1), (-235, 1), (-115, 1), (-115, 1), (-40, 1), (-40, 1), (-35, 1), (-35, 1), (-20, 1), (-20, 1), (-15, 1), (-15, 1), (-15, 2), (-15, 2), (-4, 5), (-4, 5), (-3, 5), (-3, 5)] Over number fields K of many higher degrees this also works:: - sage: K.<a> = NumberField(x^3 - 2) - sage: cm_j_invariants_and_orders(K) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: cm_j_invariants_and_orders(K) # needs sage.rings.number_field [(-163, 1, -262537412640768000), (-67, 1, -147197952000), (-43, 1, -884736000), (-19, 1, -884736), (-11, 1, -32768), (-8, 1, 8000), (-7, 1, -3375), (-7, 2, 16581375), (-4, 1, 1728), @@ -282,8 +453,10 @@ def cm_j_invariants_and_orders(K, proof=None): # Get the list of CM orders that could possibly have Hilbert class # polynomial F(x) with a root in K. If F(x) has a root alpha in K, # then F is the minimal polynomial of alpha in K, so the degree of - # F(x) is at most [K:QQ]. - dlist = sorted(Df for v in discriminants_with_bounded_class_number(K.degree(), proof=proof).values() for Df in v) + # F(x) divides [K:QQ]. + n = K.absolute_degree() + T = discriminants_with_bounded_class_number(n, proof=proof) + dlist = sorted(sum((Dflist for h,Dflist in T.items() if h.divides(n)), [])) return [(D, f, j) for D, f in dlist for j in hilbert_class_polynomial(D*f*f).roots(K, multiplicities=False)] @@ -303,27 +476,36 @@ def cm_orders(h, proof=None): OUTPUT: - - list of 2-tuples `(D,f)` + - list of 2-tuples `(D,f)` sorted lexicographically by `(|D|, f)` EXAMPLES:: sage: cm_orders(0) [] sage: v = cm_orders(1); v - [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)] + [(-3, 1), (-3, 2), (-3, 3), (-4, 1), (-4, 2), (-7, 1), (-7, 2), (-8, 1), + (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)] sage: type(v[0][0]), type(v[0][1]) (<... 'sage.rings.integer.Integer'>, <... 'sage.rings.integer.Integer'>) + sage: # needs sage.libs.pari sage: v = cm_orders(2); v - [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1), (-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1), (-148, 1), (-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)] + [(-3, 4), (-3, 5), (-3, 7), (-4, 3), (-4, 4), (-4, 5), (-7, 4), (-8, 2), + (-8, 3), (-11, 3), (-15, 1), (-15, 2), (-20, 1), (-24, 1), (-35, 1), + (-40, 1), (-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1), + (-148, 1), (-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)] sage: len(v) 29 sage: set([hilbert_class_polynomial(D*f^2).degree() for D,f in v]) {2} - Any degree up to 100 is implemented, but may be prohibitively slow:: + Any degree up to 100 is implemented, but may be slow:: + sage: # needs sage.libs.pari sage: cm_orders(3) - [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2), (-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1), (-643, 1), (-883, 1), (-907, 1)] + [(-3, 6), (-3, 9), (-11, 2), (-19, 2), (-23, 1), (-23, 2), (-31, 1), (-31, 2), + (-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2), + (-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1), + (-643, 1), (-883, 1), (-907, 1)] sage: len(cm_orders(4)) 84 """ @@ -331,13 +513,16 @@ def cm_orders(h, proof=None): if h <= 0: # trivial case return [] - # Get information for all discriminants then throw away everything - # but for h. If this is replaced by a table it will be faster, - # but not now. (David Kohel is rumored to have a large table.) - return discriminants_with_bounded_class_number(h, proof=proof)[h] + + if h in hDf_dict: + return hDf_dict[h] + else: # Get all discriminants for all class numbers up to h (which will + # be stored in hDf_dict), and return just those with class number h. + return discriminants_with_bounded_class_number(h, proof=proof)[h] # Table from Mark Watkins paper "Class numbers of imaginary quadratic fields". -# I extracted this by cutting/pasting from the pdf, and running this program: + +# WAS extracted this by cutting/pasting from the pdf, and running this program: # z = {} # for X in open('/Users/wstein/tmp/a.txt').readlines(): # if len(X.strip()): @@ -345,6 +530,11 @@ def cm_orders(h, proof=None): # for i in range(5): # z[v[3*i]]=(v[3*i+2], v[3*i+1]) +# The keys are integers 1--100 and the value for each h is (|D|,n) +# where |D| is the largest absolute discriminant of an imaginary +# quadratic field with class number h, and n is the number of such +# fields. These are all *unconditional* (not dependent on GRH). + watkins_table = {1: (163, 9), 2: (427, 18), 3: (907, 16), 4: (1555, 54), 5: (2683, 25), 6: (3763, 51), 7: (5923, 31), 8: (6307, 131), 9: (10627, 34), 10: @@ -374,13 +564,60 @@ def cm_orders(h, proof=None): 95:(1659067, 241), 96: (1684027, 3283), 97: (1842523, 185), 98: (2383747,580), 99: (1480627, 289), 100: (1856563, 1736)} +# Table from Janis Klaise [Klaise2012]_ + +# Extracted by converting pdf to text via pdf2ps and ps2txt, cutting/pasting +# and running this code: + +# klaise_table = {} +# for X in open('klaise_table.txt').readlines(): +# if len(X.strip()): +# v = [int(a) for a in X.split()] +# for i in range(4): +# klaise_table[v[3*i]]=(v[3*i+2], v[3*i+1]) + +# The keys are integers 1--100 and the value for each h is (|D|,n) +# where |D| is the largest discriminant of an imaginary quadratic +# order with class number h, and n is the number of such orders. +# These are all *unconditional* (not dependent on GRH). + +klaise_table = {1: (163, 13), 2: (427, 29), 3: (907, 25), 4: (1555, 84), 5: (2683, 29), 6: (4075, 101), + 7: (5923, 38), 8: (7987, 208), 9: (10627, 55), 10: (13843, 123), 11: (15667, 46), + 12: (19723, 379), 13: (20563, 43), 14: (30067, 134), 15: (34483, 95), 16: (35275, 531), + 17: (37123, 50), 18: (48427, 291), 19: (38707, 59), 20: (58843, 502), 21: (61483, 118), + 22: (85507, 184), 23: (90787, 78), 24: (111763, 1042), 25: (93307, 101), 26: (103027, 227), + 27: (103387, 136), 28: (126043, 623), 29: (166147, 94), 30: (137083, 473), 31: (133387, 83), + 32: (164803, 1231), 33: (222643, 158), 34: (189883, 262), 35: (210907, 111), 36: (217627, 1306), + 37: (158923, 96), 38: (289963, 284), 39: (253507, 162), 40: (274003, 1418), 41: (296587, 125), + 42: (301387, 596), 43: (300787, 123), 44: (319867, 911), 45: (308323, 231), 46: (462883, 330), + 47: (375523, 117), 48: (335203, 2895), 49: (393187, 146), 50: (389467, 445), 51: (546067, 217), + 52: (457867, 1006), 53: (425107, 130), 54: (532123, 812), 55: (452083, 177), 56: (494323, 1812), + 57: (615883, 237), 58: (586987, 361), 59: (474307, 144), 60: (662803, 2361), 61: (606643, 149), + 62: (647707, 386), 63: (991027, 311), 64: (693067, 2919), 65: (703123, 192), 66: (958483, 861), + 67: (652723, 145), 68: (819163, 1228), 69: (888427, 292), 70: (821683, 704), 71: (909547, 176), + 72: (947923, 4059), 73: (886867, 137), 74: (951043, 474), 75: (916507, 353), 76: (1086187, 1384), + 77: (1242763, 236), 78: (1004347, 925), 79: (1333963, 200), 80: (1165483, 3856), 81: (1030723, 339), + 82: (1446547, 487), 83: (1074907, 174), 84: (1225387, 2998), 85: (1285747, 246), 86: (1534723, 555), + 87: (1261747, 313), 88: (1265587, 2771), 89: (1429387, 206), 90: (1548523, 1516), 91: (1391083, 249), + 92: (1452067, 1591), 93: (1475203, 354), 94: (1587763, 600), 95: (1659067, 273), 96: (1684027, 7276), + 97: (1842523, 208), 98: (2383747, 710), 99: (1480627, 396), 100: (1856563, 2311)} + def largest_fundamental_disc_with_class_number(h): - """ - Return largest absolute value of any fundamental discriminant with - class number `h`, and the number of fundamental discriminants with - that class number. This is known for `h` up to 100, by work of Mark - Watkins. + r""" + Return largest absolute value of any fundamental negative discriminant with + class number `h`, and the number of fundamental negative discriminants with + that class number. This is known (unconditionally) for `h` up to 100, + by work of Mark Watkins ([Watkins2004]_). + + .. NOTE:: + + The class number of a fundamental negative discriminant `D` is + the same as the class number of the imaginary quadratic field + `\QQ(\sqrt{D})`, so this function gives the number of such + fields of each class number `h\le100`. It is easy to extend + this to larger class number conditional on the GRH, but much + harder to obtain unconditional results. INPUT: @@ -388,202 +625,280 @@ class number `h`, and the number of fundamental discriminants with EXAMPLES:: - sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(0) + sage: from sage.schemes.elliptic_curves.cm import largest_fundamental_disc_with_class_number + sage: largest_fundamental_disc_with_class_number(0) (0, 0) - sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(1) + sage: largest_fundamental_disc_with_class_number(1) (163, 9) - sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(2) + sage: largest_fundamental_disc_with_class_number(2) (427, 18) - sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(10) + sage: largest_fundamental_disc_with_class_number(10) (13843, 87) - sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(100) + sage: largest_fundamental_disc_with_class_number(100) (1856563, 1736) - sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(101) + sage: largest_fundamental_disc_with_class_number(101) Traceback (most recent call last): ... - NotImplementedError: largest discriminant not known for class number 101 + NotImplementedError: largest fundamental discriminant not available for class number 101 + """ h = Integer(h) if h <= 0: - # very easy special case return Integer(0), Integer(0) try: - # simply look up the answer in Watkins's table. B, c = watkins_table[h] return (Integer(B), Integer(c)) except KeyError: - # nobody knows, since I guess Watkins's is state of the art. - raise NotImplementedError("largest discriminant not known for class number %s" % h) + raise NotImplementedError("largest fundamental discriminant not available for class number %s" % h) +def largest_disc_with_class_number(h): + r""" + Return largest absolute value of any negative discriminant with + class number `h`, and the number of fundamental negative + discriminants with that class number. This is known + (unconditionally) for `h` up to 100, by work of Mark Watkins + [Watkins2004]_ for fundamental discriminants, extended to all + discriminants of class number `h\le100` by Klaise [Klaise2012]_. + + .. NOTE:: + + The class number of a negative discriminant `D` is + the same as the class number of the unique imaginary quadratic order + of discriminant `D`, so this function gives the number of such + orders of each class number `h\le100`. It is easy to extend + this to larger class number conditional on the GRH, but much + harder to obyain unconditional results. + + INPUT: + + - `h` -- integer + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.cm import largest_disc_with_class_number + sage: largest_disc_with_class_number(0) + (0, 0) + sage: largest_disc_with_class_number(1) + (163, 13) + sage: largest_disc_with_class_number(2) + (427, 29) + sage: largest_disc_with_class_number(10) + (13843, 123) + sage: largest_disc_with_class_number(100) + (1856563, 2311) + sage: largest_disc_with_class_number(101) + Traceback (most recent call last): + ... + NotImplementedError: largest discriminant not available for class number 101 + + For most `h\le100`, the largest fundamental discriminant with + class number `h` is also the largest discriminant, but this is not + the case for some `h`:: + + sage: from sage.schemes.elliptic_curves.cm import largest_disc_with_class_number, largest_fundamental_disc_with_class_number + sage: [h for h in range(1,101) if largest_disc_with_class_number(h)[0] != largest_fundamental_disc_with_class_number(h)[0]] + [6, 8, 12, 16, 20, 30, 40, 42, 52, 70] + sage: largest_fundamental_disc_with_class_number(6) + (3763, 51) + sage: largest_disc_with_class_number(6) + (4075, 101) + + """ + h = Integer(h) + if h <= 0: + return Integer(0), Integer(0) + try: + B, c = klaise_table[h] + return (Integer(B), Integer(c)) + except KeyError: + raise NotImplementedError("largest discriminant not available for class number %s" % h) + +# This dict has class numbers h as keys, the value at h is a complete +# list of pairs (D0,f) such that D=D0*f**2 has class number h. We +# initialise it with h=1 only; other values will be added by calls to +# discriminants_with_bounded_class_number(). + + +hDf_dict = {ZZ(1): [(ZZ(D), ZZ(h)) for D,h in + [(-3, 1), (-3, 2), (-3, 3), (-4, 1), (-4, 2), (-7, 1), (-7, 2), + (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)]]} -@cached_function def discriminants_with_bounded_class_number(hmax, B=None, proof=None): - r""" - Return dictionary with keys class numbers `h\le hmax` and values the - list of all pairs `(D, f)`, with `D<0` a fundamental discriminant such - that `Df^2` has class number `h`. If the optional bound `B` is given, - return only those pairs with fundamental `|D| \le B`, though `f` can - still be arbitrarily large. + r"""Return a dictionary with keys class numbers `h\le hmax` and values the + list of all pairs `(D_0, f)`, with `D_0<0` a fundamental discriminant such + that `D=D_0f^2` has class number `h`. If the optional bound `B` is given, + return only those pairs with `|D| \le B`. INPUT: - ``hmax`` -- integer - `B` -- integer or None; if None returns all pairs - ``proof`` -- this code calls the PARI function :pari:`qfbclassno`, so it - could give wrong answers when ``proof``==``False``. The default is - whatever ``proof.number_field()`` is. If ``proof==False`` and `B` is - ``None``, at least the number of discriminants is correct, since it - is double checked with Watkins's table. + could give wrong answers when ``proof``==``False`` (though only for + discriminants greater than `2\cdot10^{10}`). The default is + the current value of ``proof.number_field()``. OUTPUT: - dictionary - In case `B` is not given, we use Mark Watkins's: "Class numbers of - imaginary quadratic fields" to compute a `B` that captures all `h` - up to `hmax` (only available for `hmax\le100`). + .. NOTE:: + + In case `B` is not given, then ``hmax`` must be at most 100; we + use the tables from [Watkins2004]_ and [Klaise2012]_ to compute + a `B` that captures all `h` up to `hmax`. EXAMPLES:: - sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(3) + sage: # needs sage.libs.pari + sage: from sage.schemes.elliptic_curves.cm import discriminants_with_bounded_class_number + sage: v = discriminants_with_bounded_class_number(3) sage: sorted(v) [1, 2, 3] sage: v[1] - [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)] + [(-3, 1), (-3, 2), (-3, 3), (-4, 1), (-4, 2), (-7, 1), (-7, 2), (-8, 1), + (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)] sage: v[2] - [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1), (-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1), (-148, 1), (-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)] + [(-3, 4), (-3, 5), (-3, 7), (-4, 3), (-4, 4), (-4, 5), (-7, 4), (-8, 2), + (-8, 3), (-11, 3), (-15, 1), (-15, 2), (-20, 1), (-24, 1), (-35, 1), (-40, 1), + (-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1), (-148, 1), + (-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)] sage: v[3] - [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2), (-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1), (-643, 1), (-883, 1), (-907, 1)] - sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(8, proof=False) + [(-3, 6), (-3, 9), (-11, 2), (-19, 2), (-23, 1), (-23, 2), (-31, 1), (-31, 2), + (-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2), + (-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1), + (-643, 1), (-883, 1), (-907, 1)] + sage: v = discriminants_with_bounded_class_number(8, proof=False) sage: sorted(len(v[h]) for h in v) [13, 25, 29, 29, 38, 84, 101, 208] Find all class numbers for discriminant up to 50:: sage: sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(hmax=5, B=50) - {1: [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1)], 2: [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1)], 3: [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2)], 4: [(-3, 13), (-3, 11), (-3, 8), (-4, 10), (-4, 8), (-4, 7), (-4, 6), (-7, 8), (-7, 6), (-7, 3), (-8, 6), (-8, 4), (-11, 5), (-15, 4), (-19, 5), (-19, 3), (-20, 3), (-20, 2), (-24, 2), (-35, 3), (-39, 2), (-39, 1), (-40, 2), (-43, 3)], 5: [(-47, 2), (-47, 1)]} + {1: [(-3, 1), (-3, 2), (-3, 3), (-4, 1), (-4, 2), (-7, 1), (-7, 2), (-8, 1), (-11, 1), (-19, 1), (-43, 1)], 2: [(-3, 4), (-4, 3), (-8, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1)], 3: [(-11, 2), (-23, 1), (-31, 1)], 4: [(-39, 1)], 5: [(-47, 1)]} + """ + hmax = Integer(hmax) + global hDf_dict + + # Easy case where we have already computed and cached the relevant values + if hDf_dict and hmax <= max(hDf_dict): + T = {h:Dflist for h,Dflist in hDf_dict.items() if h <= hmax} + if B: + for h in T: + T[h] = [Df for Df in T[h] if Df[0].abs()*Df[1]**2 <= B] + return T + # imports that are needed only for this function + from sage.arith.srange import xsrange from sage.structure.proof.proof import get_flag - - # deal with input defaults and type checking proof = get_flag(proof, 'number_field') - hmax = Integer(hmax) - - # T stores the output - T = {} - - # Easy case -- instead of giving error, give meaningful output - if hmax < 1: - return T if B is None: - # Determine how far we have to go by applying Watkins's theorem. - v = [largest_fundamental_disc_with_class_number(h) for h in range(1, hmax+1)] - B = max([b for b,_ in v]) - fund_count = [0] + [cnt for _,cnt in v] + if hmax <= 100: + # Determine how far we have to go by applying Watkins + Klaise's results. + v = [largest_disc_with_class_number(h) for h in range(1, hmax+1)] + B = max([b for b,_ in v]) + #print("Testing all discriminants up to {}".format(B)) + count = [0] + [cnt for _,cnt in v] + else: + raise ValueError("if hmax>100 you must specify a discriminant bound B") else: # Nothing to do -- set to None so we can use this later to know not # to do a double check about how many we find. - fund_count = None + count = None B = Integer(B) if B <= 2: # This is an easy special case, since there are no fundamental discriminants # this small. - return T - - # This lower bound gets used in an inner loop below. - from math import log - - def lb(f): - """Lower bound on euler_phi.""" - # 1.79 > e^gamma = 1.7810724... - if f <= 1: - return 0 # don't do log(log(1)) = log(0) - llf = log(log(f)) - return f/(1.79*llf + 3.0/llf) - - for D in range(-B, -2): - D = Integer(D) - if is_fundamental_discriminant(D): - h_D = D.class_number(proof) - # For each fundamental discriminant D, loop through the f's such - # that h(D*f^2) could possibly be <= hmax. As explained to me by Cremona, - # we have h(D*f^2) >= (1/c)*h(D)*phi_D(f) >= (1/c)*h(D)*euler_phi(f), where - # phi_D(f) is like euler_phi(f) but the factor (1-1/p) is replaced - # by a factor of (1-kr(D,p)*p), where kr(D/p) is the Kronecker symbol. - # The factor c is 1 unless D=-4 and f>1 (when c=2) or D=-3 and f>1 (when c=3). - # Since (1-1/p) <= 1 and (1-1/p) <= (1+1/p), we see that - # euler_phi(f) <= phi_D(f). - # - # We have the following analytic lower bound on euler_phi: - # - # euler_phi(f) >= lb(f) = f / (exp(euler_gamma)*log(log(n)) + 3/log(log(n))). - # - # See Theorem 8 of Peter Clark's - # http://math.uga.edu/~pete/4400arithmeticorders.pdf - # which is a consequence of Theorem 15 of - # [Rosser and Schoenfeld, 1962]. - # - # By Calculus, we see that the lb(f) is an increasing function of f >= 2. - # - # NOTE: You can visibly "see" that it is a lower bound in Sage with - # lb(n) = n/(exp(euler_gamma)*log(log(n)) + 3/log(log(n))) - # plot(lb, (n, 1, 10^4), color='red') + plot(lambda x: euler_phi(int(x)), 1, 10^4).show() - # - # So we consider f=1,2,..., until the first f with lb(f)*h_D > c*h_max. - # (Note that lb(f) is <= 0 for f=1,2, so nothing special is needed there.) - # - # TODO: Maybe we could do better using a bound for phi_D(f). - # - f = Integer(1) - chmax=hmax - if D==-3: - chmax*=3 + return {} + + # T stores the values found, to be returned. It will also be used + # to update the global hDf_dict *provided that* the parameter B + # was not provided. Note that we only reach this point if we have + # not already computed data for at least one class number, hmax. + + # To avoid recomputing class numbers, we initialise T with the + # global hDf_dict, only including those (D,f) for which |D|*f**2 + # <= B if B was provided: + + # h_dict caches the class number h of all discriminants previously + # encountered; we will use the function OrderClassNumber() to + # quicky compute the class number of non-fundamental discriminants + # from the fundamental ones. Note that in the initialisation, the + # keys of h_dict include nonfundamental discriminants, but we only + # update it with fundamental ones. + + from collections import defaultdict + T = defaultdict(set) + h_dict = {} + for h, Dflist in hDf_dict.items(): + for D0,f in Dflist: + h_dict[D0*f**2] = h + if not count: + Dflist = [Df for Df in Dflist if Df[0].abs()*Df[1]**2 <= B] + T[h] = set(Dflist) + + # We do not need to certify the class number from :pari:`qfbclassno` for discriminants under 2*10^10 + if B < 2*10**10: + proof = False + + for D in xsrange(-3, -B-1, -1): + if not D.is_discriminant(): + continue + D0 = D.squarefree_part() + if D0 % 4 != 1: + D0 *= 4 + f = (D//D0).isqrt() + + # Now D0 is the fundamental discriminant and f the conductor + + if D in h_dict: + h = h_dict[D] + else: + if f == 1: # D itself is fundamental + h = D.class_number(proof) + h_dict[D] = h else: - if D==-4: - chmax*=2 - while lb(f)*h_D <= chmax: - if f == 1: - h = h_D - else: - h = (D*f*f).class_number(proof) - # If the class number of this order is within the range, then - # use it. (NOTE: In some cases there is a simple relation between - # the class number for D and D*f^2, and this could be used to - # optimize this inner loop a little.) - if h <= hmax: - z = (D, f) - if h in T: - T[h].append(z) - else: - T[h] = [z] - f += 1 + h = OrderClassNumber(D0,h_dict[D0],f) + + # If the class number of this order is within the range, then store (D0,f) + if h <= hmax: + T[h].add((D0,f)) + + # sort each list of (D,f) pairs by (|D|,f) for h in T: - T[h] = list(reversed(T[h])) + T[h] = list(T[h]) + T[h].sort(key=lambda Df: (Df[0].abs(), Df[1])) - if fund_count is not None: - # Double check that we found the right number of fundamental - # discriminants; we might as well, since Watkins provides this - # data. + # count is None precisely when the user provided a value of B + if count is not None: + # 1. Check that we found the right number of discriminants for h in T: - if len([DD for DD, ff in T[h] if ff == 1]) != fund_count[h]: + if len(T[h]) != count[h]: raise RuntimeError("number of discriminants inconsistent with Watkins's table") + # 2. Update the global dict + hDf_dict.update(dict(T)) return T @cached_function -def is_cm_j_invariant(j, method='new'): - """ - Return whether or not this is a CM `j`-invariant. +def is_cm_j_invariant(j, algorithm='CremonaSutherland', method=None): + r"""Return whether or not this is a CM `j`-invariant, and the CM discriminant if it is. INPUT: - ``j`` -- an element of a number field `K` + - ``algorithm`` (string, default 'CremonaSutherland') -- the algorithm + used, either 'CremonaSutherland' (the default, very much faster + for all but very small degrees), 'exhaustive' or 'reduction' + + - ``method`` (string) -- deprecated name for ``algorithm`` + OUTPUT: A pair (bool, (d,f)) which is either (False, None) if `j` is not a @@ -591,15 +906,24 @@ def is_cm_j_invariant(j, method='new'): imaginary quadratic order of discriminant `D=df^2` where `d` is the associated fundamental discriminant and `f` the index. - .. NOTE:: + ALGORITHM: + + The default algorithm used is to test whether the minimal + polynomial of ``j`` is a Hilbert CLass Polynomail, using + :func:`is_HCP` which implements Algorithm 2 of [CreSuth2023]_ by + Cremona and Sutherland. + + Two older algorithms are available, both of which are much slower + except for very small degrees. - The current implementation makes use of the classification of - all orders of class number up to 100, and hence will raise an - error if `j` is an algebraic integer of degree greater than - this. It would be possible to implement a more general - version, using the fact that `d` must be supported on the - primes dividing the discriminant of the minimal polynomial of - `j`. + Method 'exhaustive' makes use of the complete and unconditionsl classification of + all orders of class number up to 100, and hence will raise an + error if `j` is an algebraic integer of degree greater than + this. + + Method 'reduction' constructs an elliptic curve over the number + field `\QQ(j)` and computes its traces of Frobenius at several + primes of degree 1. EXAMPLES:: @@ -609,22 +933,40 @@ def is_cm_j_invariant(j, method='new'): sage: is_cm_j_invariant(8000) (True, (-8, 1)) + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(5) sage: is_cm_j_invariant(282880*a + 632000) (True, (-20, 1)) + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: is_cm_j_invariant(31710790944000*a^2 + 39953093016000*a + 50337742902000) (True, (-3, 6)) + An example of large degree. This is only possible using the default algorithm:: + + sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant + sage: D = -1856563 + sage: H = hilbert_class_polynomial(D) # needs sage.libs.flint + sage: H.degree() # needs sage.libs.flint + 100 + sage: K.<j> = NumberField(H) # needs sage.libs.flint sage.rings.number_field + sage: is_cm_j_invariant(j) # needs sage.libs.flint sage.rings.number_field + (True, (-1856563, 1)) + TESTS:: sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant sage: all(is_cm_j_invariant(j) == (True, (d,f)) for d,f,j in cm_j_invariants_and_orders(QQ)) True + """ + if method: + if not algorithm: + algorithm = method + raise DeprecationWarning("'method' is deprecated, use 'algorithm instead'") + # First we check that j is an algebraic number: - from sage.rings.all import NumberFieldElement, NumberField - if not isinstance(j, NumberFieldElement) and j not in QQ: + if not isinstance(j, NumberFieldElement_base) and j not in QQ: raise NotImplementedError("is_cm_j_invariant() is only implemented for number field elements") # for j in ZZ we have a lookup-table: @@ -641,46 +983,64 @@ def is_cm_j_invariant(j, method='new'): if j in QQ: return False, None - # Now j has degree at least 2. If it is not integral so is not CM: + # Next we find its minimal polynomial of j: + + if j.parent().absolute_degree() == 2: + jpol = j.absolute_minpoly() # no algorithm parameter + else: + jpol = j.absolute_minpoly(algorithm='pari') - if not j.is_integral(): + # If it does not have integer coefficients then j is not integral, hence not CM: + + if not all(c in ZZ for c in jpol): return False, None - # Next we find its minimal polynomial and degree h, and if h is - # less than the degree of j.parent() we recreate j as an element - # of Q(j): + # Otherwise test whether it is a Hilbert Class Polynomial + # (using the fact that we know that it is monic and irreducible): - jpol = PolynomialRing(QQ,'x')([-j,1]) if j in QQ else j.absolute_minpoly() - h = jpol.degree() + if algorithm == 'CremonaSutherland': + D = is_HCP(jpol, check_monic_irreducible=False) + if D: + D0 = D.squarefree_part() + if D0 % 4 != 1: + D0 *= 4 + f = ZZ(D // D0).isqrt() + return (True, (D0, f)) + else: + return (False, None) - # This will be used as a fall-back if we cannot determine the - # result using local data. For this to be necessary there would - # have to be very few primes of degree 1 and norm under 1000, - # since we only need to find one prime of degree 1, good - # reduction for which a_P is nonzero. - if method=='old': - if h>100: + h = jpol.degree() + if algorithm in ['exhaustive', 'old']: + if h > 100: raise NotImplementedError("CM data only available for class numbers up to 100") for d,f in cm_orders(h): if jpol == hilbert_class_polynomial(d*f**2): - return True, (d,f) - return False, None + return (True, (d,f)) + return (False, None) - # replace j by a clone whose parent is Q(j), if necessary: + if algorithm not in ['reduction', 'new']: + raise ValueError("Invalid algorithm {} in is_cm_j_invariant".format(algorithm)) + + # Now we use the reduction algorithm + + # If the degree h is less than the degree of j.parent() we recreate j as an element + # of Q(j, and replace j by a clone whose parent is Q(j), if necessary: K = j.parent() if h < K.absolute_degree(): + from sage.rings.number_field.number_field import NumberField + K = NumberField(jpol, 'j') j = K.gen() # Construct an elliptic curve with j-invariant j, with # integral model: - from sage.schemes.elliptic_curves.all import EllipticCurve + from sage.schemes.elliptic_curves.constructor import EllipticCurve E = EllipticCurve(j=j).integral_model() D = E.discriminant() - prime_bound = 1000 # test primes of degree 1 up to this norm - max_primes = 20 # test at most this many primes + prime_bound = 1000 # test primes of degree 1 up to this norm + max_primes = 20 # test at most this many primes num_prime = 0 cmd = 0 cmf = 0 @@ -704,8 +1064,8 @@ def is_cm_j_invariant(j, method='new'): if cmd: # we have a candidate CM field already break else: # we need to try more primes - max_primes *=2 - if D.valuation(P)>0: # skip bad primes + max_primes *= 2 + if D.valuation(P) > 0: # skip bad primes continue aP = E.reduction(P).trace_of_frobenius() if aP == 0: # skip supersingular primes @@ -714,16 +1074,16 @@ def is_cm_j_invariant(j, method='new'): DP = aP**2 - 4*P.norm() dP = DP.squarefree_part() fP = ZZ(DP//dP).isqrt() - if cmd==0: # first one, so store d and f + if cmd == 0: # first one, so store d and f cmd = dP cmf = fP elif cmd != dP: # inconsistent with previous - return False, None + return (False, None) else: # consistent d, so update f cmf = cmf.gcd(fP) - if cmd==0: # no conclusion, we found no degree 1 primes, revert to old method - return is_cm_j_invariant(j, method='old') + if cmd == 0: # no conclusion, we found no degree 1 primes, revert to default algorithm + return is_cm_j_invariant(j) # it looks like cm by disc cmd * f**2 where f divides cmf @@ -733,11 +1093,10 @@ def is_cm_j_invariant(j, method='new'): # Now we must check if h(cmd*f**2)==h for f|cmf; if so we check # whether j is a root of the associated Hilbert class polynomial. + h0 = cmd.class_number() for f in cmf.divisors(): # only positive divisors - d = cmd*f**2 - if h != d.class_number(): + if h != OrderClassNumber(cmd,h0,f): continue - pol = hilbert_class_polynomial(d) - if pol(j) == 0: - return True, (cmd, f) - return False, None + if jpol == hilbert_class_polynomial(cmd*f**2): + return (True, (cmd, f)) + return (False, None) diff --git a/src/sage/schemes/elliptic_curves/constructor.py b/src/sage/schemes/elliptic_curves/constructor.py index 1ecdc082cd5..e7a1767cecb 100644 --- a/src/sage/schemes/elliptic_curves/constructor.py +++ b/src/sage/schemes/elliptic_curves/constructor.py @@ -23,13 +23,15 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -import sage.rings.all as rings +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.rational_field import RationalField import sage.rings.abc from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField -from sage.rings.number_field.number_field import is_NumberField -from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial +from sage.rings.number_field.number_field_base import NumberField +from sage.rings.finite_rings.finite_field_base import FiniteField +from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.rings.ring import is_Ring from sage.categories.fields import Fields @@ -146,7 +148,8 @@ class EllipticCurveFactory(UniqueFactory): sage: E = EllipticCurve(CC, [0,0,1,-1,0]) sage: E - Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision + Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x + over Complex Field with 53 bits of precision sage: E.j_invariant() 2988.97297297297 @@ -163,7 +166,7 @@ class EllipticCurveFactory(UniqueFactory): We can also create elliptic curves by giving a smooth plane cubic with a rational point:: sage: R3.<x,y,z> = PolynomialRing(QQ,3) - sage: F = x^3+y^3+30*z^3 + sage: F = x^3 + y^3 + 30*z^3 sage: P = [1,-1,0] sage: EllipticCurve(F,P) Elliptic Curve defined by y^2 - 270*y = x^3 - 24300 over Rational Field @@ -181,7 +184,7 @@ class EllipticCurveFactory(UniqueFactory): See :trac:`6657` :: - sage: EllipticCurve(GF(144169),j=1728) + sage: EllipticCurve(GF(144169), j=1728) # needs sage.rings.finite_rings Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 144169 Elliptic curves over the same ring with the same Weierstrass @@ -215,7 +218,7 @@ class EllipticCurveFactory(UniqueFactory): since both `j` and `j-1728` have to be factored to compute the minimal twist (see :trac:`13100`):: - sage: E = EllipticCurve_from_j(2^256+1,minimal_twist=False) + sage: E = EllipticCurve_from_j(2^256+1, minimal_twist=False) sage: E.j_invariant() == 2^256+1 True @@ -228,49 +231,52 @@ class EllipticCurveFactory(UniqueFactory): We create a curve and a point over ``QQbar`` (see :trac:`6879`):: - sage: E = EllipticCurve(QQbar,[0,1]) - sage: E(0) + sage: E = EllipticCurve(QQbar, [0,1]) # needs sage.rings.number_field + sage: E(0) # needs sage.rings.number_field (0 : 1 : 0) - sage: E.base_field() + sage: E.base_field() # needs sage.rings.number_field Algebraic Field - sage: E = EllipticCurve(RR,[1,2]); E; E.base_field() - Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision + sage: E = EllipticCurve(RR, [1,2]); E; E.base_field() + Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 + over Real Field with 53 bits of precision Real Field with 53 bits of precision - sage: EllipticCurve(CC,[3,4]); E; E.base_field() - Elliptic Curve defined by y^2 = x^3 + 3.00000000000000*x + 4.00000000000000 over Complex Field with 53 bits of precision - Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision - Real Field with 53 bits of precision - sage: E = EllipticCurve(QQbar,[5,6]); E; E.base_field() + sage: E = EllipticCurve(CC,[3,4]); E; E.base_field() + Elliptic Curve defined by y^2 = x^3 + 3.00000000000000*x + 4.00000000000000 + over Complex Field with 53 bits of precision + Complex Field with 53 bits of precision + sage: E = EllipticCurve(QQbar, [5,6]); E; E.base_field() # needs sage.rings.number_field Elliptic Curve defined by y^2 = x^3 + 5*x + 6 over Algebraic Field Algebraic Field See :trac:`6657` :: - sage: EllipticCurve(3,j=1728) + sage: EllipticCurve(3, j=1728) Traceback (most recent call last): ... ValueError: First parameter (if present) must be a ring when j is specified - sage: EllipticCurve(GF(5),j=3/5) + sage: EllipticCurve(GF(5), j=3/5) Traceback (most recent call last): ... ValueError: First parameter must be a ring containing 3/5 If the universe of the coefficients is a general field, the object - constructed has type EllipticCurve_field. Otherwise it is - EllipticCurve_generic. See :trac:`9816` :: + constructed has type :class:`EllipticCurve_field`. Otherwise it is + :class:`EllipticCurve_generic`. See :trac:`9816` :: - sage: E = EllipticCurve([QQbar(1),3]); E + sage: E = EllipticCurve([QQbar(1), 3]); E # needs sage.rings.number_field Elliptic Curve defined by y^2 = x^3 + x + 3 over Algebraic Field - sage: type(E) + sage: type(E) # needs sage.rings.number_field <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> - sage: E = EllipticCurve([RR(1),3]); E - Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 3.00000000000000 over Real Field with 53 bits of precision + sage: E = EllipticCurve([RR(1), 3]); E + Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 3.00000000000000 + over Real Field with 53 bits of precision sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> + sage: # needs sage.symbolic sage: E = EllipticCurve([SR(i),i]); E Elliptic Curve defined by y^2 = x^3 + I*x + I over Symbolic Ring sage: type(E) @@ -283,11 +289,13 @@ class EllipticCurveFactory(UniqueFactory): sage: F = FractionField(PolynomialRing(QQ,'t')) sage: t = F.gen() sage: E = EllipticCurve([t,0]); E - Elliptic Curve defined by y^2 = x^3 + t*x over Fraction Field of Univariate Polynomial Ring in t over Rational Field + Elliptic Curve defined by y^2 = x^3 + t*x + over Fraction Field of Univariate Polynomial Ring in t over Rational Field sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E.category() - Category of schemes over Fraction Field of Univariate Polynomial Ring in t over Rational Field + Category of schemes over + Fraction Field of Univariate Polynomial Ring in t over Rational Field See :trac:`12517`:: @@ -303,12 +311,10 @@ class EllipticCurveFactory(UniqueFactory): TypeError: invalid input to EllipticCurve constructor """ def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, **kwds): - """ + r""" Return a ``UniqueFactory`` key and possibly extra parameters. - INPUT: - - See the documentation for :class:`EllipticCurveFactory`. + INPUT: See the documentation for :class:`EllipticCurveFactory`. OUTPUT: @@ -326,7 +332,7 @@ def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, sage: EllipticCurve.create_key_and_extra_args(j=8000) ((Rational Field, (0, 1, 0, -3, 1)), {}) - When constructing a curve over `\\QQ` from a Cremona or LMFDB + When constructing a curve over `\QQ` from a Cremona or LMFDB label, the invariants from the database are returned as ``extra_args``:: @@ -384,6 +390,7 @@ def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, TESTS:: + sage: # needs sage.symbolic sage: var('x', 'y', 'v', 'w') (x, y, v, w) sage: EllipticCurve(y^2 + y > x^3 + x - 9) @@ -418,9 +425,9 @@ def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, x = x.lhs() - x.rhs() if isinstance(parent(x), sage.rings.abc.SymbolicRing): - x = x._polynomial_(rings.QQ['x', 'y']) + x = x._polynomial_(QQ['x', 'y']) - if is_MPolynomial(x): + if isinstance(x, MPolynomial): if y is None: x = coefficients_from_Weierstrass_polynomial(x) else: @@ -445,13 +452,13 @@ def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, if R is None: R = Sequence(x).universe() - if R in (rings.ZZ, int): - R = rings.QQ + if R in (ZZ, int): + R = QQ return (R, tuple(R(a) for a in x)), kwds def create_object(self, version, key, **kwds): - """ + r""" Create an object from a ``UniqueFactory`` key. EXAMPLES:: @@ -463,21 +470,21 @@ def create_object(self, version, key, **kwds): .. NOTE:: Keyword arguments are currently only passed to the - constructor for elliptic curves over `\\QQ`; elliptic + constructor for elliptic curves over `\QQ`; elliptic curves over other fields do not support them. """ R, x = key - if R is rings.QQ: + if R is QQ: from .ell_rational_field import EllipticCurve_rational_field return EllipticCurve_rational_field(x, **kwds) - elif is_NumberField(R): + elif isinstance(R, NumberField): from .ell_number_field import EllipticCurve_number_field return EllipticCurve_number_field(R, x) elif isinstance(R, sage.rings.abc.pAdicField): from .ell_padic_field import EllipticCurve_padic_field return EllipticCurve_padic_field(R, x) - elif is_FiniteField(R) or (isinstance(R, sage.rings.abc.IntegerModRing) and R.characteristic().is_prime()): + elif isinstance(R, FiniteField) or (isinstance(R, sage.rings.abc.IntegerModRing) and R.characteristic().is_prime()): from .ell_finite_field import EllipticCurve_finite_field return EllipticCurve_finite_field(R, x) elif R in _Fields: @@ -491,7 +498,7 @@ def create_object(self, version, key, **kwds): def EllipticCurve_from_Weierstrass_polynomial(f): - """ + r""" Return the elliptic curve defined by a cubic in (long) Weierstrass form. @@ -500,9 +507,7 @@ def EllipticCurve_from_Weierstrass_polynomial(f): - ``f`` -- a inhomogeneous cubic polynomial in long Weierstrass form. - OUTPUT: - - The elliptic curve defined by it. + OUTPUT: The elliptic curve defined by it. EXAMPLES:: @@ -533,7 +538,7 @@ def EllipticCurve_from_Weierstrass_polynomial(f): return EllipticCurve(coefficients_from_Weierstrass_polynomial(f)) def coefficients_from_Weierstrass_polynomial(f): - """ + r""" Return the coefficients `[a_1, a_2, a_3, a_4, a_6]` of a cubic in Weierstrass form. @@ -581,7 +586,7 @@ def coefficients_from_Weierstrass_polynomial(f): def EllipticCurve_from_c4c6(c4, c6): - """ + r""" Return an elliptic curve with given `c_4` and `c_6` invariants. @@ -596,7 +601,7 @@ def EllipticCurve_from_c4c6(c4, c6): try: K = c4.parent() except AttributeError: - K = rings.RationalField() + K = RationalField() if K not in _Fields: K = K.fraction_field() return EllipticCurve([-K(c4)/K(48), -K(c6)/K(864)]) @@ -655,7 +660,7 @@ def EllipticCurve_from_j(j, minimal_twist=True): `j-1728` the following example would take a long time without setting ``minimal_twist`` to False:: - sage: E = EllipticCurve_from_j(2^256+1,minimal_twist=False) + sage: E = EllipticCurve_from_j(2^256+1, minimal_twist=False) sage: E.j_invariant() == 2^256+1 True """ @@ -663,13 +668,11 @@ def EllipticCurve_from_j(j, minimal_twist=True): def coefficients_from_j(j, minimal_twist=True): - """ + r""" Return Weierstrass coefficients `(a_1, a_2, a_3, a_4, a_6)` for an elliptic curve with given `j`-invariant. - INPUT: - - See :func:`EllipticCurve_from_j`. + INPUT: See :func:`EllipticCurve_from_j`. EXAMPLES:: @@ -681,7 +684,7 @@ def coefficients_from_j(j, minimal_twist=True): sage: coefficients_from_j(1) [1, 0, 0, 36, 3455] - The ``minimal_twist`` parameter (ignored except over `\\QQ` and + The ``minimal_twist`` parameter (ignored except over `\QQ` and True by default) controls whether or not a minimal twist is computed:: @@ -693,23 +696,23 @@ def coefficients_from_j(j, minimal_twist=True): try: K = j.parent() except AttributeError: - K = rings.RationalField() + K = RationalField() if K not in _Fields: K = K.fraction_field() - char=K.characteristic() - if char==2: + char = K.characteristic() + if char == 2: if j == 0: return Sequence([0, 0, 1, 0, 0], universe=K) else: return Sequence([1, 0, 0, 0, 1/j], universe=K) if char == 3: - if j==0: + if j == 0: return Sequence([0, 0, 0, 1, 0], universe=K) else: return Sequence([0, j, 0, 0, -j**2], universe=K) - if K is rings.RationalField(): + if K is RationalField(): # we construct the minimal twist, i.e. the curve with minimal # conductor with this j_invariant: if j == 0: @@ -718,7 +721,7 @@ def coefficients_from_j(j, minimal_twist=True): return Sequence([0, 0, 0, -1, 0], universe=K) # 32a2 if not minimal_twist: - k=j-1728 + k = j-1728 return Sequence([0, 0, 0, -3*j*k, -2*j*k**2], universe=K) n = j.numerator() @@ -730,8 +733,8 @@ def coefficients_from_j(j, minimal_twist=True): from sage.sets.set import Set for p in Set(n.prime_divisors()+m.prime_divisors()): e = min(a4.valuation(p)//2,a6.valuation(p)//3) - if e>0: - p = p**e + if e > 0: + p = p**e a4 /= p**2 a6 /= p**3 @@ -755,7 +758,7 @@ def coefficients_from_j(j, minimal_twist=True): return Sequence([0, 0, 0, 0, 1], universe=K) if j == 1728: return Sequence([0, 0, 0, 1, 0], universe=K) - k=j-1728 + k = j-1728 return Sequence([0, 0, 0, -3*j*k, -2*j*k**2], universe=K) @@ -819,7 +822,7 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): with Cremona label 27a1:: sage: R.<x,y,z> = QQ[] - sage: cubic = x^3+y^3+z^3 + sage: cubic = x^3 + y^3 + z^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 - 9*y = x^3 - 27 over Rational Field @@ -834,7 +837,7 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): Selmer curve:: sage: R.<a,b,c> = QQ[] - sage: cubic = a^3+b^3+60*c^3 + sage: cubic = a^3 + b^3 + 60*c^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 - 540*y = x^3 - 97200 over Rational Field @@ -865,8 +868,8 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): Scheme morphism: From: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field - To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - a^3 + b^3 + 60*c^3 + To: Closed subscheme of Projective Space of dimension 2 over Rational Field + defined by: a^3 + b^3 + 60*c^3 Defn: Defined on coordinates by sending (x : y : z) to (x + y + 20*z : -x - y : -x) @@ -897,10 +900,19 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): sage: cubic = x^2*y + 4*x*y^2 + x^2*z + 8*x*y*z + 4*y^2*z + 9*x*z^2 + 9*y*z^2 sage: f = EllipticCurve_from_cubic(cubic, [1,-1,1], morphism=True); f Scheme morphism: - From: Projective Plane Curve over Rational Field defined by x^2*y + 4*x*y^2 + x^2*z + 8*x*y*z + 4*y^2*z + 9*x*z^2 + 9*y*z^2 - To: Elliptic Curve defined by y^2 + 7560/19*x*y + 552960000000/2352637*y = x^3 - 3445200/133*x^2 over Rational Field + From: Projective Plane Curve over Rational Field defined + by x^2*y + 4*x*y^2 + x^2*z + 8*x*y*z + 4*y^2*z + 9*x*z^2 + 9*y*z^2 + To: Elliptic Curve defined + by y^2 + 7560/19*x*y + 552960000000/2352637*y = x^3 - 3445200/133*x^2 + over Rational Field Defn: Defined on coordinates by sending (x : y : z) to - (2527/17280*x^2 + 133/2160*x*y + 133/108000*y^2 + 133/2880*x*z + 931/18000*y*z - 3857/48000*z^2 : -6859/288*x^2 + 323/36*x*y + 359/1800*y^2 + 551/48*x*z + 2813/300*y*z + 24389/800*z^2 : -2352637/99532800000*x^2 - 2352637/124416000000*x*y - 2352637/622080000000*y^2 + 2352637/82944000000*x*z + 2352637/207360000000*y*z - 2352637/276480000000*z^2) + (2527/17280*x^2 + 133/2160*x*y + 133/108000*y^2 + 133/2880*x*z + + 931/18000*y*z - 3857/48000*z^2 + : -6859/288*x^2 + 323/36*x*y + 359/1800*y^2 + 551/48*x*z + + 2813/300*y*z + 24389/800*z^2 + : -2352637/99532800000*x^2 - 2352637/124416000000*x*y + - 2352637/622080000000*y^2 + 2352637/82944000000*x*z + + 2352637/207360000000*y*z - 2352637/276480000000*z^2) Note that the morphism returned cannot be evaluated directly at the given point ``P=(1:-1:1)`` since the polynomials defining it @@ -951,7 +963,7 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): Weierstrass model:: sage: R.<a,b,c> = QQ[] - sage: cubic = a^3+7*b^3+64*c^3 + sage: cubic = a^3 + 7*b^3 + 64*c^3 sage: P = [2,2,-1] sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True) sage: E = f.codomain(); E @@ -989,7 +1001,7 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): and one will be used as a base point:: sage: R.<x,y,z> = QQ[] - sage: cubic = x^3+y^3+z^3 + sage: cubic = x^3 + y^3 + z^3 sage: f = EllipticCurve_from_cubic(cubic, morphism=True) sage: f Scheme morphism: @@ -1001,7 +1013,7 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): An error will be raised if no point is given and there are no rational flexes:: sage: R.<x,y,z> = QQ[] - sage: cubic = 3*x^3+4*y^3+5*z^3 + sage: cubic = 3*x^3 + 4*y^3 + 5*z^3 sage: EllipticCurve_from_cubic(cubic) Traceback (most recent call last): ... @@ -1011,10 +1023,11 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): sage: K = GF(17) sage: R.<x,y,z> = K[] - sage: cubic = 2*x^3+3*y^3+4*z^3 - sage: EllipticCurve_from_cubic(cubic,[0,3,1]) + sage: cubic = 2*x^3 + 3*y^3 + 4*z^3 + sage: EllipticCurve_from_cubic(cubic, [0,3,1]) Scheme morphism: - From: Projective Plane Curve over Finite Field of size 17 defined by 2*x^3 + 3*y^3 + 4*z^3 + From: Projective Plane Curve over Finite Field of size 17 + defined by 2*x^3 + 3*y^3 + 4*z^3 To: Elliptic Curve defined by y^2 + 16*y = x^3 + 11 over Finite Field of size 17 Defn: Defined on coordinates by sending (x : y : z) to (-x : 4*y : 4*y + 5*z) @@ -1023,33 +1036,44 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): sage: K = GF(3) sage: R.<x,y,z> = K[] - sage: cubic = x^3+y^3+z^3+x*y*z - sage: EllipticCurve_from_cubic(cubic,[0,1,-1]) + sage: cubic = x^3 + y^3 + z^3 + x*y*z + sage: EllipticCurve_from_cubic(cubic, [0,1,-1]) Scheme morphism: - From: Projective Plane Curve over Finite Field of size 3 defined by x^3 + y^3 + x*y*z + z^3 + From: Projective Plane Curve over Finite Field of size 3 + defined by x^3 + y^3 + x*y*z + z^3 To: Elliptic Curve defined by y^2 + x*y = x^3 + 1 over Finite Field of size 3 Defn: Defined on coordinates by sending (x : y : z) to (y + z : -y : x) An example over a number field, using a non-flex and where there are no rational flexes:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-3) sage: R.<x,y,z> = K[] - sage: cubic = 2*x^3+3*y^3+5*z^3 - sage: EllipticCurve_from_cubic(cubic,[1,1,-1]) + sage: cubic = 2*x^3 + 3*y^3 + 5*z^3 + sage: EllipticCurve_from_cubic(cubic, [1,1,-1]) Scheme morphism: - From: Projective Plane Curve over Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I defined by 2*x^3 + 3*y^3 + 5*z^3 - To: Elliptic Curve defined by y^2 + 1754460/2053*x*y + 5226454388736000/8653002877*y = x^3 + (-652253285700/4214809)*x^2 over Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + From: Projective Plane Curve over Number Field in a + with defining polynomial x^2 + 3 with a = 1.732050807568878?*I + defined by 2*x^3 + 3*y^3 + 5*z^3 + To: Elliptic Curve defined by + y^2 + 1754460/2053*x*y + 5226454388736000/8653002877*y + = x^3 + (-652253285700/4214809)*x^2 + over Number Field in a with defining polynomial x^2 + 3 + with a = 1.732050807568878?*I Defn: Defined on coordinates by sending (x : y : z) to - (-16424/127575*x^2 - 231989/680400*x*y - 14371/64800*y^2 - 26689/81648*x*z - 10265/27216*y*z - 2053/163296*z^2 : 24496/315*x^2 + 119243/840*x*y + 4837/80*y^2 + 67259/504*x*z + 25507/168*y*z + 5135/1008*z^2 : 8653002877/2099914709760000*x^2 + 8653002877/699971569920000*x*y + 8653002877/933295426560000*y^2 + 8653002877/419982941952000*x*z + 8653002877/279988627968000*y*z + 8653002877/335986353561600*z^2) + (-16424/127575*x^2 - 231989/680400*x*y - 14371/64800*y^2 - 26689/81648*x*z - 10265/27216*y*z - 2053/163296*z^2 + : 24496/315*x^2 + 119243/840*x*y + 4837/80*y^2 + 67259/504*x*z + 25507/168*y*z + 5135/1008*z^2 + : 8653002877/2099914709760000*x^2 + 8653002877/699971569920000*x*y + 8653002877/933295426560000*y^2 + 8653002877/419982941952000*x*z + 8653002877/279988627968000*y*z + 8653002877/335986353561600*z^2) An example over a function field, using a non-flex:: sage: K.<t> = FunctionField(QQ) sage: R.<x,y,z> = K[] - sage: cubic = x^3+t*y^3+(1+t)*z^3 - sage: EllipticCurve_from_cubic(cubic,[1,1,-1], morphism=False) - Elliptic Curve defined by y^2 + ((162*t^6+486*t^5+810*t^4+810*t^3+486*t^2+162*t)/(t^6+12*t^5-3*t^4-20*t^3-3*t^2+12*t+1))*x*y + ((314928*t^14+4094064*t^13+23462136*t^12+78102144*t^11+167561379*t^10+243026001*t^9+243026001*t^8+167561379*t^7+78102144*t^6+23462136*t^5+4094064*t^4+314928*t^3)/(t^14+40*t^13+577*t^12+3524*t^11+8075*t^10+5288*t^9-8661*t^8-17688*t^7-8661*t^6+5288*t^5+8075*t^4+3524*t^3+577*t^2+40*t+1))*y = x^3 + ((2187*t^12+13122*t^11-17496*t^10-207765*t^9-516132*t^8-673596*t^7-516132*t^6-207765*t^5-17496*t^4+13122*t^3+2187*t^2)/(t^12+24*t^11+138*t^10-112*t^9-477*t^8+72*t^7+708*t^6+72*t^5-477*t^4-112*t^3+138*t^2+24*t+1))*x^2 over Rational function field in t over Rational Field + sage: cubic = x^3 + t*y^3 + (1+t)*z^3 + sage: EllipticCurve_from_cubic(cubic, [1,1,-1], morphism=False) # needs sage.libs.singular + Elliptic Curve defined by y^2 + ((162*t^6+486*t^5+810*t^4+810*t^3+486*t^2+162*t)/(t^6+12*t^5-3*t^4-20*t^3-3*t^2+12*t+1))*x*y + ((314928*t^14+4094064*t^13+23462136*t^12+78102144*t^11+167561379*t^10+243026001*t^9+243026001*t^8+167561379*t^7+78102144*t^6+23462136*t^5+4094064*t^4+314928*t^3)/(t^14+40*t^13+577*t^12+3524*t^11+8075*t^10+5288*t^9-8661*t^8-17688*t^7-8661*t^6+5288*t^5+8075*t^4+3524*t^3+577*t^2+40*t+1))*y = x^3 + ((2187*t^12+13122*t^11-17496*t^10-207765*t^9-516132*t^8-673596*t^7-516132*t^6-207765*t^5-17496*t^4+13122*t^3+2187*t^2)/(t^12+24*t^11+138*t^10-112*t^9-477*t^8+72*t^7+708*t^6+72*t^5-477*t^4-112*t^3+138*t^2+24*t+1))*x^2 + over Rational function field in t over Rational Field TESTS: @@ -1059,8 +1083,10 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): sage: cubic = -3*x^2*y + 3*x*y^2 + 4*x^2*z + 4*y^2*z - 3*x*z^2 + 3*y*z^2 - 8*z^3 sage: EllipticCurve_from_cubic(cubic, (-4/5, 4/5, 3/5) ) Scheme morphism: - From: Projective Plane Curve over Rational Field defined by -3*x^2*y + 3*x*y^2 + 4*x^2*z + 4*y^2*z - 3*x*z^2 + 3*y*z^2 - 8*z^3 - To: Elliptic Curve defined by y^2 + 24*x*y + 3024*y = x^3 + 495*x^2 + 36288*x over Rational Field + From: Projective Plane Curve over Rational Field defined + by -3*x^2*y + 3*x*y^2 + 4*x^2*z + 4*y^2*z - 3*x*z^2 + 3*y*z^2 - 8*z^3 + To: Elliptic Curve defined by y^2 + 24*x*y + 3024*y = x^3 + 495*x^2 + 36288*x + over Rational Field Defn: Defined on coordinates by sending (x : y : z) to (-1/3*z : 3*x : -1/1008*x + 1/1008*y + 1/378*z) """ @@ -1091,7 +1117,7 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): # Test whether P is a flex; if not test whether there are any rational flexes: hessian = Matrix([[F.derivative(v1, v2) for v1 in R.gens()] for v2 in R.gens()]).det() - if P and hessian(P)==0: + if P and hessian(P) == 0: flex_point = P else: flexes = C.intersection(Curve(hessian)).rational_points() @@ -1153,11 +1179,11 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): if not P: raise ValueError('A point must be given when the cubic has no rational flexes') L = tangent_at_smooth_point(C,P) - Qlist = [Q for Q in C.intersection(Curve(L)).rational_points() if C(Q)!=CP] + Qlist = [Q for Q in C.intersection(Curve(L)).rational_points() if C(Q) != CP] # assert Qlist P2 = C(Qlist[0]) L2 = tangent_at_smooth_point(C,P2) - Qlist = [Q for Q in C.intersection(Curve(L2)).rational_points() if C(Q)!=P2] + Qlist = [Q for Q in C.intersection(Curve(L2)).rational_points() if C(Q) != P2] # assert Qlist P3 = C(Qlist[0]) @@ -1217,7 +1243,7 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): def tangent_at_smooth_point(C,P): - """Return the tangent at the smooth point `P` of projective curve `C`. + r"""Return the tangent at the smooth point `P` of projective curve `C`. INPUT: @@ -1233,13 +1259,13 @@ def tangent_at_smooth_point(C,P): sage: R.<x,y,z> = QQ[] sage: from sage.schemes.elliptic_curves.constructor import tangent_at_smooth_point - sage: C = Curve(x^3+y^3+60*z^3) + sage: C = Curve(x^3 + y^3 + 60*z^3) sage: tangent_at_smooth_point(C, [1,-1,0]) x + y sage: K.<t> = FunctionField(QQ) sage: R.<x,y,z> = K[] - sage: C = Curve(x^3+2*y^3+3*z^3) + sage: C = Curve(x^3 + 2*y^3 + 3*z^3) sage: from sage.schemes.elliptic_curves.constructor import tangent_at_smooth_point sage: tangent_at_smooth_point(C,[1,1,-1]) 3*x + 6*y + 9*z @@ -1257,7 +1283,7 @@ def tangent_at_smooth_point(C,P): return C.tangents(P,factor=False)[0] def chord_and_tangent(F, P): - """Return the third point of intersection of a cubic with the tangent at one point. + r"""Return the third point of intersection of a cubic with the tangent at one point. INPUT: @@ -1278,11 +1304,11 @@ def chord_and_tangent(F, P): sage: R.<x,y,z> = QQ[] sage: from sage.schemes.elliptic_curves.constructor import chord_and_tangent - sage: F = x^3+y^3+60*z^3 + sage: F = x^3 + y^3 + 60*z^3 sage: chord_and_tangent(F, [1,-1,0]) (-1 : 1 : 0) - sage: F = x^3+7*y^3+64*z^3 + sage: F = x^3 + 7*y^3 + 64*z^3 sage: p0 = [2,2,-1] sage: p1 = chord_and_tangent(F, p0); p1 (5 : -3 : 1) @@ -1324,14 +1350,14 @@ def chord_and_tangent(F, P): raise TypeError('{} does not define a point on a projective curve over {} defined by {}'.format(P,K,F)) L = Curve(tangent_at_smooth_point(C,P)) - Qlist = [Q for Q in C.intersection(L).rational_points() if Q!=P] + Qlist = [Q for Q in C.intersection(L).rational_points() if Q != P] if Qlist: return Qlist[0] return P def projective_point(p): - """ + r""" Return equivalent point with denominators removed INPUT: @@ -1363,7 +1389,7 @@ def projective_point(p): def are_projectively_equivalent(P, Q, base_ring): - """ + r""" Test whether ``P`` and ``Q`` are projectively equivalent. INPUT: @@ -1372,9 +1398,7 @@ def are_projectively_equivalent(P, Q, base_ring): - ``base_ring`` -- the base ring. - OUTPUT: - - Boolean. + OUTPUT: A boolean. EXAMPLES:: @@ -1390,7 +1414,7 @@ def are_projectively_equivalent(P, Q, base_ring): def EllipticCurves_with_good_reduction_outside_S(S=[], proof=None, verbose=False): r""" - Return a sorted list of all elliptic curves defined over `Q` + Return a sorted list of all elliptic curves defined over `\QQ` with good reduction outside the set `S` of primes. INPUT: @@ -1424,9 +1448,9 @@ def EllipticCurves_with_good_reduction_outside_S(S=[], proof=None, verbose=False sage: elist = EllipticCurves_with_good_reduction_outside_S([2]) sage: elist [Elliptic Curve defined by y^2 = x^3 + 4*x over Rational Field, - Elliptic Curve defined by y^2 = x^3 - x over Rational Field, - ... - Elliptic Curve defined by y^2 = x^3 - x^2 - 13*x + 21 over Rational Field] + Elliptic Curve defined by y^2 = x^3 - x over Rational Field, + ... + Elliptic Curve defined by y^2 = x^3 - x^2 - 13*x + 21 over Rational Field] sage: len(elist) 24 sage: ', '.join(e.label() for e in elist) @@ -1434,19 +1458,20 @@ def EllipticCurves_with_good_reduction_outside_S(S=[], proof=None, verbose=False Without ``Proof=False``, this example gives two warnings:: - sage: elist = EllipticCurves_with_good_reduction_outside_S([11],proof=False) # long time (14s on sage.math, 2011) - sage: len(elist) # long time + sage: elist = EllipticCurves_with_good_reduction_outside_S([11], proof=False) # long time (14s on sage.math, 2011) + sage: len(elist) # long time 12 - sage: ', '.join(e.label() for e in elist) # long time + sage: ', '.join(e.label() for e in elist) # long time '11a1, 11a2, 11a3, 121a1, 121a2, 121b1, 121b2, 121c1, 121c2, 121d1, 121d2, 121d3' - sage: elist = EllipticCurves_with_good_reduction_outside_S([2,3]) # long time (26s on sage.math, 2011) - sage: len(elist) # long time + sage: # long time + sage: elist = EllipticCurves_with_good_reduction_outside_S([2,3]) # long time (26s on sage.math, 2011) + sage: len(elist) 752 - sage: conds = sorted(set([e.conductor() for e in elist])) # long time - sage: max(conds) # long time + sage: conds = sorted(set([e.conductor() for e in elist])) + sage: max(conds) 62208 - sage: [N.factor() for N in conds] # long time + sage: [N.factor() for N in conds] [2^3 * 3, 3^3, 2^5, diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx index 5a265b40c85..458ce65a61d 100644 --- a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx +++ b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx @@ -13,14 +13,14 @@ Descent on elliptic curves over `\QQ` with a 2-isogeny # *************************************************************************** from cysignals.memory cimport sig_malloc, sig_free -from cysignals.signals cimport sig_on, sig_off +from cysignals.signals cimport sig_on from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring import polygen cdef object x_ZZ = polygen(ZZ) from sage.rings.polynomial.real_roots import real_roots -from sage.arith.all import prime_divisors -from sage.all import ntl +from sage.arith.misc import prime_divisors +import sage.libs.ntl.all as ntl from sage.rings.integer cimport Integer from sage.libs.gmp.mpz cimport * @@ -29,7 +29,8 @@ from sage.libs.flint.nmod_poly cimport * from sage.libs.flint.ulong_extras cimport * from cypari2.paridecl cimport (GEN, cgetg, t_POL, set_gel, gel, stoi, lg, - evalvarn, evalsigne, Z_issquare, hyperellratpoints) + evalvarn, evalsigne, Z_issquare, + hyperellratpoints) from cypari2.stack cimport clear_stack from sage.libs.pari.convert_gmp cimport _new_GEN_from_mpz_t @@ -44,7 +45,7 @@ cdef unsigned long valuation(mpz_t a, mpz_t p): cdef mpz_t aa cdef unsigned long v mpz_init(aa) - v = mpz_remove(aa,a,p) + v = mpz_remove(aa, a, p) mpz_clear(aa) return v @@ -92,22 +93,25 @@ cdef int padic_square(mpz_t a, mpz_t p): cdef mpz_t aa cdef int result - if mpz_sgn(a) == 0: return 1 + if mpz_sgn(a) == 0: + return 1 - v = valuation(a,p) - if v & 1: return 0 + v = valuation(a, p) + if v & 1: + return 0 - mpz_init_set(aa,a) + mpz_init_set(aa, a) while v: v -= 1 mpz_divexact(aa, aa, p) - if mpz_cmp_ui(p, 2)==0: - result = (mpz_fdiv_ui(aa, 8) == 1) + if mpz_cmp_ui(p, 2) == 0: + result = bool(mpz_fdiv_ui(aa, 8) == 1) else: - result = (mpz_legendre(aa, p) == 1) + result = bool(mpz_legendre(aa, p) == 1) mpz_clear(aa) return result + def test_padic_square(a, p): """ Doctest function for cdef int padic_square(mpz_t, unsigned long). @@ -117,13 +121,14 @@ def test_padic_square(a, p): sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_padic_square as ps sage: for i in [1..300]: ....: for p in prime_range(100): - ....: if not Qp(p)(i).is_square()==bool(ps(i,p)): + ....: if Qp(p)(i).is_square() != bool(ps(i,p)): ....: print(i, p) """ cdef Integer A = Integer(a) cdef Integer P = Integer(p) return padic_square(A.value, P.value) + cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t x, mpz_t p, unsigned long nu): """ @@ -147,7 +152,7 @@ cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, if padic_square(g_of_x, p): mpz_clear(g_of_x) - return +1 # soluble + return +1 # soluble mpz_init_set(g_prime_of_x, x) mpz_mul(g_prime_of_x, a, x) @@ -159,17 +164,21 @@ cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_add(g_prime_of_x, g_prime_of_x, d) lambd = valuation(g_of_x, p) - if mpz_sgn(g_prime_of_x)==0: - if lambd >= 2*nu: result = 0 # undecided + if mpz_sgn(g_prime_of_x) == 0: + if lambd >= 2*nu: + result = 0 # undecided else: mu = valuation(g_prime_of_x, p) - if lambd > 2*mu: result = +1 # soluble - elif lambd >= 2*nu and mu >= nu: result = 0 # undecided + if lambd > 2*mu: + result = 1 # soluble + elif lambd >= 2*nu and mu >= nu: + result = 0 # undecided mpz_clear(g_prime_of_x) mpz_clear(g_of_x) return result + cdef int lemma7(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t x, mpz_t p, unsigned long nu): """ @@ -209,28 +218,33 @@ cdef int lemma7(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, while mpz_even_p(g_of_x_odd_part): mpz_divexact_ui(g_of_x_odd_part, g_of_x_odd_part, 2) g_of_x_odd_part_mod_4 = mpz_fdiv_ui(g_of_x_odd_part, 4) - if mpz_sgn(g_prime_of_x)==0: - if lambd >= 2*nu: result = 0 # undecided + if mpz_sgn(g_prime_of_x) == 0: + if lambd >= 2*nu: + result = 0 # undecided elif lambd == 2*nu-2 and g_of_x_odd_part_mod_4==1: - result = 0 # undecided + result = 0 # undecided else: mu = valuation(g_prime_of_x, p) - if lambd > 2*mu: result = +1 # soluble + if lambd > 2*mu: + result = 1 # soluble elif nu > mu: - if lambd >= mu+nu: result = +1 # soluble + if lambd >= mu+nu: + result = 1 # soluble elif lambd+1 == mu+nu and (lambd & 1) == 0: - result = +1 # soluble + result = 1 # soluble elif lambd+2 == mu+nu and (lambd & 1) == 0 and g_of_x_odd_part_mod_4 == 1: - result = +1 # soluble + result = 1 # soluble else: # nu <= mu - if lambd >= 2*nu: result = 0 # undecided + if lambd >= 2*nu: + result = 0 # undecided elif lambd+2 == 2*nu and g_of_x_odd_part_mod_4==1: - result = 0 # undecided + result = 0 # undecided mpz_clear(g_prime_of_x) mpz_clear(g_of_x) return result + cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t x_k, mpz_t p, unsigned long k): """ @@ -245,9 +259,9 @@ cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, cdef mpz_t s if mpz_cmp_ui(p, 2) == 0: - code = lemma7(a,b,c,d,e,x_k,p,k) + code = lemma7(a, b, c, d, e, x_k, p, k) else: - code = lemma6(a,b,c,d,e,x_k,p,k) + code = lemma6(a, b, c, d, e, x_k, p, k) if code == 1: return 1 if code == -1: @@ -260,11 +274,12 @@ cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_pow_ui(s, p, k) mpz_mul_ui(s, s, t) mpz_add(s, s, x_k) - code = Zp_soluble_BSD(a,b,c,d,e,s,p,k+1) + code = Zp_soluble_BSD(a, b, c, d, e, s, p, k+1) t += 1 mpz_clear(s) return code + cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t pp, unsigned long pp_ui, nmod_poly_factor_t f_factzn, nmod_poly_t f, @@ -288,24 +303,28 @@ cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, v_min = valuation(a, pp) if mpz_cmp_ui(b, 0) != 0: v = valuation(b, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(c, 0) != 0: v = valuation(c, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(d, 0) != 0: v = valuation(d, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(e, 0) != 0: v = valuation(e, pp) - if v < v_min: v_min = v - for 0 <= v < v_min: + if v < v_min: + v_min = v + for v in range(v_min): mpz_divexact(a, a, pp) mpz_divexact(b, b, pp) mpz_divexact(c, c, pp) mpz_divexact(d, d, pp) mpz_divexact(e, e, pp) - if not v_min%2: + if not v_min % 2: # Step I in Alg. 5.3.1 of Siksek's thesis nmod_poly_set_coeff_ui(f, 0, mpz_fdiv_ui(e, pp_ui)) nmod_poly_set_coeff_ui(f, 1, mpz_fdiv_ui(d, pp_ui)) @@ -389,7 +408,7 @@ cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_divexact(ccc, ccc, pp) mpz_divexact(ddd, ddd, pp) mpz_divexact(eee, eee, pp) - # now aaa,bbb,ccc,ddd,eee represents h(x) + # now aaa, bbb, ccc, ddd, eee represents h(x) result = 0 mpz_init(tt) @@ -463,8 +482,10 @@ cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, roots[j] = pp_ui - nmod_poly_get_coeff_ui(&f_factzn.p[i], 0) j += 1 - if not has_roots: return 0 - if has_single_roots: return 1 + if not has_roots: + return 0 + if has_single_roots: + return 1 result = 0 if j > 0: @@ -515,36 +536,50 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, cdef mpz_t aa, bb, cc, dd, ee cdef mpz_t aaa, bbb, ccc, ddd, eee cdef mpz_t qq, rr, ss, tt - cdef Integer A,B,C,D,E,P + cdef Integer A, B, C, D, E, P # Step 0: divide out all common p from the quartic v_min = valuation(a, pp) if mpz_cmp_ui(b, 0) != 0: v = valuation(b, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(c, 0) != 0: v = valuation(c, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(d, 0) != 0: v = valuation(d, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(e, 0) != 0: v = valuation(e, pp) - if v < v_min: v_min = v - for 0 <= v < v_min: + if v < v_min: + v_min = v + for v in range(v_min): mpz_divexact(a, a, pp) mpz_divexact(b, b, pp) mpz_divexact(c, c, pp) mpz_divexact(d, d, pp) mpz_divexact(e, e, pp) - if not v_min%2: + if not v_min % 2: # Step I in Alg. 5.3.1 of Siksek's thesis - A = Integer(0); B = Integer(0); C = Integer(0); D = Integer(0); E = Integer(0); P = Integer(0) - mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e); mpz_set(P.value, pp) - f = ntl.ZZ_pX([E,D,C,B,A], P) - f /= ntl.ZZ_pX([A], P) # now f is monic, and we are done with A,B,C,D,E - mpz_set(qq, A.value) # qq is the leading coefficient of the polynomial + A = Integer(0) + B = Integer(0) + C = Integer(0) + D = Integer(0) + E = Integer(0) + P = Integer(0) + mpz_set(A.value, a) + mpz_set(B.value, b) + mpz_set(C.value, c) + mpz_set(D.value, d) + mpz_set(E.value, e) + mpz_set(P.value, pp) + f = ntl.ZZ_pX([E, D, C, B, A], P) + f /= ntl.ZZ_pX([A], P) # now f is monic, and we are done with A,B,C,D,E + mpz_set(qq, A.value) # qq is the leading coefficient of the polynomial f_factzn = f.factor() result = 0 for factor, exponent in f_factzn: @@ -627,7 +662,7 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_divexact(ccc, ccc, pp) mpz_divexact(ddd, ddd, pp) mpz_divexact(eee, eee, pp) - # now aaa,bbb,ccc,ddd,eee represents h(x) + # now aaa, bbb, ccc, ddd, eee represents h(x) result = 0 mpz_init(tt) @@ -683,10 +718,20 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, return result else: # Step II in Alg. 5.3.1 of Siksek's thesis - A = Integer(0); B = Integer(0); C = Integer(0); D = Integer(0); E = Integer(0); P = Integer(0) - mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e); mpz_set(P.value, pp) - f = ntl.ZZ_pX([E,D,C,B,A], P) - f /= ntl.ZZ_pX([A], P) # now f is monic + A = Integer(0) + B = Integer(0) + C = Integer(0) + D = Integer(0) + E = Integer(0) + P = Integer(0) + mpz_set(A.value, a) + mpz_set(B.value, b) + mpz_set(C.value, c) + mpz_set(D.value, d) + mpz_set(E.value, e) + mpz_set(P.value, pp) + f = ntl.ZZ_pX([E, D, C, B, A], P) + f /= ntl.ZZ_pX([A], P) # now f is monic f_factzn = f.factor() has_roots = 0 @@ -702,8 +747,10 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_set(roots[j], A.value) j += 1 - if not has_roots: return 0 - if has_single_roots: return 1 + if not has_roots: + return 0 + if has_single_roots: + return 1 result = 0 if j > 0: @@ -749,25 +796,27 @@ cdef bint Qp_soluble_siksek(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, locally soluble at p. """ cdef int result = 0 - cdef mpz_t a,b,c,d,e + cdef mpz_t a, b, c, d, e cdef nmod_poly_t f nmod_poly_init(f, P) - mpz_init_set(a,A) - mpz_init_set(b,B) - mpz_init_set(c,C) - mpz_init_set(d,D) - mpz_init_set(e,E) + mpz_init_set(a, A) + mpz_init_set(b, B) + mpz_init_set(c, C) + mpz_init_set(d, D) + mpz_init_set(e, E) - if Zp_soluble_siksek(a,b,c,d,e,p,P,f_factzn, f, f1, linear): + if Zp_soluble_siksek(a, b, c, d, e, + p, P, f_factzn, f, f1, linear): result = 1 else: - mpz_set(a,A) - mpz_set(b,B) - mpz_set(c,C) - mpz_set(d,D) - mpz_set(e,E) - if Zp_soluble_siksek(e,d,c,b,a,p,P,f_factzn, f, f1, linear): + mpz_set(a, A) + mpz_set(b, B) + mpz_set(c, C) + mpz_set(d, D) + mpz_set(e, E) + if Zp_soluble_siksek(e, d, c, b, a, + p, P,f_factzn, f, f1, linear): result = 1 mpz_clear(a) @@ -778,6 +827,7 @@ cdef bint Qp_soluble_siksek(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, nmod_poly_clear(f) return result + cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, mpz_t p, fmpz_poly_t f1, fmpz_poly_t linear): """ @@ -786,7 +836,7 @@ cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, FLINT. """ cdef int result = 0 - cdef mpz_t a,b,c,d,e + cdef mpz_t a, b, c, d, e mpz_init_set(a,A) mpz_init_set(b,B) @@ -794,7 +844,8 @@ cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, mpz_init_set(d,D) mpz_init_set(e,E) - if Zp_soluble_siksek_large_p(a,b,c,d,e,p,f1,linear): + if Zp_soluble_siksek_large_p(a, b, c, d, e, + p, f1, linear): result = 1 else: mpz_set(a,A) @@ -820,9 +871,11 @@ cdef bint Qp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p): cdef mpz_t zero cdef int result = 0 mpz_init_set_ui(zero, 0) - if Zp_soluble_BSD(a,b,c,d,e,zero,p,0): + if Zp_soluble_BSD(a, b, c, d, e, + zero, p, 0): result = 1 - elif Zp_soluble_BSD(e,d,c,b,a,zero,p,1): + elif Zp_soluble_BSD(e, d, c, b, a, + zero, p, 1): result = 1 mpz_clear(zero) return result @@ -843,17 +896,20 @@ cdef bint Qp_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p): if mpz_fits_ulong_p(p): nmod_poly_factor_init(f_factzn) pp = mpz_get_ui(p) - sik_sol = Qp_soluble_siksek(a,b,c,d,e,p,pp,f_factzn,f1,linear) + sik_sol = Qp_soluble_siksek(a, b, c, d, e, + p, pp, f_factzn, f1,linear) nmod_poly_factor_clear(f_factzn) else: - sik_sol = Qp_soluble_siksek_large_p(a,b,c,d,e,p,f1,linear) + sik_sol = Qp_soluble_siksek_large_p(a, b, c, d, e, + p, f1, linear) fmpz_poly_clear(f1) fmpz_poly_clear(linear) else: sik_sol = bsd_sol return sik_sol -def test_qpls(a,b,c,d,e,p): + +def test_qpls(a, b, c, d, e, p): """ Testing function for Qp_soluble. @@ -863,10 +919,15 @@ def test_qpls(a,b,c,d,e,p): sage: tq(1,2,3,4,5,7) 1 """ - cdef Integer A,B,C,D,E,P - cdef int i, result - cdef mpz_t aa,bb,cc,dd,ee,pp - A=Integer(a); B=Integer(b); C=Integer(c); D=Integer(d); E=Integer(e); P=Integer(p) + cdef Integer A, B, C, D, E, P + cdef int result + cdef mpz_t aa, bb, cc, dd, ee, pp + A = Integer(a) + B = Integer(b) + C = Integer(c) + D = Integer(d) + E = Integer(e) + P = Integer(p) mpz_init_set(aa, A.value) mpz_init_set(bb, B.value) mpz_init_set(cc, C.value) @@ -882,24 +943,33 @@ def test_qpls(a,b,c,d,e,p): mpz_clear(pp) return result + cdef int everywhere_locally_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e) except -1: """ Returns whether the quartic has local solutions at all primes p. """ - cdef Integer A,B,C,D,E,Delta,p + cdef Integer A, B, C, D, E, Delta,p cdef mpz_t mpz_2 - A=Integer(0); B=Integer(0); C=Integer(0); D=Integer(0); E=Integer(0) - mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e) + A = Integer(0) + B = Integer(0) + C = Integer(0) + D = Integer(0) + E = Integer(0) + mpz_set(A.value, a) + mpz_set(B.value, b) + mpz_set(C.value, c) + mpz_set(D.value, d) + mpz_set(E.value, e) f = (((A*x_ZZ + B)*x_ZZ + C)*x_ZZ + D)*x_ZZ + E # RR soluble: - if mpz_sgn(a)!=1: + if mpz_sgn(a) != 1: if not real_roots(f): return 0 # Q2 soluble: mpz_init_set_ui(mpz_2, 2) - if not Qp_soluble(a,b,c,d,e,mpz_2): + if not Qp_soluble(a, b, c, d, e, mpz_2): mpz_clear(mpz_2) return 0 mpz_clear(mpz_2) @@ -907,12 +977,15 @@ cdef int everywhere_locally_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e) # Odd finite primes Delta = f.discriminant() for p in prime_divisors(Delta): - if p == 2: continue - if not Qp_soluble(a,b,c,d,e,p.value): return 0 + if p == 2: + continue + if not Qp_soluble(a, b, c, d, e, p.value): + return 0 return 1 -def test_els(a,b,c,d,e): + +def test_els(a, b, c, d, e): """ Doctest function for cdef int everywhere_locally_soluble(mpz_t, mpz_t, mpz_t, mpz_t, mpz_t). @@ -928,10 +1001,15 @@ def test_els(a,b,c,d,e): ....: except ValueError: ....: continue """ - cdef Integer A,B,C,D,E,Delta - A=Integer(a); B=Integer(b); C=Integer(c); D=Integer(d); E=Integer(e) + cdef Integer A, B, C, D, E + A = Integer(a) + B = Integer(b) + C = Integer(c) + D = Integer(d) + E = Integer(e) return everywhere_locally_soluble(A.value, B.value, C.value, D.value, E.value) + cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len, int global_limit_small, int global_limit_large, int verbosity, bint selmer_only, mpz_t n1, mpz_t n2) except -1: @@ -955,7 +1033,6 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len mpz_clear(c_sq_mpz) mpz_clear(d_prime_mpz) - # Set up coefficient array, and static variables cdef mpz_t *coeffs = <mpz_t *> sig_malloc(5 * sizeof(mpz_t)) for i in range(5): @@ -991,7 +1068,8 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len if mpz_tstbit(j, i): mpz_mul(coeffs[4], coeffs[4], p_div_d_mpz[i]) if verbosity > 3: - a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4]) + a_Int = Integer(0) + mpz_set(a_Int.value, coeffs[4]) print('\nSquarefree divisor:', a_Int) mpz_divexact(coeffs[0], d_mpz, coeffs[4]) found_global_points = 0 @@ -1001,10 +1079,13 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len found_global_points = ratpoints_mpz_exists_only(coeffs, 4, global_limit_small) if found_global_points: if verbosity > 2: - a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4]) - c_Int = Integer(0); mpz_set(c_Int.value, coeffs[2]) - e_Int = Integer(0); mpz_set(e_Int.value, coeffs[0]) - print('Found small global point, quartic (%d,%d,%d,%d,%d)'%(a_Int,0,c_Int,0,e_Int)) + a_Int = Integer(0) + mpz_set(a_Int.value, coeffs[4]) + c_Int = Integer(0) + mpz_set(c_Int.value, coeffs[2]) + e_Int = Integer(0) + mpz_set(e_Int.value, coeffs[0]) + print('Found small global point, quartic (%d,%d,%d,%d,%d)' % (a_Int, 0, c_Int, 0, e_Int)) mpz_add_ui(n1, n1, 1) mpz_add_ui(n2, n2, 1) if verbose: @@ -1018,10 +1099,13 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len break if els: if verbosity > 2: - a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4]) - c_Int = Integer(0); mpz_set(c_Int.value, coeffs[2]) - e_Int = Integer(0); mpz_set(e_Int.value, coeffs[0]) - print('ELS without small global points, quartic (%d,%d,%d,%d,%d)'%(a_Int,0,c_Int,0,e_Int)) + a_Int = Integer(0) + mpz_set(a_Int.value, coeffs[4]) + c_Int = Integer(0) + mpz_set(c_Int.value, coeffs[2]) + e_Int = Integer(0) + mpz_set(e_Int.value, coeffs[0]) + print('ELS without small global points, quartic (%d,%d,%d,%d,%d)' % (a_Int, 0, c_Int, 0, e_Int)) mpz_add_ui(n2, n2, 1) if not selmer_only: if verbose: @@ -1044,11 +1128,12 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len sig_free(coeffs) return 0 + def two_descent_by_two_isogeny(E, - int global_limit_small=10, - int global_limit_large=10000, - int verbosity=0, - bint selmer_only=0, bint proof=1): + int global_limit_small=10, + int global_limit_large=10000, + int verbosity=0, + bint selmer_only=0, bint proof=1): """ Given an elliptic curve E with a two-isogeny phi : E --> E' and dual isogeny phi', runs a two-isogeny descent on E, returning n1, n2, n1' and n2'. Here @@ -1066,14 +1151,16 @@ def two_descent_by_two_isogeny(E, sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E) sage: log(n1,2) + log(n1_prime,2) - 2 # the rank 1 + + sage: # needs sage.symbolic sage: x,y = var('x,y') sage: E = EllipticCurve(y^2 == x^3 + x^2 - 25*x + 39) sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E) - sage: log(n1,2) + log(n1_prime,2) - 2 # the rank + sage: log(n1,2) + log(n1_prime,2) - 2 # the rank 2 sage: E = EllipticCurve(y^2 + x*y + y == x^3 - 131*x + 558) sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E) - sage: log(n1,2) + log(n1_prime,2) - 2 # the rank + sage: log(n1,2) + log(n1_prime,2) - 2 # the rank 3 Using the verbosity option:: @@ -1127,7 +1214,7 @@ def two_descent_by_two_isogeny(E, cdef Integer a1, a2, a3, a4, a6, s2, s4, s6 cdef Integer c, d, x0 cdef list x_list - assert E.torsion_order()%2==0, 'Need rational two-torsion for isogeny descent.' + assert E.torsion_order() % 2 == 0, 'Need rational two-torsion for isogeny descent.' if verbosity > 0: print('\n2-isogeny') if verbosity > 1: @@ -1137,21 +1224,30 @@ def two_descent_by_two_isogeny(E, a3 = Integer(E.a3()) a4 = Integer(E.a4()) a6 = Integer(E.a6()) - if a1==0 and a3==0: - s2=a2; s4=a4; s6=a6 + if a1 == 0 == a3: + s2 = a2 + s4 = a4 + s6 = a6 else: - s2=a1*a1+4*a2; s4=8*(a1*a3+2*a4); s6=16*(a3*a3+4*a6) + s2 = a1*a1+4*a2 + s4 = 8*(a1*a3+2*a4) + s6 = 16*(a3*a3+4*a6) f = ((x_ZZ + s2)*x_ZZ + s4)*x_ZZ + s6 - x_list = f.roots() # over ZZ -- use FLINT directly? + x_list = f.roots() # over ZZ -- use FLINT directly? x0 = x_list[0][0] - c = 3*x0+s2; d = (c+s2)*x0+s4 + c = 3*x0+s2 + d = (c+s2)*x0+s4 return two_descent_by_two_isogeny_work(c, d, - global_limit_small, global_limit_large, verbosity, selmer_only, proof) + global_limit_small, + global_limit_large, verbosity, + selmer_only, proof) def two_descent_by_two_isogeny_work(Integer c, Integer d, - int global_limit_small=10, int global_limit_large=10000, - int verbosity=0, bint selmer_only=0, bint proof=1): + int global_limit_small=10, + int global_limit_large=10000, + int verbosity=0, bint selmer_only=0, + bint proof=1): """ Do all the work in doing a two-isogeny descent. @@ -1176,7 +1272,7 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, cdef unsigned long i, j, p, p_list_len cdef Integer P, n1, n2, n1_prime, n2_prime, c_prime, d_prime cdef object PO - cdef bint found, too_big, d_neg, d_prime_neg + cdef bint found, d_neg, d_prime_neg cdef n_factor_t fact cdef list primes mpz_init_set(c_mpz, c.value) @@ -1212,7 +1308,7 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, p = fact.p[i] found = 0 for j in range(p_list_len): - if mpz_cmp_ui(p_list_mpz[j], p)==0: + if mpz_cmp_ui(p_list_mpz[j], p) == 0: found = 1 break if not found: @@ -1230,7 +1326,8 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, if PO not in primes: primes.append(PO) P = Integer(2) - if P not in primes: primes.append(P) + if P not in primes: + primes.append(P) p_list_len = len(primes) p_list_mpz = <mpz_t *> sig_malloc(p_list_len * sizeof(mpz_t)) for i in range(p_list_len): @@ -1244,12 +1341,14 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, if verbosity > 1: c_prime = -2*c d_prime = c*c-4*d - print('\nnew curve is y^2 == x( x^2 + (%d)x + (%d) )'%(int(c),int(d))) + print('\nnew curve is y^2 == x( x^2 + (%d)x + (%d) )' % (int(c), int(d))) print('new isogenous curve is' + - ' y^2 == x( x^2 + (%d)x + (%d) )'%(int(c_prime),int(d_prime))) + ' y^2 == x( x^2 + (%d)x + (%d) )' % (int(c_prime), int(d_prime))) - n1 = Integer(0); n2 = Integer(0) - n1_prime = Integer(0); n2_prime = Integer(0) + n1 = Integer(0) + n2 = Integer(0) + n1_prime = Integer(0) + n2_prime = Integer(0) count(c.value, d.value, p_list_mpz, p_list_len, global_limit_small, global_limit_large, verbosity, selmer_only, n1.value, n2.value) @@ -1303,7 +1402,7 @@ cdef bint ratpoints_mpz_exists_only(mpz_t *coeffs, long degree, long H) except - # PARI checks only for affine points, so we manually check for # points at infinity (of the smooth model) cdef int r - if degree % 2 == 1 or Z_issquare(gel(pol, degree+2)): + if degree % 2 or Z_issquare(gel(pol, degree+2)): r = 1 else: R = hyperellratpoints(pol, stoi(H), 1) diff --git a/src/sage/schemes/elliptic_curves/ec_database.py b/src/sage/schemes/elliptic_curves/ec_database.py index 4c221715432..043c287ec7e 100644 --- a/src/sage/schemes/elliptic_curves/ec_database.py +++ b/src/sage/schemes/elliptic_curves/ec_database.py @@ -58,10 +58,12 @@ which are not included in the tables. AUTHORS: + - William Stein (2007-10-07): initial version + - Simon Spicer (2014-10-24): Added examples of more high-rank curves -See also the functions cremona_curves() and cremona_optimal_curves() +See also the functions :func:`cremona_curves` and :func:`cremona_optimal_curves` which enable easy looping through the Cremona elliptic curve database. """ @@ -125,12 +127,13 @@ def rank(self, rank, tors=0, n=10, labels=False): sage: L[0].cremona_label() Traceback (most recent call last): ... - LookupError: Cremona database does not contain entry for Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 2582*x + 48720 over Rational Field + LookupError: Cremona database does not contain entry for Elliptic Curve + defined by y^2 + x*y = x^3 + x^2 - 2582*x + 48720 over Rational Field sage: elliptic_curves.rank(6, n=3, labels=True) [] """ from sage.env import ELLCURVE_DATA_DIR - data = os.path.join(ELLCURVE_DATA_DIR, 'rank%s'%rank) + data = os.path.join(ELLCURVE_DATA_DIR, 'rank%s' % rank) try: f = open(data) except IOError: @@ -148,7 +151,7 @@ def rank(self, rank, tors=0, n=10, labels=False): # NOTE: only change this bound below after checking/fixing # the Cremona labels in the elliptic_curves package! if N <= 400000: - label = '%s%s%s'%(N, iso, num) + label = '%s%s%s' % (N, iso, num) else: label = None diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 68194f600c2..6195ec76a5e 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -14,12 +14,13 @@ the following example:: sage: k = GF(11) - sage: E = EllipticCurve(k,[1,1]) + sage: E = EllipticCurve(k, [1,1]) sage: Q = E(6,5) sage: phi = E.isogeny(Q) sage: phi - Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x + 1 over - Finite Field of size 11 to Elliptic Curve defined by y^2 = x^3 + 7*x + 8 + Isogeny of degree 7 + from Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 11 + to Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 11 sage: P = E(4,5) sage: phi(P) @@ -27,9 +28,10 @@ sage: phi.codomain() Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 11 sage: phi.rational_maps() - ((x^7 + 4*x^6 - 3*x^5 - 2*x^4 - 3*x^3 + 3*x^2 + x - 2)/(x^6 + 4*x^5 - 4*x^4 - - 5*x^3 + 5*x^2), (x^9*y - 5*x^8*y - x^7*y + x^5*y - x^4*y - 5*x^3*y - - 5*x^2*y - 2*x*y - 5*y)/(x^9 - 5*x^8 + 4*x^6 - 3*x^4 + 2*x^3)) + ((x^7 + 4*x^6 - 3*x^5 - 2*x^4 + - 3*x^3 + 3*x^2 + x - 2)/(x^6 + 4*x^5 - 4*x^4 - 5*x^3 + 5*x^2), + (x^9*y - 5*x^8*y - x^7*y + x^5*y - x^4*y + - 5*x^3*y - 5*x^2*y - 2*x*y - 5*y)/(x^9 - 5*x^8 + 4*x^6 - 3*x^4 + 2*x^3)) The methods directly accessible from an elliptic curve ``E`` over a field are @@ -86,10 +88,10 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer from sage.rings.laurent_series_ring import LaurentSeriesRing -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.fraction_field import FractionField -from sage.schemes.elliptic_curves.all import EllipticCurve +from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.schemes.elliptic_curves.ell_generic import is_EllipticCurve from sage.schemes.elliptic_curves.weierstrass_morphism \ @@ -130,7 +132,7 @@ def _isogeny_determine_algorithm(E, kernel): We can construct the same isogeny from a kernel polynomial:: - sage: phi = EllipticCurveIsogeny(E, x+3) # indirect doctest + sage: phi = EllipticCurveIsogeny(E, x + 3) # indirect doctest or from a list of coefficients of a kernel polynomial:: @@ -146,7 +148,7 @@ def _isogeny_determine_algorithm(E, kernel): the third case it is Vรฉlu:: sage: from sage.schemes.elliptic_curves.ell_curve_isogeny import _isogeny_determine_algorithm - sage: _isogeny_determine_algorithm(E, x+3) + sage: _isogeny_determine_algorithm(E, x + 3) 'kohel' sage: _isogeny_determine_algorithm(E, [3, 1]) 'kohel' @@ -159,7 +161,7 @@ def _isogeny_determine_algorithm(E, kernel): kernel = [kernel] kernel_is_list = True - if is_Polynomial(kernel) or (kernel_is_list and kernel[0] in E.base_ring()): + if isinstance(kernel, Polynomial) or (kernel_is_list and kernel[0] in E.base_ring()): return "kohel" if kernel_is_list and kernel[0] in E: @@ -169,10 +171,7 @@ def _isogeny_determine_algorithm(E, kernel): raise ValueError("invalid parameters to EllipticCurveIsogeny constructor") -from sage.misc.superseded import deprecated_function_alias -isogeny_determine_algorithm = deprecated_function_alias(33619, _isogeny_determine_algorithm) - -def isogeny_codomain_from_kernel(E, kernel, degree=None): +def isogeny_codomain_from_kernel(E, kernel): r""" Compute the isogeny codomain given a kernel. @@ -195,34 +194,25 @@ def isogeny_codomain_from_kernel(E, kernel, degree=None): sage: E = EllipticCurve(GF(7), [1,0,1,0,1]) sage: R.<x> = GF(7)[] sage: isogeny_codomain_from_kernel(E, [4,1]) - Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + 6 over Finite Field of size 7 - sage: EllipticCurveIsogeny(E, [4,1]).codomain() == isogeny_codomain_from_kernel(E, [4,1]) + Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + 6 + over Finite Field of size 7 + sage: (EllipticCurveIsogeny(E, [4,1]).codomain() + ....: == isogeny_codomain_from_kernel(E, [4,1])) True sage: isogeny_codomain_from_kernel(E, x^3 + x^2 + 4*x + 3) - Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + 6 over Finite Field of size 7 + Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + 6 + over Finite Field of size 7 sage: isogeny_codomain_from_kernel(E, x^3 + 2*x^2 + 4*x + 3) - Elliptic Curve defined by y^2 + x*y + y = x^3 + 5*x + 2 over Finite Field of size 7 + Elliptic Curve defined by y^2 + x*y + y = x^3 + 5*x + 2 + over Finite Field of size 7 + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(19), [1,2,3,4,5]) sage: kernel_list = [E((15,10)), E((10,3)), E((6,5))] sage: isogeny_codomain_from_kernel(E, kernel_list) - Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 3*x + 15 over Finite Field of size 19 - - TESTS: - - Test deprecation warning for obsolete argument:: - - sage: isogeny_codomain_from_kernel(E, kernel_list, degree=4) - doctest:warning - ... - DeprecationWarning: The "degree" argument to isogeny_codomain_from_kernel() does nothing and will be removed. - ... - Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 3*x + 15 over Finite Field of size 19 + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 3*x + 15 + over Finite Field of size 19 """ - if degree is not None: - from sage.misc.superseded import deprecation - deprecation(33619, 'The "degree" argument to isogeny_codomain_from_kernel() does nothing and will be removed.') - algorithm = _isogeny_determine_algorithm(E, kernel) if algorithm == 'velu': @@ -260,7 +250,8 @@ def compute_codomain_formula(E, v, w): sage: E = EllipticCurve(GF(19), [1,2,3,4,5]) sage: phi = EllipticCurveIsogeny(E, E((1,2)) ) sage: phi.codomain() - Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 9*x + 13 over Finite Field of size 19 + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 9*x + 13 + over Finite Field of size 19 sage: from sage.schemes.elliptic_curves.ell_curve_isogeny import compute_codomain_formula sage: v = phi._EllipticCurveIsogeny__v sage: w = phi._EllipticCurveIsogeny__w @@ -295,7 +286,11 @@ def compute_vw_kohel_even_deg1(x0, y0, a1, a2, a4): sage: E = EllipticCurve(GF(19), [1,2,3,4,5]) sage: phi = EllipticCurveIsogeny(E, [9,1]); phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 19 to Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 9*x + 8 over Finite Field of size 19 + Isogeny of degree 2 + from Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 + over Finite Field of size 19 + to Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 9*x + 8 + over Finite Field of size 19 sage: from sage.schemes.elliptic_curves.ell_curve_isogeny import compute_vw_kohel_even_deg1 sage: a1,a2,a3,a4,a6 = E.a_invariants() sage: x0 = -9 @@ -330,7 +325,11 @@ def compute_vw_kohel_even_deg3(b2, b4, s1, s2, s3): sage: E = EllipticCurve(GF(19), [1,2,3,4,5]) sage: R.<x> = GF(19)[] sage: phi = EllipticCurveIsogeny(E, x^3 + 7*x^2 + 15*x + 12); phi - Isogeny of degree 4 from Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 19 to Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 3*x + 15 over Finite Field of size 19 + Isogeny of degree 4 + from Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 + over Finite Field of size 19 + to Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 3*x + 15 + over Finite Field of size 19 sage: from sage.schemes.elliptic_curves.ell_curve_isogeny import compute_vw_kohel_even_deg3 sage: b2,b4 = E.b2(), E.b4() sage: s1, s2, s3 = -7, 15, -12 @@ -367,7 +366,11 @@ def compute_vw_kohel_odd(b2, b4, b6, s1, s2, s3, n): sage: E = EllipticCurve(GF(19), [18,17,16,15,14]) sage: R.<x> = GF(19)[] sage: phi = EllipticCurveIsogeny(E, x^3 + 14*x^2 + 3*x + 11); phi - Isogeny of degree 7 from Elliptic Curve defined by y^2 + 18*x*y + 16*y = x^3 + 17*x^2 + 15*x + 14 over Finite Field of size 19 to Elliptic Curve defined by y^2 + 18*x*y + 16*y = x^3 + 17*x^2 + 18*x + 18 over Finite Field of size 19 + Isogeny of degree 7 + from Elliptic Curve defined by y^2 + 18*x*y + 16*y = x^3 + 17*x^2 + 15*x + 14 + over Finite Field of size 19 + to Elliptic Curve defined by y^2 + 18*x*y + 16*y = x^3 + 17*x^2 + 18*x + 18 + over Finite Field of size 19 sage: from sage.schemes.elliptic_curves.ell_curve_isogeny import compute_vw_kohel_odd sage: b2,b4,b6 = E.b2(), E.b4(), E.b6() sage: s1,s2,s3 = -14,3,-11 @@ -403,20 +406,23 @@ def compute_codomain_kohel(E, kernel): sage: phi.codomain() == isogeny_codomain_from_kernel(E, [9,1]) True sage: compute_codomain_kohel(E, [9,1]) - Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 9*x + 8 over Finite Field of size 19 + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 9*x + 8 + over Finite Field of size 19 sage: R.<x> = GF(19)[] sage: E = EllipticCurve(GF(19), [18,17,16,15,14]) sage: phi = EllipticCurveIsogeny(E, x^3 + 14*x^2 + 3*x + 11) sage: phi.codomain() == isogeny_codomain_from_kernel(E, x^3 + 14*x^2 + 3*x + 11) True sage: compute_codomain_kohel(E, x^3 + 14*x^2 + 3*x + 11) - Elliptic Curve defined by y^2 + 18*x*y + 16*y = x^3 + 17*x^2 + 18*x + 18 over Finite Field of size 19 + Elliptic Curve defined by y^2 + 18*x*y + 16*y = x^3 + 17*x^2 + 18*x + 18 + over Finite Field of size 19 sage: E = EllipticCurve(GF(19), [1,2,3,4,5]) sage: phi = EllipticCurveIsogeny(E, x^3 + 7*x^2 + 15*x + 12) sage: isogeny_codomain_from_kernel(E, x^3 + 7*x^2 + 15*x + 12) == phi.codomain() True sage: compute_codomain_kohel(E, x^3 + 7*x^2 + 15*x + 12) - Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 3*x + 15 over Finite Field of size 19 + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 3*x + 15 + over Finite Field of size 19 ALGORITHM: @@ -459,13 +465,13 @@ def compute_codomain_kohel(E, kernel): v, w = compute_vw_kohel_even_deg1(x0, y0, a1, a2, a4) - elif n == 3: # psi_2tor is the full 2-division polynomial + elif n == 3: # psi_2tor is the full 2-division polynomial b2, b4, _, _ = E.b_invariants() - s1 = -psi_2tor[n-1] - s2 = psi_2tor[n-2] - s3 = -psi_2tor[n-3] + s1 = -psi_2tor[n - 1] + s2 = psi_2tor[n - 2] + s3 = -psi_2tor[n - 3] v, w = compute_vw_kohel_even_deg3(b2, b4, s1, s2, s3) @@ -475,9 +481,9 @@ def compute_codomain_kohel(E, kernel): b2, b4, b6, _ = E.b_invariants() - s1 = -psi[n-1] if n >= 1 else 0 - s2 = psi[n-2] if n >= 2 else 0 - s3 = -psi[n-3] if n >= 3 else 0 + s1 = -psi[n - 1] if n >= 1 else 0 + s2 = psi[n - 2] if n >= 2 else 0 + s3 = -psi[n - 3] if n >= 3 else 0 # initializing these allows us to calculate E2. v, w = compute_vw_kohel_odd(b2, b4, b6, s1, s2, s3, n) @@ -511,7 +517,7 @@ def two_torsion_part(E, psi): sage: isogeny_codomain_from_kernel(E, x + 13) == phi.codomain() True sage: from sage.schemes.elliptic_curves.ell_curve_isogeny import two_torsion_part - sage: two_torsion_part(E, x+13) + sage: two_torsion_part(E, x + 13) x + 13 """ x = psi.parent().gen() # NB psi is univariate but could be constant @@ -590,22 +596,29 @@ class EllipticCurveIsogeny(EllipticCurveHom): sage: E = EllipticCurve(GF(7), [0,0,0,1,0]) sage: phi = EllipticCurveIsogeny(E, E((0,0)) ); phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 3*x over Finite Field of size 7 + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 3*x over Finite Field of size 7 sage: phi.degree() == 2 True sage: phi.kernel_polynomial() x sage: phi.rational_maps() ((x^2 + 1)/x, (x^2*y - y)/x^2) - sage: phi == loads(dumps(phi)) # known bug + sage: phi == loads(dumps(phi)) # known bug True A more complicated example of a characteristic-2 field:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(2^4,'alpha'), [0,0,1,0,1]) sage: P = E((1,1)) sage: phi_v = EllipticCurveIsogeny(E, P); phi_v - Isogeny of degree 3 from Elliptic Curve defined by y^2 + y = x^3 + 1 over Finite Field in alpha of size 2^4 to Elliptic Curve defined by y^2 + y = x^3 over Finite Field in alpha of size 2^4 + Isogeny of degree 3 + from Elliptic Curve defined by y^2 + y = x^3 + 1 + over Finite Field in alpha of size 2^4 + to Elliptic Curve defined by y^2 + y = x^3 + over Finite Field in alpha of size 2^4 sage: phi_ker_poly = phi_v.kernel_polynomial() sage: phi_ker_poly x + 1 @@ -633,10 +646,15 @@ class EllipticCurveIsogeny(EllipticCurveHom): We can create an isogeny whose kernel equals the full 2-torsion:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF((3,2)), [0,0,0,1,1]) sage: ker_poly = E.division_polynomial(2) sage: phi = EllipticCurveIsogeny(E, ker_poly); phi - Isogeny of degree 4 from Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in z2 of size 3^2 to Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in z2 of size 3^2 + Isogeny of degree 4 + from Elliptic Curve defined by y^2 = x^3 + x + 1 + over Finite Field in z2 of size 3^2 + to Elliptic Curve defined by y^2 = x^3 + x + 1 + over Finite Field in z2 of size 3^2 sage: P1,P2,P3 = filter(bool, E(0).division_points(2)) sage: phi(P1) (0 : 1 : 0) @@ -663,7 +681,11 @@ class EllipticCurveIsogeny(EllipticCurveHom): sage: E = EllipticCurve(GF(31), [23, 1, 22, 7, 18]) sage: phi_k = EllipticCurveIsogeny(E, [1]); phi_k - Isogeny of degree 1 from Elliptic Curve defined by y^2 + 23*x*y + 22*y = x^3 + x^2 + 7*x + 18 over Finite Field of size 31 to Elliptic Curve defined by y^2 + 23*x*y + 22*y = x^3 + x^2 + 7*x + 18 over Finite Field of size 31 + Isogeny of degree 1 + from Elliptic Curve defined by y^2 + 23*x*y + 22*y = x^3 + x^2 + 7*x + 18 + over Finite Field of size 31 + to Elliptic Curve defined by y^2 + 23*x*y + 22*y = x^3 + x^2 + 7*x + 18 + over Finite Field of size 31 sage: phi_k.degree() 1 sage: phi_k.rational_maps() @@ -680,7 +702,9 @@ class EllipticCurveIsogeny(EllipticCurveHom): sage: E = EllipticCurve(QQ, [0,0,0,3,4]) sage: P_list = E.torsion_points() sage: phi = EllipticCurveIsogeny(E, P_list); phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 3*x + 4 over Rational Field to Elliptic Curve defined by y^2 = x^3 - 27*x + 46 over Rational Field + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 3*x + 4 over Rational Field + to Elliptic Curve defined by y^2 = x^3 - 27*x + 46 over Rational Field sage: P = E((0,2)) sage: phi(P) (6 : -10 : 1) @@ -688,7 +712,9 @@ class EllipticCurveIsogeny(EllipticCurveHom): sage: phi_ker_poly x + 1 sage: phi_k = EllipticCurveIsogeny(E, phi_ker_poly); phi_k - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 3*x + 4 over Rational Field to Elliptic Curve defined by y^2 = x^3 - 27*x + 46 over Rational Field + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 3*x + 4 over Rational Field + to Elliptic Curve defined by y^2 = x^3 - 27*x + 46 over Rational Field sage: phi_k(P) == phi(P) True sage: phi_k == phi @@ -703,14 +729,18 @@ class EllipticCurveIsogeny(EllipticCurveHom): sage: E = EllipticCurve('11a1') sage: P_list = E.torsion_points() sage: phi_v = EllipticCurveIsogeny(E, P_list); phi_v - Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field + Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field sage: P = E((16,-61)) sage: phi_v(P) (0 : 1 : 0) sage: ker_poly = phi_v.kernel_polynomial(); ker_poly x^2 - 21*x + 80 sage: phi_k = EllipticCurveIsogeny(E, ker_poly); phi_k - Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field + Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field sage: phi_k == phi_v True sage: phi_v(P) == phi_k(P) @@ -721,22 +751,31 @@ class EllipticCurveIsogeny(EllipticCurveHom): We can also do this same example over the number field defined by the irreducible two-torsion polynomial of `E`:: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('11a1') sage: P_list = E.torsion_points() + sage: x = polygen(ZZ, 'x') sage: K.<alpha> = NumberField(x^3 - 2* x^2 - 40*x - 158) sage: EK = E.change_ring(K) sage: P_list = [EK(P) for P in P_list] sage: phi_v = EllipticCurveIsogeny(EK, P_list); phi_v - Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in alpha with defining polynomial x^3 - 2*x^2 - 40*x - 158 to Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-7820)*x + (-263580) over Number Field in alpha with defining polynomial x^3 - 2*x^2 - 40*x - 158 + Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) + over Number Field in alpha with defining polynomial x^3 - 2*x^2 - 40*x - 158 + to Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-7820)*x + (-263580) + over Number Field in alpha with defining polynomial x^3 - 2*x^2 - 40*x - 158 sage: P = EK((alpha/2,-1/2)) sage: phi_v(P) (122/121*alpha^2 + 1633/242*alpha - 3920/121 : -1/2 : 1) sage: ker_poly = phi_v.kernel_polynomial() sage: ker_poly x^2 - 21*x + 80 - sage: phi_k = EllipticCurveIsogeny(EK, ker_poly) - sage: phi_k - Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in alpha with defining polynomial x^3 - 2*x^2 - 40*x - 158 to Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-7820)*x + (-263580) over Number Field in alpha with defining polynomial x^3 - 2*x^2 - 40*x - 158 + sage: phi_k = EllipticCurveIsogeny(EK, ker_poly); phi_k + Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) + over Number Field in alpha with defining polynomial x^3 - 2*x^2 - 40*x - 158 + to Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-7820)*x + (-263580) + over Number Field in alpha with defining polynomial x^3 - 2*x^2 - 40*x - 158 sage: phi_v == phi_k True sage: phi_k(P) == phi_v(P) @@ -756,9 +795,10 @@ class EllipticCurveIsogeny(EllipticCurveHom): sage: f = x^2 - 21*x + 80 sage: phi = E.isogeny(f) sage: E2 = phi.codomain() - sage: phi_s = EllipticCurveIsogeny(E, None, E2, 5) - sage: phi_s - Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field + sage: phi_s = EllipticCurveIsogeny(E, None, E2, 5); phi_s + Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field sage: phi_s == phi True sage: phi_s.rational_maps() == phi.rational_maps() @@ -779,14 +819,18 @@ class EllipticCurveIsogeny(EllipticCurveHom): ... ValueError: the two curves are not linked by a cyclic normalized isogeny of degree 5 sage: phihat = phi.dual(); phihat - Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 + over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: phihat.is_normalized() False Here an example of a construction of a endomorphisms with cyclic kernel on a CM-curve:: - sage: K.<i> = NumberField(x^2+1) + sage: # needs sage.rings.number_field + sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve(K, [1,0]) sage: RK.<X> = K[] sage: f = X^2 - 2/5*i + 1/5 @@ -796,7 +840,8 @@ class EllipticCurveIsogeny(EllipticCurveHom): sage: phi.codomain() == phi.domain() True sage: phi.rational_maps() - (((4/25*i + 3/25)*x^5 + (4/5*i - 2/5)*x^3 - x)/(x^4 + (-4/5*i + 2/5)*x^2 + (-4/25*i - 3/25)), ((11/125*i + 2/125)*x^6*y + (-23/125*i + 64/125)*x^4*y + (141/125*i + 162/125)*x^2*y + (3/25*i - 4/25)*y)/(x^6 + (-6/5*i + 3/5)*x^4 + (-12/25*i - 9/25)*x^2 + (2/125*i - 11/125))) + (((4/25*i + 3/25)*x^5 + (4/5*i - 2/5)*x^3 - x)/(x^4 + (-4/5*i + 2/5)*x^2 + (-4/25*i - 3/25)), + ((11/125*i + 2/125)*x^6*y + (-23/125*i + 64/125)*x^4*y + (141/125*i + 162/125)*x^2*y + (3/25*i - 4/25)*y)/(x^6 + (-6/5*i + 3/5)*x^4 + (-12/25*i - 9/25)*x^2 + (2/125*i - 11/125))) TESTS: @@ -820,7 +865,9 @@ class EllipticCurveIsogeny(EllipticCurveHom): sage: E = EllipticCurve(j=GF(7)(0)) sage: phi = E.isogeny([E(0), E((0,1)), E((0,-1))]); phi - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 + Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 sage: phi2 = phi * phi; phi2 Composite morphism of degree 9 = 3^2: From: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 @@ -828,12 +875,14 @@ class EllipticCurveIsogeny(EllipticCurveHom): Examples over relative number fields used not to work (see :trac:`16779`):: + sage: # long time, needs sage.rings.number_field sage: pol26 = hilbert_class_polynomial(-4*26) - sage: pol = NumberField(pol26,'a').optimized_representation()[0].polynomial() + sage: F = NumberField(pol26,'a') + sage: pol = F.optimized_representation()[0].polynomial() sage: K.<a> = NumberField(pol) sage: j = pol26.roots(K)[0][0] sage: E = EllipticCurve(j=j) - sage: L.<b> = K.extension(x^2+26) + sage: L.<b> = K.extension(x^2 + 26) sage: EL = E.change_ring(L) sage: iso2 = EL.isogenies_prime_degree(2); len(iso2) 1 @@ -846,16 +895,28 @@ class EllipticCurveIsogeny(EllipticCurveHom): sage: E = EllipticCurve([0,0,0,-t^2,0]) sage: isogs = E.isogenies_prime_degree(2) sage: isogs[0] - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + (-t^2)*x over Rational function field in t over Rational Field to Elliptic Curve defined by y^2 = x^3 + 4*t^2*x over Rational function field in t over Rational Field + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + (-t^2)*x + over Rational function field in t over Rational Field + to Elliptic Curve defined by y^2 = x^3 + 4*t^2*x + over Rational function field in t over Rational Field sage: isogs[0].rational_maps() ((x^2 - t^2)/x, (x^2*y + t^2*y)/x^2) sage: duals = [phi.dual() for phi in isogs] sage: duals[0] - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 4*t^2*x over Rational function field in t over Rational Field to Elliptic Curve defined by y^2 = x^3 + (-t^2)*x over Rational function field in t over Rational Field + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 4*t^2*x + over Rational function field in t over Rational Field + to Elliptic Curve defined by y^2 = x^3 + (-t^2)*x + over Rational function field in t over Rational Field sage: duals[0].rational_maps() ((1/4*x^2 + t^2)/x, (1/8*x^2*y + (-1/2*t^2)*y)/x^2) sage: duals[0] - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 4*t^2*x over Rational function field in t over Rational Field to Elliptic Curve defined by y^2 = x^3 + (-t^2)*x over Rational function field in t over Rational Field + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 4*t^2*x + over Rational function field in t over Rational Field + to Elliptic Curve defined by y^2 = x^3 + (-t^2)*x + over Rational function field in t over Rational Field """ #################### @@ -891,7 +952,7 @@ class EllipticCurveIsogeny(EllipticCurveHom): # __base_field = None __poly_ring = None # univariate in x over __base_field - __mpoly_ring = None # bivariate in x, y over __base_field + __mpoly_ring = None # __base_field[x][y], internal use only # # Rational Maps @@ -913,7 +974,6 @@ class EllipticCurveIsogeny(EllipticCurveHom): __inner_kernel_polynomial = None # the inner kernel polynomial (ignoring preisomorphism) - # # member variables common to Velu's formula # @@ -925,14 +985,12 @@ class EllipticCurveIsogeny(EllipticCurveHom): __v = None __w = None - # # member variables specific to Kohel's algorithm. # __psi = None # psi polynomial __phi = None # phi polynomial - __omega = None # omega polynomial - + __omega = None # omega polynomial, an element of k[x][y] # # Python Special Functions @@ -946,27 +1004,41 @@ def __init__(self, E, kernel, codomain=None, degree=None, model=None, check=True sage: E = EllipticCurve(GF(2), [0,0,1,0,1]) sage: phi = EllipticCurveIsogeny(E, [1,1]); phi - Isogeny of degree 3 from Elliptic Curve defined by y^2 + y = x^3 + 1 over Finite Field of size 2 to Elliptic Curve defined by y^2 + y = x^3 over Finite Field of size 2 + Isogeny of degree 3 + from Elliptic Curve defined by y^2 + y = x^3 + 1 over Finite Field of size 2 + to Elliptic Curve defined by y^2 + y = x^3 over Finite Field of size 2 sage: E = EllipticCurve(GF(31), [0,0,0,1,0]) sage: P = E((2,17)) sage: phi = EllipticCurveIsogeny(E, P); phi - Isogeny of degree 8 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 31 to Elliptic Curve defined by y^2 = x^3 + 10*x + 28 over Finite Field of size 31 + Isogeny of degree 8 + from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 31 + to Elliptic Curve defined by y^2 = x^3 + 10*x + 28 over Finite Field of size 31 sage: E = EllipticCurve('17a1') sage: phi = EllipticCurveIsogeny(E, [41/3, -55, -1, -1, 1]); phi - Isogeny of degree 9 from Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - x - 14 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 56*x - 10124 over Rational Field + Isogeny of degree 9 + from Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - x - 14 + over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 56*x - 10124 + over Rational Field sage: E = EllipticCurve('37a1') sage: triv = EllipticCurveIsogeny(E, E(0)); triv - Isogeny of degree 1 from Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + Isogeny of degree 1 + from Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field sage: triv.rational_maps() (x, y) sage: E = EllipticCurve('49a3') sage: R.<X> = QQ[] - sage: EllipticCurveIsogeny(E, X^3-13*X^2-58*X+503, check=False) - Isogeny of degree 7 from Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 107*x + 552 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 5252*x - 178837 over Rational Field + sage: EllipticCurveIsogeny(E, X^3 - 13*X^2 - 58*X + 503, check=False) + Isogeny of degree 7 + from Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 107*x + 552 + over Rational Field + to Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 5252*x - 178837 + over Rational Field """ if not is_EllipticCurve(E): raise ValueError("given E is not an elliptic curve") @@ -1039,8 +1111,8 @@ def _eval(self, P): sage: E = EllipticCurve([1,0]); E Elliptic Curve defined by y^2 = x^3 + x over Rational Field sage: phi = E.isogeny(E(0,0)) - sage: P = E.change_ring(QQbar).lift_x(QQbar.random_element()) - sage: phi._eval(P).curve() + sage: P = E.change_ring(QQbar).lift_x(QQbar.random_element()) # needs sage.rings.number_field + sage: phi._eval(P).curve() # needs sage.rings.number_field Elliptic Curve defined by y^2 = x^3 + (-4)*x over Algebraic Field :: @@ -1048,8 +1120,8 @@ def _eval(self, P): sage: E = EllipticCurve(j=Mod(0,419)) sage: K = next(filter(bool, E(0).division_points(5))) sage: psi = E.isogeny(K) - sage: Ps = E.change_ring(GF(419**2))(0).division_points(5) - sage: {psi._eval(P).curve() for P in Ps} + sage: Ps = E.change_ring(GF(419**2))(0).division_points(5) # needs sage.rings.number_field + sage: {psi._eval(P).curve() for P in Ps} # needs sage.rings.number_field {Elliptic Curve defined by y^2 = x^3 + 140*x + 214 over Finite Field in z2 of size 419^2} """ if self._domain.defining_polynomial()(*P): @@ -1117,8 +1189,10 @@ def _call_(self, P): Tests for :trac:`10888`:: - sage: K.<th> = NumberField(x^2+3) - sage: E = EllipticCurve(K,[7,0]) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<th> = NumberField(x^2 + 3) + sage: E = EllipticCurve(K, [7,0]) sage: phi = E.isogeny(E(0,0)) sage: P = E(-3,4*th) sage: phi(P) @@ -1140,9 +1214,10 @@ def _call_(self, P): Coercion works fine with :meth:`_call_` (added for :trac:`16238`):: - sage: K.<th> = NumberField(x^2+3) - sage: E = EllipticCurve(K,[7,0]) - sage: E2 = EllipticCurve(K,[5,0]) + sage: # needs sage.rings.number_field + sage: K.<th> = NumberField(x^2 + 3) + sage: E = EllipticCurve(K, [7,0]) + sage: E2 = EllipticCurve(K, [5,0]) sage: phi = E.isogeny(E(0)) sage: phi(E2(0)) (0 : 1 : 0) @@ -1151,10 +1226,13 @@ def _call_(self, P): sage: phi(E2(20,90)) Traceback (most recent call last): ... - TypeError: (20 : 90 : 1) fails to convert into the map's domain Elliptic Curve defined by y^2 = x^3 + 7*x over Number Field in th with defining polynomial x^2 + 3, but a `pushforward` method is not properly implemented + TypeError: (20 : 90 : 1) fails to convert into the map's domain + Elliptic Curve defined by y^2 = x^3 + 7*x over Number Field in th with defining polynomial x^2 + 3, + but a `pushforward` method is not properly implemented Check that copying the order over works:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(431), [1,0]) sage: P, = E.gens() sage: Q = 2^99*P; Q.order() @@ -1162,6 +1240,19 @@ def _call_(self, P): sage: phi = E.isogeny(3^99*P) sage: phi(Q)._order 27 + + Test for :trac:`35983`:: + + sage: E = EllipticCurve([1,0,0,-1,0]) + sage: P = E([1,0]) + sage: P.order() + +Infinity + sage: phi = E.isogenies_prime_degree(2)[0] + sage: Q = phi(P); Q + (0 : 1 : 1) + sage: Q.order() + +Infinity + """ if P.is_zero(): return self._codomain(0) @@ -1193,14 +1284,15 @@ def _call_(self, P): xP = self.__posti_ratl_maps[0](xP) Q = self._codomain(xP, yP) - if hasattr(P, '_order') and P._order.gcd(self._degree).is_one(): + if hasattr(P, '_order'): + if P.has_infinite_order() or P._order.gcd(self._degree).is_one(): + Q._order = P._order # TODO: For non-coprime degree, the order of the point - # gets reduced by a divisor of the degree when passing + # may get reduced by a divisor of the degree when passing # through the isogeny. We could run something along the # lines of order_from_multiple() to determine the new # order, but this probably shouldn't happen by default # as it'll be detrimental to performance in some cases. - Q._order = P._order return Q def __getitem__(self, i): @@ -1302,14 +1394,17 @@ def __neg__(self): sage: E = EllipticCurve(GF(17), [-2, 3, -5, 7, -11]) sage: R.<x> = GF(17)[] sage: f = x+6 - sage: phi = EllipticCurveIsogeny(E, f) - sage: phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 7*x + 6 over Finite Field of size 17 to Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 4*x + 8 over Finite Field of size 17 + sage: phi = EllipticCurveIsogeny(E, f); phi + Isogeny of degree 2 + from Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 7*x + 6 over Finite Field of size 17 + to Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 4*x + 8 over Finite Field of size 17 sage: phi.rational_maps() ((x^2 + 6*x + 4)/(x + 6), (x^2*y - 5*x*y + 8*x - 2*y)/(x^2 - 5*x + 2)) sage: negphi = -phi sage: negphi - Isogeny of degree 2 from Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 7*x + 6 over Finite Field of size 17 to Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 4*x + 8 over Finite Field of size 17 + Isogeny of degree 2 + from Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 7*x + 6 over Finite Field of size 17 + to Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 4*x + 8 over Finite Field of size 17 sage: negphi.rational_maps() ((x^2 + 6*x + 4)/(x + 6), (2*x^3 - x^2*y - 5*x^2 + 5*x*y - 4*x + 2*y + 7)/(x^2 - 5*x + 2)) @@ -1326,10 +1421,11 @@ def __neg__(self): sage: ymap1 == -ymap2 - E.a1()*xmap2 - E.a3() True + sage: # needs sage.rings.number_field sage: K.<a> = NumberField(x^2 + 1) sage: E = EllipticCurve(K, [0,0,0,1,0]) sage: R.<x> = K[] - sage: phi = EllipticCurveIsogeny(E, x-a) + sage: phi = EllipticCurveIsogeny(E, x - a) sage: phi.rational_maps() ((x^2 + (-a)*x - 2)/(x + (-a)), (x^2*y + (-2*a)*x*y + y)/(x^2 + (-2*a)*x - 1)) sage: negphi = -phi @@ -1378,14 +1474,13 @@ def _latex_(self): sage: E = EllipticCurve(GF(17), [0,0,0,1,-1]) sage: R.<X> = GF(17)[] - sage: phi = EllipticCurveIsogeny(E, X+11) + sage: phi = EllipticCurveIsogeny(E, X + 11) sage: phi._latex_() '\\left( \\frac{x^{2} + 11 x + 7}{x + 11} , \\frac{x^{2} y + 5 x y + 12 y}{x^{2} + 5 x + 2} \\right)' """ fx,fy = self.rational_maps() return fr'\left( {fx._latex_()} , {fy._latex_()} \right)' - ########################### # Private Common Functions ########################### @@ -1414,7 +1509,8 @@ def __clear_cached_values(self): sage: phi = EllipticCurveIsogeny(E, f) sage: old_ratl_maps = phi.rational_maps() sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: phi._set_post_isomorphism(WeierstrassIsomorphism(phi.codomain(), (-13,13,-13,13))) + sage: phi._set_post_isomorphism(WeierstrassIsomorphism(phi.codomain(), + ....: (-13,13,-13,13))) sage: old_ratl_maps == phi.rational_maps() False sage: phi._EllipticCurveIsogeny__clear_cached_values() @@ -1466,7 +1562,7 @@ def __init_algebraic_structs(self, E): sage: phi._EllipticCurveIsogeny__poly_ring Univariate Polynomial Ring in x over Finite Field of size 17 sage: phi._EllipticCurveIsogeny__mpoly_ring - Multivariate Polynomial Ring in x, y over Finite Field of size 17 + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Finite Field of size 17 Now, calling the initialization function does nothing more:: @@ -1478,7 +1574,7 @@ def __init_algebraic_structs(self, E): sage: phi._EllipticCurveIsogeny__poly_ring Univariate Polynomial Ring in x over Finite Field of size 17 sage: phi._EllipticCurveIsogeny__mpoly_ring - Multivariate Polynomial Ring in x, y over Finite Field of size 17 + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Finite Field of size 17 sage: E = EllipticCurve(QQ, [0,0,0,1,0]) sage: phi = EllipticCurveIsogeny(E, E((0,0))) @@ -1490,7 +1586,7 @@ def __init_algebraic_structs(self, E): sage: phi._EllipticCurveIsogeny__poly_ring Univariate Polynomial Ring in x over Rational Field sage: phi._EllipticCurveIsogeny__mpoly_ring - Multivariate Polynomial Ring in x, y over Rational Field + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field sage: F = GF(19); R.<x> = F[] sage: E = EllipticCurve(j=GF(19)(0)) @@ -1503,14 +1599,16 @@ def __init_algebraic_structs(self, E): sage: phi._EllipticCurveIsogeny__poly_ring Univariate Polynomial Ring in x over Finite Field of size 19 sage: phi._EllipticCurveIsogeny__mpoly_ring - Multivariate Polynomial Ring in x, y over Finite Field of size 19 + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Finite Field of size 19 """ self._domain = E self.__base_field = E.base_ring() self.__poly_ring = PolynomialRing(self.__base_field, ['x']) - self.__mpoly_ring = PolynomialRing(self.__base_field, ['x','y']) + self.__mpoly_ring = PolynomialRing(self.__poly_ring, ['y']) + # The fraction fields are implicitly part of the public API, being the parents + # of the rational maps. self.__xfield = FractionField(self.__poly_ring) - self.__xyfield = FractionField(self.__mpoly_ring) + self.__xyfield = FractionField(PolynomialRing(self.__base_field, ['x', 'y'])) def __compute_codomain(self): r""" @@ -1600,7 +1698,6 @@ def __initialize_rational_maps(self, precomputed_maps=None): self.__ratl_maps = self.__xfield(X_map), self.__xyfield(Y_map) - def __init_kernel_polynomial(self): r""" Private function that initializes the kernel polynomial (if @@ -1711,25 +1808,35 @@ def __setup_post_isomorphism(self, codomain, model): sage: E = EllipticCurve(j=GF(7)(1728)) sage: E2 = EllipticCurve(GF(7), [0,0,0,5,0]) sage: phi = EllipticCurveIsogeny(E, E((0,0)), E2); phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 7 + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 7 sage: E3 = EllipticCurve(GF(7), [0,0,0,6,0]) sage: phi._EllipticCurveIsogeny__setup_post_isomorphism(E3, None) sage: phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7 + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7 sage: EllipticCurveIsogeny(E, E(0,0), model='montgomery') - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + x^2 + x over Finite Field of size 7 + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + x^2 + x over Finite Field of size 7 sage: R.<x> = QQ[] sage: E = EllipticCurve(j=1728) sage: f = x^3 - x sage: phi = EllipticCurveIsogeny(E, f, model='minimal'); phi - Isogeny of degree 4 from Elliptic Curve defined by y^2 = x^3 - x over Rational Field to Elliptic Curve defined by y^2 = x^3 - x over Rational Field + Isogeny of degree 4 + from Elliptic Curve defined by y^2 = x^3 - x over Rational Field + to Elliptic Curve defined by y^2 = x^3 - x over Rational Field sage: phi = EllipticCurveIsogeny(E, f, model=None) sage: phi._EllipticCurveIsogeny__setup_post_isomorphism(None, 'minimal') sage: phi - Isogeny of degree 4 from Elliptic Curve defined by y^2 = x^3 - x over Rational Field to Elliptic Curve defined by y^2 = x^3 - x over Rational Field + Isogeny of degree 4 + from Elliptic Curve defined by y^2 = x^3 - x over Rational Field + to Elliptic Curve defined by y^2 = x^3 - x over Rational Field """ if model is codomain is None: return @@ -1772,21 +1879,28 @@ def __init_from_kernel_list(self, kernel_gens): sage: E = EllipticCurve(GF(7), [0,0,0,-1,0]) sage: phi = EllipticCurveIsogeny(E, E((0,0))); phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 4*x over Finite Field of size 7 + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 4*x over Finite Field of size 7 sage: phi._EllipticCurveIsogeny__init_from_kernel_list([E(0), E((0,0))]) The following example demonstrates the necessity of avoiding any calls to P.order(), since such calls involve factoring the group order which could take a long time. :: + sage: # needs sage.rings.finite_rings sage: p = 12 * next_prime(2^180) * next_prime(2^194) - 1 sage: F = FiniteField(p, proof=False) sage: E = EllipticCurve([F(1), F(0)]) sage: P = E(0).division_points(3)[1] sage: EllipticCurveIsogeny(E, P) - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 461742260113997803268895001173557974278278194575766957660028841364655249961609425998827452443620996655395008156411 to Elliptic Curve defined by y^2 = x^3 + 80816485163488178037199320944019099858815874115367810482828676054000067654558381377552245721755005198633191074893*x + 301497584865165444049833326660609767433467459033532853758006118022998267706948164646650354324860226263546558337993 over Finite Field of size 461742260113997803268895001173557974278278194575766957660028841364655249961609425998827452443620996655395008156411 + Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + x + over Finite Field of size 461742260113997803268895001173557974278278194575766957660028841364655249961609425998827452443620996655395008156411 + to Elliptic Curve defined by y^2 = x^3 + 80816485163488178037199320944019099858815874115367810482828676054000067654558381377552245721755005198633191074893*x + 301497584865165444049833326660609767433467459033532853758006118022998267706948164646650354324860226263546558337993 + over Finite Field of size 461742260113997803268895001173557974278278194575766957660028841364655249961609425998827452443620996655395008156411 """ - if self.__check : + if self.__check: for P in kernel_gens: if not P.has_finite_order(): raise ValueError("given kernel contains point of infinite order") @@ -1829,7 +1943,9 @@ def __sort_kernel_list(self): sage: E = EllipticCurve(GF(7), [0,0,0,-1,0]) sage: P = E((4,2)) sage: phi = EllipticCurveIsogeny(E, P); phi - Isogeny of degree 4 from Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 7 + Isogeny of degree 4 + from Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 7 sage: phi._EllipticCurveIsogeny__sort_kernel_list() """ a1, a2, a3, a4, _ = self._domain.a_invariants() @@ -1990,6 +2106,7 @@ def __compute_via_velu(self, xP, yP): Check for :trac:`33214`:: + sage: # needs sage.rings.finite_rings sage: z2 = GF(71^2).gen() sage: E = EllipticCurve(GF(71^2), [5,5]) sage: phi = E.isogeny(E.lift_x(0)) @@ -2003,6 +2120,7 @@ def __compute_via_velu(self, xP, yP): The rational maps are also computed via this code path; check that they are plausible (this failed prior to :trac:`33214`):: + sage: # needs sage.rings.finite_rings sage: fx,fy = phi.rational_maps() # indirect doctest sage: R.<x,y> = GF(71^2)[] sage: E0, E2 = phi.domain(), phi.codomain() @@ -2046,7 +2164,7 @@ def __initialize_rational_maps_via_velu(self): ((x^4 + 5*x^3 + x^2 + 4*x)/(x^3 + 5*x^2 + 3*x + 5), (x^5*y - 2*x^3*y - x^2*y - 2*x*y + 2*y)/(x^5 + 3*x^3 + 3*x^2 + x - 1)) """ x = self.__poly_ring.gen() - y = self.__mpoly_ring.gen(1) + y = self.__xyfield.gen(1) return self.__compute_via_velu(x,y) def __init_kernel_polynomial_velu(self): @@ -2094,13 +2212,17 @@ def __init_from_kernel_polynomial(self, kernel_polynomial): sage: R.<x> = GF(7)[] sage: E = EllipticCurve(GF(7), [0,0,0,-1,0]) sage: phi = EllipticCurveIsogeny(E, x);phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 4*x over Finite Field of size 7 + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 4*x over Finite Field of size 7 sage: phi._EllipticCurveIsogeny__init_from_kernel_polynomial(x) sage: E = EllipticCurve(GF(7), [0,-1,0,0,1]) sage: phi = EllipticCurveIsogeny(E, x+6, degree=3); phi - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 1 over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 4*x + 2 over Finite Field of size 7 + Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 1 over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 4*x + 2 over Finite Field of size 7 sage: phi._EllipticCurveIsogeny__init_from_kernel_polynomial(x+6) """ @@ -2134,7 +2256,6 @@ def __init_from_kernel_polynomial(self, kernel_polynomial): phi, omega, v, w, _, d = self.__init_odd_kernel_polynomial(E, psi) - # # Set up the necessary instance variables # @@ -2192,34 +2313,40 @@ def __init_even_kernel_polynomial(self, E, psi_G): sage: R.<x> = GF(7)[] sage: E = EllipticCurve(GF(7), [-1,0]) sage: phi = EllipticCurveIsogeny(E, x); phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 4*x over Finite Field of size 7 + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 4*x over Finite Field of size 7 sage: from sage.schemes.elliptic_curves.ell_curve_isogeny import two_torsion_part sage: psig = two_torsion_part(E,x) sage: phi._EllipticCurveIsogeny__init_even_kernel_polynomial(E,psig) - (x^3 + 6*x, x^3*y + x*y, 6, 0, 1, 2) + (x^3 + 6*x, (x^3 + x)*y, 6, 0, 1, 2) - sage: F = GF(2^4, 'alpha'); R.<x> = F[] - sage: E = EllipticCurve(F, [1,1,0,1,0]) - sage: phi = EllipticCurveIsogeny(E, x); phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + x over Finite Field in alpha of size 2^4 to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 1 over Finite Field in alpha of size 2^4 + sage: F = GF(2^4, 'alpha'); R.<x> = F[] # needs sage.rings.finite_rings + sage: E = EllipticCurve(F, [1,1,0,1,0]) # needs sage.rings.finite_rings + sage: phi = EllipticCurveIsogeny(E, x); phi # needs sage.rings.finite_rings + Isogeny of degree 2 + from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + x over Finite Field in alpha of size 2^4 + to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 1 over Finite Field in alpha of size 2^4 - sage: psig = two_torsion_part(E,x) - sage: phi._EllipticCurveIsogeny__init_even_kernel_polynomial(E,psig) - (x^3 + x, x^3*y + x^2 + x*y, 1, 0, 1, 2) + sage: psig = two_torsion_part(E,x) # needs sage.rings.finite_rings + sage: phi._EllipticCurveIsogeny__init_even_kernel_polynomial(E,psig) # needs sage.rings.finite_rings + (x^3 + x, (x^3 + x)*y + x^2, 1, 0, 1, 2) sage: E = EllipticCurve(GF(7), [0,-1,0,0,1]) sage: R.<x> = GF(7)[] sage: f = x^3 + 6*x^2 + 1 sage: phi = EllipticCurveIsogeny(E, f); phi - Isogeny of degree 4 from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 1 over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 2*x + 5 over Finite Field of size 7 + Isogeny of degree 4 + from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 1 over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 2*x + 5 over Finite Field of size 7 sage: psig = two_torsion_part(E,f) sage: psig = two_torsion_part(E,f) sage: phi._EllipticCurveIsogeny__init_even_kernel_polynomial(E,psig) - (x^7 + 5*x^6 + 2*x^5 + 6*x^4 + 3*x^3 + 5*x^2 + 6*x + 3, x^9*y - 3*x^8*y + 2*x^7*y - 3*x^3*y + 2*x^2*y + x*y - y, 1, 6, 3, 4) + (x^7 + 5*x^6 + 2*x^5 + 6*x^4 + 3*x^3 + 5*x^2 + 6*x + 3, (x^9 + 4*x^8 + 2*x^7 + 4*x^3 + 2*x^2 + x + 6)*y, 1, 6, 3, 4) """ # check if the polynomial really divides the two_torsion_polynomial - if self.__check and E.division_polynomial(2, x=self.__poly_ring.gen()) % psi_G != 0 : + if self.__check and E.division_polynomial(2, x=self.__poly_ring.gen()) % psi_G != 0: raise ValueError(f"the polynomial {psi_G} does not define a finite subgroup of {E}") n = psi_G.degree() # 1 or 3 @@ -2228,7 +2355,7 @@ def __init_even_kernel_polynomial(self, E, psi_G): a1, a2, a3, a4, a6 = E.a_invariants() b2, b4, _, _ = E.b_invariants() x = self.__poly_ring.gen() - y = self.__mpoly_ring.gen(1) + y = self.__mpoly_ring.gen() if n == 1: x0 = -psi_G.constant_coefficient() @@ -2245,9 +2372,9 @@ def __init_even_kernel_polynomial(self, E, psi_G): omega = (y*psi_G**2 - v*(a1*psi_G + (y - y0)))*psi_G elif n == 3: - s1 = -psi_G[n-1] - s2 = psi_G[n-2] - s3 = -psi_G[n-3] + s1 = -psi_G[n - 1] + s2 = psi_G[n - 2] + s3 = -psi_G[n - 3] psi_G_pr = psi_G.derivative() psi_G_prpr = psi_G_pr.derivative() @@ -2303,30 +2430,37 @@ def __init_odd_kernel_polynomial(self, E, psi): sage: R.<x> = GF(7)[] sage: E = EllipticCurve(GF(7), [0,-1,0,0,1]) sage: phi = EllipticCurveIsogeny(E, x+6, degree=3); phi - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 1 over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 4*x + 2 over Finite Field of size 7 + Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 1 over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 4*x + 2 over Finite Field of size 7 sage: R.<x> = GF(7)[] sage: phi._EllipticCurveIsogeny__init_odd_kernel_polynomial(E, x+6) - (x^3 + 5*x^2 + 3*x + 2, x^3*y - 3*x^2*y + x*y, 2, 6, 1, 3) + (x^3 + 5*x^2 + 3*x + 2, (x^3 + 4*x^2 + x)*y, 2, 6, 1, 3) + sage: # needs sage.rings.finite_rings sage: F = GF(2^4, 'alpha'); R.<x> = F[] sage: alpha = F.gen() sage: E = EllipticCurve(F, [1,1,F.gen(),F.gen()^2+1,1]) sage: f = x + alpha^2 + 1 sage: phi = EllipticCurveIsogeny(E, f); phi - Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y + alpha*y = x^3 + x^2 + (alpha^2+1)*x + 1 over Finite Field in alpha of size 2^4 to Elliptic Curve defined by y^2 + x*y + alpha*y = x^3 + x^2 + alpha*x + alpha^3 over Finite Field in alpha of size 2^4 + Isogeny of degree 3 + from Elliptic Curve defined by y^2 + x*y + alpha*y = x^3 + x^2 + (alpha^2+1)*x + 1 over Finite Field in alpha of size 2^4 + to Elliptic Curve defined by y^2 + x*y + alpha*y = x^3 + x^2 + alpha*x + alpha^3 over Finite Field in alpha of size 2^4 - sage: R.<x> = F[] - sage: f = x + alpha^2 + 1 - sage: phi._EllipticCurveIsogeny__init_odd_kernel_polynomial(E, f) - (x^3 + (alpha^2 + 1)*x + alpha^3 + alpha^2 + alpha, x^3*y + (alpha^2 + 1)*x^2*y + (alpha^2 + alpha + 1)*x^2 + (alpha^2 + 1)*x*y + (alpha^2 + alpha)*x + alpha*y + alpha, alpha^2 + alpha + 1, alpha^3 + alpha^2 + alpha, 1, 3) + sage: R.<x> = F[] # needs sage.rings.finite_rings + sage: f = x + alpha^2 + 1 # needs sage.rings.finite_rings + sage: phi._EllipticCurveIsogeny__init_odd_kernel_polynomial(E, f) # needs sage.rings.finite_rings + (x^3 + (alpha^2 + 1)*x + alpha^3 + alpha^2 + alpha, (x^3 + (alpha^2 + 1)*x^2 + (alpha^2 + 1)*x + alpha)*y + (alpha^2 + alpha + 1)*x^2 + (alpha^2 + alpha)*x + alpha, alpha^2 + alpha + 1, alpha^3 + alpha^2 + alpha, 1, 3) sage: E = EllipticCurve(j=-262537412640768000) sage: f = E.isogenies_prime_degree()[0].kernel_polynomial() sage: f.degree() 81 sage: E.isogeny(kernel=f, check=False) - Isogeny of degree 163 from Elliptic Curve defined by y^2 + y = x^3 - 2174420*x + 1234136692 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - 57772164980*x - 5344733777551611 over Rational Field + Isogeny of degree 163 + from Elliptic Curve defined by y^2 + y = x^3 - 2174420*x + 1234136692 over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - 57772164980*x - 5344733777551611 over Rational Field """ n = psi.degree() d = 2*n + 1 @@ -2399,7 +2533,9 @@ def __compute_omega_fast(self, E, psi, psi_pr, phi, phi_pr): sage: R.<x> = GF(7)[] sage: E = EllipticCurve(GF(7), [0,-1,0,0,1]) sage: phi = EllipticCurveIsogeny(E, x+6, degree=3); phi - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 1 over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 4*x + 2 over Finite Field of size 7 + Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 1 over Finite Field of size 7 + to Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 4*x + 2 over Finite Field of size 7 sage: R.<x,y> = GF(7)[] sage: psi = phi._EllipticCurveIsogeny__psi @@ -2407,11 +2543,12 @@ def __compute_omega_fast(self, E, psi, psi_pr, phi, phi_pr): sage: fi = phi._EllipticCurveIsogeny__phi sage: fi_pr = fi.derivative() sage: phi._EllipticCurveIsogeny__compute_omega_fast(E, psi, psi_pr, fi, fi_pr) - x^3*y - 3*x^2*y + x*y + (x^3 + 4*x^2 + x)*y """ a1 = E.a1() a3 = E.a3() - x, y = self.__mpoly_ring.gens() + x = self.__poly_ring.gen() + y = self.__mpoly_ring.gen() psi_2 = 2*y + a1*x + a3 @@ -2443,34 +2580,43 @@ def __compute_omega_general(self, E, psi, psi_pr, phi, phi_pr): These examples inherently exercise this private function:: + sage: # needs sage.rings.finite_rings sage: F = GF(2^4, 'alpha'); R.<x> = F[] sage: alpha = F.gen() sage: E = EllipticCurve(F, [1, 1, F.gen(), F.gen()^2+1, 1]) sage: f = x + alpha^2 + 1 sage: phi = EllipticCurveIsogeny(E, f); phi - Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y + alpha*y = x^3 + x^2 + (alpha^2+1)*x + 1 over Finite Field in alpha of size 2^4 to Elliptic Curve defined by y^2 + x*y + alpha*y = x^3 + x^2 + alpha*x + alpha^3 over Finite Field in alpha of size 2^4 + Isogeny of degree 3 + from Elliptic Curve defined by y^2 + x*y + alpha*y = x^3 + x^2 + (alpha^2+1)*x + 1 over Finite Field in alpha of size 2^4 + to Elliptic Curve defined by y^2 + x*y + alpha*y = x^3 + x^2 + alpha*x + alpha^3 over Finite Field in alpha of size 2^4 + sage: # needs sage.rings.finite_rings sage: R.<x,y> = F[] sage: psi = phi._EllipticCurveIsogeny__psi sage: psi_pr = psi.derivative() sage: fi = phi._EllipticCurveIsogeny__phi sage: fi_pr = fi.derivative() sage: phi._EllipticCurveIsogeny__compute_omega_general(E, psi, psi_pr, fi, fi_pr) - x^3*y + (alpha^2 + 1)*x^2*y + (alpha^2 + alpha + 1)*x^2 + (alpha^2 + 1)*x*y + (alpha^2 + alpha)*x + alpha*y + alpha + (x^3 + (alpha^2 + 1)*x^2 + (alpha^2 + 1)*x + alpha)*y + (alpha^2 + alpha + 1)*x^2 + (alpha^2 + alpha)*x + alpha A bug fixed in :trac:`7907`:: + sage: # needs sage.rings.finite_rings sage: F = GF(128,'a') sage: a = F.gen() sage: E = EllipticCurve([1,0,0,0,(a**6+a**4+a**2+a)]) sage: x = polygen(F) - sage: ker = x^6 + (a^6 + a^5 + a^4 + a^3 + a^2 + a)*x^5 + (a^6 + a^5 + a^2 + 1)*x^4 + (a^6 + a^5 + a^4 + a^3 + a^2 + 1)*x^3 + (a^6 + a^3 + a)*x^2 + (a^4 + a^3 + 1)*x + a^5 + a^4 + a + sage: ker = (x^6 + (a^6 + a^5 + a^4 + a^3 + a^2 + a)*x^5 + (a^6 + a^5 + a^2 + 1)*x^4 + ....: + (a^6 + a^5 + a^4 + a^3 + a^2 + 1)*x^3 + (a^6 + a^3 + a)*x^2 + (a^4 + a^3 + 1)*x + a^5 + a^4 + a) sage: E.isogeny(ker) - Isogeny of degree 13 from Elliptic Curve defined by y^2 + x*y = x^3 + (a^6+a^4+a^2+a) over Finite Field in a of size 2^7 to Elliptic Curve defined by y^2 + x*y = x^3 + (a^6+a^5+a^4+a^3+a^2+a)*x + (a^5+a^3) over Finite Field in a of size 2^7 + Isogeny of degree 13 + from Elliptic Curve defined by y^2 + x*y = x^3 + (a^6+a^4+a^2+a) over Finite Field in a of size 2^7 + to Elliptic Curve defined by y^2 + x*y = x^3 + (a^6+a^5+a^4+a^3+a^2+a)*x + (a^5+a^3) over Finite Field in a of size 2^7 """ a1, a2, a3, a4, a6 = E.a_invariants() b2, b4, _, _ = E.b_invariants() - x, y = self.__mpoly_ring.gens() + x = self.__poly_ring.gen() + y = self.__mpoly_ring.gen() n = psi.degree() d = 2 * n + 1 @@ -2486,7 +2632,7 @@ def __compute_omega_general(self, E, psi, psi_pr, phi, phi_pr): # thesis are wrong, the correct formulas # are coded below - from sage.arith.all import binomial + from sage.arith.misc import binomial for j in range(n - 1): psi_prpr += binomial(j+2, 2) * psi[j+2] * cur_x_pow @@ -2559,7 +2705,9 @@ def __compute_via_kohel(self, xP, yP): ((x^3 - 2*x^2 + 3*x + 2)/(x^2 - 2*x + 1), (x^3*y - 3*x^2*y + x*y)/(x^3 - 3*x^2 + 3*x - 1)) """ a = self.__phi(xP) - b = self.__omega(xP, yP) + omega0 = self.__omega[0] + omega1 = self.__omega[1] + b = omega0(xP) + omega1(xP)*yP c = self.__psi(xP) return a/c**2, b/c**3 @@ -2677,6 +2825,7 @@ def scaling_factor(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(257^2), [0,1]) sage: phi = E.isogeny(E.lift_x(240)) sage: phi.degree() @@ -2727,7 +2876,6 @@ def kernel_polynomial(self): self.__init_kernel_polynomial() return self.__kernel_polynomial - def is_separable(self): r""" Determine whether or not this isogeny is separable. @@ -2751,7 +2899,6 @@ def is_separable(self): """ return True - def _set_pre_isomorphism(self, preWI): """ Modify this isogeny by pre-composing with a @@ -2769,7 +2916,8 @@ def _set_pre_isomorphism(self, preWI): sage: isom = Epr.isomorphism_to(E) sage: phi._set_pre_isomorphism(isom) sage: phi.rational_maps() - ((-6*x^4 - 3*x^3 + 12*x^2 + 10*x - 1)/(x^3 + x - 12), (3*x^7 + x^6*y - 14*x^6 - 3*x^5 + 5*x^4*y + 7*x^4 + 8*x^3*y - 8*x^3 - 5*x^2*y + 5*x^2 - 14*x*y + 14*x - 6*y - 6)/(x^6 + 2*x^4 + 7*x^3 + x^2 + 7*x - 11)) + ((-6*x^4 - 3*x^3 + 12*x^2 + 10*x - 1)/(x^3 + x - 12), + (3*x^7 + x^6*y - 14*x^6 - 3*x^5 + 5*x^4*y + 7*x^4 + 8*x^3*y - 8*x^3 - 5*x^2*y + 5*x^2 - 14*x*y + 14*x - 6*y - 6)/(x^6 + 2*x^4 + 7*x^3 + x^2 + 7*x - 11)) sage: phi(Epr((0,22))) (13 : 21 : 1) sage: phi(Epr((3,7))) @@ -2780,14 +2928,18 @@ def _set_pre_isomorphism(self, preWI): sage: f = x^2 + 5 sage: phi = EllipticCurveIsogeny(E, f) sage: phi - Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 29 to Elliptic Curve defined by y^2 = x^3 + 20*x over Finite Field of size 29 + Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 29 + to Elliptic Curve defined by y^2 = x^3 + 20*x over Finite Field of size 29 sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: inv_isom = WeierstrassIsomorphism(E, (1,-2,5,10)) sage: Epr = inv_isom.codomain() sage: isom = Epr.isomorphism_to(E) sage: phi._set_pre_isomorphism(isom) sage: phi - Isogeny of degree 5 from Elliptic Curve defined by y^2 + 10*x*y + 20*y = x^3 + 27*x^2 + 6 over Finite Field of size 29 to Elliptic Curve defined by y^2 = x^3 + 20*x over Finite Field of size 29 + Isogeny of degree 5 + from Elliptic Curve defined by y^2 + 10*x*y + 20*y = x^3 + 27*x^2 + 6 over Finite Field of size 29 + to Elliptic Curve defined by y^2 = x^3 + 20*x over Finite Field of size 29 sage: phi(Epr((12,1))) (26 : 0 : 1) sage: phi(Epr((2,9))) @@ -2801,13 +2953,17 @@ def _set_pre_isomorphism(self, preWI): sage: R.<x> = QQ[] sage: f = x^2 - 21*x + 80 sage: phi = EllipticCurveIsogeny(E, f); phi - Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field + Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: Epr = E.short_weierstrass_model() sage: isom = Epr.isomorphism_to(E) sage: phi._set_pre_isomorphism(isom) sage: phi - Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 - 13392*x - 1080432 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field + Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 - 13392*x - 1080432 over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field sage: phi(Epr((168,1188))) (0 : 1 : 0) """ @@ -2831,7 +2987,6 @@ def _set_pre_isomorphism(self, preWI): self.__set_pre_isomorphism(domain, isom) - def _set_post_isomorphism(self, postWI): """ Modify this isogeny by post-composing with a @@ -2847,7 +3002,9 @@ def _set_post_isomorphism(self, postWI): sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: phi._set_post_isomorphism(WeierstrassIsomorphism(phi.codomain(), (6,8,10,12))) sage: phi - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 31 to Elliptic Curve defined by y^2 + 24*x*y + 7*y = x^3 + 22*x^2 + 16*x + 20 over Finite Field of size 31 + Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 31 + to Elliptic Curve defined by y^2 + 24*x*y + 7*y = x^3 + 22*x^2 + 16*x + 20 over Finite Field of size 31 sage: E = EllipticCurve(j=GF(47)(0)) sage: f = E.torsion_polynomial(3)/3 @@ -2869,7 +3026,9 @@ def _set_post_isomorphism(self, postWI): sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: post_isom = WeierstrassIsomorphism(phi.codomain(), (a,2,3,5)) sage: phi - Isogeny of degree 4 from Elliptic Curve defined by y^2 = x^3 + x over Number Field in a with defining polynomial x^2 + 2 to Elliptic Curve defined by y^2 = x^3 + (-44)*x + 112 over Number Field in a with defining polynomial x^2 + 2 + Isogeny of degree 4 + from Elliptic Curve defined by y^2 = x^3 + x over Number Field in a with defining polynomial x^2 + 2 + to Elliptic Curve defined by y^2 = x^3 + (-44)*x + 112 over Number Field in a with defining polynomial x^2 + 2 """ WIdom = postWI.domain() WIcod = postWI.codomain() @@ -2891,7 +3050,6 @@ def _set_post_isomorphism(self, postWI): self.__set_post_isomorphism(codomain, isom) - def dual(self): r""" Return the isogeny dual to this isogeny. @@ -2957,19 +3115,25 @@ def dual(self): Inseparable duals should be computed correctly:: + sage: # needs sage.rings.finite_rings sage: z2 = GF(71^2).gen() sage: E = EllipticCurve(j=57*z2+51) sage: E.isogeny(3*E.lift_x(0)).dual() Composite morphism of degree 71 = 71*1^2: - From: Elliptic Curve defined by y^2 = x^3 + (32*z2+67)*x + (24*z2+37) over Finite Field in z2 of size 71^2 - To: Elliptic Curve defined by y^2 = x^3 + (41*z2+56)*x + (18*z2+42) over Finite Field in z2 of size 71^2 + From: Elliptic Curve defined by y^2 = x^3 + (32*z2+67)*x + (24*z2+37) + over Finite Field in z2 of size 71^2 + To: Elliptic Curve defined by y^2 = x^3 + (41*z2+56)*x + (18*z2+42) + over Finite Field in z2 of size 71^2 sage: E.isogeny(E.lift_x(0)).dual() Composite morphism of degree 213 = 71*3: - From: Elliptic Curve defined by y^2 = x^3 + (58*z2+31)*x + (34*z2+58) over Finite Field in z2 of size 71^2 - To: Elliptic Curve defined by y^2 = x^3 + (41*z2+56)*x + (18*z2+42) over Finite Field in z2 of size 71^2 + From: Elliptic Curve defined by y^2 = x^3 + (58*z2+31)*x + (34*z2+58) + over Finite Field in z2 of size 71^2 + To: Elliptic Curve defined by y^2 = x^3 + (41*z2+56)*x + (18*z2+42) + over Finite Field in z2 of size 71^2 ...even if pre- or post-isomorphisms are present:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: phi = E.isogeny(E.lift_x(0)) sage: pre = ~WeierstrassIsomorphism(phi.domain(), (z2,2,3,4)) @@ -2977,17 +3141,24 @@ def dual(self): sage: phi = post * phi * pre sage: phi.dual() Composite morphism of degree 213 = 71*3: - From: Elliptic Curve defined by y^2 + 17*x*y + 45*y = x^3 + 30*x^2 + (6*z2+64)*x + (48*z2+65) over Finite Field in z2 of size 71^2 - To: Elliptic Curve defined by y^2 + (60*z2+22)*x*y + (69*z2+37)*y = x^3 + (32*z2+48)*x^2 + (19*z2+58)*x + (56*z2+22) over Finite Field in z2 of size 71^2 + From: Elliptic Curve defined + by y^2 + 17*x*y + 45*y = x^3 + 30*x^2 + (6*z2+64)*x + (48*z2+65) + over Finite Field in z2 of size 71^2 + To: Elliptic Curve defined + by y^2 + (60*z2+22)*x*y + (69*z2+37)*y = x^3 + (32*z2+48)*x^2 + + (19*z2+58)*x + (56*z2+22) + over Finite Field in z2 of size 71^2 TESTS: Test for :trac:`23928`:: - sage: E = EllipticCurve(j=GF(431**2)(4)) - sage: phi = E.isogeny(E.lift_x(0)) - sage: phi.dual() - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 427*x over Finite Field in z2 of size 431^2 to Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 431^2 + sage: E = EllipticCurve(j=GF(431**2)(4)) # needs sage.rings.finite_rings + sage: phi = E.isogeny(E.lift_x(0)) # needs sage.rings.finite_rings + sage: phi.dual() # needs sage.rings.finite_rings + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 427*x over Finite Field in z2 of size 431^2 + to Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 431^2 Test (for :trac:`7096`):: @@ -3000,7 +3171,9 @@ def dual(self): sage: E = EllipticCurve(k,[11,11]) sage: phi = E.isogeny(E(4,4)) sage: phi - Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + 11*x + 11 over Finite Field of size 103 to Elliptic Curve defined by y^2 = x^3 + 25*x + 80 over Finite Field of size 103 + Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + 11*x + 11 over Finite Field of size 103 + to Elliptic Curve defined by y^2 = x^3 + 25*x + 80 over Finite Field of size 103 sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: phi = WeierstrassIsomorphism(phi.codomain(),(5,0,1,2)) * phi sage: phi.dual().dual() == phi @@ -3009,10 +3182,13 @@ def dual(self): sage: E = EllipticCurve(GF(103),[1,0,0,1,-1]) sage: phi = E.isogeny(E(60,85)) sage: phi.dual() - Isogeny of degree 7 from Elliptic Curve defined by y^2 + x*y = x^3 + 84*x + 34 over Finite Field of size 103 to Elliptic Curve defined by y^2 + x*y = x^3 + x + 102 over Finite Field of size 103 + Isogeny of degree 7 + from Elliptic Curve defined by y^2 + x*y = x^3 + 84*x + 34 over Finite Field of size 103 + to Elliptic Curve defined by y^2 + x*y = x^3 + x + 102 over Finite Field of size 103 Check that :trac:`17293` is fixed:: + sage: # needs sage.rings.number_field sage: k.<s> = QuadraticField(2) sage: E = EllipticCurve(k, [-3*s*(4 + 5*s), 2*s*(2 + 14*s + 11*s^2)]) sage: phi = E.isogenies_prime_degree(3)[0] @@ -3101,7 +3277,6 @@ def dual(self): phi_hat.__perform_inheritance_housekeeping() return phi_hat - @staticmethod def _composition_impl(left, right): r""" @@ -3117,11 +3292,17 @@ def _composition_impl(left, right): sage: iso1 = E.change_weierstrass_model(1,1,1,1).isomorphism_to(E) sage: iso2 = E2.isomorphism_to(E2.change_weierstrass_model(39,0,0,0)) sage: phi * iso1 # indirect doctest - Isogeny of degree 11 from Elliptic Curve defined by y^2 + 2*x*y + 2*y = x^3 + 2*x^2 + 6*x + 7 over Finite Field of size 127 to Elliptic Curve defined by y^2 = x^3 + 37*x + 85 over Finite Field of size 127 + Isogeny of degree 11 + from Elliptic Curve defined by y^2 + 2*x*y + 2*y = x^3 + 2*x^2 + 6*x + 7 over Finite Field of size 127 + to Elliptic Curve defined by y^2 = x^3 + 37*x + 85 over Finite Field of size 127 sage: iso2 * phi # indirect doctest - Isogeny of degree 11 from Elliptic Curve defined by y^2 = x^3 + 5*x + 2 over Finite Field of size 127 to Elliptic Curve defined by y^2 = x^3 + 117*x + 58 over Finite Field of size 127 + Isogeny of degree 11 + from Elliptic Curve defined by y^2 = x^3 + 5*x + 2 over Finite Field of size 127 + to Elliptic Curve defined by y^2 = x^3 + 117*x + 58 over Finite Field of size 127 sage: iso2 * phi * iso1 # indirect doctest - Isogeny of degree 11 from Elliptic Curve defined by y^2 + 2*x*y + 2*y = x^3 + 2*x^2 + 6*x + 7 over Finite Field of size 127 to Elliptic Curve defined by y^2 = x^3 + 117*x + 58 over Finite Field of size 127 + Isogeny of degree 11 + from Elliptic Curve defined by y^2 + 2*x*y + 2*y = x^3 + 2*x^2 + 6*x + 7 over Finite Field of size 127 + to Elliptic Curve defined by y^2 = x^3 + 117*x + 58 over Finite Field of size 127 TESTS: @@ -3187,7 +3368,7 @@ def compute_isogeny_stark(E1, E2, ell): sage: R.<x> = GF(97)[]; f = x^5 + 27*x^4 + 61*x^3 + 58*x^2 + 28*x + 21 sage: phi = EllipticCurveIsogeny(E, f) sage: E2 = phi.codomain() - sage: (isom1, isom2, E1pr, E2pr, ker_poly) = compute_sequence_of_maps(E, E2, 11) + sage: isom1, isom2, E1pr, E2pr, ker_poly = compute_sequence_of_maps(E, E2, 11) sage: compute_isogeny_stark(E1pr, E2pr, 11) x^10 + 37*x^9 + 53*x^8 + 66*x^7 + 66*x^6 + 17*x^5 + 57*x^4 + 6*x^3 + 89*x^2 + 53*x + 8 @@ -3252,49 +3433,10 @@ def compute_isogeny_stark(E1, E2, ell): qn /= qn.leading_coefficient() return qn + from sage.misc.superseded import deprecated_function_alias compute_isogeny_starks = deprecated_function_alias(34871, compute_isogeny_stark) -def split_kernel_polynomial(poly): - r""" - Obsolete internal helper function formerly used by - :func:`compute_isogeny_kernel_polynomial`. - - Use - :meth:`~sage.rings.polynomial.polynomial_element.Polynomial.radical` - instead. - - INPUT: - - - ``poly`` -- a nonzero univariate polynomial - - OUTPUT: - - The maximum separable divisor of ``poly``. If the input is a full - kernel polynomial where the roots which are `x`-coordinates of - points of order greater than 2 have multiplicity 1, the output - will be a polynomial with the same roots, all of multiplicity 1. - - EXAMPLES: - - Check that this behaves identically to ``.radical()``:: - - sage: from sage.schemes.elliptic_curves.ell_curve_isogeny import split_kernel_polynomial - sage: q = next_prime(randrange(3,10^3)) - sage: e = randrange(1,5) - sage: R = GF(q^e,'a')['x'] - sage: f = R.random_element(randrange(10,100)).monic() - sage: split_kernel_polynomial(f) == f.radical() - doctest:warning ... - DeprecationWarning: ... - True - """ - from sage.misc.superseded import deprecation - deprecation(33619, 'The split_kernel_polynomial() function is obsolete. ' - 'Use .radical() instead.') - from sage.misc.misc_c import prod - return prod([p for p,e in poly.squarefree_decomposition()]) - def compute_isogeny_kernel_polynomial(E1, E2, ell, algorithm="stark"): r""" Return the kernel polynomial of an isogeny of degree ``ell`` @@ -3334,6 +3476,7 @@ def compute_isogeny_kernel_polynomial(E1, E2, ell, algorithm="stark"): sage: f x^2 + 7*x + 13 + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve(K, [0,0,0,1,0]) @@ -3406,31 +3549,40 @@ def compute_intermediate_curves(E1, E2): sage: from sage.schemes.elliptic_curves.ell_curve_isogeny import compute_intermediate_curves sage: E = EllipticCurve(GF(83), [1,0,1,1,0]) - sage: R.<x> = GF(83)[]; f = x+24 + sage: R.<x> = GF(83)[]; f = x + 24 sage: phi = EllipticCurveIsogeny(E, f) sage: E2 = phi.codomain() sage: compute_intermediate_curves(E, E2) (Elliptic Curve defined by y^2 = x^3 + 62*x + 74 over Finite Field of size 83, Elliptic Curve defined by y^2 = x^3 + 65*x + 69 over Finite Field of size 83, Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x over Finite Field of size 83 - To: Elliptic Curve defined by y^2 = x^3 + 62*x + 74 over Finite Field of size 83 + From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x + over Finite Field of size 83 + To: Elliptic Curve defined by y^2 = x^3 + 62*x + 74 + over Finite Field of size 83 Via: (u,r,s,t) = (1, 76, 41, 3), Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 = x^3 + 65*x + 69 over Finite Field of size 83 - To: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + 16 over Finite Field of size 83 + From: Elliptic Curve defined by y^2 = x^3 + 65*x + 69 + over Finite Field of size 83 + To: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + 16 + over Finite Field of size 83 Via: (u,r,s,t) = (1, 7, 42, 42)) + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve(K, [0,0,0,1,0]) sage: E2 = EllipticCurve(K, [0,0,0,16,0]) sage: compute_intermediate_curves(E, E2) - (Elliptic Curve defined by y^2 = x^3 + x over Number Field in i with defining polynomial x^2 + 1, - Elliptic Curve defined by y^2 = x^3 + 16*x over Number Field in i with defining polynomial x^2 + 1, - Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Number Field in i with defining polynomial x^2 + 1 + (Elliptic Curve defined by y^2 = x^3 + x + over Number Field in i with defining polynomial x^2 + 1, + Elliptic Curve defined by y^2 = x^3 + 16*x + over Number Field in i with defining polynomial x^2 + 1, + Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x + over Number Field in i with defining polynomial x^2 + 1 Via: (u,r,s,t) = (1, 0, 0, 0), - Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + 16*x over Number Field in i with defining polynomial x^2 + 1 + Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + 16*x + over Number Field in i with defining polynomial x^2 + 1 Via: (u,r,s,t) = (1, 0, 0, 0)) """ if E1.base_ring().characteristic() in (2, 3): @@ -3493,27 +3645,36 @@ def compute_sequence_of_maps(E1, E2, ell): sage: E2 = phi.codomain() sage: compute_sequence_of_maps(E, E2, 5) (Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field - To: Elliptic Curve defined by y^2 = x^3 - 31/3*x - 2501/108 over Rational Field + From: Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 + over Rational Field + To: Elliptic Curve defined by y^2 = x^3 - 31/3*x - 2501/108 + over Rational Field Via: (u,r,s,t) = (1, 1/3, 0, -1/2), Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 = x^3 - 23461/3*x - 28748141/108 over Rational Field - To: Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field + From: Elliptic Curve defined by y^2 = x^3 - 23461/3*x - 28748141/108 + over Rational Field + To: Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 + over Rational Field Via: (u,r,s,t) = (1, -1/3, 0, 1/2), Elliptic Curve defined by y^2 = x^3 - 31/3*x - 2501/108 over Rational Field, Elliptic Curve defined by y^2 = x^3 - 23461/3*x - 28748141/108 over Rational Field, x^2 - 61/3*x + 658/9) + sage: # needs sage.rings.number_field sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve(K, [0,0,0,1,0]) sage: E2 = EllipticCurve(K, [0,0,0,16,0]) sage: compute_sequence_of_maps(E, E2, 4) - (Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Number Field in i with defining polynomial x^2 + 1 + (Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x + over Number Field in i with defining polynomial x^2 + 1 Via: (u,r,s,t) = (1, 0, 0, 0), - Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + 16*x over Number Field in i with defining polynomial x^2 + 1 + Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + 16*x + over Number Field in i with defining polynomial x^2 + 1 Via: (u,r,s,t) = (1, 0, 0, 0), - Elliptic Curve defined by y^2 = x^3 + x over Number Field in i with defining polynomial x^2 + 1, - Elliptic Curve defined by y^2 = x^3 + 16*x over Number Field in i with defining polynomial x^2 + 1, + Elliptic Curve defined by y^2 = x^3 + x + over Number Field in i with defining polynomial x^2 + 1, + Elliptic Curve defined by y^2 = x^3 + 16*x + over Number Field in i with defining polynomial x^2 + 1, x^3 + x) sage: E = EllipticCurve(GF(97), [1,0,1,1,0]) @@ -3522,12 +3683,16 @@ def compute_sequence_of_maps(E1, E2, ell): sage: E2 = phi.codomain() sage: compute_sequence_of_maps(E, E2, 11) (Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x over Finite Field of size 97 - To: Elliptic Curve defined by y^2 = x^3 + 52*x + 31 over Finite Field of size 97 + From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x + over Finite Field of size 97 + To: Elliptic Curve defined by y^2 = x^3 + 52*x + 31 + over Finite Field of size 97 Via: (u,r,s,t) = (1, 8, 48, 44), Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 = x^3 + 41*x + 66 over Finite Field of size 97 - To: Elliptic Curve defined by y^2 + x*y + y = x^3 + 87*x + 26 over Finite Field of size 97 + From: Elliptic Curve defined by y^2 = x^3 + 41*x + 66 + over Finite Field of size 97 + To: Elliptic Curve defined by y^2 + x*y + y = x^3 + 87*x + 26 + over Finite Field of size 97 Via: (u,r,s,t) = (1, 89, 49, 49), Elliptic Curve defined by y^2 = x^3 + 52*x + 31 over Finite Field of size 97, Elliptic Curve defined by y^2 = x^3 + 41*x + 66 over Finite Field of size 97, @@ -3559,7 +3724,8 @@ def fill_isogeny_matrix(M): EXAMPLES:: - sage: M = Matrix([[0, 2, 3, 3, 0, 0], [2, 0, 0, 0, 3, 3], [3, 0, 0, 0, 2, 0], [3, 0, 0, 0, 0, 2], [0, 3, 2, 0, 0, 0], [0, 3, 0, 2, 0, 0]]); M + sage: M = Matrix([[0, 2, 3, 3, 0, 0], [2, 0, 0, 0, 3, 3], [3, 0, 0, 0, 2, 0], + ....: [3, 0, 0, 0, 0, 2], [0, 3, 2, 0, 0, 0], [0, 3, 0, 2, 0, 0]]); M [0 2 3 3 0 0] [2 0 0 0 3 3] [3 0 0 0 2 0] @@ -3614,7 +3780,8 @@ def unfill_isogeny_matrix(M): EXAMPLES:: - sage: M = Matrix([[0, 2, 3, 3, 0, 0], [2, 0, 0, 0, 3, 3], [3, 0, 0, 0, 2, 0], [3, 0, 0, 0, 0, 2], [0, 3, 2, 0, 0, 0], [0, 3, 0, 2, 0, 0]]); M + sage: M = Matrix([[0, 2, 3, 3, 0, 0], [2, 0, 0, 0, 3, 3], [3, 0, 0, 0, 2, 0], + ....: [3, 0, 0, 0, 0, 2], [0, 3, 2, 0, 0, 0], [0, 3, 0, 2, 0, 0]]); M [0 2 3 3 0 0] [2 0 0 0 3 3] [3 0 0 0 2 0] diff --git a/src/sage/schemes/elliptic_curves/ell_egros.py b/src/sage/schemes/elliptic_curves/ell_egros.py index 53c507e4c89..42c8d0738be 100644 --- a/src/sage/schemes/elliptic_curves/ell_egros.py +++ b/src/sage/schemes/elliptic_curves/ell_egros.py @@ -115,11 +115,9 @@ def is_possible_j(j, S=[]): True """ j = QQ(j) - return (j.is_zero() and 3 in S) \ - or (j == 1728) \ - or (j.is_S_integral(S) \ - and j.prime_to_S_part(S).is_nth_power(3) \ - and (j-1728).prime_to_S_part(S).abs().is_square()) + return (j.is_zero() and 3 in S) or (j == 1728) \ + or (j.is_S_integral(S) and j.prime_to_S_part(S).is_nth_power(3) + and (j - 1728).prime_to_S_part(S).abs().is_square()) def curve_key(E1): diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 9d342607c7b..70848089476 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -1,8 +1,8 @@ r""" Elliptic curves over a general field -This module defines the class ``EllipticCurve_field``, based on -``EllipticCurve_generic``, for elliptic curves over general fields. +This module defines the class :class:`EllipticCurve_field`, based on +:class:`EllipticCurve_generic`, for elliptic curves over general fields. """ #***************************************************************************** # Copyright (C) 2006 William Stein <wstein@gmail.com> @@ -12,11 +12,13 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -import sage.rings.all as rings import sage.rings.abc from sage.categories.number_fields import NumberFields from sage.categories.finite_fields import FiniteFields - +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.rational_field import QQ from sage.schemes.elliptic_curves.ell_point import EllipticCurvePoint_field from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_field @@ -55,7 +57,7 @@ def genus(self): sage: E.genus() 1 """ - return rings.ZZ.one() + return ZZ.one() r""" Twists: rewritten by John Cremona as follows: @@ -96,42 +98,51 @@ def quadratic_twist(self, D=None): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve([GF(1103)(1), 0, 0, 107, 340]); E - Elliptic Curve defined by y^2 + x*y = x^3 + 107*x + 340 over Finite Field of size 1103 - sage: F=E.quadratic_twist(-1); F - Elliptic Curve defined by y^2 = x^3 + 1102*x^2 + 609*x + 300 over Finite Field of size 1103 + Elliptic Curve defined by y^2 + x*y = x^3 + 107*x + 340 + over Finite Field of size 1103 + sage: F = E.quadratic_twist(-1); F + Elliptic Curve defined by y^2 = x^3 + 1102*x^2 + 609*x + 300 + over Finite Field of size 1103 sage: E.is_isomorphic(F) False - sage: E.is_isomorphic(F,GF(1103^2,'a')) + sage: E.is_isomorphic(F, GF(1103^2,'a')) True A characteristic 2 example:: - sage: E=EllipticCurve(GF(2),[1,0,1,1,1]) - sage: E1=E.quadratic_twist(1) + sage: E = EllipticCurve(GF(2), [1,0,1,1,1]) + sage: E1 = E.quadratic_twist(1) sage: E.is_isomorphic(E1) False - sage: E.is_isomorphic(E1,GF(4,'a')) + sage: E.is_isomorphic(E1, GF(4,'a')) True Over finite fields, the twisting parameter may be omitted:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(2^10) - sage: E = EllipticCurve(k,[a^2,a,1,a+1,1]) + sage: E = EllipticCurve(k, [a^2,a,1,a+1,1]) sage: Et = E.quadratic_twist() - sage: Et # random (only determined up to isomorphism) - Elliptic Curve defined by y^2 + x*y = x^3 + (a^7+a^4+a^3+a^2+a+1)*x^2 + (a^8+a^6+a^4+1) over Finite Field in a of size 2^10 + sage: Et # random (only determined up to isomorphism) + Elliptic Curve defined + by y^2 + x*y = x^3 + (a^7+a^4+a^3+a^2+a+1)*x^2 + (a^8+a^6+a^4+1) + over Finite Field in a of size 2^10 sage: E.is_isomorphic(Et) False - sage: E.j_invariant()==Et.j_invariant() + sage: E.j_invariant() == Et.j_invariant() True - sage: p=next_prime(10^10) + sage: # needs sage.rings.finite_rings + sage: p = next_prime(10^10) sage: k = GF(p) - sage: E = EllipticCurve(k,[1,2,3,4,5]) + sage: E = EllipticCurve(k, [1,2,3,4,5]) sage: Et = E.quadratic_twist() - sage: Et # random (only determined up to isomorphism) - Elliptic Curve defined by y^2 = x^3 + 7860088097*x^2 + 9495240877*x + 3048660957 over Finite Field of size 10000000019 + sage: Et # random (only determined up to isomorphism) + Elliptic Curve defined + by y^2 = x^3 + 7860088097*x^2 + 9495240877*x + 3048660957 + over Finite Field of size 10000000019 sage: E.is_isomorphic(Et) False sage: k2 = GF(p^2,'a') @@ -143,13 +154,13 @@ def quadratic_twist(self, D=None): if D is None: if K.is_finite(): - x = rings.polygen(K) + x = polygen(K) if char == 2: # We find D such that x^2+x+D is irreducible. If the # degree is odd we can take D=1; otherwise it suffices to # consider odd powers of a generator. D = K(1) - if K.degree()%2==0: + if K.degree() % 2 == 0: D = K.gen() a = D**2 while (x**2 + x + D).roots(): @@ -157,34 +168,35 @@ def quadratic_twist(self, D=None): else: # We could take a multiplicative generator but # that might be expensive to compute; otherwise - # half the elements will do + # half the elements will do, and testing squares + # is very fast. D = K.random_element() - while (x**2 - D).roots(): + while D.is_square(): D = K.random_element() else: raise ValueError("twisting parameter D must be specified over infinite fields.") else: try: - D=K(D) + D = K(D) except ValueError: raise ValueError("twisting parameter D must be in the base field.") - if char!=2 and D.is_zero(): + if char != 2 and D.is_zero(): raise ValueError("twisting parameter D must be nonzero when characteristic is not 2") - if char!=2: - b2,b4,b6,b8=self.b_invariants() + if char != 2: + b2,b4,b6,b8 = self.b_invariants() # E is isomorphic to [0,b2,0,8*b4,16*b6] return EllipticCurve(K,[0,b2*D,0,8*b4*D**2,16*b6*D**3]) # now char==2 - if self.j_invariant() !=0: # iff a1!=0 - a1,a2,a3,a4,a6=self.ainvs() - E0=self.change_weierstrass_model(a1,a3/a1,0,(a1**2*a4+a3**2)/a1**3) + if self.j_invariant() != 0: # iff a1!=0 + a1,a2,a3,a4,a6 = self.ainvs() + E0 = self.change_weierstrass_model(a1,a3/a1,0,(a1**2*a4+a3**2)/a1**3) # which has the form = [1,A2,0,0,A6] - assert E0.a1()==K(1) - assert E0.a3()==K(0) - assert E0.a4()==K(0) + assert E0.a1() == K(1) + assert E0.a3() == K(0) + assert E0.a4() == K(0) return EllipticCurve(K,[1,E0.a2()+D,0,0,E0.a6()]) else: raise ValueError("Quadratic twist not implemented in char 2 when j=0") @@ -198,11 +210,11 @@ def two_torsion_rank(self): EXAMPLES:: - sage: E=EllipticCurve('11a1') + sage: E = EllipticCurve('11a1') sage: E.two_torsion_rank() 0 - sage: K.<alpha>=QQ.extension(E.division_polynomial(2).monic()) - sage: E.base_extend(K).two_torsion_rank() + sage: K.<alpha> = QQ.extension(E.division_polynomial(2).monic()) # needs sage.rings.number_field + sage: E.base_extend(K).two_torsion_rank() # needs sage.rings.number_field 1 sage: E.reduction(53).two_torsion_rank() 2 @@ -212,8 +224,9 @@ def two_torsion_rank(self): sage: E = EllipticCurve('14a1') sage: E.two_torsion_rank() 1 - sage: K.<alpha>=QQ.extension(E.division_polynomial(2).monic().factor()[1][0]) - sage: E.base_extend(K).two_torsion_rank() + sage: f = E.division_polynomial(2).monic().factor()[1][0] + sage: K.<alpha> = QQ.extension(f) # needs sage.rings.number_field + sage: E.base_extend(K).two_torsion_rank() # needs sage.rings.number_field 2 :: @@ -221,10 +234,9 @@ def two_torsion_rank(self): sage: EllipticCurve('15a1').two_torsion_rank() 2 """ - f=self.division_polynomial(rings.Integer(2)) - n=len(f.roots())+1 - return rings.Integer(n).ord(rings.Integer(2)) - + f = self.division_polynomial(Integer(2)) + n = len(f.roots())+1 + return Integer(n).ord(Integer(2)) def quartic_twist(self, D): r""" @@ -232,7 +244,7 @@ def quartic_twist(self, D): INPUT: - - ``D`` (must be nonzero) -- the twisting parameter.. + - ``D`` (must be nonzero) -- the twisting parameter .. NOTE:: @@ -240,42 +252,43 @@ def quartic_twist(self, D): EXAMPLES:: - sage: E=EllipticCurve_from_j(GF(13)(1728)); E - Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 13 - sage: E1=E.quartic_twist(2); E1 - Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 13 + sage: # needs sage.rings.finite_rings + sage: E = EllipticCurve_from_j(GF(13)(1728)); E + Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 13 + sage: E1 = E.quartic_twist(2); E1 + Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 13 sage: E.is_isomorphic(E1) False - sage: E.is_isomorphic(E1,GF(13^2,'a')) + sage: E.is_isomorphic(E1, GF(13^2,'a')) False - sage: E.is_isomorphic(E1,GF(13^4,'a')) + sage: E.is_isomorphic(E1, GF(13^4,'a')) True """ - K=self.base_ring() - char=K.characteristic() - D=K(D) + K = self.base_ring() + char = K.characteristic() + D = K(D) - if char==2 or char==3: + if char == 2 or char == 3: raise ValueError("Quartic twist not defined in chars 2,3") - if self.j_invariant() !=K(1728): + if self.j_invariant() != K(1728): raise ValueError("Quartic twist not defined when j!=1728") if D.is_zero(): raise ValueError("quartic twist requires a nonzero argument") - c4,c6=self.c_invariants() + c4,c6 = self.c_invariants() # E is isomorphic to [0,0,0,-27*c4,0] - assert c6==0 + assert c6 == 0 return EllipticCurve(K,[0,0,0,-27*c4*D,0]) def sextic_twist(self, D): r""" - Return the quartic twist of this curve by `D`. + Return the sextic twist of this curve by `D`. INPUT: - - ``D`` (must be nonzero) -- the twisting parameter.. + - ``D`` (must be nonzero) -- the twisting parameter .. NOTE:: @@ -283,35 +296,36 @@ def sextic_twist(self, D): EXAMPLES:: - sage: E=EllipticCurve_from_j(GF(13)(0)); E + sage: # needs sage.rings.finite_rings + sage: E = EllipticCurve_from_j(GF(13)(0)); E Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 13 - sage: E1=E.sextic_twist(2); E1 + sage: E1 = E.sextic_twist(2); E1 Elliptic Curve defined by y^2 = x^3 + 11 over Finite Field of size 13 sage: E.is_isomorphic(E1) False - sage: E.is_isomorphic(E1,GF(13^2,'a')) + sage: E.is_isomorphic(E1, GF(13^2,'a')) False - sage: E.is_isomorphic(E1,GF(13^4,'a')) + sage: E.is_isomorphic(E1, GF(13^4,'a')) False - sage: E.is_isomorphic(E1,GF(13^6,'a')) + sage: E.is_isomorphic(E1, GF(13^6,'a')) True """ - K=self.base_ring() - char=K.characteristic() - D=K(D) + K = self.base_ring() + char = K.characteristic() + D = K(D) - if char==2 or char==3: + if char == 2 or char == 3: raise ValueError("Sextic twist not defined in chars 2,3") - if self.j_invariant() !=K(0): + if self.j_invariant() != K(0): raise ValueError("Sextic twist not defined when j!=0") if D.is_zero(): raise ValueError("Sextic twist requires a nonzero argument") - c4,c6=self.c_invariants() + c4,c6 = self.c_invariants() # E is isomorphic to [0,0,0,0,-54*c6] - assert c4==0 + assert c4 == 0 return EllipticCurve(K,[0,0,0,0,-54*c6*D]) def is_quadratic_twist(self, other): @@ -320,7 +334,7 @@ def is_quadratic_twist(self, other): INPUT: - - ``other`` -- an elliptic curves with the same base field as self. + - ``other`` -- an elliptic curve with the same base field as ``self``. OUTPUT: @@ -343,38 +357,39 @@ def is_quadratic_twist(self, other): sage: E.is_quadratic_twist(Et) -6 - sage: E1=EllipticCurve([0,0,1,0,0]) + sage: E1 = EllipticCurve([0,0,1,0,0]) sage: E1.j_invariant() 0 - sage: E2=EllipticCurve([0,0,0,0,2]) + sage: E2 = EllipticCurve([0,0,0,0,2]) sage: E1.is_quadratic_twist(E2) 2 sage: E1.is_quadratic_twist(E1) 1 - sage: type(E1.is_quadratic_twist(E1)) == type(E1.is_quadratic_twist(E2)) #trac 6574 + sage: type(E1.is_quadratic_twist(E1)) == type(E1.is_quadratic_twist(E2)) # Issue #6574 True :: - sage: E1=EllipticCurve([0,0,0,1,0]) + sage: E1 = EllipticCurve([0,0,0,1,0]) sage: E1.j_invariant() 1728 - sage: E2=EllipticCurve([0,0,0,2,0]) + sage: E2 = EllipticCurve([0,0,0,2,0]) sage: E1.is_quadratic_twist(E2) 0 - sage: E2=EllipticCurve([0,0,0,25,0]) + sage: E2 = EllipticCurve([0,0,0,25,0]) sage: E1.is_quadratic_twist(E2) 5 :: + sage: # needs sage.rings.finite_rings sage: F = GF(101) - sage: E1 = EllipticCurve(F,[4,7]) + sage: E1 = EllipticCurve(F, [4,7]) sage: E2 = E1.quadratic_twist() - sage: D = E1.is_quadratic_twist(E2); D!=0 + sage: D = E1.is_quadratic_twist(E2); D != 0 True sage: F = GF(101) - sage: E1 = EllipticCurve(F,[4,7]) + sage: E1 = EllipticCurve(F, [4,7]) sage: E2 = E1.quadratic_twist() sage: D = E1.is_quadratic_twist(E2) sage: E1.quadratic_twist(D).is_isomorphic(E2) @@ -387,16 +402,18 @@ def is_quadratic_twist(self, other): A characteristic 3 example:: + sage: # needs sage.rings.finite_rings sage: F = GF(3^5,'a') sage: E1 = EllipticCurve_from_j(F(1)) sage: E2 = E1.quadratic_twist(-1) - sage: D = E1.is_quadratic_twist(E2); D!=0 + sage: D = E1.is_quadratic_twist(E2); D != 0 True sage: E1.quadratic_twist(D).is_isomorphic(E2) True :: + sage: # needs sage.rings.finite_rings sage: E1 = EllipticCurve_from_j(F(0)) sage: E2 = E1.quadratic_twist() sage: D = E1.is_quadratic_twist(E2); D @@ -413,21 +430,21 @@ def is_quadratic_twist(self, other): zero = K.zero() if not K == F.base_ring(): return zero - j=E.j_invariant() + j = E.j_invariant() if j != F.j_invariant(): return zero if E.is_isomorphic(F): - if K is rings.QQ: - return rings.ZZ(1) + if K is QQ: + return ZZ(1) return K.one() - char=K.characteristic() + char = K.characteristic() - if char==2: + if char == 2: raise NotImplementedError("not implemented in characteristic 2") - elif char==3: - if j==0: + elif char == 3: + if j == 0: raise NotImplementedError("not implemented in characteristic 3 for curves of j-invariant 0") D = E.b2()/F.b2() @@ -436,18 +453,18 @@ def is_quadratic_twist(self, other): c4E,c6E = E.c_invariants() c4F,c6F = F.c_invariants() - if j==0: + if j == 0: um = c6E/c6F - x=rings.polygen(K) - ulist=(x**3-um).roots(multiplicities=False) + x = polygen(K) + ulist = (x**3-um).roots(multiplicities=False) if not ulist: D = zero else: D = ulist[0] - elif j==1728: - um=c4E/c4F - x=rings.polygen(K) - ulist=(x**2-um).roots(multiplicities=False) + elif j == 1728: + um = c4E/c4F + x = polygen(K) + ulist = (x**2-um).roots(multiplicities=False) if not ulist: D = zero else: @@ -460,7 +477,7 @@ def is_quadratic_twist(self, other): if D.is_zero(): return D - if K is rings.QQ: + if K is QQ: D = D.squarefree_part() assert E.quadratic_twist(D).is_isomorphic(F) @@ -512,18 +529,18 @@ def is_quartic_twist(self, other): zero = K.zero() if not K == F.base_ring(): return zero - j=E.j_invariant() - if j != F.j_invariant() or j!=K(1728): + j = E.j_invariant() + if j != F.j_invariant() or j != K(1728): return zero if E.is_isomorphic(F): return K.one() - char=K.characteristic() + char = K.characteristic() - if char==2: + if char == 2: raise NotImplementedError("not implemented in characteristic 2") - elif char==3: + elif char == 3: raise NotImplementedError("not implemented in characteristic 3") else: # now char!=2,3: @@ -558,7 +575,7 @@ def is_sextic_twist(self, other): sage: E = EllipticCurve_from_j(GF(13)(0)) sage: E1 = E.sextic_twist(2) - sage: D = E.is_sextic_twist(E1); D!=0 + sage: D = E.is_sextic_twist(E1); D != 0 True sage: E.sextic_twist(D).is_isomorphic(E1) True @@ -581,18 +598,18 @@ def is_sextic_twist(self, other): zero = K.zero() if not K == F.base_ring(): return zero - j=E.j_invariant() + j = E.j_invariant() if j != F.j_invariant() or not j.is_zero(): return zero if E.is_isomorphic(F): return K.one() - char=K.characteristic() + char = K.characteristic() - if char==2: + if char == 2: raise NotImplementedError("not implemented in characteristic 2") - elif char==3: + elif char == 3: raise NotImplementedError("not implemented in characteristic 3") else: # now char!=2,3: @@ -641,48 +658,56 @@ def descend_to(self, K, f=None): :: + sage: # needs sage.rings.number_field sage: F.<b> = QuadraticField(23) - sage: G.<a> = F.extension(x^3+5) + sage: x = polygen(ZZ, 'x') + sage: G.<a> = F.extension(x^3 + 5) sage: E = EllipticCurve(j=1728*b).change_ring(G) sage: EF = E.descend_to(F); EF - [Elliptic Curve defined by y^2 = x^3 + (27*b-621)*x + (-1296*b+2484) over Number Field in b with defining polynomial x^2 - 23 with b = 4.795831523312720?] + [Elliptic Curve defined by y^2 = x^3 + (27*b-621)*x + (-1296*b+2484) + over Number Field in b with defining polynomial x^2 - 23 + with b = 4.795831523312720?] sage: all(Ei.change_ring(G).is_isomorphic(E) for Ei in EF) True :: + sage: # needs sage.rings.number_field sage: L.<a> = NumberField(x^4 - 7) sage: K.<b> = NumberField(x^2 - 7, embedding=a^2) - sage: E = EllipticCurve([a^6,0]) + sage: E = EllipticCurve([a^6, 0]) sage: EK = E.descend_to(K); EK - [Elliptic Curve defined by y^2 = x^3 + b*x over Number Field in b with defining polynomial x^2 - 7 with b = a^2, - Elliptic Curve defined by y^2 = x^3 + 7*b*x over Number Field in b with defining polynomial x^2 - 7 with b = a^2] + [Elliptic Curve defined by y^2 = x^3 + b*x over Number Field in b + with defining polynomial x^2 - 7 with b = a^2, + Elliptic Curve defined by y^2 = x^3 + 7*b*x over Number Field in b + with defining polynomial x^2 - 7 with b = a^2] sage: all(Ei.change_ring(L).is_isomorphic(E) for Ei in EK) True :: - sage: K.<a> = QuadraticField(17) - sage: E = EllipticCurve(j = 2*a) - sage: E.descend_to(QQ) + sage: K.<a> = QuadraticField(17) # needs sage.rings.number_field + sage: E = EllipticCurve(j=2*a) # needs sage.rings.number_field + sage: E.descend_to(QQ) # needs sage.rings.number_field [] TESTS: Check that :trac:`16456` is fixed:: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve('11a1').quadratic_twist(2) sage: EK = E.change_ring(K) sage: EK2 = EK.change_weierstrass_model((a,a,a,a+1)) sage: EK2.descend_to(QQ) [Elliptic Curve defined by y^2 = x^3 + x^2 - 41*x - 199 over Rational Field] - sage: k.<i> = QuadraticField(-1) - sage: E = EllipticCurve(k,[0,0,0,1,0]) - sage: E.descend_to(QQ) + sage: k.<i> = QuadraticField(-1) # needs sage.rings.number_field + sage: E = EllipticCurve(k,[0,0,0,1,0]) # needs sage.rings.number_field + sage: E.descend_to(QQ) # needs sage.rings.number_field [Elliptic Curve defined by y^2 = x^3 + x over Rational Field, - Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field] + Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field] """ if not K.is_field(): raise TypeError("Input must be a field.") @@ -696,7 +721,6 @@ def descend_to(self, K, f=None): # j-invariant is in the image, otherwise return an empty list: j = self.j_invariant() - from sage.rings.rational_field import QQ if K == QQ: try: jK = QQ(j) @@ -806,6 +830,7 @@ def division_field(self, l, names='t', map=False, **kwds): The 2-division field is the same as the splitting field of the 2-division polynomial (therefore, it has degree 1, 2, 3 or 6):: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('15a1') sage: K.<b> = E.division_field(2); K Number Field in b with defining polynomial x @@ -817,64 +842,82 @@ def division_field(self, l, names='t', map=False, **kwds): Number Field in b with defining polynomial x^3 + x^2 - 114*x - 127 sage: E = EllipticCurve('19a1') sage: K.<b> = E.division_field(2); K - Number Field in b with defining polynomial x^6 + 10*x^5 + 24*x^4 - 212*x^3 + 1364*x^2 + 24072*x + 104292 + Number Field in b with defining polynomial + x^6 + 10*x^5 + 24*x^4 - 212*x^3 + 1364*x^2 + 24072*x + 104292 For odd primes `\ell`, the division field is either the splitting field of the `\ell`-division polynomial, or a quadratic extension of it. :: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('50a1') sage: F.<a> = E.division_polynomial(3).splitting_field(simplify_all=True); F - Number Field in a with defining polynomial x^6 - 3*x^5 + 4*x^4 - 3*x^3 - 2*x^2 + 3*x + 3 + Number Field in a + with defining polynomial x^6 - 3*x^5 + 4*x^4 - 3*x^3 - 2*x^2 + 3*x + 3 sage: K.<b> = E.division_field(3, simplify_all=True); K - Number Field in b with defining polynomial x^6 - 3*x^5 + 4*x^4 - 3*x^3 - 2*x^2 + 3*x + 3 + Number Field in b + with defining polynomial x^6 - 3*x^5 + 4*x^4 - 3*x^3 - 2*x^2 + 3*x + 3 If we take any quadratic twist, the splitting field of the 3-division polynomial remains the same, but the 3-division field becomes a quadratic extension:: + sage: # needs sage.rings.number_field sage: E = E.quadratic_twist(5) # 50b3 sage: F.<a> = E.division_polynomial(3).splitting_field(simplify_all=True); F - Number Field in a with defining polynomial x^6 - 3*x^5 + 4*x^4 - 3*x^3 - 2*x^2 + 3*x + 3 + Number Field in a + with defining polynomial x^6 - 3*x^5 + 4*x^4 - 3*x^3 - 2*x^2 + 3*x + 3 sage: K.<b> = E.division_field(3, simplify_all=True); K - Number Field in b with defining polynomial x^12 - 3*x^11 + 8*x^10 - 15*x^9 + 30*x^8 - 63*x^7 + 109*x^6 - 144*x^5 + 150*x^4 - 120*x^3 + 68*x^2 - 24*x + 4 + Number Field in b with defining polynomial x^12 - 3*x^11 + 8*x^10 - 15*x^9 + + 30*x^8 - 63*x^7 + 109*x^6 - 144*x^5 + 150*x^4 - 120*x^3 + 68*x^2 - 24*x + 4 Try another quadratic twist, this time over a subfield of `F`:: + sage: # needs sage.rings.number_field sage: G.<c>,_,_ = F.subfields(3)[0] sage: E = E.base_extend(G).quadratic_twist(c); E - Elliptic Curve defined by y^2 = x^3 + 5*a0*x^2 + (-200*a0^2)*x + (-42000*a0^2+42000*a0+126000) over Number Field in a0 with defining polynomial x^3 - 3*x^2 + 3*x + 9 + Elliptic Curve defined + by y^2 = x^3 + 5*a0*x^2 + (-200*a0^2)*x + (-42000*a0^2+42000*a0+126000) + over Number Field in a0 with defining polynomial x^3 - 3*x^2 + 3*x + 9 sage: K.<b> = E.division_field(3, simplify_all=True); K - Number Field in b with defining polynomial x^12 + 5*x^10 + 40*x^8 + 315*x^6 + 750*x^4 + 675*x^2 + 2025 + Number Field in b with defining polynomial + x^12 + 5*x^10 + 40*x^8 + 315*x^6 + 750*x^4 + 675*x^2 + 2025 Some higher-degree examples:: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('11a1') sage: K.<b> = E.division_field(2); K - Number Field in b with defining polynomial x^6 + 2*x^5 - 48*x^4 - 436*x^3 + 1668*x^2 + 28792*x + 73844 - sage: K.<b> = E.division_field(3); K # long time (3s on sage.math, 2014) + Number Field in b with defining polynomial + x^6 + 2*x^5 - 48*x^4 - 436*x^3 + 1668*x^2 + 28792*x + 73844 + sage: K.<b> = E.division_field(3); K # long time Number Field in b with defining polynomial x^48 ... sage: K.<b> = E.division_field(5); K Number Field in b with defining polynomial x^4 - x^3 + x^2 - x + 1 sage: E.division_field(5, 'b', simplify=False) Number Field in b with defining polynomial x^4 + x^3 + 11*x^2 + 41*x + 101 - sage: E.base_extend(K).torsion_subgroup() # long time (2s on sage.math, 2014) - Torsion Subgroup isomorphic to Z/5 + Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in b with defining polynomial x^4 - x^3 + x^2 - x + 1 + sage: E.base_extend(K).torsion_subgroup() # long time + Torsion Subgroup isomorphic to Z/5 + Z/5 associated to the Elliptic Curve + defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) + over Number Field in b with defining polynomial x^4 - x^3 + x^2 - x + 1 + sage: # needs sage.rings.number_field sage: E = EllipticCurve('27a1') sage: K.<b> = E.division_field(3); K Number Field in b with defining polynomial x^2 + 3*x + 9 sage: K.<b> = E.division_field(2); K - Number Field in b with defining polynomial x^6 + 6*x^5 + 24*x^4 - 52*x^3 - 228*x^2 + 744*x + 3844 + Number Field in b with defining polynomial + x^6 + 6*x^5 + 24*x^4 - 52*x^3 - 228*x^2 + 744*x + 3844 sage: K.<b> = E.division_field(2, simplify_all=True); K Number Field in b with defining polynomial x^6 - 3*x^5 + 5*x^3 - 3*x + 1 - sage: K.<b> = E.division_field(5); K # long time (4s on sage.math, 2014) + sage: K.<b> = E.division_field(5); K # long time Number Field in b with defining polynomial x^48 ... - sage: K.<b> = E.division_field(7); K # long time (8s on sage.math, 2014) + sage: K.<b> = E.division_field(7); K # long time Number Field in b with defining polynomial x^72 ... Over a number field:: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve([0,0,0,0,i]) @@ -887,7 +930,11 @@ def division_field(self, l, names='t', map=False, **kwds): Defn: i |--> -b^3 sage: L.<b>, phi = E.division_field(3, map=True) sage: L - Number Field in b with defining polynomial x^24 - 6*x^22 - 12*x^21 - 21*x^20 + 216*x^19 + 48*x^18 + 804*x^17 + 1194*x^16 - 13488*x^15 + 21222*x^14 + 44196*x^13 - 47977*x^12 - 102888*x^11 + 173424*x^10 - 172308*x^9 + 302046*x^8 + 252864*x^7 - 931182*x^6 + 180300*x^5 + 879567*x^4 - 415896*x^3 + 1941012*x^2 + 650220*x + 443089 + Number Field in b with defining polynomial x^24 - 6*x^22 - 12*x^21 + - 21*x^20 + 216*x^19 + 48*x^18 + 804*x^17 + 1194*x^16 - 13488*x^15 + + 21222*x^14 + 44196*x^13 - 47977*x^12 - 102888*x^11 + 173424*x^10 + - 172308*x^9 + 302046*x^8 + 252864*x^7 - 931182*x^6 + 180300*x^5 + + 879567*x^4 - 415896*x^3 + 1941012*x^2 + 650220*x + 443089 sage: phi Ring morphism: From: Number Field in i with defining polynomial x^2 + 1 @@ -896,8 +943,8 @@ def division_field(self, l, names='t', map=False, **kwds): Over a finite field:: - sage: E = EllipticCurve(GF(431^2), [1,0]) - sage: E.division_field(5, map=True) + sage: E = EllipticCurve(GF(431^2), [1,0]) # needs sage.rings.finite_rings + sage: E.division_field(5, map=True) # needs sage.rings.finite_rings (Finite Field in t of size 431^4, Ring morphism: From: Finite Field in z2 of size 431^2 @@ -906,8 +953,8 @@ def division_field(self, l, names='t', map=False, **kwds): :: - sage: E = EllipticCurve(GF(433^2), [1,0]) - sage: K.<v> = E.division_field(7); K + sage: E = EllipticCurve(GF(433^2), [1,0]) # needs sage.rings.finite_rings + sage: K.<v> = E.division_field(7); K # needs sage.rings.finite_rings Finite Field in v of size 433^16 .. SEEALSO:: @@ -922,6 +969,7 @@ def division_field(self, l, names='t', map=False, **kwds): Some random testing:: + sage: # needs sage.rings.finite_rings sage: def check(E, l, K): ....: EE = E.change_ring(K) ....: cof = EE.order().prime_to_m_part(l) @@ -958,7 +1006,7 @@ def division_field(self, l, names='t', map=False, **kwds): sage: n = E.cardinality(extension_degree=K.degree()//F.degree()) sage: (l^2 if q%l else 0 + E.is_ordinary()).divides(n) True - sage: check(E, l, K) # long time + sage: check(E, l, K) # long time AUTHORS: @@ -968,7 +1016,7 @@ def division_field(self, l, names='t', map=False, **kwds): - Lorenz Panny (2022): extend to finite fields """ from sage.misc.verbose import verbose - l = rings.Integer(l) + l = Integer(l) if not l.is_prime(): raise ValueError("l must be a prime number") @@ -1024,7 +1072,7 @@ def division_field(self, l, names='t', map=False, **kwds): # Polynomial defining the corresponding Y-coordinate curve = self.defining_polynomial().map_coefficients(F_to_K) - ypol = curve(X, rings.polygen(K), 1) + ypol = curve(X, polygen(K), 1) L = ypol.splitting_field(names, map=map, **kwds) if map: L, K_to_L = L @@ -1086,12 +1134,12 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al - ``degree`` -- an integer (default: ``None``). - - If ``kernel`` is ``None``, then this is the degree of the isogeny - from this curve to ``codomain``. + - If ``kernel`` is ``None``, then this is the degree of the isogeny + from this curve to ``codomain``. - - If ``kernel`` is not ``None``, then this is used to determine - whether or not to skip a `\gcd` of the given kernel polynomial - with the two-torsion polynomial of this curve. + - If ``kernel`` is not ``None``, then this is used to determine + whether or not to skip a `\gcd` of the given kernel polynomial + with the two-torsion polynomial of this curve. - ``model`` -- a string (default: ``None``). Supported values (cf. :func:`~sage.schemes.elliptic_curves.ell_field.compute_model`): @@ -1132,10 +1180,11 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(2^5, 'alpha'); alpha = F.gen() sage: E = EllipticCurve(F, [1,0,1,1,1]) sage: R.<x> = F[] - sage: phi = E.isogeny(x+1) + sage: phi = E.isogeny(x + 1) sage: phi.rational_maps() ((x^2 + x + 1)/(x + 1), (x^2*y + x)/(x^2 + 1)) @@ -1144,35 +1193,45 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al sage: E = EllipticCurve('11a1') sage: P = E.torsion_points()[1] sage: E.isogeny(P) - Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field + Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 + over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 + over Rational Field :: sage: E = EllipticCurve(GF(19),[1,1]) - sage: P = E(15,3); Q = E(2,12); + sage: P = E(15,3); Q = E(2,12) sage: (P.order(), Q.order()) (7, 3) sage: phi = E.isogeny([P,Q]); phi - Isogeny of degree 21 from Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 19 to Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 19 - sage: phi(E.random_point()) # all points defined over GF(19) are in the kernel + Isogeny of degree 21 + from Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 19 + to Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 19 + sage: phi(E.random_point()) # all points defined over GF(19) are in the kernel (0 : 1 : 0) :: - sage: E = EllipticCurve(GF(2^32-5), [170246996, 2036646110]) - sage: P = E.lift_x(2) - sage: E.isogeny(P, algorithm="factored") + sage: E = EllipticCurve(GF(2^32 - 5), [170246996, 2036646110]) # needs sage.rings.finite_rings + sage: P = E.lift_x(2) # needs sage.rings.finite_rings + sage: E.isogeny(P, algorithm="factored") # needs sage.rings.finite_rings Composite morphism of degree 1073721825 = 3^4*5^2*11*19*43*59: - From: Elliptic Curve defined by y^2 = x^3 + 170246996*x + 2036646110 over Finite Field of size 4294967291 - To: Elliptic Curve defined by y^2 = x^3 + 272790262*x + 1903695400 over Finite Field of size 4294967291 + From: Elliptic Curve defined by y^2 = x^3 + 170246996*x + 2036646110 + over Finite Field of size 4294967291 + To: Elliptic Curve defined by y^2 = x^3 + 272790262*x + 1903695400 + over Finite Field of size 4294967291 Not all polynomials define a finite subgroup (:trac:`6384`):: - sage: E = EllipticCurve(GF(31),[1,0,0,1,2]) + sage: E = EllipticCurve(GF(31), [1,0,0,1,2]) sage: phi = E.isogeny([14,27,4,1]) Traceback (most recent call last): ... - ValueError: the polynomial x^3 + 4*x^2 + 27*x + 14 does not define a finite subgroup of Elliptic Curve defined by y^2 + x*y = x^3 + x + 2 over Finite Field of size 31 + ValueError: the polynomial x^3 + 4*x^2 + 27*x + 14 does not define a finite + subgroup of Elliptic Curve defined by y^2 + x*y = x^3 + x + 2 + over Finite Field of size 31 .. SEEALSO:: @@ -1186,18 +1245,22 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al :trac:`23222`, the following raised no error but returned an invalid morphism. See also :trac:`11578`:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^2-x-1) + sage: K.<a> = NumberField(x^2 - x - 1) sage: E = EllipticCurve(K, [-13392, -1080432]) sage: R.<x> = K[] sage: phi = E.isogeny( (x-564)*(x - 396/5*a + 348/5) ) Traceback (most recent call last): ... - ValueError: the polynomial x^2 + (-396/5*a - 2472/5)*x + 223344/5*a - 196272/5 does not define a finite subgroup of Elliptic Curve defined by y^2 = x^3 + (-13392)*x + (-1080432) over Number Field in a with defining polynomial x^2 - x - 1 + ValueError: the polynomial x^2 + (-396/5*a - 2472/5)*x + 223344/5*a - 196272/5 does not + define a finite subgroup of Elliptic Curve defined by y^2 = x^3 + (-13392)*x + (-1080432) + over Number Field in a with defining polynomial x^2 - x - 1 We check that the cached order is correctly copied over:: - sage: E = EllipticCurve(GF(2^127-1), [1,2,3,4,5]) + sage: # needs sage.rings.finite_rings + sage: E = EllipticCurve(GF(2^127 - 1), [1,2,3,4,5]) sage: E.set_order(170141183460469231746191640949390434666) sage: phi = E.isogeny(E.lift_x(77347718128277853096420969229987528666)) sage: phi.codomain()._order @@ -1216,15 +1279,14 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al except AttributeError as e: raise RuntimeError("Unable to construct isogeny: %s" % e) - def isogeny_codomain(self, kernel, degree=None): + def isogeny_codomain(self, kernel): r""" Return the codomain of the isogeny from ``self`` with given kernel. INPUT: - ``kernel`` -- Either a list of points in the kernel of the isogeny, - or a kernel polynomial (specified as either a - univariate polynomial or a coefficient list.) + or a kernel polynomial (specified as either a univariate polynomial or a coefficient list.) OUTPUT: @@ -1236,31 +1298,20 @@ def isogeny_codomain(self, kernel, degree=None): sage: E = EllipticCurve('17a1') sage: R.<x> = QQ[] sage: E2 = E.isogeny_codomain(x - 11/4); E2 - Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 1461/16*x - 19681/64 over Rational Field + Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 1461/16*x - 19681/64 + over Rational Field TESTS: We check that the cached order is correctly copied over:: - sage: E = EllipticCurve(GF(2^127-1), [1,2,3,4,5]) + sage: # needs sage.rings.finite_rings + sage: E = EllipticCurve(GF(2^127 - 1), [1,2,3,4,5]) sage: E.set_order(170141183460469231746191640949390434666) sage: E2 = E.isogeny_codomain(E.lift_x(77347718128277853096420969229987528666)) sage: E2._order 170141183460469231746191640949390434666 - - Test deprecation warning for obsolete argument:: - - sage: E.isogeny_codomain(E.lift_x(77347718128277853096420969229987528666), degree=11) - doctest:warning - ... - DeprecationWarning: The "degree" argument to .isogeny_codomain() does nothing and will be removed. - ... - Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 20731788786372791581385345584850817122*x + 125200507378516567345719286707201096361 over Finite Field of size 170141183460469231731687303715884105727 """ - if degree is not None: - from sage.misc.superseded import deprecation - deprecation(33619, 'The "degree" argument to .isogeny_codomain() does nothing and will be removed.') - E = isogeny_codomain_from_kernel(self, kernel) if self.base_field().is_finite(): E._fetch_cached_order(self) @@ -1294,11 +1345,18 @@ def isogenies_prime_degree(self, l=None, max_l=31): Examples over finite fields:: + sage: # needs sage.libs.pari sage: E = EllipticCurve(GF(next_prime(1000000)), [7,8]) sage: E.isogenies_prime_degree(2) - [Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 970389*x + 794257 over Finite Field of size 1000003, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 29783*x + 206196 over Finite Field of size 1000003, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 999960*x + 78 over Finite Field of size 1000003] + [Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 970389*x + 794257 over Finite Field of size 1000003, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 29783*x + 206196 over Finite Field of size 1000003, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 999960*x + 78 over Finite Field of size 1000003] sage: E.isogenies_prime_degree(3) [] sage: E.isogenies_prime_degree(5) @@ -1308,62 +1366,128 @@ def isogenies_prime_degree(self, l=None, max_l=31): sage: E.isogenies_prime_degree(11) [] sage: E.isogenies_prime_degree(13) - [Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 878063*x + 845666 over Finite Field of size 1000003, - Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 375648*x + 342776 over Finite Field of size 1000003] + [Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 878063*x + 845666 over Finite Field of size 1000003, + Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 375648*x + 342776 over Finite Field of size 1000003] sage: E.isogenies_prime_degree(max_l=13) - [Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 970389*x + 794257 over Finite Field of size 1000003, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 29783*x + 206196 over Finite Field of size 1000003, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 999960*x + 78 over Finite Field of size 1000003, - Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 878063*x + 845666 over Finite Field of size 1000003, - Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 375648*x + 342776 over Finite Field of size 1000003] + [Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 970389*x + 794257 over Finite Field of size 1000003, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 29783*x + 206196 over Finite Field of size 1000003, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 999960*x + 78 over Finite Field of size 1000003, + Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 878063*x + 845666 over Finite Field of size 1000003, + Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 375648*x + 342776 over Finite Field of size 1000003] sage: E.isogenies_prime_degree() # Default limit of 31 - [Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 970389*x + 794257 over Finite Field of size 1000003, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 29783*x + 206196 over Finite Field of size 1000003, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 999960*x + 78 over Finite Field of size 1000003, - Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 878063*x + 845666 over Finite Field of size 1000003, - Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 375648*x + 342776 over Finite Field of size 1000003, - Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 347438*x + 594729 over Finite Field of size 1000003, - Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 674846*x + 7392 over Finite Field of size 1000003, - Isogeny of degree 23 from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 to Elliptic Curve defined by y^2 = x^3 + 390065*x + 605596 over Finite Field of size 1000003] + [Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 970389*x + 794257 over Finite Field of size 1000003, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 29783*x + 206196 over Finite Field of size 1000003, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 999960*x + 78 over Finite Field of size 1000003, + Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 878063*x + 845666 over Finite Field of size 1000003, + Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 375648*x + 342776 over Finite Field of size 1000003, + Isogeny of degree 17 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 347438*x + 594729 over Finite Field of size 1000003, + Isogeny of degree 17 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 674846*x + 7392 over Finite Field of size 1000003, + Isogeny of degree 23 + from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003 + to Elliptic Curve defined by y^2 = x^3 + 390065*x + 605596 over Finite Field of size 1000003] sage: E = EllipticCurve(GF(17), [2,0]) sage: E.isogenies_prime_degree(3) [] sage: E.isogenies_prime_degree(2) - [Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 17 to Elliptic Curve defined by y^2 = x^3 + 9*x over Finite Field of size 17, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 17 to Elliptic Curve defined by y^2 = x^3 + 5*x + 9 over Finite Field of size 17, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 17 to Elliptic Curve defined by y^2 = x^3 + 5*x + 8 over Finite Field of size 17] + [Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 17 + to Elliptic Curve defined by y^2 = x^3 + 9*x over Finite Field of size 17, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 17 + to Elliptic Curve defined by y^2 = x^3 + 5*x + 9 over Finite Field of size 17, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 17 + to Elliptic Curve defined by y^2 = x^3 + 5*x + 8 over Finite Field of size 17] The base field matters, over a field extension we find more isogenies:: sage: E = EllipticCurve(GF(13), [2,8]) sage: E.isogenies_prime_degree(max_l=3) - [Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field of size 13 to Elliptic Curve defined by y^2 = x^3 + 7*x + 4 over Finite Field of size 13, - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field of size 13 to Elliptic Curve defined by y^2 = x^3 + 9*x + 11 over Finite Field of size 13] + [Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field of size 13 + to Elliptic Curve defined by y^2 = x^3 + 7*x + 4 over Finite Field of size 13, + Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field of size 13 + to Elliptic Curve defined by y^2 = x^3 + 9*x + 11 over Finite Field of size 13] + + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(13^6), [2,8]) sage: E.isogenies_prime_degree(max_l=3) - [Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 to Elliptic Curve defined by y^2 = x^3 + 7*x + 4 over Finite Field in z6 of size 13^6, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 to Elliptic Curve defined by y^2 = x^3 + (2*z6^5+6*z6^4+9*z6^3+8*z6+7)*x + (3*z6^5+9*z6^4+7*z6^3+12*z6+7) over Finite Field in z6 of size 13^6, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 to Elliptic Curve defined by y^2 = x^3 + (11*z6^5+7*z6^4+4*z6^3+5*z6+9)*x + (10*z6^5+4*z6^4+6*z6^3+z6+10) over Finite Field in z6 of size 13^6, - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 to Elliptic Curve defined by y^2 = x^3 + 9*x + 11 over Finite Field in z6 of size 13^6, - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 to Elliptic Curve defined by y^2 = x^3 + (3*z6^5+5*z6^4+8*z6^3+11*z6^2+5*z6+12)*x + (12*z6^5+6*z6^4+8*z6^3+4*z6^2+7*z6+6) over Finite Field in z6 of size 13^6, - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 to Elliptic Curve defined by y^2 = x^3 + (7*z6^4+12*z6^3+7*z6^2+4)*x + (6*z6^5+10*z6^3+12*z6^2+10*z6+8) over Finite Field in z6 of size 13^6, - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 to Elliptic Curve defined by y^2 = x^3 + (10*z6^5+z6^4+6*z6^3+8*z6^2+8*z6)*x + (8*z6^5+7*z6^4+8*z6^3+10*z6^2+9*z6+7) over Finite Field in z6 of size 13^6] + [Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 + to Elliptic Curve defined by y^2 = x^3 + 7*x + 4 over Finite Field in z6 of size 13^6, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 + to Elliptic Curve defined by y^2 = x^3 + (2*z6^5+6*z6^4+9*z6^3+8*z6+7)*x + (3*z6^5+9*z6^4+7*z6^3+12*z6+7) over Finite Field in z6 of size 13^6, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 + to Elliptic Curve defined by y^2 = x^3 + (11*z6^5+7*z6^4+4*z6^3+5*z6+9)*x + (10*z6^5+4*z6^4+6*z6^3+z6+10) over Finite Field in z6 of size 13^6, + Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 + to Elliptic Curve defined by y^2 = x^3 + 9*x + 11 over Finite Field in z6 of size 13^6, + Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 + to Elliptic Curve defined by y^2 = x^3 + (3*z6^5+5*z6^4+8*z6^3+11*z6^2+5*z6+12)*x + (12*z6^5+6*z6^4+8*z6^3+4*z6^2+7*z6+6) over Finite Field in z6 of size 13^6, + Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 + to Elliptic Curve defined by y^2 = x^3 + (7*z6^4+12*z6^3+7*z6^2+4)*x + (6*z6^5+10*z6^3+12*z6^2+10*z6+8) over Finite Field in z6 of size 13^6, + Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6 + to Elliptic Curve defined by y^2 = x^3 + (10*z6^5+z6^4+6*z6^3+8*z6^2+8*z6)*x + (8*z6^5+7*z6^4+8*z6^3+10*z6^2+9*z6+7) over Finite Field in z6 of size 13^6] If the degree equals the characteristic, we find only separable isogenies:: sage: E = EllipticCurve(GF(13), [2,8]) sage: E.isogenies_prime_degree(13) - [Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field of size 13 to Elliptic Curve defined by y^2 = x^3 + 6*x + 5 over Finite Field of size 13] + [Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field of size 13 + to Elliptic Curve defined by y^2 = x^3 + 6*x + 5 over Finite Field of size 13] sage: E = EllipticCurve(GF(5), [1,1]) sage: E.isogenies_prime_degree(5) - [Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 to Elliptic Curve defined by y^2 = x^3 + x + 4 over Finite Field of size 5] + [Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 + to Elliptic Curve defined by y^2 = x^3 + x + 4 over Finite Field of size 5] + + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(3^4) sage: E = EllipticCurve(k, [0,1,0,0,a]) sage: E.isogenies_prime_degree(3) - [Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + x^2 + a over Finite Field in a of size 3^4 to Elliptic Curve defined by y^2 = x^3 + x^2 + (2*a^3+a^2+2)*x + (a^2+2) over Finite Field in a of size 3^4] + [Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + x^2 + a + over Finite Field in a of size 3^4 + to Elliptic Curve defined by y^2 = x^3 + x^2 + (2*a^3+a^2+2)*x + (a^2+2) + over Finite Field in a of size 3^4] In the supersingular case, there are no separable isogenies of degree equal to the characteristic:: @@ -1378,40 +1502,72 @@ def isogenies_prime_degree(self, l=None, max_l=31): sage: K = R.fraction_field() sage: E = EllipticCurve(K, [1, t^5]) sage: E.isogenies_prime_degree(5) - [Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + x + t^5 over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 to Elliptic Curve defined by y^2 = x^3 + x + 4*t over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5] + [Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + x + t^5 over Fraction Field + of Univariate Polynomial Ring in t over Finite Field of size 5 + to Elliptic Curve defined by y^2 = x^3 + x + 4*t over Fraction Field + of Univariate Polynomial Ring in t over Finite Field of size 5] Examples over number fields (other than QQ):: - sage: QQroot2.<e> = NumberField(x^2-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: QQroot2.<e> = NumberField(x^2 - 2) sage: E = EllipticCurve(QQroot2, j=8000) sage: E.isogenies_prime_degree() - [Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + (-150528000)*x + (-629407744000) over Number Field in e with defining polynomial x^2 - 2 to Elliptic Curve defined by y^2 = x^3 + (-36750)*x + 2401000 over Number Field in e with defining polynomial x^2 - 2, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + (-150528000)*x + (-629407744000) over Number Field in e with defining polynomial x^2 - 2 to Elliptic Curve defined by y^2 = x^3 + (220500*e-257250)*x + (54022500*e-88837000) over Number Field in e with defining polynomial x^2 - 2, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + (-150528000)*x + (-629407744000) over Number Field in e with defining polynomial x^2 - 2 to Elliptic Curve defined by y^2 = x^3 + (-220500*e-257250)*x + (-54022500*e-88837000) over Number Field in e with defining polynomial x^2 - 2] - + [Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + (-150528000)*x + (-629407744000) + over Number Field in e with defining polynomial x^2 - 2 + to Elliptic Curve defined by y^2 = x^3 + (-36750)*x + 2401000 + over Number Field in e with defining polynomial x^2 - 2, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + (-150528000)*x + (-629407744000) + over Number Field in e with defining polynomial x^2 - 2 + to Elliptic Curve defined by y^2 = x^3 + (220500*e-257250)*x + (54022500*e-88837000) + over Number Field in e with defining polynomial x^2 - 2, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + (-150528000)*x + (-629407744000) + over Number Field in e with defining polynomial x^2 - 2 + to Elliptic Curve defined by y^2 = x^3 + (-220500*e-257250)*x + (-54022500*e-88837000) + over Number Field in e with defining polynomial x^2 - 2] sage: E = EllipticCurve(QQroot2, [1,0,1,4, -6]); E - Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6) over Number Field in e with defining polynomial x^2 - 2 + Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6) + over Number Field in e with defining polynomial x^2 - 2 sage: E.isogenies_prime_degree(2) - [Isogeny of degree 2 from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6) over Number Field in e with defining polynomial x^2 - 2 to Elliptic Curve defined by y^2 + x*y + y = x^3 + (-36)*x + (-70) over Number Field in e with defining polynomial x^2 - 2] + [Isogeny of degree 2 + from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6) + over Number Field in e with defining polynomial x^2 - 2 + to Elliptic Curve defined by y^2 + x*y + y = x^3 + (-36)*x + (-70) + over Number Field in e with defining polynomial x^2 - 2] sage: E.isogenies_prime_degree(3) - [Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6) over Number Field in e with defining polynomial x^2 - 2 to Elliptic Curve defined by y^2 + x*y + y = x^3 + (-1)*x over Number Field in e with defining polynomial x^2 - 2, - Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6) over Number Field in e with defining polynomial x^2 - 2 to Elliptic Curve defined by y^2 + x*y + y = x^3 + (-171)*x + (-874) over Number Field in e with defining polynomial x^2 - 2] + [Isogeny of degree 3 + from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6) + over Number Field in e with defining polynomial x^2 - 2 + to Elliptic Curve defined by y^2 + x*y + y = x^3 + (-1)*x + over Number Field in e with defining polynomial x^2 - 2, + Isogeny of degree 3 + from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6) + over Number Field in e with defining polynomial x^2 - 2 + to Elliptic Curve defined by y^2 + x*y + y = x^3 + (-171)*x + (-874) + over Number Field in e with defining polynomial x^2 - 2] These are not implemented yet:: - sage: E = EllipticCurve(QQbar, [1,18]); E + sage: E = EllipticCurve(QQbar, [1,18]); E # needs sage.rings.number_field Elliptic Curve defined by y^2 = x^3 + x + 18 over Algebraic Field - sage: E.isogenies_prime_degree() + sage: E.isogenies_prime_degree() # needs sage.rings.number_field Traceback (most recent call last): ... NotImplementedError: This code could be implemented for QQbar, but has not been yet. sage: E = EllipticCurve(CC, [1,18]); E - Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 18.0000000000000 over Complex Field with 53 bits of precision + Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 18.0000000000000 + over Complex Field with 53 bits of precision sage: E.isogenies_prime_degree(11) Traceback (most recent call last): ... - NotImplementedError: This code could be implemented for general complex fields, but has not been yet. + NotImplementedError: This code could be implemented for general complex fields, + but has not been yet. TESTS:: @@ -1430,19 +1586,19 @@ def isogenies_prime_degree(self, l=None, max_l=31): raise NotImplementedError("This code could be implemented for general real fields, but has not been yet.") if isinstance(F, sage.rings.abc.ComplexField): raise NotImplementedError("This code could be implemented for general complex fields, but has not been yet.") - if F is rings.QQbar: + if isinstance(F, sage.rings.abc.AlgebraicField): raise NotImplementedError("This code could be implemented for QQbar, but has not been yet.") if l is None: - from sage.rings.all import prime_range + from sage.rings.fast_arith import prime_range L = prime_range(max_l + 1) else: try: l = list(l) except TypeError: - L = [rings.ZZ(l)] + L = [ZZ(l)] else: - L = [rings.ZZ(d) for d in l] + L = [ZZ(d) for d in l] from .isogeny_small_degree import isogenies_prime_degree return sum([isogenies_prime_degree(self, d) for d in L], []) @@ -1458,7 +1614,7 @@ def is_isogenous(self, other, field=None): - ``field`` (default None) -- Currently not implemented. A field containing the base fields of the two elliptic curves onto which the two curves may be extended to test if they - are isogenous over this field. By default is_isogenous will + are isogenous over this field. By default ``is_isogenous`` will not try to find this field unless one of the curves can be be extended into the base field of the other, in which case it will test over the larger base field. @@ -1475,18 +1631,22 @@ def is_isogenous(self, other, field=None): EXAMPLES:: sage: E1 = EllipticCurve(CC, [1,18]); E1 - Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 18.0000000000000 over Complex Field with 53 bits of precision + Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 18.0000000000000 + over Complex Field with 53 bits of precision sage: E2 = EllipticCurve(CC, [2,7]); E2 - Elliptic Curve defined by y^2 = x^3 + 2.00000000000000*x + 7.00000000000000 over Complex Field with 53 bits of precision + Elliptic Curve defined by y^2 = x^3 + 2.00000000000000*x + 7.00000000000000 + over Complex Field with 53 bits of precision sage: E1.is_isogenous(E2) Traceback (most recent call last): ... NotImplementedError: Only implemented for isomorphic curves over general fields. sage: E1 = EllipticCurve(Frac(PolynomialRing(ZZ,'t')), [2,19]); E1 - Elliptic Curve defined by y^2 = x^3 + 2*x + 19 over Fraction Field of Univariate Polynomial Ring in t over Integer Ring + Elliptic Curve defined by y^2 = x^3 + 2*x + 19 + over Fraction Field of Univariate Polynomial Ring in t over Integer Ring sage: E2 = EllipticCurve(CC, [23,4]); E2 - Elliptic Curve defined by y^2 = x^3 + 23.0000000000000*x + 4.00000000000000 over Complex Field with 53 bits of precision + Elliptic Curve defined by y^2 = x^3 + 23.0000000000000*x + 4.00000000000000 + over Complex Field with 53 bits of precision sage: E1.is_isogenous(E2) Traceback (most recent call last): ... @@ -1516,7 +1676,7 @@ def weierstrass_p(self, prec=20, algorithm=None): OUTPUT: - a Laurent series in one variable `z` with coefficients in the + A Laurent series in one variable `z` with coefficients in the base field `k` of `E`. EXAMPLES:: @@ -1530,11 +1690,17 @@ def weierstrass_p(self, prec=20, algorithm=None): sage: Esh.weierstrass_p(prec=8) z^-2 + 13392/5*z^2 + 1080432/7*z^4 + 59781888/25*z^6 + O(z^8) sage: E.weierstrass_p(prec=20, algorithm='fast') - z^-2 + 31/15*z^2 + 2501/756*z^4 + 961/675*z^6 + 77531/41580*z^8 + 1202285717/928746000*z^10 + 2403461/2806650*z^12 + 30211462703/43418875500*z^14 + 3539374016033/7723451736000*z^16 + 413306031683977/1289540602350000*z^18 + O(z^20) + z^-2 + 31/15*z^2 + 2501/756*z^4 + 961/675*z^6 + 77531/41580*z^8 + + 1202285717/928746000*z^10 + 2403461/2806650*z^12 + 30211462703/43418875500*z^14 + + 3539374016033/7723451736000*z^16 + 413306031683977/1289540602350000*z^18 + O(z^20) sage: E.weierstrass_p(prec=20, algorithm='pari') - z^-2 + 31/15*z^2 + 2501/756*z^4 + 961/675*z^6 + 77531/41580*z^8 + 1202285717/928746000*z^10 + 2403461/2806650*z^12 + 30211462703/43418875500*z^14 + 3539374016033/7723451736000*z^16 + 413306031683977/1289540602350000*z^18 + O(z^20) + z^-2 + 31/15*z^2 + 2501/756*z^4 + 961/675*z^6 + 77531/41580*z^8 + + 1202285717/928746000*z^10 + 2403461/2806650*z^12 + 30211462703/43418875500*z^14 + + 3539374016033/7723451736000*z^16 + 413306031683977/1289540602350000*z^18 + O(z^20) sage: E.weierstrass_p(prec=20, algorithm='quadratic') - z^-2 + 31/15*z^2 + 2501/756*z^4 + 961/675*z^6 + 77531/41580*z^8 + 1202285717/928746000*z^10 + 2403461/2806650*z^12 + 30211462703/43418875500*z^14 + 3539374016033/7723451736000*z^16 + 413306031683977/1289540602350000*z^18 + O(z^20) + z^-2 + 31/15*z^2 + 2501/756*z^4 + 961/675*z^6 + 77531/41580*z^8 + + 1202285717/928746000*z^10 + 2403461/2806650*z^12 + 30211462703/43418875500*z^14 + + 3539374016033/7723451736000*z^16 + 413306031683977/1289540602350000*z^18 + O(z^20) """ from .ell_wp import weierstrass_p return weierstrass_p(self, prec=prec, algorithm=algorithm) @@ -1550,37 +1716,38 @@ def hasse_invariant(self): characteristic, and is an element of the field which is zero if and only if the curve is supersingular. Over a field of characteristic zero, where the Hasse invariant is undefined, - a ``ValueError`` is returned. + a ``ValueError`` is raised. EXAMPLES:: - sage: E = EllipticCurve([Mod(1,2),Mod(1,2),0,0,Mod(1,2)]) + sage: E = EllipticCurve([Mod(1,2), Mod(1,2), 0, 0, Mod(1,2)]) sage: E.hasse_invariant() 1 - sage: E = EllipticCurve([0,0,Mod(1,3),Mod(1,3),Mod(1,3)]) + sage: E = EllipticCurve([0, 0, Mod(1,3), Mod(1,3), Mod(1,3)]) sage: E.hasse_invariant() 0 - sage: E = EllipticCurve([0,0,Mod(1,5),0,Mod(2,5)]) + sage: E = EllipticCurve([0, 0, Mod(1,5), 0, Mod(2,5)]) sage: E.hasse_invariant() 0 - sage: E = EllipticCurve([0,0,Mod(1,5),Mod(1,5),Mod(2,5)]) + sage: E = EllipticCurve([0, 0, Mod(1,5), Mod(1,5), Mod(2,5)]) sage: E.hasse_invariant() 2 Some examples over larger fields:: - sage: EllipticCurve(GF(101),[0,0,0,0,1]).hasse_invariant() + sage: # needs sage.rings.finite_rings + sage: EllipticCurve(GF(101), [0,0,0,0,1]).hasse_invariant() 0 - sage: EllipticCurve(GF(101),[0,0,0,1,1]).hasse_invariant() + sage: EllipticCurve(GF(101), [0,0,0,1,1]).hasse_invariant() 98 - sage: EllipticCurve(GF(103),[0,0,0,0,1]).hasse_invariant() + sage: EllipticCurve(GF(103), [0,0,0,0,1]).hasse_invariant() 20 - sage: EllipticCurve(GF(103),[0,0,0,1,1]).hasse_invariant() + sage: EllipticCurve(GF(103), [0,0,0,1,1]).hasse_invariant() 17 sage: F.<a> = GF(107^2) - sage: EllipticCurve(F,[0,0,0,a,1]).hasse_invariant() + sage: EllipticCurve(F, [0,0,0,a,1]).hasse_invariant() 62*a + 75 - sage: EllipticCurve(F,[0,0,0,0,a]).hasse_invariant() + sage: EllipticCurve(F, [0,0,0,0,a]).hasse_invariant() 0 Over fields of characteristic zero, the Hasse invariant is @@ -1608,7 +1775,7 @@ def hasse_invariant(self): R = k['x'] x = R.gen() E = self.short_weierstrass_model() - f=(x**3+E.a4()*x+E.a6())**((p-1)//2) + f = (x**3+E.a4()*x+E.a6())**((p-1)//2) return f.coefficients(sparse=False)[p-1] def isogeny_ell_graph(self, l, directed=True, label_by_j=False): @@ -1634,17 +1801,16 @@ class of curves. If the j-invariant is not unique in the isogeny class, append ``*`` to it to indicate a twist. Otherwise, if ``False`` label vertices by the equation of a representative curve. - OUTPUT: - - A ``Graph`` or ``Digraph`` + OUTPUT: A :class:`Graph` or :class:`DiGraph`. EXAMPLES: Ordinary curve over finite extension field of degree 2:: + sage: # needs sage.graphs sage.rings.finite_rings + sage: x = polygen(ZZ, 'x') sage: E = EllipticCurve(GF(59^2, "i", x^2 + 1), j=5) - sage: G = E.isogeny_ell_graph(5, directed=False, label_by_j=True) - sage: G + sage: G = E.isogeny_ell_graph(5, directed=False, label_by_j=True); G Graph on 20 vertices sage: G.vertices(sort=True) ['1', @@ -1659,9 +1825,9 @@ class of curves. If the j-invariant is not unique in the isogeny Supersingular curve over prime field:: + sage: # needs sage.graphs sage.rings.finite_rings sage: E = EllipticCurve(GF(419), j=1728) - sage: G3 = E.isogeny_ell_graph(3, directed=False, label_by_j=True) - sage: G3 + sage: G3 = E.isogeny_ell_graph(3, directed=False, label_by_j=True); G3 Graph on 27 vertices sage: G3.vertices(sort=True) ['0', @@ -1673,8 +1839,7 @@ class of curves. If the j-invariant is not unique in the isogeny ('0', '13', None), ... ('48*', '98*', None)] - sage: G5 = E.isogeny_ell_graph(5, directed=False, label_by_j=True) - sage: G5 + sage: G5 = E.isogeny_ell_graph(5, directed=False, label_by_j=True); G5 Graph on 9 vertices sage: G5.vertices(sort=True) ['13', '13*', '407', '407*', '52', '62', '62*', '98', '98*'] @@ -1686,12 +1851,12 @@ class of curves. If the j-invariant is not unique in the isogeny Supersingular curve over finite extension field of degree 2:: + sage: # needs sage.graphs sage.rings.finite_rings sage: K = GF(431^2, "i", x^2 + 1) sage: E = EllipticCurve(K, j=0) sage: E.is_supersingular() True - sage: G = E.isogeny_ell_graph(2, directed=True, label_by_j=True) - sage: G + sage: G = E.isogeny_ell_graph(2, directed=True, label_by_j=True); G Looped multi-digraph on 37 vertices sage: G.vertices(sort=True) ['0', @@ -1703,8 +1868,7 @@ class of curves. If the j-invariant is not unique in the isogeny ('0', '125', None), ... '81*i + 65', None)] - sage: H = E.isogeny_ell_graph(2, directed=False, label_by_j=True) - sage: H + sage: H = E.isogeny_ell_graph(2, directed=False, label_by_j=True); H Looped multi-graph on 37 vertices sage: H.vertices(sort=True) ['0', @@ -1719,8 +1883,9 @@ class of curves. If the j-invariant is not unique in the isogeny Curve over a quadratic number field:: + sage: # needs sage.graphs sage.rings.finite_rings sage.rings.number_field sage: K.<e> = NumberField(x^2 - 2) - sage: E = EllipticCurve(K, [1,0,1,4, -6]) + sage: E = EllipticCurve(K, [1, 0, 1, 4, -6]) sage: G2 = E.isogeny_ell_graph(2, directed=False) sage: G2.vertices(sort=True) ['y^2 + x*y + y = x^3 + (-130*e-356)*x + (-2000*e-2038)', @@ -1729,11 +1894,11 @@ class of curves. If the j-invariant is not unique in the isogeny 'y^2 + x*y + y = x^3 + 4*x + (-6)'] sage: G2.edges(sort=True) [('y^2 + x*y + y = x^3 + (-130*e-356)*x + (-2000*e-2038)', - 'y^2 + x*y + y = x^3 + (-36)*x + (-70)', None), + 'y^2 + x*y + y = x^3 + (-36)*x + (-70)', None), ('y^2 + x*y + y = x^3 + (-36)*x + (-70)', - 'y^2 + x*y + y = x^3 + (130*e-356)*x + (2000*e-2038)', None), + 'y^2 + x*y + y = x^3 + (130*e-356)*x + (2000*e-2038)', None), ('y^2 + x*y + y = x^3 + (-36)*x + (-70)', - 'y^2 + x*y + y = x^3 + 4*x + (-6)', None)] + 'y^2 + x*y + y = x^3 + 4*x + (-6)', None)] sage: G3 = E.isogeny_ell_graph(3, directed=False) sage: G3.vertices(sort=True) ['y^2 + x*y + y = x^3 + (-1)*x', @@ -1741,9 +1906,9 @@ class of curves. If the j-invariant is not unique in the isogeny 'y^2 + x*y + y = x^3 + 4*x + (-6)'] sage: G3.edges(sort=True) [('y^2 + x*y + y = x^3 + (-1)*x', - 'y^2 + x*y + y = x^3 + 4*x + (-6)', None), + 'y^2 + x*y + y = x^3 + 4*x + (-6)', None), ('y^2 + x*y + y = x^3 + (-171)*x + (-874)', - 'y^2 + x*y + y = x^3 + 4*x + (-6)', None)] + 'y^2 + x*y + y = x^3 + 4*x + (-6)', None)] TESTS:: @@ -1871,8 +2036,8 @@ def compute_model(E, name): raise TypeError('not an elliptic curve') if name == 'minimal': - from sage.rings.number_field.number_field_base import is_NumberField - if not is_NumberField(E.base_field()): + from sage.rings.number_field.number_field_base import NumberField + if not isinstance(E.base_field(), NumberField): raise ValueError('can only compute minimal model for curves over number fields') return E.global_minimal_model(semi_global=True) diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py index 2ab127bcb92..52115c51c7d 100644 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -10,7 +10,9 @@ - John Cremona (2008-02): Point counting and group structure for non-prime fields, Frobenius endomorphism and order, elliptic logs -- Mariah Lenox (2011-03): Added set_order method +- Mariah Lenox (2011-03): Added ``set_order`` method + +- Lorenz Panny, John Cremona (2023-02): ``.twists()`` """ # **************************************************************************** @@ -23,18 +25,25 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import sage.groups.generic as generic +from sage.arith.functions import lcm +from sage.arith.misc import binomial, GCD as gcd +from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper +from sage.misc.cachefunc import cached_method +from sage.rings.finite_rings.finite_field_base import FiniteField +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.schemes.curves.projective_curve import Hasse_bounds -from .ell_field import EllipticCurve_field -from .constructor import EllipticCurve from sage.schemes.hyperelliptic_curves.hyperelliptic_finite_field import HyperellipticCurve_finite_field -from sage.rings.all import Integer, ZZ, PolynomialRing, GF, polygen -from sage.rings.finite_rings.element_base import is_FiniteFieldElement -import sage.groups.generic as generic +from sage.structure.element import Element + from . import ell_point -from sage.arith.all import gcd, lcm, binomial -from sage.misc.cachefunc import cached_method -from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper +from .constructor import EllipticCurve +from .ell_field import EllipticCurve_field class EllipticCurve_finite_field(EllipticCurve_field, HyperellipticCurve_finite_field): @@ -46,6 +55,7 @@ class EllipticCurve_finite_field(EllipticCurve_field, HyperellipticCurve_finite_ sage: EllipticCurve(GF(101),[2,3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Finite Field of size 101 + sage: # needs sage.rings.finite_rings sage: F = GF(101^2, 'a') sage: EllipticCurve([F(2),F(3)]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Finite Field in a of size 101^2 @@ -90,7 +100,7 @@ def plot(self, *args, **kwds): EXAMPLES:: sage: E = EllipticCurve(FiniteField(17), [0,1]) - sage: P = plot(E, rgbcolor=(0,0,1)) + sage: P = plot(E, rgbcolor=(0,0,1)) # needs sage.plot """ R = self.base_ring() if not R.is_prime_field(): @@ -126,6 +136,7 @@ def _points_via_group_structure(self): :: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(4,'a'),[0, 0, 1, 0, 1]) sage: E.points() [(0 : 1 : 0), (0 : a : 1), (0 : a + 1 : 1), (1 : 0 : 1), (1 : 1 : 1), (a : 0 : 1), (a : 1 : 1), (a + 1 : 0 : 1), (a + 1 : 1 : 1)] @@ -137,7 +148,7 @@ def _points_via_group_structure(self): ni = G.generator_orders() ngens = G.ngens() - H0=[self(0)] + H0 = [self(0)] if ngens == 0: # trivial group return H0 for m in range(1,ni[0]): @@ -146,7 +157,7 @@ def _points_via_group_structure(self): return H0 # else noncyclic group - H1=[self(0)] + H1 = [self(0)] for m in range(1,ni[1]): H1.append(H1[-1]+pts[1]) return [P+Q for P in H0 for Q in H1] @@ -175,6 +186,7 @@ def points(self): :: + sage: # needs sage.rings.finite_rings sage: K = GF((p, 2),'a') sage: E = E.change_ring(K) sage: len(E.points()) @@ -186,7 +198,7 @@ def points(self): Note that the returned list is an immutable sorted Sequence:: - sage: w[0] = 9 + sage: w[0] = 9 # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: object is immutable; please change a copy instead. @@ -198,10 +210,10 @@ def points(self): from sage.structure.sequence import Sequence k = self.base_ring() - if k.is_prime_field() and k.order()>50: + if k.is_prime_field() and k.order() > 50: v = self._points_via_group_structure() else: - v =self._points_fast_sqrt() + v = self._points_fast_sqrt() v.sort() self.__points = Sequence(v, immutable=True) return self.__points @@ -236,6 +248,7 @@ def count_points(self, n=1): :: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(p^2) sage: E = EllipticCurve(F, [a,a]) sage: E.cardinality() @@ -300,6 +313,7 @@ def random_element(self): :: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(7^5) sage: E = EllipticCurve(k,[2,4]) sage: P = E.random_element(); P # random @@ -311,9 +325,10 @@ def random_element(self): :: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(2^5) sage: E = EllipticCurve(k,[a^2,a,1,a+1,1]) - sage: P = E.random_element();P # random + sage: P = E.random_element(); P # random (a^4 + a : a^4 + a^3 + a^2 : 1) sage: type(P) <class 'sage.schemes.elliptic_curves.ell_point.EllipticCurvePoint_finite_field'> @@ -343,6 +358,7 @@ def random_element(self): sage: E.cardinality() 1 + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) sage: E = EllipticCurve(F, [0, 0, 1, 0, a]) sage: E.random_point() @@ -381,14 +397,14 @@ def trace_of_frobenius(self): sage: E = EllipticCurve(GF(101),[2,3]) sage: E.trace_of_frobenius() 6 - sage: E = EllipticCurve(GF(11^5,'a'),[2,5]) - sage: E.trace_of_frobenius() + sage: E = EllipticCurve(GF(11^5,'a'),[2,5]) # needs sage.rings.finite_rings + sage: E.trace_of_frobenius() # needs sage.rings.finite_rings 802 The following shows that the issue from :trac:`2849` is fixed:: - sage: E = EllipticCurve(GF(3^5,'a'),[-1,-1]) - sage: E.trace_of_frobenius() + sage: E = EllipticCurve(GF(3^5,'a'),[-1,-1]) # needs sage.rings.finite_rings + sage: E.trace_of_frobenius() # needs sage.rings.finite_rings -27 """ return 1 + self.base_field().order() - self.cardinality() @@ -428,6 +444,7 @@ def cardinality(self, algorithm=None, extension_degree=1): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: EllipticCurve(GF(4, 'a'), [1,2,3,4,5]).cardinality() 8 sage: k.<a> = GF(3^3) @@ -437,12 +454,14 @@ def cardinality(self, algorithm=None, extension_degree=1): :: + sage: # needs sage.rings.finite_rings sage: l = [1, 1, 0, 2, 0] sage: EllipticCurve(k, l).cardinality() 38 An even bigger extension (which we check against Magma):: + sage: # needs sage.rings.finite_rings sage: EllipticCurve(GF(3^100, 'a'), [1,2,3,4,5]).cardinality() 515377520732011331036459693969645888996929981504 sage: magma.eval("Order(EllipticCurve([GF(3^100)|1,2,3,4,5]))") # optional - magma @@ -459,6 +478,7 @@ def cardinality(self, algorithm=None, extension_degree=1): The cardinality is cached:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(3^100, 'a'), [1,2,3,4,5]) sage: E.cardinality() is E.cardinality() True @@ -466,6 +486,7 @@ def cardinality(self, algorithm=None, extension_degree=1): The following is very fast since the curve is actually defined over the prime field:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(11^100) sage: E1 = EllipticCurve(k, [3,3]) sage: N1 = E1.cardinality(algorithm="subfield"); N1 @@ -482,17 +503,20 @@ def cardinality(self, algorithm=None, extension_degree=1): We can count points over curves defined as a reduction:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) sage: K.<w> = NumberField(x^2 + x + 1) sage: EK = EllipticCurve(K, [0, 0, w, 2, 1]) sage: E = EK.base_extend(K.residue_field(2)) sage: E - Elliptic Curve defined by y^2 + wbar*y = x^3 + 1 over Residue field in wbar of Fractional ideal (2) + Elliptic Curve defined by y^2 + wbar*y = x^3 + 1 + over Residue field in wbar of Fractional ideal (2) sage: E.cardinality() 7 sage: E = EK.base_extend(K.residue_field(w - 1)) sage: E.abelian_group() - Trivial group embedded in Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 + 2*x + 1 over Residue field of Fractional ideal (w - 1) + Trivial group embedded in Abelian group of points on Elliptic Curve defined + by y^2 + y = x^3 + 2*x + 1 over Residue field of Fractional ideal (w - 1) :: @@ -501,7 +525,9 @@ def cardinality(self, algorithm=None, extension_degree=1): sage: k.<a> = R.residue_field(pol) sage: E = EllipticCurve(R, [1, x]).base_extend(k) sage: E - Elliptic Curve defined by y^2 = x^3 + x + a over Residue field in a of Principal ideal (x^5 + x + 14) of Univariate Polynomial Ring in x over Finite Field of size 17 + Elliptic Curve defined by y^2 = x^3 + x + a + over Residue field in a of Principal ideal (x^5 + x + 14) + of Univariate Polynomial Ring in x over Finite Field of size 17 sage: E.cardinality() 1421004 @@ -523,6 +549,7 @@ def cardinality(self, algorithm=None, extension_degree=1): Check that a bug noted at :trac:`15667` is fixed:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(3^6) sage: EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a, a^4 + a^3 + 2*a + 1]).cardinality() 784 @@ -605,6 +632,7 @@ def frobenius_polynomial(self): For some supersingular curves, Frobenius is in Z and the polynomial is a square:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(25,'a'),[0,0,0,0,1]) sage: E.frobenius_polynomial().factor() (x + 5)^2 @@ -631,6 +659,7 @@ def frobenius_order(self): For some supersingular curves, Frobenius is in Z and the Frobenius order is Z:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(25,'a'),[0,0,0,0,1]) sage: R = E.frobenius_order() sage: R @@ -662,6 +691,7 @@ def frobenius(self): For some supersingular curves, Frobenius is in Z:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(25,'a'),[0,0,0,0,1]) sage: E.frobenius() -5 @@ -679,6 +709,7 @@ def frobenius_endomorphism(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<t> = GF(11^4) sage: E = EllipticCurve([t,t]) sage: E.frobenius_endomorphism() @@ -694,6 +725,20 @@ def frobenius_endomorphism(self): """ return self.frobenius_isogeny(self.base_field().degree()) + def frobenius_discriminant(self): + r""" + Return the discriminant of the ring `\ZZ[\pi_E]` where `\pi_E` is the Frobenius endomorphism. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: F.<t> = GF(11^4) + sage: E = EllipticCurve([t,t]) + sage: E.frobenius_discriminant() + -57339 + """ + return self.frobenius_polynomial().discriminant() + def cardinality_pari(self): r""" Return the cardinality of ``self`` using PARI. @@ -714,6 +759,7 @@ def cardinality_pari(self): Since :trac:`16931`, this now works over finite fields which are not prime fields:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(7^3) sage: E = EllipticCurve_from_j(a) sage: E.cardinality_pari() @@ -725,7 +771,7 @@ def cardinality_pari(self): TESTS:: - sage: E.cardinality_pari().parent() + sage: E.cardinality_pari().parent() # needs sage.rings.finite_rings Integer Ring """ return Integer(self.__pari__().ellcard()) @@ -778,7 +824,9 @@ def gens(self): instead:: sage: E.abelian_group() - Additive abelian group isomorphic to Z/22 + Z/2 embedded in Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 2*x + 5 over Finite Field of size 41 + Additive abelian group isomorphic to Z/22 + Z/2 + embedded in Abelian group of points on Elliptic Curve + defined by y^2 = x^3 + 2*x + 5 over Finite Field of size 41 sage: ab_gens = E.abelian_group().gens() sage: ab_gens == E.gens() True @@ -789,6 +837,7 @@ def gens(self): Examples with 1 and 0 generators:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(3^6) sage: E = EllipticCurve([a, a+1]) sage: pts = E.gens() @@ -796,6 +845,7 @@ def gens(self): 1 sage: pts[0].order() == E.cardinality() True + sage: E = EllipticCurve(GF(2), [0,0,1,1,1]) sage: E.gens() () @@ -803,6 +853,7 @@ def gens(self): This works over larger finite fields where :meth:`abelian_group` may be too expensive:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^60) sage: E = EllipticCurve([a, a]) sage: len(E.gens()) @@ -839,8 +890,7 @@ def __iter__(self): ... (10 : 0 : 1) 2 """ - for P in self.points(): - yield P + yield from self.points() def __getitem__(self, n): """ @@ -910,11 +960,17 @@ def abelian_group(self): - John Cremona: original implementation - Lorenz Panny (2021): current implementation + .. SEEALSO:: + + :meth:`AdditiveAbelianGroupWrapper.from_generators()<sage.groups.additive_abelian.additive_abelian_wrapper.AdditiveAbelianGroupWrapper.from_generators>` + EXAMPLES:: sage: E = EllipticCurve(GF(11),[2,5]) sage: E.abelian_group() - Additive abelian group isomorphic to Z/10 embedded in Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 2*x + 5 over Finite Field of size 11 + Additive abelian group isomorphic to Z/10 embedded in + Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 2*x + 5 + over Finite Field of size 11 :: @@ -924,6 +980,7 @@ def abelian_group(self): :: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(3^6,'a') sage: E = EllipticCurve([a^4 + a^3 + 2*a^2 + 2*a, 2*a^5 + 2*a^3 + 2*a^2 + 1]) sage: E.abelian_group() @@ -931,6 +988,7 @@ def abelian_group(self): :: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(101^3,'a') sage: E = EllipticCurve([2*a^2 + 48*a + 27, 89*a^2 + 76*a + 24]) sage: E.abelian_group() @@ -938,9 +996,10 @@ def abelian_group(self): The group can be trivial:: - sage: E = EllipticCurve(GF(2),[0,0,1,1,1]) + sage: E = EllipticCurve(GF(2), [0,0,1,1,1]) sage: E.abelian_group() - Trivial group embedded in Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 + x + 1 over Finite Field of size 2 + Trivial group embedded in Abelian group of points on + Elliptic Curve defined by y^2 + y = x^3 + x + 1 over Finite Field of size 2 Of course, there are plenty of points if we extend the field:: @@ -959,16 +1018,18 @@ def abelian_group(self): This tests that the bug reported in :trac:`3926` has been fixed:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: OK = K.ring_of_integers() - sage: P=K.factor(10007)[0][0] + sage: P = K.factor(10007)[0][0] sage: OKmodP = OK.residue_field(P) - sage: E = EllipticCurve([0,0,0,i,i+3]) + sage: E = EllipticCurve([0, 0, 0, i, i + 3]) sage: Emod = E.change_ring(OKmodP); Emod - Elliptic Curve defined by y^2 = x^3 + ibar*x + (ibar+3) over Residue field in ibar of Fractional ideal (10007) + Elliptic Curve defined by y^2 = x^3 + ibar*x + (ibar+3) + over Residue field in ibar of Fractional ideal (10007) sage: Emod.abelian_group() #random generators (Multiplicative Abelian group isomorphic to C50067594 x C2, - ((3152*ibar + 7679 : 7330*ibar + 7913 : 1), (8466*ibar + 1770 : 0 : 1))) + ((3152*ibar + 7679 : 7330*ibar + 7913 : 1), (8466*ibar + 1770 : 0 : 1))) """ gens = self.gens() @@ -1009,9 +1070,12 @@ def torsion_basis(self, n): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(62207^2), [1,0]) sage: E.abelian_group() - Additive abelian group isomorphic to Z/62208 + Z/62208 embedded in Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 62207^2 + Additive abelian group isomorphic to Z/62208 + Z/62208 embedded in + Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x + over Finite Field in z2 of size 62207^2 sage: PA,QA = E.torsion_basis(2^8) sage: PA.weil_pairing(QA, 2^8).multiplicative_order() 256 @@ -1090,6 +1154,7 @@ def is_isogenous(self, other, field=None, proof=True): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: E1 = EllipticCurve(GF(11^2,'a'),[2,7]); E1 Elliptic Curve defined by y^2 = x^3 + 2*x + 7 over Finite Field in a of size 11^2 sage: E1.is_isogenous(5) @@ -1099,6 +1164,7 @@ def is_isogenous(self, other, field=None, proof=True): sage: E1.is_isogenous(E1) True + sage: # needs sage.rings.finite_rings sage: E2 = EllipticCurve(GF(7^3,'b'),[3,1]); E2 Elliptic Curve defined by y^2 = x^3 + 3*x + 1 over Finite Field in b of size 7^3 sage: E1.is_isogenous(E2) @@ -1106,16 +1172,19 @@ def is_isogenous(self, other, field=None, proof=True): ... ValueError: The base fields must have the same characteristic. + sage: # needs sage.rings.finite_rings sage: E3 = EllipticCurve(GF(11^2,'c'),[4,3]); E3 Elliptic Curve defined by y^2 = x^3 + 4*x + 3 over Finite Field in c of size 11^2 sage: E1.is_isogenous(E3) False + sage: # needs sage.rings.finite_rings sage: E4 = EllipticCurve(GF(11^6,'d'),[6,5]); E4 Elliptic Curve defined by y^2 = x^3 + 6*x + 5 over Finite Field in d of size 11^6 sage: E1.is_isogenous(E4) True + sage: # needs sage.rings.finite_rings sage: E5 = EllipticCurve(GF(11^7,'e'),[4,2]); E5 Elliptic Curve defined by y^2 = x^3 + 4*x + 2 over Finite Field in e of size 11^7 sage: E1.is_isogenous(E5) @@ -1123,8 +1192,9 @@ def is_isogenous(self, other, field=None, proof=True): ... ValueError: Curves have different base fields: use the field parameter. - When the field is given: + When the field is given:: + sage: # needs sage.rings.finite_rings sage: E1 = EllipticCurve(GF(13^2,'a'),[2,7]); E1 Elliptic Curve defined by y^2 = x^3 + 2*x + 7 over Finite Field in a of size 13^2 sage: E1.is_isogenous(5,GF(13^6,'f')) @@ -1242,7 +1312,7 @@ def is_ordinary(self, proof=True): def set_order(self, value, *, check=True, num_checks=8): r""" - Set the value of self._order to value. + Set the value of ``self._order`` to ``value``. Use this when you know a priori the order of the curve to avoid a potentially expensive order calculation. @@ -1315,7 +1385,7 @@ def set_order(self, value, *, check=True, num_checks=8): It is also very likely an error to pass a value which is not the actual order of this curve. How unlikely is determined by - num_checks, the factorization of the actual order, and the + ``num_checks``, the factorization of the actual order, and the actual group structure:: sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 6 @@ -1333,7 +1403,7 @@ def set_order(self, value, *, check=True, num_checks=8): sage: E.order() 12 - Or, the order can be set incorrectly along with num_checks set + Or, the order can be set incorrectly along with ``num_checks`` set too small:: sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 6 @@ -1341,7 +1411,7 @@ def set_order(self, value, *, check=True, num_checks=8): sage: E.order() 4 - The value of num_checks must be an integer. Negative values + The value of ``num_checks`` must be an integer. Negative values are interpreted as zero, which means don't do any checking:: sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 6 @@ -1414,9 +1484,650 @@ def _fetch_cached_order(self, other): if n is not None: self._order = n + def height_above_floor(self, ell, e): + r""" + Return the height of the `j`-invariant of this ordinary elliptic curve on its `\ell`-volcano. + + INPUT: + + - ``ell`` -- a prime number + - ``e`` -- a non-negative integer, the ell-adic valuation of + the conductor the Frobenius order + + + .. NOTE:: + + For an ordinary `E/\GF{q}`, and a prime `\ell`, the height + `e` of the `\ell`-volcano containing `j(E)` is the `\ell`-adic + valuation of the conductor of the order generated by the + Frobenius `\pi_E`; the height of `j(E)` on its + ell-volcano is the `\ell`-adic valuation of the conductor + of the order `\text{End}(E)`. + + ALGORITHM: + + See [RouSuthZur2022]_. + + EXAMPLES:: + + sage: F = GF(312401) + sage: E = EllipticCurve(F,(0, 0, 0, 309381, 93465)) + sage: D = E.frobenius_discriminant(); D + -687104 + sage: D.factor() + -1 * 2^10 * 11 * 61 + sage: E.height_above_floor(2,8) + 5 + + """ + if self.is_supersingular(): + raise ValueError("{} is not ordinary".format(self)) + if e == 0: + return 0 + j = self.j_invariant() + if j in [0, 1728]: + return e + F = j.parent() + x = polygen(F) + from sage.rings.polynomial.polynomial_ring import polygens + from sage.libs.pari.convert_sage import gen_to_sage + from sage.libs.pari.all import pari + X,Y = polygens(F,['X', 'Y'],2) + phi = gen_to_sage(pari.polmodular(ell),{'x':X, 'y':Y}) + j1 = phi([x,j]).roots(multiplicities=False) + nj1 = len(j1) + on_floor = self.two_torsion_rank() < 2 if ell == 2 else nj1 <= ell + if on_floor: + return 0 + if e == 1 or nj1 != ell+1: # double roots can only happen at the surface + return e + if nj1 < 3: + return 0 + j0 = [j,j,j] + h = 1 + while True: + for i in range(3): + r = (phi([x,j1[i]])//(x-j0[i])).roots(multiplicities=False) + if not r: + return h + j0[i] = j1[i] + j1[i] = r[0] + h += 1 + + def endomorphism_discriminant_from_class_number(self, h): + r""" + Return the endomorphism order discriminant of this ordinary elliptic curve, given its class number ``h``. + + INPUT: + + - ``h`` -- a positive integer + + OUTPUT: + + (integer) The discriminant of the endomorphism ring `\text{End}(E)`, if + this has class number ``h``. If `\text{End}(E)` does not have class + number ``h``, a ``ValueError`` is raised. + + ALGORITHM: + + Compute the trace of Frobenius and hence the discriminant + `D_0` and class number `h_0` of the maximal order containing + the endomorphism order. From the given value of `h`, which + must be a multiple of `h_0`, compute the possible conductors, + using :meth:`height_above_floor` for each prime `\ell` + dividing the quotient `h/h_0`. If exactly one conductor `f` + remains, return `f^2D_0`, otherwise raise a ``ValueError``; + this can onlyhappen when the input value of `h` was incorrect. + + .. NOTE:: + + Adapted from [RouSuthZur2022]_. The application for which + one knows the class number in advance is in the + recognition of Hilbert Class Polynomials: see + :func:`sage.schemes.elliptic_curves.cm.is_HCP`. + + EXAMPLES:: + + sage: F = GF(312401) + sage: E = EllipticCurve(F,(0, 0, 0, 309381, 93465)) + sage: E.endomorphism_discriminant_from_class_number(30) + -671 + + We check that this is the correct discriminant, and the input value of `h` was correct:: + + sage: H = hilbert_class_polynomial(-671) + sage: H(E.j_invariant()) == 0 and H.degree()==30 + True + + """ + F = self.base_field() + if not F.is_finite(): + raise ValueError("Base field {} must be finite".format(F)) + if self.is_supersingular(): + raise ValueError("Elliptic curve ({}) must be ordinary".format(self)) + D1 = self.frobenius_discriminant() + D0 = D1.squarefree_part() + if D0 % 4 != 1: + D0 *= 4 + v = ZZ(D1//D0).isqrt() + h0 = D0.class_number() + if h % h0: + raise ValueError("Incorrect class number {}".format(h)) + from sage.schemes.elliptic_curves.cm import OrderClassNumber + cs = [v//f for f in v.divisors() if OrderClassNumber(D0,h0,f) == h] # cofactors c=v/f compatible with h(f**2D0)=h + if not cs: + raise ValueError("Incorrect class number {}".format(h)) + if len(cs) == 1: + return (v//cs[0])**2 * D0 + from sage.sets.set import Set + L = sorted(set(sum([c.prime_factors() for c in cs], []))) + for ell in L: + e = self.height_above_floor(ell,v.valuation(ell)) + cs = [c for c in cs if c.valuation(ell) == e] + if not cs: + raise ValueError("Incorrect class number {}".format(h)) + if len(cs) == 1: + return (v//cs[0])**2 * D0 + raise ValueError("Incorrect class number {}".format(h)) + + def twists(self): + r""" + Return a list of `k`-isomorphism representatives of all + twists of this elliptic curve, where `k` is the base field. + + The input curve appears as the first entry of the result. + + .. NOTE:: + + A *twist* of `E/k` is an elliptic curve `E'` defined over + `k` that is isomorphic to `E` over the algebraic closure + `\bar k`. + + Most elliptic curves over a finite field only admit a + single nontrivial twist (the quadratic twist); the only + exceptions are curves with `j`-invariant `0` or `1728`. + + In all cases the sum over all the twists `E'` of `1/|Aut(E')|` is 1. + + .. SEEALSO:: + + - :meth:`~sage.schemes.elliptic_curves.ell_field.EllipticCurve_field.quadratic_twist` + - :meth:`~sage.schemes.elliptic_curves.ell_field.EllipticCurve_field.quartic_twist` + - :meth:`~sage.schemes.elliptic_curves.ell_field.EllipticCurve_field.sextic_twist` + + EXAMPLES:: + + sage: E = EllipticCurve(GF(97), [1,1]) + sage: E.j_invariant() + 54 + sage: E.twists() + [Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 97, + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97] + + :: + + sage: E = EllipticCurve(GF(97), [1,0]) + sage: E.j_invariant() + 79 + sage: E.twists() + [Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 97, + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97, + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97, + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97] + + :: + + sage: E = EllipticCurve(GF(97), [0,1]) + sage: E.j_invariant() + 0 + sage: E.twists() + [Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 97, + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97, + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97, + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97, + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97, + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97] + + This can be useful to quickly compute a list of all elliptic curves + over a finite field `k` up to `k`-isomorphism:: + + sage: Es = [E for j in GF(13) for E in EllipticCurve(j=j).twists()] + sage: len(Es) + 32 + sage: Es + [Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 13, + ... + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 13] + + In characteristic 3, the number of twists is 2 except for + `j=0=1728`, when there are either 4 or 6 depending on whether the + field has odd or even degree over `\GF{3}`:: + + sage: # needs sage.rings.finite_rings + sage: K = GF(3**5) + sage: [E.ainvs() for E in EllipticCurve(j=K(1)).twists()] + [(0, 1, 0, 0, 2), (0, z5, 0, 0, 2*z5^3)] + + sage: # needs sage.rings.finite_rings + sage: K = GF(3**5) + sage: [E.ainvs() for E in EllipticCurve(j=K(0)).twists()] # random + [(0, 0, 0, 1, 0), + (0, 0, 0, 2, 0), + (0, 0, 0, 2, z5^4 + z5^3 + z5^2), + (0, 0, 0, 2, 2*z5^4 + 2*z5^3 + 2*z5^2)] + + sage: # needs sage.rings.finite_rings + sage: K = GF(3**4) + sage: [E.ainvs() for E in EllipticCurve(j=K(1)).twists()] + [(0, 1, 0, 0, 2), (0, z4, 0, 0, 2*z4^3)] + + sage: # needs sage.rings.finite_rings + sage: K = GF(3**4) + sage: [E.ainvs() for E in EllipticCurve(j=K(0)).twists()] # random + [(0, 0, 0, 1, 0), + (0, 0, 0, 2, 2*z4^3 + 2*z4^2 + 2*z4 + 2), + (0, 0, 0, 1, 0), + (0, 0, 0, 1, 2*z4^3 + 2*z4^2 + 2*z4 + 2), + (0, 0, 0, z4, 0), + (0, 0, 0, z4^3, 0)] + + In characteristic 2, the number of twists is 2 except for + `j=0=1728`, when there are either 3 or 7 depending on whether the + field has odd or even degree over `\GF{2}`:: + + sage: # needs sage.rings.finite_rings + sage: K = GF(2**7) + sage: [E.ainvs() for E in EllipticCurve(j=K(1)).twists()] + [(1, 0, 0, 0, 1), (1, 1, 0, 0, 1)] + + sage: # needs sage.rings.finite_rings + sage: K = GF(2**7) + sage: [E.ainvs() for E in EllipticCurve(j=K(0)).twists()] + [(0, 0, 1, 0, 0), (0, 0, 1, 1, 0), (0, 0, 1, 1, 1)] + + sage: # needs sage.rings.finite_rings + sage: K = GF(2**8) + sage: [E.ainvs() for E in EllipticCurve(j=K(1)).twists()] # random + [(1, 0, 0, 0, 1), (1, z8^7 + z8^6 + z8^5 + z8^4 + z8^2 + z8, 0, 0, 1)] + + sage: # needs sage.rings.finite_rings + sage: K = GF(2**8) + sage: [E.ainvs() for E in EllipticCurve(j=K(0)).twists()] # random + [(0, 0, 1, 0, 0), + (0, 0, 1, 0, z8^5 + z8^4 + z8^3), + (0, 0, 1, z8^6 + z8^5 + z8^2 + 1, 0), + (0, 0, z8^4 + z8^3 + z8^2 + 1, 0, 0), + (0, 0, z8^4 + z8^3 + z8^2 + 1, 0, z8^3 + z8^2 + 1), + (0, 0, z8^6 + z8^3 + z8^2, 0, 0), + (0, 0, z8^6 + z8^3 + z8^2, 0, z8^3 + z8^2)] + + TESTS: + + Randomized check that we find all twists and there are no duplicates:: + + sage: # needs sage.rings.finite_rings + sage: p = next_prime(randrange(2,100)) + sage: e = randrange(1,10) + sage: F.<t> = GF((p,e)) + sage: while True: + ....: try: + ....: E = EllipticCurve([F.random_element() for _ in range(5)]) + ....: except ArithmeticError: + ....: pass + ....: else: + ....: break + sage: twists1 = E.twists() + sage: {sum(E1.is_isomorphic(E2) for E2 in twists1) == 1 for E1 in twists1} + {True} + sage: j = E.j_invariant() + sage: A,B = polygens(F, 'A,B') + sage: eq = 1728*4*A**3 - j * (4*A**3 + 27*B**2) + sage: twists2 = [] + sage: for _ in range(10): + ....: V = Ideal([eq, A + B - F.random_element()]).variety() + ....: if not V: + ....: continue + ....: sol = choice(V) + ....: a, b = sol[A], sol[B] + ....: try: + ....: twists2.append(EllipticCurve([a, b])) + ....: except ArithmeticError: + ....: pass + sage: all(any(E2.is_isomorphic(E1) for E1 in twists1) for E2 in twists2) + True + """ + K = self.base_field() + j = self.j_invariant() + twists = None + if not j: + twists = curves_with_j_0(K) + elif j == 1728: + twists = curves_with_j_1728(K) + if twists: # i.e. if j=0 or 1728 + # replace the one isomorphic to self with self and move to front + for i,t in enumerate(twists): + if self.is_isomorphic(t): + twists[i] = twists[0] + twists[0] = self + break + return twists + + # Now j is not 0 or 1728, and we only have a quadratic twist + + if K.characteristic() == 2: # find D with trace 1 for the additive twist + D = K.one() # will work if degree is odd + while D.trace() == 0: + D = K.random_element() + else: # find a nonsquare D + D = K.gen() + q2 = (K.cardinality()-1)//2 + while not D or D**q2 == 1: + D = K.random_element() + return [self, self.quadratic_twist(D)] + +def curves_with_j_0(K): + r""" + Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 0 over the finite field `K`. + + .. NOTE:: + + In characteristics 2 and 3 this function simply calls ``curves_with_j_0_char2`` or + ``curves_with_j_0_char3``. Otherwise there are either 2 or 6 curves, parametrised by + `K^*/(K^*)^6`. + + Examples: + + For `K=\GF{q}` where `q\equiv1\mod{6}` there are six curves, the sextic twists of `y^2=x^3+1`:: + + sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0 + sage: sorted(curves_with_j_0(GF(7)), key = lambda E: E.a_invariants()) + [Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7, + Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field of size 7, + Elliptic Curve defined by y^2 = x^3 + 3 over Finite Field of size 7, + Elliptic Curve defined by y^2 = x^3 + 4 over Finite Field of size 7, + Elliptic Curve defined by y^2 = x^3 + 5 over Finite Field of size 7, + Elliptic Curve defined by y^2 = x^3 + 6 over Finite Field of size 7] + sage: curves_with_j_0(GF(25)) # needs sage.rings.finite_rings + [Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in z2 of size 5^2, + Elliptic Curve defined by y^2 = x^3 + z2 over Finite Field in z2 of size 5^2, + Elliptic Curve defined by y^2 = x^3 + (z2+3) over Finite Field in z2 of size 5^2, + Elliptic Curve defined by y^2 = x^3 + (4*z2+3) over Finite Field in z2 of size 5^2, + Elliptic Curve defined by y^2 = x^3 + (2*z2+2) over Finite Field in z2 of size 5^2, + Elliptic Curve defined by y^2 = x^3 + (4*z2+1) over Finite Field in z2 of size 5^2] + + For `K=\GF{q}` where `q\equiv5\mod{6}` there are two curves, + quadratic twists of each other by `-3`: `y^2=x^3+1` and + `y^2=x^3-27`:: + + sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0 + sage: curves_with_j_0(GF(5)) + [Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 5, + Elliptic Curve defined by y^2 = x^3 + 3 over Finite Field of size 5] + sage: curves_with_j_0(GF(11)) + [Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 11, + Elliptic Curve defined by y^2 = x^3 + 6 over Finite Field of size 11] + """ + if not K.is_finite(): + raise ValueError("field must be finite") + p = K.characteristic() + if p == 2: + return curves_with_j_0_char2(K) + if p == 3: + return curves_with_j_0_char3(K) + q = K.cardinality() + if q % 3 == 2: + # Then we only have two quadratic twists (and -3 is non-square) + return [EllipticCurve(K, [0,a]) for a in [1,-27]] + # Now we have genuine sextic twists, find D generating K* mod 6th powers + q2 = (q-1)//2 + q3 = (q-1)//3 + D = K.gen() + while not D or D**q2 == 1 or D**q3 == 1: + D = K.random_element() + return [EllipticCurve(K, [0,D**i]) for i in range(6)] + +def curves_with_j_1728(K): + r""" + Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 1728 over the finite field `K`. + + .. NOTE:: + + In characteristics 2 and 3 (so 0=1728) this function simply calls ``curves_with_j_0_char2`` or + ``curves_with_j_0_char3``. Otherwise there are either 2 or 4 curves, parametrised by + `K^*/(K^*)^4`. + + EXAMPLES: + + For `K=\GF{q}` where `q\equiv1\mod{4}`, there are four curves, the quartic twists of `y^2=x^3+x`:: + + sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_1728 + sage: sorted(curves_with_j_1728(GF(5)), key = lambda E: E.a_invariants()) + [Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 5, + Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 5, + Elliptic Curve defined by y^2 = x^3 + 3*x over Finite Field of size 5, + Elliptic Curve defined by y^2 = x^3 + 4*x over Finite Field of size 5] + sage: curves_with_j_1728(GF(49)) # needs sage.rings.finite_rings + [Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 7^2, + Elliptic Curve defined by y^2 = x^3 + z2*x over Finite Field in z2 of size 7^2, + Elliptic Curve defined by y^2 = x^3 + (z2+4)*x over Finite Field in z2 of size 7^2, + Elliptic Curve defined by y^2 = x^3 + (5*z2+4)*x over Finite Field in z2 of size 7^2] + + For `K=\GF{q}` where `q\equiv3\mod{4}`, there are two curves, + quadratic twists of each other by `-1`: `y^2=x^3+x` and + `y^2=x^3-x`:: + + sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_1728 + sage: curves_with_j_1728(GF(7)) + [Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7, + Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7] + sage: curves_with_j_1728(GF(11)) + [Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 11, + Elliptic Curve defined by y^2 = x^3 + 10*x over Finite Field of size 11] + """ + if not K.is_finite(): + raise ValueError("field must be finite") + p = K.characteristic() + if p == 2: + return curves_with_j_0_char2(K) + if p == 3: + return curves_with_j_0_char3(K) + q = K.cardinality() + if q % 4 == 3: + return [EllipticCurve(K, [a,0]) for a in [1,-1]] + # Now we have genuine quartic twists, find D generating K* mod 4th powers + q2 = (q-1)//2 + D = K.gen() + while not D or D**q2 == 1: + D = K.random_element() + return [EllipticCurve(K, [D**i,0]) for i in range(4)] + +def curves_with_j_0_char2(K): + r""" + Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 0 over the finite field `K` of characteristic 2. + + .. NOTE:: + + The number of twists is either 3 or 7 depending on whether + the field has odd or even degree over `\GF{2}`. See + [Connell1999]_, pages 429-431. + + Examples: + + In odd degree, there are three isomorphism classes all with representatives defined over `\GF{2}`:: + + sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0_char2 + sage: # needs sage.rings.finite_rings + sage: K = GF(2**7) + sage: curves = curves_with_j_0_char2(K) + sage: len(curves) + 3 + sage: [E.ainvs() for E in curves] + [(0, 0, 1, 0, 0), (0, 0, 1, 1, 0), (0, 0, 1, 1, 1)] + + Check that the curves are mutually non-isomorphic:: + + sage: all((e1 == e2 or not e1.is_isomorphic(e2)) # needs sage.rings.finite_rings + ....: for e1 in curves for e2 in curves) + True + + Check that the weight formula holds:: + + sage: sum(1/len(E.automorphisms()) for E in curves) == 1 # needs sage.rings.finite_rings + True + + In even degree there are seven isomorphism classes:: + + sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0_char2 + sage: # needs sage.rings.finite_rings + sage: K = GF(2**8) + sage: curves = EllipticCurve(j=K(0)).twists() + sage: len(curves) + 7 + sage: [E.ainvs() for E in curves] # random + [(0, 0, 1, 0, 0), + (0, 0, 1, 0, z8^5 + z8^4 + z8^3), + (0, 0, 1, z8^6 + z8^5 + z8^2 + 1, 0), + (0, 0, z8^4 + z8^3 + z8^2 + 1, 0, 0), + (0, 0, z8^4 + z8^3 + z8^2 + 1, 0, z8^3 + z8^2 + 1), + (0, 0, z8^6 + z8^3 + z8^2, 0, 0), + (0, 0, z8^6 + z8^3 + z8^2, 0, z8^3 + z8^2)] + + Check that the twists are mutually non-isomorphic:: + + sage: all((e1 == e2 or not e1.is_isomorphic(e2)) # needs sage.rings.finite_rings + ....: for e1 in curves for e2 in curves) + True + + Check that the weight formula holds:: + + sage: sum(1/len(E.automorphisms()) for E in curves) == 1 # needs sage.rings.finite_rings + True + """ + if not K.is_finite() or K.characteristic() != 2: + raise ValueError("field must be finite of characteristic 2") + if K.degree() % 2: + return [EllipticCurve(K, [0, 0, 1, 0, 0]), + EllipticCurve(K, [0, 0, 1, 1, 0]), + EllipticCurve(K, [0, 0, 1, 1, 1])] + # find a,b,c,d,e such that + # a is not a cube, i.e. a**((q-1)//3)!=1 + # Tr(b)=1 + # X^4+X+c irreducible + # X^2+a*X+d irreducible + # X^2+a^2*X+e irreducible + a = b = c = d = e = None + x = polygen(K) + q3 = (K.cardinality()-1)//3 + while not a or a**q3 == 1: + a = K.random_element() + asq = a*a + while not b or not b.trace(): + b = K.random_element() + c = K.one() # OK if degree is 2 mod 4 + if K.degree() % 4 == 0: + while (x**4+x+c).roots(): + c = K.random_element() + while not d or (x**2+a*x+d).roots(): + d = K.random_element() + while not e or (x**2+asq*x+e).roots(): + e = K.random_element() + return [EllipticCurve(K, ai) for ai in + [[0,0,1,0,0], [0,0,1,0,b], [0,0,1,c,0], [0,0,a,0,0], [0,0,a,0,d], [0,0,asq,0,0], [0,0,asq,0,e]]] + +def curves_with_j_0_char3(K): + r""" + Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 0 over the finite field `K` of characteristic 3. + + .. NOTE:: + + The number of twists is either 4 or 6 depending on whether + the field has odd or even degree over `\GF{3}`. See + [Connell1999]_, pages 429-431. + + Examples: + + In odd degree, there are four isomorphism classes:: + + sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0_char3 + sage: # needs sage.rings.finite_rings + sage: K = GF(3**5) + sage: curves = curves_with_j_0_char3(K) + sage: len(curves) + 4 + sage: [E.ainvs() for E in curves] # random + [(0, 0, 0, 1, 0), + (0, 0, 0, 2, 0), + (0, 0, 0, 2, z5^4 + z5^3 + z5^2), + (0, 0, 0, 2, 2*z5^4 + 2*z5^3 + 2*z5^2)] + + Check that the twists are mutually non-isomorphic:: + + sage: all((e1 == e2 or not e1.is_isomorphic(e2)) # needs sage.rings.finite_rings + ....: for e1 in curves for e2 in curves) + True + + Check that the weight formula holds:: + + sage: sum(1/len(E.automorphisms()) for E in curves) == 1 # needs sage.rings.finite_rings + True + + In even degree, there are six isomorphism classes:: + + sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0_char3 + sage: # needs sage.rings.finite_rings + sage: K = GF(3**4) + sage: curves = EllipticCurve(j=K(0)).twists() + sage: len(curves) + 6 + sage: [E.ainvs() for E in curves] # random + [(0, 0, 0, 1, 0), + (0, 0, 0, 2, 2*z4^3 + 2*z4^2 + 2*z4 + 2), + (0, 0, 0, 1, 0), + (0, 0, 0, 1, 2*z4^3 + 2*z4^2 + 2*z4 + 2), + (0, 0, 0, z4, 0), + (0, 0, 0, z4^3, 0)] + + Check that the twists are mutually non-isomorphic:: + + sage: all((e1 == e2 or not e1.is_isomorphic(e2)) # needs sage.rings.finite_rings + ....: for e1 in curves for e2 in curves) + True + + Check that the weight formula holds:: + + sage: sum(1/len(E.automorphisms()) for E in curves) == 1 # needs sage.rings.finite_rings + True + """ + if not K.is_finite() or K.characteristic() != 3: + raise ValueError("field must be finite of characteristic 3") + # find b with nonzero trace + b = None + while not b or not b.trace(): + b = K.random_element() + + if K.degree() % 2: + return [EllipticCurve(K, a4a6) for a4a6 in + [[1,0], [-1,0], [-1,b], [-1,-b]]] + + # find a, i, c where: + # a generates K* mod 4th powers, i.e. non-square, + # i^2=-1 + # c with x^3+a^2*x+c irreducible + a = K.gen() + q2 = (K.cardinality()-1)//2 + while not a or a**q2 == 1: + a = K.random_element() + x = polygen(K) + i = (x**2+1).roots()[0][0] + c = None + while not c or (x**3 + a**2*x + c).roots(): + c = K.random_element() + return [EllipticCurve(K, a4a6) for a4a6 in + [[1,0], [1,i*b], [a,0], [a**2,0], [a**2,c], [a**3,0]]] # dict to hold precomputed coefficient vectors of supersingular j values (excluding 0, 1728): + supersingular_j_polynomials = {} def fill_ss_j_dict(): @@ -1497,7 +2208,7 @@ def supersingular_j_polynomial(p, use_cache=True): - `p` (integer) -- a prime number. - - `use_cache` (boolean, default ``True``) -- use cached coefficients if they exist + - ``use_cache`` (boolean, default ``True``) -- use cached coefficients if they exist ALGORITHM: @@ -1548,7 +2259,7 @@ def supersingular_j_polynomial(p, use_cache=True): raise ValueError("p (=%s) should be a prime number" % p) J = polygen(GF(p),'j') - if p<13: + if p < 13: return J.parent().one() if use_cache: fill_ss_j_dict() @@ -1556,7 +2267,7 @@ def supersingular_j_polynomial(p, use_cache=True): return J.parent()(supersingular_j_polynomials[p]) from sage.misc.misc_c import prod - m=(p-1)//2 + m = (p-1)//2 X,T = PolynomialRing(GF(p),2,names=['X','T']).gens() H = sum(binomial(m, i) ** 2 * T ** i for i in range(m + 1)) F = T**2 * (T-1)**2 * X - 256*(T**2-T+1)**3 @@ -1604,7 +2315,8 @@ def is_j_supersingular(j, proof=True): sage: from sage.schemes.elliptic_curves.ell_finite_field import is_j_supersingular, supersingular_j_polynomials sage: [(p,[j for j in GF(p) if is_j_supersingular(j)]) for p in prime_range(30)] - [(2, [0]), (3, [0]), (5, [0]), (7, [6]), (11, [0, 1]), (13, [5]), (17, [0, 8]), (19, [7, 18]), (23, [0, 3, 19]), (29, [0, 2, 25])] + [(2, [0]), (3, [0]), (5, [0]), (7, [6]), (11, [0, 1]), (13, [5]), + (17, [0, 8]), (19, [7, 18]), (23, [0, 3, 19]), (29, [0, 2, 25])] sage: [j for j in GF(109) if is_j_supersingular(j)] [17, 41, 43] @@ -1618,7 +2330,7 @@ def is_j_supersingular(j, proof=True): sage: [p for p in prime_range(100) if is_j_supersingular(GF(p)(123456))] [2, 3, 59, 89] """ - if not is_FiniteFieldElement(j): + if not (isinstance(j, Element) and isinstance(j.parent(), FiniteField)): raise ValueError("%s must be an element of a finite field" % j) F = j.parent() diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index d3ca4896b01..8e7fb204892 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -23,7 +23,8 @@ sage: S.<v> = R[] sage: T = S.fraction_field() sage: E = EllipticCurve(T, [a, b]); E - Elliptic Curve defined by y^2 = x^3 + x + 3 over Fraction Field of Univariate Polynomial Ring in v over Univariate Polynomial Ring in u over Finite Field of size 97 + Elliptic Curve defined by y^2 = x^3 + x + 3 over Fraction Field of Univariate + Polynomial Ring in v over Univariate Polynomial Ring in u over Finite Field of size 97 sage: latex(E) y^2 = x^{3} + x + 3 @@ -54,6 +55,7 @@ import math import sage.rings.abc +from sage.rings.finite_rings.integer_mod import mod from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import polygen, polygens from sage.rings.polynomial.polynomial_element import polynomial_is_variable @@ -62,8 +64,14 @@ import sage.groups.additive_abelian.additive_abelian_group as groups import sage.groups.generic as generic -from sage.arith.all import lcm -import sage.rings.all as rings +from sage.arith.functions import lcm +from sage.rings.integer import Integer +from sage.rings.big_oh import O +from sage.rings.infinity import Infinity as oo +from sage.rings.rational import Rational +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.rational_field import RationalField +from sage.rings.real_mpfr import RealField from sage.misc.cachefunc import cached_method from sage.misc.fast_methods import WithEqualityById @@ -81,9 +89,6 @@ sqrt = math.sqrt exp = math.exp -oo = rings.infinity # infinity -O = rings.O # big oh - def is_EllipticCurve(x): r""" @@ -136,9 +141,11 @@ def __init__(self, K, ainvs): EXAMPLES:: sage: E = EllipticCurve([1,2,3,4,5]); E - Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field - sage: E = EllipticCurve(GF(7),[1,2,3,4,5]); E - Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 7 + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 + over Rational Field + sage: E = EllipticCurve(GF(7), [1,2,3,4,5]); E + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 + over Finite Field of size 7 Constructor from `[a_4,a_6]` sets `a_1=a_2=a_3=0`:: @@ -147,8 +154,9 @@ def __init__(self, K, ainvs): The base ring need not be a field:: - sage: EllipticCurve(IntegerModRing(91),[1,2,3,4,5]) - Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Ring of integers modulo 91 + sage: EllipticCurve(IntegerModRing(91), [1,2,3,4,5]) + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 + over Ring of integers modulo 91 """ self.__base_ring = K self.__ainvs = tuple(K(a) for a in ainvs) @@ -245,9 +253,10 @@ def _repr_(self): :: sage: R.<x> = QQ['x'] - sage: K.<a> = NumberField(x^3-17) - sage: EllipticCurve([a^2-3, -2/3*a + 3]) - Elliptic Curve defined by y^2 = x^3 + (a^2-3)*x + (-2/3*a+3) over Number Field in a + sage: K.<a> = NumberField(x^3 - 17) # needs sage.rings.number_field + sage: EllipticCurve([a^2 - 3, -2/3*a + 3]) # needs sage.rings.number_field + Elliptic Curve defined by y^2 = x^3 + (a^2-3)*x + (-2/3*a+3) + over Number Field in a with defining polynomial x^3 - 17 """ s = "Elliptic Curve defined by " @@ -273,9 +282,10 @@ def _latex_(self): Check that :trac:`12524` is solved:: - sage: K.<phi> = NumberField(x^2-x-1) - sage: E = EllipticCurve([0,0,phi,27*phi-43,-80*phi+128]) - sage: E._latex_() + sage: x = polygen(ZZ, 'x') + sage: K.<phi> = NumberField(x^2 - x - 1) # needs sage.rings.number_field + sage: E = EllipticCurve([0, 0, phi, 27*phi - 43, -80*phi + 128]) # needs sage.rings.number_field + sage: E._latex_() # needs sage.rings.number_field 'y^2 + \\phi y = x^{3} + \\left(27 \\phi - 43\\right) x - 80 \\phi + 128 ' """ from sage.rings.polynomial.polynomial_ring import polygen @@ -311,20 +321,22 @@ def _magma_init_(self, magma): EXAMPLES:: - sage: E = EllipticCurve(QQ,[1,1]) - sage: E._magma_init_(magma) # optional - magma + sage: # optional - magma + sage: E = EllipticCurve(QQ, [1,1]) + sage: E._magma_init_(magma) 'EllipticCurve([_sage_ref...|0/1,0/1,0/1,1/1,1/1])' - sage: E = EllipticCurve(GF(41),[2,5]) # optional - magma - sage: E._magma_init_(magma) # optional - magma + sage: E = EllipticCurve(GF(41), [2,5]) + sage: E._magma_init_(magma) 'EllipticCurve([_sage_ref...|GF(41)!0,GF(41)!0,GF(41)!0,GF(41)!2,GF(41)!5])' - sage: E = EllipticCurve(GF(25,'a'), [0,0,1,4,0]) - sage: magma(E) # optional - magma + sage: E = EllipticCurve(GF(25,'a'), [0,0,1,4,0]) # needs sage.rings.finite_rings + sage: magma(E) # needs sage.rings.finite_rings Elliptic Curve defined by y^2 + y = x^3 + 4*x over GF(5^2) - sage: magma(EllipticCurve([1/2,2/3,-4/5,6/7,8/9])) # optional - magma + sage: magma(EllipticCurve([1/2,2/3,-4/5,6/7,8/9])) Elliptic Curve defined by y^2 + 1/2*x*y - 4/5*y = x^3 + 2/3*x^2 + 6/7*x + 8/9 over Rational Field sage: R.<x> = Frac(QQ['x']) - sage: magma(EllipticCurve([x,1+x])) # optional - magma - Elliptic Curve defined by y^2 = x^3 + x*x + (x + 1) over Univariate rational function field over Rational Field + sage: magma(EllipticCurve([x, 1 + x])) + Elliptic Curve defined by y^2 = x^3 + x*x + (x + 1) + over Univariate rational function field over Rational Field """ kmn = magma(self.base_ring())._ref() return 'EllipticCurve([%s|%s])' % (kmn,','.join(x._magma_init_(magma) @@ -340,29 +352,29 @@ def _symbolic_(self, SR): :: sage: E = EllipticCurve('11a') - sage: E._symbolic_(SR) + sage: E._symbolic_(SR) # needs sage.symbolic y^2 + y == x^3 - x^2 - 10*x - 20 - sage: E.torsion_subgroup().gens() + sage: E.torsion_subgroup().gens() # needs sage.symbolic ((5 : 5 : 1),) We find the corresponding symbolic equality:: - sage: eqn = symbolic_expression(E); eqn + sage: eqn = symbolic_expression(E); eqn # needs sage.symbolic y^2 + y == x^3 - x^2 - 10*x - 20 We verify that the given point is on the curve:: - sage: eqn(x=5,y=5) + sage: eqn(x=5, y=5) # needs sage.symbolic 30 == 30 - sage: bool(eqn(x=5,y=5)) + sage: bool(eqn(x=5, y=5)) # needs sage.symbolic True We create a single expression:: - sage: F = eqn.lhs() - eqn.rhs(); F + sage: F = eqn.lhs() - eqn.rhs(); F # needs sage.symbolic -x^3 + x^2 + y^2 + 10*x + y + 20 - sage: y = var('y') - sage: F.solve(y) + sage: y = var('y') # needs sage.symbolic + sage: F.solve(y) # needs sage.symbolic [y == -1/2*sqrt(4*x^3 - 4*x^2 - 40*x - 79) - 1/2, y == 1/2*sqrt(4*x^3 - 4*x^2 - 40*x - 79) - 1/2] @@ -370,6 +382,7 @@ def _symbolic_(self, SR): horrendous. Continuing with the above example, we can explicitly find points over random fields by substituting in values for x:: + sage: # needs sage.symbolic sage: v = F.solve(y)[0].rhs(); v -1/2*sqrt(4*x^3 - 4*x^2 - 40*x - 79) - 1/2 sage: v = v.function(x) @@ -384,9 +397,11 @@ def _symbolic_(self, SR): We can even do arithmetic with them, as follows:: + sage: # needs sage.symbolic sage: E2 = E.change_ring(SR); E2 - Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Symbolic Ring - sage: P = E2.point((3, v(3), 1), check=False) # the check=False option doesn't verify that y^2 = f(x) + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) + over Symbolic Ring + sage: P = E2.point((3, v(3), 1), check=False) # the check=False option doesn't verify that y^2 = f(x) sage: P (3 : -1/2*sqrt(-127) - 1/2 : 1) sage: P + P @@ -394,19 +409,19 @@ def _symbolic_(self, SR): We can even throw in a transcendental:: - sage: w = E2.point((pi,v(pi),1), check=False); w + sage: w = E2.point((pi,v(pi),1), check=False); w # needs sage.symbolic (pi : -1/2*sqrt(-40*pi + 4*pi^3 - 4*pi^2 - 79) - 1/2 : 1) - sage: x, y, z = w; ((y^2 + y) - (x^3 - x^2 - 10*x - 20)).expand() + sage: x, y, z = w; ((y^2 + y) - (x^3 - x^2 - 10*x - 20)).expand() # needs sage.symbolic 0 - sage: 2*w + sage: 2*w # needs sage.symbolic (-2*pi - (2*pi - 3*pi^2 + 10)^2/(40*pi - 4*pi^3 + 4*pi^2 + 79) + 1 : (3*pi + (2*pi - 3*pi^2 + 10)^2/(40*pi - 4*pi^3 + 4*pi^2 + 79) - 1)*(2*pi - 3*pi^2 + 10)/sqrt(-40*pi + 4*pi^3 - 4*pi^2 - 79) + 1/2*sqrt(-40*pi + 4*pi^3 - 4*pi^2 - 79) - 1/2 : 1) - sage: x, y, z = 2*w; temp = ((y^2 + y) - (x^3 - x^2 - 10*x - 20)) + sage: x, y, z = 2*w; temp = ((y^2 + y) - (x^3 - x^2 - 10*x - 20)) # needs sage.symbolic This is a point on the curve:: - sage: bool(temp == 0) + sage: bool(temp == 0) # needs sage.symbolic True """ a = [SR(x) for x in self.a_invariants()] @@ -490,22 +505,26 @@ def __call__(self, *args, **kwds): sage: E([0,0]) Traceback (most recent call last): ... - TypeError: Coordinates [0, 0, 1] do not define a point on Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 + TypeError: Coordinates [0, 0, 1] do not define a point + on Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 We create a point on an elliptic curve over a number field:: + sage: # needs sage.rings.number_field sage: x = polygen(RationalField()) sage: K = NumberField(x**3 + x + 1, 'a'); a = K.gen() - sage: E = EllipticCurve([a,a]) + sage: E = EllipticCurve([a, a]) sage: E - Elliptic Curve defined by y^2 = x^3 + a*x + a over Number Field in a with defining polynomial x^3 + x + 1 - sage: E = EllipticCurve([K(1),1]) + Elliptic Curve defined by y^2 = x^3 + a*x + a + over Number Field in a with defining polynomial x^3 + x + 1 + sage: E = EllipticCurve([K(1), 1]) sage: E - Elliptic Curve defined by y^2 = x^3 + x + 1 over Number Field in a with defining polynomial x^3 + x + 1 + Elliptic Curve defined by y^2 = x^3 + x + 1 + over Number Field in a with defining polynomial x^3 + x + 1 sage: P = E([a,0,1]) sage: P (a : 0 : 1) - sage: P+P + sage: P + P (0 : 1 : 0) Another example involving p-adics:: @@ -513,10 +532,12 @@ def __call__(self, *args, **kwds): sage: E = EllipticCurve('37a1') sage: P = E([0,0]); P (0 : 0 : 1) - sage: R = pAdicField(3,20) - sage: Ep = E.base_extend(R); Ep - Elliptic Curve defined by y^2 + (1+O(3^20))*y = x^3 + (2+2*3+2*3^2+2*3^3+2*3^4+2*3^5+2*3^6+2*3^7+2*3^8+2*3^9+2*3^10+2*3^11+2*3^12+2*3^13+2*3^14+2*3^15+2*3^16+2*3^17+2*3^18+2*3^19+O(3^20))*x over 3-adic Field with capped relative precision 20 - sage: Ep(P) + sage: R = pAdicField(3, 20) # needs sage.rings.padics + sage: Ep = E.base_extend(R); Ep # needs sage.rings.padics + Elliptic Curve defined by + y^2 + (1+O(3^20))*y = x^3 + (2+2*3+2*3^2+2*3^3+2*3^4+2*3^5+2*3^6+2*3^7+2*3^8+2*3^9+2*3^10+2*3^11+2*3^12+2*3^13+2*3^14+2*3^15+2*3^16+2*3^17+2*3^18+2*3^19+O(3^20))*x + over 3-adic Field with capped relative precision 20 + sage: Ep(P) # needs sage.rings.padics (0 : 0 : 1 + O(3^20)) Constructing points from the torsion subgroup (which is an abstract @@ -562,8 +583,8 @@ def __call__(self, *args, **kwds): # characteristic of the base ring. if so, coerce the point to # infinity. characteristic = self.base_ring().characteristic() - if characteristic != 0 and isinstance(args[0][0], rings.Rational) and isinstance(args[0][1], rings.Rational): - if rings.mod(args[0][0].denominator(),characteristic) == 0 or rings.mod(args[0][1].denominator(),characteristic) == 0: + if characteristic != 0 and isinstance(args[0][0], Rational) and isinstance(args[0][1], Rational): + if mod(args[0][0].denominator(),characteristic) == 0 or mod(args[0][1].denominator(),characteristic) == 0: return self._reduce_point(args[0], characteristic) args = tuple(args[0]) @@ -619,10 +640,10 @@ def _reduce_point(self, R, p): \code{EllipticCurve._reduce_point} """ if R.is_zero(): - return R.curve().change_ring(rings.GF(p))(0) + return R.curve().change_ring(GF(p))(0) x, y = R.xy() d = lcm(x.denominator(), y.denominator()) - return R.curve().change_ring(rings.GF(p))([x*d, y*d, d]) + return R.curve().change_ring(GF(p))([x*d, y*d, d]) def is_x_coord(self, x): r""" @@ -673,9 +694,9 @@ def is_x_coord(self, x): :: - sage: F = GF(32,'a') - sage: E = EllipticCurve(F,[1,0,0,0,1]) - sage: set(P[0] for P in E.points() if P!=E(0)) == set(x for x in F if E.is_x_coord(x)) + sage: F = GF(32,'a') # needs sage.rings.finite_rings + sage: E = EllipticCurve(F,[1,0,0,0,1]) # needs sage.rings.finite_rings + sage: set(P[0] for P in E.points() if P!=E(0)) == set(x for x in F if E.is_x_coord(x)) # needs sage.rings.finite_rings True """ K = self.base_ring() @@ -699,6 +720,9 @@ def lift_x(self, x, all=False, extend=False): r""" Return one or all points with given `x`-coordinate. + This method is deterministic: It returns the same data each + time when called again with the same `x`. + INPUT: - ``x`` -- an element of the base ring of the curve, or of an extension. @@ -733,41 +757,43 @@ def lift_x(self, x, all=False, extend=False): sage: E = EllipticCurve('37a'); E Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field sage: E.lift_x(1) - (1 : 0 : 1) + (1 : -1 : 1) sage: E.lift_x(2) - (2 : 2 : 1) + (2 : -3 : 1) sage: E.lift_x(1/4, all=True) - [(1/4 : -3/8 : 1), (1/4 : -5/8 : 1)] + [(1/4 : -5/8 : 1), (1/4 : -3/8 : 1)] There are no rational points with `x`-coordinate 3:: sage: E.lift_x(3) Traceback (most recent call last): ... - ValueError: No point with x-coordinate 3 on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + ValueError: No point with x-coordinate 3 + on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field We can use the ``extend`` parameter to make the necessary quadratic extension. Note that in such cases the returned point is a point on a new curve object, the result of changing the base ring to the parent of `x`:: - sage: P = E.lift_x(3, extend=True); P - (3 : y : 1) - sage: P.curve() - Elliptic Curve defined by y^2 + y = x^3 + (-1)*x over Number Field in y with defining polynomial y^2 + y - 24 + sage: P = E.lift_x(3, extend=True); P # needs sage.rings.number_field + (3 : -y - 1 : 1) + sage: P.curve() # needs sage.rings.number_field + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x + over Number Field in y with defining polynomial y^2 + y - 24 Or we can extend scalars. There are two such points in `E(\RR)`:: sage: E.change_ring(RR).lift_x(3, all=True) - [(3.00000000000000 : 4.42442890089805 : 1.00000000000000), - (3.00000000000000 : -5.42442890089805 : 1.00000000000000)] + [(3.00000000000000 : -5.42442890089805 : 1.00000000000000), + (3.00000000000000 : 4.42442890089805 : 1.00000000000000)] And of course it always works in `E(\CC)`:: sage: E.change_ring(RR).lift_x(.5, all=True) [] sage: E.change_ring(CC).lift_x(.5) - (0.500000000000000 : -0.500000000000000 + 0.353553390593274*I : 1.00000000000000) + (0.500000000000000 : -0.500000000000000 - 0.353553390593274*I : 1.00000000000000) In this example we start with a curve defined over `\QQ` which has no rational points with `x=0`, but using @@ -776,21 +802,23 @@ def lift_x(self, x, all=False, extend=False): sage: E = EllipticCurve([0,0,0,0,2]); E Elliptic Curve defined by y^2 = x^3 + 2 over Rational Field - sage: P = E.lift_x(0, extend=True); P - (0 : y : 1) - sage: P.curve() - Elliptic Curve defined by y^2 = x^3 + 2 over Number Field in y with defining polynomial y^2 - 2 + sage: P = E.lift_x(0, extend=True); P # needs sage.rings.number_field + (0 : -y : 1) + sage: P.curve() # needs sage.rings.number_field + Elliptic Curve defined by y^2 = x^3 + 2 + over Number Field in y with defining polynomial y^2 - 2 We can perform these operations over finite fields too:: sage: E = EllipticCurve('37a').change_ring(GF(17)); E Elliptic Curve defined by y^2 + y = x^3 + 16*x over Finite Field of size 17 sage: E.lift_x(7) - (7 : 11 : 1) + (7 : 5 : 1) sage: E.lift_x(3) Traceback (most recent call last): ... - ValueError: No point with x-coordinate 3 on Elliptic Curve defined by y^2 + y = x^3 + 16*x over Finite Field of size 17 + ValueError: No point with x-coordinate 3 on + Elliptic Curve defined by y^2 + y = x^3 + 16*x over Finite Field of size 17 Note that there is only one lift with `x`-coordinate 10 in `E(\GF{17})`:: @@ -803,17 +831,19 @@ def lift_x(self, x, all=False, extend=False): returned is on the base-extended curve:: sage: E = EllipticCurve('37a') - sage: P = E.lift_x(pAdicField(17, 5)(6)); P - (6 + O(17^5) : 2 + 16*17 + 16*17^2 + 16*17^3 + 16*17^4 + O(17^5) : 1 + O(17^5)) - sage: P.curve() - Elliptic Curve defined by y^2 + (1+O(17^5))*y = x^3 + (16+16*17+16*17^2+16*17^3+16*17^4+O(17^5))*x over 17-adic Field with capped relative precision 5 + sage: P = E.lift_x(pAdicField(17, 5)(6)); P # needs sage.rings.padics + (6 + O(17^5) : 14 + O(17^5) : 1 + O(17^5)) + sage: P.curve() # needs sage.rings.padics + Elliptic Curve defined by + y^2 + (1+O(17^5))*y = x^3 + (16+16*17+16*17^2+16*17^3+16*17^4+O(17^5))*x + over 17-adic Field with capped relative precision 5 sage: K.<t> = PowerSeriesRing(QQ, 't', 5) - sage: P = E.lift_x(1+t); P - (1 + t : 2*t - t^2 + 5*t^3 - 21*t^4 + O(t^5) : 1) - sage: K.<a> = GF(16) - sage: P = E.change_ring(K).lift_x(a^3); P + sage: P = E.lift_x(1 + t); P + (1 + t : -1 - 2*t + t^2 - 5*t^3 + 21*t^4 + O(t^5) : 1) + sage: K.<a> = GF(16) # needs sage.rings.finite_rings + sage: P = E.change_ring(K).lift_x(a^3); P # needs sage.rings.finite_rings (a^3 : a^3 + a : 1) - sage: P.curve() + sage: P.curve() # needs sage.rings.finite_rings Elliptic Curve defined by y^2 + y = x^3 + x over Finite Field in a of size 2^4 We can extend the base field to include the associated `y` value(s):: @@ -822,22 +852,25 @@ def lift_x(self, x, all=False, extend=False): Elliptic Curve defined by y^2 = x^3 + 2 over Rational Field sage: x = polygen(QQ) sage: P = E.lift_x(x, extend=True); P - (x : y : 1) + (x : -y : 1) This point is a generic point on E:: sage: P.curve() - Elliptic Curve defined by y^2 = x^3 + 2 over Univariate Quotient Polynomial Ring in y over Fraction Field of Univariate Polynomial Ring in x over Rational Field with modulus y^2 - x^3 - 2 + Elliptic Curve defined by y^2 = x^3 + 2 + over Univariate Quotient Polynomial Ring in y + over Fraction Field of Univariate Polynomial Ring in x over Rational Field + with modulus y^2 - x^3 - 2 sage: -P - (x : -y : 1) + (x : y : 1) sage: 2*P - ((1/4*x^4 - 4*x)/(x^3 + 2) : ((1/8*x^6 + 5*x^3 - 4)/(x^6 + 4*x^3 + 4))*y : 1) + ((1/4*x^4 - 4*x)/(x^3 + 2) : ((-1/8*x^6 - 5*x^3 + 4)/(x^6 + 4*x^3 + 4))*y : 1) Check that :trac:`30297` is fixed:: - sage: K = Qp(5) - sage: E = EllipticCurve([K(0), K(1)]) - sage: E.lift_x(1, extend=True) + sage: K = Qp(5) # needs sage.rings.padics + sage: E = EllipticCurve([K(0), K(1)]) # needs sage.rings.padics + sage: E.lift_x(1, extend=True) # needs sage.rings.padics (1 + O(5^20) : y + O(5^20) : 1 + O(5^20)) AUTHORS: @@ -852,6 +885,15 @@ def lift_x(self, x, all=False, extend=False): [] sage: E.lift_x(7, all=True) [(7 : 3 : 1), (7 : 14 : 1)] + + Check determinism:: + + sage: F.<t> = GF((101,3)) + sage: {(t+1).sqrt() for _ in range(1000)} # both square roots can occur + {29*t^2 + 56*t + 26, 72*t^2 + 45*t + 75} + sage: E = EllipticCurve(F, [1,1]) + sage: {E.lift_x(t+1) for _ in range(1000)} # but .lift_x() uses a fixed one + {(t + 1 : 39*t^2 + 14*t + 12 : 1)} """ K = self.base_ring() L = x.parent() @@ -888,6 +930,8 @@ def lift_x(self, x, all=False, extend=False): if D.is_square(): # avoid automatic creation of sqrts ys = [(-b+d)/2 for d in D.sqrt(all=True)] + ys.sort() # ensure deterministic behavior + # Return the point(s) if any: if ys: @@ -918,6 +962,7 @@ def lift_x(self, x, all=False, extend=False): ys = [y1] else: ys = [y1, y2] + ys.sort() # ensure deterministic behavior one = M.one() if all: return [EM.point([x, y, one], check=False) for y in ys] @@ -932,7 +977,7 @@ def _point_homset(self, *args, **kwds): EXAMPLES:: sage: E = EllipticCurve(GF(5),[1,1]) - sage: E._point_homset(Spec(GF(5^10,'a'),GF(5)), E) + sage: E._point_homset(Spec(GF(5^10,'a'), GF(5)), E) # needs sage.rings.finite_rings Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 5^10 @@ -981,7 +1026,7 @@ def __is_over_RationalField(self): sage: E._EllipticCurve_generic__is_over_RationalField() False """ - return isinstance(self.base_ring(), rings.RationalField) + return isinstance(self.base_ring(), RationalField) def is_on_curve(self, x, y): r""" @@ -1319,9 +1364,9 @@ def base_extend(self, R): EXAMPLES:: - sage: E = EllipticCurve(GF(5),[1,1]); E + sage: E = EllipticCurve(GF(5), [1,1]); E Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 - sage: E1 = E.base_extend(GF(125,'a')); E1 + sage: E1 = E.base_extend(GF(125,'a')); E1 # needs sage.rings.finite_rings Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 5^3 TESTS: @@ -1329,6 +1374,7 @@ def base_extend(self, R): Check that we are correctly keeping track of known cardinalities when extending the base field:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(j=GF(7)(5)) sage: E.cardinality() 10 @@ -1338,15 +1384,15 @@ def base_extend(self, R): Changing to a smaller field should not cache orders:: - sage: EE = EllipticCurve(j=GF(7^3)(6)) - sage: hasattr(EE.change_ring(GF(7)), '_order') + sage: EE = EllipticCurve(j=GF(7^3)(6)) # needs sage.rings.finite_rings + sage: hasattr(EE.change_ring(GF(7)), '_order') # needs sage.rings.finite_rings False Changing to a field of different characteristic should not cache orders:: - sage: Elift = E.change_ring(QQ) - sage: hasattr(Elift, '_order') + sage: Elift = E.change_ring(QQ) # needs sage.rings.finite_rings + sage: hasattr(Elift, '_order') # needs sage.rings.finite_rings False """ E = constructor.EllipticCurve([R(a) for a in self.a_invariants()]) @@ -1367,13 +1413,17 @@ def change_ring(self, R): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F2 = GF(5^2,'a'); a = F2.gen() sage: F4 = GF(5^4,'b'); b = F4.gen() - sage: h = F2.hom([a.charpoly().roots(ring=F4,multiplicities=False)[0]],F4) - sage: E = EllipticCurve(F2,[1,a]); E - Elliptic Curve defined by y^2 = x^3 + x + a over Finite Field in a of size 5^2 + sage: roots = a.charpoly().roots(ring=F4, multiplicities=False) + sage: h = F2.hom([roots[0]], F4) + sage: E = EllipticCurve(F2, [1,a]); E + Elliptic Curve defined by y^2 = x^3 + x + a + over Finite Field in a of size 5^2 sage: E.change_ring(h) - Elliptic Curve defined by y^2 = x^3 + x + (4*b^3+4*b^2+4*b+3) over Finite Field in b of size 5^4 + Elliptic Curve defined by y^2 = x^3 + x + (4*b^3+4*b^2+4*b+3) + over Finite Field in b of size 5^4 """ return self.base_extend(R) @@ -1383,8 +1433,8 @@ def base_ring(self): EXAMPLES:: - sage: E = EllipticCurve(GF(49, 'a'), [3,5]) - sage: E.base_ring() + sage: E = EllipticCurve(GF(49, 'a'), [3,5]) # needs sage.rings.finite_rings + sage: E.base_ring() # needs sage.rings.finite_rings Finite Field in a of size 7^2 :: @@ -1412,13 +1462,13 @@ def gens(self): EXAMPLES:: - sage: R.<a1,a2,a3,a4,a6>=QQ[] + sage: R.<a1,a2,a3,a4,a6> = QQ[] sage: E = EllipticCurve([a1,a2,a3,a4,a6]) sage: E.gens() Traceback (most recent call last): ... NotImplementedError: not implemented. - sage: E = EllipticCurve(QQ,[1,1]) + sage: E = EllipticCurve(QQ, [1,1]) sage: E.gens() [(0 : 1 : 1)] """ @@ -1434,7 +1484,7 @@ def gen(self, i): EXAMPLES:: - sage: R.<a1,a2,a3,a4,a6>=QQ[] + sage: R.<a1,a2,a3,a4,a6> = QQ[] sage: E = EllipticCurve([a1,a2,a3,a4,a6]) sage: E.gen(0) Traceback (most recent call last): @@ -1453,7 +1503,7 @@ def rst_transform(self, r, s, t): OUTPUT: - The elliptic curve obtained from self by the standard + The elliptic curve obtained from ``self`` by the standard Weierstrass transformation `(u,r,s,t)` with `u=1`. .. NOTE:: @@ -1463,10 +1513,13 @@ def rst_transform(self, r, s, t): EXAMPLES:: - sage: R.<r,s,t>=QQ[] + sage: R.<r,s,t> = QQ[] sage: E = EllipticCurve([1,2,3,4,5]) - sage: E.rst_transform(r,s,t) - Elliptic Curve defined by y^2 + (2*s+1)*x*y + (r+2*t+3)*y = x^3 + (-s^2+3*r-s+2)*x^2 + (3*r^2-r*s-2*s*t+4*r-3*s-t+4)*x + (r^3+2*r^2-r*t-t^2+4*r-3*t+5) over Multivariate Polynomial Ring in r, s, t over Rational Field + sage: E.rst_transform(r, s, t) + Elliptic Curve defined by y^2 + (2*s+1)*x*y + (r+2*t+3)*y + = x^3 + (-s^2+3*r-s+2)*x^2 + (3*r^2-r*s-2*s*t+4*r-3*s-t+4)*x + + (r^3+2*r^2-r*t-t^2+4*r-3*t+5) + over Multivariate Polynomial Ring in r, s, t over Rational Field """ return self.change_weierstrass_model(1, r, s, t) @@ -1480,7 +1533,7 @@ def scale_curve(self, u): OUTPUT: - The elliptic curve obtained from self by the standard + The elliptic curve obtained from ``self`` by the standard Weierstrass transformation `(u,r,s,t)` with `r=s=t=0`. .. NOTE:: @@ -1490,11 +1543,13 @@ def scale_curve(self, u): EXAMPLES:: - sage: K = Frac(PolynomialRing(QQ,'u')) + sage: K = Frac(PolynomialRing(QQ, 'u')) sage: u = K.gen() sage: E = EllipticCurve([1,2,3,4,5]) sage: E.scale_curve(u) - Elliptic Curve defined by y^2 + u*x*y + 3*u^3*y = x^3 + 2*u^2*x^2 + 4*u^4*x + 5*u^6 over Fraction Field of Univariate Polynomial Ring in u over Rational Field + Elliptic Curve defined by + y^2 + u*x*y + 3*u^3*y = x^3 + 2*u^2*x^2 + 4*u^4*x + 5*u^6 + over Fraction Field of Univariate Polynomial Ring in u over Rational Field """ if isinstance(u, int): u = self.base_ring()(u) # because otherwise 1/u would round! @@ -1617,12 +1672,14 @@ def division_polynomial_0(self, n, x=None): sage: f = E.division_polynomial_0(5); f 5*x^12 + x^9 + 8*x^6 + 4*x^3 + 7 sage: f.factor() - (5) * (x^2 + 5) * (x^2 + 2*x + 5) * (x^2 + 5*x + 7) * (x^2 + 7*x + 7) * (x^2 + 9*x + 5) * (x^2 + 10*x + 7) + (5) * (x^2 + 5) * (x^2 + 2*x + 5) * (x^2 + 5*x + 7) + * (x^2 + 7*x + 7) * (x^2 + 9*x + 5) * (x^2 + 10*x + 7) This indicates that the `x`-coordinates of all the 5-torsion points of `E` are in `\GF{11^2}`, and therefore the `y`-coordinates are in `\GF{11^4}`:: + sage: # needs sage.rings.finite_rings sage: K = GF(11^4, 'a') sage: X = E.change_ring(K) sage: f = X.division_polynomial_0(5) @@ -1643,7 +1700,7 @@ def division_polynomial_0(self, n, x=None): Now we check that these are exactly the `x`-coordinates of the 5-torsion points of `E`:: - sage: for x in x_coords: + sage: for x in x_coords: # needs sage.rings.finite_rings ....: assert X.lift_x(x).order() == 5 The roots of the polynomial are the `x`-coordinates of the points `P` @@ -1662,7 +1719,7 @@ def division_polynomial_0(self, n, x=None): sage: xlist = pol.roots(multiplicities=False); xlist [9, 2, -1/3, -5] sage: [E.lift_x(x, all=True) for x in xlist] - [[(9 : 23 : 1), (9 : -33 : 1)], [(2 : 2 : 1), (2 : -5 : 1)], [], []] + [[(9 : -33 : 1), (9 : 23 : 1)], [(2 : -5 : 1), (2 : 2 : 1)], [], []] .. NOTE:: @@ -1733,10 +1790,10 @@ def two_division_polynomial(self, x=None): sage: E = EllipticCurve('5077a1') sage: E.two_division_polynomial() 4*x^3 - 28*x + 25 - sage: E = EllipticCurve(GF(3^2,'a'),[1,1,1,1,1]) - sage: E.two_division_polynomial() + sage: E = EllipticCurve(GF(3^2,'a'), [1,1,1,1,1]) # needs sage.rings.finite_rings + sage: E.two_division_polynomial() # needs sage.rings.finite_rings x^3 + 2*x^2 + 2 - sage: E.two_division_polynomial().roots() + sage: E.two_division_polynomial().roots() # needs sage.rings.finite_rings [(2, 1), (2*a, 1), (a + 2, 1)] """ return self.division_polynomial_0(-1,x) @@ -1825,11 +1882,12 @@ def division_polynomial(self, m, x=None, two_torsion_multiplicity=2, force_evalu :: sage: E = EllipticCurve([0, -1, 1, -10, -20]) - sage: R.<z>=PolynomialRing(QQ) - sage: E.division_polynomial(4,z,0) + sage: R.<z> = PolynomialRing(QQ) + sage: E.division_polynomial(4, z, 0) 2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821 - sage: E.division_polynomial(4,z) - 8*z^9 - 24*z^8 - 464*z^7 - 2758*z^6 + 6636*z^5 + 34356*z^4 + 53510*z^3 + 99714*z^2 + 351024*z + 459859 + sage: E.division_polynomial(4, z) + 8*z^9 - 24*z^8 - 464*z^7 - 2758*z^6 + 6636*z^5 + 34356*z^4 + + 53510*z^3 + 99714*z^2 + 351024*z + 459859 This does not work, since when two_torsion_multiplicity is 1, we compute a bivariate polynomial, and must evaluate at a tuple of @@ -1838,9 +1896,10 @@ def division_polynomial(self, m, x=None, two_torsion_multiplicity=2, force_evalu sage: E.division_polynomial(4,z,1) Traceback (most recent call last): ... - ValueError: x should be a tuple of length 2 (or None) when two_torsion_multiplicity is 1 - sage: R.<z,w>=PolynomialRing(QQ,2) - sage: E.division_polynomial(4,(z,w),1).factor() + ValueError: x should be a tuple of length 2 (or None) + when two_torsion_multiplicity is 1 + sage: R.<z,w> = PolynomialRing(QQ, 2) + sage: E.division_polynomial(4, (z,w), 1).factor() (2*w + 1) * (2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821) We can also evaluate this bivariate polynomial at a point:: @@ -1888,7 +1947,7 @@ def division_polynomial(self, m, x=None, two_torsion_multiplicity=2, force_evalu if not (isinstance(x, tuple) and len(x) == 2): raise ValueError("x should be a tuple of length 2 (or None) when two_torsion_multiplicity is 1") - m = rings.Integer(m) + m = Integer(m) if x is None: try: @@ -1991,6 +2050,14 @@ def _multiple_x_numerator(self, n, x=None): EXAMPLES:: + sage: E = EllipticCurve([1,2]) + sage: E._multiple_x_numerator(3) + x^9 - 12*x^7 - 192*x^6 + 30*x^5 - 48*x^4 + 228*x^3 + 96*x^2 + 393*x + 528 + sage: E._multiple_x_numerator(-3) + x^9 - 12*x^7 - 192*x^6 + 30*x^5 - 48*x^4 + 228*x^3 + 96*x^2 + 393*x + 528 + + :: + sage: E = EllipticCurve("37a") sage: P = E.gens()[0] sage: x = P[0] @@ -2036,6 +2103,7 @@ def _multiple_x_numerator(self, n, x=None): Check for :trac:`33156`:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(65537), [5,5]) sage: R.<x> = E.base_field()[] sage: E._multiple_x_numerator(5, x=R.quotient(x^2).gen()) @@ -2043,9 +2111,9 @@ def _multiple_x_numerator(self, n, x=None): sage: E._multiple_x_numerator(5) x^25 + 65037*x^23 + 55137*x^22 + ... + 813*x^2 + 10220*x + 42539 """ - n = rings.Integer(n) - if n < 2: - raise ValueError("n must be at least 2") + n = Integer(n).abs() + if not n: + raise ValueError("n must be nonzero") if x is None: try: @@ -2061,6 +2129,9 @@ def _multiple_x_numerator(self, n, x=None): cache = None xx = x + if n == 1: + return xx + polys = self.division_polynomial_0([-2,-1,n-1,n,n+1], x) if n % 2 == 0: @@ -2101,6 +2172,14 @@ def _multiple_x_denominator(self, n, x=None): EXAMPLES:: + sage: E = EllipticCurve([1,2]) + sage: E._multiple_x_denominator(3) + 9*x^8 + 36*x^6 + 144*x^5 + 30*x^4 + 288*x^3 + 564*x^2 - 48*x + 1 + sage: E._multiple_x_denominator(-3) + 9*x^8 + 36*x^6 + 144*x^5 + 30*x^4 + 288*x^3 + 564*x^2 - 48*x + 1 + + :: + sage: E = EllipticCurve("43a") sage: P = E.gens()[0] sage: x = P[0] @@ -2121,6 +2200,7 @@ def _multiple_x_denominator(self, n, x=None): Check for :trac:`33156`:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(65537), [5,5]) sage: R.<x> = E.base_field()[] sage: E._multiple_x_denominator(5, x=R.quotient(x^2).gen()) @@ -2128,9 +2208,9 @@ def _multiple_x_denominator(self, n, x=None): sage: E._multiple_x_denominator(5) 25*x^24 + 3100*x^22 + 19000*x^21 + ... + 24111*x^2 + 52039*x + 56726 """ - n = rings.Integer(n) - if n < 2: - raise ValueError("n must be at least 2") + n = Integer(n).abs() + if not n: + raise ValueError("n must be nonzero") if x is None: try: @@ -2194,7 +2274,8 @@ def multiplication_by_m(self, m, x_only=False): sage: f = E.multiplication_by_m(2) sage: f - ((x^4 + 2*x^2 - 24*x + 1)/(4*x^3 - 4*x + 12), (8*x^6*y - 40*x^4*y + 480*x^3*y - 40*x^2*y + 96*x*y - 568*y)/(64*x^6 - 128*x^4 + 384*x^3 + 64*x^2 - 384*x + 576)) + ((x^4 + 2*x^2 - 24*x + 1)/(4*x^3 - 4*x + 12), + (8*x^6*y - 40*x^4*y + 480*x^3*y - 40*x^2*y + 96*x*y - 568*y)/(64*x^6 - 128*x^4 + 384*x^3 + 64*x^2 - 384*x + 576)) Grab only the x-coordinate (less work):: @@ -2243,7 +2324,8 @@ def multiplication_by_m(self, m, x_only=False): The following test shows that :trac:`4364` is indeed fixed:: - sage: p = next_prime(2^30-41) + sage: # needs sage.rings.finite_rings + sage: p = next_prime(2^30 - 41) sage: a = GF(p)(1) sage: b = GF(p)(1) sage: E = EllipticCurve([a, b]) @@ -2253,7 +2335,7 @@ def multiplication_by_m(self, m, x_only=False): sage: assert(E(eval(f,P)) == 2*P) """ # Coerce the input m to be an integer - m = rings.Integer(m) + m = Integer(m) if m == 0: raise ValueError("m must be a non-zero integer") @@ -2302,8 +2384,8 @@ def multiplication_by_m_isogeny(self, m): multiplication-by-`m` map on this elliptic curve. The resulting isogeny will - have the associated rational maps (i.e. those returned by - `self.multiplication_by_m()`) already computed. + have the associated rational maps (i.e., those returned by + :meth:`multiplication_by_m`) already computed. NOTE: This function is currently *much* slower than the result of ``self.multiplication_by_m()``, because @@ -2325,21 +2407,25 @@ def multiplication_by_m_isogeny(self, m): sage: E = EllipticCurve('11a1') sage: E.multiplication_by_m_isogeny(7) doctest:warning ... DeprecationWarning: ... - Isogeny of degree 49 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Isogeny of degree 49 + from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 + over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 + over Rational Field TESTS: Tests for :trac:`32490`:: - sage: E = EllipticCurve(QQbar, [1,0]) - sage: E.multiplication_by_m_isogeny(1).rational_maps() + sage: E = EllipticCurve(QQbar, [1,0]) # needs sage.rings.number_field + sage: E.multiplication_by_m_isogeny(1).rational_maps() # needs sage.rings.number_field (x, y) :: - sage: E = EllipticCurve_from_j(GF(31337).random_element()) - sage: P = E.random_point() - sage: [E.multiplication_by_m_isogeny(m)(P) == m*P for m in (1,2,3,5,7,9)] + sage: E = EllipticCurve_from_j(GF(31337).random_element()) # needs sage.rings.finite_rings + sage: P = E.random_point() # needs sage.rings.finite_rings + sage: [E.multiplication_by_m_isogeny(m)(P) == m*P for m in (1,2,3,5,7,9)] # needs sage.rings.finite_rings [True, True, True, True, True, True] :: @@ -2355,11 +2441,17 @@ def multiplication_by_m_isogeny(self, m): sage: E = EllipticCurve([5,5]) sage: E.multiplication_by_m_isogeny(-1) - Isogeny of degree 1 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field to Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field + Isogeny of degree 1 + from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field + to Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field sage: E.multiplication_by_m_isogeny(-2) - Isogeny of degree 4 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field to Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field + Isogeny of degree 4 + from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field + to Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field sage: E.multiplication_by_m_isogeny(-3) - Isogeny of degree 9 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field to Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field + Isogeny of degree 9 + from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field + to Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Rational Field sage: mu = E.multiplication_by_m_isogeny sage: all(mu(-m) == -mu(m) for m in (1,2,3,5,7)) True @@ -2392,7 +2484,8 @@ def scalar_multiplication(self, m): sage: E = EllipticCurve('77a1') sage: m = E.scalar_multiplication(-7); m - Scalar-multiplication endomorphism [-7] of Elliptic Curve defined by y^2 + y = x^3 + 2*x over Rational Field + Scalar-multiplication endomorphism [-7] + of Elliptic Curve defined by y^2 + y = x^3 + 2*x over Rational Field sage: m.degree() 49 sage: P = E(2,3) @@ -2418,16 +2511,21 @@ def frobenius_isogeny(self, n=1): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: z3, = GF(13^3).gens() - sage: E = EllipticCurve([z3,z3^2]) + sage: E = EllipticCurve([z3, z3^2]) sage: E.frobenius_isogeny() Frobenius isogeny of degree 13: - From: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2 over Finite Field in z3 of size 13^3 - To: Elliptic Curve defined by y^2 = x^3 + (5*z3^2+7*z3+11)*x + (5*z3^2+12*z3+1) over Finite Field in z3 of size 13^3 + From: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2 + over Finite Field in z3 of size 13^3 + To: Elliptic Curve defined by y^2 = x^3 + (5*z3^2+7*z3+11)*x + (5*z3^2+12*z3+1) + over Finite Field in z3 of size 13^3 sage: E.frobenius_isogeny(3) Frobenius endomorphism of degree 2197 = 13^3: - From: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2 over Finite Field in z3 of size 13^3 - To: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2 over Finite Field in z3 of size 13^3 + From: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2 + over Finite Field in z3 of size 13^3 + To: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2 + over Finite Field in z3 of size 13^3 """ p = self.base_ring().characteristic() if not p: @@ -2437,8 +2535,8 @@ def frobenius_isogeny(self, n=1): def isomorphism_to(self, other): """ - Given another weierstrass model ``other`` of self, return an - isomorphism from self to ``other``. + Given another weierstrass model ``other`` of ``self``, return an + isomorphism from ``self`` to ``other``. INPUT: @@ -2446,7 +2544,7 @@ def isomorphism_to(self, other): OUTPUT: - (Weierstrassmorphism) An isomorphism from self to other. + (Weierstrassmorphism) An isomorphism from ``self`` to ``other``. .. NOTE:: @@ -2459,9 +2557,9 @@ def isomorphism_to(self, other): sage: F = E.short_weierstrass_model() sage: w = E.isomorphism_to(F); w Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field - To: Elliptic Curve defined by y^2 = x^3 - 16*x + 16 over Rational Field - Via: (u,r,s,t) = (1/2, 0, 0, -1/2) + From: Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + To: Elliptic Curve defined by y^2 = x^3 - 16*x + 16 over Rational Field + Via: (u,r,s,t) = (1/2, 0, 0, -1/2) sage: P = E(0,-1,1) sage: w(P) (0 : -4 : 1) @@ -2474,18 +2572,20 @@ def isomorphism_to(self, other): We can also handle injections to different base rings:: - sage: K.<a> = NumberField(x^3-7) - sage: E.isomorphism_to(E.change_ring(K)) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 7) # needs sage.rings.number_field + sage: E.isomorphism_to(E.change_ring(K)) # needs sage.rings.number_field Elliptic-curve morphism: From: Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field - To: Elliptic Curve defined by y^2 + y = x^3 + (-1)*x over Number Field in a with defining polynomial x^3 - 7 + To: Elliptic Curve defined by y^2 + y = x^3 + (-1)*x + over Number Field in a with defining polynomial x^3 - 7 Via: (u,r,s,t) = (1, 0, 0, 0) """ return wm.WeierstrassIsomorphism(self, None, other) def automorphisms(self, field=None): """ - Return the set of isomorphisms from self to itself (as a list). + Return the set of isomorphisms from ``self`` to itself (as a list). The identity and negation morphisms are guaranteed to appear as the first and second entry of the returned list. @@ -2506,37 +2606,48 @@ def automorphisms(self, field=None): sage: E = EllipticCurve_from_j(QQ(0)) # a curve with j=0 over QQ sage: E.automorphisms() - [Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 over Rational Field + [Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 + over Rational Field Via: (u,r,s,t) = (1, 0, 0, 0), - Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 over Rational Field + Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 + over Rational Field Via: (u,r,s,t) = (-1, 0, 0, -1)] We can also find automorphisms defined over extension fields:: - sage: K.<a> = NumberField(x^2+3) # adjoin roots of unity - sage: E.automorphisms(K) - [Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 over Number Field in a with defining polynomial x^2 + 3 + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 + 3) # adjoin roots of unity # needs sage.rings.number_field + sage: E.automorphisms(K) # needs sage.rings.number_field + [Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 + over Number Field in a with defining polynomial x^2 + 3 Via: (u,r,s,t) = (1, 0, 0, 0), - Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 over Number Field in a with defining polynomial x^2 + 3 + Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 + over Number Field in a with defining polynomial x^2 + 3 Via: (u,r,s,t) = (-1, 0, 0, -1), - Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 over Number Field in a with defining polynomial x^2 + 3 + Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 + over Number Field in a with defining polynomial x^2 + 3 Via: (u,r,s,t) = (-1/2*a - 1/2, 0, 0, 0), - Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 over Number Field in a with defining polynomial x^2 + 3 + Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 + over Number Field in a with defining polynomial x^2 + 3 Via: (u,r,s,t) = (1/2*a + 1/2, 0, 0, -1), - Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 over Number Field in a with defining polynomial x^2 + 3 + Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 + over Number Field in a with defining polynomial x^2 + 3 Via: (u,r,s,t) = (1/2*a - 1/2, 0, 0, 0), - Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 over Number Field in a with defining polynomial x^2 + 3 + Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 + over Number Field in a with defining polynomial x^2 + 3 Via: (u,r,s,t) = (-1/2*a + 1/2, 0, 0, -1)] :: - sage: [len(EllipticCurve_from_j(GF(q,'a')(0)).automorphisms()) for q in [2,4,3,9,5,25,7,49]] + sage: [len(EllipticCurve_from_j(GF(q,'a')(0)).automorphisms()) # needs sage.rings.finite_rings + ....: for q in [2,4,3,9,5,25,7,49]] [2, 24, 2, 12, 2, 6, 6, 6] TESTS: Random testing:: + sage: # needs sage.rings.finite_rings sage: p = random_prime(100) sage: k = randrange(1,30) sage: F.<t> = GF((p,k)) @@ -2560,7 +2671,7 @@ def automorphisms(self, field=None): def isomorphisms(self, other, field=None): """ - Return the set of isomorphisms from self to other (as a list). + Return the set of isomorphisms from ``self`` to ``other`` (as a list). INPUT: @@ -2581,25 +2692,33 @@ def isomorphisms(self, other, field=None): sage: E = EllipticCurve_from_j(QQ(0)) # a curve with j=0 over QQ sage: F = EllipticCurve('27a3') # should be the same one sage: E.isomorphisms(F) - [Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 over Rational Field + [Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 + over Rational Field Via: (u,r,s,t) = (1, 0, 0, 0), - Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 over Rational Field + Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3 + over Rational Field Via: (u,r,s,t) = (-1, 0, 0, -1)] We can also find isomorphisms defined over extension fields:: - sage: E = EllipticCurve(GF(7),[0,0,0,1,1]) - sage: F = EllipticCurve(GF(7),[0,0,0,1,-1]) + sage: # needs sage.rings.finite_rings + sage: E = EllipticCurve(GF(7), [0,0,0,1,1]) + sage: F = EllipticCurve(GF(7), [0,0,0,1,-1]) sage: E.isomorphisms(F) [] - sage: E.isomorphisms(F,GF(49,'a')) + sage: E.isomorphisms(F, GF(49,'a')) [Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 7^2 - To: Elliptic Curve defined by y^2 = x^3 + x + 6 over Finite Field in a of size 7^2 - Via: (u,r,s,t) = (a + 3, 0, 0, 0), Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 7^2 - To: Elliptic Curve defined by y^2 = x^3 + x + 6 over Finite Field in a of size 7^2 - Via: (u,r,s,t) = (6*a + 4, 0, 0, 0)] + From: Elliptic Curve defined by y^2 = x^3 + x + 1 + over Finite Field in a of size 7^2 + To: Elliptic Curve defined by y^2 = x^3 + x + 6 + over Finite Field in a of size 7^2 + Via: (u,r,s,t) = (a + 3, 0, 0, 0), + Elliptic-curve morphism: + From: Elliptic Curve defined by y^2 = x^3 + x + 1 + over Finite Field in a of size 7^2 + To: Elliptic Curve defined by y^2 = x^3 + x + 6 + over Finite Field in a of size 7^2 + Via: (u,r,s,t) = (6*a + 4, 0, 0, 0)] """ if field is not None: self = self.change_ring(field) @@ -2609,7 +2728,7 @@ def isomorphisms(self, other, field=None): def is_isomorphic(self, other, field=None): """ - Return whether or not self is isomorphic to other. + Return whether or not ``self`` is isomorphic to ``other``. INPUT: @@ -2628,7 +2747,8 @@ def is_isomorphic(self, other, field=None): sage: E = EllipticCurve('389a') sage: F = E.change_weierstrass_model([2,3,4,5]); F - Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 3/2*x^2 - 13/16*x over Rational Field + Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 3/2*x^2 - 13/16*x + over Rational Field sage: E.is_isomorphic(F) True sage: E.is_isomorphic(F.change_ring(CC)) @@ -2652,7 +2772,7 @@ def is_isomorphic(self, other, field=None): def change_weierstrass_model(self, *urst): r""" - Return a new Weierstrass model of self under the standard transformation `(u,r,s,t)` + Return a new Weierstrass model of ``self`` under the standard transformation `(u,r,s,t)` .. MATH:: @@ -2662,9 +2782,12 @@ def change_weierstrass_model(self, *urst): sage: E = EllipticCurve('15a') sage: F1 = E.change_weierstrass_model([1/2,0,0,0]); F1 - Elliptic Curve defined by y^2 + 2*x*y + 8*y = x^3 + 4*x^2 - 160*x - 640 over Rational Field + Elliptic Curve defined by y^2 + 2*x*y + 8*y = x^3 + 4*x^2 - 160*x - 640 + over Rational Field sage: F2 = E.change_weierstrass_model([7,2,1/3,5]); F2 - Elliptic Curve defined by y^2 + 5/21*x*y + 13/343*y = x^3 + 59/441*x^2 - 10/7203*x - 58/117649 over Rational Field + Elliptic Curve defined by + y^2 + 5/21*x*y + 13/343*y = x^3 + 59/441*x^2 - 10/7203*x - 58/117649 + over Rational Field sage: F1.is_isomorphic(F2) True """ @@ -2711,7 +2834,7 @@ def short_weierstrass_model(self, complete_cube=True): :: - sage: E = EllipticCurve(GF(3),[1,2,3,4,5]) + sage: E = EllipticCurve(GF(3), [1,2,3,4,5]) sage: E.short_weierstrass_model(complete_cube=False) Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 3 @@ -2722,13 +2845,16 @@ def short_weierstrass_model(self, complete_cube=True): More tests in characteristic 3:: - sage: E = EllipticCurve(GF(3),[0,2,1,2,1]) + sage: E = EllipticCurve(GF(3), [0,2,1,2,1]) sage: E.short_weierstrass_model() Traceback (most recent call last): ... - ValueError: short_weierstrass_model(): no short model for Elliptic Curve defined by y^2 + y = x^3 + 2*x^2 + 2*x + 1 over Finite Field of size 3 (characteristic is 3) + ValueError: short_weierstrass_model(): no short model for Elliptic Curve + defined by y^2 + y = x^3 + 2*x^2 + 2*x + 1 over Finite Field of size 3 + (characteristic is 3) sage: E.short_weierstrass_model(complete_cube=False) - Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2*x + 2 over Finite Field of size 3 + Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2*x + 2 + over Finite Field of size 3 sage: E.short_weierstrass_model(complete_cube=False).is_isomorphic(E) True """ @@ -2802,24 +2928,29 @@ def montgomery_model(self, twisted=False, morphism=False): EXAMPLES:: - sage: E = EllipticCurve(QQbar, '11a1') - sage: E.montgomery_model() - Elliptic Curve defined by y^2 = x^3 + (-1.953522420987248?)*x^2 + x over Algebraic Field + sage: E = EllipticCurve(QQbar, '11a1') # needs sage.rings.number_field + sage: E.montgomery_model() # needs sage.rings.number_field + Elliptic Curve defined by y^2 = x^3 + (-1.953522420987248?)*x^2 + x + over Algebraic Field :: - sage: E = EllipticCurve(GF(431^2), [7,7]) - sage: E.montgomery_model() - Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x over Finite Field in z2 of size 431^2 + sage: E = EllipticCurve(GF(431^2), [7,7]) # needs sage.rings.finite_rings + sage: E.montgomery_model() # needs sage.rings.finite_rings + Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x + over Finite Field in z2 of size 431^2 An isomorphism between the Montgomery and Weierstrass form can be obtained using the ``morphism`` parameter:: - sage: E.montgomery_model(morphism=True) - (Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x over Finite Field in z2 of size 431^2, + sage: E.montgomery_model(morphism=True) # needs sage.rings.finite_rings + (Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x + over Finite Field in z2 of size 431^2, Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 = x^3 + 7*x + 7 over Finite Field in z2 of size 431^2 - To: Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x over Finite Field in z2 of size 431^2 + From: Elliptic Curve defined by y^2 = x^3 + 7*x + 7 + over Finite Field in z2 of size 431^2 + To: Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x + over Finite Field in z2 of size 431^2 Via: (u,r,s,t) = (64*z2 + 407, 159, 0, 0)) Not all elliptic curves have a Montgomery model over their field @@ -2829,7 +2960,8 @@ def montgomery_model(self, twisted=False, morphism=False): sage: E.montgomery_model() Traceback (most recent call last): ... - ValueError: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 257 has no Montgomery model + ValueError: Elliptic Curve defined by y^2 = x^3 + x + 1 + over Finite Field of size 257 has no Montgomery model :: @@ -2837,14 +2969,16 @@ def montgomery_model(self, twisted=False, morphism=False): sage: E.montgomery_model() Traceback (most recent call last): ... - ValueError: Elliptic Curve defined by y^2 = x^3 + 10*x + 10 over Finite Field of size 257 has no untwisted Montgomery model + ValueError: Elliptic Curve defined by y^2 = x^3 + 10*x + 10 + over Finite Field of size 257 has no untwisted Montgomery model However, as hinted by the error message, the latter curve does admit a *twisted* Montgomery model, which can be computed by passing ``twisted=True``:: sage: E.montgomery_model(twisted=True) - Projective Plane Curve over Finite Field of size 257 defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2 + Projective Plane Curve over Finite Field of size 257 + defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2 Since Sage internally represents elliptic curves as (long) Weierstrass curves, which do not feature the Montgomery `B` coefficient, the @@ -2859,14 +2993,18 @@ def montgomery_model(self, twisted=False, morphism=False): sage: C, f = E.montgomery_model(twisted=True, morphism=True) sage: f Scheme morphism: - From: Elliptic Curve defined by y^2 = x^3 + 10*x + 10 over Finite Field of size 257 - To: Projective Plane Curve over Finite Field of size 257 defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2 + From: Elliptic Curve defined by y^2 = x^3 + 10*x + 10 + over Finite Field of size 257 + To: Projective Plane Curve over Finite Field of size 257 + defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2 Defn: Defined on coordinates by sending (x : y : z) to (x + 116*z : -y : -85*z) sage: g = f.inverse(); g Scheme morphism: - From: Projective Plane Curve over Finite Field of size 257 defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2 - To: Elliptic Curve defined by y^2 = x^3 + 10*x + 10 over Finite Field of size 257 + From: Projective Plane Curve over Finite Field of size 257 + defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2 + To: Elliptic Curve defined by y^2 = x^3 + 10*x + 10 + over Finite Field of size 257 Defn: Defined on coordinates by sending (x : y : z) to (-85*x - 116*z : 85*y : z) sage: P = C(70, 8) @@ -2882,6 +3020,7 @@ def montgomery_model(self, twisted=False, morphism=False): e(P,Q)^{\deg\psi}`, even pairings can be emulated in this way (note that isomorphisms have degree `1`):: + sage: # needs sage.rings.finite_rings sage: F.<z2> = GF(257^2) sage: C_ = C.change_ring(F) sage: g_ = g.change_ring(F) @@ -2896,11 +3035,12 @@ def montgomery_model(self, twisted=False, morphism=False): Another alternative is to simply extend the base field enough for the curve to have an untwisted Montgomery model:: - sage: C_ = E.change_ring(F).montgomery_model(); C_ - Elliptic Curve defined by y^2 = x^3 + 249*x^2 + x over Finite Field in z2 of size 257^2 - sage: h = C.defining_polynomial().change_ring(F); h + sage: C_ = E.change_ring(F).montgomery_model(); C_ # needs sage.rings.finite_rings + Elliptic Curve defined by y^2 = x^3 + 249*x^2 + x + over Finite Field in z2 of size 257^2 + sage: h = C.defining_polynomial().change_ring(F); h # needs sage.rings.finite_rings -x^3 + 8*x^2*z - 127*y^2*z - x*z^2 - sage: C_.is_isomorphic(EllipticCurve_from_cubic(h).codomain()) + sage: C_.is_isomorphic(EllipticCurve_from_cubic(h).codomain()) # needs sage.rings.finite_rings True .. SEEALSO:: @@ -3010,29 +3150,29 @@ def plot(self, xmin=None, xmax=None, components='both', **args): EXAMPLES:: - sage: E = EllipticCurve([0,-1]) - sage: plot(E, rgbcolor=hue(0.7)) + sage: E = EllipticCurve([0, -1]) + sage: plot(E, rgbcolor=hue(0.7)) # needs sage.plot Graphics object consisting of 1 graphics primitive sage: E = EllipticCurve('37a') - sage: plot(E) + sage: plot(E) # needs sage.plot Graphics object consisting of 2 graphics primitives - sage: plot(E, xmin=25,xmax=26) + sage: plot(E, xmin=25, xmax=26) # needs sage.plot Graphics object consisting of 2 graphics primitives With :trac:`12766` we added the components keyword:: sage: E.real_components() 2 - sage: E.plot(components='bounded') + sage: E.plot(components='bounded') # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: E.plot(components='unbounded') + sage: E.plot(components='unbounded') # needs sage.plot Graphics object consisting of 1 graphics primitive If there is only one component then specifying components='bounded' raises a ValueError:: sage: E = EllipticCurve('9990be2') - sage: E.plot(components='bounded') + sage: E.plot(components='bounded') # needs sage.plot Traceback (most recent call last): ... ValueError: no bounded component for this curve @@ -3040,12 +3180,13 @@ def plot(self, xmin=None, xmax=None, components='both', **args): An elliptic curve defined over the Complex Field can not be plotted:: sage: E = EllipticCurve(CC, [0,0,1,-1,0]) - sage: E.plot() + sage: E.plot() # needs sage.plot Traceback (most recent call last): ... - NotImplementedError: plotting of curves over Complex Field with 53 bits of precision is not implemented yet + NotImplementedError: plotting of curves over Complex Field + with 53 bits of precision is not implemented yet """ - RR = rings.RealField() + RR = RealField() K = self.base_ring() if not RR.has_coerce_map_from(K): raise NotImplementedError("plotting of curves over %s is not implemented yet" % K) @@ -3183,7 +3324,8 @@ def formal_group(self): sage: E = EllipticCurve("37a") sage: E.formal_group() - Formal Group associated to the Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + Formal Group associated to the Elliptic Curve + defined by y^2 + y = x^3 - x over Rational Field """ return formal_group.EllipticCurveFormalGroup(self) @@ -3222,31 +3364,35 @@ def _p_primary_torsion_basis(self, p, m=None): sage: E = EllipticCurve('11a1') sage: E._p_primary_torsion_basis(5) [[(5 : -6 : 1), 1]] + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<t> = NumberField(x^4 + x^3 + 11*x^2 + 41*x + 101) sage: EK = E.base_extend(K) - sage: EK._p_primary_torsion_basis(5) # long time (2s on sage.math, 2011) + sage: EK._p_primary_torsion_basis(5) # long time [[(16 : 60 : 1), 1], [(t : 1/11*t^3 + 6/11*t^2 + 19/11*t + 48/11 : 1), 1]] - sage: EF = E.change_ring(GF(101)) - sage: EF._p_primary_torsion_basis(5) + sage: EF = E.change_ring(GF(101)) # needs sage.rings.finite_rings + sage: EF._p_primary_torsion_basis(5) # needs sage.rings.finite_rings [[(0 : 13 : 1), 1], [(5 : 5 : 1), 1]] - sage: F.<z> = CyclotomicField(21) - sage: E = EllipticCurve([2,-z^7,-z^7,0,0]) - sage: E._p_primary_torsion_basis(7,2) # long time (8s on sage.math, 2011) + sage: F.<z> = CyclotomicField(21) # needs sage.rings.number_field + sage: E = EllipticCurve([2, -z^7, -z^7, 0, 0]) # needs sage.rings.number_field + sage: E._p_primary_torsion_basis(7,2) # long time # needs sage.rings.number_field [[(0 : z^7 : 1), 1], - [(z^7 - z^6 + z^4 - z^3 + z^2 - 1 : z^8 - 2*z^7 + z^6 + 2*z^5 - 3*z^4 + 2*z^3 - 2*z + 2 : 1), 1]] + [(z^7 - z^6 + z^4 - z^3 + z^2 - 1 + : z^8 - 2*z^7 + z^6 + 2*z^5 - 3*z^4 + 2*z^3 - 2*z + 2 : 1), 1]] TESTS: This shows that the bug at :trac:`4937` is fixed:: - sage: a=804515977734860566494239770982282063895480484302363715494873 - sage: b=584772221603632866665682322899297141793188252000674256662071 - sage: E = EllipticCurve(GF(10^60+3201),[0,a,0,b,0]) - sage: [t[1] for t in E._p_primary_torsion_basis(2)] # long time (3s on sage.math, 2011) + sage: a = 804515977734860566494239770982282063895480484302363715494873 + sage: b = 584772221603632866665682322899297141793188252000674256662071 + sage: E = EllipticCurve(GF(10^60 + 3201), [0,a,0,b,0]) # needs sage.rings.finite_rings + sage: [t[1] for t in E._p_primary_torsion_basis(2)] # long time, needs sage.rings.finite_rings [16, 1] """ - p = rings.Integer(p) + p = Integer(p) if not p.is_prime(): raise ValueError("p (=%s) should be prime" % p) @@ -3259,7 +3405,7 @@ def _p_primary_torsion_basis(self, p, m=None): # First find the p-torsion: Ep = self(0).division_points(p) - p_rank = rings.Integer(len(Ep)).exact_log(p) + p_rank = Integer(len(Ep)).exact_log(p) assert p_rank in [0, 1, 2] if p_rank == 0: @@ -3396,6 +3542,7 @@ def pari_curve(self): EXAMPLES:: + sage: # needs sage.libs.pari sage: E = EllipticCurve([RR(0), RR(0), RR(1), RR(-1), RR(0)]) sage: e = E.pari_curve() sage: type(e) @@ -3407,40 +3554,48 @@ def pari_curve(self): Over a finite field:: - sage: EllipticCurve(GF(41),[2,5]).pari_curve() - [Mod(0, 41), Mod(0, 41), Mod(0, 41), Mod(2, 41), Mod(5, 41), Mod(0, 41), Mod(4, 41), Mod(20, 41), Mod(37, 41), Mod(27, 41), Mod(26, 41), Mod(4, 41), Mod(11, 41), Vecsmall([3]), [41, [9, 31, [6, 0, 0, 0]]], [0, 0, 0, 0]] + sage: EllipticCurve(GF(41), [2,5]).pari_curve() # needs sage.libs.pari + [Mod(0, 41), Mod(0, 41), Mod(0, 41), Mod(2, 41), Mod(5, 41), + Mod(0, 41), Mod(4, 41), Mod(20, 41), Mod(37, 41), Mod(27, 41), + Mod(26, 41), Mod(4, 41), Mod(11, 41), + Vecsmall([3]), + [41, [9, 31, [6, 0, 0, 0]]], [0, 0, 0, 0]] Over a `p`-adic field:: + sage: # needs sage.libs.pari sage.rings.padics sage: Qp = pAdicField(5, prec=3) - sage: E = EllipticCurve(Qp,[3, 4]) + sage: E = EllipticCurve(Qp, [3, 4]) sage: E.pari_curve() - [0, 0, 0, 3, 4, 0, 6, 16, -9, -144, -3456, -8640, 1728/5, Vecsmall([2]), [O(5^3)], [0, 0]] + [0, 0, 0, 3, 4, 0, 6, 16, -9, -144, -3456, -8640, 1728/5, + Vecsmall([2]), [O(5^3)], [0, 0]] sage: E.j_invariant() 3*5^-1 + O(5) Over a number field:: - sage: K.<a> = QuadraticField(2) - sage: E = EllipticCurve([1,a]) - sage: E.pari_curve() + sage: K.<a> = QuadraticField(2) # needs sage.libs.pari sage.rings.number_field + sage: E = EllipticCurve([1,a]) # needs sage.libs.pari sage.rings.number_field + sage: E.pari_curve() # needs sage.libs.pari sage.rings.number_field [0, 0, 0, Mod(1, y^2 - 2), - Mod(y, y^2 - 2), 0, Mod(2, y^2 - 2), Mod(4*y, y^2 - 2), - Mod(-1, y^2 - 2), Mod(-48, y^2 - 2), Mod(-864*y, y^2 - 2), - Mod(-928, y^2 - 2), Mod(3456/29, y^2 - 2), Vecsmall([5]), - [[y^2 - 2, [2, 0], 8, 1, [[1, -1.41421356237310; - 1, 1.41421356237310], [1, -1.41421356237310; 1, 1.41421356237310], - [16, -23; 16, 23], [2, 0; 0, 4], [4, 0; 0, 2], [2, 0; 0, 1], - [2, [0, 2; 1, 0]], [2]], [-1.41421356237310, 1.41421356237310], - [1, y], [1, 0; 0, 1], [1, 0, 0, 2; 0, 1, 1, 0]]], [0, 0, 0, 0, 0]] + Mod(y, y^2 - 2), 0, Mod(2, y^2 - 2), Mod(4*y, y^2 - 2), + Mod(-1, y^2 - 2), Mod(-48, y^2 - 2), Mod(-864*y, y^2 - 2), + Mod(-928, y^2 - 2), Mod(3456/29, y^2 - 2), + Vecsmall([5]), + [[y^2 - 2, [2, 0], 8, 1, [[1, -1.41421356237310; 1, 1.41421356237310], + [1, -1.41421356237310; 1, 1.41421356237310], + [16, -23; 16, 23], [2, 0; 0, 4], [4, 0; 0, 2], [2, 0; 0, 1], + [2, [0, 2; 1, 0]], [2]], [-1.41421356237310, 1.41421356237310], + [1, y], [1, 0; 0, 1], [1, 0, 0, 2; 0, 1, 1, 0]]], [0, 0, 0, 0, 0]] PARI no longer requires that the `j`-invariant has negative `p`-adic valuation:: - sage: E = EllipticCurve(Qp,[1, 1]) - sage: E.j_invariant() # the j-invariant is a p-adic integer + sage: E = EllipticCurve(Qp,[1, 1]) # needs sage.libs.pari sage.rings.padics + sage: E.j_invariant() # the j-invariant is a p-adic integer # needs sage.libs.pari sage.rings.padics 2 + 4*5^2 + O(5^3) - sage: E.pari_curve() - [0, 0, 0, 1, 1, 0, 2, 4, -1, -48, -864, -496, 6912/31, Vecsmall([2]), [O(5^3)], [0, 0]] + sage: E.pari_curve() # needs sage.libs.pari sage.rings.padics + [0, 0, 0, 1, 1, 0, 2, 4, -1, -48, -864, -496, 6912/31, + Vecsmall([2]), [O(5^3)], [0, 0]] """ from sage.categories.number_fields import NumberFields from sage.libs.pari import pari @@ -3459,12 +3614,12 @@ def __pari__(self): EXAMPLES:: sage: E = EllipticCurve('11a1') - sage: pari(E) + sage: pari(E) # needs sage.libs.pari [0, -1, 1, -10, -20, -4, -20, -79, -21, 496, 20008, -161051, -122023936/161051, Vecsmall([1]), [Vecsmall([64, -1])], [0, 0, 0, 0, 0, 0, 0, 0]] Over a finite field:: - sage: EllipticCurve(GF(2), [0,0,1,1,1]).__pari__() + sage: EllipticCurve(GF(2), [0,0,1,1,1]).__pari__() # needs sage.libs.pari [0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, Vecsmall([4]), [1, [[Vecsmall([0, 1]), Vecsmall([0, 1]), Vecsmall([0, 1])], Vecsmall([0, 1]), [Vecsmall([0, 1]), Vecsmall([0]), Vecsmall([0]), Vecsmall([0])]]], [0, 0, 0, 0]] """ return self.pari_curve() diff --git a/src/sage/schemes/elliptic_curves/ell_local_data.py b/src/sage/schemes/elliptic_curves/ell_local_data.py index 541492f527e..11a0e9db661 100644 --- a/src/sage/schemes/elliptic_curves/ell_local_data.py +++ b/src/sage/schemes/elliptic_curves/ell_local_data.py @@ -16,8 +16,10 @@ EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) - sage: E = EllipticCurve([(2+i)^2,(2+i)^7]) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) + sage: E = EllipticCurve([(2+i)^2, (2+i)^7]) sage: pp = K.fractional_ideal(2+i) sage: da = E.local_data(pp) sage: da.has_bad_reduction() @@ -29,39 +31,45 @@ sage: da.tamagawa_number() 4 sage: da.minimal_model() - Elliptic Curve defined by y^2 = x^3 + (4*i+3)*x + (-29*i-278) over Number Field in i with defining polynomial x^2 + 1 + Elliptic Curve defined by y^2 = x^3 + (4*i+3)*x + (-29*i-278) + over Number Field in i with defining polynomial x^2 + 1 An example to show how the Neron model can change as one extends the field:: sage: E = EllipticCurve([0,-1]) sage: E.local_data(2) Local data at Principal ideal (2) of Integer Ring: - Reduction type: bad additive - Local minimal model: Elliptic Curve defined by y^2 = x^3 - 1 over Rational Field - Minimal discriminant valuation: 4 - Conductor exponent: 4 - Kodaira Symbol: II - Tamagawa Number: 1 - + Reduction type: bad additive + Local minimal model: Elliptic Curve defined by y^2 = x^3 - 1 over Rational Field + Minimal discriminant valuation: 4 + Conductor exponent: 4 + Kodaira Symbol: II + Tamagawa Number: 1 + + sage: # needs sage.rings.number_field sage: EK = E.base_extend(K) sage: EK.local_data(1+i) Local data at Fractional ideal (i + 1): - Reduction type: bad additive - Local minimal model: Elliptic Curve defined by y^2 = x^3 + (-1) over Number Field in i with defining polynomial x^2 + 1 - Minimal discriminant valuation: 8 - Conductor exponent: 2 - Kodaira Symbol: IV* - Tamagawa Number: 3 + Reduction type: bad additive + Local minimal model: Elliptic Curve defined by y^2 = x^3 + (-1) + over Number Field in i with defining polynomial x^2 + 1 + Minimal discriminant valuation: 8 + Conductor exponent: 2 + Kodaira Symbol: IV* + Tamagawa Number: 3 Or how the minimal equation changes:: sage: E = EllipticCurve([0,8]) sage: E.is_minimal() True + + sage: # needs sage.rings.number_field sage: EK = E.base_extend(K) sage: da = EK.local_data(1+i) sage: da.minimal_model() - Elliptic Curve defined by y^2 = x^3 + (-i) over Number Field in i with defining polynomial x^2 + 1 + Elliptic Curve defined by y^2 = x^3 + (-i) + over Number Field in i with defining polynomial x^2 + 1 AUTHORS: @@ -95,7 +103,7 @@ from sage.rings.integer import Integer from sage.rings.number_field.number_field_ideal import is_NumberFieldFractionalIdeal -from sage.rings.number_field.number_field import is_NumberField +from sage.rings.number_field.number_field_base import NumberField from sage.rings.ideal import is_Ideal from .constructor import EllipticCurve @@ -116,7 +124,7 @@ class EllipticCurveLocalData(SageObject): - ``P`` -- a prime ideal of the field, or a prime integer if the field is `\QQ`. - - ``proof`` (bool)-- if True, only use provably correct + - ``proof`` (bool) -- if ``True``, only use provably correct methods (default controlled by global proof module). Note that the proof module is number_field, not elliptic_curves, since the functions that actually need the flag are in @@ -140,12 +148,13 @@ class EllipticCurveLocalData(SageObject): sage: E = EllipticCurve('14a1') sage: EllipticCurveLocalData(E,2) Local data at Principal ideal (2) of Integer Ring: - Reduction type: bad non-split multiplicative - Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field - Minimal discriminant valuation: 6 - Conductor exponent: 1 - Kodaira Symbol: I6 - Tamagawa Number: 2 + Reduction type: bad non-split multiplicative + Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 + over Rational Field + Minimal discriminant valuation: 6 + Conductor exponent: 1 + Kodaira Symbol: I6 + Tamagawa Number: 2 """ def __init__(self, E, P, proof=None, algorithm="pari", globally=False): @@ -184,65 +193,70 @@ def __init__(self, E, P, proof=None, algorithm="pari", globally=False): sage: from sage.schemes.elliptic_curves.ell_local_data import EllipticCurveLocalData sage: E = EllipticCurve('14a1') - sage: EllipticCurveLocalData(E,2) + sage: EllipticCurveLocalData(E, 2) Local data at Principal ideal (2) of Integer Ring: - Reduction type: bad non-split multiplicative - Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field - Minimal discriminant valuation: 6 - Conductor exponent: 1 - Kodaira Symbol: I6 - Tamagawa Number: 2 + Reduction type: bad non-split multiplicative + Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 + over Rational Field + Minimal discriminant valuation: 6 + Conductor exponent: 1 + Kodaira Symbol: I6 + Tamagawa Number: 2 :: - sage: EllipticCurveLocalData(E,2,algorithm="generic") + sage: EllipticCurveLocalData(E, 2, algorithm="generic") Local data at Principal ideal (2) of Integer Ring: - Reduction type: bad non-split multiplicative - Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field - Minimal discriminant valuation: 6 - Conductor exponent: 1 - Kodaira Symbol: I6 - Tamagawa Number: 2 + Reduction type: bad non-split multiplicative + Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 + over Rational Field + Minimal discriminant valuation: 6 + Conductor exponent: 1 + Kodaira Symbol: I6 + Tamagawa Number: 2 :: - sage: EllipticCurveLocalData(E,2,algorithm="pari") + sage: EllipticCurveLocalData(E, 2, algorithm="pari") Local data at Principal ideal (2) of Integer Ring: - Reduction type: bad non-split multiplicative - Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field - Minimal discriminant valuation: 6 - Conductor exponent: 1 - Kodaira Symbol: I6 - Tamagawa Number: 2 + Reduction type: bad non-split multiplicative + Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 + over Rational Field + Minimal discriminant valuation: 6 + Conductor exponent: 1 + Kodaira Symbol: I6 + Tamagawa Number: 2 :: - sage: EllipticCurveLocalData(E,2,algorithm="unknown") + sage: EllipticCurveLocalData(E, 2, algorithm="unknown") Traceback (most recent call last): ... ValueError: algorithm must be one of 'pari', 'generic' :: - sage: EllipticCurveLocalData(E,3) + sage: EllipticCurveLocalData(E, 3) Local data at Principal ideal (3) of Integer Ring: - Reduction type: good - Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field - Minimal discriminant valuation: 0 - Conductor exponent: 0 - Kodaira Symbol: I0 - Tamagawa Number: 1 + Reduction type: good + Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 + over Rational Field + Minimal discriminant valuation: 0 + Conductor exponent: 0 + Kodaira Symbol: I0 + Tamagawa Number: 1 :: - sage: EllipticCurveLocalData(E,7) + sage: EllipticCurveLocalData(E, 7) Local data at Principal ideal (7) of Integer Ring: - Reduction type: bad split multiplicative - Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field - Minimal discriminant valuation: 3 - Conductor exponent: 1 - Kodaira Symbol: I3 - Tamagawa Number: 3 + Reduction type: bad split multiplicative + Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 + over Rational Field + Minimal discriminant valuation: 3 + Conductor exponent: 1 + Kodaira Symbol: I3 + Tamagawa Number: 3 """ self._curve = E K = E.base_field() @@ -313,8 +327,8 @@ def minimal_model(self, reduce=True): sage: from sage.schemes.elliptic_curves.ell_local_data import EllipticCurveLocalData sage: E = EllipticCurve([0,0,0,0,64]); E - Elliptic Curve defined by y^2 = x^3 + 64 over Rational Field - sage: data = EllipticCurveLocalData(E,2) + Elliptic Curve defined by y^2 = x^3 + 64 over Rational Field + sage: data = EllipticCurveLocalData(E, 2) sage: data.minimal_model() Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field sage: data.minimal_model() == E.local_minimal_model(2) @@ -322,12 +336,16 @@ def minimal_model(self, reduce=True): To demonstrate the behaviour of the parameter ``reduce``:: - sage: K.<a> = NumberField(x^3+x+1) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 + x + 1) sage: E = EllipticCurve(K, [0, 0, a, 0, 1]) sage: E.local_data(K.ideal(a-1)).minimal_model() - Elliptic Curve defined by y^2 + a*y = x^3 + 1 over Number Field in a with defining polynomial x^3 + x + 1 + Elliptic Curve defined by y^2 + a*y = x^3 + 1 + over Number Field in a with defining polynomial x^3 + x + 1 sage: E.local_data(K.ideal(a-1)).minimal_model(reduce=False) - Elliptic Curve defined by y^2 + (a+2)*y = x^3 + 3*x^2 + 3*x + (-a+1) over Number Field in a with defining polynomial x^3 + x + 1 + Elliptic Curve defined by y^2 + (a+2)*y = x^3 + 3*x^2 + 3*x + (-a+1) + over Number Field in a with defining polynomial x^3 + x + 1 sage: E = EllipticCurve([2, 1, 0, -2, -1]) sage: E.local_data(ZZ.ideal(2), algorithm="generic").minimal_model(reduce=False) @@ -343,12 +361,18 @@ def minimal_model(self, reduce=True): :trac:`14476`:: + sage: # needs sage.rings.number_field sage: t = QQ['t'].0 sage: K.<g> = NumberField(t^4 - t^3-3*t^2 - t +1) - sage: E = EllipticCurve([-2*g^3 + 10/3*g^2 + 3*g - 2/3, -11/9*g^3 + 34/9*g^2 - 7/3*g + 4/9, -11/9*g^3 + 34/9*g^2 - 7/3*g + 4/9, 0, 0]) + sage: E = EllipticCurve([-2*g^3 + 10/3*g^2 + 3*g - 2/3, + ....: -11/9*g^3 + 34/9*g^2 - 7/3*g + 4/9, + ....: -11/9*g^3 + 34/9*g^2 - 7/3*g + 4/9, 0, 0]) sage: vv = K.fractional_ideal(g^2 - g - 2) sage: E.local_data(vv).minimal_model() - Elliptic Curve defined by y^2 + (-2*g^3+10/3*g^2+3*g-2/3)*x*y + (-11/9*g^3+34/9*g^2-7/3*g+4/9)*y = x^3 + (-11/9*g^3+34/9*g^2-7/3*g+4/9)*x^2 over Number Field in g with defining polynomial t^4 - t^3 - 3*t^2 - t + 1 + Elliptic Curve defined by + y^2 + (-2*g^3+10/3*g^2+3*g-2/3)*x*y + (-11/9*g^3+34/9*g^2-7/3*g+4/9)*y + = x^3 + (-11/9*g^3+34/9*g^2-7/3*g+4/9)*x^2 + over Number Field in g with defining polynomial t^4 - t^3 - 3*t^2 - t + 1 """ if reduce: try: @@ -455,7 +479,7 @@ def tamagawa_exponent(self): sage: from sage.schemes.elliptic_curves.ell_local_data import EllipticCurveLocalData sage: E = EllipticCurve('816a1') - sage: data = EllipticCurveLocalData(E,2) + sage: data = EllipticCurveLocalData(E, 2) sage: data.kodaira_symbol() I2* sage: data.tamagawa_number() @@ -464,7 +488,7 @@ def tamagawa_exponent(self): 2 sage: E = EllipticCurve('200c4') - sage: data = EllipticCurveLocalData(E,5) + sage: data = EllipticCurveLocalData(E, 5) sage: data.kodaira_symbol() I4* sage: data.tamagawa_number() @@ -499,9 +523,11 @@ def bad_reduction_type(self): sage: [(p,E.local_data(p).bad_reduction_type()) for p in prime_range(15)] [(2, -1), (3, None), (5, None), (7, 1), (11, None), (13, None)] - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] - sage: E = EllipticCurve([0,0,0,0,2*a+1]) + sage: E = EllipticCurve([0, 0, 0, 0, 2*a+1]) sage: [(p,E.local_data(p).bad_reduction_type()) for p in [P17a,P17b]] [(Fractional ideal (4*a^2 - 2*a + 1), None), (Fractional ideal (2*a + 1), 0)] """ @@ -517,12 +543,14 @@ def has_good_reduction(self): sage: [(p,E.local_data(p).has_good_reduction()) for p in prime_range(15)] [(2, False), (3, True), (5, True), (7, False), (11, True), (13, True)] - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] - sage: E = EllipticCurve([0,0,0,0,2*a+1]) + sage: E = EllipticCurve([0, 0, 0, 0, 2*a+1]) sage: [(p,E.local_data(p).has_good_reduction()) for p in [P17a,P17b]] [(Fractional ideal (4*a^2 - 2*a + 1), True), - (Fractional ideal (2*a + 1), False)] + (Fractional ideal (2*a + 1), False)] """ return self._reduction_type is None @@ -538,12 +566,14 @@ def has_bad_reduction(self): :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] - sage: E = EllipticCurve([0,0,0,0,2*a+1]) + sage: E = EllipticCurve([0, 0, 0, 0, 2*a+1]) sage: [(p,E.local_data(p).has_bad_reduction()) for p in [P17a,P17b]] [(Fractional ideal (4*a^2 - 2*a + 1), False), - (Fractional ideal (2*a + 1), True)] + (Fractional ideal (2*a + 1), True)] """ return self._reduction_type is not None @@ -559,14 +589,16 @@ def has_multiplicative_reduction(self): EXAMPLES:: sage: E = EllipticCurve('14a1') - sage: [(p,E.local_data(p).has_multiplicative_reduction()) for p in prime_range(15)] + sage: [(p, E.local_data(p).has_multiplicative_reduction()) for p in prime_range(15)] [(2, True), (3, False), (5, False), (7, True), (11, False), (13, False)] :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] - sage: E = EllipticCurve([0,0,0,0,2*a+1]) + sage: E = EllipticCurve([0, 0, 0, 0, 2*a+1]) sage: [(p,E.local_data(p).has_multiplicative_reduction()) for p in [P17a,P17b]] [(Fractional ideal (4*a^2 - 2*a + 1), False), (Fractional ideal (2*a + 1), False)] """ @@ -579,17 +611,21 @@ def has_split_multiplicative_reduction(self): EXAMPLES:: sage: E = EllipticCurve('14a1') - sage: [(p,E.local_data(p).has_split_multiplicative_reduction()) for p in prime_range(15)] + sage: [(p, E.local_data(p).has_split_multiplicative_reduction()) + ....: for p in prime_range(15)] [(2, False), (3, False), (5, False), (7, True), (11, False), (13, False)] :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] - sage: E = EllipticCurve([0,0,0,0,2*a+1]) - sage: [(p,E.local_data(p).has_split_multiplicative_reduction()) for p in [P17a,P17b]] + sage: E = EllipticCurve([0, 0, 0, 0, 2*a+1]) + sage: [(p,E .local_data(p).has_split_multiplicative_reduction()) + ....: for p in [P17a,P17b]] [(Fractional ideal (4*a^2 - 2*a + 1), False), - (Fractional ideal (2*a + 1), False)] + (Fractional ideal (2*a + 1), False)] """ return self._reduction_type == +1 @@ -600,15 +636,19 @@ def has_nonsplit_multiplicative_reduction(self): EXAMPLES:: sage: E = EllipticCurve('14a1') - sage: [(p,E.local_data(p).has_nonsplit_multiplicative_reduction()) for p in prime_range(15)] + sage: [(p, E.local_data(p).has_nonsplit_multiplicative_reduction()) + ....: for p in prime_range(15)] [(2, True), (3, False), (5, False), (7, False), (11, False), (13, False)] :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] - sage: E = EllipticCurve([0,0,0,0,2*a+1]) - sage: [(p,E.local_data(p).has_nonsplit_multiplicative_reduction()) for p in [P17a,P17b]] + sage: E = EllipticCurve([0, 0, 0, 0, 2*a+1]) + sage: [(p, E.local_data(p).has_nonsplit_multiplicative_reduction()) + ....: for p in [P17a,P17b]] [(Fractional ideal (4*a^2 - 2*a + 1), False), (Fractional ideal (2*a + 1), False)] """ return self._reduction_type == -1 @@ -620,17 +660,19 @@ def has_additive_reduction(self): EXAMPLES:: sage: E = EllipticCurve('27a1') - sage: [(p,E.local_data(p).has_additive_reduction()) for p in prime_range(15)] + sage: [(p, E.local_data(p).has_additive_reduction()) for p in prime_range(15)] [(2, False), (3, True), (5, False), (7, False), (11, False), (13, False)] :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] - sage: E = EllipticCurve([0,0,0,0,2*a+1]) - sage: [(p,E.local_data(p).has_additive_reduction()) for p in [P17a,P17b]] + sage: E = EllipticCurve([0, 0, 0, 0, 2*a+1]) + sage: [(p, E.local_data(p).has_additive_reduction()) for p in [P17a,P17b]] [(Fractional ideal (4*a^2 - 2*a + 1), False), - (Fractional ideal (2*a + 1), True)] + (Fractional ideal (2*a + 1), True)] """ return self._reduction_type == 0 @@ -666,16 +708,14 @@ def _tate(self, proof=None, globally=False): EXAMPLES (this raised a type error in sage prior to 4.4.4, see :trac:`7930`) :: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('99d1') - sage: R.<X> = QQ[] sage: K.<t> = NumberField(X^3 + X^2 - 2*X - 1) sage: L.<s> = NumberField(X^3 + X^2 - 36*X - 4) - sage: EK = E.base_extend(K) sage: toK = EK.torsion_order() sage: da = EK.local_data() # indirect doctest - sage: EL = E.base_extend(L) sage: da = EL.local_data() # indirect doctest @@ -683,21 +723,25 @@ def _tate(self, proof=None, globally=False): The following example shows that the bug at :trac:`9324` is fixed:: - sage: K.<a> = NumberField(x^2-x+6) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - x + 6) sage: E = EllipticCurve([0,0,0,-53160*a-43995,-5067640*a+19402006]) sage: E.conductor() # indirect doctest Fractional ideal (18, 6*a) The following example shows that the bug at :trac:`9417` is fixed:: - sage: K.<a> = NumberField(x^2+18*x+1) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^2 + 18*x + 1) sage: E = EllipticCurve(K, [0, -36, 0, 320, 0]) sage: E.tamagawa_number(K.ideal(2)) 4 This is to show that the bug :trac:`11630` is fixed. (The computation of the class group would produce a warning):: - sage: K.<t> = NumberField(x^7-2*x+177) + sage: # needs sage.rings.number_field + sage: K.<t> = NumberField(x^7 - 2*x + 177) sage: E = EllipticCurve([0,1,0,t,t]) sage: P = K.ideal(2,t^3 + t + 1) sage: E.local_data(P).kodaira_symbol() @@ -1111,8 +1155,11 @@ def check_prime(K, P): 3 sage: check_prime(QQ,ZZ.ideal(31)) 31 - sage: K.<a> = NumberField(x^2-5) - sage: check_prime(K,a) + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 5) + sage: check_prime(K, a) Fractional ideal (a) sage: check_prime(K,a+1) Fractional ideal (a + 1) @@ -1122,11 +1169,14 @@ def check_prime(K, P): sage: check_prime(K, L.ideal(5)) Traceback (most recent call last): ... - TypeError: The ideal Fractional ideal (5) is not a prime ideal of Number Field in a with defining polynomial x^2 - 5 + TypeError: The ideal Fractional ideal (5) is not a prime ideal of + Number Field in a with defining polynomial x^2 - 5 sage: check_prime(K, L.ideal(b)) Traceback (most recent call last): ... - TypeError: No compatible natural embeddings found for Number Field in a with defining polynomial x^2 - 5 and Number Field in b with defining polynomial x^2 + 3 + TypeError: No compatible natural embeddings found for + Number Field in a with defining polynomial x^2 - 5 and + Number Field in b with defining polynomial x^2 + 3 """ if K is QQ: if P in ZZ or isinstance(P, (Integer, int)): @@ -1145,7 +1195,7 @@ def check_prime(K, P): else: raise TypeError("%s is neither an element of QQ or an ideal of %s" % (P, ZZ)) - if not is_NumberField(K): + if not isinstance(K, NumberField): raise TypeError("%s is not a number field" % (K,)) if is_NumberFieldFractionalIdeal(P) or P in K: diff --git a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py index c91a54fdc27..243df1d23f0 100644 --- a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py +++ b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py @@ -48,9 +48,11 @@ sage: V = E.modular_symbol_space() sage: V - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 2 for Gamma_0(19) of weight 2 with sign 1 over Rational Field + Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 2 + for Gamma_0(19) of weight 2 with sign 1 over Rational Field sage: V.q_eigenform(30) - q - 2*q^3 - 2*q^4 + 3*q^5 - q^7 + q^9 + 3*q^11 + 4*q^12 - 4*q^13 - 6*q^15 + 4*q^16 - 3*q^17 + q^19 - 6*q^20 + 2*q^21 + 4*q^25 + 4*q^27 + 2*q^28 + 6*q^29 + O(q^30) + q - 2*q^3 - 2*q^4 + 3*q^5 - q^7 + q^9 + 3*q^11 + 4*q^12 - 4*q^13 - 6*q^15 + 4*q^16 + - 3*q^17 + q^19 - 6*q^20 + 2*q^21 + 4*q^25 + 4*q^27 + 2*q^28 + 6*q^29 + O(q^30) For more details on modular symbols consult the following @@ -87,19 +89,22 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.sage_object import SageObject -from sage.modular.modsym.all import ModularSymbols +from sage.arith.misc import (kronecker as kronecker_symbol, + next_prime, + prime_divisors, + valuation) from sage.databases.cremona import parse_cremona_label - -from sage.arith.all import next_prime, kronecker_symbol, prime_divisors, valuation +from sage.misc.verbose import verbose +from sage.modular.cusps import Cusps +from sage.modular.modsym.all import ModularSymbols from sage.rings.infinity import unsigned_infinity as infinity from sage.rings.integer import Integer -from sage.modular.cusps import Cusps from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.misc.verbose import verbose +from sage.structure.sage_object import SageObject + +from .constructor import EllipticCurve -from sage.schemes.elliptic_curves.constructor import EllipticCurve oo = Cusps(infinity) zero = Integer(0) @@ -122,11 +127,12 @@ def modular_symbol_space(E, sign, base_ring, bound=None): EXAMPLES:: - sage: import sage.schemes.elliptic_curves.ell_modular_symbols + sage: from sage.schemes.elliptic_curves.ell_modular_symbols import modular_symbol_space sage: E = EllipticCurve('11a1') - sage: M = sage.schemes.elliptic_curves.ell_modular_symbols.modular_symbol_space(E,-1,GF(37)) + sage: M = modular_symbol_space(E, -1, GF(37)) sage: M - Modular Symbols space of dimension 1 for Gamma_0(11) of weight 2 with sign -1 over Finite Field of size 37 + Modular Symbols space of dimension 1 for Gamma_0(11) of weight 2 with sign -1 + over Finite Field of size 37 """ if sign not in [-1, 0, 1]: raise TypeError('sign must -1, 0 or 1') @@ -206,12 +212,14 @@ def _repr_(self): sage: m = EllipticCurve('11a1').modular_symbol() sage: m - Modular symbol with sign 1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Modular symbol with sign 1 over Rational Field attached to + Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: m = EllipticCurve('43a1').modular_symbol(sign=-1, implementation="sage") sage: m - Modular symbol with sign -1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 + x^2 over Rational Field + Modular symbol with sign -1 over Rational Field attached to + Elliptic Curve defined by y^2 + y = x^3 + x^2 over Rational Field """ - return "Modular symbol with sign %s over %s attached to %s"%( + return "Modular symbol with sign %s over %s attached to %s" % ( self._sign, self._base_ring, self._E) class ModularSymbolECLIB(ModularSymbol): @@ -237,22 +245,23 @@ def __init__(self, E, sign, nap=1000): EXAMPLES:: - sage: import sage.schemes.elliptic_curves.ell_modular_symbols + sage: from sage.schemes.elliptic_curves.ell_modular_symbols import ModularSymbolECLIB sage: E = EllipticCurve('11a1') - sage: M = sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolECLIB(E,+1) + sage: M = ModularSymbolECLIB(E,+1) sage: M - Modular symbol with sign 1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Modular symbol with sign 1 over Rational Field attached to + Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: M(0) 1/5 sage: E = EllipticCurve('11a2') - sage: M = sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolECLIB(E,+1) + sage: M = ModularSymbolECLIB(E,+1) sage: M(0) 1 This is a rank 1 case with vanishing positive twists:: sage: E = EllipticCurve('121b1') - sage: M = sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolECLIB(E,+1) + sage: M = ModularSymbolECLIB(E,+1) sage: M(0) 0 sage: M(1/7) @@ -270,11 +279,13 @@ def __init__(self, E, sign, nap=1000): sage: E = EllipticCurve('11a1') sage: Mplus = E.modular_symbol(+1); Mplus - Modular symbol with sign 1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Modular symbol with sign 1 over Rational Field attached to + Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: [Mplus(1/i) for i in [1..11]] [1/5, -4/5, -3/10, 7/10, 6/5, 6/5, 7/10, -3/10, -4/5, 1/5, 0] sage: Mminus = E.modular_symbol(-1); Mminus - Modular symbol with sign -1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Modular symbol with sign -1 over Rational Field attached to + Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: [Mminus(1/i) for i in [1..11]] [0, 0, 1/2, 1/2, 0, 0, -1/2, -1/2, 0, 0, 0] @@ -322,11 +333,11 @@ def __init__(self, E, sign, nap=1000): raise TypeError('sign must -1 or 1') self._sign = ZZ(sign) self._E = E - self._scaling = 1 if E.discriminant()>0 else ZZ(1)/2 + self._scaling = 1 if E.discriminant() > 0 else ZZ(1)/2 self._implementation = "eclib" self._base_ring = QQ # The ECModularSymbol class must be initialized with sign=0 to compute minus symbols - self._modsym = ECModularSymbol(E, int(sign==1), nap) + self._modsym = ECModularSymbol(E, int(sign == 1), nap) self.cache = {True: {}, False: {}} def _call_with_caching(self, r, base_at_infinity=True): @@ -390,17 +401,18 @@ def __init__(self, E, sign, normalize="L_ratio"): EXAMPLES:: sage: E = EllipticCurve('11a1') - sage: import sage.schemes.elliptic_curves.ell_modular_symbols - sage: M = sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolSage(E,+1) + sage: from sage.schemes.elliptic_curves.ell_modular_symbols import ModularSymbolSage + sage: M = ModularSymbolSage(E, +1) sage: M - Modular symbol with sign 1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Modular symbol with sign 1 over Rational Field attached to + Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: M(0) 1/5 sage: E = EllipticCurve('11a2') - sage: M = sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolSage(E,+1) + sage: M = ModularSymbolSage(E, +1) sage: M(0) 1 - sage: M = sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolSage(E,-1) + sage: M = ModularSymbolSage(E, -1) sage: M(1/3) 1/2 @@ -408,7 +420,7 @@ def __init__(self, E, sign, normalize="L_ratio"): The modular symbol is adjusted by -2:: sage: E = EllipticCurve('121b1') - sage: M = sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolSage(E,-1,normalize='L_ratio') + sage: M = ModularSymbolSage(E, -1, normalize='L_ratio') sage: M(1/3) 1 sage: M._scaling @@ -417,16 +429,20 @@ def __init__(self, E, sign, normalize="L_ratio"): sage: M = EllipticCurve('121d1').modular_symbol(implementation="sage") sage: M(0) 2 - sage: M = EllipticCurve('121d1').modular_symbol(implementation="sage", normalize='none') + sage: M = EllipticCurve('121d1').modular_symbol(implementation="sage", + ....: normalize='none') sage: M(0) 1 sage: E = EllipticCurve('15a1') - sage: [C.modular_symbol(implementation="sage", normalize='L_ratio')(0) for C in E.isogeny_class()] + sage: [C.modular_symbol(implementation="sage", normalize='L_ratio')(0) + ....: for C in E.isogeny_class()] [1/4, 1/8, 1/4, 1/2, 1/8, 1/16, 1/2, 1] - sage: [C.modular_symbol(implementation="sage", normalize='period')(0) for C in E.isogeny_class()] + sage: [C.modular_symbol(implementation="sage", normalize='period')(0) + ....: for C in E.isogeny_class()] [1/8, 1/16, 1/8, 1/4, 1/16, 1/32, 1/4, 1/2] - sage: [C.modular_symbol(implementation="sage", normalize='none')(0) for C in E.isogeny_class()] + sage: [C.modular_symbol(implementation="sage", normalize='none')(0) + ....: for C in E.isogeny_class()] [1, 1, 1, 1, 1, 1, 1, 1] """ if sign not in [-1, 1]: @@ -445,14 +461,14 @@ def __init__(self, E, sign, normalize="L_ratio"): if self._failed_to_scale: self._find_scaling_period() # will reset _e and _scaling else: - self._e *= self._scaling + self._e *= self._scaling elif normalize == "period" : self._find_scaling_period() # this will set _e and _scaling elif normalize == "none": self._scaling = 1 self._e = self._modsym.dual_eigenvector() else : - raise ValueError("no normalization %s known for modular symbols"%normalize) + raise ValueError("no normalization %s known for modular symbols" % normalize) def _find_scaling_L_ratio(self): r""" @@ -537,7 +553,7 @@ def _find_scaling_L_ratio(self): if at0 != 0 : l1 = self.__lalg__(1) if at0 != l1: - verbose('scale modular symbols by %s'%(l1/at0)) + verbose('scale modular symbols by %s' % (l1/at0)) self._scaling = l1/at0 else : # if [0] = 0, we can still hope to scale it correctly by considering twists of E @@ -549,7 +565,7 @@ def _find_scaling_L_ratio(self): D = Dlist[j] # the following line checks if the twist of the newform of E by D is a newform # this is to avoid that we 'twist back' - if all( valuation(E.conductor(),ell)<= valuation(D,ell) for ell in prime_divisors(D) ) : + if all( valuation(E.conductor(),ell) <= valuation(D,ell) for ell in prime_divisors(D) ) : at0 = sum([kronecker_symbol(D,u) * self(ZZ(u)/D) for u in range(1,abs(D))]) j += 1 if j == 30 and at0 == 0: # curves like "121b1", "225a1", "225e1", "256a1", "256b1", "289a1", "361a1", "400a1", "400c1", "400h1", "441b1", "441c1", "441d1", "441f1 .. will arrive here @@ -558,7 +574,7 @@ def _find_scaling_L_ratio(self): else : l1 = self.__lalg__(D) if at0 != l1: - verbose('scale modular symbols by %s found at D=%s '%(l1/at0,D), level=2) + verbose('scale modular symbols by %s found at D=%s ' % (l1/at0,D), level=2) self._scaling = l1/at0 else : # that is when sign = -1 @@ -568,7 +584,7 @@ def _find_scaling_L_ratio(self): while j < 30 and at0 == 0 : # computes [0]+ for the twist of E by D until one value is non-zero D = Dlist[j] - if all( valuation(E.conductor(),ell)<= valuation(D,ell) for ell in prime_divisors(D) ) : + if all( valuation(E.conductor(),ell) <= valuation(D,ell) for ell in prime_divisors(D) ) : at0 = - sum([kronecker_symbol(D,u) * self(ZZ(u)/D) for u in range(1,abs(D))]) j += 1 if j == 30 and at0 == 0: # no more hope for a normalization @@ -577,7 +593,7 @@ def _find_scaling_L_ratio(self): else : l1 = self.__lalg__(D) if at0 != l1: - verbose('scale modular symbols by %s'%(l1/at0)) + verbose('scale modular symbols by %s' % (l1/at0)) self._scaling = l1/at0 def __lalg__(self, D): diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 3b31f9cf43f..54777488572 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.rings.number_field r""" Elliptic curves over number fields @@ -19,8 +19,8 @@ EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) - sage: E = EllipticCurve([0,4+i]) + sage: K.<i> = NumberField(x^2 + 1) + sage: E = EllipticCurve([0, 4+i]) sage: E.discriminant() -3456*i - 6480 sage: P= E([i,2]) @@ -29,16 +29,17 @@ :: - sage: E.has_good_reduction(2+i) + sage: E.has_good_reduction(2 + i) True sage: E.local_data(4+i) Local data at Fractional ideal (i + 4): - Reduction type: bad additive - Local minimal model: Elliptic Curve defined by y^2 = x^3 + (i+4) over Number Field in i with defining polynomial x^2 + 1 - Minimal discriminant valuation: 2 - Conductor exponent: 2 - Kodaira Symbol: II - Tamagawa Number: 1 + Reduction type: bad additive + Local minimal model: Elliptic Curve defined by y^2 = x^3 + (i+4) + over Number Field in i with defining polynomial x^2 + 1 + Minimal discriminant valuation: 2 + Conductor exponent: 2 + Kodaira Symbol: II + Tamagawa Number: 1 sage: E.tamagawa_product_bsd() 1 @@ -55,7 +56,11 @@ :: sage: E.isogenies_prime_degree(3) - [Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + (i+4) over Number Field in i with defining polynomial x^2 + 1 to Elliptic Curve defined by y^2 = x^3 + (-27*i-108) over Number Field in i with defining polynomial x^2 + 1] + [Isogeny of degree 3 + from Elliptic Curve defined by y^2 = x^3 + (i+4) + over Number Field in i with defining polynomial x^2 + 1 + to Elliptic Curve defined by y^2 = x^3 + (-27*i-108) + over Number Field in i with defining polynomial x^2 + 1] AUTHORS: @@ -104,24 +109,28 @@ class EllipticCurve_number_field(EllipticCurve_field): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) + sage: K.<i> = NumberField(x^2 + 1) sage: EllipticCurve([i, i - 1, i + 1, 24*i + 15, 14*i + 35]) - Elliptic Curve defined by y^2 + i*x*y + (i+1)*y = x^3 + (i-1)*x^2 + (24*i+15)*x + (14*i+35) over Number Field in i with defining polynomial x^2 + 1 + Elliptic Curve defined by + y^2 + i*x*y + (i+1)*y = x^3 + (i-1)*x^2 + (24*i+15)*x + (14*i+35) + over Number Field in i with defining polynomial x^2 + 1 """ def __init__(self, K, ainvs): r""" EXAMPLES: - A curve from the database of curves over `\QQ`, but over a larger field: + A curve from the database of curves over `\QQ`, but over a larger field:: - sage: K.<i> = NumberField(x^2+1) + sage: K.<i> = NumberField(x^2 + 1) sage: EllipticCurve(K,'389a1') - Elliptic Curve defined by y^2 + y = x^3 + x^2 + (-2)*x over Number Field in i with defining polynomial x^2 + 1 + Elliptic Curve defined by y^2 + y = x^3 + x^2 + (-2)*x + over Number Field in i with defining polynomial x^2 + 1 Making the field of definition explicitly larger:: sage: EllipticCurve(K,[0,-1,1,0,0]) - Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 over Number Field in i with defining polynomial x^2 + 1 + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + over Number Field in i with defining polynomial x^2 + 1 """ self._known_points = [] EllipticCurve_field.__init__(self, K, ainvs) @@ -137,7 +146,8 @@ def base_extend(self, R): sage: E = EllipticCurve('11a3') sage: K = QuadraticField(-5, 'a') sage: E.base_extend(K) - Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 over Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 over Number Field in a + with defining polynomial x^2 + 5 with a = 2.236067977499790?*I Check that non-torsion points are remembered when extending the base field (see :trac:`16034`):: @@ -213,6 +223,7 @@ def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23, 'a') sage: E = EllipticCurve(K, '37') sage: E == loads(dumps(E)) @@ -226,7 +237,8 @@ def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, sage: K.<a> = NumberField(x^2 + 7, 'a') sage: E = EllipticCurve(K, [0,0,0,1,a]); E - Elliptic Curve defined by y^2 = x^3 + x + a over Number Field in a with defining polynomial x^2 + 7 + Elliptic Curve defined by y^2 = x^3 + x + a + over Number Field in a with defining polynomial x^2 + 7 sage: v = E.simon_two_descent(verbose=1); v elliptic curve: Y^2 = x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7) @@ -265,7 +277,7 @@ def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, sage: R.<t> = QQ[] sage: L.<g> = NumberField(t^3 - 9*t^2 + 13*t - 4) - sage: E1 = EllipticCurve(L,[1-g*(g-1),-g^2*(g-1),-g^2*(g-1),0,0]) + sage: E1 = EllipticCurve(L, [1-g*(g-1), -g^2*(g-1), -g^2*(g-1), 0, 0]) sage: E1.rank() # long time (about 5 s) 0 @@ -341,7 +353,7 @@ def height_pairing_matrix(self, points=None, precision=None, normalised=True): sage: E = EllipticCurve('389a1') sage: E = EllipticCurve('389a1') - sage: P,Q = E.point([-1,1,1]),E.point([0,-1,1]) + sage: P, Q = E.point([-1,1,1]), E.point([0,-1,1]) sage: E.height_pairing_matrix([P,Q]) [0.686667083305587 0.268478098806726] [0.268478098806726 0.327000773651605] @@ -349,7 +361,7 @@ def height_pairing_matrix(self, points=None, precision=None, normalised=True): Over a number field:: sage: x = polygen(QQ) - sage: K.<t> = NumberField(x^2+47) + sage: K.<t> = NumberField(x^2 + 47) sage: EK = E.base_extend(K) sage: EK.height_pairing_matrix([EK(P),EK(Q)]) [0.686667083305587 0.268478098806726] @@ -359,7 +371,7 @@ def height_pairing_matrix(self, points=None, precision=None, normalised=True): sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve([0,0,0,i,i]) - sage: P = E(-9+4*i,-18-25*i) + sage: P = E(-9+4*i, -18-25*i) sage: Q = E(i,-i) sage: E.height_pairing_matrix([P,Q]) [ 2.16941934493768 -0.870059380421505] @@ -388,7 +400,7 @@ def height_pairing_matrix(self, points=None, precision=None, normalised=True): RR = RealField() else: RR = RealField(precision) - from sage.matrix.all import MatrixSpace + from sage.matrix.matrix_space import MatrixSpace M = MatrixSpace(RR, r) mat = M() for j in range(r): @@ -430,7 +442,7 @@ def regulator_of_points(self, points=[], precision=None, normalised=True): sage: points = [E.lift_x(x) for x in [-2,-7/4,1]] sage: E.regulator_of_points(points) 0.417143558758384 - sage: E.regulator_of_points(points,precision=100) + sage: E.regulator_of_points(points, precision=100) 0.41714355875838396981711954462 :: @@ -438,7 +450,7 @@ def regulator_of_points(self, points=[], precision=None, normalised=True): sage: E = EllipticCurve('389a') sage: E.regulator_of_points() 1.00000000000000 - sage: points = [P,Q] = [E(-1,1),E(0,-1)] + sage: points = [P,Q] = [E(-1,1), E(0,-1)] sage: E.regulator_of_points(points) 0.152460177943144 sage: E.regulator_of_points(points, precision=100) @@ -451,7 +463,7 @@ def regulator_of_points(self, points=[], precision=None, normalised=True): Examples over number fields:: sage: K.<a> = QuadraticField(97) - sage: E = EllipticCurve(K,[1,1]) + sage: E = EllipticCurve(K, [1,1]) sage: P = E(0,1) sage: P.height() 0.476223106404866 @@ -471,9 +483,9 @@ def regulator_of_points(self, points=[], precision=None, normalised=True): sage: E = EllipticCurve('11a1') sage: x = polygen(QQ) - sage: K.<t> = NumberField(x^2+47) + sage: K.<t> = NumberField(x^2 + 47) sage: EK = E.base_extend(K) - sage: T = EK(5,5) + sage: T = EK(5, 5) sage: T.order() 5 sage: P = EK(-2, -1/2*t - 1/2) @@ -490,7 +502,7 @@ def regulator_of_points(self, points=[], precision=None, normalised=True): sage: P,Q = E.gens() sage: E.regulator_of_points([P,Q]) 0.152460177943144 - sage: K.<t> = NumberField(x^2+47) + sage: K.<t> = NumberField(x^2 + 47) sage: EK = E.base_extend(K) sage: EK.regulator_of_points([EK(P),EK(Q)]) 0.152460177943144 @@ -499,8 +511,8 @@ def regulator_of_points(self, points=[], precision=None, normalised=True): sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve([0,0,0,i,i]) - sage: P = E(-9+4*i,-18-25*i) - sage: Q = E(i,-i) + sage: P = E(-9+4*i, -18-25*i) + sage: Q = E(i, -i) sage: E.height_pairing_matrix([P,Q]) [ 2.16941934493768 -0.870059380421505] [-0.870059380421505 0.424585837470709] @@ -523,13 +535,13 @@ def is_local_integral_model(self, *P): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) - sage: P1,P2 = K.primes_above(5) + sage: K.<i> = NumberField(x^2 + 1) + sage: P1, P2 = K.primes_above(5) sage: E = EllipticCurve([i/5,i/5,i/5,i/5,i/5]) - sage: E.is_local_integral_model(P1,P2) + sage: E.is_local_integral_model(P1, P2) False - sage: Emin = E.local_integral_model(P1,P2) - sage: Emin.is_local_integral_model(P1,P2) + sage: Emin = E.local_integral_model(P1, P2) + sage: Emin.is_local_integral_model(P1, P2) True """ if len(P) == 1: @@ -540,8 +552,7 @@ def is_local_integral_model(self, *P): def local_integral_model(self,*P): r""" - Return a model of self which is integral at the prime ideal - `P`. + Return a model of self which is integral at the prime ideal `P`. .. NOTE:: @@ -554,11 +565,13 @@ def local_integral_model(self,*P): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) - sage: P1,P2 = K.primes_above(5) + sage: K.<i> = NumberField(x^2 + 1) + sage: P1, P2 = K.primes_above(5) sage: E = EllipticCurve([i/5,i/5,i/5,i/5,i/5]) sage: E.local_integral_model((P1,P2)) - Elliptic Curve defined by y^2 + (-i)*x*y + (-25*i)*y = x^3 + 5*i*x^2 + 125*i*x + 3125*i over Number Field in i with defining polynomial x^2 + 1 + Elliptic Curve defined by + y^2 + (-i)*x*y + (-25*i)*y = x^3 + 5*i*x^2 + 125*i*x + 3125*i + over Number Field in i with defining polynomial x^2 + 1 """ if len(P) == 1: P = P[0] @@ -579,9 +592,9 @@ def is_global_integral_model(self): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) + sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve([i/5,i/5,i/5,i/5,i/5]) - sage: P1,P2 = K.primes_above(5) + sage: P1, P2 = K.primes_above(5) sage: Emin = E.global_integral_model() sage: Emin.is_global_integral_model() True @@ -594,33 +607,39 @@ def global_integral_model(self): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) + sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve([i/5,i/5,i/5,i/5,i/5]) - sage: P1,P2 = K.primes_above(5) + sage: P1, P2 = K.primes_above(5) sage: E.global_integral_model() - Elliptic Curve defined by y^2 + (-i)*x*y + (-25*i)*y = x^3 + 5*i*x^2 + 125*i*x + 3125*i over Number Field in i with defining polynomial x^2 + 1 + Elliptic Curve defined by + y^2 + (-i)*x*y + (-25*i)*y = x^3 + 5*i*x^2 + 125*i*x + 3125*i + over Number Field in i with defining polynomial x^2 + 1 :trac:`7935`:: - sage: K.<a> = NumberField(x^2-38) + sage: K.<a> = NumberField(x^2 - 38) sage: E = EllipticCurve([a,1/2]) sage: E.global_integral_model() - Elliptic Curve defined by y^2 = x^3 + 1444*a*x + 27436 over Number Field in a with defining polynomial x^2 - 38 + Elliptic Curve defined by y^2 = x^3 + 1444*a*x + 27436 + over Number Field in a with defining polynomial x^2 - 38 :trac:`9266`:: - sage: K.<s> = NumberField(x^2-5) + sage: K.<s> = NumberField(x^2 - 5) sage: w = (1+s)/2 - sage: E = EllipticCurve(K,[2,w]) + sage: E = EllipticCurve(K, [2,w]) sage: E.global_integral_model() - Elliptic Curve defined by y^2 = x^3 + 2*x + (1/2*s+1/2) over Number Field in s with defining polynomial x^2 - 5 + Elliptic Curve defined by y^2 = x^3 + 2*x + (1/2*s+1/2) + over Number Field in s with defining polynomial x^2 - 5 :trac:`12151`:: sage: K.<v> = NumberField(x^2 + 161*x - 150) sage: E = EllipticCurve([25105/216*v - 3839/36, 634768555/7776*v - 98002625/1296, 634768555/7776*v - 98002625/1296, 0, 0]) sage: M = E.global_integral_model(); M # choice varies, not tested - Elliptic Curve defined by y^2 + (2094779518028859*v-1940492905300351)*x*y + (477997268472544193101178234454165304071127500*v-442791377441346852919930773849502871958097500)*y = x^3 + (26519784690047674853185542622500*v-24566525306469707225840460652500)*x^2 over Number Field in v with defining polynomial x^2 + 161*x - 150 + Elliptic Curve defined by + y^2 + (2094779518028859*v-1940492905300351)*x*y + (477997268472544193101178234454165304071127500*v-442791377441346852919930773849502871958097500)*y = x^3 + (26519784690047674853185542622500*v-24566525306469707225840460652500)*x^2 + over Number Field in v with defining polynomial x^2 + 161*x - 150 :trac:`14476`:: @@ -628,7 +647,9 @@ def global_integral_model(self): sage: K.<g> = NumberField(t^4 - t^3 - 3*t^2 - t + 1) sage: E = EllipticCurve([ -43/625*g^3 + 14/625*g^2 - 4/625*g + 706/625, -4862/78125*g^3 - 4074/78125*g^2 - 711/78125*g + 10304/78125, -4862/78125*g^3 - 4074/78125*g^2 - 711/78125*g + 10304/78125, 0,0]) sage: E.global_integral_model() - Elliptic Curve defined by y^2 + (15*g^3-48*g-42)*x*y + (-111510*g^3-162162*g^2-44145*g+37638)*y = x^3 + (-954*g^3-1134*g^2+81*g+576)*x^2 over Number Field in g with defining polynomial t^4 - t^3 - 3*t^2 - t + 1 + Elliptic Curve defined by + y^2 + (15*g^3-48*g-42)*x*y + (-111510*g^3-162162*g^2-44145*g+37638)*y = x^3 + (-954*g^3-1134*g^2+81*g+576)*x^2 + over Number Field in g with defining polynomial t^4 - t^3 - 3*t^2 - t + 1 TESTS: @@ -684,7 +705,8 @@ def _reduce_model(self): EXAMPLES:: - sage: K.<a> = NumberField(x^2-38) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 38) sage: E = EllipticCurve([a, -5*a + 19, -39*a + 237, 368258520200522046806318224*a - 2270097978636731786720858047, 8456608930180227786550494643437985949781*a - 52130038506835491453281450568107193773505]) sage: E.ainvs() (a, @@ -694,10 +716,10 @@ def _reduce_model(self): 8456608930180227786550494643437985949781*a - 52130038506835491453281450568107193773505) sage: E._reduce_model().ainvs() (a, - a + 1, - a + 1, - 368258520200522046806318444*a - 2270097978636731786720859345, - 8456608930173478039472018047583706316424*a - 52130038506793883217874390501829588391299) + a + 1, + a + 1, + 368258520200522046806318444*a - 2270097978636731786720859345, + 8456608930173478039472018047583706316424*a - 52130038506793883217874390501829588391299) sage: EllipticCurve([101,202,303,404,505])._reduce_model().ainvs() (1, 1, 0, -2509254, 1528863051) sage: EllipticCurve([-101,-202,-303,-404,-505])._reduce_model().ainvs() @@ -742,7 +764,8 @@ def _scale_by_units(self): EXAMPLES:: - sage: K.<a> = NumberField(x^2-10) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: u = a + 3 sage: u.is_unit() True @@ -855,51 +878,56 @@ def local_data(self, P=None, proof=None, algorithm="pari", globally=False): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) + sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve([1 + i, 0, 1, 0, 0]) sage: E.local_data() [Local data at Fractional ideal (2*i + 1): - Reduction type: bad non-split multiplicative - Local minimal model: Elliptic Curve defined by y^2 + (i+1)*x*y + y = x^3 over Number Field in i with defining polynomial x^2 + 1 - Minimal discriminant valuation: 1 - Conductor exponent: 1 - Kodaira Symbol: I1 - Tamagawa Number: 1, - Local data at Fractional ideal (-2*i + 3): - Reduction type: bad split multiplicative - Local minimal model: Elliptic Curve defined by y^2 + (i+1)*x*y + y = x^3 over Number Field in i with defining polynomial x^2 + 1 - Minimal discriminant valuation: 2 - Conductor exponent: 1 - Kodaira Symbol: I2 - Tamagawa Number: 2] + Reduction type: bad non-split multiplicative + Local minimal model: Elliptic Curve defined by y^2 + (i+1)*x*y + y = x^3 + over Number Field in i with defining polynomial x^2 + 1 + Minimal discriminant valuation: 1 + Conductor exponent: 1 + Kodaira Symbol: I1 + Tamagawa Number: 1, + Local data at Fractional ideal (-2*i + 3): + Reduction type: bad split multiplicative + Local minimal model: Elliptic Curve defined by y^2 + (i+1)*x*y + y = x^3 + over Number Field in i with defining polynomial x^2 + 1 + Minimal discriminant valuation: 2 + Conductor exponent: 1 + Kodaira Symbol: I2 + Tamagawa Number: 2] sage: E.local_data(K.ideal(3)) Local data at Fractional ideal (3): - Reduction type: good - Local minimal model: Elliptic Curve defined by y^2 + (i+1)*x*y + y = x^3 over Number Field in i with defining polynomial x^2 + 1 - Minimal discriminant valuation: 0 - Conductor exponent: 0 - Kodaira Symbol: I0 - Tamagawa Number: 1 + Reduction type: good + Local minimal model: Elliptic Curve defined by y^2 + (i+1)*x*y + y = x^3 + over Number Field in i with defining polynomial x^2 + 1 + Minimal discriminant valuation: 0 + Conductor exponent: 0 + Kodaira Symbol: I0 + Tamagawa Number: 1 sage: E.local_data(2*i + 1) Local data at Fractional ideal (2*i + 1): - Reduction type: bad non-split multiplicative - Local minimal model: Elliptic Curve defined by y^2 + (i+1)*x*y + y = x^3 over Number Field in i with defining polynomial x^2 + 1 - Minimal discriminant valuation: 1 - Conductor exponent: 1 - Kodaira Symbol: I1 - Tamagawa Number: 1 + Reduction type: bad non-split multiplicative + Local minimal model: Elliptic Curve defined by y^2 + (i+1)*x*y + y = x^3 + over Number Field in i with defining polynomial x^2 + 1 + Minimal discriminant valuation: 1 + Conductor exponent: 1 + Kodaira Symbol: I1 + Tamagawa Number: 1 An example raised in :trac:`3897`:: sage: E = EllipticCurve([1,1]) sage: E.local_data(3) Local data at Principal ideal (3) of Integer Ring: - Reduction type: good - Local minimal model: Elliptic Curve defined by y^2 = x^3 + x + 1 over Rational Field - Minimal discriminant valuation: 0 - Conductor exponent: 0 - Kodaira Symbol: I0 - Tamagawa Number: 1 + Reduction type: good + Local minimal model: Elliptic Curve defined by y^2 = x^3 + x + 1 + over Rational Field + Minimal discriminant valuation: 0 + Conductor exponent: 0 + Kodaira Symbol: I0 + Tamagawa Number: 1 """ if proof is None: import sage.structure.proof.proof @@ -947,17 +975,19 @@ def _get_local_data(self, P, proof, algorithm="pari", globally=False): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) - sage: E = EllipticCurve(K,[0,1,0,-160,308]) - sage: p = K.ideal(i+1) + sage: K.<i> = NumberField(x^2 + 1) + sage: E = EllipticCurve(K, [0,1,0,-160,308]) + sage: p = K.ideal(i + 1) sage: E._get_local_data(p, False) Local data at Fractional ideal (i + 1): - Reduction type: good - Local minimal model: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + (-10)*x + (-10) over Number Field in i with defining polynomial x^2 + 1 - Minimal discriminant valuation: 0 - Conductor exponent: 0 - Kodaira Symbol: I0 - Tamagawa Number: 1 + Reduction type: good + Local minimal model: Elliptic Curve defined by + y^2 + x*y + y = x^3 + x^2 + (-10)*x + (-10) + over Number Field in i with defining polynomial x^2 + 1 + Minimal discriminant valuation: 0 + Conductor exponent: 0 + Kodaira Symbol: I0 + Tamagawa Number: 1 Verify that we cache based on the proof value and the algorithm choice:: @@ -1012,7 +1042,7 @@ def local_minimal_model(self, P, proof=None, algorithm="pari"): EXAMPLES:: - sage: K.<a> = NumberField(x^2-5) + sage: K.<a> = NumberField(x^2 - 5) sage: E = EllipticCurve([20, 225, 750, 1250*a + 6250, 62500*a + 15625]) sage: P = K.ideal(a) sage: E.local_minimal_model(P).ainvs() @@ -1047,15 +1077,15 @@ def has_good_reduction(self, P): EXAMPLES:: sage: E = EllipticCurve('14a1') - sage: [(p,E.has_good_reduction(p)) for p in prime_range(15)] + sage: [(p, E.has_good_reduction(p)) for p in prime_range(15)] [(2, False), (3, True), (5, True), (7, False), (11, True), (13, True)] - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] sage: E = EllipticCurve([0,0,0,0,2*a+1]) - sage: [(p,E.has_good_reduction(p)) for p in [P17a,P17b]] + sage: [(p, E.has_good_reduction(p)) for p in [P17a,P17b]] [(Fractional ideal (4*a^2 - 2*a + 1), True), - (Fractional ideal (2*a + 1), False)] + (Fractional ideal (2*a + 1), False)] """ return self.local_data(P).has_good_reduction() @@ -1081,15 +1111,15 @@ def has_bad_reduction(self, P): EXAMPLES:: sage: E = EllipticCurve('14a1') - sage: [(p,E.has_bad_reduction(p)) for p in prime_range(15)] + sage: [(p, E.has_bad_reduction(p)) for p in prime_range(15)] [(2, True), (3, False), (5, False), (7, True), (11, False), (13, False)] - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] sage: E = EllipticCurve([0,0,0,0,2*a+1]) - sage: [(p,E.has_bad_reduction(p)) for p in [P17a,P17b]] + sage: [(p, E.has_bad_reduction(p)) for p in [P17a,P17b]] [(Fractional ideal (4*a^2 - 2*a + 1), False), - (Fractional ideal (2*a + 1), True)] + (Fractional ideal (2*a + 1), True)] """ return self.local_data(P).has_bad_reduction() @@ -1105,7 +1135,7 @@ def has_multiplicative_reduction(self, P): INPUT: - ``P`` -- a prime ideal of the base field of self, or a field - element generating such an ideal. + element generating such an ideal. OUTPUT: @@ -1115,14 +1145,15 @@ def has_multiplicative_reduction(self, P): EXAMPLES:: sage: E = EllipticCurve('14a1') - sage: [(p,E.has_multiplicative_reduction(p)) for p in prime_range(15)] + sage: [(p, E.has_multiplicative_reduction(p)) for p in prime_range(15)] [(2, True), (3, False), (5, False), (7, True), (11, False), (13, False)] - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] sage: E = EllipticCurve([0,0,0,0,2*a+1]) - sage: [(p,E.has_multiplicative_reduction(p)) for p in [P17a,P17b]] - [(Fractional ideal (4*a^2 - 2*a + 1), False), (Fractional ideal (2*a + 1), False)] + sage: [(p, E.has_multiplicative_reduction(p)) for p in [P17a,P17b]] + [(Fractional ideal (4*a^2 - 2*a + 1), False), + (Fractional ideal (2*a + 1), False)] """ return self.local_data(P).has_multiplicative_reduction() @@ -1143,14 +1174,15 @@ def has_split_multiplicative_reduction(self, P): EXAMPLES:: sage: E = EllipticCurve('14a1') - sage: [(p,E.has_split_multiplicative_reduction(p)) for p in prime_range(15)] + sage: [(p, E.has_split_multiplicative_reduction(p)) for p in prime_range(15)] [(2, False), (3, False), (5, False), (7, True), (11, False), (13, False)] - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] sage: E = EllipticCurve([0,0,0,0,2*a+1]) - sage: [(p,E.has_split_multiplicative_reduction(p)) for p in [P17a,P17b]] - [(Fractional ideal (4*a^2 - 2*a + 1), False), (Fractional ideal (2*a + 1), False)] + sage: [(p, E.has_split_multiplicative_reduction(p)) for p in [P17a,P17b]] + [(Fractional ideal (4*a^2 - 2*a + 1), False), + (Fractional ideal (2*a + 1), False)] """ return self.local_data(P).has_split_multiplicative_reduction() @@ -1171,14 +1203,15 @@ def has_nonsplit_multiplicative_reduction(self, P): EXAMPLES:: sage: E = EllipticCurve('14a1') - sage: [(p,E.has_nonsplit_multiplicative_reduction(p)) for p in prime_range(15)] + sage: [(p, E.has_nonsplit_multiplicative_reduction(p)) for p in prime_range(15)] [(2, True), (3, False), (5, False), (7, False), (11, False), (13, False)] - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] sage: E = EllipticCurve([0,0,0,0,2*a+1]) - sage: [(p,E.has_nonsplit_multiplicative_reduction(p)) for p in [P17a,P17b]] - [(Fractional ideal (4*a^2 - 2*a + 1), False), (Fractional ideal (2*a + 1), False)] + sage: [(p, E.has_nonsplit_multiplicative_reduction(p)) for p in [P17a,P17b]] + [(Fractional ideal (4*a^2 - 2*a + 1), False), + (Fractional ideal (2*a + 1), False)] """ return self.local_data(P).has_nonsplit_multiplicative_reduction() @@ -1198,15 +1231,15 @@ def has_additive_reduction(self, P): EXAMPLES:: sage: E = EllipticCurve('27a1') - sage: [(p,E.has_additive_reduction(p)) for p in prime_range(15)] + sage: [(p, E.has_additive_reduction(p)) for p in prime_range(15)] [(2, False), (3, True), (5, False), (7, False), (11, False), (13, False)] - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: P17a, P17b = [P for P,e in K.factor(17)] sage: E = EllipticCurve([0,0,0,0,2*a+1]) - sage: [(p,E.has_additive_reduction(p)) for p in [P17a,P17b]] + sage: [(p, E.has_additive_reduction(p)) for p in [P17a,P17b]] [(Fractional ideal (4*a^2 - 2*a + 1), False), - (Fractional ideal (2*a + 1), True)] + (Fractional ideal (2*a + 1), True)] """ return self.local_data(P).has_additive_reduction() @@ -1229,7 +1262,8 @@ def tamagawa_number(self, P, proof=None): EXAMPLES:: - sage: K.<a> = NumberField(x^2-5) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 5) sage: E = EllipticCurve([20, 225, 750, 625*a + 6875, 31250*a + 46875]) sage: [E.tamagawa_number(P) for P in E.discriminant().support()] [1, 1, 1, 1] @@ -1257,7 +1291,7 @@ def tamagawa_numbers(self): [2, 3, 1] sage: vector(e.tamagawa_numbers()) (2, 3, 1) - sage: K.<a> = NumberField(x^2+3) + sage: K.<a> = NumberField(x^2 + 3) sage: eK = e.base_extend(K) sage: eK.tamagawa_numbers() [4, 6, 1] @@ -1284,7 +1318,7 @@ def tamagawa_exponent(self, P, proof=None): EXAMPLES:: - sage: K.<a> = NumberField(x^2-5) + sage: K.<a> = NumberField(x^2 - 5) sage: E = EllipticCurve([20, 225, 750, 625*a + 6875, 31250*a + 46875]) sage: [E.tamagawa_exponent(P) for P in E.discriminant().support()] [1, 1, 1, 1] @@ -1316,12 +1350,12 @@ def tamagawa_product(self): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) - sage: E = EllipticCurve([0,2+i]) + sage: K.<i> = NumberField(x^2 + 1) + sage: E = EllipticCurve([0, 2+i]) sage: E.tamagawa_product() 1 - sage: E = EllipticCurve([(2*i+1)^2,i*(2*i+1)^7]) + sage: E = EllipticCurve([(2*i+1)^2, i*(2*i+1)^7]) sage: E.tamagawa_product() 4 @@ -1371,19 +1405,19 @@ def tamagawa_product_bsd(self): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) - sage: E = EllipticCurve([0,2+i]) + sage: K.<i> = NumberField(x^2 + 1) + sage: E = EllipticCurve([0, 2+i]) sage: E.tamagawa_product_bsd() 1 - sage: E = EllipticCurve([(2*i+1)^2,i*(2*i+1)^7]) + sage: E = EllipticCurve([(2*i+1)^2, i*(2*i+1)^7]) sage: E.tamagawa_product_bsd() 4 An example where the Neron model changes over K:: - sage: K.<t> = NumberField(x^5-10*x^3+5*x^2+10*x+1) - sage: E = EllipticCurve(K,'75a1') + sage: K.<t> = NumberField(x^5 - 10*x^3 + 5*x^2 + 10*x + 1) + sage: E = EllipticCurve(K, '75a1') sage: E.tamagawa_product_bsd() 5 sage: da = E.local_data() @@ -1430,14 +1464,15 @@ def kodaira_symbol(self, P, proof=None): OUTPUT: - The Kodaira Symbol of the curve at P, represented as a string. + The Kodaira Symbol of the curve at ``P``, represented as a string. EXAMPLES:: - sage: K.<a> = NumberField(x^2-5) + sage: K.<a> = NumberField(x^2 - 5) sage: E = EllipticCurve([20, 225, 750, 625*a + 6875, 31250*a + 46875]) sage: bad_primes = E.discriminant().support(); bad_primes - [Fractional ideal (-a), Fractional ideal (7/2*a - 81/2), Fractional ideal (-a - 52), Fractional ideal (2)] + [Fractional ideal (-a), Fractional ideal (7/2*a - 81/2), + Fractional ideal (-a - 52), Fractional ideal (2)] sage: [E.kodaira_symbol(P) for P in bad_primes] [I0, I1, I1, II] sage: K.<a> = QuadraticField(-11) @@ -1463,32 +1498,32 @@ def conductor(self): EXAMPLES:: - sage: K.<i> = NumberField(x^2+1) + sage: K.<i> = NumberField(x^2 + 1) sage: EllipticCurve([i, i - 1, i + 1, 24*i + 15, 14*i + 35]).conductor() Fractional ideal (21*i - 3) - sage: K.<a> = NumberField(x^2-x+3) - sage: EllipticCurve([1 + a , -1 + a , 1 + a , -11 + a , 5 -9*a ]).conductor() + sage: K.<a> = NumberField(x^2 - x + 3) + sage: EllipticCurve([1 + a, -1 + a, 1 + a, -11 + a, 5 - 9*a]).conductor() Fractional ideal (-6*a) A not so well known curve with everywhere good reduction:: - sage: K.<a> = NumberField(x^2-38) + sage: K.<a> = NumberField(x^2 - 38) sage: E = EllipticCurve([0,0,0, 21796814856932765568243810*a - 134364590724198567128296995, 121774567239345229314269094644186997594*a - 750668847495706904791115375024037711300]) sage: E.conductor() Fractional ideal (1) An example which used to fail (see :trac:`5307`):: - sage: K.<w> = NumberField(x^2+x+6) - sage: E = EllipticCurve([w,-1,0,-w-6,0]) + sage: K.<w> = NumberField(x^2 + x + 6) + sage: E = EllipticCurve([w, -1, 0, -w-6, 0]) sage: E.conductor() Fractional ideal (86304, w + 5898) An example raised in :trac:`11346`:: sage: K.<g> = NumberField(x^2 - x - 1) - sage: E1 = EllipticCurve(K,[0,0,0,-1/48,-161/864]) - sage: [(p.smallest_integer(),e) for p,e in E1.conductor().factor()] + sage: E1 = EllipticCurve(K, [0, 0, 0, -1/48, -161/864]) + sage: [(p.smallest_integer(), e) for p,e in E1.conductor().factor()] [(2, 4), (3, 1), (5, 1)] """ try: @@ -1499,10 +1534,11 @@ def conductor(self): # Note: for number fields other than QQ we could initialize # N=K.ideal(1) or N=OK.ideal(1), which are the same, but for # K == QQ it has to be ZZ.ideal(1). - OK = self.base_ring().ring_of_integers() + K = self.base_field() + N = ZZ.ideal(1) if K is QQ else K.fractional_ideal(1) self._conductor = prod([d.prime()**d.conductor_valuation() for d in self.local_data()], - OK.ideal(1)) + N) return self._conductor def minimal_discriminant_ideal(self): @@ -1519,10 +1555,10 @@ def minimal_discriminant_ideal(self): EXAMPLES:: - sage: K.<a> = NumberField(x^2-x-57) + sage: K.<a> = NumberField(x^2 - x - 57) sage: K.class_number() 3 - sage: E = EllipticCurve([a,-a,a,-5692-820*a,-259213-36720*a]) + sage: E = EllipticCurve([a, -a, a, -5692-820*a, -259213-36720*a]) sage: K.ideal(E.discriminant()) Fractional ideal (90118662980*a + 636812084644) sage: K.ideal(E.discriminant()).factor() @@ -1540,8 +1576,8 @@ def minimal_discriminant_ideal(self): If (and only if) the curve has everywhere good reduction the result is the unit ideal:: - sage: K.<a> = NumberField(x^2-26) - sage: E = EllipticCurve([a,a-1,a+1,4*a+10,2*a+6]) + sage: K.<a> = NumberField(x^2 - 26) + sage: E = EllipticCurve([a, a-1, a+1, 4*a+10, 2*a+6]) sage: E.conductor() Fractional ideal (1) sage: E.discriminant() @@ -1575,7 +1611,7 @@ def non_minimal_primes(self): EXAMPLES:: - sage: K.<a> = NumberField(x^2-10) + sage: K.<a> = NumberField(x^2 - 10) sage: E = EllipticCurve([0, 0, 0, -22500, 750000*a]) sage: E.non_minimal_primes() [Fractional ideal (2, a), Fractional ideal (5, a)] @@ -1586,7 +1622,7 @@ def non_minimal_primes(self): Over `\QQ`, the primes returned are integers, not ideals:: - sage: E = EllipticCurve([0,0,0,-3024,46224]) + sage: E = EllipticCurve([0, 0, 0, -3024, 46224]) sage: E.non_minimal_primes() [2, 3] sage: Emin = E.global_minimal_model() @@ -1596,7 +1632,7 @@ def non_minimal_primes(self): If the model is not globally integral, a ``ValueError`` is raised:: - sage: E = EllipticCurve([0,0,0,1/2,1/3]) + sage: E = EllipticCurve([0, 0, 0, 1/2, 1/3]) sage: E.non_minimal_primes() Traceback (most recent call last): ... @@ -1623,14 +1659,14 @@ def is_global_minimal_model(self): EXAMPLES:: - sage: K.<a> = NumberField(x^2-10) + sage: K.<a> = NumberField(x^2 - 10) sage: E = EllipticCurve([0, 0, 0, -22500, 750000*a]) sage: E.is_global_minimal_model() False sage: E.non_minimal_primes() [Fractional ideal (2, a), Fractional ideal (5, a)] - sage: E = EllipticCurve([0,0,0,-3024,46224]) + sage: E = EllipticCurve([0, 0, 0, -3024, 46224]) sage: E.is_global_minimal_model() False sage: E.non_minimal_primes() @@ -1670,7 +1706,7 @@ def global_minimality_class(self): A curve defined over a field of class number 2 with no global minimal model was a nontrivial minimality class:: - sage: K.<a> = NumberField(x^2-10) + sage: K.<a> = NumberField(x^2 - 10) sage: K.class_number() 2 sage: E = EllipticCurve([0, 0, 0, -22500, 750000*a]) @@ -1683,8 +1719,8 @@ def global_minimality_class(self): has trivial class, showing that a global minimal model does exist:: - sage: K.<a> = NumberField(x^2-10) - sage: E = EllipticCurve([0,0,0,4536*a+14148,-163728*a- 474336]) + sage: K.<a> = NumberField(x^2 - 10) + sage: E = EllipticCurve([0, 0, 0, 4536*a+14148, -163728*a-474336]) sage: E.is_global_minimal_model() False sage: E.global_minimality_class() @@ -1693,7 +1729,7 @@ def global_minimality_class(self): Over a field of class number 1 the result is always the trivial class:: - sage: K.<a> = NumberField(x^2-5) + sage: K.<a> = NumberField(x^2 - 5) sage: E = EllipticCurve([0, 0, 0, K(16), K(64)]) sage: E.global_minimality_class() Trivial principal fractional ideal class @@ -1727,8 +1763,8 @@ def has_global_minimal_model(self): EXAMPLES:: - sage: K.<a> = NumberField(x^2-10) - sage: E = EllipticCurve([0,0,0,4536*a+14148,-163728*a-474336]) + sage: K.<a> = NumberField(x^2 - 10) + sage: E = EllipticCurve([0, 0, 0, 4536*a+14148, -163728*a-474336]) sage: E.is_global_minimal_model() False sage: E.has_global_minimal_model() @@ -1767,41 +1803,46 @@ def global_minimal_model(self, proof=None, semi_global=False): EXAMPLES:: - sage: K.<a> = NumberField(x^2-38) + sage: K.<a> = NumberField(x^2 - 38) sage: E = EllipticCurve([0,0,0, 21796814856932765568243810*a - 134364590724198567128296995, 121774567239345229314269094644186997594*a - 750668847495706904791115375024037711300]) sage: E2 = E.global_minimal_model() sage: E2 - Elliptic Curve defined by y^2 + a*x*y + (a+1)*y = x^3 + (a+1)*x^2 + (4*a+15)*x + (4*a+21) over Number Field in a with defining polynomial x^2 - 38 + Elliptic Curve defined by + y^2 + a*x*y + (a+1)*y = x^3 + (a+1)*x^2 + (4*a+15)*x + (4*a+21) + over Number Field in a with defining polynomial x^2 - 38 sage: E2.local_data() [] See :trac:`11347`:: sage: K.<g> = NumberField(x^2 - x - 1) - sage: E = EllipticCurve(K,[0,0,0,-1/48,161/864]).integral_model().global_minimal_model(); E - Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 over Number Field in g with defining polynomial x^2 - x - 1 - sage: [(p.norm(), e) for p, e in E.conductor().factor()] + sage: E = EllipticCurve(K, [0, 0, 0, -1/48, 161/864]) + sage: E2 = E.integral_model().global_minimal_model(); E2 + Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + over Number Field in g with defining polynomial x^2 - x - 1 + sage: [(p.norm(), e) for p, e in E2.conductor().factor()] [(9, 1), (5, 1)] - sage: [(p.norm(), e) for p, e in E.discriminant().factor()] + sage: [(p.norm(), e) for p, e in E2.discriminant().factor()] [(-5, 2), (9, 1)] See :trac:`14472`, this used not to work over a relative extension:: - sage: K1.<w> = NumberField(x^2+x+1) + sage: K1.<w> = NumberField(x^2 + x + 1) sage: m = polygen(K1) - sage: K2.<v> = K1.extension(m^2-w+1) - sage: E = EllipticCurve([0*v,-432]) + sage: K2.<v> = K1.extension(m^2 - w + 1) + sage: E = EllipticCurve([0*v, -432]) sage: E.global_minimal_model() - Elliptic Curve defined by y^2 + y = x^3 over Number Field in v with defining polynomial x^2 - w + 1 over its base field + Elliptic Curve defined by y^2 + y = x^3 + over Number Field in v with defining polynomial x^2 - w + 1 over its base field See :trac:`18662`: for fields of class number greater than 1, even when global minimal models did exist, their computation was not implemented. Now it is:: - sage: K.<a> = NumberField(x^2-10) + sage: K.<a> = NumberField(x^2 - 10) sage: K.class_number() 2 - sage: E = EllipticCurve([0,0,0,-186408*a - 589491, 78055704*a + 246833838]) + sage: E = EllipticCurve([0, 0, 0, -186408*a - 589491, 78055704*a + 246833838]) sage: E.discriminant().norm() 16375845905239507992576 sage: E.discriminant().norm().factor() @@ -1809,7 +1850,9 @@ def global_minimal_model(self, proof=None, semi_global=False): sage: E.has_global_minimal_model() True sage: Emin = E.global_minimal_model(); Emin - Elliptic Curve defined by y^2 + (a+1)*x*y + (a+1)*y = x^3 + (-a)*x^2 + (a-12)*x + (-2*a+2) over Number Field in a with defining polynomial x^2 - 10 + Elliptic Curve defined by + y^2 + (a+1)*x*y + (a+1)*y = x^3 + (-a)*x^2 + (a-12)*x + (-2*a+2) + over Number Field in a with defining polynomial x^2 - 10 sage: Emin.discriminant().norm() 3456 sage: Emin.discriminant().norm().factor() @@ -1818,23 +1861,28 @@ def global_minimal_model(self, proof=None, semi_global=False): If there is no global minimal model, this method will raise an error unless you set the parameter ``semi_global`` to ``True``:: - sage: K.<a> = NumberField(x^2-10) + sage: K.<a> = NumberField(x^2 - 10) sage: K.class_number() 2 - sage: E = EllipticCurve([a,a,0,3*a+8,4*a+3]) + sage: E = EllipticCurve([a, a, 0, 3*a+8, 4*a+3]) sage: E.has_global_minimal_model() False sage: E.global_minimal_model() Traceback (most recent call last): ... - ValueError: Elliptic Curve defined by y^2 + a*x*y = x^3 + a*x^2 + (3*a+8)*x + (4*a+3) over Number Field in a with defining polynomial x^2 - 10 has no global minimal model! For a semi-global minimal model use semi_global=True + ValueError: Elliptic Curve defined by + y^2 + a*x*y = x^3 + a*x^2 + (3*a+8)*x + (4*a+3) over Number Field + in a with defining polynomial x^2 - 10 has no global minimal model! + For a semi-global minimal model use semi_global=True sage: E.global_minimal_model(semi_global=True) - Elliptic Curve defined by y^2 + a*x*y = x^3 + a*x^2 + (3*a+8)*x + (4*a+3) over Number Field in a with defining polynomial x^2 - 10 + Elliptic Curve defined by + y^2 + a*x*y = x^3 + a*x^2 + (3*a+8)*x + (4*a+3) over Number Field in a + with defining polynomial x^2 - 10 An example of a curve with everywhere good reduction but which has no model with unit discriminant:: - sage: K.<a> = NumberField(x^2-x-16) + sage: K.<a> = NumberField(x^2 - x - 16) sage: K.class_number() 2 sage: E = EllipticCurve([0,0,0,-15221331*a - 53748576, -79617688290*a - 281140318368]) @@ -1882,10 +1930,11 @@ def reduction(self,place): EXAMPLES:: sage: K.<i> = QuadraticField(-1) - sage: EK = EllipticCurve([0,0,0,i,i+3]) + sage: EK = EllipticCurve([0, 0, 0, i, i+3]) sage: v = K.fractional_ideal(2*i+3) sage: EK.reduction(v) - Elliptic Curve defined by y^2 = x^3 + 5*x + 8 over Residue field of Fractional ideal (2*i + 3) + Elliptic Curve defined by y^2 = x^3 + 5*x + 8 + over Residue field of Fractional ideal (2*i + 3) sage: EK.reduction(K.ideal(1+i)) Traceback (most recent call last): ... @@ -1894,10 +1943,11 @@ def reduction(self,place): Traceback (most recent call last): ... ValueError: The ideal must be prime. - sage: K=QQ.extension(x^2+x+1,"a") - sage: E = EllipticCurve([1024*K.0,1024*K.0]) + sage: K = QQ.extension(x^2 + x + 1, "a") + sage: E = EllipticCurve([1024*K.0, 1024*K.0]) sage: E.reduction(2*K) - Elliptic Curve defined by y^2 + (abar+1)*y = x^3 over Residue field in abar of Fractional ideal (2) + Elliptic Curve defined by y^2 + (abar+1)*y = x^3 + over Residue field in abar of Fractional ideal (2) """ K = self.base_field() OK = K.ring_of_integers() @@ -1922,20 +1972,20 @@ def torsion_subgroup(self): r""" Return the torsion subgroup of this elliptic curve. - OUTPUT: - - (``EllipticCurveTorsionSubgroup``) The - ``EllipticCurveTorsionSubgroup`` associated to this elliptic + OUTPUT: The :class:`EllipticCurveTorsionSubgroup` associated to this elliptic curve. EXAMPLES:: sage: E = EllipticCurve('11a1') + sage: x = polygen(ZZ, 'x') sage: K.<t> = NumberField(x^4 + x^3 + 11*x^2 + 41*x + 101) sage: EK = E.base_extend(K) sage: tor = EK.torsion_subgroup() # long time (2s on sage.math, 2014) sage: tor # long time - Torsion Subgroup isomorphic to Z/5 + Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in t with defining polynomial x^4 + x^3 + 11*x^2 + 41*x + 101 + Torsion Subgroup isomorphic to Z/5 + Z/5 associated to the Elliptic Curve + defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field + in t with defining polynomial x^4 + x^3 + 11*x^2 + 41*x + 101 sage: tor.gens() # long time ((16 : 60 : 1), (t : 1/11*t^3 + 6/11*t^2 + 19/11*t + 48/11 : 1)) @@ -1945,7 +1995,9 @@ def torsion_subgroup(self): sage: K.<t> = NumberField(x^2 + 2*x + 10) sage: EK = E.base_extend(K) sage: EK.torsion_subgroup() - Torsion Subgroup isomorphic to Z/4 + Z/4 associated to the Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + (-10)*x + (-10) over Number Field in t with defining polynomial x^2 + 2*x + 10 + Torsion Subgroup isomorphic to Z/4 + Z/4 associated to the + Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + (-10)*x + (-10) + over Number Field in t with defining polynomial x^2 + 2*x + 10 :: @@ -1953,14 +2005,18 @@ def torsion_subgroup(self): sage: K.<t> = NumberField(x^9-3*x^8-4*x^7+16*x^6-3*x^5-21*x^4+5*x^3+7*x^2-7*x+1) sage: EK = E.base_extend(K) sage: EK.torsion_subgroup() - Torsion Subgroup isomorphic to Z/9 associated to the Elliptic Curve defined by y^2 + y = x^3 + x^2 + (-9)*x + (-15) over Number Field in t with defining polynomial x^9 - 3*x^8 - 4*x^7 + 16*x^6 - 3*x^5 - 21*x^4 + 5*x^3 + 7*x^2 - 7*x + 1 + Torsion Subgroup isomorphic to Z/9 associated to the Elliptic Curve defined + by y^2 + y = x^3 + x^2 + (-9)*x + (-15) over Number Field in t with defining + polynomial x^9 - 3*x^8 - 4*x^7 + 16*x^6 - 3*x^5 - 21*x^4 + 5*x^3 + 7*x^2 - 7*x + 1 :: sage: K.<i> = QuadraticField(-1) - sage: EK = EllipticCurve([0,0,0,i,i+3]) + sage: EK = EllipticCurve([0, 0, 0, i, i+3]) sage: EK.torsion_subgroup () - Torsion Subgroup isomorphic to Trivial group associated to the Elliptic Curve defined by y^2 = x^3 + i*x + (i+3) over Number Field in i with defining polynomial x^2 + 1 with i = 1*I + Torsion Subgroup isomorphic to Trivial group associated to the + Elliptic Curve defined by y^2 = x^3 + i*x + (i+3) + over Number Field in i with defining polynomial x^2 + 1 with i = 1*I .. SEEALSO:: @@ -1982,6 +2038,7 @@ def torsion_order(self): EXAMPLES:: sage: E = EllipticCurve('11a1') + sage: x = polygen(ZZ, 'x') sage: K.<t> = NumberField(x^4 + x^3 + 11*x^2 + 41*x + 101) sage: EK = E.base_extend(K) sage: EK.torsion_order() # long time (2s on sage.math, 2014) @@ -1998,7 +2055,7 @@ def torsion_order(self): :: sage: E = EllipticCurve('19a1') - sage: K.<t> = NumberField(x^9-3*x^8-4*x^7+16*x^6-3*x^5-21*x^4+5*x^3+7*x^2-7*x+1) + sage: K.<t> = NumberField(x^9 - 3*x^8 - 4*x^7 + 16*x^6 - 3*x^5 - 21*x^4 + 5*x^3 + 7*x^2 - 7*x + 1) sage: EK = E.base_extend(K) sage: EK.torsion_order() 9 @@ -2006,7 +2063,7 @@ def torsion_order(self): :: sage: K.<i> = QuadraticField(-1) - sage: EK = EllipticCurve([0,0,0,i,i+3]) + sage: EK = EllipticCurve([0, 0, 0, i, i + 3]) sage: EK.torsion_order() 1 """ @@ -2025,6 +2082,7 @@ def torsion_points(self): sage: E = EllipticCurve('11a1') sage: E.torsion_points() [(0 : 1 : 0), (5 : -6 : 1), (5 : 5 : 1), (16 : -61 : 1), (16 : 60 : 1)] + sage: x = polygen(ZZ, 'x') sage: K.<t> = NumberField(x^4 + x^3 + 11*x^2 + 41*x + 101) sage: EK = E.base_extend(K) sage: EK.torsion_points() # long time (1s on sage.math, 2014) @@ -2080,8 +2138,8 @@ def torsion_points(self): :: sage: K.<i> = QuadraticField(-1) - sage: EK = EllipticCurve(K,[0,0,0,0,-1]) - sage: EK.torsion_points () + sage: EK = EllipticCurve(K, [0,0,0,0,-1]) + sage: EK.torsion_points() [(-2 : -3*i : 1), (-2 : 3*i : 1), (0 : -i : 1), (0 : i : 1), (0 : 1 : 0), (1 : 0 : 1)] """ T = self.torsion_subgroup() # cached @@ -2128,6 +2186,7 @@ def rank_bounds(self, **kwds): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23, 'a') sage: E = EllipticCurve(K, '37') sage: E == loads(dumps(E)) @@ -2137,8 +2196,8 @@ def rank_bounds(self, **kwds): Here is a curve with two-torsion, again the bounds coincide:: - sage: Qrt5.<rt5> = NumberField(x^2-5) - sage: E = EllipticCurve([0,5-rt5,0,rt5,0]) + sage: Qrt5.<rt5> = NumberField(x^2 - 5) + sage: E = EllipticCurve([0, 5-rt5, 0, rt5, 0]) sage: E.rank_bounds() (1, 1) @@ -2147,9 +2206,9 @@ def rank_bounds(self, **kwds): give bounds:: sage: E = EllipticCurve("15a5") - sage: K.<t> = NumberField(x^2-6) + sage: K.<t> = NumberField(x^2 - 6) sage: EK = E.base_extend(K) - sage: EK.rank_bounds(lim1=1,lim3=1,limtriv=1) + sage: EK.rank_bounds(lim1=1, lim3=1, limtriv=1) (0, 2) IMPLEMENTATION: @@ -2207,6 +2266,7 @@ def rank(self, **kwds): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23, 'a') sage: E = EllipticCurve(K, '37') sage: E == loads(dumps(E)) @@ -2219,7 +2279,7 @@ def rank(self, **kwds): determine the rank:: sage: E = EllipticCurve("15a5") - sage: K.<t> = NumberField(x^2-6) + sage: K.<t> = NumberField(x^2 - 6) sage: EK = E.base_extend(K) sage: EK.rank(lim1=1, lim3=1, limtriv=1) Traceback (most recent call last): @@ -2285,6 +2345,7 @@ def gens(self, **kwds): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + 23, 'a') sage: E = EllipticCurve(K,[0,0,0,101,0]) sage: E.gens() @@ -2313,8 +2374,8 @@ def gens(self, **kwds): Here is a curve of rank 2:: - sage: K.<t> = NumberField(x^2-17) - sage: E = EllipticCurve(K,[-4,0]) + sage: K.<t> = NumberField(x^2 - 17) + sage: E = EllipticCurve(K, [-4, 0]) sage: E.gens() [(-1/2*t + 1/2 : -1/2*t + 1/2 : 1), (-t + 3 : -2*t + 10 : 1)] sage: E.rank() @@ -2323,7 +2384,7 @@ def gens(self, **kwds): Test that points of finite order are not included (see :trac:`13593`):: sage: E = EllipticCurve("17a3") - sage: K.<t> = NumberField(x^2+3) + sage: K.<t> = NumberField(x^2 + 3) sage: EK = E.base_extend(K) sage: EK.rank() 0 @@ -2364,7 +2425,7 @@ def period_lattice(self, embedding): First define a field with two real embeddings:: - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,0,0,a,2]) sage: embs = K.embeddings(CC); len(embs) 3 @@ -2372,38 +2433,44 @@ def period_lattice(self, embedding): For each embedding we have a different period lattice:: sage: E.period_lattice(embs[0]) - Period lattice associated to Elliptic Curve defined by y^2 = x^3 + a*x + 2 over Number Field in a with defining polynomial x^3 - 2 with respect to the embedding Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Algebraic Field - Defn: a |--> -0.6299605249474365? - 1.091123635971722?*I + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + a*x + 2 + over Number Field in a with defining polynomial x^3 - 2 + with respect to the embedding Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Algebraic Field + Defn: a |--> -0.6299605249474365? - 1.091123635971722?*I sage: E.period_lattice(embs[1]) - Period lattice associated to Elliptic Curve defined by y^2 = x^3 + a*x + 2 over Number Field in a with defining polynomial x^3 - 2 with respect to the embedding Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Algebraic Field - Defn: a |--> -0.6299605249474365? + 1.091123635971722?*I + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + a*x + 2 + over Number Field in a with defining polynomial x^3 - 2 + with respect to the embedding Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Algebraic Field + Defn: a |--> -0.6299605249474365? + 1.091123635971722?*I sage: E.period_lattice(embs[2]) - Period lattice associated to Elliptic Curve defined by y^2 = x^3 + a*x + 2 over Number Field in a with defining polynomial x^3 - 2 with respect to the embedding Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Algebraic Field - Defn: a |--> 1.259921049894873? + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + a*x + 2 + over Number Field in a with defining polynomial x^3 - 2 + with respect to the embedding Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Algebraic Field + Defn: a |--> 1.259921049894873? Although the original embeddings have only the default precision, we can obtain the basis with higher precision later:: - sage: L=E.period_lattice(embs[0]) + sage: L = E.period_lattice(embs[0]) sage: L.basis() (1.86405007647981 - 0.903761485143226*I, -0.149344633143919 - 2.06619546272945*I) sage: L.basis(prec=100) - (1.8640500764798108425920506200 - 0.90376148514322594749786960975*I, -0.14934463314391922099120107422 - 2.0661954627294548995621225062*I) + (1.8640500764798108425920506200 - 0.90376148514322594749786960975*I, + -0.14934463314391922099120107422 - 2.0661954627294548995621225062*I) """ from sage.schemes.elliptic_curves.period_lattice import PeriodLattice_ell return PeriodLattice_ell(self,embedding) - def real_components(self, embedding): """ Return the number of real components with respect to a real embedding of the base field. @@ -2462,10 +2529,13 @@ def height_function(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - 5) sage: E = EllipticCurve(K, '11a3') sage: E.height_function() - EllipticCurveCanonicalHeight object associated to Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 over Number Field in a with defining polynomial x^2 - 5 + EllipticCurveCanonicalHeight object associated to + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + over Number Field in a with defining polynomial x^2 - 5 """ if not hasattr(self, '_height_function'): from sage.schemes.elliptic_curves.height import EllipticCurveCanonicalHeight @@ -2486,10 +2556,10 @@ def isogeny_class(self, reducible_primes=None, algorithm='Billerey', minimal_mod the isogeny class, only composites isogenies of these degrees will be used. - - ``algorithm`` (string, default 'Billerey') -- the algorithm + - ``algorithm`` (string, default ``'Billerey'``) -- the algorithm to use to compute the reducible primes. Ignored for CM curves or if ``reducible_primes`` is provided. Values are - 'Billerey' (default), 'Larson', and 'heuristic'. + ``'Billerey'`` (default), ``'Larson'``, and ``'heuristic'``. - ``minimal_models`` (bool, default ``True``) -- if ``True``, all curves in the class will be minimal or semi-minimal @@ -2506,7 +2576,7 @@ def isogeny_class(self, reducible_primes=None, algorithm='Billerey', minimal_mod .. NOTE:: - If using the algorithm 'heuristic' for non-CM curves, the + If using the algorithm ``'heuristic'`` for non-CM curves, the result is not guaranteed to be the complete isogeny class, since only reducible primes up to the default bound in :meth:`reducible_primes_naive` (currently 1000) are @@ -2528,7 +2598,8 @@ def isogeny_class(self, reducible_primes=None, algorithm='Billerey', minimal_mod sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve(K, [0,0,0,0,1]) sage: C = E.isogeny_class(); C - Isogeny class of Elliptic Curve defined by y^2 = x^3 + 1 over Number Field in i with defining polynomial x^2 + 1 with i = 1*I + Isogeny class of Elliptic Curve defined by y^2 = x^3 + 1 + over Number Field in i with defining polynomial x^2 + 1 with i = 1*I The curves in the class (sorted):: @@ -2554,16 +2625,18 @@ class :class:`EllipticCurveIsogeny` allowed composition. In to 3, and `3`-isogenies to go from 0 to 1 and from 2 to 3:: sage: isogs = C.isogenies() - sage: [((i,j),isogs[i][j].degree()) for i in range(4) for j in range(4) if isogs[i][j]!=0] + sage: [((i,j), isogs[i][j].degree()) + ....: for i in range(4) for j in range(4) if isogs[i][j] != 0] [((0, 1), 3), - ((0, 3), 2), - ((1, 0), 3), - ((1, 2), 2), - ((2, 1), 2), - ((2, 3), 3), - ((3, 0), 2), - ((3, 2), 3)] - sage: [((i,j),isogs[i][j].x_rational_map()) for i in range(4) for j in range(4) if isogs[i][j]!=0] + ((0, 3), 2), + ((1, 0), 3), + ((1, 2), 2), + ((2, 1), 2), + ((2, 3), 3), + ((3, 0), 2), + ((3, 2), 3)] + sage: [((i,j), isogs[i][j].x_rational_map()) + ....: for i in range(4) for j in range(4) if isogs[i][j] != 0] [((0, 1), (1/9*x^3 - 12)/x^2), ((0, 3), (-1/2*i*x^2 + i*x - 12*i)/(x - 3)), ((1, 0), (x^3 + 4)/x^2), @@ -2582,7 +2655,9 @@ class :class:`EllipticCurveIsogeny` allowed composition. In sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve([1+i, -i, i, 1, 0]) sage: C = E.isogeny_class(); C # long time - Isogeny class of Elliptic Curve defined by y^2 + (i+1)*x*y + i*y = x^3 + (-i)*x^2 + x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I + Isogeny class of + Elliptic Curve defined by y^2 + (i+1)*x*y + i*y = x^3 + (-i)*x^2 + x + over Number Field in i with defining polynomial x^2 + 1 with i = 1*I sage: len(C) # long time 6 sage: C.matrix() # long time @@ -2594,17 +2669,17 @@ class :class:`EllipticCurveIsogeny` allowed composition. In [ 2 6 18 9 3 1] sage: [E1.ainvs() for E1 in C] # long time [(i + 1, i - 1, i, -i - 1, -i + 1), - (i + 1, i - 1, i, 14*i + 4, 7*i + 14), - (i + 1, i - 1, i, 59*i + 99, 372*i - 410), - (i + 1, -i, i, -240*i - 399, 2869*i + 2627), - (i + 1, -i, i, -5*i - 4, 2*i + 5), - (i + 1, -i, i, 1, 0)] + (i + 1, i - 1, i, 14*i + 4, 7*i + 14), + (i + 1, i - 1, i, 59*i + 99, 372*i - 410), + (i + 1, -i, i, -240*i - 399, 2869*i + 2627), + (i + 1, -i, i, -5*i - 4, 2*i + 5), + (i + 1, -i, i, 1, 0)] An example with CM by `\sqrt{-5}`:: sage: pol = PolynomialRing(QQ,'x')([1,0,3,0,1]) sage: K.<c> = NumberField(pol) - sage: j = 1480640+565760*c^2 + sage: j = 1480640 + 565760*c^2 sage: E = EllipticCurve(j=j) sage: E.has_cm() True @@ -2622,7 +2697,13 @@ class :class:`EllipticCurveIsogeny` allowed composition. In [(0, 0, 0, 83490*c^2 - 147015, -64739840*c^2 - 84465260), (0, 0, 0, -161535*c^2 + 70785, -62264180*c^3 + 6229080*c)] sage: C.isogenies()[0][1] - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + (83490*c^2-147015)*x + (-64739840*c^2-84465260) over Number Field in c with defining polynomial x^4 + 3*x^2 + 1 to Elliptic Curve defined by y^2 = x^3 + (-161535*c^2+70785)*x + (-62264180*c^3+6229080*c) over Number Field in c with defining polynomial x^4 + 3*x^2 + 1 + Isogeny of degree 2 + from Elliptic Curve defined by + y^2 = x^3 + (83490*c^2-147015)*x + (-64739840*c^2-84465260) + over Number Field in c with defining polynomial x^4 + 3*x^2 + 1 + to Elliptic Curve defined by + y^2 = x^3 + (-161535*c^2+70785)*x + (-62264180*c^3+6229080*c) + over Number Field in c with defining polynomial x^4 + 3*x^2 + 1 An example with CM by `\sqrt{-23}` (class number `3`):: @@ -2715,7 +2796,7 @@ class number is only `3` is that the class also contains three different endomorphism rings, then use a 3-dimensional plot which can be rotated:: - sage: for i,j,l in G.edge_iterator(): # long time + sage: for i, j, l in G.edge_iterator(): # long time ....: G.set_edge_label(i, j, l.count(',')) sage: G.show3d(color_by_label=True) # long time @@ -2723,9 +2804,9 @@ class number is only `3` is that the class also contains three defines the same field as ``pol26`` but is simpler:: sage: pol26 = hilbert_class_polynomial(-4*26) - sage: pol = x^6-x^5+2*x^4+x^3-2*x^2-x-1 + sage: pol = x^6 - x^5 + 2*x^4 + x^3 - 2*x^2 - x - 1 sage: K.<a> = NumberField(pol) - sage: L.<b> = K.extension(x^2+26) + sage: L.<b> = K.extension(x^2 + 26) Only `2` of the `j`-invariants with discriminant -104 are in `K`, though all are in `L`:: @@ -2768,7 +2849,7 @@ class number is only `3` is that the class also contains three sage: len(CL) # long time 6 sage: s1 = Set([EE.j_invariant() for EE in CL.curves]) # long time - sage: s2 = Set(pol26.roots(L,multiplicities=False)) # long time + sage: s2 = Set(pol26.roots(L, multiplicities=False)) # long time sage: s1 == s2 # long time True @@ -2822,17 +2903,20 @@ class number is only `3` is that the class also contains three sage: K.<z> = CyclotomicField(53) sage: E = EllipticCurve(K,[0,6,0,2,0]) sage: C = E.isogeny_class(algorithm='heuristic', minimal_models=False); C # long time (10s) - Isogeny class of Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 2*x over Cyclotomic Field of order 53 and degree 52 + Isogeny class of Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 2*x + over Cyclotomic Field of order 53 and degree 52 sage: C.curves # long time - [Elliptic Curve defined by y^2 = x^3 + 6*x^2 + (-8)*x + (-48) over Cyclotomic Field of order 53 and degree 52, - Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 2*x over Cyclotomic Field of order 53 and degree 52] + [Elliptic Curve defined by y^2 = x^3 + 6*x^2 + (-8)*x + (-48) + over Cyclotomic Field of order 53 and degree 52, + Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 2*x + over Cyclotomic Field of order 53 and degree 52] TESTS: An example which failed until fixed at :trac:`19229`:: - sage: K.<a> = NumberField(x^2-x+1) - sage: E = EllipticCurve([a+1,1,1,0,0]) + sage: K.<a> = NumberField(x^2 - x + 1) + sage: E = EllipticCurve([a+1, 1, 1, 0, 0]) sage: C = E.isogeny_class(); len(C) # long time 4 """ @@ -2892,7 +2976,7 @@ def isogenies_prime_degree(self, l=None, algorithm='Billerey', minimal_models=Tr sage: pol = PolynomialRing(QQ,'x')([1,-3,5,-5,5,-3,1]) sage: L.<a> = NumberField(pol) - sage: js = hilbert_class_polynomial(-23).roots(L,multiplicities=False); len(js) + sage: js = hilbert_class_polynomial(-23).roots(L, multiplicities=False); len(js) 3 sage: E = EllipticCurve(j=js[0]) sage: len(E.isogenies_prime_degree()) # long time @@ -2905,11 +2989,19 @@ def isogenies_prime_degree(self, l=None, algorithm='Billerey', minimal_models=Tr sage: proof.number_field(False) sage: K.<z> = CyclotomicField(53) - sage: E = EllipticCurve(K,[0,6,0,2,0]) + sage: E = EllipticCurve(K, [0,6,0,2,0]) sage: E.isogenies_prime_degree(2, minimal_models=False) - [Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 2*x over Cyclotomic Field of order 53 and degree 52 to Elliptic Curve defined by y^2 = x^3 + 6*x^2 + (-8)*x + (-48) over Cyclotomic Field of order 53 and degree 52] + [Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 2*x + over Cyclotomic Field of order 53 and degree 52 + to Elliptic Curve defined by y^2 = x^3 + 6*x^2 + (-8)*x + (-48) + over Cyclotomic Field of order 53 and degree 52] sage: E.isogenies_prime_degree(2, minimal_models=True) # not tested (10s) - [Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 2*x over Cyclotomic Field of order 53 and degree 52 to Elliptic Curve defined by y^2 = x^3 + (-20)*x + (-16) over Cyclotomic Field of order 53 and degree 52] + [Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 2*x + over Cyclotomic Field of order 53 and degree 52 + to Elliptic Curve defined by y^2 = x^3 + (-20)*x + (-16) + over Cyclotomic Field of order 53 and degree 52] TESTS:: @@ -2977,7 +3069,7 @@ def is_isogenous(self, other, proof=True, maxnorm=100): EXAMPLES:: sage: x = polygen(QQ, 'x') - sage: F = NumberField(x^2 -2, 's'); F + sage: F = NumberField(x^2 - 2, 's'); F Number Field in s with defining polynomial x^2 - 2 sage: E1 = EllipticCurve(F, [7,8]) sage: E2 = EllipticCurve(F, [0,5,0,1,0]) @@ -2996,7 +3088,7 @@ def is_isogenous(self, other, proof=True, maxnorm=100): :: sage: x = polygen(QQ, 'x') - sage: F = NumberField(x^2 -2, 's'); F + sage: F = NumberField(x^2 - 2, 's'); F Number Field in s with defining polynomial x^2 - 2 sage: E = EllipticCurve('14a1') sage: EE = EllipticCurve('14a2') @@ -3008,9 +3100,9 @@ def is_isogenous(self, other, proof=True, maxnorm=100): :: sage: x = polygen(QQ, 'x') - sage: F = NumberField(x^2 -2, 's'); F + sage: F = NumberField(x^2 - 2, 's'); F Number Field in s with defining polynomial x^2 - 2 - sage: k.<a> = NumberField(x^3+7) + sage: k.<a> = NumberField(x^3 + 7) sage: E = EllipticCurve(F, [7,8]) sage: EE = EllipticCurve(k, [2, 2]) sage: E.is_isogenous(EE) @@ -3144,7 +3236,7 @@ def isogeny_degree(self, other): EXAMPLES:: sage: x = QQ['x'].0 - sage: F = NumberField(x^2 -2, 's'); F + sage: F = NumberField(x^2 - 2, 's'); F Number Field in s with defining polynomial x^2 - 2 sage: E = EllipticCurve('14a1') sage: EE = EllipticCurve('14a2') @@ -3222,6 +3314,7 @@ def reducible_primes(self, algorithm='Billerey', max_l=None, EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: rho = E.galois_representation() @@ -3304,30 +3397,30 @@ def lll_reduce(self, points, height_matrix=None, precision=None): :: sage: E = EllipticCurve([1,0,1,-120039822036992245303534619191166796374,504224992484910670010801799168082726759443756222911415116]) - sage: xi = [2005024558054813068,\ - -4690836759490453344,\ - 4700156326649806635,\ - 6785546256295273860,\ - 6823803569166584943,\ - 7788809602110240789,\ - 27385442304350994620556,\ - 54284682060285253719/4,\ - -94200235260395075139/25,\ - -3463661055331841724647/576,\ - -6684065934033506970637/676,\ - -956077386192640344198/2209,\ - -27067471797013364392578/2809,\ - -25538866857137199063309/3721,\ - -1026325011760259051894331/108241,\ - 9351361230729481250627334/1366561,\ - 10100878635879432897339615/1423249,\ - 11499655868211022625340735/17522596,\ - 110352253665081002517811734/21353641,\ - 414280096426033094143668538257/285204544,\ - 36101712290699828042930087436/4098432361,\ - 45442463408503524215460183165/5424617104,\ - 983886013344700707678587482584/141566320009,\ - 1124614335716851053281176544216033/152487126016] + sage: xi = [2005024558054813068, + ....: -4690836759490453344, + ....: 4700156326649806635, + ....: 6785546256295273860, + ....: 6823803569166584943, + ....: 7788809602110240789, + ....: 27385442304350994620556, + ....: 54284682060285253719/4, + ....: -94200235260395075139/25, + ....: -3463661055331841724647/576, + ....: -6684065934033506970637/676, + ....: -956077386192640344198/2209, + ....: -27067471797013364392578/2809, + ....: -25538866857137199063309/3721, + ....: -1026325011760259051894331/108241, + ....: 9351361230729481250627334/1366561, + ....: 10100878635879432897339615/1423249, + ....: 11499655868211022625340735/17522596, + ....: 110352253665081002517811734/21353641, + ....: 414280096426033094143668538257/285204544, + ....: 36101712290699828042930087436/4098432361, + ....: 45442463408503524215460183165/5424617104, + ....: 983886013344700707678587482584/141566320009, + ....: 1124614335716851053281176544216033/152487126016] sage: points = [E.lift_x(x) for x in xi] sage: newpoints, U = E.lll_reduce(points) # long time (35s on sage.math, 2011) sage: [P[0] for P in newpoints] # long time @@ -3350,7 +3443,7 @@ def lll_reduce(self, points, height_matrix=None, precision=None): sage: K.<a> = QuadraticField(-23, 'a') sage: E = EllipticCurve(K, [0,0,1,-1,0]) - sage: P = E(-2,-(a+1)/2) + sage: P = E(-2, -(a+1)/2) sage: Q = E(0,-1) sage: E.lll_reduce([P,Q]) ( @@ -3361,8 +3454,9 @@ def lll_reduce(self, points, height_matrix=None, precision=None): :: sage: K.<a> = QuadraticField(-5) - sage: E = EllipticCurve(K,[0,a]) - sage: points = [E.point([-211/841*a - 6044/841,-209584/24389*a + 53634/24389]),E.point([-17/18*a - 1/9, -109/108*a - 277/108]) ] + sage: E = EllipticCurve(K, [0,a]) + sage: points = [E.point([-211/841*a - 6044/841,-209584/24389*a + 53634/24389]), + ....: E.point([-17/18*a - 1/9, -109/108*a - 277/108])] sage: E.lll_reduce(points) ( [(-a + 4 : -3*a + 7 : 1), (-17/18*a - 1/9 : 109/108*a + 277/108 : 1)], @@ -3394,11 +3488,14 @@ def galois_representation(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 + 1, 'a') sage: E = EllipticCurve('11a1').change_ring(K) sage: rho = E.galois_representation() sage: rho - Compatible family of Galois representations associated to the Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in a with defining polynomial x^2 + 1 + Compatible family of Galois representations associated to the + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) + over Number Field in a with defining polynomial x^2 + 1 sage: rho.is_surjective(3) True sage: rho.is_surjective(5) # long time (4s on sage.math, 2014) @@ -3434,7 +3531,8 @@ def cm_discriminant(self): sage: EllipticCurve(j=1).cm_discriminant() Traceback (most recent call last): ... - ValueError: Elliptic Curve defined by y^2 + x*y = x^3 + 36*x + 3455 over Rational Field does not have CM + ValueError: Elliptic Curve defined by y^2 + x*y = x^3 + 36*x + 3455 + over Rational Field does not have CM sage: EllipticCurve(j=1728).cm_discriminant() -4 sage: EllipticCurve(j=8000).cm_discriminant() @@ -3442,6 +3540,7 @@ def cm_discriminant(self): sage: K.<a> = QuadraticField(5) sage: EllipticCurve(j=282880*a + 632000).cm_discriminant() -20 + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: EllipticCurve(j=31710790944000*a^2 + 39953093016000*a + 50337742902000).cm_discriminant() -108 @@ -3488,6 +3587,7 @@ def has_cm(self): sage: K.<a> = QuadraticField(5) sage: EllipticCurve(j=282880*a + 632000).has_cm() True + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: EllipticCurve(j=31710790944000*a^2 + 39953093016000*a + 50337742902000).has_cm() True @@ -3552,7 +3652,7 @@ def has_rational_cm(self, field=None): False sage: E.cm_discriminant() -20 - sage: E.has_rational_cm(K.extension(x^2+5,'b')) + sage: E.has_rational_cm(K.extension(x^2 + 5, 'b')) True An error is raised if a field is given which is not an extension of the base field:: @@ -3560,8 +3660,12 @@ def has_rational_cm(self, field=None): sage: E.has_rational_cm(QuadraticField(-20)) Traceback (most recent call last): ... - ValueError: Error in has_rational_cm: Number Field in a with defining polynomial x^2 + 20 with a = 4.472135954999579?*I is not an extension field of Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? + ValueError: Error in has_rational_cm: Number Field in a + with defining polynomial x^2 + 20 with a = 4.472135954999579?*I + is not an extension field of Number Field in a + with defining polynomial x^2 - 5 with a = 2.236067977499790? + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve(j=31710790944000*a^2 + 39953093016000*a + 50337742902000) sage: E.has_cm() @@ -3570,7 +3674,7 @@ def has_rational_cm(self, field=None): False sage: D = E.cm_discriminant(); D -108 - sage: E.has_rational_cm(K.extension(x^2+108,'b')) + sage: E.has_rational_cm(K.extension(x^2 + 108,'b')) True """ D = self.cm_discriminant() @@ -3610,20 +3714,20 @@ def is_Q_curve(self, maxp=100, certificate=False, verbose=False): - when the flag is ``True``, so `E` is a `\QQ`-curve: - - either {'CM':`D`} where `D` is a negative discriminant, when - `E` has potential CM with discriminant `D`; - - - otherwise {'CM': `0`, 'core_poly': `f`, 'rho': `\rho`, - 'r': `r`, 'N': `N`}, when `E` is a non-CM `\QQ`-curve, - where the core polynomial `f` is an irreducible monic - polynomial over `QQ` of degree `2^\rho`, all of whose - roots are `j`-invariants of curves isogenous to `E`, the - core level `N` is a square-free integer with `r` prime - factors which is the LCM of the degrees of the isogenies - between these conjugates. For example, if there exists - a curve `E'` isogenous to `E` with `j(E')=j\in\QQ`, then - the certificate is {'CM':0, 'r':0, 'rho':0, 'core_poly': - x-j, 'N':1}. + - either {'CM':`D`} where `D` is a negative discriminant, when + `E` has potential CM with discriminant `D`; + + - otherwise {'CM': `0`, 'core_poly': `f`, 'rho': `\rho`, + 'r': `r`, 'N': `N`}, when `E` is a non-CM `\QQ`-curve, + where the core polynomial `f` is an irreducible monic + polynomial over `QQ` of degree `2^\rho`, all of whose + roots are `j`-invariants of curves isogenous to `E`, the + core level `N` is a square-free integer with `r` prime + factors which is the LCM of the degrees of the isogenies + between these conjugates. For example, if there exists + a curve `E'` isogenous to `E` with `j(E')=j\in\QQ`, then + the certificate is {'CM':0, 'r':0, 'rho':0, 'core_poly': + x-j, 'N':1}. - when the flag is ``False``, so `E` is not a `\QQ`-curve, the certificate is a prime `p` such that the reductions of `E` @@ -3662,7 +3766,7 @@ def is_Q_curve(self, maxp=100, certificate=False, verbose=False): sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(R([3, 0, -5, 0, 1])) - sage: E = EllipticCurve([K([-3,-4,1,1]),K([4,-1,-1,0]),K([-2,0,1,0]),K([-621,778,138,-178]),K([9509,2046,-24728,10380])]) + sage: E = EllipticCurve([K([-3,-4,1,1]), K([4,-1,-1,0]), K([-2,0,1,0]), K([-621,778,138,-178]), K([9509,2046,-24728,10380])]) sage: E.is_Q_curve(certificate=True, verbose=True) Checking whether Elliptic Curve defined by y^2 + (a^3+a^2-4*a-3)*x*y + (a^2-2)*y = x^3 + (-a^2-a+4)*x^2 + (-178*a^3+138*a^2+778*a-621)*x + (10380*a^3-24728*a^2+2046*a+9509) over Number Field in a with defining polynomial x^4 - 5*x^2 + 3 is a Q-curve No: inconsistency at the 2 primes dividing 3 @@ -3674,7 +3778,7 @@ def is_Q_curve(self, maxp=100, certificate=False, verbose=False): is not:: sage: K.<a> = NumberField(R([-10, 0, 1])) - sage: E = EllipticCurve([K([0,1]),K([-1,-1]),K([0,0]),K([-236,40]),K([-1840,464])]) + sage: E = EllipticCurve([K([0,1]), K([-1,-1]), K([0,0]), K([-236,40]), K([-1840,464])]) sage: E.is_Q_curve(certificate=True, verbose=True) Checking whether Elliptic Curve defined by y^2 + a*x*y = x^3 + (-a-1)*x^2 + (40*a-236)*x + (464*a-1840) over Number Field in a with defining polynomial x^2 - 10 is a Q-curve Applying local tests at good primes above p<=100 @@ -3688,7 +3792,7 @@ def is_Q_curve(self, maxp=100, certificate=False, verbose=False): sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(R([-1, -1, 1])) - sage: E = EllipticCurve([K([1,0]),K([-1,0]),K([0,1]),K([0,-2]),K([0,1])]) + sage: E = EllipticCurve([K([1,0]), K([-1,0]), K([0,1]), K([0,-2]), K([0,1])]) sage: E.is_Q_curve(certificate=True, verbose=True) Checking whether Elliptic Curve defined by y^2 + x*y + a*y = x^3 + (-1)*x^2 + (-2*a)*x + a over Number Field in a with defining polynomial x^2 - x - 1 is a Q-curve Yes: E is CM (discriminant -15) @@ -3700,7 +3804,7 @@ def is_Q_curve(self, maxp=100, certificate=False, verbose=False): `j`, so we have a so-called rational `\QQ`-curve:: sage: K.<a> = NumberField(R([1, 0, -4, 0, 1])) - sage: E = EllipticCurve([K([-2,-4,1,1]),K([0,1,0,0]),K([0,1,0,0]),K([-4780,9170,1265,-2463]),K([163923,-316598,-43876,84852])]) + sage: E = EllipticCurve([K([-2,-4,1,1]), K([0,1,0,0]), K([0,1,0,0]), K([-4780,9170,1265,-2463]), K([163923,-316598,-43876,84852])]) sage: flag, cert = E.is_Q_curve(certificate=True) # long time sage: flag # long time True @@ -3714,17 +3818,17 @@ def is_Q_curve(self, maxp=100, certificate=False, verbose=False): with quadratic conjugate `j`-invariants in `\QQ(\sqrt{3})` (but which are not base-changes from the quadratic subfield):: - sage: E = EllipticCurve([K([0,-3,0,1]),K([1,4,0,-1]),K([0,0,0,0]),K([-2,-16,0,4]),K([-19,-32,4,8])]) + sage: E = EllipticCurve([K([0,-3,0,1]), K([1,4,0,-1]), K([0,0,0,0]), K([-2,-16,0,4]), K([-19,-32,4,8])]) sage: flag, cert = E.is_Q_curve(certificate=True) # long time sage: flag # long time True sage: cert # long time {'CM': 0, - 'N': 2, - 'core_degs': [1, 2], - 'core_poly': x^2 - 840064*x + 1593413632, - 'r': 1, - 'rho': 1} + 'N': 2, + 'core_degs': [1, 2], + 'core_poly': x^2 - 840064*x + 1593413632, + 'r': 1, + 'rho': 1} """ from sage.schemes.elliptic_curves.Qcurves import is_Q_curve as isQ return isQ(self, maxp, certificate, verbose) @@ -3794,13 +3898,13 @@ def saturation(self, points, verbose=False, ([(-1 : 1 : 1)], 12, 0.686667083305587) sage: EK.saturation([2*P, Q], max_prime=2) ([(-1 : 1 : 1), (0 : -1 : 1)], 2, 0.152460177943144) - sage: EK.saturation([P+Q, P-Q], lower_ht_bound=.1, debug=2) + sage: EK.saturation([P + Q, P - Q], lower_ht_bound=.1, debug=2) ([(-1 : 1 : 1), (1 : 0 : 1)], 2, 0.152460177943144) - sage: EK.saturation([P+Q, 17*Q], lower_ht_bound=0.1) # long time + sage: EK.saturation([P + Q, 17*Q], lower_ht_bound=0.1) # long time ([(4 : 8 : 1), (0 : -1 : 1)], 17, 0.152460177943143) sage: R = EK(i-2,-i-3) - sage: EK.saturation([P+R, P+Q, Q+R], lower_ht_bound=0.1) + sage: EK.saturation([P + R, P + Q, Q + R], lower_ht_bound=0.1) ([(841/1369*i - 171/1369 : 41334/50653*i - 74525/50653 : 1), (4 : 8 : 1), (-1/25*i + 18/25 : -69/125*i - 58/125 : 1)], @@ -3812,12 +3916,12 @@ def saturation(self, points, verbose=False, Another number field:: sage: E = EllipticCurve('389a1') - sage: K.<a> = NumberField(x^3-x+1) + sage: K.<a> = NumberField(x^3 - x + 1) sage: EK = E.change_ring(K) sage: P = EK(-1,1); Q = EK(0,-1) - sage: EK.saturation([P+Q, P-Q], lower_ht_bound=0.1) + sage: EK.saturation([P + Q, P - Q], lower_ht_bound=0.1) ([(-1 : 1 : 1), (1 : 0 : 1)], 2, 0.152460177943144) - sage: EK.saturation([3*P, P+5*Q], lower_ht_bound=0.1) + sage: EK.saturation([3*P, P + 5*Q], lower_ht_bound=0.1) ([(-185/2209 : -119510/103823 : 1), (80041/34225 : -26714961/6331625 : 1)], 15, 0.152460177943144) @@ -3827,8 +3931,8 @@ def saturation(self, points, verbose=False, sage: K.<a> = QuadraticField(3) sage: E = EllipticCurve('37a1') sage: EK = E.change_ring(K) - sage: P = EK(0,0); Q = EK(2-a,2*a-4) - sage: EK.saturation([3*P-Q, 3*P+Q], lower_ht_bound=.01) + sage: P = EK(0,0); Q = EK(2-a, 2*a-4) + sage: EK.saturation([3*P - Q, 3*P + Q], lower_ht_bound=.01) ([(0 : 0 : 1), (1/2*a : -1/4*a - 1/4 : 1)], 6, 0.0317814530725985) The points must be linearly independent:: @@ -3861,21 +3965,21 @@ def saturation(self, points, verbose=False, sage: EK.saturation([P+Q, P-Q], lower_ht_bound=.1, debug=2) ([(-1 : 1 : 1), (1 : 0 : 1)], 2, 0.152460177943144) - sage: EK.saturation([5*P+6*Q, 5*P-3*Q], lower_ht_bound=.1) + sage: EK.saturation([5*P + 6*Q, 5*P - 3*Q], lower_ht_bound=.1) ([(-3/4 : -15/8 : 1), (159965/16129 : -67536260/2048383 : 1)], - 45, - 0.152460177943144) - sage: EK.saturation([5*P+6*Q, 5*P-3*Q], lower_ht_bound=.1, debug=2) + 45, + 0.152460177943144) + sage: EK.saturation([5*P + 6*Q, 5*P - 3*Q], lower_ht_bound=.1, debug=2) ([(-3/4 : -15/8 : 1), (159965/16129 : -67536260/2048383 : 1)], - 45, - 0.152460177943144) + 45, + 0.152460177943144) See :trac:`27387`:: - sage: K.<a> = NumberField(x^2-x-26) - sage: E = EllipticCurve([a,1-a,0,93-16*a, 3150-560*a]) + sage: K.<a> = NumberField(x^2 - x - 26) + sage: E = EllipticCurve([a, 1-a, 0, 93-16*a, 3150-560*a]) sage: P = E([65-35*a/3, (959*a-5377)/9]) - sage: E.saturation([P],one_prime=2) + sage: E.saturation([P], one_prime=2) ([(-1/4*a + 3/4 : 59/8*a - 317/8 : 1)], 2, 0.344624259712631) """ full_saturation = (max_prime == 0) and (one_prime == 0) @@ -3897,7 +4001,7 @@ def saturation(self, points, verbose=False, raise ValueError("points not linearly independent in saturation()") sat_reg = reg - from sage.rings.all import prime_range + from sage.rings.fast_arith import prime_range if full_saturation: if lower_ht_bound is None: # TODO (robertwb): verify this for rank > 1 @@ -4052,7 +4156,7 @@ def rational_points(self, **kwds): An example over a number field:: sage: E = EllipticCurve([1,0]) - sage: pts = E.rational_points(bound = 2, F = QuadraticField(-1)) + sage: pts = E.rational_points(bound=2, F=QuadraticField(-1)) sage: pts [(-a : 0 : 1), (0 : 0 : 1), (0 : 1 : 0), (a : 0 : 1)] sage: pts[0] + pts[1] diff --git a/src/sage/schemes/elliptic_curves/ell_padic_field.py b/src/sage/schemes/elliptic_curves/ell_padic_field.py index 2ac42b1b7e7..ba796d1b75b 100644 --- a/src/sage/schemes/elliptic_curves/ell_padic_field.py +++ b/src/sage/schemes/elliptic_curves/ell_padic_field.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.padics """ Elliptic curves over padic fields """ @@ -33,9 +34,10 @@ class EllipticCurve_padic_field(EllipticCurve_field, HyperellipticCurve_padic_fi EXAMPLES:: - sage: Qp=pAdicField(17) - sage: E=EllipticCurve(Qp,[2,3]); E - Elliptic Curve defined by y^2 = x^3 + (2+O(17^20))*x + (3+O(17^20)) over 17-adic Field with capped relative precision 20 + sage: Qp = pAdicField(17) + sage: E = EllipticCurve(Qp,[2,3]); E + Elliptic Curve defined by y^2 = x^3 + (2+O(17^20))*x + (3+O(17^20)) + over 17-adic Field with capped relative precision 20 sage: E == loads(dumps(E)) True """ diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 9f0c3799f36..774ad2d383a 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -32,19 +32,21 @@ An example over a number field:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) - sage: E = EllipticCurve(K,[1,0,0,0,-1]) + sage: E = EllipticCurve(K, [1,0,0,0,-1]) sage: P = E(0,i); P (0 : i : 1) sage: P.order() +Infinity - sage: 101*P-100*P == P + sage: 101*P - 100*P == P True An example over a finite field:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF((101,3)) - sage: E = EllipticCurve(K,[1,0,0,0,-1]) + sage: E = EllipticCurve(K, [1,0,0,0,-1]) sage: P = E(40*a^2 + 69*a + 84 , 58*a^2 + 73*a + 45) sage: P.order() 1032210 @@ -53,6 +55,7 @@ Arithmetic with a point over an extension of a finite field:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF((5,2)) sage: E = EllipticCurve(k,[1,0]); E Elliptic Curve defined by y^2 = x^3 + x over Finite Field in a of size 5^2 @@ -67,7 +70,7 @@ :: sage: F = Zmod(3) - sage: E = EllipticCurve(F,[1,0]); + sage: E = EllipticCurve(F, [1,0]); sage: P = E([2,1]) sage: import sys sage: n = sys.maxsize @@ -76,16 +79,17 @@ Arithmetic over `\ZZ/N\ZZ` with composite `N` is supported. When an operation tries to invert a non-invertible element, a -ZeroDivisionError is raised and a factorization of the modulus appears +:class:`ZeroDivisionError` is raised and a factorization of the modulus appears in the error message:: sage: N = 1715761513 - sage: E = EllipticCurve(Integers(N),[3,-13]) + sage: E = EllipticCurve(Integers(N), [3,-13]) sage: P = E(2,1) sage: LCM([2..60])*P Traceback (most recent call last): ... - ZeroDivisionError: Inverse of 26927 does not exist (characteristic = 1715761513 = 26927*63719) + ZeroDivisionError: Inverse of 26927 does not exist + (characteristic = 1715761513 = 26927*63719) AUTHORS: @@ -121,13 +125,15 @@ from sage.rings.padics.factory import Qp from sage.rings.padics.precision_error import PrecisionError -import sage.rings.all as rings import sage.rings.abc + +from sage.rings.infinity import Infinity as oo from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.real_mpfr import RealField +from sage.rings.real_mpfr import RR import sage.groups.generic as generic -from sage.libs.pari.all import pari, PariError -from cypari2.pari_instance import prec_words_to_bits from sage.structure.sequence import Sequence from sage.structure.richcmp import richcmp @@ -140,7 +146,11 @@ from .constructor import EllipticCurve -oo = rings.infinity # infinity +try: + from sage.libs.pari.all import pari, PariError + from cypari2.pari_instance import prec_words_to_bits +except ImportError: + PariError = () class EllipticCurvePoint(SchemeMorphism_point_projective_ring): @@ -178,23 +188,26 @@ class EllipticCurvePoint_field(SchemeMorphism_point_abelian_variety_field): sage: E = EllipticCurve([0,0,1,-1,0]) sage: S = E(QQ); S - Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field - - sage: K.<i>=NumberField(x^2+1) - sage: E=EllipticCurve(K,[0,1,0,-160,308]) - sage: P=E(26,-120) - sage: Q=E(2+12*i,-36+48*i) - sage: P.order() == Q.order() == 4 # long time (3s) + Abelian group of points on + Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) + sage: E = EllipticCurve(K, [0,1,0,-160,308]) + sage: P = E(26, -120) + sage: Q = E(2+12*i, -36+48*i) + sage: P.order() == Q.order() == 4 # long time True - sage: 2*P==2*Q + sage: 2*P == 2*Q False :: - sage: K.<t>=FractionField(PolynomialRing(QQ,'t')) - sage: E=EllipticCurve([0,0,0,0,t^2]) - sage: P=E(0,t) - sage: P,2*P,3*P + sage: K.<t> = FractionField(PolynomialRing(QQ,'t')) + sage: E = EllipticCurve([0,0,0,0,t^2]) + sage: P = E(0,t) + sage: P, 2*P, 3*P ((0 : t : 1), (0 : -t : 1), (0 : 1 : 0)) TESTS:: @@ -218,17 +231,18 @@ class EllipticCurvePoint_field(SchemeMorphism_point_abelian_variety_field): Test that the refactoring from :trac:`14711` did preserve the behaviour of domain and codomain:: - sage: E=EllipticCurve(QQ,[1,1]) - sage: P=E(0,1) + sage: E = EllipticCurve(QQ,[1,1]) + sage: P = E(0,1) sage: P.domain() Spectrum of Rational Field - sage: K.<a>=NumberField(x^2-3,'a') - sage: P=E.base_extend(K)(1,a) - sage: P.domain() + sage: K.<a> = NumberField(x^2 - 3, 'a') # needs sage.rings.number_field + sage: P = E.base_extend(K)(1,a) # needs sage.rings.number_field + sage: P.domain() # needs sage.rings.number_field Spectrum of Number Field in a with defining polynomial x^2 - 3 - sage: P.codomain() - Elliptic Curve defined by y^2 = x^3 + x + 1 over Number Field in a with defining polynomial x^2 - 3 - sage: P.codomain() == P.curve() + sage: P.codomain() # needs sage.rings.number_field + Elliptic Curve defined by y^2 = x^3 + x + 1 + over Number Field in a with defining polynomial x^2 - 3 + sage: P.codomain() == P.curve() # needs sage.rings.number_field True """ def __init__(self, curve, v, check=True): @@ -431,16 +445,18 @@ def scheme(self): EXAMPLES:: - sage: E=EllipticCurve(QQ,[1,1]) - sage: P=E(0,1) + sage: E = EllipticCurve(QQ,[1,1]) + sage: P = E(0,1) sage: P.scheme() Elliptic Curve defined by y^2 = x^3 + x + 1 over Rational Field sage: P.scheme() == P.curve() True - sage: K.<a>=NumberField(x^2-3,'a') - sage: P=E.base_extend(K)(1,a) - sage: P.scheme() - Elliptic Curve defined by y^2 = x^3 + x + 1 over Number Field in a with defining polynomial x^2 - 3 + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 3,'a') # needs sage.rings.number_field + sage: P = E.base_extend(K)(1, a) # needs sage.rings.number_field + sage: P.scheme() # needs sage.rings.number_field + Elliptic Curve defined by y^2 = x^3 + x + 1 + over Number Field in a with defining polynomial x^2 - 3 """ # The following text is just not true: it applies to the class # EllipticCurvePoint, which appears to be never used, but does @@ -459,7 +475,7 @@ def order(self): Return the order of this point on the elliptic curve. If the point is zero, returns 1, otherwise raise a - NotImplementedError. + :class:`NotImplementedError`. For curves over number fields and finite fields, see below. @@ -469,13 +485,14 @@ def order(self): EXAMPLES:: - sage: K.<t>=FractionField(PolynomialRing(QQ,'t')) - sage: E=EllipticCurve([0,0,0,-t^2,0]) - sage: P=E(t,0) + sage: K.<t> = FractionField(PolynomialRing(QQ,'t')) + sage: E = EllipticCurve([0, 0, 0, -t^2, 0]) + sage: P = E(t,0) sage: P.order() Traceback (most recent call last): ... - NotImplementedError: Computation of order of a point not implemented over general fields. + NotImplementedError: Computation of order of a point not implemented + over general fields. sage: E(0).additive_order() 1 sage: E(0).order() == 1 @@ -523,8 +540,6 @@ def __bool__(self): """ return bool(self[2]) - - def has_finite_order(self): """ Return ``True`` if this point has finite additive order as an @@ -535,16 +550,17 @@ def has_finite_order(self): EXAMPLES:: - sage: K.<t>=FractionField(PolynomialRing(QQ,'t')) - sage: E=EllipticCurve([0,0,0,-t^2,0]) + sage: K.<t> = FractionField(PolynomialRing(QQ,'t')) + sage: E = EllipticCurve([0, 0, 0, -t^2, 0]) sage: P = E(0) sage: P.has_finite_order() True - sage: P=E(t,0) + sage: P = E(t,0) sage: P.has_finite_order() Traceback (most recent call last): ... - NotImplementedError: Computation of order of a point not implemented over general fields. + NotImplementedError: Computation of order of a point not implemented + over general fields. sage: (2*P).is_zero() True """ @@ -564,12 +580,12 @@ def has_infinite_order(self): EXAMPLES:: - sage: K.<t>=FractionField(PolynomialRing(QQ,'t')) - sage: E=EllipticCurve([0,0,0,-t^2,0]) + sage: K.<t> = FractionField(PolynomialRing(QQ,'t')) + sage: E = EllipticCurve([0, 0, 0, -t^2, 0]) sage: P = E(0) sage: P.has_infinite_order() False - sage: P=E(t,0) + sage: P = E(t,0) sage: P.has_infinite_order() Traceback (most recent call last): ... @@ -594,7 +610,7 @@ def plot(self, **args): sage: E = EllipticCurve('389a') sage: P = E([-1,1]) - sage: P.plot(pointsize=30, rgbcolor=(1,0,0)) + sage: P.plot(pointsize=30, rgbcolor=(1,0,0)) # needs sage.plot Graphics object consisting of 1 graphics primitive """ from sage.plot.point import point @@ -628,7 +644,7 @@ def _add_(self, right): Checks that :trac:`15964` is fixed:: sage: N = 1715761513 - sage: E = EllipticCurve(Integers(N),[3,-13]) + sage: E = EllipticCurve(Integers(N), [3,-13]) sage: P = E(2,1) sage: LCM([2..60])*P Traceback (most recent call last): @@ -637,7 +653,7 @@ def _add_(self, right): (characteristic = 1715761513 = 26927*63719) sage: N = 35 - sage: E = EllipticCurve(Integers(N),[5,1]) + sage: E = EllipticCurve(Integers(N), [5,1]) sage: P = E(0,1) sage: 4*P Traceback (most recent call last): @@ -731,8 +747,8 @@ def __neg__(self): sage: [type(c) for c in -EllipticCurve('37a1').gen(0)] [<... 'sage.rings.rational.Rational'>, - <... 'sage.rings.rational.Rational'>, - <... 'sage.rings.rational.Rational'>] + <... 'sage.rings.rational.Rational'>, + <... 'sage.rings.rational.Rational'>] """ if self.is_zero(): return self @@ -743,7 +759,7 @@ def __neg__(self): def xy(self): """ Return the `x` and `y` coordinates of this point, as a 2-tuple. - If this is the point at infinity a ZeroDivisionError is raised. + If this is the point at infinity, a :class:`ZeroDivisionError` is raised. EXAMPLES:: @@ -795,7 +811,7 @@ def is_divisible_by(self, m): A finite field example:: - sage: E = EllipticCurve(GF(101),[23,34]) + sage: E = EllipticCurve(GF(101), [23,34]) sage: E.cardinality().factor() 2 * 53 sage: Set([T.order() for T in E.points()]) @@ -809,6 +825,7 @@ def is_divisible_by(self, m): This shows that the bug reported at :trac:`10076` is fixed:: + sage: # needs sage.rings.number_field sage: K = QuadraticField(8,'a') sage: E = EllipticCurve([K(0),0,0,-1,0]) sage: P = E([-1,0]) @@ -820,9 +837,10 @@ def is_divisible_by(self, m): Note that it is not sufficient to test that ``self.division_points(m,poly_only=True)`` has roots:: - sage: P.division_points(2, poly_only=True).roots() + sage: P.division_points(2, poly_only=True).roots() # needs sage.rings.number_field [(1/2*a - 1, 1), (-1/2*a - 1, 1)] + sage: # needs sage.rings.number_field sage: tor = E.torsion_points(); len(tor) 8 sage: [T.order() for T in tor] @@ -885,7 +903,7 @@ def is_divisible_by(self, m): def division_points(self, m, poly_only=False): r""" - Return a list of all points `Q` such that `mQ=P` where `P` = self. + Return a list of all points `Q` such that `mQ=P` where `P` = ``self``. Only points on the elliptic curve containing self and defined over the base field are included. @@ -896,7 +914,7 @@ def division_points(self, m, poly_only=False): - ``poly_only`` -- bool (default: False); if True return polynomial whose roots give all possible `x`-coordinates of - `m`-th roots of self. + `m`-th roots of ``self``. OUTPUT: @@ -926,9 +944,10 @@ def division_points(self, m, poly_only=False): We create a curve over a non-prime finite field with group of order `18`:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF((5,2)) sage: E = EllipticCurve(k, [1,2+a,3,4*a,2]) - sage: P = E([3,3*a+4]) + sage: P = E([3, 3*a+4]) sage: factor(E.order()) 2 * 3^2 sage: P.order() @@ -937,32 +956,35 @@ def division_points(self, m, poly_only=False): We find the `1`-division points as a consistency check -- there is just one, of course:: - sage: P.division_points(1) + sage: P.division_points(1) # needs sage.rings.finite_rings [(3 : 3*a + 4 : 1)] The point `P` has order coprime to 2 but divisible by 3, so:: - sage: P.division_points(2) + sage: P.division_points(2) # needs sage.rings.finite_rings [(2*a + 1 : 3*a + 4 : 1), (3*a + 1 : a : 1)] We check that each of the 2-division points works as claimed:: - sage: [2*Q for Q in P.division_points(2)] + sage: [2*Q for Q in P.division_points(2)] # needs sage.rings.finite_rings [(3 : 3*a + 4 : 1), (3 : 3*a + 4 : 1)] Some other checks:: - sage: P.division_points(3) + sage: P.division_points(3) # needs sage.rings.finite_rings [] - sage: P.division_points(4) + sage: P.division_points(4) # needs sage.rings.finite_rings [(0 : 3*a + 2 : 1), (1 : 0 : 1)] - sage: P.division_points(5) + sage: P.division_points(5) # needs sage.rings.finite_rings [(1 : 1 : 1)] An example over a number field (see :trac:`3383`):: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('19a1') - sage: K.<t> = NumberField(x^9-3*x^8-4*x^7+16*x^6-3*x^5-21*x^4+5*x^3+7*x^2-7*x+1) + sage: x = polygen(ZZ, 'x') + sage: K.<t> = NumberField(x^9 - 3*x^8 - 4*x^7 + 16*x^6 - 3*x^5 + ....: - 21*x^4 + 5*x^3 + 7*x^2 - 7*x + 1) sage: EK = E.base_extend(K) sage: E(0).division_points(3) [(0 : 1 : 0), (5 : -10 : 1), (5 : 9 : 1)] @@ -977,6 +999,7 @@ def division_points(self, m, poly_only=False): Check that :trac:`24844` is fixed:: + sage: # needs sage.rings.finite_rings sage: p = next_prime(1000000) sage: E = EllipticCurve(GF(p), 123, 456) sage: pts = E(0).division_points(3) @@ -993,7 +1016,7 @@ def division_points(self, m, poly_only=False): sage: P = E(-1,0) sage: P.order() +Infinity - sage: pts = P.division_points(3); len(pts) + sage: pts = P.division_points(3); len(pts) 1 sage: [(Q,Q._order) for Q in pts] [((0 : -1 : 1), +Infinity)] @@ -1005,17 +1028,17 @@ def division_points(self, m, poly_only=False): sage: E = EllipticCurve([1, 0, 1, -19, 26]) sage: [(Q,Q._order) for Q in E(0).division_points(12)] [((-5 : 2 : 1), 2), - ((-2 : -7 : 1), 6), - ((-2 : 8 : 1), 6), - ((0 : 1 : 0), 1), - ((1 : -4 : 1), 6), - ((1 : 2 : 1), 6), - ((7/4 : -11/8 : 1), 2), - ((3 : -2 : 1), 2), - ((4 : -7 : 1), 3), - ((4 : 2 : 1), 3), - ((13 : -52 : 1), 6), - ((13 : 38 : 1), 6)] + ((-2 : -7 : 1), 6), + ((-2 : 8 : 1), 6), + ((0 : 1 : 0), 1), + ((1 : -4 : 1), 6), + ((1 : 2 : 1), 6), + ((7/4 : -11/8 : 1), 2), + ((3 : -2 : 1), 2), + ((4 : -7 : 1), 3), + ((4 : 2 : 1), 3), + ((13 : -52 : 1), 6), + ((13 : 38 : 1), 6)] sage: P = E(4,-7) sage: P.order() 3 @@ -1175,20 +1198,26 @@ def _divide_out(self, p): pts = Q.division_points(p) return (Q, k) - def set_order(self, value, *, check=True): + def set_order(self, value=None, *, multiple=None, check=True): r""" - Set the value of self._order to value. + Set the cached order of this point (i.e., the value of + ``self._order``) to the given ``value``. - Use this when you know a priori the order of this point to avoid a - potentially expensive order calculation. + Alternatively, when ``multiple`` is given, this method will + first run :func:`~sage.groups.generic.order_from_multiple` + to determine the exact order from the given multiple of the + point order, then cache the result. + + Use this when you know a priori the order of this point, or + a multiple of the order, to avoid a potentially expensive + order calculation. INPUT: - ``value`` -- positive integer + - ``multiple`` -- positive integer; mutually exclusive with ``value`` - OUTPUT: - - ``None`` + OUTPUT: ``None`` EXAMPLES: @@ -1201,6 +1230,10 @@ def set_order(self, value, *, check=True): sage: G.set_order(2) sage: 2*G (0 : 1 : 0) + sage: G = E(0, 6) + sage: G.set_order(multiple=12) + sage: G._order + 3 We now give a more interesting case, the NIST-P521 curve. Its order is too big to calculate with Sage, and takes a long time @@ -1208,9 +1241,10 @@ def set_order(self, value, *, check=True): :: + sage: # needs sage.rings.finite_rings sage: p = 2^521 - 1 sage: prev_proof_state = proof.arithmetic() - sage: proof.arithmetic(False) # turn off primality checking + sage: proof.arithmetic(False) # turn off primality checking sage: F = GF(p) sage: A = p - 3 sage: B = 1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984 @@ -1222,8 +1256,33 @@ def set_order(self, value, *, check=True): (0 : 1 : 0) sage: proof.arithmetic(prev_proof_state) # restore state - It is an error to pass a `value` equal to `0`:: + Using ``.set_order()`` with a ``multiple=`` argument can + be used to compute a point's order *significantly* faster + than calling :meth:`order` if the point is already known + to be `m`-torsion:: + + sage: F.<a> = GF((10007, 23)) + sage: E = EllipticCurve(F, [9,9]) + sage: n = E.order() + sage: m = 5 * 47 * 139 * 1427 * 2027 * 4831 * 275449 * 29523031 + sage: assert m.divides(n) + sage: P = n/m * E.lift_x(6747+a) + sage: assert m * P == 0 + sage: P.set_order(multiple=m) # compute exact order + sage: factor(m // P.order()) # order is now cached + 47 * 139 + + The algorithm used internally for this functionality is + :meth:`~sage.groups.generic.order_from_multiple`. + Indeed, simply calling :meth:`order` on ``P`` would take + much longer since factoring ``n`` is fairly expensive:: + + sage: n == m * 6670822796985115651 * 441770032618665681677 * 9289973478285634606114927 + True + + It is an error to pass a ``value`` equal to `0`:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12 sage: G = E.random_point() sage: G.set_order(0) @@ -1246,9 +1305,8 @@ def set_order(self, value, *, check=True): ... ValueError: Value 11 illegal: 11 * (5 : 0 : 1) is not the identity - However, set_order can be fooled, though it's not likely in "real cases - of interest". For instance, the order can be set to a multiple the - actual order:: + However, ``set_order`` can be fooled. For instance, the order + can be set to a multiple the actual order:: sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12 sage: G = E(5, 0) # G has order 2 @@ -1256,10 +1314,44 @@ def set_order(self, value, *, check=True): sage: G.order() 8 + TESTS: + + Check that some invalid inputs are caught:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: P = E.lift_x(11) + sage: P.set_order(17, multiple=119) + Traceback (most recent call last): + ... + ValueError: cannot pass both value and multiple + sage: P.set_order(17) + sage: P.set_order(multiple=119+1) + Traceback (most recent call last): + ... + ValueError: previously cached order 17 does not divide given multiple 120 + sage: P.set_order(119) + Traceback (most recent call last): + ... + ValueError: value 119 contradicts previously cached order 17 + AUTHORS: - - Mariah Lenox (2011-02-16) + - Mariah Lenox (2011-02-16) + - Lorenz Panny (2022): add ``multiple=`` option """ + if multiple is not None: + if value is not None: + raise ValueError('cannot pass both value and multiple') + + if hasattr(self, '_order'): # already known + if check and not self._order.divides(multiple): + raise ValueError(f'previously cached order {self._order} does not divide given multiple {multiple}') + return + + from sage.groups.generic import order_from_multiple + value = order_from_multiple(self, multiple, check=check) + check = False + value = Integer(value) if check: @@ -1272,6 +1364,9 @@ def set_order(self, value, *, check=True): raise ValueError('Value %s illegal: outside max Hasse bound' % value) if value * self != E(0): raise ValueError('Value %s illegal: %s * %s is not the identity' % (value, value, self)) + if hasattr(self, '_order') and self._order != value: # already known + raise ValueError(f'value {value} contradicts previously cached order {self._order}') + self._order = value # ############################# end ################################ @@ -1292,8 +1387,9 @@ def _line_(self, R, Q): EXAMPLES:: - sage: F.<a>=GF((2,5)) - sage: E=EllipticCurve(F,[0,0,1,1,1]) + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF((2,5)) + sage: E = EllipticCurve(F,[0,0,1,1,1]) sage: P = E(a^4 + 1, a^3) sage: Q = E(a^4, a^4 + a^3) sage: O = E(0) @@ -1312,7 +1408,7 @@ def _line_(self, R, Q): See :trac:`7116`:: - sage: P._line_ (Q,O) + sage: P._line_ (Q,O) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: Q must be nonzero. @@ -1365,19 +1461,21 @@ def _miller_(self, Q, n): OUTPUT: - An element in the base field self.curve().base_field() - A ValueError is raised if `Q` is zero. + An element in the base field ``self.curve().base_field()``. + A :class:`ValueError` is raised if `Q` is zero. EXAMPLES:: - sage: F.<a>=GF((2,5)) - sage: E=EllipticCurve(F,[0,0,1,1,1]) + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF((2,5)) + sage: E = EllipticCurve(F, [0,0,1,1,1]) sage: P = E(a^4 + 1, a^3) - sage: Fx.<b>=GF((2,(4*5))) - sage: Ex=EllipticCurve(Fx,[0,0,1,1,1]) - sage: phi=Hom(F,Fx)(F.gen().minpoly().roots(Fx)[0][0]) - sage: Px=Ex(phi(P.xy()[0]),phi(P.xy()[1])) - sage: Qx = Ex(b^19 + b^18 + b^16 + b^12 + b^10 + b^9 + b^8 + b^5 + b^3 + 1, b^18 + b^13 + b^10 + b^8 + b^5 + b^4 + b^3 + b) + sage: Fx.<b> = GF((2,(4*5))) + sage: Ex = EllipticCurve(Fx, [0,0,1,1,1]) + sage: phi = Hom(F,Fx)(F.gen().minpoly().roots(Fx)[0][0]) + sage: Px = Ex(phi(P.xy()[0]), phi(P.xy()[1])) + sage: Qx = Ex(b^19 + b^18 + b^16 + b^12 + b^10 + b^9 + b^8 + b^5 + b^3 + 1, + ....: b^18 + b^13 + b^10 + b^8 + b^5 + b^4 + b^3 + b) sage: Px._miller_(Qx,41) == b^17 + b^13 + b^12 + b^9 + b^8 + b^6 + b^4 + 1 True sage: Qx._miller_(Px,41) == b^13 + b^10 + b^8 + b^7 + b^6 + b^5 @@ -1389,27 +1487,30 @@ def _miller_(self, Q, n): An example of even order:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF((19,4)) - sage: E = EllipticCurve(F,[-1,0]) + sage: E = EllipticCurve(F, [-1,0]) sage: P = E(15*a^3 + 17*a^2 + 14*a + 13,16*a^3 + 7*a^2 + a + 18) sage: Q = E(10*a^3 + 16*a^2 + 4*a + 2, 6*a^3 + 4*a^2 + 3*a + 2) - sage: x=P.weil_pairing(Q,360) + sage: x = P.weil_pairing(Q, 360) sage: x^360 == F(1) True You can use the _miller_ function on linearly dependent points, but with the risk of a dividing with zero:: - sage: Px._miller_(2*Px,41) + sage: Px._miller_(2*Px, 41) # needs sage.rings.finite_rings Traceback (most recent call last): ... ZeroDivisionError: division by zero in finite field A small example of embedding degree 6:: + sage: # needs sage.rings.finite_rings sage: q = 401; F = GF(q); a = 146; b = 400; k = 6 sage: E = EllipticCurve([F(a), F(b)]) - sage: R.<x> = F[]; K.<a> = GF(q^k, modulus=x^6 + 4*x^4 + 115*x^3 + 81*x^2 + 51*x + 3) + sage: R.<x> = F[] + sage: K.<a> = GF(q^k, modulus=x^6 + 4*x^4 + 115*x^3 + 81*x^2 + 51*x + 3) sage: EK = E.base_extend(K) sage: P = E([F(338), F(227)]) sage: Q_x = 333*a^5 + 391*a^4 + 160*a^3 + 335*a^2 + 71*a + 93 @@ -1474,14 +1575,15 @@ def _miller_(self, Q, n): the curve is negative, so it should exercise the `n<0` case in the code:: - sage: p = 2017; A = 1; B = 30; r = 29; t = -70; k = 7; + sage: # needs sage.rings.finite_rings + sage: p = 2017; A = 1; B = 30; r = 29; t = -70; k = 7 sage: F = GF(p); R.<x> = F[] sage: E = EllipticCurve([F(A), F(B)]); P = E(369, 716) sage: K.<a> = GF(p^k, modulus=x^k+2); EK = E.base_extend(K) sage: Qx = 1226*a^6 + 1778*a^5 + 660*a^4 + 1791*a^3 + 1750*a^2 + 867*a + 770 sage: Qy = 1764*a^6 + 198*a^5 + 1206*a^4 + 406*a^3 + 1200*a^2 + 273*a + 1712 sage: Q = EK(Qx, Qy) - sage: Q._miller_(P, t-1) + sage: Q._miller_(P, t - 1) 1311*a^6 + 1362*a^5 + 1177*a^4 + 807*a^3 + 1331*a^2 + 1530*a + 1931 ALGORITHM: @@ -1549,53 +1651,59 @@ def weil_pairing(self, Q, n, algorithm=None): EXAMPLES:: - sage: F.<a>=GF((2,5)) - sage: E=EllipticCurve(F,[0,0,1,1,1]) + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF((2,5)) + sage: E = EllipticCurve(F, [0,0,1,1,1]) sage: P = E(a^4 + 1, a^3) - sage: Fx.<b>=GF((2,4*5)) - sage: Ex=EllipticCurve(Fx,[0,0,1,1,1]) - sage: phi=Hom(F,Fx)(F.gen().minpoly().roots(Fx)[0][0]) - sage: Px=Ex(phi(P.xy()[0]),phi(P.xy()[1])) + sage: Fx.<b> = GF((2, 4*5)) + sage: Ex = EllipticCurve(Fx, [0,0,1,1,1]) + sage: phi = Hom(F, Fx)(F.gen().minpoly().roots(Fx)[0][0]) + sage: Px = Ex(phi(P.xy()[0]), phi(P.xy()[1])) sage: O = Ex(0) - sage: Qx = Ex(b^19 + b^18 + b^16 + b^12 + b^10 + b^9 + b^8 + b^5 + b^3 + 1, b^18 + b^13 + b^10 + b^8 + b^5 + b^4 + b^3 + b) - sage: Px.weil_pairing(Qx,41) == b^19 + b^15 + b^9 + b^8 + b^6 + b^4 + b^3 + b^2 + 1 + sage: Qx = Ex(b^19 + b^18 + b^16 + b^12 + b^10 + b^9 + b^8 + b^5 + b^3 + 1, + ....: b^18 + b^13 + b^10 + b^8 + b^5 + b^4 + b^3 + b) + sage: Px.weil_pairing(Qx, 41) == b^19 + b^15 + b^9 + b^8 + b^6 + b^4 + b^3 + b^2 + 1 True - sage: Px.weil_pairing(17*Px,41) == Fx(1) + sage: Px.weil_pairing(17*Px, 41) == Fx(1) True - sage: Px.weil_pairing(O,41) == Fx(1) + sage: Px.weil_pairing(O, 41) == Fx(1) True An error is raised if either point is not `n`-torsion:: - sage: Px.weil_pairing(O,40) + sage: Px.weil_pairing(O, 40) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: points must both be n-torsion A larger example (see :trac:`4964`):: - sage: P,Q = EllipticCurve(GF((19,4),'a'),[-1,0]).gens() + sage: # needs sage.rings.finite_rings + sage: P, Q = EllipticCurve(GF((19,4),'a'), [-1,0]).gens() sage: P.order(), Q.order() (360, 360) - sage: z = P.weil_pairing(Q,360) + sage: z = P.weil_pairing(Q, 360) sage: z.multiplicative_order() 360 An example over a number field:: - sage: P,Q = EllipticCurve('11a1').change_ring(CyclotomicField(5)).torsion_subgroup().gens() - sage: P,Q = (P.element(), Q.element()) - sage: (P.order(),Q.order()) + sage: # needs sage.rings.number_field + sage: E = EllipticCurve('11a1').change_ring(CyclotomicField(5)) + sage: P, Q = E.torsion_subgroup().gens() + sage: P, Q = (P.element(), Q.element()) + sage: (P.order(), Q.order()) (5, 5) - sage: P.weil_pairing(Q,5) + sage: P.weil_pairing(Q, 5) zeta5^2 - sage: Q.weil_pairing(P,5) + sage: Q.weil_pairing(P, 5) zeta5^3 TESTS: Check that the original Sage implementation still works:: + sage: # needs sage.rings.finite_rings sage: GF(65537^2).inject_variables() Defining z2 sage: E = EllipticCurve(GF(65537^2), [0,1]) @@ -1606,7 +1714,7 @@ def weil_pairing(self, Q, n, algorithm=None): Passing an unknown ``algorithm=`` argument should fail:: - sage: P.weil_pairing(Q, 7282, algorithm='_invalid_') + sage: P.weil_pairing(Q, 7282, algorithm='_invalid_') # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: unknown algorithm @@ -1618,7 +1726,7 @@ def weil_pairing(self, Q, n, algorithm=None): - For ``algorithm='sage'``: Implemented using Proposition 8 in [Mil2004]_. The value 1 is returned for linearly dependent input points. This condition - is caught via a DivisionByZeroError, since the use of a + is caught via a :class:`ZeroDivisionError`, since the use of a discrete logarithm test for linear dependence is much too slow for large `n`. @@ -1718,7 +1826,7 @@ def tate_pairing(self, Q, n, k, q=None): OUTPUT: - An `n`'th root of unity in the base field self.curve().base_field() + An `n`'th root of unity in the base field ``self.curve().base_field()`` EXAMPLES: @@ -1736,13 +1844,14 @@ def tate_pairing(self, Q, n, k, q=None): sage: P.tate_pairing(Q, n, k) 1 sage: set_random_seed(35) - sage: P.tate_pairing(P,n,k) + sage: P.tate_pairing(P, n, k) 1 - We now let Q be a point on the same curve as above, but defined over + We now let `Q` be a point on the same curve as above, but defined over the pairing extension field, and we also demonstrate the bilinearity of the pairing:: + sage: # needs sage.rings.finite_rings sage: K.<a> = GF((p,k)) sage: EK = E.base_extend(K); P = EK(P) sage: Qx = 69*a^5 + 96*a^4 + 22*a^3 + 86*a^2 + 6*a + 35 @@ -1751,6 +1860,7 @@ def tate_pairing(self, Q, n, k, q=None): Multiply by cofactor so Q has order n:: + sage: # needs sage.rings.finite_rings sage: h = 551269674; Q = h*Q sage: P = EK(P); P.tate_pairing(Q, n, k) 24*a^5 + 34*a^4 + 3*a^3 + 69*a^2 + 86*a + 45 @@ -1766,6 +1876,7 @@ def tate_pairing(self, Q, n, k, q=None): Here is an example of using the Tate pairing to compute the Weil pairing (using the same data as above):: + sage: # needs sage.rings.finite_rings sage: e = Integer((p^k-1)/n); e 62844857712 sage: P.weil_pairing(Q, n)^e @@ -1780,18 +1891,21 @@ def tate_pairing(self, Q, n, k, q=None): An example where we have to pass the base field size (and we again have agreement with the Weil pairing):: - sage: F.<a>=GF((2,5)) - sage: E=EllipticCurve(F,[0,0,1,1,1]) + sage: # needs sage.rings.finite_rings + sage: F.<a> = GF((2,5)) + sage: E = EllipticCurve(F, [0,0,1,1,1]) sage: P = E(a^4 + 1, a^3) - sage: Fx.<b>=GF((2,4*5)) - sage: Ex=EllipticCurve(Fx,[0,0,1,1,1]) - sage: phi=Hom(F,Fx)(F.gen().minpoly().roots(Fx)[0][0]) - sage: Px=Ex(phi(P.xy()[0]),phi(P.xy()[1])) - sage: Qx = Ex(b^19+b^18+b^16+b^12+b^10+b^9+b^8+b^5+b^3+1, b^18+b^13+b^10+b^8+b^5+b^4+b^3+b) + sage: Fx.<b> = GF((2,4*5)) + sage: Ex = EllipticCurve(Fx,[0,0,1,1,1]) + sage: phi = Hom(F, Fx)(F.gen().minpoly().roots(Fx)[0][0]) + sage: Px = Ex(phi(P.xy()[0]), phi(P.xy()[1])) + sage: Qx = Ex(b^19 + b^18 + b^16 + b^12 + b^10 + b^9 + b^8 + b^5 + b^3 + 1, + ....: b^18 + b^13 + b^10 + b^8 + b^5 + b^4 + b^3 + b) sage: Px.tate_pairing(Qx, n=41, k=4) Traceback (most recent call last): ... - ValueError: Unexpected field degree: set keyword argument q equal to the size of the base field (big field is GF(q^4)). + ValueError: Unexpected field degree: set keyword argument q equal to + the size of the base field (big field is GF(q^4)). sage: num = Px.tate_pairing(Qx, n=41, k=4, q=32); num b^19 + b^14 + b^13 + b^12 + b^6 + b^4 + b^3 sage: den = Qx.tate_pairing(Px, n=41, k=4, q=32); den @@ -1807,7 +1921,7 @@ def tate_pairing(self, Q, n, k, q=None): exponentiation. It does not do anything fancy. In the case that there is an issue with `Q` being on one of the lines generated in the `r*P` calculation, `Q` is offset by a random - point `R` and P.tate_pairing(Q+R,n,k)/P.tate_pairing(R,n,k) + point `R` and ``P.tate_pairing(Q+R,n,k)/P.tate_pairing(R,n,k)`` is returned. AUTHORS: @@ -1848,7 +1962,7 @@ def tate_pairing(self, Q, n, k, q=None): def ate_pairing(self, Q, n, k, t, q=None): r""" - Return ate pairing of `n`-torsion points `P=self` and `Q`. + Return ate pairing of `n`-torsion points `P` (``=self``) and `Q`. Also known as the `n`-th modified ate pairing. `P` is `GF(q)`-rational, and `Q` must be an element of `Ker(\pi-p)`, where `\pi` is the @@ -1856,8 +1970,8 @@ def ate_pairing(self, Q, n, k, t, q=None): INPUT: - - ``P=self`` -- a point of order `n`, in `ker(\pi-1)`, where - `\pi` is the `q`-Frobenius map (e.g., `P` is `q-rational`). + - `P` (``=self``) -- a point of order `n`, in `ker(\pi-1)`, where + `\pi` is the `q`-Frobenius map (e.g., `P` is `q`-rational). - ``Q`` -- a point of order `n` in `ker(\pi-q)` @@ -1879,6 +1993,7 @@ def ate_pairing(self, Q, n, k, t, q=None): An example with embedding degree 6:: + sage: # needs sage.rings.finite_rings sage: p = 7549; A = 0; B = 1; n = 157; k = 6; t = 14 sage: F = GF(p); E = EllipticCurve(F, [A, B]) sage: R.<x> = F[]; K.<a> = GF((p,k), modulus=x^k+2) @@ -1894,6 +2009,7 @@ def ate_pairing(self, Q, n, k, t, q=None): Another example with embedding degree 7 and positive trace:: + sage: # needs sage.rings.finite_rings sage: p = 2213; A = 1; B = 49; n = 1093; k = 7; t = 28 sage: F = GF(p); E = EllipticCurve(F, [A, B]) sage: R.<x> = F[]; K.<a> = GF((p,k), modulus=x^k+2) @@ -1912,6 +2028,7 @@ def ate_pairing(self, Q, n, k, t, q=None): Another example with embedding degree 7 and negative trace:: + sage: # needs sage.rings.finite_rings sage: p = 2017; A = 1; B = 30; n = 29; k = 7; t = -70 sage: F = GF(p); E = EllipticCurve(F, [A, B]) sage: R.<x> = F[]; K.<a> = GF((p,k), modulus=x^k+2) @@ -1931,6 +2048,7 @@ def ate_pairing(self, Q, n, k, t, q=None): Using the same data, we show that the ate pairing is a power of the Tate pairing (see [HSV2006]_ end of section 3.1):: + sage: # needs sage.rings.finite_rings sage: c = (k*p^(k-1)).mod(n); T = t - 1 sage: N = gcd(T^k - 1, p^k - 1) sage: s = Integer(N/n) @@ -1944,22 +2062,26 @@ def ate_pairing(self, Q, n, k, t, q=None): `F`-rational, (it is the homomorphic image of an `F`-rational point) it is nonetheless in `ker(\pi-1)`, and so is a legitimate input:: - sage: q = 2^5; F.<a>=GF(q) + sage: # needs sage.rings.finite_rings + sage: q = 2^5; F.<a> = GF(q) sage: n = 41; k = 4; t = -8 - sage: E=EllipticCurve(F,[0,0,1,1,1]) + sage: E = EllipticCurve(F,[0,0,1,1,1]) sage: P = E(a^4 + 1, a^3) - sage: Fx.<b>=GF(q^k) - sage: Ex=EllipticCurve(Fx,[0,0,1,1,1]) - sage: phi=Hom(F,Fx)(F.gen().minpoly().roots(Fx)[0][0]) - sage: Px=Ex(phi(P.xy()[0]),phi(P.xy()[1])) - sage: Qx = Ex(b^19+b^18+b^16+b^12+b^10+b^9+b^8+b^5+b^3+1, b^18+b^13+b^10+b^8+b^5+b^4+b^3+b) + sage: Fx.<b> = GF(q^k) + sage: Ex = EllipticCurve(Fx, [0,0,1,1,1]) + sage: phi = Hom(F, Fx)(F.gen().minpoly().roots(Fx)[0][0]) + sage: Px = Ex(phi(P.xy()[0]), phi(P.xy()[1])) + sage: Qx = Ex(b^19+b^18+b^16+b^12+b^10+b^9+b^8+b^5+b^3+1, + ....: b^18+b^13+b^10+b^8+b^5+b^4+b^3+b) sage: Qx = Ex(Qx[0]^q, Qx[1]^q) - Qx # ensure Qx is in ker(pi - q) sage: Px.ate_pairing(Qx, n, k, t) Traceback (most recent call last): ... - ValueError: Unexpected field degree: set keyword argument q equal to the size of the base field (big field is GF(q^4)). + ValueError: Unexpected field degree: set keyword argument q equal to + the size of the base field (big field is GF(q^4)). sage: Px.ate_pairing(Qx, n, k, t, q) - b^19 + b^18 + b^17 + b^16 + b^15 + b^14 + b^13 + b^12 + b^11 + b^9 + b^8 + b^5 + b^4 + b^2 + b + 1 + b^19 + b^18 + b^17 + b^16 + b^15 + b^14 + b^13 + b^12 + + b^11 + b^9 + b^8 + b^5 + b^4 + b^2 + b + 1 sage: s = Integer(randrange(1, n)) sage: (s*Px).ate_pairing(Qx, n, k, t, q) == Px.ate_pairing(s*Qx, n, k, t, q) True @@ -1976,6 +2098,7 @@ def ate_pairing(self, Q, n, k, t, q=None): It is an error if `Q` is not in the kernel of `\pi - p`, where `\pi` is the Frobenius automorphism:: + sage: # needs sage.rings.finite_rings sage: p = 29; A = 1; B = 0; n = 5; k = 2; t = 10 sage: F = GF(p); R.<x> = F[] sage: E = EllipticCurve(F, [A, B]); @@ -1988,6 +2111,7 @@ def ate_pairing(self, Q, n, k, t, q=None): It is also an error if `P` is not in the kernel os `\pi - 1`:: + sage: # needs sage.rings.finite_rings sage: p = 29; A = 1; B = 0; n = 5; k = 2; t = 10 sage: F = GF(p); R.<x> = F[] sage: E = EllipticCurve(F, [A, B]); @@ -2053,7 +2177,7 @@ class EllipticCurvePoint_number_field(EllipticCurvePoint_field): A point on an elliptic curve over a number field. Most of the functionality is derived from the parent class - ``EllipticCurvePoint_field``. In addition we have support for + :class:`EllipticCurvePoint_field`. In addition we have support for orders, heights, reduction modulo primes, and elliptic logarithms. EXAMPLES:: @@ -2079,7 +2203,8 @@ class EllipticCurvePoint_number_field(EllipticCurvePoint_field): sage: E = EllipticCurve([0,0,1,-1,0]) sage: S = E(QQ); S - Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + Abelian group of points on + Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field TESTS:: @@ -2220,7 +2345,7 @@ def has_infinite_order(self): def is_on_identity_component(self, embedding=None): r""" - Returns True iff this point is on the identity component of + Return True iff this point is on the identity component of its curve with respect to a given (real or complex) embedding. INPUT: @@ -2241,25 +2366,28 @@ def is_on_identity_component(self, embedding=None): For `K=\QQ` there is no need to specify an embedding:: - sage: E=EllipticCurve('5077a1') + sage: E = EllipticCurve('5077a1') sage: [E.lift_x(x).is_on_identity_component() for x in srange(-3,5)] [False, False, False, False, False, True, True, True] An example over a field with two real embeddings:: + sage: # needs sage.rings.number_field sage: L.<a> = QuadraticField(2) - sage: E=EllipticCurve(L,[0,1,0,a,a]) - sage: P=E(-1,0) + sage: E = EllipticCurve(L, [0,1,0,a,a]) + sage: P = E(-1,0) sage: [P.is_on_identity_component(e) for e in L.embeddings(RR)] [False, True] We can check this as follows:: - sage: [e(E.discriminant())>0 for e in L.embeddings(RR)] + sage: # needs sage.rings.number_field + sage: [e(E.discriminant()) > 0 for e in L.embeddings(RR)] [True, False] sage: e = L.embeddings(RR)[0] - sage: E1 = EllipticCurve(RR,[e(ai) for ai in E.ainvs()]) - sage: e1,e2,e3 = E1.two_division_polynomial().roots(RR,multiplicities=False) + sage: E1 = EllipticCurve(RR, [e(ai) for ai in E.ainvs()]) + sage: e1, e2, e3 = E1.two_division_polynomial().roots(RR, + ....: multiplicities=False) sage: e1 < e2 < e3 and e(P[0]) < e3 True """ @@ -2277,9 +2405,9 @@ def is_on_identity_component(self, embedding=None): K = E.base_field() if e is None: try: - e = K.embeddings(rings.RealField())[0] + e = K.embeddings(RealField())[0] except IndexError: - e = K.embeddings(rings.ComplexField())[0] + e = K.embeddings(ComplexField())[0] # If there is only one component, the result is True: if not isinstance(e.codomain(), sage.rings.abc.RealField): # complex embedding @@ -2331,14 +2459,16 @@ def has_good_reduction(self, P=None): :: - sage: K.<i> = NumberField(x^2+1) - sage: E = EllipticCurve(K,[0,1,0,-160,308]) - sage: P = E(26,-120) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) + sage: E = EllipticCurve(K, [0,1,0,-160,308]) + sage: P = E(26, -120) sage: E.discriminant().support() [Fractional ideal (i + 1), - Fractional ideal (-i - 2), - Fractional ideal (2*i + 1), - Fractional ideal (3)] + Fractional ideal (-i - 2), + Fractional ideal (2*i + 1), + Fractional ideal (3)] sage: [E.tamagawa_exponent(p) for p in E.discriminant().support()] [1, 4, 4, 4] sage: P.has_good_reduction() @@ -2353,14 +2483,14 @@ def has_good_reduction(self, P=None): An example showing that :trac:`8498` is fixed:: sage: E = EllipticCurve('11a1') - sage: K.<t> = NumberField(x^2+47) - sage: EK = E.base_extend(K) - sage: T = EK(5,5) - sage: P = EK(-2, -1/2*t - 1/2) - sage: p = K.ideal(11) - sage: T.has_good_reduction(p) + sage: K.<t> = NumberField(x^2 + 47) # needs sage.rings.number_field + sage: EK = E.base_extend(K) # needs sage.rings.number_field + sage: T = EK(5, 5) # needs sage.rings.number_field + sage: P = EK(-2, -1/2*t - 1/2) # needs sage.rings.number_field + sage: p = K.ideal(11) # needs sage.rings.number_field + sage: T.has_good_reduction(p) # needs sage.rings.number_field False - sage: P.has_good_reduction(p) + sage: P.has_good_reduction(p) # needs sage.rings.number_field True """ if self.is_zero(): # trivial case @@ -2388,7 +2518,7 @@ def has_good_reduction(self, P=None): xyz = list(Q) e = min([c.valuation(P) for c in xyz]) if e != 0: - if K is rings.QQ: + if K is QQ: pi = P else: pi = K.uniformizer(P) @@ -2441,9 +2571,11 @@ def reduction(self, p): :: - sage: F.<a> = NumberField(x^2+5) - sage: E = EllipticCurve(F,[1,2,3,4,0]) - sage: Q = E(98,931) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: F.<a> = NumberField(x^2 + 5) + sage: E = EllipticCurve(F, [1,2,3,4,0]) + sage: Q = E(98, 931) sage: Q.reduction(a) (3 : 1 : 1) sage: Q.reduction(11) @@ -2451,12 +2583,13 @@ def reduction(self, p): :: - sage: F.<a> = NumberField(x^3+x^2+1) - sage: E = EllipticCurve(F,[a,2]) - sage: P = E(a,1) + sage: # needs sage.rings.number_field + sage: F.<a> = NumberField(x^3 + x^2 + 1) + sage: E = EllipticCurve(F, [a,2]) + sage: P = E(a, 1) sage: P.reduction(F.ideal(5)) (abar : 1 : 1) - sage: P.reduction(F.ideal(a^2-4*a-2)) + sage: P.reduction(F.ideal(a^2 - 4*a - 2)) (abar : 1 : 1) """ P = self @@ -2480,8 +2613,8 @@ def height(self, precision=None, normalised=True, algorithm='pari'): return this normalised height multiplied by the degree of `K`. - - ``algorithm`` -- string: either 'pari' (default) or 'sage'. - If 'pari' and the base field is `\QQ`, use the PARI library + - ``algorithm`` -- string: either ``'pari'`` (default) or ``'sage'``. + If ``'pari'`` and the base field is `\QQ`, use the PARI library function; otherwise use the Sage implementation. OUTPUT: @@ -2542,7 +2675,8 @@ def height(self, precision=None, normalised=True, algorithm='pari'): :: sage: E = EllipticCurve('4602a1'); E - Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 37746035*x - 89296920339 over Rational Field + Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 37746035*x - 89296920339 + over Rational Field sage: x = 77985922458974949246858229195945103471590 sage: y = 19575260230015313702261379022151675961965157108920263594545223 sage: d = 2254020761884782243 @@ -2558,7 +2692,7 @@ def height(self, precision=None, normalised=True, algorithm='pari'): sage: E = EllipticCurve('389a1'); E Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field - sage: [P,Q] = [E(-1,1),E(0,-1)] + sage: P, Q = E(-1,1), E(0,-1) sage: P.height(precision=100) 0.68666708330558658572355210295 sage: (3*Q).height(precision=100)/Q.height(precision=100) @@ -2569,22 +2703,23 @@ def height(self, precision=None, normalised=True, algorithm='pari'): Canonical heights over number fields are implemented as well:: sage: R.<x> = QQ[] - sage: K.<a> = NumberField(x^3-2) - sage: E = EllipticCurve([a, 4]); E - Elliptic Curve defined by y^2 = x^3 + a*x + 4 over Number Field in a with defining polynomial x^3 - 2 - sage: P = E((0,2)) - sage: P.height() + sage: K.<a> = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: E = EllipticCurve([a, 4]); E # needs sage.rings.number_field + Elliptic Curve defined by y^2 = x^3 + a*x + 4 + over Number Field in a with defining polynomial x^3 - 2 + sage: P = E((0,2)) # needs sage.rings.number_field + sage: P.height() # needs sage.rings.number_field 0.810463096585925 - sage: P.height(precision=100) + sage: P.height(precision=100) # needs sage.rings.number_field 0.81046309658592536863991810577 - sage: P.height(precision=200) + sage: P.height(precision=200) # needs sage.rings.number_field 0.81046309658592536863991810576865158896130286417155832378086 - sage: (2*P).height() / P.height() + sage: (2*P).height() / P.height() # needs sage.rings.number_field 4.00000000000000 - sage: (100*P).height() / P.height() + sage: (100*P).height() / P.height() # needs sage.rings.number_field 10000.0000000000 - Setting normalised=False multiplies the height by the degree of `K`:: + Setting ``normalised=False`` multiplies the height by the degree of `K`:: sage: E = EllipticCurve('37a') sage: P = E([0,0]) @@ -2592,12 +2727,12 @@ def height(self, precision=None, normalised=True, algorithm='pari'): 0.0511114082399688 sage: P.height(normalised=False) 0.0511114082399688 - sage: K.<z> = CyclotomicField(5) - sage: EK = E.change_ring(K) - sage: PK = EK([0,0]) - sage: PK.height() + sage: K.<z> = CyclotomicField(5) # needs sage.rings.number_field + sage: EK = E.change_ring(K) # needs sage.rings.number_field + sage: PK = EK([0,0]) # needs sage.rings.number_field + sage: PK.height() # needs sage.rings.number_field 0.0511114082399688 - sage: PK.height(normalised=False) + sage: PK.height(normalised=False) # needs sage.rings.number_field 0.204445632959875 Some consistency checks:: @@ -2607,15 +2742,16 @@ def height(self, precision=None, normalised=True, algorithm='pari'): sage: P.height() 1.36857250535393 - sage: EK = E.change_ring(QuadraticField(-3,'a')) - sage: PK = EK([-2,3,1]) - sage: PK.height() + sage: EK = E.change_ring(QuadraticField(-3,'a')) # needs sage.rings.number_field + sage: PK = EK([-2,3,1]) # needs sage.rings.number_field + sage: PK.height() # needs sage.rings.number_field 1.36857250535393 - sage: K.<i> = NumberField(x^2+1) + sage: # needs sage.rings.number_field + sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve(K, [0,0,4,6*i,0]) sage: Q = E.lift_x(-9/4); Q - (-9/4 : -27/8*i : 1) + (-9/4 : 27/8*i - 4 : 1) sage: Q.height() 2.69518560017909 sage: (15*Q).height() / Q.height() @@ -2625,13 +2761,13 @@ def height(self, precision=None, normalised=True, algorithm='pari'): sage: P = E([0,-1]) sage: P.height() 0.0511114082399688 - sage: K.<a> = QuadraticField(-7) - sage: ED = E.quadratic_twist(-7) - sage: Q = E.isomorphism_to(ED.change_ring(K))(P); Q + sage: K.<a> = QuadraticField(-7) # needs sage.rings.number_field + sage: ED = E.quadratic_twist(-7) # needs sage.rings.number_field + sage: Q = E.isomorphism_to(ED.change_ring(K))(P); Q # needs sage.rings.number_field (0 : -7/2*a - 1/2 : 1) - sage: Q.height() + sage: Q.height() # needs sage.rings.number_field 0.0511114082399688 - sage: Q.height(precision=100) + sage: Q.height(precision=100) # needs sage.rings.number_field 0.051111408239968840235886099757 An example to show that the bug at :trac:`5252` is fixed:: @@ -2665,8 +2801,9 @@ def height(self, precision=None, normalised=True, algorithm='pari'): An example to show that the bug at :trac:`12509` is fixed (precision issues):: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: K.<a> = NumberField(x^2-x-1) + sage: K.<a> = NumberField(x^2 - x - 1) sage: v = [0, a + 1, 1, 28665*a - 46382, 2797026*a - 4525688] sage: E = EllipticCurve(v) sage: P = E([72*a - 509/5, -682/25*a - 434/25]) @@ -2685,36 +2822,36 @@ def height(self, precision=None, normalised=True, algorithm='pari'): sage: P1 = E(2,5) sage: P1.height() 1.06248137652528 - sage: F = E.change_ring(QuadraticField(-3,'a')) - sage: P2 = F([2,5]) - sage: P2.height() + sage: F = E.change_ring(QuadraticField(-3, 'a')) # needs sage.rings.number_field + sage: P2 = F([2,5]) # needs sage.rings.number_field + sage: P2.height() # needs sage.rings.number_field 1.06248137652528 """ if self.has_finite_order(): - return rings.QQ(0) + return QQ(0) E = self.curve() K = E.base_ring() if precision is None: - precision = rings.RealField().precision() + precision = RealField().precision() known_prec = -1 try: height = self.__height known_prec = height.prec() if known_prec > precision: - height = rings.RealField(precision)(height) + height = RealField(precision)(height) except AttributeError: pass if known_prec < precision: - if algorithm == 'pari' and K is rings.QQ: + if algorithm == 'pari' and K is QQ: Emin = E.minimal_model() iso = E.isomorphism_to(Emin) P = iso(self) h = Emin.pari_curve().ellheight(P, precision=precision) - height = rings.RealField(precision)(h) + height = RealField(precision)(h) else: height = (self.non_archimedean_local_height(prec=precision) + self.archimedean_local_height(prec=precision)) @@ -2740,7 +2877,7 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): archimedean contribution to the global height. - ``prec`` -- integer, or None (default). The precision of the - computation. If None, the precision is deduced from v. + computation. If None, the precision is deduced from `v`. - ``weighted`` -- boolean. If False (default), the height is normalised to be invariant under extension of `K`. If True, @@ -2762,24 +2899,29 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): Examples 1, 2, and 3 from [Sil1988]_:: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-2) sage: E = EllipticCurve(K, [0,-1,1,0,0]); E - Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 over Number Field in a with defining polynomial x^2 + 2 with a = 1.414213562373095?*I - sage: P = E.lift_x(2+a); P - (a + 2 : 2*a + 1 : 1) + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 over Number Field + in a with defining polynomial x^2 + 2 with a = 1.414213562373095?*I + sage: P = E.lift_x(2 + a); P + (a + 2 : -2*a - 2 : 1) sage: P.archimedean_local_height(K.places(prec=170)[0]) / 2 0.45754773287523276736211210741423654346576029814695 - sage: K.<i> = NumberField(x^2+1) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve(K, [0,0,4,6*i,0]); E - Elliptic Curve defined by y^2 + 4*y = x^3 + 6*i*x over Number Field in i with defining polynomial x^2 + 1 + Elliptic Curve defined by y^2 + 4*y = x^3 + 6*i*x + over Number Field in i with defining polynomial x^2 + 1 sage: P = E((0,0)) sage: P.archimedean_local_height(K.places()[0]) / 2 0.510184995162373 - sage: Q = E.lift_x(-9/4); Q - (-9/4 : -27/8*i : 1) - sage: Q.archimedean_local_height(K.places()[0]) / 2 + sage: Q = E.lift_x(-9/4); Q # needs sage.rings.number_field + (-9/4 : 27/8*i - 4 : 1) + sage: Q.archimedean_local_height(K.places()[0]) / 2 # needs sage.rings.number_field 0.654445619529600 An example over the rational numbers:: @@ -2792,6 +2934,7 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): Local heights of torsion points can be non-zero (unlike the global height):: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve([0, 0, 0, K(1), 0]) sage: P = E(i, 0) @@ -2802,8 +2945,9 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): See :trac:`12509`:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: K.<a> = NumberField(x^2-x-1) + sage: K.<a> = NumberField(x^2 - x - 1) sage: v = [0, a + 1, 1, 28665*a - 46382, 2797026*a - 4525688] sage: E = EllipticCurve(v) sage: P = E([72*a - 509/5, -682/25*a - 434/25]) @@ -2812,7 +2956,8 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): See :trac:`19276`:: - sage: K.<a> = NumberField(x^2-x-104) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^2 - x - 104) sage: E = EllipticCurve([1, a - 1, 1, -816765673272*a - 7931030674178, 1478955604013312315*a + 14361086227143654561]) sage: P = E(5393511/49*a + 52372721/49 , -33896210324/343*a - 329141996591/343 ) sage: P.height() @@ -2820,8 +2965,10 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): See :trac:`29966`:: + sage: # needs sage.rings.number_field sage: K.<a> = NumberField(x^3 - x^2 - 6*x + 2) - sage: E = EllipticCurve([1, -a^2 + 2*a + 4, 0, -6056450500590472699700624*a^2 - 11239394326797569935861742*a + 4241549693833829432516231, 1904879037869682826729875958079326124520*a^2 + 3535022146945771697732350459284777382011*a - 1334055169621036218710397707677347972626]) + sage: E = EllipticCurve([1, -a^2 + 2*a + 4, 0, -6056450500590472699700624*a^2 - 11239394326797569935861742*a + 4241549693833829432516231, + ....: 1904879037869682826729875958079326124520*a^2 + 3535022146945771697732350459284777382011*a - 1334055169621036218710397707677347972626]) sage: P = E([1033399668533*a^2 + 1917754693229*a - 723726883800 , 12536493059202326563*a^2 + 23264879148900575548*a - 8779756111574815918 , 1]) sage: P.height() 0.297318833424763 @@ -2833,7 +2980,9 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): 4.0000000000000000000000000000000000000000000000000000000000 """ from sage.rings.number_field.number_field import refine_embedding - from sage.all import RealField, ComplexField, Infinity + from sage.rings.real_mpfr import RealField + from sage.rings.complex_mpfr import ComplexField + from sage.rings.infinity import Infinity E = self.curve() K = E.base_ring() @@ -2842,8 +2991,8 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): if prec is None: prec = 53 - if K is rings.QQ: - v = K.embeddings(rings.RR)[0] + if K is QQ: + v = K.embeddings(RR)[0] h = self.archimedean_local_height(v, prec+10) else: r1, r2 = K.signature() @@ -2859,7 +3008,7 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): prec_v = v.codomain().prec() if prec is None: prec = prec_v - if K is rings.QQ: + if K is QQ: v = K.embeddings(RealField())[0] v_inf = refine_embedding(v, Infinity) v_is_real = v_inf(K.gen()).imag().is_zero() @@ -2917,7 +3066,7 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): beta = False lam = -t.abs().log() mu = 0 - four_to_n = rings.QQ(1) + four_to_n = QQ(1) for n in range(nterms): if beta: @@ -2985,9 +3134,12 @@ def non_archimedean_local_height(self, v=None, prec=None, Examples 2 and 3 from [Sil1988]_:: - sage: K.<i> = NumberField(x^2+1) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve(K, [0,0,4,6*i,0]); E - Elliptic Curve defined by y^2 + 4*y = x^3 + 6*i*x over Number Field in i with defining polynomial x^2 + 1 + Elliptic Curve defined by y^2 + 4*y = x^3 + 6*i*x + over Number Field in i with defining polynomial x^2 + 1 sage: P = E((0,0)) sage: P.non_archimedean_local_height(K.ideal(i+1)) -1/2*log(2) @@ -2996,8 +3148,9 @@ def non_archimedean_local_height(self, v=None, prec=None, sage: P.non_archimedean_local_height(K.ideal(1-2*i)) 0 + sage: # needs sage.rings.number_field sage: Q = E.lift_x(-9/4); Q - (-9/4 : -27/8*i : 1) + (-9/4 : 27/8*i - 4 : 1) sage: Q.non_archimedean_local_height(K.ideal(1+i)) 2*log(2) sage: Q.non_archimedean_local_height(K.ideal(3)) @@ -3017,6 +3170,7 @@ def non_archimedean_local_height(self, v=None, prec=None, Local heights of torsion points can be non-zero (unlike the global height):: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve([0, 0, 0, K(1), 0]) sage: P = E(i, 0) @@ -3025,11 +3179,12 @@ def non_archimedean_local_height(self, v=None, prec=None, TESTS:: - sage: Q.non_archimedean_local_height(prec=100) + sage: Q.non_archimedean_local_height(prec=100) # needs sage.rings.number_field 1.3862943611198906188344642429 - sage: (3*Q).non_archimedean_local_height() + sage: (3*Q).non_archimedean_local_height() # needs sage.rings.number_field 1/2*log(75923153929839865104) + sage: # needs sage.rings.number_field sage: F.<a> = NumberField(x^4 + 2*x^3 + 19*x^2 + 18*x + 288) sage: F.ring_of_integers().basis() [1, 5/6*a^3 + 1/6*a, 1/6*a^3 + 1/6*a^2, a^3] @@ -3051,14 +3206,14 @@ def non_archimedean_local_height(self, v=None, prec=None, -2/3*log(2) """ if prec: - log = lambda x: rings.RealField(prec)(x).log() + log = lambda x: RealField(prec)(x).log() else: from sage.functions.log import log if v is None: D = self.curve().discriminant() K = self.curve().base_ring() - if K is rings.QQ: + if K is QQ: factorD = D.factor() if self[0] == 0: c = 1 @@ -3121,9 +3276,9 @@ def non_archimedean_local_height(self, v=None, prec=None, r = -C/4 r -= offset/6 if not r: - return rings.QQ.zero() + return QQ.zero() else: - if E.base_ring() is rings.QQ: + if E.base_ring() is QQ: Nv = Integer(v) else: Nv = v.norm() @@ -3148,8 +3303,8 @@ def elliptic_logarithm(self, embedding=None, precision=100, - ``precision``: a positive integer (default 100) setting the number of bits of precision for the computation - - ``algorithm``: either 'pari' (default for real embeddings) - to use PARI's :pari:`ellpointtoz`, or 'sage' for a native + - ``algorithm``: either ``'pari'`` (default for real embeddings) + to use PARI's :pari:`ellpointtoz`, or ``'sage'`` for a native implementation. Ignored for complex embeddings. ALGORITHM: @@ -3175,7 +3330,7 @@ def elliptic_logarithm(self, embedding=None, precision=100, False sage: P.elliptic_logarithm (precision=96) 0.4793482501902193161295330101 + 0.985868850775824102211203849...*I - sage: Q=E([3,5]) + sage: Q = E([3,5]) sage: Q.is_on_identity_component() True sage: Q.elliptic_logarithm (precision=96) @@ -3200,7 +3355,7 @@ def elliptic_logarithm(self, embedding=None, precision=100, sage: P.elliptic_logarithm() # 100 bits 0.27656204014107061464076203097 - The native algorithm 'sage' used to have trouble with + The native algorithm ``'sage'`` used to have trouble with precision in this example, but no longer:: sage: P.elliptic_logarithm(algorithm='sage') # 100 bits @@ -3227,7 +3382,9 @@ def elliptic_logarithm(self, embedding=None, precision=100, Examples over number fields:: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: embs = K.embeddings(CC) sage: E = EllipticCurve([0,1,0,a,a]) sage: Ls = [E.period_lattice(e) for e in embs] @@ -3235,26 +3392,39 @@ def elliptic_logarithm(self, embedding=None, precision=100, [0, 0, -1] sage: P = E(-1,0) # order 2 sage: [L.elliptic_logarithm(P) for L in Ls] - [-1.73964256006716 - 1.07861534489191*I, -0.363756518406398 - 1.50699412135253*I, 1.90726488608927] + [-1.73964256006716 - 1.07861534489191*I, + -0.363756518406398 - 1.50699412135253*I, 1.90726488608927] + sage: # needs sage.rings.number_field sage: E = EllipticCurve([-a^2 - a - 1, a^2 + a]) sage: Ls = [E.period_lattice(e) for e in embs] - sage: pts = [E(2*a^2 - a - 1 , -2*a^2 - 2*a + 6 ), E(-2/3*a^2 - 1/3 , -4/3*a - 2/3 ), E(5/4*a^2 - 1/2*a , -a^2 - 1/4*a + 9/4 ), E(2*a^2 + 3*a + 4 , -7*a^2 - 10*a - 12 )] + sage: pts = [E(2*a^2 - a - 1 , -2*a^2 - 2*a + 6 ), + ....: E(-2/3*a^2 - 1/3 , -4/3*a - 2/3 ), + ....: E(5/4*a^2 - 1/2*a , -a^2 - 1/4*a + 9/4 ), + ....: E(2*a^2 + 3*a + 4 , -7*a^2 - 10*a - 12 )] sage: [[L.elliptic_logarithm(P) for P in pts] for L in Ls] - [[0.250819591818930 - 0.411963479992219*I, -0.290994550611374 - 1.37239400324105*I, -0.693473752205595 - 2.45028458830342*I, -0.151659609775291 - 1.48985406505459*I], [1.33444787667954 - 1.50889756650544*I, 0.792633734249234 - 0.548467043256610*I, 0.390154532655013 + 0.529423541805758*I, 0.931968675085317 - 0.431006981443071*I], [1.14758249500109 + 0.853389664016075*I, 2.59823462472518 + 0.853389664016075*I, 1.75372176444709, 0.303069634723001]] + [[0.250819591818930 - 0.411963479992219*I, -0.290994550611374 - 1.37239400324105*I, + -0.693473752205595 - 2.45028458830342*I, -0.151659609775291 - 1.48985406505459*I], + [1.33444787667954 - 1.50889756650544*I, 0.792633734249234 - 0.548467043256610*I, + 0.390154532655013 + 0.529423541805758*I, 0.931968675085317 - 0.431006981443071*I], + [1.14758249500109 + 0.853389664016075*I, 2.59823462472518 + 0.853389664016075*I, + 1.75372176444709, 0.303069634723001]] :: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve([0,0,0,9*i-10,21-i]) sage: emb = K.embeddings(CC)[1] sage: L = E.period_lattice(emb) - sage: P = E(2-i,4+2*i) - sage: L.elliptic_logarithm(P,prec=100) + sage: P = E(2-i, 4+2*i) + sage: L.elliptic_logarithm(P, prec=100) 0.70448375537782208460499649302 - 0.79246725643650979858266018068*I """ from sage.rings.number_field.number_field import refine_embedding - from sage.rings.all import RealField, ComplexField, QQ + from sage.rings.real_mpfr import RealField + from sage.rings.complex_mpfr import ComplexField + from sage.rings.rational_field import QQ # Check the trivial case: @@ -3366,31 +3536,32 @@ def padic_elliptic_logarithm(self, p, absprec=20): EXAMPLES:: sage: E = EllipticCurve([0,1,1,-2,0]) - sage: E(0).padic_elliptic_logarithm(3) + sage: E(0).padic_elliptic_logarithm(3) # needs sage.rings.padics 0 - sage: P = E(0,0) - sage: P.padic_elliptic_logarithm(3) + sage: P = E(0, 0) # needs sage.rings.padics + sage: P.padic_elliptic_logarithm(3) # needs sage.rings.padics 2 + 2*3 + 3^3 + 2*3^7 + 3^8 + 3^9 + 3^11 + 3^15 + 2*3^17 + 3^18 + O(3^19) - sage: P.padic_elliptic_logarithm(3).lift() + sage: P.padic_elliptic_logarithm(3).lift() # needs sage.rings.padics 660257522 - sage: P = E(-11/9,28/27) - sage: [(2*P).padic_elliptic_logarithm(p)/P.padic_elliptic_logarithm(p) for p in prime_range(20)] # long time (3s) + sage: P = E(-11/9, 28/27) # needs sage.rings.padics + sage: [(2*P).padic_elliptic_logarithm(p)/P.padic_elliptic_logarithm(p) for p in prime_range(20)] # long time, needs sage.rings.padics [2 + O(2^19), 2 + O(3^20), 2 + O(5^19), 2 + O(7^19), 2 + O(11^19), 2 + O(13^19), 2 + O(17^19), 2 + O(19^19)] - sage: [(3*P).padic_elliptic_logarithm(p)/P.padic_elliptic_logarithm(p) for p in prime_range(12)] # long time (2s) + sage: [(3*P).padic_elliptic_logarithm(p)/P.padic_elliptic_logarithm(p) for p in prime_range(12)] # long time, needs sage.rings.padics [1 + 2 + O(2^19), 3 + 3^20 + O(3^21), 3 + O(5^19), 3 + O(7^19), 3 + O(11^19)] - sage: [(5*P).padic_elliptic_logarithm(p)/P.padic_elliptic_logarithm(p) for p in prime_range(12)] # long time (2s) + sage: [(5*P).padic_elliptic_logarithm(p)/P.padic_elliptic_logarithm(p) for p in prime_range(12)] # long time, needs sage.rings.padics [1 + 2^2 + O(2^19), 2 + 3 + O(3^20), 5 + O(5^19), 5 + O(7^19), 5 + O(11^19)] An example which arose during reviewing :trac:`4741`:: sage: E = EllipticCurve('794a1') sage: P = E(-1,2) - sage: P.padic_elliptic_logarithm(2) # default precision=20 + sage: P.padic_elliptic_logarithm(2) # default precision=20 # needs sage.rings.padics 2^4 + 2^5 + 2^6 + 2^8 + 2^9 + 2^13 + 2^14 + 2^15 + O(2^16) - sage: P.padic_elliptic_logarithm(2, absprec=30) + sage: P.padic_elliptic_logarithm(2, absprec=30) # needs sage.rings.padics 2^4 + 2^5 + 2^6 + 2^8 + 2^9 + 2^13 + 2^14 + 2^15 + 2^22 + 2^23 + 2^24 + O(2^26) - sage: P.padic_elliptic_logarithm(2, absprec=40) - 2^4 + 2^5 + 2^6 + 2^8 + 2^9 + 2^13 + 2^14 + 2^15 + 2^22 + 2^23 + 2^24 + 2^28 + 2^29 + 2^31 + 2^34 + O(2^35) + sage: P.padic_elliptic_logarithm(2, absprec=40) # needs sage.rings.padics + 2^4 + 2^5 + 2^6 + 2^8 + 2^9 + 2^13 + 2^14 + 2^15 + 2^22 + 2^23 + 2^24 + + 2^28 + 2^29 + 2^31 + 2^34 + O(2^35) """ if not p.is_prime(): raise ValueError('p must be prime') @@ -3479,7 +3650,7 @@ def _magma_init_(self, magma): sage: E = EllipticCurve(GF(17), [1,-1]) sage: P = E([13, 4]) - sage: P._magma_init_(magma) # optional - magma + sage: P._magma_init_(magma) # optional - magma 'EllipticCurve([_sage_ref...|GF(17)!0,GF(17)!0,GF(17)!0,GF(17)!1,GF(17)!16])![13,4]' """ E = self.curve()._magma_init_(magma) @@ -3493,6 +3664,7 @@ def _acted_upon_(self, other, side): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: P = EllipticCurve(GF(65537), [2,2]).lift_x(6) sage: P.order().factor() 2^2 * 3 * 37^2 @@ -3537,7 +3709,7 @@ def _acted_upon_(self, other, side): return Q - def discrete_log(self, Q, ord=None): + def discrete_log(self, Q): r""" Return the discrete logarithm of `Q` to base `P` = ``self``, that is, an integer `x` such that `xP = Q`. @@ -3583,6 +3755,7 @@ def discrete_log(self, Q, ord=None): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF((3,6),'a') sage: a = F.gen() sage: E = EllipticCurve([0,1,1,a,a]) @@ -3597,6 +3770,7 @@ def discrete_log(self, Q, ord=None): Some random testing:: + sage: # needs sage.rings.finite_rings sage: sz = randint(8,32) sage: e = randint(1,3) sage: p = random_prime(ceil(2**(sz/e))) @@ -3606,18 +3780,7 @@ def discrete_log(self, Q, ord=None): sage: x = P.discrete_log(Q) sage: x*P == Q True - - Doctest deprecation:: - - sage: P.discrete_log(Q, ord=P.order()) - doctest:warning - ... - DeprecationWarning: The "ord" argument to .discrete_log() is obsolete. ... """ - if ord is not None: - from sage.misc.superseded import deprecation - deprecation(33121, 'The "ord" argument to .discrete_log() is obsolete. Use the .set_order() method instead.') - self.set_order(ord) if Q not in self.parent(): raise ValueError('not a point on the same curve') n = self.order() @@ -3648,8 +3811,8 @@ def padic_elliptic_logarithm(self,Q, p): INPUT: - - ``Q`` (point) -- another point on the same curve as ``self``. - - ``p`` (integer) -- a prime equals the order of the curve. + - ``Q`` (point) -- another point on the same curve as ``self``. + - ``p`` (integer) -- a prime equal to the order of the curve. OUTPUT: @@ -3665,27 +3828,29 @@ def padic_elliptic_logarithm(self,Q, p): EXAMPLES:: - sage: p=235322474717419 - sage: b=8856682 + sage: # needs sage.rings.finite_rings + sage: p = 235322474717419 + sage: b = 8856682 sage: E = EllipticCurve(GF(p), [0, b]) sage: P = E(200673830421813, 57025307876612) sage: Q = E(40345734829479, 211738132651297) - sage: x = P.padic_elliptic_logarithm(Q, p) - sage: x * P == Q + sage: x = P.padic_elliptic_logarithm(Q, p) # needs sage.rings.padics + sage: x * P == Q # needs sage.rings.padics True TESTS: Some testing:: + sage: # needs sage.rings.finite_rings sage: a = 49850651047495986645822557378918223 sage: b = 21049438014429831351540675253466229 sage: p = 54283205379427155782089046839411711 - sage: E = EllipticCurve(GF(p),[a, b]) + sage: E = EllipticCurve(GF(p), [a, b]) sage: P = E.random_point() sage: Q = randrange(0, p-1) * P - sage: x = P.padic_elliptic_logarithm(Q, p) - sage: x*P == Q + sage: x = P.padic_elliptic_logarithm(Q, p) # needs sage.rings.padics + sage: x*P == Q # needs sage.rings.padics True """ E = self.curve() @@ -3752,10 +3917,11 @@ def order(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF((5,5)) sage: E = EllipticCurve(k,[2,4]); E Elliptic Curve defined by y^2 = x^3 + 2*x + 4 over Finite Field in a of size 5^5 - sage: P = E(3*a^4 + 3*a , 2*a + 1 ) + sage: P = E(3*a^4 + 3*a, 2*a + 1) sage: P.order() 3227 sage: Q = E(0,2) @@ -3766,9 +3932,11 @@ def order(self): :: - sage: p=next_prime(2^150) - sage: E=EllipticCurve(GF(p),[1,1]) - sage: P=E(831623307675610677632782670796608848711856078, 42295786042873366706573292533588638217232964) + sage: # needs sage.rings.finite_rings + sage: p = next_prime(2^150) + sage: E = EllipticCurve(GF(p), [1,1]) + sage: P = E(831623307675610677632782670796608848711856078, + ....: 42295786042873366706573292533588638217232964) sage: P.order() 1427247692705959881058262545272474300628281448 sage: P.order() == E.cardinality() @@ -3776,30 +3944,33 @@ def order(self): The next example has `j(E)=0`:: + sage: # needs sage.rings.finite_rings sage: p = 33554501 sage: F.<u> = GF((p,2)) - sage: E = EllipticCurve(F,[0,1]) + sage: E = EllipticCurve(F, [0,1]) sage: E.j_invariant() 0 sage: P = E.random_point() - sage: P.order() # random + sage: P.order() # random 16777251 Similarly when `j(E)=1728`:: + sage: # needs sage.rings.finite_rings sage: p = 33554473 sage: F.<u> = GF((p,2)) - sage: E = EllipticCurve(F,[1,0]) + sage: E = EllipticCurve(F, [1,0]) sage: E.j_invariant() 1728 sage: P = E.random_point() - sage: P.order() # random + sage: P.order() # random 46912611635760 TESTS: Check that the order actually gets cached (:trac:`32786`):: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(31337), [42,1]) sage: P = E.lift_x(1) sage: hasattr(P, '_order') @@ -3812,7 +3983,7 @@ def order(self): The curve order should also get cached as a side effect of computing a point order:: - sage: E._order + sage: E._order # needs sage.rings.finite_rings 31298 """ try: diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index c2b8436f2a1..47dc2fc2a64 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -""" +r""" Elliptic curves over the rational numbers AUTHORS: @@ -49,6 +49,7 @@ # # https://www.gnu.org/licenses/ ############################################################################## +from itertools import product from . import constructor from . import BSD @@ -66,32 +67,38 @@ from sage.modular.modsym.modsym import ModularSymbols from sage.modular.pollack_stevens.space import ps_modsym_from_elliptic_curve -from sage.lfunctions.zero_sums import LFunctionZeroSum_EllipticCurve - import sage.modular.modform.constructor import sage.modular.modform.element import sage.databases.cremona import sage.arith.all as arith -import sage.rings.all as rings -from sage.rings.all import ( - PowerSeriesRing, - infinity as oo, - ZZ, QQ, - Integer, - IntegerRing, RealField, - ComplexField, RationalField) +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.fast_arith import prime_range +from sage.rings.real_mpfr import RR +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.structure.element import RingElement +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.infinity import Infinity as oo +from sage.rings.integer_ring import ZZ, IntegerRing +from sage.rings.rational_field import QQ +from sage.rings.integer import Integer +from sage.rings.real_mpfi import RealIntervalField +from sage.rings.real_mpfr import RealField +from sage.rings.complex_mpfr import ComplexField +from sage.rings.rational_field import RationalField from sage.structure.coerce import py_scalar_to_element from sage.structure.element import Element -import sage.misc.all as misc +from sage.misc.misc_c import prod as mul +from sage.misc.misc_c import prod +from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose as verbose_verbose from sage.functions.log import log -import sage.matrix.all as matrix -from sage.libs.pari.all import pari -from sage.functions.gamma import gamma_inc +from sage.matrix.matrix_space import MatrixSpace +lazy_import('sage.libs.pari.all', 'pari') +lazy_import("sage.functions.gamma", "gamma_inc") from math import sqrt from sage.interfaces.gp import gp from sage.misc.cachefunc import cached_method @@ -101,15 +108,15 @@ C = ComplexField() R = RealField() Z = IntegerRing() -IR = rings.RealIntervalField(20) +IR = RealIntervalField(20) -_MAX_HEIGHT=21 +_MAX_HEIGHT = 21 # complex multiplication dictionary: # CMJ is a dict of pairs (j,D) where j is a rational CM j-invariant # and D is the corresponding quadratic discriminant -CMJ={ 0: -3, 54000: -12, -12288000: -27, 1728: -4, 287496: -16, +CMJ = { 0: -3, 54000: -12, -12288000: -27, 1728: -4, 287496: -16, -3375: -7, 16581375: -28, 8000: -8, -32768: -11, -884736: -19, -884736000: -43, -147197952000: -67, -262537412640768000: -163} @@ -199,7 +206,7 @@ def __init__(self, ainvs, **kwds): self._set_torsion_order(kwds['torsion_order']) def _set_rank(self, r): - """ + r""" Internal function to set the cached rank of this elliptic curve to ``r``. @@ -220,7 +227,7 @@ def _set_rank(self, r): self.__rank = (Integer(r), True) def _set_torsion_order(self, t): - """ + r""" Internal function to set the cached torsion order of this elliptic curve to ``t``. @@ -241,7 +248,7 @@ def _set_torsion_order(self, t): self.__torsion_order = Integer(t) def _set_cremona_label(self, L): - """ + r""" Internal function to set the cached label of this elliptic curve to ``L``. @@ -266,7 +273,7 @@ def _set_cremona_label(self, L): self.__cremona_label = L def _set_conductor(self, N): - """ + r""" Internal function to set the cached conductor of this elliptic curve to ``N.`` @@ -287,7 +294,7 @@ def _set_conductor(self, N): self.__conductor_pari = Integer(N) def _set_modular_degree(self, deg): - """ + r""" Internal function to set the cached modular degree of this elliptic curve to ``deg``. @@ -308,7 +315,7 @@ def _set_modular_degree(self, deg): self.__modular_degree = Integer(deg) def _set_gens(self, gens): - """ + r""" Internal function to set the cached generators of this elliptic curve to ``gens``. @@ -378,10 +385,10 @@ def is_p_integral(self, p): raise ArithmeticError("p must be prime") if self.is_integral(): return True - return bool(misc.mul([x.valuation(p) >= 0 for x in self.ainvs()])) + return bool(mul([x.valuation(p) >= 0 for x in self.ainvs()])) def is_integral(self): - """ + r""" Return ``True`` if this elliptic curve has integral coefficients (in Z). @@ -399,10 +406,9 @@ def is_integral(self): try: return self.__is_integral except AttributeError: - self.__is_integral = bool(misc.mul([x.denominator() == 1 for x in self.ainvs()])) + self.__is_integral = bool(mul([x.denominator() == 1 for x in self.ainvs()])) return self.__is_integral - def mwrank(self, options=''): r""" Run Cremona's mwrank program on this elliptic curve and return the @@ -476,7 +482,7 @@ def mwrank(self, options=''): return mwrank(list(self.a_invariants())) def conductor(self, algorithm="pari"): - """ + r""" Return the conductor of the elliptic curve. INPUT: @@ -539,7 +545,7 @@ def conductor(self, algorithm="pari"): try: return self.__conductor_gp except AttributeError: - self.__conductor_gp = Integer(gp.eval('ellglobalred(ellinit(%s,0))[1]'%list(self.a_invariants()))) + self.__conductor_gp = Integer(gp.eval('ellglobalred(ellinit(%s,0))[1]' % list(self.a_invariants()))) return self.__conductor_gp elif algorithm == "mwrank": @@ -565,18 +571,18 @@ def conductor(self, algorithm="pari"): N3 = self.conductor("gp") N4 = self.conductor("generic") if N1 != N2 or N2 != N3 or N2 != N4: - raise ArithmeticError("PARI, mwrank, gp and Sage compute different conductors (%s,%s,%s,%s) for %s"%( + raise ArithmeticError("PARI, mwrank, gp and Sage compute different conductors (%s,%s,%s,%s) for %s" % ( N1, N2, N3, N4, self)) return N1 else: - raise ValueError("algorithm %r is not known"%algorithm) + raise ValueError("algorithm %r is not known" % algorithm) #################################################################### # Access to PARI curves related to this curve. #################################################################### def pari_curve(self): - """ + r""" Return the PARI curve corresponding to this elliptic curve. EXAMPLES:: @@ -629,7 +635,7 @@ def pari_curve(self): return self._pari_curve def pari_mincurve(self): - """ + r""" Return the PARI curve corresponding to a minimal model for this elliptic curve. @@ -653,12 +659,12 @@ def pari_mincurve(self): @cached_method def database_attributes(self): - """ + r""" Return a dictionary containing information about ``self`` in the elliptic curve database. If there is no elliptic curve isomorphic to ``self`` in the - database, a ``LookupError`` is raised. + database, a :class:`LookupError` is raised. EXAMPLES:: @@ -677,7 +683,8 @@ def database_attributes(self): sage: E.database_attributes() Traceback (most recent call last): ... - LookupError: Cremona database does not contain entry for Elliptic Curve defined by y^2 + 8*x*y + 21*y = x^3 + 13*x^2 + 34*x + 55 over Rational Field + LookupError: Cremona database does not contain entry for Elliptic Curve + defined by y^2 + 8*x*y + 21*y = x^3 + 13*x^2 + 34*x + 55 over Rational Field """ from sage.databases.cremona import CremonaDatabase ainvs = self.minimal_model().ainvs() @@ -687,7 +694,7 @@ def database_attributes(self): raise LookupError("Cremona database does not contain entry for " + repr(self)) def database_curve(self): - """ + r""" Return the curve in the elliptic curve database isomorphic to this curve, if possible. Otherwise raise a ``LookupError`` exception. @@ -710,13 +717,13 @@ def database_curve(self): try: return self.__database_curve except AttributeError: - verbose_verbose("Looking up %s in the database."%self) + verbose_verbose("Looking up %s in the database." % self) D = sage.databases.cremona.CremonaDatabase() ainvs = list(self.minimal_model().ainvs()) try: self.__database_curve = D.elliptic_curve_from_ainvs(ainvs) except RuntimeError: - raise RuntimeError("Elliptic curve %s not in the database."%self) + raise RuntimeError("Elliptic curve %s not in the database." % self) return self.__database_curve def Np(self, p): @@ -759,7 +766,7 @@ def Np(self, p): # Access to mwrank #################################################################### def mwrank_curve(self, verbose=False): - """ + r""" Construct an mwrank_EllipticCurve from this elliptic curve The resulting mwrank_EllipticCurve has available methods from John @@ -775,7 +782,7 @@ def mwrank_curve(self, verbose=False): <class 'sage.libs.eclib.interface.mwrank_EllipticCurve'> sage: EE.isogeny_class() ([[0, -1, 1, -10, -20], [0, -1, 1, -7820, -263580], [0, -1, 1, 0, 0]], - [[0, 5, 5], [5, 0, 0], [5, 0, 0]]) + [[0, 5, 5], [5, 0, 0], [5, 0, 0]]) """ try: return self.__mwrank_curve @@ -791,7 +798,7 @@ def two_descent(self, verbose=True, second_limit=8, n_aux=-1, second_descent=1): - """ + r""" Compute 2-descent data for this curve. INPUT: @@ -909,14 +916,13 @@ def anlist(self, n, python_ints=False): n = int(n) e = self.pari_mincurve() if n >= 2147483648: - raise RuntimeError("anlist: n (=%s) must be < 2147483648."%n) + raise RuntimeError("anlist: n (=%s) must be < 2147483648." % n) v = [0] + e.ellan(n, python_ints=True) if not python_ints: v = [Integer(x) for x in v] return v - # There is some overhead associated with coercing the PARI # list back to Python, but it's not bad. It's better to do it # this way instead of trying to eval the whole list, since the @@ -1030,11 +1036,14 @@ def modular_symbol_space(self, sign=1, base_ring=Q, bound=None): sage: f = EllipticCurve('37b') sage: f.modular_symbol_space() - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(37) of weight 2 with sign 1 over Rational Field + Modular Symbols subspace of dimension 1 of Modular Symbols space + of dimension 3 for Gamma_0(37) of weight 2 with sign 1 over Rational Field sage: f.modular_symbol_space(-1) - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 2 for Gamma_0(37) of weight 2 with sign -1 over Rational Field + Modular Symbols subspace of dimension 1 of Modular Symbols space + of dimension 2 for Gamma_0(37) of weight 2 with sign -1 over Rational Field sage: f.modular_symbol_space(0, bound=3) - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Gamma_0(37) of weight 2 with sign 0 over Rational Field + Modular Symbols subspace of dimension 2 of Modular Symbols space + of dimension 5 for Gamma_0(37) of weight 2 with sign 0 over Rational Field .. NOTE:: @@ -1178,7 +1187,8 @@ def modular_symbol(self, sign=+1, normalize=None, implementation='eclib', nap=0) sage: E = EllipticCurve('37a1') sage: M = E.modular_symbol(); M - Modular symbol with sign 1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + Modular symbol with sign 1 over Rational Field attached to + Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field sage: M(1/2) 0 sage: M(1/5) @@ -1188,7 +1198,8 @@ def modular_symbol(self, sign=+1, normalize=None, implementation='eclib', nap=0) sage: E = EllipticCurve('121b1') sage: M = E.modular_symbol(implementation="sage") - Warning : Could not normalize the modular symbols, maybe all further results will be multiplied by -1 and a power of 2 + Warning : Could not normalize the modular symbols, maybe all further results + will be multiplied by -1 and a power of 2 sage: M(1/7) -1/2 @@ -1254,11 +1265,13 @@ def modular_symbol(self, sign=+1, normalize=None, implementation='eclib', nap=0) sage: E = EllipticCurve('11a1') sage: Mplus = E.modular_symbol(+1); Mplus - Modular symbol with sign 1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Modular symbol with sign 1 over Rational Field attached to + Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: [Mplus(1/i) for i in [1..11]] [1/5, -4/5, -3/10, 7/10, 6/5, 6/5, 7/10, -3/10, -4/5, 1/5, 0] sage: Mminus = E.modular_symbol(-1); Mminus - Modular symbol with sign -1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Modular symbol with sign -1 over Rational Field attached to + Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: [Mminus(1/i) for i in [1..11]] [0, 0, 1/2, 1/2, 0, 0, -1/2, -1/2, 0, 0, 0] @@ -1270,8 +1283,8 @@ def modular_symbol(self, sign=+1, normalize=None, implementation='eclib', nap=0) See :trac:`31443`:: sage: E = EllipticCurve('1590g1') - sage: m = E.modular_symbol(nap=300) - sage: [m(a/5) for a in [1..4]] + sage: m = E.modular_symbol(nap=300) # long time + sage: [m(a/5) for a in [1..4]] # long time [13/2, -13/2, -13/2, 13/2] These values are correct, as verified by the numerical @@ -1355,7 +1368,7 @@ def f(r): return f def pollack_stevens_modular_symbol(self, sign=0, implementation='eclib'): - """ + r""" Create the modular symbol attached to the elliptic curve, suitable for overconvergent calculations. @@ -1438,7 +1451,7 @@ def analytic_rank(self, algorithm="pari", leading_coefficient=False): - ``'rubinstein'`` -- use Rubinstein's L-function C++ program lcalc. - ``'magma'`` -- use MAGMA - ``'zero_sum'`` -- Use the rank bounding zero sum method implemented - in self.analytic_rank_upper_bound() + in :meth:`analytic_rank_upper_bound` - ``'all'`` -- compute with PARI, sympow and lcalc, check that the answers agree, and return the common answer. @@ -1510,7 +1523,7 @@ def analytic_rank(self, algorithm="pari", leading_coefficient=False): Traceback (most recent call last): ... RuntimeError: unable to compute analytic rank using rubinstein algorithm (unable to convert ' 6.19283... and is too large' to an integer) - sage: EllipticCurve([1234567,89101112]).analytic_rank(algorithm='sympow') + sage: EllipticCurve([1234567,89101112]).analytic_rank(algorithm='sympow') # long time Traceback (most recent call last): ... RuntimeError: failed to compute analytic rank @@ -1518,9 +1531,9 @@ def analytic_rank(self, algorithm="pari", leading_coefficient=False): if algorithm == 'pari': rank_lead = self.pari_curve().ellanalyticrank() if leading_coefficient: - return (rings.Integer(rank_lead[0]), rank_lead[1].sage()) + return (Integer(rank_lead[0]), rank_lead[1].sage()) else: - return rings.Integer(self.pari_curve().ellanalyticrank()[0]) + return Integer(self.pari_curve().ellanalyticrank()[0]) elif algorithm == 'rubinstein': if leading_coefficient: raise NotImplementedError("Cannot compute leading coefficient using rubinstein algorithm") @@ -1528,7 +1541,7 @@ def analytic_rank(self, algorithm="pari", leading_coefficient=False): from sage.lfunctions.lcalc import lcalc return lcalc.analytic_rank(L=self) except TypeError as msg: - raise RuntimeError("unable to compute analytic rank using rubinstein algorithm (%s)"%msg) + raise RuntimeError("unable to compute analytic rank using rubinstein algorithm (%s)" % msg) elif algorithm == 'sympow': if leading_coefficient: raise NotImplementedError("Cannot compute leading coefficient using sympow") @@ -1538,7 +1551,7 @@ def analytic_rank(self, algorithm="pari", leading_coefficient=False): if leading_coefficient: raise NotImplementedError("Cannot compute leading coefficient using magma") from sage.interfaces.magma import magma - return rings.Integer(magma(self).AnalyticRank()) + return Integer(magma(self).AnalyticRank()) elif algorithm == 'zero_sum': if leading_coefficient: s = "Cannot compute leading coefficient using the zero sum method" @@ -1554,7 +1567,7 @@ def analytic_rank(self, algorithm="pari", leading_coefficient=False): raise RuntimeError("Bug in analytic_rank; algorithms don't agree! (E=%s)" % self) return list(S)[0] else: - raise ValueError("algorithm %s not defined"%algorithm) + raise ValueError("algorithm %s not defined" % algorithm) def analytic_rank_upper_bound(self, max_Delta=None, @@ -1665,12 +1678,12 @@ def analytic_rank_upper_bound(self, sage: E = EllipticCurve("11a") sage: E.rank() 0 - sage: E.analytic_rank_upper_bound(max_Delta=1,adaptive=False) + sage: E.analytic_rank_upper_bound(max_Delta=1, adaptive=False) 0 sage: E = EllipticCurve([-39,123]) sage: E.rank() 1 - sage: E.analytic_rank_upper_bound(max_Delta=1,adaptive=True) + sage: E.analytic_rank_upper_bound(max_Delta=1, adaptive=True) 1 This is especially true for elliptic curves with large rank. @@ -1680,7 +1693,8 @@ def analytic_rank_upper_bound(self, sage: for r in range(9): ....: E = elliptic_curves.rank(r)[0] ....: print((r, E.analytic_rank_upper_bound(max_Delta=1, - ....: adaptive=False,root_number="ignore"))) + ....: adaptive=False, + ....: root_number="ignore"))) (0, 0) (1, 1) (2, 2) @@ -1699,9 +1713,9 @@ def analytic_rank_upper_bound(self, sage: E = EllipticCurve("974b1") sage: r = E.rank(); r 0 - sage: E.analytic_rank_upper_bound(max_Delta=1,root_number="ignore") + sage: E.analytic_rank_upper_bound(max_Delta=1, root_number="ignore") 1 - sage: E.analytic_rank_upper_bound(max_Delta=1.3,root_number="ignore") + sage: E.analytic_rank_upper_bound(max_Delta=1.3, root_number="ignore") 0 Knowing the root number of `E` allows us to use smaller Delta values @@ -1709,7 +1723,7 @@ def analytic_rank_upper_bound(self, :: - sage: E.analytic_rank_upper_bound(max_Delta=0.6,root_number="compute") + sage: E.analytic_rank_upper_bound(max_Delta=0.6, root_number="compute") 0 There are a small number of curves which have pathologically low-lying @@ -1722,11 +1736,11 @@ def analytic_rank_upper_bound(self, :: sage: E = EllipticCurve([0, -1, 0, -7460362000712, -7842981500851012704]) - sage: N,r = E.conductor(),E.analytic_rank(); N, r + sage: N, r = E.conductor(), E.analytic_rank(); N, r (256944, 0) - sage: E.analytic_rank_upper_bound(max_Delta=1,adaptive=False) + sage: E.analytic_rank_upper_bound(max_Delta=1, adaptive=False) 2 - sage: E.analytic_rank_upper_bound(max_Delta=2,adaptive=False) + sage: E.analytic_rank_upper_bound(max_Delta=2, adaptive=False) 2 This method is can be called on curves with large conductor. @@ -1747,13 +1761,16 @@ def analytic_rank_upper_bound(self, sage: a4 = -20067762415575526585033208209338542750930230312178956502 sage: a6 = 34481611795030556467032985690390720374855944359319180361266008296291939448732243429 - sage: E = EllipticCurve([1,-1,1,a4,a6]) - sage: bad_primes = [2,3,5,7,11,13,17,19,48463] + sage: E = EllipticCurve([1, -1, 1, a4, a6]) + sage: bad_primes = [2, 3, 5, 7, 11, 13, 17, 19, 48463] sage: N = 3455601108357547341532253864901605231198511505793733138900595189472144724781456635380154149870961231592352897621963802238155192936274322687070 - sage: E.analytic_rank_upper_bound(max_Delta=2.37,adaptive=False, # long time - ....: N=N,root_number=1,bad_primes=bad_primes,ncpus=2) # long time + sage: E.analytic_rank_upper_bound(max_Delta=2.37, adaptive=False, # long time + ....: N=N, root_number=1, + ....: bad_primes=bad_primes, ncpus=2) 32 """ + from sage.lfunctions.zero_sums import LFunctionZeroSum_EllipticCurve + Z = LFunctionZeroSum_EllipticCurve(self, N) bound = Z.analytic_rank_upper_bound(max_Delta=max_Delta, adaptive=adaptive, @@ -1768,6 +1785,13 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=3, Return lower and upper bounds on the rank of the Mordell-Weil group `E(\QQ)` and a list of points of infinite order. + .. WARNING:: + + This function is deprecated as the functionality of + Simon's script for elliptic curves over the rationals + has been ported over to pari. + Use :meth:`.rank` with the keyword ``algorithm='pari'`` instead. + INPUT: - ``verbose`` -- 0, 1, 2, or 3 (default: 0), the verbosity level @@ -1820,6 +1844,10 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=3, sage: E = EllipticCurve('11a1') sage: E.simon_two_descent() + doctest:warning + ... + DeprecationWarning: Use E.rank(algorithm="pari") instead, as this script has been ported over to pari. + See https://github.com/sagemath/sage/issues/35621 for details. (0, 0, []) sage: E = EllipticCurve('37a1') sage: E.simon_two_descent() @@ -1856,10 +1884,10 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=3, sage: r, s, G = E.simon_two_descent(); r,s (6, 6) sage: E = EllipticCurve([0, 0, 0, -10012, 346900]) - sage: r, s, G = E.simon_two_descent(); r,s + sage: r, s, G = E.simon_two_descent(); r,s # long time (7, 7) sage: E = EllipticCurve([0, 0, 1, -23737, 960366]) - sage: r, s, G = E.simon_two_descent(); r,s + sage: r, s, G = E.simon_two_descent(); r,s # long time (8, 8) Example from :trac:`10832`:: @@ -1900,6 +1928,9 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=3, sage: E.selmer_rank() # uses mwrank 1 """ + from sage.misc.superseded import deprecation + deprecation(35621, 'Use E.rank(algorithm="pari") instead, as this script has been ported over to pari.') + t = EllipticCurve_number_field.simon_two_descent(self, verbose=verbose, lim1=lim1, lim3=lim3, limtriv=limtriv, maxprob=maxprob, limbigprime=limbigprime, @@ -1908,7 +1939,7 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=3, two_selmer_rank = t[1] pts = t[2] if rank_low_bd == two_selmer_rank - self.two_torsion_rank(): - if verbose>0: + if verbose > 0: print("Rank determined successfully, saturating...") gens = self.saturation(pts)[0] if len(gens) == rank_low_bd: @@ -1969,8 +2000,9 @@ def three_selmer_rank(self, algorithm='UseSUnits'): def rank(self, use_database=True, verbose=False, only_use_mwrank=True, algorithm='mwrank_lib', - proof=None): - """ + proof=None, + pari_effort=0): + r""" Return the rank of this elliptic curve, assuming no conjectures. If we fail to provably compute the rank, raises a RuntimeError @@ -1990,6 +2022,8 @@ def rank(self, use_database=True, verbose=False, - ``'mwrank_lib'`` -- call mwrank c library + - ``'pari'`` -- call ellrank in pari + - ``only_use_mwrank`` -- (default: ``True``) if ``False`` try using analytic rank methods first @@ -1997,9 +2031,15 @@ def rank(self, use_database=True, verbose=False, ``proof.elliptic_curve`` or ``sage.structure.proof``); note that results obtained from databases are considered ``proof=True`` + - ``pari_effort`` -- (default: 0) parameter used in when + the algorithm ``pari`` is chosen. It measure of the effort + done to find rational points. Values up to 10 can be chosen; + the running times increase roughly like the cube of the + effort value. + OUTPUT: the rank of the elliptic curve as :class:`Integer` - IMPLEMENTATION: Uses L-functions, mwrank, and databases. + IMPLEMENTATION: Uses L-functions, mwrank, pari, and databases. EXAMPLES:: @@ -2015,7 +2055,7 @@ def rank(self, use_database=True, verbose=False, 4 sage: EllipticCurve([0, 0, 1, -79, 342]).rank(proof=False) 5 - sage: EllipticCurve([0, 0, 1, -79, 342]).simon_two_descent()[0] # long time (7s on sage.math, 2012) + sage: EllipticCurve([0, 0, 1, -79, 342]).rank(algorithm="pari") 5 Examples with denominators in defining equations:: @@ -2029,7 +2069,7 @@ def rank(self, use_database=True, verbose=False, sage: E.minimal_model().rank() 1 - A large example where mwrank doesn't determine the result with certainty:: + A large example where mwrank doesn't determine the result with certainty, but pari does:: sage: EllipticCurve([1,0,0,0,37455]).rank(proof=False) 0 @@ -2037,6 +2077,8 @@ def rank(self, use_database=True, verbose=False, Traceback (most recent call last): ... RuntimeError: rank not provably correct (lower bound: 0) + sage: EllipticCurve([1,0,0,0,37455]).rank(algorithm="pari") + 0 TESTS:: @@ -2045,6 +2087,14 @@ def rank(self, use_database=True, verbose=False, ... ValueError: unknown algorithm 'garbage' + An example to check if the points are saturated:: + + sage: E = EllipticCurve([0,0, 1, -7, 6]) + sage: E.gens(use_database=False, algorithm="pari") # random + [(2 : 0 : 1), (-1 : 3 : 1), (11 : 35 : 1)] + sage: E.saturation(_)[1] + 1 + Since :trac:`23962`, the default is to use the Cremona database. We also check that the result is cached correctly:: @@ -2059,6 +2109,15 @@ def rank(self, use_database=True, verbose=False, 0 sage: E._EllipticCurve_rational_field__rank (0, True) + + This example has Sha = Z/4 x Z/4 and the rank cannot be + determined using pari only:: + + sage: E =EllipticCurve([-113^2,0]) + sage: E.rank(use_database=False, verbose=False, algorithm="pari") + Traceback (most recent call last): + ... + RuntimeError: rank not provably correct (lower bound: 0, upper bound:2). Hint: increase pari_effort. """ if proof is None: from sage.structure.proof.proof import get_flag @@ -2086,7 +2145,7 @@ def rank(self, use_database=True, verbose=False, # true rank rank_bound = self.analytic_rank_upper_bound() if rank_bound <= 1: - verbose_verbose("rank %s due to zero sum bound and parity"%rank_bound) + verbose_verbose("rank %s due to zero sum bound and parity" % rank_bound) rank = Integer(rank_bound) self.__rank = (rank, proof) return rank @@ -2104,7 +2163,7 @@ def rank(self, use_database=True, verbose=False, else: Lprime, err = self.lseries().deriv_at1(prec) if abs(Lprime) > err + R(0.0001): # definitely doesn't vanish - verbose_verbose("rank 1 because L'(E,1)=%s"%Lprime) + verbose_verbose("rank 1 because L'(E,1)=%s" % Lprime) rank = Integer(1) self.__rank = (rank, proof) return rank @@ -2135,7 +2194,7 @@ def rank(self, use_database=True, verbose=False, X = self.mwrank() if 'determined unconditionally' not in X or 'only a lower bound of' in X: if proof: - X= "".join(X.split("\n")[-4:-2]) + X = "".join(X.split("\n")[-4:-2]) print(X) raise RuntimeError('rank not provably correct') else: @@ -2153,12 +2212,33 @@ def rank(self, use_database=True, verbose=False, match = 'found points of rank' i = X.find(match) if i == -1: - raise RuntimeError("%s\nbug -- tried to find 'Rank =' or 'found points of rank' in mwrank output but couldn't."%X) + raise RuntimeError("%s\nbug -- tried to find 'Rank =' or 'found points of rank' in mwrank output but couldn't." % X) j = i + X[i:].find('\n') rank = Integer(X[i+len(match)+1:j]) self.__rank = (rank, proof) return rank + if algorithm == 'pari': + ep = self.pari_curve() + # if we know already some points in _known_points + # we can give them to pari to speed it up + kpts = [ [x[0],x[1]] for x in self._known_points ] + lower, upper, s, pts = ep.ellrank(pari_effort, kpts) + ge = sorted([self.point([QQ(x[0]),QQ(x[1])], check=True) for x in pts]) + ge = self.saturation(ge)[0] + self._known_points = ge + # note that lower is only a conjectural + # lower bound for the rank, the only + # proven lower bound is #ge. + if len(ge) == upper: + verbose_verbose(f"rank {upper} unconditionally determined by pari") + rank = Integer(upper) + self.__rank = (rank, True) + self.__gens = (ge, True) + return rank + else: + verbose_verbose(f"Warning -- rank could not be determined by pari; ellrank returned {lower=}, {upper=}, {s=}, {pts=}", level=1) + raise RuntimeError(f"rank not provably correct (lower bound: {len(ge)}, upper bound:{upper}). Hint: increase pari_effort.") raise ValueError("unknown algorithm {!r}".format(algorithm)) def gens(self, proof=None, **kwds): @@ -2185,6 +2265,8 @@ def gens(self, proof=None, **kwds): - ``'mwrank_lib'`` -- call mwrank C library + - ``'pari'`` -- use ellrank in pari + - ``only_use_mwrank`` -- bool (default True) if False, first attempts to use more naive, natively implemented methods @@ -2198,6 +2280,12 @@ def gens(self, proof=None, **kwds): points found by two-descent in the Mordell-Weil group is greater than this, a warning message will be displayed. + - ``pari_effort`` -- (default: 0) parameter used in when + the algorithm ``pari`` is chosen. It measure of the effort + done to find rational points. Values up to 10 can be chosen, + the running times increase roughly like the cube of the + effort value. + OUTPUT: - ``generators`` -- list of generators for the Mordell-Weil @@ -2209,13 +2297,18 @@ def gens(self, proof=None, **kwds): :meth:`~gens_certain` method to find out afterwards whether the generators were proved. - IMPLEMENTATION: Uses Cremona's mwrank C library. + IMPLEMENTATION: Uses Cremona's mwrank C++ library or ellrank in pari. EXAMPLES:: sage: E = EllipticCurve('389a') sage: E.gens() # random output [(-1 : 1 : 1), (0 : 0 : 1)] + sage: E.gens(algorithm="pari") # random output + [(5/4 : 5/8 : 1), (0 : 0 : 1)] + sage: E = EllipticCurve([0,2429469980725060,0,275130703388172136833647756388,0]) + sage: len(E.gens(algorithm="pari")) # not tested (takes too long) + 14 A non-integral example:: @@ -2227,9 +2320,29 @@ def gens(self, proof=None, **kwds): sage: E = EllipticCurve('389a1') sage: E1 = E.change_weierstrass_model([1/20,0,0,0]); E1 - Elliptic Curve defined by y^2 + 8000*y = x^3 + 400*x^2 - 320000*x over Rational Field + Elliptic Curve defined by y^2 + 8000*y = x^3 + 400*x^2 - 320000*x + over Rational Field sage: E1.gens() # random (if database not used) [(-400 : 8000 : 1), (0 : -8000 : 1)] + sage: E1.gens(algorithm="pari") #random + [(-400 : 8000 : 1), (0 : -8000 : 1)] + + TESTS:: + + sage: E = EllipticCurve('389a') + sage: len(E.gens()) + 2 + sage: E.saturation(E.gens())[1] + 1 + sage: len(E.gens(algorithm="pari")) + 2 + sage: E.saturation(E.gens(algorithm="pari"))[1] + 1 + sage: E = EllipticCurve([-3/8,-2/3]) + sage: P = E.lift_x(10/9) + sage: set(E.gens()) <= set([P,-P]) + True + """ if proof is None: from sage.structure.proof.proof import get_flag @@ -2256,7 +2369,8 @@ def _compute_gens(self, proof, only_use_mwrank=True, use_database=True, descent_second_limit=12, - sat_bound=1000): + sat_bound=1000, + pari_effort=0): r""" Return generators for the Mordell-Weil group `E(Q)` *modulo* torsion. @@ -2279,6 +2393,31 @@ def _compute_gens(self, proof, sage: gens, proved = E._compute_gens(proof=False) sage: proved True + + sage: E = EllipticCurve([-127^2,0]) + sage: E.gens(use_database=False, algorithm="pari",pari_effort=4) # random + [(611429153205013185025/9492121848205441 : 15118836457596902442737698070880/924793900700594415341761 : 1)] + + TESTS:: + + sage: P = E.lift_x(611429153205013185025/9492121848205441) + sage: set(E.gens(use_database=False, algorithm="pari",pari_effort=4)) <= set([P+T for T + ....: in E.torsion_points()] + [-P+T for T in E.torsion_points()]) + True + + sage: E = EllipticCurve([-157^2,0]) + sage: E.gens(use_database=False, algorithm="pari") + Traceback (most recent call last): + ... + RuntimeError: generators could not be determined. So far we found []. Hint: increase pari_effort. + sage: ge = E.gens(use_database=False, algorithm="pari",pari_effort=10) + sage: ge #random + [(-166136231668185267540804/2825630694251145858025 : 167661624456834335404812111469782006/150201095200135518108761470235125 : 1)] + sage: P = E.lift_x(-166136231668185267540804/2825630694251145858025) + sage: set(E.gens(use_database=False, algorithm="pari",pari_effort=4)) <= set([P+T for T + ....: in E.torsion_points()] + [-P+T for T in E.torsion_points()]) + True + """ # If the optional extended database is installed and an # isomorphic curve is in the database then its gens will be @@ -2310,7 +2449,7 @@ def _compute_gens(self, proof, verbose_verbose("Rank = 1, so using direct search.") h = 6 while h <= rank1_search: - verbose_verbose("Trying direct search up to height %s"%h) + verbose_verbose("Trying direct search up to height %s" % h) G = self.point_search(h, verbose) G = [P for P in G if P.order() == oo] if G: @@ -2323,7 +2462,29 @@ def _compute_gens(self, proof, except RuntimeError: pass # end if (not_use_mwrank) - if algorithm == "mwrank_lib": + if algorithm == "pari": + ep = self.pari_curve() + # if we know already some points in _known_points + # we can give them to pari to speed it up + kpts = [ [x[0],x[1]] for x in self._known_points ] + lower, upper, s, pts = ep.ellrank(pari_effort, kpts) + ge = sorted([self.point([QQ(x[0]),QQ(x[1])], check=True) for x in pts]) + ge = self.saturation(ge)[0] + self._known_points = ge + # note that lower is only a conjectural + # lower bound for the rank, the only + # proven lower bound is #ge. + if len(ge) == upper: + verbose_verbose(f"rank {upper} unconditionally determined by pari") + rank = Integer(upper) + self.__rank = (rank, True) + if len(ge) == rank: + self.__gens = (ge, True) + return ge, True + # cases when we did not find all points + verbose_verbose(f"Warning -- generators could not be determined by pari; ellrank returned {lower=}, {upper=}, {s=}, {pts=}", level=1) + raise RuntimeError(f"generators could not be determined. So far we found {ge}. Hint: increase pari_effort.") + elif algorithm == "mwrank_lib": verbose_verbose("Calling mwrank C++ library.") if not self.is_integral(): xterm = 1 @@ -2332,7 +2493,7 @@ def _compute_gens(self, proof, for a in ai: if not a.is_integral(): for p, _ in a.denom().factor(): - e = min((ai[i].valuation(p)/[1,2,3,4,6][i]) + e = min((ai[i].valuation(p)/[1,2,3,4,6][i]) for i in range(5)).floor() ai = [ai[i]/p**(e*[1,2,3,4,6][i]) for i in range(5)] xterm *= p**(2*e) @@ -2343,17 +2504,17 @@ def _compute_gens(self, proof, xterm = 1 yterm = 1 C = E.mwrank_curve(verbose) - if not (verbose is None): + if verbose is not None: C.set_verbose(verbose) C.two_descent(verbose=verbose, second_limit=descent_second_limit) C.saturate(bound=sat_bound) G = C.gens() if proof is True and C.certain() is False: del self.__mwrank_curve - raise RuntimeError("Unable to compute the rank, hence generators, with certainty (lower bound=%s, generators found=%s). This could be because Sha(E/Q)[2] is nontrivial."%(C.rank(),G) + \ - "\nTry increasing descent_second_limit then trying this command again.") + raise RuntimeError("Unable to compute the rank, hence generators, with certainty (lower bound=%s, generators found=%s). This could be because Sha(E/Q)[2] is nontrivial." % (C.rank(), G) + + "\nTry increasing descent_second_limit then trying this command again.") proved = C.certain() - G = [[x*xterm,y*yterm,z] for x, y, z in G] + G = [[x*xterm, y*yterm, z] for x, y, z in G] else: # when gens() calls mwrank it passes the command-line # parameter "-p 100" which helps curves with large @@ -2388,7 +2549,7 @@ def _compute_gens(self, proof, return G, proved def gens_certain(self): - """ + r""" Return ``True`` if the generators have been proven correct. EXAMPLES:: @@ -2401,6 +2562,11 @@ def gens_certain(self): TESTS:: + sage: E = EllipticCurve('37a1') + sage: P = E([0,-1]) + sage: set(E.gens()) <= set([P,-P]) + True + sage: E = EllipticCurve([2, 4, 6, 8, 10]) sage: E.gens_certain() Traceback (most recent call last): @@ -2473,7 +2639,7 @@ def regulator(self, proof=None, precision=53, **kwds): sage: EllipticCurve([0, 0, 1, -79, 342]).regulator(proof=False) # long time (6s on sage.math, 2011) 14.790527570131... """ - R = rings.RealField(precision) + R = RealField(precision) if proof is None: from sage.structure.proof.proof import get_flag @@ -2626,7 +2792,7 @@ def saturation(self, points, verbose=False, max_prime=-1, min_prime=2): if not isinstance(P, ell_point.EllipticCurvePoint_field): P = self(P) elif P.curve() != self: - raise ArithmeticError("point (=%s) must be %s."%(P,self)) + raise ArithmeticError("point (=%s) must be %s." % (P,self)) minimal = True if not self.is_minimal(): @@ -2699,7 +2865,6 @@ def CPS_height_bound(self): raise RuntimeError("curve must be minimal.") return self.mwrank_curve().CPS_height_bound() - def silverman_height_bound(self, algorithm='default'): r""" Return the Silverman height bound. @@ -2746,9 +2911,9 @@ def silverman_height_bound(self, algorithm='default'): 0.16397076103046915 """ if algorithm == 'default': - Delta = self.discriminant() - j = self.j_invariant() - b2 = self.b2() + Delta = self.discriminant() + j = self.j_invariant() + b2 = self.b2() twostar = 2 if b2 else 1 from math import log @@ -2757,14 +2922,14 @@ def h(x): def h_oo(x): return log(max(abs(x), 1)) - mu = h(Delta)/12 + h_oo(j)/12 + h_oo(b2/12)/2 + log(twostar)/2 + mu = h(Delta)/12 + h_oo(j)/12 + h_oo(b2/12)/2 + log(twostar)/2 lower = 2*(-h(j)/24 - mu - 0.961) upper = 2*(mu + 1.07) return max(abs(lower), abs(upper)) elif algorithm == 'mwrank': return self.mwrank_curve().silverman_bound() else: - raise ValueError("unknown algorithm '%s'"%algorithm) + raise ValueError("unknown algorithm '%s'" % algorithm) def point_search(self, height_limit, verbose=False, rank_bound=None): r""" @@ -2798,13 +2963,13 @@ def point_search(self, height_limit, verbose=False, rank_bound=None): EXAMPLES:: sage: E = EllipticCurve('389a1') - sage: E.point_search(5, verbose=False) + sage: E.point_search(1, verbose=False) [(-1 : 1 : 1), (0 : 0 : 1)] Increasing the height_limit takes longer, but finds no more points:: - sage: E.point_search(10, verbose=False) + sage: E.point_search(10, verbose=False) # long time [(-1 : 1 : 1), (0 : 0 : 1)] In fact this curve has rank 2 so no more than 2 points will ever be @@ -2844,86 +3009,118 @@ def point_search(self, height_limit, verbose=False, rank_bound=None): points = self.saturation(points, verbose=verbose)[0] return points - def selmer_rank(self): + def selmer_rank(self, algorithm="pari"): r""" - The rank of the 2-Selmer group of the curve. - - EXAMPLES: The following is the curve 960D1, which has rank 0, but - Sha of order 4. + Return the rank of the 2-Selmer group of the curve. - :: + INPUT: - sage: E = EllipticCurve([0, -1, 0, -900, -10098]) - sage: E.selmer_rank() - 3 + - ``algorithm`` -- (default:``'pari'``) + either ``'pari'`` or ``'mwrank'`` - Here the Selmer rank is equal to the 2-torsion rank (=1) plus - the 2-rank of Sha (=2), and the rank itself is zero:: + EXAMPLES: + This example has rank 1, Sha[2] of order 4 and + a single rational 2-torsion point:: - sage: E.rank() - 0 + sage: E = EllipticCurve([1, 1, 1, 508, -2551]) + sage: E.selmer_rank() + 4 + sage: E.selmer_rank(algorithm="mwrank") + 4 - In contrast, for the curve 571A, also with rank 0 and Sha of - order 4, we get a worse bound:: + The following is the curve 960d1, which has rank 0, but + Sha of order 4:: - sage: E = EllipticCurve([0, -1, 1, -929, -10595]) + sage: E = EllipticCurve([0, -1, 0, -900, -10098]) sage: E.selmer_rank() - 2 - sage: E.rank_bound() - 2 + 3 + sage: E.selmer_rank(algorithm="mwrank") + 3 - To establish that the rank is in fact 0 in this case, we would - need to carry out a higher descent:: + This curve has rank 1, and 4 elements in Sha[2]. + Yet the order of Sha is 16, so that group is the product + of two cyclic groups of order 4:: - sage: E.three_selmer_rank() # optional - magma - 0 + sage: E = EllipticCurve([1, 0, 0, -150752, -22541610]) + sage: E.selmer_rank() + 4 - Or use the L-function to compute the analytic rank:: + Instead in this last example of rank 0, Sha is a product of four cyclic groups of order 2:: - sage: E.rank(only_use_mwrank=False) + sage: E = EllipticCurve([1, 0, 0, -49280, -4214808]) + sage: E.selmer_rank() + 5 + sage: E.rank() 0 """ try: return self.__selmer_rank except AttributeError: - C = self.mwrank_curve() - self.__selmer_rank = C.selmer_rank() - return self.__selmer_rank + if algorithm == "pari": + ep = self.pari_curve() + lower, upper, s, pts = ep.ellrank() + tor = self.two_torsion_rank() + return upper + tor + s + elif algorithm == "mwrank": + C = self.mwrank_curve() + self.__selmer_rank = C.selmer_rank() + return self.__selmer_rank + else: + raise ValueError(f"unknown {algorithm=}") - def rank_bound(self): + def rank_bound(self, algorithm="pari"): r""" - Upper bound on the rank of the curve, computed using - 2-descent. + Return the upper bound on the rank of the curve, + computed using a 2-descent. + + INPUT: + + - ``algorithm`` -- (default:``'pari'``) + either ``'pari'`` or ``'mwrank'`` In many cases, this is the actual rank of the - curve. If the curve has no 2-torsion it is the same as the - 2-selmer rank. + curve. - EXAMPLES: The following is the curve 960D1, which has rank 0, but - Sha of order 4. + EXAMPLES:: - :: + sage: E = EllipticCurve("389a1") + sage: E.rank_bound() + 2 - sage: E = EllipticCurve([0, -1, 0, -900, -10098]) + The following is the curve 571a1, which has + rank 0, but Sha of order 4, yet pari, using the Cassels + pairing is able to show that the rank is 0. + The 2-descent in mwrank only determines a weaker upper bound:: + + sage: E = EllipticCurve([0, -1, 1, -929, -10595]) sage: E.rank_bound() 0 + sage: E.rank_bound(algorithm="mwrank") + 2 - It gives 0 instead of 2, because it knows Sha is nontrivial. In - contrast, for the curve 571A, also with rank 0 and Sha of order 4, - we get a worse bound:: + In the following last example, both algorithm only determine a rank bound larger than the actual rank:: - sage: E = EllipticCurve([0, -1, 1, -929, -10595]) + sage: E = EllipticCurve([1, 1, 1, -896670, -327184905]) sage: E.rank_bound() 2 - sage: E.rank(only_use_mwrank=False) # uses L-function + sage: E.rank_bound(algorithm="mwrank") + 2 + sage: E.rank(only_use_mwrank=False) # uses L-function 0 """ try: return self.__rank_bound except AttributeError: - C = self.mwrank_curve() - self.__rank_bound = C.rank_bound() - return self.__rank_bound + if algorithm == "pari": + ep = self.pari_curve() + lower, upper, s, pts = ep.ellrank() + return upper + elif algorithm == "mwrank": + C = self.mwrank_curve() + self.__rank_bound = C.rank_bound() + return self.__rank_bound + else: + raise ValueError(f"unknown {algorithm=}") def an(self, n): r""" @@ -2939,7 +3136,7 @@ def an(self, n): return Integer(self.pari_mincurve().ellak(n)) def ap(self, p): - """ + r""" The ``p``-th Fourier coefficient of the modular form corresponding to this elliptic curve, where ``p`` is prime. @@ -3000,7 +3197,7 @@ def is_minimal(self): return self.ainvs() == self.minimal_model().ainvs() def is_p_minimal(self, p): - """ + r""" Tests if curve is ``p``-minimal at a given prime ``p``. INPUT: @@ -3171,15 +3368,15 @@ def tamagawa_exponent(self, p): if not arith.is_prime(p): raise ArithmeticError("p must be prime") cp = self.tamagawa_number(p) - if not cp==4: + if not cp == 4: return cp ks = self.kodaira_type(p) - if ks._roman==1 and ks._n%2==0 and ks._starred: + if ks._roman == 1 and ks._n % 2 == 0 and ks._starred: return 2 return 4 def tamagawa_product(self): - """ + r""" Return the product of the Tamagawa numbers. EXAMPLES:: @@ -3195,7 +3392,7 @@ def tamagawa_product(self): return self.__tamagawa_product def real_components(self): - """ + r""" Return the number of real components. EXAMPLES:: @@ -3255,15 +3452,16 @@ def period_lattice(self, embedding=None): OUTPUT: - (period lattice) The PeriodLattice_ell object associated to - this elliptic curve (with respect to the natural embedding of + (period lattice) The :class:`~sage.schemes.elliptic_curves.period_lattice.PeriodLattice_ell` + object associated to this elliptic curve (with respect to the natural embedding of `\QQ` into `\RR`). EXAMPLES:: sage: E = EllipticCurve('37a') sage: E.period_lattice() - Period lattice associated to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + Period lattice associated to + Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field """ try: return self._period_lattice @@ -3327,13 +3525,13 @@ def elliptic_exponential(self, z, embedding=None): sage: E.division_polynomial(3).roots(CC,multiplicities=False) [-2.88288879135..., - 1.39292799513..., - 0.078313731444316... - 0.492840991709...*I, - 0.078313731444316... + 0.492840991709...*I] + 1.39292799513..., + 0.078313731444316... - 0.492840991709...*I, + 0.078313731444316... + 0.492840991709...*I] sage: [E.elliptic_exponential((a*w1+b*w2)/3)[0] for a,b in [(0,1),(1,0),(1,1),(2,1)]] [-2.8828887913533..., 1.39292799513138, - 0.0783137314443... - 0.492840991709...*I, - 0.0783137314443... + 0.492840991709...*I] + 0.0783137314443... - 0.492840991709...*I, + 0.0783137314443... + 0.492840991709...*I] Observe that this is a group homomorphism (modulo rounding error):: @@ -3351,7 +3549,7 @@ def elliptic_exponential(self, z, embedding=None): return self.period_lattice().elliptic_exponential(z) def lseries(self): - """ + r""" Return the L-series of this elliptic curve. Further documentation is available for the functions which apply to @@ -3395,7 +3593,9 @@ def lseries_gross_zagier(self, A): sage: A = K.class_group().gen(0); A Fractional ideal class (2, 1/2*a) sage: L = E.lseries_gross_zagier(A) ; L - Gross Zagier L-series attached to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field with ideal class Fractional ideal class (2, 1/2*a) + Gross Zagier L-series attached to + Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + with ideal class Fractional ideal class (2, 1/2*a) sage: L(1) 0.000000000000000 sage: L.taylor_series(1, 5) @@ -3433,10 +3633,10 @@ def Lambda(self, s, prec): EXAMPLES:: sage: E = EllipticCurve('389a') - sage: E.Lambda(1.4+0.5*I, 50) + sage: E.Lambda(1.4 + 0.5*I, 50) -0.354172680517... + 0.874518681720...*I """ - from sage.all import pi + from sage.symbolic.constants import pi s = C(s) N = self.conductor() @@ -3456,7 +3656,7 @@ def is_local_integral_model(self, *p): EXAMPLES:: - sage: E = EllipticCurve([1/2,1/5,1/5,1/5,1/5]) + sage: E = EllipticCurve([1/2, 1/5, 1/5, 1/5, 1/5]) sage: [E.is_local_integral_model(p) for p in (2,3,5)] [False, True, False] sage: E.is_local_integral_model(2,3,5) @@ -3488,7 +3688,7 @@ def local_integral_model(self, p): """ assert p.is_prime(), "p must be prime in local_integral_model()" ai = self.a_invariants() - e = min([(ai[i].valuation(p)/[1,2,3,4,6][i]) for i in range(5)]).floor() + e = min([(ai[i].valuation(p)/[1,2,3,4,6][i]) for i in range(5)]).floor() return constructor.EllipticCurve([ai[i]/p**(e*[1,2,3,4,6][i]) for i in range(5)]) def is_global_integral_model(self): @@ -3497,7 +3697,7 @@ def is_global_integral_model(self): EXAMPLES:: - sage: E = EllipticCurve([1/2,1/5,1/5,1/5,1/5]) + sage: E = EllipticCurve([1/2, 1/5, 1/5, 1/5, 1/5]) sage: E.is_global_integral_model() False sage: Emin=E.global_integral_model() @@ -3522,7 +3722,7 @@ def global_integral_model(self): for a in ai: if not a.is_integral(): for p, _ in a.denom().factor(): - e = min((ai[i].valuation(p)/[1,2,3,4,6][i]) + e = min((ai[i].valuation(p)/[1,2,3,4,6][i]) for i in range(5)).floor() ai = [ai[i]/p**(e*[1,2,3,4,6][i]) for i in range(5)] for z in ai: @@ -3586,8 +3786,8 @@ def _generalized_congmod_numbers(self, M, invariant="both"): EXAMPLES:: sage: E = EllipticCurve('37a') - sage: for M in range(2,8): # long time (22s on 2009 MBP) - ....: print((M, E.modular_degree(M=M),E.congruence_number(M=M))) + sage: for M in range(2, 8): # long time (22s on 2009 MBP) + ....: print((M, E.modular_degree(M=M), E.congruence_number(M=M))) (2, 5, 20) (3, 7, 28) (4, 50, 400) @@ -3619,7 +3819,7 @@ def _generalized_congmod_numbers(self, M, invariant="both"): if invariant in ["moddeg", "both"]: V = A.integral_structure() W = B.integral_structure() - moddeg = (V + W).index_in(S.integral_structure()) + moddeg = (V + W).index_in(S.integral_structure()) L["moddeg"] = moddeg self.__generalized_modular_degree[M] = moddeg @@ -3630,7 +3830,6 @@ def _generalized_congmod_numbers(self, M, invariant="both"): return L - def modular_degree(self, algorithm='sympow', M=1): r""" Return the modular degree at level `MN` of this elliptic curve. The case @@ -3750,9 +3949,9 @@ def modular_degree(self, algorithm='sympow', M=1): m = sympow.modular_degree(self) elif algorithm == 'magma': from sage.interfaces.magma import magma - m = rings.Integer(magma(self).ModularDegree()) + m = Integer(magma(self).ModularDegree()) else: - raise ValueError("unknown algorithm %s"%algorithm) + raise ValueError("unknown algorithm %s" % algorithm) self.__modular_degree = m return m @@ -3764,7 +3963,6 @@ def modular_degree(self, algorithm='sympow', M=1): # self._generalized_congmod_numbers() also populates cache return self._generalized_congmod_numbers(M)["moddeg"] - def modular_parametrization(self): r""" Return the modular parametrization of this elliptic curve, which is @@ -3774,7 +3972,10 @@ def modular_parametrization(self): sage: E = EllipticCurve('15a') sage: phi = E.modular_parametrization(); phi - Modular parameterization from the upper half plane to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field + Modular parameterization + from the upper half plane + to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 + over Rational Field sage: z = 0.1 + 0.2j sage: phi(z) (8.20822465478531 - 13.1562816054682*I : -8.79855099049364 + 69.4006129342200*I : 1.00000000000000) @@ -3788,7 +3989,7 @@ def modular_parametrization(self): We can also get a series expansion of this modular parameterization:: sage: E = EllipticCurve('389a1') - sage: X,Y=E.modular_parametrization().power_series() + sage: X, Y = E.modular_parametrization().power_series() sage: X q^-2 + 2*q^-1 + 4 + 7*q + 13*q^2 + 18*q^3 + 31*q^4 + 49*q^5 + 74*q^6 + 111*q^7 + 173*q^8 + 251*q^9 + 379*q^10 + 560*q^11 + 824*q^12 + 1199*q^13 + 1773*q^14 + 2548*q^15 + 3722*q^16 + 5374*q^17 + O(q^18) sage: Y @@ -3871,7 +4072,7 @@ def congruence_number(self, M=1): 1 """ # Case 1: M==1 - if M==1: + if M == 1: try: return self.__congruence_number except AttributeError: @@ -3897,9 +4098,8 @@ def congruence_number(self, M=1): # self._generalized_congmod_numbers() also populates cache return self._generalized_congmod_numbers(M)["congnum"] - def cremona_label(self, space=False): - """ + r""" Return the Cremona label associated to (the minimal model) of this curve, if it is known. If not, raise a ``LookupError`` exception. @@ -3927,7 +4127,8 @@ def cremona_label(self, space=False): sage: E.cremona_label() Traceback (most recent call last): ... - LookupError: Cremona database does not contain entry for Elliptic Curve defined by y^2 + y = x^3 - 79*x + 342 over Rational Field + LookupError: Cremona database does not contain entry for + Elliptic Curve defined by y^2 + y = x^3 - 79*x + 342 over Rational Field """ try: label = self.__cremona_label @@ -3974,23 +4175,23 @@ def reduction(self,p): Traceback (most recent call last): ... AttributeError: The curve must have good reduction at p. - sage: E = EllipticCurve([5^4,5^6]) + sage: E = EllipticCurve([5^4, 5^6]) sage: E.reduction(5) Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 """ - p = rings.Integer(p) + p = Integer(p) if not p.is_prime(): raise AttributeError("p must be prime.") disc = self.discriminant() if not disc.valuation(p) == 0: - local_data=self.local_data(p) + local_data = self.local_data(p) if local_data.has_good_reduction(): - return local_data.minimal_model().change_ring(rings.GF(p)) + return local_data.minimal_model().change_ring(GF(p)) raise AttributeError("The curve must have good reduction at p.") - return self.change_ring(rings.GF(p)) + return self.change_ring(GF(p)) def torsion_order(self): - """ + r""" Return the order of the torsion subgroup. EXAMPLES:: @@ -4060,14 +4261,16 @@ def torsion_subgroup(self): EXAMPLES:: sage: EllipticCurve('11a').torsion_subgroup() - Torsion Subgroup isomorphic to Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Torsion Subgroup isomorphic to Z/5 associated to the + Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: EllipticCurve('37b').torsion_subgroup() - Torsion Subgroup isomorphic to Z/3 associated to the Elliptic Curve defined by y^2 + y = x^3 + x^2 - 23*x - 50 over Rational Field + Torsion Subgroup isomorphic to Z/3 associated to the + Elliptic Curve defined by y^2 + y = x^3 + x^2 - 23*x - 50 over Rational Field :: - sage: e = EllipticCurve([-1386747,368636886]);e - Elliptic Curve defined by y^2 = x^3 - 1386747*x + 368636886 over Rational Field + sage: e = EllipticCurve([-1386747,368636886]); e + Elliptic Curve defined by y^2 = x^3 - 1386747*x + 368636886 over Rational Field sage: G = e.torsion_subgroup(); G Torsion Subgroup isomorphic to Z/8 + Z/2 associated to the Elliptic Curve defined by y^2 = x^3 - 1386747*x + 368636886 over @@ -4077,7 +4280,10 @@ def torsion_subgroup(self): sage: G.1 (282 : 0 : 1) sage: list(G) - [(0 : 1 : 0), (147 : -12960 : 1), (2307 : -97200 : 1), (-933 : -29160 : 1), (1011 : 0 : 1), (-933 : 29160 : 1), (2307 : 97200 : 1), (147 : 12960 : 1), (-1293 : 0 : 1), (1227 : 22680 : 1), (-285 : 27216 : 1), (8787 : 816480 : 1), (282 : 0 : 1), (8787 : -816480 : 1), (-285 : -27216 : 1), (1227 : -22680 : 1)] + [(0 : 1 : 0), (147 : -12960 : 1), (2307 : -97200 : 1), (-933 : -29160 : 1), + (1011 : 0 : 1), (-933 : 29160 : 1), (2307 : 97200 : 1), (147 : 12960 : 1), + (-1293 : 0 : 1), (1227 : 22680 : 1), (-285 : 27216 : 1), (8787 : 816480 : 1), + (282 : 0 : 1), (8787 : -816480 : 1), (-285 : -27216 : 1), (1227 : -22680 : 1)] """ try: G = self.__torsion_subgroup @@ -4089,7 +4295,7 @@ def torsion_subgroup(self): return self.__torsion_subgroup def torsion_points(self): - """ + r""" Return the torsion points of this elliptic curve as a sorted list. @@ -4245,7 +4451,7 @@ def cm_discriminant(self): Return the associated quadratic discriminant if this elliptic curve has Complex Multiplication over the algebraic closure. - A ValueError is raised if the curve does not have CM (see the + A :class:`ValueError` is raised if the curve does not have CM (see the function :meth:`has_cm()`). EXAMPLES:: @@ -4260,13 +4466,14 @@ def cm_discriminant(self): sage: E.cm_discriminant() Traceback (most recent call last): ... - ValueError: Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field does not have CM + ValueError: Elliptic Curve defined by y^2 + y = x^3 - x + over Rational Field does not have CM """ try: return ZZ(CMJ[self.j_invariant()]) except KeyError: - raise ValueError("%s does not have CM"%self) + raise ValueError("%s does not have CM" % self) def has_rational_cm(self, field=None): r""" @@ -4307,7 +4514,7 @@ def has_rational_cm(self, field=None): If we extend scalars to a field in which the discriminant is a square, the CM becomes rational:: - sage: E.has_rational_cm(QuadraticField(-3)) + sage: E.has_rational_cm(QuadraticField(-3)) # needs sage.rings.number_field True sage: E = EllipticCurve(j=8000) @@ -4321,7 +4528,7 @@ def has_rational_cm(self, field=None): Again, we may extend scalars to a field in which the discriminant is a square, where the CM becomes rational:: - sage: E.has_rational_cm(QuadraticField(-2)) + sage: E.has_rational_cm(QuadraticField(-2)) # needs sage.rings.number_field True The field need not be a number field provided that it is an @@ -4338,7 +4545,8 @@ def has_rational_cm(self, field=None): sage: E.has_rational_cm(GF(2)) Traceback (most recent call last): ... - ValueError: Error in has_rational_cm: Finite Field of size 2 is not an extension field of QQ + ValueError: Error in has_rational_cm: Finite Field of size 2 + is not an extension field of QQ """ if field is None: return False @@ -4347,7 +4555,7 @@ def has_rational_cm(self, field=None): except ValueError: return False try: - if field.characteristic()==0: + if field.characteristic() == 0: D = field(D) return D.is_square() raise ValueError("Error in has_rational_cm: %s is not an extension field of QQ" % field) @@ -4355,15 +4563,15 @@ def has_rational_cm(self, field=None): raise ValueError("Error in has_rational_cm: %s is not an extension field of QQ" % field) def quadratic_twist(self, D): - """ + r""" Return the global minimal model of the quadratic twist of this curve by ``D``. EXAMPLES:: sage: E = EllipticCurve('37a1') - sage: E7=E.quadratic_twist(7); E7 - Elliptic Curve defined by y^2 = x^3 - 784*x + 5488 over Rational Field + sage: E7 = E.quadratic_twist(7); E7 + Elliptic Curve defined by y^2 = x^3 - 784*x + 5488 over Rational Field sage: E7.conductor() 29008 sage: E7.quadratic_twist(7) == E @@ -4462,7 +4670,6 @@ def minimal_quadratic_twist(self): return Et, D - ########################################################## # Isogeny class ########################################################## @@ -4666,16 +4873,27 @@ def isogenies_prime_degree(self, l=None): [] sage: E = EllipticCurve(j = -262537412640768000) sage: E.isogenies_prime_degree() - [Isogeny of degree 163 from Elliptic Curve defined by y^2 + y = x^3 - 2174420*x + 1234136692 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - 57772164980*x - 5344733777551611 over Rational Field] + [Isogeny of degree 163 + from Elliptic Curve defined by y^2 + y = x^3 - 2174420*x + 1234136692 over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - 57772164980*x - 5344733777551611 over Rational Field] sage: E1 = E.quadratic_twist(6584935282) sage: E1.isogenies_prime_degree() - [Isogeny of degree 163 from Elliptic Curve defined by y^2 = x^3 - 94285835957031797981376080*x + 352385311612420041387338054224547830898 over Rational Field to Elliptic Curve defined by y^2 = x^3 - 2505080375542377840567181069520*x - 1526091631109553256978090116318797845018020806 over Rational Field] + [Isogeny of degree 163 + from Elliptic Curve defined by y^2 = x^3 - 94285835957031797981376080*x + 352385311612420041387338054224547830898 over Rational Field + to Elliptic Curve defined by y^2 = x^3 - 2505080375542377840567181069520*x - 1526091631109553256978090116318797845018020806 over Rational Field] sage: E = EllipticCurve('14a1') sage: E.isogenies_prime_degree(2) - [Isogeny of degree 2 from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - 36*x - 70 over Rational Field] + [Isogeny of degree 2 + from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 - 36*x - 70 over Rational Field] sage: E.isogenies_prime_degree(3) - [Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - x over Rational Field, Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - 171*x - 874 over Rational Field] + [Isogeny of degree 3 + from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 - x over Rational Field, + Isogeny of degree 3 + from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 - 171*x - 874 over Rational Field] sage: E.isogenies_prime_degree(5) [] sage: E.isogenies_prime_degree(11) @@ -4696,9 +4914,9 @@ def isogenies_prime_degree(self, l=None): if l.is_prime(proof=False): return isogenies_sporadic_Q(self, l) else: - raise ValueError("%s is not prime."%l) + raise ValueError("%s is not prime." % l) except AttributeError: - raise ValueError("%s is not prime."%l) + raise ValueError("%s is not prime." % l) if l is None: isogs = isogenies_prime_degree_genus_0(self) if isogs: @@ -4716,7 +4934,7 @@ def isogenies_prime_degree(self, l=None): return isogs def is_isogenous(self, other, proof=True, maxp=200): - """ + r""" Return whether or not self is isogenous to other. INPUT: @@ -4780,8 +4998,8 @@ def is_isogenous(self, other, proof=True, maxp=200): D1 = E1.discriminant() D2 = E2.discriminant() - if any(E1.change_ring(rings.GF(p)).cardinality() != E2.change_ring(rings.GF(p)).cardinality() - for p in rings.prime_range(2, maxp) + if any(E1.change_ring(GF(p)).cardinality() != E2.change_ring(GF(p)).cardinality() + for p in prime_range(2, maxp) if D1.valuation(p) == 0 and D2.valuation(p) == 0): return False @@ -4794,7 +5012,7 @@ def is_isogenous(self, other, proof=True, maxp=200): return E2 in E1.isogeny_class().curves def isogeny_degree(self, other): - """ + r""" Return the minimal degree of an isogeny between ``self`` and ``other``. @@ -4918,9 +5136,8 @@ def isogeny_degree(self, other): # the same isogeny class. # """ - def optimal_curve(self): - """ + r""" Given an elliptic curve that is in the installed Cremona database, return the optimal curve isogenous to it. @@ -5013,7 +5230,7 @@ def isogeny_graph(self, order=None): 6 Elliptic Curve defined by y^2 + x*y = x^3 - 8125*x - 282568 over Rational Field 7 Elliptic Curve defined by y^2 + x*y = x^3 - 7930*x - 296725 over Rational Field 8 Elliptic Curve defined by y^2 + x*y = x^3 - 130000*x - 18051943 over Rational Field - sage: G.plot(edge_labels=True) + sage: G.plot(edge_labels=True) # needs sage.plot Graphics object consisting of 23 graphics primitives """ return self.isogeny_class(order=order).graph() @@ -5033,9 +5250,7 @@ def manin_constant(self): that in each class there is at least one, more precisely the so-called strong Weil curve or `X_0(N)`-optimal curve, that has Manin constant `1`. - OUTPUT: - - an integer + OUTPUT: An integer. This function only works if the curve is in the installed Cremona database. Sage includes by default a small database; @@ -5127,7 +5342,7 @@ def _shortest_paths(self): """ from sage.graphs.graph import Graph isocls = self.isogeny_class() - M = isocls.matrix(fill=True).change_ring(rings.RR) + M = isocls.matrix(fill=True).change_ring(RR) # see trac #4889 for nebulous M.list() --> M.entries() change... # Take logs here since shortest path minimizes the *sum* of the weights -- not the product. M = M.parent()([a.log() if a else 0 for a in M.list()]) @@ -5193,7 +5408,8 @@ def galois_representation(self): sage: rho = EllipticCurve('11a1').galois_representation() sage: rho - Compatible family of Galois representations associated to the Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Compatible family of Galois representations associated to the + Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: rho.is_irreducible(7) True sage: rho.is_irreducible(5) @@ -5261,7 +5477,7 @@ def is_ordinary(self, p, ell=None): return self.ap(ell) % p != 0 def is_good(self, p, check=True): - """ + r""" Return ``True`` if ``p`` is a prime of good reduction for `E`. INPUT: @@ -5286,7 +5502,7 @@ def is_good(self, p, check=True): return self.conductor() % p != 0 def is_supersingular(self, p, ell=None): - """ + r""" Return ``True`` precisely when p is a prime of good reduction and the mod-``p`` representation attached to this elliptic curve is supersingular at ell. @@ -5316,7 +5532,7 @@ def is_supersingular(self, p, ell=None): return self.is_good(p) and not self.is_ordinary(p, ell) def supersingular_primes(self, B): - """ + r""" Return a list of all supersingular primes for this elliptic curve up to and possibly including B. @@ -5345,13 +5561,13 @@ def supersingular_primes(self, B): [] """ v = self.aplist(max(B, 3)) - P = rings.prime_range(max(B,3)+1) + P = prime_range(max(B,3)+1) N = self.conductor() - return [P[i] for i in [0,1] if P[i] <= B and v[i]%P[i]==0 and N%P[i] != 0] + \ - [P[i] for i in range(2,len(v)) if v[i] == 0 and N%P[i] != 0] + return [P[i] for i in [0,1] if P[i] <= B and v[i] % P[i] == 0 and N % P[i] != 0] + \ + [P[i] for i in range(2,len(v)) if v[i] == 0 and N % P[i] != 0] def ordinary_primes(self, B): - """ + r""" Return a list of all ordinary primes for this elliptic curve up to and possibly including B. @@ -5377,7 +5593,7 @@ def ordinary_primes(self, B): [] """ v = self.aplist(max(B, 3)) - P = rings.prime_range(max(B, 3) + 1) + P = prime_range(max(B, 3) + 1) result = [P[i] for i in [0, 1] if P[i] <= B and v[i] % P[i]] result += [P[i] for i in range(2, len(v)) if v[i] != 0] return result @@ -5435,7 +5651,7 @@ def eval_modular_form(self, points, order): ######################################################################## def sha(self): - """ + r""" Return an object of class 'sage.schemes.elliptic_curves.sha_tate.Sha' attached to this elliptic curve. @@ -5446,9 +5662,10 @@ def sha(self): EXAMPLES:: sage: E = EllipticCurve('37a1') - sage: S=E.sha() + sage: S = E.sha() sage: S - Tate-Shafarevich group for the Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + Tate-Shafarevich group for the Elliptic Curve + defined by y^2 + y = x^3 - x over Rational Field sage: S.bound_kolyvagin() ([2], 1) """ @@ -5499,7 +5716,7 @@ def sha(self): matrix_of_frobenius = padics.matrix_of_frobenius def mod5family(self): - """ + r""" Return the family of all elliptic curves with the same mod-5 representation as ``self``. @@ -5507,7 +5724,8 @@ def mod5family(self): sage: E = EllipticCurve('32a1') sage: E.mod5family() - Elliptic Curve defined by y^2 = x^3 + 4*x over Fraction Field of Univariate Polynomial Ring in t over Rational Field + Elliptic Curve defined by y^2 = x^3 + 4*x + over Fraction Field of Univariate Polynomial Ring in t over Rational Field """ E = self.short_weierstrass_model() a = E.a4() @@ -5535,7 +5753,8 @@ def tate_curve(self, p): sage: e = EllipticCurve('130a1') sage: e.tate_curve(2) - 2-adic Tate curve associated to the Elliptic Curve defined by y^2 + x*y + y = x^3 - 33*x + 68 over Rational Field + 2-adic Tate curve associated to the Elliptic Curve + defined by y^2 + x*y + y = x^3 - 33*x + 68 over Rational Field The input curve must have multiplicative reduction at the prime. @@ -5549,7 +5768,8 @@ def tate_curve(self, p): We compute with `p=5`:: sage: T = e.tate_curve(5); T - 5-adic Tate curve associated to the Elliptic Curve defined by y^2 + x*y + y = x^3 - 33*x + 68 over Rational Field + 5-adic Tate curve associated to the Elliptic Curve + defined by y^2 + x*y + y = x^3 - 33*x + 68 over Rational Field We find the Tate parameter `q`:: @@ -5722,7 +5942,7 @@ def antilogarithm(self, z, max_denominator=None): - point on the curve: the rational point which is the image of `z` under the Weierstrass parametrization, if it exists and can be determined from `z` and the given value - of max_denominator (if any); otherwise a ``ValueError`` exception + of max_denominator (if any); otherwise a :class:`ValueError` exception is raised. EXAMPLES:: @@ -5789,7 +6009,7 @@ def integral_x_coords_in_interval(self,xmin,xmax): sage: E = EllipticCurve("141d1") sage: E.integral_points() - [(0 : 0 : 1), (2 : 1 : 1)] + [(0 : -1 : 1), (2 : -2 : 1)] """ xmin = pari(xmin) xmax = pari(xmax) @@ -5804,7 +6024,7 @@ def integral_x_coords_in_interval(self,xmin,xmax): prove_BSD = BSD.prove_BSD def integral_points(self, mw_base='auto', both_signs=False, verbose=False): - """ + r""" Compute all integral points (up to sign) on this elliptic curve. INPUT: @@ -5825,8 +6045,8 @@ def integral_points(self, mw_base='auto', both_signs=False, verbose=False): .. NOTE:: The complexity increases exponentially in the rank of curve - E. The computation time (but not the output!) depends on - the Mordell-Weil basis. If mw_base is given but is not a + `E`. The computation time (but not the output!) depends on + the Mordell-Weil basis. If ``mw_base`` is given but is not a basis for the Mordell-Weil group (modulo torsion), integral points which are not in the subgroup generated by the given points will almost certainly not be listed. @@ -5834,9 +6054,13 @@ def integral_points(self, mw_base='auto', both_signs=False, verbose=False): EXAMPLES: A curve of rank 3 with no torsion points:: sage: E = EllipticCurve([0,0,1,-7,6]) - sage: P1=E.point((2,0)); P2=E.point((-1,3)); P3=E.point((4,6)) - sage: a=E.integral_points([P1,P2,P3]); a - [(-3 : 0 : 1), (-2 : 3 : 1), (-1 : 3 : 1), (0 : 2 : 1), (1 : 0 : 1), (2 : 0 : 1), (3 : 3 : 1), (4 : 6 : 1), (8 : 21 : 1), (11 : 35 : 1), (14 : 51 : 1), (21 : 95 : 1), (37 : 224 : 1), (52 : 374 : 1), (93 : 896 : 1), (342 : 6324 : 1), (406 : 8180 : 1), (816 : 23309 : 1)] + sage: P1 = E.point((2,0)); P2 = E.point((-1,3)); P3 = E.point((4,6)) + sage: a = E.integral_points([P1,P2,P3]); a + [(-3 : -1 : 1), (-2 : -4 : 1), (-1 : -4 : 1), (0 : -3 : 1), + (1 : -1 : 1), (2 : -1 : 1), (3 : -4 : 1), (4 : -7 : 1), + (8 : -22 : 1), (11 : -36 : 1), (14 : -52 : 1), (21 : -96 : 1), + (37 : -225 : 1), (52 : -375 : 1), (93 : -897 : 1), + (342 : -6325 : 1), (406 : -8181 : 1), (816 : -23310 : 1)] :: @@ -5853,28 +6077,35 @@ def integral_points(self, mw_base='auto', both_signs=False, verbose=False): [2, 3, 4, 8, 11, 14, 21, 37, 52, 93, 342, 406, 816] Total number of integral points: 18 - It is not necessary to specify mw_base; if it is not provided, + It is not necessary to specify ``mw_base``; if it is not provided, then the Mordell-Weil basis must be computed, which may take much longer. :: sage: E = EllipticCurve([0,0,1,-7,6]) - sage: a=E.integral_points(both_signs=True); a - [(-3 : -1 : 1), (-3 : 0 : 1), (-2 : -4 : 1), (-2 : 3 : 1), (-1 : -4 : 1), (-1 : 3 : 1), (0 : -3 : 1), (0 : 2 : 1), (1 : -1 : 1), (1 : 0 : 1), (2 : -1 : 1), (2 : 0 : 1), (3 : -4 : 1), (3 : 3 : 1), (4 : -7 : 1), (4 : 6 : 1), (8 : -22 : 1), (8 : 21 : 1), (11 : -36 : 1), (11 : 35 : 1), (14 : -52 : 1), (14 : 51 : 1), (21 : -96 : 1), (21 : 95 : 1), (37 : -225 : 1), (37 : 224 : 1), (52 : -375 : 1), (52 : 374 : 1), (93 : -897 : 1), (93 : 896 : 1), (342 : -6325 : 1), (342 : 6324 : 1), (406 : -8181 : 1), (406 : 8180 : 1), (816 : -23310 : 1), (816 : 23309 : 1)] + sage: a = E.integral_points(both_signs=True); a + [(-3 : -1 : 1), (-3 : 0 : 1), (-2 : -4 : 1), (-2 : 3 : 1), (-1 : -4 : 1), + (-1 : 3 : 1), (0 : -3 : 1), (0 : 2 : 1), (1 : -1 : 1), (1 : 0 : 1), + (2 : -1 : 1), (2 : 0 : 1), (3 : -4 : 1), (3 : 3 : 1), (4 : -7 : 1), + (4 : 6 : 1), (8 : -22 : 1), (8 : 21 : 1), (11 : -36 : 1), (11 : 35 : 1), + (14 : -52 : 1), (14 : 51 : 1), (21 : -96 : 1), (21 : 95 : 1), + (37 : -225 : 1), (37 : 224 : 1), (52 : -375 : 1), (52 : 374 : 1), + (93 : -897 : 1), (93 : 896 : 1), (342 : -6325 : 1), (342 : 6324 : 1), + (406 : -8181 : 1), (406 : 8180 : 1), (816 : -23310 : 1), (816 : 23309 : 1)] An example with negative discriminant:: sage: EllipticCurve('900d1').integral_points() - [(-11 : 27 : 1), (-4 : 34 : 1), (4 : 18 : 1), (16 : 54 : 1)] + [(-11 : -27 : 1), (-4 : -34 : 1), (4 : -18 : 1), (16 : -54 : 1)] Another example with rank 5 and no torsion points:: sage: E = EllipticCurve([-879984,319138704]) - sage: P1=E.point((540,1188)); P2=E.point((576,1836)) - sage: P3=E.point((468,3132)); P4=E.point((612,3132)) - sage: P5=E.point((432,4428)) - sage: a=E.integral_points([P1,P2,P3,P4,P5]); len(a) # long time (18s on sage.math, 2011) + sage: P1 = E.point((540,1188)); P2 = E.point((576,1836)) + sage: P3 = E.point((468,3132)); P4 = E.point((612,3132)) + sage: P5 = E.point((432,4428)) + sage: a = E.integral_points([P1,P2,P3,P4,P5]); len(a) # long time (18s on sage.math, 2011) 54 TESTS: @@ -5882,7 +6113,7 @@ def integral_points(self, mw_base='auto', both_signs=False, verbose=False): The bug reported on :trac:`4525` is now fixed:: sage: EllipticCurve('91b1').integral_points() - [(-1 : 3 : 1), (1 : 0 : 1), (3 : 4 : 1)] + [(-1 : -4 : 1), (1 : -1 : 1), (3 : -5 : 1)] :: @@ -5896,8 +6127,8 @@ def integral_points(self, mw_base='auto', both_signs=False, verbose=False): See :trac:`22063`:: - sage: for n in [67,71,74,91]: - ....: assert 4*n^6+4*n^2 in [P[0] for P in EllipticCurve([0,0,0,2,n^2]).integral_points()] + sage: for n in [67,71,74,91]: # long time + ....: assert 4*n^6 + 4*n^2 in [P[0] for P in EllipticCurve([0,0,0,2,n^2]).integral_points()] ALGORITHM: @@ -5962,7 +6193,7 @@ def point_preprocessing(free,tor): P = free[i0] for i in range(r): if not free_id[i]: - if i==i0: + if i == i0: newfree[i] = 2*newfree[i] else: newfree[i] += P @@ -5990,16 +6221,16 @@ def point_preprocessing(free,tor): j = self.j_invariant() b2 = self.b2() - Qx = rings.PolynomialRing(RationalField(),'x') + Qx = PolynomialRing(RationalField(),'x') pol = Qx([-self.c6()/216,-self.c4()/12,0,4]) if disc > 0: # two real component -> 3 roots in RR #on curve 897e4, only one root is found with default precision! RR = R prec = RR.precision() ei = pol.roots(RR,multiplicities=False) - while len(ei)<3: - prec*=2 - RR=RealField(prec) + while len(ei) < 3: + prec *= 2 + RR = RealField(prec) ei = pol.roots(RR,multiplicities=False) e1,e2,e3 = ei if r >= 1: #preprocessing of mw_base only necessary if rank > 0 @@ -6013,7 +6244,7 @@ def point_preprocessing(free,tor): roots.remove(e3) e1,e2 = roots - from sage.all import pi + from sage.symbolic.constants import pi e = R(1).exp() pi = R(pi) @@ -6030,9 +6261,9 @@ def point_preprocessing(free,tor): h_E = self.height() w1, w2 = self.period_lattice().basis() mu = R(disc).abs().log() / 6 - if j!=0: + if j != 0: mu += max(R(1),R(j).abs().log()) / 6 - if b2!=0: + if b2 != 0: mu += max(R(1),R(b2).abs().log()) mu += log(R(2)) else: @@ -6058,8 +6289,8 @@ def point_preprocessing(free,tor): mod_h_list.append(max(mw_base[i].height(),h_E,c7*mw_base_log[i]**2)) c9_help_list.append((mod_h_list[i]).sqrt()/mw_base_log[i]) c9 = e/c7.sqrt() * min(c9_help_list) - n=r+1 - c10 = R(2 * 10**(8+7*n) * R((2/e)**(2 * n**2)) * (n+1)**(4 * n**2 + 10 * n) * log(c9)**(-2*n - 1) * misc.prod(mod_h_list)) + n = r+1 + c10 = R(2 * 10**(8+7*n) * R((2/e)**(2 * n**2)) * (n+1)**(4 * n**2 + 10 * n) * log(c9)**(-2*n - 1) * prod(mod_h_list)) top = Z(128) # arbitrary first upper bound bottom = Z(0) @@ -6082,7 +6313,7 @@ def point_preprocessing(free,tor): H_q = R(10)**bound break_cond = 0 #at least one reduction step #reduction via LLL - M = matrix.MatrixSpace(Z,n) + M = MatrixSpace(Z,n) while break_cond < 0.9: #as long as the improvement of the new bound in comparison to the old is greater than 10% c = R((H_q**n)*10) #c has to be greater than H_q^n m = copy(M.identity_matrix()) @@ -6168,7 +6399,7 @@ def point_preprocessing(free,tor): print(L) sys.stdout.flush() - if len(tors_points)>1: + if len(tors_points) > 1: x_int_points_t = set() for x in x_int_points: P = self.lift_x(x) @@ -6190,7 +6421,7 @@ def point_preprocessing(free,tor): return int_points def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, proof=None): - """ + r""" Compute all S-integral points (up to sign) on this elliptic curve. INPUT: @@ -6239,7 +6470,7 @@ def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, sage: P1 = E.point((2,0)) sage: P2 = E.point((-1,3)) sage: P3 = E.point((4,6)) - sage: a = E.S_integral_points(S=[2,3], mw_base=[P1,P2,P3], verbose=True);a + sage: a = E.S_integral_points(S=[2,3], mw_base=[P1,P2,P3], verbose=True); a max_S: 3 len_S: 3 len_tors: 1 lambda 0.485997517468... k1,k2,k3,k4 7.65200453902598e234 1.31952866480763 3.54035317966420e9 2.42767548272846e17 @@ -6265,7 +6496,49 @@ def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, x-coords of points with bounded absolute value [-3, -2, -1, 0, 1, 2] Total number of S-integral points: 43 - [(-3 : 0 : 1), (-26/9 : 28/27 : 1), (-8159/2916 : 233461/157464 : 1), (-2759/1024 : 60819/32768 : 1), (-151/64 : 1333/512 : 1), (-1343/576 : 36575/13824 : 1), (-2 : 3 : 1), (-7/4 : 25/8 : 1), (-1 : 3 : 1), (-47/256 : 9191/4096 : 1), (0 : 2 : 1), (1/4 : 13/8 : 1), (4/9 : 35/27 : 1), (9/16 : 69/64 : 1), (58/81 : 559/729 : 1), (7/9 : 17/27 : 1), (6169/6561 : 109871/531441 : 1), (1 : 0 : 1), (17/16 : -25/64 : 1), (2 : 0 : 1), (33/16 : 17/64 : 1), (172/81 : 350/729 : 1), (9/4 : 7/8 : 1), (25/9 : 64/27 : 1), (3 : 3 : 1), (31/9 : 116/27 : 1), (4 : 6 : 1), (25/4 : 111/8 : 1), (1793/256 : 68991/4096 : 1), (8 : 21 : 1), (625/64 : 14839/512 : 1), (11 : 35 : 1), (14 : 51 : 1), (21 : 95 : 1), (37 : 224 : 1), (52 : 374 : 1), (6142/81 : 480700/729 : 1), (93 : 896 : 1), (4537/36 : 305425/216 : 1), (342 : 6324 : 1), (406 : 8180 : 1), (816 : 23309 : 1), (207331217/4096 : 2985362173625/262144 : 1)] + [(-3 : -1 : 1), + (-26/9 : -55/27 : 1), + (-8159/2916 : -390925/157464 : 1), + (-2759/1024 : -93587/32768 : 1), + (-151/64 : -1845/512 : 1), + (-1343/576 : -50399/13824 : 1), + (-2 : -4 : 1), + (-7/4 : -33/8 : 1), + (-1 : -4 : 1), + (-47/256 : -13287/4096 : 1), + (0 : -3 : 1), + (1/4 : -21/8 : 1), + (4/9 : -62/27 : 1), + (9/16 : -133/64 : 1), + (58/81 : -1288/729 : 1), + (7/9 : -44/27 : 1), + (6169/6561 : -641312/531441 : 1), + (1 : -1 : 1), + (17/16 : -39/64 : 1), + (2 : -1 : 1), + (33/16 : -81/64 : 1), + (172/81 : -1079/729 : 1), + (9/4 : -15/8 : 1), + (25/9 : -91/27 : 1), + (3 : -4 : 1), + (31/9 : -143/27 : 1), + (4 : -7 : 1), + (25/4 : -119/8 : 1), + (1793/256 : -73087/4096 : 1), + (8 : -22 : 1), + (625/64 : -15351/512 : 1), + (11 : -36 : 1), + (14 : -52 : 1), + (21 : -96 : 1), + (37 : -225 : 1), + (52 : -375 : 1), + (6142/81 : -481429/729 : 1), + (93 : -897 : 1), + (4537/36 : -305641/216 : 1), + (342 : -6325 : 1), + (406 : -8181 : 1), + (816 : -23310 : 1), + (207331217/4096 : -2985362435769/262144 : 1)] It is not necessary to specify mw_base; if it is not provided, then the Mordell-Weil basis must be computed, which may take @@ -6280,7 +6553,9 @@ def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, An example with negative discriminant:: sage: EllipticCurve('900d1').S_integral_points([17], both_signs=True) - [(-11 : -27 : 1), (-11 : 27 : 1), (-4 : -34 : 1), (-4 : 34 : 1), (4 : -18 : 1), (4 : 18 : 1), (2636/289 : -98786/4913 : 1), (2636/289 : 98786/4913 : 1), (16 : -54 : 1), (16 : 54 : 1)] + [(-11 : -27 : 1), (-11 : 27 : 1), (-4 : -34 : 1), (-4 : 34 : 1), (4 : -18 : 1), + (4 : 18 : 1), (2636/289 : -98786/4913 : 1), (2636/289 : 98786/4913 : 1), + (16 : -54 : 1), (16 : 54 : 1)] Output checked with Magma (corrected in 3 cases):: @@ -6296,17 +6571,9 @@ def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, This is curve "7690e1" which failed until :trac:`4805` was fixed:: sage: EllipticCurve([1,1,1,-301,-1821]).S_integral_points([13,2]) - [(-13 : 16 : 1), - (-9 : 20 : 1), - (-7 : 4 : 1), - (21 : 30 : 1), - (23 : 52 : 1), - (63 : 452 : 1), - (71 : 548 : 1), - (87 : 756 : 1), - (2711 : 139828 : 1), - (7323 : 623052 : 1), - (17687 : 2343476 : 1)] + [(-13 : -4 : 1), (-9 : -12 : 1), (-7 : 2 : 1), (21 : -52 : 1), + (23 : -76 : 1), (63 : -516 : 1), (71 : -620 : 1), (87 : -844 : 1), + (2711 : -142540 : 1), (7323 : -630376 : 1), (17687 : -2361164 : 1)] - Some parts of this implementation are partially based on the function integral_points() @@ -6327,11 +6594,10 @@ def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, else: proof = bool(proof) - if not self.is_integral(): raise ValueError("S_integral_points() can only be called on an integral model") if not all(self.is_p_minimal(s) for s in S): - raise ValueError("%s must be p-minimal for all primes in S"%self) + raise ValueError("%s must be p-minimal for all primes in S" % self) try: len_S = len(S) @@ -6375,11 +6641,11 @@ def reduction_at(p): m = copy(M.identity_matrix()) for i in range(r): try: - m[i, r] = Z((beta[indexp][i])%pc) + m[i, r] = Z((beta[indexp][i]) % pc) except ZeroDivisionError: #If Inverse doesn't exist, change denominator (which is only approx) val_nu = (beta[indexp][i]).numerator() val_de = (beta[indexp][i]).denominator() - m[i, r] = Z((val_nu/(val_de+1))%pc) + m[i, r] = Z((val_nu/(val_de+1)) % pc) m[r,r] = max(Z(1), pc) #LLL - implemented in sage - operates on rows not on columns @@ -6396,22 +6662,24 @@ def reduction_at(p): raise RuntimeError('Unexpected intermediate result. Please try another Mordell-Weil base') d_L_0 = R(b1_norm**2 / c1_LLL) - #Reducing of upper bound + # Reducing of upper bound Q = r * H_q**2 T = (1 + (Z(3)/2*r*H_q))/2 if d_L_0 < R(T**2+Q): d_L_0 = 10*(T**2*Q) low_bound = (R(d_L_0 - Q).sqrt() - T) / c - ##new bound according to low_bound and upper bound - ##[k5*k6 exp(-k7**H_q^2)] + # new bound according to low_bound and upper bound + # [k5*k6 exp(-k7**H_q^2)] if low_bound != 0: H_q_infinity = R(((low_bound/(k6)).log()/(-k7)).sqrt()) - return (H_q_infinity.ceil()) + return H_q_infinity.ceil() else: - return (H_q) - #<------------------------------------------------------------------------- - #>------------------------------------------------------------------------- + return H_q + + # -------------------------------------------------------------------- + # -------------------------------------------------------------------- + def S_integral_points_with_bounded_mw_coeffs(): r""" Return the set of S-integers x which are x-coordinates of @@ -6434,8 +6702,8 @@ def S_integral_points_with_bounded_mw_coeffs(): denominator. """ from sage.groups.generic import multiples - xs=set() - N=H_q + xs = set() + N = H_q def test(P): """ @@ -6454,7 +6722,7 @@ def test_with_T(R): test(R+T) # For small rank and small H_q perform simple search - if r==1 and N<=10: + if r == 1 and N <= 10: for P in multiples(mw_base[0],N+1): test_with_T(P) return xs @@ -6464,7 +6732,7 @@ def test_with_T(R): # stops when (0,0,...,0) is reached because after that, only inverse points of # previously tested points would be tested - E0=E(0) + E0 = E(0) ni = [-N for i in range(r)] mw_baseN = [-N*P for P in mw_base] Pi = [0 for j in range(r)] @@ -6473,7 +6741,7 @@ def test_with_T(R): Pi[i] = Pi[i-1] + mw_baseN[i] while True: - if all(n==0 for n in ni): + if all(n == 0 for n in ni): test_with_T(E0) break @@ -6482,11 +6750,11 @@ def test_with_T(R): # increment indices and stored points i0 = r-1 - while ni[i0]==N: + while ni[i0] == N: ni[i0] = -N i0 -= 1 ni[i0] += 1 - if all(n==0 for n in ni[0:i0+1]): + if all(n == 0 for n in ni[0:i0+1]): Pi[i0] = E0 else: Pi[i0] += mw_base[i0] @@ -6494,8 +6762,10 @@ def test_with_T(R): Pi[i] = Pi[i-1] + mw_baseN[i] return xs - #<------------------------------------------------------------------------- - #>------------------------------------------------------------------------- + + # -------------------------------------------------------------------- + # -------------------------------------------------------------------- + def S_integral_x_coords_with_abs_bounded_by(abs_bound): r""" Extra search of points with `|x|< ` abs_bound, assuming @@ -6524,7 +6794,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): and search for integral points on the scaled model. """ x_min = min(self.two_division_polynomial().roots(R,multiplicities=False)) - x_min_neg = bool(x_min<0) + x_min_neg = bool(x_min < 0) x_min_pos = not x_min_neg log_ab = R(abs_bound.log()) alpha = [(log_ab/R(log(p,e))).floor() for p in S] @@ -6545,9 +6815,9 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): # denom_maxpa is a list of pairs (d,q) where d runs # through possible denominators, and q=p^a is the # maximum prime power divisor of d: - denom_maxpa = [(misc.prod(tmp),max(tmp)) for tmp in cartesian_product_iterator(p_pow_alpha)] + denom_maxpa = [(prod(tmp), max(tmp)) for tmp in product(*p_pow_alpha)] # The maximum denominator is this (not used): -# denom = [misc.prod([pp[-1] for pp in p_pow_alpha],1)] +# denom = [prod([pp[-1] for pp in p_pow_alpha],1)] for de,maxpa in denom_maxpa: n_max = (abs_bound*de).ceil() n_min = maxpa*de @@ -6562,21 +6832,20 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): for n in arith.xsrange(n_min,n_max+1): tmp = n/de # to save time, do not check de is the exact denominator if E.is_x_coord(tmp): - xs+=[tmp] + xs += [tmp] if not pos_n_only: if n <= neg_n_max: if E.is_x_coord(-tmp): - xs+=[-tmp] + xs += [-tmp] return set(xs) - #<------------------------------------------------------------------------- - #End internal functions ############################################### - from sage.misc.mrange import cartesian_product_iterator + # ------------------------------------------------------------------- + # End internal functions ############################################ E = self tors_points = E.torsion_points() - if (r==0):#only Torsionpoints to consider + if (r == 0): # only Torsionpoints to consider int_points = [P for P in tors_points if not P.is_zero()] int_points = [P for P in int_points if P[0].is_S_integral(S)] if not both_signs: @@ -6603,16 +6872,16 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): w1, w2 = E.period_lattice().basis() - Qx = rings.PolynomialRing(RationalField(),'x') + Qx = PolynomialRing(RationalField(),'x') pol = Qx([-54*c6,-27*c4,0,1]) if disc > 0: # two real component -> 3 roots in RR # it is possible that only one root is found with default precision! (see integral_points()) RR = R prec = RR.precision() ei = pol.roots(RR,multiplicities=False) - while len(ei)<3: - prec*=2 - RR=RealField(prec) + while len(ei) < 3: + prec *= 2 + RR = RealField(prec) ei = pol.roots(RR,multiplicities=False) e1,e2,e3 = ei elif disc < 0: # one real component => 1 root in RR (=: e3), @@ -6647,7 +6916,6 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): k4 = R(20**4 * max(3**6 * c4**2, 16*(disc_sh.abs().sqrt())**3)) k3 = R(32/3 * disc_sh.abs().sqrt() * (8 + 0.5*disc_sh.abs().log())**4) - k2 = max(R(b2.abs()), R(b4.abs().sqrt()), R(b6.abs()**(1/3)), R(b8.abs()**(1/4))).log() k1 = R(7 * 10**(38*len_S+49)) * R(len_S**(20*len_S+15)) * max_S**24 * R(max(1,log(max_S, e))**(4*len_S - 2)) * k3 * k3.log()**2 * ((20*len_S - 19)*k3 + (e*k4).log()) + 2*R(2*b2.abs()+6).log() @@ -6661,21 +6929,21 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): mw_base_log = [(pts.elliptic_logarithm().abs())*(len_tors/w1) for pts in mw_base] mw_base_p_log = [] beta = [] - mp=[] + mp = [] tmp = 0 for p in S: Np = E.Np(p) cp = E.tamagawa_exponent(p) mp_temp = Z(len_tors).lcm(cp*Np) mp.append(mp_temp) #only necessary because of verbose below - p_prec=30+E.discriminant().valuation(p) - p_prec_ok=False + p_prec = 30+E.discriminant().valuation(p) + p_prec_ok = False while not p_prec_ok: if verbose: print("p=", p, ": trying with p_prec = ", p_prec) try: mw_base_p_log.append([mp_temp*(pts.padic_elliptic_logarithm(p,absprec=p_prec)) for pts in mw_base]) - p_prec_ok=True + p_prec_ok = True except ValueError: p_prec *= 2 #reorder mw_base_p: last value has minimal valuation at p @@ -6694,7 +6962,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): except ValueError: # e.g. mw_base_p_log[tmp]==[0]: can occur e.g. [?]'172c6, S=[2] beta.append([0] for j in range(r)) - tmp +=1 + tmp += 1 if verbose: print('mw_base', mw_base) @@ -6713,7 +6981,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): sys.stdout.flush() break_cond = 0 - M = matrix.MatrixSpace(Z,n) + M = MatrixSpace(Z,n) #Reduction of initial bound if verbose: print('initial bound', H_q) @@ -6721,7 +6989,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): while break_cond < 0.9: #reduction at infinity - bound_list=[] + bound_list = [] c = R((H_q**n)*100) m = copy(M.identity_matrix()) for i in range(r): @@ -6811,7 +7079,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): print(L) sys.stdout.flush() - if len(tors_points)>1: + if len(tors_points) > 1: x_S_int_points_t = set() for x in x_S_int_points: P = E.lift_x(x) @@ -6833,7 +7101,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): def cremona_curves(conductors): - """ + r""" Return iterator over all known curves (in database) with conductor in the list of conductors. @@ -6841,32 +7109,32 @@ def cremona_curves(conductors): sage: [(E.label(), E.rank()) for E in cremona_curves(srange(35,40))] [('35a1', 0), - ('35a2', 0), - ('35a3', 0), - ('36a1', 0), - ('36a2', 0), - ('36a3', 0), - ('36a4', 0), - ('37a1', 1), - ('37b1', 0), - ('37b2', 0), - ('37b3', 0), - ('38a1', 0), - ('38a2', 0), - ('38a3', 0), - ('38b1', 0), - ('38b2', 0), - ('39a1', 0), - ('39a2', 0), - ('39a3', 0), - ('39a4', 0)] + ('35a2', 0), + ('35a3', 0), + ('36a1', 0), + ('36a2', 0), + ('36a3', 0), + ('36a4', 0), + ('37a1', 1), + ('37b1', 0), + ('37b2', 0), + ('37b3', 0), + ('38a1', 0), + ('38a2', 0), + ('38a3', 0), + ('38b1', 0), + ('38b2', 0), + ('39a1', 0), + ('39a2', 0), + ('39a3', 0), + ('39a4', 0)] """ - if isinstance(conductors, (rings.RingElement, int)): + if isinstance(conductors, (RingElement, int)): conductors = [conductors] return sage.databases.cremona.CremonaDatabase().iter(conductors) def cremona_optimal_curves(conductors): - """ + r""" Return iterator over all known optimal curves (in database) with conductor in the list of conductors. @@ -6874,19 +7142,20 @@ def cremona_optimal_curves(conductors): sage: [(E.label(), E.rank()) for E in cremona_optimal_curves(srange(35,40))] [('35a1', 0), - ('36a1', 0), - ('37a1', 1), - ('37b1', 0), - ('38a1', 0), - ('38b1', 0), - ('39a1', 0)] + ('36a1', 0), + ('37a1', 1), + ('37b1', 0), + ('38a1', 0), + ('38b1', 0), + ('39a1', 0)] There is one case -- 990h3 -- when the optimal curve isn't labeled with a 1:: sage: [e.cremona_label() for e in cremona_optimal_curves([990])] - ['990a1', '990b1', '990c1', '990d1', '990e1', '990f1', '990g1', '990h3', '990i1', '990j1', '990k1', '990l1'] + ['990a1', '990b1', '990c1', '990d1', '990e1', '990f1', '990g1', + '990h3', '990i1', '990j1', '990k1', '990l1'] """ - if isinstance(conductors, (rings.RingElement, int)): + if isinstance(conductors, (RingElement, int)): conductors = [conductors] return sage.databases.cremona.CremonaDatabase().iter_optimal(conductors) @@ -6914,11 +7183,11 @@ def integral_points_with_bounded_mw_coeffs(E, mw_base, N, x_bound): We check that some large integral points in a paper of Zagier are found:: - sage: def t(a,b,x): # indirect doctest - ....: E = EllipticCurve([0,0,0,a,b]) - ....: xs = [P[0] for P in E.integral_points()] - ....: return x in xs - sage: all(t(a,b,x) for a,b,x in [ (-2,5, 1318), (4,-1, 4321), + sage: def t(a, b, x): # indirect doctest + ....: E = EllipticCurve([0,0,0,a,b]) + ....: xs = [P[0] for P in E.integral_points()] + ....: return x in xs + sage: all(t(a,b,x) for a,b,x in [(-2,5, 1318), (4,-1, 4321), # long time ....: (0,17, 5234), (11,4, 16833), (-13,37, 60721), (-12,-10, 80327), ....: (-7,22, 484961), (-9,28, 764396), (-13,4, 1056517), (-19,-51, ....: 2955980), (-24,124, 4435710), (-30,133, 5143326), (-37,60, @@ -6929,7 +7198,7 @@ def integral_points_with_bounded_mw_coeffs(E, mw_base, N, x_bound): True """ from sage.groups.generic import multiples - xs=set() + xs = set() tors_points = E.torsion_points() r = len(mw_base) @@ -6952,7 +7221,7 @@ def use_t(R): # We use a naive method when the number of possibilities is small: - if r==1 and N<=10: + if r == 1 and N <= 10: for P in multiples(mw_base[0],N+1): use_t(P) return xs @@ -6985,7 +7254,7 @@ def is_approx_integral(rx): Rgens = [ER.lift_x(P[0]) for P in mw_base] for i in range(r): - if abs(Rgens[i][1]-mw_base[i][1])>abs((-Rgens[i])[1]-mw_base[i][1]): + if abs(Rgens[i][1]-mw_base[i][1]) > abs((-Rgens[i])[1]-mw_base[i][1]): Rgens[i] = -Rgens[i] # the ni loop through all tuples (a1,a2,...,ar) with @@ -7015,13 +7284,13 @@ def is_approx_integral(rx): # increment indices and stored points i0 = r-1 - while ni[i0]==N: + while ni[i0] == N: ni[i0] = -N i0 -= 1 ni[i0] += 1 # The next lines are to prevent rounding error: (-P)+P behaves # badly for real points! - if all(n==0 for n in ni[0:i0+1]): + if all(n == 0 for n in ni[0:i0+1]): RPi[i0] = ER0 else: RPi[i0] += Rgens[i0] @@ -7054,7 +7323,7 @@ def elliptic_curve_congruence_graph(curves): Graph on 12 vertices """ from sage.graphs.graph import Graph - from sage.arith.all import lcm + from sage.arith.functions import lcm from sage.rings.fast_arith import prime_range from sage.misc.misc_c import prod G = Graph() diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 22a4f0a29d0..7b616671e24 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -44,13 +44,13 @@ from sage.rings.padics.factory import Qp from sage.structure.sage_object import SageObject from sage.structure.richcmp import richcmp, richcmp_method -from sage.arith.all import LCM +from sage.arith.functions import lcm as LCM from sage.modular.modform.constructor import EisensteinForms, CuspForms from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.functions.log import log from sage.misc.functional import denominator from sage.misc.misc_c import prod -import sage.matrix.all as matrix +from sage.matrix.constructor import matrix @richcmp_method @@ -68,7 +68,8 @@ class TateCurve(SageObject): sage: e = EllipticCurve('130a1') sage: eq = e.tate_curve(5); eq - 5-adic Tate curve associated to the Elliptic Curve defined by y^2 + x*y + y = x^3 - 33*x + 68 over Rational Field + 5-adic Tate curve associated to the Elliptic Curve + defined by y^2 + x*y + y = x^3 - 33*x + 68 over Rational Field sage: eq == loads(dumps(eq)) True @@ -87,7 +88,8 @@ def __init__(self, E, p): sage: e = EllipticCurve('130a1') sage: eq = e.tate_curve(2); eq - 2-adic Tate curve associated to the Elliptic Curve defined by y^2 + x*y + y = x^3 - 33*x + 68 over Rational Field + 2-adic Tate curve associated to the Elliptic Curve + defined by y^2 + x*y + y = x^3 - 33*x + 68 over Rational Field """ if not p.is_prime(): raise ValueError("p (=%s) must be a prime" % p) @@ -111,7 +113,7 @@ def __richcmp__(self, other, op): sage: eq7 == eq5 False """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self._E, self._p), (other._E, other._p), op) @@ -138,7 +140,7 @@ def original_curve(self): sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.original_curve() Elliptic Curve defined by y^2 + x*y + y = x^3 - 33*x + 68 - over Rational Field + over Rational Field """ return self._E @@ -151,7 +153,7 @@ def prime(self): sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.original_curve() Elliptic Curve defined by y^2 + x*y + y = x^3 - 33*x + 68 - over Rational Field + over Rational Field sage: eq.prime() 5 """ @@ -213,10 +215,9 @@ def curve(self, prec=20): sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.curve(prec=5) - Elliptic Curve defined by y^2 + (1+O(5^5))*x*y = x^3 + - (2*5^4+5^5+2*5^6+5^7+3*5^8+O(5^9))*x + - (2*5^3+5^4+2*5^5+5^7+O(5^8)) over 5-adic - Field with capped relative precision 5 + Elliptic Curve defined by y^2 + (1+O(5^5))*x*y = + x^3 + (2*5^4+5^5+2*5^6+5^7+3*5^8+O(5^9))*x + (2*5^3+5^4+2*5^5+5^7+O(5^8)) + over 5-adic Field with capped relative precision 5 """ Eq = getattr(self, "__curve", None) if Eq and Eq.a6().precision_relative() >= prec: @@ -321,9 +322,11 @@ def parametrisation_onto_tate_curve(self, u, prec=None): sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10), prec=10) - (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) : 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^10)) + (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) + : 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^10)) sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10)) - (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) : 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^10)) + (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) + : 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^10)) sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10), prec=20) Traceback (most recent call last): ... @@ -447,7 +450,7 @@ def _inverse_isomorphism(self, prec=20): sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq._inverse_isomorphism(prec=5) [3 + 2*5 + 3*5^3 + O(5^5), 4 + 2*5 + 4*5^3 + 3*5^4 + O(5^5), - 1 + 5 + 4*5^3 + 2*5^4 + O(5^5), 5 + 2*5^2 + 3*5^4 + O(5^5)] + 1 + 5 + 4*5^3 + 2*5^4 + O(5^5), 5 + 2*5^2 + 3*5^4 + O(5^5)] """ if not self.is_split(): raise RuntimeError("the curve must have split multiplicative " @@ -478,10 +481,12 @@ def lift(self, P, prec=20): Now we map the lift l back and check that it is indeed right.:: sage: eq.parametrisation_onto_original_curve(l) - (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^10)) + (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) + : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^10)) sage: e5 = e.change_ring(Qp(5,9)) sage: e5(12*P) - (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^9)) + (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) + : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^9)) """ p = self._p R = Qp(self._p, prec) @@ -527,8 +532,8 @@ def parametrisation_onto_original_curve(self, u, prec=None): sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.parametrisation_onto_original_curve(1+5+5^2+O(5^10)) (4*5^-2 + 4*5^-1 + 4 + 2*5^3 + 3*5^4 + 2*5^6 + O(5^7) : - 3*5^-3 + 5^-2 + 4*5^-1 + 1 + 4*5 + 5^2 + 3*5^5 + O(5^6) : - 1 + O(5^10)) + 3*5^-3 + 5^-2 + 4*5^-1 + 1 + 4*5 + 5^2 + 3*5^5 + O(5^6) : + 1 + O(5^10)) sage: eq.parametrisation_onto_original_curve(1+5+5^2+O(5^10), prec=20) Traceback (most recent call last): ... @@ -654,7 +659,7 @@ def padic_regulator(self, prec=20): "for non-split multiplicative reduction.") basis = self._E.gens() - M = matrix.matrix(K, rank, rank, 0) + M = matrix(K, rank, rank, 0) height = self.padic_height(prec=prec) point_height = [height(P) for P in basis] diff --git a/src/sage/schemes/elliptic_curves/ell_torsion.py b/src/sage/schemes/elliptic_curves/ell_torsion.py index 8a1208569f2..9a39ead60e5 100644 --- a/src/sage/schemes/elliptic_curves/ell_torsion.py +++ b/src/sage/schemes/elliptic_curves/ell_torsion.py @@ -7,7 +7,7 @@ - Nick Alexander: original implementation over `\QQ` - Chris Wuthrich: original implementation over number fields - John Cremona: rewrote p-primary part to use division - polynomials, added some features, unified Number Field and `\QQ` code. + polynomials, added some features, unified Number Field and `\QQ` code. """ # **************************************************************************** @@ -26,7 +26,7 @@ # **************************************************************************** from sage.misc.cachefunc import cached_method -from sage.rings.all import RationalField +from sage.rings.rational_field import RationalField import sage.groups.additive_abelian.additive_abelian_wrapper as groups from sage.structure.richcmp import richcmp_method, richcmp @@ -41,9 +41,10 @@ class EllipticCurveTorsionSubgroup(groups.AdditiveAbelianGroupWrapper): Examples over `\QQ`:: sage: E = EllipticCurve([-4, 0]); E - Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field + Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field sage: G = E.torsion_subgroup(); G - Torsion Subgroup isomorphic to Z/2 + Z/2 associated to the Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field + Torsion Subgroup isomorphic to Z/2 + Z/2 associated to the + Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field sage: G.order() 4 sage: G.gen(0) @@ -58,12 +59,13 @@ class EllipticCurveTorsionSubgroup(groups.AdditiveAbelianGroupWrapper): sage: E = EllipticCurve([17, -120, -60, 0, 0]); E Elliptic Curve defined by y^2 + 17*x*y - 60*y = x^3 - 120*x^2 over Rational Field sage: G = E.torsion_subgroup(); G - Torsion Subgroup isomorphic to Trivial group associated to the Elliptic Curve defined by y^2 + 17*x*y - 60*y = x^3 - 120*x^2 over Rational Field + Torsion Subgroup isomorphic to Trivial group associated to the + Elliptic Curve defined by y^2 + 17*x*y - 60*y = x^3 - 120*x^2 over Rational Field sage: G.gens() () - sage: e = EllipticCurve([0, 33076156654533652066609946884,0,\ - 347897536144342179642120321790729023127716119338758604800,\ - 1141128154369274295519023032806804247788154621049857648870032370285851781352816640000]) + sage: e = EllipticCurve([0, 33076156654533652066609946884, 0, + ....: 347897536144342179642120321790729023127716119338758604800, + ....: 1141128154369274295519023032806804247788154621049857648870032370285851781352816640000]) sage: e.torsion_order() 16 @@ -73,11 +75,11 @@ class EllipticCurveTorsionSubgroup(groups.AdditiveAbelianGroupWrapper): sage: T = E.torsion_subgroup() sage: [E(t) for t in T] [(0 : 1 : 0), - (9 : 23 : 1), - (2 : 2 : 1), - (1 : -1 : 1), - (2 : -5 : 1), - (9 : -33 : 1)] + (9 : 23 : 1), + (2 : 2 : 1), + (1 : -1 : 1), + (2 : -5 : 1), + (9 : -33 : 1)] An example where the torsion subgroup is not cyclic:: @@ -91,23 +93,28 @@ class EllipticCurveTorsionSubgroup(groups.AdditiveAbelianGroupWrapper): sage: E = EllipticCurve('37a1') sage: T = E.torsion_subgroup() sage: T - Torsion Subgroup isomorphic to Trivial group associated to the Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + Torsion Subgroup isomorphic to Trivial group associated to the + Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field sage: [E(t) for t in T] [(0 : 1 : 0)] Examples over other Number Fields:: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('11a1') - sage: K.<i> = NumberField(x^2+1) + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) sage: EK = E.change_ring(K) sage: from sage.schemes.elliptic_curves.ell_torsion import EllipticCurveTorsionSubgroup sage: EllipticCurveTorsionSubgroup(EK) - Torsion Subgroup isomorphic to Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in i with defining polynomial x^2 + 1 + Torsion Subgroup isomorphic to Z/5 associated to the + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) + over Number Field in i with defining polynomial x^2 + 1 sage: E = EllipticCurve('11a1') - sage: K.<i> = NumberField(x^2+1) - sage: EK = E.change_ring(K) - sage: T = EK.torsion_subgroup() + sage: K.<i> = NumberField(x^2 + 1) # needs sage.rings.number_field + sage: EK = E.change_ring(K) # needs sage.rings.number_field + sage: T = EK.torsion_subgroup() # needs sage.rings.number_field sage: T.ngens() 1 sage: T.gen(0) @@ -115,8 +122,11 @@ class EllipticCurveTorsionSubgroup(groups.AdditiveAbelianGroupWrapper): Note: this class is normally constructed indirectly as follows:: + sage: # needs sage.rings.number_field sage: T = EK.torsion_subgroup(); T - Torsion Subgroup isomorphic to Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in i with defining polynomial x^2 + 1 + Torsion Subgroup isomorphic to Z/5 associated to the + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) + over Number Field in i with defining polynomial x^2 + 1 sage: type(T) <class 'sage.schemes.elliptic_curves.ell_torsion.EllipticCurveTorsionSubgroup_with_category'> @@ -132,22 +142,27 @@ def __init__(self, E): INPUT: - - ``E`` -- An elliptic curve defined over a number field (including `\Q`) + - ``E`` -- An elliptic curve defined over a number field (including `\QQ`) EXAMPLES:: sage: from sage.schemes.elliptic_curves.ell_torsion import EllipticCurveTorsionSubgroup sage: E = EllipticCurve('11a1') - sage: K.<i> = NumberField(x^2+1) - sage: EK = E.change_ring(K) - sage: EllipticCurveTorsionSubgroup(EK) - Torsion Subgroup isomorphic to Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in i with defining polynomial x^2 + 1 + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) # needs sage.rings.number_field + sage: EK = E.change_ring(K) # needs sage.rings.number_field + sage: EllipticCurveTorsionSubgroup(EK) # needs sage.rings.number_field + Torsion Subgroup isomorphic to Z/5 associated to the + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) + over Number Field in i with defining polynomial x^2 + 1 Note: this class is normally constructed indirectly as follows:: - sage: T = EK.torsion_subgroup(); T - Torsion Subgroup isomorphic to Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in i with defining polynomial x^2 + 1 - sage: type(T) + sage: T = EK.torsion_subgroup(); T # needs sage.rings.number_field + Torsion Subgroup isomorphic to Z/5 associated to the + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) + over Number Field in i with defining polynomial x^2 + 1 + sage: type(T) # needs sage.rings.number_field <class 'sage.schemes.elliptic_curves.ell_torsion.EllipticCurveTorsionSubgroup_with_category'> sage: T == loads(dumps(T)) # known bug, see https://github.com/sagemath/sage/issues/11599#comment:7 @@ -199,15 +214,16 @@ def __init__(self, E): [T1, T2], structure) def _repr_(self): - """ + r""" String representation of an instance of the EllipticCurveTorsionSubgroup class. EXAMPLES:: sage: E = EllipticCurve('11a1') - sage: K.<i> = NumberField(x^2+1) - sage: EK = E.change_ring(K) - sage: T = EK.torsion_subgroup(); T._repr_() + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) # needs sage.rings.number_field + sage: EK = E.change_ring(K) # needs sage.rings.number_field + sage: T = EK.torsion_subgroup(); T._repr_() # needs sage.rings.number_field 'Torsion Subgroup isomorphic to Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in i with defining polynomial x^2 + 1' """ return "Torsion Subgroup isomorphic to %s associated to the %s" % (self.short_name(), self.__E) @@ -223,18 +239,20 @@ def __richcmp__(self, other, op): sage: tor == tor True """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp(self.__E, other.__E, op) def curve(self): - """ + r""" Return the curve of this torsion subgroup. EXAMPLES:: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('11a1') - sage: K.<i> = NumberField(x^2+1) + sage: x = polygen(ZZ, 'x') + sage: K.<i> = NumberField(x^2 + 1) sage: EK = E.change_ring(K) sage: T = EK.torsion_subgroup() sage: T.curve() is EK @@ -244,15 +262,17 @@ def curve(self): @cached_method def points(self): - """ + r""" Return a list of all the points in this torsion subgroup. The list is cached. EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<i> = NumberField(x^2 + 1) - sage: E = EllipticCurve(K,[0,0,0,1,0]) + sage: E = EllipticCurve(K, [0,0,0,1,0]) sage: tor = E.torsion_subgroup() sage: tor.points() [(0 : 1 : 0), (0 : 0 : 1), (-i : 0 : 1), (i : 0 : 1)] @@ -269,7 +289,7 @@ def torsion_bound(E, number_of_places=20): - ``E`` -- an elliptic curve over `\QQ` or a number field - ``number_of_places`` (positive integer, default = 20) -- the - number of places that will be used to find the bound + number of places that will be used to find the bound OUTPUT: @@ -299,15 +319,17 @@ def torsion_bound(E, number_of_places=20): An example over a relative number field (see :trac:`16011`):: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] sage: F.<a> = QuadraticField(5) - sage: K.<b> = F.extension(x^2-3) - sage: E = EllipticCurve(K,[0,0,0,b,1]) + sage: K.<b> = F.extension(x^2 - 3) + sage: E = EllipticCurve(K, [0,0,0,b,1]) sage: E.torsion_subgroup().order() 1 An example of a base-change curve from `\QQ` to a degree 16 field:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.ell_torsion import torsion_bound sage: f = PolynomialRing(QQ,'x')([5643417737593488384,0, ....: -11114515801179776,0,-455989850911004,0,379781901872, diff --git a/src/sage/schemes/elliptic_curves/ell_wp.py b/src/sage/schemes/elliptic_curves/ell_wp.py index 8ea82fe35e2..8785976dec3 100644 --- a/src/sage/schemes/elliptic_curves/ell_wp.py +++ b/src/sage/schemes/elliptic_curves/ell_wp.py @@ -98,7 +98,8 @@ def weierstrass_p(E, prec=20, algorithm=None): sage: E.weierstrass_p(prec=7, algorithm='fast') Traceback (most recent call last): ... - ValueError: for computing the Weierstrass p-function via the fast algorithm, the characteristic (11) of the underlying field must be greater than prec + 4 = 11 + ValueError: for computing the Weierstrass p-function via the fast algorithm, + the characteristic (11) of the underlying field must be greater than prec + 4 = 11 sage: E.weierstrass_p(prec=8) z^-2 + 2*z^2 + 3*z^4 + 5*z^6 + O(z^8) sage: E.weierstrass_p(prec=8, algorithm='quadratic') @@ -108,15 +109,20 @@ def weierstrass_p(E, prec=20, algorithm=None): sage: E.weierstrass_p(prec=9) Traceback (most recent call last): ... - NotImplementedError: currently no algorithms for computing the Weierstrass p-function for that characteristic / precision pair is implemented. Lower the precision below char(k) - 2 + NotImplementedError: currently no algorithms for computing the Weierstrass + p-function for that characteristic / precision pair is implemented. + Lower the precision below char(k) - 2 sage: E.weierstrass_p(prec=9, algorithm="quadratic") Traceback (most recent call last): ... - ValueError: for computing the Weierstrass p-function via the quadratic algorithm, the characteristic (11) of the underlying field must be greater than prec + 2 = 11 + ValueError: for computing the Weierstrass p-function via the quadratic + algorithm, the characteristic (11) of the underlying field must be greater + than prec + 2 = 11 sage: E.weierstrass_p(prec=9, algorithm='pari') Traceback (most recent call last): ... - ValueError: for computing the Weierstrass p-function via pari, the characteristic (11) of the underlying field must be greater than prec + 2 = 11 + ValueError: for computing the Weierstrass p-function via pari, the + characteristic (11) of the underlying field must be greater than prec + 2 = 11 TESTS:: @@ -136,7 +142,7 @@ def weierstrass_p(E, prec=20, algorithm=None): if algorithm == "pari": if 0 < p <= prec + 2: - raise ValueError("for computing the Weierstrass p-function via pari, the characteristic (%s) of the underlying field must be greater than prec + 2 = %s"%(p,prec+2)) + raise ValueError("for computing the Weierstrass p-function via pari, the characteristic (%s) of the underlying field must be greater than prec + 2 = %s" % (p,prec+2)) return compute_wp_pari(E, prec) # quadratic and fast algorithms require short Weierstrass model @@ -147,11 +153,11 @@ def weierstrass_p(E, prec=20, algorithm=None): if algorithm == "quadratic": if 0 < p <= prec + 2: - raise ValueError("for computing the Weierstrass p-function via the quadratic algorithm, the characteristic (%s) of the underlying field must be greater than prec + 2 = %s"%(p,prec+2)) + raise ValueError("for computing the Weierstrass p-function via the quadratic algorithm, the characteristic (%s) of the underlying field must be greater than prec + 2 = %s" % (p,prec+2)) wp = compute_wp_quadratic(k, A, B, prec) elif algorithm == "fast": if 0 < p <= prec + 4: - raise ValueError("for computing the Weierstrass p-function via the fast algorithm, the characteristic (%s) of the underlying field must be greater than prec + 4 = %s"%(p,prec+4)) + raise ValueError("for computing the Weierstrass p-function via the fast algorithm, the characteristic (%s) of the underlying field must be greater than prec + 4 = %s" % (p,prec+4)) wp = compute_wp_fast(k, A, B, prec) else: raise ValueError("unknown algorithm for computing the Weierstrass p-function") @@ -173,7 +179,8 @@ def compute_wp_pari(E,prec): sage: compute_wp_pari(E, prec=20) z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + O(z^20) sage: compute_wp_pari(E, prec=30) - z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + 3/38548055*z^22 - 4/8364927935*z^28 + O(z^30) + z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + + 3/38548055*z^22 - 4/8364927935*z^28 + O(z^30) """ ep = E.__pari__() wpp = ep.ellwp(n=prec) @@ -198,10 +205,10 @@ def compute_wp_quadratic(k, A, B, prec): INPUT: - - ``k`` -- the field of definition of the curve - - ``A`` -- and - - ``B`` -- the coefficients of the elliptic curve - - ``prec`` -- the precision to which we compute the series. + - ``k`` -- the field of definition of the curve + - ``A`` -- and + - ``B`` -- the coefficients of the elliptic curve + - ``prec`` -- the precision to which we compute the series. OUTPUT: @@ -217,9 +224,10 @@ def compute_wp_quadratic(k, A, B, prec): sage: E.weierstrass_p(prec=10, algorithm='quadratic') z^-2 - 7/5*z^2 + 49/75*z^6 + O(z^10) - sage: E = EllipticCurve(GF(103),[1,2]) + sage: E = EllipticCurve(GF(103), [1,2]) sage: E.weierstrass_p(algorithm='quadratic') - z^-2 + 41*z^2 + 88*z^4 + 11*z^6 + 57*z^8 + 55*z^10 + 73*z^12 + 11*z^14 + 17*z^16 + 50*z^18 + O(z^20) + z^-2 + 41*z^2 + 88*z^4 + 11*z^6 + 57*z^8 + 55*z^10 + 73*z^12 + + 11*z^14 + 17*z^16 + 50*z^18 + O(z^20) sage: from sage.schemes.elliptic_curves.ell_wp import compute_wp_quadratic sage: compute_wp_quadratic(E.base_ring(), E.a4(), E.a6(), prec=10) @@ -247,16 +255,18 @@ def compute_wp_quadratic(k, A, B, prec): def compute_wp_fast(k, A, B, m): r""" - Computes the Weierstrass function of an elliptic curve defined by short Weierstrass model: `y^2 = x^3 + Ax + B`. It does this with as fast as polynomial of degree `m` can be multiplied together in the base ring, i.e. `O(M(n))` in the notation of [BMSS2006]_. + Computes the Weierstrass function of an elliptic curve defined by short Weierstrass model: + `y^2 = x^3 + Ax + B`. It does this with as fast as polynomial of degree `m` can be multiplied + together in the base ring, i.e. `O(M(n))` in the notation of [BMSS2006]_. Let `p` be the characteristic of the underlying field: Then we must have either `p=0`, or `p > m + 3`. INPUT: - - ``k`` -- the base field of the curve - - ``A`` -- and - - ``B`` -- as the coefficients of the short Weierstrass model `y^2 = x^3 +Ax +B`, and - - ``m`` -- the precision to which the function is computed to. + - ``k`` -- the base field of the curve + - ``A`` -- and + - ``B`` -- as the coefficients of the short Weierstrass model `y^2 = x^3 +Ax +B`, and + - ``m`` -- the precision to which the function is computed to. OUTPUT: @@ -322,23 +332,21 @@ def solve_linear_differential_system(a, b, c, alpha): sage: from sage.schemes.elliptic_curves.ell_wp import solve_linear_differential_system sage: k = GF(17) sage: R.<x> = PowerSeriesRing(k) - sage: a = 1+x+O(x^7); b = x+O(x^7); c = 1+x^3+O(x^7); alpha = k(3) - sage: f = solve_linear_differential_system(a,b,c,alpha) + sage: a = 1 + x + O(x^7); b = x + O(x^7); c = 1 + x^3 + O(x^7); alpha = k(3) + sage: f = solve_linear_differential_system(a, b, c, alpha) sage: f 3 + x + 15*x^2 + x^3 + 10*x^5 + 3*x^6 + 13*x^7 + O(x^8) - sage: a*f.derivative()+b*f - c + sage: a*f.derivative() + b*f - c O(x^7) sage: f(0) == alpha True """ - a_recip = 1/a - B = b * a_recip - C = c * a_recip + a_recip = 1 / a + B = b * a_recip + C = c * a_recip int_B = B.integral() J = int_B.exp() - J_recip = 1/J + J_recip = 1 / J CJ = C * J int_CJ = CJ.integral() - f = J_recip * (alpha + int_CJ) - - return f + return J_recip * (alpha + int_CJ) diff --git a/src/sage/schemes/elliptic_curves/formal_group.py b/src/sage/schemes/elliptic_curves/formal_group.py index 17019a5794e..dbd2db5f778 100644 --- a/src/sage/schemes/elliptic_curves/formal_group.py +++ b/src/sage/schemes/elliptic_curves/formal_group.py @@ -15,8 +15,9 @@ from sage.structure.sage_object import SageObject import sage.misc.misc as misc -import sage.rings.all as rings -from sage.rings.all import O +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.laurent_series_ring import LaurentSeriesRing +from sage.rings.big_oh import O class EllipticCurveFormalGroup(SageObject): @@ -29,7 +30,8 @@ def __init__(self, E): sage: E = EllipticCurve('11a') sage: F = E.formal_group(); F - Formal Group associated to the Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Formal Group associated to the Elliptic Curve + defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: F == loads(dumps(F)) True """ @@ -158,7 +160,7 @@ def w(self, prec=20): R = w.parent() except AttributeError: # No cached version available - R = rings.PowerSeriesRing(k, "t") + R = PowerSeriesRing(k, "t") w = R([k(0), k(0), k(0), k(1)], 4) cached_prec = 4 self.__w = w @@ -395,7 +397,7 @@ def log(self, prec=20): def inverse(self, prec=20): r""" - Return the formal group inverse law i(t), which satisfies F(t, i(t)) = 0. + Return the formal group inverse law `i(t)`, which satisfies `F(t, i(t)) = 0`. INPUT: @@ -454,8 +456,8 @@ def group_law(self, prec=10): - ``prec`` -- integer (default: 10) - OUTPUT: a power series with given precision in R[['t1','t2']], where - the curve is defined over R. + OUTPUT: a power series with given precision in `R[[t_1,t_2]]`, where + the curve is defined over `R`. Return the formal power series @@ -463,7 +465,7 @@ def group_law(self, prec=10): F(t_1, t_2) = t_1 + t_2 - a_1 t_1 t_2 - \cdots - to precision `O(t1,t2)^{prec}` of page 115 of [Sil2009]_. + to precision `O(t_1,t_2)^{prec}` of page 115 of [Sil2009]_. The result is cached, and a cached version is returned if possible. @@ -525,7 +527,7 @@ def group_law(self, prec=10): if prec <= 0: raise ValueError("The precision must be positive.") - R = rings.PowerSeriesRing(self.curve().base_ring(), 2, 't1,t2') + R = PowerSeriesRing(self.curve().base_ring(), 2, 't1,t2') t1, t2 = R.gens() if prec == 1: @@ -550,7 +552,7 @@ def group_law(self, prec=10): # note that the following formula differs from the one in Silverman page 119. # See github issue 9646 for the explanation and justification. t3 = -t1 - t2 - \ - (a1*lam + a3*lam2 + a2*nu + 2*a4*lam*nu + 3*a6*lam2*nu)/ \ + (a1*lam + a3*lam2 + a2*nu + 2*a4*lam*nu + 3*a6*lam2*nu) / \ (1 + a2*lam + a4*lam2 + a6*lam3) inv = self.inverse(prec) @@ -624,7 +626,7 @@ def mult_by_n(self, n, prec=10): TESTS:: sage: F = EllipticCurve(GF(17), [1, 1]).formal_group() - sage: F.mult_by_n(10, 50) # long time (13s on sage.math, 2011) + sage: F.mult_by_n(10, 50) # long time 10*t + 5*t^5 + 7*t^7 + 13*t^9 + t^11 + 16*t^13 + 13*t^15 + 9*t^17 + 16*t^19 + 15*t^23 + 15*t^25 + 2*t^27 + 10*t^29 + 8*t^31 + 15*t^33 + 6*t^35 + 7*t^37 + 9*t^39 + 10*t^41 + 5*t^43 + 4*t^45 + 6*t^47 + 13*t^49 + O(t^50) sage: F = EllipticCurve(GF(101), [1, 1]).formal_group() @@ -633,11 +635,11 @@ def mult_by_n(self, n, prec=10): sage: P.<a1, a2, a3, a4, a6> = PolynomialRing(ZZ, 5) sage: E = EllipticCurve(list(P.gens())) - sage: E.formal().mult_by_n(2,prec=5) + sage: E.formal().mult_by_n(2, prec=5) 2*t - a1*t^2 - 2*a2*t^3 + (a1*a2 - 7*a3)*t^4 + O(t^5) sage: E = EllipticCurve(QQ, [1,2,3,4,6]) - sage: E.formal().mult_by_n(2,prec=5) + sage: E.formal().mult_by_n(2, prec=5) 2*t - t^2 - 4*t^3 - 19*t^4 + O(t^5) """ if self.curve().base_ring().is_field() and self.curve().base_ring().characteristic() == 0 and n != 0: @@ -663,10 +665,9 @@ def mult_by_n(self, n, prec=10): # express it in terms of the formal parameter return -Q[0] / Q[1] - # Now the general case, not necessarily over a field. - R = rings.PowerSeriesRing(self.curve().base_ring(), "t") + R = PowerSeriesRing(self.curve().base_ring(), "t") t = R.gen() if n == 1: @@ -744,7 +745,7 @@ def sigma(self, prec=10): fl = self.log(prec) F = fl.reverse() - S = rings.LaurentSeriesRing(k,'z') + S = LaurentSeriesRing(k,'z') z = S.gen() F = F(z + O(z**prec)) wp = self.x()(F) + (a1**2 + 4*a2)/12 @@ -752,7 +753,7 @@ def sigma(self, prec=10): h = g.integral().integral() sigma_of_z = z.power_series() * h.exp() - T = rings.PowerSeriesRing(k,'t') + T = PowerSeriesRing(k,'t') fl = fl(T.gen()+O(T.gen()**prec)) sigma_of_t = sigma_of_z(fl) return sigma_of_t diff --git a/src/sage/schemes/elliptic_curves/gal_reps.py b/src/sage/schemes/elliptic_curves/gal_reps.py index 55d0ac2d352..c28b4f76d2c 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps.py +++ b/src/sage/schemes/elliptic_curves/gal_reps.py @@ -115,16 +115,19 @@ # http://www.gnu.org/licenses/ ###################################################################### +from math import sqrt + from sage.structure.sage_object import SageObject import sage.arith.all as arith from sage.rings.fast_arith import prime_range -import sage.misc.all as misc +from sage.misc.lazy_import import lazy_import +from sage.misc.misc_c import prod as mul from sage.misc.verbose import verbose -import sage.rings.all as rings -from sage.rings.all import RealField, GF +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.real_mpfr import RealField +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from math import sqrt -from sage.libs.pari.all import pari +lazy_import('sage.libs.pari.all', 'pari') def _ex_set(p): @@ -261,9 +264,7 @@ def is_reducible(self, p): - ``p`` -- a prime number - OUTPUT: - - - a boolean + OUTPUT: A boolean. The answer is cached. @@ -314,9 +315,7 @@ def is_irreducible(self, p): - ``p`` -- a prime number - OUTPUT: - - - a boolean + OUTPUT: A boolean. EXAMPLES:: @@ -355,7 +354,7 @@ def reducible_primes(self): if j in sporadic_j: # includes all CM j-invariants R = [sporadic_j[j]] else: - R = [l for l in [2,3,5,7,13] if len(E.isogenies_prime_degree(l))>0] + R = [l for l in [2,3,5,7,13] if len(E.isogenies_prime_degree(l)) > 0] self.__reducible_primes = R return R @@ -444,7 +443,6 @@ def is_surjective(self, p, A=1000): self.__is_surjective[key] = ans return ans - def _is_surjective(self, p, A): r""" helper function for ``is_surjective`` @@ -466,17 +464,17 @@ def _is_surjective(self, p, A): sage: rho._is_surjective(5,1000) """ T = self._E.torsion_subgroup().order() - if T % p == 0 and p != 2 : + if T % p == 0 and p != 2: # we could probably determine the group structure directly - self.__image_type[p] = "The image is meta-cyclic inside a Borel subgroup as there is a %s-torsion point on the curve."%p + self.__image_type[p] = "The image is meta-cyclic inside a Borel subgroup as there is a %s-torsion point on the curve." % p return False - R = rings.PolynomialRing(self._E.base_ring(), 'x') + R = PolynomialRing(self._E.base_ring(), 'x') x = R.gen() if p == 2: # E is isomorphic to [0,b2,0,8*b4,16*b6] - b2,b4,b6,b8=self._E.b_invariants() + b2,b4,b6,b8 = self._E.b_invariants() f = x**3 + b2*x**2 + 8*b4*x + 16*b6 if not f.is_irreducible(): if len(f.roots()) > 2: @@ -582,7 +580,7 @@ def _is_surjective(self, p, A): if s != 0 and s not in signs: signs.append(s) if len(signs) == 2 and exclude_exceptional_image: - self.__image_type[p] = "The image is all of GL_2(F_%s)."%p + self.__image_type[p] = "The image is all of GL_2(F_%s)." % p return True #,None if A == -1: # we came in from is reducible. Now go out with False @@ -679,19 +677,19 @@ def non_surjective(self, A=1000): p0 = arith.next_prime(p0+1) C2 = (sqrt(p0)+1)**8 C = max(C1,C2) - verbose("j is not integral -- Serre's bound is %s"%C) - C3 = 1 + 4*sqrt(6)*int(N)/3 * sqrt(misc.mul([1+1.0/int(p) for p,_ in arith.factor(N)])) + verbose("j is not integral -- Serre's bound is %s" % C) + C3 = 1 + 4*sqrt(6)*int(N)/3 * sqrt(mul([1+1.0/int(p) for p,_ in arith.factor(N)])) C = min(C,C3) - verbose("conductor = %s, and bound is %s"%(N,C)) + verbose("conductor = %s, and bound is %s" % (N,C)) else: # Cojocaru's bound (depends on the conductor) - C = 1 + 4*sqrt(6)*int(N)/3 * sqrt(misc.mul([1+1.0/int(p) for p,_ in arith.factor(N)])) - verbose("conductor = %s, and bound is %s"%(N,C)) + C = 1 + 4*sqrt(6)*int(N)/3 * sqrt(mul([1+1.0/int(p) for p,_ in arith.factor(N)])) + verbose("conductor = %s, and bound is %s" % (N,C)) B = [] p = 2 while p <= C: t = self.is_surjective(p, A=A) - verbose("(%s,%s)"%(p,t)) + verbose("(%s,%s)" % (p,t)) # both False and None will be appended here. if not t: B.append(p) @@ -714,9 +712,7 @@ def image_type(self, p): - ``p`` a prime number - OUTPUT: - - - a string. + OUTPUT: A string. EXAMPLES:: @@ -839,7 +835,7 @@ def image_type(self, p): # check if the rep is reducible if self.is_reducible(p): - self.__image_type[p] = "The image is contained in a Borel subgroup as there is a %s-isogeny."%p + self.__image_type[p] = "The image is contained in a Borel subgroup as there is a %s-isogeny." % p return self.__image_type[p] # if we are then the image of rho is not surjective and not contained in a Borel subgroup @@ -849,10 +845,10 @@ def image_type(self, p): # or the image in PGL_2 is one of the three exceptional groups A_4 S_4 A_5 non_split_str = "The image is contained in the normalizer of a non-split Cartan group." - split_str = "The image is contained in the normalizer of a split Cartan group." - s4_str = "The image in PGL_2(F_%s) is the exceptional group S_4."%p - a4_str = "The image in PGL_2(F_%s) is the exceptional group A_4."%p - a5_str = "The image in PGL_2(F_%s) is the exceptional group A_5."%p + split_str = "The image is contained in the normalizer of a split Cartan group." + s4_str = "The image in PGL_2(F_%s) is the exceptional group S_4." % p + a4_str = "The image in PGL_2(F_%s) is the exceptional group A_4." % p + a5_str = "The image in PGL_2(F_%s) is the exceptional group A_5." % p # we first treat p=3 and 5 separately. p=2 has already been done. @@ -916,14 +912,14 @@ def image_type(self, p): a_ell = self._E.ap(ell) u = k(a_ell)**2 * k(ell)**(-1) if u == 3: - verbose("found an element of order 6",2) + verbose("found an element of order 6", level=2) # found an element of order 6: self.__image_type[p] = non_split_str return self.__image_type[p] if u == 2 and not has_an_el_order_4: # found an element of order 4 - verbose("found an element of order 4",2) + verbose("found an element of order 4", level=2) has_an_el_order_4 = True if has_an_el_order_3: self.__image_type[p] = s4_str @@ -931,13 +927,13 @@ def image_type(self, p): if u == 1 and not has_an_el_order_3: # found an element of order 3 - verbose("found an element of order 3",2) + verbose("found an element of order 3", level=2) has_an_el_order_3 = True if has_an_el_order_4: self.__image_type[p] = s4_str return self.__image_type[p] - verbose("p=5 and we could not determine the image, yet", 2) + verbose("p=5 and we could not determine the image, yet", level=2) # we have not yet determined the image, there are only the following possible subgroups of PGL_2 # (unless we were unlucky and none of the elements of order 6 showed up above, for instance) # A_4 of order 12 with elements of order 2 and 3 @@ -988,32 +984,32 @@ def image_type(self, p): could_be_split = 1 could_be_non_split = 1 # loops over primes as long as we still have two options left - while ell < 10000 and (could_be_exc + could_be_split + could_be_non_split > 1): + while ell < 10000 and (could_be_exc + could_be_split + could_be_non_split > 1): ell = arith.next_prime(ell) if Np % ell != 0: a_ell = self._E.ap(ell) u = k(a_ell)**2 * k(ell)**(-1) if (u not in ex_setp) and could_be_exc == 1: # it can not be in the exceptional - verbose("the image cannot be exceptional, found u=%s"%u,2) + verbose("the image cannot be exceptional, found u=%s" % u, level=2) could_be_exc = 0 if a_ell != 0 and arith.kronecker(a_ell**2 - 4*ell,p) == 1 and could_be_non_split == 1: # it can not be in the normalizer of the non-split Cartan - verbose("the image cannot be non-split, found u=%s"%u,2) + verbose("the image cannot be non-split, found u=%s" % u, level=2) could_be_non_split = 0 if a_ell != 0 and arith.kronecker(a_ell**2 - 4*ell,p) == -1 and could_be_split == 1: # it can not be in the normalizer of the split Cartan - verbose("the image cannot be split, found u=%s"%u,2) + verbose("the image cannot be split, found u=%s" % u, level=2) could_be_split = 0 - assert could_be_exc + could_be_split + could_be_non_split > 0, "bug in image_type." + assert could_be_exc + could_be_split + could_be_non_split > 0, "bug in image_type." if could_be_exc + could_be_split + could_be_non_split == 1: # it is only one of the three cases: - if could_be_split == 1 : + if could_be_split == 1: self.__image_type[p] = split_str return self.__image_type[p] - if could_be_non_split == 1 : + if could_be_non_split == 1: self.__image_type[p] = non_split_str return self.__image_type[p] if could_be_exc == 1: @@ -1021,14 +1017,14 @@ def image_type(self, p): could_be_a4 = 1 could_be_s4 = 1 could_be_a5 = 1 - if p % 5 != 1 and p % 5 != 4 : + if p % 5 != 1 and p % 5 != 4: could_be_a5 = 0 # elements of order 5 # bug corrected see trac 14577 R = k['X'] f = R([1,-3,1]) #(X**2 - 3*X+1) el5 = f.roots() # loops over primes as long as we still have two options left - while ell < 10000 and (could_be_s4 + could_be_a4 + could_be_a5 > 1): + while ell < 10000 and (could_be_s4 + could_be_a4 + could_be_a5 > 1): ell = arith.next_prime(ell) if Np % ell != 0: a_ell = self._E.ap(ell) @@ -1037,12 +1033,12 @@ def image_type(self, p): # it can not be A4 not A5 as they have no elements of order 4 could_be_a4 = 0 could_be_a5 = 0 - if u in el5 : + if u in el5: # it can not be A4 or S4 as they have no elements of order 5 could_be_a4 = 0 could_be_s4 = 0 - assert (could_be_s4 + could_be_a4 + could_be_a5 > 0), "bug in image_type." + assert (could_be_s4 + could_be_a4 + could_be_a5 > 0), "bug in image_type." if could_be_s4 + could_be_a4 + could_be_a5 == 1: if could_be_s4 == 1: @@ -1056,7 +1052,7 @@ def image_type(self, p): return self.__image_type[p] else: - self.__image_type[p] = "The image in PGL_2(F_%s) is an exceptional group A_4, S_4 or A_5, but we could not determine which one."%p + self.__image_type[p] = "The image in PGL_2(F_%s) is an exceptional group A_4, S_4 or A_5, but we could not determine which one." % p return self.__image_type[p] # If all fails, we probably have a fairly small group and we can try to detect it using the galois_group @@ -1064,7 +1060,7 @@ def image_type(self, p): K = self._E.division_field(p, 'z') d = K.absolute_degree() - verbose("field of degree %s. try to compute Galois group"%(d),2) + verbose("field of degree %s. try to compute Galois group" % (d), level=2) # If the degree is too big, we have no chance at the Galois # group. K.galois_group calls is_galois which used to rely on # pari's Galois group computations, so degree < 12 @@ -1073,7 +1069,7 @@ def image_type(self, p): raise Exception() G = K.galois_group() except Exception: - self.__image_type[p] = "The image is a group of order %s."%d + self.__image_type[p] = "The image is a group of order %s." % d return self.__image_type[p] else: @@ -1081,7 +1077,7 @@ def image_type(self, p): ab = "" else: ab = "non-" - self.__image_type[p] = "The image is a " + ab + "abelian group of order %s."%G.order() + self.__image_type[p] = "The image is a " + ab + "abelian group of order %s." % G.order() return self.__image_type[p] ## everything failed : @@ -1089,7 +1085,6 @@ def image_type(self, p): self.__image_type[p] = "The image could not be determined. Sorry." return self.__image_type[p] - def image_classes(self,p,bound=10000): r""" This function returns, given the representation `\rho` @@ -1253,9 +1248,7 @@ def is_unramified(self,p,ell): - ``p`` a prime - ``ell`` another prime - OUTPUT: - - - Boolean + OUTPUT: A boolean. EXAMPLES:: @@ -1288,9 +1281,7 @@ def is_unipotent(self,p,ell): - ``p`` a prime - ``ell`` a different prime - OUTPUT: - - - Boolean + OUTPUT: A boolean. EXAMPLES:: @@ -1327,9 +1318,7 @@ def is_quasi_unipotent(self,p,ell): - ``p`` a prime - ``ell`` a different prime - OUTPUT: - - - Boolean + OUTPUT: A boolean. EXAMPLES:: @@ -1359,9 +1348,7 @@ def is_ordinary(self,p): - ``p`` a prime - OUTPUT: - - - a Boolean + OUTPUT: A boolean. EXAMPLES:: @@ -1389,9 +1376,7 @@ def is_crystalline(self,p): - ``p`` a prime - OUTPUT: - - - a Boolean + OUTPUT: A boolean. EXAMPLES:: @@ -1416,9 +1401,7 @@ def is_potentially_crystalline(self,p): - ``p`` a prime - OUTPUT: - - - a Boolean + OUTPUT: A boolean. EXAMPLES:: @@ -1432,7 +1415,6 @@ def is_potentially_crystalline(self,p): raise ValueError('p (=%s) must be prime' % p) return self._E.j_invariant().valuation(p) >= 0 - def is_semistable(self,p): r""" Return true if the `p`-adic Galois representation to `GL_2(\ZZ_p)` is semistable. @@ -1443,9 +1425,7 @@ def is_semistable(self,p): - ``p`` a prime - OUTPUT: - - - a Boolean + OUTPUT: A boolean. EXAMPLES:: @@ -1471,9 +1451,7 @@ def is_potentially_semistable(self,p): - ``p`` a prime - OUTPUT: - - - a Boolean + OUTPUT: A boolean. EXAMPLES:: diff --git a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py index d484a4a18bd..e257b511371 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py +++ b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.rings.number_field r""" Galois representations for elliptic curves over number fields @@ -9,6 +9,7 @@ EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: rho = E.galois_representation() @@ -45,14 +46,17 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.sage_object import SageObject -from sage.rings.number_field.number_field import NumberField +from sage.arith.misc import legendre_symbol, primes +from sage.misc.functional import cyclotomic_polynomial from sage.modules.free_module import VectorSpace from sage.rings.finite_rings.finite_field_constructor import GF -from sage.misc.functional import cyclotomic_polynomial -from sage.arith.all import legendre_symbol, primes +from sage.rings.infinity import Infinity +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import NumberField +from sage.rings.rational_field import QQ from sage.sets.set import Set -from sage.rings.all import Integer, ZZ, QQ, Infinity +from sage.structure.sage_object import SageObject class GaloisRepresentation(SageObject): @@ -71,6 +75,7 @@ class GaloisRepresentation(SageObject): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 + 1, 'a') sage: E = EllipticCurve('11a1').change_ring(K) sage: rho = E.galois_representation() @@ -84,6 +89,7 @@ def __init__(self, E): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 + 1, 'a') sage: E = EllipticCurve('11a1').change_ring(K) sage: rho = E.galois_representation() @@ -100,6 +106,7 @@ def __repr__(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 + 1, 'a') sage: E = EllipticCurve('11a1').change_ring(K) sage: rho = E.galois_representation() @@ -116,7 +123,6 @@ def __repr__(self): else: return "Compatible family of Galois representations associated to the " + repr(self.E) - def __eq__(self,other): r""" Compares two Galois representations. @@ -126,6 +132,7 @@ def __eq__(self,other): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 + 1, 'a'); a = K.gen() sage: rho1 = EllipticCurve_from_j(1 + a).galois_representation() sage: rho2 = EllipticCurve_from_j(2 + a).galois_representation() @@ -146,6 +153,7 @@ def elliptic_curve(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 + 1, 'a'); a = K.gen() sage: E = EllipticCurve_from_j(a) sage: rho = E.galois_representation() @@ -154,7 +162,6 @@ def elliptic_curve(self): """ return self.E - def non_surjective(self, A=100): r""" Return a list of primes `p` including all primes for which the mod-`p` @@ -174,10 +181,11 @@ def non_surjective(self, A=100): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: rho = E.galois_representation() - sage: rho.non_surjective() # See Section 5.10 of [Ser1972]. + sage: rho.non_surjective() # See Section 5.10 of [Ser1972]. # long time [3, 5, 29] sage: K = NumberField(x**2 + 3, 'a'); a = K.gen() sage: E = EllipticCurve([0, -1, 1, -10, -20]).change_ring(K) # X_0(11) @@ -224,6 +232,7 @@ def is_surjective(self, p, A=100): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: rho = E.galois_representation() @@ -289,18 +298,22 @@ def isogeny_bound(self, A=100): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: rho = E.galois_representation() - sage: rho.isogeny_bound() # See Section 5.10 of [Ser1972]. + sage: rho.isogeny_bound() # See Section 5.10 of [Ser1972]. # long time [3, 5] sage: K = NumberField(x**2 + 1, 'a') - sage: EllipticCurve_from_j(K(1728)).galois_representation().isogeny_bound() # CM over K + sage: E = EllipticCurve_from_j(K(1728)) # CM over K + sage: E.galois_representation().isogeny_bound() [0] - sage: EllipticCurve_from_j(K(0)).galois_representation().isogeny_bound() # CM NOT over K + sage: E = EllipticCurve_from_j(K(0)) # CM NOT over K + sage: E.galois_representation().isogeny_bound() # long time [2, 3] - sage: E = EllipticCurve_from_j(K(2268945/128)) # c.f. [Sut2012] - sage: E.galois_representation().isogeny_bound() # No 7-isogeny, but... + sage: E = EllipticCurve_from_j(K(2268945/128)) # c.f. [Sut2012] + sage: rho = E.galois_representation() + sage: rho.isogeny_bound() # No 7-isogeny, but... # long time [7] For curves with rational CM, there are infinitely many primes @@ -365,24 +378,25 @@ def reducible_primes(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: rho = E.galois_representation() - sage: rho.isogeny_bound() # See Section 5.10 of [Ser1972]. - [3, 5] - sage: rho.reducible_primes() + sage: rho.reducible_primes() # See Section 5.10 of [Ser1972]. # long time [3, 5] sage: K = NumberField(x**2 + 1, 'a') - sage: EllipticCurve_from_j(K(1728)).galois_representation().isogeny_bound() # CM over K + sage: E = EllipticCurve_from_j(K(1728)) # CM over K + sage: E.galois_representation().reducible_primes() [0] - sage: EllipticCurve_from_j(K(0)).galois_representation().reducible_primes() # CM but NOT over K + sage: E = EllipticCurve_from_j(K(0)) # CM but NOT over K + sage: E.galois_representation().reducible_primes() # long time [2, 3] - sage: E = EllipticCurve_from_j(K(2268945/128)) # c.f. [Sut2012] + sage: E = EllipticCurve_from_j(K(2268945/128)) # c.f. [Sut2012] sage: rho = E.galois_representation() - sage: rho.isogeny_bound() # ... but there is no 7-isogeny ... + sage: rho.isogeny_bound() # No 7-isogeny, but... # long time [7] - sage: rho.reducible_primes() + sage: rho.reducible_primes() # long time [] For curves with rational CM, there are infinitely many primes @@ -422,9 +436,10 @@ def _non_surjective(E, patience=100): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) - sage: sage.schemes.elliptic_curves.gal_reps_number_field._non_surjective(E) # See Section 5.10 of [Ser1972]. + sage: sage.schemes.elliptic_curves.gal_reps_number_field._non_surjective(E) # See Section 5.10 of [Ser1972]. # long time [3, 5, 29] sage: E = EllipticCurve_from_j(1728).change_ring(K) # CM sage: sage.schemes.elliptic_curves.gal_reps_number_field._non_surjective(E) @@ -498,7 +513,7 @@ def Frobenius_filter(E, L, patience=100): EXAMPLES:: sage: E = EllipticCurve('11a1') # has a 5-isogeny - sage: sage.schemes.elliptic_curves.gal_reps_number_field.Frobenius_filter(E,primes(40)) + sage: sage.schemes.elliptic_curves.gal_reps_number_field.Frobenius_filter(E,primes(40)) # long time [5] Example to show that the output may contain primes where the @@ -506,7 +521,7 @@ def Frobenius_filter(E, L, patience=100): essentially the unique such example by [Sut2012]_:: sage: E = EllipticCurve_from_j(2268945/128) - sage: sage.schemes.elliptic_curves.gal_reps_number_field.Frobenius_filter(E, [7, 11]) + sage: sage.schemes.elliptic_curves.gal_reps_number_field.Frobenius_filter(E, [7, 11]) # long time [7] This curve does possess a 7-isogeny modulo every prime of good @@ -519,7 +534,7 @@ def Frobenius_filter(E, L, patience=100): sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve([1+i, -i, i, -399-240*i, 2627+2869*i]) - sage: sage.schemes.elliptic_curves.gal_reps_number_field.Frobenius_filter(E, primes(20)) + sage: sage.schemes.elliptic_curves.gal_reps_number_field.Frobenius_filter(E, primes(20)) # long time [2, 3] Here the curve really does possess isogenies of degrees 2 and 3:: @@ -538,7 +553,7 @@ def Frobenius_filter(E, L, patience=100): L.remove(2) include_2 = not E.division_polynomial(2).is_irreducible() - K_is_Q = (K==QQ) + K_is_Q = (K == QQ) from sage.arith.misc import primes from sage.rings.infinity import infinity @@ -553,7 +568,7 @@ def primes_iter(): yield P numP = 0 for P in primes_iter(): - if not L or numP==patience: # stop if no primes are left, or patience is exhausted + if not L or numP == patience: # stop if no primes are left, or patience is exhausted break numP += 1 @@ -596,6 +611,7 @@ def _exceptionals(E, L, patience=1000): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: sage.schemes.elliptic_curves.gal_reps_number_field._exceptionals(E, [29, 31]) @@ -705,7 +721,6 @@ def _exceptionals(E, L, patience=1000): if u not in (1, 2, 4) and u**2 - 3 * u + 1 != 0: D[l][2] = False - if D[l] == [False, False, False]: unexc.append(l) @@ -795,7 +810,7 @@ def deg_one_primes_iter(K, principal_only=False): # imaginary quadratic fields have no principal primes of norm < disc / 4 start = K.discriminant().abs() // 4 if principal_only and K.signature() == (0,1) else 2 - K_is_Q = (K==QQ) + K_is_Q = (K == QQ) for p in primes(start=start, stop=Infinity): if K_is_Q: @@ -829,6 +844,7 @@ def _semistable_reducible_primes(E, verbose=False): This example, over a quintic field with Galois group `S_5`, took a very long time before :trac:`22343`:: + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^5 - 6*x^3 + 8*x - 1) sage: E = EllipticCurve(K, [a^3 - 2*a, a^4 - 2*a^3 - 4*a^2 + 6*a + 1, a + 1, -a^3 + a + 1, -a]) sage: from sage.schemes.elliptic_curves.gal_reps_number_field import _semistable_reducible_primes @@ -856,23 +872,23 @@ def _semistable_reducible_primes(E, verbose=False): while len(precomp) < 2: P = next(deg_one_primes) p = P.norm() - if p != last_p and (d==1 or P.ramification_index() == 1) and E.has_good_reduction(P): + if p != last_p and (d == 1 or P.ramification_index() == 1) and E.has_good_reduction(P): precomp.append(P) last_p = p Px, Py = precomp x, y = [PP.gens_reduced()[0] for PP in precomp] - EmodPx = E.reduction(Px) if d>1 else E.reduction(x) - EmodPy = E.reduction(Py) if d>1 else E.reduction(y) + EmodPx = E.reduction(Px) if d > 1 else E.reduction(x) + EmodPy = E.reduction(Py) if d > 1 else E.reduction(y) fxpol = EmodPx.frobenius_polynomial() fypol = EmodPy.frobenius_polynomial() fx12pol = fxpol.adams_operator(12) # roots are 12th powers of those of fxpol fy12pol = fypol.adams_operator(12) - px = x.norm() if d>1 else x - py = y.norm() if d>1 else x + px = x.norm() if d > 1 else x + py = y.norm() if d > 1 else x Zx = fxpol.parent() - xpol = x.charpoly() if d>1 else Zx([-x,1]) - ypol = y.charpoly() if d>1 else Zx([-y,1]) + xpol = x.charpoly() if d > 1 else Zx([-x,1]) + ypol = y.charpoly() if d > 1 else Zx([-y,1]) if verbose: print("Finished precomp, x={} (p={}), y={} (p={})".format(x,px,y,py)) @@ -900,7 +916,6 @@ def _semistable_reducible_primes(E, verbose=False): if verbose: print("gx and gy both 0!") - ## It is possible that our curve has CM. ## # Our character must be of the form Nm^K_F for an imaginary @@ -936,7 +951,7 @@ def _semistable_reducible_primes(E, verbose=False): # has CM and computing the set of CM j-invariants of K to check. # TODO: Is this the best value for this parameter? - while div==0 and patience>0: + while div == 0 and patience > 0: P = next(deg_one_primes) # a prime of K not K_rel while E.has_bad_reduction(P): P = next(deg_one_primes) @@ -952,7 +967,7 @@ def _semistable_reducible_primes(E, verbose=False): div2 = Integer(xpol.resultant(fpol.adams_operator(12)) // x.norm()**12) if div2: div = div2.isqrt() - assert div2==div**2 + assert div2 == div**2 if verbose: print("...div = {}".format(div)) else: @@ -1146,14 +1161,15 @@ def Billerey_P_l(E, l): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: from sage.schemes.elliptic_curves.gal_reps_number_field import Billerey_P_l sage: [Billerey_P_l(E,l) for l in primes(10)] [x^2 + 8143*x + 16777216, - x^2 + 451358*x + 282429536481, - x^4 - 664299076*x^3 + 205155493652343750*x^2 - 39595310449600219726562500*x + 3552713678800500929355621337890625, - x^4 - 207302404*x^3 - 377423798538689366394*x^2 - 39715249826471656586987520004*x + 36703368217294125441230211032033660188801] + x^2 + 451358*x + 282429536481, + x^4 - 664299076*x^3 + 205155493652343750*x^2 - 39595310449600219726562500*x + 3552713678800500929355621337890625, + x^4 - 207302404*x^3 - 377423798538689366394*x^2 - 39715249826471656586987520004*x + 36703368217294125441230211032033660188801] """ K = E.base_field() qq = K.primes_above(l) @@ -1182,16 +1198,17 @@ def Billerey_B_l(E,l,B=0): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: from sage.schemes.elliptic_curves.gal_reps_number_field import Billerey_B_l sage: [Billerey_B_l(E,l) for l in primes(15)] [1123077552537600, - 227279663773903886745600, - 0, - 0, - 269247154818492941287713746693964214802283882086400, - 0] + 227279663773903886745600, + 0, + 0, + 269247154818492941287713746693964214802283882086400, + 0] """ d = E.base_field().absolute_degree() P = Billerey_P_l(E, l) @@ -1223,6 +1240,7 @@ def Billerey_R_q(E, q, B=0): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: from sage.schemes.elliptic_curves.gal_reps_number_field import Billerey_R_q @@ -1283,6 +1301,7 @@ def Billerey_B_bound(E, max_l=200, num_l=8, small_prime_bound=0, debug=False): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: from sage.schemes.elliptic_curves.gal_reps_number_field import Billerey_B_bound @@ -1322,7 +1341,7 @@ def remove_primes(B): B1 = B1.prime_to_m_part(p) return B1 ll = primes(5,max_l) # iterator - while B!=1 and len(ells)<num_l: + while B != 1 and len(ells) < num_l: try: l = next(ll) while B0.valuation(l): @@ -1392,6 +1411,7 @@ def Billerey_R_bound(E, max_l=200, num_l=8, small_prime_bound=None, debug=False) EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: from sage.schemes.elliptic_curves.gal_reps_number_field import Billerey_R_bound @@ -1501,22 +1521,23 @@ def reducible_primes_Billerey(E, num_l=None, max_l=None, verbose=False): EXAMPLES:: sage: from sage.schemes.elliptic_curves.gal_reps_number_field import reducible_primes_Billerey + sage: x = polygen(ZZ, 'x') sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) - sage: reducible_primes_Billerey(E) + sage: reducible_primes_Billerey(E) # long time [3, 5] sage: K = NumberField(x**2 + 1, 'a') sage: E = EllipticCurve_from_j(K(1728)) # CM over K - sage: reducible_primes_Billerey(E) + sage: reducible_primes_Billerey(E) # long time [0] sage: E = EllipticCurve_from_j(K(0)) # CM but NOT over K - sage: reducible_primes_Billerey(E) + sage: reducible_primes_Billerey(E) # long time [2, 3] An example where a prime is not reducible but passes the test:: sage: E = EllipticCurve_from_j(K(2268945/128)).global_minimal_model() # c.f. [Sut2012] - sage: reducible_primes_Billerey(E) + sage: reducible_primes_Billerey(E) # long time [7] TESTS: @@ -1527,8 +1548,8 @@ def reducible_primes_Billerey(E, num_l=None, max_l=None, verbose=False): sage: j = 46969655/32768 sage: E = EllipticCurve(j=K(j)) sage: EK = E.change_ring(K) - sage: C = EK.isogeny_class(minimal_models=False) - sage: len(C) + sage: C = EK.isogeny_class(minimal_models=False) # long time + sage: len(C) # long time 4 """ #verbose=True @@ -1610,6 +1631,7 @@ def reducible_primes_naive(E, max_l=None, num_P=None, verbose=False): EXAMPLES:: sage: from sage.schemes.elliptic_curves.gal_reps_number_field import reducible_primes_naive + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^4 - 5*x^2 + 3) sage: E = EllipticCurve(K, [a^2 - 2, -a^2 + 3, a^2 - 2, -50*a^2 + 35, 95*a^2 - 67]) sage: reducible_primes_naive(E,num_P=10) @@ -1618,9 +1640,9 @@ def reducible_primes_naive(E, max_l=None, num_P=None, verbose=False): [2, 5, 197, 557, 653, 769] sage: reducible_primes_naive(E,num_P=20) [2, 5] - sage: reducible_primes_naive(E) + sage: reducible_primes_naive(E) # long time [2, 5] - sage: [phi.degree() for phi in E.isogenies_prime_degree()] + sage: [phi.degree() for phi in E.isogenies_prime_degree()] # long time [2, 2, 2, 5] """ if max_l is None: diff --git a/src/sage/schemes/elliptic_curves/gp_simon.py b/src/sage/schemes/elliptic_curves/gp_simon.py index 9f7d1b60203..198ceed7218 100644 --- a/src/sage/schemes/elliptic_curves/gp_simon.py +++ b/src/sage/schemes/elliptic_curves/gp_simon.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari """ Denis Simon's PARI scripts """ @@ -54,37 +55,41 @@ def simon_two_descent(E, verbose=0, lim1=None, lim3=None, limtriv=None, EXAMPLES:: sage: import sage.schemes.elliptic_curves.gp_simon - sage: E=EllipticCurve('389a1') + sage: E = EllipticCurve('389a1') sage: sage.schemes.elliptic_curves.gp_simon.simon_two_descent(E) (2, 2, [(5/4 : 5/8 : 1), (-3/4 : 7/8 : 1)]) TESTS:: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('37a1').change_ring(QuadraticField(-11,'x')) sage: E.simon_two_descent() (1, 1, [(0 : 0 : 1)]) An example with an elliptic curve defined over a relative number field:: + sage: # needs sage.rings.number_field sage: F.<a> = QuadraticField(29) sage: x = QQ['x'].gen() sage: K.<b> = F.extension(x^2-1/2*a+1/2) - sage: E = EllipticCurve(K,[1, 0, 5/2*a + 27/2, 0, 0]) # long time (about 3 s) + sage: E = EllipticCurve(K,[1, 0, 5/2*a + 27/2, 0, 0]) # long time (about 3 s) sage: E.simon_two_descent(lim1=2, limtriv=3) (1, 1, ...) Check that :trac:`16022` is fixed:: + sage: # needs sage.rings.number_field sage: K.<y> = NumberField(x^4 + x^2 - 7) sage: E = EllipticCurve(K, [1, 0, 5*y^2 + 16, 0, 0]) - sage: E.simon_two_descent(lim1=2, limtriv=3) # long time (about 3 s) + sage: E.simon_two_descent(lim1=2, limtriv=3) # long time (about 3 s) (1, 1, ...) An example that checks that :trac:`9322` is fixed (it should take less than a second to run):: - sage: K.<w> = NumberField(x^2-x-232) - sage: E = EllipticCurve([2-w,18+3*w,209+9*w,2581+175*w,852-55*w]) - sage: E.simon_two_descent() + sage: # needs sage.rings.number_field + sage: K.<w> = NumberField(x^2 - x - 232) + sage: E = EllipticCurve([2 - w, 18 + 3*w, 209 + 9*w, 2581 + 175*w, 852 - 55*w]) + sage: E.simon_two_descent() # long time (0, 2, []) """ init() @@ -133,18 +138,18 @@ def simon_two_descent(E, verbose=0, lim1=None, lim3=None, limtriv=None, if limtriv is None: limtriv = 2 - gp('DEBUGLEVEL_ell=%s; LIM1=%s; LIM3=%s; LIMTRIV=%s; MAXPROB=%s; LIMBIGPRIME=%s;'%( + gp('DEBUGLEVEL_ell=%s; LIM1=%s; LIM3=%s; LIMTRIV=%s; MAXPROB=%s; LIMBIGPRIME=%s;' % ( verbose, lim1, lim3, limtriv, maxprob, limbigprime)) if verbose >= 2: print(cmd) - s = gp.eval('ans=%s;'%cmd) + s = gp.eval('ans=%s;' % cmd) if s.find(" *** ") != -1: - raise RuntimeError("\n%s\nAn error occurred while running Simon's 2-descent program"%s) + raise RuntimeError("\n%s\nAn error occurred while running Simon's 2-descent program" % s) if verbose > 0: print(s) v = gp.eval('ans') - if v=='ans': # then the call to ellQ_ellrank() or bnfellrank() failed + if v == 'ans': # then the call to ellQ_ellrank() or bnfellrank() failed raise RuntimeError("An error occurred while running Simon's 2-descent program") if verbose >= 2: print("v = %s" % v) diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index 298f44fedc6..058b2f84669 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.rings.number_field r""" Heegner points on elliptic curves over the rational numbers @@ -15,7 +15,8 @@ sage: z = P.point_exact(201); z (-4/3 : 1/9*a : 1) sage: parent(z) - Abelian group of points on Elliptic Curve defined by y^2 + x*y = x^3 + 1 over Number Field in a with defining polynomial x^2 - 12*x + 111 + Abelian group of points on Elliptic Curve defined by y^2 + x*y = x^3 + 1 + over Number Field in a with defining polynomial x^2 - 12*x + 111 sage: parent(z[0]).discriminant() -3 sage: E.quadratic_twist(-3).rank() @@ -33,7 +34,9 @@ sage: z[0].charpoly().factor() (x^6 + x^5 - 1/4*x^4 + 19/10*x^3 + 31/20*x^2 - 7/10*x + 49/100)^2 sage: z[1].charpoly().factor() - x^12 - x^11 + 6/5*x^10 - 33/40*x^9 - 89/320*x^8 + 3287/800*x^7 - 5273/1600*x^6 + 993/4000*x^5 + 823/320*x^4 - 2424/625*x^3 + 12059/12500*x^2 + 3329/25000*x + 123251/250000 + x^12 - x^11 + 6/5*x^10 - 33/40*x^9 - 89/320*x^8 + 3287/800*x^7 + - 5273/1600*x^6 + 993/4000*x^5 + 823/320*x^4 - 2424/625*x^3 + + 12059/12500*x^2 + 3329/25000*x + 123251/250000 sage: f = P.x_poly_exact(300); f x^6 + x^5 - 1/4*x^4 + 19/10*x^3 + 31/20*x^2 - 7/10*x + 49/100 sage: f.discriminant().factor() @@ -44,8 +47,8 @@ sage: E = EllipticCurve('43a'); P = E.heegner_point(-7) sage: P.x_poly_exact() x - sage: P.point_exact() - (0 : 0 : 1) + sage: z = P.point_exact(); z == E(0,0,1) or -z == E(0,0,1) + True sage: E = EllipticCurve('997a') sage: E.rank() @@ -55,16 +58,17 @@ sage: P = E.heegner_point(-19) sage: P.x_poly_exact() x - 141/49 - sage: P.point_exact() - (141/49 : -162/343 : 1) + sage: z = P.point_exact(); z == E(141/49, -162/343, 1) or -z == E(141/49, -162/343, 1) + True Here we find that the Heegner point generates a subgroup of index 3:: sage: E = EllipticCurve('92b1') sage: E.heegner_discriminants_list(1) [-7] - sage: P = E.heegner_point(-7); z = P.point_exact(); z - (0 : 1 : 1) + sage: P = E.heegner_point(-7) + sage: z = P.point_exact(); z == E(0, 1, 1) or -z == E(0, 1, 1) + True sage: E.regulator() 0.0498083972980648 sage: z.height() @@ -91,32 +95,44 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from itertools import product - +import sage.rings.abc +import sage.rings.number_field.number_field_element +import sage.rings.number_field.number_field as number_field +from sage.rings.number_field.number_field import NumberField +from sage.rings.number_field.number_field import QuadraticField +from sage.rings.real_mpfr import RealField +from sage.rings.complex_mpfr import ComplexField +from sage.rings.real_mpfi import RealIntervalField +from sage.rings.infinity import Infinity as infinity +from sage.rings.fast_arith import prime_range + +from sage.arith.functions import lcm +from sage.arith.misc import (binomial, factorial, prime_divisors, + GCD as gcd, XGCD as xgcd) +from sage.matrix.constructor import matrix +from sage.matrix.matrix_space import MatrixSpace +from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod from sage.misc.verbose import verbose -from sage.misc.cachefunc import cached_method - +from sage.modular.modsym.p1list import P1List +from sage.rings.complex_double import CDF +from sage.rings.complex_mpfr import ComplexField +from sage.rings.factorint import factor_trial_division +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as Integers +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import QuadraticField +from sage.rings.rational_field import QQ +from sage.rings.real_mpfr import RealField +from sage.quadratic_forms.binary_qf import BinaryQF +from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives +from sage.rings.number_field.number_field_element_base import NumberFieldElement_base from sage.structure.sage_object import SageObject from sage.structure.richcmp import (richcmp_method, richcmp, richcmp_not_equal, rich_to_bool) -import sage.rings.abc -import sage.rings.number_field.number_field_element -import sage.rings.number_field.number_field as number_field -import sage.rings.all as rings -from sage.rings.all import (ZZ, GF, QQ, CDF, - Integers, RealField, ComplexField, QuadraticField) -from sage.arith.all import (gcd, xgcd, lcm, prime_divisors, factorial, - binomial) -from sage.rings.factorint import factor_trial_division -from sage.quadratic_forms.all import (BinaryQF, - BinaryQF_reduced_representatives) -from sage.matrix.all import MatrixSpace, matrix - -from sage.modular.modsym.p1list import P1List - - ############################################################################### # # The exported functions, which are in most cases enough to get the @@ -143,11 +159,11 @@ def heegner_points(N, D=None, c=None): EXAMPLES:: - sage: heegner_points(389,-7) + sage: heegner_points(389, -7) Set of all Heegner points on X_0(389) associated to QQ[sqrt(-7)] - sage: heegner_points(389,-7,1) + sage: heegner_points(389, -7, 1) All Heegner points of conductor 1 on X_0(389) associated to QQ[sqrt(-7)] - sage: heegner_points(389,-7,5) + sage: heegner_points(389, -7, 5) All Heegner points of conductor 5 on X_0(389) associated to QQ[sqrt(-7)] """ if D is None and c is None: @@ -232,16 +248,16 @@ def __init__(self, D, c, check=True): """ INPUT: - - `D` -- discriminant of quadratic imaginary field + - `D` -- discriminant of quadratic imaginary field - - `c` -- conductor (positive integer coprime to `D`) + - `c` -- conductor (positive integer coprime to `D`) - - ``check`` -- bool (default: ``True``); whether to check - validity of input + - ``check`` -- bool (default: ``True``); whether to check + validity of input EXAMPLES:: - sage: sage.schemes.elliptic_curves.heegner.RingClassField(-7,5, False) + sage: sage.schemes.elliptic_curves.heegner.RingClassField(-7, 5, False) Ring class field extension of QQ[sqrt(-7)] of conductor 5 """ if check: @@ -509,10 +525,11 @@ def quadratic_field(self): sage: E = EllipticCurve('389a'); K = E.heegner_point(-7,5).ring_class_field() sage: K.quadratic_field() - Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I """ - D = self.__D - var = 'sqrt_minus_%s'%(-D) + D = self.__D + var = 'sqrt_minus_%s' % (-D) return number_field.QuadraticField(D,var) @cached_method @@ -522,7 +539,7 @@ def galois_group(self, base=QQ): INPUT: - - ``base`` -- (default: `\QQ`) a subfield of ``self`` or `\QQ` + - ``base`` -- (default: `\QQ`) a subfield of ``self`` or `\QQ` EXAMPLES:: @@ -535,13 +552,15 @@ def galois_group(self, base=QQ): sage: A.galois_group() Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 sage: A.galois_group(B) - Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 over Hilbert class field of QQ[sqrt(-7)] + Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 + over Hilbert class field of QQ[sqrt(-7)] sage: A.galois_group().cardinality() 12 sage: A.galois_group(B).cardinality() 6 sage: C.galois_group(A) - Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 15 over Ring class field extension of QQ[sqrt(-7)] of conductor 5 + Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 15 + over Ring class field extension of QQ[sqrt(-7)] of conductor 5 sage: C.galois_group(A).cardinality() 4 """ @@ -550,7 +569,7 @@ def galois_group(self, base=QQ): def is_subfield(self, M): """ Return ``True`` if this ring class field is a subfield of the ring class field `M`. - If `M` is not a ring class field, then a TypeError is raised. + If `M` is not a ring class field, then a :class:`TypeError` is raised. EXAMPLES:: @@ -597,7 +616,8 @@ class GaloisGroup(SageObject): sage: G.cardinality() 12 sage: G.complex_conjugation() - Complex conjugation automorphism of Ring class field extension of QQ[sqrt(-7)] of conductor 5 + Complex conjugation automorphism of Ring class field extension of QQ[sqrt(-7)] + of conductor 5 TESTS:: @@ -611,18 +631,20 @@ def __init__(self, field, base=QQ): r""" INPUT: - - ``field`` -- a ring class field + - ``field`` -- a ring class field - - ``base`` -- subfield of field (default: `\QQ`) + - ``base`` -- subfield of field (default: `\QQ`) EXAMPLES:: sage: K5 = heegner_points(389,-7,5).ring_class_field() sage: K1 = heegner_points(389,-7,1).ring_class_field() sage: sage.schemes.elliptic_curves.heegner.GaloisGroup(K5,K1) - Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 over Hilbert class field of QQ[sqrt(-7)] + Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 + over Hilbert class field of QQ[sqrt(-7)] sage: K5.galois_group(K1) - Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 over Hilbert class field of QQ[sqrt(-7)] + Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 + over Hilbert class field of QQ[sqrt(-7)] """ if not isinstance(field, RingClassField): raise TypeError("field must be of type RingClassField") @@ -685,11 +707,9 @@ def __call__(self, x): INPUT: - - `x` -- automorphism or quadratic field element - - OUTPUT: + - `x` -- automorphism or quadratic field element - - automorphism (or TypeError) + OUTPUT: An automorphism (or ``TypeError``) EXAMPLES:: @@ -705,7 +725,7 @@ def __call__(self, x): sage: G(alpha) Class field automorphism defined by 14*x^2 - 10*x*y + 25*y^2 - A TypeError is raised when the coercion is not possible:: + A :class:`TypeError` is raised when the coercion is not possible:: sage: G(0) Traceback (most recent call last): @@ -731,10 +751,10 @@ def _repr_(self): 'Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5' """ if self.base_field() != QQ: - s = " over %s"%self.base_field() + s = " over %s" % self.base_field() else: s = '' - return "Galois group of %s%s"%(self.field(), s) + return "Galois group of %s%s" % (self.field(), s) def field(self): """ @@ -768,13 +788,17 @@ def base_field(self): sage: Kc.absolute_degree() 12 sage: G = Kc.galois_group(K); G - Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 over Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 + over Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I sage: G.cardinality() 6 sage: G.base_field() - Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I sage: G = Kc.galois_group(Kc); G - Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 over Ring class field extension of QQ[sqrt(-7)] of conductor 5 + Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 + over Ring class field extension of QQ[sqrt(-7)] of conductor 5 sage: G.cardinality() 1 sage: G.base_field() @@ -796,7 +820,7 @@ def kolyvagin_generators(self): OUTPUT: - - list of elements of ``self`` + - list of elements of ``self`` EXAMPLES:: @@ -836,14 +860,15 @@ def lift_of_hilbert_class_field_galois_group(self): OUTPUT: - - tuple of elements of self + - tuple of elements of self EXAMPLES:: sage: K5 = heegner_points(389,-52,5).ring_class_field() sage: G = K5.galois_group(K5.quadratic_field()) sage: G.lift_of_hilbert_class_field_galois_group() - (Class field automorphism defined by x^2 + 325*y^2, Class field automorphism defined by 2*x^2 + 2*x*y + 163*y^2) + (Class field automorphism defined by x^2 + 325*y^2, + Class field automorphism defined by 2*x^2 + 2*x*y + 163*y^2) sage: G.cardinality() 12 sage: K5.quadratic_field().class_number() @@ -872,17 +897,22 @@ def _list(self): Example with order 1 (a special case):: - sage: E = EllipticCurve('389a'); F= E.heegner_point(-7,1).ring_class_field() + sage: E = EllipticCurve('389a'); F = E.heegner_point(-7,1).ring_class_field() sage: G = F.galois_group(F.quadratic_field()) sage: G._list() (Class field automorphism defined by x^2 + x*y + 2*y^2,) Example over quadratic imaginary field:: - sage: E = EllipticCurve('389a'); F= E.heegner_point(-7,5).ring_class_field() + sage: E = EllipticCurve('389a'); F = E.heegner_point(-7,5).ring_class_field() sage: G = F.galois_group(F.quadratic_field()) sage: G._list() - (Class field automorphism defined by x^2 + x*y + 44*y^2, Class field automorphism defined by 2*x^2 - x*y + 22*y^2, Class field automorphism defined by 2*x^2 + x*y + 22*y^2, Class field automorphism defined by 4*x^2 - x*y + 11*y^2, Class field automorphism defined by 4*x^2 + x*y + 11*y^2, Class field automorphism defined by 7*x^2 + 7*x*y + 8*y^2) + (Class field automorphism defined by x^2 + x*y + 44*y^2, + Class field automorphism defined by 2*x^2 - x*y + 22*y^2, + Class field automorphism defined by 2*x^2 + x*y + 22*y^2, + Class field automorphism defined by 4*x^2 - x*y + 11*y^2, + Class field automorphism defined by 4*x^2 + x*y + 11*y^2, + Class field automorphism defined by 7*x^2 + 7*x*y + 8*y^2) Example over `\QQ` (it is not implemented yet):: @@ -894,10 +924,12 @@ def _list(self): Example over Hilbert class field:: - sage: K3 = heegner_points(389,-52,3).ring_class_field(); K1 = heegner_points(389,-52,1).ring_class_field() + sage: K3 = heegner_points(389,-52,3).ring_class_field() + sage: K1 = heegner_points(389,-52,1).ring_class_field() sage: G = K3.galois_group(K1) sage: G._list() - (Class field automorphism defined by x^2 + 117*y^2, Class field automorphism defined by 9*x^2 - 6*x*y + 14*y^2, Class field automorphism defined by 9*x^2 + 13*y^2, Class field automorphism defined by 9*x^2 + 6*x*y + 14*y^2) + (Class field automorphism defined by x^2 + 117*y^2, Class field automorphism defined by 9*x^2 - 6*x*y + 14*y^2, + Class field automorphism defined by 9*x^2 + 13*y^2, Class field automorphism defined by 9*x^2 + 6*x*y + 14*y^2) """ if self._base_is_QQ(): raise NotImplementedError("Galois group over QQ not yet implemented") @@ -936,12 +968,11 @@ def _quadratic_form_to_alpha(self, f): """ INPUT: - - `f` -- a binary quadratic form with discriminant `c^2 D` + - `f` -- a binary quadratic form with discriminant `c^2 D` OUTPUT: - - an element of the ring of integers of the quadratic - imaginary field + - an element of the ring of integers of the quadratic imaginary field EXAMPLES:: @@ -975,7 +1006,7 @@ def _alpha_to_automorphism(self, alpha): INPUT: - - `\alpha` -- element of quadratic imaginary field coprime to conductor + - `\alpha` -- element of quadratic imaginary field coprime to conductor EXAMPLES:: @@ -998,7 +1029,6 @@ def _alpha_to_automorphism(self, alpha): d = self.__p1_to_automorphism return d[uv] - def _alpha_to_p1_element(self, alpha): r""" Given an element of the ring of integers that is nonzero @@ -1007,12 +1037,11 @@ def _alpha_to_p1_element(self, alpha): INPUT: - - `\alpha` -- element of the ring of integers of the - quadratic imaginary field + - `\alpha` -- element of the ring of integers of the quadratic imaginary field OUTPUT: - - 2-tuple of integers + - 2-tuple of integers EXAMPLES:: @@ -1039,7 +1068,7 @@ def _alpha_to_p1_element(self, alpha): n = gcd(w) w /= n c = P1.N() - w = P1.normalize(ZZ(w[0])%c, ZZ(w[1])%c) + w = P1.normalize(ZZ(w[0]) % c, ZZ(w[1]) % c) if w == (0,0): w = (1,0) return w @@ -1053,11 +1082,11 @@ def _p1_element_to_alpha(self, uv): INPUT: - - ``uv`` -- pair of integers + - ``uv`` -- pair of integers OUTPUT: - - element of maximal order of quadratic field + - element of maximal order of quadratic field EXAMPLES:: @@ -1073,7 +1102,6 @@ def _p1_element_to_alpha(self, uv): B = self.field().quadratic_field().maximal_order().basis() return uv[0]*B[0] + uv[1]*B[1] - def _base_is_QQ(self): r""" Return ``True`` if the base field of this ring class field is `\QQ`. @@ -1157,7 +1185,6 @@ def _base_is_hilbert_class_field(self): M = self.__base return isinstance(M, RingClassField) and M.conductor() == 1 - def __getitem__(self, i): """ EXAMPLES:: @@ -1169,7 +1196,6 @@ def __getitem__(self, i): """ return self._list()[i] - def __len__(self): """ EXAMPLES:: @@ -1216,7 +1242,8 @@ def complex_conjugation(self): sage: E = EllipticCurve('389a') sage: G = E.heegner_point(-7,5).ring_class_field().galois_group() sage: G.complex_conjugation() - Complex conjugation automorphism of Ring class field extension of QQ[sqrt(-7)] of conductor 5 + Complex conjugation automorphism of Ring class field extension + of QQ[sqrt(-7)] of conductor 5 """ if self.base_field() != QQ: raise ValueError("the base field must be fixed by complex conjugation") @@ -1243,7 +1270,7 @@ def __init__(self, parent): """ INPUT: - - ``parent`` -- a group of automorphisms of a ring class field + - ``parent`` -- a group of automorphisms of a ring class field EXAMPLES:: @@ -1262,7 +1289,8 @@ def parent(self): EXAMPLES:: sage: E = EllipticCurve('389a') - sage: s = E.heegner_point(-7,5).ring_class_field().galois_group().complex_conjugation() + sage: G = E.heegner_point(-7,5).ring_class_field().galois_group() + sage: s = G.complex_conjugation() sage: s.parent() Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 5 """ @@ -1275,7 +1303,8 @@ def domain(self): EXAMPLES:: sage: E = EllipticCurve('389a') - sage: s = E.heegner_point(-7,5).ring_class_field().galois_group().complex_conjugation() + sage: G = E.heegner_point(-7,5).ring_class_field().galois_group() + sage: s = G.complex_conjugation() sage: s.domain() Ring class field extension of QQ[sqrt(-7)] of conductor 5 """ @@ -1288,9 +1317,11 @@ class GaloisAutomorphismComplexConjugation(GaloisAutomorphism): EXAMPLES:: - sage: conj = heegner_point(37,-7,5).ring_class_field().galois_group().complex_conjugation() + sage: G = heegner_point(37,-7,5).ring_class_field().galois_group() + sage: conj = G.complex_conjugation() sage: conj - Complex conjugation automorphism of Ring class field extension of QQ[sqrt(-7)] of conductor 5 + Complex conjugation automorphism of Ring class field extension + of QQ[sqrt(-7)] of conductor 5 sage: conj.domain() Ring class field extension of QQ[sqrt(-7)] of conductor 5 @@ -1311,7 +1342,8 @@ def __init__(self, parent): sage: G = heegner_point(37,-7,5).ring_class_field().galois_group() sage: sage.schemes.elliptic_curves.heegner.GaloisAutomorphismComplexConjugation(G) - Complex conjugation automorphism of Ring class field extension of QQ[sqrt(-7)] of conductor 5 + Complex conjugation automorphism of Ring class field extension + of QQ[sqrt(-7)] of conductor 5 """ GaloisAutomorphism.__init__(self, parent) @@ -1366,7 +1398,7 @@ def _repr_(self): sage: conj._repr_() 'Complex conjugation automorphism of Ring class field extension of QQ[sqrt(-7)] of conductor 5' """ - return "Complex conjugation automorphism of %s"%self.domain() + return "Complex conjugation automorphism of %s" % self.domain() ## def __mul__(self, right): ## """ @@ -1396,7 +1428,8 @@ def order(self): """ EXAMPLES:: - sage: conj = heegner_point(37,-7,5).ring_class_field().galois_group().complex_conjugation() + sage: G = heegner_point(37,-7,5).ring_class_field().galois_group() + sage: conj = G.complex_conjugation() sage: conj.order() 2 """ @@ -1422,19 +1455,19 @@ def __init__(self, parent, quadratic_form, alpha=None): r""" INPUT: - - ``parent`` -- a group of automorphisms of a ring class field + - ``parent`` -- a group of automorphisms of a ring class field - - ``quadratic_form`` -- a binary quadratic form that - defines an element of the Galois group of `K_c` over `K`. + - ``quadratic_form`` -- a binary quadratic form that + defines an element of the Galois group of `K_c` over `K`. - - ``\alpha`` -- (default: ``None``) optional data that specified - element corresponding element of `(\mathcal{O}_K / - c\mathcal{O}_K)^* / (\ZZ/c\ZZ)^*`, via class field - theory. + - ``\alpha`` -- (default: ``None``) optional data that specified + element corresponding element of `(\mathcal{O}_K / + c\mathcal{O}_K)^* / (\ZZ/c\ZZ)^*`, via class field theory. EXAMPLES:: - sage: H = heegner_points(389,-20,3); G = H.ring_class_field().galois_group(H.quadratic_field()) + sage: H = heegner_points(389,-20,3) + sage: G = H.ring_class_field().galois_group(H.quadratic_field()) sage: f = BinaryQF_reduced_representatives(-20*9)[0] sage: sage.schemes.elliptic_curves.heegner.GaloisAutomorphismQuadraticForm(G, f) Class field automorphism defined by x^2 + 45*y^2 @@ -1498,9 +1531,11 @@ def alpha(self): sage: K1 = heegner_points(389,-52,1).ring_class_field() sage: G = K5.galois_group(K1) sage: orb = sorted([g.alpha() for g in G]); orb # random (the sign depends on the database being installed or not) - [1, -1/2*sqrt_minus_52, 1/2*sqrt_minus_52 + 1, 1/2*sqrt_minus_52 - 1, 1/2*sqrt_minus_52 - 2, -1/2*sqrt_minus_52 - 2] + [1, -1/2*sqrt_minus_52, 1/2*sqrt_minus_52 + 1, 1/2*sqrt_minus_52 - 1, + 1/2*sqrt_minus_52 - 2, -1/2*sqrt_minus_52 - 2] sage: sorted([x^2 for x in orb]) # just for testing - [-13, -sqrt_minus_52 - 12, sqrt_minus_52 - 12, -2*sqrt_minus_52 - 9, 2*sqrt_minus_52 - 9, 1] + [-13, -sqrt_minus_52 - 12, sqrt_minus_52 - 12, + -2*sqrt_minus_52 - 9, 2*sqrt_minus_52 - 9, 1] """ if self.__alpha is None: raise ValueError("alpha data not defined") @@ -1589,7 +1624,7 @@ def _repr_(self): sage: s._repr_() 'Class field automorphism defined by x^2 + 45*y^2' """ - return "Class field automorphism defined by %s"%self.__quadratic_form + return "Class field automorphism defined by %s" % self.__quadratic_form def __mul__(self, right): """ @@ -1601,7 +1636,8 @@ def __mul__(self, right): sage: s * s Class field automorphism defined by x^2 + 45*y^2 sage: G = s.parent(); list(G) - [Class field automorphism defined by x^2 + 45*y^2, Class field automorphism defined by 2*x^2 + 2*x*y + 23*y^2, Class field automorphism defined by 5*x^2 + 9*y^2, Class field automorphism defined by 7*x^2 + 4*x*y + 7*y^2] + [Class field automorphism defined by x^2 + 45*y^2, Class field automorphism defined by 2*x^2 + 2*x*y + 23*y^2, + Class field automorphism defined by 5*x^2 + 9*y^2, Class field automorphism defined by 7*x^2 + 4*x*y + 7*y^2] sage: G[0]*G[0] Class field automorphism defined by x^2 + 45*y^2 sage: G[1]*G[2] == G[3] @@ -1647,7 +1683,8 @@ def ideal(self): sage: G[1].ideal() Fractional ideal (2, 1/2*sqrt_minus_20 + 1) sage: [s.ideal().gens() for s in G] - [(1, 3/2*sqrt_minus_20), (2, 3/2*sqrt_minus_20 - 1), (5, 3/2*sqrt_minus_20), (7, 3/2*sqrt_minus_20 - 2)] + [(1, 3/2*sqrt_minus_20), (2, 3/2*sqrt_minus_20 - 1), + (5, 3/2*sqrt_minus_20), (7, 3/2*sqrt_minus_20 - 2)] """ M = self.parent().field() K = M.quadratic_field() @@ -1655,9 +1692,9 @@ def ideal(self): c = M.conductor() sqrtD = K.gen() (A,B,C) = f - if A%c == 0: + if A % c == 0: A, C = C, A - return K.maximal_order().ideal([A, (-B+c*sqrtD)/2]) + return K.fractional_ideal([A, (-B+c*sqrtD)/2]) ## def __call__(self, z): ## """ @@ -1778,7 +1815,7 @@ def _repr_(self): sage: H._repr_() 'Heegner point of level 389, discriminant -7, and conductor 5' """ - return "Heegner point of level %s, discriminant %s, and conductor %s"%( + return "Heegner point of level %s, discriminant %s, and conductor %s" % ( self.__N, self.__D, self.__c) def __hash__(self): @@ -1815,7 +1852,8 @@ def conductor(self): sage: heegner_point(389,-7,5).conductor() 5 sage: E = EllipticCurve('37a1'); P = E.kolyvagin_point(-67,7); P - Kolyvagin point of discriminant -67 and conductor 7 on elliptic curve of conductor 37 + Kolyvagin point of discriminant -67 and conductor 7 + on elliptic curve of conductor 37 sage: P.conductor() 7 sage: E = EllipticCurve('389a'); P = E.heegner_point(-7, 5); P.conductor() @@ -1833,7 +1871,8 @@ def discriminant(self): sage: heegner_point(389,-7,5).discriminant() -7 sage: E = EllipticCurve('37a1'); P = E.kolyvagin_point(-67,7); P - Kolyvagin point of discriminant -67 and conductor 7 on elliptic curve of conductor 37 + Kolyvagin point of discriminant -67 and conductor 7 + on elliptic curve of conductor 37 sage: P.discriminant() -67 sage: E = EllipticCurve('389a'); P = E.heegner_point(-7, 5); P.discriminant() @@ -1850,11 +1889,13 @@ def quadratic_field(self): sage: x = heegner_point(37,-7,5) sage: x.quadratic_field() - Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I sage: E = EllipticCurve('37a'); P = E.heegner_point(-40) sage: P.quadratic_field() - Number Field in sqrt_minus_40 with defining polynomial x^2 + 40 with sqrt_minus_40 = 6.324555320336759?*I + Number Field in sqrt_minus_40 with defining polynomial x^2 + 40 + with sqrt_minus_40 = 6.324555320336759?*I sage: P.quadratic_field() is P.quadratic_field() True sage: type(P.quadratic_field()) @@ -1871,13 +1912,15 @@ def quadratic_order(self): EXAMPLES:: sage: heegner_point(389,-7,5).quadratic_order() - Order in Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Order in Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I sage: heegner_point(389,-7,5).quadratic_order().basis() [1, 5*sqrt_minus_7] sage: E = EllipticCurve('37a'); P = E.heegner_point(-40,11) sage: P.quadratic_order() - Order in Number Field in sqrt_minus_40 with defining polynomial x^2 + 40 with sqrt_minus_40 = 6.324555320336759?*I + Order in Number Field in sqrt_minus_40 with defining polynomial x^2 + 40 + with sqrt_minus_40 = 6.324555320336759?*I sage: P.quadratic_order().basis() [1, 11*sqrt_minus_40] """ @@ -1938,7 +1981,7 @@ def __init__(self, N): """ INPUT: - - `N` -- level, a positive integer + - `N` -- level, a positive integer EXAMPLES:: @@ -2016,7 +2059,7 @@ def _repr_(self): sage: heegner_points(389)._repr_() 'Set of all Heegner points on X_0(389)' """ - return "Set of all Heegner points on X_0(%s)"%self.level() + return "Set of all Heegner points on X_0(%s)" % self.level() def reduce_mod(self, ell): r""" @@ -2026,7 +2069,7 @@ def reduce_mod(self, ell): INPUT: - - `\ell` -- prime + - `\ell` -- prime EXAMPLES:: @@ -2042,11 +2085,11 @@ def discriminants(self, n=10, weak=False): INPUT: - - `n` -- nonnegative integer + - `n` -- nonnegative integer - - ``weak`` -- bool (default: ``False``); if ``True`` only require - weak Heegner hypothesis, which is the same as usual but - without the condition that `\gcd(D,N)=1`. + - ``weak`` -- bool (default: ``False``); if ``True`` only require + weak Heegner hypothesis, which is the same as usual but + without the condition that `\gcd(D,N)=1`. EXAMPLES:: @@ -2064,7 +2107,7 @@ def discriminants(self, n=10, weak=False): The discriminant -111 satisfies only the weak Heegner hypothesis, since it is divisible by 37:: - sage: X.discriminants(15,weak=True) + sage: X.discriminants(15, weak=True) [-7, -11, -40, -47, -67, -71, -83, -84, -95, -104, -107, -111, -115, -120, -123] """ N = self.level() @@ -2096,7 +2139,8 @@ class HeegnerPoints_level_disc(HeegnerPoints): sage: H.discriminant() -7 sage: H.quadratic_field() - Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I sage: H.kolyvagin_conductors() [1, 3, 5, 13, 15, 17, 19, 31, 39, 41] @@ -2107,9 +2151,9 @@ def __init__(self, N, D): """ INPUT: - - `N` -- positive integer + - `N` -- positive integer - - `D` -- negative fundamental discriminant + - `D` -- negative fundamental discriminant EXAMPLES:: @@ -2119,7 +2163,7 @@ def __init__(self, N, D): HeegnerPoints.__init__(self, N) D = ZZ(D) if not satisfies_weak_heegner_hypothesis(N,D): - raise ValueError("D (=%s) must satisfy the weak Heegner hypothesis for N (=%s)"%(D,N)) + raise ValueError("D (=%s) must satisfy the weak Heegner hypothesis for N (=%s)" % (D,N)) self.__D = D def __eq__(self, other): @@ -2161,10 +2205,9 @@ def _repr_(self): sage: heegner_points(389,-7)._repr_() 'Set of all Heegner points on X_0(389) associated to QQ[sqrt(-7)]' """ - return "Set of all Heegner points on X_0(%s) associated to QQ[sqrt(%s)]"%( + return "Set of all Heegner points on X_0(%s) associated to QQ[sqrt(%s)]" % ( self.level(), self.discriminant()) - def discriminant(self): r""" Return the discriminant of the quadratic imaginary extension `K`. @@ -2185,10 +2228,11 @@ def quadratic_field(self): sage: E = EllipticCurve('389a'); K = E.heegner_point(-7,5).ring_class_field() sage: K.quadratic_field() - Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I """ - D = self.__D - var = 'sqrt_minus_%s'%(-D) + D = self.__D + var = 'sqrt_minus_%s' % (-D) return number_field.QuadraticField(D,var) def kolyvagin_conductors(self, r=None, n=10, E=None, m=None): @@ -2206,17 +2250,17 @@ def kolyvagin_conductors(self, r=None, n=10, E=None, m=None): INPUT: - - `r` -- (default: ``None``) nonnegative integer or ``None`` + - `r` -- (default: ``None``) nonnegative integer or ``None`` - - `n` -- positive integer + - `n` -- positive integer - - `E` -- an elliptic curve + - `E` -- an elliptic curve - - `m` -- a positive integer + - `m` -- a positive integer EXAMPLES:: - sage: H = heegner_points(389,-7) + sage: H = heegner_points(389, -7) sage: H.kolyvagin_conductors(0) [1] sage: H.kolyvagin_conductors(1) @@ -2225,9 +2269,9 @@ def kolyvagin_conductors(self, r=None, n=10, E=None, m=None): [3, 5, 13, 17, 19, 31, 41, 47, 59, 61, 73, 83, 89, 97, 101] sage: H.kolyvagin_conductors(1,5) [3, 5, 13, 17, 19] - sage: H.kolyvagin_conductors(1,5,EllipticCurve('389a'),3) + sage: H.kolyvagin_conductors(1, 5, EllipticCurve('389a'), 3) [5, 17, 41, 59, 83] - sage: H.kolyvagin_conductors(2,5,EllipticCurve('389a'),3) + sage: H.kolyvagin_conductors(2, 5, EllipticCurve('389a'), 3) [85, 205, 295, 415, 697] """ D = self.__D @@ -2268,30 +2312,30 @@ def is_kolyvagin_conductor(N, E, D, r, n, c): INPUT: - - `N` -- level (positive integer) + - `N` -- level (positive integer) - - `E` -- elliptic curve or ``None`` + - `E` -- elliptic curve or ``None`` - - `D` -- negative fundamental discriminant + - `D` -- negative fundamental discriminant - - `r` -- number of prime factors (nonnegative integer) or ``None`` + - `r` -- number of prime factors (nonnegative integer) or ``None`` - - `n` -- torsion order (i.e., do we get class in `(E(K_c)/n E(K_c))^{Gal(K_c/K)}`?) + - `n` -- torsion order (i.e., do we get class in `(E(K_c)/n E(K_c))^{Gal(K_c/K)}`?) - - `c` -- conductor (positive integer) + - `c` -- conductor (positive integer) EXAMPLES:: sage: from sage.schemes.elliptic_curves.heegner import is_kolyvagin_conductor - sage: is_kolyvagin_conductor(389,None,-7,1,None,5) + sage: is_kolyvagin_conductor(389, None, -7, 1, None, 5) True - sage: is_kolyvagin_conductor(389,None,-7,1,None,7) + sage: is_kolyvagin_conductor(389, None, -7, 1, None, 7) False - sage: is_kolyvagin_conductor(389,None,-7,1,None,11) + sage: is_kolyvagin_conductor(389, None, -7, 1, None, 11) False - sage: is_kolyvagin_conductor(389,EllipticCurve('389a'),-7,1,3,5) + sage: is_kolyvagin_conductor(389, EllipticCurve('389a'), -7, 1, 3, 5) True - sage: is_kolyvagin_conductor(389,EllipticCurve('389a'),-7,1,11,5) + sage: is_kolyvagin_conductor(389, EllipticCurve('389a'), -7, 1, 11, 5) False """ ND = N*D @@ -2336,7 +2380,8 @@ class HeegnerPoints_level_disc_cond(HeegnerPoints_level, HeegnerPoints_level_dis (147, 631) sage: H.quadratic_field() - Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I sage: H.ring_class_field() Ring class field extension of QQ[sqrt(-7)] of conductor 5 @@ -2355,11 +2400,11 @@ def __init__(self, N, D, c=ZZ(1)): INPUT: - - `N` -- positive integer (the level) + - `N` -- positive integer (the level) - - `D` -- negative fundamental discriminant + - `D` -- negative fundamental discriminant - - `c` -- conductor (default: 1) + - `c` -- conductor (default: 1) EXAMPLES:: @@ -2411,7 +2456,7 @@ def _repr_(self): sage: H = heegner_points(37,-7,5); H._repr_() 'All Heegner points of conductor 5 on X_0(37) associated to QQ[sqrt(-7)]' """ - return "All Heegner points of conductor %s on X_0(%s) associated to QQ[sqrt(%s)]"%( + return "All Heegner points of conductor %s on X_0(%s) associated to QQ[sqrt(%s)]" % ( self.conductor(), self.level(), self.discriminant()) def conductor(self): @@ -2471,9 +2516,11 @@ def __getitem__(self, i): sage: len(H) 12 sage: H[0] - Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 and conductor 5 on X_0(389) + Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 and conductor 5 + on X_0(389) sage: H[-1] - Heegner point 5/5446*sqrt(-7) - 757/778 of discriminant -7 and conductor 5 on X_0(389) + Heegner point 5/5446*sqrt(-7) - 757/778 of discriminant -7 and conductor 5 + on X_0(389) """ return self.points()[i] @@ -2524,8 +2571,7 @@ def betas(self): N = self.level() R = Integers(4*N) m = 2*N - return tuple(sorted( set([a%m for a in R(D).sqrt(all=True)]) )) - + return tuple(sorted( set([a % m for a in R(D).sqrt(all=True)]) )) @cached_method def points(self, beta=None): @@ -2538,17 +2584,25 @@ def points(self, beta=None): EXAMPLES:: - sage: H = heegner_points(389,-7,5); H + sage: H = heegner_points(389, -7, 5); H All Heegner points of conductor 5 on X_0(389) associated to QQ[sqrt(-7)] sage: H.points() - (Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 and conductor 5 on X_0(389), ..., Heegner point 5/5446*sqrt(-7) - 757/778 of discriminant -7 and conductor 5 on X_0(389)) + (Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 and conductor 5 + on X_0(389), + ..., + Heegner point 5/5446*sqrt(-7) - 757/778 of discriminant -7 and conductor 5 + on X_0(389)) sage: H.betas() (147, 631) sage: [x.tau() for x in H.points(147)] - [5/778*sqrt_minus_7 - 147/778, 5/1556*sqrt_minus_7 - 147/1556, 5/1556*sqrt_minus_7 - 925/1556, 5/3112*sqrt_minus_7 - 1703/3112, 5/3112*sqrt_minus_7 - 2481/3112, 5/5446*sqrt_minus_7 - 21/778] + [5/778*sqrt_minus_7 - 147/778, 5/1556*sqrt_minus_7 - 147/1556, + 5/1556*sqrt_minus_7 - 925/1556, 5/3112*sqrt_minus_7 - 1703/3112, + 5/3112*sqrt_minus_7 - 2481/3112, 5/5446*sqrt_minus_7 - 21/778] sage: [x.tau() for x in H.points(631)] - [5/778*sqrt_minus_7 - 631/778, 5/1556*sqrt_minus_7 - 631/1556, 5/1556*sqrt_minus_7 - 1409/1556, 5/3112*sqrt_minus_7 - 631/3112, 5/3112*sqrt_minus_7 - 1409/3112, 5/5446*sqrt_minus_7 - 757/778] + [5/778*sqrt_minus_7 - 631/778, 5/1556*sqrt_minus_7 - 631/1556, + 5/1556*sqrt_minus_7 - 1409/1556, 5/3112*sqrt_minus_7 - 631/3112, + 5/3112*sqrt_minus_7 - 1409/3112, 5/5446*sqrt_minus_7 - 757/778] The result is cached and is a tuple (since it is immutable):: @@ -2601,9 +2655,9 @@ def plot(self, *args, **kwds): EXAMPLES:: - sage: heegner_points(389,-7,5).plot(pointsize=50, rgbcolor='red') + sage: heegner_points(389,-7,5).plot(pointsize=50, rgbcolor='red') # needs sage.plot Graphics object consisting of 12 graphics primitives - sage: heegner_points(53,-7,15).plot(pointsize=50, rgbcolor='purple') + sage: heegner_points(53,-7,15).plot(pointsize=50, rgbcolor='purple') # needs sage.plot Graphics object consisting of 48 graphics primitives """ return sum(z.plot(*args, **kwds) for z in self) @@ -2616,7 +2670,7 @@ class HeegnerPointOnX0N(HeegnerPoint): EXAMPLES:: - sage: x = heegner_point(37,-7,5); x + sage: x = heegner_point(37, -7, 5); x Heegner point 5/74*sqrt(-7) - 11/74 of discriminant -7 and conductor 5 on X_0(37) sage: type(x) <class 'sage.schemes.elliptic_curves.heegner.HeegnerPointOnX0N'> @@ -2627,11 +2681,13 @@ class HeegnerPointOnX0N(HeegnerPoint): sage: x.discriminant() -7 sage: x.quadratic_field() - Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I sage: x.quadratic_form() 37*x^2 + 11*x*y + 2*y^2 sage: x.quadratic_order() - Order in Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Order in Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I sage: x.tau() 5/74*sqrt_minus_7 - 11/74 sage: loads(dumps(x)) == x @@ -2641,27 +2697,30 @@ def __init__(self, N, D, c=ZZ(1), f=None, check=True): r""" INPUT: - - `N` -- positive integer + - `N` -- positive integer - - `D` -- fundamental discriminant, a negative integer + - `D` -- fundamental discriminant, a negative integer - - `c` -- conductor, a positive integer coprime to `N` + - `c` -- conductor, a positive integer coprime to `N` - - `f` -- binary quadratic form, 3-tuple `(A,B,C)` of coefficients - of `AX^2 + BXY + CY^2`, or element of quadratic imaginary - field `\QQ(\sqrt{D})` in the upper half plan. + - `f` -- binary quadratic form, 3-tuple `(A,B,C)` of coefficients + of `AX^2 + BXY + CY^2`, or element of quadratic imaginary + field `\QQ(\sqrt{D})` in the upper half plan. - - ``check`` -- bool, default: ``True``. should not be used - except internally. + - ``check`` -- bool, default: ``True``. should not be used + except internally. EXAMPLES:: + sage: from sage.schemes.elliptic_curves.heegner import HeegnerPointOnX0N sage: x = heegner_point(389, -7, 5); x - Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 and conductor 5 on X_0(389) + Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 and conductor 5 + on X_0(389) sage: type(x) <class 'sage.schemes.elliptic_curves.heegner.HeegnerPointOnX0N'> - sage: sage.schemes.elliptic_curves.heegner.HeegnerPointOnX0N(389, -7, 5, None, check=False) - Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 and conductor 5 on X_0(389) + sage: HeegnerPointOnX0N(389, -7, 5, None, check=False) + Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 and conductor 5 + on X_0(389) """ if check: N = ZZ(N) @@ -2670,7 +2729,7 @@ def __init__(self, N, D, c=ZZ(1), f=None, check=True): if c.gcd(N) != 1: raise ValueError("conductor c (=%s) must be coprime to N (=%s)" % (c, N)) if not satisfies_weak_heegner_hypothesis(N, D): - raise ValueError("N (=%s) and D (=%s) must satisfy the Heegner hypothesis"%(N, D)) + raise ValueError("N (=%s) and D (=%s) must satisfy the Heegner hypothesis" % (N, D)) if f is not None: if isinstance(f, tuple): if len(f) != 3: @@ -2679,7 +2738,7 @@ def __init__(self, N, D, c=ZZ(1), f=None, check=True): elif isinstance(f, BinaryQF): # convert from BinaryQF f = tuple(f) - elif sage.rings.number_field.number_field_element.is_NumberFieldElement(f): + elif isinstance(f, NumberFieldElement_base): # tau = number field element g = f.minpoly() if g.degree() != 2: @@ -2690,7 +2749,7 @@ def __init__(self, N, D, c=ZZ(1), f=None, check=True): raise TypeError("f must be a 3-tuple, quadratic form, or element of the upper half plane") A, B, C = f if B*B - 4*A*C != D*c*c: - raise ValueError("f (=%s) must have discriminant %s"%(f, D*c*c)) + raise ValueError("f (=%s) must have discriminant %s" % (f, D*c*c)) HeegnerPoint.__init__(self, N, D, c) if f is None: # We know that N|A, so A = N is optimal. @@ -2700,7 +2759,6 @@ def __init__(self, N, D, c=ZZ(1), f=None, check=True): f = (A,B,C) self.__f = f - def __hash__(self): """ The hash is obtained from the hash provided by :class:`HeegnerPoint`, @@ -2708,7 +2766,7 @@ def __hash__(self): EXAMPLES:: - sage: x = heegner_point(37,-7,5) + sage: x = heegner_point(37, -7, 5) sage: from sage.schemes.elliptic_curves.heegner import HeegnerPoint sage: hash(x) == hash( (HeegnerPoint.__hash__(x), x.reduced_quadratic_form()) ) True @@ -2722,7 +2780,7 @@ def __richcmp__(self, x, op): EXAMPLES:: sage: x1 = EllipticCurve('389a').heegner_point(-7).heegner_point_on_X0N() - sage: x5 = EllipticCurve('389a').heegner_point(-7,5).heegner_point_on_X0N() + sage: x5 = EllipticCurve('389a').heegner_point(-7, 5).heegner_point_on_X0N() sage: x1 == x1 True sage: x1 < x5 @@ -2743,32 +2801,33 @@ def _repr_(self): EXAMPLES:: - sage: x = heegner_point(37,-7,5); x._repr_() + sage: x = heegner_point(37, -7, 5); x._repr_() 'Heegner point 5/74*sqrt(-7) - 11/74 of discriminant -7 and conductor 5 on X_0(37)' """ c = self.conductor() - s = " and conductor %s"%c if c != 1 else "" + s = " and conductor %s" % c if c != 1 else "" N = self.level() D = self.discriminant() - tau = repr(self.tau()).replace('sqrt_minus_%s'%(-D),'sqrt(%s)'%D) - return "Heegner point %s of discriminant %s%s on X_0(%s)"%(tau, D, s, N) + tau = repr(self.tau()).replace('sqrt_minus_%s' % (-D),'sqrt(%s)' % D) + return "Heegner point %s of discriminant %s%s on X_0(%s)" % (tau, D, s, N) def atkin_lehner_act(self, Q=None): r""" - Given an integer Q dividing the level N such that `\gcd(Q, N/Q) = 1`, returns the + Given an integer Q dividing the level N such that `\gcd(Q, N/Q) = 1`, return the image of this Heegner point under the Atkin-Lehner operator `W_Q`. INPUT: - - `Q` -- positive divisor of `N`; if not given, default to `N` + - `Q` -- positive divisor of `N`; if not given, default to `N` EXAMPLES:: - sage: x = heegner_point(389,-7,5) + sage: x = heegner_point(389, -7, 5) sage: x.atkin_lehner_act() - Heegner point 5/199168*sqrt(-7) - 631/199168 of discriminant -7 and conductor 5 on X_0(389) + Heegner point 5/199168*sqrt(-7) - 631/199168 of discriminant -7 + and conductor 5 on X_0(389) - sage: x = heegner_point(45,D=-11,c=1); x + sage: x = heegner_point(45, D=-11, c=1); x Heegner point 1/90*sqrt(-11) - 13/90 of discriminant -11 on X_0(45) sage: x.atkin_lehner_act(5) Heegner point 1/90*sqrt(-11) + 23/90 of discriminant -11 on X_0(45) @@ -2800,7 +2859,7 @@ def quadratic_form(self): EXAMPLES:: - sage: heegner_point(389,-7,5).quadratic_form() + sage: heegner_point(389, -7, 5).quadratic_form() 389*x^2 + 147*x*y + 14*y^2 """ # It is good/important that this return a copy, since @@ -2815,7 +2874,7 @@ def reduced_quadratic_form(self): EXAMPLES:: - sage: x = heegner_point(389,-7,5) + sage: x = heegner_point(389, -7, 5) sage: x.quadratic_form() 389*x^2 + 147*x*y + 14*y^2 sage: x.reduced_quadratic_form() @@ -2834,7 +2893,7 @@ def tau(self): EXAMPLES:: - sage: x = heegner_point(37,-7,5); tau = x.tau(); tau + sage: x = heegner_point(37, -7, 5); tau = x.tau(); tau 5/74*sqrt_minus_7 - 11/74 sage: 37 * tau.minpoly() 37*x^2 + 11*x + 2 @@ -2854,14 +2913,17 @@ def map_to_curve(self, E): EXAMPLES:: - sage: x = heegner_point(389,-7,5); x - Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 and conductor 5 on X_0(389) + sage: x = heegner_point(389, -7, 5); x + Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 + and conductor 5 on X_0(389) sage: y = x.map_to_curve(EllipticCurve('389a')); y - Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 389 + Heegner point of discriminant -7 and conductor 5 + on elliptic curve of conductor 389 sage: y.curve().cremona_label() '389a1' sage: y.heegner_point_on_X0N() - Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 and conductor 5 on X_0(389) + Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 + and conductor 5 on X_0(389) You can also directly apply the modular parametrization of the elliptic curve:: @@ -2880,10 +2942,14 @@ def galois_orbit_over_K(self): EXAMPLES:: - sage: x = heegner_point(389,-7,3); x - Heegner point 3/778*sqrt(-7) - 223/778 of discriminant -7 and conductor 3 on X_0(389) + sage: x = heegner_point(389, -7, 3); x + Heegner point 3/778*sqrt(-7) - 223/778 of discriminant -7 + and conductor 3 on X_0(389) sage: x.galois_orbit_over_K() - [Heegner point 3/778*sqrt(-7) - 223/778 of discriminant -7 and conductor 3 on X_0(389), Heegner point 3/1556*sqrt(-7) - 223/1556 of discriminant -7 and conductor 3 on X_0(389), Heegner point 3/1556*sqrt(-7) - 1001/1556 of discriminant -7 and conductor 3 on X_0(389), Heegner point 3/3112*sqrt(-7) - 223/3112 of discriminant -7 and conductor 3 on X_0(389)] + [Heegner point 3/778*sqrt(-7) - 223/778 of discriminant -7 and conductor 3 on X_0(389), + Heegner point 3/1556*sqrt(-7) - 223/1556 of discriminant -7 and conductor 3 on X_0(389), + Heegner point 3/1556*sqrt(-7) - 1001/1556 of discriminant -7 and conductor 3 on X_0(389), + Heegner point 3/3112*sqrt(-7) - 223/3112 of discriminant -7 and conductor 3 on X_0(389)] """ c = self.conductor() N = self.level() @@ -2952,15 +3018,15 @@ def __init__(self, E, x, check=True): - `x` -- Heegner point on `X_0(N)` - ``check`` -- bool (default: ``True``); if ``True``, ensure that `D`, - `c` are of type Integer and define a Heegner point - on `E` + `c` are of type Integer and define a Heegner point on `E` EXAMPLES:: sage: x = heegner_point(389,-7,5) sage: E = EllipticCurve('389a') sage: sage.schemes.elliptic_curves.heegner.HeegnerPointOnEllipticCurve(E, x) - Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 389 + Heegner point of discriminant -7 and conductor 5 on elliptic curve + of conductor 389 """ if check: if E.conductor() != x.level(): @@ -2980,15 +3046,15 @@ def satisfies_kolyvagin_hypothesis(self, n=None): INPUT: - `n` -- positive integer + - `n` -- positive integer EXAMPLES:: sage: EllipticCurve('389a').heegner_point(-7).satisfies_kolyvagin_hypothesis() True - sage: EllipticCurve('389a').heegner_point(-7,5).satisfies_kolyvagin_hypothesis() + sage: EllipticCurve('389a').heegner_point(-7, 5).satisfies_kolyvagin_hypothesis() True - sage: EllipticCurve('389a').heegner_point(-7,11).satisfies_kolyvagin_hypothesis() + sage: EllipticCurve('389a').heegner_point(-7, 11).satisfies_kolyvagin_hypothesis() False """ if n is not None: @@ -3005,7 +3071,7 @@ def __hash__(self): EXAMPLES:: - sage: x = EllipticCurve('389a').heegner_point(-7,5) + sage: x = EllipticCurve('389a').heegner_point(-7, 5) sage: hash(x) == hash( (x.curve(), x.heegner_point_on_X0N()) ) True """ @@ -3016,7 +3082,7 @@ def __eq__(self, right): EXAMPLES:: sage: y1 = EllipticCurve('389a').heegner_point(-7) - sage: y5 = EllipticCurve('389a').heegner_point(-7,5) + sage: y5 = EllipticCurve('389a').heegner_point(-7, 5) sage: y1 == y1 True sage: y5 == y5 @@ -3034,7 +3100,7 @@ def __ne__(self, other): EXAMPLES:: sage: y1 = EllipticCurve('389a').heegner_point(-7) - sage: y5 = EllipticCurve('389a').heegner_point(-7,5) + sage: y5 = EllipticCurve('389a').heegner_point(-7, 5) sage: y1 != y1 False sage: y5 != y5 @@ -3056,9 +3122,9 @@ def _repr_(self): sage: P._repr_() 'Heegner point of discriminant -7 and conductor 97 on elliptic curve of conductor 389' """ - s = " and conductor %s"%self.conductor() if self.conductor() != 1 else "" + s = " and conductor %s" % self.conductor() if self.conductor() != 1 else "" N = self.__E.conductor() - return "Heegner point of discriminant %s%s on elliptic curve of conductor %s"%(self.discriminant(), s, N) + return "Heegner point of discriminant %s%s on elliptic curve of conductor %s" % (self.discriminant(), s, N) def heegner_point_on_X0N(self): r""" @@ -3067,9 +3133,11 @@ def heegner_point_on_X0N(self): EXAMPLES:: sage: E = EllipticCurve('37a'); P = E.heegner_point(-7,5); P - Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 37 + Heegner point of discriminant -7 and conductor 5 on elliptic curve + of conductor 37 sage: P.heegner_point_on_X0N() - Heegner point 5/74*sqrt(-7) - 11/74 of discriminant -7 and conductor 5 on X_0(37) + Heegner point 5/74*sqrt(-7) - 11/74 of discriminant -7 and conductor 5 + on X_0(37) """ return self.__x @@ -3151,7 +3219,8 @@ def kolyvagin_point(self): sage: P = y.kolyvagin_point(); P Kolyvagin point of discriminant -7 on elliptic curve of conductor 37 sage: P.numerical_approx() # abs tol 1e-15 - (-3.36910401903861e-16 - 2.22076195576076e-16*I : 3.33066907387547e-16 + 2.22076195576075e-16*I : 1.00000000000000) + (-3.36910401903861e-16 - 2.22076195576076e-16*I + : 3.33066907387547e-16 + 2.22076195576075e-16*I : 1.00000000000000) """ return KolyvaginPoint(self) @@ -3167,12 +3236,13 @@ def _trace_index(self, *args, **kwds): OUTPUT: - - ``Integer`` -- returns an integer + - ``Integer`` -- returns an integer EXAMPLES:: sage: E = EllipticCurve('77a1') - sage: P = E.heegner_point(-19); y = P._trace_numerical_conductor_1(); [c.real() for c in y] + sage: P = E.heegner_point(-19); y = P._trace_numerical_conductor_1() + sage: [c.real() for c in y] [-1.2...e-16, -1.00000000000000, 1.00000000000000] sage: -2*E.gens()[0] (0 : -1 : 1) @@ -3182,7 +3252,8 @@ def _trace_index(self, *args, **kwds): sage: P = E.heegner_point(-68); P Heegner point of discriminant -68 on elliptic curve of conductor 77 sage: N(P) - (0.219223593595584 - 1.87443160153148*I : -1.34232921921325 - 1.52356748877889*I : 1.00000000000000) + (0.219223593595584 - 1.87443160153148*I + : -1.34232921921325 - 1.52356748877889*I : 1.00000000000000) sage: P._trace_index() 0 """ @@ -3222,7 +3293,8 @@ def quadratic_form(self): 389*x^2 + 147*x*y + 14*y^2 sage: P = EllipticCurve('389a').heegner_point(-7, 5, (778,925,275)); P - Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 389 + Heegner point of discriminant -7 and conductor 5 on elliptic curve + of conductor 389 sage: P.quadratic_form() 778*x^2 + 925*x*y + 275*y^2 """ @@ -3242,14 +3314,15 @@ def numerical_approx(self, prec=53, algorithm=None): INPUT: - - prec -- (default: ``None``) the working precision + - prec -- (default: ``None``) the working precision EXAMPLES:: sage: E = EllipticCurve('37a'); P = E.heegner_point(-7); P Heegner point of discriminant -7 on elliptic curve of conductor 37 sage: P.numerical_approx() # abs tol 1e-15 - (-3.36910401903861e-16 - 2.22076195576076e-16*I : 3.33066907387547e-16 + 2.22076195576075e-16*I : 1.00000000000000) + (-3.36910401903861e-16 - 2.22076195576076e-16*I + : 3.33066907387547e-16 + 2.22076195576075e-16*I : 1.00000000000000) sage: P.numerical_approx(10) # expect random digits (0.0030 - 0.0028*I : -0.0030 + 0.0028*I : 1.0) sage: P.numerical_approx(100)[0] # expect random digits @@ -3257,7 +3330,8 @@ def numerical_approx(self, prec=53, algorithm=None): sage: E = EllipticCurve('37a'); P = E.heegner_point(-40); P Heegner point of discriminant -40 on elliptic curve of conductor 37 sage: P.numerical_approx() # abs tol 1e-14 - (-3.15940603400359e-16 + 1.41421356237309*I : 1.00000000000000 - 1.41421356237309*I : 1.00000000000000) + (-3.15940603400359e-16 + 1.41421356237309*I + : 1.00000000000000 - 1.41421356237309*I : 1.00000000000000) A rank 2 curve, where all Heegner points of conductor 1 are 0:: @@ -3271,15 +3345,20 @@ def numerical_approx(self, prec=53, algorithm=None): However, Heegner points of bigger conductor are often nonzero:: sage: E = EllipticCurve('389a'); P = E.heegner_point(-7, 5); P - Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 389 + Heegner point of discriminant -7 and conductor 5 on elliptic curve + of conductor 389 sage: numerical_approx(P) - (0.675507556926807 + 0.344749649302635*I : -0.377142931401887 + 0.843366227137146*I : 1.00000000000000) + (0.675507556926807 + 0.344749649302635*I + : -0.377142931401887 + 0.843366227137146*I : 1.00000000000000) sage: P.numerical_approx() - (0.6755075569268... + 0.3447496493026...*I : -0.3771429314018... + 0.8433662271371...*I : 1.00000000000000) + (0.6755075569268... + 0.3447496493026...*I + : -0.3771429314018... + 0.8433662271371...*I : 1.00000000000000) sage: E.heegner_point(-7, 11).numerical_approx() - (0.1795583794118... + 0.02035501750912...*I : -0.5573941377055... + 0.2738940831635...*I : 1.00000000000000) + (0.1795583794118... + 0.02035501750912...*I + : -0.5573941377055... + 0.2738940831635...*I : 1.00000000000000) sage: E.heegner_point(-7, 13).numerical_approx() - (1.034302915374... - 3.302744319777...*I : 1.323937875767... + 6.908264226850...*I : 1.00000000000000) + (1.034302915374... - 3.302744319777...*I + : 1.323937875767... + 6.908264226850...*I : 1.00000000000000) We find (probably) the defining polynomial of the `x`-coordinate of `P`, which defines a class field. The shape of @@ -3324,15 +3403,15 @@ def x_poly_exact(self, prec=53, algorithm='lll'): INPUT: - - ``prec`` -- integer (default: 53) + - ``prec`` -- integer (default: 53) - - ``algorithm`` -- 'conjugates' or 'lll' (default); if - 'conjugates', compute numerically all the - conjugates ``y[i]`` of the Heegner point and construct - the characteristic polynomial as the product - `f(X)=(X-y[i])`. If 'lll', compute only one of the - conjugates ``y[0]``, then uses the LLL algorithm to - guess `f(X)`. + - ``algorithm`` -- 'conjugates' or 'lll' (default); if + 'conjugates', compute numerically all the + conjugates ``y[i]`` of the Heegner point and construct + the characteristic polynomial as the product + `f(X)=(X-y[i])`. If 'lll', compute only one of the + conjugates ``y[0]``, then uses the LLL algorithm to + guess `f(X)`. EXAMPLES: @@ -3342,26 +3421,37 @@ def x_poly_exact(self, prec=53, algorithm='lll'): sage: E = EllipticCurve('37a') sage: v = E.heegner_discriminants_list(10) sage: [E.heegner_point(D).x_poly_exact() for D in v] - [x, x, x^2 + 2, x^5 - x^4 + x^3 + x^2 - 2*x + 1, x - 6, x^7 - 2*x^6 + 9*x^5 - 10*x^4 - x^3 + 8*x^2 - 5*x + 1, x^3 + 5*x^2 + 10*x + 4, x^4 - 10*x^3 + 10*x^2 + 12*x - 12, x^8 - 5*x^7 + 7*x^6 + 13*x^5 - 10*x^4 - 4*x^3 + x^2 - 5*x + 7, x^6 - 2*x^5 + 11*x^4 - 24*x^3 + 30*x^2 - 16*x + 4] + [x, x, x^2 + 2, x^5 - x^4 + x^3 + x^2 - 2*x + 1, x - 6, + x^7 - 2*x^6 + 9*x^5 - 10*x^4 - x^3 + 8*x^2 - 5*x + 1, + x^3 + 5*x^2 + 10*x + 4, x^4 - 10*x^3 + 10*x^2 + 12*x - 12, + x^8 - 5*x^7 + 7*x^6 + 13*x^5 - 10*x^4 - 4*x^3 + x^2 - 5*x + 7, + x^6 - 2*x^5 + 11*x^4 - 24*x^3 + 30*x^2 - 16*x + 4] We compute `x`-coordinate polynomials for some Heegner points of conductor bigger than 1 on a rank 2 curve:: sage: E = EllipticCurve('389a'); P = E.heegner_point(-7, 5); P - Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 389 + Heegner point of discriminant -7 and conductor 5 + on elliptic curve of conductor 389 sage: P.x_poly_exact() Traceback (most recent call last): ... - ValueError: insufficient precision to determine Heegner point (fails discriminant test) + ValueError: insufficient precision to determine Heegner point + (fails discriminant test) sage: P.x_poly_exact(120) x^6 + 10/7*x^5 - 867/49*x^4 - 76/245*x^3 + 3148/35*x^2 - 25944/245*x + 48771/1225 - sage: E.heegner_point(-7,11).x_poly_exact(500) - x^10 + 282527/52441*x^9 + 27049007420/2750058481*x^8 - 22058564794/2750058481*x^7 - 140054237301/2750058481*x^6 + 696429998952/30250643291*x^5 + 2791387923058/30250643291*x^4 - 3148473886134/30250643291*x^3 + 1359454055022/30250643291*x^2 - 250620385365/30250643291*x + 181599685425/332757076201 + sage: E.heegner_point(-7, 11).x_poly_exact(500) + x^10 + 282527/52441*x^9 + 27049007420/2750058481*x^8 - 22058564794/2750058481*x^7 + - 140054237301/2750058481*x^6 + 696429998952/30250643291*x^5 + + 2791387923058/30250643291*x^4 - 3148473886134/30250643291*x^3 + + 1359454055022/30250643291*x^2 - 250620385365/30250643291*x + + 181599685425/332757076201 Here we compute a Heegner point of conductor 5 on a rank 3 curve:: sage: E = EllipticCurve('5077a'); P = E.heegner_point(-7,5); P - Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 5077 + Heegner point of discriminant -7 and conductor 5 + on elliptic curve of conductor 5077 sage: P.x_poly_exact(500) x^6 + 1108754853727159228/72351048803252547*x^5 + 88875505551184048168/1953478317687818769*x^4 - 2216200271166098662132/3255797196146364615*x^3 + 14941627504168839449851/9767391588439093845*x^2 - 3456417460183342963918/3255797196146364615*x + 1306572835857500500459/5426328660243941025 @@ -3398,12 +3488,13 @@ def _check_poly_discriminant(self, f): INPUT: - - `f` -- a polynomial + - `f` -- a polynomial EXAMPLES:: sage: E = EllipticCurve('389a'); P = E.heegner_point(-7, 5); P - Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 389 + Heegner point of discriminant -7 and conductor 5 + on elliptic curve of conductor 389 sage: R.<x> = QQ[] sage: P._check_poly_discriminant(x^2 - 5) True @@ -3423,7 +3514,6 @@ def _check_poly_discriminant(self, f): return all(self._check_poly_discriminant(g) for g,_ in f.factor()) - def point_exact(self, prec=53, algorithm='lll', var='a', optimize=False): """ Return exact point on the elliptic curve over a number field @@ -3445,22 +3535,23 @@ def point_exact(self, prec=53, algorithm='lll', var='a', optimize=False): INPUT: - - ``prec`` -- integer (default: 53) + - ``prec`` -- integer (default: 53) - - ``algorithm`` -- see the description of the algorithm - parameter for the ``x_poly_exact`` method. + - ``algorithm`` -- see the description of the algorithm + parameter for the ``x_poly_exact`` method. - - ``var`` -- string (default: 'a') + - ``var`` -- string (default: 'a') - - ``optimize`` -- bool (default; False) if ``True``, try to - optimize defining polynomial for the number field that - the point is defined over. Off by default, since this - can be very expensive. + - ``optimize`` -- bool (default; False) if ``True``, try to + optimize defining polynomial for the number field that + the point is defined over. Off by default, since this + can be very expensive. EXAMPLES:: sage: E = EllipticCurve('389a'); P = E.heegner_point(-7, 5); P - Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 389 + Heegner point of discriminant -7 and conductor 5 + on elliptic curve of conductor 389 sage: z = P.point_exact(200, optimize=True) sage: z[1].charpoly() x^12 + 6*x^11 + 90089/1715*x^10 + 71224/343*x^9 + 52563964/588245*x^8 - 483814934/588245*x^7 - 156744579/16807*x^6 - 2041518032/84035*x^5 + 1259355443184/14706125*x^4 + 3094420220918/14706125*x^3 + 123060442043827/367653125*x^2 + 82963044474852/367653125*x + 211679465261391/1838265625 @@ -3482,14 +3573,14 @@ def point_exact(self, prec=53, algorithm='lll', var='a', optimize=False): return v[0] g, d = make_monic(f) - K = rings.NumberField(g, var) + K = NumberField(g, var) x = K.gen() / d if optimize: KO, from_KO, to_KO = K.optimized_representation() K = KO x = to_KO(x) if K.degree() < 2 * self.ring_class_field().degree_over_K(): - M = rings.QuadraticField(self.discriminant(),'b') + M = QuadraticField(self.discriminant(),'b') KD = K.composite_fields(M, names='a')[0] phi = K.embeddings(KD)[0] x = phi(x) @@ -3538,9 +3629,14 @@ def conjugates_over_K(self): sage: E = EllipticCurve('77a') sage: y = E.heegner_point(-52,5); y - Heegner point of discriminant -52 and conductor 5 on elliptic curve of conductor 77 + Heegner point of discriminant -52 and conductor 5 + on elliptic curve of conductor 77 sage: print([z.quadratic_form() for z in y.conjugates_over_K()]) - [77*x^2 + 52*x*y + 13*y^2, 154*x^2 + 206*x*y + 71*y^2, 539*x^2 + 822*x*y + 314*y^2, 847*x^2 + 1284*x*y + 487*y^2, 1001*x^2 + 52*x*y + y^2, 1078*x^2 + 822*x*y + 157*y^2, 1309*x^2 + 360*x*y + 25*y^2, 1309*x^2 + 2054*x*y + 806*y^2, 1463*x^2 + 976*x*y + 163*y^2, 2233*x^2 + 2824*x*y + 893*y^2, 2387*x^2 + 2054*x*y + 442*y^2, 3619*x^2 + 3286*x*y + 746*y^2] + [77*x^2 + 52*x*y + 13*y^2, 154*x^2 + 206*x*y + 71*y^2, 539*x^2 + 822*x*y + 314*y^2, + 847*x^2 + 1284*x*y + 487*y^2, 1001*x^2 + 52*x*y + y^2, 1078*x^2 + 822*x*y + 157*y^2, + 1309*x^2 + 360*x*y + 25*y^2, 1309*x^2 + 2054*x*y + 806*y^2, + 1463*x^2 + 976*x*y + 163*y^2, 2233*x^2 + 2824*x*y + 893*y^2, + 2387*x^2 + 2054*x*y + 442*y^2, 3619*x^2 + 3286*x*y + 746*y^2] sage: y.quadratic_form() 77*x^2 + 52*x*y + 13*y^2 """ @@ -3557,7 +3653,7 @@ def _numerical_approx_conjugates_over_QQ(self, prec=53): INPUT: - - ``prec`` -- positive integer (default: 53) + - ``prec`` -- positive integer (default: 53) EXAMPLES:: @@ -3588,11 +3684,11 @@ def _numerical_approx_xy_poly(self, prec=53): INPUT: - - ``prec`` -- positive integer (default: 53) + - ``prec`` -- positive integer (default: 53) OUTPUT: - - 2-tuple of polynomials with floating point coefficients + - 2-tuple of polynomials with floating point coefficients EXAMPLES:: @@ -3600,7 +3696,8 @@ def _numerical_approx_xy_poly(self, prec=53): sage: y = E.heegner_point(-7,3); y Heegner point of discriminant -7 and conductor 3 on elliptic curve of conductor 37 sage: y._numerical_approx_xy_poly() # rel tol 1e-14 - (X^8 + 6.00000000000000*X^7 + 8.99999999999998*X^6 - 12.0000000000000*X^5 - 42.0000000000000*X^4 - 17.9999999999999*X^3 + 36.0000000000001*X^2 + 35.9999999999999*X + 8.99999999999995, X^8 + 12.0000000000000*X^7 + 72.0000000000000*X^6 + 270.000000000000*X^5 + 678.000000000001*X^4 + 1152.00000000000*X^3 + 1269.00000000000*X^2 + 810.000000000002*X + 225.000000000001) + (X^8 + 6.00000000000000*X^7 + 8.99999999999998*X^6 - 12.0000000000000*X^5 - 42.0000000000000*X^4 - 17.9999999999999*X^3 + 36.0000000000001*X^2 + 35.9999999999999*X + 8.99999999999995, + X^8 + 12.0000000000000*X^7 + 72.0000000000000*X^6 + 270.000000000000*X^5 + 678.000000000001*X^4 + 1152.00000000000*X^3 + 1269.00000000000*X^2 + 810.000000000002*X + 225.000000000001) """ v = self._numerical_approx_conjugates_over_QQ(prec) R = ComplexField(prec)['X'] @@ -3620,13 +3717,13 @@ def _xy_poly_nearby(self, prec=53, max_error=10**(-10)): INPUT: - - ``prec`` -- positive integer (default: 53) + - ``prec`` -- positive integer (default: 53) - - ``max_error`` -- very small floating point number + - ``max_error`` -- very small floating point number OUTPUT: - - 2-tuple of polynomials with rational coefficients + - 2-tuple of polynomials with rational coefficients EXAMPLES:: @@ -3635,7 +3732,7 @@ def _xy_poly_nearby(self, prec=53, max_error=10**(-10)): Heegner point of discriminant -7 and conductor 3 on elliptic curve of conductor 37 sage: y._xy_poly_nearby() [X^8 + 6*X^7 + 9*X^6 - 12*X^5 - 42*X^4 - 18*X^3 + 36*X^2 + 36*X + 9, - X^8 + 12*X^7 + 72*X^6 + 270*X^5 + 678*X^4 + 1152*X^3 + 1269*X^2 + 810*X + 225] + X^8 + 12*X^7 + 72*X^6 + 270*X^5 + 678*X^4 + 1152*X^3 + 1269*X^2 + 810*X + 225] """ v = self._numerical_approx_xy_poly(prec) return [nearby_rational_poly(g, max_error=max_error) for g in v] @@ -3648,9 +3745,9 @@ def _xy_poly_simplest(self, prec=53, prec2=None): INPUT: - - ``prec`` -- positive integer (default: 53) + - ``prec`` -- positive integer (default: 53) - - ``prec2`` -- passed into simplest_rational_poly function + - ``prec2`` -- passed into simplest_rational_poly function EXAMPLES:: @@ -3682,7 +3779,7 @@ def _square_roots_mod_2N_of_D_mod_4N(self): N = self.__E.conductor() R = Integers(4*N) m = 2*N - return sorted( set([a%m for a in R(self.discriminant()).sqrt(all=True)]) ) + return sorted( set([a % m for a in R(self.discriminant()).sqrt(all=True)]) ) def _trace_numerical_conductor_1(self, prec=53): """ @@ -3692,7 +3789,7 @@ def _trace_numerical_conductor_1(self, prec=53): INPUT: - - `prec` -- bits precision (default: 53) + - `prec` -- bits precision (default: 53) EXAMPLES:: @@ -3718,7 +3815,7 @@ def _trace_numerical_conductor_1(self, prec=53): R, U = self._good_tau_representatives() E = self.__E phi = E.modular_parametrization() - C = rings.ComplexField(prec) + C = ComplexField(prec) F = E.change_ring(C) s = 0 for u, weight in U: @@ -3773,7 +3870,7 @@ def _good_tau_representatives(self): s = s.lift() f = (a*N, b+2*N*s, ZZ( ((b + 2*N*s)**2 - D)/(4*a*N)) ) for d in divs: - Q = d * prod(p**k for p,k in N.factor() if (b-beta)%(p**k)!=0) + Q = d * prod(p**k for p,k in N.factor() if (b-beta) % (p**k) != 0) g = self._qf_atkin_lehner_act(Q, f) gbar = (ZZ(g[0]/N), -g[1], g[2]*N) g = self._qf_reduce(g) @@ -3806,7 +3903,7 @@ def _qf_to_tau(self, f): INPUT: - - `f` -- binary quadratic form + - `f` -- binary quadratic form EXAMPLES:: @@ -3829,7 +3926,7 @@ def _qf_from_tau(self, tau): INPUT: - - `\tau` -- quadratic element of the upper half plane + - `\tau` -- quadratic element of the upper half plane EXAMPLES:: @@ -3842,11 +3939,10 @@ def _qf_from_tau(self, tau): sage: P._qf_from_tau(tau) (57, 26, 3) """ - g = tau.minpoly() + g = tau.minpoly() g *= g.denominator() return (ZZ(g[2]), ZZ(g[1]), ZZ(g[0])) - def _qf_atkin_lehner_act(self, Q, f): r""" Given a positive integer `Q` with `Q | N` and `\gcd(Q, N/Q) = @@ -3860,13 +3956,13 @@ def _qf_atkin_lehner_act(self, Q, f): INPUT: - - `Q` -- integer that divides the level `N` + - `Q` -- integer that divides the level `N` - - `f` -- quadratic form + - `f` -- quadratic form OUTPUT: - - quadratic form + - quadratic form EXAMPLES:: @@ -3890,7 +3986,6 @@ def _qf_atkin_lehner_act(self, Q, f): tau2 = ((u*Q*tau + v) / (N*tau + Q)) return self._qf_from_tau(tau2) - def _qf_reduce(self, f): """ Given a binary quadratic form `f` represented as a 3-tuple @@ -3914,9 +4009,9 @@ def kolyvagin_cohomology_class(self, n=None): INPUT: - - `n` -- positive integer that divides the gcd of `a_p` - and `p+1` for all `p` dividing the conductor. If `n` is - ``None``, choose the largest valid `n`. + - `n` -- positive integer that divides the gcd of `a_p` + and `p+1` for all `p` dividing the conductor. If `n` is + ``None``, choose the largest valid `n`. EXAMPLES:: @@ -3944,7 +4039,8 @@ class KolyvaginPoint(HeegnerPoint): sage: EllipticCurve('37a1').kolyvagin_point(-67) Kolyvagin point of discriminant -67 on elliptic curve of conductor 37 sage: EllipticCurve('389a1').kolyvagin_point(-7, 5) - Kolyvagin point of discriminant -7 and conductor 5 on elliptic curve of conductor 389 + Kolyvagin point of discriminant -7 and conductor 5 + on elliptic curve of conductor 389 One can also associated a Kolyvagin point to a Heegner point:: @@ -4074,7 +4170,7 @@ def numerical_approx(self, prec=53): INPUT: - - ``prec`` -- precision in bits (default: 53) + - ``prec`` -- precision in bits (default: 53) EXAMPLES:: @@ -4086,7 +4182,8 @@ def numerical_approx(self, prec=53): True sage: P = EllipticCurve('389a1').kolyvagin_point(-7, 5); P - Kolyvagin point of discriminant -7 and conductor 5 on elliptic curve of conductor 389 + Kolyvagin point of discriminant -7 and conductor 5 + on elliptic curve of conductor 389 Numerical approximation is only implemented for points of conductor 1:: @@ -4103,7 +4200,7 @@ def point_exact(self, prec=53): """ INPUT: - - ``prec`` -- precision in bits (default: 53) + - ``prec`` -- precision in bits (default: 53) EXAMPLES: @@ -4189,7 +4286,7 @@ def plot(self, prec=53, *args, **kwds): EXAMPLES:: sage: E = EllipticCurve('37a'); P = E.heegner_point(-11).kolyvagin_point() - sage: P.plot(prec=30, pointsize=50, rgbcolor='red') + E.plot() + sage: P.plot(prec=30, pointsize=50, rgbcolor='red') + E.plot() # needs sage.plot Graphics object consisting of 3 graphics primitives """ if self.conductor() != 1: @@ -4206,7 +4303,6 @@ def plot(self, prec=53, *args, **kwds): else: raise NotImplementedError - @cached_method def trace_to_real_numerical(self, prec=53): """ @@ -4235,7 +4331,7 @@ def trace_to_real_numerical(self, prec=53): R = 2*P else: R = P + E.point([x.conjugate() for x in P],check=False) - F = self.curve().change_ring(rings.RealField(prec)) + F = self.curve().change_ring(RealField(prec)) return F.point([x.real() for x in R], check=False) @cached_method @@ -4245,7 +4341,7 @@ def _trace_exact_conductor_1(self, prec=53): the case of conductor 1, computed using prec bits of precision, then approximated using some algorithm (e.g., continued fractions). If the precision is not enough to - determine a point on the curve, then a RuntimeError is raised. + determine a point on the curve, then a :class:`RuntimeError` is raised. Even if the precision determines a point, there is no guarantee that it is correct. @@ -4273,9 +4369,9 @@ def _recognize_point_over_QQ(self, P, n): INPUT: - - `P` -- numerical approximation for a point on `E` + - `P` -- numerical approximation for a point on `E` - - `n` -- upper bound on divisibility index of `P` in group `E(\QQ)` + - `n` -- upper bound on divisibility index of `P` in group `E(\QQ)` EXAMPLES:: @@ -4387,23 +4483,22 @@ def mod(self, p, prec=53): ## """ ## raise NotImplementedError - def kolyvagin_cohomology_class(self, n=None): """ INPUT: - - `n` -- positive integer that divides the gcd of `a_p` - and `p+1` for all `p` dividing the conductor. If `n` is - ``None``, choose the largest valid `n`. + - `n` -- positive integer that divides the gcd of `a_p` + and `p+1` for all `p` dividing the conductor. If `n` is + ``None``, choose the largest valid `n`. EXAMPLES:: - sage: y = EllipticCurve('389a').heegner_point(-7,5) + sage: y = EllipticCurve('389a').heegner_point(-7, 5) sage: P = y.kolyvagin_point() sage: P.kolyvagin_cohomology_class(3) Kolyvagin cohomology class c(5) in H^1(K,E[3]) - sage: y = EllipticCurve('37a').heegner_point(-7,5).kolyvagin_point() + sage: y = EllipticCurve('37a').heegner_point(-7, 5).kolyvagin_point() sage: y.kolyvagin_cohomology_class() Kolyvagin cohomology class c(5) in H^1(K,E[2]) """ @@ -4432,7 +4527,7 @@ def __init__(self, kolyvagin_point, n): EXAMPLES:: - sage: y = EllipticCurve('389a').heegner_point(-7,5) + sage: y = EllipticCurve('389a').heegner_point(-7, 5) sage: y.kolyvagin_cohomology_class(3) Kolyvagin cohomology class c(5) in H^1(K,E[3]) """ @@ -4442,7 +4537,7 @@ def __init__(self, kolyvagin_point, n): n = gcd([(p+1).gcd(E.ap(p)) for p in c.prime_divisors()]) if not kolyvagin_point.satisfies_kolyvagin_hypothesis(n): - raise ValueError("Kolyvagin point does not satisfy Kolyvagin hypothesis for %s"%n) + raise ValueError("Kolyvagin point does not satisfy Kolyvagin hypothesis for %s" % n) self.__kolyvagin_point = kolyvagin_point self.__n = n @@ -4501,7 +4596,7 @@ def conductor(self): EXAMPLES:: - sage: y = EllipticCurve('37a').heegner_point(-7,5) + sage: y = EllipticCurve('37a').heegner_point(-7, 5) sage: t = y.kolyvagin_cohomology_class() sage: t.conductor() 5 @@ -4515,10 +4610,11 @@ class is associated. EXAMPLES:: - sage: y = EllipticCurve('37a').heegner_point(-7,5) + sage: y = EllipticCurve('37a').heegner_point(-7, 5) sage: t = y.kolyvagin_cohomology_class() sage: t.kolyvagin_point() - Kolyvagin point of discriminant -7 and conductor 5 on elliptic curve of conductor 37 + Kolyvagin point of discriminant -7 and conductor 5 + on elliptic curve of conductor 37 """ return self.__kolyvagin_point @@ -4529,10 +4625,11 @@ def heegner_point(self): EXAMPLES:: - sage: y = EllipticCurve('37a').heegner_point(-7,5) + sage: y = EllipticCurve('37a').heegner_point(-7, 5) sage: t = y.kolyvagin_cohomology_class() sage: t.heegner_point() - Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 37 + Heegner point of discriminant -7 and conductor 5 + on elliptic curve of conductor 37 """ return self.__kolyvagin_point.heegner_point() @@ -4547,12 +4644,12 @@ def _repr_(self): EXAMPLES:: - sage: y = EllipticCurve('37a').heegner_point(-7,5) + sage: y = EllipticCurve('37a').heegner_point(-7, 5) sage: t = y.kolyvagin_cohomology_class() sage: t._repr_() 'Kolyvagin cohomology class c(5) in H^1(K,E[2])' """ - return "Kolyvagin cohomology class c(%s) in H^1(K,E[%s])"%( + return "Kolyvagin cohomology class c(%s) in H^1(K,E[%s])" % ( self.conductor(), self.n()) @@ -4584,9 +4681,9 @@ def __init__(self, level, ell): r""" INPUT: - - ``level`` -- the level (a positive integer) + - ``level`` -- the level (a positive integer) - - `\ell` -- the characteristic, a prime coprime to the level + - `\ell` -- the characteristic, a prime coprime to the level EXAMPLES:: @@ -4640,7 +4737,7 @@ def _repr_(self): sage: heegner_points(11).reduce_mod(13)._repr_() 'Heegner points on X_0(11) over F_13' """ - return "Heegner points on X_0(%s) over F_%s"%( + return "Heegner points on X_0(%s) over F_%s" % ( self.__level, self.__ell) def level(self): @@ -4674,13 +4771,11 @@ def satisfies_heegner_hypothesis(self, D, c=ZZ(1)): INPUT: - - `D` -- negative integer - - - `c` -- positive integer (default: 1) + - `D` -- negative integer - OUTPUT: + - `c` -- positive integer (default: 1) - - bool + OUTPUT: A boolean. EXAMPLES:: @@ -4713,11 +4808,9 @@ def heegner_discriminants(self, n=5): INPUT: - - `n` -- positive integer (default: 5) - - OUTPUT: + - `n` -- positive integer (default: 5) - - list + OUTPUT: A list. EXAMPLES:: @@ -4744,14 +4837,11 @@ def heegner_conductors(self, D, n=5): INPUT: - - `D` -- negative integer; a fundamental Heegner - discriminant - - - `n` -- positive integer (default: 5) + - `D` -- negative integer; a fundamental Heegner discriminant - OUTPUT: + - `n` -- positive integer (default: 5) - - list + OUTPUT: A list. EXAMPLES:: @@ -4769,7 +4859,6 @@ def heegner_conductors(self, D, n=5): c += 1 return v - def optimal_embeddings(self, D, c, R): """ INPUT: @@ -4794,7 +4883,7 @@ def optimal_embeddings(self, D, c, R): Embedding sending 2*sqrt(-7) to -2*i + 2*j + 2*k] """ Q, G = R.ternary_quadratic_form(include_basis=True) - n = -D*c*c + n = -D*c*c reps = Q.representation_vector_list(n+1)[-1] # The representatives give elements in terms of the @@ -4855,8 +4944,10 @@ def left_orders(self): EXAMPLES:: sage: heegner_points(11).reduce_mod(3).left_orders() - [Order of Quaternion Algebra (-1, -3) with base ring Rational Field with basis (1/2 + 1/2*j + 7*k, 1/2*i + 13/2*k, j + 3*k, 11*k), - Order of Quaternion Algebra (-1, -3) with base ring Rational Field with basis (1/2 + 1/2*j + 7*k, 1/4*i + 1/2*j + 63/4*k, j + 14*k, 22*k)] + [Order of Quaternion Algebra (-1, -3) with base ring Rational Field + with basis (1/2 + 1/2*j + 7*k, 1/2*i + 13/2*k, j + 3*k, 11*k), + Order of Quaternion Algebra (-1, -3) with base ring Rational Field + with basis (1/2 + 1/2*j + 7*k, 1/4*i + 1/2*j + 63/4*k, j + 14*k, 22*k)] """ return [I.left_order() for I in self.right_ideals()] @@ -4874,13 +4965,11 @@ def heegner_divisor(self, D, c=ZZ(1)): INPUT: - - `D` -- discriminant (negative integer) + - `D` -- discriminant (negative integer) - - `c` -- conductor (positive integer) - - OUTPUT: + - `c` -- conductor (positive integer) - - Brandt module element + OUTPUT: A Brandt module element. EXAMPLES:: @@ -4921,7 +5010,7 @@ def heegner_divisor(self, D, c=ZZ(1)): if a > 0: reps = Q.representation_vector_list(n+1)[-1] k = len([r for r in reps if gcd(r) == 1]) - assert k%2 == 0 + assert k % 2 == 0 v[i] += k // 2 return B(v) @@ -4940,11 +5029,9 @@ def modp_splitting_data(self, p): INPUT: - - `p` -- unramified odd prime - - OUTPUT: + - `p` -- unramified odd prime - - 2-tuple of matrices over finite field + OUTPUT: A 2-tuple of matrices over finite field. EXAMPLES:: @@ -4993,12 +5080,12 @@ def modp_splitting_data(self, p): """ p = ZZ(p) if not p.is_prime(): - raise ValueError("p (=%s) must be prime"%p) + raise ValueError("p (=%s) must be prime" % p) if p == 2: raise ValueError("p must be odd") Q = self.quaternion_algebra() if Q.discriminant() % p == 0: - raise ValueError("p (=%s) must be an unramified prime"%p) + raise ValueError("p (=%s) must be an unramified prime" % p) i, j, k = Q.gens() F = GF(p) i2 = F(i*i) @@ -5027,7 +5114,7 @@ def modp_splitting_map(self, p): INPUT: - - `p` -- prime number + - `p` -- prime number EXAMPLES:: @@ -5035,8 +5122,8 @@ def modp_splitting_map(self, p): sage: f = H.modp_splitting_map(13) sage: B = H.quaternion_algebra(); B Quaternion Algebra (-1, -7) with base ring Rational Field - sage: i,j,k = H.quaternion_algebra().gens() - sage: a = 2+i-j+3*k; b = 7+2*i-4*j+k + sage: i, j, k = H.quaternion_algebra().gens() + sage: a = 2 + i - j + 3*k; b = 7 + 2*i - 4*j + k sage: f(a*b) [12 3] [10 5] @@ -5060,11 +5147,10 @@ def cyclic_subideal_p1(self, I, c): INPUT: - - `I` -- right ideal of Eichler order or in quaternion algebra + - `I` -- right ideal of Eichler order or in quaternion algebra - - `c` -- square free integer (currently must be odd prime - and coprime to level, discriminant, characteristic, - etc. + - `c` -- square free integer (currently must be odd prime + and coprime to level, discriminant, characteristic, etc. OUTPUT: @@ -5074,7 +5160,7 @@ def cyclic_subideal_p1(self, I, c): sage: H = heegner_points(11).reduce_mod(7) sage: I = H.brandt_module().right_ideals()[0] - sage: sorted(H.cyclic_subideal_p1(I,3).items()) + sage: sorted(H.cyclic_subideal_p1(I, 3).items()) [((0, 1), Fractional ideal (2 + 2*j + 32*k, 2*i + 8*j + 82*k, 12*j + 60*k, 132*k)), ((1, 0), @@ -5083,7 +5169,7 @@ def cyclic_subideal_p1(self, I, c): Fractional ideal (2 + 2*j + 76*k, 2*i + 4*j + 106*k, 12*j + 60*k, 132*k)), ((1, 2), Fractional ideal (2 + 10*j + 116*k, 2*i + 8*j + 38*k, 12*j + 60*k, 132*k))] - sage: len(H.cyclic_subideal_p1(I,17)) + sage: len(H.cyclic_subideal_p1(I, 17)) 18 """ c = ZZ(c) @@ -5103,7 +5189,7 @@ def cyclic_subideal_p1(self, I, c): V = V.intersection(phi(B[i]).kernel()) b = V.basis() assert len(b) == 1, "common kernel must have dimension 1" - uv = P1.normalize(ZZ(b[0][0])%c, ZZ(b[0][1])%c) + uv = P1.normalize(ZZ(b[0][0]) % c, ZZ(b[0][1]) % c) ans[uv] = J assert len(ans) == c+1 return ans @@ -5117,16 +5203,17 @@ def galois_group_over_hilbert_class_field(self, D, c): INPUT: - - `D` -- fundamental discriminant + - `D` -- fundamental discriminant - - `c` -- conductor (square-free integer) + - `c` -- conductor (square-free integer) EXAMPLES:: sage: N = 37; D = -7; ell = 17; c = 41; p = 3 sage: H = heegner_points(N).reduce_mod(ell) sage: H.galois_group_over_hilbert_class_field(D, c) - Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 41 over Hilbert class field of QQ[sqrt(-7)] + Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 41 + over Hilbert class field of QQ[sqrt(-7)] """ Kc = heegner_points(self.level(), D, c).ring_class_field() K1 = heegner_points(self.level(), D, 1).ring_class_field() @@ -5140,16 +5227,18 @@ def galois_group_over_quadratic_field(self, D, c): INPUT: - - `D` -- fundamental discriminant + - `D` -- fundamental discriminant - - `c` -- conductor (square-free integer) + - `c` -- conductor (square-free integer) EXAMPLES:: sage: N = 37; D = -7; ell = 17; c = 41; p = 3 sage: H = heegner_points(N).reduce_mod(ell) sage: H.galois_group_over_quadratic_field(D, c) - Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 41 over Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Galois group of Ring class field extension of QQ[sqrt(-7)] of conductor 41 + over Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I """ Kc = heegner_points(self.level(), D, c).ring_class_field() return Kc.galois_group(Kc.quadratic_field()) @@ -5162,17 +5251,16 @@ def quadratic_field(self, D): INPUT: - - `D` -- fundamental discriminant - - OUTPUT: + - `D` -- fundamental discriminant - - a quadratic number field + OUTPUT: A quadratic number field. EXAMPLES:: sage: H = heegner_points(389).reduce_mod(5) sage: H.quadratic_field(-7) - Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 with sqrt_minus_7 = 2.645751311064591?*I + Number Field in sqrt_minus_7 with defining polynomial x^2 + 7 + with sqrt_minus_7 = 2.645751311064591?*I """ Kc = heegner_points(self.level(), D, 1).ring_class_field() return Kc.quadratic_field() @@ -5186,21 +5274,18 @@ def kolyvagin_cyclic_subideals(self, I, p, alpha_quaternion): INPUT: - - `I` -- right ideal of the quaternion algebra + - `I` -- right ideal of the quaternion algebra - - `p` -- prime number + - `p` -- prime number - - ``alpha_quaternion`` -- image in the quaternion algebra - of generator `\alpha` for - `(\mathcal{O}_K / c\mathcal{O}_K)^* / (\ZZ/c\ZZ)^*`. + - ``alpha_quaternion`` -- image in the quaternion algebra + of generator `\alpha` for `(\mathcal{O}_K / c\mathcal{O}_K)^* / (\ZZ/c\ZZ)^*`. - OUTPUT: - - - list of 2-tuples + OUTPUT: A list of 2-tuples. EXAMPLES:: - sage: N = 37; D = -7; ell = 17; c=5 + sage: N = 37; D = -7; ell = 17; c = 5 sage: H = heegner_points(N).reduce_mod(ell) sage: I = H.brandt_module().right_ideals()[49] sage: f = H.optimal_embeddings(D, 1, I.left_order())[1] @@ -5208,12 +5293,24 @@ def kolyvagin_cyclic_subideals(self, I, p, alpha_quaternion): sage: alpha_quaternion = f(g[0]); alpha_quaternion 1 - 77/192*i - 5/128*j - 137/384*k sage: H.kolyvagin_cyclic_subideals(I, 5, alpha_quaternion) - [(Fractional ideal (2 + 2/3*i + 364*j + 231928/3*k, 4/3*i + 946*j + 69338/3*k, 1280*j + 49920*k, 94720*k), 0), - (Fractional ideal (2 + 2/3*i + 108*j + 31480/3*k, 4/3*i + 434*j + 123098/3*k, 1280*j + 49920*k, 94720*k), 1), - (Fractional ideal (2 + 2/3*i + 876*j + 7672/3*k, 4/3*i + 434*j + 236762/3*k, 1280*j + 49920*k, 94720*k), 2), - (Fractional ideal (2 + 2/3*i + 364*j + 61432/3*k, 4/3*i + 178*j + 206810/3*k, 1280*j + 49920*k, 94720*k), 3), - (Fractional ideal (2 + 2/3*i + 876*j + 178168/3*k, 4/3*i + 1202*j + 99290/3*k, 1280*j + 49920*k, 94720*k), 4), - (Fractional ideal (2 + 2/3*i + 1132*j + 208120/3*k, 4/3*i + 946*j + 183002/3*k, 1280*j + 49920*k, 94720*k), 5)] + [(Fractional ideal (2 + 2/3*i + 364*j + 231928/3*k, + 4/3*i + 946*j + 69338/3*k, + 1280*j + 49920*k, 94720*k), 0), + (Fractional ideal (2 + 2/3*i + 108*j + 31480/3*k, + 4/3*i + 434*j + 123098/3*k, + 1280*j + 49920*k, 94720*k), 1), + (Fractional ideal (2 + 2/3*i + 876*j + 7672/3*k, + 4/3*i + 434*j + 236762/3*k, + 1280*j + 49920*k, 94720*k), 2), + (Fractional ideal (2 + 2/3*i + 364*j + 61432/3*k, + 4/3*i + 178*j + 206810/3*k, + 1280*j + 49920*k, 94720*k), 3), + (Fractional ideal (2 + 2/3*i + 876*j + 178168/3*k, + 4/3*i + 1202*j + 99290/3*k, + 1280*j + 49920*k, 94720*k), 4), + (Fractional ideal (2 + 2/3*i + 1132*j + 208120/3*k, + 4/3*i + 946*j + 183002/3*k, + 1280*j + 49920*k, 94720*k), 5)] """ X = I.cyclic_right_subideals(p, alpha_quaternion) return [(J, i) for i, J in enumerate(X)] @@ -5230,20 +5327,20 @@ def kolyvagin_generator(self, K, p): INPUT: - - `K` -- quadratic imaginary field + - `K` -- quadratic imaginary field - - `p` -- inert prime + - `p` -- inert prime EXAMPLES:: - sage: N = 37; D = -7; ell = 17; p=5 + sage: N = 37; D = -7; ell = 17; p = 5 sage: H = heegner_points(N).reduce_mod(ell) sage: I = H.brandt_module().right_ideals()[49] sage: f = H.optimal_embeddings(D, 1, I.left_order())[0] sage: H.kolyvagin_generator(f.domain().number_field(), 5) a + 1 - This function requires that p be prime, but kolyvagin_generators works in general:: + This function requires that `p` be prime, but ``kolyvagin_generators`` works in general:: sage: H.kolyvagin_generator(f.domain().number_field(), 5*17) Traceback (most recent call last): @@ -5281,13 +5378,13 @@ def kolyvagin_generators(self, K, c): INPUT: - - `K` -- quadratic imaginary field + - `K` -- quadratic imaginary field - - `c` -- square free product of inert prime + - `c` -- square free product of inert prime EXAMPLES:: - sage: N = 37; D = -7; ell = 17; p=5 + sage: N = 37; D = -7; ell = 17; p = 5 sage: H = heegner_points(N).reduce_mod(ell) sage: I = H.brandt_module().right_ideals()[49] sage: f = H.optimal_embeddings(D, 1, I.left_order())[0] @@ -5322,15 +5419,15 @@ def kolyvagin_sigma_operator(self, D, c, r, bound=None): INPUT: - - `D` -- fundamental discriminant + - `D` -- fundamental discriminant - - `c` -- conductor (square-free integer, need not be prime) + - `c` -- conductor (square-free integer, need not be prime) - - `r` -- nonnegative integer + - `r` -- nonnegative integer - - ``bound`` -- (default: ``None``), if given, controls - precision of computation of theta series, which could - impact performance, but does not impact correctness + - ``bound`` -- (default: ``None``), if given, controls + precision of computation of theta series, which could + impact performance, but does not impact correctness EXAMPLES: @@ -5343,9 +5440,11 @@ def kolyvagin_sigma_operator(self, D, c, r, bound=None): sage: V = H.modp_dual_elliptic_curve_factor(E, q, 5) # long time (4s on sage.math, 2012) sage: k118 = H.kolyvagin_sigma_operator(D, c, 118) sage: k104 = H.kolyvagin_sigma_operator(D, c, 104) - sage: [b.dot_product(k104.element().change_ring(GF(3))) for b in V.basis()] # long time + sage: [b.dot_product(k104.element().change_ring(GF(3))) # long time + ....: for b in V.basis()] [0, 0] - sage: [b.dot_product(k118.element().change_ring(GF(3))) for b in V.basis()] # long time + sage: [b.dot_product(k118.element().change_ring(GF(3))) # long time + ....: for b in V.basis()] [0, 0] Next we try again with `c=41` and this does work, in that we @@ -5354,9 +5453,11 @@ def kolyvagin_sigma_operator(self, D, c, r, bound=None): sage: c = 41 sage: k118 = H.kolyvagin_sigma_operator(D, c, 118) sage: k104 = H.kolyvagin_sigma_operator(D, c, 104) - sage: [b.dot_product(k118.element().change_ring(GF(3))) for b in V.basis()] # long time + sage: [b.dot_product(k118.element().change_ring(GF(3))) # long time + ....: for b in V.basis()] [2, 0] - sage: [b.dot_product(k104.element().change_ring(GF(3))) for b in V.basis()] # long time + sage: [b.dot_product(k104.element().change_ring(GF(3))) # long time + ....: for b in V.basis()] [1, 0] By the way, the above is the first ever provable verification @@ -5413,11 +5514,10 @@ def kolyvagin_sigma_operator(self, D, c, r, bound=None): X = I.cyclic_right_subideals(p, alpha_quaternions[i]) J_lists.append(dict(enumerate(X))) - ans = [0]*B.dimension() - from sage.misc.mrange import cartesian_product_iterator - for v in cartesian_product_iterator([range(1,p+1) for p,_ in F]): + ans = [0] * B.dimension() + for v in product(*[range(1, p + 1) for p, _ in F]): J = J_lists[0][v[0]] - for i in range(1,len(J_lists)): + for i in range(1, len(J_lists)): J = J.intersection(J_lists[i][v[i]]) J_theta = tuple(J.theta_series_vector(bound)) d = theta_dict[J_theta] @@ -5444,11 +5544,11 @@ def modp_dual_elliptic_curve_factor(self, E, p, bound=10): INPUT: - - `E` -- elliptic curve of conductor equal to the level of self + - `E` -- elliptic curve of conductor equal to the level of ``self`` - - `p` -- prime number + - `p` -- prime number - - `bound` -- positive integer (default: 10) + - ``bound`` -- positive integer (default: 10) EXAMPLES:: @@ -5456,14 +5556,13 @@ def modp_dual_elliptic_curve_factor(self, E, p, bound=10): sage: H = heegner_points(N).reduce_mod(ell) sage: V = H.modp_dual_elliptic_curve_factor(EllipticCurve('37a'), q, 5); V Vector space of degree 52 and dimension 2 over Ring of integers modulo 3 - Basis matrix: - 2 x 52 dense matrix over Ring of integers modulo 3 + Basis matrix: 2 x 52 dense matrix over Ring of integers modulo 3 """ if E.conductor() != self.level(): raise ValueError("conductor of E must equal level of self") p = ZZ(p) if not p.is_prime(): - raise ValueError("p (=%s) must be prime"%p) + raise ValueError("p (=%s) must be prime" % p) bad = self.__level * self.__ell V = None @@ -5471,7 +5570,7 @@ def modp_dual_elliptic_curve_factor(self, E, p, bound=10): B = self.brandt_module() F = GF(p) while q <= bound and (V is None or V.dimension() > 2): - verbose("q = %s"%q) + verbose("q = %s" % q) if bad % q != 0: T = B._compute_hecke_matrix_directly(q).change_ring(F).transpose() if V is None: @@ -5492,13 +5591,11 @@ def rational_kolyvagin_divisor(self, D, c): INPUT: - - `D` -- discriminant (negative integer) - - - `c` -- conductor (positive integer) + - `D` -- discriminant (negative integer) - OUTPUT: + - `c` -- conductor (positive integer) - - Brandt module element (or tuple of them) + OUTPUT: Brandt module element (or tuple of them). EXAMPLES:: @@ -5537,16 +5634,16 @@ def kolyvagin_point_on_curve(self, D, c, E, p, bound=10): INPUT: - - `D` -- fundamental negative discriminant + - `D` -- fundamental negative discriminant - - `c` -- conductor + - `c` -- conductor - - `E` -- elliptic curve of conductor the level of self + - `E` -- elliptic curve of conductor the level of self - - `p` -- odd prime number such that we consider image in - `E(\GF{\ell^2}) / p E(\GF{\ell^2})` + - `p` -- odd prime number such that we consider image in + `E(\GF{\ell^2}) / p E(\GF{\ell^2})` - - ``bound`` -- integer (default: 10) + - ``bound`` -- integer (default: 10) EXAMPLES:: @@ -5568,51 +5665,51 @@ def kolyvagin_reduction_data(E, q, first_only=True): INPUT: - - `E` -- elliptic curve over `\QQ` of rank 1 or 2 + - `E` -- elliptic curve over `\QQ` of rank 1 or 2 - - `q` -- an odd prime that does not divide the order of the - rational torsion subgroup of `E` + - `q` -- an odd prime that does not divide the order of the + rational torsion subgroup of `E` - - ``first_only`` -- bool (default: ``True``) whether two only return - the first prime that one can work modulo to get data about - the Euler system + - ``first_only`` -- bool (default: ``True``) whether two only return + the first prime that one can work modulo to get data about + the Euler system OUTPUT in the rank 1 case or when the default flag ``first_only=True``: - - `\ell` -- first good odd prime satisfying the Kolyvagin - condition that `q` divides \gcd(a_{\ell},\ell+1)` and the - reduction map is surjective to `E(\GF{\ell}) / q - E(\GF{\ell})` + - `\ell` -- first good odd prime satisfying the Kolyvagin + condition that `q` divides \gcd(a_{\ell},\ell+1)` and the + reduction map is surjective to `E(\GF{\ell}) / q + E(\GF{\ell})` - - `D` -- discriminant of the first quadratic imaginary field - `K` that satisfies the Heegner hypothesis for `E` such that - both `\ell` is inert in `K`, and the twist `E^D` has analytic - rank `\leq 1` + - `D` -- discriminant of the first quadratic imaginary field + `K` that satisfies the Heegner hypothesis for `E` such that + both `\ell` is inert in `K`, and the twist `E^D` has analytic + rank `\leq 1` - - `h_D` -- the class number of `K` + - `h_D` -- the class number of `K` - - the dimension of the Brandt module `B(\ell,N)`, where `N` is - the conductor of `E` + - the dimension of the Brandt module `B(\ell,N)`, where `N` is + the conductor of `E` OUTPUT in the rank 2 case: - - `\ell_1` -- first prime (as above in the rank 1 case) where - reduction map is surjective + - `\ell_1` -- first prime (as above in the rank 1 case) where + reduction map is surjective - - `\ell_2` -- second prime (as above) where reduction map is - surjective + - `\ell_2` -- second prime (as above) where reduction map is + surjective - - `D` -- discriminant of the first quadratic imaginary field - `K` that satisfies the Heegner hypothesis for `E` such that - both `\ell_1` and `\ell_2` are simultaneously inert in `K`, - and the twist `E^D` has analytic rank `\leq 1` + - `D` -- discriminant of the first quadratic imaginary field + `K` that satisfies the Heegner hypothesis for `E` such that + both `\ell_1` and `\ell_2` are simultaneously inert in `K`, + and the twist `E^D` has analytic rank `\leq 1` - - `h_D` -- the class number of `K` + - `h_D` -- the class number of `K` - - the dimension of the Brandt module `B(\ell_1,N)`, where `N` is - the conductor of `E` + - the dimension of the Brandt module `B(\ell_1,N)`, where `N` is + the conductor of `E` - - the dimension of the Brandt module `B(\ell_2,N)` + - the dimension of the Brandt module `B(\ell_2,N)` EXAMPLES: @@ -5622,15 +5719,16 @@ def kolyvagin_reduction_data(E, q, first_only=True): A rank 1 example:: - sage: kolyvagin_reduction_data(EllipticCurve('37a1'),3) + sage: kolyvagin_reduction_data(EllipticCurve('37a1'), 3) (17, -7, 1, 52) A rank 3 example:: - sage: kolyvagin_reduction_data(EllipticCurve('5077a1'),3) + sage: kolyvagin_reduction_data(EllipticCurve('5077a1'), 3) (11, -47, 5, 4234) sage: H = heegner_points(5077, -47) - sage: [c for c in H.kolyvagin_conductors(2,10,EllipticCurve('5077a1'),3) if c%11] + sage: [c for c in H.kolyvagin_conductors(2, 10, EllipticCurve('5077a1'), 3) + ....: if c % 11] [667, 943, 1189, 2461] sage: factor(667) 23 * 29 @@ -5649,19 +5747,19 @@ def kolyvagin_reduction_data(E, q, first_only=True): The first rank 2 example:: - sage: kolyvagin_reduction_data(EllipticCurve('389a'),3) + sage: kolyvagin_reduction_data(EllipticCurve('389a'), 3) (5, -7, 1, 130) - sage: kolyvagin_reduction_data(EllipticCurve('389a'),3, first_only=False) + sage: kolyvagin_reduction_data(EllipticCurve('389a'), 3, first_only=False) (5, 17, -7, 1, 130, 520) A large `q = 7`:: - sage: kolyvagin_reduction_data(EllipticCurve('1143c1'),7, first_only=False) + sage: kolyvagin_reduction_data(EllipticCurve('1143c1'), 7, first_only=False) (13, 83, -59, 3, 1536, 10496) Additive reduction:: - sage: kolyvagin_reduction_data(EllipticCurve('2350g1'),5, first_only=False) + sage: kolyvagin_reduction_data(EllipticCurve('2350g1'), 5, first_only=False) (19, 239, -311, 19, 6480, 85680) """ from .ell_generic import is_EllipticCurve @@ -5699,9 +5797,9 @@ def red(P, ell): def best_heegner_D(ell_1, ell_2): # return the first Heegner D satisfy all hypothesis such that # both ell_1 and ell_2 are inert - D = -5 + D = ZZ(-5) while True: - if number_field.is_fundamental_discriminant(D) and \ + if D.is_fundamental_discriminant() and \ D % ell_1 and D % ell_2 and \ E.satisfies_heegner_hypothesis(D) and \ is_inert(D, ell_1) and is_inert(D, ell_2) and \ @@ -5786,14 +5884,14 @@ def __init__(self, D, c, R, beta): r""" INPUT: - - `D` -- negative fundamental discriminant + - `D` -- negative fundamental discriminant - - `c` -- positive integer coprime to `D` + - `c` -- positive integer coprime to `D` - - `R` -- Eichler order in a rational quaternion algebra + - `R` -- Eichler order in a rational quaternion algebra - - `\beta` -- element of `R` such that the homomorphism - sends `c\sqrt{D}` to `\beta` + - `\beta` -- element of `R` such that the homomorphism + sends `c\sqrt{D}` to `\beta` EXAMPLES:: @@ -5903,7 +6001,8 @@ def domain(self): sage: H = heegner_points(11).reduce_mod(3); R = H.left_orders()[0] sage: H.optimal_embeddings(-7, 2, R)[0].domain() - Order in Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I + Order in Number Field in a with defining polynomial x^2 + 7 + with a = 2.645751311064591?*I """ R, a = quadratic_order(self.__D, self.__c) @@ -5967,7 +6066,8 @@ def codomain(self): sage: H = heegner_points(11).reduce_mod(3); R = H.left_orders()[0] sage: H.optimal_embeddings(-7, 2, R)[0].codomain() - Order of Quaternion Algebra (-1, -3) with base ring Rational Field with basis (1/2 + 1/2*j + 7*k, 1/2*i + 13/2*k, j + 3*k, 11*k) + Order of Quaternion Algebra (-1, -3) with base ring Rational Field + with basis (1/2 + 1/2*j + 7*k, 1/2*i + 13/2*k, j + 3*k, 11*k) """ return self.__R @@ -5982,8 +6082,8 @@ def _repr_(self): sage: f = H.optimal_embeddings(-7, 2, R)[1]; f._repr_() 'Embedding sending 2*sqrt(-7) to -5*i + k' """ - a = '%ssqrt(%s)'%('%s*'%self.__c if self.__c > 1 else '', self.__D) - return "Embedding sending %s to %s"%(a, self.__beta) + a = '%ssqrt(%s)' % ('%s*' % self.__c if self.__c > 1 else '', self.__D) + return "Embedding sending %s to %s" % (a, self.__beta) def conjugate(self): """ @@ -6015,27 +6115,29 @@ def quadratic_order(D, c, names='a'): INPUT: - - `D` -- fundamental discriminant + - `D` -- fundamental discriminant - - `c` -- conductor + - `c` -- conductor - - ``names`` -- string (default: 'a') + - ``names`` -- string (default: 'a') OUTPUT: - - order `R` of conductor `c` in an imaginary quadratic field + - order `R` of conductor `c` in an imaginary quadratic field - - the element `c\sqrt{D}` as an element of `R` + - the element `c\sqrt{D}` as an element of `R` The generator for the field is named 'a' by default. EXAMPLES:: sage: sage.schemes.elliptic_curves.heegner.quadratic_order(-7,3) - (Order in Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I, + (Order in Number Field in a with defining polynomial x^2 + 7 + with a = 2.645751311064591?*I, 3*a) sage: sage.schemes.elliptic_curves.heegner.quadratic_order(-7,3,'alpha') - (Order in Number Field in alpha with defining polynomial x^2 + 7 with alpha = 2.645751311064591?*I, + (Order in Number Field in alpha with defining polynomial x^2 + 7 + with alpha = 2.645751311064591?*I, 3*alpha) """ K = QuadraticField(D, names) @@ -6051,7 +6153,7 @@ def class_number(D): INPUT: - - `D` -- integer + - `D` -- integer EXAMPLES:: @@ -6062,7 +6164,7 @@ def class_number(D): sage: sage.schemes.elliptic_curves.heegner.class_number(-163) 1 - A ValueError is raised when `D` is not a fundamental + A :class:`ValueError` is raised when `D` is not a fundamental discriminant:: sage: sage.schemes.elliptic_curves.heegner.class_number(-5) @@ -6070,10 +6172,9 @@ def class_number(D): ... ValueError: D (=-5) must be a fundamental discriminant """ - if not number_field.is_fundamental_discriminant(D): + if not D.is_fundamental_discriminant(): raise ValueError("D (=%s) must be a fundamental discriminant" % D) - return QuadraticField(D, 'a').class_number() - + return D.class_number() def is_inert(D, p): r""" @@ -6081,9 +6182,9 @@ def is_inert(D, p): INPUT: - - `D` -- fundamental discriminant + - `D` -- fundamental discriminant - - `p` -- prime integer + - `p` -- prime integer EXAMPLES:: @@ -6104,9 +6205,9 @@ def is_split(D, p): INPUT: - - `D` -- fundamental discriminant + - `D` -- fundamental discriminant - - `p` -- prime integer + - `p` -- prime integer EXAMPLES:: @@ -6127,9 +6228,9 @@ def is_ramified(D, p): INPUT: - - `D` -- fundamental discriminant + - `D` -- fundamental discriminant - - `p` -- prime integer + - `p` -- prime integer EXAMPLES:: @@ -6149,16 +6250,17 @@ def nearby_rational_poly(f, **kwds): INPUT: - - `f` -- polynomial with real floating point entries + - `f` -- polynomial with real floating point entries - - ``**kwds`` -- passed on to ``nearby_rational`` method + - ``**kwds`` -- passed on to ``nearby_rational`` method EXAMPLES:: + sage: from sage.schemes.elliptic_curves.heegner import nearby_rational_poly sage: R.<x> = RR[] - sage: sage.schemes.elliptic_curves.heegner.nearby_rational_poly(2.1*x^2 + 3.5*x - 1.2, max_error=10e-16) + sage: nearby_rational_poly(2.1*x^2 + 3.5*x - 1.2, max_error=10e-16) 21/10*X^2 + 7/2*X - 6/5 - sage: sage.schemes.elliptic_curves.heegner.nearby_rational_poly(2.1*x^2 + 3.5*x - 1.2, max_error=10e-17) + sage: nearby_rational_poly(2.1*x^2 + 3.5*x - 1.2, max_error=10e-17) 4728779608739021/2251799813685248*X^2 + 7/2*X - 5404319552844595/4503599627370496 sage: RR(4728779608739021/2251799813685248 - 21/10) 8.88178419700125e-17 @@ -6173,14 +6275,15 @@ def simplest_rational_poly(f, prec): INPUT: - - `f` -- polynomial with real floating point entries + - `f` -- polynomial with real floating point entries - - ``prec`` -- positive integer + - ``prec`` -- positive integer EXAMPLES:: + sage: from sage.schemes.elliptic_curves.heegner import simplest_rational_poly sage: R.<x> = RR[] - sage: sage.schemes.elliptic_curves.heegner.simplest_rational_poly(2.1*x^2 + 3.5*x - 1.2, 53) + sage: simplest_rational_poly(2.1*x^2 + 3.5*x - 1.2, 53) 21/10*X^2 + 7/2*X - 6/5 """ R = QQ['X'] @@ -6199,9 +6302,9 @@ def satisfies_weak_heegner_hypothesis(N, D): INPUT: - - `N` -- positive integer + - `N` -- positive integer - - `D` -- negative integer + - `D` -- negative integer EXAMPLES:: @@ -6221,7 +6324,7 @@ def satisfies_weak_heegner_hypothesis(N, D): sage: EllipticCurve('37a').heegner_discriminants_list(10) [-7, -11, -40, -47, -67, -71, -83, -84, -95, -104] """ - if not number_field.is_fundamental_discriminant(D): + if not D.is_fundamental_discriminant(): return False if D >= 0: return False @@ -6242,11 +6345,9 @@ def make_monic(f): INPUT: - - f -- polynomial over the rational numbers - - OUTPUT: + - `f` -- polynomial over the rational numbers - a monic integral polynomial and an integer + OUTPUT: A monic integral polynomial and an integer. EXAMPLES:: @@ -6318,9 +6419,7 @@ def ell_heegner_point(self, D, c=ZZ(1), f=None, check=True): - ``check`` -- bool (default: ``True``) - OUTPUT: - - The Heegner point `y_c`. + OUTPUT: The Heegner point `y_c`. EXAMPLES:: @@ -6329,8 +6428,8 @@ def ell_heegner_point(self, D, c=ZZ(1), f=None, check=True): [-7, -11, -40, -47, -67, -71, -83, -84, -95, -104] sage: P = E.heegner_point(-7); P # indirect doctest Heegner point of discriminant -7 on elliptic curve of conductor 37 - sage: P.point_exact() - (0 : 0 : 1) + sage: z = P.point_exact(); z == E(0, 0, 1) or -z == E(0, 0, 1) + True sage: P.curve() Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field sage: P = E.heegner_point(-40).point_exact(); P @@ -6358,7 +6457,8 @@ def ell_heegner_point(self, D, c=ZZ(1), f=None, check=True): We can specify the quadratic form:: sage: P = EllipticCurve('389a').heegner_point(-7, 5, (778,925,275)); P - Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 389 + Heegner point of discriminant -7 and conductor 5 + on elliptic curve of conductor 389 sage: P.quadratic_form() 778*x^2 + 925*x*y + 275*y^2 """ @@ -6372,15 +6472,13 @@ def kolyvagin_point(self, D, c=ZZ(1), check=True): INPUT: - - `D` -- a Heegner discriminant - - - `c` -- (default: 1) conductor, must be coprime to `DN` + - `D` -- a Heegner discriminant - - ``check`` -- bool (default: ``True``) + - `c` -- (default: 1) conductor, must be coprime to `DN` - OUTPUT: + - ``check`` -- bool (default: ``True``) - The Kolyvagin point `P` of conductor `c`. + OUTPUT: The Kolyvagin point `P` of conductor `c`. EXAMPLES:: @@ -6417,7 +6515,7 @@ def ell_heegner_discriminants(self, bound): sage: E.heegner_discriminants(30) # indirect doctest [-7, -8, -19, -24] """ - return [-D for D in range(1, bound) + return [ZZ(-D) for D in range(1, bound) if self.satisfies_heegner_hypothesis(-D)] @@ -6440,7 +6538,7 @@ def ell_heegner_discriminants_list(self, n): [-7, -8, -19, -24] """ v = [] - D = -5 + D = ZZ(-5) while len(v) < n: while not self.satisfies_heegner_hypothesis(D): D -= 1 @@ -6484,27 +6582,27 @@ def heegner_point_height(self, D, prec=2, check_rank=True): sage: E = EllipticCurve('5077a') sage: E.heegner_point_height(-7) 0 - sage: E.heegner_point_height(-7,check_rank=False) + sage: E.heegner_point_height(-7, check_rank=False) 0.0000? """ if not self.satisfies_heegner_hypothesis(D): - raise ArithmeticError("Discriminant (=%s) must be a fundamental discriminant that satisfies the Heegner hypothesis."%D) + raise ArithmeticError("Discriminant (=%s) must be a fundamental discriminant that satisfies the Heegner hypothesis." % D) if check_rank and self.rank() >= 2: return ZZ(0) if D == -3 or D == -4: - raise ArithmeticError("Discriminant (=%s) must not be -3 or -4."%D) + raise ArithmeticError("Discriminant (=%s) must not be -3 or -4." % D) eps = self.root_number() L1_vanishes = self.lseries().L1_vanishes() - IR = rings.RealIntervalField(20) # TODO: why 20 bits here? + IR = RealIntervalField(20) # TODO: why 20 bits here? if eps == 1 and L1_vanishes: return IR(0) # rank even hence >= 2, so Heegner point is torsion. - RR = rings.RealField() + RR = RealField() from math import sqrt alpha = RR(sqrt(abs(D)))/(2*self.period_lattice().complex_area()) @@ -6645,38 +6743,38 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, True """ if not self.satisfies_heegner_hypothesis(D): - raise ArithmeticError("Discriminant (=%s) must be a fundamental discriminant that satisfies the Heegner hypothesis."%D) + raise ArithmeticError("Discriminant (=%s) must be a fundamental discriminant that satisfies the Heegner hypothesis." % D) if check_rank and self.rank() >= 2: - return rings.infinity + return infinity # First compute upper bound on height of Heegner point. tm = verbose("computing heegner point height...") h0 = self.heegner_point_height(D, prec=prec, check_rank=check_rank) if h0 == 0: - return rings.infinity + return infinity # We divide by 2 to get the height **over Q** of the # Heegner point on the twist. ht = h0/2 - verbose('Height of heegner point = %s'%ht, tm) + verbose('Height of heegner point = %s' % ht, tm) if self.root_number() == 1: F = self.quadratic_twist(D) else: F = self # Now rank(F) > 0 - h = ht.upper() - verbose("Heegner height bound = %s"%h) + h = ht.upper() + verbose("Heegner height bound = %s" % h) B = F.CPS_height_bound() - verbose("CPS bound = %s"%B) + verbose("CPS bound = %s" % B) c = h/(min_p**2) + B - verbose("Search would have to be up to height = %s"%c) + verbose("Search would have to be up to height = %s" % c) from .ell_rational_field import _MAX_HEIGHT - IR = rings.RealIntervalField(20) # todo: 20? + IR = RealIntervalField(20) # todo: 20? a = 1 if c > _MAX_HEIGHT or F is self: @@ -6689,7 +6787,7 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, if z.is_divisible_by(2): a = 2 else: - FK_even_tor_pts = [T for T in FK.torsion_subgroup().gens() if T.order()%2==0] + FK_even_tor_pts = [T for T in FK.torsion_subgroup().gens() if T.order() % 2 == 0] if len(FK_even_tor_pts) == 2: FK_even_tor_pts.append(sum(FK_even_tor_pts)) for T in FK_even_tor_pts: @@ -6703,7 +6801,7 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, verbose("doing point search") P = F.point_search(c) verbose("done with point search") - P = [x for x in P if x.order() == rings.infinity] + P = [x for x in P if x.order() == infinity] a = 1 if len(P) == 0: return IR(1) @@ -6714,7 +6812,7 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, if z.is_divisible_by(2): a = 2 else: - FK_even_tor_pts = [T for T in FK.torsion_subgroup().gens() if T.order()%2==0] + FK_even_tor_pts = [T for T in FK.torsion_subgroup().gens() if T.order() % 2 == 0] if len(FK_even_tor_pts) == 2: FK_even_tor_pts.append(sum(FK_even_tor_pts)) for T in FK_even_tor_pts: @@ -6736,12 +6834,12 @@ def _adjust_heegner_index(self, a): EXAMPLES:: sage: E = EllipticCurve('11a1') - sage: a = RIF(sqrt(2))-RIF(1.4142135623730951) + sage: a = RIF(sqrt(2)) - RIF(1.4142135623730951) sage: E._adjust_heegner_index(a) 1.?e-8 """ if a.lower() < 0: - IR = rings.RealIntervalField(20) # todo: 20? + IR = RealIntervalField(20) # todo: 20? a = IR((0, a.upper())) return a.sqrt() @@ -6813,16 +6911,16 @@ def heegner_index_bound(self, D=0, prec=5, max_height=None): if 0 in ht: return 0, D, False F = self.quadratic_twist(D) - h = ht.upper() - verbose("Heegner height bound = %s"%h) + h = ht.upper() + verbose("Heegner height bound = %s" % h) B = F.CPS_height_bound() - verbose("CPS bound = %s"%B) + verbose("CPS bound = %s" % B) if self.two_torsion_rank() == 0: H = h else: H = 4*h p = 3 - from sage.all import next_prime + from sage.arith.misc import next_prime while True: c = H/(2*p**2) + B if c < max_height: @@ -6830,13 +6928,13 @@ def heegner_index_bound(self, D=0, prec=5, max_height=None): if p > 100: break p = next_prime(p) - verbose("Using p = %s"%p) + verbose("Using p = %s" % p) if c > max_height: - verbose("No information by searching only up to max_height (=%s)."%c) + verbose("No information by searching only up to max_height (=%s)." % c) return -1, D, False - verbose("Searching up to height = %s"%c) + verbose("Searching up to height = %s" % c) eps = 10e-5 def _bound(P): @@ -6848,33 +6946,33 @@ def _bound(P): S, I, reg = F.saturation(P) - IR = rings.RealIntervalField(20) # todo: 20? + IR = RealIntervalField(20) # todo: 20? h = IR(reg-eps,reg+eps) ind2 = ht/(h/2) - verbose("index squared = %s"%ind2) + verbose("index squared = %s" % ind2) ind = ind2.sqrt() - verbose("index = %s"%ind) + verbose("index = %s" % ind) # Compute upper bound on square root of index. if ind.absolute_diameter() < 1: t, i = ind.is_int() if t: # unique integer in interval, so we've found exact index squared. return prime_divisors(i), D, i - raise RuntimeError("Unable to compute bound for e=%s, D=%s (try increasing precision)"%(self, D)) + raise RuntimeError("Unable to compute bound for e=%s, D=%s (try increasing precision)" % (self, D)) # First try a quick search, in case we get lucky and find # a generator. P = F.point_search(13, rank_bound=1) - P = [x for x in P if x.order() == rings.infinity] + P = [x for x in P if x.order() == infinity] if len(P) > 0: return _bound(P) # Do search to eliminate possibility that Heegner point is # divisible by primes up to p, without finding Heegner point. P = F.point_search(c, rank_bound=1) - P = [x for x in P if x.order() == rings.infinity] + P = [x for x in P if x.order() == infinity] if len(P) == 0: # We've eliminated the possibility of a divisor up to p. - return rings.prime_range(3, p), D, False + return prime_range(3, p), D, False else: return _bound(P) @@ -6888,9 +6986,7 @@ def _heegner_index_in_EK(self, D): - `D` -- negative integer; the Heegner discriminant - OUTPUT: - - a power of 2 -- the given index + OUTPUT: A power of 2 -- the given index. EXAMPLES: @@ -6915,7 +7011,7 @@ def _heegner_index_in_EK(self, D): """ # check conditions, then use cache if possible. if not self.satisfies_heegner_hypothesis(D): - raise ValueError("D (=%s) must satisfy the Heegner hypothesis"%D) + raise ValueError("D (=%s) must satisfy the Heegner hypothesis" % D) try: return self.__heegner_index_in_EK[D] except AttributeError: @@ -6944,28 +7040,28 @@ def _heegner_index_in_EK(self, D): # so we may assume t is of 2-power order. ##################################################################### - E = self # nice shortcut - F = E.quadratic_twist(D).minimal_model() - K = rings.QuadraticField(D, 'a') + E = self # nice shortcut + F = E.quadratic_twist(D).minimal_model() + K = QuadraticField(D, 'a') # Define a map phi that we'll use to put the points of E^D(QQ) # into E(K): - G = E.change_ring(K) - G2 = F.change_ring(K) - phi = G2.isomorphism_to(G) + G = E.change_ring(K) + G2 = F.change_ring(K) + phi = G2.isomorphism_to(G) # Basis for E(Q)/tor oplus E^D(QQ)/tor in E(K): basis = [G(z) for z in E.gens()] + [G(phi(z)) for z in F.gens()] # Make a list of the 2-power order torsion points in E(K), including 0. - T = [G(z) for z in G.torsion_subgroup().list() if z.order() == 1 or + T = [G(z) for z in G.torsion_subgroup().list() if z.order() == 1 or ((z.order() % 2 == 0 and len(z.order().factor()) == 1))] - r = len(basis) # rank - V = rings.QQ**r - B = [] + r = len(basis) # rank + V = QQ**r + B = [] # Iterate through reps for A/(2*A) creating vectors in (1/2)*ZZ^r - for v in rings.GF(2)**r: + for v in GF(2)**r: if not v: continue P = sum([basis[i] for i in range(r) if v[i]]) @@ -6973,9 +7069,9 @@ def _heegner_index_in_EK(self, D): if (P+t).is_divisible_by(2): B.append(V(v)/2) - A = rings.ZZ**r + A = ZZ**r # Take span of our vectors in (1/2)*ZZ^r, along with ZZ^r. This is E(K)/tor. - W = V.span(B, rings.ZZ) + A + W = V.span(B, ZZ) + A # Compute the index in E(K)/tor of A = E(Q)/tor + E^D(Q)/tor, cache, and return. index = A.index_in(W) @@ -7050,19 +7146,20 @@ def heegner_sha_an(self, D, prec=53): 2.3 in [GZ1986]_ page 311, then that conjecture is false, as the following example shows:: - sage: E = EllipticCurve('65a') # long time - sage: E.heegner_sha_an(-56) # long time + sage: # long time + sage: E = EllipticCurve('65a') + sage: E.heegner_sha_an(-56) 1.00000000000000 - sage: E.torsion_order() # long time + sage: E.torsion_order() 2 - sage: E.tamagawa_product() # long time + sage: E.tamagawa_product() 1 - sage: E.quadratic_twist(-56).rank() # long time + sage: E.quadratic_twist(-56).rank() 2 """ # check conditions, then return from cache if possible. if not self.satisfies_heegner_hypothesis(D): - raise ValueError("D (=%s) must satisfy the Heegner hypothesis"%D) + raise ValueError("D (=%s) must satisfy the Heegner hypothesis" % D) try: return self.__heegner_sha_an[(D, prec)] except AttributeError: @@ -7072,13 +7169,13 @@ def heegner_sha_an(self, D, prec=53): # Use the BSD conjecture over the quadratic imaginary K -- # see page 311 of [GZ1986]_ for the formula. - E = self # notational convenience - F = E.quadratic_twist(D).minimal_model() - K = rings.QuadraticField(D, 'a') + E = self # notational convenience + F = E.quadratic_twist(D).minimal_model() + K = QuadraticField(D, 'a') # Compute each of the quantities in BSD # - The torsion subgroup over K. - T = E.change_ring(K).torsion_order() + T = E.change_ring(K).torsion_order() # - The product of the Tamagawa numbers, which because D is # coprime to N is just the square of the product of the @@ -7088,7 +7185,7 @@ def heegner_sha_an(self, D, prec=53): # - The leading term of the L-series, as a product of two # other L-series. - rE = E.rank() + rE = E.rank() rF = F.rank() L_E = E.lseries().dokchitser(prec).derivative(1, rE) L_F = F.lseries().dokchitser(prec).derivative(1, rF) @@ -7169,13 +7266,13 @@ def _heegner_forms_list(self, D, beta=None, expected_count=None): [389*x^2 + 313*x*y + 63*y^2, 1167*x^2 + 313*x*y + 21*y^2, 3501*x^2 + 313*x*y + 7*y^2] """ if expected_count is None: - expected_count = number_field.QuadraticField(D, 'a').class_number() + expected_count = D.class_number() N = self.conductor() if beta is None: beta = Integers(4*N)(D).sqrt(extend=False) else: assert beta**2 == Integers(4*N)(D) - from sage.quadratic_forms.all import BinaryQF + from sage.quadratic_forms.binary_qf import BinaryQF b = ZZ(beta) % (2*N) all = [] seen = [] @@ -7229,11 +7326,11 @@ def satisfies_heegner_hypothesis(self, D): sage: E.satisfies_heegner_hypothesis(-11) False """ - if not number_field.is_fundamental_discriminant(D): - return False D = ZZ(D) if D >= 0: return False + if not D.is_fundamental_discriminant(): + return False if D.gcd(self.conductor()) != 1: return False for p, _ in self.conductor().factor(): diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index 06d83bc7759..64d025a6481 100644 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -29,6 +29,7 @@ import numpy import math import bisect +from itertools import product from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -41,8 +42,8 @@ from sage.rings.real_mpfr import RR from sage.misc.cachefunc import cached_method -from sage.misc.mrange import cartesian_product_iterator -from sage.arith.all import lcm, factorial +from sage.arith.functions import lcm +from sage.arith.misc import factorial from sage.ext.fast_callable import fast_callable from sage.functions.log import log, exp from sage.symbolic.ring import SR @@ -59,7 +60,7 @@ class UnionOfIntervals: EXAMPLES:: sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals - sage: R = UnionOfIntervals([1,2,3,infinity]); R + sage: R = UnionOfIntervals([1, 2, 3, infinity]); R ([1, 2] U [3, +Infinity]) sage: R + 5 ([6, 7] U [8, +Infinity]) @@ -82,9 +83,9 @@ def __init__(self, endpoints): EXAMPLES:: sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals - sage: UnionOfIntervals([0,1]) + sage: UnionOfIntervals([0, 1]) ([0, 1]) - sage: UnionOfIntervals([-infinity, pi, 17, infinity]) + sage: UnionOfIntervals([-infinity, pi, 17, infinity]) # needs sage.symbolic ([-Infinity, pi] U [17, +Infinity]) sage: UnionOfIntervals([]) () @@ -93,7 +94,7 @@ def __init__(self, endpoints): Traceback (most recent call last): ... ValueError: an even number of endpoints must be given (got 1) - sage: UnionOfIntervals([3,2,1,0]) + sage: UnionOfIntervals([3, 2, 1, 0]) Traceback (most recent call last): ... ValueError: endpoints must be given in order @@ -111,7 +112,7 @@ def finite_endpoints(self): EXAMPLES:: sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals - sage: UnionOfIntervals([0,1]).finite_endpoints() + sage: UnionOfIntervals([0, 1]).finite_endpoints() [0, 1] sage: UnionOfIntervals([-infinity, 0, 1, infinity]).finite_endpoints() [0, 1] @@ -127,7 +128,7 @@ def intervals(self): sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals sage: UnionOfIntervals(list(range(10))).intervals() [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)] - sage: UnionOfIntervals([-infinity, pi, 17, infinity]).intervals() + sage: UnionOfIntervals([-infinity, pi, 17, infinity]).intervals() # needs sage.symbolic [(-Infinity, pi), (17, +Infinity)] """ return list(zip(self._endpoints[::2], self._endpoints[1::2])) @@ -139,14 +140,14 @@ def is_empty(self): EXAMPLES:: sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals - sage: UnionOfIntervals([3,4]).is_empty() + sage: UnionOfIntervals([3, 4]).is_empty() False sage: all = UnionOfIntervals([-infinity, infinity]) sage: all.is_empty() False sage: (~all).is_empty() True - sage: A = UnionOfIntervals([0,1]) & UnionOfIntervals([2,3]) + sage: A = UnionOfIntervals([0, 1]) & UnionOfIntervals([2, 3]) sage: A.is_empty() True """ @@ -164,7 +165,7 @@ def __add__(left, right): ([0, 1/2] U [2, +Infinity]) sage: A + 1 ([1, 3/2] U [3, +Infinity]) - sage: pi + A + sage: pi + A # needs sage.symbolic ([pi, pi + 1/2] U [pi + 2, +Infinity]) sage: A + UnionOfIntervals([-infinity, -1]) ([-Infinity, -1] U [0, 1/2] U [2, +Infinity]) @@ -208,7 +209,7 @@ def __rmul__(self, other): sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals sage: A = UnionOfIntervals([0, 1/2, 2, infinity]); A ([0, 1/2] U [2, +Infinity]) - sage: pi * A + sage: pi * A # needs sage.symbolic ([0, 1/2*pi] U [2*pi, +Infinity]) """ return self * other @@ -285,13 +286,13 @@ def join(L, condition): sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals sage: A = UnionOfIntervals([1,3,5,7]); A ([1, 3] U [5, 7]) - sage: B = A+1; B + sage: B = A + 1; B ([2, 4] U [6, 8]) - sage: A.join([A,B],any) # union + sage: A.join([A,B], any) # union ([1, 4] U [5, 8]) - sage: A.join([A,B],all) # intersection + sage: A.join([A,B], all) # intersection ([2, 3] U [6, 7]) - sage: A.join([A,B],sum) # symmetric difference + sage: A.join([A,B], sum) # symmetric difference ([1, 2] U [3, 4] U [5, 6] U [7, 8]) """ all = [] @@ -332,7 +333,7 @@ def union(cls, L): sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals sage: A = UnionOfIntervals([1,3,5,7]); A ([1, 3] U [5, 7]) - sage: B = A+1; B + sage: B = A + 1; B ([2, 4] U [6, 8]) sage: A.union([A,B]) ([1, 4] U [5, 8]) @@ -362,7 +363,7 @@ def intersection(cls, L): sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals sage: A = UnionOfIntervals([1,3,5,7]); A ([1, 3] U [5, 7]) - sage: B = A+1; B + sage: B = A + 1; B ([2, 4] U [6, 8]) sage: A.intersection([A,B]) ([2, 3] U [6, 7]) @@ -389,7 +390,7 @@ def __or__(left, right): sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals sage: A = UnionOfIntervals([1,3,5,7]); A ([1, 3] U [5, 7]) - sage: B = A+1; B + sage: B = A + 1; B ([2, 4] U [6, 8]) sage: A | B ([1, 4] U [5, 8]) @@ -413,7 +414,7 @@ def __and__(left, right): sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals sage: A = UnionOfIntervals([1,3,5,7]); A ([1, 3] U [5, 7]) - sage: B = A+1; B + sage: B = A + 1; B ([2, 4] U [6, 8]) sage: A & B ([2, 3] U [6, 7]) @@ -488,13 +489,13 @@ def nonneg_region(f): sage: from sage.schemes.elliptic_curves.height import nonneg_region sage: x = polygen(RR) - sage: nonneg_region(x^2-1) + sage: nonneg_region(x^2 - 1) ([-Infinity, -1.00000000000000] U [1.00000000000000, +Infinity]) - sage: nonneg_region(1-x^2) + sage: nonneg_region(1 - x^2) ([-1.00000000000000, 1.00000000000000]) - sage: nonneg_region(1-x^3) + sage: nonneg_region(1 - x^3) ([-Infinity, 1.00000000000000]) - sage: nonneg_region(x^3-1) + sage: nonneg_region(x^3 - 1) ([1.00000000000000, +Infinity]) sage: nonneg_region((x-1)*(x-2)) ([-Infinity, 1.00000000000000] U [2.00000000000000, +Infinity]) @@ -504,13 +505,13 @@ def nonneg_region(f): ([1.00000000000000, 2.00000000000000] U [3.00000000000000, +Infinity]) sage: nonneg_region(-(x-1)*(x-2)*(x-3)) ([-Infinity, 1.00000000000000] U [2.00000000000000, 3.00000000000000]) - sage: nonneg_region(x^4+1) + sage: nonneg_region(x^4 + 1) ([-Infinity, +Infinity]) - sage: nonneg_region(-x^4-1) + sage: nonneg_region(-x^4 - 1) () """ roots = sorted(f.roots()) - sign_changes = [r for r,e in roots if e%2 == 1] + sign_changes = [r for r,e in roots if e % 2 == 1] if (f.leading_coefficient() * (-1)**f.degree()) > 0: sign_changes = [-infinity] + sign_changes if f.leading_coefficient() > 0: @@ -525,7 +526,7 @@ def inf_max_abs(f, g, D): - ``f``, ``g`` (polynomials) -- real univariate polynomials - - ``D`` (UnionOfIntervals) -- a subset of `\RR` + - ``D`` (:class:`UnionOfIntervals`) -- a subset of `\RR` OUTPUT: @@ -541,25 +542,26 @@ def inf_max_abs(f, g, D): sage: from sage.schemes.elliptic_curves.height import inf_max_abs, UnionOfIntervals sage: x = polygen(RR) - sage: f = (x-10)^4+1 - sage: g = 2*x^3+100 - sage: inf_max_abs(f,g,UnionOfIntervals([1,2,3,4,5,6])) + sage: f = (x-10)^4 + 1 + sage: g = 2*x^3 + 100 + sage: inf_max_abs(f, g, UnionOfIntervals([1,2,3,4,5,6])) 425.638201706391 - sage: r0 = (f-g).roots()[0][0] + sage: r0 = (f - g).roots()[0][0] sage: r0 5.46053402234697 - sage: max(abs(f(r0)),abs(g(r0))) + sage: max(abs(f(r0)), abs(g(r0))) 425.638201706391 """ - xs = f.roots() + f.derivative().roots() + xs = f.roots() + f.derivative().roots() xs += g.roots() + g.derivative().roots() - xs += (f-g).roots() + (f+g).roots() - xs = [r for r,e in xs if r in D] # ignore multiplicities and points outside D + xs += (f - g).roots() + (f + g).roots() + xs = [r for r, _ in xs if r in D] # ignore multiplicities and points outside D xs += D.finite_endpoints() # include endpoints of intervals if xs: - return min([max(abs(f(r)), abs(g(r))) for r in xs]) + return min(max(abs(f(r)), abs(g(r))) for r in xs) return infinity + def min_on_disk(f, tol, max_iter=10000): r""" Returns the minimum of a real-valued complex function on a square. @@ -582,7 +584,7 @@ def min_on_disk(f, tol, max_iter=10000): EXAMPLES:: sage: from sage.schemes.elliptic_curves.height import min_on_disk - sage: f = lambda x: (x^2+100).abs() + sage: f = lambda x: (x^2 + 100).abs() sage: s, t = min_on_disk(f, 0.0001) sage: s, f(s), t (0.01? + 1.00?*I, 99.01?, 99.0000000000000) @@ -683,7 +685,7 @@ def rat_term_CIF(z, try_strict=True): corner_reals = [] corner_imags = [] - for a, b in cartesian_product_iterator([z.real().endpoints(), z.imag().endpoints()]): + for a, b in product(z.real().endpoints(), z.imag().endpoints()): zz = CDF(a,b) u = (two_pi_i_CDF*zz).exp() f = u/(1-u)**2 @@ -756,12 +758,14 @@ class EllipticCurveCanonicalHeight: sage: from sage.schemes.elliptic_curves.height import EllipticCurveCanonicalHeight sage: E = EllipticCurve([0,0,0,0,1]) sage: EllipticCurveCanonicalHeight(E) - EllipticCurveCanonicalHeight object associated to Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field + EllipticCurveCanonicalHeight object associated to + Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field Normally this object would be created like this:: sage: E.height_function() - EllipticCurveCanonicalHeight object associated to Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field + EllipticCurveCanonicalHeight object associated to + Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field """ def __init__(self, E): @@ -777,32 +781,36 @@ def __init__(self, E): sage: from sage.schemes.elliptic_curves.height import EllipticCurveCanonicalHeight sage: E = EllipticCurve([0,0,0,0,1]) sage: EllipticCurveCanonicalHeight(E) - EllipticCurveCanonicalHeight object associated to Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field + EllipticCurveCanonicalHeight object associated to + Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field An example over a number field:: - sage: K.<i>=QuadraticField(-1) - sage: E = EllipticCurve([0,i,0,i,i]) - sage: EllipticCurveCanonicalHeight(E) - EllipticCurveCanonicalHeight object associated to Elliptic Curve defined by y^2 = x^3 + i*x^2 + i*x + i over Number Field in i with defining polynomial x^2 + 1 with i = 1*I + sage: K.<i> = QuadraticField(-1) # needs sage.rings.number_field + sage: E = EllipticCurve([0,i,0,i,i]) # needs sage.rings.number_field + sage: EllipticCurveCanonicalHeight(E) # needs sage.rings.number_field + EllipticCurveCanonicalHeight object associated to + Elliptic Curve defined by y^2 = x^3 + i*x^2 + i*x + i + over Number Field in i with defining polynomial x^2 + 1 with i = 1*I TESTS: The base field must be a number field (or `\QQ`):: sage: from sage.schemes.elliptic_curves.height import EllipticCurveCanonicalHeight - sage: E = EllipticCurve(GF(7),[0,0,0,0,1]) + sage: E = EllipticCurve(GF(7), [0,0,0,0,1]) sage: EllipticCurveCanonicalHeight(E) Traceback (most recent call last): ... - ValueError: EllipticCurveCanonicalHeight class can only be created from an elliptic curve defined over a number field + ValueError: EllipticCurveCanonicalHeight class can only be created + from an elliptic curve defined over a number field """ from sage.schemes.elliptic_curves.ell_generic import is_EllipticCurve if is_EllipticCurve(E): self.E = E - from sage.rings.number_field.number_field_base import is_NumberField + from sage.rings.number_field.number_field_base import NumberField K = E.base_ring() - if is_NumberField(K): + if isinstance(K, NumberField): self.K = K else: raise ValueError("EllipticCurveCanonicalHeight class can only be created from an elliptic curve defined over a number field") @@ -817,7 +825,8 @@ def __repr__(self): sage: E = EllipticCurve([0,0,0,0,1]) sage: E.height_function() - EllipticCurveCanonicalHeight object associated to Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field + EllipticCurveCanonicalHeight object associated to + Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field """ return "EllipticCurveCanonicalHeight object associated to %s" % self.E @@ -875,12 +884,13 @@ def __call__(self, P): Over a number field other than `\QQ`:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve(K, [0,0,0,1,-27]) sage: H = E.height_function() sage: H.base_field() Number Field in i with defining polynomial x^2 + 1 with i = 1*I - sage: H((1,5*i)) + sage: H((1, 5*i)) 1.22257115164148 """ return self.E(P).height() @@ -904,8 +914,9 @@ def alpha(self, v, tol=0.01): Example 1 from [CPS2006]_:: - sage: K.<i>=QuadraticField(-1) - sage: E = EllipticCurve([0,0,0,1+5*i,3+i]) + sage: # needs sage.rings.number_field + sage: K.<i> = QuadraticField(-1) + sage: E = EllipticCurve([0, 0, 0, 1 + 5*i, 3 + i]) sage: H = E.height_function() sage: alpha = H.alpha(K.places()[0]) sage: alpha @@ -913,7 +924,7 @@ def alpha(self, v, tol=0.01): Compare with `\log(\epsilon_v)=0.344562...` in [CPS2006]_:: - sage: 3*alpha.log() + sage: 3*alpha.log() # needs sage.rings.number_field 0.347263296676126 """ from sage.rings.polynomial.polynomial_ring import polygen @@ -975,8 +986,9 @@ def e_p(self, p): EXAMPLES:: - sage: K.<i>=QuadraticField(-1) - sage: E = EllipticCurve([0,0,0,1+5*i,3+i]) + sage: # needs sage.rings.number_field + sage: K.<i> = QuadraticField(-1) + sage: E = EllipticCurve([0, 0, 0, 1 + 5*i, 3 + i]) sage: H = E.height_function() sage: H.e_p(K.prime_above(2)) 2 @@ -1027,8 +1039,9 @@ def DE(self, n): EXAMPLES:: - sage: K.<i>=QuadraticField(-1) - sage: E = EllipticCurve([0,0,0,1+5*i,3+i]) + sage: # needs sage.rings.number_field + sage: K.<i> = QuadraticField(-1) + sage: E = EllipticCurve([0, 0, 0, 1+5*i, 3+i]) sage: H = E.height_function() sage: [H.DE(n) for n in srange(1,6)] [0, 2*log(5) + 2*log(2), 0, 2*log(13) + 2*log(5) + 4*log(2), 0] @@ -1055,10 +1068,10 @@ def ME(self): EXAMPLES:: - sage: K.<i>=QuadraticField(-1) - sage: E = EllipticCurve([0,0,0,1+5*i,3+i]) - sage: H = E.height_function() - sage: H.ME() + sage: K.<i> = QuadraticField(-1) # needs sage.rings.number_field + sage: E = EllipticCurve([0, 0, 0, 1+5*i, 3+i]) # needs sage.rings.number_field + sage: H = E.height_function() # needs sage.rings.number_field + sage: H.ME() # needs sage.rings.number_field 1 sage: E = EllipticCurve([0,0,0,0,1]) sage: E.height_function().ME() @@ -1094,13 +1107,13 @@ def B(self, n, mu): Example 10.2 from [Tho2010]_:: - sage: K.<i>=QuadraticField(-1) - sage: E = EllipticCurve([0,1-i,i,-i,0]) - sage: H = E.height_function() + sage: K.<i> = QuadraticField(-1) # needs sage.rings.number_field + sage: E = EllipticCurve([0, 1-i, i, -i, 0]) # needs sage.rings.number_field + sage: H = E.height_function() # needs sage.rings.number_field In [Tho2010]_ the value is given as 0.772:: - sage: RealField(12)( H.B(5, 0.01) ) + sage: RealField(12)( H.B(5, 0.01) ) # needs sage.rings.number_field 0.777 """ K = self.K @@ -1144,16 +1157,18 @@ def psi(self, xi, v): sage: L = E.period_lattice(v) sage: P = E.lift_x(10/9) sage: L(P) - 1.53151606047462 + 0.958696500380439 sage: L(P) / L.real_period() - 0.615014189772115 + 0.384985810227885 sage: H = E.height_function() - sage: H.psi(10/9,v) + sage: H.psi(10/9, v) 0.615014189772115 An example over a number field:: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,0,0,0,a]) sage: P = E.lift_x(1/3*a^2 + a + 5/3) sage: v = K.real_places()[0] @@ -1164,9 +1179,9 @@ def psi(self, xi, v): 0.867385122699931 sage: xP = v(P.xy()[0]) sage: H = E.height_function() - sage: H.psi(xP,v) + sage: H.psi(xP, v) 0.867385122699931 - sage: H.psi(1.23,v) + sage: H.psi(1.23, v) 0.785854718241495 """ if xi > 1e9: @@ -1203,17 +1218,19 @@ def S(self, xi1, xi2, v): sage: E = EllipticCurve('389a') sage: v = QQ.places()[0] sage: H = E.height_function() - sage: H.S(2,3,v) + sage: H.S(2, 3, v) ([0.224512677391895, 0.274544821597130] U [0.725455178402870, 0.775487322608105]) An example over a number field:: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,0,0,0,a]) sage: v = K.real_places()[0] sage: H = E.height_function() - sage: H.S(9,10,v) - ([0.0781194447253472, 0.0823423732016403] U [0.917657626798360, 0.921880555274653]) + sage: H.S(9, 10, v) + ([0.078119444725347..., 0.082342373201640...] U [0.91765762679836..., 0.92188055527465...]) """ L = self.E.period_lattice(v) w1, w2 = L.basis(prec=v.codomain().prec()) @@ -1251,22 +1268,24 @@ def Sn(self, xi1, xi2, n, v): sage: E = EllipticCurve('389a') sage: v = QQ.places()[0] sage: H = E.height_function() - sage: H.S(2,3,v) , H.Sn(2,3,1,v) + sage: H.S(2, 3, v), H.Sn(2, 3, 1, v) (([0.224512677391895, 0.274544821597130] U [0.725455178402870, 0.775487322608105]), ([0.224512677391895, 0.274544821597130] U [0.725455178402870, 0.775487322608105])) - sage: H.Sn(2,3,6,v) + sage: H.Sn(2, 3, 6, v) ([0.0374187795653158, 0.0457574702661884] U [0.120909196400478, 0.129247887101351] U [0.204085446231982, 0.212424136932855] U [0.287575863067145, 0.295914553768017] U [0.370752112898649, 0.379090803599522] U [0.454242529733812, 0.462581220434684] U [0.537418779565316, 0.545757470266188] U [0.620909196400478, 0.629247887101351] U [0.704085446231982, 0.712424136932855] U [0.787575863067145, 0.795914553768017] U [0.870752112898649, 0.879090803599522] U [0.954242529733812, 0.962581220434684]) An example over a number field:: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,0,0,0,a]) sage: v = K.real_places()[0] sage: H = E.height_function() - sage: H.S(2,3,v) , H.Sn(2,3,1,v) + sage: H.S(2, 3, v), H.Sn(2, 3, 1, v) (([0.142172065860075, 0.172845716928584] U [0.827154283071416, 0.857827934139925]), - ([0.142172065860075, 0.172845716928584] U [0.827154283071416, 0.857827934139925])) - sage: H.Sn(2,3,6,v) + ([0.142172065860075, 0.172845716928584] U [0.827154283071416, 0.857827934139925])) + sage: H.Sn(2, 3, 6, v) ([0.0236953443100124, 0.0288076194880974] U [0.137859047178569, 0.142971322356654] U [0.190362010976679, 0.195474286154764] U [0.304525713845236, 0.309637989023321] U [0.357028677643346, 0.362140952821431] U [0.471192380511903, 0.476304655689988] U [0.523695344310012, 0.528807619488097] U [0.637859047178569, 0.642971322356654] U [0.690362010976679, 0.695474286154764] U [0.804525713845236, 0.809637989023321] U [0.857028677643346, 0.862140952821431] U [0.971192380511903, 0.976304655689988]) """ SS = 1/ZZ(n) * self.S(xi1, xi2, v) @@ -1305,14 +1324,16 @@ def real_intersection_is_empty(self, Bk, v): height strictly greater than 0.2, but fail to prove the same for 0.3:: - sage: H.real_intersection_is_empty([H.B(n,0.2) for n in srange(1,10)],v) + sage: H.real_intersection_is_empty([H.B(n,0.2) for n in srange(1,10)], v) True - sage: H.real_intersection_is_empty([H.B(n,0.3) for n in srange(1,10)],v) + sage: H.real_intersection_is_empty([H.B(n,0.3) for n in srange(1,10)], v) False An example over a number field:: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,0,0,0,a]) sage: v = K.real_places()[0] sage: H = E.height_function() @@ -1322,9 +1343,9 @@ def real_intersection_is_empty(self, Bk, v): height strictly greater than 0.07, but fail to prove the same for 0.08:: - sage: H.real_intersection_is_empty([H.B(n,0.07) for n in srange(1,5)],v) # long time (3.3s) + sage: H.real_intersection_is_empty([H.B(n,0.07) for n in srange(1,5)], v) # long time, needs sage.rings.number_field True - sage: H.real_intersection_is_empty([H.B(n,0.08) for n in srange(1,5)],v) + sage: H.real_intersection_is_empty([H.B(n,0.08) for n in srange(1,5)], v) # needs sage.rings.number_field False """ return UnionOfIntervals.intersection([self.Sn(-B, B, k+1, v) for k,B in enumerate(Bk)]).is_empty() @@ -1383,8 +1404,9 @@ def wp_c(self, v): sage: H.wp_c(QQ.places()[0]) 2.68744508779950 - sage: K.<i>=QuadraticField(-1) - sage: E = EllipticCurve([0,0,0,1+5*i,3+i]) + sage: # needs sage.rings.number_field + sage: K.<i> = QuadraticField(-1) + sage: E = EllipticCurve([0, 0, 0, 1 + 5*i, 3 + i]) sage: H = E.height_function() sage: H.wp_c(K.places()[0]) 2.66213425640096 @@ -1662,7 +1684,9 @@ def complex_intersection_is_empty(self, Bk, v, verbose=False, use_half=True): EXAMPLES:: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,0,0,0,a]) sage: v = K.complex_embeddings()[0] sage: H = E.height_function() @@ -1673,18 +1697,18 @@ def complex_intersection_is_empty(self, Bk, v, verbose=False, use_half=True): for 0.03. For the first proof, using only `n=1,2,3` is not sufficient:: - sage: H.complex_intersection_is_empty([H.B(n,0.02) for n in [1,2,3]],v) # long time (~6s) + sage: H.complex_intersection_is_empty([H.B(n,0.02) for n in [1,2,3]], v) # long time, needs sage.rings.number_field False - sage: H.complex_intersection_is_empty([H.B(n,0.02) for n in [1,2,3,4]],v) + sage: H.complex_intersection_is_empty([H.B(n,0.02) for n in [1,2,3,4]], v) # needs sage.rings.number_field True - sage: H.complex_intersection_is_empty([H.B(n,0.03) for n in [1,2,3,4]],v) # long time (4s) + sage: H.complex_intersection_is_empty([H.B(n,0.03) for n in [1,2,3,4]], v) # long time, needs sage.rings.number_field False Using `n\le6` enables us to prove the lower bound 0.03. Note that it takes longer when the result is ``False`` than when it is ``True``:: - sage: H.complex_intersection_is_empty([H.B(n,0.03) for n in [1..6]],v) + sage: H.complex_intersection_is_empty([H.B(n,0.03) for n in [1..6]], v) # needs sage.rings.number_field True """ from sage.schemes.elliptic_curves.period_lattice_region import PeriodicRegion @@ -1780,28 +1804,29 @@ def test_mu(self, mu, N, verbose=True): EXAMPLES:: - sage: K.<a> = NumberField(x^3-2) - sage: E = EllipticCurve([0,0,0,0,a]) - sage: H = E.height_function() + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: E = EllipticCurve([0,0,0,0,a]) # needs sage.rings.number_field + sage: H = E.height_function() # needs sage.rings.number_field This curve does have a point of good reduction whose canonical point is approximately 1.68:: - sage: P = E.gens(lim3=5)[0]; P + sage: P = E.gens(lim3=5)[0]; P # needs sage.rings.number_field (1/3*a^2 + a + 5/3 : -2*a^2 - 4/3*a - 5/3 : 1) - sage: P.height() + sage: P.height() # needs sage.rings.number_field 1.68038085233673 - sage: P.has_good_reduction() + sage: P.has_good_reduction() # needs sage.rings.number_field True Using `N=5` we can prove that 0.1 is a lower bound (in fact we only need `N=2`), but not that 0.2 is:: - sage: H.test_mu(0.1, 5) + sage: H.test_mu(0.1, 5) # needs sage.rings.number_field B_1(0.100000000000000) = 1.51580969677387 B_2(0.100000000000000) = 0.932072561526720 True - sage: H.test_mu(0.2, 5) + sage: H.test_mu(0.2, 5) # needs sage.rings.number_field B_1(0.200000000000000) = 2.04612906979932 B_2(0.200000000000000) = 3.09458988474327 B_3(0.200000000000000) = 27.6251108409484 @@ -1813,11 +1838,11 @@ def test_mu(self, mu, N, verbose=True): either primitive or divisible by either 2 or 3. In fact it is primitive:: - sage: (P.height()/0.1).sqrt() + sage: (P.height()/0.1).sqrt() # needs sage.rings.number_field 4.09924487233530 - sage: P.division_points(2) + sage: P.division_points(2) # needs sage.rings.number_field [] - sage: P.division_points(3) + sage: P.division_points(3) # needs sage.rings.number_field [] """ # Compute the list of values `B_n(\mu)` for n in 1..N. If any @@ -1888,46 +1913,50 @@ def min_gr(self, tol, n_max, verbose=False): Example 10.1 from [Tho2010]_ (where a lower bound of 0.18 was given):: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) - sage: E = EllipticCurve([0,0,0,91-26*i,-144-323*i]) + sage: E = EllipticCurve([0, 0, 0, 91 - 26*i, -144 - 323*i]) sage: H = E.height_function() - sage: H.min_gr(0.1,4) # long time (8.1s) + sage: H.min_gr(0.1, 4) # long time 0.1621049443313762 Example 10.2 from [Tho2010]_:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) - sage: E = EllipticCurve([0,1-i,i,-i,0]) + sage: E = EllipticCurve([0, 1 - i, i, -i, 0]) sage: H = E.height_function() - sage: H.min_gr(0.01, 5) # long time + sage: H.min_gr(0.01, 5) # long time 0.020153685521979152 In this example the point `P=(0,0)` has height 0.023 so our lower bound is quite good:: - sage: P = E((0,0)) - sage: P.has_good_reduction() + sage: P = E((0,0)) # needs sage.rings.number_field + sage: P.has_good_reduction() # needs sage.rings.number_field True - sage: P.height() + sage: P.height() # needs sage.rings.number_field 0.0230242154471211 Example 10.3 from [Tho2010]_ (where the same bound of 0.25 is given):: - sage: K.<a> = NumberField(x^3-2) - sage: E = EllipticCurve([0,0,0,-3*a-a^2,a^2]) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^3 - 2) + sage: E = EllipticCurve([0, 0, 0, -3*a - a^2, a^2]) sage: H = E.height_function() - sage: H.min_gr(0.1,5) # long time (7.2s) + sage: H.min_gr(0.1, 5) # long time 0.25 TESTS: This example from the LMFDB gave problems before the fix in :trac:`8829`:: - sage: K.<phi> = NumberField(x^2-x-1) + sage: # needs sage.rings.number_field + sage: K.<phi> = NumberField(x^2 - x - 1) sage: E = EllipticCurve([phi + 1, -phi + 1, 1, 20*phi - 39, 196*phi + 237]) sage: H = E.height_function() - sage: H.min_gr(.1, 5, verbose=True) # long time (~22s) + sage: H.min_gr(.1, 5, verbose=True) # long time B_1(1) = 1540.199246369678 ... halving mu to 0.25 and increasing n_max to 6 @@ -2009,34 +2038,37 @@ def min(self, tol, n_max, verbose=False): Example 10.1 from [Tho2010]_ (where a lower bound of 0.18 was given):: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) - sage: E = EllipticCurve([0,0,0,91-26*i,-144-323*i]) + sage: E = EllipticCurve([0, 0, 0, 91 - 26*i, -144 - 323*i]) sage: H = E.height_function() - sage: H.min(0.1,4) # long time (8.1s) + sage: H.min(0.1, 4) # long time 0.1621049443313762 Example 10.2 from [Tho2010]_:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) - sage: E = EllipticCurve([0,1-i,i,-i,0]) + sage: E = EllipticCurve([0, 1 - i, i, -i, 0]) sage: H = E.height_function() - sage: H.min(0.01,5) # long time (4s) + sage: H.min(0.01, 5) # long time 0.020153685521979152 In this example the point `P=(0,0)` has height 0.023 so our lower bound is quite good:: - sage: P = E((0,0)) - sage: P.height() + sage: P = E((0,0)) # needs sage.rings.number_field + sage: P.height() # needs sage.rings.number_field 0.0230242154471211 Example 10.3 from [Tho2010]_ (where the same bound of 0.0625 is given):: - sage: K.<a> = NumberField(x^3-2) - sage: E = EllipticCurve([0,0,0,-3*a-a^2,a^2]) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^3 - 2) + sage: E = EllipticCurve([0, 0, 0, -3*a - a^2, a^2]) sage: H = E.height_function() - sage: H.min(0.1,5) # long time (7s) + sage: H.min(0.1, 5) # long time 0.0625 More examples over `\QQ`:: @@ -2050,8 +2082,8 @@ def min(self, tol, n_max, verbose=False): After base change the lower bound can decrease:: - sage: K.<a> = QuadraticField(-5) - sage: E.change_ring(K).height_function().min(0.5, 10) # long time (8s) + sage: K.<a> = QuadraticField(-5) # needs sage.rings.number_field + sage: E.change_ring(K).height_function().min(0.5, 10) # long time, needs sage.rings.number_field 0.04419417382415922 sage: E = EllipticCurve('389a') diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index e4de0f2cf42..58375d02a64 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -21,6 +21,8 @@ - Lorenz Panny (2021): Refactor isogenies and isomorphisms into the common :class:`EllipticCurveHom` interface. + +- Lorenz Panny (2022): :meth:`~EllipticCurveHom.matrix_on_subgroup` """ from sage.misc.cachefunc import cached_method from sage.structure.richcmp import richcmp_not_equal, richcmp, op_EQ, op_NE @@ -54,7 +56,7 @@ def __init__(self, *args, **kwds): From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field in z2 of size 257^2 To: Elliptic Curve defined by y^2 = x^3 + 151*x + 22 over Finite Field in z2 of size 257^2 sage: E.isogeny(P, algorithm='velusqrt') # indirect doctest - Elliptic-curve isogeny (using โˆšรฉlu) of degree 127: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 127: From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field in z2 of size 257^2 To: Elliptic Curve defined by y^2 = x^3 + 119*x + 231 over Finite Field in z2 of size 257^2 sage: E.montgomery_model(morphism=True) # indirect doctest @@ -73,7 +75,7 @@ def __init__(self, *args, **kwds): self._domain._fetch_cached_order(self._codomain) def _repr_type(self): - """ + r""" Return a textual representation of what kind of morphism this is. Used by :meth:`Morphism._repr_`. @@ -87,7 +89,7 @@ def _repr_type(self): @staticmethod def _composition_impl(left, right): - """ + r""" Called by :meth:`_composition_`. TESTS:: @@ -99,7 +101,7 @@ def _composition_impl(left, right): return NotImplemented def _composition_(self, other, homset): - """ + r""" Return the composition of this elliptic-curve morphism with another elliptic-curve morphism. @@ -131,7 +133,7 @@ def _composition_(self, other, homset): @staticmethod def _comparison_impl(left, right, op): - """ + r""" Called by :meth:`_richcmp_`. TESTS:: @@ -624,7 +626,7 @@ def is_injective(self): return self.degree() == 1 def is_zero(self): - """ + r""" Check whether this elliptic-curve morphism is the zero map. .. NOTE:: @@ -662,7 +664,7 @@ def __neg__(self): @cached_method def __hash__(self): - """ + r""" Return a hash value for this elliptic-curve morphism. ALGORITHM: @@ -722,6 +724,128 @@ def as_morphism(self): Y_affine = Curve(self.codomain()).affine_patch(2) return X_affine.hom(self.rational_maps(), Y_affine).homogenize(2) + def matrix_on_subgroup(self, domain_gens, codomain_gens=None): + r""" + Return the matrix by which this isogeny acts on the + `n`-torsion subgroup with respect to the given bases. + + INPUT: + + - ``domain_gens`` -- basis `(P,Q)` of some `n`-torsion + subgroup on the domain of this elliptic-curve morphism + + - ``codomain_gens`` -- basis `(R,S)` of the `n`-torsion + on the codomain of this morphism, or (default) ``None`` + if ``self`` is an endomorphism + + OUTPUT: + + A `2\times 2` matrix `M` over `\ZZ/n`, such that the + image of any point `[a]P + [b]Q` under this morphism + equals `[c]R + [d]S` where `(c\ d)^T = (a\ b) M`. + + EXAMPLES:: + + sage: F.<i> = GF(419^2, modulus=[1,0,1]) + sage: E = EllipticCurve(F, [1,0]) + sage: P = E(3, 176*i) + sage: Q = E(i+7, 67*i+48) + sage: P.weil_pairing(Q, 420).multiplicative_order() + 420 + sage: iota = E.automorphisms()[2]; iota + Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in i of size 419^2 + Via: (u,r,s,t) = (i, 0, 0, 0) + sage: iota^2 == E.scalar_multiplication(-1) + True + sage: mat = iota.matrix_on_subgroup((P,Q)); mat + [301 386] + [ 83 119] + sage: mat.parent() + Full MatrixSpace of 2 by 2 dense matrices over Ring of integers modulo 420 + sage: iota(P) == 301*P + 386*Q + True + sage: iota(Q) == 83*P + 119*Q + True + sage: a,b = 123, 456 + sage: c,d = vector((a,b)) * mat; (c,d) + (111, 102) + sage: iota(a*P + b*Q) == c*P + d*Q + True + + One important application of this is to compute generators of + the kernel subgroup of an isogeny, when the `n`-torsion subgroup + containing the kernel is accessible:: + + sage: K = E(83*i-16, 9*i-147) + sage: K.order() + 7 + sage: phi = E.isogeny(K) + sage: R,S = phi.codomain().gens() + sage: mat = phi.matrix_on_subgroup((P,Q), (R,S)) + sage: mat # random -- depends on R,S + [124 263] + [115 141] + sage: kermat = mat.left_kernel_matrix(); kermat + [300 60] + sage: ker = [ZZ(v[0])*P + ZZ(v[1])*Q for v in kermat] + sage: {phi(T) for T in ker} + {(0 : 1 : 0)} + sage: phi == E.isogeny(ker) + True + + We can also compute the matrix of a Frobenius endomorphism + (:class:`~sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius`) + on a large enough subgroup to verify point-counting results:: + + sage: F.<a> = GF((101, 36)) + sage: E = EllipticCurve(GF(101), [1,1]) + sage: EE = E.change_ring(F) + sage: P,Q = EE.torsion_basis(37) + sage: pi = EE.frobenius_isogeny() + sage: M = pi.matrix_on_subgroup((P,Q)) + sage: M.parent() + Full MatrixSpace of 2 by 2 dense matrices over Ring of integers modulo 37 + sage: M.trace() + 34 + sage: E.trace_of_frobenius() + -3 + + .. SEEALSO:: + + To compute a basis of the `n`-torsion, you may use + :meth:`~sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field.torsion_basis`. + """ + if codomain_gens is None: + if not self.is_endomorphism(): + raise ValueError('basis of codomain subgroup is required for non-endomorphisms') + codomain_gens = domain_gens + + P,Q = domain_gens + R,S = codomain_gens + + ords = {P.order() for P in (P,Q,R,S)} + if len(ords) != 1: + #TODO: Is there some meaningful way to lift this restriction? + raise ValueError('generator points must all have the same order') + n, = ords + + if P.weil_pairing(Q, n).multiplicative_order() != n: + raise ValueError('generator points on domain are not independent') + if R.weil_pairing(S, n).multiplicative_order() != n: + raise ValueError('generator points on codomain are not independent') + + imP = self(P) + imQ = self(Q) + + from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper + H = AdditiveAbelianGroupWrapper(self.codomain().point_homset(), [R,S], [n,n]) + vecP = H.discrete_log(imP) + vecQ = H.discrete_log(imQ) + + from sage.matrix.constructor import matrix + from sage.rings.finite_rings.integer_mod_ring import Zmod + return matrix(Zmod(n), [vecP, vecQ]) + def compare_via_evaluation(left, right): r""" @@ -775,7 +899,7 @@ def compare_via_evaluation(left, right): d = left.degree() e = integer_floor(1 + 2 * (2*d.sqrt() + 1).log(q)) # from Hasse bound e = next(i for i, n in enumerate(E.count_points(e+1), 1) if n > 4*d) - EE = E.base_extend(F.extension(e)) + EE = E.base_extend(F.extension(e, 'U')) # named extension is faster Ps = EE.gens() return all(left._eval(P) == right._eval(P) for P in Ps) elif isinstance(F, number_field_base.NumberField): @@ -821,6 +945,7 @@ def find_post_isomorphism(phi, psi): sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + sage: x = polygen(ZZ, 'x') sage: F.<i> = GF(883^2, modulus=x^2+1) sage: E = EllipticCurve(F, [1,0]) sage: P = E.lift_x(117) @@ -857,7 +982,7 @@ def find_post_isomorphism(phi, psi): if len(isos) <= 1: break else: - E = E.base_extend(E.base_field().extension(2)) + E = E.base_extend(E.base_field().extension(2, 'U')) # named extension is faster elif isinstance(F, number_field_base.NumberField): for _ in range(100): diff --git a/src/sage/schemes/elliptic_curves/hom_composite.py b/src/sage/schemes/elliptic_curves/hom_composite.py index 576107582db..e457c9854ee 100644 --- a/src/sage/schemes/elliptic_curves/hom_composite.py +++ b/src/sage/schemes/elliptic_curves/hom_composite.py @@ -13,6 +13,7 @@ straightforward :class:`EllipticCurveIsogeny` implementation, but decomposing into prime steps is exponentially faster:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite sage: p = 3 * 2^143 - 1 sage: GF(p^2).inject_variables() @@ -23,15 +24,17 @@ 2^143 sage: EllipticCurveHom_composite(E, P) Composite morphism of degree 11150372599265311570767859136324180752990208 = 2^143: - From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2 + From: Elliptic Curve defined by y^2 = x^3 + x + over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2 To: Elliptic Curve defined by y^2 = x^3 + (18676616716352953484576727486205473216172067*z2+32690199585974925193292786311814241821808308)*x - + (3369702436351367403910078877591946300201903*z2+15227558615699041241851978605002704626689722) - over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2 + + (3369702436351367403910078877591946300201903*z2+15227558615699041241851978605002704626689722) + over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2 Yet, the interface provided by :class:`EllipticCurveHom_composite` is identical to :class:`EllipticCurveIsogeny` and other instantiations of :class:`EllipticCurveHom`:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(419), [0,1]) sage: P = E.lift_x(33); P.order() 35 @@ -40,17 +43,15 @@ From: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 419 To: Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419 sage: psi(E.lift_x(11)) - (352 : 73 : 1) + (352 : 346 : 1) sage: psi.rational_maps() - ((x^35 + 162*x^34 + 186*x^33 + 92*x^32 - ... + 44*x^3 + 190*x^2 + 80*x - - 72)/(x^34 + 162*x^33 - 129*x^32 + 41*x^31 + ... + 66*x^3 - 191*x^2 + 119*x - + 21), (x^51*y - 176*x^50*y + 115*x^49*y - 120*x^48*y + ... + 72*x^3*y + - 129*x^2*y + 163*x*y + 178*y)/(x^51 - 176*x^50 + 11*x^49 + 26*x^48 - ... - - 77*x^3 + 185*x^2 + 169*x - 128)) + ((x^35 + 162*x^34 + 186*x^33 + 92*x^32 - ... + 44*x^3 + 190*x^2 + 80*x + - 72)/(x^34 + 162*x^33 - 129*x^32 + 41*x^31 + ... + 66*x^3 - 191*x^2 + 119*x + 21), + (x^51*y - 176*x^50*y + 115*x^49*y - 120*x^48*y + ... + 72*x^3*y + 129*x^2*y + 163*x*y + + 178*y)/(x^51 - 176*x^50 + 11*x^49 + 26*x^48 - ... - 77*x^3 + 185*x^2 + 169*x - 128)) sage: psi.kernel_polynomial() x^17 + 81*x^16 + 7*x^15 + 82*x^14 + 49*x^13 + 68*x^12 + 109*x^11 + 326*x^10 - + 117*x^9 + 136*x^8 + 111*x^7 + 292*x^6 + 55*x^5 + 389*x^4 + 175*x^3 + - 43*x^2 + 149*x + 373 + + 117*x^9 + 136*x^8 + 111*x^7 + 292*x^6 + 55*x^5 + 389*x^4 + 175*x^3 + 43*x^2 + 149*x + 373 sage: psi.dual() Composite morphism of degree 35 = 7*5: From: Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419 @@ -62,14 +63,18 @@ comparing :meth:`EllipticCurveHom.rational_maps`) even when distinct factorizations of the same isogeny are compared:: - sage: psi == EllipticCurveIsogeny(E, P) + sage: psi == EllipticCurveIsogeny(E, P) # needs sage.rings.finite_rings True We can easily obtain the individual factors of the composite map:: - sage: psi.factors() - (Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 419 to Elliptic Curve defined by y^2 = x^3 + 140*x + 214 over Finite Field of size 419, - Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 140*x + 214 over Finite Field of size 419 to Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419) + sage: psi.factors() # needs sage.rings.finite_rings + (Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 419 + to Elliptic Curve defined by y^2 = x^3 + 140*x + 214 over Finite Field of size 419, + Isogeny of degree 7 + from Elliptic Curve defined by y^2 = x^3 + 140*x + 214 over Finite Field of size 419 + to Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419) AUTHORS: @@ -89,8 +94,6 @@ from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism, identity_morphism -# TODO: Implement sparse strategies? (cf. the SIKE cryptosystem) - def _eval_factored_isogeny(phis, P): """ @@ -99,9 +102,10 @@ def _eval_factored_isogeny(phis, P): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves import hom_composite sage: E = EllipticCurve(GF(419), [1,0]) - sage: Q = E(21,8) + sage: Q = E(21, 8) sage: phis = [] sage: while len(phis) < 10: ....: P = list(sorted(E(0).division_points(7)))[1] @@ -117,33 +121,102 @@ def _eval_factored_isogeny(phis, P): return P -def _compute_factored_isogeny_prime_power(P, l, e): - """ - This method takes a point `P` of order `l^e` and returns - a sequence of degree-`l` isogenies whose composition has +def _compute_factored_isogeny_prime_power(P, l, n, split=.8): + r""" + This method takes a point `P` of order `\ell^n` and returns + a sequence of degree-`\ell` isogenies whose composition has the subgroup generated by `P` as its kernel. + The optional argument ``split``, a real number between + `0` and `1`, controls the *strategy* used to compute the + isogeny: In general, the algorithm performs a number of + scalar multiplications `[\ell]` and a number of + `\ell`-isogeny evaluations, and there exist tradeoffs + between them. + + - Setting ``split`` to `0` skews the algorithm towards + isogenies, minimizing multiplications. + The asymptotic complexity is `O(n \log(\ell) + n^2 \ell)`. + + - Setting ``split`` to `1` skews the algorithm towards + multiplications, minimizing isogenies. + The asymptotic complexity is `O(n^2 \log(\ell) + n \ell)`. + + - Values strictly between `0` and `1` define *sparse* + strategies, which balance the number of isogenies and + multiplications according to the parameter. + The asymptotic complexity is `O(n \log(n) \ell)`. + + .. NOTE:: + + As of July 2022, good values for ``split`` range somewhere + between roughly `0.6` and `0.9`, depending on the size of + `\ell` and the cost of base-field arithmetic. + + REFERENCES: + + Sparse strategies were introduced in [DJP2014]_, ยง4.2.2. + + ALGORITHM: + + The splitting rule implemented here is a simple heuristic which + is usually not optimal. The advantage is that it does not rely + on prior knowledge of degrees and exact costs of elliptic-curve + arithmetic, while still working reasonably well for a fairly + wide range of situations. + EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves import hom_composite sage: E = EllipticCurve(GF(8191), [1,0]) sage: P = E.random_point() - sage: (l,e), = P.order().factor() - sage: phis = hom_composite._compute_factored_isogeny_prime_power(P,l,e) + sage: (l,n), = P.order().factor() + sage: phis = hom_composite._compute_factored_isogeny_prime_power(P, l, n) sage: hom_composite._eval_factored_isogeny(phis, P) (0 : 1 : 0) - sage: [phi.degree() for phi in phis] == [l]*e + sage: [phi.degree() for phi in phis] == [l]*n + True + + All choices of ``split`` produce the same result, albeit + not equally fast:: + + sage: # needs sage.rings.finite_rings + sage: E = EllipticCurve(GF(2^127 - 1), [1,0]) + sage: P, = E.gens() + sage: (l,n), = P.order().factor() + sage: phis = hom_composite._compute_factored_isogeny_prime_power(P,l,n) + sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0) + True + sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.1) + True + sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.5) + True + sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.9) + True + sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=1) True """ - E = P.curve() - phis = [] - for i in range(e): - K = l**(e-1-i) * P - phi = EllipticCurveIsogeny(E, K) - E = phi.codomain() - P = phi(P) - phis.append(phi) - return phis + def rec(Q, k): + + if k == 1: + # base case: Q has order l + return [EllipticCurveIsogeny(Q.curve(), Q)] + + # recursive case: k > 1 and Q has order l^k + + k1 = int(k * split + .5) + k1 = max(1, min(k - 1, k1)) # clamp to [1, k - 1] + + Q1 = l**k1 * Q + L = rec(Q1, k - k1) + + Q2 = _eval_factored_isogeny(L, Q) + R = rec(Q2, k1) + + return L + R + + return rec(P, n) def _compute_factored_isogeny_single_generator(P): @@ -154,9 +227,10 @@ def _compute_factored_isogeny_single_generator(P): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves import hom_composite sage: E = EllipticCurve(GF(419), [1,0]) - sage: P = E(42,321) + sage: P = E(42, 321) sage: phis = hom_composite._compute_factored_isogeny_single_generator(P) sage: list(sorted(phi.degree() for phi in phis)) [2, 2, 3, 5, 7] @@ -181,6 +255,7 @@ def _compute_factored_isogeny(kernel): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves import hom_composite sage: E = EllipticCurve(GF(419), [-1,0]) sage: Ps = [E(41,99), E(41,-99), E(51,14), E(21,21), E(33,17)] @@ -193,7 +268,7 @@ def _compute_factored_isogeny(kernel): phis = [] ker = list(kernel) while ker: - K, ker = ker[0], ker[1:] + K = ker.pop(0) psis = _compute_factored_isogeny_single_generator(K) ker = [_eval_factored_isogeny(psis, P) for P in ker] phis += psis @@ -217,22 +292,31 @@ def __init__(self, E, kernel, codomain=None, model=None): EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite - sage: E = EllipticCurve(GF(419), [1,0]) - sage: EllipticCurveHom_composite(E, E.lift_x(23)) + sage: E = EllipticCurve(GF(419), [1,0]) # needs sage.rings.finite_rings + sage: EllipticCurveHom_composite(E, E.lift_x(23)) # needs sage.rings.finite_rings Composite morphism of degree 105 = 3*5*7: - From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 419 - To: Elliptic Curve defined by y^2 = x^3 + 373*x + 126 over Finite Field of size 419 + From: Elliptic Curve defined by y^2 = x^3 + x + over Finite Field of size 419 + To: Elliptic Curve defined by y^2 = x^3 + 373*x + 126 + over Finite Field of size 419 The given kernel generators need not be independent:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - x - 5) sage: E = EllipticCurve('210.b6').change_ring(K) sage: E.torsion_subgroup() - Torsion Subgroup isomorphic to Z/12 + Z/2 associated to the Elliptic Curve defined by y^2 + x*y + y = x^3 + (-578)*x + 2756 over Number Field in a with defining polynomial x^2 - x - 5 + Torsion Subgroup isomorphic to Z/12 + Z/2 associated to the Elliptic Curve + defined by y^2 + x*y + y = x^3 + (-578)*x + 2756 + over Number Field in a with defining polynomial x^2 - x - 5 sage: EllipticCurveHom_composite(E, E.torsion_points()) Composite morphism of degree 24 = 2^3*3: - From: Elliptic Curve defined by y^2 + x*y + y = x^3 + (-578)*x + 2756 over Number Field in a with defining polynomial x^2 - x - 5 - To: Elliptic Curve defined by y^2 + x*y + y = x^3 + (-89915533/16)*x + (-328200928141/64) over Number Field in a with defining polynomial x^2 - x - 5 + From: Elliptic Curve defined by y^2 + x*y + y = x^3 + (-578)*x + 2756 + over Number Field in a with defining polynomial x^2 - x - 5 + To: Elliptic Curve defined by + y^2 + x*y + y = x^3 + (-89915533/16)*x + (-328200928141/64) + over Number Field in a with defining polynomial x^2 - x - 5 TESTS:: @@ -253,6 +337,7 @@ def __init__(self, E, kernel, codomain=None, model=None): :: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF((2^127-1)^2), [1,0]) sage: K = 2^30 * E.random_point() sage: psi = EllipticCurveHom_composite(E, K, model='montgomery') @@ -355,6 +440,7 @@ def from_factors(cls, maps, E=None, strict=True): :: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(419), [1,0]) sage: P, = E.gens() sage: phi = EllipticCurveHom_composite(E, P) @@ -391,16 +477,19 @@ def _call_(self, P): TESTS:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 - x - 5) sage: E = EllipticCurve('210.b6').change_ring(K) sage: psi = EllipticCurveHom_composite(E, E.torsion_points()) sage: R = E.lift_x(15/4 * (a+3)) sage: psi(R) # indirect doctest - (1033648757/303450 : 58397496786187/1083316500*a - 62088706165177/2166633000 : 1) + (1033648757/303450 : -58397496786187/1083316500*a + 54706287407197/2166633000 : 1) Check that copying the order over works:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(431), [1,0]) sage: P, = E.gens() sage: Q = 2^99*P; Q.order() @@ -428,8 +517,8 @@ def _eval(self, P): sage: E = EllipticCurve(j=Mod(1728,419)) sage: K, = E.gens() sage: psi = EllipticCurveHom_composite(E, 4*K) - sage: Ps = E.change_ring(GF(419**2))(0).division_points(5) - sage: {psi._eval(P).curve() for P in Ps} + sage: Ps = E.change_ring(GF(419**2))(0).division_points(5) # needs sage.rings.finite_rings + sage: {psi._eval(P).curve() for P in Ps} # needs sage.rings.finite_rings {Elliptic Curve defined by y^2 = x^3 + 373*x + 126 over Finite Field in z2 of size 419^2} """ if self._domain.defining_polynomial()(*P): @@ -464,7 +553,7 @@ def _repr_(self): from itertools import groupby degs = [phi.degree() for phi in self._phis] grouped = [(d, sum(1 for _ in g)) for d,g in groupby(degs)] - degs_str = '*'.join(str(d) + (f'^{e}' if e>1 else '') for d,e in grouped) + degs_str = '*'.join(str(d) + (f'^{e}' if e > 1 else '') for d,e in grouped) return f'Composite morphism of degree {self._degree} = {degs_str}:' \ f'\n From: {self._domain}' \ f'\n To: {self._codomain}' @@ -484,9 +573,15 @@ def factors(self): sage: P, = E.gens() sage: phi = EllipticCurveHom_composite(E, P) sage: phi.factors() - (Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43 to Elliptic Curve defined by y^2 = x^3 + 39*x over Finite Field of size 43, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 39*x over Finite Field of size 43 to Elliptic Curve defined by y^2 = x^3 + 42*x + 26 over Finite Field of size 43, - Isogeny of degree 11 from Elliptic Curve defined by y^2 = x^3 + 42*x + 26 over Finite Field of size 43 to Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43) + (Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43 + to Elliptic Curve defined by y^2 = x^3 + 39*x over Finite Field of size 43, + Isogeny of degree 2 + from Elliptic Curve defined by y^2 = x^3 + 39*x over Finite Field of size 43 + to Elliptic Curve defined by y^2 = x^3 + 42*x + 26 over Finite Field of size 43, + Isogeny of degree 11 + from Elliptic Curve defined by y^2 = x^3 + 42*x + 26 over Finite Field of size 43 + to Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43) """ return self._phis @@ -501,30 +596,39 @@ def _composition_impl(left, right): TESTS:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite - sage: E = EllipticCurve([i+1, i, 0, -4, -6*i]) - sage: P,Q = E.lift_x(i-5), E.lift_x(-4*i) + sage: E = EllipticCurve([i + 1, i, 0, -4, -6*i]) + sage: P,Q = E.lift_x(i - 5), E.lift_x(-4*i) sage: phi = EllipticCurveHom_composite(E, P) sage: psi = phi.codomain().isogeny(phi(Q)) sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: iso1 = WeierstrassIsomorphism(E, (-1, 0, -i-1, 0)) + sage: iso1 = WeierstrassIsomorphism(E, (-1, 0, -i - 1, 0)) sage: iso2 = psi.codomain().isomorphism_to(E) sage: psi * phi # indirect doctest Composite morphism of degree 16 = 2^2*4: - From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) over Number Field in I with defining polynomial x^2 + 1 with I = 1*I - To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-3331/4)*x + (-142593/8*I) over Number Field in I with defining polynomial x^2 + 1 with I = 1*I + From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) + over Number Field in I with defining polynomial x^2 + 1 with I = 1*I + To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-3331/4)*x + (-142593/8*I) + over Number Field in I with defining polynomial x^2 + 1 with I = 1*I sage: iso2 * EllipticCurveHom_composite.from_factors([phi, psi]) # indirect doctest Composite morphism of degree 16 = 4^2: - From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) over Number Field in I with defining polynomial x^2 + 1 with I = 1*I - To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) over Number Field in I with defining polynomial x^2 + 1 with I = 1*I + From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) + over Number Field in I with defining polynomial x^2 + 1 with I = 1*I + To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) + over Number Field in I with defining polynomial x^2 + 1 with I = 1*I sage: phi * iso1 # indirect doctest Composite morphism of degree 4 = 2^2: - From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) over Number Field in I with defining polynomial x^2 + 1 with I = 1*I - To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (480*I-694)*x + (-7778*I+5556) over Number Field in I with defining polynomial x^2 + 1 with I = 1*I + From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) + over Number Field in I with defining polynomial x^2 + 1 with I = 1*I + To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (480*I-694)*x + (-7778*I+5556) + over Number Field in I with defining polynomial x^2 + 1 with I = 1*I sage: iso2 * psi * phi * iso1 # indirect doctest Composite morphism of degree 16 = 2^2*4: - From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) over Number Field in I with defining polynomial x^2 + 1 with I = 1*I - To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) over Number Field in I with defining polynomial x^2 + 1 with I = 1*I + From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) + over Number Field in I with defining polynomial x^2 + 1 with I = 1*I + To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) + over Number Field in I with defining polynomial x^2 + 1 with I = 1*I """ if isinstance(left, EllipticCurveHom_composite): if isinstance(right, WeierstrassIsomorphism) and hasattr(left.factors()[0], '_set_pre_isomorphism'): # XXX bit of a hack @@ -556,6 +660,7 @@ def _comparison_impl(left, right, op): TESTS:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite sage: E = EllipticCurve(QuadraticField(-3), [0,16]) sage: P,Q = E.lift_x(0), E.lift_x(-4) @@ -569,13 +674,14 @@ def _comparison_impl(left, right, op): :: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(431**2), [1,0]) sage: P,Q = E.gens() - sage: phi1 = EllipticCurveHom_composite(E, P) - sage: phi2 = EllipticCurveHom_composite(phi1.codomain(), phi1(Q)) - sage: psi1 = EllipticCurveHom_composite(E, Q) - sage: psi2 = EllipticCurveHom_composite(psi1.codomain(), psi1(P)) - sage: phi2 * phi1 == psi2 * psi1 + sage: phi1 = EllipticCurveHom_composite(E, P) # needs sage.rings.number_field + sage: phi2 = EllipticCurveHom_composite(phi1.codomain(), phi1(Q)) # needs sage.rings.number_field + sage: psi1 = EllipticCurveHom_composite(E, Q) # needs sage.rings.number_field + sage: psi2 = EllipticCurveHom_composite(psi1.codomain(), psi1(P)) # needs sage.rings.number_field + sage: phi2 * phi1 == psi2 * psi1 # needs sage.rings.number_field True """ if op != op_EQ: @@ -592,27 +698,37 @@ def rational_maps(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite sage: E = EllipticCurve(GF(65537), [1,2,3,4,5]) sage: P = E.lift_x(7321) sage: phi = EllipticCurveHom_composite(E, P) sage: phi.rational_maps() - ((x^9 + 27463*x^8 + 21204*x^7 - 5750*x^6 + 1610*x^5 + 14440*x^4 + 26605*x^3 - 15569*x^2 - 3341*x + 1267)/(x^8 + 27463*x^7 + 26871*x^6 + 5999*x^5 - 20194*x^4 - 6310*x^3 + 24366*x^2 - 20905*x - 13867), - (x^12*y + 8426*x^11*y + 5667*x^11 + 27612*x^10*y + 26124*x^10 + 9688*x^9*y - 22715*x^9 + 19864*x^8*y + 498*x^8 + 22466*x^7*y - 14036*x^7 + 8070*x^6*y + 19955*x^6 - 20765*x^5*y - 12481*x^5 + 12672*x^4*y + 24142*x^4 - 23695*x^3*y + 26667*x^3 + 23780*x^2*y + 17864*x^2 + 15053*x*y - 30118*x + 17539*y - 23609)/(x^12 + 8426*x^11 + 21945*x^10 - 22587*x^9 + 22094*x^8 + 14603*x^7 - 26255*x^6 + 11171*x^5 - 16508*x^4 - 14435*x^3 - 2170*x^2 + 29081*x - 19009)) + ((x^9 + 27463*x^8 + 21204*x^7 - 5750*x^6 + 1610*x^5 + 14440*x^4 + + 26605*x^3 - 15569*x^2 - 3341*x + 1267)/(x^8 + 27463*x^7 + 26871*x^6 + + 5999*x^5 - 20194*x^4 - 6310*x^3 + 24366*x^2 - 20905*x - 13867), + (x^12*y + 8426*x^11*y + 5667*x^11 + 27612*x^10*y + 26124*x^10 + 9688*x^9*y + - 22715*x^9 + 19864*x^8*y + 498*x^8 + 22466*x^7*y - 14036*x^7 + 8070*x^6*y + + 19955*x^6 - 20765*x^5*y - 12481*x^5 + 12672*x^4*y + 24142*x^4 - 23695*x^3*y + + 26667*x^3 + 23780*x^2*y + 17864*x^2 + 15053*x*y - 30118*x + 17539*y + - 23609)/(x^12 + 8426*x^11 + 21945*x^10 - 22587*x^9 + 22094*x^8 + 14603*x^7 + - 26255*x^6 + 11171*x^5 - 16508*x^4 - 14435*x^3 - 2170*x^2 + 29081*x - 19009)) TESTS:: - sage: f = phi.codomain().defining_polynomial() - sage: g = E.defining_polynomial().subs({2:1}) - sage: f(*phi.rational_maps(), 1) % g + sage: f = phi.codomain().defining_polynomial() # needs sage.rings.finite_rings + sage: g = E.defining_polynomial().subs({2:1}) # needs sage.rings.finite_rings + sage: f(*phi.rational_maps(), 1) % g # needs sage.rings.finite_rings 0 :: - sage: phi.rational_maps()[0].parent() - Fraction Field of Multivariate Polynomial Ring in x, y over Finite Field of size 65537 - sage: phi.rational_maps()[1].parent() - Fraction Field of Multivariate Polynomial Ring in x, y over Finite Field of size 65537 + sage: phi.rational_maps()[0].parent() # needs sage.rings.finite_rings + Fraction Field of + Multivariate Polynomial Ring in x, y over Finite Field of size 65537 + sage: phi.rational_maps()[1].parent() # needs sage.rings.finite_rings + Fraction Field of + Multivariate Polynomial Ring in x, y over Finite Field of size 65537 """ fx, fy = self._phis[-1].rational_maps() for phi in self._phis[:-1][::-1]: @@ -626,6 +742,7 @@ def x_rational_map(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite sage: E = EllipticCurve(GF(65537), [1,2,3,4,5]) sage: P = E.lift_x(7321) @@ -635,8 +752,9 @@ def x_rational_map(self): TESTS:: - sage: phi.x_rational_map().parent() - Fraction Field of Univariate Polynomial Ring in x over Finite Field of size 65537 + sage: phi.x_rational_map().parent() # needs sage.rings.finite_rings + Fraction Field of Univariate Polynomial Ring in x + over Finite Field of size 65537 """ fx = self._phis[-1].x_rational_map() for phi in self._phis[:-1][::-1]: @@ -649,13 +767,16 @@ def kernel_polynomial(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite sage: E = EllipticCurve(GF(65537), [1,2,3,4,5]) sage: P = E.lift_x(7321) sage: phi = EllipticCurveHom_composite(E, P); phi Composite morphism of degree 9 = 3^2: - From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 65537 - To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518 over Finite Field of size 65537 + From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 + over Finite Field of size 65537 + To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518 + over Finite Field of size 65537 sage: phi.kernel_polynomial() x^4 + 46500*x^3 + 19556*x^2 + 7643*x + 15952 """ @@ -669,17 +790,22 @@ def dual(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite sage: E = EllipticCurve(GF(65537), [1,2,3,4,5]) sage: P = E.lift_x(7321) sage: phi = EllipticCurveHom_composite(E, P); phi Composite morphism of degree 9 = 3^2: - From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 65537 - To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518 over Finite Field of size 65537 + From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 + over Finite Field of size 65537 + To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518 + over Finite Field of size 65537 sage: psi = phi.dual(); psi Composite morphism of degree 9 = 3^2: - From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518 over Finite Field of size 65537 - To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 65537 + From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518 + over Finite Field of size 65537 + To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 + over Finite Field of size 65537 sage: psi * phi == phi.domain().scalar_multiplication(phi.degree()) True sage: phi * psi == psi.domain().scalar_multiplication(psi.degree()) @@ -697,13 +823,16 @@ def is_separable(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite sage: E = EllipticCurve(GF(7^2), [3,2]) sage: P = E.lift_x(1) sage: phi = EllipticCurveHom_composite(E, P); phi Composite morphism of degree 7 = 7: - From: Elliptic Curve defined by y^2 = x^3 + 3*x + 2 over Finite Field in z2 of size 7^2 - To: Elliptic Curve defined by y^2 = x^3 + 3*x + 2 over Finite Field in z2 of size 7^2 + From: Elliptic Curve defined by y^2 = x^3 + 3*x + 2 + over Finite Field in z2 of size 7^2 + To: Elliptic Curve defined by y^2 = x^3 + 3*x + 2 + over Finite Field in z2 of size 7^2 sage: phi.is_separable() True """ @@ -717,14 +846,19 @@ def formal(self, prec=20): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite sage: E = EllipticCurve(GF(65537), [1,2,3,4,5]) sage: P = E.lift_x(7321) sage: phi = EllipticCurveHom_composite(E, P) sage: phi.formal() - t + 54203*t^5 + 48536*t^6 + 40698*t^7 + 37808*t^8 + 21111*t^9 + 42381*t^10 + 46688*t^11 + 657*t^12 + 38916*t^13 + 62261*t^14 + 59707*t^15 + 30767*t^16 + 7248*t^17 + 60287*t^18 + 50451*t^19 + 38305*t^20 + 12312*t^21 + 31329*t^22 + O(t^23) + t + 54203*t^5 + 48536*t^6 + 40698*t^7 + 37808*t^8 + 21111*t^9 + 42381*t^10 + + 46688*t^11 + 657*t^12 + 38916*t^13 + 62261*t^14 + 59707*t^15 + + 30767*t^16 + 7248*t^17 + 60287*t^18 + 50451*t^19 + 38305*t^20 + + 12312*t^21 + 31329*t^22 + O(t^23) sage: (phi.dual() * phi).formal(prec=5) - 9*t + 65501*t^2 + 65141*t^3 + 59183*t^4 + 21491*t^5 + 8957*t^6 + 999*t^7 + O(t^8) + 9*t + 65501*t^2 + 65141*t^3 + 59183*t^4 + 21491*t^5 + 8957*t^6 + + 999*t^7 + O(t^8) """ res = self._phis[-1].formal(prec=prec) for phi in self._phis[:-1][::-1]: @@ -744,6 +878,7 @@ def scaling_factor(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: E = EllipticCurve(GF(65537), [1,2,3,4,5]) @@ -751,7 +886,10 @@ def scaling_factor(self): sage: phi = EllipticCurveHom_composite(E, P) sage: phi = WeierstrassIsomorphism(phi.codomain(), [7,8,9,10]) * phi sage: phi.formal() - 7*t + 65474*t^2 + 511*t^3 + 61316*t^4 + 20548*t^5 + 45511*t^6 + 37285*t^7 + 48414*t^8 + 9022*t^9 + 24025*t^10 + 35986*t^11 + 55397*t^12 + 25199*t^13 + 18744*t^14 + 46142*t^15 + 9078*t^16 + 18030*t^17 + 47599*t^18 + 12158*t^19 + 50630*t^20 + 56449*t^21 + 43320*t^22 + O(t^23) + 7*t + 65474*t^2 + 511*t^3 + 61316*t^4 + 20548*t^5 + 45511*t^6 + 37285*t^7 + + 48414*t^8 + 9022*t^9 + 24025*t^10 + 35986*t^11 + 55397*t^12 + 25199*t^13 + + 18744*t^14 + 46142*t^15 + 9078*t^16 + 18030*t^17 + 47599*t^18 + + 12158*t^19 + 50630*t^20 + 56449*t^21 + 43320*t^22 + O(t^23) sage: phi.scaling_factor() 7 @@ -779,26 +917,11 @@ def is_injective(self): sage: nu = EllipticCurveHom_composite.from_factors(E.automorphisms()) sage: nu Composite morphism of degree 1 = 1^12: - From: Elliptic Curve defined by y^2 = x^3 + x over Algebraic closure of Finite Field of size 3 - To: Elliptic Curve defined by y^2 = x^3 + x over Algebraic closure of Finite Field of size 3 + From: Elliptic Curve defined by y^2 = x^3 + x + over Algebraic closure of Finite Field of size 3 + To: Elliptic Curve defined by y^2 = x^3 + x + over Algebraic closure of Finite Field of size 3 sage: nu.is_injective() True """ return all(phi.is_injective() for phi in self._phis) - - @staticmethod - def make_default(): - r""" - This method does nothing and will be removed. - - (It is a leftover from the time when :class:`EllipticCurveHom_composite` - wasn't the default yet.) - - EXAMPLES:: - - sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite - sage: EllipticCurveHom_composite.make_default() - doctest:warning ... - """ - from sage.misc.superseded import deprecation - deprecation(34410, 'calling EllipticCurveHom_composite.make_default() is no longer necessary') diff --git a/src/sage/schemes/elliptic_curves/hom_frobenius.py b/src/sage/schemes/elliptic_curves/hom_frobenius.py index 430f8a3f417..fb4496aedbb 100644 --- a/src/sage/schemes/elliptic_curves/hom_frobenius.py +++ b/src/sage/schemes/elliptic_curves/hom_frobenius.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Frobenius isogenies of elliptic curves @@ -17,18 +18,22 @@ sage: E = EllipticCurve([z5,1]) sage: pi = EllipticCurveHom_frobenius(E); pi Frobenius isogeny of degree 17: - From: Elliptic Curve defined by y^2 = x^3 + z5*x + 1 over Finite Field in z5 of size 17^5 - To: Elliptic Curve defined by y^2 = x^3 + (9*z5^4+7*z5^3+10*z5^2+z5+14)*x + 1 over Finite Field in z5 of size 17^5 + From: Elliptic Curve defined by y^2 = x^3 + z5*x + 1 + over Finite Field in z5 of size 17^5 + To: Elliptic Curve defined by y^2 = x^3 + (9*z5^4+7*z5^3+10*z5^2+z5+14)*x + 1 + over Finite Field in z5 of size 17^5 By passing `n`, we can also construct higher-power Frobenius maps, such as the Frobenius *endo*\morphism:: sage: z5, = GF(7^5).gens() sage: E = EllipticCurve([z5,1]) - sage: pi = EllipticCurveHom_frobenius(E,5); pi + sage: pi = EllipticCurveHom_frobenius(E, 5); pi Frobenius endomorphism of degree 16807 = 7^5: - From: Elliptic Curve defined by y^2 = x^3 + z5*x + 1 over Finite Field in z5 of size 7^5 - To: Elliptic Curve defined by y^2 = x^3 + z5*x + 1 over Finite Field in z5 of size 7^5 + From: Elliptic Curve defined by y^2 = x^3 + z5*x + 1 + over Finite Field in z5 of size 7^5 + To: Elliptic Curve defined by y^2 = x^3 + z5*x + 1 + over Finite Field in z5 of size 7^5 The usual :class:`EllipticCurveHom` methods are supported:: @@ -55,7 +60,11 @@ sage: E = EllipticCurve([GF(17^6).gen(), 0]) sage: pi = EllipticCurveHom_frobenius(E) sage: pihat = pi.dual(); pihat - Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + (15*z6^5+5*z6^4+8*z6^3+12*z6^2+11*z6+7)*x over Finite Field in z6 of size 17^6 to Elliptic Curve defined by y^2 = x^3 + z6*x over Finite Field in z6 of size 17^6 + Isogeny of degree 17 + from Elliptic Curve defined by y^2 = x^3 + (15*z6^5+5*z6^4+8*z6^3+12*z6^2+11*z6+7)*x + over Finite Field in z6 of size 17^6 + to Elliptic Curve defined by y^2 = x^3 + z6*x + over Finite Field in z6 of size 17^6 sage: pihat.is_separable() True sage: pihat * pi == EllipticCurveHom_scalar(E,17) # known bug -- #6413 @@ -69,18 +78,25 @@ sage: pi1 = EllipticCurveHom_frobenius(E) sage: pi1hat = pi1.dual(); pi1hat Composite morphism of degree 17 = 17*1: - From: Elliptic Curve defined by y^2 = x^3 + (15*z6^5+5*z6^4+8*z6^3+12*z6^2+11*z6+7) over Finite Field in z6 of size 17^6 - To: Elliptic Curve defined by y^2 = x^3 + z6 over Finite Field in z6 of size 17^6 + From: Elliptic Curve defined by y^2 = x^3 + (15*z6^5+5*z6^4+8*z6^3+12*z6^2+11*z6+7) + over Finite Field in z6 of size 17^6 + To: Elliptic Curve defined by y^2 = x^3 + z6 + over Finite Field in z6 of size 17^6 sage: pi6 = EllipticCurveHom_frobenius(E,6) sage: pi6hat = pi6.dual(); pi6hat Composite morphism of degree 24137569 = 24137569*1: - From: Elliptic Curve defined by y^2 = x^3 + z6 over Finite Field in z6 of size 17^6 - To: Elliptic Curve defined by y^2 = x^3 + z6 over Finite Field in z6 of size 17^6 + From: Elliptic Curve defined by y^2 = x^3 + z6 + over Finite Field in z6 of size 17^6 + To: Elliptic Curve defined by y^2 = x^3 + z6 + over Finite Field in z6 of size 17^6 sage: pi6hat.factors() (Frobenius endomorphism of degree 24137569 = 17^6: - From: Elliptic Curve defined by y^2 = x^3 + z6 over Finite Field in z6 of size 17^6 - To: Elliptic Curve defined by y^2 = x^3 + z6 over Finite Field in z6 of size 17^6, - Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + z6 over Finite Field in z6 of size 17^6 + From: Elliptic Curve defined by y^2 = x^3 + z6 + over Finite Field in z6 of size 17^6 + To: Elliptic Curve defined by y^2 = x^3 + z6 + over Finite Field in z6 of size 17^6, + Elliptic-curve endomorphism of + Elliptic Curve defined by y^2 = x^3 + z6 over Finite Field in z6 of size 17^6 Via: (u,r,s,t) = (2*z6^5 + 10*z6^3 + z6^2 + 8, 0, 0, 0)) @@ -253,10 +269,14 @@ def _eval(self, P): sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius sage: E = EllipticCurve(GF(11), [1,1]) sage: pi = EllipticCurveHom_frobenius(E) - sage: P = E.change_ring(GF(11^6)).lift_x(GF(11^3).gen()); P - (6*z6^5 + 8*z6^4 + 8*z6^3 + 6*z6^2 + 10*z6 + 5 : 2*z6^5 + 2*z6^4 + 2*z6^3 + 4*z6 + 6 : 1) - sage: pi._eval(P) - (z6^5 + 3*z6^4 + 3*z6^3 + 6*z6^2 + 9 : z6^5 + 10*z6^4 + 10*z6^3 + 5*z6^2 + 4*z6 + 8 : 1) + sage: Ebar = E.change_ring(GF(11^6)) + sage: z6 = GF(11^6).gen() + sage: P = Ebar.lift_x(GF(11^3).gen()) + sage: p = Ebar(6*z6^5 + 8*z6^4 + 8*z6^3 + 6*z6^2 + 10*z6 + 5, 2*z6^5 + 2*z6^4 + 2*z6^3 + 4*z6 + 6, 1) + sage: Q = pi._eval(P) + sage: q = Ebar(z6^5 + 3*z6^4 + 3*z6^3 + 6*z6^2 + 9, z6^5 + 10*z6^4 + 10*z6^3 + 5*z6^2 + 4*z6 + 8, 1) + sage: (P == p and Q == q) or (P == -p and Q == -q) + True """ if self._domain.defining_polynomial()(*P): raise ValueError(f'{P} not on {self._domain}') diff --git a/src/sage/schemes/elliptic_curves/hom_scalar.py b/src/sage/schemes/elliptic_curves/hom_scalar.py index e18e514bb35..66e675250f9 100644 --- a/src/sage/schemes/elliptic_curves/hom_scalar.py +++ b/src/sage/schemes/elliptic_curves/hom_scalar.py @@ -207,7 +207,6 @@ def _eval(self, P): raise ValueError(f'{P} not on {self._domain}') return self._m * P - def _repr_(self): """ Return basic facts about this scalar multiplication as a string. @@ -220,7 +219,6 @@ def _repr_(self): """ return f'Scalar-multiplication endomorphism [{self._m}] of {self._domain}' - # EllipticCurveHom methods @staticmethod diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 22ae56018a3..4bc84d944f8 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -1,7 +1,8 @@ r""" -โˆšรฉlu algorithm for elliptic-curve isogenies +Squareโ€‘root Vรฉlu algorithm for elliptic-curve isogenies -The โˆšรฉlu algorithm computes isogenies of elliptic curves in time `\tilde +The square-root Vรฉlu algorithm, also called the โˆšรฉlu algorithm, +computes isogenies of elliptic curves in time `\tilde O(\sqrt\ell)` rather than naรฏvely `O(\ell)`, where `\ell` is the degree. The core idea is to reindex the points in the kernel subgroup in a @@ -26,7 +27,7 @@ 10009 sage: phi = EllipticCurveHom_velusqrt(E, K) sage: phi - Elliptic-curve isogeny (using โˆšรฉlu) of degree 10009: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 10009: From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 6666679 To: Elliptic Curve defined by y^2 = x^3 + 227975*x + 3596133 over Finite Field of size 6666679 sage: phi.codomain() @@ -56,7 +57,7 @@ sage: K = E(9091, 517864) sage: phi = EllipticCurveHom_velusqrt(E, K, model='montgomery') sage: phi - Elliptic-curve isogeny (using โˆšรฉlu) of degree 2999: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 2999: From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 6666679 To: Elliptic Curve defined by y^2 = x^3 + 1559358*x^2 + x over Finite Field of size 6666679 @@ -68,7 +69,7 @@ sage: K.order() 37 sage: EllipticCurveHom_velusqrt(E, K) - Elliptic-curve isogeny (using โˆšรฉlu) of degree 37: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 37: From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 101 To: Elliptic Curve defined by y^2 = x^3 + 66*x + 86 over Finite Field of size 101 @@ -88,7 +89,7 @@ Furthermore, the implementation is restricted to finite fields, since this appears to be the most relevant application for the -โˆšรฉlu algorithm:: +square-root Vรฉlu algorithm:: sage: E = EllipticCurve('26b1') sage: P = E(1,0) @@ -122,21 +123,17 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.sequence import Sequence -from sage.structure.all import coercion_model as cm - from sage.misc.cachefunc import cached_method - from sage.misc.misc_c import prod from sage.rings.generic import ProductTree, prod_with_derivative - -from sage.structure.richcmp import op_EQ - from sage.rings.integer import Integer +from sage.structure.all import coercion_model as cm +from sage.structure.richcmp import op_EQ +from sage.structure.sequence import Sequence -from sage.schemes.elliptic_curves.constructor import EllipticCurve -from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_finite_field -from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation +from .constructor import EllipticCurve +from .ell_finite_field import EllipticCurve_finite_field +from .hom import EllipticCurveHom, compare_via_evaluation def _choose_IJK(n): @@ -459,7 +456,7 @@ def _hI_resultant(self, poly, rems=None): if rems is None: rems = self.hItree.remainders(poly) r = prod(rems) - s = -1 if len(self.hItree)%2 == 1 == poly.degree() else 1 + s = -1 if len(self.hItree) % 2 == 1 == poly.degree() else 1 assert r.is_constant() return s * r[0] @@ -515,7 +512,7 @@ def _point_outside_subgroup(P): ... ValueError: ECDLog problem has no solution (...) - An example where the group is non-cyclic: + An example where the group is non-cyclic:: sage: E.<P,_> = EllipticCurve(GF(71^2), [0,1]) sage: E.abelian_group() @@ -538,7 +535,7 @@ def _point_outside_subgroup(P): Frobenius). Thus, once `\pi-1` can be represented in Sage, we may just return that in :meth:`~sage.schemes.elliptic_curves.ell_field.EllipticCurve_field.isogeny` - rather than insisting on using โˆšรฉlu. + rather than insisting on using square-root Vรฉlu. """ E = P.curve() n = P.order() @@ -559,7 +556,7 @@ def _point_outside_subgroup(P): class EllipticCurveHom_velusqrt(EllipticCurveHom): r""" This class implements separable odd-degree isogenies of elliptic - curves over finite fields using the โˆšรฉlu algorithm. + curves over finite fields using the square-root Vรฉlu algorithm. The complexity is `\tilde O(\sqrt{\ell})` base-field operations, where `\ell` is the degree. @@ -582,7 +579,7 @@ class EllipticCurveHom_velusqrt(EllipticCurveHom): sage: E = EllipticCurve(F, [t,t]) sage: K = E(2154*t^2 + 5711*t + 2899, 7340*t^2 + 4653*t + 6935) sage: phi = EllipticCurveHom_velusqrt(E, K); phi - Elliptic-curve isogeny (using โˆšรฉlu) of degree 601: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 601: From: Elliptic Curve defined by y^2 = x^3 + t*x + t over Finite Field in t of size 10009^3 To: Elliptic Curve defined by y^2 = x^3 + (263*t^2+3173*t+4759)*x + (3898*t^2+6111*t+9443) over Finite Field in t of size 10009^3 sage: phi(K) @@ -648,7 +645,7 @@ class EllipticCurveHom_velusqrt(EllipticCurveHom): """ def __init__(self, E, P, *, codomain=None, model=None, Q=None): r""" - Initialize this โˆšรฉlu isogeny from a kernel point of odd order. + Initialize this square-root Vรฉlu isogeny from a kernel point of odd order. EXAMPLES:: @@ -656,7 +653,7 @@ def __init__(self, E, P, *, codomain=None, model=None, Q=None): sage: E = EllipticCurve(GF(71), [5,5]) sage: P = E(-2, 22) sage: EllipticCurveHom_velusqrt(E, P) - Elliptic-curve isogeny (using โˆšรฉlu) of degree 19: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 19: From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 71 To: Elliptic Curve defined by y^2 = x^3 + 13*x + 11 over Finite Field of size 71 @@ -665,16 +662,16 @@ def __init__(self, E, P, *, codomain=None, model=None, Q=None): sage: E.<P> = EllipticCurve(GF(419), [1,0]) sage: K = 4*P sage: EllipticCurveHom_velusqrt(E, K) - Elliptic-curve isogeny (using โˆšรฉlu) of degree 105: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 105: From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 419 To: Elliptic Curve defined by y^2 = x^3 + 301*x + 86 over Finite Field of size 419 sage: E2 = EllipticCurve(GF(419), [0,6,0,385,42]) sage: EllipticCurveHom_velusqrt(E, K, codomain=E2) - Elliptic-curve isogeny (using โˆšรฉlu) of degree 105: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 105: From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 419 To: Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 385*x + 42 over Finite Field of size 419 sage: EllipticCurveHom_velusqrt(E, K, model="montgomery") - Elliptic-curve isogeny (using โˆšรฉlu) of degree 105: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 105: From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 419 To: Elliptic Curve defined by y^2 = x^3 + 6*x^2 + x over Finite Field of size 419 @@ -743,9 +740,10 @@ def __init__(self, E, P, *, codomain=None, model=None, Q=None): def _raw_eval(self, x, y=None): r""" - Evaluate the "inner" โˆšรฉlu isogeny (i.e., without applying - pre- and post-isomorphism) at either just an `x`-coordinate - or a pair `(x,y)` of coordinates. + Evaluate the "inner" square-root Vรฉlu isogeny + (i.e., without applying pre- and post-isomorphism) + at either just an `x`-coordinate or a pair + `(x,y)` of coordinates. If the given point lies in the kernel, the empty tuple ``()`` is returned. @@ -816,7 +814,8 @@ def _raw_eval(self, x, y=None): def _compute_codomain(self, model=None): r""" - Helper method to compute the codomain of this โˆšรฉlu isogeny + Helper method to compute the codomain of this + square-root Vรฉlu isogeny once the data for :meth:`_raw_eval` has been initialized. Called by the constructor. @@ -843,7 +842,7 @@ def _compute_codomain(self, model=None): sage: phi._compute_codomain('montgomery') sage: phi - Elliptic-curve isogeny (using โˆšรฉlu) of degree 19: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 19: From: Elliptic Curve defined by y^2 = x^3 + 5*x^2 + x over Finite Field of size 71 To: Elliptic Curve defined by y^2 = x^3 + 40*x^2 + x over Finite Field of size 71 @@ -853,7 +852,7 @@ def _compute_codomain(self, model=None): sage: E = EllipticCurve([3*t, 2*t+4, 3*t+2, t+4, 3*t]) sage: K = E(3*t, 2) sage: EllipticCurveHom_velusqrt(E, K) # indirect doctest - Elliptic-curve isogeny (using โˆšรฉlu) of degree 19: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 19: From: Elliptic Curve defined by y^2 + 3*t*x*y + (3*t+2)*y = x^3 + (2*t+4)*x^2 + (t+4)*x + 3*t over Finite Field in t of size 5^2 To: Elliptic Curve defined by y^2 = x^3 + (4*t+3)*x + 2 over Finite Field in t of size 5^2 """ @@ -887,7 +886,7 @@ def _compute_codomain(self, model=None): def _eval(self, P): r""" - Evaluate this โˆšรฉlu isogeny at a point. + Evaluate this square-root Vรฉlu isogeny at a point. INPUT: @@ -900,7 +899,7 @@ def _eval(self, P): sage: K = E(4, 19) sage: phi = EllipticCurveHom_velusqrt(E, K, model='montgomery') sage: phi - Elliptic-curve isogeny (using โˆšรฉlu) of degree 19: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 19: From: Elliptic Curve defined by y^2 = x^3 + 5*x^2 + x over Finite Field of size 71 To: Elliptic Curve defined by y^2 = x^3 + 40*x^2 + x over Finite Field of size 71 sage: phi(K) @@ -959,7 +958,7 @@ def _eval(self, P): def _repr_(self): r""" - Return basic information about this โˆšรฉlu isogeny as a string. + Return basic information about this square-root Vรฉlu isogeny as a string. EXAMPLES:: @@ -967,18 +966,18 @@ def _repr_(self): sage: E.<P> = EllipticCurve(GF(71), [5,5]) sage: phi = EllipticCurveHom_velusqrt(E, P) sage: phi # indirect doctest - Elliptic-curve isogeny (using โˆšรฉlu) of degree 57: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 57: From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 71 To: Elliptic Curve defined by y^2 = x^3 + 19*x + 45 over Finite Field of size 71 """ - return f'Elliptic-curve isogeny (using โˆšรฉlu) of degree {self._degree}:' \ + return f'Elliptic-curve isogeny (using square-root Vรฉlu) of degree {self._degree}:' \ f'\n From: {self._domain}' \ f'\n To: {self._codomain}' @staticmethod def _comparison_impl(left, right, op): r""" - Compare a โˆšรฉlu isogeny to another elliptic-curve morphism. + Compare a square-root Vรฉlu isogeny to another elliptic-curve morphism. Called by :meth:`EllipticCurveHom._richcmp_`. @@ -995,11 +994,11 @@ def _comparison_impl(left, right, op): sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt sage: E = EllipticCurve(GF(101), [5,5,5,5,5]) sage: phi = EllipticCurveHom_velusqrt(E, E.lift_x(11)); phi - Elliptic-curve isogeny (using โˆšรฉlu) of degree 59: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 59: From: Elliptic Curve defined by y^2 + 5*x*y + 5*y = x^3 + 5*x^2 + 5*x + 5 over Finite Field of size 101 To: Elliptic Curve defined by y^2 = x^3 + 15*x + 25 over Finite Field of size 101 sage: psi = EllipticCurveHom_velusqrt(E, E.lift_x(-1)); psi - Elliptic-curve isogeny (using โˆšรฉlu) of degree 59: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 59: From: Elliptic Curve defined by y^2 + 5*x*y + 5*y = x^3 + 5*x^2 + 5*x + 5 over Finite Field of size 101 To: Elliptic Curve defined by y^2 = x^3 + 15*x + 25 over Finite Field of size 101 sage: phi == psi @@ -1012,7 +1011,7 @@ def _comparison_impl(left, right, op): @cached_method def kernel_polynomial(self): r""" - Return the kernel polynomial of this โˆšรฉlu isogeny. + Return the kernel polynomial of this square-root Vรฉlu isogeny. .. NOTE:: @@ -1043,19 +1042,20 @@ def kernel_polynomial(self): @cached_method def dual(self): r""" - Return the dual of this โˆšรฉlu isogeny as an :class:`EllipticCurveHom`. + Return the dual of this square-root Vรฉlu + isogeny as an :class:`EllipticCurveHom`. .. NOTE:: The dual is computed by :class:`EllipticCurveIsogeny`, - hence it does not benefit from the โˆšรฉlu speedup. + hence it does not benefit from the square-root Vรฉlu speedup. EXAMPLES:: sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1]) sage: K = E.cardinality() // 11 * E.gens()[0] sage: phi = E.isogeny(K, algorithm='velusqrt'); phi - Elliptic-curve isogeny (using โˆšรฉlu) of degree 11: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 11: From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2 To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2 sage: phi.dual() @@ -1076,7 +1076,7 @@ def dual(self): @cached_method def rational_maps(self): r""" - Return the pair of explicit rational maps of this โˆšรฉlu isogeny + Return the pair of explicit rational maps of this square-root Vรฉlu isogeny as fractions of bivariate polynomials in `x` and `y`. .. NOTE:: @@ -1088,7 +1088,7 @@ def rational_maps(self): sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1]) sage: K = (E.cardinality() // 11) * E.gens()[0] sage: phi = E.isogeny(K, algorithm='velusqrt'); phi - Elliptic-curve isogeny (using โˆšรฉlu) of degree 11: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 11: From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2 To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2 sage: phi.rational_maps() @@ -1113,7 +1113,8 @@ def rational_maps(self): @cached_method def x_rational_map(self): r""" - Return the `x`-coordinate rational map of this โˆšรฉlu isogeny + Return the `x`-coordinate rational map of + this square-root Vรฉlu isogeny as a univariate rational function in `x`. .. NOTE:: @@ -1125,7 +1126,7 @@ def x_rational_map(self): sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1]) sage: K = (E.cardinality() // 11) * E.gens()[0] sage: phi = E.isogeny(K, algorithm='velusqrt'); phi - Elliptic-curve isogeny (using โˆšรฉlu) of degree 11: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 11: From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2 To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2 sage: phi.x_rational_map() @@ -1149,7 +1150,7 @@ def x_rational_map(self): def scaling_factor(self): r""" Return the Weierstrass scaling factor associated to this - โˆšรฉlu isogeny. + square-root Vรฉlu isogeny. The scaling factor is the constant `u` (in the base field) such that `\varphi^* \omega_2 = u \omega_1`, where @@ -1162,7 +1163,7 @@ def scaling_factor(self): sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1]) sage: K = (E.cardinality() // 11) * E.gens()[0] sage: phi = E.isogeny(K, algorithm='velusqrt', model='montgomery'); phi - Elliptic-curve isogeny (using โˆšรฉlu) of degree 11: + Elliptic-curve isogeny (using square-root Vรฉlu) of degree 11: From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2 To: Elliptic Curve defined by y^2 = x^3 + 61*x^2 + x over Finite Field in z2 of size 101^2 sage: phi.scaling_factor() @@ -1191,7 +1192,7 @@ def is_separable(self): def _random_example_for_testing(): r""" - Function to generate somewhat random valid โˆšรฉlu inputs + Function to generate somewhat random valid Vรฉlu inputs for testing purposes. EXAMPLES:: @@ -1213,7 +1214,12 @@ def _random_example_for_testing(): sage: 5 <= K.order() True """ - from sage.all import prime_range, choice, randrange, GF, lcm, Mod + from sage.rings.fast_arith import prime_range + from sage.misc.prandom import choice, randrange + from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + from sage.arith.functions import lcm + from sage.rings.finite_rings.integer_mod import Mod + while True: p = choice(prime_range(2, 100)) e = randrange(1,5) diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py index e635c77a458..84404c28b76 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_class.py +++ b/src/sage/schemes/elliptic_curves/isogeny_class.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.rings.number_field r""" Isogeny class of elliptic curves over number fields @@ -227,9 +227,9 @@ def _repr_(self): Elliptic Curve defined by y^2 + (i+1)*x*y + (i+1)*y = x^3 + i*x^2 + (-i+33)*x + (-58*i) over Number Field in i with defining polynomial x^2 + 1 with i = 1*I] """ if self._label: - return "Elliptic curve isogeny class %s"%(self._label) + return "Elliptic curve isogeny class %s" % (self._label) else: - return "Isogeny class of %r"%(self.E) + return "Isogeny class of %r" % (self.E) def __contains__(self, x): """ @@ -322,7 +322,7 @@ class (CM case only). sage: pol = PolynomialRing(QQ,'x')([1,0,3,0,1]) sage: K.<c> = NumberField(pol) - sage: j = 1480640+565760*c^2 + sage: j = 1480640 + 565760*c^2 sage: E = EllipticCurve(j=j) sage: C = E.isogeny_class() sage: C.qf_matrix() @@ -362,7 +362,9 @@ def isogenies(self, fill=False): sage: isocls = EllipticCurve('15a3').isogeny_class() sage: f = isocls.isogenies()[0][1]; f - Isogeny of degree 2 from Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field + Isogeny of degree 2 + from Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field sage: f.domain() == isocls.curves[0] and f.codomain() == isocls.curves[1] True """ @@ -398,7 +400,9 @@ def graph(self): sage: isocls = EllipticCurve('15a3').isogeny_class() sage: G = isocls.graph() sage: sorted(G._pos.items()) - [(1, [-0.8660254, 0.5]), (2, [-0.8660254, 1.5]), (3, [-1.7320508, 0]), (4, [0, 0]), (5, [0, -1]), (6, [0.8660254, 0.5]), (7, [0.8660254, 1.5]), (8, [1.7320508, 0])] + [(1, [-0.8660254, 0.5]), (2, [-0.8660254, 1.5]), (3, [-1.7320508, 0]), + (4, [0, 0]), (5, [0, -1]), (6, [0.8660254, 0.5]), + (7, [0.8660254, 1.5]), (8, [1.7320508, 0])] """ from sage.graphs.graph import Graph @@ -591,10 +595,10 @@ def __init__(self, E, reducible_primes=None, algorithm='Billerey', minimal_model the isogeny class, only composites isogenies of these degrees will be used. - - ``algorithm`` (string, default 'Billerey') -- the algorithm + - ``algorithm`` (string, default ``'Billerey'``) -- the algorithm to use to compute the reducible primes. Ignored for CM curves or if ``reducible_primes`` is provided. Values are - 'Billerey' (default), 'Larson', and 'heuristic'. + ``'Billerey'`` (default), ``'Larson'``, and ``'heuristic'``. - ``minimal_models`` (bool, default ``True``) -- if ``True``, all curves in the class will be minimal or semi-minimal @@ -606,15 +610,16 @@ def __init__(self, E, reducible_primes=None, algorithm='Billerey', minimal_model sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve(K, [0,0,0,0,1]) sage: C = E.isogeny_class(); C - Isogeny class of Elliptic Curve defined by y^2 = x^3 + 1 over Number Field in i with defining polynomial x^2 + 1 with i = 1*I + Isogeny class of Elliptic Curve defined by y^2 = x^3 + 1 + over Number Field in i with defining polynomial x^2 + 1 with i = 1*I The curves in the class (sorted):: sage: [E1.ainvs() for E1 in C] [(0, 0, 0, 0, -27), - (0, 0, 0, 0, 1), - (i + 1, i, i + 1, -i + 3, 4*i), - (i + 1, i, i + 1, -i + 33, -58*i)] + (0, 0, 0, 0, 1), + (i + 1, i, i + 1, -i + 3, 4*i), + (i + 1, i, i + 1, -i + 33, -58*i)] The matrix of degrees of cyclic isogenies between curves:: @@ -632,16 +637,18 @@ class :class:`EllipticCurveIsogeny` allowed composition. In to 3, and `3`-isogenies to go from 0 to 1 and from 2 to 3:: sage: isogs = C.isogenies() - sage: [((i,j),isogs[i][j].degree()) for i in range(4) for j in range(4) if isogs[i][j]!=0] + sage: [((i,j), isogs[i][j].degree()) + ....: for i in range(4) for j in range(4) if isogs[i][j] != 0] [((0, 1), 3), - ((0, 3), 2), - ((1, 0), 3), - ((1, 2), 2), - ((2, 1), 2), - ((2, 3), 3), - ((3, 0), 2), - ((3, 2), 3)] - sage: [((i,j),isogs[i][j].x_rational_map()) for i in range(4) for j in range(4) if isogs[i][j]!=0] + ((0, 3), 2), + ((1, 0), 3), + ((1, 2), 2), + ((2, 1), 2), + ((2, 3), 3), + ((3, 0), 2), + ((3, 2), 3)] + sage: [((i,j), isogs[i][j].x_rational_map()) + ....: for i in range(4) for j in range(4) if isogs[i][j] != 0] [((0, 1), (1/9*x^3 - 12)/x^2), ((0, 3), (-1/2*i*x^2 + i*x - 12*i)/(x - 3)), ((1, 0), (x^3 + 4)/x^2), @@ -654,7 +661,9 @@ class :class:`EllipticCurveIsogeny` allowed composition. In sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve([1+i, -i, i, 1, 0]) sage: C = E.isogeny_class(); C - Isogeny class of Elliptic Curve defined by y^2 + (i+1)*x*y + i*y = x^3 + (-i)*x^2 + x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I + Isogeny class of Elliptic Curve defined + by y^2 + (i+1)*x*y + i*y = x^3 + (-i)*x^2 + x + over Number Field in i with defining polynomial x^2 + 1 with i = 1*I sage: len(C) 6 sage: C.matrix() @@ -676,7 +685,7 @@ class :class:`EllipticCurveIsogeny` allowed composition. In sage: pol = PolynomialRing(QQ,'x')([1,0,3,0,1]) sage: K.<c> = NumberField(pol) - sage: j = 1480640+565760*c^2 + sage: j = 1480640 + 565760*c^2 sage: E = EllipticCurve(j=j) sage: E.has_cm() True @@ -692,9 +701,15 @@ class :class:`EllipticCurveIsogeny` allowed composition. In [2 1] sage: [E.ainvs() for E in C] [(0, 0, 0, 83490*c^2 - 147015, -64739840*c^2 - 84465260), - (0, 0, 0, -161535*c^2 + 70785, -62264180*c^3 + 6229080*c)] + (0, 0, 0, -161535*c^2 + 70785, -62264180*c^3 + 6229080*c)] sage: C.isogenies()[0][1] - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + (83490*c^2-147015)*x + (-64739840*c^2-84465260) over Number Field in c with defining polynomial x^4 + 3*x^2 + 1 to Elliptic Curve defined by y^2 = x^3 + (-161535*c^2+70785)*x + (-62264180*c^3+6229080*c) over Number Field in c with defining polynomial x^4 + 3*x^2 + 1 + Isogeny of degree 2 + from Elliptic Curve defined by + y^2 = x^3 + (83490*c^2-147015)*x + (-64739840*c^2-84465260) + over Number Field in c with defining polynomial x^4 + 3*x^2 + 1 + to Elliptic Curve defined by + y^2 = x^3 + (-161535*c^2+70785)*x + (-62264180*c^3+6229080*c) + over Number Field in c with defining polynomial x^4 + 3*x^2 + 1 TESTS:: @@ -761,7 +776,7 @@ def _compute(self, verbose=False): Check that :trac:`19030` is fixed (codomains of reverse isogenies were wrong):: - sage: K.<i> = NumberField(x^2+1) + sage: K.<i> = NumberField(x^2 + 1) sage: E = EllipticCurve([1, i + 1, 1, -72*i + 8, 95*i + 146]) sage: C = E.isogeny_class() sage: curves = C.curves @@ -770,7 +785,7 @@ def _compute(self, verbose=False): True """ from sage.schemes.elliptic_curves.ell_curve_isogeny import fill_isogeny_matrix - from sage.matrix.all import MatrixSpace + from sage.matrix.matrix_space import MatrixSpace from sage.sets.set import Set self._maps = None @@ -838,9 +853,9 @@ def add_tup(t): js = [j for j,E3 in enumerate(curves) if E2.is_isomorphic(E3)] if js: # seen codomain already -- up to isomorphism j = js[0] - if phi.codomain()!=curves[j]: + if phi.codomain() != curves[j]: phi = E2.isomorphism_to(curves[j]) * phi - assert phi.domain()==curves[i] and phi.codomain()==curves[j] + assert phi.domain() == curves[i] and phi.codomain() == curves[j] add_tup([i,j,d,phi]) else: curves.append(E2) @@ -870,7 +885,7 @@ def add_tup(t): mat = MatrixSpace(ZZ, ncurves)(0) self._maps = [[0] * ncurves for _ in range(ncurves)] for i,j,l,phi in tuples: - if phi!=0: + if phi != 0: mat[perm[i],perm[j]] = l self._maps[perm[i]][perm[j]] = phi self._mat = fill_isogeny_matrix(mat) @@ -917,16 +932,16 @@ def find_quadratic_form(d, n): for Q in allQs[d]: if Q.solve_integer(n): return Q - raise ValueError("No form of discriminant %d represents %s" %(d,n)) + raise ValueError("No form of discriminant %d represents %s" % (d,n)) mat = self._mat qfmat = [[0 for i in range(ncurves)] for j in range(ncurves)] for i, E1 in enumerate(self.curves): for j, E2 in enumerate(self.curves): - if j<i: + if j < i: qfmat[i][j] = qfmat[j][i] mat[i,j] = mat[j,i] - elif i==j: + elif i == j: qfmat[i][j] = [1] # mat[i,j] already 1 else: @@ -986,13 +1001,13 @@ def __init__(self, E, algorithm="sage", label=None, empty=False): - ``E`` -- an elliptic curve over `\QQ`. - - ``algorithm`` -- a string (default "sage"). One of the + - ``algorithm`` -- a string (default ``"sage"``). One of the following: - - "sage" -- Use sage's implementation to compute the curves, + - ``"sage"`` -- Use sage's implementation to compute the curves, matrix and isogenies - - "database" -- Use the Cremona database (only works if the + - ``"database"`` -- Use the Cremona database (only works if the curve is in the database) - ``label`` -- a string, the label of this isogeny class @@ -1008,7 +1023,8 @@ def __init__(self, E, algorithm="sage", label=None, empty=False): sage: E.isogeny_class(order='database') Traceback (most recent call last): ... - LookupError: Cremona database does not contain entry for Elliptic Curve defined by y^2 = x^3 + 1001 over Rational Field + LookupError: Cremona database does not contain entry for + Elliptic Curve defined by y^2 = x^3 + 1001 over Rational Field sage: TestSuite(isocls).run() """ self._algorithm = algorithm @@ -1055,7 +1071,7 @@ def _compute(self): [0 2 0 0 0 0] """ algorithm = self._algorithm - from sage.matrix.all import MatrixSpace + from sage.matrix.matrix_space import MatrixSpace self._maps = None if algorithm == "database": try: @@ -1076,7 +1092,7 @@ def _compute(self): ijl_triples = [] l_list = None i = 0 - while i<len(curves): + while i < len(curves): E = curves[i] isogs = E.isogenies_prime_degree(l_list) for phi in isogs: @@ -1101,7 +1117,7 @@ def _compute(self): self._maps = [[0]*ncurves for _ in range(ncurves)] for i,j,l,phi in ijl_triples: self._mat[i,j] = l - self._maps[i][j]=phi + self._maps[i][j] = phi else: raise ValueError("unknown algorithm '%s'" % algorithm) @@ -1161,7 +1177,7 @@ def isogeny_degrees_cm(E, verbose=False): sage: pol = PolynomialRing(QQ,'x')([1,-3,5,-5,5,-3,1]) sage: L.<a> = NumberField(pol) - sage: j = hilbert_class_polynomial(-23).roots(L,multiplicities=False)[0] + sage: j = hilbert_class_polynomial(-23).roots(L, multiplicities=False)[0] sage: E = EllipticCurve(j=j) sage: from sage.schemes.elliptic_curves.isogeny_class import isogeny_degrees_cm sage: isogeny_degrees_cm(E, verbose=True) @@ -1183,8 +1199,8 @@ def isogeny_degrees_cm(E, verbose=False): print("CM case, discriminant = %s" % d) from sage.libs.pari.all import pari - from sage.sets.all import Set - from sage.arith.all import kronecker_symbol + from sage.sets.set import Set + from sage.arith.misc import kronecker as kronecker_symbol n = E.base_field().absolute_degree() if not E.has_rational_cm(): @@ -1207,7 +1223,7 @@ def isogeny_degrees_cm(E, verbose=False): # Collect possible primes. First put in 2, and also 3 for # discriminant -3 (special case because of units): - L = Set([ZZ(2), ZZ(3)]) if d==-3 else Set([ZZ(2)]) + L = Set([ZZ(2), ZZ(3)]) if d == -3 else Set([ZZ(2)]) if verbose: print("initial primes: %s" % L) @@ -1233,7 +1249,7 @@ def isogeny_degrees_cm(E, verbose=False): # Find the "upward" primes (index divided by l): - L1 = Set([l for l in ram_l if d.valuation(l)>1]) + L1 = Set([l for l in ram_l if d.valuation(l) > 1]) L += L1 if verbose: print("upward primes: %s" % L1) @@ -1253,7 +1269,7 @@ def isogeny_degrees_cm(E, verbose=False): # l-1 must divide n/2h: L1 = Set([lm1+1 for lm1 in divs - if (lm1+1).is_prime() and kronecker_symbol(d,lm1+1)==+1]) + if (lm1+1).is_prime() and kronecker_symbol(d,lm1+1) == +1]) L += L1 if verbose: print("downward split primes: %s" % L1) @@ -1262,7 +1278,7 @@ def isogeny_degrees_cm(E, verbose=False): # l+1 must divide n/2h: L1 = Set([lp1-1 for lp1 in divs - if (lp1-1).is_prime() and kronecker_symbol(d,lp1-1)==-1]) + if (lp1-1).is_prime() and kronecker_symbol(d,lp1-1) == -1]) L += L1 if verbose: print("downward inert primes: %s" % L1) @@ -1299,18 +1315,18 @@ def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None, - ``E`` -- An elliptic curve defined over a number field. - - ``algorithm`` (string, default 'Billerey') -- Algorithm to be - used for non-CM curves: either 'Billerey', 'Larson', or - 'heuristic'. Only relevant for non-CM curves and base fields + - ``algorithm`` (string, default ``'Billerey'``) -- Algorithm to be + used for non-CM curves: either ``'Billerey'``, ``'Larson'``, or + ``'heuristic'``. Only relevant for non-CM curves and base fields other than `\QQ`. - ``max_l`` (int or ``None``) -- only relevant for non-CM curves - and algorithms 'Billerey' and 'heuristic. Controls the maximum + and algorithms ``'Billerey'`` and ``'heuristic'``. Controls the maximum prime used in either algorithm. If ``None``, use the default for that algorithm. - ``num_l`` (int or ``None``) -- only relevant for non-CM curves - and algorithm 'Billerey'. Controls the maximum number of primes + and algorithm ``'Billerey'``. Controls the maximum number of primes used in the algorithm. If ``None``, use the default for that algorithm. @@ -1373,7 +1389,9 @@ def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None, A higher degree example (LMFDB curve 5.5.170701.1-4.1-b1):: sage: K.<a> = NumberField(x^5 - x^4 - 6*x^3 + 4*x + 1) - sage: E = EllipticCurve(K, [a^3 - a^2 - 5*a + 1, a^4 - a^3 - 5*a^2 - a + 1, -a^4 + 2*a^3 + 5*a^2 - 5*a - 3, a^4 - a^3 - 5*a^2 - a, -3*a^4 + 4*a^3 + 17*a^2 - 6*a - 12]) + sage: E = EllipticCurve(K, [a^3 - a^2 - 5*a + 1, a^4 - a^3 - 5*a^2 - a + 1, + ....: -a^4 + 2*a^3 + 5*a^2 - 5*a - 3, a^4 - a^3 - 5*a^2 - a, + ....: -3*a^4 + 4*a^3 + 17*a^2 - 6*a - 12]) sage: possible_isogeny_degrees(E, algorithm='heuristic') [2] sage: possible_isogeny_degrees(E, algorithm='Billerey') @@ -1405,7 +1423,7 @@ def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None, sage: pol = PolynomialRing(QQ,'x')([1,-3,5,-5,5,-3,1]) sage: L.<a> = NumberField(pol) - sage: j = hilbert_class_polynomial(-23).roots(L,multiplicities=False)[0] + sage: j = hilbert_class_polynomial(-23).roots(L, multiplicities=False)[0] sage: E = EllipticCurve(j=j) sage: from sage.schemes.elliptic_curves.isogeny_class import possible_isogeny_degrees sage: possible_isogeny_degrees(E, verbose=True) diff --git a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py index f5657f2cf19..ac68ba3d601 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py +++ b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py @@ -34,7 +34,7 @@ from sage.rings.polynomial.polynomial_ring import polygen from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.schemes.elliptic_curves.all import EllipticCurve +from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.misc.cachefunc import cached_function @@ -79,7 +79,9 @@ def Fricke_polynomial(l): sage: Fricke_polynomial(7) t^8 + 28*t^7 + 322*t^6 + 1904*t^5 + 5915*t^4 + 8624*t^3 + 4018*t^2 + 748*t + 49 sage: Fricke_polynomial(13) - t^14 + 26*t^13 + 325*t^12 + 2548*t^11 + 13832*t^10 + 54340*t^9 + 157118*t^8 + 333580*t^7 + 509366*t^6 + 534820*t^5 + 354536*t^4 + 124852*t^3 + 15145*t^2 + 746*t + 13 + t^14 + 26*t^13 + 325*t^12 + 2548*t^11 + 13832*t^10 + 54340*t^9 + 157118*t^8 + + 333580*t^7 + 509366*t^6 + 534820*t^5 + 354536*t^4 + 124852*t^3 + + 15145*t^2 + 746*t + 13 """ t = PolynomialRing(ZZ, 't').gen() if l == 2: @@ -129,7 +131,9 @@ def Fricke_module(l): sage: Fricke_module(7) (t^8 + 28*t^7 + 322*t^6 + 1904*t^5 + 5915*t^4 + 8624*t^3 + 4018*t^2 + 748*t + 49)/t sage: Fricke_module(13) - (t^14 + 26*t^13 + 325*t^12 + 2548*t^11 + 13832*t^10 + 54340*t^9 + 157118*t^8 + 333580*t^7 + 509366*t^6 + 534820*t^5 + 354536*t^4 + 124852*t^3 + 15145*t^2 + 746*t + 13)/t + (t^14 + 26*t^13 + 325*t^12 + 2548*t^11 + 13832*t^10 + + 54340*t^9 + 157118*t^8 + 333580*t^7 + 509366*t^6 + + 534820*t^5 + 354536*t^4 + 124852*t^3 + 15145*t^2 + 746*t + 13)/t """ t = PolynomialRing(QQ, 't').gen() return Fricke_polynomial(l) / t @@ -200,7 +204,7 @@ def Psi(l, use_stored=True): if l == 3: return X + t + 27 if l == 5: - return X**2 + 2*X*(t**2 + 22*t + 125)+ (t**2 + 22*t + 89) * (t**2 + 22*t + 125) + return X**2 + 2*X*(t**2 + 22*t + 125) + (t**2 + 22*t + 89) * (t**2 + 22*t + 125) if l == 7: return (X**3 + 3*(t**2 + 13*t + 49)*X**2 + 3*(t**2 + 13*t + 33)*(t**2 + 13*t + 49)*X @@ -268,15 +272,23 @@ def isogenies_prime_degree_genus_0(E, l=None, minimal_models=True): sage: E = EllipticCurve('1450c1') sage: isogenies_prime_degree_genus_0(E) - [Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 300*x - 1000 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 5950*x - 182250 over Rational Field] + [Isogeny of degree 3 + from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 300*x - 1000 + over Rational Field + to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 5950*x - 182250 + over Rational Field] sage: E = EllipticCurve('50a1') sage: isogenies_prime_degree_genus_0(E) - [Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - 126*x - 552 over Rational Field, - Isogeny of degree 5 from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - 76*x + 298 over Rational Field] + [Isogeny of degree 3 + from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 - 126*x - 552 over Rational Field, + Isogeny of degree 5 + from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 - 76*x + 298 over Rational Field] """ if l not in [2, 3, 5, 7, 13, None]: - raise ValueError("%s is not a genus 0 prime."%l) + raise ValueError("%s is not a genus 0 prime." % l) F = E.base_ring() j = E.j_invariant() if F.characteristic() in [2, 3, l]: @@ -315,14 +327,14 @@ def isogenies_prime_degree_genus_0(E, l=None, minimal_models=True): from sage.misc.misc_c import prod psi = Psi(l) X = t - f = R(prod( [p for p,e in jt.factor() if e==3] - +[p for p,e in kt.factor() if e==2])) + f = R(prod( [p for p,e in jt.factor() if e == 3] + + [p for p,e in kt.factor() if e == 2])) kernels = [R(psi(X*T*(j-1728)*t0/f(t0),t0)) for t0 in t_list] kernels = [ker.monic() for ker in kernels] E1 = EllipticCurve([-27*c4,-54*c6]) w = E.isomorphism_to(E1) - from sage.rings.number_field.number_field_base import is_NumberField - model = "minimal" if minimal_models and is_NumberField(F) else None + from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None isogs = [E1.isogeny(kernel=ker, model=model) for ker in kernels] isogs = [isog * w for isog in isogs] return isogs @@ -536,24 +548,24 @@ def _sporadic_Q_data(j): ....: g = E.division_polynomial(ell) ....: assert g % f == 0 """ - from sage.rings.all import RealField + from sage.rings.real_mpfr import RealField from sage.misc.misc_c import prod ell = sporadic_j[j] E = EllipticCurve(j=j).short_weierstrass_model() a4a6 = list(E.ainvs())[3:] L = E.period_lattice() pr = 100 - if ell==163: - pr=1000 - elif ell>30: - pr=300 + if ell == 163: + pr = 1000 + elif ell > 30: + pr = 300 w1, w2 = L.basis(prec=pr) X = polygen(RealField(pr),'X') w = w1 # real period if j in [-121, -24729001, -162677523113838677, QQ(-882216989)/131072]: w = 2*w2-w1 # imaginary period kerpol = prod(([X-L.elliptic_exponential(n*w/ell)[0] for n in range(1,(ell+1)//2)])) - if j==-162677523113838677: + if j == -162677523113838677: kerpolcoeffs = [(37*c.real()).round()/37 for c in list(kerpol)] else: kerpolcoeffs = [c.real().round() for c in list(kerpol)] @@ -588,19 +600,35 @@ def isogenies_sporadic_Q(E, l=None, minimal_models=True): sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_sporadic_Q sage: E = EllipticCurve('121a1') sage: isogenies_sporadic_Q(E, 11) - [Isogeny of degree 11 from Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 30*x - 76 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 305*x + 7888 over Rational Field] + [Isogeny of degree 11 + from Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 30*x - 76 + over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 305*x + 7888 + over Rational Field] sage: isogenies_sporadic_Q(E, 13) [] sage: isogenies_sporadic_Q(E, 17) [] sage: isogenies_sporadic_Q(E) - [Isogeny of degree 11 from Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 30*x - 76 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 305*x + 7888 over Rational Field] + [Isogeny of degree 11 + from Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 30*x - 76 + over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 305*x + 7888 + over Rational Field] sage: E = EllipticCurve([1, 1, 0, -660, -7600]) sage: isogenies_sporadic_Q(E, 17) - [Isogeny of degree 17 from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 660*x - 7600 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 878710*x + 316677750 over Rational Field] + [Isogeny of degree 17 + from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 660*x - 7600 + over Rational Field + to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 878710*x + 316677750 + over Rational Field] sage: isogenies_sporadic_Q(E) - [Isogeny of degree 17 from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 660*x - 7600 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 878710*x + 316677750 over Rational Field] + [Isogeny of degree 17 + from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 660*x - 7600 + over Rational Field + to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 878710*x + 316677750 + over Rational Field] sage: isogenies_sporadic_Q(E, 11) [] @@ -608,39 +636,67 @@ def isogenies_sporadic_Q(E, l=None, minimal_models=True): sage: isogenies_sporadic_Q(E, 11) [] sage: isogenies_sporadic_Q(E, 19) - [Isogeny of degree 19 from Elliptic Curve defined by y^2 + y = x^3 - 1862*x - 30956 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - 672182*x + 212325489 over Rational Field] + [Isogeny of degree 19 + from Elliptic Curve defined by y^2 + y = x^3 - 1862*x - 30956 + over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - 672182*x + 212325489 + over Rational Field] sage: isogenies_sporadic_Q(E) - [Isogeny of degree 19 from Elliptic Curve defined by y^2 + y = x^3 - 1862*x - 30956 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - 672182*x + 212325489 over Rational Field] + [Isogeny of degree 19 + from Elliptic Curve defined by y^2 + y = x^3 - 1862*x - 30956 + over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - 672182*x + 212325489 + over Rational Field] sage: E = EllipticCurve([0, -1, 0, -6288, 211072]) sage: E.conductor() 19600 sage: isogenies_sporadic_Q(E,37) - [Isogeny of degree 37 from Elliptic Curve defined by y^2 = x^3 - x^2 - 6288*x + 211072 over Rational Field to Elliptic Curve defined by y^2 = x^3 - x^2 - 163137088*x - 801950801728 over Rational Field] + [Isogeny of degree 37 + from Elliptic Curve defined by y^2 = x^3 - x^2 - 6288*x + 211072 + over Rational Field + to Elliptic Curve defined by y^2 = x^3 - x^2 - 163137088*x - 801950801728 + over Rational Field] sage: E = EllipticCurve([1, 1, 0, -25178045, 48616918750]) sage: E.conductor() 148225 sage: isogenies_sporadic_Q(E,37) - [Isogeny of degree 37 from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 25178045*x + 48616918750 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 970*x - 13075 over Rational Field] + [Isogeny of degree 37 + from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 25178045*x + 48616918750 + over Rational Field + to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 970*x - 13075 + over Rational Field] sage: E = EllipticCurve([-3440, 77658]) sage: E.conductor() 118336 sage: isogenies_sporadic_Q(E,43) - [Isogeny of degree 43 from Elliptic Curve defined by y^2 = x^3 - 3440*x + 77658 over Rational Field to Elliptic Curve defined by y^2 = x^3 - 6360560*x - 6174354606 over Rational Field] + [Isogeny of degree 43 + from Elliptic Curve defined by y^2 = x^3 - 3440*x + 77658 + over Rational Field + to Elliptic Curve defined by y^2 = x^3 - 6360560*x - 6174354606 + over Rational Field] sage: E = EllipticCurve([-29480, -1948226]) sage: E.conductor() 287296 sage: isogenies_sporadic_Q(E,67) - [Isogeny of degree 67 from Elliptic Curve defined by y^2 = x^3 - 29480*x - 1948226 over Rational Field to Elliptic Curve defined by y^2 = x^3 - 132335720*x + 585954296438 over Rational Field] + [Isogeny of degree 67 + from Elliptic Curve defined by y^2 = x^3 - 29480*x - 1948226 + over Rational Field + to Elliptic Curve defined by y^2 = x^3 - 132335720*x + 585954296438 + over Rational Field] sage: E = EllipticCurve([-34790720, -78984748304]) sage: E.conductor() 425104 sage: isogenies_sporadic_Q(E,163) - [Isogeny of degree 163 from Elliptic Curve defined by y^2 = x^3 - 34790720*x - 78984748304 over Rational Field to Elliptic Curve defined by y^2 = x^3 - 924354639680*x + 342062961763303088 over Rational Field] + [Isogeny of degree 163 + from Elliptic Curve defined by y^2 = x^3 - 34790720*x - 78984748304 + over Rational Field + to Elliptic Curve defined by y^2 = x^3 - 924354639680*x + 342062961763303088 + over Rational Field] """ j = E.j_invariant() j = QQ(j) @@ -657,8 +713,8 @@ def isogenies_sporadic_Q(E, l=None, minimal_models=True): R = PolynomialRing(F, 'X') n = len(f) ker = R([d**(n-i-1) * f[i] for i in range(n)]) - from sage.rings.number_field.number_field_base import is_NumberField - model = "minimal" if minimal_models and is_NumberField(F) else None + from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None isog = Ew.isogeny(kernel=ker, degree=l, model=model, check=False) isog = isog * E_to_Ew return [isog] @@ -695,16 +751,16 @@ def isogenies_2(E, minimal_models=True): Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field sage: [phi.codomain().ainvs() for phi in isogenies_2(E)] [] - sage: E = EllipticCurve(QQbar, [9,8]); E + sage: E = EllipticCurve(QQbar, [9,8]); E # needs sage.rings.number_field Elliptic Curve defined by y^2 = x^3 + 9*x + 8 over Algebraic Field - sage: isogenies_2(E) # not implemented + sage: isogenies_2(E) # not implemented # needs sage.rings.number_field """ f2 = E.division_polynomial(2) x2 = sorted(f2.roots(multiplicities=False)) x = f2.parent().gen() ff = [x-x2i for x2i in x2] - from sage.rings.number_field.number_field_base import is_NumberField - model = "minimal" if minimal_models and is_NumberField(E.base_field()) else None + from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(E.base_field(), NumberField) else None isogs = [E.isogeny(f, model=model) for f in ff] return isogs @@ -735,8 +791,8 @@ def isogenies_3(E, minimal_models=True): sage: [phi.codomain().ainvs() for phi in isogenies_3(E)] [(0, 0, 0, 9, 7), (0, 0, 0, 0, 1)] - sage: E = EllipticCurve(GF(17^2,'a'), [1,1]) - sage: [phi.codomain().ainvs() for phi in isogenies_3(E)] + sage: E = EllipticCurve(GF(17^2,'a'), [1,1]) # needs sage.rings.finite_rings + sage: [phi.codomain().ainvs() for phi in isogenies_3(E)] # needs sage.rings.finite_rings [(0, 0, 0, 9, 7), (0, 0, 0, 0, 1), (0, 0, 0, 5*a + 1, a + 13), (0, 0, 0, 12*a + 6, 16*a + 14)] sage: E = EllipticCurve('19a1') @@ -751,8 +807,8 @@ def isogenies_3(E, minimal_models=True): x3 = sorted(f3.roots(multiplicities=False)) x = f3.parent().gen() ff = [x - x3i for x3i in x3] - from sage.rings.number_field.number_field_base import is_NumberField - model = "minimal" if minimal_models and is_NumberField(E.base_field()) else None + from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(E.base_field(), NumberField) else None isogs = [E.isogeny(f, model=model) for f in ff] return isogs @@ -794,15 +850,51 @@ def isogenies_5_0(E, minimal_models=True): sage: isogenies_5_0(E) [] - sage: E = EllipticCurve(GF(13^2,'a'),[0,-3]) - sage: isogenies_5_0(E) - [Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 to Elliptic Curve defined by y^2 = x^3 + (4*a+6)*x + (2*a+10) over Finite Field in a of size 13^2, Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 to Elliptic Curve defined by y^2 = x^3 + (12*a+5)*x + (2*a+10) over Finite Field in a of size 13^2, Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 to Elliptic Curve defined by y^2 = x^3 + (10*a+2)*x + (2*a+10) over Finite Field in a of size 13^2, Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 to Elliptic Curve defined by y^2 = x^3 + (3*a+12)*x + (11*a+12) over Finite Field in a of size 13^2, Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 to Elliptic Curve defined by y^2 = x^3 + (a+4)*x + (11*a+12) over Finite Field in a of size 13^2, Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 to Elliptic Curve defined by y^2 = x^3 + (9*a+10)*x + (11*a+12) over Finite Field in a of size 13^2] - - sage: K.<a> = NumberField(x**6-320*x**3-320) - sage: E = EllipticCurve(K,[0,0,1,0,0]) - sage: isogenies_5_0(E) - [Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 over Number Field in a with defining polynomial x^6 - 320*x^3 - 320 to Elliptic Curve defined by y^2 + y = x^3 + (241565/32*a^5-362149/48*a^4+180281/24*a^3-9693307/4*a^2+14524871/6*a-7254985/3)*x + (1660391123/192*a^5-829315373/96*a^4+77680504/9*a^3-66622345345/24*a^2+33276655441/12*a-24931615912/9) over Number Field in a with defining polynomial x^6 - 320*x^3 - 320, - Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 over Number Field in a with defining polynomial x^6 - 320*x^3 - 320 to Elliptic Curve defined by y^2 + y = x^3 + (47519/32*a^5-72103/48*a^4+32939/24*a^3-1909753/4*a^2+2861549/6*a-1429675/3)*x + (-131678717/192*a^5+65520419/96*a^4-12594215/18*a^3+5280985135/24*a^2-2637787519/12*a+1976130088/9) over Number Field in a with defining polynomial x^6 - 320*x^3 - 320] + sage: E = EllipticCurve(GF(13^2,'a'), [0,-3]) # needs sage.rings.finite_rings + sage: isogenies_5_0(E) # needs sage.rings.finite_rings + [Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 + to Elliptic Curve defined by y^2 = x^3 + (4*a+6)*x + (2*a+10) + over Finite Field in a of size 13^2, + Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 + to Elliptic Curve defined by y^2 = x^3 + (12*a+5)*x + (2*a+10) + over Finite Field in a of size 13^2, + Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 + to Elliptic Curve defined by y^2 = x^3 + (10*a+2)*x + (2*a+10) + over Finite Field in a of size 13^2, + Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 + to Elliptic Curve defined by y^2 = x^3 + (3*a+12)*x + (11*a+12) + over Finite Field in a of size 13^2, + Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 + to Elliptic Curve defined by y^2 = x^3 + (a+4)*x + (11*a+12) + over Finite Field in a of size 13^2, + Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 + to Elliptic Curve defined by y^2 = x^3 + (9*a+10)*x + (11*a+12) + over Finite Field in a of size 13^2] + + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField(x**6 - 320*x**3 - 320) # needs sage.rings.number_field + sage: E = EllipticCurve(K, [0,0,1,0,0]) # needs sage.rings.number_field + sage: isogenies_5_0(E) # needs sage.rings.number_field + [Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 + over Number Field in a with defining polynomial x^6 - 320*x^3 - 320 + to Elliptic Curve defined by + y^2 + y = x^3 + (241565/32*a^5-362149/48*a^4+180281/24*a^3-9693307/4*a^2+14524871/6*a-7254985/3)*x + + (1660391123/192*a^5-829315373/96*a^4+77680504/9*a^3-66622345345/24*a^2+33276655441/12*a-24931615912/9) + over Number Field in a with defining polynomial x^6 - 320*x^3 - 320, + Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 + over Number Field in a with defining polynomial x^6 - 320*x^3 - 320 + to Elliptic Curve defined by + y^2 + y = x^3 + (47519/32*a^5-72103/48*a^4+32939/24*a^3-1909753/4*a^2+2861549/6*a-1429675/3)*x + + (-131678717/192*a^5+65520419/96*a^4-12594215/18*a^3+5280985135/24*a^2-2637787519/12*a+1976130088/9) + over Number Field in a with defining polynomial x^6 - 320*x^3 - 320] """ F = E.base_field() if E.j_invariant() != 0: @@ -817,9 +909,9 @@ def isogenies_5_0(E, minimal_models=True): betas = sorted((x**6-160*a*x**3-80*a**2).roots(multiplicities=False)) if not betas: return [] - gammas = [(beta**2 *(beta**3-140*a))/(120*a) for beta in betas] - from sage.rings.number_field.number_field_base import is_NumberField - model = "minimal" if minimal_models and is_NumberField(F) else None + gammas = [(beta**2 * (beta**3-140*a))/(120*a) for beta in betas] + from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None isogs = [Ew.isogeny(x**2+beta*x+gamma, model=model) for beta,gamma in zip(betas,gammas)] iso = E.isomorphism_to(Ew) isogs = [isog * iso for isog in isogs] @@ -863,36 +955,66 @@ def isogenies_5_1728(E, minimal_models=True): sage: isogenies_5_1728(E) [] - sage: E = EllipticCurve(GF(13),[11,0]) + sage: E = EllipticCurve(GF(13), [11,0]) sage: isogenies_5_1728(E) - [Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + 11*x over Finite Field of size 13 to Elliptic Curve defined by y^2 = x^3 + 11*x over Finite Field of size 13, - Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + 11*x over Finite Field of size 13 to Elliptic Curve defined by y^2 = x^3 + 11*x over Finite Field of size 13] + [Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + 11*x over Finite Field of size 13 + to Elliptic Curve defined by y^2 = x^3 + 11*x over Finite Field of size 13, + Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + 11*x over Finite Field of size 13 + to Elliptic Curve defined by y^2 = x^3 + 11*x over Finite Field of size 13] An example of endomorphisms of degree 5:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) - sage: E = EllipticCurve(K,[0,0,0,1,0]) + sage: E = EllipticCurve(K, [0,0,0,1,0]) sage: isogenies_5_1728(E) - [Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I to Elliptic Curve defined by y^2 = x^3 + x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I, - Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I to Elliptic Curve defined by y^2 = x^3 + x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I] + [Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + x over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I + to Elliptic Curve defined by y^2 = x^3 + x over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I, + Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + x over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I + to Elliptic Curve defined by y^2 = x^3 + x over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I] sage: _[0].rational_maps() - (((4/25*i + 3/25)*x^5 + (4/5*i - 2/5)*x^3 - x)/(x^4 + (-4/5*i + 2/5)*x^2 + (-4/25*i - 3/25)), - ((11/125*i + 2/125)*x^6*y + (-23/125*i + 64/125)*x^4*y + (141/125*i + 162/125)*x^2*y + (3/25*i - 4/25)*y)/(x^6 + (-6/5*i + 3/5)*x^4 + (-12/25*i - 9/25)*x^2 + (2/125*i - 11/125))) + (((4/25*i + 3/25)*x^5 + + (4/5*i - 2/5)*x^3 - x)/(x^4 + (-4/5*i + 2/5)*x^2 + (-4/25*i - 3/25)), + ((11/125*i + 2/125)*x^6*y + (-23/125*i + 64/125)*x^4*y + + (141/125*i + 162/125)*x^2*y + + (3/25*i - 4/25)*y)/(x^6 + (-6/5*i + 3/5)*x^4 + + (-12/25*i - 9/25)*x^2 + (2/125*i - 11/125))) An example of 5-isogenies over a number field:: - sage: K.<a> = NumberField(x**4+20*x**2-80) - sage: K(5).is_square() #necessary but not sufficient! + sage: # needs sage.rings.number_field + sage: x = polygen(QQ, 'x') + sage: K.<a> = NumberField(x**4 + 20*x**2 - 80) + sage: K(5).is_square() # necessary but not sufficient! True - sage: E = EllipticCurve(K,[0,0,0,1,0]) + sage: E = EllipticCurve(K, [0,0,0,1,0]) sage: isogenies_5_1728(E) - [Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + x over Number Field in a with defining polynomial x^4 + 20*x^2 - 80 to Elliptic Curve defined by y^2 = x^3 + (-753/4*a^2-4399)*x + (2779*a^3+65072*a) over Number Field in a with defining polynomial x^4 + 20*x^2 - 80, - Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + x over Number Field in a with defining polynomial x^4 + 20*x^2 - 80 to Elliptic Curve defined by y^2 = x^3 + (-753/4*a^2-4399)*x + (-2779*a^3-65072*a) over Number Field in a with defining polynomial x^4 + 20*x^2 - 80] + [Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + x + over Number Field in a with defining polynomial x^4 + 20*x^2 - 80 + to Elliptic Curve defined by y^2 = x^3 + (-753/4*a^2-4399)*x + (2779*a^3+65072*a) + over Number Field in a with defining polynomial x^4 + 20*x^2 - 80, + Isogeny of degree 5 + from Elliptic Curve defined by y^2 = x^3 + x + over Number Field in a with defining polynomial x^4 + 20*x^2 - 80 + to Elliptic Curve defined by y^2 = x^3 + (-753/4*a^2-4399)*x + (-2779*a^3-65072*a) + over Number Field in a with defining polynomial x^4 + 20*x^2 - 80] See :trac:`19840`:: + sage: # needs sage.rings.number_field sage: K.<a> = NumberField(x^4 - 5*x^2 + 5) - sage: E = EllipticCurve([a^2 + a + 1, a^3 + a^2 + a + 1, a^2 + a, 17*a^3 + 34*a^2 - 16*a - 37, 54*a^3 + 105*a^2 - 66*a - 135]) + sage: E = EllipticCurve([a^2 + a + 1, a^3 + a^2 + a + 1, a^2 + a, + ....: 17*a^3 + 34*a^2 - 16*a - 37, + ....: 54*a^3 + 105*a^2 - 66*a - 135]) sage: len(E.isogenies_prime_degree(5)) 2 sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_5_1728 @@ -904,8 +1026,8 @@ def isogenies_5_1728(E, minimal_models=True): raise ValueError("j-invariant must be 1728.") if F.characteristic() in [2,3,5]: raise NotImplementedError("Not implemented in characteristic 2, 3 or 5.") - from sage.rings.number_field.number_field_base import is_NumberField - model = "minimal" if minimal_models and is_NumberField(F) else None + from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None # quick test for a negative answer (from Fricke module) square5 = F(5).is_square() square1 = F(-1).is_square() @@ -965,31 +1087,59 @@ def isogenies_7_0(E, minimal_models=True): First some examples of endomorphisms:: sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_7_0 - sage: K.<r> = QuadraticField(-3) - sage: E = EllipticCurve(K, [0,1]) - sage: isogenies_7_0(E) - [Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 1 over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I to Elliptic Curve defined by y^2 = x^3 + 1 over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I, - Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 1 over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I to Elliptic Curve defined by y^2 = x^3 + 1 over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I] - - sage: E = EllipticCurve(GF(13^2,'a'),[0,-3]) - sage: isogenies_7_0(E) - [Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 to Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 to Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2] + sage: K.<r> = QuadraticField(-3) # needs sage.rings.number_field + sage: E = EllipticCurve(K, [0,1]) # needs sage.rings.number_field + sage: isogenies_7_0(E) # needs sage.rings.number_field + [Isogeny of degree 7 + from Elliptic Curve defined by y^2 = x^3 + 1 over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I + to Elliptic Curve defined by y^2 = x^3 + 1 over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I, + Isogeny of degree 7 + from Elliptic Curve defined by y^2 = x^3 + 1 over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I + to Elliptic Curve defined by y^2 = x^3 + 1 over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I] + + sage: E = EllipticCurve(GF(13^2,'a'), [0,-3]) # needs sage.rings.finite_rings + sage: isogenies_7_0(E) # needs sage.rings.finite_rings + [Isogeny of degree 7 + from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 + to Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2, + Isogeny of degree 7 + from Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2 + to Elliptic Curve defined by y^2 = x^3 + 10 over Finite Field in a of size 13^2] Now some examples of 7-isogenies which are not endomorphisms:: sage: K = GF(101) sage: E = EllipticCurve(K, [0,1]) sage: isogenies_7_0(E) - [Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 55*x + 100 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 83*x + 26 over Finite Field of size 101] + [Isogeny of degree 7 + from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 101 + to Elliptic Curve defined by y^2 = x^3 + 55*x + 100 over Finite Field of size 101, + Isogeny of degree 7 + from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 101 + to Elliptic Curve defined by y^2 = x^3 + 83*x + 26 over Finite Field of size 101] Examples over a number field:: sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_7_0 - sage: E = EllipticCurve('27a1').change_ring(QuadraticField(-3,'r')) - sage: isogenies_7_0(E) - [Isogeny of degree 7 from Elliptic Curve defined by y^2 + y = x^3 + (-7) over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I to Elliptic Curve defined by y^2 + y = x^3 + (-7) over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I, - Isogeny of degree 7 from Elliptic Curve defined by y^2 + y = x^3 + (-7) over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I to Elliptic Curve defined by y^2 + y = x^3 + (-7) over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I] - + sage: E = EllipticCurve('27a1').change_ring(QuadraticField(-3,'r')) # needs sage.rings.number_field + sage: isogenies_7_0(E) # needs sage.rings.number_field + [Isogeny of degree 7 + from Elliptic Curve defined by y^2 + y = x^3 + (-7) over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I + to Elliptic Curve defined by y^2 + y = x^3 + (-7) over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I, + Isogeny of degree 7 + from Elliptic Curve defined by y^2 + y = x^3 + (-7) over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I + to Elliptic Curve defined by y^2 + y = x^3 + (-7) over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I] + + sage: # needs sage.rings.number_field + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^6 + 1512*x^3 - 21168) sage: E = EllipticCurve(K, [0,1]) sage: isogs = isogenies_7_0(E) @@ -998,17 +1148,19 @@ def isogenies_7_0(E, minimal_models=True): 0, 0, -415/98*a^5 - 675/14*a^4 + 2255/7*a^3 - 74700/7*a^2 - 25110*a - 66420, - -141163/56*a^5 + 1443453/112*a^4 - 374275/2*a^3 - 3500211/2*a^2 - 17871975/4*a - 7710065), + -141163/56*a^5 + 1443453/112*a^4 - 374275/2*a^3 + - 3500211/2*a^2 - 17871975/4*a - 7710065), (0, 0, 0, -24485/392*a^5 - 1080/7*a^4 - 2255/7*a^3 - 1340865/14*a^2 - 230040*a - 553500, - 1753037/56*a^5 + 8345733/112*a^4 + 374275/2*a^3 + 95377029/2*a^2 + 458385345/4*a + 275241835)] + 1753037/56*a^5 + 8345733/112*a^4 + 374275/2*a^3 + + 95377029/2*a^2 + 458385345/4*a + 275241835)] sage: [phi.codomain().j_invariant() for phi in isogs] [158428486656000/7*a^3 - 313976217600000, -158428486656000/7*a^3 - 34534529335296000] """ - if E.j_invariant()!=0: + if E.j_invariant() != 0: raise ValueError("j-invariant must be 0.") F = E.base_field() if F.characteristic() in [2,3,7]: @@ -1017,8 +1169,8 @@ def isogenies_7_0(E, minimal_models=True): Ew = E.short_weierstrass_model() iso = E.isomorphism_to(Ew) a = Ew.a6() - from sage.rings.number_field.number_field_base import is_NumberField - model = "minimal" if minimal_models and is_NumberField(F) else None + from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None # there will be 2 endomorphisms if -3 is a square: @@ -1073,27 +1225,38 @@ def isogenies_7_1728(E, minimal_models=True): sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_7_1728 sage: E = EllipticCurve(GF(47), [1, 0]) sage: isogenies_7_1728(E) - [Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 47 to Elliptic Curve defined by y^2 = x^3 + 26 over Finite Field of size 47, - Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 47 to Elliptic Curve defined by y^2 = x^3 + 21 over Finite Field of size 47] + [Isogeny of degree 7 + from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 47 + to Elliptic Curve defined by y^2 = x^3 + 26 over Finite Field of size 47, + Isogeny of degree 7 + from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 47 + to Elliptic Curve defined by y^2 = x^3 + 21 over Finite Field of size 47] An example in characteristic 53 (for which an earlier implementation did not work):: + sage: # needs sage.rings.finite_rings sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_7_1728 sage: E = EllipticCurve(GF(53), [1, 0]) sage: isogenies_7_1728(E) [] sage: E = EllipticCurve(GF(53^2,'a'), [1, 0]) sage: [iso.codomain().ainvs() for iso in isogenies_7_1728(E)] - [(0, 0, 0, 36, 19*a + 15), (0, 0, 0, 36, 34*a + 38), (0, 0, 0, 33, 39*a + 28), (0, 0, 0, 33, 14*a + 25), (0, 0, 0, 19, 45*a + 16), (0, 0, 0, 19, 8*a + 37), (0, 0, 0, 3, 45*a + 16), (0, 0, 0, 3, 8*a + 37)] + [(0, 0, 0, 36, 19*a + 15), (0, 0, 0, 36, 34*a + 38), (0, 0, 0, 33, 39*a + 28), + (0, 0, 0, 33, 14*a + 25), (0, 0, 0, 19, 45*a + 16), (0, 0, 0, 19, 8*a + 37), + (0, 0, 0, 3, 45*a + 16), (0, 0, 0, 3, 8*a + 37)] :: + sage: # needs sage.rings.number_field + sage: x = polygen(QQ, 'x') sage: K.<a> = NumberField(x^8 + 84*x^6 - 1890*x^4 + 644*x^2 - 567) sage: E = EllipticCurve(K, [1, 0]) sage: isogs = isogenies_7_1728(E) sage: [phi.codomain().j_invariant() for phi in isogs] - [-526110256146528/53*a^6 + 183649373229024*a^4 - 3333881559996576/53*a^2 + 2910267397643616/53, - -526110256146528/53*a^6 + 183649373229024*a^4 - 3333881559996576/53*a^2 + 2910267397643616/53] + [-526110256146528/53*a^6 + 183649373229024*a^4 + - 3333881559996576/53*a^2 + 2910267397643616/53, + -526110256146528/53*a^6 + 183649373229024*a^4 + - 3333881559996576/53*a^2 + 2910267397643616/53] sage: E1 = isogs[0].codomain() sage: E2 = isogs[1].codomain() sage: E1.is_isomorphic(E2) @@ -1101,7 +1264,7 @@ def isogenies_7_1728(E, minimal_models=True): sage: E1.is_quadratic_twist(E2) -1 """ - if E.j_invariant()!=1728: + if E.j_invariant() != 1728: raise ValueError("j_invariant must be 1728 (in base field).") F = E.base_field() if F.characteristic() in [2,3,7]: @@ -1115,8 +1278,8 @@ def isogenies_7_1728(E, minimal_models=True): return [] ts.sort() isogs = [] - from sage.rings.number_field.number_field_base import is_NumberField - model = "minimal" if minimal_models and is_NumberField(F) else None + from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None x = polygen(F) for t0 in ts: s2 = a/t0 @@ -1163,32 +1326,65 @@ def isogenies_13_0(E, minimal_models=True): Endomorphisms of degree 13 will exist when -3 is a square:: + sage: # needs sage.rings.number_field sage: K.<r> = QuadraticField(-3) sage: E = EllipticCurve(K, [0, r]); E - Elliptic Curve defined by y^2 = x^3 + r over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I + Elliptic Curve defined by y^2 = x^3 + r over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I sage: isogenies_13_0(E) - [Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + r over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I to Elliptic Curve defined by y^2 = x^3 + r over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I, - Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + r over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I to Elliptic Curve defined by y^2 = x^3 + r over Number Field in r with defining polynomial x^2 + 3 with r = 1.732050807568878?*I] + [Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + r over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I + to Elliptic Curve defined by y^2 = x^3 + r over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I, + Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + r over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I + to Elliptic Curve defined by y^2 = x^3 + r over Number Field in r + with defining polynomial x^2 + 3 with r = 1.732050807568878?*I] sage: isogenies_13_0(E)[0].rational_maps() - (((7/338*r + 23/338)*x^13 + (-164/13*r - 420/13)*x^10 + (720/13*r + 3168/13)*x^7 + (3840/13*r - 576/13)*x^4 + (4608/13*r + 2304/13)*x)/(x^12 + (4*r + 36)*x^9 + (1080/13*r + 3816/13)*x^6 + (2112/13*r - 5184/13)*x^3 + (-17280/169*r - 1152/169)), ((18/2197*r + 35/2197)*x^18*y + (23142/2197*r + 35478/2197)*x^15*y + (-1127520/2197*r - 1559664/2197)*x^12*y + (-87744/2197*r + 5992704/2197)*x^9*y + (-6625152/2197*r - 9085824/2197)*x^6*y + (-28919808/2197*r - 2239488/2197)*x^3*y + (-1990656/2197*r - 3870720/2197)*y)/(x^18 + (6*r + 54)*x^15 + (3024/13*r + 11808/13)*x^12 + (31296/13*r + 51840/13)*x^9 + (487296/169*r - 2070144/169)*x^6 + (-940032/169*r + 248832/169)*x^3 + (1990656/2197*r + 3870720/2197))) + (((7/338*r + 23/338)*x^13 + (-164/13*r - 420/13)*x^10 + + (720/13*r + 3168/13)*x^7 + (3840/13*r - 576/13)*x^4 + + (4608/13*r + 2304/13)*x)/(x^12 + (4*r + 36)*x^9 + (1080/13*r + 3816/13)*x^6 + + (2112/13*r - 5184/13)*x^3 + (-17280/169*r - 1152/169)), + ((18/2197*r + 35/2197)*x^18*y + (23142/2197*r + 35478/2197)*x^15*y + + (-1127520/2197*r - 1559664/2197)*x^12*y + (-87744/2197*r + 5992704/2197)*x^9*y + + (-6625152/2197*r - 9085824/2197)*x^6*y + (-28919808/2197*r - 2239488/2197)*x^3*y + + (-1990656/2197*r - 3870720/2197)*y)/(x^18 + (6*r + 54)*x^15 + + (3024/13*r + 11808/13)*x^12 + (31296/13*r + 51840/13)*x^9 + + (487296/169*r - 2070144/169)*x^6 + (-940032/169*r + 248832/169)*x^3 + + (1990656/2197*r + 3870720/2197))) An example of endomorphisms over a finite field:: + sage: # needs sage.rings.finite_rings sage: K = GF(19^2,'a') sage: E = EllipticCurve(j=K(0)); E - Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 19^2 + Elliptic Curve defined by y^2 = x^3 + 1 + over Finite Field in a of size 19^2 sage: isogenies_13_0(E) - [Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 19^2 to Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 19^2, - Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 19^2 to Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 19^2] + [Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 19^2 + to Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 19^2, + Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 19^2 + to Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 19^2] sage: isogenies_13_0(E)[0].rational_maps() - ((6*x^13 - 6*x^10 - 3*x^7 + 6*x^4 + x)/(x^12 - 5*x^9 - 9*x^6 - 7*x^3 + 5), (-8*x^18*y - 9*x^15*y + 9*x^12*y - 5*x^9*y + 5*x^6*y - 7*x^3*y + 7*y)/(x^18 + 2*x^15 + 3*x^12 - x^9 + 8*x^6 - 9*x^3 + 7)) + ((6*x^13 - 6*x^10 - 3*x^7 + 6*x^4 + x)/(x^12 - 5*x^9 - 9*x^6 - 7*x^3 + 5), + (-8*x^18*y - 9*x^15*y + 9*x^12*y - 5*x^9*y + + 5*x^6*y - 7*x^3*y + 7*y)/(x^18 + 2*x^15 + 3*x^12 - x^9 + 8*x^6 - 9*x^3 + 7)) A previous implementation did not work in some characteristics:: sage: K = GF(29) sage: E = EllipticCurve(j=K(0)) sage: isogenies_13_0(E) - [Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 29 to Elliptic Curve defined by y^2 = x^3 + 26*x + 12 over Finite Field of size 29, Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 29 to Elliptic Curve defined by y^2 = x^3 + 16*x + 28 over Finite Field of size 29] + [Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 29 + to Elliptic Curve defined by y^2 = x^3 + 26*x + 12 over Finite Field of size 29, + Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 29 + to Elliptic Curve defined by y^2 = x^3 + 16*x + 28 over Finite Field of size 29] :: @@ -1202,13 +1398,14 @@ def isogenies_13_0(E, minimal_models=True): sage: x = polygen(QQ) sage: f = x^12 + 78624*x^9 - 130308048*x^6 + 2270840832*x^3 - 54500179968 - sage: K.<a> = NumberField(f) - sage: E = EllipticCurve(j=K(0)); E.ainvs() + sage: K.<a> = NumberField(f) # needs sage.rings.number_field + sage: E = EllipticCurve(j=K(0)); E.ainvs() # needs sage.rings.number_field (0, 0, 0, 0, 1) - sage: len([phi.codomain().ainvs() for phi in isogenies_13_0(E)]) # long time (4s) + sage: len([phi.codomain().ainvs() # long time # needs sage.rings.number_field + ....: for phi in isogenies_13_0(E)]) 2 """ - if E.j_invariant()!=0: + if E.j_invariant() != 0: raise ValueError("j-invariant must be 0.") F = E.base_field() if F.characteristic() in [2,3,13]: @@ -1216,8 +1413,8 @@ def isogenies_13_0(E, minimal_models=True): Ew = E.short_weierstrass_model() iso = E.isomorphism_to(Ew) a = Ew.a6() - from sage.rings.number_field.number_field_base import is_NumberField - model = "minimal" if minimal_models and is_NumberField(F) else None + from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None x = polygen(F) # there will be 2 endomorphisms if -3 is a square: @@ -1280,12 +1477,20 @@ def isogenies_13_1728(E, minimal_models=True): sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_13_1728 - sage: K.<i> = QuadraticField(-1) - sage: E = EllipticCurve([0,0,0,i,0]); E.ainvs() + sage: K.<i> = QuadraticField(-1) # needs sage.rings.number_field + sage: E = EllipticCurve([0,0,0,i,0]); E.ainvs() # needs sage.rings.number_field (0, 0, 0, i, 0) - sage: isogenies_13_1728(E) - [Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + i*x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I to Elliptic Curve defined by y^2 = x^3 + i*x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I, - Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + i*x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I to Elliptic Curve defined by y^2 = x^3 + i*x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I] + sage: isogenies_13_1728(E) # needs sage.rings.number_field + [Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + i*x over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I + to Elliptic Curve defined by y^2 = x^3 + i*x over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I, + Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + i*x over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I + to Elliptic Curve defined by y^2 = x^3 + i*x over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I] :: @@ -1298,35 +1503,54 @@ def isogenies_13_1728(E, minimal_models=True): sage: E = EllipticCurve(K, [0,0,0,5,0]); E.ainvs() (0, 0, 0, 5, 0) sage: isogenies_13_1728(E) - [Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 89 to Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 89, - Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 89 to Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 89] + [Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 89 + to Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 89, + Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 89 + to Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 89] :: sage: K = GF(23) sage: E = EllipticCurve(K, [1,0]) sage: isogenies_13_1728(E) - [Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 23 to Elliptic Curve defined by y^2 = x^3 + 16 over Finite Field of size 23, Isogeny of degree 13 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 23 to Elliptic Curve defined by y^2 = x^3 + 7 over Finite Field of size 23] + [Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 23 + to Elliptic Curve defined by y^2 = x^3 + 16 over Finite Field of size 23, + Isogeny of degree 13 + from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 23 + to Elliptic Curve defined by y^2 = x^3 + 7 over Finite Field of size 23] :: sage: x = polygen(QQ) - sage: f = x^12 + 1092*x^10 - 432432*x^8 + 6641024*x^6 - 282896640*x^4 - 149879808*x^2 - 349360128 - sage: K.<a> = NumberField(f) - sage: E = EllipticCurve(K, [1,0]) - sage: [phi.codomain().ainvs() for phi in isogenies_13_1728(E)] # long time (3s) + sage: f = (x^12 + 1092*x^10 - 432432*x^8 + 6641024*x^6 + ....: - 282896640*x^4 - 149879808*x^2 - 349360128) + sage: K.<a> = NumberField(f) # needs sage.rings.number_field + sage: E = EllipticCurve(K, [1,0]) # needs sage.rings.number_field + sage: [phi.codomain().ainvs() # long time # needs sage.rings.number_field + ....: for phi in isogenies_13_1728(E)] [(0, - 0, - 0, - -4225010072113/3063768069807341568*a^10 - 24841071989413/15957125363579904*a^8 + 11179537789374271/21276167151439872*a^6 - 407474562289492049/47871376090739712*a^4 + 1608052769560747/4522994717568*a^2 + 7786720245212809/36937790193472, - -363594277511/574456513088876544*a^11 - 7213386922793/2991961005671232*a^9 - 2810970361185589/1329760446964992*a^7 + 281503836888046601/8975883017013696*a^5 - 1287313166530075/848061509544*a^3 + 9768837984886039/6925835661276*a), - (0, - 0, - 0, - -4225010072113/3063768069807341568*a^10 - 24841071989413/15957125363579904*a^8 + 11179537789374271/21276167151439872*a^6 - 407474562289492049/47871376090739712*a^4 + 1608052769560747/4522994717568*a^2 + 7786720245212809/36937790193472, - 363594277511/574456513088876544*a^11 + 7213386922793/2991961005671232*a^9 + 2810970361185589/1329760446964992*a^7 - 281503836888046601/8975883017013696*a^5 + 1287313166530075/848061509544*a^3 - 9768837984886039/6925835661276*a)] + 0, + 0, + -4225010072113/3063768069807341568*a^10 - 24841071989413/15957125363579904*a^8 + + 11179537789374271/21276167151439872*a^6 - 407474562289492049/47871376090739712*a^4 + + 1608052769560747/4522994717568*a^2 + 7786720245212809/36937790193472, + -363594277511/574456513088876544*a^11 - 7213386922793/2991961005671232*a^9 + - 2810970361185589/1329760446964992*a^7 + 281503836888046601/8975883017013696*a^5 + - 1287313166530075/848061509544*a^3 + 9768837984886039/6925835661276*a), + (0, + 0, + 0, + -4225010072113/3063768069807341568*a^10 - 24841071989413/15957125363579904*a^8 + + 11179537789374271/21276167151439872*a^6 - 407474562289492049/47871376090739712*a^4 + + 1608052769560747/4522994717568*a^2 + 7786720245212809/36937790193472, + 363594277511/574456513088876544*a^11 + 7213386922793/2991961005671232*a^9 + + 2810970361185589/1329760446964992*a^7 - 281503836888046601/8975883017013696*a^5 + + 1287313166530075/848061509544*a^3 - 9768837984886039/6925835661276*a)] """ - if E.j_invariant()!=1728: + if E.j_invariant() != 1728: raise ValueError("j-invariant must be 1728.") F = E.base_field() if F.characteristic() in [2, 3, 13]: @@ -1334,8 +1558,8 @@ def isogenies_13_1728(E, minimal_models=True): Ew = E.short_weierstrass_model() iso = E.isomorphism_to(Ew) a = Ew.a4() - from sage.rings.number_field.number_field_base import is_NumberField - model = "minimal" if minimal_models and is_NumberField(F) else None + from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None x = polygen(F) # we will have two endomorphisms if -1 is a square: @@ -1412,7 +1636,7 @@ def _hyperelliptic_isogeny_data(l): ValueError: 37 must be one of [11, 17, 19, 23, 29, 31, 41, 47, 59, 71]. """ if l not in hyperelliptic_primes: - raise ValueError("%s must be one of %s."%(l,hyperelliptic_primes)) + raise ValueError("%s must be one of %s." % (l,hyperelliptic_primes)) data = {} Zu = PolynomialRing(ZZ,'u') Zuv = PolynomialRing(ZZ,['u','v']) @@ -1537,7 +1761,12 @@ def Psi2(l): sage: from sage.schemes.elliptic_curves.isogeny_small_degree import Psi2 sage: Psi2(11) - x^5 - 55*x^4*u + 994*x^3*u^2 - 8774*x^2*u^3 + 41453*x*u^4 - 928945/11*u^5 + 33*x^4 + 276*x^3*u - 7794*x^2*u^2 + 4452*x*u^3 + 1319331/11*u^4 + 216*x^3*v - 4536*x^2*u*v + 31752*x*u^2*v - 842616/11*u^3*v + 162*x^3 + 38718*x^2*u - 610578*x*u^2 + 33434694/11*u^3 - 4536*x^2*v + 73872*x*u*v - 2745576/11*u^2*v - 16470*x^2 + 580068*x*u - 67821354/11*u^2 - 185976*x*v + 14143896/11*u*v + 7533*x - 20437029/11*u - 12389112/11*v + 19964151/11 + x^5 - 55*x^4*u + 994*x^3*u^2 - 8774*x^2*u^3 + 41453*x*u^4 - 928945/11*u^5 + + 33*x^4 + 276*x^3*u - 7794*x^2*u^2 + 4452*x*u^3 + 1319331/11*u^4 + 216*x^3*v + - 4536*x^2*u*v + 31752*x*u^2*v - 842616/11*u^3*v + 162*x^3 + 38718*x^2*u + - 610578*x*u^2 + 33434694/11*u^3 - 4536*x^2*v + 73872*x*u*v - 2745576/11*u^2*v + - 16470*x^2 + 580068*x*u - 67821354/11*u^2 - 185976*x*v + 14143896/11*u*v + + 7533*x - 20437029/11*u - 12389112/11*v + 19964151/11 sage: p = Psi2(71) # long time sage: (x,u,v) = p.variables() # long time sage: p.coefficient({x: 0, u: 210, v: 0}) # long time @@ -1622,62 +1851,151 @@ def isogenies_prime_degree_genus_plus_0(E, l=None, minimal_models=True): sage: E = EllipticCurve('121a1') sage: isogenies_prime_degree_genus_plus_0(E, 11) - [Isogeny of degree 11 from Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 30*x - 76 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 305*x + 7888 over Rational Field] + [Isogeny of degree 11 + from Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 30*x - 76 + over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 305*x + 7888 + over Rational Field] sage: E = EllipticCurve([1, 1, 0, -660, -7600]) sage: isogenies_prime_degree_genus_plus_0(E, 17) - [Isogeny of degree 17 from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 660*x - 7600 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 878710*x + 316677750 over Rational Field] + [Isogeny of degree 17 + from Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 660*x - 7600 + over Rational Field + to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 878710*x + 316677750 + over Rational Field] sage: E = EllipticCurve([0, 0, 1, -1862, -30956]) sage: isogenies_prime_degree_genus_plus_0(E, 19) - [Isogeny of degree 19 from Elliptic Curve defined by y^2 + y = x^3 - 1862*x - 30956 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - 672182*x + 212325489 over Rational Field] + [Isogeny of degree 19 + from Elliptic Curve defined by y^2 + y = x^3 - 1862*x - 30956 + over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - 672182*x + 212325489 + over Rational Field] + sage: # needs sage.rings.number_field sage: K = QuadraticField(-295,'a') sage: a = K.gen() sage: E = EllipticCurve_from_j(-484650135/16777216*a + 4549855725/16777216) sage: isogenies_prime_degree_genus_plus_0(E, 23) - [Isogeny of degree 23 from Elliptic Curve defined by y^2 = x^3 + (-14460494784192904095/140737488355328*a+270742665778826768325/140737488355328)*x + (37035998788154488846811217135/590295810358705651712*a-1447451882571839266752561148725/590295810358705651712) over Number Field in a with defining polynomial x^2 + 295 with a = 17.17556403731767?*I to Elliptic Curve defined by y^2 = x^3 + (-5130542435555445498495/140737488355328*a+173233955029127361005925/140737488355328)*x + (-1104699335561165691575396879260545/590295810358705651712*a+3169785826904210171629535101419675/590295810358705651712) over Number Field in a with defining polynomial x^2 + 295 with a = 17.17556403731767?*I] - + [Isogeny of degree 23 + from Elliptic Curve defined by + y^2 = x^3 + (-14460494784192904095/140737488355328*a+270742665778826768325/140737488355328)*x + + (37035998788154488846811217135/590295810358705651712*a-1447451882571839266752561148725/590295810358705651712) + over Number Field in a with defining polynomial x^2 + 295 + with a = 17.17556403731767?*I + to Elliptic Curve defined by + y^2 = x^3 + (-5130542435555445498495/140737488355328*a+173233955029127361005925/140737488355328)*x + + (-1104699335561165691575396879260545/590295810358705651712*a+3169785826904210171629535101419675/590295810358705651712) + over Number Field in a with defining polynomial x^2 + 295 + with a = 17.17556403731767?*I] + + sage: # needs sage.rings.number_field sage: K = QuadraticField(-199,'a') sage: a = K.gen() sage: E = EllipticCurve_from_j(94743000*a + 269989875) sage: isogenies_prime_degree_genus_plus_0(E, 29) - [Isogeny of degree 29 from Elliptic Curve defined by y^2 = x^3 + (-153477413215038000*a+5140130723072965125)*x + (297036215130547008455526000*a+2854277047164317800973582250) over Number Field in a with defining polynomial x^2 + 199 with a = 14.106735979665884?*I to Elliptic Curve defined by y^2 = x^3 + (251336161378040805000*a-3071093219933084341875)*x + (-8411064283162168580187643221000*a+34804337770798389546017184785250) over Number Field in a with defining polynomial x^2 + 199 with a = 14.106735979665884?*I] - + [Isogeny of degree 29 + from Elliptic Curve defined by + y^2 = x^3 + (-153477413215038000*a+5140130723072965125)*x + + (297036215130547008455526000*a+2854277047164317800973582250) + over Number Field in a with defining polynomial x^2 + 199 + with a = 14.106735979665884?*I + to Elliptic Curve defined by + y^2 = x^3 + (251336161378040805000*a-3071093219933084341875)*x + + (-8411064283162168580187643221000*a+34804337770798389546017184785250) + over Number Field in a with defining polynomial x^2 + 199 + with a = 14.106735979665884?*I] + + sage: # needs sage.rings.number_field sage: K = QuadraticField(253,'a') sage: a = K.gen() sage: E = EllipticCurve_from_j(208438034112000*a - 3315409892960000) sage: isogenies_prime_degree_genus_plus_0(E, 31) - [Isogeny of degree 31 from Elliptic Curve defined by y^2 = x^3 + (4146345122185433034677956608000*a-65951656549965037259634800640000)*x + (-18329111516954473474583425393698245080252416000*a+291542366110383928366510368064204147260129280000) over Number Field in a with defining polynomial x^2 - 253 with a = 15.905973720586867? to Elliptic Curve defined by y^2 = x^3 + (200339763852548615776123686912000*a-3186599019027216904280948275200000)*x + (7443671791411479629112717260182286294850207744000*a-118398847898864757209685951728838895495168655360000) over Number Field in a with defining polynomial x^2 - 253 with a = 15.905973720586867?] + [Isogeny of degree 31 + from Elliptic Curve defined by + y^2 = x^3 + (4146345122185433034677956608000*a-65951656549965037259634800640000)*x + + (-18329111516954473474583425393698245080252416000*a+291542366110383928366510368064204147260129280000) + over Number Field in a with defining polynomial x^2 - 253 + with a = 15.905973720586867? + to Elliptic Curve defined by + y^2 = x^3 + (200339763852548615776123686912000*a-3186599019027216904280948275200000)*x + + (7443671791411479629112717260182286294850207744000*a-118398847898864757209685951728838895495168655360000) + over Number Field in a with defining polynomial x^2 - 253 + with a = 15.905973720586867?] sage: E = EllipticCurve_from_j(GF(5)(1)) sage: isogenies_prime_degree_genus_plus_0(E, 41) - [Isogeny of degree 41 from Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 5 to Elliptic Curve defined by y^2 = x^3 + x + 3 over Finite Field of size 5, Isogeny of degree 41 from Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 5 to Elliptic Curve defined by y^2 = x^3 + x + 3 over Finite Field of size 5] - + [Isogeny of degree 41 + from Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 5 + to Elliptic Curve defined by y^2 = x^3 + x + 3 over Finite Field of size 5, + Isogeny of degree 41 + from Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 5 + to Elliptic Curve defined by y^2 = x^3 + x + 3 over Finite Field of size 5] + + sage: # needs sage.rings.number_field sage: K = QuadraticField(5,'a') sage: a = K.gen() - sage: E = EllipticCurve_from_j(184068066743177379840*a - 411588709724712960000) - sage: isogenies_prime_degree_genus_plus_0(E, 47) # long time (2s) - [Isogeny of degree 47 from Elliptic Curve defined by y^2 = x^3 + (454562028554080355857852049849975895490560*a-1016431595837124114668689286176511361024000)*x + (-249456798429896080881440540950393713303830363999480904280965120*a+557802358738710443451273320227578156598454035482869042774016000) over Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? to Elliptic Curve defined by y^2 = x^3 + (39533118442361013730577638493616965245992960*a-88398740199669828340617478832005245173760000)*x + (214030321479466610282320528611562368963830105830555363061803253760*a-478586348074220699687616322532666163722004497458452316582576128000) over Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?] - - sage: K = QuadraticField(-66827,'a') - sage: a = K.gen() - sage: E = EllipticCurve_from_j(-98669236224000*a + 4401720074240000) + sage: E = EllipticCurve_from_j(184068066743177379840*a + ....: - 411588709724712960000) + sage: isogenies_prime_degree_genus_plus_0(E, 47) # long time + [Isogeny of degree 47 + from Elliptic Curve defined by + y^2 = x^3 + (454562028554080355857852049849975895490560*a-1016431595837124114668689286176511361024000)*x + + (-249456798429896080881440540950393713303830363999480904280965120*a+557802358738710443451273320227578156598454035482869042774016000) + over Number Field in a with defining polynomial x^2 - 5 + with a = 2.236067977499790? + to Elliptic Curve defined by + y^2 = x^3 + (39533118442361013730577638493616965245992960*a-88398740199669828340617478832005245173760000)*x + + (214030321479466610282320528611562368963830105830555363061803253760*a-478586348074220699687616322532666163722004497458452316582576128000) + over Number Field in a with defining polynomial x^2 - 5 + with a = 2.236067977499790?] + + sage: K = QuadraticField(-66827,'a') # needs sage.rings.number_field + sage: a = K.gen() # needs sage.rings.number_field + sage: E = EllipticCurve_from_j(-98669236224000*a + 4401720074240000) # needs sage.rings.number_field sage: isogenies_prime_degree_genus_plus_0(E, 59) # long time (5s) - [Isogeny of degree 59 from Elliptic Curve defined by y^2 = x^3 + (2605886146782144762297974784000*a+1893681048912773634944634716160000)*x + (-116918454256410782232296183198067568744071168000*a+17012043538294664027185882358514011304812871680000) over Number Field in a with defining polynomial x^2 + 66827 with a = 258.5091874576221?*I to Elliptic Curve defined by y^2 = x^3 + (-19387084027159786821400775098368000*a-4882059104868154225052787156713472000)*x + (-25659862010101415428713331477227179429538847260672000*a-2596038148441293485938798119003462972840818381946880000) over Number Field in a with defining polynomial x^2 + 66827 with a = 258.5091874576221?*I] + [Isogeny of degree 59 + from Elliptic Curve defined by + y^2 = x^3 + (2605886146782144762297974784000*a+1893681048912773634944634716160000)*x + + (-116918454256410782232296183198067568744071168000*a+17012043538294664027185882358514011304812871680000) + over Number Field in a with defining polynomial x^2 + 66827 + with a = 258.5091874576221?*I + to Elliptic Curve defined by + y^2 = x^3 + (-19387084027159786821400775098368000*a-4882059104868154225052787156713472000)*x + + (-25659862010101415428713331477227179429538847260672000*a-2596038148441293485938798119003462972840818381946880000) + over Number Field in a with defining polynomial x^2 + 66827 + with a = 258.5091874576221?*I] sage: E = EllipticCurve_from_j(GF(13)(5)) sage: isogenies_prime_degree_genus_plus_0(E, 71) - [Isogeny of degree 71 from Elliptic Curve defined by y^2 = x^3 + x + 4 over Finite Field of size 13 to Elliptic Curve defined by y^2 = x^3 + 10*x + 7 over Finite Field of size 13, Isogeny of degree 71 from Elliptic Curve defined by y^2 = x^3 + x + 4 over Finite Field of size 13 to Elliptic Curve defined by y^2 = x^3 + 10*x + 7 over Finite Field of size 13] - - sage: E = EllipticCurve(GF(13),[0,1,1,1,0]) + [Isogeny of degree 71 + from Elliptic Curve defined by y^2 = x^3 + x + 4 over Finite Field of size 13 + to Elliptic Curve defined by y^2 = x^3 + 10*x + 7 over Finite Field of size 13, + Isogeny of degree 71 + from Elliptic Curve defined by y^2 = x^3 + x + 4 over Finite Field of size 13 + to Elliptic Curve defined by y^2 = x^3 + 10*x + 7 over Finite Field of size 13] + + sage: E = EllipticCurve(GF(13), [0,1,1,1,0]) sage: isogenies_prime_degree_genus_plus_0(E) - [Isogeny of degree 17 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 10*x + 1 over Finite Field of size 13, - Isogeny of degree 17 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 4 over Finite Field of size 13, - Isogeny of degree 29 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 6 over Finite Field of size 13, - Isogeny of degree 29 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 5*x + 6 over Finite Field of size 13, - Isogeny of degree 41 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 4 over Finite Field of size 13, - Isogeny of degree 41 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 5*x + 6 over Finite Field of size 13] + [Isogeny of degree 17 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 10*x + 1 over Finite Field of size 13, + Isogeny of degree 17 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 4 over Finite Field of size 13, + Isogeny of degree 29 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 6 over Finite Field of size 13, + Isogeny of degree 29 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 5*x + 6 over Finite Field of size 13, + Isogeny of degree 41 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 4 over Finite Field of size 13, + Isogeny of degree 41 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 13 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 5*x + 6 over Finite Field of size 13] """ if l is None: return sum([isogenies_prime_degree_genus_plus_0(E, ell, minimal_models=minimal_models) @@ -1764,17 +2082,32 @@ def isogenies_prime_degree_genus_plus_0_j0(E, l, minimal_models=True): sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_prime_degree_genus_plus_0_j0 sage: u = polygen(QQ) - sage: K.<a> = NumberField(u^4+228*u^3+486*u^2-540*u+225) - sage: E = EllipticCurve(K,[0,-121/5*a^3-20691/5*a^2-29403/5*a+3267]) - sage: isogenies_prime_degree_genus_plus_0_j0(E,11) - [Isogeny of degree 11 from Elliptic Curve defined by y^2 = x^3 + (-121/5*a^3-20691/5*a^2-29403/5*a+3267) over Number Field in a with defining polynomial x^4 + 228*x^3 + 486*x^2 - 540*x + 225 to Elliptic Curve defined by y^2 = x^3 + (-44286*a^2+178596*a-32670)*x + (-17863351/5*a^3+125072739/5*a^2-74353653/5*a-682803) over Number Field in a with defining polynomial x^4 + 228*x^3 + 486*x^2 - 540*x + 225, Isogeny of degree 11 from Elliptic Curve defined by y^2 = x^3 + (-121/5*a^3-20691/5*a^2-29403/5*a+3267) over Number Field in a with defining polynomial x^4 + 228*x^3 + 486*x^2 - 540*x + 225 to Elliptic Curve defined by y^2 = x^3 + (-3267*a^3-740157*a^2+600039*a-277695)*x + (-17863351/5*a^3-4171554981/5*a^2+3769467867/5*a-272366523) over Number Field in a with defining polynomial x^4 + 228*x^3 + 486*x^2 - 540*x + 225] + sage: K.<a> = NumberField(u^4 + 228*u^3 + 486*u^2 - 540*u + 225) # needs sage.rings.number_field + sage: E = EllipticCurve(K, [0, -121/5*a^3 - 20691/5*a^2 - 29403/5*a + 3267]) # needs sage.rings.number_field + sage: isogenies_prime_degree_genus_plus_0_j0(E, 11) # needs sage.rings.number_field + [Isogeny of degree 11 + from Elliptic Curve defined by + y^2 = x^3 + (-121/5*a^3-20691/5*a^2-29403/5*a+3267) over + Number Field in a with defining polynomial x^4 + 228*x^3 + 486*x^2 - 540*x + 225 + to Elliptic Curve defined by + y^2 = x^3 + (-44286*a^2+178596*a-32670)*x + + (-17863351/5*a^3+125072739/5*a^2-74353653/5*a-682803) over + Number Field in a with defining polynomial x^4 + 228*x^3 + 486*x^2 - 540*x + 225, + Isogeny of degree 11 + from Elliptic Curve defined by + y^2 = x^3 + (-121/5*a^3-20691/5*a^2-29403/5*a+3267) over + Number Field in a with defining polynomial x^4 + 228*x^3 + 486*x^2 - 540*x + 225 + to Elliptic Curve defined by + y^2 = x^3 + (-3267*a^3-740157*a^2+600039*a-277695)*x + + (-17863351/5*a^3-4171554981/5*a^2+3769467867/5*a-272366523) over + Number Field in a with defining polynomial x^4 + 228*x^3 + 486*x^2 - 540*x + 225] sage: E = EllipticCurve(GF(5^6,'a'),[0,1]) sage: isogenies_prime_degree_genus_plus_0_j0(E,17) [Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in a of size 5^6 to Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field in a of size 5^6] """ if l not in hyperelliptic_primes: - raise ValueError("%s must be one of %s."%(l,hyperelliptic_primes)) + raise ValueError("%s must be one of %s." % (l,hyperelliptic_primes)) F = E.base_field() if E.j_invariant() != 0: raise ValueError(("j-invariant must be 0.")) @@ -1850,22 +2183,54 @@ def isogenies_prime_degree_genus_plus_0_j1728(E, l, minimal_models=True): sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_prime_degree_genus_plus_0_j1728 + sage: # needs sage.rings.number_field sage: u = polygen(QQ) - sage: K.<a> = NumberField(u^6 - 522*u^5 - 10017*u^4 + 2484*u^3 - 5265*u^2 + 12150*u - 5103) - sage: E = EllipticCurve(K,[-75295/1335852*a^5+13066735/445284*a^4+44903485/74214*a^3+17086861/24738*a^2+11373021/16492*a-1246245/2356,0]) - sage: isogenies_prime_degree_genus_plus_0_j1728(E,11) - [Isogeny of degree 11 from Elliptic Curve defined by y^2 = x^3 + (-75295/1335852*a^5+13066735/445284*a^4+44903485/74214*a^3+17086861/24738*a^2+11373021/16492*a-1246245/2356)*x over Number Field in a with defining polynomial x^6 - 522*x^5 - 10017*x^4 + 2484*x^3 - 5265*x^2 + 12150*x - 5103 to Elliptic Curve defined by y^2 = x^3 + (9110695/1335852*a^5-1581074935/445284*a^4-5433321685/74214*a^3-3163057249/24738*a^2+1569269691/16492*a+73825125/2356)*x + (-3540460*a^3+30522492*a^2-7043652*a-5031180) over Number Field in a with defining polynomial x^6 - 522*x^5 - 10017*x^4 + 2484*x^3 - 5265*x^2 + 12150*x - 5103, Isogeny of degree 11 from Elliptic Curve defined by y^2 = x^3 + (-75295/1335852*a^5+13066735/445284*a^4+44903485/74214*a^3+17086861/24738*a^2+11373021/16492*a-1246245/2356)*x over Number Field in a with defining polynomial x^6 - 522*x^5 - 10017*x^4 + 2484*x^3 - 5265*x^2 + 12150*x - 5103 to Elliptic Curve defined by y^2 = x^3 + (9110695/1335852*a^5-1581074935/445284*a^4-5433321685/74214*a^3-3163057249/24738*a^2+1569269691/16492*a+73825125/2356)*x + (3540460*a^3-30522492*a^2+7043652*a+5031180) over Number Field in a with defining polynomial x^6 - 522*x^5 - 10017*x^4 + 2484*x^3 - 5265*x^2 + 12150*x - 5103] + sage: K.<a> = NumberField(u^6 - 522*u^5 - 10017*u^4 + ....: + 2484*u^3 - 5265*u^2 + 12150*u - 5103) + sage: E = EllipticCurve(K, [-75295/1335852*a^5 + 13066735/445284*a^4 + ....: + 44903485/74214*a^3 + 17086861/24738*a^2 + ....: + 11373021/16492*a - 1246245/2356, 0]) + sage: isogenies_prime_degree_genus_plus_0_j1728(E, 11) + [Isogeny of degree 11 + from Elliptic Curve defined by + y^2 = x^3 + (-75295/1335852*a^5+13066735/445284*a^4+44903485/74214*a^3+17086861/24738*a^2+11373021/16492*a-1246245/2356)*x + over Number Field in a with defining polynomial + x^6 - 522*x^5 - 10017*x^4 + 2484*x^3 - 5265*x^2 + 12150*x - 5103 + to Elliptic Curve defined by + y^2 = x^3 + (9110695/1335852*a^5-1581074935/445284*a^4-5433321685/74214*a^3-3163057249/24738*a^2+1569269691/16492*a+73825125/2356)*x + + (-3540460*a^3+30522492*a^2-7043652*a-5031180) + over Number Field in a with defining polynomial + x^6 - 522*x^5 - 10017*x^4 + 2484*x^3 - 5265*x^2 + 12150*x - 5103, + Isogeny of degree 11 + from Elliptic Curve defined by + y^2 = x^3 + (-75295/1335852*a^5+13066735/445284*a^4+44903485/74214*a^3+17086861/24738*a^2+11373021/16492*a-1246245/2356)*x + over Number Field in a with defining polynomial + x^6 - 522*x^5 - 10017*x^4 + 2484*x^3 - 5265*x^2 + 12150*x - 5103 + to Elliptic Curve defined by + y^2 = x^3 + (9110695/1335852*a^5-1581074935/445284*a^4-5433321685/74214*a^3-3163057249/24738*a^2+1569269691/16492*a+73825125/2356)*x + + (3540460*a^3-30522492*a^2+7043652*a+5031180) + over Number Field in a with defining polynomial + x^6 - 522*x^5 - 10017*x^4 + 2484*x^3 - 5265*x^2 + 12150*x - 5103] sage: i = QuadraticField(-1,'i').gen() - sage: E = EllipticCurve([-1-2*i,0]) - sage: isogenies_prime_degree_genus_plus_0_j1728(E,17) - [Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + (-2*i-1)*x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I to Elliptic Curve defined by y^2 = x^3 + (-82*i-641)*x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I, - Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + (-2*i-1)*x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I to Elliptic Curve defined by y^2 = x^3 + (-562*i+319)*x over Number Field in i with defining polynomial x^2 + 1 with i = 1*I] + sage: E = EllipticCurve([-1 - 2*i, 0]) + sage: isogenies_prime_degree_genus_plus_0_j1728(E, 17) + [Isogeny of degree 17 + from Elliptic Curve defined by y^2 = x^3 + (-2*i-1)*x + over Number Field in i with defining polynomial x^2 + 1 with i = 1*I + to Elliptic Curve defined by y^2 = x^3 + (-82*i-641)*x + over Number Field in i with defining polynomial x^2 + 1 with i = 1*I, + Isogeny of degree 17 + from Elliptic Curve defined by y^2 = x^3 + (-2*i-1)*x + over Number Field in i with defining polynomial x^2 + 1 with i = 1*I + to Elliptic Curve defined by y^2 = x^3 + (-562*i+319)*x + over Number Field in i with defining polynomial x^2 + 1 with i = 1*I] sage: Emin = E.global_minimal_model() - sage: [(p,len(isogenies_prime_degree_genus_plus_0_j1728(Emin,p))) for p in [17, 29, 41]] + sage: [(p, len(isogenies_prime_degree_genus_plus_0_j1728(Emin, p))) + ....: for p in [17, 29, 41]] [(17, 2), (29, 2), (41, 2)] """ if l not in hyperelliptic_primes: - raise ValueError("%s must be one of %s."%(l,hyperelliptic_primes)) + raise ValueError("%s must be one of %s." % (l,hyperelliptic_primes)) F = E.base_ring() if E.j_invariant() != 1728: raise ValueError("j-invariant must be 1728.") @@ -1985,9 +2350,9 @@ def is_kernel_polynomial(E, m, f): sage: from sage.schemes.elliptic_curves.isogeny_small_degree import is_kernel_polynomial sage: E = EllipticCurve([0, -1, 1, -10, -20]) sage: x = polygen(QQ) - sage: is_kernel_polynomial(E,5,x^2 + x - 29/5) + sage: is_kernel_polynomial(E, 5, x^2 + x - 29/5) True - sage: is_kernel_polynomial(E,5,(x - 16) * (x - 5)) + sage: is_kernel_polynomial(E, 5, (x - 16) * (x - 5)) True An example from [KT2013]_, where the 13-division polynomial splits @@ -1995,12 +2360,12 @@ def is_kernel_polynomial(E, m, f): kernel polynomial for a 13-isogeny:: sage: F = GF(3) - sage: E = EllipticCurve(F,[0,0,0,-1,0]) + sage: E = EllipticCurve(F, [0,0,0,-1,0]) sage: f13 = E.division_polynomial(13) - sage: factors = [f for f,e in f13.factor()] + sage: factors = [f for f, e in f13.factor()] sage: all(f.degree() == 6 for f in factors) True - sage: [is_kernel_polynomial(E,13,f) for f in factors] + sage: [is_kernel_polynomial(E, 13, f) for f in factors] [True, True, False, @@ -2018,7 +2383,8 @@ def is_kernel_polynomial(E, m, f): See :trac:`22232`:: - sage: K =GF(47^2) + sage: # needs sage.rings.finite_rings + sage: K = GF(47^2) sage: E = EllipticCurve([0, K.gen()]) sage: psi7 = E.division_polynomial(7) sage: f = psi7.factor()[4][0] @@ -2026,7 +2392,7 @@ def is_kernel_polynomial(E, m, f): x^3 + (7*z2 + 11)*x^2 + (25*z2 + 33)*x + 25*z2 sage: f.divides(psi7) True - sage: is_kernel_polynomial(E,7, f) + sage: is_kernel_polynomial(E, 7, f) False """ m2 = m // 2 @@ -2045,14 +2411,18 @@ def is_kernel_polynomial(E, m, f): if m == 2 or m == 3: return True - # For each a in a set of generators of (Z/mZ)^* we check that the - # multiplication-by-a map permutes the roots of f. It would be - # enough to take a generating (Z/mZ)^*/{1,-1} but that is not - # implemented. If m is prime (or more generally, has a primitive - # root) then only one a will be needed. + # For each a in a set of generators of (Z/mZ)^*/{1,-1} we check + # that the multiplication-by-a map permutes the roots of f. + # If m is prime (or more generally, has a primitive root) then + # only one a will be needed. - from sage.rings.finite_rings.integer_mod_ring import Integers - for a in Integers(m).unit_gens(): + if m & 1 and m.is_prime_power(): + gens = _least_semi_primitive(m), + else: + from sage.rings.finite_rings.integer_mod_ring import Integers + gens = Integers(m).unit_gens() + + for a in gens: mu = E.multiplication_by_m(a, x_only=True) if f( S(mu.numerator()) / S(mu.denominator()) ) != 0: return False @@ -2092,27 +2462,57 @@ def isogenies_prime_degree_general(E, l, minimal_models=True): EXAMPLES:: sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_prime_degree_general - sage: E = EllipticCurve_from_j(GF(2^6,'a')(1)) - sage: isogenies_prime_degree_general(E, 7) - [Isogeny of degree 7 from Elliptic Curve defined by y^2 + x*y = x^3 + 1 over Finite Field in a of size 2^6 to Elliptic Curve defined by y^2 + x*y = x^3 + x over Finite Field in a of size 2^6] - sage: E = EllipticCurve_from_j(GF(3^12,'a')(2)) - sage: isogenies_prime_degree_general(E, 17) - [Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2 over Finite Field in a of size 3^12 to Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2*x over Finite Field in a of size 3^12, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2 over Finite Field in a of size 3^12 to Elliptic Curve defined by y^2 = x^3 + 2*x^2 + x + 2 over Finite Field in a of size 3^12] + sage: E = EllipticCurve_from_j(GF(2^6,'a')(1)) # needs sage.rings.finite_rings + sage: isogenies_prime_degree_general(E, 7) # needs sage.rings.finite_rings + [Isogeny of degree 7 + from Elliptic Curve defined by y^2 + x*y = x^3 + 1 + over Finite Field in a of size 2^6 + to Elliptic Curve defined by y^2 + x*y = x^3 + x + over Finite Field in a of size 2^6] + sage: E = EllipticCurve_from_j(GF(3^12,'a')(2)) # needs sage.rings.finite_rings + sage: isogenies_prime_degree_general(E, 17) # needs sage.rings.finite_rings + [Isogeny of degree 17 + from Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2 + over Finite Field in a of size 3^12 + to Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2*x + over Finite Field in a of size 3^12, + Isogeny of degree 17 + from Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2 + over Finite Field in a of size 3^12 + to Elliptic Curve defined by y^2 = x^3 + 2*x^2 + x + 2 + over Finite Field in a of size 3^12] sage: E = EllipticCurve('50a1') sage: isogenies_prime_degree_general(E, 3) - [Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - 126*x - 552 over Rational Field] + [Isogeny of degree 3 + from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 - 126*x - 552 + over Rational Field] sage: isogenies_prime_degree_general(E, 5) - [Isogeny of degree 5 from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - 76*x + 298 over Rational Field] + [Isogeny of degree 5 + from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 - 76*x + 298 + over Rational Field] sage: E = EllipticCurve([0, 0, 1, -1862, -30956]) sage: isogenies_prime_degree_general(E, 19) - [Isogeny of degree 19 from Elliptic Curve defined by y^2 + y = x^3 - 1862*x - 30956 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - 672182*x + 212325489 over Rational Field] + [Isogeny of degree 19 + from Elliptic Curve defined by y^2 + y = x^3 - 1862*x - 30956 + over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - 672182*x + 212325489 + over Rational Field] sage: E = EllipticCurve([0, -1, 0, -6288, 211072]) sage: isogenies_prime_degree_general(E, 37) # long time (2s) - [Isogeny of degree 37 from Elliptic Curve defined by y^2 = x^3 - x^2 - 6288*x + 211072 over Rational Field to Elliptic Curve defined by y^2 = x^3 - x^2 - 163137088*x - 801950801728 over Rational Field] + [Isogeny of degree 37 + from Elliptic Curve defined by y^2 = x^3 - x^2 - 6288*x + 211072 + over Rational Field + to Elliptic Curve defined by y^2 = x^3 - x^2 - 163137088*x - 801950801728 + over Rational Field] sage: E = EllipticCurve([-3440, 77658]) sage: isogenies_prime_degree_general(E, 43) # long time (2s) - [Isogeny of degree 43 from Elliptic Curve defined by y^2 = x^3 - 3440*x + 77658 over Rational Field to Elliptic Curve defined by y^2 = x^3 - 6360560*x - 6174354606 over Rational Field] + [Isogeny of degree 43 + from Elliptic Curve defined by y^2 = x^3 - 3440*x + 77658 over Rational Field + to Elliptic Curve defined by y^2 = x^3 - 6360560*x - 6174354606 + over Rational Field] Isogenies of degree equal to the characteristic are computed (but only the separable isogeny). In the following example we consider @@ -2125,11 +2525,29 @@ def isogenies_prime_degree_general(E, l, minimal_models=True): ....: E = EllipticCurve(GF(l),ainvs) ....: isogenies_prime_degree_general(E,l) [] - [Isogeny of degree 3 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 2*x + 2 over Finite Field of size 3 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 3] - [Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4*x + 4 over Finite Field of size 5 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4*x + 4 over Finite Field of size 5] - [Isogeny of degree 7 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 6*x + 6 over Finite Field of size 7 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4 over Finite Field of size 7] - [Isogeny of degree 11 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 10*x + 10 over Finite Field of size 11 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + x + 1 over Finite Field of size 11] - [Isogeny of degree 13 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 12 over Finite Field of size 13 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 12 over Finite Field of size 13] + [Isogeny of degree 3 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 2*x + 2 + over Finite Field of size 3 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 3] + [Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4*x + 4 + over Finite Field of size 5 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4*x + 4 + over Finite Field of size 5] + [Isogeny of degree 7 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 6*x + 6 + over Finite Field of size 7 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4 over Finite Field of size 7] + [Isogeny of degree 11 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 10*x + 10 + over Finite Field of size 11 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + x + 1 + over Finite Field of size 11] + [Isogeny of degree 13 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 12 + over Finite Field of size 13 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 12 + over Finite Field of size 13] [Isogeny of degree 17 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 16*x + 16 over Finite Field of size 17 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 15 over Finite Field of size 17] [Isogeny of degree 19 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 18*x + 18 over Finite Field of size 19 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 3*x + 12 over Finite Field of size 19] [Isogeny of degree 23 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 22*x + 22 over Finite Field of size 23 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 22*x + 22 over Finite Field of size 23] @@ -2140,16 +2558,16 @@ def isogenies_prime_degree_general(E, l, minimal_models=True): [Isogeny of degree 43 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 42*x + 42 over Finite Field of size 43 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 36 over Finite Field of size 43] [Isogeny of degree 47 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 46*x + 46 over Finite Field of size 47 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 42*x + 34 over Finite Field of size 47] - Note that not all factors of degree (l-1)/2 of the l-division + Note that not all factors of degree `(l-1)/2` of the `l`-division polynomial are kernel polynomials. In this example, the 13-division polynomial factors as a product of 14 irreducible factors of degree 6 each, but only two those are kernel polynomials:: sage: F3 = GF(3) - sage: E = EllipticCurve(F3,[0,0,0,-1,0]) + sage: E = EllipticCurve(F3, [0,0,0,-1,0]) sage: Psi13 = E.division_polynomial(13) - sage: len([f for f,e in Psi13.factor() if f.degree()==6]) + sage: len([f for f, e in Psi13.factor() if f.degree() == 6]) 14 sage: len(E.isogenies_prime_degree(13)) 2 @@ -2158,15 +2576,17 @@ def isogenies_prime_degree_general(E, l, minimal_models=True): cubics which can be rearranged to give the remaining 12 kernel polynomials:: - sage: len(E.change_ring(GF(3^2,'a')).isogenies_prime_degree(13)) + sage: len(E.change_ring(GF(3^2,'a')).isogenies_prime_degree(13)) # needs sage.rings.finite_rings 14 See :trac:`18589`: the following example took 20s before, now only 4s:: - sage: K.<i> = QuadraticField(-1) - sage: E = EllipticCurve(K,[0,0,0,1,0]) - sage: [phi.codomain().ainvs() for phi in E.isogenies_prime_degree(37)] # long time (6s) - [(0, 0, 0, -840*i + 1081, 0), (0, 0, 0, 840*i + 1081, 0)] + sage: K.<i> = QuadraticField(-1) # needs sage.rings.number_field + sage: E = EllipticCurve(K,[0,0,0,1,0]) # needs sage.rings.number_field + sage: [phi.codomain().ainvs() # long time # needs sage.rings.number_field + ....: for phi in E.isogenies_prime_degree(37)] + [(0, 0, 0, -840*i + 1081, 0), + (0, 0, 0, 840*i + 1081, 0)] """ if not l.is_prime(): raise ValueError("%s is not prime." % l) @@ -2266,23 +2686,48 @@ def isogenies_prime_degree(E, l, minimal_models=True): EXAMPLES:: sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_prime_degree - sage: E = EllipticCurve_from_j(GF(2^6,'a')(1)) - sage: isogenies_prime_degree(E, 7) - [Isogeny of degree 7 from Elliptic Curve defined by y^2 + x*y = x^3 + 1 over Finite Field in a of size 2^6 to Elliptic Curve defined by y^2 + x*y = x^3 + x over Finite Field in a of size 2^6] - sage: E = EllipticCurve_from_j(GF(3^12,'a')(2)) - sage: isogenies_prime_degree(E, 17) - [Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2 over Finite Field in a of size 3^12 to Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2*x over Finite Field in a of size 3^12, Isogeny of degree 17 from Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2 over Finite Field in a of size 3^12 to Elliptic Curve defined by y^2 = x^3 + 2*x^2 + x + 2 over Finite Field in a of size 3^12] + sage: E = EllipticCurve_from_j(GF(2^6,'a')(1)) # needs sage.rings.finite_rings + sage: isogenies_prime_degree(E, 7) # needs sage.rings.finite_rings + [Isogeny of degree 7 + from Elliptic Curve defined by y^2 + x*y = x^3 + 1 + over Finite Field in a of size 2^6 + to Elliptic Curve defined by y^2 + x*y = x^3 + x + over Finite Field in a of size 2^6] + sage: E = EllipticCurve_from_j(GF(3^12,'a')(2)) # needs sage.rings.finite_rings + sage: isogenies_prime_degree(E, 17) # needs sage.rings.finite_rings + [Isogeny of degree 17 + from Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2 + over Finite Field in a of size 3^12 + to Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2*x + over Finite Field in a of size 3^12, + Isogeny of degree 17 + from Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2 + over Finite Field in a of size 3^12 + to Elliptic Curve defined by y^2 = x^3 + 2*x^2 + x + 2 + over Finite Field in a of size 3^12] sage: E = EllipticCurve('50a1') sage: isogenies_prime_degree(E, 3) - [Isogeny of degree 3 from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - 126*x - 552 over Rational Field] + [Isogeny of degree 3 + from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 - 126*x - 552 over Rational Field] sage: isogenies_prime_degree(E, 5) - [Isogeny of degree 5 from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - 76*x + 298 over Rational Field] + [Isogeny of degree 5 + from Elliptic Curve defined by y^2 + x*y + y = x^3 - x - 2 over Rational Field + to Elliptic Curve defined by y^2 + x*y + y = x^3 - 76*x + 298 over Rational Field] sage: E = EllipticCurve([0, 0, 1, -1862, -30956]) sage: isogenies_prime_degree(E, 19) - [Isogeny of degree 19 from Elliptic Curve defined by y^2 + y = x^3 - 1862*x - 30956 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - 672182*x + 212325489 over Rational Field] + [Isogeny of degree 19 + from Elliptic Curve defined by y^2 + y = x^3 - 1862*x - 30956 + over Rational Field + to Elliptic Curve defined by y^2 + y = x^3 - 672182*x + 212325489 + over Rational Field] sage: E = EllipticCurve([0, -1, 0, -6288, 211072]) sage: isogenies_prime_degree(E, 37) - [Isogeny of degree 37 from Elliptic Curve defined by y^2 = x^3 - x^2 - 6288*x + 211072 over Rational Field to Elliptic Curve defined by y^2 = x^3 - x^2 - 163137088*x - 801950801728 over Rational Field] + [Isogeny of degree 37 + from Elliptic Curve defined by y^2 = x^3 - x^2 - 6288*x + 211072 + over Rational Field + to Elliptic Curve defined by y^2 = x^3 - x^2 - 163137088*x - 801950801728 + over Rational Field] Isogenies of degree equal to the characteristic are computed (but only the separable isogeny). In the following example we consider @@ -2292,23 +2737,51 @@ def isogenies_prime_degree(E, l, minimal_models=True): sage: from sage.schemes.elliptic_curves.isogeny_small_degree import isogenies_prime_degree sage: ainvs = (0,1,1,-1,-1) sage: for l in prime_range(50): - ....: E = EllipticCurve(GF(l),ainvs) - ....: isogenies_prime_degree(E,l) + ....: E = EllipticCurve(GF(l), ainvs) + ....: isogenies_prime_degree(E, l) [] - [Isogeny of degree 3 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 2*x + 2 over Finite Field of size 3 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 3] - [Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4*x + 4 over Finite Field of size 5 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4*x + 4 over Finite Field of size 5] - [Isogeny of degree 7 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 6*x + 6 over Finite Field of size 7 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4 over Finite Field of size 7] - [Isogeny of degree 11 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 10*x + 10 over Finite Field of size 11 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + x + 1 over Finite Field of size 11] - [Isogeny of degree 13 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 12 over Finite Field of size 13 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 12 over Finite Field of size 13] - [Isogeny of degree 17 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 16*x + 16 over Finite Field of size 17 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 15 over Finite Field of size 17] - [Isogeny of degree 19 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 18*x + 18 over Finite Field of size 19 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 3*x + 12 over Finite Field of size 19] - [Isogeny of degree 23 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 22*x + 22 over Finite Field of size 23 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 22*x + 22 over Finite Field of size 23] - [Isogeny of degree 29 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 28*x + 28 over Finite Field of size 29 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 7*x + 27 over Finite Field of size 29] - [Isogeny of degree 31 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 30*x + 30 over Finite Field of size 31 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 15*x + 16 over Finite Field of size 31] - [Isogeny of degree 37 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 36*x + 36 over Finite Field of size 37 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 16*x + 17 over Finite Field of size 37] - [Isogeny of degree 41 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 40*x + 40 over Finite Field of size 41 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 33*x + 16 over Finite Field of size 41] - [Isogeny of degree 43 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 42*x + 42 over Finite Field of size 43 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 36 over Finite Field of size 43] - [Isogeny of degree 47 from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 46*x + 46 over Finite Field of size 47 to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 42*x + 34 over Finite Field of size 47] + [Isogeny of degree 3 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 2*x + 2 over Finite Field of size 3 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + x over Finite Field of size 3] + [Isogeny of degree 5 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4*x + 4 over Finite Field of size 5 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4*x + 4 over Finite Field of size 5] + [Isogeny of degree 7 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 6*x + 6 over Finite Field of size 7 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 4 over Finite Field of size 7] + [Isogeny of degree 11 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 10*x + 10 over Finite Field of size 11 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + x + 1 over Finite Field of size 11] + [Isogeny of degree 13 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 12 over Finite Field of size 13 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 12*x + 12 over Finite Field of size 13] + [Isogeny of degree 17 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 16*x + 16 over Finite Field of size 17 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 15 over Finite Field of size 17] + [Isogeny of degree 19 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 18*x + 18 over Finite Field of size 19 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 3*x + 12 over Finite Field of size 19] + [Isogeny of degree 23 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 22*x + 22 over Finite Field of size 23 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 22*x + 22 over Finite Field of size 23] + [Isogeny of degree 29 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 28*x + 28 over Finite Field of size 29 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 7*x + 27 over Finite Field of size 29] + [Isogeny of degree 31 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 30*x + 30 over Finite Field of size 31 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 15*x + 16 over Finite Field of size 31] + [Isogeny of degree 37 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 36*x + 36 over Finite Field of size 37 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 16*x + 17 over Finite Field of size 37] + [Isogeny of degree 41 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 40*x + 40 over Finite Field of size 41 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 33*x + 16 over Finite Field of size 41] + [Isogeny of degree 43 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 42*x + 42 over Finite Field of size 43 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 36 over Finite Field of size 43] + [Isogeny of degree 47 + from Elliptic Curve defined by y^2 + y = x^3 + x^2 + 46*x + 46 over Finite Field of size 47 + to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 42*x + 34 over Finite Field of size 47] Note that the computation is faster for degrees equal to one of the genus 0 primes (2, 3, 5, 7, 13) or one of the hyperelliptic @@ -2316,28 +2789,42 @@ def isogenies_prime_degree(E, l, minimal_models=True): generic code must be used:: sage: E = EllipticCurve(GF(101), [-3440, 77658]) - sage: E.isogenies_prime_degree(71) # fast + sage: E.isogenies_prime_degree(71) # fast [] - sage: E.isogenies_prime_degree(73) # long time (2s) + sage: E.isogenies_prime_degree(73) # long time [] Test that :trac:`32269` is fixed:: - sage: K = QuadraticField(-11) - sage: E = EllipticCurve(K, [0,1,0,-117,-541]) - sage: E.isogenies_prime_degree(37) # long time (9s) - [Isogeny of degree 37 from Elliptic Curve defined by y^2 = x^3 + x^2 + (-117)*x + (-541) over Number Field in a with defining polynomial x^2 + 11 with a = 3.316624790355400?*I to Elliptic Curve defined by y^2 = x^3 + x^2 + (30800*a+123963)*x + (3931312*a-21805005) over Number Field in a with defining polynomial x^2 + 11 with a = 3.316624790355400?*I, - Isogeny of degree 37 from Elliptic Curve defined by y^2 = x^3 + x^2 + (-117)*x + (-541) over Number Field in a with defining polynomial x^2 + 11 with a = 3.316624790355400?*I to Elliptic Curve defined by y^2 = x^3 + x^2 + (-30800*a+123963)*x + (-3931312*a-21805005) over Number Field in a with defining polynomial x^2 + 11 with a = 3.316624790355400?*I] + sage: K = QuadraticField(-11) # needs sage.rings.number_field + sage: E = EllipticCurve(K, [0,1,0,-117,-541]) # needs sage.rings.number_field + sage: E.isogenies_prime_degree(37) # long time # needs sage.rings.number_field + [Isogeny of degree 37 + from Elliptic Curve defined by y^2 = x^3 + x^2 + (-117)*x + (-541) + over Number Field in a with defining polynomial x^2 + 11 + with a = 3.316624790355400?*I + to Elliptic Curve defined by + y^2 = x^3 + x^2 + (30800*a+123963)*x + (3931312*a-21805005) + over Number Field in a with defining polynomial x^2 + 11 + with a = 3.316624790355400?*I, + Isogeny of degree 37 + from Elliptic Curve defined by y^2 = x^3 + x^2 + (-117)*x + (-541) + over Number Field in a with defining polynomial x^2 + 11 + with a = 3.316624790355400?*I + to Elliptic Curve defined by + y^2 = x^3 + x^2 + (-30800*a+123963)*x + (-3931312*a-21805005) + over Number Field in a with defining polynomial x^2 + 11 + with a = 3.316624790355400?*I] """ if not l.is_prime(): - raise ValueError("%s is not prime."%l) - if l==2: + raise ValueError("%s is not prime." % l) + if l == 2: return isogenies_2(E, minimal_models=minimal_models) - if l==3: + if l == 3: return isogenies_3(E, minimal_models=minimal_models) p = E.base_ring().characteristic() - if l==p: + if l == p: return isogenies_prime_degree_general(E,l, minimal_models=minimal_models) if l in [5,7,13] and p not in [2,3]: diff --git a/src/sage/schemes/elliptic_curves/jacobian.py b/src/sage/schemes/elliptic_curves/jacobian.py index b6983ab75f7..1a33c7e4726 100644 --- a/src/sage/schemes/elliptic_curves/jacobian.py +++ b/src/sage/schemes/elliptic_curves/jacobian.py @@ -13,17 +13,17 @@ EXAMPLES:: sage: R.<u,v,w> = QQ[] - sage: Jacobian(u^3+v^3+w^3) + sage: Jacobian(u^3 + v^3 + w^3) Elliptic Curve defined by y^2 = x^3 - 27/4 over Rational Field - sage: Jacobian(u^4+v^4+w^2) + sage: Jacobian(u^4 + v^4 + w^2) Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field - sage: C = Curve(u^3+v^3+w^3) + sage: C = Curve(u^3 + v^3 + w^3) sage: Jacobian(C) Elliptic Curve defined by y^2 = x^3 - 27/4 over Rational Field sage: P2.<u,v,w> = ProjectiveSpace(2, QQ) - sage: C = P2.subscheme(u^3+v^3+w^3) + sage: C = P2.subscheme(u^3 + v^3 + w^3) sage: Jacobian(C) Elliptic Curve defined by y^2 = x^3 - 27/4 over Rational Field @@ -36,7 +36,7 @@ sage: C = HyperellipticCurve(f) sage: Jacobian(C) Jacobian of Hyperelliptic Curve over Rational Field defined - by y^2 = x^5 + 1184*x^3 + 1846*x^2 + 956*x + 560 + by y^2 = x^5 + 1184*x^3 + 1846*x^2 + 956*x + 560 REFERENCES: @@ -76,15 +76,15 @@ def Jacobian(X, **kwds): EXAMPLES:: sage: R.<u,v,w> = QQ[] - sage: Jacobian(u^3+v^3+w^3) + sage: Jacobian(u^3 + v^3 + w^3) Elliptic Curve defined by y^2 = x^3 - 27/4 over Rational Field - sage: C = Curve(u^3+v^3+w^3) + sage: C = Curve(u^3 + v^3 + w^3) sage: Jacobian(C) Elliptic Curve defined by y^2 = x^3 - 27/4 over Rational Field sage: P2.<u,v,w> = ProjectiveSpace(2, QQ) - sage: C = P2.subscheme(u^3+v^3+w^3) + sage: C = P2.subscheme(u^3 + v^3 + w^3) sage: Jacobian(C) Elliptic Curve defined by y^2 = x^3 - 27/4 over Rational Field @@ -95,8 +95,8 @@ def Jacobian(X, **kwds): To: Elliptic Curve defined by y^2 = x^3 - 27/4 over Rational Field Defn: Defined on coordinates by sending (u : v : w) to (-u^4*v^4*w - u^4*v*w^4 - u*v^4*w^4 : - 1/2*u^6*v^3 - 1/2*u^3*v^6 - 1/2*u^6*w^3 + 1/2*v^6*w^3 + 1/2*u^3*w^6 - 1/2*v^3*w^6 : - u^3*v^3*w^3) + 1/2*u^6*v^3 - 1/2*u^3*v^6 - 1/2*u^6*w^3 + 1/2*v^6*w^3 + 1/2*u^3*w^6 - 1/2*v^3*w^6 : + u^3*v^3*w^3) """ try: return X.jacobian(**kwds) @@ -104,8 +104,8 @@ def Jacobian(X, **kwds): pass morphism = kwds.pop('morphism', False) - from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial - if is_MPolynomial(X): + from sage.rings.polynomial.multi_polynomial import MPolynomial + if isinstance(X, MPolynomial): if morphism: from sage.schemes.curves.constructor import Curve return Jacobian_of_equation(X, curve=Curve(X), **kwds) @@ -125,14 +125,12 @@ def Jacobian_of_curve(curve, morphism=False): - ``curve`` -- a one-dimensional algebraic variety of genus one. - OUTPUT: - - Its Jacobian elliptic curve. + OUTPUT: Its Jacobian elliptic curve. EXAMPLES:: sage: R.<u,v,w> = QQ[] - sage: C = Curve(u^3+v^3+w^3) + sage: C = Curve(u^3 + v^3 + w^3) sage: Jacobian(C) Elliptic Curve defined by y^2 = x^3 - 27/4 over Rational Field """ @@ -178,22 +176,23 @@ def Jacobian_of_equation(polynomial, variables=None, curve=None): EXAMPLES:: sage: R.<a,b,c> = QQ[] - sage: f = a^3+b^3+60*c^3 + sage: f = a^3 + b^3 + 60*c^3 sage: Jacobian(f) Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field sage: Jacobian(f.subs(c=1)) Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field - If we specify the domain curve the birational covering is returned:: + If we specify the domain curve, the birational covering is returned:: sage: h = Jacobian(f, curve=Curve(f)); h Scheme morphism: From: Projective Plane Curve over Rational Field defined by a^3 + b^3 + 60*c^3 To: Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to - (-216000*a^4*b^4*c - 12960000*a^4*b*c^4 - 12960000*a*b^4*c^4 : - 108000*a^6*b^3 - 108000*a^3*b^6 - 6480000*a^6*c^3 + 6480000*b^6*c^3 + 388800000*a^3*c^6 - 388800000*b^3*c^6 : - 216000*a^3*b^3*c^3) + (-216000*a^4*b^4*c - 12960000*a^4*b*c^4 - 12960000*a*b^4*c^4 + : 108000*a^6*b^3 - 108000*a^3*b^6 - 6480000*a^6*c^3 + 6480000*b^6*c^3 + + 388800000*a^3*c^6 - 388800000*b^3*c^6 + : 216000*a^3*b^3*c^3) sage: h([1,-1,0]) (0 : 1 : 0) @@ -203,18 +202,18 @@ def Jacobian_of_equation(polynomial, variables=None, curve=None): sage: E = h.codomain() sage: E.defining_polynomial()(h.defining_polynomials()).factor() - (2519424000000000) * c^3 * b^3 * a^3 * (a^3 + b^3 + 60*c^3) * - (a^9*b^6 + a^6*b^9 - 120*a^9*b^3*c^3 + 900*a^6*b^6*c^3 - 120*a^3*b^9*c^3 + - 3600*a^9*c^6 + 54000*a^6*b^3*c^6 + 54000*a^3*b^6*c^6 + 3600*b^9*c^6 + - 216000*a^6*c^9 - 432000*a^3*b^3*c^9 + 216000*b^6*c^9) + (2519424000000000) * c^3 * b^3 * a^3 * (a^3 + b^3 + 60*c^3) + * (a^9*b^6 + a^6*b^9 - 120*a^9*b^3*c^3 + 900*a^6*b^6*c^3 - 120*a^3*b^9*c^3 + + 3600*a^9*c^6 + 54000*a^6*b^3*c^6 + 54000*a^3*b^6*c^6 + 3600*b^9*c^6 + + 216000*a^6*c^9 - 432000*a^3*b^3*c^9 + 216000*b^6*c^9) By specifying the variables, we can also construct an elliptic curve over a polynomial ring:: sage: R.<u,v,t> = QQ[] - sage: Jacobian(u^3+v^3+t, variables=[u,v]) + sage: Jacobian(u^3 + v^3 + t, variables=[u,v]) Elliptic Curve defined by y^2 = x^3 + (-27/4*t^2) over - Multivariate Polynomial Ring in u, v, t over Rational Field + Multivariate Polynomial Ring in u, v, t over Rational Field TESTS:: diff --git a/src/sage/schemes/elliptic_curves/kodaira_symbol.py b/src/sage/schemes/elliptic_curves/kodaira_symbol.py index c8a9f90da4a..b4bbe78b951 100644 --- a/src/sage/schemes/elliptic_curves/kodaira_symbol.py +++ b/src/sage/schemes/elliptic_curves/kodaira_symbol.py @@ -202,14 +202,14 @@ def __init__(self, symbol): else: self._pari = -self._n - 4 self._str = "I" + symbol + "*" - self._latex = "I_{%s}^*"%(symbol) + self._latex = "I_{%s}^*" % (symbol) else: if self._n == 0: self._pari = 1 else: self._pari = self._n + 4 self._str = "I" + symbol - self._latex = "I_{%s}"%(symbol) + self._latex = "I_{%s}" % (symbol) else: raise ValueError("input is not a Kodaira symbol") diff --git a/src/sage/schemes/elliptic_curves/kraus.py b/src/sage/schemes/elliptic_curves/kraus.py index 98ec70ecb5a..8565cc5e3be 100644 --- a/src/sage/schemes/elliptic_curves/kraus.py +++ b/src/sage/schemes/elliptic_curves/kraus.py @@ -52,7 +52,7 @@ # https://www.gnu.org/licenses/ ############################################################################## -from sage.schemes.elliptic_curves.all import EllipticCurve +from sage.schemes.elliptic_curves.constructor import EllipticCurve def c4c6_nonsingular(c4, c6): @@ -86,7 +86,9 @@ def c4c6_nonsingular(c4, c6): Over number fields:: - sage: K.<a> = NumberField(x^2-10) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: c4c6_nonsingular(-217728*a - 679104, 141460992*a + 409826304) True sage: K.<a> = NumberField(x^3-10) @@ -120,9 +122,11 @@ def c4c6_model(c4, c6, assume_nonsingular=False): EXAMPLES:: sage: from sage.schemes.elliptic_curves.kraus import c4c6_model - sage: K.<a> = NumberField(x^3-10) - sage: c4c6_model(-217728*a - 679104, 141460992*a + 409826304) - Elliptic Curve defined by y^2 = x^3 + (4536*a+14148)*x + (-163728*a-474336) over Number Field in a with defining polynomial x^3 - 10 + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 10) # needs sage.rings.number_field + sage: c4c6_model(-217728*a - 679104, 141460992*a + 409826304) # needs sage.rings.number_field + Elliptic Curve defined by y^2 = x^3 + (4536*a+14148)*x + (-163728*a-474336) + over Number Field in a with defining polynomial x^3 - 10 sage: c4, c6 = EllipticCurve('389a1').c_invariants() sage: c4c6_model(c4,c6) @@ -164,7 +168,9 @@ def make_integral(a, P, e): sage: from sage.schemes.elliptic_curves.kraus import make_integral - sage: K.<a> = NumberField(x^2-10) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: P = K.primes_above(2)[0] sage: e = P.ramification_index(); e 2 @@ -203,8 +209,10 @@ def sqrt_mod_4(x, P): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.kraus import sqrt_mod_4 - sage: K.<a> = NumberField(x^2-10) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: P = K.primes_above(2)[0] sage: sqrt_mod_4(1+2*a,P) (False, 0) @@ -245,7 +253,9 @@ def test_b2_local(c4, c6, P, b2, debug=False): EXAMPLES:: - sage: K.<a> = NumberField(x^2-10) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: c4 = -60544*a + 385796 sage: c6 = -55799680*a + 262126328 sage: P3a, P3b = K.primes_above(3) @@ -254,28 +264,36 @@ def test_b2_local(c4, c6, P, b2, debug=False): b2=0 works at the first prime but not the second:: sage: b2 = 0 - sage: test_b2_local(c4,c6,P3a,b2) - Elliptic Curve defined by y^2 = x^3 + (3784/3*a-96449/12)*x + (1743740/27*a-32765791/108) over Number Field in a with defining polynomial x^2 - 10 - sage: test_b2_local(c4,c6,P3b,b2) + sage: test_b2_local(c4,c6,P3a,b2) # needs sage.rings.number_field + Elliptic Curve defined by + y^2 = x^3 + (3784/3*a-96449/12)*x + (1743740/27*a-32765791/108) + over Number Field in a with defining polynomial x^2 - 10 + sage: test_b2_local(c4,c6,P3b,b2) # needs sage.rings.number_field False b2=-a works at the second prime but not the first:: - sage: b2 = -a - sage: test_b2_local(c4,c6,P3a,b2,debug=True) + sage: b2 = -a # needs sage.rings.number_field + sage: test_b2_local(c4,c6,P3a,b2,debug=True) # needs sage.rings.number_field test_b2_local: not integral at Fractional ideal (3, a + 1) False - sage: test_b2_local(c4,c6,P3b,b2) - Elliptic Curve defined by y^2 = x^3 + (-1/4*a)*x^2 + (3784/3*a-192893/24)*x + (56378369/864*a-32879311/108) over Number Field in a with defining polynomial x^2 - 10 + sage: test_b2_local(c4,c6,P3b,b2) # needs sage.rings.number_field + Elliptic Curve defined by + y^2 = x^3 + (-1/4*a)*x^2 + (3784/3*a-192893/24)*x + (56378369/864*a-32879311/108) + over Number Field in a with defining polynomial x^2 - 10 Using CRT we can do both with the same b2:: - sage: b2 = K.solve_CRT([0,-a],[P3a,P3b]); b2 + sage: b2 = K.solve_CRT([0,-a],[P3a,P3b]); b2 # needs sage.rings.number_field a + 1 - sage: test_b2_local(c4,c6,P3a,b2) - Elliptic Curve defined by y^2 = x^3 + (1/4*a+1/4)*x^2 + (10091/8*a-128595/16)*x + (4097171/64*a-19392359/64) over Number Field in a with defining polynomial x^2 - 10 - sage: test_b2_local(c4,c6,P3b,b2) - Elliptic Curve defined by y^2 = x^3 + (1/4*a+1/4)*x^2 + (10091/8*a-128595/16)*x + (4097171/64*a-19392359/64) over Number Field in a with defining polynomial x^2 - 10 + sage: test_b2_local(c4,c6,P3a,b2) # needs sage.rings.number_field + Elliptic Curve defined by + y^2 = x^3 + (1/4*a+1/4)*x^2 + (10091/8*a-128595/16)*x + (4097171/64*a-19392359/64) + over Number Field in a with defining polynomial x^2 - 10 + sage: test_b2_local(c4,c6,P3b,b2) # needs sage.rings.number_field + Elliptic Curve defined + by y^2 = x^3 + (1/4*a+1/4)*x^2 + (10091/8*a-128595/16)*x + (4097171/64*a-19392359/64) + over Number Field in a with defining polynomial x^2 - 10 """ E = c4c6_model(c4,c6).rst_transform(b2/12,0,0) if not (c4,c6) == E.c_invariants(): @@ -307,7 +325,9 @@ def test_b2_global(c4, c6, b2, debug=False): EXAMPLES:: - sage: K.<a> = NumberField(x^2-10) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: c4 = -60544*a + 385796 sage: c6 = -55799680*a + 262126328 sage: b2 = a+1 @@ -355,8 +375,10 @@ def check_Kraus_local_3(c4, c6, P, assume_nonsingular=False, debug=False): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.kraus import check_Kraus_local_3 - sage: K.<a> = NumberField(x^2-10) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: c4 = -60544*a + 385796 sage: c6 = -55799680*a + 262126328 sage: P3a, P3b = K.primes_above(3) @@ -367,7 +389,8 @@ def check_Kraus_local_3(c4, c6, P, assume_nonsingular=False, debug=False): An example in a field where 3 is ramified:: - sage: K.<a> = NumberField(x^2-15) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^2 - 15) sage: c4 = -60504*a + 386001 sage: c6 = -55346820*a + 261045153 sage: P3 = K.primes_above(3)[0] @@ -379,12 +402,12 @@ def check_Kraus_local_3(c4, c6, P, assume_nonsingular=False, debug=False): return False, 0 e = P.ramification_index() P3 = P**e - if c4.valuation(P)==0: + if c4.valuation(P) == 0: b2 = (-c6*c4.inverse_mod(P3)).mod(P3) if debug: assert test_b2_local(c4,c6,P,b2) return True, b2 - if c6.valuation(P)>=3*e: + if c6.valuation(P) >= 3*e: b2 = c6.parent().zero() if debug: assert test_b2_local(c4,c6,P,b2) @@ -423,8 +446,10 @@ def test_a1a3_local(c4, c6, P, a1, a3, debug=False): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.kraus import test_a1a3_local - sage: K.<a> = NumberField(x^2-10) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: c4 = -60544*a + 385796 sage: c6 = -55799680*a + 262126328 sage: P = K.primes_above(2)[0] @@ -464,8 +489,10 @@ def test_a1a3_global(c4, c6, a1, a3, debug=False): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.kraus import test_a1a3_global - sage: K.<a> = NumberField(x^2-10) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: c4 = -60544*a + 385796 sage: c6 = -55799680*a + 262126328 sage: test_a1a3_global(c4,c6,a,a,debug=False) @@ -504,7 +531,9 @@ def test_rst_global(c4, c6, r, s, t, debug=False): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.kraus import test_rst_global + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2-10) sage: c4 = -60544*a + 385796 sage: c6 = -55799680*a + 262126328 @@ -525,7 +554,7 @@ def test_rst_global(c4, c6, r, s, t, debug=False): K = E.base_field() for P in K.primes_above(2)+K.primes_above(3): if not E.is_local_integral_model(P): - print(" -- not integral at P=%s" %P) + print(" -- not integral at P=%s" % P) return False return E @@ -569,9 +598,11 @@ def check_Kraus_local_2(c4, c6, P, a1=None, assume_nonsingular=False): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.kraus import check_Kraus_local_2 - sage: K.<a> = NumberField(x^2-10) - sage: c4 = -60544*a + 385796 # EllipticCurve([a,a,0,1263*a-8032,62956*a-305877]) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) + sage: c4 = -60544*a + 385796 # EllipticCurve([a,a,0,1263*a-8032,62956*a-305877]) sage: c6 = -55799680*a + 262126328 sage: P = K.primes_above(2)[0] sage: check_Kraus_local_2(c4,c6,P) @@ -584,7 +615,7 @@ def check_Kraus_local_2(c4, c6, P, a1=None, assume_nonsingular=False): P2 = P**e c4val = c4.valuation(P) - if c4val==0: + if c4val == 0: if a1 is None: flag, t = sqrt_mod_4(-c6,P) if not flag: @@ -618,17 +649,17 @@ def check_Kraus_local_2(c4, c6, P, a1=None, assume_nonsingular=False): P2res = [a1] if a1 else P2.residues() for a1 in P2res: Px = -a1**6+3*a1**2*c4+2*c6 - if Px.valuation(P) >= 4*e : # (i) + if Px.valuation(P) >= 4*e: # (i) flag, a3 = sqrt_mod_4(Px/16,P) # (ii) if flag: a1sq = a1*a1 - if (4*a1sq*Px-(a1sq**2-c4)**2).valuation(P) >= 8*e : # (iii) + if (4*a1sq*Px-(a1sq**2-c4)**2).valuation(P) >= 8*e: # (iii) if test_a1a3_local(c4,c6,P,a1,a3): - return True, a1,a3 + return True, a1, a3 else: raise RuntimeError("check_Kraus_local_2 fails") # end of loop, but no a1 found - return False,0,0 + return False, 0, 0 # Wrapper function for local Kraus check, outsources the real work to # other functions for primes dividing 2 or 3: @@ -655,8 +686,10 @@ def check_Kraus_local(c4, c6, P, assume_nonsingular=False): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.kraus import check_Kraus_local - sage: K.<a> = NumberField(x^2-15) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 15) sage: P2 = K.primes_above(2)[0] sage: P3 = K.primes_above(3)[0] sage: P5 = K.primes_above(5)[0] @@ -675,6 +708,7 @@ def check_Kraus_local(c4, c6, P, assume_nonsingular=False): sage: E.is_local_integral_model(P5) and (c4,c6)==E.c_invariants() True + sage: # needs sage.rings.number_field sage: c4 = 123+456*a sage: c6 = 789+101112*a sage: check_Kraus_local(c4,c6,P2) @@ -688,14 +722,14 @@ def check_Kraus_local(c4, c6, P, assume_nonsingular=False): if not c4c6_nonsingular(c4,c6): return False, None K = c4.parent() - if K(2).valuation(P) >0: + if K(2).valuation(P) > 0: flag, a1, a3 = check_Kraus_local_2(c4,c6,P,None,True) if flag: E = test_a1a3_local(c4,c6,P,a1,a3) if E: return (True, E) return (False, None) - if K(3).valuation(P) >0: + if K(3).valuation(P) > 0: flag, b2 = check_Kraus_local_3(c4,c6,P,True) if flag: E = test_b2_local(c4,c6,P,b2) @@ -723,8 +757,10 @@ def check_Kraus_global(c4, c6, assume_nonsingular=False, debug=False): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.kraus import check_Kraus_global - sage: K.<a> = NumberField(x^2-10) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: E = EllipticCurve([a,a,0,1263*a-8032,62956*a-305877]) sage: c4, c6 = E.c_invariants() sage: check_Kraus_global(c4,c6,debug=True) @@ -739,7 +775,8 @@ def check_Kraus_global(c4, c6, assume_nonsingular=False, debug=False): ...and it does! Elliptic Curve defined by y^2 + 3*a*x*y + (-89*a+10)*y = x^3 + (a-89)*x^2 + (1202*a-5225)*x + (34881*a-151813) over Number Field in a with defining polynomial x^2 - 10 - sage: K.<a> = NumberField(x^2-15) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^2 - 15) sage: E = EllipticCurve([0, 0, 0, 4536*a + 14148, -163728*a - 474336]) sage: c4, c6 = E.c_invariants() sage: check_Kraus_global(c4,c6) @@ -747,16 +784,19 @@ def check_Kraus_global(c4, c6, assume_nonsingular=False, debug=False): TESTS (see :trac:`17295`):: - sage: K.<a> =NumberField(x^3 - 7*x - 5) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^3 - 7*x - 5) sage: E = EllipticCurve([a, 0, 1, 2*a^2 + 5*a + 3, -a^2 - 3*a - 2]) sage: assert E.conductor().norm() ==8 sage: G = K.galois_group(names='b') sage: def conj_curve(E,sigma): return EllipticCurve([sigma(a) for a in E.ainvs()]) sage: EL = conj_curve(E,G[0]) sage: L = EL.base_field() - sage: assert L.class_number()== 2 - sage: EL.isogeny_class() # long time (~10s) - Isogeny class of Elliptic Curve defined by y^2 + (-1/90*b^4+7/18*b^2-1/2*b-98/45)*x*y + y = x^3 + (1/45*b^5-1/18*b^4-7/9*b^3+41/18*b^2+167/90*b-29/9)*x + (-1/90*b^5+1/30*b^4+7/18*b^3-4/3*b^2-61/90*b+11/5) over Number Field in b with defining polynomial x^6 - 42*x^4 + 441*x^2 - 697 + sage: assert L.class_number() == 2 + sage: EL.isogeny_class() # long time (~10s) + Isogeny class of Elliptic Curve defined by + y^2 + (-1/90*b^4+7/18*b^2-1/2*b-98/45)*x*y + y = x^3 + (1/45*b^5-1/18*b^4-7/9*b^3+41/18*b^2+167/90*b-29/9)*x + (-1/90*b^5+1/30*b^4+7/18*b^3-4/3*b^2-61/90*b+11/5) + over Number Field in b with defining polynomial x^6 - 42*x^4 + 441*x^2 - 697 """ if not assume_nonsingular: if not c4c6_nonsingular(c4,c6): @@ -900,7 +940,9 @@ def semi_global_minimal_model(E, debug=False): EXAMPLES:: - sage: K.<a> = NumberField(x^2-10) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^2 - 10) sage: K.class_number() 2 sage: E = EllipticCurve([0,0,0,-186408*a - 589491, 78055704*a + 246833838]) @@ -918,16 +960,18 @@ def semi_global_minimal_model(E, debug=False): has order 3315. The smallest prime in that ideal class has norm 23567:: - sage: K.<a> = NumberField(x^2-x+31821453) - sage: ainvs = (0, 0, 0, -382586771000351226384*a - 2498023791133552294513515, 358777608829102441023422458989744*a + 1110881475104109582383304709231832166) + sage: # long time, needs sage.rings.number_field + sage: K.<a> = NumberField(x^2 - x + 31821453) + sage: ainvs = (0, 0, 0, -382586771000351226384*a - 2498023791133552294513515, + ....: 358777608829102441023422458989744*a + 1110881475104109582383304709231832166) sage: E = EllipticCurve(ainvs) sage: from sage.schemes.elliptic_curves.kraus import semi_global_minimal_model - sage: Emin, p = semi_global_minimal_model(E) # long time (25s) - sage: p # long time + sage: Emin, p = semi_global_minimal_model(E) # 25s + sage: p Fractional ideal (23567, a + 2270) - sage: p.norm() # long time + sage: p.norm() 23567 - sage: Emin.discriminant().norm().factor() # long time + sage: Emin.discriminant().norm().factor() 23567^12 """ c = E.global_minimality_class() diff --git a/src/sage/schemes/elliptic_curves/lseries_ell.py b/src/sage/schemes/elliptic_curves/lseries_ell.py index 94b381a2f0c..6e1dfa18c52 100644 --- a/src/sage/schemes/elliptic_curves/lseries_ell.py +++ b/src/sage/schemes/elliptic_curves/lseries_ell.py @@ -23,7 +23,8 @@ #***************************************************************************** from sage.structure.sage_object import SageObject -from sage.rings.all import RealField, RationalField +from sage.rings.real_mpfr import RealField +from sage.rings.rational_field import RationalField from math import sqrt, log, ceil import sage.functions.exp_integral as exp_integral from sage.misc.verbose import verbose @@ -41,7 +42,8 @@ def __init__(self, E): EXAMPLES:: sage: EllipticCurve([1..5]).lseries() - Complex L-series of the Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field + Complex L-series of the Elliptic Curve + defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field """ self.__E = E @@ -96,7 +98,7 @@ def _repr_(self): sage: L._repr_() 'Complex L-series of the Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field' """ - return "Complex L-series of the %s"%self.__E + return "Complex L-series of the %s" % self.__E def dokchitser(self, prec=53, max_imaginary_part=0, @@ -659,17 +661,18 @@ def deriv_at1(self, k=None, prec=None): EXAMPLES:: sage: E = EllipticCurve('37a') - sage: E.lseries().deriv_at1() + sage: E.lseries().deriv_at1() # needs sage.symbolic (0.3059866, 0.000801045) - sage: E.lseries().deriv_at1(100) + sage: E.lseries().deriv_at1(100) # needs sage.symbolic (0.3059997738340523018204836833216764744526377745903, 1.52493e-45) - sage: E.lseries().deriv_at1(1000) + sage: E.lseries().deriv_at1(1000) # needs sage.symbolic (0.305999773834052301820483683321676474452637774590771998..., 2.75031e-449) With less numerical precision, the error is bounded by numerical accuracy:: - sage: L,err = E.lseries().deriv_at1(100, prec=64) - sage: L,err + sage: # needs sage.symbolic + sage: L, err = E.lseries().deriv_at1(100, prec=64) + sage: L, err (0.305999773834052302, 5.55318e-18) sage: parent(L) Real Field with 64 bits of precision @@ -679,12 +682,12 @@ def deriv_at1(self, k=None, prec=None): Rank 2 and rank 3 elliptic curves:: sage: E = EllipticCurve('389a1') - sage: E.lseries().deriv_at1() + sage: E.lseries().deriv_at1() # needs sage.symbolic (0.0000000, 0.000000) sage: E = EllipticCurve((1, 0, 1, -131, 558)) # curve 59450i1 - sage: E.lseries().deriv_at1() + sage: E.lseries().deriv_at1() # needs sage.symbolic (-0.00010911444, 0.142428) - sage: E.lseries().deriv_at1(4000) + sage: E.lseries().deriv_at1(4000) # needs sage.symbolic (6.990...e-50, 1.31318e-43) """ sqrtN = sqrt(self.__E.conductor()) @@ -934,7 +937,8 @@ def zero_sums(self, N=None): sage: E = EllipticCurve("5077a") sage: E.lseries().zero_sums() - Zero sum estimator for L-function attached to Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field + Zero sum estimator for L-function attached to + Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field """ from sage.lfunctions.zero_sums import LFunctionZeroSum return LFunctionZeroSum(self.__E, N=N) diff --git a/src/sage/schemes/elliptic_curves/mod5family.py b/src/sage/schemes/elliptic_curves/mod5family.py index 1afc5588f74..64069c342b7 100644 --- a/src/sage/schemes/elliptic_curves/mod5family.py +++ b/src/sage/schemes/elliptic_curves/mod5family.py @@ -80,20 +80,20 @@ def mod5family(a, b): beta[20] = 30015*(J - 1)**10*(1001 + 634920*J + 3880800*J**2 + 142879744*J**3 - 1168475904*J**4 + 1188919296*J**5 - 143327232*J**6) beta[21] = 100050*(J - 1)**10*(143 + 107250*J + 808368*J**2 + 38518336*J**3 - 451953408*J**4 + 757651968*J**5 - 367276032*J**6) beta[22] = 450225*(J - 1)**11*(-13 - 11440*J - 117216*J**2 - 6444800*J**3 + 94192384*J**4 - 142000128*J**5 + 95551488*J**6) - beta[23] = 156600*(J - 1)**11*(-13 - 13299*J - 163284*J**2 - 11171552*J**3 + 217203840*J**4 - 474406656*J**5 + 747740160*J**6 - 429981696*J**7) - beta[24] = 6525*(J - 1)**12*(91 + 107536*J + 1680624*J**2 + 132912128*J**3 -\ + beta[23] = 156600*(J - 1)**11*(-13 - 13299*J - 163284*J**2 - 11171552*J**3 + 217203840*J**4 - 474406656*J**5 + 747740160*J**6 - 429981696*J**7) + beta[24] = 6525*(J - 1)**12*(91 + 107536*J + 1680624*J**2 + 132912128*J**3 - 3147511552*J**4 + 6260502528*J**5 - 21054173184*J**6 + 10319560704*J**7) - beta[25] = 1566*(J - 1)**12*(91 + 123292*J + 2261248*J**2 + 216211904*J**3 - \ + beta[25] = 1566*(J - 1)**12*(91 + 123292*J + 2261248*J**2 + 216211904*J**3 - 6487793920*J**4 + 17369596928*J**5 - 97854234624*J**6 + 96136740864*J**7 - 20639121408*J**8) - beta[26] = 3915*(J - 1)**13*(-7 - 10816*J - 242352*J**2 - 26620160*J**3 + 953885440*J**4 - \ + beta[26] = 3915*(J - 1)**13*(-7 - 10816*J - 242352*J**2 - 26620160*J**3 + 953885440*J**4 - 2350596096*J**5 + 26796552192*J**6 - 13329432576*J**7) - beta[27] = 580*(J - 1)**13*(-7 - 12259*J - 317176*J**2 - 41205008*J**3 + \ + beta[27] = 580*(J - 1)**13*(-7 - 12259*J - 317176*J**2 - 41205008*J**3 + 1808220160*J**4 - 5714806016*J**5 + 93590857728*J**6 - 70131806208*J**7 - 36118462464*J**8) - beta[28] = 435*(J - 1)**14*(1 + 1976*J + 60720*J**2 + 8987648*J**3 - 463120640*J**4 + 1359157248*J**5 - \ + beta[28] = 435*(J - 1)**14*(1 + 1976*J + 60720*J**2 + 8987648*J**3 - 463120640*J**4 + 1359157248*J**5 - 40644882432*J**6 - 5016453120*J**7 + 61917364224*J**8) - beta[29] = 30*(J - 1)**14*(1 + 2218*J + 77680*J**2 + 13365152*J**3 - \ + beta[29] = 30*(J - 1)**14*(1 + 2218*J + 77680*J**2 + 13365152*J**3 - 822366976*J**4 + 2990693888*J**5 - 118286217216*J**6 - 24514928640*J**7 + 509958291456*J**8 - 743008370688*J**9) - beta[30] = (J - 1)**15*(-1 - 2480*J - 101040*J**2 - 19642496*J**3 + 1399023872*J**4 - \ + beta[30] = (J - 1)**15*(-1 - 2480*J - 101040*J**2 - 19642496*J**3 + 1399023872*J**4 - 4759216128*J**5 + 315623485440*J**6 + 471904911360*J**7 - 2600529297408*J**8 + 8916100448256*J**9) R = PolynomialRing(QQ, 't') diff --git a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx index ea646b7fbe3..296a6b5d075 100644 --- a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx +++ b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx @@ -62,7 +62,7 @@ The most likely usage for the code is through the functions ``modular_symbol_numerical``:: sage: E = EllipticCurve("5077a1") - sage: M = E.modular_symbol(implementation = "num") + sage: M = E.modular_symbol(implementation="num") sage: M(0) 0 sage: M(1/123) @@ -80,7 +80,8 @@ accessible, too):: 35261176 sage: M = E.modular_symbol(implementation="num", sign=-1) sage: M - Numerical modular symbol attached to Elliptic Curve defined by y^2 = x^3 + 101*x + 103 over Rational Field + Numerical modular symbol attached to + Elliptic Curve defined by y^2 = x^3 + 101*x + 103 over Rational Field We can then compute the value `[13/17]^{-}` and `[1/17]^{+}` by calling the function ``M``. The value of `[0]^{+}=0` tells us that the rank of @@ -164,18 +165,16 @@ AUTHORS: from cysignals.memory cimport sig_malloc, sig_free, sig_realloc from cysignals.signals cimport sig_check +from sage.arith.misc import euler_phi, kronecker as kronecker_symbol from sage.misc.cachefunc import cached_method - +from sage.misc.misc_c import prod +from sage.misc.verbose import verbose from sage.rings.complex_mpfr cimport ComplexNumber from sage.rings.complex_mpfr import ComplexField -from sage.rings.real_mpfr cimport RealNumber, RealField -from sage.rings.rational cimport Rational from sage.rings.integer cimport Integer +from sage.rings.rational cimport Rational +from sage.rings.real_mpfr cimport RealNumber, RealField -from sage.misc.misc_c import prod -from sage.misc.verbose import verbose -from sage.arith.all import kronecker_symbol -from sage.arith.misc import euler_phi cdef extern from "<math.h>": double log(double) @@ -202,7 +201,7 @@ cdef llong llgcd(llong a, llong b) except -1: return fa.gcd_longlong(a,b) cdef llong llinvmod(llong a, llong m): - return fa.inverse_mod_longlong(a,m) + return fa.inverse_mod_longlong(a, m) DEF TWOPI = 6.28318530717958647 @@ -274,7 +273,8 @@ cdef llong llxgcd(llong a, llong b, llong *ss, llong *tt) except -1: tt[0] = q * qsign return a -def _test_llfunctions(a,b): + +def _test_llfunctions(a, b): r""" Doctest function for the above three functions. Given a, b this returns the absolute value of a, @@ -301,6 +301,7 @@ def _test_llfunctions(a,b): assert a*a4 + b*a5 == a3 return (a1,a2,a3,a4,a5) + # ================================ # this is a llong version of a function in @@ -392,7 +393,8 @@ cdef int proj_normalise(llong N, llong u, llong v, #verbose(" leaving proj_normalise with s=%s, t=%s"%(u,v), level=5) return 0 -def _test_proj_normalise(N,u,v): + +def _test_proj_normalise(N, u, v): r""" The doctest function for proj_normalise. @@ -412,9 +414,10 @@ def _test_proj_normalise(N,u,v): (1, 7) """ cdef llong uu, vv - ans = proj_normalise(N,u,v,&uu,&vv) + _ = proj_normalise(N,u,v,&uu,&vv) return (Integer(uu), Integer(vv)) + cdef int best_proj_point(llong u, llong v, llong N, llong* uu, llong* vv) except -1: r""" @@ -519,7 +522,8 @@ cdef int best_proj_point(llong u, llong v, llong N, vv[0] = t1 return 0 -def _test_best_proj_point(u,v,N): + +def _test_best_proj_point(u, v, N): r""" Doctest function of best_proj_point. @@ -547,6 +551,7 @@ def _test_best_proj_point(u,v,N): assert a == 0 return (Integer(uu), Integer(vv)) + #====================================================================== cdef class _CuspsForModularSymbolNumerical: @@ -615,7 +620,7 @@ cdef class _CuspsForModularSymbolNumerical: four [a,b,c,d] corresponds to [[a,b],[c,d]]. """ - cdef llong Q, B, c, g, x, y + cdef llong Q, B, c, x, y #verbose(" enter atkin_lehner for cusp r=%s"%self._r, level=5) Q = self._width @@ -624,7 +629,7 @@ cdef class _CuspsForModularSymbolNumerical: if llgcd(Q, B) != 1: raise ValueError("This cusp is not in the Atkin-Lehner " "orbit of oo.") - g = llxgcd( self._a * Q, self._m, &x, &y) + _ = llxgcd( self._a * Q, self._m, &x, &y) res[0] = Q * x res[1] = y res[2] = -c * self._N_level @@ -634,7 +639,8 @@ cdef class _CuspsForModularSymbolNumerical: # level=5) return 0 -def _test_cusps(r,N): + +def _test_cusps(r, N): r""" Doctest function for the above class. @@ -659,12 +665,12 @@ def _test_cusps(r,N): sage: _test_cusps(5/27,27) (1, 1, [[11, -2], [-27, 5]]) """ - cdef llong *wQ = [0L,0L,0L,0L] - rc = _CuspsForModularSymbolNumerical(r,N) + cdef llong *wQ = [0L, 0L, 0L, 0L] + rc = _CuspsForModularSymbolNumerical(r, N) a1 = rc._width a2 = rc.is_unitary() if a2: - a3 = rc.atkin_lehner(wQ) + _ = rc.atkin_lehner(wQ) a = Integer(wQ[0]) b = Integer(wQ[1]) c = Integer(wQ[2]) @@ -724,7 +730,7 @@ cdef class ModularSymbolNumerical: double _eps_plus, _eps_minus, _eps_unitary_plus, _eps_unitary_minus public RealNumber _om1, _om2 object _E, _epsQs, _Mt, _Epari - public dict __cached_methods + public dict _cached_methods Rational _twist_q Integer _D int _global_sign @@ -779,7 +785,7 @@ cdef class ModularSymbolNumerical: self._set_epsQs() self._initialise_an_coefficients() self._set_den_bounds() - self.__cached_methods = {} + self._cached_methods = {} # self.nc_sums = Integer(0) # self.nc_direct = Integer(0) @@ -803,7 +809,7 @@ cdef class ModularSymbolNumerical: sig_free(self._ans_num) sig_free(self._ans) -# == basics ================ + # == basics ================ def __repr__(self): """ @@ -816,7 +822,7 @@ cdef class ModularSymbolNumerical: sage: M Numerical modular symbol attached to Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field """ - return "Numerical modular symbol attached to %s"%(self._E) + return "Numerical modular symbol attached to %s" % (self._E) def elliptic_curve(self): r""" @@ -868,9 +874,8 @@ cdef class ModularSymbolNumerical: 0 sage: M(112379/43568779) 5 - """ - cdef llong Q - cdef Rational ra, ans + """ + cdef Rational ra if sign == 0: sign = self._global_sign @@ -883,7 +888,7 @@ cdef class ModularSymbolNumerical: ra = Rational( (0,1) ) elif isinstance(r, sage.rings.infinity.PlusInfinity): return Rational(0) - else: #who knows + else: # who knows raise ValueError("The modular symbol can be evaluated at a " "rational number only.") if use_twist: @@ -893,7 +898,6 @@ cdef class ModularSymbolNumerical: return self._twisted_symbol(ra, sign=sign) return self._evaluate(ra, sign=sign) - def approximative_value(self, r, int sign=0, int prec=20, use_twist=True): r""" The numerical modular symbol evaluated at rational. @@ -937,14 +941,12 @@ cdef class ModularSymbolNumerical: sage: M.approximative_value(1/7,prec=10) # abs tol 1e-11 0.999999972802649 """ - cdef llong Q cdef Rational ra cdef ComplexNumber ans cdef double eps cdef object L cdef int cinf - if sign == 0: sign = self._global_sign @@ -954,7 +956,7 @@ cdef class ModularSymbolNumerical: ra = r elif isinstance(r, Integer): ra = Rational( (0,1) ) - else: #who knows + else: # who knows raise ValueError("The modular symbol can be evaluated at a" "rational number only.") if use_twist: @@ -982,8 +984,7 @@ cdef class ModularSymbolNumerical: else: return ans.imag()/ self._om2 - -# == initialisation ======== + # == initialisation ======== def _set_epsQs(self): r""" @@ -998,10 +999,9 @@ cdef class ModularSymbolNumerical: sage: E = EllipticCurve("20a2") sage: M = E.modular_symbol(implementation="num") #indirect doctest """ - self._epsQs = dict( - [d,prod(self._E.root_number(p) - for p in d.prime_divisors() )] - for d in Integer( self._N_E ).divisors()) + self._epsQs = {d: prod(self._E.root_number(p) + for p in d.prime_divisors()) + for d in Integer(self._N_E).divisors()} def _set_den_bounds(self): r""" @@ -1153,11 +1153,11 @@ cdef class ModularSymbolNumerical: EXAMPLES:: sage: E = EllipticCurve("63a2") - sage: M =E.modular_symbol(implementation="num") + sage: M = E.modular_symbol(implementation="num") sage: M(3/4, use_twist=True) # indirect doctest -1 """ - cdef Integer D, ell, de, ve, Dmax, DD, Nmin + cdef Integer D, ell cdef RealNumber qq, Db #verbose(" enter _set_up_twist", level=5) @@ -1201,7 +1201,6 @@ cdef class ModularSymbolNumerical: qq = self._om1 * Db/self._Mt._om2 * 2 assert self._twist_q == Rational( ( qq.round(),2)) - def _round(self, RealNumber val, int sign, int unitary): r""" Round the numerical approximation to the rational. @@ -1344,7 +1343,6 @@ cdef class ModularSymbolNumerical: # last n such that ans[n] is allowed self._lans = T - def clear_cache(self): r""" Clear the cached values in all methods of this class @@ -1359,12 +1357,11 @@ cdef class ModularSymbolNumerical: sage: M(0) 1/5 """ - cadi = self.__cached_methods + cadi = self._cached_methods for me in cadi: cadi[me].clear_cache() - -#================== Low level summation ========= + #================== Low level summation ========= def _integration_to_tau(self, ComplexNumber tau, int number_of_terms, int prec): @@ -1649,8 +1646,7 @@ cdef class ModularSymbolNumerical: # " %s, %s, ... %s"%(res[0], res[1], res[m-1]), level=5) return res - -#================ + #================ def _get_truncation_and_prec(self, double y, double eps): r""" @@ -1837,7 +1833,7 @@ cdef class ModularSymbolNumerical: # if called with a previous (m,z,eps) but a larger eps, # return the cached value - cac = self.__cached_methods['_kappa'].cache + cac = self._cached_methods['_kappa'].cache for ke in cac: mm, zz, eeps = ke[0] if mm == m and zz == z: @@ -1868,7 +1864,7 @@ cdef class ModularSymbolNumerical: ra = <double *> sig_malloc( m * sizeof(double)) if ra is NULL: raise MemoryError - oi = self._partial_real_sums_double(y, m, T, ra) + _ = self._partial_real_sums_double(y, m, T, ra) res = [ra[j] for j in range(m)] sig_free(ra) #verbose(" leaving _kappa with" @@ -1926,8 +1922,8 @@ cdef class ModularSymbolNumerical: # " and eps=%s"%(r,eps), level=5) cdef: llong m, Q, epsQ, a, u - double yy, taui, zz, epsi - int T, prec, j, oi, preci + double yy, taui + int T, prec, j double complex tauc, tauphc, int1c, int2c, twopii, ze1, ze2, su ComplexNumber tau, tauph, int1, int2 llong * wQ = [0L, 0L, 0L, 0L] @@ -1935,7 +1931,7 @@ cdef class ModularSymbolNumerical: rc = _CuspsForModularSymbolNumerical(r, self._N_E) Q = rc._width - oi = rc.atkin_lehner(wQ) + _ = rc.atkin_lehner(wQ) m = rc._m epsQ = self._epsQs[Q] r = rc._r @@ -1971,7 +1967,6 @@ cdef class ModularSymbolNumerical: verbose(" yields %s"%int2, level=2) return int2 + int1 - elif not use_partials: # prec = 53 taui = <double>(Q) taui = sqrt(taui) @@ -2052,7 +2047,7 @@ cdef class ModularSymbolNumerical: RealNumber x1, x2, s complex tau0c, tau1c, int1c, int2c, ze1, ze2, su, twopii llong g, u, v, uu, vv, D, a, aa, m, mm, Q, QQ, z, xi, xixi - int oi, j, preci + int oi, j double x1d, x2d, sd #verbose(" enter _from_r_to_rr_approx_direct with r=%s," @@ -2226,7 +2221,6 @@ cdef class ModularSymbolNumerical: llong * wQ = [0L, 0L, 0L, 0L] llong * wQQ = [0L, 0L, 0L, 0L] Integer epsQ, epsQQ - Rational csq, x double s, yy ComplexNumber ans, ans2 int T=0, prec=0, T1=0, T2=0, oi @@ -2699,7 +2693,7 @@ cdef class ModularSymbolNumerical: #verbose(" enter _symbol_non_unitary with r=%s," # " sign=%s"%(r,sign), level=5) cdef: - llong a, m, B, Q, N_ell, aell, u, N = self._N_E + llong m, B, N_ell, aell, u, N = self._N_E Integer ell Rational r2, res @@ -2708,9 +2702,7 @@ cdef class ModularSymbolNumerical: rc = _CuspsForModularSymbolNumerical(r, N) r = rc._r - a = rc._a m = rc._m - Q = rc._width B = llgcd(m, N) # find a prime congruent to 1 modulo B @@ -2723,14 +2715,14 @@ cdef class ModularSymbolNumerical: aell = Integer(self._ans[ell]) N_ell = ell + 1 - aell # {ell * r , r} - verbose(" Compute symbol {ell*r -> r} = {%s -> %s}"%(ell*r,r), + verbose(" Compute symbol {ell*r -> r} = {%s -> %s}" % (ell*r, r), level=4) res = self.transportable_symbol(ell * r, r, sign=sign) # {(r + u)/ ell, r} u = Integer(0) while u < ell: r2 = (r+u) / ell - verbose(" Compute symbol {r2-> r} = {%s -> %s}"%(r2,r), + verbose(" Compute symbol {r2-> r} = {%s -> %s}" % (r2, r), level=4) res += self.transportable_symbol(r2, r, sign=sign) u += 1 @@ -2754,16 +2746,16 @@ cdef class ModularSymbolNumerical: sage: ms = ModularSymbolNumerical(E) sage: ms.manin_symbol(4,17) 1 - sage: ms.__cached_methods["_manin_symbol_with_cache"].cache # random + sage: ms._cached_methods["_manin_symbol_with_cache"].cache # random {((1, 5, 1), ()): 1, ((1, 15, 1), ()): -1, ((1, 22, 1), ()): -1, ((1, 32, 1), ()): 1} - sage: ms.__cached_methods["_manin_symbol_with_cache"].cache[(1,15,1),()] + sage: ms._cached_methods["_manin_symbol_with_cache"].cache[(1,15,1),()] -1 sage: ms.manin_symbol(4+17,-4) 0 - sage: ms.__cached_methods["_manin_symbol_with_cache"].cache # random + sage: ms._cached_methods["_manin_symbol_with_cache"].cache # random {((1, 4, 1), ()): 0, ((1, 5, 1), ()): 1, ((1, 8, 1), ()): 1, @@ -2776,13 +2768,12 @@ cdef class ModularSymbolNumerical: ((1, 29, 1), ()): 1, ((1, 32, 1), ()): 1, ((1, 33, 1), ()): 0} - sage: ms.__cached_methods["_manin_symbol_with_cache"].cache[ (1,23,1), () ] + sage: ms._cached_methods["_manin_symbol_with_cache"].cache[ (1,23,1), () ] -1 """ cdef: llong c, d, x, y, N = self._N_E, Mu, Mv, Qu, Qv, du=1, dv=1 Rational r, rr, res - int oi #verbose(" enter _manin_symbol_with_cache with u=%s, v=%s," # " sign =%s"%(u,v,sign), level=5) @@ -2803,9 +2794,9 @@ cdef class ModularSymbolNumerical: Mv = llgcd(v,N) Qv = N/Mv isunitary = ( llgcd(Qu,Mu) == 1 and llgcd(Qv,Mv) == 1 ) - if isunitary: # unitary case - oi = best_proj_point(u, v, self._N_E, &c, &d) - else: # at least one of the two cusps is not unitary + if isunitary: # unitary case + _ = best_proj_point(u, v, self._N_E, &c, &d) + else: # at least one of the two cusps is not unitary du = llgcd(Qu,Mu) dv = llgcd(Qv,Mv) NMM = N/Mv/Mu @@ -2912,7 +2903,7 @@ cdef class ModularSymbolNumerical: # "(%s :%s)"%(un, vn), level=3) # is it already in the cache ? - c = self.__cached_methods + c = self._cached_methods if "_manin_symbol_with_cache" in c: c = c["_manin_symbol_with_cache"] if c.is_in_cache(un,vn,sign): @@ -2928,7 +2919,7 @@ cdef class ModularSymbolNumerical: # we get for free additional values of Manin # symbols that we cache, too. # This sets 6 values in average - c = self.__cached_methods["_manin_symbol_with_cache"] + c = self._cached_methods["_manin_symbol_with_cache"] # (-v:u) = - (u:v) oi = proj_normalise(self._N_E, -v, u, &un, &vn) @@ -2987,10 +2978,9 @@ cdef class ModularSymbolNumerical: return res + # =============================== -# =============================== - - @cached_method # not sure this is not a waist + @cached_method # not sure this is not a waist def _evaluate(self, Rational r, int sign=0): r""" Given a rational number `r` this computes the modular symbol @@ -3358,21 +3348,21 @@ cdef class ModularSymbolNumerical: # level=4) # make the cusp -x/y unitary if possible. B = y.gcd(N) - if B.gcd(N//B) != 1: + if B.gcd(N // B) != 1: if y > 0: y -= m x += a else: y += m x -= a - r2 = - x/y + r2 = - x / y B = y.gcd(N) Q = N // B - if Q.gcd(N//Q) != 1: # r2 is not unitary - return self._symbol_non_unitary_approx(r, eps) + if Q.gcd(N // Q) != 1: # r2 is not unitary + return self._symbol_non_unitary_approx(r, eps) - r2 = - x/y - verbose("Next piece: integrate to the cusp %s "%r2, level=2) + r2 = - x / y + verbose("Next piece: integrate to the cusp %s " % r2, level=2) res = self._from_r_to_rr_approx(r, r2, eps, use_partials=2) res += self._evaluate_approx(r2, eps) @@ -3418,16 +3408,14 @@ cdef class ModularSymbolNumerical: #verbose(" enter _symbol_nonunitary_approx with r=%s," # " eps=%s"%(r,eps), level=5) cdef: - llong a, m, B, Q, N_ell, aell, u, N = self._N_E + llong m, B, N_ell, aell, u, N = self._N_E Integer ell Rational r2 ComplexNumber res rc = _CuspsForModularSymbolNumerical(r, N) r = rc._r - a = rc._a m = rc._m - Q = rc._width B = llgcd(m, N) # find a prime congruent to 1 modulo B @@ -3620,7 +3608,8 @@ def _test_init(E): e2 = M._eps_minus e3 = M._eps_unitary_plus e4 = M._eps_unitary_minus - return e, [a1,a2,a3,a4,a5], [t1,t2,t3,t4], [e1,e2,e3,e4] + return e, [a1, a2, a3, a4, a5], [t1, t2, t3, t4], [e1, e2, e3, e4] + def _test_integration(E, a, b, T): r""" @@ -3662,6 +3651,7 @@ def _test_integration(E, a, b, T): ans = M._integration_to_tau_double(c,tt) return ans + def _test_integration_via_partials(E, y, m, T): r""" Doctest for the numerical integration in @@ -3693,15 +3683,13 @@ def _test_integration_via_partials(E, y, m, T): sage: _test_integration_via_partials(E,0.03,3,7000) # abs tol 1e-11 [0.49198993741342784, 0.6601504274130793, 0.3177042713926389] """ - cdef int oi, mm = <int>(m) + cdef int mm = <int>(m) cdef double * ra ra = <double *> sig_malloc( mm * sizeof(double)) if ra is NULL: raise MemoryError M = ModularSymbolNumerical(E) - yy = <double>(y) - tt = <int>T - oi = M._partial_real_sums_double(y, m, T, ra) + _ = M._partial_real_sums_double(y, m, T, ra) res = [ra[j] for j in range(m)] sig_free(ra) return res diff --git a/src/sage/schemes/elliptic_curves/modular_parametrization.py b/src/sage/schemes/elliptic_curves/modular_parametrization.py index dca43dcd191..501c17cd571 100644 --- a/src/sage/schemes/elliptic_curves/modular_parametrization.py +++ b/src/sage/schemes/elliptic_curves/modular_parametrization.py @@ -16,11 +16,14 @@ sage: phi = EllipticCurve('11a1').modular_parametrization() sage: phi - Modular parameterization from the upper half plane to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Modular parameterization + from the upper half plane + to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: phi(0.5+CDF(I)) (285684.320516... + 7.0...e-11*I : 1.526964169...e8 + 5.6...e-8*I : 1.00000000000000) sage: phi.power_series(prec = 7) - (q^-2 + 2*q^-1 + 4 + 5*q + 8*q^2 + q^3 + 7*q^4 + O(q^5), -q^-3 - 3*q^-2 - 7*q^-1 - 13 - 17*q - 26*q^2 - 19*q^3 + O(q^4)) + (q^-2 + 2*q^-1 + 4 + 5*q + 8*q^2 + q^3 + 7*q^4 + O(q^5), + -q^-3 - 3*q^-2 - 7*q^-1 - 13 - 17*q - 26*q^2 - 19*q^3 + O(q^4)) AUTHORS: @@ -44,7 +47,10 @@ from . import heegner -from sage.rings.all import (LaurentSeriesRing, RationalField, ComplexField, QQ) +from sage.rings.laurent_series_ring import LaurentSeriesRing +from sage.rings.rational_field import RationalField +from sage.rings.complex_mpfr import ComplexField +from sage.rings.rational_field import QQ class ModularParameterization: @@ -61,7 +67,10 @@ class ModularParameterization: sage: phi = EllipticCurve('11a1').modular_parametrization() sage: phi - Modular parameterization from the upper half plane to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Modular parameterization + from the upper half plane + to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 + over Rational Field """ def __init__(self, E): r""" @@ -144,7 +153,7 @@ def __call__(self, z, prec=None): sage: E = EllipticCurve('37a') sage: phi = E.modular_parametrization() - sage: phi((sqrt(7)*I - 17)/74, 53) + sage: phi((sqrt(7)*I - 17)/74, 53) # needs sage.symbolic (...e-16 - ...e-16*I : ...e-16 + ...e-16*I : 1.00000000000000) Verify that the mapping is invariant under the action of `\Gamma_0(N)` @@ -203,7 +212,9 @@ def map_to_complex_numbers(self, z, prec=None): EXAMPLES:: + sage: # needs sage.symbolic sage: E = EllipticCurve('37a'); phi = E.modular_parametrization() + sage: x = polygen(ZZ, 'x') sage: tau = (sqrt(7)*I - 17)/74 sage: z = phi.map_to_complex_numbers(tau); z 0.929592715285395 - 1.22569469099340*I @@ -261,7 +272,7 @@ def power_series(self, prec=20): sage: E = EllipticCurve('389a1') sage: phi = E.modular_parametrization() - sage: X,Y = phi.power_series(prec=10) + sage: X, Y = phi.power_series(prec=10) sage: X q^-2 + 2*q^-1 + 4 + 7*q + 13*q^2 + 18*q^3 + 31*q^4 + 49*q^5 + 74*q^6 + 111*q^7 + O(q^8) sage: Y diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index ccdc0dcc941..96177ed417c 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.rings.padics r""" `p`-adic `L`-functions of elliptic curves @@ -61,27 +61,33 @@ # https://www.gnu.org/licenses/ ###################################################################### -from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ -from sage.rings.padics.factory import Qp -from sage.rings.infinity import infinity -from sage.rings.all import LaurentSeriesRing, PowerSeriesRing, PolynomialRing, Integers - -from sage.rings.integer import Integer -from sage.arith.all import valuation, binomial, kronecker_symbol, gcd, prime_divisors, LCM - -from sage.structure.sage_object import SageObject -from sage.structure.richcmp import richcmp_method, richcmp - -from sage.misc.functional import denominator -from sage.misc.verbose import verbose, get_verbose - -from sage.modules.free_module_element import vector -import sage.matrix.all as matrix +from sage.matrix.constructor import matrix import sage.schemes.hyperelliptic_curves.monsky_washnitzer + +from sage.arith.functions import lcm as LCM +from sage.arith.misc import (binomial, + GCD as gcd, + prime_divisors, + kronecker as kronecker_symbol, + valuation) from sage.functions.log import log from sage.functions.other import floor from sage.misc.cachefunc import cached_method +from sage.misc.functional import denominator +from sage.misc.verbose import get_verbose, verbose +from sage.modules.free_module_element import vector +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as Integers +from sage.rings.infinity import infinity +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.laurent_series_ring import LaurentSeriesRing +from sage.rings.padics.factory import Qp +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import QQ +from sage.structure.richcmp import richcmp_method, richcmp +from sage.structure.sage_object import SageObject + @richcmp_method class pAdicLseries(SageObject): @@ -218,7 +224,7 @@ def __richcmp__(self, other, op): sage: lp1 == lp3 False """ - if type(self) != type(other): + if type(self) is not type(other): return NotImplemented return richcmp((self._E, self._p), (other._E, other._p), op) @@ -438,7 +444,7 @@ def measure(self, a, n, prec, quadratic_twist=+1, sign=+1): if self._E.conductor() % p == 0: mu = chip**n * z * sum([kronecker_symbol(D,u) * f(a/(p*w)+ZZ(u)/D) for u in range(1,D.abs())]) else: - mu = chip**n * z * sum([kronecker_symbol(D,u) *( f(a/(p*w)+ZZ(u)/D) - chip /alpha * f(a/w+ZZ(u)/D) ) for u in range(1,D.abs())]) + mu = chip**n * z * sum([kronecker_symbol(D,u) * ( f(a/(p*w)+ZZ(u)/D) - chip / alpha * f(a/w+ZZ(u)/D) ) for u in range(1,D.abs())]) return s*mu def alpha(self, prec=20): @@ -862,7 +868,7 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): raise ValueError("Insufficient precision (%s)" % prec) # check if the conditions on quadratic_twist are satisfied - eta = ZZ(eta) % (self._p- 1) if self._p != 2 else ZZ(eta) % 2 + eta = ZZ(eta) % (self._p - 1) if self._p != 2 else ZZ(eta) % 2 D = ZZ(quadratic_twist) if D != 1: if eta != 0: @@ -870,20 +876,20 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): if D % 4 == 0: d = D//4 if not d.is_squarefree() or d % 4 == 1: - raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field"%D) + raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field" % D) else: if not D.is_squarefree() or D % 4 != 1: - raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field"%D) + raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field" % D) if gcd(D,self._p) != 1: - raise ValueError("quadratic twist (=%s) must be coprime to p (=%s) "%(D,self._p)) + raise ValueError("quadratic twist (=%s) must be coprime to p (=%s) " % (D,self._p)) if gcd(D, self._E.conductor()) != 1: for ell in prime_divisors(D): if valuation(self._E.conductor(), ell) > valuation(D, ell): - raise ValueError("cannot twist a curve of conductor (=%s) by the quadratic twist (=%s)."%(self._E.conductor(),D)) + raise ValueError("cannot twist a curve of conductor (=%s) by the quadratic twist (=%s)." % (self._E.conductor(),D)) p = self._p si = 1-2*(eta % 2) - #verbose("computing L-series for p=%s, n=%s, and prec=%s"%(p,n,prec)) + # verbose("computing L-series for p=%s, n=%s, and prec=%s" % (p,n,prec)) if prec == 1: if eta == 0: @@ -909,13 +915,13 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): bounds = self._prec_bounds(n,prec,sign=si) padic_prec = max(bounds[1:]) + 5 - verbose("using p-adic precision of %s"%padic_prec) + verbose("using p-adic precision of %s" % padic_prec) if p == 2: res_series_prec = min(p**(n-2), prec) else: res_series_prec = min(p**(n-1), prec) - verbose("using series precision of %s"%res_series_prec) + verbose("using series precision of %s" % res_series_prec) ans = self._get_series_from_cache(n, res_series_prec,D,eta) if ans is not None: @@ -936,17 +942,17 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): a_range = 3 else: teich = self.teichmuller(padic_prec) - gamma = K(1+ p) + gamma = K(1 + p) p_power = p**(n-1) a_range = p - verbose("Now iterating over %s summands"%((p-1)*p_power)) + verbose("Now iterating over %s summands" % ((p-1)*p_power)) verbose_level = get_verbose() count_verb = 0 for j in range(p_power): s = K(0) if verbose_level >= 2 and j/p_power*100 > count_verb + 3: - verbose("%.2f percent done"%(float(j)/p_power*100)) + verbose("%.2f percent done" % (float(j)/p_power*100)) count_verb += 3 for a in range(1,a_range): b = teich[a] * gamma_power @@ -955,7 +961,7 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): one_plus_T_factor *= 1+T gamma_power *= gamma - verbose("the series before adjusting the precision is %s"%L) + verbose("the series before adjusting the precision is %s" % L) # Now create series but with each coefficient truncated # so it is proven correct: K = Qp(p, padic_prec, print_mode='series') @@ -1046,7 +1052,7 @@ def _c_bound(self, sign=+1): if E.galois_representation().is_irreducible(p): return 0 - if self._implementation=="sage": + if self._implementation == "sage": m = E.modular_symbol_space(sign=1) b = m.boundary_map().codomain() C = b._known_cusps() # all known, since computed the boundary map @@ -1064,7 +1070,7 @@ def _c_bound(self, sign=+1): # else the same reasoning as in _set_denom in numerical # modular symbol. We rely on the fact that p is semistable from sage.databases.cremona import CremonaDatabase - isog = E.isogeny_class() + isog = E.isogeny_class() t = 0 if N <= CremonaDatabase().largest_conductor(): E0 = E.optimal_curve() @@ -1089,7 +1095,7 @@ def _c_bound(self, sign=+1): if p == 2: t += 1 if p == 2 and E0.real_components() == 1: - t += 1 # slanted lattice + t += 1 # slanted lattice # this was the bound for E0 now compare periods # to get the bound for E @@ -1106,7 +1112,7 @@ def _c_bound(self, sign=+1): if E0.real_components() == 1: om0 *= 2 m = max(isog.matrix().list()) - q = (om/om0 *m).round()/m + q = (om/om0 * m).round()/m t += valuation(q,p) return max(t,0) @@ -1221,7 +1227,7 @@ def series(self, n=3, quadratic_twist=+1, prec=5, eta=0): if D % 4 == 0: d = D//4 if not d.is_squarefree() or d % 4 == 1: - raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field"%D) + raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field" % D) else: if not D.is_squarefree() or D % 4 != 1: raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field" % D) @@ -1277,18 +1283,18 @@ def series(self, n=3, quadratic_twist=+1, prec=5, eta=0): a_range = 3 else: teich = self.teichmuller(padic_prec) - gamma = 1+ p + gamma = 1 + p p_power = p**(n-1) a_range = p si = 1-2*(eta % 2) - verbose("Now iterating over %s summands"%((p-1)*p_power)) + verbose("Now iterating over %s summands" % ((p-1)*p_power)) verbose_level = get_verbose() count_verb = 0 for j in range(p_power): s = K(0) if verbose_level >= 2 and j/p_power*100 > count_verb + 3: - verbose("%.2f percent done"%(float(j)/p_power*100)) + verbose("%.2f percent done" % (float(j)/p_power*100)) count_verb += 3 for a in range(1,a_range): b = teich[a] * gamma_power @@ -1369,7 +1375,7 @@ def _prec_bounds(self, n, prec): return [infinity] + [2 * e[j] - c0 for j in range(1, len(e))] def _poly(self, a): - """ + r""" Given an element a in Qp[alpha] this returns the list containing the two coordinates in Qp. @@ -1387,15 +1393,15 @@ def _poly(self, a): # this should be implemented in elements of Eisenstein rings at some point trac 20248 if a.is_zero(): - return [0,0] + return [0, 0] v, k = a._ntl_rep_abs() K = a.base_ring() pi = K.uniformiser() - v0 = K(v[0]._sage_()) * pi**k - v1 = K(v[1]._sage_()) * pi**k + v0 = K(v[0]._sage_()) * pi**k + v1 = K(v[1]._sage_()) * pi**k alpha = a.parent().gen() - assert v0 + v1*alpha == a - return [ v0, v1 ] + assert v0 + v1 * alpha == a + return [v0, v1] def Dp_valued_series(self, n=3, quadratic_twist=+1, prec=5): r""" @@ -1431,8 +1437,8 @@ def Dp_valued_series(self, n=3, quadratic_twist=+1, prec=5): lps = self.series(n, quadratic_twist=quadratic_twist, prec=prec) # now split up the series in two lps = G + H * alpha - R = lps.base_ring().base_ring() # Qp - QpT , T = PowerSeriesRing(R, 'T', prec).objgen() + R = lps.base_ring().base_ring() # Qp + QpT, T = PowerSeriesRing(R, 'T', prec).objgen() Gli = [] Hli = [] for n in range(lps.prec()): @@ -1443,10 +1449,10 @@ def Dp_valued_series(self, n=3, quadratic_twist=+1, prec=5): H = QpT(Hli, prec) # now compute phi - phi = matrix.matrix([[0,-1/p],[1,E.ap(p)/p]]) - lpv = vector([G + (E.ap(p))*H , - R(p) * H ]) # this is L_p - eps = (1-phi)**(-2) - resu = lpv*eps.transpose() + phi = matrix([[0, -1 / p], [1, E.ap(p) / p]]) + lpv = vector([G + (E.ap(p)) * H, - R(p) * H]) # this is L_p + eps = (1 - phi)**(-2) + resu = lpv * eps.transpose() return resu def frobenius(self, prec=20, algorithm="mw"): @@ -1478,8 +1484,8 @@ def frobenius(self, prec=20, algorithm="mw"): """ E = self._E p = self._p - if algorithm != "mw" and algorithm !="approx": - raise ValueError("Unknown algorithm %s."%algorithm) + if algorithm != "mw" and algorithm != "approx": + raise ValueError("Unknown algorithm %s." % algorithm) if algorithm == "approx": return self.__phi_bpr(prec=prec) if p < 4 and algorithm == "mw": @@ -1492,28 +1498,27 @@ def frobenius(self, prec=20, algorithm="mw"): Q = x**3 + modprecring(Ew.a4()) * x + modprecring(Ew.a6()) trace = Ew.ap(p) fr = sage.schemes.hyperelliptic_curves.monsky_washnitzer.matrix_of_frobenius(Q, p, adjusted_prec, trace) - fr = matrix.matrix(output_ring,2,2,fr) + fr = matrix(output_ring,2,2,fr) # return a vector for PARI's ellchangecurve to pass from e1 to e2 - def isom(e1,e2): + def isom(e1, e2): if not e1.is_isomorphic(e2): raise ValueError("Curves must be isomorphic.") - usq = (e1.discriminant()/e2.discriminant()).nth_root(6) + usq = (e1.discriminant() / e2.discriminant()).nth_root(6) u = usq.sqrt() - s = (u * e2.a1() - e1.a1() )/ZZ(2) - r = (usq * e2.a2() - e1.a2() + s**2 + e1.a1()*s)/ZZ(3) - t = (u**3 * e2.a3() - e1.a3() - e1.a1()*r)/ZZ(2) - return [u,r,s,t] + s = (u * e2.a1() - e1.a1()) / ZZ(2) + r = (usq * e2.a2() - e1.a2() + s**2 + e1.a1()*s) / ZZ(3) + t = (u**3 * e2.a3() - e1.a3() - e1.a1()*r) / ZZ(2) + return [u, r, s, t] - v = isom(E,Ew) + v = isom(E, Ew) u = v[0] r = v[1] # change basis - A = matrix.matrix([[u,-r/u],[0,1/u]]) + A = matrix([[u, -r/u], [0, 1/u]]) frn = A * fr * A**(-1) - return 1/p*frn - + return 1 / p*frn def __phi_bpr(self, prec=0): r""" @@ -1566,31 +1571,33 @@ def __phi_bpr(self, prec=0): for k in range(1,prec+1): # this is the equation eq[0]*x+eq[1]*y+eq[2] == 0 # such that delta_ = delta + d^dpr*x ... - eq = [(p**dpr*cs[k]) % p**k,(-p**dga*ds[k]) % p**k , (delta*cs[k]-gamma*ds[k]-cs[k-1]) % p**k ] + eq = [(p**dpr*cs[k]) % p**k, + (-p**dga*ds[k]) % p**k, + (delta*cs[k]-gamma*ds[k]-cs[k-1]) % p**k] verbose("valuations : %s" % ([x.valuation(p) for x in eq])) - v = min([x.valuation(p) for x in eq]) + v = min(x.valuation(p) for x in eq) if v == infinity: - verbose("no new information at step k=%s"%k) + verbose("no new information at step k=%s" % k) else: eq = [ZZ(x/p**v) for x in eq] - verbose("renormalised eq mod p^%s is now %s"%(k-v,eq)) + verbose("renormalised eq mod p^%s is now %s" % (k-v,eq)) if eq[0].valuation(p) == 0: l = min(eq[1].valuation(p),k-v) if l == 0: - verbose("not uniquely determined at step k=%s"%k) + verbose("not uniquely determined at step k=%s" % k) else: ainv = eq[0].inverse_mod(p**l) delta = delta - eq[2]*ainv*p**dpr dpr = dpr + l delta = delta % p**dpr - verbose("delta_prec increased to %s\n delta is now %s"%(dpr,delta)) + verbose("delta_prec increased to %s\n delta is now %s" % (dpr,delta)) elif eq[1].valuation(p) == 0: l = min(eq[0].valuation(p),k-v) ainv = eq[1].inverse_mod(p**l) gamma = gamma - eq[2]*ainv*p**dga dga = dga + l gamma = gamma % p**dga - verbose("gamma_prec increased to %s\n gamma is now %s"%(dga,gamma)) + verbose("gamma_prec increased to %s\n gamma is now %s" % (dga,gamma)) else: raise RuntimeError("Bug: no delta or gamma can exist") @@ -1598,12 +1605,12 @@ def __phi_bpr(self, prec=0): R = Qp(p,max(dpr,dga)+1) delta = R(delta,absprec=dpr) gamma = R(gamma,absprec=dga) - verbose("result delta = %s\n gamma = %s\n check : %s"%(delta,gamma, [Qp(p,k)(delta * cs[k] - gamma * ds[k] - cs[k-1]) for k in range(1,prec+1)] )) + verbose("result delta = %s\n gamma = %s\n check : %s" % (delta,gamma, [Qp(p,k)(delta * cs[k] - gamma * ds[k] - cs[k-1]) for k in range(1,prec+1)] )) a = delta c = -gamma d = E.ap(p) - a b = (-1/p+a*d)/c - phi = matrix.matrix([[a,b],[c,d]]) + phi = matrix([[a,b],[c,d]]) return phi def bernardi_sigma_function(self, prec=20): @@ -1665,7 +1672,9 @@ def Dp_valued_height(self,prec=20): elog = Ehat.log(prec + Integer(3)) # we will have to do it properly with David Harvey's _multiply_point() - n = LCM(E.tamagawa_numbers()) + # import here to avoid circular import + from sage.schemes.elliptic_curves.padics import _multiple_to_make_good_reduction + n = _multiple_to_make_good_reduction(E) n = LCM(n, E.Np(p)) # allowed here because E has good reduction at p def height(P,check=True): @@ -1680,15 +1689,15 @@ def height(P,check=True): tt = R(tt) zz = elog(tt) - homega = -zz**2/n**2 + homega = -zz**2 / n**2 - eQ = denominator(Q[1])/denominator(Q[0]) + eQ = denominator(Q[1]) / denominator(Q[0]) si = self.bernardi_sigma_function(prec=prec+4) - heta = 2 * log(si(zz)/eQ) / n**2 + heta = 2 * log(si(zz)/eQ) / n**2 - R = Qp(p,prec) + R = Qp(p, prec) - return vector([-R(heta),R(homega)]) + return vector([-R(heta), R(homega)]) return height @@ -1715,12 +1724,12 @@ def Dp_valued_regulator(self, prec=20, v1=0, v2=0): p = self._p E = self._E - h = self.Dp_valued_height(prec=prec) + h = self.Dp_valued_height(prec=prec) # this is the height_{v} (P) for a v in D_p - def hv(vec,P): + def hv(vec, P): hP = h(P) - return - vec[0]*hP[1] +vec[1]*hP[0] + return - vec[0]*hP[1] + vec[1]*hP[0] # def hvpairing(vec,P,Q): # return (hv(vec, P+Q) - hv(vec,P)-hv(vec,Q))/2 @@ -1739,11 +1748,11 @@ def hv(vec,P): basis = E.gens() def regv(vec): - M = matrix.matrix(K, rk, rk, 0) + M = matrix(K, rk, rk, 0) point_height = [hv(vec, P) for P in basis] for i in range(rk): for j in range(i+1, rk): - M[i, j] = M[j, i] = (hv(vec,basis[i] + basis[j])- point_height[i] - point_height[j] )/2 + M[i, j] = M[j, i] = (hv(vec,basis[i] + basis[j]) - point_height[i] - point_height[j] )/2 for i in range(rk): M[i, i] = point_height[i] diff --git a/src/sage/schemes/elliptic_curves/padics.py b/src/sage/schemes/elliptic_curves/padics.py index 96fb8510c12..6f05c10e6b5 100644 --- a/src/sage/schemes/elliptic_curves/padics.py +++ b/src/sage/schemes/elliptic_curves/padics.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.rings.padics # # All these methods are imported in EllipticCurve_rational_field, # so there is no reason to add this module to the documentation. -""" +r""" Miscellaneous `p`-adic methods """ @@ -21,25 +21,31 @@ # https://www.gnu.org/licenses/ ###################################################################### - -import sage.rings.all as rings -from . import padic_lseries as plseries -import sage.arith.all as arith -from sage.rings.all import ( - Qp, Zp, - Integers, - Integer, - O, - PowerSeriesRing, - LaurentSeriesRing, - RationalField) import math -import sage.misc.misc as misc -import sage.matrix.all as matrix -sqrt = math.sqrt -import sage.schemes.hyperelliptic_curves.monsky_washnitzer + +from sage.arith.functions import lcm as LCM +from sage.arith.misc import valuation +from sage.matrix.constructor import matrix +from sage.misc.misc import newton_method_sizes +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.padics.factory import Qp as pAdicField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing import sage.schemes.hyperelliptic_curves.hypellfrob +import sage.schemes.hyperelliptic_curves.monsky_washnitzer + from sage.misc.cachefunc import cached_method +from sage.rings.big_oh import O +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as Integers +from sage.rings.integer import Integer +from sage.rings.laurent_series_ring import LaurentSeriesRing +from sage.rings.padics.factory import Qp, Zp +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import RationalField + +from . import padic_lseries as plseries + +sqrt = math.sqrt + def __check_padic_hypotheses(self, p): r""" @@ -58,7 +64,7 @@ def __check_padic_hypotheses(self, p): ArithmeticError: p must be a good ordinary prime """ - p = rings.Integer(p) + p = Integer(p) if not p.is_prime(): raise ValueError("p = (%s) must be prime" % p) if p == 2: @@ -205,8 +211,8 @@ def padic_lseries(self, p, normalize=None, implementation='eclib', sage: L[3] O(11^0) """ - p, normalize, implementation, precision = self._normalize_padic_lseries(p,\ - normalize, implementation, precision) + p, normalize, implementation, precision = self._normalize_padic_lseries(p, + normalize, implementation, precision) if implementation in ['sage', 'eclib', 'num']: if self.ap(p) % p != 0: @@ -229,6 +235,8 @@ def padic_lseries(self, p, normalize=None, implementation='eclib', def padic_regulator(self, p, prec=20, height=None, check_hypotheses=True): r""" Compute the cyclotomic `p`-adic regulator of this curve. + The model of the curve needs to be integral and minimal at `p`. + Moreover the reduction at `p` should not be additive. INPUT: @@ -243,16 +251,11 @@ def padic_regulator(self, p, prec=20, height=None, check_hypotheses=True): - ``check_hypotheses`` -- boolean, whether to check that this is a curve for which the p-adic height makes sense - OUTPUT: The p-adic cyclotomic regulator of this curve, to the + OUTPUT: The `p`-adic cyclotomic regulator of this curve, to the requested precision. If the rank is 0, we output 1. - .. TODO:: - - Remove restriction that curve must be in minimal - Weierstrass form. This is currently required for E.gens(). - AUTHORS: - Liang Xiao: original implementation at the 2006 MSRI @@ -289,7 +292,7 @@ def padic_regulator(self, p, prec=20, height=None, check_hypotheses=True): sage: max_prec = 30 # make sure we get past p^2 # long time sage: full = E.padic_regulator(5, max_prec) # long time sage: for prec in range(1, max_prec): # long time - ....: assert E.padic_regulator(5, prec) == full # long time + ....: assert E.padic_regulator(5, prec) == full A case where the generator belongs to the formal group already (:trac:`3632`):: @@ -305,7 +308,7 @@ def padic_regulator(self, p, prec=20, height=None, check_hypotheses=True): sage: E.padic_regulator(7) == Em.padic_regulator(7) True - Allow a Python int as input:: + Allow a python int as input:: sage: E = EllipticCurve('37a') sage: E.padic_regulator(int(5)) @@ -314,7 +317,7 @@ def padic_regulator(self, p, prec=20, height=None, check_hypotheses=True): p = Integer(p) # this is assumed in code below if check_hypotheses: if not p.is_prime(): - raise ValueError("p = (%s) must be prime"%p) + raise ValueError("p = (%s) must be prime" % p) if p == 2: raise ValueError("p must be odd") # todo if self.conductor() % (p**2) == 0: @@ -340,9 +343,10 @@ def padic_regulator(self, p, prec=20, height=None, check_hypotheses=True): def padic_height_pairing_matrix(self, p, prec=20, height=None, check_hypotheses=True): r""" Computes the cyclotomic `p`-adic height pairing matrix of - this curve with respect to the basis self.gens() for the - Mordell-Weil group for a given odd prime p of good ordinary + this curve with respect to the basis ``self.gens()`` for the + Mordell-Weil group for a given odd prime `p` of good ordinary reduction. + The model needs to be integral and minimal at `p`. INPUT: @@ -357,14 +361,9 @@ def padic_height_pairing_matrix(self, p, prec=20, height=None, check_hypotheses= - ``check_hypotheses`` -- boolean, whether to check that this is a curve for which the p-adic height makes sense - OUTPUT: The p-adic cyclotomic height pairing matrix of this curve + OUTPUT: The `p`-adic cyclotomic height pairing matrix of this curve to the given precision. - .. TODO:: - - remove restriction that curve must be in minimal - Weierstrass form. This is currently required for E.gens(). - AUTHORS: - David Harvey, Liang Xiao, Robert Bradshaw, Jennifer @@ -403,7 +402,7 @@ def padic_height_pairing_matrix(self, p, prec=20, height=None, check_hypotheses= K = Qp(p, prec=prec) rank = self.rank() - M = matrix.matrix(K, rank, rank, 0) + M = matrix(K, rank, rank, 0) if rank == 0: return M @@ -425,14 +424,14 @@ def padic_height_pairing_matrix(self, p, prec=20, height=None, check_hypotheses= def _multiply_point(E, R, P, m): r""" - Computes coordinates of a multiple of P with entries in a ring. + Computes coordinates of a multiple of `P` with entries in a ring. INPUT: - - ``E`` -- elliptic curve over Q with integer + - ``E`` -- elliptic curve over `\QQ` with integer coefficients - - ``P`` -- a rational point on P that reduces to a + - ``P`` -- a rational point on `P` that reduces to a non-singular point at all primes - ``R`` -- a ring in which 2 is invertible (typically @@ -452,8 +451,7 @@ def _multiply_point(E, R, P, m): that the sign for `b'` will match the sign for `d'`. - ALGORITHM: Proposition 9 of "Efficient Computation of p-adic - Heights" (David Harvey, to appear in LMS JCM). + ALGORITHM: Proposition 9 in [Har2009]_. Complexity is soft-`O(\log L \log m + \log^2 m)`. @@ -581,12 +579,89 @@ def _multiply_point(E, R, P, m): return theta, omega, psi_m * d +def _multiple_to_make_good_reduction(E): + r""" + Return the integer `n_2` such that for all points `P` in `E(\QQ)` + `n_2*P` has good reduction at all primes. + If the model is globally minimal the lcm of the + Tamagawa numbers will do, otherwise we have to take into + account the change of the model. + + INPUT: + + - ``E`` -- an elliptic curve over `\QQ` + + OUTPUT: + + - a positive integer ``n2`` + + EXAMPLE (:trac:`34790`):: + + sage: from sage.schemes.elliptic_curves.padics import _multiple_to_make_good_reduction + sage: E = EllipticCurve([-1728,-100656]) + sage: _multiple_to_make_good_reduction(E) + 30 + + The number ``n_2`` is not always optimal but it is in this example. + The first multiple of the generator `P` with good reduction in this + non-minimal model is `30 P`. + + TESTS:: + + sage: from sage.schemes.elliptic_curves.padics import _multiple_to_make_good_reduction + sage: E = EllipticCurve([1/2,1/3]) + sage: _multiple_to_make_good_reduction(E) + Traceback (most recent call last): + ... + NotImplementedError: This only implemented for integral models. Please change the model first. + sage: E = EllipticCurve([0,3]) + sage: _multiple_to_make_good_reduction(E) + 1 + sage: E = EllipticCurve([0,5^7]) # min eq is additive + sage: _multiple_to_make_good_reduction(E) + 5 + sage: E = EllipticCurve([7,0,0,0,7^7]) # min eq is split mult + sage: _multiple_to_make_good_reduction(E) + 6 + sage: E = EllipticCurve([0,-3^2,0,0,3^7]) # min eq is non-split mult + sage: _multiple_to_make_good_reduction(E) + 4 + + """ + if not E.is_integral(): + st = ("This only implemented for integral models. " + "Please change the model first.") + raise NotImplementedError(st) + if E.is_minimal(): + n2 = LCM(E.tamagawa_numbers()) + else: + # generalising to number fields one can get the u from local_data + Emin = E.global_minimal_model() + iota = E.isomorphism_to(Emin) + u = Integer(iota.u) + ps = u.prime_divisors() + li = [] + for p in ps: + np = u.valuation(p) + if Emin.discriminant() % p != 0: + li.append(Emin.Np(p) * p**(np-1)) + elif Emin.has_additive_reduction(p): + li.append(E.tamagawa_number(p) * p**np) + elif E.has_split_multiplicative_reduction(p): + li.append(E.tamagawa_number(p) * (p-1) * p**(np-1)) + else: # non split + li.append(E.tamagawa_number(p) * (p+1) * p**(np-1)) + otherbad = Integer(Emin.discriminant()).prime_divisors() + otherbad = [p for p in otherbad if u % p != 0 ] + li += [E.tamagawa_number(p) for p in otherbad] + n2 = LCM(li) + return n2 def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): r""" - Compute the cyclotomic p-adic height. + Compute the cyclotomic `p`-adic height. - The equation of the curve must be minimal at `p`. + The equation of the curve must be integral and minimal at `p`. INPUT: @@ -603,7 +678,7 @@ def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): OUTPUT: A function that accepts two parameters: - - a Q-rational point on the curve whose height should be computed + - a `\QQ`-rational point on the curve whose height should be computed - optional boolean flag 'check': if False, it skips some input checking, and returns the p-adic height of that point to the @@ -611,8 +686,8 @@ def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): - The normalization (sign and a factor 1/2 with respect to some other normalizations that appear in the literature) is chosen in such a way - as to make the p-adic Birch Swinnerton-Dyer conjecture hold as stated - in [Mazur-Tate-Teitelbaum]. + as to make the `p`-adic Birch Swinnerton-Dyer conjecture hold as stated + in [MTT1986]_. AUTHORS: @@ -660,7 +735,7 @@ def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): sage: max_prec = 30 # make sure we get past p^2 # long time sage: full = E.padic_height(5, max_prec)(P) # long time sage: for prec in range(1, max_prec): # long time - ....: assert E.padic_height(5, prec)(P) == full # long time + ....: assert E.padic_height(5, prec)(P) == full A supersingular prime for a curve:: @@ -712,7 +787,7 @@ def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): """ if check_hypotheses: if not p.is_prime(): - raise ValueError("p = (%s) must be prime"%p) + raise ValueError("p = (%s) must be prime" % p) if p == 2: raise ValueError("p must be odd") # todo if self.conductor() % (p**2) == 0: @@ -731,16 +806,15 @@ def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): # else good ordinary case - # For notation and definitions, see "Efficient Computation of - # p-adic Heights", David Harvey (unpublished) + # For notation and definitions, see [Har2009]_. - n1 = self.change_ring(rings.GF(p)).cardinality() - n2 = arith.LCM(self.tamagawa_numbers()) - n = arith.LCM(n1, n2) + n1 = self.change_ring(GF(p)).cardinality() + n2 = _multiple_to_make_good_reduction(self) + n = LCM(n1, n2) m = int(n / n2) - adjusted_prec = prec + 2 * arith.valuation(n, p) # this is M' - R = rings.Integers(p ** adjusted_prec) + adjusted_prec = prec + 2 * valuation(n, p) # this is M' + R = Integers(p ** adjusted_prec) if sigma is None: sigma = self.padic_sigma(p, adjusted_prec, check_hypotheses=False) @@ -783,15 +857,13 @@ def height(P, check=True): "answer with precision at least prec, but we didn't." return K(answer) - # (man... I love python's local function definitions...) return height - def padic_height_via_multiply(self, p, prec=20, E2=None, check_hypotheses=True): r""" - Computes the cyclotomic p-adic height. + Computes the cyclotomic `p`-adic height. The equation of the curve must be minimal at `p`. @@ -804,7 +876,7 @@ def padic_height_via_multiply(self, p, prec=20, E2=None, check_hypotheses=True): - ``E2`` -- precomputed value of E2. If not supplied, this function will call padic_E2 to compute it. The value supplied - must be correct mod `p^(prec-2)` (or slightly higher in the + must be correct mod `p^{prec-2}` (or slightly higher in the anomalous case; see the code for details). - ``check_hypotheses`` -- boolean, whether to check @@ -812,22 +884,21 @@ def padic_height_via_multiply(self, p, prec=20, E2=None, check_hypotheses=True): OUTPUT: A function that accepts two parameters: - - a Q-rational point on the curve whose height should be computed + - a `\QQ`-rational point on the curve whose height should be computed - optional boolean flag 'check': if False, it skips some input - checking, and returns the p-adic height of that point to the + checking, and returns the `p`-adic height of that point to the desired precision. - The normalization (sign and a factor 1/2 with respect to some other normalizations that appear in the literature) is chosen in such a way as to make the p-adic Birch Swinnerton-Dyer conjecture hold as stated - in [Mazur-Tate-Teitelbaum]. + in [MTT1986]_. AUTHORS: - David Harvey (2008-01): based on the padic_height() function, - using the algorithm of"Computing p-adic heights via - point multiplication" + using the algorithm of [Har2009]_. EXAMPLES:: @@ -862,11 +933,11 @@ def padic_height_via_multiply(self, p, prec=20, E2=None, check_hypotheses=True): sage: max_prec = 30 # make sure we get past p^2 # long time sage: full = E.padic_height(5, max_prec)(P) # long time sage: for prec in range(2, max_prec): # long time - ....: assert E.padic_height_via_multiply(5, prec)(P) == full # long time + ....: assert E.padic_height_via_multiply(5, prec)(P) == full """ if check_hypotheses: if not p.is_prime(): - raise ValueError("p = (%s) must be prime"%p) + raise ValueError("p = (%s) must be prime" % p) if p == 2: raise ValueError("p must be odd") # todo if self.conductor() % p == 0: @@ -878,18 +949,17 @@ def padic_height_via_multiply(self, p, prec=20, E2=None, check_hypotheses=True): if prec < 1: raise ValueError("prec (=%s) must be at least 1" % prec) - # For notation and definitions, see ``Computing p-adic heights via point - # multiplication'' (David Harvey, still in draft form) + # For notation and definitions, [Har2009]_ - n1 = self.change_ring(rings.GF(p)).cardinality() - n2 = arith.LCM(self.tamagawa_numbers()) - n = arith.LCM(n1, n2) + n1 = self.change_ring(GF(p)).cardinality() + n2 = _multiple_to_make_good_reduction(self) + n = LCM(n1, n2) m = int(n / n2) lamb = int(math.floor(math.sqrt(prec))) - adjusted_prec = prec + 2 * arith.valuation(n, p) # this is M' - R = rings.Integers(p ** (adjusted_prec + 2*lamb)) + adjusted_prec = prec + 2 * valuation(n, p) # this is M' + R = Integers(p ** (adjusted_prec + 2*lamb)) sigma = self.padic_sigma_truncated(p, N=adjusted_prec, E2=E2, lamb=lamb) @@ -931,16 +1001,15 @@ def height(P, check=True): "answer with precision at least prec, but we didn't." return K(answer) - # (man... I love python's local function definitions...) return height def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): r""" - Computes the p-adic sigma function with respect to the standard + Computes the `p`-adic sigma function with respect to the standard invariant differential `dx/(2y + a_1 x + a_3)`, as - defined by Mazur and Tate, as a power series in the usual + defined by Mazur and Tate in [MT1991]_, as a power series in the usual uniformiser `t` at the origin. The equation of the curve must be minimal at `p`. @@ -963,7 +1032,7 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): - ``differential equation`` -- note that this does NOT guarantee correctness of all the returned digits, but it comes - pretty close :-)) + pretty close. - ``check_hypotheses`` -- boolean, whether to check that this is a curve for which the p-adic sigma function makes @@ -984,9 +1053,9 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): `p`-adic digits). ALGORITHM: Described in "Efficient Computation of p-adic Heights" - (David Harvey), which is basically an optimised version of the + (David Harvey) [Har2009]_ which is basically an optimised version of the algorithm from "p-adic Heights and Log Convergence" (Mazur, Stein, - Tate). + Tate) [MST2006]_. Running time is soft-`O(N^2 \log p)`, plus whatever time is necessary to compute `E_2`. @@ -1038,13 +1107,14 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): Test that it returns consistent results over a range of precision:: - sage: max_N = 30 # get up to at least p^2 # long time - sage: E = EllipticCurve([1, 1, 1, 1, 1]) # long time - sage: p = 5 # long time - sage: E2 = E.padic_E2(5, max_N) # long time - sage: max_sigma = E.padic_sigma(p, max_N, E2=E2) # long time - sage: for N in range(3, max_N): # long time - ....: sigma = E.padic_sigma(p, N, E2=E2) # long time + sage: # long time + sage: max_N = 30 # get up to at least p^2 + sage: E = EllipticCurve([1, 1, 1, 1, 1]) + sage: p = 5 + sage: E2 = E.padic_E2(5, max_N) + sage: max_sigma = E.padic_sigma(p, max_N, E2=E2) + sage: for N in range(3, max_N): + ....: sigma = E.padic_sigma(p, N, E2=E2) ....: assert sigma == max_sigma """ if check_hypotheses: @@ -1084,7 +1154,7 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): QQt = LaurentSeriesRing(RationalField(), "x") - R = rings.Integers(p**(N-2)) + R = Integers(p**(N-2)) X = self.change_ring(R) c = (X.a1()**2 + 4*X.a2() - R(E2)) / 12 @@ -1093,7 +1163,7 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): Rt = x.parent() - A = (x + c) * f + A = (x + c) * f # do integral over QQ, to avoid divisions by p A = Rt(QQt(A).integral()) A = (-X.a1()/2 - A) * f @@ -1105,7 +1175,7 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): assert A.valuation() == -1 and A[-1] == 1 A = A - A.parent().gen() ** (-1) A = A.power_series().list() - R = rings.Integers(p**(N-1)) + R = Integers(p**(N-1)) A = [R(u) for u in A] A[0] = self.change_ring(R).a1()/2 # fix constant term A = PowerSeriesRing(R, "x")(A, len(A)) @@ -1118,22 +1188,22 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): # [Note: there are actually more digits available, but it's a bit # tricky to figure out exactly how many, and we only need p^(N-k+1) # for p-adic height purposes anyway] - K = rings.pAdicField(p, N + 1) + K = pAdicField(p, N + 1) sigma = sigma.padded_list(N+1) - sigma[0] = K(0, N +1) + sigma[0] = K(0, N + 1) sigma[1] = K(1, N) for n in range(2, N+1): sigma[n] = K(sigma[n].lift(), N - n + 1) - S = rings.PowerSeriesRing(K, "t", N+1) + S = PowerSeriesRing(K, "t", N+1) sigma = S(sigma, N+1) # if requested, check that sigma satisfies the appropriate # differential equation if check: - R = rings.Integers(p**N) + R = Integers(p**N) X = self.change_ring(R) x = X.formal_group().x(N+5) # few extra terms for safety f = X.formal_group().differential(N+5) @@ -1159,7 +1229,7 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) r""" Compute the p-adic sigma function with respect to the standard invariant differential `dx/(2y + a_1 x + a_3)`, as - defined by Mazur and Tate, as a power series in the usual + defined by Mazur and Tate in [MT1991]_, as a power series in the usual uniformiser `t` at the origin. The equation of the curve must be minimal at `p`. @@ -1193,10 +1263,9 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) correct to precision `O(p^{N - 2 + (3 - j)(lamb + 1)})`. ALGORITHM: Described in "Efficient Computation of p-adic Heights" - (David Harvey, to appear in LMS JCM), which is basically an + [Har2009]_, which is basically an optimised version of the algorithm from "p-adic Heights and Log - Convergence" (Mazur, Stein, Tate), and "Computing p-adic heights - via point multiplication" (David Harvey, still draft form). + Convergence" (Mazur, Stein, Tate) [MST2006]_. Running time is soft-`O(N^2 \lambda^{-1} \log p)`, plus whatever time is necessary to compute `E_2`. @@ -1226,10 +1295,10 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) sage: E = EllipticCurve([1, 2, 3, 4, 7]) # long time sage: E2 = E.padic_E2(5, 50) # long time sage: for N in range(2, 10): # long time - ....: for lamb in range(10): # long time - ....: correct = E.padic_sigma(5, N + 3*lamb, E2=E2) # long time - ....: compare = E.padic_sigma_truncated(5, N=N, lamb=lamb, E2=E2) # long time - ....: assert compare == correct # long time + ....: for lamb in range(10): + ....: correct = E.padic_sigma(5, N + 3*lamb, E2=E2) + ....: compare = E.padic_sigma_truncated(5, N=N, lamb=lamb, E2=E2) + ....: assert compare == correct """ if check_hypotheses: p = __check_padic_hypotheses(self, p) @@ -1272,7 +1341,7 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) QQt = LaurentSeriesRing(RationalField(), "x") - R = rings.Integers(p**(N-2)) + R = Integers(p**(N-2)) X = self.change_ring(R) c = (X.a1()**2 + 4*X.a2() - R(E2)) / 12 @@ -1281,7 +1350,7 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) Rt = x.parent() - A = (x + c) * f + A = (x + c) * f # do integral over QQ, to avoid divisions by p A = Rt(QQt(A).integral()) A = (-X.a1()/2 - A) * f @@ -1293,7 +1362,7 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) assert A.valuation() == -1 and A[-1] == 1 A = A - A.parent().gen() ** (-1) A = A.power_series().list() - R = rings.Integers(p**(N-1+lamb)) + R = Integers(p**(N-1+lamb)) A = [R(u) for u in A] A[0] = self.change_ring(R).a1()/2 # fix constant term A = PowerSeriesRing(R, "x")(A, len(A)) @@ -1303,7 +1372,7 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) # Convert the answer to power series over p-adics; drop the precision # of the t^j coefficient to p^{N - 2 + (3 - j)(lamb + 1)}). - K = rings.pAdicField(p, N - 2 + 3*(lamb+1)) + K = pAdicField(p, N - 2 + 3*(lamb+1)) sigma = sigma.padded_list(trunc+1) @@ -1312,7 +1381,7 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) for j in range(2, trunc+1): sigma[j] = K(sigma[j].lift(), N - 2 + (3 - j)*(lamb+1)) - S = rings.PowerSeriesRing(K, "t", trunc + 1) + S = PowerSeriesRing(K, "t", trunc + 1) sigma = S(sigma, trunc+1) return sigma @@ -1378,7 +1447,7 @@ def padic_E2(self, p, prec=20, check=False, check_hypotheses=True, algorithm="au trick. EXAMPLES: Here is the example discussed in the paper "Computation - of p-adic Heights and Log Convergence" (Mazur, Stein, Tate):: + of p-adic Heights and Log Convergence" (Mazur, Stein, Tate) [MST2006]_:: sage: EllipticCurve([-1, 1/4]).padic_E2(5) 2 + 4*5 + 2*5^3 + 5^4 + 3*5^5 + 2*5^6 + 5^8 + 3*5^9 + 4*5^10 + 2*5^11 + 2*5^12 + 2*5^14 + 3*5^15 + 3*5^16 + 3*5^17 + 4*5^18 + 2*5^19 + O(5^20) @@ -1486,7 +1555,7 @@ def padic_E2(self, p, prec=20, check=False, check_hypotheses=True, algorithm="au frob_p_n = frob_p**prec # todo: think about the sign of this. Is it correct? - output_ring = rings.pAdicField(p, prec) + output_ring = pAdicField(p, prec) E2_of_X = output_ring( (-12 * frob_p_n[0,1] / frob_p_n[1,1]).lift() ) \ + O(p**prec) @@ -1621,16 +1690,16 @@ def matrix_of_frobenius(self, p, prec=20, check=False, check_hypotheses=True, al else: trace = self.ap(p) - base_ring = rings.Integers(p**adjusted_prec) + base_ring = Integers(p**adjusted_prec) - R, x = rings.PolynomialRing(base_ring, 'x').objgen() + R, x = PolynomialRing(base_ring, 'x').objgen() Q = x**3 + base_ring(X.a4()) * x + base_ring(X.a6()) frob_p = sage.schemes.hyperelliptic_curves.monsky_washnitzer.matrix_of_frobenius( Q, p, adjusted_prec, trace) else: # algorithm == "sqrtp" p_to_prec = p**prec - R = rings.PolynomialRing(Integers(), "x") + R = PolynomialRing(Integers(), "x") Q = R([X.a6() % p_to_prec, X.a4() % p_to_prec, 0, 1]) frob_p = sage.schemes.hyperelliptic_curves.hypellfrob.hypellfrob(p, prec, Q) @@ -1673,7 +1742,7 @@ def _brent(F, p, N): some log-log factors. For more information, and a proof of the precision guarantees, see - Lemma 4 in "Efficient Computation of p-adic Heights" (David Harvey). + Lemma 4 in [Har2009]_. AUTHORS: @@ -1711,7 +1780,7 @@ def _brent(F, p, N): G = Rx.one() # loop over an appropriate increasing sequence of lengths s - for s in misc.newton_method_sizes(N): + for s in newton_method_sizes(N): # zero-extend to s terms # todo: there has to be a better way in Sage to do this... G = Rx(G.list(), s) diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 7206ea74a7a..fe07917abaa 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Period lattices of elliptic curves and related functions @@ -17,46 +16,52 @@ EXAMPLES:: - sage: K.<a> = NumberField(x^3-2) - sage: E = EllipticCurve([0,1,0,a,a]) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: E = EllipticCurve([0,1,0,a,a]) # needs sage.rings.number_field First we try a real embedding:: - sage: emb = K.embeddings(RealField())[0] - sage: L = E.period_lattice(emb); L - Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x^2 + a*x + a over Number Field in a with defining polynomial x^3 - 2 with respect to the embedding Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Algebraic Real Field - Defn: a |--> 1.259921049894873? + sage: emb = K.embeddings(RealField())[0] # needs sage.rings.number_field + sage: L = E.period_lattice(emb); L # needs sage.rings.number_field + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x^2 + a*x + a + over Number Field in a with defining polynomial x^3 - 2 + with respect to the embedding Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Algebraic Real Field + Defn: a |--> 1.259921049894873? The first basis period is real:: - sage: L.basis() + sage: L.basis() # needs sage.rings.number_field (3.81452977217855, 1.90726488608927 + 1.34047785962440*I) - sage: L.is_real() + sage: L.is_real() # needs sage.rings.number_field True For a basis `\omega_1,\omega_2` normalised so that `\omega_1/\omega_2` is in the fundamental region of the upper half-plane, use the function ``normalised_basis()`` instead:: - sage: L.normalised_basis() + sage: L.normalised_basis() # needs sage.rings.number_field (1.90726488608927 - 1.34047785962440*I, -1.90726488608927 - 1.34047785962440*I) Next a complex embedding:: - sage: emb = K.embeddings(ComplexField())[0] - sage: L = E.period_lattice(emb); L - Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x^2 + a*x + a over Number Field in a with defining polynomial x^3 - 2 with respect to the embedding Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Algebraic Field - Defn: a |--> -0.6299605249474365? - 1.091123635971722?*I + sage: emb = K.embeddings(ComplexField())[0] # needs sage.rings.number_field + sage: L = E.period_lattice(emb); L # needs sage.rings.number_field + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x^2 + a*x + a + over Number Field in a with defining polynomial x^3 - 2 + with respect to the embedding Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Algebraic Field + Defn: a |--> -0.6299605249474365? - 1.091123635971722?*I In this case, the basis `\omega_1`, `\omega_2` is always normalised so that `\tau = \omega_1/\omega_2` is in the fundamental region in the upper half plane:: - sage: w1,w2 = L.basis(); w1,w2 + sage: # needs sage.rings.number_field + sage: w1, w2 = L.basis(); w1, w2 (-1.37588604166076 - 2.58560946624443*I, -2.10339907847356 + 0.428378776460622*I) sage: L.is_real() False @@ -67,14 +72,19 @@ We test that bug :trac:`8415` (caused by a PARI bug fixed in v2.3.5) is OK:: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('37a') sage: K.<a> = QuadraticField(-7) sage: EK = E.change_ring(K) sage: EK.period_lattice(K.complex_embeddings()[0]) - Period lattice associated to Elliptic Curve defined by y^2 + y = x^3 + (-1)*x over Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I with respect to the embedding Ring morphism: - From: Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I - To: Algebraic Field - Defn: a |--> -2.645751311064591?*I + Period lattice associated to Elliptic Curve defined by y^2 + y = x^3 + (-1)*x + over Number Field in a with defining polynomial x^2 + 7 + with a = 2.645751311064591?*I + with respect to the embedding Ring morphism: + From: Number Field in a with defining polynomial x^2 + 7 + with a = 2.645751311064591?*I + To: Algebraic Field + Defn: a |--> -2.645751311064591?*I REFERENCES: @@ -96,17 +106,22 @@ """ -from sage.modules.free_module import FreeModule_generic_pid -from sage.rings.all import ZZ, QQ, RealField, ComplexField, QQbar, AA import sage.rings.abc + +from sage.libs.pari.all import pari +from sage.misc.cachefunc import cached_method +from sage.modules.free_module import FreeModule_generic_pid +from sage.rings.complex_mpfr import ComplexField from sage.rings.complex_mpfr import ComplexNumber -from sage.rings.real_mpfr import RealNumber as RealNumber -from sage.rings.number_field.number_field import refine_embedding from sage.rings.infinity import Infinity +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import refine_embedding +from sage.rings.qqbar import AA, QQbar +from sage.rings.rational_field import QQ +from sage.rings.real_mpfr import RealField +from sage.rings.real_mpfr import RealNumber as RealNumber from sage.schemes.elliptic_curves.constructor import EllipticCurve -from sage.misc.cachefunc import cached_method from sage.structure.richcmp import richcmp_method, richcmp, richcmp_not_equal -from sage.libs.pari.all import pari class PeriodLattice(FreeModule_generic_pid): @@ -162,30 +177,38 @@ def __init__(self, E, embedding=None): sage: from sage.schemes.elliptic_curves.period_lattice import PeriodLattice_ell sage: E = EllipticCurve('37a') sage: PeriodLattice_ell(E) - Period lattice associated to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + Period lattice associated to + Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: emb = K.embeddings(RealField())[0] sage: E = EllipticCurve([0,1,0,a,a]) - sage: L = PeriodLattice_ell(E,emb); L - Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x^2 + a*x + a over Number Field in a with defining polynomial x^3 - 2 with respect to the embedding Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Algebraic Real Field - Defn: a |--> 1.259921049894873? - - sage: emb = K.embeddings(ComplexField())[0] - sage: L = PeriodLattice_ell(E,emb); L - Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x^2 + a*x + a over Number Field in a with defining polynomial x^3 - 2 with respect to the embedding Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Algebraic Field - Defn: a |--> -0.6299605249474365? - 1.091123635971722?*I + sage: L = PeriodLattice_ell(E, emb); L + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x^2 + a*x + a + over Number Field in a with defining polynomial x^3 - 2 + with respect to the embedding Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Algebraic Real Field + Defn: a |--> 1.259921049894873? + + sage: emb = K.embeddings(ComplexField())[0] # needs sage.rings.number_field + sage: L = PeriodLattice_ell(E, emb); L # needs sage.rings.number_field + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x^2 + a*x + a + over Number Field in a with defining polynomial x^3 - 2 + with respect to the embedding Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Algebraic Field + Defn: a |--> -0.6299605249474365? - 1.091123635971722?*I TESTS:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.period_lattice import PeriodLattice_ell - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: emb = K.embeddings(RealField())[0] sage: E = EllipticCurve([0,1,0,a,a]) sage: L = PeriodLattice_ell(E,emb) @@ -219,7 +242,7 @@ def __init__(self, E, embedding=None): self.real_flag = 0 if real: self.real_flag = +1 - if embedding(E.discriminant())<0: + if embedding(E.discriminant()) < 0: self.real_flag = -1 # The following algebraic data associated to E and the @@ -261,11 +284,13 @@ def __richcmp__(self, other, op): TESTS:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.period_lattice import PeriodLattice_ell - sage: K.<a> = NumberField(x^3-2) + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,1,0,a,a]) sage: embs = K.embeddings(ComplexField()) - sage: L1,L2,L3 = [PeriodLattice_ell(E,e) for e in embs] + sage: L1, L2, L3 = [PeriodLattice_ell(E, e) for e in embs] sage: L1 < L2 < L3 True """ @@ -292,19 +317,21 @@ def __repr__(self): :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: emb = K.embeddings(RealField())[0] sage: E = EllipticCurve([0,1,0,a,a]) sage: L = E.period_lattice(emb); L - Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x^2 + a*x + a over Number Field in a with defining polynomial x^3 - 2 with respect to the embedding Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Algebraic Real Field - Defn: a |--> 1.259921049894873? + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x^2 + a*x + a over Number Field in a + with defining polynomial x^3 - 2 with respect to the embedding Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Algebraic Real Field + Defn: a |--> 1.259921049894873? """ if self.E.base_field() is QQ: - return "Period lattice associated to %s"%(self.E) - else: - return "Period lattice associated to %s with respect to the embedding %s"%(self.E, self.embedding) + return "Period lattice associated to %s" % (self.E) + return "Period lattice associated to %s with respect to the embedding %s" % (self.E, self.embedding) def __call__(self, P, prec=None): r""" @@ -339,7 +366,7 @@ def __call__(self, P, prec=None): False sage: L(P, prec=96) 0.4793482501902193161295330101 + 0.985868850775824102211203849...*I - sage: Q=E([3,5]) + sage: Q = E([3,5]) sage: Q.is_on_identity_component() True sage: L(Q, prec=96) @@ -417,16 +444,19 @@ def basis(self, prec=None, algorithm='sage'): :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: emb = K.embeddings(RealField())[0] sage: E = EllipticCurve([0,1,0,a,a]) sage: L = E.period_lattice(emb) sage: L.basis(64) (3.81452977217854509, 1.90726488608927255 + 1.34047785962440202*I) + sage: # needs sage.rings.number_field sage: emb = K.embeddings(ComplexField())[0] sage: L = E.period_lattice(emb) - sage: w1,w2 = L.basis(); w1,w2 + sage: w1, w2 = L.basis(); w1, w2 (-1.37588604166076 - 2.58560946624443*I, -2.10339907847356 + 0.428378776460622*I) sage: L.is_real() False @@ -481,7 +511,7 @@ def gens(self, prec=None, algorithm='sage'): sage: E.period_lattice().gens() (2.99345864623196, 2.45138938198679*I) - sage: E.period_lattice().gens(prec = 100) + sage: E.period_lattice().gens(prec=100) (2.9934586462319596298320099794, 2.4513893819867900608542248319*I) """ return tuple(self.basis(prec=prec, algorithm=algorithm)) @@ -518,17 +548,22 @@ def normalised_basis(self, prec=None, algorithm='sage'): :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: emb = K.embeddings(RealField())[0] sage: E = EllipticCurve([0,1,0,a,a]) sage: L = E.period_lattice(emb) sage: L.normalised_basis(64) - (1.90726488608927255 - 1.34047785962440202*I, -1.90726488608927255 - 1.34047785962440202*I) + (1.90726488608927255 - 1.34047785962440202*I, + -1.90726488608927255 - 1.34047785962440202*I) + sage: # needs sage.rings.number_field sage: emb = K.embeddings(ComplexField())[0] sage: L = E.period_lattice(emb) - sage: w1,w2 = L.normalised_basis(); w1,w2 - (-1.37588604166076 - 2.58560946624443*I, -2.10339907847356 + 0.428378776460622*I) + sage: w1, w2 = L.normalised_basis(); w1, w2 + (-1.37588604166076 - 2.58560946624443*I, + -2.10339907847356 + 0.428378776460622*I) sage: L.is_real() False sage: tau = w1/w2; tau @@ -569,7 +604,9 @@ def tau(self, prec=None, algorithm='sage'): :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: emb = K.embeddings(RealField())[0] sage: E = EllipticCurve([0,1,0,a,a]) sage: L = E.period_lattice(emb) @@ -580,6 +617,7 @@ def tau(self, prec=None, algorithm='sage'): sage: -0.5 <= tau.real() <= 0.5 True + sage: # needs sage.rings.number_field sage: emb = K.embeddings(ComplexField())[0] sage: L = E.period_lattice(emb) sage: tau = L.tau(); tau @@ -615,7 +653,9 @@ def _compute_periods_real(self, prec=None, algorithm='sage'): EXAMPLES:: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,1,0,a,a]) sage: embs = K.embeddings(CC) sage: Ls = [E.period_lattice(e) for e in embs] @@ -643,7 +683,7 @@ def _compute_periods_real(self, prec=None, algorithm='sage'): w1, w2 = E_pari.omega() return R(w1), C(w2) - if algorithm!='sage': + if algorithm != 'sage': raise ValueError("invalid value of 'algorithm' parameter") pi = R.pi() @@ -685,7 +725,9 @@ def _compute_periods_complex(self, prec=None, normalise=True): EXAMPLES:: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,1,0,a,a]) sage: embs = K.embeddings(CC) sage: Ls = [E.period_lattice(e) for e in embs] @@ -693,7 +735,8 @@ def _compute_periods_complex(self, prec=None, normalise=True): [False, False, True] sage: L = Ls[0] sage: w1,w2 = L._compute_periods_complex(100); w1,w2 - (-1.3758860416607626645495991458 - 2.5856094662444337042877901304*I, -2.1033990784735587243397865076 + 0.42837877646062187766760569686*I) + (-1.3758860416607626645495991458 - 2.5856094662444337042877901304*I, + -2.1033990784735587243397865076 + 0.42837877646062187766760569686*I) sage: tau = w1/w2; tau 0.38769450503287609349437509561 + 1.3082108821440725664008561928*I sage: tau.real() @@ -703,6 +746,7 @@ def _compute_periods_complex(self, prec=None, normalise=True): Without normalisation:: + sage: # needs sage.rings.number_field sage: w1,w2 = L._compute_periods_complex(normalise=False); w1,w2 (2.10339907847356 - 0.428378776460622*I, 0.727513036812796 - 3.01398824270506*I) sage: tau = w1/w2; tau @@ -722,13 +766,13 @@ def _compute_periods_complex(self, prec=None, normalise=True): pi = C.pi() a, b, c = (C(x) for x in self._abc) if (a+b).abs() < (a-b).abs(): - b=-b + b = -b if (a+c).abs() < (a-c).abs(): - c=-c + c = -c w1 = pi/a.agm(b) w2 = pi*C.gen()/a.agm(c) - if (w1/w2).imag()<0: - w2=-w2 + if (w1/w2).imag() < 0: + w2 = -w2 if normalise: w1w2, mat = normalise_periods(w1,w2) return w1w2 @@ -746,8 +790,9 @@ def is_real(self): :: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) - sage: E = EllipticCurve(K,[0,0,0,i,2*i]) + sage: E = EllipticCurve(K, [0,0,0,i,2*i]) sage: emb = K.embeddings(ComplexField())[0] sage: L = E.period_lattice(emb) sage: L.is_real() @@ -755,9 +800,10 @@ def is_real(self): :: - sage: K.<a> = NumberField(x^3-2) - sage: E = EllipticCurve([0,1,0,a,a]) - sage: [E.period_lattice(emb).is_real() for emb in K.embeddings(CC)] + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) # needs sage.rings.number_field + sage: E = EllipticCurve([0,1,0,a,a]) # needs sage.rings.number_field + sage: [E.period_lattice(emb).is_real() for emb in K.embeddings(CC)] # needs sage.rings.number_field [False, False, True] ALGORITHM: @@ -765,7 +811,7 @@ def is_real(self): The lattice is real if it is associated to a real embedding; such lattices are stable under conjugation. """ - return self.real_flag!=0 + return self.real_flag != 0 def is_rectangular(self): r""" @@ -829,7 +875,9 @@ def real_period(self, prec=None, algorithm='sage'): :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: emb = K.embeddings(RealField())[0] sage: E = EllipticCurve([0,1,0,a,a]) sage: L = E.period_lattice(emb) @@ -876,7 +924,7 @@ def omega(self, prec=None, bsd_normalise=False): This is not a minimal model:: - sage: E = EllipticCurve([0,-432*6^2]) + sage: E = EllipticCurve([0, -432*6^2]) sage: E.period_lattice().omega() 0.486109385710056 @@ -890,7 +938,9 @@ def omega(self, prec=None, bsd_normalise=False): :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: emb = K.embeddings(RealField())[0] sage: E = EllipticCurve([0,1,0,a,a]) sage: L = E.period_lattice(emb) @@ -902,6 +952,7 @@ def omega(self, prec=None, bsd_normalise=False): quadratic fields*, Mathematics of Computation 62 No. 205 (1994), 407-429). See :trac:`29645` and :trac:`29782`:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: E = EllipticCurve([0,1-i,i,-i,0]) sage: L = E.period_lattice(K.embeddings(CC)[0]) @@ -947,7 +998,9 @@ def basis_matrix(self, prec=None, normalised=False): :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: emb = K.embeddings(RealField())[0] sage: E = EllipticCurve([0,1,0,a,a]) sage: L = E.period_lattice(emb) @@ -1004,7 +1057,9 @@ def complex_area(self, prec=None): :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: embs = K.embeddings(ComplexField()) sage: E = EllipticCurve([0,1,0,a,a]) sage: [E.period_lattice(emb).is_real() for emb in K.embeddings(CC)] @@ -1028,11 +1083,11 @@ def sigma(self, z, prec=None, flag=0): - ``flag`` -- - 0: (default) ???; + 0: (default) ???; - 1: computes an arbitrary determination of log(sigma(z)) + 1: computes an arbitrary determination of log(sigma(z)) - 2, 3: same using the product expansion instead of theta series. ??? + 2, 3: same using the product expansion instead of theta series. ??? .. NOTE:: @@ -1070,21 +1125,24 @@ def curve(self): :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,1,0,a,a]) sage: L = E.period_lattice(K.embeddings(RealField())[0]) sage: L.curve() is E True - sage: L = E.period_lattice(K.embeddings(ComplexField())[0]) - sage: L.curve() is E + sage: L = E.period_lattice(K.embeddings(ComplexField())[0]) # needs sage.rings.number_field + sage: L.curve() is E # needs sage.rings.number_field True """ return self.E def ei(self): r""" - Return the x-coordinates of the 2-division points of the elliptic curve associated with this period lattice, as elements of QQbar. + Return the x-coordinates of the 2-division points of the elliptic curve associated + with this period lattice, as elements of ``QQbar``. EXAMPLES:: @@ -1098,22 +1156,24 @@ def ei(self): :: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,1,0,a,a]) sage: L = E.period_lattice(K.embeddings(RealField())[0]) sage: x1,x2,x3 = L.ei() - sage: abs(x1.real())+abs(x2.real())<1e-14 + sage: abs(x1.real()) + abs(x2.real()) < 1e-14 True - sage: x1.imag(),x2.imag(),x3 + sage: x1.imag(), x2.imag(), x3 (-1.122462048309373?, 1.122462048309373?, -1.000000000000000?) :: - sage: L = E.period_lattice(K.embeddings(ComplexField())[0]) - sage: L.ei() + sage: L = E.period_lattice(K.embeddings(ComplexField())[0]) # needs sage.rings.number_field + sage: L.ei() # needs sage.rings.number_field [-1.000000000000000? + 0.?e-1...*I, - -0.9720806486198328? - 0.561231024154687?*I, - 0.9720806486198328? + 0.561231024154687?*I] + -0.9720806486198328? - 0.561231024154687?*I, + 0.9720806486198328? + 0.561231024154687?*I] """ return self._ei @@ -1135,12 +1195,12 @@ def coordinates(self, z, rounding=None): are a basis for the lattice (normalised in the case of complex embeddings). - When ``rounding`` is 'round', returns a tuple of integers `n_1`, + When ``rounding`` is ``'round'``, returns a tuple of integers `n_1`, `n_2` which are the closest integers to the `x`, `y` defined above. If `z` is in the lattice these are the coordinates of `z` with respect to the lattice basis. - When ``rounding`` is 'floor', returns a tuple of integers + When ``rounding`` is ``'floor'``, returns a tuple of integers `n_1`, `n_2` which are the integer parts to the `x`, `y` defined above. These are used in :meth:`.reduce` @@ -1154,14 +1214,14 @@ def coordinates(self, z, rounding=None): 0.47934825019021931612953301006 + 0.98586885077582410221120384908*I sage: L.coordinates(zP) (0.19249290511394227352563996419, 0.50000000000000000000000000000) - sage: sum([x*w for x,w in zip(L.coordinates(zP), L.basis(prec=100))]) + sage: sum([x*w for x, w in zip(L.coordinates(zP), L.basis(prec=100))]) 0.47934825019021931612953301006 + 0.98586885077582410221120384908*I - sage: L.coordinates(12*w1+23*w2) + sage: L.coordinates(12*w1 + 23*w2) (12.000000000000000000000000000, 23.000000000000000000000000000) - sage: L.coordinates(12*w1+23*w2, rounding='floor') + sage: L.coordinates(12*w1 + 23*w2, rounding='floor') (11, 22) - sage: L.coordinates(12*w1+23*w2, rounding='round') + sage: L.coordinates(12*w1 + 23*w2, rounding='round') (12, 23) """ C = z.parent() @@ -1176,23 +1236,23 @@ def coordinates(self, z, rounding=None): C = ComplexField() z = C(z) except TypeError: - raise TypeError("%s is not a complex number"%z) + raise TypeError("%s is not a complex number" % z) prec = C.precision() from sage.matrix.constructor import Matrix from sage.modules.free_module_element import vector if self.real_flag: - w1,w2 = self.basis(prec) - M = Matrix([[w1,0], list(w2)])**(-1) + w1, w2 = self.basis(prec) + M = Matrix([[w1, 0], list(w2)])**(-1) else: - w1,w2 = self.normalised_basis(prec) + w1, w2 = self.normalised_basis(prec) M = Matrix([list(w1), list(w2)])**(-1) - u,v = vector(z)*M + u, v = vector(z) * M # Now z = u*w1+v*w2 - if rounding=='round': + if rounding == 'round': return u.round(), v.round() - if rounding=='floor': + if rounding == 'floor': return u.floor(), v.floor() - return u,v + return u, v def reduce(self, z): r""" @@ -1217,7 +1277,7 @@ def reduce(self, z): sage: P = E([-1,1]) sage: zP = P.elliptic_logarithm(precision=100); zP 0.47934825019021931612953301006 + 0.98586885077582410221120384908*I - sage: z = zP+10*w1-20*w2; z + sage: z = zP + 10*w1 - 20*w2; z 25.381473858740770069343110929 - 38.448885180257139986236950114*I sage: L.reduce(z) 0.47934825019021931612953301006 + 0.98586885077582410221120384908*I @@ -1225,7 +1285,7 @@ def reduce(self, z): 0.958696500380439 sage: L.reduce(L.elliptic_logarithm(2*P)) 0.958696500380439 - sage: L.reduce(L.elliptic_logarithm(2*P)+10*w1-20*w2) + sage: L.reduce(L.elliptic_logarithm(2*P) + 10*w1 - 20*w2) 0.958696500380444 """ C = z.parent() @@ -1253,17 +1313,17 @@ def reduce(self, z): # NB We assume here that when the embedding is real then the # point is also real! - if self.real_flag == 0: + if self.real_flag == 0: return z if self.real_flag == -1: - k = (z.imag()/w2.imag()).round() + k = (z.imag() / w2.imag()).round() z = z-k*w2 - return C(z.real(),0) + return C(z.real(), 0) - if ((2*z.imag()/w2.imag()).round())%2: - return C(z.real(),w2.imag()/2) + if ((2*z.imag()/w2.imag()).round()) % 2: + return C(z.real(), w2.imag() / 2) else: - return C(z.real(),0) + return C(z.real(), 0) def e_log_RC(self, xP, yP, prec=None, reduce=True): r""" @@ -1313,7 +1373,9 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): A number field example:: - sage: K.<a> = NumberField(x^3-2) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 2) sage: E = EllipticCurve([0,0,0,0,a]) sage: v = K.real_places()[0] sage: L = E.period_lattice(v) @@ -1327,19 +1389,21 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): Elliptic logs of real points which do not come from algebraic points:: + sage: # needs sage.rings.number_field sage: ER = EllipticCurve([v(ai) for ai in E.a_invariants()]) sage: P = ER.lift_x(12.34) sage: xP, yP = P.xy() sage: xP, yP - (12.3400000000000, 43.3628968710567) + (12.3400000000000, -43.3628968710567) sage: L.e_log_RC(xP, yP) - 3.76298229503967 + 0.284656841192041 sage: xP, yP = ER.lift_x(0).xy() sage: L.e_log_RC(xP, yP) - 2.69842609082114 + 1.34921304541057 Elliptic logs of complex points:: + sage: # needs sage.rings.number_field sage: v = K.complex_embeddings()[0] sage: L = E.period_lattice(v) sage: P = E.lift_x(1/3*a^2 + a + 5/3) @@ -1351,7 +1415,7 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): sage: EC = EllipticCurve([v(ai) for ai in E.a_invariants()]) sage: xP, yP = EC.lift_x(0).xy() sage: L.e_log_RC(xP, yP) - 1.03355715602040 - 0.867257428417356*I + 2.06711431204080 - 1.73451485683471*I """ if prec is None: prec = RealField().precision() @@ -1372,10 +1436,10 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): if wP.is_zero(): # 2-torsion treated separately w1,w2 = self._compute_periods_complex(prec,normalise=False) - if xP==e1: + if xP == e1: z = w2/2 else: - if xP==e3: + if xP == e3: z = w1/2 else: z = (w1+w2)/2 @@ -1393,15 +1457,15 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): # but also causes problems (see #10026). It is left in but # commented out below. - if self.real_flag==0: # complex case + if self.real_flag == 0: # complex case a = C((e1-e3).sqrt()) b = C((e1-e2).sqrt()) if (a+b).abs() < (a-b).abs(): - b=-b + b = -b r = C(((xP-e3)/(xP-e2)).sqrt()) - if r.real()<0: - r=-r + if r.real() < 0: + r = -r t = -C(wP)/(2*r*(xP-e2)) # eps controls the end of the loop. Since we aim at a target # precision of prec bits, eps = 2^(-prec) is enough. @@ -1410,20 +1474,20 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): s = b*r+a a, b = (a+b)/2, (a*b).sqrt() if (a+b).abs() < (a-b).abs(): - b=-b + b = -b r = (a*(r+1)/s).sqrt() if (r.abs()-1).abs() < eps: break - if r.real()<0: - r=-r + if r.real() < 0: + r = -r t *= r z = ((a/t).arctan())/a z = ComplexField(prec)(z) if reduce: - z = self.reduce(z) + z = self.reduce(z) return z - if self.real_flag==-1: # real, connected case + if self.real_flag == -1: # real, connected case z = C(self._abc[0]) # sqrt(e3-e1) a, y, b = z.real(), z.imag(), z.abs() uv = (xP-e1).sqrt() @@ -1435,8 +1499,8 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): a = R(e3-e1).sqrt() b = R(e3-e2).sqrt() if (a+b).abs() < (a-b).abs(): - b=-b - on_egg = (xP<e3) + b = -b + on_egg = (xP < e3) if on_egg: r = a/R(e3-xP).sqrt() t = r*R(wP)/(2*R(xP-e1)) @@ -1454,16 +1518,15 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): if (r-1).abs() < eps: break t *= r - z = ((a/t).arctan())/a + z = ((a / t).arctan()) / a if on_egg: - w1,w2 = self._compute_periods_real(prec) - z += w2/2 + w1, w2 = self._compute_periods_real(prec) + z += w2 / 2 z = ComplexField(prec)(z) if reduce: - z = self.reduce(z) + z = self.reduce(z) return z - def elliptic_logarithm(self, P, prec=None, reduce=True): r""" Return the elliptic logarithm of a point. @@ -1534,32 +1597,35 @@ def elliptic_logarithm(self, P, prec=None, reduce=True): An example where precision is problematic:: - sage: E = EllipticCurve([1, 0, 1, -85357462, 303528987048]) #18074g1 + sage: E = EllipticCurve([1, 0, 1, -85357462, 303528987048]) #18074g1 sage: P = E([4458713781401/835903744, -64466909836503771/24167649046528, 1]) sage: L = E.period_lattice() sage: L.ei() - [5334.003952567705? - 1.964393150436?e-6*I, 5334.003952567705? + 1.964393150436?e-6*I, -10668.25790513541?] + [5334.003952567705? - 1.964393150436?e-6*I, + 5334.003952567705? + 1.964393150436?e-6*I, + -10668.25790513541?] sage: L.elliptic_logarithm(P,prec=100) 0.27656204014107061464076203097 Some complex examples, taken from the paper by Cremona and Thongjunthug:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) - sage: a4 = 9*i-10 - sage: a6 = 21-i + sage: a4 = 9*i - 10 + sage: a6 = 21 - i sage: E = EllipticCurve([0,0,0,a4,a6]) - sage: e1 = 3-2*i; e2 = 1+i; e3 = -4+i + sage: e1 = 3 - 2*i; e2 = 1 + i; e3 = -4 + i sage: emb = K.embeddings(CC)[1] sage: L = E.period_lattice(emb) - sage: P = E(2-i,4+2*i) + sage: P = E(2 - i, 4 + 2*i) By default, the output is reduced with respect to the normalised lattice basis, so that its coordinates with respect to that basis lie in the interval [0,1):: - sage: z = L.elliptic_logarithm(P,prec=100); z + sage: z = L.elliptic_logarithm(P, prec=100); z # needs sage.rings.number_field 0.70448375537782208460499649302 - 0.79246725643650979858266018068*I - sage: L.coordinates(z) + sage: L.coordinates(z) # needs sage.rings.number_field (0.46247636364807931766105406092, 0.79497588726808704200760395829) Using ``reduce=False`` this step can be omitted. In this case @@ -1567,58 +1633,60 @@ def elliptic_logarithm(self, P, prec=None, reduce=True): this is not guaranteed. This option is mainly for testing purposes:: - sage: z = L.elliptic_logarithm(P,prec=100, reduce=False); z + sage: z = L.elliptic_logarithm(P, prec=100, reduce=False); z # needs sage.rings.number_field 0.57002153834710752778063503023 + 0.46476340520469798857457031393*I - sage: L.coordinates(z) + sage: L.coordinates(z) # needs sage.rings.number_field (0.46247636364807931766105406092, -0.20502411273191295799239604171) The elliptic logs of the 2-torsion points are half-periods:: - sage: L.elliptic_logarithm(E(e1,0),prec=100) + sage: L.elliptic_logarithm(E(e1, 0), prec=100) # needs sage.rings.number_field 0.64607575874356525952487867052 + 0.22379609053909448304176885364*I - sage: L.elliptic_logarithm(E(e2,0),prec=100) + sage: L.elliptic_logarithm(E(e2, 0), prec=100) # needs sage.rings.number_field 0.71330686725892253793705940192 - 0.40481924028150941053684639367*I - sage: L.elliptic_logarithm(E(e3,0),prec=100) + sage: L.elliptic_logarithm(E(e3, 0), prec=100) # needs sage.rings.number_field 0.067231108515357278412180731396 - 0.62861533082060389357861524731*I We check this by doubling and seeing that the resulting coordinates are integers:: - sage: L.coordinates(2*L.elliptic_logarithm(E(e1,0),prec=100)) + sage: L.coordinates(2*L.elliptic_logarithm(E(e1, 0), prec=100)) # needs sage.rings.number_field (1.0000000000000000000000000000, 0.00000000000000000000000000000) - sage: L.coordinates(2*L.elliptic_logarithm(E(e2,0),prec=100)) + sage: L.coordinates(2*L.elliptic_logarithm(E(e2, 0), prec=100)) # needs sage.rings.number_field (1.0000000000000000000000000000, 1.0000000000000000000000000000) - sage: L.coordinates(2*L.elliptic_logarithm(E(e3,0),prec=100)) + sage: L.coordinates(2*L.elliptic_logarithm(E(e3, 0), prec=100)) # needs sage.rings.number_field (0.00000000000000000000000000000, 1.0000000000000000000000000000) :: + sage: # needs sage.rings.number_field sage: a4 = -78*i + 104 sage: a6 = -216*i - 312 sage: E = EllipticCurve([0,0,0,a4,a6]) sage: emb = K.embeddings(CC)[1] sage: L = E.period_lattice(emb) - sage: P = E(3+2*i,14-7*i) + sage: P = E(3 + 2*i, 14 - 7*i) sage: L.elliptic_logarithm(P) 0.297147783912228 - 0.546125549639461*I sage: L.coordinates(L.elliptic_logarithm(P)) (0.628653378040238, 0.371417754610223) - sage: e1 = 1+3*i; e2 = -4-12*i; e3=-e1-e2 - sage: L.coordinates(L.elliptic_logarithm(E(e1,0))) + sage: e1 = 1 + 3*i; e2 = -4 - 12*i; e3 = -e1 - e2 + sage: L.coordinates(L.elliptic_logarithm(E(e1, 0))) (0.500000000000000, 0.500000000000000) - sage: L.coordinates(L.elliptic_logarithm(E(e2,0))) + sage: L.coordinates(L.elliptic_logarithm(E(e2, 0))) (1.00000000000000, 0.500000000000000) - sage: L.coordinates(L.elliptic_logarithm(E(e3,0))) + sage: L.coordinates(L.elliptic_logarithm(E(e3, 0))) (0.500000000000000, 0.000000000000000) TESTS: See :trac:`10026` and :trac:`11767`:: + sage: # needs sage.rings.number_field sage: K.<w> = QuadraticField(2) - sage: E = EllipticCurve([ 0, -1, 1, -3*w -4, 3*w + 4 ]) - sage: T = E.simon_two_descent(lim1=20,lim3=5,limtriv=20) - sage: P,Q = T[2] + sage: E = EllipticCurve([0, -1, 1, -3*w - 4, 3*w + 4]) + sage: T = E.simon_two_descent(lim1=20, lim3=5, limtriv=20) + sage: P, Q = T[2] sage: embs = K.embeddings(CC) sage: Lambda = E.period_lattice(embs[0]) sage: Lambda.elliptic_logarithm(P, 100) @@ -1632,7 +1700,7 @@ def elliptic_logarithm(self, P, prec=None, reduce=True): -0.842248166487739393375018008381693990800588864069506187033873183845246233548058477561706400464057832396643843146464236956684557207157300006542470428493573195030603817094900751609464 - 0.571366031453267388121279381354098224265947866751130917440598461117775339240176310729173301979590106474259885638797913383502735083088736326391919063211421189027226502851390118943491*I sage: K.<a> = QuadraticField(-5) sage: E = EllipticCurve([1,1,a,a,0]) - sage: P = E(0,0) + sage: P = E(0, 0) sage: L = P.curve().period_lattice(K.embeddings(ComplexField())[0]) sage: L.elliptic_logarithm(P, prec=500) 1.17058357737548897849026170185581196033579563441850967539191867385734983296504066660506637438866628981886518901958717288150400849746892393771983141354 - 1.13513899565966043682474529757126359416758251309237866586896869548539516543734207347695898664875799307727928332953834601460994992792519799260968053875*I @@ -1688,31 +1756,36 @@ def elliptic_exponential(self, z, to_curve=True): EXAMPLES:: sage: E = EllipticCurve([1,1,1,-8,6]) - sage: P = E(1,-2) + sage: P = E(1, -2) sage: L = E.period_lattice() sage: z = L(P); z 1.17044757240090 sage: L.elliptic_exponential(z) (0.999999999999999 : -2.00000000000000 : 1.00000000000000) sage: _.curve() - Elliptic Curve defined by y^2 + 1.00000000000000*x*y + 1.00000000000000*y = x^3 + 1.00000000000000*x^2 - 8.00000000000000*x + 6.00000000000000 over Real Field with 53 bits of precision + Elliptic Curve defined by y^2 + 1.00000000000000*x*y + 1.00000000000000*y + = x^3 + 1.00000000000000*x^2 - 8.00000000000000*x + 6.00000000000000 + over Real Field with 53 bits of precision sage: L.elliptic_exponential(z,to_curve=False) (1.41666666666667, -2.00000000000000) - sage: z = L(P,prec=201); z + sage: z = L(P, prec=201); z 1.17044757240089592298992188482371493504472561677451007994189 sage: L.elliptic_exponential(z) - (1.00000000000000000000000000000000000000000000000000000000000 : -2.00000000000000000000000000000000000000000000000000000000000 : 1.00000000000000000000000000000000000000000000000000000000000) + (1.00000000000000000000000000000000000000000000000000000000000 + : -2.00000000000000000000000000000000000000000000000000000000000 + : 1.00000000000000000000000000000000000000000000000000000000000) Examples over number fields:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) - sage: K.<a> = NumberField(x^3-2) + sage: K.<a> = NumberField(x^3 - 2) sage: embs = K.embeddings(CC) sage: E = EllipticCurve('37a') sage: EK = E.change_ring(K) sage: Li = [EK.period_lattice(e) for e in embs] - sage: P = EK(-1,-1) - sage: Q = EK(a-1,1-a^2) + sage: P = EK(-1, -1) + sage: Q = EK(a - 1, 1 - a^2) sage: zi = [L.elliptic_logarithm(P) for L in Li] sage: [c.real() for c in Li[0].elliptic_exponential(zi[0])] [-1.00000000000000, -1.00000000000000, 1.00000000000000] @@ -1721,15 +1794,24 @@ def elliptic_exponential(self, z, to_curve=True): sage: [c.real() for c in Li[0].elliptic_exponential(zi[2])] [-1.00000000000000, -1.00000000000000, 1.00000000000000] + sage: # needs sage.rings.number_field sage: zi = [L.elliptic_logarithm(Q) for L in Li] sage: Li[0].elliptic_exponential(zi[0]) - (-1.62996052494744 - 1.09112363597172*I : 1.79370052598410 - 1.37472963699860*I : 1.00000000000000) + (-1.62996052494744 - 1.09112363597172*I + : 1.79370052598410 - 1.37472963699860*I + : 1.00000000000000) sage: [embs[0](c) for c in Q] - [-1.62996052494744 - 1.09112363597172*I, 1.79370052598410 - 1.37472963699860*I, 1.00000000000000] + [-1.62996052494744 - 1.09112363597172*I, + 1.79370052598410 - 1.37472963699860*I, + 1.00000000000000] sage: Li[1].elliptic_exponential(zi[1]) - (-1.62996052494744 + 1.09112363597172*I : 1.79370052598410 + 1.37472963699860*I : 1.00000000000000) + (-1.62996052494744 + 1.09112363597172*I + : 1.79370052598410 + 1.37472963699860*I + : 1.00000000000000) sage: [embs[1](c) for c in Q] - [-1.62996052494744 + 1.09112363597172*I, 1.79370052598410 + 1.37472963699860*I, 1.00000000000000] + [-1.62996052494744 + 1.09112363597172*I, + 1.79370052598410 + 1.37472963699860*I, + 1.00000000000000] sage: [c.real() for c in Li[2].elliptic_exponential(zi[2])] [0.259921049894873, -0.587401051968199, 1.00000000000000] sage: [embs[2](c) for c in Q] @@ -1737,13 +1819,16 @@ def elliptic_exponential(self, z, to_curve=True): Test to show that :trac:`8820` is fixed:: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('37a') sage: K.<a> = QuadraticField(-5) sage: L = E.change_ring(K).period_lattice(K.places()[0]) sage: L.elliptic_exponential(CDF(.1,.1)) - (0.0000142854026029... - 49.9960001066650*I : 249.520141250950 + 250.019855549131*I : 1.00000000000000) + (0.0000142854026029... - 49.9960001066650*I + : 249.520141250950 + 250.019855549131*I : 1.00000000000000) sage: L.elliptic_exponential(CDF(.1,.1), to_curve=False) - (0.0000142854026029447 - 49.9960001066650*I, 500.040282501900 + 500.039711098263*I) + (0.0000142854026029447 - 49.9960001066650*I, + 500.040282501900 + 500.039711098263*I) `z=0` is treated as a special case:: @@ -1756,16 +1841,20 @@ def elliptic_exponential(self, z, to_curve=True): :: + sage: # needs sage.rings.number_field sage: E = EllipticCurve('37a') sage: K.<a> = QuadraticField(-5) sage: L = E.change_ring(K).period_lattice(K.places()[0]) sage: P = L.elliptic_exponential(0); P (0.000000000000000 : 1.00000000000000 : 0.000000000000000) sage: P.parent() - Abelian group of points on Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision + Abelian group of points on Elliptic Curve defined by + y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x + over Complex Field with 53 bits of precision Very small `z` are handled properly (see :trac:`8820`):: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-1) sage: E = EllipticCurve([0,0,0,a,0]) sage: L = E.period_lattice(K.complex_embeddings()[0]) @@ -1778,9 +1867,9 @@ def elliptic_exponential(self, z, to_curve=True): sage: (100/log(2.0,10))/0.8 415.241011860920 - sage: L.elliptic_exponential((RealField(415)(1e-100))).is_zero() + sage: L.elliptic_exponential((RealField(415)(1e-100))).is_zero() # needs sage.rings.number_field True - sage: L.elliptic_exponential((RealField(420)(1e-100))).is_zero() + sage: L.elliptic_exponential((RealField(420)(1e-100))).is_zero() # needs sage.rings.number_field False """ C = z.parent() @@ -1857,13 +1946,14 @@ def reduce_tau(tau): (tuple) `(\tau',[a,b,c,d])` where `a,b,c,d` are integers such that - - `ad-bc=1`; - - `\tau`=(a\tau+b)/(c\tau+d)`; - - `|\tau'|\ge1`; - - `|\Re(\tau')|\le\frac{1}{2}`. + - `ad-bc=1`; + - `\tau'=(a\tau+b)/(c\tau+d)`; + - `|\tau'|\ge1`; + - `|\Re(\tau')|\le\frac{1}{2}`. EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage.symbolic sage: from sage.schemes.elliptic_curves.period_lattice import reduce_tau sage: reduce_tau(CC(1.23,3.45)) (0.230000000000000 + 3.45000000000000*I, [1, -1, 0, 1]) @@ -1879,15 +1969,15 @@ def reduce_tau(tau): tau -= k a -= k*c b -= k*d - while tau.abs()<0.999: + while tau.abs() < 0.999: tau = -1/tau a, b, c, d = c, d, -a, -b k = tau.real().round() tau -= k a -= k*c b -= k*d - assert a*d-b*c==1 - assert tau.abs()>=0.999 and tau.real().abs() <= 0.5 + assert a*d-b*c == 1 + assert tau.abs() >= 0.999 and tau.real().abs() <= 0.5 return tau, [a,b,c,d] @@ -1904,19 +1994,20 @@ def normalise_periods(w1, w2): (tuple) `((\omega_1',\omega_2'),[a,b,c,d])` where `a,b,c,d` are integers such that - - `ad-bc=\pm1`; - - `(\omega_1',\omega_2') = (a\omega_1+b\omega_2,c\omega_1+d\omega_2)`; - - `\tau=\omega_1'/\omega_2'` is in the upper half plane; - - `|\tau|\ge1` and `|\Re(\tau)|\le\frac{1}{2}`. + - `ad-bc=\pm1`; + - `(\omega_1',\omega_2') = (a\omega_1+b\omega_2,c\omega_1+d\omega_2)`; + - `\tau=\omega_1'/\omega_2'` is in the upper half plane; + - `|\tau|\ge1` and `|\Re(\tau)|\le\frac{1}{2}`. EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage.symbolic sage: from sage.schemes.elliptic_curves.period_lattice import reduce_tau, normalise_periods sage: w1 = CC(1.234, 3.456) sage: w2 = CC(1.234, 3.456000001) sage: w1/w2 # in lower half plane! 0.999999999743367 - 9.16334785827644e-11*I - sage: w1w2, abcd = normalise_periods(w1,w2) + sage: w1w2, abcd = normalise_periods(w1, w2) sage: a,b,c,d = abcd sage: w1w2 == (a*w1+b*w2, c*w1+d*w2) True @@ -1927,13 +2018,13 @@ def normalise_periods(w1, w2): """ tau = w1/w2 s = +1 - if tau.imag()<0: + if tau.imag() < 0: w2 = -w2 tau = -tau s = -1 tau, abcd = reduce_tau(tau) a, b, c, d = abcd - if s<0: + if s < 0: abcd = (a,-b,c,-d) return (a*w1+b*w2,c*w1+d*w2), abcd @@ -1952,17 +2043,18 @@ def extended_agm_iteration(a, b, c): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage: from sage.schemes.elliptic_curves.period_lattice import extended_agm_iteration - sage: extended_agm_iteration(RR(1),RR(2),RR(3)) + sage: extended_agm_iteration(RR(1), RR(2), RR(3)) (1.45679103104691, 1.45679103104691, 3.21245294970054) - sage: extended_agm_iteration(CC(1,2),CC(2,3),CC(3,4)) + sage: extended_agm_iteration(CC(1,2), CC(2,3), CC(3,4)) (1.46242448156430 + 2.47791311676267*I, - 1.46242448156430 + 2.47791311676267*I, - 3.22202144343535 + 4.28383734262540*I) + 1.46242448156430 + 2.47791311676267*I, + 3.22202144343535 + 4.28383734262540*I) TESTS:: - sage: extended_agm_iteration(1,2,3) + sage: extended_agm_iteration(1,2,3) # needs sage.rings.real_mpfr Traceback (most recent call last): ... ValueError: values must be real or complex numbers diff --git a/src/sage/schemes/elliptic_curves/period_lattice_region.pyx b/src/sage/schemes/elliptic_curves/period_lattice_region.pyx index 0d24651f4c1..b0914d6347a 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice_region.pyx +++ b/src/sage/schemes/elliptic_curves/period_lattice_region.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.complex_double sage.symbolic r""" Regions in fundamental domains of period lattices @@ -54,12 +55,12 @@ cdef class PeriodicRegion: sage: import numpy as np sage: from sage.schemes.elliptic_curves.period_lattice_region import PeriodicRegion sage: S = PeriodicRegion(CDF(2), CDF(2*I), np.zeros((4, 4))) - sage: S.plot() + sage: S.plot() # needs sage.plot Graphics object consisting of 1 graphics primitive sage: data = np.zeros((4, 4)) sage: data[1,1] = True sage: S = PeriodicRegion(CDF(2), CDF(2*I+1), data) - sage: S.plot() + sage: S.plot() # needs sage.plot Graphics object consisting of 5 graphics primitives """ if data.dtype is not np.int8: @@ -250,16 +251,16 @@ cdef class PeriodicRegion: sage: data = np.zeros((4, 4)) sage: data[1,1] = True sage: S = PeriodicRegion(CDF(1), CDF(I + 1/2), data) - sage: S.plot() + sage: S.plot() # needs sage.plot Graphics object consisting of 5 graphics primitives - sage: S.expand().plot() + sage: S.expand().plot() # needs sage.plot Graphics object consisting of 13 graphics primitives sage: S.expand().data array([[1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0]], dtype=int8) - sage: S.expand(corners=False).plot() + sage: S.expand(corners=False).plot() # needs sage.plot Graphics object consisting of 13 graphics primitives sage: S.expand(corners=False).data array([[0, 1, 0, 0], @@ -298,9 +299,9 @@ cdef class PeriodicRegion: sage: data = np.zeros((10, 10)) sage: data[1:4,1:4] = True sage: S = PeriodicRegion(CDF(1), CDF(I + 1/2), data) - sage: S.plot() + sage: S.plot() # needs sage.plot Graphics object consisting of 13 graphics primitives - sage: S.contract().plot() + sage: S.contract().plot() # needs sage.plot Graphics object consisting of 5 graphics primitives sage: S.contract().data.sum() 1 @@ -376,11 +377,11 @@ cdef class PeriodicRegion: sage: data[2:6, 2] = True sage: data[3, 3] = True sage: S = PeriodicRegion(CDF(1), CDF(I + 1/2), data) - sage: S.plot() + sage: S.plot() # needs sage.plot Graphics object consisting of 29 graphics primitives - sage: (S / 2).plot() + sage: (S / 2).plot() # needs sage.plot Graphics object consisting of 57 graphics primitives - sage: (S / 3).plot() + sage: (S / 3).plot() # needs sage.plot Graphics object consisting of 109 graphics primitives sage: (S / 2 / 3) == (S / 6) == (S / 3 / 2) True @@ -619,7 +620,7 @@ cdef class PeriodicRegion: sage: S = PeriodicRegion(CDF(1), CDF(I+1/2), data) sage: S.innermost_point() 0.375 + 0.25*I - sage: S.plot() + point(S.innermost_point()) + sage: S.plot() + point(S.innermost_point()) # needs sage.plot Graphics object consisting of 24 graphics primitives """ if self.is_empty(): @@ -646,7 +647,7 @@ cdef class PeriodicRegion: sage: data[2:5, 2] = True sage: data[3, 3] = True sage: S = PeriodicRegion(CDF(1), CDF(I + 1/2), data) - sage: plot(S) + plot(S.expand(), rgbcolor=(1, 0, 1), thickness=2) + sage: plot(S) + plot(S.expand(), rgbcolor=(1, 0, 1), thickness=2) # needs sage.plot Graphics object consisting of 46 graphics primitives """ from sage.plot.line import line diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index 9f5b59ac404..095b5b1be12 100644 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.rings.finite_rings sage.rings.number_field r""" Saturation of Mordell-Weil groups of elliptic curves over number fields @@ -24,7 +24,7 @@ already `p`-saturated this sieving technique can prove their saturation quickly. -The method :meth:`saturation` of the class EllipticCurve_number_field +The method :meth:`saturation` of the class :class:`EllipticCurve_number_field` applies full `p`-saturation at any given set of primes, or can compute a bound on the primes `p` at which the given points may not be `p`-saturated. This involves computing a lower bound for the @@ -52,10 +52,10 @@ from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.integer_ring import ZZ -from sage.arith.all import kronecker_symbol as kro +from sage.arith.misc import kronecker as kro from sage.structure.sage_object import SageObject -def reduce_mod_q(x,amodq): +def reduce_mod_q(x, amodq): r"""The reduction of ``x`` modulo the prime ideal defined by ``amodq``. INPUT: @@ -64,7 +64,7 @@ def reduce_mod_q(x,amodq): - ``amodq`` -- an element of `GF(q)` which is a root mod `q` of the defining polynomial of `K`. This defines a degree 1 prime - ideal `Q=(q,\alpha-a)` of `K=\QQ(\alpha)`, where `a \mod q = ` + ideal `Q=(q,\alpha-a)` of `K=\QQ(\alpha)`, where `a \bmod q` = ``amodq``. OUTPUT: @@ -75,15 +75,15 @@ def reduce_mod_q(x,amodq): sage: from sage.schemes.elliptic_curves.saturation import reduce_mod_q sage: x = polygen(QQ) - sage: pol = x^3 -x^2 -3*x + 1 + sage: pol = x^3 - x^2 - 3*x + 1 sage: K.<a> = NumberField(pol) - sage: [(q,[(amodq,reduce_mod_q(1-a+a^4,amodq)) - ....: for amodq in sorted(pol.roots(GF(q), multiplicities=False))]) - ....: for q in primes(50,70)] + sage: [(q, [(amodq, reduce_mod_q(1 - a + a^4, amodq)) + ....: for amodq in sorted(pol.roots(GF(q), multiplicities=False))]) + ....: for q in primes(50, 70)] [(53, []), - (59, [(36, 28)]), - (61, [(40, 35)]), - (67, [(10, 8), (62, 28), (63, 60)])] + (59, [(36, 28)]), + (61, [(40, 35)]), + (67, [(10, 8), (62, 28), (63, 60)])] """ Fq = amodq.parent() try: @@ -123,7 +123,7 @@ def __init__(self, E, verbose=False): self._field = K = E.base_field() if K.absolute_degree() == 1: from sage.rings.rational_field import QQ - from sage.rings.polynomial.all import polygen + from sage.rings.polynomial.polynomial_ring import polygen self._Kpol = polygen(QQ) else: self._Kpol = K.defining_polynomial() @@ -138,12 +138,13 @@ def __init__(self, E, verbose=False): # and gens are generators of that reduction. def add_reductions(self, q): - r"""Add reduction data at primes above q if not already there. + r""" + Add reduction data at primes above ``q`` if not already there. INPUT: - ``q`` -- a prime number not dividing the defining polynomial - of self.__field. + of ``self.__field``. OUTPUT: @@ -165,8 +166,8 @@ def add_reductions(self, q): {} sage: saturator.add_reductions(19) sage: saturator._reductions - {19: {0: (20, - Elliptic Curve defined by y^2 + y = x^3 + 18*x^2 + 9*x + 18 over Finite Field of size 19)}} + {19: {0: (20, Elliptic Curve defined by y^2 + y = x^3 + 18*x^2 + 9*x + 18 + over Finite Field of size 19)}} Over a number field:: @@ -177,30 +178,30 @@ def add_reductions(self, q): sage: for q in primes(20): ....: saturator.add_reductions(q) sage: saturator._reductions - {2: {}, - 3: {}, - 5: {}, - 7: {}, - 11: {3: (16, - Elliptic Curve defined by y^2 = x^3 + x^2 + 3*x + 3 over Finite Field of size 11), - 8: (8, - Elliptic Curve defined by y^2 = x^3 + x^2 + 8*x + 8 over Finite Field of size 11)}, - 13: {}, - 17: {7: (20, - Elliptic Curve defined by y^2 = x^3 + x^2 + 7*x + 7 over Finite Field of size 17), - 10: (18, - Elliptic Curve defined by y^2 = x^3 + x^2 + 10*x + 10 over Finite Field of size 17)}, - 19: {6: (16, - Elliptic Curve defined by y^2 = x^3 + x^2 + 6*x + 6 over Finite Field of size 19), - 13: (12, - Elliptic Curve defined by y^2 = x^3 + x^2 + 13*x + 13 over Finite Field of size 19)}} + {2: {}, + 3: {}, + 5: {}, + 7: {}, + 11: {3: (16, Elliptic Curve defined by y^2 = x^3 + x^2 + 3*x + 3 + over Finite Field of size 11), + 8: (8, Elliptic Curve defined by y^2 = x^3 + x^2 + 8*x + 8 + over Finite Field of size 11)}, + 13: {}, + 17: {7: (20, Elliptic Curve defined by y^2 = x^3 + x^2 + 7*x + 7 + over Finite Field of size 17), + 10: (18, Elliptic Curve defined by y^2 = x^3 + x^2 + 10*x + 10 + over Finite Field of size 17)}, + 19: {6: (16, Elliptic Curve defined by y^2 = x^3 + x^2 + 6*x + 6 + over Finite Field of size 19), + 13: (12, Elliptic Curve defined by y^2 = x^3 + x^2 + 13*x + 13 + over Finite Field of size 19)}} """ if q in self._reductions: return self._reductions[q] = redmodq = dict() if q.divides(self._N) or q.divides(self._D): return - from sage.schemes.elliptic_curves.all import EllipticCurve + from sage.schemes.elliptic_curves.constructor import EllipticCurve for amodq in sorted(self._Kpol.roots(GF(q), multiplicities=False)): Eq = EllipticCurve([reduce_mod_q(ai, amodq) for ai in self._curve.ainvs()]) nq = Eq.cardinality() @@ -228,17 +229,17 @@ def full_p_saturation(self, Plist, p): sage: E = EllipticCurve('389a') sage: K.<i> = QuadraticField(-1) sage: EK = E.change_ring(K) - sage: P = EK(1+i,-1-2*i) + sage: P = EK(1 + i, -1 - 2*i) sage: saturator = EllipticCurveSaturator(EK, verbose=True) - sage: saturator.full_p_saturation([8*P],2) + sage: saturator.full_p_saturation([8*P], 2) --starting full 2-saturation Points were not 2-saturated, exponent was 3 ([(i + 1 : -2*i - 1 : 1)], 3) - sage: Q = EK(0,0) - sage: R = EK(-1,1) + sage: Q = EK(0, 0) + sage: R = EK(-1, 1) sage: saturator = EllipticCurveSaturator(EK, verbose=False) - sage: saturator.full_p_saturation([P,Q,R],3) + sage: saturator.full_p_saturation([P, Q, R], 3) ([(i + 1 : -2*i - 1 : 1), (0 : 0 : 1), (-1 : 1 : 1)], 0) An example where the points are not 7-saturated and we gain @@ -247,11 +248,10 @@ def full_p_saturation(self, Plist, p): `p`-rank 2 (which occurs for the reduction modulo `(16-5i)`), which uses the Weil pairing:: - sage: saturator.full_p_saturation([P,Q+3*R,Q-4*R],7) + sage: saturator.full_p_saturation([P, Q + 3*R, Q - 4*R], 7) ([(i + 1 : -2*i - 1 : 1), - (2869/676 : 154413/17576 : 1), - (-7095/502681 : -366258864/356400829 : 1)], - 1) + (2869/676 : 154413/17576 : 1), + (-7095/502681 : -366258864/356400829 : 1)], 1) """ if not Plist: return Plist, ZZ.zero() @@ -268,7 +268,7 @@ def full_p_saturation(self, Plist, p): verbose = self._verbose if verbose: - print(" --starting full %s-saturation" % p) + print(" --starting full %s-saturation" % p) n = len(Plist) # number of points supplied & to be returned Plist = Plist + [T for T in self._torsion_gens if p.divides(T.order())] @@ -328,23 +328,23 @@ def p_saturation(self, Plist, p, sieve=True): sage: E = EllipticCurve('389a') sage: K.<i> = QuadraticField(-1) sage: EK = E.change_ring(K) - sage: P = EK(1+i,-1-2*i) + sage: P = EK(1 + i, -1 - 2*i) sage: saturator = EllipticCurveSaturator(EK) - sage: saturator.p_saturation([P],2) + sage: saturator.p_saturation([P], 2) False - sage: saturator.p_saturation([2*P],2) + sage: saturator.p_saturation([2*P], 2) (0, (i + 1 : -2*i - 1 : 1)) - sage: Q = EK(0,0) - sage: R = EK(-1,1) - sage: saturator.p_saturation([P,Q,R],3) + sage: Q = EK(0, 0) + sage: R = EK(-1, 1) + sage: saturator.p_saturation([P, Q, R], 3) False Here we see an example where 19-saturation is proved, with the verbose flag set to True so that we can see what is going on:: sage: saturator = EllipticCurveSaturator(EK, verbose=True) - sage: saturator.p_saturation([P,Q,R],19) + sage: saturator.p_saturation([P, Q, R], 19) Using sieve method to saturate... E has 19-torsion over Finite Field of size 197, projecting points --> [(15 : 168 : 1), (0 : 0 : 1), (196 : 1 : 1)] @@ -361,27 +361,27 @@ def p_saturation(self, Plist, p, sieve=True): An example where the points are not 11-saturated:: sage: saturator = EllipticCurveSaturator(EK, verbose=False) - sage: res = saturator.p_saturation([P+5*Q,P-6*Q,R],11); res - (0, - (-5783311/14600041*i + 1396143/14600041 : 37679338314/55786756661*i + 3813624227/55786756661 : 1)) + sage: res = saturator.p_saturation([P + 5*Q, P - 6*Q, R], 11); res + (0, (-5783311/14600041*i + 1396143/14600041 + : 37679338314/55786756661*i + 3813624227/55786756661 : 1)) That means that the 0'th point may be replaced by the displayed point to achieve an index gain of 11:: - sage: saturator.p_saturation([res[1],P-6*Q,R],11) + sage: saturator.p_saturation([res[1], P - 6*Q, R], 11) False TESTS: See :trac:`27387`:: - sage: K.<a> = NumberField(x^2-x-26) - sage: E = EllipticCurve([a,1-a,0,93-16*a, 3150-560*a]) - sage: P = E([65-35*a/3, (959*a-5377)/9]) + sage: K.<a> = NumberField(x^2 - x - 26) + sage: E = EllipticCurve([a, 1 - a, 0, 93 - 16*a, 3150 - 560*a]) + sage: P = E([65 - 35*a/3, (959*a-5377)/9]) sage: T = E.torsion_points()[0] sage: from sage.schemes.elliptic_curves.saturation import EllipticCurveSaturator sage: saturator = EllipticCurveSaturator(E, True) - sage: saturator.p_saturation([P,T], 2) + sage: saturator.p_saturation([P, T], 2) Using sieve method to saturate... ... -- points were not 2-saturated, gaining index 2 @@ -390,7 +390,7 @@ def p_saturation(self, Plist, p, sieve=True): A CM example where large siecing primes are needed (LMFDB label 2.0.3.1-50625.1-CMb2):: - sage: K.<a> = NumberField(x^2-x+1) + sage: K.<a> = NumberField(x^2 - x + 1) sage: E = EllipticCurve(K, [0, 0, 1, -750, 7906]) sage: E.has_rational_cm() True @@ -492,7 +492,7 @@ def p_saturation(self, Plist, p, sieve=True): # and there is no simple test.) avoid = [self._N, self._D] + [P[0].denominator_ideal().norm() for P in Plist] - cm_test = E.has_rational_cm() and kro(E.cm_discriminant(), p)==-1 + cm_test = E.has_rational_cm() and kro(E.cm_discriminant(), p) == -1 for q in Primes(): if any(q.divides(m) for m in avoid): continue @@ -543,7 +543,7 @@ def p_saturation(self, Plist, p, sieve=True): # point which is certainly a p-multiple # modulo 15 primes Q, and we test if it # actually is a p-multiple: - if len(Rlist)==1: + if len(Rlist) == 1: R = Rlist[0] pts = R.division_points(p) if pts: @@ -593,11 +593,11 @@ def p_projections(Eq, Plist, p, debug=False): INPUT: - - `Eq` -- An elliptic curve over a finite field. + - ``Eq`` -- An elliptic curve over a finite field. - - `Plist` -- a list of points on `Eq`. + - ``Plist`` -- a list of points on `Eq`. - - `p` -- a prime number. + - ``p`` -- a prime number. OUTPUT: @@ -626,7 +626,9 @@ def p_projections(Eq, Plist, p, debug=False): sage: EF = E.change_ring(F) sage: G = EF.abelian_group() sage: G - Additive abelian group isomorphic to Z/147 + Z/3 embedded in Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 + 402*x + 6 over Finite Field of size 409 + Additive abelian group isomorphic to Z/147 + Z/3 + embedded in Abelian group of points on Elliptic Curve + defined by y^2 + y = x^3 + 402*x + 6 over Finite Field of size 409 sage: G.order().factor() 3^2 * 7^2 @@ -637,9 +639,9 @@ def p_projections(Eq, Plist, p, debug=False): sage: Plist = [EF([-2,3]), EF([0,2]), EF([1,0])] sage: from sage.schemes.elliptic_curves.saturation import p_projections - sage: [(p,p_projections(EF,Plist,p)) for p in primes(11)] # random + sage: [(p, p_projections(EF, Plist, p)) for p in primes(11)] # random [(2, []), (3, [(0, 2, 2), (2, 2, 1)]), (5, []), (7, [(5, 1, 1)])] - sage: [(p,len(p_projections(EF,Plist,p))) for p in primes(11)] + sage: [(p, len(p_projections(EF, Plist, p))) for p in primes(11)] [(2, 0), (3, 2), (5, 0), (7, 1)] """ if debug: @@ -648,7 +650,7 @@ def p_projections(Eq, Plist, p, debug=False): m = n.prime_to_m_part(p) # prime-to-p part of order if debug: print("m={}, n={}".format(m,n)) - if m==n: # p-primary part trivial, nothing to do + if m == n: # p-primary part trivial, nothing to do return [] G = Eq.abelian_group() if debug: @@ -656,7 +658,7 @@ def p_projections(Eq, Plist, p, debug=False): # project onto p-primary part - pts = [m*pt for pt in Plist] + pts = [m*pt for pt in Plist] gens = [m*g.element() for g in G.gens()] gens = [g for g in gens if g] if debug: diff --git a/src/sage/schemes/elliptic_curves/sha_tate.py b/src/sage/schemes/elliptic_curves/sha_tate.py index bf8eb3e060e..33818051b8f 100644 --- a/src/sage/schemes/elliptic_curves/sha_tate.py +++ b/src/sage/schemes/elliptic_curves/sha_tate.py @@ -50,7 +50,8 @@ sage: E = EllipticCurve('389a') sage: S = E.sha(); S - Tate-Shafarevich group for the Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field + Tate-Shafarevich group for the + Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field sage: S.an_numerical() 1.00000000000000 sage: S.p_primary_bound(5) @@ -80,12 +81,11 @@ # **************************************************************************** from sage.structure.sage_object import SageObject -from sage.rings.all import ( - Integer, - RealField, - RationalField, - RIF, - ZZ) +from sage.rings.integer import Integer +from sage.rings.real_mpfr import RealField +from sage.rings.rational_field import RationalField +from sage.rings.real_mpfi import RIF +from sage.rings.integer_ring import ZZ from sage.functions.log import log from math import sqrt from sage.misc.verbose import verbose @@ -125,7 +125,8 @@ class Sha(SageObject): sage: E = EllipticCurve('389a') sage: S = E.sha(); S - Tate-Shafarevich group for the Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field + Tate-Shafarevich group for the + Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field sage: S.an_numerical() 1.00000000000000 sage: S.p_primary_bound(5) # long time @@ -148,7 +149,8 @@ def __init__(self, E): sage: E = EllipticCurve('11a1') sage: S = E.sha() sage: S - Tate-Shafarevich group for the Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + Tate-Shafarevich group for the + Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field sage: S == loads(dumps(S)) True @@ -261,11 +263,11 @@ def an_numerical(self, prec=None, sage: sha = EllipticCurve('37a1').sha() sage: [sha.an_numerical(prec) for prec in range(40,100,10)] # long time (3s on sage.math, 2013) [1.0000000000, - 1.0000000000000, - 1.0000000000000000, - 1.0000000000000000000, - 1.0000000000000000000000, - 1.0000000000000000000000000] + 1.0000000000000, + 1.0000000000000000, + 1.0000000000000000000, + 1.0000000000000000000000, + 1.0000000000000000000000000] """ if prec is None: prec = RealField().precision() @@ -325,8 +327,9 @@ def an(self, use_database=False, descent_second_limit=12): sage: E.sha().an() Traceback (most recent call last): ... - RuntimeError: Unable to compute the rank, hence generators, with certainty (lower bound=0, generators found=[]). This could be because Sha(E/Q)[2] is nontrivial. - Try increasing descent_second_limit then trying this command again. + RuntimeError: Unable to compute the rank, hence generators, with certainty + (lower bound=0, generators found=[]). This could be because Sha(E/Q)[2] is + nontrivial. Try increasing descent_second_limit then trying this command again. You can increase the ``descent_second_limit`` (in the above example, set to the default, 12) option to try again:: @@ -389,14 +392,14 @@ def an(self, use_database=False, descent_second_limit=12): In this case the input curve is not minimal, and if this function did not transform it to be minimal, it would give nonsense:: - sage: E = EllipticCurve([0,-432*6^2]) + sage: E = EllipticCurve([0, -432*6^2]) sage: E.sha().an() 1 See :trac:`10096`: this used to give the wrong result 6.0000 before since the minimal model was not used:: - sage: E = EllipticCurve([1215*1216,0]) # non-minimal model + sage: E = EllipticCurve([1215*1216, 0]) # non-minimal model sage: E.sha().an() # long time (2s on sage.math, 2011) 1.00000000000000 sage: E.minimal_model().sha().an() # long time (1s on sage.math, 2011) @@ -524,7 +527,7 @@ def an_padic(self, p, prec=0, use_twists=True): 1 + O(5) sage: EllipticCurve('240d3').sha().an_padic(5) # sha has 4 elements here 4 + O(5) - sage: EllipticCurve('448c5').sha().an_padic(7,prec=4, use_twists=False) # long time (2s on sage.math, 2011) + sage: EllipticCurve('448c5').sha().an_padic(7, prec=4, use_twists=False) # long time (2s on sage.math, 2011) 2 + 7 + O(7^6) sage: EllipticCurve([-19,34]).sha().an_padic(5) # see trac #6455, long time (4s on sage.math, 2011) 1 + O(5) @@ -842,7 +845,9 @@ def p_primary_bound(self, p): sage: E.sha().p_primary_bound(5) Traceback (most recent call last): ... - ValueError: The p-adic Galois representation is not surjective or reducible. Current knowledge about Euler systems does not provide an upper bound in this case. Try an_padic for a conjectural bound. + ValueError: The p-adic Galois representation is not surjective or reducible. + Current knowledge about Euler systems does not provide an upper bound + in this case. Try an_padic for a conjectural bound. sage: E.sha().an_padic(5) # long time 1 + O(5^22) @@ -1076,9 +1081,9 @@ def bound_kato(self): THEOREM: Suppose `L(E,1) \neq 0` and `p \neq 2` is a prime such that - - `E` does not have additive reduction at `p`, - - either the `p`-adic representation is surjective or has its - image contained in a Borel subgroup. + - `E` does not have additive reduction at `p`, + - either the `p`-adic representation is surjective or has its + image contained in a Borel subgroup. Then `{ord}_p(\#Sha(E))` is bounded from above by the `p`-adic valuation of `L(E,1)\cdot\#E(\QQ)_{tor}^2 / (\Omega_E \cdot \prod c_v)`. @@ -1100,15 +1105,15 @@ def bound_kato(self): order of `Sha` (by [GJPST2009]_):: sage: E = EllipticCurve([1, -1, 0, -332311, -73733731]) # 1058D1 - sage: E.sha().bound_kato() # long time (about 1 second) + sage: E.sha().bound_kato() # long time (about 1 second) [2, 5, 23] - sage: E.galois_representation().non_surjective() # long time (about 1 second) + sage: E.galois_representation().non_surjective() # long time (about 1 second) [] For this one, `Sha` is divisible by 7:: sage: E = EllipticCurve([0, 0, 0, -4062871, -3152083138]) # 3364C1 - sage: E.sha().bound_kato() # long time (< 10 seconds) + sage: E.sha().bound_kato() # long time (< 10 seconds) [2, 7, 29] No information about curves of rank > 0:: diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index 6b56e94eba8..57ff015a2b2 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -29,7 +29,8 @@ from sage.schemes.elliptic_curves.hom import EllipticCurveHom from sage.structure.richcmp import (richcmp, richcmp_not_equal, op_EQ, op_NE) from sage.structure.sequence import Sequence -from sage.rings.all import Integer, PolynomialRing +from sage.rings.integer import Integer +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing class baseWI(): r""" @@ -257,12 +258,14 @@ def _isomorphisms(E, F): sage: p = random_prime(100) sage: F = GF(p).algebraic_closure() - sage: while True: - ....: try: - ....: E = EllipticCurve(list((F^5).random_element())) - ....: except ArithmeticError: - ....: continue - ....: break + sage: j = F.random_element() + sage: while j in (0, 1728): # skip the hard case + ....: j = F.random_element() + sage: j = F(choice((0, 1728))) # long time -- do the hard case + sage: E = EllipticCurve_from_j(j) + sage: u,r,s,t = (F^4).random_element() + sage: u = u or 1 + sage: E = E.change_weierstrass_model(u,r,s,t) sage: Aut = E.automorphisms() sage: len(set(Aut)) == len(Aut) True @@ -378,7 +381,7 @@ class WeierstrassIsomorphism(EllipticCurveHom, baseWI): - ``E`` -- an ``EllipticCurve``, or ``None`` (see below). - ``urst`` -- a 4-tuple `(u,r,s,t)`, a :class:`baseWI` object, - or ``None`` (see below). + or ``None`` (see below). - ``F`` -- an ``EllipticCurve``, or ``None`` (see below). @@ -420,16 +423,16 @@ class WeierstrassIsomorphism(EllipticCurveHom, baseWI): sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * sage: WeierstrassIsomorphism(EllipticCurve([0,1,2,3,4]), (-1,2,3,4)) Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field - To: Elliptic Curve defined by y^2 - 6*x*y - 10*y = x^3 - 2*x^2 - 11*x - 2 over Rational Field - Via: (u,r,s,t) = (-1, 2, 3, 4) + From: Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field + To: Elliptic Curve defined by y^2 - 6*x*y - 10*y = x^3 - 2*x^2 - 11*x - 2 over Rational Field + Via: (u,r,s,t) = (-1, 2, 3, 4) sage: E = EllipticCurve([0,1,2,3,4]) sage: F = EllipticCurve(E.cremona_label()) sage: WeierstrassIsomorphism(E, None, F) Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field - To: Elliptic Curve defined by y^2 = x^3 + x^2 + 3*x + 5 over Rational Field - Via: (u,r,s,t) = (1, 0, 0, -1) + From: Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field + To: Elliptic Curve defined by y^2 = x^3 + x^2 + 3*x + 5 over Rational Field + Via: (u,r,s,t) = (1, 0, 0, -1) sage: w = WeierstrassIsomorphism(None, (1,0,0,-1), F) sage: w._domain == E True @@ -442,10 +445,10 @@ def __init__(self, E=None, urst=None, F=None): Check for :trac:`33215`:: - sage: E = EllipticCurve(GF(71^2),[5,5]) sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: iso = WeierstrassIsomorphism(E, (1,2,3,4)) - sage: ~iso # indirect doctest + sage: E = EllipticCurve(GF(71^2), [5,5]) # needs sage.rings.finite_rings + sage: iso = WeierstrassIsomorphism(E, (1,2,3,4)) # needs sage.rings.finite_rings + sage: ~iso # indirect doctest # needs sage.rings.finite_rings Elliptic-curve morphism: From: Elliptic Curve defined by y^2 + 6*x*y + 8*y = x^3 + 68*x^2 + 64*x + 7 over Finite Field in z2 of size 71^2 To: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field in z2 of size 71^2 @@ -453,8 +456,7 @@ def __init__(self, E=None, urst=None, F=None): Test for :trac:`33312`:: - sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: type(iso.degree()) + sage: type(iso.degree()) # needs sage.rings.finite_rings <class 'sage.rings.integer.Integer'> """ from .ell_generic import is_EllipticCurve @@ -587,14 +589,17 @@ def _eval(self, P): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: E = EllipticCurve([i,0]); E - Elliptic Curve defined by y^2 = x^3 + I*x over Number Field in I with defining polynomial x^2 + 1 with I = 1*I + sage: E = EllipticCurve([i, 0]); E + Elliptic Curve defined by y^2 = x^3 + I*x + over Number Field in I with defining polynomial x^2 + 1 with I = 1*I sage: iso = WeierstrassIsomorphism(E, (i,1,2,3)) sage: P = E.change_ring(QQbar).lift_x(QQbar.random_element()) sage: Q = iso._eval(P) sage: Q.curve() - Elliptic Curve defined by y^2 + (-4*I)*x*y + 6*I*y = x^3 + x^2 + (I-9)*x + (-I+8) over Algebraic Field + Elliptic Curve defined by y^2 + (-4*I)*x*y + 6*I*y = x^3 + x^2 + (I-9)*x + (-I+8) + over Algebraic Field sage: y = next(filter(bool, iter(QQbar.random_element, None))) # sample until nonzero sage: iso._eval((0, y, 0)) == 0 True @@ -633,6 +638,7 @@ def __call__(self, P): Check that copying the order over works:: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(431^2), [1,0]) sage: i = next(a for a in E.automorphisms() if a^2 == -a^24) sage: P,_ = E.gens() @@ -731,9 +737,9 @@ def __repr__(self): sage: E2 = E1.change_weierstrass_model([2,3,4,5]) sage: E1.isomorphism_to(E2) Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field - To: Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 7/4*x^2 - 3/2*x - 9/32 over Rational Field - Via: (u,r,s,t) = (2, 3, 4, 5) + From: Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field + To: Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 7/4*x^2 - 3/2*x - 9/32 over Rational Field + Via: (u,r,s,t) = (2, 3, 4, 5) """ return EllipticCurveHom.__repr__(self) + "\n Via: (u,r,s,t) = " + baseWI.__repr__(self) @@ -749,8 +755,10 @@ def rational_maps(self): sage: E2 = EllipticCurve_from_j(E1.j_invariant()) sage: iso = E1.isomorphism_to(E2); iso Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 over Rational Field - To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 over Rational Field + From: Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 + over Rational Field + To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 + over Rational Field Via: (u,r,s,t) = (1, -17, -5, 77) sage: iso.rational_maps() (x + 17, 5*x + y + 8) @@ -762,6 +770,7 @@ def rational_maps(self): :: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF(65537), [1,1,1,1,1]) sage: w = E.isomorphism_to(E.short_weierstrass_model()) sage: f,g = w.rational_maps() @@ -790,8 +799,10 @@ def x_rational_map(self): sage: E2 = EllipticCurve_from_j(E1.j_invariant()) sage: iso = E1.isomorphism_to(E2); iso Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 over Rational Field - To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 over Rational Field + From: Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 + over Rational Field + To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 + over Rational Field Via: (u,r,s,t) = (1, -17, -5, 77) sage: iso.x_rational_map() x + 17 @@ -823,7 +834,11 @@ def kernel_polynomial(self): sage: iso.kernel_polynomial() 1 sage: psi = E1.isogeny(iso.kernel_polynomial(), codomain=E2); psi - Isogeny of degree 1 from Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 over Rational Field + Isogeny of degree 1 + from Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 + over Rational Field + to Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 684*x + 6681 + over Rational Field sage: psi in {iso, -iso} True @@ -843,8 +858,8 @@ def is_separable(self): EXAMPLES:: - sage: E = EllipticCurve(GF(31337), [0,1]) - sage: {f.is_separable() for f in E.automorphisms()} + sage: E = EllipticCurve(GF(31337), [0,1]) # needs sage.rings.finite_rings + sage: {f.is_separable() for f in E.automorphisms()} # needs sage.rings.finite_rings {True} """ return True @@ -858,9 +873,9 @@ def dual(self): EXAMPLES:: sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: E = EllipticCurve(QuadraticField(-3), [0,1]) - sage: w = WeierstrassIsomorphism(E, (CyclotomicField(3).gen(),0,0,0)) - sage: (w.dual() * w).rational_maps() + sage: E = EllipticCurve(QuadraticField(-3), [0,1]) # needs sage.rings.number_field + sage: w = WeierstrassIsomorphism(E, (CyclotomicField(3).gen(),0,0,0)) # needs sage.rings.number_field + sage: (w.dual() * w).rational_maps() # needs sage.rings.number_field (x, y) :: @@ -886,13 +901,15 @@ def __neg__(self): sage: -w Elliptic-curve morphism: From: Elliptic Curve defined by y^2 + 11*x*y + 33*y = x^3 + 22*x^2 + 44*x + 55 over Rational Field - To: Elliptic Curve defined by y^2 + 17/6*x*y + 49/13068*y = x^3 - 769/396*x^2 - 3397/862488*x + 44863/7513995456 over Rational Field + To: Elliptic Curve defined by y^2 + 17/6*x*y + 49/13068*y = x^3 - 769/396*x^2 - 3397/862488*x + 44863/7513995456 + over Rational Field Via: (u,r,s,t) = (-66, 77, -99, -979) sage: -(-w) == w True :: + sage: # needs sage.rings.number_field sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: K.<a> = QuadraticField(-3) sage: E = EllipticCurve(K, [0,1]) @@ -907,9 +924,9 @@ def __neg__(self): :: sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism, identity_morphism - sage: E = EllipticCurve(QuadraticField(-1), [1,0]) - sage: t = WeierstrassIsomorphism(E, (i,0,0,0)) - sage: -t^2 == identity_morphism(E) + sage: E = EllipticCurve(QuadraticField(-1), [1,0]) # needs sage.rings.number_field + sage: t = WeierstrassIsomorphism(E, (i,0,0,0)) # needs sage.rings.number_field + sage: -t^2 == identity_morphism(E) # needs sage.rings.number_field True """ a1,_,a3,_,_ = self._domain.a_invariants() @@ -930,8 +947,8 @@ def scaling_factor(self): EXAMPLES:: - sage: E = EllipticCurve(QQbar, [0,1]) - sage: all(f.scaling_factor() == f.formal()[1] for f in E.automorphisms()) + sage: E = EllipticCurve(QQbar, [0,1]) # needs sage.rings.number_field + sage: all(f.scaling_factor() == f.formal()[1] for f in E.automorphisms()) # needs sage.rings.number_field True ALGORITHM: The scaling factor equals the `u` component of diff --git a/src/sage/schemes/generic/__init__.py b/src/sage/schemes/generic/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index 9e1fe6b4b56..5d071f2bd49 100644 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -4,14 +4,14 @@ An algebraic scheme is defined by a set of polynomials in some suitable affine or projective coordinates. Possible ambient spaces are - * Affine spaces (:class:`AffineSpace - <sage.schemes.affine.affine_space.AffineSpace_generic>`), +* Affine spaces (:class:`AffineSpace + <sage.schemes.affine.affine_space.AffineSpace_generic>`), - * Projective spaces (:class:`ProjectiveSpace - <sage.schemes.projective.projective_space.ProjectiveSpace_ring>`), or +* Projective spaces (:class:`ProjectiveSpace + <sage.schemes.projective.projective_space.ProjectiveSpace_ring>`), or - * Toric varieties (:class:`ToricVariety - <sage.schemes.toric.variety.ToricVariety_field>`). +* Toric varieties (:class:`ToricVariety + <sage.schemes.toric.variety.ToricVariety_field>`). Note that while projective spaces are of course toric varieties themselves, they are implemented differently in Sage due to efficiency considerations. @@ -44,11 +44,10 @@ Now we can write polynomial equations in the variables `x` and `y`. For example, one equation cuts out a curve (a one-dimensional subscheme):: - sage: V = A2.subscheme([x^2+y^2-1]); V - Closed subscheme of Affine Space of dimension 2 - over Rational Field defined by: + sage: V = A2.subscheme([x^2 + y^2 - 1]); V + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: x^2 + y^2 - 1 - sage: V.dimension() + sage: V.dimension() # needs sage.libs.singular 1 Here is a more complicated example in a projective space:: @@ -56,16 +55,14 @@ sage: P3 = ProjectiveSpace(3, QQ, 'x') sage: P3.inject_variables() Defining x0, x1, x2, x3 - sage: Q = matrix([[x0, x1, x2], [x1, x2, x3]]).minors(2); Q + sage: Q = matrix([[x0, x1, x2], [x1, x2, x3]]).minors(2); Q # needs sage.modules [-x1^2 + x0*x2, -x1*x2 + x0*x3, -x2^2 + x1*x3] - sage: twisted_cubic = P3.subscheme(Q) - sage: twisted_cubic - Closed subscheme of Projective Space of dimension 3 - over Rational Field defined by: + sage: twisted_cubic = P3.subscheme(Q); twisted_cubic # needs sage.libs.singular sage.modules + Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: -x1^2 + x0*x2, -x1*x2 + x0*x3, -x2^2 + x1*x3 - sage: twisted_cubic.dimension() + sage: twisted_cubic.dimension() # needs sage.libs.singular sage.modules 1 Note that there are 3 equations in the 3-dimensional ambient space, @@ -75,27 +72,18 @@ Let us look at one affine patch, for example the one where `x_0=1` :: - sage: patch = twisted_cubic.affine_patch(0) - sage: patch - Closed subscheme of Affine Space of dimension 3 - over Rational Field defined by: + sage: patch = twisted_cubic.affine_patch(0); patch # needs sage.libs.singular sage.modules + Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: -x1^2 + x2, -x1*x2 + x3, -x2^2 + x1*x3 - sage: patch.embedding_morphism() + sage: patch.embedding_morphism() # needs sage.libs.singular sage.modules Scheme morphism: - From: Closed subscheme of Affine Space of dimension 3 - over Rational Field defined by: - -x1^2 + x2, - -x1*x2 + x3, - -x2^2 + x1*x3 - To: Closed subscheme of Projective Space of dimension 3 - over Rational Field defined by: - x1^2 - x0*x2, - x1*x2 - x0*x3, - x2^2 - x1*x3 - Defn: Defined on coordinates by sending (x1, x2, x3) to - (1 : x1 : x2 : x3) + From: Closed subscheme of Affine Space of dimension 3 over Rational Field + defined by: -x1^2 + x2, -x1*x2 + x3, -x2^2 + x1*x3 + To: Closed subscheme of Projective Space of dimension 3 over Rational Field + defined by: x1^2 - x0*x2, x1*x2 - x0*x3, x2^2 - x1*x3 + Defn: Defined on coordinates by sending (x1, x2, x3) to (1 : x1 : x2 : x3) AUTHORS: @@ -132,7 +120,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.qqbar import QQbar from sage.rings.rational_field import is_RationalField -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.number_field.order import is_NumberFieldOrder from sage.misc.latex import latex @@ -169,7 +157,7 @@ def is_AlgebraicScheme(x): sage: A2 = AffineSpace(2, QQ, 'x, y') sage: A2.coordinate_ring().inject_variables() Defining x, y - sage: V = A2.subscheme([x^2+y^2]); V + sage: V = A2.subscheme([x^2 + y^2]); V Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: x^2 + y^2 sage: from sage.schemes.generic.algebraic_scheme import is_AlgebraicScheme @@ -193,7 +181,7 @@ def is_AlgebraicScheme(x): sage: A,x = AffineSpace(10, QQ).objgens() sage: X = A.subscheme([sum(x)]); X Closed subscheme of Affine Space of dimension 10 over Rational Field defined by: - x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 sage: is_AlgebraicScheme(X) True @@ -274,14 +262,14 @@ def is_projective(self): EXAMPLES:: - sage: PP.<x,y,z,w> = ProjectiveSpace(3,QQ) + sage: PP.<x,y,z,w> = ProjectiveSpace(3, QQ) sage: f = x^3 + y^3 + z^3 + w^3 sage: R = f.parent() sage: I = [f] + [f.derivative(zz) for zz in PP.gens()] sage: V = PP.subscheme(I) sage: V.is_projective() True - sage: AA.<x,y,z,w> = AffineSpace(4,QQ) + sage: AA.<x,y,z,w> = AffineSpace(4, QQ) sage: V = AA.subscheme(I) sage: V.is_projective() False @@ -290,9 +278,9 @@ def is_projective(self): projective spaces. This is why this method returns ``False`` for toric varieties:: - sage: PP.<x,y,z,w> = toric_varieties.P(3) + sage: PP.<x,y,z,w> = toric_varieties.P(3) # needs sage.geometry.polyhedron sage: V = PP.subscheme(x^3 + y^3 + z^3 + w^3) - sage: V.is_projective() + sage: V.is_projective() # needs sage.geometry.polyhedron False """ return self.ambient_space().is_projective() @@ -310,9 +298,10 @@ def coordinate_ring(self): EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) - sage: S = P.subscheme([x-y, x-z]) + sage: S = P.subscheme([x - y, x - z]) sage: S.coordinate_ring() - Quotient of Multivariate Polynomial Ring in x, y, z over Integer Ring by the ideal (x - y, x - z) + Quotient of Multivariate Polynomial Ring in x, y, z over Integer Ring + by the ideal (x - y, x - z) """ try: return self._coordinate_ring @@ -335,7 +324,7 @@ def ambient_space(self): Affine Space of dimension 2 over Finite Field of size 5 sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) - sage: S = P.subscheme([x-y, x-z]) + sage: S = P.subscheme([x - y, x - z]) sage: S.ambient_space() is P True """ @@ -389,34 +378,30 @@ def embedding_morphism(self): EXAMPLES:: - sage: A2.<x,y> = AffineSpace(QQ,2) - sage: C = A2.subscheme(x^2+y^2-1) - sage: C.embedding_morphism() + sage: A2.<x,y> = AffineSpace(QQ, 2) + sage: C = A2.subscheme(x^2 + y^2 - 1) + sage: C.embedding_morphism() # needs sage.libs.singular Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 + y^2 - 1 + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x^2 + y^2 - 1 To: Affine Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (x, y) - sage: P1xP1.<x,y,u,v> = toric_varieties.P1xP1() - sage: P1 = P1xP1.subscheme(x-y) - sage: P1.embedding_morphism() + Defn: Defined on coordinates by sending (x, y) to (x, y) + sage: P1xP1.<x,y,u,v> = toric_varieties.P1xP1() # needs sage.geometry.polyhedron + sage: P1 = P1xP1.subscheme(x - y) # needs sage.geometry.polyhedron sage.libs.singular + sage: P1.embedding_morphism() # needs sage.geometry.polyhedron sage.libs.singular Scheme morphism: - From: Closed subscheme of 2-d CPR-Fano toric variety covered - by 4 affine patches defined by: - x - y - To: 2-d CPR-Fano toric variety covered by 4 affine patches - Defn: Defined on coordinates by sending [x : y : u : v] to - [y : y : u : v] + From: Closed subscheme of 2-d CPR-Fano toric variety covered + by 4 affine patches defined by: x - y + To: 2-d CPR-Fano toric variety covered by 4 affine patches + Defn: Defined on coordinates by sending [x : y : u : v] to [y : y : u : v] So far, the embedding was just in the own ambient space. Now a bit more interesting examples:: - sage: P2.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) sage: X = P2.subscheme((x^2-y^2)*z) sage: p = (1,1,0) - sage: nbhd = X.neighborhood(p) - sage: nbhd + sage: nbhd = X.neighborhood(p); nbhd Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: -y^2*z - 2*y*z @@ -434,37 +419,31 @@ def embedding_morphism(self): sage: nbhd.embedding_morphism() Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - -y^2*z - 2*y*z - To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x^2*z - y^2*z - Defn: Defined on coordinates by sending (y, z) to - (1 : y + 1 : z) + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: -y^2*z - 2*y*z + To: Closed subscheme of Projective Space of dimension 2 over Rational Field + defined by: x^2*z - y^2*z + Defn: Defined on coordinates by sending (y, z) to (1 : y + 1 : z) A couple more examples:: - sage: patch1 = P1xP1.affine_patch(1) - sage: patch1 + sage: # needs sage.geometry.polyhedron + sage: patch1 = P1xP1.affine_patch(1); patch1 2-d affine toric variety - sage: patch1.embedding_morphism() - Scheme morphism: + sage: patch1.embedding_morphism() # needs sage.libs.singular + Scheme morphism: From: 2-d affine toric variety To: 2-d CPR-Fano toric variety covered by 4 affine patches - Defn: Defined on coordinates by sending [y : u] to - [1 : y : u : 1] - sage: subpatch = P1.affine_patch(1) - sage: subpatch + Defn: Defined on coordinates by sending [y : u] to [1 : y : u : 1] + sage: subpatch = P1.affine_patch(1); subpatch # needs sage.libs.singular Closed subscheme of 2-d affine toric variety defined by: -y + 1 - sage: subpatch.embedding_morphism() + sage: subpatch.embedding_morphism() # needs sage.libs.singular Scheme morphism: - From: Closed subscheme of 2-d affine toric variety defined by: - -y + 1 + From: Closed subscheme of 2-d affine toric variety defined by: -y + 1 To: Closed subscheme of 2-d CPR-Fano toric variety covered - by 4 affine patches defined by: - x - y - Defn: Defined on coordinates by sending [y : u] to - [1 : y : u : 1] + by 4 affine patches defined by: x - y + Defn: Defined on coordinates by sending [y : u] to [1 : y : u : 1] """ if '_embedding_morphism' in self.__dict__: hom = self._embedding_morphism @@ -492,7 +471,7 @@ def embedding_center(self): EXAMPLES:: - sage: P3.<w,x,y,z> = ProjectiveSpace(QQ,3) + sage: P3.<w,x,y,z> = ProjectiveSpace(QQ, 3) sage: X = P3.subscheme( (w^2-x^2)*(y^2-z^2) ) sage: p = [1,-1,3,4] sage: nbhd = X.neighborhood(p); nbhd @@ -505,11 +484,11 @@ def embedding_center(self): (1/4 : -1/4 : 3/4 : 1) sage: nbhd.embedding_morphism() Scheme morphism: - From: Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: - w^2*y^2 - x^2*y^2 + 6*w^2*y - 6*x^2*y + 2*w*y^2 + - 2*x*y^2 - 7*w^2 + 7*x^2 + 12*w*y + 12*x*y - 14*w - 14*x - To: Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: - w^2*y^2 - x^2*y^2 - w^2*z^2 + x^2*z^2 + From: Closed subscheme of Affine Space of dimension 3 over Rational Field + defined by: w^2*y^2 - x^2*y^2 + 6*w^2*y - 6*x^2*y + 2*w*y^2 + 2*x*y^2 + - 7*w^2 + 7*x^2 + 12*w*y + 12*x*y - 14*w - 14*x + To: Closed subscheme of Projective Space of dimension 3 over Rational Field + defined by: w^2*y^2 - x^2*y^2 - w^2*z^2 + x^2*z^2 Defn: Defined on coordinates by sending (w, x, y) to (w + 1 : x - 1 : y + 3 : 4) """ @@ -529,7 +508,7 @@ def ngens(self): sage: S.ngens() 2 sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) - sage: S = P.subscheme([x-y, x-z]) + sage: S = P.subscheme([x - y, x - z]) sage: P.ngens() 3 """ @@ -548,7 +527,7 @@ def _repr_(self): sage: S._repr_() 'Subscheme of Projective Space of dimension 3 over Integer Ring' """ - return "Subscheme of %s"%self.__A + return "Subscheme of %s" % self.__A def _homset(self, *args, **kwds): """ @@ -564,18 +543,19 @@ def _homset(self, *args, **kwds): EXAMPLES:: + sage: # needs sage.geometry.polyhedron sage: P1.<x,y> = toric_varieties.P1() sage: type(P1.Hom(P1)) <class 'sage.schemes.toric.homset.SchemeHomset_toric_variety_with_category'> - sage: X = P1.subscheme(x-y) + sage: X = P1.subscheme(x - y) sage: type(X.Hom(X)) <class 'sage.schemes.toric.homset.SchemeHomset_toric_variety_with_category'> :: - sage: P1xP1 = toric_varieties.P1xP1() - sage: P1 = toric_varieties.P1() - sage: P1xP1._homset(P1xP1,P1) + sage: P1xP1 = toric_varieties.P1xP1() # needs sage.geometry.polyhedron + sage: P1 = toric_varieties.P1() # needs sage.geometry.polyhedron + sage: P1xP1._homset(P1xP1, P1) # needs sage.geometry.polyhedron Set of morphisms From: 2-d CPR-Fano toric variety covered by 4 affine patches To: 1-d CPR-Fano toric variety covered by 2 affine patches @@ -628,13 +608,14 @@ class AlgebraicScheme_quasi(AlgebraicScheme): sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) sage: S = P.subscheme([]) - sage: T = P.subscheme([x-y]) + sage: T = P.subscheme([x - y]) sage: T.complement(S) - Quasi-projective subscheme X - Y of Projective Space of dimension 2 over - Integer Ring, where X is defined by: - (no polynomials) - and Y is defined by: - x - y + Quasi-projective subscheme X - Y + of Projective Space of dimension 2 over Integer Ring, + where X is defined by: + (no polynomials) + and Y is defined by: + x - y """ def __init__(self, X, Y): @@ -649,13 +630,14 @@ def __init__(self, X, Y): sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) sage: S = P.subscheme([]) - sage: T = P.subscheme([x-y]) + sage: T = P.subscheme([x - y]) sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi sage: AlgebraicScheme_quasi(S, T) - Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, where X is defined by: - (no polynomials) - and Y is defined by: - x - y + Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, + where X is defined by: + (no polynomials) + and Y is defined by: + x - y """ self.__X = X self.__Y = Y @@ -680,13 +662,13 @@ def _latex_(self): sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) sage: S = P.subscheme([]) - sage: T = P.subscheme([x-y]) + sage: T = P.subscheme([x - y]) sage: U = AlgebraicScheme_quasi(S, T); U - Quasi-projective subscheme X - Y of Projective Space of dimension 2 - over Integer Ring, where X is defined by: - (no polynomials) - and Y is defined by: - x - y + Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, + where X is defined by: + (no polynomials) + and Y is defined by: + x - y sage: U._latex_() '\\text{Quasi-projective subscheme } (X\\setminus Y)\\subset {\\mathbf P}_{\\Bold{Z}}^2,\\text{ where } @@ -717,12 +699,13 @@ def _repr_(self): sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) sage: S = P.subscheme([]) - sage: T = P.subscheme([x-y]) + sage: T = P.subscheme([x - y]) sage: U = AlgebraicScheme_quasi(S, T); U - Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, where X is defined by: - (no polynomials) - and Y is defined by: - x - y + Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, + where X is defined by: + (no polynomials) + and Y is defined by: + x - y sage: U._repr_() 'Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, where X is defined by:\n (no polynomials)\nand Y is defined by:\n x - y' """ @@ -743,7 +726,7 @@ def X(self): sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) sage: S = P.subscheme([]) - sage: T = P.subscheme([x-y]) + sage: T = P.subscheme([x - y]) sage: U = T.complement(S) sage: U.X() is S True @@ -758,7 +741,7 @@ def Y(self): sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) sage: S = P.subscheme([]) - sage: T = P.subscheme([x-y]) + sage: T = P.subscheme([x - y]) sage: U = T.complement(S) sage: U.Y() is T True @@ -774,7 +757,7 @@ def _check_satisfies_equations(self, v): sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) sage: S = P.subscheme([]) - sage: T = P.subscheme([x-y]) + sage: T = P.subscheme([x - y]) sage: U = T.complement(S) sage: U._check_satisfies_equations([1, 2, 0]) True @@ -782,11 +765,11 @@ def _check_satisfies_equations(self, v): Traceback (most recent call last): ... TypeError: Coordinates [1, 1, 0] do not define a point on - Quasi-projective subscheme X - Y of Projective Space of dimension 2 - over Integer Ring, where X is defined by: - (no polynomials) - and Y is defined by: - x - y + Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, + where X is defined by: + (no polynomials) + and Y is defined by: + x - y sage: U._check_satisfies_equations([1, 4]) Traceback (most recent call last): @@ -794,8 +777,8 @@ def _check_satisfies_equations(self, v): TypeError: number of arguments does not match number of variables in parent sage: A.<x, y> = AffineSpace(2, GF(7)) - sage: S = A.subscheme([x^2-y]) - sage: T = A.subscheme([x-y]) + sage: S = A.subscheme([x^2 - y]) + sage: T = A.subscheme([x - y]) sage: U = T.complement(S) sage: U._check_satisfies_equations([2, 4]) True @@ -836,11 +819,11 @@ def _check_satisfies_equations(self, v): coords = list(v) for f in self.__X.defining_polynomials(): if f(coords) != 0: - raise TypeError("Coordinates %s do not define a point on %s"%(v,self)) + raise TypeError("Coordinates %s do not define a point on %s" % (v,self)) for f in self.__Y.defining_polynomials(): if f(coords) != 0: return True - raise TypeError("Coordinates %s do not define a point on %s"%(v,self)) + raise TypeError("Coordinates %s do not define a point on %s" % (v,self)) def rational_points(self, **kwds): """ @@ -861,22 +844,24 @@ def rational_points(self, **kwds): EXAMPLES:: sage: A.<x, y> = AffineSpace(2, GF(7)) - sage: S = A.subscheme([x^2-y]) - sage: T = A.subscheme([x-y]) + sage: S = A.subscheme([x^2 - y]) + sage: T = A.subscheme([x - y]) sage: U = T.complement(S) sage: U.rational_points() [(2, 4), (3, 2), (4, 2), (5, 4), (6, 1)] - sage: U.rational_points(F=GF(7^2, 'b')) - [(2, 4), (3, 2), (4, 2), (5, 4), (6, 1), (b, b + 4), (b + 1, 3*b + 5), (b + 2, 5*b + 1), - (b + 3, 6), (b + 4, 2*b + 6), (b + 5, 4*b + 1), (b + 6, 6*b + 5), (2*b, 4*b + 2), - (2*b + 1, b + 3), (2*b + 2, 5*b + 6), (2*b + 3, 2*b + 4), (2*b + 4, 6*b + 4), - (2*b + 5, 3*b + 6), (2*b + 6, 3), (3*b, 2*b + 1), (3*b + 1, b + 2), (3*b + 2, 5), - (3*b + 3, 6*b + 3), (3*b + 4, 5*b + 3), (3*b + 5, 4*b + 5), (3*b + 6, 3*b + 2), - (4*b, 2*b + 1), (4*b + 1, 3*b + 2), (4*b + 2, 4*b + 5), (4*b + 3, 5*b + 3), - (4*b + 4, 6*b + 3), (4*b + 5, 5), (4*b + 6, b + 2), (5*b, 4*b + 2), (5*b + 1, 3), - (5*b + 2, 3*b + 6), (5*b + 3, 6*b + 4), (5*b + 4, 2*b + 4), (5*b + 5, 5*b + 6), - (5*b + 6, b + 3), (6*b, b + 4), (6*b + 1, 6*b + 5), (6*b + 2, 4*b + 1), (6*b + 3, 2*b + 6), - (6*b + 4, 6), (6*b + 5, 5*b + 1), (6*b + 6, 3*b + 5)] + sage: U.rational_points(F=GF(7^2, 'b')) # needs sage.rings.finite_rings + [(2, 4), (3, 2), (4, 2), (5, 4), (6, 1), (b, b + 4), (b + 1, 3*b + 5), + (b + 2, 5*b + 1), (b + 3, 6), (b + 4, 2*b + 6), (b + 5, 4*b + 1), + (b + 6, 6*b + 5), (2*b, 4*b + 2), (2*b + 1, b + 3), (2*b + 2, 5*b + 6), + (2*b + 3, 2*b + 4), (2*b + 4, 6*b + 4), (2*b + 5, 3*b + 6), (2*b + 6, 3), + (3*b, 2*b + 1), (3*b + 1, b + 2), (3*b + 2, 5), (3*b + 3, 6*b + 3), + (3*b + 4, 5*b + 3), (3*b + 5, 4*b + 5), (3*b + 6, 3*b + 2), + (4*b, 2*b + 1), (4*b + 1, 3*b + 2), (4*b + 2, 4*b + 5), + (4*b + 3, 5*b + 3), (4*b + 4, 6*b + 3), (4*b + 5, 5), (4*b + 6, b + 2), + (5*b, 4*b + 2), (5*b + 1, 3), (5*b + 2, 3*b + 6), (5*b + 3, 6*b + 4), + (5*b + 4, 2*b + 4), (5*b + 5, 5*b + 6), (5*b + 6, b + 3), (6*b, b + 4), + (6*b + 1, 6*b + 5), (6*b + 2, 4*b + 1), (6*b + 3, 2*b + 6), (6*b + 4, 6), + (6*b + 5, 5*b + 1), (6*b + 6, 3*b + 5)] """ F = kwds.get('F', None) bound = kwds.get('bound', 0) @@ -885,9 +870,9 @@ def rational_points(self, **kwds): if bound == 0: if is_RationalField(F): - raise TypeError("A positive bound (= %s) must be specified."%bound) - if not is_FiniteField(F): - raise TypeError("Argument F (= %s) must be a finite field."%F) + raise TypeError("A positive bound (= %s) must be specified." % bound) + if not isinstance(F, FiniteField): + raise TypeError("Argument F (= %s) must be a finite field." % F) pts = [] for P in self.ambient_space().rational_points(F): try: @@ -912,9 +897,9 @@ class AlgebraicScheme_subscheme(AlgebraicScheme): - ``A`` - ambient space (e.g. affine or projective `n`-space) - ``polynomials`` - single polynomial, ideal or iterable of defining - polynomials; in any case polynomials must belong to the coordinate - ring of the ambient space and define valid polynomial functions (e.g. - they should be homogeneous in the case of a projective space) + polynomials; in any case polynomials must belong to the coordinate + ring of the ambient space and define valid polynomial functions (e.g. + they should be homogeneous in the case of a projective space) OUTPUT: @@ -924,10 +909,10 @@ class AlgebraicScheme_subscheme(AlgebraicScheme): sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme sage: P.<x, y, z> = ProjectiveSpace(2, QQ) - sage: P.subscheme([x^2-y*z]) + sage: P.subscheme([x^2 - y*z]) Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^2 - y*z - sage: AlgebraicScheme_subscheme(P, [x^2-y*z]) + sage: AlgebraicScheme_subscheme(P, [x^2 - y*z]) Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^2 - y*z """ @@ -940,10 +925,10 @@ def __init__(self, A, polynomials): sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme sage: P.<x, y, z> = ProjectiveSpace(2, QQ) - sage: P.subscheme([x^2-y*z]) + sage: P.subscheme([x^2 - y*z]) Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^2 - y*z - sage: AlgebraicScheme_subscheme(P, [x^2-y*z]) + sage: AlgebraicScheme_subscheme(P, [x^2 - y*z]) Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^2 - y*z """ @@ -979,7 +964,7 @@ def _check_satisfies_equations(self, v): EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(2, QQ) - sage: S = P.subscheme([x^2-y*z]) + sage: S = P.subscheme([x^2 - y*z]) sage: S._check_satisfies_equations([1, 1, 1]) True sage: S._check_satisfies_equations([1, 0, 1]) @@ -999,11 +984,11 @@ def _check_satisfies_equations(self, v): for f in self.defining_polynomials(): if f(coords) != 0: # it must be "!=0" instead of "if f(v)", e.g., # because of p-adic base rings. - raise TypeError("Coordinates %s do not define a point on %s"%(coords,self)) + raise TypeError("Coordinates %s do not define a point on %s" % (coords,self)) try: return self.ambient_space()._check_satisfies_equations(coords) except TypeError: - raise TypeError("Coordinates %s do not define a point on %s"%(coords,self)) + raise TypeError("Coordinates %s do not define a point on %s" % (coords,self)) def base_extend(self, R): """ @@ -1012,14 +997,16 @@ def base_extend(self, R): EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(2, GF(11)) - sage: S = P.subscheme([x^2-y*z]) - sage: S.base_extend(GF(11^2, 'b')) - Closed subscheme of Projective Space of dimension 2 over Finite Field in b of size 11^2 defined by: - x^2 - y*z + sage: S = P.subscheme([x^2 - y*z]) + sage: S.base_extend(GF(11^2, 'b')) # needs sage.rings.finite_rings + Closed subscheme of Projective Space of dimension 2 + over Finite Field in b of size 11^2 + defined by: x^2 - y*z sage: S.base_extend(ZZ) Traceback (most recent call last): ... - ValueError: no natural map from the base ring (=Finite Field of size 11) to R (=Integer Ring)! + ValueError: no natural map from the base ring (=Finite Field of size 11) + to R (=Integer Ring)! """ A = self.ambient_space().base_extend(R) return A.subscheme(self.__polys) @@ -1032,7 +1019,7 @@ def __richcmp__(self, other, op): sage: X = A.subscheme([x*y, z]) sage: X == A.subscheme([z, x*y]) True - sage: X == A.subscheme([x*y, z^2]) + sage: X == A.subscheme([x*y, z^2]) # needs sage.libs.singular False sage: B.<u, v, t> = AffineSpace(3, QQ) sage: X == B.subscheme([u*v, t]) @@ -1052,14 +1039,12 @@ def _latex_(self): EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(2, GF(11)) - sage: S = P.subscheme([x^2-y*z]) - sage: S + sage: S = P.subscheme([x^2 - y*z]); S Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by: x^2 - y*z sage: S._latex_() '\\text{Closed subscheme of } {\\mathbf P}_{\\Bold{F}_{11}}^2 \\text{ defined by } x^{2} - y z' - sage: S = P.subscheme([x^2-y*z, x^5]) - sage: S + sage: S = P.subscheme([x^2 - y*z, x^5]); S Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by: x^2 - y*z, x^5 @@ -1079,14 +1064,12 @@ def _repr_(self): EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(2, GF(11)) - sage: S = P.subscheme([x^2-y*z]) - sage: S + sage: S = P.subscheme([x^2 - y*z]); S Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by: x^2 - y*z sage: S._repr_() 'Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:\n x^2 - y*z' - sage: S = P.subscheme([x^2-y*z, x^5]) - sage: S + sage: S = P.subscheme([x^2 - y*z, x^5]); S Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by: x^2 - y*z, x^5 @@ -1112,7 +1095,7 @@ def defining_polynomials(self): EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) - sage: S = P.subscheme([x^2-y*z, x^3+z^3]) + sage: S = P.subscheme([x^2 - y*z, x^3 + z^3]) sage: S.defining_polynomials() (x^2 - y*z, x^3 + z^3) """ @@ -1170,9 +1153,10 @@ def defining_ideal(self): EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) - sage: S = P.subscheme([x^2-y*z, x^3+z^3]) + sage: S = P.subscheme([x^2 - y*z, x^3 + z^3]) sage: S.defining_ideal() - Ideal (x^2 - y*z, x^3 + z^3) of Multivariate Polynomial Ring in x, y, z over Integer Ring + Ideal (x^2 - y*z, x^3 + z^3) of Multivariate Polynomial Ring in x, y, z + over Integer Ring """ try: return self.__I @@ -1192,11 +1176,11 @@ def codimension(self): EXAMPLES:: - sage: PP.<x,y,z,w,v> = ProjectiveSpace(4,QQ) + sage: PP.<x,y,z,w,v> = ProjectiveSpace(4, QQ) sage: V = PP.subscheme(x*y) - sage: V.codimension() + sage: V.codimension() # needs sage.libs.singular 1 - sage: V.dimension() + sage: V.dimension() # needs sage.libs.singular 3 """ return self.ambient_space().dimension() - self.dimension() @@ -1218,29 +1202,29 @@ def irreducible_components(self): We define what is clearly a union of four hypersurfaces in `\P^4_{\QQ}` then find the irreducible components:: - sage: PP.<x,y,z,w,v> = ProjectiveSpace(4,QQ) - sage: V = PP.subscheme( (x^2 - y^2 - z^2)*(w^5 - 2*v^2*z^3)* w * (v^3 - x^2*z) ) - sage: V.irreducible_components() + sage: PP.<x,y,z,w,v> = ProjectiveSpace(4, QQ) + sage: V = PP.subscheme((x^2 - y^2 - z^2) * (w^5 - 2*v^2*z^3) * w * (v^3 - x^2*z)) + sage: V.irreducible_components() # needs sage.libs.singular [ Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: - w, + w, Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: - x^2 - y^2 - z^2, + x^2 - y^2 - z^2, Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: - x^2*z - v^3, + x^2*z - v^3, Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: - w^5 - 2*z^3*v^2 + w^5 - 2*z^3*v^2 ] We verify that the irrelevant ideal is not accidentally returned (see :trac:`6920`):: - sage: PP.<x,y,z,w> = ProjectiveSpace(3,QQ) + sage: PP.<x,y,z,w> = ProjectiveSpace(3, QQ) sage: f = x^3 + y^3 + z^3 + w^3 sage: R = f.parent() sage: I = [f] + [f.derivative(zz) for zz in PP.gens()] sage: V = PP.subscheme(I) - sage: V.irreducible_components() + sage: V.irreducible_components() # needs sage.libs.singular [ <BLANKLINE> ] @@ -1249,9 +1233,9 @@ def irreducible_components(self): nontrivial irreducible component in affine space (instead of the empty scheme as above):: - sage: AA.<x,y,z,w> = AffineSpace(4,QQ) + sage: AA.<x,y,z,w> = AffineSpace(4, QQ) sage: V = AA.subscheme(I) - sage: V.irreducible_components() + sage: V.irreducible_components() # needs sage.libs.singular [ Closed subscheme of Affine Space of dimension 4 over Rational Field defined by: w, @@ -1291,6 +1275,7 @@ def is_irreducible(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: K = QuadraticField(-3) sage: P.<x,y,z,w,t,u> = ProjectiveSpace(K, 5) sage: X = P.subscheme([x*y - z^2 - K.0*t^2, t*w*x + y*z^2 - u^3]) @@ -1301,15 +1286,17 @@ def is_irreducible(self): sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: X = P.subscheme([(y + x - z)^2]) - sage: X.is_irreducible() + sage: X.is_irreducible() # needs sage.libs.singular False :: sage: A.<x,y,z,w> = AffineSpace(GF(17), 4) - sage: X = A.subscheme([x*y*z^2 - x*y*z*w - z*w^2 + w^3, x^3*y*z*w - x*y^3*z - x^2*y*z*w \ - - x^2*w^3 + y^2*w^2 + x*w^3]) - sage: X.is_irreducible() + sage: X = A.subscheme([ + ....: x*y*z^2 - x*y*z*w - z*w^2 + w^3, + ....: x^3*y*z*w - x*y^3*z - x^2*y*z*w - x^2*w^3 + y^2*w^2 + x*w^3 + ....: ]) + sage: X.is_irreducible() # needs sage.rings.finite_rings False """ return self.defining_ideal().is_prime() @@ -1326,8 +1313,9 @@ def Jacobian_matrix(self): EXAMPLES:: sage: P3.<w,x,y,z> = ProjectiveSpace(3, QQ) - sage: twisted_cubic = P3.subscheme(matrix([[w, x, y],[x, y, z]]).minors(2)) - sage: twisted_cubic.Jacobian_matrix() + sage: twisted_cubic = P3.subscheme(matrix([[w, x, y], # needs sage.libs.singular + ....: [x, y, z]]).minors(2)) + sage: twisted_cubic.Jacobian_matrix() # needs sage.libs.singular [ y -2*x w 0] [ z -y -x w] [ 0 z -2*y x] @@ -1335,7 +1323,7 @@ def Jacobian_matrix(self): This example addresses issue :trac:`20512`:: sage: X = P3.subscheme([]) - sage: X.Jacobian_matrix().base_ring() == P3.coordinate_ring() + sage: X.Jacobian_matrix().base_ring() == P3.coordinate_ring() # needs sage.libs.singular True """ R = self.ambient_space().coordinate_ring() @@ -1365,19 +1353,21 @@ def Jacobian(self): EXAMPLES:: sage: P3.<w,x,y,z> = ProjectiveSpace(3, QQ) - sage: twisted_cubic = P3.subscheme(matrix([[w, x, y],[x, y, z]]).minors(2)) - sage: twisted_cubic.Jacobian() - Ideal (-x^2 + w*y, -x*y + w*z, -y^2 + x*z, x*z, -2*w*z, w*y, 3*w*y, -2*w*x, - w^2, y*z, -2*x*z, w*z, 3*w*z, -2*w*y, w*x, z^2, -2*y*z, x*z, 3*x*z, -2*w*z, - w*y) of Multivariate Polynomial Ring in w, x, y, z over Rational Field - sage: twisted_cubic.defining_ideal() - Ideal (-x^2 + w*y, -x*y + w*z, -y^2 + x*z) of Multivariate Polynomial Ring - in w, x, y, z over Rational Field + sage: twisted_cubic = P3.subscheme(matrix([[w, x, y], # needs sage.libs.singular + ....: [x, y, z]]).minors(2)) + sage: twisted_cubic.Jacobian() # needs sage.libs.singular + Ideal (-x^2 + w*y, -x*y + w*z, -y^2 + x*z, x*z, -2*w*z, w*y, 3*w*y, + -2*w*x, w^2, y*z, -2*x*z, w*z, 3*w*z, -2*w*y, w*x, z^2, -2*y*z, + x*z, 3*x*z, -2*w*z, w*y) + of Multivariate Polynomial Ring in w, x, y, z over Rational Field + sage: twisted_cubic.defining_ideal() # needs sage.libs.singular + Ideal (-x^2 + w*y, -x*y + w*z, -y^2 + x*z) + of Multivariate Polynomial Ring in w, x, y, z over Rational Field This example addresses issue :trac:`20512`:: sage: X = P3.subscheme([]) - sage: X.Jacobian() == P3.coordinate_ring().unit_ideal() + sage: X.Jacobian() == P3.coordinate_ring().unit_ideal() # needs sage.libs.singular True """ d = self.codimension() @@ -1399,22 +1389,23 @@ def reduce(self): Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: x^5 - 3*x^4*y + 3*x^3*y^2 - x^2*y^3 - 2*x^4 + 6*x^3*y - 6*x^2*y^2 + 2*x*y^3 + x^3 - 3*x^2*y + 3*x*y^2 - y^3 - sage: X.dimension() + sage: X.dimension() # needs sage.libs.singular 1 Then we compute the corresponding reduced scheme:: - sage: Y = X.reduce(); Y + sage: Y = X.reduce(); Y # needs sage.libs.singular Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: x^2 - x*y - x + y Finally, we verify that the reduced scheme `Y` is the union of those two lines:: - sage: L1 = A.subscheme([x-1]); L1 + sage: # needs sage.libs.singular + sage: L1 = A.subscheme([x - 1]); L1 Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: x - 1 - sage: L2 = A.subscheme([x-y]); L2 + sage: L2 = A.subscheme([x - y]); L2 Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: x - y sage: W = L1.union(L2); W # taken in ambient space @@ -1444,38 +1435,38 @@ def union(self, other): :: sage: A.<x,y> = AffineSpace(2, QQ) - sage: I = ideal([x,y])^3 + sage: I = ideal([x, y])^3 sage: P = A.subscheme(I) - sage: L = A.subscheme([y-1]) - sage: S = L.union(P); S + sage: L = A.subscheme([y - 1]) + sage: S = L.union(P); S # needs sage.libs.singular Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y^4 - y^3, - x*y^3 - x*y^2, - x^2*y^2 - x^2*y, - x^3*y - x^3 - sage: S.dimension() + y^4 - y^3, + x*y^3 - x*y^2, + x^2*y^2 - x^2*y, + x^3*y - x^3 + sage: S.dimension() # needs sage.libs.singular 1 - sage: S.reduce() + sage: S.reduce() # needs sage.libs.singular Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y^2 - y, - x*y - x + y^2 - y, + x*y - x We can also use the notation "+" for the union:: - sage: A.subscheme([x]) + A.subscheme([y^2 - (x^3+1)]) + sage: A.subscheme([x]) + A.subscheme([y^2 - (x^3+1)]) # needs sage.libs.singular Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^4 - x*y^2 + x + x^4 - x*y^2 + x Saving and loading:: - sage: loads(S.dumps()) == S + sage: loads(S.dumps()) == S # needs sage.libs.singular True """ if not isinstance(other, AlgebraicScheme_subscheme): - raise TypeError("other (=%s) must be a closed algebraic subscheme of an ambient space"%other) + raise TypeError("other (=%s) must be a closed algebraic subscheme of an ambient space" % other) A = self.ambient_space() if other.ambient_space() != A: - raise ValueError("other (=%s) must be in the same ambient space as self"%other) + raise ValueError("other (=%s) must be in the same ambient space as self" % other) return A.subscheme(self.defining_ideal().intersection(other.defining_ideal())) def __pow__(self, m): @@ -1492,7 +1483,7 @@ def __pow__(self, m): sage: Z = P2.subscheme([y0^2 - y1*y2, y2]) sage: Z**3 Closed subscheme of Product of projective spaces P^2 x P^2 x P^2 over - Integer Ring defined by: + Integer Ring defined by: x0^2 - x1*x2, x2, x3^2 - x4*x5, @@ -1501,10 +1492,10 @@ def __pow__(self, m): x8 sage: A2.<x,y> = AffineSpace(QQ, 2) - sage: V = A2.subscheme([x^2-y, x-1]) + sage: V = A2.subscheme([x^2 - y, x - 1]) sage: V**4 Closed subscheme of Affine Space of dimension 8 over Rational Field - defined by: + defined by: x0^2 - x1, x0 - 1, x2^2 - x3, @@ -1518,14 +1509,14 @@ def __pow__(self, m): sage: X = T.subscheme([x0*x4 - x1*x3]) sage: X^2 Closed subscheme of Product of projective spaces P^2 x P^2 x P^2 x P^2 - over Integer Ring defined by: + over Integer Ring defined by: -x1*x3 + x0*x4, -x7*x9 + x6*x10 - sage: E = EllipticCurve([0,0,0,0,1]) - sage: E^2 - Closed subscheme of Product of projective spaces P^2 x P^2 over Rational - Field defined by: + sage: E = EllipticCurve([0,0,0,0,1]) # needs sage.schemes + sage: E^2 # needs sage.schemes + Closed subscheme of Product of projective spaces P^2 x P^2 + over Rational Field defined by: -x0^3 + x1^2*x2 - x2^3, -x3^3 + x4^2*x5 - x5^3 """ @@ -1555,8 +1546,9 @@ def __mul__(self, right): Defining x0, x1, x2, x3, x4, x5 sage: X = T.subscheme([x0*x4 - x1*x3]) sage: X*S - Closed subscheme of Product of projective spaces P^2 x P^2 x P^1 x P^2 x - P^1 over Integer Ring defined by: + Closed subscheme of + Product of projective spaces P^2 x P^2 x P^1 x P^2 x P^1 over Integer Ring + defined by: -x1*x3 + x0*x4 :: @@ -1565,8 +1557,8 @@ def __mul__(self, right): sage: T.<x0,x1,x2,x3> = ProjectiveSpace(ZZ, 3) sage: X = T.subscheme([x0*x2 - x1*x3]) sage: X*S - Closed subscheme of Product of projective spaces P^3 x P^2 - over Integer Ring defined by: + Closed subscheme of Product of projective spaces P^3 x P^2 over Integer Ring + defined by: x0*x2 - x1*x3 :: @@ -1576,7 +1568,7 @@ def __mul__(self, right): sage: X = A3.subscheme([x0*x2 - x1]) sage: X*A2 Closed subscheme of Affine Space of dimension 5 over Integer Ring - defined by: + defined by: x0*x2 - x1 :: @@ -1585,7 +1577,7 @@ def __mul__(self, right): sage: X = T.subscheme([x0*x4 - x1*x3]) sage: X*X Closed subscheme of Product of projective spaces P^2 x P^2 x P^2 x P^2 - over Integer Ring defined by: + over Integer Ring defined by: -x1*x3 + x0*x4, -x7*x9 + x6*x10 @@ -1596,8 +1588,8 @@ def __mul__(self, right): sage: T.<x0,x1,x2,x3,x4,x5> = ProductProjectiveSpaces([2,2], ZZ) sage: X = T.subscheme([x0*x4 - x1*x3]) sage: X*Y - Closed subscheme of Product of projective spaces P^2 x P^2 x P^1 over - Integer Ring defined by: + Closed subscheme of Product of projective spaces P^2 x P^2 x P^1 + over Integer Ring defined by: -x1*x3 + x0*x4, z0 - z1 @@ -1605,8 +1597,8 @@ def __mul__(self, right): sage: A3.<x0,x1,x2> = AffineSpace(ZZ, 3) sage: X = A3.subscheme([x0*x2 - x1]) - sage: P1.<u,v>=ProjectiveSpace(ZZ,1) - sage: Y = P1.subscheme([u-v]) + sage: P1.<u,v> = ProjectiveSpace(ZZ, 1) + sage: Y = P1.subscheme([u - v]) sage: X*Y Traceback (most recent call last): ... @@ -1614,9 +1606,10 @@ def __mul__(self, right): sage: Y*X Traceback (most recent call last): ... - TypeError: Affine Space of dimension 3 over Integer Ring must be a projective space, product of projective spaces, or subscheme - sage: PP.<a,b,c,d>=ProductProjectiveSpaces(ZZ, [1,1]) - sage: Z = PP.subscheme([a*d-b*c]) + TypeError: Affine Space of dimension 3 over Integer Ring must be a projective space, + product of projective spaces, or subscheme + sage: PP.<a,b,c,d> = ProductProjectiveSpaces(ZZ, [1,1]) + sage: Z = PP.subscheme([a*d - b*c]) sage: X*Z Traceback (most recent call last): ... @@ -1624,7 +1617,8 @@ def __mul__(self, right): sage: Z*X Traceback (most recent call last): ... - TypeError: Affine Space of dimension 3 over Integer Ring must be a projective space, product of projective spaces, or subscheme + TypeError: Affine Space of dimension 3 over Integer Ring must be a projective space, + product of projective spaces, or subscheme """ #This will catch any ambient space mismatches AS = self.ambient_space()*right.ambient_space() @@ -1645,7 +1639,7 @@ def intersection(self, other): EXAMPLES:: sage: A.<x, y> = AffineSpace(2, ZZ) - sage: X = A.subscheme([x^2-y]) + sage: X = A.subscheme([x^2 - y]) sage: Y = A.subscheme([y]) sage: X.intersection(Y) Closed subscheme of Affine Space of dimension 2 over Integer Ring defined by: @@ -1653,10 +1647,10 @@ def intersection(self, other): y """ if not isinstance(other, AlgebraicScheme_subscheme): - raise TypeError("other (=%s) must be a closed algebraic subscheme of an ambient space"%other) + raise TypeError("other (=%s) must be a closed algebraic subscheme of an ambient space" % other) A = self.ambient_space() if other.ambient_space() != A: - raise ValueError("other (=%s) must be in the same ambient space as self"%other) + raise ValueError("other (=%s) must be in the same ambient space as self" % other) return A.subscheme(self.defining_ideal() + other.defining_ideal()) def complement(self, other=None): @@ -1671,35 +1665,39 @@ def complement(self, other=None): EXAMPLES:: sage: A.<x, y, z> = AffineSpace(3, ZZ) - sage: X = A.subscheme([x+y-z]) - sage: Y = A.subscheme([x-y+z]) + sage: X = A.subscheme([x + y - z]) + sage: Y = A.subscheme([x - y + z]) sage: Y.complement(X) - Quasi-affine subscheme X - Y of Affine Space of - dimension 3 over Integer Ring, where X is defined by: - x + y - z - and Y is defined by: - x - y + z + Quasi-affine subscheme X - Y of + Affine Space of dimension 3 over Integer Ring, + where X is defined by: + x + y - z + and Y is defined by: + x - y + z sage: Y.complement() - Quasi-affine subscheme X - Y of Affine Space of - dimension 3 over Integer Ring, where X is defined by: - (no polynomials) - and Y is defined by: - x - y + z + Quasi-affine subscheme X - Y of + Affine Space of dimension 3 over Integer Ring, + where X is defined by: + (no polynomials) + and Y is defined by: + x - y + z sage: P.<x, y, z> = ProjectiveSpace(2, QQ) - sage: X = P.subscheme([x^2+y^2+z^2]) - sage: Y = P.subscheme([x*y+y*z+z*x]) + sage: X = P.subscheme([x^2 + y^2 + z^2]) + sage: Y = P.subscheme([x*y + y*z + z*x]) sage: Y.complement(X) - Quasi-projective subscheme X - Y of Projective Space of - dimension 2 over Rational Field, where X is defined by: - x^2 + y^2 + z^2 - and Y is defined by: - x*y + x*z + y*z + Quasi-projective subscheme X - Y of + Projective Space of dimension 2 over Rational Field, + where X is defined by: + x^2 + y^2 + z^2 + and Y is defined by: + x*y + x*z + y*z sage: Y.complement(P) - Quasi-projective subscheme X - Y of Projective Space of - dimension 2 over Rational Field, where X is defined by: - (no polynomials) - and Y is defined by: - x*y + x*z + y*z + Quasi-projective subscheme X - Y of + Projective Space of dimension 2 over Rational Field, + where X is defined by: + (no polynomials) + and Y is defined by: + x*y + x*z + y*z """ A = self.ambient_space() if other is None: @@ -1708,9 +1706,9 @@ def complement(self, other=None): if other == A: other = A.subscheme([]) else: - raise TypeError("Argument other (=%s) must be a closed algebraic subscheme of an ambient space"%other) + raise TypeError("Argument other (=%s) must be a closed algebraic subscheme of an ambient space" % other) if other.ambient_space() != A: - raise ValueError("other (=%s) must be in the same ambient space as self"%other) + raise ValueError("other (=%s) must be in the same ambient space as self" % other) return AlgebraicScheme_quasi(other, self) def rational_points(self, **kwds): @@ -1766,26 +1764,28 @@ def rational_points(self, **kwds): Enumerate over a projective scheme over a number field:: + sage: # needs sage.rings.number_field sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) - sage: A.<x,y> = ProjectiveSpace(K,1) - sage: X=A.subscheme(x^2 - y^2) + sage: A.<x,y> = ProjectiveSpace(K, 1) + sage: X = A.subscheme(x^2 - y^2) sage: X.rational_points(bound=3) [(-1 : 1), (1 : 1)] One can enumerate points up to a given bound on a projective scheme over the rationals:: - sage: E = EllipticCurve('37a') - sage: E.rational_points(bound=8) - [(-1 : -1 : 1), (-1 : 0 : 1), (0 : -1 : 1), (0 : 0 : 1), (0 : 1 : 0), (1/4 : -5/8 : 1), - (1/4 : -3/8 : 1), (1 : -1 : 1), (1 : 0 : 1), (2 : -3 : 1), (2 : 2 : 1)] + sage: E = EllipticCurve('37a') # needs sage.schemes + sage: E.rational_points(bound=8) # needs sage.schemes + [(-1 : -1 : 1), (-1 : 0 : 1), (0 : -1 : 1), (0 : 0 : 1), (0 : 1 : 0), + (1/4 : -5/8 : 1), (1/4 : -3/8 : 1), (1 : -1 : 1), (1 : 0 : 1), + (2 : -3 : 1), (2 : 2 : 1)] For a small finite field, the complete set of points can be enumerated. :: - sage: Etilde = E.base_extend(GF(3)) - sage: Etilde.rational_points() + sage: Etilde = E.base_extend(GF(3)) # needs sage.schemes + sage: Etilde.rational_points() # needs sage.schemes [(0 : 0 : 1), (0 : 1 : 0), (0 : 2 : 1), (1 : 0 : 1), (1 : 2 : 1), (2 : 0 : 1), (2 : 2 : 1)] @@ -1794,25 +1794,27 @@ def rational_points(self, **kwds): sage: FF = FiniteField(7) sage: P.<x> = PolynomialRing(FiniteField(7)) - sage: C = HyperellipticCurve(x^8+x+1) - sage: C.rational_points() + sage: C = HyperellipticCurve(x^8 + x + 1) # needs sage.schemes + sage: C.rational_points() # needs sage.schemes [(0 : 1 : 0), (0 : 1 : 1), (0 : 6 : 1), (2 : 0 : 1), (4 : 0 : 1), (6 : 1 : 1), (6 : 6 : 1)] :: + sage: # needs sage.rings.number_field sage: K.<v> = QuadraticField(-3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) - sage: X = P.subscheme([x^2 - v^2*x*z, y*x-v*z^2]) + sage: X = P.subscheme([x^2 - v^2*x*z, y*x - v*z^2]) sage: X.rational_points(F=CC) [(-3.00000000000000 : -0.577350269189626*I : 1.00000000000000), (0.000000000000000 : 1.00000000000000 : 0.000000000000000)] :: + sage: # needs sage.rings.number_field sage: K.<v> = QuadraticField(3) sage: A.<x,y> = AffineSpace(K, 2) - sage: X = A.subscheme([x^2 - v^2*y, y*x-v]) + sage: X = A.subscheme([x^2 - v^2*y, y*x - v]) sage: X.rational_points(F=RR) [(1.73205080756888, 1.00000000000000)] @@ -1830,7 +1832,7 @@ def rational_points(self, **kwds): try: return X.points(**kwds) # checks for proper bound done in points functions except TypeError: - raise TypeError("Unable to enumerate points over %s."%F) + raise TypeError("Unable to enumerate points over %s." % F) elif (self.base_ring() in NumberFields() or self.base_ring() == ZZ)\ and hasattr(F, 'precision'): #we are numerically approximating number field points @@ -1839,7 +1841,7 @@ def rational_points(self, **kwds): X = self.base_extend(F)(F) return X.points() except TypeError: - raise TypeError("Unable to enumerate points over %s."%F) + raise TypeError("Unable to enumerate points over %s." % F) def change_ring(self, R): r""" @@ -1856,97 +1858,105 @@ def change_ring(self, R): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: X = P.subscheme([3*x^2-y^2]) - sage: H = Hom(X,X) + sage: X = P.subscheme([3*x^2 - y^2]) + sage: H = Hom(X, X) sage: X.change_ring(GF(3)) - Closed subscheme of Projective Space of dimension 1 over Finite Field of size 3 defined by: - -y^2 + Closed subscheme of Projective Space of dimension 1 + over Finite Field of size 3 defined by: -y^2 :: + sage: # needs sage.rings.number_field sage: K.<w> = QuadraticField(2) sage: R.<z> = K[] - sage: L.<v> = K.extension(z^3-5) + sage: L.<v> = K.extension(z^3 - 5) sage: P.<x,y> = ProjectiveSpace(K, 1) - sage: X = P.subscheme(x - w*y) - sage: X.change_ring(L) - Closed subscheme of Projective Space of dimension 1 over Number Field in v with - defining polynomial z^3 - 5 over its base field defined by: - x + (-w)*y + sage: X = P.subscheme(x - w*y) # needs sage.libs.singular + sage: X.change_ring(L) # needs sage.libs.singular + Closed subscheme of Projective Space of dimension 1 over + Number Field in v with defining polynomial z^3 - 5 over its base field + defined by: x + (-w)*y :: + sage: # needs sage.rings.number_field sage: K.<w> = QuadraticField(2) sage: R.<z> = K[] - sage: L.<v> = K.extension(z^3-5) - sage: P.<x,y,z> = AffineSpace(L,3) - sage: X = P.subscheme([x-w*y, z^2-v*x]) - sage: emb = L.embeddings(QQbar) - sage: X.change_ring(emb[0]) + sage: L.<v> = K.extension(z^3 - 5) + sage: P.<x,y,z> = AffineSpace(L, 3) + sage: X = P.subscheme([x - w*y, z^2 - v*x]) # needs sage.libs.singular + sage: emb = L.embeddings(QQbar) # needs sage.libs.singular + sage: X.change_ring(emb[0]) # needs sage.libs.singular Closed subscheme of Affine Space of dimension 3 over Algebraic Field - defined by: + defined by: x + (-1.414213562373095? + 0.?e-16*I)*y, z^2 + (0.8549879733383485? + 1.480882609682365?*I)*x :: + sage: # needs sage.rings.number_field sage: K.<w> = QuadraticField(2) sage: R.<z> = K[] - sage: L.<v> = K.extension(z^3-5) - sage: P.<x,y,z> = AffineSpace(L,3) - sage: X = P.subscheme([x-w*y, z^2-v*x]) - sage: emb = L.embeddings(QQbar) - sage: X.change_ring(emb[1]) + sage: L.<v> = K.extension(z^3 - 5) + sage: P.<x,y,z> = AffineSpace(L, 3) + sage: X = P.subscheme([x - w*y, z^2 - v*x]) # needs sage.libs.singular + sage: emb = L.embeddings(QQbar) # needs sage.libs.singular + sage: X.change_ring(emb[1]) # needs sage.libs.singular Closed subscheme of Affine Space of dimension 3 over Algebraic Field - defined by: + defined by: x + (-1.414213562373095? + 0.?e-16*I)*y, z^2 + (0.8549879733383485? - 1.480882609682365?*I)*x :: + sage: # needs sage.rings.number_field sage: K.<w> = QuadraticField(-3) sage: P.<x,y> = ProjectiveSpace(K, 1) - sage: X = P.subscheme(x-w*y) - sage: X.change_ring(CC) - Closed subscheme of Projective Space of dimension 1 over Complex Field - with 53 bits of precision defined by: + sage: X = P.subscheme(x - w*y) # needs sage.libs.singular + sage: X.change_ring(CC) # needs sage.libs.singular + Closed subscheme of Projective Space of dimension 1 + over Complex Field with 53 bits of precision defined by: x + (-1.73205080756888*I)*y :: + sage: # needs sage.rings.number_field sage: K.<w> = QuadraticField(3) - sage: P.<x,y> = ProjectiveSpace(K,1) - sage: X = P.subscheme(x-w*y) - sage: X.change_ring(RR) - Closed subscheme of Projective Space of dimension 1 over Real Field - with 53 bits of precision defined by: + sage: P.<x,y> = ProjectiveSpace(K, 1) + sage: X = P.subscheme(x - w*y) # needs sage.libs.singular + sage: X.change_ring(RR) # needs sage.libs.singular + Closed subscheme of Projective Space of dimension 1 + over Real Field with 53 bits of precision defined by: x - 1.73205080756888*y :: + sage: # needs sage.rings.number_field sage: K.<v> = CyclotomicField(7) sage: O = K.maximal_order() sage: P.<x,y> = ProjectiveSpace(O, 1) - sage: X = P.subscheme([x^2+O(v)*y^2]) - sage: X.change_ring(CC) - Closed subscheme of Projective Space of dimension 1 over Complex Field - with 53 bits of precision defined by: + sage: X = P.subscheme([x^2 + O(v)*y^2]) # needs sage.libs.singular + sage: X.change_ring(CC) # needs sage.libs.singular + Closed subscheme of Projective Space of dimension 1 + over Complex Field with 53 bits of precision defined by: x^2 + (0.623489801858734 + 0.781831482468030*I)*y^2 - sage: X.change_ring(K).change_ring(K.embeddings(QQbar)[3]) - Closed subscheme of Projective Space of dimension 1 over Algebraic Field defined by: + sage: X.change_ring(K).change_ring(K.embeddings(QQbar)[3]) # needs sage.libs.singular + Closed subscheme of Projective Space of dimension 1 + over Algebraic Field defined by: x^2 + (-0.9009688679024191? - 0.4338837391175581?*I)*y^2 :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: f = x^6-2 + sage: f = x^6 - 2 sage: L.<b> = NumberField(f, embedding=f.roots(CC)[2][0]) sage: A.<x,y> = AffineSpace(L, 2) - sage: H = Hom(A,A) - sage: X = A.subscheme([b*x^2, y^2]) - sage: X.change_ring(CC) - Closed subscheme of Affine Space of dimension 2 over Complex Field with - 53 bits of precision defined by: + sage: H = Hom(A, A) + sage: X = A.subscheme([b*x^2, y^2]) # needs sage.libs.singular + sage: X.change_ring(CC) # needs sage.libs.singular + Closed subscheme of Affine Space of dimension 2 + over Complex Field with 53 bits of precision defined by: (-0.561231024154687 - 0.972080648619833*I)*x^2, y^2 """ @@ -1990,27 +2000,28 @@ def weil_restriction(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: K.<w> = NumberField(x^5-2) + sage: K.<w> = NumberField(x^5 - 2) sage: R.<x> = K[] - sage: L.<v> = K.extension(x^2+1) - sage: A.<x,y> = AffineSpace(L,2) - sage: X = A.subscheme([y^2-L(w)*x^3-v]) - sage: X.weil_restriction() - Closed subscheme of Affine Space of dimension 4 over Number Field in w - with defining polynomial x^5 - 2 defined by: + sage: L.<v> = K.extension(x^2 + 1) + sage: A.<x,y> = AffineSpace(L, 2) + sage: X = A.subscheme([y^2 - L(w)*x^3 - v]) # needs sage.libs.singular + sage: X.weil_restriction() # needs sage.libs.singular + Closed subscheme of Affine Space of dimension 4 + over Number Field in w with defining polynomial x^5 - 2 defined by: (-w)*z0^3 + (3*w)*z0*z1^2 + z2^2 - z3^2, (-3*w)*z0^2*z1 + w*z1^3 + 2*z2*z3 - 1 - sage: X.weil_restriction().ambient_space() is A.weil_restriction() + sage: X.weil_restriction().ambient_space() is A.weil_restriction() # needs sage.libs.singular True :: - sage: A.<x,y,z> = AffineSpace(GF(5^2,'t'),3) - sage: X = A.subscheme([y^2-x*z, z^2+2*y]) - sage: X.weil_restriction() - Closed subscheme of Affine Space of dimension 6 over Finite Field of - size 5 defined by: + sage: A.<x,y,z> = AffineSpace(GF(5^2, 't'), 3) # needs sage.rings.finite_rings + sage: X = A.subscheme([y^2 - x*z, z^2 + 2*y]) # needs sage.libs.singular sage.rings.finite_rings + sage: X.weil_restriction() # needs sage.libs.singular sage.rings.finite_rings + Closed subscheme of Affine Space of dimension 6 + over Finite Field of size 5 defined by: z2^2 - 2*z3^2 - z0*z4 + 2*z1*z5, 2*z2*z3 + z3^2 - z1*z4 - z0*z5 - z1*z5, z4^2 - 2*z5^2 + 2*z2, @@ -2046,7 +2057,7 @@ def specialization(self, D=None, phi=None): - ``D`` -- dictionary (optional) - - ``phi`` -- SpecializationMorphism (optional) + - ``phi`` -- :class:`SpecializationMorphism` (optional) OUTPUT: :class:`SchemeMorphism_polynomial` @@ -2057,19 +2068,21 @@ def specialization(self, D=None, phi=None): sage: X = P.subscheme([x^2 + c*y^2]) sage: X.specialization(dict({c:2})) Closed subscheme of Projective Space of dimension 1 over Rational Field defined by: - x^2 + 2*y^2 + x^2 + 2*y^2 :: sage: R.<c> = PolynomialRing(QQ) sage: S.<a,b> = R[] - sage: P.<x,y,z> = AffineSpace(S,3) - sage: X = P.subscheme([x^2+a*c*y^2 - b*z^2]) + sage: P.<x,y,z> = AffineSpace(S, 3) + sage: X = P.subscheme([x^2 + a*c*y^2 - b*z^2]) sage: from sage.rings.polynomial.flatten import SpecializationMorphism - sage: phi = SpecializationMorphism(P.coordinate_ring(),dict({c:2,a:1})) - sage: X.specialization(phi=phi) - Closed subscheme of Affine Space of dimension 3 over Univariate Polynomial Ring in b over Rational Field defined by: - x^2 + 2*y^2 + (-b)*z^2 + sage: phi = SpecializationMorphism(P.coordinate_ring(), + ....: dict({c: 2, a: 1})) + sage: X.specialization(phi=phi) # needs sage.libs.singular + Closed subscheme of Affine Space of dimension 3 + over Univariate Polynomial Ring in b over Rational Field defined by: + x^2 + 2*y^2 + (-b)*z^2 """ if D is None: if phi is None: diff --git a/src/sage/schemes/generic/ambient_space.py b/src/sage/schemes/generic/ambient_space.py index aa4645d4e88..d22ea07d149 100644 --- a/src/sage/schemes/generic/ambient_space.py +++ b/src/sage/schemes/generic/ambient_space.py @@ -29,7 +29,7 @@ def is_AmbientSpace(x): sage: is_AmbientSpace(AffineSpace(2, QQ)) True sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) - sage: is_AmbientSpace(P.subscheme([x+y+z])) + sage: is_AmbientSpace(P.subscheme([x + y + z])) False """ return isinstance(x, AmbientSpace) @@ -148,7 +148,7 @@ def _validate(self, polynomials): sage: from sage.schemes.generic.ambient_space import AmbientSpace sage: A = AmbientSpace(3, ZZ) - sage: A._validate((x + 1, 1)) + sage: A._validate((x + 1, 1)) # needs sage.symbolic Traceback (most recent call last): ... NotImplementedError: ambient spaces must override "_validate" method! @@ -196,9 +196,9 @@ def is_projective(self): EXAMPLES:: - sage: AffineSpace(3,QQ).is_projective() + sage: AffineSpace(3, QQ).is_projective() False - sage: ProjectiveSpace(3,QQ).is_projective() + sage: ProjectiveSpace(3, QQ).is_projective() True """ # overloaded in the projective space derived class @@ -379,7 +379,7 @@ def dimension_absolute(self): base = self.base_scheme() if base.is_noetherian(): return self.dimension_relative() + base.dimension() - raise NotImplementedError("Cannot compute the dimension of this scheme.") + raise NotImplementedError("cannot compute the dimension of this scheme") dimension = dimension_absolute diff --git a/src/sage/schemes/generic/divisor.py b/src/sage/schemes/generic/divisor.py index 336fee8304f..6a55c3e8ce7 100644 --- a/src/sage/schemes/generic/divisor.py +++ b/src/sage/schemes/generic/divisor.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.schemes """ Divisors on schemes @@ -28,7 +29,7 @@ -1 sage: D[1][1] Ideal (x, z) of Multivariate Polynomial Ring in x, y, z over Finite Field of size 5 - sage: C.divisor([(3, pts[0]), (-1, pts[1]), (10,pts[5])]) + sage: C.divisor([(3, pts[0]), (-1, pts[1]), (10, pts[5])]) 3*(x, y) - (x, z) + 10*(x + 2*z, y + z) """ #******************************************************************************* @@ -109,7 +110,7 @@ def is_Divisor(x): sage: from sage.schemes.generic.divisor import is_Divisor sage: x,y = AffineSpace(2, GF(5), names='xy').gens() sage: C = Curve(y^2 - x^9 - x) - sage: is_Divisor( C.divisor([]) ) + sage: is_Divisor(C.divisor([])) True sage: is_Divisor("Ceci n'est pas un diviseur") False @@ -291,7 +292,7 @@ def __init__(self, v, parent=None, check=True, reduce=True): sage: P = E(0,0) sage: from sage.schemes.generic.divisor import Divisor_curve sage: from sage.schemes.generic.divisor_group import DivisorGroup - sage: Divisor_curve([(1,P)], parent=DivisorGroup(E)) + sage: Divisor_curve([(1, P)], parent=DivisorGroup(E)) (x, y) """ from sage.schemes.generic.divisor_group import DivisorGroup_curve @@ -373,7 +374,7 @@ def support(self): sage: C = Curve(y^2 - x^9 - x) sage: pts = C.rational_points(); pts [(0, 0), (2, 2), (2, 3), (3, 1), (3, 4)] - sage: D = C.divisor_group()([(3,pts[0]), (-1, pts[1])]); D + sage: D = C.divisor_group()([(3, pts[0]), (-1, pts[1])]); D 3*(x, y) - (x - 2, y - 2) sage: D.support() [(0, 0), (2, 2)] @@ -411,7 +412,6 @@ def support(self): self._support = [s[1] for s in pts] return self._support - def coefficient(self, P): """ Return the coefficient of a given point P in this divisor. @@ -425,7 +425,7 @@ def coefficient(self, P): sage: D = C.divisor(pts[0]) sage: D.coefficient(pts[0]) 1 - sage: D = C.divisor([(3,pts[0]), (-1,pts[1])]); D + sage: D = C.divisor([(3, pts[0]), (-1, pts[1])]); D 3*(x, y) - (x - 2, y - 2) sage: D.coefficient(pts[0]) 3 diff --git a/src/sage/schemes/generic/divisor_group.py b/src/sage/schemes/generic/divisor_group.py index 1301f783eb1..5dfd66a1bb9 100644 --- a/src/sage/schemes/generic/divisor_group.py +++ b/src/sage/schemes/generic/divisor_group.py @@ -171,7 +171,7 @@ def _element_constructor_(self, x, check=True, reduce=True): EXAMPLES:: sage: from sage.schemes.generic.divisor_group import DivisorGroup - sage: DivZZ=DivisorGroup(Spec(ZZ)) + sage: DivZZ = DivisorGroup(Spec(ZZ)) sage: DivZZ([(2,5)]) 2*V(5) """ @@ -209,10 +209,10 @@ def _an_element_(self): EXAMPLES:: - sage: A.<x, y> = AffineSpace(2, CC) - sage: C = Curve(y^2 - x^9 - x) + sage: A.<x, y> = AffineSpace(2, CC) # needs sage.rings.real_mpfr + sage: C = Curve(y^2 - x^9 - x) # needs sage.rings.real_mpfr sage.schemes sage: from sage.schemes.generic.divisor_group import DivisorGroup - sage: DivisorGroup(C).an_element() # indirect test + sage: DivisorGroup(C).an_element() # indirect test # needs sage.rings.real_mpfr sage.schemes 0 """ return self._scheme.divisor([], base_ring=self.base_ring(), check=False, reduce=False) @@ -222,16 +222,16 @@ def base_extend(self, R): EXAMPLES:: sage: from sage.schemes.generic.divisor_group import DivisorGroup - sage: DivisorGroup(Spec(ZZ),ZZ).base_extend(QQ) + sage: DivisorGroup(Spec(ZZ), ZZ).base_extend(QQ) Group of QQ-Divisors on Spectrum of Integer Ring - sage: DivisorGroup(Spec(ZZ),ZZ).base_extend(GF(7)) + sage: DivisorGroup(Spec(ZZ), ZZ).base_extend(GF(7)) Group of (Finite Field of size 7)-Divisors on Spectrum of Integer Ring Divisor groups are unique:: - sage: A.<x, y> = AffineSpace(2, CC) - sage: C = Curve(y^2 - x^9 - x) - sage: DivisorGroup(C,ZZ).base_extend(QQ) is DivisorGroup(C,QQ) + sage: A.<x, y> = AffineSpace(2, CC) # needs sage.rings.real_mpfr + sage: C = Curve(y^2 - x^9 - x) # needs sage.rings.real_mpfr sage.schemes + sage: DivisorGroup(C, ZZ).base_extend(QQ) is DivisorGroup(C, QQ) # needs sage.rings.real_mpfr sage.schemes True """ if self.base_ring().has_coerce_map_from(R): @@ -251,15 +251,16 @@ def _element_constructor_(self, x, check=True, reduce=True): EXAMPLES:: + sage: # needs sage.rings.real_mpfr sage.schemes sage: A.<x, y> = AffineSpace(2, CC) sage: C = Curve(y^2 - x^9 - x) - sage: DivZZ=C.divisor_group(ZZ) - sage: DivQQ=C.divisor_group(QQ) - sage: DivQQ( DivQQ.an_element() ) # indirect test + sage: DivZZ = C.divisor_group(ZZ) + sage: DivQQ = C.divisor_group(QQ) + sage: DivQQ(DivQQ.an_element()) # indirect test 0 - sage: DivZZ( DivZZ.an_element() ) # indirect test + sage: DivZZ(DivZZ.an_element()) # indirect test 0 - sage: DivQQ( DivZZ.an_element() ) # indirect test + sage: DivQQ(DivZZ.an_element()) # indirect test 0 """ if isinstance(x, Divisor_curve): diff --git a/src/sage/schemes/generic/glue.py b/src/sage/schemes/generic/glue.py index d3169ba0116..76bd9a1ab9e 100644 --- a/src/sage/schemes/generic/glue.py +++ b/src/sage/schemes/generic/glue.py @@ -33,11 +33,11 @@ class GluedScheme(scheme.Scheme): def __init__(self, f, g, check=True): if check: if not morphism.is_SchemeMorphism(f): - raise TypeError("f (=%s) must be a scheme morphism"%f) + raise TypeError("f (=%s) must be a scheme morphism" % f) if not morphism.is_SchemeMorphism(g): - raise TypeError("g (=%s) must be a scheme morphism"%g) + raise TypeError("g (=%s) must be a scheme morphism" % g) if f.domain() != g.domain(): - raise ValueError("f (=%s) and g (=%s) must have the same domain"%(f,g)) + raise ValueError("f (=%s) and g (=%s) must have the same domain" % (f,g)) self.__f = f self.__g = g @@ -45,5 +45,5 @@ def gluing_maps(self): return self.__f, self.__g def _repr_(self): - return "Scheme obtained by gluing X and Y along U, where\n X: %s\n Y: %s\n U: %s"%( + return "Scheme obtained by gluing X and Y along U, where\n X: %s\n Y: %s\n U: %s" % ( self.__f.codomain(), self.__g.codomain(), self.__f.domain()) diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index c918e2f4395..5db57860f7d 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -80,8 +80,8 @@ class SchemeHomsetFactory(UniqueFactory): EXAMPLES:: - sage: A2 = AffineSpace(QQ,2) - sage: A3 = AffineSpace(QQ,3) + sage: A2 = AffineSpace(QQ, 2) + sage: A3 = AffineSpace(QQ, 3) sage: Hom = A3.Hom(A2) The Hom-sets are uniquely determined by domain and codomain:: @@ -96,7 +96,7 @@ class SchemeHomsetFactory(UniqueFactory): sage: loads(Hom.dumps()) is Hom True - sage: A3_iso = AffineSpace(QQ,3) + sage: A3_iso = AffineSpace(QQ, 3) sage: A3_iso is A3 True sage: Hom_iso = A3_iso.Hom(A2) @@ -133,15 +133,15 @@ def create_key_and_extra_args(self, X, Y, category=None, base=None, EXAMPLES:: - sage: A2 = AffineSpace(QQ,2) - sage: A3 = AffineSpace(QQ,3) + sage: A2 = AffineSpace(QQ, 2) + sage: A3 = AffineSpace(QQ, 3) sage: A3.Hom(A2) # indirect doctest Set of morphisms From: Affine Space of dimension 3 over Rational Field To: Affine Space of dimension 2 over Rational Field sage: from sage.schemes.generic.homset import SchemeHomsetFactory sage: SHOMfactory = SchemeHomsetFactory('test') - sage: key, extra = SHOMfactory.create_key_and_extra_args(A3,A2,check=False) + sage: key, extra = SHOMfactory.create_key_and_extra_args(A3, A2, check=False) sage: key (..., ..., Category of schemes over Rational Field, False) sage: extra @@ -187,8 +187,8 @@ def create_object(self, version, key, **extra_args): EXAMPLES:: - sage: A2 = AffineSpace(QQ,2) - sage: A3 = AffineSpace(QQ,3) + sage: A2 = AffineSpace(QQ, 2) + sage: A3 = AffineSpace(QQ, 3) sage: A3.Hom(A2) is A3.Hom(A2) # indirect doctest True sage: from sage.schemes.generic.homset import SchemeHomsetFactory @@ -231,7 +231,7 @@ class SchemeHomset_generic(HomsetWithBase): - ``category`` -- a category (optional). The category of the Hom-set. - - ``check`` -- boolean (optional, default=``True``). Whether to + - ``check`` -- boolean (optional, default: ``True``). Whether to check the defining data for consistency. EXAMPLES:: @@ -253,8 +253,8 @@ def __reduce__(self): EXAMPLES:: - sage: A2 = AffineSpace(QQ,2) - sage: A3 = AffineSpace(QQ,3) + sage: A2 = AffineSpace(QQ, 2) + sage: A3 = AffineSpace(QQ, 3) sage: Hom = A3.Hom(A2) sage: loads(Hom.dumps()) == Hom True @@ -271,7 +271,7 @@ def __call__(self, *args, **kwds): EXAMPLES:: - sage: A2 = AffineSpace(QQ,2) + sage: A2 = AffineSpace(QQ, 2) sage: A2(4,5) (4, 5) """ @@ -372,13 +372,13 @@ def _element_constructor_(self, x, check=True): sage: R.<x,y> = QQ[] sage: A.<x,y> = AffineSpace(R) - sage: C = A.subscheme(x*y-1) + sage: C = A.subscheme(x*y - 1) sage: H = C.Hom(C); H Set of morphisms - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x*y - 1 - To: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x*y - 1 + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x*y - 1 + To: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x*y - 1 sage: H(1) Traceback (most recent call last): ... @@ -448,7 +448,7 @@ def __reduce__(self): EXAMPLES:: - sage: A2 = AffineSpace(QQ,2) + sage: A2 = AffineSpace(QQ, 2) sage: Hom = A2(QQ) sage: loads(Hom.dumps()) == Hom True @@ -473,24 +473,24 @@ def _coerce_map_from_(self, other): :: sage: P = ProjectiveSpace(QQ, 1, 'x') - sage: P2 = ProjectiveSpace(CC, 1, 'y') - sage: P2(CC)._coerce_map_from_(P(QQ)) + sage: P2 = ProjectiveSpace(CC, 1, 'y') # needs sage.rings.real_mpfr + sage: P2(CC)._coerce_map_from_(P(QQ)) # needs sage.rings.real_mpfr False :: sage: A.<x,y,z> = AffineSpace(QQ, 3) sage: H = A.subscheme(z) - sage: L = A.subscheme([z, y+z]) + sage: L = A.subscheme([z, y + z]) sage: A(QQ)._coerce_map_from_(H(QQ)) True - sage: H(QQ)._coerce_map_from_(L(QQ)) + sage: H(QQ)._coerce_map_from_(L(QQ)) # needs sage.libs.singular True - sage: L(QQ).has_coerce_map_from(H(QQ)) + sage: L(QQ).has_coerce_map_from(H(QQ)) # needs sage.libs.singular False - sage: A(CC)._coerce_map_from_(H(QQ)) + sage: A(CC)._coerce_map_from_(H(QQ)) # needs sage.rings.real_mpfr True - sage: H(CC)._coerce_map_from_(L(RR)) + sage: H(CC)._coerce_map_from_(L(RR)) # needs sage.libs.singular sage.rings.real_mpfr True :: @@ -516,10 +516,10 @@ def _coerce_map_from_(self, other): :: sage: PS = ProjectiveSpace(ZZ, 1, 'x') - sage: PS2 = ProjectiveSpace(Zp(7), 1, 'x') - sage: PS(ZZ).has_coerce_map_from(PS2(Zp(7))) + sage: PS2 = ProjectiveSpace(Zp(7), 1, 'x') # needs sage.rings.padics + sage: PS(ZZ).has_coerce_map_from(PS2(Zp(7))) # needs sage.rings.padics False - sage: PS2(Zp(7)).has_coerce_map_from(PS(ZZ)) + sage: PS2(Zp(7)).has_coerce_map_from(PS(ZZ)) # needs sage.rings.padics True :: @@ -536,6 +536,7 @@ def _coerce_map_from_(self, other): :: + sage: # needs sage.rings.number_field sage: K.<w> = QuadraticField(2) sage: A.<x,y,z> = AffineSpace(QQ, 3) sage: H = A.subscheme(z) @@ -545,15 +546,15 @@ def _coerce_map_from_(self, other): TESTS:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: X = P. subscheme ([x-y]) + sage: X = P.subscheme([x - y]) sage: P(1,1) == X(1,1) True :: sage: A = AffineSpace(QQ, 1, 'x') - sage: AC = AffineSpace(CC, 1, 'x') - sage: A(3/2) == AC(3/2) + sage: AC = AffineSpace(CC, 1, 'x') # needs sage.rings.real_mpfr + sage: A(3/2) == AC(3/2) # needs sage.rings.real_mpfr True :: @@ -631,15 +632,16 @@ def _element_constructor_(self, *v, **kwds): EXAMPLES:: - sage: A2 = AffineSpace(ZZ,2) + sage: A2 = AffineSpace(ZZ, 2) sage: F = GF(3) sage: F_points = A2(F); type(F_points) <class 'sage.schemes.affine.affine_homset.SchemeHomset_points_affine_with_category'> sage: F_points([2,5]) (2, 2) - sage: P2 = ProjectiveSpace(GF(3),2) - sage: F.<a> = GF(9,'a') + sage: # needs sage.rings.finite_rings + sage: P2 = ProjectiveSpace(GF(3), 2) + sage: F.<a> = GF(9, 'a') sage: F_points = P2(F) sage: type(F_points) <class 'sage.schemes.projective.projective_homset.SchemeHomset_points_projective_field_with_category'> @@ -648,7 +650,7 @@ def _element_constructor_(self, *v, **kwds): TESTS:: - sage: F_points._element_constructor_([4,2*a]) + sage: F_points._element_constructor_([4,2*a]) # needs sage.rings.finite_rings (1 : 2*a : 1) """ if len(v) == 1: @@ -667,18 +669,18 @@ def extended_codomain(self): EXAMPLES:: - sage: P2 = ProjectiveSpace(QQ,2) + sage: # needs sage.rings.number_field + sage: P2 = ProjectiveSpace(QQ, 2) + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + x - (3^3-3)) sage: K_points = P2(K); K_points Set of rational points of Projective Space of dimension 2 - over Number Field in a with defining polynomial x^2 + x - 24 - + over Number Field in a with defining polynomial x^2 + x - 24 sage: K_points.codomain() Projective Space of dimension 2 over Rational Field - sage: K_points.extended_codomain() - Projective Space of dimension 2 over Number Field in a with - defining polynomial x^2 + x - 24 + Projective Space of dimension 2 + over Number Field in a with defining polynomial x^2 + x - 24 """ if '_extended_codomain' in self.__dict__: return self._extended_codomain @@ -700,7 +702,7 @@ def _repr_(self): EXAMPLES:: - sage: P2 = ProjectiveSpace(ZZ,2) + sage: P2 = ProjectiveSpace(ZZ, 2) sage: P2(QQ)._repr_() 'Set of rational points of Projective Space of dimension 2 over Rational Field' """ @@ -716,7 +718,7 @@ def value_ring(self): EXAMPLES:: - sage: P2 = ProjectiveSpace(ZZ,2) + sage: P2 = ProjectiveSpace(ZZ, 2) sage: P2(QQ).value_ring() Rational Field """ @@ -735,11 +737,11 @@ def cardinality(self): EXAMPLES:: - sage: toric_varieties.P2().point_set().cardinality() + sage: toric_varieties.P2().point_set().cardinality() # needs sage.geometry.polyhedron +Infinity - sage: P2 = toric_varieties.P2(base_ring=GF(3)) - sage: P2.point_set().cardinality() + sage: P2 = toric_varieties.P2(base_ring=GF(3)) # needs sage.geometry.polyhedron + sage: P2.point_set().cardinality() # needs sage.geometry.polyhedron 13 """ if hasattr(self, 'is_finite') and not self.is_finite(): @@ -759,8 +761,8 @@ def list(self): EXAMPLES:: - sage: P1 = toric_varieties.P1(base_ring=GF(3)) - sage: P1.point_set().list() + sage: P1 = toric_varieties.P1(base_ring=GF(3)) # needs sage.geometry.polyhedron + sage: P1.point_set().list() # needs sage.geometry.polyhedron ([0 : 1], [1 : 0], [1 : 1], [1 : 2]) """ return tuple(self) diff --git a/src/sage/schemes/generic/hypersurface.py b/src/sage/schemes/generic/hypersurface.py index 12138d596af..f4991527c78 100644 --- a/src/sage/schemes/generic/hypersurface.py +++ b/src/sage/schemes/generic/hypersurface.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.schemes r""" Hypersurfaces in affine and projective space @@ -18,26 +19,26 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial +from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.schemes.affine.affine_subscheme import AlgebraicScheme_subscheme_affine from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective def is_Hypersurface(self): """ - Return True if self is a hypersurface, i.e. an object of the type - ProjectiveHypersurface or AffineHypersurface. + Return True if ``self`` is a hypersurface, i.e. an object of the type + :class:`ProjectiveHypersurface` or :class:`AffineHypersurface`. EXAMPLES:: sage: from sage.schemes.generic.hypersurface import is_Hypersurface sage: R.<x, y, z> = ZZ[] - sage: H = ProjectiveHypersurface(x*z+y^2) + sage: H = ProjectiveHypersurface(x*z + y^2) sage: is_Hypersurface(H) True :: - sage: H = AffineHypersurface(x*z+y^2) + sage: H = AffineHypersurface(x*z + y^2) sage: is_Hypersurface(H) True @@ -56,46 +57,47 @@ class ProjectiveHypersurface(AlgebraicScheme_subscheme_projective): EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(ZZ, 2) - sage: ProjectiveHypersurface(x-y, P) - Projective hypersurface defined by x - y in Projective Space of dimension 2 over Integer Ring + sage: ProjectiveHypersurface(x - y, P) + Projective hypersurface defined by x - y + in Projective Space of dimension 2 over Integer Ring :: sage: R.<x, y, z> = QQ[] - sage: ProjectiveHypersurface(x-y) - Projective hypersurface defined by x - y in Projective Space of dimension 2 over Rational Field + sage: ProjectiveHypersurface(x - y) + Projective hypersurface defined by x - y + in Projective Space of dimension 2 over Rational Field """ def __init__(self, poly, ambient=None): """ Return the projective hypersurface in the space ambient - defined by the polynomial poly. + defined by the polynomial ``poly``. - If ambient is not given, it will be constructed based on - poly. + If ambient is not given, it will be constructed based on ``poly``. EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(ZZ, 2) - sage: ProjectiveHypersurface(x-y, P) + sage: ProjectiveHypersurface(x - y, P) Projective hypersurface defined by x - y in Projective Space of dimension 2 over Integer Ring :: sage: R.<x, y, z> = QQ[] - sage: ProjectiveHypersurface(x-y) + sage: ProjectiveHypersurface(x - y) Projective hypersurface defined by x - y in Projective Space of dimension 2 over Rational Field TESTS:: - sage: H = ProjectiveHypersurface(x-y) + sage: H = ProjectiveHypersurface(x - y) sage: H == loads(dumps(H)) True """ - if not is_MPolynomial(poly): - raise TypeError("Defining polynomial (=%s) must be a multivariate polynomial."%poly) + if not isinstance(poly, MPolynomial): + raise TypeError("Defining polynomial (=%s) must be a multivariate polynomial." % poly) if not poly.is_homogeneous(): - raise TypeError("Defining polynomial (=%s) must be homogeneous."%poly) + raise TypeError("Defining polynomial (=%s) must be homogeneous." % poly) if ambient is None: R = poly.parent() from sage.schemes.projective.projective_space import ProjectiveSpace @@ -111,13 +113,14 @@ def _repr_(self): EXAMPLES:: sage: R.<x, y, z> = ZZ[] - sage: H = ProjectiveHypersurface(x*z+y^2) + sage: H = ProjectiveHypersurface(x*z + y^2) sage: H - Projective hypersurface defined by y^2 + x*z in Projective Space of dimension 2 over Integer Ring + Projective hypersurface defined by y^2 + x*z + in Projective Space of dimension 2 over Integer Ring sage: H._repr_() 'Projective hypersurface defined by y^2 + x*z in Projective Space of dimension 2 over Integer Ring' """ - return "Projective hypersurface defined by %s in %s"%( + return "Projective hypersurface defined by %s in %s" % ( self.defining_polynomial(), self.ambient_space()) def defining_polynomial(self): @@ -128,7 +131,7 @@ def defining_polynomial(self): EXAMPLES:: sage: R.<x, y, z> = ZZ[] - sage: H = ProjectiveHypersurface(x*z+y^2) + sage: H = ProjectiveHypersurface(x*z + y^2) sage: H.defining_polynomial() y^2 + x*z """ @@ -142,14 +145,16 @@ class AffineHypersurface(AlgebraicScheme_subscheme_affine): EXAMPLES:: sage: A.<x, y, z> = AffineSpace(ZZ, 3) - sage: AffineHypersurface(x*y-z^3, A) - Affine hypersurface defined by -z^3 + x*y in Affine Space of dimension 3 over Integer Ring + sage: AffineHypersurface(x*y - z^3, A) + Affine hypersurface defined by -z^3 + x*y + in Affine Space of dimension 3 over Integer Ring :: sage: A.<x, y, z> = QQ[] - sage: AffineHypersurface(x*y-z^3) - Affine hypersurface defined by -z^3 + x*y in Affine Space of dimension 3 over Rational Field + sage: AffineHypersurface(x*y - z^3) + Affine hypersurface defined by -z^3 + x*y + in Affine Space of dimension 3 over Rational Field """ def __init__(self, poly, ambient=None): """ @@ -162,23 +167,25 @@ def __init__(self, poly, ambient=None): EXAMPLES:: sage: A.<x, y, z> = AffineSpace(ZZ, 3) - sage: AffineHypersurface(x*y-z^3, A) - Affine hypersurface defined by -z^3 + x*y in Affine Space of dimension 3 over Integer Ring + sage: AffineHypersurface(x*y - z^3, A) + Affine hypersurface defined by -z^3 + x*y + in Affine Space of dimension 3 over Integer Ring :: sage: A.<x, y, z> = QQ[] - sage: AffineHypersurface(x*y-z^3) - Affine hypersurface defined by -z^3 + x*y in Affine Space of dimension 3 over Rational Field + sage: AffineHypersurface(x*y - z^3) + Affine hypersurface defined by -z^3 + x*y + in Affine Space of dimension 3 over Rational Field TESTS:: - sage: H = AffineHypersurface(x*y-z^3) + sage: H = AffineHypersurface(x*y - z^3) sage: H == loads(dumps(H)) True """ - if not is_MPolynomial(poly): - raise TypeError("Defining polynomial (= %s) must be a multivariate polynomial"%poly) + if not isinstance(poly, MPolynomial): + raise TypeError("Defining polynomial (= %s) must be a multivariate polynomial" % poly) if ambient is None: R = poly.parent() from sage.schemes.affine.affine_space import AffineSpace @@ -194,13 +201,14 @@ def _repr_(self): EXAMPLES:: sage: R.<x, y, z> = ZZ[] - sage: H = AffineHypersurface(x*z+y^2) + sage: H = AffineHypersurface(x*z + y^2) sage: H - Affine hypersurface defined by y^2 + x*z in Affine Space of dimension 3 over Integer Ring + Affine hypersurface defined by y^2 + x*z + in Affine Space of dimension 3 over Integer Ring sage: H._repr_() 'Affine hypersurface defined by y^2 + x*z in Affine Space of dimension 3 over Integer Ring' """ - return "Affine hypersurface defined by %s in %s"%( + return "Affine hypersurface defined by %s in %s" % ( self.defining_polynomial(), self.ambient_space()) def defining_polynomial(self): @@ -211,7 +219,7 @@ def defining_polynomial(self): EXAMPLES:: sage: R.<x, y, z> = ZZ[] - sage: H = AffineHypersurface(x*z+y^2) + sage: H = AffineHypersurface(x*z + y^2) sage: H.defining_polynomial() y^2 + x*z """ diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index d3fe7abd885..f42e8f4a680 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -9,9 +9,9 @@ all schemes. If you want to extend the Sage library with some new kind of scheme, -your new class (say, ``myscheme``) should provide a method +your new class (say, ``MyScheme``) should provide a method -* ``myscheme._morphism(*args, **kwds)`` returning a morphism +* ``MyScheme._morphism(*args, **kwds)`` returning a morphism between two schemes in your category, usually defined via polynomials. Your morphism class should derive from :class:`SchemeMorphism_polynomial`. These morphisms will usually be @@ -22,17 +22,17 @@ subcategory of schemes. If you want to do this, you should also provide a method -* ``myscheme._homset(*args, **kwds)`` returning a +* ``MyScheme._homset(*args, **kwds)`` returning a Hom-set, which must be an element of a derived class of :class:`~sage.schemes.generic.homset.SchemeHomset_generic`. If your - new Hom-set class does not use ``myscheme._morphism`` then you + new Hom-set class does not use ``MyScheme._morphism`` then you do not have to provide it. Note that points on schemes are morphisms `Spec(K)\to X`, too. But we typically use a different notation, so they are implemented in a different derived class. For this, you should implement a method -* ``myscheme._point(*args, **kwds)`` returning a point, that is, +* ``MyScheme._point(*args, **kwds)`` returning a point, that is, a morphism `Spec(K)\to X`. Your point class should derive from :class:`SchemeMorphism_point`. @@ -40,10 +40,10 @@ example the point Hom-set can provide a method to enumerate all points. If you want to do this, you should also provide a method -* ``myscheme._point_homset(*args, **kwds)`` returning +* ``MyScheme._point_homset(*args, **kwds)`` returning the :mod:`~sage.schemes.generic.homset` of points. The Hom-sets of points are implemented in classes named ``SchemeHomset_points_...``. - If your new Hom-set class does not use ``myscheme._point`` then + If your new Hom-set class does not use ``MyScheme._point`` then you do not have to provide it. AUTHORS: @@ -105,11 +105,10 @@ def is_SchemeMorphism(f): EXAMPLES:: - sage: A.<x,y> = AffineSpace(QQ,2); H = A.Hom(A) - sage: f = H([y,x^2+y]); f + sage: A.<x,y> = AffineSpace(QQ, 2); H = A.Hom(A) + sage: f = H([y, x^2 + y]); f Scheme endomorphism of Affine Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (y, x^2 + y) + Defn: Defined on coordinates by sending (x, y) to (y, x^2 + y) sage: from sage.schemes.generic.morphism import is_SchemeMorphism sage: is_SchemeMorphism(f) True @@ -143,7 +142,7 @@ class SchemeMorphism(Element): TESTS:: - sage: A2 = AffineSpace(QQ,2) + sage: A2 = AffineSpace(QQ, 2) sage: A2.structure_morphism().domain() Affine Space of dimension 2 over Rational Field sage: A2.structure_morphism().category() @@ -166,7 +165,7 @@ def __init__(self, parent, codomain=None): if codomain is not None: parent = Hom(parent, codomain) if not isinstance(parent, Homset): - raise TypeError("parent (=%s) must be a Homspace"%parent) + raise TypeError("parent (=%s) must be a Homspace" % parent) Element.__init__(self, parent) self._codomain = parent.codomain() @@ -179,7 +178,7 @@ def domain(self): sage: A.<x,y> = AffineSpace(QQ['x,y']) sage: H = A.Hom(A) - sage: f = H([y,x^2+y]) + sage: f = H([y, x^2 + y]) sage: f.domain() is A True """ @@ -194,7 +193,7 @@ def codomain(self): sage: A.<x,y> = AffineSpace(QQ['x,y']) sage: H = A.Hom(A) - sage: f = H([y,x^2+y]) + sage: f = H([y, x^2 + y]) sage: f.codomain() is A True """ @@ -217,17 +216,17 @@ def __call__(self, x, *args, **kwds): sage: R.<x,y> = QQ[] sage: A.<x,y> = AffineSpace(R) sage: H = A.Hom(A) - sage: f = H([y,x^2+y]) + sage: f = H([y, x^2 + y]) sage: f([2,3]) # indirect doctest (3, 7) An example with optional arguments:: - sage: PS.<x,y>=ProjectiveSpace(QQ,1) - sage: H=Hom(PS,PS) - sage: f=H([x^3,x*y^2]) - sage: P=PS(0,1) - sage: f(P,check=False) # indirect doctest + sage: PS.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(PS, PS) + sage: f = H([x^3, x*y^2]) + sage: P = PS(0, 1) + sage: f(P, check=False) # indirect doctest (0 : 0) """ P = parent(x) @@ -262,9 +261,9 @@ def __call__(self, x, *args, **kwds): try: x = D(x) except (TypeError, NotImplementedError): - raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented"%(x, self.domain())) - elif self.domain()!=x.codomain(): - raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented"%(x, self.domain())) + raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented" % (x, self.domain())) + elif self.domain() != x.codomain(): + raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented" % (x, self.domain())) else: x = converter(x) if not args and not kwds: @@ -302,7 +301,7 @@ def _repr_type(self): EXAMPLES:: - sage: A2 = AffineSpace(QQ,2) + sage: A2 = AffineSpace(QQ, 2) sage: A2.structure_morphism() # indirect doctest Scheme morphism: From: Affine Space of dimension 2 over Rational Field @@ -331,14 +330,14 @@ def _repr_(self): NotImplementedError """ if self.is_endomorphism(): - s = "%s endomorphism of %s"%(self._repr_type(), self.domain()) + s = "%s endomorphism of %s" % (self._repr_type(), self.domain()) else: - s = "%s morphism:"%self._repr_type() - s += "\n From: %s"%self.domain() - s += "\n To: %s"%self._codomain + s = "%s morphism:" % self._repr_type() + s += "\n From: %s" % self.domain() + s += "\n To: %s" % self._codomain d = self._repr_defn() if d != '': - s += "\n Defn: %s"%('\n '.join(self._repr_defn().split('\n'))) + s += "\n Defn: %s" % ('\n '.join(self._repr_defn().split('\n'))) return s def __mul__(self, right): @@ -353,7 +352,7 @@ def __mul__(self, right): Identity maps do not contribute to the product:: - sage: X = AffineSpace(QQ,2) + sage: X = AffineSpace(QQ, 2) sage: id = X.identity_morphism() sage: id^0 # indirect doctest Scheme endomorphism of Affine Space of dimension 2 over Rational Field @@ -364,12 +363,12 @@ def __mul__(self, right): Here, we see a formal composition:: - sage: X = AffineSpace(QQ,2) + sage: X = AffineSpace(QQ, 2) sage: f = X.structure_morphism() sage: Y = Spec(QQ) sage: g = Y.structure_morphism() sage: g * f # indirect doctest - Composite map: + Composite map: From: Affine Space of dimension 2 over Rational Field To: Spectrum of Integer Ring Defn: Generic morphism: @@ -397,7 +396,7 @@ def __mul__(self, right): if not isinstance(right, SchemeMorphism): return coercion_model.bin_op(self, right, operator.mul) if right.codomain() != self.domain(): - raise TypeError("self (=%s) domain must equal right (=%s) codomain"%(self, right)) + raise TypeError("self (=%s) domain must equal right (=%s) codomain" % (self, right)) if isinstance(self, SchemeMorphism_id): return right if isinstance(right, SchemeMorphism_id): @@ -418,7 +417,7 @@ def __pow__(self, n, dummy=None): EXAMPLES:: - sage: X = AffineSpace(QQ,2) + sage: X = AffineSpace(QQ, 2) sage: id = X.identity_morphism() sage: id^0 Scheme endomorphism of Affine Space of dimension 2 over Rational Field @@ -429,7 +428,7 @@ def __pow__(self, n, dummy=None): """ if not self.is_endomorphism(): raise TypeError("self must be an endomorphism.") - if n==0: + if n == 0: return self.domain().identity_morphism() return generic_power(self, n) @@ -443,7 +442,7 @@ def category(self): EXAMPLES:: - sage: A2 = AffineSpace(QQ,2) + sage: A2 = AffineSpace(QQ, 2) sage: A2.structure_morphism().category() Category of homsets of schemes """ @@ -455,7 +454,7 @@ def category_for(self): EXAMPLES:: - sage: A2 = AffineSpace(QQ,2) + sage: A2 = AffineSpace(QQ, 2) sage: A2.structure_morphism().category_for() Category of schemes """ @@ -471,7 +470,7 @@ def is_endomorphism(self) -> bool: EXAMPLES:: - sage: X = AffineSpace(QQ,2) + sage: X = AffineSpace(QQ, 2) sage: X.structure_morphism().is_endomorphism() False sage: X.identity_morphism().is_endomorphism() @@ -491,7 +490,7 @@ def base_ring(self): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: H = Hom(P,P) + sage: H = Hom(P, P) sage: f = H([3/5*x^2, 6*y^2]) sage: f.base_ring() Rational Field @@ -514,6 +513,7 @@ def base_ring(self): :: + sage: # needs sage.rings.finite_rings sage: E = EllipticCurve(GF((17,2)), [1,2,3,4,5]) sage: P = E.random_point() sage: P.base_ring() @@ -532,7 +532,7 @@ def _composition(self, right): EXAMPLES:: - sage: X = AffineSpace(QQ,2) + sage: X = AffineSpace(QQ, 2) sage: f = X.structure_morphism() sage: Y = Spec(QQ) sage: g = Y.structure_morphism() @@ -554,7 +554,8 @@ def _composition(self, right): TypeError: self (=Scheme morphism: From: Affine Space of dimension 2 over Rational Field To: Spectrum of Rational Field - Defn: Structure map) domain must equal right (=Scheme morphism: + Defn: Structure map) domain + must equal right (=Scheme morphism: From: Spectrum of Rational Field To: Spectrum of Integer Ring Defn: Structure map) codomain @@ -582,12 +583,12 @@ def _composition_(self, right, homset): EXAMPLES:: - sage: X = AffineSpace(QQ,2) + sage: X = AffineSpace(QQ, 2) sage: f = X.structure_morphism() sage: Y = Spec(QQ) sage: g = Y.structure_morphism() sage: g * f # indirect doctest - Composite map: + Composite map: From: Affine Space of dimension 2 over Rational Field To: Spectrum of Integer Ring Defn: Generic morphism: @@ -612,7 +613,7 @@ def glue_along_domains(self, other): OUTPUT: - Assuming that self and other are open immersions with the same + Assuming that ``self`` and ``other`` are open immersions with the same domain, return scheme obtained by gluing along the images. EXAMPLES: @@ -621,6 +622,7 @@ def glue_along_domains(self, other): `\mathrm{Spec}(\QQ)` by gluing two copies of `\mathbb{A}^1` minus a point:: + sage: # needs sage.libs.singular sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S.<xbar, ybar> = R.quotient(x*y - 1) sage: Rx = PolynomialRing(QQ, 'x') @@ -634,19 +636,18 @@ def glue_along_domains(self, other): Now f1 and f2 have the same domain, which is a `\mathbb{A}^1` minus a point. We glue along the domain:: - sage: P1 = f1.glue_along_domains(f2) - sage: P1 + sage: # needs sage.libs.singular + sage: P1 = f1.glue_along_domains(f2); P1 Scheme obtained by gluing X and Y along U, where X: Spectrum of Univariate Polynomial Ring in x over Rational Field Y: Spectrum of Univariate Polynomial Ring in y over Rational Field U: Spectrum of Quotient of Multivariate Polynomial Ring in x, y - over Rational Field by the ideal (x*y - 1) - + over Rational Field by the ideal (x*y - 1) sage: a, b = P1.gluing_maps() sage: a Affine Scheme morphism: - From: Spectrum of Quotient of Multivariate Polynomial Ring in x, y - over Rational Field by the ideal (x*y - 1) + From: Spectrum of Quotient of Multivariate Polynomial Ring in x, y + over Rational Field by the ideal (x*y - 1) To: Spectrum of Univariate Polynomial Ring in x over Rational Field Defn: Ring morphism: From: Univariate Polynomial Ring in x over Rational Field @@ -956,8 +957,8 @@ class SchemeMorphism_polynomial(SchemeMorphism): sage: R.<x,y> = QQ[] sage: A2 = AffineSpace(R) sage: H = A2.Hom(A2) - sage: f = H([x-y, x*y]) - sage: f([0,1]) + sage: f = H([x - y, x*y]) + sage: f([0, 1]) (-1, 0) An example involving the projective line:: @@ -965,14 +966,14 @@ class SchemeMorphism_polynomial(SchemeMorphism): sage: R.<x,y> = QQ[] sage: P1 = ProjectiveSpace(R) sage: H = P1.Hom(P1) - sage: f = H([x^2+y^2,x*y]) - sage: f([0,1]) + sage: f = H([x^2 + y^2, x*y]) + sage: f([0, 1]) (1 : 0) Some checks are performed to make sure the given polynomials define a morphism:: - sage: f = H([exp(x),exp(y)]) + sage: f = H([exp(x),exp(y)]) # needs sage.symbolic Traceback (most recent call last): ... TypeError: polys (=[e^x, e^y]) must be elements of Multivariate @@ -987,20 +988,19 @@ def __init__(self, parent, polys, check=True): EXAMPLES:: - sage: A2.<x,y> = AffineSpace(QQ,2) + sage: A2.<x,y> = AffineSpace(QQ, 2) sage: H = A2.Hom(A2) - sage: H([x-y, x*y]) + sage: H([x - y, x*y]) Scheme endomorphism of Affine Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (x - y, x*y) + Defn: Defined on coordinates by sending (x, y) to (x - y, x*y) """ if check: if not isinstance(polys, (list, tuple)): - raise TypeError("polys (=%s) must be a list or tuple"%polys) + raise TypeError("polys (=%s) must be a list or tuple" % polys) source_ring = parent.domain().ambient_space().coordinate_ring() target = parent._codomain.ambient_space() if len(polys) != target.ngens(): - raise ValueError("there must be %s polynomials"%target.ngens()) + raise ValueError("there must be %s polynomials" % target.ngens()) F = [] for poly in polys: try: @@ -1012,7 +1012,7 @@ def __init__(self, parent, polys, check=True): try: p = source_ring(poly.numerator()) / source_ring(poly.denominator()) except (TypeError, AttributeError): - raise TypeError("polys (=%s) must be elements of %s"%(polys, source_ring)) + raise TypeError("polys (=%s) must be elements of %s" % (polys, source_ring)) F.append(p) polys = Sequence(F) @@ -1054,7 +1054,7 @@ def defining_polynomials(self): sage: R.<x,y> = QQ[] sage: A.<x,y> = AffineSpace(R) sage: H = A.Hom(A) - sage: H([x^3+y, 1-x-y]).defining_polynomials() + sage: H([x^3 + y, 1 - x - y]).defining_polynomials() (x^3 + y, -x - y + 1) """ return self._polys @@ -1077,8 +1077,8 @@ def _call_(self, x): sage: R.<x,y> = QQ[] sage: A.<x,y> = AffineSpace(R) sage: H = A.Hom(A) - sage: f = H([y,x^2+y]) - sage: f([2,3]) # indirect doctest + sage: f = H([y, x^2 + y]) + sage: f([2, 3]) # indirect doctest (3, 7) An example with algebraic schemes:: @@ -1090,12 +1090,11 @@ def _call_(self, x): sage: f = Hom_XY([y,0]) # (0,y) |-> (y,0) sage: f Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x - To: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y - Defn: Defined on coordinates by sending (x, y) to - (y, 0) + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x + To: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: y + Defn: Defined on coordinates by sending (x, y) to (y, 0) sage: f([0,3]) (3, 0) @@ -1112,24 +1111,24 @@ def _call_(self, x): It is possible to avoid the checks on the resulting point which can be useful for indeterminacies, but be careful!! :: - sage: PS.<x,y>=ProjectiveSpace(QQ,1) - sage: H=Hom(PS,PS) - sage: f=H([x^3,x*y^2]) - sage: P=PS(0,1) - sage: f(P,check=False) + sage: PS.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(PS, PS) + sage: f = H([x^3, x*y^2]) + sage: P = PS(0,1) + sage: f(P, check=False) (0 : 0) - sage: P.<x,y,z>=ProjectiveSpace(ZZ,2) - sage: X=P.subscheme(x^2-y^2) - sage: H=Hom(X,X) - sage: f=H([x^2,y^2,z^2]) + sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) + sage: X = P.subscheme(x^2 - y^2) + sage: H = Hom(X, X) + sage: f = H([x^2, y^2, z^2]) sage: f([4,4,1]) (16 : 16 : 1) - sage: P.<x,y,z>=ProjectiveSpace(ZZ,2) - sage: X=P.subscheme(x^2-y^2) - sage: H=Hom(X,X) - sage: f=H([x^2,y^2,z^2]) + sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) + sage: X = P.subscheme(x^2 - y^2) + sage: H = Hom(X, X) + sage: f = H([x^2, y^2, z^2]) sage: f(P([4,4,1])) (16 : 16 : 1) """ @@ -1155,7 +1154,7 @@ def _call_with_args(self, x, args, kwds): sage: R.<x,y> = QQ[] sage: A.<x,y> = AffineSpace(R) sage: H = A.Hom(A) - sage: f = H([y,x^2+y]) + sage: f = H([y, x^2 + y]) sage: f([2,3]) (3, 7) @@ -1168,12 +1167,11 @@ def _call_with_args(self, x, args, kwds): sage: f = Hom_XY([y,0]) # (0,y) |-> (y,0) sage: f Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x - To: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y - Defn: Defined on coordinates by sending (x, y) to - (y, 0) + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x + To: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: y + Defn: Defined on coordinates by sending (x, y) to (y, 0) sage: f([0,3]) (3, 0) @@ -1190,19 +1188,19 @@ def _call_with_args(self, x, args, kwds): It is possible to avoid the checks on the resulting point which can be useful for indeterminacies, but be careful!! :: - sage: PS.<x,y>=ProjectiveSpace(QQ,1) - sage: H=Hom(PS,PS) - sage: f=H([x^3,x*y^2]) - sage: P=PS(0,1) - sage: f(P,check=False) # indirect doctest + sage: PS.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(PS,PS) + sage: f = H([x^3, x*y^2]) + sage: P = PS(0,1) + sage: f(P, check=False) # indirect doctest (0 : 0) :: - sage: P.<x,y,z>=ProjectiveSpace(ZZ,2) - sage: X=P.subscheme(x^2-y^2) - sage: H=Hom(X,X) - sage: f=H([x^2,y^2,z^2]) + sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) + sage: X = P.subscheme(x^2 - y^2) + sage: H = Hom(X, X) + sage: f = H([x^2, y^2, z^2]) sage: f([4,4,1]) (16 : 16 : 1) @@ -1210,7 +1208,7 @@ def _call_with_args(self, x, args, kwds): sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: P2.<u,v,w,t> = ProjectiveSpace(ZZ, 3) - sage: X = P.subscheme(x^2-y^2) + sage: X = P.subscheme(x^2 - y^2) sage: H = Hom(X, X) sage: f = H([x^2, y^2, z^2]) sage: f(P2([4,4,1,1])) @@ -1241,14 +1239,13 @@ def _repr_defn(self): sage: R.<x,y> = QQ[] sage: A.<x,y> = AffineSpace(R) sage: H = A.Hom(A) - sage: f = H([y,x^2+y]) + sage: f = H([y, x^2 + y]) sage: print(f._repr_defn()) - Defined on coordinates by sending (x, y) to - (y, x^2 + y) + Defined on coordinates by sending (x, y) to (y, x^2 + y) """ i = self.domain().ambient_space()._repr_generic_point() o = self._codomain.ambient_space()._repr_generic_point(self.defining_polynomials()) - return "Defined on coordinates by sending %s to\n%s"%(i,o) + return "Defined on coordinates by sending %s to\n%s" % (i,o) def __getitem__(self, i): """ @@ -1264,9 +1261,9 @@ def __getitem__(self, i): EXAMPLES:: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: H = Hom(P,P) - sage: f = H([3/5*x^2,6*y^2]) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(P, P) + sage: f = H([3/5*x^2, 6*y^2]) sage: f[1] 6*y^2 """ @@ -1282,7 +1279,7 @@ def __copy__(self): EXAMPLES:: - sage: P.<x,y> = ProjectiveSpace(QQ,1) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = Hom(P, P) sage: f = H([3/5*x^2, 6*y^2]) sage: g = copy(f) @@ -1293,7 +1290,7 @@ def __copy__(self): :: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: X = P.subscheme(x^2 - y^2) sage: Q = X(23, 23, 46) sage: P = X(1, 1, 1) @@ -1304,27 +1301,24 @@ def __copy__(self): def coordinate_ring(self): r""" - Returns the coordinate ring of the ambient projective space - the multivariable polynomial ring over the base ring - - OUTPUT: + Return the coordinate ring of the ambient projective space. - - ring + OUTPUT: A multivariable polynomial ring over the base ring. EXAMPLES:: - sage: P.<x,y>=ProjectiveSpace(QQ,1) - sage: H=Hom(P,P) - sage: f=H([3/5*x^2,6*y^2]) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(P, P) + sage: f = H([3/5*x^2, 6*y^2]) sage: f.coordinate_ring() Multivariate Polynomial Ring in x, y over Rational Field :: - sage: R.<t>=PolynomialRing(ZZ,1) - sage: P.<x,y>=ProjectiveSpace(R,1) - sage: H=Hom(P,P) - sage: f=H([3*x^2,y^2]) + sage: R.<t> = PolynomialRing(ZZ, 1) + sage: P.<x,y> = ProjectiveSpace(R, 1) + sage: H = Hom(P, P) + sage: f = H([3*x^2, y^2]) sage: f.coordinate_ring() Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in t over Integer Ring @@ -1349,26 +1343,28 @@ def change_ring(self, R, check=True): TESTS:: + sage: # needs sage.rings.number_field sage: R.<t> = QQ[] sage: K.<v> = QuadraticField(2) - sage: K2.<w> = NumberField(t**4-2) - sage: P.<x,y> = ProjectiveSpace(QQ,1) + sage: K2.<w> = NumberField(t**4 - 2) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: phi = K.embeddings(K2)[0] - sage: f = DynamicalSystem_projective([x**2+3*y**2,y**2]) + sage: f = DynamicalSystem_projective([x**2 + 3*y**2, y**2]) sage: f.change_ring(phi) - Dynamical System of Projective Space of dimension 1 over Number Field in w with defining polynomial t^4 - 2 - Defn: Defined on coordinates by sending (x : y) to - (x^2 + 3*y^2 : y^2) + Dynamical System of Projective Space of dimension 1 over + Number Field in w with defining polynomial t^4 - 2 + Defn: Defined on coordinates by sending (x : y) to (x^2 + 3*y^2 : y^2) :: + sage: # needs sage.rings.number_field sage: R.<t> = QQ[] sage: K.<u> = QuadraticField(2) - sage: K1.<v> = NumberField(t^4-2) - sage: K2.<w> = NumberField(t^8-2) - sage: P.<x,y> = ProjectiveSpace(K,1) + sage: K1.<v> = NumberField(t^4 - 2) + sage: K2.<w> = NumberField(t^8 - 2) + sage: P.<x,y> = ProjectiveSpace(K, 1) sage: phi = K1.embeddings(K2)[0] - sage: f = DynamicalSystem_projective([x^2+3*y^2,y^2]) + sage: f = DynamicalSystem_projective([x^2 + 3*y^2, y^2]) sage: f.change_ring(phi) Traceback (most recent call last): ... @@ -1378,46 +1374,45 @@ def change_ring(self, R, check=True): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(ZZ, 1) - sage: H = Hom(P,P) + sage: H = Hom(P, P) sage: f = H([3*x^2, y^2]) sage: f.change_ring(GF(3)) Scheme endomorphism of Projective Space of dimension 1 over Finite Field of size 3 - Defn: Defined on coordinates by sending (x : y) to - (0 : y^2) + Defn: Defined on coordinates by sending (x : y) to (0 : y^2) :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: H = Hom(P,P) - sage: f = H([5/2*x^3 + 3*x*y^2-y^3, 3*z^3 + y*x^2, x^3-z^3]) + sage: H = Hom(P, P) + sage: f = H([5/2*x^3 + 3*x*y^2 - y^3, 3*z^3 + y*x^2, x^3 - z^3]) sage: f.change_ring(GF(3)) Scheme endomorphism of Projective Space of dimension 2 over Finite Field of size 3 - Defn: Defined on coordinates by sending (x : y : z) to + Defn: Defined on coordinates by sending (x : y : z) to (x^3 - y^3 : x^2*y : x^3 - z^3) :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: X = P.subscheme([5*x^2 - y^2]) - sage: H = Hom(X,X) + sage: H = Hom(X, X) sage: f = H([x, y]) sage: f.change_ring(GF(3)) - Scheme endomorphism of Closed subscheme of Projective Space of dimension - 1 over Finite Field of size 3 defined by: - -x^2 - y^2 - Defn: Defined on coordinates by sending (x : y) to - (x : y) + Scheme endomorphism of Closed subscheme of Projective Space of dimension 1 + over Finite Field of size 3 defined by: -x^2 - y^2 + Defn: Defined on coordinates by sending (x : y) to (x : y) Check that :trac:`16834` is fixed:: + sage: # needs sage.rings.real_mpfr sage: A.<x,y,z> = AffineSpace(RR, 3) - sage: h = Hom(A,A) - sage: f = h([x^2+1.5, y^3, z^5-2.0]) + sage: h = Hom(A, A) + sage: f = h([x^2 + 1.5, y^3, z^5 - 2.0]) sage: f.change_ring(CC) - Scheme endomorphism of Affine Space of dimension 3 over Complex Field with 53 bits of precision - Defn: Defined on coordinates by sending (x, y, z) to - (x^2 + 1.50000000000000, y^3, z^5 - 2.00000000000000) + Scheme endomorphism of Affine Space of dimension 3 over + Complex Field with 53 bits of precision + Defn: Defined on coordinates by sending (x, y, z) to + (x^2 + 1.50000000000000, y^3, z^5 - 2.00000000000000) :: @@ -1429,76 +1424,78 @@ def change_ring(self, R, check=True): Scheme morphism: From: Affine Space of dimension 2 over Rational Field To: Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x, y) to - (x^2 : y^2) + Defn: Defined on coordinates by sending (x, y) to (x^2 : y^2) :: - sage: A.<x,y> = AffineSpace(QQ,2) - sage: H = Hom(A,A) + sage: A.<x,y> = AffineSpace(QQ, 2) + sage: H = Hom(A, A) sage: f = H([3*x^2/y, y^2/x]) - sage: f.change_ring(RR) + sage: f.change_ring(RR) # needs sage.rings.real_mpfr Scheme endomorphism of Affine Space of dimension 2 over Real Field with 53 bits of precision - Defn: Defined on coordinates by sending (x, y) to + Defn: Defined on coordinates by sending (x, y) to (3.00000000000000*x^2/y, y^2/x) :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) - sage: K.<a> = NumberField(x^3-x+1) + sage: K.<a> = NumberField(x^3 - x + 1) sage: P.<x,y> = ProjectiveSpace(K, 1) sage: H = End(P) sage: f = H([x^2 + a*x*y + a^2*y^2, y^2]) sage: emb = K.embeddings(QQbar) sage: f.change_ring(emb[0]) - Scheme endomorphism of Projective Space of dimension 1 over Algebraic - Field + Scheme endomorphism of Projective Space of dimension 1 + over Algebraic Field Defn: Defined on coordinates by sending (x : y) to (x^2 + (-1.324717957244746?)*x*y + 1.754877666246693?*y^2 : y^2) sage: f.change_ring(emb[1]) - Scheme endomorphism of Projective Space of dimension 1 over Algebraic - Field + Scheme endomorphism of Projective Space of dimension 1 + over Algebraic Field Defn: Defined on coordinates by sending (x : y) to - (x^2 + (0.6623589786223730? - 0.5622795120623013?*I)*x*y + - (0.1225611668766537? - 0.744861766619745?*I)*y^2 : y^2) + (x^2 + (0.6623589786223730? - 0.5622795120623013?*I)*x*y + + (0.1225611668766537? - 0.744861766619745?*I)*y^2 : y^2) :: + sage: # needs sage.rings.number_field sage.symbolic sage: K.<v> = QuadraticField(2, embedding=QQbar(sqrt(2))) sage: P.<x,y> = ProjectiveSpace(K, 1) sage: H = End(P) - sage: f = H([x^2+v*y^2, y^2]) + sage: f = H([x^2 + v*y^2, y^2]) sage: f.change_ring(QQbar) - Scheme endomorphism of Projective Space of dimension 1 over Algebraic - Field + Scheme endomorphism of Projective Space of dimension 1 + over Algebraic Field Defn: Defined on coordinates by sending (x : y) to (x^2 + 1.414213562373095?*y^2 : y^2) :: + sage: # needs sage.rings.number_field sage.symbolic sage: from sage.misc.verbose import set_verbose sage: set_verbose(-1) sage: K.<w> = QuadraticField(2, embedding=QQbar(-sqrt(2))) sage: P.<x,y> = ProjectiveSpace(K, 1) - sage: X = P.subscheme(x-y) + sage: X = P.subscheme(x - y) sage: H = End(X) - sage: f = H([6*x^2+2*x*y+16*y^2, -w*x^2-4*x*y-4*y^2]) + sage: f = H([6*x^2 + 2*x*y + 16*y^2, -w*x^2 - 4*x*y - 4*y^2]) sage: f.change_ring(QQbar) - Scheme endomorphism of Closed subscheme of Projective Space of dimension - 1 over Algebraic Field defined by: - x - y + Scheme endomorphism of Closed subscheme of Projective Space of dimension 1 + over Algebraic Field defined by: x - y Defn: Defined on coordinates by sending (x : y) to - (6*x^2 + 2*x*y + 16*y^2 : 1.414213562373095?*x^2 + (-4)*x*y + (-4)*y^2) + (6*x^2 + 2*x*y + 16*y^2 : 1.414213562373095?*x^2 + (-4)*x*y + (-4)*y^2) :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: f = x^6-2 + sage: f = x^6 - 2 sage: L.<b> = NumberField(f, embedding=f.roots(QQbar)[1][0]) - sage: A.<x,y> = AffineSpace(L,2) - sage: H = Hom(A,A) - sage: F = H([b*x/y, 1+y]) + sage: A.<x,y> = AffineSpace(L, 2) + sage: H = Hom(A, A) + sage: F = H([b*x/y, 1 + y]) sage: F.change_ring(QQbar) Scheme endomorphism of Affine Space of dimension 2 over Algebraic Field Defn: Defined on coordinates by sending (x, y) to @@ -1506,6 +1503,7 @@ def change_ring(self, R, check=True): :: + sage: # needs sage.rings.number_field sage: K.<a> = QuadraticField(-1) sage: A.<x,y> = AffineSpace(K, 2) sage: H = End(A) @@ -1513,8 +1511,7 @@ def change_ring(self, R, check=True): sage: emb = K.embeddings(QQbar)[0] sage: phi.change_ring(emb) Scheme endomorphism of Affine Space of dimension 2 over Algebraic Field - Defn: Defined on coordinates by sending (x, y) to - (x/y, y) + Defn: Defined on coordinates by sending (x, y) to (x/y, y) """ T = self.domain().change_ring(R) if self.is_endomorphism(): @@ -1581,11 +1578,10 @@ def specialization(self, D=None, phi=None, homset=None): sage: R.<c> = PolynomialRing(QQ) sage: P.<x,y> = ProjectiveSpace(R, 1) sage: H = End(P) - sage: f = H([x^2 + c*y^2,y^2]) - sage: f.specialization({c:1}) + sage: f = H([x^2 + c*y^2, y^2]) + sage: f.specialization({c: 1}) Scheme endomorphism of Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (x^2 + y^2 : y^2) + Defn: Defined on coordinates by sending (x : y) to (x^2 + y^2 : y^2) :: @@ -1594,12 +1590,12 @@ def specialization(self, D=None, phi=None, homset=None): sage: H = End(P) sage: f = H([x^3 + a*x*y^2 + b*y^3, y^3]) sage: from sage.rings.polynomial.flatten import SpecializationMorphism - sage: phi = SpecializationMorphism(P.coordinate_ring(), dict({a:2,b:-1})) + sage: phi = SpecializationMorphism(P.coordinate_ring(), {a: 2, b: -1}) sage: F = f.specialization(phi=phi); F Scheme endomorphism of Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (x^3 + 2*x*y^2 - y^3 : y^3) - sage: g = H([x^2 + a*y^2,y^2]) + Defn: Defined on coordinates by sending (x : y) to + (x^3 + 2*x*y^2 - y^3 : y^3) + sage: g = H([x^2 + a*y^2, y^2]) sage: G = g.specialization(phi=phi) sage: G.parent() is F.parent() True @@ -1614,33 +1610,33 @@ def specialization(self, D=None, phi=None, homset=None): sage: X = P.subscheme([x - c*y]) sage: H = End(X) sage: f = H([x^2, c*y^2]) - sage: f.specialization({c:2}) - Scheme endomorphism of Closed subscheme of Projective Space of dimension 1 over Rational Field defined by: - x - 2*y - Defn: Defined on coordinates by sending (x : y) to - (x^2 : 2*y^2) + sage: f.specialization({c: 2}) + Scheme endomorphism of Closed subscheme of Projective Space of dimension 1 + over Rational Field defined by: x - 2*y + Defn: Defined on coordinates by sending (x : y) to (x^2 : 2*y^2) :: sage: R.<c> = QQ[] - sage: P.<x,y> = ProjectiveSpace(R,1) + sage: P.<x,y> = ProjectiveSpace(R, 1) sage: f = DynamicalSystem_projective([x^2 + c*y^2, y^2], domain=P) - sage: F = f.dynatomic_polynomial(3) - sage: g = F.specialization({c:1}); g + sage: F = f.dynatomic_polynomial(3) # needs sage.libs.pari + sage: g = F.specialization({c: 1}); g x^6 + x^5*y + 4*x^4*y^2 + 3*x^3*y^3 + 7*x^2*y^4 + 4*x*y^5 + 5*y^6 - sage: g == f.specialization({c:1}).dynatomic_polynomial(3) + sage: g == f.specialization({c:1}).dynatomic_polynomial(3) # needs sage.libs.pari True :: sage: R1.<alpha, beta> = QQ[] - sage: A.<x> = AffineSpace(Frac(R1),1) + sage: A.<x> = AffineSpace(Frac(R1), 1) sage: f = DynamicalSystem_affine([alpha/(x^2 + 1/alpha)/(x - 1/beta^2)]) - sage: f.specialization({alpha:5,beta:10}) + sage: f.specialization({alpha: 5, beta: 10}) Dynamical System of Affine Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x) to (5/(x^3 - 1/100*x^2 + 1/5*x - 1/500)) - sage: f.specialization({alpha:5}).specialization({beta:10}) == f.specialization({alpha:5,beta:10}) + sage: f_5_10 = f.specialization({alpha: 5}).specialization({beta: 10}) + sage: f_5_10 == f.specialization({alpha: 5, beta: 10}) True """ if D is None: @@ -1677,36 +1673,37 @@ def _composition_(self, other, homset): TESTS:: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: H = Hom(P,P) - sage: f = H([x^2 -29/16*y^2, y^2]) - sage: g = H([y,x+y]) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(P, P) + sage: f = H([x^2 - 29/16*y^2, y^2]) + sage: g = H([y, x + y]) sage: h = f*g sage: h - Scheme endomorphism of Projective Space of dimension 1 over Rational - Field + Scheme endomorphism of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (-29/16*x^2 - 29/8*x*y - 13/16*y^2 : x^2 + 2*x*y + y^2) sage: p = P((1,3)) sage: h(p) == f(g(p)) True - sage: Q = ProjectiveSpace(QQ,2) - sage: H2 = Hom(P,Q) - sage: h2 = H2([x^2+y^2,x^2,y^2+2*x^2]) + sage: Q = ProjectiveSpace(QQ, 2) + sage: H2 = Hom(P, Q) + sage: h2 = H2([x^2 + y^2, x^2, y^2 + 2*x^2]) sage: h2 * f Scheme morphism: From: Projective Space of dimension 1 over Rational Field To: Projective Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x : y) to - (x^4 - 29/8*x^2*y^2 + 1097/256*y^4 : x^4 - 29/8*x^2*y^2 + 841/256*y^4 : 2*x^4 - 29/4*x^2*y^2 + 969/128*y^4) + (x^4 - 29/8*x^2*y^2 + 1097/256*y^4 + : x^4 - 29/8*x^2*y^2 + 841/256*y^4 + : 2*x^4 - 29/4*x^2*y^2 + 969/128*y^4) :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: A1.<z> = AffineSpace(QQ, 1) sage: H = End(A) - sage: f = H([x^2+y^2, y^2/x]) + sage: f = H([x^2 + y^2, y^2/x]) sage: H1 = Hom(A, A1) sage: g = H1([x + y^2]) sage: g*f @@ -1720,7 +1717,8 @@ def _composition_(self, other, homset): ... TypeError: self (=Scheme endomorphism of Affine Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x, y) to - (x^2 + y^2, y^2/x)) domain must equal right (=Scheme morphism: + (x^2 + y^2, y^2/x)) domain + must equal right (=Scheme morphism: From: Affine Space of dimension 2 over Rational Field To: Affine Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x, y) to @@ -1728,6 +1726,7 @@ def _composition_(self, other, homset): Not both defined by polynomials:: + sage: # needs sage.rings.number_field sage: x = polygen(QQ) sage: K.<a> = NumberField(x^2 - 2) sage: p1, p2 = K.Hom(K) @@ -1735,14 +1734,18 @@ def _composition_(self, other, homset): sage: q1 = R.Hom(R)(p1) sage: A = AffineSpace(R) sage: f1 = A.Hom(A)(q1) - sage: g = A.Hom(A)([x^2-y, y+1]) + sage: g = A.Hom(A)([x^2 - y, y + 1]) sage: g*f1 Composite map: - From: Affine Space of dimension 2 over Number Field in a with defining polynomial x^2 - 2 - To: Affine Space of dimension 2 over Number Field in a with defining polynomial x^2 - 2 - Defn: Generic endomorphism of Affine Space of dimension 2 over Number Field in a with defining polynomial x^2 - 2 + From: Affine Space of dimension 2 over Number Field in a + with defining polynomial x^2 - 2 + To: Affine Space of dimension 2 over Number Field in a + with defining polynomial x^2 - 2 + Defn: Generic endomorphism of Affine Space of dimension 2 + over Number Field in a with defining polynomial x^2 - 2 then - Generic endomorphism of Affine Space of dimension 2 over Number Field in a with defining polynomial x^2 - 2 + Generic endomorphism of Affine Space of dimension 2 + over Number Field in a with defining polynomial x^2 - 2 """ try: opolys = tuple(other._polys) @@ -1961,7 +1964,7 @@ def scheme(self): def change_ring(self, R, check=True): r""" - Returns a new :class:`SchemeMorphism_point` which is this point coerced to``R``. + Returns a new :class:`SchemeMorphism_point` which is this point coerced to ``R``. If ``check`` is true, then the initialization checks are performed. @@ -1969,8 +1972,6 @@ def change_ring(self, R, check=True): - ``R`` -- ring or morphism. - kwds: - - ``check`` -- Boolean OUTPUT: :class:`SchemeMorphism_point` @@ -1978,40 +1979,43 @@ def change_ring(self, R, check=True): EXAMPLES:: sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) - sage: X = P.subscheme(x^2-y^2) + sage: X = P.subscheme(x^2 - y^2) sage: X(23,23,1).change_ring(GF(13)) (10 : 10 : 1) :: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: P(-2/3,1).change_ring(CC) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: P(-2/3,1).change_ring(CC) # needs sage.rings.real_mpfr (-0.666666666666667 : 1.00000000000000) :: - sage: P.<x,y> = ProjectiveSpace(ZZ,1) - sage: P(152,113).change_ring(Zp(5)) + sage: P.<x,y> = ProjectiveSpace(ZZ, 1) + sage: P(152,113).change_ring(Zp(5)) # needs sage.rings.padics (2 + 5^2 + 5^3 + O(5^20) : 3 + 2*5 + 4*5^2 + O(5^20)) :: + sage: # needs sage.rings.number_field sage: K.<v> = QuadraticField(-7) sage: O = K.maximal_order() sage: P.<x,y> = ProjectiveSpace(O, 1) sage: H = End(P) - sage: F = H([x^2+O(v)*y^2, y^2]) + sage: F = H([x^2 + O(v)*y^2, y^2]) sage: F.change_ring(K).change_ring(K.embeddings(QQbar)[0]) - Scheme endomorphism of Projective Space of dimension 1 over Algebraic Field + Scheme endomorphism of Projective Space of dimension 1 + over Algebraic Field Defn: Defined on coordinates by sending (x : y) to (x^2 + (-2.645751311064591?*I)*y^2 : y^2) :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) - sage: K.<a> = NumberField(x^2-x+1) - sage: P.<x,y> = ProjectiveSpace(K,1) - sage: Q = P([a+1,1]) + sage: K.<a> = NumberField(x^2 - x + 1) + sage: P.<x,y> = ProjectiveSpace(K, 1) + sage: Q = P([a + 1, 1]) sage: emb = K.embeddings(QQbar) sage: Q.change_ring(emb[0]) (1.5000000000000000? - 0.866025403784439?*I : 1) @@ -2020,18 +2024,20 @@ def change_ring(self, R, check=True): :: + sage: # needs sage.rings.number_field sage: K.<v> = QuadraticField(2) - sage: P.<x,y> = ProjectiveSpace(K,1) + sage: P.<x,y> = ProjectiveSpace(K, 1) sage: Q = P([v,1]) sage: Q.change_ring(K.embeddings(QQbar)[0]) (-1.414213562373095? : 1) :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: f = x^6-2 + sage: f = x^6 - 2 sage: L.<b> = NumberField(f, embedding=f.roots(QQbar)[1][0]) - sage: A.<x,y> = AffineSpace(L,2) + sage: A.<x,y> = AffineSpace(L, 2) sage: P = A([b,1]) sage: P.change_ring(QQbar) (1.122462048309373?, 1) @@ -2083,16 +2089,16 @@ def specialization(self, D=None, phi=None, ambient=None): sage: R.<c> = PolynomialRing(QQ) sage: P.<x,y> = ProjectiveSpace(R, 1) sage: Q = P([c,1]) - sage: Q.specialization({c:1}) + sage: Q.specialization({c: 1}) (1 : 1) - :: + :: sage: R.<a,b> = PolynomialRing(QQ) sage: P.<x,y> = ProjectiveSpace(R, 1) sage: Q = P([a^2 + 2*a*b + 34, 1]) sage: from sage.rings.polynomial.flatten import SpecializationMorphism - sage: phi = SpecializationMorphism(P.coordinate_ring(),dict({a:2,b:-1})) + sage: phi = SpecializationMorphism(P.coordinate_ring(), {a: 2, b: -1}) sage: T = Q.specialization(phi=phi); T (34 : 1) sage: Q2 = P([a,1]) @@ -2112,8 +2118,8 @@ def specialization(self, D=None, phi=None, ambient=None): sage: Q2 = Q.specialization({c:2}); Q2 (2 : 1) sage: Q2.codomain() - Closed subscheme of Projective Space of dimension 1 over Rational Field defined by: - x - 2*y + Closed subscheme of Projective Space of dimension 1 over Rational Field + defined by: x - 2*y :: @@ -2122,8 +2128,8 @@ def specialization(self, D=None, phi=None, ambient=None): sage: K.<a,b,c,d> = S[] sage: P.<x,y> = ProjectiveSpace(K, 1) sage: H = End(P) - sage: Q = P([a^2,b^2]) - sage: Q.specialization({a:2}) + sage: Q = P([a^2, b^2]) + sage: Q.specialization({a: 2}) (4 : b^2) """ if D is None: diff --git a/src/sage/schemes/generic/point.py b/src/sage/schemes/generic/point.py index 0cadc10957e..c65963e3eaa 100644 --- a/src/sage/schemes/generic/point.py +++ b/src/sage/schemes/generic/point.py @@ -66,7 +66,7 @@ def _repr_(self): sage: P._repr_() 'Point on Spectrum of Integer Ring' """ - return "Point on %s"%self.__S + return "Point on %s" % self.__S ######################################################## # Topological points on a scheme @@ -100,6 +100,7 @@ def __init__(self, S): """ SchemePoint.__init__(self, S, parent=S) + class SchemeTopologicalPoint_affine_open(SchemeTopologicalPoint): def __init__(self, u, x): """ @@ -114,26 +115,25 @@ def __init__(self, u, x): self.__x = x def _repr_(self): - return "Point on %s defined by x in U, where:\n U: %s\n x: %s"%(\ - self.scheme(), self.embedding_of_affine_open().domain(), - self.point_on_affine()) + return "Point on %s defined by x in U, where:\n U: %s\n x: %s" % ( + self.scheme(), self.embedding_of_affine_open().domain(), + self.point_on_affine()) def point_on_affine(self): """ - Return the scheme point on the affine open U. + Return the scheme point on the affine open `U`. """ return self.__x def affine_open(self): """ - Return the affine open subset U. + Return the affine open subset `U`. """ return self.__u.domain() def embedding_of_affine_open(self): """ - Return the embedding from the affine open subset U into this - scheme. + Return the embedding from the affine open subset `U` into this scheme. """ return self.__u @@ -165,8 +165,9 @@ def __init__(self, S, P, check=False): corresponding to a prime ideal:: sage: P2.<x, y, z> = ProjectiveSpace(2, QQ) - sage: SchemeTopologicalPoint_prime_ideal(P2, y*z-x^2) - Point on Projective Space of dimension 2 over Rational Field defined by the Ideal (-x^2 + y*z) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: SchemeTopologicalPoint_prime_ideal(P2, y*z - x^2) + Point on Projective Space of dimension 2 over Rational Field defined by + the Ideal (-x^2 + y*z) of Multivariate Polynomial Ring in x, y, z over Rational Field """ R = S.coordinate_ring() from sage.rings.ideal import is_Ideal @@ -178,7 +179,7 @@ def __init__(self, S, P, check=False): # unfortunately is_prime() is only implemented in a small # number of cases if check and not P.is_prime(): - raise ValueError("The argument %s must be a prime ideal of %s"%(P, R)) + raise ValueError("The argument %s must be a prime ideal of %s" % (P, R)) SchemeTopologicalPoint.__init__(self, S) self.__P = P @@ -190,13 +191,15 @@ def _repr_(self): sage: from sage.schemes.generic.point import SchemeTopologicalPoint_prime_ideal sage: P2.<x, y, z> = ProjectiveSpace(2, QQ) - sage: pt = SchemeTopologicalPoint_prime_ideal(P2, y*z-x^2); pt - Point on Projective Space of dimension 2 over Rational Field defined by the Ideal (-x^2 + y*z) of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: pt = SchemeTopologicalPoint_prime_ideal(P2, y*z - x^2); pt + Point on Projective Space of dimension 2 over Rational Field defined by + the Ideal (-x^2 + y*z) of Multivariate Polynomial Ring in x, y, z over Rational Field sage: pt._repr_() 'Point on Projective Space of dimension 2 over Rational Field defined by the Ideal (-x^2 + y*z) of Multivariate Polynomial Ring in x, y, z over Rational Field' """ - return "Point on %s defined by the %s"%(self.scheme(), + return "Point on %s defined by the %s" % (self.scheme(), self.prime_ideal()) + def prime_ideal(self): """ Return the prime ideal that defines this scheme point. @@ -205,7 +208,7 @@ def prime_ideal(self): sage: from sage.schemes.generic.point import SchemeTopologicalPoint_prime_ideal sage: P2.<x, y, z> = ProjectiveSpace(2, QQ) - sage: pt = SchemeTopologicalPoint_prime_ideal(P2, y*z-x^2) + sage: pt = SchemeTopologicalPoint_prime_ideal(P2, y*z - x^2) sage: pt.prime_ideal() Ideal (-x^2 + y*z) of Multivariate Polynomial Ring in x, y, z over Rational Field """ @@ -244,7 +247,7 @@ def __init__(self, f): self.__f = f def _repr_(self): - return "Point on %s defined by the morphism %s"%(self.scheme(), + return "Point on %s defined by the morphism %s" % (self.scheme(), self.morphism()) def morphism(self): diff --git a/src/sage/schemes/generic/scheme.py b/src/sage/schemes/generic/scheme.py index 520b1fa6b6d..fe55bca9117 100644 --- a/src/sage/schemes/generic/scheme.py +++ b/src/sage/schemes/generic/scheme.py @@ -96,7 +96,7 @@ def __init__(self, X=None, category=None): sage: I = (x^2 - y^2)*R sage: RmodI = R.quotient(I) sage: X = Spec(RmodI) - sage: TestSuite(X).run() + sage: TestSuite(X).run() # needs sage.libs.singular """ from sage.schemes.generic.morphism import is_SchemeMorphism @@ -167,7 +167,7 @@ def _morphism(self, *args, **kwds): sage: S = Spec(ZZ) sage: f = S.identity_morphism() sage: from sage.schemes.generic.glue import GluedScheme - sage: T = GluedScheme(f,f) + sage: T = GluedScheme(f, f) sage: S.hom([1],T) Traceback (most recent call last): ... @@ -216,16 +216,16 @@ def __call__(self, *args): sage: A(QQ) Set of rational points of Affine Space of dimension 2 over Rational Field - sage: A(RR) - Set of rational points of Affine Space of dimension 2 over Real Field - with 53 bits of precision + sage: A(RR) # needs sage.rings.real_mpfr + Set of rational points of Affine Space of dimension 2 + over Real Field with 53 bits of precision Space of dimension 2 over Rational Field:: sage: R.<x> = PolynomialRing(QQ) - sage: A(NumberField(x^2+1, 'a')) - Set of rational points of Affine Space of dimension 2 over Number Field - in a with defining polynomial x^2 + 1 + sage: A(NumberField(x^2 + 1, 'a')) # needs sage.rings.number_field + Set of rational points of Affine Space of dimension 2 + over Number Field in a with defining polynomial x^2 + 1 sage: A(GF(7)) Traceback (most recent call last): ... @@ -246,7 +246,7 @@ def __call__(self, *args): Check that :trac:`16832` is fixed:: sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) - sage: X=P.subscheme(x^2 - y^2) + sage: X = P.subscheme(x^2 - y^2) sage: X(P([4, 4, 1])) (4 : 4 : 1) """ @@ -287,11 +287,11 @@ def point_homset(self, S=None): Set of rational points of Projective Space of dimension 3 over Rational Field sage: P.point_homset(GF(11)) Set of rational points of Projective Space of dimension 3 over - Finite Field of size 11 + Finite Field of size 11 TESTS:: - sage: P = ProjectiveSpace(QQ,3) + sage: P = ProjectiveSpace(QQ, 3) sage: P.point_homset(GF(11)) Traceback (most recent call last): ... @@ -321,13 +321,13 @@ def point(self, v, check=True): EXAMPLES:: - sage: A2 = AffineSpace(QQ,2) - sage: A2.point([4,5]) + sage: A2 = AffineSpace(QQ, 2) + sage: A2.point([4, 5]) (4, 5) sage: R.<t> = PolynomialRing(QQ) - sage: E = EllipticCurve([t + 1, t, t, 0, 0]) - sage: E.point([0, 0]) + sage: E = EllipticCurve([t + 1, t, t, 0, 0]) # needs sage.schemes + sage: E.point([0, 0]) # needs sage.schemes (0 : 0 : 1) """ # todo: update elliptic curve stuff to take point_homset as argument @@ -506,7 +506,8 @@ def coordinate_ring(self): sage: I = (x^2 - y^2)*R sage: X = Spec(R.quotient(I)) sage: X.coordinate_ring() - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 - y^2) + Quotient of Multivariate Polynomial Ring in x, y over Rational Field + by the ideal (x^2 - y^2) """ try: return self._coordinate_ring @@ -644,8 +645,8 @@ def _Hom_(self, Y, category=None, check=True): sage: S._Hom_(P).__class__ <class 'sage.schemes.generic.homset.SchemeHomset_generic_with_category'> - sage: E = EllipticCurve('37a1') - sage: Hom(E, E).__class__ + sage: E = EllipticCurve('37a1') # needs sage.schemes + sage: Hom(E, E).__class__ # needs sage.schemes <class 'sage.schemes.projective.projective_homset.SchemeHomset_polynomial_projective_space_with_category'> sage: Hom(Spec(ZZ), Spec(ZZ)).__class__ @@ -671,18 +672,19 @@ def count_points(self, n): EXAMPLES:: + sage: # needs sage.schemes sage: P.<x> = PolynomialRing(GF(3)) - sage: C = HyperellipticCurve(x^3+x^2+1) + sage: C = HyperellipticCurve(x^3 + x^2 + 1) sage: C.count_points(4) [6, 12, 18, 96] - sage: C.base_extend(GF(9,'a')).count_points(2) + sage: C.base_extend(GF(9,'a')).count_points(2) # needs sage.rings.finite_rings [12, 96] :: - sage: P.<x,y,z> = ProjectiveSpace(GF(4,'t'), 2) - sage: X = P.subscheme([y^2*z - x^3 - z^3]) - sage: X.count_points(2) + sage: P.<x,y,z> = ProjectiveSpace(GF(4, 't'), 2) # needs sage.rings.finite_rings + sage: X = P.subscheme([y^2*z - x^3 - z^3]) # needs sage.rings.finite_rings + sage: X.count_points(2) # needs sage.rings.finite_rings [5, 17] """ F = self.base_ring() @@ -705,16 +707,15 @@ def zeta_function(self): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(GF(4,'t'), 2) - sage: X = P.subscheme([y^2*z - x^3 - z^3]) - sage: X.zeta_function() + sage: P.<x,y,z> = ProjectiveSpace(GF(4, 't'), 2) # needs sage.rings.finite_rings + sage: X = P.subscheme([y^2*z - x^3 - z^3]) # needs sage.rings.finite_rings + sage: X.zeta_function() # needs sage.rings.finite_rings Traceback (most recent call last): ... NotImplementedError """ raise NotImplementedError - def zeta_series(self, n, t): """ Return the zeta series. @@ -735,9 +736,9 @@ def zeta_series(self, n, t): EXAMPLES:: sage: P.<x> = PolynomialRing(GF(3)) - sage: C = HyperellipticCurve(x^3+x^2+1) + sage: C = HyperellipticCurve(x^3 + x^2 + 1) # needs sage.schemes sage: R.<t> = PowerSeriesRing(Integers()) - sage: C.zeta_series(4,t) + sage: C.zeta_series(4, t) # needs sage.schemes 1 + 6*t + 24*t^2 + 78*t^3 + 240*t^4 + O(t^5) sage: (1+2*t+3*t^2)/(1-t)/(1-3*t) + O(t^5) 1 + 6*t + 24*t^2 + 78*t^3 + 240*t^4 + O(t^5) @@ -749,23 +750,24 @@ def zeta_series(self, n, t): Nonetheless, since :trac:`15108` and :trac:`15148`, it supports hyperelliptic curves over non-prime fields:: - sage: C.base_extend(GF(9,'a')).zeta_series(4,t) + sage: C.base_extend(GF(9, 'a')).zeta_series(4, t) # needs sage.rings.finite_rings sage.schemes 1 + 12*t + 120*t^2 + 1092*t^3 + 9840*t^4 + O(t^5) :: - sage: P.<x,y,z> = ProjectiveSpace(GF(4,'t'), 2) - sage: X = P.subscheme([y^2*z - x^3 - z^3]) + sage: P.<x,y,z> = ProjectiveSpace(GF(4, 't'), 2) # needs sage.rings.finite_rings + sage: X = P.subscheme([y^2*z - x^3 - z^3]) # needs sage.rings.finite_rings + sage: R.<t> = PowerSeriesRing(Integers()) - sage: X.zeta_series(2,t) + sage: X.zeta_series(2, t) # needs sage.libs.singular sage.rings.finite_rings 1 + 5*t + 21*t^2 + O(t^3) TESTS:: sage: P.<x> = PolynomialRing(ZZ) - sage: C = HyperellipticCurve(x^3+x+1) + sage: C = HyperellipticCurve(x^3 + x + 1) # needs sage.schemes sage: R.<t> = PowerSeriesRing(Integers()) - sage: C.zeta_series(4,t) + sage: C.zeta_series(4, t) # needs sage.schemes Traceback (most recent call last): ... TypeError: zeta functions only defined for schemes @@ -952,15 +954,16 @@ def __call__(self, *args): Point on Spectrum of Integer Ring defined by the Principal ideal (3) of Integer Ring sage: type(P) <class 'sage.schemes.generic.scheme.AffineScheme_with_category.element_class'> - sage: S(ZZ.ideal(next_prime(1000000))) - Point on Spectrum of Integer Ring defined by the Principal ideal (1000003) of Integer Ring + sage: S(ZZ.ideal(next_prime(1000000))) # needs sage.libs.pari + Point on Spectrum of Integer Ring + defined by the Principal ideal (1000003) of Integer Ring sage: R.<x, y, z> = QQ[] sage: S = Spec(R) sage: P = S(R.ideal(x, y, z)); P Point on Spectrum of Multivariate Polynomial Ring - in x, y, z over Rational Field defined by the Ideal (x, y, z) - of Multivariate Polynomial Ring in x, y, z over Rational Field + in x, y, z over Rational Field defined by the Ideal (x, y, z) + of Multivariate Polynomial Ring in x, y, z over Rational Field This indicates the fix of :trac:`12734`:: @@ -990,7 +993,8 @@ def __call__(self, *args): sage: R = S.coordinate_ring() sage: S(R.ideal(0)) - Point on Affine Space of dimension 1 over Integer Ring defined by the Ideal (0) of Multivariate Polynomial Ring in x over Integer Ring + Point on Affine Space of dimension 1 over Integer Ring + defined by the Ideal (0) of Multivariate Polynomial Ring in x over Integer Ring This explains why the following example raises an error rather than constructing the topological point defined by the prime @@ -1201,14 +1205,13 @@ def hom(self, x, Y=None): We can construct a morphism to an affine curve (:trac:`7956`):: sage: S.<p,q> = QQ[] - sage: A1.<r> = AffineSpace(QQ,1) - sage: A1_emb = Curve(p-2) - sage: A1.hom([2,r],A1_emb) + sage: A1.<r> = AffineSpace(QQ, 1) + sage: A1_emb = Curve(p - 2) # needs sage.schemes + sage: A1.hom([2, r], A1_emb) # needs sage.schemes Scheme morphism: From: Affine Space of dimension 1 over Rational Field To: Affine Plane Curve over Rational Field defined by p - 2 - Defn: Defined on coordinates by sending (r) to - (2, r) + Defn: Defined on coordinates by sending (r) to (2, r) """ from sage.categories.map import Map from sage.categories.rings import Rings diff --git a/src/sage/schemes/generic/spec.py b/src/sage/schemes/generic/spec.py index 261bb899d68..c9a07313bb3 100644 --- a/src/sage/schemes/generic/spec.py +++ b/src/sage/schemes/generic/spec.py @@ -42,9 +42,10 @@ def Spec(R, S=None): Spectrum of Univariate Polynomial Ring in x over Rational Field sage: Spec(PolynomialRing(QQ, 'x', 3)) Spectrum of Multivariate Polynomial Ring in x0, x1, x2 over Rational Field - sage: X = Spec(PolynomialRing(GF(49,'a'), 3, 'x')); X - Spectrum of Multivariate Polynomial Ring in x0, x1, x2 over Finite Field in a of size 7^2 - sage: TestSuite(X).run() + sage: X = Spec(PolynomialRing(GF(49,'a'), 3, 'x')); X # needs sage.rings.finite_rings + Spectrum of Multivariate Polynomial Ring in x0, x1, x2 + over Finite Field in a of size 7^2 + sage: TestSuite(X).run() # needs sage.rings.finite_rings Applying ``Spec`` twice to the same ring gives identical output (see :trac:`17008`):: @@ -59,10 +60,11 @@ def Spec(R, S=None): Traceback (most recent call last): ... TypeError: x (=5) is not in Category of commutative rings - sage: Spec(FreeAlgebra(QQ,2, 'x')) + sage: Spec(FreeAlgebra(QQ, 2, 'x')) # needs sage.combinat sage.modules Traceback (most recent call last): ... - TypeError: x (=Free Algebra on 2 generators (x0, x1) over Rational Field) is not in Category of commutative rings + TypeError: x (=Free Algebra on 2 generators (x0, x1) over Rational Field) + is not in Category of commutative rings TESTS:: @@ -75,9 +77,9 @@ def Spec(R, S=None): Integer Ring sage: X.dimension() 1 - sage: Spec(QQ,QQ).base_scheme() + sage: Spec(QQ, QQ).base_scheme() Spectrum of Rational Field - sage: Spec(RDF,QQ).base_scheme() + sage: Spec(RDF, QQ).base_scheme() Spectrum of Rational Field """ return SpecFunctor(S)(R) @@ -98,7 +100,8 @@ def __init__(self, base_ring=None): Spec functor from Category of commutative rings to Category of schemes over Rational Field """ - from sage.categories.all import CommutativeRings, Schemes + from sage.categories.commutative_rings import CommutativeRings + from sage.categories.schemes import Schemes if base_ring is None: domain = CommutativeRings() @@ -149,7 +152,7 @@ def _apply_functor(self, A): sage: from sage.schemes.generic.spec import SpecFunctor sage: F = SpecFunctor() - sage: F(RR) # indirect doctest + sage: F(RR) # indirect doctest # needs sage.rings.real_mpfr Spectrum of Real Field with 53 bits of precision """ # The second argument of AffineScheme defaults to None. @@ -171,7 +174,7 @@ def _apply_functor_to_morphism(self, f): sage: A.<x, y> = GF(7)[] sage: B.<t> = GF(7)[] sage: f = A.hom((t^2, t^3)) - sage: Spec(f) # indirect doctest + sage: Spec(f) # indirect doctest Affine Scheme morphism: From: Spectrum of Univariate Polynomial Ring in t over Finite Field of size 7 To: Spectrum of Multivariate Polynomial Ring in x, y over Finite Field of size 7 diff --git a/src/sage/schemes/hyperelliptic_curves/__init__.py b/src/sage/schemes/hyperelliptic_curves/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/hyperelliptic_curves/constructor.py b/src/sage/schemes/hyperelliptic_curves/constructor.py index 54556e08755..de93cc7e371 100644 --- a/src/sage/schemes/hyperelliptic_curves/constructor.py +++ b/src/sage/schemes/hyperelliptic_curves/constructor.py @@ -23,10 +23,10 @@ from .hyperelliptic_g2 import HyperellipticCurve_g2 import sage.rings.abc -from sage.rings.rational_field import is_RationalField -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.finite_rings.finite_field_base import FiniteField +from sage.rings.polynomial.polynomial_element import Polynomial +from sage.rings.rational_field import is_RationalField from sage.structure.dynamic_class import dynamic_class @@ -71,51 +71,55 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): sage: R.<x> = QQ[] sage: HyperellipticCurve(x^5 + x + 1) Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x + 1 - sage: HyperellipticCurve(x^19 + x + 1, x-2) + sage: HyperellipticCurve(x^19 + x + 1, x - 2) Hyperelliptic Curve over Rational Field defined by y^2 + (x - 2)*y = x^19 + x + 1 - sage: k.<a> = GF(9); R.<x> = k[] - sage: HyperellipticCurve(x^3 + x - 1, x+a) - Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 + (x + a)*y = x^3 + x + 2 + sage: k.<a> = GF(9); R.<x> = k[] # needs sage.rings.finite_rings + sage: HyperellipticCurve(x^3 + x - 1, x+a) # needs sage.rings.finite_rings + Hyperelliptic Curve over Finite Field in a of size 3^2 + defined by y^2 + (x + a)*y = x^3 + x + 2 Characteristic two:: - sage: P.<x> = GF(8,'a')[] - sage: HyperellipticCurve(x^7+1, x) - Hyperelliptic Curve over Finite Field in a of size 2^3 defined by y^2 + x*y = x^7 + 1 - sage: HyperellipticCurve(x^8+x^7+1, x^4+1) - Hyperelliptic Curve over Finite Field in a of size 2^3 defined by y^2 + (x^4 + 1)*y = x^8 + x^7 + 1 - - sage: HyperellipticCurve(x^8+1, x) + sage: # needs sage.rings.finite_rings + sage: P.<x> = GF(8, 'a')[] + sage: HyperellipticCurve(x^7 + 1, x) + Hyperelliptic Curve over Finite Field in a of size 2^3 + defined by y^2 + x*y = x^7 + 1 + sage: HyperellipticCurve(x^8 + x^7 + 1, x^4 + 1) + Hyperelliptic Curve over Finite Field in a of size 2^3 + defined by y^2 + (x^4 + 1)*y = x^8 + x^7 + 1 + sage: HyperellipticCurve(x^8 + 1, x) Traceback (most recent call last): ... ValueError: Not a hyperelliptic curve: highly singular at infinity. - - sage: HyperellipticCurve(x^8+x^7+1, x^4) + sage: HyperellipticCurve(x^8 + x^7 + 1, x^4) Traceback (most recent call last): ... ValueError: Not a hyperelliptic curve: singularity in the provided affine patch. sage: F.<t> = PowerSeriesRing(FiniteField(2)) sage: P.<x> = PolynomialRing(FractionField(F)) - sage: HyperellipticCurve(x^5+t, x) - Hyperelliptic Curve over Laurent Series Ring in t over Finite Field of size 2 defined by y^2 + x*y = x^5 + t + sage: HyperellipticCurve(x^5 + t, x) + Hyperelliptic Curve over Laurent Series Ring in t over Finite Field of size 2 + defined by y^2 + x*y = x^5 + t We can change the names of the variables in the output:: - sage: k.<a> = GF(9); R.<x> = k[] - sage: HyperellipticCurve(x^3 + x - 1, x+a, names=['X','Y']) - Hyperelliptic Curve over Finite Field in a of size 3^2 defined by Y^2 + (X + a)*Y = X^3 + X + 2 + sage: k.<a> = GF(9); R.<x> = k[] # needs sage.rings.finite_rings + sage: HyperellipticCurve(x^3 + x - 1, x + a, names=['X','Y']) # needs sage.rings.finite_rings + Hyperelliptic Curve over Finite Field in a of size 3^2 + defined by Y^2 + (X + a)*Y = X^3 + X + 2 This class also allows curves of genus zero or one, which are strictly speaking not hyperelliptic:: sage: P.<x> = QQ[] - sage: HyperellipticCurve(x^2+1) + sage: HyperellipticCurve(x^2 + 1) Hyperelliptic Curve over Rational Field defined by y^2 = x^2 + 1 - sage: HyperellipticCurve(x^4-1) + sage: HyperellipticCurve(x^4 - 1) Hyperelliptic Curve over Rational Field defined by y^2 = x^4 - 1 - sage: HyperellipticCurve(x^3+2*x+2) + sage: HyperellipticCurve(x^3 + 2*x + 2) Hyperelliptic Curve over Rational Field defined by y^2 = x^3 + 2*x + 2 Double roots:: @@ -127,7 +131,8 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): ValueError: Not a hyperelliptic curve: singularity in the provided affine patch. sage: HyperellipticCurve((x^3-x+2)^2*(x^6-1), check_squarefree=False) - Hyperelliptic Curve over Finite Field of size 7 defined by y^2 = x^12 + 5*x^10 + 4*x^9 + x^8 + 3*x^7 + 3*x^6 + 2*x^4 + 3*x^3 + 6*x^2 + 4*x + 3 + Hyperelliptic Curve over Finite Field of size 7 defined by + y^2 = x^12 + 5*x^10 + 4*x^9 + x^8 + 3*x^7 + 3*x^6 + 2*x^4 + 3*x^3 + 6*x^2 + 4*x + 3 The input for a (smooth) hyperelliptic curve of genus `g` should not contain polynomials of degree greater than `2g+2`. In the following @@ -137,8 +142,8 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): sage: P.<x> = QQ[] sage: h = x^100 - sage: F = x^6+1 - sage: f = F-h^2/4 + sage: F = x^6 + 1 + sage: f = F - h^2/4 sage: HyperellipticCurve(f, h) Traceback (most recent call last): ... @@ -152,7 +157,7 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): sage: F.<t> = GF(5)[] sage: P.<x> = F[] - sage: HyperellipticCurve(x^5+t) + sage: HyperellipticCurve(x^5 + t) Traceback (most recent call last): ... ValueError: Not a hyperelliptic curve: singularity in the provided affine patch. @@ -163,7 +168,7 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): not checked whether the discriminant is a unit in `\ZZ^*`.:: sage: P.<x> = ZZ[] - sage: HyperellipticCurve(3*x^7+6*x+6) + sage: HyperellipticCurve(3*x^7 + 6*x + 6) Hyperelliptic Curve over Integer Ring defined by y^2 = 3*x^7 + 6*x + 6 TESTS: @@ -176,6 +181,7 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): Check that two curves with the same class name have the same class type:: + sage: # needs sage.rings.finite_rings sage: R.<t> = PolynomialRing(GF(next_prime(10^9))) sage: C = HyperellipticCurve(t^5 + t + 1) sage: C2 = HyperellipticCurve(t^5 + 3*t + 1) @@ -184,6 +190,7 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): Check that the inheritance is correct:: + sage: # needs sage.rings.finite_rings sage: R.<t> = PolynomialRing(GF(next_prime(10^9))) sage: C = HyperellipticCurve(t^5 + t + 1) sage: type(C).mro() @@ -197,7 +204,7 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): # F is the discriminant; use this for the type check # rather than f and h, one of which might be constant. F = h**2 + 4*f - if not is_Polynomial(F): + if not isinstance(F, Polynomial): raise TypeError("Arguments f (= %s) and h (= %s) must be polynomials" % (f, h)) P = F.parent() f = P(f) @@ -249,7 +256,11 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): genus_classes = {2: HyperellipticCurve_g2} - is_pAdicField = lambda x: isinstance(x, sage.rings.abc.pAdicField) + def is_FiniteField(x): + return isinstance(x, FiniteField) + + def is_pAdicField(x): + return isinstance(x, sage.rings.abc.pAdicField) fields = [ ("FiniteField", is_FiniteField, HyperellipticCurve_finite_field), diff --git a/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx b/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx index c08bb3cfb53..50730d1081f 100644 --- a/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx +++ b/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx @@ -38,8 +38,9 @@ from libcpp.vector cimport vector from sage.libs.ntl.ntl_ZZ_pContext import ZZ_pContext_factory from sage.libs.ntl.all import ZZ, ZZX from sage.matrix.constructor import Matrix -from sage.rings.all import Qp, O as big_oh -from sage.arith.all import is_prime +from sage.rings.padics.factory import Qp +from sage.rings.big_oh import O as big_oh +from sage.arith.misc import is_prime from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py index 9f9227cbcf3..a4cabb5bb93 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Hyperelliptic curves over a finite field @@ -7,7 +8,8 @@ sage: x = polygen(K) sage: C = HyperellipticCurve(x^7 - x^5 - 2, x^2 + a) sage: C._points_fast_sqrt() - [(0 : 1 : 0), (a + 1 : a : 1), (a + 1 : a + 1 : 1), (2 : a + 1 : 1), (2*a : 2*a + 2 : 1), (2*a : 2*a : 1), (1 : a + 1 : 1)] + [(0 : 1 : 0), (a + 1 : a : 1), (a + 1 : a + 1 : 1), (2 : a + 1 : 1), + (2*a : 2*a + 2 : 1), (2*a : 2*a : 1), (1 : a + 1 : 1)] AUTHORS: @@ -48,8 +50,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ, RR, QQ, GF -from sage.arith.all import binomial +from sage.rings.integer_ring import ZZ +from sage.rings.real_mpfr import RR +from sage.rings.rational_field import QQ +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.arith.misc import binomial from sage.rings.power_series_ring import PowerSeriesRing from . import hyperelliptic_generic from sage.schemes.hyperelliptic_curves.hypellfrob import hypellfrob @@ -201,7 +206,8 @@ def frobenius_matrix_hypellfrob(self, N=None): sage: H.frobenius_matrix_hypellfrob() Traceback (most recent call last): ... - NotImplementedError: Computation of Frobenius matrix only implemented for hyperelliptic curves defined over prime fields. + NotImplementedError: Computation of Frobenius matrix only implemented + for hyperelliptic curves defined over prime fields. nor too small characteristic:: @@ -276,7 +282,8 @@ def frobenius_matrix(self, N=None, algorithm='hypellfrob'): sage: H.frobenius_matrix(algorithm='hypellfrob') Traceback (most recent call last): ... - NotImplementedError: Computation of Frobenius matrix only implemented for hyperelliptic curves defined over prime fields. + NotImplementedError: Computation of Frobenius matrix only implemented + for hyperelliptic curves defined over prime fields. nor too small characteristic:: @@ -330,7 +337,7 @@ def frobenius_polynomial_cardinalities(self, a=None): sage: H.frobenius_polynomial_cardinalities() x^4 + 8*x^3 + 70*x^2 + 392*x + 2401 - This method may actually be useful when `hypellfrob` does not work:: + This method may actually be useful when ``hypellfrob`` does not work:: sage: K = GF(7) sage: R.<t> = PolynomialRing(K) @@ -391,10 +398,15 @@ def frobenius_polynomial_matrix(self, M=None, algorithm='hypellfrob'): sage: R.<t> = PolynomialRing(K) sage: H = HyperellipticCurve(t^9 + t^5 + 1) sage: H.frobenius_polynomial_matrix() - x^8 + 281*x^7 + 55939*x^6 + 14144175*x^5 + 3156455369*x^4 + 707194605825*x^3 + 139841906155939*x^2 + 35122892542149719*x + 6249500014999800001 + x^8 + 281*x^7 + 55939*x^6 + 14144175*x^5 + 3156455369*x^4 + 707194605825*x^3 + + 139841906155939*x^2 + 35122892542149719*x + 6249500014999800001 sage: H = HyperellipticCurve(t^15 + t^5 + 1) - sage: H.frobenius_polynomial_matrix() # long time, 8s on a Corei7 - x^14 - 76*x^13 + 220846*x^12 - 12984372*x^11 + 24374326657*x^10 - 1203243210304*x^9 + 1770558798515792*x^8 - 74401511415210496*x^7 + 88526169366991084208*x^6 - 3007987702642212810304*x^5 + 3046608028331197124223343*x^4 - 81145833008762983138584372*x^3 + 69007473838551978905211279154*x^2 - 1187357507124810002849977200076*x + 781140631562281254374947500349999 + sage: H.frobenius_polynomial_matrix() # long time, 8s on a Corei7 + x^14 - 76*x^13 + 220846*x^12 - 12984372*x^11 + 24374326657*x^10 - 1203243210304*x^9 + + 1770558798515792*x^8 - 74401511415210496*x^7 + 88526169366991084208*x^6 + - 3007987702642212810304*x^5 + 3046608028331197124223343*x^4 + - 81145833008762983138584372*x^3 + 69007473838551978905211279154*x^2 + - 1187357507124810002849977200076*x + 781140631562281254374947500349999 This ``hypellfrob`` program doesn't support non-prime fields:: @@ -404,7 +416,8 @@ def frobenius_polynomial_matrix(self, M=None, algorithm='hypellfrob'): sage: H.frobenius_polynomial_matrix(algorithm='hypellfrob') Traceback (most recent call last): ... - NotImplementedError: Computation of Frobenius matrix only implemented for hyperelliptic curves defined over prime fields. + NotImplementedError: Computation of Frobenius matrix only implemented + for hyperelliptic curves defined over prime fields. """ K = self.base_ring() p = K.characteristic() @@ -591,7 +604,8 @@ def _points_fast_sqrt(self): sage: x = polygen(K) sage: C = HyperellipticCurve(x^7 - 1, x^2 + a) sage: C._points_fast_sqrt() - [(0 : 1 : 0), (a : 2*a + 1 : 1), (2 : a + 1 : 1), (2*a + 2 : 2*a : 1), (2*a + 2 : 1 : 1), (1 : 2*a + 2 : 1), (1 : 0 : 1)] + [(0 : 1 : 0), (a : 2*a + 1 : 1), (2 : a + 1 : 1), (2*a + 2 : 2*a : 1), + (2*a + 2 : 1 : 1), (1 : 2*a + 2 : 1), (1 : 0 : 1)] sage: K.<a> = GF(49, 'a') sage: x = polygen(K) sage: C = HyperellipticCurve(x^5 - x^2 - 1, x^2 + a) @@ -611,7 +625,10 @@ def _points_fast_sqrt(self): sage: x = polygen(GF(13)) sage: C = HyperellipticCurve(x^3 + x^2 - 1) sage: C._points_fast_sqrt() - [(0 : 1 : 0), (0 : 5 : 1), (0 : 8 : 1), (1 : 1 : 1), (1 : 12 : 1), (3 : 3 : 1), (3 : 10 : 1), (4 : 1 : 1), (4 : 12 : 1), (6 : 2 : 1), (6 : 11 : 1), (7 : 1 : 1), (7 : 12 : 1), (8 : 4 : 1), (8 : 9 : 1), (9 : 4 : 1), (9 : 9 : 1), (12 : 5 : 1), (12 : 8 : 1)] + [(0 : 1 : 0), (0 : 5 : 1), (0 : 8 : 1), (1 : 1 : 1), (1 : 12 : 1), + (3 : 3 : 1), (3 : 10 : 1), (4 : 1 : 1), (4 : 12 : 1), (6 : 2 : 1), + (6 : 11 : 1), (7 : 1 : 1), (7 : 12 : 1), (8 : 4 : 1), (8 : 9 : 1), + (9 : 4 : 1), (9 : 9 : 1), (12 : 5 : 1), (12 : 8 : 1)] sage: set(C._points_fast_sqrt()) == set(C._points_cache_sqrt()) True """ @@ -627,7 +644,7 @@ def _points_fast_sqrt(self): # (0:1:0) is a point on the curve points = [self.point([K(0), K(1), K(0)], check=True)] else: - points=[] + points = [] if P.degree() > 2: # P(1, y, 0) = r*y + s s = P(K(1), K(0), K(0)) @@ -638,7 +655,7 @@ def _points_fast_sqrt(self): elif K.characteristic() == 2: # deg(P) = 2 and char(K) = 2 # quadratic equation doesn't work in characteristic 2 so use brute # force - points += [self.point([K(1), y, K(0)], check=True) for y in K \ + points += [self.point([K(1), y, K(0)], check=True) for y in K if not P(K(1), y, K(0))] else: # deg(P) = 2 and char(K) not 2 # P(1, y, 0) = y^2 + r*y + s @@ -711,7 +728,8 @@ def _points_cache_sqrt(self, brute_force=False): sage: x = polygen(GF(7)) sage: C = HyperellipticCurve(x^3 + x^2 - 1) sage: C._points_cache_sqrt() - [(0 : 1 : 0), (1 : 6 : 1), (1 : 1 : 1), (2 : 5 : 1), (2 : 2 : 1), (3 : 0 : 1), (4 : 4 : 1), (4 : 3 : 1), (5 : 4 : 1), (5 : 3 : 1)] + [(0 : 1 : 0), (1 : 6 : 1), (1 : 1 : 1), (2 : 5 : 1), (2 : 2 : 1), + (3 : 0 : 1), (4 : 4 : 1), (4 : 3 : 1), (5 : 4 : 1), (5 : 3 : 1)] sage: set(C._points_cache_sqrt()) == set(C._points_cache_sqrt(brute_force=True)) True """ @@ -730,7 +748,7 @@ def _points_cache_sqrt(self, brute_force=False): # (0:1:0) is a point on the curve points = [self.point([K(0), K(1), K(0)], check=True)] else: - points=[] + points = [] if P.degree() > 2: # P(1, y, 0) = r*y + s s = P(K(1), K(0), K(0)) @@ -741,7 +759,7 @@ def _points_cache_sqrt(self, brute_force=False): elif K.characteristic() == 2: # deg(P) = 2 and char(K) = 2 # quadratic equation doesn't work in characteristic 2 so use brute # force - points += [self.point([K(1), y, K(0)], check=True) for y in K \ + points += [self.point([K(1), y, K(0)], check=True) for y in K if not P(K(1), y, K(0))] else: # deg(P) = 2 and char(K) not 2 # P(1, y, 0) = y^2 + r*y + s @@ -793,7 +811,8 @@ def points(self): sage: x = polygen(GF(7)) sage: C = HyperellipticCurve(x^7 - x^2 - 1) sage: C.points() - [(0 : 1 : 0), (2 : 5 : 1), (2 : 2 : 1), (3 : 0 : 1), (4 : 6 : 1), (4 : 1 : 1), (5 : 0 : 1), (6 : 5 : 1), (6 : 2 : 1)] + [(0 : 1 : 0), (2 : 5 : 1), (2 : 2 : 1), (3 : 0 : 1), (4 : 6 : 1), + (4 : 1 : 1), (5 : 0 : 1), (6 : 5 : 1), (6 : 2 : 1)] :: @@ -808,7 +827,8 @@ def points(self): sage: R.<x> = GF(7)[] sage: H = HyperellipticCurve(3*x^2 + 5*x + 1) sage: H.points() - [(0 : 6 : 1), (0 : 1 : 1), (1 : 4 : 1), (1 : 3 : 1), (2 : 4 : 1), (2 : 3 : 1), (3 : 6 : 1), (3 : 1 : 1)] + [(0 : 6 : 1), (0 : 1 : 1), (1 : 4 : 1), (1 : 3 : 1), (2 : 4 : 1), + (2 : 3 : 1), (3 : 6 : 1), (3 : 1 : 1)] The method currently lists points on the plane projective model, that is the closure in `\mathbb{P}^2` of the curve defined by `y^2+hy=f`. @@ -824,7 +844,8 @@ def points(self): sage: R.<x>=GF(11)[] sage: H = HyperellipticCurve(x*(x+1)*(x+2)*(x+3)*(x+4)*(x+5)) sage: H.points() - [(0 : 1 : 0), (0 : 0 : 1), (1 : 7 : 1), (1 : 4 : 1), (5 : 7 : 1), (5 : 4 : 1), (6 : 0 : 1), (7 : 0 : 1), (8 : 0 : 1), (9 : 0 : 1), (10 : 0 : 1)] + [(0 : 1 : 0), (0 : 0 : 1), (1 : 7 : 1), (1 : 4 : 1), (5 : 7 : 1), (5 : 4 : 1), + (6 : 0 : 1), (7 : 0 : 1), (8 : 0 : 1), (9 : 0 : 1), (10 : 0 : 1)] The plane model of the genus 2 hyperelliptic curve in the above example is the curve in `\mathbb{P}^2` defined by `y^2z^4=g(x,z)` where @@ -1088,7 +1109,7 @@ def count_points_hypellfrob(self, n=1, N=None, algorithm=None): raise ValueError("Unknown algorithm") if p <= (2*g+1)*(2*N-1): - raise ValueError("p=%d should be greater than (2*g+1)(2*N-1)=%d"%(p,(2*g+1)*(2*N-1))) + raise ValueError("p=%d should be greater than (2*g+1)(2*N-1)=%d" % (p,(2*g+1)*(2*N-1))) if algorithm == 'traces': M = self.frobenius_matrix(N=N, algorithm='hypellfrob') @@ -1514,16 +1535,16 @@ def _Cartier_matrix_cached(self): #retrieve the function f(x) ,where y^2=f(x) f,h = self.hyperelliptic_polynomials() #This implementation only deals with h=0 - if h!=0: + if h != 0: raise ValueError("E must be of the form y^2 = f(x)") d = f.degree() #this implementation is for odd degree only, even degree will be handled later. - if d%2 == 0: + if d % 2 == 0: raise ValueError("In this implementation the degree of f must be odd") #Compute resultant to make sure no repeated roots - df=f.derivative() - R=df.resultant(f) + df = f.derivative() + R = df.resultant(f) if R == 0: raise ValueError("curve is not smooth") @@ -1545,9 +1566,9 @@ def _Cartier_matrix_cached(self): # compute each row of matrix as list and then M=list of lists(rows) - M=[] + M = [] for j in range(1,g+1): - H=[Coeff[i] for i in range((p*j-1), (p*j-g-1),-1)] + H = [Coeff[i] for i in range((p*j-1), (p*j-g-1),-1)] M.append(H) return matrix(Fq,M), Coeff, g, Fq,p, self @@ -1568,21 +1589,21 @@ def Cartier_matrix(self): EXAMPLES:: - sage: K.<x>=GF(9,'x')[] - sage: C=HyperellipticCurve(x^7-1,0) + sage: K.<x> = GF(9,'x')[] + sage: C = HyperellipticCurve(x^7 - 1, 0) sage: C.Cartier_matrix() [0 0 2] [0 0 0] [0 1 0] - sage: K.<x>=GF(49,'x')[] - sage: C=HyperellipticCurve(x^5+1,0) + sage: K.<x> = GF(49, 'x')[] + sage: C = HyperellipticCurve(x^5 + 1, 0) sage: C.Cartier_matrix() [0 3] [0 0] - sage: P.<x>=GF(9,'a')[] - sage: E=HyperellipticCurve(x^29+1,0) + sage: P.<x> = GF(9, 'a')[] + sage: E = HyperellipticCurve(x^29 + 1, 0) sage: E.Cartier_matrix() [0 0 1 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0 0 0 0] @@ -1636,10 +1657,10 @@ def Cartier_matrix(self): # Github Issue #11115: Why shall we waste time by studying # the cache manually? We only need to check whether the cached # data belong to self. - M, Coeffs,g, Fq, p, E= self._Cartier_matrix_cached() - if E!=self: + M, Coeffs,g, Fq, p, E = self._Cartier_matrix_cached() + if E != self: self._Cartier_matrix_cached.clear_cache() - M, Coeffs,g, Fq, p, E= self._Cartier_matrix_cached() + M, Coeffs,g, Fq, p, E = self._Cartier_matrix_cached() return M @cached_method @@ -1766,21 +1787,21 @@ def Hasse_Witt(self): EXAMPLES:: - sage: K.<x>=GF(9,'x')[] - sage: C=HyperellipticCurve(x^7-1,0) + sage: K.<x> = GF(9, 'x')[] + sage: C = HyperellipticCurve(x^7 - 1, 0) sage: C.Hasse_Witt() [0 0 0] [0 0 0] [0 0 0] - sage: K.<x>=GF(49,'x')[] - sage: C=HyperellipticCurve(x^5+1,0) + sage: K.<x> = GF(49, 'x')[] + sage: C = HyperellipticCurve(x^5 + 1, 0) sage: C.Hasse_Witt() [0 0] [0 0] - sage: P.<x>=GF(9,'a')[] - sage: E=HyperellipticCurve(x^29+1,0) + sage: P.<x> = GF(9, 'a')[] + sage: E = HyperellipticCurve(x^29 + 1, 0) sage: E.Hasse_Witt() [0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0] @@ -1803,10 +1824,10 @@ def Hasse_Witt(self): # from the cache - but apparently it could be # that the cached value does not belong to self. # So, the easiest is: - N, E= self._Hasse_Witt_cached() - if E!=self: + N, E = self._Hasse_Witt_cached() + if E != self: self._Hasse_Witt_cached.clear_cache() - N, E= self._Hasse_Witt_cached() + N, E = self._Hasse_Witt_cached() return N def a_number(self): @@ -1820,20 +1841,20 @@ def a_number(self): - ``a`` : a-number - EXAMPLES:: + EXAMPLES:: - sage: K.<x>=GF(49,'x')[] - sage: C=HyperellipticCurve(x^5+1,0) + sage: K.<x> = GF(49, 'x')[] + sage: C = HyperellipticCurve(x^5 + 1, 0) sage: C.a_number() 1 - sage: K.<x>=GF(9,'x')[] - sage: C=HyperellipticCurve(x^7-1,0) + sage: K.<x> = GF(9, 'x')[] + sage: C = HyperellipticCurve(x^7 - 1, 0) sage: C.a_number() 1 - sage: P.<x>=GF(9,'a')[] - sage: E=HyperellipticCurve(x^29+1,0) + sage: P.<x> = GF(9, 'a')[] + sage: E = HyperellipticCurve(x^29 + 1, 0) sage: E.a_number() 5 """ @@ -1845,10 +1866,10 @@ def a_number(self): # Since Github Issue #11115, there is a special cache for methods # that don't accept arguments. The easiest is: Call the cached # method, and test whether the last entry is self. - M,Coeffs,g, Fq, p,E= self._Cartier_matrix_cached() + M,Coeffs,g, Fq, p,E = self._Cartier_matrix_cached() if E != self: self._Cartier_matrix_cached.clear_cache() - M,Coeffs,g, Fq, p,E= self._Cartier_matrix_cached() + M,Coeffs,g, Fq, p,E = self._Cartier_matrix_cached() return g - rank(M) def p_rank(self): @@ -1864,18 +1885,18 @@ def p_rank(self): EXAMPLES:: - sage: K.<x>=GF(49,'x')[] - sage: C=HyperellipticCurve(x^5+1,0) + sage: K.<x> = GF(49, 'x')[] + sage: C = HyperellipticCurve(x^5 + 1, 0) sage: C.p_rank() 0 - sage: K.<x>=GF(9,'x')[] - sage: C=HyperellipticCurve(x^7-1,0) + sage: K.<x> = GF(9, 'x')[] + sage: C = HyperellipticCurve(x^7 - 1, 0) sage: C.p_rank() 0 - sage: P.<x>=GF(9,'a')[] - sage: E=HyperellipticCurve(x^29+1,0) + sage: P.<x> = GF(9, 'a')[] + sage: E = HyperellipticCurve(x^29 + 1, 0) sage: E.p_rank() 0 """ diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py index 19d767ea2f3..7a8fe986448 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py @@ -27,7 +27,7 @@ def is_odd_degree(self): f, h = self.hyperelliptic_polynomials() df = f.degree() if h.degree() < 3: - return df%2 == 1 + return df % 2 == 1 elif df < 6: return False else: @@ -95,13 +95,14 @@ def clebsch_invariants(self): TESTS:: - sage: magma(HyperellipticCurve(f)).ClebschInvariants() # optional - magma + sage: # optional - magma + sage: magma(HyperellipticCurve(f)).ClebschInvariants() [ 0, -2048/375, -4096/25, -4881645568/84375 ] - sage: magma(HyperellipticCurve(f(2*x))).ClebschInvariants() # optional - magma + sage: magma(HyperellipticCurve(f(2*x))).ClebschInvariants() [ 0, -8388608/375, -1073741824/25, -5241627016305836032/84375 ] - sage: magma(HyperellipticCurve(f, x)).ClebschInvariants() # optional - magma + sage: magma(HyperellipticCurve(f, x)).ClebschInvariants() [ -8/15, 17504/5625, -23162896/140625, -420832861216768/7119140625 ] - sage: magma(HyperellipticCurve(f(2*x), 2*x)).ClebschInvariants() # optional - magma + sage: magma(HyperellipticCurve(f(2*x), 2*x)).ClebschInvariants() [ -512/15, 71696384/5625, -6072014209024/140625, -451865844002031331704832/7119140625 ] """ f, h = self.hyperelliptic_polynomials() @@ -131,13 +132,14 @@ def igusa_clebsch_invariants(self): TESTS:: - sage: magma(HyperellipticCurve(f)).IgusaClebschInvariants() # optional - magma + sage: # optional - magma + sage: magma(HyperellipticCurve(f)).IgusaClebschInvariants() [ -640, -20480, 1310720, 52160364544 ] - sage: magma(HyperellipticCurve(f(2*x))).IgusaClebschInvariants() # optional - magma + sage: magma(HyperellipticCurve(f(2*x))).IgusaClebschInvariants() [ -40960, -83886080, 343597383680, 56006764965979488256 ] - sage: magma(HyperellipticCurve(f, x)).IgusaClebschInvariants() # optional - magma + sage: magma(HyperellipticCurve(f, x)).IgusaClebschInvariants() [ -640, 17920, -1966656, 52409511936 ] - sage: magma(HyperellipticCurve(f(2*x), 2*x)).IgusaClebschInvariants() # optional - magma + sage: magma(HyperellipticCurve(f(2*x), 2*x)).IgusaClebschInvariants() [ -40960, 73400320, -515547070464, 56274284941110411264 ] """ f, h = self.hyperelliptic_polynomials() @@ -203,13 +205,14 @@ def clebsch_invariants(self): TESTS:: - sage: magma(HyperellipticCurve(f)).ClebschInvariants() # optional - magma + sage: # optional - magma + sage: magma(HyperellipticCurve(f)).ClebschInvariants() [ 0, -2048/375, -4096/25, -4881645568/84375 ] - sage: magma(HyperellipticCurve(f(2*x))).ClebschInvariants() # optional - magma + sage: magma(HyperellipticCurve(f(2*x))).ClebschInvariants() [ 0, -8388608/375, -1073741824/25, -5241627016305836032/84375 ] - sage: magma(HyperellipticCurve(f, x)).ClebschInvariants() # optional - magma + sage: magma(HyperellipticCurve(f, x)).ClebschInvariants() [ -8/15, 17504/5625, -23162896/140625, -420832861216768/7119140625 ] - sage: magma(HyperellipticCurve(f(2*x), 2*x)).ClebschInvariants() # optional - magma + sage: magma(HyperellipticCurve(f(2*x), 2*x)).ClebschInvariants() [ -512/15, 71696384/5625, -6072014209024/140625, -451865844002031331704832/7119140625 ] """ f, h = self.hyperelliptic_polynomials() diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py index ad3b7d59a53..8c94e32705a 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py @@ -6,7 +6,8 @@ sage: P.<x> = GF(5)[] sage: f = x^5 - 3*x^4 - 2*x^3 + 6*x^2 + 3*x - 1 sage: C = HyperellipticCurve(f); C - Hyperelliptic Curve over Finite Field of size 5 defined by y^2 = x^5 + 2*x^4 + 3*x^3 + x^2 + 3*x + 4 + Hyperelliptic Curve over Finite Field of size 5 + defined by y^2 = x^5 + 2*x^4 + 3*x^3 + x^2 + 3*x + 4 :: @@ -32,7 +33,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.polynomial.all import PolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.big_oh import O from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.laurent_series_ring import LaurentSeriesRing @@ -46,12 +47,13 @@ def is_HyperellipticCurve(C): """ EXAMPLES:: + sage: from sage.schemes.hyperelliptic_curves.hyperelliptic_generic import is_HyperellipticCurve sage: R.<x> = QQ[]; C = HyperellipticCurve(x^3 + x - 1); C Hyperelliptic Curve over Rational Field defined by y^2 = x^3 + x - 1 - sage: sage.schemes.hyperelliptic_curves.hyperelliptic_generic.is_HyperellipticCurve(C) + sage: is_HyperellipticCurve(C) True """ - return isinstance(C,HyperellipticCurve_generic) + return isinstance(C, HyperellipticCurve_generic) class HyperellipticCurve_generic(plane_curve.ProjectivePlaneCurve): @@ -120,28 +122,33 @@ def __init__(self, PP, f, h=None, names=None, genus=None): def change_ring(self, R): """ - Returns this HyperellipticCurve over a new base ring R. + Returns this HyperellipticCurve over a new base ring ``R``. EXAMPLES:: + sage: # needs sage.rings.padics sage: R.<x> = QQ[] sage: H = HyperellipticCurve(x^5 - 10*x + 9) - sage: K = Qp(3,5) - sage: L.<a> = K.extension(x^30-3) + sage: K = Qp(3, 5) + sage: L.<a> = K.extension(x^30 - 3) sage: HK = H.change_ring(K) sage: HL = HK.change_ring(L); HL - Hyperelliptic Curve over 3-adic Eisenstein Extension Field in a defined by x^30 - 3 defined by (1 + O(a^150))*y^2 = (1 + O(a^150))*x^5 + (2 + 2*a^30 + a^60 + 2*a^90 + 2*a^120 + O(a^150))*x + a^60 + O(a^210) + Hyperelliptic Curve + over 3-adic Eisenstein Extension Field in a defined by x^30 - 3 + defined by (1 + O(a^150))*y^2 = (1 + O(a^150))*x^5 + + (2 + 2*a^30 + a^60 + 2*a^90 + 2*a^120 + O(a^150))*x + a^60 + O(a^210) sage: R.<x> = FiniteField(7)[] sage: H = HyperellipticCurve(x^8 + x + 5) - sage: H.base_extend(FiniteField(7^2, 'a')) - Hyperelliptic Curve over Finite Field in a of size 7^2 defined by y^2 = x^8 + x + 5 + sage: H.base_extend(FiniteField(7^2, 'a')) # needs sage.rings.finite_rings + Hyperelliptic Curve over Finite Field in a of size 7^2 + defined by y^2 = x^8 + x + 5 """ from .constructor import HyperellipticCurve f, h = self._hyperelliptic_polynomials y = self._printing_ring.variable_name() x = self._printing_ring.base_ring().variable_name() - return HyperellipticCurve(f.change_ring(R), h.change_ring(R), "%s,%s"%(x,y)) + return HyperellipticCurve(f.change_ring(R), h.change_ring(R), "%s,%s" % (x,y)) base_extend = change_ring @@ -192,7 +199,7 @@ def is_singular(self): EXAMPLES:: sage: R.<x> = QQ[] - sage: H = HyperellipticCurve(x^5+1) + sage: H = HyperellipticCurve(x^5 + 1) sage: H.is_singular() False @@ -201,7 +208,7 @@ def is_singular(self): the following example.:: sage: R.<x> = QQ[] - sage: H = HyperellipticCurve(x^5+2) + sage: H = HyperellipticCurve(x^5 + 2) sage: from sage.misc.verbose import set_verbose sage: set_verbose(-1) sage: H.is_singular() @@ -220,7 +227,7 @@ def is_smooth(self): EXAMPLES:: sage: R.<x> = GF(13)[] - sage: H = HyperellipticCurve(x^8+1) + sage: H = HyperellipticCurve(x^8 + 1) sage: H.is_smooth() True @@ -228,8 +235,9 @@ def is_smooth(self): infinity when viewed as a *plane* projective curve. This can be seen in the following example.:: + sage: # needs sage.rings.finite_rings sage: R.<x> = GF(27, 'a')[] - sage: H = HyperellipticCurve(x^10+2) + sage: H = HyperellipticCurve(x^10 + 2) sage: from sage.misc.verbose import set_verbose sage: set_verbose(-1) sage: H.is_smooth() @@ -262,7 +270,7 @@ def lift_x(self, x, all=False): if all: return [] else: - raise ValueError("No point with x-coordinate %s on %s"%(x, self)) + raise ValueError("No point with x-coordinate %s on %s" % (x, self)) def genus(self): return self._genus @@ -285,36 +293,44 @@ def odd_degree_model(self): ... ValueError: No odd degree model exists over field of definition - sage: K2 = QuadraticField(-2, 'a') - sage: Hp2 = H.change_ring(K2).odd_degree_model(); Hp2 - Hyperelliptic Curve over Number Field in a with defining polynomial x^2 + 2 with a = 1.414213562373095?*I defined by y^2 = 6*a*x^5 - 29*x^4 - 20*x^2 + 6*a*x + 1 + sage: K2 = QuadraticField(-2, 'a') # needs sage.rings.number_field + sage: Hp2 = H.change_ring(K2).odd_degree_model(); Hp2 # needs sage.rings.number_field + Hyperelliptic Curve over Number Field in a + with defining polynomial x^2 + 2 with a = 1.414213562373095?*I + defined by y^2 = 6*a*x^5 - 29*x^4 - 20*x^2 + 6*a*x + 1 - sage: K3 = QuadraticField(-3, 'b') - sage: Hp3 = H.change_ring(QuadraticField(-3, 'b')).odd_degree_model(); Hp3 - Hyperelliptic Curve over Number Field in b with defining polynomial x^2 + 3 with b = 1.732050807568878?*I defined by y^2 = -4*b*x^5 - 14*x^4 - 20*b*x^3 - 35*x^2 + 6*b*x + 1 + sage: K3 = QuadraticField(-3, 'b') # needs sage.rings.number_field + sage: Hp3 = H.change_ring(QuadraticField(-3, 'b')).odd_degree_model(); Hp3 # needs sage.rings.number_field + Hyperelliptic Curve over Number Field in b + with defining polynomial x^2 + 3 with b = 1.732050807568878?*I + defined by y^2 = -4*b*x^5 - 14*x^4 - 20*b*x^3 - 35*x^2 + 6*b*x + 1 - Of course, Hp2 and Hp3 are isomorphic over the composite + Of course, ``Hp2`` and ``Hp3`` are isomorphic over the composite extension. One consequence of this is that odd degree models reduced over "different" fields should have the same number of points on their reductions. 43 and 67 split completely in the compositum, so when we reduce we find: + sage: # needs sage.rings.number_field sage: P2 = K2.factor(43)[0][0] sage: P3 = K3.factor(43)[0][0] sage: Hp2.change_ring(K2.residue_field(P2)).frobenius_polynomial() x^4 - 16*x^3 + 134*x^2 - 688*x + 1849 sage: Hp3.change_ring(K3.residue_field(P3)).frobenius_polynomial() x^4 - 16*x^3 + 134*x^2 - 688*x + 1849 - sage: H.change_ring(GF(43)).odd_degree_model().frobenius_polynomial() + + sage: H.change_ring(GF(43)).odd_degree_model().frobenius_polynomial() # needs sage.rings.finite_rings x^4 - 16*x^3 + 134*x^2 - 688*x + 1849 + sage: # needs sage.rings.number_field sage: P2 = K2.factor(67)[0][0] sage: P3 = K3.factor(67)[0][0] sage: Hp2.change_ring(K2.residue_field(P2)).frobenius_polynomial() x^4 - 8*x^3 + 150*x^2 - 536*x + 4489 sage: Hp3.change_ring(K3.residue_field(P3)).frobenius_polynomial() x^4 - 8*x^3 + 150*x^2 - 536*x + 4489 - sage: H.change_ring(GF(67)).odd_degree_model().frobenius_polynomial() + + sage: H.change_ring(GF(67)).odd_degree_model().frobenius_polynomial() # needs sage.rings.finite_rings x^4 - 8*x^3 + 150*x^2 - 536*x + 4489 TESTS:: @@ -339,7 +355,7 @@ def odd_degree_model(self): raise ValueError("No odd degree model exists over field of definition") rt = rts[0] x = f.parent().gen() - fnew = f((x*rt + 1)/x).numerator() # move rt to "infinity" + fnew = f((x * rt + 1) / x).numerator() # move rt to "infinity" from .constructor import HyperellipticCurve return HyperellipticCurve(fnew, 0, names=self._names, PP=self._PP) @@ -372,19 +388,23 @@ def _magma_init_(self, magma): EXAMPLES:: + sage: # optional - magma sage: R.<x> = QQ[]; C = HyperellipticCurve(x^3 + x - 1, x); C - Hyperelliptic Curve over Rational Field defined by y^2 + x*y = x^3 + x - 1 - sage: magma(C) # optional - magma + Hyperelliptic Curve over Rational Field + defined by y^2 + x*y = x^3 + x - 1 + sage: magma(C) Hyperelliptic Curve defined by y^2 + x*y = x^3 + x - 1 over Rational Field - sage: R.<x> = GF(9,'a')[]; C = HyperellipticCurve(x^3 + x - 1, x^10); C - Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 + x^10*y = x^3 + x + 2 - sage: D = magma(C); D # optional - magma + sage: R.<x> = GF(9,'a')[]; C = HyperellipticCurve(x^3 + x - 1, x^10); C # needs sage.rings.finite_rings + Hyperelliptic Curve over Finite Field in a of size 3^2 + defined by y^2 + x^10*y = x^3 + x + 2 + sage: D = magma(C); D # needs sage.rings.finite_rings Hyperelliptic Curve defined by y^2 + (x^10)*y = x^3 + x + 2 over GF(3^2) - sage: D.sage() # optional - magma - Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 + x^10*y = x^3 + x + 2 + sage: D.sage() # needs sage.rings.finite_rings + Hyperelliptic Curve over Finite Field in a of size 3^2 + defined by y^2 + x^10*y = x^3 + x + 2 """ f, h = self._hyperelliptic_polynomials - return 'HyperellipticCurve(%s, %s)'%(f._magma_init_(magma), h._magma_init_(magma)) + return 'HyperellipticCurve(%s, %s)' % (f._magma_init_(magma), h._magma_init_(magma)) def monsky_washnitzer_gens(self): import sage.schemes.hyperelliptic_curves.monsky_washnitzer as monsky_washnitzer @@ -429,15 +449,15 @@ def local_coordinates_at_nonweierstrass(self, P, prec=20, name='t'): EXAMPLES:: sage: R.<x> = QQ['x'] - sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x) - sage: P = H(1,6) - sage: x,y = H.local_coordinates_at_nonweierstrass(P,prec=5) + sage: H = HyperellipticCurve(x^5 - 23*x^3 + 18*x^2 + 40*x) + sage: P = H(1, 6) + sage: x, y = H.local_coordinates_at_nonweierstrass(P, prec=5) sage: x 1 + t + O(t^5) sage: y 6 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5) - sage: Q = H(-2,12) - sage: x,y = H.local_coordinates_at_nonweierstrass(Q,prec=5) + sage: Q = H(-2, 12) + sage: x, y = H.local_coordinates_at_nonweierstrass(Q, prec=5) sage: x -2 + t + O(t^5) sage: y @@ -445,11 +465,11 @@ def local_coordinates_at_nonweierstrass(self, P, prec=20, name='t'): AUTHOR: - - Jennifer Balakrishnan (2007-12) + - Jennifer Balakrishnan (2007-12) """ d = P[1] if d == 0: - raise TypeError("P = %s is a Weierstrass point. Use local_coordinates_at_weierstrass instead!"%P) + raise TypeError("P = %s is a Weierstrass point. Use local_coordinates_at_weierstrass instead!" % P) pol = self.hyperelliptic_polynomials()[0] L = PowerSeriesRing(self.base_ring(), name, default_prec=prec) t = L.gen() @@ -481,7 +501,7 @@ def local_coordinates_at_weierstrass(self, P, prec=20, name='t'): EXAMPLES:: sage: R.<x> = QQ['x'] - sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x) + sage: H = HyperellipticCurve(x^5 - 23*x^3 + 18*x^2 + 40*x) sage: A = H(4, 0) sage: x, y = H.local_coordinates_at_weierstrass(A, prec=7) sage: x @@ -496,18 +516,18 @@ def local_coordinates_at_weierstrass(self, P, prec=20, name='t'): t + O(t^5) AUTHOR: - - Jennifer Balakrishnan (2007-12) + - Jennifer Balakrishnan (2007-12) - Francis Clarke (2012-08-26) """ if P[1] != 0: - raise TypeError("P = %s is not a finite Weierstrass point. Use local_coordinates_at_nonweierstrass instead!"%P) + raise TypeError("P = %s is not a finite Weierstrass point. Use local_coordinates_at_nonweierstrass instead!" % P) L = PowerSeriesRing(self.base_ring(), name) t = L.gen() pol = self.hyperelliptic_polynomials()[0] pol_prime = pol.derivative() b = P[0] - t2 = t**2 + t2 = t**2 c = b + t2/pol_prime(b) c = c.add_bigoh(prec) for _ in range(int(1 + log(prec, 2))): @@ -533,8 +553,8 @@ def local_coordinates_at_infinity(self, prec=20, name='t'): EXAMPLES:: sage: R.<x> = QQ['x'] - sage: H = HyperellipticCurve(x^5-5*x^2+1) - sage: x,y = H.local_coordinates_at_infinity(10) + sage: H = HyperellipticCurve(x^5 - 5*x^2 + 1) + sage: x, y = H.local_coordinates_at_infinity(10) sage: x t^-2 + 5*t^4 - t^8 - 50*t^10 + O(t^12) sage: y @@ -543,8 +563,8 @@ def local_coordinates_at_infinity(self, prec=20, name='t'): :: sage: R.<x> = QQ['x'] - sage: H = HyperellipticCurve(x^3-x+1) - sage: x,y = H.local_coordinates_at_infinity(10) + sage: H = HyperellipticCurve(x^3 - x + 1) + sage: x, y = H.local_coordinates_at_infinity(10) sage: x t^-2 + t^2 - t^4 - t^6 + 3*t^8 + O(t^12) sage: y @@ -587,16 +607,18 @@ def local_coord(self, P, prec=20, name='t'): EXAMPLES:: sage: R.<x> = QQ['x'] - sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x) + sage: H = HyperellipticCurve(x^5 - 23*x^3 + 18*x^2 + 40*x) sage: H.local_coord(H(1 ,6), prec=5) (1 + t + O(t^5), 6 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5)) sage: H.local_coord(H(4, 0), prec=7) (4 + 1/360*t^2 - 191/23328000*t^4 + 7579/188956800000*t^6 + O(t^7), t + O(t^7)) sage: H.local_coord(H(0, 1, 0), prec=5) - (t^-2 + 23*t^2 - 18*t^4 - 569*t^6 + O(t^7), t^-5 + 46*t^-1 - 36*t - 609*t^3 + 1656*t^5 + O(t^6)) + (t^-2 + 23*t^2 - 18*t^4 - 569*t^6 + O(t^7), + t^-5 + 46*t^-1 - 36*t - 609*t^3 + 1656*t^5 + O(t^6)) AUTHOR: - - Jennifer Balakrishnan (2007-12) + + - Jennifer Balakrishnan (2007-12) """ if P[1] == 0: return self.local_coordinates_at_weierstrass(P, prec, name) @@ -605,8 +627,6 @@ def local_coord(self, P, prec=20, name='t'): else: return self.local_coordinates_at_nonweierstrass(P, prec, name) - - def rational_points(self, **kwds): r""" Find rational points on the hyperelliptic curve, all arguments are passed @@ -614,9 +634,10 @@ def rational_points(self, **kwds): EXAMPLES: - For the LMFDB genus 2 curve `932.a.3728.1 <https://www.lmfdb.org/Genus2Curve/Q/932/a/3728/1>`:: + For the LMFDB genus 2 curve `932.a.3728.1 <https://www.lmfdb.org/Genus2Curve/Q/932/a/3728/1>`_:: - sage: R.<x> = PolynomialRing(QQ); C = HyperellipticCurve(R([0, -1, 1, 0, 1, -2, 1]), R([1])); + sage: R.<x> = PolynomialRing(QQ) + sage: C = HyperellipticCurve(R([0, -1, 1, 0, 1, -2, 1]), R([1])) sage: C.rational_points(bound=8) [(-1 : -3 : 1), (-1 : 2 : 1), @@ -629,9 +650,9 @@ def rational_points(self, **kwds): (1 : 0 : 1)] Check that :trac:`29509` is fixed for the LMFDB genus 2 curve - `169.a.169.1 <https://www.lmfdb.org/Genus2Curve/Q/169/a/169/1>`:: + `169.a.169.1 <https://www.lmfdb.org/Genus2Curve/Q/169/a/169/1>`_:: - sage: C = HyperellipticCurve(R([0, 0, 0, 0, 1, 1]), R([1, 1, 0, 1])); + sage: C = HyperellipticCurve(R([0, 0, 0, 0, 1, 1]), R([1, 1, 0, 1])) sage: C.rational_points(bound=10) [(-1 : 0 : 1), (-1 : 1 : 1), @@ -641,9 +662,9 @@ def rational_points(self, **kwds): An example over a number field:: - sage: R.<x> = PolynomialRing(QuadraticField(2)); - sage: C = HyperellipticCurve(R([1, 0, 0, 0, 0, 1])); - sage: C.rational_points(bound=2) + sage: R.<x> = PolynomialRing(QuadraticField(2)) # needs sage.rings.number_field + sage: C = HyperellipticCurve(R([1, 0, 0, 0, 0, 1])) # needs sage.rings.number_field + sage: C.rational_points(bound=2) # needs sage.rings.number_field [(-1 : 0 : 1), (0 : -1 : 1), (0 : 1 : 0), diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py index a79843c0e99..619619dce30 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.padics """ Hyperelliptic curves over a `p`-adic field """ @@ -12,8 +13,15 @@ # **************************************************************************** -from sage.rings.all import (PowerSeriesRing, PolynomialRing, ZZ, QQ, - pAdicField, GF, RR, RationalField, Infinity) +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.padics.factory import Qp as pAdicField +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.rings.real_mpfr import RR +from sage.rings.rational_field import RationalField +from sage.rings.infinity import Infinity from sage.functions.log import log from sage.modules.free_module import VectorSpace from sage.matrix.constructor import matrix @@ -116,7 +124,7 @@ def local_analytic_interpolation(self, P, Q): """ prec = self.base_ring().precision_cap() if not self.is_same_disc(P,Q): - raise ValueError("%s and %s are not in the same residue disc"%(P,Q)) + raise ValueError("%s and %s are not in the same residue disc" % (P,Q)) disc = self.residue_disc(P) t = PowerSeriesRing(self.base_ring(), 't', prec).gen(0) if disc == self.change_ring(self.base_ring().residue_field())(0,1,0): # Infinite disc @@ -247,7 +255,7 @@ def find_char_zero_weier_point(self, Q): - Jennifer Balakrishnan """ if not self.is_in_weierstrass_disc(Q): - raise ValueError("%s is not in a Weierstrass disc"%Q) + raise ValueError("%s is not in a Weierstrass disc" % Q) points = self.weierstrass_points() for P in points: if self.is_same_disc(P,Q): @@ -291,7 +299,7 @@ def residue_disc(self, P): return HF(0,0,1) if xPv == 0: return HF(P[0].expansion(0), 0,1) - elif yPv ==0: + elif yPv == 0: if xPv > 0: return HF(0, P[1].expansion(0),1) if xPv == 0: @@ -597,7 +605,7 @@ def coleman_integrals_on_basis(self, P, Q, algorithm=None): offset = (2*g-1)*max(TPv, TQv) if offset == +Infinity: offset = (2*g-1)*min(TPv,TQv) - if (offset > prec and (xTPv <0 or xTQv <0) and (self.residue_disc(P) == self.change_ring(GF(p))(0,1,0) or self.residue_disc(Q) == self.change_ring(GF(p))(0,1,0))): + if (offset > prec and (xTPv < 0 or xTQv < 0) and (self.residue_disc(P) == self.change_ring(GF(p))(0,1,0) or self.residue_disc(Q) == self.change_ring(GF(p))(0,1,0))): newprec = offset + prec K = pAdicField(p,newprec) A = PolynomialRing(RationalField(),'x') @@ -664,7 +672,6 @@ def coleman_integrals_on_basis(self, P, Q, algorithm=None): coleman_integrals_on_basis_hyperelliptic = coleman_integrals_on_basis - # def invariant_differential(self): # """ # Returns the invariant differential `dx/2y` on self @@ -926,10 +933,10 @@ def _frob(P): y0 = P[1] try: uN = (1 + h(x0)/y0**(2*p)).sqrt() - yres=y0**p * uN - xres=x0**p + yres = y0**p * uN + xres = x0**p if (yres-y0).valuation() == 0: - yres=-yres + yres = -yres return self.point([xres,yres, K(1)]) except (TypeError, NotImplementedError): uN2 = 1 + h(x0)/y0**(2*p) @@ -938,7 +945,7 @@ def _frob(P): v = uN2.valuation() a = uN2.parent().gen() uN = self.newton_sqrt(uN2,c.sqrt()*a**(v//2),K.precision_cap()) - yres = y0**p *uN + yres = y0**p * uN xres = x0**p if (yres - y0).valuation() == 0: yres = -yres @@ -1106,7 +1113,7 @@ def P_to_S(self, P, S): """ prec = self.base_ring().precision_cap() deg = (S[0]).parent().defining_polynomial().degree() - prec2= prec*deg + prec2 = prec*deg x,y = self.local_coord(P,prec2) g = self.genus() integrals = [((x**k*x.derivative()/(2*y)).integral()) for k in range(2*g)] diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py index 5eab9f7237a..f9337b0fbc0 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py @@ -9,7 +9,7 @@ import sage.rings.abc -from sage.rings.padics.all import pAdicField +from sage.rings.padics.factory import Qp as pAdicField from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_field @@ -27,7 +27,7 @@ def my_chage_ring(self, R): f, h = self._hyperelliptic_polynomials y = self._printing_ring.gen() x = self._printing_ring.base_ring().gen() - return HyperellipticCurve(f.change_ring(R), h, "%s,%s"%(x,y)) + return HyperellipticCurve(f.change_ring(R), h, "%s,%s" % (x,y)) import sage.schemes.hyperelliptic_curves.monsky_washnitzer as monsky_washnitzer if isinstance(p, (sage.rings.abc.pAdicField, sage.rings.abc.pAdicRing)): diff --git a/src/sage/schemes/hyperelliptic_curves/invariants.py b/src/sage/schemes/hyperelliptic_curves/invariants.py index a6952117abc..05bffb5c113 100644 --- a/src/sage/schemes/hyperelliptic_curves/invariants.py +++ b/src/sage/schemes/hyperelliptic_curves/invariants.py @@ -24,14 +24,15 @@ def diffxy(f, x, xtimes, y, ytimes): EXAMPLES:: + sage: from sage.schemes.hyperelliptic_curves.invariants import diffxy sage: R.<u, v> = QQ[] - sage: sage.schemes.hyperelliptic_curves.invariants.diffxy(u^2*v^3, u, 0, v, 0) + sage: diffxy(u^2*v^3, u, 0, v, 0) u^2*v^3 - sage: sage.schemes.hyperelliptic_curves.invariants.diffxy(u^2*v^3, u, 2, v, 1) + sage: diffxy(u^2*v^3, u, 2, v, 1) 6*v^2 - sage: sage.schemes.hyperelliptic_curves.invariants.diffxy(u^2*v^3, u, 2, v, 2) + sage: diffxy(u^2*v^3, u, 2, v, 2) 12*v - sage: sage.schemes.hyperelliptic_curves.invariants.diffxy(u^2*v^3 + u^4*v^4, u, 2, v, 2) + sage: diffxy(u^2*v^3 + u^4*v^4, u, 2, v, 2) 144*u^2*v^2 + 12*v """ h = f @@ -67,7 +68,8 @@ def differential_operator(f, g, k): sage: differential_operator(x^2*y, x*y^2, 2) 1/36*dfdy^2*dgdx^2 - 1/18*dfdx*dfdy*dgdx*dgdy + 1/36*dfdx^2*dgdy^2 sage: differential_operator(x^2*y, x*y^2, 4) - 1/576*dfdy^4*dgdx^4 - 1/144*dfdx*dfdy^3*dgdx^3*dgdy + 1/96*dfdx^2*dfdy^2*dgdx^2*dgdy^2 - 1/144*dfdx^3*dfdy*dgdx*dgdy^3 + 1/576*dfdx^4*dgdy^4 + 1/576*dfdy^4*dgdx^4 - 1/144*dfdx*dfdy^3*dgdx^3*dgdy + 1/96*dfdx^2*dfdy^2*dgdx^2*dgdy^2 + - 1/144*dfdx^3*dfdy*dgdx*dgdy^3 + 1/576*dfdx^4*dgdy^4 """ (x, y) = f.parent().gens() n = max(ZZ(f.degree()), ZZ(k)) @@ -274,9 +276,9 @@ def clebsch_invariants(f): sage: clebsch_invariants(x^6 + x^5 + x^4 + x^2 + 2) (62/15, 15434/5625, -236951/140625, 229930748/791015625) - sage: magma(x^6 + 1).ClebschInvariants() # optional - magma + sage: magma(x^6 + 1).ClebschInvariants() # optional - magma [ 2, 2/3, -2/9, 0 ] - sage: magma(x^6 + x^5 + x^4 + x^2 + 2).ClebschInvariants() # optional - magma + sage: magma(x^6 + x^5 + x^4 + x^2 + 2).ClebschInvariants() # optional - magma [ 62/15, 15434/5625, -236951/140625, 229930748/791015625 ] """ R = f.parent().base_ring() @@ -307,9 +309,9 @@ def igusa_clebsch_invariants(f): sage: igusa_clebsch_invariants(x^6 + x^5 + x^4 + x^2 + 2) (-496, 6220, -955932, -1111784) - sage: magma(x^6 + 1).IgusaClebschInvariants() # optional - magma + sage: magma(x^6 + 1).IgusaClebschInvariants() # optional - magma [ -240, 1620, -119880, -46656 ] - sage: magma(x^6 + x^5 + x^4 + x^2 + 2).IgusaClebschInvariants() # optional - magma + sage: magma(x^6 + x^5 + x^4 + x^2 + 2).IgusaClebschInvariants() # optional - magma [ -496, 6220, -955932, -1111784 ] TESTS: @@ -324,7 +326,8 @@ def igusa_clebsch_invariants(f): sage: absolute_igusa_invariants_wamelen(GF(5)['x'](x^6 - 2*x)) Traceback (most recent call last): ... - NotImplementedError: Invariants of binary sextics/genus 2 hyperelliptic curves not implemented in characteristics 2, 3, and 5 + NotImplementedError: Invariants of binary sextics/genus 2 hyperelliptic curves + not implemented in characteristics 2, 3, and 5 """ return clebsch_to_igusa(*clebsch_invariants(f)) @@ -348,7 +351,8 @@ def absolute_igusa_invariants_wamelen(f): The following example can be checked against van Wamelen's paper:: - sage: i1, i2, i3 = absolute_igusa_invariants_wamelen(-x^5 + 3*x^4 + 2*x^3 - 6*x^2 - 3*x + 1) + sage: h = -x^5 + 3*x^4 + 2*x^3 - 6*x^2 - 3*x + 1 + sage: i1, i2, i3 = absolute_igusa_invariants_wamelen(h) sage: list(map(factor, (i1, i2, i3))) [2^7 * 3^15, 2^5 * 3^11 * 5, 2^4 * 3^9 * 31] @@ -357,7 +361,8 @@ def absolute_igusa_invariants_wamelen(f): sage: absolute_igusa_invariants_wamelen(GF(3)['x'](x^5 - 2*x)) Traceback (most recent call last): ... - NotImplementedError: Invariants of binary sextics/genus 2 hyperelliptic curves not implemented in characteristics 2, 3, and 5 + NotImplementedError: Invariants of binary sextics/genus 2 hyperelliptic curves + not implemented in characteristics 2, 3, and 5 """ I2, I4, I6, I10 = igusa_clebsch_invariants(f) i1 = I2**5/I10 @@ -383,7 +388,8 @@ def absolute_igusa_invariants_kohel(f): The following example can be checked against Kohel's database [KohECHIDNA]_ :: - sage: i1, i2, i3 = absolute_igusa_invariants_kohel(-x^5 + 3*x^4 + 2*x^3 - 6*x^2 - 3*x + 1) + sage: h = -x^5 + 3*x^4 + 2*x^3 - 6*x^2 - 3*x + 1 + sage: i1, i2, i3 = absolute_igusa_invariants_kohel(h) sage: list(map(factor, (i1, i2, i3))) [2^2 * 3^5 * 5 * 31, 2^5 * 3^11 * 5, 2^4 * 3^9 * 31] sage: list(map(factor, (150660, 28343520, 9762768))) @@ -394,7 +400,8 @@ def absolute_igusa_invariants_kohel(f): sage: absolute_igusa_invariants_kohel(GF(2)['x'](x^5 - x)) Traceback (most recent call last): ... - NotImplementedError: Invariants of binary sextics/genus 2 hyperelliptic curves not implemented in characteristics 2, 3, and 5 + NotImplementedError: Invariants of binary sextics/genus 2 hyperelliptic curves + not implemented in characteristics 2, 3, and 5 """ I2, I4, I6, I10 = igusa_clebsch_invariants(f) i1 = I4*I6/I10 diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py b/src/sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py index e75a071657f..8d8d89896db 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py @@ -90,10 +90,14 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import QQ, ZZ, PolynomialRing, FiniteField, NumberField +from sage.rings.rational_field import QQ +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.finite_rings.finite_field_constructor import FiniteField +from sage.rings.number_field.number_field import NumberField from sage.misc.lazy_import import lazy_import from sage.rings.fast_arith import prime_range -from sage.arith.all import gcd +from sage.arith.misc import GCD as gcd lazy_import('sage.interfaces.genus2reduction', ['genus2reduction', 'Genus2reduction']) @@ -118,7 +122,7 @@ def satisfies_coefficient_condition(g, p): return False if g[3]*p != g[1]: return False - if g[2]%p == 0: + if g[2] % p == 0: return False return True diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py b/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py index c7cdf99a83f..8e2df486769 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py @@ -8,7 +8,8 @@ # http://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import Integer, QQ +from sage.rings.integer import Integer +from sage.rings.rational_field import QQ from sage.misc.lazy_attribute import lazy_attribute from sage.schemes.jacobians.abstract_jacobian import Jacobian_generic from . import jacobian_homset @@ -22,6 +23,7 @@ class HyperellipticJacobian_generic(Jacobian_generic): """ EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: FF = FiniteField(2003) sage: R.<x> = PolynomialRing(FF) sage: f = x**5 + 1184*x**3 + 1846*x**2 + 956*x + 560 @@ -46,33 +48,38 @@ class HyperellipticJacobian_generic(Jacobian_generic): sage: P.<x> = PolynomialRing(QQ) sage: f = x^5 - x + 1; h = x - sage: C = HyperellipticCurve(f,h,'u,v') - sage: C + sage: C = HyperellipticCurve(f,h,'u,v'); C Hyperelliptic Curve over Rational Field defined by v^2 + u*v = u^5 - u + 1 - sage: PP = C.ambient_space() - sage: PP + sage: PP = C.ambient_space(); PP Projective Space of dimension 2 over Rational Field sage: C.defining_polynomial() -x0^5 + x0*x1*x2^3 + x1^2*x2^3 + x0*x2^4 - x2^5 sage: C(QQ) - Set of rational points of Hyperelliptic Curve over Rational Field defined by v^2 + u*v = u^5 - u + 1 - sage: K.<t> = NumberField(x^2-2) - sage: C(K) - Set of rational points of Hyperelliptic Curve over Number Field in t with defining polynomial x^2 - 2 defined by v^2 + u*v = u^5 - u + 1 + Set of rational points of Hyperelliptic Curve over Rational Field + defined by v^2 + u*v = u^5 - u + 1 + sage: K.<t> = NumberField(x^2 - 2) # needs sage.rings.number_field + sage: C(K) # needs sage.rings.number_field + Set of rational points of Hyperelliptic Curve + over Number Field in t with defining polynomial x^2 - 2 + defined by v^2 + u*v = u^5 - u + 1 sage: P = C(QQ)(0,1,1); P (0 : 1 : 1) sage: P == C(0,1,1) True sage: C(0,1,1).parent() - Set of rational points of Hyperelliptic Curve over Rational Field defined by v^2 + u*v = u^5 - u + 1 + Set of rational points of Hyperelliptic Curve over Rational Field + defined by v^2 + u*v = u^5 - u + 1 + + sage: # needs sage.rings.number_field sage: P1 = C(K)(P) - sage: P2 = C(K)([2,4*t-1,1]) - sage: P3 = C(K)([-1/2,1/8*(7*t+2),1]) + sage: P2 = C(K)([2, 4*t - 1, 1]) + sage: P3 = C(K)([-1/2, 1/8*(7*t+2), 1]) sage: P1, P2, P3 ((0 : 1 : 1), (2 : 4*t - 1 : 1), (-1/2 : 7/8*t + 1/4 : 1)) - sage: J = C.jacobian() - sage: J - Jacobian of Hyperelliptic Curve over Rational Field defined by v^2 + u*v = u^5 - u + 1 + + sage: J = C.jacobian(); J + Jacobian of Hyperelliptic Curve over Rational Field + defined by v^2 + u*v = u^5 - u + 1 sage: Q = J(QQ)(P); Q (u, v - 1) sage: for i in range(6): Q*i @@ -82,6 +89,8 @@ class HyperellipticJacobian_generic(Jacobian_generic): (u^2, v + 1) (u, v + 1) (1) + + sage: # needs sage.rings.number_field sage: Q1 = J(K)(P1); print("%s -> %s"%( P1, Q1 )) (0 : 1 : 1) -> (u, v - 1) sage: Q2 = J(K)(P2); print("%s -> %s"%( P2, Q2 )) @@ -89,33 +98,41 @@ class HyperellipticJacobian_generic(Jacobian_generic): sage: Q3 = J(K)(P3); print("%s -> %s"%( P3, Q3 )) (-1/2 : 7/8*t + 1/4 : 1) -> (u + 1/2, v - 7/8*t - 1/4) sage: R.<x> = PolynomialRing(K) - sage: Q4 = J(K)([x^2-t,R(1)]) + sage: Q4 = J(K)([x^2 - t, R(1)]) sage: for i in range(4): Q4*i (1) (u^2 - t, v - 1) (u^2 + (-3/4*t - 9/16)*u + 1/2*t + 1/4, v + (-1/32*t - 57/64)*u + 1/2*t + 9/16) - (u^2 + (1352416/247009*t - 1636930/247009)*u - 1156544/247009*t + 1900544/247009, v + (-2326345442/122763473*t + 3233153137/122763473)*u + 2439343104/122763473*t - 3350862929/122763473) + (u^2 + (1352416/247009*t - 1636930/247009)*u - 1156544/247009*t + 1900544/247009, + v + (-2326345442/122763473*t + 3233153137/122763473)*u + + 2439343104/122763473*t - 3350862929/122763473) sage: R2 = Q2*5; R2 - (u^2 - 3789465233/116983808*u - 267915823/58491904, v + (-233827256513849/1789384327168*t + 1/2)*u - 15782925357447/894692163584*t) + (u^2 - 3789465233/116983808*u - 267915823/58491904, + v + (-233827256513849/1789384327168*t + 1/2)*u - 15782925357447/894692163584*t) sage: R3 = Q3*5; R3 - (u^2 + 5663300808399913890623/14426454798950909645952*u - 26531814176395676231273/28852909597901819291904, v + (253155440321645614070860868199103/2450498420175733688903836378159104*t + 1/2)*u + 2427708505064902611513563431764311/4900996840351467377807672756318208*t) + (u^2 + 5663300808399913890623/14426454798950909645952*u + - 26531814176395676231273/28852909597901819291904, + v + (253155440321645614070860868199103/2450498420175733688903836378159104*t + 1/2)*u + + 2427708505064902611513563431764311/4900996840351467377807672756318208*t) sage: R4 = Q4*5; R4 - (u^2 - 3789465233/116983808*u - 267915823/58491904, v + (233827256513849/1789384327168*t + 1/2)*u + 15782925357447/894692163584*t) + (u^2 - 3789465233/116983808*u - 267915823/58491904, + v + (233827256513849/1789384327168*t + 1/2)*u + 15782925357447/894692163584*t) Thus we find the following identity:: - sage: 5*Q2 + 5*Q4 + sage: 5*Q2 + 5*Q4 # needs sage.rings.number_field (1) Moreover the following relation holds in the 5-torsion subgroup:: - sage: Q2 + Q4 == 2*Q1 + sage: Q2 + Q4 == 2*Q1 # needs sage.rings.number_field True TESTS:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(9); R.<x> = k[] - sage: J1 = HyperellipticCurve(x^3 + x - 1, x+a).jacobian() + sage: J1 = HyperellipticCurve(x^3 + x - 1, x + a).jacobian() sage: FF = FiniteField(2003) sage: R.<x> = PolynomialRing(FF) sage: f = x**5 + 1184*x**3 + 1846*x**2 + 956*x + 560 @@ -135,10 +152,11 @@ def dimension(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: k.<a> = GF(9); R.<x> = k[] - sage: HyperellipticCurve(x^3 + x - 1, x+a).jacobian().dimension() + sage: HyperellipticCurve(x^3 + x - 1, x + a).jacobian().dimension() 1 - sage: g = HyperellipticCurve(x^6 + x - 1, x+a).jacobian().dimension(); g + sage: g = HyperellipticCurve(x^6 + x - 1, x + a).jacobian().dimension(); g 2 sage: type(g) <... 'sage.rings.integer.Integer'> diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py b/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py index f7b0a1f67f0..a5f4f63876c 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py @@ -8,7 +8,8 @@ sage: C = HyperellipticCurve(f); C Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x + 1 sage: C(QQ) - Set of rational points of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x + 1 + Set of rational points of Hyperelliptic Curve over Rational Field + defined by y^2 = x^5 + x + 1 sage: P = C([0,1,1]) sage: J = C.jacobian(); J Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x + 1 @@ -23,21 +24,16 @@ sage: F.<a> = GF(3) sage: R.<x> = F[] - sage: f = x^5-1 + sage: f = x^5 - 1 sage: C = HyperellipticCurve(f) sage: J = C.jacobian() sage: X = J(F) - sage: a = x^2-x+1 - sage: b = -x +1 - sage: c = x-1 - sage: d = 0 - sage: D1 = X([a,b]) - sage: D1 + sage: a = x^2 - x + 1; b = -x + 1; c = x - 1; d = 0 + sage: D1 = X([a,b]); D1 (x^2 + 2*x + 1, y + x + 2) - sage: D2 = X([c,d]) - sage: D2 + sage: D2 = X([c,d]); D2 (x + 2, y) - sage: D1+D2 + sage: D1 + D2 (x^2 + 2*x + 2, y + 2*x + 1) """ # **************************************************************************** @@ -49,7 +45,7 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer_ring import ZZ from sage.rings.integer import is_Integer, Integer -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_element import Polynomial from sage.schemes.generic.homset import SchemeHomset_points from sage.schemes.generic.morphism import is_SchemeMorphism @@ -104,21 +100,16 @@ def __call__(self, P): sage: F.<a> = GF(3) sage: R.<x> = F[] - sage: f = x^5-1 + sage: f = x^5 - 1 sage: C = HyperellipticCurve(f) sage: J = C.jacobian() sage: X = J(F) - sage: a = x^2-x+1 - sage: b = -x +1 - sage: c = x-1 - sage: d = 0 - sage: D1 = X([a,b]) - sage: D1 + sage: a = x^2 - x + 1; b = -x + 1; c = x - 1; d = 0 + sage: D1 = X([a,b]); D1 (x^2 + 2*x + 1, y + x + 2) - sage: D2 = X([c,d]) - sage: D2 + sage: D2 = X([c,d]); D2 (x + 2, y) - sage: D1+D2 + sage: D1 + D2 (x^2 + 2*x + 2, y + 2*x + 1) """ if isinstance(P, (Integer, int)) and P == 0: @@ -138,15 +129,15 @@ def __call__(self, P): P1 = R(P1) P2 = R(P2) return JacobianMorphism_divisor_class_field(self, (P1, P2)) - if is_Integer(P1) and is_Polynomial(P2): + if is_Integer(P1) and isinstance(P2, Polynomial): R = PolynomialRing(self.value_ring(), 'x') P1 = R(P1) return JacobianMorphism_divisor_class_field(self, (P1, P2)) - if is_Integer(P2) and is_Polynomial(P1): + if is_Integer(P2) and isinstance(P1, Polynomial): R = PolynomialRing(self.value_ring(), 'x') P2 = R(P2) return JacobianMorphism_divisor_class_field(self, (P1, P2)) - if is_Polynomial(P1) and is_Polynomial(P2): + if isinstance(P1, Polynomial) and isinstance(P2, Polynomial): return JacobianMorphism_divisor_class_field(self, tuple(P)) if is_SchemeMorphism(P1) and is_SchemeMorphism(P2): return self(P1) - self(P2) diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py index 19262aece79..53545229451 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py @@ -39,17 +39,17 @@ sage: x = GF(37)['x'].gen() sage: H = HyperellipticCurve(x^5 + 12*x^4 + 13*x^3 + 15*x^2 + 33*x); H Hyperelliptic Curve over Finite Field of size 37 defined - by y^2 = x^5 + 12*x^4 + 13*x^3 + 15*x^2 + 33*x + by y^2 = x^5 + 12*x^4 + 13*x^3 + 15*x^2 + 33*x At this time, Jacobians of hyperelliptic curves are handled differently than elliptic curves:: sage: J = H.jacobian(); J Jacobian of Hyperelliptic Curve over Finite Field of size 37 defined - by y^2 = x^5 + 12*x^4 + 13*x^3 + 15*x^2 + 33*x + by y^2 = x^5 + 12*x^4 + 13*x^3 + 15*x^2 + 33*x sage: J = J(J.base_ring()); J Set of rational points of Jacobian of Hyperelliptic Curve over Finite Field - of size 37 defined by y^2 = x^5 + 12*x^4 + 13*x^3 + 15*x^2 + 33*x + of size 37 defined by y^2 = x^5 + 12*x^4 + 13*x^3 + 15*x^2 + 33*x Points on the Jacobian are represented by Mumford's polynomials. First we find a couple of points on the curve:: @@ -136,7 +136,7 @@ def cantor_reduction_simple(a, b, f, genus): Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - x sage: J = H.jacobian()(QQ); J Set of rational points of Jacobian of Hyperelliptic Curve over Rational Field - defined by y^2 = x^5 - x + defined by y^2 = x^5 - x The following point is 2-torsion:: @@ -175,7 +175,7 @@ def cantor_reduction(a, b, f, h, genus): Hyperelliptic Curve over Rational Field defined by y^2 + x*y = x^5 - x sage: J = H.jacobian()(QQ); J Set of rational points of Jacobian of Hyperelliptic Curve over - Rational Field defined by y^2 + x*y = x^5 - x + Rational Field defined by y^2 + x*y = x^5 - x The following point is 2-torsion:: @@ -230,14 +230,14 @@ def cantor_composition_simple(D1,D2,f,genus): :: - sage: F.<a> = NumberField(x^2 - 2, 'a') - sage: J = H.jacobian()(F); J + sage: F.<a> = NumberField(x^2 - 2, 'a') # needs sage.rings.number_field + sage: J = H.jacobian()(F); J # needs sage.rings.number_field Set of rational points of Jacobian of Hyperelliptic Curve over - Number Field in a with defining polynomial x^2 - 2 defined - by y^2 = x^5 + x + Number Field in a with defining polynomial x^2 - 2 defined by y^2 = x^5 + x :: + sage: # needs sage.rings.number_field sage: P = J(H.lift_x(F(1))); P (x - 1, y - a) sage: Q = J(H.lift_x(F(0))); Q @@ -265,55 +265,66 @@ def cantor_composition_simple(D1,D2,f,genus): d, l, h3 = d0.xgcd(b1 + b2) a = (a1*a2) // (d**2) b = ((b2 + l*h2*(b1-b2)*(a2 // d)) + h3*((f - b2**2) // d)) % (a) - a =a.monic() + a = a.monic() return (a, b) def cantor_composition(D1,D2,f,h,genus): r""" EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(7^2, 'a') sage: x = F['x'].gen() sage: f = x^7 + x^2 + a sage: H = HyperellipticCurve(f, 2*x); H - Hyperelliptic Curve over Finite Field in a of size 7^2 defined by y^2 + 2*x*y = x^7 + x^2 + a + Hyperelliptic Curve over Finite Field in a of size 7^2 + defined by y^2 + 2*x*y = x^7 + x^2 + a sage: J = H.jacobian()(F); J Set of rational points of Jacobian of Hyperelliptic Curve over - Finite Field in a of size 7^2 defined by y^2 + 2*x*y = x^7 + x^2 + a + Finite Field in a of size 7^2 defined by y^2 + 2*x*y = x^7 + x^2 + a :: - sage: Q = J(H.lift_x(F(1))); Q + sage: Q = J(H.lift_x(F(1))); Q # needs sage.rings.finite_rings (x + 6, y + 2*a + 2) - sage: 10*Q # indirect doctest - (x^3 + (3*a + 1)*x^2 + (2*a + 5)*x + a + 5, y + (4*a + 5)*x^2 + (a + 1)*x + 6*a + 3) - sage: 7*8297*Q + sage: 10*Q # indirect doctest # needs sage.rings.finite_rings + (x^3 + (3*a + 1)*x^2 + (2*a + 5)*x + a + 5, + y + (4*a + 5)*x^2 + (a + 1)*x + 6*a + 3) + sage: 7*8297*Q # needs sage.rings.finite_rings (1) :: - sage: Q = J(H.lift_x(F(a+1))); Q + sage: Q = J(H.lift_x(F(a+1))); Q # needs sage.rings.finite_rings (x + 6*a + 6, y + 2*a) - sage: 7*8297*Q # indirect doctest + sage: 7*8297*Q # indirect doctest # needs sage.rings.finite_rings (1) A test over a prime field: + sage: # needs sage.rings.finite_rings sage: F = GF(next_prime(10^30)) sage: x = F['x'].gen() sage: f = x^7 + x^2 + 1 sage: H = HyperellipticCurve(f, 2*x); H - Hyperelliptic Curve over Finite Field of size 1000000000000000000000000000057 defined by y^2 + 2*x*y = x^7 + x^2 + 1 + Hyperelliptic Curve over Finite Field of size 1000000000000000000000000000057 + defined by y^2 + 2*x*y = x^7 + x^2 + 1 sage: J = H.jacobian()(F); J - Set of rational points of Jacobian of Hyperelliptic Curve over - Finite Field of size 1000000000000000000000000000057 defined - by y^2 + 2*x*y = x^7 + x^2 + 1 + Set of rational points of Jacobian of Hyperelliptic Curve + over Finite Field of size 1000000000000000000000000000057 + defined by y^2 + 2*x*y = x^7 + x^2 + 1 sage: Q = J(H.lift_x(F(1))); Q (x + 1000000000000000000000000000056, y + 1000000000000000000000000000056) - sage: 10*Q # indirect doctest - (x^3 + 150296037169838934997145567227*x^2 + 377701248971234560956743242408*x + 509456150352486043408603286615, y + 514451014495791237681619598519*x^2 + 875375621665039398768235387900*x + 861429240012590886251910326876) + sage: 10*Q # indirect doctest + (x^3 + 150296037169838934997145567227*x^2 + + 377701248971234560956743242408*x + 509456150352486043408603286615, + y + 514451014495791237681619598519*x^2 + + 875375621665039398768235387900*x + 861429240012590886251910326876) sage: 7*8297*Q - (x^3 + 35410976139548567549919839063*x^2 + 26230404235226464545886889960*x + 681571430588959705539385624700, y + 999722365017286747841221441793*x^2 + 262703715994522725686603955650*x + 626219823403254233972118260890) + (x^3 + 35410976139548567549919839063*x^2 + + 26230404235226464545886889960*x + 681571430588959705539385624700, + y + 999722365017286747841221441793*x^2 + + 262703715994522725686603955650*x + 626219823403254233972118260890) """ a1, b1 = D1 a2, b2 = D2 @@ -367,16 +378,16 @@ def __init__(self, parent, polys, check=True): sage: H = HyperellipticCurve(x^5 + 12*x^4 + 13*x^3 + 15*x^2 + 33*x) sage: J = H.jacobian()(GF(37)); J Set of rational points of Jacobian of Hyperelliptic Curve over - Finite Field of size 37 defined by + Finite Field of size 37 defined by y^2 = x^5 + 12*x^4 + 13*x^3 + 15*x^2 + 33*x :: - sage: P1 = J(H.lift_x(2)); P1 # indirect doctest + sage: P1 = J(H.lift_x(2)); P1 # indirect doctest (x + 35, y + 26) sage: P1.parent() Set of rational points of Jacobian of Hyperelliptic Curve over - Finite Field of size 37 defined by + Finite Field of size 37 defined by y^2 = x^5 + 12*x^4 + 13*x^3 + 15*x^2 + 33*x sage: type(P1) <class 'sage.schemes.hyperelliptic_curves.jacobian_morphism.JacobianMorphism_divisor_class_field'> @@ -386,8 +397,8 @@ def __init__(self, parent, polys, check=True): C = parent.curve() f, h = C.hyperelliptic_polynomials() a, b = polys - if not (b**2 + h*b - f)%a == 0: - raise ValueError("Argument polys (= %s) must be divisor on curve %s."%( + if not (b**2 + h*b - f) % a == 0: + raise ValueError("Argument polys (= %s) must be divisor on curve %s." % ( polys, C)) genus = C.genus() if a.degree() > genus: @@ -400,6 +411,7 @@ def _printing_polys(self): TESTS:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(7^2, 'a') sage: x = F['x'].gen() sage: f = x^7 + x^2 + a @@ -408,7 +420,7 @@ def _printing_polys(self): :: - sage: Q = J(H.lift_x(F(1))); Q # indirect doctest + sage: Q = J(H.lift_x(F(1))); Q # indirect doctest # needs sage.rings.finite_rings (x + 6, y + 2*a + 2) """ a, b = self.__polys @@ -423,6 +435,7 @@ def _repr_(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(7^2, 'a') sage: x = F['x'].gen() sage: f = x^7 + x^2 + a @@ -431,11 +444,11 @@ def _repr_(self): :: - sage: Q = J(0); Q # indirect doctest + sage: Q = J(0); Q # indirect doctest # needs sage.rings.finite_rings (1) - sage: Q = J(H.lift_x(F(1))); Q # indirect doctest + sage: Q = J(H.lift_x(F(1))); Q # indirect doctest # needs sage.rings.finite_rings (x + 6, y + 2*a + 2) - sage: Q + Q # indirect doctest + sage: Q + Q # indirect doctest # needs sage.rings.finite_rings (x^2 + 5*x + 1, y + 3*a*x + 6*a + 2) """ if self.is_zero(): @@ -449,6 +462,7 @@ def _latex_(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<alpha> = GF(7^2) sage: x = F['x'].gen() sage: f = x^7 + x^2 + alpha @@ -457,14 +471,14 @@ def _latex_(self): :: - sage: Q = J(0); print(latex(Q)) # indirect doctest + sage: Q = J(0); print(latex(Q)) # indirect doctest # needs sage.rings.finite_rings \left(1\right) - sage: Q = J(H.lift_x(F(1))); print(latex(Q)) # indirect doctest + sage: Q = J(H.lift_x(F(1))); print(latex(Q)) # indirect doctest # needs sage.rings.finite_rings \left(x + 6, y + 2 \alpha + 2\right) :: - sage: print(latex(Q + Q)) + sage: print(latex(Q + Q)) # needs sage.rings.finite_rings \left(x^{2} + 5 x + 1, y + 3 \alpha x + 6 \alpha + 2\right) """ if self.is_zero(): @@ -474,8 +488,7 @@ def _latex_(self): def scheme(self): r""" - Return the scheme this morphism maps to; or, where this divisor - lives. + Return the scheme this morphism maps to; or, where this divisor lives. .. warning:: @@ -490,21 +503,20 @@ def scheme(self): sage: x = QQ['x'].gen() sage: f = x^5 + x sage: H = HyperellipticCurve(f) - sage: F.<a> = NumberField(x^2 - 2, 'a') - sage: J = H.jacobian()(F); J - Set of rational points of Jacobian of Hyperelliptic Curve over - Number Field in a with defining polynomial x^2 - 2 defined - by y^2 = x^5 + x + sage: F.<a> = NumberField(x^2 - 2, 'a') # needs sage.rings.number_field + sage: J = H.jacobian()(F); J # needs sage.rings.number_field + Set of rational points of Jacobian of Hyperelliptic Curve + over Number Field in a with defining polynomial x^2 - 2 + defined by y^2 = x^5 + x :: - sage: P = J(H.lift_x(F(1))) - sage: P.scheme() + sage: P = J(H.lift_x(F(1))) # needs sage.rings.number_field + sage: P.scheme() # needs sage.rings.number_field Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x """ return self.codomain() - def __list__(self): r""" Return a list `(a(x), b(x))` of the polynomials giving the @@ -515,16 +527,16 @@ def __list__(self): sage: x = QQ['x'].gen() sage: f = x^5 + x sage: H = HyperellipticCurve(f) - sage: F.<a> = NumberField(x^2 - 2, 'a') - sage: J = H.jacobian()(F); J - Set of rational points of Jacobian of Hyperelliptic Curve over - Number Field in a with defining polynomial x^2 - 2 defined - by y^2 = x^5 + x + sage: F.<a> = NumberField(x^2 - 2, 'a') # needs sage.rings.number_field + sage: J = H.jacobian()(F); J # needs sage.rings.number_field + Set of rational points of Jacobian of Hyperelliptic Curve + over Number Field in a with defining polynomial x^2 - 2 + defined by y^2 = x^5 + x :: - sage: P = J(H.lift_x(F(1))) - sage: list(P) # indirect doctest + sage: P = J(H.lift_x(F(1))) # needs sage.rings.number_field + sage: list(P) # indirect doctest # needs sage.rings.number_field [x - 1, a] """ return list(self.__polys) @@ -539,16 +551,16 @@ def __tuple__(self): sage: x = QQ['x'].gen() sage: f = x^5 + x sage: H = HyperellipticCurve(f) - sage: F.<a> = NumberField(x^2 - 2, 'a') - sage: J = H.jacobian()(F); J - Set of rational points of Jacobian of Hyperelliptic Curve over - Number Field in a with defining polynomial x^2 - 2 defined - by y^2 = x^5 + x + sage: F.<a> = NumberField(x^2 - 2, 'a') # needs sage.rings.number_field + sage: J = H.jacobian()(F); J # needs sage.rings.number_field + Set of rational points of Jacobian of Hyperelliptic Curve + over Number Field in a with defining polynomial x^2 - 2 + defined by y^2 = x^5 + x :: - sage: P = J(H.lift_x(F(1))) - sage: tuple(P) # indirect doctest + sage: P = J(H.lift_x(F(1))) # needs sage.rings.number_field + sage: tuple(P) # indirect doctest # needs sage.rings.number_field (x - 1, a) """ return tuple(self.__polys) @@ -563,14 +575,15 @@ def __getitem__(self, n): sage: x = QQ['x'].gen() sage: f = x^5 + x sage: H = HyperellipticCurve(f) - sage: F.<a> = NumberField(x^2 - 2, 'a') - sage: J = H.jacobian()(F); J - Set of rational points of Jacobian of Hyperelliptic Curve over - Number Field in a with defining polynomial x^2 - 2 defined - by y^2 = x^5 + x + sage: F.<a> = NumberField(x^2 - 2, 'a') # needs sage.rings.number_field + sage: J = H.jacobian()(F); J # needs sage.rings.number_field + Set of rational points of Jacobian of Hyperelliptic Curve + over Number Field in a with defining polynomial x^2 - 2 + defined by y^2 = x^5 + x :: + sage: # needs sage.rings.number_field sage: P = J(H.lift_x(F(1))) sage: P[0] # indirect doctest x - 1 @@ -655,15 +668,13 @@ def __bool__(self): sage: P1 = J(H.lift_x(2)); P1 (x + 35, y + 26) - sage: P1 == 0 # indirect doctest + sage: P1 == 0 # indirect doctest False - sage: P1 - P1 == 0 # indirect doctest + sage: P1 - P1 == 0 # indirect doctest True """ return self.__polys[0] != 1 - - def __neg__(self): r""" Return the additive inverse of this divisor. @@ -675,9 +686,9 @@ def __neg__(self): sage: J = H.jacobian()(GF(37)) sage: P1 = J(H.lift_x(2)); P1 (x + 35, y + 26) - sage: - P1 # indirect doctest + sage: - P1 # indirect doctest (x + 35, y + 11) - sage: P1 + (-P1) # indirect doctest + sage: P1 + (-P1) # indirect doctest (1) :: @@ -686,22 +697,23 @@ def __neg__(self): sage: J2 = H2.jacobian()(GF(37)) sage: P2 = J2(H2.lift_x(2)); P2 (x + 35, y + 15) - sage: - P2 # indirect doctest + sage: - P2 # indirect doctest (x + 35, y + 24) - sage: P2 + (-P2) # indirect doctest + sage: P2 + (-P2) # indirect doctest (1) TESTS: The following was fixed in :trac:`14264`:: + sage: # needs sage.rings.number_field sage: P.<x> = QQ[] sage: f = x^5 - x + 1; h = x - sage: C = HyperellipticCurve(f,h,'u,v') + sage: C = HyperellipticCurve(f, h, 'u,v') sage: J = C.jacobian() - sage: K.<t> = NumberField(x^2-2) + sage: K.<t> = NumberField(x^2 - 2) sage: R.<x> = K[] - sage: Q = J(K)([x^2-t,R(1)]) + sage: Q = J(K)([x^2 - t, R(1)]) sage: Q (u^2 - t, v - 1) sage: -Q @@ -741,7 +753,7 @@ def _add_(self,other): sage: P1 = J(H.lift_x(2)); P1 (x + 35, y + 26) - sage: P1 + P1 # indirect doctest + sage: P1 + P1 # indirect doctest (x^2 + 33*x + 4, y + 13*x) """ X = self.parent() @@ -772,7 +784,7 @@ def _sub_(self, other): sage: P1 = J(H.lift_x(2)); P1 (x + 35, y + 26) - sage: P1 - P1 # indirect doctest + sage: P1 - P1 # indirect doctest (1) :: @@ -783,11 +795,11 @@ def _sub_(self, other): Observe that the `x`-coordinates are the same but the `y`-coordinates differ:: - sage: P1 - P2 # indirect doctest + sage: P1 - P2 # indirect doctest (x^2 + 31*x + 8, y + 7*x + 12) - sage: P1 + P2 # indirect doctest + sage: P1 + P2 # indirect doctest (x^2 + 31*x + 8, y + 4*x + 18) - sage: (P1 - P2) - (P1 + P2) + 2*P2 # indirect doctest + sage: (P1 - P2) - (P1 + P2) + 2*P2 # indirect doctest (1) """ return self + (-other) diff --git a/src/sage/schemes/hyperelliptic_curves/kummer_surface.py b/src/sage/schemes/hyperelliptic_curves/kummer_surface.py index 987099f8d4b..dadf1200f01 100644 --- a/src/sage/schemes/hyperelliptic_curves/kummer_surface.py +++ b/src/sage/schemes/hyperelliptic_curves/kummer_surface.py @@ -12,7 +12,7 @@ from sage.schemes.projective.projective_subscheme\ import AlgebraicScheme_subscheme_projective from sage.categories.homset import Hom -from sage.categories.all import Schemes +from sage.categories.schemes import Schemes # The generic genus 2 curve in Weierstrass form: # diff --git a/src/sage/schemes/hyperelliptic_curves/mestre.py b/src/sage/schemes/hyperelliptic_curves/mestre.py index 31ba672800c..7687cff0916 100644 --- a/src/sage/schemes/hyperelliptic_curves/mestre.py +++ b/src/sage/schemes/hyperelliptic_curves/mestre.py @@ -67,26 +67,32 @@ def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, sage: HyperellipticCurve_from_invariants([3840,414720,491028480,2437709561856]) Traceback (most recent call last): ... - NotImplementedError: Reduction of hyperelliptic curves not yet implemented. See trac #14755 and #14756. - sage: HyperellipticCurve_from_invariants([3840,414720,491028480,2437709561856],reduced = False) - Hyperelliptic Curve over Rational Field defined by y^2 = -46656*x^6 + 46656*x^5 - 19440*x^4 + 4320*x^3 - 540*x^2 + 4410*x - 1 + NotImplementedError: Reduction of hyperelliptic curves not yet implemented. + See issues #14755 and #14756. + + sage: HyperellipticCurve_from_invariants([3840,414720,491028480,2437709561856], reduced=False) + Hyperelliptic Curve over Rational Field defined by + y^2 = -46656*x^6 + 46656*x^5 - 19440*x^4 + 4320*x^3 - 540*x^2 + 4410*x - 1 + sage: HyperellipticCurve_from_invariants([21, 225/64, 22941/512, 1]) Traceback (most recent call last): ... - NotImplementedError: Reduction of hyperelliptic curves not yet implemented. See trac #14755 and #14756. + NotImplementedError: Reduction of hyperelliptic curves not yet implemented. + See issues #14755 and #14756. An example over a finite field:: - sage: H = HyperellipticCurve_from_invariants([GF(13)(1),3,7,5]); H + sage: H = HyperellipticCurve_from_invariants([GF(13)(1), 3, 7, 5]); H Hyperelliptic Curve over Finite Field of size 13 defined by ... sage: H.igusa_clebsch_invariants() (4, 9, 6, 11) An example over a number field:: - sage: K = QuadraticField(353, 'a') - sage: H = HyperellipticCurve_from_invariants([21, 225/64, 22941/512, 1], reduced = false) - sage: f = K['x'](H.hyperelliptic_polynomials()[0]) + sage: K = QuadraticField(353, 'a') # needs sage.rings.number_field + sage: H = HyperellipticCurve_from_invariants([21, 225/64, 22941/512, 1], # needs sage.rings.number_field + ....: reduced=false) + sage: f = K['x'](H.hyperelliptic_polynomials()[0]) # needs sage.rings.number_field If the Mestre Conic defined by the Igusa-Clebsch invariants has no rational points, then there exists no hyperelliptic curve over the base field with @@ -95,14 +101,17 @@ def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, sage: HyperellipticCurve_from_invariants([1,2,3,4]) Traceback (most recent call last): ... - ValueError: No such curve exists over Rational Field as there are no rational points on Projective Conic Curve over Rational Field defined by -2572155000*u^2 - 317736000*u*v + 1250755459200*v^2 + 2501510918400*u*w + 39276887040*v*w + 2736219686912*w^2 + ValueError: No such curve exists over Rational Field as there are + no rational points on Projective Conic Curve over Rational Field defined by + -2572155000*u^2 - 317736000*u*v + 1250755459200*v^2 + 2501510918400*u*w + + 39276887040*v*w + 2736219686912*w^2 Mestre's algorithm only works for generic curves of genus two, so another algorithm is needed for those curves with extra automorphism. See also :trac:`12199`:: sage: P.<x> = QQ[] - sage: C = HyperellipticCurve(x^6+1) + sage: C = HyperellipticCurve(x^6 + 1) sage: i = C.igusa_clebsch_invariants() sage: HyperellipticCurve_from_invariants(i) Traceback (most recent call last): @@ -115,11 +124,12 @@ def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, of those characteristics. See also :trac:`12200`:: sage: P.<x> = GF(3)[] - sage: HyperellipticCurve(x^6+x+1).igusa_clebsch_invariants() + sage: HyperellipticCurve(x^6 + x + 1).igusa_clebsch_invariants() Traceback (most recent call last): ... - NotImplementedError: Invariants of binary sextics/genus 2 hyperelliptic curves not implemented in characteristics 2, 3, and 5 - sage: HyperellipticCurve_from_invariants([GF(5)(1),1,0,1]) + NotImplementedError: Invariants of binary sextics/genus 2 hyperelliptic curves + not implemented in characteristics 2, 3, and 5 + sage: HyperellipticCurve_from_invariants([GF(5)(1), 1, 0, 1]) Traceback (most recent call last): ... ZeroDivisionError: inverse of Mod(0, 5) does not exist @@ -160,25 +170,25 @@ def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, from sage.interfaces.magma import magma from sage.misc.sage_eval import sage_eval if MConic.has_rational_point(algorithm='magma'): - parametrization = [l.replace('$.1', 't').replace('$.2', 'u') \ + parametrization = [l.replace('$.1', 't').replace('$.2', 'u') for l in str(magma(MConic).Parametrization()).splitlines()[4:7]] - [F1, F2, F3] = [sage_eval(p, locals={'t':t,'u':1,'a':k.gen()}) \ - for p in parametrization] + [F1, F2, F3] = [sage_eval(p, locals={'t': t, 'u': 1, 'a': k.gen()}) + for p in parametrization] else: - raise ValueError("No such curve exists over %s as there are no " \ - "rational points on %s" % (k, MConic)) + raise ValueError(f"No such curve exists over {k} as there are no " + f"rational points on {MConic}") else: if MConic.has_rational_point(): parametrization = MConic.parametrization(morphism=False)[0] [F1, F2, F3] = [p(t, 1) for p in parametrization] else: - raise ValueError("No such curve exists over %s as there are no " \ - "rational points on %s" % (k, MConic)) + raise ValueError(f"No such curve exists over {k} as there are no " + f"rational points on {MConic}") # setting the cijk from Mestre's algorithm c111 = 12*x*y - 2*y/3 - 4*z c112 = -18*x**3 - 12*x*y - 36*y**2 - 2*z - c113 = -9*x**3 - 36*x**2*y -4*x*y - 6*x*z - 18*y**2 + c113 = -9*x**3 - 36*x**2*y - 4*x*y - 6*x*z - 18*y**2 c122 = c113 c123 = -54*x**4 - 36*x**2*y - 36*x*y**2 - 6*x*z - 4*y**2 - 24*y*z c133 = -27*x**4/2 - 72*x**3*y - 6*x**2*y - 9*x**2*z - 39*x*y**2 - \ @@ -195,14 +205,14 @@ def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, c233*F2*F3**2 + c333*F3**3 try: - f = f*f.denominator() # clear the denominator + f = f * f.denominator() # clear the denominator except (AttributeError, TypeError): pass if reduced: - raise NotImplementedError("Reduction of hyperelliptic curves not " \ - "yet implemented. " \ - "See trac #14755 and #14756.") + raise NotImplementedError("Reduction of hyperelliptic curves not " + "yet implemented. " + "See issues #14755 and #14756.") return HyperellipticCurve(f) @@ -221,7 +231,7 @@ def Mestre_conic(i, xyz=False, names='u,v,w'): invariants: I2, I4, I6, I10 - ``xyz`` - Boolean (default: False) if True, the algorithm also returns three invariants x,y,z used in Mestre's algorithm - - ``names`` (default: 'u,v,w') - the variable names for the Conic + - ``names`` (default: 'u,v,w') - the variable names for the conic OUTPUT: @@ -232,24 +242,34 @@ def Mestre_conic(i, xyz=False, names='u,v,w'): A standard example:: sage: Mestre_conic([1,2,3,4]) - Projective Conic Curve over Rational Field defined by -2572155000*u^2 - 317736000*u*v + 1250755459200*v^2 + 2501510918400*u*w + 39276887040*v*w + 2736219686912*w^2 + Projective Conic Curve over Rational Field defined by + -2572155000*u^2 - 317736000*u*v + 1250755459200*v^2 + 2501510918400*u*w + + 39276887040*v*w + 2736219686912*w^2 Note that the algorithm works over number fields as well:: - sage: k = NumberField(x^2-41,'a') - sage: a = k.an_element() - sage: Mestre_conic([1,2+a,a,4+a]) - Projective Conic Curve over Number Field in a with defining polynomial x^2 - 41 defined by (-801900000*a + 343845000)*u^2 + (855360000*a + 15795864000)*u*v + (312292800000*a + 1284808579200)*v^2 + (624585600000*a + 2569617158400)*u*w + (15799910400*a + 234573143040)*v*w + (2034199306240*a + 16429854656512)*w^2 + sage: x = polygen(ZZ, 'x') + sage: k = NumberField(x^2 - 41, 'a') # needs sage.rings.number_field + sage: a = k.an_element() # needs sage.rings.number_field + sage: Mestre_conic([1, 2 + a, a, 4 + a]) # needs sage.rings.number_field + Projective Conic Curve over Number Field in a with defining polynomial x^2 - 41 + defined by (-801900000*a + 343845000)*u^2 + (855360000*a + 15795864000)*u*v + + (312292800000*a + 1284808579200)*v^2 + (624585600000*a + 2569617158400)*u*w + + (15799910400*a + 234573143040)*v*w + (2034199306240*a + 16429854656512)*w^2 And over finite fields:: - sage: Mestre_conic([GF(7)(10),GF(7)(1),GF(7)(2),GF(7)(3)]) - Projective Conic Curve over Finite Field of size 7 defined by -2*u*v - v^2 - 2*u*w + 2*v*w - 3*w^2 + sage: Mestre_conic([GF(7)(10), GF(7)(1), GF(7)(2), GF(7)(3)]) + Projective Conic Curve over Finite Field of size 7 + defined by -2*u*v - v^2 - 2*u*w + 2*v*w - 3*w^2 - An example with xyz:: + An example with ``xyz``:: sage: Mestre_conic([5,6,7,8], xyz=True) - (Projective Conic Curve over Rational Field defined by -415125000*u^2 + 608040000*u*v + 33065136000*v^2 + 66130272000*u*w + 240829440*v*w + 10208835584*w^2, 232/1125, -1072/16875, 14695616/2109375) + (Projective Conic Curve over Rational Field + defined by -415125000*u^2 + 608040000*u*v + 33065136000*v^2 + + 66130272000*u*w + 240829440*v*w + 10208835584*w^2, + 232/1125, -1072/16875, 14695616/2109375) ALGORITHM: diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index 8118089acdb..321928f1464 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -46,7 +46,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.all import integer_ceil as ceil +from sage.arith.misc import integer_ceil as ceil from sage.arith.misc import binomial from sage.functions.log import log from sage.matrix.constructor import matrix @@ -58,13 +58,20 @@ from sage.modules.free_module import FreeModule from sage.modules.free_module_element import is_FreeModuleElement from sage.modules.module import Module -from sage.rings.all import (Integers, Integer, PolynomialRing, PowerSeriesRing, - Rationals, Rational, LaurentSeriesRing, QQ, ZZ, - IntegralDomain) +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as Integers +from sage.rings.integer import Integer +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import RationalField as Rationals +from sage.rings.rational import Rational +from sage.rings.laurent_series_ring import LaurentSeriesRing +from sage.rings.rational_field import QQ +from sage.rings.integer_ring import ZZ +from sage.rings.ring import IntegralDomain from sage.rings.infinity import Infinity from sage.rings.laurent_series_ring import is_LaurentSeriesRing -from sage.rings.padics.all import pAdicField -from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.padics.factory import Qp as pAdicField +from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.ring import CommutativeAlgebra from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.schemes.elliptic_curves.ell_generic import is_EllipticCurve @@ -489,7 +496,7 @@ def __init__(self, Q, laurent_series=False): ... ArithmeticError: 2 and 3 must be invertible in the coefficient ring (=Ring of integers modulo 10) of Q """ - if not is_Polynomial(Q): + if not isinstance(Q, Polynomial): raise TypeError("Q (=%s) must be a polynomial" % Q) if Q.degree() != 3 or not Q[2].is_zero(): @@ -1519,7 +1526,7 @@ def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False): sage: M = monsky_washnitzer.adjusted_prec(p, prec) sage: R.<x> = PolynomialRing(Integers(p**M)) sage: A = monsky_washnitzer.matrix_of_frobenius( # long time - ....: x^3 - x + R(1/4), p, M) # long time + ....: x^3 - x + R(1/4), p, M) sage: B = A.change_ring(Integers(p**prec)); B # long time [74311982 57996908] [95877067 25828133] @@ -1537,7 +1544,7 @@ def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False): sage: M = monsky_washnitzer.adjusted_prec(p, prec) sage: R.<x> = PolynomialRing(Integers(p**M)) sage: A = monsky_washnitzer.matrix_of_frobenius( # long time - ....: x^3 - x + R(1/4), p, M) # long time + ....: x^3 - x + R(1/4), p, M) sage: B = A.change_ring(Integers(p**prec)) # long time sage: B.det() # long time 5 @@ -1556,13 +1563,13 @@ def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False): sage: A = A.change_ring(Integers(p**max_prec)) # long time sage: result = [] # long time sage: for prec in range(1, max_prec): # long time - ....: M = monsky_washnitzer.adjusted_prec(p, prec) # long time - ....: R.<x> = PolynomialRing(Integers(p^M),'x') # long time - ....: B = monsky_washnitzer.matrix_of_frobenius( # long time - ....: x^3 - x + R(1/4), p, M) # long time - ....: B = B.change_ring(Integers(p**prec)) # long time - ....: result.append(B == A.change_ring( # long time - ....: Integers(p**prec))) # long time + ....: M = monsky_washnitzer.adjusted_prec(p, prec) + ....: R.<x> = PolynomialRing(Integers(p^M),'x') + ....: B = monsky_washnitzer.matrix_of_frobenius( + ....: x^3 - x + R(1/4), p, M) + ....: B = B.change_ring(Integers(p**prec)) + ....: result.append(B == A.change_ring( + ....: Integers(p**prec))) sage: result == [True] * (max_prec - 1) # long time True @@ -2389,7 +2396,7 @@ def __init__(self, Q, R=None, invert_y=True): Q = C.hyperelliptic_polynomials()[0].change_ring(R) self._curve = C - if is_Polynomial(Q): + if isinstance(Q, Polynomial): self._Q = Q.change_ring(R) self._coeffs = self._Q.coefficients(sparse=False) if self._coeffs.pop() != 1: @@ -2787,7 +2794,6 @@ def is_field(self, proof=True): SpecialHyperellipticQuotientRing_class = SpecialHyperellipticQuotientRing - class MonskyWashnitzerDifferential(ModuleElement): r""" An element of the Monsky-Washnitzer ring of differentials, of diff --git a/src/sage/schemes/jacobians/__init__.py b/src/sage/schemes/jacobians/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/jacobians/abstract_jacobian.py b/src/sage/schemes/jacobians/abstract_jacobian.py index e2007663c81..8fece57a242 100644 --- a/src/sage/schemes/jacobians/abstract_jacobian.py +++ b/src/sage/schemes/jacobians/abstract_jacobian.py @@ -122,18 +122,18 @@ def __init__(self, C): defined by x + y + z) must be defined over a field. """ if not is_Scheme(C): - raise TypeError("Argument (=%s) must be a scheme."%C) + raise TypeError("Argument (=%s) must be a scheme." % C) if C.base_ring() not in _Fields: - raise TypeError("C (=%s) must be defined over a field."%C) + raise TypeError("C (=%s) must be defined over a field." % C) if C.dimension() != 1: - raise ValueError("C (=%s) must have dimension 1."%C) + raise ValueError("C (=%s) must have dimension 1." % C) self.__curve = C Scheme.__init__(self, C.base_scheme()) def __richcmp__(self, J, op): """ - Compare the Jacobian self to `J`. If `J` is a Jacobian, then - self and `J` are equal if and only if their curves are equal. + Compare the Jacobian ``self`` to `J`. If `J` is a Jacobian, then + ``self`` and `J` are equal if and only if their curves are equal. EXAMPLES:: @@ -194,7 +194,7 @@ def _point(self): def curve(self): """ - Return the curve of which self is the Jacobian. + Return the curve of which ``self`` is the Jacobian. EXAMPLES:: @@ -214,45 +214,42 @@ def change_ring(self, R): - ``R`` -- a field. The new base ring. - OUTPUT: - - The Jacobian over the ring `R`. + OUTPUT: The Jacobian over the ring `R`. EXAMPLES:: sage: R.<x> = QQ['x'] - sage: H = HyperellipticCurve(x^3-10*x+9) + sage: H = HyperellipticCurve(x^3 - 10*x + 9) sage: Jac = H.jacobian(); Jac - Jacobian of Hyperelliptic Curve over Rational - Field defined by y^2 = x^3 - 10*x + 9 + Jacobian of Hyperelliptic Curve over Rational Field + defined by y^2 = x^3 - 10*x + 9 sage: Jac.change_ring(RDF) - Jacobian of Hyperelliptic Curve over Real Double - Field defined by y^2 = x^3 - 10.0*x + 9.0 + Jacobian of Hyperelliptic Curve over Real Double Field + defined by y^2 = x^3 - 10.0*x + 9.0 """ return self.curve().change_ring(R).jacobian() def base_extend(self, R): r""" - Return the natural extension of ``self`` over `R` + Return the natural extension of ``self`` over `R`. INPUT: - ``R`` -- a field. The new base field. - OUTPUT: - - The Jacobian over the ring `R`. + OUTPUT: The Jacobian over the ring `R`. EXAMPLES:: sage: R.<x> = QQ['x'] - sage: H = HyperellipticCurve(x^3-10*x+9) + sage: H = HyperellipticCurve(x^3 - 10*x + 9) sage: Jac = H.jacobian(); Jac - Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^3 - 10*x + 9 - sage: F.<a> = QQ.extension(x^2+1) - sage: Jac.base_extend(F) + Jacobian of Hyperelliptic Curve over Rational Field + defined by y^2 = x^3 - 10*x + 9 + sage: F.<a> = QQ.extension(x^2 + 1) # needs sage.rings.number_field + sage: Jac.base_extend(F) # needs sage.rings.number_field Jacobian of Hyperelliptic Curve over Number Field in a with defining - polynomial x^2 + 1 defined by y^2 = x^3 - 10*x + 9 + polynomial x^2 + 1 defined by y^2 = x^3 - 10*x + 9 """ if R not in _Fields: raise ValueError('Not a field: ' + str(R)) diff --git a/src/sage/schemes/overview.py b/src/sage/schemes/overview.py index d57b74d8f32..bd83daafac0 100644 --- a/src/sage/schemes/overview.py +++ b/src/sage/schemes/overview.py @@ -117,7 +117,7 @@ :: sage: R.<x> = ZZ[] - sage: S.<t> = R.quo(x^2+5) + sage: S.<t> = R.quo(x^2 + 5) sage: P.<X,Y,Z> = ProjectiveSpace(2, S) sage: P(S) Set of rational points of Projective Space of dimension 2 over diff --git a/src/sage/schemes/plane_conics/__init__.py b/src/sage/schemes/plane_conics/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index b5454923998..9794790e1ae 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -51,7 +51,8 @@ class ProjectiveConic_field(ProjectivePlaneCurve_field): sage: K = FractionField(PolynomialRing(QQ, 't')) sage: P.<X, Y, Z> = K[] sage: Conic(X^2 + Y^2 - Z^2) - Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Rational Field defined by X^2 + Y^2 - Z^2 + Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t + over Rational Field defined by X^2 + Y^2 - Z^2 TESTS:: @@ -79,7 +80,7 @@ def __init__(self, A, f): def _repr_type(self): r""" - Returns ``'Projective Conic'``, which is the first part of the + Return ``'Projective Conic'``, which is the first part of the plain text representation of this object as output by the function ``_repr_`` of the class ``Curve_generic``. @@ -96,7 +97,7 @@ def _repr_type(self): def base_extend(self, S): r""" - Returns the conic over ``S`` given by the same equation as ``self``. + Return the conic over ``S`` given by the same equation as ``self``. EXAMPLES:: @@ -104,9 +105,10 @@ def base_extend(self, S): Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2 sage: c.has_rational_point() False - sage: d = c.base_extend(QuadraticField(-1, 'i')); d - Projective Conic Curve over Number Field in i with defining polynomial x^2 + 1 with i = 1*I defined by x^2 + y^2 + z^2 - sage: d.rational_point(algorithm = 'rnfisnorm') + sage: d = c.base_extend(QuadraticField(-1, 'i')); d # needs sage.rings.number_field + Projective Conic Curve over Number Field in i + with defining polynomial x^2 + 1 with i = 1*I defined by x^2 + y^2 + z^2 + sage: d.rational_point(algorithm='rnfisnorm') # needs sage.rings.number_field (i : 1 : 0) """ if S in _Fields: @@ -131,7 +133,7 @@ def base_extend(self, S): def cache_point(self, p): r""" Replace the point in the cache of ``self`` by ``p`` for use - by ``self.rational_point()`` and ``self.parametrization()``. + by :meth:`rational_point` and :meth:`parametrization`. EXAMPLES:: @@ -159,10 +161,11 @@ def coefficients(self): [1, 2, 3, 4, 5, 6] sage: P.<x,y,z> = GF(13)[] - sage: a = Conic(x^2+5*x*y+y^2+z^2).coefficients(); a + sage: a = Conic(x^2 + 5*x*y + y^2 + z^2).coefficients(); a [1, 5, 0, 1, 0, 1] sage: Conic(a) - Projective Conic Curve over Finite Field of size 13 defined by x^2 + 5*x*y + y^2 + z^2 + Projective Conic Curve over Finite Field of size 13 + defined by x^2 + 5*x*y + y^2 + z^2 """ return self._coefficients @@ -192,8 +195,10 @@ def derivative_matrix(self): An example in characteristic `2`:: sage: P.<t> = GF(2)[] - sage: c = Conic([t, 1, t^2, 1, 1, 0]); c - Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) defined by t*x^2 + x*y + y^2 + (t^2)*x*z + y*z + sage: c = Conic([t, 1, t^2, 1, 1, 0]); c # needs sage.libs.ntl + Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Finite Field of size 2 (using GF2X) + defined by t*x^2 + x*y + y^2 + (t^2)*x*z + y*z sage: c.is_smooth() True sage: c.derivative_matrix() @@ -208,7 +213,7 @@ def derivative_matrix(self): def determinant(self): r""" - Returns the determinant of the symmetric matrix that defines + Return the determinant of the symmetric matrix that defines the conic ``self``. This is defined only if the base field has characteristic @@ -232,13 +237,15 @@ def determinant(self): sage: C.determinant() Traceback (most recent call last): ... - ValueError: The conic self (= Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z) has no symmetric matrix because the base field has characteristic 2 + ValueError: The conic self (= Projective Conic Curve over Finite Field + of size 2 defined by x^2 + x*y + y^2 + x*z + y*z) has no symmetric matrix + because the base field has characteristic 2 """ return self.symmetric_matrix().determinant() def diagonal_matrix(self): r""" - Returns a diagonal matrix `D` and a matrix `T` such that `T^t A T = D` + Return a diagonal matrix `D` and a matrix `T` such that `T^t A T = D` holds, where `(x, y, z) A (x, y, z)^t` is the defining polynomial of the conic ``self``. @@ -263,19 +270,21 @@ def diagonal_matrix(self): :: - sage: c = Conic(GF(4, 'a'), [0, 1, 1, 1, 1, 1]) - sage: c.is_smooth() + sage: c = Conic(GF(4, 'a'), [0, 1, 1, 1, 1, 1]) # needs sage.rings.finite_rings + sage: c.is_smooth() # needs sage.rings.finite_rings True - sage: c.diagonal_matrix() + sage: c.diagonal_matrix() # needs sage.rings.finite_rings Traceback (most recent call last): ... - ValueError: The conic self (= Projective Conic Curve over Finite Field in a of size 2^2 defined by x*y + y^2 + x*z + y*z + z^2) has no symmetric matrix because the base field has characteristic 2 + ValueError: The conic self (= Projective Conic Curve over Finite Field + in a of size 2^2 defined by x*y + y^2 + x*z + y*z + z^2) has + no symmetric matrix because the base field has characteristic 2 """ A = self.symmetric_matrix() B = self.base_ring() basis = [vector(B,{2:0,i:1}) for i in range(3)] for i in range(3): - zerovalue = (basis[i]*A*basis[i].column()== 0) + zerovalue = (basis[i]*A*basis[i].column() == 0) if zerovalue: for j in range(i+1,3): if basis[j]*A*basis[j].column() != 0: @@ -298,23 +307,26 @@ def diagonal_matrix(self): def diagonalization(self, names=None): r""" - Returns a diagonal conic `C`, an isomorphism of schemes `M: C` -> ``self`` + Return a diagonal conic `C`, an isomorphism of schemes `M: C` -> ``self`` and the inverse `N` of `M`. EXAMPLES:: sage: Conic(GF(5), [1,0,1,1,0,1]).diagonalization() - (Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2, + (Projective Conic Curve over Finite Field of size 5 + defined by x^2 + y^2 + 2*z^2, Scheme morphism: - From: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2 - To: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + x*z + z^2 - Defn: Defined on coordinates by sending (x : y : z) to - (x + 2*z : y : z), + From: Projective Conic Curve over Finite Field of size 5 + defined by x^2 + y^2 + 2*z^2 + To: Projective Conic Curve over Finite Field of size 5 + defined by x^2 + y^2 + x*z + z^2 + Defn: Defined on coordinates by sending (x : y : z) to (x + 2*z : y : z), Scheme morphism: - From: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + x*z + z^2 - To: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2 - Defn: Defined on coordinates by sending (x : y : z) to - (x - 2*z : y : z)) + From: Projective Conic Curve over Finite Field of size 5 + defined by x^2 + y^2 + x*z + z^2 + To: Projective Conic Curve over Finite Field of size 5 + defined by x^2 + y^2 + 2*z^2 + Defn: Defined on coordinates by sending (x : y : z) to (x - 2*z : y : z)) The diagonalization is only defined in characteristic different from 2: @@ -324,7 +336,9 @@ def diagonalization(self, names=None): sage: Conic(GF(2), [1,1,1,1,1,0]).diagonalization() Traceback (most recent call last): ... - ValueError: The conic self (= Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z) has no symmetric matrix because the base field has characteristic 2 + ValueError: The conic self (= Projective Conic Curve over Finite Field + of size 2 defined by x^2 + x*y + y^2 + x*z + y*z) has no symmetric matrix + because the base field has characteristic 2 An example over a global function field: @@ -334,19 +348,25 @@ def diagonalization(self, names=None): sage: (t,) = K.gens() sage: C = Conic(K, [t/2,0, 1, 2, 0, 3]) sage: C.diagonalization() - (Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (-3*t)*x^2 + 2*y^2 + (3*t + 3)/t*z^2, + (Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Finite Field of size 7 + defined by (-3*t)*x^2 + 2*y^2 + (3*t + 3)/t*z^2, Scheme morphism: - From: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (-3*t)*x^2 + 2*y^2 + (3*t + 3)/t*z^2 - To: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (-3*t)*x^2 + 2*y^2 + x*z + 3*z^2 - Defn: Defined on coordinates by sending (x : y : z) to - (x - 1/t*z : y : z), + From: Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Finite Field of size 7 + defined by (-3*t)*x^2 + 2*y^2 + (3*t + 3)/t*z^2 + To: Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Finite Field of size 7 + defined by (-3*t)*x^2 + 2*y^2 + x*z + 3*z^2 + Defn: Defined on coordinates by sending (x : y : z) to (x - 1/t*z : y : z), Scheme morphism: - From: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (-3*t)*x^2 + 2*y^2 + x*z + 3*z^2 - To: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (-3*t)*x^2 + 2*y^2 + (3*t + 3)/t*z^2 - Defn: Defined on coordinates by sending (x : y : z) to - (x + 1/t*z : y : z)) - - + From: Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Finite Field of size 7 + defined by (-3*t)*x^2 + 2*y^2 + x*z + 3*z^2 + To: Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Finite Field of size 7 + defined by (-3*t)*x^2 + 2*y^2 + (3*t + 3)/t*z^2 + Defn: Defined on coordinates by sending (x : y : z) to (x + 1/t*z : y : z)) """ if names is None: names = self.defining_polynomial().parent().variable_names() @@ -357,14 +377,14 @@ def diagonalization(self, names=None): def gens(self): r""" - Returns the generators of the coordinate ring of ``self``. + Return the generators of the coordinate ring of ``self``. EXAMPLES: :: sage: P.<x,y,z> = QQ[] - sage: c = Conic(x^2+y^2+z^2) + sage: c = Conic(x^2 + y^2 + z^2) sage: c.gens() (xbar, ybar, zbar) sage: c.defining_polynomial()(c.gens()) @@ -376,7 +396,8 @@ def gens(self): sage: C.<a,b,c> = Conic(GF(3), [1, 1, 1]) sage: C - Projective Conic Curve over Finite Field of size 3 defined by a^2 + b^2 + c^2 + Projective Conic Curve over + Finite Field of size 3 defined by a^2 + b^2 + c^2 """ return self.coordinate_ring().gens() @@ -384,7 +405,7 @@ def gens(self): def has_rational_point(self, point=False, algorithm='default', read_cache=True): r""" - Returns True if and only if the conic ``self`` + Return True if and only if the conic ``self`` has a point over its base field `B`. If ``point`` is True, then returns a second output, which is @@ -398,12 +419,12 @@ def has_rational_point(self, point=False, The parameter ``algorithm`` specifies the algorithm to be used: - - ``'default'`` -- If the base field is real or complex, - use an elementary native Sage implementation. + - ``'default'`` -- If the base field is real or complex, + use an elementary native Sage implementation. - - ``'magma'`` (requires Magma to be installed) -- - delegates the task to the Magma computer algebra - system. + - ``'magma'`` (requires Magma to be installed) -- + delegates the task to the Magma computer algebra + system. EXAMPLES:: @@ -424,13 +445,13 @@ def has_rational_point(self, point=False, And they can also be solved with Magma:: - sage: C.has_rational_point(algorithm='magma') # optional - magma + sage: C.has_rational_point(algorithm='magma') # optional - magma True - sage: C.has_rational_point(algorithm='magma', point=True) # optional - magma + sage: C.has_rational_point(algorithm='magma', point=True) # optional - magma (True, (-t : 1 : 1)) sage: D = Conic([t,1,t^2]) - sage: D.has_rational_point(algorithm='magma') # optional - magma + sage: D.has_rational_point(algorithm='magma') # optional - magma False TESTS: @@ -439,18 +460,20 @@ def has_rational_point(self, point=False, numbers, one does not. Check that they are both handled correctly by the Magma interface. :: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: K.coerce_embedding() Generic morphism: From: Number Field in i with defining polynomial x^2 + 1 with i = 1*I To: Complex Lazy Field Defn: i -> 1*I - sage: Conic(K, [1,1,1]).rational_point(algorithm='magma') # optional - magma + sage: Conic(K, [1,1,1]).rational_point(algorithm='magma') # optional - magma (-i : 1 : 0) + sage: # needs sage.rings.number_field sage: x = QQ['x'].gen() - sage: L.<i> = NumberField(x^2+1, embedding=None) - sage: Conic(L, [1,1,1]).rational_point(algorithm='magma') # optional - magma + sage: L.<i> = NumberField(x^2 + 1, embedding=None) + sage: Conic(L, [1,1,1]).rational_point(algorithm='magma') # optional - magma (-i : 1 : 0) sage: L == K False @@ -560,13 +583,14 @@ def has_singular_point(self, point=False): sage: P.<x,y,z> = GF(7)[] sage: e = Conic((x+y+z)*(x-y+2*z)); e - Projective Conic Curve over Finite Field of size 7 defined by x^2 - y^2 + 3*x*z + y*z + 2*z^2 + Projective Conic Curve over Finite Field of size 7 + defined by x^2 - y^2 + 3*x*z + y*z + 2*z^2 sage: e.has_singular_point(point = True) (True, (2 : 4 : 1)) sage: Conic([1, 1, -1]).has_singular_point() False - sage: Conic([1, 1, -1]).has_singular_point(point = True) + sage: Conic([1, 1, -1]).has_singular_point(point=True) (False, None) ``has_singular_point`` is not implemented over all fields @@ -574,17 +598,19 @@ def has_singular_point(self, point=False): :: - sage: F.<a> = FiniteField(8) - sage: Conic([a, a+1, 1]).has_singular_point(point = True) + sage: F.<a> = FiniteField(8) # needs sage.rings.finite_rings + sage: Conic([a, a + 1, 1]).has_singular_point(point=True) # needs sage.rings.finite_rings (True, (a + 1 : 0 : 1)) sage: P.<t> = GF(2)[] - sage: C = Conic(P, [t,t,1]); C - Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) defined by t*x^2 + t*y^2 + z^2 - sage: C.has_singular_point(point = False) + sage: C = Conic(P, [t,t,1]); C # needs sage.libs.ntl + Projective Conic Curve over Fraction Field of Univariate Polynomial Ring + in t over Finite Field of size 2 (using GF2X) defined by t*x^2 + t*y^2 + z^2 + sage: C.has_singular_point(point=False) # needs sage.libs.ntl Traceback (most recent call last): ... - NotImplementedError: Sorry, find singular point on conics not implemented over all fields of characteristic 2. + NotImplementedError: Sorry, find singular point on conics not implemented + over all fields of characteristic 2. """ if not point: ret = self.has_singular_point(point=True) @@ -619,7 +645,7 @@ def hom(self, x, Y=None): EXAMPLES: - Here are a few Morphisms given by matrices. In the first + Here are a few morphisms given by matrices. In the first example, ``Y`` is omitted, in the second example, ``Y`` is specified. :: @@ -629,8 +655,7 @@ def hom(self, x, Y=None): Scheme morphism: From: Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2 To: Projective Conic Curve over Rational Field defined by -x^2 + 2*x*y + z^2 - Defn: Defined on coordinates by sending (x : y : z) to - (x + y : y : z) + Defn: Defined on coordinates by sending (x : y : z) to (x + y : y : z) sage: h([-1, 1, 0]) (0 : 1 : 0) @@ -640,8 +665,7 @@ def hom(self, x, Y=None): Scheme morphism: From: Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2 To: Projective Conic Curve over Rational Field defined by 4*x^2 + y^2 - z^2 - Defn: Defined on coordinates by sending (x : y : z) to - (1/2*z : y : x) + Defn: Defined on coordinates by sending (x : y : z) to (1/2*z : y : x) ``ValueError`` is raised if the wrong codomain ``Y`` is specified: @@ -652,8 +676,10 @@ def hom(self, x, Y=None): Traceback (most recent call last): ... ValueError: The matrix x (= [ 0 0 1/2] - [ 0 1 0] - [ 1 0 0]) does not define a map from self (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2) to Y (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2) + [ 0 1 0] + [ 1 0 0]) does not define a map + from self (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2) + to Y (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2) The identity map between two representations of the same conic: @@ -663,10 +689,11 @@ def hom(self, x, Y=None): sage: D = Conic([2,4,6,8,10,12]) sage: C.hom(identity_matrix(3), D) Scheme morphism: - From: Projective Conic Curve over Rational Field defined by x^2 + 2*x*y + 4*y^2 + 3*x*z + 5*y*z + 6*z^2 - To: Projective Conic Curve over Rational Field defined by 2*x^2 + 4*x*y + 8*y^2 + 6*x*z + 10*y*z + 12*z^2 - Defn: Defined on coordinates by sending (x : y : z) to - (x : y : z) + From: Projective Conic Curve over Rational Field + defined by x^2 + 2*x*y + 4*y^2 + 3*x*z + 5*y*z + 6*z^2 + To: Projective Conic Curve over Rational Field + defined by 2*x^2 + 4*x*y + 8*y^2 + 6*x*z + 10*y*z + 12*z^2 + Defn: Defined on coordinates by sending (x : y : z) to (x : y : z) An example not over the rational numbers: @@ -675,13 +702,15 @@ def hom(self, x, Y=None): sage: P.<t> = QQ[] sage: C = Conic([1,0,0,t,0,1/t]) sage: D = Conic([1/t^2, 0, -2/t^2, t, 0, (t + 1)/t^2]) - sage: T = Matrix([[t,0,1],[0,1,0],[0,0,1]]) + sage: T = Matrix([[t,0,1], [0,1,0], [0,0,1]]) sage: C.hom(T, D) Scheme morphism: - From: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Rational Field defined by x^2 + t*y^2 + 1/t*z^2 - To: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Rational Field defined by 1/(t^2)*x^2 + t*y^2 - 2/(t^2)*x*z + (t + 1)/(t^2)*z^2 - Defn: Defined on coordinates by sending (x : y : z) to - (t*x + z : y : z) + From: Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Rational Field defined by x^2 + t*y^2 + 1/t*z^2 + To: Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Rational Field defined by + 1/(t^2)*x^2 + t*y^2 - 2/(t^2)*x*z + (t + 1)/(t^2)*z^2 + Defn: Defined on coordinates by sending (x : y : z) to (t*x + z : y : z) """ if is_Matrix(x): @@ -702,15 +731,15 @@ def hom(self, x, Y=None): def is_diagonal(self): r""" Return True if and only if the conic has the form - `a*x^2 + b*y^2 + c*z^2`. + `a x^2 + b y^2 + c z^2`. EXAMPLES: :: - sage: c=Conic([1,1,0,1,0,1]); c + sage: c = Conic([1,1,0,1,0,1]); c Projective Conic Curve over Rational Field defined by x^2 + x*y + y^2 + z^2 - sage: d,t = c.diagonal_matrix() + sage: d, t = c.diagonal_matrix() sage: c.is_diagonal() False sage: c.diagonalization()[0].is_diagonal() @@ -720,7 +749,7 @@ def is_diagonal(self): def is_smooth(self): r""" - Returns True if and only if ``self`` is smooth. + Return True if and only if ``self`` is smooth. EXAMPLES: @@ -745,31 +774,32 @@ def _magma_init_(self, magma): EXAMPLES:: + sage: # optional - magma sage: C = Conic(QQ, [1,2,3]) - sage: C._magma_init_(magma) # optional - magma + sage: C._magma_init_(magma) 'Conic([_sage_ref...|1/1,2/1,3/1,0/1,0/1,0/1])' - sage: C = Conic(GF(41), [-1,2,5]) # optional - magma - sage: C._magma_init_(magma) # optional - magma + sage: C = Conic(GF(41), [-1,2,5]) + sage: C._magma_init_(magma) 'Conic([_sage_ref...|GF(41)!40,GF(41)!2,GF(41)!5,GF(41)!0,GF(41)!0,GF(41)!0])' - sage: F.<a> = GF(25) - sage: C = Conic([3,0,1,4,a,2]) - sage: C - Projective Conic Curve over Finite Field in a of size 5^2 defined by -2*x^2 - y^2 + x*z + a*y*z + 2*z^2 - sage: magma(C) # optional - magma + sage: F.<a> = GF(25) # needs sage.rings.finite_rings + sage: C = Conic([3,0,1,4,a,2]); C # needs sage.rings.finite_rings + Projective Conic Curve over Finite Field in a of size 5^2 + defined by -2*x^2 - y^2 + x*z + a*y*z + 2*z^2 + sage: magma(C) # needs sage.rings.finite_rings Conic over GF(5^2) defined by 3*X^2 + 4*Y^2 + X*Z + a*Y*Z + 2*Z^2 - sage: magma(Conic([1/2,2/3,-4/5,6/7,8/9,-10/11])) # optional - magma + sage: magma(Conic([1/2,2/3,-4/5,6/7,8/9,-10/11])) Conic over Rational Field defined by 1/2*X^2 + 2/3*X*Y + 6/7*Y^2 - 4/5*X*Z + 8/9*Y*Z - 10/11*Z^2 sage: R.<x> = Frac(QQ['x']) - sage: magma(Conic([x,1+x,1-x])) # optional - magma + sage: magma(Conic([x, 1 + x, 1 - x])) Conic over Univariate rational function field over Rational Field defined by x*X^2 + (x + 1)*Y^2 + (-x + 1)*Z^2 sage: P.<x> = QQ[] - sage: K.<b> = NumberField(x^3+x+1) - sage: magma(Conic([b,1,2])) # optional - magma - Conic over Number Field with defining polynomial x^3 + x + 1 over the Rational Field defined by - b*X^2 + Y^2 + 2*Z^2 + sage: K.<b> = NumberField(x^3 + x + 1) # needs sage.rings.number_field + sage: magma(Conic([b,1,2])) # needs sage.rings.number_field + Conic over Number Field with defining polynomial x^3 + x + 1 + over the Rational Field defined by b*X^2 + Y^2 + 2*Z^2 """ kmn = magma(self.base_ring())._ref() coeffs = self.coefficients() @@ -778,7 +808,7 @@ def _magma_init_(self, magma): def matrix(self): r""" - Returns a matrix `M` such that `(x, y, z) M (x, y, z)^t` + Return a matrix `M` such that `(x, y, z) M (x, y, z)^t` is the defining equation of ``self``. The matrix `M` is upper triangular if the base field has @@ -812,7 +842,7 @@ def parametrization(self, point=None, morphism=True): inverse of `f`. If ``point`` is specified, then that point is used - for the parametrization. Otherwise, use ``self.rational_point()`` + for the parametrization. Otherwise, use :meth:`rational_point()` to find a point. If ``morphism`` is True, then `f` is returned in the form @@ -827,12 +857,12 @@ def parametrization(self, point=None, morphism=True): sage: f, g = c.parametrization(); f, g (Scheme morphism: From: Projective Space of dimension 1 over Finite Field of size 2 - To: Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y - + y^2 + x*z + y*z + To: Projective Conic Curve over Finite Field of size 2 + defined by x^2 + x*y + y^2 + x*z + y*z Defn: Defined on coordinates by sending (x : y) to ..., Scheme morphism: - From: Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y - + y^2 + x*z + y*z + From: Projective Conic Curve over Finite Field of size 2 + defined by x^2 + x*y + y^2 + x*z + y*z To: Projective Space of dimension 1 over Finite Field of size 2 Defn: Defined on coordinates by sending (x : y : z) to ...) sage: set(f(p) for p in f.domain()) @@ -840,16 +870,19 @@ def parametrization(self, point=None, morphism=True): Verfication of the example :: + sage: # needs sage.rings.finite_rings sage: h = g*f; h - Scheme endomorphism of Projective Space of dimension 1 over Finite Field of size 2 + Scheme endomorphism of Projective Space of dimension 1 + over Finite Field of size 2 Defn: Defined on coordinates by sending (x : y) to ... sage: h[0]/h[1] x/y - sage: h.is_one() # known bug (see :trac:`31892`) + sage: h.is_one() # known bug (see :trac:`31892`) True sage: (x,y,z) = c.gens() sage: x.parent() - Quotient of Multivariate Polynomial Ring in x, y, z over Finite Field of size 2 by the ideal (x^2 + x*y + y^2 + x*z + y*z) + Quotient of Multivariate Polynomial Ring in x, y, z + over Finite Field of size 2 by the ideal (x^2 + x*y + y^2 + x*z + y*z) sage: k = f*g sage: k[0]*z-k[2]*x 0 @@ -859,6 +892,7 @@ def parametrization(self, point=None, morphism=True): The morphisms are mathematically defined in all points, but don't work completely in SageMath (see :trac:`31892`) :: + sage: # needs sage.rings.finite_rings sage: f, g = c.parametrization([0,0,1]) sage: g([0,1,1]) (1 : 0) @@ -873,7 +907,7 @@ def parametrization(self, point=None, morphism=True): sage: R.<x,y,z> = QQ[] sage: C = Curve(7*x^2 + 2*y*z + z^2) - sage: (p, i) = C.parametrization(morphism = False); (p, i) + sage: (p, i) = C.parametrization(morphism=False); (p, i) ([-2*x*y, x^2 + 7*y^2, -2*x^2], [-1/2*x, 1/7*y + 1/14*z]) sage: C.defining_polynomial()(p) 0 @@ -886,7 +920,8 @@ def parametrization(self, point=None, morphism=True): sage: C.parametrization() Traceback (most recent call last): ... - ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field! + ValueError: Conic Projective Conic Curve over Rational Field defined by + x^2 + y^2 + 7*z^2 has no rational points over Rational Field! A ``ValueError`` is raised if ``self`` is not smooth :: @@ -894,7 +929,8 @@ def parametrization(self, point=None, morphism=True): sage: C.parametrization() Traceback (most recent call last): ... - ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization. + ValueError: The conic self (=Projective Conic Curve over Rational Field + defined by x^2 + y^2) is not smooth, hence does not have a parametrization. """ if (self._parametrization is not None) and not point: par = self._parametrization @@ -937,7 +973,7 @@ def point(self, v, check=True): point on ``self``. If no rational point on ``self`` is known yet, then also caches the point - for use by ``self.rational_point()`` and ``self.parametrization()``. + for use by :meth:`rational_point` and :meth:`parametrization`. EXAMPLES:: @@ -963,13 +999,11 @@ def random_rational_point(self, *args1, **args2): ALGORITHM: - 1. Compute a parametrization `f` of ``self`` using - ``self.parametrization()``. - 2. Computes a random point `(x:y)` on the projective - line. - 3. Output `f(x:y)`. + 1. Compute a parametrization `f` of ``self`` using :meth:`parametrization`. + 2. Computes a random point `(x:y)` on the projective line. + 3. Output `f(x:y)`. - The coordinates x and y are computed using + The coordinates `x` and `y` are computed using ``B.random_element``, where ``B`` is the base field of ``self`` and additional arguments to ``random_rational_point`` are passed to ``random_element``. @@ -980,17 +1014,19 @@ def random_rational_point(self, *args1, **args2): EXAMPLES:: sage: c = Conic(GF(2), [1,1,1,1,1,0]) - sage: [c.random_rational_point() for i in range(10)] # output is random - [(1 : 0 : 1), (1 : 0 : 1), (1 : 0 : 1), (0 : 1 : 1), (1 : 0 : 1), (0 : 0 : 1), (1 : 0 : 1), (1 : 0 : 1), (0 : 0 : 1), (1 : 0 : 1)] + sage: [c.random_rational_point() for i in range(10)] # random + [(1 : 0 : 1), (1 : 0 : 1), (1 : 0 : 1), (0 : 1 : 1), (1 : 0 : 1), + (0 : 0 : 1), (1 : 0 : 1), (1 : 0 : 1), (0 : 0 : 1), (1 : 0 : 1)] sage: d = Conic(QQ, [1, 1, -1]) - sage: d.random_rational_point(den_bound = 1, num_bound = 5) # output is random + sage: d.random_rational_point(den_bound=1, num_bound=5) # random (-24/25 : 7/25 : 1) sage: Conic(QQ, [1, 1, 1]).random_rational_point() Traceback (most recent call last): ... - ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2 has no rational points over Rational Field! + ValueError: Conic Projective Conic Curve over Rational Field defined by + x^2 + y^2 + z^2 has no rational points over Rational Field! """ if not self.is_smooth(): @@ -1027,30 +1063,34 @@ def rational_point(self, algorithm='default', read_cache=True): sage: C.rational_point() Traceback (most recent call last): ... - ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field! + ValueError: Conic Projective Conic Curve over Rational Field defined by + x^2 + 2*y^2 + z^2 has no rational points over Rational Field! sage: C = Conic(x^2 + y^2 + 7*z^2) - sage: C.rational_point(algorithm = 'rnfisnorm') + sage: C.rational_point(algorithm='rnfisnorm') Traceback (most recent call last): ... - ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field! + ValueError: Conic Projective Conic Curve over Rational Field defined by + x^2 + y^2 + 7*z^2 has no rational points over Rational Field! Examples over number fields :: + sage: # needs sage.rings.number_field sage: P.<x> = QQ[] - sage: L.<b> = NumberField(x^3-5) + sage: L.<b> = NumberField(x^3 - 5) sage: C = Conic(L, [3, 2, -b]) - sage: p = C.rational_point(algorithm = 'rnfisnorm') + sage: p = C.rational_point(algorithm='rnfisnorm') sage: p # output is random (1/3*b^2 - 4/3*b + 4/3 : b^2 - 2 : 1) sage: C.defining_polynomial()(list(p)) 0 - sage: K.<i> = QuadraticField(-1) - sage: D = Conic(K, [3, 2, 5]) - sage: D.rational_point(algorithm = 'rnfisnorm') # output is random + sage: K.<i> = QuadraticField(-1) # needs sage.rings.number_field + sage: D = Conic(K, [3, 2, 5]) # needs sage.rings.number_field + sage: D.rational_point(algorithm='rnfisnorm') # output is random # needs sage.rings.number_field (-3 : 4*i : 1) + sage: # needs sage.rings.number_field sage: L.<s> = QuadraticField(2) sage: Conic(QQ, [1, 1, -3]).has_rational_point() False @@ -1061,53 +1101,70 @@ def rational_point(self, algorithm='default', read_cache=True): Currently Magma is better at solving conics over number fields than Sage, so it helps to use the algorithm 'magma' if Magma is installed:: - sage: q = C.rational_point(algorithm = 'magma', read_cache=False) # optional - magma - sage: q # output is random, optional - magma + sage: # optional - magma, needs sage.rings.number_field + sage: q = C.rational_point(algorithm='magma', + ....: read_cache=False) + sage: q # output is random (1/5*b^2 : 1/5*b^2 : 1) - sage: C.defining_polynomial()(list(q)) # optional - magma + sage: C.defining_polynomial()(list(q)) 0 - sage: len(str(p)) > 1.5*len(str(q)) # optional - magma + sage: len(str(p)) > 1.5*len(str(q)) True - - sage: D.rational_point(algorithm = 'magma', read_cache=False) # random, optional - magma + sage: D.rational_point(algorithm='magma', # random + ....: read_cache=False) (1 : 2*i : 1) - - sage: E.rational_point(algorithm='magma', read_cache=False) # random, optional - magma + sage: E.rational_point(algorithm='magma', # random + ....: read_cache=False) (-s : 1 : 1) + sage: # needs sage.rings.number_field sage: F = Conic([L.gen(), 30, -20]) - sage: q = F.rational_point(algorithm='magma') # optional - magma - sage: q # output is random, optional - magma + sage: q = F.rational_point(algorithm='magma') # optional - magma + sage: q # random # optional - magma (-10/7*s + 40/7 : 5/7*s - 6/7 : 1) sage: p = F.rational_point(read_cache=False) - sage: p # output is random + sage: p # random (788210*s - 1114700 : -171135*s + 242022 : 1) - sage: len(str(p)) > len(str(q)) # optional - magma + sage: len(str(p)) > len(str(q)) # optional - magma True + sage: # needs sage.rings.number_field sage: G = Conic([L.gen(), 30, -21]) - sage: G.has_rational_point(algorithm='magma') # optional - magma + sage: G.has_rational_point(algorithm='magma') # optional - magma False sage: G.has_rational_point(read_cache=False) False - sage: G.has_rational_point(algorithm='local', read_cache=False) + sage: G.has_rational_point(algorithm='local', + ....: read_cache=False) False - sage: G.rational_point(algorithm='magma') # optional - magma + sage: G.rational_point(algorithm='magma') # optional - magma Traceback (most recent call last): ... - ValueError: Conic Projective Conic Curve over Number Field in s with defining polynomial x^2 - 2 with s = 1.414213562373095? defined by s*x^2 + 30*y^2 - 21*z^2 has no rational points over Number Field in s with defining polynomial x^2 - 2 with s = 1.414213562373095?! - sage: G.rational_point(algorithm='magma', read_cache=False) # optional - magma + ValueError: Conic Projective Conic Curve over Number Field in s + with defining polynomial x^2 - 2 with s = 1.414213562373095? + defined by s*x^2 + 30*y^2 - 21*z^2 has no rational points over + Number Field in s with defining polynomial x^2 - 2 with s = 1.414213562373095?! + sage: G.rational_point(algorithm='magma', # optional - magma + ....: read_cache=False) Traceback (most recent call last): ... - ValueError: Conic Projective Conic Curve over Number Field in s with defining polynomial x^2 - 2 with s = 1.414213562373095? defined by s*x^2 + 30*y^2 - 21*z^2 has no rational points over Number Field in s with defining polynomial x^2 - 2 with s = 1.414213562373095?! + ValueError: Conic Projective Conic Curve over Number Field in s + with defining polynomial x^2 - 2 with s = 1.414213562373095? + defined by s*x^2 + 30*y^2 - 21*z^2 has no rational points over + Number Field in s with defining polynomial x^2 - 2 with s = 1.414213562373095?! Examples over finite fields :: - sage: F.<a> = FiniteField(7^20) - sage: C = Conic([1, a, -5]); C - Projective Conic Curve over Finite Field in a of size 7^20 defined by x^2 + a*y^2 + 2*z^2 - sage: C.rational_point() # output is random - (4*a^19 + 5*a^18 + 4*a^17 + a^16 + 6*a^15 + 3*a^13 + 6*a^11 + a^9 + 3*a^8 + 2*a^7 + 4*a^6 + 3*a^5 + 3*a^4 + a^3 + a + 6 : 5*a^18 + a^17 + a^16 + 6*a^15 + 4*a^14 + a^13 + 5*a^12 + 5*a^10 + 2*a^9 + 6*a^8 + 6*a^7 + 6*a^6 + 2*a^4 + 3 : 1) + sage: F.<a> = FiniteField(7^20) # needs sage.rings.finite_rings + sage: C = Conic([1, a, -5]); C # needs sage.rings.finite_rings + Projective Conic Curve over Finite Field in a of size 7^20 + defined by x^2 + a*y^2 + 2*z^2 + sage: C.rational_point() # output is random # needs sage.rings.finite_rings + (4*a^19 + 5*a^18 + 4*a^17 + a^16 + 6*a^15 + 3*a^13 + 6*a^11 + a^9 + + 3*a^8 + 2*a^7 + 4*a^6 + 3*a^5 + 3*a^4 + a^3 + a + 6 + : 5*a^18 + a^17 + a^16 + 6*a^15 + 4*a^14 + a^13 + 5*a^12 + 5*a^10 + + 2*a^9 + 6*a^8 + 6*a^7 + 6*a^6 + 2*a^4 + 3 + : 1) Examples over `\RR` and `\CC` :: @@ -1117,7 +1174,9 @@ def rational_point(self, algorithm='default', read_cache=True): sage: Conic(RR, [1, 1, 1]).rational_point() Traceback (most recent call last): ... - ValueError: Conic Projective Conic Curve over Real Field with 53 bits of precision defined by x^2 + y^2 + z^2 has no rational points over Real Field with 53 bits of precision! + ValueError: Conic Projective Conic Curve over Real Field + with 53 bits of precision defined by x^2 + y^2 + z^2 has + no rational points over Real Field with 53 bits of precision! """ bl, pt = self.has_rational_point(point=True, algorithm=algorithm, read_cache=read_cache) @@ -1128,7 +1187,7 @@ def rational_point(self, algorithm='default', read_cache=True): def singular_point(self): r""" - Returns a singular rational point of ``self`` + Return a singular rational point of ``self``. EXAMPLES: @@ -1144,7 +1203,8 @@ def singular_point(self): sage: Conic(QQ, [1,1,1,1,1,1]).singular_point() Traceback (most recent call last): ... - ValueError: The conic self (= Projective Conic Curve over Rational Field defined by x^2 + x*y + y^2 + x*z + y*z + z^2) has no rational singular point + ValueError: The conic self (= Projective Conic Curve over Rational Field + defined by x^2 + x*y + y^2 + x*z + y*z + z^2) has no rational singular point """ b = self.has_singular_point(point=True) if not b[0]: @@ -1209,14 +1269,13 @@ def upper_triangular_matrix(self): def variable_names(self): r""" - Returns the variable names of the defining polynomial - of ``self``. + Return the variable names of the defining polynomial of ``self``. EXAMPLES: :: - sage: c=Conic([1,1,0,1,0,1], 'x,y,z') + sage: c = Conic([1,1,0,1,0,1], 'x,y,z') sage: c.variable_names() ('x', 'y', 'z') sage: c.variable_name() diff --git a/src/sage/schemes/plane_conics/con_finite_field.py b/src/sage/schemes/plane_conics/con_finite_field.py index 7eb316746f3..e62d8db828f 100644 --- a/src/sage/schemes/plane_conics/con_finite_field.py +++ b/src/sage/schemes/plane_conics/con_finite_field.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings r""" Projective plane conics over finite fields @@ -37,7 +38,8 @@ class ProjectiveConic_finite_field(ProjectiveConic_field, ProjectivePlaneCurve_f sage: K.<a> = FiniteField(9, 'a') sage: P.<X, Y, Z> = K[] sage: Conic(X^2 + Y^2 - a*Z^2) - Projective Conic Curve over Finite Field in a of size 3^2 defined by X^2 + Y^2 + (-a)*Z^2 + Projective Conic Curve over Finite Field in a of size 3^2 + defined by X^2 + Y^2 + (-a)*Z^2 :: @@ -94,36 +96,50 @@ def has_rational_point(self, point=False, read_cache=True, True sage: C = Conic(FiniteField(2), [1, 1, 1, 1, 1, 0]); C - Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z + Projective Conic Curve over Finite Field of size 2 + defined by x^2 + x*y + y^2 + x*z + y*z sage: C.has_rational_point(point = True) # output is random (True, (0 : 0 : 1)) sage: p = next_prime(10^50) sage: F = FiniteField(p) sage: C = Conic(F, [1, 2, 3]); C - Projective Conic Curve over Finite Field of size 100000000000000000000000000000000000000000000000151 defined by x^2 + 2*y^2 + 3*z^2 + Projective Conic Curve over Finite Field + of size 100000000000000000000000000000000000000000000000151 + defined by x^2 + 2*y^2 + 3*z^2 sage: C.has_rational_point(point = True) # output is random (True, - (14971942941468509742682168602989039212496867586852 : 75235465708017792892762202088174741054630437326388 : 1) + (14971942941468509742682168602989039212496867586852 + : 75235465708017792892762202088174741054630437326388 : 1) sage: F.<a> = FiniteField(7^20) sage: C = Conic([1, a, -5]); C - Projective Conic Curve over Finite Field in a of size 7^20 defined by x^2 + a*y^2 + 2*z^2 + Projective Conic Curve over Finite Field in a of size 7^20 + defined by x^2 + a*y^2 + 2*z^2 sage: C.has_rational_point(point = True) # output is random (True, - (a^18 + 2*a^17 + 4*a^16 + 6*a^13 + a^12 + 6*a^11 + 3*a^10 + 4*a^9 + 2*a^8 + 4*a^7 + a^6 + 4*a^4 + 6*a^2 + 3*a + 6 : 5*a^19 + 5*a^18 + 5*a^17 + a^16 + 2*a^15 + 3*a^14 + 4*a^13 + 5*a^12 + a^11 + 3*a^10 + 2*a^8 + 3*a^7 + 4*a^6 + 4*a^5 + 6*a^3 + 5*a^2 + 2*a + 4 : 1)) + (a^18 + 2*a^17 + 4*a^16 + 6*a^13 + a^12 + 6*a^11 + 3*a^10 + 4*a^9 + 2*a^8 + + 4*a^7 + a^6 + 4*a^4 + 6*a^2 + 3*a + 6 + : 5*a^19 + 5*a^18 + 5*a^17 + a^16 + 2*a^15 + 3*a^14 + 4*a^13 + 5*a^12 + + a^11 + 3*a^10 + 2*a^8 + 3*a^7 + 4*a^6 + 4*a^5 + 6*a^3 + 5*a^2 + 2*a + 4 + : 1)) TESTS:: sage: l = Sequence(cartesian_product_iterator([[0, 1] for i in range(6)])) sage: bigF = GF(next_prime(2^100)) sage: bigF2 = GF(next_prime(2^50)^2, 'b') - sage: m = [[F(b) for b in a] for a in l for F in [GF(2), GF(4, 'a'), GF(5), GF(9, 'a'), bigF, bigF2]] - sage: m += [[F.random_element() for i in range(6)] for j in range(20) for F in [GF(5), bigF]] + sage: m = [[F(b) for b in a] + ....: for a in l + ....: for F in [GF(2), GF(4, 'a'), GF(5), GF(9, 'a'), bigF, bigF2]] + sage: m += [[F.random_element() for i in range(6)] + ....: for j in range(20) for F in [GF(5), bigF]] sage: c = [Conic(a) for a in m if a != [0,0,0,0,0,0]] sage: assert all(C.has_rational_point() for C in c) sage: r = randrange(0, 5) - sage: assert all(C.defining_polynomial()(Sequence(C.has_rational_point(point = True)[1])) == 0 for C in c[r::5]) # long time (1.4s on sage.math, 2013) + sage: assert all(C.defining_polynomial()( # long time (1.4s on sage.math, 2013) + ....: Sequence(C.has_rational_point(point=True)[1])) == 0 + ....: for C in c[r::5]) """ if not point: return True diff --git a/src/sage/schemes/plane_conics/con_number_field.py b/src/sage/schemes/plane_conics/con_number_field.py index 4d2c55f36d9..19be6d237a8 100644 --- a/src/sage/schemes/plane_conics/con_number_field.py +++ b/src/sage/schemes/plane_conics/con_number_field.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.number_field r""" Projective plane conics over a number field @@ -36,7 +37,8 @@ class ProjectiveConic_number_field(ProjectiveConic_field): sage: K.<a> = NumberField(x^3 - 2, 'a') sage: P.<X, Y, Z> = K[] sage: Conic(X^2 + Y^2 - a*Z^2) - Projective Conic Curve over Number Field in a with defining polynomial x^3 - 2 defined by X^2 + Y^2 + (-a)*Z^2 + Projective Conic Curve over Number Field in a with defining polynomial x^3 - 2 + defined by X^2 + Y^2 + (-a)*Z^2 TESTS:: @@ -64,7 +66,7 @@ def __init__(self, A, f): def has_rational_point(self, point=False, obstruction=False, algorithm='default', read_cache=True): r""" - Returns ``True`` if and only if ``self`` has a point + Return ``True`` if and only if ``self`` has a point defined over its base field `B`. If ``point`` and ``obstruction`` are both False (default), @@ -74,12 +76,12 @@ def has_rational_point(self, point=False, obstruction=False, If ``point`` or ``obstruction`` is True, then the output is a pair ``(out, S)``, where ``out`` is as above and: - - if ``point`` is True and ``self`` has a rational point, - then ``S`` is a rational point, + - if ``point`` is True and ``self`` has a rational point, + then ``S`` is a rational point, - - if ``obstruction`` is True, ``self`` has no rational point, - then ``S`` is a prime or infinite place of `B` such that no - rational point exists over the completion at ``S``. + - if ``obstruction`` is True, ``self`` has no rational point, + then ``S`` is a prime or infinite place of `B` such that no + rational point exists over the completion at ``S``. Points and obstructions are cached whenever they are found. Cached information is used for the output if available, but only @@ -90,20 +92,20 @@ def has_rational_point(self, point=False, obstruction=False, The parameter ``algorithm`` specifies the algorithm to be used: - - ``'rnfisnorm'`` -- Use PARI's rnfisnorm - (cannot be combined with ``obstruction = True``) + - ``'rnfisnorm'`` -- Use PARI's ``rnfisnorm`` + (cannot be combined with ``obstruction = True``) - - ``'local'`` -- Check if a local solution exists for all primes - and infinite places of `B` and apply the Hasse principle. - (Cannot be combined with ``point = True``.) + - ``'local'`` -- Check if a local solution exists for all primes + and infinite places of `B` and apply the Hasse principle. + (Cannot be combined with ``point = True``.) - - ``'default'`` -- Use algorithm ``'rnfisnorm'`` first. - Then, if no point exists and obstructions are requested, use - algorithm ``'local'`` to find an obstruction. + - ``'default'`` -- Use algorithm ``'rnfisnorm'`` first. + Then, if no point exists and obstructions are requested, use + algorithm ``'local'`` to find an obstruction. - - ``'magma'`` (requires Magma to be installed) -- - delegates the task to the Magma computer algebra - system. + - ``'magma'`` (requires Magma to be installed) -- + delegates the task to the Magma computer algebra + system. EXAMPLES: @@ -111,28 +113,30 @@ def has_rational_point(self, point=False, obstruction=False, An example over `\QQ` :: sage: C = Conic(QQ, [1, 113922743, -310146482690273725409]) - sage: C.has_rational_point(point = True) + sage: C.has_rational_point(point=True) (True, (-76842858034579/5424 : -5316144401/5424 : 1)) - sage: C.has_rational_point(algorithm = 'local', read_cache = False) + sage: C.has_rational_point(algorithm='local', read_cache=False) True Examples over number fields:: sage: K.<i> = QuadraticField(-1) sage: C = Conic(K, [1, 3, -5]) - sage: C.has_rational_point(point = True, obstruction = True) + sage: C.has_rational_point(point=True, obstruction=True) (False, Fractional ideal (-i - 2)) - sage: C.has_rational_point(algorithm = "rnfisnorm") + sage: C.has_rational_point(algorithm="rnfisnorm") False - sage: C.has_rational_point(algorithm = "rnfisnorm", obstruction = True, read_cache=False) + sage: C.has_rational_point(algorithm="rnfisnorm", obstruction=True, + ....: read_cache=False) Traceback (most recent call last): ... - ValueError: Algorithm rnfisnorm cannot be combined with obstruction = True in has_rational_point + ValueError: Algorithm rnfisnorm cannot be combined with + obstruction = True in has_rational_point sage: P.<x> = QQ[] - sage: L.<b> = NumberField(x^3-5) + sage: L.<b> = NumberField(x^3 - 5) sage: C = Conic(L, [1, 2, -3]) - sage: C.has_rational_point(point = True, algorithm = 'rnfisnorm') + sage: C.has_rational_point(point=True, algorithm='rnfisnorm') (True, (5/3 : -1/3 : 1)) sage: K.<a> = NumberField(x^4+2) @@ -140,7 +144,8 @@ def has_rational_point(self, point=False, obstruction=False, False sage: Conic(K, [4,5,6]).has_rational_point() True - sage: Conic(K, [4,5,6]).has_rational_point(algorithm='magma', read_cache=False) # optional - magma + sage: Conic(K, [4,5,6]).has_rational_point(algorithm='magma', # optional - magma + ....: read_cache=False) True sage: P.<a> = QuadraticField(2) @@ -152,13 +157,15 @@ def has_rational_point(self, point=False, obstruction=False, sage: C.has_rational_point(obstruction=True) (False, Ring morphism: - From: Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? + From: Number Field in a with defining polynomial x^2 - 2 + with a = 1.414213562373095? To: Algebraic Real Field Defn: a |--> -1.414213562373095?) sage: C.has_rational_point(point=True, obstruction=True) (False, Ring morphism: - From: Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? + From: Number Field in a with defining polynomial x^2 - 2 + with a = 1.414213562373095? To: Algebraic Real Field Defn: a |--> -1.414213562373095?) @@ -182,12 +189,12 @@ def has_rational_point(self, point=False, obstruction=False, sage: d = [] sage: c = [] sage: c = [Conic(a) for a in m if a != [0,0,0]] - sage: d = [C.has_rational_point(algorithm = 'rnfisnorm', point = True) for C in c] # long time: 3.3 seconds + sage: d = [C.has_rational_point(algorithm='rnfisnorm', point=True) for C in c] # long time: 3.3 seconds sage: all(c[k].defining_polynomial()(Sequence(d[k][1])) == 0 for k in range(len(d)) if d[k][0]) True sage: [C.has_rational_point(algorithm='local', read_cache=False) for C in c] == [o[0] for o in d] # long time: 5 seconds True - sage: [C.has_rational_point(algorithm = 'magma', read_cache=False) for C in c] == [o[0] for o in d] # long time: 3 seconds, optional - magma + sage: [C.has_rational_point(algorithm='magma', read_cache=False) for C in c] == [o[0] for o in d] # long time: 3 seconds, optional - magma True Create a bunch of conics that are known to have rational points @@ -200,8 +207,8 @@ def has_rational_point(self, point=False, obstruction=False, sage: M.<c> = NumberField(x^5+3*x+1) sage: m = [[F(b) for b in a] for a in l for F in [K, L, M]] sage: c = [Conic(a) for a in m if a != [0,0,0] and a != [1,1,1] and a != [-1,-1,-1]] - sage: assert all(C.has_rational_point(algorithm = 'rnfisnorm') for C in c) - sage: assert all(C.defining_polynomial()(Sequence(C.has_rational_point(point = True)[1])) == 0 for C in c) + sage: assert all(C.has_rational_point(algorithm='rnfisnorm') for C in c) + sage: assert all(C.defining_polynomial()(Sequence(C.has_rational_point(point=True)[1])) == 0 for C in c) sage: assert all(C.has_rational_point(algorithm='local', read_cache=False) for C in c) # long time: 1 second """ if read_cache: @@ -332,7 +339,7 @@ def has_rational_point(self, point=False, obstruction=False, def is_locally_solvable(self, p): r""" - Returns ``True`` if and only if ``self`` has a solution over the + Return ``True`` if and only if ``self`` has a solution over the completion of the base field `B` of ``self`` at ``p``. Here ``p`` is a finite prime or infinite place of `B`. @@ -381,7 +388,7 @@ def is_locally_solvable(self, p): def local_obstructions(self, finite=True, infinite=True, read_cache=True): r""" - Returns the sequence of finite primes and/or infinite places + Return the sequence of finite primes and/or infinite places such that ``self`` is locally solvable at those primes and places. If the base field is `\QQ`, then the infinite place is denoted `-1`. @@ -403,10 +410,13 @@ def local_obstructions(self, finite=True, infinite=True, read_cache=True): sage: L.<a> = QuadraticField(5) sage: Conic(L, [1, 2, 3]).local_obstructions() [Ring morphism: - From: Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? + From: Number Field in a with defining polynomial x^2 - 5 + with a = 2.236067977499790? To: Algebraic Real Field - Defn: a |--> -2.236067977499790?, Ring morphism: - From: Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? + Defn: a |--> -2.236067977499790?, + Ring morphism: + From: Number Field in a with defining polynomial x^2 - 5 + with a = 2.236067977499790? To: Algebraic Real Field Defn: a |--> 2.236067977499790?] """ diff --git a/src/sage/schemes/plane_conics/con_rational_field.py b/src/sage/schemes/plane_conics/con_rational_field.py index 9a75336901f..46de65132b5 100644 --- a/src/sage/schemes/plane_conics/con_rational_field.py +++ b/src/sage/schemes/plane_conics/con_rational_field.py @@ -24,7 +24,9 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import (PolynomialRing, ZZ, QQ) +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ import sage.rings.abc @@ -38,7 +40,8 @@ from sage.structure.element import InfinityElement -from sage.arith.all import lcm, hilbert_symbol +from sage.arith.functions import lcm +from sage.arith.misc import hilbert_symbol class ProjectiveConic_rational_field(ProjectiveConic_number_field): @@ -81,12 +84,12 @@ def has_rational_point(self, point=False, obstruction=False, a pair ``(out, S)``, where ``out`` is as above and the following holds: - - if ``point`` is ``True`` and ``self`` has a rational point, - then ``S`` is a rational point, + - if ``point`` is ``True`` and ``self`` has a rational point, + then ``S`` is a rational point, - - if ``obstruction`` is ``True`` and ``self`` has no rational point, - then ``S`` is a prime such that no rational point exists - over the completion at ``S`` or `-1` if no point exists over `\RR`. + - if ``obstruction`` is ``True`` and ``self`` has no rational point, + then ``S`` is a prime such that no rational point exists + over the completion at ``S`` or `-1` if no point exists over `\RR`. Points and obstructions are cached, whenever they are found. Cached information is used if and only if ``read_cache`` is ``True``. @@ -96,43 +99,44 @@ def has_rational_point(self, point=False, obstruction=False, The parameter ``algorithm`` specifies the algorithm to be used: - - ``'qfsolve'`` -- Use PARI/GP function :pari:`qfsolve` + - ``'qfsolve'`` -- Use PARI/GP function :pari:`qfsolve` - - ``'rnfisnorm'`` -- Use PARI's function :pari:`rnfisnorm` - (cannot be combined with ``obstruction = True``) + - ``'rnfisnorm'`` -- Use PARI's function :pari:`rnfisnorm` + (cannot be combined with ``obstruction = True``) - - ``'local'`` -- Check if a local solution exists for all primes - and infinite places of `\QQ` and apply the Hasse principle - (cannot be combined with ``point = True``) + - ``'local'`` -- Check if a local solution exists for all primes + and infinite places of `\QQ` and apply the Hasse principle + (cannot be combined with ``point = True``) - - ``'default'`` -- Use ``'qfsolve'`` + - ``'default'`` -- Use ``'qfsolve'`` - - ``'magma'`` (requires Magma to be installed) -- - delegates the task to the Magma computer algebra system. + - ``'magma'`` (requires Magma to be installed) -- + delegates the task to the Magma computer algebra system. EXAMPLES:: sage: C = Conic(QQ, [1, 2, -3]) - sage: C.has_rational_point(point = True) + sage: C.has_rational_point(point=True) (True, (1 : 1 : 1)) sage: D = Conic(QQ, [1, 3, -5]) - sage: D.has_rational_point(point = True) + sage: D.has_rational_point(point=True) (False, 3) sage: P.<X,Y,Z> = QQ[] sage: E = Curve(X^2 + Y^2 + Z^2); E Projective Conic Curve over Rational Field defined by X^2 + Y^2 + Z^2 - sage: E.has_rational_point(obstruction = True) + sage: E.has_rational_point(obstruction=True) (False, -1) The following would not terminate quickly with ``algorithm = 'rnfisnorm'`` :: sage: C = Conic(QQ, [1, 113922743, -310146482690273725409]) - sage: C.has_rational_point(point = True) + sage: C.has_rational_point(point=True) (True, (-76842858034579/5424 : -5316144401/5424 : 1)) - sage: C.has_rational_point(algorithm = 'local', read_cache = False) + sage: C.has_rational_point(algorithm='local', read_cache=False) True - sage: C.has_rational_point(point=True, algorithm='magma', read_cache=False) # optional - magma + sage: C.has_rational_point(point=True, algorithm='magma', # optional - magma + ....: read_cache=False) (True, (30106379962113/7913 : 12747947692/7913 : 1)) TESTS: @@ -143,7 +147,11 @@ def has_rational_point(self, point=False, obstruction=False, sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(6)])) sage: c = [Conic(QQ, a) for a in l if a != [0,0,0] and a != (0,0,0,0,0,0)] sage: d = [] - sage: d = [[C]+[C.has_rational_point(algorithm = algorithm, read_cache = False, obstruction = (algorithm != 'rnfisnorm'), point = (algorithm != 'local')) for algorithm in ['local', 'qfsolve', 'rnfisnorm']] for C in c[::10]] # long time: 7 seconds + sage: d = [[C] + [C.has_rational_point(algorithm=algorithm, read_cache=False, # long time: 7 seconds + ....: obstruction=(algorithm != 'rnfisnorm'), + ....: point=(algorithm != 'local')) + ....: for algorithm in ['local', 'qfsolve', 'rnfisnorm']] + ....: for C in c[::10]] sage: assert all(e[1][0] == e[2][0] and e[1][0] == e[3][0] for e in d) sage: assert all(e[0].defining_polynomial()(Sequence(e[i][1])) == 0 for e in d for i in [2,3] if e[1][0]) """ @@ -339,7 +347,7 @@ def parametrization(self, point=None, morphism=True): sage: R.<x,y,z> = QQ[] sage: C = Curve(7*x^2 + 2*y*z + z^2) - sage: (p, i) = C.parametrization(morphism = False); (p, i) + sage: (p, i) = C.parametrization(morphism=False); (p, i) ([-2*x*y, x^2 + 7*y^2, -2*x^2], [-1/2*x, 1/7*y + 1/14*z]) sage: C.defining_polynomial()(p) 0 @@ -352,7 +360,8 @@ def parametrization(self, point=None, morphism=True): sage: C.parametrization() Traceback (most recent call last): ... - ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field! + ValueError: Conic Projective Conic Curve over Rational Field defined + by x^2 + 2*y^2 + z^2 has no rational points over Rational Field! A ``ValueError`` is raised if ``self`` is not smooth :: @@ -360,7 +369,8 @@ def parametrization(self, point=None, morphism=True): sage: C.parametrization() Traceback (most recent call last): ... - ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization. + ValueError: The conic self (=Projective Conic Curve over Rational Field defined + by x^2 + y^2) is not smooth, hence does not have a parametrization. """ if (self._parametrization is not None) and not point: par = self._parametrization diff --git a/src/sage/schemes/plane_conics/con_rational_function_field.py b/src/sage/schemes/plane_conics/con_rational_function_field.py index 0d1d457f085..1b3f0ac412a 100644 --- a/src/sage/schemes/plane_conics/con_rational_function_field.py +++ b/src/sage/schemes/plane_conics/con_rational_function_field.py @@ -24,8 +24,8 @@ Points can be found using :meth:`has_rational_point`:: sage: K.<t> = FractionField(QQ['t']) - sage: C = Conic([1,-t,t]) - sage: C.has_rational_point(point = True) + sage: C = Conic([1, -t, t]) + sage: C.has_rational_point(point=True) (True, (0 : 1 : 1)) """ @@ -42,7 +42,8 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.matrix.constructor import diagonal_matrix, matrix, block_matrix from sage.schemes.plane_conics.con_field import ProjectiveConic_field -from sage.arith.all import lcm, gcd +from sage.arith.functions import lcm +from sage.arith.misc import GCD as gcd from sage.modules.free_module_element import vector from sage.rings.fraction_field import is_FractionField @@ -126,18 +127,21 @@ def has_rational_point(self, point=False, algorithm='default', and finite fields:: sage: K.<t> = FractionField(PolynomialRing(QQ, 't')) - sage: C = Conic(K, [t^2-2, 2*t^3, -2*t^3-13*t^2-2*t+18]) + sage: C = Conic(K, [t^2 - 2, 2*t^3, -2*t^3 - 13*t^2 - 2*t + 18]) sage: C.has_rational_point(point=True) (True, (-3 : (t + 1)/t : 1)) + sage: R.<t> = FiniteField(23)[] - sage: C = Conic([2, t^2+1, t^2+5]) + sage: C = Conic([2, t^2 + 1, t^2 + 5]) sage: C.has_rational_point() True sage: C.has_rational_point(point=True) (True, (5*t : 8 : 1)) + + sage: # needs sage.rings.number_field sage: F.<i> = QuadraticField(-1) sage: R.<t> = F[] - sage: C = Conic([1,i*t,-t^2+4]) + sage: C = Conic([1, i*t, -t^2 + 4]) sage: C.has_rational_point(point=True) (True, (-t - 2*i : -2*i : 1)) @@ -164,8 +168,8 @@ def has_rational_point(self, point=False, algorithm='default', sage: F.<t1> = FractionField(QQ['t1']) sage: K.<t2> = FractionField(F['t2']) sage: a = K(1) - sage: b = 2*t2^2+2*t1*t2-t1^2 - sage: c = -3*t2^4-4*t1*t2^3+8*t1^2*t2^2+16*t1^3-t2-48*t1^4 + sage: b = 2*t2^2 + 2*t1*t2 - t1^2 + sage: c = -3*t2^4 - 4*t1*t2^3 + 8*t1^2*t2^2 + 16*t1^3 - t2 - 48*t1^4 sage: C = Conic([a,b,c]) sage: C.has_rational_point() Traceback (most recent call last): @@ -184,9 +188,9 @@ def has_rational_point(self, point=False, algorithm='default', sage: Q.<Y> = E[] sage: F.<v> = E.extension(Y^2 - u^3 - 1) sage: R.<t> = F[] - sage: K = R.fraction_field() - sage: C = Conic(K, [u, v, 1]) - sage: C.has_rational_point() + sage: K = R.fraction_field() # needs sage.rings.function_field + sage: C = Conic(K, [u, v, 1]) # needs sage.rings.function_field + sage: C.has_rational_point() # needs sage.rings.function_field Traceback (most recent call last): ... NotImplementedError: has_rational_point not implemented for conics @@ -198,19 +202,31 @@ def has_rational_point(self, point=False, algorithm='default', over finite fields, due to :trac:`20003`:: sage: K.<t> = PolynomialRing(GF(7)) - sage: C = Conic([5*t^2+4, t^2+3*t+3, 6*t^2+3*t+2, 5*t^2+5, 4*t+3, 4*t^2+t+5]) + sage: C = Conic([5*t^2 + 4, t^2 + 3*t + 3, 6*t^2 + 3*t + 2, + ....: 5*t^2 + 5, 4*t + 3, 4*t^2 + t + 5]) sage: C.has_rational_point() Traceback (most recent call last): ... TypeError: self (=Scheme morphism: - From: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (-2*t^2 - 3)*x^2 + (-t^3 + 3*t^2 - 2*t - 2)/(t + 3)*y^2 + (-t^6 + 3*t^5 + t^3 - t^2 - t + 2)/(t^4 + t^3 - 3*t^2 + 3*t + 1)*z^2 - To: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (-2*t^2 - 3)*x^2 + (t^2 + 3*t + 3)*x*y + (-2*t^2 - 2)*y^2 + (-t^2 + 3*t + 2)*x*z + (-3*t + 3)*y*z + (-3*t^2 + t - 2)*z^2 + From: Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Finite Field of size 7 defined by + (-2*t^2 - 3)*x^2 + (-t^3 + 3*t^2 - 2*t - 2)/(t + 3)*y^2 + (-t^6 + 3*t^5 + t^3 - t^2 - t + 2)/(t^4 + t^3 - 3*t^2 + 3*t + 1)*z^2 + To: Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Finite Field of size 7 defined by + (-2*t^2 - 3)*x^2 + (t^2 + 3*t + 3)*x*y + (-2*t^2 - 2)*y^2 + (-t^2 + 3*t + 2)*x*z + (-3*t + 3)*y*z + (-3*t^2 + t - 2)*z^2 Defn: Defined on coordinates by sending (x : y : z) to - (x + (2*t - 2)/(t + 3)*y + (3*t^4 + 2*t^3 - 2*t^2 - 2*t + 3)/(t^4 + t^3 - 3*t^2 + 3*t + 1)*z : y + (-t^3 - t^2 + 3*t - 1)/(t^3 - 3*t^2 + 2*t + 2)*z : z)) domain must equal right (=Scheme morphism: - From: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (-2*t^3 - t^2 + 3*t + 3)*x^2 + (t - 3)*y^2 + (-t^7 + 2*t^5 + t^4 + 2*t^3 + 3*t^2 - t - 1)*z^2 - To: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by -2/(t^3 - 3*t^2 + 2*t + 2)*x^2 + 1/(t^3 + 3*t^2 - 2*t + 1)*y^2 + (-t^6 + 3*t^5 + t^3 - t^2 - t + 2)/(t^9 - 2*t^8 + t^7 - t^6 + 3*t^5 - 3*t^3 + t^2 - 2*t + 3)*z^2 + (x + (2*t - 2)/(t + 3)*y + (3*t^4 + 2*t^3 - 2*t^2 - 2*t + 3)/(t^4 + t^3 - 3*t^2 + 3*t + 1)*z + : y + (-t^3 - t^2 + 3*t - 1)/(t^3 - 3*t^2 + 2*t + 2)*z : z)) + domain must equal right (=Scheme morphism: + From: Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Finite Field of size 7 defined by + (-2*t^3 - t^2 + 3*t + 3)*x^2 + (t - 3)*y^2 + (-t^7 + 2*t^5 + t^4 + 2*t^3 + 3*t^2 - t - 1)*z^2 + To: Projective Conic Curve over Fraction Field of Univariate + Polynomial Ring in t over Finite Field of size 7 defined by + -2/(t^3 - 3*t^2 + 2*t + 2)*x^2 + 1/(t^3 + 3*t^2 - 2*t + 1)*y^2 + (-t^6 + 3*t^5 + t^3 - t^2 - t + 2)/(t^9 - 2*t^8 + t^7 - t^6 + 3*t^5 - 3*t^3 + t^2 - 2*t + 3)*z^2 Defn: Defined on coordinates by sending (x : y : z) to - ((t^3 - 3*t^2 + 2*t + 2)*x : (t^2 - 2)*y : (t^5 - 3*t^4 + t^2 + 3*t + 3)*z)) codomain + ((t^3 - 3*t^2 + 2*t + 2)*x : (t^2 - 2)*y : (t^5 - 3*t^4 + t^2 + 3*t + 3)*z)) + codomain @@ -361,7 +377,7 @@ def _reduce_conic(self): EXAMPLES:: sage: K.<t> = FractionField(PolynomialRing(QQ, 't')) - sage: C = Conic(K, [t^2-2, 2*t^3, -2*t^3-13*t^2-2*t+18]) + sage: C = Conic(K, [t^2 - 2, 2*t^3, -2*t^3 - 13*t^2 - 2*t + 18]) sage: C._reduce_conic() ([t^2 - 2, 2*t, -2*t^3 - 13*t^2 - 2*t + 18], [t, 1, t]) """ @@ -458,14 +474,15 @@ def find_point(self, supports, roots, case, solution=0): EXAMPLES:: sage: K.<t> = FractionField(QQ['t']) - sage: C = Conic(K, [t^2-2, 2*t^3, -2*t^3-13*t^2-2*t+18]) + sage: C = Conic(K, [t^2 - 2, 2*t^3, -2*t^3 - 13*t^2 - 2*t + 18]) sage: C.has_rational_point(point=True) # indirect test (True, (-3 : (t + 1)/t : 1)) Different solubility certificates give different points:: + sage: # needs sage.rings.number_field sage: K.<t> = PolynomialRing(QQ, 't') - sage: C = Conic(K, [t^2-2, 2*t, -2*t^3-13*t^2-2*t+18]) + sage: C = Conic(K, [t^2 - 2, 2*t, -2*t^3 - 13*t^2 - 2*t + 18]) sage: supp = [[t^2 - 2], [t], [t^3 + 13/2*t^2 + t - 9]] sage: tbar1 = QQ.extension(supp[0][0], 'tbar').gens()[0] sage: tbar2 = QQ.extension(supp[1][0], 'tbar').gens()[0] diff --git a/src/sage/schemes/plane_conics/constructor.py b/src/sage/schemes/plane_conics/constructor.py index a2a14190087..20bc5630ac1 100644 --- a/src/sage/schemes/plane_conics/constructor.py +++ b/src/sage/schemes/plane_conics/constructor.py @@ -26,21 +26,19 @@ from sage.matrix.constructor import Matrix from sage.modules.free_module_element import vector -from sage.quadratic_forms.quadratic_form import is_QuadraticForm -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - from sage.rings.ring import IntegralDomain from sage.rings.rational_field import is_RationalField -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField -from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial -from sage.rings.polynomial.polynomial_ring import is_PolynomialRing -from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.fraction_field import is_FractionField -from sage.rings.number_field.number_field import is_NumberField -from sage.schemes.projective.projective_space import ProjectiveSpace -from sage.schemes.projective.projective_point import SchemeMorphism_point_projective_field +from sage.rings.number_field.number_field_base import NumberField +from sage.rings.polynomial.multi_polynomial import MPolynomial +from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing +from sage.rings.polynomial.polynomial_ring import is_PolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.schemes.affine.affine_point import SchemeMorphism_point_affine +from sage.schemes.projective.projective_point import SchemeMorphism_point_projective_field +from sage.schemes.projective.projective_space import ProjectiveSpace from sage.structure.all import Sequence from sage.structure.element import is_Matrix @@ -109,7 +107,8 @@ def Conic(base_field, F=None, names=None, unique=True): Projective Conic Curve over Rational Field defined by X^2 - X*Y + Y^2 - Z^2 sage: x,y = GF(7)['x,y'].gens() sage: Conic(x^2 - x + 2*y^2 - 3, 'U,V,W') - Projective Conic Curve over Finite Field of size 7 defined by U^2 + 2*V^2 - U*W - 3*W^2 + Projective Conic Curve over Finite Field of size 7 + defined by U^2 + 2*V^2 - U*W - 3*W^2 Conic curves given by matrices :: @@ -117,7 +116,7 @@ def Conic(base_field, F=None, names=None, unique=True): Projective Conic Curve over Rational Field defined by x^2 + 6*x*y + 7*x*z + 9*z^2 sage: x,y,z = GF(11)['x,y,z'].gens() - sage: C = Conic(x^2+y^2-2*z^2); C + sage: C = Conic(x^2 + y^2 - 2*z^2); C Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2 sage: Conic(C.symmetric_matrix(), 'x,y,z') Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2 @@ -127,18 +126,20 @@ def Conic(base_field, F=None, names=None, unique=True): sage: Conic(QQ, [1,2,3]) Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + 3*z^2 sage: Conic(GF(7), [1,2,3,4,5,6], 'X') - Projective Conic Curve over Finite Field of size 7 defined by X0^2 + 2*X0*X1 - 3*X1^2 + 3*X0*X2 - 2*X1*X2 - X2^2 + Projective Conic Curve over Finite Field of size 7 + defined by X0^2 + 2*X0*X1 - 3*X1^2 + 3*X0*X2 - 2*X1*X2 - X2^2 The conic through a set of points :: sage: C = Conic(QQ, [[10,2],[3,4],[-7,6],[7,8],[9,10]]); C - Projective Conic Curve over Rational Field defined by x^2 + 13/4*x*y - 17/4*y^2 - 35/2*x*z + 91/4*y*z - 37/2*z^2 + Projective Conic Curve over Rational Field + defined by x^2 + 13/4*x*y - 17/4*y^2 - 35/2*x*z + 91/4*y*z - 37/2*z^2 sage: C.rational_point() (10 : 2 : 1) sage: C.point([3,4]) (3 : 4 : 1) - sage: a = AffineSpace(GF(13),2) + sage: a = AffineSpace(GF(13), 2) sage: Conic([a([x,x^2]) for x in range(5)]) Projective Conic Curve over Finite Field of size 13 defined by x^2 - y*z """ @@ -196,7 +197,10 @@ def Conic(base_field, F=None, names=None, unique=True): F[3] * y**2 + F[4] * y * z + F[5] * z**2) raise TypeError("F (=%s) must be a sequence of 3 or 6" "coefficients" % F) - if is_QuadraticForm(F): + + from sage.quadratic_forms.quadratic_form import QuadraticForm + + if isinstance(F, QuadraticForm): F = F.matrix() if is_Matrix(F) and F.is_square() and F.ncols() == 3: if names is None: @@ -204,7 +208,7 @@ def Conic(base_field, F=None, names=None, unique=True): temp_ring = PolynomialRing(F.base_ring(), 3, names) F = vector(temp_ring.gens()) * F * vector(temp_ring.gens()) - if not is_MPolynomial(F): + if not isinstance(F, MPolynomial): raise TypeError("F (=%s) must be a three-variable polynomial or " "a sequence of points or coefficients" % F) @@ -233,11 +237,11 @@ def Conic(base_field, F=None, names=None, unique=True): if F.parent().ngens() == 3: P2 = ProjectiveSpace(2, base_field, names) - if is_FiniteField(base_field): + if isinstance(base_field, FiniteField): return ProjectiveConic_finite_field(P2, F) if is_RationalField(base_field): return ProjectiveConic_rational_field(P2, F) - if is_NumberField(base_field): + if isinstance(base_field, NumberField): return ProjectiveConic_number_field(P2, F) if is_FractionField(base_field) and (is_PolynomialRing(base_field.ring()) or is_MPolynomialRing(base_field.ring())): return ProjectiveConic_rational_function_field(P2, F) diff --git a/src/sage/schemes/plane_quartics/__init__.py b/src/sage/schemes/plane_quartics/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/plane_quartics/quartic_constructor.py b/src/sage/schemes/plane_quartics/quartic_constructor.py index a0b5ce3c93a..37c06a1f5c9 100644 --- a/src/sage/schemes/plane_quartics/quartic_constructor.py +++ b/src/sage/schemes/plane_quartics/quartic_constructor.py @@ -9,48 +9,48 @@ #***************************************************************************** from sage.schemes.projective.projective_space import is_ProjectiveSpace, ProjectiveSpace -from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial +from sage.rings.polynomial.multi_polynomial import MPolynomial from .quartic_generic import QuarticCurve_generic def QuarticCurve(F, PP=None, check=False): """ - Returns the quartic curve defined by the polynomial F. + Return the quartic curve defined by the polynomial ``F``. INPUT: - - F -- a polynomial in three variables, homogeneous of degree 4 + - ``F`` -- a polynomial in three variables, homogeneous of degree 4 - - PP -- a projective plane (default:None) + - ``PP`` -- a projective plane (default: None) - - check -- whether to check for smoothness or not (default:False) + - ``check`` -- whether to check for smoothness or not (default: False) EXAMPLES:: - sage: x,y,z=PolynomialRing(QQ,['x','y','z']).gens() - sage: QuarticCurve(x**4+y**4+z**4) + sage: x,y,z = PolynomialRing(QQ, ['x','y','z']).gens() + sage: QuarticCurve(x**4 + y**4 + z**4) Quartic Curve over Rational Field defined by x^4 + y^4 + z^4 TESTS:: - sage: QuarticCurve(x**3+y**3) + sage: QuarticCurve(x**3 + y**3) Traceback (most recent call last): ... ValueError: Argument F (=x^3 + y^3) must be a homogeneous polynomial of degree 4 - sage: QuarticCurve(x**4+y**4+z**3) + sage: QuarticCurve(x**4 + y**4 + z**3) Traceback (most recent call last): ... ValueError: Argument F (=x^4 + y^4 + z^3) must be a homogeneous polynomial of degree 4 sage: x,y=PolynomialRing(QQ,['x','y']).gens() - sage: QuarticCurve(x**4+y**4) + sage: QuarticCurve(x**4 + y**4) Traceback (most recent call last): ... ValueError: Argument F (=x^4 + y^4) must be a polynomial in 3 variables """ - if not is_MPolynomial(F): + if not isinstance(F, MPolynomial): raise ValueError(f"Argument F (={F}) must be a multivariate polynomial") P = F.parent() if not P.ngens() == 3: diff --git a/src/sage/schemes/plane_quartics/quartic_generic.py b/src/sage/schemes/plane_quartics/quartic_generic.py index e5e546ad724..ac2cdd84d82 100644 --- a/src/sage/schemes/plane_quartics/quartic_generic.py +++ b/src/sage/schemes/plane_quartics/quartic_generic.py @@ -8,7 +8,8 @@ sage: PP.<X,Y,Z> = ProjectiveSpace(2, QQ) sage: f = X^4 + Y^4 + Z^4 - 3*X*Y*Z*(X+Y+Z) sage: C = QuarticCurve(f); C - Quartic Curve over Rational Field defined by X^4 + Y^4 - 3*X^2*Y*Z - 3*X*Y^2*Z - 3*X*Y*Z^2 + Z^4 + Quartic Curve over Rational Field + defined by X^4 + Y^4 - 3*X^2*Y*Z - 3*X*Y^2*Z - 3*X*Y*Z^2 + Z^4 """ #***************************************************************************** @@ -22,13 +23,13 @@ def is_QuarticCurve(C): """ - Checks whether C is a Quartic Curve + Check whether ``C`` is a Quartic Curve. EXAMPLES:: sage: from sage.schemes.plane_quartics.quartic_generic import is_QuarticCurve - sage: x,y,z=PolynomialRing(QQ,['x','y','z']).gens() - sage: Q = QuarticCurve(x**4+y**4+z**4) + sage: x,y,z = PolynomialRing(QQ, ['x','y','z']).gens() + sage: Q = QuarticCurve(x**4 + y**4 + z**4) sage: is_QuarticCurve(Q) True @@ -40,12 +41,12 @@ class QuarticCurve_generic(projective_curve.ProjectivePlaneCurve): def _repr_type(self): """ - Return the representation of self + Return the representation of ``self``. EXAMPLES:: - sage: x,y,z=PolynomialRing(QQ,['x','y','z']).gens() - sage: Q = QuarticCurve(x**4+y**4+z**4) + sage: x,y,z = PolynomialRing(QQ, ['x','y','z']).gens() + sage: Q = QuarticCurve(x**4 + y**4 + z**4) sage: Q._repr_type() 'Quartic' """ @@ -53,12 +54,12 @@ def _repr_type(self): def genus(self): """ - Returns the genus of self + Return the genus of ``self``. EXAMPLES:: - sage: x,y,z=PolynomialRing(QQ,['x','y','z']).gens() - sage: Q = QuarticCurve(x**4+y**4+z**4) + sage: x,y,z = PolynomialRing(QQ, ['x','y','z']).gens() + sage: Q = QuarticCurve(x**4 + y**4 + z**4) sage: Q.genus() 3 """ diff --git a/src/sage/schemes/product_projective/__init__.py b/src/sage/schemes/product_projective/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/product_projective/homset.py b/src/sage/schemes/product_projective/homset.py index 28aa566bb73..42d463077ee 100644 --- a/src/sage/schemes/product_projective/homset.py +++ b/src/sage/schemes/product_projective/homset.py @@ -22,7 +22,7 @@ from sage.categories.number_fields import NumberFields from sage.misc.mrange import xmrange from sage.misc.misc_c import prod -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.rational_field import is_RationalField from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme from sage.schemes.generic.homset import SchemeHomset_points @@ -31,15 +31,13 @@ class SchemeHomset_points_product_projective_spaces_ring(SchemeHomset_points): r""" Set of rational points of a product of projective spaces. - INPUT: - - See :class:`~sage.schemes.generic.homset.SchemeHomset_generic`. + INPUT: See :class:`~sage.schemes.generic.homset.SchemeHomset_generic`. EXAMPLES:: sage: from sage.schemes.product_projective.homset import SchemeHomset_points_product_projective_spaces_ring - sage: SchemeHomset_points_product_projective_spaces_ring(Spec(QQ), \ - ProductProjectiveSpaces([1, 1], QQ, 'z')) + sage: SchemeHomset_points_product_projective_spaces_ring( + ....: Spec(QQ), ProductProjectiveSpaces([1, 1], QQ, 'z')) Set of rational points of Product of projective spaces P^1 x P^1 over Rational Field """ @@ -93,71 +91,70 @@ def points(self, **kwds): - ``bound`` - a real number - - ``tolerance`` - a rational number in (0,1] used in doyle-krumm algorithm-4 + - ``tolerance`` - a rational number in (0,1] used in Doyle-Krumm algorithm 4 - ``precision`` - the precision to use for computing the elements of bounded height of number fields. - - ``algorithm`` - either 'sieve' or 'enumerate' algorithms can be used over `QQ`. If - not specified, enumerate is used only for small height bounds. - - OUTPUT: + - ``algorithm`` - either ``'sieve'`` or ``'enumerate'`` algorithms can be used over `\QQ`. If + not specified, ``'enumerate'`` is used only for small height bounds. - - a list of rational points of a projective scheme + OUTPUT: A list of rational points of the projective scheme. EXAMPLES:: sage: P.<x,y,z,w> = ProductProjectiveSpaces([1, 1], QQ) sage: X = P.subscheme([x - y, z^2 - 2*w^2]) - sage: X(P.base_ring()).points() + sage: X(P.base_ring()).points() # needs sage.libs.singular [] :: sage: u = QQ['u'].0 - sage: P.<x,y,z,w> = ProductProjectiveSpaces([1,1], NumberField(u^2 - 2, 'v')) + sage: K = NumberField(u^2 - 2, 'v') # needs sage.rings.number_field + sage: P.<x,y,z,w> = ProductProjectiveSpaces([1, 1], K) # needs sage.rings.number_field sage: X = P.subscheme([x^2 - y^2, z^2 - 2*w^2]) - sage: sorted(X(P.base_ring()).points()) + sage: sorted(X(P.base_ring()).points()) # needs sage.libs.singular sage.rings.number_field [(-1 : 1 , -v : 1), (-1 : 1 , v : 1), (1 : 1 , -v : 1), (1 : 1 , v : 1)] :: sage: u = QQ['u'].0 - sage: K = NumberField(u^2 + 1, 'v') - sage: P.<x,y,z,w> = ProductProjectiveSpaces([1, 1], K) - sage: P(K).points(bound=1) + sage: K = NumberField(u^2 + 1, 'v') # needs sage.rings.number_field + sage: P.<x,y,z,w> = ProductProjectiveSpaces([1, 1], K) # needs sage.rings.number_field + sage: P(K).points(bound=1) # needs sage.libs.singular sage.rings.number_field [(-1 : 1 , -1 : 1), (-1 : 1 , -v : 1), (-1 : 1 , 0 : 1), (-1 : 1 , v : 1), - (-1 : 1 , 1 : 0), (-1 : 1 , 1 : 1), (-v : 1 , -1 : 1), (-v : 1 , -v : 1), - (-v : 1 , 0 : 1), (-v : 1 , v : 1), (-v : 1 , 1 : 0), (-v : 1 , 1 : 1), - (0 : 1 , -1 : 1), (0 : 1 , -v : 1), (0 : 1 , 0 : 1), (0 : 1 , v : 1), - (0 : 1 , 1 : 0), (0 : 1 , 1 : 1), (v : 1 , -1 : 1), (v : 1 , -v : 1), - (v : 1 , 0 : 1), (v : 1 , v : 1), (v : 1 , 1 : 0), (v : 1 , 1 : 1), - (1 : 0 , -1 : 1), (1 : 0 , -v : 1), (1 : 0 , 0 : 1), (1 : 0 , v : 1), - (1 : 0 , 1 : 0), (1 : 0 , 1 : 1), (1 : 1 , -1 : 1), (1 : 1 , -v : 1), - (1 : 1 , 0 : 1), (1 : 1 , v : 1), (1 : 1 , 1 : 0), (1 : 1 , 1 : 1)] + (-1 : 1 , 1 : 0), (-1 : 1 , 1 : 1), (-v : 1 , -1 : 1), (-v : 1 , -v : 1), + (-v : 1 , 0 : 1), (-v : 1 , v : 1), (-v : 1 , 1 : 0), (-v : 1 , 1 : 1), + (0 : 1 , -1 : 1), (0 : 1 , -v : 1), (0 : 1 , 0 : 1), (0 : 1 , v : 1), + (0 : 1 , 1 : 0), (0 : 1 , 1 : 1), (v : 1 , -1 : 1), (v : 1 , -v : 1), + (v : 1 , 0 : 1), (v : 1 , v : 1), (v : 1 , 1 : 0), (v : 1 , 1 : 1), + (1 : 0 , -1 : 1), (1 : 0 , -v : 1), (1 : 0 , 0 : 1), (1 : 0 , v : 1), + (1 : 0 , 1 : 0), (1 : 0 , 1 : 1), (1 : 1 , -1 : 1), (1 : 1 , -v : 1), + (1 : 1 , 0 : 1), (1 : 1 , v : 1), (1 : 1 , 1 : 0), (1 : 1 , 1 : 1)] :: sage: P.<x,y,z,u,v> = ProductProjectiveSpaces([2, 1], GF(3)) sage: P(P.base_ring()).points() [(0 : 0 : 1 , 0 : 1), (0 : 0 : 1 , 1 : 0), (0 : 0 : 1 , 1 : 1), (0 : 0 : 1 , 2 : 1), - (0 : 1 : 0 , 0 : 1), (0 : 1 : 0 , 1 : 0), (0 : 1 : 0 , 1 : 1), (0 : 1 : 0 , 2 : 1), - (0 : 1 : 1 , 0 : 1), (0 : 1 : 1 , 1 : 0), (0 : 1 : 1 , 1 : 1), (0 : 1 : 1 , 2 : 1), - (0 : 2 : 1 , 0 : 1), (0 : 2 : 1 , 1 : 0), (0 : 2 : 1 , 1 : 1), (0 : 2 : 1 , 2 : 1), - (1 : 0 : 0 , 0 : 1), (1 : 0 : 0 , 1 : 0), (1 : 0 : 0 , 1 : 1), (1 : 0 : 0 , 2 : 1), - (1 : 0 : 1 , 0 : 1), (1 : 0 : 1 , 1 : 0), (1 : 0 : 1 , 1 : 1), (1 : 0 : 1 , 2 : 1), - (1 : 1 : 0 , 0 : 1), (1 : 1 : 0 , 1 : 0), (1 : 1 : 0 , 1 : 1), (1 : 1 : 0 , 2 : 1), - (1 : 1 : 1 , 0 : 1), (1 : 1 : 1 , 1 : 0), (1 : 1 : 1 , 1 : 1), (1 : 1 : 1 , 2 : 1), - (1 : 2 : 1 , 0 : 1), (1 : 2 : 1 , 1 : 0), (1 : 2 : 1 , 1 : 1), (1 : 2 : 1 , 2 : 1), - (2 : 0 : 1 , 0 : 1), (2 : 0 : 1 , 1 : 0), (2 : 0 : 1 , 1 : 1), (2 : 0 : 1 , 2 : 1), - (2 : 1 : 0 , 0 : 1), (2 : 1 : 0 , 1 : 0), (2 : 1 : 0 , 1 : 1), (2 : 1 : 0 , 2 : 1), - (2 : 1 : 1 , 0 : 1), (2 : 1 : 1 , 1 : 0), (2 : 1 : 1 , 1 : 1), (2 : 1 : 1 , 2 : 1), - (2 : 2 : 1 , 0 : 1), (2 : 2 : 1 , 1 : 0), (2 : 2 : 1 , 1 : 1), (2 : 2 : 1 , 2 : 1)] + (0 : 1 : 0 , 0 : 1), (0 : 1 : 0 , 1 : 0), (0 : 1 : 0 , 1 : 1), (0 : 1 : 0 , 2 : 1), + (0 : 1 : 1 , 0 : 1), (0 : 1 : 1 , 1 : 0), (0 : 1 : 1 , 1 : 1), (0 : 1 : 1 , 2 : 1), + (0 : 2 : 1 , 0 : 1), (0 : 2 : 1 , 1 : 0), (0 : 2 : 1 , 1 : 1), (0 : 2 : 1 , 2 : 1), + (1 : 0 : 0 , 0 : 1), (1 : 0 : 0 , 1 : 0), (1 : 0 : 0 , 1 : 1), (1 : 0 : 0 , 2 : 1), + (1 : 0 : 1 , 0 : 1), (1 : 0 : 1 , 1 : 0), (1 : 0 : 1 , 1 : 1), (1 : 0 : 1 , 2 : 1), + (1 : 1 : 0 , 0 : 1), (1 : 1 : 0 , 1 : 0), (1 : 1 : 0 , 1 : 1), (1 : 1 : 0 , 2 : 1), + (1 : 1 : 1 , 0 : 1), (1 : 1 : 1 , 1 : 0), (1 : 1 : 1 , 1 : 1), (1 : 1 : 1 , 2 : 1), + (1 : 2 : 1 , 0 : 1), (1 : 2 : 1 , 1 : 0), (1 : 2 : 1 , 1 : 1), (1 : 2 : 1 , 2 : 1), + (2 : 0 : 1 , 0 : 1), (2 : 0 : 1 , 1 : 0), (2 : 0 : 1 , 1 : 1), (2 : 0 : 1 , 2 : 1), + (2 : 1 : 0 , 0 : 1), (2 : 1 : 0 , 1 : 0), (2 : 1 : 0 , 1 : 1), (2 : 1 : 0 , 2 : 1), + (2 : 1 : 1 , 0 : 1), (2 : 1 : 1 , 1 : 0), (2 : 1 : 1 , 1 : 1), (2 : 1 : 1 , 2 : 1), + (2 : 2 : 1 , 0 : 1), (2 : 2 : 1 , 1 : 0), (2 : 2 : 1 , 1 : 1), (2 : 2 : 1 , 2 : 1)] :: - sage: PP.<x,y,z,u,v> = ProductProjectiveSpaces([2,1], QQ) - sage: X = PP.subscheme([x + y, u*u-v*u]) - sage: X.rational_points(bound=2) + sage: PP.<x,y,z,u,v> = ProductProjectiveSpaces([2, 1], QQ) + sage: X = PP.subscheme([x + y, u*u - v*u]) + sage: X.rational_points(bound=2) # needs sage.libs.singular [(-2 : 2 : 1 , 0 : 1), (-2 : 2 : 1 , 1 : 1), (-1 : 1 : 0 , 0 : 1), @@ -177,9 +174,9 @@ def points(self, **kwds): better to enumerate with low codimension:: - sage: PP.<x,y,z,u,v,a,b,c> = ProductProjectiveSpaces([2,1,2], QQ) - sage: X = PP.subscheme([x*u^2*a, b*z*u*v,z*v^2*c ]) - sage: len(X.rational_points(bound=1, algorithm='enumerate')) + sage: PP.<x,y,z,u,v,a,b,c> = ProductProjectiveSpaces([2, 1, 2], QQ) + sage: X = PP.subscheme([x*u^2*a, b*z*u*v, z*v^2*c]) + sage: len(X.rational_points(bound=1, algorithm='enumerate')) # needs sage.libs.singular 232 """ B = kwds.pop('bound', 0) @@ -204,7 +201,7 @@ def points(self, **kwds): points = [] if is_RationalField(R): if not B > 0: - raise TypeError("a positive bound B (= %s) must be specified"%B) + raise TypeError("a positive bound B (= %s) must be specified" % B) alg = kwds.pop('algorithm', None) if alg is None: # sieve should only be called for subschemes and if the bound is not very small @@ -225,10 +222,10 @@ def points(self, **kwds): raise ValueError("algorithm must be 'sieve' or 'enumerate'") elif R in NumberFields(): if not B > 0: - raise TypeError("a positive bound B (= %s) must be specified"%B) + raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.product_projective.rational_point import enum_product_projective_number_field return enum_product_projective_number_field(self, bound=B) - elif is_FiniteField(R): + elif isinstance(R, FiniteField): from sage.schemes.product_projective.rational_point import enum_product_projective_finite_field return enum_product_projective_finite_field(self) else: diff --git a/src/sage/schemes/product_projective/morphism.py b/src/sage/schemes/product_projective/morphism.py index b558d88b304..74b424022a2 100644 --- a/src/sage/schemes/product_projective/morphism.py +++ b/src/sage/schemes/product_projective/morphism.py @@ -9,8 +9,7 @@ sage: H = End(P1xP1) sage: H([x^2*u, y^2*v, x*v^2, y*u^2]) Scheme endomorphism of Product of projective spaces P^1 x P^1 over Rational Field - Defn: Defined by sending (x : y , u : v) to - (x^2*u : y^2*v , x*v^2 : y*u^2). + Defn: Defined by sending (x : y , u : v) to (x^2*u : y^2*v , x*v^2 : y*u^2). """ # **************************************************************************** # Copyright (C) 2014 Ben Hutz <bn4941@gmail.com> @@ -41,8 +40,7 @@ class ProductProjectiveSpaces_morphism_ring(SchemeMorphism_polynomial): sage: H = T.Hom(T) sage: H([x^2, y^2, z^2, w^2, u^2]) Scheme endomorphism of Product of projective spaces P^2 x P^1 over Rational Field - Defn: Defined by sending (x : y : z , w : u) to - (x^2 : y^2 : z^2 , w^2 : u^2). + Defn: Defined by sending (x : y : z , w : u) to (x^2 : y^2 : z^2 , w^2 : u^2). """ def __init__(self, parent, polys, check=True): @@ -56,7 +54,7 @@ def __init__(self, parent, polys, check=True): - ``polys`` -- anything that defines a point in the class. - ``check`` -- Boolean. Whether or not to perform input checks. - (Default:`` True``) + (Default: ``True``) EXAMPLES:: @@ -83,7 +81,7 @@ def __init__(self, parent, polys, check=True): sage: Z.<a,b,x,y,z> = ProductProjectiveSpaces([1, 2], QQ) sage: P.<u,v,w,s,t,r> = ProductProjectiveSpaces([3, 1], QQ) sage: H = Hom(Z,P) - sage: f = H([a^2,b^2,a^2,a*b,a*x,b*z]); f + sage: f = H([a^2, b^2, a^2, a*b, a*x, b*z]); f Scheme morphism: From: Product of projective spaces P^1 x P^2 over Rational Field To: Product of projective spaces P^3 x P^1 over Rational Field @@ -95,7 +93,7 @@ def __init__(self, parent, polys, check=True): sage: Z.<a,b,c,x,y,z> = ProductProjectiveSpaces([1, 3], QQ) sage: P.<u,v,w,s,t,r> = ProductProjectiveSpaces([2, 2], QQ) sage: H = Hom(Z,P) - sage: f = H([a^2,b^2,c^2,x^2,y^2,z^2]) + sage: f = H([a^2, b^2, c^2, x^2, y^2, z^2]) Traceback (most recent call last): ... TypeError: polys (=[a^2, b^2, c^2, x^2, y^2, z^2]) must be @@ -117,7 +115,7 @@ def __init__(self, parent, polys, check=True): for m in range(len(splitpolys)): d = dom._degree(splitpolys[m][0]) if not all(d == dom._degree(f) for f in splitpolys[m]): - raise TypeError("polys (=%s) must be multi-homogeneous of the same degrees (by component)"%polys) + raise TypeError("polys (=%s) must be multi-homogeneous of the same degrees (by component)" % polys) else: #we are mapping into some other kind of space target._validate(polys) @@ -160,7 +158,7 @@ def _repr_defn(self): sage: f._repr_defn() 'Defined by sending (x : y , z : w) to \n(x^2 : y^2 , z : w).' """ - s = 'Defined by sending ' + s = 'Defined by sending ' s += self.domain().ambient_space()._repr_generic_point() s += ' to \n' s += self.codomain().ambient_space()._repr_generic_point(self._polys) @@ -199,11 +197,11 @@ def __call__(self, P, check=True): :: - sage: PP.<t0,t1,t2,t3,t4> = ProductProjectiveSpaces([2,1], ZZ) + sage: PP.<t0,t1,t2,t3,t4> = ProductProjectiveSpaces([2, 1], ZZ) sage: Q = PP([1,1,1,2,1]) - sage: Z.<a,b,x,y,z> = ProductProjectiveSpaces([1,2], ZZ) + sage: Z.<a,b,x,y,z> = ProductProjectiveSpaces([1, 2], ZZ) sage: H = End(Z) - sage: f = H([a^3, b^3+a*b^2, x^2, y^2-z^2, z*y]) + sage: f = H([a^3, b^3 + a*b^2, x^2, y^2 - z^2, z*y]) sage: f(Q) Traceback (most recent call last): ... @@ -218,7 +216,7 @@ def __call__(self, P, check=True): sage: PP.<x,y,u,v> = ProductProjectiveSpaces(ZZ, [1, 1]) sage: HP = End(PP) sage: g = HP([x^2, y^2, u^2, v^2]) - sage: g([0, 0, 0, 0],check=False) + sage: g([0, 0, 0, 0], check=False) (0 : 0 , 0 : 0) """ from sage.schemes.product_projective.point import ProductProjectiveSpaces_point_ring @@ -227,9 +225,9 @@ def __call__(self, P, check=True): try: P = self.domain()(P) except (TypeError, NotImplementedError): - raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented"%(P, self.domain())) - elif self.domain()!= P.codomain(): - raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented"%(P, self.domain())) + raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented" % (P, self.domain())) + elif self.domain() != P.codomain(): + raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented" % (P, self.domain())) A = self.codomain() Q = list(P) @@ -252,11 +250,12 @@ def __eq__(self, right): EXAMPLES:: sage: P1.<x1,x2,x3,x4> = ProductProjectiveSpaces([1, 1], QQ) - sage: P2.<y1,y2,y3,y4> = ProductProjectiveSpaces([1, 1], CC) - sage: H1 = End(P1); H2 = End(P2) + sage: P2.<y1,y2,y3,y4> = ProductProjectiveSpaces([1, 1], CC) # needs sage.rings.real_mpfr + sage: H1 = End(P1) + sage: H2 = End(P2) # needs sage.rings.real_mpfr sage: f = H1([x1*x2, x2^2, x3*x4, x4^2]) - sage: g = H2([y1*y2, y2^2, y3*y4, y4^2]) - sage: f == g + sage: g = H2([y1*y2, y2^2, y3*y4, y4^2]) # needs sage.rings.real_mpfr + sage: f == g # needs sage.rings.real_mpfr False :: @@ -315,7 +314,7 @@ def __ne__(self, right): EXAMPLES:: - sage: PP.<a,b,x,y,z> = ProductProjectiveSpaces([1,2], ZZ) + sage: PP.<a,b,x,y,z> = ProductProjectiveSpaces([1, 2], ZZ) sage: E = End(PP) sage: f = E([a^3, a*b^2, x*y, y*z, z*x]) sage: g = E([a*b, a^2, x^2, y^2, z^2]) @@ -348,7 +347,7 @@ def __ne__(self, right): def is_morphism(self): r""" - Returns ``True`` if this mapping is a morphism of products of projective spaces. + Return ``True`` if this mapping is a morphism of products of projective spaces. For each component space of the codomain of this mapping we consider the subscheme of the domain of this map generated by the corresponding coordinates of the map. @@ -360,16 +359,16 @@ def is_morphism(self): sage: Z.<a,b,x,y,z> = ProductProjectiveSpaces([1, 2], ZZ) sage: H = End(Z) - sage: f = H([a^2, b^2, x*z-y*z, x^2-y^2, z^2]) - sage: f.is_morphism() + sage: f = H([a^2, b^2, x*z - y*z, x^2 - y^2, z^2]) + sage: f.is_morphism() # needs sage.libs.singular False :: - sage: P.<x,y,z,u,v,w>=ProductProjectiveSpaces([2, 2], QQ) + sage: P.<x,y,z,u,v,w> = ProductProjectiveSpaces([2, 2], QQ) sage: H = End(P) sage: f = H([u, v, w, u^2, v^2, w^2]) - sage: f.is_morphism() + sage: f.is_morphism() # needs sage.libs.singular True :: @@ -378,7 +377,7 @@ def is_morphism(self): sage: Q.<a,b,c,d,e> = ProductProjectiveSpaces([1, 2], QQ) sage: H = Hom(P, Q) sage: f = H([x^2, y^2, u^3, w^3, u^3]) - sage: f.is_morphism() + sage: f.is_morphism() # needs sage.libs.singular False """ m = 0 @@ -402,18 +401,18 @@ def is_morphism(self): def as_dynamical_system(self): """ - Return this endomorphism as a :class:`DynamicalSystem_producte_projective`. + Return this endomorphism as a :class:`~sage.dynamics.arithmetic_dynamics.product_projective_ds.DynamicalSystem_product_projective`. OUTPUT: - - :class:`DynamicalSystem_produce_projective` + - :class:`~sage.dynamics.arithmetic_dynamics.product_projective_ds.DynamicalSystem_product_projective` EXAMPLES:: - sage: Z.<a,b,x,y,z> = ProductProjectiveSpaces([1 , 2], ZZ) + sage: Z.<a,b,x,y,z> = ProductProjectiveSpaces([1, 2], ZZ) sage: H = End(Z) sage: f = H([a^3, b^3, x^2, y^2, z^2]) - sage: type(f.as_dynamical_system()) + sage: type(f.as_dynamical_system()) # needs sage.schemes <class 'sage.dynamics.arithmetic_dynamics.product_projective_ds.DynamicalSystem_product_projective'> """ if not self.is_endomorphism(): @@ -423,7 +422,7 @@ def as_dynamical_system(self): def global_height(self, prec=None): r""" - Returns the maximum of the absolute logarithmic heights of the coefficients + Return the maximum of the absolute logarithmic heights of the coefficients in any of the coordinate functions of this map. INPUT: @@ -445,18 +444,19 @@ def global_height(self, prec=None): sage: P1xP1.<x,y,u,v> = ProductProjectiveSpaces([1, 1], ZZ) sage: H = End(P1xP1) sage: f = H([x^2*u, 3*y^2*v, 5*x*v^2, y*u^2]) - sage: f.global_height() + sage: f.global_height() # needs sage.rings.real_mpfr 1.60943791243410 :: + sage: # needs sage.rings.number_field sage: u = QQ['u'].0 sage: R = NumberField(u^2 - 2, 'v') sage: PP.<x,y,a,b> = ProductProjectiveSpaces([1, 1], R) sage: H = End(PP) sage: O = R.maximal_order() sage: g = H([3*O(u)*x^2, 13*x*y, 7*a*y, 5*b*x + O(u)*a*y]) - sage: g.global_height() + sage: g.global_height() # needs sage.rings.real_mpfr 2.56494935746154 """ K = self.domain().base_ring() @@ -474,7 +474,7 @@ def global_height(self, prec=None): def local_height(self, v, prec=None): r""" - Returns the maximum of the local height of the coefficients in any + Return the maximum of the local height of the coefficients in any of the coordinate functions of this map. INPUT: @@ -484,26 +484,25 @@ def local_height(self, v, prec=None): - ``prec`` -- desired floating point precision (default: default RealField precision). - OUTPUT: - - - a real number. + OUTPUT: A real number. EXAMPLES:: sage: T.<x,y,z,w,u> = ProductProjectiveSpaces([2, 1], QQ) sage: H = T.Hom(T) - sage: f = H([4*x^2+3/100*y^2, 8/210*x*y, 1/10000*z^2, 20*w^2, 1/384*u*w]) - sage: f.local_height(2) + sage: f = H([4*x^2 + 3/100*y^2, 8/210*x*y, 1/10000*z^2, 20*w^2, 1/384*u*w]) + sage: f.local_height(2) # needs sage.rings.real_mpfr 4.85203026391962 :: + sage: # needs sage.rings.number_field sage: R.<z> = PolynomialRing(QQ) - sage: K.<w> = NumberField(z^2-5) + sage: K.<w> = NumberField(z^2 - 5) sage: P.<x,y,a,b> = ProductProjectiveSpaces([1, 1], K) - sage: H = Hom(P,P) + sage: H = Hom(P, P) sage: f = H([2*x^2 + w/3*y^2, 1/w*y^2, a^2, 6*b^2 + 1/9*a*b]) - sage: f.local_height(K.ideal(3)) + sage: f.local_height(K.ideal(3)) # needs sage.rings.real_mpfr 2.19722457733622 """ K = FractionField(self.domain().base_ring()) diff --git a/src/sage/schemes/product_projective/point.py b/src/sage/schemes/product_projective/point.py index e884deb2809..d51d5d369bf 100644 --- a/src/sage/schemes/product_projective/point.py +++ b/src/sage/schemes/product_projective/point.py @@ -41,7 +41,7 @@ class ProductProjectiveSpaces_point_ring(SchemeMorphism_point): EXAMPLES:: sage: T.<x,y,z,w,u> = ProductProjectiveSpaces([2, 1], QQ) - sage: T.point([1, 2, 3, 4, 5]); + sage: T.point([1, 2, 3, 4, 5]) (1/3 : 2/3 : 1 , 4/5 : 1) """ def __init__(self, parent, polys, check=True): @@ -76,7 +76,7 @@ def __init__(self, parent, polys, check=True): :: sage: T.<x,y,z,w> = ProductProjectiveSpaces([1, 1], GF(5)) - sage: X = T.subscheme([x-y, z-2*w]) + sage: X = T.subscheme([x - y, z - 2*w]) sage: X([1, 1, 2, 1]) (1 : 1 , 2 : 1) """ @@ -99,7 +99,7 @@ def __init__(self, parent, polys, check=True): N = parent.codomain().ambient_space().dimension_relative_components() if check: parent.codomain()._check_satisfies_equations(polys) - splitpolys=self.codomain().ambient_space()._factors(polys) + splitpolys = self.codomain().ambient_space()._factors(polys) self._points = [parent.codomain().ambient_space()[i].point(splitpolys[i], check) for i in range(len(N))] def __getitem__(self, i): @@ -339,6 +339,7 @@ def dehomogenize(self, L): :: + sage: # needs sage.rings.real_mpfr sage: PP.<a,b,x,y,z> = ProductProjectiveSpaces([1, 2], CC) sage: X = PP.subscheme([a^2 + b^2]) sage: P = X([2, 2*i, -3, 6*i, 3 - 6*i]) @@ -404,14 +405,12 @@ def change_ring(self, R, **kwds): - ``embedding`` -- field embedding from the base ring of this point to ``R``. - OUTPUT: - - :class:`ProductProjectiveSpaces_point`. + OUTPUT: :class:`ProductProjectiveSpaces_point`. EXAMPLES:: sage: T.<x,y,z,u,v,w> = ProductProjectiveSpaces([1, 1, 1], ZZ) - sage: P = T.point([5, 3, 15, 4, 2, 6]); + sage: P = T.point([5, 3, 15, 4, 2, 6]) sage: P.change_ring(GF(3)) (1 : 0 , 0 : 1 , 1 : 0) """ @@ -433,38 +432,37 @@ def global_height(self, prec=None): - ``prec`` -- desired floating point precision (default: default RealField precision). - OUTPUT: - - - a real number. + OUTPUT: A real number. EXAMPLES:: - sage: PP = ProductProjectiveSpaces(QQ, [2,2], 'x') + sage: PP = ProductProjectiveSpaces(QQ, [2, 2], 'x') sage: Q = PP([1, 7, 5, 18, 2, 3]) - sage: Q.global_height() + sage: Q.global_height() # needs sage.symbolic 2.89037175789616 :: - sage: PP = ProductProjectiveSpaces(ZZ, [1,1], 'x') + sage: PP = ProductProjectiveSpaces(ZZ, [1, 1], 'x') sage: A = PP([-30, 2, 1, 6]) - sage: A.global_height() + sage: A.global_height() # needs sage.symbolic 2.70805020110221 :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) sage: k.<w> = NumberField(x^2 + 5) sage: PP = ProductProjectiveSpaces(k, [1, 2], 'y') - sage: Q = PP([3, 5*w+1, 1, 7*w, 10]) + sage: Q = PP([3, 5*w + 1, 1, 7*w, 10]) sage: Q.global_height() 2.75062910527236 :: - sage: PP = ProductProjectiveSpaces(QQbar, [1, 1], 'x') - sage: Q = PP([1, QQbar(sqrt(2)), QQbar(5^(1/3)), QQbar(3^(1/3))]) - sage: Q.global_height() + sage: PP = ProductProjectiveSpaces(QQbar, [1, 1], 'x') # needs sage.rings.number_field + sage: Q = PP([1, QQbar(sqrt(2)), QQbar(5^(1/3)), QQbar(3^(1/3))]) # needs sage.rings.number_field sage.symbolic + sage: Q.global_height() # needs sage.rings.number_field sage.symbolic 0.536479304144700 """ K = self.codomain().base_ring() @@ -489,22 +487,20 @@ def local_height(self, v, prec=None): - ``prec`` -- desired floating point precision (default: default RealField precision). - OUTPUT: - - - a real number. + OUTPUT: A real number. EXAMPLES:: sage: PP = ProductProjectiveSpaces(QQ, [1, 1], 'x') sage: A = PP([11, 5, 10, 2]) - sage: A.local_height(5) + sage: A.local_height(5) # needs sage.rings.real_mpfr 1.60943791243410 :: - sage: P = ProductProjectiveSpaces(QQ, [1,2], 'x') + sage: P = ProductProjectiveSpaces(QQ, [1, 2], 'x') sage: Q = P([1, 4, 1/2, 2, 32]) - sage: Q.local_height(2) + sage: Q.local_height(2) # needs sage.rings.real_mpfr 4.15888308335967 """ K = FractionField(self.domain().base_ring()) @@ -532,11 +528,11 @@ def intersection_multiplicity(self, X): EXAMPLES:: - sage: PP.<x,y,z,u,v> = ProductProjectiveSpaces(QQ, [2,1]) + sage: PP.<x,y,z,u,v> = ProductProjectiveSpaces(QQ, [2, 1]) sage: X = PP.subscheme([y^2*z^3*u - x^5*v]) sage: Y = PP.subscheme([u^3 - v^3, x - y]) sage: Q = X([0,0,1,1,1]) - sage: Q.intersection_multiplicity(Y) + sage: Q.intersection_multiplicity(Y) # needs sage.libs.singular 2 """ from sage.schemes.product_projective.space import is_ProductProjectiveSpaces @@ -555,16 +551,16 @@ def multiplicity(self): EXAMPLES:: - sage: PP.<x,y,z,w,u,v,t> = ProductProjectiveSpaces(QQ, [3,2]) + sage: PP.<x,y,z,w,u,v,t> = ProductProjectiveSpaces(QQ, [3, 2]) sage: X = PP.subscheme([x^8*t - y^8*t + z^5*w^3*v]) sage: Q1 = X([1,1,0,0,-1,-1,1]) - sage: Q1.multiplicity() + sage: Q1.multiplicity() # needs sage.libs.singular 1 sage: Q2 = X([0,0,0,1,0,1,1]) - sage: Q2.multiplicity() + sage: Q2.multiplicity() # needs sage.libs.singular 5 sage: Q3 = X([0,0,0,1,1,0,0]) - sage: Q3.multiplicity() + sage: Q3.multiplicity() # needs sage.libs.singular 6 """ from sage.schemes.product_projective.space import is_ProductProjectiveSpaces diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index 53e08bcc171..5375ffb4535 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -17,7 +17,7 @@ sage: PP.<x,y,z> = ProductProjectiveSpaces([1,0], QQ) sage: from sage.schemes.product_projective.rational_point import \ enum_product_projective_rational_field - sage: enum_product_projective_rational_field(PP,3) + sage: enum_product_projective_rational_field(PP, 3) [(-3 : 1 , 1), (-2 : 1 , 1), (-3/2 : 1 , 1), (-1 : 1 , 1), (-2/3 : 1 , 1), (-1/2 : 1 , 1), (-1/3 : 1 , 1), (0 : 1 , 1), (1/3 : 1 , 1), @@ -27,8 +27,8 @@ Product projective over finite field:: - sage: P1.<x,y,a,b> = ProductProjectiveSpaces([1,1], GF(7)) - sage: X = P1.subscheme([2*x+3*y]) + sage: P1.<x,y,a,b> = ProductProjectiveSpaces([1, 1], GF(7)) + sage: X = P1.subscheme([2*x + 3*y]) sage: from sage.schemes.product_projective.rational_point import \ enum_product_projective_finite_field sage: enum_product_projective_finite_field(X) @@ -89,7 +89,7 @@ def enum_product_projective_rational_field(X, B): sage: PP.<x0,x1,x2,x3,x4> = ProductProjectiveSpaces([1, 2], QQ) sage: from sage.schemes.product_projective.rational_point import \ enum_product_projective_rational_field - sage: enum_product_projective_rational_field(PP,1) + sage: enum_product_projective_rational_field(PP, 1) [(-1 : 1 , -1 : -1 : 1), (-1 : 1 , -1 : 0 : 1), (-1 : 1 , -1 : 1 : 0), (-1 : 1 , -1 : 1 : 1), (-1 : 1 , 0 : -1 : 1), (-1 : 1 , 0 : 0 : 1), (-1 : 1 , 0 : 1 : 0), (-1 : 1 , 0 : 1 : 1), (-1 : 1 , 1 : -1 : 1), @@ -111,11 +111,11 @@ def enum_product_projective_rational_field(X, B): :: - sage: PP.<x,y,z,u,v> = ProductProjectiveSpaces([2,1], QQ) - sage: X = PP.subscheme([x^2 + x*y + y*z, u*u-v*u]) + sage: PP.<x,y,z,u,v> = ProductProjectiveSpaces([2, 1], QQ) + sage: X = PP.subscheme([x^2 + x*y + y*z, u*u - v*u]) sage: from sage.schemes.product_projective.rational_point import \ enum_product_projective_rational_field - sage: enum_product_projective_rational_field(X,4) + sage: enum_product_projective_rational_field(X, 4) [(-2 : 4 : 1 , 0 : 1), (-2 : 4 : 1 , 1 : 1), (-1 : 1 : 0 , 0 : 1), (-1 : 1 : 0 , 1 : 1), (-2/3 : -4/3 : 1 , 0 : 1), (-2/3 : -4/3 : 1 , 1 : 1), (-1/2 : -1/2 : 1 , 0 : 1), (-1/2 : -1/2 : 1 , 1 : 1), @@ -207,6 +207,7 @@ def enum_product_projective_number_field(X, **kwds): EXAMPLES:: + sage: # needs sage.rings.number_field sage: u = QQ['u'].0 sage: K = NumberField(u^2 + 2, 'v') sage: PP.<x,y,z,w> = ProductProjectiveSpaces([1, 1], K) @@ -334,9 +335,9 @@ def sieve(X, bound): EXAMPLES:: sage: from sage.schemes.product_projective.rational_point import sieve - sage: PP.<x,y,z,u,v> = ProductProjectiveSpaces([2,1], QQ) - sage: X = PP.subscheme([x^2 + y^2 - x*z, u*u-v*u]) - sage: sieve(X, 2) + sage: PP.<x,y,z,u,v> = ProductProjectiveSpaces([2, 1], QQ) + sage: X = PP.subscheme([x^2 + y^2 - x*z, u*u - v*u]) + sage: sieve(X, 2) # needs sage.libs.singular [(0 : 0 : 1 , 0 : 1), (0 : 0 : 1 , 1 : 1), (1/2 : -1/2 : 1 , 0 : 1), (1/2 : -1/2 : 1 , 1 : 1), (1/2 : 1/2 : 1 , 0 : 1), (1/2 : 1/2 : 1 , 1 : 1), (1 : 0 : 1 , 0 : 1), (1 : 0 : 1 , 1 : 1)] @@ -471,15 +472,16 @@ def parallel_function_combination(point_p_max): # lift all coordinates of given point using chinese remainder theorem L = [modulo_points[j][tupl[j]][k].lift() for j in range(len_primes - 1)] L.append(point_p_max[k].lift()) - point.append( crt(L, primes_list) ) + point.append(crt(L, primes_list)) for i in range(num_comp): for j in range(comp_dim_relative[i]): m[i][j] = point[dim_prefix[i] + j] # generating matrix to compute LLL reduction for each component - M = [matrix(ZZ, comp_dim_relative[i] + 1, comp_dim_relative[i], m[i]) \ - for i in range(num_comp)] + M = [matrix(ZZ, comp_dim_relative[i] + 1, + comp_dim_relative[i], m[i]) + for i in range(num_comp)] A = [M[i].LLL() for i in range(num_comp)] point = [] for i in range(num_comp): diff --git a/src/sage/schemes/product_projective/space.py b/src/sage/schemes/product_projective/space.py index 604adcc8a41..0293e666cd6 100644 --- a/src/sage/schemes/product_projective/space.py +++ b/src/sage/schemes/product_projective/space.py @@ -45,7 +45,7 @@ from sage.rings.integer import Integer from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.categories.fields import Fields from sage.categories.commutative_rings import CommutativeRings from sage.rings.polynomial.polydict import ETuple @@ -105,7 +105,7 @@ def ProductProjectiveSpaces(n, R=None, names='x'): :: - sage: ProductProjectiveSpaces([2, 2],GF(7), 'y') + sage: ProductProjectiveSpaces([2, 2], GF(7), 'y') Product of projective spaces P^2 x P^2 over Finite Field of size 7 :: @@ -137,7 +137,7 @@ def ProductProjectiveSpaces(n, R=None, names='x'): raise AttributeError("components must be over the same base ring") N.append(PS.dimension_relative()) names += PS.variable_names() - if is_FiniteField(R): + if isinstance(R, FiniteField): X = ProductProjectiveSpaces_finite_field(N, R, names) elif R in Fields(): X = ProductProjectiveSpaces_field(N, R, names) @@ -162,7 +162,7 @@ def ProductProjectiveSpaces(n, R=None, names='x'): else: n_vars = sum(1+d for d in n) names = normalize_names(n_vars, name_list) - if is_FiniteField(R): + if isinstance(R, FiniteField): X = ProductProjectiveSpaces_finite_field(n, R, names) elif R in Fields(): X = ProductProjectiveSpaces_field(n, R, names) @@ -243,7 +243,7 @@ def __init__(self, N, R=QQ, names=None): # Note that the coordinate ring should really be the tensor product of # the component coordinate rings. But we just deal with them as # multihomogeneous polynomial rings. - self._coordinate_ring = PolynomialRing(R,sum(N)+ len(N),names) + self._coordinate_ring = PolynomialRing(R,sum(N) + len(N),names) self._assign_names(names) def _repr_(self): @@ -396,10 +396,10 @@ def __pow__(self, m): EXAMPLES:: - sage: P1 = ProductProjectiveSpaces([2,1], QQ, 'x') + sage: P1 = ProductProjectiveSpaces([2, 1], QQ, 'x') sage: P1^3 - Product of projective spaces P^2 x P^1 x P^2 x P^1 x P^2 x P^1 over - Rational Field + Product of projective spaces P^2 x P^1 x P^2 x P^1 x P^2 x P^1 + over Rational Field As you see, custom variable names are not preserved by power operator, since there is no natural way to make new ones in general. @@ -435,8 +435,8 @@ def __mul__(self, right): :: - sage: S = ProductProjectiveSpaces([1,2,1], ZZ, 't') - sage: T = ProductProjectiveSpaces([2,2], ZZ, 'x') + sage: S = ProductProjectiveSpaces([1, 2, 1], ZZ, 't') + sage: T = ProductProjectiveSpaces([2, 2], ZZ, 'x') sage: T.inject_variables() Defining x0, x1, x2, x3, x4, x5 sage: X = T.subscheme([x0*x4 - x1*x3]) @@ -479,7 +479,7 @@ def components(self): EXAMPLES:: - sage: P.<x,y,z,u,v> = ProductProjectiveSpaces(QQ,[2,1]) + sage: P.<x,y,z,u,v> = ProductProjectiveSpaces(QQ, [2, 1]) sage: P.components() [Projective Space of dimension 2 over Rational Field, Projective Space of dimension 1 over Rational Field] @@ -494,7 +494,7 @@ def dimension_relative(self): EXAMPLES:: - sage: T.<a,x,y,z,u,v,w> = ProductProjectiveSpaces([3,2],QQ) + sage: T.<a,x,y,z,u,v,w> = ProductProjectiveSpaces([3, 2], QQ) sage: T.dimension_relative() 5 """ @@ -604,12 +604,12 @@ def _factors(self, v): [[1, 2], [3, 4], [5, 6]] """ if not isinstance(v, (list, tuple, ETuple)): - raise TypeError("%s, must be a list or tuple"%v) + raise TypeError("%s, must be a list or tuple" % v) if len(v) != self.ngens(): - raise ValueError("%s must have %s elements"%(v, self.ngens())) + raise ValueError("%s must have %s elements" % (v, self.ngens())) index = 0 splitv = [] - dims=self._dims + dims = self._dims for i in range(len(dims)): splitv.append(v[index:index+dims[i]+1]) index += dims[i]+1 @@ -731,21 +731,21 @@ def _validate(self, polynomials): Polynomial Ring in x, y, z, w, u over Rational Field """ if not isinstance(polynomials, (list, tuple)): - raise TypeError('the argument polynomials=%s must be a list or tuple'%polynomials) + raise TypeError('the argument polynomials=%s must be a list or tuple' % polynomials) #check in the coordinate ring source_ring = self.coordinate_ring() try: polynomials = [source_ring(poly) for poly in polynomials] except TypeError: - raise TypeError("polynomials (=%s) must be elements of %s"%(polynomials,source_ring)) + raise TypeError("polynomials (=%s) must be elements of %s" % (polynomials,source_ring)) for f in polynomials: - self._degree(f) #raises a ValueError if not multi-homogeneous + self._degree(f) # raises a ValueError if not multi-homogeneous return polynomials def _check_satisfies_equations(self, v): """ - Return True if ``v`` defines a point on the scheme this space; raise a - TypeError otherwise. + Return ``True`` if ``v`` defines a point on the scheme this space; + raise a :class:`TypeError` otherwise. EXAMPLES:: @@ -785,15 +785,15 @@ def _check_satisfies_equations(self, v): TypeError: the components of v=[1, 1/2, 1, 0] must be elements of Integer Ring """ if not isinstance(v, (list, tuple)): - raise TypeError('the argument v=%s must be a list or tuple'%v) + raise TypeError('the argument v=%s must be a list or tuple' % v) n = self.ngens() if not len(v) == n: - raise TypeError('the list v=%s must have %s components'%(v, n)) + raise TypeError('the list v=%s must have %s components' % (v, n)) R = self.base_ring() try: n = [R(w) for w in v] except TypeError: - raise TypeError('the components of v=%s must be elements of %s'%(v, R)) + raise TypeError('the components of v=%s must be elements of %s' % (v, R)) #check if any of the component points are 0 N = self._dims start = 0 @@ -837,17 +837,18 @@ def subscheme(self, X): EXAMPLES:: - sage: P.<x,y,z,w> = ProductProjectiveSpaces([1, 1],GF(5)) - sage: X = P.subscheme([x-y, z-w]);X - Closed subscheme of Product of projective spaces P^1 x P^1 over Finite Field of size 5 defined by: - x - y, - z - w - sage: X.defining_polynomials () + sage: P.<x,y,z,w> = ProductProjectiveSpaces([1, 1], GF(5)) + sage: X = P.subscheme([x - y, z - w]); X + Closed subscheme of Product of projective spaces P^1 x P^1 + over Finite Field of size 5 defined by: + x - y, + z - w + sage: X.defining_polynomials() [x - y, z - w] sage: I = X.defining_ideal(); I - Ideal (x - y, z - w) of Multivariate Polynomial Ring in x, y, z, w over - Finite Field of size 5 - sage: X.dimension() + Ideal (x - y, z - w) of Multivariate Polynomial Ring in x, y, z, w + over Finite Field of size 5 + sage: X.dimension() # needs sage.libs.singular 0 sage: X.base_ring() Finite Field of size 5 @@ -855,11 +856,10 @@ def subscheme(self, X): Spectrum of Finite Field of size 5 sage: X.structure_morphism() Scheme morphism: - From: Closed subscheme of Product of projective spaces P^1 x P^1 over Finite Field of size 5 defined by: - x - y, - z - w - To: Spectrum of Finite Field of size 5 - Defn: Structure map + From: Closed subscheme of Product of projective spaces P^1 x P^1 + over Finite Field of size 5 defined by: x - y, z - w + To: Spectrum of Finite Field of size 5 + Defn: Structure map """ return AlgebraicScheme_subscheme_product_projective(self, X) @@ -915,21 +915,21 @@ def affine_patch(self, I, return_embedding=False): Affine Space of dimension 6 over Integer Ring sage: phi Scheme morphism: - From: Affine Space of dimension 6 over Integer Ring - To: Product of projective spaces P^2 x P^2 x P^2 over Integer Ring - Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4, x5) to - (1 : x0 : x1 , x2 : 1 : x3 , x4 : x5 : 1) + From: Affine Space of dimension 6 over Integer Ring + To: Product of projective spaces P^2 x P^2 x P^2 over Integer Ring + Defn: Defined on coordinates by sending (x0, x1, x2, x3, x4, x5) to + (1 : x0 : x1 , x2 : 1 : x3 , x4 : x5 : 1) """ if not isinstance(I, (list, tuple)): - raise TypeError('the argument I=%s must be a list or tuple of positive integers'%I) + raise TypeError('the argument I=%s must be a list or tuple of positive integers' % I) PP = self.ambient_space() N = PP._dims if len(I) != len(N): - raise ValueError('the argument I=%s must have %s entries'%(I,len(N))) + raise ValueError('the argument I=%s must have %s entries' % (I,len(N))) I = tuple([int(i) for i in I]) # implicit type checking for i in range(len(I)): if I[i] < 0 or I[i] > N[i]: - raise ValueError("argument i (= %s) must be between 0 and %s."%(I[i], N[i])) + raise ValueError("argument i (= %s) must be between 0 and %s." % (I[i], N[i])) try: if return_embedding: return self.__affine_patches[I][1] @@ -977,70 +977,49 @@ def segre_embedding(self, PP=None, var='u'): EXAMPLES:: sage: X.<y0,y1,y2,y3,y4,y5> = ProductProjectiveSpaces(ZZ, [2, 2]) - sage: phi = X.segre_embedding(); phi + sage: phi = X.segre_embedding(); phi # needs sage.libs.singular Scheme morphism: From: Product of projective spaces P^2 x P^2 over Integer Ring - To: Closed subscheme of Projective Space of dimension 8 over Integer Ring defined by: - -u5*u7 + u4*u8, - -u5*u6 + u3*u8, - -u4*u6 + u3*u7, - -u2*u7 + u1*u8, - -u2*u4 + u1*u5, - -u2*u6 + u0*u8, - -u1*u6 + u0*u7, - -u2*u3 + u0*u5, - -u1*u3 + u0*u4 + To: Closed subscheme of Projective Space of dimension 8 over Integer Ring + defined by: + -u5*u7 + u4*u8, -u5*u6 + u3*u8, -u4*u6 + u3*u7, + -u2*u7 + u1*u8, -u2*u4 + u1*u5, -u2*u6 + u0*u8, + -u1*u6 + u0*u7, -u2*u3 + u0*u5, -u1*u3 + u0*u4 Defn: Defined by sending (y0 : y1 : y2 , y3 : y4 : y5) to (y0*y3 : y0*y4 : y0*y5 : y1*y3 : y1*y4 : y1*y5 : y2*y3 : y2*y4 : y2*y5). :: - sage: T = ProductProjectiveSpaces([1, 2], CC, 'z') - sage: T.segre_embedding() + sage: T = ProductProjectiveSpaces([1, 2], CC, 'z') # needs sage.rings.real_mpfr + sage: T.segre_embedding() # needs sage.libs.singular sage.rings.real_mpfr Scheme morphism: - From: Product of projective spaces P^1 x P^2 over Complex Field with 53 bits of precision - To: Closed subscheme of Projective Space of dimension 5 over Complex Field with 53 bits of precision defined by: - -u2*u4 + u1*u5, - -u2*u3 + u0*u5, - -u1*u3 + u0*u4 + From: Product of projective spaces P^1 x P^2 + over Complex Field with 53 bits of precision + To: Closed subscheme of Projective Space of dimension 5 + over Complex Field with 53 bits of precision defined by: + -u2*u4 + u1*u5, -u2*u3 + u0*u5, -u1*u3 + u0*u4 Defn: Defined by sending (z0 : z1 , z2 : z3 : z4) to (z0*z2 : z0*z3 : z0*z4 : z1*z2 : z1*z3 : z1*z4). :: sage: T = ProductProjectiveSpaces([1, 2, 1], QQ, 'z') - sage: T.segre_embedding() + sage: T.segre_embedding() # needs sage.libs.singular Scheme morphism: From: Product of projective spaces P^1 x P^2 x P^1 over Rational Field - To: Closed subscheme of Projective Space of dimension 11 over - Rational Field defined by: - -u9*u10 + u8*u11, - -u7*u10 + u6*u11, - -u7*u8 + u6*u9, - -u5*u10 + u4*u11, - -u5*u8 + u4*u9, - -u5*u6 + u4*u7, - -u5*u9 + u3*u11, - -u5*u8 + u3*u10, - -u5*u8 + u2*u11, - -u4*u8 + u2*u10, - -u3*u8 + u2*u9, - -u3*u6 + u2*u7, - -u3*u4 + u2*u5, - -u5*u7 + u1*u11, - -u5*u6 + u1*u10, - -u3*u7 + u1*u9, - -u3*u6 + u1*u8, - -u5*u6 + u0*u11, - -u4*u6 + u0*u10, - -u3*u6 + u0*u9, - -u2*u6 + u0*u8, - -u1*u6 + u0*u7, - -u1*u4 + u0*u5, - -u1*u2 + u0*u3 + To: Closed subscheme of Projective Space of dimension 11 + over Rational Field defined by: + -u9*u10 + u8*u11, -u7*u10 + u6*u11, -u7*u8 + u6*u9, + -u5*u10 + u4*u11, -u5*u8 + u4*u9, -u5*u6 + u4*u7, + -u5*u9 + u3*u11, -u5*u8 + u3*u10, -u5*u8 + u2*u11, + -u4*u8 + u2*u10, -u3*u8 + u2*u9, -u3*u6 + u2*u7, + -u3*u4 + u2*u5, -u5*u7 + u1*u11, -u5*u6 + u1*u10, + -u3*u7 + u1*u9, -u3*u6 + u1*u8, -u5*u6 + u0*u11, + -u4*u6 + u0*u10, -u3*u6 + u0*u9, -u2*u6 + u0*u8, + -u1*u6 + u0*u7, -u1*u4 + u0*u5, -u1*u2 + u0*u3 Defn: Defined by sending (z0 : z1 , z2 : z3 : z4 , z5 : z6) to (z0*z2*z5 : z0*z2*z6 : z0*z3*z5 : z0*z3*z6 : z0*z4*z5 : z0*z4*z6 - : z1*z2*z5 : z1*z2*z6 : z1*z3*z5 : z1*z3*z6 : z1*z4*z5 : z1*z4*z6). + : z1*z2*z5 : z1*z2*z6 : z1*z3*z5 : z1*z3*z6 : z1*z4*z5 : z1*z4*z6). """ N = self._dims M = prod([n+1 for n in N]) - 1 @@ -1078,7 +1057,7 @@ def segre_embedding(self, PP=None, var='u'): Y = PS.subscheme(L) else: if PP.dimension_relative() != M: - raise ValueError("projective Space %s must be dimension %s")%(PP, M) + raise ValueError("projective Space %s must be dimension %s") % (PP, M) S = PP.coordinate_ring() psi = R.hom([0]*k + list(S.gens()), S) L = [psi(l) for l in L] @@ -1109,8 +1088,9 @@ def _point(self, *args, **kwds): EXAMPLES:: sage: u = QQ['u'].0 - sage: P = ProductProjectiveSpaces([1, 2], NumberField(u^2 - 2, 'v'), 'x') - sage: P([1, 3, u, 1, 1]) + sage: K = NumberField(u^2 - 2, 'v') # needs sage.rings.number_field + sage: P = ProductProjectiveSpaces([1, 2], K, 'x') # needs sage.rings.number_field + sage: P([1, 3, u, 1, 1]) # needs sage.rings.number_field (1/3 : 1 , v : 1 : 1) """ return ProductProjectiveSpaces_point_field(*args, **kwds) @@ -1126,7 +1106,7 @@ def _point_homset(self, *args, **kwds): sage: P.<x,y,z,w> = ProductProjectiveSpaces([1, 1], GF(5)) sage: P._point_homset(Spec(GF(5)), P) Set of rational points of Product of projective spaces P^1 x P^1 - over Finite Field of size 5 + over Finite Field of size 5 """ return SchemeHomset_points_product_projective_spaces_field(*args, **kwds) @@ -1161,38 +1141,47 @@ def points_of_bounded_height(self, **kwds): sage: PP = ProductProjectiveSpaces(QQ, [1, 2]) sage: sorted(list(PP.points_of_bounded_height(bound=1))) - [(-1 : 1 , -1 : -1 : 1), (-1 : 1 , -1 : 0 : 1), (-1 : 1 , -1 : 1 : 0), (-1 : 1 , -1 : 1 : 1), - (-1 : 1 , 0 : -1 : 1), (-1 : 1 , 0 : 0 : 1), (-1 : 1 , 0 : 1 : 0), (-1 : 1 , 0 : 1 : 1), - (-1 : 1 , 1 : -1 : 1), (-1 : 1 , 1 : 0 : 0), (-1 : 1 , 1 : 0 : 1), (-1 : 1 , 1 : 1 : 0), - (-1 : 1 , 1 : 1 : 1), (0 : 1 , -1 : -1 : 1), (0 : 1 , -1 : 0 : 1), (0 : 1 , -1 : 1 : 0), - (0 : 1 , -1 : 1 : 1), (0 : 1 , 0 : -1 : 1), (0 : 1 , 0 : 0 : 1), (0 : 1 , 0 : 1 : 0), - (0 : 1 , 0 : 1 : 1), (0 : 1 , 1 : -1 : 1), (0 : 1 , 1 : 0 : 0), (0 : 1 , 1 : 0 : 1), - (0 : 1 , 1 : 1 : 0), (0 : 1 , 1 : 1 : 1), (1 : 0 , -1 : -1 : 1), (1 : 0 , -1 : 0 : 1), - (1 : 0 , -1 : 1 : 0), (1 : 0 , -1 : 1 : 1), (1 : 0 , 0 : -1 : 1), (1 : 0 , 0 : 0 : 1), - (1 : 0 , 0 : 1 : 0), (1 : 0 , 0 : 1 : 1), (1 : 0 , 1 : -1 : 1), (1 : 0 , 1 : 0 : 0), - (1 : 0 , 1 : 0 : 1), (1 : 0 , 1 : 1 : 0), (1 : 0 , 1 : 1 : 1), (1 : 1 , -1 : -1 : 1), - (1 : 1 , -1 : 0 : 1), (1 : 1 , -1 : 1 : 0), (1 : 1 , -1 : 1 : 1), (1 : 1 , 0 : -1 : 1), - (1 : 1 , 0 : 0 : 1), (1 : 1 , 0 : 1 : 0), (1 : 1 , 0 : 1 : 1), (1 : 1 , 1 : -1 : 1), - (1 : 1 , 1 : 0 : 0), (1 : 1 , 1 : 0 : 1), (1 : 1 , 1 : 1 : 0), (1 : 1 , 1 : 1 : 1)] + [(-1 : 1 , -1 : -1 : 1), (-1 : 1 , -1 : 0 : 1), (-1 : 1 , -1 : 1 : 0), + (-1 : 1 , -1 : 1 : 1), (-1 : 1 , 0 : -1 : 1), (-1 : 1 , 0 : 0 : 1), + (-1 : 1 , 0 : 1 : 0), (-1 : 1 , 0 : 1 : 1), (-1 : 1 , 1 : -1 : 1), + (-1 : 1 , 1 : 0 : 0), (-1 : 1 , 1 : 0 : 1), (-1 : 1 , 1 : 1 : 0), + (-1 : 1 , 1 : 1 : 1), (0 : 1 , -1 : -1 : 1), (0 : 1 , -1 : 0 : 1), + (0 : 1 , -1 : 1 : 0), (0 : 1 , -1 : 1 : 1), (0 : 1 , 0 : -1 : 1), + (0 : 1 , 0 : 0 : 1), (0 : 1 , 0 : 1 : 0), (0 : 1 , 0 : 1 : 1), + (0 : 1 , 1 : -1 : 1), (0 : 1 , 1 : 0 : 0), (0 : 1 , 1 : 0 : 1), + (0 : 1 , 1 : 1 : 0), (0 : 1 , 1 : 1 : 1), (1 : 0 , -1 : -1 : 1), + (1 : 0 , -1 : 0 : 1), (1 : 0 , -1 : 1 : 0), (1 : 0 , -1 : 1 : 1), + (1 : 0 , 0 : -1 : 1), (1 : 0 , 0 : 0 : 1), (1 : 0 , 0 : 1 : 0), + (1 : 0 , 0 : 1 : 1), (1 : 0 , 1 : -1 : 1), (1 : 0 , 1 : 0 : 0), + (1 : 0 , 1 : 0 : 1), (1 : 0 , 1 : 1 : 0), (1 : 0 , 1 : 1 : 1), + (1 : 1 , -1 : -1 : 1), (1 : 1 , -1 : 0 : 1), (1 : 1 , -1 : 1 : 0), + (1 : 1 , -1 : 1 : 1), (1 : 1 , 0 : -1 : 1), (1 : 1 , 0 : 0 : 1), + (1 : 1 , 0 : 1 : 0), (1 : 1 , 0 : 1 : 1), (1 : 1 , 1 : -1 : 1), + (1 : 1 , 1 : 0 : 0), (1 : 1 , 1 : 0 : 1), (1 : 1 , 1 : 1 : 0), + (1 : 1 , 1 : 1 : 1)] :: sage: u = QQ['u'].0 - sage: P = ProductProjectiveSpaces([1, 1], NumberField(u^2 - 2, 'v')) - sage: sorted(list(P.points_of_bounded_height(bound=1.5))) - [(-v : 1 , -v : 1), (-v : 1 , -1 : 1), (-v : 1 , -1/2*v : 1), (-v : 1 , 0 : 1), (-v : 1 , 1/2*v : 1), - (-v : 1 , 1 : 0), (-v : 1 , 1 : 1), (-v : 1 , v : 1), (-1 : 1 , -v : 1), (-1 : 1 , -1 : 1), - (-1 : 1 , -1/2*v : 1), (-1 : 1 , 0 : 1), (-1 : 1 , 1/2*v : 1), (-1 : 1 , 1 : 0), (-1 : 1 , 1 : 1), - (-1 : 1 , v : 1), (-1/2*v : 1 , -v : 1), (-1/2*v : 1 , -1 : 1), (-1/2*v : 1 , -1/2*v : 1), (-1/2*v : 1 , 0 : 1), - (-1/2*v : 1 , 1/2*v : 1), (-1/2*v : 1 , 1 : 0), (-1/2*v : 1 , 1 : 1), (-1/2*v : 1 , v : 1), (0 : 1 , -v : 1), - (0 : 1 , -1 : 1), (0 : 1 , -1/2*v : 1), (0 : 1 , 0 : 1), (0 : 1 , 1/2*v : 1), (0 : 1 , 1 : 0), - (0 : 1 , 1 : 1), (0 : 1 , v : 1), (1/2*v : 1 , -v : 1), (1/2*v : 1 , -1 : 1), (1/2*v : 1 , -1/2*v : 1), - (1/2*v : 1 , 0 : 1), (1/2*v : 1 , 1/2*v : 1), (1/2*v : 1 , 1 : 0), (1/2*v : 1 , 1 : 1), (1/2*v : 1 , v : 1), - (1 : 0 , -v : 1), (1 : 0 , -1 : 1), (1 : 0 , -1/2*v : 1), (1 : 0 , 0 : 1), (1 : 0 , 1/2*v : 1), - (1 : 0 , 1 : 0), (1 : 0 , 1 : 1), (1 : 0 , v : 1), (1 : 1 , -v : 1), (1 : 1 , -1 : 1), - (1 : 1 , -1/2*v : 1), (1 : 1 , 0 : 1), (1 : 1 , 1/2*v : 1), (1 : 1 , 1 : 0), (1 : 1 , 1 : 1), - (1 : 1 , v : 1), (v : 1 , -v : 1), (v : 1 , -1 : 1), (v : 1 , -1/2*v : 1), (v : 1 , 0 : 1), - (v : 1 , 1/2*v : 1), (v : 1 , 1 : 0), (v : 1 , 1 : 1), (v : 1 , v : 1)] + sage: P = ProductProjectiveSpaces([1, 1], NumberField(u^2 - 2, 'v')) # needs sage.rings.number_field + sage: sorted(list(P.points_of_bounded_height(bound=1.5))) # needs sage.rings.number_field + [(-v : 1 , -v : 1), (-v : 1 , -1 : 1), (-v : 1 , -1/2*v : 1), (-v : 1 , 0 : 1), + (-v : 1 , 1/2*v : 1), (-v : 1 , 1 : 0), (-v : 1 , 1 : 1), (-v : 1 , v : 1), + (-1 : 1 , -v : 1), (-1 : 1 , -1 : 1), (-1 : 1 , -1/2*v : 1), (-1 : 1 , 0 : 1), + (-1 : 1 , 1/2*v : 1), (-1 : 1 , 1 : 0), (-1 : 1 , 1 : 1), (-1 : 1 , v : 1), + (-1/2*v : 1 , -v : 1), (-1/2*v : 1 , -1 : 1), (-1/2*v : 1 , -1/2*v : 1), + (-1/2*v : 1 , 0 : 1), (-1/2*v : 1 , 1/2*v : 1), (-1/2*v : 1 , 1 : 0), + (-1/2*v : 1 , 1 : 1), (-1/2*v : 1 , v : 1), (0 : 1 , -v : 1), (0 : 1 , -1 : 1), + (0 : 1 , -1/2*v : 1), (0 : 1 , 0 : 1), (0 : 1 , 1/2*v : 1), (0 : 1 , 1 : 0), + (0 : 1 , 1 : 1), (0 : 1 , v : 1), (1/2*v : 1 , -v : 1), (1/2*v : 1 , -1 : 1), + (1/2*v : 1 , -1/2*v : 1), (1/2*v : 1 , 0 : 1), (1/2*v : 1 , 1/2*v : 1), + (1/2*v : 1 , 1 : 0), (1/2*v : 1 , 1 : 1), (1/2*v : 1 , v : 1), (1 : 0 , -v : 1), + (1 : 0 , -1 : 1), (1 : 0 , -1/2*v : 1), (1 : 0 , 0 : 1), (1 : 0 , 1/2*v : 1), + (1 : 0 , 1 : 0), (1 : 0 , 1 : 1), (1 : 0 , v : 1), (1 : 1 , -v : 1), + (1 : 1 , -1 : 1), (1 : 1 , -1/2*v : 1), (1 : 1 , 0 : 1), (1 : 1 , 1/2*v : 1), + (1 : 1 , 1 : 0), (1 : 1 , 1 : 1), (1 : 1 , v : 1), (v : 1 , -v : 1), + (v : 1 , -1 : 1), (v : 1 , -1/2*v : 1), (v : 1 , 0 : 1), (v : 1 , 1/2*v : 1), + (v : 1 , 1 : 0), (v : 1 , 1 : 1), (v : 1 , v : 1)] """ B = kwds.pop('bound') tol = kwds.pop('tolerance', 1e-2) @@ -1251,12 +1240,12 @@ def __iter__(self): sage: P = ProductProjectiveSpaces([2, 1], GF(3)) sage: [x for x in P] [(0 : 0 : 1 , 0 : 1), - (0 : 1 : 1 , 0 : 1), - (0 : 2 : 1 , 0 : 1), - ... - (1 : 1 : 0 , 1 : 0), - (2 : 1 : 0 , 1 : 0), - (1 : 0 : 0 , 1 : 0)] + (0 : 1 : 1 , 0 : 1), + (0 : 2 : 1 , 0 : 1), + ... + (1 : 1 : 0 , 1 : 0), + (2 : 1 : 0 , 1 : 0), + (1 : 0 : 0 , 1 : 0)] """ iters = [iter(T) for T in self._components] L = [] @@ -1284,24 +1273,24 @@ def rational_points(self, F=None): sage: P = ProductProjectiveSpaces([1, 1], GF(5)) sage: P.rational_points() [(0 : 1 , 0 : 1), (1 : 1 , 0 : 1), (2 : 1 , 0 : 1), (3 : 1 , 0 : 1), (4 : 1 , 0 : 1), (1 : 0 , 0 : 1), - (0 : 1 , 1 : 1), (1 : 1 , 1 : 1), (2 : 1 , 1 : 1), (3 : 1 , 1 : 1), (4 : 1 , 1 : 1), (1 : 0 , 1 : 1), - (0 : 1 , 2 : 1), (1 : 1 , 2 : 1), (2 : 1 , 2 : 1), (3 : 1 , 2 : 1), (4 : 1 , 2 : 1), (1 : 0 , 2 : 1), - (0 : 1 , 3 : 1), (1 : 1 , 3 : 1), (2 : 1 , 3 : 1), (3 : 1 , 3 : 1), (4 : 1 , 3 : 1), (1 : 0 , 3 : 1), - (0 : 1 , 4 : 1), (1 : 1 , 4 : 1), (2 : 1 , 4 : 1), (3 : 1 , 4 : 1), (4 : 1 , 4 : 1), (1 : 0 , 4 : 1), - (0 : 1 , 1 : 0), (1 : 1 , 1 : 0), (2 : 1 , 1 : 0), (3 : 1 , 1 : 0), (4 : 1 , 1 : 0), (1 : 0 , 1 : 0)] + (0 : 1 , 1 : 1), (1 : 1 , 1 : 1), (2 : 1 , 1 : 1), (3 : 1 , 1 : 1), (4 : 1 , 1 : 1), (1 : 0 , 1 : 1), + (0 : 1 , 2 : 1), (1 : 1 , 2 : 1), (2 : 1 , 2 : 1), (3 : 1 , 2 : 1), (4 : 1 , 2 : 1), (1 : 0 , 2 : 1), + (0 : 1 , 3 : 1), (1 : 1 , 3 : 1), (2 : 1 , 3 : 1), (3 : 1 , 3 : 1), (4 : 1 , 3 : 1), (1 : 0 , 3 : 1), + (0 : 1 , 4 : 1), (1 : 1 , 4 : 1), (2 : 1 , 4 : 1), (3 : 1 , 4 : 1), (4 : 1 , 4 : 1), (1 : 0 , 4 : 1), + (0 : 1 , 1 : 0), (1 : 1 , 1 : 0), (2 : 1 , 1 : 0), (3 : 1 , 1 : 0), (4 : 1 , 1 : 0), (1 : 0 , 1 : 0)] :: sage: P = ProductProjectiveSpaces([1, 1], GF(2)) - sage: P.rational_points(GF(2^2,'a')) - [(0 : 1 , 0 : 1), (a : 1 , 0 : 1), (a + 1 : 1 , 0 : 1), (1 : 1 , 0 : 1), (1 : 0 , 0 : 1), (0 : 1 , a : 1), - (a : 1 , a : 1), (a + 1 : 1 , a : 1), (1 : 1 , a : 1), (1 : 0 , a : 1), (0 : 1 , a + 1 : 1), (a : 1 , a + 1 : 1), - (a + 1 : 1 , a + 1 : 1), (1 : 1 , a + 1 : 1), (1 : 0 , a + 1 : 1), (0 : 1 , 1 : 1), (a : 1 , 1 : 1), - (a + 1 : 1 , 1 : 1), (1 : 1 , 1 : 1), (1 : 0 , 1 : 1), (0 : 1 , 1 : 0), (a : 1 , 1 : 0), (a + 1 : 1 , 1 : 0), - (1 : 1 , 1 : 0), (1 : 0 , 1 : 0)] + sage: sorted(P.rational_points(GF(2^2, 'a')), key=str) # needs sage.rings.finite_rings + [(0 : 1 , 0 : 1), (0 : 1 , 1 : 0), (0 : 1 , 1 : 1), (0 : 1 , a + 1 : 1), (0 : 1 , a : 1), + (1 : 0 , 0 : 1), (1 : 0 , 1 : 0), (1 : 0 , 1 : 1), (1 : 0 , a + 1 : 1), (1 : 0 , a : 1), + (1 : 1 , 0 : 1), (1 : 1 , 1 : 0), (1 : 1 , 1 : 1), (1 : 1 , a + 1 : 1), (1 : 1 , a : 1), + (a + 1 : 1 , 0 : 1), (a + 1 : 1 , 1 : 0), (a + 1 : 1 , 1 : 1), (a + 1 : 1 , a + 1 : 1), (a + 1 : 1 , a : 1), + (a : 1 , 0 : 1), (a : 1 , 1 : 0), (a : 1 , 1 : 1), (a : 1 , a + 1 : 1), (a : 1 , a : 1)] """ if F is None: return list(self) - elif not is_FiniteField(F): - raise TypeError("second argument (= %s) must be a finite field"%F) + elif not isinstance(F, FiniteField): + raise TypeError("second argument (= %s) must be a finite field" % F) return list(self.base_extend(F)) diff --git a/src/sage/schemes/product_projective/subscheme.py b/src/sage/schemes/product_projective/subscheme.py index 963feea3d09..35433ba565b 100644 --- a/src/sage/schemes/product_projective/subscheme.py +++ b/src/sage/schemes/product_projective/subscheme.py @@ -45,19 +45,19 @@ class AlgebraicScheme_subscheme_product_projective(AlgebraicScheme_subscheme_pro EXAMPLES:: - sage: P.<x, y, u, v> = ProductProjectiveSpaces([1,1], QQ) - sage: P.subscheme([u*x^2-v*y*x]) - Closed subscheme of Product of projective spaces P^1 x P^1 over Rational - Field defined by: + sage: P.<x, y, u, v> = ProductProjectiveSpaces([1, 1], QQ) + sage: P.subscheme([u*x^2 - v*y*x]) + Closed subscheme of Product of projective spaces P^1 x P^1 over Rational Field + defined by: x^2*u - x*y*v TESTS:: sage: from sage.schemes.product_projective.subscheme \ import AlgebraicScheme_subscheme_product_projective - sage: AlgebraicScheme_subscheme_product_projective(P, [u*x^2-v*y*x]) - Closed subscheme of Product of projective spaces P^1 x P^1 over Rational - Field defined by: + sage: AlgebraicScheme_subscheme_product_projective(P, [u*x^2 - v*y*x]) + Closed subscheme of Product of projective spaces P^1 x P^1 + over Rational Field defined by: x^2*u - x*y*v """ @@ -78,70 +78,51 @@ def segre_embedding(self, PP=None): EXAMPLES:: - sage: X.<x,y,z,w,u,v> = ProductProjectiveSpaces([2,2], QQ) - sage: P = ProjectiveSpace(QQ,8,'t') + sage: X.<x,y,z,w,u,v> = ProductProjectiveSpaces([2, 2], QQ) + sage: P = ProjectiveSpace(QQ, 8, 't') sage: L = (-w - v)*x + (-w*y - u*z) - sage: Q = (-u*w - v^2)*x^2 + ((-w^2 - u*w + (-u*v - u^2))*y + (-w^2 - u*v)*z)*x + \ - ((-w^2 - u*w - u^2)*y^2 + (-u*w - v^2)*z*y + (-w^2 + (-v - u)*w)*z^2) + sage: Q = ((-u*w - v^2)*x^2 + ((-w^2 - u*w + (-u*v - u^2))*y + (-w^2 - u*v)*z)*x + ....: + ((-w^2 - u*w - u^2)*y^2 + (-u*w - v^2)*z*y + (-w^2 + (-v - u)*w)*z^2)) sage: W = X.subscheme([L,Q]) - sage: phi = W.segre_embedding(P) - sage: phi.codomain().ambient_space() == P + sage: phi = W.segre_embedding(P) # needs sage.libs.singular + sage: phi.codomain().ambient_space() == P # needs sage.libs.singular True :: - sage: PP.<x,y,u,v,s,t> = ProductProjectiveSpaces([1,1,1], CC) - sage: PP.subscheme([]).segre_embedding() + sage: PP.<x,y,u,v,s,t> = ProductProjectiveSpaces([1, 1, 1], CC) # needs sage.rings.real_mpfr + sage: PP.subscheme([]).segre_embedding() # needs sage.libs.singular sage.rings.real_mpfr Scheme morphism: From: Closed subscheme of Product of projective spaces P^1 x P^1 x P^1 - over Complex Field with 53 bits of precision defined by: - (no polynomials) - To: Closed subscheme of Projective Space of dimension 7 over Complex - Field with 53 bits of precision defined by: - -u5*u6 + u4*u7, - -u3*u6 + u2*u7, - -u3*u4 + u2*u5, - -u3*u5 + u1*u7, - -u3*u4 + u1*u6, - -u3*u4 + u0*u7, - -u2*u4 + u0*u6, - -u1*u4 + u0*u5, - -u1*u2 + u0*u3 + over Complex Field with 53 bits of precision defined by: + (no polynomials) + To: Closed subscheme of Projective Space of dimension 7 + over Complex Field with 53 bits of precision defined by: + -u5*u6 + u4*u7, -u3*u6 + u2*u7, -u3*u4 + u2*u5, + -u3*u5 + u1*u7, -u3*u4 + u1*u6, -u3*u4 + u0*u7, + -u2*u4 + u0*u6, -u1*u4 + u0*u5, -u1*u2 + u0*u3 Defn: Defined by sending (x : y , u : v , s : t) to (x*u*s : x*u*t : x*v*s : x*v*t : y*u*s : y*u*t : y*v*s : y*v*t). :: - sage: PP.<x,y,z,u,v,s,t> = ProductProjectiveSpaces([2,1,1], ZZ) - sage: PP.subscheme([x^3, u-v, s^2-t^2]).segre_embedding() + sage: PP.<x,y,z,u,v,s,t> = ProductProjectiveSpaces([2, 1, 1], ZZ) + sage: PP.subscheme([x^3, u - v, s^2 - t^2]).segre_embedding() # needs sage.libs.singular Scheme morphism: From: Closed subscheme of Product of projective spaces P^2 x P^1 x P^1 - over Integer Ring defined by: - x^3, - u - v, - s^2 - t^2 - To: Closed subscheme of Projective Space of dimension 11 over - Integer Ring defined by: - u10^2 - u11^2, - u9 - u11, - u8 - u10, - -u7*u10 + u6*u11, - u6*u10 - u7*u11, - u6^2 - u7^2, - u5 - u7, - u4 - u6, - u3^3, - -u3*u10 + u2*u11, - u2*u10 - u3*u11, - -u3*u6 + u2*u7, - u2*u6 - u3*u7, - u2*u3^2, - u2^2 - u3^2, - u1 - u3, - u0 - u2 + over Integer Ring defined by: + x^3, u - v, s^2 - t^2 + To: Closed subscheme of Projective Space of dimension 11 + over Integer Ring defined by: + u10^2 - u11^2, u9 - u11, u8 - u10, + -u7*u10 + u6*u11, u6*u10 - u7*u11, u6^2 - u7^2, + u5 - u7, u4 - u6, u3^3, + -u3*u10 + u2*u11, u2*u10 - u3*u11, -u3*u6 + u2*u7, + u2*u6 - u3*u7, u2*u3^2, u2^2 - u3^2, + u1 - u3, u0 - u2 Defn: Defined by sending (x : y : z , u : v , s : t) to - (x*u*s : x*u*t : x*v*s : x*v*t : y*u*s : y*u*t : y*v*s : y*v*t : - z*u*s : z*u*t : z*v*s : z*v*t). + (x*u*s : x*u*t : x*v*s : x*v*t : y*u*s : y*u*t : y*v*s : y*v*t + : z*u*s : z*u*t : z*v*s : z*v*t). """ AS = self.ambient_space() CR = AS.coordinate_ring() @@ -180,7 +161,7 @@ def segre_embedding(self, PP=None): Y = PS.subscheme(L) else: if PP.dimension_relative() != M: - raise ValueError("projective space %s must be dimension %s")%(PP, M) + raise ValueError("projective space %s must be dimension %s") % (PP, M) S = PP.coordinate_ring() psi = R.hom([0]*k + list(S.gens()), S) L = [psi(l) for l in L] @@ -205,44 +186,42 @@ def dimension(self): r""" Return the dimension of the algebraic subscheme. - OUTPUT: - - Integer. + OUTPUT: An integer. EXAMPLES:: - sage: X.<x,y,z,w,u,v> = ProductProjectiveSpaces([2,2],QQ) + sage: X.<x,y,z,w,u,v> = ProductProjectiveSpaces([2, 2], QQ) sage: L = (-w - v)*x + (-w*y - u*z) - sage: Q = (-u*w - v^2)*x^2 + ((-w^2 - u*w + (-u*v - u^2))*y + (-w^2 - u*v)*z)*x + \ - ((-w^2 - u*w - u^2)*y^2 + (-u*w - v^2)*z*y + (-w^2 + (-v - u)*w)*z^2) - sage: W = X.subscheme([L,Q]) - sage: W.dimension() + sage: Q = ((-u*w - v^2)*x^2 + ((-w^2 - u*w + (-u*v - u^2))*y + (-w^2 - u*v)*z)*x + ....: + ((-w^2 - u*w - u^2)*y^2 + (-u*w - v^2)*z*y + (-w^2 + (-v - u)*w)*z^2)) + sage: W = X.subscheme([L, Q]) + sage: W.dimension() # needs sage.libs.singular 2 :: - sage: PP.<x,y,z,u,v,s,t> = ProductProjectiveSpaces([2,1,1], QQ) - sage: X = PP.subscheme([x^3, x^5+y^5, z^6, x*u-v*y, s^2-t^2]) - sage: X.dimension() + sage: PP.<x,y,z,u,v,s,t> = ProductProjectiveSpaces([2, 1, 1], QQ) + sage: X = PP.subscheme([x^3, x^5 + y^5, z^6, x*u - v*y, s^2 - t^2]) + sage: X.dimension() # needs sage.libs.singular -1 :: - sage: PP = ProductProjectiveSpaces([2,1,3], CC, 't') - sage: PP.subscheme([]).dimension() + sage: PP = ProductProjectiveSpaces([2, 1, 3], CC, 't') # needs sage.rings.real_mpfr + sage: PP.subscheme([]).dimension() # needs sage.libs.singular sage.rings.real_mpfr 6 :: - sage: PP = ProductProjectiveSpaces([1,3,1], ZZ, 't') - sage: PP.subscheme([]).dimension() + sage: PP = ProductProjectiveSpaces([1, 3, 1], ZZ, 't') + sage: PP.subscheme([]).dimension() # needs sage.libs.singular 5 :: - sage: PP.<x,y,u,v,s,t> = ProductProjectiveSpaces([1,1,1], CC) - sage: X = PP.subscheme([x^2-y^2, u-v, s^2-t^2]) - sage: X.dimension() + sage: PP.<x,y,u,v,s,t> = ProductProjectiveSpaces([1,1,1], CC) # needs sage.rings.real_mpfr + sage: X = PP.subscheme([x^2 - y^2, u - v, s^2 - t^2]) # needs sage.libs.singular sage.rings.real_mpfr + sage: X.dimension() # needs sage.libs.singular sage.rings.real_mpfr 0 """ try: @@ -270,11 +249,11 @@ def is_smooth(self, point=None): EXAMPLES:: - sage: X.<x,y,z,w,u,v> = ProductProjectiveSpaces([2,2],QQ) + sage: X.<x,y,z,w,u,v> = ProductProjectiveSpaces([2, 2],QQ) sage: L = (-w - v)*x + (-w*y - u*z) - sage: Q = (-u*w - v^2)*x^2 + ((-w^2 - u*w + (-u*v - u^2))*y + (-w^2 - u*v)*z)*x + \ - ((-w^2 - u*w - u^2)*y^2 + (-u*w - v^2)*z*y + (-w^2 + (-v - u)*w)*z^2) - sage: W = X.subscheme([L,Q]) + sage: Q = ((-u*w - v^2)*x^2 + ((-w^2 - u*w + (-u*v - u^2))*y + (-w^2 - u*v)*z)*x + ....: + ((-w^2 - u*w - u^2)*y^2 + (-u*w - v^2)*z*y + (-w^2 + (-v - u)*w)*z^2)) + sage: W = X.subscheme([L, Q]) sage: W.is_smooth() Traceback (most recent call last): ... @@ -285,7 +264,7 @@ def is_smooth(self, point=None): def affine_patch(self, I, return_embedding=False): r""" Return the `I^{th}` affine patch of this projective scheme - where 'I' is a multi-index. + where `I` is a multi-index. INPUT: @@ -301,21 +280,18 @@ def affine_patch(self, I, return_embedding=False): EXAMPLES:: - sage: PP.<x,y,z,w,u,v> = ProductProjectiveSpaces([3,1],QQ) - sage: W = PP.subscheme([y^2*z-x^3,z^2-w^2,u^3-v^3]) - sage: W.affine_patch([0,1],True) + sage: PP.<x,y,z,w,u,v> = ProductProjectiveSpaces([3, 1],QQ) + sage: W = PP.subscheme([y^2*z - x^3, z^2 - w^2, u^3 - v^3]) + sage: W.affine_patch([0, 1], True) (Closed subscheme of Affine Space of dimension 4 over Rational Field defined by: x0^2*x1 - 1, x1^2 - x2^2, - x3^3 - 1, Scheme morphism: - From: Closed subscheme of Affine Space of dimension 4 over Rational Field defined by: - x0^2*x1 - 1, - x1^2 - x2^2, - x3^3 - 1 - To: Closed subscheme of Product of projective spaces P^3 x P^1 over Rational Field defined by: - -x^3 + y^2*z, - z^2 - w^2, - u^3 - v^3 + x3^3 - 1, + Scheme morphism: + From: Closed subscheme of Affine Space of dimension 4 + over Rational Field defined by: x0^2*x1 - 1, x1^2 - x2^2, x3^3 - 1 + To: Closed subscheme of Product of projective spaces P^3 x P^1 + over Rational Field defined by: -x^3 + y^2*z, z^2 - w^2, u^3 - v^3 Defn: Defined on coordinates by sending (x0, x1, x2, x3) to (1 : x0 : x1 : x2 , x3 : 1)) """ @@ -324,11 +300,11 @@ def affine_patch(self, I, return_embedding=False): PP = self.ambient_space() N = PP.dimension_relative_components() if len(I) != len(N): - raise ValueError('The argument I=%s must have %s entries'%(I,len(N))) + raise ValueError('The argument I=%s must have %s entries' % (I,len(N))) I = tuple([int(i) for i in I]) # implicit type checking for i in range(len(I)): if I[i] < 0 or I[i] > N[i]: - raise ValueError("Argument i (= %s) must be between 0 and %s."%(I[i], N[i])) + raise ValueError("Argument i (= %s) must be between 0 and %s." % (I[i], N[i])) #see if we've already created this affine patch try: if return_embedding: @@ -377,32 +353,33 @@ def intersection_multiplicity(self, X, P): Multiplicity of a fixed point of the map `z^2 + \frac{1}{4}`:: - sage: PP.<x,y,u,v> = ProductProjectiveSpaces(QQ, [1,1]) + sage: PP.<x,y,u,v> = ProductProjectiveSpaces(QQ, [1, 1]) sage: G = PP.subscheme([(x^2 + 1/4*y^2)*v - y^2*u]) sage: D = PP.subscheme([x*v - y*u]) - sage: sorted(G.intersection(D).rational_points()) + sage: sorted(G.intersection(D).rational_points()) # needs sage.libs.singular [(1/2 : 1 , 1/2 : 1), (1 : 0 , 1 : 0)] sage: Q = PP([1/2,1,1/2,1]) - sage: G.intersection_multiplicity(D, Q) + sage: G.intersection_multiplicity(D, Q) # needs sage.libs.singular 2 :: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) - sage: PP.<x,y,z,u,v,w> = ProductProjectiveSpaces(F, [2,2]) + sage: PP.<x,y,z,u,v,w> = ProductProjectiveSpaces(F, [2, 2]) sage: X = PP.subscheme([z^5 + 3*x*y^4 + 8*y^5, u^2 - v^2]) sage: Y = PP.subscheme([x^6 + z^6, w*z - v*y]) sage: Q = PP([a,a+1,1,a,a,1]) - sage: X.intersection_multiplicity(Y, Q) + sage: X.intersection_multiplicity(Y, Q) # needs sage.libs.singular 16 :: - sage: PP.<x,y,z,u,v,w> = ProductProjectiveSpaces(QQ, [2,2]) + sage: PP.<x,y,z,u,v,w> = ProductProjectiveSpaces(QQ, [2, 2]) sage: X = PP.subscheme([x^2*u^3 + y*z*u*v^2, x - y]) sage: Y = PP.subscheme([u^3 - w^3, x*v - y*w, z^3*w^2 - y^3*u*v]) sage: Q = PP([0,0,1,0,1,0]) - sage: X.intersection_multiplicity(Y, Q) + sage: X.intersection_multiplicity(Y, Q) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: the intersection of this subscheme and (=Closed subscheme of Affine Space of dimension 4 @@ -412,7 +389,7 @@ def intersection_multiplicity(self, X, P): try: PP(P) except TypeError: - raise TypeError("(=%s) must be a point in the ambient space of this subscheme and (=%s)"%(P,X)) + raise TypeError("(=%s) must be a point in the ambient space of this subscheme and (=%s)" % (P,X)) # find an affine chart of the ambient space of this subscheme that contains P indices = [] aff_pt = [] @@ -441,17 +418,17 @@ def multiplicity(self, P): - ``P`` -- a point on this subscheme. - OUTPUT: an integer. + OUTPUT: An integer. EXAMPLES:: - sage: PP.<x,y,z,w> = ProductProjectiveSpaces(QQ, [1,1]) + sage: PP.<x,y,z,w> = ProductProjectiveSpaces(QQ, [1, 1]) sage: X = PP.subscheme([x^4*z^3 - y^4*w^3]) sage: Q1 = PP([1,1,1,1]) - sage: X.multiplicity(Q1) + sage: X.multiplicity(Q1) # needs sage.libs.singular 1 sage: Q2 = PP([0,1,1,0]) - sage: X.multiplicity(Q2) + sage: X.multiplicity(Q2) # needs sage.libs.singular 3 :: @@ -459,10 +436,10 @@ def multiplicity(self, P): sage: PP.<x,y,z,w,u> = ProductProjectiveSpaces(GF(11), [1,2]) sage: X = PP.subscheme([x^7*u - y^7*z, u^6*x^2 - w^3*z^3*x*y - w^6*y^2]) sage: Q1 = PP([1,0,10,1,0]) - sage: X.multiplicity(Q1) + sage: X.multiplicity(Q1) # needs sage.libs.singular sage.rings.finite_rings 1 sage: Q2 = PP([1,0,1,0,0]) - sage: X.multiplicity(Q2) + sage: X.multiplicity(Q2) # needs sage.libs.singular sage.rings.finite_rings 4 """ PP = self.ambient_space() diff --git a/src/sage/schemes/projective/__init__.py b/src/sage/schemes/projective/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/projective/proj_bdd_height.py b/src/sage/schemes/projective/proj_bdd_height.py index 9034f2d5352..744313fc77f 100644 --- a/src/sage/schemes/projective/proj_bdd_height.py +++ b/src/sage/schemes/projective/proj_bdd_height.py @@ -22,10 +22,12 @@ from math import floor from sage.schemes.projective.projective_space import ProjectiveSpace +from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.all import RealField +from sage.rings.real_mpfr import RealField from sage.rings.number_field.unit_group import UnitGroup -from sage.arith.all import gcd +from sage.arith.misc import gcd +from sage.arith.functions import lcm from sage.matrix.constructor import matrix, column_matrix from sage.libs.pari.all import pari from sage.modules.free_module_element import vector @@ -33,39 +35,106 @@ from sage.geometry.polyhedron.constructor import Polyhedron -def QQ_points_of_bounded_height(dim, bound): +def ZZ_points_of_bounded_height(PS, dim, bound): r""" Return an iterator of the points in ``self`` of absolute multiplicative height of at most ``bound`` in the rational field. INPUT: + - ``PS`` -- a projective space + + - ``dim`` -- a positive integer + + - ``bound`` -- a positive integer + + OUTPUT: + + - an iterator of points of bounded height + + EXAMPLES:: + + sage: from sage.schemes.projective.proj_bdd_height import ZZ_points_of_bounded_height + sage: PS = ProjectiveSpace(ZZ, 1) + sage: sorted(list(ZZ_points_of_bounded_height(PS, 1, 1))) + [(-1 : -1), (-1 : 0), (-1 : 1), (0 : -1)] + sage: len(list(ZZ_points_of_bounded_height(PS, 1, 5))) + 40 + sage: sorted(list(ZZ_points_of_bounded_height(PS, 1, 2))) + [(-2 : -1), (-2 : 1), (-1 : -2), (-1 : -1), + (-1 : 0), (-1 : 1), (-1 : 2), (0 : -1)] + sage: PS = ProjectiveSpace(ZZ, 2) + sage: sorted(list(ZZ_points_of_bounded_height(PS, 2, 1))) + [(-1 : -1 : -1), (-1 : -1 : 0), (-1 : -1 : 1), (-1 : 0 : -1), + (-1 : 0 : 0), (-1 : 0 : 1), (-1 : 1 : -1), (-1 : 1 : 0), + (-1 : 1 : 1), (0 : -1 : -1), (0 : -1 : 0), (0 : -1 : 1), + (0 : 0 : -1)] + + There are no points of negative height:: + + sage: from sage.schemes.projective.proj_bdd_height import ZZ_points_of_bounded_height + sage: PS = ProjectiveSpace(ZZ, 1) + sage: list(ZZ_points_of_bounded_height(PS, 1, -3)) + [] + """ + if bound < 1: + return iter(set([])) + + points_of_bounded_height = set([]) + + for t in itertools.product(range(-bound, bound+1), repeat=dim+1): + if gcd(t) == 1: + point = PS(t) + if point not in points_of_bounded_height: + points_of_bounded_height.add(point) + yield point + + +def QQ_points_of_bounded_height(PS, dim, bound, normalize=False): + r""" + Return an iterator of the points in ``self`` of absolute multiplicative + height of at most ``bound`` in the rational field. + + INPUT: + + - ``PS`` -- a projective space + - ``dim`` -- a positive integer - ``bound`` -- a real number + - ``normalize`` -- boolean (optional, default: ``False``); whether to + normalize the coordinates of returned points + OUTPUT: - an iterator of points of bounded height - EXAMPLES: + EXAMPLES:: sage: from sage.schemes.projective.proj_bdd_height import QQ_points_of_bounded_height - sage: sorted(list(QQ_points_of_bounded_height(1, 1))) + sage: PS = ProjectiveSpace(QQ, 1) + sage: sorted(list(QQ_points_of_bounded_height(PS, 1, 1))) [(-1 : 1), (0 : 1), (1 : 0), (1 : 1)] - sage: len(list(QQ_points_of_bounded_height(1, 5))) + sage: len(list(QQ_points_of_bounded_height(PS, 1, 5))) 40 + sage: sorted(list(QQ_points_of_bounded_height(PS, 1, 2))) + [(-2 : 1), (-1 : 1), (-1/2 : 1), (0 : 1), + (1/2 : 1), (1 : 0), (1 : 1), (2 : 1)] + sage: sorted(list(QQ_points_of_bounded_height(PS, 1, 2, normalize=True))) + [(-2 : 1), (-1 : 1), (-1 : 2), (0 : 1), + (1 : 0), (1 : 1), (1 : 2), (2 : 1)] There are no points of negative height:: sage: from sage.schemes.projective.proj_bdd_height import QQ_points_of_bounded_height - sage: list(QQ_points_of_bounded_height(1, -3)) + sage: PS = ProjectiveSpace(QQ, 1) + sage: list(QQ_points_of_bounded_height(PS, 1, -3)) [] """ if bound < 1: return iter(set([])) - PN = ProjectiveSpace(QQ, dim) unit_tuples = list(itertools.product([-1, 1], repeat=dim)) points_of_bounded_height = set([]) increasing_tuples = itertools.combinations_with_replacement(range(floor(bound + 1)), dim + 1) @@ -73,20 +142,23 @@ def QQ_points_of_bounded_height(dim, bound): if gcd(t) == 1: for p in itertools.permutations(t): for u in unit_tuples: - point = PN([a*b for a, b in zip(u, p)] + [p[dim]]) + point = PS([a*b for a, b in zip(u, p)] + [p[dim]]) if point not in points_of_bounded_height: + if normalize: + point.scale_by(lcm([point[i].denominator() for i in range(dim + 1)])) + points_of_bounded_height.add(point) yield point -def IQ_points_of_bounded_height(PN, K, dim, bound): +def IQ_points_of_bounded_height(PS, K, dim, bound): r""" Return an iterator of the points in ``self`` of absolute multiplicative height of at most ``bound`` in the imaginary quadratic field ``K``. INPUT: - - ``PN`` -- a projective space + - ``PS`` -- a projective space - ``K`` -- a number field @@ -100,6 +172,7 @@ def IQ_points_of_bounded_height(PN, K, dim, bound): EXAMPLES: + sage: # needs sage.rings.number_field sage: from sage.schemes.projective.proj_bdd_height import IQ_points_of_bounded_height sage: CF.<a> = CyclotomicField(3) sage: P.<x,y,z> = ProjectiveSpace(CF, 2) @@ -147,13 +220,14 @@ def IQ_points_of_bounded_height(PN, K, dim, bound): if a == K.ideal(point_coordinates): for p in itertools.permutations(point_coordinates): for u in unit_tuples: - point = PN([i*j for i, j in zip(u, p)] + [p[dim]]) + point = PS([i*j for i, j in zip(u, p)] + [p[dim]]) + if point not in points_in_class_a: points_in_class_a.add(point) yield point -def points_of_bounded_height(PN, K, dim, bound, prec=53): +def points_of_bounded_height(PS, K, dim, bound, prec=53): r""" Return an iterator of the points in ``K`` with dimension ``dim`` of absolute multiplicative height of at most ``bound``. @@ -164,7 +238,7 @@ def points_of_bounded_height(PN, K, dim, bound, prec=53): INPUT: - - ``PN`` -- a projective space + - ``PS`` -- a projective space - ``K`` -- a number field @@ -178,13 +252,50 @@ def points_of_bounded_height(PN, K, dim, bound, prec=53): - an iterator of points of bounded height - EXAMPLES: + EXAMPLES:: sage: from sage.schemes.projective.proj_bdd_height import points_of_bounded_height + sage: x = polygen(ZZ, 'x') + + sage: # needs sage.geometry.polyhedron sage.libs.pari sage.rings.number_field sage: K.<a> = NumberField(x^3 - 7) sage: P.<x,y,z> = ProjectiveSpace(K, 2) - sage: len(list(points_of_bounded_height(P, K, 2, 1))) - 13 + sage: sorted(list(points_of_bounded_height(P, K, 2, 1))) + [(0 : 0 : 1), (0 : 1 : 0), (1 : 0 : 0), (0 : -1 : 1), (0 : 1 : 1), + (-1 : 0 : 1), (1 : 0 : 1), (1 : 1 : 0), (-1 : 1 : 0), (-1 : -1 : 1), + (-1 : 1 : 1), (1 : -1 : 1), (1 : 1 : 1)] + + :: + + sage: # needs sage.geometry.polyhedron sage.libs.pari sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(3*x^2 + 1) + sage: O = K.maximal_order() + sage: P.<z,w> = ProjectiveSpace(O, 1) + sage: len(list(P.points_of_bounded_height(bound=2))) + 44 + + :: + + sage: # needs sage.geometry.polyhedron sage.libs.pari sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(3*x^2 + 1) + sage: O = K.maximal_order() + sage: P.<z,w> = ProjectiveSpace(O, 1) + sage: sorted(list(P.points_of_bounded_height(bound=1))) + [(-1 : 1), (-3/2*a - 1/2 : 1), (3/2*a - 1/2 : 1), (0 : 1), + (-3/2*a + 1/2 : 0), (-3/2*a + 1/2 : 1), (3/2*a + 1/2 : 1), (1 : 1)] + + :: + + sage: # needs sage.geometry.polyhedron sage.libs.pari sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<z> = NumberField(x^2 - 2) + sage: R2.<y> = K[] + sage: L.<w> = K.extension(y^2 - 3) + sage: P.<a,b> = ProjectiveSpace(L, 1) + sage: len(list(P.points_of_bounded_height(bound=2))) + 256 """ if bound < 1: return iter([]) @@ -343,7 +454,8 @@ def points_of_bounded_height(PN, K, dim, bound, prec=53): if log_arch_height <= log_arch_height_bound and a == K.ideal(point_coordinates): for p in itertools.permutations(point_coordinates): for u in unit_tuples: - point = PN([i*j for i, j in zip(u, p)] + [p[dim]]) + point = PS([i*j for i, j in zip(u, p)] + [p[dim]]) + if point not in points_in_class_a: points_in_class_a.add(point) yield point diff --git a/src/sage/schemes/projective/projective_homset.py b/src/sage/schemes/projective/projective_homset.py index 3ffd4a6b6e4..e1031e71fcf 100644 --- a/src/sage/schemes/projective/projective_homset.py +++ b/src/sage/schemes/projective/projective_homset.py @@ -47,7 +47,7 @@ from sage.rings.rational_field import is_RationalField from sage.categories.fields import Fields from sage.categories.number_fields import NumberFields -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme from copy import copy @@ -83,17 +83,17 @@ def points(self, **kwds): kwds: - - ``bound`` - real number (optional, default=0). The bound for the coordinates for + - ``bound`` - real number (optional, default: 0). The bound for the coordinates for subschemes with dimension at least 1. - - ``precision`` - integer (optional, default=53). The precision to use to + - ``precision`` - integer (optional, default: 53). The precision to use to compute the elements of bounded height for number fields. - - ``point_tolerance`` - positive real number (optional, default=10^(-10)). + - ``point_tolerance`` - positive real number (optional, default: `10^{-10}`). For numerically inexact fields, two points are considered the same if their coordinates are within tolerance. - - ``zero_tolerance`` - positive real number (optional, default=10^(-10)). + - ``zero_tolerance`` - positive real number (optional, default: `10^{-10}`). For numerically inexact fields, points are on the subscheme if they satisfy the equations to within tolerance. @@ -112,57 +112,61 @@ def points(self, **kwds): EXAMPLES:: - sage: P.<x,y> = ProjectiveSpace(QQ,1) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: P(QQ).points(bound=4) [(-4 : 1), (-3 : 1), (-2 : 1), (-3/2 : 1), (-4/3 : 1), (-1 : 1), - (-3/4 : 1), (-2/3 : 1), (-1/2 : 1), (-1/3 : 1), (-1/4 : 1), (0 : 1), - (1/4 : 1), (1/3 : 1), (1/2 : 1), (2/3 : 1), (3/4 : 1), (1 : 0), (1 : 1), - (4/3 : 1), (3/2 : 1), (2 : 1), (3 : 1), (4 : 1)] + (-3/4 : 1), (-2/3 : 1), (-1/2 : 1), (-1/3 : 1), (-1/4 : 1), (0 : 1), + (1/4 : 1), (1/3 : 1), (1/2 : 1), (2/3 : 1), (3/4 : 1), (1 : 0), (1 : 1), + (4/3 : 1), (3/2 : 1), (2 : 1), (3 : 1), (4 : 1)] :: sage: u = QQ['u'].0 - sage: K.<v> = NumberField(u^2 + 3) - sage: P.<x,y,z> = ProjectiveSpace(K,2) - sage: len(P(K).points(bound=1.8)) + sage: K.<v> = NumberField(u^2 + 3) # needs sage.rings.number_field + sage: P.<x,y,z> = ProjectiveSpace(K, 2) # needs sage.rings.number_field + sage: len(P(K).points(bound=1.8)) # needs sage.rings.number_field 309 :: - sage: P1 = ProjectiveSpace(GF(2),1) - sage: F.<a> = GF(4,'a') - sage: P1(F).points() + sage: P1 = ProjectiveSpace(GF(2), 1) + sage: F.<a> = GF(4, 'a') # needs sage.rings.finite_rings + sage: P1(F).points() # needs sage.libs.singular sage.rings.finite_rings [(0 : 1), (1 : 0), (1 : 1), (a : 1), (a + 1 : 1)] :: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: E = P.subscheme([(y^3-y*z^2) - (x^3-x*z^2),(y^3-y*z^2) + (x^3-x*z^2)]) - sage: E(P.base_ring()).points() - [(-1 : -1 : 1), (-1 : 0 : 1), (-1 : 1 : 1), (0 : -1 : 1), (0 : 0 : 1), (0 : 1 : 1), - (1 : -1 : 1), (1 : 0 : 1), (1 : 1 : 1)] + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: E = P.subscheme([(y^3-y*z^2) - (x^3-x*z^2), (y^3-y*z^2) + (x^3-x*z^2)]) + sage: E(P.base_ring()).points() # needs sage.libs.singular + [(-1 : -1 : 1), (-1 : 0 : 1), (-1 : 1 : 1), (0 : -1 : 1), (0 : 0 : 1), + (0 : 1 : 1), (1 : -1 : 1), (1 : 0 : 1), (1 : 1 : 1)] :: + sage: # needs sage.rings.real_mpfr sage: P.<x,y,z> = ProjectiveSpace(CC, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) - sage: L=E(P.base_ring()).points(); sorted(L, key=str) - verbose 0 (...: projective_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. + sage: L = E(P.base_ring()).points(); sorted(L, key=str) # needs sage.libs.singular + verbose 0 (...: projective_homset.py, points) Warning: computations in + the numerical fields are inexact;points may be computed partially or incorrectly. [(-0.500000000000000 + 0.866025403784439*I : 1.00000000000000 : 0.000000000000000), - (-0.500000000000000 - 0.866025403784439*I : 1.00000000000000 : 0.000000000000000), - (-1.00000000000000*I : 0.000000000000000 : 1.00000000000000), - (0.000000000000000 : 0.000000000000000 : 1.00000000000000), - (1.00000000000000 : 1.00000000000000 : 0.000000000000000), - (1.00000000000000*I : 0.000000000000000 : 1.00000000000000)] - sage: L[0].codomain() + (-0.500000000000000 - 0.866025403784439*I : 1.00000000000000 : 0.000000000000000), + (-1.00000000000000*I : 0.000000000000000 : 1.00000000000000), + (0.000000000000000 : 0.000000000000000 : 1.00000000000000), + (1.00000000000000 : 1.00000000000000 : 0.000000000000000), + (1.00000000000000*I : 0.000000000000000 : 1.00000000000000)] + sage: L[0].codomain() # needs sage.libs.singular Projective Space of dimension 2 over Complex Field with 53 bits of precision :: + sage: # needs sage.rings.complex_double sage: P.<x,y,z> = ProjectiveSpace(CDF, 2) sage: E = P.subscheme([y^2 + x^2 + z^2, x*y*z]) - sage: len(E(P.base_ring()).points()) - verbose 0 (...: projective_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. + sage: len(E(P.base_ring()).points()) # needs sage.libs.singular + verbose 0 (...: projective_homset.py, points) Warning: computations in + the numerical fields are inexact;points may be computed partially or incorrectly. 6 """ from sage.schemes.projective.projective_space import is_ProjectiveSpace @@ -272,7 +276,7 @@ def points(self, **kwds): prec = kwds.pop('precision', 53) if is_RationalField(R): if not B > 0: - raise TypeError("a positive bound B (= %s) must be specified"%B) + raise TypeError("a positive bound B (= %s) must be specified" % B) if isinstance(X, AlgebraicScheme_subscheme): # sieve should only be called for subschemes from sage.schemes.projective.projective_rational_point import sieve return sieve(X, B) @@ -281,14 +285,14 @@ def points(self, **kwds): return enum_projective_rational_field(self, B) elif R in NumberFields(): if not B > 0: - raise TypeError("a positive bound B (= %s) must be specified"%B) + raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.projective.projective_rational_point import enum_projective_number_field return enum_projective_number_field(self, bound=B, tolerance=tol, precision=prec) - elif is_FiniteField(R): + elif isinstance(R, FiniteField): from sage.schemes.projective.projective_rational_point import enum_projective_finite_field return enum_projective_finite_field(self.extended_codomain()) else: - raise TypeError("unable to enumerate points over %s"%R) + raise TypeError("unable to enumerate points over %s" % R) def numerical_points(self, F=None, **kwds): """ @@ -305,11 +309,11 @@ def numerical_points(self, F=None, **kwds): kwds: - - ``point_tolerance`` - positive real number (optional, default=10^(-10)). + - ``point_tolerance`` - positive real number (optional, default: `10^{-10}`). For numerically inexact fields, two points are considered the same if their coordinates are within tolerance. - - ``zero_tolerance`` - positive real number (optional, default=10^(-10)). + - ``zero_tolerance`` - positive real number (optional, default: `10^{-10}`). For numerically inexact fields, points are on the subscheme if they satisfy the equations to within tolerance. @@ -324,33 +328,33 @@ def numerical_points(self, F=None, **kwds): sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) - sage: L = E(QQ).numerical_points(F=RR); L + sage: L = E(QQ).numerical_points(F=RR); L # needs sage.libs.singular [(0.000000000000000 : 0.000000000000000 : 1.00000000000000), (1.00000000000000 : 1.00000000000000 : 0.000000000000000)] - sage: L[0].codomain() + sage: L[0].codomain() # needs sage.libs.singular Projective Space of dimension 2 over Real Field with 53 bits of precision :: sage: S.<a> = QQ[] - sage: K.<v> = NumberField(a^5 - 7, embedding=CC((7)**(1/5))) - sage: P.<x,y,z> = ProjectiveSpace(K,2) - sage: X = P.subscheme([x^2 - v^2*z^2, y-v*z]) - sage: len(X(K).numerical_points(F=CDF)) + sage: K.<v> = NumberField(a^5 - 7, embedding=CC(7)**(1/5)) # needs sage.rings.number_field + sage: P.<x,y,z> = ProjectiveSpace(K, 2) # needs sage.rings.number_field + sage: X = P.subscheme([x^2 - v^2*z^2, y - v*z]) # needs sage.rings.number_field + sage: len(X(K).numerical_points(F=CDF)) # needs sage.libs.singular sage.rings.number_field 2 :: sage: P.<x1, x2, x3> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([3000*x1^50 + 9875643*x2^2*x3^48 + 12334545*x2^50, x1 + x2]) - sage: len(E(P.base_ring()).numerical_points(F=CDF, zero_tolerance=1e-6)) + sage: len(E(P.base_ring()).numerical_points(F=CDF, zero_tolerance=1e-6)) # needs sage.libs.singular 49 TESTS:: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) - sage: E(QQ).numerical_points(F=CDF, point_tolerance=-1) + sage: E(QQ).numerical_points(F=CDF, point_tolerance=-1) # needs sage.libs.singular Traceback (most recent call last): ... ValueError: tolerance must be positive @@ -359,7 +363,7 @@ def numerical_points(self, F=None, **kwds): sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) - sage: E(QQ).numerical_points(F=CC, zero_tolerance=-1) + sage: E(QQ).numerical_points(F=CC, zero_tolerance=-1) # needs sage.libs.singular Traceback (most recent call last): ... ValueError: tolerance must be positive @@ -368,7 +372,7 @@ def numerical_points(self, F=None, **kwds): sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) - sage: E(QQ).numerical_points(F=QQbar) + sage: E(QQ).numerical_points(F=QQbar) # needs sage.rings.number_field Traceback (most recent call last): ... TypeError: F must be a numerical field @@ -422,7 +426,7 @@ def numerical_points(self, F=None, **kwds): #of coordinates known so far. This results in a single #variable polynomial (by elimination) L = G[i].substitute(P) - if len(RF(L).variables())==1: + if len(RF(L).variables()) == 1: for pol in L.univariate_polynomial().roots(ring=F, multiplicities=False): r = L.variables()[0] varindex = RF.gens().index(r) @@ -488,45 +492,44 @@ def points(self, B=0): EXAMPLES:: sage: from sage.schemes.projective.projective_homset import SchemeHomset_points_projective_ring - sage: H = SchemeHomset_points_projective_ring(Spec(ZZ), ProjectiveSpace(ZZ,2)) + sage: H = SchemeHomset_points_projective_ring(Spec(ZZ), ProjectiveSpace(ZZ, 2)) sage: H.points(3) - [(0 : 0 : 1), (0 : 1 : -3), (0 : 1 : -2), (0 : 1 : -1), (0 : 1 : 0), (0 - : 1 : 1), (0 : 1 : 2), (0 : 1 : 3), (0 : 2 : -3), (0 : 2 : -1), (0 : 2 : - 1), (0 : 2 : 3), (0 : 3 : -2), (0 : 3 : -1), (0 : 3 : 1), (0 : 3 : 2), - (1 : -3 : -3), (1 : -3 : -2), (1 : -3 : -1), (1 : -3 : 0), (1 : -3 : 1), - (1 : -3 : 2), (1 : -3 : 3), (1 : -2 : -3), (1 : -2 : -2), (1 : -2 : -1), - (1 : -2 : 0), (1 : -2 : 1), (1 : -2 : 2), (1 : -2 : 3), (1 : -1 : -3), - (1 : -1 : -2), (1 : -1 : -1), (1 : -1 : 0), (1 : -1 : 1), (1 : -1 : 2), - (1 : -1 : 3), (1 : 0 : -3), (1 : 0 : -2), (1 : 0 : -1), (1 : 0 : 0), (1 - : 0 : 1), (1 : 0 : 2), (1 : 0 : 3), (1 : 1 : -3), (1 : 1 : -2), (1 : 1 : - -1), (1 : 1 : 0), (1 : 1 : 1), (1 : 1 : 2), (1 : 1 : 3), (1 : 2 : -3), - (1 : 2 : -2), (1 : 2 : -1), (1 : 2 : 0), (1 : 2 : 1), (1 : 2 : 2), (1 : - 2 : 3), (1 : 3 : -3), (1 : 3 : -2), (1 : 3 : -1), (1 : 3 : 0), (1 : 3 : - 1), (1 : 3 : 2), (1 : 3 : 3), (2 : -3 : -3), (2 : -3 : -2), (2 : -3 : - -1), (2 : -3 : 0), (2 : -3 : 1), (2 : -3 : 2), (2 : -3 : 3), (2 : -2 : - -3), (2 : -2 : -1), (2 : -2 : 1), (2 : -2 : 3), (2 : -1 : -3), (2 : -1 : - -2), (2 : -1 : -1), (2 : -1 : 0), (2 : -1 : 1), (2 : -1 : 2), (2 : -1 : - 3), (2 : 0 : -3), (2 : 0 : -1), (2 : 0 : 1), (2 : 0 : 3), (2 : 1 : -3), - (2 : 1 : -2), (2 : 1 : -1), (2 : 1 : 0), (2 : 1 : 1), (2 : 1 : 2), (2 : - 1 : 3), (2 : 2 : -3), (2 : 2 : -1), (2 : 2 : 1), (2 : 2 : 3), (2 : 3 : - -3), (2 : 3 : -2), (2 : 3 : -1), (2 : 3 : 0), (2 : 3 : 1), (2 : 3 : 2), - (2 : 3 : 3), (3 : -3 : -2), (3 : -3 : -1), (3 : -3 : 1), (3 : -3 : 2), - (3 : -2 : -3), (3 : -2 : -2), (3 : -2 : -1), (3 : -2 : 0), (3 : -2 : 1), - (3 : -2 : 2), (3 : -2 : 3), (3 : -1 : -3), (3 : -1 : -2), (3 : -1 : -1), - (3 : -1 : 0), (3 : -1 : 1), (3 : -1 : 2), (3 : -1 : 3), (3 : 0 : -2), (3 - : 0 : -1), (3 : 0 : 1), (3 : 0 : 2), (3 : 1 : -3), (3 : 1 : -2), (3 : 1 - : -1), (3 : 1 : 0), (3 : 1 : 1), (3 : 1 : 2), (3 : 1 : 3), (3 : 2 : -3), - (3 : 2 : -2), (3 : 2 : -1), (3 : 2 : 0), (3 : 2 : 1), (3 : 2 : 2), (3 : - 2 : 3), (3 : 3 : -2), (3 : 3 : -1), (3 : 3 : 1), (3 : 3 : 2)] + [(0 : 0 : 1), (0 : 1 : -3), (0 : 1 : -2), (0 : 1 : -1), (0 : 1 : 0), (0 : 1 : 1), + (0 : 1 : 2), (0 : 1 : 3), (0 : 2 : -3), (0 : 2 : -1), (0 : 2 : 1), (0 : 2 : 3), + (0 : 3 : -2), (0 : 3 : -1), (0 : 3 : 1), (0 : 3 : 2), (1 : -3 : -3), + (1 : -3 : -2), (1 : -3 : -1), (1 : -3 : 0), (1 : -3 : 1), (1 : -3 : 2), + (1 : -3 : 3), (1 : -2 : -3), (1 : -2 : -2), (1 : -2 : -1), (1 : -2 : 0), + (1 : -2 : 1), (1 : -2 : 2), (1 : -2 : 3), (1 : -1 : -3), (1 : -1 : -2), + (1 : -1 : -1), (1 : -1 : 0), (1 : -1 : 1), (1 : -1 : 2), (1 : -1 : 3), + (1 : 0 : -3), (1 : 0 : -2), (1 : 0 : -1), (1 : 0 : 0), (1 : 0 : 1), (1 : 0 : 2), + (1 : 0 : 3), (1 : 1 : -3), (1 : 1 : -2), (1 : 1 : -1), (1 : 1 : 0), (1 : 1 : 1), + (1 : 1 : 2), (1 : 1 : 3), (1 : 2 : -3), (1 : 2 : -2), (1 : 2 : -1), (1 : 2 : 0), + (1 : 2 : 1), (1 : 2 : 2), (1 : 2 : 3), (1 : 3 : -3), (1 : 3 : -2), (1 : 3 : -1), + (1 : 3 : 0), (1 : 3 : 1), (1 : 3 : 2), (1 : 3 : 3), (2 : -3 : -3), + (2 : -3 : -2), (2 : -3 : -1), (2 : -3 : 0), (2 : -3 : 1), (2 : -3 : 2), + (2 : -3 : 3), (2 : -2 : -3), (2 : -2 : -1), (2 : -2 : 1), (2 : -2 : 3), + (2 : -1 : -3), (2 : -1 : -2), (2 : -1 : -1), (2 : -1 : 0), (2 : -1 : 1), + (2 : -1 : 2), (2 : -1 : 3), (2 : 0 : -3), (2 : 0 : -1), (2 : 0 : 1), + (2 : 0 : 3), (2 : 1 : -3), (2 : 1 : -2), (2 : 1 : -1), (2 : 1 : 0), (2 : 1 : 1), + (2 : 1 : 2), (2 : 1 : 3), (2 : 2 : -3), (2 : 2 : -1), (2 : 2 : 1), (2 : 2 : 3), + (2 : 3 : -3), (2 : 3 : -2), (2 : 3 : -1), (2 : 3 : 0), (2 : 3 : 1), (2 : 3 : 2), + (2 : 3 : 3), (3 : -3 : -2), (3 : -3 : -1), (3 : -3 : 1), (3 : -3 : 2), + (3 : -2 : -3), (3 : -2 : -2), (3 : -2 : -1), (3 : -2 : 0), (3 : -2 : 1), + (3 : -2 : 2), (3 : -2 : 3), (3 : -1 : -3), (3 : -1 : -2), (3 : -1 : -1), + (3 : -1 : 0), (3 : -1 : 1), (3 : -1 : 2), (3 : -1 : 3), (3 : 0 : -2), + (3 : 0 : -1), (3 : 0 : 1), (3 : 0 : 2), (3 : 1 : -3), (3 : 1 : -2), + (3 : 1 : -1), (3 : 1 : 0), (3 : 1 : 1), (3 : 1 : 2), (3 : 1 : 3), (3 : 2 : -3), + (3 : 2 : -2), (3 : 2 : -1), (3 : 2 : 0), (3 : 2 : 1), (3 : 2 : 2), (3 : 2 : 3), + (3 : 3 : -2), (3 : 3 : -1), (3 : 3 : 1), (3 : 3 : 2)] """ R = self.value_ring() if R == ZZ: if not B > 0: - raise TypeError("a positive bound B (= %s) must be specified"%B) + raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.projective.projective_rational_point import enum_projective_rational_field return enum_projective_rational_field(self,B) else: - raise TypeError("unable to enumerate points over %s"%R) + raise TypeError("unable to enumerate points over %s" % R) class SchemeHomset_polynomial_projective_space(SchemeHomset_generic): @@ -578,13 +581,15 @@ class SchemeHomset_points_abelian_variety_field(SchemeHomset_points_projective_f The bug reported at :trac:`1785` is fixed:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<a> = NumberField(x^2 + x - (3^3-3)) sage: E = EllipticCurve('37a') sage: X = E(K) sage: X - Abelian group of points on Elliptic Curve defined by - y^2 + y = x^3 + (-1)*x over Number Field in a with - defining polynomial x^2 + x - 24 + Abelian group of points on + Elliptic Curve defined by y^2 + y = x^3 + (-1)*x + over Number Field in a with defining polynomial x^2 + x - 24 sage: P = X([3,a]) sage: P (3 : a : 1) @@ -601,10 +606,10 @@ class SchemeHomset_points_abelian_variety_field(SchemeHomset_points_projective_f sage: P2.<x,y,z> = ProjectiveSpace(QQ,2) sage: d = 7 - sage: C = Curve(x^3 + y^3 - d*z^3) - sage: E = EllipticCurve([0,-432*d^2]) - sage: transformation = [(36*d*z-y)/(72*d),(36*d*z+y)/(72*d),x/(12*d)] - sage: phi = E.hom(transformation, C); phi + sage: C = Curve(x^3 + y^3 - d*z^3) # needs sage.schemes + sage: E = EllipticCurve([0,-432*d^2]) # needs sage.schemes + sage: transformation = [(36*d*z-y)/(72*d), (36*d*z+y)/(72*d), x/(12*d)] + sage: phi = E.hom(transformation, C); phi # needs sage.schemes Scheme morphism: From: Elliptic Curve defined by y^2 = x^3 - 21168 over Rational Field To: Projective Plane Curve over Rational Field defined by x^3 + y^3 - 7*z^3 @@ -627,6 +632,7 @@ def _element_constructor_(self, *v, **kwds): EXAMPLES:: + sage: # needs sage.schemes sage: E = EllipticCurve('37a') sage: X = E(QQ) sage: P = X([0,1,0]); P @@ -636,7 +642,7 @@ def _element_constructor_(self, *v, **kwds): TESTS:: - sage: X._element_constructor_([0,1,0]) + sage: X._element_constructor_([0,1,0]) # needs sage.schemes (0 : 1 : 0) """ if len(v) == 1: @@ -653,9 +659,9 @@ def _repr_(self): EXAMPLES:: - sage: E = EllipticCurve('37a') - sage: X = E(QQ) - sage: X._repr_() + sage: E = EllipticCurve('37a') # needs sage.schemes + sage: X = E(QQ) # needs sage.schemes + sage: X._repr_() # needs sage.schemes 'Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field' """ s = 'Abelian group of points on ' + str(self.extended_codomain()) @@ -674,10 +680,11 @@ def base_extend(self, R): EXAMPLES:: + sage: # needs sage.schemes sage: E = EllipticCurve('37a') sage: Hom = E.point_homset(); Hom Abelian group of points on Elliptic Curve defined - by y^2 + y = x^3 - x over Rational Field + by y^2 + y = x^3 - x over Rational Field sage: Hom.base_ring() Rational Field sage: Hom.base_extend(QQ) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 87ad986bb06..5ba47f00afa 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -15,14 +15,12 @@ sage: A2.<x,y> = AffineSpace(QQ, 2) sage: P2.hom([x0, x1, x1 + x2], P2) Scheme endomorphism of Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x0 : x1 : x2) to - (x0 : x1 : x1 + x2) + Defn: Defined on coordinates by sending (x0 : x1 : x2) to (x0 : x1 : x1 + x2) sage: P2.hom([x1/x0, (x1 + x2)/x0], A2) Scheme morphism: From: Projective Space of dimension 2 over Rational Field To: Affine Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x0 : x1 : x2) to - (x1/x0, (x1 + x2)/x0) + Defn: Defined on coordinates by sending (x0 : x1 : x2) to (x1/x0, (x1 + x2)/x0) AUTHORS: @@ -62,7 +60,8 @@ # **************************************************************************** import sys -from sage.arith.all import gcd, lcm +from sage.arith.misc import GCD as gcd +from sage.arith.functions import lcm from sage.interfaces.singular import singular from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method @@ -72,8 +71,7 @@ import sage.rings.abc from sage.rings.integer import Integer from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField -from sage.rings.finite_rings.finite_field_constructor import is_PrimeFiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.fraction_field import FractionField from sage.rings.integer_ring import ZZ @@ -112,14 +110,15 @@ class SchemeMorphism_polynomial_projective_space(SchemeMorphism_polynomial): An example of a morphism between projective plane curves (see :trac:`10297`):: - sage: P2.<x,y,z> = ProjectiveSpace(QQ,2) - sage: f = x^3+y^3+60*z^3 - sage: g = y^2*z-( x^3 - 6400*z^3/3) + sage: # needs sage.schemes + sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: f = x^3 + y^3 + 60*z^3 + sage: g = y^2*z - (x^3 - 6400*z^3/3) sage: C = Curve(f) sage: E = Curve(g) sage: xbar,ybar,zbar = C.coordinate_ring().gens() sage: H = C.Hom(E) - sage: H([zbar,xbar-ybar,-(xbar+ybar)/80]) + sage: H([zbar, xbar - ybar, -(xbar+ybar)/80]) Scheme morphism: From: Projective Plane Curve over Rational Field defined by x^3 + y^3 + 60*z^3 To: Projective Plane Curve over Rational Field defined by -x^3 + y^2*z + 6400/3*z^3 @@ -129,32 +128,31 @@ class SchemeMorphism_polynomial_projective_space(SchemeMorphism_polynomial): A more complicated example:: sage: P2.<x,y,z> = ProjectiveSpace(2, QQ) - sage: P1 = P2.subscheme(x-y) + sage: P1 = P2.subscheme(x - y) sage: H12 = P1.Hom(P2) sage: H12([x^2, x*z, z^2]) Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x - y + From: Closed subscheme of Projective Space of dimension 2 over Rational Field + defined by: x - y To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (x^2 : x*z : z^2) + Defn: Defined on coordinates by sending (x : y : z) to (x^2 : x*z : z^2) We illustrate some error checking:: sage: R.<x,y> = QQ[] sage: P1 = ProjectiveSpace(R) sage: H = P1.Hom(P1) - sage: f = H([x-y, x*y]) + sage: f = H([x - y, x*y]) Traceback (most recent call last): ... ValueError: polys (=[x - y, x*y]) must be of the same degree - sage: H([x-1, x*y+x]) + sage: H([x - 1, x*y + x]) Traceback (most recent call last): ... ValueError: polys (=[x - 1, x*y + x]) must be homogeneous - sage: H([exp(x),exp(y)]) + sage: H([exp(x), exp(y)]) # needs sage.symbolic Traceback (most recent call last): ... TypeError: polys (=[e^x, e^y]) must be elements of @@ -170,9 +168,9 @@ class SchemeMorphism_polynomial_projective_space(SchemeMorphism_polynomial): sage: H = End(P) sage: f = H([(x-2*y)^2, (x-2*z)^2, x^2]) sage: X = P.subscheme(y-z) - sage: f(f(f(X))) + sage: f(f(f(X))) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Rational Field - defined by: + defined by: y - z :: @@ -180,9 +178,9 @@ class SchemeMorphism_polynomial_projective_space(SchemeMorphism_polynomial): sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: H = End(P) sage: f = H([(x-2*y)^2, (x-2*z)^2, (x-2*w)^2, x^2]) - sage: f(P.subscheme([x,y,z])) + sage: f(P.subscheme([x,y,z])) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 3 over Rational Field - defined by: + defined by: w, y, x @@ -207,22 +205,21 @@ def __init__(self, parent, polys, check=True): sage: X = P.subscheme([x]) sage: H = End(X) sage: H([x^2, t*y^2, x*z]) - Scheme endomorphism of Closed subscheme of Projective Space of dimension - 2 over Univariate Polynomial Ring in t over Rational Field defined by: - x + Scheme endomorphism of Closed subscheme of Projective Space of dimension 2 + over Univariate Polynomial Ring in t over Rational Field defined by: x Defn: Defined on coordinates by sending (x : y : z) to (x^2 : t*y^2 : x*z) When elements of the quotient ring is used, they are reduced:: + sage: # needs sage.rings.real_mpfr sage: P.<x,y,z> = ProjectiveSpace(CC, 2) - sage: X = P.subscheme([x-y]) - sage: u,v,w = X.coordinate_ring().gens() + sage: X = P.subscheme([x - y]) + sage: u,v,w = X.coordinate_ring().gens() # needs sage.libs.singular sage: H = End(X) - sage: H([u^2, v^2, w*u]) - Scheme endomorphism of Closed subscheme of Projective Space of dimension - 2 over Complex Field with 53 bits of precision defined by: - x - y + sage: H([u^2, v^2, w*u]) # needs sage.libs.singular + Scheme endomorphism of Closed subscheme of Projective Space of dimension 2 + over Complex Field with 53 bits of precision defined by: x - y Defn: Defined on coordinates by sending (x : y : z) to (y^2 : y^2 : y*z) """ @@ -239,7 +236,7 @@ def __init__(self, parent, polys, check=True): try: polys = [K(f) for f in polys] except TypeError: - raise TypeError("polys (=%s) must be elements of %s"%(polys, source_ring)) + raise TypeError("polys (=%s) must be elements of %s" % (polys, source_ring)) if parent.codomain().is_projective(): degs = [] @@ -258,7 +255,7 @@ def __init__(self, parent, polys, check=True): if not all(d == deg for deg in degs[1:]): raise ValueError("polys (={}) must be of the same degree".format(polys)) - polys = [(l*f).numerator() for f in polys] + polys = [(l * f).numerator() for f in polys] elif parent.codomain().is_affine(): for f in polys: num = f.numerator() @@ -274,7 +271,8 @@ def __init__(self, parent, polys, check=True): SchemeMorphism_polynomial.__init__(self, parent, polys, check) - self._is_prime_finite_field = is_PrimeFiniteField(polys[0].base_ring()) + R = polys[0].base_ring() + self._is_prime_finite_field = isinstance(R, FiniteField) and R.is_prime_field() def __call__(self, x, check=True): r""" @@ -300,14 +298,14 @@ def __call__(self, x, check=True): sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(P) - sage: f = H([x^2+y^2, y^2, z^2 + y*z]) + sage: f = H([x^2 + y^2, y^2, z^2 + y*z]) sage: f(P([1,1,1])) (1 : 1/2 : 1) :: sage: PS.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: P1.<u,v> = ProjectiveSpace(QQ,1) + sage: P1.<u,v> = ProjectiveSpace(QQ, 1) sage: H = End(P1) sage: f = H([u^2, v^2]) sage: f(PS([0,1,1])) @@ -332,8 +330,8 @@ def __call__(self, x, check=True): sage: PS.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: H = End(PS) sage: f = H([y^2, x^2, w^2, z^2]) - sage: X = PS.subscheme([z^2+y*w]) - sage: f(X) + sage: X = PS.subscheme([z^2 + y*w]) + sage: f(X) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: x*z - w^2 @@ -344,8 +342,8 @@ def __call__(self, x, check=True): sage: P1.<u,v> = ProjectiveSpace(ZZ, 1) sage: H = End(PS) sage: f = H([x^2, y^2, z^2]) - sage: X = P1.subscheme([u-v]) - sage: f(X) + sage: X = P1.subscheme([u - v]) + sage: f(X) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: subscheme must be in ambient space of domain of map @@ -356,11 +354,11 @@ def __call__(self, x, check=True): sage: P1.<u,v> = ProjectiveSpace(ZZ, 1) sage: H = End(P1) sage: f = H([u^2, v^2]) - sage: f([u-v]) + sage: f([u - v]) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 1 over Integer Ring defined by: u - v - sage: X = PS.subscheme([x-z]) - sage: f([x-z]) + sage: X = PS.subscheme([x - z]) + sage: f([x - z]) Traceback (most recent call last): ... TypeError: [x - z] fails to convert into the map's domain Projective Space of @@ -379,9 +377,10 @@ def __call__(self, x, check=True): Defn: Defined on coordinates by sending (u : v) to (u^2 + v^2 : u*v) + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(4) sage: P = T(F)(1, a) - sage: h(P) + sage: h(P) # needs sage.libs.singular (a : a) sage: h(P).domain() Spectrum of Finite Field in a of size 2^2 @@ -396,19 +395,19 @@ def __call__(self, x, check=True): try: x = self.domain()(x) except (TypeError, NotImplementedError): - raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented"%(x, self.domain())) - #else pass it onto the eval below + raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented" % (x, self.domain())) + # else pass it onto the eval below elif isinstance(x, AlgebraicScheme_subscheme_projective): - return x._forward_image(self) #call subscheme eval - else: #not a projective point or subscheme + return x._forward_image(self) # call subscheme eval + else: # not a projective point or subscheme try: x = self.domain()(x) except (TypeError, NotImplementedError): try: x = self.domain().subscheme(x) - return x._forward_image(self) #call subscheme eval + return x._forward_image(self) # call subscheme eval except (TypeError, NotImplementedError): - raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented"%(x, self.domain())) + raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented" % (x, self.domain())) R = x.domain().coordinate_ring() if R is self.base_ring(): @@ -424,11 +423,12 @@ def _fastpolys(self): EXAMPLES:: - sage: P.<x,y>=ProjectiveSpace(QQ,1) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = Hom(P,P) - sage: f = H([x^2+y^2,y^2]) + sage: f = H([x^2 + y^2, y^2]) sage: [g.op_list() for g in f._fastpolys] - [[('load_const', 0), ('load_const', 1), ('load_arg', ...), ('ipow', 2), 'mul', 'add', ('load_const', 1), ('load_arg', ...), ('ipow', 2), 'mul', 'add', 'return'], [('load_const', 0), ('load_const', 1), ('load_arg', 1), ('ipow', 2), 'mul', 'add', 'return']] + [[('load_const', 0), ('load_const', 1), ('load_arg', ...), ('ipow', 2), 'mul', 'add', ('load_const', 1), ('load_arg', ...), ('ipow', 2), 'mul', 'add', 'return'], + [('load_const', 0), ('load_const', 1), ('load_arg', 1), ('ipow', 2), 'mul', 'add', 'return']] """ polys = self._polys @@ -459,40 +459,42 @@ def _fast_eval(self, x): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: H = Hom(P,P) - sage: f = H([x^2+y^2, y^2, z^2 + y*z]) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: H = Hom(P, P) + sage: f = H([x^2 + y^2, y^2, z^2 + y*z]) sage: f._fast_eval([1,1,1]) [2, 1, 2] :: sage: T.<z> = LaurentSeriesRing(ZZ) - sage: P.<x,y> = ProjectiveSpace(T,1) + sage: P.<x,y> = ProjectiveSpace(T, 1) sage: H = End(P) - sage: f = H([x^2+x*y, y^2]) + sage: f = H([x^2 + x*y, y^2]) sage: Q = P(z,1) sage: f._fast_eval(list(Q)) [z + z^2, 1] :: + sage: # needs sage.libs.pari sage.rings.real_mpfr sage: T.<z> = PolynomialRing(CC) sage: I = T.ideal(z^3) - sage: P.<x,y> = ProjectiveSpace(T.quotient_ring(I),1) + sage: P.<x,y> = ProjectiveSpace(T.quotient_ring(I), 1) sage: H = End(P) - sage: f = H([x^2+x*y, y^2]) + sage: f = H([x^2 + x*y, y^2]) sage: Q = P(z^2, 1) sage: f._fast_eval(list(Q)) [zbar^2, 1.00000000000000] :: + sage: # needs sage.rings.real_mpfr sage: T.<z> = LaurentSeriesRing(CC) sage: R.<t> = PolynomialRing(T) sage: P.<x,y> = ProjectiveSpace(R,1) sage: H = End(P) - sage: f = H([x^2+x*y, y^2]) + sage: f = H([x^2 + x*y, y^2]) sage: Q = P(t^2, z) sage: f._fast_eval(list(Q)) [t^4 + z*t^2, z^2] @@ -516,14 +518,15 @@ def __eq__(self, right): EXAMPLES:: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: H = Hom(P,P) - sage: f = H([x^2 - 2*x*y + z*x, z^2 -y^2 , 5*z*y]) + sage: H = Hom(P, P) + sage: f = H([x^2 - 2*x*y + z*x, z^2 - y^2, 5*z*y]) sage: g = H([x^2, y^2, z^2]) sage: f == g False :: + sage: # needs sage.rings.real_mpfr sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: P2.<u,v> = ProjectiveSpace(CC, 1) sage: H = End(P) @@ -548,7 +551,7 @@ def __eq__(self, right): return False n = len(self._polys) return all(self._polys[i] * right._polys[j] == self._polys[j] * right._polys[i] - for i in range(n) for j in range(i+1, n)) + for i in range(n) for j in range(i + 1, n)) def __ne__(self, right): """ @@ -566,8 +569,8 @@ def __ne__(self, right): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: H = Hom(P,P) - sage: f = H([x^3 - 2*x^2*y , 5*x*y^2]) + sage: H = Hom(P, P) + sage: f = H([x^3 - 2*x^2*y, 5*x*y^2]) sage: g = f.change_ring(GF(7)) sage: f != g True @@ -576,7 +579,7 @@ def __ne__(self, right): sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = Hom(P, P) - sage: f = H([x^2 - 2*x*y + z*x, z^2 -y^2 , 5*z*y]) + sage: f = H([x^2 - 2*x*y + z*x, z^2 - y^2, 5*z*y]) sage: f != f False """ @@ -603,20 +606,22 @@ def _matrix_times_polymap_(self, mat, h): sage: P.<x,y> = ProjectiveSpace(ZZ, 1) sage: H = Hom(P,P) sage: f = H([x^2 + y^2, y^2]) - sage: matrix([[1,2], [0,1]]) * f + sage: matrix([[1,2], [0,1]]) * f # needs sage.modules Scheme endomorphism of Projective Space of dimension 1 over Integer Ring Defn: Defined on coordinates by sending (x : y) to (x^2 + 3*y^2 : y^2) :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) - sage: K.<i> = NumberField(x^2+1) + sage: K.<i> = NumberField(x^2 + 1) sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: H = Hom(P,P) + sage: H = Hom(P, P) sage: f = H([1/3*x^2 + 1/2*y^2, y^2]) - sage: matrix([[i,0], [0,i]]) * f - Scheme endomorphism of Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 + sage: matrix([[i,0], [0,i]]) * f # needs sage.modules + Scheme endomorphism of Projective Space of dimension 1 over + Number Field in i with defining polynomial x^2 + 1 Defn: Defined on coordinates by sending (x : y) to ((1/3*i)*x^2 + (1/2*i)*y^2 : i*y^2) """ @@ -646,20 +651,22 @@ def _polymap_times_matrix_(self, mat, h): sage: P.<x,y> = ProjectiveSpace(ZZ, 1) sage: H = Hom(P, P) sage: f = H([x^2 + y^2, y^2]) - sage: f * matrix([[1,2], [0,1]]) + sage: f * matrix([[1,2], [0,1]]) # needs sage.modules Scheme endomorphism of Projective Space of dimension 1 over Integer Ring Defn: Defined on coordinates by sending (x : y) to (x^2 + 4*x*y + 5*y^2 : y^2) :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) - sage: K.<i> = NumberField(x^2+1) + sage: K.<i> = NumberField(x^2 + 1) sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: H = Hom(P,P) + sage: H = Hom(P, P) sage: f = H([1/3*x^2 + 1/2*y^2, y^2]) - sage: f * matrix([[i,0], [0,i]]) - Scheme endomorphism of Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 + sage: f * matrix([[i,0], [0,i]]) # needs sage.modules + Scheme endomorphism of Projective Space of dimension 1 over + Number Field in i with defining polynomial x^2 + 1 Defn: Defined on coordinates by sending (x : y) to (-1/3*x^2 - 1/2*y^2 : -y^2) """ @@ -689,15 +696,15 @@ def as_dynamical_system(self): sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: H = End(P) sage: f = H([x^2, y^2, z^2]) - sage: type(f.as_dynamical_system()) + sage: type(f.as_dynamical_system()) # needs sage.schemes <class 'sage.dynamics.arithmetic_dynamics.projective_ds.DynamicalSystem_projective'> :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = End(P) - sage: f = H([x^2-y^2, y^2]) - sage: type(f.as_dynamical_system()) + sage: f = H([x^2 - y^2, y^2]) + sage: type(f.as_dynamical_system()) # needs sage.schemes <class 'sage.dynamics.arithmetic_dynamics.projective_ds.DynamicalSystem_projective_field'> :: @@ -705,15 +712,15 @@ def as_dynamical_system(self): sage: P.<x,y> = ProjectiveSpace(GF(5), 1) sage: H = End(P) sage: f = H([x^2, y^2]) - sage: type(f.as_dynamical_system()) + sage: type(f.as_dynamical_system()) # needs sage.schemes <class 'sage.dynamics.arithmetic_dynamics.projective_ds.DynamicalSystem_projective_finite_field'> :: sage: P.<x,y> = ProjectiveSpace(RR, 1) - sage: f = DynamicalSystem([x^2 + y^2, y^2], P) - sage: g = f.as_dynamical_system() - sage: g is f + sage: f = DynamicalSystem([x^2 + y^2, y^2], P) # needs sage.schemes + sage: g = f.as_dynamical_system() # needs sage.schemes + sage: g is f # needs sage.schemes True """ from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem @@ -727,7 +734,7 @@ def as_dynamical_system(self): R = self.base_ring() if R not in _Fields: return DynamicalSystem_projective(list(self), self.domain()) - if is_FiniteField(R): + if isinstance(R, FiniteField): return DynamicalSystem_projective_finite_field(list(self), self.domain()) return DynamicalSystem_projective_field(list(self), self.domain()) @@ -735,7 +742,7 @@ def scale_by(self, t): """ Scales each coordinate by a factor of ``t``. - A ``TypeError`` occurs if the point is not in the coordinate_ring + A ``TypeError`` occurs if the point is not in the coordinate ring of the parent after scaling. INPUT: @@ -748,38 +755,34 @@ def scale_by(self, t): EXAMPLES:: - sage: A.<x,y> = ProjectiveSpace(QQ,1) - sage: H = Hom(A,A) - sage: f = H([x^3-2*x*y^2,x^2*y]) + sage: A.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(A, A) + sage: f = H([x^3 - 2*x*y^2, x^2*y]) sage: f.scale_by(1/x) sage: f - Scheme endomorphism of Projective Space of dimension 1 over Rational - Field - Defn: Defined on coordinates by sending (x : y) to - (x^2 - 2*y^2 : x*y) + Scheme endomorphism of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to (x^2 - 2*y^2 : x*y) :: sage: R.<t> = PolynomialRing(QQ) - sage: P.<x,y> = ProjectiveSpace(R,1) + sage: P.<x,y> = ProjectiveSpace(R, 1) sage: H = Hom(P,P) - sage: f = H([3/5*x^2,6*y^2]) + sage: f = H([3/5*x^2, 6*y^2]) sage: f.scale_by(5/3*t); f - Scheme endomorphism of Projective Space of dimension 1 over Univariate - Polynomial Ring in t over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (t*x^2 : 10*t*y^2) + Scheme endomorphism of Projective Space of dimension 1 over + Univariate Polynomial Ring in t over Rational Field + Defn: Defined on coordinates by sending (x : y) to (t*x^2 : 10*t*y^2) :: - sage: P.<x,y,z> = ProjectiveSpace(GF(7),2) - sage: X = P.subscheme(x^2-y^2) - sage: H = Hom(X,X) - sage: f = H([x^2,y^2,z^2]) - sage: f.scale_by(x-y);f - Scheme endomorphism of Closed subscheme of Projective Space of dimension - 2 over Finite Field of size 7 defined by: - x^2 - y^2 + sage: P.<x,y,z> = ProjectiveSpace(GF(7), 2) + sage: X = P.subscheme(x^2 - y^2) + sage: H = Hom(X, X) + sage: f = H([x^2, y^2, z^2]) + sage: f.scale_by(x - y); f # needs sage.libs.singular + Scheme endomorphism of Closed subscheme of Projective Space of dimension 2 + over Finite Field of size 7 defined by: x^2 - y^2 Defn: Defined on coordinates by sending (x : y : z) to (x*y^2 - y^3 : x*y^2 - y^3 : x*z^2 - y*z^2) """ @@ -789,33 +792,32 @@ def scale_by(self, t): if isinstance(R, QuotientRing_generic): phi = R._internal_coerce_map_from(self.domain().ambient_space().coordinate_ring()) for i in range(self.codomain().ambient_space().dimension_relative() + 1): - new_polys = [phi(u*t).lift() for u in self] + new_polys = [phi(u * t).lift() for u in self] else: for i in range(self.codomain().ambient_space().dimension_relative() + 1): - new_polys = [R(u*t) for u in self] + new_polys = [R(u * t) for u in self] self._polys = tuple(new_polys) def normalize_coordinates(self, **kwds): """ - Ensures that this morphism has integral coefficients, and, - if the coordinate ring has a GCD, then it ensures that the + Ensures that this morphism has integral coefficients. + If the coordinate ring has a GCD, then it ensures that the coefficients have no common factor. - Also, makes the leading coefficients of the first polynomial + It also makes the leading coefficients of the first polynomial positive (if positive has meaning in the coordinate ring). This is done in place. - When ``ideal`` or ``valuation`` is specified, - normalization occurs with respect to the absolute value - defined by the ``ideal`` or ``valuation``. That is, the - coefficients are scaled such that one coefficient has - absolute value 1 while the others have absolute value - less than or equal to 1. Only supported when the base - ring is a number field. + When ``ideal`` or ``valuation`` is specified, normalization occurs + with respect to the absolute value defined by the ``ideal`` or + ``valuation``. That is, the coefficients are scaled such that + one coefficient has absolute value 1 while the others have + absolute value less than or equal to 1. + Only supported when the base ring is a number field. INPUT: - keywords: + kwds: - ``ideal`` -- (optional) a prime ideal of the base ring of this morphism. @@ -833,10 +835,8 @@ def normalize_coordinates(self, **kwds): sage: H = Hom(P, P) sage: f = H([5/4*x^3, 5*x*y^2]) sage: f.normalize_coordinates(); f - Scheme endomorphism of Projective Space of dimension 1 over Rational - Field - Defn: Defined on coordinates by sending (x : y) to - (x^2 : 4*y^2) + Scheme endomorphism of Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to (x^2 : 4*y^2) :: @@ -844,12 +844,10 @@ def normalize_coordinates(self, **kwds): sage: X = P.subscheme(x^2 - y^2) sage: H = Hom(X, X) sage: f = H([x^3 + x*y^2, x*y^2, x*z^2]) - sage: f.normalize_coordinates(); f - Scheme endomorphism of Closed subscheme of Projective Space of dimension - 2 over Finite Field of size 7 defined by: - x^2 - y^2 - Defn: Defined on coordinates by sending (x : y : z) to - (2*y^2 : y^2 : z^2) + sage: f.normalize_coordinates(); f # needs sage.libs.singular + Scheme endomorphism of Closed subscheme of Projective Space of dimension 2 + over Finite Field of size 7 defined by: x^2 - y^2 + Defn: Defined on coordinates by sending (x : y : z) to (2*y^2 : y^2 : z^2) :: @@ -858,33 +856,35 @@ def normalize_coordinates(self, **kwds): sage: H = End(P) sage: f = H([a*(x*z + y^2)*x^2, a*b*(x*z + y^2)*y^2, a*(x*z + y^2)*z^2]) sage: f.normalize_coordinates(); f - Scheme endomorphism of Projective Space of dimension 2 over Multivariate - Polynomial Ring in a, b over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (x^2 : b*y^2 : z^2) + Scheme endomorphism of Projective Space of dimension 2 over + Multivariate Polynomial Ring in a, b over Rational Field + Defn: Defined on coordinates by sending (x : y : z) to (x^2 : b*y^2 : z^2) :: + sage: # needs sage.rings.number_field sage: K.<w> = QuadraticField(5) sage: P.<x,y> = ProjectiveSpace(K, 1) sage: f = DynamicalSystem([w*x^2 + (1/5*w)*y^2, w*y^2]) sage: f.normalize_coordinates(); f - Dynamical System of Projective Space of dimension 1 over Number Field in - w with defining polynomial x^2 - 5 with w = 2.236067977499790? - Defn: Defined on coordinates by sending (x : y) to - (5*x^2 + y^2 : 5*y^2) + Dynamical System of Projective Space of dimension 1 over Number Field in w + with defining polynomial x^2 - 5 with w = 2.236067977499790? + Defn: Defined on coordinates by sending (x : y) to (5*x^2 + y^2 : 5*y^2) :: + sage: # needs sage.rings.number_field sage: R.<t> = PolynomialRing(ZZ) sage: K.<b> = NumberField(t^3 - 11) sage: a = 7/(b - 1) sage: P.<x,y> = ProjectiveSpace(K, 1) sage: f = DynamicalSystem_projective([a*y^2 - (a*y - x)^2, y^2]) sage: f.normalize_coordinates(); f - Dynamical System of Projective Space of dimension 1 over Number Field in b with defining polynomial t^3 - 11 - Defn: Defined on coordinates by sending (x : y) to - (-100*x^2 + (140*b^2 + 140*b + 140)*x*y + (-77*b^2 - 567*b - 1057)*y^2 : 100*y^2) + Dynamical System of Projective Space of dimension 1 over + Number Field in b with defining polynomial t^3 - 11 + Defn: Defined on coordinates by sending (x : y) to + (-100*x^2 + (140*b^2 + 140*b + 140)*x*y + (-77*b^2 - 567*b - 1057)*y^2 + : 100*y^2) We can used ``ideal`` to scale with respect to a norm defined by an ideal:: @@ -892,52 +892,78 @@ def normalize_coordinates(self, **kwds): sage: f = DynamicalSystem_projective([2*x^3, 2*x^2*y + 4*x*y^2]) sage: f.normalize_coordinates(ideal=2); f Dynamical System of Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (x^3 : x^2*y + 2*x*y^2) + Defn: Defined on coordinates by sending (x : y) to (x^3 : x^2*y + 2*x*y^2) :: + sage: # needs sage.rings.number_field sage: R.<w> = QQ[] sage: A.<a> = NumberField(w^2 + 1) sage: P.<x,y,z> = ProjectiveSpace(A, 2) - sage: X = P.subscheme(x^2-y^2) - sage: H = Hom(X,X) + sage: X = P.subscheme(x^2 - y^2) + sage: H = Hom(X, X) sage: f = H([(a+1)*x^3 + 2*x*y^2, 4*x*y^2, 8*x*z^2]) sage: f.normalize_coordinates(ideal=A.prime_above(2)); f Scheme endomorphism of Closed subscheme of Projective Space of dimension 2 over - Number Field in a with defining polynomial w^2 + 1 defined by: - x^2 - y^2 + Number Field in a with defining polynomial w^2 + 1 defined by: x^2 - y^2 Defn: Defined on coordinates by sending (x : y : z) to ((-a + 2)*x*y^2 : (-2*a + 2)*x*y^2 : (-4*a + 4)*x*z^2) We can pass in a valuation to ``valuation``:: - sage: g = H([(a+1)*x^3 + 2*x*y^2, 4*x*y^2, 8*x*z^2]) - sage: g.normalize_coordinates(valuation=A.valuation(A.prime_above(2))) - sage: g == f + sage: g = H([(a+1)*x^3 + 2*x*y^2, 4*x*y^2, 8*x*z^2]) # needs sage.rings.number_field + sage: g.normalize_coordinates(valuation=A.valuation(A.prime_above(2))) # needs sage.rings.number_field + sage: g == f # needs sage.rings.number_field True :: - sage: P.<x,y> = ProjectiveSpace(Qp(3), 1) - sage: f = DynamicalSystem_projective([3*x^2+6*y^2, 9*x*y]) - sage: f.normalize_coordinates(); f - Dynamical System of Projective Space of dimension 1 over 3-adic Field with capped relative precision 20 + sage: P.<x,y> = ProjectiveSpace(Qp(3), 1) # needs sage.rings.padics + sage: f = DynamicalSystem_projective([3*x^2 + 6*y^2, 9*x*y]) # needs sage.rings.padics + sage: f.normalize_coordinates(); f # needs sage.rings.padics + Dynamical System of Projective Space of dimension 1 over + 3-adic Field with capped relative precision 20 Defn: Defined on coordinates by sending (x : y) to (x^2 + (2 + O(3^20))*y^2 : (3 + O(3^21))*x*y) + + Check that #35797 is fixed:: + + sage: # needs sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(3*x^2 + 1) + sage: P.<z,w> = ProjectiveSpace(K, 1) + sage: f = DynamicalSystem_projective([a*(z^2 + w^2), z*w]) + sage: f.normalize_coordinates(); f + Dynamical System of Projective Space of dimension 1 over + Number Field in a with defining polynomial 3*x^2 + 1 + Defn: Defined on coordinates by sending (z : w) to + ((-3/2*a + 1/2)*z^2 + (-3/2*a + 1/2)*w^2 : (-3/2*a - 3/2)*z*w) + + :: + + sage: R.<a,b> = QQ[] + sage: P.<x,y,z> = ProjectiveSpace(FractionField(R), 2) + sage: H = End(P) + sage: f = H([a/b*(x*z + y^2)*x^2, a*b*(x*z + y^2)*y^2, a*(x*z + y^2)*z^2]) + sage: f.normalize_coordinates(); f + Scheme endomorphism of Projective Space of dimension 2 over Fraction + Field of Multivariate Polynomial Ring in a, b over Rational Field + Defn: Defined on coordinates by sending (x : y : z) to + (x^2 : (b^2)*y^2 : b*z^2) """ - # if ideal or valuation is specified, we scale according the norm defined by the ideal/valuation + # If ideal or valuation is specified, we scale according the norm + # defined by the ideal/valuation ideal = kwds.pop('ideal', None) if ideal is not None: from sage.rings.number_field.number_field_ideal import NumberFieldFractionalIdeal if not (ideal in ZZ or isinstance(ideal, NumberFieldFractionalIdeal)): - raise TypeError('ideal must be an ideal of a number field, not %s' %ideal) + raise TypeError('ideal must be an ideal of a number field, not %s' % ideal) if isinstance(ideal, NumberFieldFractionalIdeal): if ideal.number_field() != self.base_ring(): - raise ValueError('ideal must be an ideal of the base ring of this morphism ' + \ - ', not an ideal of %s' %ideal.number_field()) + raise ValueError('ideal must be an ideal of the base ring of this morphism ' + + ', not an ideal of %s' % ideal.number_field()) if not ideal.is_prime(): - raise ValueError('ideal was %s, not a prime ideal' %ideal) + raise ValueError('ideal was %s, not a prime ideal' % ideal) for generator in ideal.gens(): if generator.valuation(ideal) == 1: uniformizer = generator @@ -945,10 +971,10 @@ def normalize_coordinates(self, **kwds): else: ideal = ZZ(ideal) if self.base_ring() != QQ: - raise ValueError('ideal was an integer, but the base ring of this ' + \ - 'morphism is %s' %self.base_ring()) + raise ValueError('ideal was an integer, but the base ring of this ' + + 'morphism is %s' % self.base_ring()) if not ideal.is_prime(): - raise ValueError('ideal must be a prime, not %s' %ideal) + raise ValueError('ideal must be a prime, not %s' % ideal) uniformizer = ideal valuations = [] for poly in self: @@ -956,34 +982,43 @@ def normalize_coordinates(self, **kwds): if coefficient != 0: valuations.append(coefficient.valuation(ideal)) min_val = min(valuations) - self.scale_by(uniformizer**(-1*min_val)) + self.scale_by(uniformizer**(-1 * min_val)) return + valuation = kwds.pop('valuation', None) if valuation is not None: from sage.rings.padics.padic_valuation import pAdicValuation_base if not isinstance(valuation, pAdicValuation_base): - raise TypeError('valuation must be a valuation on a number field, not %s' %valuation) + raise TypeError('valuation must be a valuation on a number field, not %s' % valuation) if valuation.domain() != self.base_ring(): - raise ValueError('the domain of valuation must be the base ring of this morphism ' + \ - 'not %s' %valuation.domain()) + raise ValueError('the domain of valuation must be the base ring of this morphism ' + + 'not %s' % valuation.domain()) uniformizer = valuation.uniformizer() - ramification_index = 1/valuation(uniformizer) + ramification_index = 1 / valuation(uniformizer) valuations = [] for poly in self: for coefficient, monomial in poly: if coefficient != 0: valuations.append(valuation(coefficient) * ramification_index) min_val = min(valuations) - self.scale_by(uniformizer**(-1*min_val)) + self.scale_by(uniformizer**(-1 * min_val)) return - # clear any denominators from the coefficients N = self.codomain().ambient_space().dimension_relative() + 1 - LCM = lcm([self[i].denominator() for i in range(N)]) - self.scale_by(LCM) R = self.domain().base_ring() + # Clear any denominators from the coefficients + if R in NumberFields(): + if R.maximal_order() is ZZ: + denom = lcm([self[i].denominator() for i in range(N)]) + else: + denom = R.ideal([c for poly in self for c in poly.coefficients()]).norm().denominator() + + self.scale_by(denom) + else: + self.scale_by(lcm([self[i].denominator() for i in range(N)])) + # There are cases, such as the example above over GF(7), # where we want to compute GCDs, but NOT in the case # where R is a NumberField of class number > 1. @@ -1003,10 +1038,10 @@ def normalize_coordinates(self, **kwds): if GCD != 1: self.scale_by(R(1) / GCD) - # scales by 1/gcd of the coefficients. + # Scale by 1/GCD of the coefficients. if R in _NumberFields: O = R.maximal_order() - elif is_FiniteField(R): + elif isinstance(R, FiniteField): O = R elif isinstance(R, QuotientRing_generic): O = R.ring() @@ -1017,9 +1052,10 @@ def normalize_coordinates(self, **kwds): GCD = gcd([O(c) for poly in self for c in poly.coefficients()]) if GCD != 1: - self.scale_by(1/GCD) + self.scale_by(1 / GCD) + + # If R is not p-adic, we make the first coordinate positive from sage.rings.padics.padic_base_generic import pAdicGeneric - # if R is not padic, we make the first coordinate positive if not isinstance(R, pAdicGeneric): if self[0].lc() < 0: self.scale_by(-1) @@ -1037,34 +1073,35 @@ def degree(self): EXAMPLES:: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: H = Hom(P,P) - sage: f = H([x^2+y^2, y^2]) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(P, P) + sage: f = H([x^2 + y^2, y^2]) sage: f.degree() 2 :: - sage: P.<x,y,z> = ProjectiveSpace(CC,2) - sage: H = Hom(P,P) - sage: f = H([x^3+y^3, y^2*z, z*x*y]) + sage: # needs sage.rings.real_mpfr + sage: P.<x,y,z> = ProjectiveSpace(CC, 2) + sage: H = Hom(P, P) + sage: f = H([x^3 + y^3, y^2*z, z*x*y]) sage: f.degree() 3 :: sage: R.<t> = PolynomialRing(QQ) - sage: P.<x,y,z> = ProjectiveSpace(R,2) - sage: H = Hom(P,P) - sage: f = H([x^2+t*y^2, (2-t)*y^2, z^2]) + sage: P.<x,y,z> = ProjectiveSpace(R, 2) + sage: H = Hom(P, P) + sage: f = H([x^2 + t*y^2, (2-t)*y^2, z^2]) sage: f.degree() 2 :: - sage: P.<x,y,z> = ProjectiveSpace(ZZ,2) - sage: X = P.subscheme(x^2-y^2) - sage: H = Hom(X,X) + sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) + sage: X = P.subscheme(x^2 - y^2) + sage: H = Hom(X, X) sage: f = H([x^2, y^2, z^2]) sage: f.degree() 2 @@ -1073,7 +1110,7 @@ def degree(self): def dehomogenize(self, n): r""" - Returns the standard dehomogenization at the ``n[0]`` coordinate for the domain + Return the standard dehomogenization at the ``n[0]`` coordinate for the domain and the ``n[1]`` coordinate for the codomain. Note that the new function is defined over the fraction field @@ -1090,31 +1127,29 @@ def dehomogenize(self, n): EXAMPLES:: - sage: P.<x,y> = ProjectiveSpace(ZZ,1) - sage: H = Hom(P,P) - sage: f = H([x^2+y^2, y^2]) + sage: P.<x,y> = ProjectiveSpace(ZZ, 1) + sage: H = Hom(P, P) + sage: f = H([x^2 + y^2, y^2]) sage: f.dehomogenize(0) Scheme endomorphism of Affine Space of dimension 1 over Integer Ring - Defn: Defined on coordinates by sending (y) to - (y^2/(y^2 + 1)) + Defn: Defined on coordinates by sending (y) to (y^2/(y^2 + 1)) :: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: H = Hom(P,P) - sage: f = H([x^2-y^2, y^2]) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(P, P) + sage: f = H([x^2 - y^2, y^2]) sage: f.dehomogenize((0,1)) Scheme morphism: From: Affine Space of dimension 1 over Rational Field To: Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (y) to - ((-y^2 + 1)/y^2) + Defn: Defined on coordinates by sending (y) to ((-y^2 + 1)/y^2) :: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: H = Hom(P,P) - sage: f = H([x^2+y^2, y^2-z^2, 2*z^2]) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: H = Hom(P, P) + sage: f = H([x^2 + y^2, y^2 - z^2, 2*z^2]) sage: f.dehomogenize(2) Scheme endomorphism of Affine Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x, y) to @@ -1125,28 +1160,27 @@ def dehomogenize(self, n): sage: R.<t> = PolynomialRing(QQ) sage: P.<x,y,z> = ProjectiveSpace(FractionField(R),2) sage: H = Hom(P,P) - sage: f = H([x^2+t*y^2, t*y^2-z^2, t*z^2]) + sage: f = H([x^2 + t*y^2, t*y^2 - z^2, t*z^2]) sage: f.dehomogenize(2) Scheme endomorphism of Affine Space of dimension 2 over Fraction Field - of Univariate Polynomial Ring in t over Rational Field + of Univariate Polynomial Ring in t over Rational Field Defn: Defined on coordinates by sending (x, y) to (1/t*x^2 + y^2, y^2 - 1/t) :: - sage: P.<x,y,z> = ProjectiveSpace(ZZ,2) - sage: X = P.subscheme(x^2-y^2) - sage: H = Hom(X,X) + sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) + sage: X = P.subscheme(x^2 - y^2) + sage: H = Hom(X, X) sage: f = H([x^2, y^2, x*z]) - sage: f.dehomogenize(2) - Scheme endomorphism of Closed subscheme of Affine Space of dimension 2 over Integer Ring defined by: - x^2 - y^2 - Defn: Defined on coordinates by sending (x, y) to - (x, y^2/x) + sage: f.dehomogenize(2) # needs sage.libs.singular + Scheme endomorphism of Closed subscheme of Affine Space of dimension 2 + over Integer Ring defined by: x^2 - y^2 + Defn: Defined on coordinates by sending (x, y) to (x, y^2/x) :: - sage: P.<x,y> = ProjectiveSpace(QQ,1) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = End(P) sage: f = H([x^2 - 2*x*y, y^2]) sage: f.dehomogenize(0).homogenize(0) == f @@ -1154,28 +1188,29 @@ def dehomogenize(self, n): :: + sage: # needs sage.rings.number_field sage: K.<w> = QuadraticField(3) sage: O = K.ring_of_integers() - sage: P.<x,y> = ProjectiveSpace(O,1) + sage: P.<x,y> = ProjectiveSpace(O, 1) sage: H = End(P) - sage: f = H([x^2 - O(w)*y^2,y^2]) + sage: f = H([x^2 - O(w)*y^2, y^2]) sage: f.dehomogenize(1) - Scheme endomorphism of Affine Space of dimension 1 over Maximal Order in Number Field in w with defining polynomial x^2 - 3 with w = 1.732050807568878? - Defn: Defined on coordinates by sending (x) to - (x^2 - w) + Scheme endomorphism of Affine Space of dimension 1 over + Maximal Order in Number Field in w with defining polynomial x^2 - 3 + with w = 1.732050807568878? + Defn: Defined on coordinates by sending (x) to (x^2 - w) :: - sage: P1.<x,y> = ProjectiveSpace(QQ,1) - sage: P2.<u,v,w> = ProjectiveSpace(QQ,2) - sage: H = Hom(P2,P1) - sage: f = H([u*w,v^2 + w^2]) + sage: P1.<x,y> = ProjectiveSpace(QQ, 1) + sage: P2.<u,v,w> = ProjectiveSpace(QQ, 2) + sage: H = Hom(P2, P1) + sage: f = H([u*w, v^2 + w^2]) sage: f.dehomogenize((2,1)) Scheme morphism: From: Affine Space of dimension 2 over Rational Field To: Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (u, v) to - (u/(v^2 + 1)) + Defn: Defined on coordinates by sending (u, v) to (u/(v^2 + 1)) """ # the dehomogenizations are stored for future use try: @@ -1185,13 +1220,13 @@ def dehomogenize(self, n): except KeyError: pass # it is possible to dehomogenize the domain and codomain at different coordinates - if isinstance(n,(tuple,list)): - ind=tuple(n) + if isinstance(n, (tuple, list)): + ind = tuple(n) else: - ind=(n,n) + ind = (n, n) PS_domain = self.domain() A_domain = PS_domain.ambient_space() - if self._polys[ind[1]].substitute({A_domain.gen(ind[0]):1}) == 0: + if self._polys[ind[1]].substitute({A_domain.gen(ind[0]): 1}) == 0: raise ValueError("can't dehomogenize at 0 coordinate") else: Aff_domain = PS_domain.affine_patch(ind[0]) @@ -1210,17 +1245,17 @@ def dehomogenize(self, n): H = Hom(Aff_domain, self.codomain().affine_patch(ind[1])) # since often you dehomogenize at the same coordinate in domain # and codomain it should be stored appropriately. - if ind == (n,n): - self.__dehomogenization[ind]=H(F) + if ind == (n, n): + self.__dehomogenization[ind] = H(F) return self.__dehomogenization[ind] else: - self.__dehomogenization[n]=H(F) + self.__dehomogenization[n] = H(F) return self.__dehomogenization[n] @cached_method def is_morphism(self): r""" - returns ``True`` if this map is a morphism. + Return ``True`` if this map is a morphism. The map is a morphism if and only if the ideal generated by the defining polynomials is the unit ideal @@ -1232,36 +1267,36 @@ def is_morphism(self): EXAMPLES:: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: H = Hom(P,P) - sage: f = H([x^2+y^2, y^2]) - sage: f.is_morphism() + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(P, P) + sage: f = H([x^2 + y^2, y^2]) + sage: f.is_morphism() # needs sage.libs.singular True :: - sage: P.<x,y,z> = ProjectiveSpace(RR,2) - sage: H = Hom(P,P) - sage: f = H([x*z-y*z, x^2-y^2, z^2]) - sage: f.is_morphism() + sage: P.<x,y,z> = ProjectiveSpace(RR, 2) + sage: H = Hom(P, P) + sage: f = H([x*z - y*z, x^2 - y^2, z^2]) + sage: f.is_morphism() # needs sage.libs.singular False :: sage: R.<t> = PolynomialRing(GF(5)) - sage: P.<x,y,z> = ProjectiveSpace(R,2) - sage: H = Hom(P,P) - sage: f = H([x*z-t*y^2, x^2-y^2, t*z^2]) - sage: f.is_morphism() + sage: P.<x,y,z> = ProjectiveSpace(R, 2) + sage: H = Hom(P, P) + sage: f = H([x*z - t*y^2, x^2 - y^2, t*z^2]) + sage: f.is_morphism() # needs sage.libs.singular True Map that is not morphism on projective space, but is over a subscheme:: - sage: P.<x,y,z> = ProjectiveSpace(RR,2) + sage: P.<x,y,z> = ProjectiveSpace(RR, 2) sage: X = P.subscheme([x*y + y*z]) - sage: H = Hom(X,X) - sage: f = H([x*z-y*z, x^2-y^2, z^2]) - sage: f.is_morphism() + sage: H = Hom(X, X) + sage: f = H([x*z - y*z, x^2 - y^2, z^2]) + sage: f.is_morphism() # needs sage.libs.singular True """ @@ -1298,7 +1333,7 @@ def global_height(self, prec=None): sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = Hom(P, P) sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]); - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 20.8348429892146 :: @@ -1306,7 +1341,7 @@ def global_height(self, prec=None): sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = Hom(P, P) sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]); - sage: f.global_height(prec=11) + sage: f.global_height(prec=11) # needs sage.symbolic 20.8 :: @@ -1314,11 +1349,12 @@ def global_height(self, prec=None): sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: H = Hom(P, P) sage: f = H([4*x^2 + 100*y^2, 210*x*y, 10000*z^2]); - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 8.51719319141624 :: + sage: # needs sage.rings.number_field sage: R.<z> = PolynomialRing(QQ) sage: K.<w> = NumberField(z^2 - 2) sage: O = K.maximal_order() @@ -1330,6 +1366,7 @@ def global_height(self, prec=None): :: + sage: # needs sage.rings.number_field sage: P.<x,y> = ProjectiveSpace(QQbar, 1) sage: P2.<u,v,w> = ProjectiveSpace(QQbar, 2) sage: H = Hom(P, P2) @@ -1343,25 +1380,25 @@ def global_height(self, prec=None): sage: A.<z,w> = ProjectiveSpace(QQ, 1) sage: H = Hom(P, A) sage: f = H([1/1331*x^2 + 4000*y*z, y^2]) - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 15.4877354584971 :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem([1/25*x^2 + 25/3*x*y + y^2, 1*y^2]) - sage: exp(f.global_height()) + sage: exp(f.global_height()) # needs sage.symbolic 625.000000000000 Scaling should not change the result:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem([1/25*x^2 + 25/3*x*y + y^2, 1*y^2]) - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 6.43775164973640 sage: c = 10000 sage: f.scale_by(c) - sage: f.global_height() + sage: f.global_height() # needs sage.symbolic 6.43775164973640 """ K = self.domain().base_ring() @@ -1373,16 +1410,16 @@ def global_height(self, prec=None): raise TypeError("Must be over a Numberfield or a Numberfield Order or QQbar") # Get the coefficients from all of the polynomials in the dynamical system - coeffs = [x for xs in [k.coefficients() for k in f] for x in xs] + coeffs = [x for k in f for x in k.coefficients()] from sage.schemes.projective.projective_space import ProjectiveSpace - P = ProjectiveSpace(K, len(coeffs)-1) + P = ProjectiveSpace(K, len(coeffs) - 1) return P.point(coeffs).global_height(prec=prec) def local_height(self, v, prec=None): r""" - Returns the maximum of the local height of the coefficients in any + Return the maximum of the local height of the coefficients in any of the coordinate functions of this map. INPUT: @@ -1398,37 +1435,38 @@ def local_height(self, v, prec=None): EXAMPLES:: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: H = Hom(P,P) - sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]); - sage: f.local_height(1331) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(P, P) + sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]) + sage: f.local_height(1331) # needs sage.rings.real_mpfr 7.19368581839511 :: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: H = Hom(P,P) - sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]); - sage: f.local_height(1331, prec=2) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(P, P) + sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]) + sage: f.local_height(1331, prec=2) # needs sage.rings.real_mpfr 8.0 This function does not automatically normalize:: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: H = Hom(P,P) - sage: f = H([4*x^2 + 3/100*y^2, 8/210*x*y, 1/10000*z^2]); - sage: f.local_height(2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: H = Hom(P, P) + sage: f = H([4*x^2 + 3/100*y^2, 8/210*x*y, 1/10000*z^2]) + sage: f.local_height(2) # needs sage.rings.real_mpfr 2.77258872223978 - sage: f.normalize_coordinates() - sage: f.local_height(2) + sage: f.normalize_coordinates() # needs sage.libs.singular + sage: f.local_height(2) # needs sage.libs.singular 0.000000000000000 :: + sage: # needs sage.rings.number_field sage: R.<z> = PolynomialRing(QQ) - sage: K.<w> = NumberField(z^2-2) - sage: P.<x,y> = ProjectiveSpace(K,1) - sage: H = Hom(P,P) + sage: K.<w> = NumberField(z^2 - 2) + sage: P.<x,y> = ProjectiveSpace(K, 1) + sage: H = Hom(P, P) sage: f = H([2*x^2 + w/3*y^2, 1/w*y^2]) sage: f.local_height(K.ideal(3)) 1.09861228866811 @@ -1440,7 +1478,7 @@ def local_height(self, v, prec=None): def local_height_arch(self, i, prec=None): r""" - Returns the maximum of the local height at the ``i``-th infinite place of the coefficients in any + Return the maximum of the local height at the ``i``-th infinite place of the coefficients in any of the coordinate functions of this map. INPUT: @@ -1458,23 +1496,24 @@ def local_height_arch(self, i, prec=None): sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = Hom(P, P) - sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]); - sage: f.local_height_arch(0) + sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]) + sage: f.local_height_arch(0) # needs sage.rings.real_mpfr 5.34710753071747 :: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: H = Hom(P,P) - sage: f = H([1/1331*x^2+1/4000*y^2, 210*x*y]); - sage: f.local_height_arch(0, prec=5) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: H = Hom(P, P) + sage: f = H([1/1331*x^2 + 1/4000*y^2, 210*x*y]) + sage: f.local_height_arch(0, prec=5) # needs sage.rings.real_mpfr 5.2 :: + sage: # needs sage.rings.number_field sage: R.<z> = PolynomialRing(QQ) sage: K.<w> = NumberField(z^2 - 2) - sage: P.<x,y> = ProjectiveSpace(K,1) + sage: P.<x,y> = ProjectiveSpace(K, 1) sage: H = Hom(P, P) sage: f = H([2*x^2 + w/3*y^2, 1/w*y^2]) sage: f.local_height_arch(1) @@ -1490,7 +1529,7 @@ def local_height_arch(self, i, prec=None): def wronskian_ideal(self): r""" - Returns the ideal generated by the critical point locus. + Return the ideal generated by the critical point locus. This is the vanishing of the maximal minors of the Jacobian matrix. Not implemented for subvarieties. @@ -1499,32 +1538,34 @@ def wronskian_ideal(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) - sage: K.<w> = NumberField(x^2+11) - sage: P.<x,y> = ProjectiveSpace(K,1) + sage: K.<w> = NumberField(x^2 + 11) + sage: P.<x,y> = ProjectiveSpace(K, 1) sage: H = End(P) - sage: f = H([x^2-w*y^2, w*y^2]) + sage: f = H([x^2 - w*y^2, w*y^2]) sage: f.wronskian_ideal() - Ideal ((4*w)*x*y) of Multivariate Polynomial Ring in x, y over Number - Field in w with defining polynomial x^2 + 11 + Ideal ((4*w)*x*y) of Multivariate Polynomial Ring in x, y + over Number Field in w with defining polynomial x^2 + 11 :: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: P2.<u,v,t> = ProjectiveSpace(K,2) - sage: H = Hom(P,P2) - sage: f = H([x^2-2*y^2, y^2, x*y]) + sage: # needs sage.rings.number_field + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: P2.<u,v,t> = ProjectiveSpace(K, 2) + sage: H = Hom(P, P2) + sage: f = H([x^2 - 2*y^2, y^2, x*y]) sage: f.wronskian_ideal() - Ideal (4*x*y, 2*x^2 + 4*y^2, -2*y^2) of Multivariate Polynomial Ring in - x, y over Rational Field + Ideal (4*x*y, 2*x^2 + 4*y^2, -2*y^2) of + Multivariate Polynomial Ring in x, y over Rational Field """ dom = self.domain() from sage.schemes.projective.projective_space import is_ProjectiveSpace if not (is_ProjectiveSpace(dom) and is_ProjectiveSpace(self.codomain())): raise NotImplementedError("not implemented for subschemes") - N = dom.dimension_relative()+1 + N = dom.dimension_relative() + 1 R = dom.coordinate_ring() - J = jacobian(self.defining_polynomials(),dom.gens()) + J = jacobian(self.defining_polynomials(), dom.gens()) return R.ideal(J.minors(N)) @@ -1556,16 +1597,17 @@ def rational_preimages(self, Q, k=1): sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = End(P) sage: f = H([16*x^2 - 29*y^2, 16*y^2]) - sage: f.rational_preimages(P(-1, 4)) + sage: f.rational_preimages(P(-1, 4)) # needs sage.libs.singular [(-5/4 : 1), (5/4 : 1)] :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(P) - sage: f = H([76*x^2 - 180*x*y + 45*y^2 + 14*x*z + 45*y*z\ - - 90*z^2, 67*x^2 - 180*x*y - 157*x*z + 90*y*z, -90*z^2]) - sage: f.rational_preimages(P(-9, -4, 1)) + sage: f = H([76*x^2 - 180*x*y + 45*y^2 + 14*x*z + 45*y*z - 90*z^2, + ....: 67*x^2 - 180*x*y - 157*x*z + 90*y*z, + ....: -90*z^2]) + sage: f.rational_preimages(P(-9, -4, 1)) # needs sage.libs.singular [(0 : 4 : 1)] A non-periodic example :: @@ -1573,16 +1615,17 @@ def rational_preimages(self, Q, k=1): sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = End(P) sage: f = H([x^2 + y^2, 2*x*y]) - sage: f.rational_preimages(P(17, 15)) + sage: f.rational_preimages(P(17, 15)) # needs sage.libs.singular [(3/5 : 1), (5/3 : 1)] :: sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: H = End(P) - sage: f = H([x^2 - 2*y*w - 3*w^2, -2*x^2 + y^2 - 2*x*z\ - + 4*y*w + 3*w^2, x^2 - y^2 + 2*x*z + z^2 - 2*y*w - w^2, w^2]) - sage: f.rational_preimages(P(0, -1, 0, 1)) + sage: f = H([x^2 - 2*y*w - 3*w^2, -2*x^2 + y^2 - 2*x*z + 4*y*w + 3*w^2, + ....: x^2 - y^2 + 2*x*z + z^2 - 2*y*w - w^2, + ....: w^2]) + sage: f.rational_preimages(P(0, -1, 0, 1)) # needs sage.libs.singular [] :: @@ -1590,30 +1633,32 @@ def rational_preimages(self, Q, k=1): sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = End(P) sage: f = H([x^2 + y^2, 2*x*y]) - sage: f.rational_preimages([CC.0, 1]) + sage: f.rational_preimages([CC.0, 1]) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: point must be in codomain of self A number field example :: + sage: # needs sage.rings.number_field sage: z = QQ['z'].0 - sage: K.<a> = NumberField(z^2 - 2); + sage: K.<a> = NumberField(z^2 - 2) sage: P.<x,y> = ProjectiveSpace(K, 1) sage: H = End(P) sage: f = H([x^2 + y^2, y^2]) - sage: f.rational_preimages(P(3, 1)) + sage: f.rational_preimages(P(3, 1)) # needs sage.libs.singular [(-a : 1), (a : 1)] :: + sage: # needs sage.rings.number_field sage: z = QQ['z'].0 - sage: K.<a> = NumberField(z^2 - 2); + sage: K.<a> = NumberField(z^2 - 2) sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: X = P.subscheme([x^2 - z^2]) sage: H = End(X) sage: f= H([x^2 - z^2, a*y^2, z^2 - x^2]) - sage: f.rational_preimages(X([1, 2, -1])) + sage: f.rational_preimages(X([1, 2, -1])) # needs sage.libs.singular [] :: @@ -1622,29 +1667,28 @@ def rational_preimages(self, Q, k=1): sage: X = P.subscheme([x^2 - z^2]) sage: H = End(X) sage: f = H([x^2-z^2, y^2, z^2-x^2]) - sage: f.rational_preimages(X([0, 1, 0])) + sage: f.rational_preimages(X([0, 1, 0])) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x^2 - z^2, - -x^2 + z^2, - 0, - -x^2 + z^2 + x^2 - z^2, + -x^2 + z^2, + 0, + -x^2 + z^2 :: sage: P.<x, y> = ProjectiveSpace(QQ, 1) sage: H = End(P) - sage: f = H([x^2-y^2, y^2]) - sage: f.rational_preimages(P.subscheme([x])) + sage: f = H([x^2 - y^2, y^2]) + sage: f.rational_preimages(P.subscheme([x])) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 1 over Rational Field - defined by: - x^2 - y^2 + defined by: x^2 - y^2 :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = End(P) sage: f = H([x^2 - 29/16*y^2, y^2]) - sage: f.rational_preimages(P(5/4, 1), k=4) + sage: f.rational_preimages(P(5/4, 1), k=4) # needs sage.libs.singular [(-3/4 : 1), (3/4 : 1), (-7/4 : 1), (7/4 : 1)] :: @@ -1653,7 +1697,7 @@ def rational_preimages(self, Q, k=1): sage: P2.<u,v,w> = ProjectiveSpace(QQ, 2) sage: H = Hom(P, P2) sage: f = H([x^2, y^2, x^2-y^2]) - sage: f.rational_preimages(P2(1, 1, 0)) + sage: f.rational_preimages(P2(1, 1, 0)) # needs sage.libs.singular [(-1 : 1), (1 : 1)] """ k = ZZ(k) @@ -1705,14 +1749,15 @@ def _number_field_from_algebraics(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) - sage: P.<x,y> = ProjectiveSpace(QQbar,1) + sage: P.<x,y> = ProjectiveSpace(QQbar, 1) sage: H = End(P) - sage: f = H([QQbar(3^(1/3))*x^2 + QQbar(sqrt(-2))*y^2, y^2]) - sage: f._number_field_from_algebraics() + sage: f = H([QQbar(3^(1/3))*x^2 + QQbar(sqrt(-2))*y^2, y^2]) # needs sage.symbolic + sage: f._number_field_from_algebraics() # needs sage.symbolic Scheme endomorphism of Projective Space of dimension 1 over Number - Field in a with defining polynomial y^6 + 6*y^4 - 6*y^3 + 12*y^2 + 36*y + 17 - with a = 1.442249570307409? + 1.414213562373095?*I + Field in a with defining polynomial y^6 + 6*y^4 - 6*y^3 + 12*y^2 + 36*y + 17 + with a = 1.442249570307409? + 1.414213562373095?*I Defn: Defined on coordinates by sending (x : y) to ((-48/269*a^5 + 27/269*a^4 - 320/269*a^3 + 468/269*a^2 - 772/269*a - 1092/269)*x^2 + (48/269*a^5 - 27/269*a^4 + 320/269*a^3 - 468/269*a^2 @@ -1720,32 +1765,36 @@ def _number_field_from_algebraics(self): :: - sage: P.<x,y> = ProjectiveSpace(QQbar,1) - sage: P2.<u,v,w> = ProjectiveSpace(QQbar,2) + sage: # needs sage.rings.number_field + sage: P.<x,y> = ProjectiveSpace(QQbar, 1) + sage: P2.<u,v,w> = ProjectiveSpace(QQbar, 2) sage: H = Hom(P, P2) - sage: f = H([x^2 + QQbar(I)*x*y + 3*y^2, y^2, QQbar(sqrt(5))*x*y]) - sage: f._number_field_from_algebraics() + sage: f = H([x^2 + QQbar(I)*x*y + 3*y^2, y^2, QQbar(sqrt(5))*x*y]) # needs sage.symbolic + sage: f._number_field_from_algebraics() # needs sage.symbolic Scheme morphism: - From: Projective Space of dimension 1 over Number Field in a with - defining polynomial y^4 + 3*y^2 + 1 with a = 0.?e-113 + 0.618033988749895?*I - To: Projective Space of dimension 2 over Number Field in a with - defining polynomial y^4 + 3*y^2 + 1 with a = 0.?e-113 + 0.618033988749895?*I + From: Projective Space of dimension 1 over Number Field in a + with defining polynomial y^4 + 3*y^2 + 1 + with a = 0.?e-113 + 0.618033988749895?*I + To: Projective Space of dimension 2 over Number Field in a + with defining polynomial y^4 + 3*y^2 + 1 + with a = 0.?e-113 + 0.618033988749895?*I Defn: Defined on coordinates by sending (x : y) to (x^2 + (a^3 + 2*a)*x*y + 3*y^2 : y^2 : (2*a^2 + 3)*x*y) The following was fixed in :trac:`23808`:: - sage: R.<t>=PolynomialRing(QQ) - sage: s = (t^3+t+1).roots(QQbar)[0][0] - sage: P.<x,y>=ProjectiveSpace(QQbar,1) - sage: H = Hom(P,P) - sage: f = H([s*x^3-13*y^3, y^3-15*y^3]) + sage: # needs sage.rings.number_field + sage: R.<t> = PolynomialRing(QQ) + sage: s = (t^3 + t + 1).roots(QQbar)[0][0] + sage: P.<x,y> = ProjectiveSpace(QQbar, 1) + sage: H = Hom(P, P) + sage: f = H([s*x^3 - 13*y^3, y^3 - 15*y^3]) sage: f Scheme endomorphism of Projective Space of dimension 1 over Algebraic Field Defn: Defined on coordinates by sending (x : y) to ((-0.6823278038280193?)*x^3 + (-13)*y^3 : (-14)*y^3) sage: f_alg = f._number_field_from_algebraics() - sage: f_alg.change_ring(QQbar) # Used to fail + sage: f_alg.change_ring(QQbar) # Used to fail Scheme endomorphism of Projective Space of dimension 1 over Algebraic Field Defn: Defined on coordinates by sending (x : y) to ((-0.6823278038280193?)*x^3 + (-13)*y^3 : (-14)*y^3) @@ -1754,7 +1803,7 @@ def _number_field_from_algebraics(self): if not (is_ProjectiveSpace(self.domain()) and is_ProjectiveSpace(self.domain())): raise NotImplementedError("not implemented for subschemes") - K_pre,C,phi = number_field_elements_from_algebraics([c for f in self \ + K_pre, C, phi = number_field_elements_from_algebraics([c for f in self for c in f.coefficients()], minimal=True) # check if the same field if K_pre is QQ: @@ -1770,17 +1819,17 @@ def _number_field_from_algebraics(self): else: from sage.rings.number_field.number_field import NumberField K = NumberField(K_pre.polynomial(), embedding=phi(K_pre.gen()), name='a') - psi = K_pre.hom([K.gen()], K) # Identification of K_pre with K - C = [ psi(c) for c in C ] # The elements of C were in K_pre, move them to K + psi = K_pre.hom([K.gen()], K) # Identification of K_pre with K + C = [psi(c) for c in C] # The elements of C were in K_pre, move them to K from sage.schemes.projective.projective_space import ProjectiveSpace N = self.domain().dimension_relative() - PS = ProjectiveSpace(K,N,self.domain().variable_names()) + PS = ProjectiveSpace(K, N, self.domain().variable_names()) if self.is_endomorphism(): H = End(PS) else: - PS2 = ProjectiveSpace(K,self.codomain().dimension_relative(),\ - self.codomain().variable_names()) - H = Hom(PS,PS2) + PS2 = ProjectiveSpace(K, self.codomain().dimension_relative(), + self.codomain().variable_names()) + H = Hom(PS, PS2) R = PS.coordinate_ring() exps = [f.exponents() for f in self] F = [] @@ -1805,36 +1854,36 @@ def base_indeterminacy_locus(self): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(P) - sage: f = H([x*z-y*z, x^2-y^2, z^2]) + sage: f = H([x*z - y*z, x^2 - y^2, z^2]) sage: f.base_indeterminacy_locus() Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x*z - y*z, - x^2 - y^2, - z^2 + x*z - y*z, + x^2 - y^2, + z^2 :: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(P) sage: f = H([x^2, y^2, z^2]) sage: f.base_indeterminacy_locus() Closed subscheme of Projective Space of dimension 2 over Rational Field - defined by: - x^2, - y^2, - z^2 + defined by: + x^2, + y^2, + z^2 :: - sage: P1.<x,y,z> = ProjectiveSpace(RR,2) - sage: P2.<t,u,v,w> = ProjectiveSpace(RR,3) - sage: H = Hom(P1,P2) + sage: P1.<x,y,z> = ProjectiveSpace(RR, 2) + sage: P2.<t,u,v,w> = ProjectiveSpace(RR, 3) + sage: H = Hom(P1, P2) sage: h = H([y^3*z^3, x^3*z^3, y^3*z^3, x^2*y^2*z^2]) - sage: h.base_indeterminacy_locus() - Closed subscheme of Projective Space of dimension 2 over Real Field with - 53 bits of precision defined by: + sage: h.base_indeterminacy_locus() # needs sage.rings.real_mpfr + Closed subscheme of Projective Space of dimension 2 over + Real Field with 53 bits of precision defined by: y^3*z^3, x^3*z^3, y^3*z^3, @@ -1842,12 +1891,12 @@ def base_indeterminacy_locus(self): If defining polynomials are not normalized, output scheme will not be normalized:: - sage: P.<x,y,z>=ProjectiveSpace(QQ,2) - sage: H=End(P) - sage: f=H([x*x^2,x*y^2,x*z^2]) + sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: H = End(P) + sage: f = H([x*x^2,x*y^2,x*z^2]) sage: f.base_indeterminacy_locus() Closed subscheme of Projective Space of dimension 2 over Rational Field - defined by: + defined by: x^3, x*y^2, x*z^2 @@ -1867,12 +1916,12 @@ def indeterminacy_locus(self): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(P) sage: f = H([x^2, y^2, z^2]) - sage: f.indeterminacy_locus() - ... DeprecationWarning: The meaning of indeterminacy_locus() has changed. Read the docstring. - See https://github.com/sagemath/sage/issues/29145 for details. + sage: f.indeterminacy_locus() # needs sage.libs.singular + ... DeprecationWarning: The meaning of indeterminacy_locus() has changed. + Read the docstring. See https://github.com/sagemath/sage/issues/29145 for details. Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: z, y, @@ -1880,10 +1929,10 @@ def indeterminacy_locus(self): :: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(P) sage: f = H([x*z - y*z, x^2 - y^2, z^2]) - sage: f.indeterminacy_locus() + sage: f.indeterminacy_locus() # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: z, x^2 - y^2 @@ -1892,7 +1941,7 @@ def indeterminacy_locus(self): computes the indeterminacy locus only from the defining polynomials of the map:: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(P) sage: f = H([x*z - y*z, x^2 - y^2, z^2]) sage: f.base_indeterminacy_locus() @@ -1924,42 +1973,43 @@ def indeterminacy_points(self, F=None, base=False): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(P) - sage: f = H([x*z-y*z, x^2-y^2, z^2]) - sage: f.indeterminacy_points() - ... DeprecationWarning: The meaning of indeterminacy_locus() has changed. Read the docstring. - See https://github.com/sagemath/sage/issues/29145 for details. + sage: f = H([x*z - y*z, x^2 - y^2, z^2]) + sage: f.indeterminacy_points() # needs sage.libs.singular + ... DeprecationWarning: The meaning of indeterminacy_locus() has changed. + Read the docstring. See https://github.com/sagemath/sage/issues/29145 for details. [(-1 : 1 : 0), (1 : 1 : 0)] :: - sage: P1.<x,y,z> = ProjectiveSpace(RR,2) - sage: P2.<t,u,v,w> = ProjectiveSpace(RR,3) - sage: H = Hom(P1,P2) - sage: h = H([x+y, y, z+y, y]) + sage: P1.<x,y,z> = ProjectiveSpace(RR, 2) + sage: P2.<t,u,v,w> = ProjectiveSpace(RR, 3) + sage: H = Hom(P1, P2) + sage: h = H([x + y, y, z + y, y]) sage: set_verbose(None) - sage: h.indeterminacy_points(base=True) + sage: h.indeterminacy_points(base=True) # needs sage.libs.singular [] sage: g = H([y^3*z^3, x^3*z^3, y^3*z^3, x^2*y^2*z^2]) - sage: g.indeterminacy_points(base=True) + sage: g.indeterminacy_points(base=True) # needs sage.libs.singular Traceback (most recent call last): ... ValueError: indeterminacy scheme is not dimension 0 :: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(P) - sage: f = H([x^2+y^2, x*z, x^2+y^2]) - sage: f.indeterminacy_points() + sage: f = H([x^2 + y^2, x*z, x^2 + y^2]) + sage: f.indeterminacy_points() # needs sage.libs.singular [(0 : 0 : 1)] + sage: R.<t> = QQ[] - sage: K.<a> = NumberField(t^2+1) - sage: f.indeterminacy_points(F=K) + sage: K.<a> = NumberField(t^2 + 1) # needs sage.rings.number_field + sage: f.indeterminacy_points(F=K) # needs sage.libs.singular sage.rings.number_field [(-a : 1 : 0), (0 : 0 : 1), (a : 1 : 0)] sage: set_verbose(None) - sage: f.indeterminacy_points(F=QQbar, base=True) + sage: f.indeterminacy_points(F=QQbar, base=True) # needs sage.libs.singular sage.rings.number_field [(-1*I : 1 : 0), (0 : 0 : 1), (1*I : 1 : 0)] :: @@ -1969,31 +2019,30 @@ def indeterminacy_points(self, F=None, base=False): sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: H = End(P) sage: f = H([x^2 - t^2*y^2, y^2 - z^2, x^2 - t^2*z^2]) - sage: f.indeterminacy_points(base=True) + sage: f.indeterminacy_points(base=True) # needs sage.libs.singular [(-t : -1 : 1), (-t : 1 : 1), (t : -1 : 1), (t : 1 : 1)] :: + sage: # needs sage.rings.padics sage: set_verbose(None) sage: P.<x,y,z> = ProjectiveSpace(Qp(3), 2) sage: H = End(P) sage: f = H([x^2 - 7*y^2, y^2 - z^2, x^2 - 7*z^2]) - sage: f.indeterminacy_points(base=True) - [(2 + 3 + 3^2 + 2*3^3 + 2*3^5 + 2*3^6 + 3^8 + 3^9 + 2*3^11 + 3^15 + - 2*3^16 + 3^18 + O(3^20) : 1 + O(3^20) : 1 + O(3^20)), - (2 + 3 + 3^2 + 2*3^3 + 2*3^5 + 2*3^6 + 3^8 + 3^9 + 2*3^11 + 3^15 + - 2*3^16 + 3^18 + O(3^20) : 2 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + - 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + 2*3^12 + 2*3^13 + - 2*3^14 + 2*3^15 + 2*3^16 + 2*3^17 + 2*3^18 + 2*3^19 + O(3^20) : 1 + - O(3^20)), - (1 + 3 + 3^2 + 2*3^4 + 2*3^7 + 3^8 + 3^9 + 2*3^10 + 2*3^12 + 2*3^13 + - 2*3^14 + 3^15 + 2*3^17 + 3^18 + 2*3^19 + O(3^20) : 1 + O(3^20) : 1 + - O(3^20)), - (1 + 3 + 3^2 + 2*3^4 + 2*3^7 + 3^8 + 3^9 + 2*3^10 + 2*3^12 + 2*3^13 + - 2*3^14 + 3^15 + 2*3^17 + 3^18 + 2*3^19 + O(3^20) : 2 + 2*3 + 2*3^2 + - 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 - + 2*3^12 + 2*3^13 + 2*3^14 + 2*3^15 + 2*3^16 + 2*3^17 + 2*3^18 + 2*3^19 - + O(3^20) : 1 + O(3^20))] + sage: f.indeterminacy_points(base=True) # needs sage.libs.singular + [(2 + 3 + 3^2 + 2*3^3 + 2*3^5 + 2*3^6 + 3^8 + + 3^9 + 2*3^11 + 3^15 + 2*3^16 + 3^18 + O(3^20) : 1 + O(3^20) : 1 + O(3^20)), + (2 + 3 + 3^2 + 2*3^3 + 2*3^5 + 2*3^6 + 3^8 + 3^9 + 2*3^11 + 3^15 + + 2*3^16 + 3^18 + O(3^20) : 2 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + 2*3^12 + 2*3^13 + + 2*3^14 + 2*3^15 + 2*3^16 + 2*3^17 + 2*3^18 + 2*3^19 + O(3^20) : 1 + O(3^20)), + (1 + 3 + 3^2 + 2*3^4 + 2*3^7 + 3^8 + 3^9 + 2*3^10 + 2*3^12 + 2*3^13 + + 2*3^14 + 3^15 + 2*3^17 + 3^18 + 2*3^19 + O(3^20) : 1 + O(3^20) : 1 + O(3^20)), + (1 + 3 + 3^2 + 2*3^4 + 2*3^7 + 3^8 + 3^9 + 2*3^10 + 2*3^12 + 2*3^13 + + 2*3^14 + 3^15 + 2*3^17 + 3^18 + 2*3^19 + O(3^20) : 2 + 2*3 + 2*3^2 + + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + + 2*3^12 + 2*3^13 + 2*3^14 + 2*3^15 + 2*3^16 + 2*3^17 + 2*3^18 + 2*3^19 + + O(3^20) : 1 + O(3^20))] """ if F is None: fcn = self @@ -2025,62 +2074,66 @@ def reduce_base_field(self): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: K.<t> = GF(3^4) sage: P.<x,y> = ProjectiveSpace(K, 1) sage: P2.<a,b,c> = ProjectiveSpace(K, 2) sage: H = End(P) - sage: H2 = Hom(P,P2) - sage: H3 = Hom(P2,P) + sage: H2 = Hom(P, P2) + sage: H3 = Hom(P2, P) sage: f = H([x^2 + (2*t^3 + 2*t^2 + 1)*y^2, y^2]) sage: f.reduce_base_field() - Scheme endomorphism of Projective Space of dimension 1 over Finite Field in t2 of size 3^2 - Defn: Defined on coordinates by sending (x : y) to - (x^2 + t2*y^2 : y^2) - sage: f2 = H2([x^2 + 5*y^2,y^2, 2*x*y]) + Scheme endomorphism of Projective Space of dimension 1 + over Finite Field in t2 of size 3^2 + Defn: Defined on coordinates by sending (x : y) to (x^2 + t2*y^2 : y^2) + sage: f2 = H2([x^2 + 5*y^2, y^2, 2*x*y]) sage: f2.reduce_base_field() Scheme morphism: From: Projective Space of dimension 1 over Finite Field of size 3 To: Projective Space of dimension 2 over Finite Field of size 3 - Defn: Defined on coordinates by sending (x : y) to - (x^2 - y^2 : y^2 : -x*y) + Defn: Defined on coordinates by sending (x : y) to (x^2 - y^2 : y^2 : -x*y) sage: f3 = H3([a^2 + t*b^2, c^2]) sage: f3.reduce_base_field() Scheme morphism: From: Projective Space of dimension 2 over Finite Field in t of size 3^4 To: Projective Space of dimension 1 over Finite Field in t of size 3^4 - Defn: Defined on coordinates by sending (a : b : c) to - (a^2 + t*b^2 : c^2) + Defn: Defined on coordinates by sending (a : b : c) to (a^2 + t*b^2 : c^2) :: + sage: # needs sage.rings.number_field sage: K.<v> = CyclotomicField(4) sage: P.<x,y> = ProjectiveSpace(K, 1) sage: H = End(P) sage: f = H([x^2 + 2*y^2, y^2]) sage: f.reduce_base_field() Scheme endomorphism of Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (x^2 + 2*y^2 : y^2) + Defn: Defined on coordinates by sending (x : y) to (x^2 + 2*y^2 : y^2) :: + sage: # needs sage.rings.finite_rings sage: K.<v> = GF(5) sage: L = K.algebraic_closure() sage: P.<x,y> = ProjectiveSpace(L, 1) sage: H = End(P) sage: f = H([(L.gen(2))*x^2 + L.gen(4)*y^2, x*y]) sage: f.reduce_base_field() - Scheme endomorphism of Projective Space of dimension 1 over Finite Field in z4 of size 5^4 + Scheme endomorphism of Projective Space of dimension 1 + over Finite Field in z4 of size 5^4 Defn: Defined on coordinates by sending (x : y) to ((z4^3 + z4^2 + z4 - 2)*x^2 + z4*y^2 : x*y) - sage: f=DynamicalSystem_projective([L.gen(3)*x^2 + L.gen(2)*y^2, x*y]) + sage: f = DynamicalSystem_projective([L.gen(3)*x^2 + L.gen(2)*y^2, x*y]) sage: f.reduce_base_field() - Dynamical System of Projective Space of dimension 1 over Finite Field in z6 of size 5^6 + Dynamical System of Projective Space of dimension 1 + over Finite Field in z6 of size 5^6 Defn: Defined on coordinates by sending (x : y) to - ((-z6^5 + z6^4 - z6^3 - z6^2 - 2*z6 - 2)*x^2 + (z6^5 - 2*z6^4 + z6^2 - z6 + 1)*y^2 : x*y) + ((-z6^5 + z6^4 - z6^3 - z6^2 - 2*z6 - 2)*x^2 + + (z6^5 - 2*z6^4 + z6^2 - z6 + 1)*y^2 : x*y) TESTS:: + sage: # needs sage.rings.finite_rings sage: F = GF(3).algebraic_closure() sage: P.<x,y> = ProjectiveSpace(F, 1) sage: H = Hom(P, P) @@ -2103,20 +2156,20 @@ def reduce_base_field(self): return self # otherwise we are not in the prime subfield so coercion # to it does not work - for L,phi in K.subfields(): + for L, phi in K.subfields(): # find the right subfield and its embedding if L.degree() == d: break # we need to rewrite each of the coefficients in terms of the generator # of L. To do this, we'll set-up an ideal and use elimination R = PolynomialRing(K.prime_subfield(), 2, 'a') - a,b = R.gens() + a, b = R.gens() from sage.schemes.projective.projective_space import ProjectiveSpace - new_domain = ProjectiveSpace(L, self.domain().dimension_relative(),\ - self.domain().variable_names()) + new_domain = ProjectiveSpace(L, self.domain().dimension_relative(), + self.domain().variable_names()) new_R = new_domain.coordinate_ring() - u = phi(L.gen()) # gen of L in terms of gen of K - g = R(str(u).replace(K.variable_name(),R.variable_names()[0])) #converted to R + u = phi(L.gen()) # gen of L in terms of gen of K + g = R(str(u).replace(K.variable_name(), R.variable_names()[0])) #converted to R new_f = [] for fi in self: mon = fi.monomials() @@ -2147,14 +2200,14 @@ def reduce_base_field(self): return H(new_f) elif isinstance(K, AlgebraicClosureFiniteField_generic): self.domain().coordinate_ring() - #find the degree of the extension containing the coefficients + # find the degree of the extension containing the coefficients c = [v for g in self for v in g.coefficients()] d = lcm([a.minpoly().degree() for a in c]) - #get the appropriate subfield + # get the appropriate subfield L, L_to_K = K.subfield(d) from sage.schemes.projective.projective_space import ProjectiveSpace - new_domain = ProjectiveSpace(L, self.domain().dimension_relative(),\ - self.domain().variable_names()) + new_domain = ProjectiveSpace(L, self.domain().dimension_relative(), + self.domain().variable_names()) new_R = new_domain.coordinate_ring() # we need to rewrite each of the coefficients in terms of the generator # of L. To do this, we'll set-up an ideal and use elimination @@ -2167,16 +2220,17 @@ def reduce_base_field(self): for c in coef: # for each coefficient move to the correct base field da = c.minpoly().degree() - for M,M_to_L in L.subfields(): - #find the right subfield and it's embedding + for M, M_to_L in L.subfields(): + # find the right subfield and it's embedding if M.degree() == da: break - c = M((str(c).replace(c.as_finite_field_element()[0].variable_name(),\ - M.variable_name()))) + c = M((str(c).replace(c.as_finite_field_element()[0].variable_name(), + M.variable_name()))) new_c.append(M_to_L(c)) # reconstruct as a poly in the new domain - new_f.append(sum([new_c[i]*prod([new_R.gen(j)**mon_deg[i][j] \ - for j in range(new_R.ngens())]) for i in range(len(mon))])) + new_f.append(sum([new_c[i] * prod(new_R.gen(j)**mon_deg[i][j] + for j in range(new_R.ngens())) + for i in range(len(mon))])) # return the correct type of map if self.is_endomorphism(): H = Hom(new_domain, new_domain) @@ -2196,11 +2250,11 @@ def image(self): sage: P2.<x0,x1,x2> = ProjectiveSpace(QQ, 2) sage: f = P2.hom([x0^3, x0^2*x1, x0*x1^2], P2) - sage: f.image() + sage: f.image() # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x1^2 - x0*x2 sage: f = P2.hom([x0 - x1, x0 - x2, x1 - x2], P2) - sage: f.image() + sage: f.image() # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x0 - x1 + x2 @@ -2208,8 +2262,8 @@ def image(self): sage: P2.<x0,x1,x2> = ProjectiveSpace(QQ, 2) sage: A2.<x,y> = AffineSpace(QQ, 2) - sage: f = P2.hom([1,x0/x1], A2) - sage: f.image() + sage: f = P2.hom([1, x0/x1], A2) + sage: f.image() # needs sage.libs.singular Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: -x + 1 """ @@ -2226,9 +2280,9 @@ def _fast_eval(self, x): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(GF(7),2) - sage: H = Hom(P,P) - sage: f = H([x^2+y^2, y^2, z^2 + y*z]) + sage: P.<x,y,z> = ProjectiveSpace(GF(7), 2) + sage: H = Hom(P, P) + sage: f = H([x^2 + y^2, y^2, z^2 + y*z]) sage: f._fast_eval([1,1,1]) [2, 1, 2] """ @@ -2256,6 +2310,7 @@ def __call__(self, x): TESTS:: + sage: # needs sage.schemes sage: R.<x,y,z> = QQ[] sage: C = Curve(7*x^2 + 2*y*z + z^2) sage: f, g = C.parametrization() @@ -2286,11 +2341,12 @@ def __eq__(self, other): EXAMPLES:: sage: R.<x,y,z> = QQ[] - sage: C = Curve(7*x^2 + 2*y*z + z^2) # conic - sage: f, g = C.parametrization() - sage: f*g == C.identity_morphism() + sage: C = Curve(7*x^2 + 2*y*z + z^2) # conic # needs sage.schemes + sage: f, g = C.parametrization() # needs sage.schemes + sage: f*g == C.identity_morphism() # needs sage.schemes True + sage: # needs sage.schemes sage: C = Curve(x^2 + y^2 - z^2) sage: P.<u, v> = ProjectiveSpace(QQ, 1) sage: f = C.hom([x + z, y], P) @@ -2323,86 +2379,77 @@ def representatives(self): EXAMPLES:: - sage: P2.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) sage: X = P2.subscheme(0) sage: f = X.hom([x^2*y, x^2*z, x*y*z], P2) - sage: f.representatives() + sage: f.representatives() # needs sage.libs.singular [Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - 0 + From: Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: 0 To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (x*y : x*z : y*z)] + Defn: Defined on coordinates by sending (x : y : z) to (x*y : x*z : y*z)] :: - sage: P2.<x,y,z> = ProjectiveSpace(QQ,2) - sage: P1.<a,b> = ProjectiveSpace(QQ,1) + sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: P1.<a,b> = ProjectiveSpace(QQ, 1) sage: X = P2.subscheme([x^2 - y^2 - y*z]) sage: f = X.hom([x, y], P1) - sage: f.representatives() + sage: f.representatives() # needs sage.libs.singular [Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y*z + From: Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: x^2 - y^2 - y*z To: Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (y + z : x), - Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y*z + Defn: Defined on coordinates by sending (x : y : z) to (y + z : x), + Scheme morphism: + From: Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: x^2 - y^2 - y*z To: Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (x : y)] - sage: g = _[0] - sage: g.representatives() + Defn: Defined on coordinates by sending (x : y : z) to (x : y)] + sage: g = _[0] # needs sage.libs.singular + sage: g.representatives() # needs sage.libs.singular [Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y*z + From: Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: x^2 - y^2 - y*z To: Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (y + z : x), - Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y*z + Defn: Defined on coordinates by sending (x : y : z) to (y + z : x), + Scheme morphism: + From: Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: x^2 - y^2 - y*z To: Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (x : y)] + Defn: Defined on coordinates by sending (x : y : z) to (x : y)] :: - sage: P2.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) sage: X = P2.subscheme([x^2 - y^2 - y*z]) - sage: A1.<a> = AffineSpace(QQ,1) + sage: A1.<a> = AffineSpace(QQ, 1) sage: g = X.hom([y/x], A1) - sage: g.representatives() + sage: g.representatives() # needs sage.libs.singular [Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y*z + From: Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: x^2 - y^2 - y*z To: Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (x/(y + z)), - Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y*z + Defn: Defined on coordinates by sending (x : y : z) to (x/(y + z)), + Scheme morphism: + From: Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: x^2 - y^2 - y*z To: Affine Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (y/x)] - sage: g0, g1 = _ + Defn: Defined on coordinates by sending (x : y : z) to (y/x)] + sage: g0, g1 = _ # needs sage.libs.singular sage: emb = A1.projective_embedding(0) - sage: emb*g0 + sage: emb*g0 # needs sage.libs.singular Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y*z + From: Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: x^2 - y^2 - y*z To: Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (y + z : x) - sage: emb*g1 + Defn: Defined on coordinates by sending (x : y : z) to (y + z : x) + sage: emb*g1 # needs sage.libs.singular Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x^2 - y^2 - y*z + From: Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: x^2 - y^2 - y*z To: Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (x : y) + Defn: Defined on coordinates by sending (x : y : z) to (x : y) ALGORITHM: @@ -2464,7 +2511,8 @@ def representatives(self): M = kernel.sage_matrix(R) # m * n matrix over R reprs = [] for i in range(M.ncols()): - reprs.append(X.hom([lift(F[j]*M[r][i] / F[r]) for j in range(n)], Y)) + lifts = [lift(F[j] * M[r][i] / F[r]) for j in range(n)] + reprs.append(X.hom(lifts, Y)) return reprs @@ -2482,17 +2530,17 @@ def indeterminacy_locus(self): sage: P2.<x0,x1,x2> = ProjectiveSpace(QQ, 2) sage: X = P2.subscheme(0) sage: f = X.hom([x1,x0], P) - sage: L = f.indeterminacy_locus() - sage: L.rational_points() + sage: L = f.indeterminacy_locus() # needs sage.libs.singular + sage: L.rational_points() # needs sage.libs.singular [(0 : 0 : 1)] :: sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: P1.<a,b> = ProjectiveSpace(QQ,1) + sage: P1.<a,b> = ProjectiveSpace(QQ, 1) sage: X = P2.subscheme([x^2 - y^2 - y*z]) sage: f = X.hom([x,y], P1) - sage: f.indeterminacy_locus() + sage: f.indeterminacy_locus() # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: z, y, @@ -2504,12 +2552,12 @@ def indeterminacy_locus(self): sage: P2.<a,b,c> = ProjectiveSpace(QQ, 2) sage: X = P3.subscheme(x^2 - w*y - x*z) sage: f = X.hom([x*y, y*z, z*x], P2) - sage: L = f.indeterminacy_locus() - sage: L.dimension() + sage: L = f.indeterminacy_locus() # needs sage.libs.singular + sage: L.dimension() # needs sage.libs.singular 0 - sage: L.degree() + sage: L.degree() # needs sage.libs.singular 2 - sage: L.rational_points() + sage: L.rational_points() # needs sage.libs.singular [(0 : 0 : 0 : 1), (0 : 1 : 0 : 0)] :: @@ -2518,8 +2566,8 @@ def indeterminacy_locus(self): sage: A2.<a,b> = AffineSpace(QQ, 2) sage: X = P3.subscheme(x^2 - w*y - x*z) sage: f = X.hom([x/z, y/x], A2) - sage: L = f.indeterminacy_locus() - sage: L.rational_points() + sage: L = f.indeterminacy_locus() # needs sage.libs.singular + sage: L.rational_points() # needs sage.libs.singular [(0 : 0 : 0 : 1), (0 : 1 : 0 : 0)] :: @@ -2528,7 +2576,7 @@ def indeterminacy_locus(self): sage: X = P.subscheme(x - y) sage: H = End(X) sage: f = H([x^2 - 4*y^2, y^2 - z^2, 4*z^2 - x^2]) - sage: Z = f.indeterminacy_locus(); Z + sage: Z = f.indeterminacy_locus(); Z # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: z, y, @@ -2571,10 +2619,10 @@ def is_morphism(self): EXAMPLES:: sage: P2.<x,y,z> = ProjectiveSpace(QQ,2) - sage: P1.<a,b> = ProjectiveSpace(QQ,1) + sage: P1.<a,b> = ProjectiveSpace(QQ, 1) sage: X = P2.subscheme([x^2 - y^2 - y*z]) sage: f = X.hom([x,y], P1) - sage: f.is_morphism() + sage: f.is_morphism() # needs sage.libs.singular True """ return self.indeterminacy_locus().dimension() < 0 @@ -2589,7 +2637,7 @@ def image(self): sage: P2.<x0,x1,x2> = ProjectiveSpace(QQ, 2) sage: X = P2.subscheme(0) sage: f = X.hom([x1,x0], P) - sage: f.image() + sage: f.image() # needs sage.libs.singular Closed subscheme of Projective Space of dimension 1 over Rational Field defined by: (no polynomials) @@ -2598,7 +2646,7 @@ def image(self): sage: P2.<x,y,z> = ProjectiveSpace(QQ,2) sage: X = P2.subscheme([z^3 - x*y^2 + y^3]) sage: f = X.hom([x*z, x*y, x^2 + y*z], P2) - sage: f.image() + sage: f.image() # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^6 + 2*x^3*y^3 + x*y^5 + y^6 - x^3*y^2*z - y^5*z """ @@ -2650,13 +2698,13 @@ def graph(self): sage: A1.<x> = AffineSpace(1, QQ) sage: X = A1.subscheme(0) # affine line sage: phi = X.hom([x^2], A1) - sage: mor = phi.homogenize(0) - sage: G = mor.graph(); G - Closed subscheme of Product of projective spaces P^1 x P^1 over Rational Field defined by: - x1^2*x2 - x0^2*x3 - sage: G.affine_patch([0, 0]) - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x0^2 - x1 + sage: mor = phi.homogenize(0) # needs sage.libs.singular + sage: G = mor.graph(); G # needs sage.libs.singular + Closed subscheme of Product of projective spaces P^1 x P^1 + over Rational Field defined by: x1^2*x2 - x0^2*x3 + sage: G.affine_patch([0, 0]) # needs sage.libs.singular + Closed subscheme of Affine Space of dimension 2 + over Rational Field defined by: x0^2 - x1 """ X = self.domain() Y = self.codomain() @@ -2702,9 +2750,10 @@ def projective_degrees(self): EXAMPLES:: + sage: # needs sage.schemes sage: k = GF(11) - sage: E = EllipticCurve(k,[1,1]) - sage: Q = E(6,5) + sage: E = EllipticCurve(k, [1,1]) + sage: Q = E(6, 5) sage: phi = E.scalar_multiplication(2) sage: mor = phi.as_morphism() sage: mor.projective_degrees() @@ -2725,7 +2774,7 @@ def projective_degrees(self): G = self.graph() I = G.defining_ideal() # a bihomogeneous ideal - degrees = xn*[vector([1,0])] + yn*[vector([0,1])] + degrees = xn * [vector([1, 0])] + yn * [vector([0, 1])] res = I.graded_free_resolution(degrees=degrees, algorithm='shreyer') kpoly = res.K_polynomial() @@ -2744,9 +2793,10 @@ def degree(self): EXAMPLES:: + sage: # needs sage.schemes sage: k = GF(11) - sage: E = EllipticCurve(k,[1,1]) - sage: Q = E(6,5) + sage: E = EllipticCurve(k, [1,1]) + sage: Q = E(6, 5) sage: phi = E.scalar_multiplication(2) sage: mor = phi.as_morphism() sage: mor.degree() diff --git a/src/sage/schemes/projective/projective_point.py b/src/sage/schemes/projective/projective_point.py index d94d108e5d6..53038b21efe 100644 --- a/src/sage/schemes/projective/projective_point.py +++ b/src/sage/schemes/projective/projective_point.py @@ -36,11 +36,12 @@ from sage.categories.number_fields import NumberFields _NumberFields = NumberFields() from sage.rings.fraction_field import FractionField -from sage.rings.number_field.order import is_NumberFieldOrder +from sage.rings.number_field.order import is_NumberFieldOrder, Order as NumberFieldOrder from sage.rings.qqbar import number_field_elements_from_algebraics from sage.rings.quotient_ring import QuotientRing_generic from sage.rings.rational_field import QQ -from sage.arith.all import gcd, lcm +from sage.arith.misc import GCD as gcd +from sage.arith.functions import lcm from sage.misc.misc_c import prod from copy import copy @@ -104,7 +105,8 @@ def __init__(self, X, v, check=True): sage: P(0,0,0,0) Traceback (most recent call last): ... - ValueError: [0, 0, 0, 0] does not define a point in Projective Space of dimension 3 over Integer Ring since all entries are zero + ValueError: [0, 0, 0, 0] does not define a point in Projective Space of dimension 3 + over Integer Ring since all entries are zero :: @@ -118,7 +120,8 @@ def __init__(self, X, v, check=True): sage: P(0,5,10,15) Traceback (most recent call last): ... - ValueError: [0, 5, 10, 0] does not define a point in Projective Space of dimension 3 over Ring of integers modulo 15 since it is a multiple of a zero divisor + ValueError: [0, 5, 10, 0] does not define a point in Projective Space of dimension 3 + over Ring of integers modulo 15 since it is a multiple of a zero divisor It is possible to avoid the possibly time-consuming checks, but be careful!! :: @@ -129,20 +132,20 @@ def __init__(self, X, v, check=True): :: sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) - sage: X = P.subscheme([x^2-y*z]) + sage: X = P.subscheme([x^2 - y*z]) sage: X([2, 2, 2]) (2 : 2 : 2) :: sage: R.<t> = PolynomialRing(ZZ) - sage: P = ProjectiveSpace(1, R.quo(t^2+1)) - sage: P([2*t, 1]) + sage: P = ProjectiveSpace(1, R.quo(t^2 + 1)) # needs sage.libs.pari + sage: P([2*t, 1]) # needs sage.libs.pari (2*tbar : 1) :: - sage: P = ProjectiveSpace(ZZ,1) + sage: P = ProjectiveSpace(ZZ, 1) sage: P.point(Infinity) (1 : 0) sage: P(infinity) @@ -150,7 +153,7 @@ def __init__(self, X, v, check=True): :: - sage: P = ProjectiveSpace(ZZ,2) + sage: P = ProjectiveSpace(ZZ, 2) sage: P(Infinity) Traceback (most recent call last): ... @@ -174,9 +177,9 @@ def __init__(self, X, v, check=True): except AttributeError: pass if not isinstance(v, (list, tuple)): - raise TypeError("argument v (= %s) must be a scheme point, list, or tuple"%str(v)) + raise TypeError("argument v (= %s) must be a scheme point, list, or tuple" % str(v)) if len(v) != d and len(v) != d-1: - raise TypeError("v (=%s) must have %s components"%(v, d)) + raise TypeError("v (=%s) must have %s components" % (v, d)) R = X.value_ring() v = Sequence(v, R) @@ -233,6 +236,7 @@ def _richcmp_(self, right, op): :: + sage: # needs sage.rings.padics sage: PS = ProjectiveSpace(Zp(5), 1, 'x') sage: P = PS([0, 1]) sage: P == PS(0) @@ -242,8 +246,8 @@ def _richcmp_(self, right, op): sage: R.<t> = PolynomialRing(QQ) sage: PS = ProjectiveSpace(R, 1, 'x') - sage: P = PS([t, 1+t^2]) - sage: Q = PS([t^2, t+t^3]) + sage: P = PS([t, 1 + t^2]) + sage: Q = PS([t^2, t + t^3]) sage: P == Q True @@ -258,9 +262,9 @@ def _richcmp_(self, right, op): sage: PS = ProjectiveSpace(ZZ, 1, 'x') sage: P = PS([2, 1]) - sage: PS2 = ProjectiveSpace(Zp(7), 1, 'x') - sage: Q = PS2([2, 1]) - sage: P == Q + sage: PS2 = ProjectiveSpace(Zp(7), 1, 'x') # needs sage.rings.padics + sage: Q = PS2([2, 1]) # needs sage.rings.padics + sage: P == Q # needs sage.rings.padics True :: @@ -281,24 +285,27 @@ def _richcmp_(self, right, op): :: + sage: # needs sage.rings.number_field sage: R.<z> = PolynomialRing(QQ) - sage: K.<t> = NumberField(z^2+5) + sage: K.<t> = NumberField(z^2 + 5) sage: OK = K.ring_of_integers() sage: t = OK.gen(1) - sage: PS.<x,y> = ProjectiveSpace(OK,1) - sage: P = PS(2, 1+t) - sage: Q = PS(1-t, 3) + sage: PS.<x,y> = ProjectiveSpace(OK, 1) + sage: P = PS(2, 1 + t) + sage: Q = PS(1 - t, 3) sage: P == Q True Check that :trac:`17429` is fixed:: + sage: # needs sage.rings.complex_interval_field sage: R.<x> = PolynomialRing(QQ) - sage: r = (x^2-x-3).polynomial(x).roots(ComplexIntervalField(), multiplicities=False) + sage: r = (x^2 - x - 3).polynomial(x).roots(ComplexIntervalField(), + ....: multiplicities=False) sage: P.<x,y> = ProjectiveSpace(ComplexIntervalField(), 1) sage: P1 = P(r[0], 1) sage: H = End(P) - sage: f = H([x^2-3*y^2, y^2]) + sage: f = H([x^2 - 3*y^2, y^2]) sage: Q1 = f(P1) sage: Q1 == P1 False @@ -321,6 +328,7 @@ def _richcmp_(self, right, op): :: + sage: # needs sage.rings.padics sage: PS = ProjectiveSpace(Zp(5), 1, 'x') sage: P = PS([0, 1]) sage: P != PS(0) @@ -330,8 +338,8 @@ def _richcmp_(self, right, op): sage: R.<t> = PolynomialRing(QQ) sage: PS = ProjectiveSpace(R, 1, 'x') - sage: P = PS([t, 1+t^2]) - sage: Q = PS([t^2, t+t^3]) + sage: P = PS([t, 1 + t^2]) + sage: Q = PS([t^2, t + t^3]) sage: P != Q False @@ -346,9 +354,9 @@ def _richcmp_(self, right, op): sage: PS = ProjectiveSpace(ZZ, 1, 'x') sage: P = PS([2, 1]) - sage: PS2 = ProjectiveSpace(Zp(7), 1, 'x') - sage: Q = PS2([2, 1]) - sage: P != Q + sage: PS2 = ProjectiveSpace(Zp(7), 1, 'x') # needs sage.rings.padics + sage: Q = PS2([2, 1]) # needs sage.rings.padics + sage: P != Q # needs sage.rings.padics False :: @@ -393,11 +401,12 @@ def __hash__(self): :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) sage: K.<w> = NumberField(x^2 + 3) sage: O = K.maximal_order() sage: P.<x,y> = ProjectiveSpace(O, 1) - sage: hash(P([1+w, 2])) == hash(P([2, 1-w])) + sage: hash(P([1 + w, 2])) == hash(P([2, 1 - w])) True TESTS:: @@ -406,9 +415,9 @@ def __hash__(self): sage: Q.<x,y> = ProjectiveSpace(Zmod(10), 1) sage: hash(P([2, 5])) == hash(Q([2, 5])) True - sage: hash(P([2, 5])) == hash(P([2,5])) + sage: hash(P([2, 5])) == hash(P([2, 5])) True - sage: hash(P([3, 7])) == hash(P([2,5])) + sage: hash(P([3, 7])) == hash(P([2, 5])) True """ R = self.codomain().base_ring() @@ -436,36 +445,37 @@ def _matrix_times_point_(self, mat, dom): EXAMPLES:: - sage: P = ProjectiveSpace(QQ,1) + sage: P = ProjectiveSpace(QQ, 1) sage: Q = P(1,1) - sage: m = matrix(QQ, 2, 2, [1,1,0,1]) - sage: m*Q + sage: m = matrix(QQ, 2, 2, [1,1, 0,1]) # needs sage.modules + sage: m*Q # needs sage.modules (2 : 1) :: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: X = P.subscheme(x-y) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: X = P.subscheme(x - y) sage: Q = X(1,1) - sage: m = matrix(CC, 3, 3, [1,CC.0,0,CC.0,1,0,1,1,1]) - sage: m*Q + sage: m = matrix(CC, 3, 3, [1,CC.0,0, CC.0,1,0, 1,1,1]) # needs sage.modules + sage: m*Q # needs sage.modules (0.333333333333333 + 0.333333333333333*I : 0.333333333333333 + 0.333333333333333*I : 1.00000000000000) :: - sage: P = ProjectiveSpace(QQbar,1) + sage: # needs sage.modules sage.rings.number_field sage.symbolic + sage: P = ProjectiveSpace(QQbar, 1) sage: Q = P(QQbar(sqrt(2)),1) - sage: m = matrix(ZZ, 2, 2, [1,-1,0,1]) + sage: m = matrix(ZZ, 2, 2, [1,-1, 0,1]) sage: m*Q (0.4142135623730951? : 1) :: - sage: P = ProjectiveSpace(QQ,1) + sage: P = ProjectiveSpace(QQ, 1) sage: Q = P(1,1) - sage: m = matrix(QQ, 3, 2, [1,1,0,1,1,1]) - sage: m*Q + sage: m = matrix(QQ, 3, 2, [1,1, 0,1, 1,1]) # needs sage.modules + sage: m*Q # needs sage.modules Traceback (most recent call last): ... ValueError: matrix must be square @@ -501,6 +511,7 @@ def scale_by(self,t): :: + sage: # needs sage.libs.pari sage: R.<t> = PolynomialRing(QQ) sage: S = R.quo(R.ideal(t^3)) sage: P.<x,y,z> = ProjectiveSpace(S, 2) @@ -536,14 +547,15 @@ def normalize_coordinates(self): EXAMPLES:: - sage: P = ProjectiveSpace(ZZ,2,'x') + sage: P = ProjectiveSpace(ZZ, 2, 'x') sage: p = P([-5, -15, -20]) sage: p.normalize_coordinates(); p (1 : 3 : 4) :: - sage: P = ProjectiveSpace(Zp(7),2,'x') + sage: # needs sage.rings.padics + sage: P = ProjectiveSpace(Zp(7), 2, 'x') sage: p = P([-5, -15, -2]) sage: p.normalize_coordinates(); p (5 + O(7^20) : 1 + 2*7 + O(7^20) : 2 + O(7^20)) @@ -551,14 +563,14 @@ def normalize_coordinates(self): :: sage: R.<t> = PolynomialRing(QQ) - sage: P = ProjectiveSpace(R,2,'x') + sage: P = ProjectiveSpace(R, 2, 'x') sage: p = P([3/5*t^3, 6*t, t]) sage: p.normalize_coordinates(); p (3/5*t^2 : 6 : 1) :: - sage: P.<x,y> = ProjectiveSpace(Zmod(20),1) + sage: P.<x,y> = ProjectiveSpace(Zmod(20), 1) sage: Q = P(3, 6) sage: Q.normalize_coordinates() sage: Q @@ -568,7 +580,7 @@ def normalize_coordinates(self): gcd `c` is removed. :: sage: R.<c> = PolynomialRing(QQ) - sage: P = ProjectiveSpace(R,1) + sage: P = ProjectiveSpace(R, 1) sage: Q = P(2*c, 4*c) sage: Q.normalize_coordinates();Q (2 : 4) @@ -576,17 +588,18 @@ def normalize_coordinates(self): A polynomial ring over a ring gives the more intuitive result. :: sage: R.<c> = PolynomialRing(ZZ) - sage: P = ProjectiveSpace(R,1) + sage: P = ProjectiveSpace(R, 1) sage: Q = P(2*c, 4*c) sage: Q.normalize_coordinates();Q (1 : 2) :: - sage: R.<t> = PolynomialRing(QQ,1) + sage: # needs sage.libs.singular + sage: R.<t> = PolynomialRing(QQ, 1) sage: S = R.quotient_ring(R.ideal(t^3)) - sage: P.<x,y> = ProjectiveSpace(S,1) - sage: Q = P(t+1, t^2+t) + sage: P.<x,y> = ProjectiveSpace(S, 1) + sage: Q = P(t + 1, t^2 + t) sage: Q.normalize_coordinates() sage: Q (1 : tbar) @@ -635,31 +648,32 @@ def dehomogenize(self,n): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: X = P.subscheme(x^2-y^2); + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: X = P.subscheme(x^2 - y^2) sage: Q = X(23, 23, 46) - sage: Q.dehomogenize(2) + sage: Q.dehomogenize(2) # needs sage.libs.singular (1/2, 1/2) :: + sage: # needs sage.libs.pari sage: R.<t> = PolynomialRing(QQ) sage: S = R.quo(R.ideal(t^3)) - sage: P.<x,y,z> = ProjectiveSpace(S,2) + sage: P.<x,y,z> = ProjectiveSpace(S, 2) sage: Q = P(t, 1, 1) sage: Q.dehomogenize(1) (tbar, 1) :: - sage: P.<x,y,z> = ProjectiveSpace(GF(5),2) + sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2) sage: Q = P(1, 3, 1) sage: Q.dehomogenize(0) (3, 1) :: - sage: P.<x,y,z>= ProjectiveSpace(GF(5),2) + sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2) sage: Q = P(1, 3, 0) sage: Q.dehomogenize(2) Traceback (most recent call last): @@ -691,37 +705,38 @@ def global_height(self, prec=None): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: Q = P.point([4, 4, 1/30]) - sage: Q.global_height() + sage: Q.global_height() # needs sage.symbolic 4.78749174278205 :: - sage: P.<x,y,z> = ProjectiveSpace(ZZ,2) + sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: Q = P([4, 1, 30]) - sage: Q.global_height() + sage: Q.global_height() # needs sage.symbolic 3.40119738166216 :: sage: R.<x> = PolynomialRing(QQ) - sage: k.<w> = NumberField(x^2+5) - sage: A = ProjectiveSpace(k, 2, 'z') - sage: A([3, 5*w+1, 1]).global_height(prec=100) + sage: k.<w> = NumberField(x^2 + 5) # needs sage.rings.number_field + sage: A = ProjectiveSpace(k, 2, 'z') # needs sage.rings.number_field + sage: A([3, 5*w + 1, 1]).global_height(prec=100) # needs sage.rings.number_field 2.4181409534757389986565376694 :: - sage: P.<x,y,z> = ProjectiveSpace(QQbar,2) - sage: Q = P([QQbar(sqrt(3)), QQbar(sqrt(-2)), 1]) - sage: Q.global_height() + sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) # needs sage.rings.number_field + sage: Q = P([QQbar(sqrt(3)), QQbar(sqrt(-2)), 1]) # needs sage.rings.number_field + sage: Q.global_height() # needs sage.rings.number_field 0.549306144334055 :: + sage: # needs sage.rings.number_field sage: K = UniversalCyclotomicField() - sage: P.<x,y,z> = ProjectiveSpace(K,2) + sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: Q = P.point([K(4/3), K.gen(7), K.gen(5)]) sage: Q.global_height() 1.38629436111989 @@ -729,13 +744,13 @@ def global_height(self, prec=None): TESTS:: sage: P = ProjectiveSpace(QQ, 2) - sage: P(1/1,2/3,5/8).global_height() + sage: P(1/1, 2/3, 5/8).global_height() # needs sage.symbolic 3.17805383034795 sage: x = polygen(QQ, 'x') - sage: F.<u> = NumberField(x^3 - 5) - sage: P = ProjectiveSpace(F, 2) - sage: P(u,u^2/5,1).global_height() + sage: F.<u> = NumberField(x^3 - 5) # needs sage.rings.number_field + sage: P = ProjectiveSpace(F, 2) # needs sage.rings.number_field + sage: P(u, u^2/5, 1).global_height() # needs sage.rings.number_field 1.07295860828940 """ if prec is None: @@ -750,6 +765,8 @@ def global_height(self, prec=None): raise TypeError("must be defined over an algebraic field") else: K = P.codomain().base_ring() + if isinstance(K, NumberFieldOrder): + K = K.number_field() # first get rid of the denominators denom = lcm([xi.denominator() for xi in P]) x = [xi * denom for xi in P] @@ -781,16 +798,16 @@ def local_height(self, v, prec=None): EXAMPLES:: - sage: P.<x,y,z>= ProjectiveSpace(QQ,2) - sage: Q = P.point([4,4,1/150], False) - sage: Q.local_height(5) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: Q = P.point([4, 4, 1/150], False) + sage: Q.local_height(5) # needs sage.rings.real_mpfr 3.21887582486820 :: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: Q = P([4, 1, 30]) - sage: Q.local_height(2) + sage: Q.local_height(2) # needs sage.rings.real_mpfr 0.693147180559945 """ K = FractionField(self.domain().base_ring()) @@ -815,13 +832,14 @@ def local_height_arch(self, i, prec=None): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: Q = P.point([4, 4, 1/150], False) - sage: Q.local_height_arch(0) + sage: Q.local_height_arch(0) # needs sage.rings.real_mpfr 1.38629436111989 :: + sage: # needs sage.rings.number_field sage: P.<x,y,z> = ProjectiveSpace(QuadraticField(5, 'w'), 2) sage: Q = P.point([4, 1, 30], False) sage: Q.local_height_arch(1) @@ -856,10 +874,10 @@ def multiplier(self, f, n, check=True): EXAMPLES:: - sage: P.<x,y,z,w> = ProjectiveSpace(QQ,3) - sage: f = DynamicalSystem_projective([x^2, y^2, 4*w^2, 4*z^2], domain=P) - sage: Q = P.point([4, 4, 1, 1], False); - sage: Q.multiplier(f, 1) + sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) + sage: f = DynamicalSystem_projective([x^2, y^2, 4*w^2, 4*z^2], domain=P) # needs sage.schemes + sage: Q = P.point([4, 4, 1, 1], False) + sage: Q.multiplier(f, 1) # needs sage.schemes [ 2 0 -8] [ 0 2 -8] [ 0 0 -2] @@ -873,7 +891,7 @@ def is_preperiodic(self, f, err=0.1, return_period=False): r""" Determine if the point is preperiodic with respect to the map ``f``. - This is only implemented for projective space (not subschemes). + This is implemented for both projective space and subschemes. There are two optional keyword arguments: ``error_bound`` sets the error_bound used in the canonical height computation and ``return_period`` a boolean which controls if the period is returned if the @@ -908,73 +926,93 @@ def is_preperiodic(self, f, err=0.1, return_period=False): - boolean -- ``True`` if preperiodic. - - if return_period is ``True``, then ``(0,0)`` if wandering, and ``(m,n)`` - if preperiod ``m`` and period ``n``. + - if ``return_period`` is ``True``, then ``(0,0)`` if wandering, and ``(m,n)`` + if preperiod ``m`` and period ``n``. EXAMPLES:: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^3-3*x*y^2, y^3], domain=P) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([x^3 - 3*x*y^2, y^3], domain=P) # needs sage.schemes sage: Q = P(-1, 1) - sage: Q.is_preperiodic(f) + sage: Q.is_preperiodic(f) # needs sage.libs.singular sage.schemes True + :: + + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: X = P.subscheme(z) + sage: f = DynamicalSystem([x^2 - y^2, y^2, z^2], domain=X) # needs sage.schemes + sage: p = X((-1, 1, 0)) + sage: p.is_preperiodic(f, return_period=True) # needs sage.libs.singular sage.schemes + (0, 2) + :: sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2-29/16*y^2, y^2], domain=P) + sage: f = DynamicalSystem_projective([x^2 - 29/16*y^2, y^2], domain=P) # needs sage.schemes sage: Q = P(1, 4) - sage: Q.is_preperiodic(f, return_period=True) + sage: Q.is_preperiodic(f, return_period=True) # needs sage.libs.singular sage.schemes (1, 3) sage: Q = P(1, 1) - sage: Q.is_preperiodic(f, return_period=True) + sage: Q.is_preperiodic(f, return_period=True) # needs sage.libs.singular sage.schemes (0, 0) :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) - sage: K.<a> = NumberField(x^2+1) + sage: K.<a> = NumberField(x^2 + 1) sage: P.<x,y> = ProjectiveSpace(K, 1) - sage: f = DynamicalSystem_projective([x^5 + 5/4*x*y^4, y^5], domain=P) - sage: Q = P([-1/2*a+1/2, 1]) - sage: Q.is_preperiodic(f) + sage: f = DynamicalSystem_projective([x^5 + 5/4*x*y^4, y^5], domain=P) # needs sage.schemes + sage: Q = P([-1/2*a + 1/2, 1]) + sage: Q.is_preperiodic(f) # needs sage.schemes True sage: Q = P([a, 1]) - sage: Q.is_preperiodic(f) + sage: Q.is_preperiodic(f) # needs sage.schemes False :: - sage: P.<x,y,z> = ProjectiveSpace(QQ,2) - sage: f = DynamicalSystem_projective([-38/45*x^2 + (2*y - 7/45*z)*x + (-1/2*y^2 - 1/2*y*z + z^2),\ - -67/90*x^2 + (2*y + z*157/90)*x - y*z, z^2], domain=P) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem_projective([ # needs sage.schemes + ....: -38/45*x^2 + (2*y - 7/45*z)*x + (-1/2*y^2 - 1/2*y*z + z^2), + ....: -67/90*x^2 + (2*y + z*157/90)*x - y*z, + ....: z^2 + ....: ], domain=P) sage: Q = P([1, 3, 1]) - sage: Q.is_preperiodic(f, return_period=True) + sage: Q.is_preperiodic(f, return_period=True) # needs sage.libs.singular sage.schemes (0, 9) :: - sage: P.<x,y,z,w> = ProjectiveSpace(QQ,3) - sage: f = DynamicalSystem_projective([(-y - w)*x + (-13/30*y^2 + 13/30*w*y + w^2),\ - -1/2*x^2 + (-y + 3/2*w)*x + (-1/3*y^2 + 4/3*w*y),-3/2*z^2 + 5/2*z*w + w^2,w^2], domain=P) + sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) + sage: f = DynamicalSystem_projective([ # needs sage.schemes + ....: (-y - w)*x + (-13/30*y^2 + 13/30*w*y + w^2), + ....: -1/2*x^2 + (-y + 3/2*w)*x + (-1/3*y^2 + 4/3*w*y), + ....: -3/2*z^2 + 5/2*z*w + w^2, + ....: w^2 + ....: ], domain=P) sage: Q = P([3,0,4/3,1]) - sage: Q.is_preperiodic(f, return_period=True) + sage: Q.is_preperiodic(f, return_period=True) # needs sage.libs.singular sage.schemes (2, 24) :: + sage: # needs sage.rings.number_field sage.schemes sage.symbolic sage: from sage.misc.verbose import set_verbose sage: set_verbose(-1) - sage: P.<x,y,z> = ProjectiveSpace(QQbar,2) - sage: f = DynamicalSystem_projective([x^2, QQbar(sqrt(-1))*y^2, z^2], domain=P) + sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) + sage: f = DynamicalSystem_projective([x^2, QQbar(sqrt(-1))*y^2, z^2], + ....: domain=P) sage: Q = P([1, 1, 1]) sage: Q.is_preperiodic(f) True :: + sage: # needs sage.rings.number_field sage.schemes sage.symbolic sage: set_verbose(-1) - sage: P.<x,y,z> = ProjectiveSpace(QQbar,2) + sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2) sage: f = DynamicalSystem_projective([x^2, y^2, z^2], domain=P) sage: Q = P([QQbar(sqrt(-1)), 1, 1]) sage: Q.is_preperiodic(f) @@ -983,24 +1021,24 @@ def is_preperiodic(self, f, err=0.1, return_period=False): :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem_projective([16*x^2-29*y^2, 16*y^2], domain=P) + sage: f = DynamicalSystem_projective([16*x^2 - 29*y^2, 16*y^2], domain=P) # needs sage.schemes sage: Q = P(-1,4) - sage: Q.is_preperiodic(f) + sage: Q.is_preperiodic(f) # needs sage.libs.singular sage.schemes True :: - sage: P.<x,y,z> =ProjectiveSpace(GF(3), 2) - sage: F = DynamicalSystem([x^2 - 2*y^2, y^2, z^2]) + sage: P.<x,y,z> = ProjectiveSpace(GF(3), 2) + sage: F = DynamicalSystem([x^2 - 2*y^2, y^2, z^2]) # needs sage.schemes sage: Q = P(1, 1, 1) - sage: Q.is_preperiodic(F, return_period=True) + sage: Q.is_preperiodic(F, return_period=True) # needs sage.schemes (1, 1) TESTS:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = End(P) - sage: f = H([16*x^2-29*y^2, 16*y^2]) + sage: f = H([16*x^2 - 29*y^2, 16*y^2]) sage: Q = P(-1,4) sage: Q.is_preperiodic(f) Traceback (most recent call last): @@ -1010,9 +1048,9 @@ def is_preperiodic(self, f, err=0.1, return_period=False): :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: f = DynamicalSystem_projective([16*x^2-29*y^2, 16*y^2]) + sage: f = DynamicalSystem_projective([16*x^2 - 29*y^2, 16*y^2]) # needs sage.schemes sage: Q = P(11,4) - sage: Q.is_preperiodic(f, err=2) + sage: Q.is_preperiodic(f, err=2) # needs sage.libs.singular sage.schemes False """ try: @@ -1064,25 +1102,26 @@ def __init__(self, X, v, check=True): sage: P(0, 0, 0, 0) Traceback (most recent call last): ... - ValueError: [0, 0, 0, 0] does not define a point in Projective Space of dimension 3 over Rational Field since all entries are zero + ValueError: [0, 0, 0, 0] does not define a point in Projective Space of dimension 3 + over Rational Field since all entries are zero :: sage: P.<x, y, z> = ProjectiveSpace(2, QQ) - sage: X = P.subscheme([x^2-y*z]) + sage: X = P.subscheme([x^2 - y*z]) sage: X([2, 2, 2]) (1 : 1 : 1) :: sage: P = ProjectiveSpace(1, GF(7)) - sage: Q=P([2, 1]) + sage: Q = P([2, 1]) sage: Q[0].parent() Finite Field of size 7 :: - sage: P = ProjectiveSpace(QQ,1) + sage: P = ProjectiveSpace(QQ, 1) sage: P.point(Infinity) (1 : 0) sage: P(infinity) @@ -1090,7 +1129,7 @@ def __init__(self, X, v, check=True): :: - sage: P = ProjectiveSpace(QQ,2) + sage: P = ProjectiveSpace(QQ, 2) sage: P(infinity) Traceback (most recent call last): ... @@ -1114,9 +1153,9 @@ def __init__(self, X, v, check=True): except AttributeError: pass if not isinstance(v, (list,tuple)): - raise TypeError("argument v (= %s) must be a scheme point, list, or tuple"%str(v)) + raise TypeError("argument v (= %s) must be a scheme point, list, or tuple" % str(v)) if len(v) != d and len(v) != d-1: - raise TypeError("v (=%s) must have %s components"%(v, d)) + raise TypeError("v (=%s) must have %s components" % (v, d)) R = X.value_ring() v = Sequence(v, R) @@ -1169,7 +1208,7 @@ def normalize_coordinates(self): EXAMPLES:: - sage: P.<x,y,z> = ProjectiveSpace(GF(5),2) + sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2) sage: Q = P.point([GF(5)(1), GF(5)(3), GF(5)(0)], False); Q (1 : 3 : 0) sage: Q.normalize_coordinates(); Q @@ -1178,7 +1217,7 @@ def normalize_coordinates(self): :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: X = P.subscheme(x^2-y^2); + sage: X = P.subscheme(x^2 - y^2); sage: Q = X.point([23, 23, 46], False); Q (23 : 23 : 46) sage: Q.normalize_coordinates(); Q @@ -1200,23 +1239,26 @@ def _number_field_from_algebraics(self): EXAMPLES:: + sage: # needs sage.rings.number_field sage.symbolic sage: R.<x> = PolynomialRing(QQ) - sage: P.<x,y> = ProjectiveSpace(QQbar,1) + sage: P.<x,y> = ProjectiveSpace(QQbar, 1) sage: Q = P([-1/2*QQbar(sqrt(2)) + QQbar(I), 1]) sage: S = Q._number_field_from_algebraics(); S (1/2*a^3 + a^2 - 1/2*a : 1) sage: S.codomain() - Projective Space of dimension 1 over Number Field in a with defining polynomial y^4 + 1 with a = 0.7071067811865475? + 0.7071067811865475?*I + Projective Space of dimension 1 over Number Field in a with defining + polynomial y^4 + 1 with a = 0.7071067811865475? + 0.7071067811865475?*I The following was fixed in :trac:`23808`:: + sage: # needs sage.rings.number_field sage.symbolic sage: R.<x> = PolynomialRing(QQ) - sage: P.<x,y> = ProjectiveSpace(QQbar,1) + sage: P.<x,y> = ProjectiveSpace(QQbar, 1) sage: Q = P([-1/2*QQbar(sqrt(2)) + QQbar(I), 1]);Q (-0.7071067811865475? + 1*I : 1) sage: S = Q._number_field_from_algebraics(); S (1/2*a^3 + a^2 - 1/2*a : 1) - sage: T = S.change_ring(QQbar) # Used to fail + sage: T = S.change_ring(QQbar) # Used to fail sage: T (-0.7071067811865475? + 1.000000000000000?*I : 1) sage: Q[0] == T[0] @@ -1257,6 +1299,7 @@ def clear_denominators(self): :: + sage: # needs sage.rings.number_field sage: R.<x> = PolynomialRing(QQ) sage: K.<w> = NumberField(x^2 - 3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) @@ -1267,8 +1310,8 @@ def clear_denominators(self): :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: X = P.subscheme(x^2 - y^2); - sage: Q = X([1/2, 1/2, 1]); + sage: X = P.subscheme(x^2 - y^2) + sage: Q = X([1/2, 1/2, 1]) sage: Q.clear_denominators(); Q (1 : 1 : 2) @@ -1301,13 +1344,13 @@ def intersection_multiplicity(self, X): sage: X = P.subscheme([x*z - y^2]) sage: Y = P.subscheme([x^3 - y*w^2 + z*w^2, x*y - z*w]) sage: Q1 = X([1/2, 1/4, 1/8, 1]) - sage: Q1.intersection_multiplicity(Y) + sage: Q1.intersection_multiplicity(Y) # needs sage.libs.singular 1 sage: Q2 = X([0,0,0,1]) - sage: Q2.intersection_multiplicity(Y) + sage: Q2.intersection_multiplicity(Y) # needs sage.libs.singular 5 sage: Q3 = X([0,0,1,0]) - sage: Q3.intersection_multiplicity(Y) + sage: Q3.intersection_multiplicity(Y) # needs sage.libs.singular 6 :: @@ -1339,10 +1382,10 @@ def multiplicity(self): sage: P.<x,y,z,w,t> = ProjectiveSpace(QQ, 4) sage: X = P.subscheme([y^6 - x^3*w^2*t + t^5*w, x^2 - t^2]) sage: Q1 = X([1,0,2,1,1]) - sage: Q1.multiplicity() + sage: Q1.multiplicity() # needs sage.libs.singular 1 sage: Q2 = X([0,0,-2,1,0]) - sage: Q2.multiplicity() + sage: Q2.multiplicity() # needs sage.libs.singular 8 """ from sage.schemes.projective.projective_space import is_ProjectiveSpace @@ -1379,8 +1422,8 @@ def __hash__(self): :: - sage: P.<x,y> = ProjectiveSpace(GF(13^3,'t'), 1) - sage: hash(P(3, 4)) + sage: P.<x,y> = ProjectiveSpace(GF(13^3,'t'), 1) # needs sage.rings.finite_rings + sage: hash(P(3, 4)) # needs sage.rings.finite_rings 2201 """ p = self.codomain().base_ring().order() @@ -1396,6 +1439,7 @@ class SchemeMorphism_point_abelian_variety_field(AdditiveGroupElement, SchemeMor EXAMPLES:: + sage: # needs sage.schemes sage: E = EllipticCurve([0,0,1,-1,0]) sage: origin = E(0) sage: origin.domain() diff --git a/src/sage/schemes/projective/projective_rational_point.py b/src/sage/schemes/projective/projective_rational_point.py index 738f28cb993..0525883886d 100644 --- a/src/sage/schemes/projective/projective_rational_point.py +++ b/src/sage/schemes/projective/projective_rational_point.py @@ -15,8 +15,8 @@ Projective, over `\QQ`:: sage: from sage.schemes.projective.projective_rational_point import enum_projective_rational_field - sage: P.<X,Y,Z> = ProjectiveSpace(2,QQ) - sage: C = P.subscheme([X+Y-Z]) + sage: P.<X,Y,Z> = ProjectiveSpace(2, QQ) + sage: C = P.subscheme([X + Y - Z]) sage: enum_projective_rational_field(C, 3) [(-2 : 3 : 1), (-1 : 1 : 0), (-1 : 2 : 1), (-1/2 : 3/2 : 1), (0 : 1 : 1), (1/3 : 2/3 : 1), (1/2 : 1/2 : 1), (2/3 : 1/3 : 1), @@ -26,8 +26,8 @@ Projective over a finite field:: sage: from sage.schemes.projective.projective_rational_point import enum_projective_finite_field - sage: E = EllipticCurve('72').change_ring(GF(19)) - sage: enum_projective_finite_field(E) + sage: E = EllipticCurve('72').change_ring(GF(19)) # needs sage.schemes + sage: enum_projective_finite_field(E) # needs sage.schemes [(0 : 1 : 0), (1 : 0 : 1), (3 : 0 : 1), (4 : 9 : 1), (4 : 10 : 1), (6 : 6 : 1), (6 : 13 : 1), (7 : 6 : 1), (7 : 13 : 1), (9 : 4 : 1), (9 : 15 : 1), (12 : 8 : 1), (12 : 11 : 1), (13 : 8 : 1), (13 : 11 : 1), @@ -45,23 +45,22 @@ - Raghukul Raman <raghukul.raman01@gmail.com> (2018): Added sieve algorithm """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 William Stein, David Kohel, John Cremona, Charlie Turner # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** +from itertools import product from sage.arith.misc import gcd, next_prime, previous_prime, crt from sage.arith.srange import srange from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from sage.misc.mrange import cartesian_product_iterator from sage.misc.misc_c import prod from sage.misc.mrange import xmrange from sage.schemes.generic.scheme import is_Scheme @@ -89,7 +88,7 @@ def enum_projective_rational_field(X, B): EXAMPLES:: sage: P.<X,Y,Z> = ProjectiveSpace(2, QQ) - sage: C = P.subscheme([X+Y-Z]) + sage: C = P.subscheme([X + Y - Z]) sage: from sage.schemes.projective.projective_rational_point import enum_projective_rational_field sage: enum_projective_rational_field(C(QQ), 6) [(-5 : 6 : 1), (-4 : 5 : 1), (-3 : 4 : 1), (-2 : 3 : 1), @@ -110,15 +109,15 @@ def enum_projective_rational_field(X, B): sage: P3.<W,X,Y,Z> = ProjectiveSpace(3, QQ) sage: enum_projective_rational_field(P3, 1) [(-1 : -1 : -1 : 1), (-1 : -1 : 0 : 1), (-1 : -1 : 1 : 0), (-1 : -1 : 1 : 1), - (-1 : 0 : -1 : 1), (-1 : 0 : 0 : 1), (-1 : 0 : 1 : 0), (-1 : 0 : 1 : 1), - (-1 : 1 : -1 : 1), (-1 : 1 : 0 : 0), (-1 : 1 : 0 : 1), (-1 : 1 : 1 : 0), - (-1 : 1 : 1 : 1), (0 : -1 : -1 : 1), (0 : -1 : 0 : 1), (0 : -1 : 1 : 0), - (0 : -1 : 1 : 1), (0 : 0 : -1 : 1), (0 : 0 : 0 : 1), (0 : 0 : 1 : 0), - (0 : 0 : 1 : 1), (0 : 1 : -1 : 1), (0 : 1 : 0 : 0), (0 : 1 : 0 : 1), - (0 : 1 : 1 : 0), (0 : 1 : 1 : 1), (1 : -1 : -1 : 1), (1 : -1 : 0 : 1), - (1 : -1 : 1 : 0), (1 : -1 : 1 : 1), (1 : 0 : -1 : 1), (1 : 0 : 0 : 0), - (1 : 0 : 0 : 1), (1 : 0 : 1 : 0), (1 : 0 : 1 : 1), (1 : 1 : -1 : 1), - (1 : 1 : 0 : 0), (1 : 1 : 0 : 1), (1 : 1 : 1 : 0), (1 : 1 : 1 : 1)] + (-1 : 0 : -1 : 1), (-1 : 0 : 0 : 1), (-1 : 0 : 1 : 0), (-1 : 0 : 1 : 1), + (-1 : 1 : -1 : 1), (-1 : 1 : 0 : 0), (-1 : 1 : 0 : 1), (-1 : 1 : 1 : 0), + (-1 : 1 : 1 : 1), (0 : -1 : -1 : 1), (0 : -1 : 0 : 1), (0 : -1 : 1 : 0), + (0 : -1 : 1 : 1), (0 : 0 : -1 : 1), (0 : 0 : 0 : 1), (0 : 0 : 1 : 0), + (0 : 0 : 1 : 1), (0 : 1 : -1 : 1), (0 : 1 : 0 : 0), (0 : 1 : 0 : 1), + (0 : 1 : 1 : 0), (0 : 1 : 1 : 1), (1 : -1 : -1 : 1), (1 : -1 : 0 : 1), + (1 : -1 : 1 : 0), (1 : -1 : 1 : 1), (1 : 0 : -1 : 1), (1 : 0 : 0 : 0), + (1 : 0 : 0 : 1), (1 : 0 : 1 : 0), (1 : 0 : 1 : 1), (1 : 1 : -1 : 1), + (1 : 1 : 0 : 0), (1 : 1 : 0 : 1), (1 : 1 : 1 : 0), (1 : 1 : 1 : 1)] ALGORITHM: @@ -140,7 +139,7 @@ def enum_projective_rational_field(X, B): n = X.codomain().ambient_space().ngens() zero = (0,) * n pts = [] - for c in cartesian_product_iterator([srange(-B,B+1) for _ in range(n)]): + for c in product(*[srange(-B, B + 1) for _ in range(n)]): if gcd(c) == 1 and c > zero: try: pts.append(X(c)) @@ -185,9 +184,10 @@ def enum_projective_number_field(X, **kwds): EXAMPLES:: + sage: # needs sage.rings.number_field sage: from sage.schemes.projective.projective_rational_point import enum_projective_number_field sage: u = QQ['u'].0 - sage: K = NumberField(u^3 - 5,'v') + sage: K = NumberField(u^3 - 5, 'v') sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: X = P.subscheme([x - y]) sage: enum_projective_number_field(X(K), bound=RR(5^(1/3)), prec=2^10) @@ -195,11 +195,11 @@ def enum_projective_number_field(X, **kwds): :: + sage: # needs sage.rings.number_field sage: u = QQ['u'].0 sage: K = NumberField(u^2 + 3, 'v') - sage: A.<x,y> = ProjectiveSpace(K,1) - sage: X = A.subscheme(x-y) - sage: from sage.schemes.projective.projective_rational_point import enum_projective_number_field + sage: A.<x,y> = ProjectiveSpace(K, 1) + sage: X = A.subscheme(x - y) sage: enum_projective_number_field(X, bound=2) [(1 : 1)] """ @@ -244,35 +244,36 @@ def enum_projective_finite_field(X): EXAMPLES:: - sage: F = GF(53) - sage: P.<X,Y,Z> = ProjectiveSpace(2,F) sage: from sage.schemes.projective.projective_rational_point import enum_projective_finite_field + sage: F = GF(53) + sage: P.<X,Y,Z> = ProjectiveSpace(2, F) sage: len(enum_projective_finite_field(P(F))) 2863 - sage: 53^2+53+1 + sage: 53^2 + 53 + 1 2863 :: - sage: F = GF(9,'a') + sage: # needs sage.rings.finite_rings + sage: F = GF(9, 'a') sage: P.<X,Y,Z> = ProjectiveSpace(2,F) - sage: C = Curve(X^3-Y^3+Z^2*Y) - sage: enum_projective_finite_field(C(F)) + sage: C = Curve(X^3 - Y^3 + Z^2*Y) # needs sage.schemes + sage: enum_projective_finite_field(C(F)) # needs sage.schemes [(0 : 0 : 1), (0 : 1 : 1), (0 : 2 : 1), (1 : 1 : 0), (a + 1 : 2*a : 1), - (a + 1 : 2*a + 1 : 1), (a + 1 : 2*a + 2 : 1), (2*a + 2 : a : 1), - (2*a + 2 : a + 1 : 1), (2*a + 2 : a + 2 : 1)] + (a + 1 : 2*a + 1 : 1), (a + 1 : 2*a + 2 : 1), (2*a + 2 : a : 1), + (2*a + 2 : a + 1 : 1), (2*a + 2 : a + 2 : 1)] :: sage: F = GF(5) - sage: P2F.<X,Y,Z> = ProjectiveSpace(2,F) + sage: P2F.<X,Y,Z> = ProjectiveSpace(2, F) sage: enum_projective_finite_field(P2F) [(0 : 0 : 1), (0 : 1 : 0), (0 : 1 : 1), (0 : 2 : 1), (0 : 3 : 1), (0 : 4 : 1), - (1 : 0 : 0), (1 : 0 : 1), (1 : 1 : 0), (1 : 1 : 1), (1 : 2 : 1), (1 : 3 : 1), - (1 : 4 : 1), (2 : 0 : 1), (2 : 1 : 0), (2 : 1 : 1), (2 : 2 : 1), (2 : 3 : 1), - (2 : 4 : 1), (3 : 0 : 1), (3 : 1 : 0), (3 : 1 : 1), (3 : 2 : 1), (3 : 3 : 1), - (3 : 4 : 1), (4 : 0 : 1), (4 : 1 : 0), (4 : 1 : 1), (4 : 2 : 1), (4 : 3 : 1), - (4 : 4 : 1)] + (1 : 0 : 0), (1 : 0 : 1), (1 : 1 : 0), (1 : 1 : 1), (1 : 2 : 1), (1 : 3 : 1), + (1 : 4 : 1), (2 : 0 : 1), (2 : 1 : 0), (2 : 1 : 1), (2 : 2 : 1), (2 : 3 : 1), + (2 : 4 : 1), (3 : 0 : 1), (3 : 1 : 0), (3 : 1 : 1), (3 : 2 : 1), (3 : 3 : 1), + (3 : 4 : 1), (4 : 0 : 1), (4 : 1 : 0), (4 : 1 : 1), (4 : 2 : 1), (4 : 3 : 1), + (4 : 4 : 1)] ALGORITHM: @@ -294,29 +295,28 @@ def enum_projective_finite_field(X): elif not is_ProjectiveSpace(X.codomain().ambient_space()): raise TypeError("codomain must be projective space over a finite field") - n = X.codomain().ambient_space().ngens()-1 + n = X.codomain().ambient_space().ngens() - 1 F = X.value_ring() pts = [] - for k in range(n+1): - for c in cartesian_product_iterator([F for _ in range(k)]): + for k in range(n + 1): + for c in product(*[F for _ in range(k)]): try: - pts.append(X(list(c)+[1]+[0]*(n-k))) + pts.append(X(list(c) + [1] + [0] * (n - k))) except TypeError: pass pts.sort() return pts - def sieve(X, bound): r""" Returns the list of all projective, rational points on scheme ``X`` of height up to ``bound``. - Height of a projective point X = (x_1, x_2,..., x_n) is given by - H_X = max(y_1, y_2,..., y_n), where H_X is height of point X and y_i's - are the normalized coordinates such that all y_i are integers and - gcd(y_1, y_2,..., y_n) = 1. + Height of a projective point `X = (x_1, x_2,\dots, x_n)` is given by + `H_X = \max(y_1, y_2,\dots, y_n)`, where the values `y_i` + are the normalized coordinates such that all `y_i` are integers and + `\gcd(y_1, y_2,\dots, y_n) = 1`. ALGORITHM: @@ -343,17 +343,17 @@ def sieve(X, bound): EXAMPLES:: sage: from sage.schemes.projective.projective_rational_point import sieve - sage: P.<x,y,z,q>=ProjectiveSpace(QQ,3) - sage: Y=P.subscheme([x^2-3^2*y^2+z*q,x+z+4*q]) - sage: sorted(sieve(Y, 12)) # long time + sage: P.<x,y,z,q> = ProjectiveSpace(QQ, 3) + sage: Y = P.subscheme([x^2 - 3^2*y^2 + z*q, x + z + 4*q]) + sage: sorted(sieve(Y, 12)) # long time # needs sage.libs.singular [(-4 : -4/3 : 0 : 1), (-4 : 4/3 : 0 : 1), (-1 : -1/3 : 1 : 0), (-1 : 1/3 : 1 : 0)] :: sage: from sage.schemes.projective.projective_rational_point import sieve - sage: E = EllipticCurve('37a') - sage: sorted(sieve(E, 14)) # long time + sage: E = EllipticCurve('37a') # needs sage.schemes + sage: sorted(sieve(E, 14)) # long time # needs sage.libs.singular sage.schemes [(-1 : -1 : 1), (-1 : 0 : 1), (0 : -1 : 1), (0 : 0 : 1), (0 : 1 : 0), (1/4 : -5/8 : 1), (1/4 : -3/8 : 1), (1 : -1 : 1), (1 : 0 : 1), @@ -364,9 +364,9 @@ def sieve(X, bound): Algorithm works even if coefficients are fraction:: sage: from sage.schemes.projective.projective_rational_point import sieve - sage: P.<x,y,z> = ProjectiveSpace(2,QQ) + sage: P.<x,y,z> = ProjectiveSpace(2, QQ) sage: X = P.subscheme(3*x - 3/2*y) - sage: sieve(X, 3) + sage: sieve(X, 3) # needs sage.libs.singular [(-1 : -2 : 1), (-1/2 : -1 : 1), (-1/3 : -2/3 : 1), (0 : 0 : 1), (1/3 : 2/3 : 1), (1/2 : 1 : 0), (1/2 : 1 : 1), (1 : 2 : 1)] """ @@ -445,7 +445,7 @@ def good_primes(B): best_size = 2 best_time = (N**2)*M[2][-1]**(N) + (N**5 * RR(prod(M[2])**dim_scheme / M[2][-1]) ) for i in range(2, max_length + 1): - current_time = (N**2)*M[i][-1]**(N) + (N**5 * RR(prod(M[i])**dim_scheme / M[i][-1]) ) + current_time = (N**2)*M[i][-1]**(N) + (N**5 * RR(prod(M[i])**dim_scheme / M[i][-1]) ) if current_time < best_time: best_size = i best_time = current_time diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 670304af237..622f9ef911c 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -24,11 +24,11 @@ sage: X = ProjectiveSpace(5)/QQ; X Projective Space of dimension 5 over Rational Field - sage: X/CC + sage: X/CC # needs sage.rings.real_mpfr Projective Space of dimension 5 over Complex Field with 53 bits of precision The third argument specifies the printing names of the generators of the -homogeneous coordinate ring. Using the method `.objgens()` you can obtain both +homogeneous coordinate ring. Using the method :meth:`objgens` you can obtain both the space and the generators as ready to use variables. :: sage: P2, vars = ProjectiveSpace(10, QQ, 't').objgens() @@ -55,11 +55,11 @@ :: - sage: V = P2.subscheme([x+y+z, x+y-z]); V + sage: V = P2.subscheme([x + y + z, x + y - z]); V Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x + y + z, - x + y - z - sage: V.dimension() + x + y + z, + x + y - z + sage: V.dimension() # needs sage.libs.singular 0 AUTHORS: @@ -76,18 +76,21 @@ # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** +from itertools import product from sage.arith.misc import gcd, binomial -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.rational_field import is_RationalField +from sage.rings.rational_field import QQ, is_RationalField +from sage.rings.fraction_field import FractionField +from sage.rings.number_field.order import Order from sage.categories.fields import Fields from sage.categories.rings import Rings @@ -96,7 +99,6 @@ from sage.categories.map import Map from sage.misc.latex import latex from sage.misc.misc_c import prod -from sage.misc.mrange import cartesian_product_iterator from sage.misc.persist import register_unpickle_override from sage.structure.category_object import normalize_names @@ -139,7 +141,7 @@ def is_ProjectiveSpace(x): sage: from sage.schemes.projective.projective_space import is_ProjectiveSpace sage: is_ProjectiveSpace(ProjectiveSpace(5, names='x')) True - sage: is_ProjectiveSpace(ProjectiveSpace(5, GF(9,'alpha'), names='x')) + sage: is_ProjectiveSpace(ProjectiveSpace(5, GF(9, 'alpha'), names='x')) # needs sage.rings.finite_rings True sage: is_ProjectiveSpace(Spec(ZZ)) False @@ -192,18 +194,17 @@ def ProjectiveSpace(n, R=None, names=None): :: - sage: ProjectiveSpace(3, Zp(5), 'y') + sage: ProjectiveSpace(3, Zp(5), 'y') # needs sage.rings.padics Projective Space of dimension 3 over 5-adic Ring with capped relative precision 20 :: - sage: ProjectiveSpace(2,QQ,'x,y,z') + sage: ProjectiveSpace(2, QQ, 'x,y,z') Projective Space of dimension 2 over Rational Field :: - sage: PS.<x,y>=ProjectiveSpace(1,CC) - sage: PS + sage: PS.<x,y> = ProjectiveSpace(1, CC); PS # needs sage.rings.real_mpfr Projective Space of dimension 1 over Complex Field with 53 bits of precision :: @@ -224,7 +225,7 @@ def ProjectiveSpace(n, R=None, names=None): TESTS:: - sage: R.<x,y>=QQ[] + sage: R.<x,y> = QQ[] sage: P.<z,w> = ProjectiveSpace(R) Traceback (most recent call last): ... @@ -232,7 +233,7 @@ def ProjectiveSpace(n, R=None, names=None): :: - sage: R.<x,y>=QQ[] + sage: R.<x,y> = QQ[] sage: P.<x,y> = ProjectiveSpace(R) sage: P.gens() == R.gens() True @@ -256,7 +257,7 @@ def ProjectiveSpace(n, R=None, names=None): if R is None: R = ZZ # default is the integers if R in _Fields: - if is_FiniteField(R): + if isinstance(R, FiniteField): return ProjectiveSpace_finite_field(n, R, names) if is_RationalField(R): return ProjectiveSpace_rational_field(n, R, names) @@ -335,7 +336,7 @@ def __init__(self, n, R=ZZ, names=None): EXAMPLES:: - sage: ProjectiveSpace(3, Zp(5), 'y') + sage: ProjectiveSpace(3, Zp(5), 'y') # needs sage.rings.padics Projective Space of dimension 3 over 5-adic Ring with capped relative precision 20 """ AmbientSpace.__init__(self, n, R) @@ -345,7 +346,7 @@ def ngens(self): """ Return the number of generators of this projective space. - This is the number of variables in the coordinate ring of self. + This is the number of variables in the coordinate ring of ``self``. EXAMPLES:: @@ -358,8 +359,8 @@ def ngens(self): def _check_satisfies_equations(self, v): """ - Return True if ``v`` defines a point on the scheme; raise a - TypeError otherwise. + Return ``True`` if ``v`` defines a point on the scheme; raise a + :class:`TypeError` otherwise. EXAMPLES:: @@ -417,7 +418,7 @@ def coordinate_ring(self): EXAMPLES:: - sage: ProjectiveSpace(3, GF(19^2,'alpha'), 'abcd').coordinate_ring() + sage: ProjectiveSpace(3, GF(19^2,'alpha'), 'abcd').coordinate_ring() # needs sage.rings.finite_rings Multivariate Polynomial Ring in a, b, c, d over Finite Field in alpha of size 19^2 :: @@ -588,7 +589,7 @@ def _latex_(self): TESTS:: - sage: ProjectiveSpace(3, Zp(5), 'y')._latex_() + sage: ProjectiveSpace(3, Zp(5), 'y')._latex_() # needs sage.rings.padics '{\\mathbf P}_{\\Bold{Z}_{5}}^3' """ return "{\\mathbf P}_{%s}^%s" % (latex(self.base_ring()), @@ -604,7 +605,7 @@ def _linear_system_as_kernel(self, d, pt, m): - ``d`` -- a nonnegative integer. - - ``pt`` -- a point of self (possibly represented by a list with at \ + - ``pt`` -- a point of ``self`` (possibly represented by a list with at \ least one component equal to 1). - ``m`` -- a nonnegative integer. @@ -612,8 +613,8 @@ def _linear_system_as_kernel(self, d, pt, m): OUTPUT: A matrix of size `\binom{m-1+n}{n}` x `\binom{d+n}{n}` where n is the - relative dimension of self. The base ring of the matrix is a ring that - contains the base ring of self and the coefficients of the given point. + relative dimension of ``self``. The base ring of the matrix is a ring that + contains the base ring of ``self`` and the coefficients of the given point. EXAMPLES: @@ -622,7 +623,7 @@ def _linear_system_as_kernel(self, d, pt, m): sage: P = ProjectiveSpace(GF(5), 2, names='x') sage: pt = P([1, 1, 1]) - sage: P._linear_system_as_kernel(0, pt, 3) + sage: P._linear_system_as_kernel(0, pt, 3) # needs sage.modules [1] [0] [0] @@ -635,8 +636,8 @@ def _linear_system_as_kernel(self, d, pt, m): sage: P = ProjectiveSpace(GF(5), 2, names='x') sage: pt = P([1, 1, 1]) - sage: M = P._linear_system_as_kernel(2, pt, 0) - sage: [M.nrows(), M.ncols()] + sage: M = P._linear_system_as_kernel(2, pt, 0) # needs sage.modules + sage: [M.nrows(), M.ncols()] # needs sage.modules [0, 6] The base ring does not need to be a field or even an integral domain. @@ -645,7 +646,7 @@ def _linear_system_as_kernel(self, d, pt, m): sage: R = Zmod(4) sage: P = ProjectiveSpace(R, 2, names='x') sage: pt = [R(1), R(3), R(0)] - sage: P._linear_system_as_kernel(3, pt, 2) + sage: P._linear_system_as_kernel(3, pt, 2) # needs sage.modules [1 3 0 1 0 0 3 0 0 0] [0 1 0 2 0 0 3 0 0 0] [0 0 1 0 3 0 0 1 0 0] @@ -657,11 +658,10 @@ def _linear_system_as_kernel(self, d, pt, m): sage: R = GF(5) sage: P = ProjectiveSpace(R, 2, names='x') sage: pt = [R(3), R(3), R(0)] - sage: P._linear_system_as_kernel(3, pt, 2) + sage: P._linear_system_as_kernel(3, pt, 2) # needs sage.modules Traceback (most recent call last): ... - TypeError: at least one component of pt=[3, 3, 0] must be equal - to 1 + TypeError: at least one component of pt=[3, 3, 0] must be equal to 1 The components of the list do not have to be elements of the base ring of the projective space. It suffices if there exists a common parent. @@ -669,10 +669,10 @@ def _linear_system_as_kernel(self, d, pt, m): hypersurfaces of degree 2 in 3-space with multiplicity at least 2 at a general point in the third affine patch:: - sage: P = ProjectiveSpace(QQ,3,names='x') - sage: RPol.<t0,t1,t2,t3> = PolynomialRing(QQ,4) + sage: P = ProjectiveSpace(QQ, 3, names='x') + sage: RPol.<t0,t1,t2,t3> = PolynomialRing(QQ, 4) sage: pt = [t0,t1,1,t3] - sage: P._linear_system_as_kernel(2,pt,2) + sage: P._linear_system_as_kernel(2, pt, 2) # needs sage.modules [ 2*t0 t1 1 t3 0 0 0 0 0 0] [ 0 t0 0 0 2*t1 1 t3 0 0 0] [ t0^2 t0*t1 t0 t0*t3 t1^2 t1 t1*t3 1 t3 t3^2] @@ -846,7 +846,7 @@ def _repr_(self): TESTS:: - sage: ProjectiveSpace(3, Zp(5), 'y')._repr_() + sage: ProjectiveSpace(3, Zp(5), 'y')._repr_() # needs sage.rings.padics 'Projective Space of dimension 3 over 5-adic Ring with capped relative precision 20' """ return "Projective Space of dimension %s over %s" % (self.dimension_relative(), self.base_ring()) @@ -862,7 +862,7 @@ def _repr_generic_point(self, v=None): EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) - sage: P._repr_generic_point([z*y-x^2]) + sage: P._repr_generic_point([z*y - x^2]) '(-x^2 + y*z)' sage: P._repr_generic_point() '(x : y : z)' @@ -882,7 +882,7 @@ def _latex_generic_point(self, v=None): EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) - sage: P._latex_generic_point([z*y-x^2]) + sage: P._latex_generic_point([z*y - x^2]) '\\left(-x^{2} + y z\\right)' sage: P._latex_generic_point() '\\left(x : y : z\\right)' @@ -919,9 +919,9 @@ def change_ring(self, R): :: - sage: K.<w> = QuadraticField(2) - sage: P = ProjectiveSpace(K,2,'t') - sage: P.change_ring(K.embeddings(QQbar)[0]) + sage: K.<w> = QuadraticField(2) # needs sage.rings.number_field + sage: P = ProjectiveSpace(K, 2, 't') # needs sage.rings.number_field + sage: P.change_ring(K.embeddings(QQbar)[0]) # needs sage.rings.number_field Projective Space of dimension 2 over Algebraic Field """ if isinstance(R, Map): @@ -961,10 +961,11 @@ def subscheme(self, X): sage: X.defining_polynomials () (x*z^2, y^2*z, x*y^2) sage: I = X.defining_ideal(); I - Ideal (x*z^2, y^2*z, x*y^2) of Multivariate Polynomial Ring in x, y, z over Rational Field - sage: I.groebner_basis() + Ideal (x*z^2, y^2*z, x*y^2) of Multivariate Polynomial Ring in x, y, z + over Rational Field + sage: I.groebner_basis() # needs sage.libs.singular [x*y^2, y^2*z, x*z^2] - sage: X.dimension() + sage: X.dimension() # needs sage.libs.singular 0 sage: X.base_ring() Rational Field @@ -972,13 +973,13 @@ def subscheme(self, X): Spectrum of Rational Field sage: X.structure_morphism() Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x*z^2, - y^2*z, - x*y^2 + From: Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: x*z^2, y^2*z, x*y^2 To: Spectrum of Rational Field Defn: Structure map + TESTS:: + sage: TestSuite(X).run(skip=["_test_an_element", "_test_elements",\ "_test_elements_eq", "_test_some_elements", "_test_elements_eq_reflexive",\ "_test_elements_eq_symmetric", "_test_elements_eq_transitive",\ @@ -992,20 +993,250 @@ def subscheme(self, X): return AlgebraicScheme_subscheme_projective(self, X) + def points_of_bounded_height(self, **kwds): + r""" + Return an iterator of the points in ``self`` of absolute multiplicative + height of at most the given bound. + + ALGORITHM: + + This is an implementation of Algorithm 6 in [Krumm2016]_. + + INPUT: + + kwds: + + - ``bound`` - a real number + + - ``precision`` - (default: 53) a positive integer + + OUTPUT: + + - an iterator of points of bounded height + + EXAMPLES:: + + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: sorted(list(P.points_of_bounded_height(bound=2))) + [(-2 : 1), (-1 : 1), (-1/2 : 1), (0 : 1), + (1/2 : 1), (1 : 0), (1 : 1), (2 : 1)] + + :: + + sage: u = QQ['u'].0 + sage: P.<x,y,z> = ProjectiveSpace(NumberField(u^2 - 2, 'v'), 2) # needs sage.rings.number_field + sage: len(list(P.points_of_bounded_height(bound=2))) # needs sage.rings.number_field + 265 + + :: + + sage: # needs sage.rings.number_field + sage: CF.<a> = CyclotomicField(3) + sage: R.<x> = CF[] + sage: L.<l> = CF.extension(x^3 + 2) + sage: Q.<x,y> = ProjectiveSpace(L, 1) + sage: sorted(list(Q.points_of_bounded_height(bound=1))) + [(0 : 1), (1 : 0), (a + 1 : 1), (a : 1), + (-1 : 1), (-a - 1 : 1), (-a : 1), (1 : 1)] + + :: + + sage: # needs sage.rings.number_field + sage: R.<x> = QQ[] + sage: F.<a> = NumberField(x^4 - 8*x^2 + 3) + sage: P.<x,y,z> = ProjectiveSpace(F, 2) + sage: all(exp(p.global_height()) <= 1 # needs sage.symbolic + ....: for p in P.points_of_bounded_height(bound=1)) + True + + :: + + sage: K.<a> = CyclotomicField(3) # needs sage.rings.number_field + sage: P.<x,y,z> = ProjectiveSpace(K, 2) # needs sage.rings.number_field + sage: len(list(P.points_of_bounded_height(bound=1))) # needs sage.rings.number_field + 57 + + :: + + sage: u = QQ['u'].0 + sage: K.<k> = NumberField(u^2 - 2) # needs sage.rings.number_field + sage: P.<x,y> = ProjectiveSpace(K, 1) # needs sage.rings.number_field + sage: len(list(P.points_of_bounded_height(bound=2))) # needs sage.rings.number_field + 24 + + :: + + sage: R.<x> = QQ[] + sage: K.<k> = NumberField(x^4 - 8*x^2 + 3) # needs sage.rings.number_field + sage: P.<x,y> = ProjectiveSpace(K, 1) # needs sage.rings.number_field + sage: len(list(P.points_of_bounded_height(bound=2))) # needs sage.rings.number_field + 108 + + :: + + sage: # needs sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<v> = NumberField(x^5 + x^3 + 1) + sage: P.<x,y,z> = ProjectiveSpace(K, 2) + sage: L = P.points_of_bounded_height(bound=1.2) + sage: len(list(L)) + 109 + + :: + + sage: # needs sage.rings.number_field + sage: K.<v> = QuadraticField(2) + sage: P.<x,y> = ProjectiveSpace(K, 1) + sage: sorted(list(P.points_of_bounded_height(bound=2))) + [(-v - 2 : 1), (-v - 1 : 1), (-2 : 1), (-1/2*v - 1 : 1), (-v : 1), (-1 : 1), + (-1/2*v : 1), (v - 2 : 1), (-1/2 : 1), (-v + 1 : 1), (1/2*v - 1 : 1), (0 : 1), + (-1/2*v + 1 : 1), (v - 1 : 1), (1/2 : 1), (-v + 2 : 1), (1/2*v : 1), (1 : 0), + (1 : 1), (v : 1), (1/2*v + 1 : 1), (2 : 1), (v + 1 : 1), (v + 2 : 1)] + + :: + + sage: # needs sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(3*x^2 + 1) + sage: P.<z,w> = ProjectiveSpace(K, 1) + sage: sorted(list(P.points_of_bounded_height(bound=1))) + [(-1 : 1), (-3/2*a - 1/2 : 1), (3/2*a - 1/2 : 1), (0 : 1), + (-3/2*a + 1/2 : 1), (3/2*a + 1/2 : 1), (1 : 0), (1 : 1)] + + :: + + sage: # needs sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(3*x^2 + 1) + sage: O = K.maximal_order() + sage: P.<z,w> = ProjectiveSpace(O, 1) + sage: len(sorted(list(P.points_of_bounded_height(bound=2)))) + 44 + + :: + + sage: # needs sage.rings.number_field + sage: R.<x> = QQ[] + sage: K.<a> = NumberField(x^3 - 7) + sage: O = K.maximal_order() + sage: P.<z,w> = ProjectiveSpace(O, 1) + sage: len(sorted(list(P.points_of_bounded_height(bound=2)))) + 28 + + :: + + sage: P.<w,z> = ProjectiveSpace(ZZ, 1) + sage: sorted(list(P.points_of_bounded_height(bound=2))) + [(-2 : -1), (-2 : 1), (-1 : -2), (-1 : -1), + (-1 : 0), (-1 : 1), (-1 : 2), (0 : -1)] + + :: + + sage: R.<x> = QQ[] + sage: P.<z,w> = ProjectiveSpace(R, 1) + sage: P.points_of_bounded_height(bound=2) + Traceback (most recent call last): + ... + NotImplementedError: self must be a projective space over + a number field or a ring of integers + + :: + + sage: # needs sage.rings.number_field + sage: K.<i> = NumberField(x^2 + 1) + sage: PK.<t> = K[] + sage: L.<a> = K.extension(t^4 - i) + sage: P.<z,w> = ProjectiveSpace(L, 1) + sage: sorted(list(P.points_of_bounded_height(bound=1))) + [(0 : 1), (1 : 0), (a : 1), (a^2 : 1), (a^3 : 1), (i : 1), + (i*a : 1), (i*a^2 : 1), (i*a^3 : 1), (-1 : 1), (-a : 1), (-a^2 : 1), + (-a^3 : 1), (-i : 1), (-i*a : 1), (-i*a^2 : 1), (-i*a^3 : 1), (1 : 1)] + """ + from sage.schemes.projective.proj_bdd_height import ( + ZZ_points_of_bounded_height, + QQ_points_of_bounded_height, + IQ_points_of_bounded_height, + points_of_bounded_height + ) + + R = self.base_ring() + + # Check the base ring is the rational field, a number field, + # or the ring of integers + is_ring_of_ints = False + + if is_RationalField(R): + field_type = False + elif R in NumberFields(): + # True for the rational field as well, so check is_RationalField first + field_type = True + elif (R is ZZ) or (isinstance(R, Order) and R.is_integrally_closed()): # Ensure ring of integers / maximal order + is_ring_of_ints = True + else: + raise NotImplementedError("self must be a projective space over a number field or a ring of integers") + + bound = kwds.pop('bound') + prec = kwds.pop('precision', 53) + + # Convert between absolute and relative height for calling Krumm's algorithm + bound = bound**R.absolute_degree() + + dim = self.dimension_relative() + + # When R is the ring of integers + if is_ring_of_ints: + fraction_field = FractionField(R) + + # Field of fraction is the rational field + if fraction_field == QQ: + return ZZ_points_of_bounded_height(self, dim, bound) + + # Field of fraction is a number field + r1, r2 = fraction_field.signature() + r = r1 + r2 - 1 + + if fraction_field.is_relative(): + deg = fraction_field.relative_degree() + else: + deg = fraction_field.degree() + + if deg == 2 and r == 0: + return IQ_points_of_bounded_height(self, fraction_field, dim, bound) + + return points_of_bounded_height(self, fraction_field, dim, bound, prec) + + # When R is a field + if field_type: + # For checking whether R is imaginary quadratic field + r1, r2 = R.signature() + r = r1 + r2 - 1 + + if R.is_relative(): + deg = R.relative_degree() + else: + deg = R.degree() + + if deg == 2 and r == 0: + return IQ_points_of_bounded_height(self, R, dim, bound) + + return points_of_bounded_height(self, R, dim, bound, prec) + else: + return QQ_points_of_bounded_height(self, dim, bound) + def affine_patch(self, i, AA=None): r""" Return the `i^{th}` affine patch of this projective space. This is an ambient affine space `\mathbb{A}^n_R,` where - `R` is the base ring of self, whose "projective embedding" + `R` is the base ring of ``self``, whose "projective embedding" map is `1` in the `i^{th}` factor. INPUT: - - ``i`` -- integer between 0 and dimension of self, inclusive. + - ``i`` -- integer between 0 and dimension of ``self``, inclusive. - ``AA`` -- (default: None) ambient affine space, this is constructed - if it is not given. + if it is not given. OUTPUT: @@ -1032,7 +1263,7 @@ def affine_patch(self, i, AA=None): :: - sage: P.<x,y> = ProjectiveSpace(QQ,1) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: P.affine_patch(0).projective_embedding(0).codomain() == P True """ @@ -1101,9 +1332,9 @@ def Lattes_map(self, E, m): EXAMPLES:: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: E = EllipticCurve(QQ,[-1, 0]) - sage: P.Lattes_map(E, 2) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: E = EllipticCurve(QQ,[-1, 0]) # needs sage.schemes + sage: P.Lattes_map(E, 2) # needs sage.schemes Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (1/4*x^4 + 1/2*x^2*y^2 + 1/4*y^4 : x^3*y - x*y^3) @@ -1111,8 +1342,8 @@ def Lattes_map(self, E, m): TESTS:: sage: P.<x,y> = ProjectiveSpace(GF(37), 1) - sage: E = EllipticCurve([1, 1]) - sage: f = P.Lattes_map(E, 2); f + sage: E = EllipticCurve([1, 1]) # needs sage.rings.finite_rings sage.schemes + sage: f = P.Lattes_map(E, 2); f # needs sage.rings.finite_rings sage.schemes Dynamical System of Projective Space of dimension 1 over Finite Field of size 37 Defn: Defined on coordinates by sending (x : y) to (-9*x^4 + 18*x^2*y^2 - 2*x*y^3 - 9*y^4 : x^3*y + x*y^3 + y^4) @@ -1181,23 +1412,23 @@ def chebyshev_polynomial(self, n, kind='first', monic=False): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: P.chebyshev_polynomial(5, 'first') + sage: P.chebyshev_polynomial(5, 'first') # needs sage.symbolic Dynamical System of Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (16*x^5 - 20*x^3*y^2 + 5*x*y^4 : y^5) + Defn: Defined on coordinates by sending (x : y) to + (16*x^5 - 20*x^3*y^2 + 5*x*y^4 : y^5) :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: P.chebyshev_polynomial(3, 'second') + sage: P.chebyshev_polynomial(3, 'second') # needs sage.symbolic Dynamical System of Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (8*x^3 - 4*x*y^2 : y^3) + Defn: Defined on coordinates by sending (x : y) to + (8*x^3 - 4*x*y^2 : y^3) :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: P.chebyshev_polynomial(3, 2) + sage: P.chebyshev_polynomial(3, 2) # needs sage.symbolic Traceback (most recent call last): ... ValueError: keyword 'kind' must have a value of either 'first' or 'second' @@ -1220,8 +1451,8 @@ def chebyshev_polynomial(self, n, kind='first', monic=False): :: - sage: P.<x,y> = ProjectiveSpace(QQ,1) - sage: P.chebyshev_polynomial(3, monic=True) + sage: P.<x,y> = ProjectiveSpace(QQ, 1) + sage: P.chebyshev_polynomial(3, monic=True) # needs sage.symbolic Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (x^3 - 3*x*y^2 : y^3) @@ -1229,9 +1460,10 @@ def chebyshev_polynomial(self, n, kind='first', monic=False): :: sage: F.<t> = FunctionField(QQ) - sage: P.<y,z> = ProjectiveSpace(F,1) - sage: P.chebyshev_polynomial(4,monic=True) - Dynamical System of Projective Space of dimension 1 over Rational function field in t over Rational Field + sage: P.<y,z> = ProjectiveSpace(F, 1) + sage: P.chebyshev_polynomial(4, monic=True) # needs sage.symbolic + Dynamical System of Projective Space of dimension 1 + over Rational function field in t over Rational Field Defn: Defined on coordinates by sending (y : z) to (y^4 + (-4)*y^2*z^2 + 2*z^4 : z^4) """ @@ -1270,8 +1502,8 @@ def veronese_embedding(self, d, CS=None, order='lex'): EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: vd = P.veronese_embedding(4, order='invlex') - sage: vd + sage: vd = P.veronese_embedding(4, order='invlex') # needs sage.combinat + sage: vd # needs sage.combinat Scheme morphism: From: Projective Space of dimension 1 over Rational Field To: Projective Space of dimension 4 over Rational Field @@ -1282,16 +1514,16 @@ def veronese_embedding(self, d, CS=None, order='lex'): sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: Q.<q,r,s,t,u,v> = ProjectiveSpace(QQ, 5) - sage: vd = P.veronese_embedding(2, Q) - sage: vd + sage: vd = P.veronese_embedding(2, Q) # needs sage.combinat + sage: vd # needs sage.combinat Scheme morphism: From: Projective Space of dimension 2 over Rational Field To: Projective Space of dimension 5 over Rational Field Defn: Defined on coordinates by sending (x : y : z) to (x^2 : x*y : x*z : y^2 : y*z : z^2) - sage: vd(P.subscheme([])) + sage: vd(P.subscheme([])) # needs sage.combinat sage.libs.singular Closed subscheme of Projective Space of dimension 5 over Rational Field - defined by: + defined by: -u^2 + t*v, -s*u + r*v, -s*t + r*u, @@ -1332,14 +1564,14 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr INPUT: - - ``points_source`` -- points in source projective space. + - ``points_source`` -- points in source projective space. - - ``points_target`` -- points in target projective space. + - ``points_target`` -- points in target projective space. - - ``normalize`` -- (default: `True`) If the returned matrix should be normalized. - Only works over exact rings. If the base ring is a field, the matrix is normalized so - that the last nonzero entry in the last row is 1. If the base ring is a ring, then - the matrix is normalized so that the entries are elements of the base ring. + - ``normalize`` -- (default: ``True``) If the returned matrix should be normalized. + Only works over exact rings. If the base ring is a field, the matrix is normalized so + that the last nonzero entry in the last row is 1. If the base ring is a ring, then + the matrix is normalized so that the entries are elements of the base ring. OUTPUT: Transformation matrix - element of PGL. @@ -1349,14 +1581,14 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr EXAMPLES:: - sage: P1.<a,b,c>=ProjectiveSpace(QQ, 2) - sage: points_source=[P1([1, 4, 1]), P1([1, 2, 2]), P1([3, 5, 1]), P1([1, -1, 1])] - sage: points_target=[P1([5, -2, 7]), P1([3, -2, 3]), P1([6, -5, 9]), P1([3, 6, 7])] - sage: m = P1.point_transformation_matrix(points_source, points_target); m + sage: P1.<a,b,c> = ProjectiveSpace(QQ, 2) + sage: points_source = [P1([1, 4, 1]), P1([1, 2, 2]), P1([3, 5, 1]), P1([1, -1, 1])] + sage: points_target = [P1([5, -2, 7]), P1([3, -2, 3]), P1([6, -5, 9]), P1([3, 6, 7])] + sage: m = P1.point_transformation_matrix(points_source, points_target); m # needs sage.modules [ -13/59 -128/59 -25/59] [538/177 8/59 26/177] [ -45/59 -196/59 1] - sage: [m*points_source[i] == points_target[i] for i in range(4)] + sage: [m*points_source[i] == points_target[i] for i in range(4)] # needs sage.modules [True, True, True, True] :: @@ -1364,7 +1596,7 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr sage: P.<a,b> = ProjectiveSpace(GF(13), 1) sage: points_source = [P([-6, 7]), P([1, 4]), P([3, 2])] sage: points_target = [P([-1, 2]), P([0, 2]), P([-1, 6])] - sage: P.point_transformation_matrix(points_source, points_target) + sage: P.point_transformation_matrix(points_source, points_target) # needs sage.modules [10 4] [10 1] @@ -1373,7 +1605,7 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr sage: P.<a,b> = ProjectiveSpace(QQ, 1) sage: points_source = [P([-6, -4]), P([1, 4]), P([3, 2])] sage: points_target = [P([-1, 2]), P([0, 2]), P([-7, -3])] - sage: P.point_transformation_matrix(points_source, points_target) + sage: P.point_transformation_matrix(points_source, points_target) # needs sage.modules Traceback (most recent call last): ... ValueError: source points not independent @@ -1384,36 +1616,38 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr sage: P.<a,b> = ProjectiveSpace(R, 1) sage: points_source = [P([-6*t, 7]), P([1, 4]), P([3, 2])] sage: points_target = [P([-1, 2*t]), P([0, 2]), P([-1, 6])] - sage: P.point_transformation_matrix(points_source, points_target) - [ (1/3*t + 7/12)/(t^2 - 53/24*t) (-1/12*t - 7/48)/(t^2 - 53/24*t)] - [(-2/3*t^2 - 7/36*t - 35/12)/(t^2 - 53/24*t) 1] + sage: P.point_transformation_matrix(points_source, points_target) # needs sage.modules + [ (1/3*t + 7/12)/(t^2 - 53/24*t) (-1/12*t - 7/48)/(t^2 - 53/24*t)] + [(-2/3*t^2 - 7/36*t - 35/12)/(t^2 - 53/24*t) 1] :: - sage: P1.<a,b,c>=ProjectiveSpace(RR, 2) - sage: points_source=[P1([1, 4, 1]), P1([1, 2, 2]), P1([3, 5, 1]), P1([1, -1, 1])] - sage: points_target=[P1([5, -2, 7]), P1([3, -2, 3]), P1([6, -5, 9]), P1([3, 6, 7])] - sage: P1.point_transformation_matrix(points_source, points_target) # abs tol 1e-13 + sage: P1.<a,b,c> = ProjectiveSpace(RR, 2) + sage: points_source = [P1([1, 4, 1]), P1([1, 2, 2]), P1([3, 5, 1]), P1([1, -1, 1])] + sage: points_target = [P1([5, -2, 7]), P1([3, -2, 3]), P1([6, -5, 9]), P1([3, 6, 7])] + sage: P1.point_transformation_matrix(points_source, # abs tol 1e-13 # needs sage.modules + ....: points_target) [-0.0619047619047597 -0.609523809523810 -0.119047619047621] [ 0.853968253968253 0.0380952380952380 0.0412698412698421] [ -0.214285714285712 -0.933333333333333 0.280952380952379] :: - sage: P1.<a,b,c>=ProjectiveSpace(ZZ, 2) - sage: points_source=[P1([1, 4, 1]), P1([1, 2, 2]), P1([3, 5, 1]), P1([1, -1, 1])] - sage: points_target=[P1([5, -2, 7]), P1([3, -2, 3]), P1([6, -5, 9]), P1([3, 6, 7])] - sage: P1.point_transformation_matrix(points_source, points_target) + sage: P1.<a,b,c> = ProjectiveSpace(ZZ, 2) + sage: points_source = [P1([1, 4, 1]), P1([1, 2, 2]), P1([3, 5, 1]), P1([1, -1, 1])] + sage: points_target = [P1([5, -2, 7]), P1([3, -2, 3]), P1([6, -5, 9]), P1([3, 6, 7])] + sage: P1.point_transformation_matrix(points_source, points_target) # needs sage.modules [ -39 -384 -75] [ 538 24 26] [-135 -588 177] :: - sage: P1.<a,b,c>=ProjectiveSpace(ZZ, 2) - sage: points_source=[P1([1, 4, 1]), P1([1, 2, 2]), P1([3, 5, 1]), P1([1, -1, 1])] - sage: points_target=[P1([5, -2, 7]), P1([3, -2, 3]), P1([6, -5, 9]), P1([3, 6, 7])] - sage: P1.point_transformation_matrix(points_source, points_target, normalize=False) + sage: P1.<a,b,c> = ProjectiveSpace(ZZ, 2) + sage: points_source = [P1([1, 4, 1]), P1([1, 2, 2]), P1([3, 5, 1]), P1([1, -1, 1])] + sage: points_target = [P1([5, -2, 7]), P1([3, -2, 3]), P1([6, -5, 9]), P1([3, 6, 7])] + sage: P1.point_transformation_matrix(points_source, points_target, # needs sage.modules + ....: normalize=False) [-13/30 -64/15 -5/6] [269/45 4/15 13/45] [ -3/2 -98/15 59/30] @@ -1424,7 +1658,7 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr sage: P.<a,b> = ProjectiveSpace(R, 1) sage: points_source = [P([-6*t, 7]), P([1, 4]), P([3, 2])] sage: points_target = [P([-1, 2*t]), P([0, 2]), P([-1, 6])] - sage: P.point_transformation_matrix(points_source, points_target) + sage: P.point_transformation_matrix(points_source, points_target) # needs sage.modules [ -48*t - 84 12*t + 21] [96*t^2 + 28*t + 420 -144*t^2 + 318*t] @@ -1433,16 +1667,16 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr sage: P.<a,b> = ProjectiveSpace(QQ, 1) sage: points_source = [P([-6, -1]), P([1, 4]), P([3, 2])] sage: points_target = [P([-1, 2]), P([0, 2]), P([-2, 4])] - sage: P.point_transformation_matrix(points_source, points_target) + sage: P.point_transformation_matrix(points_source, points_target) # needs sage.modules Traceback (most recent call last): ... ValueError: target points not independent :: - sage: P.<a,b,c>=ProjectiveSpace(QQ, 2) - sage: points_source=[P([1, 4, 1]), P([2, -7, 9]), P([3, 5, 1])] - sage: points_target=[P([5, -2, 7]), P([3, -2, 3]), P([6, -5, 9]), P([6, -1, 1])] + sage: P.<a,b,c> = ProjectiveSpace(QQ, 2) + sage: points_source = [P([1, 4, 1]), P([2, -7, 9]), P([3, 5, 1])] + sage: points_target = [P([5, -2, 7]), P([3, -2, 3]), P([6, -5, 9]), P([6, -1, 1])] sage: P.point_transformation_matrix(points_source, points_target) Traceback (most recent call last): ... @@ -1450,9 +1684,9 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr :: - sage: P.<a,b,c>=ProjectiveSpace(QQ, 2) - sage: points_source=[P([1, 4, 1]), P([2, -7, 9]), P([3, 5, 1]), P([1, -1, 1])] - sage: points_target=[P([5, -2, 7]), P([3, -2, 3]), P([6, -5, 9]), P([6, -1, 1]),P([7, 8, -9])] + sage: P.<a,b,c> = ProjectiveSpace(QQ, 2) + sage: points_source = [P([1, 4, 1]), P([2, -7, 9]), P([3, 5, 1]), P([1, -1, 1])] + sage: points_target = [P([5, -2, 7]), P([3, -2, 3]), P([6, -5, 9]), P([6, -1, 1]), P([7, 8, -9])] sage: P.point_transformation_matrix(points_source, points_target) Traceback (most recent call last): ... @@ -1460,9 +1694,9 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr :: - sage: P.<a,b,c>=ProjectiveSpace(QQ, 2) - sage: P1.<x,y,z>=ProjectiveSpace(QQ, 2) - sage: points_source=[P([1, 4, 1]), P([2, -7, 9]), P([3, 5, 1]), P1([1, -1, 1])] + sage: P.<a,b,c> = ProjectiveSpace(QQ, 2) + sage: P1.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: points_source = [P([1, 4, 1]), P([2, -7, 9]), P([3, 5, 1]), P1([1, -1, 1])] sage: points_target=[P([5, -2, 7]), P([3, -2, 3]), P([6, -5, 9]), P([6, -1, 1])] sage: P.point_transformation_matrix(points_source, points_target) Traceback (most recent call last): @@ -1471,10 +1705,10 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr :: - sage: P.<a,b,c>=ProjectiveSpace(QQ, 2) - sage: P1.<x,y,z>=ProjectiveSpace(QQ, 2) - sage: points_source=[P([1, 4, 1]), P([2, -7, 9]), P([3, 5, 1]), P([1, -1, 1])] - sage: points_target=[P([5, -2, 7]), P([3, -2, 3]), P([6, -5, 9]), P1([6, -1, 1])] + sage: P.<a,b,c> = ProjectiveSpace(QQ, 2) + sage: P1.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: points_source = [P([1, 4, 1]), P([2, -7, 9]), P([3, 5, 1]), P([1, -1, 1])] + sage: points_target = [P([5, -2, 7]), P([3, -2, 3]), P([6, -5, 9]), P1([6, -1, 1])] sage: P.point_transformation_matrix(points_source, points_target) Traceback (most recent call last): ... @@ -1482,10 +1716,11 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr :: - sage: P.<x,y,z>=ProjectiveSpace(ZZ,2) + sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: points_source = [P(1, 0, 0), P(0, 1, 0), P(0, 0, 1), P(1, -1, -1)] sage: points_target = [P(0, 1, 0), P(-2, 0, 1), P(0, 0, 1), P(1, -1, -1)] - sage: P.point_transformation_matrix(points_source,points_target,normalize=True) + sage: P.point_transformation_matrix(points_source, points_target, # needs sage.modules + ....: normalize=True) [ 0 -2 0] [-2 0 0] [ 0 1 1] @@ -1561,10 +1796,10 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: plane1 = P.subscheme(x) sage: plane2 = P.subscheme(y) - sage: m = P.hyperplane_transformation_matrix(plane1, plane2); m + sage: m = P.hyperplane_transformation_matrix(plane1, plane2); m # needs sage.modules [0 1] [1 0] - sage: plane2(m*P((0,1))) + sage: plane2(m*P((0,1))) # needs sage.modules (1 : 0) :: @@ -1572,7 +1807,7 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) sage: plane1 = P.subscheme(x + 2*y + z) sage: plane2 = P.subscheme(2*x + y + z) - sage: P.hyperplane_transformation_matrix(plane1, plane2) + sage: P.hyperplane_transformation_matrix(plane1, plane2) # needs sage.modules [1 0 0 0] [0 4 0 0] [0 0 2 0] @@ -1583,30 +1818,31 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: P.<x,y> = ProjectiveSpace(ZZ, 1) sage: plane1 = P.subscheme(x + y) sage: plane2 = P.subscheme(y) - sage: P.hyperplane_transformation_matrix(plane1, plane2) + sage: P.hyperplane_transformation_matrix(plane1, plane2) # needs sage.modules [-1 0] [ 1 1] :: + sage: # needs sage.rings.number_field sage: K.<v> = CyclotomicField(3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) sage: plane1 = P.subscheme(x - 2*v*y + z) sage: plane2 = P.subscheme(x + v*y + v*z) - sage: m = P.hyperplane_transformation_matrix(plane1, plane2) - sage: m + sage: m = P.hyperplane_transformation_matrix(plane1, plane2); m # needs sage.modules [ v 0 0] [ 0 -2*v 0] [ 0 0 1] :: + sage: # needs sage.rings.number_field sage: R.<x> = QQ[] - sage: K.<k> = NumberField(x^2+1) + sage: K.<k> = NumberField(x^2 + 1) sage: P.<x,y,z,w> = ProjectiveSpace(K, 3) sage: plane1 = P.subscheme(k*x + 2*k*y + z) sage: plane2 = P.subscheme(7*k*x + y + 9*z) - sage: m = P.hyperplane_transformation_matrix(plane1, plane2); m + sage: m = P.hyperplane_transformation_matrix(plane1, plane2); m # needs sage.modules [ 1 0 0 0] [ 0 14*k 0 0] [ 0 0 7/9 0] @@ -1614,6 +1850,7 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): :: + sage: # needs sage.rings.number_field sage: K.<v> = CyclotomicField(3) sage: R.<t> = K[] sage: F.<w> = K.extension(t^5 + 2) @@ -1621,8 +1858,8 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: P.<x,y,z> = ProjectiveSpace(G, 2) sage: plane1 = P.subscheme(x - 2*u*y + z) sage: plane2 = P.subscheme(x + u*y + z) - sage: m = P.hyperplane_transformation_matrix(plane1, plane2) - sage: plane2(m*P((2*u, 1, 0))) + sage: m = P.hyperplane_transformation_matrix(plane1, plane2) # needs sage.modules + sage: plane2(m*P((2*u, 1, 0))) # needs sage.modules (-u : 1 : 0) :: @@ -1630,7 +1867,7 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: P.<x,y,z> = ProjectiveSpace(FiniteField(2), 2) sage: plane1 = P.subscheme(x + y + z) sage: plane2 = P.subscheme(z) - sage: P.hyperplane_transformation_matrix(plane1, plane2) + sage: P.hyperplane_transformation_matrix(plane1, plane2) # needs sage.modules [1 0 0] [1 1 0] [1 1 1] @@ -1641,7 +1878,7 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: P.<x,y,z> = ProjectiveSpace(R, 2) sage: plane1 = P.subscheme(x + 9*t*y + z) sage: plane2 = P.subscheme(x + z) - sage: P.hyperplane_transformation_matrix(plane1, plane2) + sage: P.hyperplane_transformation_matrix(plane1, plane2) # needs sage.modules [ 1 9*t 0] [ 1 0 0] [ 0 0 1] @@ -1746,45 +1983,46 @@ def is_linearly_independent(self, points, n=None): sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: points = [P((1, 0, 1)), P((1, 2, 1)), P((1, 3, 4))] - sage: P.is_linearly_independent(points) + sage: P.is_linearly_independent(points) # needs sage.modules True :: sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2) - sage: points = [P((1, 0, 1)), P((1, 2, 1)), P((1, 3, 4)), P((0, 0 ,1))] - sage: P.is_linearly_independent(points, 2) + sage: points = [P((1, 0, 1)), P((1, 2, 1)), P((1, 3, 4)), P((0, 0, 1))] + sage: P.is_linearly_independent(points, 2) # needs sage.modules True :: sage: R.<c> = QQ[] sage: P.<x,y,z> = ProjectiveSpace(R, 2) - sage: points = [P((c, 0, 1)), P((0, c, 1)), P((1, 0, 4)), P((0, 0 ,1))] - sage: P.is_linearly_independent(points, 3) + sage: points = [P((c, 0, 1)), P((0, c, 1)), P((1, 0, 4)), P((0, 0, 1))] + sage: P.is_linearly_independent(points, 3) # needs sage.modules False :: sage: R.<c> = QQ[] sage: P.<x,y,z> = ProjectiveSpace(FractionField(R), 2) - sage: points = [P((c, 0, 1)), P((0, c, 1)), P((1, 3, 4)), P((0, 0 ,1))] - sage: P.is_linearly_independent(points, 3) + sage: points = [P((c, 0, 1)), P((0, c, 1)), P((1, 3, 4)), P((0, 0, 1))] + sage: P.is_linearly_independent(points, 3) # needs sage.modules True :: + sage: # needs sage.rings.number_field sage: K.<k> = CyclotomicField(3) sage: P.<x,y,z> = ProjectiveSpace(K, 2) - sage: points = [P((k, k^2, 1)), P((0, k, 1)), P((1, 0, 4)), P((0, 0 ,1))] - sage: P.is_linearly_independent(points, 3) + sage: points = [P((k, k^2, 1)), P((0, k, 1)), P((1, 0, 4)), P((0, 0, 1))] + sage: P.is_linearly_independent(points, 3) # needs sage.modules True :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: points = [P((1, 0)), P((1, 1))] - sage: P.is_linearly_independent(points) + sage: P.is_linearly_independent(points) # needs sage.modules True TESTS:: @@ -1866,129 +2104,6 @@ def _morphism(self, *args, **kwds): """ return SchemeMorphism_polynomial_projective_space_field(*args, **kwds) - def points_of_bounded_height(self, **kwds): - r""" - Return an iterator of the points in ``self`` of absolute multiplicative - height of at most the given bound. - - ALGORITHM: - - This is an implementation of Algorithm 6 in [Krumm2016]_. - - INPUT: - - kwds: - - - ``bound`` - a real number - - - ``precision`` - (default: 53) a positive integer - - OUTPUT: - - - an iterator of points of bounded height - - EXAMPLES:: - - sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: sorted(list(P.points_of_bounded_height(bound=2))) - [(-2 : 1), (-1 : 1), (-1/2 : 1), (0 : 1), - (1/2 : 1), (1 : 0), (1 : 1), (2 : 1)] - - :: - - sage: u = QQ['u'].0 - sage: P.<x,y,z> = ProjectiveSpace(NumberField(u^2 - 2, 'v'), 2) - sage: len(list(P.points_of_bounded_height(bound=2))) - 265 - - :: - - sage: CF.<a> = CyclotomicField(3) - sage: R.<x> = CF[] - sage: L.<l> = CF.extension(x^3 + 2) - sage: Q.<x,y> = ProjectiveSpace(L, 1) - sage: sorted(list(Q.points_of_bounded_height(bound=1))) - [(0 : 1), (1 : 0), (a + 1 : 1), (a : 1), - (-1 : 1), (-a - 1 : 1), (-a : 1), (1 : 1)] - - :: - - sage: R.<x> = QQ[] - sage: F.<a> = NumberField(x^4 - 8*x^2 + 3) - sage: P.<x,y,z> = ProjectiveSpace(F, 2) - sage: all([exp(p.global_height()) <= 1 for p in P.points_of_bounded_height(bound=1)]) - True - - :: - - sage: K.<a> = CyclotomicField(3) - sage: P.<x,y,z> = ProjectiveSpace(K, 2) - sage: len(list(P.points_of_bounded_height(bound=1))) - 57 - - :: - - sage: u = QQ['u'].0 - sage: K.<k> = NumberField(u^2 - 2) - sage: P.<x,y> = ProjectiveSpace(K, 1) - sage: len(list(P.points_of_bounded_height(bound=2))) - 24 - - :: - - sage: R.<x> = QQ[] - sage: K.<k> = NumberField(x^4 - 8*x^2 + 3) - sage: P.<x,y> = ProjectiveSpace(K, 1) - sage: len(list(P.points_of_bounded_height(bound=2))) - 108 - - :: - - sage: R.<x> = QQ[] - sage: K.<v> = NumberField(x^5 + x^3 + 1) - sage: P.<x,y,z> = ProjectiveSpace(K, 2) - sage: L = P.points_of_bounded_height(bound=1.2) - sage: len(list(L)) - 109 - """ - from sage.schemes.projective.proj_bdd_height import QQ_points_of_bounded_height, IQ_points_of_bounded_height, points_of_bounded_height - - R = self.base_ring() - - # whether the field is a number field or the rational field - if is_RationalField(R): - field_type = False - elif R in NumberFields(): - # true for rational field as well, so check is_RationalField first - field_type = True - else: - raise NotImplementedError("self must be projective space over a number field") - - bound = kwds.pop('bound') - prec = kwds.pop('precision', 53) - - # Convert between absolute and relative height for calling Krumm's algorithm - bound = bound**R.absolute_degree() - - dim = self.dimension_relative() - - if field_type: - # for imaginary quadratic field - r1, r2 = R.signature() - r = r1 + r2 - 1 - - if R.is_relative(): - deg = R.relative_degree() - else: - deg = R.degree() - - if deg == 2 and r == 0: - return IQ_points_of_bounded_height(self, R, dim, bound) - - return points_of_bounded_height(self, R, dim, bound, prec) - else: - return QQ_points_of_bounded_height(dim, bound) - def subscheme_from_Chow_form(self, Ch, dim): r""" Returns the subscheme defined by the Chow equations associated to the Chow form ``Ch``. @@ -2017,7 +2132,7 @@ def subscheme_from_Chow_form(self, Ch, dim): sage: P = ProjectiveSpace(QQ, 4, 'z') sage: R.<x0,x1,x2,x3,x4> = PolynomialRing(QQ) sage: H = x1^2 + x2^2 + 5*x3*x4 - sage: P.subscheme_from_Chow_form(H,3) + sage: P.subscheme_from_Chow_form(H, 3) # needs sage.modules Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: -5*z0*z1 + z2^2 + z3^2 @@ -2025,8 +2140,8 @@ def subscheme_from_Chow_form(self, Ch, dim): sage: P = ProjectiveSpace(QQ, 3, 'z') sage: R.<x0,x1,x2,x3,x4,x5> = PolynomialRing(QQ) - sage: H = x1-x2-x3+x5+2*x0 - sage: P.subscheme_from_Chow_form(H, 1) + sage: H = x1 - x2 - x3 + x5 + 2*x0 + sage: P.subscheme_from_Chow_form(H, 1) # needs sage.modules Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: -z1 + z3, @@ -2036,13 +2151,14 @@ def subscheme_from_Chow_form(self, Ch, dim): :: + sage: # needs sage.libs.singular sage: P.<x0,x1,x2,x3> = ProjectiveSpace(GF(7), 3) - sage: X = P.subscheme([x3^2+x1*x2,x2-x0]) - sage: Ch = X.Chow_form();Ch + sage: X = P.subscheme([x3^2 + x1*x2, x2 - x0]) + sage: Ch = X.Chow_form(); Ch t0^2 - 2*t0*t3 + t3^2 - t2*t4 - t4*t5 sage: Y = P.subscheme_from_Chow_form(Ch, 1); Y - Closed subscheme of Projective Space of dimension 3 over Finite Field of - size 7 defined by: + Closed subscheme of Projective Space of dimension 3 + over Finite Field of size 7 defined by: x1*x2 + x3^2, -x0*x2 + x2^2, -x0*x1 - x1*x2 - 2*x3^2, @@ -2053,8 +2169,8 @@ def subscheme_from_Chow_form(self, Ch, dim): x0^2 - 2*x0*x2 + x2^2 sage: I = Y.defining_ideal() sage: I.saturation(I.ring().ideal(list(I.ring().gens())))[0] - Ideal (x0 - x2, x1*x2 + x3^2) of Multivariate Polynomial Ring in x0, x1, - x2, x3 over Finite Field of size 7 + Ideal (x0 - x2, x1*x2 + x3^2) of Multivariate Polynomial Ring + in x0, x1, x2, x3 over Finite Field of size 7 """ if not Ch.is_homogeneous(): raise ValueError("Chow form must be a homogeneous polynomial") @@ -2066,7 +2182,7 @@ def subscheme_from_Chow_form(self, Ch, dim): L1 = [] for t in UnorderedTuples(list(range(n + 1)), dim + 1): if all(t[i] < t[i + 1] for i in range(dim)): - L1.append(t) + L1.append(list(t)) # create the dual brackets L2 = [] signs = [] @@ -2112,7 +2228,7 @@ def curve(self, F): EXAMPLES:: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: P.curve([y^2 - x*z]) + sage: P.curve([y^2 - x*z]) # needs sage.schemes Projective Plane Curve over Rational Field defined by y^2 - x*z """ from sage.schemes.curves.constructor import Curve @@ -2131,9 +2247,10 @@ def line_through(self, p, q): sage: P3.<x0,x1,x2,x3> = ProjectiveSpace(3, QQ) sage: p1 = P3(1, 2, 3, 4) sage: p2 = P3(4, 3, 2, 1) - sage: P3.line_through(p1, p2) - Projective Curve over Rational Field defined by -5/4*x0 + 5/2*x1 - 5/4*x2, - -5/2*x0 + 15/4*x1 - 5/4*x3, -5/4*x0 + 15/4*x2 - 5/2*x3, -5/4*x1 + 5/2*x2 - 5/4*x3 + sage: P3.line_through(p1, p2) # needs sage.schemes + Projective Curve over Rational Field defined by + -5/4*x0 + 5/2*x1 - 5/4*x2, -5/2*x0 + 15/4*x1 - 5/4*x3, + -5/4*x0 + 15/4*x2 - 5/2*x3, -5/4*x1 + 5/2*x2 - 5/4*x3 sage: p3 = P3(2,4,6,8) sage: P3.line_through(p1, p3) Traceback (most recent call last): @@ -2195,27 +2312,27 @@ def __iter__(self): EXAMPLES:: sage: FF = FiniteField(3) - sage: PP = ProjectiveSpace(0,FF) + sage: PP = ProjectiveSpace(0, FF) sage: [ x for x in PP ] [(1)] - sage: PP = ProjectiveSpace(1,FF) + sage: PP = ProjectiveSpace(1, FF) sage: [ x for x in PP ] [(0 : 1), (1 : 1), (2 : 1), (1 : 0)] - sage: PP = ProjectiveSpace(2,FF) + sage: PP = ProjectiveSpace(2, FF) sage: [ x for x in PP ] [(0 : 0 : 1), - (0 : 1 : 1), - (0 : 2 : 1), - (1 : 0 : 1), - (1 : 1 : 1), - (1 : 2 : 1), - (2 : 0 : 1), - (2 : 1 : 1), - (2 : 2 : 1), - (0 : 1 : 0), - (1 : 1 : 0), - (2 : 1 : 0), - (1 : 0 : 0)] + (0 : 1 : 1), + (0 : 2 : 1), + (1 : 0 : 1), + (1 : 1 : 1), + (1 : 2 : 1), + (2 : 0 : 1), + (2 : 1 : 1), + (2 : 2 : 1), + (0 : 1 : 0), + (1 : 1 : 0), + (2 : 1 : 0), + (1 : 0 : 0)] AUTHORS: @@ -2235,7 +2352,7 @@ def __iter__(self): C = PHom.codomain() for k in range(n + 1): # position of last 1 before the 0's - for v in cartesian_product_iterator([R for _ in range(n - k)]): + for v in product(*[R for _ in range(n - k)]): yield C._point(PHom, v + one + zero * k, check=False) def rational_points(self, F=None): @@ -2248,12 +2365,14 @@ def rational_points(self, F=None): sage: P = ProjectiveSpace(1, GF(3)) sage: P.rational_points() [(0 : 1), (1 : 1), (2 : 1), (1 : 0)] - sage: P.rational_points(GF(3^2, 'b')) - [(0 : 1), (b : 1), (b + 1 : 1), (2*b + 1 : 1), (2 : 1), (2*b : 1), (2*b + 2 : 1), (b + 2 : 1), (1 : 1), (1 : 0)] + sage: sorted(P.rational_points(GF(3^2, 'b')), key=str) # needs sage.rings.finite_rings + [(0 : 1), (1 : 0), (1 : 1), (2 : 1), + (2*b + 1 : 1), (2*b + 2 : 1), (2*b : 1), + (b + 1 : 1), (b + 2 : 1), (b : 1)] """ if F is None: return [P for P in self] - elif not is_FiniteField(F): + elif not isinstance(F, FiniteField): raise TypeError("second argument (= %s) must be a finite field" % F) return [P for P in self.base_extend(F)] @@ -2267,7 +2386,7 @@ def rational_points_dictionary(self): EXAMPLES:: - sage: P1 = ProjectiveSpace(GF(7),1,'x') + sage: P1 = ProjectiveSpace(GF(7), 1, 'x') sage: P1.rational_points_dictionary() {(0 : 1): 0, (1 : 0): 7, @@ -2314,16 +2433,16 @@ def rational_points(self, bound=0): Returns the projective points `(x_0:\cdots:x_n)` over `\QQ` with `|x_i| \leq` bound. - ALGORITHM: + ALGORITHM: - The very simple algorithm works as follows: every point - `(x_0:\cdots:x_n)` in projective space has a unique - largest index `i` for which `x_i` is not - zero. The algorithm then iterates downward on this - index. We normalize by choosing `x_i` positive. Then, - the points `x_0,\ldots,x_{i-1}` are the points of - affine `i`-space that are relatively prime to - `x_i`. We access these by using the Tuples method. + The very simple algorithm works as follows: every point + `(x_0:\cdots:x_n)` in projective space has a unique + largest index `i` for which `x_i` is not + zero. The algorithm then iterates downward on this + index. We normalize by choosing `x_i` positive. Then, + the points `x_0,\ldots,x_{i-1}` are the points of + affine `i`-space that are relatively prime to + `x_i`. We access these by using the Tuples method. INPUT: @@ -2340,16 +2459,15 @@ def rational_points(self, bound=0): sage: PP = ProjectiveSpace(2, QQ) sage: PP.rational_points(2) [(-2 : -2 : 1), (-1 : -2 : 1), (0 : -2 : 1), (1 : -2 : 1), (2 : -2 : 1), - (-2 : -1 : 1), (-1 : -1 : 1), (0 : -1 : 1), (1 : -1 : 1), (2 : -1 : 1), - (-2 : 0 : 1), (-1 : 0 : 1), (0 : 0 : 1), (1 : 0 : 1), (2 : 0 : 1), (-2 : - 1 : 1), (-1 : 1 : 1), (0 : 1 : 1), (1 : 1 : 1), (2 : 1 : 1), (-2 : 2 : - 1), (-1 : 2 : 1), (0 : 2 : 1), (1 : 2 : 1), (2 : 2 : 1), (-1/2 : -1 : - 1), (1/2 : -1 : 1), (-1 : -1/2 : 1), (-1/2 : -1/2 : 1), (0 : -1/2 : 1), - (1/2 : -1/2 : 1), (1 : -1/2 : 1), (-1/2 : 0 : 1), (1/2 : 0 : 1), (-1 : - 1/2 : 1), (-1/2 : 1/2 : 1), (0 : 1/2 : 1), (1/2 : 1/2 : 1), (1 : 1/2 : - 1), (-1/2 : 1 : 1), (1/2 : 1 : 1), (-2 : 1 : 0), (-1 : 1 : 0), (0 : 1 : - 0), (1 : 1 : 0), (2 : 1 : 0), (-1/2 : 1 : 0), (1/2 : 1 : 0), (1 : 0 : - 0)] + (-2 : -1 : 1), (-1 : -1 : 1), (0 : -1 : 1), (1 : -1 : 1), (2 : -1 : 1), + (-2 : 0 : 1), (-1 : 0 : 1), (0 : 0 : 1), (1 : 0 : 1), (2 : 0 : 1), (-2 : 1 : 1), + (-1 : 1 : 1), (0 : 1 : 1), (1 : 1 : 1), (2 : 1 : 1), (-2 : 2 : 1), + (-1 : 2 : 1), (0 : 2 : 1), (1 : 2 : 1), (2 : 2 : 1), (-1/2 : -1 : 1), + (1/2 : -1 : 1), (-1 : -1/2 : 1), (-1/2 : -1/2 : 1), (0 : -1/2 : 1), + (1/2 : -1/2 : 1), (1 : -1/2 : 1), (-1/2 : 0 : 1), (1/2 : 0 : 1), (-1 : 1/2 : 1), + (-1/2 : 1/2 : 1), (0 : 1/2 : 1), (1/2 : 1/2 : 1), (1 : 1/2 : 1), (-1/2 : 1 : 1), + (1/2 : 1 : 1), (-2 : 1 : 0), (-1 : 1 : 0), (0 : 1 : 0), (1 : 1 : 0), + (2 : 1 : 0), (-1/2 : 1 : 0), (1/2 : 1 : 0), (1 : 0 : 0)] AUTHORS: @@ -2371,7 +2489,7 @@ def rational_points(self, bound=0): for ai in R: P[i] = ai for tup in S[i - 1]: - if gcd([ai] + tup) == 1: + if gcd((ai,) + tup) == 1: for j in range(i): P[j] = tup[j] pts.append(self(P)) diff --git a/src/sage/schemes/projective/projective_subscheme.py b/src/sage/schemes/projective/projective_subscheme.py index 8a93cb30d83..8970637882d 100644 --- a/src/sage/schemes/projective/projective_subscheme.py +++ b/src/sage/schemes/projective/projective_subscheme.py @@ -29,7 +29,7 @@ from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import is_RationalField @@ -60,7 +60,7 @@ class AlgebraicScheme_subscheme_projective(AlgebraicScheme_subscheme): EXAMPLES:: sage: P.<x, y, z> = ProjectiveSpace(2, QQ) - sage: P.subscheme([x^2-y*z]) + sage: P.subscheme([x^2 - y*z]) Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^2 - y*z @@ -87,7 +87,7 @@ def point(self, v, check=True): EXAMPLES:: sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: X = P2.subscheme([x-y,y-z]) + sage: X = P2.subscheme([x - y, y - z]) sage: X.point([1,1,1]) (1 : 1 : 1) @@ -101,7 +101,7 @@ def point(self, v, check=True): :: sage: P.<x,y> = ProjectiveSpace(QQ, 1) - sage: X = P.subscheme(x^2+2*y^2) + sage: X = P.subscheme(x^2 + 2*y^2) sage: X.point(infinity) Traceback (most recent call last): ... @@ -113,7 +113,7 @@ def point(self, v, check=True): if v is infinity or\ (isinstance(v, (list,tuple)) and len(v) == 1 and v[0] is infinity): if self.ambient_space().dimension_relative() > 1: - raise ValueError("%s not well defined in dimension > 1"%v) + raise ValueError("%s not well defined in dimension > 1" % v) v = [1, 0] # todo: update elliptic curve stuff to take point_homset as argument from sage.schemes.elliptic_curves.ell_generic import is_EllipticCurve @@ -142,21 +142,19 @@ def _morphism(self, *args, **kwds): TESTS:: - sage: P1.<x,y> = ProjectiveSpace(1,QQ) - sage: P2 = ProjectiveSpace(2,QQ) + sage: P1.<x,y> = ProjectiveSpace(1, QQ) + sage: P2 = ProjectiveSpace(2, QQ) sage: H12 = P1.Hom(P2) - sage: H12([x^2,x*y, y^2]) # indirect doctest + sage: H12([x^2, x*y, y^2]) # indirect doctest Scheme morphism: From: Projective Space of dimension 1 over Rational Field To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (x^2 : x*y : y^2) - sage: P1._morphism(H12, [x^2,x*y, y^2]) + Defn: Defined on coordinates by sending (x : y) to (x^2 : x*y : y^2) + sage: P1._morphism(H12, [x^2, x*y, y^2]) Scheme morphism: From: Projective Space of dimension 1 over Rational Field To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (x^2 : x*y : y^2) + Defn: Defined on coordinates by sending (x : y) to (x^2 : x*y : y^2) """ return self.ambient_space()._morphism(*args, **kwds) @@ -170,6 +168,7 @@ def dimension(self): EXAMPLES:: + sage: # needs sage.libs.singular sage: P2.<x,y,z> = ProjectiveSpace(2, QQ) sage: P2.subscheme([]).dimension() 2 @@ -192,7 +191,7 @@ def dimension(self): x^2*y^2 + z^2*t^2, z^2 - w^2, 10*x^2 - z^2 + w^2 - sage: X.dimension() + sage: X.dimension() # needs sage.libs.singular 1 """ try: @@ -223,47 +222,45 @@ def affine_patch(self, i, AA=None): EXAMPLES:: + sage: # needs sage.libs.singular sage: PP = ProjectiveSpace(2, QQ, names='X,Y,Z') sage: X,Y,Z = PP.gens() sage: C = PP.subscheme(X^3*Y + Y^3*Z + Z^3*X) - sage: U = C.affine_patch(0) - sage: U + sage: U = C.affine_patch(0); U Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: Y^3*Z + Z^3 + Y sage: U.embedding_morphism() Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - Y^3*Z + Z^3 + Y - To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - X^3*Y + Y^3*Z + X*Z^3 - Defn: Defined on coordinates by sending (Y, Z) to - (1 : Y : Z) + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: Y^3*Z + Z^3 + Y + To: Closed subscheme of Projective Space of dimension 2 over Rational Field + defined by: X^3*Y + Y^3*Z + X*Z^3 + Defn: Defined on coordinates by sending (Y, Z) to (1 : Y : Z) sage: U.projective_embedding() is U.embedding_morphism() True :: - sage: A.<x,y,z> = AffineSpace(QQ,3) - sage: X = A.subscheme([x-y*z]) - sage: Y = X.projective_embedding(1).codomain() - sage: Y.affine_patch(1,A).ambient_space() == A + sage: A.<x,y,z> = AffineSpace(QQ, 3) + sage: X = A.subscheme([x - y*z]) + sage: Y = X.projective_embedding(1).codomain() # needs sage.libs.singular + sage: Y.affine_patch(1, A).ambient_space() == A # needs sage.libs.singular True :: - sage: P.<u,v,w> = ProjectiveSpace(2,ZZ) - sage: S = P.subscheme([u^2-v*w]) + sage: P.<u,v,w> = ProjectiveSpace(2, ZZ) + sage: S = P.subscheme([u^2 - v*w]) sage: A.<x, y> = AffineSpace(2, ZZ) - sage: S.affine_patch(1, A) - Closed subscheme of Affine Space of dimension 2 over Integer Ring - defined by: + sage: S.affine_patch(1, A) # needs sage.libs.singular + Closed subscheme of Affine Space of dimension 2 over Integer Ring defined by: x^2 - y """ i = int(i) # implicit type checking PP = self.ambient_space() n = PP.dimension_relative() if i < 0 or i > n: - raise ValueError("Argument i (= %s) must be between 0 and %s."%(i, n)) + raise ValueError("Argument i (= %s) must be between 0 and %s." % (i, n)) try: A = self.__affine_patches[i] #assume that if you've passed in a new ambient affine space @@ -277,7 +274,7 @@ def affine_patch(self, i, AA=None): if AA is None: AA = PP.affine_patch(i) elif AA.dimension_relative() != n: - raise ValueError("Affine Space must be of the dimension %s"%(n)) + raise ValueError("Affine Space must be of the dimension %s" % (n)) phi = AA.projective_embedding(i, PP) polys = self.defining_polynomials() xi = phi.defining_polynomials() @@ -305,8 +302,8 @@ def _best_affine_patch(self, point): EXAMPLES:: - sage: P.<x,y,z>= ProjectiveSpace(QQ,2) - sage: S = P.subscheme(x+2*y+3*z) + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: S = P.subscheme(x + 2*y + 3*z) sage: S._best_affine_patch(P.point([0,-3,2])) 1 sage: S._best_affine_patch([0,-3,2]) @@ -315,7 +312,7 @@ def _best_affine_patch(self, point): TESTS:: sage: F = GF(3) - sage: P.<x,y,z>= ProjectiveSpace(F,2) + sage: P.<x,y,z> = ProjectiveSpace(F, 2) sage: S._best_affine_patch([0,1,2]) 2 """ @@ -329,7 +326,7 @@ def _best_affine_patch(self, point): i_max = 0 p_max = abs_point[i_max] for i in range(1,len(point)): - if abs_point[i]>p_max: + if abs_point[i] > p_max: i_max = i p_max = abs_point[i_max] return i_max @@ -357,8 +354,8 @@ def neighborhood(self, point): EXAMPLES:: - sage: P.<x,y,z>= ProjectiveSpace(QQ,2) - sage: S = P.subscheme(x+2*y+3*z) + sage: P.<x,y,z>= ProjectiveSpace(QQ, 2) + sage: S = P.subscheme(x + 2*y + 3*z) sage: s = S.point([0,-3,2]); s (0 : -3/2 : 1) sage: patch = S.neighborhood(s); patch @@ -366,12 +363,11 @@ def neighborhood(self, point): x + 3*z sage: patch.embedding_morphism() Scheme morphism: - From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x + 3*z - To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x + 2*y + 3*z - Defn: Defined on coordinates by sending (x, z) to - (x : -3/2 : z + 1) + From: Closed subscheme of Affine Space of dimension 2 over Rational Field + defined by: x + 3*z + To: Closed subscheme of Projective Space of dimension 2 over Rational Field + defined by: x + 2*y + 3*z + Defn: Defined on coordinates by sending (x, z) to (x : -3/2 : z + 1) sage: patch.embedding_center() (0, 0) sage: patch.embedding_morphism()([0,0]) @@ -415,8 +411,9 @@ def is_smooth(self, point=None): EXAMPLES:: - sage: P2.<x,y,z> = ProjectiveSpace(2,QQ) - sage: cuspidal_curve = P2.subscheme([y^2*z-x^3]) + sage: # needs sage.libs.singular + sage: P2.<x,y,z> = ProjectiveSpace(2, QQ) + sage: cuspidal_curve = P2.subscheme([y^2*z - x^3]) sage: cuspidal_curve Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: -x^3 + y^2*z @@ -426,13 +423,13 @@ def is_smooth(self, point=None): False sage: cuspidal_curve.is_smooth() False - sage: P2.subscheme([y^2*z-x^3+z^3+1/10*x*y*z]).is_smooth() + sage: P2.subscheme([y^2*z - x^3 + z^3 + 1/10*x*y*z]).is_smooth() True TESTS:: - sage: H = P2.subscheme(x) - sage: H.is_smooth() # one of the few cases where the cone over the subvariety is smooth + sage: H = P2.subscheme(x) # needs sage.libs.singular + sage: H.is_smooth() # one of the few cases where the cone over the subvariety is smooth # needs sage.libs.singular True """ if point is not None: @@ -473,26 +470,21 @@ def orbit(self, f, N): EXAMPLES:: sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) - sage: f = DynamicalSystem_projective([(x-2*y)^2,(x-2*z)^2,(x-2*w)^2,x^2]) - sage: f.orbit(P.subscheme([x]),5) + sage: f = DynamicalSystem_projective([(x-2*y)^2, (x-2*z)^2, # needs sage.schemes + ....: (x-2*w)^2, x^2]) + sage: f.orbit(P.subscheme([x]), 5) # needs sage.schemes [Closed subscheme of Projective Space of dimension 3 over Rational Field - defined by: - x, + defined by: x, Closed subscheme of Projective Space of dimension 3 over Rational Field - defined by: - w, + defined by: w, Closed subscheme of Projective Space of dimension 3 over Rational Field - defined by: - z - w, + defined by: z - w, Closed subscheme of Projective Space of dimension 3 over Rational Field - defined by: - y - z, + defined by: y - z, Closed subscheme of Projective Space of dimension 3 over Rational Field - defined by: - x - y, + defined by: x - y, Closed subscheme of Projective Space of dimension 3 over Rational Field - defined by: - x - w] + defined by: x - w] :: @@ -500,8 +492,8 @@ def orbit(self, f, N): sage: P1.<u,v> = ProjectiveSpace(QQ, 1) sage: H = Hom(PS, P1) sage: f = H([x^2, y^2]) - sage: X = PS.subscheme([x-y]) - sage: X.orbit(f,2) + sage: X = PS.subscheme([x - y]) + sage: X.orbit(f, 2) Traceback (most recent call last): ... TypeError: map must be a dynamical system for iteration @@ -509,9 +501,9 @@ def orbit(self, f, N): :: sage: PS.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) - sage: X = PS.subscheme([x-y]) - sage: X.orbit(f,[-1,2]) + sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) # needs sage.schemes + sage: X = PS.subscheme([x - y]) + sage: X.orbit(f, [-1,2]) # needs sage.schemes Traceback (most recent call last): ... TypeError: orbit bounds must be non-negative @@ -555,19 +547,19 @@ def nth_iterate(self, f, n): EXAMPLES:: sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3) - sage: f = DynamicalSystem_projective([y^2, z^2, x^2, w^2]) - sage: f.nth_iterate(P.subscheme([x-w,y-z]), 3) + sage: f = DynamicalSystem_projective([y^2, z^2, x^2, w^2]) # needs sage.schemes + sage: f.nth_iterate(P.subscheme([x - w, y - z]), 3) # needs sage.schemes Closed subscheme of Projective Space of dimension 3 over Rational Field - defined by: + defined by: y - z, x - w :: sage: PS.<x,y,z> = ProjectiveSpace(ZZ, 2) - sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) - sage: X = PS.subscheme([x-y]) - sage: X.nth_iterate(f,-2) + sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) # needs sage.schemes + sage: X = PS.subscheme([x - y]) + sage: X.nth_iterate(f, -2) # needs sage.schemes Traceback (most recent call last): ... TypeError: must be a forward orbit @@ -575,11 +567,11 @@ def nth_iterate(self, f, n): :: sage: PS.<x,y,z> = ProjectiveSpace(ZZ, 2) - sage: P2.<u,v,w>=ProjectiveSpace(QQ, 2) + sage: P2.<u,v,w> = ProjectiveSpace(QQ, 2) sage: H = Hom(PS, P2) sage: f = H([x^2, y^2, z^2]) - sage: X = PS.subscheme([x-y]) - sage: X.nth_iterate(f,2) + sage: X = PS.subscheme([x - y]) + sage: X.nth_iterate(f, 2) Traceback (most recent call last): ... TypeError: map must be a dynamical system for iteration @@ -587,9 +579,9 @@ def nth_iterate(self, f, n): :: sage: PS.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) - sage: X = PS.subscheme([x-y]) - sage: X.nth_iterate(f,2.5) + sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) # needs sage.schemes + sage: X = PS.subscheme([x - y]) + sage: X.nth_iterate(f, 2.5) # needs sage.schemes Traceback (most recent call last): ... TypeError: Attempt to coerce non-integral RealNumber to Integer @@ -624,11 +616,11 @@ def _forward_image(self, f, check=True): sage: PS.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(PS) - sage: f = H([x^2, y^2-2*z^2, z^2]) - sage: X = PS.subscheme(y-2*z) - sage: X._forward_image(f) + sage: f = H([x^2, y^2 - 2*z^2, z^2]) + sage: X = PS.subscheme(y - 2*z) + sage: X._forward_image(f) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Rational Field - defined by: + defined by: y - 2*z :: @@ -637,22 +629,23 @@ def _forward_image(self, f, check=True): sage: PS.<x,y,z,w> = ProjectiveSpace(ZZ, 3) sage: H = End(PS) sage: f = H([y^2, x^2, w^2, z^2]) - sage: X = PS.subscheme([z^2+y*w, x-w]) - sage: f(X) + sage: X = PS.subscheme([z^2 + y*w, x - w]) + sage: f(X) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 3 over Integer Ring - defined by: + defined by: y - z, x*z - w^2 :: + sage: # needs sage.rings.real_mpfr sage: PS.<x,y,z,w> = ProjectiveSpace(CC, 3) sage: H = End(PS) sage: f = H([x^2 + y^2, y^2, z^2-y^2, w^2]) - sage: X = PS.subscheme([z-2*w]) - sage: f(X) + sage: X = PS.subscheme([z - 2*w]) + sage: f(X) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 3 over Complex Field - with 53 bits of precision defined by: + with 53 bits of precision defined by: y + z + (-4.00000000000000)*w :: @@ -661,36 +654,36 @@ def _forward_image(self, f, check=True): sage: P.<x,y,z> = ProjectiveSpace(FractionField(R), 2) sage: H = End(P) sage: f = H([x^2 + 2*y*z, t^2*y^2, z^2]) - sage: f([t^2*y-z]) + sage: f([t^2*y - z]) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Fraction Field - of Univariate Polynomial Ring in t over Rational Field defined by: + of Univariate Polynomial Ring in t over Rational Field defined by: y - 1/(t^2)*z :: + sage: # needs sage.rings.padics sage: set_verbose(-1) sage: PS.<x,y,z> = ProjectiveSpace(Qp(3), 2) sage: H = End(PS) - sage: f = H([x^2,2*y^2,z^2]) - sage: X = PS.subscheme([2*x-y,z]) - sage: f(X) + sage: f = H([x^2, 2*y^2, z^2]) + sage: X = PS.subscheme([2*x - y, z]) + sage: f(X) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over 3-adic Field - with capped relative precision 20 defined by: + with capped relative precision 20 defined by: z, - x + (1 + 3^2 + 3^4 + 3^6 + 3^8 + 3^10 + 3^12 + 3^14 + 3^16 + 3^18 + - O(3^20))*y + x + (1 + 3^2 + 3^4 + 3^6 + 3^8 + 3^10 + 3^12 + 3^14 + 3^16 + 3^18 + O(3^20))*y :: sage: R.<y0,y1,y2,y3> = PolynomialRing(QQ) sage: P.<x,y,z> = ProjectiveSpace(FractionField(R), 2) sage: H = End(P) - sage: f = H([y0*x^2+y1*z^2, y2*y^2+y3*z^2, z^2]) + sage: f = H([y0*x^2 + y1*z^2, y2*y^2 + y3*z^2, z^2]) sage: X = P.subscheme(x*z) - sage: X._forward_image(f) + sage: X._forward_image(f) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Fraction Field - of Multivariate Polynomial Ring in y0, y1, y2, y3 over Rational Field - defined by: + of Multivariate Polynomial Ring in y0, y1, y2, y3 over Rational Field + defined by: x*z + (-y1)*z^2 :: @@ -698,11 +691,11 @@ def _forward_image(self, f, check=True): sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) sage: P5.<z0,z1,z2,z3,z4,z5> = ProjectiveSpace(QQ, 5) sage: H = Hom(P2, P5) - sage: f = H([x^2,x*y,x*z,y^2,y*z,z^2]) #Veronese map + sage: f = H([x^2, x*y, x*z, y^2, y*z, z^2]) # Veronese map sage: X = P2.subscheme([]) - sage: f(X) + sage: f(X) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 5 over Rational Field - defined by: + defined by: -z4^2 + z3*z5, -z2*z4 + z1*z5, -z2*z3 + z1*z4, @@ -712,14 +705,14 @@ def _forward_image(self, f, check=True): :: - sage: P2.<x,y,z>=ProjectiveSpace(QQ, 2) - sage: P3.<u,v,w,t>=ProjectiveSpace(QQ, 3) + sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: P3.<u,v,w,t> = ProjectiveSpace(QQ, 3) sage: H = Hom(P2, P3) - sage: X = P2.subscheme([x-y,x-z]) - sage: f = H([x^2,y^2,z^2,x*y]) - sage: f(X) + sage: X = P2.subscheme([x - y, x - z]) + sage: f = H([x^2, y^2, z^2, x*y]) + sage: f(X) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 3 over Rational Field - defined by: + defined by: w - t, v - t, u - t @@ -728,10 +721,10 @@ def _forward_image(self, f, check=True): sage: P1.<u,v> = ProjectiveSpace(QQ, 1) sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: H = Hom(P2,P1) - sage: f = H([x^2,y*z]) - sage: X = P2.subscheme([x-y]) - sage: f(X) + sage: H = Hom(P2, P1) + sage: f = H([x^2, y*z]) + sage: X = P2.subscheme([x - y]) + sage: f(X) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: map must be a morphism @@ -741,8 +734,8 @@ def _forward_image(self, f, check=True): sage: PS.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: H = End(PS) sage: f = H([x^3, x*y^2, x*z^2]) - sage: X = PS.subscheme([x-y]) - sage: X._forward_image(f) + sage: X = PS.subscheme([x - y]) + sage: X._forward_image(f) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: map must be a morphism @@ -751,10 +744,10 @@ def _forward_image(self, f, check=True): sage: PS.<x,y,z> = ProjectiveSpace(QQ, 2) sage: P1.<u,v> = ProjectiveSpace(QQ, 1) - sage: Y = P1.subscheme([u-v]) + sage: Y = P1.subscheme([u - v]) sage: H = End(PS) sage: f = H([x^2, y^2, z^2]) - sage: Y._forward_image(f) + sage: Y._forward_image(f) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: subscheme must be in ambient space of domain of map @@ -812,20 +805,20 @@ def preimage(self, f, k=1, check=True): sage: PS.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: H = End(PS) sage: f = H([y^2, x^2, z^2]) - sage: X = PS.subscheme([x-y]) - sage: X.preimage(f) + sage: X = PS.subscheme([x - y]) + sage: X.preimage(f) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Integer Ring - defined by: + defined by: -x^2 + y^2 :: sage: P.<x,y,z,w,t> = ProjectiveSpace(QQ, 4) sage: H = End(P) - sage: f = H([x^2-y^2, y^2, z^2, w^2, t^2+w^2]) - sage: f.rational_preimages(P.subscheme([x-z, t^2, w-t])) + sage: f = H([x^2 - y^2, y^2, z^2, w^2, t^2 + w^2]) + sage: f.rational_preimages(P.subscheme([x - z, t^2, w - t])) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 4 over Rational Field - defined by: + defined by: x^2 - y^2 - z^2, w^4 + 2*w^2*t^2 + t^4, -t^2 @@ -835,11 +828,11 @@ def preimage(self, f, k=1, check=True): sage: P1.<x,y> = ProjectiveSpace(QQ, 1) sage: P3.<u,v,w,t> = ProjectiveSpace(QQ, 3) sage: H = Hom(P1, P3) - sage: X = P3.subscheme([u-v, 2*u-w, u+t]) - sage: f = H([x^2,y^2, x^2+y^2, x*y]) - sage: X.preimage(f) + sage: X = P3.subscheme([u - v, 2*u - w, u + t]) + sage: f = H([x^2, y^2, x^2 + y^2, x*y]) + sage: X.preimage(f) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 1 over Rational Field - defined by: + defined by: x^2 - y^2, x^2 - y^2, x^2 + x*y @@ -849,9 +842,9 @@ def preimage(self, f, k=1, check=True): sage: P1.<x,y> = ProjectiveSpace(QQ, 1) sage: P3.<u,v,w,t> = ProjectiveSpace(QQ, 3) sage: H = Hom(P3, P1) - sage: X = P1.subscheme([x-y]) + sage: X = P1.subscheme([x - y]) sage: f = H([u^2, v^2]) - sage: X.preimage(f) + sage: X.preimage(f) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: map must be a morphism @@ -861,8 +854,8 @@ def preimage(self, f, k=1, check=True): sage: PS.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: H = End(PS) sage: f = H([x^2, x^2, x^2]) - sage: X = PS.subscheme([x-y]) - sage: X.preimage(f) + sage: X = PS.subscheme([x - y]) + sage: X.preimage(f) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: map must be a morphism @@ -871,10 +864,10 @@ def preimage(self, f, k=1, check=True): sage: PS.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: P1.<u,v> = ProjectiveSpace(ZZ, 1) - sage: Y = P1.subscheme([u^2-v^2]) + sage: Y = P1.subscheme([u^2 - v^2]) sage: H = End(PS) sage: f = H([x^2, y^2, z^2]) - sage: Y.preimage(f) + sage: Y.preimage(f) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: subscheme must be in ambient space of codomain @@ -882,12 +875,12 @@ def preimage(self, f, k=1, check=True): :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) - sage: Y = P.subscheme([x-y]) + sage: Y = P.subscheme([x - y]) sage: H = End(P) sage: f = H([x^2, y^2, z^2]) - sage: Y.preimage(f, k=2) + sage: Y.preimage(f, k=2) # needs sage.libs.singular Closed subscheme of Projective Space of dimension 2 over Rational Field - defined by: + defined by: x^4 - y^4 """ dom = f.domain() @@ -932,8 +925,9 @@ def dual(self): sage: P.<x, y, z> = ProjectiveSpace(2, QQ) sage: I = R.ideal(x^2 + y^2 + z^2) sage: X = P.subscheme(I) - sage: X.dual() - Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: + sage: X.dual() # needs sage.libs.singular + Closed subscheme of Projective Space of dimension 2 over Rational Field + defined by: y0^2 + y1^2 + y2^2 The dual of the twisted cubic curve in projective 3-space is a singular @@ -945,9 +939,9 @@ def dual(self): sage: P.<x, y, z, w> = ProjectiveSpace(3, QQ) sage: I = R.ideal(y^2*z^2 - 4*x*z^3 - 4*y^3*w + 18*x*y*z*w - 27*x^2*w^2) sage: X = P.subscheme(I) - sage: X.dual() + sage: X.dual() # needs sage.libs.singular Closed subscheme of Projective Space of dimension 3 over - Rational Field defined by: + Rational Field defined by: y2^2 - y1*y3, y1*y2 - y0*y3, y1^2 - y0*y2 @@ -955,7 +949,7 @@ def dual(self): The singular locus of the quartic surface in the last example is itself supported on a twisted cubic:: - sage: X.Jacobian().radical() + sage: X.Jacobian().radical() # needs sage.libs.singular Ideal (z^2 - 3*y*w, y*z - 9*x*w, y^2 - 3*x*z) of Multivariate Polynomial Ring in x, y, z, w over Rational Field @@ -963,17 +957,18 @@ def dual(self): sage: R = PolynomialRing(GF(61), 'a,b,c') sage: P.<a, b, c> = ProjectiveSpace(2, R.base_ring()) - sage: X = P.subscheme(R.ideal(a*a+2*b*b+3*c*c)) - sage: X.dual() + sage: X = P.subscheme(R.ideal(a*a + 2*b*b + 3*c*c)) + sage: X.dual() # needs sage.libs.singular sage.rings.finite_rings Closed subscheme of Projective Space of dimension 2 over - Finite Field of size 61 defined by: - y0^2 - 30*y1^2 - 20*y2^2 + Finite Field of size 61 defined by: + y0^2 - 30*y1^2 - 20*y2^2 TESTS:: + sage: # needs sage.rings.padics sage: R = PolynomialRing(Qp(3), 'a,b,c') sage: P.<a, b, c> = ProjectiveSpace(2, R.base_ring()) - sage: X = P.subscheme(R.ideal(a*a+2*b*b+3*c*c)) + sage: X = P.subscheme(R.ideal(a*a + 2*b*b + 3*c*c)) sage: X.dual() Traceback (most recent call last): ... @@ -982,7 +977,7 @@ def dual(self): from sage.libs.singular.function_factory import ff K = self.base_ring() - if not (is_RationalField(K) or is_FiniteField(K)): + if not (is_RationalField(K) or isinstance(K, FiniteField)): raise NotImplementedError("base ring must be QQ or a finite field") I = self.defining_ideal() m = I.ngens() @@ -1012,7 +1007,10 @@ def dual(self): for i in range(n + 1): J = J + S.ideal(z[-1] * f_S.derivative(z[i]) - z[i + n + 1]) - sat = ff.elim__lib.sat + try: + sat = ff.elim__lib.sat_with_exp + except NameError: + sat = ff.elim__lib.sat max_ideal = S.ideal(z[n + 1: 2 * n + 2]) J_sat_gens = sat(J, max_ideal)[0] @@ -1033,17 +1031,17 @@ def degree(self): sage: P.<x,y,z,w,t,u> = ProjectiveSpace(QQ, 5) sage: X = P.subscheme([x^7 + x*y*z*t^4 - u^7]) - sage: X.degree() + sage: X.degree() # needs sage.libs.singular 7 sage: P.<x,y,z,w> = ProjectiveSpace(GF(13), 3) sage: X = P.subscheme([y^3 - w^3, x + 7*z]) - sage: X.degree() + sage: X.degree() # needs sage.libs.singular 3 sage: P.<x,y,z,w,u> = ProjectiveSpace(QQ, 4) - sage: C = P.curve([x^7 - y*z^3*w^2*u, w*x^2 - y*u^2, z^3 + y^3]) - sage: C.degree() + sage: C = P.curve([x^7 - y*z^3*w^2*u, w*x^2 - y*u^2, z^3 + y^3]) # needs sage.schemes + sage: C.degree() # needs sage.libs.singular sage.schemes 63 """ P = self.defining_ideal().hilbert_polynomial() @@ -1066,28 +1064,30 @@ def intersection_multiplicity(self, X, P): EXAMPLES:: + sage: # needs sage.schemes sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2) sage: C = Curve([x^4 - z^2*y^2], P) sage: D = Curve([y^4*z - x^5 - x^3*z^2], P) sage: Q1 = P([0,1,0]) - sage: C.intersection_multiplicity(D, Q1) + sage: C.intersection_multiplicity(D, Q1) # needs sage.libs.singular 4 sage: Q2 = P([0,0,1]) - sage: C.intersection_multiplicity(D, Q2) + sage: C.intersection_multiplicity(D, Q2) # needs sage.libs.singular 6 :: + sage: # needs sage.rings.number_field sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^4 + 1) sage: P.<x,y,z,w> = ProjectiveSpace(K, 3) sage: X = P.subscheme([x^2 + y^2 - z*w]) sage: Y = P.subscheme([y*z - x*w, z - w]) sage: Q1 = P([b^2,1,0,0]) - sage: X.intersection_multiplicity(Y, Q1) + sage: X.intersection_multiplicity(Y, Q1) # needs sage.libs.singular 1 - sage: Q2 = P([1/2*b^3-1/2*b,1/2*b^3-1/2*b,1,1]) - sage: X.intersection_multiplicity(Y, Q2) + sage: Q2 = P([1/2*b^3 - 1/2*b, 1/2*b^3 - 1/2*b, 1, 1]) + sage: X.intersection_multiplicity(Y, Q2) # needs sage.libs.singular 1 :: @@ -1096,18 +1096,17 @@ def intersection_multiplicity(self, X, P): sage: X = P.subscheme([x^2 - z^2, y^3 - w*x^2]) sage: Y = P.subscheme([w^2 - 2*x*y + z^2, y^2 - w^2]) sage: Q = P([1,1,-1,1]) - sage: X.intersection_multiplicity(Y, Q) + sage: X.intersection_multiplicity(Y, Q) # needs sage.libs.singular Traceback (most recent call last): ... TypeError: the intersection of this subscheme and (=Closed subscheme of Affine Space of dimension 3 - over Rational Field defined by: - z^2 + w^2 - 2*y, - y^2 - w^2) must be proper and finite + over Rational Field defined by: z^2 + w^2 - 2*y, y^2 - w^2) + must be proper and finite """ try: self.ambient_space()(P) except TypeError: - raise TypeError("(=%s) must be a point in the ambient space of this subscheme and (=%s)"%(P,X)) + raise TypeError("(=%s) must be a point in the ambient space of this subscheme and (=%s)" % (P,X)) # find an affine chart of the ambient space of this curve that contains P n = self.ambient_space().dimension_relative() for i in range(n + 1): @@ -1138,29 +1137,30 @@ def multiplicity(self, P): sage: P.<x,y,z,w,t> = ProjectiveSpace(QQ, 4) sage: X = P.subscheme([y^2 - x*t, w^7 - t*w*x^5 - z^7]) sage: Q1 = P([0,0,1,1,1]) - sage: X.multiplicity(Q1) + sage: X.multiplicity(Q1) # needs sage.libs.singular 1 sage: Q2 = P([1,0,0,0,0]) - sage: X.multiplicity(Q2) + sage: X.multiplicity(Q2) # needs sage.libs.singular 3 sage: Q3 = P([0,0,0,0,1]) - sage: X.multiplicity(Q3) + sage: X.multiplicity(Q3) # needs sage.libs.singular 7 :: + sage: # needs sage.rings.real_mpfr sage: P.<x,y,z,w> = ProjectiveSpace(CC, 3) sage: X = P.subscheme([z^5*x^2*w - y^8]) sage: Q = P([2,0,0,1]) - sage: X.multiplicity(Q) + sage: X.multiplicity(Q) # needs sage.libs.singular 5 :: sage: P.<x,y,z,w> = ProjectiveSpace(GF(29), 3) - sage: C = Curve([y^17 - x^5*w^4*z^8, x*y - z^2], P) + sage: C = Curve([y^17 - x^5*w^4*z^8, x*y - z^2], P) # needs sage.schemes sage: Q = P([3,0,0,1]) - sage: C.multiplicity(Q) + sage: C.multiplicity(Q) # needs sage.libs.singular sage.schemes 8 """ if self.base_ring() not in Fields(): @@ -1202,40 +1202,37 @@ def veronese_embedding(self, d, CS=None, order='lex'): sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: L = P.subscheme([y - x]) - sage: v = L.veronese_embedding(2) - sage: v + sage: v = L.veronese_embedding(2); v # needs sage.libs.singular Scheme morphism: - From: Closed subscheme of Projective Space of dimension 2 over - Rational Field defined by: - -x + y - To: Closed subscheme of Projective Space of dimension 5 over - Rational Field defined by: - -x4^2 + x3*x5, - x2 - x4, - x1 - x3, - x0 - x3 + From: Closed subscheme of Projective Space of dimension 2 + over Rational Field defined by: -x + y + To: Closed subscheme of Projective Space of dimension 5 + over Rational Field defined by: + -x4^2 + x3*x5, + x2 - x4, + x1 - x3, + x0 - x3 Defn: Defined on coordinates by sending (x : y : z) to (x^2 : x*y : x*z : y^2 : y*z : z^2) - sage: v.codomain().degree() + sage: v.codomain().degree() # needs sage.libs.singular 2 sage: C = P.subscheme([y*z - x^2]) - sage: C.veronese_embedding(2).codomain().degree() + sage: C.veronese_embedding(2).codomain().degree() # needs sage.libs.singular 4 twisted cubic:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: Q.<u,v,s,t> = ProjectiveSpace(QQ, 3) - sage: P.subscheme([]).veronese_embedding(3, Q) + sage: P.subscheme([]).veronese_embedding(3, Q) # needs sage.libs.singular Scheme morphism: - From: Closed subscheme of Projective Space of dimension 1 over - Rational Field defined by: - (no polynomials) - To: Closed subscheme of Projective Space of dimension 3 over - Rational Field defined by: - -s^2 + v*t, - -v*s + u*t, - -v^2 + u*s + From: Closed subscheme of Projective Space of dimension 1 + over Rational Field defined by: (no polynomials) + To: Closed subscheme of Projective Space of dimension 3 + over Rational Field defined by: + -s^2 + v*t, + -v*s + u*t, + -v^2 + u*s Defn: Defined on coordinates by sending (x : y) to (x^3 : x^2*y : x*y^2 : y^3) """ @@ -1266,21 +1263,19 @@ def _morphism(self, *args, **kwds): TESTS:: - sage: P1.<x,y> = ProjectiveSpace(1,QQ) - sage: P2 = ProjectiveSpace(2,QQ) + sage: P1.<x,y> = ProjectiveSpace(1, QQ) + sage: P2 = ProjectiveSpace(2, QQ) sage: H12 = P1.Hom(P2) - sage: H12([x^2,x*y, y^2]) # indirect doctest + sage: H12([x^2, x*y, y^2]) # indirect doctest Scheme morphism: From: Projective Space of dimension 1 over Rational Field To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (x^2 : x*y : y^2) - sage: P1._morphism(H12, [x^2,x*y, y^2]) + Defn: Defined on coordinates by sending (x : y) to (x^2 : x*y : y^2) + sage: P1._morphism(H12, [x^2, x*y, y^2]) Scheme morphism: From: Projective Space of dimension 1 over Rational Field To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x : y) to - (x^2 : x*y : y^2) + Defn: Defined on coordinates by sending (x : y) to (x^2 : x*y : y^2) """ return SchemeMorphism_polynomial_projective_subscheme_field(*args, **kwds) @@ -1312,46 +1307,39 @@ def Chow_form(self): EXAMPLES:: sage: P.<x0,x1,x2,x3> = ProjectiveSpace(GF(17), 3) - sage: X = P.subscheme([x3+x1,x2-x0,x2-x3]) - sage: X.Chow_form() + sage: X = P.subscheme([x3 + x1, x2 - x0, x2 - x3]) + sage: X.Chow_form() # needs sage.libs.singular t0 - t1 + t2 + t3 :: - sage: P.<x0,x1,x2,x3> = ProjectiveSpace(QQ,3) - sage: X = P.subscheme([x3^2 -101*x1^2 - 3*x2*x0]) - sage: X.Chow_form() + sage: P.<x0,x1,x2,x3> = ProjectiveSpace(QQ, 3) + sage: X = P.subscheme([x3^2 - 101*x1^2 - 3*x2*x0]) + sage: X.Chow_form() # needs sage.libs.singular t0^2 - 101*t2^2 - 3*t1*t3 :: - sage: P.<x0,x1,x2,x3>=ProjectiveSpace(QQ,3) - sage: X = P.subscheme([x0*x2-x1^2, x0*x3-x1*x2, x1*x3-x2^2]) + sage: # needs sage.libs.singular + sage: P.<x0,x1,x2,x3> = ProjectiveSpace(QQ, 3) + sage: X = P.subscheme([x0*x2 - x1^2, x0*x3 - x1*x2, x1*x3 - x2^2]) sage: Ch = X.Chow_form(); Ch t2^3 + 2*t2^2*t3 + t2*t3^2 - 3*t1*t2*t4 - t1*t3*t4 + t0*t4^2 + t1^2*t5 sage: Y = P.subscheme_from_Chow_form(Ch, 1); Y Closed subscheme of Projective Space of dimension 3 over Rational Field - defined by: - x2^2*x3 - x1*x3^2, - -x2^3 + x0*x3^2, - -x2^2*x3 + x1*x3^2, - x1*x2*x3 - x0*x3^2, - 3*x1*x2^2 - 3*x0*x2*x3, - -2*x1^2*x3 + 2*x0*x2*x3, - -3*x1^2*x2 + 3*x0*x1*x3, - x1^3 - x0^2*x3, - x2^3 - x1*x2*x3, - -3*x1*x2^2 + 2*x1^2*x3 + x0*x2*x3, - 2*x0*x2^2 - 2*x0*x1*x3, - 3*x1^2*x2 - 2*x0*x2^2 - x0*x1*x3, - -x0*x1*x2 + x0^2*x3, - -x0*x1^2 + x0^2*x2, - -x1^3 + x0*x1*x2, - x0*x1^2 - x0^2*x2 + defined by: + x2^2*x3 - x1*x3^2, -x2^3 + x0*x3^2, + -x2^2*x3 + x1*x3^2, x1*x2*x3 - x0*x3^2, + 3*x1*x2^2 - 3*x0*x2*x3, -2*x1^2*x3 + 2*x0*x2*x3, + -3*x1^2*x2 + 3*x0*x1*x3, x1^3 - x0^2*x3, + x2^3 - x1*x2*x3, -3*x1*x2^2 + 2*x1^2*x3 + x0*x2*x3, + 2*x0*x2^2 - 2*x0*x1*x3, 3*x1^2*x2 - 2*x0*x2^2 - x0*x1*x3, + -x0*x1*x2 + x0^2*x3, -x0*x1^2 + x0^2*x2, + -x1^3 + x0*x1*x2, x0*x1^2 - x0^2*x2 sage: I = Y.defining_ideal() sage: I.saturation(I.ring().ideal(list(I.ring().gens())))[0] - Ideal (x2^2 - x1*x3, x1*x2 - x0*x3, x1^2 - x0*x2) of Multivariate - Polynomial Ring in x0, x1, x2, x3 over Rational Field + Ideal (x2^2 - x1*x3, x1*x2 - x0*x3, x1^2 - x0*x2) + of Multivariate Polynomial Ring in x0, x1, x2, x3 over Rational Field """ I = self.defining_ideal() P = self.ambient_space() @@ -1414,7 +1402,7 @@ def Chow_form(self): # polynomial ring in just the plucker coordinates T2 = PolynomialRing(R.base_ring(), tvars) - alp = T.hom(tvars + (N*(d+1) +N)*[0], T2) + alp = T.hom(tvars + (N*(d+1) + N)*[0], T2) # get the degrees of the reduced generators of CH degs = [u.degree() for u in reduced] mind = max(degs) @@ -1428,3 +1416,101 @@ def Chow_form(self): rel2 = rel + [CF] assert all(f in rel2 for f in CH.gens()), "did not find a principal generator" return alp(CF) + + def global_height(self, prec=None): + """ + Return the (projective) global height of the subscheme. + + INPUT: + + - ``prec`` -- desired floating point precision (default: + default ``RealField`` precision). + + OUTPUT: + + - a real number. + + EXAMPLES:: + + sage: R.<x> = QQ[] + sage: NF.<a> = NumberField(x^2 - 5) + sage: P.<x,y,z> = ProjectiveSpace(NF, 2) + sage: X = P.subscheme([x^2 + y*z, 2*y*z, 3*x*y]) + sage: X.global_height() + 0.000000000000000 + + :: + + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: X = P.subscheme([z^2 - 101*y^2 - 3*x*z]) + sage: X.global_height() # long time + 4.61512051684126 + """ + return self.Chow_form().global_height(prec) + + def local_height(self, v, prec=None): + """ + Return the (projective) local height of the subscheme. + + INPUT: + + - ``v`` -- a prime or prime ideal of the base ring. + + - ``prec`` -- desired floating point precision (default: + default ``RealField`` precision). + + OUTPUT: + + - a real number. + + EXAMPLES:: + + sage: R.<x> = QQ[] + sage: NF.<a> = NumberField(x^2 - 5) + sage: I = NF.ideal(3) + sage: P.<x,y,z> = ProjectiveSpace(NF, 2) + sage: X = P.subscheme([3*x*y - 5*x*z, y^2]) + sage: X.local_height(I) + 0.000000000000000 + + :: + + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: X = P.subscheme([z^2 - 101*y^2 - 3*x*z]) + sage: X.local_height(2) + 0.000000000000000 + """ + return self.Chow_form().local_height(v, prec) + + def local_height_arch(self, i, prec=None): + """ + Return the local height at the ``i``-th infinite place of the subscheme. + + INPUT: + + - ``i`` -- an integer. + + - ``prec`` -- desired floating point precision (default: + default ``RealField`` precision). + + OUTPUT: + + - a real number. + + EXAMPLES:: + + sage: R.<x> = QQ[] + sage: NF.<a> = NumberField(x^2 - 5) + sage: P.<x,y,z> = ProjectiveSpace(NF, 2) + sage: X = P.subscheme([x^2 + y*z, 3*x*y]) + sage: X.local_height_arch(1) + 0.0000000000000000000000000000000 + + :: + + sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) + sage: X = P.subscheme([z^2 - 101*y^2 - 3*x*z]) + sage: X.local_height_arch(1) + 4.61512051684126 + """ + return self.Chow_form().local_height_arch(i, prec) \ No newline at end of file diff --git a/src/sage/schemes/riemann_surfaces/__init__.py b/src/sage/schemes/riemann_surfaces/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/geometry/__init__.py b/src/sage/schemes/riemann_surfaces/all.py similarity index 100% rename from src/sage/geometry/__init__.py rename to src/sage/schemes/riemann_surfaces/all.py diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index b219cb975e2..14599021c5d 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -1,3 +1,4 @@ +# sage.doctest: needs scipy sage.graphs sage.groups r""" Riemann matrices and endomorphism rings of algebraic Riemann surfaces @@ -124,6 +125,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.flatten import flatten from sage.misc.functional import numerical_approx +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modules.free_module import VectorSpace from sage.modules.free_module_integer import IntegerLattice @@ -134,12 +136,13 @@ from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.qqbar import number_field_elements_from_algebraics from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RealField from sage.schemes.curves.constructor import Curve import sage.libs.mpmath.all as mpall +lazy_import('sage.rings.qqbar', 'number_field_elements_from_algebraics') + def voronoi_ghost(cpoints, n=6, CC=CDF): r""" @@ -258,15 +261,15 @@ def numerical_inverse(C): EXAMPLES:: - sage: C = matrix(CC,3,3,[-4.5606e-31 + 1.2326e-31*I, - ....: -0.21313 + 0.24166*I, - ....: -3.4513e-31 + 0.16111*I, - ....: -1.0175 + 9.8608e-32*I, - ....: 0.30912 + 0.19962*I, - ....: -4.9304e-32 + 0.39923*I, - ....: 0.96793 - 3.4513e-31*I, - ....: -0.091587 + 0.19276*I, - ....: 3.9443e-31 + 0.38552*I]) + sage: C = matrix(CC, 3, 3, [-4.5606e-31 + 1.2326e-31*I, + ....: -0.21313 + 0.24166*I, + ....: -3.4513e-31 + 0.16111*I, + ....: -1.0175 + 9.8608e-32*I, + ....: 0.30912 + 0.19962*I, + ....: -4.9304e-32 + 0.39923*I, + ....: 0.96793 - 3.4513e-31*I, + ....: -0.091587 + 0.19276*I, + ....: 3.9443e-31 + 0.38552*I]) sage: from sage.schemes.riemann_surfaces.riemann_surface import numerical_inverse sage: 3e-16 < (C^-1*C-C^0).norm() < 1e-15 True @@ -416,8 +419,8 @@ def reparameterize_differential_minpoly(minpoly, z0): INPUT: - - ``minpoly`` -- a polynomial in two variables, where the first variables - corresponds to the base coordinate on the Riemann surface + - ``minpoly`` -- a polynomial in two variables, where the first variable + corresponds to the base coordinate on the Riemann surface - ``z0`` -- complex number or infinity; the point about which to reparameterize @@ -434,7 +437,7 @@ def reparameterize_differential_minpoly(minpoly, z0): .. MATH:: - `\frac{-\bar{z}^{-2} d\bar{z}}{2\sqrt{\bar{z}^{-3}-1}} = \frac{-d\bar{z}}{2\sqrt{\bar{z}(1-\bar{z}^3)}}`. + \frac{-\bar{z}^{-2} d\bar{z}}{2\sqrt{\bar{z}^{-3}-1}} = \frac{-d\bar{z}}{2\sqrt{\bar{z}(1-\bar{z}^3)}}. Hence the transformed differential should have minimal polynomial `\bar{g}^2 \bar{z} (1 - \bar{z}^3) - 1/4 = 0`, and we can check this:: @@ -529,7 +532,7 @@ class RiemannSurface(): We can also work with Riemann surfaces that are defined over fields with a complex embedding, but since the current interface for computing genus and regular differentials in Singular presently does not support extensions of - QQ, we need to specify a description of the differentials ourselves. We give + `\QQ`, we need to specify a description of the differentials ourselves. We give an example of a CM elliptic curve:: sage: Qt.<t> = QQ[] @@ -2128,6 +2131,7 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): # CCzg is required to be known as we need to know the ring which the minpolys # lie in. CCzg, bounding_data_list = bounding_data + CCz = CCzg.univariate_ring(CCzg.gen(1)).base_ring() d_edge = tuple(u[0] for u in upstairs_edge) # Using a try-catch here allows us to retain a certain amount of back @@ -2193,7 +2197,7 @@ def local_N(ct, rt): z_1 = a0lc.abs() * prod((cz - r).abs() - rho_z for r in a0roots) n = minpoly.degree(CCzg.gen(1)) ai_new = [ - (minpoly.coefficient({CCzg.gen(1): i}))(z=cz + self._CCz.gen(0)) + CCz(minpoly.coefficient({CCzg.gen(1): i}))(z=cz + self._CCz.gen(0)) for i in range(n) ] ai_pos = [self._RRz([c.abs() for c in h.list()]) for h in ai_new] @@ -2293,7 +2297,7 @@ def matrix_of_integral_values(self, differentials, integration_method="heuristic .. NOTE:: If ``differentials is self.cohomology_basis()``, the calculations - of the integrals along the edges are written to `self._integral_dict``. + of the integrals along the edges are written to ``self._integral_dict``. This is as this data will be required when computing the Abel-Jacobi map, and so it is helpful to have is stored rather than recomputing. @@ -2371,7 +2375,8 @@ def period_matrix(self): easier to test.:: sage: parent(M) - Full MatrixSpace of 3 by 6 dense matrices over Complex Field with 30 bits of precision + Full MatrixSpace of 3 by 6 dense matrices + over Complex Field with 30 bits of precision sage: M.rank() 3 @@ -2437,7 +2442,7 @@ def plot_paths(self): sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface sage: R.<x,y> = QQ[] sage: S = RiemannSurface(y^2 - x^3 - x) - sage: S.plot_paths() + sage: S.plot_paths() # needs sage.plot Graphics object consisting of 2 graphics primitives """ from sage.plot.point import point2d @@ -2473,8 +2478,8 @@ def plot_paths3d(self, thickness=0.01): sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface sage: R.<x,y> = QQ[] - sage: S = RiemannSurface(y^2-x^3-x) - sage: S.plot_paths3d() + sage: S = RiemannSurface(y^2 - x^3 - x) + sage: S.plot_paths3d() # needs sage.plot Graphics3d Object """ from sage.plot.graphics import Graphics @@ -2561,12 +2566,12 @@ def homomorphism_basis(self, other, b=None, r=None): Given another complex torus (given as the analytic Jacobian of a Riemann surface), numerically compute a basis for the homomorphism module. The - answer is returned as a list of 2g x 2g integer matrices T=(D, B; C, A) - such that if the columns of (I|M1) generate the lattice defining the - Jacobian of the Riemann surface and the columns of (I|M2) do this for - the codomain, then approximately we have (I|M2)T=(D+M2C)(I|M1), i.e., up + answer is returned as a list of `2g \times 2g` integer matrices `T=(D, B; C, A)` + such that if the columns of `(I|M_1)` generate the lattice defining the + Jacobian of the Riemann surface and the columns of `(I|M_2)` do this for + the codomain, then approximately we have `(I|M_2)T=(D+M_2C)(I|M_1)`, i.e., up to a choice of basis for `\CC^g` as a complex vector space, we we - realize (I|M1) as a sublattice of (I|M2). + realize `(I|M_1)` as a sublattice of `(I|M_2)`. INPUT: @@ -2954,7 +2959,7 @@ def _integrate_differentials_iteratively( sage: s = sign(w_start) sage: u_edge = ((z_start, w_start), z_end) sage: J, _ = S._integrate_differentials_iteratively(u_edge) - sage: bool(J[0]+s*S._RR(sqrt(pi)*gamma(5/4)/gamma(3/4)/2)<1e-10) + sage: bool(J[0] + s*S._RR(sqrt(pi)*gamma(5/4)/gamma(3/4)/2) < 1e-10) # needs sage.symbolic True .. NOTE:: @@ -3264,9 +3269,7 @@ def _aj_based(self, P): we are using the convention that the `w` value over `\infty` is given by the limit as ``z`` tends to `\infty` of ``self.w_values(z)[branch]``. - OUTPUT: - - A vector of length ``self.genus``. + OUTPUT: A vector of length ``self.genus``. EXAMPLES: @@ -3496,9 +3499,7 @@ def abel_jacobi(self, divisor, verbose=False): of the computation, in terms of how many elements of the list ``divisor`` have been completed. - OUTPUT: - - A vector of length ``self.genus``. + OUTPUT: A vector of length ``self.genus``. EXAMPLES: @@ -3665,9 +3666,7 @@ def curve(self): For others, the curve is constructed and cached, so that an identical curve is returned upon subsequent calls. - OUTPUT: - - Curve from which Riemann surface is obtained. + OUTPUT: Curve from which Riemann surface is obtained. EXAMPLES:: diff --git a/src/sage/schemes/toric/__init__.py b/src/sage/schemes/toric/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/schemes/toric/all.py b/src/sage/schemes/toric/all.py index 9d7c83954a7..71ad52ef5c6 100644 --- a/src/sage/schemes/toric/all.py +++ b/src/sage/schemes/toric/all.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs from sage.misc.lazy_import import lazy_import lazy_import('sage.schemes.toric.weierstrass', 'WeierstrassForm') diff --git a/src/sage/schemes/toric/chow_group.py b/src/sage/schemes/toric/chow_group.py index 2384d342656..ae3d245c744 100644 --- a/src/sage/schemes/toric/chow_group.py +++ b/src/sage/schemes/toric/chow_group.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs # -*- coding: utf-8 -*- r""" The Chow group of a toric variety @@ -274,8 +275,7 @@ def project_to_degree(self, degree): EXAMPLES:: sage: A = toric_varieties.P2().Chow_group() - sage: cycle = 10*A.gen(0) + 11*A.gen(1) + 12*A.gen(2) - sage: cycle + sage: cycle = 10*A.gen(0) + 11*A.gen(1) + 12*A.gen(2); cycle ( 12 | 11 | 10 ) sage: cycle.project_to_degree(2) ( 0 | 0 | 10 ) @@ -657,9 +657,7 @@ def scheme(self): r""" Return the underlying toric variety. - OUTPUT: - - A :class:`ToricVariety + OUTPUT: A :class:`ToricVariety <sage.schemes.toric.variety.ToricVariety_field>`. EXAMPLES:: @@ -787,9 +785,9 @@ def _repr_(self) -> str: sage: P2 = toric_varieties.P2() sage: from sage.schemes.toric.chow_group import ChowGroup - sage: ChowGroup(P2,ZZ)._repr_() + sage: ChowGroup(P2, ZZ)._repr_() 'Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches' - sage: ChowGroup(P2,QQ)._repr_() + sage: ChowGroup(P2, QQ)._repr_() 'QQ-Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches' """ if self.base_ring() == QQ: @@ -855,17 +853,17 @@ def degree(self, k=None): Four exercises from page 65 of [Ful1993]_. First, an example with `A_1(X)=\ZZ\oplus\ZZ/3\ZZ`:: - sage: X = ToricVariety(Fan(cones=[[0,1],[1,2],[2,0]], - ....: rays=[[2,-1],[-1,2],[-1,-1]])) + sage: X = ToricVariety(Fan(cones=[[0,1], [1,2], [2,0]], + ....: rays=[[2,-1], [-1,2], [-1,-1]])) sage: A = X.Chow_group() sage: A.degree(1) C3 x Z Second, an example with `A_2(X)=\ZZ^2`:: - sage: points = [[1,0,0],[0,1,0],[0,0,1],[1,-1,1],[-1,0,-1]] + sage: points = [[1,0,0], [0,1,0], [0,0,1], [1,-1,1], [-1,0,-1]] sage: l = LatticePolytope(points) - sage: l.show3d() + sage: l.show3d() # needs sage.plot sage: X = ToricVariety(FaceFan(l)) sage: A = X.Chow_group() sage: A.degree(2) @@ -873,8 +871,8 @@ def degree(self, k=None): Third, an example with `A_2(X)=\ZZ^5`:: - sage: cube = [[ 1,0,0],[0, 1,0],[0,0, 1],[-1, 1, 1], - ....: [-1,0,0],[0,-1,0],[0,0,-1],[ 1,-1,-1]] + sage: cube = [[ 1,0,0], [0, 1,0], [0,0, 1], [-1, 1, 1], + ....: [-1,0,0], [0,-1,0], [0,0,-1], [ 1,-1,-1]] sage: lat_cube = LatticePolytope(cube) sage: X = ToricVariety(FaceFan((LatticePolytope(lat_cube)))) sage: X.Chow_group().degree(2) @@ -887,23 +885,25 @@ def degree(self, k=None): cube, so the variety is "more singular". Its Chow group has torsion, `A_2(X)=\ZZ^5 \oplus \ZZ/2`:: - sage: rays = [[ 1, 2, 3],[ 1,-1, 1],[-1, 1, 1],[-1,-1, 1], - ....: [-1,-1,-1],[-1, 1,-1],[ 1,-1,-1],[ 1, 1,-1]] - sage: cones = [[0,1,2,3],[4,5,6,7],[0,1,7,6], - ....: [4,5,3,2],[0,2,5,7],[4,6,1,3]] + sage: rays = [[ 1, 2, 3], [ 1,-1, 1], [-1, 1, 1], [-1,-1, 1], + ....: [-1,-1,-1], [-1, 1,-1], [ 1,-1,-1], [ 1, 1,-1]] + sage: cones = [[0,1,2,3], [4,5,6,7], [0,1,7,6], + ....: [4,5,3,2], [0,2,5,7], [4,6,1,3]] sage: X = ToricVariety(Fan(cones, rays)) sage: X.Chow_group().degree(2) # long time (2s on sage.math, 2011) C2 x Z^5 Finally, Example 1.3 of [FS1994]_:: - sage: points_mod = lambda k: matrix([[ 1, 1, 2*k+1],[ 1,-1, 1], - ....: [-1, 1, 1],[-1,-1, 1],[-1,-1,-1], - ....: [-1, 1,-1],[ 1,-1,-1],[ 1, 1,-1]]) - sage: rays = lambda k: matrix([[1,1,1],[1,-1,1],[-1,1,1]] - ....: ).solve_left(points_mod(k)).rows() - sage: cones = [[0,1,2,3],[4,5,6,7],[0,1,7,6], - ....: [4,5,3,2],[0,2,5,7],[4,6,1,3]] + sage: def points_mod(k): + ....: return matrix([[ 1, 1, 2*k+1], [ 1,-1, 1], + ....: [-1, 1, 1], [-1,-1, 1], [-1,-1,-1], + ....: [-1, 1,-1], [ 1,-1,-1], [ 1, 1,-1]]) + sage: def rays(k): + ....: return matrix([[ 1, 1, 1], + ....: [ 1, -1, 1], + ....: [-1, 1, 1]]).solve_left(points_mod(k)).rows() + sage: cones = [[0,1,2,3], [4,5,6,7], [0,1,7,6], [4,5,3,2], [0,2,5,7], [4,6,1,3]] sage: X_Delta = lambda k: ToricVariety(Fan(cones=cones, rays=rays(k))) sage: X_Delta(0).Chow_group().degree() # long time (3s on sage.math, 2011) (Z, Z, Z^5, Z) @@ -1027,8 +1027,7 @@ def relation_gens(self): sage: P2 = toric_varieties.P2() sage: A = P2.Chow_group() - sage: first = A.relation_gens()[0] - sage: first + sage: first = A.relation_gens()[0]; first ( 0 | 0 | 0 ) sage: first.is_zero() True @@ -1051,8 +1050,7 @@ class ChowGroup_degree_class(SageObject): EXAMPLES:: sage: P2 = toric_varieties.P2() - sage: A = P2.Chow_group() - sage: A + sage: A = P2.Chow_group(); A Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches sage: A.degree() (Z, Z, Z) @@ -1102,9 +1100,7 @@ def _repr_(self) -> str: """ Return a string representation. - OUTPUT: - - String. + OUTPUT: A string. EXAMPLES:: @@ -1141,9 +1137,7 @@ def module(self): """ Return the submodule of the toric Chow group generated. - OUTPUT: - - A :class:`sage.modules.fg_pid.fgp_module.FGP_Module_class` + OUTPUT: A :class:`sage.modules.fg_pid.fgp_module.FGP_Module_class`. EXAMPLES:: @@ -1158,9 +1152,7 @@ def ngens(self) -> int: """ Return the number of generators. - OUTPUT: - - An integer. + OUTPUT: An integer. EXAMPLES:: @@ -1173,17 +1165,13 @@ def ngens(self) -> int: def gen(self, i): """ - Return the ``i``-th generator of the Chow group of fixed - degree. + Return the ``i``-th generator of the Chow group of fixed degree. INPUT: - ``i`` -- integer. The index of the generator to be returned. - OUTPUT: - - A tuple of Chow cycles of fixed degree generating - :meth:`module`. + OUTPUT: A Chow cycle. EXAMPLES:: @@ -1198,9 +1186,7 @@ def gens(self): """ Return the generators of the Chow group of fixed degree. - OUTPUT: - - A tuple of Chow cycles of fixed degree generating + OUTPUT: A tuple of Chow cycles of fixed degree generating :meth:`module`. EXAMPLES:: @@ -1215,15 +1201,13 @@ def gens(self): def is_ChowGroup(x) -> bool: r""" - Return whether ``x`` is a :class:`ChowGroup_class` + Return whether ``x`` is a :class:`ChowGroup_class`. INPUT: - ``x`` -- anything. - OUTPUT: - - ``True`` or ``False``. + OUTPUT: ``True`` or ``False``. EXAMPLES:: @@ -1240,15 +1224,13 @@ def is_ChowGroup(x) -> bool: def is_ChowCycle(x) -> bool: r""" - Return whether ``x`` is a :class:`ChowGroup_class` + Return whether ``x`` is a :class:`ChowCycle`. INPUT: - ``x`` -- anything. - OUTPUT: - - ``True`` or ``False``. + OUTPUT: ``True`` or ``False``. EXAMPLES:: diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index 8647225c77b..3fbdae4cdb5 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Toric divisors and divisor classes @@ -45,7 +46,7 @@ types:: sage: F = Fan(cones=[(0,1,2,3), (0,1,4)], - ....: rays=[(1,1,1), (1,-1,1), (1,-1,-1), (1,1,-1), (0,0,1)]) + ....: rays=[(1,1,1), (1,-1,1), (1,-1,-1), (1,1,-1), (0,0,1)]) sage: X = ToricVariety(F) sage: QQ_Cartier = X.divisor([2,2,1,1,1]) sage: Cartier = 2 * QQ_Cartier @@ -93,7 +94,7 @@ Divisor class [1, 0, 0, 0] sage: Dx.divisor_class() in Cl True - sage: (-Dw+Dv+Dy).divisor_class() + sage: (-Dw + Dv + Dy).divisor_class() Divisor class [1, 0, 0, 0] sage: c0 Divisor class [1, 0, 0, 0] @@ -257,9 +258,7 @@ def ToricDivisor(toric_variety, arg=None, ring=None, check=True, reduce=True): ``reduce=False`` it is your responsibility to pass valid input data ``arg``. - OUTPUT: - - - A :class:`sage.schemes.toric.divisor.ToricDivisor_generic` + OUTPUT: A :class:`sage.schemes.toric.divisor.ToricDivisor_generic`. EXAMPLES:: @@ -271,7 +270,7 @@ def ToricDivisor(toric_variety, arg=None, ring=None, check=True, reduce=True): V(u) + V(y) sage: dP6.inject_variables() Defining x, u, y, v, z, w - sage: ToricDivisor(dP6, u+y) + sage: ToricDivisor(dP6, u + y) Traceback (most recent call last): ... ValueError: u + y is not a monomial @@ -384,10 +383,10 @@ class ToricDivisor_generic(Divisor_generic): - ``parent`` -- :class:`ToricDivisorGroup`. The parent divisor group. - ``check`` -- boolean. Type-check the entries of ``v``, see - :meth:`sage.schemes.generic.divisor_group.DivisorGroup_generic.__init__`. + :class:`~sage.schemes.generic.divisor_group.DivisorGroup_generic`. - ``reduce`` -- boolean. Combine coefficients in ``v``, see - :meth:`sage.schemes.generic.divisor_group.DivisorGroup_generic.__init__`. + :class:`~sage.schemes.generic.divisor_group.DivisorGroup_generic`. .. WARNING:: @@ -518,9 +517,7 @@ def function_value(self, point): - ``point`` -- either an integer, interpreted as the index of a ray of `\Sigma`, or a point of the lattice `N`. - OUTPUT: - - - an integer or a rational number. + OUTPUT: An integer or a rational number. EXAMPLES:: @@ -575,7 +572,7 @@ def m(self, cone): EXAMPLES:: sage: F = Fan(cones=[(0,1,2,3), (0,1,4)], - ....: rays=[(1,1,1), (1,-1,1), (1,-1,-1), (1,1,-1), (0,0,1)]) + ....: rays=[(1,1,1), (1,-1,1), (1,-1,-1), (1,1,-1), (0,0,1)]) sage: X = ToricVariety(F) sage: square_cone = X.fan().cone_containing(0,1,2,3) sage: triangle_cone = X.fan().cone_containing(0,1,4) @@ -781,7 +778,7 @@ def move_away_from(self, cone): EXAMPLES:: sage: F = Fan(cones=[(0,1,2,3), (0,1,4)], - ....: rays=[(1,1,1), (1,-1,1), (1,-1,-1), (1,1,-1), (0,0,1)]) + ....: rays=[(1,1,1), (1,-1,1), (1,-1,-1), (1,1,-1), (0,0,1)]) sage: X = ToricVariety(F) sage: square_cone = X.fan().cone_containing(0,1,2,3) sage: triangle_cone = X.fan().cone_containing(0,1,4) @@ -812,7 +809,7 @@ def cohomology_class(self): OUTPUT: - Returns the corresponding cohomology class as an instance of + The corresponding cohomology class as an instance of :class:`~sage.schemes.toric.variety.CohomologyClass`. The cohomology class is the first Chern class of the associated line bundle `\mathcal{O}(D)`. @@ -820,7 +817,7 @@ def cohomology_class(self): EXAMPLES:: sage: dP6 = toric_varieties.dP6() - sage: D = dP6.divisor(dP6.fan().ray(0) ) + sage: D = dP6.divisor(dP6.fan().ray(0)) sage: D.cohomology_class() [y + v - w] """ @@ -859,7 +856,7 @@ def divisor_class(self): OUTPUT: - Returns the class of the divisor in `\mathop{Cl}(X) + The class of the divisor in `\mathop{Cl}(X) \otimes_\ZZ \QQ` as an instance of :class:`ToricRationalDivisorClassGroup`. @@ -915,7 +912,7 @@ def is_ample(self): .. NOTE:: - * For a QQ-Cartier divisor, some positive integral + * For a `\QQ`-Cartier divisor, some positive integral multiple is Cartier. We return whether this associated divisor is ample, i.e. corresponds to an ample line bundle. @@ -959,8 +956,7 @@ def is_ample(self): [(1, 1), (1, 2), (2, 1), (2, 2)] sage: [ (a,b) for a,b in product(range(-3,3), repeat=2) ....: if D(a,b).is_nef() ] - [(0, 0), (0, 1), (0, 2), (1, 0), - (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] + [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] A (worse than orbifold) singular Fano threefold:: @@ -1037,8 +1033,7 @@ def is_nef(self): [(1, 1), (1, 2), (2, 1), (2, 2)] sage: [ (a,b) for a,b in product(range(-3,3), repeat=2) ....: if D(a,b).is_nef() ] - [(0, 0), (0, 1), (0, 2), (1, 0), - (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] + [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] """ try: return self._is_nef @@ -1140,9 +1135,7 @@ def sections(self): the line bundle (or reflexive sheaf) associated to the divisor. - OUTPUT: - - - :class:`tuple` of points of lattice `M`. + OUTPUT: A :class:`tuple` of points of lattice `M`. EXAMPLES:: @@ -1160,7 +1153,7 @@ def sections(self): sage: rays = [(1,0,0),(0,1,0),(0,0,1),(-2,0,-1),(-2,-1,0),(-3,-1,-1),(1,1,1),(-1,0,0)] sage: cones = [[0,1,3],[0,1,6],[0,2,4],[0,2,6],[0,3,5],[0,4,5],[1,3,7],[1,6,7],[2,4,7],[2,6,7],[3,5,7],[4,5,7]] - sage: X = ToricVariety(Fan(rays=rays,cones=cones)) + sage: X = ToricVariety(Fan(rays=rays, cones=cones)) sage: D = X.divisor(2); D V(z2) sage: D.is_nef() @@ -1206,10 +1199,10 @@ def sections_monomials(self): From [Cox]_ page 38:: - sage: lp = LatticePolytope([(1,0),(1,1),(0,1),(-1,0),(0,-1)]) + sage: lp = LatticePolytope([(1,0), (1,1), (0,1), (-1,0), (0,-1)]) sage: lp 2-d reflexive polytope #5 in 2-d lattice M - sage: dP7 = ToricVariety( FaceFan(lp), 'x1, x2, x3, x4, x5') + sage: dP7 = ToricVariety(FaceFan(lp), 'x1, x2, x3, x4, x5') sage: AK = -dP7.K() sage: AK.sections() (N(-1, 0), N(-1, 1), N(0, -1), N(0, 0), @@ -1278,10 +1271,8 @@ def Kodaira_map(self, names='z'): Scheme morphism: From: 1-d CPR-Fano toric variety covered by 2 affine patches To: Closed subscheme of Projective Space of dimension 2 - over Rational Field defined by: - -z1^2 + z0*z2 - Defn: Defined on coordinates by sending [u : v] to - (v^2 : u*v : u^2) + over Rational Field defined by: -z1^2 + z0*z2 + Defn: Defined on coordinates by sending [u : v] to (v^2 : u*v : u^2) sage: dP6 = toric_varieties.dP6() sage: D = -dP6.K() @@ -1290,17 +1281,10 @@ def Kodaira_map(self, names='z'): From: 2-d CPR-Fano toric variety covered by 6 affine patches To: Closed subscheme of Projective Space of dimension 6 over Rational Field defined by: - -x1*x5 + x0*x6, - -x2*x3 + x0*x5, - -x1*x3 + x0*x4, - x4*x5 - x3*x6, - -x1*x2 + x0*x3, - x3*x5 - x2*x6, - x3*x4 - x1*x6, - x3^2 - x1*x5, - x2*x4 - x1*x5, - -x1*x5^2 + x2*x3*x6, - -x1*x5^3 + x2^2*x6^2 + -x1*x5 + x0*x6, -x2*x3 + x0*x5, -x1*x3 + x0*x4, + x4*x5 - x3*x6, -x1*x2 + x0*x3, x3*x5 - x2*x6, + x3*x4 - x1*x6, x3^2 - x1*x5, x2*x4 - x1*x5, + -x1*x5^2 + x2*x3*x6, -x1*x5^3 + x2^2*x6^2 Defn: Defined on coordinates by sending [x : u : y : v : z : w] to (x*u^2*y^2*v : x^2*u^2*y*w : u*y^2*v^2*z : x*u*y*v*z*w : x^2*u*z*w^2 : y*v^2*z^2*w : x*v*z^2*w^2) @@ -1329,9 +1313,7 @@ def _sheaf_complex(self, m): - `m` -- a point in ``self.scheme().fan().dual_lattice()``. - OUTPUT: - - - :class:`simplicial complex <sage.topology.simplicial_complex.SimplicialComplex>`. + OUTPUT: A :class:`simplicial complex <sage.topology.simplicial_complex.SimplicialComplex>`. EXAMPLES:: @@ -1367,9 +1349,7 @@ def _sheaf_cohomology(self, cplx): - ``cplx`` -- simplicial complex. - OUTPUT: - - - integer vector. + OUTPUT: An integer vector. EXAMPLES:: @@ -1704,7 +1684,7 @@ def __init__(self, toric_variety, base_ring): parent classes even if the schemes are the same:: sage: from sage.schemes.generic.divisor_group import DivisorGroup - sage: DivisorGroup(P2,ZZ) is ToricDivisorGroup(P2,ZZ) + sage: DivisorGroup(P2, ZZ) is ToricDivisorGroup(P2, ZZ) False """ assert is_ToricVariety(toric_variety), str(toric_variety) + ' is not a toric variety!' @@ -1714,9 +1694,7 @@ def _latex_(self): r""" Return a LaTeX representation of ``self``. - OUTPUT: - - - string. + OUTPUT: A string. TESTS:: diff --git a/src/sage/schemes/toric/divisor_class.pyx b/src/sage/schemes/toric/divisor_class.pyx index 50e23646087..5a92fe5b38d 100644 --- a/src/sage/schemes/toric/divisor_class.pyx +++ b/src/sage/schemes/toric/divisor_class.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Toric rational divisor classes @@ -52,7 +53,7 @@ divisor representing a divisor class:: # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from sage.libs.gmp.mpq cimport * @@ -62,7 +63,7 @@ from sage.modules.free_module_element import vector from sage.modules.vector_rational_dense cimport Vector_rational_dense from sage.rings.rational_field import QQ from sage.rings.rational cimport Rational -from sage.structure.element cimport Element, Vector +from sage.structure.element cimport Vector from sage.structure.element import is_Vector @@ -80,13 +81,11 @@ def is_ToricRationalDivisorClass(x): EXAMPLES:: - sage: from sage.schemes.toric.divisor_class import ( - ....: is_ToricRationalDivisorClass) + sage: from sage.schemes.toric.divisor_class import is_ToricRationalDivisorClass sage: is_ToricRationalDivisorClass(1) False sage: dP6 = toric_varieties.dP6() - sage: D = dP6.rational_class_group().gen(0) - sage: D + sage: D = dP6.rational_class_group().gen(0); D Divisor class [1, 0, 0, 0] sage: is_ToricRationalDivisorClass(D) True diff --git a/src/sage/schemes/toric/fano_variety.py b/src/sage/schemes/toric/fano_variety.py index 1bf2b79ad36..a1405c966ec 100644 --- a/src/sage/schemes/toric/fano_variety.py +++ b/src/sage/schemes/toric/fano_variety.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Fano toric varieties @@ -53,49 +54,35 @@ Its anticanonical "hypersurface" is a one-dimensional Calabi-Yau manifold:: - sage: P2.anticanonical_hypersurface( - ....: monomial_points="all") - Closed subscheme of 2-d CPR-Fano toric variety - covered by 3 affine patches defined by: - a0*z0^3 + a9*z0^2*z1 + a7*z0*z1^2 - + a1*z1^3 + a8*z0^2*z2 + a6*z0*z1*z2 - + a4*z1^2*z2 + a5*z0*z2^2 - + a3*z1*z2^2 + a2*z2^3 + sage: P2.anticanonical_hypersurface(monomial_points="all") + Closed subscheme of 2-d CPR-Fano toric variety covered by 3 affine patches defined by: + a0*z0^3 + a9*z0^2*z1 + a7*z0*z1^2 + a1*z1^3 + a8*z0^2*z2 + a6*z0*z1*z2 + + a4*z1^2*z2 + a5*z0*z2^2 + a3*z1*z2^2 + a2*z2^3 In many cases it is sufficient to work with the "simplified polynomial moduli space" of anticanonical hypersurfaces:: - sage: P2.anticanonical_hypersurface( - ....: monomial_points="simplified") - Closed subscheme of 2-d CPR-Fano toric variety - covered by 3 affine patches defined by: + sage: P2.anticanonical_hypersurface(monomial_points="simplified") + Closed subscheme of 2-d CPR-Fano toric variety covered by 3 affine patches defined by: a0*z0^3 + a1*z1^3 + a6*z0*z1*z2 + a2*z2^3 The mirror family to these hypersurfaces lives inside the Fano toric variety obtained using ``simplex`` as ``Delta`` instead of ``Delta_polar``:: - sage: FTV = CPRFanoToricVariety(Delta=simplex, - ....: coordinate_points="all") - sage: FTV.anticanonical_hypersurface( - ....: monomial_points="simplified") - Closed subscheme of 2-d CPR-Fano toric variety - covered by 9 affine patches defined by: - a2*z2^3*z3^2*z4*z5^2*z8 - + a1*z1^3*z3*z4^2*z7^2*z9 - + a3*z0*z1*z2*z3*z4*z5*z7*z8*z9 - + a0*z0^3*z5*z7*z8^2*z9^2 + sage: FTV = CPRFanoToricVariety(Delta=simplex, coordinate_points="all") + sage: FTV.anticanonical_hypersurface(monomial_points="simplified") + Closed subscheme of 2-d CPR-Fano toric variety covered by 9 affine patches defined by: + a2*z2^3*z3^2*z4*z5^2*z8 + a1*z1^3*z3*z4^2*z7^2*z9 + + a3*z0*z1*z2*z3*z4*z5*z7*z8*z9 + a0*z0^3*z5*z7*z8^2*z9^2 Here we have taken the resolved version of the ambient space for the mirror family, but in fact we don't have to resolve singularities corresponding to the interior points of facets - they are singular points which do not lie on a generic anticanonical hypersurface:: - sage: FTV = CPRFanoToricVariety(Delta=simplex, - ....: coordinate_points="all but facets") - sage: FTV.anticanonical_hypersurface( - ....: monomial_points="simplified") - Closed subscheme of 2-d CPR-Fano toric variety - covered by 3 affine patches defined by: + sage: FTV = CPRFanoToricVariety(Delta=simplex, coordinate_points="all but facets") + sage: FTV.anticanonical_hypersurface(monomial_points="simplified") + Closed subscheme of 2-d CPR-Fano toric variety covered by 3 affine patches defined by: a0*z0^3 + a1*z1^3 + a3*z0*z1*z2 + a2*z2^3 This looks very similar to our second version of the anticanonical @@ -108,10 +95,8 @@ sage: p4318 = ReflexivePolytope(3, 4318) sage: FTV = CPRFanoToricVariety(Delta_polar=p4318) sage: FTV.anticanonical_hypersurface() - Closed subscheme of 3-d CPR-Fano toric variety - covered by 4 affine patches defined by: - a0*z2^12 + a4*z2^6*z3^6 + a3*z3^12 - + a8*z0*z1*z2*z3 + a2*z1^3 + a1*z0^2 + Closed subscheme of 3-d CPR-Fano toric variety covered by 4 affine patches defined by: + a0*z2^12 + a4*z2^6*z3^6 + a3*z3^12 + a8*z0*z1*z2*z3 + a2*z1^3 + a1*z0^2 Below you will find detailed descriptions of available functions. Current functionality of this module is very basic, but it is under active @@ -123,19 +108,21 @@ # The first example of the tutorial is taken from # CPRFanoToricVariety_field.anticanonical_hypersurface - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Andrey Novoseltsev <novoselt@gmail.com> # Copyright (C) 2010 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import re -from sage.geometry.all import Cone, FaceFan, Fan, LatticePolytope +from sage.geometry.cone import Cone +from sage.geometry.fan import FaceFan +from sage.geometry.fan import Fan +from sage.geometry.lattice_polytope import LatticePolytope from sage.misc.latex import latex from sage.misc.misc_c import prod from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -181,8 +168,7 @@ def is_CPRFanoToricVariety(x): EXAMPLES:: - sage: from sage.schemes.toric.fano_variety import ( - ....: is_CPRFanoToricVariety) + sage: from sage.schemes.toric.fano_variety import is_CPRFanoToricVariety sage: is_CPRFanoToricVariety(1) False sage: FTV = toric_varieties.P2() @@ -281,9 +267,7 @@ def CPRFanoToricVariety(Delta=None, ``Delta``). If you know for sure that the input is valid, you may significantly decrease construction time using ``check=False`` option. - OUTPUT: - - - :class:`CPR-Fano toric variety <CPRFanoToricVariety_field>`. + OUTPUT: :class:`CPR-Fano toric variety <CPRFanoToricVariety_field>`. EXAMPLES: @@ -291,10 +275,8 @@ def CPRFanoToricVariety(Delta=None, sage: diamond = lattice_polytope.cross_polytope(2) sage: diamond.vertices() - M( 1, 0), - M( 0, 1), - M(-1, 0), - M( 0, -1) + M( 1, 0), M( 0, 1), + M(-1, 0), M( 0, -1) in 2-d lattice M sage: P1xP1 = CPRFanoToricVariety(Delta_polar=diamond) sage: P1xP1 @@ -302,10 +284,8 @@ def CPRFanoToricVariety(Delta=None, sage: P1xP1.fan() Rational polyhedral fan in 2-d lattice M sage: P1xP1.fan().rays() - M( 1, 0), - M( 0, 1), - M(-1, 0), - M( 0, -1) + M( 1, 0), M( 0, 1), + M(-1, 0), M( 0, -1) in 2-d lattice M "Unfortunately," this variety is smooth to start with and we cannot @@ -315,72 +295,50 @@ def CPRFanoToricVariety(Delta=None, sage: square = diamond.polar() sage: square.vertices() - N( 1, 1), - N( 1, -1), - N(-1, -1), - N(-1, 1) + N( 1, 1), N( 1, -1), + N(-1, -1), N(-1, 1) in 2-d lattice N sage: square.points() - N( 1, 1), - N( 1, -1), - N(-1, -1), - N(-1, 1), - N(-1, 0), - N( 0, -1), - N( 0, 0), - N( 0, 1), - N( 1, 0) + N( 1, 1), N( 1, -1), N(-1, -1), + N(-1, 1), N(-1, 0), N( 0, -1), + N( 0, 0), N( 0, 1), N( 1, 0) in 2-d lattice N We will construct several varieties associated to it:: sage: FTV = CPRFanoToricVariety(Delta_polar=square) sage: FTV.fan().rays() - N( 1, 1), - N( 1, -1), - N(-1, -1), - N(-1, 1) + N( 1, 1), N( 1, -1), + N(-1, -1), N(-1, 1) in 2-d lattice N sage: FTV.gens() (z0, z1, z2, z3) sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points=[0,1,2,3,8]) + ....: coordinate_points=[0,1,2,3,8]) sage: FTV.fan().rays() - N( 1, 1), - N( 1, -1), - N(-1, -1), - N(-1, 1), - N( 1, 0) + N( 1, 1), N( 1, -1), N(-1, -1), + N(-1, 1), N( 1, 0) in 2-d lattice N sage: FTV.gens() (z0, z1, z2, z3, z8) sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points=[8,0,2,1,3], - ....: coordinate_names="x+") + ....: coordinate_points=[8,0,2,1,3], + ....: coordinate_names="x+") sage: FTV.fan().rays() - N( 1, 0), - N( 1, 1), - N(-1, -1), - N( 1, -1), - N(-1, 1) + N( 1, 0), N( 1, 1), N(-1, -1), + N( 1, -1), N(-1, 1) in 2-d lattice N sage: FTV.gens() (x8, x0, x2, x1, x3) sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points="all", - ....: coordinate_names="x y Z+") + ....: coordinate_points="all", + ....: coordinate_names="x y Z+") sage: FTV.fan().rays() - N( 1, 1), - N( 1, -1), - N(-1, -1), - N(-1, 1), - N(-1, 0), - N( 0, -1), - N( 0, 1), - N( 1, 0) + N( 1, 1), N( 1, -1), N(-1, -1), N(-1, 1), + N(-1, 0), N( 0, -1), N( 0, 1), N( 1, 0) in 2-d lattice N sage: FTV.gens() (x, y, Z2, Z3, Z4, Z5, Z7, Z8) @@ -394,9 +352,9 @@ def CPRFanoToricVariety(Delta=None, you want:: sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points="all", - ....: coordinate_names="x y Z+", - ....: coordinate_name_indices=list(range(8))) + ....: coordinate_points="all", + ....: coordinate_names="x y Z+", + ....: coordinate_name_indices=list(range(8))) sage: FTV.gens() (x, y, Z2, Z3, Z4, Z5, Z6, Z7) @@ -406,9 +364,9 @@ def CPRFanoToricVariety(Delta=None, much "automatic" ones:: sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points="all", - ....: coordinate_names="x Z+", - ....: coordinate_name_indices=list(range(8))) + ....: coordinate_points="all", + ....: coordinate_names="x Z+", + ....: coordinate_name_indices=list(range(8))) sage: FTV.gens() (x, Z1, Z2, Z3, Z4, Z5, Z6, Z7) @@ -416,16 +374,16 @@ def CPRFanoToricVariety(Delta=None, accordingly:: sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points="all", - ....: coordinate_names="x Z+", - ....: coordinate_name_indices=[0] + list(range(7))) + ....: coordinate_points="all", + ....: coordinate_names="x Z+", + ....: coordinate_name_indices=[0] + list(range(7))) sage: FTV.gens() (x, Z0, Z1, Z2, Z3, Z4, Z5, Z6) sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points="all", - ....: coordinate_names="x y Z+", - ....: coordinate_name_indices=[0]*2 + list(range(6))) + ....: coordinate_points="all", + ....: coordinate_names="x y Z+", + ....: coordinate_name_indices=[0]*2 + list(range(6))) sage: FTV.gens() (x, y, Z0, Z1, Z2, Z3, Z4, Z5) @@ -440,14 +398,11 @@ def CPRFanoToricVariety(Delta=None, (these charts actually form exactly the face fan of our square) :: sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points=[0,1,2,3,4], - ....: charts=charts) + ....: coordinate_points=[0,1,2,3,4], + ....: charts=charts) sage: FTV.fan().rays() - N( 1, 1), - N( 1, -1), - N(-1, -1), - N(-1, 1), - N(-1, 0) + N( 1, 1), N( 1, -1), N(-1, -1), + N(-1, 1), N(-1, 0) in 2-d lattice N sage: [cone.ambient_ray_indices() for cone in FTV.fan()] [(0, 1), (1, 2), (2, 4), (3, 4), (0, 3)] @@ -456,22 +411,21 @@ def CPRFanoToricVariety(Delta=None, sage: bad_charts = charts + [(3,0)] sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points=[0,1,2,3,4], - ....: charts=bad_charts) + ....: coordinate_points=[0,1,2,3,4], + ....: charts=bad_charts) Traceback (most recent call last): ... ValueError: you have provided 5 cones, but only 4 of them are maximal! - Use discard_faces=True if you indeed need to construct a fan from - these cones. + Use discard_faces=True if you indeed need to construct a fan from these cones. These charts are technically correct, they just happened to list one of them twice, but it is assumed that such a situation will not happen. It is especially important when you try to speed up your code:: sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points=[0,1,2,3,4], - ....: charts=bad_charts, - ....: check=False) + ....: coordinate_points=[0,1,2,3,4], + ....: charts=bad_charts, + ....: check=False) Traceback (most recent call last): ... IndexError: list assignment index out of range @@ -485,8 +439,8 @@ def CPRFanoToricVariety(Delta=None, sage: bad_charts = charts + [(0,2)] sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points=[0,1,2,3,4], - ....: charts=bad_charts) + ....: coordinate_points=[0,1,2,3,4], + ....: charts=bad_charts) Traceback (most recent call last): ... ValueError: (0, 2) does not form a chart of a subdivision of @@ -494,34 +448,31 @@ def CPRFanoToricVariety(Delta=None, sage: bad_charts = charts[:-1] sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points=[0,1,2,3,4], - ....: charts=bad_charts) + ....: coordinate_points=[0,1,2,3,4], + ....: charts=bad_charts) Traceback (most recent call last): ... ValueError: given charts do not form a complete fan! sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points=[1,2,3,4]) + ....: coordinate_points=[1,2,3,4]) Traceback (most recent call last): ... - ValueError: all 4 vertices of Delta_polar - must be used for coordinates! + ValueError: all 4 vertices of Delta_polar must be used for coordinates! Got: [1, 2, 3, 4] sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points=[0,0,1,2,3,4]) + ....: coordinate_points=[0,0,1,2,3,4]) Traceback (most recent call last): ... - ValueError: no repetitions are - allowed for coordinate points! + ValueError: no repetitions are allowed for coordinate points! Got: [0, 0, 1, 2, 3, 4] sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points=[0,1,2,3,6]) + ....: coordinate_points=[0,1,2,3,6]) Traceback (most recent call last): ... - ValueError: the origin (point #6) - cannot be used for a coordinate! + ValueError: the origin (point #6) cannot be used for a coordinate! Got: [0, 1, 2, 3, 6] Here is a shorthand for defining the toric variety and homogeneous @@ -576,7 +527,7 @@ def CPRFanoToricVariety(Delta=None, raise ValueError("the origin (point #%d) cannot be used for a " "coordinate!\nGot: %s" % (Delta_polar.origin(), coordinate_points)) - point_to_ray = dict() + point_to_ray = {} for n, point in enumerate(coordinate_points): point_to_ray[point] = n # This can be simplified if LatticePolytopeClass is adjusted. @@ -617,7 +568,7 @@ def CPRFanoToricVariety(Delta=None, make_simplicial=make_simplicial) # Now create yet another fan making sure that the order of the rays is # the same as requested (it is a bit difficult to get it from the start) - trans = dict() + trans = {} for n, ray in enumerate(fan.rays()): trans[n] = rays.index(ray) cones = tuple(tuple(sorted(trans[r] for r in cone.ambient_ray_indices())) @@ -676,9 +627,7 @@ class CPRFanoToricVariety_field(ToricVariety_field): - ``base_field`` -- base field of the CPR-Fano toric variety. - OUTPUT: - - - :class:`CPR-Fano toric variety <CPRFanoToricVariety_field>`. + OUTPUT: :class:`CPR-Fano toric variety <CPRFanoToricVariety_field>`. TESTS:: @@ -804,22 +753,18 @@ def anticanonical_hypersurface(self, **kwds): Its anticanonical "hypersurface" is a one-dimensional Calabi-Yau manifold:: - sage: P2.anticanonical_hypersurface( - ....: monomial_points="all") + sage: P2.anticanonical_hypersurface(monomial_points="all") Closed subscheme of 2-d CPR-Fano toric variety - covered by 3 affine patches defined by: - a0*z0^3 + a9*z0^2*z1 + a7*z0*z1^2 - + a1*z1^3 + a8*z0^2*z2 + a6*z0*z1*z2 - + a4*z1^2*z2 + a5*z0*z2^2 - + a3*z1*z2^2 + a2*z2^3 + covered by 3 affine patches defined by: + a0*z0^3 + a9*z0^2*z1 + a7*z0*z1^2 + a1*z1^3 + a8*z0^2*z2 + a6*z0*z1*z2 + + a4*z1^2*z2 + a5*z0*z2^2 + a3*z1*z2^2 + a2*z2^3 In many cases it is sufficient to work with the "simplified polynomial moduli space" of anticanonical hypersurfaces:: - sage: P2.anticanonical_hypersurface( - ....: monomial_points="simplified") + sage: P2.anticanonical_hypersurface(monomial_points="simplified") Closed subscheme of 2-d CPR-Fano toric variety - covered by 3 affine patches defined by: + covered by 3 affine patches defined by: a0*z0^3 + a1*z1^3 + a6*z0*z1*z2 + a2*z2^3 The mirror family to these hypersurfaces lives inside the Fano toric @@ -827,15 +772,12 @@ def anticanonical_hypersurface(self, **kwds): ``Delta_polar``:: sage: FTV = CPRFanoToricVariety(Delta=simplex, - ....: coordinate_points="all") - sage: FTV.anticanonical_hypersurface( - ....: monomial_points="simplified") + ....: coordinate_points="all") + sage: FTV.anticanonical_hypersurface(monomial_points="simplified") Closed subscheme of 2-d CPR-Fano toric variety - covered by 9 affine patches defined by: - a2*z2^3*z3^2*z4*z5^2*z8 - + a1*z1^3*z3*z4^2*z7^2*z9 - + a3*z0*z1*z2*z3*z4*z5*z7*z8*z9 - + a0*z0^3*z5*z7*z8^2*z9^2 + covered by 9 affine patches defined by: + a2*z2^3*z3^2*z4*z5^2*z8 + a1*z1^3*z3*z4^2*z7^2*z9 + + a3*z0*z1*z2*z3*z4*z5*z7*z8*z9 + a0*z0^3*z5*z7*z8^2*z9^2 Here we have taken the resolved version of the ambient space for the mirror family, but in fact we don't have to resolve singularities @@ -843,11 +785,10 @@ def anticanonical_hypersurface(self, **kwds): points which do not lie on a generic anticanonical hypersurface:: sage: FTV = CPRFanoToricVariety(Delta=simplex, - ....: coordinate_points="all but facets") - sage: FTV.anticanonical_hypersurface( - ....: monomial_points="simplified") + ....: coordinate_points="all but facets") + sage: FTV.anticanonical_hypersurface(monomial_points="simplified") Closed subscheme of 2-d CPR-Fano toric variety - covered by 3 affine patches defined by: + covered by 3 affine patches defined by: a0*z0^3 + a1*z1^3 + a3*z0*z1*z2 + a2*z2^3 This looks very similar to our second anticanonical @@ -858,18 +799,16 @@ def anticanonical_hypersurface(self, **kwds): automatically generated coefficients. If you want, you can specify your own names :: - sage: FTV.anticanonical_hypersurface( - ....: coefficient_names="a b c d") + sage: FTV.anticanonical_hypersurface(coefficient_names="a b c d") Closed subscheme of 2-d CPR-Fano toric variety - covered by 3 affine patches defined by: + covered by 3 affine patches defined by: a*z0^3 + b*z1^3 + d*z0*z1*z2 + c*z2^3 or give concrete coefficients :: - sage: FTV.anticanonical_hypersurface( - ....: coefficients=[1, 2, 3, 4]) + sage: FTV.anticanonical_hypersurface(coefficients=[1, 2, 3, 4]) Closed subscheme of 2-d CPR-Fano toric variety - covered by 3 affine patches defined by: + covered by 3 affine patches defined by: z0^3 + 2*z1^3 + 4*z0*z1*z2 + 3*z2^3 or even mix numerical coefficients with some expressions :: @@ -878,13 +817,12 @@ def anticanonical_hypersurface(self, **kwds): ....: coefficients=[0, "t", "1/t", "psi/(psi^2 + phi)"]) sage: H Closed subscheme of 2-d CPR-Fano toric variety - covered by 3 affine patches defined by: + covered by 3 affine patches defined by: t*z1^3 + psi/(phi + psi^2)*z0*z1*z2 + 1/t*z2^3 sage: R = H.ambient_space().base_ring() sage: R Fraction Field of - Multivariate Polynomial Ring in phi, psi, t - over Rational Field + Multivariate Polynomial Ring in phi, psi, t over Rational Field """ # The example above is also copied to the tutorial section in the # main documentation of the module. @@ -899,10 +837,7 @@ def change_ring(self, F): - ``F`` -- field. - OUTPUT: - - - :class:`CPR-Fano toric variety <CPRFanoToricVariety_field>` over - ``F``. + OUTPUT: :class:`CPR-Fano toric variety <CPRFanoToricVariety_field>` over ``F``. .. NOTE:: @@ -925,14 +860,13 @@ def change_ring(self, F): Traceback (most recent call last): ... ValueError: no natural map from the base ring - (=Real Field with 53 bits of precision) - to R (=Rational Field)! + (=Real Field with 53 bits of precision) to R (=Rational Field)! sage: R = PolynomialRing(QQ, 2, 'a') sage: P1xP1.change_ring(R) Traceback (most recent call last): ... TypeError: need a field to construct a Fano toric variety! - Got Multivariate Polynomial Ring in a0, a1 over Rational Field + Got Multivariate Polynomial Ring in a0, a1 over Rational Field """ if self.base_ring() == F: return self @@ -961,8 +895,7 @@ def coordinate_point_to_coordinate(self, point): EXAMPLES:: sage: diamond = lattice_polytope.cross_polytope(2) - sage: FTV = CPRFanoToricVariety(diamond, - ....: coordinate_points=[0,1,2,3,8]) + sage: FTV = CPRFanoToricVariety(diamond, coordinate_points=[0,1,2,3,8]) sage: FTV.coordinate_points() (0, 1, 2, 3, 8) sage: FTV.gens() @@ -976,23 +909,21 @@ def coordinate_points(self): r""" Return indices of points of :meth:`Delta_polar` used for coordinates. - OUTPUT: - - - :class:`tuple` of integers. + OUTPUT: :class:`tuple` of integers. EXAMPLES:: sage: diamond = lattice_polytope.cross_polytope(2) sage: square = diamond.polar() sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points=[0,1,2,3,8]) + ....: coordinate_points=[0,1,2,3,8]) sage: FTV.coordinate_points() (0, 1, 2, 3, 8) sage: FTV.gens() (z0, z1, z2, z3, z8) sage: FTV = CPRFanoToricVariety(Delta_polar=square, - ....: coordinate_points="all") + ....: coordinate_points="all") sage: FTV.coordinate_points() (0, 1, 2, 3, 4, 5, 7, 8) sage: FTV.gens() @@ -1119,13 +1050,12 @@ def nef_complete_intersection(self, nef_partition, **kwds): nef-partition of the 3-dimensional reflexive polytope #2254:: sage: p = ReflexivePolytope(3, 2254) - sage: np = p.nef_partitions()[1] - sage: np + sage: np = p.nef_partitions()[1]; np Nef-partition {2, 3, 4, 7, 8} โŠ” {0, 1, 5, 6} sage: X = CPRFanoToricVariety(Delta_polar=p) sage: X.nef_complete_intersection(np) Closed subscheme of 3-d CPR-Fano toric variety - covered by 10 affine patches defined by: + covered by 10 affine patches defined by: a0*z1*z4^2*z5^2*z7^3 + a2*z2*z4*z5*z6*z7^2*z8^2 + a3*z2*z3*z4*z7*z8 + a1*z0*z2, b3*z1*z4*z5^2*z6^2*z7^2*z8^2 + b0*z2*z5*z6^3*z7*z8^4 @@ -1136,7 +1066,7 @@ def nef_complete_intersection(self, nef_partition, **kwds): sage: X.nef_complete_intersection(np, monomial_points="vertices") Closed subscheme of 3-d CPR-Fano toric variety - covered by 10 affine patches defined by: + covered by 10 affine patches defined by: a0*z1*z4^2*z5^2*z7^3 + a2*z2*z4*z5*z6*z7^2*z8^2 + a3*z2*z3*z4*z7*z8 + a1*z0*z2, b3*z1*z4*z5^2*z6^2*z7^2*z8^2 + b0*z2*z5*z6^3*z7*z8^4 @@ -1149,7 +1079,7 @@ def nef_complete_intersection(self, nef_partition, **kwds): ....: monomial_points="vertices", ....: coefficients=[("a", "a^2", "a/e", "c_i"), list(range(1,6))]) Closed subscheme of 3-d CPR-Fano toric variety - covered by 10 affine patches defined by: + covered by 10 affine patches defined by: a*z1*z4^2*z5^2*z7^3 + a/e*z2*z4*z5*z6*z7^2*z8^2 + (c_i)*z2*z3*z4*z7*z8 + (a^2)*z0*z2, 4*z1*z4*z5^2*z6^2*z7^2*z8^2 + z2*z5*z6^3*z7*z8^4 @@ -1159,10 +1089,10 @@ def nef_complete_intersection(self, nef_partition, **kwds): intersections in a completely resolved ambient toric variety:: sage: X = CPRFanoToricVariety(Delta_polar=p, - ....: coordinate_points="all") + ....: coordinate_points="all") sage: X.nef_complete_intersection(np) Closed subscheme of 3-d CPR-Fano toric variety - covered by 22 affine patches defined by: + covered by 22 affine patches defined by: a2*z2*z4*z5*z6*z7^2*z8^2*z9^2*z10^2*z11*z12*z13 + a0*z1*z4^2*z5^2*z7^3*z9*z10^2*z12*z13 + a3*z2*z3*z4*z7*z8*z9*z10*z11*z12 + a1*z0*z2, @@ -1206,11 +1136,8 @@ def cartesian_product(self, other, sage: P1xP2 = P1.cartesian_product(P2); P1xP2 3-d CPR-Fano toric variety covered by 6 affine patches sage: P1xP2.fan().rays() - N+N( 1, 0, 0), - N+N(-1, 0, 0), - N+N( 0, 1, 0), - N+N( 0, 0, 1), - N+N( 0, -1, -1) + N+N( 1, 0, 0), N+N(-1, 0, 0), N+N( 0, 1, 0), + N+N( 0, 0, 1), N+N( 0, -1, -1) in 3-d lattice N+N sage: P1xP2.Delta_polar() 3-d reflexive polytope in 3-d lattice N+N @@ -1220,7 +1147,7 @@ def cartesian_product(self, other, Delta_polar = LatticePolytope(fan.rays()) points = Delta_polar.points() - point_to_ray = dict() + point_to_ray = {} coordinate_points = [] for ray_index, ray in enumerate(fan.rays()): point = points.index(ray) @@ -1270,16 +1197,14 @@ def resolve(self, **kwds): ... ValueError: the origin (point #6) cannot be used for subdivision! - sage: FTV_res = FTV.resolve(new_points=[8,5]) - sage: FTV_res + sage: FTV_res = FTV.resolve(new_points=[8,5]); FTV_res 2-d CPR-Fano toric variety covered by 6 affine patches sage: FTV_res.coordinate_points() (0, 1, 2, 3, 8, 5) sage: FTV_res.gens() (z0, z1, z2, z3, z8, z5) - sage: TV_res = FTV.resolve(new_rays=[(1,2)]) - sage: TV_res + sage: TV_res = FTV.resolve(new_rays=[(1,2)]); TV_res 2-d toric variety covered by 5 affine patches sage: TV_res.gens() (z0, z1, z2, z3, z4) @@ -1305,7 +1230,7 @@ def resolve(self, **kwds): "subdivision!" % Delta_polar.origin()) if new_points: coordinate_points = coordinate_points + new_points - point_to_ray = dict() + point_to_ray = {} for n, point in enumerate(coordinate_points): point_to_ray[point] = n else: @@ -1357,7 +1282,7 @@ class AnticanonicalHypersurface(AlgebraicScheme_subscheme_toric): sage: import sage.schemes.toric.fano_variety as ftv sage: ftv.AnticanonicalHypersurface(P1xP1) Closed subscheme of 2-d CPR-Fano toric variety - covered by 4 affine patches defined by: + covered by 4 affine patches defined by: a0*s^2*x^2 + a3*t^2*x^2 + a6*s*t*x*y + a1*s^2*y^2 + a2*t^2*y^2 See :meth:`~CPRFanoToricVariety_field.anticanonical_hypersurface()` for a @@ -1375,19 +1300,19 @@ def __init__(self, P_Delta, monomial_points=None, coefficient_names=None, sage: import sage.schemes.toric.fano_variety as ftv sage: ftv.AnticanonicalHypersurface(P1xP1) Closed subscheme of 2-d CPR-Fano toric variety - covered by 4 affine patches defined by: + covered by 4 affine patches defined by: a0*s^2*x^2 + a3*t^2*x^2 + a6*s*t*x*y + a1*s^2*y^2 + a2*t^2*y^2 Check that finite fields are handled correctly :trac:`14899`:: - sage: F = GF(5^2, "a") - sage: X = P1xP1.change_ring(F) - sage: X.anticanonical_hypersurface(monomial_points="all", + sage: F = GF(5^2, "a") # needs sage.rings.finite_rings + sage: X = P1xP1.change_ring(F) # needs sage.rings.finite_rings + sage: X.anticanonical_hypersurface(monomial_points="all", # needs sage.rings.finite_rings ....: coefficients=[1]*X.Delta().npoints()) Closed subscheme of 2-d CPR-Fano toric variety - covered by 4 affine patches defined by: + covered by 4 affine patches defined by: s^2*x^2 + s*t*x^2 + t^2*x^2 + s^2*x*y + s*t*x*y - + t^2*x*y + s^2*y^2 + s*t*y^2 + t^2*y^2 + + t^2*x*y + s^2*y^2 + s*t*y^2 + t^2*y^2 """ if not is_CPRFanoToricVariety(P_Delta): raise TypeError("anticanonical hypersurfaces can only be " @@ -1468,17 +1393,14 @@ class NefCompleteIntersection(AlgebraicScheme_subscheme_toric): EXAMPLES:: sage: o = lattice_polytope.cross_polytope(3) - sage: np = o.nef_partitions()[0] - sage: np + sage: np = o.nef_partitions()[0]; np Nef-partition {0, 1, 3} โŠ” {2, 4, 5} sage: X = CPRFanoToricVariety(Delta_polar=o) sage: X.nef_complete_intersection(np) Closed subscheme of 3-d CPR-Fano toric variety - covered by 8 affine patches defined by: - a2*z0^2*z1 + a5*z0*z1*z3 + a1*z1*z3^2 - + a3*z0^2*z4 + a4*z0*z3*z4 + a0*z3^2*z4, - b1*z1*z2^2 + b2*z2^2*z4 + b5*z1*z2*z5 - + b4*z2*z4*z5 + b3*z1*z5^2 + b0*z4*z5^2 + covered by 8 affine patches defined by: + a2*z0^2*z1 + a5*z0*z1*z3 + a1*z1*z3^2 + a3*z0^2*z4 + a4*z0*z3*z4 + a0*z3^2*z4, + b1*z1*z2^2 + b2*z2^2*z4 + b5*z1*z2*z5 + b4*z2*z4*z5 + b3*z1*z5^2 + b0*z4*z5^2 See :meth:`CPRFanoToricVariety_field.nef_complete_intersection` for a more elaborate example. @@ -1500,7 +1422,7 @@ def __init__(self, P_Delta, nef_partition, sage: from sage.schemes.toric.fano_variety import * sage: NefCompleteIntersection(X, np) Closed subscheme of 3-d CPR-Fano toric variety - covered by 8 affine patches defined by: + covered by 8 affine patches defined by: a2*z0^2*z1 + a5*z0*z1*z3 + a1*z1*z3^2 + a3*z0^2*z4 + a4*z0*z3*z4 + a0*z3^2*z4, b1*z1*z2^2 + b2*z2^2*z4 + b5*z1*z2*z5 @@ -1583,26 +1505,19 @@ def cohomology_class(self): r""" Return the class of ``self`` in the ambient space cohomology ring. - OUTPUT: - - - a :class:`cohomology class - <sage.schemes.generic.toric_variety.CohomologyClass>`. + OUTPUT: A :class:`cohomology class <sage.schemes.generic.toric_variety.CohomologyClass>`. EXAMPLES:: sage: o = lattice_polytope.cross_polytope(3) - sage: np = o.nef_partitions()[0] - sage: np + sage: np = o.nef_partitions()[0]; np Nef-partition {0, 1, 3} โŠ” {2, 4, 5} sage: X = CPRFanoToricVariety(Delta_polar=o) - sage: CI = X.nef_complete_intersection(np) - sage: CI + sage: CI = X.nef_complete_intersection(np); CI Closed subscheme of 3-d CPR-Fano toric variety - covered by 8 affine patches defined by: - a2*z0^2*z1 + a5*z0*z1*z3 + a1*z1*z3^2 - + a3*z0^2*z4 + a4*z0*z3*z4 + a0*z3^2*z4, - b1*z1*z2^2 + b2*z2^2*z4 + b5*z1*z2*z5 - + b4*z2*z4*z5 + b3*z1*z5^2 + b0*z4*z5^2 + covered by 8 affine patches defined by: + a2*z0^2*z1 + a5*z0*z1*z3 + a1*z1*z3^2 + a3*z0^2*z4 + a4*z0*z3*z4 + a0*z3^2*z4, + b1*z1*z2^2 + b2*z2^2*z4 + b5*z1*z2*z5 + b4*z2*z4*z5 + b3*z1*z5^2 + b0*z4*z5^2 sage: CI.cohomology_class() [2*z3*z4 + 4*z3*z5 + 2*z4*z5] """ @@ -1616,26 +1531,19 @@ def nef_partition(self): r""" Return the nef-partition associated to ``self``. - OUTPUT: - - - a :class:`nef-partition - <sage.geometry.lattice_polytope.NefPartition>`. + OUTPUT: A :class:`nef-partition <sage.geometry.lattice_polytope.NefPartition>`. EXAMPLES:: sage: o = lattice_polytope.cross_polytope(3) - sage: np = o.nef_partitions()[0] - sage: np + sage: np = o.nef_partitions()[0]; np Nef-partition {0, 1, 3} โŠ” {2, 4, 5} sage: X = CPRFanoToricVariety(Delta_polar=o) - sage: CI = X.nef_complete_intersection(np) - sage: CI + sage: CI = X.nef_complete_intersection(np); CI Closed subscheme of 3-d CPR-Fano toric variety - covered by 8 affine patches defined by: - a2*z0^2*z1 + a5*z0*z1*z3 + a1*z1*z3^2 - + a3*z0^2*z4 + a4*z0*z3*z4 + a0*z3^2*z4, - b1*z1*z2^2 + b2*z2^2*z4 + b5*z1*z2*z5 - + b4*z2*z4*z5 + b3*z1*z5^2 + b0*z4*z5^2 + covered by 8 affine patches defined by: + a2*z0^2*z1 + a5*z0*z1*z3 + a1*z1*z3^2 + a3*z0^2*z4 + a4*z0*z3*z4 + a0*z3^2*z4, + b1*z1*z2^2 + b2*z2^2*z4 + b5*z1*z2*z5 + b4*z2*z4*z5 + b3*z1*z5^2 + b0*z4*z5^2 sage: CI.nef_partition() Nef-partition {0, 1, 3} โŠ” {2, 4, 5} sage: CI.nef_partition() is np @@ -1667,17 +1575,13 @@ def add_variables(field, variables): sage: F = add_variables(QQ, []); F # No extension Rational Field sage: F = add_variables(QQ, ["a"]); F - Fraction Field of Univariate Polynomial Ring - in a over Rational Field + Fraction Field of Univariate Polynomial Ring in a over Rational Field sage: F = add_variables(F, ["a"]); F - Fraction Field of Univariate Polynomial Ring - in a over Rational Field + Fraction Field of Univariate Polynomial Ring in a over Rational Field sage: F = add_variables(F, ["b", "c"]); F - Fraction Field of Multivariate Polynomial Ring - in a, b, c over Rational Field + Fraction Field of Multivariate Polynomial Ring in a, b, c over Rational Field sage: F = add_variables(F, ["c", "d", "b", "c", "d"]); F - Fraction Field of Multivariate Polynomial Ring - in a, b, c, d over Rational Field + Fraction Field of Multivariate Polynomial Ring in a, b, c, d over Rational Field """ if not variables: return field diff --git a/src/sage/schemes/toric/homset.py b/src/sage/schemes/toric/homset.py index a057ecdf1ab..bd535edf932 100644 --- a/src/sage/schemes/toric/homset.py +++ b/src/sage/schemes/toric/homset.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Set of homomorphisms between two toric varieties @@ -48,8 +49,7 @@ Scheme morphism: From: 2-d CPR-Fano toric variety covered by 4 affine patches To: 1-d CPR-Fano toric variety covered by 2 affine patches - Defn: Defined on coordinates by sending [s : t : x : y] to - [s : t] + Defn: Defined on coordinates by sending [s : t : x : y] to [s : t] In the case of toric algebraic schemes (defined by polynomials in toric varieties), this module defines the underlying morphism of the @@ -57,7 +57,7 @@ sage: P1xP1.inject_variables() Defining s, t, x, y - sage: S = P1xP1.subscheme([s*x-t*y]) + sage: S = P1xP1.subscheme([s*x - t*y]) sage: type(S.Hom(S)) <class 'sage.schemes.toric.homset.SchemeHomset_toric_variety_with_category'> @@ -76,8 +76,7 @@ Scheme morphism: From: 2-d CPR-Fano toric variety covered by 3 affine patches To: Projective Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending [x : y : z] to - (x^2 : y^2 : z^2) + Defn: Defined on coordinates by sending [x : y : z] to (x^2 : y^2 : z^2) sage: native_to_toric = P2_native.Hom(P2_toric); native_to_toric Set of morphisms @@ -89,8 +88,7 @@ Scheme morphism: From: Projective Space of dimension 2 over Rational Field To: 2-d CPR-Fano toric variety covered by 3 affine patches - Defn: Defined on coordinates by sending (u : v : w) to - [u^2 : v^2 : w^2] + Defn: Defined on coordinates by sending (u : v : w) to [u^2 : v^2 : w^2] """ # **************************************************************************** @@ -294,16 +292,13 @@ def _an_element_(self): class SchemeHomset_points_toric_base(SchemeHomset_points): """ - Base class for homsets with toric ambient spaces + Base class for homsets with toric ambient spaces. INPUT: - same as for :class:`SchemeHomset_points`. - OUTPUT: - - A scheme morphism of type - :class:`SchemeHomset_points_toric_base`. + OUTPUT: A scheme morphism of type :class:`SchemeHomset_points_toric_base`. EXAMPLES:: @@ -323,9 +318,7 @@ def is_finite(self): """ Return whether there are finitely many points. - OUTPUT: - - Boolean. + OUTPUT: A boolean. EXAMPLES:: @@ -439,10 +432,7 @@ class SchemeHomset_points_toric_field(SchemeHomset_points_toric_base): - same as for :class:`~sage.schemes.generic.homset.SchemeHomset_points`. - OUTPUT: - - A scheme morphism of type - :class:`SchemeHomset_points_toric_field`. + OUTPUT: A scheme morphism of type :class:`SchemeHomset_points_toric_field`. EXAMPLES:: @@ -513,7 +503,7 @@ def cardinality(self): sage: V = ToricVariety(FaceFan(o)) sage: V.change_ring(GF(2)).point_set().cardinality() 27 - sage: V.change_ring(GF(8, "a")).point_set().cardinality() + sage: V.change_ring(GF(8, "a")).point_set().cardinality() # needs sage.rings.finite_rings 729 sage: V.change_ring(GF(101)).point_set().cardinality() 1061208 @@ -578,9 +568,7 @@ def __iter__(self): """ Iterate over the points of the variety. - OUTPUT: - - Iterator over points. + OUTPUT: Iterator over points. EXAMPLES:: diff --git a/src/sage/schemes/toric/ideal.py b/src/sage/schemes/toric/ideal.py index e5902d83ffd..bf9eb94e331 100644 --- a/src/sage/schemes/toric/ideal.py +++ b/src/sage/schemes/toric/ideal.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Toric ideals @@ -19,7 +20,7 @@ EXAMPLES:: - sage: A = matrix([[1,1,1],[0,1,2]]) + sage: A = matrix([[1,1,1], [0,1,2]]) sage: IA = ToricIdeal(A) sage: IA.ker() Free module of degree 3 and rank 1 over Integer Ring @@ -34,7 +35,7 @@ this toric ideal ([Stu1997]_, Example 1.2) is the twisted cubic and cannot be generated by `2=\dim \ker(A)` polynomials:: - sage: A = matrix([[3,2,1,0],[0,1,2,3]]) + sage: A = matrix([[3,2,1,0], [0,1,2,3]]) sage: IA = ToricIdeal(A) sage: IA.ker() Free module of degree 4 and rank 2 over Integer Ring @@ -49,7 +50,8 @@ [Stu1997]_. One can show that `I_d` is generated by one quadric and `d` binomials of degree `d`:: - sage: I = lambda d: ToricIdeal(matrix([[1,1,1,1,1],[0,1,1,0,0],[0,0,1,1,d]])) + sage: def I(d): + ....: return ToricIdeal(matrix([[1,1,1,1,1], [0,1,1,0,0], [0,0,1,1,d]])) sage: I(2) Ideal (-z3^2 + z0*z4, z0*z2 - z1*z3, @@ -168,7 +170,7 @@ class ToricIdeal(MPolynomialIdeal): EXAMPLES:: - sage: A = matrix([[1,1,1],[0,1,2]]) + sage: A = matrix([[1,1,1], [0,1,2]]) sage: ToricIdeal(A) Ideal (-z1^2 + z0*z2) of Multivariate Polynomial Ring in z0, z1, z2 over Rational Field @@ -212,7 +214,7 @@ def __init__(self, A, EXAMPLES:: - sage: A = matrix([[1,1,1],[0,1,2]]) + sage: A = matrix([[1,1,1], [0,1,2]]) sage: ToricIdeal(A) Ideal (-z1^2 + z0*z2) of Multivariate Polynomial Ring in z0, z1, z2 over Rational Field @@ -220,14 +222,15 @@ def __init__(self, A, Ideal (-x1^2 + x0*x2) of Multivariate Polynomial Ring in x0, x1, x2 over Finite Field of size 101 sage: ToricIdeal(A, names='x', base_ring=FractionField(QQ['t'])) - Ideal (-x1^2 + x0*x2) of Multivariate Polynomial Ring - in x0, x1, x2 over Fraction Field of Univariate Polynomial Ring in t over Rational Field + Ideal (-x1^2 + x0*x2) of + Multivariate Polynomial Ring in x0, x1, x2 over + Fraction Field of Univariate Polynomial Ring in t over Rational Field """ self._A = matrix(ZZ, A) if polynomial_ring: - if (names!='z') or (base_ring is not QQ): + if names != 'z' or base_ring is not QQ: raise ValueError('you must not specify both variable names and a polynomial ring') - self._names = [str(_) for _ in polynomial_ring.gens()] + self._names = [str(g) for g in polynomial_ring.gens()] self._base_ring = polynomial_ring.base_ring() ring = polynomial_ring else: @@ -235,7 +238,7 @@ def __init__(self, A, self._base_ring = base_ring ring = self._init_ring('degrevlex') - if algorithm=='HostenSturmfels': + if algorithm == 'HostenSturmfels': ideal = self._ideal_HostenSturmfels() else: raise ValueError(f'algorithm = {algorithm} is not known') @@ -247,13 +250,11 @@ def A(self): """ Return the defining matrix. - OUTPUT: - - An integer matrix. + OUTPUT: An integer matrix. EXAMPLES:: - sage: A = matrix([[1,1,1],[0,1,2]]) + sage: A = matrix([[1,1,1], [0,1,2]]) sage: IA = ToricIdeal(A) sage: IA.A() [1 1 1] @@ -265,18 +266,15 @@ def ker(self): """ Return the kernel of the defining matrix. - OUTPUT: - - The kernel of ``self.A()``. + OUTPUT: The kernel of ``self.A()``. EXAMPLES:: - sage: A = matrix([[1,1,1],[0,1,2]]) + sage: A = matrix([[1,1,1], [0,1,2]]) sage: IA = ToricIdeal(A) sage: IA.ker() Free module of degree 3 and rank 1 over Integer Ring - User basis matrix: - [-1 2 -1] + User basis matrix: [-1 2 -1] """ if '_ker' in self.__dict__: @@ -288,14 +286,12 @@ def nvariables(self): r""" Return the number of variables of the ambient polynomial ring. - OUTPUT: - - Integer. The number of columns of the defining matrix + OUTPUT: An integer. The number of columns of the defining matrix :meth:`A`. EXAMPLES:: - sage: A = matrix([[1,1,1],[0,1,2]]) + sage: A = matrix([[1,1,1], [0,1,2]]) sage: IA = ToricIdeal(A) sage: IA.nvariables() 3 @@ -324,7 +320,7 @@ def _init_ring(self, term_order): EXAMPLES:: - sage: A = matrix([[1,1,1],[0,1,2]]) + sage: A = matrix([[1,1,1], [0,1,2]]) sage: IA = ToricIdeal(A) sage: R = IA._init_ring('neglex'); R Multivariate Polynomial Ring in z0, z1, z2 over Rational Field @@ -352,12 +348,11 @@ def _naive_ideal(self, ring): EXAMPLES:: - sage: A = matrix([[1,1,1],[0,1,2]]) + sage: A = matrix([[1,1,1], [0,1,2]]) sage: IA = ToricIdeal(A) sage: IA.ker() Free module of degree 3 and rank 1 over Integer Ring - User basis matrix: - [-1 2 -1] + User basis matrix: [-1 2 -1] sage: IA._naive_ideal(IA.ring()) Ideal (z1^2 - z0*z2) of Multivariate Polynomial Ring in z0, z1, z2 over Rational Field """ @@ -398,13 +393,13 @@ def _ideal_quotient_by_variable(self, ring, ideal, n): sage: IA._ideal_quotient_by_variable(R, J0, 0) Ideal (z2*z3^2 - z0*z1*z4, z1*z3 - z0*z2, z2^2*z3 - z1^2*z4, z1^3*z4 - z0*z2^3) - of Multivariate Polynomial Ring in z0, z1, z2, z3, z4 over Rational Field + of Multivariate Polynomial Ring in z0, z1, z2, z3, z4 over Rational Field """ N = self.nvariables() y = list(ring.gens()) - x = [ y[i-n] for i in range(N) ] - y_to_x = dict(zip(x,y)) - x_to_y = dict(zip(y,x)) + x = [y[i - n] for i in range(N)] + y_to_x = dict(zip(x, y)) + x_to_y = dict(zip(y, x)) # swap variables such that the n-th variable becomes the last one J = ideal.subs(y_to_x) @@ -416,7 +411,7 @@ def _ideal_quotient_by_variable(self, ring, ideal, n): # x_n = y[0] # the cheapest variable in the revlex order def subtract(e, power): l = list(e) - return tuple([l[0]-power] + l[1:]) + return tuple([l[0] - power] + l[1:]) def divide_by_x_n(p): d_old = p.dict() @@ -439,17 +434,17 @@ def _ideal_HostenSturmfels(self): EXAMPLES:: - sage: A = matrix([[3,2,1,0],[0,1,2,3]]) + sage: A = matrix([[3,2,1,0], [0,1,2,3]]) sage: IA = ToricIdeal(A); IA Ideal (-z1*z2 + z0*z3, -z1^2 + z0*z2, z2^2 - z1*z3) - of Multivariate Polynomial Ring in z0, z1, z2, z3 over Rational Field + of Multivariate Polynomial Ring in z0, z1, z2, z3 over Rational Field sage: R = IA.ring() sage: IA == IA._ideal_HostenSturmfels() True TESTS:: - sage: I_2x2 = identity_matrix(ZZ,2) + sage: I_2x2 = identity_matrix(ZZ, 2) sage: ToricIdeal(I_2x2) Ideal (0) of Multivariate Polynomial Ring in z0, z1 over Rational Field """ diff --git a/src/sage/schemes/toric/library.py b/src/sage/schemes/toric/library.py index c8ecbf6a587..d70a3e95d5d 100644 --- a/src/sage/schemes/toric/library.py +++ b/src/sage/schemes/toric/library.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Library of toric varieties @@ -27,7 +28,7 @@ Multivariate Polynomial Ring in x, y, z over Rational Field """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Volker Braun <vbraun.name@gmail.com> # Copyright (C) 2010 Andrey Novoseltsev <novoselt@gmail.com> # @@ -35,16 +36,19 @@ # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.sage_object import SageObject -from sage.matrix.all import matrix, identity_matrix -from sage.geometry.all import Fan, LatticePolytope, ToricLattice +from sage.matrix.constructor import matrix +from sage.matrix.special import identity_matrix +from sage.geometry.fan import Fan +from sage.geometry.lattice_polytope import LatticePolytope +from sage.geometry.toric_lattice import ToricLattice from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.arith.all import gcd +from sage.arith.misc import GCD as gcd from sage.schemes.toric.variety import (DEFAULT_PREFIX, ToricVariety, normalize_names) @@ -118,30 +122,30 @@ (-1, -1, -1), (-1, 1, -1), (1, -1, -1), (1, 1, -1)], [[0,1,2,3],[4,5,6,7],[0,1,7,6],[4,5,3,2],[0,2,5,7],[4,6,1,3]] ], 'BCdlOG':[ - [(-1, 0, 0, 2, 3), # 0 - ( 0,-1, 0, 2, 3), # 1 - ( 0, 0,-1, 2, 3), # 2 - ( 0, 0,-1, 1, 2), # 3 - ( 0, 0, 0,-1, 0), # 4 - ( 0, 0, 0, 0,-1), # 5 - ( 0, 0, 0, 2, 3), # 6 - ( 0, 0, 1, 2, 3), # 7 - ( 0, 0, 2, 2, 3), # 8 - ( 0, 0, 1, 1, 1), # 9 + [(-1, 0, 0, 2, 3), # 0 + ( 0,-1, 0, 2, 3), # 1 + ( 0, 0,-1, 2, 3), # 2 + ( 0, 0,-1, 1, 2), # 3 + ( 0, 0, 0,-1, 0), # 4 + ( 0, 0, 0, 0,-1), # 5 + ( 0, 0, 0, 2, 3), # 6 + ( 0, 0, 1, 2, 3), # 7 + ( 0, 0, 2, 2, 3), # 8 + ( 0, 0, 1, 1, 1), # 9 ( 0, 1, 2, 2, 3), # 10 ( 0, 1, 3, 2, 3), # 11 - ( 1, 0, 4, 2, 3)], # 12 - [ [0,6,7,1,4], [0,6,10,2,4], [0,6,1,2,4], [0,9,7,1,5], [0,6,7,1,5], - [0,6,10,2,5], [0,6,1,2,5], [0,9,1,4,5], [0,6,10,4,11],[0,6,7,4,11], - [0,6,10,5,11], [0,9,7,5,11], [0,6,7,5,11], [0,9,4,5,11], [0,10,4,5,11], - [0,9,7,1,8], [0,9,1,4,8], [0,7,1,4,8], [0,9,7,11,8], [0,9,4,11,8], - [0,7,4,11,8], [0,10,2,4,3], [0,1,2,4,3], [0,10,2,5,3], [0,1,2,5,3], - [0,10,4,5,3], [0,1,4,5,3], [12,6,7,1,4], [12,6,10,2,4],[12,6,1,2,4], - [12,9,7,1,5], [12,6,7,1,5], [12,6,10,2,5], [12,6,1,2,5], [12,9,1,4,5], + ( 1, 0, 4, 2, 3)], # 12 + [ [0,6,7,1,4], [0,6,10,2,4], [0,6,1,2,4], [0,9,7,1,5], [0,6,7,1,5], + [0,6,10,2,5], [0,6,1,2,5], [0,9,1,4,5], [0,6,10,4,11],[0,6,7,4,11], + [0,6,10,5,11], [0,9,7,5,11], [0,6,7,5,11], [0,9,4,5,11], [0,10,4,5,11], + [0,9,7,1,8], [0,9,1,4,8], [0,7,1,4,8], [0,9,7,11,8], [0,9,4,11,8], + [0,7,4,11,8], [0,10,2,4,3], [0,1,2,4,3], [0,10,2,5,3], [0,1,2,5,3], + [0,10,4,5,3], [0,1,4,5,3], [12,6,7,1,4], [12,6,10,2,4],[12,6,1,2,4], + [12,9,7,1,5], [12,6,7,1,5], [12,6,10,2,5], [12,6,1,2,5], [12,9,1,4,5], [12,6,10,4,11],[12,6,7,4,11], [12,6,10,5,11],[12,9,7,5,11],[12,6,7,5,11], - [12,9,4,5,11], [12,10,4,5,11],[12,9,7,1,8], [12,9,1,4,8], [12,7,1,4,8], + [12,9,4,5,11], [12,10,4,5,11],[12,9,7,1,8], [12,9,1,4,8], [12,7,1,4,8], [12,9,7,11,8], [12,9,4,11,8], [12,7,4,11,8], [12,10,2,4,3],[12,1,2,4,3], - [12,10,2,5,3], [12,1,2,5,3], [12,10,4,5,3], [12,1,4,5,3] ] ], + [12,10,2,5,3], [12,1,2,5,3], [12,10,4,5,3], [12,1,4,5,3] ] ], 'BCdlOG_base':[ [(-1, 0, 0), ( 0,-1, 0), @@ -202,9 +206,7 @@ def _make_ToricVariety(self, name, coordinate_names, base_ring): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`toric variety + OUTPUT: A :class:`toric variety <sage.schemes.toric.variety.ToricVariety_field>`. EXAMPLES:: @@ -243,9 +245,7 @@ def _make_CPRFanoToricVariety(self, name, coordinate_names, base_ring): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: @@ -289,23 +289,16 @@ def dP6(self, names='x u y v z w', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: dP6 = toric_varieties.dP6() - sage: dP6 + sage: dP6 = toric_varieties.dP6(); dP6 2-d CPR-Fano toric variety covered by 6 affine patches sage: dP6.fan().rays() - N( 0, 1), - N(-1, 0), - N(-1, -1), - N( 0, -1), - N( 1, 0), - N( 1, 1) + N( 0, 1), N(-1, 0), N(-1, -1), + N( 0, -1), N( 1, 0), N( 1, 1) in 2-d lattice N sage: dP6.gens() (x, u, y, v, z, w) @@ -327,22 +320,16 @@ def dP7(self, names='x u y v z', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: dP7 = toric_varieties.dP7() - sage: dP7 + sage: dP7 = toric_varieties.dP7(); dP7 2-d CPR-Fano toric variety covered by 5 affine patches sage: dP7.fan().rays() - N( 0, 1), - N(-1, 0), - N(-1, -1), - N( 0, -1), - N( 1, 0) + N( 0, 1), N(-1, 0), N(-1, -1), + N( 0, -1), N( 1, 0) in 2-d lattice N sage: dP7.gens() (x, u, y, v, z) @@ -364,21 +351,16 @@ def dP8(self, names='t x y z', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: dP8 = toric_varieties.dP8() - sage: dP8 + sage: dP8 = toric_varieties.dP8(); dP8 2-d CPR-Fano toric variety covered by 4 affine patches sage: dP8.fan().rays() - N( 1, 1), - N( 0, 1), - N(-1, -1), - N( 1, 0) + N( 1, 1), N( 0, 1), + N(-1, -1), N( 1, 0) in 2-d lattice N sage: dP8.gens() (t, x, y, z) @@ -400,21 +382,16 @@ def P1xP1(self, names='s t x y', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: P1xP1 = toric_varieties.P1xP1() - sage: P1xP1 + sage: P1xP1 = toric_varieties.P1xP1(); P1xP1 2-d CPR-Fano toric variety covered by 4 affine patches sage: P1xP1.fan().rays() - N( 1, 0), - N(-1, 0), - N( 0, 1), - N( 0, -1) + N( 1, 0), N(-1, 0), + N( 0, 1), N( 0, -1) in 2-d lattice N sage: P1xP1.gens() (s, t, x, y) @@ -436,21 +413,16 @@ def P1xP1_Z2(self, names='s t x y', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: P1xP1_Z2 = toric_varieties.P1xP1_Z2() - sage: P1xP1_Z2 + sage: P1xP1_Z2 = toric_varieties.P1xP1_Z2(); P1xP1_Z2 2-d CPR-Fano toric variety covered by 4 affine patches sage: P1xP1_Z2.fan().rays() - N( 1, 1), - N(-1, -1), - N(-1, 1), - N( 1, -1) + N( 1, 1), N(-1, -1), + N(-1, 1), N( 1, -1) in 2-d lattice N sage: P1xP1_Z2.gens() (s, t, x, y) @@ -474,15 +446,12 @@ def P1(self, names='s t', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: P1 = toric_varieties.P1() - sage: P1 + sage: P1 = toric_varieties.P1(); P1 1-d CPR-Fano toric variety covered by 2 affine patches sage: P1.fan().rays() N( 1), @@ -508,15 +477,12 @@ def P2(self, names='x y z', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: P2 = toric_varieties.P2() - sage: P2 + sage: P2 = toric_varieties.P2(); P2 2-d CPR-Fano toric variety covered by 3 affine patches sage: P2.fan().rays() N( 1, 0), @@ -544,15 +510,12 @@ def P(self, n, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: P3 = toric_varieties.P(3) - sage: P3 + sage: P3 = toric_varieties.P(3); P3 3-d CPR-Fano toric variety covered by 4 affine patches sage: P3.fan().rays() N( 1, 0, 0), @@ -573,7 +536,7 @@ def P(self, n, names='z+', base_ring=QQ): if n <= 0: raise ValueError("only projective spaces of positive dimension " "can be constructed!\nGot: %s" % n) - m = identity_matrix(n).augment(matrix(n, 1, [-1]*n)) + m = identity_matrix(n).augment(matrix(n, 1, [-1] * n)) charts = [list(range(i)) + list(range(i + 1, n + 1)) for i in range(n + 1)] return CPRFanoToricVariety( @@ -595,15 +558,12 @@ def A1(self, names='z', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`toric variety + OUTPUT: A :class:`toric variety <sage.schemes.toric.variety.ToricVariety_field>`. EXAMPLES:: - sage: A1 = toric_varieties.A1() - sage: A1 + sage: A1 = toric_varieties.A1(); A1 1-d affine toric variety sage: A1.fan().rays() N(1) @@ -627,15 +587,12 @@ def A2(self, names='x y', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`toric variety + OUTPUT: A :class:`toric variety <sage.schemes.toric.variety.ToricVariety_field>`. EXAMPLES:: - sage: A2 = toric_varieties.A2() - sage: A2 + sage: A2 = toric_varieties.A2(); A2 2-d affine toric variety sage: A2.fan().rays() N(1, 0), @@ -662,15 +619,12 @@ def A(self, n, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`toric variety + OUTPUT: A :class:`toric variety <sage.schemes.toric.variety.ToricVariety_field>`. EXAMPLES:: - sage: A3 = toric_varieties.A(3) - sage: A3 + sage: A3 = toric_varieties.A(3); A3 3-d affine toric variety sage: A3.fan().rays() N(1, 0, 0), @@ -710,15 +664,12 @@ def A2_Z2(self, names='x y', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`toric variety + OUTPUT: A :class:`toric variety <sage.schemes.toric.variety.ToricVariety_field>`. EXAMPLES:: - sage: A2_Z2 = toric_varieties.A2_Z2() - sage: A2_Z2 + sage: A2_Z2 = toric_varieties.A2_Z2(); A2_Z2 2-d affine toric variety sage: A2_Z2.fan().rays() N(1, 0), @@ -744,15 +695,12 @@ def P1xA1(self, names='s t z', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`toric variety + OUTPUT: A :class:`toric variety <sage.schemes.toric.variety.ToricVariety_field>`. EXAMPLES:: - sage: P1xA1 = toric_varieties.P1xA1() - sage: P1xA1 + sage: P1xA1 = toric_varieties.P1xA1(); P1xA1 2-d toric variety covered by 2 affine patches sage: P1xA1.fan().rays() N( 1, 0), @@ -778,21 +726,16 @@ def Conifold(self, names='u x y v', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`toric variety + OUTPUT: A :class:`toric variety <sage.schemes.toric.variety.ToricVariety_field>`. EXAMPLES:: - sage: Conifold = toric_varieties.Conifold() - sage: Conifold + sage: Conifold = toric_varieties.Conifold(); Conifold 3-d affine toric variety sage: Conifold.fan().rays() - N(0, 0, 1), - N(0, 1, 1), - N(1, 0, 1), - N(1, 1, 1) + N(0, 0, 1), N(0, 1, 1), + N(1, 0, 1), N(1, 1, 1) in 3-d lattice N sage: Conifold.gens() (u, x, y, v) @@ -814,29 +757,18 @@ def dP6xdP6(self, names='x0 x1 x2 x3 x4 x5 y0 y1 y2 y3 y4 y5', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: dP6xdP6 = toric_varieties.dP6xdP6() - sage: dP6xdP6 + sage: dP6xdP6 = toric_varieties.dP6xdP6(); dP6xdP6 4-d CPR-Fano toric variety covered by 36 affine patches sage: dP6xdP6.fan().rays() - N( 0, 1, 0, 0), - N(-1, 0, 0, 0), - N(-1, -1, 0, 0), - N( 0, -1, 0, 0), - N( 1, 0, 0, 0), - N( 1, 1, 0, 0), - N( 0, 0, 0, 1), - N( 0, 0, -1, 0), - N( 0, 0, -1, -1), - N( 0, 0, 0, -1), - N( 0, 0, 1, 0), - N( 0, 0, 1, 1) + N( 0, 1, 0, 0), N(-1, 0, 0, 0), N(-1, -1, 0, 0), + N( 0, -1, 0, 0), N( 1, 0, 0, 0), N( 1, 1, 0, 0), + N( 0, 0, 0, 1), N( 0, 0, -1, 0), N( 0, 0, -1, -1), + N( 0, 0, 0, -1), N( 0, 0, 1, 0), N( 0, 0, 1, 1) in 4-d lattice N sage: dP6xdP6.gens() (x0, x1, x2, x3, x4, x5, y0, y1, y2, y3, y4, y5) @@ -861,25 +793,16 @@ def Cube_face_fan(self, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: Cube_face_fan = toric_varieties.Cube_face_fan() - sage: Cube_face_fan + sage: Cube_face_fan = toric_varieties.Cube_face_fan(); Cube_face_fan 3-d CPR-Fano toric variety covered by 6 affine patches sage: Cube_face_fan.fan().rays() - N( 1, 1, 1), - N( 1, -1, 1), - N(-1, 1, 1), - N(-1, -1, 1), - N(-1, -1, -1), - N(-1, 1, -1), - N( 1, -1, -1), - N( 1, 1, -1) + N( 1, 1, 1), N( 1, -1, 1), N(-1, 1, 1), N(-1, -1, 1), + N(-1, -1, -1), N(-1, 1, -1), N( 1, -1, -1), N( 1, 1, -1) in 3-d lattice N sage: Cube_face_fan.gens() (z0, z1, z2, z3, z4, z5, z6, z7) @@ -905,25 +828,16 @@ def Cube_sublattice(self, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: Cube_sublattice = toric_varieties.Cube_sublattice() - sage: Cube_sublattice + sage: Cube_sublattice = toric_varieties.Cube_sublattice(); Cube_sublattice 3-d CPR-Fano toric variety covered by 6 affine patches sage: Cube_sublattice.fan().rays() - N( 1, 0, 0), - N( 0, 1, 0), - N( 0, 0, 1), - N(-1, 1, 1), - N(-1, 0, 0), - N( 0, -1, 0), - N( 0, 0, -1), - N( 1, -1, -1) + N( 1, 0, 0), N( 0, 1, 0), N( 0, 0, 1), N(-1, 1, 1), + N(-1, 0, 0), N( 0, -1, 0), N( 0, 0, -1), N( 1, -1, -1) in 3-d lattice N sage: Cube_sublattice.gens() (z0, z1, z2, z3, z4, z5, z6, z7) @@ -949,9 +863,7 @@ def Cube_nonpolyhedral(self, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`toric variety + OUTPUT: A :class:`toric variety <sage.schemes.toric.variety.ToricVariety_field>`. .. NOTE:: @@ -966,14 +878,8 @@ def Cube_nonpolyhedral(self, names='z+', base_ring=QQ): sage: Cube_nonpolyhedral 3-d toric variety covered by 6 affine patches sage: Cube_nonpolyhedral.fan().rays() - N( 1, 2, 3), - N( 1, -1, 1), - N(-1, 1, 1), - N(-1, -1, 1), - N(-1, -1, -1), - N(-1, 1, -1), - N( 1, -1, -1), - N( 1, 1, -1) + N( 1, 2, 3), N( 1, -1, 1), N(-1, 1, 1), N(-1, -1, 1), + N(-1, -1, -1), N(-1, 1, -1), N( 1, -1, -1), N( 1, 1, -1) in 3-d lattice N sage: Cube_nonpolyhedral.gens() (z0, z1, z2, z3, z4, z5, z6, z7) @@ -1011,18 +917,11 @@ def Cube_deformation(self,k, names=None, base_ring=QQ): EXAMPLES:: - sage: X_2 = toric_varieties.Cube_deformation(2) - sage: X_2 + sage: X_2 = toric_varieties.Cube_deformation(2); X_2 3-d toric variety covered by 6 affine patches sage: X_2.fan().rays() - N( 1, 1, 5), - N( 1, -1, 1), - N(-1, 1, 1), - N(-1, -1, 1), - N(-1, -1, -1), - N(-1, 1, -1), - N( 1, -1, -1), - N( 1, 1, -1) + N( 1, 1, 5), N( 1, -1, 1), N(-1, 1, 1), N(-1, -1, 1), + N(-1, -1, -1), N(-1, 1, -1), N( 1, -1, -1), N( 1, 1, -1) in 3-d lattice N sage: X_2.gens() (z0, z1, z2, z3, z4, z5, z6, z7) @@ -1037,9 +936,15 @@ def Cube_deformation(self,k, names=None, base_ring=QQ): if k < 0: raise ValueError("cube deformations X_k are defined only for " "non-negative k!\nGot: %s" % k) - rays = lambda kappa: matrix([[ 1, 1, 2*kappa+1],[ 1,-1, 1],[-1, 1, 1],[-1,-1, 1], - [-1,-1,-1],[-1, 1,-1],[ 1,-1,-1],[ 1, 1,-1]]) - cones = [[0,1,2,3],[4,5,6,7],[0,1,7,6],[4,5,3,2],[0,2,5,7],[4,6,1,3]] + + def rays(kappa): + return matrix([[1, 1, 2 * kappa + 1], [1, -1, 1], + [-1, 1, 1], [-1, -1, 1], + [-1, -1, -1], [-1, 1, -1], + [1, -1, -1], [1, 1, -1]]) + + cones = [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], + [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]] fan = Fan(cones, rays(k)) return ToricVariety(fan, coordinate_names=names) @@ -1058,29 +963,20 @@ def BCdlOG(self, names='v1 v2 c1 c2 v4 v5 b e1 e2 e3 f g v6', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: X = toric_varieties.BCdlOG() - sage: X + sage: X = toric_varieties.BCdlOG(); X 5-d CPR-Fano toric variety covered by 54 affine patches sage: X.fan().rays() - N(-1, 0, 0, 2, 3), - N( 0, -1, 0, 2, 3), - N( 0, 0, -1, 2, 3), - N( 0, 0, -1, 1, 2), - N( 0, 0, 0, -1, 0), - N( 0, 0, 0, 0, -1), - N( 0, 0, 0, 2, 3), - N( 0, 0, 1, 2, 3), - N( 0, 0, 2, 2, 3), - N( 0, 0, 1, 1, 1), - N( 0, 1, 2, 2, 3), - N( 0, 1, 3, 2, 3), + N(-1, 0, 0, 2, 3), N( 0, -1, 0, 2, 3), + N( 0, 0, -1, 2, 3), N( 0, 0, -1, 1, 2), + N( 0, 0, 0, -1, 0), N( 0, 0, 0, 0, -1), + N( 0, 0, 0, 2, 3), N( 0, 0, 1, 2, 3), + N( 0, 0, 2, 2, 3), N( 0, 0, 1, 1, 1), + N( 0, 1, 2, 2, 3), N( 0, 1, 3, 2, 3), N( 1, 0, 4, 2, 3) in 5-d lattice N sage: X.gens() @@ -1103,24 +999,16 @@ def BCdlOG_base(self, names='d4 d3 r2 r1 d2 u d1', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`toric variety + OUTPUT: A :class:`toric variety <sage.schemes.toric.variety.ToricVariety_field>`. EXAMPLES:: - sage: base = toric_varieties.BCdlOG_base() - sage: base + sage: base = toric_varieties.BCdlOG_base(); base 3-d toric variety covered by 10 affine patches sage: base.fan().rays() - N(-1, 0, 0), - N( 0, -1, 0), - N( 0, 0, -1), - N( 0, 0, 1), - N( 0, 1, 2), - N( 0, 1, 3), - N( 1, 0, 4) + N(-1, 0, 0), N( 0, -1, 0), N( 0, 0, -1), N( 0, 0, 1), + N( 0, 1, 2), N( 0, 1, 3), N( 1, 0, 4) in 3-d lattice N sage: base.gens() (d4, d3, r2, r1, d2, u, d1) @@ -1142,15 +1030,12 @@ def P2_112(self, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: P2_112 = toric_varieties.P2_112() - sage: P2_112 + sage: P2_112 = toric_varieties.P2_112(); P2_112 2-d CPR-Fano toric variety covered by 3 affine patches sage: P2_112.fan().rays() N( 1, 0), @@ -1177,15 +1062,12 @@ def P2_123(self, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: P2_123 = toric_varieties.P2_123() - sage: P2_123 + sage: P2_123 = toric_varieties.P2_123(); P2_123 2-d CPR-Fano toric variety covered by 3 affine patches sage: P2_123.fan().rays() N( 1, 0), @@ -1212,22 +1094,16 @@ def P4_11169(self, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: P4_11169 = toric_varieties.P4_11169() - sage: P4_11169 + sage: P4_11169 = toric_varieties.P4_11169(); P4_11169 4-d CPR-Fano toric variety covered by 5 affine patches sage: P4_11169.fan().rays() - N( 1, 0, 0, 0), - N( 0, 1, 0, 0), - N( 0, 0, 1, 0), - N( 0, 0, 0, 1), - N(-9, -6, -1, -1) + N( 1, 0, 0, 0), N( 0, 1, 0, 0), N( 0, 0, 1, 0), + N( 0, 0, 0, 1), N(-9, -6, -1, -1) in 4-d lattice N sage: P4_11169.gens() (z0, z1, z2, z3, z4) @@ -1250,9 +1126,7 @@ def P4_11169_resolved(self, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: @@ -1261,12 +1135,8 @@ def P4_11169_resolved(self, names='z+', base_ring=QQ): sage: P4_11169_resolved 4-d CPR-Fano toric variety covered by 9 affine patches sage: P4_11169_resolved.fan().rays() - N( 1, 0, 0, 0), - N( 0, 1, 0, 0), - N( 0, 0, 1, 0), - N( 0, 0, 0, 1), - N(-9, -6, -1, -1), - N(-3, -2, 0, 0) + N( 1, 0, 0, 0), N( 0, 1, 0, 0), N( 0, 0, 1, 0), + N( 0, 0, 0, 1), N(-9, -6, -1, -1), N(-3, -2, 0, 0) in 4-d lattice N sage: P4_11169_resolved.gens() (z0, z1, z2, z3, z4, z5) @@ -1288,22 +1158,16 @@ def P4_11133(self, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: - sage: P4_11133 = toric_varieties.P4_11133() - sage: P4_11133 + sage: P4_11133 = toric_varieties.P4_11133(); P4_11133 4-d CPR-Fano toric variety covered by 5 affine patches sage: P4_11133.fan().rays() - N( 1, 0, 0, 0), - N( 0, 1, 0, 0), - N( 0, 0, 1, 0), - N( 0, 0, 0, 1), - N(-3, -3, -1, -1) + N( 1, 0, 0, 0), N( 0, 1, 0, 0), N( 0, 0, 1, 0), + N( 0, 0, 0, 1), N(-3, -3, -1, -1) in 4-d lattice N sage: P4_11133.gens() (z0, z1, z2, z3, z4) @@ -1325,9 +1189,7 @@ def P4_11133_resolved(self, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`CPR-Fano toric variety + OUTPUT: A :class:`CPR-Fano toric variety <sage.schemes.toric.fano_variety.CPRFanoToricVariety_field>`. EXAMPLES:: @@ -1336,12 +1198,8 @@ def P4_11133_resolved(self, names='z+', base_ring=QQ): sage: P4_11133_resolved 4-d CPR-Fano toric variety covered by 9 affine patches sage: P4_11133_resolved.fan().rays() - N( 1, 0, 0, 0), - N( 0, 1, 0, 0), - N( 0, 0, 1, 0), - N( 0, 0, 0, 1), - N(-3, -3, -1, -1), - N(-1, -1, 0, 0) + N( 1, 0, 0, 0), N( 0, 1, 0, 0), N( 0, 0, 1, 0), + N( 0, 0, 0, 1), N(-3, -3, -1, -1), N(-1, -1, 0, 0) in 4-d lattice N sage: P4_11133_resolved.gens() (z0, z1, z2, z3, z4, z5) @@ -1386,7 +1244,7 @@ def WP(self, *q, **kw): sage: X = toric_varieties.WP([1,3,1], names='x y z') sage: X.inject_variables() Defining x, y, z - sage: g = y^2-(x^6-z^6) + sage: g = y^2 - (x^6-z^6) sage: C = X.subscheme([g]); C Closed subscheme of 2-d toric variety covered by 3 affine patches defined by: -x^6 + z^6 + y^2 @@ -1426,7 +1284,7 @@ def WP(self, *q, **kw): L = ToricLattice(m) L_sub = L.submodule([L(q)]) - Q = L/L_sub + Q = L / L_sub rays = [] cones = [] w = list(range(m)) @@ -1435,7 +1293,7 @@ def WP(self, *q, **kw): b = L_basis[i] v = Q.coordinate_vector(Q(b)) rays = rays + [v] - w_c = w[:i] + w[i+1:] + w_c = w[:i] + w[i + 1:] cones = cones + [tuple(w_c)] fan = Fan(cones,rays) return ToricVariety(fan, coordinate_names=names, base_ring=base_ring) @@ -1456,9 +1314,7 @@ def torus(self, n, names='z+', base_ring=QQ): - ``base_ring`` -- a ring (default: `\QQ`). The base ring for the toric variety. - OUTPUT: - - A :class:`toric variety + OUTPUT: A :class:`toric variety <sage.schemes.toric.variety.ToricVariety_field>`. EXAMPLES:: diff --git a/src/sage/schemes/toric/morphism.py b/src/sage/schemes/toric/morphism.py index c86503bd699..1c8944b6dfc 100644 --- a/src/sage/schemes/toric/morphism.py +++ b/src/sage/schemes/toric/morphism.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Morphisms of toric varieties @@ -48,12 +49,11 @@ sage: P2.<x,y,z> = toric_varieties.P2() sage: P1.<u,v> = toric_varieties.P1() - sage: P1.hom([0,u^2+v^2,u*v], P2) + sage: P1.hom([0, u^2 + v^2, u*v], P2) Scheme morphism: From: 1-d CPR-Fano toric variety covered by 2 affine patches To: 2-d CPR-Fano toric variety covered by 3 affine patches - Defn: Defined on coordinates by sending [u : v] to - [0 : u^2 + v^2 : u*v] + Defn: Defined on coordinates by sending [u : v] to [0 : u^2 + v^2 : u*v] This is a well-defined morphism of algebraic varieties because homogeneously rescaled coordinates of a point of `\mathbb{P}^1` map to the same @@ -78,8 +78,7 @@ Scheme morphism: From: 1-d CPR-Fano toric variety covered by 2 affine patches To: 2-d CPR-Fano toric variety covered by 3 affine patches - Defn: Defined on coordinates by sending [u : v] to - [0 : u : v] + Defn: Defined on coordinates by sending [u : v] to [0 : u : v] This map is actually the embedding of the :meth:`~sage.schemes.toric.variety.ToricVariety_field.orbit_closure` @@ -93,7 +92,7 @@ Consider instead the following morphism of fans:: - sage: fm = FanMorphism( matrix(ZZ,[[1,0]]), P1.fan(), P2.fan() ); fm + sage: fm = FanMorphism(matrix(ZZ, [[1,0]]), P1.fan(), P2.fan()); fm Fan morphism defined by the matrix [1 0] Domain fan: Rational polyhedral fan in 1-d lattice N @@ -114,8 +113,7 @@ Scheme morphism: From: 1-d CPR-Fano toric variety covered by 2 affine patches To: 2-d CPR-Fano toric variety covered by 3 affine patches - Defn: Defined on coordinates by sending [u : v] to - [u : v : v] + Defn: Defined on coordinates by sending [u : v] to [u : v : v] Finally, here is an example of a fan morphism that cannot be written using homogeneous polynomials. Consider the blowup `O_{\mathbb{P}^1}(2) @@ -174,8 +172,7 @@ Scheme morphism: From: 0-d affine toric variety To: 2-d affine toric variety - Defn: Defined on coordinates by sending [] to - [1 : 1] + Defn: Defined on coordinates by sending [] to [1 : 1] The fibers are labeled by torus orbits in the base, that is, cones of the codomain fan. In this case, the fibers over lower-dimensional @@ -217,7 +214,8 @@ 2-dimensional cone, which represents the exceptional set of the blow-up in this single coordinate chart. Lets investigate further:: - sage: exceptional_cones = single_chart.fan_morphism().primitive_preimage_cones(A2_Z2.fan(2)[0]) + sage: fm = single_chart.fan_morphism() + sage: exceptional_cones = fm.primitive_preimage_cones(A2_Z2.fan(2)[0]) sage: exceptional_set = single_chart.fiber_component(exceptional_cones[0]) sage: exceptional_set 1-d affine toric variety @@ -225,8 +223,7 @@ Scheme morphism: From: 1-d affine toric variety To: 2-d affine toric variety - Defn: Defined on coordinates by sending [z0] to - [z0 : 0] + Defn: Defined on coordinates by sending [z0] to [z0 : 0] So we see that the fiber over this point is an affine line. Together with another affine line in the other coordinate patch, this covers @@ -237,7 +234,7 @@ sage: A3 = toric_varieties.A(3) sage: P3 = toric_varieties.P(3) - sage: m = matrix([(2,0,0), (1,1,0), (3, 1, 0)]) + sage: m = matrix([(2,0,0), (1,1,0), (3,1,0)]) sage: phi = A3.hom(m, P3) sage: phi.as_polynomial_map() Scheme morphism: @@ -348,7 +345,7 @@ 1 connected components over (1, 2), each with 2 irreducible components. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Volker Braun <vbraun.name@gmail.com> # Copyright (C) 2010 Andrey Novoseltsev <novoselt@gmail.com> # Copyright (C) 2006 William Stein <wstein@gmail.com> @@ -357,8 +354,8 @@ # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** # For now, the scheme morphism base class cannot derive from Morphism # since this would clash with elliptic curves. So we derive only on @@ -370,11 +367,12 @@ from sage.structure.sequence import Sequence from sage.rings.integer_ring import ZZ -from sage.arith.all import gcd +from sage.arith.misc import GCD as gcd from sage.misc.cachefunc import cached_method from sage.matrix.constructor import matrix, identity_matrix from sage.modules.free_module_element import vector -from sage.geometry.all import Cone, Fan +from sage.geometry.cone import Cone +from sage.geometry.fan import Fan from sage.schemes.generic.scheme import is_Scheme from sage.schemes.generic.morphism import ( @@ -407,9 +405,7 @@ class SchemeMorphism_point_toric_field(SchemeMorphism_point, Morphism): - ``check`` -- if ``True`` (default), the input will be checked for correctness. - OUTPUT: - - A :class:`SchemeMorphism_point_toric_field`. + OUTPUT: A :class:`SchemeMorphism_point_toric_field`. TESTS:: @@ -470,16 +466,14 @@ class SchemeMorphism_polynomial_toric_variety(SchemeMorphism_polynomial, Morphis Same as for :class:`~sage.schemes.toric.morphism.SchemeMorphism_polynomial`. - OUTPUT: - - A :class:`~sage.schemes.toric.morphism.SchemeMorphism_polynomial_toric_variety`. + OUTPUT: A :class:`~sage.schemes.toric.morphism.SchemeMorphism_polynomial_toric_variety`. TESTS:: sage: P1xP1 = toric_varieties.P1xP1() sage: P1xP1.inject_variables() Defining s, t, x, y - sage: P1 = P1xP1.subscheme(s-t) + sage: P1 = P1xP1.subscheme(s - t) sage: H = P1xP1.Hom(P1) sage: import sage.schemes.toric.morphism as MOR sage: MOR.SchemeMorphism_polynomial_toric_variety(H, [s, s, x, y]) @@ -501,7 +495,7 @@ def __init__(self, parent, polynomials, check=True): sage: P1xP1 = toric_varieties.P1xP1() sage: P1xP1.inject_variables() Defining s, t, x, y - sage: P1 = P1xP1.subscheme(s-t) + sage: P1 = P1xP1.subscheme(s - t) sage: H = P1xP1.Hom(P1) sage: import sage.schemes.toric.morphism as MOR sage: MOR.SchemeMorphism_polynomial_toric_variety(H, [s, s, x, y]) @@ -525,10 +519,9 @@ def as_fan_morphism(self): """ Express the morphism as a map defined by a fan morphism. - OUTPUT: + OUTPUT: A :class:`SchemeMorphism_polynomial_toric_variety`. - A :class:`SchemeMorphism_polynomial_toric_variety`. Raises a - ``TypeError`` if the morphism cannot be written in such a way. + Raises a ``TypeError`` if the morphism cannot be written in such a way. EXAMPLES:: @@ -611,9 +604,7 @@ def defining_cone(self): r""" Return the cone corresponding to the torus orbit. - OUTPUT: - - A cone of the fan of the ambient toric variety. + OUTPUT: A cone of the fan of the ambient toric variety. EXAMPLES:: @@ -634,8 +625,8 @@ def _reverse_ray_map(self): OUTPUT: - Return a dictionary `{orbit ray generator : preimage ray - index}`. Note that the orbit ray generator need not be + A dictionary ``{orbit ray generator: preimage ray + index}``. Note that the orbit ray generator need not be primitive. Also, the preimage ray is not necessarily unique. EXAMPLES:: @@ -650,7 +641,7 @@ def _reverse_ray_map(self): """ orbit = self.parent().domain() codomain_fan = self.parent().codomain().fan() - reverse_ray_dict = dict() + reverse_ray_dict = {} for n1, n2 in self._ray_map.items(): ray_index = codomain_fan.rays().index(n1) if n2.is_zero(): @@ -678,7 +669,7 @@ def _repr_defn(self): 'Defined by embedding the torus closure associated to the 1-d cone of Rational polyhedral fan in 2-d lattice N.' """ - s = 'Defined by embedding the torus closure associated to the ' + s = 'Defined by embedding the torus closure associated to the ' s += str(self._defining_cone) s += '.' return s @@ -710,8 +701,7 @@ def as_polynomial_map(self): Scheme morphism: From: 1-d toric variety covered by 2 affine patches To: 2-d CPR-Fano toric variety covered by 3 affine patches - Defn: Defined on coordinates by sending [z0 : z1] to - [0 : z1 : z0] + Defn: Defined on coordinates by sending [z0 : z1] to [0 : z1 : z0] If the toric variety is singular, then some orbit closure embeddings cannot be written with homogeneous polynomials:: @@ -744,7 +734,7 @@ def pullback_divisor(self, divisor): INPUT: - - ``divisor`` -- a torus-invariant QQ-Cartier divisor on the + - ``divisor`` -- a torus-invariant `\QQ`-Cartier divisor on the codomain of the embedding map. OUTPUT: @@ -771,7 +761,7 @@ def pullback_divisor(self, divisor): codomain_rays = self.codomain().fan().rays() for ray in self.domain().fan().rays(): ray = codomain_rays[self._reverse_ray_map()[ray]] - value = divisor.function_value(ray) - m*ray + value = divisor.function_value(ray) - m * ray values.append(value) return self.domain().divisor(values) @@ -811,9 +801,7 @@ class SchemeMorphism_fan_toric_variety(SchemeMorphism, Morphism): :class:`SchemeMorphism_fan_toric_variety_dominant` for additional functionality for fibrations. - OUTPUT: - - A :class:`~sage.schemes.toric.morphism.SchemeMorphism_fan_toric_variety`. + OUTPUT: A :class:`~sage.schemes.toric.morphism.SchemeMorphism_fan_toric_variety`. EXAMPLES:: @@ -833,13 +821,13 @@ class SchemeMorphism_fan_toric_variety(SchemeMorphism, Morphism): sage: P1xP1 = toric_varieties.P1xP1() sage: P1 = toric_varieties.P1() sage: hom_set = P1xP1.Hom(P1) - sage: fm = FanMorphism( matrix(ZZ,[[1],[0]]), P1xP1.fan(), P1.fan() ) + sage: fm = FanMorphism(matrix(ZZ, [[1],[0]]), P1xP1.fan(), P1.fan()) sage: hom_set(fm) Scheme morphism: From: 2-d CPR-Fano toric variety covered by 4 affine patches To: 1-d CPR-Fano toric variety covered by 2 affine patches Defn: Defined by sending Rational polyhedral fan in 2-d lattice N - to Rational polyhedral fan in 1-d lattice N. + to Rational polyhedral fan in 1-d lattice N. sage: P1xP1.hom(fm, P1) Scheme morphism: @@ -858,7 +846,7 @@ def __init__(self, parent, fan_morphism, check=True): sage: P1xP1 = toric_varieties.P1xP1() sage: P1 = toric_varieties.P1() sage: hom_set = P1xP1.Hom(P1) - sage: fan_morphism = FanMorphism( matrix(ZZ,[[1],[0]]), P1xP1.fan(), P1.fan() ) + sage: fan_morphism = FanMorphism(matrix(ZZ, [[1],[0]]), P1xP1.fan(), P1.fan()) sage: from sage.schemes.toric.morphism import SchemeMorphism_fan_toric_variety sage: SchemeMorphism_fan_toric_variety(hom_set, fan_morphism) Scheme morphism: @@ -868,9 +856,9 @@ def __init__(self, parent, fan_morphism, check=True): to Rational polyhedral fan in 1-d lattice N. """ SchemeMorphism.__init__(self, parent) - if check and self.domain().fan()!=fan_morphism.domain_fan(): + if check and self.domain().fan() != fan_morphism.domain_fan(): raise ValueError('the fan morphism domain must be the fan of the domain') - if check and self.codomain().fan()!=fan_morphism.codomain_fan(): + if check and self.codomain().fan() != fan_morphism.codomain_fan(): raise ValueError('the fan morphism codomain must be the fan of the codomain') self._fan_morphism = fan_morphism @@ -882,9 +870,7 @@ def _richcmp_(self, right, op): - ``right`` -- another toric morphism - OUTPUT: - - - boolean + OUTPUT: A boolean. Comparison is done first by domain, then by codomain, then by fan morphism. @@ -925,9 +911,7 @@ def _composition_(self, right, homset): - ``right`` -- a toric morphism defined by a fan morphism. - OUTPUT: - - - a toric morphism. + OUTPUT: A toric morphism. EXAMPLES:: @@ -964,7 +948,7 @@ def _repr_defn(self): sage: f._repr_defn() 'Defined by sending Rational polyhedral fan in 2-d lattice N to Rational polyhedral fan in 1-d lattice N.' """ - s = 'Defined by sending ' + s = 'Defined by sending ' s += str(self.domain().fan()) s += ' to ' s += str(self.codomain().fan()) @@ -1034,8 +1018,7 @@ def factor(self): Scheme morphism: From: 2-d affine toric variety To: 2-d affine toric variety - Defn: Defined on coordinates by sending [x : y] to - [x^2 : y] + Defn: Defined on coordinates by sending [x : y] to [x^2 : y] Blowup chart (birational):: @@ -1043,8 +1026,7 @@ def factor(self): Scheme morphism: From: 2-d affine toric variety To: 2-d toric variety covered by 3 affine patches - Defn: Defined on coordinates by sending [z0 : z1] to - [1 : z1 : z0*z1] + Defn: Defined on coordinates by sending [z0 : z1] to [1 : z1 : z0*z1] Coordinate plane inclusion (injective):: @@ -1052,11 +1034,10 @@ def factor(self): Scheme morphism: From: 2-d toric variety covered by 3 affine patches To: 3-d CPR-Fano toric variety covered by 4 affine patches - Defn: Defined on coordinates by sending [z0 : z1 : z2] to - [z2 : z1 : z0 : z0] + Defn: Defined on coordinates by sending [z0 : z1 : z2] to [z2 : z1 : z0 : z0] """ phi_i, phi_b, phi_s = self.fan_morphism().factor() - from sage.schemes.toric.all import ToricVariety + from sage.schemes.toric.variety import ToricVariety X = self.domain() X_s = ToricVariety(phi_s.codomain_fan()) X_i = ToricVariety(phi_i.domain_fan()) @@ -1067,9 +1048,7 @@ def fan_morphism(self): """ Return the defining fan morphism. - OUTPUT: - - A :class:`~sage.geometry.fan_morphism.FanMorphism`. + OUTPUT: A :class:`~sage.geometry.fan_morphism.FanMorphism`. EXAMPLES:: @@ -1089,10 +1068,9 @@ def as_polynomial_map(self): """ Express the morphism via homogeneous polynomials. - OUTPUT: + OUTPUT: A :class:`SchemeMorphism_polynomial_toric_variety`. - A :class:`SchemeMorphism_polynomial_toric_variety`. Raises a - ``TypeError`` if the morphism cannot be written in terms of + Raises a ``TypeError`` if the morphism cannot be written in terms of homogeneous polynomials. EXAMPLES:: @@ -1101,8 +1079,7 @@ def as_polynomial_map(self): sage: square = A1.hom(matrix([[2]]), A1) sage: square.as_polynomial_map() Scheme endomorphism of 1-d affine toric variety - Defn: Defined on coordinates by sending [z] to - [z^2] + Defn: Defined on coordinates by sending [z] to [z^2] sage: P1 = toric_varieties.P1() sage: patch = A1.hom(matrix([[1]]), P1) @@ -1110,8 +1087,7 @@ def as_polynomial_map(self): Scheme morphism: From: 1-d affine toric variety To: 1-d CPR-Fano toric variety covered by 2 affine patches - Defn: Defined on coordinates by sending [z] to - [z : 1] + Defn: Defined on coordinates by sending [z] to [z : 1] """ R = self.domain().coordinate_ring() phi = self.fan_morphism() @@ -1300,7 +1276,7 @@ def pullback_divisor(self, divisor): INPUT: - - ``divisor`` -- a torus-invariant QQ-Cartier divisor on the + - ``divisor`` -- a torus-invariant `\QQ`-Cartier divisor on the codomain of ``self``. OUTPUT: @@ -1311,7 +1287,7 @@ def pullback_divisor(self, divisor): sage: A2_Z2 = toric_varieties.A2_Z2() sage: A2 = toric_varieties.A2() - sage: f = A2.hom( matrix([[1,0],[1,2]]), A2_Z2) + sage: f = A2.hom(matrix([[1,0], [1,2]]), A2_Z2) sage: f.pullback_divisor(A2_Z2.divisor(0)) V(x) @@ -1357,9 +1333,7 @@ class SchemeMorphism_fan_toric_variety_dominant(SchemeMorphism_fan_toric_variety morphism :meth:`must be dominant <sage.geometry.fan_morphism.FanMorphism.is_dominant>`. - OUTPUT: - - A :class:`~sage.schemes.toric.morphism.SchemeMorphism_fan_toric_variety_dominant`. + OUTPUT: A :class:`~sage.schemes.toric.morphism.SchemeMorphism_fan_toric_variety_dominant`. EXAMPLES:: @@ -1419,11 +1393,10 @@ def fiber_generic(self): Scheme morphism: From: 1-d toric variety covered by 2 affine patches To: 2-d CPR-Fano toric variety covered by 4 affine patches - Defn: Defined on coordinates by sending [z0 : z1] to - [1 : 1 : z0 : z1] + Defn: Defined on coordinates by sending [z0 : z1] to [1 : 1 : z0 : z1] sage: A1 = toric_varieties.A1() - sage: fan = Fan([(0,1,2)], [(1,1,0),(1,0,1),(1,-1,-1)]) + sage: fan = Fan([(0,1,2)], [(1,1,0), (1,0,1), (1,-1,-1)]) sage: fan = fan.subdivide(new_rays=[(1,0,0)]) sage: f = ToricVariety(fan).hom(matrix([[1],[0],[0]]), A1) sage: f.fiber_generic() @@ -1478,10 +1451,11 @@ def fiber_component(self, domain_cone, multiplicity=False): ....: (0,1,0,0),(0,2,-1,-1),(1,0,0,0),(2,0,-1,-1)]) sage: coarse_fan = FaceFan(polytope) sage: P2 = toric_varieties.P2() - sage: proj24 = matrix([[0,0],[1,0],[0,0],[0,1]]) + sage: proj24 = matrix([[0,0], [1,0], [0,0], [0,1]]) sage: fm = FanMorphism(proj24, coarse_fan, P2.fan(), subdivide=True) sage: fibration = ToricVariety(fm.domain_fan()).hom(fm, P2) - sage: primitive_cones = fibration.fan_morphism().primitive_preimage_cones(P2.fan(1)[0]) + sage: ffm = fibration.fan_morphism() + sage: primitive_cones = ffm.primitive_preimage_cones(P2.fan(1)[0]) sage: primitive_cone = primitive_cones[0] sage: fibration.fiber_component(primitive_cone) 2-d toric variety covered by 4 affine patches @@ -1597,11 +1571,12 @@ def fiber_graph(self, codomain_cone): sage: coarse_fan = FaceFan(polytope, lattice=ToricLattice(4)) sage: P2 = toric_varieties.P2() - sage: proj34 = block_matrix(2,1,[zero_matrix(2,2), identity_matrix(2)]) + sage: proj34 = block_matrix(2, 1, [zero_matrix(2,2), + ....: identity_matrix(2)]) sage: fm = FanMorphism(proj34, coarse_fan, P2.fan(), subdivide=True) sage: fibration = ToricVariety(fm.domain_fan()).hom(fm, P2) - sage: fibration.fiber_graph( P2.fan(0)[0] ) + sage: fibration.fiber_graph(P2.fan(0)[0]) Graph on 1 vertex sage: for c1 in P2.fan(1): ....: fibration.fiber_graph(c1) @@ -1674,7 +1649,8 @@ class SchemeMorphism_fan_fiber_component_toric_variety(SchemeMorphism): sage: proj24 = matrix([[0,0],[1,0],[0,0],[0,1]]) sage: fm = FanMorphism(proj24, coarse_fan, P2.fan(), subdivide=True) sage: fibration = ToricVariety(fm.domain_fan()).hom(fm, P2) - sage: primitive_cones = fibration.fan_morphism().primitive_preimage_cones(P2.fan(1)[0]) + sage: ffm = fibration.fan_morphism() + sage: primitive_cones = ffm.primitive_preimage_cones(P2.fan(1)[0]) sage: primitive_cone = primitive_cones[0] sage: fiber_component = fibration.fiber_component(primitive_cone) sage: fiber_component @@ -1706,7 +1682,7 @@ def __init__(self, toric_morphism, defining_cone): ....: (0,1,0,0),(0,2,-1,-1),(1,0,0,0),(2,0,-1,-1)]) sage: coarse_fan = FaceFan(polytope, lattice=ToricLattice(4)) sage: P2 = toric_varieties.P2() - sage: proj24 = matrix([[0,0],[1,0],[0,0],[0,1]]) + sage: proj24 = matrix([[0,0], [1,0], [0,0], [0,1]]) sage: fm = FanMorphism(proj24, coarse_fan, P2.fan(), subdivide=True) sage: fibration = ToricVariety(fm.domain_fan()).hom(fm, P2) sage: primitive_cone = Cone([(-1, 2, -1, 0)]) @@ -1762,7 +1738,7 @@ def as_polynomial_map(self): ....: (0,1,0,0),(0,2,-1,-1),(1,0,0,0),(2,0,-1,-1)]) sage: coarse_fan = FaceFan(polytope, lattice=ToricLattice(4)) sage: P2 = toric_varieties.P2() - sage: proj24 = matrix([[0,0],[1,0],[0,0],[0,1]]) + sage: proj24 = matrix([[0,0], [1,0], [0,0], [0,1]]) sage: fm = FanMorphism(proj24, coarse_fan, P2.fan(), subdivide=True) sage: fibration = ToricVariety(fm.domain_fan()).hom(fm, P2) @@ -1841,7 +1817,7 @@ def _make_fiber_component(self): ker = fm.kernel().basis() m = fm.matrix() * base_cone.lattice().basis_matrix() base_cone_preimg = [m.solve_left(r) for r in base_cone.rays()] - L = fm.domain_fan().lattice().span(ker+base_cone_preimg).saturation() + L = fm.domain_fan().lattice().span(ker + base_cone_preimg).saturation() cone_L = Cone([L.coordinates(r) for r in defining_cone.rays()]) L_quotient = cone_L.sublattice_quotient() @@ -1858,7 +1834,7 @@ def projection(ray): cones.append(Cone(projected_rays)) fiber_fan = Fan(cones) - ray_index_map = dict() + ray_index_map = {} for ray in star_rays: ray_index = fm.domain_fan().rays().index(ray) projected_ray = fiber_fan.lattice()(projection(ray)) @@ -1939,7 +1915,7 @@ def _image_ray_multiplicity(self, fiber_ray): ....: (0,1,0,0),(0,2,-1,-1),(1,0,0,0),(2,0,-1,-1)]) sage: coarse_fan = FaceFan(polytope, lattice=ToricLattice(4)) sage: P2 = toric_varieties.P2() - sage: proj24 = matrix([[0,0],[1,0],[0,0],[0,1]]) + sage: proj24 = matrix([[0,0], [1,0], [0,0], [0,1]]) sage: fm = FanMorphism(proj24, coarse_fan, P2.fan(), subdivide=True) sage: fibration = ToricVariety(fm.domain_fan()).hom(fm, P2) sage: primitive_cone = Cone([(-1, 2, -1, 0)]) @@ -1964,7 +1940,7 @@ def _image_ray_multiplicity(self, fiber_ray): d = gcd(ray) if d * fiber_ray != ray: continue - if multiplicity is not None and d>multiplicity: + if multiplicity is not None and d > multiplicity: continue multiplicity = d image_ray_index = index @@ -1976,7 +1952,7 @@ def pullback_divisor(self, divisor): INPUT: - - ``divisor`` -- a torus-invariant QQ-Cartier divisor on the + - ``divisor`` -- a torus-invariant `\QQ`-Cartier divisor on the codomain of the embedding map. OUTPUT: @@ -2009,7 +1985,7 @@ def pullback_divisor(self, divisor): for ray in self.domain().fan().rays(): image_ray_index, multiplicity = self._image_ray_multiplicity(ray) image_ray = codomain_rays[image_ray_index] - value = divisor.function_value(image_ray) - m*image_ray + value = divisor.function_value(image_ray) - m * image_ray value /= multiplicity values.append(value) return self.domain().divisor(values) diff --git a/src/sage/schemes/toric/points.py b/src/sage/schemes/toric/points.py index 5da8f26a9c5..f9563bd0acc 100644 --- a/src/sage/schemes/toric/points.py +++ b/src/sage/schemes/toric/points.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.geometry.polyhedron sage.graphs """ Enumerate points of a toric variety @@ -39,7 +39,7 @@ from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method -from sage.arith.all import gcd +from sage.arith.misc import GCD as gcd from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.parallel.decorate import Parallel @@ -82,9 +82,7 @@ def __iter__(self): """ Iterate over the points. - OUTPUT: - - Iterator over points. + OUTPUT: Iterator over points. EXAMPLES:: @@ -138,9 +136,7 @@ def rays(self): """ Return all rays (real and virtual). - OUTPUT: - - Tuple of rays of the fan. + OUTPUT: Tuple of rays of the fan. EXAMPLES:: @@ -164,7 +160,8 @@ def units(self): EXAMPLES:: - sage: ne = toric_varieties.P2(base_ring=GF(5)).point_set()._naive_enumerator() + sage: P2 = toric_varieties.P2(base_ring=GF(5)) + sage: ne = P2.point_set()._naive_enumerator() sage: ne.units() (1, 2, 3, 4) """ @@ -186,7 +183,8 @@ def roots(self, n): EXAMPLES:: - sage: ne = toric_varieties.P2(base_ring=GF(5)).point_set()._naive_enumerator() + sage: P2 = toric_varieties.P2(base_ring=GF(5)) + sage: ne = P2.point_set()._naive_enumerator() sage: ne.roots(2) (1, 4) sage: ne.roots(3) @@ -269,15 +267,18 @@ def rescalings(self): EXAMPLES:: - sage: ni = toric_varieties.P2_123(base_ring=GF(5)).point_set()._naive_enumerator() + sage: P2_123 = toric_varieties.P2_123(base_ring=GF(5)) + sage: ni = P2_123.point_set()._naive_enumerator() sage: ni.rescalings() ((1, 1, 1), (1, 4, 4), (4, 2, 3), (4, 3, 2)) - sage: ni = toric_varieties.dP8(base_ring=GF(3)).point_set()._naive_enumerator() + sage: dP8 = toric_varieties.dP8(base_ring=GF(3)) + sage: ni = dP8.point_set()._naive_enumerator() sage: ni.rescalings() ((1, 1, 1, 1), (1, 2, 2, 2), (2, 1, 2, 1), (2, 2, 1, 2)) - sage: ni = toric_varieties.P1xP1(base_ring=GF(3)).point_set()._naive_enumerator() + sage: P1xP1 = toric_varieties.P1xP1(base_ring=GF(3)) + sage: ni = P1xP1.point_set()._naive_enumerator() sage: ni.rescalings() ((1, 1, 1, 1), (1, 1, 2, 2), (2, 2, 1, 1), (2, 2, 2, 2)) """ @@ -302,7 +303,8 @@ def orbit(self, point): EXAMPLES:: - sage: ne = toric_varieties.P2_123(base_ring=GF(7)).point_set()._naive_enumerator() + sage: P2_123 = toric_varieties.P2_123(base_ring=GF(7)) + sage: ne = P2_123.point_set()._naive_enumerator() sage: sorted(ne.orbit([1, 0, 0])) [(1, 0, 0), (2, 0, 0), (4, 0, 0)] sage: sorted(ne.orbit([0, 1, 0])) @@ -329,7 +331,8 @@ def cone_iter(self): EXAMPLES:: - sage: ne = toric_varieties.dP6(base_ring=GF(11)).point_set()._naive_enumerator() + sage: dP6 = toric_varieties.dP6(base_ring=GF(11)) + sage: ne = dP6.point_set()._naive_enumerator() sage: for cone in ne.cone_iter(): ....: print(cone.ambient_ray_indices()) (0, 1) @@ -348,8 +351,7 @@ def cone_iter(self): """ fan = self.fan for d in range(fan.dim(), -1, -1): - for cone in fan.cones(d): - yield cone + yield from fan.cones(d) def coordinate_iter(self): """ @@ -358,18 +360,18 @@ def coordinate_iter(self): This method does NOT identify homogeneous coordinates that are equivalent by a homogeneous rescaling. - OUTPUT: - - An iterator over the points. + OUTPUT: An iterator over the points. EXAMPLES:: - sage: F2 = GF(2) - sage: ni = toric_varieties.P2(base_ring=F2).point_set()._naive_enumerator() + sage: P2 = toric_varieties.P2(base_ring=GF(2)) + sage: ni = P2.point_set()._naive_enumerator() sage: list(ni.coordinate_iter()) - [(0, 0, 1), (1, 0, 0), (0, 1, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0), (1, 1, 1)] + [(0, 0, 1), (1, 0, 0), (0, 1, 0), (0, 1, 1), + (1, 0, 1), (1, 1, 0), (1, 1, 1)] - sage: ni = toric_varieties.P1xP1(base_ring=F2).point_set()._naive_enumerator() + sage: P1xP1 = toric_varieties.P1xP1(base_ring=GF(2)) + sage: ni = P1xP1.point_set()._naive_enumerator() sage: list(ni.coordinate_iter()) [(0, 1, 0, 1), (1, 0, 0, 1), (1, 0, 1, 0), (0, 1, 1, 0), (0, 1, 1, 1), (1, 0, 1, 1), @@ -400,17 +402,18 @@ def __iter__(self): rescalings, and returns precisely one representative per orbit. - OUTPUT: - - Iterator over points. + OUTPUT: An iterator over points. EXAMPLES:: - sage: ni = toric_varieties.P2(base_ring=GF(2)).point_set()._naive_enumerator() + sage: P2 = toric_varieties.P2(base_ring=GF(2)) + sage: ni = P2.point_set()._naive_enumerator() sage: list(ni) - [(0, 0, 1), (1, 0, 0), (0, 1, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0), (1, 1, 1)] + [(0, 0, 1), (1, 0, 0), (0, 1, 0), (0, 1, 1), + (1, 0, 1), (1, 1, 0), (1, 1, 1)] - sage: ni = toric_varieties.P1xP1(base_ring=GF(3)).point_set()._naive_enumerator() + sage: P1xP1 = toric_varieties.P1xP1(base_ring=GF(3)) + sage: ni = P1xP1.point_set()._naive_enumerator() sage: list(ni) [(0, 1, 0, 1), (1, 0, 0, 1), (1, 0, 1, 0), (0, 1, 1, 0), (0, 1, 1, 1), (0, 1, 1, 2), (1, 0, 1, 1), (1, 0, 1, 2), @@ -432,15 +435,13 @@ def multiplicative_generator(self): """ Return the multiplicative generator of the finite field. - OUTPUT: - - A finite field element. + OUTPUT: A finite field element. EXAMPLES:: - sage: point_set = toric_varieties.P2(base_ring=GF(5^2, 'a')).point_set() - sage: ffe = point_set._finite_field_enumerator() - sage: ffe.multiplicative_generator() + sage: point_set = toric_varieties.P2(base_ring=GF(5^2, 'a')).point_set() # needs sage.rings.finite_rings + sage: ffe = point_set._finite_field_enumerator() # needs sage.rings.finite_rings + sage: ffe.multiplicative_generator() # needs sage.rings.finite_rings a """ return self.ring.multiplicative_generator() @@ -458,9 +459,7 @@ def root_generator(self, n): - ``n`` integer. - OUTPUT: - - A multiplicative generator for :meth:`roots`. + OUTPUT: A multiplicative generator for :meth:`roots`. EXAMPLES:: @@ -475,8 +474,8 @@ def root_generator(self, n): TESTS:: - sage: for p in primes(10): - ....: for k in range(1,5): + sage: for p in primes(10): # needs sage.rings.finite_rings + ....: for k in range(1, 5): ....: F = GF(p^k, 'a') ....: N = F.cardinality() - 1 ....: ffe = point_set._finite_field_enumerator(F) @@ -570,6 +569,7 @@ def log(self, z): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(5^2) sage: point_set = toric_varieties.P2_123(base_ring=F).point_set() sage: ffe = point_set._finite_field_enumerator() @@ -603,6 +603,7 @@ def exp(self, powers): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F.<a> = GF(5^2) sage: point_set = toric_varieties.P2_123(base_ring=F).point_set() sage: ffe = point_set._finite_field_enumerator() @@ -702,16 +703,15 @@ def __iter__(self): rescalings, and returns precisely one representative per orbit. - OUTPUT: - - Iterator over points. + OUTPUT: Iterator over points. EXAMPLES:: sage: point_set = toric_varieties.P2(base_ring=GF(2)).point_set() sage: ffe = point_set._finite_field_enumerator() sage: list(ffe) - [(0, 0, 1), (1, 0, 0), (0, 1, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0), (1, 1, 1)] + [(0, 0, 1), (1, 0, 0), (0, 1, 0), (0, 1, 1), + (1, 0, 1), (1, 1, 0), (1, 1, 1)] sage: fan = NormalFan(ReflexivePolytope(2, 0)) sage: X = ToricVariety(fan, base_ring=GF(7)) @@ -739,9 +739,7 @@ def cardinality(self): """ Return the cardinality of the point set. - OUTPUT: - - Integer. The number of points. + OUTPUT: An integer. The number of points. EXAMPLES:: @@ -776,7 +774,7 @@ def __init__(self, polynomials, ambient): sage: P2.<x,y,z> = toric_varieties.P2() sage: from sage.schemes.toric.points import NaiveSubschemePointEnumerator sage: ne = NaiveSubschemePointEnumerator( - ....: [x^2+y^2-2*z^2], P2.point_set()._enumerator()) + ....: [x^2 + y^2 - 2*z^2], P2.point_set()._enumerator()) sage: next(iter(ne)) (1, 1, 1) """ @@ -801,7 +799,7 @@ def __iter__(self): sage: P2.<x,y,z> = toric_varieties.P2() sage: from sage.schemes.toric.points import NaiveSubschemePointEnumerator sage: ne = NaiveSubschemePointEnumerator( - ....: [x^2+y^2-2*z^2], P2.point_set()._enumerator()) + ....: [x^2 + y^2 - 2*z^2], P2.point_set()._enumerator()) sage: next(iter(ne)) (1, 1, 1) """ @@ -849,7 +847,7 @@ def inhomogeneous_equations(self, ring, nonzero_coordinates, cokernel): z = [ring.zero()] * nrays for i, value in zip(nonzero_coordinates, z_nonzero): z[i] = value - return [poly(z) for poly in self.polynomials] + return [poly.change_ring(ring)(z) for poly in self.polynomials] def solutions_serial(self, inhomogeneous_equations, log_range): """ @@ -877,7 +875,7 @@ def solutions_serial(self, inhomogeneous_equations, log_range): sage: X = P2.subscheme(1) sage: point_set = X.point_set() sage: ffe = point_set._enumerator() - sage: ffe.solutions_serial([s^2-1, s^6-s^2], [range(6)]) + sage: ffe.solutions_serial([s^2 - 1, s^6 - s^2], [range(6)]) <generator object ...solutions_serial at 0x...> sage: list(_) [(0,), (3,)] @@ -905,7 +903,7 @@ def solutions(self, inhomogeneous_equations, log_range): sage: X = P2.subscheme(1) sage: point_set = X.point_set() sage: ffe = point_set._enumerator() - sage: ffe.solutions([s^2-1, s^6-s^2], [range(6)]) + sage: ffe.solutions([s^2 - 1, s^6 - s^2], [range(6)]) <generator object ...solutions at 0x...> sage: sorted(_) [(0,), (3,)] @@ -1001,9 +999,7 @@ def cardinality(self): """ Return the cardinality of the point set. - OUTPUT: - - Integer. The number of points. + OUTPUT: An integer. The number of points. EXAMPLES:: diff --git a/src/sage/schemes/toric/sheaf/__init__.py b/src/sage/schemes/toric/sheaf/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/geometry/hyperbolic_space/__init__.py b/src/sage/schemes/toric/sheaf/all.py similarity index 100% rename from src/sage/geometry/hyperbolic_space/__init__.py rename to src/sage/schemes/toric/sheaf/all.py diff --git a/src/sage/schemes/toric/sheaf/constructor.py b/src/sage/schemes/toric/sheaf/constructor.py index 74aa578d422..52f00d99815 100644 --- a/src/sage/schemes/toric/sheaf/constructor.py +++ b/src/sage/schemes/toric/sheaf/constructor.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Construct sheaves on toric varieties @@ -272,9 +273,9 @@ def Klyachko(self, multi_filtration): EXAMPLES:: sage: P1 = toric_varieties.P1() - sage: v1, v2, v3 = [(1,0,0),(0,1,0),(0,0,1)] - sage: F1 = FilteredVectorSpace({1:[v1, v2, v3], 3:[v1]}) - sage: F2 = FilteredVectorSpace({0:[v1, v2, v3], 2:[v2, v3]}) + sage: v1, v2, v3 = [(1,0,0), (0,1,0), (0,0,1)] + sage: F1 = FilteredVectorSpace({1: [v1, v2, v3], 3: [v1]}) + sage: F2 = FilteredVectorSpace({0: [v1, v2, v3], 2: [v2, v3]}) sage: P1 = toric_varieties.P1() sage: r1, r2 = P1.fan().rays() sage: F = MultiFilteredVectorSpace({r1:F1, r2:F2}); F diff --git a/src/sage/schemes/toric/sheaf/klyachko.py b/src/sage/schemes/toric/sheaf/klyachko.py index 77fae4b7545..08cea1487f9 100644 --- a/src/sage/schemes/toric/sheaf/klyachko.py +++ b/src/sage/schemes/toric/sheaf/klyachko.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs """ Klyachko bundles and sheaves @@ -62,9 +63,7 @@ def is_KlyachkoBundle(X): - ``X`` -- anything. - OUTPUT: - - Boolean. + OUTPUT: A boolean. EXAMPLES:: @@ -93,12 +92,12 @@ def Bundle(toric_variety, multi_filtration, check=True): EXAMPLES:: sage: P1 = toric_varieties.P1() - sage: v1, v2, v3 = [(1,0,0),(0,1,0),(0,0,1)] - sage: F1 = FilteredVectorSpace({1:[v1, v2, v3], 3:[v1]}) - sage: F2 = FilteredVectorSpace({0:[v1, v2, v3], 2:[v2, v3]}) + sage: v1, v2, v3 = [(1,0,0), (0,1,0), (0,0,1)] + sage: F1 = FilteredVectorSpace({1: [v1, v2, v3], 3: [v1]}) + sage: F2 = FilteredVectorSpace({0: [v1, v2, v3], 2: [v2, v3]}) sage: P1 = toric_varieties.P1() sage: r1, r2 = P1.fan().rays() - sage: F = MultiFilteredVectorSpace({r1:F1, r2:F2}); F + sage: F = MultiFilteredVectorSpace({r1: F1, r2: F2}); F Filtrations N(-1): QQ^3 >= QQ^2 >= QQ^2 >= 0 >= 0 N(1): QQ^3 >= QQ^3 >= QQ^1 >= QQ^1 >= 0 @@ -110,7 +109,7 @@ def Bundle(toric_variety, multi_filtration, check=True): sage: P1.sheaves.Klyachko(F) Rank 3 bundle on 1-d CPR-Fano toric variety covered by 2 affine patches. - sage: P1.sheaves.Klyachko({r1:F1, r2:F2}) # alternative + sage: P1.sheaves.Klyachko({r1: F1, r2: F2}) # alternative Rank 3 bundle on 1-d CPR-Fano toric variety covered by 2 affine patches. The above is just a shorthand for:: @@ -157,8 +156,8 @@ def __init__(self, toric_variety, multi_filtration, check=True): sage: P1 = toric_varieties.P1() sage: r1, r2 = P1.fan().rays() sage: F = MultiFilteredVectorSpace({ - ....: r1:FilteredVectorSpace(3,1), - ....: r2:FilteredVectorSpace(3,0)}); F + ....: r1: FilteredVectorSpace(3,1), + ....: r2: FilteredVectorSpace(3,0)}); F Filtrations N(-1): QQ^3 >= 0 >= 0 N(1): QQ^3 >= QQ^3 >= 0 @@ -183,9 +182,7 @@ def variety(self): r""" Return the base toric variety. - OUTPUT: - - A toric variety. + OUTPUT: A toric variety. EXAMPLES:: @@ -201,9 +198,7 @@ def base_ring(self): r""" Return the base field. - OUTPUT: - - A field. + OUTPUT: A field. EXAMPLES:: @@ -217,9 +212,7 @@ def fiber(self): r""" Return the generic fiber of the vector bundle. - OUTPUT: - - A vector space over :meth:`base_ring`. + OUTPUT: A vector space over :meth:`base_ring`. EXAMPLES:: @@ -227,16 +220,14 @@ def fiber(self): sage: T_P2.fiber() Vector space of dimension 2 over Rational Field """ - from sage.modules.all import VectorSpace + from sage.modules.free_module import VectorSpace return VectorSpace(self.base_ring(), self.rank()) def rank(self): r""" Return the rank of the vector bundle. - OUTPUT: - - Integer. + OUTPUT: An integer. EXAMPLES:: @@ -250,9 +241,7 @@ def _repr_(self): r""" Return a string representation. - OUTPUT: - - String. + OUTPUT: A string. EXAMPLES:: @@ -331,8 +320,7 @@ def get_degree(self, ray, i): sage: TX = toric_varieties.dP6().sheaves.tangent_bundle() sage: TX.get_degree(0, 1) Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [0 1] + Basis matrix: [0 1] """ return self.get_filtration(ray).get_degree(i) @@ -363,12 +351,10 @@ def filtration_intersection(self, sigma, i): sage: V = X.sheaves.tangent_bundle() sage: V.filtration_intersection(fan(1)[0], 1) Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 0] + Basis matrix: [1 0] sage: V.filtration_intersection(fan(2)[0], 1) Vector space of degree 2 and dimension 0 over Rational Field - Basis matrix: - [] + Basis matrix: [] """ sigma = self._variety.fan().embed(sigma) V = self.fiber() @@ -401,16 +387,13 @@ def E_degree(self, alpha, m): sage: V = X.sheaves.tangent_bundle() sage: V.E_degree(X.fan().ray(0), (1,0)) Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 0] + Basis matrix: [1 0] sage: V.E_degree(X.fan(1)[0], (1,0)) Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 0] + Basis matrix: [1 0] sage: V.E_degree(0, (1,0)) Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 0] + Basis matrix: [1 0] """ fan = self.variety().fan() N = fan.lattice() @@ -430,7 +413,7 @@ def E_degree(self, alpha, m): @cached_method def E_intersection(self, sigma, m): r""" - Return the vector subspace ``E^\sigma(m)``. + Return the vector subspace `E^\sigma(m)`. See [Kly1990]_, equation 4.1. @@ -441,9 +424,7 @@ def E_intersection(self, sigma, m): - ``m`` -- tuple of integers or `M`-lattice point. A point in the dual lattice of the fan. Must be immutable. - OUTPUT: - - The subspace `E^\sigma(m)` + OUTPUT: The subspace `E^\sigma(m)`. EXAMPLES:: @@ -452,12 +433,10 @@ def E_intersection(self, sigma, m): sage: V = X.sheaves.tangent_bundle() sage: V.E_intersection(fan(1)[0], (1,0)) Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 0] + Basis matrix: [1 0] sage: V.E_intersection(fan(2)[0], (-1,1)) Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [0 1] + Basis matrix: [0 1] For the empty cone, this is always the whole vector space:: @@ -484,9 +463,7 @@ def E_quotient(self, sigma, m): - ``m`` -- tuple of integers or `M`-lattice point. A point in the dual lattice of the fan. Must be immutable. - OUTPUT: - - The subspace `E_\sigma(m)` + OUTPUT: The subspace `E_\sigma(m)`. EXAMPLES:: @@ -499,17 +476,16 @@ def E_quotient(self, sigma, m): sage: m.set_immutable() sage: V.E_quotient(cone, m) Vector space quotient V/W of dimension 1 over Rational Field where - V: Vector space of dimension 2 over Rational Field - W: Vector space of degree 2 and dimension 1 over Rational Field - Basis matrix: - [1 0] + V: Vector space of dimension 2 over Rational Field + W: Vector space of degree 2 and dimension 1 over Rational Field + Basis matrix: [1 0] sage: V.E_quotient(fan(2)[0], (-1,1)) Vector space quotient V/W of dimension 0 over Rational Field where - V: Vector space of dimension 2 over Rational Field - W: Vector space of degree 2 and dimension 2 over Rational Field - Basis matrix: - [1 0] - [0 1] + V: Vector space of dimension 2 over Rational Field + W: Vector space of degree 2 and dimension 2 over Rational Field + Basis matrix: + [1 0] + [0 1] """ sigma = self._variety.fan().embed(sigma) V = self.fiber() @@ -545,10 +521,10 @@ def E_quotient_projection(self, sigma, tau, m): sage: P3 = toric_varieties.P(3) sage: rays = [(1,0,0), (0,1,0), (0,0,1)] - sage: F1 = FilteredVectorSpace(rays, {0:[0], 1:[2], 2:[1]}) + sage: F1 = FilteredVectorSpace(rays, {0: [0], 1: [2], 2: [1]}) sage: F2 = FilteredVectorSpace(3, 0) sage: r = P3.fan().rays() - sage: V = P3.sheaves.Klyachko({r[0]:F1, r[1]:F2, r[2]:F2, r[3]:F2}) + sage: V = P3.sheaves.Klyachko({r[0]: F1, r[1]: F2, r[2]: F2, r[3]: F2}) sage: tau = Cone([(1,0,0), (0,1,0)]) sage: sigma = Cone([(1,0,0)]) sage: M = P3.fan().dual_lattice() @@ -556,30 +532,26 @@ def E_quotient_projection(self, sigma, tau, m): sage: m.set_immutable() sage: V.E_quotient(sigma, m) Vector space quotient V/W of dimension 2 over Rational Field where - V: Vector space of dimension 3 over Rational Field - W: Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [0 1 0] + V: Vector space of dimension 3 over Rational Field + W: Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: [0 1 0] sage: V.E_quotient(tau, m) Vector space quotient V/W of dimension 2 over Rational Field where - V: Vector space of dimension 3 over Rational Field - W: Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [0 1 0] + V: Vector space of dimension 3 over Rational Field + W: Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: [0 1 0] sage: V.E_quotient_projection(sigma, tau, m) Vector space morphism represented by the matrix: - [1 0] - [0 1] - Domain: Vector space quotient V/W of dimension 2 over Rational Field where - V: Vector space of dimension 3 over Rational Field - W: Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [0 1 0] - Codomain: Vector space quotient V/W of dimension 2 over Rational Field where - V: Vector space of dimension 3 over Rational Field - W: Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [0 1 0] + [1 0] + [0 1] + Domain: Vector space quotient V/W of dimension 2 over Rational Field where + V: Vector space of dimension 3 over Rational Field + W: Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: [0 1 0] + Codomain: Vector space quotient V/W of dimension 2 over Rational Field where + V: Vector space of dimension 3 over Rational Field + W: Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: [0 1 0] """ if not sigma.is_face_of(tau): raise ValueError('the cone sigma is not a face of the cone tau') @@ -608,10 +580,10 @@ def cohomology_complex(self, m): sage: P3 = toric_varieties.P(3) sage: rays = [(1,0,0), (0,1,0), (0,0,1)] - sage: F1 = FilteredVectorSpace(rays, {0:[0], 1:[2], 2:[1]}) - sage: F2 = FilteredVectorSpace(rays, {0:[1,2], 1:[0]}) + sage: F1 = FilteredVectorSpace(rays, {0: [0], 1: [2], 2: [1]}) + sage: F2 = FilteredVectorSpace(rays, {0: [1,2], 1: [0]}) sage: r = P3.fan().rays() - sage: V = P3.sheaves.Klyachko({r[0]:F1, r[1]:F2, r[2]:F2, r[3]:F2}) + sage: V = P3.sheaves.Klyachko({r[0]: F1, r[1]: F2, r[2]: F2, r[3]: F2}) sage: tau = Cone([(1,0,0), (0,1,0)]) sage: sigma = Cone([(1, 0, 0)]) sage: M = P3.fan().dual_lattice() @@ -621,7 +593,7 @@ def cohomology_complex(self, m): sage: F = CyclotomicField(3) sage: P3 = toric_varieties.P(3).change_ring(F) - sage: V = P3.sheaves.Klyachko({r[0]:F1, r[1]:F2, r[2]:F2, r[3]:F2}) + sage: V = P3.sheaves.Klyachko({r[0]: F1, r[1]: F2, r[2]: F2, r[3]: F2}) sage: V.cohomology_complex(m) Chain complex with at most 2 nonzero terms over Cyclotomic Field of order 3 and degree 2 @@ -702,7 +674,7 @@ def cohomology(self, degree=None, weight=None, dim=False): H^*i(P^2, TP^2)_M(1, -1) = (1, 0, 0) H^*i(P^2, TP^2)_M(1, 0) = (1, 0, 0) """ - from sage.modules.all import FreeModule + from sage.modules.free_module import FreeModule if weight is None: raise NotImplementedError('sum over weights is not implemented') else: @@ -737,9 +709,7 @@ def __richcmp__(self, other, op): - ``other`` -- anything. - OUTPUT: - - Boolean. + OUTPUT: A boolean. EXAMPLES:: @@ -748,7 +718,7 @@ def __richcmp__(self, other, op): sage: V2 = X.sheaves.trivial_bundle(2) sage: V2 == V1 False - sage: V2 == V1+V1 + sage: V2 == V1 + V1 True sage: T_X = X.sheaves.tangent_bundle() @@ -774,9 +744,7 @@ def is_isomorphic(self, other): - ``other`` -- anything. - OUTPUT: - - Boolean. + OUTPUT: A boolean. EXAMPLES:: @@ -800,9 +768,7 @@ def direct_sum(self, other): - ``other`` -- a Klyachko bundle over the same base. - OUTPUT: - - The direct sum as a new Klyachko bundle. + OUTPUT: The direct sum as a new Klyachko bundle. EXAMPLES:: @@ -832,9 +798,7 @@ def tensor_product(self, other): - ``other`` -- a Klyachko bundle over the same base. - OUTPUT: - - The tensor product as a new Klyachko bundle. + OUTPUT: The tensor product as a new Klyachko bundle. EXAMPLES:: @@ -888,18 +852,16 @@ def symmetric_power(self, n): - ``n`` -- integer. - OUTPUT: - - The `n`-th symmetric power as a new Klyachko bundle. + OUTPUT: The `n`-th symmetric power as a new Klyachko bundle. EXAMPLES:: sage: P1 = toric_varieties.P1() sage: H = P1.divisor(0) sage: L = P1.sheaves.line_bundle(H) - sage: (L+L).symmetric_power(2) + sage: (L + L).symmetric_power(2) Rank 3 bundle on 1-d CPR-Fano toric variety covered by 2 affine patches. - sage: (L+L).symmetric_power(2) == L*L+L*L+L*L + sage: (L + L).symmetric_power(2) == L*L + L*L + L*L True """ filt = self._filt.symmetric_power(n) @@ -909,9 +871,7 @@ def dual(self): """ Return the dual bundle. - OUTPUT: - - The dual bundle as a new Klyachko bundle. + OUTPUT: The dual bundle as a new Klyachko bundle. EXAMPLES:: diff --git a/src/sage/schemes/toric/toric_subscheme.py b/src/sage/schemes/toric/toric_subscheme.py index 76c0b300813..acdfd05d0d1 100644 --- a/src/sage/schemes/toric/toric_subscheme.py +++ b/src/sage/schemes/toric/toric_subscheme.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Subschemes of toric space @@ -44,10 +45,8 @@ class AlgebraicScheme_subscheme_toric(AlgebraicScheme_subscheme): - ``polynomials`` -- single polynomial, list, or ideal of defining polynomials in the coordinate ring of ``toric_variety``. - OUTPUT: - - - :class:`algebraic subscheme of a toric variety - <AlgebraicScheme_subscheme_toric>`. + OUTPUT: An :class:`algebraic subscheme of a toric variety + <AlgebraicScheme_subscheme_toric>`. TESTS:: @@ -56,7 +55,7 @@ class AlgebraicScheme_subscheme_toric(AlgebraicScheme_subscheme): Defining s, t, x, y sage: import sage.schemes.toric.toric_subscheme as SCM sage: X = SCM.AlgebraicScheme_subscheme_toric( - ....: P1xP1, [x*s + y*t, x^3+y^3]) + ....: P1xP1, [x*s + y*t, x^3 + y^3]) sage: X Closed subscheme of 2-d CPR-Fano toric variety covered by 4 affine patches defined by: @@ -65,7 +64,7 @@ class AlgebraicScheme_subscheme_toric(AlgebraicScheme_subscheme): A better way to construct the same scheme as above:: - sage: P1xP1.subscheme([x*s + y*t, x^3+y^3]) + sage: P1xP1.subscheme([x*s + y*t, x^3 + y^3]) Closed subscheme of 2-d CPR-Fano toric variety covered by 4 affine patches defined by: s*x + t*y, @@ -87,7 +86,7 @@ def __init__(self, toric_variety, polynomials): Defining s, t, x, y sage: import sage.schemes.toric.toric_subscheme as SCM sage: X = SCM.AlgebraicScheme_subscheme_toric( - ....: P1xP1, [x*s + y*t, x^3+y^3]) + ....: P1xP1, [x*s + y*t, x^3 + y^3]) sage: X Closed subscheme of 2-d CPR-Fano toric variety covered by 4 affine patches defined by: @@ -106,9 +105,7 @@ def _morphism(self, *args, **kwds): - same as for :class:`~sage.schemes.toric.morphism.SchemeMorphism_polynomial_toric_variety`. - OUTPUT: - - - :class:`~sage.schemes.toric.morphism.SchemeMorphism_polynomial_toric_variety`. + OUTPUT: A :class:`~sage.schemes.toric.morphism.SchemeMorphism_polynomial_toric_variety`. TESTS:: @@ -148,9 +145,7 @@ def _point_homset(self, *args, **kwds): - same as for :class:`~sage.schemes.toric.homset.SchemeHomset_points_toric_field`. - OUTPUT: - - :class:`~sage.schemes.toric.homset.SchemeHomset_points_subscheme_toric_field`. + OUTPUT: A :class:`~sage.schemes.toric.homset.SchemeHomset_points_subscheme_toric_field`. TESTS:: @@ -170,14 +165,12 @@ def fan(self): """ Return the fan of the ambient space. - OUTPUT: - - A fan. + OUTPUT: A fan. EXAMPLES:: sage: P2.<x,y,z> = toric_varieties.P(2) - sage: E = P2.subscheme([x^2+y^2+z^2]) + sage: E = P2.subscheme([x^2 + y^2 + z^2]) sage: E.fan() Rational polyhedral fan in 2-d lattice N """ @@ -214,11 +207,10 @@ def affine_patch(self, i): Scheme morphism: From: 2-d affine toric variety To: 2-d CPR-Fano toric variety covered by 4 affine patches - Defn: Defined on coordinates by sending [t : x] to - [1 : t : x : 1] + Defn: Defined on coordinates by sending [t : x] to [1 : t : x : 1] sage: P1xP1.inject_variables() Defining s, t, x, y - sage: P1 = P1xP1.subscheme(x-y) + sage: P1 = P1xP1.subscheme(x - y) sage: subpatch = P1.affine_patch(1) sage: subpatch Closed subscheme of 2-d affine toric variety defined by: @@ -273,17 +265,17 @@ def affine_algebraic_patch(self, cone=None, names=None): sage: P2.<x,y,z> = toric_varieties.P2() sage: cone = P2.fan().generating_cone(0) - sage: V = P2.subscheme(x^3+y^3+z^3) + sage: V = P2.subscheme(x^3 + y^3 + z^3) sage: V.affine_algebraic_patch(cone) Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: z0^3 + z1^3 + 1 - sage: cone = Cone([(0,1),(2,1)]) + sage: cone = Cone([(0,1), (2,1)]) sage: A2Z2.<x,y> = AffineToricVariety(cone) sage: A2Z2.affine_algebraic_patch() Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: -z0*z1 + z2^2 - sage: V = A2Z2.subscheme(x^2+y^2-1) + sage: V = A2Z2.subscheme(x^2 + y^2 - 1) sage: patch = V.affine_algebraic_patch(); patch Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: -z0*z1 + z2^2, @@ -299,11 +291,11 @@ def affine_algebraic_patch(self, cone=None, names=None): the singularity of the ambient space and the second is the pull-back of `x^2+y^2-1` :: - sage: lp = LatticePolytope([(1,0,0),(1,1,0),(1,1,1),(1,0,1),(-2,-1,-1)], + sage: lp = LatticePolytope([(1,0,0), (1,1,0), (1,1,1), (1,0,1), (-2,-1,-1)], ....: lattice=ToricLattice(3)) sage: X.<x,y,u,v,t> = CPRFanoToricVariety(Delta_polar=lp) - sage: Y = X.subscheme(x*v+y*u+t) - sage: cone = Cone([(1,0,0),(1,1,0),(1,1,1),(1,0,1)]) + sage: Y = X.subscheme(x*v + y*u + t) + sage: cone = Cone([(1,0,0), (1,1,0), (1,1,1), (1,0,1)]) sage: Y.affine_algebraic_patch(cone) Closed subscheme of Affine Space of dimension 4 over Rational Field defined by: z0*z2 - z1*z3, @@ -398,8 +390,8 @@ def _best_affine_patch(self, point): EXAMPLES:: - sage: P.<x,y,z>= toric_varieties.P2() - sage: S = P.subscheme(x+2*y+3*z) + sage: P.<x,y,z> = toric_varieties.P2() + sage: S = P.subscheme(x + 2*y + 3*z) sage: S._best_affine_patch(P.point([2,-3,0])) 1 sage: S._best_affine_patch([2,-3,0]) @@ -433,8 +425,8 @@ def neighborhood(self, point): EXAMPLES:: - sage: P.<x,y,z>= toric_varieties.P2() - sage: S = P.subscheme(x+2*y+3*z) + sage: P.<x,y,z> = toric_varieties.P2() + sage: S = P.subscheme(x + 2*y + 3*z) sage: s = S.point([0,-3,2]); s [0 : -3 : 2] sage: patch = S.neighborhood(s); patch @@ -442,12 +434,10 @@ def neighborhood(self, point): x + 2*y + 6 sage: patch.embedding_morphism() Scheme morphism: - From: Closed subscheme of 2-d affine toric variety defined by: - x + 2*y + 6 - To: Closed subscheme of 2-d CPR-Fano toric variety covered by 3 affine patches defined by: - x + 2*y + 3*z - Defn: Defined on coordinates by sending [x : y] to - [-2*y - 6 : y : 2] + From: Closed subscheme of 2-d affine toric variety defined by: x + 2*y + 6 + To: Closed subscheme of 2-d CPR-Fano toric variety + covered by 3 affine patches defined by: x + 2*y + 3*z + Defn: Defined on coordinates by sending [x : y] to [-2*y - 6 : y : 2] sage: patch.embedding_center() [0 : -3] sage: patch.embedding_morphism()(patch.embedding_center()) @@ -462,12 +452,10 @@ def neighborhood(self, point): 3*x0 sage: patch.embedding_morphism() Scheme morphism: - From: Closed subscheme of 2-d affine toric variety defined by: - 3*x0 - To: Closed subscheme of 2-d CPR-Fano toric variety covered by 6 affine patches defined by: - x0*x3 - Defn: Defined on coordinates by sending [x0 : x1] to - [0 : x1 : 2 : 3 : 4 : 5] + From: Closed subscheme of 2-d affine toric variety defined by: 3*x0 + To: Closed subscheme of 2-d CPR-Fano toric variety + covered by 6 affine patches defined by: x0*x3 + Defn: Defined on coordinates by sending [x0 : x1] to [0 : x1 : 2 : 3 : 4 : 5] sage: patch.embedding_center() [0 : 1] sage: patch.embedding_morphism()(patch.embedding_center()) @@ -504,19 +492,17 @@ def dimension(self): """ Return the dimension of ``self``. - OUTPUT: - - Integer. If ``self`` is empty, `-1` is returned. + OUTPUT: An integer. If ``self`` is empty, `-1` is returned. EXAMPLES:: sage: P1xP1 = toric_varieties.P1xP1() sage: P1xP1.inject_variables() Defining s, t, x, y - sage: P1 = P1xP1.subscheme(s-t) + sage: P1 = P1xP1.subscheme(s - t) sage: P1.dimension() 1 - sage: P1xP1.subscheme([s-t, (s-t)^2]).dimension() + sage: P1xP1.subscheme([s - t, (s-t)^2]).dimension() 1 sage: P1xP1.subscheme([s, t]).dimension() -1 @@ -546,7 +532,7 @@ def is_smooth(self, point=None): EXAMPLES:: sage: P2.<x,y,z> = toric_varieties.P2() - sage: cuspidal_curve = P2.subscheme([y^2*z-x^3]) + sage: cuspidal_curve = P2.subscheme([y^2*z - x^3]) sage: cuspidal_curve Closed subscheme of 2-d CPR-Fano toric variety covered by 3 affine patches defined by: -x^3 + y^2*z @@ -574,11 +560,11 @@ def is_smooth(self, point=None): A smooth hypersurface in a compact singular toric variety:: - sage: lp = LatticePolytope([(1,0,0),(1,1,0),(1,1,1),(1,0,1),(-2,-1,-1)], + sage: lp = LatticePolytope([(1,0,0), (1,1,0), (1,1,1), (1,0,1), (-2,-1,-1)], ....: lattice=ToricLattice(3)) sage: X.<x,y,u,v,t> = CPRFanoToricVariety(Delta_polar=lp) - sage: Y = X.subscheme(x*v+y*u+t) - sage: cone = Cone([(1,0,0),(1,1,0),(1,1,1),(1,0,1)]) + sage: Y = X.subscheme(x*v + y*u + t) + sage: cone = Cone([(1,0,0), (1,1,0), (1,1,1), (1,0,1)]) sage: Y.is_smooth() True """ @@ -621,7 +607,7 @@ def is_nondegenerate(self): sage: fan = FaceFan(diamond) sage: P1xP1xP1 = ToricVariety(fan) sage: z0, z1, z2, z3, z4, z5 = P1xP1xP1.gens() - sage: t = 5; + sage: t = 5 sage: F = z0^2*z1^2*z2^2 + z1^2*z2^2*z3^2 + z0^2*z2^2*z4^2\ ....: + z2^2*z3^2*z4^2 + t*z0*z1*z2*z3*z4*z5 + z0^2*z1^2*z5^2\ ....: + z1^2*z3^2*z5^2 + z0^2*z4^2*z5^2 + z3^2*z4^2*z5^2 @@ -634,23 +620,23 @@ def is_nondegenerate(self): Taking a random change of variables breaks the symmetry, but makes the surface nondegenerate:: - sage: F1 = F.subs(z0 = 1*z0 + 1*z3, z3 = 1*z0 + 2*z3,\ - ....: z1 = -2*z1 + -1*z4, z4 = 1*z1 + 2*z4,\ - ....: z2 = -3*z2 + -1*z5, z5 = -3*z2 + 2*z5 ) + sage: F1 = F.subs(z0=1*z0 + 1*z3, z3=1*z0 + 2*z3, + ....: z1=-2*z1 + -1*z4, z4=1*z1 + 2*z4, + ....: z2=-3*z2 + -1*z5, z5=-3*z2 + 2*z5) sage: Y = P1xP1xP1.subscheme([F1]) sage: Y.is_smooth() True sage: Y.is_nondegenerate() True - This example is from Hamm, :arxiv:`1106.1826v1`. It addresses - an issue raised at :trac:`15239`:: + This example is from Hamm, :arxiv:`1106.1826v1`. It addresses + an issue raised at :trac:`15239`:: sage: X = toric_varieties.WP([1,4,2,3], names='z0 z1 z2 z3') sage: X.inject_variables() Defining z0, z1, z2, z3 - sage: g0 = z1^3 + z2^6 +z3^4 - sage: g = g0-2*z3^2*z0^6+z2*z0^10+z0^12 + sage: g0 = z1^3 + z2^6 + z3^4 + sage: g = g0 - 2*z3^2*z0^6 + z2*z0^10 + z0^12 sage: Y = X.subscheme([g]) sage: Y.is_nondegenerate() False @@ -713,7 +699,7 @@ def is_schon(self): r""" Check if ``self`` is schon (nondegenerate). - See `is_nondegenerate` for further documentation. + See :meth:`is_nondegenerate` for further documentation. EXAMPLES:: @@ -759,7 +745,7 @@ class AlgebraicScheme_subscheme_affine_toric(AlgebraicScheme_subscheme_toric): Defining s, t, x, y sage: import sage.schemes.toric.toric_subscheme as SCM sage: X = SCM.AlgebraicScheme_subscheme_toric( - ....: P1xP1, [x*s + y*t, x^3+y^3]) + ....: P1xP1, [x*s + y*t, x^3 + y^3]) sage: X Closed subscheme of 2-d CPR-Fano toric variety covered by 4 affine patches defined by: @@ -768,7 +754,7 @@ class AlgebraicScheme_subscheme_affine_toric(AlgebraicScheme_subscheme_toric): A better way to construct the same scheme as above:: - sage: P1xP1.subscheme([x*s + y*t, x^3+y^3]) + sage: P1xP1.subscheme([x*s + y*t, x^3 + y^3]) Closed subscheme of 2-d CPR-Fano toric variety covered by 4 affine patches defined by: s*x + t*y, @@ -786,7 +772,7 @@ def __init__(self, toric_variety, polynomials): Defining s, t, x, y sage: import sage.schemes.toric.toric_subscheme as SCM sage: X = SCM.AlgebraicScheme_subscheme_toric( - ....: P1xP1, [x*s + y*t, x^3+y^3]) + ....: P1xP1, [x*s + y*t, x^3 + y^3]) sage: X Closed subscheme of 2-d CPR-Fano toric variety covered by 4 affine patches defined by: @@ -801,14 +787,12 @@ def dimension(self): """ Return the dimension of ``self``. - OUTPUT: - - - integer. + OUTPUT: An integer. EXAMPLES:: sage: P1xP1.<s0,s1,t0,t1> = toric_varieties.P1xP1() - sage: P1 = P1xP1.subscheme(s0-s1) + sage: P1 = P1xP1.subscheme(s0 - s1) sage: P1.dimension() 1 @@ -853,7 +837,7 @@ def is_smooth(self, point=None): EXAMPLES:: sage: A2.<x,y> = toric_varieties.A2() - sage: cuspidal_curve = A2.subscheme([y^2-x^3]) + sage: cuspidal_curve = A2.subscheme([y^2 - x^3]) sage: cuspidal_curve Closed subscheme of 2-d affine toric variety defined by: -x^3 + y^2 @@ -863,7 +847,7 @@ def is_smooth(self, point=None): False sage: cuspidal_curve.is_smooth() False - sage: circle = A2.subscheme(x^2+y^2-1) + sage: circle = A2.subscheme(x^2 + y^2 - 1) sage: circle.is_smooth([1,0]) True sage: circle.is_smooth() diff --git a/src/sage/schemes/toric/variety.py b/src/sage/schemes/toric/variety.py index 9b543e71cdd..82d2ec7769a 100644 --- a/src/sage/schemes/toric/variety.py +++ b/src/sage/schemes/toric/variety.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs # -*- coding: utf-8 -*- r""" Toric varieties @@ -85,20 +86,16 @@ sage: diamond = lattice_polytope.cross_polytope(2) sage: diamond.vertices() - M( 1, 0), - M( 0, 1), - M(-1, 0), - M( 0, -1) + M( 1, 0), M( 0, 1), + M(-1, 0), M( 0, -1) in 2-d lattice M sage: fan = FaceFan(diamond) sage: P1xP1 = ToricVariety(fan) sage: P1xP1 2-d toric variety covered by 4 affine patches sage: P1xP1.fan().rays() - M( 1, 0), - M( 0, 1), - M(-1, 0), - M( 0, -1) + M( 1, 0), M( 0, 1), + M(-1, 0), M( 0, -1) in 2-d lattice M sage: P1xP1.gens() (z0, z1, z2, z3) @@ -117,21 +114,18 @@ sage: P1xP1.inject_variables() Defining x, s, y, t sage: P1xP1.subscheme(x) - Closed subscheme of 2-d toric variety - covered by 4 affine patches defined by: + Closed subscheme of 2-d toric variety covered by 4 affine patches defined by: x sage: P1xP1.subscheme(x^2 + y^2) - Closed subscheme of 2-d toric variety - covered by 4 affine patches defined by: + Closed subscheme of 2-d toric variety covered by 4 affine patches defined by: x^2 + y^2 sage: P1xP1.subscheme(x^2 + s^2) Traceback (most recent call last): ... ValueError: x^2 + s^2 is not homogeneous on 2-d toric variety covered by 4 affine patches - sage: P1xP1.subscheme([x^2*s^2 + x*y*t^2 +y^2*t^2, s^3 + t^3]) - Closed subscheme of 2-d toric variety - covered by 4 affine patches defined by: + sage: P1xP1.subscheme([x^2*s^2 + x*y*t^2 + y^2*t^2, s^3 + t^3]) + Closed subscheme of 2-d toric variety covered by 4 affine patches defined by: x^2*s^2 + x*y*t^2 + y^2*t^2, s^3 + t^3 @@ -149,8 +143,7 @@ Scheme morphism: From: 2-d affine toric variety To: 2-d toric variety covered by 4 affine patches - Defn: Defined on coordinates by sending [x : s] to - [x : s : 1 : 1] + Defn: Defined on coordinates by sending [x : s] to [x : s : 1 : 1] The patch above was specifically chosen to coincide with our representation of the affine plane before, but you can get the other three patches as well. @@ -170,10 +163,8 @@ True sage: TV = ToricVariety(NormalFan(diamond)) sage: TV.fan().rays() - N( 1, 1), - N( 1, -1), - N(-1, -1), - N(-1, 1) + N( 1, 1), N( 1, -1), + N(-1, -1), N(-1, 1) in 2-d lattice N sage: TV.is_orbifold() True @@ -184,14 +175,8 @@ sage: TV3 = ToricVariety(NormalFan(lattice_polytope.cross_polytope(3))) sage: TV3.fan().rays() - N( 1, -1, -1), - N( 1, 1, -1), - N( 1, 1, 1), - N( 1, -1, 1), - N(-1, -1, 1), - N(-1, -1, -1), - N(-1, 1, -1), - N(-1, 1, 1) + N( 1, -1, -1), N( 1, 1, -1), N( 1, 1, 1), N( 1, -1, 1), + N(-1, -1, 1), N(-1, -1, -1), N(-1, 1, -1), N(-1, 1, 1) in 3-d lattice N sage: TV3.is_orbifold() False @@ -267,9 +252,9 @@ sage: D = P4_11133.divisor(0) sage: HH(D) [3*z4] - sage: P4_11133.integrate( HH(D)^4 ) + sage: P4_11133.integrate(HH(D)^4) 9 - sage: P4_11133.integrate( HH(D) * HH(cone) ) + sage: P4_11133.integrate(HH(D) * HH(cone)) 1 Although computationally less efficient, we can do the same @@ -287,13 +272,13 @@ The real advantage of the Chow group is that - * it works just as well over `\ZZ`, so torsion information is also - easily available, and +* it works just as well over `\ZZ`, so torsion information is also + easily available, and - * its combinatorial description also works over worse-than-orbifold - singularities. By contrast, the cohomology groups can become very - complicated to compute in this case, and one usually only has a - spectral sequence but no toric algorithm. +* its combinatorial description also works over worse-than-orbifold + singularities. By contrast, the cohomology groups can become very + complicated to compute in this case, and one usually only has a + spectral sequence but no toric algorithm. Below you will find detailed descriptions of available functions. If you are familiar with toric geometry, you will likely see that many important objects @@ -304,7 +289,7 @@ implementing them on your own as a patch for inclusion! """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Volker Braun <vbraun.name@gmail.com> # Copyright (C) 2010 Andrey Novoseltsev <novoselt@gmail.com> # Copyright (C) 2010 William Stein <wstein@gmail.com> @@ -313,8 +298,8 @@ # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import sys @@ -411,9 +396,7 @@ def ToricVariety(fan, - ``base_field`` -- alias for ``base_ring``. Takes precedence if both are specified. - OUTPUT: - - - :class:`toric variety <ToricVariety_field>`. + OUTPUT: A :class:`toric variety <ToricVariety_field>`. EXAMPLES: @@ -421,10 +404,8 @@ def ToricVariety(fan, sage: fan = FaceFan(lattice_polytope.cross_polytope(2)) sage: fan.rays() - M( 1, 0), - M( 0, 1), - M(-1, 0), - M( 0, -1) + M( 1, 0), M( 0, 1), + M(-1, 0), M( 0, -1) in 2-d lattice M sage: P1xP1 = ToricVariety(fan) sage: P1xP1.gens() @@ -439,8 +420,7 @@ def ToricVariety(fan, sage: P1xP1(0,1,0,1) Traceback (most recent call last): ... - TypeError: coordinates (0, 1, 0, 1) - are in the exceptional set + TypeError: coordinates (0, 1, 0, 1) are in the exceptional set We cannot set to zero both coordinates of the same projective line! @@ -455,9 +435,8 @@ def ToricVariety(fan, sage: P1xP1.inject_variables() Defining x, s, y, t - sage: P1xP1.subscheme(x*s-y*t) - Closed subscheme of 2-d toric variety - covered by 4 affine patches defined by: + sage: P1xP1.subscheme(x*s - y*t) + Closed subscheme of 2-d toric variety covered by 4 affine patches defined by: x*s - y*t Here is a shorthand for defining the toric variety and homogeneous @@ -493,9 +472,7 @@ def AffineToricVariety(cone, *args, **kwds): <sage.geometry.fan.RationalPolyhedralFan>`, which will be passed to :func:`ToricVariety` with the rest of positional and keyword arguments. - OUTPUT: - - - :class:`toric variety <ToricVariety_field>`. + OUTPUT: A :class:`toric variety <ToricVariety_field>`. .. NOTE:: @@ -552,9 +529,7 @@ class ToricVariety_field(AmbientSpace): - ``base_field`` -- base field of the toric variety. - OUTPUT: - - - :class:`toric variety <ToricVariety_field>`. + OUTPUT: A :class:`toric variety <ToricVariety_field>`. TESTS:: @@ -589,9 +564,7 @@ def __eq__(self, right): - ``right`` -- anything - OUTPUT: - - boolean + OUTPUT: A boolean. ``True`` if and only if ``right`` is of the same type as ``self``, their fans are the same, names of variables are the same and @@ -627,9 +600,7 @@ def __ne__(self, other): - ``other`` -- anything - OUTPUT: - - boolean + OUTPUT: A boolean. ``True`` if and only if ``other`` is of the same type as ``self``, their fans are the same, names of variables are the same and @@ -755,8 +726,7 @@ def _check_satisfies_equations(self, coordinates): possible_charts.intersection_update(fan._ray_to_cones(i)) if possible_charts: return True # All zeros are inside one generating cone - raise TypeError("coordinates %s are in the exceptional set" - % str(coordinates)) # Need str, coordinates is a tuple + raise TypeError(f"coordinates {coordinates} are in the exceptional set") def _point_homset(self, *args, **kwds): r""" @@ -872,7 +842,7 @@ def _homset(self, *args, **kwds): sage: P1xP1.inject_variables() Defining s, t, x, y - sage: P1 = P1xP1.subscheme(s-t) + sage: P1 = P1xP1.subscheme(s - t) sage: hom_set = P1xP1.Hom(P1) sage: hom_set([s,s,x,y]) Scheme morphism: @@ -1010,15 +980,13 @@ def affine_patch(self, i): Scheme morphism: From: 2-d affine toric variety To: 2-d toric variety covered by 4 affine patches - Defn: Defined on coordinates by sending [y : t] to - [1 : 1 : y : t] + Defn: Defined on coordinates by sending [y : t] to [1 : 1 : y : t] sage: patch1 = P1xP1.affine_patch(1) sage: patch1.embedding_morphism() Scheme morphism: From: 2-d affine toric variety To: 2-d toric variety covered by 4 affine patches - Defn: Defined on coordinates by sending [s : y] to - [1 : s : y : 1] + Defn: Defined on coordinates by sending [s : y] to [1 : s : y : 1] sage: patch1 is P1xP1.affine_patch(1) True """ @@ -1026,7 +994,7 @@ def affine_patch(self, i): try: return self._affine_patches[i] except AttributeError: - self._affine_patches = dict() + self._affine_patches = {} except KeyError: pass cone = self.fan().generating_cone(i) @@ -1041,7 +1009,7 @@ def affine_patch(self, i): embedding_coordinates = [1] * n for k, ray in enumerate(cone.ambient_ray_indices()): embedding_coordinates[ray] = patch.gen(k) - if t > 0: # Passing "-0" gives unintended result + if t > 0: # Passing "-0" gives unintended result embedding_coordinates.extend(patch.gens()[-t:]) patch._embedding_morphism = patch.hom(embedding_coordinates, self) self._affine_patches[i] = patch @@ -1055,9 +1023,7 @@ def change_ring(self, F): - ``F`` -- field. - OUTPUT: - - - :class:`toric variety <ToricVariety_field>` over ``F``. + OUTPUT: :class:`toric variety <ToricVariety_field>` over ``F``. .. NOTE:: @@ -1080,8 +1046,7 @@ def change_ring(self, F): Traceback (most recent call last): ... ValueError: no natural map from the base ring - (=Real Field with 53 bits of precision) - to R (=Rational Field)! + (=Real Field with 53 bits of precision) to R (=Rational Field)! sage: R = PolynomialRing(QQ, 2, 'a') sage: P1xA1.change_ring(R) Traceback (most recent call last): @@ -1105,16 +1070,13 @@ def coordinate_ring(self): For toric varieties this is the homogeneous coordinate ring (a.k.a. Cox's ring and total ring). - OUTPUT: - - - polynomial ring. + OUTPUT: A polynomial ring. EXAMPLES:: sage: P1xP1 = toric_varieties.P1xP1() sage: P1xP1.coordinate_ring() - Multivariate Polynomial Ring in s, t, x, y - over Rational Field + Multivariate Polynomial Ring in s, t, x, y over Rational Field TESTS:: @@ -1149,8 +1111,7 @@ def embedding_morphism(self): sage: P1xP1.embedding_morphism() Traceback (most recent call last): ... - ValueError: no default embedding was - defined for this toric variety + ValueError: no default embedding was defined for this toric variety sage: patch = P1xP1.affine_patch(0) sage: patch 2-d affine toric variety @@ -1158,8 +1119,7 @@ def embedding_morphism(self): Scheme morphism: From: 2-d affine toric variety To: 2-d toric variety covered by 4 affine patches - Defn: Defined on coordinates by sending [y : t] to - [1 : 1 : y : t] + Defn: Defined on coordinates by sending [y : t] to [1 : 1 : y : t] """ try: return self._embedding_morphism @@ -1212,9 +1172,7 @@ def inject_coefficients(self, scope=None, verbose=True): - ``verbose`` -- if ``True`` (default), names of injected generators will be printed. - OUTPUT: - - - none. + OUTPUT: None. EXAMPLES:: @@ -1311,7 +1269,7 @@ def is_homogeneous(self, polynomial): no homogeneous rescalings, for example:: sage: A1.<z> = toric_varieties.A1() - sage: A1.is_homogeneous(z^3+z^7) + sage: A1.is_homogeneous(z^3 + z^7) True Finally, the degree group is really the Chow group @@ -1321,11 +1279,11 @@ def is_homogeneous(self, polynomial): from odd-degree homogeneous polynomials:: sage: A2_Z2.<x,y> = toric_varieties.A2_Z2() - sage: A2_Z2.is_homogeneous(x+y+x^3+y^5+x^3*y^4) + sage: A2_Z2.is_homogeneous(x + y + x^3 + y^5 + x^3*y^4) True - sage: A2_Z2.is_homogeneous(x^2+x*y+y^4+(x*y)^5+x^4*y^4) + sage: A2_Z2.is_homogeneous(x^2 + x*y + y^4 + (x*y)^5 + x^4*y^4) True - sage: A2_Z2.is_homogeneous(x+y^2) + sage: A2_Z2.is_homogeneous(x + y^2) False """ if '_homogeneous_degrees_group' not in self.__dict__: @@ -1376,8 +1334,7 @@ def is_isomorphic(self, another): sage: TV1.is_isomorphic(TV2) Traceback (most recent call last): ... - NotImplementedError: - isomorphism check is not yet implemented + NotImplementedError: isomorphism check is not yet implemented """ if self is another: return True @@ -1395,9 +1352,7 @@ def is_affine(self): face lattice of a single cone. See also :func:`AffineToricVariety`. - OUTPUT: - - Boolean. + OUTPUT: A boolean. EXAMPLES:: @@ -1479,9 +1434,7 @@ def Kaehler_cone(self): r""" Return the closure of the Kรคhler cone of ``self``. - OUTPUT: - - - :class:`cone <sage.geometry.cone.ConvexRationalPolyhedralCone>`. + OUTPUT: :class:`cone <sage.geometry.cone.ConvexRationalPolyhedralCone>`. .. NOTE:: @@ -1526,9 +1479,7 @@ def Mori_cone(self): r""" Returns the Mori cone of ``self``. - OUTPUT: - - - :class:`cone <sage.geometry.cone.ConvexRationalPolyhedralCone>`. + OUTPUT: :class:`cone <sage.geometry.cone.ConvexRationalPolyhedralCone>`. .. NOTE:: @@ -1558,8 +1509,7 @@ def Mori_cone(self): sage: P4_11169.Mori_cone().rays() (3, 2, 0, 0, 0, 1, -6), (0, 0, 1, 1, 1, -3, 0) - in Ambient free module of rank 7 - over the principal ideal domain Integer Ring + in Ambient free module of rank 7 over the principal ideal domain Integer Ring """ # Ideally, self.Kaehler_cone().dual() should be it, but # so far this is not the case. @@ -1576,9 +1526,7 @@ def plot(self, **options): - any options for toric plots (see :func:`toric_plotter.options <sage.geometry.toric_plotter.options>`), none are mandatory. - OUTPUT: - - - a plot. + OUTPUT: A plot. .. NOTE:: @@ -1589,7 +1537,7 @@ def plot(self, **options): EXAMPLES:: sage: X = toric_varieties.Cube_deformation(4) - sage: X.plot() + sage: X.plot() # needs sage.plot Graphics3d Object """ if "ray_label" not in options: @@ -1617,10 +1565,8 @@ def rational_class_group(self): we write as addition) is the tensor product of the line bundles. The Picard group of a toric variety is always torsion-free. - OUTPUT: - - - :class:`rational divisor class group - <sage.schemes.toric.divisor.ToricRationalDivisorClassGroup>`. + OUTPUT: :class:`rational divisor class group + <sage.schemes.toric.divisor.ToricRationalDivisorClassGroup>`. .. NOTE:: @@ -1648,9 +1594,7 @@ def Chow_group(self, base_ring=ZZ): - ``base_ring`` -- either ``ZZ`` (default) or ``QQ``. The coefficient ring of the Chow group. - OUTPUT: - - A :class:`sage.schemes.toric.chow_group.ChowGroup_class` + OUTPUT: A :class:`sage.schemes.toric.chow_group.ChowGroup_class`. EXAMPLES:: @@ -1679,9 +1623,7 @@ def cartesian_product(self, other, variables. If not given, the index of each variable will coincide with the index of the corresponding ray of the fan. - OUTPUT: - - -- a :class:`toric variety <ToricVariety_field>`. + OUTPUT: A :class:`toric variety <ToricVariety_field>`. EXAMPLES:: @@ -1689,10 +1631,8 @@ def cartesian_product(self, other, sage: P1xP1 = P1.cartesian_product(P1); P1xP1 2-d toric variety covered by 4 affine patches sage: P1xP1.fan().rays() - N+N(-1, 0), - N+N( 1, 0), - N+N( 0, -1), - N+N( 0, 1) + N+N(-1, 0), N+N( 1, 0), + N+N( 0, -1), N+N( 0, 1) in 2-d lattice N+N """ return ToricVariety(self.fan().cartesian_product(other.fan()), @@ -1726,9 +1666,7 @@ def resolve(self, **kwds): <sage.geometry.fan.RationalPolyhedralFan>`, see its documentation for the available options. - OUTPUT: - - - :class:`toric variety <ToricVariety_field>`. + OUTPUT: A :class:`toric variety <ToricVariety_field>`. EXAMPLES: @@ -1830,9 +1768,7 @@ def resolve_to_orbifold(self, **kwds): - this function accepts only keyword arguments. See :meth:`resolve` for documentation. - OUTPUT: - - - :class:`toric variety <ToricVariety_field>`. + OUTPUT: A :class:`toric variety <ToricVariety_field>`. EXAMPLES:: @@ -1863,10 +1799,8 @@ def subscheme(self, polynomials): - ``polynomials`` -- list of polynomials in the coordinate ring of ``self``. - OUTPUT: - - - :class:`subscheme of a toric variety - <sage.schemes.toric.toric_subscheme.AlgebraicScheme_subscheme_toric>`. + OUTPUT: A :class:`subscheme of a toric variety + <sage.schemes.toric.toric_subscheme.AlgebraicScheme_subscheme_toric>`. EXAMPLES: @@ -1874,7 +1808,7 @@ def subscheme(self, polynomials): with coordinates `(x, y)` for one and `(s, t)` for the other:: sage: P1xP1.<x,y,s,t> = toric_varieties.P1xP1() - sage: X = P1xP1.subscheme([x*s + y*t, x^3+y^3]) + sage: X = P1xP1.subscheme([x*s + y*t, x^3 + y^3]) sage: X Closed subscheme of 2-d CPR-Fano toric variety covered by 4 affine patches defined by: @@ -1883,9 +1817,8 @@ def subscheme(self, polynomials): sage: X.defining_polynomials() (x*s + y*t, x^3 + y^3) sage: X.defining_ideal() - Ideal (x*s + y*t, x^3 + y^3) - of Multivariate Polynomial Ring in x, y, s, t - over Rational Field + Ideal (x*s + y*t, x^3 + y^3) of + Multivariate Polynomial Ring in x, y, s, t over Rational Field sage: X.base_ring() Rational Field sage: X.base_scheme() @@ -1893,9 +1826,7 @@ def subscheme(self, polynomials): sage: X.structure_morphism() Scheme morphism: From: Closed subscheme of 2-d CPR-Fano toric variety - covered by 4 affine patches defined by: - x*s + y*t, - x^3 + y^3 + covered by 4 affine patches defined by: x*s + y*t, x^3 + y^3 To: Spectrum of Rational Field Defn: Structure map """ @@ -1917,10 +1848,12 @@ def Stanley_Reisner_ideal(self): EXAMPLES:: - sage: fan = Fan([[0,1,3],[3,4],[2,0],[1,2,4]], [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)]) + sage: fan = Fan([[0,1,3], [3,4], [2,0], [1,2,4]], + ....: [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)]) sage: X = ToricVariety(fan, coordinate_names='A B C D E', base_field=GF(5)) sage: SR = X.Stanley_Reisner_ideal(); SR - Ideal (A*E, C*D, A*B*C, B*D*E) of Multivariate Polynomial Ring in A, B, C, D, E over Rational Field + Ideal (A*E, C*D, A*B*C, B*D*E) of + Multivariate Polynomial Ring in A, B, C, D, E over Rational Field """ if "_SR" not in self.__dict__: R = PolynomialRing(QQ, self.variable_names()) @@ -1939,10 +1872,12 @@ def linear_equivalence_ideal(self): EXAMPLES:: - sage: fan = Fan([[0,1,3],[3,4],[2,0],[1,2,4]], [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)]) + sage: fan = Fan([[0,1,3], [3,4], [2,0], [1,2,4]], + ....: [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)]) sage: X = ToricVariety(fan, coordinate_names='A B C D E', base_field=GF(5)) sage: lin = X.linear_equivalence_ideal(); lin - Ideal (-3*A + 3*C - D + E, -2*A - 2*C - D - E, A + B + C + D + E) of Multivariate Polynomial Ring in A, B, C, D, E over Rational Field + Ideal (-3*A + 3*C - D + E, -2*A - 2*C - D - E, A + B + C + D + E) of + Multivariate Polynomial Ring in A, B, C, D, E over Rational Field """ if "_linear_equivalence_ideal" not in self.__dict__: R = PolynomialRing(QQ, self.variable_names()) @@ -1980,7 +1915,8 @@ def cohomology_ring(self): sage: X.cohomology_ring() Rational cohomology ring of a 2-d CPR-Fano toric variety covered by 6 affine patches sage: X.cohomology_ring().defining_ideal() - Ideal (-u - y + z + w, x - y - v + w, x*y, x*v, x*z, u*v, u*z, u*w, y*z, y*w, v*w) of Multivariate Polynomial Ring in x, u, y, v, z, w over Rational Field + Ideal (-u - y + z + w, x - y - v + w, x*y, x*v, x*z, u*v, u*z, u*w, y*z, y*w, v*w) + of Multivariate Polynomial Ring in x, u, y, v, z, w over Rational Field sage: X.cohomology_ring().defining_ideal().ring() Multivariate Polynomial Ring in x, u, y, v, z, w over Rational Field sage: X.variable_names() @@ -2000,7 +1936,7 @@ def cohomology_ring(self): sage: loads(dumps(variety)) == variety True """ - if self.base_ring().characteristic()>0: + if self.base_ring().characteristic() > 0: raise NotImplementedError('only characteristic 0 base fields ' 'are implemented') return CohomologyRing(self) @@ -2313,19 +2249,19 @@ def Todd_class(self, deg=None): sage: dP6.integrate( dP6.Td() ) 1 """ - Td = QQ(1) + Td = QQ.one() if self.dimension() >= 1: c1 = self.Chern_class(1) - Td += QQ(1)/2 * c1 + Td += QQ.one() / 2 * c1 if self.dimension() >= 2: c2 = self.Chern_class(2) - Td += QQ(1)/12 * (c1**2 + c2) + Td += QQ.one() / 12 * (c1**2 + c2) if self.dimension() >= 3: - Td += QQ(1)/24 * c1*c2 + Td += QQ.one() / 24 * c1*c2 if self.dimension() >= 4: c3 = self.Chern_class(3) c4 = self.Chern_class(4) - Td += -QQ(1)/720 * (c1**4 -4*c1**2*c2 -3*c2**2 -c1*c3 +c4) + Td += -QQ.one() / 720 * (c1**4 - 4*c1**2*c2 - 3*c2**2 - c1*c3 + c4) if self.dimension() >= 5: raise NotImplementedError('Todd class is currently only implemented up to degree 4') if deg is None: @@ -2361,7 +2297,7 @@ def Euler_number(self): if self.is_complete(): chi = self.integrate(self.Chern_class()) else: - chi=0 + chi = 0 H = self.cohomology_basis() for d in range(self.dimension()+1): chi += (-1)**d * len(H[d]) @@ -2407,8 +2343,7 @@ def divisor(self, arg, base_ring=None, check=True, reduce=True): sage: dP6 = toric_varieties.dP6() sage: dP6.coordinate_ring() - Multivariate Polynomial Ring in x, u, y, v, z, w - over Rational Field + Multivariate Polynomial Ring in x, u, y, v, z, w over Rational Field sage: dP6.divisor(list(range(6))) V(u) + 2*V(y) + 3*V(v) + 4*V(z) + 5*V(w) sage: dP6.inject_variables() @@ -2440,7 +2375,7 @@ def divisor(self, arg, base_ring=None, check=True, reduce=True): # Divisor by a ray index - must be treated here, see Issue #12812. if arg in ZZ: arg = [(1, self.gen(arg))] - check = True # 1 must be coerced into the coefficient ring + check = True # 1 must be coerced into the coefficient ring reduce = False from sage.schemes.toric.divisor import ToricDivisor return ToricDivisor(self, ring=base_ring, arg=arg, @@ -2476,9 +2411,8 @@ def divisor_group(self, base_ring=ZZ): sage: dP6 = toric_varieties.dP6() sage: Div = dP6.divisor_group(); Div - Group of ZZ-Divisors on 2-d CPR-Fano toric variety - covered by 6 affine patches - sage: Div(x) + Group of ZZ-Divisors on 2-d CPR-Fano toric variety covered by 6 affine patches + sage: Div(x) # needs sage.symbolic V(x) """ from sage.schemes.generic.divisor_group import DivisorGroup @@ -2542,7 +2476,7 @@ def _semigroup_ring(self, cone=None, names=None): EXAMPLES:: - sage: A2Z2 = Cone([(0,1),(2,1)]) + sage: A2Z2 = Cone([(0,1), (2,1)]) sage: AffineToricVariety(A2Z2)._semigroup_ring() (Multivariate Polynomial Ring in z0, z1, z2 over Rational Field, Ideal (-z0*z1 + z2^2) of Multivariate Polynomial Ring in z0, z1, z2 over Rational Field, @@ -2611,19 +2545,19 @@ def Spec(self, cone=None, names=None): formats. If not given, indexed variable names will be created automatically. - Output: + OUTPUT: The spectrum of the semigroup ring `\CC[\sigma^\vee \cap M]`. EXAMPLES:: - sage: quadrant = Cone([(1,0),(0,1)]) + sage: quadrant = Cone([(1,0), (0,1)]) sage: AffineToricVariety(quadrant).Spec() Spectrum of Multivariate Polynomial Ring in z0, z1 over Rational Field A more interesting example:: - sage: A2Z2 = Cone([(0,1),(2,1)]) + sage: A2Z2 = Cone([(0,1), (2,1)]) sage: AffineToricVariety(A2Z2).Spec(names='u,v,t') Spectrum of Quotient of Multivariate Polynomial Ring in u, v, t over Rational Field by the ideal (-u*v + t^2) @@ -2656,7 +2590,7 @@ def affine_algebraic_patch(self, cone=None, names=None): EXAMPLES:: - sage: cone = Cone([(0,1),(2,1)]) + sage: cone = Cone([(0,1), (2,1)]) sage: A2Z2 = AffineToricVariety(cone) sage: A2Z2.affine_algebraic_patch() Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: @@ -2718,14 +2652,14 @@ def _orbit_closure_projection(self, cone, x): return result assert isinstance(x, sage.geometry.abc.ConvexRationalPolyhedralCone) - rays = [ vector(quot(r)) for r in x.rays() ] + rays = [vector(quot(r)) for r in x.rays()] return Cone(rays) # TODO: make the following work nicely. - #if x in cone.lattice(): - #return quot(x) - #assert is_Cone(x) - #return Cone(x.rays(), lattice=quot) + # if x in cone.lattice(): + # return quot(x) + # assert is_Cone(x) + # return Cone(x.rays(), lattice=quot) def orbit_closure(self, cone): r""" @@ -2768,8 +2702,7 @@ def orbit_closure(self, cone): Scheme morphism: From: 1-d toric variety covered by 2 affine patches To: 2-d CPR-Fano toric variety covered by 4 affine patches - Defn: Defined on coordinates by sending [z0 : z1] to - [0 : 1 : z1 : z0] + Defn: Defined on coordinates by sending [z0 : z1] to [0 : 1 : z1 : z0] TESTS:: @@ -2838,18 +2771,19 @@ def Demazure_roots(self): Here are the remaining three examples listed in [Baz2011]_, Example 2.1 and 2.3:: sage: s = 3 - sage: cones = [(0,1),(1,2),(2,3),(3,0)] - sage: Hs = ToricVariety(Fan(rays=[(1,0),(0,-1),(-1,s),(0,1)], cones=cones)) + sage: cones = [(0,1), (1,2), (2,3), (3,0)] + sage: Hs = ToricVariety(Fan(rays=[(1,0), (0,-1), (-1,s), (0,1)], cones=cones)) sage: Hs.Demazure_roots() (M(-1, 0), M(1, 0), M(0, 1), M(1, 1), M(2, 1), M(3, 1)) - sage: P11s = ToricVariety(Fan(rays=[(1,0),(0,-1),(-1,s)], cones=[(0,1),(1,2),(2,0)])) + sage: P11s = ToricVariety(Fan(rays=[(1,0), (0,-1), (-1,s)], + ....: cones=[(0,1), (1,2), (2,0)])) sage: P11s.Demazure_roots() (M(-1, 0), M(1, 0), M(0, 1), M(1, 1), M(2, 1), M(3, 1)) sage: P11s.Demazure_roots() == Hs.Demazure_roots() True - sage: Bs = ToricVariety(Fan(rays=[(s,1),(s,-1),(-s,-1),(-s,1)], cones=cones)) + sage: Bs = ToricVariety(Fan(rays=[(s,1), (s,-1), (-s,-1), (-s,1)], cones=cones)) sage: Bs.Demazure_roots() () @@ -3069,7 +3003,7 @@ def normalize_names(names=None, ngens=None, prefix=None, indices=None, return names -#***************************************************************** +# ***************************************************************** class CohomologyRing(QuotientRing_generic, UniqueRepresentation): r""" The (even) cohomology ring of a toric variety. @@ -3257,7 +3191,7 @@ def _element_constructor_(self,x): [z^2 + z + 1] """ fan = self._variety.fan() - if isinstance(x, CohomologyClass) and x.parent()==self: + if isinstance(x, CohomologyClass) and x.parent() == self: return x if isinstance(x, QuotientRingElement): x = x.lift() @@ -3340,7 +3274,7 @@ def gen(self, i): return CohomologyClass(self, self._polynomial_ring.gen(i)) -#***************************************************************** +# ***************************************************************** def is_CohomologyClass(x): r""" Check whether ``x`` is a cohomology class of a toric variety. @@ -3366,10 +3300,10 @@ def is_CohomologyClass(x): sage: is_CohomologyClass('z') False """ - return isinstance(x,CohomologyClass) + return isinstance(x, CohomologyClass) -#***************************************************************** +# ***************************************************************** class CohomologyClass(QuotientRingElement): r""" An element of the :class:`CohomologyRing`. @@ -3491,9 +3425,9 @@ def part_of_degree(self, d): sage: P1xP1 = toric_varieties.P1xP1() sage: t = P1xP1.cohomology_ring().gen(0) sage: y = P1xP1.cohomology_ring().gen(2) - sage: 3*t+4*t^2*y+y+t*y+t+1 + sage: 3*t + 4*t^2*y + y + t*y + t + 1 [t*y + 4*t + y + 1] - sage: (3*t+4*t^2*y+y+t*y+t+1).part_of_degree(1) + sage: (3*t + 4*t^2*y + y + t*y + t + 1).part_of_degree(1) [4*t + y] """ Q = self.parent() diff --git a/src/sage/schemes/toric/weierstrass.py b/src/sage/schemes/toric/weierstrass.py index 552a91093d6..137dfd3e042 100644 --- a/src/sage/schemes/toric/weierstrass.py +++ b/src/sage/schemes/toric/weierstrass.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Weierstrass form of a toric elliptic curve @@ -25,9 +26,9 @@ (that is, set one or more of the coefficients to zero) of the following three cases. In inhomogeneous coordinates, they are - * Cubic in `\mathbb{P}^2`: +* Cubic in `\mathbb{P}^2`: - .. MATH:: + .. MATH:: \begin{split} p(x,y) =&\; @@ -38,9 +39,9 @@ a_{02} y^{2} + a_{10} x + a_{01} y + a_{00} \end{split} - * Biquadric in `\mathbb{P}^1\times \mathbb{P}^1`: +* Biquadric in `\mathbb{P}^1\times \mathbb{P}^1`: - .. MATH:: + .. MATH:: \begin{split} p(x,y) =&\; @@ -51,10 +52,9 @@ y^2 a_{02} + y a_{01} + a_{00} \end{split} - * Anticanonical hypersurface in weighted projective space - `\mathbb{P}^2[1,1,2]`: +* Anticanonical hypersurface in weighted projective space `\mathbb{P}^2[1,1,2]`: - .. MATH:: + .. MATH:: \begin{split} p(x,y) =&\; @@ -141,7 +141,7 @@ from sage.rings.infinity import Infinity from sage.modules.free_module_element import vector from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL -from sage.rings.invariants.all import invariant_theory +from sage.rings.invariants.invariant_theory import invariant_theory ###################################################################### @@ -160,20 +160,18 @@ def Discriminant(polynomial, variables=None): See :func:`WeierstrassForm` for how to specify the input polynomial(s) and variables. - OUTPUT: - - The discriminant of the elliptic curve. + OUTPUT: The discriminant of the elliptic curve. EXAMPLES:: sage: from sage.schemes.toric.weierstrass import Discriminant sage: R.<x, y, z> = QQ[] - sage: Discriminant(x^3+y^3+z^3) + sage: Discriminant(x^3 + y^3 + z^3) 19683/16 sage: Discriminant(x*y*z) 0 sage: R.<w,x,y,z> = QQ[] - sage: quadratic1 = w^2+x^2+y^2 + sage: quadratic1 = w^2 + x^2 + y^2 sage: quadratic2 = z^2 + w*x sage: Discriminant([quadratic1, quadratic2]) -1/16 @@ -196,18 +194,18 @@ def j_invariant(polynomial, variables=None): The j-invariant of the (irreducible) cubic. Notable special values: - * The Fermat cubic: `j(x^3+y^3+z^3) = 0` + * The Fermat cubic: `j(x^3+y^3+z^3) = 0` - * A nodal cubic: `j(-y^2 + x^2 + x^3) = \infty` + * A nodal cubic: `j(-y^2 + x^2 + x^3) = \infty` - * A cuspidal cubic `y^2=x^3` has undefined `j`-invariant. In this - case, a ``ValueError`` is returned. + * A cuspidal cubic `y^2=x^3` has undefined `j`-invariant. In this + case, a ``ValueError`` is raised. EXAMPLES:: sage: from sage.schemes.toric.weierstrass import j_invariant sage: R.<x,y,z> = QQ[] - sage: j_invariant(x^3+y^3+z^3) + sage: j_invariant(x^3 + y^3 + z^3) 0 sage: j_invariant(-y^2 + x^2 + x^3) +Infinity @@ -538,7 +536,7 @@ def _check_homogeneity(polynomial, variables, weights, total_weight=None): ....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3) sage: _check_homogeneity(p, [x,y,z], (1,1,1), 3) - sage: _check_homogeneity(p+x^4, [x,y,z], (1,1,1), 3) + sage: _check_homogeneity(p + x^4, [x,y,z], (1,1,1), 3) Traceback (most recent call last): ... ValueError: the polynomial is not homogeneous with weights (1, 1, 1) @@ -632,7 +630,7 @@ def _check_polynomial_P2(cubic, variables): sage: from sage.schemes.toric.weierstrass import _check_polynomial_P2 sage: R.<x,y,z> = QQ[] - sage: cubic = x^3+y^3+z^3 + sage: cubic = x^3 + y^3 + z^3 sage: _check_polynomial_P2(cubic, [x,y,z]) (x, y, z) sage: _check_polynomial_P2(cubic, None) @@ -640,7 +638,7 @@ def _check_polynomial_P2(cubic, variables): sage: _check_polynomial_P2(cubic.subs(z=1), None) (x, y, None) sage: R.<x,y,z,t> = QQ[] - sage: cubic = x^3+y^3+z^3 + t*x*y*z + sage: cubic = x^3 + y^3 + z^3 + t*x*y*z sage: _check_polynomial_P2(cubic, [x,y,z]) (x, y, z) sage: _check_polynomial_P2(cubic, [x,y,t]) @@ -684,11 +682,11 @@ def WeierstrassForm_P2(polynomial, variables=None): sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2 sage: R.<x,y,z> = QQ[] - sage: WeierstrassForm_P2( x^3+y^3+z^3 ) + sage: WeierstrassForm_P2(x^3 + y^3 + z^3) (0, -27/4) sage: R.<x,y,z, a,b> = QQ[] - sage: WeierstrassForm_P2( -y^2*z+x^3+a*x*z^2+b*z^3, [x,y,z] ) + sage: WeierstrassForm_P2(-y^2*z + x^3 + a*x*z^2 + b*z^3, [x,y,z]) (a, b) TESTS:: @@ -789,9 +787,9 @@ def _check_polynomial_P1xP1(biquadric, variables): sage: from sage.schemes.toric.weierstrass import _check_polynomial_P1xP1 sage: R.<x0,x1,y0,y1> = QQ[] - sage: biquadric = ( x0^2*y0^2 + x0*x1*y0^2*2 + x1^2*y0^2*3 - ....: + x0^2*y0*y1*4 + x0*x1*y0*y1*5 + x1^2*y0*y1*6 - ....: + x0^2*y1^2*7 + x0*x1*y1^2*8 ) + sage: biquadric = (x0^2*y0^2 + x0*x1*y0^2*2 + x1^2*y0^2*3 + ....: + x0^2*y0*y1*4 + x0*x1*y0*y1*5 + x1^2*y0*y1*6 + ....: + x0^2*y1^2*7 + x0*x1*y1^2*8) sage: _check_polynomial_P1xP1(biquadric, [x0,x1,y0,y1]) [x0, x1, y0, y1] sage: _check_polynomial_P1xP1(biquadric, None) @@ -834,9 +832,9 @@ def _partial_discriminant(quadric, y0, y1=None): EXAMPLES:: sage: R.<x0,x1,y0,y1,a00,a10,a20,a01,a11,a21,a02,a12,a22> = QQ[] - sage: biquadric = ( x0^2*y0^2*a00 + x0*x1*y0^2*a10 + x1^2*y0^2*a20 - ....: + x0^2*y0*y1*a01 + x0*x1*y0*y1*a11 + x1^2*y0*y1*a21 - ....: + x0^2*y1^2*a02 + x0*x1*y1^2*a12 + x1^2*y1^2*a22 ) + sage: biquadric = (x0^2*y0^2*a00 + x0*x1*y0^2*a10 + x1^2*y0^2*a20 + ....: + x0^2*y0*y1*a01 + x0*x1*y0*y1*a11 + x1^2*y0*y1*a21 + ....: + x0^2*y1^2*a02 + x0*x1*y1^2*a12 + x1^2*y1^2*a22) sage: from sage.schemes.toric.weierstrass import _partial_discriminant sage: _partial_discriminant(biquadric, y0, y1) x0^4*a01^2 + 2*x0^3*x1*a01*a11 + x0^2*x1^2*a11^2 @@ -888,10 +886,10 @@ def WeierstrassForm_P1xP1(biquadric, variables=None): EXAMPLES:: sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P1xP1 - sage: R.<x0,x1,y0,y1>= QQ[] - sage: biquadric = ( x0^2*y0^2 + x0*x1*y0^2*2 + x1^2*y0^2*3 - ....: + x0^2*y0*y1*4 + x0*x1*y0*y1*5 + x1^2*y0*y1*6 - ....: + x0^2*y1^2*7 + x0*x1*y1^2*8 ) + sage: R.<x0,x1,y0,y1> = QQ[] + sage: biquadric = (x0^2*y0^2 + x0*x1*y0^2*2 + x1^2*y0^2*3 + ....: + x0^2*y0*y1*4 + x0*x1*y0*y1*5 + x1^2*y0*y1*6 + ....: + x0^2*y1^2*7 + x0*x1*y1^2*8) sage: WeierstrassForm_P1xP1(biquadric, [x0, x1, y0, y1]) (1581/16, -3529/32) @@ -905,9 +903,9 @@ def WeierstrassForm_P1xP1(biquadric, variables=None): TESTS:: sage: R.<x0,x1,y0,y1,a00,a10,a20,a01,a11,a21,a02,a12,a22> = QQ[] - sage: biquadric = ( x0^2*y0^2*a00 + x0*x1*y0^2*a10 + x1^2*y0^2*a20 - ....: + x0^2*y0*y1*a01 + x0*x1*y0*y1*a11 + x1^2*y0*y1*a21 - ....: + x0^2*y1^2*a02 + x0*x1*y1^2*a12 ) + sage: biquadric = (x0^2*y0^2*a00 + x0*x1*y0^2*a10 + x1^2*y0^2*a20 + ....: + x0^2*y0*y1*a01 + x0*x1*y0*y1*a11 + x1^2*y0*y1*a21 + ....: + x0^2*y1^2*a02 + x0*x1*y1^2*a12) sage: WeierstrassForm_P1xP1(biquadric, [x0, x1, y0, y1]) (-1/48*a11^4 + 1/6*a01*a11^2*a21 - 1/3*a01^2*a21^2 + 1/6*a20*a11^2*a02 + 1/3*a20*a01*a21*a02 - 1/2*a10*a11*a21*a02 @@ -935,7 +933,7 @@ def WeierstrassForm_P1xP1(biquadric, variables=None): + 1/9*a10^2*a20*a02*a12^2 - 2/3*a00*a20^2*a02*a12^2 - 2/27*a10^3*a12^3 + 1/3*a00*a10*a20*a12^3) - sage: _ == WeierstrassForm_P1xP1(biquadric.subs(x1=1,y1=1), [x0, y0]) + sage: _ == WeierstrassForm_P1xP1(biquadric.subs(x1=1, y1=1), [x0, y0]) True """ x, y, s, t = _check_polynomial_P1xP1(biquadric, variables) @@ -1027,7 +1025,8 @@ def WeierstrassForm_P2_112(polynomial, variables=None): EXAMPLES:: sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2_112 - sage: fan = Fan(rays=[(1,0),(0,1),(-1,-2),(0,-1)],cones=[[0,1],[1,2],[2,3],[3,0]]) + sage: fan = Fan(rays=[(1,0),(0,1),(-1,-2),(0,-1)], + ....: cones=[[0,1],[1,2],[2,3],[3,0]]) sage: P112.<x,y,z,t> = ToricVariety(fan) sage: (-P112.K()).sections_monomials() (z^4*t^2, x*z^3*t^2, x^2*z^2*t^2, x^3*z*t^2, @@ -1038,8 +1037,8 @@ def WeierstrassForm_P2_112(polynomial, variables=None): TESTS:: sage: R.<x,y,z,t,a40,a30,a20,a10,a00,a21,a11,a01,a02> = QQ[] - sage: p = ( a40*x^4*t^2 + a30*x^3*z*t^2 + a20*x^2*z^2*t^2 + a10*x*z^3*t^2 + - ....: a00*z^4*t^2 + a21*x^2*y*t + a11*x*y*z*t + a01*y*z^2*t + a02*y^2 ) + sage: p = (a40*x^4*t^2 + a30*x^3*z*t^2 + a20*x^2*z^2*t^2 + a10*x*z^3*t^2 + + ....: a00*z^4*t^2 + a21*x^2*y*t + a11*x*y*z*t + a01*y*z^2*t + a02*y^2) sage: WeierstrassForm_P2_112(p, [x,y,z,t]) (-1/48*a11^4 + 1/6*a21*a11^2*a01 - 1/3*a21^2*a01^2 + a00*a21^2*a02 - 1/2*a10*a21*a11*a02 + 1/6*a20*a11^2*a02 + 1/3*a20*a21*a01*a02 @@ -1061,15 +1060,15 @@ def WeierstrassForm_P2_112(polynomial, variables=None): + 1/3*a30*a20*a10*a02^3 - a40*a10^2*a02^3 - a30^2*a00*a02^3 + 8/3*a40*a20*a00*a02^3) - sage: _ == WeierstrassForm_P2_112(p.subs(z=1,t=1), [x,y]) + sage: _ == WeierstrassForm_P2_112(p.subs(z=1, t=1), [x,y]) True sage: cubic = p.subs(a40=0) sage: a,b = WeierstrassForm_P2_112(cubic, [x,y,z,t]) - sage: a = a.subs(t=1,z=1) - sage: b = b.subs(t=1,z=1) + sage: a = a.subs(t=1, z=1) + sage: b = b.subs(t=1, z=1) sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2 - sage: (a,b) == WeierstrassForm_P2(cubic.subs(t=1,z=1), [x,y]) + sage: (a,b) == WeierstrassForm_P2(cubic.subs(t=1, z=1), [x,y]) True """ x, y, z, t = _check_polynomial_P2_112(polynomial, variables) diff --git a/src/sage/schemes/toric/weierstrass_covering.py b/src/sage/schemes/toric/weierstrass_covering.py index fe3c45ed722..13e3c24b2c1 100644 --- a/src/sage/schemes/toric/weierstrass_covering.py +++ b/src/sage/schemes/toric/weierstrass_covering.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Map to the Weierstrass form of a toric elliptic curve @@ -161,10 +162,10 @@ def WeierstrassMap(polynomial, variables=None): 1/2*x^6*y^3 - 1/2*x^3*y^6 - 1/2*x^6*z^3 + 1/2*y^6*z^3 + 1/2*x^3*z^6 - 1/2*y^3*z^6, x*y*z) - sage: f, g = WeierstrassForm(cubic); (f,g) - (0, -27/4) - sage: cubic.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6) - True + sage: f, g = WeierstrassForm(cubic); (f,g) + (0, -27/4) + sage: cubic.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6) + True Only the affine span of the Newton polytope of the polynomial matters. For example:: @@ -192,8 +193,8 @@ def WeierstrassMap(polynomial, variables=None): - 1/27*t^4*z^6 - 4/81*t^2*x^4*y^2 - 4/81*t^2*x^3*y^2*z - 4/81*t^2*x*y^2*z^3 - 4/81*t^2*y^2*z^4 - 2/81*x^2*y^4 - 4/81*x*y^4*z - 2/81*y^4*z^2, - 0, - 1/3*t^2*x^2*z + 1/3*t^2*x*z^2 - 1/9*x*y^2 - 1/9*y^2*z) + 0, + 1/3*t^2*x^2*z + 1/3*t^2*x*z^2 - 1/9*x*y^2 - 1/9*y^2*z) sage: WeierstrassForm(x*y^2 + y^2 + x^3 + 1, transformation=True) (-1/27*x^6 - 4/81*x^4*y^2 - 2/81*x^2*y^4 - 2/27*x^5 - 4/81*x^3*y^2 - 4/81*x*y^4 - 5/27*x^4 - 2/81*y^4 - 8/27*x^3 @@ -280,7 +281,7 @@ def homogenize(inhomog, degree): def WeierstrassMap_P2(polynomial, variables=None): r""" - Map a cubic to its Weierstrass form + Map a cubic to its Weierstrass form. Input/output is the same as :func:`WeierstrassMap`, except that the input polynomial must be a cubic in `\mathbb{P}^2`, @@ -301,7 +302,7 @@ def WeierstrassMap_P2(polynomial, variables=None): sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2 sage: from sage.schemes.toric.weierstrass_covering import WeierstrassMap_P2 sage: R.<x,y,z> = QQ[] - sage: equation = x^3+y^3+z^3+x*y*z + sage: equation = x^3 + y^3 + z^3 + x*y*z sage: f, g = WeierstrassForm_P2(equation) sage: X,Y,Z = WeierstrassMap_P2(equation) sage: equation.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6) @@ -310,7 +311,7 @@ def WeierstrassMap_P2(polynomial, variables=None): sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2 sage: from sage.schemes.toric.weierstrass_covering import WeierstrassMap_P2 sage: R.<x,y> = QQ[] - sage: equation = x^3+y^3+1 + sage: equation = x^3 + y^3 + 1 sage: f, g = WeierstrassForm_P2(equation) sage: X,Y,Z = WeierstrassMap_P2(equation) sage: equation.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6) @@ -344,9 +345,9 @@ def WeierstrassMap_P1xP1(polynomial, variables=None): sage: from sage.schemes.toric.weierstrass_covering import WeierstrassMap_P1xP1 sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P1xP1 - sage: R.<x0,x1,y0,y1,a>= QQ[] - sage: biquadric = ( x0^2*y0^2 + x1^2*y0^2 + x0^2*y1^2 + x1^2*y1^2 + - ....: a * x0*x1*y0*y1*5 ) + sage: R.<x0,x1,y0,y1,a> = QQ[] + sage: biquadric = (x0^2*y0^2 + x1^2*y0^2 + x0^2*y1^2 + x1^2*y1^2 + + ....: a * x0*x1*y0*y1*5) sage: f, g = WeierstrassForm_P1xP1(biquadric, [x0, x1, y0, y1]); (f,g) (-625/48*a^4 + 25/3*a^2 - 16/3, 15625/864*a^6 - 625/36*a^4 - 100/9*a^2 + 128/27) sage: X, Y, Z = WeierstrassMap_P1xP1(biquadric, [x0, x1, y0, y1]) @@ -356,8 +357,8 @@ def WeierstrassMap_P1xP1(polynomial, variables=None): sage: R = PolynomialRing(QQ, 'x,y,s,t', order='lex') sage: R.inject_variables() Defining x, y, s, t - sage: equation = ( s^2*(x^2+2*x*y+3*y^2) + s*t*(4*x^2+5*x*y+6*y^2) - ....: + t^2*(7*x^2+8*x*y+9*y^2) ) + sage: equation = (s^2*(x^2+2*x*y+3*y^2) + s*t*(4*x^2+5*x*y+6*y^2) + ....: + t^2*(7*x^2+8*x*y+9*y^2)) sage: X, Y, Z = WeierstrassMap_P1xP1(equation, [x,y,s,t]) sage: f, g = WeierstrassForm_P1xP1(equation, variables=[x,y,s,t]) sage: (-Y^2 + X^3 + f*X*Z^4 + g*Z^6).reduce(R.ideal(equation)) @@ -429,7 +430,8 @@ def WeierstrassMap_P2_112(polynomial, variables=None): Another example, this time in homogeneous coordinates:: - sage: fan = Fan(rays=[(1,0),(0,1),(-1,-2),(0,-1)],cones=[[0,1],[1,2],[2,3],[3,0]]) + sage: fan = Fan(rays=[(1,0),(0,1),(-1,-2),(0,-1)], + ....: cones=[[0,1],[1,2],[2,3],[3,0]]) sage: P112.<x,y,z,t> = ToricVariety(fan) sage: (-P112.K()).sections_monomials() (z^4*t^2, x*z^3*t^2, x^2*z^2*t^2, x^3*z*t^2, diff --git a/src/sage/schemes/toric/weierstrass_higher.py b/src/sage/schemes/toric/weierstrass_higher.py index 034d3ead9e4..2a83234e6ca 100644 --- a/src/sage/schemes/toric/weierstrass_higher.py +++ b/src/sage/schemes/toric/weierstrass_higher.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.geometry.polyhedron sage.graphs r""" Weierstrass for elliptic curves in higher codimension @@ -11,7 +12,7 @@ quadratic equations in `\mathbb{P}^3` :: sage: R.<w,x,y,z> = QQ[] - sage: quadratic1 = w^2+x^2+y^2 + sage: quadratic1 = w^2 + x^2 + y^2 sage: quadratic2 = z^2 + w*x sage: WeierstrassForm([quadratic1, quadratic2]) (-1/4, 0) @@ -20,14 +21,14 @@ X^3 - \frac{1}{4} X Z^4`. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Volker Braun <vbraun.name@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.invariants.invariant_theory import invariant_theory @@ -50,7 +51,7 @@ def WeierstrassForm2(polynomial, variables=None, transformation=False): sage: from sage.schemes.toric.weierstrass_higher import WeierstrassForm2 sage: R.<w,x,y,z> = QQ[] - sage: quadratic1 = w^2+x^2+y^2 + sage: quadratic1 = w^2 + x^2 + y^2 sage: quadratic2 = z^2 + w*x sage: WeierstrassForm2([quadratic1, quadratic2]) (-1/4, 0) @@ -87,7 +88,7 @@ def _check_polynomials_P3(quadratic1, quadratic2, variables): sage: from sage.schemes.toric.weierstrass_higher import _check_polynomials_P3 sage: R.<w,x,y,z> = QQ[] - sage: quadratic = w^2+x^2+y^2+z^2 + sage: quadratic = w^2 + x^2 + y^2 + z^2 sage: _check_polynomials_P3(w^2, quadratic, [w,x,y,z]) (w, x, y, z) sage: _check_polynomials_P3(w^2, quadratic, None) @@ -95,7 +96,7 @@ def _check_polynomials_P3(quadratic1, quadratic2, variables): sage: _check_polynomials_P3(z^2, quadratic.subs(w=0), None) (x, y, z, None) sage: R.<w,x,y,z,t> = QQ[] - sage: quadratic = w^2+x^2+y^2+z^2 + t*(x*y+y*z+z*w+w*x) + sage: quadratic = w^2 + x^2 + y^2 + z^2 + t*(x*y+y*z+z*w+w*x) sage: _check_polynomials_P3(w^2, quadratic, [w,x,y,z]) (w, x, y, z) sage: _check_polynomials_P3(w^2, quadratic, [w,x,y,t]) @@ -157,7 +158,7 @@ def _biquadratic_syzygy_quartic(quadratic1, quadratic2, variables=None): sage: from sage.schemes.toric.weierstrass_higher import _biquadratic_syzygy_quartic sage: R.<w,x,y,z> = QQ[] - sage: _biquadratic_syzygy_quartic(w^2+x^2+y^2, z^2) + sage: _biquadratic_syzygy_quartic(w^2 + x^2 + y^2, z^2) (Joint quaternary quadratic with coefficients (1, 1, 1, 0, 0, 0, 0, 0, 0, 0) and quaternary quadratic with coefficients (0, 0, 0, 1, 0, 0, 0, 0, 0, 0), Binary quartic with coefficients (0, 0, 0, -1, 0), {aux...}) @@ -168,9 +169,9 @@ def _biquadratic_syzygy_quartic(quadratic1, quadratic2, variables=None): # construct auxiliary polynomial ring to work with the rhs of the syzygy R = biquadratic.ring() n = R.ngens() - R_aux = PolynomialRing(R.base_ring(), n+2, 'aux') - to_aux = dict() - from_aux = dict() + R_aux = PolynomialRing(R.base_ring(), n + 2, 'aux') + to_aux = {} + from_aux = {} for var, var_aux in zip(R.gens(), R_aux.gens()[0:n]): to_aux[var] = var_aux from_aux[var_aux] = var @@ -181,9 +182,9 @@ def _biquadratic_syzygy_quartic(quadratic1, quadratic2, variables=None): # Syzygy is J^2 = syz_rhs + (terms that vanish on the biquadratic) with # J = biquadratic.J_covariant() syz_rhs = T**4 * biquadratic.Delta_invariant().subs(to_aux) \ - - T**3*T_prime * biquadratic.Theta_invariant().subs(to_aux) \ - + T**2*T_prime**2 * biquadratic.Phi_invariant().subs(to_aux) \ - - T*T_prime**3 * biquadratic.Theta_prime_invariant().subs(to_aux) \ + - T**3 * T_prime * biquadratic.Theta_invariant().subs(to_aux) \ + + T**2 * T_prime**2 * biquadratic.Phi_invariant().subs(to_aux) \ + - T * T_prime**3 * biquadratic.Theta_prime_invariant().subs(to_aux) \ + T_prime**4 * biquadratic.Delta_prime_invariant().subs(to_aux) quartic = invariant_theory.binary_quartic(syz_rhs, [T, T_prime]) return (biquadratic, quartic, from_aux) @@ -203,7 +204,7 @@ def WeierstrassForm_P3(quadratic1, quadratic2, variables=None): sage: from sage.schemes.toric.weierstrass_higher import WeierstrassForm_P3 sage: R.<w,x,y,z> = QQ[] - sage: quadratic1 = w^2+x^2+y^2 + sage: quadratic1 = w^2 + x^2 + y^2 sage: quadratic2 = z^2 + w*x sage: WeierstrassForm_P3(quadratic1, quadratic2) (-1/4, 0) @@ -224,7 +225,7 @@ def WeierstrassForm_P3(quadratic1, quadratic2, variables=None): _biquadratic_syzygy_quartic(quadratic1, quadratic2, variables=variables) a = quartic.EisensteinD().subs(from_aux) b = quartic.EisensteinE().subs(from_aux) - return (-4*a, 16*b) + return (-4 * a, 16 * b) ###################################################################### @@ -242,7 +243,7 @@ def WeierstrassMap_P3(quadratic1, quadratic2, variables=None): sage: from sage.schemes.toric.weierstrass_higher import \ ....: WeierstrassMap_P3, WeierstrassForm_P3 sage: R.<w,x,y,z> = QQ[] - sage: quadratic1 = w^2+x^2+y^2 + sage: quadratic1 = w^2 + x^2 + y^2 sage: quadratic2 = z^2 + w*x sage: X, Y, Z = WeierstrassMap_P3(quadratic1, quadratic2) sage: X @@ -287,4 +288,4 @@ def WeierstrassMap_P3(quadratic1, quadratic2, variables=None): J = biquadratic.J_covariant() g = quartic.g_covariant().subs(from_aux) h = quartic.h_covariant().subs(from_aux) - return (4*g, 4*h, J) + return (4 * g, 4 * h, J) diff --git a/src/sage/server/__init__.py b/src/sage/server/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index cc2ce557bd0..f110f55cfc9 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -28,6 +28,7 @@ from sage.categories.rings import Rings _Rings = Rings() + class CartesianProduct(UniqueRepresentation, Parent): """ A class implementing a raw data structure for Cartesian products @@ -79,7 +80,7 @@ def __init__(self, sets, category, flatten=False): self._sets = tuple(sets) Parent.__init__(self, category=category) - def _element_constructor_(self,x): + def _element_constructor_(self, x): r""" Construct an element of a Cartesian product from a list or iterable @@ -141,7 +142,7 @@ def _repr_(self): sage: cartesian_product([QQ, ZZ, ZZ]) # indirect doctest The Cartesian product of (Rational Field, Integer Ring, Integer Ring) """ - return "The Cartesian product of %s"%(self._sets,) + return "The Cartesian product of %s" % (self._sets,) def __contains__(self, x): """ @@ -160,8 +161,8 @@ def __contains__(self, x): return True elif not isinstance(x, tuple): return False - return ( len(x) == len(self._sets) - and all(elt in self._sets[i] for i,elt in enumerate(x)) ) + return (len(x) == len(self._sets) + and all(elt in self._sets[i] for i, elt in enumerate(x))) def cartesian_factors(self): """ diff --git a/src/sage/sets/condition_set.py b/src/sage/sets/condition_set.py index 34265775dd3..92f17647315 100644 --- a/src/sage/sets/condition_set.py +++ b/src/sage/sets/condition_set.py @@ -18,7 +18,7 @@ from sage.categories.sets_cat import Sets from sage.categories.enumerated_sets import EnumeratedSets from sage.misc.cachefunc import cached_method -from sage.misc.misc import _stable_uniq +from sage.combinat.subset import uniq from sage.structure.element import Expression from .set import Set, Set_base, Set_boolean_operators, Set_add_sub_operators @@ -173,7 +173,7 @@ def __classcall_private__(cls, universe, *predicates, vars=None, names=None, cat else: other_predicates.append(predicate) - predicates = list(_stable_uniq(callable_symbolic_predicates + other_predicates)) + predicates = list(uniq(callable_symbolic_predicates + other_predicates)) if not other_predicates and not callable_symbolic_predicates: if names is None and category is None: @@ -204,7 +204,7 @@ def __init__(self, universe, *predicates, names=None, category=None): if isinstance(universe, Parent): facade = universe super().__init__(facade=facade, category=category, - names=names, normalize=False) # names already normalized by classcall + names=names, normalize=False) # names already normalized by classcall def _first_ngens(self, n): r""" @@ -368,7 +368,7 @@ def _an_element_(self): r""" Return an element of ``self``. - This may raise ``NotImplementedError``. + This may raise :class:`NotImplementedError`. TESTS:: diff --git a/src/sage/sets/disjoint_set.pxd b/src/sage/sets/disjoint_set.pxd index 0b16d2fce83..1ec38f5966b 100644 --- a/src/sage/sets/disjoint_set.pxd +++ b/src/sage/sets/disjoint_set.pxd @@ -21,4 +21,3 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): cdef list _int_to_el cdef dict _el_to_int cdef DisjointSet_of_integers _d - diff --git a/src/sage/sets/disjoint_set.pyx b/src/sage/sets/disjoint_set.pyx index eb6b04f4b9c..0dc2f93c20b 100644 --- a/src/sage/sets/disjoint_set.pyx +++ b/src/sage/sets/disjoint_set.pyx @@ -86,7 +86,7 @@ def DisjointSet(arg): INPUT: - - ``arg`` -- non negative integer or an iterable of hashable objects. + - ``arg`` -- non negative integer or an iterable of hashable objects. EXAMPLES: @@ -141,6 +141,7 @@ def DisjointSet(arg): else: return DisjointSet_of_hashables(arg) + cdef class DisjointSet_class(SageObject): r""" Common class and methods for :class:`DisjointSet_of_integers` and @@ -398,7 +399,7 @@ cdef class DisjointSet_of_integers(DisjointSet_class): """ l = [] cdef int i - for i from 0 <= i < self.cardinality(): + for i in range(self.cardinality()): l.append(self._nodes.parent[i]) return l @@ -439,7 +440,7 @@ cdef class DisjointSet_of_integers(DisjointSet_class): sage: d {{0, 1, 2, 3}, {4}} """ - for i,parent in enumerate(l): + for i, parent in enumerate(l): self.union(parent, i) def find(self, int i): @@ -491,8 +492,8 @@ cdef class DisjointSet_of_integers(DisjointSet_class): INPUT: - - ``i`` - element in ``self`` - - ``j`` - element in ``self`` + - ``i`` -- element in ``self`` + - ``j`` -- element in ``self`` EXAMPLES:: @@ -515,9 +516,9 @@ cdef class DisjointSet_of_integers(DisjointSet_class): """ cdef int card = self._nodes.degree if i < 0 or i >= card: - raise ValueError('i(=%s) must be between 0 and %s'%(i, card-1)) + raise ValueError('i(=%s) must be between 0 and %s' % (i, card - 1)) if j < 0 or j >= card: - raise ValueError('j(=%s) must be between 0 and %s'%(j, card-1)) + raise ValueError('j(=%s) must be between 0 and %s' % (j, card - 1)) OP_join(self._nodes, i, j) def root_to_elements_dict(self): @@ -541,7 +542,7 @@ cdef class DisjointSet_of_integers(DisjointSet_class): """ s = {} cdef int i - for i from 0 <= i < self.cardinality(): + for i in range(self.cardinality()): o = self.find(i) if o not in s: s[o] = [] @@ -565,7 +566,7 @@ cdef class DisjointSet_of_integers(DisjointSet_class): """ d = {} cdef int i - for i from 0 <= i < self.cardinality(): + for i in range(self.cardinality()): d[i] = self.find(i) return d @@ -597,11 +598,8 @@ cdef class DisjointSet_of_integers(DisjointSet_class): {{0}, {1, 2, 3, 4}} sage: d.to_digraph().edges(sort=True) [(0, 0, None), (1, 1, None), (2, 1, None), (3, 1, None), (4, 1, None)] - """ - d = {} - for i from 0 <= i < self.cardinality(): - d[i] = [self._nodes.parent[i]] + d = {i: [self._nodes.parent[i]] for i in range(self.cardinality())} from sage.graphs.graph import DiGraph return DiGraph(d) @@ -639,7 +637,7 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): INPUT: - - ``iterable`` -- An iterable of hashable objects. + - ``iterable`` -- An iterable of hashable objects. EXAMPLES:: @@ -654,7 +652,7 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): """ self._int_to_el = [] self._el_to_int = {} - for (i,e) in enumerate(iterable): + for i, e in enumerate(iterable): self._int_to_el.append(e) self._el_to_int[e] = i self._d = DisjointSet_of_integers(len(self._int_to_el)) @@ -716,7 +714,7 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): gs = self._d.__getstate__() l = [] cdef int i - for i from 0 <= i < self.cardinality(): + for i in range(self.cardinality()): l.append(self._int_to_el[gs[i]]) return list(zip(self._int_to_el, l)) @@ -743,7 +741,7 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): sage: d {{'a', 'b', 'c', 'd', 'e'}} """ - for a,b in l: + for a, b in l: self.union(a, b) def find(self, e): @@ -794,8 +792,8 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): INPUT: - - ``e`` - element in ``self`` - - ``f`` - element in ``self`` + - ``e`` -- element in ``self`` + - ``f`` -- element in ``self`` EXAMPLES:: @@ -889,7 +887,7 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): [(0, 0, None), (1, 1, None), (2, 1, None), (3, 1, None), (4, 1, None)] """ d = {} - for i from 0 <= i < self.cardinality(): + for i in range(self.cardinality()): e = self._int_to_el[i] p = self._int_to_el[self._nodes.parent[i]] d[e] = [p] diff --git a/src/sage/sets/disjoint_union_enumerated_sets.py b/src/sage/sets/disjoint_union_enumerated_sets.py index c1276dc9edf..3dea567a779 100644 --- a/src/sage/sets/disjoint_union_enumerated_sets.py +++ b/src/sage/sets/disjoint_union_enumerated_sets.py @@ -7,12 +7,12 @@ - Florent Hivert (2010-03): classcall related stuff. - Florent Hivert (2010-12): fixed facade element construction. """ -#**************************************************************************** +# *************************************************************************** # Copyright (C) 2009 Florent Hivert <Florent.Hivert@univ-rouen.fr> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#**************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from sage.structure.element import Element from sage.structure.parent import Parent @@ -25,6 +25,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.structure.unique_representation import UniqueRepresentation + class DisjointUnionEnumeratedSets(UniqueRepresentation, Parent): """ A class for disjoint unions of enumerated sets. @@ -258,8 +259,8 @@ def __classcall_private__(cls, fam, facade=True, """ # facade = options.pop('facade', True); # keepkey = options.pop('keepkey', False); - assert(isinstance(facade, bool)) - assert(isinstance(keepkey, bool)) + assert isinstance(facade, bool) + assert isinstance(keepkey, bool) return super().__classcall__( cls, Family(fam), facade=facade, keepkey=keepkey, category=category) @@ -311,8 +312,7 @@ def _repr_(self): sage: U Disjoint union of Finite family {1: {1, 2, 3}, 2: {4, 5, 6}} """ - return "Disjoint union of %s"%self._family - + return "Disjoint union of %s" % self._family def _is_a(self, x): """ @@ -337,10 +337,9 @@ def _is_a(self, x): else: from warnings import warn if self._family.cardinality() == Infinity: - warn("%s is an infinite union\nThe default implementation of __contains__ can loop forever. Please overload it."%(self)) + warn("%s is an infinite union\nThe default implementation of __contains__ can loop forever. Please overload it." % (self)) return any(x in a for a in self._family) - def __contains__(self, x): """ Check containment. @@ -406,7 +405,7 @@ def __iter__(self): if self._facade: yield el else: - yield self.element_class(self, el) # Bypass correctness tests + yield self.element_class(self, el) # Bypass correctness tests def an_element(self): """ @@ -517,7 +516,7 @@ def _element_constructor_default(self, el): if self._is_a(el): return self.element_class(self, el) else: - raise ValueError("value %s does not belong to %s"%(el, self)) + raise ValueError("value %s does not belong to %s" % (el, self)) def _element_constructor_facade(self, el): """ @@ -570,11 +569,11 @@ def _element_constructor_facade(self, el): try: return (el[0], P(el[1])) except Exception: - raise ValueError("cannot coerce `%s` in the parent `%s`"%(el[1], P)) + raise ValueError("cannot coerce `%s` in the parent `%s`" % (el[1], P)) # Check first to see if the parent of el is in the family if (isinstance(el, Element) and self._facade_for is not True - and el.parent() in self._facade_for): + and el.parent() in self._facade_for): return el for P in self._family: @@ -582,7 +581,7 @@ def _element_constructor_facade(self, el): return P(el) except Exception: pass - raise ValueError("cannot coerce `%s` in any parent in `%s`"%(el, self._family)) + raise ValueError("cannot coerce `%s` in any parent in `%s`" % (el, self._family)) @lazy_attribute def Element(self): diff --git a/src/sage/sets/family.py b/src/sage/sets/family.py index 10c59a02490..a630ef51e24 100644 --- a/src/sage/sets/family.py +++ b/src/sage/sets/family.py @@ -22,7 +22,7 @@ Category of finite enumerated sets """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Nicolas Thiery <nthiery at users.sf.net>, # Mike Hansen <mhansen@gmail.com>, # Florent Hivert <Florent.Hivert@univ-rouen.fr> @@ -32,7 +32,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** import types from copy import copy from pprint import pformat, saferepr @@ -48,8 +48,11 @@ from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.misc.call import AttrCallObject +from sage.sets.non_negative_integers import NonNegativeIntegers +from sage.rings.infinity import Infinity lazy_import('sage.combinat.combinat', 'CombinatorialClass') + def Family(indices, function=None, hidden_keys=[], hidden_function=None, lazy=False, name=None): r""" A Family is an associative container which models a family @@ -377,8 +380,8 @@ def Family(indices, function=None, hidden_keys=[], hidden_function=None, lazy=Fa sage: f[5] 1 """ - assert(isinstance(hidden_keys, list)) - assert(isinstance(lazy, bool)) + assert isinstance(hidden_keys, list) + assert isinstance(lazy, bool) if not hidden_keys: if hidden_function is not None: @@ -389,19 +392,19 @@ def Family(indices, function=None, hidden_keys=[], hidden_function=None, lazy=Fa raise ValueError("lazy keyword only makes sense together with function keyword") if isinstance(indices, dict): return FiniteFamily(indices) - if isinstance(indices, (list, tuple) ): + if isinstance(indices, (list, tuple)): return TrivialFamily(indices) - if isinstance(indices, (FiniteFamily, LazyFamily, TrivialFamily) ): + if isinstance(indices, (FiniteFamily, LazyFamily, TrivialFamily)): return indices if (indices in EnumeratedSets() - or isinstance(indices, CombinatorialClass)): + or isinstance(indices, CombinatorialClass)): return EnumeratedFamily(indices) if isinstance(indices, Iterable): return TrivialFamily(indices) raise NotImplementedError if (isinstance(indices, (list, tuple, FiniteEnumeratedSet)) - and not lazy): + and not lazy): return FiniteFamily({i: function(i) for i in indices}, keys=indices) @@ -488,13 +491,14 @@ def zip(self, f, other, name=None): sage: list(h) ['a1', 'b2', 'd3'] """ - assert(self.keys() == other.keys()) - assert(self.hidden_keys() == other.hidden_keys()) - return Family(self.keys(), lambda i: f(self[i],other[i]), hidden_keys=self.hidden_keys(), name=name) + assert self.keys() == other.keys() + assert self.hidden_keys() == other.hidden_keys() + return Family(self.keys(), lambda i: f(self[i], other[i]), + hidden_keys=self.hidden_keys(), name=name) def map(self, f, name=None): r""" - Returns the family `( f(\mathtt{self}[i]) )_{i \in I}`, where + Return the family `( f(\mathtt{self}[i]) )_{i \in I}`, where `I` is the index set of self. .. TODO:: good name? @@ -527,9 +531,9 @@ def inverse_family(self): sage: Family((3,4,7)).inverse_family() Finite family {3: 0, 4: 1, 7: 2} - """ - return Family( dict( (self[k], k) for k in self.keys()) ) + return Family({self[k]: k for k in self.keys()}) + class FiniteFamily(AbstractFamily): r""" @@ -653,7 +657,7 @@ def keys(self): ['c', 'a', 'b'] """ return (self._keys if self._keys is not None - else list(self._dictionary)) + else list(self._dictionary)) def values(self): """ @@ -708,7 +712,7 @@ def __eq__(self, other): False """ return (isinstance(other, self.__class__) and - self._keys == other._keys and + self._keys == other._keys and self._dictionary == other._dictionary) def _repr_(self): @@ -822,7 +826,8 @@ def __setstate__(self, state): sage: f Finite family {4: 'b'} """ - self.__init__(state['dictionary'], keys = state.get("keys")) + self.__init__(state['dictionary'], keys=state.get("keys")) + class FiniteFamilyWithHiddenKeys(FiniteFamily): r""" @@ -848,7 +853,7 @@ def __init__(self, dictionary, hidden_keys, hidden_function, keys=None): # would be better to define as usual method # any better to unset the def of __getitem__ by FiniteFamily? - #self.__getitem__ = lambda i: dictionary[i] if dictionary.has_key(i) else hidden_dictionary[i] + # self.__getitem__ = lambda i: dictionary[i] if dictionary.has_key(i) else hidden_dictionary[i] def __getitem__(self, i): """ @@ -918,7 +923,7 @@ def __setstate__(self, d): """ hidden_function = d['hidden_function'] if isinstance(hidden_function, str): - # Let's assume that hidden_function is an unpickled function. + # Let's assume that hidden_function is an unpickled function. from sage.misc.fpickle import unpickle_function hidden_function = unpickle_function(hidden_function) self.__init__(d['dictionary'], d['hidden_keys'], hidden_function) @@ -1069,15 +1074,15 @@ def _repr_(self): """ if self.function_name is not None: name = self.function_name + "(i)" - elif isinstance(self.function, type(lambda x:1)): + elif isinstance(self.function, type(lambda x: 1)): name = self.function.__name__ - name = name+"(i)" + name = name + "(i)" else: name = repr(self.function) if isinstance(self.function, AttrCallObject): - name = "i"+name[1:] + name = "i" + name[1:] else: - name = name+"(i)" + name = name + "(i)" return "Lazy family ({})_{{i in {}}}".format(name, self.set) def keys(self): @@ -1216,7 +1221,7 @@ def __setstate__(self, d): """ function = d['function'] if isinstance(function, bytes): - # Let's assume that function is an unpickled function. + # Let's assume that function is an unpickled function. from sage.misc.fpickle import unpickle_function function = unpickle_function(function) @@ -1242,7 +1247,7 @@ def __init__(self, enumeration): Family (3, 4, 7) sage: TestSuite(f).run() """ - Parent.__init__(self, category = FiniteEnumeratedSets()) + Parent.__init__(self, category=FiniteEnumeratedSets()) self._enumeration = tuple(enumeration) def __bool__(self): @@ -1294,7 +1299,7 @@ def _repr_(self): sage: f = TrivialFamily([3,4,7]); f # indirect doctest Family (3, 4, 7) """ - return "Family %s"%((self._enumeration),) + return "Family %s" % ((self._enumeration),) def keys(self): """ @@ -1398,9 +1403,6 @@ def map(self, f, name=None): return Family(tuple([f(x) for x in self._enumeration]), name=name) -from sage.sets.non_negative_integers import NonNegativeIntegers -from sage.rings.infinity import Infinity - class EnumeratedFamily(LazyFamily): r""" :class:`EnumeratedFamily` turns an enumerated set ``c`` into a family @@ -1467,8 +1469,8 @@ def __repr__(self): """ # return "Family ((%s)[i])_(i=1...%s)"%(self.enumset, self.enumset.cardinality()) if isinstance(self.enumset, FiniteEnumeratedSet): - return "Family %s"%(self.enumset._elements,) - return "Family (%s)"%(self.enumset) + return "Family %s" % (self.enumset._elements,) + return "Family (%s)" % (self.enumset) def __contains__(self, x): """ diff --git a/src/sage/sets/finite_enumerated_set.py b/src/sage/sets/finite_enumerated_set.py index a2f5dc759ec..cc8deaea4d8 100644 --- a/src/sage/sets/finite_enumerated_set.py +++ b/src/sage/sets/finite_enumerated_set.py @@ -23,7 +23,7 @@ from sage.categories.sets_cat import EmptySetError from sage.rings.integer import Integer -################################################################# + class FiniteEnumeratedSet(UniqueRepresentation, Parent): """ A class for finite enumerated set. @@ -271,7 +271,7 @@ def rank(self, x): index = rank - def unrank(self,i): + def unrank(self, i): r""" Return the element at position ``i``. @@ -402,5 +402,5 @@ def _element_constructor_(self, el): """ try: return self._elements[self.rank(el)] - except (ValueError,KeyError): - raise ValueError("%s not in %s"%(el, self)) + except (ValueError, KeyError): + raise ValueError("%s not in %s" % (el, self)) diff --git a/src/sage/sets/finite_set_maps.py b/src/sage/sets/finite_set_maps.py index ce5029d8032..e41f9f781b2 100644 --- a/src/sage/sets/finite_set_maps.py +++ b/src/sage/sets/finite_set_maps.py @@ -10,12 +10,12 @@ - Florent Hivert """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Florent Hivert <Florent.Hivert@univ-rouen.fr>, # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import itertools @@ -29,7 +29,7 @@ from sage.sets.integer_range import IntegerRange from sage.sets.finite_set_map_cy import ( FiniteSetMap_MN, FiniteSetMap_Set, - FiniteSetEndoMap_N, FiniteSetEndoMap_Set ) + FiniteSetEndoMap_N, FiniteSetEndoMap_Set) from sage.misc.cachefunc import cached_method # TODO: finite set maps should be morphisms in the category of finite sets @@ -156,7 +156,7 @@ class FiniteSetMaps(UniqueRepresentation, Parent): sage: TestSuite(FiniteSetMaps([], [1, 2])).run() """ @staticmethod - def __classcall_private__(cls, domain, codomain = None, action = "left", category = None): + def __classcall_private__(cls, domain, codomain=None, action="left", category=None): """ TESTS:: @@ -266,7 +266,7 @@ def _repr_(self): sage: FiniteSetMaps(2,3) Maps from {0, 1} to {0, 1, 2} """ - return "Maps from %s to %s"%(self.domain(), self.codomain()) + return "Maps from %s to %s" % (self.domain(), self.codomain()) def __contains__(self, x): """ @@ -305,7 +305,7 @@ def an_element(self): An exception :class:`~sage.categories.sets_cat.EmptySetError` is raised if this set is empty, that is if the codomain is - empty and the domain is not. + empty and the domain is not. :: sage: M = FiniteSetMaps(4, 0) sage: M.cardinality() @@ -317,7 +317,7 @@ def an_element(self): """ if self._m > 0 and self._n == 0: raise EmptySetError - return self._from_list_([0]*self._m) + return self._from_list_([0] * self._m) def __iter__(self): """ @@ -411,8 +411,9 @@ def __init__(self, domain, codomain, category=None): Category of finite enumerated sets sage: TestSuite(M).run() """ - FiniteSetMaps_MN.__init__(self, domain.cardinality(), codomain.cardinality(), - category=category) + FiniteSetMaps_MN.__init__(self, domain.cardinality(), + codomain.cardinality(), + category=category) self._domain = domain self._codomain = codomain @@ -530,7 +531,7 @@ def an_element(self): sage: M.an_element() [3, 2, 1, 0] """ - return self._from_list_(range(self._n-1, -1, -1)) + return self._from_list_(range(self._n - 1, -1, -1)) def _repr_(self): """ @@ -539,10 +540,11 @@ def _repr_(self): sage: FiniteSetMaps(2) Maps from {0, 1} to itself """ - return "Maps from %s to itself"%(self.domain()) + return "Maps from %s to itself" % (self.domain()) Element = FiniteSetEndoMap_N + class FiniteSetEndoMaps_Set(FiniteSetMaps_Set, FiniteSetEndoMaps_N): """ The sets of all maps from a set to itself @@ -570,8 +572,9 @@ def __init__(self, domain, action, category=None): sage: TestSuite(M).run() """ category = (EnumeratedSets() & Monoids().Finite()).or_subcategory(category) - FiniteSetMaps_MN.__init__(self, domain.cardinality(), domain.cardinality(), - category=category) + FiniteSetMaps_MN.__init__(self, domain.cardinality(), + domain.cardinality(), + category=category) self._domain = domain self._codomain = domain diff --git a/src/sage/sets/integer_range.py b/src/sage/sets/integer_range.py index fe61d24d623..1eeb9681527 100644 --- a/src/sage/sets/integer_range.py +++ b/src/sage/sets/integer_range.py @@ -251,7 +251,7 @@ def __classcall_private__(cls, begin, end=None, step=Integer(1), middle_point=No if middle_point is not None: return IntegerRangeFromMiddle(begin, end, step, middle_point) - if (begin == -Infinity) or (begin == Infinity): + if begin == -Infinity or begin == Infinity: raise ValueError("Can't iterate over this set: It is impossible to begin an enumeration with plus/minus Infinity") # Check for empty sets @@ -261,7 +261,7 @@ def __classcall_private__(cls, begin, end=None, step=Integer(1), middle_point=No if end != Infinity and end != -Infinity: # Normalize the input sgn = 1 if step > 0 else -1 - end = begin+((end-begin-sgn)//(step)+1)*step + end = begin + ((end - begin - sgn) // (step) + 1) * step return IntegerRangeFinite(begin, end, step) else: return IntegerRangeInfinite(begin, step) @@ -279,14 +279,15 @@ def _element_constructor_(self, el): ValueError: 0 not in {1, 3, 5, 7, 9} """ if el in self: - if not isinstance(el,Integer): + if not isinstance(el, Integer): return Integer(el) return el else: - raise ValueError("%s not in %s"%(el, self)) + raise ValueError("%s not in %s" % (el, self)) element_class = Integer + class IntegerRangeEmpty(IntegerRange, FiniteEnumeratedSet): r""" A singleton class for empty integer ranges @@ -313,6 +314,7 @@ def __classcall__(cls, *args): """ return FiniteEnumeratedSet.__classcall__(cls, ()) + class IntegerRangeFinite(IntegerRange): r""" The class of finite enumerated sets of integers defined by finite @@ -332,7 +334,7 @@ def __init__(self, begin, end, step=Integer(1)): self._begin = begin self._end = end self._step = step - Parent.__init__(self, facade = IntegerRing(), category = FiniteEnumeratedSets()) + Parent.__init__(self, facade=IntegerRing(), category=FiniteEnumeratedSets()) def __contains__(self, elt): r""" @@ -403,13 +405,12 @@ def _repr_(self): """ if self.cardinality() < 6: return "{" + ", ".join(str(x) for x in self) + "}" - elif self._step == 1: - return "{%s, ..., %s}"%(self._begin, self._end-self._step) - else: - return "{%s, %s, ..., %s}"%(self._begin, self._begin+self._step, - self._end-self._step) + if self._step == 1: + return "{%s, ..., %s}" % (self._begin, self._end - self._step) + return "{%s, %s, ..., %s}" % (self._begin, self._begin + self._step, + self._end - self._step) - def rank(self,x): + def rank(self, x): r""" EXAMPLES:: @@ -428,7 +429,7 @@ def rank(self,x): IndexError: 87 not in self """ if x not in self: - raise IndexError("%s not in self"%x) + raise IndexError("%s not in self" % x) return Integer((x - self._begin)/self._step) def __getitem__(self, i): @@ -459,12 +460,12 @@ def __getitem__(self, i): sage: [I[i] for i in range(-1,-I.cardinality()-1,-1)] == l True """ - if isinstance(i,slice): + if isinstance(i, slice): raise NotImplementedError("not yet") if isinstance(i, int): i = Integer(i) - elif not isinstance(i,Integer): + elif not isinstance(i, Integer): raise ValueError("argument should be an integer") if i < 0: @@ -523,6 +524,7 @@ def _an_element_(self): else: return self._begin + class IntegerRangeInfinite(IntegerRange): r""" The class of infinite enumerated sets of integers defined by infinite arithmetic progressions. @@ -542,7 +544,7 @@ def __init__(self, begin, step=Integer(1)): raise TypeError("begin should be Integer, not %r" % type(begin)) self._begin = begin self._step = step - Parent.__init__(self, facade = IntegerRing(), category = InfiniteEnumeratedSets()) + Parent.__init__(self, facade=IntegerRing(), category=InfiniteEnumeratedSets()) def _repr_(self): r""" @@ -558,7 +560,7 @@ def _repr_(self): sage: IntegerRange(-112,-Infinity,-13) #indirect doctest {-112, -125, ...} """ - return "{%s, %s, ...}"%(self._begin, self._begin+self._step) + return "{%s, %s, ...}" % (self._begin, self._begin+self._step) def __contains__(self, elt): r""" @@ -601,7 +603,7 @@ def rank(self, x): IndexError: 22 not in self """ if x not in self: - raise IndexError("%s not in self"%x) + raise IndexError("%s not in self" % x) return Integer((x - self._begin)/self._step) def __getitem__(self, i): @@ -614,12 +616,12 @@ def __getitem__(self, i): sage: I.unrank(1) -5 """ - if isinstance(i,slice): + if isinstance(i, slice): raise NotImplementedError("not yet") if isinstance(i, int): i = Integer(i) - elif not isinstance(i,Integer): + elif not isinstance(i, Integer): raise ValueError if i < 0: @@ -666,6 +668,7 @@ def _an_element_(self): """ return self._begin + 31*self._step + class IntegerRangeFromMiddle(IntegerRange): r""" The class of finite or infinite enumerated sets defined with @@ -699,11 +702,13 @@ def __init__(self, begin, end, step=Integer(1), middle_point=Integer(1)): if middle_point not in self: raise ValueError("middle_point is not in the interval") - if (begin != Infinity and begin != -Infinity) and \ - (end != Infinity and end != -Infinity): - Parent.__init__(self, facade = IntegerRing(), category = FiniteEnumeratedSets()) + if (begin != Infinity and begin != -Infinity and + end != Infinity and end != -Infinity): + cat = FiniteEnumeratedSets() else: - Parent.__init__(self, facade = IntegerRing(), category = InfiniteEnumeratedSets()) + cat = InfiniteEnumeratedSets() + + Parent.__init__(self, facade=IntegerRing(), category=cat) def _repr_(self): r""" @@ -715,7 +720,8 @@ def _repr_(self): sage: IntegerRangeFromMiddle(-100,100,10,0) #indirect doctest Integer progression containing 0 with increment 10 and bounded with -100 and 100 """ - return "Integer progression containing %s with increment %s and bounded with %s and %s"%(self._middle_point,self._step,self._begin,self._end) + return "Integer progression containing %s with increment %s and bounded with %s and %s" % ( + self._middle_point, self._step, self._begin, self._end) def __contains__(self, elt): r""" diff --git a/src/sage/sets/non_negative_integers.py b/src/sage/sets/non_negative_integers.py index 9b5def119e0..c7b3fd27a2d 100644 --- a/src/sage/sets/non_negative_integers.py +++ b/src/sage/sets/non_negative_integers.py @@ -1,18 +1,19 @@ """ Non Negative Integers """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Florent Hivert <Florent.Hivert@univ-rouen.fr> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.parent import Parent from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.structure.unique_representation import UniqueRepresentation from sage.rings.integer import Integer + class NonNegativeIntegers(UniqueRepresentation, Parent): r""" The enumerated set of non negative integers. @@ -80,7 +81,8 @@ def __init__(self, category=None): sage: TestSuite(NN).run() """ from sage.rings.integer_ring import ZZ - Parent.__init__(self, facade = ZZ, category = InfiniteEnumeratedSets().or_subcategory(category) ) + Parent.__init__(self, facade=ZZ, + category=InfiniteEnumeratedSets().or_subcategory(category)) def _repr_(self): """ @@ -115,7 +117,7 @@ def __contains__(self, elt): """ try: i = Integer(elt) - return i >= Integer(0) and i == elt + return i >= Integer(0) and i == elt except (TypeError, ValueError): return False @@ -161,8 +163,7 @@ def _element_constructor_(self, i): """ if i in self: return self.from_integer(i) - else: - raise ValueError("Value %s in not in %s."%(i, self)) + raise ValueError("Value %s in not in %s." % (i, self)) from_integer = Integer @@ -182,8 +183,8 @@ def __iter__(self): yield self.from_integer(i) i += 1 # Uncomment the following two lines to catch infinite loops when debugging - #if i > 200: - # raise ValueError, "Infinite loop during DEBUG! TODO: remove me" + # if i > 200: + # raise ValueError("Infinite loop during DEBUG! TODO:remove me") def an_element(self): """ @@ -211,7 +212,7 @@ def next(self, o): sage: NN.next(3) 4 """ - return self.from_integer(o+1) + return self.from_integer(o + 1) def unrank(self, rnk): """ diff --git a/src/sage/sets/positive_integers.py b/src/sage/sets/positive_integers.py index 7ed7d9657e9..aae3c5a031f 100644 --- a/src/sage/sets/positive_integers.py +++ b/src/sage/sets/positive_integers.py @@ -1,16 +1,17 @@ """ Positive Integers """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Nicolas Borie <nicolas.borie@math.u-psud.fr> # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.sets.integer_range import IntegerRangeInfinite from sage.rings.integer import Integer + class PositiveIntegers(IntegerRangeInfinite): r""" The enumerated set of positive integers. To fix the ideas, diff --git a/src/sage/sets/primes.py b/src/sage/sets/primes.py index 96558ba9215..df64c2efbbf 100644 --- a/src/sage/sets/primes.py +++ b/src/sage/sets/primes.py @@ -184,4 +184,4 @@ def unrank(self, n): sage: P.unrank(42) 191 """ - return nth_prime(n+1) + return nth_prime(n + 1) diff --git a/src/sage/sets/recursively_enumerated_set.pyx b/src/sage/sets/recursively_enumerated_set.pyx index 2ee74cbae1c..a8b21530946 100644 --- a/src/sage/sets/recursively_enumerated_set.pyx +++ b/src/sage/sets/recursively_enumerated_set.pyx @@ -827,8 +827,7 @@ cdef class RecursivelyEnumeratedSet_generic(Parent): current_level = self._seeds known = set(current_level) if max_depth >= 0: - for x in current_level: - yield x + yield from current_level depth = 0 while current_level and depth < max_depth: next_level = [] @@ -1078,8 +1077,7 @@ cdef class RecursivelyEnumeratedSet_symmetric(RecursivelyEnumeratedSet_generic): B = self._seeds set_B = set(B) if max_depth >= 0: - for x in B: - yield x + yield from B depth = 0 while B and depth < max_depth: C = list() @@ -1329,8 +1327,7 @@ cdef class RecursivelyEnumeratedSet_graded(RecursivelyEnumeratedSet_generic): max_depth = self._max_depth current_level = self._seeds if max_depth >= 0: - for x in current_level: - yield x + yield from current_level depth = 0 while current_level and depth < max_depth: next_level = list() @@ -1936,12 +1933,10 @@ class RecursivelyEnumeratedSet_forest(Parent): [] """ if depth == 0: - for node in self.roots(): - yield node + yield from self.roots() else: for father in self._elements_of_depth_iterator_rec(depth - 1): - for node in self.children(father): - yield node + yield from self.children(father) def elements_of_depth_iterator(self, depth=0): r""" @@ -2093,13 +2088,20 @@ class RecursivelyEnumeratedSet_forest(Parent): sage: F = RecursivelyEnumeratedSet(seeds, succ, ....: structure='forest', enumeration='depth') + sage: # needs sage.symbolic sage: y = var('y') sage: def map_function(t): ....: li, sum, _ = t ....: return y ^ sum - sage: reduce_function = lambda x,y: x + y + sage: def reduce_function(x, y): + ....: return x + y sage: F.map_reduce(map_function, reduce_function, 0) - y^45 + y^44 + y^43 + 2*y^42 + 2*y^41 + 3*y^40 + 4*y^39 + 5*y^38 + 6*y^37 + 8*y^36 + 9*y^35 + 10*y^34 + 12*y^33 + 13*y^32 + 15*y^31 + 17*y^30 + 18*y^29 + 19*y^28 + 21*y^27 + 21*y^26 + 22*y^25 + 23*y^24 + 23*y^23 + 23*y^22 + 23*y^21 + 22*y^20 + 21*y^19 + 21*y^18 + 19*y^17 + 18*y^16 + 17*y^15 + 15*y^14 + 13*y^13 + 12*y^12 + 10*y^11 + 9*y^10 + 8*y^9 + 6*y^8 + 5*y^7 + 4*y^6 + 3*y^5 + 2*y^4 + 2*y^3 + y^2 + y + y^45 + y^44 + y^43 + 2*y^42 + 2*y^41 + 3*y^40 + 4*y^39 + 5*y^38 + 6*y^37 + + 8*y^36 + 9*y^35 + 10*y^34 + 12*y^33 + 13*y^32 + 15*y^31 + 17*y^30 + + 18*y^29 + 19*y^28 + 21*y^27 + 21*y^26 + 22*y^25 + 23*y^24 + 23*y^23 + + 23*y^22 + 23*y^21 + 22*y^20 + 21*y^19 + 21*y^18 + 19*y^17 + 18*y^16 + + 17*y^15 + 15*y^14 + 13*y^13 + 12*y^12 + 10*y^11 + 9*y^10 + 8*y^9 + 6*y^8 + + 5*y^7 + 4*y^6 + 3*y^5 + 2*y^4 + 2*y^3 + y^2 + y Here is an example with the default values:: diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index b988525a880..a1789c61300 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -616,7 +616,7 @@ def __contains__(self, x): False Finite fields better illustrate the difference between - ``__contains__`` for objects and their underlying sets. + ``__contains__`` for objects and their underlying sets:: sage: X = Set(GF(7)) sage: X @@ -1061,10 +1061,20 @@ def __richcmp__(self, other, op): False sage: Set([1]) == set([1]) True + + Test set equality and inequality:: + + sage: L = {0} + sage: S = Set(L) + sage: S == L + True + sage: S != L + False """ if not isinstance(other, Set_object_enumerated): if isinstance(other, (set, frozenset)): - return self.set() == other + if self.set() == other: + return rich_to_bool(op, 0) return NotImplemented if self.set() == other.set(): return rich_to_bool(op, 0) diff --git a/src/sage/sets/set_from_iterator.py b/src/sage/sets/set_from_iterator.py index 74015c4433d..4c92deb5d52 100644 --- a/src/sage/sets/set_from_iterator.py +++ b/src/sage/sets/set_from_iterator.py @@ -46,7 +46,7 @@ sage: f(100) {0, 1, 2, 3, 4, ...} """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Vincent Delecroix <vincent.delecroix@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) @@ -58,8 +58,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.structure.parent import Parent from sage.categories.enumerated_sets import EnumeratedSets @@ -158,10 +158,9 @@ def __init__(self, f, args=None, kwds=None, name=None, category=None, cache=Fals sage: TestSuite(S).run() """ if category is not None: - Parent.__init__(self, facade = True, category = category) + Parent.__init__(self, facade=True, category=category) else: - Parent.__init__(self, facade = True, category = EnumeratedSets()) - + Parent.__init__(self, facade=True, category=EnumeratedSets()) if name is not None: self.rename(name) @@ -175,8 +174,8 @@ def __init__(self, f, args=None, kwds=None, name=None, category=None, cache=Fals if cache: self._cache = lazy_list(iter(self._func( - *getattr(self, '_args', ()), - **getattr(self, '_kwds', {})))) + *getattr(self, '_args', ()), + **getattr(self, '_kwds', {})))) def __hash__(self): r""" @@ -215,12 +214,12 @@ def __reduce__(self): True """ return (EnumeratedSetFromIterator, - (self._func, # func - getattr(self, '_args', None), # args - getattr(self, '_kwds', None), # kwds - getattr(self, '__custom_name', None), # name - self.category(), # category - hasattr(self, '_cache')) # cache + (self._func, # func + getattr(self, '_args', None), # args + getattr(self, '_kwds', None), # kwds + self.get_custom_name(), # name + self.category(), # category + hasattr(self, '_cache')) # cache ) def _repr_(self): @@ -271,7 +270,7 @@ def __contains__(self, x): is_parent_of = __contains__ - #TODO: what should we do for comparisons of infinite sets + # TODO: what should we do for comparisons of infinite sets def __eq__(self, other): r""" Equality test. @@ -300,12 +299,12 @@ def __eq__(self, other): # trick to allow equality between infinite sets # this assume that the function does not return randomized data! if (self._func == other._func and - getattr(self, '_args', None) == getattr(other, '_args', None) and - getattr(self, '_kwds', None) == getattr(other, '_kwds', None)): + getattr(self, '_args', None) == getattr(other, '_args', None) and + getattr(self, '_kwds', None) == getattr(other, '_kwds', None)): return True if other in EnumeratedSets(): - #TODO: think about what should be done at that point + # TODO: think about what should be done at that point if self not in FiniteEnumeratedSets() and other not in FiniteEnumeratedSets(): import warnings warnings.warn("Testing equality of infinite sets which will not end in case of equality") @@ -328,7 +327,7 @@ def __eq__(self, other): if x != y: return False - def __ne__(self,other): + def __ne__(self, other): r""" Difference test. @@ -410,8 +409,7 @@ def _element_constructor_(self, el): """ if el in self: return el - else: - raise ValueError("%s not in %s"%(el, self)) + raise ValueError("%s not in %s" % (el, self)) def clear_cache(self): r""" @@ -433,14 +431,15 @@ def clear_cache(self): """ if hasattr(self, '_cache'): self._cache = lazy_list(iter(self._func( - *getattr(self, '_args', ()), - **getattr(self, '_kwds', {})))) + *getattr(self, '_args', ()), + **getattr(self, '_kwds', {})))) # # Decorators # -#TODO: move it in sage.misc ? + +# TODO: move it in sage.misc ? @instancedoc class Decorator(): r""" @@ -461,7 +460,7 @@ def _instancedoc_(self): sage: print(sage_getdoc(d)) # indirect doctest Test whether "self" is prime. ... - Calls the PARI "isprime" function. + Calls the PARI ...isprime... """ # Duplicates sage.misc.cachefunc.CachedFunction._instancedoc_ from sage.misc.sageinspect import sage_getsourcelines, sage_getfile_relative, _extract_embedded_position @@ -510,7 +509,7 @@ def _sage_src_lines_(self): sage: S[0][2] ' Return the number of elements of this group.\n' sage: S[0][25] - ' return Integer(1)\n' + ' if not gens:\n' """ from sage.misc.sageinspect import sage_getsourcelines return sage_getsourcelines(self.f) @@ -680,11 +679,11 @@ def __call__(self, *args, **kwds): sage: F(10).cardinality() 10 """ - if hasattr(self, 'f'): # yet initialized - if hasattr(self,'name'): + if hasattr(self, 'f'): # yet initialized + if hasattr(self, 'name'): if isinstance(self.name, str): if args or kwds: - _, kk = self.af.fix_to_named(*args,**kwds) + _, kk = self.af.fix_to_named(*args, **kwds) name = self.name % dict(kk) else: name = self.name @@ -693,7 +692,7 @@ def __call__(self, *args, **kwds): return EnumeratedSetFromIterator(self.f, args, kwds, name=name, **self.options) return EnumeratedSetFromIterator(self.f, args, kwds, **self.options) - else: # potential global options + else: # potential global options if args == (): f, = kwds.values() else: @@ -701,9 +700,10 @@ def __call__(self, *args, **kwds): f = args[0] return EnumeratedSetFromIterator_function_decorator( f, - name=getattr(self,'name',None), + name=getattr(self, 'name', None), **self.options) + set_from_function = EnumeratedSetFromIterator_function_decorator @@ -760,9 +760,9 @@ def __init__(self, inst, f, name=None, **options): self.name = name self.options = options - def __call__(self,*args,**kwds): + def __call__(self, *args, **kwds): r""" - Returns an instance of :class:`EnumeratedSetFromIterator` with + Return an instance of :class:`EnumeratedSetFromIterator` with proper argument. TESTS:: @@ -785,9 +785,9 @@ def __call__(self,*args,**kwds): if self.inst is not None: args = (self.inst,) + args if self.name: - if isinstance(self.name,str): - aa,kk = self.af.fix_to_named(*args,**kwds) - name = self.name%dict(kk) + if isinstance(self.name, str): + aa, kk = self.af.fix_to_named(*args, **kwds) + name = self.name % dict(kk) else: name = self.name(*args, **kwds) return EnumeratedSetFromIterator(self.f, args, kwds, name, **self.options) @@ -827,9 +827,10 @@ def __get__(self, inst, cls): {2, 3, 4, 5, 6, ...} """ return EnumeratedSetFromIterator_method_caller( - inst, self.f, - self.name, - **self.options) + inst, self.f, + self.name, + **self.options) + class EnumeratedSetFromIterator_method_decorator(): r""" @@ -922,7 +923,7 @@ def __init__(self, f=None, **options): """ if f is not None: self.f = f - if hasattr(f,"__name__"): + if hasattr(f, "__name__"): self.__name__ = f.__name__ self.__module__ = f.__module__ else: @@ -946,15 +947,15 @@ def __call__(self, f): TESTS:: sage: from sage.sets.set_from_iterator import set_from_method - sage: class A: - ....: @set_from_method() # indirect doctest + sage: class A: # indirect doctest + ....: @set_from_method() ....: def f(self): ....: return xsrange(3) sage: a = A() sage: a.f() {0, 1, 2} """ - return EnumeratedSetFromIterator_method_decorator(f,**self.options) + return EnumeratedSetFromIterator_method_decorator(f, **self.options) def __get__(self, inst, cls): r""" @@ -974,8 +975,10 @@ def __get__(self, inst, cls): # You would hardly ever see an instance of this class alive. return EnumeratedSetFromIterator_method_caller(inst, self.f, **self.options) + set_from_method = EnumeratedSetFromIterator_method_decorator + class DummyExampleForPicklingTest: r""" Class example to test pickling with the decorator :class:`set_from_method`. @@ -991,7 +994,8 @@ class DummyExampleForPicklingTest: {10, 11, 12, 13, 14, ...} """ start = 10 - stop = 100 + stop = 100 + @set_from_method def f(self): r""" diff --git a/src/sage/sets/totally_ordered_finite_set.py b/src/sage/sets/totally_ordered_finite_set.py index 8a6966a845a..fde8984b501 100644 --- a/src/sage/sets/totally_ordered_finite_set.py +++ b/src/sage/sets/totally_ordered_finite_set.py @@ -5,7 +5,7 @@ - Stepan Starosta (2012): Initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Stepan Starosta <stepan.starosta@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) @@ -17,8 +17,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.structure.element import Element from sage.structure.parent import Parent @@ -241,7 +241,7 @@ def __classcall__(cls, iterable, facade=True): sage: S1 = TotallyOrderedFiniteSet([1, 2, 3]) sage: S2 = TotallyOrderedFiniteSet((1, 2, 3)) - sage: S3 = TotallyOrderedFiniteSet((x for x in range(1,4))) + sage: S3 = TotallyOrderedFiniteSet(range(1,4)) sage: S1 is S2 True sage: S2 is S3 @@ -254,9 +254,9 @@ def __classcall__(cls, iterable, facade=True): elements.append(x) seen.add(x) return super(FiniteEnumeratedSet, cls).__classcall__( - cls, - tuple(elements), - facade) + cls, + tuple(elements), + facade) def __init__(self, elements, facade=True): """ @@ -269,13 +269,13 @@ def __init__(self, elements, facade=True): sage: TestSuite(TotallyOrderedFiniteSet([1,3,2],facade=False)).run() sage: TestSuite(TotallyOrderedFiniteSet([])).run() """ - Parent.__init__(self, facade = facade, category = (Posets(),FiniteEnumeratedSets())) + Parent.__init__(self, facade=facade, category=(Posets(), FiniteEnumeratedSets())) self._elements = elements if facade: self._facade_elements = None else: self._facade_elements = self._elements - self._elements = [self.element_class(self,x) for x in elements] + self._elements = [self.element_class(self, x) for x in elements] def _element_constructor_(self, data): r""" @@ -306,7 +306,7 @@ def _element_constructor_(self, data): try: i = self._facade_elements.index(data) except ValueError: - raise ValueError("%s not in %s"%(data, self)) + raise ValueError("%s not in %s" % (data, self)) return self._elements[i] diff --git a/src/sage/stats/__init__.py b/src/sage/stats/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/stats/basic_stats.py b/src/sage/stats/basic_stats.py index d83f08111f0..15e85197f3e 100644 --- a/src/sage/stats/basic_stats.py +++ b/src/sage/stats/basic_stats.py @@ -6,22 +6,22 @@ When calling a function on data, there are checks for functions already defined for that data type. -The ``mean`` function returns the arithmetic mean (the sum of all the members +The :func:`mean` function returns the arithmetic mean (the sum of all the members of a list, divided by the number of members). Further revisions may include -the geometric and harmonic mean. The ``median`` function returns the number -separating the higher half of a sample from the lower half. The ``mode`` +the geometric and harmonic mean. The :func:`median` function returns the number +separating the higher half of a sample from the lower half. The :func:`mode` returns the most common occurring member of a sample, plus the number of times it occurs. If entries occur equally common, the smallest of a list of the most -common entries is returned. The ``moving_average`` is a finite impulse +common entries is returned. The :func:`moving_average` is a finite impulse response filter, creating a series of averages using a user-defined number of -subsets of the full data set. The ``std`` and the ``variance`` return a +subsets of the full data set. The :func:`std` and the :func:`variance` return a measurement of how far data points tend to be from the arithmetic mean. -Functions are available in the namespace ``stats``, i.e. you can use them by +Functions are available in the namespace :mod:`stats`, i.e. you can use them by typing ``stats.mean``, ``stats.median``, etc. REMARK: If all the data you are working with are floating point -numbers, you may find ``stats.TimeSeries`` helpful, since it is +numbers, you may find :class:`stats.TimeSeries` helpful, since it is extremely fast and offers many of the same descriptive statistics as in the module. @@ -40,10 +40,14 @@ ###################################################################### from sage.rings.integer_ring import ZZ -from sage.symbolic.constants import NaN +from sage.misc.lazy_import import lazy_import from sage.misc.functional import sqrt from sage.misc.superseded import deprecation +lazy_import("sage.symbolic.constants", "NaN") +lazy_import("numpy", "ndarray", as_="numpy_ndarray") +lazy_import("sage.stats.time_series", "TimeSeries") + def mean(v): """ @@ -52,12 +56,12 @@ def mean(v): We define the mean of the empty list to be the (symbolic) NaN, following the convention of MATLAB, Scipy, and R. - This function is deprecated. Use ``numpy.mean`` or ``numpy.nanmean`` + This function is deprecated. Use :func:`numpy.mean` or :func:`numpy.nanmean` instead. INPUT: - - `v` -- a list of numbers + - ``v`` -- a list of numbers OUTPUT: @@ -65,21 +69,22 @@ def mean(v): EXAMPLES:: - sage: mean([pi, e]) + sage: mean([pi, e]) # needs sage.symbolic doctest:warning... - DeprecationWarning: sage.stats.basic_stats.mean is deprecated; use numpy.mean or numpy.nanmean instead + DeprecationWarning: sage.stats.basic_stats.mean is deprecated; + use numpy.mean or numpy.nanmean instead See https://github.com/sagemath/sage/issues/29662 for details. 1/2*pi + 1/2*e - sage: mean([]) + sage: mean([]) # needs sage.symbolic NaN - sage: mean([I, sqrt(2), 3/5]) + sage: mean([I, sqrt(2), 3/5]) # needs sage.symbolic 1/3*sqrt(2) + 1/3*I + 1/5 - sage: mean([RIF(1.0103,1.0103), RIF(2)]) + sage: mean([RIF(1.0103,1.0103), RIF(2)]) # needs sage.rings.real_interval_field 1.5051500000000000? sage: mean(range(4)) 3/2 - sage: v = stats.TimeSeries([1..100]) - sage: mean(v) + sage: v = stats.TimeSeries([1..100]) # needs numpy + sage: mean(v) # needs numpy 50.5 """ deprecation(29662, 'sage.stats.basic_stats.mean is deprecated; use numpy.mean or numpy.nanmean instead') @@ -103,8 +108,8 @@ def mode(v): in `v`, then the mode is the list of elements of `v` that occur `n` times. The list is sorted if possible. - This function is deprecated. Use ``scipy.stats.mode`` or - ``statistics.mode`` instead. + This function is deprecated. Use :func:`scipy.stats.mode` or + :func:`statistics.mode` instead. .. NOTE:: @@ -112,7 +117,7 @@ def mode(v): INPUT: - - `v` -- a list + - ``v`` -- a list OUTPUT: @@ -123,7 +128,8 @@ def mode(v): sage: v = [1,2,4,1,6,2,6,7,1] sage: mode(v) doctest:warning... - DeprecationWarning: sage.stats.basic_stats.mode is deprecated; use scipy.stats.mode or statistics.mode instead + DeprecationWarning: sage.stats.basic_stats.mode is deprecated; + use scipy.stats.mode or statistics.mode instead See https://github.com/sagemath/sage/issues/29662 for details. [1] sage: v.count(1) @@ -176,17 +182,16 @@ def std(v, bias=False): We define the standard deviation of the empty list to be NaN, following the convention of MATLAB, Scipy, and R. - This function is deprecated. Use ``numpy.std`` or ``numpy.nanstd`` + This function is deprecated. Use :func:`numpy.std` or :func:`numpy.nanstd` instead. INPUT: - - `v` -- a list of numbers + - ``v`` -- a list of numbers - - ``bias`` -- bool (default: False); if False, divide by - len(v) - 1 instead of len(v) - to give a less biased estimator (sample) for the - standard deviation. + - ``bias`` -- bool (default: ``False``); if ``False``, divide by + ``len(v) - 1`` instead of ``len(v)`` to give a less biased + estimator (sample) for the standard deviation. OUTPUT: @@ -194,15 +199,19 @@ def std(v, bias=False): EXAMPLES:: + sage: # needs sage.symbolic sage: std([1..6], bias=True) doctest:warning... - DeprecationWarning: sage.stats.basic_stats.std is deprecated; use numpy.std or numpy.nanstd instead + DeprecationWarning: sage.stats.basic_stats.std is deprecated; + use numpy.std or numpy.nanstd instead See https://github.com/sagemath/sage/issues/29662 for details. doctest:warning... - DeprecationWarning: sage.stats.basic_stats.variance is deprecated; use numpy.var or numpy.nanvar instead + DeprecationWarning: sage.stats.basic_stats.variance is deprecated; + use numpy.var or numpy.nanvar instead See https://github.com/sagemath/sage/issues/29662 for details. doctest:warning... - DeprecationWarning: sage.stats.basic_stats.mean is deprecated; use numpy.mean or numpy.nanmean instead + DeprecationWarning: sage.stats.basic_stats.mean is deprecated; + use numpy.mean or numpy.nanmean instead See https://github.com/sagemath/sage/issues/29662 for details. 1/2*sqrt(35/3) sage: std([1..6], bias=False) @@ -216,6 +225,8 @@ def std(v, bias=False): + (5*sqrt(2) - 10*I + 3)^2 + (5*sqrt(2) + 5*I - 6)^2) sage: std([RIF(1.0103, 1.0103), RIF(2)]) 0.6998235813403261? + + sage: # needs numpy sage: import numpy sage: x = numpy.array([1,2,3,4,5]) sage: std(x, bias=False) @@ -238,9 +249,7 @@ def std(v, bias=False): if hasattr(v, 'standard_deviation'): return v.standard_deviation(bias=bias) - import numpy - - if isinstance(v, numpy.ndarray): + if isinstance(v, numpy_ndarray): # accounts for numpy arrays if bias: return v.std() @@ -261,17 +270,16 @@ def variance(v, bias=False): We define the variance of the empty list to be NaN, following the convention of MATLAB, Scipy, and R. - This function is deprecated. Use ``numpy.var`` or ``numpy.nanvar`` + This function is deprecated. Use :func:`numpy.var` or :func:`numpy.nanvar` instead. INPUT: - - `v` -- a list of numbers + - ``v`` -- a list of numbers - - ``bias`` -- bool (default: False); if False, divide by - len(v) - 1 instead of len(v) - to give a less biased estimator (sample) for the - standard deviation. + - ``bias`` -- bool (default: ``False``); if ``False``, divide by + ``len(v) - 1`` instead of ``len(v)`` to give a less biased + estimator (sample) for the standard deviation. OUTPUT: @@ -281,23 +289,24 @@ def variance(v, bias=False): sage: variance([1..6]) doctest:warning... - DeprecationWarning: sage.stats.basic_stats.variance is deprecated; use numpy.var or numpy.nanvar instead + DeprecationWarning: sage.stats.basic_stats.variance is deprecated; + use numpy.var or numpy.nanvar instead See https://github.com/sagemath/sage/issues/29662 for details. 7/2 sage: variance([1..6], bias=True) 35/12 - sage: variance([e, pi]) + sage: variance([e, pi]) # needs sage.symbolic 1/2*(pi - e)^2 sage: variance([]) NaN - sage: variance([I, sqrt(2), 3/5]) + sage: variance([I, sqrt(2), 3/5]) # needs sage.symbolic 1/450*(10*sqrt(2) - 5*I - 3)^2 + 1/450*(5*sqrt(2) - 10*I + 3)^2 + 1/450*(5*sqrt(2) + 5*I - 6)^2 sage: variance([RIF(1.0103, 1.0103), RIF(2)]) 0.4897530450000000? - sage: import numpy - sage: x = numpy.array([1,2,3,4,5]) - sage: variance(x, bias=False) + sage: import numpy # needs numpy + sage: x = numpy.array([1,2,3,4,5]) # needs numpy + sage: variance(x, bias=False) # needs numpy 2.5 sage: x = stats.TimeSeries([1..100]) sage: variance(x) @@ -305,7 +314,7 @@ def variance(v, bias=False): sage: variance(x, bias=True) 833.25 sage: class MyClass: - ....: def variance(self, bias = False): + ....: def variance(self, bias=False): ....: return 1 sage: stats.variance(MyClass()) 1 @@ -335,10 +344,9 @@ def variance(v, bias=False): if hasattr(v, 'variance'): return v.variance(bias=bias) - import numpy x = 0 - if isinstance(v, numpy.ndarray): + if isinstance(v, numpy_ndarray): # accounts for numpy arrays if bias: return v.var() @@ -369,15 +377,15 @@ def median(v): If `v` is empty, we define the median to be NaN, which is consistent with NumPy (note that R returns NULL). - If `v` is comprised of strings, TypeError occurs. - For elements other than numbers, the median is a result of ``sorted()``. + If `v` is comprised of strings, :class:`TypeError` occurs. + For elements other than numbers, the median is a result of :func:`sorted`. - This function is deprecated. Use ``numpy.median`` or ``numpy.nanmedian`` + This function is deprecated. Use :func:`numpy.median` or :func:`numpy.nanmedian` instead. INPUT: - - `v` -- a list + - ``v`` -- a list OUTPUT: @@ -387,14 +395,15 @@ def median(v): sage: median([1,2,3,4,5]) doctest:warning... - DeprecationWarning: sage.stats.basic_stats.median is deprecated; use numpy.median or numpy.nanmedian instead + DeprecationWarning: sage.stats.basic_stats.median is deprecated; + use numpy.median or numpy.nanmedian instead See https://github.com/sagemath/sage/issues/29662 for details. 3 - sage: median([e, pi]) + sage: median([e, pi]) # needs sage.symbolic 1/2*pi + 1/2*e sage: median(['sage', 'linux', 'python']) 'python' - sage: median([]) + sage: median([]) # needs sage.symbolic NaN sage: class MyClass: ....: def median(self): @@ -427,13 +436,13 @@ def moving_average(v, n): If `v` is empty, we define the entries of the moving average to be NaN. - This method is deprecated. Use ``pandas.Series.rolling`` instead. + This method is deprecated. Use :meth:`pandas.Series.rolling` instead. INPUT: - - `v` -- a list + - ``v`` -- a list - - `n` -- the number of values used in computing each average. + - ``n`` -- the number of values used in computing each average. OUTPUT: @@ -443,26 +452,27 @@ def moving_average(v, n): sage: moving_average([1..10], 1) doctest:warning... - DeprecationWarning: sage.stats.basic_stats.moving_average is deprecated; use pandas.Series.rolling instead + DeprecationWarning: sage.stats.basic_stats.moving_average is deprecated; + use pandas.Series.rolling instead See https://github.com/sagemath/sage/issues/29662 for details. [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] sage: moving_average([1..10], 4) [5/2, 7/2, 9/2, 11/2, 13/2, 15/2, 17/2] sage: moving_average([], 1) [] - sage: moving_average([pi, e, I, sqrt(2), 3/5], 2) + sage: moving_average([pi, e, I, sqrt(2), 3/5], 2) # needs sage.symbolic [1/2*pi + 1/2*e, 1/2*e + 1/2*I, 1/2*sqrt(2) + 1/2*I, 1/2*sqrt(2) + 3/10] We check if the input is a time series, and if so use the - optimized ``simple_moving_average`` method, but with (slightly + optimized :meth:`simple_moving_average` method, but with (slightly different) meaning as defined above (the point is that the - ``simple_moving_average`` on time series returns `n` values:: + :meth:`simple_moving_average` on time series returns `n` values:: - sage: a = stats.TimeSeries([1..10]) - sage: stats.moving_average(a, 3) + sage: a = stats.TimeSeries([1..10]) # needs numpy + sage: stats.moving_average(a, 3) # needs numpy [2.0000, 3.0000, 4.0000, 5.0000, 6.0000, 7.0000, 8.0000, 9.0000] - sage: stats.moving_average(list(a), 3) + sage: stats.moving_average(list(a), 3) # needs numpy [2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] """ @@ -470,7 +480,6 @@ def moving_average(v, n): if not v: return v - from .time_series import TimeSeries if isinstance(v, TimeSeries): return v.simple_moving_average(n)[n - 1:] n = int(n) diff --git a/src/sage/stats/distributions/__init__.py b/src/sage/stats/distributions/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/geometry/hyperplane_arrangement/__init__.py b/src/sage/stats/distributions/all.py similarity index 100% rename from src/sage/geometry/hyperplane_arrangement/__init__.py rename to src/sage/stats/distributions/all.py diff --git a/src/sage/stats/distributions/discrete_gaussian_integer.pyx b/src/sage/stats/distributions/discrete_gaussian_integer.pyx index 87fbe6ca5cd..2aa28609180 100644 --- a/src/sage/stats/distributions/discrete_gaussian_integer.pyx +++ b/src/sage/stats/distributions/discrete_gaussian_integer.pyx @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.symbolic # # distutils: sources = sage/stats/distributions/dgs_gauss_mp.c sage/stats/distributions/dgs_gauss_dp.c sage/stats/distributions/dgs_bern.c # distutils: depends = sage/stats/distributions/dgs_gauss.h sage/stats/distributions/dgs_bern.h sage/stats/distributions/dgs_misc.h diff --git a/src/sage/stats/distributions/discrete_gaussian_lattice.py b/src/sage/stats/distributions/discrete_gaussian_lattice.py index 695c8fc3615..8e35d45129f 100644 --- a/src/sage/stats/distributions/discrete_gaussian_lattice.py +++ b/src/sage/stats/distributions/discrete_gaussian_lattice.py @@ -58,7 +58,10 @@ from sage.functions.log import exp from sage.functions.other import ceil -from sage.rings.all import RealField, RR, ZZ, QQ +from sage.rings.real_mpfr import RealField +from sage.rings.real_mpfr import RR +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from .discrete_gaussian_integer import DiscreteGaussianDistributionIntegerSampler from sage.structure.sage_object import SageObject from sage.matrix.constructor import matrix, identity_matrix @@ -92,7 +95,7 @@ def _iter_vectors(n, lower, upper, step=None): raise ValueError("Expected n>0 but got %d <= 0" % n) step = n - assert(step > 0) + assert step > 0 if step == 1: for x in range(lower, upper): v = vector(ZZ, n) @@ -136,7 +139,7 @@ class DiscreteGaussianDistributionLatticeSampler(SageObject): sage: D = DiscreteGaussianDistributionLatticeSampler(identity_matrix(2), 3.0) sage: S = [D() for _ in range(2^12)] sage: l = [vector(v.list() + [S.count(v)]) for v in set(S)] - sage: list_plot3d(l, point_list=True, interpolation='nn') + sage: list_plot3d(l, point_list=True, interpolation='nn') # needs sage.plot Graphics3d Object REFERENCES: @@ -194,7 +197,7 @@ def _normalisation_factor_zz(self, tau=3): INPUT: - ``tau`` -- all vectors `v` with `|v|_โˆž โ‰ค ฯ„ยทฯƒ` are enumerated - (default: ``3``). + (default: ``3``). EXAMPLES:: @@ -202,7 +205,7 @@ def _normalisation_factor_zz(self, tau=3): sage: n = 3; sigma = 1.0 sage: D = DiscreteGaussianDistributionLatticeSampler(ZZ^n, sigma) sage: f = D.f - sage: c = D._normalisation_factor_zz(); c + sage: c = D._normalisation_factor_zz(); c # needs sage.symbolic 15.528... sage: from collections import defaultdict @@ -216,15 +219,19 @@ def _normalisation_factor_zz(self, tau=3): sage: v = vector(ZZ, n, (0, 0, 0)) sage: v.set_immutable() - sage: while v not in counter: add_samples(1000) + sage: while v not in counter: + ....: add_samples(1000) - sage: while abs(m*f(v)*1.0/c/counter[v] - 1.0) >= 0.1: add_samples(1000) + sage: while abs(m*f(v)*1.0/c/counter[v] - 1.0) >= 0.1: # needs sage.symbolic + ....: add_samples(1000) sage: v = vector(ZZ, n, (-1, 2, 3)) sage: v.set_immutable() - sage: while v not in counter: add_samples(1000) + sage: while v not in counter: + ....: add_samples(1000) - sage: while abs(m*f(v)*1.0/c/counter[v] - 1.0) >= 0.2: add_samples(1000) # long time + sage: while abs(m*f(v)*1.0/c/counter[v] - 1.0) >= 0.2: # long time, needs sage.symbolic + ....: add_samples(1000) """ if self.B != identity_matrix(ZZ, self.B.nrows()): raise NotImplementedError("This function is only implemented when B is an identity matrix.") @@ -258,7 +265,7 @@ def __init__(self, B, sigma=1, c=None, precision=None): sage: n = 2; sigma = 3.0 sage: D = DiscreteGaussianDistributionLatticeSampler(ZZ^n, sigma) sage: f = D.f - sage: c = D._normalisation_factor_zz(); c + sage: c = D._normalisation_factor_zz(); c # needs sage.symbolic 56.2162803067524 sage: from collections import defaultdict @@ -272,23 +279,27 @@ def __init__(self, B, sigma=1, c=None, precision=None): sage: v = vector(ZZ, n, (-3, -3)) sage: v.set_immutable() - sage: while v not in counter: add_samples(1000) - sage: while abs(m*f(v)*1.0/c/counter[v] - 1.0) >= 0.1: add_samples(1000) + sage: while v not in counter: + ....: add_samples(1000) + sage: while abs(m*f(v)*1.0/c/counter[v] - 1.0) >= 0.1: # needs sage.symbolic + ....: add_samples(1000) sage: v = vector(ZZ, n, (0, 0)) sage: v.set_immutable() - sage: while v not in counter: add_samples(1000) - sage: while abs(m*f(v)*1.0/c/counter[v] - 1.0) >= 0.1: add_samples(1000) + sage: while v not in counter: + ....: add_samples(1000) + sage: while abs(m*f(v)*1.0/c/counter[v] - 1.0) >= 0.1: # needs sage.symbolic + ....: add_samples(1000) sage: from sage.stats.distributions.discrete_gaussian_lattice import DiscreteGaussianDistributionLatticeSampler sage: qf = QuadraticForm(matrix(3, [2, 1, 1, 1, 2, 1, 1, 1, 2])) - sage: D = DiscreteGaussianDistributionLatticeSampler(qf, 3.0); D + sage: D = DiscreteGaussianDistributionLatticeSampler(qf, 3.0); D # needs sage.symbolic Discrete Gaussian sampler with ฯƒ = 3.000000, c=(0, 0, 0) over lattice with basis <BLANKLINE> [2 1 1] [1 2 1] [1 1 2] - sage: D().parent() is D.c.parent() + sage: D().parent() is D.c.parent() # needs sage.symbolic True """ precision = DiscreteGaussianDistributionLatticeSampler.compute_precision(precision, sigma) @@ -467,7 +478,7 @@ def _call(self): b_ = self._G[i] c_ = c.dot_product(b_) / b_.dot_product(b_) sigma_ = sigma / b_.norm() - assert(sigma_ > 0) + assert sigma_ > 0 z = DiscreteGaussianDistributionIntegerSampler(sigma=sigma_, c=c_, algorithm="uniform+online")() c = c - z * B[i] v = v + z * B[i] diff --git a/src/sage/stats/distributions/discrete_gaussian_polynomial.py b/src/sage/stats/distributions/discrete_gaussian_polynomial.py index 698727f48d0..7d61ab7eb0c 100644 --- a/src/sage/stats/distributions/discrete_gaussian_polynomial.py +++ b/src/sage/stats/distributions/discrete_gaussian_polynomial.py @@ -14,11 +14,12 @@ EXAMPLES:: sage: from sage.stats.distributions.discrete_gaussian_polynomial import DiscreteGaussianDistributionPolynomialSampler - sage: sigma = 3.0; n=1000 - sage: l = [DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], 64, sigma)() for _ in range(n)] - sage: l = [vector(f).norm().n() for f in l] - sage: from numpy import mean - sage: mean(l), sqrt(64)*sigma # abs tol 5e-1 + sage: sigma = 3.0; n = 1000 + sage: l = [DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], 64, sigma)() + ....: for _ in range(n)] + sage: l = [vector(f).norm().n() for f in l] # needs sage.symbolic + sage: from numpy import mean # needs numpy + sage: mean(l), sqrt(64)*sigma # abs tol 5e-1 # needs numpy sage.symbolic (24.0, 24.0) """ @@ -54,7 +55,8 @@ # policies, either expressed or implied, of the FreeBSD Project. #*****************************************************************************/ -from sage.rings.all import RR, ZZ +from sage.rings.real_mpfr import RR +from sage.rings.integer_ring import ZZ from .discrete_gaussian_integer import DiscreteGaussianDistributionIntegerSampler from sage.structure.sage_object import SageObject diff --git a/src/sage/stats/hmm/__init__.py b/src/sage/stats/hmm/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/stats/hmm/chmm.pyx b/src/sage/stats/hmm/chmm.pyx index eb2d4ed6856..fe84e176a8a 100644 --- a/src/sage/stats/hmm/chmm.pyx +++ b/src/sage/stats/hmm/chmm.pyx @@ -1,4 +1,5 @@ -""" +# sage.doctest: needs numpy +r""" Continuous Emission Hidden Markov Models AUTHOR: @@ -38,18 +39,18 @@ from sage.misc.randstate cimport current_randstate, randstate # TODO: DELETE THIS FUNCTION WHEN MOVE Gaussian stuff to distributions.pyx!!! (next version) cdef double random_normal(double mean, double std, randstate rstate): - """ + r""" Return a number chosen randomly with given mean and standard deviation. INPUT: - - ``mean`` -- double - - ``std`` -- double, standard deviation - - ``rstate`` -- a randstate object + - ``mean`` -- double + - ``std`` -- double, standard deviation + - ``rstate`` -- a randstate object OUTPUT: - - a double + a double """ # Ported from http://users.tkk.fi/~nbeijar/soft/terrain/source_o2/boxmuller.c # This the box muller algorithm. @@ -67,23 +68,23 @@ cdef double random_normal(double mean, double std, randstate rstate): return mean + y1*std cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): - """ - GaussianHiddenMarkovModel(A, B, pi) - + r""" Gaussian emissions Hidden Markov Model. INPUT: - - ``A`` -- matrix; the N x N transition matrix - - ``B`` -- list of pairs (mu,sigma) that define the distributions - - ``pi`` -- initial state probabilities - - ``normalize`` --bool (default: True) + - ``A`` -- matrix; the `N \times N` transition matrix + - ``B`` -- list of pairs ``(mu, sigma)`` that define the distributions + - ``pi`` -- initial state probabilities + - ``normalize`` -- bool (default: ``True``) EXAMPLES: We illustrate the primary functions with an example 2-state Gaussian HMM:: - sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,1), (-1,1)], [.5,.5]); m + sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], + ....: [(1,1), (-1,1)], + ....: [.5,.5]); m Gaussian Hidden Markov Model with 2 States Transition matrix: [0.1 0.9] @@ -148,40 +149,40 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): [ 0.4154981366185841 0.584501863381416] [ 0.9999993174253741 6.825746258991804e-07] Emission parameters: - [(0.4178882427119503, 0.5173109664360919), (-1.5025208631331122, 0.5085512836055119)] + [(0.4178882427119503, 0.5173109664360919), + (-1.5025208631331122, 0.5085512836055119)] Initial probabilities: [0.0000, 1.0000] """ cdef TimeSeries B, prob cdef int n_out def __init__(self, A, B, pi, bint normalize=True): - """ + r""" Create a Gaussian emissions HMM with transition probability - matrix A, normal emissions given by B, and initial state - probability distribution pi. + matrix `A`, normal emissions given by `B`, and initial state + probability distribution ``pi``. INPUT: - - A -- a list of lists or a square N x N matrix, whose - (i,j) entry gives the probability of transitioning from - state i to state j. + - ``A`` -- a list of lists or a square `N \times N` matrix, whose + `(i,j)` entry gives the probability of transitioning from + state `i` to state `j`. - - B -- a list of N pairs (mu,std), where if B[i]=(mu,std), - then the probability distribution associated with state i - normal with mean mu and standard deviation std. + - ``B`` -- a list of `N` pairs ``(mu, std)``, where if ``B[i]=(mu,std)``, + then the probability distribution associated with state `i` + normal with mean ``mu`` and standard deviation ``std``. - - pi -- the probabilities of starting in each initial - state, i.e,. pi[i] is the probability of starting in - state i. + - ``pi`` -- the probabilities of starting in each initial + state, i.e., ``pi[i]`` is the probability of starting in + state `i`. - - normalize --bool (default: True); if given, input is - normalized to define valid probability distributions, - e.g., the entries of A are made nonnegative and the rows - sum to 1. + - ``normalize`` -- bool (default: ``True``); if given, input is + normalized to define valid probability distributions, + e.g., the entries of `A` are made nonnegative and the rows + sum to 1. EXAMPLES:: - sage: hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,1), (-1,1)], [.5,.5]) Gaussian Hidden Markov Model with 2 States Transition matrix: @@ -191,7 +192,7 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): [(1.0, 1.0), (-1.0, 1.0)] Initial probabilities: [0.5000, 0.5000] - We input a model in which both A and pi have to be + We input a model in which both `A` and ``pi`` have to be renormalized to define valid probability distributions:: sage: hmm.GaussianHiddenMarkovModel([[-1,.7],[.3,.4]], [(1,1), (-1,1)], [-1,.3]) # rel tol 3e-14 @@ -205,7 +206,8 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): Bad things can happen:: - sage: hmm.GaussianHiddenMarkovModel([[-1,.7],[.3,.4]], [(1,1), (-1,1)], [-1,.3], normalize=False) + sage: hmm.GaussianHiddenMarkovModel([[-1,.7],[.3,.4]], [(1,1), (-1,1)], [-1,.3], + ....: normalize=False) Gaussian Hidden Markov Model with 2 States Transition matrix: [-1.0 0.7] @@ -226,8 +228,8 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): self.probability_init() def __richcmp__(self, other, op): - """ - Compare self and other, which must both be GaussianHiddenMarkovModel's. + r""" + Compare ``self`` and ``other``, which must both be GaussianHiddenMarkovModel's. EXAMPLES:: @@ -248,16 +250,14 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): other.__reduce__()[1], op) def __getitem__(self, Py_ssize_t i): - """ - Return the mean and standard distribution for the i-th state. + r""" + Return the mean and standard distribution for the `i`-th state. INPUT: - - i -- integer + - ``i`` -- integer - OUTPUT: - - - 2 floats + OUTPUT: 2 floats EXAMPLES:: @@ -286,7 +286,7 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): return self.B[2*i], self.B[2*i+1] def __reduce__(self): - """ + r""" Used in pickling. EXAMPLES:: @@ -299,19 +299,22 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): (self.A, self.B, self.pi, self.prob, self.n_out) def emission_parameters(self): - """ + r""" Return the parameters that define the normal distributions associated to all of the states. OUTPUT: - - a list B of pairs B[i] = (mu, std), such that the - distribution associated to state i is normal with mean - mu and standard deviation std. + a list ``B`` of pairs ``B[i] = (mu, std)``, such that the + distribution associated to state `i` is normal with mean + ``mu`` and standard deviation ``std``. EXAMPLES:: - sage: hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,.5), (-1,3)], [.1,.9]).emission_parameters() + sage: M = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], + ....: [(1,.5), (-1,3)], + ....: [.1,.9]) + sage: M.emission_parameters() [(1.0, 0.5), (-1.0, 3.0)] """ cdef Py_ssize_t i @@ -335,25 +338,27 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): def generate_sequence(self, Py_ssize_t length, starting_state=None): - """ + r""" Return a sample of the given length from this HMM. INPUT: - - length -- positive integer - - starting_state -- int (or None); if specified then generate - a sequence using this model starting with the given state - instead of the initial probabilities to determine the - starting state. + - ``length`` -- positive integer + - ``starting_state`` -- int (or ``None``); if specified then generate + a sequence using this model starting with the given state + instead of the initial probabilities to determine the + starting state. OUTPUT: - - an IntList or list of emission symbols - - TimeSeries of emissions + - an :class:`IntList` or list of emission symbols + - :class:`TimeSeries` of emissions EXAMPLES:: - sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,.5), (-1,3)], [.1,.9]) + sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], + ....: [(1,.5), (-1,3)], + ....: [.1,.9]) sage: m.generate_sequence(5) # random ([-3.0505, 0.5317, -4.5065, 0.6521, 1.0435], [1, 0, 1, 0, 1]) sage: m.generate_sequence(0) @@ -442,7 +447,7 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): return obs, states cdef probability_init(self): - """ + r""" Used internally to compute caching information that makes certain computations in the Baum-Welch algorithm faster. This function has no input or output. @@ -454,7 +459,7 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): self.prob[2*i+1] = -1.0/(2*self.B[2*i+1]*self.B[2*i+1]) cdef double random_sample(self, int state, randstate rstate): - """ + r""" Return a random sample from the normal distribution associated to the given state. @@ -464,17 +469,17 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): INPUT: - - state -- integer - - rstate -- randstate instance + - ``state`` -- integer + - ``rstate`` -- randstate instance OUTPUT: - - double + double """ return random_normal(self.B._values[state*2], self.B._values[state*2+1], rstate) cdef double probability_of(self, int state, double observation): - """ + r""" Return a useful continuous analogue of "the probability b_j(o)" of seeing the given observation given that we're in the given state j (=state). @@ -490,12 +495,12 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): INPUT: - - state -- integer - - observation -- double + - ``state`` -- integer + - ``observation`` -- double OUTPUT: - - double + double """ # The code below is an optimized version of the following code: # cdef double mean = self.B._values[2*state], \ @@ -518,7 +523,7 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): return self.prob._values[2*state] * exp(x*x*self.prob._values[2*state+1]) def log_likelihood(self, obs): - """ + r""" Return the logarithm of a continuous analogue of the probability that this model produced the given observation sequence. @@ -528,15 +533,17 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): INPUT: - - obs -- sequence of observations + - ``obs`` -- sequence of observations OUTPUT: - - float + float EXAMPLES:: - sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,.5), (-1,3)], [.1,.9]) + sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], + ....: [(1,.5), (-1,3)], + ....: [.1,.9]) sage: m.log_likelihood([1,1,1]) -4.297880766072486 sage: s = m.sample(20) @@ -550,17 +557,17 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): return self._forward_scale(obs) def _forward_scale(self, TimeSeries obs): - """ + r""" Memory-efficient implementation of the forward algorithm (with scaling). INPUT: - - obs -- an integer list of observation states. + - ``obs`` -- an integer list of observation states. OUTPUT: - - float -- the log of the probability that the model - produced this sequence + float -- the log of the probability that the model + produced this sequence EXAMPLES:: @@ -606,36 +613,40 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): return log_probability def viterbi(self, obs): - """ + r""" Determine "the" hidden sequence of states that is most likely - to produce the given sequence seq of observations, along with + to produce the given sequence ``obs`` of observations, along with the probability that this hidden sequence actually produced the observation. INPUT: - - seq -- sequence of emitted ints or symbols + - ``obs`` -- sequence of emitted ints or symbols OUTPUT: - - list -- "the" most probable sequence of hidden states, i.e., - the Viterbi path. + - list -- "the" most probable sequence of hidden states, i.e., + the Viterbi path. - - float -- log of probability that the observed sequence - was produced by the Viterbi sequence of states. + - float -- log of probability that the observed sequence + was produced by the Viterbi sequence of states. EXAMPLES: We find the optimal state sequence for a given model:: - sage: m = hmm.GaussianHiddenMarkovModel([[0.5,0.5],[0.5,0.5]], [(0,1),(10,1)], [0.5,0.5]) + sage: m = hmm.GaussianHiddenMarkovModel([[0.5,0.5],[0.5,0.5]], + ....: [(0,1),(10,1)], + ....: [0.5,0.5]) sage: m.viterbi([0,1,10,10,1]) ([0, 0, 1, 1, 0], -9.0604285688230...) Another example in which the most likely states change based on the last observation:: - sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,.5), (-1,3)], [.1,.9]) + sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], + ....: [(1,.5), (-1,3)], + ....: [.1,.9]) sage: m.viterbi([-2,-1,.1,0.1]) ([1, 1, 0, 1], -9.61823698847639...) sage: m.viterbi([-2,-1,.1,0.3]) @@ -706,7 +717,7 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): return state_sequence, mx cdef TimeSeries _backward_scale_all(self, TimeSeries obs, TimeSeries scale): - """ + r""" This function returns the matrix beta_t(i), and is used internally as part of the Baum-Welch algorithm. @@ -716,13 +727,13 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): INPUT: - - obs -- TimeSeries - - scale -- TimeSeries + - ``obs`` -- TimeSeries + - ``scale`` -- TimeSeries OUTPUT: - - TimeSeries beta such that beta_t(i) = beta[t*N + i] - - scale is also changed by this function + - TimeSeries beta such that beta_t(i) = beta[t*N + i] + - scale is also changed by this function """ cdef Py_ssize_t t, T = obs._length cdef int N = self.N, i, j @@ -746,7 +757,7 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): return beta cdef _forward_scale_all(self, TimeSeries obs): - """ + r""" Return scaled values alpha_t(i), the sequence of scalings, and the log probability. @@ -756,14 +767,14 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): INPUT: - - obs -- TimeSeries + - ``obs`` -- TimeSeries OUTPUT: - - TimeSeries alpha with alpha_t(i) = alpha[t*N + i] - - TimeSeries scale with scale[t] the scaling at step t - - float -- log_probability of the observation sequence - being produced by the model. + - TimeSeries alpha with alpha_t(i) = alpha[t*N + i] + - TimeSeries scale with scale[t] the scaling at step t + - float -- log_probability of the observation sequence + being produced by the model. """ cdef Py_ssize_t i, j, t, T = len(obs) cdef int N = self.N @@ -811,19 +822,19 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): return alpha, scale, log_probability cdef TimeSeries _baum_welch_xi(self, TimeSeries alpha, TimeSeries beta, TimeSeries obs): - """ + r""" Used internally to compute the scaled quantity xi_t(i,j) appearing in the Baum-Welch reestimation algorithm. INPUT: - - alpha -- TimeSeries as output by the scaled forward algorithm - - beta -- TimeSeries as output by the scaled backward algorithm - - obs -- TimeSeries of observations + - ``alpha`` -- TimeSeries as output by the scaled forward algorithm + - ``beta`` -- TimeSeries as output by the scaled backward algorithm + - ``obs`` -- TimeSeries of observations OUTPUT: - - TimeSeries xi such that xi[t*N*N + i*N + j] = xi_t(i,j). + TimeSeries xi such that xi[t*N*N + i*N + j] = xi_t(i,j). """ cdef int i, j, N = self.N cdef double sum @@ -843,37 +854,39 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): def baum_welch(self, obs, int max_iter=500, double log_likelihood_cutoff=1e-4, double min_sd=0.01, bint fix_emissions=False, bint v=False): - """ - Given an observation sequence obs, improve this HMM using the - Baum-Welch algorithm to increase the probability of observing obs. + r""" + Given an observation sequence ``obs``, improve this HMM using the + Baum-Welch algorithm to increase the probability of observing ``obs``. INPUT: - - obs -- a time series of emissions + - ``obs`` -- a time series of emissions - - max_iter -- integer (default: 500) maximum number - of Baum-Welch steps to take + - ``max_iter`` -- integer (default: 500) maximum number + of Baum-Welch steps to take - - log_likelihood_cutoff -- positive float (default: 1e-4); - the minimal improvement in likelihood with respect to - the last iteration required to continue. Relative value - to log likelihood. + - ``log_likelihood_cutoff`` -- positive float (default: 1e-4); + the minimal improvement in likelihood with respect to + the last iteration required to continue. Relative value + to log likelihood. - - min_sd -- positive float (default: 0.01); when - reestimating, the standard deviation of emissions is not - allowed to be less than min_sd. + - ``min_sd`` -- positive float (default: 0.01); when + reestimating, the standard deviation of emissions is not + allowed to be less than ``min_sd``. - - fix_emissions -- bool (default: False); if True, do not - change emissions when updating + - ``fix_emissions`` -- bool (default: ``False``); if ``True``, do not + change emissions when updating OUTPUT: - - changes the model in places, and returns the log - likelihood and number of iterations. + changes the model in place, and returns the log + likelihood and number of iterations. EXAMPLES:: - sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,.5), (-1,3)], [.1,.9]) + sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], + ....: [(1,.5), (-1,3)], + ....: [.1,.9]) sage: m.log_likelihood([-2,-1,.1,0.1]) -8.858282215986275 sage: m.baum_welch([-2,-1,.1,0.1]) @@ -890,9 +903,11 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): Initial probabilities: [0.0000, 1.0000] We illustrate bounding the standard deviation below. Note that above we had - different emission parameters when the min_sd was the default of 0.01:: + different emission parameters when the ``min_sd`` was the default of 0.01:: - sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,.5), (-1,3)], [.1,.9]) + sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], + ....: [(1,.5), (-1,3)], + ....: [.1,.9]) sage: m.baum_welch([-2,-1,.1,0.1], min_sd=1) (-4.07939572755..., 32) sage: m.emission_parameters() @@ -900,27 +915,36 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): We watch the log likelihoods of the model converge, step by step:: - sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,.5), (-1,3)], [.1,.9]) + sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], + ....: [(1,.5), (-1,3)], + ....: [.1,.9]) sage: v = m.sample(10) - sage: l = stats.TimeSeries([m.baum_welch(v,max_iter=1)[0] for _ in range(len(v))]) + sage: l = stats.TimeSeries([m.baum_welch(v, max_iter=1)[0] + ....: for _ in range(len(v))]) sage: all(l[i] <= l[i+1] + 0.0001 for i in range(9)) True sage: l # random - [-20.1167, -17.7611, -16.9814, -16.9364, -16.9314, -16.9309, -16.9309, -16.9309, -16.9309, -16.9309] + [-20.1167, -17.7611, -16.9814, -16.9364, -16.9314, + -16.9309, -16.9309, -16.9309, -16.9309, -16.9309] We illustrate fixing emissions:: - sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.9,.1]], [(1,2),(-1,.5)], [.3,.7]) + sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.9,.1]], + ....: [(1,2),(-1,.5)], + ....: [.3,.7]) sage: set_random_seed(0); v = m.sample(100) sage: m.baum_welch(v,fix_emissions=True) (-164.72944548204..., 23) sage: m.emission_parameters() [(1.0, 2.0), (-1.0, 0.5)] - sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.9,.1]], [(1,2),(-1,.5)], [.3,.7]) + sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.9,.1]], + ....: [(1,2),(-1,.5)], + ....: [.3,.7]) sage: m.baum_welch(v) (-162.854370397998..., 49) sage: m.emission_parameters() # rel tol 3e-14 - [(1.2722419172602375, 2.371368751761901), (-0.9486174675179113, 0.5762360385123765)] + [(1.2722419172602375, 2.371368751761901), + (-0.9486174675179113, 0.5762360385123765)] """ if not isinstance(obs, TimeSeries): obs = TimeSeries(obs) @@ -1021,30 +1045,28 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): - """ - GaussianMixtureHiddenMarkovModel(A, B, pi) - + r""" Gaussian mixture Hidden Markov Model. INPUT: - - ``A`` -- matrix; the N x N transition matrix + - ``A`` -- matrix; the `N \times N` transition matrix - - ``B`` -- list of mixture definitions for each state. Each - state may have a varying number of gaussians with selection - probabilities that sum to 1 and encoded as (p,(mu,sigma)) + - ``B`` -- list of mixture definitions for each state. Each + state may have a varying number of gaussians with selection + probabilities that sum to 1 and encoded as ``(p, (mu,sigma))`` - - ``pi`` -- initial state probabilities + - ``pi`` -- initial state probabilities - - ``normalize`` --bool (default: True); if given, input is - normalized to define valid probability distributions, - e.g., the entries of A are made nonnegative and the rows - sum to 1, and the probabilities in pi are normalized. + - ``normalize`` -- bool (default: ``True``); if given, input is + normalized to define valid probability distributions, + e.g., the entries of `A` are made nonnegative and the rows + sum to 1, and the probabilities in ``pi`` are normalized. EXAMPLES:: - sage: A = [[0.5,0.5],[0.5,0.5]] - sage: B = [[(0.9,(0.0,1.0)), (0.1,(1,10000))],[(1,(1,1)), (0,(0,0.1))]] + sage: A = [[0.5,0.5],[0.5,0.5]] + sage: B = [[(0.9,(0.0,1.0)), (0.1,(1,10000))],[(1,(1,1)), (0,(0,0.1))]] sage: hmm.GaussianMixtureHiddenMarkovModel(A, B, [1,0]) Gaussian Mixture Hidden Markov Model with 2 States Transition matrix: @@ -1089,7 +1111,7 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): cdef object mixture # mixture def __init__(self, A, B, pi=None, bint normalize=True): - """ + r""" Initialize a Gaussian mixture hidden Markov model. EXAMPLES:: @@ -1131,7 +1153,7 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): return s def __reduce__(self): - """ + r""" Used in pickling. EXAMPLES:: @@ -1145,7 +1167,7 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): def __richcmp__(self, other, op): - """ + r""" Compare self and other, which must both be GaussianMixtureHiddenMarkovModel's. EXAMPLES:: @@ -1167,17 +1189,17 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): other.__reduce__()[1], op) def __getitem__(self, Py_ssize_t i): - """ + r""" Return the Gaussian mixture distribution associated to the i-th state. INPUT: - - i -- integer + - ``i`` -- integer OUTPUT: - - a Gaussian mixture distribution object + a Gaussian mixture distribution object EXAMPLES:: @@ -1210,23 +1232,25 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): return self.mixture[i] def emission_parameters(self): - """ + r""" Returns a list of all the emission distributions. OUTPUT: - - list of Gaussian mixtures + list of Gaussian mixtures EXAMPLES:: - sage: m = hmm.GaussianMixtureHiddenMarkovModel([[.9,.1],[.4,.6]], [[(.4,(0,1)), (.6,(1,0.1))],[(1,(0,1))]], [.7,.3]) + sage: m = hmm.GaussianMixtureHiddenMarkovModel([[.9,.1],[.4,.6]], + ....: [[(.4,(0,1)), (.6,(1,0.1))], [(1,(0,1))]], + ....: [.7,.3]) sage: m.emission_parameters() [0.4*N(0.0,1.0) + 0.6*N(1.0,0.1), 1.0*N(0.0,1.0)] """ return list(self.mixture) cdef double random_sample(self, int state, randstate rstate): - """ + r""" Return a random sample from the normal distribution associated to the given state. @@ -1236,18 +1260,18 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): INPUT: - - state -- integer - - rstate -- randstate instance + - ``state`` -- integer + - ``rstate`` -- randstate instance OUTPUT: - - double + double """ cdef GaussianMixtureDistribution G = self.mixture[state] return G._sample(rstate) cdef double probability_of(self, int state, double observation): - """ + r""" Return the probability b_j(o) of see the given observation o (=observation) given that we're in the given state j (=state). @@ -1257,19 +1281,19 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): INPUT: - - state -- integer - - observation -- double + - ``state`` -- integer + - ``observation`` -- double OUTPUT: - - double + double """ cdef GaussianMixtureDistribution G = self.mixture[state] return G.prob(observation) cdef TimeSeries _baum_welch_mixed_gamma(self, TimeSeries alpha, TimeSeries beta, TimeSeries obs, int j): - """ + r""" Let gamma_t(j,m) be the m-component (in the mixture) of the probability of being in state j at time t, given the observation sequence. This function outputs a TimeSeries v @@ -1278,14 +1302,14 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): INPUT: - - alpha -- TimeSeries - - beta -- TimeSeries - - obs -- TimeSeries - - j -- int + - ``alpha`` -- TimeSeries + - ``beta`` -- TimeSeries + - ``obs`` -- TimeSeries + - ``j`` -- int OUTPUT: - - TimeSeries + TimeSeries """ cdef int i, k, m, N = self.N cdef Py_ssize_t t, T = alpha._length//N @@ -1322,35 +1346,39 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): def baum_welch(self, obs, int max_iter=1000, double log_likelihood_cutoff=1e-12, double min_sd=0.01, bint fix_emissions=False): - """ - Given an observation sequence obs, improve this HMM using the - Baum-Welch algorithm to increase the probability of observing obs. + r""" + Given an observation sequence ``obs``, improve this HMM using the + Baum-Welch algorithm to increase the probability of observing ``obs``. INPUT: - - obs -- a time series of emissions - - max_iter -- integer (default: 1000) maximum number - of Baum-Welch steps to take - - log_likelihood_cutoff -- positive float (default: 1e-12); - the minimal improvement in likelihood with respect to - the last iteration required to continue. Relative value - to log likelihood. - - min_sd -- positive float (default: 0.01); when - reestimating, the standard deviation of emissions is not - allowed to be less than min_sd. - - fix_emissions -- bool (default: False); if True, do not - change emissions when updating + - ``obs`` -- a time series of emissions + - ``max_iter`` -- integer (default: 1000) maximum number + of Baum-Welch steps to take + - ``log_likelihood_cutoff`` -- positive float (default: 1e-12); + the minimal improvement in likelihood with respect to + the last iteration required to continue. Relative value + to log likelihood. + - ``min_sd`` -- positive float (default: 0.01); when + reestimating, the standard deviation of emissions is not + allowed to be less than ``min_sd``. + - ``fix_emissions`` -- bool (default: ``False``); if ``True``, do not + change emissions when updating OUTPUT: - - changes the model in places, and returns the log - likelihood and number of iterations. + changes the model in place, and returns the log + likelihood and number of iterations. EXAMPLES:: - sage: m = hmm.GaussianMixtureHiddenMarkovModel([[.9,.1],[.4,.6]], [[(.4,(0,1)), (.6,(1,0.1))],[(1,(0,1))]], [.7,.3]) + sage: m = hmm.GaussianMixtureHiddenMarkovModel( + ....: [[.9,.1],[.4,.6]], + ....: [[(.4,(0,1)), (.6,(1,0.1))], [(1,(0,1))]], + ....: [.7,.3]) sage: set_random_seed(0); v = m.sample(10); v - [0.3576, -0.9365, 0.9449, -0.6957, 1.0217, 0.9644, 0.9987, -0.5950, -1.0219, 0.6477] + [0.3576, -0.9365, 0.9449, -0.6957, 1.0217, + 0.9644, 0.9987, -0.5950, -1.0219, 0.6477] sage: m.log_likelihood(v) -8.31408655939536... sage: m.baum_welch(v) @@ -1363,26 +1391,36 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): [ 0.8746363339773399 0.12536366602266016] [ 1.0 1.451685202290174e-40] Emission parameters: - [0.500161629343*N(-0.812298726239,0.173329026744) + 0.499838370657*N(0.982433690378,0.029719932009), 1.0*N(0.503260056832,0.145881515324)] + [0.500161629343*N(-0.812298726239,0.173329026744) + + 0.499838370657*N(0.982433690378,0.029719932009), + 1.0*N(0.503260056832,0.145881515324)] Initial probabilities: [0.0000, 1.0000] We illustrate bounding the standard deviation below. Note that above we had different emission parameters when the min_sd was the default of 0.01:: - sage: m = hmm.GaussianMixtureHiddenMarkovModel([[.9,.1],[.4,.6]], [[(.4,(0,1)), (.6,(1,0.1))],[(1,(0,1))]], [.7,.3]) + sage: m = hmm.GaussianMixtureHiddenMarkovModel( + ....: [[.9,.1],[.4,.6]], + ....: [[(.4,(0,1)), (.6,(1,0.1))], [(1,(0,1))]], + ....: [.7,.3]) sage: m.baum_welch(v, min_sd=1) (-12.617885761692..., 1000) sage: m.emission_parameters() # rel tol 6e-12 - [0.503545634447*N(0.200166509595,1.0) + 0.496454365553*N(0.200166509595,1.0), 1.0*N(0.0543433426535,1.0)] + [0.503545634447*N(0.200166509595,1.0) + 0.496454365553*N(0.200166509595,1.0), + 1.0*N(0.0543433426535,1.0)] We illustrate fixing all emissions:: - sage: m = hmm.GaussianMixtureHiddenMarkovModel([[.9,.1],[.4,.6]], [[(.4,(0,1)), (.6,(1,0.1))],[(1,(0,1))]], [.7,.3]) + sage: m = hmm.GaussianMixtureHiddenMarkovModel( + ....: [[.9,.1],[.4,.6]], + ....: [[(.4,(0,1)), (.6,(1,0.1))], [(1,(0,1))]], + ....: [.7,.3]) sage: set_random_seed(0); v = m.sample(10) sage: m.baum_welch(v, fix_emissions=True) (-7.58656858997..., 36) sage: m.emission_parameters() - [0.4*N(0.0,1.0) + 0.6*N(1.0,0.1), 1.0*N(0.0,1.0)] + [0.4*N(0.0,1.0) + 0.6*N(1.0,0.1), + 1.0*N(0.0,1.0)] """ if not isinstance(obs, TimeSeries): obs = TimeSeries(obs) @@ -1515,7 +1553,7 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): # We keep the _v0 function for backwards compatible. def unpickle_gaussian_hmm_v0(A, B, pi, name): - """ + r""" EXAMPLES:: sage: m = hmm.GaussianHiddenMarkovModel([[1]], [(0,1)], [1]) @@ -1531,7 +1569,7 @@ def unpickle_gaussian_hmm_v0(A, B, pi, name): def unpickle_gaussian_hmm_v1(A, B, pi, prob, n_out): - """ + r""" EXAMPLES:: sage: m = hmm.GaussianHiddenMarkovModel([[1]], [(0,1)], [1]) @@ -1547,7 +1585,7 @@ def unpickle_gaussian_hmm_v1(A, B, pi, prob, n_out): return m def unpickle_gaussian_mixture_hmm_v1(A, B, pi, mixture): - """ + r""" EXAMPLES:: sage: m = hmm.GaussianMixtureHiddenMarkovModel([[1]], [[(.4,(0,1)), (.6,(1,0.1))]], [1]) diff --git a/src/sage/stats/hmm/distributions.pyx b/src/sage/stats/hmm/distributions.pyx index 0cc9823a38f..65a743e26f1 100644 --- a/src/sage/stats/hmm/distributions.pyx +++ b/src/sage/stats/hmm/distributions.pyx @@ -1,4 +1,5 @@ -""" +# sage.doctest: optional - numpy +r""" Distributions used in implementing Hidden Markov Models These distribution classes are designed specifically for HMM's and not @@ -34,20 +35,20 @@ from sage.stats.time_series cimport TimeSeries cdef double random_normal(double mean, double std, randstate rstate): - """ + r""" Return a floating point number chosen from the normal distribution with given mean and standard deviation, using the given randstate. The computation uses the box muller algorithm. INPUT: - - mean -- float; the mean - - std -- float; the standard deviation - - rstate -- randstate; the random number generator state + - ``mean`` -- float; the mean + - ``std`` -- float; the standard deviation + - ``rstate`` -- randstate; the random number generator state OUTPUT: - - double + - double """ # Ported from http://users.tkk.fi/~nbeijar/soft/terrain/source_o2/boxmuller.c # This the box muller algorithm. @@ -66,21 +67,21 @@ cdef double random_normal(double mean, double std, randstate rstate): # Abstract base class for distributions used for hidden Markov models. cdef class Distribution: - """ + r""" A distribution. """ def sample(self, n=None): - """ - Return either a single sample (the default) or n samples from + r""" + Return either a single sample (the default) or `n` samples from this probability distribution. INPUT: - - n -- None or a positive integer + - ``n`` -- ``None`` or a positive integer OUTPUT: - - a single sample if n is 1; otherwise many samples + - a single sample if `n` is 1; otherwise many samples EXAMPLES: @@ -95,16 +96,16 @@ cdef class Distribution: raise NotImplementedError def prob(self, x): - """ - The probability density function evaluated at x. + r""" + The probability density function evaluated at `x`. INPUT: - - x -- object + - ``x`` -- object OUTPUT: - - float + - float EXAMPLES: @@ -119,28 +120,28 @@ cdef class Distribution: raise NotImplementedError def plot(self, *args, **kwds): - """ + r""" Return a plot of the probability density function. INPUT: - - args and kwds, passed to the Sage plot function + - ``args`` and ``kwds``, passed to the Sage :func:`plot` function OUTPUT: - - a Graphics object + - a :class:`Graphics` object EXAMPLES:: sage: P = hmm.GaussianMixtureDistribution([(.2,-10,.5),(.6,1,1),(.2,20,.5)]) - sage: P.plot(-10,30) + sage: P.plot(-10,30) # needs sage.plot Graphics object consisting of 1 graphics primitive """ from sage.plot.all import plot return plot(self.prob, *args, **kwds) cdef class GaussianMixtureDistribution(Distribution): - """ + r""" A probability distribution defined by taking a weighted linear combination of Gaussian distributions. @@ -162,17 +163,17 @@ cdef class GaussianMixtureDistribution(Distribution): False """ def __init__(self, B, eps=1e-8, bint normalize=True): - """ + r""" INPUT: - - `B` -- a list of triples `(c_i, mean_i, std_i)`, where - the `c_i` and `std_i` are positive and the sum of the - `c_i` is `1`. + - ``B`` -- a list of triples ``(c_i, mean_i, std_i)``, where + the ``c_i`` and ``std_i`` are positive and the sum of the + ``c_i`` is `1`. - - eps -- positive real number; any standard deviation in B - less than eps is replaced by eps. + - ``eps`` -- positive real number; any standard deviation in B + less than eps is replaced by eps. - - normalize -- if True, ensure that the c_i are nonnegative + - ``normalize`` -- if ``True``, ensure that the ``c_i`` are nonnegative EXAMPLES:: @@ -201,16 +202,16 @@ cdef class GaussianMixtureDistribution(Distribution): self.fixed = IntList(self.c0._length) def __getitem__(self, Py_ssize_t i): - """ - Returns triple (coefficient, mu, std). + r""" + Return triple (coefficient, mu, std). INPUT: - - i -- integer + - ``i`` -- integer OUTPUT: - - triple of floats + - triple of floats EXAMPLES:: @@ -238,7 +239,7 @@ cdef class GaussianMixtureDistribution(Distribution): return self.param._values[3*i], self.param._values[3*i+1], self.param._values[3*i+2] def __reduce__(self): - """ + r""" Used in pickling. EXAMPLES:: @@ -251,7 +252,7 @@ cdef class GaussianMixtureDistribution(Distribution): self.c0, self.c1, self.param, self.fixed) def __richcmp__(self, other, op): - """ + r""" EXAMPLES:: sage: G = hmm.GaussianMixtureDistribution([(.1,1,2), (.9,0,1)]) @@ -271,7 +272,7 @@ cdef class GaussianMixtureDistribution(Distribution): other.__reduce__()[1], op) def __len__(self): - """ + r""" Return the number of components of this GaussianMixtureDistribution. EXAMPLES:: @@ -282,14 +283,14 @@ cdef class GaussianMixtureDistribution(Distribution): return self.c0._length cpdef is_fixed(self, i=None): - """ - Return whether or not this GaussianMixtureDistribution is + r""" + Return whether or not this :class:`GaussianMixtureDistribution` is fixed when using Baum-Welch to update the corresponding HMM. INPUT: - - i -- None (default) or integer; if given, only return - whether the i-th component is fixed + - ``i`` -- ``None`` (default) or integer; if given, only return + whether the `i`-th component is fixed EXAMPLES:: @@ -311,15 +312,15 @@ cdef class GaussianMixtureDistribution(Distribution): return bool(self.fixed[i]) def fix(self, i=None): - """ - Set that this GaussianMixtureDistribution (or its ith + r""" + Set that this :class:`GaussianMixtureDistribution` (or its `i`-th component) is fixed when using Baum-Welch to update the corresponding HMM. INPUT: - - i -- None (default) or integer; if given, only fix the - i-th component + - ``i`` -- ``None`` (default) or integer; if given, only fix the + `i`-th component EXAMPLES:: @@ -339,15 +340,15 @@ cdef class GaussianMixtureDistribution(Distribution): self.fixed[i] = 1 def unfix(self, i=None): - """ - Set that this GaussianMixtureDistribution (or its ith + r""" + Set that this :class:`GaussianMixtureDistribution` (or its `i`-th component) is not fixed when using Baum-Welch to update the corresponding HMM. INPUT: - - i -- None (default) or integer; if given, only fix the - i-th component + - ``i`` -- ``None`` (default) or integer; if given, only fix the + `i`-th component EXAMPLES:: @@ -371,7 +372,7 @@ cdef class GaussianMixtureDistribution(Distribution): def __repr__(self): - """ + r""" Return string representation of this mixed Gaussian distribution. EXAMPLES:: @@ -382,17 +383,17 @@ cdef class GaussianMixtureDistribution(Distribution): return ' + '.join("%s*N(%s,%s)" % x for x in self) def sample(self, n=None): - """ + r""" Return a single sample from this distribution (by default), or - if n>1, return a TimeSeries of samples. + if `n>1`, return a :class:`TimeSeries` of samples. INPUT: - - n -- integer or None (default: None) + - ``n`` -- integer or ``None`` (default: ``None``) OUTPUT: - - float if n is None (default); otherwise a TimeSeries + - float if ``n`` is ``None`` (default); otherwise a :class:`TimeSeries` EXAMPLES:: @@ -434,16 +435,16 @@ cdef class GaussianMixtureDistribution(Distribution): return T cdef double _sample(self, randstate rstate): - """ + r""" Used internally to compute a sample from this distribution quickly. INPUT: - - rstate -- a randstate object + - ``rstate`` -- a randstate object OUTPUT: - - double + - double """ cdef double accum, r cdef int n @@ -459,19 +460,19 @@ cdef class GaussianMixtureDistribution(Distribution): raise RuntimeError("invalid probability distribution") cpdef double prob(self, double x): - """ - Return the probability of x. + r""" + Return the probability of `x`. Since this is a continuous distribution, this is defined to be the limit of the p's such that the probability of [x,x+h] is p*h. INPUT: - - x -- float + - ``x`` -- float OUTPUT: - - float + - float EXAMPLES:: @@ -495,17 +496,17 @@ cdef class GaussianMixtureDistribution(Distribution): return s cpdef double prob_m(self, double x, int m): - """ - Return the probability of x using just the m-th summand. + r""" + Return the probability of `x` using just the `m`-th summand. INPUT: - - x -- float - - m -- integer + - ``x`` -- float + - ``m`` -- integer OUTPUT: - - float + - float EXAMPLES:: @@ -525,8 +526,8 @@ cdef class GaussianMixtureDistribution(Distribution): def unpickle_gaussian_mixture_distribution_v1(TimeSeries c0, TimeSeries c1, TimeSeries param, IntList fixed): - """ - Used in unpickling GaussianMixtureDistribution's. + r""" + Used in unpickling :class:`GaussianMixtureDistribution` objects. EXAMPLES:: diff --git a/src/sage/stats/hmm/hmm.pyx b/src/sage/stats/hmm/hmm.pyx index 8f2eee8bebc..f48d0c9e4db 100644 --- a/src/sage/stats/hmm/hmm.pyx +++ b/src/sage/stats/hmm/hmm.pyx @@ -1,4 +1,5 @@ -""" +# sage.doctest: needs numpy sage.modules +r""" Hidden Markov Models This is a complete pure-Cython optimized implementation of Hidden @@ -7,10 +8,10 @@ Gaussian emissions. The best references for the basic HMM algorithms implemented here are: - - Tapas Kanungo's "Hidden Markov Models" +- Tapas Kanungo's "Hidden Markov Models" - - Jackson's HMM tutorial: - http://personal.ee.surrey.ac.uk/Personal/P.Jackson/tutorial/ +- Jackson's HMM tutorial: + http://personal.ee.surrey.ac.uk/Personal/P.Jackson/tutorial/ LICENSE: Some of the code in this file is based on reading Kanungo's GPLv2+ implementation of discrete HMM's, hence the present code must @@ -47,24 +48,26 @@ cdef HMM_Util util = HMM_Util() ########################################### cdef class HiddenMarkovModel: - """ + r""" Abstract base class for all Hidden Markov Models. """ def initial_probabilities(self): - """ - Return the initial probabilities, which as a TimeSeries of - length N, where N is the number of states of the Markov model. + r""" + Return the initial probabilities as a :class:`TimeSeries` of + length `N`, where `N` is the number of states of the Markov model. EXAMPLES:: - sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.5,0.5]], [.2,.8]) + sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], + ....: [[0.1,0.9],[0.5,0.5]], + ....: [.2,.8]) sage: pi = m.initial_probabilities(); pi [0.2000, 0.8000] sage: type(pi) <... 'sage.stats.time_series.TimeSeries'> The returned time series is a copy, so changing it does not - change the model. + change the model:: sage: pi[0] = .1; pi[1] = .9 sage: m.initial_probabilities() @@ -72,24 +75,31 @@ cdef class HiddenMarkovModel: Some other models:: - sage: hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,1), (-1,1)], [.1,.9]).initial_probabilities() + sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], + ....: [(1,1), (-1,1)], + ....: [.1,.9]) + sage: m.initial_probabilities() [0.1000, 0.9000] - sage: hmm.GaussianMixtureHiddenMarkovModel([[.9,.1],[.4,.6]], [[(.4,(0,1)), (.6,(1,0.1))],[(1,(0,1))]], [.7,.3]).initial_probabilities() + sage: m = hmm.GaussianMixtureHiddenMarkovModel( + ....: [[.9,.1],[.4,.6]], + ....: [[(.4,(0,1)), (.6,(1,0.1))], [(1,(0,1))]], + ....: [.7,.3]) + sage: m.initial_probabilities() [0.7000, 0.3000] """ return TimeSeries(self.pi) def transition_matrix(self): - """ + r""" Return the state transition matrix. - OUTPUT: - - - a Sage matrix with real double precision (RDF) entries. + OUTPUT: a Sage matrix with real double precision (RDF) entries. EXAMPLES:: - sage: M = hmm.DiscreteHiddenMarkovModel([[0.7,0.3],[0.9,0.1]], [[0.5,.5],[.1,.9]], [0.3,0.7]) + sage: M = hmm.DiscreteHiddenMarkovModel([[0.7,0.3],[0.9,0.1]], + ....: [[0.5,.5],[.1,.9]], + ....: [0.3,0.7]) sage: T = M.transition_matrix(); T [0.7 0.3] [0.9 0.1] @@ -104,10 +114,17 @@ cdef class HiddenMarkovModel: Transition matrices for other types of models:: - sage: hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,1), (-1,1)], [.5,.5]).transition_matrix() + sage: M = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], + ....: [(1,1), (-1,1)], + ....: [.5,.5]) + sage: M.transition_matrix() [0.1 0.9] [0.5 0.5] - sage: hmm.GaussianMixtureHiddenMarkovModel([[.9,.1],[.4,.6]], [[(.4,(0,1)), (.6,(1,0.1))],[(1,(0,1))]], [.7,.3]).transition_matrix() + sage: M = hmm.GaussianMixtureHiddenMarkovModel( + ....: [[.9,.1],[.4,.6]], + ....: [[(.4,(0,1)), (.6,(1,0.1))],[(1,(0,1))]], + ....: [.7,.3]) + sage: M.transition_matrix() [0.9 0.1] [0.4 0.6] """ @@ -116,26 +133,26 @@ cdef class HiddenMarkovModel: return matrix(RDF, self.N, self.A.list()) def graph(self, eps=1e-3): - """ + r""" Create a weighted directed graph from the transition matrix, - not including any edge with a probability less than eps. + not including any edge with a probability less than ``eps``. INPUT: - - eps -- nonnegative real number - - OUTPUT: + - ``eps`` -- nonnegative real number - - a digraph + OUTPUT: a :class:`DiGraph` EXAMPLES:: - sage: m = hmm.DiscreteHiddenMarkovModel([[.3,0,.7],[0,0,1],[.5,.5,0]], [[.5,.5,.2]]*3, [1/3]*3) - sage: G = m.graph(); G + sage: m = hmm.DiscreteHiddenMarkovModel([[.3,0,.7],[0,0,1],[.5,.5,0]], + ....: [[.5,.5,.2]]*3, + ....: [1/3]*3) + sage: G = m.graph(); G # needs sage.graphs Looped digraph on 3 vertices - sage: G.edges(sort=True) + sage: G.edges(sort=True) # needs sage.graphs [(0, 0, 0.3), (0, 2, 0.7), (1, 2, 1.0), (2, 0, 0.5), (2, 1, 0.5)] - sage: G.plot() + sage: G.plot() # needs sage.graphs sage.plot Graphics object consisting of 11 graphics primitives """ cdef int i, j @@ -148,29 +165,33 @@ cdef class HiddenMarkovModel: return DiGraph(m, weighted=True) def sample(self, Py_ssize_t length, number=None, starting_state=None): - """ + r""" Return number samples from this HMM of given length. INPUT: - - ``length`` -- positive integer - - ``number`` -- (default: None) if given, compute list of this many sample sequences - - ``starting_state`` -- int (or None); if specified then generate - a sequence using this model starting with the given state - instead of the initial probabilities to determine the - starting state. + - ``length`` -- positive integer + - ``number`` -- (default: ``None``) if given, compute list of this many sample sequences + - ``starting_state`` -- int (or ``None``); if specified, generate + a sequence using this model starting with the given state + instead of the initial probabilities to determine the + starting state. OUTPUT: - - if number is not given, return a single TimeSeries. - - if number is given, return a list of TimeSeries. + - if ``number`` is not given, return a single :class:`TimeSeries`. + - if ``number`` is given, return a list of :class:`TimeSeries`. EXAMPLES:: sage: set_random_seed(0) - sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]], [[1,0],[0,1]], [0,1]) + sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]], + ....: [[1,0],[0,1]], + ....: [0,1]) sage: print(a.sample(10, 3)) - [[1, 0, 1, 1, 1, 1, 0, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 0, 1, 0, 1, 1, 1]] + [[1, 0, 1, 1, 1, 1, 0, 1, 1, 1], + [1, 1, 0, 0, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 0, 1, 0, 1, 1, 1]] sage: a.sample(15) [1, 1, 1, 1, 0 ... 1, 1, 1, 1, 1] sage: a.sample(3, 1) @@ -181,7 +202,9 @@ cdef class HiddenMarkovModel: If the emission symbols are set:: sage: set_random_seed(0) - sage: a = hmm.DiscreteHiddenMarkovModel([[0.5,0.5],[0.1,0.9]], [[1,0],[0,1]], [0,1], ['up', 'down']) + sage: a = hmm.DiscreteHiddenMarkovModel([[0.5,0.5],[0.1,0.9]], + ....: [[1,0],[0,1]], [0,1], + ....: ['up', 'down']) sage: a.sample(10) ['down', 'up', 'down', 'down', 'down', 'down', 'up', 'up', 'up', 'up'] @@ -202,7 +225,7 @@ cdef class HiddenMarkovModel: # HMM algorithms. ######################################################### cdef TimeSeries _baum_welch_gamma(self, TimeSeries alpha, TimeSeries beta): - """ + r""" Used internally to compute the scaled quantity gamma_t(j) appearing in the Baum-Welch reestimation algorithm. @@ -211,12 +234,10 @@ cdef class HiddenMarkovModel: INPUT: - - ``alpha`` -- TimeSeries as output by the scaled forward algorithm - - ``beta`` -- TimeSeries as output by the scaled backward algorithm - - OUTPUT: + - ``alpha`` -- :class:`TimeSeries` as output by the scaled forward algorithm + - ``beta`` -- :class:`TimeSeries` as output by the scaled backward algorithm - - TimeSeries gamma such that gamma[t*N+j] is gamma_t(j). + OUTPUT: :class:`TimeSeries` gamma such that gamma[t*N+j] is gamma_t(j). """ cdef int j, N = self.N cdef Py_ssize_t t, T = alpha._length//N @@ -235,37 +256,39 @@ cdef class HiddenMarkovModel: cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): - """ + r""" A discrete Hidden Markov model implemented using double precision floating point arithmetic. INPUT: - - ``A`` -- a list of lists or a square N x N matrix, whose - (i,j) entry gives the probability of transitioning from - state i to state j. + - ``A`` -- a list of lists or a square `N \times N` matrix, whose + `(i,j)` entry gives the probability of transitioning from + state `i` to state `j`. - - ``B`` -- a list of N lists or a matrix with N rows, such that - B[i,k] gives the probability of emitting symbol k while - in state i. + - ``B`` -- a list of `N` lists or a matrix with `N` rows, such that + `B[i,k]` gives the probability of emitting symbol `k` while + in state `i`. - - ``pi`` -- the probabilities of starting in each initial - state, i.e,. pi[i] is the probability of starting in - state i. + - ``pi`` -- the probabilities of starting in each initial + state, i.e., ``pi[i]`` is the probability of starting in + state `i`. - - ``emission_symbols`` -- None or list (default: None); if - None, the emission_symbols are the ints [0..N-1], where N - is the number of states. Otherwise, they are the entries - of the list emissions_symbols, which must all be hashable. + - ``emission_symbols`` -- ``None`` or list (default: ``None``); if + None, the emission_symbols are the ints ``[0..N-1]``, where `N` + is the number of states. Otherwise, they are the entries + of the list ``emissions_symbols``, which must all be hashable. - - ``normalize`` --bool (default: True); if given, input is - normalized to define valid probability distributions, - e.g., the entries of A are made nonnegative and the rows - sum to 1, and the probabilities in pi are normalized. + - ``normalize`` -- bool (default: ``True``); if given, input is + normalized to define valid probability distributions, + e.g., the entries of `A` are made nonnegative and the rows + sum to 1, and the probabilities in ``pi`` are normalized. EXAMPLES:: - sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.5,0.5]], [.5,.5]); m + sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], + ....: [[0.1,0.9],[0.5,0.5]], + ....: [.5,.5]); m Discrete Hidden Markov Model with 2 States and 2 Emissions Transition matrix: [0.4 0.6] @@ -291,7 +314,7 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): Initial probabilities: [0.0000, 1.0000] sage: m.sample(10) [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] - sage: m.graph().plot() + sage: m.graph().plot() # needs sage.plot Graphics object consisting of 6 graphics primitives A 3-state model that happens to always outputs 'b':: @@ -305,7 +328,7 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): cdef object _emission_symbols, _emission_symbols_dict def __init__(self, A, B, pi, emission_symbols=None, bint normalize=True): - """ + r""" Create a discrete emissions HMM with transition probability matrix A, emission probabilities given by B, initial state probabilities pi, and given emission symbols (which default @@ -348,7 +371,7 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): util.normalize_probability_TimeSeries(self.B, i*self.n_out, (i+1)*self.n_out) def __reduce__(self): - """ + r""" Used in pickling. EXAMPLES:: @@ -361,7 +384,7 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): (self.A, self.B, self.pi, self.n_out, self._emission_symbols, self._emission_symbols_dict) def __richcmp__(self, other, op): - """ + r""" EXAMPLES:: sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.0,1.0],[0.5,0.5]], [.5,.5]) @@ -381,21 +404,21 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): other.__reduce__()[1], op) def emission_matrix(self): - """ - Return the matrix whose i-th row specifies the emission - probability distribution for the i-th state. + r""" + Return the matrix whose `i`-th row specifies the emission + probability distribution for the `i`-th state. More precisely, - the i,j entry of the matrix is the probability of the Markov - model outputting the j-th symbol when it is in the i-th state. - - OUTPUT: + the `i,j` entry of the matrix is the probability of the Markov + model outputting the `j`-th symbol when it is in the `i`-th state. - - a Sage matrix with real double precision (RDF) entries. + OUTPUT: a Sage matrix with real double precision (RDF) entries. EXAMPLES:: - sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.5,0.5]], [.5,.5]) + sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], + ....: [[0.1,0.9],[0.5,0.5]], + ....: [.5,.5]) sage: E = m.emission_matrix(); E [0.1 0.9] [0.5 0.5] @@ -433,16 +456,14 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return s def _emission_symbols_to_IntList(self, obs): - """ - Internal function used to convert a list of emission symbols to an IntList. + r""" + Internal function used to convert a list of emission symbols to an :class:`IntList`. INPUT: - - obs -- a list of objects + - ``obs`` -- a list of objects - OUTPUT: - - - an IntList + OUTPUT: an IntList EXAMPLES:: @@ -454,16 +475,14 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return IntList([d[x] for x in obs]) def _IntList_to_emission_symbols(self, obs): - """ + r""" Internal function used to convert a list of emission symbols to an IntList. INPUT: - - obs -- a list of objects - - OUTPUT: + - ``obs`` -- a list of objects - - an IntList + OUTPUT: an IntList EXAMPLES:: @@ -475,22 +494,24 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return [d[x] for x in obs] def log_likelihood(self, obs, bint scale=True): - """ + r""" Return the logarithm of the probability that this model produced the given observation sequence. Thus the output is a non-positive number. INPUT: - - ``obs`` -- sequence of observations + - ``obs`` -- sequence of observations - - ``scale`` -- boolean (default: True); if True, use rescaling - to overoid loss of precision due to the very limited - dynamic range of floats. You should leave this as True - unless the obs sequence is very small. + - ``scale`` -- boolean (default: ``True``); if ``True``, use rescaling + to overoid loss of precision due to the very limited + dynamic range of floats. You should leave this as ``True`` + unless the ``obs`` sequence is very small. EXAMPLES:: - sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.5,0.5]], [.2,.8]) + sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], + ....: [[0.1,0.9],[0.5,0.5]], + ....: [.2,.8]) sage: m.log_likelihood([0, 1, 0, 1, 1, 0, 1, 0, 0, 0]) -7.3301308009370825 sage: m.log_likelihood([0, 1, 0, 1, 1, 0, 1, 0, 0, 0], scale=False) @@ -498,7 +519,9 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): sage: m.log_likelihood([]) 0.0 - sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.5,0.5]], [.2,.8], ['happy','sad']) + sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], + ....: [[0.1,0.9],[0.5,0.5]], + ....: [.2,.8], ['happy','sad']) sage: m.log_likelihood(['happy','happy']) -1.6565295199679506 sage: m.log_likelihood(['happy','sad']) @@ -506,7 +529,9 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): Overflow from not using the scale option:: - sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.1,0.9],[0.5,0.5]], [.2,.8]) + sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], + ....: [[0.1,0.9],[0.5,0.5]], + ....: [.2,.8]) sage: m.log_likelihood([0,1]*1000, scale=True) -1433.820666652728 sage: m.log_likelihood([0,1]*1000, scale=False) @@ -524,16 +549,16 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return self._forward(obs) def _forward(self, IntList obs): - """ + r""" Memory-efficient implementation of the forward algorithm, without scaling. INPUT: - - ``obs`` -- an integer list of observation states. + - ``obs`` -- an integer list of observation states. OUTPUT: - - ``float`` -- the log of the probability that the model produced this sequence + ``float`` -- the log of the probability that the model produced this sequence EXAMPLES:: @@ -579,16 +604,16 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return log(alpha.sum()) def _forward_scale(self, IntList obs): - """ + r""" Memory-efficient implementation of the forward algorithm, with scaling. INPUT: - - ``obs`` -- an integer list of observation states. + - ``obs`` -- an integer list of observation states. OUTPUT: - - ``float`` -- the log of the probability that the model produced this sequence + ``float`` -- the log of the probability that the model produced this sequence EXAMPLES:: @@ -668,30 +693,31 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return log_probability def generate_sequence(self, Py_ssize_t length, starting_state=None): - """ + r""" Return a sample of the given length from this HMM. INPUT: - - ``length`` -- positive integer - - ``starting_state`` -- int (or None); if specified then generate - a sequence using this model starting with the given state - instead of the initial probabilities to determine the - starting state. - + - ``length`` -- positive integer + - ``starting_state`` -- int (or ``None``); if specified, generate + a sequence using this model starting with the given state + instead of the initial probabilities to determine the + starting state. OUTPUT: - - an IntList or list of emission symbols - - IntList of the actual states the model was in when - emitting the corresponding symbols + - an :class:`IntList` or list of emission symbols + - :class:`IntList` of the actual states the model was in when + emitting the corresponding symbols EXAMPLES: In this example, the emission symbols are not set:: sage: set_random_seed(0) - sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]], [[1,0],[0,1]], [0,1]) + sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]], + ....: [[1,0],[0,1]], + ....: [0,1]) sage: a.generate_sequence(5) ([1, 0, 1, 1, 1], [1, 0, 1, 1, 1]) sage: list(a.generate_sequence(1000)[0]).count(0) @@ -700,7 +726,9 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): Here the emission symbols are set:: sage: set_random_seed(0) - sage: a = hmm.DiscreteHiddenMarkovModel([[0.5,0.5],[0.1,0.9]], [[1,0],[0,1]], [0,1], ['up', 'down']) + sage: a = hmm.DiscreteHiddenMarkovModel([[0.5,0.5],[0.1,0.9]], + ....: [[1,0],[0,1]], + ....: [0,1], ['up', 'down']) sage: a.generate_sequence(5) (['down', 'up', 'down', 'down', 'down'], [1, 0, 1, 1, 1]) @@ -783,18 +811,18 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return self._IntList_to_emission_symbols(obs), states cdef int _gen_symbol(self, int q, double r): - """ + r""" Generate a symbol in state q using the randomly chosen floating point number r, which should be between 0 and 1. INPUT: - - ``q`` -- a nonnegative integer, which specifies a state - - ``r`` -- a real number between 0 and 1 + - ``q`` -- a nonnegative integer, which specifies a state + - ``r`` -- a real number between 0 and 1 OUTPUT: - - a nonnegative int + a nonnegative int EXAMPLES:: @@ -819,7 +847,7 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return self.n_out - 1 def viterbi(self, obs, log_scale=True): - """ + r""" Determine "the" hidden sequence of states that is most likely to produce the given sequence seq of observations, along with the probability that this hidden sequence actually produced @@ -827,28 +855,32 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): INPUT: - - ``seq`` -- sequence of emitted ints or symbols + - ``seq`` -- sequence of emitted ints or symbols - - ``log_scale`` -- bool (default: True) whether to scale the - sequence in order to avoid numerical overflow. + - ``log_scale`` -- bool (default: ``True``) whether to scale the + sequence in order to avoid numerical overflow. OUTPUT: - - ``list`` -- "the" most probable sequence of hidden states, i.e., - the Viterbi path. + - ``list`` -- "the" most probable sequence of hidden states, i.e., + the Viterbi path. - - ``float`` -- log of probability that the observed sequence - was produced by the Viterbi sequence of states. + - ``float`` -- log of probability that the observed sequence + was produced by the Viterbi sequence of states. EXAMPLES:: - sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]], [[0.9,0.1],[0.1,0.9]], [0.5,0.5]) + sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]], + ....: [[0.9,0.1],[0.1,0.9]], + ....: [0.5,0.5]) sage: a.viterbi([1,0,0,1,0,0,1,1]) ([1, 0, 0, 1, ..., 0, 1, 1], -11.06245322477221...) We predict the state sequence when the emissions are 3/4 and 'abc'.:: - sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]], [[0.9,0.1],[0.1,0.9]], [0.5,0.5], [3/4, 'abc']) + sage: a = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.1,0.9]], + ....: [[0.9,0.1],[0.1,0.9]], + ....: [0.5,0.5], [3/4, 'abc']) Note that state 0 is common below, despite the model trying hard to switch to state 1:: @@ -866,20 +898,20 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return self._viterbi(obs) cpdef _viterbi(self, IntList obs): - """ + r""" Used internally to compute the viterbi path, without rescaling. This can be useful for short sequences. INPUT: - - ``obs`` -- IntList + - ``obs`` -- IntList OUTPUT: - - IntList (most likely state sequence) + - IntList (most likely state sequence) - - log of probability that the observed sequence was - produced by the Viterbi sequence of states. + - log of probability that the observed sequence was + produced by the Viterbi sequence of states. EXAMPLES:: @@ -946,19 +978,19 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): cpdef _viterbi_scale(self, IntList obs): - """ + r""" Used internally to compute the viterbi path with rescaling. INPUT: - - obs -- IntList + - ``obs`` -- IntList OUTPUT: - - IntList (most likely state sequence) + - IntList (most likely state sequence) - - log of probability that the observed sequence was - produced by the Viterbi sequence of states. + - log of probability that the observed sequence was + produced by the Viterbi sequence of states. EXAMPLES:: @@ -1045,15 +1077,15 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): INPUT: - - ``obs`` -- IntList - - ``scale`` -- series that is *changed* in place, so that - after calling this function, scale[t] is value that is - used to scale each of the `\beta_t(i)`. + - ``obs`` -- IntList + - ``scale`` -- series that is *changed* in place, so that + after calling this function, scale[t] is value that is + used to scale each of the `\beta_t(i)`. OUTPUT: - - a TimeSeries of values beta_t(i). - - the input object scale is modified + - a TimeSeries of values beta_t(i). + - the input object scale is modified """ cdef Py_ssize_t t, T = obs._length cdef int N = self.N, i, j @@ -1077,20 +1109,20 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return beta cdef _forward_scale_all(self, IntList obs): - """ + r""" Return scaled values alpha_t(i), the sequence of scalings, and the log probability. INPUT: - - ``obs`` -- IntList + - ``obs`` -- IntList OUTPUT: - - TimeSeries alpha with alpha_t(i) = alpha[t*N + i] - - TimeSeries scale with scale[t] the scaling at step t - - float -- log_probability of the observation sequence - being produced by the model. + - TimeSeries alpha with alpha_t(i) = alpha[t*N + i] + - TimeSeries scale with scale[t] the scaling at step t + - float -- log_probability of the observation sequence + being produced by the model. """ cdef Py_ssize_t i, j, t, T = len(obs) cdef int N = self.N @@ -1138,19 +1170,19 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return alpha, scale, log_probability cdef TimeSeries _baum_welch_xi(self, TimeSeries alpha, TimeSeries beta, IntList obs): - """ + r""" Used internally to compute the scaled quantity xi_t(i,j) appearing in the Baum-Welch reestimation algorithm. INPUT: - - ``alpha`` -- TimeSeries as output by the scaled forward algorithm - - ``beta`` -- TimeSeries as output by the scaled backward algorithm - - ``obs ``-- IntList of observations + - ``alpha`` -- TimeSeries as output by the scaled forward algorithm + - ``beta`` -- TimeSeries as output by the scaled backward algorithm + - ``obs ``-- IntList of observations OUTPUT: - - TimeSeries xi such that xi[t*N*N + i*N + j] = xi_t(i,j). + - TimeSeries xi such that xi[t*N*N + i*N + j] = xi_t(i,j). """ cdef int i, j, N = self.N cdef double sum @@ -1171,33 +1203,35 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): return xi def baum_welch(self, obs, int max_iter=100, double log_likelihood_cutoff=1e-4, bint fix_emissions=False): - """ + r""" Given an observation sequence obs, improve this HMM using the Baum-Welch algorithm to increase the probability of observing obs. INPUT: - - ``obs`` -- list of emissions + - ``obs`` -- list of emissions - - ``max_iter`` -- integer (default: 100) maximum number - of Baum-Welch steps to take + - ``max_iter`` -- integer (default: 100) maximum number + of Baum-Welch steps to take - - ``log_likelihood_cutoff`` -- positive float (default: 1e-4); - the minimal improvement in likelihood with respect to - the last iteration required to continue. Relative value - to log likelihood. + - ``log_likelihood_cutoff`` -- positive float (default: 1e-4); + the minimal improvement in likelihood with respect to + the last iteration required to continue. Relative value + to log likelihood. - - ``fix_emissions`` -- bool (default: False); if True, do not - change emissions when updating + - ``fix_emissions`` -- bool (default: ``False``); if ``True``, do not + change emissions when updating OUTPUT: - - changes the model in places, and returns the log - likelihood and number of iterations. + changes the model in place, and returns the log + likelihood and number of iterations. EXAMPLES:: - sage: m = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.9,0.1]], [[.5,.5],[0,1]], [.2,.8]) + sage: m = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.9,0.1]], + ....: [[.5,.5],[0,1]], + ....: [.2,.8]) sage: m.baum_welch([1,0]*20, log_likelihood_cutoff=0) (0.0, 4) sage: m # rel tol 1e-14 @@ -1214,7 +1248,9 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): optimizer, i.e., the above model is far more likely to produce the sequence [1,0]*20 than the one we get below:: - sage: m = hmm.DiscreteHiddenMarkovModel([[0.5,0.5],[0.5,0.5]], [[.5,.5],[.5,.5]], [.5,.5]) + sage: m = hmm.DiscreteHiddenMarkovModel([[0.5,0.5],[0.5,0.5]], + ....: [[.5,.5],[.5,.5]], + ....: [.5,.5]) sage: m.baum_welch([1,0]*20, log_likelihood_cutoff=0) (-27.725887222397784, 1) sage: m @@ -1229,14 +1265,18 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): We illustrate fixing emissions:: - sage: m = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.9,0.1]], [[.5,.5],[.2,.8]], [.2,.8]) + sage: m = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.9,0.1]], + ....: [[.5,.5],[.2,.8]], + ....: [.2,.8]) sage: set_random_seed(0); v = m.sample(100) sage: m.baum_welch(v,fix_emissions=True) (-66.98630856918774, 100) sage: m.emission_matrix() [0.5 0.5] [0.2 0.8] - sage: m = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.9,0.1]], [[.5,.5],[.2,.8]], [.2,.8]) + sage: m = hmm.DiscreteHiddenMarkovModel([[0.1,0.9],[0.9,0.1]], + ....: [[.5,.5],[.2,.8]], + ....: [.2,.8]) sage: m.baum_welch(v) (-66.782360659293..., 100) sage: m.emission_matrix() # rel tol 1e-14 @@ -1314,7 +1354,7 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): # Keep this -- it's for backwards compatibility with the GHMM based implementation def unpickle_discrete_hmm_v0(A, B, pi, emission_symbols, name): - """ + r""" TESTS:: sage: m = hmm.DiscreteHiddenMarkovModel([[0.4,0.6],[0.1,0.9]], [[0.0,1.0],[0.5,0.5]], [1,0]) diff --git a/src/sage/stats/hmm/util.pyx b/src/sage/stats/hmm/util.pyx index a5eb8f728d4..553eb997364 100644 --- a/src/sage/stats/hmm/util.pyx +++ b/src/sage/stats/hmm/util.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - numpy """ Hidden Markov Models -- Utility functions @@ -33,13 +34,13 @@ cdef class HMM_Util: INPUT: - - T -- a TimeSeries - - i -- nonnegative integer - - j -- nonnegative integer + - ``T`` -- a :class:`TimeSeries` + - ``i`` -- nonnegative integer + - ``j`` -- nonnegative integer OUTPUT: - - T is modified + - ``T`` is modified EXAMPLES:: @@ -92,14 +93,15 @@ cdef class HMM_Util: INPUT: - - pi -- vector, list, or TimeSeries - - normalize -- if True, replace negative entries by 0 and - rescale to ensure that the sum of the entries in each row is - equal to 1. If the sum of the entries in a row is 0, replace them - all by 1/N. + - ``pi`` -- vector, list, or :class:`TimeSeries` + - ``normalize`` -- if ``True``, replace negative entries by 0 and + rescale to ensure that the sum of the entries in each row is + equal to 1. If the sum of the entries in a row is 0, replace them + all by `1/N`. OUTPUT: - - a TimeSeries of length N + + - a :class:`TimeSeries` of length `N` EXAMPLES:: @@ -125,22 +127,22 @@ cdef class HMM_Util: cpdef TimeSeries state_matrix_to_TimeSeries(self, A, int N, bint normalize): """ - This function is used internally by the __init__ methods of - Hidden Markov Models to make a transition matrix from A. + This function is used internally by the ``__init__`` methods of + Hidden Markov Models to make a transition matrix from ``A``. INPUT: - - A -- matrix, list, list of lists, or TimeSeries - - N -- number of states - - normalize -- if True, replace negative entries by 0 and - rescale to ensure that the sum of the entries in each row is - equal to 1. If the sum of the entries in a row is 0, replace them - all by 1/N. + - ``A`` -- matrix, list, list of lists, or :class:`TimeSeries` + - ``N`` -- number of states + - ``normalize`` -- if ``True``, replace negative entries by 0 and + rescale to ensure that the sum of the entries in each row is + equal to 1. If the sum of the entries in a row is 0, replace them + all by `1/N`. OUTPUT: - - a TimeSeries + - a :class:`TimeSeries` EXAMPLES:: diff --git a/src/sage/stats/intlist.pyx b/src/sage/stats/intlist.pyx index f29d6519d97..1bfc74aed96 100644 --- a/src/sage/stats/intlist.pyx +++ b/src/sage/stats/intlist.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - numpy """ C Int Lists @@ -150,7 +151,7 @@ cdef class IntList: return rich_to_bool(op, -1 if c < 0 else 1) return rich_to_bool(op, 0) - def __dealloc__(self): + def __dealloc__(self): """ Deallocate memory used by the IntList, if it was allocated. """ @@ -306,7 +307,7 @@ cdef class IntList: def list(self): """ - Return Python list version of self with Python ints as entries. + Return Python list version of ``self`` with Python ints as entries. EXAMPLES:: @@ -324,7 +325,7 @@ cdef class IntList: cpdef int sum(self): """ - Return the sum of the entries of self. + Return the sum of the entries of ``self``. EXAMPLES:: @@ -348,7 +349,7 @@ cdef class IntList: cpdef int prod(self): """ - Return the product of the entries of self. + Return the product of the entries of ``self``. EXAMPLES:: @@ -416,18 +417,18 @@ cdef class IntList: def min(self, bint index=False): """ Return the smallest value in this integer list. If this - series has length 0 we raise a ValueError. + series has length 0 we raise a :class:`ValueError`. INPUT: - - index -- bool (default: False); if True, also return - index of minimal entry. + - ``index`` -- bool (default: ``False``); if ``True``, also return + index of minimal entry. OUTPUT: - - float -- smallest value - - integer -- index of smallest value; only returned if - index=True + - float -- smallest value + - integer -- index of smallest value; only returned if + ``index=True`` EXAMPLES:: @@ -454,17 +455,17 @@ cdef class IntList: def max(self, bint index=False): """ Return the largest value in this time series. If this series - has length 0 we raise a ValueError + has length 0 we raise a :class:`ValueError` INPUT: - - index -- bool (default: False); if True, also return - index of maximum entry. + - ``index`` -- bool (default: ``False``); if ``True``, also return + index of maximum entry. OUTPUT: - - int -- largest value - - int -- index of largest value; only returned if index=True + - int -- largest value + - int -- index of largest value; only returned if ``index=True`` EXAMPLES:: @@ -489,7 +490,7 @@ cdef class IntList: def time_series(self): """ - Return TimeSeries version of self, which involves changing + Return :class:`TimeSeries` version of ``self``, which involves changing each entry to a double. EXAMPLES:: @@ -511,28 +512,33 @@ cdef class IntList: def plot(self, *args, **kwds): """ - Return a plot of this IntList. This just constructs the - corresponding double-precision floating point TimeSeries + Return a plot of this :class:`IntList`. + + This just constructs the + corresponding double-precision floating point :class:`TimeSeries` object, passing on all arguments. EXAMPLES:: - sage: stats.IntList([3,7,19,-2]).plot() + sage: stats.IntList([3,7,19,-2]).plot() # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: stats.IntList([3,7,19,-2]).plot(color='red',pointsize=50,points=True) + sage: stats.IntList([3,7,19,-2]).plot(color='red', # needs sage.plot + ....: pointsize=50, points=True) Graphics object consisting of 1 graphics primitive """ return self.time_series().plot(*args, **kwds) def plot_histogram(self, *args, **kwds): """ - Return a histogram plot of this IntList. This just constructs - the corresponding double-precision floating point TimeSeries object, + Return a histogram plot of this :class:`IntList`. + + This just constructs + the corresponding double-precision floating point :class:`TimeSeries` object, and plots it, passing on all arguments. EXAMPLES:: - sage: stats.IntList([1..15]).plot_histogram() + sage: stats.IntList([1..15]).plot_histogram() # needs sage.plot Graphics object consisting of 50 graphics primitives """ return self.time_series().plot_histogram(*args, **kwds) diff --git a/src/sage/stats/r.py b/src/sage/stats/r.py index 5d644b7f54e..47f492eff61 100644 --- a/src/sage/stats/r.py +++ b/src/sage/stats/r.py @@ -26,18 +26,18 @@ def ttest(x, y, conf_level=0.95, **kw): """ T-Test using R - Arguments: + INPUT: - - x, y -- vectors of same length + - ``x``, ``y`` -- vectors of same length - conf_level -- confidence level of the interval, [0,1) in percent - Result: + OUTPUT: Tuple: (p-value, R return object) EXAMPLES:: - sage: a, b = ttest([1,2,3,4,5],[1,2,3,3.5,5.121]); a # abs tol 1e-12 # optional - rpy2 + sage: a, b = ttest([1,2,3,4,5],[1,2,3,3.5,5.121]); a # abs tol 1e-12 # optional - rpy2 0.9410263720274274 """ if len(x) != len(y): diff --git a/src/sage/stats/time_series.pyx b/src/sage/stats/time_series.pyx index dda5f533792..4a0e9f868db 100644 --- a/src/sage/stats/time_series.pyx +++ b/src/sage/stats/time_series.pyx @@ -1,4 +1,5 @@ -""" +# sage.doctest: optional - numpy +r""" Time Series This is a module for working with discrete floating point time series. @@ -36,19 +37,19 @@ AUTHOR: - William Stein """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 William Stein <wstein@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** cimport cython from cpython.bytes cimport PyBytes_FromStringAndSize, PyBytes_AsString -from libc.math cimport exp, floor, log, pow, sqrt +from libc.math cimport exp, log, pow, sqrt from libc.string cimport memcpy from cysignals.memory cimport sig_malloc, sig_free from sage.structure.richcmp cimport rich_to_bool @@ -66,7 +67,7 @@ digits = 4 cdef class TimeSeries: def __cinit__(self): - """ + r""" Create new empty uninitialized time series. EXAMPLES: @@ -79,7 +80,7 @@ cdef class TimeSeries: self._values = NULL def __init__(self, values, bint initialize=True): - """ + r""" Initialize new time series. INPUT: @@ -96,7 +97,7 @@ cdef class TimeSeries: This implicitly calls init:: - sage: stats.TimeSeries([pi, 3, 18.2]) + sage: stats.TimeSeries([pi, 3, 18.2]) # needs sage.symbolic [3.1416, 3.0000, 18.2000] Conversion from a NumPy 1-D array, which is very fast:: @@ -171,7 +172,7 @@ cdef class TimeSeries: self._values[i] = 0 def __reduce__(self): - """ + r""" Used in pickling time series. EXAMPLES:: @@ -193,7 +194,7 @@ cdef class TimeSeries: return unpickle_time_series_v1, (buf, self._length) def __richcmp__(TimeSeries self, other, int op): - """ + r""" Compare ``self`` and ``other``. This has the same semantics as list comparison. @@ -223,8 +224,8 @@ cdef class TimeSeries: return rich_to_bool(op, -1 if c < 0 else 1) return rich_to_bool(op, 0) - def __dealloc__(self): - """ + def __dealloc__(self): + r""" Free up memory used by a time series. EXAMPLES: @@ -237,7 +238,7 @@ cdef class TimeSeries: sig_free(self._values) def vector(self): - """ + r""" Return real double vector whose entries are the values of this time series. This is useful since vectors have standard algebraic structure and play well with matrices. @@ -258,7 +259,7 @@ cdef class TimeSeries: return x def __repr__(self): - """ + r""" Return string representation of ``self``. EXAMPLES:: @@ -282,7 +283,7 @@ cdef class TimeSeries: return self._repr() def _repr(self, prec=None): - """ + r""" Print representation of a time series. INPUT: @@ -316,7 +317,7 @@ cdef class TimeSeries: return '[' + ', '.join(format%x for x in self) + ']' def __len__(self): - """ + r""" Return the number of entries in this time series. OUTPUT: @@ -334,8 +335,8 @@ cdef class TimeSeries: return self._length def __getitem__(self, i): - """ - Return i-th entry or slice of ``self``. + r""" + Return `i`-th entry or slice of ``self``. EXAMPLES:: @@ -420,14 +421,14 @@ cdef class TimeSeries: return self._values[j] def __setitem__(self, Py_ssize_t i, double x): - """ - Set the i-th entry of ``self`` to ``x``. + r""" + Set the `i`-th entry of ``self`` to ``x``. INPUT: - - i -- a nonnegative integer. + - ``i`` -- a nonnegative integer. - - x -- a float. + - ``x`` -- a float. EXAMPLES:: @@ -455,7 +456,7 @@ cdef class TimeSeries: self._values[i] = x def __copy__(self): - """ + r""" Return a copy of ``self``. EXAMPLES:: @@ -474,7 +475,7 @@ cdef class TimeSeries: return t def __add__(left, right): - """ + r""" Concatenate the time series ``self`` and ``right``. .. NOTE:: @@ -522,7 +523,7 @@ cdef class TimeSeries: return t def __mul__(left, right): - """ + r""" Multiply a time series by an integer n, which (like for lists) results in the time series concatenated with itself n times. @@ -624,9 +625,9 @@ cdef class TimeSeries: return autoregressive_fit(acvs) def autoregressive_forecast(self, filter): - """ + r""" Given the autoregression coefficients as outputted by the - ``autoregressive_fit`` command, compute the forecast for the next + :meth:`autoregressive_fit` command, compute the forecast for the next term in the series. INPUT: @@ -658,7 +659,7 @@ cdef class TimeSeries: return f def reversed(self): - """ + r""" Return new time series obtain from this time series by reversing the order of the entries in this time series. @@ -680,7 +681,7 @@ cdef class TimeSeries: return t def extend(self, right): - """ + r""" Extend this time series by appending elements from the iterable ``right``. @@ -711,7 +712,7 @@ cdef class TimeSeries: self._length = self._length + T._length def list(self): - """ + r""" Return list of elements of ``self``. EXAMPLES:: @@ -724,7 +725,7 @@ cdef class TimeSeries: return [self._values[i] for i in range(self._length)] def log(self): - """ + r""" Return new time series got by taking the logarithms of all the terms in the time series. @@ -756,7 +757,7 @@ cdef class TimeSeries: return t def exp(self): - """ + r""" Return new time series got by applying the exponential map to all the terms in the time series. @@ -780,7 +781,7 @@ cdef class TimeSeries: return t def abs(self): - """ + r""" Return new time series got by replacing all entries of ``self`` by their absolute value. @@ -892,7 +893,7 @@ cdef class TimeSeries: return t cpdef rescale(self, double s): - """ + r""" Change ``self`` by multiplying every value in the series by ``s``. INPUT: @@ -911,7 +912,7 @@ cdef class TimeSeries: self._values[i] = self._values[i] * s def scale(self, double s): - """ + r""" Return new time series obtained by multiplying every value in the series by ``s``. @@ -936,13 +937,13 @@ cdef class TimeSeries: return t def add_scalar(self, double s): - """ + r""" Return new time series obtained by adding a scalar to every value in the series. .. NOTE:: - To add componentwise, use the ``add_entries`` method. + To add componentwise, use the :meth:`add_entries` method. INPUT: @@ -965,7 +966,7 @@ cdef class TimeSeries: return t def add_entries(self, t): - """ + r""" Add corresponding entries of ``self`` and ``t`` together, extending either ``self`` or ``t`` by 0's if they do not have the same length. @@ -981,7 +982,7 @@ cdef class TimeSeries: OUTPUT: - A time series with length the maxima of the lengths of + A time series with length the maximum of the lengths of ``self`` and ``t``. EXAMPLES:: @@ -1022,22 +1023,25 @@ cdef class TimeSeries: return v def show(self, *args, **kwds): - """ - Calls plot and passes all arguments onto the plot function. This is - thus just an alias for plot. + r""" + Return a plot of this time series. + + This is an alias of :meth:`plot`. EXAMPLES: Draw a plot of a time series:: - sage: stats.TimeSeries([1..10]).show() + sage: stats.TimeSeries([1..10]).show() # needs sage.plot Graphics object consisting of 1 graphics primitive """ return self.plot(*args, **kwds) def plot(self, Py_ssize_t plot_points=1000, points=False, **kwds): r""" - Return a plot of this time series as a line or points through + Return a plot of this time series. + + The plot shows a line or points through `(i,T(i))`, where `i` ranges over nonnegative integers up to the length of ``self``. @@ -1054,6 +1058,7 @@ cdef class TimeSeries: EXAMPLES:: + sage: # needs sage.plot sage: v = stats.TimeSeries([5,4,1.3,2,8,10,3,-5]); v [5.0000, 4.0000, 1.3000, 2.0000, 8.0000, 10.0000, 3.0000, -5.0000] sage: v.plot() @@ -1088,12 +1093,13 @@ cdef class TimeSeries: return L def simple_moving_average(self, Py_ssize_t k): - """ - Return the moving average time series over the last ``k`` time units. + r""" + Return the moving average time series over the last `k` time units. + Assumes the input time series was constant with its starting value - for negative time. The t-th step of the output is the sum of - the previous ``k - 1`` steps of ``self`` and the ``k``-th step - divided by ``k``. Thus ``k`` values are averaged at each point. + for negative time. The `t`-th step of the output is the sum of + the previous `k - 1` steps of ``self`` and the `k`-th step + divided by `k`. Thus `k` values are averaged at each point. INPUT: @@ -1138,11 +1144,13 @@ cdef class TimeSeries: return t def exponential_moving_average(self, double alpha): - """ - Return the exponential moving average time series. Assumes - the input time series was constant with its starting value for - negative time. The t-th step of the output is the sum of the - previous k-1 steps of ``self`` and the k-th step divided by k. + r""" + Return the exponential moving average time series. + + Assumes the input time series was constant with its starting + value for negative time. The `t`-th step of the output is the + sum of the previous `k-1` steps of ``self`` and the `k`-th + step divided by `k`. The 0-th term is formally undefined, so we define it to be 0, and we define the first term to be ``self[0]``. @@ -1189,7 +1197,7 @@ cdef class TimeSeries: return t def sums(self, double s=0): - """ + r""" Return the new time series got by taking the running partial sums of the terms of this time series. @@ -1216,9 +1224,10 @@ cdef class TimeSeries: return t cpdef double sum(self): - """ - Return the sum of all the entries of ``self``. If ``self`` has - length 0, returns 0. + r""" + Return the sum of all the entries of ``self``. + + If ``self`` has length 0, returns 0. OUTPUT: @@ -1238,9 +1247,10 @@ cdef class TimeSeries: return s def prod(self): - """ - Return the product of all the entries of ``self``. If ``self`` has - length 0, returns 1. + r""" + Return the product of all the entries of ``self``. + + If ``self`` has length 0, returns 1. OUTPUT: @@ -1261,7 +1271,7 @@ cdef class TimeSeries: def mean(self): - """ + r""" Return the mean (average) of the elements of ``self``. OUTPUT: @@ -1278,9 +1288,9 @@ cdef class TimeSeries: return self.sum() / self._length def pow(self, double k): - """ - Return a new time series with every elements of ``self`` raised to the - k-th power. + r""" + Return a new time series with all elements of ``self`` raised to the + `k`-th power. INPUT: @@ -1304,9 +1314,9 @@ cdef class TimeSeries: return t def moment(self, int k): - """ - Return the k-th moment of ``self``, which is just the - mean of the k-th powers of the elements of ``self``. + r""" + Return the `k`-th moment of ``self``, which is just the + mean of the `k`-th powers of the elements of ``self``. INPUT: @@ -1336,9 +1346,9 @@ cdef class TimeSeries: return s / self._length def central_moment(self, int k): - """ - Return the k-th central moment of ``self``, which is just the mean - of the k-th powers of the differences ``self[i] - mu``, where ``mu`` is + r""" + Return the `k`-th central moment of ``self``, which is just the mean + of the `k`-th powers of the differences ``self[i] - mu``, where ``mu`` is the mean of ``self``. INPUT: @@ -1405,7 +1415,8 @@ cdef class TimeSeries: def autocovariance(self, Py_ssize_t k=0): r""" - Return the k-th autocovariance function `\gamma(k)` of ``self``. + Return the `k`-th autocovariance function `\gamma(k)` of ``self``. + This is the covariance of ``self`` with ``self`` shifted by `k`, i.e., .. MATH:: @@ -1436,7 +1447,8 @@ cdef class TimeSeries: 14.4 sage: v.autocovariance(1) -2.7 - sage: mu = v.mean(); sum([(v[i]-mu)*(v[i+1]-mu) for i in range(len(v)-1)])/len(v) + sage: mu = v.mean() + sage: sum((v[i]-mu)*(v[i+1]-mu) for i in range(len(v)-1))/len(v) -2.7 sage: v.autocovariance(1) -2.7 @@ -1449,7 +1461,8 @@ cdef class TimeSeries: sage: set_random_seed(0) sage: v = stats.TimeSeries(10^6) sage: v.randomize('normal', 0, 5) - [3.3835, -2.0055, 1.7882, -2.9319, -4.6827 ... -5.1868, 9.2613, 0.9274, -6.2282, -8.7652] + [3.3835, -2.0055, 1.7882, -2.9319, -4.6827 ... + -5.1868, 9.2613, 0.9274, -6.2282, -8.7652] sage: v.autocovariance(0) 24.95410689... sage: v.autocovariance(1) @@ -1468,7 +1481,7 @@ cdef class TimeSeries: return s / self._length def correlation(self, TimeSeries other): - """ + r""" Return the correlation of ``self`` and ``other``, which is the covariance of ``self`` and ``other`` divided by the product of their standard deviation. @@ -1491,7 +1504,7 @@ cdef class TimeSeries: def autocorrelation(self, Py_ssize_t k=1): r""" - Return the k-th sample autocorrelation of this time series + Return the `k`-th sample autocorrelation of this time series `x_i`. Let `\mu` be the sample mean. Then the sample autocorrelation @@ -1503,7 +1516,7 @@ cdef class TimeSeries: {\sum_{t=0}^{n-1} (x_t - \mu)^2}. Note that the variance must be nonzero or you will get a - ``ZeroDivisionError``. + :class:`ZeroDivisionError`. INPUT: @@ -1533,7 +1546,7 @@ cdef class TimeSeries: return self.autocovariance(k) / self.variance(bias=True) def variance(self, bias=False): - """ + r""" Return the variance of the elements of ``self``, which is the mean of the squares of the differences from the mean. @@ -1578,7 +1591,7 @@ cdef class TimeSeries: return s / (self._length - 1) def standard_deviation(self, bias=False): - """ + r""" Return the standard deviation of the entries of ``self``. INPUT: @@ -1617,7 +1630,7 @@ cdef class TimeSeries: statistics of disjoint blocks of size ``b``. Let `\sigma` be the standard deviation of the sequence of - differences of ``self``, and let `Y_k` be the k-th term of ``self``. + differences of ``self``, and let `Y_k` be the `k`-th term of ``self``. Let `n` be the number of terms of ``self``, and set `Z_k = Y_k - ((k+1)/n) \cdot Y_n`. Then @@ -1668,7 +1681,7 @@ cdef class TimeSeries: return (Z.max() - Z.min()) / sigma def hurst_exponent(self): - """ + r""" Return an estimate of the Hurst exponent of this time series. We use the algorithm from pages 61 -- 63 of [Peteres, Fractal @@ -1684,47 +1697,10 @@ cdef class TimeSeries: sage: set_random_seed(0) sage: bm = stats.TimeSeries(10^5).randomize('normal').sums(); bm - [0.6767, 0.2756, 0.6332, 0.0469, -0.8897 ... 152.2437, 151.5327, 152.7629, 152.9169, 152.9084] + [0.6767, 0.2756, 0.6332, 0.0469, -0.8897 ... + 152.2437, 151.5327, 152.7629, 152.9169, 152.9084] sage: bm.hurst_exponent() 0.527450972... - - We compute the Hurst exponent of a simulated fractional Brownian - motion with Hurst parameter 0.7. This function estimates the - Hurst exponent as 0.706511951... :: - - sage: set_random_seed(0) - sage: import sage.finance.all as finance - doctest:warning... - DeprecationWarning: the package sage.finance is deprecated - See https://github.com/sagemath/sage/issues/32427 for details. - sage: fbm = finance.fractional_brownian_motion_simulation(0.7,0.1,10^5,1)[0] - sage: fbm.hurst_exponent() - 0.706511951... - - Another example with small Hurst exponent (notice the overestimation). - - :: - - sage: fbm = finance.fractional_brownian_motion_simulation(0.2,0.1,10^5,1)[0] - sage: fbm.hurst_exponent() - 0.278997441... - - We compute the mean Hurst exponent of 100 simulated multifractal - cascade random walks:: - - sage: set_random_seed(0) - sage: y = finance.multifractal_cascade_random_walk_simulation(3700,0.02,0.01,0.01,1000,100) - sage: stats.TimeSeries([z.hurst_exponent() for z in y]).mean() - 0.57984822577934... - - We compute the mean Hurst exponent of 100 simulated Markov switching - multifractal time series. The Hurst exponent is quite small. :: - - sage: set_random_seed(0) - sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,0.5,0.95,3) - sage: y = msm.simulations(1000,100) - sage: stats.TimeSeries([z.hurst_exponent() for z in y]).mean() - 0.286102325623705... """ # We use disjoint blocks of size 8, 16, 32, .... cdef Py_ssize_t k = 8 @@ -1748,7 +1724,7 @@ cdef class TimeSeries: return coeffs[0] def min(self, bint index=False): - """ + r""" Return the smallest value in this time series. If this series has length 0 we raise a ``ValueError``. @@ -1786,9 +1762,9 @@ cdef class TimeSeries: return s def max(self, bint index=False): - """ + r""" Return the largest value in this time series. If this series - has length 0 we raise a ``ValueError``. + has length 0 we raise a :class:`ValueError`. INPUT: @@ -1823,7 +1799,7 @@ cdef class TimeSeries: return s def clip_remove(self, min=None, max=None): - """ + r""" Return new time series obtained from ``self`` by removing all values that are less than or equal to a certain minimum value or greater than or equal to a certain maximum. @@ -1901,7 +1877,7 @@ cdef class TimeSeries: return t def histogram(self, Py_ssize_t bins=50, bint normalize=False): - """ + r""" Return the frequency histogram of the values in this time series divided up into the given number of bins. @@ -1970,7 +1946,7 @@ cdef class TimeSeries: return counts, v def plot_histogram(self, bins=50, normalize=True, **kwds): - """ + r""" Return histogram plot of this time series with given number of bins. INPUT: @@ -1987,12 +1963,12 @@ cdef class TimeSeries: EXAMPLES:: sage: v = stats.TimeSeries([1..50]) - sage: v.plot_histogram(bins=10) + sage: v.plot_histogram(bins=10) # needs sage.plot Graphics object consisting of 10 graphics primitives :: - sage: v.plot_histogram(bins=3,normalize=False,aspect_ratio=1) + sage: v.plot_histogram(bins=3,normalize=False,aspect_ratio=1) # needs sage.plot Graphics object consisting of 3 graphics primitives """ from sage.plot.all import polygon @@ -2006,7 +1982,7 @@ cdef class TimeSeries: return s def plot_candlestick(self, int bins=30): - """ + r""" Return a candlestick plot of this time series with the given number of bins. @@ -2031,7 +2007,7 @@ cdef class TimeSeries: Here we look at the candlestick plot for Brownian motion:: sage: v = stats.TimeSeries(1000).randomize() - sage: v.plot_candlestick(bins=20) + sage: v.plot_candlestick(bins=20) # needs sage.plot Graphics object consisting of 40 graphics primitives """ from sage.plot.all import line, polygon, Graphics @@ -2066,7 +2042,7 @@ cdef class TimeSeries: return p def numpy(self, copy=True): - """ + r""" Return a NumPy version of this time series. .. NOTE:: @@ -2226,7 +2202,7 @@ cdef class TimeSeries: return self def _randomize_uniform(self, double left, double right): - """ + r""" Generates a uniform random distribution of doubles between ``left`` and ``right`` and stores values in place. @@ -2263,7 +2239,7 @@ cdef class TimeSeries: self._values[k] = rstate.c_rand_double() * d + left def _randomize_normal(self, double m, double s): - """ + r""" Generates a normal random distribution of doubles with mean ``m`` and standard deviation ``s`` and stores values in place. Uses the Box-Muller algorithm. @@ -2320,7 +2296,7 @@ cdef class TimeSeries: self._values[k] = m + y2*s def _randomize_semicircle(self, double center): - """ + r""" Generates a semicircle random distribution of doubles about center and stores values in place. Uses the acceptance-rejection method. @@ -2394,7 +2370,7 @@ cdef class TimeSeries: sage: v = stats.TimeSeries(10^6) sage: v.randomize('lognormal').mean() 1.647351973... - sage: exp(0.5) + sage: exp(0.5) # needs sage.symbolic 1.648721270... A log-normal distribution can be simply thought of as the logarithm @@ -2538,7 +2514,7 @@ cdef class TimeSeries: cdef new_time_series(Py_ssize_t length): - """ + r""" Return a new uninitialized time series of the given length. The entries of the time series are garbage. @@ -2568,7 +2544,7 @@ cdef new_time_series(Py_ssize_t length): @cython.binding(True) def unpickle_time_series_v1(bytes v, Py_ssize_t n): - """ + r""" Version 1 unpickle method. INPUT: @@ -2607,108 +2583,6 @@ def autoregressive_fit(acvs): `\Gamma a =\gamma`, where `\gamma=(\gamma(1),\dots,\gamma(M))`, `a=(a_1,\dots,a_M)`, with `\gamma(i)` the autocovariance of lag `i` and `\Gamma_{ij}=\gamma(i-j)`. - - EXAMPLES: - - In this example we consider the multifractal cascade random walk - of length 1000, and use simulations to estimate the - expected first few autocovariance parameters for this model, then - use them to construct a linear filter that works vastly better - than a linear filter constructed from the same data but not using - this model. The Monte-Carlo method illustrated below should work for - predicting one "time step" into the future for any - model that can be simulated. To predict k time steps into the - future would require using a similar technique but would require - scaling time by k. - - We create 100 simulations of a multifractal random walk. This - models the logarithms of a stock price sequence. :: - - sage: set_random_seed(0) - sage: import sage.finance.all as finance - sage: y = finance.multifractal_cascade_random_walk_simulation(3700,0.02,0.01,0.01,1000,100) - - For each walk below we replace the walk by the walk but where each - step size is replaced by its absolute value -- this is what we - expect to be able to predict given the model, which is only a - model for predicting volatility. We compute the first 200 - autocovariance values for every random walk:: - - sage: c = [[a.diffs().abs().sums().autocovariance(i) for a in y] for i in range(200)] - - We make a time series out of the expected values of the - autocovariances:: - - sage: ac = stats.TimeSeries([stats.TimeSeries(z).mean() for z in c]) - sage: ac - [3.9962, 3.9842, 3.9722, 3.9601, 3.9481 ... 1.7144, 1.7033, 1.6922, 1.6812, 1.6701] - - .. NOTE:: - - ``ac`` looks like a line -- one could best fit it to yield a lot - more approximate autocovariances. - - We compute the autoregression coefficients matching the above - autocovariances:: - - sage: F = stats.autoregressive_fit(ac); F - [0.9982, -0.0002, -0.0002, 0.0003, 0.0001 ... 0.0002, -0.0002, -0.0000, -0.0002, -0.0014] - - Note that the sum is close to 1:: - - sage: sum(F) - 0.99593284089454... - - Now we make up an 'out of sample' sequence:: - - sage: y2 = finance.multifractal_cascade_random_walk_simulation(3700,0.02,0.01,0.01,1000,1)[0].diffs().abs().sums() - sage: y2 - [0.0013, 0.0059, 0.0066, 0.0068, 0.0184 ... 6.8004, 6.8009, 6.8063, 6.8090, 6.8339] - - And we forecast the very last value using our linear filter; the forecast - is close:: - - sage: y2[:-1].autoregressive_forecast(F) - 6.7836741372407... - - In fact it is closer than we would get by forecasting using a - linear filter made from all the autocovariances of our sequence:: - - sage: y2[:-1].autoregressive_forecast(y2[:-1].autoregressive_fit(len(y2))) - 6.770168705668... - - We record the last 20 forecasts, always using all correct values up to the - one we are forecasting:: - - sage: s1 = sum([(y2[:-i].autoregressive_forecast(F)-y2[-i])^2 for i in range(1,20)]) - - We do the same, but using the autocovariances of the sample sequence:: - - sage: F2 = y2[:-100].autoregressive_fit(len(F)) - sage: s2 = sum([(y2[:-i].autoregressive_forecast(F2)-y2[-i])^2 for i in range(1,20)]) - - Our model gives us something that is 15 percent better in this case:: - - sage: s2/s1 - 1.15464636102... - - How does it compare overall? To find out we do 100 simulations - and for each we compute the percent that our model beats naively - using the autocovariances of the sample:: - - sage: y_out = finance.multifractal_cascade_random_walk_simulation(3700,0.02,0.01,0.01,1000,100) - sage: s1 = []; s2 = [] - sage: for v in y_out: - ....: s1.append(sum([(v[:-i].autoregressive_forecast(F)-v[-i])^2 for i in range(1,20)])) - ....: F2 = v[:-len(F)].autoregressive_fit(len(F)) - ....: s2.append(sum([(v[:-i].autoregressive_forecast(F2)-v[-i])^2 for i in range(1,20)])) - - We find that overall the model beats naive linear forecasting by 35 - percent! :: - - sage: s = stats.TimeSeries([s2[i]/s1[i] for i in range(len(s1))]) - sage: s.mean() - 1.354073591877... """ cdef TimeSeries c cdef Py_ssize_t i diff --git a/src/sage/structure/category_object.pxd b/src/sage/structure/category_object.pxd index ff3088ae9b6..83d3d4967d4 100644 --- a/src/sage/structure/category_object.pxd +++ b/src/sage/structure/category_object.pxd @@ -13,7 +13,7 @@ from sage.structure.sage_object cimport SageObject cpdef check_default_category(default_category, category) cdef class CategoryObject(SageObject): - cdef public dict __cached_methods + cdef public dict _cached_methods cdef _category cdef public _base cdef public _names diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index 52abd7d918b..b6a7eaecb5b 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -36,6 +36,7 @@ This example illustrates generators for a free module over `\ZZ`. :: + sage: # needs sage.modules sage: M = FreeModule(ZZ, 4) sage: M Ambient free module of rank 4 over the principal ideal domain Integer Ring @@ -47,18 +48,17 @@ This example illustrates generators for a free module over `\ZZ`. ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)) """ -#***************************************************************************** +# **************************************************************************** # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.cpython.getattr import dir_with_other_class from sage.cpython.getattr cimport getattr_from_other_class from sage.categories.category import Category -from sage.structure.debug_options cimport debug from sage.misc.cachefunc import cached_method from sage.structure.dynamic_class import DynamicMetaclass @@ -113,7 +113,7 @@ cdef class CategoryObject(SageObject): self._init_category_(category) def __cinit__(self): - self.__cached_methods = {} + self._cached_methods = {} self._hash_value = -1 def _init_category_(self, category): @@ -189,7 +189,7 @@ cdef class CategoryObject(SageObject): if self._category is None: self._init_category_(category) return - if not (type(category) == tuple or type(category) == list): + if not isinstance(category, (tuple, list)): category = [category] self._category = self._category.join([self._category]+list(category)) @@ -271,8 +271,8 @@ cdef class CategoryObject(SageObject): EXAMPLES:: - sage: B.<a,b,c,d> = BooleanPolynomialRing() - sage: B.gens_dict() + sage: B.<a,b,c,d> = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: B.gens_dict() # needs sage.rings.polynomial.pbori {'a': a, 'b': b, 'c': c, 'd': d} TESTS:: @@ -352,16 +352,16 @@ cdef class CategoryObject(SageObject): For orders, we correctly use the ring generator, see :trac:`15348`:: - sage: A.<i> = ZZ.extension(x^2 + 1) - sage: i + sage: A.<i> = ZZ.extension(x^2 + 1) # needs sage.rings.number_field + sage: i # needs sage.rings.number_field i - sage: parent(i) + sage: parent(i) # needs sage.rings.number_field Order in Number Field in i with defining polynomial x^2 + 1 :: - sage: B.<z> = EquationOrder(x^2 + 3) - sage: z.minpoly() + sage: B.<z> = EquationOrder(x^2 + 3) # needs sage.rings.number_field + sage: z.minpoly() # needs sage.rings.number_field x^2 + 3 """ return self._defining_names()[:n] @@ -389,13 +389,14 @@ cdef class CategoryObject(SageObject): For orders, we correctly use the ring generator, see :trac:`15348`:: - sage: B.<z> = EquationOrder(x^2 + 3) - sage: B._defining_names() + sage: B.<z> = EquationOrder(x^2 + 3) # needs sage.rings.number_field + sage: B._defining_names() # needs sage.rings.number_field (z,) For vector spaces and free modules, we get a basis (which can be different from the given generators):: + sage: # needs sage.modules sage: V = ZZ^3 sage: V._defining_names() ((1, 0, 0), (0, 1, 0), (0, 0, 1)) @@ -490,7 +491,7 @@ cdef class CategoryObject(SageObject): """ return self.variable_names()[0] - def __temporarily_change_names(self, names, latex_names): + def _temporarily_change_names(self, names, latex_names): """ This is used by the variable names context manager. @@ -501,8 +502,9 @@ cdef class CategoryObject(SageObject): wants to print elements of the quotient of such an "unnamed" ring, an error resulted. That was fixed in :trac:`11068`:: - sage: MS = MatrixSpace(GF(5),2,2) - sage: I = MS*[MS.0*MS.1,MS.2+MS.3]*MS + sage: # needs sage.modules + sage: MS = MatrixSpace(GF(5), 2, 2) + sage: I = MS * [MS.0*MS.1, MS.2 + MS.3] * MS sage: Q.<a,b,c,d> = MS.quo(I) sage: a #indirect doctest [1 0] @@ -567,15 +569,16 @@ cdef class CategoryObject(SageObject): sage: Module(ZZ).base_ring() Integer Ring - sage: F = FreeModule(ZZ,3) - sage: F.base_ring() + sage: F = FreeModule(ZZ, 3) # needs sage.modules + sage: F.base_ring() # needs sage.modules Integer Ring - sage: F.__class__.base_ring + sage: F.__class__.base_ring # needs sage.modules <method 'base_ring' of 'sage.structure.category_object.CategoryObject' objects> Note that the coordinates of the elements of a module can lie in a bigger ring, the ``coordinate_ring``:: + sage: # needs sage.modules sage: M = (ZZ^2) * (1/2) sage: v = M([1/2, 0]) sage: v.base_ring() @@ -587,12 +590,13 @@ cdef class CategoryObject(SageObject): More examples:: - sage: F = FreeAlgebra(QQ, 'x') - sage: F.base_ring() + sage: F = FreeAlgebra(QQ, 'x') # needs sage.combinat sage.modules + sage: F.base_ring() # needs sage.combinat sage.modules Rational Field - sage: F.__class__.base_ring + sage: F.__class__.base_ring # needs sage.combinat sage.modules <method 'base_ring' of 'sage.structure.category_object.CategoryObject' objects> + sage: # needs sage.modules sage: E = CombinatorialFreeModule(ZZ, [1,2,3]) sage: F = CombinatorialFreeModule(ZZ, [2,3,4]) sage: H = Hom(E, F) @@ -627,7 +631,9 @@ cdef class CategoryObject(SageObject): sage: R.<x,y> = PolynomialRing(QQ, 2) sage: R.Hom(QQ) - Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Rational Field + Set of Homomorphisms + from Multivariate Polynomial Ring in x, y over Rational Field + to Rational Field Homspaces are defined for very general Sage objects, even elements of familiar rings. @@ -635,7 +641,7 @@ cdef class CategoryObject(SageObject): sage: n = 5; Hom(n,7) Set of Morphisms from 5 to 7 in Category of elements of Integer Ring - sage: z=(2/3); Hom(z,8/1) + sage: z = 2/3; Hom(z, 8/1) Set of Morphisms from 2/3 to 8 in Category of elements of Rational Field This example illustrates the optional third argument:: @@ -663,12 +669,13 @@ cdef class CategoryObject(SageObject): sage: x (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) sage: R.latex_variable_names () - ['x_{0}', 'x_{1}', 'x_{2}', 'x_{3}', 'x_{4}', 'x_{5}', 'x_{6}', 'x_{7}', 'x_{8}', 'x_{9}', 'x_{10}', 'x_{11}'] + ['x_{0}', 'x_{1}', 'x_{2}', 'x_{3}', 'x_{4}', 'x_{5}', 'x_{6}', + 'x_{7}', 'x_{8}', 'x_{9}', 'x_{10}', 'x_{11}'] sage: f = x[0]^3 + 15/3 * x[1]^10 sage: print(latex(f)) 5 x_{1}^{10} + x_{0}^{3} """ - from sage.misc.latex import latex, latex_variable_name + from sage.misc.latex import latex_variable_name try: names = self._latex_names if names is not None: @@ -676,7 +683,8 @@ cdef class CategoryObject(SageObject): except AttributeError: pass # Compute the latex versions of the variable names. - self._latex_names = [latex_variable_name(x) for x in self.variable_names()] + self._latex_names = [latex_variable_name(x) + for x in self.variable_names()] return self._latex_names def latex_name(self): @@ -836,7 +844,7 @@ cdef class CategoryObject(SageObject): # Lookup a method or attribute from the category abstract classes. # See __getattr__ above for documentation. try: - return self.__cached_methods[name] + return self._cached_methods[name] except KeyError: if self._category is None: # Usually, this will just raise AttributeError in @@ -846,7 +854,7 @@ cdef class CategoryObject(SageObject): cls = self._category.parent_class attr = getattr_from_other_class(self, cls, name) - self.__cached_methods[name] = attr + self._cached_methods[name] = attr return attr def __dir__(self): @@ -890,8 +898,8 @@ cdef class CategoryObject(SageObject): _test_some_elements _test_zero _test_zero_divisors - sage: F = GF(9,'a') - sage: dir(F) + sage: F = GF(9,'a') # needs sage.rings.finite_rings + sage: dir(F) # needs sage.rings.finite_rings [..., '__class__', ..., '_test_pickling', ..., 'extension', ...] """ @@ -947,11 +955,11 @@ cpdef normalize_names(Py_ssize_t ngens, names): sage: nn(1, u'a') ('a',) - sage: var('alpha') + sage: var('alpha') # needs sage.symbolic alpha - sage: nn(2, alpha) + sage: nn(2, alpha) # needs sage.symbolic ('alpha0', 'alpha1') - sage: nn(1, [alpha]) + sage: nn(1, [alpha]) # needs sage.symbolic ('alpha',) With an unknown number of generators:: @@ -1004,7 +1012,7 @@ cpdef normalize_names(Py_ssize_t ngens, names): names = tuple(names) except ValueError: pass - if isinstance(names, basestring): + if isinstance(names, str): if ngens < 0: names = [names] else: diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 86664258c8c..d8c3f684217 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -21,23 +21,23 @@ there. For example:: Rational Field sage: b = ZZ['x'].gen(); b.parent() Univariate Polynomial Ring in x over Integer Ring - sage: a+b + sage: a + b x + 1/2 - sage: (a+b).parent() + sage: (a + b).parent() Univariate Polynomial Ring in x over Rational Field If there is a coercion (see below) from one of the parents to the other, the operation is always performed in the codomain of that coercion. Otherwise a reasonable attempt to create a new parent with coercion maps from both original parents is made. The results of these discoveries are cached. -On failure, a TypeError is always raised. +On failure, a :class:`TypeError` is always raised. Some arithmetic operations (such as multiplication) can indicate an action rather than arithmetic in a common parent. For example:: - sage: E = EllipticCurve('37a') - sage: P = E(0,0) - sage: 5*P + sage: E = EllipticCurve('37a') # needs sage.schemes + sage: P = E(0,0) # needs sage.schemes + sage: 5*P # needs sage.schemes (1/4 : -5/8 : 1) where there is action of `\ZZ` on the points of `E` given by the additive @@ -64,36 +64,35 @@ For more information on how to specify coercions, conversions, and actions, see the documentation for :class:`Parent`. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Robert Bradshaw <robertwb@math.washington.edu> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -from cpython.object cimport (PyObject, PyTypeObject, - PyObject_CallObject, PyObject_RichCompare, Py_TYPE, - Py_EQ, Py_NE, Py_LT, Py_LE, Py_GT, Py_GE) +from cpython.object cimport (PyTypeObject, PyObject_CallObject, + PyObject_RichCompare, Py_TYPE, + Py_EQ, Py_NE, Py_LT, Py_LE, Py_GT) from cpython.weakref cimport PyWeakref_GET_OBJECT, PyWeakref_NewRef from libc.string cimport strncmp cimport gmpy2 -cdef add, mul, truediv -from operator import add, mul, truediv +cdef mul, truediv +from operator import mul, truediv from .richcmp cimport rich_to_bool, revop from .sage_object cimport SageObject from .parent cimport Parent_richcmp_element_without_coercion from .element cimport bin_op_exception, parent, Element -from .coerce_actions import LeftModuleAction, RightModuleAction from .coerce_exceptions import CoercionException from sage.rings.integer_fake cimport is_Integer from sage.categories.map cimport Map from sage.categories.morphism import IdentityMorphism -from sage.categories.action cimport Action, InverseAction, PrecomposedAction +from sage.categories.action cimport Action, PrecomposedAction from sage.sets.pythonclass cimport Set_PythonType import traceback @@ -113,7 +112,7 @@ cpdef py_scalar_parent(py_type): Integer Ring sage: py_scalar_parent(float) Real Double Field - sage: py_scalar_parent(complex) + sage: py_scalar_parent(complex) # needs sage.rings.complex_double Complex Double Field sage: py_scalar_parent(bool) Integer Ring @@ -124,6 +123,7 @@ cpdef py_scalar_parent(py_type): sage: py_scalar_parent(fractions.Fraction) Rational Field + sage: # needs numpy sage: import numpy sage: py_scalar_parent(numpy.int16) Integer Ring @@ -131,15 +131,9 @@ cpdef py_scalar_parent(py_type): Integer Ring sage: py_scalar_parent(numpy.uint64) Integer Ring - - sage: py_scalar_parent(float) - Real Double Field sage: py_scalar_parent(numpy.double) Real Double Field - sage: py_scalar_parent(complex) - Complex Double Field - sage: import gmpy2 sage: py_scalar_parent(gmpy2.mpz) Integer Ring @@ -147,7 +141,7 @@ cpdef py_scalar_parent(py_type): Rational Field sage: py_scalar_parent(gmpy2.mpfr) Real Double Field - sage: py_scalar_parent(gmpy2.mpc) + sage: py_scalar_parent(gmpy2.mpc) # needs sage.rings.complex_double Complex Double Field """ if issubclass(py_type, int): @@ -209,8 +203,8 @@ cpdef py_scalar_to_element(x): sage: x = py_scalar_to_element(float(42)) sage: x, parent(x) (42.0, Real Double Field) - sage: x = py_scalar_to_element(complex(42)) - sage: x, parent(x) + sage: x = py_scalar_to_element(complex(42)) # needs sage.rings.complex_double + sage: x, parent(x) # needs sage.rings.complex_double (42.0, Complex Double Field) sage: py_scalar_to_element('hello') 'hello' @@ -237,31 +231,31 @@ cpdef py_scalar_to_element(x): sage: x = py_scalar_to_element(gmpy2.mpfr(42.57)) sage: x, parent(x) (42.57, Real Double Field) - sage: x = py_scalar_to_element(gmpy2.mpc(int(42), int(42))) - sage: x, parent(x) + sage: x = py_scalar_to_element(gmpy2.mpc(int(42), int(42))) # needs sage.rings.complex_double + sage: x, parent(x) # needs sage.rings.complex_double (42.0 + 42.0*I, Complex Double Field) Test compatibility with :func:`py_scalar_parent`:: sage: from sage.structure.coerce import py_scalar_parent sage: elt = [True, int(42), float(42), complex(42)] - sage: for x in elt: + sage: for x in elt: # needs sage.rings.complex_double ....: assert py_scalar_parent(type(x)) == py_scalar_to_element(x).parent() - sage: import numpy - sage: elt = [numpy.int8('-12'), numpy.uint8('143'), + sage: import numpy # needs numpy + sage: elt = [numpy.int8('-12'), numpy.uint8('143'), # needs numpy ....: numpy.int16('-33'), numpy.uint16('122'), ....: numpy.int32('-19'), numpy.uint32('44'), ....: numpy.int64('-3'), numpy.uint64('552'), ....: numpy.float16('-1.23'), numpy.float32('-2.22'), ....: numpy.float64('-3.412'), numpy.complex64(1.2+I), - ....: numpy.complex128(-2+I)] - sage: for x in elt: + ....: numpy.complex128(-2+I)] + sage: for x in elt: # needs numpy ....: assert py_scalar_parent(type(x)) == py_scalar_to_element(x).parent() sage: elt = [gmpy2.mpz(42), gmpy2.mpq('3/4'), ....: gmpy2.mpfr(42.57), gmpy2.mpc(int(42), int(42))] - sage: for x in elt: + sage: for x in elt: # needs sage.rings.complex_double ....: assert py_scalar_parent(type(x)) == py_scalar_to_element(x).parent() """ if isinstance(x, Element): @@ -323,10 +317,10 @@ cpdef bint parent_is_integers(P) except -1: sage: parent_is_integers(dict) False - sage: import numpy - sage: parent_is_integers(numpy.int16) + sage: import numpy # needs numpy + sage: parent_is_integers(numpy.int16) # needs numpy True - sage: parent_is_integers(numpy.uint64) + sage: parent_is_integers(numpy.uint64) # needs numpy True sage: parent_is_integers(float) False @@ -365,13 +359,20 @@ def parent_is_numerical(P): EXAMPLES:: sage: from sage.structure.coerce import parent_is_numerical - sage: import gmpy2, numpy - sage: [parent_is_numerical(R) for R in [RR, CC, QQ, QuadraticField(-1), - ....: int, complex, gmpy2.mpc, numpy.complexfloating]] - [True, True, True, True, True, True, True, True] - sage: [parent_is_numerical(R) for R in [SR, QQ['x'], QQ[['x']], str]] - [False, False, False, False] - sage: [parent_is_numerical(R) for R in [RIF, RBF, CIF, CBF]] + sage: import gmpy2 + sage: [parent_is_numerical(R) for R in [QQ, int, complex, gmpy2.mpc]] # needs sage.rings.complex_double + [True, True, True, True] + sage: [parent_is_numerical(R) for R in [RR, CC]] # needs sage.rings.real_mpfr + [True, True] + sage: parent_is_numerical(QuadraticField(-1)) # needs sage.rings.number_field + True + sage: import numpy; parent_is_numerical(numpy.complexfloating) # needs numpy + True + sage: parent_is_numerical(SR) # needs sage.symbolic + False + sage: [parent_is_numerical(R) for R in [QQ['x'], QQ[['x']], str]] + [False, False, False] + sage: [parent_is_numerical(R) for R in [RIF, RBF, CIF, CBF]] # needs sage.libs.flint [False, False, False, False] """ if not isinstance(P, Parent): @@ -388,16 +389,23 @@ def parent_is_real_numerical(P): EXAMPLES:: sage: from sage.structure.coerce import parent_is_real_numerical - sage: import gmpy2, numpy - sage: [parent_is_real_numerical(R) for R in [RR, QQ, ZZ, RLF, - ....: QuadraticField(2), int, float, gmpy2.mpq, numpy.integer]] - [True, True, True, True, True, True, True, True, True] - sage: [parent_is_real_numerical(R) for R in [CC, QuadraticField(-1), - ....: complex, gmpy2.mpc, numpy.complexfloating]] - [False, False, False, False, False] - sage: [parent_is_real_numerical(R) for R in [SR, QQ['x'], QQ[['x']], str]] + sage: import gmpy2 + sage: [parent_is_real_numerical(R) for R in [RR, QQ, ZZ, RLF, int, float, gmpy2.mpq]] + [True, True, True, True, True, True, True] + sage: parent_is_real_numerical(QuadraticField(2)) # needs sage.rings.number_field + True + sage: import numpy; parent_is_real_numerical(numpy.integer) # needs numpy + True + sage: parent_is_real_numerical(QuadraticField(-1)) # needs sage.rings.number_field + False + sage: [parent_is_real_numerical(R) # needs numpy + ....: for R in [CC, complex, gmpy2.mpc, numpy.complexfloating]] [False, False, False, False] - sage: [parent_is_real_numerical(R) for R in [RIF, RBF, CIF, CBF]] + sage: [parent_is_real_numerical(R) for R in [QQ['x'], QQ[['x']], str]] + [False, False, False] + sage: parent_is_real_numerical(SR) # needs sage.symbolic + False + sage: [parent_is_real_numerical(R) for R in [RIF, RBF, CIF, CBF]] # needs sage.libs.flint [False, False, False, False] """ if not isinstance(P, Parent): @@ -415,6 +423,8 @@ cpdef bint is_numpy_type(t): EXAMPLES:: sage: from sage.structure.coerce import is_numpy_type + + sage: # needs numpy sage: import numpy sage: is_numpy_type(numpy.int16) True @@ -424,11 +434,12 @@ cpdef bint is_numpy_type(t): True sage: is_numpy_type(numpy.matrix) True + sage: is_numpy_type(int) False sage: is_numpy_type(Integer) False - sage: is_numpy_type(Sudoku) + sage: is_numpy_type(Sudoku) # needs sage.combinat False sage: is_numpy_type(None) False @@ -462,6 +473,7 @@ cpdef bint is_mpmath_type(t): EXAMPLES:: + sage: # needs mpmath sage: from sage.structure.coerce import is_mpmath_type sage: is_mpmath_type(int) False @@ -483,13 +495,14 @@ cdef class CoercionModel: EXAMPLES:: - sage: f = ZZ['t','x'].0 + QQ['x'].0 + CyclotomicField(13).gen(); f + sage: f = ZZ['t', 'x'].0 + QQ['x'].0 + CyclotomicField(13).gen(); f # needs sage.rings.number_field t + x + zeta13 - sage: f.parent() - Multivariate Polynomial Ring in t, x over Cyclotomic Field of order 13 and degree 12 + sage: f.parent() # needs sage.rings.number_field + Multivariate Polynomial Ring in t, x + over Cyclotomic Field of order 13 and degree 12 sage: ZZ['x','y'].0 + ~Frac(QQ['y']).0 (x*y + 1)/y - sage: MatrixSpace(ZZ['x'], 2, 2)(2) + ~Frac(QQ['x']).0 + sage: MatrixSpace(ZZ['x'], 2, 2)(2) + ~Frac(QQ['x']).0 # needs sage.modules [(2*x + 1)/x 0] [ 0 (2*x + 1)/x] sage: f = ZZ['x,y,z'].0 + QQ['w,x,z,a'].0; f @@ -503,11 +516,11 @@ cdef class CoercionModel: Check that :trac:`8426` is fixed (see also :trac:`18076`):: - sage: import numpy + sage: import numpy # needs numpy sage: x = polygen(RR) - sage: numpy.float32('1.5') * x + sage: numpy.float32('1.5') * x # needs numpy 1.50000000000000*x - sage: x * numpy.float32('1.5') + sage: x * numpy.float32('1.5') # needs numpy 1.50000000000000*x sage: p = x**3 + 2*x - 1 sage: p(float('1.2')) @@ -517,26 +530,26 @@ cdef class CoercionModel: This used to fail (see :trac:`18076`):: - sage: 1/3 + numpy.int8('12') + sage: 1/3 + numpy.int8('12') # needs numpy 37/3 - sage: -2/3 + numpy.int16('-2') + sage: -2/3 + numpy.int16('-2') # needs numpy -8/3 - sage: 2/5 + numpy.uint8('2') + sage: 2/5 + numpy.uint8('2') # needs numpy 12/5 The numpy types do not interact well with the Sage coercion framework. More precisely, if a numpy type is the first operand in a binary operation then this operation is done in numpy. The result is hence a numpy type:: - sage: numpy.uint8('2') + 3 + sage: numpy.uint8('2') + 3 # needs numpy 5 - sage: type(_) + sage: type(_) # needs numpy <class 'numpy.int32'> # 32-bit <class 'numpy.int64'> # 64-bit - sage: numpy.int8('12') + 1/3 + sage: numpy.int8('12') + 1/3 # needs numpy 12.333333333333334 - sage: type(_) + sage: type(_) # needs numpy <class 'numpy.float64'> AUTHOR: @@ -549,8 +562,9 @@ cdef class CoercionModel: sage: from sage.structure.coerce import CoercionModel sage: cm = CoercionModel() - sage: K = NumberField(x^2-2, 'a') - sage: A = cm.get_action(ZZ, K, operator.mul) + sage: x = polygen(ZZ, 'x') + sage: K = NumberField(x^2 - 2, 'a') # needs sage.rings.number_field + sage: A = cm.get_action(ZZ, K, operator.mul) # needs sage.rings.number_field sage: f, g = cm.coercion_maps(QQ, int) sage: f, g = cm.coercion_maps(ZZ, int) """ @@ -591,7 +605,7 @@ cdef class CoercionModel: EXAMPLES:: sage: cm = sage.structure.element.get_coercion_model() - sage: cm.canonical_coercion(1,2/3) + sage: cm.canonical_coercion(1, 2/3) (1, 2/3) sage: maps, actions = cm.get_cache() @@ -635,7 +649,8 @@ cdef class CoercionModel: 1/2*x sage: maps, actions = cm.get_cache() sage: act = actions[QQ, R, operator.mul]; act - Left scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring + Left scalar multiplication by Rational Field + on Univariate Polynomial Ring in x over Integer Ring sage: act.actor() Rational Field sage: act.domain() @@ -685,7 +700,7 @@ cdef class CoercionModel: sage: cm = sage.structure.element.get_coercion_model() sage: cm.record_exceptions() - sage: 1+1/2+2 # make sure there aren't any errors hanging around + sage: 1 + 1/2 + 2 # make sure there aren't any errors hanging around 7/2 sage: cm.exception_stack() [] @@ -750,7 +765,8 @@ cdef class CoercionModel: sage: 1/2 + GF(3)(2) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for +: 'Rational Field' and 'Finite Field of size 3' + TypeError: unsupported operand parent(s) for +: + 'Rational Field' and 'Finite Field of size 3' Now see what the actual problem was:: @@ -760,7 +776,8 @@ cdef class CoercionModel: sage: print(cm.exception_stack()[-1]) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Rational Field' and 'Finite Field of size 3' + TypeError: no common canonical parent for objects with parents: + 'Rational Field' and 'Finite Field of size 3' This is typically accessed via the :func:`coercion_traceback` function. @@ -769,7 +786,8 @@ cdef class CoercionModel: sage: coercion_traceback() Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Rational Field' and 'Finite Field of size 3' + TypeError: no common canonical parent for objects with parents: + 'Rational Field' and 'Finite Field of size 3' """ if not self._exceptions_cleared: self._exception_stack = [] @@ -805,7 +823,8 @@ cdef class CoercionModel: sage: R = ZZ['x'] sage: cm.explain(R, QQ) Action discovered. - Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring + Right scalar multiplication by Rational Field + on Univariate Polynomial Ring in x over Integer Ring Result lives in Univariate Polynomial Ring in x over Rational Field Univariate Polynomial Ring in x over Rational Field @@ -829,11 +848,11 @@ cdef class CoercionModel: Sometimes with non-sage types there is not enough information to deduce what will actually happen:: - sage: R100 = RealField(100) - sage: cm.explain(R100, float, operator.add) + sage: R100 = RealField(100) # needs sage.rings.real_mpfr + sage: cm.explain(R100, float, operator.add) # needs sage.rings.real_mpfr Right operand is numeric, will attempt coercion in both directions. Unknown result parent. - sage: parent(R100(1) + float(1)) + sage: parent(R100(1) + float(1)) # needs sage.rings.real_mpfr <class 'float'> sage: cm.explain(QQ, float, operator.add) Right operand is numeric, will attempt coercion in both directions. @@ -874,7 +893,8 @@ cdef class CoercionModel: sage: cm.explain(ZZx, ZZ, operator.truediv) Action discovered. - Right inverse action by Rational Field on Univariate Polynomial Ring in x over Integer Ring + Right inverse action by Rational Field + on Univariate Polynomial Ring in x over Integer Ring with precomposition on right by Natural morphism: From: Integer Ring To: Rational Field @@ -906,10 +926,11 @@ cdef class CoercionModel: cpdef analyse(self, xp, yp, op=mul): """ Emulate the process of doing arithmetic between xp and yp, returning - a list of steps and the parent that the result will live in. The - ``explain`` function is easier to use, but if one wants access to + a list of steps and the parent that the result will live in. + + The :meth:`explain` method is easier to use, but if one wants access to the actual morphism and action objects (rather than their string - representations) then this is the function to use. + representations), then this is the function to use. EXAMPLES:: @@ -917,9 +938,11 @@ cdef class CoercionModel: sage: GF7 = GF(7) sage: steps, res = cm.analyse(GF7, ZZ) sage: steps - ['Coercion on right operand via', Natural morphism: + ['Coercion on right operand via', + Natural morphism: From: Integer Ring - To: Finite Field of size 7, 'Arithmetic performed after coercions.'] + To: Finite Field of size 7, + 'Arithmetic performed after coercions.'] sage: res Finite Field of size 7 sage: f = steps[1]; type(f) @@ -999,9 +1022,10 @@ cdef class CoercionModel: def common_parent(self, *args): """ - Computes a common parent for all the inputs. It's essentially - an `n`-ary canonical coercion except it can operate on parents - rather than just elements. + Compute a common parent for all the inputs. + + It's essentially an `n`-ary canonical coercion except it can + operate on parents rather than just elements. INPUT: @@ -1010,14 +1034,14 @@ cdef class CoercionModel: OUTPUT: A :class:`Parent` into which each input should coerce, or raises a - ``TypeError`` if no such :class:`Parent` can be found. + :class:`TypeError` if no such :class:`Parent` can be found. EXAMPLES:: sage: cm = sage.structure.element.get_coercion_model() sage: cm.common_parent(ZZ, QQ) Rational Field - sage: cm.common_parent(ZZ, QQ, RR) + sage: cm.common_parent(ZZ, QQ, RR) # needs sage.rings.real_mpfr Real Field with 53 bits of precision sage: ZZT = ZZ[['T']] sage: QQT = QQ['T'] @@ -1027,8 +1051,8 @@ cdef class CoercionModel: <class 'int'> sage: cm.common_parent(int, float, ZZ) <class 'float'> - sage: real_fields = [RealField(prec) for prec in [10,20..100]] - sage: cm.common_parent(*real_fields) + sage: real_fields = [RealField(prec) for prec in [10,20..100]] # needs sage.rings.real_mpfr + sage: cm.common_parent(*real_fields) # needs sage.rings.real_mpfr Real Field with 10 bits of precision There are some cases where the ordering does matter, but if a parent @@ -1044,7 +1068,9 @@ cdef class CoercionModel: sage: cm.common_parent(QQxy, QQzt, QQyz) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Multivariate Polynomial Ring in x, y over Rational Field' and 'Multivariate Polynomial Ring in z, t over Rational Field' + TypeError: no common canonical parent for objects with parents: + 'Multivariate Polynomial Ring in x, y over Rational Field' and + 'Multivariate Polynomial Ring in z, t over Rational Field' """ base = None for x in args: @@ -1085,8 +1111,8 @@ cdef class CoercionModel: sage: Zmod100 = Integers(100) sage: cm.division_parent(Zmod100) Ring of integers modulo 100 - sage: S5 = SymmetricGroup(5) # optional - sage.groups - sage: cm.division_parent(S5) # optional - sage.groups + sage: S5 = SymmetricGroup(5) # needs sage.groups + sage: cm.division_parent(S5) # needs sage.groups Symmetric group of order 5! as a permutation group """ try: @@ -1103,23 +1129,25 @@ cdef class CoercionModel: cpdef bin_op(self, x, y, op): """ - Execute the operation op on x and y. It first looks for an action - corresponding to op, and failing that, it tries to coerces x and y - into a common parent and calls op on them. + Execute the operation ``op`` on `x` and `y`. - If it cannot make sense of the operation, a TypeError is raised. + It first looks for an action + corresponding to ``op``, and failing that, it tries to coerce `x` and `y` + into a common parent and calls ``op`` on them. + + If it cannot make sense of the operation, a :class:`TypeError` is raised. INPUT: - - ``x`` - the left operand + - ``x`` -- the left operand - - ``y`` - the right operand + - ``y`` -- the right operand - - ``op`` - a python function taking 2 arguments + - ``op`` -- a python function taking 2 arguments .. NOTE:: - op is often an arithmetic operation, but need not be so. + ``op`` is often an arithmetic operation, but need not be so. EXAMPLES:: @@ -1130,14 +1158,14 @@ cdef class CoercionModel: The operator can be any callable:: sage: R.<x> = ZZ['x'] - sage: cm.bin_op(x^2-1, x+1, gcd) + sage: cm.bin_op(x^2 - 1, x + 1, gcd) x + 1 Actions are detected and performed:: - sage: M = matrix(ZZ, 2, 2, range(4)) - sage: V = vector(ZZ, [5,7]) - sage: cm.bin_op(M, V, operator.mul) + sage: M = matrix(ZZ, 2, 2, range(4)) # needs sage.modules + sage: V = vector(ZZ, [5,7]) # needs sage.modules + sage: cm.bin_op(M, V, operator.mul) # needs sage.modules (7, 31) TESTS:: @@ -1249,18 +1277,20 @@ cdef class CoercionModel: cpdef canonical_coercion(self, x, y): r""" - Given two elements x and y, with parents S and R respectively, - find a common parent Z such that there are coercions - `f: S \mapsto Z` and `g: R \mapsto Z` and return `f(x), g(y)` + Given two elements `x` and `y`, with parents `S` and `R` respectively, + find a common parent `Z` such that there are coercions + `f: S \to Z` and `g: R \to Z` and return `f(x), g(y)`, which will have the same parent. - Raises a type error if no such Z can be found. + Raises a type error if no such `Z` can be found. EXAMPLES:: sage: cm = sage.structure.element.get_coercion_model() sage: cm.canonical_coercion(mod(2, 10), 17) (2, 7) + + sage: # needs sage.modules sage: x, y = cm.canonical_coercion(1/2, matrix(ZZ, 2, 2, range(4))) sage: x [1/2 0] @@ -1277,7 +1307,6 @@ cdef class CoercionModel: sage: type(x), type(y) (<class 'sage.rings.integer.Integer'>, <class 'sage.rings.integer.Integer'>) - sage: x, y = cm.canonical_coercion(int(5), complex(3)) sage: type(x), type(y) (<class 'complex'>, <class 'complex'>) @@ -1293,7 +1322,7 @@ cdef class CoercionModel: We also make an exception for 0, even if `\ZZ` does not map in:: - sage: canonical_coercion(vector([1, 2, 3]), 0) + sage: canonical_coercion(vector([1, 2, 3]), 0) # needs sage.modules ((1, 2, 3), (0, 0, 0)) sage: canonical_coercion(GF(5)(0), float(0)) (0, 0) @@ -1392,7 +1421,6 @@ cdef class CoercionModel: raise TypeError("no common canonical parent for objects with parents: '%s' and '%s'"%(xp, yp)) - cpdef coercion_maps(self, R, S): r""" Give two parents `R` and `S`, return a pair of coercion maps @@ -1443,6 +1471,7 @@ cdef class CoercionModel: Note that to break symmetry, if there is a coercion map in both directions, the parent on the left is used:: + sage: # needs sage.modules sage: V = QQ^3 sage: W = V.__class__(QQ, 3) sage: V == W @@ -1451,20 +1480,22 @@ cdef class CoercionModel: False sage: cm = sage.structure.element.get_coercion_model() sage: cm.coercion_maps(V, W) - (None, (map internal to coercion system -- copy before use) + (None, + (map internal to coercion system -- copy before use) Coercion map: From: Vector space of dimension 3 over Rational Field To: Vector space of dimension 3 over Rational Field) sage: cm.coercion_maps(W, V) - (None, (map internal to coercion system -- copy before use) + (None, + (map internal to coercion system -- copy before use) Coercion map: From: Vector space of dimension 3 over Rational Field To: Vector space of dimension 3 over Rational Field) sage: v = V([1,2,3]) sage: w = W([1,2,3]) - sage: parent(v+w) is V + sage: parent(v + w) is V True - sage: parent(w+v) is W + sage: parent(w + v) is W True TESTS: @@ -1472,20 +1503,21 @@ cdef class CoercionModel: We check that with :trac:`14058`, parents are still eligible for garbage collection after being involved in binary operations:: + sage: # needs sage.libs.pari sage: import gc - sage: T=type(GF(2)) - sage: gc.collect() #random + sage: T = type(GF(2)) + sage: gc.collect() # random 852 - sage: N0=len(list(o for o in gc.get_objects() if type(o) is T)) - sage: L=[ZZ(1)+GF(p)(1) for p in prime_range(2,50)] - sage: N1=len(list(o for o in gc.get_objects() if type(o) is T)) + sage: N0 = len(list(o for o in gc.get_objects() if type(o) is T)) + sage: L = [ZZ(1) + GF(p)(1) for p in prime_range(2, 50)] + sage: N1 = len(list(o for o in gc.get_objects() if type(o) is T)) sage: N1 > N0 True sage: del L - sage: gc.collect() #random + sage: gc.collect() # random 3939 - sage: N2=len(list(o for o in gc.get_objects() if type(o) is T)) - sage: N2-N0 + sage: N2 = len(list(o for o in gc.get_objects() if type(o) is T)) + sage: N2 - N0 0 """ @@ -1540,7 +1572,7 @@ cdef class CoercionModel: cpdef verify_coercion_maps(self, R, S, homs, bint fix=False): """ - Make sure this is a valid pair of homomorphisms from R and S to a common parent. + Make sure this is a valid pair of homomorphisms from `R` and `S` to a common parent. This function is used to protect the user against buggy parents. EXAMPLES:: @@ -1553,9 +1585,11 @@ cdef class CoercionModel: sage: cm.verify_coercion_maps(ZZ, QQ, homs) == homs Traceback (most recent call last): ... - RuntimeError: ('BUG in coercion model, codomains must be identical', Natural morphism: + RuntimeError: ('BUG in coercion model, codomains must be identical', + Natural morphism: From: Integer Ring - To: Rational Field, Generic map: + To: Rational Field, + Generic map: From: Rational Field To: Real Field with 53 bits of precision) """ @@ -1608,7 +1642,7 @@ cdef class CoercionModel: cpdef discover_coercion(self, R, S): """ This actually implements the finding of coercion maps as described in - the ``coercion_maps`` method. + the :meth:`coercion_maps` method. EXAMPLES:: @@ -1616,7 +1650,7 @@ cdef class CoercionModel: If R is S, then two identity morphisms suffice:: - sage: cm.discover_coercion(SR, SR) + sage: cm.discover_coercion(SR, SR) # needs sage.symbolic (None, None) If there is a coercion map either direction, use that:: @@ -1626,7 +1660,7 @@ cdef class CoercionModel: Natural morphism: From: Integer Ring To: Rational Field, None) - sage: cm.discover_coercion(RR, QQ) + sage: cm.discover_coercion(RR, QQ) # needs sage.rings.real_mpfr (None, (map internal to coercion system -- copy before use) Generic map: From: Rational Field @@ -1647,12 +1681,11 @@ cdef class CoercionModel: Sometimes there is a reasonable "cover," but no canonical coercion:: - sage: sage.categories.pushout.pushout(QQ, QQ^3) + sage: sage.categories.pushout.pushout(QQ, QQ^3) # needs sage.modules Vector space of dimension 3 over Rational Field - sage: print(cm.discover_coercion(QQ, QQ^3)) + sage: print(cm.discover_coercion(QQ, QQ^3)) # needs sage.modules None """ - from sage.categories.homset import Hom if R is S: return None, None @@ -1694,18 +1727,22 @@ cdef class CoercionModel: sage: cm = sage.structure.element.get_coercion_model() sage: ZZx = ZZ['x'] sage: cm.get_action(ZZx, ZZ, operator.mul) - Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring + Right scalar multiplication by Integer Ring + on Univariate Polynomial Ring in x over Integer Ring sage: cm.get_action(ZZx, QQ, operator.mul) - Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring + Right scalar multiplication by Rational Field + on Univariate Polynomial Ring in x over Integer Ring sage: QQx = QQ['x'] sage: cm.get_action(QQx, int, operator.mul) - Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Rational Field + Right scalar multiplication by Integer Ring + on Univariate Polynomial Ring in x over Rational Field with precomposition on right by Native morphism: From: Set of Python objects of class 'int' To: Integer Ring sage: A = cm.get_action(QQx, ZZ, operator.truediv); A - Right inverse action by Rational Field on Univariate Polynomial Ring in x over Rational Field + Right inverse action by Rational Field + on Univariate Polynomial Ring in x over Rational Field with precomposition on right by Natural morphism: From: Integer Ring To: Rational Field @@ -1734,7 +1771,8 @@ cdef class CoercionModel: sage: R.<x> = ZZ['x'] sage: cm = sage.structure.element.get_coercion_model() sage: cm.verify_action(R.get_action(QQ), R, QQ, operator.mul) - Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring + Right scalar multiplication by Rational Field + on Univariate Polynomial Ring in x over Integer Ring sage: cm.verify_action(R.get_action(QQ), RDF, R, operator.mul) Traceback (most recent call last): ... @@ -1743,8 +1781,9 @@ cdef class CoercionModel: R = Real Double Field S = Univariate Polynomial Ring in x over Integer Ring (should be Univariate Polynomial Ring in x over Integer Ring, Rational Field) - action = Right scalar multiplication by Rational Field on - Univariate Polynomial Ring in x over Integer Ring (<class 'sage.structure.coerce_actions.RightModuleAction'>) + action = Right scalar multiplication by Rational Field + on Univariate Polynomial Ring in x over Integer Ring + (<class 'sage.structure.coerce_actions.RightModuleAction'>) """ if action is None: return action @@ -1783,15 +1822,15 @@ cdef class CoercionModel: """ INPUT: - - ``R`` - the left Parent (or type) - - ``S`` - the right Parent (or type) - - ``op`` - the operand, typically an element of the operator module - - ``r`` - (optional) element of R - - ``s`` - (optional) element of S. + - ``R`` -- the left :class:`Parent` (or type) + - ``S`` -- the right :class:`Parent` (or type) + - ``op`` -- the operand, typically an element of the :mod:`operator` module + - ``r`` -- (optional) element of `R` + - ``s`` -- (optional) element of `S`. OUTPUT: - - An action A such that s op r is given by A(s,r). + - An action `A` such that `s` ``op`` `r` is given by `A(s,r)`. The steps taken are illustrated below. @@ -1799,28 +1838,33 @@ cdef class CoercionModel: sage: P.<x> = ZZ['x'] sage: P.get_action(ZZ) - Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring + Right scalar multiplication by Integer Ring on + Univariate Polynomial Ring in x over Integer Ring sage: ZZ.get_action(P) is None True sage: cm = sage.structure.element.get_coercion_model() - If R or S is a Parent, ask it for an action by/on R:: + If `R` or `S` is a :class:`Parent`, ask it for an action by/on `R`:: sage: cm.discover_action(ZZ, P, operator.mul) - Left scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring + Left scalar multiplication by Integer Ring on + Univariate Polynomial Ring in x over Integer Ring - If R or S a type, recursively call get_action with the Sage versions of R and/or S:: + If `R` or `S` a type, recursively call :meth:`get_action` + with the Sage versions of `R` and/or `S`:: sage: cm.discover_action(P, int, operator.mul) - Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring - with precomposition on right by Native morphism: + Right scalar multiplication by Integer Ring on + Univariate Polynomial Ring in x over Integer Ring + with precomposition on right by Native morphism: From: Set of Python objects of class 'int' To: Integer Ring - If op is division, look for action on right by inverse:: + If ``op`` is division, look for action on ``right`` by inverse:: sage: cm.discover_action(P, ZZ, operator.truediv) - Right inverse action by Rational Field on Univariate Polynomial Ring in x over Integer Ring + Right inverse action by Rational Field on + Univariate Polynomial Ring in x over Integer Ring with precomposition on right by Natural morphism: From: Integer Ring To: Rational Field @@ -1829,7 +1873,8 @@ cdef class CoercionModel: sage: R = GF(5)['x'] sage: cm.discover_action(R, ZZ, operator.truediv) - Right inverse action by Finite Field of size 5 on Univariate Polynomial Ring in x over Finite Field of size 5 + Right inverse action by Finite Field of size 5 + on Univariate Polynomial Ring in x over Finite Field of size 5 with precomposition on right by Natural morphism: From: Integer Ring To: Finite Field of size 5 @@ -1838,12 +1883,14 @@ cdef class CoercionModel: Check that :trac:`18221` is fixed:: + sage: # needs sage.combinat sage.modules sage: F.<x> = FreeAlgebra(QQ) sage: x / 2 1/2*x sage: cm.discover_action(F, ZZ, operator.truediv) - Right inverse action by Rational Field on Free Algebra on 1 generators (x,) over Rational Field - with precomposition on right by Natural morphism: + Right inverse action by Rational Field on + Free Algebra on 1 generators (x,) over Rational Field + with precomposition on right by Natural morphism: From: Integer Ring To: Rational Field """ @@ -1941,7 +1988,8 @@ cdef class CoercionModel: sage: richcmp(x, y, op_GT) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for >: 'Rational Field' and 'Finite Field of size 2' + TypeError: unsupported operand parent(s) for >: + 'Rational Field' and 'Finite Field of size 2' We support non-Sage types with the usual Python convention:: diff --git a/src/sage/structure/coerce_actions.pyx b/src/sage/structure/coerce_actions.pyx index 3096282f068..6df2aec6695 100644 --- a/src/sage/structure/coerce_actions.pyx +++ b/src/sage/structure/coerce_actions.pyx @@ -14,7 +14,7 @@ Coerce actions import operator -from cpython.int cimport * +from cpython.long cimport * from cpython.number cimport * from cysignals.signals cimport sig_check @@ -55,12 +55,15 @@ cdef class GenericAction(Action): for otherwise they could be garbage collected, giving rise to random errors (see :trac:`18157`). :: - sage: M = MatrixSpace(ZZ,2) - sage: sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) - Left action by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring on Set P^1(QQ) of all cusps + sage: from sage.structure.coerce_actions import ActedUponAction, GenericAction + sage: M = MatrixSpace(ZZ, 2) # needs sage.modules + sage: ActedUponAction(M, Cusps, True) # needs sage.modular sage.modules + Left action + by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring + on Set P^1(QQ) of all cusps sage: Z6 = Zmod(6) - sage: sage.structure.coerce_actions.GenericAction(QQ, Z6, True) + sage: GenericAction(QQ, Z6, True) Traceback (most recent call last): ... NotImplementedError: action for <class 'sage.structure.coerce_actions.GenericAction'> not implemented @@ -92,15 +95,16 @@ cdef class GenericAction(Action): errors (see :trac:`18157`). :: - sage: M = MatrixSpace(ZZ,2) - sage: A = sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) - sage: A.codomain() + sage: M = MatrixSpace(ZZ, 2) # needs sage.modules + sage: A = sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) # needs sage.modular sage.modules + sage: A.codomain() # needs sage.modular sage.modules Set P^1(QQ) of all cusps - sage: S3 = SymmetricGroup(3) # optional - sage.groups - sage: QQxyz = QQ['x,y,z'] # optional - sage.groups - sage: A = sage.structure.coerce_actions.ActOnAction(S3, QQxyz, False) # optional - sage.groups - sage: A.codomain() # optional - sage.groups + sage: # needs sage.groups + sage: S3 = SymmetricGroup(3) + sage: QQxyz = QQ['x,y,z'] + sage: A = sage.structure.coerce_actions.ActOnAction(S3, QQxyz, False) + sage: A.codomain() Multivariate Polynomial Ring in x, y, z over Rational Field """ @@ -118,15 +122,15 @@ cdef class ActOnAction(GenericAction): """ TESTS:: - sage: G = SymmetricGroup(3) # optional - sage.groups - sage: R.<x,y,z> = QQ[] # optional - sage.groups - sage: A = sage.structure.coerce_actions.ActOnAction(G, R, False) # optional - sage.groups - sage: A(x^2 + y - z, G((1,2))) # optional - sage.groups + sage: # needs sage.groups + sage: G = SymmetricGroup(3) + sage: R.<x,y,z> = QQ[] + sage: A = sage.structure.coerce_actions.ActOnAction(G, R, False) + sage: A(x^2 + y - z, G((1,2))) y^2 + x - z - sage: A(x+2*y+3*z, G((1,3,2))) # optional - sage.groups + sage: A(x + 2*y + 3*z, G((1,3,2))) 2*x + 3*y + z - - sage: type(A) # optional - sage.groups + sage: type(A) <... 'sage.structure.coerce_actions.ActOnAction'> """ return (<Element>g)._act_on_(x, self._is_left) @@ -140,13 +144,13 @@ cdef class ActedUponAction(GenericAction): """ TESTS:: - sage: M = MatrixSpace(ZZ,2) + sage: # needs sage.modular sage.modules + sage: M = MatrixSpace(ZZ, 2) sage: A = sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) sage: A.act(matrix(ZZ, 2, [1,0,2,-1]), Cusp(1,2)) Infinity sage: A(matrix(ZZ, 2, [1,0,2,-1]), Cusp(1,2)) Infinity - sage: type(A) <... 'sage.structure.coerce_actions.ActedUponAction'> """ @@ -166,14 +170,16 @@ def detect_element_action(Parent X, Y, bint X_on_left, X_el=None, Y_el=None): sage: from sage.structure.coerce_actions import detect_element_action sage: ZZx = ZZ['x'] - sage: M = MatrixSpace(ZZ,2) + sage: M = MatrixSpace(ZZ, 2) # needs sage.modules sage: detect_element_action(ZZx, ZZ, False) Left scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring sage: detect_element_action(ZZx, QQ, True) - Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring - sage: detect_element_action(Cusps, M, False) - Left action by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring on Set P^1(QQ) of all cusps - sage: detect_element_action(Cusps, M, True), + Right scalar multiplication by Rational Field + on Univariate Polynomial Ring in x over Integer Ring + sage: detect_element_action(Cusps, M, False) # needs sage.modular sage.modules + Left action by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring + on Set P^1(QQ) of all cusps + sage: detect_element_action(Cusps, M, True), # needs sage.modular sage.modules (None,) sage: detect_element_action(ZZ, QQ, True), (None,) @@ -400,7 +406,8 @@ cdef class ModuleAction(Action): sage: GF5 = GF(5) sage: GF5t = GF5[['t']] sage: RightModuleAction(GF5, GF5t) - Right scalar multiplication by Finite Field of size 5 on Power Series Ring in t over Finite Field of size 5 + Right scalar multiplication by Finite Field of size 5 + on Power Series Ring in t over Finite Field of size 5 """ return "scalar multiplication" @@ -483,7 +490,8 @@ cdef class ModuleAction(Action): sage: GF5x = GF(5)['x'] sage: A = ~RightModuleAction(ZZ, GF5x); A - Right inverse action by Finite Field of size 5 on Univariate Polynomial Ring in x over Finite Field of size 5 + Right inverse action by Finite Field of size 5 + on Univariate Polynomial Ring in x over Finite Field of size 5 with precomposition on right by Natural morphism: From: Integer Ring To: Finite Field of size 5 @@ -492,7 +500,8 @@ cdef class ModuleAction(Action): sage: GF5xy = GF5x['y'] sage: A = ~RightModuleAction(ZZ, GF5xy); A - Right inverse action by Finite Field of size 5 on Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Finite Field of size 5 + Right inverse action by Finite Field of size 5 + on Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Finite Field of size 5 with precomposition on right by Natural morphism: From: Integer Ring To: Finite Field of size 5 @@ -516,6 +525,7 @@ cdef class ModuleAction(Action): See :trac:`19521`:: + sage: # needs sage.symbolic sage: Q.<y> = SR.subring(no_variables=True)[[]] sage: (y / 1).parent() Power Series Ring in y over Symbolic Constants Subring @@ -678,8 +688,8 @@ cdef class IntegerAction(Action): Check that this action can be pickled (:trac:`29031`):: sage: from sage.structure.coerce_actions import IntegerMulAction - sage: act = IntegerMulAction(ZZ, CDF) - sage: loads(dumps(act)) is not None + sage: act = IntegerMulAction(ZZ, CDF) # needs sage.rings.complex_double + sage: loads(dumps(act)) is not None # needs sage.rings.complex_double True """ # All base classes must take the signature @@ -691,8 +701,8 @@ cdef class IntegerAction(Action): EXAMPLES:: sage: from sage.structure.coerce_actions import IntegerMulAction - sage: act = IntegerMulAction(ZZ, CDF) - sage: ~act + sage: act = IntegerMulAction(ZZ, CDF) # needs sage.rings.complex_double + sage: ~act # needs sage.rings.complex_double Traceback (most recent call last): ... TypeError: actions by ZZ cannot be inverted @@ -763,13 +773,14 @@ cdef class IntegerMulAction(IntegerAction): This used to hang before :trac:`17844`:: - sage: E = EllipticCurve(GF(5), [4,0]) - sage: P = E.random_element() - sage: (-2^63)*P + sage: E = EllipticCurve(GF(5), [4,0]) # needs sage.schemes + sage: P = E.random_element() # needs sage.schemes + sage: (-2^63)*P # needs sage.schemes (0 : 1 : 0) Check that large multiplications can be interrupted:: + sage: # needs sage.schemes sage: alarm(0.001); 2^(10^7) * P Traceback (most recent call last): ... @@ -778,6 +789,7 @@ cdef class IntegerMulAction(IntegerAction): Verify that cysignals correctly detects that the above exception has been handled:: + sage: # needs sage.schemes sage: from cysignals.tests import print_sig_occurred sage: print_sig_occurred() No current exception @@ -802,7 +814,8 @@ cdef class IntegerMulAction(IntegerAction): sage: from sage.structure.coerce_actions import IntegerMulAction sage: GF5 = GF(5) sage: IntegerMulAction(ZZ, GF5) - Left Integer Multiplication by Integer Ring on Finite Field of size 5 + Left Integer Multiplication by Integer Ring + on Finite Field of size 5 """ return "Integer Multiplication" @@ -840,18 +853,18 @@ cdef class IntegerPowAction(IntegerAction): Traceback (most recent call last): ... ValueError: powering must be a right action - sage: IntegerPowAction(ZZ, QQ^3) + sage: IntegerPowAction(ZZ, QQ^3) # needs sage.modules Traceback (most recent call last): ... TypeError: no integer powering action defined on Vector space of dimension 3 over Rational Field :: - sage: var('x,y') + sage: var('x,y') # needs sage.symbolic (x, y) - sage: RDF('-2.3')^(x+y^3+sin(x)) + sage: RDF('-2.3')^(x+y^3+sin(x)) # needs sage.symbolic (-2.3)^(y^3 + x + sin(x)) - sage: RDF('-2.3')^x + sage: RDF('-2.3')^x # needs sage.symbolic (-2.3)^x """ def __init__(self, Z, M, is_left=False, m=None): diff --git a/src/sage/structure/coerce_dict.pyx b/src/sage/structure/coerce_dict.pyx index 5fc749e9522..ef86c6af35c 100644 --- a/src/sage/structure/coerce_dict.pyx +++ b/src/sage/structure/coerce_dict.pyx @@ -35,8 +35,9 @@ coerce maps. In previous versions of Sage, the cache was by strong references and resulted in a memory leak in the following example. However, this leak was fixed by :trac:`715`, using weak references:: + sage: # needs sage.combinat sage.modules sage.rings.finite_rings sage: K.<t> = GF(2^55) - sage: for i in range(50): + sage: for i in range(20): ....: a = K.random_element() ....: E = EllipticCurve(j=a) ....: P = E.random_point() @@ -404,17 +405,18 @@ cdef class MonoDict: sage: import gc sage: def count_type(T): ....: return len([c for c in gc.get_objects() if isinstance(c,T)]) - sage: _ = gc.collect() + sage: gc.freeze() # so that gc.collect() only deals with our trash sage: N = count_type(MonoDict) sage: for i in range(100): ....: V = [MonoDict({"id":j+100*i}) for j in range(100)] - ....: n= len(V) - ....: for i in range(n): V[i][V[(i+1)%n]]=(i+1)%n + ....: n = len(V) + ....: for i in range(n): V[i][V[(i+1)%n]] = (i+1)%n ....: del V ....: _ = gc.collect() ....: assert count_type(MonoDict) == N sage: count_type(MonoDict) == N True + sage: gc.unfreeze() AUTHORS: @@ -775,7 +777,7 @@ cdef class MonoDict: sage: L[1] = None sage: L[2] = True sage: L.items() - <generator object at ...> + <...generator object at ...> sage: sorted(L.items()) [(1, None), (2, True)] """ @@ -1450,7 +1452,7 @@ cdef class TripleDict: sage: L = TripleDict() sage: L[1,2,3] = None sage: L.items() - <generator object at ...> + <...generator object at ...> sage: list(L.items()) [((1, 2, 3), None)] """ diff --git a/src/sage/structure/coerce_maps.pyx b/src/sage/structure/coerce_maps.pyx index 6675fc84019..1c1464a7899 100644 --- a/src/sage/structure/coerce_maps.pyx +++ b/src/sage/structure/coerce_maps.pyx @@ -1,8 +1,6 @@ """ Coerce maps """ - -import re import types from sage.structure.parent cimport Parent @@ -34,16 +32,19 @@ cdef class DefaultConvertMap(Map): Maps of this type are morphisms in the category of sets with partial maps (see :trac:`15618`):: - sage: f = GF(11).convert_map_from(GF(7)); f + sage: f = GF(11).convert_map_from(GF(7)); f # needs sage.rings.finite_rings Conversion map: From: Finite Field of size 7 To: Finite Field of size 11 - sage: f.parent() - Set of Morphisms from Finite Field of size 7 to Finite Field of size 11 in Category of sets with partial maps + sage: f.parent() # needs sage.rings.finite_rings + Set of Morphisms + from Finite Field of size 7 + to Finite Field of size 11 + in Category of sets with partial maps Test that :trac:`23211` is resolved:: - sage: f._is_coercion + sage: f._is_coercion # needs sage.rings.finite_rings False sage: QQ[['x']].coerce_map_from(QQ)._is_coercion True @@ -52,7 +53,8 @@ cdef class DefaultConvertMap(Map): sage: from sage.structure.coerce_maps import DefaultConvertMap sage: DefaultConvertMap(ZZ, ZZ) - doctest:...: DeprecationWarning: DefaultConvertMap is deprecated, use DefaultConvertMap_unique instead. This probably means that _element_constructor_ should be a method and not some other kind of callable + doctest:...: DeprecationWarning: DefaultConvertMap is deprecated, use DefaultConvertMap_unique instead. + This probably means that _element_constructor_ should be a method and not some other kind of callable See https://github.com/sagemath/sage/issues/26879 for details. Conversion map: From: Integer Ring @@ -83,8 +85,8 @@ cdef class DefaultConvertMap(Map): EXAMPLES:: - sage: f = GF(11).convert_map_from(GF(7)) - sage: f._repr_type() + sage: f = GF(11).convert_map_from(GF(7)) # needs sage.rings.finite_rings + sage: f._repr_type() # needs sage.rings.finite_rings 'Conversion' """ return self._repr_type_str or ("Coercion" if self._is_coercion else "Conversion") @@ -192,14 +194,15 @@ cdef class NamedConvertMap(Map): """ EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.structure.coerce_maps import NamedConvertMap sage: var('t') t sage: mor = NamedConvertMap(SR, QQ['t'], '_polynomial_') - sage: mor(t^2/4+1) + sage: mor(t^2/4 + 1) 1/4*t^2 + 1 sage: mor = NamedConvertMap(SR, GF(7)[['t']], '_polynomial_') - sage: mor(t^2/4+1) + sage: mor(t^2/4 + 1) 1 + 2*t^2 """ if isinstance(domain, type): @@ -215,6 +218,7 @@ cdef class NamedConvertMap(Map): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.structure.coerce_maps import NamedConvertMap sage: var('t') t @@ -224,11 +228,11 @@ cdef class NamedConvertMap(Map): Conversion via _polynomial_ method map: From: Symbolic Ring To: Univariate Polynomial Ring in t over Rational Field - sage: phi == psi # todo: comparison not implemented + sage: phi == psi # not implemented True - sage: psi(t^2/4+1) + sage: psi(t^2/4 + 1) 1/4*t^2 + 1 - sage: psi(t^2/4+1) == phi(t^2/4+1) + sage: psi(t^2/4 + 1) == phi(t^2/4 + 1) True """ slots = Map._extra_slots(self) @@ -241,6 +245,7 @@ cdef class NamedConvertMap(Map): EXAMPLES:: + sage: # needs sage.symbolic sage: from sage.structure.coerce_maps import NamedConvertMap sage: var('t') t @@ -250,11 +255,11 @@ cdef class NamedConvertMap(Map): Conversion via _polynomial_ method map: From: Symbolic Ring To: Univariate Polynomial Ring in t over Rational Field - sage: phi == psi # todo: comparison not implemented + sage: phi == psi # not implemented True - sage: psi(t^2/4+1) + sage: psi(t^2/4 + 1) 1/4*t^2 + 1 - sage: psi(t^2/4+1) == phi(t^2/4+1) + sage: psi(t^2/4 + 1) == phi(t^2/4 + 1) True """ self.method_name = _slots['method_name'] @@ -282,7 +287,7 @@ cdef class NamedConvertMap(Map): print(type(x), x) print(type(C), C) print(self.method_name) - raise TypeError("Cannot coerce {} to {}".format(x, C)) + raise TypeError(f"cannot coerce {x} to {C}") cdef Map m cdef Element e = method(C) if e is None: @@ -299,8 +304,8 @@ cdef class NamedConvertMap(Map): EXAMPLES:: sage: from sage.structure.coerce_maps import NamedConvertMap - sage: f = NamedConvertMap(SR, ZZ['x'], '_polynomial_') - sage: f(x^2+1, check=True) + sage: f = NamedConvertMap(SR, ZZ['x'], '_polynomial_') # needs sage.symbolic + sage: f(x^2 + 1, check=True) # needs sage.symbolic x^2 + 1 """ cdef Parent C = self._codomain @@ -333,6 +338,7 @@ cdef class CallableConvertMap(Map): :: + sage: # needs sage.symbolic sage: f = CallableConvertMap(RR, RR, exp, parent_as_first_arg=False) sage: f(0) 1.00000000000000 diff --git a/src/sage/structure/dynamic_class.py b/src/sage/structure/dynamic_class.py index 0e671f90c1c..cd72c1832a0 100644 --- a/src/sage/structure/dynamic_class.py +++ b/src/sage/structure/dynamic_class.py @@ -322,7 +322,7 @@ class also has a zero ``__dictoffset__``. This means that the name = str(name) except UnicodeEncodeError: pass - assert(isinstance(name, str)) + assert isinstance(name, str) # assert(cls is None or issubtype(type(cls), type) or type(cls) is classobj) if cache is True: return dynamic_class_internal(name, bases, cls, reduction, doccls, prepend_cls_bases) diff --git a/src/sage/structure/element.pxd b/src/sage/structure/element.pxd index 5c6e295a4b8..20c556b985e 100644 --- a/src/sage/structure/element.pxd +++ b/src/sage/structure/element.pxd @@ -34,16 +34,16 @@ cpdef inline parent(x): sage: parent(b) Rational Field sage: c = 42.0 - sage: parent(c) + sage: parent(c) # needs sage.rings.real_mpfr Real Field with 53 bits of precision Some more complicated examples:: - sage: x = Partition([3,2,1,1,1]) - sage: parent(x) + sage: x = Partition([3,2,1,1,1]) # needs sage.combinat + sage: parent(x) # needs sage.combinat Partitions - sage: v = vector(RDF, [1,2,3]) - sage: parent(v) + sage: v = vector(RDF, [1,2,3]) # needs sage.modules + sage: parent(v) # needs sage.modules Vector space of dimension 3 over Real Double Field The following are not considered to be elements, so the type is @@ -126,7 +126,7 @@ cpdef inline bint have_same_parent(left, right): True sage: have_same_parent(1, 1/2) False - sage: have_same_parent(gap(1), gap(1/2)) + sage: have_same_parent(gap(1), gap(1/2)) # needs sage.libs.gap True These have different types but the same parent:: @@ -176,7 +176,7 @@ cdef class Element(SageObject): cdef class ElementWithCachedMethod(Element): - cdef public dict __cached_methods + cdef public dict _cached_methods cdef class ModuleElement(Element) # forward declaration diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 6ad3075c5f4..caae7e40ffc 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -290,15 +290,11 @@ continue down the MRO and find the ``_add_`` method in the category. cimport cython from cpython cimport * -from cpython.ref cimport PyObject from sage.ext.stdsage cimport * -import types cdef add, sub, mul, truediv, floordiv, mod, matmul, pow -cdef iadd, isub, imul, itruediv, ifloordiv, imod, ipow -from operator import (add, sub, mul, truediv, floordiv, mod, matmul, pow, - iadd, isub, imul, itruediv, ifloordiv, imod, imatmul, ipow) +from operator import (add, sub, mul, truediv, floordiv, mod, matmul, pow) cdef dict _coerce_op_symbols = dict( add='+', sub='-', mul='*', truediv='/', floordiv='//', mod='%', matmul='@', pow='^', @@ -310,8 +306,6 @@ from sage.structure.parent cimport Parent from sage.cpython.type cimport can_assign_class from sage.cpython.getattr cimport getattr_from_other_class from sage.misc.lazy_format import LazyFormat -from sage.misc import sageinspect -from sage.misc.classcall_metaclass cimport ClasscallMetaclass from sage.arith.long cimport integer_check_long_py from sage.arith.power cimport generic_power as arith_generic_power from sage.arith.numerical_approx cimport digits_to_bits @@ -360,7 +354,7 @@ def is_Element(x): sage: from sage.structure.element import is_Element sage: is_Element(2/3) True - sage: is_Element(QQ^3) + sage: is_Element(QQ^3) # needs sage.modules False """ return isinstance(x, Element) @@ -385,6 +379,7 @@ cdef class Element(SageObject): .. automethod:: __mod__ """ @cython.binding(False) + @cython.always_allow_keywords(False) def __getmetaclass__(_): from sage.misc.inherit_comparison import InheritComparisonMetaclass return InheritComparisonMetaclass @@ -418,10 +413,10 @@ cdef class Element(SageObject): sage: q = 3/5 sage: parent(q) Rational Field - sage: q._set_parent(CC) - sage: parent(q) + sage: q._set_parent(CC) # needs sage.rings.real_mpfr + sage: parent(q) # needs sage.rings.real_mpfr Complex Field with 53 bits of precision - sage: q._set_parent(float) + sage: q._set_parent(float) # needs sage.rings.real_mpfr Traceback (most recent call last): ... TypeError: Cannot convert type to sage.structure.parent.Parent @@ -654,7 +649,7 @@ cdef class Element(SageObject): sage: QQ.base_ring() Rational Field - sage: identity_matrix(3).base_ring() + sage: identity_matrix(3).base_ring() # needs sage.modules Integer Ring """ return self._parent.base_ring() @@ -711,7 +706,6 @@ cdef class Element(SageObject): ... AssertionError: self.an_element() is not in self """ - from sage.categories.objects import Objects tester = self._tester(**options) SageObject._test_category(self, tester = tester) category = self.category() @@ -855,18 +849,18 @@ cdef class Element(SageObject): EXAMPLES:: - sage: (2/3).numerical_approx() + sage: (2/3).numerical_approx() # needs sage.rings.real_mpfr 0.666666666666667 - sage: pi.n(digits=10) + sage: pi.n(digits=10) # needs sage.symbolic 3.141592654 - sage: pi.n(prec=20) + sage: pi.n(prec=20) # needs sage.symbolic 3.1416 TESTS: Check that :trac:`14778` is fixed:: - sage: (0).n(algorithm='foo') + sage: (0).n(algorithm='foo') # needs sage.rings.real_mpfr 0.000000000000000 """ from sage.arith.numerical_approx import numerical_approx_generic @@ -880,7 +874,7 @@ cdef class Element(SageObject): EXAMPLES:: - sage: (2/3).n() + sage: (2/3).n() # needs sage.rings.real_mpfr 0.666666666666667 """ return self.numerical_approx(prec, digits, algorithm) @@ -896,17 +890,18 @@ cdef class Element(SageObject): EXAMPLES:: + sage: # needs mpmath sage: from sage.libs.mpmath.all import mp, mpmathify sage: mp.dps = 30 sage: 25._mpmath_(53) mpf('25.0') - sage: mpmathify(3+4*I) + sage: mpmathify(3 + 4*I) mpc(real='3.0', imag='4.0') - sage: mpmathify(1+pi) + sage: mpmathify(1 + pi) # needs sage.symbolic mpf('4.14159265358979323846264338327933') - sage: (1+pi)._mpmath_(10) + sage: (1 + pi)._mpmath_(10) # needs sage.symbolic mpf('4.140625') - sage: (1+pi)._mpmath_(mp.prec) + sage: (1 + pi)._mpmath_(mp.prec) # needs sage.symbolic mpf('4.14159265358979323846264338327933') """ return self.n(prec)._mpmath_(prec=prec) @@ -927,11 +922,11 @@ cdef class Element(SageObject): EXAMPLES:: - sage: x, y = PolynomialRing(ZZ,2,'xy').gens() + sage: x, y = PolynomialRing(ZZ, 2, 'xy').gens() sage: f = x^2 + y + x^2*y^2 + 5 sage: f((5,y)) 25*y^2 + y + 30 - sage: f.substitute({x:5}) + sage: f.substitute({x: 5}) 25*y^2 + y + 30 sage: f.substitute(x=5) 25*y^2 + y + 30 @@ -995,7 +990,7 @@ cdef class Element(SageObject): sage: n = 5; n._is_atomic() True - sage: n = x+1; n._is_atomic() + sage: n = x + 1; n._is_atomic() # needs sage.symbolic False """ if self._parent._repr_option('element_is_atomic'): @@ -1031,13 +1026,14 @@ cdef class Element(SageObject): Verify that :trac:`5185` is fixed:: + sage: # needs sage.modules sage: v = vector({1: 1, 3: -1}) sage: w = vector({1: -1, 3: 1}) sage: v + w (0, 0, 0, 0) - sage: (v+w).is_zero() + sage: (v + w).is_zero() True - sage: bool(v+w) + sage: bool(v + w) False """ @@ -1137,7 +1133,9 @@ cdef class Element(SageObject): We now create an ``Element`` class where we define ``_richcmp_`` and check that comparison works:: - sage: cython(''' # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython( + ....: ''' ....: from sage.structure.richcmp cimport rich_to_bool ....: from sage.structure.element cimport Element ....: cdef class FloatCmp(Element): @@ -1149,9 +1147,9 @@ cdef class Element(SageObject): ....: cdef float x2 = (<FloatCmp>other).x ....: return rich_to_bool(op, (x1 > x2) - (x1 < x2)) ....: ''') - sage: a = FloatCmp(1) # optional - sage.misc.cython - sage: b = FloatCmp(2) # optional - sage.misc.cython - sage: a <= b, b <= a # optional - sage.misc.cython + sage: a = FloatCmp(1) + sage: b = FloatCmp(2) + sage: a <= b, b <= a (True, False) """ # Obvious case @@ -1286,16 +1284,17 @@ cdef class Element(SageObject): EXAMPLES:: - sage: cython( # long time # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython( # long time ....: ''' ....: from sage.structure.element cimport Element ....: cdef class MyElement(Element): ....: cdef _add_long(self, long n): ....: return n ....: ''') - sage: e = MyElement(Parent()) # long time # optional - sage.misc.cython - sage: i = int(42) # optional - sage.misc.cython - sage: i + e, e + i # long time # optional - sage.misc.cython + sage: e = MyElement(Parent()) # long time + sage: i = int(42) + sage: i + e, e + i # long time (42, 42) """ return coercion_model.bin_op(self, n, add) @@ -1496,6 +1495,7 @@ cdef class Element(SageObject): :: + sage: # needs sage.combinat sage.modules sage: A = AlgebrasWithBasis(QQ).example(); A An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field @@ -1564,16 +1564,17 @@ cdef class Element(SageObject): EXAMPLES:: - sage: cython( # long time # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython( # long time ....: ''' ....: from sage.structure.element cimport Element ....: cdef class MyElement(Element): ....: cdef _mul_long(self, long n): ....: return n ....: ''') - sage: e = MyElement(Parent()) # long time # optional - sage.misc.cython - sage: i = int(42) # optional - sage.misc.cython - sage: i * e, e * i # long time # optional - sage.misc.cython + sage: e = MyElement(Parent()) # long time + sage: i = int(42) + sage: i * e, e * i # long time (42, 42) """ return coercion_model.bin_op(self, n, mul) @@ -1681,11 +1682,11 @@ cdef class Element(SageObject): sage: operator.truediv(2, 3) 2/3 - sage: operator.truediv(pi, 3) + sage: operator.truediv(pi, 3) # needs sage.symbolic 1/3*pi sage: x = polygen(QQ, 'x') - sage: K.<i> = NumberField(x^2 + 1) - sage: operator.truediv(2, K.ideal(i+1)) + sage: K.<i> = NumberField(x^2 + 1) # needs sage.rings.number_field + sage: operator.truediv(2, K.ideal(i + 1)) # needs sage.rings.number_field Fractional ideal (-i + 1) :: @@ -2000,6 +2001,7 @@ cdef class Element(SageObject): :: + sage: # needs sage.symbolic sage: (2/3)^I (2/3)^I sage: (2/3)^sqrt(2) @@ -2010,9 +2012,10 @@ cdef class Element(SageObject): (2/3)^(x^n + y^n + z^n) sage: (-7/11)^(tan(x)+exp(x)) (-7/11)^(e^x + tan(x)) + sage: float(1.2)**(1/2) 1.0954451150103321 - sage: complex(1,2)**(1/2) + sage: complex(1,2)**(1/2) # needs sage.rings.complex_double (1.272019649514069+0.786151377757423...j) TESTS:: @@ -2146,7 +2149,7 @@ def is_ModuleElement(x): sage: from sage.structure.element import is_ModuleElement sage: is_ModuleElement(2/3) True - sage: is_ModuleElement((QQ^3).0) + sage: is_ModuleElement((QQ^3).0) # needs sage.modules True sage: is_ModuleElement('a') False @@ -2189,6 +2192,7 @@ cdef class ElementWithCachedMethod(Element): category whose element and parent classes define cached methods. :: + sage: # needs sage.misc.cython sage: cython_code = ["from sage.structure.element cimport Element, ElementWithCachedMethod", ....: "from sage.structure.richcmp cimport richcmp", ....: "cdef class MyBrokenElement(Element):", @@ -2225,8 +2229,11 @@ cdef class ElementWithCachedMethod(Element): ....: "from sage.structure.parent cimport Parent", ....: "cdef class MyParent(Parent):", ....: " Element = MyElement"] - sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython - sage: cython_code = ["from sage.all import cached_method, cached_in_parent_method, Category, Objects", + sage: cython('\n'.join(cython_code)) + sage: cython_code = ["from sage.misc.cachefunc import cached_method", + ....: "from sage.misc.cachefunc import cached_in_parent_method", + ....: "from sage.categories.category import Category", + ....: "from sage.categories.objects import Objects", ....: "class MyCategory(Category):", ....: " @cached_method", ....: " def super_categories(self):", @@ -2245,21 +2252,22 @@ cdef class ElementWithCachedMethod(Element): ....: " @cached_method", ....: " def invert(self, x):", ....: " return -x"] - sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython - sage: C = MyCategory() # optional - sage.misc.cython - sage: P = MyParent(category=C) # optional - sage.misc.cython - sage: ebroken = MyBrokenElement(P, 5) # optional - sage.misc.cython - sage: e = MyElement(P, 5) # optional - sage.misc.cython + sage: cython('\n'.join(cython_code)) + sage: C = MyCategory() + sage: P = MyParent(category=C) + sage: ebroken = MyBrokenElement(P, 5) + sage: e = MyElement(P, 5) The cached methods inherited by ``MyElement`` works:: - sage: e.element_cache_test() # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: e.element_cache_test() <-5> - sage: e.element_cache_test() is e.element_cache_test() # optional - sage.misc.cython + sage: e.element_cache_test() is e.element_cache_test() True - sage: e.element_via_parent_test() # optional - sage.misc.cython + sage: e.element_via_parent_test() <-5> - sage: e.element_via_parent_test() is e.element_via_parent_test() # optional - sage.misc.cython + sage: e.element_via_parent_test() is e.element_via_parent_test() True The other element class can only inherit a @@ -2267,36 +2275,36 @@ cdef class ElementWithCachedMethod(Element): parent. In fact, equal elements share the cache, even if they are of different types:: - sage: e == ebroken # optional - sage.misc.cython + sage: e == ebroken # needs sage.misc.cython True - sage: type(e) == type(ebroken) # optional - sage.misc.cython + sage: type(e) == type(ebroken) # needs sage.misc.cython False - sage: ebroken.element_via_parent_test() is e.element_via_parent_test() # optional - sage.misc.cython + sage: ebroken.element_via_parent_test() is e.element_via_parent_test() # needs sage.misc.cython True However, the cache of the other inherited method breaks, although the method as such works:: - sage: ebroken.element_cache_test() # optional - sage.misc.cython + sage: ebroken.element_cache_test() # needs sage.misc.cython <-5> - sage: ebroken.element_cache_test() is ebroken.element_cache_test() # optional - sage.misc.cython + sage: ebroken.element_cache_test() is ebroken.element_cache_test() # needs sage.misc.cython False Since ``e`` and ``ebroken`` share the cache, when we empty it for one element it is empty for the other as well:: - sage: b = ebroken.element_via_parent_test() # optional - sage.misc.cython - sage: e.element_via_parent_test.clear_cache() # optional - sage.misc.cython - sage: b is ebroken.element_via_parent_test() # optional - sage.misc.cython + sage: b = ebroken.element_via_parent_test() # needs sage.misc.cython + sage: e.element_via_parent_test.clear_cache() # needs sage.misc.cython + sage: b is ebroken.element_via_parent_test() # needs sage.misc.cython False Note that the cache only breaks for elements that do no allow attribute assignment. A Python version of ``MyBrokenElement`` therefore allows for cached methods:: - sage: epython = MyPythonElement(P, 5) # optional - sage.misc.cython - sage: epython.element_cache_test() # optional - sage.misc.cython + sage: epython = MyPythonElement(P, 5) # needs sage.misc.cython + sage: epython.element_cache_test() # needs sage.misc.cython <-5> - sage: epython.element_cache_test() is epython.element_cache_test() # optional - sage.misc.cython + sage: epython.element_cache_test() is epython.element_cache_test() # needs sage.misc.cython True """ @@ -2313,7 +2321,9 @@ cdef class ElementWithCachedMethod(Element): EXAMPLES:: - sage: cython(''' # optional - sage.misc.cython + sage: # needs sage.misc.cython + sage: cython( + ....: ''' ....: from sage.structure.element cimport ElementWithCachedMethod ....: cdef class MyElement(ElementWithCachedMethod): ....: cdef public object x @@ -2325,7 +2335,10 @@ cdef class ElementWithCachedMethod(Element): ....: from sage.structure.parent cimport Parent ....: cdef class MyParent(Parent): ....: Element = MyElement - ....: from sage.all import cached_method, lazy_attribute, Category, Objects + ....: from sage.misc.cachefunc import cached_method + ....: from sage.misc.lazy_attribute import lazy_attribute + ....: from sage.categories.category import Category + ....: from sage.categories.objects import Objects ....: class MyCategory(Category): ....: @cached_method ....: def super_categories(self): @@ -2335,27 +2348,27 @@ cdef class ElementWithCachedMethod(Element): ....: def my_lazy_attr(self): ....: return 'lazy attribute of <%s>'%self.x ....: ''') - sage: C = MyCategory() # optional - sage.misc.cython - sage: P = MyParent(category=C) # optional - sage.misc.cython - sage: e = MyElement(P, 5) # optional - sage.misc.cython - sage: e.my_lazy_attr # optional - sage.misc.cython + sage: C = MyCategory() + sage: P = MyParent(category=C) + sage: e = MyElement(P, 5) + sage: e.my_lazy_attr 'lazy attribute of <5>' - sage: e.my_lazy_attr is e.my_lazy_attr # optional - sage.misc.cython + sage: e.my_lazy_attr is e.my_lazy_attr True """ try: - return self.__cached_methods[name] + return self._cached_methods[name] except KeyError: attr = getattr_from_other_class(self, self._parent.category().element_class, name) - self.__cached_methods[name] = attr + self._cached_methods[name] = attr return attr except TypeError: attr = getattr_from_other_class(self, self._parent.category().element_class, name) - self.__cached_methods = {name : attr} + self._cached_methods = {name : attr} return attr @@ -2452,8 +2465,8 @@ cdef class ModuleElementWithMutability(ModuleElement): """ EXAMPLES:: - sage: v = sage.modules.free_module_element.FreeModuleElement(QQ^3) - sage: type(v) + sage: v = sage.modules.free_module_element.FreeModuleElement(QQ^3) # needs sage.modules + sage: type(v) # needs sage.modules <class 'sage.modules.free_module_element.FreeModuleElement'> """ self._parent = parent @@ -2465,6 +2478,7 @@ cdef class ModuleElementWithMutability(ModuleElement): EXAMPLES:: + sage: # needs sage.modules sage: v = vector([1..5]); v (1, 2, 3, 4, 5) sage: v[1] = 10 @@ -2483,10 +2497,10 @@ cdef class ModuleElementWithMutability(ModuleElement): EXAMPLES:: - sage: v = vector(QQ['x,y'], [1..5]); v.is_mutable() + sage: v = vector(QQ['x,y'], [1..5]); v.is_mutable() # needs sage.modules True - sage: v.set_immutable() - sage: v.is_mutable() + sage: v.set_immutable() # needs sage.modules + sage: v.is_mutable() # needs sage.modules False """ return not self._is_immutable @@ -2498,10 +2512,10 @@ cdef class ModuleElementWithMutability(ModuleElement): EXAMPLES:: - sage: v = vector(QQ['x,y'], [1..5]); v.is_immutable() + sage: v = vector(QQ['x,y'], [1..5]); v.is_immutable() # needs sage.modules False - sage: v.set_immutable() - sage: v.is_immutable() + sage: v.set_immutable() # needs sage.modules + sage: v.is_immutable() # needs sage.modules True """ return self._is_immutable @@ -2549,9 +2563,9 @@ cdef class MonoidElement(Element): EXAMPLES:: - sage: G = SymmetricGroup(4) # optional - sage.groups - sage: g = G([2, 3, 4, 1]) # optional - sage.groups - sage: g.powers(4) # optional - sage.groups + sage: G = SymmetricGroup(4) # needs sage.groups + sage: g = G([2, 3, 4, 1]) # needs sage.groups + sage: g.powers(4) # needs sage.groups [(), (1,2,3,4), (1,3)(2,4), (1,4,3,2)] """ if n < 0: @@ -2560,7 +2574,7 @@ cdef class MonoidElement(Element): return [] x = self._parent.one() l = [x] - for i in xrange(n - 1): + for i in range(n - 1): x = x * self l.append(x) return l @@ -2680,22 +2694,22 @@ cdef class RingElement(ModuleElement): True sage: p(a,200) * p(a,-64) == p(a,136) True - sage: p(2, 1/2) + sage: p(2, 1/2) # needs sage.symbolic sqrt(2) TESTS: These are not testing this code, but they are probably good to have around:: - sage: 2r**(SR(2)-1-1r) + sage: 2r**(SR(2)-1-1r) # needs sage.symbolic 1 - sage: 2r^(1/2) + sage: 2r^(1/2) # needs sage.symbolic sqrt(2) - Exponent overflow should throw an OverflowError (:trac:`2956`):: + Exponent overflow should throw an :class:`OverflowError` (:trac:`2956`):: - sage: K.<x,y> = AA[] - sage: x^(2^64 + 12345) + sage: K.<x,y> = AA[] # needs sage.rings.number_field + sage: x^(2^64 + 12345) # needs sage.rings.number_field Traceback (most recent call last): ... OverflowError: exponent overflow (2147483648) @@ -2726,7 +2740,7 @@ cdef class RingElement(ModuleElement): return [] x = self._parent.one() l = [x] - for i in xrange(n - 1): + for i in range(n - 1): x = x * self l.append(x) return l @@ -2793,12 +2807,12 @@ cdef class RingElement(ModuleElement): :: sage: R.<x> = GF(7)[] - sage: divmod(x^2, x-1) + sage: divmod(x^2, x - 1) (x + 1, 1) :: - sage: divmod(22./7, RR(pi)) + sage: divmod(22./7, RR(pi)) # needs sage.symbolic (1.00040249943477, 0.000000000000000) """ try: @@ -2838,8 +2852,8 @@ cdef class RingElement(ModuleElement): sage: a = QQ(0) sage: a.is_nilpotent() True - sage: m = matrix(QQ,3,[[3,2,3],[9,0,3],[-9,0,-3]]) - sage: m.is_nilpotent() + sage: m = matrix(QQ, 3, [[3,2,3], [9,0,3], [-9,0,-3]]) # needs sage.modules + sage: m.is_nilpotent() # needs sage.modules Traceback (most recent call last): ... AttributeError: ... object has no attribute 'is_nilpotent' @@ -2882,6 +2896,7 @@ cdef class RingElement(ModuleElement): For polynomial rings, prime is the same as irreducible:: + sage: # needs sage.libs.singular sage: R.<x,y> = QQ[] sage: x.is_prime() True @@ -2896,13 +2911,14 @@ cdef class RingElement(ModuleElement): For the Gaussian integers:: + sage: # needs sage.rings.number_field sage: K.<i> = QuadraticField(-1) sage: ZI = K.ring_of_integers() sage: ZI(3).is_prime() True sage: ZI(5).is_prime() False - sage: ZI(2+i).is_prime() + sage: ZI(2 + i).is_prime() True sage: ZI(0).is_prime() False @@ -2921,7 +2937,7 @@ cdef class RingElement(ModuleElement): sage: (-2).is_prime() False - sage: RingElement.is_prime(-2) + sage: RingElement.is_prime(-2) # needs sage.libs.pari True Similarly, @@ -2929,7 +2945,8 @@ cdef class RingElement(ModuleElement): redefines :meth:`is_prime` to determine primality in the ring of integers:: - sage: (1+i).is_prime() + sage: # needs sage.rings.number_field + sage: (1 + i).is_prime() True sage: K(5).is_prime() False @@ -2979,6 +2996,7 @@ cdef class CommutativeRingElement(RingElement): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: F = GF(25) sage: x = F.gen() sage: z = F.zero() @@ -3011,16 +3029,16 @@ cdef class CommutativeRingElement(RingElement): sage: P.<x> = PolynomialRing(QQ) sage: x.divides(x^2) True - sage: x.divides(x^2+2) + sage: x.divides(x^2 + 2) False - sage: (x^2+2).divides(x) + sage: (x^2 + 2).divides(x) False sage: P.<x> = PolynomialRing(ZZ) sage: x.divides(x^2) True - sage: x.divides(x^2+2) + sage: x.divides(x^2 + 2) False - sage: (x^2+2).divides(x) + sage: (x^2 + 2).divides(x) False :trac:`5347` has been fixed:: @@ -3058,7 +3076,8 @@ cdef class CommutativeRingElement(RingElement): sage: Zmod(5)(1).divides(Zmod(2)(1)) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Ring of integers modulo 5' and 'Ring of integers modulo 2' + TypeError: no common canonical parent for objects with parents: + 'Ring of integers modulo 5' and 'Ring of integers modulo 2' sage: Zmod(35)(4).divides(Zmod(7)(1)) True sage: Zmod(35)(7).divides(Zmod(7)(1)) @@ -3152,22 +3171,22 @@ cdef class CommutativeRingElement(RingElement): and an ideal:: sage: R.<x,y,z> = PolynomialRing(QQ, 3) - sage: (x^2 + y^2 + z^2).mod(x+y+z) + sage: (x^2 + y^2 + z^2).mod(x + y + z) # needs sage.libs.singular 2*y^2 + 2*y*z + 2*z^2 Notice above that `x` is eliminated. In the next example, both `y` and `z` are eliminated:: - sage: (x^2 + y^2 + z^2).mod( (x - y, y - z) ) + sage: (x^2 + y^2 + z^2).mod( (x - y, y - z) ) # needs sage.libs.singular 3*z^2 sage: f = (x^2 + y^2 + z^2)^2; f x^4 + 2*x^2*y^2 + y^4 + 2*x^2*z^2 + 2*y^2*z^2 + z^4 - sage: f.mod( (x - y, y - z) ) + sage: f.mod( (x - y, y - z) ) # needs sage.libs.singular 9*z^4 In this example `y` is eliminated:: - sage: (x^2 + y^2 + z^2).mod( (x^3, y - z) ) + sage: (x^2 + y^2 + z^2).mod( (x^3, y - z) ) # needs sage.libs.singular x^2 + 2*z^2 """ from sage.rings.ideal import is_Ideal @@ -3225,45 +3244,53 @@ cdef class CommutativeRingElement(RingElement): def sqrt(self, extend=True, all=False, name=None): """ - It computes the square root. + Compute the square root. INPUT: - - ``extend`` - Whether to make a ring extension containing a square root if ``self`` is not a square (default: ``True``) + - ``extend`` -- boolean (default: ``True``); whether to make a ring + extension containing a square root if ``self`` is not a square - - ``all`` - Whether to return a list of all square roots or just a square root (default: False) + - ``all`` -- boolean (default: ``False``); whether to return a list of + all square roots or just a square root - - ``name`` - Required when ``extend=True`` and ``self`` is not a square. This will be the name of the generator extension. + - ``name`` -- required when ``extend=True`` and ``self`` is not a + square. This will be the name of the generator of the extension. OUTPUT: - - if ``all=False`` it returns a square root. (throws an error if ``extend=False`` and ``self`` is not a square) + - if ``all=False``, a square root; raises an error if ``extend=False`` + and ``self`` is not a square - - if ``all=True`` it returns a list of all the square roots (could be empty if ``extend=False`` and ``self`` is not a square) + - if ``all=True``, a list of all the square roots (empty if + ``extend=False`` and ``self`` is not a square) ALGORITHM: - It uses ``is_square(root=true)`` for the hard part of the work, the rest is just wrapper code. + It uses ``is_square(root=true)`` for the hard part of the work, the rest + is just wrapper code. EXAMPLES:: + sage: # needs sage.libs.pari sage: R.<x> = ZZ[] sage: (x^2).sqrt() x - sage: f=x^2-4*x+4; f.sqrt(all=True) + sage: f = x^2 - 4*x + 4; f.sqrt(all=True) [x - 2, -x + 2] - sage: sqrtx=x.sqrt(name="y"); sqrtx + sage: sqrtx = x.sqrt(name="y"); sqrtx y sage: sqrtx^2 x - sage: x.sqrt(all=true,name="y") + sage: x.sqrt(all=true, name="y") [y, -y] - sage: x.sqrt(extend=False,all=True) + sage: x.sqrt(extend=False, all=True) [] sage: x.sqrt() Traceback (most recent call last): ... - TypeError: Polynomial is not a square. You must specify the name of the square root when using the default extend = True + TypeError: Polynomial is not a square. You must specify the name + of the square root when using the default extend = True sage: x.sqrt(extend=False) Traceback (most recent call last): ... @@ -3271,9 +3298,10 @@ cdef class CommutativeRingElement(RingElement): TESTS:: - sage: f = (x+3)^2; f.sqrt() + sage: # needs sage.libs.pari + sage: f = (x + 3)^2; f.sqrt() x + 3 - sage: f = (x+3)^2; f.sqrt(all=True) + sage: f = (x + 3)^2; f.sqrt(all=True) [x + 3, -x - 3] sage: f = (x^2 - x + 3)^2; f.sqrt() x^2 - x + 3 @@ -3283,6 +3311,7 @@ cdef class CommutativeRingElement(RingElement): sage: g.sqrt()^2 == g True + sage: # needs sage.libs.pari sage: R.<x> = GF(250037)[] sage: f = x^2/(x+1)^2; f.sqrt() x/(x + 1) @@ -3298,14 +3327,15 @@ cdef class CommutativeRingElement(RingElement): y sage: sqrtx^2 1/x - sage: (1/x).sqrt(all=true,name="y") + sage: (1/x).sqrt(all=true, name="y") [y, -y] - sage: (1/x).sqrt(extend=False,all=True) + sage: (1/x).sqrt(extend=False, all=True) [] sage: (1/(x^2-1)).sqrt() Traceback (most recent call last): ... - TypeError: Polynomial is not a square. You must specify the name of the square root when using the default extend = True + TypeError: Polynomial is not a square. You must specify the name + of the square root when using the default extend = True sage: (1/(x^2-3)).sqrt(extend=False) Traceback (most recent call last): ... @@ -3353,6 +3383,19 @@ cdef class Expression(CommutativeRingElement): r""" Abstract base class for :class:`~sage.symbolic.expression.Expression`. + + This class is defined for the purpose of :func:`isinstance` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: isinstance(SR.var('y'), sage.structure.element.Expression) # needs sage.symbolic + True + + By design, there is a unique direct subclass:: + + sage: len(sage.structure.element.Expression.__subclasses__()) <= 1 + True """ pass @@ -3383,195 +3426,259 @@ cdef class Vector(ModuleElementWithMutability): Here we test (vector * vector) multiplication:: - sage: parent(vector(ZZ,[1,2])*vector(ZZ,[1,2])) + sage: # needs sage.modules + sage: parent(vector(ZZ, [1,2]) * vector(ZZ, [1,2])) Integer Ring - sage: parent(vector(ZZ,[1,2])*vector(QQ,[1,2])) + sage: parent(vector(ZZ, [1,2]) * vector(QQ, [1,2])) Rational Field - sage: parent(vector(QQ,[1,2])*vector(ZZ,[1,2])) + sage: parent(vector(QQ, [1,2]) * vector(ZZ, [1,2])) Rational Field - sage: parent(vector(QQ,[1,2])*vector(QQ,[1,2])) + sage: parent(vector(QQ, [1,2]) * vector(QQ, [1,2])) Rational Field - sage: parent(vector(QQ,[1,2,3,4])*vector(ZZ['x'],[1,2,3,4])) + sage: parent(vector(QQ, [1,2,3,4]) * vector(ZZ['x'], [1,2,3,4])) # needs sage.modules Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x'],[1,2,3,4])*vector(QQ,[1,2,3,4])) + sage: parent(vector(ZZ['x'], [1,2,3,4]) * vector(QQ, [1,2,3,4])) # needs sage.modules Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(QQ,[1,2,3,4])*vector(ZZ['x']['y'],[1,2,3,4])) + sage: parent(vector(QQ, [1,2,3,4]) * vector(ZZ['x']['y'], [1,2,3,4])) # needs sage.modules Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x']['y'],[1,2,3,4])*vector(QQ,[1,2,3,4])) + sage: parent(vector(ZZ['x']['y'], [1,2,3,4]) * vector(QQ, [1,2,3,4])) # needs sage.modules Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(QQ['x'],[1,2,3,4])*vector(ZZ['x']['y'],[1,2,3,4])) + sage: parent(vector(QQ['x'], [1,2,3,4]) * vector(ZZ['x']['y'], [1,2,3,4])) # needs sage.modules Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x']['y'],[1,2,3,4])*vector(QQ['x'],[1,2,3,4])) + sage: parent(vector(ZZ['x']['y'], [1,2,3,4]) * vector(QQ['x'], [1,2,3,4])) # needs sage.modules Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(QQ['y'],[1,2,3,4])*vector(ZZ['x']['y'],[1,2,3,4])) + sage: parent(vector(QQ['y'], [1,2,3,4]) * vector(ZZ['x']['y'], [1,2,3,4])) # needs sage.modules Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x']['y'],[1,2,3,4])*vector(QQ['y'],[1,2,3,4])) + sage: parent(vector(ZZ['x']['y'], [1,2,3,4]) * vector(QQ['y'], [1,2,3,4])) # needs sage.modules Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x'],[1,2,3,4])*vector(ZZ['y'],[1,2,3,4])) + sage: # needs sage.modules + sage: parent(vector(ZZ['x'], [1,2,3,4]) * vector(ZZ['y'], [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Integer Ring' - sage: parent(vector(ZZ['x'],[1,2,3,4])*vector(QQ['y'],[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and + 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Integer Ring' + sage: parent(vector(ZZ['x'], [1,2,3,4]) * vector(QQ['y'], [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' - sage: parent(vector(QQ['x'],[1,2,3,4])*vector(ZZ['y'],[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and + 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' + sage: parent(vector(QQ['x'], [1,2,3,4]) * vector(ZZ['y'], [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Integer Ring' - sage: parent(vector(QQ['x'],[1,2,3,4])*vector(QQ['y'],[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and + 'Ambient free module of rank 4 over the integral domain Univariate Polynomial Ring in y over Integer Ring' + sage: parent(vector(QQ['x'], [1,2,3,4]) * vector(QQ['y'], [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and + 'Ambient free module of rank 4 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' Here we test (vector * matrix) multiplication:: - sage: parent(vector(ZZ,[1,2])*matrix(ZZ,2,2,[1,2,3,4])) + sage: # needs sage.modules + sage: parent(vector(ZZ, [1,2]) * matrix(ZZ, 2, 2, [1,2,3,4])) Ambient free module of rank 2 over the principal ideal domain Integer Ring - sage: parent(vector(QQ,[1,2])*matrix(ZZ,2,2,[1,2,3,4])) + sage: parent(vector(QQ, [1,2]) * matrix(ZZ, 2, 2, [1,2,3,4])) Vector space of dimension 2 over Rational Field - sage: parent(vector(ZZ,[1,2])*matrix(QQ,2,2,[1,2,3,4])) + sage: parent(vector(ZZ, [1,2]) * matrix(QQ, 2, 2, [1,2,3,4])) Vector space of dimension 2 over Rational Field - sage: parent(vector(QQ,[1,2])*matrix(QQ,2,2,[1,2,3,4])) + sage: parent(vector(QQ, [1,2]) * matrix(QQ, 2, 2, [1,2,3,4])) Vector space of dimension 2 over Rational Field - sage: parent(vector(QQ,[1,2])*matrix(ZZ['x'],2,2,[1,2,3,4])) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x'],[1,2])*matrix(QQ,2,2,[1,2,3,4])) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field - - sage: parent(vector(QQ,[1,2])*matrix(ZZ['x']['y'],2,2,[1,2,3,4])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x']['y'],[1,2])*matrix(QQ,2,2,[1,2,3,4])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(vector(QQ['x'],[1,2])*matrix(ZZ['x']['y'],2,2,[1,2,3,4])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x']['y'],[1,2])*matrix(QQ['x'],2,2,[1,2,3,4])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(vector(QQ['y'],[1,2])*matrix(ZZ['x']['y'],2,2,[1,2,3,4])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x']['y'],[1,2])*matrix(QQ['y'],2,2,[1,2,3,4])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(vector(ZZ['x'],[1,2])*matrix(ZZ['y'],2,2,[1,2,3,4])) + sage: parent(vector(QQ, [1,2]) * matrix(ZZ['x'], 2, 2, [1,2,3,4])) # needs sage.modules + Ambient free module of rank 2 + over the principal ideal domain Univariate Polynomial Ring in x over Rational Field + sage: parent(vector(ZZ['x'], [1,2]) * matrix(QQ, 2, 2, [1,2,3,4])) # needs sage.modules + Ambient free module of rank 2 + over the principal ideal domain Univariate Polynomial Ring in x over Rational Field + + sage: parent(vector(QQ, [1,2]) * matrix(ZZ['x']['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(vector(ZZ['x']['y'], [1,2]) * matrix(QQ, 2, 2, [1,2,3,4])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(vector(QQ['x'], [1,2]) * matrix(ZZ['x']['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(vector(ZZ['x']['y'], [1,2]) * matrix(QQ['x'], 2, 2, [1,2,3,4])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(vector(QQ['y'], [1,2]) * matrix(ZZ['x']['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(vector(ZZ['x']['y'], [1,2]) * matrix(QQ['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: # needs sage.modules + sage: parent(vector(ZZ['x'], [1,2]) * matrix(ZZ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' - sage: parent(vector(ZZ['x'],[1,2])*matrix(QQ['y'],2,2,[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' + sage: parent(vector(ZZ['x'], [1,2]) * matrix(QQ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' - sage: parent(vector(QQ['x'],[1,2])*matrix(ZZ['y'],2,2,[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' + sage: parent(vector(QQ['x'], [1,2]) * matrix(ZZ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' - sage: parent(vector(QQ['x'],[1,2])*matrix(QQ['y'],2,2,[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' + sage: parent(vector(QQ['x'], [1,2]) * matrix(QQ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' Here we test (vector * scalar) multiplication:: - sage: parent(vector(ZZ,[1,2])*ZZ(1)) + sage: # needs sage.modules + sage: parent(vector(ZZ, [1,2]) * ZZ(1)) Ambient free module of rank 2 over the principal ideal domain Integer Ring - sage: parent(vector(QQ,[1,2])*ZZ(1)) + sage: parent(vector(QQ, [1,2]) * ZZ(1)) Vector space of dimension 2 over Rational Field - sage: parent(vector(ZZ,[1,2])*QQ(1)) + sage: parent(vector(ZZ, [1,2]) * QQ(1)) Vector space of dimension 2 over Rational Field - sage: parent(vector(QQ,[1,2])*QQ(1)) + sage: parent(vector(QQ, [1,2]) * QQ(1)) Vector space of dimension 2 over Rational Field - sage: parent(vector(QQ,[1,2])*ZZ['x'](1)) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x'],[1,2])*QQ(1)) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field - - sage: parent(vector(QQ,[1,2])*ZZ['x']['y'](1)) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x']['y'],[1,2])*QQ(1)) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(vector(QQ['x'],[1,2])*ZZ['x']['y'](1)) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x']['y'],[1,2])*QQ['x'](1)) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(vector(QQ['y'],[1,2])*ZZ['x']['y'](1)) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(vector(ZZ['x']['y'],[1,2])*QQ['y'](1)) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(vector(ZZ['x'],[1,2])*ZZ['y'](1)) + sage: parent(vector(QQ, [1,2]) * ZZ['x'](1)) # needs sage.modules + Ambient free module of rank 2 + over the principal ideal domain Univariate Polynomial Ring in x over Rational Field + sage: parent(vector(ZZ['x'], [1,2]) * QQ(1)) # needs sage.modules + Ambient free module of rank 2 + over the principal ideal domain Univariate Polynomial Ring in x over Rational Field + + sage: parent(vector(QQ, [1,2]) * ZZ['x']['y'](1)) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(vector(ZZ['x']['y'], [1,2]) * QQ(1)) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(vector(QQ['x'], [1,2]) * ZZ['x']['y'](1)) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(vector(ZZ['x']['y'], [1,2]) * QQ['x'](1)) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(vector(QQ['y'], [1,2]) * ZZ['x']['y'](1)) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(vector(ZZ['x']['y'], [1,2]) * QQ['y'](1)) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: # needs sage.modules + sage: parent(vector(ZZ['x'], [1,2]) * ZZ['y'](1)) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and 'Univariate Polynomial Ring in y over Integer Ring' - sage: parent(vector(ZZ['x'],[1,2])*QQ['y'](1)) + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and + 'Univariate Polynomial Ring in y over Integer Ring' + sage: parent(vector(ZZ['x'], [1,2]) * QQ['y'](1)) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and 'Univariate Polynomial Ring in y over Rational Field' - sage: parent(vector(QQ['x'],[1,2])*ZZ['y'](1)) + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in x over Integer Ring' and + 'Univariate Polynomial Ring in y over Rational Field' + sage: parent(vector(QQ['x'], [1,2]) * ZZ['y'](1)) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and 'Univariate Polynomial Ring in y over Integer Ring' - sage: parent(vector(QQ['x'],[1,2])*QQ['y'](1)) + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and + 'Univariate Polynomial Ring in y over Integer Ring' + sage: parent(vector(QQ['x'], [1,2]) * QQ['y'](1)) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and 'Univariate Polynomial Ring in y over Rational Field' + TypeError: unsupported operand parent(s) for *: + 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field' and + 'Univariate Polynomial Ring in y over Rational Field' Here we test (scalar * vector) multiplication:: - sage: parent(ZZ(1)*vector(ZZ,[1,2])) + sage: # needs sage.modules + sage: parent(ZZ(1) * vector(ZZ, [1,2])) Ambient free module of rank 2 over the principal ideal domain Integer Ring - sage: parent(QQ(1)*vector(ZZ,[1,2])) + sage: parent(QQ(1) * vector(ZZ, [1,2])) Vector space of dimension 2 over Rational Field - sage: parent(ZZ(1)*vector(QQ,[1,2])) + sage: parent(ZZ(1) * vector(QQ, [1,2])) Vector space of dimension 2 over Rational Field - sage: parent(QQ(1)*vector(QQ,[1,2])) + sage: parent(QQ(1) * vector(QQ, [1,2])) Vector space of dimension 2 over Rational Field - sage: parent(QQ(1)*vector(ZZ['x'],[1,2])) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field - sage: parent(ZZ['x'](1)*vector(QQ,[1,2])) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field - - sage: parent(QQ(1)*vector(ZZ['x']['y'],[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(ZZ['x']['y'](1)*vector(QQ,[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(QQ['x'](1)*vector(ZZ['x']['y'],[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(ZZ['x']['y'](1)*vector(QQ['x'],[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(QQ['y'](1)*vector(ZZ['x']['y'],[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(ZZ['x']['y'](1)*vector(QQ['y'],[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(ZZ['x'](1)*vector(ZZ['y'],[1,2])) + sage: parent(QQ(1) * vector(ZZ['x'], [1,2])) # needs sage.modules + Ambient free module of rank 2 + over the principal ideal domain Univariate Polynomial Ring in x over Rational Field + sage: parent(ZZ['x'](1) * vector(QQ, [1,2])) # needs sage.modules + Ambient free module of rank 2 + over the principal ideal domain Univariate Polynomial Ring in x over Rational Field + + sage: parent(QQ(1) * vector(ZZ['x']['y'], [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(ZZ['x']['y'](1) * vector(QQ, [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(QQ['x'](1) * vector(ZZ['x']['y'], [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(ZZ['x']['y'](1) * vector(QQ['x'], [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(QQ['y'](1) * vector(ZZ['x']['y'], [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(ZZ['x']['y'](1) * vector(QQ['y'], [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: # needs sage.modules + sage: parent(ZZ['x'](1) * vector(ZZ['y'], [1,2])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Univariate Polynomial Ring in x over Integer Ring' and 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Integer Ring' - sage: parent(ZZ['x'](1)*vector(QQ['y'],[1,2])) + TypeError: unsupported operand parent(s) for *: + 'Univariate Polynomial Ring in x over Integer Ring' and + 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Integer Ring' + sage: parent(ZZ['x'](1) * vector(QQ['y'], [1,2])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Univariate Polynomial Ring in x over Integer Ring' and 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' - sage: parent(QQ['x'](1)*vector(ZZ['y'],[1,2])) + TypeError: unsupported operand parent(s) for *: + 'Univariate Polynomial Ring in x over Integer Ring' and + 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' + sage: parent(QQ['x'](1) * vector(ZZ['y'], [1,2])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Univariate Polynomial Ring in x over Rational Field' and 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Integer Ring' - sage: parent(QQ['x'](1)*vector(QQ['y'],[1,2])) + TypeError: unsupported operand parent(s) for *: + 'Univariate Polynomial Ring in x over Rational Field' and + 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Integer Ring' + sage: parent(QQ['x'](1) * vector(QQ['y'], [1,2])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Univariate Polynomial Ring in x over Rational Field' and 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' + TypeError: unsupported operand parent(s) for *: + 'Univariate Polynomial Ring in x over Rational Field' and + 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' """ if have_same_parent(left, right): return (<Vector>left)._dot_product_(<Vector>right) @@ -3592,6 +3699,7 @@ cdef class Vector(ModuleElementWithMutability): TESTS:: + sage: # needs sage.modules sage: A = matrix([[1, 2], [0, 3]]) sage: b = vector([0, 1]) sage: x = b / A; x @@ -3626,32 +3734,36 @@ cdef class Vector(ModuleElementWithMutability): EXAMPLES:: + sage: # optional - magma, needs sage.modules sage: v = vector([1,2,3]) - sage: v._magma_init_(magma) # optional - magma + sage: v._magma_init_(magma) '_sage_[...]![1,2,3]' - sage: mv = magma(v); mv # optional - magma + sage: mv = magma(v); mv (1 2 3) - sage: mv.Type() # optional - magma + sage: mv.Type() ModTupRngElt - sage: mv.Parent() # optional - magma + sage: mv.Parent() Full RSpace of degree 3 over Integer Ring + sage: # optional - magma, needs sage.modules sage: v = vector(QQ, [1/2, 3/4, 5/6]) - sage: mv = magma(v); mv # optional - magma + sage: mv = magma(v); mv (1/2 3/4 5/6) - sage: mv.Type() # optional - magma + sage: mv.Type() ModTupFldElt - sage: mv.Parent() # optional - magma + sage: mv.Parent() Full Vector space of degree 3 over Rational Field A more demanding example:: + sage: # optional - magma, needs sage.modules sage: R.<x,y,z> = QQ[] sage: v = vector([x^3, y, 2/3*z + x/y]) - sage: magma(v) # optional - magma + sage: magma(v) ( x^3 y (2/3*y*z + x)/y) - sage: magma(v).Parent() # optional - magma - Full Vector space of degree 3 over Multivariate rational function field of rank 3 over Rational Field + sage: magma(v).Parent() + Full Vector space of degree 3 + over Multivariate rational function field of rank 3 over Rational Field """ V = magma(self._parent) v = [x._magma_init_(magma) for x in self.list()] @@ -3685,210 +3797,277 @@ cdef class Matrix(ModuleElement): Here we test (matrix * matrix) multiplication:: - sage: parent(matrix(ZZ,2,2,[1,2,3,4])*matrix(ZZ,2,2,[1,2,3,4])) + sage: # needs sage.modules + sage: parent(matrix(ZZ, 2, 2, [1,2,3,4]) * matrix(ZZ, 2, 2, [1,2,3,4])) Full MatrixSpace of 2 by 2 dense matrices over Integer Ring - sage: parent(matrix(QQ,2,2,[1,2,3,4])*matrix(ZZ,2,2,[1,2,3,4])) + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * matrix(ZZ, 2, 2, [1,2,3,4])) Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: parent(matrix(ZZ,2,2,[1,2,3,4])*matrix(QQ,2,2,[1,2,3,4])) + sage: parent(matrix(ZZ, 2, 2, [1,2,3,4]) * matrix(QQ, 2, 2, [1,2,3,4])) Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: parent(matrix(QQ,2,2,[1,2,3,4])*matrix(QQ,2,2,[1,2,3,4])) + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * matrix(QQ, 2, 2, [1,2,3,4])) Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: parent(matrix(QQ,2,2,[1,2,3,4])*matrix(ZZ['x'],2,2,[1,2,3,4])) + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * matrix(ZZ['x'], 2, 2, [1,2,3,4])) # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x'],2,2,[1,2,3,4])*matrix(QQ,2,2,[1,2,3,4])) + sage: parent(matrix(ZZ['x'], 2, 2, [1,2,3,4]) * matrix(QQ, 2, 2, [1,2,3,4])) # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(QQ,2,2,[1,2,3,4])*matrix(ZZ['x']['y'],2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x']['y'],2,2,[1,2,3,4])*matrix(QQ,2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(matrix(QQ['x'],2,2,[1,2,3,4])*matrix(ZZ['x']['y'],2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x']['y'],2,2,[1,2,3,4])*matrix(QQ['x'],2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(matrix(QQ['y'],2,2,[1,2,3,4])*matrix(ZZ['x']['y'],2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x']['y'],2,2,[1,2,3,4])*matrix(QQ['y'],2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(matrix(ZZ['x'],2,2,[1,2,3,4])*matrix(ZZ['y'],2,2,[1,2,3,4])) + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * matrix(ZZ['x']['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(matrix(ZZ['x']['y'], 2, 2, [1,2,3,4]) * matrix(QQ, 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(matrix(QQ['x'], 2, 2, [1,2,3,4]) * matrix(ZZ['x']['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(matrix(ZZ['x']['y'], 2, 2, [1,2,3,4]) * matrix(QQ['x'], 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(matrix(QQ['y'], 2, 2, [1,2,3,4]) * matrix(ZZ['x']['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(matrix(ZZ['x']['y'], 2, 2, [1,2,3,4]) * matrix(QQ['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: # needs sage.modules + sage: parent(matrix(ZZ['x'], 2, 2, [1,2,3,4]) * matrix(ZZ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' - sage: parent(matrix(ZZ['x'],2,2,[1,2,3,4])*matrix(QQ['y'],2,2,[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' + sage: parent(matrix(ZZ['x'], 2, 2, [1,2,3,4]) * matrix(QQ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' - sage: parent(matrix(QQ['x'],2,2,[1,2,3,4])*matrix(ZZ['y'],2,2,[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' + sage: parent(matrix(QQ['x'], 2, 2, [1,2,3,4]) * matrix(ZZ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' - sage: parent(matrix(QQ['x'],2,2,[1,2,3,4])*matrix(QQ['y'],2,2,[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' + sage: parent(matrix(QQ['x'], 2, 2, [1,2,3,4]) * matrix(QQ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' We test that the bug reported in :trac:`27352` has been fixed:: - sage: A = matrix(QQ, [[1, 2], [-1, 0], [1, 1]]) - sage: B = matrix(QQ, [[0, 4], [1, -1], [1, 2]]) - sage: A*B + sage: A = matrix(QQ, [[1, 2], [-1, 0], [1, 1]]) # needs sage.modules + sage: B = matrix(QQ, [[0, 4], [1, -1], [1, 2]]) # needs sage.modules + sage: A * B # needs sage.modules Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 3 by 2 dense matrices over Rational Field' and 'Full MatrixSpace of 3 by 2 dense matrices over Rational Field' + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 3 by 2 dense matrices over Rational Field' and 'Full MatrixSpace of 3 by 2 dense matrices over Rational Field' Here we test (matrix * vector) multiplication:: - sage: parent(matrix(ZZ,2,2,[1,2,3,4])*vector(ZZ,[1,2])) + sage: # needs sage.modules + sage: parent(matrix(ZZ, 2, 2, [1,2,3,4]) * vector(ZZ, [1,2])) Ambient free module of rank 2 over the principal ideal domain Integer Ring - sage: parent(matrix(QQ,2,2,[1,2,3,4])*vector(ZZ,[1,2])) + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * vector(ZZ, [1,2])) Vector space of dimension 2 over Rational Field - sage: parent(matrix(ZZ,2,2,[1,2,3,4])*vector(QQ,[1,2])) + sage: parent(matrix(ZZ, 2, 2, [1,2,3,4]) * vector(QQ, [1,2])) Vector space of dimension 2 over Rational Field - sage: parent(matrix(QQ,2,2,[1,2,3,4])*vector(QQ,[1,2])) + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * vector(QQ, [1,2])) Vector space of dimension 2 over Rational Field - sage: parent(matrix(QQ,2,2,[1,2,3,4])*vector(ZZ['x'],[1,2])) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x'],2,2,[1,2,3,4])*vector(QQ,[1,2])) - Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field - - sage: parent(matrix(QQ,2,2,[1,2,3,4])*vector(ZZ['x']['y'],[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x']['y'],2,2,[1,2,3,4])*vector(QQ,[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(matrix(QQ['x'],2,2,[1,2,3,4])*vector(ZZ['x']['y'],[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x']['y'],2,2,[1,2,3,4])*vector(QQ['x'],[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(matrix(QQ['y'],2,2,[1,2,3,4])*vector(ZZ['x']['y'],[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x']['y'],2,2,[1,2,3,4])*vector(QQ['y'],[1,2])) - Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(matrix(ZZ['x'],2,2,[1,2,3,4])*vector(ZZ['y'],[1,2])) + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * vector(ZZ['x'], [1,2])) # needs sage.modules + Ambient free module of rank 2 over the principal ideal domain + Univariate Polynomial Ring in x over Rational Field + sage: parent(matrix(ZZ['x'], 2, 2, [1,2,3,4]) * vector(QQ, [1,2])) # needs sage.modules + Ambient free module of rank 2 over the principal ideal domain + Univariate Polynomial Ring in x over Rational Field + + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * vector(ZZ['x']['y'], [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(matrix(ZZ['x']['y'], 2, 2, [1,2,3,4]) * vector(QQ, [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(matrix(QQ['x'], 2, 2, [1,2,3,4]) * vector(ZZ['x']['y'], [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(matrix(ZZ['x']['y'], 2, 2, [1,2,3,4]) * vector(QQ['x'], [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(matrix(QQ['y'], 2, 2, [1,2,3,4]) * vector(ZZ['x']['y'], [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(matrix(ZZ['x']['y'], 2, 2, [1,2,3,4]) * vector(QQ['y'], [1,2])) # needs sage.modules + Ambient free module of rank 2 over the integral domain + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: # needs sage.modules + sage: parent(matrix(ZZ['x'], 2, 2, [1,2,3,4]) * vector(ZZ['y'], [1,2])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Integer Ring' - sage: parent(matrix(ZZ['x'],2,2,[1,2,3,4])*vector(QQ['y'],[1,2])) + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and + 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Integer Ring' + sage: parent(matrix(ZZ['x'], 2, 2, [1,2,3,4]) * vector(QQ['y'], [1,2])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' - sage: parent(matrix(QQ['x'],2,2,[1,2,3,4])*vector(ZZ['y'],[1,2])) + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and + 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' + sage: parent(matrix(QQ['x'], 2, 2, [1,2,3,4]) * vector(ZZ['y'], [1,2])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Integer Ring' - sage: parent(matrix(QQ['x'],2,2,[1,2,3,4])*vector(QQ['y'],[1,2])) + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and + 'Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in y over Integer Ring' + sage: parent(matrix(QQ['x'], 2, 2, [1,2,3,4]) * vector(QQ['y'], [1,2])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and + 'Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field' Here we test (matrix * scalar) multiplication:: - sage: parent(matrix(ZZ,2,2,[1,2,3,4])*ZZ(1)) + sage: # needs sage.modules + sage: parent(matrix(ZZ, 2, 2, [1,2,3,4]) * ZZ(1)) Full MatrixSpace of 2 by 2 dense matrices over Integer Ring - sage: parent(matrix(QQ,2,2,[1,2,3,4])*ZZ(1)) + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * ZZ(1)) Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: parent(matrix(ZZ,2,2,[1,2,3,4])*QQ(1)) + sage: parent(matrix(ZZ, 2, 2, [1,2,3,4]) * QQ(1)) Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: parent(matrix(QQ,2,2,[1,2,3,4])*QQ(1)) + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * QQ(1)) Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: parent(matrix(QQ,2,2,[1,2,3,4])*ZZ['x'](1)) + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * ZZ['x'](1)) # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x'],2,2,[1,2,3,4])*QQ(1)) + sage: parent(matrix(ZZ['x'], 2, 2, [1,2,3,4]) * QQ(1)) # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(QQ,2,2,[1,2,3,4])*ZZ['x']['y'](1)) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x']['y'],2,2,[1,2,3,4])*QQ(1)) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(matrix(QQ['x'],2,2,[1,2,3,4])*ZZ['x']['y'](1)) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x']['y'],2,2,[1,2,3,4])*QQ['x'](1)) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(matrix(QQ['y'],2,2,[1,2,3,4])*ZZ['x']['y'](1)) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(matrix(ZZ['x']['y'],2,2,[1,2,3,4])*QQ['y'](1)) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(matrix(ZZ['x'],2,2,[1,2,3,4])*ZZ['y'](1)) + sage: parent(matrix(QQ, 2, 2, [1,2,3,4]) * ZZ['x']['y'](1)) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(matrix(ZZ['x']['y'], 2, 2, [1,2,3,4]) * QQ(1)) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(matrix(QQ['x'], 2, 2, [1,2,3,4]) * ZZ['x']['y'](1)) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(matrix(ZZ['x']['y'], 2, 2, [1,2,3,4]) * QQ['x'](1)) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(matrix(QQ['y'], 2, 2, [1,2,3,4]) * ZZ['x']['y'](1)) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(matrix(ZZ['x']['y'], 2, 2, [1,2,3,4]) * QQ['y'](1)) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: # needs sage.modules + sage: parent(matrix(ZZ['x'], 2, 2, [1,2,3,4]) * ZZ['y'](1)) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and 'Univariate Polynomial Ring in y over Integer Ring' - sage: parent(matrix(ZZ['x'],2,2,[1,2,3,4])*QQ['y'](1)) + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and + 'Univariate Polynomial Ring in y over Integer Ring' + sage: parent(matrix(ZZ['x'], 2, 2, [1,2,3,4]) * QQ['y'](1)) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and 'Univariate Polynomial Ring in y over Rational Field' - sage: parent(matrix(QQ['x'],2,2,[1,2,3,4])*ZZ['y'](1)) + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring' and + 'Univariate Polynomial Ring in y over Rational Field' + sage: parent(matrix(QQ['x'], 2, 2, [1,2,3,4]) * ZZ['y'](1)) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and 'Univariate Polynomial Ring in y over Integer Ring' - sage: parent(matrix(QQ['x'],2,2,[1,2,3,4])*QQ['y'](1)) + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and + 'Univariate Polynomial Ring in y over Integer Ring' + sage: parent(matrix(QQ['x'], 2, 2, [1,2,3,4]) * QQ['y'](1)) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and 'Univariate Polynomial Ring in y over Rational Field' + TypeError: unsupported operand parent(s) for *: + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and + 'Univariate Polynomial Ring in y over Rational Field' Here we test (scalar * matrix) multiplication:: - sage: parent(ZZ(1)*matrix(ZZ,2,2,[1,2,3,4])) + sage: # needs sage.modules + sage: parent(ZZ(1) * matrix(ZZ, 2, 2, [1,2,3,4])) Full MatrixSpace of 2 by 2 dense matrices over Integer Ring - sage: parent(QQ(1)*matrix(ZZ,2,2,[1,2,3,4])) + sage: parent(QQ(1) * matrix(ZZ, 2, 2, [1,2,3,4])) Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: parent(ZZ(1)*matrix(QQ,2,2,[1,2,3,4])) + sage: parent(ZZ(1) * matrix(QQ, 2, 2, [1,2,3,4])) Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: parent(QQ(1)*matrix(QQ,2,2,[1,2,3,4])) + sage: parent(QQ(1) * matrix(QQ, 2, 2, [1,2,3,4])) Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: parent(QQ(1)*matrix(ZZ['x'],2,2,[1,2,3,4])) + sage: parent(QQ(1) * matrix(ZZ['x'], 2, 2, [1,2,3,4])) # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field - sage: parent(ZZ['x'](1)*matrix(QQ,2,2,[1,2,3,4])) + sage: parent(ZZ['x'](1) * matrix(QQ, 2, 2, [1,2,3,4])) # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field - sage: parent(QQ(1)*matrix(ZZ['x']['y'],2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(ZZ['x']['y'](1)*matrix(QQ,2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(QQ['x'](1)*matrix(ZZ['x']['y'],2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(ZZ['x']['y'](1)*matrix(QQ['x'],2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(QQ['y'](1)*matrix(ZZ['x']['y'],2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: parent(ZZ['x']['y'](1)*matrix(QQ['y'],2,2,[1,2,3,4])) - Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - - sage: parent(ZZ['x'](1)*matrix(ZZ['y'],2,2,[1,2,3,4])) + sage: parent(QQ(1) * matrix(ZZ['x']['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(ZZ['x']['y'](1) * matrix(QQ, 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(QQ['x'](1) * matrix(ZZ['x']['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(ZZ['x']['y'](1) * matrix(QQ['x'], 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices over + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: parent(QQ['y'](1) * matrix(ZZ['x']['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices + over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + sage: parent(ZZ['x']['y'](1) * matrix(QQ['y'], 2, 2, [1,2,3,4])) # needs sage.modules + Full MatrixSpace of 2 by 2 dense matrices + over Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field + + sage: # needs sage.modules + sage: parent(ZZ['x'](1) * matrix(ZZ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Univariate Polynomial Ring in x over Integer Ring' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' - sage: parent(ZZ['x'](1)*matrix(QQ['y'],2,2,[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Univariate Polynomial Ring in x over Integer Ring' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' + sage: parent(ZZ['x'](1) * matrix(QQ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Univariate Polynomial Ring in x over Integer Ring' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' - sage: parent(QQ['x'](1)*matrix(ZZ['y'],2,2,[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Univariate Polynomial Ring in x over Integer Ring' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' + sage: parent(QQ['x'](1) * matrix(ZZ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Univariate Polynomial Ring in x over Rational Field' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' - sage: parent(QQ['x'](1)*matrix(QQ['y'],2,2,[1,2,3,4])) + TypeError: unsupported operand parent(s) for *: + 'Univariate Polynomial Ring in x over Rational Field' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Integer Ring' + sage: parent(QQ['x'](1) * matrix(QQ['y'], 2, 2, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Univariate Polynomial Ring in x over Rational Field' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' + TypeError: unsupported operand parent(s) for *: + 'Univariate Polynomial Ring in x over Rational Field' and + 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' Examples with matrices having matrix coefficients:: - sage: m = matrix - sage: a = m([[m([[1,2],[3,4]]),m([[5,6],[7,8]])],[m([[9,10],[11,12]]),m([[13,14],[15,16]])]]) - sage: 3*a + sage: m = matrix # needs sage.modules + sage: a = m([[m([[1,2],[3,4]]),m([[5,6],[7,8]])],[m([[9,10],[11,12]]),m([[13,14],[15,16]])]]) # needs sage.modules + sage: 3 * a # needs sage.modules [[ 3 6] [ 9 12] [15 18] [21 24]] @@ -3896,9 +4075,9 @@ cdef class Matrix(ModuleElement): [33 36] [39 42] [45 48]] - sage: m = matrix - sage: a = m([[m([[1,2],[3,4]]),m([[5,6],[7,8]])],[m([[9,10],[11,12]]),m([[13,14],[15,16]])]]) - sage: a*3 + sage: m = matrix # needs sage.modules + sage: a = m([[m([[1,2],[3,4]]),m([[5,6],[7,8]])],[m([[9,10],[11,12]]),m([[13,14],[15,16]])]]) # needs sage.modules + sage: a * 3 # needs sage.modules [[ 3 6] [ 9 12] [15 18] [21 24]] @@ -3940,6 +4119,7 @@ cdef class Matrix(ModuleElement): EXAMPLES:: + sage: # needs sage.modules sage: a = matrix(ZZ, 2, range(4)) sage: operator.truediv(a, 5) [ 0 1/5] @@ -3956,6 +4136,7 @@ cdef class Matrix(ModuleElement): TESTS:: + sage: # needs sage.modules sage: a = matrix(ZZ, [[1, 2], [0, 3]]) sage: b = matrix(ZZ, 3, 2, range(6)) sage: x = b / a; x @@ -4021,14 +4202,14 @@ cdef class PrincipalIdealDomainElement(DedekindDomainElement): :trac:`30849`:: - sage: 2.gcd(pari(3)) + sage: 2.gcd(pari(3)) # needs sage.libs.pari 1 - sage: type(2.gcd(pari(3))) + sage: type(2.gcd(pari(3))) # needs sage.libs.pari <class 'sage.rings.integer.Integer'> - sage: 2.gcd(pari('1/3')) + sage: 2.gcd(pari('1/3')) # needs sage.libs.pari 1/3 - sage: type(2.gcd(pari('1/3'))) + sage: type(2.gcd(pari('1/3'))) # needs sage.libs.pari <class 'sage.rings.rational.Rational'> sage: import gmpy2 @@ -4039,7 +4220,7 @@ cdef class PrincipalIdealDomainElement(DedekindDomainElement): sage: 2.gcd(gmpy2.mpq(1,3)) 1/3 - sage: type(2.gcd(pari('1/3'))) + sage: type(2.gcd(pari('1/3'))) # needs sage.libs.pari <class 'sage.rings.rational.Rational'> """ # NOTE: in order to handle nicely pari or gmpy2 integers we do not rely only on coercion @@ -4048,7 +4229,7 @@ cdef class PrincipalIdealDomainElement(DedekindDomainElement): if not isinstance(right, Element): right = right.sage() if not ((<Element>right)._parent is self._parent): - from sage.arith.all import gcd + from sage.arith.misc import GCD as gcd return coercion_model.bin_op(self, right, gcd) return self._gcd(right) @@ -4060,14 +4241,14 @@ cdef class PrincipalIdealDomainElement(DedekindDomainElement): :trac:`30849`:: - sage: 2.lcm(pari(3)) + sage: 2.lcm(pari(3)) # needs sage.libs.pari 6 - sage: type(2.lcm(pari(3))) + sage: type(2.lcm(pari(3))) # needs sage.libs.pari <class 'sage.rings.integer.Integer'> - sage: 2.lcm(pari('1/3')) + sage: 2.lcm(pari('1/3')) # needs sage.libs.pari 2 - sage: type(2.lcm(pari('1/3'))) + sage: type(2.lcm(pari('1/3'))) # needs sage.libs.pari <class 'sage.rings.rational.Rational'> sage: import gmpy2 @@ -4082,7 +4263,7 @@ cdef class PrincipalIdealDomainElement(DedekindDomainElement): if not isinstance(right, Element): right = right.sage() if not ((<Element>right)._parent is self._parent): - from sage.arith.all import lcm + from sage.arith.functions import lcm return coercion_model.bin_op(self, right, lcm) return self._lcm(right) @@ -4117,14 +4298,15 @@ cdef class EuclideanDomainElement(PrincipalIdealDomainElement): EXAMPLES:: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' ....: from sage.structure.element cimport EuclideanDomainElement ....: cdef class MyElt(EuclideanDomainElement): ....: def quo_rem(self, other): ....: return self._parent.var('quo,rem') ....: ''') - sage: e = MyElt(SR) # optional - sage.misc.cython - sage: e // e # optional - sage.misc.cython + sage: e = MyElt(SR) # needs sage.misc.cython sage.symbolic + sage: e // e # needs sage.misc.cython sage.symbolic quo """ Q, _ = self.quo_rem(right) @@ -4147,14 +4329,15 @@ cdef class EuclideanDomainElement(PrincipalIdealDomainElement): :: - sage: cython(''' # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' ....: from sage.structure.element cimport EuclideanDomainElement ....: cdef class MyElt(EuclideanDomainElement): ....: def quo_rem(self, other): ....: return self._parent.var('quo,rem') ....: ''') - sage: e = MyElt(SR) # optional - sage.misc.cython - sage: e % e # optional - sage.misc.cython + sage: e = MyElt(SR) # needs sage.misc.cython sage.symbolic + sage: e % e # needs sage.misc.cython sage.symbolic rem """ _, R = self.quo_rem(other) @@ -4175,6 +4358,8 @@ cdef class FieldElement(CommutativeRingElement): EXAMPLES:: + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') sage: K.<b> = NumberField(x^4 + x^2 + 2/3) sage: c = (1+b) // (1-b); c 3/4*b^3 + 3/4*b^2 + 3/2*b + 1/2 @@ -4229,9 +4414,10 @@ cdef class FieldElement(CommutativeRingElement): Test if :trac:`8671` is fixed:: + sage: # needs sage.libs.pari sage.libs.singular sage: R.<x,y> = QQ[] sage: S.<a,b> = R.quo(y^2 + 1) - sage: S.is_field = lambda : False + sage: S.is_field = lambda: False sage: F = Frac(S); u = F.one() sage: u.quo_rem(u) (1, 0) @@ -4249,6 +4435,7 @@ cdef class FieldElement(CommutativeRingElement): EXAMPLES:: + sage: # needs sage.rings.number_field sage.symbolic sage: K.<rt3> = QQ[sqrt(3)] sage: K(0).divides(rt3) False @@ -4263,6 +4450,7 @@ cdef class FieldElement(CommutativeRingElement): other = self.parent()(other) return bool(self) or other.is_zero() + def is_AlgebraElement(x): """ Return ``True`` if x is of type AlgebraElement. @@ -4270,8 +4458,8 @@ def is_AlgebraElement(x): TESTS:: sage: from sage.structure.element import is_AlgebraElement - sage: R.<x,y> = FreeAlgebra(QQ,2) - sage: is_AlgebraElement(x*y) + sage: R.<x,y> = FreeAlgebra(QQ, 2) # needs sage.combinat sage.modules + sage: is_AlgebraElement(x * y) # needs sage.combinat sage.modules True sage: is_AlgebraElement(1) @@ -4291,6 +4479,8 @@ def is_CommutativeAlgebraElement(x): cdef class CommutativeAlgebraElement(CommutativeRingElement): pass + ############################################## + def is_InfinityElement(x): """ Return ``True`` if x is of type InfinityElement. @@ -4327,8 +4517,8 @@ cpdef canonical_coercion(x, y): EXAMPLES:: - sage: A = Matrix([[0, 1], [1, 0]]) - sage: canonical_coercion(A, 1) + sage: A = Matrix([[0, 1], [1, 0]]) # needs sage.modules + sage: canonical_coercion(A, 1) # needs sage.modules ( [0 1] [1 0] [1 0], [0 1] @@ -4381,11 +4571,13 @@ def coercion_traceback(dump=True): sage: 1/5 + GF(5).gen() Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for +: 'Rational Field' and 'Finite Field of size 5' + TypeError: unsupported operand parent(s) for +: + 'Rational Field' and 'Finite Field of size 5' sage: coercion_traceback() Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Rational Field' and 'Finite Field of size 5' + TypeError: no common canonical parent for objects with parents: + 'Rational Field' and 'Finite Field of size 5' """ if dump: for traceback in coercion_model.exception_stack(): @@ -4418,7 +4610,7 @@ def coerce_binop(method): Sparse polynomial rings uses `@coerce_binop` on `gcd`:: - sage: S.<x> = PolynomialRing(ZZ,sparse=True) + sage: S.<x> = PolynomialRing(ZZ, sparse=True) sage: f = x^2 sage: g = x sage: f.gcd(g) #indirect doctest @@ -4432,22 +4624,22 @@ def coerce_binop(method): Another real example:: - sage: R1=QQ['x,y'] - sage: R2=QQ['x,y,z'] - sage: f=R1(1) - sage: g=R1(2) - sage: h=R2(1) + sage: R1 = QQ['x,y'] + sage: R2 = QQ['x,y,z'] + sage: f = R1(1) + sage: g = R1(2) + sage: h = R2(1) sage: f.gcd(g) 1 - sage: f.gcd(g,algorithm='modular') + sage: f.gcd(g, algorithm='modular') 1 sage: f.gcd(h) 1 - sage: f.gcd(h,algorithm='modular') + sage: f.gcd(h, algorithm='modular') 1 sage: h.gcd(f) 1 - sage: h.gcd(f,'modular') + sage: h.gcd(f, 'modular') 1 We demonstrate a small class using `@coerce_binop` on a method:: diff --git a/src/sage/structure/element_wrapper.pyx b/src/sage/structure/element_wrapper.pyx index f77bcce6ea5..3aa87527d92 100644 --- a/src/sage/structure/element_wrapper.pyx +++ b/src/sage/structure/element_wrapper.pyx @@ -209,8 +209,8 @@ cdef class ElementWrapper(Element): sage: from sage.structure.element_wrapper import DummyParent sage: ElementWrapper(DummyParent("A parent"), 1)._ascii_art_() 1 - sage: x = var('x') - sage: ElementWrapper(DummyParent("A parent"), x^2 + x)._ascii_art_() + sage: x = var('x') # needs sage.symbolic + sage: ElementWrapper(DummyParent("A parent"), x^2 + x)._ascii_art_() # needs sage.symbolic 2 x + x """ @@ -226,8 +226,8 @@ cdef class ElementWrapper(Element): sage: from sage.structure.element_wrapper import DummyParent sage: ElementWrapper(DummyParent("A parent"), 1)._ascii_art_() 1 - sage: x = var('x') - sage: ElementWrapper(DummyParent("A parent"), x^2 + x)._unicode_art_() + sage: x = var('x') # needs sage.symbolic + sage: ElementWrapper(DummyParent("A parent"), x^2 + x)._unicode_art_() # needs sage.symbolic 2 x + x """ diff --git a/src/sage/structure/factorization.py b/src/sage/structure/factorization.py index 7636f1a9ba7..00571876e39 100644 --- a/src/sage/structure/factorization.py +++ b/src/sage/structure/factorization.py @@ -66,6 +66,7 @@ This more complicated example involving polynomials also illustrates that the unit part is not discarded from factorizations:: + sage: # needs sage.libs.pari sage: x = QQ['x'].0 sage: f = -5*(x-2)*(x-3) sage: f @@ -81,6 +82,7 @@ `p_i` is a 'prime' and each `e_i` is an integer. The unit part is discarded by the list:: + sage: # needs sage.libs.pari sage: list(F) [(x - 3, 1), (x - 2, 1)] sage: len(F) @@ -91,6 +93,7 @@ In the ring `\ZZ[x]`, the integer `-5` is not a unit, so the factorization has three factors:: + sage: # needs sage.libs.pari sage: x = ZZ['x'].0 sage: f = -5*(x-2)*(x-3) sage: f @@ -110,8 +113,9 @@ On the other hand, -1 is a unit in `\ZZ`, so it is included in the unit:: + sage: # needs sage.libs.pari sage: x = ZZ['x'].0 - sage: f = -1*(x-2)*(x-3) + sage: f = -1 * (x-2) * (x-3) sage: F = f.factor(); F (-1) * (x - 3) * (x - 2) sage: F.unit() @@ -121,15 +125,20 @@ Factorizations can involve fairly abstract mathematical objects:: - sage: F = ModularSymbols(11,4).factorization() - sage: F - (Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 6 for Gamma_0(11) of weight 4 with sign 0 over Rational Field) * - (Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 6 for Gamma_0(11) of weight 4 with sign 0 over Rational Field) * - (Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 6 for Gamma_0(11) of weight 4 with sign 0 over Rational Field) + sage: # needs sage.modular + sage: F = ModularSymbols(11,4).factorization(); F + (Modular Symbols subspace of dimension 2 of Modular Symbols space + of dimension 6 for Gamma_0(11) of weight 4 with sign 0 over Rational Field) * + (Modular Symbols subspace of dimension 2 of Modular Symbols space + of dimension 6 for Gamma_0(11) of weight 4 with sign 0 over Rational Field) * + (Modular Symbols subspace of dimension 2 of Modular Symbols space + of dimension 6 for Gamma_0(11) of weight 4 with sign 0 over Rational Field) sage: type(F) <class 'sage.structure.factorization.Factorization'> + sage: # needs sage.rings.number_field + sage: x = ZZ['x'].0 sage: K.<a> = NumberField(x^2 + 3); K Number Field in a with defining polynomial x^2 + 3 sage: f = K.factor(15); f @@ -138,7 +147,7 @@ Monoid of ideals of Number Field in a with defining polynomial x^2 + 3 sage: f.unit() Fractional ideal (1) - sage: g=K.factor(9); g + sage: g = K.factor(9); g (Fractional ideal (1/2*a + 3/2))^4 sage: f.lcm(g) (Fractional ideal (1/2*a + 3/2))^4 * (Fractional ideal (5)) @@ -171,15 +180,15 @@ universe functions """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.sage_object import SageObject from sage.structure.element import Element @@ -188,7 +197,6 @@ from sage.misc.cachefunc import cached_method - @richcmp_method class Factorization(SageObject): """ @@ -207,7 +215,7 @@ class Factorization(SageObject): -1 sage: loads(F.dumps()) == F True - sage: F = Factorization([(x,1/3)]) + sage: F = Factorization([(x, 1/3)]) # needs sage.symbolic Traceback (most recent call last): ... TypeError: no conversion of this rational to integer @@ -218,24 +226,25 @@ def __init__(self, x, unit=None, cr=False, sort=True, simplify=True): INPUT: - - ``x`` - a list of pairs (p, e) with e an integer; - otherwise a TypeError is raised + - ``x`` -- a list of pairs (p, e) with e an integer; + otherwise a :class:`TypeError` is raised - - ``unit`` - (default: 1) the unit part of the factorization. + - ``unit`` -- (default: 1); the unit part of the factorization. - - ``cr`` - (default: False) if True, print the factorization with - carriage returns between factors. + - ``cr`` -- (default: ``False``); if ``True``, print the factorization + with carriage returns between factors. - - ``sort`` - (default: True) if True, sort the factors by calling - the sort function ``self.sort()`` after creating the factorization + - ``sort`` - (default: ``True``); if ``True``, sort the factors by + calling the sort function ``self.sort()`` after creating + the factorization - - ``simplify`` - (default: True) if True, remove duplicate + - ``simplify`` -- (default: ``True``); if ``True``, remove duplicate factors from the factorization. See the documentation for self.simplify. OUTPUT: - - a Factorization object + a Factorization object EXAMPLES: @@ -282,13 +291,13 @@ def __init__(self, x, unit=None, cr=False, sort=True, simplify=True): sage: Factorization([(2, 7), (5,2), (2, 5)]) 2^12 * 5^2 - sage: R.<a,b> = FreeAlgebra(QQ,2) - sage: Factorization([(a,1),(b,1),(a,2)]) + sage: R.<a,b> = FreeAlgebra(QQ, 2) # needs sage.combinat sage.modules + sage: Factorization([(a,1), (b,1), (a,2)]) # needs sage.combinat sage.modules a * b * a^2 Autosorting (the default) swaps around the factors below:: - sage: F = Factorization([(ZZ^3, 2), (ZZ^2, 5)], cr=True); F + sage: F = Factorization([(ZZ^3, 2), (ZZ^2, 5)], cr=True); F # needs sage.modules (Ambient free module of rank 2 over the principal ideal domain Integer Ring)^5 * (Ambient free module of rank 3 over the principal ideal domain Integer Ring)^2 """ @@ -318,7 +327,7 @@ def __init__(self, x, unit=None, cr=False, sort=True, simplify=True): def __getitem__(self, i): """ - Return `i^{th}` factor of self. + Return `i^{th}` factor of ``self``. EXAMPLES:: @@ -339,7 +348,7 @@ def __getitem__(self, i): def __setitem__(self, i, v): """ - Set the `i^{th}` factor of self. + Set the `i^{th}` factor of ``self``. .. warning:: @@ -358,7 +367,7 @@ def __setitem__(self, i, v): def __len__(self): """ - Return the number of prime factors of self, not counting + Return the number of prime factors of ``self``, not counting the unit part. EXAMPLES:: @@ -414,7 +423,7 @@ def __richcmp__(self, other, op): sage: x = polygen(QQ) sage: x^2 - 1 > x^2 - 4 True - sage: factor(x^2 - 1) > factor(x^2 - 4) + sage: factor(x^2 - 1) > factor(x^2 - 4) # needs sage.libs.pari True """ if not isinstance(other, Factorization): @@ -434,11 +443,11 @@ def __richcmp__(self, other, op): def __copy__(self): r""" - Return a copy of self. + Return a copy of ``self``. This is *not* a deepcopy -- only references to the factors are returned, not copies of them. Use ``deepcopy(self)`` if you need - a deep copy of self. + a deep copy of ``self``. EXAMPLES: @@ -464,11 +473,11 @@ def __copy__(self): # No need to sort, since the factorization is already sorted # in whatever order is desired. return Factorization(self.__x, unit=self.__unit, cr=self.__cr, - sort=False, simplify=False) + sort=False, simplify=False) def __deepcopy__(self, memo): r""" - Return a deep copy of self. + Return a deep copy of ``self``. EXAMPLES: @@ -521,13 +530,13 @@ def universe(self): sage: F.universe() Integer Ring - sage: R.<x,y,z> = FreeAlgebra(QQ, 3) - sage: F = Factorization([(z, 2)], 3) - sage: (F*F^-1).universe() + sage: R.<x,y,z> = FreeAlgebra(QQ, 3) # needs sage.combinat sage.modules + sage: F = Factorization([(z, 2)], 3) # needs sage.combinat sage.modules + sage: (F*F^-1).universe() # needs sage.combinat sage.modules Free Algebra on 3 generators (x, y, z) over Rational Field - sage: F = ModularSymbols(11,4).factorization() - sage: F.universe() + sage: F = ModularSymbols(11,4).factorization() # needs sage.modular + sage: F.universe() # needs sage.modular """ try: return self.__universe @@ -536,7 +545,7 @@ def universe(self): def base_change(self, U): """ - Return the factorization self, with its factors (including the + Return the factorization ``self``, with its factors (including the unit part) coerced into the universe `U`. EXAMPLES:: @@ -548,15 +557,15 @@ def base_change(self, U): sage: F.base_change(P).universe() Univariate Polynomial Ring in x over Integer Ring - This method will return a TypeError if the coercion is not + This method will return a :class:`TypeError` if the coercion is not possible:: sage: g = x^2 - 1 - sage: F = factor(g); F + sage: F = factor(g); F # needs sage.libs.pari (x - 1) * (x + 1) - sage: F.universe() + sage: F.universe() # needs sage.libs.pari Univariate Polynomial Ring in x over Integer Ring - sage: F.base_change(ZZ) + sage: F.base_change(ZZ) # needs sage.libs.pari Traceback (most recent call last): ... TypeError: Impossible to coerce the factors of (x - 1) * (x + 1) into Integer Ring @@ -566,21 +575,25 @@ def base_change(self, U): try: return Factorization([(U(f[0]), f[1]) for f in list(self)], unit=U(self.unit())) except TypeError: - raise TypeError("Impossible to coerce the factors of %s into %s"%(self, U)) + raise TypeError("Impossible to coerce the factors of %s into %s" % (self, U)) - def is_commutative(self): + def is_commutative(self) -> bool: """ - Return True if my factors commute. + Return whether the factors commute. EXAMPLES:: sage: F = factor(2006) sage: F.is_commutative() True + + sage: # needs sage.rings.number_field sage: K = QuadraticField(23, 'a') sage: F = K.factor(13) sage: F.is_commutative() True + + sage: # needs sage.combinat sage.modules sage: R.<x,y,z> = FreeAlgebra(QQ, 3) sage: F = Factorization([(z, 2)], 3) sage: F.is_commutative() @@ -603,14 +616,14 @@ def _set_cr(self, cr): EXAMPLES:: sage: x = polygen(QQ,'x') - sage: F = factor(x^6 - 1); F + sage: F = factor(x^6 - 1); F # needs sage.libs.pari (x - 1) * (x + 1) * (x^2 - x + 1) * (x^2 + x + 1) - sage: F._set_cr(True); F + sage: F._set_cr(True); F # needs sage.libs.pari (x - 1) * (x + 1) * (x^2 - x + 1) * (x^2 + x + 1) - sage: F._set_cr(False); F + sage: F._set_cr(False); F # needs sage.libs.pari (x - 1) * (x + 1) * (x^2 - x + 1) * (x^2 + x + 1) """ self.__cr = bool(cr) @@ -621,6 +634,7 @@ def simplify(self): TESTS:: + sage: # needs sage.combinat sage.modules sage: R.<x,y> = FreeAlgebra(ZZ, 2) sage: F = Factorization([(x,3), (y, 2), (y,2)], simplify=False); F x^3 * y^2 * y^2 @@ -649,7 +663,7 @@ def sort(self, key=None): INPUT: - - ``key`` - (default: ``None``) comparison key + - ``key`` -- (default: ``None``); comparison key OUTPUT: @@ -674,14 +688,14 @@ def sort(self, key=None): We create a factored polynomial:: - sage: x = polygen(QQ,'x') - sage: F = factor(x^3 + 1); F + sage: x = polygen(QQ, 'x') + sage: F = factor(x^3 + 1); F # needs sage.libs.pari (x + 1) * (x^2 - x + 1) We sort it by decreasing degree:: - sage: F.sort(key=lambda x:(-x[0].degree(), x)) - sage: F + sage: F.sort(key=lambda x: (-x[0].degree(), x)) # needs sage.libs.pari + sage: F # needs sage.libs.pari (x^2 - x + 1) * (x + 1) """ if len(self) == 0: @@ -726,12 +740,12 @@ def unit(self): We create a polynomial over the real double field and factor it:: sage: x = polygen(RDF, 'x') - sage: F = factor(-2*x^2 - 1); F + sage: F = factor(-2*x^2 - 1); F # needs numpy (-2.0) * (x^2 + 0.5000000000000001) Note that the unit part of the factorization is `-2.0`:: - sage: F.unit() + sage: F.unit() # needs numpy -2.0 sage: F = factor(-2006); F @@ -770,7 +784,7 @@ def _cr(self): Next we factor a modular symbols space:: - sage: F = ModularSymbols(11).factor(); F + sage: F = ModularSymbols(11).factor(); F # needs sage.modular (Modular Symbols subspace of dimension 1 of ...) * (Modular Symbols subspace of dimension 1 of ...) * (Modular Symbols subspace of dimension 1 of ...) @@ -799,7 +813,7 @@ def _repr_(self): sage: f factorization of -100 - However _repr_ always prints normally:: + However ``_repr_`` always prints normally:: sage: f._repr_() '-1 * 2^2 * 5^2' @@ -816,7 +830,7 @@ def _repr_(self): if len(self) == 0: return repr(self.__unit) s = '' - mul = ' * ' + mul = ' * ' if cr: mul += '\n' x = self.__x[0][0] @@ -836,18 +850,18 @@ def _repr_(self): n = self.__x[i][1] if not atomic and (n != 1 or len(self) > 1 or self.__unit != one): if '+' in t or '-' in t or ' ' in t: - t = '(%s)'%t + t = '(%s)' % t if n != 1: - t += '^%s'%n + t += '^%s' % n s += t - if i < len(self)-1: + if i < len(self) - 1: s += mul if self.__unit != one: if atomic: u = repr(self.__unit) else: - u = '(%s)'%self.__unit - s = u + mul + s + u = '(%s)' % self.__unit + s = u + mul + s return s def _latex_(self): @@ -862,7 +876,7 @@ def _latex_(self): -1 \cdot 2^{2} \cdot 5^{2} sage: f._latex_() '-1 \\cdot 2^{2} \\cdot 5^{2}' - sage: x = AA['x'].0; factor(x^2 + x + 1)._latex_() # trac 12178 + sage: x = AA['x'].0; factor(x^2 + x + 1)._latex_() # trac 12178 # needs sage.rings.number_field '(x^{2} + x + 1.000000000000000?)' """ if len(self) == 0: @@ -876,19 +890,19 @@ def _latex_(self): for i in range(len(self)): t = self.__x[i][0]._latex_() if not atomic and ('+' in t or '-' in t or ' ' in t): - t = '(%s)'%t + t = '(%s)' % t n = self.__x[i][1] if n != 1: - t += '^{%s}'%n + t += '^{%s}' % n s += t - if i < len(self)-1: + if i < len(self) - 1: s += ' \\cdot ' if self.__unit != 1: if atomic: u = self.__unit._latex_() else: - u = '\\left(%s\\right)'%self.__unit._latex_() - s = u + ' \\cdot ' + s + u = '\\left(%s\\right)' % self.__unit._latex_() + s = u + ' \\cdot ' + s return s @cached_method @@ -899,12 +913,12 @@ def __pari__(self): EXAMPLES:: sage: f = factor(-24) - sage: pari(f) + sage: pari(f) # needs sage.libs.pari [-1, 1; 2, 3; 3, 1] sage: R.<x> = QQ[] - sage: g = factor(x^10 - 1) - sage: pari(g) + sage: g = factor(x^10 - 1) # needs sage.libs.pari + sage: pari(g) # needs sage.libs.pari [x - 1, 1; x + 1, 1; x^4 - x^3 + x^2 - x + 1, 1; x^4 + x^3 + x^2 + x + 1, 1] """ @@ -923,7 +937,7 @@ def __pari__(self): def __add__(self, other): """ - Return the (unfactored) sum of self and other. + Return the (unfactored) sum of ``self`` and ``other``. EXAMPLES:: @@ -940,7 +954,7 @@ def __add__(self, other): def __sub__(self, other): """ - Return the (unfactored) difference of self and other. + Return the (unfactored) difference of ``self`` and ``other``. EXAMPLES:: @@ -955,7 +969,7 @@ def __sub__(self, other): def __radd__(self, left): """ - Return the (unfactored) sum of self and left. + Return the (unfactored) sum of ``self`` and ``left``. EXAMPLES:: @@ -964,10 +978,9 @@ def __radd__(self, left): """ return self.value() + left - def __rsub__(self, left): """ - Return the (unfactored) difference of left and self. + Return the (unfactored) difference of ``left`` and ``self``. EXAMPLES:: @@ -995,7 +1008,7 @@ def __neg__(self): def __rmul__(self, left): """ - Return the product left * self, where left is not a Factorization. + Return the product ``left * self``, where ``left`` is not a Factorization. EXAMPLES:: @@ -1005,12 +1018,12 @@ def __rmul__(self, left): -2 * 3 * 5 sage: a * -2 -2 * 3 * 5 - sage: R.<x,y> = FreeAlgebra(QQ,2) - sage: f = Factorization([(x,2),(y,3)]); f + sage: R.<x,y> = FreeAlgebra(QQ, 2) # needs sage.combinat sage.modules + sage: f = Factorization([(x,2), (y,3)]); f # needs sage.combinat sage.modules x^2 * y^3 - sage: x * f + sage: x * f # needs sage.combinat sage.modules x^3 * y^3 - sage: f * x + sage: f * x # needs sage.combinat sage.modules x^2 * y^3 * x Note that this does not automatically factor ``left``:: @@ -1028,7 +1041,7 @@ def __mul__(self, other): If the two factorizations have different universes, this method will attempt to find a common universe for the - product. A TypeError is raised if this is impossible. + product. A :class:`TypeError` is raised if this is impossible. EXAMPLES:: @@ -1037,6 +1050,7 @@ def __mul__(self, other): sage: factor(-10) * factor(16) -1 * 2^5 * 5 + sage: # needs sage.combinat sage.modules sage: R.<x,y> = FreeAlgebra(ZZ, 2) sage: F = Factorization([(x,3), (y, 2), (x,1)]); F x^3 * y^2 * x @@ -1073,17 +1087,17 @@ def __mul__(self, other): self = self.base_change(U) other = other.base_change(U) except TypeError: - raise TypeError("Cannot multiply %s and %s because they cannot be coerced into a common universe"%(self,other)) + raise TypeError("Cannot multiply %s and %s because they cannot be coerced into a common universe" % (self, other)) if self.is_commutative() and other.is_commutative(): d1 = dict(self) d2 = dict(other) s = {} for a in set(d1).union(set(d2)): - s[a] = d1.get(a,0) + d2.get(a,0) - return Factorization(list(s.items()), unit=self.unit()*other.unit()) + s[a] = d1.get(a, 0) + d2.get(a, 0) + return Factorization(list(s.items()), unit=self.unit() * other.unit()) else: - return Factorization(list(self) + list(other), unit=self.unit()*other.unit()) + return Factorization(list(self) + list(other), unit=self.unit() * other.unit()) def __pow__(self, n): """ @@ -1099,16 +1113,17 @@ def __pow__(self, n): sage: f^4 2^8 * 5^8 - sage: K.<a> = NumberField(x^3 - 39*x - 91) - sage: F = K.factor(7); F + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 - 39*x - 91) # needs sage.rings.number_field + sage: F = K.factor(7); F # needs sage.rings.number_field (Fractional ideal (7, a)) * (Fractional ideal (7, a + 2)) * (Fractional ideal (7, a - 2)) - sage: F^9 + sage: F^9 # needs sage.rings.number_field (Fractional ideal (7, a))^9 * (Fractional ideal (7, a + 2))^9 * (Fractional ideal (7, a - 2))^9 - sage: R.<x,y> = FreeAlgebra(ZZ, 2) - sage: F = Factorization([(x,3), (y, 2), (x,1)]); F + sage: R.<x,y> = FreeAlgebra(ZZ, 2) # needs sage.combinat sage.modules + sage: F = Factorization([(x,3), (y, 2), (x,1)]); F # needs sage.combinat sage.modules x^3 * y^2 * x - sage: F**2 + sage: F**2 # needs sage.combinat sage.modules x^3 * y^2 * x^4 * y^2 * x """ from sage.rings.integer import Integer @@ -1122,7 +1137,8 @@ def __pow__(self, n): if n == 0: return Factorization([]) if self.is_commutative(): - return Factorization([(p, n*e) for p, e in self], unit=self.unit()**n, cr=self.__cr, sort=False, simplify=False) + return Factorization([(p, n * e) for p, e in self], unit=self.unit()**n, + cr=self.__cr, sort=False, simplify=False) if n < 0: self = ~self n = -n @@ -1140,14 +1156,14 @@ def __invert__(self): sage: F^-1 2^-1 * 17^-1 * 59^-1 - sage: R.<x,y> = FreeAlgebra(QQ, 2) - sage: F = Factorization([(x,3), (y, 2), (x,1)], 2); F + sage: R.<x,y> = FreeAlgebra(QQ, 2) # needs sage.combinat sage.modules + sage: F = Factorization([(x,3), (y, 2), (x,1)], 2); F # needs sage.combinat sage.modules (2) * x^3 * y^2 * x - sage: F^-1 + sage: F^-1 # needs sage.combinat sage.modules (1/2) * x^-1 * y^-2 * x^-3 """ - return Factorization([(p,-e) for p,e in reversed(self)], - cr=self._cr(), unit=self.unit()**(-1)) + return Factorization([(p, -e) for p, e in reversed(self)], + cr=self._cr(), unit=self.unit()**(-1)) def __truediv__(self, other): r""" @@ -1161,6 +1177,7 @@ def __truediv__(self, other): sage: factor(-10) / factor(16) -1 * 2^-3 * 5 + sage: # needs sage.combinat sage.modules sage: R.<x,y> = FreeAlgebra(QQ, 2) sage: F = Factorization([(x,3), (y, 2), (x,1)]); F x^3 * y^2 * x @@ -1173,6 +1190,63 @@ def __truediv__(self, other): return self / Factorization([(other, 1)]) return self * other**-1 + def __call__(self, *args, **kwds): + """ + Implement the substitution. + + This is assuming that each term can be substituted. + + There is another mechanism for substitution + in symbolic products. + + EXAMPLES:: + + sage: # needs sage.combinat sage.modules + sage: R.<x,y> = FreeAlgebra(QQ, 2) + sage: F = Factorization([(x,3), (y, 2), (x,1)]) + sage: F(x=4) + (1) * 4^3 * y^2 * 4 + sage: F.subs({y:2}) + x^3 * 2^2 * x + + sage: R.<x,y> = PolynomialRing(QQ, 2) + sage: F = Factorization([(x,3), (y, 2), (x,1)]) + sage: F(x=4) + 4 * 4^3 * y^2 + sage: F.subs({y:x}) + x * x^2 * x^3 + sage: F(x=y+x) + (x + y) * y^2 * (x + y)^3 + + TESTS:: + + sage: R.<x,y> = PolynomialRing(QQ, 2) + sage: F = Factorization([(x-2,3), (y+3, 2)]) + sage: F(x=2) + 0 + + sage: QQt = QQ['t'].fraction_field() + sage: t = QQt.gen() + sage: R.<x> = PolynomialRing(QQt, 1) + sage: F = Factorization([(x,3), (x+t, 2)], unit=QQt.gen()) + sage: F(t=0) + 0 + + sage: R.<x> = LaurentPolynomialRing(QQ, 1) # needs sage.modules + sage: F = ((x+2)/x**3).factor() # needs sage.modules + sage: F(x=4) # needs sage.modules + 1/64 * 6 + """ + unit = self.__unit.subs(*args, **kwds) + if unit == 0: + return self.universe().zero() + data = [(p.subs(*args, **kwds), e) for p, e in self.__x] + if any(p == 0 for p, _ in data): + return self.universe().zero() + return Factorization(data, unit=unit, simplify=False) + + subs = __call__ + def value(self): """ Return the product of the factors in the factorization, multiplied out. @@ -1184,10 +1258,10 @@ def value(self): sage: F.value() -2006 - sage: R.<x,y> = FreeAlgebra(ZZ, 2) - sage: F = Factorization([(x,3), (y, 2), (x,1)]); F + sage: R.<x,y> = FreeAlgebra(ZZ, 2) # needs sage.combinat sage.modules + sage: F = Factorization([(x,3), (y, 2), (x,1)]); F # needs sage.combinat sage.modules x^3 * y^2 * x - sage: F.value() + sage: F.value() # needs sage.combinat sage.modules x^3*y^2*x """ from sage.misc.misc_c import prod @@ -1195,7 +1269,7 @@ def value(self): # Two aliases for ``value(self)``. expand = value - prod = value + prod = value def gcd(self, other): r""" @@ -1203,7 +1277,7 @@ def gcd(self, other): If the two factorizations have different universes, this method will attempt to find a common universe for the - gcd. A TypeError is raised if this is impossible. + gcd. A :class:`TypeError` is raised if this is impossible. EXAMPLES:: @@ -1213,7 +1287,7 @@ def gcd(self, other): 2 * 5 sage: R.<x> = ZZ[] - sage: (factor(-20).gcd(factor(5*x+10))).universe() + sage: (factor(-20).gcd(factor(5*x+10))).universe() # needs sage.libs.pari Univariate Polynomial Ring in x over Integer Ring """ if not isinstance(other, Factorization): @@ -1227,14 +1301,14 @@ def gcd(self, other): self = self.base_change(U) other = other.base_change(U) except TypeError: - raise TypeError("Cannot take the gcd of %s and %s because they cannot be coerced into a common universe"%(self,other)) + raise TypeError("Cannot take the gcd of %s and %s because they cannot be coerced into a common universe" % (self, other)) if self.is_commutative() and other.is_commutative(): d1 = dict(self) d2 = dict(other) s = {} for a in set(d1).intersection(set(d2)): - s[a] = min(d1[a],d2[a]) + s[a] = min(d1[a], d2[a]) return Factorization(list(s.items())) else: raise NotImplementedError("gcd is not implemented for non-commutative factorizations") @@ -1245,7 +1319,7 @@ def lcm(self, other): If the two factorizations have different universes, this method will attempt to find a common universe for the - lcm. A TypeError is raised if this is impossible. + lcm. A :class:`TypeError` is raised if this is impossible. EXAMPLES:: @@ -1255,7 +1329,7 @@ def lcm(self, other): 2^4 * 5 sage: R.<x> = ZZ[] - sage: (factor(-20).lcm(factor(5*x+10))).universe() + sage: (factor(-20).lcm(factor(5*x + 10))).universe() # needs sage.libs.pari Univariate Polynomial Ring in x over Integer Ring """ if not isinstance(other, Factorization): @@ -1269,21 +1343,21 @@ def lcm(self, other): self = self.base_change(U) other = other.base_change(U) except TypeError: - raise TypeError("Cannot take the lcm of %s and %s because they cannot be coerced into a common universe"%(self,other)) + raise TypeError("Cannot take the lcm of %s and %s because they cannot be coerced into a common universe" % (self, other)) if self.is_commutative() and other.is_commutative(): d1 = dict(self) d2 = dict(other) s = {} for a in set(d1).union(set(d2)): - s[a] = max(d1.get(a,0),d2.get(a,0)) + s[a] = max(d1.get(a, 0), d2.get(a, 0)) return Factorization(list(s.items())) else: raise NotImplementedError("lcm is not implemented for non-commutative factorizations") - def is_integral(self): + def is_integral(self) -> bool: r""" - Return True iff all exponents of this Factorization are non-negative. + Return whether all exponents of this Factorization are non-negative. EXAMPLES:: @@ -1301,11 +1375,11 @@ def is_integral(self): def radical(self): """ - Return the factorization of the radical of the value of self. + Return the factorization of the radical of the value of ``self``. First, check that all exponents in the factorization are - positive, raise ValueError otherwise. If all exponents are - positive, return self with all exponents set to 1 and with the + positive, raise :class:`ValueError` otherwise. If all exponents are + positive, return ``self`` with all exponents set to 1 and with the unit set to 1. EXAMPLES:: @@ -1317,21 +1391,22 @@ def radical(self): sage: factor(1/2).radical() Traceback (most recent call last): ... - ValueError: All exponents in the factorization must be positive. + ValueError: all exponents in the factorization must be positive """ - if not all(e > 0 for p, e in self.__x): - raise ValueError("All exponents in the factorization must be positive.") - return Factorization([(p,1) for p,e in self.__x], unit=self.unit().parent()(1), cr=self.__cr, sort=False, simplify=False) + if not all(e > 0 for _, e in self.__x): + raise ValueError("all exponents in the factorization must be positive") + return Factorization([(p, 1) for p, _ in self.__x], unit=self.unit().parent()(1), + cr=self.__cr, sort=False, simplify=False) def radical_value(self): """ - Return the product of the prime factors in self. + Return the product of the prime factors in ``self``. First, check that all exponents in the factorization are - positive, raise ValueError otherwise. If all exponents are - positive, return the product of the prime factors in self. + positive, raise :class:`ValueError` otherwise. If all exponents are + positive, return the product of the prime factors in ``self``. This should be functionally equivalent to - self.radical().value() + ``self.radical().value()``. EXAMPLES:: @@ -1342,9 +1417,9 @@ def radical_value(self): sage: factor(1/2).radical_value() Traceback (most recent call last): ... - ValueError: All exponents in the factorization must be positive. + ValueError: all exponents in the factorization must be positive """ - if not all(e > 0 for p, e in self.__x): - raise ValueError("All exponents in the factorization must be positive.") + if not all(e > 0 for _, e in self.__x): + raise ValueError("all exponents in the factorization must be positive") from sage.misc.misc_c import prod - return prod([p for p, e in self.__x]) + return prod([p for p, _ in self.__x]) diff --git a/src/sage/structure/factory.pyx b/src/sage/structure/factory.pyx index a4a13186973..ddb55501d94 100644 --- a/src/sage/structure/factory.pyx +++ b/src/sage/structure/factory.pyx @@ -196,7 +196,7 @@ cdef class UniqueFactory(SageObject): :class:`object`. The third allows attribute assignment and is derived from :class:`object`. :: - sage: cython("cdef class C: pass") # optional - sage.misc.cython + sage: cython("cdef class C: pass") # needs sage.misc.cython sage: class D: ....: def __init__(self, *args): ....: self.t = args @@ -214,7 +214,7 @@ cdef class UniqueFactory(SageObject): It is impossible to create an instance of ``C`` with our factory, since it does not allow weak references:: - sage: F(1, impl='C') # optional - sage.misc.cython + sage: F(1, impl='C') # needs sage.misc.cython Traceback (most recent call last): ... TypeError: cannot create weak reference to '....C' object @@ -222,12 +222,14 @@ cdef class UniqueFactory(SageObject): Let us try again, with a Cython class that does allow weak references. Now, creation of an instance using the factory works:: - sage: cython('''cdef class C: # optional - sage.misc.cython + sage: cython( # needs sage.misc.cython + ....: ''' + ....: cdef class C: ....: cdef __weakref__ ....: ''') ....: - sage: c = F(1, impl='C') # optional - sage.misc.cython - sage: isinstance(c, C) # optional - sage.misc.cython + sage: c = F(1, impl='C') # needs sage.misc.cython + sage: isinstance(c, C) # needs sage.misc.cython True The cache is used when calling the factory again---even if it is suggested @@ -235,16 +237,16 @@ cdef class UniqueFactory(SageObject): only considered an "extra argument" that does not count for the key. :: - sage: c is F(1, impl='C') is F(1, impl="D") is F(1) # optional - sage.misc.cython + sage: c is F(1, impl='C') is F(1, impl="D") is F(1) # needs sage.misc.cython True However, pickling and unpickling does not use the cache. This is because the factory has tried to assign an attribute to the instance that provides information on the key used to create the instance, but failed:: - sage: loads(dumps(c)) is c # optional - sage.misc.cython + sage: loads(dumps(c)) is c # needs sage.misc.cython False - sage: hasattr(c, '_factory_data') # optional - sage.misc.cython + sage: hasattr(c, '_factory_data') # needs sage.misc.cython False We have already seen that our factory will only take the requested @@ -300,7 +302,7 @@ cdef class UniqueFactory(SageObject): sage: fake_factory = UniqueFactory('ZZ') sage: loads(dumps(fake_factory)) Integer Ring - sage: fake_factory = UniqueFactory('sage.rings.all.QQ') + sage: fake_factory = UniqueFactory('sage.rings.rational_field.QQ') sage: loads(dumps(fake_factory)) Rational Field """ @@ -314,6 +316,8 @@ cdef class UniqueFactory(SageObject): sage: A = FiniteField(127) sage: A is loads(dumps(A)) # indirect doctest True + + sage: # needs sage.rings.finite_rings sage: B = FiniteField(3^3,'b') sage: B is loads(dumps(B)) True @@ -394,10 +398,10 @@ cdef class UniqueFactory(SageObject): Check that :trac:`16317` has been fixed, i.e., caching works for unhashable objects:: - sage: K.<u> = Qq(4) - sage: d = test_factory.get_object(3.0, (K(1), 'c'), {}) # optional - sage.rings.padics + sage: K.<u> = Qq(4) # needs sage.rings.padics + sage: d = test_factory.get_object(3.0, (K(1), 'c'), {}) # needs sage.rings.padics Making object (1 + O(2^20), 'c') - sage: d is test_factory.get_object(3.0, (K(1), 'c'), {}) # optional - sage.rings.padics + sage: d is test_factory.get_object(3.0, (K(1), 'c'), {}) # needs sage.rings.padics True """ @@ -516,6 +520,7 @@ cdef class UniqueFactory(SageObject): The ``GF`` factory used to have a custom :meth:`other_keys` method, but this was removed in :trac:`16934`:: + sage: # needs sage.libs.linbox sage.ring.finite_rings sage: key, _ = GF.create_key_and_extra_args(27, 'k'); key (27, ('k',), x^3 + 2*x + 1, 'givaro', 3, 3, True, None, 'poly', True, True, True) sage: K = GF.create_object(0, key); K @@ -523,8 +528,8 @@ cdef class UniqueFactory(SageObject): sage: GF.other_keys(key, K) [] - sage: K = GF(7^40, 'a') - sage: loads(dumps(K)) is K + sage: K = GF(7^40, 'a') # needs sage.rings.finite_rings + sage: loads(dumps(K)) is K # needs sage.rings.finite_rings True """ return [] @@ -538,6 +543,7 @@ cdef class UniqueFactory(SageObject): EXAMPLES:: + sage: # needs sage.modules sage: from sage.modules.free_module import FreeModuleFactory_with_standard_basis as F sage: V = F(ZZ, 5) sage: factory, data = F.reduce_data(V) @@ -636,6 +642,7 @@ def generic_factory_unpickle(factory, *args): EXAMPLES:: + sage: # needs sage.modules sage: from sage.modules.free_module import FreeModuleFactory_with_standard_basis as F sage: V = F(ZZ, 5) sage: func, data = F.reduce_data(V) @@ -728,8 +735,8 @@ def generic_factory_reduce(self, proto): EXAMPLES:: - sage: V = QQ^6 - sage: sage.structure.factory.generic_factory_reduce(V, 1) == V.__reduce_ex__(1) + sage: V = QQ^6 # needs sage.modules + sage: sage.structure.factory.generic_factory_reduce(V, 1) == V.__reduce_ex__(1) # needs sage.modules True """ if self._factory_data is None: @@ -746,7 +753,7 @@ def lookup_global(name): sage: from sage.structure.factory import lookup_global sage: lookup_global('ZZ') Integer Ring - sage: lookup_global('sage.rings.all.ZZ') + sage: lookup_global('sage.rings.integer_ring.ZZ') Integer Ring """ name = bytes_to_str(name, encoding='ASCII') diff --git a/src/sage/structure/formal_sum.py b/src/sage/structure/formal_sum.py index 98178afca79..7d8d5274144 100644 --- a/src/sage/structure/formal_sum.py +++ b/src/sage/structure/formal_sum.py @@ -14,10 +14,11 @@ added. FormalSums now derives from UniqueRepresentation. FUNCTIONS: - - ``FormalSums(ring)`` -- create the module of formal finite sums with - coefficients in the given ring. - - ``FormalSum(list of pairs (coeff, number))`` -- create a formal sum +- ``FormalSums(ring)`` -- create the module of formal finite sums with + coefficients in the given ring. + +- ``FormalSum(list of pairs (coeff, number))`` -- create a formal sum. EXAMPLES:: @@ -49,7 +50,7 @@ True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) @@ -61,8 +62,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.repr import repr_lincomb import operator @@ -73,7 +74,7 @@ from sage.structure.richcmp import richcmp from sage.rings.integer_ring import ZZ from sage.structure.parent import Parent -from sage.structure.coerce import LeftModuleAction, RightModuleAction +from sage.structure.coerce_actions import LeftModuleAction, RightModuleAction from sage.categories.action import PrecomposedAction from sage.structure.unique_representation import UniqueRepresentation @@ -103,16 +104,18 @@ def __init__(self, x, parent=None, check=True, reduce=True): sage: a.reduce() sage: a 4*2/3 - 5*7 - sage: FormalSum([(1,2/3), (3,2/3), (-5, 7)], parent=FormalSums(GF(5))) + sage: FormalSum([(1, 2/3), (3, 2/3), (-5, 7)], parent=FormalSums(GF(5))) 4*2/3 Notice below that the coefficient 5 doesn't get reduced modulo 5:: - sage: FormalSum([(1,2/3), (3,2/3), (-5, 7)], parent=FormalSums(GF(5)), check=False) + sage: FormalSum([(1, 2/3), (3, 2/3), (-5, 7)], parent=FormalSums(GF(5)), + ....: check=False) 4*2/3 - 5*7 Make sure we first reduce before checking coefficient types:: + sage: # needs sage.symbolic sage: x,y = var('x, y') sage: FormalSum([(1/2,x), (2,y)], FormalSums(QQ)) 1/2*x + 2*y @@ -137,7 +140,7 @@ def __init__(self, x, parent=None, check=True, reduce=True): try: self._data = [(k(t[0]), t[1]) for t in self._data] except (IndexError, KeyError) as msg: - raise TypeError("%s\nInvalid formal sum"%msg) + raise TypeError("%s\nInvalid formal sum" % msg) def __iter__(self): """ @@ -311,9 +314,10 @@ class FormalSums(UniqueRepresentation, Module): Abelian Group of all Formal Finite Sums over Integer Ring sage: FormalSums(GF(7)) Abelian Group of all Formal Finite Sums over Finite Field of size 7 - sage: FormalSums(ZZ[sqrt(2)]) - Abelian Group of all Formal Finite Sums over Order in Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? - sage: FormalSums(GF(9,'a')) + sage: FormalSums(ZZ[sqrt(2)]) # needs sage.rings.number_field sage.symbolic + Abelian Group of all Formal Finite Sums over Order in Number Field in sqrt2 + with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? + sage: FormalSums(GF(9,'a')) # needs sage.rings.finite_rings Abelian Group of all Formal Finite Sums over Finite Field in a of size 3^2 TESTS:: @@ -322,8 +326,9 @@ class FormalSums(UniqueRepresentation, Module): """ Element = FormalSum + @staticmethod - def __classcall__(cls, base_ring = ZZ): + def __classcall__(cls, base_ring=ZZ): """ Set the default value for the base ring. @@ -343,7 +348,7 @@ def _repr_(self): sage: FormalSums(GF(7))._repr_() 'Abelian Group of all Formal Finite Sums over Finite Field of size 7' """ - return "Abelian Group of all Formal Finite Sums over %s"%self.base_ring() + return "Abelian Group of all Formal Finite Sums over %s" % self.base_ring() def _element_constructor_(self, x, check=True, reduce=True): """ @@ -418,7 +423,8 @@ def _get_action_(self, other, op, self_is_left): EXAMPLES:: sage: A = FormalSums(RR); A.get_action(RR) # indirect doctest - Right scalar multiplication by Real Field with 53 bits of precision on Abelian Group of all Formal Finite Sums over Real Field with 53 bits of precision + Right scalar multiplication by Real Field with 53 bits of precision + on Abelian Group of all Formal Finite Sums over Real Field with 53 bits of precision sage: A = FormalSums(ZZ); A.get_action(QQ) Right scalar multiplication by Rational Field on Abelian Group of all Formal Finite Sums over Rational Field diff --git a/src/sage/structure/gens_py.py b/src/sage/structure/gens_py.py index c5a4bca56ec..22555a74c92 100644 --- a/src/sage/structure/gens_py.py +++ b/src/sage/structure/gens_py.py @@ -28,7 +28,7 @@ def multiplicative_iterator(M): stop = [g.multiplicative_order() for g in G] for i in range(len(stop)): if stop[i] is infinity: - raise ArithmeticError("%s is not finite."%M) + raise ArithmeticError("%s is not finite." % M) stop[i] = stop[i] - 1 z = M(1) yield z @@ -55,7 +55,7 @@ def abelian_iterator(M): stop = [g.additive_order() for g in G] for i in range(len(stop)): if stop[i] is infinity: - raise ArithmeticError("%s is not finite."%M) + raise ArithmeticError("%s is not finite." % M) stop[i] = stop[i] - 1 z = M(0) yield z diff --git a/src/sage/structure/global_options.py b/src/sage/structure/global_options.py index c97cee38b3f..2c55464e145 100644 --- a/src/sage/structure/global_options.py +++ b/src/sage/structure/global_options.py @@ -387,7 +387,7 @@ class options(GlobalOptions): Here is an example to test the pickling of a :class:`GlobalOptions` instance:: - sage: TestSuite(Partitions.options).run() + sage: TestSuite(Partitions.options).run() # needs sage.combinat TESTS: @@ -526,15 +526,16 @@ class Option(): EXAMPLES:: + sage: # needs sage.combinat sage: Partitions.options.display list - sage: Partitions.options.display='compact' + sage: Partitions.options.display = 'compact' sage: Partitions.options.display('list') sage: Partitions.options._reset() TESTS:: - sage: TestSuite(Partitions.options.display).run() + sage: TestSuite(Partitions.options.display).run() # needs sage.combinat """ __name__ = 'Option class' @@ -545,7 +546,7 @@ def __init__(self, options, name): EXAMPLES:: - sage: type(Partitions.options.display) # indirect doctest + sage: type(Partitions.options.display) # indirect doctest # needs sage.combinat <class 'sage.structure.global_options.Option'> """ self._name = name @@ -559,7 +560,7 @@ def __repr__(self): EXAMPLES:: - sage: Partitions.options.display # indirect doctest + sage: Partitions.options.display # indirect doctest # needs sage.combinat list """ # NOTE: we intentionally use str() instead of repr() @@ -572,7 +573,7 @@ def __add__(self, other): EXAMPLES:: - sage: Tableaux.options.convention +' is good' + sage: Tableaux.options.convention + ' is good' # needs sage.combinat 'English is good' """ return self._options[self._name] + other @@ -584,7 +585,7 @@ def __radd__(self, other): EXAMPLES:: - sage: 'Good '+Tableaux.options.convention + sage: 'Good ' + Tableaux.options.convention # needs sage.combinat 'Good English' """ return other + self._options[self._name] @@ -596,7 +597,7 @@ def __mul__(self, other): EXAMPLES:: - sage: Tableaux.options.convention +' is good' + sage: Tableaux.options.convention + ' is good' # needs sage.combinat 'English is good' """ return self._options[self._name] * other @@ -608,7 +609,7 @@ def __rmul__(self, other): EXAMPLES:: - sage: 'Good '+Tableaux.options.convention + sage: 'Good ' + Tableaux.options.convention # needs sage.combinat 'Good English' """ return other * self._options[self._name] @@ -619,12 +620,13 @@ def __bool__(self) -> bool: EXAMPLES:: + sage: # needs sage.combinat sage.graphs sage.modules sage: RiggedConfigurations.options.half_width_boxes_type_B True - sage: 'yes' if RiggedConfigurations.options.half_width_boxes_type_B else 'no' + sage: 'yes' if RiggedConfigurations.options.half_width_boxes_type_B else 'no' 'yes' - sage: RiggedConfigurations.options.half_width_boxes_type_B=False - sage: 'yes' if RiggedConfigurations.options.half_width_boxes_type_B else 'no' + sage: RiggedConfigurations.options.half_width_boxes_type_B = False + sage: 'yes' if RiggedConfigurations.options.half_width_boxes_type_B else 'no' 'no' sage: RiggedConfigurations.options._reset() """ @@ -636,10 +638,11 @@ def __call__(self, *args, **kwds): EXAMPLES:: - sage: Partitions.options.display() # indirect doctest + sage: # needs sage.combinat + sage: Partitions.options.display() # indirect doctest 'list' - sage: Partitions.options.display('exp') # indirect doctest - sage: Partitions.options.display() # indirect doctest + sage: Partitions.options.display('exp') # indirect doctest + sage: Partitions.options.display() # indirect doctest 'exp_low' sage: Partitions.options._reset() @@ -696,11 +699,11 @@ def __eq__(self, other): EXAMPLES:: - sage: Tableaux.options.convention + sage: Tableaux.options.convention # needs sage.combinat English - sage: Tableaux.options.convention == "English" + sage: Tableaux.options.convention == "English" # needs sage.combinat True - sage: Tableaux.options.convention == "French" + sage: Tableaux.options.convention == "French" # needs sage.combinat False """ return self._options[self._name] == other @@ -712,11 +715,11 @@ def __ne__(self, other): EXAMPLES:: - sage: Tableaux.options.convention + sage: Tableaux.options.convention # needs sage.combinat English - sage: Tableaux.options.convention != "English" + sage: Tableaux.options.convention != "English" # needs sage.combinat False - sage: Tableaux.options.convention != "French" + sage: Tableaux.options.convention != "French" # needs sage.combinat True """ return self._options[self._name] != other @@ -728,7 +731,7 @@ def __hash__(self): EXAMPLES:: - sage: hash(Tableaux.options.convention) == hash(Tableaux.options('convention')) + sage: hash(Tableaux.options.convention) == hash(Tableaux.options('convention')) # needs sage.combinat True """ return hash(self._options[self._name]) @@ -740,7 +743,7 @@ def __str__(self): EXAMPLES:: - sage: str(Tableaux.options.convention) + sage: str(Tableaux.options.convention) # needs sage.combinat 'English' """ return str(self._options[self._name]) @@ -1232,7 +1235,7 @@ def _instancedoc_(self): EXAMPLES:: - sage: print(Partitions.options.__doc__) + sage: print(Partitions.options.__doc__) # needs sage.combinat <BLANKLINE> Sets and displays the global options for elements of the partition, skew partition, and partition tuple classes. If no parameters are @@ -1273,12 +1276,12 @@ def __setattr__(self, name, value=None): EXAMPLES:: - sage: Partitions.options.display = 'exp' - sage: Partitions.options.dispplay = 'list' + sage: Partitions.options.display = 'exp' # needs sage.combinat + sage: Partitions.options.dispplay = 'list' # needs sage.combinat Traceback (most recent call last): ... ValueError: dispplay is not an option for Partitions - sage: Partitions.options._reset() + sage: Partitions.options._reset() # needs sage.combinat """ # Underscore, and "special", attributes are set using type.__setattr__ if name[0] == '_' or name in ['reset', 'dispatch', 'default_value']: @@ -1298,6 +1301,7 @@ def __setstate__(self, state): EXAMPLES:: + sage: # needs sage.combinat sage: Partitions.options() Current options for Partitions - convention: English @@ -1305,7 +1309,7 @@ def __setstate__(self, state): - display: list - latex: young_diagram - latex_diagram_str: \ast - sage: Partitions.options.convention="French" + sage: Partitions.options.convention = "French" sage: pickle = dumps(Partitions.options) sage: Partitions.options._reset() # reset options sage: loads(pickle) # indirect doctest @@ -1350,8 +1354,8 @@ def __getstate__(self): EXAMPLES:: - sage: Partitions.options._reset() - sage: Partitions.options.__getstate__() + sage: Partitions.options._reset() # needs sage.combinat + sage: Partitions.options.__getstate__() # needs sage.combinat {'convention': 'English', 'option_class': 'Partitions', 'options_module': 'sage.combinat.partition'} @@ -1385,9 +1389,9 @@ def __eq__(self, other): EXAMPLES:: - sage: Partitions.options == PartitionsGreatestLE.options # indirect doctest + sage: Partitions.options == PartitionsGreatestLE.options # indirect doctest # needs sage.combinat True - sage: Partitions.options == Tableaux.options + sage: Partitions.options == Tableaux.options # needs sage.combinat False """ return isinstance(other, GlobalOptions) and self.__getstate__() == other.__getstate__() diff --git a/src/sage/structure/graphics_file.py b/src/sage/structure/graphics_file.py deleted file mode 100644 index 929b99c1ccb..00000000000 --- a/src/sage/structure/graphics_file.py +++ /dev/null @@ -1,260 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Wrapper for Graphics Files - -This module is deprecated. -""" - -import os - -from sage.misc.temporary_file import tmp_filename -from sage.misc.superseded import deprecation -from sage.structure.sage_object import SageObject -import sage.doctest - - -deprecation(32988, 'the module sage.structure.graphics_file is deprecated') - - -class Mime(): - TEXT = 'text/plain' - HTML = 'text/html' - LATEX = 'text/latex' - JSON = 'application/json' - JAVASCRIPT = 'application/javascript' - PDF = 'application/pdf' - PNG = 'image/png' - JPG = 'image/jpeg' - SVG = 'image/svg+xml' - - JMOL = 'application/jmol' - - @classmethod - def validate(cls, value): - """ - Check that input is known mime type - - INPUT: - - - ``value`` -- string. - - OUTPUT: - - Unicode string of that mime type. A ``ValueError`` is raised - if input is incorrect / unknown. - - EXAMPLES:: - - sage: from sage.structure.graphics_file import Mime - doctest:warning... - DeprecationWarning: the module sage.structure.graphics_file is deprecated - See https://github.com/sagemath/sage/issues/32988 for details. - sage: Mime.validate('image/png') - 'image/png' - sage: Mime.validate('foo/bar') - Traceback (most recent call last): - ... - ValueError: unknown mime type - """ - value = str(value).lower() - for k, v in cls.__dict__.items(): - if isinstance(v, str) and v == value: - return v - raise ValueError('unknown mime type') - - @classmethod - def extension(cls, mime_type): - """ - Return file extension. - - INPUT: - - - ``mime_type`` -- mime type as string. - - OUTPUT: - - String containing the usual file extension for that type of - file. Excludes ``os.extsep``. - - EXAMPLES:: - - sage: from sage.structure.graphics_file import Mime - sage: Mime.extension('image/png') - 'png' - """ - try: - return preferred_filename_ext[mime_type] - except KeyError: - raise ValueError('no known extension for mime type') - - -preferred_filename_ext = { - Mime.TEXT: 'txt', - Mime.HTML: 'html', - Mime.LATEX: 'tex', - Mime.JSON: 'json', - Mime.JAVASCRIPT: 'js', - Mime.PDF: 'pdf', - Mime.PNG: 'png', - Mime.JPG: 'jpg', - Mime.SVG: 'svg', - Mime.JMOL: 'spt.zip', -} - - -mimetype_for_ext = dict( - (value, key) for (key, value) in preferred_filename_ext.items() -) - - -class GraphicsFile(SageObject): - - def __init__(self, filename, mime_type=None): - """ - Wrapper around a graphics file. - """ - self._filename = filename - if mime_type is None: - mime_type = self._guess_mime_type(filename) - self._mime = Mime.validate(mime_type) - - def _guess_mime_type(self, filename): - """ - Guess mime type from file extension - """ - ext = os.path.splitext(filename)[1] - ext = ext.lstrip(os.path.extsep) - try: - return mimetype_for_ext[ext] - except KeyError: - raise ValueError('unknown file extension, please specify mime type') - - def _repr_(self): - """ - Return a string representation. - """ - return 'Graphics file {0}'.format(self.mime()) - - def filename(self): - return self._filename - - def save_as(self, filename): - """ - Make the file available under a new filename. - - INPUT: - - - ``filename`` -- string. The new filename. - - The newly-created ``filename`` will be a hardlink if - possible. If not, an independent copy is created. - """ - try: - os.link(self.filename(), filename) - except OSError: - import shutil - shutil.copy2(self.filename(), filename) - - def mime(self): - return self._mime - - def data(self): - """ - Return a byte string containing the image file. - """ - with open(self._filename, 'rb') as f: - return f.read() - - def launch_viewer(self): - """ - Launch external viewer for the graphics file. - - .. note:: - - Does not actually launch a new process when doctesting. - - EXAMPLES:: - - sage: from sage.structure.graphics_file import GraphicsFile - sage: g = GraphicsFile('/tmp/test.png', 'image/png') - sage: g.launch_viewer() - """ - if sage.doctest.DOCTEST_MODE: - return - if self.mime() == Mime.JMOL: - return self._launch_jmol() - from sage.misc.viewer import viewer - command = viewer(preferred_filename_ext[self.mime()]) - os.system('{0} {1} 2>/dev/null 1>/dev/null &' - .format(command, self.filename())) - # TODO: keep track of opened processes... - - def _launch_jmol(self): - launch_script = tmp_filename(ext='.spt') - with open(launch_script, 'w') as f: - f.write('set defaultdirectory "{0}"\n'.format(self.filename())) - f.write('script SCRIPT\n') - os.system('jmol {0} 2>/dev/null 1>/dev/null &' - .format(launch_script)) - - -def graphics_from_save(save_function, preferred_mime_types, - allowed_mime_types=None, figsize=None, dpi=None): - """ - Helper function to construct a graphics file. - - INPUT: - - - ``save_function`` -- callable that can save graphics to a file - and accepts options like - :meth:`sage.plot.graphics.Graphics.save`. - - - ``preferred_mime_types`` -- list of mime types. The graphics - output mime types in order of preference (i.e. best quality to - worst). - - - ``allowed_mime_types`` -- set of mime types (as strings). The - graphics types that we can display. Output, if any, will be one - of those. - - - ``figsize`` -- pair of integers (optional). The desired graphics - size in pixels. Suggested, but need not be respected by the - output. - - - ``dpi`` -- integer (optional). The desired resolution in dots - per inch. Suggested, but need not be respected by the output. - - OUTPUT: - - Return an instance of - :class:`sage.structure.graphics_file.GraphicsFile` encapsulating a - suitable image file. Image is one of the - ``preferred_mime_types``. If ``allowed_mime_types`` is specified, - the resulting file format matches one of these. - - Alternatively, this function can return ``None`` to indicate that - textual representation is preferable and/or no graphics with the - desired mime type can be generated. - """ - # Figure out best mime type - mime = None - if allowed_mime_types is None: - mime = Mime.PNG - else: - # order of preference - for m in preferred_mime_types: - if m in allowed_mime_types: - mime = m - break - if mime is None: - return None # don't know how to generate suitable graphics - # Generate suitable temp file - filename = tmp_filename(ext=os.path.extsep + Mime.extension(mime)) - # Call the save_function with the right arguments - kwds = {} - if figsize is not None: - kwds['figsize'] = figsize - if dpi is not None: - kwds['dpi'] = dpi - save_function(filename, **kwds) - return GraphicsFile(filename, mime) diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index 4cf80c3522d..3ccff8a6706 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -174,8 +174,8 @@ def indices(self): EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) - sage: F.indices() + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) # needs sage.modules + sage: F.indices() # needs sage.modules {'a', 'b', 'c'} """ return self._indices @@ -186,14 +186,14 @@ def prefix(self): EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) - sage: F.prefix() + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) # needs sage.modules + sage: F.prefix() # needs sage.modules 'B' :: - sage: X = SchubertPolynomialRing(QQ) - sage: X.prefix() + sage: X = SchubertPolynomialRing(QQ) # needs sage.combinat sage.modules + sage: X.prefix() # needs sage.combinat sage.modules 'X' """ return self._print_options['prefix'] @@ -229,6 +229,7 @@ def print_options(self, **kwds): EXAMPLES:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(ZZ, [1,2,3], prefix='x') sage: F.print_options() {...'prefix': 'x'...} @@ -238,7 +239,7 @@ def print_options(self, **kwds): TESTS:: - sage: sorted(F.print_options().items()) + sage: sorted(F.print_options().items()) # needs sage.modules [('bracket', '('), ('iterate_key', False), ('latex_bracket', False), ('latex_names', None), ('latex_prefix', None), ('latex_scalar_mult', None), @@ -247,7 +248,7 @@ def print_options(self, **kwds): ('sorting_key', <function ...<lambda> at ...>), ('sorting_reverse', False), ('string_quotes', True), ('tensor_symbol', None)] - sage: F.print_options(bracket='[') # reset + sage: F.print_options(bracket='[') # reset # needs sage.modules """ # don't just use kwds.get(...) because I want to distinguish # between an argument like "option=None" and the option not @@ -270,17 +271,18 @@ def _parse_names(self, m, use_latex): EXAMPLES:: - sage: F = CombinatorialFreeModule(ZZ, [1,2,3], names='a,b,c', + sage: F = CombinatorialFreeModule(ZZ, [1,2,3], names='a,b,c', # needs sage.modules ....: latex_names='x,y,z') - sage: F._parse_names(1, False) + sage: F._parse_names(1, False) # needs sage.modules 'a' - sage: F._parse_names(1, True) + sage: F._parse_names(1, True) # needs sage.modules 'x' - sage: F.print_options(latex_names=None) - sage: F._parse_names(1, True) + sage: F.print_options(latex_names=None) # needs sage.modules + sage: F._parse_names(1, True) # needs sage.modules 'a' + sage: # needs sage.modules sage: F.print_options(latex_names={1:'x', 2:'y'}, names=None) sage: F._parse_names(1, False) is None True @@ -289,6 +291,7 @@ def _parse_names(self, m, use_latex): sage: F._parse_names(3, True) is None True + sage: # needs sage.modules sage: F.print_options(names={1:'a', 3:'c'}, latex_names=None) sage: F._parse_names(1, False) 'a' @@ -349,11 +352,12 @@ def _repr_generator(self, m): EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) - sage: e = F.basis() - sage: e['a'] + 2*e['b'] # indirect doctest + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) # needs sage.modules + sage: e = F.basis() # needs sage.modules + sage: e['a'] + 2*e['b'] # indirect doctest # needs sage.modules B['a'] + 2*B['b'] + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'], prefix="F") sage: e = F.basis() sage: e['a'] + 2*e['b'] # indirect doctest @@ -362,6 +366,7 @@ def _repr_generator(self, m): sage: e['a'] + 2*e['b'] F[a] + 2*F[b] + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ['aa', 'bb', 'cc'], prefix="F") sage: e = F.basis() sage: F.print_options(iterate_key=True) @@ -371,41 +376,43 @@ def _repr_generator(self, m): sage: e['aa'] + 2*e['bb'] F[a, a] + 2*F[b, b] + sage: # needs sage.combinat sage.modules sage: QS3 = CombinatorialFreeModule(QQ, Permutations(3), prefix="") sage: original_print_options = QS3.print_options() sage: a = 2*QS3([1,2,3])+4*QS3([3,2,1]) sage: a # indirect doctest 2*[[1, 2, 3]] + 4*[[3, 2, 1]] - sage: QS3.print_options(bracket = False) - sage: a # indirect doctest + sage: QS3.print_options(bracket = False) # needs sage.combinat sage.modules + sage: a # indirect doctest # needs sage.combinat sage.modules 2*[1, 2, 3] + 4*[3, 2, 1] - sage: QS3.print_options(prefix='') - sage: a # indirect doctest + sage: QS3.print_options(prefix='') # needs sage.combinat sage.modules + sage: a # indirect doctest # needs sage.combinat sage.modules 2*[1, 2, 3] + 4*[3, 2, 1] - sage: QS3.print_options(bracket="|", scalar_mult=" *@* ") - sage: a # indirect doctest + sage: QS3.print_options(bracket="|", scalar_mult=" *@* ") # needs sage.combinat sage.modules + sage: a # indirect doctest # needs sage.combinat sage.modules 2 *@* |[1, 2, 3]| + 4 *@* |[3, 2, 1]| - sage: QS3.print_options(bracket="|", scalar_mult="*", iterate_key=True) - sage: a # indirect doctest + sage: QS3.print_options(bracket="|", scalar_mult="*", iterate_key=True) # needs sage.combinat sage.modules + sage: a # indirect doctest # needs sage.combinat sage.modules 2*|1, 2, 3| + 4*|3, 2, 1| - sage: QS3.print_options(**original_print_options) # reset + sage: QS3.print_options(**original_print_options) # reset # needs sage.combinat sage.modules TESTS:: - sage: F = CombinatorialFreeModule(QQ, [('a', 'b'), ('c','d')]) - sage: e = F.basis() - sage: e[('a','b')] + 2*e[('c','d')] # indirect doctest + sage: F = CombinatorialFreeModule(QQ, [('a', 'b'), ('c','d')]) # needs sage.modules + sage: e = F.basis() # needs sage.modules + sage: e[('a','b')] + 2*e[('c','d')] # indirect doctest # needs sage.modules B[('a', 'b')] + 2*B[('c', 'd')] - sage: F.<a,b,c> = CombinatorialFreeModule(QQ) - sage: a + 2*b + sage: F.<a,b,c> = CombinatorialFreeModule(QQ) # needs sage.modules + sage: a + 2*b # needs sage.modules a + 2*b + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, ZZ) sage: e = F.basis() sage: 3*e[1] + 2*e[-2] @@ -457,6 +464,7 @@ def _ascii_art_generator(self, m): TESTS:: + sage: # needs sage.combinat sage.modules sage: R = NonCommutativeSymmetricFunctions(QQ).R() sage: ascii_art(R[1,2,2,4]) R @@ -473,8 +481,8 @@ def _ascii_art_generator(self, m): #### sage: Partitions.options._reset() - sage: F.<a,b,c> = CombinatorialFreeModule(QQ) - sage: ascii_art(a + 2*b) + sage: F.<a,b,c> = CombinatorialFreeModule(QQ) # needs sage.modules + sage: ascii_art(a + 2*b) # needs sage.modules a + 2*b """ from sage.typeset.ascii_art import AsciiArt, ascii_art @@ -493,8 +501,9 @@ def _unicode_art_generator(self, m): TESTS:: - sage: R = NonCommutativeSymmetricFunctions(QQ).R() - sage: unicode_art(R[1,2,2,4]) + sage: # needs sage.combinat + sage: R = NonCommutativeSymmetricFunctions(QQ).R() # needs sage.modules + sage: unicode_art(R[1,2,2,4]) # needs sage.modules R โ”Œโ”ฌโ”ฌโ”ฌโ” โ”Œโ”ผโ”ผโ”ดโ”ดโ”˜ @@ -502,7 +511,7 @@ def _unicode_art_generator(self, m): โ”œโ”ผโ”˜ โ””โ”˜ sage: Partitions.options.convention="french" - sage: unicode_art(R[1,2,2,4]) + sage: unicode_art(R[1,2,2,4]) # needs sage.modules R โ”Œโ” โ”œโ”ผโ” @@ -511,8 +520,8 @@ def _unicode_art_generator(self, m): โ””โ”ดโ”ดโ”ดโ”˜ sage: Partitions.options._reset() - sage: F.<a,b,c> = CombinatorialFreeModule(QQ) - sage: unicode_art(a + 2*b) + sage: F.<a,b,c> = CombinatorialFreeModule(QQ) # needs sage.modules + sage: unicode_art(a + 2*b) # needs sage.modules a + 2*b """ from sage.typeset.unicode_art import UnicodeArt, unicode_art @@ -546,17 +555,19 @@ def _latex_generator(self, m): EXAMPLES:: - sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) - sage: e = F.basis() - sage: latex(e['a'] + 2*e['b']) # indirect doctest + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) # needs sage.modules + sage: e = F.basis() # needs sage.modules + sage: latex(e['a'] + 2*e['b']) # indirect doctest # needs sage.modules B_{a} + 2 B_{b} - sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'], prefix="C") - sage: e = F.basis() - sage: latex(e['a'] + 2*e['b']) # indirect doctest + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'], prefix="C") # needs sage.modules + sage: e = F.basis() # needs sage.modules + sage: latex(e['a'] + 2*e['b']) # indirect doctest # needs sage.modules C_{a} + 2 C_{b} - sage: QS3 = CombinatorialFreeModule(QQ, Permutations(3), prefix="", scalar_mult="*") + sage: # needs sage.combinat sage.modules + sage: QS3 = CombinatorialFreeModule(QQ, Permutations(3), + ....: prefix="", scalar_mult="*") sage: original_print_options = QS3.print_options() sage: a = 2*QS3([1,2,3])+4*QS3([3,2,1]) sage: latex(a) # indirect doctest @@ -567,13 +578,15 @@ def _latex_generator(self, m): sage: QS3.print_options(latex_bracket="(") sage: latex(a) # indirect doctest 2 \left( [1, 2, 3] \right) + 4 \left( [3, 2, 1] \right) - sage: QS3.print_options(latex_bracket=('\\myleftbracket', '\\myrightbracket')) + sage: QS3.print_options(latex_bracket=('\\myleftbracket', + ....: '\\myrightbracket')) sage: latex(a) # indirect doctest 2 \myleftbracket [1, 2, 3] \myrightbracket + 4 \myleftbracket [3, 2, 1] \myrightbracket sage: QS3.print_options(**original_print_options) # reset TESTS:: + sage: # needs sage.modules sage: F = CombinatorialFreeModule(QQ, [('a', 'b'), (0,1,2)]) sage: e = F.basis() sage: latex(e[('a','b')]) # indirect doctest @@ -585,8 +598,8 @@ def _latex_generator(self, m): sage: latex(2*e[(0,1,2)]) # indirect doctest 2 \left(0, 1, 2\right) - sage: F.<a,b,c> = CombinatorialFreeModule(QQ, latex_names='x,y,z') - sage: latex(a + 2*b) + sage: F.<a,b,c> = CombinatorialFreeModule(QQ, latex_names='x,y,z') # needs sage.modules + sage: latex(a + 2*b) # needs sage.modules x + 2 y """ from sage.misc.latex import latex diff --git a/src/sage/structure/list_clone.pyx b/src/sage/structure/list_clone.pyx index 61a6823fc11..ae50771c7b8 100644 --- a/src/sage/structure/list_clone.pyx +++ b/src/sage/structure/list_clone.pyx @@ -141,7 +141,7 @@ AUTHORS: # **************************************************************************** from cpython.list cimport * -from cpython.int cimport * +from cpython.long cimport * from cpython.ref cimport * from cysignals.memory cimport check_reallocarray, sig_free @@ -1391,7 +1391,7 @@ cdef class ClonableIntArray(ClonableElement): cdef list L = <list> PyList_New(self._len) cdef object o for i in range(self._len): - o = PyInt_FromLong(self._list[i]) + o = PyLong_FromLong(self._list[i]) Py_INCREF(o) PyList_SET_ITEM(L, i, o) return L diff --git a/src/sage/structure/nonexact.py b/src/sage/structure/nonexact.py index 4157295be90..ffb39e5f579 100644 --- a/src/sage/structure/nonexact.py +++ b/src/sage/structure/nonexact.py @@ -50,6 +50,7 @@ def default_prec(self): EXAMPLES:: + sage: x = polygen(ZZ, 'x') sage: R = QQ[[x]] sage: R.default_prec() 20 diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 25c4157c3df..6548d8a3656 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -86,7 +86,7 @@ TESTS: This came up in some subtle bug once:: - sage: gp(2) + gap(3) + sage: gp(2) + gap(3) # needs sage.libs.gap sage.libs.pari 5 """ # **************************************************************************** @@ -103,7 +103,7 @@ This came up in some subtle bug once:: # https://www.gnu.org/licenses/ # **************************************************************************** -from cpython.object cimport PyObject, Py_NE, Py_EQ, Py_LE, Py_GE +from cpython.object cimport Py_EQ, Py_LE, Py_GE from cpython.bool cimport * from types import MethodType, BuiltinMethodType @@ -111,7 +111,6 @@ import operator from copy import copy from sage.cpython.type cimport can_assign_class -cimport sage.categories.morphism as morphism cimport sage.categories.map as map from sage.structure.debug_options cimport debug from sage.structure.sage_object cimport SageObject @@ -119,14 +118,14 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.categories.sets_cat import Sets, EmptySetError from sage.misc.lazy_string cimport _LazyString -from sage.sets.pythonclass cimport Set_PythonType_class, Set_PythonType +from sage.sets.pythonclass cimport Set_PythonType_class from .category_object import CategoryObject from .coerce cimport coercion_model from .coerce cimport parent_is_integers from .coerce_exceptions import CoercionException from .coerce_maps cimport (NamedConvertMap, DefaultConvertMap, DefaultConvertMap_unique, CallableConvertMap) -from .element cimport parent, Element +from .element cimport parent cdef _record_exception(): @@ -362,16 +361,22 @@ cdef class Parent(sage.structure.category_object.CategoryObject): EXAMPLES:: sage: P.<x,y> = QQ[] - sage: Q = P.quotient(x^2+2) + sage: Q = P.quotient(x^2 + 2) sage: Q.category() - Join of Category of commutative rings and Category of subquotients of monoids and Category of quotients of semigroups + Join of + Category of commutative rings and + Category of subquotients of monoids and + Category of quotients of semigroups sage: first_class = Q.__class__ sage: Q._refine_category_(Fields()) sage: Q.category() - Join of Category of fields and Category of subquotients of monoids and Category of quotients of semigroups + Join of + Category of fields and + Category of subquotients of monoids and + Category of quotients of semigroups sage: first_class == Q.__class__ False - sage: TestSuite(Q).run() + sage: TestSuite(Q).run() # needs sage.libs.singular TESTS: @@ -775,7 +780,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): TESTS:: - sage: loads(dumps(CDF['x'])) == CDF['x'] + sage: loads(dumps(CDF['x'])) == CDF['x'] # needs sage.rings.complex_double True """ CategoryObject.__setstate__(self, d) @@ -824,10 +829,10 @@ cdef class Parent(sage.structure.category_object.CategoryObject): sage: ZZ._repr_option('ascii_art') False - sage: MatrixSpace(ZZ, 2)._repr_option('element_ascii_art') + sage: MatrixSpace(ZZ, 2)._repr_option('element_ascii_art') # needs sage.modules True """ - if not isinstance(key, basestring): + if not isinstance(key, str): raise ValueError('key must be a string') defaults = {'ascii_art': False, 'element_ascii_art': False, @@ -910,36 +915,37 @@ cdef class Parent(sage.structure.category_object.CategoryObject): EXAMPLES:: - sage: MS = MatrixSpace(QQ,2,2) + sage: MS = MatrixSpace(QQ, 2, 2) # needs sage.modules This matrix space is in fact an algebra, and in particular it is a ring, from the point of view of categories:: - sage: MS.category() + sage: MS.category() # needs sage.modules Category of infinite finite dimensional algebras with basis over (number fields and quotient fields and metric spaces) - sage: MS in Rings() + sage: MS in Rings() # needs sage.modules True However, its class does not inherit from the base class ``Ring``:: - sage: isinstance(MS,Ring) + sage: isinstance(MS, Ring) # needs sage.modules False Its ``_mul_`` method is inherited from the category, and can be used to create a left or right ideal:: + sage: # needs sage.modules sage: MS._mul_.__module__ 'sage.categories.rings' - sage: MS*MS.1 # indirect doctest + sage: MS * MS.1 # indirect doctest Left Ideal ( [0 1] [0 0] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: MS*[MS.1,2] + sage: MS * [MS.1, 2] Left Ideal ( [0 1] @@ -949,14 +955,14 @@ cdef class Parent(sage.structure.category_object.CategoryObject): [0 2] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: MS.1*MS + sage: MS.1 * MS Right Ideal ( [0 1] [0 0] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: [MS.1,2]*MS + sage: [MS.1, 2] * MS Right Ideal ( [0 1] @@ -1005,12 +1011,13 @@ cdef class Parent(sage.structure.category_object.CategoryObject): TESTS:: + sage: # needs sage.modules sage: ZZ^3 Ambient free module of rank 3 over the principal ideal domain Integer Ring sage: QQ^3 Vector space of dimension 3 over Rational Field - sage: QQ[x]^3 + sage: QQ['x']^3 Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in x over Rational Field sage: IntegerModRing(6)^3 @@ -1020,7 +1027,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for ^: 'Integer Ring' and '<class 'sage.rings.integer_ring.IntegerRing_class'>' - sage: Partitions(3)^3 + sage: Partitions(3)^3 # needs sage.combinat sage.modules Traceback (most recent call last): ... TypeError: unsupported operand type(s) for ** or pow(): 'Partitions_n_with_category' and 'int' @@ -1076,13 +1083,15 @@ cdef class Parent(sage.structure.category_object.CategoryObject): True sage: 5 in QQ True - sage: I in RR + sage: I in RR # needs sage.rings.real_mpfr sage.symbolic False - sage: SR(2) in ZZ + sage: RIF(1, 2) in RIF # needs sage.rings.real_interval_field True - sage: RIF(1, 2) in RIF + + sage: # needs sage.symbolic + sage: SR(2) in ZZ True - sage: pi in RIF # there is no element of RIF equal to pi + sage: pi in RIF # there is no element of RIF equal to pi False sage: sqrt(2) in CC True @@ -1099,31 +1108,31 @@ cdef class Parent(sage.structure.category_object.CategoryObject): :: - sage: 3/2 in RIF + sage: 3/2 in RIF # needs sage.rings.real_interval_field True because ``3/2`` has an exact representation in ``RIF`` (i.e. can be represented as an interval that contains exactly one value):: - sage: RIF(3/2).is_exact() + sage: RIF(3/2).is_exact() # needs sage.rings.real_interval_field True On the other hand, we have :: - sage: 2/3 in RIF + sage: 2/3 in RIF # needs sage.rings.real_interval_field False because ``2/3`` has no exact representation in ``RIF``. Since ``RIF(2/3)`` is a nontrivial interval, it cannot be equal to anything (not even itself):: - sage: RIF(2/3).is_exact() + sage: RIF(2/3).is_exact() # needs sage.rings.real_interval_field False - sage: RIF(2/3).endpoints() + sage: RIF(2/3).endpoints() # needs sage.rings.real_interval_field (0.666666666666666, 0.666666666666667) - sage: RIF(2/3) == RIF(2/3) + sage: RIF(2/3) == RIF(2/3) # needs sage.rings.real_interval_field False TESTS: @@ -1132,7 +1141,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): sage: 4/3 in GF(3) False - sage: 15/50 in GF(25, 'a') + sage: 15/50 in GF(25, 'a') # needs sage.rings.finite_rings False sage: 7/4 in Integers(4) False @@ -1149,9 +1158,9 @@ cdef class Parent(sage.structure.category_object.CategoryObject): Check that :trac:`24209` is fixed:: - sage: I in QQbar + sage: I in QQbar # needs sage.rings.number_field True - sage: sqrt(-1) in QQbar + sage: sqrt(-1) in QQbar # needs sage.rings.number_field sage.symbolic True """ P = parent(x) @@ -1195,8 +1204,8 @@ cdef class Parent(sage.structure.category_object.CategoryObject): We make an exception for zero:: - sage: V = GF(7)^7 - sage: V.coerce(0) + sage: V = GF(7)^7 # needs sage.modules + sage: V.coerce(0) # needs sage.modules (0, 0, 0, 0, 0, 0, 0) """ cdef R = parent(x) @@ -1234,7 +1243,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): EXAMPLES:: - sage: VectorSpace(GF(7), 3)[:10] + sage: VectorSpace(GF(7), 3)[:10] # needs sage.modules [(0, 0, 0), (1, 0, 0), (2, 0, 0), @@ -1335,7 +1344,8 @@ cdef class Parent(sage.structure.category_object.CategoryObject): r""" Return the unique homomorphism from self to codomain that sends ``self.gens()`` to the entries of ``im_gens``. - Raises a TypeError if there is no such homomorphism. + + This raises a :class:`TypeError` if there is no such homomorphism. INPUT: @@ -1374,8 +1384,10 @@ cdef class Parent(sage.structure.category_object.CategoryObject): sage: f = R.hom([5], GF(7)) Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators + sage: # needs sage.rings.finite_rings sage: R.<x> = PolynomialRing(GF(7)) sage: f = R.hom([3], GF(49,'a')) sage: f @@ -1383,9 +1395,9 @@ cdef class Parent(sage.structure.category_object.CategoryObject): From: Univariate Polynomial Ring in x over Finite Field of size 7 To: Finite Field in a of size 7^2 Defn: x |--> 3 - sage: f(x+6) + sage: f(x + 6) 2 - sage: f(x^2+1) + sage: f(x^2 + 1) 3 Natural morphism:: @@ -1677,11 +1689,13 @@ cdef class Parent(sage.structure.category_object.CategoryObject): ....: D[tuple(nk)] = v ....: return a.parent()(D) + sage: # needs sage.groups sage: R.<x, y, z> = QQ['x, y, z'] sage: G = SymmetricGroup(3) sage: act = SymmetricGroupAction(G, R) sage: t = x + 2*y + 3*z + sage: # needs sage.groups sage: act(G((1, 2)), t) 2*x + y + 3*z sage: act(G((2, 3)), t) @@ -1692,13 +1706,14 @@ cdef class Parent(sage.structure.category_object.CategoryObject): This should fail, since we have not registered the left action:: - sage: G((1,2)) * t + sage: G((1,2)) * t # needs sage.groups Traceback (most recent call last): ... TypeError: ... Now let's make it work:: + sage: # needs sage.groups sage: R._unset_coercions_used() sage: R.register_action(act) sage: G((1, 2)) * t @@ -1762,20 +1777,21 @@ cdef class Parent(sage.structure.category_object.CategoryObject): EXAMPLES:: - sage: S3 = AlternatingGroup(3) - sage: G = SL(3, QQ) - sage: p = S3[2]; p.matrix() + sage: S3 = AlternatingGroup(3) # needs sage.groups + sage: G = SL(3, QQ) # needs sage.groups + sage: p = S3[2]; p.matrix() # needs sage.groups [0 0 1] [1 0 0] [0 1 0] In general one cannot mix matrices and permutations:: + sage: # needs sage.groups sage: G(p) Traceback (most recent call last): ... TypeError: unable to convert (1,3,2) to a rational - sage: phi = S3.hom(lambda p: G(p.matrix()), codomain = G) + sage: phi = S3.hom(lambda p: G(p.matrix()), codomain=G) sage: phi(p) [0 0 1] [1 0 0] @@ -1786,11 +1802,11 @@ cdef class Parent(sage.structure.category_object.CategoryObject): By :trac:`14711`, coerce maps should be copied when using outside of the coercion system:: - sage: phi = copy(S3.coerce_embedding()); phi + sage: phi = copy(S3.coerce_embedding()); phi # needs sage.groups Generic morphism: From: Alternating group of order 3!/2 as a permutation group To: Special Linear Group of degree 3 over Rational Field - sage: phi(p) + sage: phi(p) # needs sage.groups [0 0 1] [1 0 0] [0 1 0] @@ -1798,17 +1814,18 @@ cdef class Parent(sage.structure.category_object.CategoryObject): This does not work since matrix groups are still old-style parents (see :trac:`14014`):: - sage: G(p) # todo: not implemented + sage: G(p) # not implemented # needs sage.groups Though one can have a permutation act on the rows of a matrix:: - sage: G(1) * p + sage: G(1) * p # needs sage.groups [0 0 1] [1 0 0] [0 1 0] Some more advanced examples:: + sage: # needs sage.rings.number_field sage: x = QQ['x'].0 sage: t = abs(ZZ.random_element(10^6)) sage: K = NumberField(x^2 + 2*3*7*11, "a"+str(t)) @@ -1817,23 +1834,25 @@ cdef class Parent(sage.structure.category_object.CategoryObject): sage: K._unset_coercions_used() sage: K.register_embedding(K_into_MS) - sage: L = NumberField(x^2 + 2*3*7*11*19*31, "b"+str(abs(ZZ.random_element(10^6)))) + sage: # needs sage.rings.number_field + sage: L = NumberField(x^2 + 2*3*7*11*19*31, + ....: "b" + str(abs(ZZ.random_element(10^6)))) sage: b = L.gen() sage: L_into_MS = L.hom([b.matrix()]) sage: L._unset_coercions_used() sage: L.register_embedding(L_into_MS) - sage: K.coerce_embedding()(a) + sage: K.coerce_embedding()(a) # needs sage.rings.number_field [ 0 1] [-462 0] - sage: L.coerce_embedding()(b) + sage: L.coerce_embedding()(b) # needs sage.rings.number_field [ 0 1] [-272118 0] - sage: a.matrix() * b.matrix() + sage: a.matrix() * b.matrix() # needs sage.rings.number_field [-272118 0] [ 0 -462] - sage: a.matrix() * b.matrix() + sage: a.matrix() * b.matrix() # needs sage.rings.number_field [-272118 0] [ 0 -462] """ @@ -1862,16 +1881,20 @@ cdef class Parent(sage.structure.category_object.CategoryObject): EXAMPLES:: - sage: K.<a>=NumberField(x^3+x^2+1,embedding=1) + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 + x^2 + 1, embedding=1) sage: K.coerce_embedding() Generic morphism: - From: Number Field in a with defining polynomial x^3 + x^2 + 1 with a = -1.465571231876768? + From: Number Field in a with defining polynomial x^3 + x^2 + 1 + with a = -1.465571231876768? To: Real Lazy Field Defn: a -> -1.465571231876768? - sage: K.<a>=NumberField(x^3+x^2+1,embedding=CC.gen()) + sage: K.<a> = NumberField(x^3 + x^2 + 1, embedding=CC.gen()) sage: K.coerce_embedding() Generic morphism: - From: Number Field in a with defining polynomial x^3 + x^2 + 1 with a = 0.2327856159383841? + 0.7925519925154479?*I + From: Number Field in a with defining polynomial x^3 + x^2 + 1 + with a = 0.2327856159383841? + 0.7925519925154479?*I To: Complex Lazy Field Defn: a -> 0.2327856159383841? + 0.7925519925154479?*I """ @@ -1922,7 +1945,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): EXAMPLES:: - sage: QQ['x']._generic_convert_map(SR) + sage: QQ['x']._generic_convert_map(SR) # needs sage.symbolic Conversion via _polynomial_ method map: From: Symbolic Ring To: Univariate Polynomial Ring in x over Rational Field @@ -2004,7 +2027,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): By :trac:`14711`, coerce maps should be copied for usage outside of the coercion system:: - sage: copy(CDF._coerce_map_via([ZZ, RR, CC], int)) + sage: copy(CDF._coerce_map_via([ZZ, RR, CC], int)) # needs sage.rings.complex_double Composite map: From: Set of Python objects of class 'int' To: Complex Double Field @@ -2016,7 +2039,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): From: Integer Ring To: Complex Double Field - sage: copy(CDF._coerce_map_via([ZZ, RR, CC], QQ)) + sage: copy(CDF._coerce_map_via([ZZ, RR, CC], QQ)) # needs sage.rings.complex_double Composite map: From: Rational Field To: Complex Double Field @@ -2028,7 +2051,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): From: Real Field with 53 bits of precision To: Complex Double Field - sage: copy(CDF._coerce_map_via([ZZ, RR, CC], CC)) + sage: copy(CDF._coerce_map_via([ZZ, RR, CC], CC)) # needs sage.rings.complex_double Generic map: From: Complex Field with 53 bits of precision To: Complex Double Field @@ -2045,8 +2068,8 @@ cdef class Parent(sage.structure.category_object.CategoryObject): cpdef bint has_coerce_map_from(self, S) except -2: """ - Return True if there is a natural map from S to self. - Otherwise, return False. + Return ``True`` if there is a natural map from ``S`` to ``self``. + Otherwise, return ``False``. EXAMPLES:: @@ -2098,19 +2121,20 @@ cdef class Parent(sage.structure.category_object.CategoryObject): sage: import gc sage: _ = gc.collect() - sage: K = GF(1<<55,'t') - sage: for i in range(50): + sage: K = GF(1<<55,'t') # needs sage.rings.finite_rings + sage: for i in range(50): # needs sage.rings.finite_rings sage.schemes ....: a = K.random_element() ....: E = EllipticCurve(j=a) ....: b = K.has_coerce_map_from(E) sage: _ = gc.collect() - sage: len([x for x in gc.get_objects() if isinstance(x,type(E))]) + sage: len([x for x in gc.get_objects() if isinstance(x, type(E))]) # needs sage.rings.finite_rings sage.schemes 1 TESTS: The following was fixed in :trac:`12969`:: + sage: # needs sage.combinat sage.modules sage: R = QQ['q,t'].fraction_field() sage: Sym = sage.combinat.sf.sf.SymmetricFunctions(R) sage: H = Sym.macdonald().H() @@ -2147,6 +2171,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): From: Integer Ring To: Rational Field + sage: # needs sage.combinat sage.modules sage: R = QQ['q,t'].fraction_field() sage: Sym = sage.combinat.sf.sf.SymmetricFunctions(R) sage: P = Sym.macdonald().P() @@ -2285,7 +2310,9 @@ cdef class Parent(sage.structure.category_object.CategoryObject): Another test:: - sage: K = NumberField([x^2-2, x^2-3], 'a,b') + sage: # needs sage.rings.number_field + sage: x = polygen(ZZ, 'x') + sage: K = NumberField([x^2 - 2, x^2 - 3], 'a,b') sage: M = K.absolute_field('c') sage: M_to_K, K_to_M = M.structure() sage: M.register_coercion(K_to_M) @@ -2318,16 +2345,19 @@ cdef class Parent(sage.structure.category_object.CategoryObject): Check that :trac:`14982` is fixed, and more generally that we discover sensible coercion paths in the presence of embeddings:: - sage: K.<a> = NumberField(x^2+1/2, embedding=CC(0,1)) - sage: L = NumberField(x^2+2, 'b', embedding=1/a) + sage: # needs sage.rings.number_field + sage: K.<a> = NumberField(x^2 + 1/2, embedding=CC(0, 1)) + sage: L = NumberField(x^2 + 2, 'b', embedding=1/a) sage: PolynomialRing(L, 'x').coerce_map_from(L) Polynomial base injection morphism: From: Number Field in b with defining polynomial x^2 + 2 with b = -2*a - To: Univariate Polynomial Ring in x over Number Field in b with defining polynomial x^2 + 2 with b = -2*a + To: Univariate Polynomial Ring in x over Number Field in b + with defining polynomial x^2 + 2 with b = -2*a sage: PolynomialRing(K, 'x').coerce_map_from(L) Composite map: From: Number Field in b with defining polynomial x^2 + 2 with b = -2*a - To: Univariate Polynomial Ring in x over Number Field in a with defining polynomial x^2 + 1/2 with a = 0.7071067811865475?*I + To: Univariate Polynomial Ring in x over Number Field in a + with defining polynomial x^2 + 1/2 with a = 0.7071067811865475?*I Defn: Generic morphism: From: Number Field in b with defining polynomial x^2 + 2 with b = -2*a To: Number Field in a with defining polynomial x^2 + 1/2 with a = 0.7071067811865475?*I @@ -2335,15 +2365,18 @@ cdef class Parent(sage.structure.category_object.CategoryObject): then Polynomial base injection morphism: From: Number Field in a with defining polynomial x^2 + 1/2 with a = 0.7071067811865475?*I - To: Univariate Polynomial Ring in x over Number Field in a with defining polynomial x^2 + 1/2 with a = 0.7071067811865475?*I + To: Univariate Polynomial Ring in x over Number Field in a + with defining polynomial x^2 + 1/2 with a = 0.7071067811865475?*I sage: MatrixSpace(L, 2, 2).coerce_map_from(L) Coercion map: From: Number Field in b with defining polynomial x^2 + 2 with b = -2*a - To: Full MatrixSpace of 2 by 2 dense matrices over Number Field in b with defining polynomial x^2 + 2 with b = -2*a + To: Full MatrixSpace of 2 by 2 dense matrices over Number Field in b + with defining polynomial x^2 + 2 with b = -2*a sage: PowerSeriesRing(L, 'x').coerce_map_from(L) Coercion map: From: Number Field in b with defining polynomial x^2 + 2 with b = -2*a - To: Power Series Ring in x over Number Field in b with defining polynomial x^2 + 2 with b = -2*a + To: Power Series Ring in x over Number Field in b + with defining polynomial x^2 + 2 with b = -2*a """ if isinstance(S, Parent) and (<Parent>S)._embedding is not None: if (<Parent>S)._embedding.codomain() is self: @@ -2539,10 +2572,14 @@ cdef class Parent(sage.structure.category_object.CategoryObject): TESTS:: - sage: M = QQ['y']^3 - sage: M.get_action(ZZ['x']['y']) - Right scalar multiplication by Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Integer Ring on Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field - sage: print(M.get_action(ZZ['x'])) + sage: M = QQ['y']^3 # needs sage.modules + sage: M.get_action(ZZ['x']['y']) # needs sage.modules + Right scalar multiplication + by Univariate Polynomial Ring in y + over Univariate Polynomial Ring in x over Integer Ring + on Ambient free module of rank 3 over the principal ideal domain + Univariate Polynomial Ring in y over Rational Field + sage: print(M.get_action(ZZ['x'])) # needs sage.modules None """ action = self._get_action_(S, op, self_on_left) @@ -2561,33 +2598,42 @@ cdef class Parent(sage.structure.category_object.CategoryObject): """ TESTS:: + sage: # needs sage.schemes sage: E = EllipticCurve([1,0]) sage: coercion_model.get_action(E, ZZ, operator.mul) - Right Integer Multiplication by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x over Rational Field + Right Integer Multiplication by Integer Ring + on Elliptic Curve defined by y^2 = x^3 + x over Rational Field sage: coercion_model.get_action(ZZ, E, operator.mul) - Left Integer Multiplication by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x over Rational Field + Left Integer Multiplication by Integer Ring + on Elliptic Curve defined by y^2 = x^3 + x over Rational Field sage: coercion_model.get_action(E, int, operator.mul) - Right Integer Multiplication by Set of Python objects of class 'int' on Elliptic Curve defined by y^2 = x^3 + x over Rational Field + Right Integer Multiplication by Set of Python objects of class 'int' + on Elliptic Curve defined by y^2 = x^3 + x over Rational Field sage: coercion_model.get_action(int, E, operator.mul) - Left Integer Multiplication by Set of Python objects of class 'int' on Elliptic Curve defined by y^2 = x^3 + x over Rational Field + Left Integer Multiplication by Set of Python objects of class 'int' + on Elliptic Curve defined by y^2 = x^3 + x over Rational Field :: + sage: # needs sage.rings.complex_double sage: R.<x> = CDF[] sage: coercion_model.get_action(R, ZZ, operator.pow) - Right Integer Powering by Integer Ring on Univariate Polynomial Ring in x over Complex Double Field + Right Integer Powering by Integer Ring + on Univariate Polynomial Ring in x over Complex Double Field sage: print(coercion_model.get_action(ZZ, R, operator.pow)) None sage: coercion_model.get_action(R, int, operator.pow) - Right Integer Powering by Set of Python objects of class 'int' on Univariate Polynomial Ring in x over Complex Double Field + Right Integer Powering by Set of Python objects of class 'int' + on Univariate Polynomial Ring in x over Complex Double Field sage: print(coercion_model.get_action(int, R, operator.pow)) None sage: coercion_model.get_action(R, IntegerModRing(7), operator.pow) - Right Integer Powering by Ring of integers modulo 7 on Univariate Polynomial Ring in x over Complex Double Field + Right Integer Powering by Ring of integers modulo 7 + on Univariate Polynomial Ring in x over Complex Double Field :: - sage: print(coercion_model.get_action(E, ZZ, operator.pow)) + sage: print(coercion_model.get_action(E, ZZ, operator.pow)) # needs sage.schemes None """ # G acts on S, G -> G', R -> S => G' acts on R (?) @@ -2597,7 +2643,6 @@ cdef class Parent(sage.structure.category_object.CategoryObject): # If needed, it will be passed to Left/RightModuleAction. from sage.categories.action import Action, PrecomposedAction from sage.categories.homset import Hom - from .coerce_actions import LeftModuleAction, RightModuleAction cdef Parent R for action in self._action_list: @@ -2684,7 +2729,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): EXAMPLES:: - sage: CDF.an_element() + sage: CDF.an_element() # needs sage.rings.complex_double 1.0*I sage: ZZ[['t']].an_element() t @@ -2791,9 +2836,9 @@ cdef class Parent(sage.structure.category_object.CategoryObject): True sage: ZZ.is_exact() True - sage: Qp(7).is_exact() + sage: Qp(7).is_exact() # needs sage.rings.padics False - sage: Zp(7, type='capped-abs').is_exact() + sage: Zp(7, type='capped-abs').is_exact() # needs sage.rings.padics False """ return True @@ -2806,12 +2851,20 @@ cdef class Parent(sage.structure.category_object.CategoryObject): EXAMPLES:: - sage: [R._is_numerical() for R in [RR, CC, QQ, QuadraticField(-1)]] - [True, True, True, True] - sage: [R._is_numerical() for R in [SR, QQ['x'], QQ[['x']]]] - [False, False, False] - sage: [R._is_numerical() for R in [RIF, RBF, CIF, CBF]] - [False, False, False, False] + sage: QuadraticField(-1)._is_numerical() # needs sage.rings.number_field + True + sage: QQ._is_numerical() + True + sage: [RR._is_numerical(), CC._is_numerical()] # needs sage.rings.real_mpfr + [True, True] + sage: SR._is_numerical() # needs sage.symbolic + False + sage: [R._is_numerical() for R in [QQ['x'], QQ[['x']]]] + [False, False] + sage: [R._is_numerical() for R in [RBF, CBF]] # needs sage.libs.flint + [False, False] + sage: [R._is_numerical() for R in [RIF, CIF]] # needs sage.rings.real_interval_field + [False, False] """ try: from sage.rings.complex_mpfr import ComplexField @@ -2821,8 +2874,15 @@ cdef class Parent(sage.structure.category_object.CategoryObject): else: return ComplexField(mpfr_prec_min()).has_coerce_map_from(self) - from sage.rings.real_double import CDF - return CDF.has_coerce_map_from(self) + try: + from sage.rings.complex_double import CDF + except ImportError: + pass + else: + return CDF.has_coerce_map_from(self) + + from sage.rings.real_double import RDF + return RDF.has_coerce_map_from(self) @cached_method def _is_real_numerical(self): @@ -2832,14 +2892,24 @@ cdef class Parent(sage.structure.category_object.CategoryObject): EXAMPLES:: - sage: [R._is_real_numerical() for R in [RR, QQ, ZZ, RLF, QuadraticField(2)]] - [True, True, True, True, True] - sage: [R._is_real_numerical() for R in [CC, QuadraticField(-1)]] + sage: QuadraticField(2)._is_real_numerical() # needs sage.rings.number_field + True + sage: [QQ._is_real_numerical(), ZZ._is_real_numerical()] + [True, True] + sage: [RR._is_real_numerical(), RLF._is_real_numerical()] # needs sage.rings.real_mpfr + [True, True] + sage: QuadraticField(-1)._is_real_numerical() # needs sage.rings.number_field + False + sage: CC._is_real_numerical() # needs sage.rings.real_mpfr + False + sage: SR._is_real_numerical() # needs sage.symbolic + False + sage: [R._is_real_numerical() for R in [QQ['x'], QQ[['x']]]] + [False, False] + sage: [R._is_real_numerical() for R in [RBF, CBF]] # needs sage.libs.flint + [False, False] + sage: [R._is_real_numerical() for R in [RIF, CIF]] # needs sage.libs.flint [False, False] - sage: [R._is_real_numerical() for R in [SR, QQ['x'], QQ[['x']]]] - [False, False, False] - sage: [R._is_real_numerical() for R in [RIF, RBF, CIF, CBF]] - [False, False, False, False] """ try: from sage.rings.real_mpfr import RealField, mpfr_prec_min @@ -2926,9 +2996,9 @@ cdef class EltPair: Verify that :trac:`16341` has been resolved:: - sage: K.<a> = Qq(9) # optional - sage.rings.padics - sage: E = EllipticCurve_from_j(0).base_extend(K) # optional - sage.rings.padics - sage: E.get_action(ZZ) # optional - sage.rings.padics + sage: K.<a> = Qq(9) # needs sage.rings.padics + sage: E = EllipticCurve_from_j(0).base_extend(K) # needs sage.rings.padics + sage: E.get_action(ZZ) # needs sage.rings.padics Right Integer Multiplication by Integer Ring on Elliptic Curve defined by y^2 + (1+O(3^20))*y = x^3 diff --git a/src/sage/structure/parent_gens.pyx b/src/sage/structure/parent_gens.pyx index c4155736e99..3f69b9daee4 100644 --- a/src/sage/structure/parent_gens.pyx +++ b/src/sage/structure/parent_gens.pyx @@ -47,6 +47,7 @@ This example illustrates generators for a free module over `\ZZ`. :: + sage: # needs sage.modules sage: M = FreeModule(ZZ, 4) sage: M Ambient free module of rank 4 over the principal ideal domain Integer Ring @@ -68,9 +69,7 @@ This example illustrates generators for a free module over `\ZZ`. # https://www.gnu.org/licenses/ # **************************************************************************** -from . import gens_py cimport sage.structure.parent as parent -from sage.structure.coerce_dict cimport MonoDict cimport sage.structure.category_object as category_object @@ -194,17 +193,17 @@ cdef class ParentWithGens(ParentWithBase): self._names = d['_names'] self._latex_names = d['_latex_names'] - - ################################################################################# + ###################################################################### # Morphisms of objects with generators - ################################################################################# + ###################################################################### def hom(self, im_gens, codomain=None, base_map=None, category=None, check=True): r""" - Return the unique homomorphism from self to codomain that + Return the unique homomorphism from ``self`` to codomain that sends ``self.gens()`` to the entries of ``im_gens`` and induces the map ``base_map`` on the base ring. - Raises a TypeError if there is no such homomorphism. + + This raises a :class:`TypeError` if there is no such homomorphism. INPUT: @@ -246,18 +245,20 @@ cdef class ParentWithGens(ParentWithBase): sage: f = R.hom([5], GF(7)) Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators + sage: # needs sage.rings.finite_rings sage: R.<x> = PolynomialRing(GF(7)) - sage: f = R.hom([3], GF(49,'a')) + sage: f = R.hom([3], GF(49, 'a')) sage: f Ring morphism: From: Univariate Polynomial Ring in x over Finite Field of size 7 To: Finite Field in a of size 7^2 Defn: x |--> 3 - sage: f(x+6) + sage: f(x + 6) 2 - sage: f(x^2+1) + sage: f(x^2 + 1) 3 EXAMPLES: Natural morphism @@ -272,7 +273,8 @@ cdef class ParentWithGens(ParentWithBase): From: Integer Ring To: Finite Field of size 5 - There might not be a natural morphism, in which case a TypeError exception is raised. + There might not be a natural morphism, in which case a + :class:`TypeError` exception is raised. :: @@ -283,6 +285,7 @@ cdef class ParentWithGens(ParentWithBase): You can specify a map on the base ring:: + sage: # needs sage.rings.finite_rings sage: k = GF(2) sage: R.<a> = k[] sage: l.<a> = k.extension(a^3 + a^2 + 1) @@ -291,7 +294,8 @@ cdef class ParentWithGens(ParentWithBase): sage: n.<z> = GF(2^6) sage: m.hom([z^4 + z^3 + 1], base_map=l.hom([z^5 + z^4 + z^2])) Ring morphism: - From: Univariate Quotient Polynomial Ring in b over Finite Field in a of size 2^3 with modulus b^2 + b + a + From: Univariate Quotient Polynomial Ring in b over + Finite Field in a of size 2^3 with modulus b^2 + b + a To: Finite Field in z of size 2^6 Defn: b |--> z^4 + z^3 + 1 with map of base ring @@ -338,7 +342,7 @@ cdef class localvars: EXAMPLES:: - sage: R.<x,y> = PolynomialRing(QQ,2) + sage: R.<x,y> = PolynomialRing(QQ, 2) sage: with localvars(R, 'z,w'): ....: print(x^3 + y^3 - x*y) z^3 + w^3 - z*w @@ -369,7 +373,7 @@ cdef class localvars: self._latex_names = latex_names def __enter__(self): - self._orig = self._obj.__temporarily_change_names(self._names, self._latex_names) + self._orig = self._obj._temporarily_change_names(self._names, self._latex_names) def __exit__(self, type, value, traceback): - self._obj.__temporarily_change_names(self._orig[0], self._orig[1]) + self._obj._temporarily_change_names(self._orig[0], self._orig[1]) diff --git a/src/sage/structure/parent_old.pyx b/src/sage/structure/parent_old.pyx index 630f0ca8613..77a7888d3b8 100644 --- a/src/sage/structure/parent_old.pyx +++ b/src/sage/structure/parent_old.pyx @@ -13,7 +13,7 @@ TESTS: This came up in some subtle bug once:: - sage: gp(2) + gap(3) + sage: gp(2) + gap(3) # needs sage.libs.gap sage.libs.pari 5 """ @@ -27,8 +27,6 @@ This came up in some subtle bug once:: # https://www.gnu.org/licenses/ # **************************************************************************** from sage.misc.superseded import deprecation -cimport sage.structure.sage_object as sage_object -import operator from .coerce cimport py_scalar_parent from sage.ext.stdsage cimport HAS_DICTIONARY from sage.sets.pythonclass cimport Set_PythonType, Set_PythonType_class @@ -48,16 +46,19 @@ cdef class Parent(parent.Parent): TESTS:: - sage: V = VectorSpace(GF(2,'a'),2) + sage: # needs sage.modules + sage: V = VectorSpace(GF(2,'a'), 2) sage: V.list() [(0, 0), (1, 0), (0, 1), (1, 1)] sage: MatrixSpace(GF(3), 1, 1).list() [[0], [1], [2]] - sage: DirichletGroup(3).list() + sage: DirichletGroup(3).list() # needs sage.modular [Dirichlet character modulo 3 of conductor 1 mapping 2 |--> 1, - Dirichlet character modulo 3 of conductor 3 mapping 2 |--> -1] + Dirichlet character modulo 3 of conductor 3 mapping 2 |--> -1] + + sage: # needs sage.rings.finite_rings sage: K = GF(7^6,'a') - sage: K.list()[:10] # long time + sage: K.list()[:10] # long time [0, 1, 2, 3, 4, 5, 6, a, a + 1, a + 2] sage: K.<a> = GF(4) sage: K.list() @@ -220,11 +221,12 @@ cdef class Parent(parent.Parent): Given a list v of rings, try to coerce x canonically into each one in turn. Return the __call__ coercion of the result into self of the first canonical coercion that succeeds. Raise a - TypeError if none of them succeed. + :class:`TypeError` if none of them succeed. INPUT: - x -- Python object - v -- parent object or list (iterator) of parent objects + + - x -- Python object + - v -- parent object or list (iterator) of parent objects """ deprecation(33464, "usage of _coerce_try is deprecated") check_old_coerce(self) diff --git a/src/sage/structure/proof/proof.py b/src/sage/structure/proof/proof.py index 24532380e8a..49d4ecebe5a 100644 --- a/src/sage/structure/proof/proof.py +++ b/src/sage/structure/proof/proof.py @@ -8,7 +8,7 @@ class _ProofPref(SageObject): A True flag means that the subsystem (such as linear algebra or number fields) should return results that are true unconditionally: the correctness should not depend on an algorithm with a nonzero probability of returning an incorrect answer or on the truth of any unproven conjectures. A False flag means that the subsystem can use faster methods to return answers that have a very small probability of being wrong. """ - def __init__(self, proof = True): + def __init__(self, proof=True): self._require_proof = {} self._require_proof["arithmetic"] = proof self._require_proof["elliptic_curve"] = proof @@ -17,7 +17,7 @@ def __init__(self, proof = True): self._require_proof["polynomial"] = proof self._require_proof["other"] = proof - def arithmetic(self, t = None): + def arithmetic(self, t=None): """ Controls the default proof strategy for integer arithmetic algorithms (such as primality testing). @@ -46,7 +46,7 @@ def arithmetic(self, t = None): return self._require_proof["arithmetic"] self._require_proof["arithmetic"] = bool(t) - def elliptic_curve(self, t = None): + def elliptic_curve(self, t=None): """ Controls the default proof strategy for elliptic curve algorithms. @@ -75,7 +75,7 @@ def elliptic_curve(self, t = None): return self._require_proof["elliptic_curve"] self._require_proof["elliptic_curve"] = bool(t) - def linear_algebra(self, t = None): + def linear_algebra(self, t=None): """ Controls the default proof strategy for linear algebra algorithms. @@ -104,7 +104,7 @@ def linear_algebra(self, t = None): return self._require_proof["linear_algebra"] self._require_proof["linear_algebra"] = bool(t) - def number_field(self, t = None): + def number_field(self, t=None): """ Controls the default proof strategy for number field algorithms. @@ -133,7 +133,7 @@ def number_field(self, t = None): return self._require_proof["number_field"] self._require_proof["number_field"] = bool(t) - def polynomial(self, t = None): + def polynomial(self, t=None): """ Controls the default proof strategy for polynomial algorithms. @@ -165,7 +165,7 @@ def polynomial(self, t = None): _proof_prefs = _ProofPref(True) #Creates the global object that stores proof preferences. -def get_flag(t = None, subsystem = None): +def get_flag(t=None, subsystem=None): """ Used for easily determining the correct proof flag to use. @@ -196,10 +196,12 @@ class WithProof(): systems for a block of code, with a guarantee that it will be set back to how it was before after the block is done, even if there is an error. - EXAMPLES:: + EXAMPLES: + + This would hang "forever" if attempted with ``proof=True``:: sage: proof.arithmetic(True) - sage: with proof.WithProof('arithmetic',False): # this would hang "forever" if attempted with proof=True + sage: with proof.WithProof('arithmetic', False): # needs sage.libs.pari ....: print((10^1000 + 453).is_prime()) ....: print(1/0) Traceback (most recent call last): diff --git a/src/sage/structure/richcmp.pxd b/src/sage/structure/richcmp.pxd index 61c0a3c4321..493af157a79 100644 --- a/src/sage/structure/richcmp.pxd +++ b/src/sage/structure/richcmp.pxd @@ -20,7 +20,7 @@ cpdef inline richcmp(x, y, int op): sage: from sage.structure.richcmp import * sage: richcmp(3, 4, op_LT) True - sage: richcmp(x, x^2, op_EQ) # optional - sage.symbolic + sage: richcmp(x, x^2, op_EQ) # needs sage.symbolic x == x^2 The two examples above are completely equivalent to ``3 < 4`` diff --git a/src/sage/structure/richcmp.pyx b/src/sage/structure/richcmp.pyx index af0c8d09e3a..465f16e8274 100644 --- a/src/sage/structure/richcmp.pyx +++ b/src/sage/structure/richcmp.pyx @@ -32,17 +32,17 @@ AUTHORS: - Jeroen Demeyer """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017-2018 Jeroen Demeyer <J.Demeyer@UGent.be> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -from cpython.object cimport Py_TYPE, PyTypeObject +from cpython.object cimport PyTypeObject from sage.cpython.wrapperdescr cimport get_slotdef, wrapperbase, PyDescr_NewWrapper cdef extern from *: diff --git a/src/sage/structure/sage_object.pyx b/src/sage/structure/sage_object.pyx index eff79810b56..10000aef394 100644 --- a/src/sage/structure/sage_object.pyx +++ b/src/sage/structure/sage_object.pyx @@ -69,6 +69,8 @@ cdef class SageObject: r""" Change self so it prints as x, where x is a string. + If x is ``None``, the existing custom name is removed. + .. NOTE:: This is *only* supported for Python classes that derive @@ -91,13 +93,16 @@ cdef class SageObject: sage: h.rename('x^300 + ...') sage: h x^300 + ... + sage: g.rename(None) + sage: g + x^3 + x - 5 Real numbers are not Python classes, so rename is not supported:: sage: a = 3.14 - sage: type(a) + sage: type(a) # needs sage.rings.real_mpfr <... 'sage.rings.real_mpfr.RealLiteral'> - sage: a.rename('pi') + sage: a.rename('pi') # needs sage.rings.real_mpfr Traceback (most recent call last): ... NotImplementedError: object does not support renaming: 3.14000000000000 @@ -110,15 +115,16 @@ cdef class SageObject: a lot of memory. To support them for a specific class, add a - ``cdef public __custom_name`` attribute. + ``cdef public _SageObject__custom_name`` attribute. """ if x is None: - #if hasattr(self, '__custom_name'): - # that's tested in reset_name anyway... self.reset_name() else: try: - self.__custom_name = str(x) + # TODO: after dropping support for Cython < 3.0.0, all + # the self._SageObject__custom_name in this class can be + # changed to self.__custom_name + self._SageObject__custom_name = str(x) except AttributeError: raise NotImplementedError("object does not support renaming: %s" % self) @@ -138,9 +144,30 @@ cdef class SageObject: sage: P Univariate Polynomial Ring in x over Rational Field """ - if hasattr(self, '__custom_name'): - del self.__custom_name + if hasattr(self, '_SageObject__custom_name'): + del self._SageObject__custom_name + def get_custom_name(self): + """ + Return the custom name of this object, or ``None`` if it is not + renamed. + + EXAMPLES:: + + sage: P.<x> = QQ[] + sage: P.get_custom_name() is None + True + sage: P.rename('A polynomial ring') + sage: P.get_custom_name() + 'A polynomial ring' + sage: P.reset_name() + sage: P.get_custom_name() is None + True + """ + try: + return self._SageObject__custom_name + except AttributeError: + return None def __repr__(self): """ @@ -182,7 +209,7 @@ cdef class SageObject: <sage.structure.sage_object.SageObject object at ...> """ try: - name = self.__custom_name + name = self._SageObject__custom_name if name is not None: return name except AttributeError: @@ -191,11 +218,7 @@ cdef class SageObject: reprfunc = self._repr_ except AttributeError: return super().__repr__() - result = reprfunc() - if isinstance(result, str): - return result - # Allow _repr_ to return unicode on Python 2 - return result.encode('utf-8') + return reprfunc() def _ascii_art_(self): r""" @@ -217,9 +240,9 @@ cdef class SageObject: You can use the :func:`~sage.typeset.ascii_art.ascii_art` function to get the ASCII art representation of any object in Sage:: - sage: result = ascii_art(integral(exp(x+x^2)/(x+1), x)) + sage: result = ascii_art(integral(exp(x+x^2)/(x+1), x)) # needs sage.symbolic ... - sage: result + sage: result # needs sage.symbolic / | | 2 @@ -233,6 +256,7 @@ cdef class SageObject: Alternatively, you can use the ``%display ascii_art/simple`` magic to switch all output to ASCII art and back:: + sage: # needs sage.combinat sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() sage: shell.run_cell('tab = StandardTableaux(3)[2]; tab') @@ -282,7 +306,7 @@ cdef class SageObject: You can use the :func:`~sage.typeset.unicode_art.unicode_art` function to get the ASCII art representation of any object in Sage:: - sage: unicode_art(integral(exp(x+x^2)/(x+1), x)) + sage: unicode_art(integral(exp(x+x^2)/(x+1), x)) # needs sage.symbolic โŒ  โŽฎ 2 โŽฎ x + x @@ -295,6 +319,7 @@ cdef class SageObject: Alternatively, you can use the ``%display ascii_art/simple`` magic to switch all output to ASCII art and back:: + sage: # needs sage.combinat sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() sage: shell.run_cell('tab = StandardTableaux(3)[2]; tab') @@ -323,6 +348,7 @@ cdef class SageObject: Check that breakpoints and baseline are preserved (:trac:`29202`):: + sage: # needs sage.groups sage: F = FreeAbelianMonoid(index_set=ZZ) sage: f = prod(F.gen(i) for i in range(5)) sage: s, t = ascii_art(f), unicode_art(f) @@ -360,18 +386,19 @@ cdef class SageObject: modified to return ``True`` for objects which might behave differently in some computations:: - sage: K.<a> = Qq(9) # optional - sage.rings.padics - sage: b = a + O(3) # optional - sage.rings.padics - sage: c = a + 3 # optional - sage.rings.padics - sage: b # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: K.<a> = Qq(9) + sage: b = a + O(3) + sage: c = a + 3 + sage: b a + O(3) - sage: c # optional - sage.rings.padics + sage: c a + 3 + O(3^20) - sage: b == c # optional - sage.rings.padics + sage: b == c True - sage: b == a # optional - sage.rings.padics + sage: b == a True - sage: c == a # optional - sage.rings.padics + sage: c == a False If such objects defined a non-trivial hash function, this would break @@ -379,20 +406,20 @@ cdef class SageObject: caches. This can be achieved by defining an appropriate ``_cache_key``:: - sage: hash(b) # optional - sage.rings.padics + sage: # needs sage.rings.padics + sage: hash(b) Traceback (most recent call last): ... TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement' sage: @cached_method ....: def f(x): return x==a - sage: f(b) # optional - sage.rings.padics + sage: f(b) True - sage: f(c) # if b and c were hashable, this would return True # optional - sage.rings.padics + sage: f(c) # if b and c were hashable, this would return True False - - sage: b._cache_key() # optional - sage.rings.padics + sage: b._cache_key() (..., ((0, 1),), 0, 1) - sage: c._cache_key() # optional - sage.rings.padics + sage: c._cache_key() (..., ((0, 1), (1,)), 0, 20) An implementation must make sure that for elements ``a`` and ``b``, @@ -400,9 +427,9 @@ cdef class SageObject: In practice this means that the ``_cache_key`` should always include the parent as its first argument:: - sage: S.<a> = Qq(4) # optional - sage.rings.padics - sage: d = a + O(2) # optional - sage.rings.padics - sage: b._cache_key() == d._cache_key() # this would be True if the parents were not included # optional - sage.rings.padics + sage: S.<a> = Qq(4) # needs sage.rings.padics + sage: d = a + O(2) # needs sage.rings.padics + sage: b._cache_key() == d._cache_key() # this would be True if the parents were not included # needs sage.rings.padics False """ @@ -423,10 +450,11 @@ cdef class SageObject: EXAMPLES:: - sage: x = SR.var("x") # optional - sage.symbolic - sage: f = x^3 + 5 # optional - sage.symbolic - sage: from tempfile import NamedTemporaryFile # optional - sage.symbolic - sage: with NamedTemporaryFile(suffix=".sobj") as t: # optional - sage.symbolic + sage: # needs sage.symbolic + sage: x = SR.var("x") + sage: f = x^3 + 5 + sage: from tempfile import NamedTemporaryFile + sage: with NamedTemporaryFile(suffix=".sobj") as t: ....: f.save(t.name) ....: load(t.name) x^3 + 5 @@ -525,22 +553,21 @@ cdef class SageObject: EXAMPLES:: - sage: t = log(sqrt(2) - 1) + log(sqrt(2) + 1); t # optional - sage.symbolic + sage: t = log(sqrt(2) - 1) + log(sqrt(2) + 1); t # needs sage.symbolic log(sqrt(2) + 1) + log(sqrt(2) - 1) - sage: u = t.maxima_methods() # optional - sage.symbolic - sage: u.parent() # optional - sage.symbolic + sage: u = t.maxima_methods() # needs sage.symbolic + sage: u.parent() # needs sage.symbolic <class 'sage.symbolic.maxima_wrapper.MaximaWrapper'> """ return type(self) - - ############################################################################# + ########################################################################## # Test framework - ############################################################################# + ########################################################################## def _tester(self, **options): """ - Returns a gadget attached to ``self`` providing testing utilities. + Return a gadget attached to ``self`` providing testing utilities. This is used by :class:`sage.misc.sage_unittest.TestSuite` and the ``_test_*`` methods. @@ -831,25 +858,28 @@ cdef class SageObject: Some other examples that illustrate conversion to Magma. :: + sage: # optional - magma, needs sage.symbolic sage: n = -3/7 sage: m2 = Magma() - sage: magma(n) # optional - magma + sage: magma(n) -3/7 - sage: magma(n).parent() # optional - magma + sage: magma(n).parent() Magma - sage: magma(n).parent() is m2 # optional - magma + sage: magma(n).parent() is m2 False - sage: magma(n).parent() is magma # optional - magma + sage: magma(n).parent() is magma True This example illustrates caching, which happens automatically since K is a Python object:: - sage: K.<a> = NumberField(x^3 + 2) - sage: magma(K) is magma(K) # optional - magma + sage: # optional - magma, needs sage.symbolic + sage: x = polygen(ZZ, 'x') + sage: K.<a> = NumberField(x^3 + 2) # needs sage.rings.number_field + sage: magma(K) is magma(K) True sage: magma2 = Magma() - sage: magma(K) is magma2(K) # optional - magma + sage: magma(K) is magma2(K) False """ return repr(self) # default @@ -929,7 +959,7 @@ cdef class SageObject: EXAMPLES:: - sage: a = 2/3 # optional - rpy2 + sage: a = 2/3 sage: a._r_init_() # optional - rpy2 '2/3' """ diff --git a/src/sage/structure/sequence.py b/src/sage/structure/sequence.py index 6cdaa84e4ef..0c700c1fb81 100644 --- a/src/sage/structure/sequence.py +++ b/src/sage/structure/sequence.py @@ -201,7 +201,7 @@ def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=Non This example illustrates how every element of a list is taken into account when constructing a sequence.:: - sage: v = Sequence([1,7,6,GF(5)(3)]); v + sage: v = Sequence([1, 7, 6, GF(5)(3)]); v [1, 2, 1, 3] sage: v.universe() Finite Field of size 5 @@ -397,7 +397,7 @@ class Sequence_generic(sage.structure.sage_object.SageObject, list): :: - sage: v = Sequence([1,7,6,GF(5)(3)]); v + sage: v = Sequence([1, 7, 6, GF(5)(3)]); v [1, 2, 1, 3] sage: v.universe() Finite Field of size 5 @@ -500,7 +500,7 @@ def __setitem__(self, n, value): else: y = self.__universe(value) list.__setitem__(self, n, y) - self.__hash=None + self.__hash = None def __getitem__(self, n): """ @@ -519,10 +519,10 @@ def __getitem__(self, n): """ if isinstance(n, slice): return Sequence(list.__getitem__(self, n), - universe = self.__universe, - check = False, - immutable = False, - cr = self.__cr) + universe=self.__universe, + check=False, + immutable=False, + cr=self.__cr) else: return list.__getitem__(self,n) @@ -674,11 +674,11 @@ def _latex_(self): r""" TESTS:: - sage: t= Sequence([sqrt(x), exp(x), x^(x-1)], universe=SR); t + sage: t= Sequence([sqrt(x), exp(x), x^(x-1)], universe=SR); t # needs sage.symbolic [sqrt(x), e^x, x^(x - 1)] - sage: t._latex_() + sage: t._latex_() # needs sage.symbolic '\\left[\\sqrt{x}, e^{x}, x^{x - 1}\\right]' - sage: latex(t) + sage: latex(t) # needs sage.symbolic \left[\sqrt{x}, e^{x}, x^{x - 1}\right] """ from sage.misc.latex import list_function as list_latex_function @@ -710,9 +710,9 @@ def universe(self): EXAMPLES:: - sage: Sequence([1,2/3,-2/5]).universe() + sage: Sequence([1, 2/3, -2/5]).universe() Rational Field - sage: Sequence([1,2/3,'-2/5']).universe() + sage: Sequence([1, 2/3, '-2/5']).universe() Category of objects """ return self.__universe @@ -738,7 +738,7 @@ def set_immutable(self): EXAMPLES:: - sage: v = Sequence([1,2,3,4/5]) + sage: v = Sequence([1, 2, 3, 4/5]) sage: v[0] = 5 sage: v [5, 2, 3, 4/5] @@ -759,7 +759,7 @@ def is_immutable(self): EXAMPLES:: - sage: v = Sequence([1,2,3,4/5]) + sage: v = Sequence([1, 2, 3, 4/5]) sage: v[0] = 5 sage: v [5, 2, 3, 4/5] @@ -778,7 +778,7 @@ def is_mutable(self): """ EXAMPLES:: - sage: a = Sequence([1,2/3,-2/5]) + sage: a = Sequence([1, 2/3, -2/5]) sage: a.is_mutable() True sage: a[0] = 100 @@ -888,7 +888,9 @@ def __getattr__(self, name): self.__hash = self._Sequence__hash return self.__hash else: - raise AttributeError("'Sequence_generic' object has no attribute '%s'"%name) + raise AttributeError("'Sequence_generic' object has no attribute '%s'" % name) + + seq = Sequence from sage.misc.persist import register_unpickle_override diff --git a/src/sage/structure/set_factories.py b/src/sage/structure/set_factories.py index badcbdc3897..f8b8e3643c9 100644 --- a/src/sage/structure/set_factories.py +++ b/src/sage/structure/set_factories.py @@ -792,8 +792,6 @@ def _repr_(self): self._parent_for) - - class BareFunctionPolicy(SetFactoryPolicy): r""" Policy where element are constructed using a bare function. diff --git a/src/sage/structure/set_factories_example.py b/src/sage/structure/set_factories_example.py index 44763fda11b..df1d7d7f49c 100644 --- a/src/sage/structure/set_factories_example.py +++ b/src/sage/structure/set_factories_example.py @@ -37,7 +37,7 @@ from sage.structure.element_wrapper import ElementWrapper from sage.structure.set_factories import ( SetFactory, ParentWithSetFactory, TopMostParentPolicy) -from sage.sets.all import DisjointUnionEnumeratedSets +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import LazyFamily from sage.categories.enumerated_sets import EnumeratedSets from sage.rings.integer import Integer @@ -169,6 +169,7 @@ def _repr_(self): """ return "Factory for XY pairs" + XYPairs = XYPairsFactory() XYPairs.__doc__ = XYPairsFactory.__call__.__doc__ diff --git a/src/sage/structure/test_factory.py b/src/sage/structure/test_factory.py index b45996c5a80..145311b9dd3 100644 --- a/src/sage/structure/test_factory.py +++ b/src/sage/structure/test_factory.py @@ -50,4 +50,5 @@ def create_object(self, version, key, **extra_args): print("Making object", key) return A() + test_factory = UniqueFactoryTester('sage.structure.test_factory.test_factory') diff --git a/src/sage/structure/unique_representation.py b/src/sage/structure/unique_representation.py index 7d30c39d66c..3bbea183fc6 100644 --- a/src/sage/structure/unique_representation.py +++ b/src/sage/structure/unique_representation.py @@ -21,13 +21,13 @@ instances constructed with the same arguments share the same memory representation. For example, calling twice:: - sage: G = SymmetricGroup(6) - sage: H = SymmetricGroup(6) + sage: G = SymmetricGroup(6) # needs sage.groups + sage: H = SymmetricGroup(6) # needs sage.groups to create the symmetric group on six elements gives back the same object:: - sage: G is H + sage: G is H # needs sage.groups True This is a standard design pattern. Besides saving memory, it allows for @@ -424,10 +424,10 @@ class is directly created, then the cache is not used:: Using :class:`CachedRepresentation` has the advantage that one has a class and creates cached instances of this class by the usual Python syntax:: - sage: G = SymmetricGroup(6) - sage: issubclass(SymmetricGroup, sage.structure.unique_representation.CachedRepresentation) + sage: G = SymmetricGroup(6) # needs sage.groups + sage: issubclass(SymmetricGroup, sage.structure.unique_representation.CachedRepresentation) # needs sage.groups True - sage: isinstance(G, SymmetricGroup) + sage: isinstance(G, SymmetricGroup) # needs sage.groups True In contrast, a factory is just a callable object that returns something that @@ -439,8 +439,10 @@ class is directly created, then the cache is not used:: sage: K5 = GF(5) sage: type(K5) <class 'sage.rings.finite_rings.finite_field_prime_modn.FiniteField_prime_modn_with_category'> + + sage: # needs sage.rings.finite_rings sage: K25 = GF(25, 'x') - sage: type(K25) + sage: type(K25) # needs sage.libs.linbox <class 'sage.rings.finite_rings.finite_field_givaro.FiniteField_givaro_with_category'> sage: Kp = GF(next_prime_power(1000000)^2, 'x') sage: type(Kp) @@ -498,8 +500,9 @@ class :class:`~sage.misc.fast_methods.WithEqualityById`, which provides since they are equal to groups created in a totally different way, namely to subgroups:: + sage: # needs sage.groups sage: G = SymmetricGroup(6) - sage: G3 = G.subgroup([G((1,2,3,4,5,6)),G((1,2))]) + sage: G3 = G.subgroup([G((1,2,3,4,5,6)), G((1,2))]) sage: G is G3 False sage: type(G) == type(G3) @@ -517,9 +520,9 @@ class that inherits from :class:`UniqueRepresentation`: By adding ring. Thus, it is reasonable to use :class:`UniqueRepresentation` in this case:: - sage: isinstance(SymmetricFunctions(CC), SymmetricFunctions) + sage: isinstance(SymmetricFunctions(CC), SymmetricFunctions) # needs sage.combinat True - sage: issubclass(SymmetricFunctions, UniqueRepresentation) + sage: issubclass(SymmetricFunctions, UniqueRepresentation) # needs sage.combinat True :class:`UniqueRepresentation` differs from :class:`CachedRepresentation` only @@ -1188,15 +1191,15 @@ class UniqueRepresentation(CachedRepresentation, WithEqualityById): the same memory representation), if and only if they were created using equal arguments. For example, calling twice:: - sage: f = SymmetricFunctions(QQ) - sage: g = SymmetricFunctions(QQ) + sage: f = SymmetricFunctions(QQ) # needs sage.combinat sage.modules + sage: g = SymmetricFunctions(QQ) # needs sage.combinat sage.modules to create the symmetric function algebra over `\QQ` actually gives back the same object:: - sage: f == g + sage: f == g # needs sage.combinat sage.modules True - sage: f is g + sage: f is g # needs sage.combinat sage.modules True This is a standard design pattern. It allows for sharing cached data (say @@ -1211,9 +1214,9 @@ class UniqueRepresentation(CachedRepresentation, WithEqualityById): derive from it, or make sure some of its super classes does. Also, it groups together the class and the factory in a single gadget:: - sage: isinstance(SymmetricFunctions(CC), SymmetricFunctions) + sage: isinstance(SymmetricFunctions(CC), SymmetricFunctions) # needs sage.combinat sage.modules True - sage: issubclass(SymmetricFunctions, UniqueRepresentation) + sage: issubclass(SymmetricFunctions, UniqueRepresentation) # needs sage.combinat sage.modules True This nice behaviour is not available when one just uses a factory:: diff --git a/src/sage/symbolic/__init__.py b/src/sage/symbolic/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/symbolic/all.py b/src/sage/symbolic/all.py index bad67459513..399ab56e78c 100644 --- a/src/sage/symbolic/all.py +++ b/src/sage/symbolic/all.py @@ -1,11 +1,10 @@ from sage.misc.lazy_import import lazy_import -lazy_import("sage.symbolic.expression", "I", deprecation=(18036, +lazy_import("sage.symbolic.constants", "I", deprecation=(18036, "import I from sage.symbolic.constants for the imaginary unit viewed as an element of SR, or from sage.rings.imaginary_unit for the element of ZZ[i]")) -lazy_import("sage.symbolic.expression", "I", as_="i", deprecation=(18036, +lazy_import("sage.symbolic.constants", "I", as_="i", deprecation=(18036, "import I from sage.symbolic.constants for the imaginary unit viewed as an element of SR, or from sage.rings.imaginary_unit for the element of ZZ[i]")) -import sage.symbolic.expression # initialize pynac before .ring from .ring import SR from .constants import (pi, e, NaN, golden_ratio, log2, euler_gamma, catalan, khinchin, twinprime, mertens, glaisher) @@ -18,3 +17,5 @@ from .units import units ฯ€ = pi + +from .operators import D diff --git a/src/sage/symbolic/assumptions.py b/src/sage/symbolic/assumptions.py index 4616fd2880b..7dcb15f0d85 100644 --- a/src/sage/symbolic/assumptions.py +++ b/src/sage/symbolic/assumptions.py @@ -75,7 +75,7 @@ from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RR from sage.rings.cc import CC -from sage.symbolic.ring import is_SymbolicVariable +from sage.structure.element import Expression from sage.structure.unique_representation import UniqueRepresentation # #30074: We use the keys of a dict to store the assumptions. @@ -261,7 +261,7 @@ def assume(self): cur = maxima.get("context") # Redeclaring on the existing context does not seem to trigger # inconsistency checking. - ## maxima.set("context", self._context._maxima_init_()) + # maxima.set("context", self._context._maxima_init_()) # Instead, use a temporary context for this purpose context = maxima.newcontext('context' + maxima._next_var_name()) must_declare = True @@ -272,7 +272,7 @@ def assume(self): try: maxima.eval("declare(%s, %s)" % (self._var._maxima_init_(), self._assumption)) except RuntimeError as mess: - if 'inconsistent' in str(mess): # note Maxima doesn't tell you if declarations are redundant + if 'inconsistent' in str(mess): # note Maxima doesn't tell you if declarations are redundant # Inconsistency with one of the active contexts. raise ValueError("Assumption is inconsistent") else: @@ -316,9 +316,9 @@ def forget(self): except KeyError: return maxima.deactivate(self._context) - else: # trying to forget a declaration explicitly rather than implicitly + else: # trying to forget a declaration explicitly rather than implicitly for x in _assumptions: - if repr(self) == repr(x): # so by implication x is also a GenericDeclaration + if repr(self) == repr(x): # so by implication x is also a GenericDeclaration x.forget() break return @@ -427,7 +427,8 @@ def preprocess_assumptions(args): if isinstance(x, str): del args[i] last = x - elif ((not hasattr(x, 'assume') or is_SymbolicVariable(x)) + elif ((not hasattr(x, 'assume') + or (isinstance(x, Expression) and x.is_symbol())) and last is not None): args[i] = GenericDeclaration(x, last) else: @@ -725,7 +726,7 @@ def forget(*args): try: x.forget() except KeyError: - raise TypeError("forget not defined for objects of type '%s'"%type(x)) + raise TypeError("forget not defined for objects of type '%s'" % type(x)) def assumptions(*args): @@ -782,11 +783,11 @@ def assumptions(*args): result = [] if len(args) == 1: result.extend([statement for statement in _assumptions - if statement.has(args[0])]) + if statement.has(args[0])]) else: for v in args: - result += [ statement for statement in list(_assumptions) \ - if str(v) in str(statement) ] + result += [statement for statement in list(_assumptions) + if str(v) in str(statement)] return result @@ -944,8 +945,8 @@ def __init__(self, *args, **kwds): sage: bool(x>-1) False """ - self.replace=kwds.pop("replace",False) - self.Ass=args + self.replace = kwds.pop("replace", False) + self.Ass = args def __enter__(self): r""" @@ -963,7 +964,7 @@ def __enter__(self): False """ if self.replace: - self.OldAss=assumptions() + self.OldAss = assumptions() forget(assumptions()) assume(self.Ass) diff --git a/src/sage/symbolic/callable.py b/src/sage/symbolic/callable.py index 062a96cb766..dc093716a34 100644 --- a/src/sage/symbolic/callable.py +++ b/src/sage/symbolic/callable.py @@ -60,14 +60,15 @@ ... SyntaxError: can...t assign to function call... """ - import sage.rings.abc from sage.symbolic.ring import SymbolicRing, SR from sage.categories.pushout import ConstructionFunctor +from sage.structure.factory import UniqueFactory -######################################################################################### + +###################################################################### # Callable functions -######################################################################################### +###################################################################### def is_CallableSymbolicExpressionRing(x): """ Return ``True`` if ``x`` is a callable symbolic expression ring. @@ -96,10 +97,10 @@ def is_CallableSymbolicExpressionRing(x): deprecation(32665, 'is_CallableSymbolicExpressionRing is deprecated; use isinstance(..., sage.rings.abc.CallableSymbolicExpressionRing instead') return isinstance(x, CallableSymbolicExpressionRing_class) + def is_CallableSymbolicExpression(x): r""" - Returns ``True`` if ``x`` is a callable symbolic - expression. + Return ``True`` if ``x`` is a callable symbolic expression. EXAMPLES:: @@ -125,6 +126,7 @@ def is_CallableSymbolicExpression(x): from sage.structure.element import Expression return isinstance(x, Expression) and isinstance(x.parent(), CallableSymbolicExpressionRing_class) + class CallableSymbolicExpressionFunctor(ConstructionFunctor): def __init__(self, arguments): """ @@ -157,7 +159,7 @@ def __repr__(self): sage: CallableSymbolicExpressionFunctor((x,y)) CallableSymbolicExpressionFunctor(x, y) """ - return "CallableSymbolicExpressionFunctor%s"%repr(self.arguments()) + return "CallableSymbolicExpressionFunctor%s" % repr(self.arguments()) def merge(self, other): """ @@ -373,9 +375,10 @@ def _repr_(self): def arguments(self): """ - Returns the arguments of ``self``. The order that the - variables appear in ``self.arguments()`` is the order that - is used in evaluating the elements of ``self``. + Return the arguments of ``self``. + + The order that the variables appear in ``self.arguments()`` is + the order that is used in evaluating the elements of ``self``. EXAMPLES:: @@ -393,7 +396,7 @@ def arguments(self): def _repr_element_(self, x): """ - Returns the string representation of the Expression ``x``. + Return the string representation of the Expression ``x``. EXAMPLES:: @@ -429,7 +432,7 @@ def _latex_element_(self, x): from sage.misc.latex import latex args = self.args() args = [latex(arg) for arg in args] - latex_x = SymbolicRing._latex_element_(self, x) + latex_x = SymbolicRing._latex_element_(self, x) if len(args) == 1: return r"%s \ {\mapsto}\ %s" % (args[0], latex_x) else: @@ -468,7 +471,7 @@ def _call_element_(self, _the_element, *args, **kwds): sage: f(z=100) a + 2*x + 3*y + 100 """ - if any(type(arg).__module__ == 'numpy' and type(arg).__name__ == "ndarray" for arg in args): # avoid importing + if any(type(arg).__module__ == 'numpy' and type(arg).__name__ == "ndarray" for arg in args): # avoid importing raise NotImplementedError("Numpy arrays are not supported as arguments for symbolic expressions") d = dict(zip([repr(_) for _ in self.arguments()], args)) @@ -479,7 +482,6 @@ def _call_element_(self, _the_element, *args, **kwds): __reduce__ = object.__reduce__ -from sage.structure.factory import UniqueFactory class CallableSymbolicExpressionRingFactory(UniqueFactory): def create_key(self, args, check=True): """ @@ -490,19 +492,18 @@ def create_key(self, args, check=True): (x, y) """ if check: - from sage.symbolic.ring import is_SymbolicVariable + from sage.structure.element import Expression if len(args) == 1 and isinstance(args[0], (list, tuple)): args, = args for arg in args: - if not is_SymbolicVariable(arg): + if not (isinstance(arg, Expression) and arg.is_symbol()): raise TypeError("must construct a function with a tuple (or list) of variables") args = tuple(args) return args def create_object(self, version, key, **extra_args): """ - Returns a CallableSymbolicExpressionRing given a version and a - key. + Return a CallableSymbolicExpressionRing given a version and a key. EXAMPLES:: @@ -512,4 +513,5 @@ def create_object(self, version, key, **extra_args): """ return CallableSymbolicExpressionRing_class(key) + CallableSymbolicExpressionRing = CallableSymbolicExpressionRingFactory('sage.symbolic.callable.CallableSymbolicExpressionRing') diff --git a/src/sage/symbolic/comparison_impl.pxi b/src/sage/symbolic/comparison_impl.pxi index 90a921112ac..c07ed620de1 100644 --- a/src/sage/symbolic/comparison_impl.pxi +++ b/src/sage/symbolic/comparison_impl.pxi @@ -35,8 +35,6 @@ There is also a mixed version: from cpython cimport * -from sage.symbolic.ring import SR - cdef int print_order_c(Expression lhs, Expression rhs): """ @@ -80,8 +78,10 @@ cpdef int print_order(lhs, rhs) except -2: 1 """ if not isinstance(lhs, Expression): + from sage.symbolic.ring import SR lhs = SR(lhs) if not isinstance(rhs, Expression): + from sage.symbolic.ring import SR rhs = SR(rhs) return print_order_c(lhs, rhs) @@ -103,7 +103,10 @@ class _print_key(): sage: _print_key(1) <sage.symbolic.expression._print_key object at 0x...> """ - self.ex = ex if isinstance(ex, Expression) else SR(ex) + if not isinstance(ex, Expression): + from sage.symbolic.ring import SR + ex = SR(ex) + self.ex = ex def __lt__(self, other): """ @@ -171,7 +174,10 @@ class _math_key(): sage: _math_key(1) <sage.symbolic.expression._math_key object at 0x...> """ - self.ex = ex if isinstance(ex, Expression) else SR(ex) + if not isinstance(ex, Expression): + from sage.symbolic.ring import SR + ex = SR(ex) + self.ex = ex def __lt__(self, other): """ @@ -284,8 +290,10 @@ cpdef int mixed_order(lhs, rhs) except -2: if lhs is rhs: return 0 if not isinstance(lhs, Expression): + from sage.symbolic.ring import SR lhs = SR(lhs) if not isinstance(rhs, Expression): + from sage.symbolic.ring import SR rhs = SR(rhs) less_than = _mixed_key(lhs) < _mixed_key(rhs) if less_than: @@ -318,7 +326,10 @@ class _mixed_key(): sage: _mixed_key(1) <sage.symbolic.expression._mixed_key object at 0x...> """ - self.ex = ex if isinstance(ex, Expression) else SR(ex) + if not isinstance(ex, Expression): + from sage.symbolic.ring import SR + ex = SR(ex) + self.ex = ex def __lt__(self, other): """ diff --git a/src/sage/symbolic/constants.py b/src/sage/symbolic/constants.py index 87e3d3117ce..07c3f34af39 100644 --- a/src/sage/symbolic/constants.py +++ b/src/sage/symbolic/constants.py @@ -74,7 +74,7 @@ We can obtain floating point approximations to each of these constants by coercing into the real field with given precision. For -example, to 200 decimal places we have the following:: +example, to 200 binary places we have the following:: sage: R = RealField(200); R Real Field with 200 bits of precision @@ -220,6 +220,8 @@ from sage.rings.infinity import (infinity, minus_infinity, unsigned_infinity) from sage.structure.richcmp import richcmp_method, op_EQ, op_GE, op_LE +from sage.symbolic.expression import register_symbol, init_pynac_I +from sage.symbolic.expression import E constants_table = {} constants_name_table = {} @@ -227,17 +229,18 @@ constants_name_table[repr(unsigned_infinity)] = unsigned_infinity constants_name_table[repr(minus_infinity)] = minus_infinity -from sage.symbolic.expression import register_symbol, I -register_symbol(infinity, {'maxima':'inf'}, 0) -register_symbol(minus_infinity, {'maxima':'minf'}, 0) -register_symbol(unsigned_infinity, {'maxima':'infinity'}, 0) -register_symbol(I, {'mathematica':'I'}, 0) -register_symbol(True, {'giac':'true', - 'mathematica':'True', - 'maxima':'true'}, 0) -register_symbol(False, {'giac':'false', - 'mathematica':'False', - 'maxima':'false'}, 0) +I = init_pynac_I() + +register_symbol(infinity, {'maxima': 'inf'}, 0) +register_symbol(minus_infinity, {'maxima': 'minf'}, 0) +register_symbol(unsigned_infinity, {'maxima': 'infinity'}, 0) +register_symbol(I, {'mathematica': 'I'}, 0) +register_symbol(True, {'giac': 'true', + 'mathematica': 'True', + 'maxima': 'true'}, 0) +register_symbol(False, {'giac': 'false', + 'mathematica': 'False', + 'maxima': 'false'}, 0) def unpickle_Constant(class_name, name, conversions, latex, mathml, domain): @@ -268,6 +271,7 @@ def unpickle_Constant(class_name, name, conversions, latex, mathml, domain): cls = globals()[class_name] return cls(name=name) + @richcmp_method class Constant(): def __init__(self, name, conversions=None, latex=None, mathml="", @@ -287,8 +291,8 @@ def __init__(self, name, conversions=None, latex=None, mathml="", self._domain = domain for system, value in self._conversions.items(): - setattr(self, "_%s_"%system, partial(self._generic_interface, value)) - setattr(self, "_%s_init_"%system, partial(self._generic_interface_init, value)) + setattr(self, "_%s_" % system, partial(self._generic_interface, value)) + setattr(self, "_%s_init_" % system, partial(self._generic_interface_init, value)) from .expression import PynacConstant self._pynac = PynacConstant(self._name, self._latex, self._domain) @@ -347,7 +351,6 @@ def __reduce__(self): self._conversions, self._latex, self._mathml, self._domain)) - def domain(self): """ Returns the domain of this constant. This is either positive, @@ -508,7 +511,7 @@ def _interface_(self, I): pass try: - return getattr(self, "_%s_"%(I.name()))(I) + return getattr(self, "_%s_" % (I.name()))(I) except AttributeError: pass @@ -527,7 +530,7 @@ def _gap_(self, gap): sage: gap(p) p """ - return gap('"%s"'%self) + return gap('"%s"' % self) def _singular_(self, singular): """ @@ -544,7 +547,7 @@ def _singular_(self, singular): sage: singular(p) p """ - return singular('"%s"'%self) + return singular('"%s"' % self) class Pi(Constant): @@ -596,17 +599,18 @@ def _real_double_(self, R): def _sympy_(self): """ - Converts pi to sympy pi. + Convert pi to sympy pi. EXAMPLES:: - sage: import sympy - sage: sympy.pi == pi # indirect doctest + sage: import sympy # needs sympy + sage: sympy.pi == pi # indirect doctest # needs sympy True """ import sympy return sympy.pi + pi = Pi().expression() """ @@ -685,12 +689,12 @@ def _sympy_(self): # The base of the natural logarithm, e, is not a constant in GiNaC/Sage. It is # represented by exp(1). A dummy class to make this work with arithmetic and # coercion is implemented in the module sage.symbolic.expression for speed. -from sage.symbolic.expression import E e = E() # Allow for backtranslation to this symbol from Mathematica (#29833). register_symbol(e, {'mathematica': 'E'}) + class NotANumber(Constant): """ Not a Number @@ -702,7 +706,7 @@ def __init__(self, name="NaN"): sage: loads(dumps(NaN)) NaN """ - conversions=dict(matlab='NaN') + conversions = dict(matlab='NaN') Constant.__init__(self, name, conversions=conversions) def __float__(self): @@ -714,7 +718,7 @@ def __float__(self): """ return float('nan') - def _mpfr_(self,R): + def _mpfr_(self, R): """ EXAMPLES:: @@ -723,7 +727,7 @@ def _mpfr_(self,R): sage: type(_) <class 'sage.rings.real_mpfr.RealNumber'> """ - return R('NaN') #??? nan in mpfr: void mpfr_set_nan (mpfr_t x) + return R('NaN') # ??? nan in mpfr: void mpfr_set_nan (mpfr_t x) def _real_double_(self, R): """ @@ -740,17 +744,19 @@ def _sympy_(self): EXAMPLES:: - sage: bool(NaN._sympy_()._sage_() == NaN) + sage: bool(NaN._sympy_()._sage_() == NaN) # needs sympy True - sage: import sympy - sage: sympy.nan == NaN # this should be fixed + sage: import sympy # needs sympy + sage: sympy.nan == NaN # this should be fixed # needs sympy False """ import sympy return sympy.nan + NaN = NotANumber().expression() + class GoldenRatio(Constant): """ The number (1+sqrt(5))/2 @@ -804,7 +810,7 @@ def __float__(self): sage: golden_ratio.__float__() 1.618033988749895 """ - return float(0.5)*(float(1.0)+math.sqrt(float(5.0))) + return 0.5 + math.sqrt(1.25) def _real_double_(self, R): """ @@ -815,8 +821,7 @@ def _real_double_(self, R): """ return R('1.61803398874989484820458') - - def _mpfr_(self,R): + def _mpfr_(self, R): """ EXAMPLES:: @@ -825,7 +830,7 @@ def _mpfr_(self,R): sage: RealField(100)(golden_ratio) 1.6180339887498948482045868344 """ - return (R(1)+R(5).sqrt())/R(2) + return (R(1) + R(5).sqrt()) / R(2) def _algebraic_(self, field): """ @@ -845,15 +850,17 @@ def _sympy_(self): EXAMPLES:: - sage: import sympy - sage: sympy.GoldenRatio == golden_ratio # indirect doctest + sage: import sympy # needs sympy + sage: sympy.GoldenRatio == golden_ratio # indirect doctest # needs sympy True """ import sympy return sympy.GoldenRatio + golden_ratio = GoldenRatio().expression() + class Log2(Constant): """ The natural logarithm of the real number 2. @@ -917,8 +924,7 @@ def _real_double_(self, R): """ return R.log2() - - def _mpfr_(self,R): + def _mpfr_(self, R): """ EXAMPLES:: @@ -929,8 +935,10 @@ def _mpfr_(self,R): """ return R.log2() + log2 = Log2().expression() + class EulerGamma(Constant): """ The limiting difference between the harmonic series and the natural @@ -964,7 +972,7 @@ def __init__(self, name='euler_gamma'): Constant.__init__(self, name, conversions=conversions, latex=r'\gamma', domain='positive') - def _mpfr_(self,R): + def _mpfr_(self, R): """ EXAMPLES:: @@ -999,15 +1007,17 @@ def _sympy_(self): EXAMPLES:: - sage: import sympy - sage: sympy.EulerGamma == euler_gamma # indirect doctest + sage: import sympy # needs sympy + sage: sympy.EulerGamma == euler_gamma # indirect doctest # needs sympy True """ import sympy return sympy.EulerGamma + euler_gamma = EulerGamma().expression() + class Catalan(Constant): """ A number appearing in combinatorics defined as the Dirichlet beta @@ -1025,14 +1035,13 @@ def __init__(self, name='catalan'): sage: loads(dumps(catalan)) catalan """ - #kash: R is default prec + # kash: R is default prec conversions = dict(mathematica='Catalan', kash='Catalan(R)', maple='Catalan', maxima='catalan', pynac='Catalan') Constant.__init__(self, name, conversions=conversions, domain='positive') - def _mpfr_(self, R): """ EXAMPLES:: @@ -1053,7 +1062,6 @@ def _real_double_(self, R): """ return R('0.91596559417721901505460351493252') - def __float__(self): """ EXAMPLES:: @@ -1069,15 +1077,17 @@ def _sympy_(self): EXAMPLES:: - sage: import sympy - sage: sympy.Catalan == catalan # indirect doctest + sage: import sympy # needs sympy + sage: sympy.Catalan == catalan # indirect doctest # needs sympy True """ import sympy return sympy.Catalan + catalan = Catalan().expression() + class Khinchin(Constant): """ The geometric mean of the continued fraction expansion of any @@ -1128,8 +1138,10 @@ def __float__(self): """ return 2.6854520010653064453097148355 + khinchin = Khinchin().expression() + class TwinPrime(Constant): r""" The Twin Primes constant is defined as @@ -1175,6 +1187,7 @@ def __float__(self): """ return 0.66016181584686957392781211001 + twinprime = TwinPrime().expression() @@ -1224,6 +1237,7 @@ def __float__(self): """ return 0.26149721284764278375542683861 + mertens = Mertens().expression() diff --git a/src/sage/symbolic/constants_c_impl.pxi b/src/sage/symbolic/constants_c_impl.pxi index 14369e848ca..3818926a9a2 100644 --- a/src/sage/symbolic/constants_c_impl.pxi +++ b/src/sage/symbolic/constants_c_impl.pxi @@ -16,10 +16,6 @@ The constant `e` # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.symbolic.expression cimport Expression -from sage.symbolic.ring import SR - - # keep exp(1) for fast access # this is initialized in the constructor of the class E below to prevent # circular imports while loading the library @@ -106,8 +102,8 @@ cdef class E(Expression): 2.7182818284590452353602874714 sage: e._real_double_(RDF) # abs tol 5e-16 2.718281828459045 - sage: import sympy - sage: sympy.E == e # indirect doctest + sage: import sympy # needs sympy + sage: sympy.E == e # indirect doctest # needs sympy True TESTS:: @@ -126,6 +122,8 @@ cdef class E(Expression): [e 0] [0 e] """ + from sage.symbolic.ring import SR + global exp_one exp_one = SR.one().exp() Expression.__init__(self, SR, exp_one) @@ -171,7 +169,8 @@ cdef class E(Expression): try: return right.exp() except AttributeError: + from sage.symbolic.ring import SR return SR(right).exp() else: + from sage.symbolic.ring import SR return SR(left)**exp_one - diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 23bed6330b7..0f251ac4e5c 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -238,7 +238,7 @@ Check that :trac:`9880` is fixed:: 11/27*b_0/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) - \ 11/27*b_1/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) - \ 11/27*b_2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ - 64/81/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + 35/81 \ + 64/81/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + 35/81 sage: f.nops() 38 @@ -400,14 +400,14 @@ from sage.rings.infinity import AnInfinity, infinity, minus_infinity, unsigned_i from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR import sage.rings.abc -from sage.misc.decorators import rename_keyword from sage.structure.dynamic_class import dynamic_class -from sage.structure.element cimport CommutativeRingElement from sage.arith.numerical_approx cimport digits_to_bits include "pynac.pxi" include "pynac_impl.pxi" +from sage.symbolic.symbols import symbol_table, register_symbol # used to be defined in pynac_impl + cpdef bint is_Expression(x): """ @@ -439,12 +439,18 @@ cpdef bint is_SymbolicEquation(x): """ Return True if *x* is a symbolic equation. + This function is deprecated. + EXAMPLES: The following two examples are symbolic equations:: sage: from sage.symbolic.expression import is_SymbolicEquation sage: is_SymbolicEquation(sin(x) == x) + doctest:warning... + DeprecationWarning: is_SymbolicEquation is deprecated; use + 'isinstance(x, sage.structure.element.Expression) and x.is_relational()' instead + See https://github.com/sagemath/sage/issues/35505 for details. True sage: is_SymbolicEquation(sin(x) < x) True @@ -464,6 +470,10 @@ cpdef bint is_SymbolicEquation(x): True """ + from sage.misc.superseded import deprecation + deprecation(35505, + "is_SymbolicEquation is deprecated; use " + "'isinstance(x, sage.structure.element.Expression) and x.is_relational()' instead") return isinstance(x, Expression) and is_a_relational((<Expression>x)._gobj) @@ -476,8 +486,12 @@ cpdef bint _is_SymbolicVariable(x): sage: from sage.symbolic.ring import is_SymbolicVariable sage: is_SymbolicVariable(x) + doctest:warning... + DeprecationWarning: is_SymbolicVariable is deprecated; use + 'isinstance(x, sage.structure.element.Expression) and x.is_symbol()' instead + See https://github.com/sagemath/sage/issues/35505 for details. True - sage: is_SymbolicVariable(x+2) + sage: is_SymbolicVariable(x + 2) False TESTS:: @@ -485,6 +499,10 @@ cpdef bint _is_SymbolicVariable(x): sage: ZZ['x'] Univariate Polynomial Ring in x over Integer Ring """ + from sage.misc.superseded import deprecation + deprecation(35505, + "is_SymbolicVariable is deprecated; use " + "'isinstance(x, sage.structure.element.Expression) and x.is_symbol()' instead") return isinstance(x, Expression) and is_a_symbol((<Expression>x)._gobj) @@ -493,7 +511,7 @@ def _dict_update_check_duplicate(dict d1, dict d2): Merge the dictionary ``d2`` into ``d1`` and check for duplicates. The two dictionaries must be of the form ``{expr: replacement}``. This - function throws a ``ValueError`` if any expressions are substituted + function throws a :class:`ValueError` if any expressions are substituted for twice. EXAMPLES: @@ -596,7 +614,7 @@ def _subs_make_dict(s): sage: actual == expected True - Check that a ``TypeError`` is raised if the input is not valid:: + Check that a :class:`TypeError` is raised if the input is not valid:: sage: _subs_make_dict(1) Traceback (most recent call last): @@ -613,7 +631,7 @@ def _subs_make_dict(s): """ if isinstance(s, dict): return s - elif is_SymbolicEquation(s): + elif isinstance(s, Expression) and s.is_relational(): if s.operator() is not operator.eq: msg = "can only substitute equality, not inequalities; got {}" raise TypeError(msg.format(s)) @@ -675,7 +693,7 @@ def _subs_fun_make_dict(s): sage: actual == expected True - Check that a ``TypeError`` is raised if the input is not valid:: + Check that a :class:`TypeError` is raised if the input is not valid:: sage: _subs_fun_make_dict(1) Traceback (most recent call last): @@ -692,7 +710,7 @@ def _subs_fun_make_dict(s): """ if isinstance(s, dict): return dict((k, v) if not isinstance(k, Expression) else (k.operator(), v.function(*k.operands())) for k, v in s.items()) - elif is_SymbolicEquation(s): + elif isinstance(s, Expression) and s.is_relational(): if s.operator() is not operator.eq: msg = "can only substitute equality, not inequalities; got {}" raise TypeError(msg.format(s)) @@ -720,7 +738,7 @@ cdef class Expression(Expression_abc): The Python object corresponding to this expression, assuming this expression is a single numerical value or an infinity - representable in Python. Otherwise, a ``TypeError`` is raised. + representable in Python. Otherwise, a :class:`TypeError` is raised. EXAMPLES:: @@ -756,7 +774,6 @@ cdef class Expression(Expression_abc): ... TypeError: Python infinity cannot have complex phase. """ - cdef GConstant* c if is_a_constant(self._gobj): from sage.symbolic.constants import constants_name_table return constants_name_table[ccrepr(self._gobj)] @@ -1056,9 +1073,9 @@ cdef class Expression(Expression_abc): Check if :trac:`7876` is fixed:: - sage: (1/2-1/2*I )*sqrt(2) + sage: (1/2-1/2*I)*sqrt(2) -(1/2*I - 1/2)*sqrt(2) - sage: latex((1/2-1/2*I )*sqrt(2)) + sage: latex((1/2-1/2*I)*sqrt(2)) -\left(\frac{1}{2} i - \frac{1}{2}\right) \, \sqrt{2} Check if :trac:`9632` is fixed:: @@ -1072,7 +1089,7 @@ cdef class Expression(Expression_abc): def _sympy_character_art(self, use_unicode): r""" - Create character art using Sympy + Create character art using Sympy. INPUT: @@ -1088,7 +1105,7 @@ cdef class Expression(Expression_abc): sage: i = var('i') sage: f = integral(exp(x + x^2)/(x+1), x) ... - sage: f._sympy_character_art(False) + sage: f._sympy_character_art(False) # needs sympy ' / \n | \n | 2 \n | x + x \n | e...' """ from sympy import pretty, sympify @@ -1110,13 +1127,13 @@ cdef class Expression(Expression_abc): EXAMPLES:: sage: i = var('i') - sage: ascii_art(sum(i^2/pi*x^i, i, 0, oo)) + sage: ascii_art(sum(i^2/pi*x^i, i, 0, oo)) # needs sympy 2 x + x ------------------------------- 3 2 - pi*x + 3*pi*x - 3*pi*x + pi - sage: ascii_art(integral(exp(x + x^2)/(x+1), x)) + sage: ascii_art(integral(exp(x + x^2)/(x+1), x)) # needs sympy / | | 2 @@ -1139,13 +1156,13 @@ cdef class Expression(Expression_abc): EXAMPLES:: sage: i = var('i') - sage: unicode_art(sum(i^2/pi*x^i, i, 0, oo)) + sage: unicode_art(sum(i^2/pi*x^i, i, 0, oo)) # needs sympy 2 x + x โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 3 2 - ฯ€โ‹…x + 3โ‹…ฯ€โ‹…x - 3โ‹…ฯ€โ‹…x + ฯ€ - sage: unicode_art(integral(exp(x + x^2)/(x+1), x)) + sage: unicode_art(integral(exp(x + x^2)/(x+1), x)) # needs sympy โŒ  โŽฎ 2 โŽฎ x + x @@ -1158,12 +1175,12 @@ cdef class Expression(Expression_abc): Check that :trac:`28891` is fixed:: - sage: unicode_art(exp(x).series(x, 4)) + sage: unicode_art(exp(x).series(x, 4)) # needs sympy 2 3 x x โŽ› 4โŽž 1 + x + โ”€โ”€ + โ”€โ”€ + OโŽx โŽ  2 6 - sage: unicode_art(exp(x).series(x==1, 3)) + sage: unicode_art(exp(x).series(x==1, 3)) # needs sympy 2 โ„ฏโ‹…(x - 1) โŽ› 3 โŽž โ„ฏ + โ„ฏโ‹…(x - 1) + โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + OโŽ(x - 1) ; x โ†’ 1โŽ  @@ -1171,6 +1188,7 @@ cdef class Expression(Expression_abc): Check that complex numbers are handled correctly (:trac:`28903`):: + sage: # needs sympy sage: unicode_art(SR(I)) โ…ˆ sage: unicode_art(SR(13 - I)) @@ -1180,17 +1198,17 @@ cdef class Expression(Expression_abc): sage: unicode_art(cos(I)) cosh(1) - sage: unicode_art(SR(CC(1/3, 1))) + sage: unicode_art(SR(CC(1/3, 1))) # needs sympy 0.333333333333333 + 1.0โ‹…โ…ˆ - sage: unicode_art(SR(CDF(1/3, 1))) + sage: unicode_art(SR(CDF(1/3, 1))) # needs sympy 0.333333333333333 + 1.0โ‹…โ…ˆ - sage: unicode_art(SR(RealField(100)(1/7))) + sage: unicode_art(SR(RealField(100)(1/7))) # needs sympy 0.14285714285714285714285714286 - sage: K.<a> = QuadraticField(-1) - sage: unicode_art(SR(2 + a)) + sage: K.<a> = QuadraticField(-1) # needs sympy + sage: unicode_art(SR(2 + a)) # needs sympy 2 + โ…ˆ - sage: unicode_art(SR(1/3 + a/2)) + sage: unicode_art(SR(1/3 + a/2)) # needs sympy 1 โ…ˆ โ”€ + โ”€ 3 2 @@ -1278,7 +1296,7 @@ cdef class Expression(Expression_abc): EXAMPLES:: - sage: gap(e + pi^2 + x^3) + sage: gap(e + pi^2 + x^3) # needs sage.libs.gap x^3 + pi^2 + e """ return '"%s"' % repr(self) @@ -1289,10 +1307,10 @@ cdef class Expression(Expression_abc): EXAMPLES:: - sage: singular(e + pi^2 + x^3) + sage: singular(e + pi^2 + x^3) # needs sage.libs.singular x^3 + pi^2 + e """ - return '"%s"'%repr(self) + return '"%s"' % repr(self) def _magma_init_(self, magma): """ @@ -1312,7 +1330,7 @@ cdef class Expression(Expression_abc): sage: magma(f).Type() # optional - magma MonStgElt """ - return '"%s"'%repr(self) + return '"%s"' % repr(self) def _latex_(self): r""" @@ -1603,7 +1621,7 @@ cdef class Expression(Expression_abc): sage: x._eval_self(CC) Traceback (most recent call last): ... - TypeError: Cannot evaluate symbolic expression to a numeric value. + TypeError: cannot evaluate symbolic expression to a numeric value Check if we can compute a real evaluation even if the expression contains complex coefficients:: @@ -1644,7 +1662,7 @@ cdef class Expression(Expression_abc): ans = ans.real return R(ans) else: - raise TypeError("Cannot evaluate symbolic expression to a numeric value.") + raise TypeError("cannot evaluate symbolic expression to a numeric value") cpdef _convert(self, kwds): """ @@ -1932,12 +1950,13 @@ cdef class Expression(Expression_abc): def __float__(self): """ - Return float conversion of self, assuming self is constant. - Otherwise, raise a TypeError. + Return float conversion of ``self``, assuming ``self`` is constant. + + Otherwise, raise a :class:`TypeError`. OUTPUT: - A ``float``. Double precision evaluation of self. + A ``float``. Double precision evaluation of ``self``. EXAMPLES:: @@ -2255,25 +2274,25 @@ cdef class Expression(Expression_abc): if is_a_relational(r._gobj): # both lhs and rhs are relations, so we can get to work if l.operator() == r.operator(): - e2 = ( # case: (x _ y) ?= (x _ y) - left._rel_equal1(right) or - # case: (x == y) ?= (y == x) - # (x != y) ?= (y != x) - ( ( l.operator() == operator.eq or - l.operator() == operator.ne ) and - left._rel_equal2(right) )) + e2 = ( # case: (x _ y) ?= (x _ y) + left._rel_equal1(right) or + # case: (x == y) ?= (y == x) + # (x != y) ?= (y != x) + ((l.operator() == operator.eq or + l.operator() == operator.ne) and + left._rel_equal2(right))) else: - e2 = ( # case: (x < y) ?= (y > x) (or vice versa) - # (x <= y) ?= (y >= x) (or vice versa) - ( ( l.operator() == operator.lt and - r.operator() == operator.gt ) or - ( l.operator() == operator.gt and - r.operator() == operator.lt ) or - ( l.operator() == operator.le and - r.operator() == operator.ge ) or - ( l.operator() == operator.ge and - r.operator() == operator.le ) ) and - left._rel_equal2(right) ) + e2 = ( # case: (x < y) ?= (y > x) (or vice versa) + # (x <= y) ?= (y >= x) (or vice versa) + ((l.operator() == operator.lt and + r.operator() == operator.gt) or + (l.operator() == operator.gt and + r.operator() == operator.lt) or + (l.operator() == operator.le and + r.operator() == operator.ge) or + (l.operator() == operator.ge and + r.operator() == operator.le)) and + left._rel_equal2(right)) else: e2 = False # l is relational but r isn't. @@ -2474,13 +2493,13 @@ cdef class Expression(Expression_abc): # if this is a function with a single argument which is a symbol, i.e. # this is of the form f(x), we pass the string 'f > 0' if is_a_function(self._gobj) and self.nops() == 1 and \ - is_a_symbol(self._gobj.op(0)): - op = self.operator() - # check if op is a user defined function, for builtin - # functions like abs() we still need to pass 'abs(x) > 0' - from sage.symbolic.function import SymbolicFunction - if isinstance(op, SymbolicFunction): - return self.operator().name() + is_a_symbol(self._gobj.op(0)): + op = self.operator() + # check if op is a user defined function, for builtin + # functions like abs() we still need to pass 'abs(x) > 0' + from sage.symbolic.function import SymbolicFunction + if isinstance(op, SymbolicFunction): + return self.operator().name() return self._maxima_init_() def decl_assume(self, decl): @@ -2549,17 +2568,20 @@ cdef class Expression(Expression_abc): True sage: SR(1.2).is_algebraic() False + + sage: complex_root_of(x^3 - x^2 - x - 1, 0).is_algebraic() + True """ from sage.rings.qqbar import QQbar try: - ex = QQbar(self) + _ = QQbar(self) except (TypeError, ValueError, NotImplementedError): return False return True def is_rational_expression(self): """ - Return True if this expression if a rational expression, i.e., + Return ``True`` if this expression if a rational expression, i.e., a quotient of polynomials. EXAMPLES:: @@ -2843,7 +2865,7 @@ cdef class Expression(Expression_abc): def _is_registered_constant_(self): """ - Return True if this symbolic expression is internally represented as + Return ``True`` if this symbolic expression is internally represented as a constant. This function is intended to provide an interface to query the internal @@ -2951,7 +2973,7 @@ cdef class Expression(Expression_abc): cpdef bint is_polynomial(self, var): """ - Return True if self is a polynomial in the given variable. + Return ``True`` if ``self`` is a polynomial in the given variable. EXAMPLES:: @@ -3003,8 +3025,8 @@ cdef class Expression(Expression_abc): sig_off() cpdef bint is_relational(self): - """ - Return True if self is a relational expression. + r""" + Return ``True`` if ``self`` is a relational expression. EXAMPLES:: @@ -3018,8 +3040,8 @@ cdef class Expression(Expression_abc): return is_a_relational(self._gobj) def is_exact(self): - """ - Return True if this expression only contains exact numerical coefficients. + r""" + Return ``True`` if this expression only contains exact numerical coefficients. EXAMPLES:: @@ -3063,18 +3085,15 @@ cdef class Expression(Expression_abc): if op.is_numeric(): yield op else: - for opp in numelems_gen(op): - yield opp + yield from numelems_gen(op) # stop at the first inexact number in the subexpression tree of self, # and if there is no such element, then self is exact - for nelem in numelems_gen(self): - if not nelem.pyobject().base_ring().is_exact(): - return False - return True + return all(nelem.pyobject().base_ring().is_exact() + for nelem in numelems_gen(self)) cpdef bint is_infinity(self): """ - Return True if self is an infinite expression. + Return ``True`` if ``self`` is an infinite expression. EXAMPLES:: @@ -3087,7 +3106,7 @@ cdef class Expression(Expression_abc): cpdef bint is_positive_infinity(self): """ - Return True if self is a positive infinite expression. + Return ``True`` if ``self`` is a positive infinite expression. EXAMPLES:: @@ -3102,7 +3121,7 @@ cdef class Expression(Expression_abc): cpdef bint is_negative_infinity(self): """ - Return True if self is a negative infinite expression. + Return ``True`` if ``self`` is a negative infinite expression. EXAMPLES:: @@ -3174,8 +3193,8 @@ cdef class Expression(Expression_abc): def left_hand_side(self): """ - If self is a relational expression, return the left hand side - of the relation. Otherwise, raise a ValueError. + If ``self`` is a relational expression, return the left hand side + of the relation. Otherwise, raise a :class:`ValueError`. EXAMPLES:: @@ -3196,8 +3215,8 @@ cdef class Expression(Expression_abc): def right_hand_side(self): """ - If self is a relational expression, return the right hand side - of the relation. Otherwise, raise a ValueError. + If ``self`` is a relational expression, return the right hand side + of the relation. Otherwise, raise a :class:`ValueError`. EXAMPLES:: @@ -3464,6 +3483,12 @@ cdef class Expression(Expression_abc): sage: bool(x^2 + 2*x + 1 != (x + 1)^2) False + + Check that :trac:`16031` is fixed:: + + sage: expr = reduce(lambda u, v: 1/u -v, [1/pi] + list(continued_fraction(pi)[:20])) + sage: expr.is_zero() + False """ if self.is_relational(): # constants are wrappers around Sage objects, compare directly @@ -3478,9 +3503,11 @@ cdef class Expression(Expression_abc): return pynac_result == relational_true if pynac_result == relational_true: - if self.operator() == operator.ne: # this hack is necessary to catch the case where the operator is != but is False because of assumptions made + if self.operator() == operator.ne: + # this hack is necessary to catch the case where the + # operator is != but is False because of assumptions made m = self._maxima_() - s = m.parent()._eval_line('is (notequal(%s,%s))'%(repr(m.lhs()),repr(m.rhs()))) + s = m.parent()._eval_line('is (notequal(%s,%s))' % (repr(m.lhs()),repr(m.rhs()))) if s == 'false': return False else: @@ -3499,7 +3526,7 @@ cdef class Expression(Expression_abc): for eqn in assumption_list: try: assumption_var_list.append(eqn.variables()) - except AttributeError: # if we have a GenericDeclaration + except AttributeError: # if we have a GenericDeclaration assumption_var_list.append((eqn._var,)) assumption_vars = set(sum(assumption_var_list, ())) if set(vars).intersection(assumption_vars): @@ -3725,8 +3752,9 @@ cdef class Expression(Expression_abc): def negation(self): """ - Return the negated version of self, that is the relation that is - False iff self is True. + Return the negated version of ``self``. + + This is the relation that is ``False`` iff self is ``True``. EXAMPLES:: @@ -4350,7 +4378,7 @@ cdef class Expression(Expression_abc): :: sage: k = GF(7) - sage: f = expand((k(1)*x^5 + k(1)*x^2 + k(2))^7); f # known bug + sage: f = expand((k(1)*x^5 + k(1)*x^2 + k(2))^7); f # known bug x^35 + x^14 + 2 sage: x^oo @@ -4655,7 +4683,7 @@ cdef class Expression(Expression_abc): def _derivative(self, symb=None, deg=1): """ - Return the deg-th (partial) derivative of self with respect to symb. + Return the ``deg``-th (partial) derivative of ``self`` with respect to ``symb``. EXAMPLES:: @@ -4787,16 +4815,16 @@ cdef class Expression(Expression_abc): def series(self, symbol, order=None): r""" - Return the power series expansion of self in terms of the + Return the power series expansion of ``self`` in terms of the given variable to the given order. INPUT: - - ``symbol`` - a symbolic variable or symbolic equality + - ``symbol`` -- a symbolic variable or symbolic equality such as ``x == 5``; if an equality is given, the expansion is around the value on the right hand side of the equality - - ``order`` - an integer; if nothing given, it is set + - ``order`` -- an integer; if nothing given, it is set to the global default (``20``), which can be changed using :func:`set_series_precision` @@ -4821,7 +4849,8 @@ cdef class Expression(Expression_abc): sage: g.truncate() x^3 - x^2*sin(y) - 5*x + 3 sage: g = f.series(x==1, 4); g - (-sin(y) - 1) + (-2*sin(y) - 2)*(x - 1) + (-sin(y) + 3)*(x - 1)^2 + 1*(x - 1)^3 + Order((x - 1)^4) + (-sin(y) - 1) + (-2*sin(y) - 2)*(x - 1) + (-sin(y) + 3)*(x - 1)^2 + + 1*(x - 1)^3 + Order((x - 1)^4) sage: h = g.truncate(); h (x - 1)^3 - (x - 1)^2*(sin(y) - 3) - 2*(x - 1)*(sin(y) + 1) - sin(y) - 1 sage: h.expand() @@ -4835,7 +4864,8 @@ cdef class Expression(Expression_abc): sage: f.series(x) 1*x^(-1) + (-1/6)*x + ... + Order(x^20) sage: f.series(x==1,3) - (sin(1)) + (cos(1) - 2*sin(1))*(x - 1) + (-2*cos(1) + 5/2*sin(1))*(x - 1)^2 + Order((x - 1)^3) + (sin(1)) + (cos(1) - 2*sin(1))*(x - 1) + (-2*cos(1) + 5/2*sin(1))*(x - 1)^2 + + Order((x - 1)^3) sage: f.series(x==1,3).truncate().expand() -2*x^2*cos(1) + 5/2*x^2*sin(1) + 5*x*cos(1) - 7*x*sin(1) - 3*cos(1) + 11/2*sin(1) @@ -5005,11 +5035,11 @@ cdef class Expression(Expression_abc): INPUT: - - ``*args`` - the following notation is supported + - ``*args`` -- the following notation is supported - - ``x, a, n`` - variable, point, degree + - ``x, a, n`` -- variable, point, degree - - ``(x, a), (y, b), n`` - variables with points, degree of polynomial + - ``(x, a), (y, b), n`` -- variables with points, degree of polynomial EXAMPLES:: @@ -5020,32 +5050,32 @@ cdef class Expression(Expression_abc): :: - sage: taylor(sqrt (sin(x) + a*x + 1), x, 0, 3) + sage: taylor(sqrt(sin(x) + a*x + 1), x, 0, 3) 1/48*(3*a^3 + 9*a^2 + 9*a - 1)*x^3 - 1/8*(a^2 + 2*a + 1)*x^2 + 1/2*(a + 1)*x + 1 :: - sage: taylor (sqrt (x + 1), x, 0, 5) + sage: taylor(sqrt(x + 1), x, 0, 5) 7/256*x^5 - 5/128*x^4 + 1/16*x^3 - 1/8*x^2 + 1/2*x + 1 :: - sage: taylor (1/log (x + 1), x, 0, 3) + sage: taylor(1/log(x + 1), x, 0, 3) -19/720*x^3 + 1/24*x^2 - 1/12*x + 1/x + 1/2 :: - sage: taylor (cos(x) - sec(x), x, 0, 5) + sage: taylor(cos(x) - sec(x), x, 0, 5) -1/6*x^4 - x^2 :: - sage: taylor ((cos(x) - sec(x))^3, x, 0, 9) + sage: taylor((cos(x) - sec(x))^3, x, 0, 9) -1/2*x^8 - x^6 :: - sage: taylor (1/(cos(x) - sec(x))^3, x, 0, 5) + sage: taylor(1/(cos(x) - sec(x))^3, x, 0, 5) -15377/7983360*x^4 - 6767/604800*x^2 + 11/120/x^2 + 1/2/x^4 - 1/x^6 - 347/15120 TESTS: @@ -5243,28 +5273,28 @@ cdef class Expression(Expression_abc): def expand_trig(self, full=False, half_angles=False, plus=True, times=True): r""" Expand trigonometric and hyperbolic functions of sums of angles - and of multiple angles occurring in self. For best results, self - should already be expanded. + and of multiple angles occurring in ``self``. + + For best results, ``self`` should already be expanded. INPUT: - - ``full`` - (default: False) To enhance user control + - ``full`` -- (default: ``False``) To enhance user control of simplification, this function expands only one level at a time by default, expanding sums of angles or multiple angles. To obtain full expansion into sines and cosines immediately, set the optional - parameter full to True. + parameter full to ``True``. - - ``half_angles`` - (default: False) If True, causes - half-angles to be simplified away. + - ``half_angles`` - (default: ``False``) If ``True``, causes + half-angles to be simplified away. - - ``plus`` - (default: True) Controls the sum rule; - expansion of sums (e.g. 'sin(x + y)') will take place only if plus - is True. - - - ``times`` - (default: True) Controls the product - rule, expansion of products (e.g. sin(2\*x)) will take place only - if times is True. + - ``plus`` -- (default: ``True``) Controls the sum rule; + expansion of sums (e.g. `\sin(x + y)`) will take place only + if ``plus`` is ``True``. + - ``times`` -- (default: ``True``) Controls the product + rule, expansion of products (e.g. `\sin(2 x)`) will take place only + if ``times`` is ``True``. OUTPUT: @@ -5283,7 +5313,10 @@ cdef class Expression(Expression_abc): sage: f.expand_trig() sin((3*cos(cos(2*x))^2*sin(cos(2*x)) - sin(cos(2*x))^3)*x) sage: f.expand_trig(full=True) - sin((3*(cos(cos(x)^2)*cos(sin(x)^2) + sin(cos(x)^2)*sin(sin(x)^2))^2*(cos(sin(x)^2)*sin(cos(x)^2) - cos(cos(x)^2)*sin(sin(x)^2)) - (cos(sin(x)^2)*sin(cos(x)^2) - cos(cos(x)^2)*sin(sin(x)^2))^3)*x) + sin((3*(cos(cos(x)^2)*cos(sin(x)^2) + + sin(cos(x)^2)*sin(sin(x)^2))^2*(cos(sin(x)^2)*sin(cos(x)^2) + - cos(cos(x)^2)*sin(sin(x)^2)) + - (cos(sin(x)^2)*sin(cos(x)^2) - cos(cos(x)^2)*sin(sin(x)^2))^3)*x) sage: sin(2*x).expand_trig(times=False) sin(2*x) sage: sin(2*x).expand_trig(times=True) @@ -5303,7 +5336,7 @@ cdef class Expression(Expression_abc): sage: cos((k1-k2)*x).expand().expand_trig() cos(k1*x)*cos(k2*x) + sin(k1*x)*sin(k2*x) - ALIASES: + ALIAS: :meth:`trig_expand` and :meth:`expand_trig` are the same """ @@ -5312,7 +5345,7 @@ cdef class Expression(Expression_abc): P = M.parent() opt = maxima_options(trigexpand=full, halfangles=half_angles, trigexpandplus=plus, trigexpandtimes=times) - cmd = 'trigexpand(%s), %s'%(M.name(), opt) + cmd = 'trigexpand(%s), %s' % (M.name(), opt) ans = P(cmd) return self.parent()(ans) @@ -5327,9 +5360,9 @@ cdef class Expression(Expression_abc): INPUT: - - ``self`` - a symbolic expression + - ``self`` -- a symbolic expression - - ``var`` - (default: None) the variable which is used for + - ``var`` -- (default: ``None``) the variable which is used for these transformations. If not specified, all variables are used. @@ -5349,14 +5382,14 @@ cdef class Expression(Expression_abc): sage: f.reduce_trig(x) sin(y)^2 + 1/8*sin(4*x) + 1/4*sin(2*x) - ALIASES: :meth:`trig_reduce` and :meth:`reduce_trig` are the same + ALIAS: :meth:`trig_reduce` and :meth:`reduce_trig` are the same """ M = self._maxima_() P = M.parent() if var is None: - cmd = 'trigreduce(%s)'%(M.name()) + cmd = 'trigreduce(%s)' % (M.name()) else: - cmd = 'trigreduce(%s,%s)'%(M.name(),'_SAGE_VAR_'+str(var)) + cmd = 'trigreduce(%s,%s)' % (M.name(),'_SAGE_VAR_' + str(var)) ans = P(cmd) return self.parent()(ans) @@ -5367,7 +5400,7 @@ cdef class Expression(Expression_abc): ############################################################################ def match(self, pattern): """ - Check if self matches the given pattern. + Check if ``self`` matches the given pattern. INPUT: @@ -5673,7 +5706,7 @@ cdef class Expression(Expression_abc): sage: cmd = 'subs({}={}, {})' # optional - maple sage: for s1,s2 in subs: # optional - maple - ....: maple.eval(cmd.format(s1,s2, E)) # optional - maple + ....: maple.eval(cmd.format(s1,s2, E)) 'y^4+y^2+y' 'x^4+x+y' 'x^4+x^2+x' @@ -5683,7 +5716,7 @@ cdef class Expression(Expression_abc): sage: cmd = '{} /. {} -> {}' # optional - mathematica sage: for s1,s2 in subs: # optional - mathematica - ....: mathematica.eval(cmd.format(E,s1,s2)) # optional - mathematica + ....: mathematica.eval(cmd.format(E,s1,s2)) 2 4 y + y + y 4 @@ -5695,7 +5728,7 @@ cdef class Expression(Expression_abc): The same, with formatting more suitable for cut and paste:: sage: for s1,s2 in subs: # optional - mathematica - ....: mathematica(cmd.format(E,s1,s2)) # optional - mathematica + ....: mathematica(cmd.format(E,s1,s2)) y + y^2 + y^4 x + x^4 + y x^4 + y @@ -6363,7 +6396,6 @@ cdef class Expression(Expression_abc): sage: type(u._unpack_operands()[0]) <... 'tuple'> """ - from sage.symbolic.expression import unpack_operands return unpack_operands(self) def operands(self): @@ -6523,19 +6555,22 @@ cdef class Expression(Expression_abc): sage: x.iterator() Traceback (most recent call last): ... - ValueError: expressions containing only a numeric coefficient, constant or symbol have no operands + ValueError: expressions containing only a numeric coefficient, + constant or symbol have no operands sage: pi.iterator() Traceback (most recent call last): ... - ValueError: expressions containing only a numeric coefficient, constant or symbol have no operands + ValueError: expressions containing only a numeric coefficient, + constant or symbol have no operands sage: SR(5).iterator() Traceback (most recent call last): ... - ValueError: expressions containing only a numeric coefficient, constant or symbol have no operands + ValueError: expressions containing only a numeric coefficient, + constant or symbol have no operands """ if (is_a_symbol(self._gobj) or is_a_constant(self._gobj) or - is_a_numeric(self._gobj)): - raise ValueError("expressions containing only a numeric coefficient, constant or symbol have no operands") + is_a_numeric(self._gobj)): + raise ValueError("expressions containing only a numeric coefficient, constant or symbol have no operands") return new_ExpIter_from_Expression(self) @property @@ -6551,7 +6586,8 @@ cdef class Expression(Expression_abc): sage: x.op Traceback (most recent call last): ... - TypeError: expressions containing only a numeric coefficient, constant or symbol have no operands + TypeError: expressions containing only a numeric coefficient, + constant or symbol have no operands sage: t.op[0] x^2 @@ -6563,8 +6599,8 @@ cdef class Expression(Expression_abc): TypeError: 'sage.symbolic.expression.Expression' object ... """ if (is_a_symbol(self._gobj) or is_a_constant(self._gobj) or - is_a_numeric(self._gobj)): - raise TypeError("expressions containing only a numeric coefficient, constant or symbol have no operands") + is_a_numeric(self._gobj)): + raise TypeError("expressions containing only a numeric coefficient, constant or symbol have no operands") cdef OperandsWrapper res = OperandsWrapper.__new__(OperandsWrapper) res._expr = self return res @@ -6673,8 +6709,8 @@ cdef class Expression(Expression_abc): class DefiniteSumExpander(ExpressionTreeWalker): def composition(self, ex, operator): if hasattr(operator, 'name') and operator.name() == 'sum' and ( - is_a_numeric((<Expression>ex.operands()[2])._gobj) - and is_a_numeric((<Expression>ex.operands()[3])._gobj)): + is_a_numeric((<Expression>ex.operands()[2])._gobj) + and is_a_numeric((<Expression>ex.operands()[3])._gobj)): from sage.calculus.calculus import symbolic_sum return symbolic_sum(*(ex.operands())) return super().composition(ex, operator) @@ -6801,12 +6837,11 @@ cdef class Expression(Expression_abc): # we override type checking in CallableSymbolicExpressionRing, # since it checks for old SymbolicVariable's # and do the check here instead - from sage.symbolic.callable import CallableSymbolicExpressionRing - from sage.symbolic.ring import is_SymbolicVariable for i in args: - if not is_SymbolicVariable(i): + if not (isinstance(i, Expression) and i.is_symbol()): break else: + from sage.symbolic.callable import CallableSymbolicExpressionRing R = CallableSymbolicExpressionRing(args, check=False) return R(self) raise TypeError(f"must construct a function with symbolic variables as arguments, got {args}.") @@ -6998,7 +7033,7 @@ cdef class Expression(Expression_abc): raise TypeError("n != 1 only allowed for s being a variable") # the following is a temporary fix for GiNaC bug #9505 - if is_a_mul(ss._gobj): # necessarily n=1 here + if is_a_mul(ss._gobj): # necessarily n=1 here res = self for i in range(ss._gobj.nops()): res = res.coefficient(new_Expression_from_GEx(self._parent, ss._gobj.op(i))) @@ -7064,7 +7099,7 @@ cdef class Expression(Expression_abc): sage: p.coefficients(x, sparse=False) Traceback (most recent call last): ... - ValueError: Cannot return dense coefficient list with noninteger exponents. + ValueError: cannot return dense coefficient list with noninteger exponents Series coefficients are now handled correctly (:trac:`17399`):: @@ -7107,7 +7142,6 @@ cdef class Expression(Expression_abc): [[(x + 1)^pi, 0]] """ cdef vector[pair[GEx,GEx]] vec - cdef pair[GEx,GEx] gexpair cdef Expression xx if x is None: x = self.default_variable() @@ -7123,20 +7157,20 @@ cdef class Expression(Expression_abc): new_Expression_from_GEx(self._parent, p.second)]) if sparse is True: return l - else: - from sage.rings.integer_ring import ZZ - if any(not c[1] in ZZ for c in l): - raise ValueError("Cannot return dense coefficient list with noninteger exponents.") - if not l: - l = [[0, 0]] - val = l[0][1] - if val < 0: - raise ValueError("Cannot return dense coefficient list with negative valuation.") - deg = l[-1][1] - ret = [ZZ(0)] * int(deg+1) - for c in l: - ret[c[1]] = c[0] - return ret + + from sage.rings.integer_ring import ZZ + if any(not c[1] in ZZ for c in l): + raise ValueError("cannot return dense coefficient list with noninteger exponents") + if not l: + l = [[0, 0]] + val = l[0][1] + if val < 0: + raise ValueError("cannot return dense coefficient list with negative valuation") + deg = l[-1][1] + ret = [ZZ(0)] * int(deg+1) + for c in l: + ret[c[1]] = c[0] + return ret def list(self, x=None): r""" @@ -7579,9 +7613,11 @@ cdef class Expression(Expression_abc): sage: f = sum((e*I)^n*x^n for n in range(5)); f x^4*e^4 - I*x^3*e^3 - x^2*e^2 + I*x*e + 1 sage: f.polynomial(CDF) # abs tol 5e-16 - 54.598150033144236*x^4 - 20.085536923187668*I*x^3 - 7.38905609893065*x^2 + 2.718281828459045*I*x + 1.0 + 54.598150033144236*x^4 - 20.085536923187668*I*x^3 - 7.38905609893065*x^2 + + 2.718281828459045*I*x + 1.0 sage: f.polynomial(CC) - 54.5981500331442*x^4 - 20.0855369231877*I*x^3 - 7.38905609893065*x^2 + 2.71828182845905*I*x + 1.00000000000000 + 54.5981500331442*x^4 - 20.0855369231877*I*x^3 - 7.38905609893065*x^2 + + 2.71828182845905*I*x + 1.00000000000000 A multivariate polynomial over a finite field:: @@ -7688,7 +7724,8 @@ cdef class Expression(Expression_abc): sage: R = ComplexField(100)['x,y'] sage: R(f) - 2.7182818284590452353602874714*x^3 + 3.1415926535897932384626433833*y^3 + 1.4142135623730950488016887242 + 1.0000000000000000000000000000*I + 2.7182818284590452353602874714*x^3 + 3.1415926535897932384626433833*y^3 + + 1.4142135623730950488016887242 + 1.0000000000000000000000000000*I TESTS: @@ -7772,6 +7809,8 @@ cdef class Expression(Expression_abc): """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.fraction_field import FractionField + from sage.symbolic.ring import SR + nu = SR(self.numerator()).polynomial(base_ring) de = SR(self.denominator()).polynomial(base_ring) vars = sorted(set(nu.variables() + de.variables()), key=repr) @@ -7807,7 +7846,7 @@ cdef class Expression(Expression_abc): def gcd(self, b): r""" - Return the symbolic gcd of self and b. + Return the symbolic gcd of ``self`` and ``b``. Note that the polynomial GCD is unique up to the multiplication by an invertible constant. The following examples make sure all @@ -7996,7 +8035,6 @@ cdef class Expression(Expression_abc): ValueError: expression not Gosper-summable """ cdef Expression s - cdef int i = 1 s = self.coerce_in(n) sig_on() try: @@ -8030,7 +8068,6 @@ cdef class Expression(Expression_abc): 0 """ cdef Expression s, f - cdef int i = 1 s = self.coerce_in(k) f = self.subs(n == n+1) - self sig_on() @@ -8043,9 +8080,10 @@ cdef class Expression(Expression_abc): def lcm(self, b): """ - Return the lcm of self and b. + Return the lcm of ``self`` and ``b``. - The lcm is computed from the gcd of self and b implicitly from the + The lcm is computed from the gcd of ``self`` and ``b`` + implicitly from the relation self * b = gcd(self, b) * lcm(self, b). .. NOTE:: @@ -8258,7 +8296,7 @@ cdef class Expression(Expression_abc): sage: (x^(1/3)).horner(x) Traceback (most recent call last): ... - ValueError: Cannot return dense coefficient list with noninteger exponents. + ValueError: cannot return dense coefficient list with noninteger exponents """ coef = self.coefficients(x, sparse=False) res = coef[-1] @@ -8289,16 +8327,16 @@ cdef class Expression(Expression_abc): Symbolic Ring """ cdef Expression zero - if not isinstance(pol[0], Expression): # avoid infinite recursion + if not isinstance(pol[0], Expression): # avoid infinite recursion try: x = self.pyobject() - y = pol(x) # may fail if x is a symbolic constant + y = pol(x) # may fail if x is a symbolic constant except TypeError: pass else: return new_Expression_from_pyobject(self._parent, y) zero = self._parent.zero() - return zero.add(*(pol[i]*self**i for i in xrange(pol.degree() + 1))) + return zero.add(*(pol[i]*self**i for i in range(pol.degree() + 1))) def collect_common_factors(self): """ @@ -8649,7 +8687,7 @@ cdef class Expression(Expression_abc): Check that :trac:`29400` is fixed:: - sage: cot(1 + i).imag().n() - (1/tan(1 + i)).imag().n() # abs tol 10^-12 + sage: cot(1 + i).imag().n() - (1/tan(1 + i)).imag().n() # abs tol 10^-12 0.00000000000000 """ return new_Expression_from_GEx(self._parent, @@ -9025,7 +9063,7 @@ cdef class Expression(Expression_abc): 1/3*pi sage: SR(0.4).arccos() 1.15927948072741 - sage: plot(lambda x: SR(x).arccos(), -1,1) + sage: plot(lambda x: SR(x).arccos(), -1,1) # needs sage.plot Graphics object consisting of 1 graphics primitive To prevent automatic evaluation use the ``hold`` argument:: @@ -9076,7 +9114,7 @@ cdef class Expression(Expression_abc): arctan(1/2) sage: SR(0.5).arctan() 0.463647609000806 - sage: plot(lambda x: SR(x).arctan(), -20,20) + sage: plot(lambda x: SR(x).arctan(), -20,20) # needs sage.plot Graphics object consisting of 1 graphics primitive To prevent automatic evaluation use the ``hold`` argument:: @@ -9346,7 +9384,7 @@ cdef class Expression(Expression_abc): 0.761594155955765 sage: maxima('tanh(1.0)') 0.7615941559557649 - sage: plot(lambda x: SR(x).tanh(), -1, 1) + sage: plot(lambda x: SR(x).tanh(), -1, 1) # needs sage.plot Graphics object consisting of 1 graphics primitive To prevent automatic evaluation use the ``hold`` argument:: @@ -9622,7 +9660,7 @@ cdef class Expression(Expression_abc): 0.500000000000000 sage: math.log(0.5) -0.6931471805599453 - sage: plot(lambda x: SR(x).log(), 0.1,10) + sage: plot(lambda x: SR(x).log(), 0.1,10) # needs sage.plot Graphics object consisting of 1 graphics primitive To prevent automatic evaluation use the ``hold`` argument:: @@ -9671,11 +9709,11 @@ cdef class Expression(Expression_abc): 1/6*pi^2 sage: SR(3).zeta() zeta(3) - sage: SR(CDF(0,1)).zeta() # abs tol 1e-16 + sage: SR(CDF(0,1)).zeta() # abs tol 1e-16 # needs sage.libs.pari 0.003300223685324103 - 0.4181554491413217*I - sage: CDF(0,1).zeta() # abs tol 1e-16 + sage: CDF(0,1).zeta() # abs tol 1e-16 # needs sage.libs.pari 0.003300223685324103 - 0.4181554491413217*I - sage: plot(lambda x: SR(x).zeta(), -10,10).show(ymin=-3,ymax=3) + sage: plot(lambda x: SR(x).zeta(), -10,10).show(ymin=-3, ymax=3) # needs sage.plot To prevent automatic evaluation use the ``hold`` argument:: @@ -9850,7 +9888,7 @@ cdef class Expression(Expression_abc): We plot the familiar plot of this log-convex function:: - sage: plot(gamma(x), -6,4).show(ymin=-3,ymax=3) + sage: plot(gamma(x), -6, 4).show(ymin=-3, ymax=3) # needs sage.plot To prevent automatic evaluation use the ``hold`` argument:: @@ -9911,10 +9949,11 @@ cdef class Expression(Expression_abc): sage: SR(5-1).factorial().log() log(24) sage: from sage.misc.verbose import set_verbose - sage: set_verbose(-1); plot(lambda x: SR(x).log_gamma(), -7,8, plot_points=1000).show() + sage: set_verbose(-1) + sage: plot(lambda x: SR(x).log_gamma(), -7,8, plot_points=1000).show() # needs sage.plot sage: math.exp(0.5) 1.6487212707001282 - sage: plot(lambda x: (SR(x).exp() - SR(-x).exp())/2 - SR(x).sinh(), -1, 1) + sage: plot(lambda x: (SR(x).exp() - SR(-x).exp())/2 - SR(x).sinh(), -1, 1) # needs sage.plot Graphics object consisting of 1 graphics primitive To prevent automatic evaluation use the ``hold`` argument:: @@ -10593,14 +10632,26 @@ cdef class Expression(Expression_abc): else: return self - def simplify(self): + def simplify(self, algorithm='maxima', **kwds): """ Return a simplified version of this symbolic expression. - .. NOTE:: + INPUT: + + - ``algorithm`` -- one of : + + - ``maxima`` : (default) sends the expression to + ``maxima`` and converts it back to Sage + + - ``sympy`` : converts the expression to ``sympy``, + simplifies it (passing any optional keyword(s)), and + converts the result to Sage - Currently, this just sends the expression to Maxima - and converts it back to Sage. + - ``giac`` : converts the expression to ``giac``, + simplifies it, and converts the result to Sage + + - ``fricas`` : converts the expression to ``fricas``, + simplifies it, and converts the result to Sage .. SEEALSO:: @@ -10617,6 +10668,22 @@ cdef class Expression(Expression_abc): sage: f.simplify() x^(-a + 1)*sin(2) + Some simplifications are quite algorithm-specific:: + + sage: x, t = var("x, t") + sage: ex = cos(t).exponentialize() + sage: ex = ex.subs((sin(t).exponentialize()==x).solve(t)[0]) + sage: ex + 1/2*I*x + 1/2*I*sqrt(x^2 - 1) + 1/2/(I*x + I*sqrt(x^2 - 1)) + sage: ex.simplify() + 1/2*I*x + 1/2*I*sqrt(x^2 - 1) + 1/(2*I*x + 2*I*sqrt(x^2 - 1)) + sage: ex.simplify(algorithm="sympy") + I*(x^2 + sqrt(x^2 - 1)*x - 1)/(x + sqrt(x^2 - 1)) + sage: ex.simplify(algorithm="giac") + I*sqrt(x^2 - 1) + sage: ex.simplify(algorithm="fricas") # optional - fricas + (I*x^2 + I*sqrt(x^2 - 1)*x - I)/(x + sqrt(x^2 - 1)) + TESTS: Check that :trac:`14637` is fixed:: @@ -10625,8 +10692,22 @@ cdef class Expression(Expression_abc): sage: acos(cos(x)).simplify() x sage: forget() + + Check that simplifying with sympy works correctly:: + + sage: expr = (-1/5*(2*sqrt(6)*(sqrt(5) - 5) + 11*sqrt(5) - 11)/(2*sqrt(6)*sqrt(5) - 11)) + sage: expr.simplify(algorithm='sympy') + 1/5*sqrt(5) - 1/5 """ - return self._parent(self._maxima_()) + if algorithm == "maxima": + return self._parent(self._maxima_()) + if algorithm == "sympy": + return self._sympy_().simplify(**kwds)._sage_() + if algorithm == "giac": + return self._giac_().simplify()._sage_() + if algorithm == "fricas": + return self._fricas_().simplify()._sage_() + raise ValueError(f"algorithm {algorithm} unknown to simplify") def simplify_full(self): """ @@ -10702,6 +10783,10 @@ cdef class Expression(Expression_abc): sage: f.simplify_full() sin(x)/cos(x) + Check that :trac:`20846` is fixed:: + + sage: ((1/6*pi^2).series(x)).simplify_full() + 1/6*pi^2 """ x = self x = x.simplify_factorial() @@ -10766,7 +10851,8 @@ cdef class Expression(Expression_abc): raise NotImplementedError( "unknown algorithm: '{}'".format(algorithm)) - simplify = lambda o: o.simplify_hypergeometric(algorithm) + def simplify(o): + return o.simplify_hypergeometric(algorithm) if op == hypergeometric: a = [simplify(o) for o in ops[0].operands()] @@ -11116,9 +11202,9 @@ cdef class Expression(Expression_abc): P = self_m.parent() self_str = self_m.str() if map: - cmd = "if atom(%s) then %s(%s) else map(%s,%s)"%(self_str,maxima_method,self_str,maxima_method,self_str) + cmd = "if atom(%s) then %s(%s) else map(%s,%s)" % (self_str, maxima_method, self_str, maxima_method, self_str) else: - cmd = "%s(%s)"%(maxima_method,self_m.str()) + cmd = "%s(%s)" % (maxima_method, self_m.str()) res = P(cmd) return self.parent()(res) @@ -11723,7 +11809,7 @@ cdef class Expression(Expression_abc): maxima_method='super' else: raise NotImplementedError("unknown algorithm, see the help for available algorithms") - maxima.eval('logexpand:%s'%maxima_method) + maxima.eval('logexpand:%s' % maxima_method) res = self._maxima_() res = res.sage() # Set the domain back to what it was before expand_log() was called. @@ -11836,7 +11922,7 @@ cdef class Expression(Expression_abc): return op(*done) return self - def factor(self, dontfactor=[]): + def factor(self, dontfactor=None): """ Factor the expression, containing any number of variables or functions, into factors irreducible over the integers. @@ -11909,6 +11995,8 @@ cdef class Expression(Expression_abc): cdef GEx x cdef bint b if dontfactor or not self.is_rational_expression(): + if dontfactor is None: + dontfactor = [] m = self._maxima_() name = m.name() varstr = ','.join('_SAGE_VAR_' + str(v) for v in dontfactor) @@ -11924,16 +12012,16 @@ cdef class Expression(Expression_abc): else: return self - def factor_list(self, dontfactor=[]): + def factor_list(self, dontfactor=None): """ Return a list of the factors of self, as computed by the factor command. INPUT: - - ``self`` - a symbolic expression + - ``self`` -- a symbolic expression - - ``dontfactor`` - see docs for :meth:`factor` + - ``dontfactor`` -- see docs for :meth:`factor` .. NOTE:: @@ -12092,7 +12180,7 @@ cdef class Expression(Expression_abc): sage: wrong.convert() Traceback (most recent call last): ... - ValueError: Cannot convert + ValueError: cannot convert """ from . import units return units.convert(self, target) @@ -12116,14 +12204,14 @@ cdef class Expression(Expression_abc): - ``x`` - variable to view the function in terms of (use default variable if not given) - - ``explicit_solutions`` - bool (default True); require that + - ``explicit_solutions`` -- bool (default ``True``); require that roots be explicit rather than implicit - - ``multiplicities`` - bool (default True); when True, return + - ``multiplicities`` -- bool (default ``True``); when ``True``, return multiplicities - - ``ring`` - a ring (default None): if not None, convert - self to a polynomial over ring and find roots over ring + - ``ring`` -- a ring (default ``None``): if not ``None``, convert + ``self`` to a polynomial over ring and find roots over ring OUTPUT: @@ -12218,19 +12306,31 @@ cdef class Expression(Expression_abc): Now let us find some roots over different rings:: sage: f.roots(ring=CC) - [(-0.0588115223184..., 1), (-1.331099917875... - 1.52241655183732*I, 1), (-1.331099917875... + 1.52241655183732*I, 1), (1.36050567903502 - 1.51880872209965*I, 1), (1.36050567903502 + 1.51880872209965*I, 1)] + [(-0.0588115223184..., 1), + (-1.331099917875... - 1.52241655183732*I, 1), + (-1.331099917875... + 1.52241655183732*I, 1), + (1.36050567903502 - 1.51880872209965*I, 1), + (1.36050567903502 + 1.51880872209965*I, 1)] sage: (2.5*f).roots(ring=RR) [(-0.058811522318449..., 1)] sage: f.roots(ring=CC, multiplicities=False) - [-0.05881152231844..., -1.331099917875... - 1.52241655183732*I, -1.331099917875... + 1.52241655183732*I, 1.36050567903502 - 1.51880872209965*I, 1.36050567903502 + 1.51880872209965*I] + [-0.05881152231844..., + -1.331099917875... - 1.52241655183732*I, + -1.331099917875... + 1.52241655183732*I, + 1.36050567903502 - 1.51880872209965*I, + 1.36050567903502 + 1.51880872209965*I] sage: f.roots(ring=QQ) [] sage: f.roots(ring=QQbar, multiplicities=False) - [-0.05881152231844944?, -1.331099917875796? - 1.522416551837318?*I, -1.331099917875796? + 1.522416551837318?*I, 1.360505679035020? - 1.518808722099650?*I, 1.360505679035020? + 1.518808722099650?*I] + [-0.05881152231844944?, + -1.331099917875796? - 1.522416551837318?*I, + -1.331099917875796? + 1.522416551837318?*I, + 1.360505679035020? - 1.518808722099650?*I, + 1.360505679035020? + 1.518808722099650?*I] Root finding over finite fields:: - sage: f.roots(ring=GF(7^2, 'a')) + sage: f.roots(ring=GF(7^2, 'a')) # needs sage.rings.finite_rings [(3, 1), (4*a + 6, 2), (3*a + 3, 2)] TESTS:: @@ -12246,7 +12346,8 @@ cdef class Expression(Expression_abc): (f6, f5, f4, x) sage: e = 15*f6*x^2 + 5*f5*x + f4 sage: res = e.roots(x); res - [(-1/30*(5*f5 + sqrt(25*f5^2 - 60*f4*f6))/f6, 1), (-1/30*(5*f5 - sqrt(25*f5^2 - 60*f4*f6))/f6, 1)] + [(-1/30*(5*f5 + sqrt(25*f5^2 - 60*f4*f6))/f6, 1), + (-1/30*(5*f5 - sqrt(25*f5^2 - 60*f4*f6))/f6, 1)] sage: e.subs(x=res[0][0]).is_zero() True """ @@ -12264,7 +12365,7 @@ cdef class Expression(Expression_abc): if multiplicities: return rt_muls else: - return [ rt for rt, mul in rt_muls ] + return [rt for rt, mul in rt_muls] def solve(self, x, multiplicities=False, solution_dict=False, explicit_solutions=False, to_poly_solve=False, algorithm=None, domain=None): r""" @@ -12273,27 +12374,27 @@ cdef class Expression(Expression_abc): .. warning:: - This is not a numerical solver - use ``find_root`` to solve - for self == 0 numerically on an interval. + This is not a numerical solver -- use :meth:`find_root` to solve + for ``self == 0`` numerically on an interval. INPUT: - - ``x`` - variable(s) to solve for + - ``x`` -- variable(s) to solve for - - ``multiplicities`` - bool (default: False); if True, + - ``multiplicities`` -- bool (default: ``False``); if ``True``, return corresponding multiplicities. This keyword is incompatible with ``to_poly_solve=True`` and does not make any sense when solving an inequality. - - ``solution_dict`` - bool (default: False); if True or non-zero, + - ``solution_dict`` -- bool (default: ``False``); if ``True`` or non-zero, return a list of dictionaries containing solutions. Not used when solving an inequality. - - ``explicit_solutions`` - bool (default: False); require that + - ``explicit_solutions`` -- bool (default: ``False``); require that all roots be explicit rather than implicit. Not used when solving an inequality. - - ``to_poly_solve`` - bool (default: False) or string; use + - ``to_poly_solve`` -- bool (default: ``False``) or string; use Maxima's ``to_poly_solver`` package to search for more possible solutions, but possibly encounter approximate solutions. This keyword is incompatible with ``multiplicities=True`` @@ -12305,7 +12406,11 @@ cdef class Expression(Expression_abc): sage: z = var('z') sage: (z^5 - 1).solve(z) - [z == 1/4*sqrt(5) + 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4, z == -1/4*sqrt(5) + 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4, z == -1/4*sqrt(5) - 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4, z == 1/4*sqrt(5) - 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4, z == 1] + [z == 1/4*sqrt(5) + 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4, + z == -1/4*sqrt(5) + 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4, + z == -1/4*sqrt(5) - 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4, + z == 1/4*sqrt(5) - 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4, + z == 1] sage: solve((z^3-1)^3, z, multiplicities=True) ([z == 1/2*I*sqrt(3) - 1/2, z == -1/2*I*sqrt(3) - 1/2, z == 1], [3, 3, 3]) @@ -12316,7 +12421,9 @@ cdef class Expression(Expression_abc): sage: w = x^4 - (1+3*i)*x^3 - (2-4*i)*x^2 + (6-2*i)*x - 4 - 4*i sage: w.solve(x,multiplicities=True) - ([x == -1/2*sqrt(2*I) + 3/2*I - 1/2, x == 1/2*sqrt(2*I) + 3/2*I - 1/2, x == (-I + 1), x == (I + 1)], + ([x == -1/2*sqrt(2*I) + 3/2*I - 1/2, + x == 1/2*sqrt(2*I) + 3/2*I - 1/2, + x == (-I + 1), x == (I + 1)], [1, 1, 1, 1]) See :func:`sage.symbolic.relation.solve` or the output of ``solve?`` @@ -12341,11 +12448,11 @@ cdef class Expression(Expression_abc): EXAMPLES:: sage: x,y = var('x,y') - sage: solve_diophantine(3*x == 4) + sage: solve_diophantine(3*x == 4) # needs sympy [] - sage: solve_diophantine(x^2 - 9) + sage: solve_diophantine(x^2 - 9) # needs sympy [-3, 3] - sage: sorted(solve_diophantine(x^2 + y^2 == 25)) + sage: sorted(solve_diophantine(x^2 + y^2 == 25)) # needs sympy [(-5, 0), (-4, -3), (-4, 3), (-3, -4), (-3, 4), (0, -5)... The function is used when ``solve()`` is called with all variables @@ -12353,45 +12460,52 @@ cdef class Expression(Expression_abc): sage: assume(x, 'integer') sage: assume(y, 'integer') - sage: sorted(solve(x*y == 1, (x,y))) + sage: sorted(solve(x*y == 1, (x,y))) # needs sympy [(-1, -1), (1, 1)] You can also pick specific variables, and get the solution as a dictionary:: + sage: # needs sympy sage: solve_diophantine(x*y == 10, x) [-10, -5, -2, -1, 1, 2, 5, 10] sage: sorted(solve_diophantine(x*y - y == 10, (x,y))) [(-9, -1), (-4, -2), (-1, -5), (0, -10), (2, 10), (3, 5), (6, 2), (11, 1)] sage: res = solve_diophantine(x*y - y == 10, solution_dict=True) - sage: sol = [{y: -5, x: -1}, {y: -10, x: 0}, {y: -1, x: -9}, {y: -2, x: -4}, {y: 10, x: 2}, {y: 1, x: 11}, {y: 2, x: 6}, {y: 5, x: 3}] - sage: all(solution in res for solution in sol) and bool(len(res) == len(sol)) + sage: sol = [{y: -5, x: -1}, {y: -10, x: 0}, {y: -1, x: -9}, {y: -2, x: -4}, + ....: {y: 10, x: 2}, {y: 1, x: 11}, {y: 2, x: 6}, {y: 5, x: 3}] + sage: all(solution in res + ....: for solution in sol) and bool(len(res) == len(sol)) True If the solution is parametrized the parameter(s) are not defined, but you can substitute them with specific integer values:: + sage: # needs sympy sage: x,y,z = var('x,y,z') - sage: sol = solve_diophantine(x^2-y==0); sol + sage: sol = solve_diophantine(x^2-y == 0); sol (t, t^2) sage: [(sol[0].subs(t=t),sol[1].subs(t=t)) for t in range(-3,4)] [(-3, 9), (-2, 4), (-1, 1), (0, 0), (1, 1), (2, 4), (3, 9)] sage: sol = solve_diophantine(x^2 + y^2 == z^2); sol (2*p*q, p^2 - q^2, p^2 + q^2) - sage: [(sol[0].subs(p=p,q=q),sol[1].subs(p=p,q=q),sol[2].subs(p=p,q=q)) for p in range(1,4) for q in range(1,4)] - [(2, 0, 2), (4, -3, 5), (6, -8, 10), (4, 3, 5), (8, 0, 8), (12, -5, 13), (6, 8, 10), (12, 5, 13), (18, 0, 18)] + sage: [(sol[0].subs(p=p,q=q), sol[1].subs(p=p,q=q), sol[2].subs(p=p,q=q)) + ....: for p in range(1,4) for q in range(1,4)] + [(2, 0, 2), (4, -3, 5), (6, -8, 10), (4, 3, 5), (8, 0, 8), + (12, -5, 13), (6, 8, 10), (12, 5, 13), (18, 0, 18)] Solve Brahmagupta-Pell equations:: - sage: sol = sorted(solve_diophantine(x^2 - 2*y^2 == 1), key=str) - sage: sol - [(-sqrt(2)*(2*sqrt(2) + 3)^t + sqrt(2)*(-2*sqrt(2) + 3)^t - 3/2*(2*sqrt(2) + 3)^t - 3/2*(-2*sqrt(2) + 3)^t,... - sage: [(sol[1][0].subs(t=t).simplify_full(),sol[1][1].subs(t=t).simplify_full()) for t in range(-1,5)] + sage: sol = sorted(solve_diophantine(x^2 - 2*y^2 == 1), key=str); sol # needs sympy + [(-sqrt(2)*(2*sqrt(2) + 3)^t + sqrt(2)*(-2*sqrt(2) + 3)^t + - 3/2*(2*sqrt(2) + 3)^t - 3/2*(-2*sqrt(2) + 3)^t,... + sage: [(sol[1][0].subs(t=t).simplify_full(), # needs sympy + ....: sol[1][1].subs(t=t).simplify_full()) for t in range(-1,5)] [(1, 0), (3, -2), (17, -12), (99, -70), (577, -408), (3363, -2378)] TESTS:: - sage: solve_diophantine(x^2 - y, x, y) + sage: solve_diophantine(x^2 - y, x, y) # needs sympy Traceback (most recent call last): ... AttributeError: please use a tuple or list for several variables. @@ -12411,7 +12525,7 @@ cdef class Expression(Expression_abc): ex = self sympy_ex = ex._sympy_() solutions = diophantine(sympy_ex) - if isinstance(solutions, (set)): + if isinstance(solutions, set): solutions = list(solutions) if len(solutions) == 0: @@ -12422,7 +12536,7 @@ cdef class Expression(Expression_abc): solutions = [tuple(SR(s) for s in sol) for sol in solutions] if x is None: wanted_vars = ex.variables() - var_idx = list(xrange(len(ex.variables()))) + var_idx = list(range(len(ex.variables()))) else: if isinstance(x, (list, tuple)): wanted_vars = x @@ -12478,6 +12592,7 @@ cdef class Expression(Expression_abc): Note that in this example both f(-2) and f(3) are positive, yet we still find a root in that interval:: + sage: # needs scipy sage: f = x^2 - 1 sage: f.find_root(-2, 3) 1.0 @@ -12497,9 +12612,9 @@ cdef class Expression(Expression_abc): More examples:: - sage: (sin(x) + exp(x)).find_root(-10, 10) + sage: (sin(x) + exp(x)).find_root(-10, 10) # needs scipy -0.588532743981862... - sage: sin(x).find_root(-1,1) + sage: sin(x).find_root(-1,1) # needs scipy 0.0 This example was fixed along with :trac:`4942` - @@ -12507,34 +12622,34 @@ cdef class Expression(Expression_abc): pi is a root for tan(x), but an asymptote to 1/tan(x) added an example to show handling of both cases:: - sage: (tan(x)).find_root(3,3.5) + sage: (tan(x)).find_root(3,3.5) # needs scipy 3.1415926535... - sage: (1/tan(x)).find_root(3, 3.5) + sage: (1/tan(x)).find_root(3, 3.5) # needs scipy Traceback (most recent call last): ... NotImplementedError: Brent's method failed to find a zero for f on the interval An example with a square root:: - sage: f = 1 + x + sqrt(x+2); f.find_root(-2,10) + sage: f = 1 + x + sqrt(x+2); f.find_root(-2,10) # needs scipy -1.618033988749895 Some examples that Ted Kosan came up with:: sage: t = var('t') sage: v = 0.004*(9600*e^(-(1200*t)) - 2400*e^(-(300*t))) - sage: v.find_root(0, 0.002) + sage: v.find_root(0, 0.002) # needs scipy 0.001540327067911417... With this expression, we can see there is a zero very close to the origin:: sage: a = .004*(8*e^(-(300*t)) - 8*e^(-(1200*t)))*(720000*e^(-(300*t)) - 11520000*e^(-(1200*t))) +.004*(9600*e^(-(1200*t)) - 2400*e^(-(300*t)))^2 - sage: show(plot(a, 0, .002), xmin=0, xmax=.002) + sage: show(plot(a, 0, .002), xmin=0, xmax=.002) # needs sage.plot It is easy to approximate with ``find_root``:: - sage: a.find_root(0,0.002) + sage: a.find_root(0,0.002) # needs scipy 0.0004110514049349... Using solve takes more effort, and even then gives @@ -12578,7 +12693,7 @@ cdef class Expression(Expression_abc): sage: x = SR.symbol('x', domain='real') sage: f = (sqrt(x) - I).abs() - sage: f.find_root(-2, 2, rtol=1e-6) # abs tol 1e-6 + sage: f.find_root(-2, 2, rtol=1e-6) # abs tol 1e-6 # needs scipy -1.0000000049668551 """ @@ -12618,9 +12733,9 @@ cdef class Expression(Expression_abc): EXAMPLES:: sage: f = x*cos(x) - sage: f.find_local_maximum(0,5) + sage: f.find_local_maximum(0,5) # needs scipy (0.5610963381910451, 0.8603335890...) - sage: f.find_local_maximum(0,5, tol=0.1, maxfun=10) + sage: f.find_local_maximum(0,5, tol=0.1, maxfun=10) # needs scipy (0.561090323458081..., 0.857926501456...) """ minval, x = (-self).find_local_minimum(a, b, var, tol, @@ -12670,6 +12785,7 @@ cdef class Expression(Expression_abc): EXAMPLES:: + sage: # needs scipy sage: f = x*cos(x) sage: f.find_local_minimum(1, 5) (-3.288371395590..., 3.4256184695...) @@ -12677,7 +12793,7 @@ cdef class Expression(Expression_abc): (-3.288371361890..., 3.4257507903...) sage: f.find_local_minimum(1, 5, tol=1e-2, maxfun=10) (-3.288370845983..., 3.4250840220...) - sage: show(f.plot(0, 20)) + sage: show(f.plot(0, 20)) # needs sage.plot sage: f.find_local_minimum(1, 15) (-9.477294259479..., 9.5293344109...) @@ -12688,7 +12804,7 @@ cdef class Expression(Expression_abc): sage: x = SR.symbol('x', domain='real') sage: f = (x + I).abs() - sage: f.find_local_minimum(-1,1) # abs tol 1e-7 + sage: f.find_local_minimum(-1,1) # abs tol 1e-7 # needs scipy (1.0, 1.6937685757340167e-08) ALGORITHM: @@ -12786,60 +12902,61 @@ cdef class Expression(Expression_abc): This displays a straight line:: - sage: sin(2).plot((x,0,3)) + sage: sin(2).plot((x,0,3)) # needs sage.plot Graphics object consisting of 1 graphics primitive This draws a red oscillatory curve:: - sage: sin(x^2).plot((x,0,2*pi), rgbcolor=(1,0,0)) + sage: sin(x^2).plot((x,0,2*pi), rgbcolor=(1,0,0)) # needs sage.plot Graphics object consisting of 1 graphics primitive Another plot using the variable theta:: sage: var('theta') theta - sage: (cos(theta) - erf(theta)).plot((theta,-2*pi,2*pi)) + sage: (cos(theta) - erf(theta)).plot((theta,-2*pi,2*pi)) # needs sage.plot Graphics object consisting of 1 graphics primitive A very thick green plot with a frame:: - sage: sin(x).plot((x,-4*pi, 4*pi), thickness=20, rgbcolor=(0,0.7,0)).show(frame=True) + sage: sin(x).plot((x, -4*pi, 4*pi), # needs sage.plot + ....: thickness=20, rgbcolor=(0,0.7,0)).show(frame=True) You can embed 2d plots in 3d space as follows:: - sage: plot(sin(x^2), (x,-pi, pi), thickness=2).plot3d(z = 1) # long time + sage: plot(sin(x^2), (x, -pi, pi), thickness=2).plot3d(z=1) # long time, needs sage.plot Graphics3d Object A more complicated family:: - sage: G = sum([plot(sin(n*x), (x,-2*pi, 2*pi)).plot3d(z=n) for n in [0,0.1,..1]]) - sage: G.show(frame_aspect_ratio=[1,1,1/2]) # long time (5s on sage.math, 2012) + sage: G = sum(plot(sin(n*x), (x, -2*pi, 2*pi)).plot3d(z=n) # needs sage.plot + ....: for n in [0,0.1,..1]) + sage: G.show(frame_aspect_ratio=[1,1,1/2]) # long time (5s on sage.math, 2012), needs sage.plot A plot involving the floor function:: - sage: plot(1.0 - x * floor(1/x), (x,0.00001,1.0)) + sage: plot(1.0 - x * floor(1/x), (x,0.00001,1.0)) # needs sage.plot Graphics object consisting of 1 graphics primitive Sage used to allow symbolic functions with "no arguments"; this no longer works:: - sage: plot(2*sin, -4, 4) + sage: plot(2*sin, -4, 4) # needs sage.plot Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for *: 'Integer Ring' and '<class 'sage.functions.trig.Function_sin'>' You should evaluate the function first:: - sage: plot(2*sin(x), -4, 4) + sage: plot(2*sin(x), -4, 4) # needs sage.plot Graphics object consisting of 1 graphics primitive TESTS:: sage: f(x) = x*(1 - x) - sage: plot(f,0,1) + sage: plot(f, 0, 1) # needs sage.plot Graphics object consisting of 1 graphics primitive """ - from sage.symbolic.ring import is_SymbolicVariable from sage.plot.plot import plot # see if the user passed a variable in. @@ -12848,7 +12965,7 @@ cdef class Expression(Expression_abc): else: param = None for i, arg in enumerate(args): - if is_SymbolicVariable(arg): + if isinstance(arg, Expression) and arg.is_symbol(): param = arg args = args[:i] + args[i+1:] break @@ -12865,10 +12982,9 @@ cdef class Expression(Expression_abc): else: A = self.variables() if len(A) == 0: - #Here we handle the case where f is something - #like ``sin``, which has takes arguments which - #aren't explicitly given - n = self.number_of_arguments() + # Here we handle the case where f is something + # like ``sin``, which has takes arguments which + # aren't explicitly given f = self._plot_fast_callable() else: param = A[0] @@ -12895,7 +13011,7 @@ cdef class Expression(Expression_abc): sage: f = s._plot_fast_callable(x) sage: abs(f(10) - abs((I*10+1)^4)) < 1e-11 True - sage: plot(s) + sage: plot(s) # needs sage.plot Graphics object consisting of 1 graphics primitive Check that :trac:`15030` is fixed:: @@ -12903,7 +13019,7 @@ cdef class Expression(Expression_abc): sage: abs(log(x))._plot_fast_callable(x)(-0.2) # abs tol 1e-10 3.52985761682672 sage: f = function('f', evalf_func=lambda self,x,parent: I*x) - sage: plot(abs(f(x)), 0,5) + sage: plot(abs(f(x)), 0,5) # needs sage.plot Graphics object consisting of 1 graphics primitive """ from sage.ext.fast_callable import fast_callable @@ -12915,31 +13031,26 @@ cdef class Expression(Expression_abc): ############ def sum(self, *args, **kwds): r""" - Return the symbolic sum - `\sum_{v = a}^b self` + Return the symbolic sum `\sum_{v = a}^b` ``self`` with respect to the variable `v` with endpoints `a` and `b`. INPUT: - - ``v`` - a variable or variable name + - ``v`` -- a variable or variable name - - ``a`` - lower endpoint of the sum + - ``a`` -- lower endpoint of the sum - - ``b`` - upper endpoint of the sum + - ``b`` -- upper endpoint of the sum - ``algorithm`` - (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) - - - ``'maple'`` - (optional) use Maple - - - ``'mathematica'`` - (optional) use Mathematica - - - ``'giac'`` - (optional) use Giac - - - ``'sympy'`` - use SymPy + - ``'maxima'`` -- use Maxima (the default) + - ``'maple'`` -- (optional) use Maple + - ``'mathematica'`` -- (optional) use Mathematica + - ``'giac'`` -- (optional) use Giac + - ``'sympy'`` -- use SymPy EXAMPLES:: @@ -13100,29 +13211,27 @@ cdef class Expression(Expression_abc): def prod(self, *args, **kwds): r""" + Return the symbolic product `\prod_{v = a}^b` ``self``. - Return the symbolic product `\prod_{v = a}^b expression` with - respect to the variable `v` with endpoints `a` and `b`. + This is the product respect to the variable `v` with endpoints `a` and `b`. INPUT: - - ``expression`` - a symbolic expression - - - ``v`` - a variable or variable name + - ``expression`` -- a symbolic expression - - ``a`` - lower endpoint of the product + - ``v`` -- a variable or variable name - - ``b`` - upper endpoint of the product + - ``a`` -- lower endpoint of the product - - ``algorithm`` - (default: ``'maxima'``) one of - - - ``'maxima'`` - use Maxima (the default) + - ``b`` -- upper endpoint of the product - - ``'giac'`` - (optional) use Giac + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'sympy'`` - use SymPy + - ``'maxima'`` -- use Maxima (the default) + - ``'giac'`` -- (optional) use Giac + - ``'sympy'`` -- use SymPy - - ``hold`` - (default: ``False``) if ``True`` don't evaluate + - ``hold`` -- (default: ``False``) if ``True``, don't evaluate TESTS: @@ -13149,8 +13258,9 @@ cdef class Expression(Expression_abc): def integral(self, *args, **kwds): """ - Compute the integral of self. Please see - :func:`sage.symbolic.integration.integral.integrate` for more details. + Compute the integral of ``self``. + + Please see :func:`sage.symbolic.integration.integral.integrate` for more details. EXAMPLES:: @@ -13195,6 +13305,7 @@ cdef class Expression(Expression_abc): integral, _normalize_integral_input R = self._parent if isinstance(R, sage.rings.abc.CallableSymbolicExpressionRing): + from sage.symbolic.ring import SR f = SR(self) f, v, a, b = _normalize_integral_input(f, *args) # Definite integral with respect to a positional variable. @@ -13214,8 +13325,9 @@ cdef class Expression(Expression_abc): def nintegral(self, *args, **kwds): """ - Compute the numerical integral of self. Please see - :obj:`sage.calculus.calculus.nintegral` for more details. + Compute the numerical integral of ``self``. + + Please see :obj:`sage.calculus.calculus.nintegral` for more details. EXAMPLES:: @@ -13248,8 +13360,9 @@ cdef class Expression(Expression_abc): def limit(self, *args, **kwds): """ - Return a symbolic limit. See - :obj:`sage.calculus.calculus.limit` + Return a symbolic limit. + + See :obj:`sage.calculus.calculus.limit` EXAMPLES:: @@ -13261,8 +13374,9 @@ cdef class Expression(Expression_abc): def laplace(self, t, s): """ - Return Laplace transform of self. See - :obj:`sage.calculus.calculus.laplace` + Return Laplace transform of ``self``. + + See :obj:`sage.calculus.calculus.laplace` EXAMPLES:: @@ -13276,8 +13390,9 @@ cdef class Expression(Expression_abc): def inverse_laplace(self, t, s): """ - Return inverse Laplace transform of self. See - :obj:`sage.calculus.calculus.inverse_laplace` + Return inverse Laplace transform of ``self``. + + See :obj:`sage.calculus.calculus.inverse_laplace` EXAMPLES:: @@ -13291,7 +13406,7 @@ cdef class Expression(Expression_abc): def add_to_both_sides(self, x): """ - Return a relation obtained by adding *x* to both sides of + Return a relation obtained by adding ``x`` to both sides of this relation. EXAMPLES:: @@ -13310,7 +13425,7 @@ cdef class Expression(Expression_abc): def subtract_from_both_sides(self, x): """ - Return a relation obtained by subtracting *x* from both sides + Return a relation obtained by subtracting ``x`` from both sides of this relation. EXAMPLES:: @@ -13328,7 +13443,7 @@ cdef class Expression(Expression_abc): def multiply_both_sides(self, x, checksign=None): """ Return a relation obtained by multiplying both sides of this - relation by *x*. + relation by ``x``. .. NOTE:: @@ -13377,11 +13492,11 @@ cdef class Expression(Expression_abc): def divide_both_sides(self, x, checksign=None): """ Return a relation obtained by dividing both sides of this - relation by *x*. + relation by ``x``. .. NOTE:: - The *checksign* keyword argument is currently ignored and + The ``checksign`` keyword argument is currently ignored and is included for backward compatibility reasons only. EXAMPLES:: @@ -13401,16 +13516,15 @@ cdef class Expression(Expression_abc): def implicit_derivative(self, Y, X, n=1): """ - Return the n'th derivative of Y with respect to X given implicitly by this expression. + Return the `n`-th derivative of `Y` with respect to `X` given implicitly by this expression. INPUT: - - ``Y`` - The dependent variable of the implicit expression. + - ``Y`` -- The dependent variable of the implicit expression. - - ``X`` - The independent variable with respect to which the derivative is taken. + - ``X`` -- The independent variable with respect to which the derivative is taken. - - - ``n`` - (default : 1) the order of the derivative. + - ``n`` -- (default: 1) the order of the derivative. EXAMPLES:: @@ -13502,20 +13616,20 @@ def solve_diophantine(f, *args, **kwds): The argument, if not given as symbolic equation, is set equal to zero. It can be given in any form that can be converted to symbolic. Please - see :meth:`Expression.solve_diophantine()` for a detailed + see :meth:`Expression.solve_diophantine` for a detailed synopsis. EXAMPLES:: sage: R.<a,b> = PolynomialRing(ZZ); R Multivariate Polynomial Ring in a, b over Integer Ring - sage: solve_diophantine(a^2-3*b^2+1) + sage: solve_diophantine(a^2 - 3*b^2 + 1) [] - sage: sorted(solve_diophantine(a^2-3*b^2+2), key=str) + sage: sorted(solve_diophantine(a^2 - 3*b^2 + 2), key=str) [(-1/2*sqrt(3)*(sqrt(3) + 2)^t + 1/2*sqrt(3)*(-sqrt(3) + 2)^t - 1/2*(sqrt(3) + 2)^t - 1/2*(-sqrt(3) + 2)^t, -1/6*sqrt(3)*(sqrt(3) + 2)^t + 1/6*sqrt(3)*(-sqrt(3) + 2)^t - 1/2*(sqrt(3) + 2)^t - 1/2*(-sqrt(3) + 2)^t), - (1/2*sqrt(3)*(sqrt(3) + 2)^t - 1/2*sqrt(3)*(-sqrt(3) + 2)^t + 1/2*(sqrt(3) + 2)^t + 1/2*(-sqrt(3) + 2)^t, - 1/6*sqrt(3)*(sqrt(3) + 2)^t - 1/6*sqrt(3)*(-sqrt(3) + 2)^t + 1/2*(sqrt(3) + 2)^t + 1/2*(-sqrt(3) + 2)^t)] + (1/2*sqrt(3)*(sqrt(3) + 2)^t - 1/2*sqrt(3)*(-sqrt(3) + 2)^t + 1/2*(sqrt(3) + 2)^t + 1/2*(-sqrt(3) + 2)^t, + 1/6*sqrt(3)*(sqrt(3) + 2)^t - 1/6*sqrt(3)*(-sqrt(3) + 2)^t + 1/2*(sqrt(3) + 2)^t + 1/2*(-sqrt(3) + 2)^t)] """ from sage.symbolic.ring import SR @@ -13656,7 +13770,6 @@ cdef get_dynamic_class_for_function(unsigned serial): cdef Expression new_Expression_from_GEx(parent, GEx juice): cdef type cls cdef Expression nex - cdef unsigned serial if is_exactly_a_function(juice): # if the function defines any dynamic methods these are made # available through a dynamic class @@ -13684,8 +13797,8 @@ cpdef new_Expression(parent, x): <class 'sage.symbolic.expression.Expression'> sage: a.parent() Symbolic Ring - sage: K.<a> = QuadraticField(-3) - sage: a + sin(x) + sage: K.<a> = QuadraticField(-3) # needs sage.rings.number_field + sage: a + sin(x) # needs sage.rings.number_field I*sqrt(3) + sin(x) sage: x = var('x'); y0,y1 = PolynomialRing(ZZ,2,'y').gens() sage: x+y0/y1 @@ -13740,6 +13853,8 @@ cpdef new_Expression(parent, x): exp = x elif isinstance(x, Factorization): from sage.misc.misc_c import prod + from sage.symbolic.ring import SR + return prod([SR(p)**e for p,e in x], SR(x.unit())) elif x in Sets(): from sage.rings.integer_ring import ZZ @@ -13815,9 +13930,10 @@ cpdef new_Expression_from_pyobject(parent, x, bint force=True, bint recursive=Tr # tuples can be packed into exprseq if isinstance(x, (tuple, list)): + from sage.symbolic.ring import SR for e in x: obj = SR._force_pyobject(e, force=(not recursive)) - ex_v.push_back( (<Expression>obj)._gobj ) + ex_v.push_back((<Expression>obj)._gobj) ex_seq = GExprSeq(ex_v) @@ -13910,12 +14026,12 @@ cpdef new_Expression_symbol(parent, name=None, latex_name=None, domain=None): return e - else: # initialize a new symbol + else: # initialize a new symbol # Construct expression e = <Expression>Expression.__new__(Expression) e._parent = parent - if name is None: # Check if we need a temporary anonymous new symbol + if name is None: # Check if we need a temporary anonymous new symbol symb = ginac_new_symbol() name = symb.get_name().decode('ascii') if domain is not None: @@ -14025,7 +14141,7 @@ cdef inline ExpressionIterator new_ExpIter_from_Expression(Expression ex): cdef ExpressionIterator m = <ExpressionIterator>ExpressionIterator.__new__(ExpressionIterator) m._ex = ex m._ind = 0 - m._len = ex._gobj.nops() + m._len = ex._gobj.nops() return m diff --git a/src/sage/symbolic/expression_conversion_algebraic.py b/src/sage/symbolic/expression_conversion_algebraic.py new file mode 100644 index 00000000000..f1b30784598 --- /dev/null +++ b/src/sage/symbolic/expression_conversion_algebraic.py @@ -0,0 +1,306 @@ +r""" +Conversion of symbolic expressions to algebraic numbers +""" +# **************************************************************************** +# Copyright (C) 2009-2012 Mike Hansen +# 2015-2018 Ralf Stephan +# 2015 Nils Bruin +# 2017 Jeroen Demeyer +# 2019-2022 Frรฉdรฉric Chapoton +# 2021 Dave Witte Morris +# 2023 Vincent Delecroix +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from operator import eq, ne, gt, lt, ge, le, mul, pow, neg, add, truediv +from functools import reduce + +import sage.rings.abc + +from sage.functions.all import exp +from sage.symbolic.expression_conversions import Converter +from sage.symbolic.operators import add_vararg, mul_vararg +from sage.symbolic.ring import SR + + +############# +# Algebraic # +############# +class AlgebraicConverter(Converter): + def __init__(self, field): + """ + EXAMPLES:: + + sage: from sage.symbolic.expression_conversions import AlgebraicConverter + sage: a = AlgebraicConverter(QQbar) + sage: a.field + Algebraic Field + sage: a.reciprocal_trig_functions['cot'] + tan + """ + self.field = field + + from sage.functions.all import reciprocal_trig_functions + self.reciprocal_trig_functions = reciprocal_trig_functions + + def pyobject(self, ex, obj): + """ + EXAMPLES:: + + sage: from sage.symbolic.expression_conversions import AlgebraicConverter + sage: a = AlgebraicConverter(QQbar) + sage: f = SR(2) + sage: a.pyobject(f, f.pyobject()) + 2 + sage: _.parent() + Algebraic Field + """ + return self.field(obj) + + def arithmetic(self, ex, operator): + """ + Convert a symbolic expression to an algebraic number. + + EXAMPLES:: + + sage: from sage.symbolic.expression_conversions import AlgebraicConverter + sage: f = 2^(1/2) + sage: a = AlgebraicConverter(QQbar) + sage: a.arithmetic(f, f.operator()) + 1.414213562373095? + + TESTS:: + + sage: f = pi^6 + sage: a = AlgebraicConverter(QQbar) + sage: a.arithmetic(f, f.operator()) + Traceback (most recent call last): + ... + TypeError: unable to convert pi^6 to Algebraic Field + + Test that :trac:`14602` is fixed:: + + sage: K = QuadraticField(3) + sage: K(sqrt(3)).parent() is K + True + sage: sqrt(K(3)).parent() is K + True + sage: (K(3)^(1/2)).parent() + Symbolic Ring + sage: bool(K.gen() == K(3)^(1/2) == sqrt(K(3)) == K(sqrt(3)) == sqrt(3)) + True + sage: L = QuadraticField(3, embedding=-AA(3).sqrt()) + sage: bool(L.gen() == -sqrt(3)) + True + """ + # We try to avoid simplifying, because maxima's simplify command + # can change the value of a radical expression (by changing which + # root is selected). + try: + if operator is pow: + from sage.rings.rational import Rational + base, expt = ex.operands() + base = self.field(base) + expt = Rational(expt) + return self.field(base**expt) + else: + if operator is add_vararg: + operator = add + elif operator is mul_vararg: + operator = mul + return reduce(operator, map(self, ex.operands())) + except TypeError: + pass + + if operator is pow: + from sage.symbolic.constants import e, pi, I + from sage.rings.rational_field import QQ + + base, expt = ex.operands() + if base == e and expt / (pi * I) in QQ: + return exp(expt)._algebraic_(self.field) + + raise TypeError("unable to convert %r to %s" % (ex, self.field)) + + def composition(self, ex, operator): + """ + Coerce to an algebraic number. + + EXAMPLES:: + + sage: from sage.symbolic.expression_conversions import AlgebraicConverter + sage: a = AlgebraicConverter(QQbar) + sage: a.composition(exp(I*pi/3, hold=True), exp) + 0.500000000000000? + 0.866025403784439?*I + sage: a.composition(sin(pi/7), sin) + 0.4338837391175581? + 0.?e-18*I + + sage: x = SR.var('x') + sage: a.composition(complex_root_of(x^3 - x^2 - x - 1, 0), complex_root_of) + 1.839286755214161? + sage: a.composition(complex_root_of(x^5 - 1, 3), complex_root_of) + 0.3090169943749474? - 0.9510565162951536?*I + sage: a.composition(complex_root_of(x^2 + 1, 0), complex_root_of) + 1.?e-684 - 0.9999999999999999?*I + sage: a.composition(complex_root_of(x^2 + 1, 1), complex_root_of) + 1.?e-684 + 0.9999999999999999?*I + + TESTS:: + + sage: QQbar(zeta(7)) + Traceback (most recent call last): + ... + TypeError: unable to convert zeta(7) to Algebraic Field + + Test :trac:`22571`:: + + sage: a.composition(exp(0, hold=True), exp) + 1 + sage: a.composition(exp(1, hold=True), exp) + Traceback (most recent call last): + ... + ValueError: unable to represent as an algebraic number + sage: a.composition(exp(pi*I*RR(1), hold=True), exp) + Traceback (most recent call last): + ... + TypeError: unable to convert e^(1.00000000000000*I*pi) to Algebraic Field + sage: a.composition(exp(pi*CC.gen(), hold=True), exp) + Traceback (most recent call last): + ... + TypeError: unable to convert e^(1.00000000000000*I*pi) to Algebraic Field + sage: bool(sin(pi*RR("0.7000000000000002")) > 0) + True + + Check that :trac:`24440` is fixed:: + + sage: QQbar(tanh(pi + 0.1)) + Traceback (most recent call last): + ... + ValueError: unable to represent as an algebraic number + sage: QQbar(sin(I*pi/7)) + Traceback (most recent call last): + ... + ValueError: unable to represent as an algebraic number + sage: QQbar(sin(I*pi/7, hold=True)) + Traceback (most recent call last): + ... + ValueError: unable to represent as an algebraic number + """ + func = operator + operands = ex.operands() + if len(operands) == 1: + operand = operands[0] + else: + operand = None + + if isinstance(self.field, sage.rings.abc.UniversalCyclotomicField): + QQbar = self.field + hold = True + else: + QQbar = self.field.algebraic_closure() + hold = False + + zeta = QQbar.zeta + # Note that comparing functions themselves goes via maxima, and is SLOW + func_name = repr(func) + if func_name == 'exp': + if operand.is_trivial_zero(): + return self.field.one() + if not (SR(-1).sqrt() * operand).is_real(): + raise ValueError("unable to represent as an algebraic number") + # Coerce (not convert, see #22571) arg to a rational + from sage.rings.rational_field import QQ + arg = operand.imag()/(2*ex.parent().pi()) + try: + rat_arg = QQ.coerce(arg.pyobject()) + except TypeError: + raise TypeError("unable to convert %r to %s" % (ex, self.field)) + res = zeta(rat_arg.denom())**rat_arg.numer() + return self.field(res) + elif func_name in ['sin', 'cos', 'tan']: + exp_ia = exp(SR(-1).sqrt() * operand, hold=hold)._algebraic_(QQbar) + if func_name == 'sin': + res = (exp_ia - ~exp_ia) / (2 * zeta(4)) + elif func_name == 'cos': + res = (exp_ia + ~exp_ia) / 2 + else: + res = -zeta(4) * (exp_ia - ~exp_ia) / (exp_ia + ~exp_ia) + return self.field(res) + elif func_name in ['sinh', 'cosh', 'tanh']: + if not (SR(-1).sqrt()*operand).is_real(): + raise ValueError("unable to represent as an algebraic number") + exp_a = exp(operand, hold=hold)._algebraic_(QQbar) + if func_name == 'sinh': + res = (exp_a - ~exp_a) / 2 + elif func_name == 'cosh': + res = (exp_a + ~exp_a) / 2 + else: + res = (exp_a - ~exp_a) / (exp_a + ~exp_a) + return self.field(res) + elif func_name in self.reciprocal_trig_functions: + res = ~self.reciprocal_trig_functions[func_name](operand)._algebraic_(QQbar) + return self.field(res) + elif func_name == 'complex_root_of': + cr = ex._sympy_() + poly = cr.poly._sage_() + interval = cr._get_interval()._sage_() + return self.field.polynomial_root(poly, interval) + elif operand is not None: + res = func(operand._algebraic_(self.field)) + # We have to handle the case where we get the same symbolic + # expression back. For example, QQbar(zeta(7)). See + # issue #12665. + if (res - ex).is_trivial_zero(): + raise TypeError("unable to convert %r to %s" % (ex, self.field)) + return self.field(res) + + raise ValueError("unable to represent as an algebraic number") + + +def algebraic(ex, field): + """ + Returns the symbolic expression *ex* as a element of the algebraic + field *field*. + + EXAMPLES:: + + sage: a = SR(5/6) + sage: AA(a) + 5/6 + sage: type(AA(a)) + <class 'sage.rings.qqbar.AlgebraicReal'> + sage: QQbar(a) + 5/6 + sage: type(QQbar(a)) + <class 'sage.rings.qqbar.AlgebraicNumber'> + sage: QQbar(i) + I + sage: AA(golden_ratio) + 1.618033988749895? + sage: QQbar(golden_ratio) + 1.618033988749895? + sage: QQbar(sin(pi/3)) + 0.866025403784439? + + sage: QQbar(sqrt(2) + sqrt(8)) + 4.242640687119285? + sage: AA(sqrt(2) ^ 4) == 4 + True + sage: AA(-golden_ratio) + -1.618033988749895? + sage: QQbar((2*SR(I))^(1/2)) + 1 + 1*I + sage: QQbar(e^(pi*I/3)) + 0.50000000000000000? + 0.866025403784439?*I + + sage: AA(x*sin(0)) + 0 + sage: QQbar(x*sin(0)) + 0 + """ + return AlgebraicConverter(field)(ex) diff --git a/src/sage/symbolic/expression_conversion_sympy.py b/src/sage/symbolic/expression_conversion_sympy.py new file mode 100644 index 00000000000..4a3b1556ce1 --- /dev/null +++ b/src/sage/symbolic/expression_conversion_sympy.py @@ -0,0 +1,317 @@ +# sage.doctest: needs sympy +r""" +Conversion of symbolic expressions to SymPy +""" +# **************************************************************************** +# Copyright (C) 2009 Mike Hansen +# 2011 D. S. McNeil +# 2011 Francois Bissey +# 2017 Ralf Stephan +# 2017 Marco Mancini +# 2017 Travis Scrimshaw +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from operator import eq, ne, gt, lt, ge, le, mul, pow, neg, add, truediv + +from sage.structure.element import Expression +from sage.symbolic.expression_conversions import Converter +from sage.symbolic.operators import arithmetic_operators + +######### +# Sympy # +######### +class SympyConverter(Converter): + """ + Converts any expression to SymPy. + + EXAMPLES:: + + sage: import sympy + sage: var('x,y') + (x, y) + sage: f = exp(x^2) - arcsin(pi+x)/y + sage: f._sympy_() + exp(x**2) - asin(x + pi)/y + sage: _._sage_() + -arcsin(pi + x)/y + e^(x^2) + + sage: sympy.sympify(x) # indirect doctest + x + + TESTS: + + Make sure we can convert I (:trac:`6424`):: + + sage: bool(I._sympy_() == I) + True + sage: (x+I)._sympy_() + x + I + + """ + def __init__(self): + """ + TESTS:: + + sage: from sage.symbolic.expression_conversions import SympyConverter + sage: s = SympyConverter() # indirect doctest + sage: TestSuite(s).run(skip="_test_pickling") + """ + from sage.interfaces.sympy import sympy_init + sympy_init() + + def __call__(self, ex=None): + """ + EXAMPLES:: + + sage: from sage.symbolic.expression_conversions import SympyConverter + sage: s = SympyConverter() + sage: f(x, y) = x^2 + y^2; f + (x, y) |--> x^2 + y^2 + sage: s(f) + Lambda((x, y), x**2 + y**2) + """ + if isinstance(ex, Expression) and ex.is_callable(): + from sympy import Symbol, Lambda + return Lambda(tuple(Symbol(str(arg)) for arg in ex.arguments()), + super().__call__(ex)) + return super().__call__(ex) + + def pyobject(self, ex, obj): + """ + EXAMPLES:: + + sage: from sage.symbolic.expression_conversions import SympyConverter + sage: s = SympyConverter() + sage: f = SR(2) + sage: s.pyobject(f, f.pyobject()) + 2 + sage: type(_) + <class 'sympy.core.numbers.Integer'> + """ + try: + return obj._sympy_() + except AttributeError: + return obj + + def arithmetic(self, ex, operator): + """ + EXAMPLES:: + + sage: from sage.symbolic.expression_conversions import SympyConverter + sage: s = SympyConverter() + sage: f = x + 2 + sage: s.arithmetic(f, f.operator()) + x + 2 + """ + import sympy + operator = arithmetic_operators[operator] + ops = [sympy.sympify(self(a), evaluate=False) for a in ex.operands()] + if operator == "+": + return sympy.Add(*ops) + elif operator == "*": + return sympy.Mul(*ops) + elif operator == "-": + return sympy.Sub(*ops) + elif operator == "/": + return sympy.Div(*ops) + elif operator == "^": + return sympy.Pow(*ops) + else: + raise NotImplementedError + + def symbol(self, ex): + """ + EXAMPLES:: + + sage: + sage: from sage.symbolic.expression_conversions import SympyConverter + sage: s = SympyConverter() + sage: s.symbol(x) + x + sage: type(_) + <class 'sympy.core.symbol.Symbol'> + """ + import sympy + return sympy.symbols(repr(ex)) + + def relation(self, ex, op): + """ + EXAMPLES:: + + sage: + sage: import operator + sage: from sage.symbolic.expression_conversions import SympyConverter + sage: s = SympyConverter() + sage: s.relation(x == 3, operator.eq) + Eq(x, 3) + sage: s.relation(pi < 3, operator.lt) + pi < 3 + sage: s.relation(x != pi, operator.ne) + Ne(x, pi) + sage: s.relation(x > 0, operator.gt) + x > 0 + """ + from sympy import Eq, Ne, Gt, Lt, Ge, Le + ops = {eq: Eq, ne: Ne, gt: Gt, lt: Lt, ge: Ge, le: Le} + return ops.get(op)(self(ex.lhs()), self(ex.rhs()), evaluate=False) + + def composition(self, ex, operator): + """ + EXAMPLES:: + + sage: from sage.symbolic.expression_conversions import SympyConverter + sage: s = SympyConverter() + sage: f = sin(2) + sage: s.composition(f, f.operator()) + sin(2) + sage: type(_) + sin + sage: f = arcsin(2) + sage: s.composition(f, f.operator()) + asin(2) + """ + g = ex.operands() + try: + return operator._sympy_(*g) + except (AttributeError, TypeError): + pass + f = operator._sympy_init_() + import sympy + + f_sympy = getattr(sympy, f, None) + if f_sympy: + return f_sympy(*sympy.sympify(g, evaluate=False)) + else: + return sympy.Function(str(f))(*g, evaluate=False) + + def tuple(self, ex): + """ + Conversion of tuples. + + EXAMPLES:: + + sage: t = SR._force_pyobject((3, 4, e^x)) + sage: t._sympy_() + (3, 4, e^x) + sage: t = SR._force_pyobject((cos(x),)) + sage: t._sympy_() + (cos(x),) + + TESTS:: + + sage: from sage.symbolic.expression_conversions import sympy_converter + sage: F = hypergeometric([1/3,2/3],[1,1],x) + sage: F._sympy_() + hyper((1/3, 2/3), (1, 1), x) + + sage: F = hypergeometric([1/3,2/3],[1],x) + sage: F._sympy_() + hyper((1/3, 2/3), (1,), x) + + sage: var('a,b,c,d') + (a, b, c, d) + sage: hypergeometric((a,b,),(c,),d)._sympy_() + hyper((a, b), (c,), d) + """ + return tuple(ex.operands()) + + def derivative(self, ex, operator): + """ + Convert the derivative of ``self`` in sympy. + + INPUT: + + - ``ex`` -- a symbolic expression + + - ``operator`` -- operator + + TESTS:: + + sage: var('x','y') + (x, y) + + sage: f_sage = function('f_sage')(x, y) + sage: f_sympy = f_sage._sympy_() + + sage: df_sage = f_sage.diff(x, 2, y, 1); df_sage + diff(f_sage(x, y), x, x, y) + sage: df_sympy = df_sage._sympy_(); df_sympy + Derivative(f_sage(x, y), (x, 2), y) + sage: df_sympy == f_sympy.diff(x, 2, y, 1) + True + + Check that :trac:`28964` is fixed:: + + sage: f = function('f') + sage: _ = var('x,t') + sage: diff(f(x, t), x)._sympy_(), diff(f(x, t), t)._sympy_() + (Derivative(f(x, t), x), Derivative(f(x, t), t)) + + Check differentiating by variables with multiple occurrences + (:trac:`28964`):: + + sage: f = function('f') + sage: _ = var('x1,x2,x3,x,t') + sage: f(x, x, t).diff(x)._sympy_()._sage_() + D[0](f)(x, x, t) + D[1](f)(x, x, t) + + sage: g = f(x1, x2, x3, t).diff(x1, 2, x2).subs(x1==x, x2==x, x3==x); g + D[0, 0, 1](f)(x, x, x, t) + sage: g._sympy_() + Subs(Derivative(f(_xi_1, _xi_2, x, t), (_xi_1, 2), _xi_2), + (_xi_1, _xi_2), (x, x)) + sage: assert g._sympy_()._sage_() == g + + Check that the use of dummy variables does not cause a collision:: + + sage: f = function('f') + sage: _ = var('x1,x2,x,xi_1') + sage: g = f(x1, x2, xi_1).diff(x1).subs(x1==x, x2==x); g + D[0](f)(x, x, xi_1) + sage: assert g._sympy_()._sage_() == g + """ + import sympy + + # retrieve derivated function + f = operator.function() + + # retrieve order + order = operator._parameter_set + # arguments + _args = [a._sympy_() for a in ex.operands()] + + # when differentiating by a variable that occurs multiple times, + # substitute it by a dummy variable + subs_new = [] + subs_old = [] + sympy_arg = [] + for idx in order: + a = _args[idx] + if _args.count(a) > 1: + D = sympy.Dummy('xi_%i' % (idx + 1)) + # to avoid collisions with ordinary symbols when converting + # back to Sage, we pick an unused variable name for the dummy + while D._sage_() in ex.variables(): + D = sympy.Dummy(D.name + '_0') + subs_old.append(a) + subs_new.append(D) + _args[idx] = D + sympy_arg.append(D) + else: + sympy_arg.append(a) + + f_sympy = f._sympy_()(*_args) + result = f_sympy.diff(*sympy_arg) + if subs_new: + return sympy.Subs(result, subs_new, subs_old) + else: + return result + + +sympy_converter = SympyConverter() diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index 8b121771867..2f44dd34a3e 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -18,14 +18,19 @@ from operator import eq, ne, gt, lt, ge, le, mul, pow, neg, add, truediv from functools import reduce -from sage.rings.rational_field import QQ +import sage.rings.abc + +from sage.misc.lazy_import import lazy_import from sage.symbolic.ring import SR from sage.structure.element import Expression from sage.functions.all import exp from sage.symbolic.operators import arithmetic_operators, relation_operators, FDerivativeOperator, add_vararg, mul_vararg -from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_gaussian +from sage.rings.number_field.number_field_element_base import NumberFieldElement_base from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField +lazy_import('sage.symbolic.expression_conversion_sympy', ['SympyConverter', 'sympy_converter']) +lazy_import('sage.symbolic.expression_conversion_algebraic', ['AlgebraicConverter', 'algebraic']) + class FakeExpression(): r""" @@ -441,9 +446,10 @@ def pyobject(self, ex, obj): sage: ii.pyobject(pi, pi.pyobject()) 'Pi' """ - if (self.interface.name() in ['pari', 'gp'] and - isinstance(obj, NumberFieldElement_gaussian)): - return repr(obj) + if (self.interface.name() in ['pari', 'gp'] and isinstance(obj, NumberFieldElement_base)): + from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_gaussian + if isinstance(obj, NumberFieldElement_gaussian): + return repr(obj) try: return getattr(obj, self.name_init)() except AttributeError: @@ -578,12 +584,11 @@ def derivative(self, ex, operator): """ # This code should probably be moved into the interface # object in a nice way. - from sage.symbolic.ring import is_SymbolicVariable if self.name_init != "_maxima_init_": raise NotImplementedError args = ex.operands() - if (not all(is_SymbolicVariable(v) for v in args) or - len(args) != len(set(args))): + if (not all(isinstance(v, Expression) and v.is_symbol() for v in args) or + len(args) != len(set(args))): # An evaluated derivative of the form f'(1) is not a # symbolic variable, yet we would like to treat it like # one. So, we replace the argument `1` with a temporary @@ -652,298 +657,6 @@ def composition(self, ex, operator): return self.interface._function_call_string(op, ops, []) -######### -# Sympy # -######### -class SympyConverter(Converter): - """ - Converts any expression to SymPy. - - EXAMPLES:: - - sage: import sympy - sage: var('x,y') - (x, y) - sage: f = exp(x^2) - arcsin(pi+x)/y - sage: f._sympy_() - exp(x**2) - asin(x + pi)/y - sage: _._sage_() - -arcsin(pi + x)/y + e^(x^2) - - sage: sympy.sympify(x) # indirect doctest - x - - TESTS: - - Make sure we can convert I (:trac:`6424`):: - - sage: bool(I._sympy_() == I) - True - sage: (x+I)._sympy_() - x + I - - """ - def __init__(self): - """ - TESTS:: - - sage: from sage.symbolic.expression_conversions import SympyConverter - sage: s = SympyConverter() # indirect doctest - sage: TestSuite(s).run(skip="_test_pickling") - """ - from sage.interfaces.sympy import sympy_init - sympy_init() - - def __call__(self, ex=None): - """ - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import SympyConverter - sage: s = SympyConverter() - sage: f(x, y) = x^2 + y^2; f - (x, y) |--> x^2 + y^2 - sage: s(f) - Lambda((x, y), x**2 + y**2) - """ - if isinstance(ex, Expression) and ex.is_callable(): - from sympy import Symbol, Lambda - return Lambda(tuple(Symbol(str(arg)) for arg in ex.arguments()), - super().__call__(ex)) - return super().__call__(ex) - - def pyobject(self, ex, obj): - """ - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import SympyConverter - sage: s = SympyConverter() - sage: f = SR(2) - sage: s.pyobject(f, f.pyobject()) - 2 - sage: type(_) - <class 'sympy.core.numbers.Integer'> - """ - try: - return obj._sympy_() - except AttributeError: - return obj - - def arithmetic(self, ex, operator): - """ - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import SympyConverter - sage: s = SympyConverter() - sage: f = x + 2 - sage: s.arithmetic(f, f.operator()) - x + 2 - """ - import sympy - operator = arithmetic_operators[operator] - ops = [sympy.sympify(self(a), evaluate=False) for a in ex.operands()] - if operator == "+": - return sympy.Add(*ops) - elif operator == "*": - return sympy.Mul(*ops) - elif operator == "-": - return sympy.Sub(*ops) - elif operator == "/": - return sympy.Div(*ops) - elif operator == "^": - return sympy.Pow(*ops) - else: - raise NotImplementedError - - def symbol(self, ex): - """ - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import SympyConverter - sage: s = SympyConverter() - sage: s.symbol(x) - x - sage: type(_) - <class 'sympy.core.symbol.Symbol'> - """ - import sympy - return sympy.symbols(repr(ex)) - - def relation(self, ex, op): - """ - EXAMPLES:: - - sage: import operator - sage: from sage.symbolic.expression_conversions import SympyConverter - sage: s = SympyConverter() - sage: s.relation(x == 3, operator.eq) - Eq(x, 3) - sage: s.relation(pi < 3, operator.lt) - pi < 3 - sage: s.relation(x != pi, operator.ne) - Ne(x, pi) - sage: s.relation(x > 0, operator.gt) - x > 0 - """ - from sympy import Eq, Ne, Gt, Lt, Ge, Le - ops = {eq: Eq, ne: Ne, gt: Gt, lt: Lt, ge: Ge, le: Le} - return ops.get(op)(self(ex.lhs()), self(ex.rhs()), evaluate=False) - - def composition(self, ex, operator): - """ - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import SympyConverter - sage: s = SympyConverter() - sage: f = sin(2) - sage: s.composition(f, f.operator()) - sin(2) - sage: type(_) - sin - sage: f = arcsin(2) - sage: s.composition(f, f.operator()) - asin(2) - """ - g = ex.operands() - try: - return operator._sympy_(*g) - except (AttributeError, TypeError): - pass - f = operator._sympy_init_() - import sympy - - f_sympy = getattr(sympy, f, None) - if f_sympy: - return f_sympy(*sympy.sympify(g, evaluate=False)) - else: - return sympy.Function(str(f))(*g, evaluate=False) - - def tuple(self, ex): - """ - Conversion of tuples. - - EXAMPLES:: - - sage: t = SR._force_pyobject((3, 4, e^x)) - sage: t._sympy_() - (3, 4, e^x) - sage: t = SR._force_pyobject((cos(x),)) - sage: t._sympy_() - (cos(x),) - - TESTS:: - - sage: from sage.symbolic.expression_conversions import sympy_converter - sage: F = hypergeometric([1/3,2/3],[1,1],x) - sage: F._sympy_() - hyper((1/3, 2/3), (1, 1), x) - - sage: F = hypergeometric([1/3,2/3],[1],x) - sage: F._sympy_() - hyper((1/3, 2/3), (1,), x) - - sage: var('a,b,c,d') - (a, b, c, d) - sage: hypergeometric((a,b,),(c,),d)._sympy_() - hyper((a, b), (c,), d) - """ - return tuple(ex.operands()) - - def derivative(self, ex, operator): - """ - Convert the derivative of ``self`` in sympy. - - INPUT: - - - ``ex`` -- a symbolic expression - - - ``operator`` -- operator - - TESTS:: - - sage: var('x','y') - (x, y) - - sage: f_sage = function('f_sage')(x, y) - sage: f_sympy = f_sage._sympy_() - - sage: df_sage = f_sage.diff(x, 2, y, 1); df_sage - diff(f_sage(x, y), x, x, y) - sage: df_sympy = df_sage._sympy_(); df_sympy - Derivative(f_sage(x, y), (x, 2), y) - sage: df_sympy == f_sympy.diff(x, 2, y, 1) - True - - Check that :trac:`28964` is fixed:: - - sage: f = function('f') - sage: _ = var('x,t') - sage: diff(f(x, t), x)._sympy_(), diff(f(x, t), t)._sympy_() - (Derivative(f(x, t), x), Derivative(f(x, t), t)) - - Check differentiating by variables with multiple occurrences - (:trac:`28964`):: - - sage: f = function('f') - sage: _ = var('x1,x2,x3,x,t') - sage: f(x, x, t).diff(x)._sympy_()._sage_() - D[0](f)(x, x, t) + D[1](f)(x, x, t) - - sage: g = f(x1, x2, x3, t).diff(x1, 2, x2).subs(x1==x, x2==x, x3==x); g - D[0, 0, 1](f)(x, x, x, t) - sage: g._sympy_() - Subs(Derivative(f(_xi_1, _xi_2, x, t), (_xi_1, 2), _xi_2), - (_xi_1, _xi_2), (x, x)) - sage: assert g._sympy_()._sage_() == g - - Check that the use of dummy variables does not cause a collision:: - - sage: f = function('f') - sage: _ = var('x1,x2,x,xi_1') - sage: g = f(x1, x2, xi_1).diff(x1).subs(x1==x, x2==x); g - D[0](f)(x, x, xi_1) - sage: assert g._sympy_()._sage_() == g - """ - import sympy - - # retrieve derivated function - f = operator.function() - - # retrieve order - order = operator._parameter_set - # arguments - _args = [a._sympy_() for a in ex.operands()] - - # when differentiating by a variable that occurs multiple times, - # substitute it by a dummy variable - subs_new = [] - subs_old = [] - sympy_arg = [] - for idx in order: - a = _args[idx] - if _args.count(a) > 1: - D = sympy.Dummy('xi_%i' % (idx + 1)) - # to avoid collisions with ordinary symbols when converting - # back to Sage, we pick an unused variable name for the dummy - while D._sage_() in ex.variables(): - D = sympy.Dummy(D.name + '_0') - subs_old.append(a) - subs_new.append(D) - _args[idx] = D - sympy_arg.append(D) - else: - sympy_arg.append(a) - - f_sympy = f._sympy_()(*_args) - result = f_sympy.diff(*sympy_arg) - if subs_new: - return sympy.Subs(result, subs_new, subs_old) - else: - return result - - -sympy_converter = SympyConverter() - - ########## # FriCAS # ########## @@ -1020,10 +733,13 @@ def pyobject(self, ex, obj): """ try: result = getattr(obj, self.name_init)() - if isinstance(obj, NumberFieldElement_gaussian): - return "((%s)::EXPR COMPLEX INT)" % result except AttributeError: result = repr(obj) + else: + if isinstance(obj, NumberFieldElement_base): + from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_gaussian + if isinstance(obj, NumberFieldElement_gaussian): + return "((%s)::EXPR COMPLEX INT)" % result return "((%s)::EXPR INT)" % result def symbol(self, ex): @@ -1099,13 +815,12 @@ def derivative(self, ex, operator): ,1,1,2 """ - from sage.symbolic.ring import is_SymbolicVariable args = ex.operands() # the arguments the derivative is evaluated at params = operator.parameter_set() params_set = set(params) mult = ",".join(str(params.count(i)) for i in params_set) - if (not all(is_SymbolicVariable(v) for v in args) or - len(args) != len(set(args))): + if (not all(isinstance(v, Expression) and v.is_symbol() for v in args) or + len(args) != len(set(args))): # An evaluated derivative of the form f'(1) is not a # symbolic variable, yet we would like to treat it like # one. So, we replace the argument `1` with a temporary @@ -1131,255 +846,6 @@ def derivative(self, ex, operator): fricas_converter = FriCASConverter() -############# -# Algebraic # -############# -class AlgebraicConverter(Converter): - def __init__(self, field): - """ - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import AlgebraicConverter - sage: a = AlgebraicConverter(QQbar) - sage: a.field - Algebraic Field - sage: a.reciprocal_trig_functions['cot'] - tan - """ - self.field = field - - from sage.functions.all import reciprocal_trig_functions - self.reciprocal_trig_functions = reciprocal_trig_functions - - def pyobject(self, ex, obj): - """ - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import AlgebraicConverter - sage: a = AlgebraicConverter(QQbar) - sage: f = SR(2) - sage: a.pyobject(f, f.pyobject()) - 2 - sage: _.parent() - Algebraic Field - """ - return self.field(obj) - - def arithmetic(self, ex, operator): - """ - Convert a symbolic expression to an algebraic number. - - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import AlgebraicConverter - sage: f = 2^(1/2) - sage: a = AlgebraicConverter(QQbar) - sage: a.arithmetic(f, f.operator()) - 1.414213562373095? - - TESTS:: - - sage: f = pi^6 - sage: a = AlgebraicConverter(QQbar) - sage: a.arithmetic(f, f.operator()) - Traceback (most recent call last): - ... - TypeError: unable to convert pi^6 to Algebraic Field - - Test that :trac:`14602` is fixed:: - - sage: K = QuadraticField(3) - sage: K(sqrt(3)).parent() is K - True - sage: sqrt(K(3)).parent() is K - True - sage: (K(3)^(1/2)).parent() - Symbolic Ring - sage: bool(K.gen() == K(3)^(1/2) == sqrt(K(3)) == K(sqrt(3)) == sqrt(3)) - True - sage: L = QuadraticField(3, embedding=-AA(3).sqrt()) - sage: bool(L.gen() == -sqrt(3)) - True - """ - # We try to avoid simplifying, because maxima's simplify command - # can change the value of a radical expression (by changing which - # root is selected). - try: - if operator is pow: - from sage.rings.rational import Rational - base, expt = ex.operands() - base = self.field(base) - expt = Rational(expt) - return self.field(base**expt) - else: - if operator is add_vararg: - operator = add - elif operator is mul_vararg: - operator = mul - return reduce(operator, map(self, ex.operands())) - except TypeError: - pass - - if operator is pow: - from sage.symbolic.constants import e, pi, I - base, expt = ex.operands() - if base == e and expt / (pi * I) in QQ: - return exp(expt)._algebraic_(self.field) - - raise TypeError("unable to convert %r to %s" % (ex, self.field)) - - def composition(self, ex, operator): - """ - Coerce to an algebraic number. - - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import AlgebraicConverter - sage: a = AlgebraicConverter(QQbar) - sage: a.composition(exp(I*pi/3, hold=True), exp) - 0.500000000000000? + 0.866025403784439?*I - sage: a.composition(sin(pi/7), sin) - 0.4338837391175581? + 0.?e-18*I - - TESTS:: - - sage: QQbar(zeta(7)) - Traceback (most recent call last): - ... - TypeError: unable to convert zeta(7) to Algebraic Field - - Test :trac:`22571`:: - - sage: a.composition(exp(0, hold=True), exp) - 1 - sage: a.composition(exp(1, hold=True), exp) - Traceback (most recent call last): - ... - ValueError: unable to represent as an algebraic number - sage: a.composition(exp(pi*I*RR(1), hold=True), exp) - Traceback (most recent call last): - ... - TypeError: unable to convert e^(1.00000000000000*I*pi) to Algebraic Field - sage: a.composition(exp(pi*CC.gen(), hold=True), exp) - Traceback (most recent call last): - ... - TypeError: unable to convert e^(1.00000000000000*I*pi) to Algebraic Field - sage: bool(sin(pi*RR("0.7000000000000002")) > 0) - True - - Check that :trac:`24440` is fixed:: - - sage: QQbar(tanh(pi + 0.1)) - Traceback (most recent call last): - ... - ValueError: unable to represent as an algebraic number - sage: QQbar(sin(I*pi/7)) - Traceback (most recent call last): - ... - ValueError: unable to represent as an algebraic number - sage: QQbar(sin(I*pi/7, hold=True)) - Traceback (most recent call last): - ... - ValueError: unable to represent as an algebraic number - """ - func = operator - operand, = ex.operands() - - if isinstance(self.field, UniversalCyclotomicField): - QQbar = self.field - hold = True - else: - QQbar = self.field.algebraic_closure() - hold = False - zeta = QQbar.zeta - # Note that comparing functions themselves goes via maxima, and is SLOW - func_name = repr(func) - if func_name == 'exp': - if operand.is_trivial_zero(): - return self.field.one() - if not (SR(-1).sqrt() * operand).is_real(): - raise ValueError("unable to represent as an algebraic number") - # Coerce (not convert, see #22571) arg to a rational - arg = operand.imag()/(2*ex.parent().pi()) - try: - rat_arg = QQ.coerce(arg.pyobject()) - except TypeError: - raise TypeError("unable to convert %r to %s" % (ex, self.field)) - res = zeta(rat_arg.denom())**rat_arg.numer() - elif func_name in ['sin', 'cos', 'tan']: - exp_ia = exp(SR(-1).sqrt() * operand, hold=hold)._algebraic_(QQbar) - if func_name == 'sin': - res = (exp_ia - ~exp_ia) / (2 * zeta(4)) - elif func_name == 'cos': - res = (exp_ia + ~exp_ia) / 2 - else: - res = -zeta(4) * (exp_ia - ~exp_ia) / (exp_ia + ~exp_ia) - elif func_name in ['sinh', 'cosh', 'tanh']: - if not (SR(-1).sqrt()*operand).is_real(): - raise ValueError("unable to represent as an algebraic number") - exp_a = exp(operand, hold=hold)._algebraic_(QQbar) - if func_name == 'sinh': - res = (exp_a - ~exp_a) / 2 - elif func_name == 'cosh': - res = (exp_a + ~exp_a) / 2 - else: - res = (exp_a - ~exp_a) / (exp_a + ~exp_a) - elif func_name in self.reciprocal_trig_functions: - res = ~self.reciprocal_trig_functions[func_name](operand)._algebraic_(QQbar) - else: - res = func(operand._algebraic_(self.field)) - # We have to handle the case where we get the same symbolic - # expression back. For example, QQbar(zeta(7)). See - # issue #12665. - if (res - ex).is_trivial_zero(): - raise TypeError("unable to convert %r to %s" % (ex, self.field)) - return self.field(res) - - -def algebraic(ex, field): - """ - Returns the symbolic expression *ex* as a element of the algebraic - field *field*. - - EXAMPLES:: - - sage: a = SR(5/6) - sage: AA(a) - 5/6 - sage: type(AA(a)) - <class 'sage.rings.qqbar.AlgebraicReal'> - sage: QQbar(a) - 5/6 - sage: type(QQbar(a)) - <class 'sage.rings.qqbar.AlgebraicNumber'> - sage: QQbar(i) - I - sage: AA(golden_ratio) - 1.618033988749895? - sage: QQbar(golden_ratio) - 1.618033988749895? - sage: QQbar(sin(pi/3)) - 0.866025403784439? - - sage: QQbar(sqrt(2) + sqrt(8)) - 4.242640687119285? - sage: AA(sqrt(2) ^ 4) == 4 - True - sage: AA(-golden_ratio) - -1.618033988749895? - sage: QQbar((2*SR(I))^(1/2)) - 1 + 1*I - sage: QQbar(e^(pi*I/3)) - 0.50000000000000000? + 0.866025403784439?*I - - sage: AA(x*sin(0)) - 0 - sage: QQbar(x*sin(0)) - 0 - """ - return AlgebraicConverter(field)(ex) - - ############## # Polynomial # ############## @@ -2198,8 +1664,7 @@ class Exponentialize(ExpressionTreeWalker): from sage.functions.hyperbolic import sinh, cosh, sech, csch, tanh, coth from sage.functions.log import exp from sage.functions.trig import sin, cos, sec, csc, tan, cot - from sage.rings.imaginary_unit import I - from sage.symbolic.constants import e + from sage.symbolic.constants import e, I from sage.rings.integer import Integer from sage.symbolic.ring import SR from sage.calculus.var import function diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 4979188159a..f4bd22df0a6 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -77,9 +77,9 @@ like a symbol. Setting ``nargs=0`` allows any number of arguments:: ....: def _eval_(self, *args): ....: pass sage: f = Test1() - sage: f() + sage: f() # needs sage.symbolic test() - sage: f(1,2,3)*f(1,2,3) + sage: f(1,2,3)*f(1,2,3) # needs sage.symbolic test(1, 2, 3)^2 In the following the ``sin`` function of ``CBF(0)`` is called because with @@ -97,14 +97,14 @@ is attempted, and after that ``sin()`` which succeeds:: sage: f = Test2() sage: f(0) 5 - sage: f(0, hold=True) + sage: f(0, hold=True) # needs sage.symbolic my_sin(0) - sage: f(0, hold=True).n() + sage: f(0, hold=True).n() # needs sage.rings.real_mpfr 3.50000000000000 - sage: f(CBF(0)) + sage: f(CBF(0)) # needs sage.libs.flint 0 - sage: latex(f(0, hold=True)) + sage: latex(f(0, hold=True)) # needs sage.symbolic \SIN\left(0\right) sage: f(1,2) Traceback (most recent call last): @@ -141,11 +141,6 @@ is attempted, and after that ``sin()`` which succeeds:: from sage.structure.sage_object cimport SageObject from sage.structure.element cimport Element, parent, Expression from sage.misc.lazy_attribute import lazy_attribute -from .expression import ( - call_registered_function, find_registered_function, register_or_update_function, - get_sfunction_from_hash -) -from .expression import get_sfunction_from_serial as get_sfunction_from_serial from sage.structure.coerce cimport (coercion_model, py_scalar_to_element, is_numpy_type, is_mpmath_type) @@ -153,6 +148,17 @@ from sage.structure.richcmp cimport richcmp from sage.misc.fpickle import pickle_function, unpickle_function +from .symbols import symbol_table, register_symbol + +try: + from .expression import ( + call_registered_function, find_registered_function, register_or_update_function, + get_sfunction_from_hash, get_sfunction_from_serial as get_sfunction_from_serial + ) +except ImportError: + register_or_update_function = None + + # List of functions which ginac allows us to define custom behavior for. # Changing the order of this list could cause problems unpickling old pickles. sfunctions_funcs = ['eval', 'evalf', 'conjugate', 'real_part', 'imag_part', @@ -176,32 +182,34 @@ cdef class Function(SageObject): EXAMPLES:: - sage: f = function('f', nargs=1, conjugate_func=lambda self,x: 2r*x) # indirect doctest - sage: f(2) + sage: f = function('f', nargs=1, # indirect doctest # needs sage.symbolic + ....: conjugate_func=lambda self, x: 2r*x) + sage: f(2) # needs sage.symbolic f(2) - sage: f(2).conjugate() + sage: f(2).conjugate() # needs sage.symbolic 4 TESTS:: # eval_func raises exception sage: def ef(self, x): raise RuntimeError("foo") - sage: bar = function("bar", nargs=1, eval_func=ef) - sage: bar(x) + sage: bar = function("bar", nargs=1, eval_func=ef) # needs sage.symbolic + sage: bar(x) # needs sage.symbolic Traceback (most recent call last): ... RuntimeError: foo # eval_func returns non coercible sage: def ef(self, x): return ZZ - sage: bar = function("bar", nargs=1, eval_func=ef) - sage: bar(x) + sage: bar = function("bar", nargs=1, eval_func=ef) # needs sage.symbolic + sage: bar(x) # needs sage.symbolic Traceback (most recent call last): ... - TypeError: function did not return a symbolic expression or an element that can be coerced into a symbolic expression + TypeError: function did not return a symbolic expression + or an element that can be coerced into a symbolic expression # eval_func is not callable - sage: bar = function("bar", nargs=1, eval_func=5) + sage: bar = function("bar", nargs=1, eval_func=5) # needs sage.symbolic Traceback (most recent call last): ... ValueError: eval_func parameter must be callable @@ -230,13 +238,11 @@ cdef class Function(SageObject): callable(getattr(self, real_fname)): raise ValueError(real_fname + " parameter must be callable") - if not self._is_registered(): - self._register_function() - - from .expression import symbol_table, register_symbol - - symbol_table['functions'][self._name] = self + symbol_table['functions'][self._name] = self + if register_or_update_function: # Symbolic subsystem present + if not self._is_registered(): + self._register_function() register_symbol(self, self._conversions) cdef _is_registered(self): @@ -255,6 +261,7 @@ cdef class Function(SageObject): functions was broken. We check here that this is fixed (:trac:`11919`):: + sage: # needs sage.symbolic sage: f = function('f')(x) sage: s = dumps(f) sage: loads(s) @@ -281,7 +288,7 @@ cdef class Function(SageObject): TESTS:: - sage: coth(5) # indirect doctest + sage: coth(5) # indirect doctest # needs sage.symbolic coth(5) sage: coth(0.5) 2.16395341373865 @@ -302,13 +309,13 @@ cdef class Function(SageObject): sage: test = Test() sage: test(1.3, 4) 2.30000000000000 - sage: test(pi, 4) + sage: test(pi, 4) # needs sage.symbolic test(pi, 4) - sage: test(2, x) + sage: test(2, x) # needs sage.symbolic 3 sage: test(2., 4) 3.00000000000000 - sage: test(1 + 1.0*I, 2) + sage: test(1 + 1.0*I, 2) # needs sage.symbolic 2.00000000000000 + 1.00000000000000*I sage: class Test2(BuiltinFunction): ....: def __init__(self): @@ -324,7 +331,7 @@ cdef class Function(SageObject): sage: test2 = Test2() sage: test2(1.3) 0.500000000000000 - sage: test2(pi) + sage: test2(pi) # needs sage.symbolic 3 """ # If any of the inputs is numerical and none is symbolic, @@ -342,10 +349,10 @@ cdef class Function(SageObject): """ EXAMPLES:: - sage: f = function('f', nargs=1, conjugate_func=lambda self,x: 2r*x) - sage: f.__hash__() #random + sage: f = function('f', nargs=1, conjugate_func=lambda self, x: 2r*x) # needs sage.symbolic + sage: f.__hash__() # random # needs sage.symbolic -2224334885124003860 - sage: hash(f(2)) #random + sage: hash(f(2)) # random # needs sage.symbolic 4168614485 """ return hash(self._name)*(self._nargs+1)*self._serial @@ -354,7 +361,7 @@ cdef class Function(SageObject): """ EXAMPLES:: - sage: foo = function("foo", nargs=2); foo + sage: foo = function("foo", nargs=2); foo # needs sage.symbolic foo """ return self._name @@ -383,12 +390,13 @@ cdef class Function(SageObject): """ TESTS:: + sage: # needs sage.symbolic sage: foo = function("foo", nargs=2) sage: foo == foo True sage: foo == 2 False - sage: foo(1,2).operator() == foo + sage: foo(1, 2).operator() == foo True """ @@ -402,56 +410,55 @@ cdef class Function(SageObject): """ Evaluates this function at the given arguments. - We coerce the arguments into symbolic expressions if coerce=True, then + We coerce the arguments into symbolic expressions if ``coerce=True``, then call the Pynac evaluation method, which in turn passes the arguments to a custom automatic evaluation method if ``_eval_()`` is defined. EXAMPLES:: + sage: # needs sage.symbolic sage: foo = function("foo", nargs=2) sage: x,y,z = var("x y z") - sage: foo(x,y) + sage: foo(x, y) foo(x, y) - sage: foo(y) Traceback (most recent call last): ... TypeError: Symbolic function foo takes exactly 2 arguments (1 given) - sage: bar = function("bar") sage: bar(x) bar(x) - sage: bar(x,y) + sage: bar(x, y) bar(x, y) The `hold` argument prevents automatic evaluation of the function:: - sage: exp(log(x)) + sage: exp(log(x)) # needs sage.symbolic x - sage: exp(log(x), hold=True) + sage: exp(log(x), hold=True) # needs sage.symbolic e^log(x) We can also handle numpy types:: - sage: import numpy - sage: sin(numpy.arange(5)) + sage: import numpy # needs numpy + sage: sin(numpy.arange(5)) # needs numpy array([ 0. , 0.84147098, 0.90929743, 0.14112001, -0.7568025 ]) Symbolic functions evaluate non-exact input numerically, and return symbolic expressions on exact input, or if any input is symbolic:: - sage: arctan(1) + sage: arctan(1) # needs sage.symbolic 1/4*pi - sage: arctan(float(1)) + sage: arctan(float(1)) # needs sage.rings.complex_double 0.7853981633974483 - sage: type(lambert_w(SR(0))) + sage: type(lambert_w(SR(0))) # needs sage.symbolic <class 'sage.symbolic.expression.Expression'> Precision of the result depends on the precision of the input:: sage: arctan(RR(1)) 0.785398163397448 - sage: arctan(RealField(100)(1)) + sage: arctan(RealField(100)(1)) # needs sage.rings.real_mpfr 0.78539816339744830961566084582 Return types for non-exact input depends on the input type:: @@ -466,29 +473,31 @@ cdef class Function(SageObject): Test coercion:: - sage: bar(ZZ) + sage: bar(ZZ) # needs sage.symbolic Traceback (most recent call last): ... TypeError: cannot coerce arguments: ... - sage: exp(QQbar(I)) + sage: exp(QQbar(I)) # needs sage.rings.number_field sage.symbolic e^I For functions with single argument, if coercion fails we try to call a method with the name of the function on the object:: - sage: M = matrix(SR, 2, 2, [x, 0, 0, I*pi]) - sage: exp(M) + sage: M = matrix(SR, 2, 2, [x, 0, 0, I*pi]) # needs sage.modules sage.symbolic + sage: exp(M) # needs sage.modules sage.symbolic [e^x 0] [ 0 -1] Make sure we can pass mpmath arguments (:trac:`13608`):: - sage: import mpmath - sage: with mpmath.workprec(128): sin(mpmath.mpc('0.5', '1.2')) - mpc(real='0.86807452059118713192871150787046523179886', imag='1.3246769633571289324095313649562791720086') + sage: import mpmath # needs mpmath + sage: with mpmath.workprec(128): sin(mpmath.mpc('0.5', '1.2')) # needs mpmath + mpc(real='0.86807452059118713192871150787046523179886', + imag='1.3246769633571289324095313649562791720086') Check that :trac:`10133` is fixed:: + sage: # needs sage.symbolic sage: out = sin(0) sage: out, parent(out) (0, Integer Ring) @@ -504,6 +513,7 @@ cdef class Function(SageObject): Check that ``real_part`` and ``imag_part`` still works after :trac:`21216`:: + sage: # needs numpy sage.symbolic sage: import numpy sage: a = numpy.array([1+2*I, -2-3*I], dtype=complex) sage: real_part(a) @@ -516,11 +526,9 @@ cdef class Function(SageObject): # if the given input is a symbolic expression, we don't convert it back # to a numeric type at the end + symbolic_input = any(isinstance(arg, Expression) for arg in args) + from .ring import SR - if any(parent(arg) is SR for arg in args): - symbolic_input = True - else: - symbolic_input = False if coerce: try: @@ -545,7 +553,7 @@ cdef class Function(SageObject): raise TypeError("arguments must be symbolic expressions") return call_registered_function(self._serial, self._nargs, args, hold, - not symbolic_input, SR) + not symbolic_input, SR) def name(self): """ @@ -553,8 +561,8 @@ cdef class Function(SageObject): EXAMPLES:: - sage: foo = function("foo", nargs=2) - sage: foo.name() + sage: foo = function("foo", nargs=2) # needs sage.symbolic + sage: foo.name() # needs sage.symbolic 'foo' """ return self._name @@ -565,12 +573,12 @@ cdef class Function(SageObject): EXAMPLES:: + sage: # needs sage.symbolic sage: foo = function("foo", nargs=2) sage: foo.number_of_arguments() 2 - sage: foo(x,x) + sage: foo(x, x) foo(x, x) - sage: foo(x) Traceback (most recent call last): ... @@ -595,7 +603,7 @@ cdef class Function(SageObject): EXAMPLES:: - sage: sin.default_variable() + sage: sin.default_variable() # needs sage.symbolic x """ from .ring import SR @@ -615,14 +623,15 @@ cdef class Function(SageObject): sage: [sin._is_numerical(a) for a in [5., 5.4r]] [True, True] - sage: [sin._is_numerical(a) for a in [5, pi]] + sage: [sin._is_numerical(a) for a in [5, pi]] # needs sage.symbolic [False, False] - sage: [sin._is_numerical(R(1)) for R in [RIF, CIF, RBF, CBF]] + sage: [sin._is_numerical(R(1)) for R in [RIF, CIF, RBF, CBF]] # needs sage.libs.flint [False, False, False, False] The following calls used to yield incorrect results because intervals were considered numerical by this method:: + sage: # needs sage.libs.flint sage: b = RBF(3/2, 1e-10) sage: airy_ai(b) airy_ai([1.500000000 +/- 1.01e-10]) @@ -650,7 +659,7 @@ cdef class Function(SageObject): """ EXAMPLES:: - sage: sin._interface_init_(maxima) + sage: sin._interface_init_(maxima) # needs sage.symbolic 'sin' """ if I is None: @@ -665,7 +674,7 @@ cdef class Function(SageObject): 'Sin' sage: exp._mathematica_init_() 'Exp' - sage: (exp(x) + sin(x) + tan(x))._mathematica_init_() + sage: (exp(x) + sin(x) + tan(x))._mathematica_init_() # needs sage.symbolic '(Exp[x])+(Sin[x])+(Tan[x])' """ s = self._conversions.get('mathematica', None) @@ -681,7 +690,7 @@ cdef class Function(SageObject): sage: g = SymbolicFunction('g', conversions=dict(sympy='gg')) sage: g._sympy_init_() 'gg' - sage: g(x)._sympy_() + sage: g(x)._sympy_() # needs sage.symbolic gg(x) """ return self._conversions.get('sympy', self._name) @@ -691,9 +700,9 @@ cdef class Function(SageObject): """ EXAMPLES:: - sage: cos._sympy_() + sage: cos._sympy_() # needs sympy cos - sage: _(0) + sage: _(0) # needs sympy 1 """ f = self._sympy_init_() @@ -742,16 +751,17 @@ cdef class Function(SageObject): EXAMPLES:: + sage: # needs numpy sage: import numpy sage: a = numpy.arange(5) sage: csc(a) doctest:...: RuntimeWarning: divide by zero encountered in ...divide array([ inf, 1.18839511, 1.09975017, 7.0861674 , -1.32134871]) - sage: factorial(a) Traceback (most recent call last): ... - NotImplementedError: The Function factorial does not support numpy arrays as arguments + NotImplementedError: The Function factorial does + not support numpy arrays as arguments """ raise NotImplementedError("The Function %s does not support numpy arrays as arguments" % self.name()) @@ -769,8 +779,8 @@ cdef class Function(SageObject): implementation, using sage reals instead of mpmath ones. This might change when aliases for these functions are established:: - sage: import mpmath - sage: with mpmath.workprec(128): arcsin(mpmath.mpf('0.5')) + sage: import mpmath # needs mpmath + sage: with mpmath.workprec(128): arcsin(mpmath.mpf('0.5')) # needs mpmath mpf('0.52359877559829887307710723054658381403157') TESTS: @@ -779,6 +789,7 @@ cdef class Function(SageObject): not using mpmath, we have to create a custom function which will certainly never get created in mpmath. :: + sage: # needs mpmath sage: import mpmath sage: from sage.symbolic.function import BuiltinFunction sage: class NoMpmathFn(BuiltinFunction): @@ -806,6 +817,7 @@ cdef class Function(SageObject): res = sage_to_mpmath(res, prec) return res + cdef class GinacFunction(BuiltinFunction): """ This class provides a wrapper around symbolic functions already defined in @@ -824,12 +836,12 @@ cdef class GinacFunction(BuiltinFunction): TESTS:: sage: from sage.functions.trig import Function_sin - sage: s = Function_sin() # indirect doctest - sage: s(0) + sage: s = Function_sin() # indirect doctest + sage: s(0) # needs sage.symbolic 0 - sage: s(pi) + sage: s(pi) # needs sage.symbolic 0 - sage: s(pi/2) + sage: s(pi/2) # needs sage.symbolic 1 """ self._ginac_name = ginac_name @@ -873,8 +885,8 @@ cdef class BuiltinFunction(Function): TESTS:: sage: from sage.functions.trig import Function_cot - sage: c = Function_cot() # indirect doctest - sage: c(pi/2) + sage: c = Function_cot() # indirect doctest + sage: c(pi/2) # needs sage.symbolic 0 """ self._preserved_arg = preserved_arg @@ -918,13 +930,13 @@ cdef class BuiltinFunction(Function): return [arg] def __call__(self, *args, bint coerce=True, bint hold=False, - bint dont_call_method_on_arg=False): + bint dont_call_method_on_arg=False): r""" Evaluate this function on the given arguments and return the result. EXAMPLES:: - sage: exp(5) + sage: exp(5) # needs sage.symbolic e^5 sage: gamma(15) 87178291200 @@ -944,16 +956,17 @@ cdef class BuiltinFunction(Function): (1.5430806348152437-0j) sage: assert type(_) is complex + sage: # needs mpmath sage: import mpmath sage: cos(mpmath.mpf('1.321412')) mpf('0.24680737898640387') sage: cos(mpmath.mpc(1,1)) mpc(real='0.83373002513114902', imag='-0.98889770576286506') - sage: import numpy - sage: sin(numpy.int32(0)) + sage: import numpy # needs numpy + sage: sin(numpy.int32(0)) # needs numpy 0.0 - sage: type(_) + sage: type(_) # needs numpy <class 'numpy.float64'> TESTS:: @@ -1081,15 +1094,15 @@ cdef class BuiltinFunction(Function): sage: from sage.symbolic.function import BuiltinFunction sage: class AFunction(BuiltinFunction): ....: def __init__(self, name, exp=1): - ....: self.exponent=exp + ....: self.exponent = exp ....: BuiltinFunction.__init__(self, name, nargs=1) ....: def _eval_(self, arg): ....: return arg**self.exponent sage: p2 = AFunction('p2', 2) - sage: p2(x) + sage: p2(x) # needs sage.symbolic x^2 sage: p3 = AFunction('p3', 3) - sage: p3(x) + sage: p3(x) # needs sage.symbolic x^3 sage: loads(dumps(cot)) == cot # trac #15138 True @@ -1132,7 +1145,7 @@ cdef class BuiltinFunction(Function): (<class 'sage.functions.trig.Function_cot'>, ()) sage: f = loads(dumps(cot)) #indirect doctest - sage: f(pi/2) + sage: f(pi/2) # needs sage.symbolic 0 """ return self.__class__, tuple() @@ -1179,11 +1192,11 @@ cdef class SymbolicFunction(Function): sage: foo = my_function() sage: foo foo - sage: foo(2,3) + sage: foo(2, 3) # needs sage.symbolic foo(2, 3) - sage: foo(2,3).n() + sage: foo(2, 3).n() # needs sage.rings.real_mpfr 12.0000000000000 - sage: foo(2,3).conjugate() + sage: foo(2, 3).conjugate() # needs sage.symbolic 2 """ self.__hinit = False @@ -1222,13 +1235,13 @@ cdef class SymbolicFunction(Function): """ TESTS:: - sage: foo = function("foo", nargs=2) - sage: hash(foo) # random output + sage: foo = function("foo", nargs=2) # needs sage.symbolic + sage: hash(foo) # random output # needs sage.symbolic -6859868030555295348 sage: def ev(self, x): return 2*x - sage: foo = function("foo", nargs=2, eval_func = ev) - sage: hash(foo) # random output + sage: foo = function("foo", nargs=2, eval_func=ev) # needs sage.symbolic + sage: hash(foo) # random output # needs sage.symbolic -6859868030555295348 """ return self._serial*self._hash_() @@ -1268,35 +1281,41 @@ cdef class SymbolicFunction(Function): EXAMPLES:: + sage: # needs sage.symbolic sage: foo = function("foo", nargs=2) sage: foo.__getstate__() - (2, 'foo', 2, None, {}, True, [None, None, None, None, None, None, None, None, None, None, None]) + (2, 'foo', 2, None, {}, True, + [None, None, None, None, None, None, None, None, None, None, None]) sage: t = loads(dumps(foo)) sage: t == foo True sage: var('x,y') (x, y) - sage: t(x,y) + sage: t(x, y) foo(x, y) sage: def ev(self, x,y): return 2*x - sage: foo = function("foo", nargs=2, eval_func = ev) - sage: foo.__getstate__() - (2, 'foo', 2, None, {}, True, [..., None, None, None, None, None, None, None, None, None, None]) + sage: foo = function("foo", nargs=2, eval_func=ev) # needs sage.symbolic + sage: foo.__getstate__() # needs sage.symbolic + (2, 'foo', 2, None, {}, True, + [..., None, None, None, None, None, None, None, None, None, None]) + sage: # needs sage.symbolic sage: u = loads(dumps(foo)) sage: u == foo True sage: t == u False - sage: u(y,x) + sage: u(y, x) 2*y sage: def evalf_f(self, x, **kwds): return int(6) - sage: foo = function("foo", nargs=1, evalf_func=evalf_f) - sage: foo.__getstate__() - (2, 'foo', 1, None, {}, True, [None, ..., None, None, None, None, None, None, None, None, None]) + sage: foo = function("foo", nargs=1, evalf_func=evalf_f) # needs sage.symbolic + sage: foo.__getstate__() # needs sage.symbolic + (2, 'foo', 1, None, {}, True, + [None, ..., None, None, None, None, None, None, None, None, None]) + sage: # needs sage.symbolic sage: v = loads(dumps(foo)) sage: v == foo True @@ -1309,11 +1328,11 @@ cdef class SymbolicFunction(Function): Test pickling expressions with symbolic functions:: - sage: u = loads(dumps(foo(x)^2 + foo(y) + x^y)); u + sage: u = loads(dumps(foo(x)^2 + foo(y) + x^y)); u # needs sage.symbolic foo(x)^2 + x^y + foo(y) - sage: u.subs(y=0) + sage: u.subs(y=0) # needs sage.symbolic foo(x)^2 + foo(0) + 1 - sage: u.subs(y=0).n() + sage: u.subs(y=0).n() # needs sage.symbolic 43.0000000000000 """ return (2, self._name, self._nargs, self._latex_name, self._conversions, @@ -1330,6 +1349,7 @@ cdef class SymbolicFunction(Function): TESTS:: + sage: # needs sage.symbolic sage: var('x,y') (x, y) sage: foo = function("foo", nargs=2) @@ -1338,23 +1358,24 @@ cdef class SymbolicFunction(Function): :: - sage: g = function('g', nargs=1, conjugate_func=lambda y,x: 2*x) + sage: # needs sage.symbolic + sage: g = function('g', nargs=1, conjugate_func=lambda y, x: 2*x) sage: st = g.__getstate__() sage: f = function('f') sage: f(x) f(x) - sage: f(x).conjugate() # no special conjugate method + sage: f(x).conjugate() # no special conjugate method conjugate(f(x)) sage: f.__setstate__(st) - sage: f(x+1).conjugate() # now there is a special method + sage: f(x + 1).conjugate() # now there is a special method 2*x + 2 Note that the other direction doesn't work here, since ``foo._hash_()`` hash already been initialized.:: - sage: bar + sage: bar # needs sage.symbolic foo - sage: bar(x,y) + sage: bar(x, y) # needs sage.symbolic foo(x, y) """ # check input diff --git a/src/sage/symbolic/function_factory.py b/src/sage/symbolic/function_factory.py index e32480bd99a..4c2542c77e3 100644 --- a/src/sage/symbolic/function_factory.py +++ b/src/sage/symbolic/function_factory.py @@ -193,8 +193,7 @@ def function(s, **kwds) -> Union[SymbolicFunction, list[SymbolicFunction]]: (a, b) sage: cr = function('cr') sage: f = cr(a) - sage: g = f.diff(a).integral(b) - sage: g + sage: g = f.diff(a).integral(b); g b*diff(cr(a), a) sage: foo = function("foo", nargs=2) sage: x,y,z = var("x y z") @@ -218,7 +217,8 @@ def function(s, **kwds) -> Union[SymbolicFunction, list[SymbolicFunction]]: sage: 2*f Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Integer Ring' and '<class 'sage.symbolic.function_factory...NewSymbolicFunction'>' + TypeError: unsupported operand parent(s) for *: 'Integer Ring' and + '<class 'sage.symbolic.function_factory...NewSymbolicFunction'>' You now need to evaluate the function in order to do the arithmetic:: diff --git a/src/sage/symbolic/getitem_impl.pxi b/src/sage/symbolic/getitem_impl.pxi index 72bf9d5f0e5..7bbb2dfe852 100644 --- a/src/sage/symbolic/getitem_impl.pxi +++ b/src/sage/symbolic/getitem_impl.pxi @@ -138,8 +138,7 @@ cdef class OperandsWrapper(SageObject): else: step = 1 return [new_Expression_from_GEx(self._expr._parent, - self._expr._gobj.op(ind)) for ind in xrange(bind, eind, step)] - + self._expr._gobj.op(ind)) for ind in range(bind, eind, step)] ind_err_msg = "index should either be a slice object, an integer or a list of integers" if isinstance(arg, (list, tuple)): diff --git a/src/sage/symbolic/ginac/numeric.cpp b/src/sage/symbolic/ginac/numeric.cpp index b40ed64edb5..c4152e092e3 100644 --- a/src/sage/symbolic/ginac/numeric.cpp +++ b/src/sage/symbolic/ginac/numeric.cpp @@ -176,12 +176,7 @@ inline void py_error(const char* errmsg) { "pyerror() called but no error occurred!"); } -#if PY_MAJOR_VERSION < 3 -#define PyNumber_TrueDivide PyNumber_Divide - -#else #define PyString_FromString PyUnicode_FromString -#endif // The following variable gets changed to true once // this library has been imported by the Python @@ -209,9 +204,9 @@ PyObject* RR_get() { static PyObject* ptr = nullptr; if (ptr == nullptr) { - PyObject* m = PyImport_ImportModule("sage.rings.all"); + PyObject* m = PyImport_ImportModule("sage.rings.real_mpfr"); if (m == nullptr) - py_error("Error importing sage.rings.all"); + py_error("Error importing sage.rings.real_mpfr"); ptr = PyObject_GetAttrString(m, "RR"); if (ptr == nullptr) py_error("Error getting RR attribute"); @@ -225,13 +220,10 @@ PyObject* CC_get() static PyObject* ptr = nullptr; if (ptr) return ptr; - PyObject* m = PyImport_ImportModule("sage.rings.all"); + PyObject* m = PyImport_ImportModule("sage.rings.cc"); if (m == nullptr) - py_error("Error importing sage.rings.all"); - ptr = PyObject_GetAttrString(m, "ComplexField"); - if (ptr == nullptr) - py_error("Error getting ComplexField attribute"); - ptr = PyObject_CallObject(ptr, NULL); + py_error("Error importing sage.rings.cc"); + ptr = PyObject_GetAttrString(m, "CC"); if (ptr == nullptr) py_error("Error getting CC attribute"); Py_INCREF(ptr); @@ -310,9 +302,9 @@ int precision(const GiNaC::numeric& num, PyObject*& a_parent) { } PyObject* CBF(int res) { - PyObject* m = PyImport_ImportModule("sage.rings.all"); + PyObject* m = PyImport_ImportModule("sage.rings.complex_arb"); if (m == nullptr) - py_error("Error importing arb"); + py_error("Error importing sage.rings.complex_arb"); PyObject* f = PyObject_GetAttrString(m, "ComplexBallField"); if (f == nullptr) py_error("Error getting ComplexBallField attribute"); @@ -392,9 +384,9 @@ PyObject* CallBallMethod1Arg(PyObject* field, const char* meth, const GiNaC::num } PyObject* CoerceBall(PyObject* ball, int prec) { - PyObject* m = PyImport_ImportModule("sage.rings.all"); + PyObject* m = PyImport_ImportModule("sage.rings.complex_mpfr"); if (m == nullptr) - py_error("Error importing sage.rings.all"); + py_error("Error importing sage.rings.complex_mpfr"); PyObject* f = PyObject_GetAttrString(m, "ComplexField"); if (f == nullptr) py_error("Error getting ComplexField attribute"); @@ -494,15 +486,9 @@ static PyObject* py_tuple_from_numvector(const std::vector<numeric>& vec) // class numeric /////////////////////////////////////////////////////////////////////////////// -#if PY_MAJOR_VERSION < 3 -PyObject* ZERO = PyInt_FromLong(0); // todo: never freed -PyObject* ONE = PyInt_FromLong(1); // todo: never freed -PyObject* TWO = PyInt_FromLong(2); // todo: never freed -#else PyObject* ZERO = PyLong_FromLong(0); // todo: never freed PyObject* ONE = PyLong_FromLong(1); // todo: never freed PyObject* TWO = PyLong_FromLong(2); // todo: never freed -#endif std::ostream& operator<<(std::ostream& os, const numeric& s) { switch (s.t) { @@ -814,16 +800,6 @@ void set_from(Type& t, Value& v, long& hash, mpq_t bigrat) numeric::numeric(PyObject* o, bool force_py) : basic(&numeric::tinfo_static) { if (o == nullptr) py_error("Error"); if (not force_py) { -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(o)) { - t = LONG; - v._long = PyInt_AsLong(o); - hash = (v._long==-1) ? -2 : v._long; - setflag(status_flags::evaluated | status_flags::expanded); - Py_DECREF(o); - return; - } -#endif if (PyLong_Check(o)) { t = MPZ; mpz_init(v._bigint); @@ -1536,31 +1512,6 @@ const numeric numeric::div(const numeric &other) const { return bigrat; } case PYOBJECT: -#if PY_MAJOR_VERSION < 3 - if (PyObject_Compare(other.v._pyobject, ONE) == 0 - and py_funcs.py_is_integer(other.v._pyobject) != 0) { - return *this; - } - if (PyInt_Check(v._pyobject)) { - if (PyInt_Check(other.v._pyobject)) { - // This branch happens at startup. - PyObject *o = PyNumber_TrueDivide(Integer(PyInt_AsLong(v._pyobject)), - Integer(PyInt_AsLong(other.v._pyobject))); - // I don't 100% understand why I have to incref this, - // but if I don't, Sage crashes on exit. - Py_INCREF(o); - return o; - } - if (PyLong_Check(other.v._pyobject)) { - PyObject *d = py_funcs. - py_integer_from_python_obj(other.v._pyobject); - PyObject *ans = PyNumber_TrueDivide(v._pyobject, - d); - Py_DECREF(d); - return ans; - } - } -#endif if (PyLong_Check(v._pyobject)) { PyObject *n = py_funcs. py_integer_from_python_obj(v._pyobject); @@ -1576,6 +1527,62 @@ const numeric numeric::div(const numeric &other) const { } } + +// Compute `a^b` as an integer, where a is an integer. Assign to ``res``` if it is integral, or return ``false``. +// The nonnegative real root is taken for even denominators. To be used inside numeric::integer_rational_power, +// to handle the special case of integral ``a``. +bool integer_rational_power_of_mpz( + numeric& res, + const numeric& a, + const numeric& b +) { + if (a.t != MPZ) + throw std::runtime_error("integer_rational_power_of_mpz: bad input"); + mpz_t z; + mpz_init(z); + mpz_set_ui(z, 0); + int sgn = mpz_sgn(a.v._bigint); + if (mpz_cmp_ui(a.v._bigint, 1) == 0 + or mpz_cmp_ui(mpq_numref(b.v._bigrat), 0) == 0) + mpz_set_ui(z, 1); + else if (sgn == 0) { + res = *_num0_p; + mpz_clear(z); + return true; + } + else if (sgn < 0 and mpz_cmp_ui(mpq_denref(b.v._bigrat), 1)) { + mpz_clear(z); + return false; + } else { + if (not mpz_fits_ulong_p(mpq_numref(b.v._bigrat)) + or not mpz_fits_ulong_p(mpq_denref(b.v._bigrat))) { + // too big to take roots/powers + mpz_clear(z); + return false; + } + if (mpz_cmp_ui(mpq_denref(b.v._bigrat), 2) == 0) { + if (mpz_perfect_square_p(a.v._bigint)) { + mpz_sqrt(z, a.v._bigint); + } else { + mpz_clear(z); + return false; + } + } + else { + bool exact = mpz_root(z, a.v._bigint, + mpz_get_ui(mpq_denref(b.v._bigrat))); + if (not exact) { + mpz_clear(z); + return false; + } + } + mpz_pow_ui(z, z, mpz_get_ui(mpq_numref(b.v._bigrat))); + } + res = numeric(z); // transfers ownership, no mpz_clear + return true; +} + + // Compute `a^b` as an integer, if it is integral, or return ``false``. // The nonnegative real root is taken for even denominators. bool numeric::integer_rational_power(numeric& res, @@ -1598,13 +1605,12 @@ bool numeric::integer_rational_power(numeric& res, if (a.v._long < 0 and mpz_cmp_ui(mpq_denref(b.v._bigrat), 1)) return false; - long z; if (not mpz_fits_ulong_p(mpq_numref(b.v._bigrat)) or not mpz_fits_ulong_p(mpq_denref(b.v._bigrat))) // too big to take roots/powers return false; if (b.is_equal(*_num1_2_p)) { - z = std::lround(std::sqrt(a.v._long)); + long z = std::lround(std::sqrt(a.v._long)); if (a.v._long == z*z) { res = numeric(z); return true; @@ -1613,44 +1619,11 @@ bool numeric::integer_rational_power(numeric& res, } return integer_rational_power(res, a.to_bigint(), b); } - if (a.t != MPZ) - throw std::runtime_error("integer_rational_power: bad input"); - int sgn = mpz_sgn(a.v._bigint); - mpz_t z; - mpz_init(z); - mpz_set_ui(z, 0); - if (mpz_cmp_ui(a.v._bigint, 1) == 0 - or mpz_cmp_ui(mpq_numref(b.v._bigrat), 0) == 0) - mpz_set_ui(z, 1); - else if (sgn == 0) { - res = *_num0_p; - return true; - } - else if (sgn < 0 and mpz_cmp_ui(mpq_denref(b.v._bigrat), 1)) - return false; - else { - if (not mpz_fits_ulong_p(mpq_numref(b.v._bigrat)) - or not mpz_fits_ulong_p(mpq_denref(b.v._bigrat))) - // too big to take roots/powers - return false; - if (mpz_cmp_ui(mpq_denref(b.v._bigrat), 2) == 0) { - if (mpz_perfect_square_p(a.v._bigint)) - mpz_sqrt(z, a.v._bigint); - else - return false; - } - else { - bool exact = mpz_root(z, a.v._bigint, - mpz_get_ui(mpq_denref(b.v._bigrat))); - if (not exact) - return false; - } - mpz_pow_ui(z, z, mpz_get_ui(mpq_numref(b.v._bigrat))); - } - res = numeric(z); - return true; + // otherwise: a is integer + return integer_rational_power_of_mpz(res, a, b); } + // for a^b return c,d such that a^b = c*d^b // only for MPZ/MPQ base and MPQ exponent void rational_power_parts(const numeric& a_orig, const numeric& b_orig, @@ -1847,17 +1820,6 @@ const ex numeric::power(const numeric &exponent) const { // any PyObjects castable to long are casted if (exponent.t == PYOBJECT) { -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(exponent.v._pyobject)) { - long si = PyInt_AsLong(exponent.v._pyobject); - if (si == -1 and PyErr_Occurred()) - PyErr_Clear(); - else { - expo.t = MPZ; - mpz_set_si(expo.v._bigint, si); - } - } else -#endif if (PyLong_Check(exponent.v._pyobject)) { expo.t = MPZ; _mpz_set_pylong(expo.v._bigint, @@ -2484,49 +2446,6 @@ numeric & operator/=(numeric & lh, const numeric & rh) return lh; case PYOBJECT: { PyObject *p = lh.v._pyobject; -#if PY_MAJOR_VERSION < 3 - { - if (PyInt_Check(p)) { - if (PyInt_Check(rh.v._pyobject)) { - // This branch happens at startup. - lh.v._pyobject = PyNumber_TrueDivide(Integer(PyInt_AsLong(p)), - Integer(PyInt_AsLong(rh.v._pyobject))); - // I don't 100% understand why I have to incref this, - // but if I don't, Sage crashes on exit. - if (lh.v._pyobject == nullptr) { - lh.v._pyobject = p; - py_error("numeric operator/="); - } - lh.hash = PyObject_Hash(lh.v._pyobject); - Py_DECREF(p); - return lh; - } - if (PyLong_Check(rh.v._pyobject)) { - PyObject *d = py_funcs.py_integer_from_python_obj(rh.v._pyobject); - lh.v._pyobject = PyNumber_TrueDivide(p, d); - if (lh.v._pyobject == nullptr) { - lh.v._pyobject = p; - py_error("numeric operator/="); - } - lh.hash = PyObject_Hash(lh.v._pyobject); - Py_DECREF(d); - Py_DECREF(p); - return lh; - } - } else if (PyLong_Check(p)) { - PyObject *n = py_funcs.py_integer_from_python_obj(p); - lh.v._pyobject = PyNumber_TrueDivide(n, rh.v._pyobject); - if (lh.v._pyobject == nullptr) { - lh.v._pyobject = p; - py_error("numeric operator/="); - } - lh.hash = PyObject_Hash(lh.v._pyobject); - Py_DECREF(n); - Py_DECREF(p); - return lh; - } - } -#else { if (PyLong_Check(p)) { PyObject *n = py_funcs.py_integer_from_python_obj(p); @@ -2541,7 +2460,7 @@ numeric & operator/=(numeric & lh, const numeric & rh) return lh; } } -#endif + lh.v._pyobject = PyNumber_TrueDivide(p, rh.v._pyobject); if (lh.v._pyobject == nullptr) { lh.v._pyobject = p; diff --git a/src/sage/symbolic/integration/__init__.py b/src/sage/symbolic/integration/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/geometry/polyhedron/__init__.py b/src/sage/symbolic/integration/all.py similarity index 100% rename from src/sage/geometry/polyhedron/__init__.py rename to src/sage/symbolic/integration/all.py diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index 0760f20920b..1e242c3f442 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -3,7 +3,7 @@ TESTS:: sage: from sage.symbolic.integration.external import sympy_integrator - sage: sympy_integrator(sin(x), x) + sage: sympy_integrator(sin(x), x) # needs sympy -cos(x) """ from sage.symbolic.expression import Expression @@ -54,9 +54,9 @@ def sympy_integrator(expression, v, a=None, b=None): EXAMPLES:: sage: from sage.symbolic.integration.external import sympy_integrator - sage: sympy_integrator(sin(x), x) + sage: sympy_integrator(sin(x), x) # needs sympy -cos(x) - sage: sympy_integrator(cos(x), x) + sage: sympy_integrator(cos(x), x) # needs sympy sin(x) """ import sympy @@ -117,7 +117,8 @@ def mma_free_integrator(expression, v, a=None, b=None): input = "Integrate[{},{}]".format(math_expr, variable) elif a is not None and b is not None: input = "Integrate[{},{{{},{},{}}}]".format(math_expr, variable, - a._mathematica_init_(), b._mathematica_init_()) + a._mathematica_init_(), + b._mathematica_init_()) else: raise ValueError('a(={}) and b(={}) should be both None' ' or both defined'.format(a, b)) @@ -135,14 +136,15 @@ def fricas_integrator(expression, v, a=None, b=None, noPole=True): EXAMPLES:: - sage: from sage.symbolic.integration.external import fricas_integrator # optional - fricas - sage: fricas_integrator(sin(x), x) # optional - fricas + sage: # optional - fricas + sage: from sage.symbolic.integration.external import fricas_integrator + sage: fricas_integrator(sin(x), x) -cos(x) - sage: fricas_integrator(cos(x), x) # optional - fricas + sage: fricas_integrator(cos(x), x) sin(x) - sage: fricas_integrator(1/(x^2-2), x, 0, 1) # optional - fricas + sage: fricas_integrator(1/(x^2-2), x, 0, 1) -1/8*sqrt(2)*(log(2) - log(-24*sqrt(2) + 34)) - sage: fricas_integrator(1/(x^2+6), x, -oo, oo) # optional - fricas + sage: fricas_integrator(1/(x^2+6), x, -oo, oo) 1/6*sqrt(6)*pi TESTS: @@ -252,8 +254,8 @@ def giac_integrator(expression, v, a=None, b=None): result = ex.integrate(v._giac_(), a._giac_(), b._giac_()) if 'integrate' in format(result) or 'integration' in format(result): return expression.integrate(v, a, b, hold=True) - else: - return result._sage_() + return result._sage_() + def libgiac_integrator(expression, v, a=None, b=None): r""" diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index 34d96b1c731..e431e76a767 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -11,7 +11,8 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # ****************************************************************************` -from sage.symbolic.ring import SR, is_SymbolicVariable +from sage.structure.element import Expression +from sage.symbolic.ring import SR from sage.symbolic.function import BuiltinFunction ################################################################## @@ -113,7 +114,7 @@ def _eval_(self, f, x): -1/2*x^2*sgn(x) + 3/2*x^2 """ # Check for x - if not is_SymbolicVariable(x): + if not (isinstance(x, Expression) and x.is_symbol()): if len(x.variables()) == 1: nx = x.variables()[0] f = f * x.diff(nx) @@ -173,7 +174,7 @@ def _print_latex_(self, f, x): \int \frac{\tan\left(x\right)}{x}\,{d x} """ from sage.misc.latex import latex - if not is_SymbolicVariable(x): + if not (isinstance(x, Expression) and x.is_symbol()): dx_str = "{d \\left(%s\\right)}" % latex(x) else: dx_str = "{d %s}" % latex(x) @@ -236,7 +237,7 @@ def _eval_(self, f, x, a, b): -1 """ # Check for x - if not is_SymbolicVariable(x): + if not (isinstance(x, Expression) and x.is_symbol()): if len(x.variables()) == 1: nx = x.variables()[0] f = f * x.diff(nx) @@ -346,7 +347,7 @@ def _print_latex_(self, f, x, a, b): \int_{0}^{1} \frac{\tan\left(x\right)}{x}\,{d x} """ from sage.misc.latex import latex - if not is_SymbolicVariable(x): + if not (isinstance(x, Expression) and x.is_symbol()): dx_str = "{d \\left(%s\\right)}" % latex(x) else: dx_str = "{d %s}" % latex(x) @@ -361,9 +362,9 @@ def _sympy_(self, f, x, a, b): EXAMPLES:: - sage: integral(x, x, 0, 1, hold=True)._sympy_() + sage: integral(x, x, 0, 1, hold=True)._sympy_() # needs sympy Integral(x, (x, 0, 1)) - sage: _.doit() + sage: _.doit() # needs sympy 1/2 """ from sympy.integrals import Integral @@ -618,12 +619,12 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False): sage: integrate(x*sin(log(x)), x) -1/5*x^2*(cos(log(x)) - 2*sin(log(x))) - sage: integrate(x*sin(log(x)), x, algorithm='sympy') + sage: integrate(x*sin(log(x)), x, algorithm='sympy') # needs sympy -1/5*x^2*cos(log(x)) + 2/5*x^2*sin(log(x)) sage: _ = var('y, z') sage: (x^y - z).integrate(y) -y*z + x^y/log(x) - sage: (x^y - z).integrate(y, algorithm="sympy") + sage: (x^y - z).integrate(y, algorithm="sympy") # needs sympy -y*z + cases(((log(x) != 0, x^y/log(x)), (1, y))) We integrate the above function in Maple now:: @@ -662,9 +663,7 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False): where the default integrator obtains another answer:: - sage: result = integrate(f(x), x) - ... - sage: result + sage: integrate(f(x), x) # long time 1/8*sqrt(x)*gamma(1/4)*gamma(-1/4)^2*hypergeometric((-1/4, -1/4, 1/4), (1/2, 3/4), -1/x^2)/(pi*gamma(3/4)) The following definite integral is not found by maxima:: @@ -682,7 +681,7 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False): sage: integrate(f(x), x, 1, 2, algorithm="fricas") # optional - fricas -1/2*pi + arctan(8) + arctan(5) + arctan(2) + arctan(1/2) - sage: integrate(f(x), x, 1, 2, algorithm="sympy") + sage: integrate(f(x), x, 1, 2, algorithm="sympy") # needs sympy -1/2*pi + arctan(8) + arctan(5) + arctan(2) + arctan(1/2) Using Giac to integrate the absolute value of a trigonometric expression:: @@ -742,14 +741,14 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False): sage: _ = var('x,y') sage: f = log(x^2+y^2) - sage: res = integral(f,x,0.0001414, 1.); res + sage: res = integral(f,x,1414/10^7, 1); res Traceback (most recent call last): ... - ValueError: Computation failed since Maxima requested additional constraints; using the 'assume' command before evaluation *may* help (example of legal syntax is 'assume(50015104*y^2-50015103>0)', see `assume?` for more details) - Is 50015104*y^2-50015103 positive, negative or zero? + ValueError: Computation failed since Maxima requested additional constraints; using the 'assume' command before evaluation *may* help ... + Is ... positive, negative or zero? sage: assume(y>1) - sage: res = integral(f,x,0.0001414, 1.); res - 2*y*arctan(1.0/y) - 2*y*arctan(0.0001414/y) + 1.0*log(1.0*y^2 + 1.0) - 0.0001414*log(1.0*y^2 + 1.9993959999999997e-08) - 1.9997172 + sage: res = integral(f,x,1414/10^7, 1); res + -2*y*arctan(707/5000000/y) + 2*y*arctan(1/y) + log(y^2 + 1) - 707/5000000*log(y^2 + 499849/25000000000000) - 4999293/2500000 sage: nres = numerical_integral(f.subs(y=2), 0.0001414, 1.); nres (1.4638323264144..., 1.6251803529759...e-14) sage: res.subs(y=2).n() @@ -857,7 +856,7 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False): Verify that MinusInfinity works with sympy (:trac:`12345`):: - sage: integral(1/x^2, x, -infinity, -1, algorithm='sympy') + sage: integral(1/x^2, x, -infinity, -1, algorithm='sympy') # needs sympy 1 Check that :trac:`11737` is fixed:: diff --git a/src/sage/symbolic/maxima_wrapper.py b/src/sage/symbolic/maxima_wrapper.py index 76a0de446ad..ca30af3efcf 100644 --- a/src/sage/symbolic/maxima_wrapper.py +++ b/src/sage/symbolic/maxima_wrapper.py @@ -5,7 +5,7 @@ # Copyright (C) 2010 Burcin Erocal <burcin@erocal.org> # Distributed under the terms of the GNU General Public License (GPL), # version 2 or any later version. The full text of the GPL is available at: -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ############################################################################### from sage.structure.sage_object import SageObject @@ -158,4 +158,4 @@ def _repr_(self): sage: u._repr_() 'MaximaWrapper(log(sqrt(2) + 1) + log(sqrt(2) - 1))' """ - return "MaximaWrapper(%s)"%(self._exp) + return "MaximaWrapper(%s)" % (self._exp) diff --git a/src/sage/symbolic/operators.py b/src/sage/symbolic/operators.py index a48b0e8e393..738f792f853 100644 --- a/src/sage/symbolic/operators.py +++ b/src/sage/symbolic/operators.py @@ -1,7 +1,8 @@ "Operators" import operator -from sage.symbolic.ring import is_SymbolicVariable, SR + +from sage.structure.element import Expression def add_vararg(first, *rest): @@ -63,12 +64,13 @@ def mul_vararg(first, *rest): operator.floordiv: '//', operator.pow: '^'} -relation_operators = {operator.eq:'==', - operator.lt:'<', - operator.gt:'>', - operator.ne:'!=', - operator.le:'<=', - operator.ge:'>='} +relation_operators = {operator.eq: '==', + operator.lt: '<', + operator.gt: '>', + operator.ne: '!=', + operator.le: '<=', + operator.ge: '>='} + class FDerivativeOperator(): r""" @@ -123,7 +125,7 @@ def __call__(self, *args): D[0](f)(1) """ - if (not all(is_SymbolicVariable(x) for x in args) or + if (not all(isinstance(x, Expression) and x.is_symbol() for x in args) or len(args) != len(set(args))): # An evaluated derivative of the form f'(1) is not a # symbolic variable, yet we would like to treat it @@ -131,6 +133,8 @@ def __call__(self, *args): # temporary variable e.g. `t0` and then evaluate the # derivative f'(t0) symbolically at t0=1. See trac # #12796. + from sage.symbolic.ring import SR + temp_args = SR.temp_var(n=len(args)) vars = [temp_args[i] for i in self._parameter_set] return self._f(*temp_args).diff(*vars).function(*temp_args)(*args) @@ -169,6 +173,8 @@ def change_function(self, new): Return a new function derivative operator with the same parameter set but for a new function. + EXAMPLES:: + sage: from sage.symbolic.operators import FDerivativeOperator sage: f = function('foo') sage: b = function('bar') @@ -194,3 +200,69 @@ def parameter_set(self): [0, 1] """ return self._parameter_set + + +class DerivativeOperator(): + """ + Derivative operator. + + Acting with this operator onto a function gives a new operator (of + type :class:`FDerivativeOperator`) representing the function + differentiated with respect to one or multiple of its arguments. + + This operator takes a list of indices specifying the position of + the arguments to differentiate. For example, D[0, 0, 1] is an + operator that differentiates a function twice with respect to its + first argument and once with respect to its second argument. + + EXAMPLES:: + + sage: x, y = var('x,y'); f = function('f') + sage: D[0](f)(x) + diff(f(x), x) + sage: D[0](f)(x, y) + diff(f(x, y), x) + sage: D[0, 1](f)(x, y) + diff(f(x, y), x, y) + sage: D[0, 1](f)(x, x^2) + D[0, 1](f)(x, x^2) + + """ + class DerivativeOperatorWithParameters(): + def __init__(self, parameter_set): + self._parameter_set = parameter_set + + def __call__(self, function): + return FDerivativeOperator(function, self._parameter_set) + + def __repr__(self): + """ + Return the string representation of this derivative operator. + + EXAMPLES:: + + sage: D[0] + D[0] + sage: D[0, 1] + D[0, 1] + """ + return "D[%s]" % (", ".join(map(repr, self._parameter_set))) + + def __getitem__(self, args): + """ + TESTS: + + The order in which the indices are given should not matter:: + + sage: x, y = var('x,y'); f = function('f') + sage: bool(D[0, 1, 0](f)(x, y) == D[0, 0, 1](f)(x, y)) + True + sage: bool(D[1, 0, 0](f)(x, y) == D[0, 0, 1](f)(x, y)) + True + """ + if not isinstance(args, tuple): + args = (args,) + return self.DerivativeOperatorWithParameters(args) + + +D = DerivativeOperator() diff --git a/src/sage/symbolic/pynac.pxi b/src/sage/symbolic/pynac.pxi index e6ab54f4e0b..09f0ad032d5 100644 --- a/src/sage/symbolic/pynac.pxi +++ b/src/sage/symbolic/pynac.pxi @@ -3,8 +3,9 @@ Declarations for pynac, a Python frontend for ginac Check that we can externally cimport this (:trac:`18825`):: - sage: cython(''' # long time; random compiler warnings # optional - sage.misc.cython - ....: from sage.symbolic cimport expression + sage: cython( # needs sage.misc.cython + ....: ''' + ....: cimport sage.symbolic.expression ....: ''') """ diff --git a/src/sage/symbolic/pynac_constant.py b/src/sage/symbolic/pynac_constant.py index 01d60ae4863..080cc7637be 100644 --- a/src/sage/symbolic/pynac_constant.py +++ b/src/sage/symbolic/pynac_constant.py @@ -2,7 +2,7 @@ Wrapper around Pynac's constants """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 William Stein <wstein@gmail.com> # Copyright (C) 2008 Burcin Erocal <burcin@erocal.org> # Copyright (C) 2009 Mike Hansen <mhansen@gmail.com> @@ -11,8 +11,8 @@ # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.lazy_import import lazy_import lazy_import('sage.symbolic.expression', 'PynacConstant', deprecation=32386) diff --git a/src/sage/symbolic/pynac_impl.pxi b/src/sage/symbolic/pynac_impl.pxi index fe9451d668d..68c31dcfde7 100644 --- a/src/sage/symbolic/pynac_impl.pxi +++ b/src/sage/symbolic/pynac_impl.pxi @@ -35,6 +35,9 @@ Pynac interface from cpython cimport * from libc cimport math +from sage.arith.misc import bernoulli, factorial, GCD as gcd, is_prime +from sage.arith.functions import lcm +from sage.cpython.string cimport str_to_bytes, char_to_str from sage.ext.stdsage cimport PY_NEW from sage.libs.gmp.all cimport * from sage.libs.gsl.types cimport * @@ -42,15 +45,7 @@ from sage.libs.gsl.complex cimport * from sage.libs.gsl.gamma cimport gsl_sf_lngamma_complex_e from sage.libs.mpmath import utils as mpmath_utils from sage.libs.pari.all import pari - -from sage.cpython.string cimport str_to_bytes, char_to_str - -from sage.arith.all import gcd, lcm, is_prime, factorial, bernoulli - -from sage.structure.coerce cimport coercion_model -from sage.structure.element cimport Element, parent from sage.misc.persist import loads, dumps - from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer, smallInteger from sage.rings.rational cimport Rational @@ -58,10 +53,10 @@ from sage.rings.real_mpfr import RR, RealField from sage.rings.rational cimport rational_power_parts from sage.rings.real_double cimport RealDoubleElement from sage.rings.cc import CC - +from sage.structure.coerce cimport coercion_model +from sage.structure.element cimport Element, parent from sage.symbolic.function cimport Function - ################################################################# # Symbolic function helpers ################################################################# @@ -1877,7 +1872,7 @@ cdef py_atan2(x, y): sage: atan2(RDF(-3), RDF(-1)) -1.8925468811915387 """ - from sage.symbolic.constants import pi, NaN + from sage.symbolic.constants import I, pi, NaN P = coercion_model.common_parent(x, y) if P is ZZ: P = RR @@ -2369,51 +2364,6 @@ cdef mpq_ptr py_mpq_from_rational(x): return <mpq_ptr>((<Rational>x).value) -symbol_table = {'functions': {}} - - -def register_symbol(obj, conversions, nargs=None): - """ - Add an object to the symbol table, along with how to convert it to - other systems such as Maxima, Mathematica, etc. This table is used - to convert *from* other systems back to Sage. - - INPUT: - - - `obj` -- a symbolic object or function. - - - `conversions` -- a dictionary of conversions, where the keys - are the names of interfaces (e.g., - 'maxima'), and the values are the string - representation of obj in that system. - - - ``nargs`` -- optional number of arguments. For most functions, - this can be deduced automatically. - - EXAMPLES:: - - sage: from sage.symbolic.expression import register_symbol as rs - sage: rs(SR(5),{'maxima':'five'}) - sage: SR(maxima_calculus('five')) - 5 - """ - conversions = dict(conversions) - try: - conversions['sage'] = obj.name() - except AttributeError: - pass - if nargs is None: - try: - nargs = obj.number_of_arguments() - except AttributeError: - nargs = -1 # meaning unknown number of arguments - for system, name in conversions.iteritems(): - system_table = symbol_table.get(system, None) - if system_table is None: - symbol_table[system] = system_table = {} - system_table[(name, nargs)] = obj - - import sage.rings.integer ginac_pyinit_Integer(sage.rings.integer.Integer) @@ -2421,22 +2371,21 @@ import sage.rings.real_double ginac_pyinit_Float(sage.rings.real_double.RDF) cdef Element pynac_I -I = None def init_pynac_I(): """ - Initialize the numeric I object in pynac. We use the generator of QQ(i). + Initialize the numeric ``I`` object in pynac. We use the generator of ``QQ(i)``. EXAMPLES:: - sage: from sage.symbolic.expression import I as symbolic_I + sage: from sage.symbolic.constants import I as symbolic_I sage: symbolic_I I sage: symbolic_I^2 -1 - Note that conversions to real fields will give TypeErrors:: + Note that conversions to real fields will give :class:`TypeError`:: sage: float(symbolic_I) Traceback (most recent call last): @@ -2484,22 +2433,22 @@ def init_pynac_I(): sage: maxima(2*symbolic_I) 2*%i - TESTS: + TESTS:: sage: repr(symbolic_I) 'I' sage: latex(symbolic_I) i - sage: sage.symbolic.expression.init_pynac_I() - sage: type(sage.symbolic.expression.I) + sage: I = sage.symbolic.expression.init_pynac_I() + sage: type(I) <class 'sage.symbolic.expression.Expression'> - sage: type(sage.symbolic.expression.I.pyobject()) + sage: type(I.pyobject()) <class 'sage.rings.number_field.number_field_element_quadratic.NumberFieldElement_gaussian'> Check that :trac:`10064` is fixed:: - sage: y = symbolic_I*symbolic_I*x / x # so y is the expression -1 + sage: y = symbolic_I*symbolic_I*x / x # so y is the expression -1 sage: y.is_positive() False sage: z = -x / x @@ -2513,12 +2462,12 @@ def init_pynac_I(): sage: x * ((3*I + 4)*x - 5) ((3*I + 4)*x - 5)*x """ - global pynac_I, I + global pynac_I from sage.rings.number_field.number_field import GaussianField pynac_I = GaussianField().gen() ginac_pyinit_I(pynac_I) from .ring import SR - I = new_Expression_from_GEx(SR, g_I) + return new_Expression_from_GEx(SR, g_I) def init_function_table(): @@ -2614,6 +2563,5 @@ def init_function_table(): init_function_table() -init_pynac_I() set_ginac_fn_serial() diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index acc7d097a4e..ebed9407776 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -8,7 +8,7 @@ # Copyright (C) 2008 Burcin Erocal <burcin@erocal.org> # Distributed under the terms of the GNU General Public License (GPL), # version 2 or any later version. The full text of the GPL is available at: -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ############################################################################### @@ -22,9 +22,10 @@ from sage.functions.hypergeometric import hypergeometric from sage.functions.other import (cases, element_of) -################################################################### -### Generate random expressions for doctests ###################### -################################################################### + +############################################################## +# Generate random expressions for doctests # +############################################################## def _mk_full_functions(): r""" @@ -52,8 +53,9 @@ def _mk_full_functions(): return [(1.0, f, f.number_of_arguments()) for (name, f) in items if hasattr(f, 'number_of_arguments') and - f.number_of_arguments() > 0 and - f not in excluded] + f.number_of_arguments() > 0 and + f not in excluded] + # For creating simple expressions @@ -73,6 +75,7 @@ def _mk_full_functions(): full_internal = [(0.6, full_binary, 2), (0.2, full_unary, 1), (0.2, full_functions)] + def normalize_prob_list(pl, extra=()): r""" INPUT: @@ -118,11 +121,12 @@ def normalize_prob_list(pl, extra=()): if isinstance(val, list): norm_val = normalize_prob_list(val, extra=p_extra) for np in norm_val: - result.append(((prob/total)*np[0], np[1]) + np[2:]) + result.append(((prob / total) * np[0], np[1]) + np[2:]) else: - result.append(((prob/total), val) + p_extra) + result.append(((prob / total), val) + p_extra) return result + def choose_from_prob_list(lst): r""" INPUT: @@ -155,12 +159,13 @@ def choose_from_prob_list(lst): ....: more_samples() """ r = random() - for i in range(len(lst)-1): + for i in range(len(lst) - 1): if r < lst[i][0]: return lst[i] r -= lst[i][0] return lst[-1] + def random_integer_vector(n, length): r""" Give a random list of length *length*, consisting of nonnegative @@ -210,10 +215,11 @@ def random_integer_vector(n, length): return [n] elif length == 2: v = randint(0, n) - return [v, n-v] + return [v, n - v] else: - v = randint(0, 2*n//length) - return [v] + random_integer_vector(n-v, length-1) + v = randint(0, 2 * n // length) + return [v] + random_integer_vector(n - v, length - 1) + def random_expr_helper(n_nodes, internal, leaves, verbose): r""" @@ -256,11 +262,13 @@ def random_expr_helper(n_nodes, internal, leaves, verbose): if n_spare_nodes <= 0: n_spare_nodes = 0 nodes_per_child = random_integer_vector(n_spare_nodes, n_children) - children = [random_expr_helper(n+1, internal, leaves, verbose) for n in nodes_per_child] + children = [random_expr_helper(n + 1, internal, leaves, verbose) + for n in nodes_per_child] if verbose: print("About to apply %r to %r" % (r[1], children)) return r[1](*children) + def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5, internal=full_internal, nullary=full_nullary, nullary_frac=0.2, @@ -295,8 +303,8 @@ def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5, sage: my_internal = [(0.6, full_binary, 2), (0.2, full_unary, 1), ....: (0.2, [(1.0,f,f.number_of_arguments()) for f in some_functions])] sage: set_random_seed(1) - sage: random_expr(50, nvars=3, internal=my_internal, - ....: coeff_generator=CDF.random_element) # not tested # known bug + sage: random_expr(50, nvars=3, internal=my_internal, # not tested # known bug + ....: coeff_generator=CDF.random_element) (v1^(0.9713408427702117 + 0.195868299334218*I)/cot(-pi + v1^2 + v3) + tan(arctan(v2 + arctan2(-0.35859061674557324 + 0.9407509502498164*I, v3) - 0.8419115504372718 + 0.30375717982404615*I) + arctan2((0.2275357305882964 - 0.8258002386106038*I)/factorial(v2), -v3 - 0.7604559947718565 - 0.5543672548552057*I) + ceil(1/arctan2(v1, v1))))/v2 sage: random_expr(5, verbose=True) # not tested # known bug About to apply <built-in function inv> to [31] @@ -305,7 +313,7 @@ def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5, sgn(v1) + 1/31 """ - vars = [(1.0, SR.var('v%d' % (n+1))) for n in range(nvars)] + vars = [(1.0, SR.var('v%d' % (n + 1))) for n in range(nvars)] if ncoeffs is None: ncoeffs = size coeffs = [(1.0, coeff_generator()) for _ in range(ncoeffs)] @@ -317,9 +325,9 @@ def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5, return random_expr_helper(size, internal, leaves, verbose) -################################################################### -### Test the ordering of operands ################################# -################################################################### +##################################### +# Test the ordering of operands # +##################################### def assert_strict_weak_order(a, b, c, cmp_func): r""" @@ -435,7 +443,7 @@ def test_symbolic_expression_order(repetitions=100): nullary_frac = 0.05 def coeff_generator(): - return randint(-100,100)/randint(1,100) + return randint(-100, 100) / randint(1, 100) def make_random_expr(): while True: @@ -452,5 +460,5 @@ def make_random_expr(): b = make_random_expr() c = make_random_expr() assert_strict_weak_order(a, b, c, mixed_order) - assert_strict_weak_order(a, b, c, lambda x,y: x._cmp_add(y)) - assert_strict_weak_order(a, b, c, lambda x,y: x._cmp_mul(y)) + assert_strict_weak_order(a, b, c, lambda x, y: x._cmp_add(y)) + assert_strict_weak_order(a, b, c, lambda x, y: x._cmp_mul(y)) diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index b8896a94be9..ea3f5b170ea 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -357,7 +357,7 @@ - William Stein (2007-07-16): added arithmetic with symbolic equations """ - +from itertools import product import operator @@ -502,7 +502,7 @@ def test_relation_maxima(relation): except TypeError: raise ValueError("unable to evaluate the predicate '%s'" % repr(relation)) - elif relation.operator() == operator.ne: # operator is not equal + elif relation.operator() == operator.ne: # operator is not equal try: s = m.parent()._eval_line('is (notequal(%s,%s))' % (repr(m.lhs()), repr(m.rhs()))) @@ -518,7 +518,7 @@ def test_relation_maxima(relation): if s == 'true': return True elif s == 'false': - return False # if neither of these, s=='unknown' and we try a few other tricks + return False # if neither of these, s=='unknown' and we try a few other tricks if relation.operator() != operator.eq: return False @@ -657,7 +657,7 @@ def solve(f, *args, **kwds): equations, at times approximations will be given by Maxima, due to the underlying algorithm:: - sage: sols = solve([x^3==y,y^2==x], [x,y]); sols[-1], sols[0] + sage: sols = solve([x^3==y,y^2==x], [x,y]); sols[-1], sols[0] # abs tol 1e-15 ([x == 0, y == 0], [x == (0.3090169943749475 + 0.9510565162951535*I), y == (-0.8090169943749475 - 0.5877852522924731*I)]) @@ -930,8 +930,7 @@ def solve(f, *args, **kwds): A basic interface to Giac is provided:: sage: solve([(2/3)^x-2], [x], algorithm='giac') - ... - [[-log(2)/(log(3) - log(2))]] + ...[[-log(2)/(log(3) - log(2))]] sage: f = (sin(x) - 8*cos(x)*sin(x))*(sin(x)^2 + cos(x)) - (2*cos(x)*sin(x) - sin(x))*(-2*sin(x)^2 + 2*cos(x)^2 - cos(x)) sage: solve(f, x, algorithm='giac') @@ -1029,7 +1028,6 @@ def solve(f, *args, **kwds): TypeError: The first argument to solve() should be a symbolic expression or a list of symbolic expressions. """ - from sage.symbolic.ring import is_SymbolicVariable from sage.structure.element import Expression explicit_solutions = kwds.get('explicit_solutions', None) multiplicities = kwds.get('multiplicities', None) @@ -1066,7 +1064,7 @@ def solve(f, *args, **kwds): "symbolic expression or a list of symbolic " "expressions.") - if isinstance(f, Expression): # f is a single expression + if isinstance(f, Expression): # f is a single expression return _solve_expression(f, x, explicit_solutions, multiplicities, to_poly_solve, solution_dict, algorithm, domain) if not isinstance(f, (list, tuple)): @@ -1076,13 +1074,13 @@ def solve(f, *args, **kwds): if not args: raise TypeError("Please input variables to solve for.") - if is_SymbolicVariable(x): + if isinstance(x, Expression) and x.is_symbol(): variables = args else: variables = tuple(x) for v in variables: - if not is_SymbolicVariable(v): + if not (isinstance(v, Expression) and v.is_symbol()): raise TypeError("%s is not a valid variable." % repr(v)) try: @@ -1096,11 +1094,11 @@ def solve(f, *args, **kwds): if algorithm == 'sympy': from sympy import solve as ssolve from sage.interfaces.sympy import sympy_set_to_list - if isinstance(f, Expression): # f is a single expression + if isinstance(f, Expression): # f is a single expression sympy_f = f._sympy_() else: sympy_f = [s._sympy_() for s in f] - if is_SymbolicVariable(x): + if isinstance(f, Expression) and f.is_symbol(): sympy_vars = (x._sympy_(),) else: sympy_vars = tuple([v._sympy_() for v in x]) @@ -1147,27 +1145,27 @@ def solve(f, *args, **kwds): else: raise - if len(s) == 0: # if Maxima's solve gave no solutions, try its to_poly_solve + if len(s) == 0: # if Maxima's solve gave no solutions, try its to_poly_solve try: s = m.to_poly_solve(variables) - except Exception: # if that gives an error, stick with no solutions + except Exception: # if that gives an error, stick with no solutions s = [] - if len(s) == 0: # if to_poly_solve gave no solutions, try use_grobner + if len(s) == 0: # if to_poly_solve gave no solutions, try use_grobner try: s = m.to_poly_solve(variables, 'use_grobner=true') - except Exception: # if that gives an error, stick with no solutions + except Exception: # if that gives an error, stick with no solutions s = [] sol_list = string_to_list_of_solutions(repr(s)) # Relaxed form suggested by Mike Hansen (#8553): if kwds.get('solution_dict', None): - if not sol_list: # fixes IndexError on empty solution list (#8553) + if not sol_list: # fixes IndexError on empty solution list (#8553) return [] if isinstance(sol_list[0], list): sol_dict = [{eq.left(): eq.right() for eq in solution} - for solution in sol_list] + for solution in sol_list] else: sol_dict = [{eq.left(): eq.right()} for eq in sol_list] @@ -1177,7 +1175,7 @@ def solve(f, *args, **kwds): def _solve_expression(f, x, explicit_solutions, multiplicities, - to_poly_solve, solution_dict, algorithm, domain): + to_poly_solve, solution_dict, algorithm, domain): """ Solve an expression ``f``. For more information, see :func:`solve`. @@ -1269,13 +1267,14 @@ def _solve_expression(f, x, explicit_solutions, multiplicities, sage: solve([x==3], [x], solution_dict=True, algorithm='sympy') [{x: 3}] """ - from sage.symbolic.ring import is_SymbolicVariable + from sage.structure.element import Expression + if f.is_relational(): if f.operator() is not operator.eq: if algorithm == 'sympy': from sympy import S, solveset from sage.interfaces.sympy import sympy_set_to_list - if is_SymbolicVariable(x): + if isinstance(x, Expression) and x.is_symbol(): sympy_vars = (x._sympy_(),) else: sympy_vars = tuple([v._sympy_() for v in x]) @@ -1306,14 +1305,14 @@ def has_integer_assumption(v): alist = assumptions() return any(isinstance(a, GenericDeclaration) and a.has(v) and a._assumption in ['even', 'odd', 'integer', 'integervalued'] - for a in alist) + for a in alist) if len(ex.variables()) and all(has_integer_assumption(var) for var in ex.variables()): return f.solve_diophantine(x, solution_dict=solution_dict) if algorithm == 'sympy': from sympy import S, solveset from sage.interfaces.sympy import sympy_set_to_list - if is_SymbolicVariable(x): + if isinstance(x, Expression) and x.is_symbol(): sympy_vars = (x._sympy_(),) else: sympy_vars = tuple([v._sympy_() for v in x]) @@ -1333,13 +1332,13 @@ def has_integer_assumption(v): m = ex._maxima_() P = m.parent() if explicit_solutions: - P.eval('solveexplicit: true') # switches Maxima to looking for only explicit solutions + P.eval('solveexplicit: true') # switches Maxima to looking for only explicit solutions try: if to_poly_solve != 'force': s = m.solve(x).str() - else: # omit Maxima's solve command + else: # omit Maxima's solve command s = str([]) - except TypeError as mess: # if Maxima's solve has an error, we catch it + except TypeError as mess: # if Maxima's solve has an error, we catch it if "Error executing code in Maxima" in str(mess): s = str([]) else: @@ -1357,9 +1356,9 @@ def has_integer_assumption(v): else: return ans - X = string_to_list_of_solutions(s) # our initial list of solutions + X = string_to_list_of_solutions(s) # our initial list of solutions - if multiplicities: # to_poly_solve does not return multiplicities, so in this case we end here + if multiplicities: # to_poly_solve does not return multiplicities, so in this case we end here if len(X) == 0: return X, [] else: @@ -1398,7 +1397,7 @@ def has_integer_assumption(v): "unable to make sense of Maxima expression" in \ str(mess): if not explicit_solutions: - X.append(eq) # we keep this implicit solution + X.append(eq) # we keep this implicit solution else: raise @@ -1566,14 +1565,11 @@ def solve_mod(eqns, modulus, solution_dict=False): [(0,)] sage: solve_mod([2*x^2+x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 1) [(0, 0)] - - """ from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.integer import Integer from sage.rings.integer_ring import crt_basis from sage.structure.element import Expression - from sage.misc.mrange import cartesian_product_iterator from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix @@ -1586,7 +1582,7 @@ def solve_mod(eqns, modulus, solution_dict=False): vars = list(set(sum([list(e.variables()) for e in eqns], []))) vars.sort(key=repr) - if modulus == 1: # degenerate case + if modulus == 1: # degenerate case ans = [tuple(Integers(1)(0) for v in vars)] return ans @@ -1605,17 +1601,15 @@ def solve_mod(eqns, modulus, solution_dict=False): ans = [] if has_solution: - for solution in cartesian_product_iterator(solutions): + for solution in product(*solutions): solution_mat = matrix(Integers(modulus), solution) ans.append(tuple(c.dot_product(crt_basis) for c in solution_mat.columns())) # if solution_dict == True: # Relaxed form suggested by Mike Hansen (#8553): if solution_dict: - sol_dict = [dict(zip(vars, solution)) for solution in ans] - return sol_dict - else: - return ans + return [dict(zip(vars, solution)) for solution in ans] + return ans def _solve_mod_prime_power(eqns, p, m, vars): @@ -1685,12 +1679,10 @@ def _solve_mod_prime_power(eqns, p, m, vars): sage: [sorted(_solve_mod_prime_power([x^2==41], 10, i, [x]))[0][0] for i in [1..13]] [1, 21, 71, 1179, 2429, 47571, 1296179, 8703821, 26452429, 526452429, 13241296179, 19473547571, 2263241296179] - """ from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.modules.free_module_element import vector - from sage.misc.mrange import cartesian_product_iterator mrunning = 1 ans = [] @@ -1700,10 +1692,10 @@ def _solve_mod_prime_power(eqns, p, m, vars): S = PolynomialRing(R, len(vars), vars) eqns_mod = [S(eq) for eq in eqns] if mi == 0: - possibles = cartesian_product_iterator([range(len(R)) for _ in range(len(vars))]) + possibles = product(*[range(len(R)) for _ in range(len(vars))]) else: - shifts = cartesian_product_iterator([range(p) for _ in range(len(vars))]) - pairs = cartesian_product_iterator([shifts, ans]) + shifts = product(*[range(p) for _ in range(len(vars))]) + pairs = product(shifts, ans) possibles = (tuple(vector(t) + vector(shift) * (mrunning // p)) for shift, t in pairs) ans = list(t for t in possibles if all(e(*t) == 0 for e in eqns_mod)) @@ -1788,8 +1780,8 @@ def solve_ineq_fourier(ineq, vars=None): sage: y = var('y') sage: solve_ineq_fourier([x+y<9,x-y>4],[x,y]) [[y + 4 < x, x < -y + 9, y < (5/2)]] - sage: solve_ineq_fourier([x+y<9,x-y>4],[y,x]) - [[y < min(x - 4, -x + 9)]] + sage: solve_ineq_fourier([x+y<9,x-y>4],[y,x])[0][0](x=42) + y < -33 sage: solve_ineq_fourier([x^2>=0]) [[x < +Infinity]] diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 20a576a3b5a..d45b88e24de 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -205,28 +205,20 @@ cdef class SymbolicRing(sage.rings.abc.SymbolicRing): return False else: - from sage.rings.real_mpfr import mpfr_prec_min - from sage.rings.fraction_field import is_FractionField - from sage.rings.real_mpfi import is_RealIntervalField - from sage.rings.real_arb import RealBallField - from sage.rings.complex_arb import ComplexBallField from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing - from sage.rings.polynomial.laurent_polynomial_ring import is_LaurentPolynomialRing - from sage.rings.complex_mpfr import ComplexField + from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.infinity import InfinityRing, UnsignedInfinityRing from sage.rings.real_lazy import RLF, CLF - from sage.rings.finite_rings.finite_field_base import is_FiniteField - - from sage.interfaces.maxima import Maxima + from sage.rings.finite_rings.finite_field_base import FiniteField from .subring import GenericSymbolicSubring if R._is_numerical(): # Almost anything with a coercion into any precision of CC return R not in (RLF, CLF) - elif is_PolynomialRing(R) or is_MPolynomialRing(R) or is_FractionField(R) or is_LaurentPolynomialRing(R): + elif is_PolynomialRing(R) or is_MPolynomialRing(R) or is_FractionField(R) or isinstance(R, LaurentPolynomialRing_generic): base = R.base_ring() return base is not self and self.has_coerce_map_from(base) elif (R is InfinityRing or R is UnsignedInfinityRing @@ -234,8 +226,8 @@ cdef class SymbolicRing(sage.rings.abc.SymbolicRing): sage.rings.abc.ComplexIntervalField, sage.rings.abc.RealBallField, sage.rings.abc.ComplexBallField, - sage.rings.abc.IntegerModRing)) - or is_FiniteField(R)): + sage.rings.abc.IntegerModRing, + FiniteField))): return True elif isinstance(R, GenericSymbolicSubring): return True @@ -873,7 +865,7 @@ cdef class SymbolicRing(sage.rings.abc.SymbolicRing): """ if isinstance(name, Expression): return name - if not isinstance(name, (basestring, list, tuple)): + if not isinstance(name, (str, list, tuple)): name = repr(name) is_multiple = False @@ -1140,7 +1132,7 @@ cdef class SymbolicRing(sage.rings.abc.SymbolicRing): :doc:`subring` """ if self is not SR: - raise NotImplementedError('Cannot create subring of %s.' % (self,)) + raise NotImplementedError('cannot create subring of %s' % (self,)) from .subring import SymbolicSubring return SymbolicSubring(*args, **kwds) @@ -1167,24 +1159,24 @@ cdef class NumpyToSRMorphism(Morphism): We check that :trac:`8949` and :trac:`9769` are fixed (see also :trac:`18076`):: - sage: import numpy + sage: import numpy # needs numpy sage: f(x) = x^2 - sage: f(numpy.int8('2')) + sage: f(numpy.int8('2')) # needs numpy 4 - sage: f(numpy.int32('3')) + sage: f(numpy.int32('3')) # needs numpy 9 Note that the answer is a Sage integer and not a numpy type:: - sage: a = f(numpy.int8('2')).pyobject() - sage: type(a) + sage: a = f(numpy.int8('2')).pyobject() # needs numpy + sage: type(a) # needs numpy <class 'sage.rings.integer.Integer'> This behavior also applies to standard functions:: sage: cos(int('2')) cos(2) - sage: numpy.cos(int('2')) + sage: numpy.cos(int('2')) # needs numpy -0.4161468365471424 """ cdef _intermediate_ring @@ -1200,6 +1192,7 @@ cdef class NumpyToSRMorphism(Morphism): EXAMPLES:: + sage: # needs numpy sage: import numpy sage: from sage.symbolic.ring import NumpyToSRMorphism sage: f = NumpyToSRMorphism(numpy.float64) @@ -1208,7 +1201,7 @@ cdef class NumpyToSRMorphism(Morphism): sage: _.parent() Symbolic Ring - sage: NumpyToSRMorphism(str) + sage: NumpyToSRMorphism(str) # needs numpy Traceback (most recent call last): ... TypeError: <... 'str'> is not a numpy number type @@ -1235,17 +1228,16 @@ cdef class NumpyToSRMorphism(Morphism): This should be called when coercing or converting a NumPy float or complex to the Symbolic Ring:: + sage: # needs numpy sage: import numpy sage: SR(numpy.int32('1')).pyobject().parent() Integer Ring sage: SR(numpy.int64('-2')).pyobject().parent() Integer Ring - sage: SR(numpy.float16('1')).pyobject().parent() Real Double Field sage: SR(numpy.float64('2.0')).pyobject().parent() Real Double Field - sage: SR(numpy.complex64(1jr)).pyobject().parent() Complex Double Field """ @@ -1260,6 +1252,7 @@ cdef class UnderscoreSageMorphism(Morphism): EXAMPLES:: + sage: # needs sympy sage: import sympy sage: from sage.symbolic.ring import UnderscoreSageMorphism sage: b = sympy.var('b') @@ -1282,9 +1275,9 @@ cdef class UnderscoreSageMorphism(Morphism): This should be called when coercing or converting a SymPy object to the Symbolic Ring:: - sage: import sympy - sage: b = sympy.var('b') - sage: bool(SR(b) == SR(b._sage_())) + sage: import sympy # needs sympy + sage: b = sympy.var('b') # needs sympy + sage: bool(SR(b) == SR(b._sage_())) # needs sympy True """ return self.codomain()(a._sage_()) diff --git a/src/sage/symbolic/series_impl.pxi b/src/sage/symbolic/series_impl.pxi index 18c017066f6..abac6155572 100644 --- a/src/sage/symbolic/series_impl.pxi +++ b/src/sage/symbolic/series_impl.pxi @@ -240,21 +240,21 @@ cdef class SymbolicSeries(Expression): """ if x is None: x = self.default_variable() - l = [[self.coefficient(x, d), d] for d in xrange(self.degree(x))] + l = [[self.coefficient(x, d), d] for d in range(self.degree(x))] if sparse: return l - else: - from sage.rings.integer_ring import ZZ - if any(not c[1] in ZZ for c in l): - raise ValueError("Cannot return dense coefficient list with noninteger exponents.") - val = l[0][1] - if val < 0: - raise ValueError("Cannot return dense coefficient list with negative valuation.") - deg = l[-1][1] - ret = [ZZ(0)] * int(deg+1) - for c in l: - ret[c[1]] = c[0] - return ret + + from sage.rings.integer_ring import ZZ + if any(not c[1] in ZZ for c in l): + raise ValueError("cannot return dense coefficient list with noninteger exponents") + val = l[0][1] + if val < 0: + raise ValueError("cannot return dense coefficient list with negative valuation") + deg = l[-1][1] + ret = [ZZ(0)] * int(deg+1) + for c in l: + ret[c[1]] = c[0] + return ret def power_series(self, base_ring): """ diff --git a/src/sage/symbolic/subring.py b/src/sage/symbolic/subring.py index e30e29a16cf..2db60e8f915 100644 --- a/src/sage/symbolic/subring.py +++ b/src/sage/symbolic/subring.py @@ -181,33 +181,33 @@ def create_key_and_extra_args( sage: SymbolicSubring.create_key_and_extra_args() Traceback (most recent call last): ... - ValueError: Cannot create a symbolic subring since nothing is specified. + ValueError: cannot create a symbolic subring since nothing is specified sage: SymbolicSubring.create_key_and_extra_args( ....: accepting_variables=('a',), rejecting_variables=('r',)) Traceback (most recent call last): ... - ValueError: Cannot create a symbolic subring since input is ambiguous. + ValueError: cannot create a symbolic subring since input is ambiguous sage: SymbolicSubring.create_key_and_extra_args( ....: accepting_variables=('a',), no_variables=True) Traceback (most recent call last): ... - ValueError: Cannot create a symbolic subring since input is ambiguous. + ValueError: cannot create a symbolic subring since input is ambiguous sage: SymbolicSubring.create_key_and_extra_args( ....: rejecting_variables=('r',), no_variables=True) Traceback (most recent call last): ... - ValueError: Cannot create a symbolic subring since input is ambiguous. + ValueError: cannot create a symbolic subring since input is ambiguous """ if accepting_variables is None and \ rejecting_variables is None and \ not no_variables: - raise ValueError('Cannot create a symbolic subring ' - 'since nothing is specified.') + raise ValueError('cannot create a symbolic subring ' + 'since nothing is specified') if accepting_variables is not None and rejecting_variables is not None or \ rejecting_variables is not None and no_variables or \ no_variables and accepting_variables is not None: - raise ValueError('Cannot create a symbolic subring ' - 'since input is ambiguous.') + raise ValueError('cannot create a symbolic subring ' + 'since input is ambiguous') if accepting_variables is not None: vars = tuple(accepting_variables) @@ -403,10 +403,6 @@ def _coerce_map_from_(self, P): sage: C.has_coerce_map_from(SR) # indirect doctest False """ - if P == SR: - # Workaround; can be deleted once #19231 is fixed - return False - from sage.rings.infinity import InfinityRing from sage.rings.qqbar import AA, QQbar from sage.rings.real_lazy import RLF, CLF @@ -414,18 +410,18 @@ def _coerce_map_from_(self, P): if isinstance(P, type): return SR._coerce_map_from_(P) - elif RLF.has_coerce_map_from(P) or \ - CLF.has_coerce_map_from(P) or \ - AA.has_coerce_map_from(P) or \ - QQbar.has_coerce_map_from(P): + if RLF.has_coerce_map_from(P) or \ + CLF.has_coerce_map_from(P) or \ + AA.has_coerce_map_from(P) or \ + QQbar.has_coerce_map_from(P): return True - elif (P is InfinityRing or - isinstance(P, (sage.rings.abc.RealIntervalField, - sage.rings.abc.ComplexIntervalField))): + if (P is InfinityRing or + isinstance(P, (sage.rings.abc.RealIntervalField, + sage.rings.abc.ComplexIntervalField))): return True - elif P._is_numerical(): + if P._is_numerical(): return P not in (RLF, CLF, AA, QQbar) def __eq__(self, other): @@ -608,7 +604,7 @@ def __eq__(self, other): sage: F == F True """ - return type(self) == type(other) and self.vars == other.vars + return type(self) is type(other) and self.vars == other.vars def __ne__(self, other): r""" @@ -771,7 +767,7 @@ def merge(self, other): """ if self == other: return self - elif type(self) == type(other): + elif type(self) is type(other): return type(self)(self.vars | other.vars) elif isinstance(other, SymbolicSubringRejectingVarsFunctor): if not (self.vars & other.vars): @@ -972,7 +968,7 @@ def merge(self, other): """ if self == other: return self - elif type(self) == type(other): + elif type(self) is type(other): return type(self)(self.vars & other.vars) elif isinstance(other, SymbolicSubringAcceptingVarsFunctor): if not (self.vars & other.vars): diff --git a/src/sage/symbolic/substitution_map.py b/src/sage/symbolic/substitution_map.py index 7dbdd6d5178..a883d3aecb0 100644 --- a/src/sage/symbolic/substitution_map.py +++ b/src/sage/symbolic/substitution_map.py @@ -7,15 +7,15 @@ back to Python. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Volker Braun <vbraun.name@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.lazy_import import lazy_import lazy_import('sage.symbolic.expression', ('SubstitutionMap', 'make_map'), deprecation=32386) diff --git a/src/sage/symbolic/substitution_map_impl.pxi b/src/sage/symbolic/substitution_map_impl.pxi index d53b9971c6e..ea60e899d1a 100644 --- a/src/sage/symbolic/substitution_map_impl.pxi +++ b/src/sage/symbolic/substitution_map_impl.pxi @@ -29,13 +29,13 @@ cdef class SubstitutionMap(SageObject): Apply the substitution to a symbolic expression EXAMPLES:: - + sage: from sage.symbolic.expression import make_map sage: subs = make_map({x:x+1}) sage: subs.apply_to(x^2, 0) (x + 1)^2 """ - return new_Expression_from_GEx(expr._parent, + return new_Expression_from_GEx(expr._parent, expr._gobj.subs_map(self._gmapobj, options)) def _repr_(self): @@ -43,7 +43,7 @@ cdef class SubstitutionMap(SageObject): Return the string representation EXAMPLES:: - + sage: from sage.symbolic.expression import make_map sage: make_map({x:x+1}) SubsMap @@ -94,4 +94,4 @@ cpdef SubstitutionMap make_map(subs_dict): smap.insert(make_pair((<Expression>k)._gobj, (<Expression>v)._gobj)) return new_SubstitutionMap_from_GExMap(smap) - + diff --git a/src/sage/symbolic/symbols.py b/src/sage/symbolic/symbols.py new file mode 100644 index 00000000000..7fe7cdb4472 --- /dev/null +++ b/src/sage/symbolic/symbols.py @@ -0,0 +1,55 @@ +r""" +Symbol table +""" +# **************************************************************************** +# Copyright (C) 2009 Mike Hansen +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +symbol_table = {'functions': {}} + + +def register_symbol(obj, conversions, nargs=None): + """ + Add an object to the symbol table, along with how to convert it to + other systems such as Maxima, Mathematica, etc. This table is used + to convert *from* other systems back to Sage. + + INPUT: + + - ``obj`` -- a symbolic object or function. + + - ``conversions`` -- a dictionary of conversions, where the keys + are the names of interfaces (e.g., ``'maxima'``), and the values + are the string representation of ``obj`` in that system. + + - ``nargs`` -- optional number of arguments. For most functions, + this can be deduced automatically. + + EXAMPLES:: + + sage: from sage.symbolic.symbols import register_symbol as rs + sage: rs(SR(5), {'maxima': 'five'}) # needs sage.symbolic + sage: SR(maxima_calculus('five')) # needs sage.symbolic + 5 + """ + conversions = dict(conversions) + try: + conversions['sage'] = obj.name() + except AttributeError: + pass + if nargs is None: + try: + nargs = obj.number_of_arguments() + except AttributeError: + nargs = -1 # meaning unknown number of arguments + for system, name in conversions.items(): + system_table = symbol_table.get(system, None) + if system_table is None: + symbol_table[system] = system_table = {} + system_table[(name, nargs)] = obj diff --git a/src/sage/symbolic/symengine.py b/src/sage/symbolic/symengine.py index 123eb51b824..5c3a46eb8b0 100644 --- a/src/sage/symbolic/symengine.py +++ b/src/sage/symbolic/symengine.py @@ -1,16 +1,18 @@ r""" EXAMPLES:: - sage: import symengine # optional - symengine_py - sage: x, y = symengine.var("x y") # optional - symengine_py - sage: expr = (x + symengine.GoldenRatio * symengine.exp(y))**2 # optional - symengine_py - sage: SR(expr) # optional - symengine_py + sage: # optional - symengine_py + sage: import symengine + sage: x, y = symengine.var("x y") + sage: expr = (x + symengine.GoldenRatio * symengine.exp(y))**2 + sage: SR(expr) (golden_ratio*e^y + x)^2 - sage: f = symengine.Lambdify([x, y], expr) # optional - symengine_py - sage: f(3, 5) # optional - symengine_py + sage: # optional - symengine_py + sage: f = symengine.Lambdify([x, y], expr) + sage: f(3, 5) array(59115.86131768) - sage: g = fast_callable(SR(expr), vars=[SR(x),SR(y)], domain=RDF) # optional - symengine_py - sage: g(3, 5) # optional - symengine_py + sage: g = fast_callable(SR(expr), vars=[SR(x),SR(y)], domain=RDF) + sage: g(3, 5) 59115.86131767523 """ diff --git a/src/sage/symbolic/tests.py b/src/sage/symbolic/tests.py index b09ae5cc4b8..c1ef2cd14f2 100644 --- a/src/sage/symbolic/tests.py +++ b/src/sage/symbolic/tests.py @@ -2,15 +2,15 @@ Tests for the Sage/Pynac interaction """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Volker Braun <vbraun.name@gmail.com> # # 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** def rational_powers_memleak(): @@ -34,7 +34,7 @@ def rational_powers_memleak(): gc.collect() c0 = sum(1 for obj in gc.get_objects()) for i in range(1000): - a = ZZ(2).sqrt() + _ = ZZ(2).sqrt() gc.collect() c1 = sum(1 for obj in gc.get_objects()) # Test that we do not leak an object at each iteration diff --git a/src/sage/symbolic/units.py b/src/sage/symbolic/units.py index 9b5407786e1..fe629bad49d 100644 --- a/src/sage/symbolic/units.py +++ b/src/sage/symbolic/units.py @@ -61,7 +61,7 @@ sage: wrong.convert() Traceback (most recent call last): ... - ValueError: Cannot convert + ValueError: cannot convert TESTS: @@ -83,7 +83,7 @@ # William Stein <wstein@gmail.com> # Distributed under the terms of the GNU General Public License (GPL), # version 2 or any later version. The full text of the GPL is available at: -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ############################################################################### # standard Python libraries @@ -99,393 +99,394 @@ # Unit conversions dictionary. ############################################################################### -unitdict = { +unitdict = { 'acceleration': - {'gal':'1/100', - 'galileo':'1/100', - 'gravity':'9.80665000000000'}, + {'gal': '1/100', + 'galileo': '1/100', + 'gravity': '9.80665000000000'}, 'amount_of_substance': - {'elementary_entity':'1/6.02214129000000e23', - 'mole':'1'}, + {'elementary_entity': '1/6.02214129000000e23', + 'mole': '1'}, 'angles': - {'arc_minute':'1/10800*pi', - 'arc_second':'1/648000*pi', - 'degree':'1/180*pi', - 'grade':'1/200*pi', - 'quadrant':'1/2*pi', - 'radian':'1', - 'right_angle':'1/2*pi'}, + {'arc_minute': '1/10800*pi', + 'arc_second': '1/648000*pi', + 'degree': '1/180*pi', + 'grade': '1/200*pi', + 'quadrant': '1/2*pi', + 'radian': '1', + 'right_angle': '1/2*pi'}, 'area': - {'acre':'316160658/78125', - 'are':'100', - 'barn':'1/10000000000000000000000000000', - 'hectare':'10000', - 'rood':'158080329/156250', - 'section':'40468564224/15625', - 'square_chain':'158080329/390625', - 'square_meter':'1', - 'township':'1456868312064/15625'}, + {'acre': '316160658/78125', + 'are': '100', + 'barn': '1/10000000000000000000000000000', + 'hectare': '10000', + 'rood': '158080329/156250', + 'section': '40468564224/15625', + 'square_chain': '158080329/390625', + 'square_meter': '1', + 'township': '1456868312064/15625'}, 'capacitance': - {'abfarad':'1000000000', - 'farad':'1', - 'statfarad':'25000/22468879468420441'}, + {'abfarad': '1000000000', + 'farad': '1', + 'statfarad': '25000/22468879468420441'}, 'charge': - {'abcoulomb':'10', - 'coulomb':'1', - 'elementary_charge':'1.60217646200000e-19', - 'faraday':'96485.3399000000', - 'franklin':'1/2997924580', - 'statcoulomb':'1/2997924580'}, + {'abcoulomb': '10', + 'coulomb': '1', + 'elementary_charge': '1.60217646200000e-19', + 'faraday': '96485.3399000000', + 'franklin': '1/2997924580', + 'statcoulomb': '1/2997924580'}, 'conductance': - {'abmho':'1000000000', - 'mho':'1', - 'siemens':'1'}, + {'abmho': '1000000000', + 'mho': '1', + 'siemens': '1'}, 'current': - {'abampere':'10', - 'amp':'1', - 'ampere':'1', - 'biot':'10', - 'statampere':'1/2997924580'}, + {'abampere': '10', + 'amp': '1', + 'ampere': '1', + 'biot': '10', + 'statampere': '1/2997924580'}, 'electric_potential': - {'abvolt':'1/100000000', - 'statvolt':'149896229/500000', - 'volt':'1'}, + {'abvolt': '1/100000000', + 'statvolt': '149896229/500000', + 'volt': '1'}, 'energy': - {'british_thermal_unit':'52752792631/50000000', - 'btu':'52752792631/50000000', - 'calorie':'10467/2500', - 'electron_volt':'1.60217733000000e-19', - 'erg':'1/10000000', - 'ev':'1.60217733000000e-19', - 'joule':'1', - 'rydberg':'2.17987200000000e-18', - 'therm':'52752792631/500'}, + {'british_thermal_unit': '52752792631/50000000', + 'btu': '52752792631/50000000', + 'calorie': '10467/2500', + 'electron_volt': '1.60217733000000e-19', + 'erg': '1/10000000', + 'ev': '1.60217733000000e-19', + 'joule': '1', + 'rydberg': '2.17987200000000e-18', + 'therm': '52752792631/500'}, 'fiber_linear_mass_density': - {'denier':'1/9000000', - 'tex':'1/1000000'}, + {'denier': '1/9000000', + 'tex': '1/1000000'}, 'force': - {'dyne':'1/100000', - 'gram_weight':'196133/20000000', - 'kilogram_force':'196133/20000', - 'kilogram_weight':'196133/20000', - 'newton':'1', - 'pound_force':'8896443230521/2000000000000', - 'pound_weight':'8896443230521/2000000000000', - 'poundal':'17281869297/125000000000', - 'ton_force':'8896443230521/1000000000'}, + {'dyne': '1/100000', + 'gram_weight': '196133/20000000', + 'kilogram_force': '196133/20000', + 'kilogram_weight': '196133/20000', + 'newton': '1', + 'pound_force': '8896443230521/2000000000000', + 'pound_weight': '8896443230521/2000000000000', + 'poundal': '17281869297/125000000000', + 'ton_force': '8896443230521/1000000000'}, 'frequency': - {'1/second':'1', - 'hertz':'1'}, + {'1/second': '1', + 'hertz': '1'}, 'illuminance': - {'foot_candle':'1562500/145161', - 'lux':'1', - 'phot':'10000'}, + {'foot_candle': '1562500/145161', + 'lux': '1', + 'phot': '10000'}, 'inductance': - {'abhenry':'1/1000000000', - 'henry':'1', - 'stathenry':'22468879468420441/25000'}, + {'abhenry': '1/1000000000', + 'henry': '1', + 'stathenry': '22468879468420441/25000'}, 'information': - {'bit':'1', - 'byte':'8', - 'nibble':'4'}, + {'bit': '1', + 'byte': '8', + 'nibble': '4'}, 'information_rate': - {'baud':'1'}, + {'baud': '1'}, 'inverse_length': - {'diopter':'1', - 'kayser':'100'}, + {'diopter': '1', + 'kayser': '100'}, 'length': - {'angstrom':'1/10000000000', - 'astronomical_unit':'149597870691', - 'bolt':'4572/125', - 'cable_international':'926/5', - 'cable_us':'27432/125', - 'caliber':'127/500000', - 'centimeter':'1/100', - 'chain':'12573/625', - 'cicero':'125/27706', - 'cubit':'1143/2500', - 'didot':'125/332472', - 'dtp_point':'127/360000', - 'ell':'1143/1000', - 'fathom':'1143/625', - 'feet':'381/1250', - 'fermi':'1/1000000000000000', - 'foot':'381/1250', - 'furlong':'25146/125', - 'hand':'127/1250', - 'inch':'127/5000', - 'kilometer':'1000', - 'league':'603504/125', - 'light_year':'9460730472580800', - 'link':'12573/62500', - 'meter':'1', - 'micron':'1/1000000', - 'mil':'127/5000000', - 'millimeter':'1/1000', - 'mile':'201168/125', - 'nautical_mile':'1852', - 'parsec':'3.08570000000000e16', - 'perch':'12573/2500', - 'pica':'127/30000', - 'pole':'12573/2500', - 'rod':'12573/2500', - 'rope':'762/125', - 'skein':'13716/125', - 'stadion':'118491/625', - 'stadium':'115443/625', - 'statute_mile':'201168/125', - 'survey_foot':'1200/3937', - 'survey_mile':'6336000/3937', - 'x_unit':'1.00210000000000e-13', - 'yard':'1143/1250'}, + {'angstrom': '1/10000000000', + 'astronomical_unit': '149597870691', + 'bolt': '4572/125', + 'cable_international': '926/5', + 'cable_us': '27432/125', + 'caliber': '127/500000', + 'centimeter': '1/100', + 'chain': '12573/625', + 'cicero': '125/27706', + 'cubit': '1143/2500', + 'didot': '125/332472', + 'dtp_point': '127/360000', + 'ell': '1143/1000', + 'fathom': '1143/625', + 'feet': '381/1250', + 'fermi': '1/1000000000000000', + 'foot': '381/1250', + 'furlong': '25146/125', + 'hand': '127/1250', + 'inch': '127/5000', + 'kilometer': '1000', + 'league': '603504/125', + 'light_year': '9460730472580800', + 'link': '12573/62500', + 'meter': '1', + 'micron': '1/1000000', + 'mil': '127/5000000', + 'millimeter': '1/1000', + 'mile': '201168/125', + 'nautical_mile': '1852', + 'parsec': '3.08570000000000e16', + 'perch': '12573/2500', + 'pica': '127/30000', + 'pole': '12573/2500', + 'rod': '12573/2500', + 'rope': '762/125', + 'skein': '13716/125', + 'stadion': '118491/625', + 'stadium': '115443/625', + 'statute_mile': '201168/125', + 'survey_foot': '1200/3937', + 'survey_mile': '6336000/3937', + 'x_unit': '1.00210000000000e-13', + 'yard': '1143/1250'}, 'luminance': - {'apostilb':'1/pi', - 'lambert':'10000/pi', - 'nit':'1', - 'stilb':'10000'}, + {'apostilb': '1/pi', + 'lambert': '10000/pi', + 'nit': '1', + 'stilb': '10000'}, 'luminous_energy': - {'lumerg':'1', - 'talbot':'1'}, + {'lumerg': '1', + 'talbot': '1'}, 'luminous_flux': - {'lumen':'1'}, + {'lumen': '1'}, 'luminous_intensity': - {'candela':'1', - 'candle':'1', - 'hefnerkerze':'1019/1128'}, + {'candela': '1', + 'candle': '1', + 'hefnerkerze': '1019/1128'}, 'magnetic_field': - {'gauss':'1/10000', - 'tesla':'1'}, + {'gauss': '1/10000', + 'tesla': '1'}, 'magnetic_flux': - {'maxwell':'1/100000000', - 'weber':'1'}, + {'maxwell': '1/100000000', + 'weber': '1'}, 'magnetic_intensity': - {'oersted':'250/pi'}, + {'oersted': '250/pi'}, 'magnetic_moment': - {'bohr_magneton':'9.27400915000000e-24', - 'nuclear_magneton':'5.05078324000000e-27'}, + {'bohr_magneton': '9.27400915000000e-24', + 'nuclear_magneton': '5.05078324000000e-27'}, 'magnetomotive_force': - {'ampere_turn':'1', - 'gilbert':'5/2/pi'}, + {'ampere_turn': '1', + 'gilbert': '5/2/pi'}, 'mass': - {'amu':'1.66053878200000e-27', - 'assay_ton':'7/240', - 'atomic_mass_unit':'1.66053878200000e-27', - 'avoirdupois_ounce':'45359237/1600000000', - 'avoirdupois_pound':'45359237/100000000', - 'bale':'45359237/200000', - 'carat':'1/5000', - 'cental':'45359237/1000000', - 'dalton':'1.66053878200000e-27', - 'drachma':"(0.00429234000000000, {'greek':1})", - 'geepound':'14593903/1000000', - 'grain':'6479891/100000000000', - 'gram':'1/1000', - 'gross_hundredweight':'317514659/6250000', - 'hundredweight':'317514659/6250000', - 'kilogram':'1', - 'libra':'0.325971000000000', - 'long_ton':'317514659/312500', - 'metric_ton':'1000', - 'mina':"(0.429234000000000, {'greek':100})", - 'net_hundredweight':'45359237/1000000', - 'obol':"(0.000715380000000000,{'greek':1/6})", - 'ounce':'45359237/1600000000', - 'ounce_troy':'19439673/625000000', - 'pennyweight':'19439673/12500000000', - 'pondus':'0.325969000000000', - 'pound':'45359237/100000000', - 'pound_troy':'58319019/156250000', - 'quintal':'100', - 'shekel':'0.0141000000000000', - 'short_hundredweight':'45359237/1000000', - 'short_ton':'45359237/50000', - 'slug':'14593903/1000000', - 'solar_mass':'1.98892000000000e30', - 'stone':'317514659/50000000', - 'talent':"(25.7540400000000, {'greek':6000})", - 'ton':'45359237/50000', - 'tonne':'1000', - 'wey':'2857631931/25000000'}, + {'amu': '1.66053878200000e-27', + 'assay_ton': '7/240', + 'atomic_mass_unit': '1.66053878200000e-27', + 'avoirdupois_ounce': '45359237/1600000000', + 'avoirdupois_pound': '45359237/100000000', + 'bale': '45359237/200000', + 'carat': '1/5000', + 'cental': '45359237/1000000', + 'dalton': '1.66053878200000e-27', + 'drachma': "(0.00429234000000000, {'greek':1})", + 'geepound': '14593903/1000000', + 'grain': '6479891/100000000000', + 'gram': '1/1000', + 'gross_hundredweight': '317514659/6250000', + 'hundredweight': '317514659/6250000', + 'kilogram': '1', + 'libra': '0.325971000000000', + 'long_ton': '317514659/312500', + 'metric_ton': '1000', + 'mina': "(0.429234000000000, {'greek':100})", + 'net_hundredweight': '45359237/1000000', + 'obol': "(0.000715380000000000,{'greek':1/6})", + 'ounce': '45359237/1600000000', + 'ounce_troy': '19439673/625000000', + 'pennyweight': '19439673/12500000000', + 'pondus': '0.325969000000000', + 'pound': '45359237/100000000', + 'pound_troy': '58319019/156250000', + 'quintal': '100', + 'shekel': '0.0141000000000000', + 'short_hundredweight': '45359237/1000000', + 'short_ton': '45359237/50000', + 'slug': '14593903/1000000', + 'solar_mass': '1.98892000000000e30', + 'stone': '317514659/50000000', + 'talent': "(25.7540400000000, {'greek':6000})", + 'ton': '45359237/50000', + 'tonne': '1000', + 'wey': '2857631931/25000000'}, 'power': - {'cheval_vapeur':'588399/800', - 'horsepower':'37284993579113511/50000000000000', - 'watt':'1'}, + {'cheval_vapeur': '588399/800', + 'horsepower': '37284993579113511/50000000000000', + 'watt': '1'}, 'pressure': - {'atmosphere':'101325', - 'bar':'100000', - 'barye':'1/10', - 'inch_mercury':'3386.38900000000', - 'millimeter_mercury':'133.322400000000', - 'mmhg':'133.322400000000', - 'pa':'1', - 'pascal':'1', - 'pounds_per_square_inch':'8896443230521/1290320000', - 'psi':'8896443230521/1290320000', - 'torr':'20265/152'}, + {'atmosphere': '101325', + 'bar': '100000', + 'barye': '1/10', + 'inch_mercury': '3386.38900000000', + 'millimeter_mercury': '133.322400000000', + 'mmhg': '133.322400000000', + 'pa': '1', + 'pascal': '1', + 'pounds_per_square_inch': '8896443230521/1290320000', + 'psi': '8896443230521/1290320000', + 'torr': '20265/152'}, 'radiation': - {'becquerel':'1', - 'curie':'37000000000', - 'rutherford':'1000000'}, + {'becquerel': '1', + 'curie': '37000000000', + 'rutherford': '1000000'}, 'radiation_absorbed': - {'gray':'1', - 'rad':'1/100'}, + {'gray': '1', + 'rad': '1/100'}, 'radiation_ionizing': - {'roentgen':'0.000258000000000000', - 'rontgen':'0.000258000000000000'}, + {'roentgen': '0.000258000000000000', + 'rontgen': '0.000258000000000000'}, 'resistance': - {'abohm':'1/1000000000', - 'ohm':'1', - 'statohm':'22468879468420441/25000'}, + {'abohm': '1/1000000000', + 'ohm': '1', + 'statohm': '22468879468420441/25000'}, 'si_prefixes': - {'atto':'1/1000000000000000000', - 'centi':'1/100', - 'deca':'10', - 'deci':'1/10', - 'exa':'1000000000000000000', - 'femto':'1/1000000000000000', - 'giga':'1000000000', - 'hecto':'100', - 'kilo':'1000', - 'mega':'1000000', - 'micro':'1/1000000', - 'milli':'1/1000', - 'nano':'1/1000000000', - 'peta':'1000000000000000', - 'pico':'1/1000000000000', - 'tera':'1000000000000', - 'yocto':'1/1000000000000000000000000', - 'yotta':'1000000000000000000000000', - 'zepto':'1/1000000000000000000000', - 'zetta':'1000000000000000000000'}, + {'atto': '1/1000000000000000000', + 'centi': '1/100', + 'deca': '10', + 'deci': '1/10', + 'exa': '1000000000000000000', + 'femto': '1/1000000000000000', + 'giga': '1000000000', + 'hecto': '100', + 'kilo': '1000', + 'mega': '1000000', + 'micro': '1/1000000', + 'milli': '1/1000', + 'nano': '1/1000000000', + 'peta': '1000000000000000', + 'pico': '1/1000000000000', + 'tera': '1000000000000', + 'yocto': '1/1000000000000000000000000', + 'yotta': '1000000000000000000000000', + 'zepto': '1/1000000000000000000000', + 'zetta': '1000000000000000000000'}, 'solid_angle': - {'steradian':'1'}, + {'steradian': '1'}, 'temperature': - {'celsius':'(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', - 'centigrade':'(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', - 'fahrenheit':'(5/9*(x + 459.67)), ((x - 32)*5/9), (x), (x+459.67)', - 'kelvin':'(x), (x - 273.15), (x*9/5 - 459.67), (x*9/5)', - 'rankine':'(5/9*x), ((x-491.67)*5/9), (x-459.67), (x)'}, + {'celsius': '(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', + 'centigrade': '(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', + 'fahrenheit': '(5/9*(x + 459.67)), ((x - 32)*5/9), (x), (x+459.67)', + 'kelvin': '(x), (x - 273.15), (x*9/5 - 459.67), (x*9/5)', + 'rankine': '(5/9*x), ((x-491.67)*5/9), (x-459.67), (x)'}, 'time': - {'century':'3153600000', - 'day':'86400', - 'decade':'315360000', - 'fortnight':'1209600', - 'hour':'3600', - 'millenium':'31536000000', - 'minute':'60', - 'month':'2628000', - 'second':'1', - 'sidereal_day':"(86164.0905308330, {'sidereal':86400})", - 'sidereal_second':"(0.997269566329086, {'sidereal':1})", - 'sidereal_year':'3.15581497632000e7', - 'tropical_year':'3.15569251779840e7', - 'week':'604800', - 'year':'31536000'}, + {'century': '3153600000', + 'day': '86400', + 'decade': '315360000', + 'fortnight': '1209600', + 'hour': '3600', + 'millenium': '31536000000', + 'minute': '60', + 'month': '2628000', + 'second': '1', + 'sidereal_day': "(86164.0905308330, {'sidereal':86400})", + 'sidereal_second': "(0.997269566329086, {'sidereal':1})", + 'sidereal_year': '3.15581497632000e7', + 'tropical_year': '3.15569251779840e7', + 'week': '604800', + 'year': '31536000'}, 'unit_multipliers': - {'bakers_dozen':'13', - 'dozen':'12', - 'gross':'144', - 'percent':'1/100'}, + {'bakers_dozen': '13', + 'dozen': '12', + 'gross': '144', + 'percent': '1/100'}, 'velocity': - {'knot':'463/900'}, + {'knot': '463/900'}, 'viscosity_absolute': - {'poise':'1/10', - 'reyn':'8896443230521/1290320000'}, + {'poise': '1/10', + 'reyn': '8896443230521/1290320000'}, 'viscosity_kinematic': - {'stokes':'1/10000'}, + {'stokes': '1/10000'}, 'viscosity_other': - {'rhes':'10'}, + {'rhes': '10'}, 'volume': - {'bag':'660732565629/6250000000000', - 'barrel':'9936705933/62500000000', - 'board_foot':'18435447/7812500000', - 'bucket':'473176473/31250000000', - 'bushel':'220244188543/6250000000000', - 'butt':'29810117799/62500000000', - 'cord':'884901456/244140625', - 'cubic_meter':'1', - 'cup':'473176473/2000000000000', - 'ephah':'1982197696887/50000000000000', - 'fifth':'473176473/625000000000', - 'firkin':'4091481/100000000', - 'fluid_dram':'473176473/128000000000000', - 'fluid_ounce':'473176473/16000000000000', - 'gallon':'473176473/125000000000', - 'gill':'473176473/4000000000000', - 'hogshead':'29810117799/125000000000', - 'imperial_gallon':'454609/100000000', - 'imperial_pint':'454609/800000000', - 'jeroboam':'473176473/156250000000', - 'jigger':'1419529419/32000000000000', - 'liter':'1/1000', - 'magnum':'473176473/250000000000', - 'minim':'157725491/2560000000000000', - 'noggin':'473176473/4000000000000', - 'omer':'1982197696887/500000000000000', - 'peck':'220244188543/25000000000000', - 'pint':'473176473/1000000000000', - 'pony':'1419529419/64000000000000', - 'puncheon':'9936705933/31250000000', - 'quart':'473176473/500000000000', - 'register_ton':'55306341/19531250', - 'seam':'220244188543/781250000000', - 'shot':'473176473/16000000000000', - 'stere':'1', - 'tablespoon':'473176473/32000000000000', - 'teaspoon':'157725491/32000000000000', - 'tun':'29810117799/31250000000', - 'uk_gallon':'454609/100000000', - 'uk_pint':'454609/800000000', - 'wine_bottle':'3/4000'} + {'bag': '660732565629/6250000000000', + 'barrel': '9936705933/62500000000', + 'board_foot': '18435447/7812500000', + 'bucket': '473176473/31250000000', + 'bushel': '220244188543/6250000000000', + 'butt': '29810117799/62500000000', + 'cord': '884901456/244140625', + 'cubic_meter': '1', + 'cup': '473176473/2000000000000', + 'ephah': '1982197696887/50000000000000', + 'fifth': '473176473/625000000000', + 'firkin': '4091481/100000000', + 'fluid_dram': '473176473/128000000000000', + 'fluid_ounce': '473176473/16000000000000', + 'gallon': '473176473/125000000000', + 'gill': '473176473/4000000000000', + 'hogshead': '29810117799/125000000000', + 'imperial_gallon': '454609/100000000', + 'imperial_pint': '454609/800000000', + 'jeroboam': '473176473/156250000000', + 'jigger': '1419529419/32000000000000', + 'liter': '1/1000', + 'magnum': '473176473/250000000000', + 'minim': '157725491/2560000000000000', + 'noggin': '473176473/4000000000000', + 'omer': '1982197696887/500000000000000', + 'peck': '220244188543/25000000000000', + 'pint': '473176473/1000000000000', + 'pony': '1419529419/64000000000000', + 'puncheon': '9936705933/31250000000', + 'quart': '473176473/500000000000', + 'register_ton': '55306341/19531250', + 'seam': '220244188543/781250000000', + 'shot': '473176473/16000000000000', + 'stere': '1', + 'tablespoon': '473176473/32000000000000', + 'teaspoon': '157725491/32000000000000', + 'tun': '29810117799/31250000000', + 'uk_gallon': '454609/100000000', + 'uk_pint': '454609/800000000', + 'wine_bottle': '3/4000'} } unit_to_type = {} value_to_unit = {} + def evalunitdict(): """ Replace all the string values of the unitdict variable by their @@ -499,7 +500,7 @@ def evalunitdict(): """ from sage.misc.sage_eval import sage_eval for key, value in unitdict.items(): - unitdict[key] = dict([(a,sage_eval(repr(b))) for a, b in value.items()]) + unitdict[key] = {a: sage_eval(repr(b)) for a, b in value.items()} # FEATURE IDEA: create a function that would allow users to add # new entries to the table without having to know anything about @@ -526,403 +527,402 @@ def evalunitdict(): unit_docs = { 'acceleration_docs': - {'gal':'Abbreviation for galileo.\nDefined to be 1/100 meter/second^2.', - 'galileo':'Defined to be 1/100 meter/second^2.', - 'gravity':'Also called standard gravity.\nPhysical constant defined to be 9.80665 meter/second^2.'}, + {'gal': 'Abbreviation for galileo.\nDefined to be 1/100 meter/second^2.', + 'galileo': 'Defined to be 1/100 meter/second^2.', + 'gravity': 'Also called standard gravity.\nPhysical constant defined to be 9.80665 meter/second^2.'}, 'amount_of_substance_docs': - {'elementary_entity':'Defined to be one elementary unit of choice, usually atoms or other elementary particles.\nApproximately equal to 1.6605e-24 moles.', - 'mole':'SI base unit of quantity.\nDefined to be the amount of substance that has an equal number of elementary entities as there are atoms in 12 grams of carbon-12.\nEquivalent to Avogadros constant elementary entities or approximately equal to 6.022*10^23 elementary entities.'}, + {'elementary_entity': 'Defined to be one elementary unit of choice, usually atoms or other elementary particles.\nApproximately equal to 1.6605e-24 moles.', + 'mole': 'SI base unit of quantity.\nDefined to be the amount of substance that has an equal number of elementary entities as there are atoms in 12 grams of carbon-12.\nEquivalent to Avogadros constant elementary entities or approximately equal to 6.022*10^23 elementary entities.'}, 'angles_docs': - {'arc_minute':'Defined to be 1/60 of a degree or pi/10800 radians.', - 'arc_second':'Defined to be 1/3600 of a degree or pi/648000 radians.', - 'degree':'Defined to be pi/180 radians.', - 'grade':'Defined to be pi/200 radians.', - 'quadrant':'Equivalent to a right angle.\nDefined to be pi/2 radians.', - 'radian':'SI derived unit of angle.\nDefined to be the angle subtended at the center of a circle by an arc that is equal in length to the radius of the circle.', - 'right_angle':'Equivalent to a quadrant.\nDefined to be pi/2 radians.'}, + {'arc_minute': 'Defined to be 1/60 of a degree or pi/10800 radians.', + 'arc_second': 'Defined to be 1/3600 of a degree or pi/648000 radians.', + 'degree': 'Defined to be pi/180 radians.', + 'grade': 'Defined to be pi/200 radians.', + 'quadrant': 'Equivalent to a right angle.\nDefined to be pi/2 radians.', + 'radian': 'SI derived unit of angle.\nDefined to be the angle subtended at the center of a circle by an arc that is equal in length to the radius of the circle.', + 'right_angle': 'Equivalent to a quadrant.\nDefined to be pi/2 radians.'}, 'area_docs': - {'acre':'Defined to be 10 square chains or 4840 square yards.\nApproximately equal to 4046.856 square meters.', - 'are':'Defined to be 100 square meters.', - 'barn':'Defined to be 100 square femtometers or 10^-28 square meters.', - 'hectare':'Defined to be 10000 square meters.', - 'rood':'Defined to be 1/4 of an acre.\nApproximately equal to 1011.714 square meters.', - 'section':'Equivalent to a square mile.\nApproximately equal to 2.59*10^6 square meters.', - 'square_chain':'Defined to be 4356 square feet.\nApproximately equal to 404.9856 square meters.', - 'square_meter':'SI derived unit of area.\nDefined to be meter^2.', - 'township':'Defined to be 36 square miles.\nApproximately equal to 9.324*10^7 square meters.'}, + {'acre': 'Defined to be 10 square chains or 4840 square yards.\nApproximately equal to 4046.856 square meters.', + 'are': 'Defined to be 100 square meters.', + 'barn': 'Defined to be 100 square femtometers or 10^-28 square meters.', + 'hectare': 'Defined to be 10000 square meters.', + 'rood': 'Defined to be 1/4 of an acre.\nApproximately equal to 1011.714 square meters.', + 'section': 'Equivalent to a square mile.\nApproximately equal to 2.59*10^6 square meters.', + 'square_chain': 'Defined to be 4356 square feet.\nApproximately equal to 404.9856 square meters.', + 'square_meter': 'SI derived unit of area.\nDefined to be meter^2.', + 'township': 'Defined to be 36 square miles.\nApproximately equal to 9.324*10^7 square meters.'}, 'capacitance_docs': - {'abfarad':'Defined to be 10^9 farads.', - 'farad':'SI derived unit of capacitance.\nDefined to be the charge in coulombs a capacitor will accept for the potential across it to change one volt.\nEquivalent to coulomb/volt.', - 'statfarad':'CGS unit defined to be statcoulomb/statvolt.\nApproximately equal to 1.11265*10^-12 farads.'}, + {'abfarad': 'Defined to be 10^9 farads.', + 'farad': 'SI derived unit of capacitance.\nDefined to be the charge in coulombs a capacitor will accept for the potential across it to change one volt.\nEquivalent to coulomb/volt.', + 'statfarad': 'CGS unit defined to be statcoulomb/statvolt.\nApproximately equal to 1.11265*10^-12 farads.'}, 'charge_docs': - {'abcoulomb':'CGS unit defined to be 10 coulombs.', - 'coulomb':'SI derived unit of charge.\nDefined to be the amount of electric charge transported by 1 ampere in 1 second.', - 'elementary_charge':'Defined to be the amount of electric charge carried by a single proton or negative charge carried by a single electron.\nApproximately equal to 1.602176462*10^-19 coulombs.', - 'faraday':'Defined to be the magnitude of electric charge in one mole of electrons.\nApproximately equal to 96485.3399 coulombs.', - 'franklin':'CGS unit defined to be the amount of electric charge necessary such that if two stationary objects placed one centimeter apart had one franklin of charge each they would repel each other with a force of one dyne.\nApproximately equal to 3.3356*10^-10 coulombs.', - 'statcoulomb':'Equivalent to franklin.\nApproximately equal to 3.3356*10^-10 coulombs.'}, + {'abcoulomb': 'CGS unit defined to be 10 coulombs.', + 'coulomb': 'SI derived unit of charge.\nDefined to be the amount of electric charge transported by 1 ampere in 1 second.', + 'elementary_charge': 'Defined to be the amount of electric charge carried by a single proton or negative charge carried by a single electron.\nApproximately equal to 1.602176462*10^-19 coulombs.', + 'faraday': 'Defined to be the magnitude of electric charge in one mole of electrons.\nApproximately equal to 96485.3399 coulombs.', + 'franklin': 'CGS unit defined to be the amount of electric charge necessary such that if two stationary objects placed one centimeter apart had one franklin of charge each they would repel each other with a force of one dyne.\nApproximately equal to 3.3356*10^-10 coulombs.', + 'statcoulomb': 'Equivalent to franklin.\nApproximately equal to 3.3356*10^-10 coulombs.'}, 'conductance_docs': - {'abmho':'Defined to be 10^9 siemens.', - 'mho':'Equivalent to siemens.', - 'siemens':'SI derived unit of conductance.\nDefined to be an ampere per volt or 1/ohm.'}, + {'abmho': 'Defined to be 10^9 siemens.', + 'mho': 'Equivalent to siemens.', + 'siemens': 'SI derived unit of conductance.\nDefined to be an ampere per volt or 1/ohm.'}, 'current_docs': - {'abampere':'CGS unit defined to be 10 amperes.', - 'amp':'Abbreviation for ampere.', - 'ampere':'SI base unit of current.\nDefined to be the constant current which will produce an attractive force of 2*10^-7 newtons per meter between two straight, parallel conductors of infinite length and negligible circular cross section placed one meter apart in free space.', - 'biot':'Equivalent to abampere.\nEqual to 10 amperes.', - 'statampere':'CGS unit defined to be statcoulomb/second.\nApproximately equal to 3.335641*10^-10 amperes.'}, + {'abampere': 'CGS unit defined to be 10 amperes.', + 'amp': 'Abbreviation for ampere.', + 'ampere': 'SI base unit of current.\nDefined to be the constant current which will produce an attractive force of 2*10^-7 newtons per meter between two straight, parallel conductors of infinite length and negligible circular cross section placed one meter apart in free space.', + 'biot': 'Equivalent to abampere.\nEqual to 10 amperes.', + 'statampere': 'CGS unit defined to be statcoulomb/second.\nApproximately equal to 3.335641*10^-10 amperes.'}, 'electric_potential_docs': - {'abvolt':'Defined to be 10^-8 volts.', - 'statvolt':'CGS unit defined to be the speed of light in a vacuum/10^6 volts or approximately 299.792 volts.', - 'volt':'SI derived unit of electric potential.\nDefined to be the value of voltage across a conductor when a current of one ampere dissipates one watt of power.'}, + {'abvolt': 'Defined to be 10^-8 volts.', + 'statvolt': 'CGS unit defined to be the speed of light in a vacuum/10^6 volts or approximately 299.792 volts.', + 'volt': 'SI derived unit of electric potential.\nDefined to be the value of voltage across a conductor when a current of one ampere dissipates one watt of power.'}, 'energy_docs': - {'british_thermal_unit':'Defined to be the amount of energy required to raise the temperature of one pound of liquid water from 60 degrees Fahrenheit to 61 degrees Fahrenheit at a constant pressure of one atmosphere.\nApproximately equal to 1055.05585 joules.', - 'btu':'Abbreviation for British thermal unit.\nApproximately equal to 1055.05585 joules.', - 'calorie':'Defined to be the amount of energy required to raise the temperature of one gram of liquid water one degree Celsius.\nEqual to 4.1868 joules.', - 'electron_volt':'Defined to be the amount of kinetic energy gained by a single unbound electron when it accelerates through an electrostatic potential difference of 1 volt.\nApproximately equal to 1.602*10^-19 joules.', - 'erg':'CGS unit for energy defined to be gram*centimeter^2/second^2.\nEqual to 10^-7 joules.', - 'ev':'Abbreviation for electron volt.\nApproximately equal to 1.602*10^-19 joules.', - 'joule':'SI derived unit of energy.\nDefined to be kilogram*meter^2/second^2.', - 'rydberg':'Defined to be the absolute value of the binding energy of the electron in the ground state hydrogen atom.\nApproximately equal to 2.17987*10^-18 joules.', - 'therm':'Defined to be 100,000 British thermal units.\nApproximately equal to 1.05505585*10^8 joules.'}, + {'british_thermal_unit': 'Defined to be the amount of energy required to raise the temperature of one pound of liquid water from 60 degrees Fahrenheit to 61 degrees Fahrenheit at a constant pressure of one atmosphere.\nApproximately equal to 1055.05585 joules.', + 'btu': 'Abbreviation for British thermal unit.\nApproximately equal to 1055.05585 joules.', + 'calorie': 'Defined to be the amount of energy required to raise the temperature of one gram of liquid water one degree Celsius.\nEqual to 4.1868 joules.', + 'electron_volt': 'Defined to be the amount of kinetic energy gained by a single unbound electron when it accelerates through an electrostatic potential difference of 1 volt.\nApproximately equal to 1.602*10^-19 joules.', + 'erg': 'CGS unit for energy defined to be gram*centimeter^2/second^2.\nEqual to 10^-7 joules.', + 'ev': 'Abbreviation for electron volt.\nApproximately equal to 1.602*10^-19 joules.', + 'joule': 'SI derived unit of energy.\nDefined to be kilogram*meter^2/second^2.', + 'rydberg': 'Defined to be the absolute value of the binding energy of the electron in the ground state hydrogen atom.\nApproximately equal to 2.17987*10^-18 joules.', + 'therm': 'Defined to be 100,000 British thermal units.\nApproximately equal to 1.05505585*10^8 joules.'}, 'fiber_linear_mass_density_docs': - {'denier':'Defined to be 1 gram per 9000 meters.\nEqual to 1/9000000 of a kilogram/meter.', - 'tex':'Defined to be 1 gram per 1000 meters.\nEqual to 1/1000000 of a kilogram/meter.'}, + {'denier': 'Defined to be 1 gram per 9000 meters.\nEqual to 1/9000000 of a kilogram/meter.', + 'tex': 'Defined to be 1 gram per 1000 meters.\nEqual to 1/1000000 of a kilogram/meter.'}, 'force_docs': - {'dyne':'CGS unit for force defined to be gram*centimeter/second^2.\nEqual to 10^-5 newtons.', - 'gram_weight':'Defined to be the magnitude of the force exerted on one gram of mass by a 9.80665 meter/second^2 gravitational field.\nEqual to 1/1000 of a kilogram weight.\nEqual to 0.00980665 newtons.', - 'kilogram_force':'Equivalent to a kilogram weight.\nEqual to 9.80665 newtons.', - 'kilogram_weight':'Defined to be the magnitude of the force exerted on one kilogram of mass by a 9.80665 meter/second^2 gravitational field.\nEqual to 9.80665 newtons.', - 'newton':'SI derived unit of force.\nDefined to be kilogram*meter/second^2.', - 'pound_force':'Equivalent to a pound weight.\nApproximately equal to 4.44822 newtons.', - 'pound_weight':'Defined to be the magnitude of the force exerted on one pound of mass by a 9.80665 meter/second^2 gravitational field.\nApproximately equal to 4.44822 newtons.', - 'poundal':'Defined to be pound*foot/second^2.\nApproximately equal to 0.13825 newtons.', - 'ton_force':'Defined to be 2000 pounds of force.\nApproximately equal to 8896.4432 newtons.'}, + {'dyne': 'CGS unit for force defined to be gram*centimeter/second^2.\nEqual to 10^-5 newtons.', + 'gram_weight': 'Defined to be the magnitude of the force exerted on one gram of mass by a 9.80665 meter/second^2 gravitational field.\nEqual to 1/1000 of a kilogram weight.\nEqual to 0.00980665 newtons.', + 'kilogram_force': 'Equivalent to a kilogram weight.\nEqual to 9.80665 newtons.', + 'kilogram_weight': 'Defined to be the magnitude of the force exerted on one kilogram of mass by a 9.80665 meter/second^2 gravitational field.\nEqual to 9.80665 newtons.', + 'newton': 'SI derived unit of force.\nDefined to be kilogram*meter/second^2.', + 'pound_force': 'Equivalent to a pound weight.\nApproximately equal to 4.44822 newtons.', + 'pound_weight': 'Defined to be the magnitude of the force exerted on one pound of mass by a 9.80665 meter/second^2 gravitational field.\nApproximately equal to 4.44822 newtons.', + 'poundal': 'Defined to be pound*foot/second^2.\nApproximately equal to 0.13825 newtons.', + 'ton_force': 'Defined to be 2000 pounds of force.\nApproximately equal to 8896.4432 newtons.'}, 'frequency_docs': - {'hertz':'SI derived unit of frequency.\nDefined to be one complete cycle per second.'}, + {'hertz': 'SI derived unit of frequency.\nDefined to be one complete cycle per second.'}, 'illuminance_docs': - {'foot_candle':'Defined to be lumen/foot^2.\nApproximately equal to 10.764 lux.', - 'lux':'SI derived unit of illuminance.\nDefined to be lumen/meter^2.', - 'phot':'CGS unit defined to be 10000 lux.'}, + {'foot_candle': 'Defined to be lumen/foot^2.\nApproximately equal to 10.764 lux.', + 'lux': 'SI derived unit of illuminance.\nDefined to be lumen/meter^2.', + 'phot': 'CGS unit defined to be 10000 lux.'}, 'inductance_docs': - {'abhenry':'Defined to be 10^-9 henries.', - 'henry':'SI derived unit of inductance./nDefined to be a volt per ampere per second.', - 'stathenry':'CGS unit defined to be one statvolt*second/statampere.\nApproximately equal to 8.98758*10^11 henries.'}, + {'abhenry': 'Defined to be 10^-9 henries.', + 'henry': 'SI derived unit of inductance./nDefined to be a volt per ampere per second.', + 'stathenry': 'CGS unit defined to be one statvolt*second/statampere.\nApproximately equal to 8.98758*10^11 henries.'}, 'information_docs': - {'bit':'Base unit of information.\nDefined to be the maximum amount of information that can be stored by a device of other physical system that can normally exist in only two distinct states.', - 'byte':'Defined to be 8 bits.', - 'nibble':'Defined to be 4 bits.'}, + {'bit': 'Base unit of information.\nDefined to be the maximum amount of information that can be stored by a device of other physical system that can normally exist in only two distinct states.', + 'byte': 'Defined to be 8 bits.', + 'nibble': 'Defined to be 4 bits.'}, 'information_rate_docs': - {'baud':'Defined to be 1 bit/second.'}, + {'baud': 'Defined to be 1 bit/second.'}, 'inverse_length_docs': - {'diopter':'Defined to be 1/meter.', - 'kayser':'Defined to be 100/meter.'}, + {'diopter': 'Defined to be 1/meter.', + 'kayser': 'Defined to be 100/meter.'}, 'length_docs': - {'angstrom':'Defined to be 10^-10 meters.', - 'astronomical_unit':'Originally defined as the length of the semi-major axis of the elliptical orbit of the Earth around the Sun.\nRedefined for accuracy to be the radius of an unperturbed circular Newtonian orbit about the Sun of a particle having infinitesimal mass, moving with a mean motion of 0.01720209895 radians per day.\nApproximately equal to 1.496*10^11 meters.', - 'bolt':'Defined to be 40 yards.\nEqual to 36.576 meters.', - 'cable_international':'Nautical unit defined to be 1/10 of a nautical mile.\nEqual to 185.2 meters.', - 'cable_us':'Nautical unit defined to be equal to 720 feet or 120 fathoms.\nEqual to 219.456 meters.', - 'caliber':'Equal to 1/100 of an inch.\nEqual to 0.000254 meters.', - 'centimeter':'Equal to 1/100 of a meter.', - 'chain':'Surveying unit defined to be 66 feet.\nApproximately equal to 20.12 meters.', - 'cicero':'Printing unit defined to be 12 didot points.\nApproximately equal to 0.004512 meters.', - 'cubit':'Ancient unit of length defined to be 18 inches.\nEqual to 0.4572 meters.', - 'didot':'Printing unit equal to 1/12 of a cicero.\nApproximately equal to 0.00037597 meters.', - 'dtp_point':'The desktop publishing point is defined to be 1/72 of an inch.\nApproximately equal to 0.0003528 meters.', - 'ell':'Ancient unit of length defined to be 45 inches.\nEqual to 1.143 meters.', - 'fathom':'Nautical unit defined to be 6 feet.\nEqual to 1.8288 meters.', - 'feet':'Equal to 12 inches.\nDefined to be 0.3048 meters.', - 'fermi':'Equivalent to a femtometer.\nEqual to 10^-15 meters.', - 'foot':'Equal to 12 inches.\nDefined to be 0.3048 meters.', - 'furlong':'Defined to be 660 feet, or 1/8 of a mile.\nEqual to 201.168 meters.', - 'hand':'Defined to be 4 inches.\nEqual to 0.1016 meters.', - 'inch':'Equal to 1/12 of a foot.\nEqual to 0.0254 meters.', - 'kilometer':'Equal to 1000 meters.\nEqual to 3280.8399 feet.', - 'league':'Defined to be 3 miles.\nConventionally equal to the distance a person or horse can walk in one hour.\nEqual to 4828.032 meters.', - 'light_year':'Defined to be the distance light travels in vacuum in 365.25 days.\nApproximately equal to 9.4607*10^15 meters.', - 'link':'Surveying unit defined to be 1/100 of a chain.\nEqual to 0.201168 meters.', - 'meter':'SI base unit of length.\nDefined to be the distance light travels in vacuum in 1/299792458 of a second.', - 'micron':'Defined to be 10^-6 meters.', - 'mil':'Defined to be 1/1000 of an inch.\nEqual to 0.0000254 meters.', - 'millimeter':'Defined to be 1/1000 of a meter.\nEqual to 0.001 meters.', - 'mile':'Defined to be 5280 feet.\nEqual to 1609.344 meters.', - 'nautical_mile':'Nautical unit defined to be 1852 meters.', - 'parsec':'Defined to be the length of the adjacent side of a right triangle whose angle is 1 arcsecond and opposite side equal to 1 astronomical unit, or 1 AU/arctan(1 arcsecond).\nApproximately equal to 30.857*10^15 meters.', - 'perch':'Equivalent to rod.\nDefined to be 16.5 feet.\nEqual to 5.0292 meters.', - 'pica':'Printing unit defined to be 12 dtp points.\nEqual to 1/72 of a foot.\nApproximately equal to 0.004233 meters.', - 'pole':'Equivalent to rod.\nDefined to be 16.5 feet.\nEqual to 5.0292 meters.', - 'rod':'Defined to be 16.5 feet.\nEqual to 5.0292 meters.', - 'rope':'Defined to be 20 feet.\nEqual to 6.096 meters.', - 'skein':'Defined to be 360 feet.\nEqual to 109.728 meters.', - 'stadion':'Ancient unit of length defined to be 622 feet.\nEqual to 189.5856 meters.', - 'stadium':'Defined to be 202 yards or 606 feet.\nEqual to 184.7088 meters.', - 'statute_mile':'Equivalent to mile.\nDefined to be 5280 feet.\nEqual to 1609.344 meters.', - 'survey_foot':'Defined to be 1200/3937 or approximately 0.3048006 meters.', - 'survey_mile':'Defined to be 5280 survey feet.\nApproximately equal to 1609.347 meters.', - 'x_unit':'Unit of length used to quote wavelengths of X-rays and gamma rays.\nApproximately equal to 1.0021*10^-13 meters.', - 'yard':'Defined to be 3 feet.\nEqual to 0.9144 meters.'}, + {'angstrom': 'Defined to be 10^-10 meters.', + 'astronomical_unit': 'Originally defined as the length of the semi-major axis of the elliptical orbit of the Earth around the Sun.\nRedefined for accuracy to be the radius of an unperturbed circular Newtonian orbit about the Sun of a particle having infinitesimal mass, moving with a mean motion of 0.01720209895 radians per day.\nApproximately equal to 1.496*10^11 meters.', + 'bolt': 'Defined to be 40 yards.\nEqual to 36.576 meters.', + 'cable_international': 'Nautical unit defined to be 1/10 of a nautical mile.\nEqual to 185.2 meters.', + 'cable_us': 'Nautical unit defined to be equal to 720 feet or 120 fathoms.\nEqual to 219.456 meters.', + 'caliber': 'Equal to 1/100 of an inch.\nEqual to 0.000254 meters.', + 'centimeter': 'Equal to 1/100 of a meter.', + 'chain': 'Surveying unit defined to be 66 feet.\nApproximately equal to 20.12 meters.', + 'cicero': 'Printing unit defined to be 12 didot points.\nApproximately equal to 0.004512 meters.', + 'cubit': 'Ancient unit of length defined to be 18 inches.\nEqual to 0.4572 meters.', + 'didot': 'Printing unit equal to 1/12 of a cicero.\nApproximately equal to 0.00037597 meters.', + 'dtp_point': 'The desktop publishing point is defined to be 1/72 of an inch.\nApproximately equal to 0.0003528 meters.', + 'ell': 'Ancient unit of length defined to be 45 inches.\nEqual to 1.143 meters.', + 'fathom': 'Nautical unit defined to be 6 feet.\nEqual to 1.8288 meters.', + 'feet': 'Equal to 12 inches.\nDefined to be 0.3048 meters.', + 'fermi': 'Equivalent to a femtometer.\nEqual to 10^-15 meters.', + 'foot': 'Equal to 12 inches.\nDefined to be 0.3048 meters.', + 'furlong': 'Defined to be 660 feet, or 1/8 of a mile.\nEqual to 201.168 meters.', + 'hand': 'Defined to be 4 inches.\nEqual to 0.1016 meters.', + 'inch': 'Equal to 1/12 of a foot.\nEqual to 0.0254 meters.', + 'kilometer': 'Equal to 1000 meters.\nEqual to 3280.8399 feet.', + 'league': 'Defined to be 3 miles.\nConventionally equal to the distance a person or horse can walk in one hour.\nEqual to 4828.032 meters.', + 'light_year': 'Defined to be the distance light travels in vacuum in 365.25 days.\nApproximately equal to 9.4607*10^15 meters.', + 'link': 'Surveying unit defined to be 1/100 of a chain.\nEqual to 0.201168 meters.', + 'meter': 'SI base unit of length.\nDefined to be the distance light travels in vacuum in 1/299792458 of a second.', + 'micron': 'Defined to be 10^-6 meters.', + 'mil': 'Defined to be 1/1000 of an inch.\nEqual to 0.0000254 meters.', + 'millimeter': 'Defined to be 1/1000 of a meter.\nEqual to 0.001 meters.', + 'mile': 'Defined to be 5280 feet.\nEqual to 1609.344 meters.', + 'nautical_mile': 'Nautical unit defined to be 1852 meters.', + 'parsec': 'Defined to be the length of the adjacent side of a right triangle whose angle is 1 arcsecond and opposite side equal to 1 astronomical unit, or 1 AU/arctan(1 arcsecond).\nApproximately equal to 30.857*10^15 meters.', + 'perch': 'Equivalent to rod.\nDefined to be 16.5 feet.\nEqual to 5.0292 meters.', + 'pica': 'Printing unit defined to be 12 dtp points.\nEqual to 1/72 of a foot.\nApproximately equal to 0.004233 meters.', + 'pole': 'Equivalent to rod.\nDefined to be 16.5 feet.\nEqual to 5.0292 meters.', + 'rod': 'Defined to be 16.5 feet.\nEqual to 5.0292 meters.', + 'rope': 'Defined to be 20 feet.\nEqual to 6.096 meters.', + 'skein': 'Defined to be 360 feet.\nEqual to 109.728 meters.', + 'stadion': 'Ancient unit of length defined to be 622 feet.\nEqual to 189.5856 meters.', + 'stadium': 'Defined to be 202 yards or 606 feet.\nEqual to 184.7088 meters.', + 'statute_mile': 'Equivalent to mile.\nDefined to be 5280 feet.\nEqual to 1609.344 meters.', + 'survey_foot': 'Defined to be 1200/3937 or approximately 0.3048006 meters.', + 'survey_mile': 'Defined to be 5280 survey feet.\nApproximately equal to 1609.347 meters.', + 'x_unit': 'Unit of length used to quote wavelengths of X-rays and gamma rays.\nApproximately equal to 1.0021*10^-13 meters.', + 'yard': 'Defined to be 3 feet.\nEqual to 0.9144 meters.'}, 'luminance_docs': - {'apostilb':'Defined to be 10^-4 lamberts.\nEqual to 1/pi*candela/meter^2.', - 'lambert':'Defined to be 10^4/pi candela/meter^2.', - 'nit':'Equivalent to candela/meter^2.', - 'stilb':'CGS unit equal to 10000 candela/meter^2.'}, + {'apostilb': 'Defined to be 10^-4 lamberts.\nEqual to 1/pi*candela/meter^2.', + 'lambert': 'Defined to be 10^4/pi candela/meter^2.', + 'nit': 'Equivalent to candela/meter^2.', + 'stilb': 'CGS unit equal to 10000 candela/meter^2.'}, 'luminous_energy_docs': - {'lumerg':'Equivalent to lumen*second', - 'talbot':'Equivalent to lumen*second.'}, + {'lumerg': 'Equivalent to lumen*second', + 'talbot': 'Equivalent to lumen*second.'}, 'luminous_flux_docs': - {'lumen':'SI derived unit of luminous flux.\nDefined to be candela*steradian.'}, + {'lumen': 'SI derived unit of luminous flux.\nDefined to be candela*steradian.'}, 'luminous_intensity_docs': - {'candela':'SI base unit of luminous intensity.\nDefined to be the luminous intensity, in a given direction, of a source that emits monochromatic radiation of frequency 540*10^12 hertz and that has a radiant intensity in that direction of 1/683 watt per steradian.', - 'candle':'Equivalent to candela.', - 'hefnerkerze':'Old German unit defined to be a 8 millimeter wick burning amyl acetate with a flame height of 40 millimeters.\nApproximately equal to 0.9034 candelas.'}, + {'candela': 'SI base unit of luminous intensity.\nDefined to be the luminous intensity, in a given direction, of a source that emits monochromatic radiation of frequency 540*10^12 hertz and that has a radiant intensity in that direction of 1/683 watt per steradian.', + 'candle': 'Equivalent to candela.', + 'hefnerkerze': 'Old German unit defined to be a 8 millimeter wick burning amyl acetate with a flame height of 40 millimeters.\nApproximately equal to 0.9034 candelas.'}, 'magnetic_field_docs': - {'gauss':'CGS unit defined to be a maxwell/centimeter^2.\nEqual to 1/10000 of a tesla.', - 'tesla':'SI derived unit of magnetic field.\nDefined to be the magnitude of a magnetic field such that a particle with a charge of 1 coulomb passing through that field at 1 meter/second will experience a force of 1 newton.'}, + {'gauss': 'CGS unit defined to be a maxwell/centimeter^2.\nEqual to 1/10000 of a tesla.', + 'tesla': 'SI derived unit of magnetic field.\nDefined to be the magnitude of a magnetic field such that a particle with a charge of 1 coulomb passing through that field at 1 meter/second will experience a force of 1 newton.'}, 'magnetic_flux_docs': - {'maxwell':'CGS unit defined to be a gauss*centimeter^2 or 10^-8 webers.', - 'weber':'SI derived unit of magnetic flux.\nDefined to be a change in magnetic flux of 1 weber per second will induce an electromotive force of 1 volt.'}, + {'maxwell': 'CGS unit defined to be a gauss*centimeter^2 or 10^-8 webers.', + 'weber': 'SI derived unit of magnetic flux.\nDefined to be a change in magnetic flux of 1 weber per second will induce an electromotive force of 1 volt.'}, 'magnetic_intensity_docs': - {'oersted':'CGS unit defined to be 1000/(4*pi) amperes per meter of flux path.'}, + {'oersted': 'CGS unit defined to be 1000/(4*pi) amperes per meter of flux path.'}, 'magnetic_moment_docs': - {'bohr_magneton':'Physical constant defined to be the magnetic moment of an electron, or elementary_charge*h_bar/2*electron_rest_mass.\nApproximately equal to 9.274*10^-24 joules/tesla.', - 'nuclear_magneton':'Physical constant defined to be the magnetic moment of a proton, or elementary_charge*h_bar/2*proton_rest_mass.\nApproximately equal to 5.05078324*10^-27 joules/tesla.'}, + {'bohr_magneton': 'Physical constant defined to be the magnetic moment of an electron, or elementary_charge*h_bar/2*electron_rest_mass.\nApproximately equal to 9.274*10^-24 joules/tesla.', + 'nuclear_magneton': 'Physical constant defined to be the magnetic moment of a proton, or elementary_charge*h_bar/2*proton_rest_mass.\nApproximately equal to 5.05078324*10^-27 joules/tesla.'}, 'magnetomotive_force_docs': - {'ampere_turn':'SI derived unit of magnetomotive force.\nDefined to be a direct current of 1 ampere flowing through a single turn loop in a vacuum.', - 'gilbert':'CGS unit defined to be 10/(4*pi) ampere turns.'}, + {'ampere_turn': 'SI derived unit of magnetomotive force.\nDefined to be a direct current of 1 ampere flowing through a single turn loop in a vacuum.', + 'gilbert': 'CGS unit defined to be 10/(4*pi) ampere turns.'}, 'mass_docs': - {'amu':'Abbreviation for atomic mass unit.\nApproximately equal to 1.660538782*10^-27 kilograms.', - 'assay_ton':'Defined to be milligram*short_ton/ounce_troy.\nEqual to 7/240 of a kilogram.', - 'atomic_mass_unit':'Defined to be one twelfth of the mass of an isolated atom of carbon-12 at rest and in its ground state.\nApproximately equal to 1.660538782*10^-27 kilograms.', - 'avoirdupois_ounce':'Equivalent to ounce.\nEqual to 1/16 of an avoirdupois pound.\nApproximately equal to 0.02835 kilograms.', - 'avoirdupois_pound':'Equivalent to pound.\nEqual to 16 avoirdupois ounces.\nApproximately equal to 0.45359 kilograms.', - 'bale':'Equal to 500 pounds.\nApproximately equal to 226.796 kilograms.', - 'carat':'Defined to be equal to 200 milligrams.\nCommonly denoted ct.', - 'cental':'Equal to 100 pounds.\nApproximately equal to 45.36 kilograms.', - 'dalton':'Equivalent to atomic_mass_unit.\nApproximately equal to 1.660538782*10^-27 kilograms.', - 'drachma':'Ancient Greek unit of mass.\nEqual to 6 obols.\nApproximately equal to 0.00429234 kilograms.', - 'geepound':'Equivalent to slug.\nApproximately equal to 14.5939 kilograms.', - 'grain':'Historically based on the average mass of a single seed of a typical cereal.\nDefined in 1958 to be 64.79891 milligrams.', - 'gram':'Equal to 0.0001 kilograms.', - 'gross_hundredweight':'Equivalent to hundredweight.\nEqual to 112 pounds.\nApproximately equal to 50.802 kilograms.', - 'hundredweight':'Defined to be 112 pounds.\nApproximately equal to 50.802 kilograms.', - 'kilogram':'SI base unit of mass.\nDefined to be equal to the mass of the International Prototype Kilogram.\nAlmost exactly equal to the amount of mass in one liter of water.', - 'libra':'Ancient Roman unit of mass.\nApproximately equal to 0.325971 kilogram.', - 'long_ton':'Defined to be 2240 pounds.\nApproximately equal to 1016.05 kilograms.', - 'metric_ton':'Defined to be 1000 kilograms.', - 'mina':'Ancient Greek unit of mass.\nEqual to 100 drachma.\nApproximately equal to 0.429234 kilograms.', - 'net_hundredweight':'Equivalent to cental.\nEqual to 100 pounds.\nApproximately equal to 45.36 kilograms.', - 'obol':'Ancient Greek unit of mass.\nEqual to 1/6 of drachma.\nApproximately equal to 0.00071538 kilograms.', - 'ounce':'Equal to 1/16 of pound.\nCommonly abbreviated oz.\nApproximately equal to 0.02835 kilograms.', - 'ounce_troy':'Equal to 1/12 of pound_troy.\nApproximately equal to 0.031103 kilograms.', - 'pennyweight':'Equal to 1/20 of ounce_troy.\nCommonly abbreviated dwt.\nApproximately equal to 0.001555 kilograms.', - 'pondus':'Ancient Roman unit of mass.\nApproximately equal to 0.325969 kilograms.', - 'pound':'Equal to 16 ounces.\nDefined to be exactly 0.45359237 kilograms.', - 'pound_troy':'Equal to 12 ounce_troy.\nApproximately equal to 0.37324 kilograms.', - 'quintal':'Equal to 100 kilograms.', - 'shekel':'Ancient Hebrew unit of mass.\nApproximately equal to 0.0141 kilograms.', - 'short_hundredweight':'Equivalent to cental.\nEqual to 100 pounds.\nApproximately equal to 45.36 kilograms.', - 'short_ton':'Equivalent to ton.\nEqual to 2000 pounds.\nApproximately equal to 907.18 kilograms.', - 'slug':'Defined to be a mass that is accelerated 1 ft/s^2 when 1 pound_force is exerted on it.\nApproximately equal to 14.5939 kilograms.', - 'solar_mass':'Defined to be the mass of the Sun.\nAbout 332,950 times the mass of the Earth or 1,048 times the mass of Jupiter.\nApproximately equal to 1.98892*10^30 kilograms.', - 'stone':'Defined to be 14 pounds.\nApproximately equal to 6.35 kilograms.', - 'talent':'Ancient Greek unit of mass.\nEqual to 6000 drachmae.\nApproximately equal to 25.754 kilograms.', - 'ton':'Equal to 2000 pounds.\nApproximately equal to 907.18 kilograms.', - 'tonne':'Equivalent to metric_ton.\nDefined to be 1000 kilograms.', - 'wey':'Defined to be 252 pounds.\nApproximately equal to 114.305 kilograms.'}, + {'amu': 'Abbreviation for atomic mass unit.\nApproximately equal to 1.660538782*10^-27 kilograms.', + 'assay_ton': 'Defined to be milligram*short_ton/ounce_troy.\nEqual to 7/240 of a kilogram.', + 'atomic_mass_unit': 'Defined to be one twelfth of the mass of an isolated atom of carbon-12 at rest and in its ground state.\nApproximately equal to 1.660538782*10^-27 kilograms.', + 'avoirdupois_ounce': 'Equivalent to ounce.\nEqual to 1/16 of an avoirdupois pound.\nApproximately equal to 0.02835 kilograms.', + 'avoirdupois_pound': 'Equivalent to pound.\nEqual to 16 avoirdupois ounces.\nApproximately equal to 0.45359 kilograms.', + 'bale': 'Equal to 500 pounds.\nApproximately equal to 226.796 kilograms.', + 'carat': 'Defined to be equal to 200 milligrams.\nCommonly denoted ct.', + 'cental': 'Equal to 100 pounds.\nApproximately equal to 45.36 kilograms.', + 'dalton': 'Equivalent to atomic_mass_unit.\nApproximately equal to 1.660538782*10^-27 kilograms.', + 'drachma': 'Ancient Greek unit of mass.\nEqual to 6 obols.\nApproximately equal to 0.00429234 kilograms.', + 'geepound': 'Equivalent to slug.\nApproximately equal to 14.5939 kilograms.', + 'grain': 'Historically based on the average mass of a single seed of a typical cereal.\nDefined in 1958 to be 64.79891 milligrams.', + 'gram': 'Equal to 0.0001 kilograms.', + 'gross_hundredweight': 'Equivalent to hundredweight.\nEqual to 112 pounds.\nApproximately equal to 50.802 kilograms.', + 'hundredweight': 'Defined to be 112 pounds.\nApproximately equal to 50.802 kilograms.', + 'kilogram': 'SI base unit of mass.\nDefined to be equal to the mass of the International Prototype Kilogram.\nAlmost exactly equal to the amount of mass in one liter of water.', + 'libra': 'Ancient Roman unit of mass.\nApproximately equal to 0.325971 kilogram.', + 'long_ton': 'Defined to be 2240 pounds.\nApproximately equal to 1016.05 kilograms.', + 'metric_ton': 'Defined to be 1000 kilograms.', + 'mina': 'Ancient Greek unit of mass.\nEqual to 100 drachma.\nApproximately equal to 0.429234 kilograms.', + 'net_hundredweight': 'Equivalent to cental.\nEqual to 100 pounds.\nApproximately equal to 45.36 kilograms.', + 'obol': 'Ancient Greek unit of mass.\nEqual to 1/6 of drachma.\nApproximately equal to 0.00071538 kilograms.', + 'ounce': 'Equal to 1/16 of pound.\nCommonly abbreviated oz.\nApproximately equal to 0.02835 kilograms.', + 'ounce_troy': 'Equal to 1/12 of pound_troy.\nApproximately equal to 0.031103 kilograms.', + 'pennyweight': 'Equal to 1/20 of ounce_troy.\nCommonly abbreviated dwt.\nApproximately equal to 0.001555 kilograms.', + 'pondus': 'Ancient Roman unit of mass.\nApproximately equal to 0.325969 kilograms.', + 'pound': 'Equal to 16 ounces.\nDefined to be exactly 0.45359237 kilograms.', + 'pound_troy': 'Equal to 12 ounce_troy.\nApproximately equal to 0.37324 kilograms.', + 'quintal': 'Equal to 100 kilograms.', + 'shekel': 'Ancient Hebrew unit of mass.\nApproximately equal to 0.0141 kilograms.', + 'short_hundredweight': 'Equivalent to cental.\nEqual to 100 pounds.\nApproximately equal to 45.36 kilograms.', + 'short_ton': 'Equivalent to ton.\nEqual to 2000 pounds.\nApproximately equal to 907.18 kilograms.', + 'slug': 'Defined to be a mass that is accelerated 1 ft/s^2 when 1 pound_force is exerted on it.\nApproximately equal to 14.5939 kilograms.', + 'solar_mass': 'Defined to be the mass of the Sun.\nAbout 332,950 times the mass of the Earth or 1,048 times the mass of Jupiter.\nApproximately equal to 1.98892*10^30 kilograms.', + 'stone': 'Defined to be 14 pounds.\nApproximately equal to 6.35 kilograms.', + 'talent': 'Ancient Greek unit of mass.\nEqual to 6000 drachmae.\nApproximately equal to 25.754 kilograms.', + 'ton': 'Equal to 2000 pounds.\nApproximately equal to 907.18 kilograms.', + 'tonne': 'Equivalent to metric_ton.\nDefined to be 1000 kilograms.', + 'wey': 'Defined to be 252 pounds.\nApproximately equal to 114.305 kilograms.'}, 'power_docs': - {'cheval_vapeur':'Defined to be 75 kilogram force*meter/second.\nAlso known as metric horsepower.\nEqual to 735.49875 watts.', - 'horsepower':'Defined to be 550 feet*pound force/second.\nApproximately equal to 745.7 watts.', - 'watt':'SI derived unit of power.\nDefined to be joule/second or, in base units, kilogram*meter^2/second^3.'}, + {'cheval_vapeur': 'Defined to be 75 kilogram force*meter/second.\nAlso known as metric horsepower.\nEqual to 735.49875 watts.', + 'horsepower': 'Defined to be 550 feet*pound force/second.\nApproximately equal to 745.7 watts.', + 'watt': 'SI derived unit of power.\nDefined to be joule/second or, in base units, kilogram*meter^2/second^3.'}, 'pressure_docs': - {'atmosphere':'Defined to be 101325 pascals.', - 'bar':'Defined to be 100000 pascals.', - 'barye':'CGS unit defined to be dyne/centimeter^2.\nEqual to 1/10 of a pascal.', - 'inch_mercury':'Defined to be 13595.1 kilogram/meter^3*inch*gravity.\nApproximately equal to 3386.389 pascals.', - 'millimeter_mercury':'Defined to be 13595.1 kilogram/meter^3*millimeter*gravity.\nApproximately equal to 133.3224 pascals.', - 'mmhg':'Abbreviation for millimeter mercury.\nApproximately equal to 133.3224 pascals.', - 'pa':'Abbreviation for pascal.', - 'pascal':'SI derived unit of pressure.\nDefined to be newton/meter^2 or, in base units, kilogram/(meter*second^2).', - 'pounds_per_square_inch':'Defined to be pound force/inch^2.\nApproximately equal to 6894.76 pascals.', - 'psi':'Abbreviation for pounds per square inch.\nApproximately equal to 6894.76 pascals.', - 'torr':'Defined to be 1/760 of an atmosphere.\nApproximately equal to 133.322 pascals.'}, + {'atmosphere': 'Defined to be 101325 pascals.', + 'bar': 'Defined to be 100000 pascals.', + 'barye': 'CGS unit defined to be dyne/centimeter^2.\nEqual to 1/10 of a pascal.', + 'inch_mercury': 'Defined to be 13595.1 kilogram/meter^3*inch*gravity.\nApproximately equal to 3386.389 pascals.', + 'millimeter_mercury': 'Defined to be 13595.1 kilogram/meter^3*millimeter*gravity.\nApproximately equal to 133.3224 pascals.', + 'mmhg': 'Abbreviation for millimeter mercury.\nApproximately equal to 133.3224 pascals.', + 'pa': 'Abbreviation for pascal.', + 'pascal': 'SI derived unit of pressure.\nDefined to be newton/meter^2 or, in base units, kilogram/(meter*second^2).', + 'pounds_per_square_inch': 'Defined to be pound force/inch^2.\nApproximately equal to 6894.76 pascals.', + 'psi': 'Abbreviation for pounds per square inch.\nApproximately equal to 6894.76 pascals.', + 'torr': 'Defined to be 1/760 of an atmosphere.\nApproximately equal to 133.322 pascals.'}, 'radiation_absorbed_docs': - {'gray':'SI derived unit of absorbed radiation.\nDefined to be the absorption of one joule of ionizing radiation by one kilogram of matter.', - 'rad':'Defined to be 1/100 of a gray.'}, + {'gray': 'SI derived unit of absorbed radiation.\nDefined to be the absorption of one joule of ionizing radiation by one kilogram of matter.', + 'rad': 'Defined to be 1/100 of a gray.'}, 'radiation_docs': - {'becquerel':'SI derived unit of radiation.\nDefined to be the activity of a quantity of radioactive material in which one nucleus decays per second.', - 'curie':'Defined to be 37*10^9 becquerels.', - 'rutherford':'Defined to be 10^6 becquerels.'}, + {'becquerel': 'SI derived unit of radiation.\nDefined to be the activity of a quantity of radioactive material in which one nucleus decays per second.', + 'curie': 'Defined to be 37*10^9 becquerels.', + 'rutherford': 'Defined to be 10^6 becquerels.'}, 'radiation_ionizing_docs': - {'roentgen':'Defined to be .000258 coulombs/kilogram.', - 'rontgen':'Equivalent to roentgen.\nDefined to be .000258 coulombs/kilogram.'}, + {'roentgen': 'Defined to be .000258 coulombs/kilogram.', + 'rontgen': 'Equivalent to roentgen.\nDefined to be .000258 coulombs/kilogram.'}, 'resistance_docs': - {'abohm':'Defined to be 10^-9 ohms.', - 'ohm':'SI derived unit of resistance.\nDefined to be a volt per ampere.', - 'statohm':'CGS unit defined to be statvolt/statampere.\nApproximately equal to 8.98758*10^11 ohms.'}, + {'abohm': 'Defined to be 10^-9 ohms.', + 'ohm': 'SI derived unit of resistance.\nDefined to be a volt per ampere.', + 'statohm': 'CGS unit defined to be statvolt/statampere.\nApproximately equal to 8.98758*10^11 ohms.'}, 'solid_angle_docs': - {'steradian':'SI derived unit of solid angle.\nDefined to be the solid angle subtended at the center of a sphere of radius r by a portion of the surface of the sphere having an area of r^2.'}, + {'steradian': 'SI derived unit of solid angle.\nDefined to be the solid angle subtended at the center of a sphere of radius r by a portion of the surface of the sphere having an area of r^2.'}, 'temperature_docs': - {'celsius':'Defined to be -273.15 at absolute zero and 0.01 at the triple point of Vienna Standard Mean Ocean Water.\nCelsius is related to kelvin by the equation K = 273.15 + degrees Celsius.\nA change of 1 degree Celsius is equivalent to a change of 1 degree kelvin.', - 'centigrade':'Equivalent to celsius.', - 'fahrenheit':'Defined to be 32 degrees at the freezing point of water and 212 degrees at the boiling point of water, both at standard pressure (1 atmosphere).\nFahrenheit is related to kelvin by the equation K = 5/9*(degrees Fahrenheit + 459.67).\nA change of 1 degree fahrenheit is equal to a change of 5/9 kelvin.', - 'kelvin':'SI base unit of temperature.\nDefined to be exactly 0 at absolute zero and 273.16 at the triple point of Vienna Standard Mean Ocean Water.', - 'rankine':'Defined to be 0 at absolute zero and to have the same degree increment as Fahrenheit.\nRankine is related to kelvin by the equation K = 5/9*R.'}, + {'celsius': 'Defined to be -273.15 at absolute zero and 0.01 at the triple point of Vienna Standard Mean Ocean Water.\nCelsius is related to kelvin by the equation K = 273.15 + degrees Celsius.\nA change of 1 degree Celsius is equivalent to a change of 1 degree kelvin.', + 'centigrade': 'Equivalent to celsius.', + 'fahrenheit': 'Defined to be 32 degrees at the freezing point of water and 212 degrees at the boiling point of water, both at standard pressure (1 atmosphere).\nFahrenheit is related to kelvin by the equation K = 5/9*(degrees Fahrenheit + 459.67).\nA change of 1 degree fahrenheit is equal to a change of 5/9 kelvin.', + 'kelvin': 'SI base unit of temperature.\nDefined to be exactly 0 at absolute zero and 273.16 at the triple point of Vienna Standard Mean Ocean Water.', + 'rankine': 'Defined to be 0 at absolute zero and to have the same degree increment as Fahrenheit.\nRankine is related to kelvin by the equation K = 5/9*R.'}, 'time_docs': - {'century':'Defined to be 100 years.\nEqual to 3153600000 seconds.', - 'day':'Defined to be 24 hours.\nEqual to 86400 seconds.', - 'decade':'Defined to be 10 years.\nEqual to 315360000 seconds.', - 'fortnight':'Defined to be 2 weeks or 14 days.\nEqual to 1209600 seconds.', - 'hour':'Defined to be 60 minutes.\nEqual to 3600 seconds.', - 'millenium':'Defined to be 1000 years.\nEqual to 31536000000 seconds.', - 'minute':'Defined to be 60 seconds.', - 'month':'Defined to be 30 days.\nEqual to 2628000 seconds.', - 'second':'SI base unit of time.\nDefined to be the duration of 9,192,631,770 periods of the radiation corresponding to the transition between the two hyperfine levels of the ground state of the caesium 133 atom.', - 'sidereal_day':'Defined to be the time it takes for the Earth to make one complete rotation relative to the stars.\nApproximately equal to 86164.09 seconds.', - 'sidereal_second':'Defined to be 1/86400 of a sidereal day.\nApproximately equal to 0.997269566329086 seconds.', - 'sidereal_year':'Defined to be the time taken by the Earth to orbit the Sun once with respect to the fixed stars.\nApproximately equal to 31558149.7632 seconds.', - 'tropical_year':'Defined to be the length of time that the Sun takes to return to the same position in the cycle of seasons, as seen from the Earth.\nApproximately equal to 31556925.1779840 seconds.', - 'week':'Defined to be 7 days.\nEqual to 604800 seconds.', - 'year':'Defined to be 365 days.\nEqual to 31536000 seconds.'}, + {'century': 'Defined to be 100 years.\nEqual to 3153600000 seconds.', + 'day': 'Defined to be 24 hours.\nEqual to 86400 seconds.', + 'decade': 'Defined to be 10 years.\nEqual to 315360000 seconds.', + 'fortnight': 'Defined to be 2 weeks or 14 days.\nEqual to 1209600 seconds.', + 'hour': 'Defined to be 60 minutes.\nEqual to 3600 seconds.', + 'millenium': 'Defined to be 1000 years.\nEqual to 31536000000 seconds.', + 'minute': 'Defined to be 60 seconds.', + 'month': 'Defined to be 30 days.\nEqual to 2628000 seconds.', + 'second': 'SI base unit of time.\nDefined to be the duration of 9,192,631,770 periods of the radiation corresponding to the transition between the two hyperfine levels of the ground state of the caesium 133 atom.', + 'sidereal_day': 'Defined to be the time it takes for the Earth to make one complete rotation relative to the stars.\nApproximately equal to 86164.09 seconds.', + 'sidereal_second': 'Defined to be 1/86400 of a sidereal day.\nApproximately equal to 0.997269566329086 seconds.', + 'sidereal_year': 'Defined to be the time taken by the Earth to orbit the Sun once with respect to the fixed stars.\nApproximately equal to 31558149.7632 seconds.', + 'tropical_year': 'Defined to be the length of time that the Sun takes to return to the same position in the cycle of seasons, as seen from the Earth.\nApproximately equal to 31556925.1779840 seconds.', + 'week': 'Defined to be 7 days.\nEqual to 604800 seconds.', + 'year': 'Defined to be 365 days.\nEqual to 31536000 seconds.'}, 'unit_multipliers_docs': - {'bakers_dozen':'Defined to be 13 items.', - 'dozen':'Defined to be 12 items.', - 'gross':'Defined to be 144 items.', - 'percent':'Defined to be 1/100 of a quantity.'}, + {'bakers_dozen': 'Defined to be 13 items.', + 'dozen': 'Defined to be 12 items.', + 'gross': 'Defined to be 144 items.', + 'percent': 'Defined to be 1/100 of a quantity.'}, 'velocity_docs': - {'knot':'Nautical unit of velocity defined to be a nautical mile per hour.\nApproximately equal to 0.5144 meter/second.'}, + {'knot': 'Nautical unit of velocity defined to be a nautical mile per hour.\nApproximately equal to 0.5144 meter/second.'}, 'viscosity_absolute_docs': - {'poise':'CGS unit defined to be 1/10 of pascal*second.', - 'reyn':'Defined to be a pound_force*second/inch^2.\nApproximately equal to 6894.76 pascal*second.'}, + {'poise': 'CGS unit defined to be 1/10 of pascal*second.', + 'reyn': 'Defined to be a pound_force*second/inch^2.\nApproximately equal to 6894.76 pascal*second.'}, 'viscosity_kinematic_docs': - {'stokes':'CGS unit defined to be 1/10000 of meter^2/second.'}, + {'stokes': 'CGS unit defined to be 1/10000 of meter^2/second.'}, 'viscosity_other_docs': - {'rhes':'Defined to be 1/poise or 10/(pascal*second).'}, + {'rhes': 'Defined to be 1/poise or 10/(pascal*second).'}, 'volume_docs': - {'bag':'Defined to be 3 bushels.\nApproximately equal to 0.10572 cubic meters.', - 'barrel':'Defined to be 42 gallons.\nApproximately equal to 0.15899 cubic meters.', - 'board_foot':'Defined to be 144 cubic inches.\nApproximately equal to 0.0023597 cubic meters.', - 'bucket':'Defined to be 4 gallons.\nApproximately equal to 0.0151416 cubic meters.', - 'bushel':'Defined to be 2150.42 cubic inches.\nEquivalent to 4 pecks.\nApproximately equal to 0.035239 cubic meters.', - 'butt':'Old English unit of wine casks defined to be 2 hogsheads or 126 gallons.\nApproximately equal to 0.476962 cubic meters.', - 'cord':'Defined to be 8 feet x 8 feet x 4 feet.\nApproximately equal to 3.624556 cubic meters.', - 'cubic_meter':'SI derived unit of volume.\nDefined to be meter^3.', - 'cup':'Defined to be 8 fluid ounces.\nApproximately equal to 0.000236588 cubic meters.', - 'ephah':'Ancient Hebrew unit of volume equal to 10 omers.\nApproximately equal to 0.03964 cubic meters.', - 'fifth':'Defined to be 1/5 of a gallon.\nApproximately equal to 0.00075708 cubic meters.', - 'firkin':'Defined to be 9 imperial gallons.\nApproximately equal to 0.04091 cubic meters.', - 'fluid_dram':'Defined to be 1/8 of a fluid ounce.\nApproximately equal to 3.69669*10^-6 cubic meters.', - 'fluid_ounce':'Defined to be 1/128 of a gallon.\nApproximately equal to 0.000029574 cubic meters.', - 'gallon':'Defined to be 231 cubic inches.\nApproximately equal to 0.0037854 cubic meters.', - 'gill':'Defined to be 4 fluid ounces.\nApproximately equal to 0.00011829 cubic meters.', - 'hogshead':'Old English unit of wine casks defined to be 63 gallons.\nApproximately equal to 0.23848 cubic meters.', - 'imperial_gallon':'Defined to be 4.54609 liters.\nEqual to 0.00454609 cubic meters.', - 'imperial_pint':'Defined to be 1/8 of an imperial gallon.\nApproximately equal to 0.00056826 cubic meters.', - 'jeroboam':'Defined to be 4/5 of a gallon.\nApproximately equal to 0.0030283 cubic meters.', - 'jigger':'Defined to be 1 1/2 fluid ounces.\nApproximately equal to 0.00004436 cubic meters.', - 'liter':'Defined to be 1 decimeter^3.\nEqual to 1/1000 of a cubic meter.', - 'magnum':'Defined to be 1/2 a gallon.\nApproximately equal to 0.0018927 cubic meters.', - 'minim':'Defined to be 1/480 of a fluid ounce.\nApproximately equal to 6.16115*10^-8 cubic meters.', - 'noggin':'Equivalent to gill.\nDefined to be 4 fluid ounces.\nApproximately equal to 0.00011829 cubic meters.', - 'omer':'Ancient Hebrew unit of volume equal to 9/20 of a peck.\nApproximately equal to 0.0039644 cubic meters.', - 'peck':'Defined to be 1/4 of a bushel.\nApproximately equal to 0.0088098 cubic meters.', - 'pint':'Defined to be 1/8 of a gallon.\nApproximately equal to 0.00047318 cubic meters.', - 'pony':'Defined to be 3/4 of a fluid ounce.\nApproximately equal to 0.00002218 cubic meters.', - 'puncheon':'Old English unit of wine casks defined to be 84 gallons.\nApproximately equal to 0.31797 cubic meters.', - 'quart':'Defined to be 1/4 of a gallon.\nApproximately equal to 0.00094635 cubic meters.', - 'register_ton':'Defined to be 100 cubic feet.\nApproximately equal to 2.83168 cubic meters.', - 'seam':'Defined to be 8 bushels.\nApproximately equal to 0.281913 cubic meters.', - 'shot':'Defined to be 1 fluid ounce.\nApproximately equal to 0.000029574 cubic meters.', - 'stere':'Equivalent to cubic meter.', - 'tablespoon':'Defined to be 1/2 of a fluid ounce.\nApproximately equal to 0.000014787 cubic meters.', - 'teaspoon':'Defined to be 1/6 of a fluid ounce.\nEqual to 1/3 of a tablespoon.\nApproximately equal to 4.9289*10^-6 cubic meters.', - 'tun':'Old English unit of wine casks defined to be 252 gallons.\nApproximately equal to 0.95392 cubic meters.', - 'uk_gallon':'Equivalent to an imperial gallon.\nEqual to 0.00454609 cubic meters.', - 'uk_pint':'Equivalent to and imperial pint.\nApproximately equal to 0.00056826 cubic meters.', - 'wine_bottle':'Defined to be 750 milliliters.\nEqual to 0.00075 cubic meters.'} + {'bag': 'Defined to be 3 bushels.\nApproximately equal to 0.10572 cubic meters.', + 'barrel': 'Defined to be 42 gallons.\nApproximately equal to 0.15899 cubic meters.', + 'board_foot': 'Defined to be 144 cubic inches.\nApproximately equal to 0.0023597 cubic meters.', + 'bucket': 'Defined to be 4 gallons.\nApproximately equal to 0.0151416 cubic meters.', + 'bushel': 'Defined to be 2150.42 cubic inches.\nEquivalent to 4 pecks.\nApproximately equal to 0.035239 cubic meters.', + 'butt': 'Old English unit of wine casks defined to be 2 hogsheads or 126 gallons.\nApproximately equal to 0.476962 cubic meters.', + 'cord': 'Defined to be 8 feet x 8 feet x 4 feet.\nApproximately equal to 3.624556 cubic meters.', + 'cubic_meter': 'SI derived unit of volume.\nDefined to be meter^3.', + 'cup': 'Defined to be 8 fluid ounces.\nApproximately equal to 0.000236588 cubic meters.', + 'ephah': 'Ancient Hebrew unit of volume equal to 10 omers.\nApproximately equal to 0.03964 cubic meters.', + 'fifth': 'Defined to be 1/5 of a gallon.\nApproximately equal to 0.00075708 cubic meters.', + 'firkin': 'Defined to be 9 imperial gallons.\nApproximately equal to 0.04091 cubic meters.', + 'fluid_dram': 'Defined to be 1/8 of a fluid ounce.\nApproximately equal to 3.69669*10^-6 cubic meters.', + 'fluid_ounce': 'Defined to be 1/128 of a gallon.\nApproximately equal to 0.000029574 cubic meters.', + 'gallon': 'Defined to be 231 cubic inches.\nApproximately equal to 0.0037854 cubic meters.', + 'gill': 'Defined to be 4 fluid ounces.\nApproximately equal to 0.00011829 cubic meters.', + 'hogshead': 'Old English unit of wine casks defined to be 63 gallons.\nApproximately equal to 0.23848 cubic meters.', + 'imperial_gallon': 'Defined to be 4.54609 liters.\nEqual to 0.00454609 cubic meters.', + 'imperial_pint': 'Defined to be 1/8 of an imperial gallon.\nApproximately equal to 0.00056826 cubic meters.', + 'jeroboam': 'Defined to be 4/5 of a gallon.\nApproximately equal to 0.0030283 cubic meters.', + 'jigger': 'Defined to be 1 1/2 fluid ounces.\nApproximately equal to 0.00004436 cubic meters.', + 'liter': 'Defined to be 1 decimeter^3.\nEqual to 1/1000 of a cubic meter.', + 'magnum': 'Defined to be 1/2 a gallon.\nApproximately equal to 0.0018927 cubic meters.', + 'minim': 'Defined to be 1/480 of a fluid ounce.\nApproximately equal to 6.16115*10^-8 cubic meters.', + 'noggin': 'Equivalent to gill.\nDefined to be 4 fluid ounces.\nApproximately equal to 0.00011829 cubic meters.', + 'omer': 'Ancient Hebrew unit of volume equal to 9/20 of a peck.\nApproximately equal to 0.0039644 cubic meters.', + 'peck': 'Defined to be 1/4 of a bushel.\nApproximately equal to 0.0088098 cubic meters.', + 'pint': 'Defined to be 1/8 of a gallon.\nApproximately equal to 0.00047318 cubic meters.', + 'pony': 'Defined to be 3/4 of a fluid ounce.\nApproximately equal to 0.00002218 cubic meters.', + 'puncheon': 'Old English unit of wine casks defined to be 84 gallons.\nApproximately equal to 0.31797 cubic meters.', + 'quart': 'Defined to be 1/4 of a gallon.\nApproximately equal to 0.00094635 cubic meters.', + 'register_ton': 'Defined to be 100 cubic feet.\nApproximately equal to 2.83168 cubic meters.', + 'seam': 'Defined to be 8 bushels.\nApproximately equal to 0.281913 cubic meters.', + 'shot': 'Defined to be 1 fluid ounce.\nApproximately equal to 0.000029574 cubic meters.', + 'stere': 'Equivalent to cubic meter.', + 'tablespoon': 'Defined to be 1/2 of a fluid ounce.\nApproximately equal to 0.000014787 cubic meters.', + 'teaspoon': 'Defined to be 1/6 of a fluid ounce.\nEqual to 1/3 of a tablespoon.\nApproximately equal to 4.9289*10^-6 cubic meters.', + 'tun': 'Old English unit of wine casks defined to be 252 gallons.\nApproximately equal to 0.95392 cubic meters.', + 'uk_gallon': 'Equivalent to an imperial gallon.\nEqual to 0.00454609 cubic meters.', + 'uk_pint': 'Equivalent to and imperial pint.\nApproximately equal to 0.00056826 cubic meters.', + 'wine_bottle': 'Defined to be 750 milliliters.\nEqual to 0.00075 cubic meters.'} } - ############################################################################### # Dictionary for converting from derived units to base SI units. ############################################################################### -unit_derivations = {'acceleration':'length/time^2', - 'area':'length^2', - 'capacitance':'time^4*current^2/(length^2*mass)', - 'charge':'current*time', - 'conductance':'current^2*time^3/(mass*length^2)', - 'electric_potential':'mass*length^2/(current*time^3)', - 'energy':'mass*length^2/time^2', - 'fiber_linear_mass_density':'mass/length', - 'force':'mass*length/time^2', - 'frequency':'1/time', - 'illuminance':'luminous_intensity*solid_angle/length^2', - 'inductance':'length^2*mass/(time^2*current^2)', - 'information_rate':'information/time', - 'inverse_length':'1/length', - 'luminance':'luminous_intensity/length^2', - 'luminous_energy':'luminous_intensity*solid_angle*time', - 'luminous_flux':'luminous_intensity*solid_angle', - 'magnetic_field':'mass/(current*time^2)', - 'magnetic_flux':'mass*length^2/(current*time^2)', - 'magnetic_intensity':'current/length', - 'magnetic_moment':'current*length^2', - 'power':'mass*length^2/time^3', - 'pressure':'mass/(length*time^2)', - 'radiation':'1/time', - 'radiation_absorbed':'length^2/time^2', - 'radiation_ionizing':'current*time/mass', - 'resistance':'mass*length^2/(current^2*time^3)', - 'velocity':'length/time', - 'viscosity_absolute':'mass/(length*time)', - 'viscosity_kinematic':'length^2/time', - 'viscosity_other':'length*time/mass', - 'volume':'length^3' +unit_derivations = {'acceleration': 'length/time^2', + 'area': 'length^2', + 'capacitance': 'time^4*current^2/(length^2*mass)', + 'charge': 'current*time', + 'conductance': 'current^2*time^3/(mass*length^2)', + 'electric_potential': 'mass*length^2/(current*time^3)', + 'energy': 'mass*length^2/time^2', + 'fiber_linear_mass_density': 'mass/length', + 'force': 'mass*length/time^2', + 'frequency': '1/time', + 'illuminance': 'luminous_intensity*solid_angle/length^2', + 'inductance': 'length^2*mass/(time^2*current^2)', + 'information_rate': 'information/time', + 'inverse_length': '1/length', + 'luminance': 'luminous_intensity/length^2', + 'luminous_energy': 'luminous_intensity*solid_angle*time', + 'luminous_flux': 'luminous_intensity*solid_angle', + 'magnetic_field': 'mass/(current*time^2)', + 'magnetic_flux': 'mass*length^2/(current*time^2)', + 'magnetic_intensity': 'current/length', + 'magnetic_moment': 'current*length^2', + 'power': 'mass*length^2/time^3', + 'pressure': 'mass/(length*time^2)', + 'radiation': '1/time', + 'radiation_absorbed': 'length^2/time^2', + 'radiation_ionizing': 'current*time/mass', + 'resistance': 'mass*length^2/(current^2*time^3)', + 'velocity': 'length/time', + 'viscosity_absolute': 'mass/(length*time)', + 'viscosity_kinematic': 'length^2/time', + 'viscosity_other': 'length*time/mass', + 'volume': 'length^3' } @@ -946,6 +946,7 @@ def vars_in_str(s): """ return re.findall('[a-z|_]+', s) + def unit_derivations_expr(v): """ Given derived units name, returns the corresponding units @@ -967,7 +968,7 @@ def unit_derivations_expr(v): sage: sage.symbolic.units.unit_derivations_expr('electric_potential') length^2*mass/(current*time^3) - If the unit name is unknown, a KeyError is raised:: + If the unit name is unknown, a :class:`KeyError` is raised:: sage: sage.symbolic.units.unit_derivations_expr('invalid') Traceback (most recent call last): @@ -976,8 +977,8 @@ def unit_derivations_expr(v): """ v = str(v) Z = unit_derivations[v] - if isinstance(Z,str): - d = dict([(x,str_to_unit(x)) for x in vars_in_str(Z)]) + if isinstance(Z, str): + d = {x: str_to_unit(x) for x in vars_in_str(Z)} from sage.misc.sage_eval import sage_eval Z = sage_eval(Z, d) unit_derivations[v] = Z @@ -1014,6 +1015,7 @@ def _instancedoc_(self): """ return unitdocs(self) + def str_to_unit(name): """ Create the symbolic unit with given name. A symbolic unit is a @@ -1038,6 +1040,7 @@ class that derives from symbolic expression, and has a specialized """ return UnitExpression(SR, SR.var(name)) + class Units(ExtraTabCompletion): """ A collection of units of some type. @@ -1196,8 +1199,10 @@ def __repr__(self): name = ' of ' + self.__name if self.__name else '' return "Collection of units{0}: {1}".format(name, ' '.join(sorted([str(x) for x in self.__data]))) + units = Units(unitdict, '') + def unitdocs(unit): r""" Returns docstring for the given unit. @@ -1222,16 +1227,16 @@ def unitdocs(unit): sage: sage.symbolic.units.unitdocs('earth') Traceback (most recent call last): ... - ValueError: No documentation exists for the unit earth. + ValueError: no documentation exists for the unit earth """ if is_unit(unit): - return unit_docs[unit_to_type[str(unit)]+"_docs"][str(unit)] - else: - raise ValueError("No documentation exists for the unit %s."%unit) + return unit_docs[unit_to_type[str(unit)] + "_docs"][str(unit)] + raise ValueError("no documentation exists for the unit %s" % unit) + -def is_unit(s): +def is_unit(s) -> bool: """ - Returns a boolean when asked whether the input is in the list of units. + Return a boolean when asked whether the input is in the list of units. INPUT: @@ -1261,6 +1266,7 @@ def is_unit(s): """ return str(s) in unit_to_type + def convert(expr, target): """ Converts units between expr and target. If target is None then converts to SI base units. @@ -1345,7 +1351,7 @@ def convert(expr, target): if is_unit(y): tz[y] = base_units(y) base_target = base_target.subs(tz) - coeff = (expr/base_target).expand() + coeff = (expr / base_target).expand() for variable in coeff.variables(): if is_unit(str(variable)): @@ -1353,6 +1359,7 @@ def convert(expr, target): return coeff.mul(target, hold=True) + def base_units(unit): """ Converts unit to base SI units. @@ -1397,12 +1404,13 @@ def base_units(unit): if str(v) in unit_derivations: base = unit_derivations_expr(v) for i in base.variables(): - base = base.subs({i:SR.var(value_to_unit[str(i)]['1'])}) - return base*sage_eval(unitdict[str(v)][str(unit)]) + base = base.subs({i: SR.var(value_to_unit[str(i)]['1'])}) + return base * sage_eval(unitdict[str(v)][str(unit)]) else: - base = SR.var(value_to_unit[str(v)]['1'])*sage_eval(unitdict[str(v)][str(unit)]) + base = SR.var(value_to_unit[str(v)]['1']) * sage_eval(unitdict[str(v)][str(unit)]) return base + def convert_temperature(expr, target): """ Function for converting between temperatures. @@ -1434,12 +1442,12 @@ def convert_temperature(expr, target): sage: t.convert(units.length.foot) Traceback (most recent call last): ... - ValueError: Cannot convert + ValueError: cannot convert sage: wrong = units.length.meter*units.temperature.fahrenheit sage: wrong.convert() Traceback (most recent call last): ... - ValueError: Cannot convert + ValueError: cannot convert We directly call the convert_temperature function:: @@ -1449,22 +1457,22 @@ def convert_temperature(expr, target): 98.6000000000000 """ if len(expr.variables()) != 1: - raise ValueError("Cannot convert") + raise ValueError("cannot convert") elif target is None or unit_to_type[str(target)] == 'temperature': from sage.misc.sage_eval import sage_eval expr_temp = expr.variables()[0] - coeff = expr/expr_temp + coeff = expr / expr_temp if target is not None: target_temp = target.variables()[0] a = sage_eval(unitdict['temperature'][str(expr_temp)], locals={'x': coeff}) - if target is None or target_temp == units.temperature.kelvin: - return a[0]*units.temperature.kelvin + if target is None or target_temp == units.temperature.kelvin: + return a[0] * units.temperature.kelvin elif target_temp == units.temperature.celsius or target_temp == units.temperature.centigrade: - return a[1]*target_temp + return a[1] * target_temp elif target_temp == units.temperature.fahrenheit: - return a[2]*units.temperature.fahrenheit + return a[2] * units.temperature.fahrenheit elif target_temp == units.temperature.rankine: - return a[3]*target_temp + return a[3] * target_temp else: - raise ValueError("Cannot convert") + raise ValueError("cannot convert") diff --git a/src/sage/tensor/__init__.py b/src/sage/tensor/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/tensor/modules/__init__.py b/src/sage/tensor/modules/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/tensor/modules/alternating_contr_tensor.py b/src/sage/tensor/modules/alternating_contr_tensor.py index 03047253b36..3ef51967bc6 100644 --- a/src/sage/tensor/modules/alternating_contr_tensor.py +++ b/src/sage/tensor/modules/alternating_contr_tensor.py @@ -311,7 +311,6 @@ def degree(self): """ return self._tensor_rank - def display(self, basis=None, format_spec=None): r""" Display the alternating contravariant tensor ``self`` in terms @@ -470,7 +469,6 @@ def display(self, basis=None, format_spec=None): disp = display - def wedge(self, other): r""" Exterior product of ``self`` with the alternating contravariant diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 8648e693fa1..482324c1b44 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1235,9 +1235,9 @@ def display(self, symbol, latex_symbol=None, index_positions=None, Check that the bug reported in :trac:`22520` is fixed:: - sage: c = Components(SR, [1, 2], 1) # optional - sage.symbolic - sage: c[0] = SR.var('t', domain='real') # optional - sage.symbolic - sage: c.display('c') # optional - sage.symbolic + sage: c = Components(SR, [1, 2], 1) # needs sage.symbolic + sage: c[0] = SR.var('t', domain='real') # needs sage.symbolic + sage: c.display('c') # needs sage.symbolic c_0 = t """ @@ -1683,7 +1683,6 @@ def __radd__(self, other): """ return self + other - def __sub__(self, other): r""" Component subtraction. @@ -1758,7 +1757,6 @@ def __rsub__(self, other): """ return (-self) + other - def __mul__(self, other): r""" Component tensor product. @@ -1922,7 +1920,6 @@ def paral_mul(a, b, local_list_ind): result._comp[ind_s + ind_o] = val_s * val_o return result - def __rmul__(self, other): r""" Reflected multiplication (multiplication on the left by ``other``). @@ -2521,11 +2518,8 @@ def non_redundant_index_generator(self): sage: list(c.non_redundant_index_generator()) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)] - """ - for ind in self.index_generator(): - yield ind - + yield from self.index_generator() def symmetrize(self, *pos): r""" @@ -3996,7 +3990,6 @@ def trace(self, pos1, pos2): result[[ind_res]] = res return result - def non_redundant_index_generator(self): r""" Generator of indices, with only ordered indices in case of symmetries, @@ -4439,7 +4432,6 @@ def symmetrize(self, *pos): result[[ind]] = sum / sym_group.order() return result - def antisymmetrize(self, *pos): r""" Antisymmetrization over the given index positions. @@ -5340,7 +5332,6 @@ def _new_instance(self): return CompFullyAntiSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) - def __add__(self, other): r""" Component addition. diff --git a/src/sage/tensor/modules/free_module_alt_form.py b/src/sage/tensor/modules/free_module_alt_form.py index 3569f686681..a11d3a447c9 100644 --- a/src/sage/tensor/modules/free_module_alt_form.py +++ b/src/sage/tensor/modules/free_module_alt_form.py @@ -554,11 +554,12 @@ def display(self, basis=None, format_spec=None): Check that the bug reported in :trac:`22520` is fixed:: - sage: M = FiniteRankFreeModule(SR, 2, name='M') # optional - sage.symbolic - sage: e = M.basis('e') # optional - sage.symbolic - sage: a = M.alternating_form(2) # optional - sage.symbolic - sage: a[0,1] = SR.var('t', domain='real') # optional - sage.symbolic - sage: a.display() # optional - sage.symbolic + sage: # needs sage.symbolic + sage: M = FiniteRankFreeModule(SR, 2, name='M') + sage: e = M.basis('e') + sage: a = M.alternating_form(2) + sage: a[0,1] = SR.var('t', domain='real') + sage: a.display() t e^0โˆงe^1 """ diff --git a/src/sage/tensor/modules/free_module_basis.py b/src/sage/tensor/modules/free_module_basis.py index 7369c93263e..7fb776621b9 100644 --- a/src/sage/tensor/modules/free_module_basis.py +++ b/src/sage/tensor/modules/free_module_basis.py @@ -905,7 +905,6 @@ def _init_from_family(self, family): aut.add_comp(self)[:] = mat fmodule.set_change_of_basis(basis, self, aut) - def module(self): r""" Return the free module on which the basis is defined. diff --git a/src/sage/tensor/modules/free_module_element.py b/src/sage/tensor/modules/free_module_element.py index 0bde6363822..d4e3f42a390 100644 --- a/src/sage/tensor/modules/free_module_element.py +++ b/src/sage/tensor/modules/free_module_element.py @@ -29,9 +29,18 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from __future__ import annotations + +from typing import TYPE_CHECKING, Optional + from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor from sage.tensor.modules.comp import Components +if TYPE_CHECKING: + from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule + from sage.tensor.modules.free_module_basis import FreeModuleBasis + + class FiniteRankFreeModuleElement(AlternatingContrTensor): r""" Element of a free module of finite rank over a commutative ring. @@ -185,7 +194,13 @@ class FiniteRankFreeModuleElement(AlternatingContrTensor): aโˆงb = -2 e_0โˆงe_1 - 6 e_0โˆงe_2 + 7 e_1โˆงe_2 """ - def __init__(self, fmodule, name=None, latex_name=None): + + def __init__( + self, + fmodule: FiniteRankFreeModule, + name: Optional[str] = None, + latex_name: Optional[str] = None, + ): r""" TESTS:: @@ -209,7 +224,7 @@ def __init__(self, fmodule, name=None, latex_name=None): AlternatingContrTensor.__init__(self, fmodule, 1, name=name, latex_name=latex_name) - def _repr_(self): + def _repr_(self) -> str: r""" Return a string representation of ``self``. @@ -227,7 +242,7 @@ def _repr_(self): description += "of the {}".format(self._fmodule) return description - def _new_comp(self, basis): + def _new_comp(self, basis: FreeModuleBasis) -> Components: r""" Create some (uninitialized) components of ``self`` in a given basis. @@ -258,7 +273,6 @@ def _new_comp(self, basis): return Components(fmodule._ring, basis, 1, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) - def _new_instance(self): r""" Create an instance of the same class as ``self``. diff --git a/src/sage/tensor/modules/free_module_homset.py b/src/sage/tensor/modules/free_module_homset.py index d240882961e..509ae146d49 100644 --- a/src/sage/tensor/modules/free_module_homset.py +++ b/src/sage/tensor/modules/free_module_homset.py @@ -466,7 +466,6 @@ def _coerce_map_from_(self, other): #### End of methods required for any Parent - #### Monoid methods (case of an endomorphism set) #### def one(self): diff --git a/src/sage/tensor/modules/free_module_linear_group.py b/src/sage/tensor/modules/free_module_linear_group.py index 1041ba71c31..36623143617 100644 --- a/src/sage/tensor/modules/free_module_linear_group.py +++ b/src/sage/tensor/modules/free_module_linear_group.py @@ -407,7 +407,6 @@ def _element_constructor_(self, comp=[], basis=None, name=None, resu.set_comp(basis)[:] = comp return resu - def _an_element_(self): r""" Construct some specific free module automorphism. @@ -550,7 +549,6 @@ def _latex_(self): from sage.misc.latex import latex return r"\mathrm{GL}\left("+ latex(self._fmodule)+ r"\right)" - def base_module(self): r""" Return the free module of which ``self`` is the general linear group. diff --git a/src/sage/tensor/modules/free_module_morphism.py b/src/sage/tensor/modules/free_module_morphism.py index abb24e89203..073cb91e60c 100644 --- a/src/sage/tensor/modules/free_module_morphism.py +++ b/src/sage/tensor/modules/free_module_morphism.py @@ -23,8 +23,15 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.rings.integer import Integer +from __future__ import annotations + +from typing import TYPE_CHECKING + from sage.categories.morphism import Morphism +from sage.rings.integer import Integer + +if TYPE_CHECKING: + from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement class FiniteRankFreeModuleMorphism(Morphism): @@ -681,7 +688,6 @@ def _lmul_(self, scalar): resu._matrices[bases] = scalar * mat return resu - # # Other module methods # @@ -764,7 +770,9 @@ def __neg__(self): # Map methods # - def _call_(self, element): + def _call_( + self, element: FiniteRankFreeModuleElement + ) -> FiniteRankFreeModuleElement: r""" Action of the homomorphism ``self`` on some free module element @@ -1050,7 +1058,7 @@ def matrix(self, basis1=None, basis2=None): sage: phi.matrix(e, f) # given bases [-1 2 0] [ 5 1 2] - sage: type(phi.matrix()) + sage: type(phi.matrix()) # needs sage.libs.flint <class 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'> Matrix in bases different from those in which the homomorphism has diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index a7865299688..4d84d76b58a 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -194,19 +194,27 @@ class being: # ***************************************************************************** from __future__ import annotations -from typing import TYPE_CHECKING, Dict +from typing import TYPE_CHECKING, Dict, Optional, Union +from sage.parallel.decorate import parallel +from sage.parallel.parallelism import Parallelism from sage.rings.integer import Integer from sage.structure.element import ModuleElementWithMutability -from sage.tensor.modules.comp import (Components, CompWithSym, CompFullySym, - CompFullyAntiSym) +from sage.tensor.modules.comp import ( + CompFullyAntiSym, + CompFullySym, + Components, + CompWithSym, +) from sage.tensor.modules.tensor_with_indices import TensorWithIndices -from sage.parallel.decorate import parallel -from sage.parallel.parallelism import Parallelism if TYPE_CHECKING: + from sage.symbolic.expression import Expression from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule from sage.tensor.modules.free_module_basis import FreeModuleBasis + from sage.manifolds.differentiable.metric import PseudoRiemannianMetric + from sage.manifolds.differentiable.poisson_tensor import PoissonTensorField + from sage.manifolds.differentiable.symplectic_form import SymplecticForm class FreeModuleTensor(ModuleElementWithMutability): @@ -264,8 +272,8 @@ def __init__( self, fmodule: FiniteRankFreeModule, tensor_type, - name=None, - latex_name=None, + name: Optional[str] = None, + latex_name: Optional[str] = None, sym=None, antisym=None, parent=None, @@ -672,10 +680,11 @@ def display(self, basis=None, format_spec=None): Check that the bug reported in :trac:`22520` is fixed:: - sage: M = FiniteRankFreeModule(SR, 3, name='M') # optional - sage.symbolic - sage: e = M.basis('e') # optional - sage.symbolic - sage: t = SR.var('t', domain='real') # optional - sage.symbolic - sage: (t*e[0]).display() # optional - sage.symbolic + sage: # needs sage.symbolic + sage: M = FiniteRankFreeModule(SR, 3, name='M') + sage: e = M.basis('e') + sage: t = SR.var('t', domain='real') + sage: (t*e[0]).display() t e_0 """ @@ -891,7 +900,7 @@ def display_comp(self, basis=None, format_spec=None, symbol=None, only_nonzero=only_nonzero, only_nonredundant=only_nonredundant) - def set_name(self, name=None, latex_name=None): + def set_name(self, name: Optional[str] = None, latex_name: Optional[str] = None): r""" Set (or change) the text name and LaTeX name of ``self``. @@ -1144,7 +1153,6 @@ def paral_newcomp(old_comp, ppinv, pp, n_con, rank, local_list_ind): for jj in val: new_comp[[jj[0]]] = jj[1] - else: # Sequential computation for ind_new in new_comp.non_redundant_index_generator(): @@ -1556,7 +1564,6 @@ def __getitem__(self, args) -> Components: basis = self._fmodule._def_basis return self.comp(basis)[args] - def __setitem__(self, args, value): r""" Set a component w.r.t. some basis. @@ -2262,7 +2269,7 @@ def __truediv__(self, other): result._components[basis] = self._components[basis] / other return result - def __call__(self, *args): + def __call__(self, *args) -> Expression: r""" The tensor acting on linear forms and module elements as a multilinear map. @@ -2442,10 +2449,20 @@ def __call__(self, *args): res._latex_name = res_latex return res - def trace(self, pos1=0, pos2=1): + def trace( + self, + pos1: int = 0, + pos2: int = 1, + using: Optional[ + Union[PseudoRiemannianMetric, SymplecticForm, PoissonTensorField] + ] = None, + ): r""" Trace (contraction) on two slots of the tensor. + If a non-degenerate form is provided, the trace of a type-`(0,2)` tensor + is computed by first raising the last index. + INPUT: - ``pos1`` -- (default: 0) position of the first index for the @@ -2455,6 +2472,8 @@ def trace(self, pos1=0, pos2=1): contraction, with the same convention as for ``pos1``; the variance type of ``pos2`` must be opposite to that of ``pos1`` + - ``using`` -- (default: ``None``) a non-degenerate form + OUTPUT: - tensor or scalar resulting from the ``(pos1, pos2)`` contraction @@ -2497,7 +2516,7 @@ def trace(self, pos1=0, pos2=1): The contraction on two slots having the same tensor type cannot occur:: - sage: b = M.tensor((2,0), name='b') ; b + sage: b = M.tensor((2,0), name='b') ; b Type-(2,0) tensor b on the Rank-3 free module M over the Integer Ring sage: b[:] = [[1,2,3], [4,5,6], [7,8,9]] sage: b.trace(0,1) @@ -2565,6 +2584,13 @@ def trace(self, pos1=0, pos2=1): True """ + if using is not None: + if self.tensor_type() != (0, 2): + raise ValueError( + "trace with respect to a non-degenerate form is only defined for type-(0,2) tensor" + ) + return self.up(using, 1).trace() + # The indices at pos1 and pos2 must be of different types: k_con = self._tensor_type[0] l_cov = self._tensor_type[1] @@ -3075,7 +3101,6 @@ def symmetrize(self, *pos, **kwargs): res_comp = self._components[basis].symmetrize(*pos) return self._fmodule.tensor_from_comp(self._tensor_type, res_comp) - def antisymmetrize(self, *pos, **kwargs): r""" Antisymmetrization over some arguments. diff --git a/src/sage/tensor/modules/reflexive_module.py b/src/sage/tensor/modules/reflexive_module.py index f9ca8f6ab71..073f76e4659 100644 --- a/src/sage/tensor/modules/reflexive_module.py +++ b/src/sage/tensor/modules/reflexive_module.py @@ -256,9 +256,9 @@ def base_module(self): sage: M.base_module() is M True - sage: M = Manifold(2, 'M') - sage: XM = M.vector_field_module() - sage: XM.base_module() is XM + sage: M = Manifold(2, 'M') # needs sage.symbolic + sage: XM = M.vector_field_module() # needs sage.symbolic + sage: XM.base_module() is XM # needs sage.symbolic True """ return self @@ -273,9 +273,9 @@ def tensor_type(self): sage: M.tensor_type() (1, 0) - sage: M = Manifold(2, 'M') - sage: XM = M.vector_field_module() - sage: XM.tensor_type() + sage: M = Manifold(2, 'M') # needs sage.symbolic + sage: XM = M.vector_field_module() # needs sage.symbolic + sage: XM.tensor_type() # needs sage.symbolic (1, 0) """ return (1, 0) diff --git a/src/sage/tensor/modules/tensor_with_indices.py b/src/sage/tensor/modules/tensor_with_indices.py index fd5eaf6824b..2e4c611b11a 100644 --- a/src/sage/tensor/modules/tensor_with_indices.py +++ b/src/sage/tensor/modules/tensor_with_indices.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.groups r""" Index notation for tensors @@ -19,7 +19,6 @@ #****************************************************************************** from sage.structure.sage_object import SageObject -from sage.groups.perm_gps.permgroup import PermutationGroup import re from itertools import combinations @@ -225,8 +224,8 @@ class TensorWithIndices(SageObject): sage: a['^ฮผฮพ'] a^ฮผฮพ - Conventions are checked and non acceptable indices raise ``ValueError``, - for instance:: + Conventions are checked and non acceptable indices raise + :class:`ValueError`, for instance:: sage: a['([..])'] # nested symmetries Traceback (most recent call last): @@ -385,7 +384,6 @@ def _parse_indices(indices, tensor_type=None, allow_contraction=True, "with the tensor type") return con,cov - def __init__(self, tensor, indices): r""" TESTS:: @@ -426,7 +424,7 @@ def __init__(self, tensor, indices): con,cov = self._parse_indices( indices, - tensor_type = self._tensor.tensor_type() + tensor_type=self._tensor.tensor_type() ) # Apply (anti)symmetrizations on contravariant indices @@ -628,7 +626,6 @@ def __mul__(self, other): True sage: s[:] [3, -6, 9] - """ if not isinstance(other, TensorWithIndices): raise TypeError("the second item of * must be a tensor with " + @@ -636,12 +633,12 @@ def __mul__(self, other): contraction_pairs = [] for ind in self._con: if ind != '.': - if ind in other._cov: + if ind in other._cov: pos1 = self._con.index(ind) pos2 = other._tensor._tensor_type[0] + other._cov.index(ind) contraction_pairs.append((pos1, pos2)) if ind in other._con: - raise IndexError("the index {} appears twice ".format(ind) + raise IndexError(f"the index {ind} appears twice " + "in a contravariant position") for ind in self._cov: if ind != '.': @@ -650,7 +647,7 @@ def __mul__(self, other): pos2 = other._con.index(ind) contraction_pairs.append((pos1, pos2)) if ind in other._cov: - raise IndexError("the index {} appears twice ".format(ind) + raise IndexError(f"the index {ind} appears twice " + "in a covariant position") if not contraction_pairs: # No contraction is performed: the tensor product is returned @@ -741,7 +738,6 @@ def __add__(self, other): result._tensor = result._tensor + other.permute_indices(permutation)._tensor return result - def __sub__(self, other): r""" Subtraction between tensors with indices. @@ -960,9 +956,11 @@ def swap(param,N): return L # Construction of the permutation group generated by swaps + from sage.groups.perm_gps.permgroup import PermutationGroup + perm_group = PermutationGroup( [swap(param, self._tensor.tensor_rank()) for param in swap_params], - canonicalize = False + canonicalize=False ) # Compute a decomposition of the permutation as a product of swaps decomposition_as_string = perm_group([x+1 for x in permutation]).word_problem( diff --git a/src/sage/tests/arxiv_0812_2725.py b/src/sage/tests/arxiv_0812_2725.py index 093025373e1..3f304803c31 100644 --- a/src/sage/tests/arxiv_0812_2725.py +++ b/src/sage/tests/arxiv_0812_2725.py @@ -73,8 +73,7 @@ def CompleteMatchings(n): integer depends on what [1..n] returns, and also on what range(1, len([1..n])) is. """ - for m in matchingsset(list(range(1, n + 1))): - yield m + yield from matchingsset(list(range(1, n + 1))) def matchingsset(L): diff --git a/src/sage/tests/benchmark.py b/src/sage/tests/benchmark.py index 1eb66f6c28b..6ac0136c653 100644 --- a/src/sage/tests/benchmark.py +++ b/src/sage/tests/benchmark.py @@ -15,7 +15,30 @@ sage: import sage.tests.benchmark """ -from sage.all import * # QQ, alarm, ModularSymbols, gp, pari, cputime, EllipticCurve +from cysignals.alarm import alarm, cancel_alarm, AlarmInterrupt +from sage.combinat.combinat import fibonacci +from sage.functions.other import factorial +from sage.interfaces.gap import gap +from sage.interfaces.gp import gp +from sage.interfaces.macaulay2 import macaulay2 +from sage.interfaces.magma import magma, Magma +from sage.interfaces.maple import maple +from sage.interfaces.mathematica import mathematica +from sage.interfaces.maxima import maxima +from sage.interfaces.singular import singular +from sage.libs.pari import pari +from sage.matrix.matrix_space import MatrixSpace +from sage.misc.functional import log +from sage.misc.timing import cputime, walltime +from sage.modular.modsym.modsym import ModularSymbols +from sage.rings.complex_mpfr import ComplexField +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.finite_rings.integer_mod_ring import Integers +from sage.rings.rational_field import QQ +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.schemes.elliptic_curves.constructor import EllipticCurve def avg(X): """ @@ -49,7 +72,7 @@ class Benchmark: sage: B = Benchmark() sage: def python(): ....: t = cputime() - ....: n = 2+2 + ....: 2+2 ....: return cputime(t) sage: B.python = python sage: B.run(systems=['python']) @@ -182,7 +205,7 @@ def sage(self): n = self.__n t = cputime() E = EllipticCurve([1,2,3,4,5]) - f = E.division_polynomial(n) + E.division_polynomial(n) return cputime(t) def magma(self): @@ -199,7 +222,7 @@ def magma(self): """ n = self.__n t = magma.cputime() - m = magma('DivisionPolynomial(EllipticCurve([1,2,3,4,5]), %s)'%n) + magma('DivisionPolynomial(EllipticCurve([1,2,3,4,5]), %s)'%n) return magma.cputime(t) class PolySquare(Benchmark): @@ -224,7 +247,7 @@ def sage(self): n = self.__n f = R['x'](range(1,n+1)) t = cputime() - g = f**2 + f**2 return cputime(t) def magma(self): @@ -242,7 +265,7 @@ def magma(self): R = magma(self.__R) f = magma('PolynomialRing(%s)![1..%s]'%(R.name(),self.__n)) t = magma.cputime() - g = f*f + f*f return magma.cputime(t) def maple(self): @@ -263,7 +286,7 @@ def maple(self): n = self.__n f = maple(str(R['x'](range(1,n+1)))) t = walltime() - g = f*f + f*f return False, walltime(t) class MPolynomialPower(Benchmark): @@ -295,10 +318,10 @@ def sage(self): if self.allow_singular: z = singular(sum(R.gens())) t = walltime() - w = z**self.exp + z**self.exp return False, walltime(t) t = cputime() - w = z**self.exp + z**self.exp return cputime(t) def macaulay2(self): @@ -316,7 +339,7 @@ def macaulay2(self): R = PolynomialRing(self.base, self.nvars, 'x') z = macaulay2(sum(R.gens())) t = walltime() - w = z**self.exp + z**self.exp return False, walltime(t) def maxima(self): @@ -334,7 +357,7 @@ def maxima(self): R = PolynomialRing(self.base, self.nvars, 'x') z = maxima(str(sum(R.gens()))) w = walltime() - f = (z**self.exp).expand() + (z**self.exp).expand() return False, walltime(w) def maple(self): @@ -352,7 +375,7 @@ def maple(self): R = PolynomialRing(self.base, self.nvars, 'x') z = maple(str(sum(R.gens()))) w = walltime() - f = (z**self.exp).expand() + (z**self.exp).expand() return False, walltime(w) def mathematica(self): @@ -370,7 +393,7 @@ def mathematica(self): R = PolynomialRing(self.base, self.nvars, 'x') z = mathematica(str(sum(R.gens()))) w = walltime() - f = (z**self.exp).Expand() + (z**self.exp).Expand() return False, walltime(w) ## this doesn't really expand out -- pari has no function to do so, @@ -379,10 +402,9 @@ def mathematica(self): ## R = PolynomialRing(self.base, self.nvars) ## z = gp(str(sum(R.gens()))) ## gp.eval('gettime') -## f = z**self.exp +## z**self.exp ## return float(gp.eval('gettime/1000.0')) - def magma(self): """ Time the computation in Magma. @@ -400,11 +422,10 @@ def magma(self): for i in range(2,self.nvars+1): z += R.gen(i) t = magma.cputime() - w = z**magma(self.exp) + z**magma(self.exp) return magma.cputime(t) - class MPolynomialMult(Benchmark): def __init__(self, nvars=2, base=QQ, allow_singular=True): if nvars%2: @@ -412,7 +433,7 @@ def __init__(self, nvars=2, base=QQ, allow_singular=True): self.nvars = nvars self.base = base self.allow_singular = allow_singular - s = 'Compute (x_0 + ... + x_%s) * (x_%s + ... + x_%s) over %s'%( + s = 'Compute (x_0 + ... + x_%s) * (x_%s + ... + x_%s) over %s'%( self.nvars/2 - 1, self.nvars/2, self.nvars, self.base) if self.allow_singular: s += ' (use singular for Sage mult.)' @@ -435,7 +456,7 @@ def maxima(self): z0 = maxima(str(sum(R.gens()[:k]))) z1 = maxima(str(sum(R.gens()[k:]))) w = walltime() - f = (z0*z1).expand() + (z0*z1).expand() return False, walltime(w) def maple(self): @@ -455,7 +476,7 @@ def maple(self): z0 = maple(str(sum(R.gens()[:k]))) z1 = maple(str(sum(R.gens()[k:]))) w = walltime() - f = (z0*z1).expand() + (z0*z1).expand() return False, walltime(w) def mathematica(self): @@ -475,7 +496,7 @@ def mathematica(self): z0 = mathematica(str(sum(R.gens()[:k]))) z1 = mathematica(str(sum(R.gens()[k:]))) w = walltime() - f = (z0*z1).Expand() + (z0*z1).Expand() return False, walltime(w) ## def gp(self): @@ -484,7 +505,7 @@ def mathematica(self): ## z0 = gp(str(sum(R.gens()[:k]))) ## z1 = gp(str(sum(R.gens()[k:]))) ## gp.eval('gettime') -## f = z0*z1 +## z0*z1 ## return float(gp.eval('gettime/1000.0')) def sage(self): @@ -507,11 +528,11 @@ def sage(self): z0 = singular(z0) z1 = singular(z1) t = walltime() - w = z0*z1 + z0*z1 return False, walltime(t) else: t = cputime() - w = z0 * z1 + z0 * z1 return cputime(t) def macaulay2(self): @@ -531,7 +552,7 @@ def macaulay2(self): z0 = macaulay2(sum(R.gens()[:k])) z1 = macaulay2(sum(R.gens()[k:])) t = walltime() - w = z0*z1 + z0*z1 return False, walltime(t) def magma(self): @@ -555,7 +576,7 @@ def magma(self): for i in range(k+1, self.nvars + 1): z1 += R.gen(i) t = magma.cputime() - w = z0 * z1 + z0 * z1 return magma.cputime(t) class MPolynomialMult2(Benchmark): @@ -565,7 +586,7 @@ def __init__(self, nvars=2, base=QQ, allow_singular=True): self.nvars = nvars self.base = base self.allow_singular = allow_singular - s = 'Compute (x_1 + 2*x_2 + 3*x_3 + ... + %s*x_%s) * (%s * x_%s + ... + %s*x_%s) over %s'%( + s = 'Compute (x_1 + 2*x_2 + 3*x_3 + ... + %s*x_%s) * (%s * x_%s + ... + %s*x_%s) over %s'%( self.nvars/2, self.nvars/2, self.nvars/2+1, self.nvars/2+1, self.nvars+1, self.nvars+1, self.base) if self.allow_singular: @@ -584,7 +605,7 @@ def __init__(self, nvars=2, base=QQ, allow_singular=True): ## z0 = gp(str(z0)) ## z1 = gp(str(z1)) ## gp.eval('gettime') -## f = z0*z1 +## z0*z1 ## return float(gp.eval('gettime/1000.0')) def maxima(self): @@ -610,7 +631,7 @@ def maxima(self): z0 = maxima(str(z0)) z1 = maxima(str(z1)) w = walltime() - f = (z0*z1).expand() + (z0*z1).expand() return False, walltime(w) def macaulay2(self): @@ -636,7 +657,7 @@ def macaulay2(self): z0 = macaulay2(z0) z1 = macaulay2(z1) t = walltime() - w = z0*z1 + z0*z1 return False, walltime(t) def maple(self): @@ -662,7 +683,7 @@ def maple(self): z0 = maple(str(z0)) z1 = maple(str(z1)) w = walltime() - f = (z0*z1).expand() + (z0*z1).expand() return False, walltime(w) def mathematica(self): @@ -688,7 +709,7 @@ def mathematica(self): z0 = mathematica(str(z0)) z1 = mathematica(str(z1)) w = walltime() - f = (z0*z1).Expand() + (z0*z1).Expand() return False, walltime(w) def sage(self): @@ -715,11 +736,11 @@ def sage(self): z0 = singular(z0) z1 = singular(z1) t = walltime() - w = z0*z1 + z0*z1 return False, walltime(t) else: t = cputime() - w = z0 * z1 + z0 * z1 return cputime(t) def magma(self): @@ -743,11 +764,10 @@ def magma(self): for i in range(k+1, self.nvars + 1): z1 += magma(i)*R.gen(i) t = magma.cputime() - w = z0 * z1 + z0 * z1 return magma.cputime(t) - class CharPolyTp(Benchmark): def __init__(self, N=37,k=2,p=2,sign=1): self.N = N @@ -777,7 +797,7 @@ def sage(self): """ m = self.matrix() t = cputime() - f = m.charpoly('x') + m.charpoly('x') return cputime(t) def gp(self): @@ -794,7 +814,7 @@ def gp(self): """ m = gp(self.matrix()) gp.eval('gettime') - f = m.charpoly('x') + m.charpoly('x') return float(gp.eval('gettime/1000.0')) def pari(self): @@ -811,7 +831,7 @@ def pari(self): """ m = pari(self.matrix()) t = cputime() - f = m.charpoly('x') + m.charpoly('x') return cputime(t) def magma(self): @@ -828,12 +848,10 @@ def magma(self): """ m = magma(self.matrix()) t = magma.cputime() - f = m.CharacteristicPolynomial() + m.CharacteristicPolynomial() return magma.cputime(t) - - class PolyFactor(Benchmark): def __init__(self, n, R): self.__n = n @@ -903,7 +921,6 @@ def gp(self): return float(gp.eval('gettime/1000.0')) - class SquareInts(Benchmark): def __init__(self, base=10, ndigits=10**5): self.__ndigits = ndigits @@ -924,7 +941,7 @@ def sage(self): """ n = Integer(self.base)**self.__ndigits t = cputime() - m = n**2 + n**2 return cputime(t) def gp(self): @@ -941,7 +958,7 @@ def gp(self): """ n = gp('%s^%s'%(self.base,self.__ndigits)) gp.eval('gettime') - m = n**2 + n**2 return float(gp.eval('gettime/1000.0')) def maxima(self): @@ -958,7 +975,7 @@ def maxima(self): """ n = maxima('%s^%s'%(self.base,self.__ndigits)) t = walltime() - m = n**2 + n**2 return False, walltime(t) def magma(self): @@ -975,7 +992,7 @@ def magma(self): """ n = magma('%s^%s'%(self.base,self.__ndigits)) t = magma.cputime() - m = n**2 + n**2 return magma.cputime(t) def python(self): @@ -992,7 +1009,7 @@ def python(self): """ n = self.base**self.__ndigits t = cputime() - m = n**2 + n**2 return cputime(t) def maple(self): @@ -1009,7 +1026,7 @@ def maple(self): """ n = maple('%s^%s'%(self.base,self.__ndigits)) t = walltime() - m = n**2 + n**2 return False, walltime(t) def gap(self): @@ -1026,7 +1043,7 @@ def gap(self): """ n = gap('%s^%s'%(self.base,self.__ndigits)) t = walltime() - m = n**2 + n**2 return False, walltime(t) def mathematica(self): @@ -1043,7 +1060,7 @@ def mathematica(self): """ n = mathematica('%s^%s'%(self.base,self.__ndigits)) t = walltime() - m = n**2 + n**2 return False, walltime(t) @@ -1069,7 +1086,7 @@ def sage(self): n = self.__n f = MatrixSpace(R,n)(list(range(n*n))) t = cputime() - g = f**2 + f**2 return cputime(t) def magma(self): @@ -1088,7 +1105,7 @@ def magma(self): f = magma('MatrixAlgebra(%s, %s)![0..%s^2-1]'%( R.name(),self.__n, self.__n)) t = magma.cputime() - g = f*f + f*f return magma.cputime(t) def gp(self): @@ -1106,7 +1123,7 @@ def gp(self): n = self.__n m = gp('matrix(%s,%s,m,n,%s*(m-1)+(n-1))'%(n,n,n)) gp('gettime') - n = m*m + m*m return float(gp.eval('gettime/1000.0')) def gap(self): @@ -1124,7 +1141,7 @@ def gap(self): n = self.__n m = gap(str([list(range(n*k,n*(k+1))) for k in range(n)])) t = walltime() - j = m*m + m*m return False, walltime(t) @@ -1146,7 +1163,7 @@ def sage(self): """ t = cputime() - n = factorial(self.__n) + factorial(self.__n) return cputime(t) def magma(self): @@ -1162,7 +1179,7 @@ def magma(self): """ t = magma.cputime() - n = magma('&*[1..%s]'%self.__n) # &* is way better than Factorial!! + magma('&*[1..%s]'%self.__n) # &* is way better than Factorial!! return magma.cputime(t) def maple(self): @@ -1179,7 +1196,7 @@ def maple(self): """ n = maple(self.__n) t = walltime() - m = n.factorial() + n.factorial() return False, walltime(t) def gp(self): @@ -1195,7 +1212,7 @@ def gp(self): """ gp.eval('gettime') - n = gp('%s!'%self.__n) + gp('%s!'%self.__n) return float(gp.eval('gettime/1000.0')) class Fibonacci(Benchmark): @@ -1216,7 +1233,7 @@ def sage(self): """ t = cputime() - n = fibonacci(self.__n) + fibonacci(self.__n) return cputime(t) def magma(self): @@ -1232,7 +1249,7 @@ def magma(self): """ t = magma.cputime() - n = magma('Fibonacci(%s)'%self.__n) + magma('Fibonacci(%s)'%self.__n) return magma.cputime(t) def gap(self): @@ -1249,7 +1266,7 @@ def gap(self): """ n = gap(self.__n) t = walltime() - m = n.Fibonacci() + n.Fibonacci() return False, walltime(t) def mathematica(self): @@ -1266,7 +1283,7 @@ def mathematica(self): """ n = mathematica(self.__n) t = walltime() - m = n.Fibonacci() + n.Fibonacci() return False, walltime(t) def gp(self): @@ -1282,11 +1299,10 @@ def gp(self): """ gp.eval('gettime') - n = gp('fibonacci(%s)'%self.__n) + gp('fibonacci(%s)'%self.__n) return float(gp.eval('gettime/1000.0')) - class SEA(Benchmark): def __init__(self, p): self.__p = p @@ -1310,7 +1326,7 @@ def sage(self): # pari library, but only for large primes, so for a better # test a prime > 2^30 should be used and not 5. In fact # next_prime(2^100) works fine (<<1s). - n = E.change_ring(GF(self.__p)).cardinality_pari() + E.change_ring(GF(self.__p)).cardinality_pari() return False, walltime(t) def magma(self): @@ -1327,7 +1343,7 @@ def magma(self): """ magma(0) t = magma.cputime() - m = magma('#EllipticCurve([GF(%s)|1,2,3,4,5])'%(self.__p)) + magma('#EllipticCurve([GF(%s)|1,2,3,4,5])'%(self.__p)) return magma.cputime(t) class MatrixKernel(Benchmark): @@ -1352,7 +1368,7 @@ def sage(self): n = self.__n f = MatrixSpace(R,n,2*n)(list(range(n*(2*n)))) t = cputime() - g = f.kernel() + f.kernel() return cputime(t) def magma(self): @@ -1371,7 +1387,7 @@ def magma(self): f = magma('RMatrixSpace(%s, %s, %s)![0..(%s*2*%s)-1]'%( R.name(),self.__n, 2*self.__n, self.__n, self.__n)) t = magma.cputime() - g = f.Kernel() + f.Kernel() return magma.cputime(t) def gp(self): @@ -1389,7 +1405,7 @@ def gp(self): n = self.__n m = gp('matrix(%s,%s,m,n,%s*(m-1)+(n-1))'%(n,2*n,n)) gp('gettime') - n = m.matker() + m.matker() return float(gp.eval('gettime/1000.0')) class ComplexMultiply(Benchmark): @@ -1413,7 +1429,7 @@ def sage(self): CC = ComplexField(self.__bits_prec) s = CC(2).sqrt() + (CC.gen()*2).sqrt() t = cputime() - v = [s*s for _ in range(self.__times)] + [s*s for _ in range(self.__times)] return cputime(t) def magma(self): @@ -1437,7 +1453,7 @@ def magma(self): s = CC(2).Sqrt() + CC.gen(1).Sqrt() t = magma.cputime() magma.eval('s := %s;'%s.name()) - v = magma('[s*s : i in [1..%s]]'%self.__times) + magma('[s*s : i in [1..%s]]'%self.__times) return magma.cputime(t) def gp(self): @@ -1456,7 +1472,7 @@ def gp(self): gp.set_real_precision(n) gp.eval('s = sqrt(2) + sqrt(2*I);') gp.eval('gettime;') - v = gp('vector(%s,i,s*s)'%self.__times) + gp('vector(%s,i,s*s)'%self.__times) return float(gp.eval('gettime/1000.0')) class ModularSymbols1(Benchmark): @@ -1478,7 +1494,7 @@ def sage(self): """ t = cputime() - M = ModularSymbols(self.__N, self.__k) + ModularSymbols(self.__N, self.__k) return cputime(t) def magma(self): @@ -1495,7 +1511,7 @@ def magma(self): """ magma = Magma() # new instance since otherwise modsyms are cached, and cache can't be cleared t = magma.cputime() - M = magma('ModularSymbols(%s, %s)'%(self.__N, self.__k)) + magma('ModularSymbols(%s, %s)'%(self.__N, self.__k)) return magma.cputime(t) class ModularSymbolsDecomp1(Benchmark): @@ -1520,7 +1536,7 @@ def sage(self): """ t = cputime() M = ModularSymbols(self.N, self.k, sign=self.sign, use_cache=False) - D = M.decomposition(self.bnd) + M.decomposition(self.bnd) return cputime(t) def magma(self): @@ -1537,7 +1553,7 @@ def magma(self): """ m = Magma() # new instance since otherwise modsyms are cached, and cache can't be cleared t = m.cputime() - D = m.eval('Decomposition(ModularSymbols(%s, %s, %s),%s);'%( + m.eval('Decomposition(ModularSymbols(%s, %s, %s),%s);'%( self.N, self.k, self.sign, self.bnd)) return m.cputime(t) @@ -1562,7 +1578,7 @@ def sage(self): """ E = EllipticCurve([1,2,3,4,5]) t = cputime() - v = E.anlist(self.B, pari_ints=True) + E.anlist(self.B, pari_ints=True) return cputime(t) def magma(self): @@ -1579,7 +1595,7 @@ def magma(self): """ E = magma.EllipticCurve([1,2,3,4,5]) t = magma.cputime() - v = E.TracesOfFrobenius(self.B) + E.TracesOfFrobenius(self.B) return magma.cputime(t) class EllipticCurvePointMul(Benchmark): @@ -1602,7 +1618,7 @@ def sage(self): E = EllipticCurve([0, 0, 1, -1, 0]) P = E([0,0]) t = cputime() - Q = self.n * P + self.n * P return cputime(t) def magma(self): @@ -1620,7 +1636,7 @@ def magma(self): E = magma.EllipticCurve('[0, 0, 1, -1, 0]') P = E('[0,0]') t = magma.cputime() - Q = magma(self.n) * P + magma(self.n) * P return magma.cputime(t) def gp(self): @@ -1638,7 +1654,7 @@ def gp(self): E = gp.ellinit('[0, 0, 1, -1, 0]') gp.eval('gettime') P = gp([0,0]) - Q = E.ellmul(P, self.n) + E.ellmul(P, self.n) return float(gp.eval('gettime/1000.0')) def pari(self): @@ -1656,7 +1672,7 @@ def pari(self): E = pari('ellinit([0, 0, 1, -1, 0])') pari('gettime') P = pari([0,0]) - Q = E.ellmul(P, self.n) + E.ellmul(P, self.n) return float(pari('gettime/1000.0')) class EllipticCurveMW(Benchmark): @@ -1678,7 +1694,7 @@ def sage(self): """ E = EllipticCurve(self.ainvs) t = walltime() - G = E.gens() + E.gens() return False, walltime(t) def magma(self): @@ -1695,7 +1711,7 @@ def magma(self): """ E = magma.EllipticCurve(str(self.ainvs)) t = magma.cputime() - G = E.Generators() + E.Generators() return magma.cputime(t) class FiniteExtFieldMult(Benchmark): @@ -1721,7 +1737,7 @@ def sage(self): e = self.e f = self.f t = cputime() - v = [e*f for _ in range(self.__times)] + [e*f for _ in range(self.__times)] return cputime(t) def pari(self): @@ -1739,7 +1755,7 @@ def pari(self): e = self.e.__pari__() f = self.f.__pari__() t = cputime() - v = [e*f for _ in range(self.__times)] + [e*f for _ in range(self.__times)] return cputime(t) def magma(self): @@ -1758,7 +1774,7 @@ def magma(self): magma.eval('e := a^Floor(%s/3);'%(self.field.cardinality())) magma.eval('f := a^Floor(2*%s/3);'%(self.field.cardinality())) t = magma.cputime() - v = magma('[e*f : i in [1..%s]]'%self.__times) + magma('[e*f : i in [1..%s]]'%self.__times) return magma.cputime(t) @@ -1785,7 +1801,7 @@ def sage(self): e = self.e f = self.f t = cputime() - v = [e+f for _ in range(self.__times)] + [e+f for _ in range(self.__times)] return cputime(t) def pari(self): @@ -1803,7 +1819,7 @@ def pari(self): e = self.e.__pari__() f = self.f.__pari__() t = cputime() - v = [e+f for _ in range(self.__times)] + [e+f for _ in range(self.__times)] return cputime(t) def magma(self): @@ -1822,7 +1838,7 @@ def magma(self): magma.eval('e := a^Floor(%s/3);'%(self.field.cardinality())) magma.eval('f := a^Floor(2*%s/3);'%(self.field.cardinality())) t = magma.cputime() - v = magma('[e+f : i in [1..%s]]'%self.__times) + magma('[e+f : i in [1..%s]]'%self.__times) return magma.cputime(t) @@ -1840,8 +1856,6 @@ def magma(self): """ - - def suite1(): PolySquare(10000,QQ).run() PolySquare(20000,ZZ).run() @@ -1855,9 +1869,9 @@ def suite1(): SquareInts(10,150000).run() - Factorial(2*10**6).run(systems = ['sage', 'magma']) + Factorial(2*10**6).run(systems=['sage', 'magma']) Fibonacci(10**6).run() - Fibonacci(2*10^7).run(systems=["sage", "magma", "mathematica"]) + Fibonacci(2*10**7).run(systems=["sage", "magma", "mathematica"]) MatrixKernel(150,QQ).run() @@ -1870,7 +1884,7 @@ def suite1(): PolyFactor(700,GF(19)) PolyFactor(500,GF(49,'a')) - PolyFactor(100,GF(10007^3,'a')) + PolyFactor(100,GF((10007,3),'a')) CharPolyTp(54,4).run() CharPolyTp(389,2).run() diff --git a/src/sage/tests/book_stein_ent.py b/src/sage/tests/book_stein_ent.py index aac0a11e922..c056e43aa55 100644 --- a/src/sage/tests/book_stein_ent.py +++ b/src/sage/tests/book_stein_ent.py @@ -21,10 +21,10 @@ sage: factor(31415926535898) 2 * 3 * 53 * 73 * 2531 * 534697 sage: n = 7403756347956171282804679609742957314259318888\ -...9231289084936232638972765034028266276891996419625117\ -...8439958943305021275853701189680982867331732731089309\ -...0055250511687706329907239638078671008609696253793465\ -...0563796359 +....: 9231289084936232638972765034028266276891996419625117\ +....: 8439958943305021275853701189680982867331732731089309\ +....: 0055250511687706329907239638078671008609696253793465\ +....: 0563796359 sage: len(n.str(2)) 704 sage: len(n.str(10)) @@ -287,8 +287,7 @@ sage: q = next_prime(randrange(2^97)) sage: n = p * q sage: qsieve(n) # long time (8s on sage.math, 2011) -([6340271405786663791648052309, - 46102313108592180286398757159], '') +[(6340271405786663791648052309, 1), (46102313108592180286398757159, 1)] sage: legendre_symbol(2,3) -1 sage: legendre_symbol(1,3) diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py index aa153fd4cd5..bdf2f5b1e1e 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py @@ -66,16 +66,7 @@ sage: liste = [10 + floor(10*sin(i)) for i in range(100)] sage: bar_chart(liste) Graphics object consisting of 1 graphics primitive - sage: finance.TimeSeries(liste).plot_histogram(bins=20) - doctest:warning... - DeprecationWarning: the package sage.finance is deprecated - See https://github.com/sagemath/sage/issues/32427 for details. - doctest:warning... - Importing finance from here is deprecated; please use "from sage.finance import all as finance" instead. - See https://github.com/sagemath/sage/issues/32427 for details. - doctest:warning... - Importing TimeSeries from here is deprecated; please use "from sage.stats.time_series import TimeSeries" instead. - See https://github.com/sagemath/sage/issues/32427 for details. + sage: TimeSeries(liste).plot_histogram(bins=20) Graphics object consisting of 20 graphics primitives Sage example in ./graphique.tex, line 714:: @@ -134,11 +125,11 @@ sage: t = srange(0, 5, 0.1); p = Graphics() sage: for k in srange(0, 10, 0.15): ....: y = integrate.odeint(f, k, t) - ....: p += line(zip(t, flatten(y))) + ....: p += line(zip(t, flatten(y.tolist()))) sage: t = srange(0, -5, -0.1); q = Graphics() sage: for k in srange(0, 10, 0.15): ....: y = integrate.odeint(f, k, t) - ....: q += line(zip(t, flatten(y))) + ....: q += line(zip(t, flatten(y.tolist()))) sage: y = var('y') sage: v = plot_vector_field((1, -cos(x*y)), (x,-5,5), (y,-2,11)) sage: g = p + q + v; g.show() @@ -215,11 +206,13 @@ sage: plot3d(h, (u,-1,1), (v,-1,1), aspect_ratio=[1,1,1]) Graphics3d Object -Sage example in ./graphique.tex, line 1833:: +Sage example in ./graphique.tex, line 1833. Sometimes the result +needs to be simplified to obtain a nice short expression:: sage: f(x, y) = x^2 * y / (x^4 + y^2) sage: t, theta = var('t, theta') - sage: limit(f(t * cos(theta), t * sin(theta)) / t, t=0) + sage: result = limit(f(t * cos(theta), t * sin(theta)) / t, t=0) + sage: result.full_simplify() cos(theta)^2/sin(theta) Sage example in ./graphique.tex, line 1847:: diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py index fcb293eb698..dbe787aa5ff 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py @@ -253,7 +253,7 @@ Sage example in ./integration.tex, line 1363:: sage: t, y = var('t, y') - sage: desolve_rk4(t*y*(2-y), y, ics=[0,1], end_points=[0, 1], step=0.5) + sage: desolve_rk4(t*y*(2-y), y, ics=[0,1], end_points=[0, 1], step=0.5) # abs tol 1e-12 [[0, 1], [0.5, 1.12419127424558], [1.0, 1.461590162288825]] Sage example in ./integration.tex, line 1399:: diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py index f3aa2201ac8..da89f065214 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py @@ -221,7 +221,7 @@ Sage example in ./lp.tex, line 906:: sage: while not h.is_connected(): - ....: S = h.connected_components()[0] + ....: S = h.connected_components(sort=False)[0] ....: p.add_constraint( ....: p.sum( B(u,v) for u,v ....: in g.edge_boundary(S, labels = False)) diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py index fae01daa748..42121f2f815 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py @@ -117,7 +117,7 @@ Sage example in ./premierspas.tex, line 1217:: - sage: from sage.all import pi + sage: from sage.symbolic.constants import pi Sage example in ./premierspas.tex, line 1224:: diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py index 50f936f8cba..95a6367dcee 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py @@ -56,9 +56,15 @@ Sage example in ./recequadiff.tex, line 459:: - sage: desolve(y == x*diff(y,x)-diff(y,x)^2, y, - ....: contrib_ode=True, show_method=True) - [[y(x) == -_C^2 + _C*x, y(x) == 1/4*x^2], 'clairault'] + sage: diffeq = y == x*diff(y,x)-diff(y,x)^2 + sage: solution,method = desolve(diffeq, + ....: y, + ....: contrib_ode=True, + ....: show_method=True) + sage: solution + [y(x) == -_C^2 + _C*x, y(x) == 1/4*x^2] + sage: method in ["clairaut", "clairault"] + True Sage example in ./recequadiff.tex, line 487:: diff --git a/src/sage/tests/cmdline.py b/src/sage/tests/cmdline.py index 12e73393206..f14cd2db768 100644 --- a/src/sage/tests/cmdline.py +++ b/src/sage/tests/cmdline.py @@ -72,7 +72,7 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False should end with a newline. - ``timeout`` -- if the program produces no output for ``timeout`` - seconds, a RuntimeError is raised. + seconds, a :class:`RuntimeError` is raised. - ``pydebug_ignore_warnings`` -- boolean. Set the PYTHONWARNINGS environment variable to ignore Python warnings when on a Python debug build (`--with-pydebug`, e.g. from building with @@ -110,56 +110,62 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False Run Sage itself with various options:: - sage: (out, err, ret) = test_executable(["sage"], pydebug_ignore_warnings=True) - sage: out.find(version()) >= 0 + sage: (out, err, ret) = test_executable([ # long time + ....: "sage"], pydebug_ignore_warnings=True) + sage: out.find(version()) >= 0 # long time True - sage: err + sage: err # long time '' - sage: ret + sage: ret # long time 0 - sage: (out, err, ret) = test_executable(["sage"], "3^33\n", pydebug_ignore_warnings=True) - sage: out.find(version()) >= 0 + sage: (out, err, ret) = test_executable([ # long time + ....: "sage"], "3^33\n", pydebug_ignore_warnings=True) + sage: out.find(version()) >= 0 # long time True - sage: out.find("5559060566555523") >= 0 + sage: out.find("5559060566555523") >= 0 # long time True - sage: err + sage: err # long time '' - sage: ret + sage: ret # long time 0 - sage: (out, err, ret) = test_executable(["sage", "-q"], "3^33\n", pydebug_ignore_warnings=True) - sage: out.find(version()) >= 0 + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", "-q"], "3^33\n", pydebug_ignore_warnings=True) + sage: out.find(version()) >= 0 # long time False - sage: out.find("5559060566555523") >= 0 + sage: out.find("5559060566555523") >= 0 # long time True - sage: err + sage: err # long time '' - sage: ret + sage: ret # long time 0 - sage: (out, err, ret) = test_executable(["sage", "-c", "print(3^33)"]) - sage: print(out) + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", "-c", "print(3^33)"]) + sage: print(out) # long time 5559060566555523 - sage: err + sage: err # long time '' - sage: ret + sage: ret # long time 0 - sage: (out, err, ret) = test_executable(["sage", "--min", "-c", "print(3^33)"]) - sage: print(out) + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", "--min", "-c", "print(3^33)"]) + sage: print(out) # long time 5559060566555523 - sage: err + sage: err # long time '' - sage: ret + sage: ret # long time 0 - sage: (out, err, ret) = test_executable(["sage", "--startuptime"]) - sage: out.find("Slowest module import") >= 0 + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", "--startuptime"]) + sage: out.find("Slowest module import") >= 0 # long time True - sage: err + sage: err # long time '' - sage: ret + sage: ret # long time 0 Test help:: @@ -253,19 +259,21 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: F = open(fullname, 'w') sage: _ = F.write("k.<a> = GF(5^3); print(a^124)\n") sage: F.close() - sage: (out, err, ret) = test_executable(["sage", fullname]) - sage: print(out) + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", fullname]) + sage: print(out) # long time 1 - sage: err + sage: err # long time '' - sage: ret + sage: ret # long time 0 - sage: (out, err, ret) = test_executable(["sage", name], cwd=dir) - sage: print(out) + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", name], cwd=dir) + sage: print(out) # long time 1 - sage: err + sage: err # long time '' - sage: ret + sage: ret # long time 0 Test running a ``.spyx`` file:: @@ -275,20 +283,22 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: F = open(fullname, 'w') sage: _ = F.write("from cysignals.signals cimport *\nfrom sage.rings.integer cimport Integer\ncdef long i, s = 0\nsig_on()\nfor i in range(1000): s += i\nsig_off()\nprint(Integer(s))") sage: F.close() - sage: (out, err, ret) = test_executable(["sage", fullname], pydebug_ignore_warnings=True) - sage: print(out) + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", fullname], pydebug_ignore_warnings=True) + sage: print(out) # long time 499500 - sage: import re - sage: bool(re.match('Compiling.*spyx.*', err)) + sage: import re # long time + sage: bool(re.match('Compiling.*spyx.*', err)) # long time True - sage: ret + sage: ret # long time 0 - sage: (out, err, ret) = test_executable(["sage", name], cwd=dir, pydebug_ignore_warnings=True) - sage: print(out) + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", name], cwd=dir, pydebug_ignore_warnings=True) + sage: print(out) # long time 499500 - sage: bool(re.match('Compiling.*spyx.*', err)) + sage: bool(re.match('Compiling.*spyx.*', err)) # long time True - sage: ret + sage: ret # long time 0 Testing ``sage --preparse FILE`` and ``sage -t FILE``. First create @@ -308,15 +318,17 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False Now test my_script.sage and the preparsed version my_script.sage.py:: - sage: (out, err, ret) = test_executable(["sage", "-t", script]) - sage: ret + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", "-t", "--optional=sage", script]) + sage: ret # long time 0 - sage: out.find("All tests passed!") >= 0 + sage: out.find("All tests passed!") >= 0 # long time True - sage: (out, err, ret) = test_executable(["sage", "-t", script_py]) - sage: ret + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", "-t", "--optional=sage", script_py]) + sage: ret # long time 0 - sage: out.find("All tests passed!") >= 0 + sage: out.find("All tests passed!") >= 0 # long time True Test that the coding line and doctest are preserved:: @@ -335,10 +347,11 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: F = open(script, 'w') sage: _ = F.write(s) sage: F.close() - sage: (out, err, ret) = test_executable(["sage", "-t", script]) - sage: ret + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", "-t", "--optional=sage", script]) + sage: ret # long time 1 - sage: out.find("1 item had failures:") >= 0 + sage: out.find("1 item had failures:") >= 0 # long time True Test ``sage -t --debug -p 2`` on a ReST file, the ``-p 2`` should @@ -349,9 +362,10 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: F = open(script, 'w') sage: _ = F.write(s) sage: F.close() - sage: (out, err, ret) = test_executable([ - ....: "sage", "-t", "--debug", "-p", "2", "--warn-long", "0", script], "help") - sage: print(out) + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", "-t", "--optional=sage", "--debug", + ....: "-p", "2", "--warn-long", "0", script], "help") + sage: print(out) # long time Debugging requires single-threaded operation, setting number of threads to 1. Running doctests with ID... Doctesting 1 file. @@ -389,7 +403,7 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False 2 of 3 in ... [2 tests, 2 failures, ...] ... - sage: ret + sage: ret # long time 1 Now run a test for the fixdoctests script and, in particular, check that the @@ -401,11 +415,11 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: F = open(test_file, 'w') sage: _ = F.write(test) sage: F.close() - sage: (out, err, ret) = test_executable(["sage", "--fixdoctests", test_file]) - sage: with open(test_file, 'r') as f: + sage: (out, err, ret) = test_executable(["sage", "--fixdoctests", test_file]) # long time + sage: with open(test_file, 'r') as f: # long time ....: fixed_test = f.read() - sage: import difflib - sage: list(difflib.unified_diff(test.splitlines(), fixed_test.splitlines()))[2:-1] + sage: import difflib # long time + sage: list(difflib.unified_diff(test.splitlines(), fixed_test.splitlines()))[2:-1] # long time ['@@ -4,18 +4,23 @@\n', ' EXAMPLES::', ' ', @@ -450,12 +464,13 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: ret 42 - sage: (out, err, ret) = test_executable(["sage", "--ipython"], "\n3**33\n", pydebug_ignore_warnings=True) - sage: out.find("5559060566555523") >= 0 + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", "--ipython"], "\n3**33\n", pydebug_ignore_warnings=True) + sage: out.find("5559060566555523") >= 0 # long time True - sage: err + sage: err # long time '' - sage: ret + sage: ret # long time 0 sage: (out, err, ret) = test_executable(["sage", "--python"], "print(3^33)\n") @@ -476,9 +491,8 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: (out, err, ret) = test_executable(["sage", "--cython"]) sage: print(err) - Cython (http://cython.org) is a compiler for code written in the - Cython language. Cython is based on Pyrex by Greg Ewing. ... + cython: error: cython: Need at least one source file sage: def has_tty(): ....: try: @@ -506,23 +520,25 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: ret 0 - sage: (out, err, ret) = test_executable(["sage", "--gap", "-q"], "Size(SymmetricGroup(5));\n") - sage: out + sage: (out, err, ret) = test_executable([ # long time + ....: "sage", "--gap", "-q"], "Size(SymmetricGroup(5));\n") + sage: out # long time '120\n' - sage: err.replace('gap: halving pool size.', '').strip() + sage: err.replace('gap: halving pool size.', '').strip() # long time '' - sage: ret + sage: ret # long time 0 - sage: (out, err, ret) = test_executable(["sage", "--gdb"], 'quit\n') # optional - gdb - sage: out.find('(gdb) ') >= 0 # optional - gdb + sage: (out, err, ret) = test_executable([ # long time # optional - gdb + ....: "sage", "--gdb"], 'quit\n') + sage: out.find('(gdb) ') >= 0 # long time # optional - gdb True - sage: ret # optional - gdb + sage: ret # long time # optional - gdb 0 - sage: (out, err, ret) = test_executable(["sage", "--mwrank", "-v0", "-q", "-o"], "0 0 1 -7 6 0 0 0 0 0\n") + sage: (out, err, ret) = test_executable(["sage", "--mwrank", "-v0", "-q"], "0 0 0 0 1\n") sage: out - 'Curve [0,0,1,-7,6] :\tRank = 3\n[[3],[[1,-1],[-2,3],[-7/4,25/8]]]\n\n\n' + 'Curve [0,0,0,0,1] :\tRank = 0\n\n' sage: err '' sage: ret @@ -715,8 +731,8 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: with open(input, 'w') as F: ....: _ = F.write(s) sage: L = ["sage", "--ipynb2rst", input, output] - sage: _ = test_executable(L) # optional - pandoc - sage: print(open(output, 'r').read() == t) # optional - pandoc # known bug #32697 + sage: _ = test_executable(L) # long time # optional - pandoc + sage: print(open(output, 'r').read() == t) # long time # optional - pandoc # known bug #32697 True """ pexpect_env = dict(os.environ) diff --git a/src/sage/tests/cython.pyx b/src/sage/tests/cython.pyx index c668fd47f02..3036085fdf2 100644 --- a/src/sage/tests/cython.pyx +++ b/src/sage/tests/cython.pyx @@ -1,15 +1,15 @@ """ This file collects tests requiring Cython. """ -#***************************************************************************** +# *************************************************************************** # Copyright (C) 2012 Jeroen Demeyer <jdemeyer@cage.ugent.be> # Copyright (C) 2012 Simon King <simon.king@uni-jena.de> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from sage.misc.fast_methods cimport FastHashable_class diff --git a/src/sage/tests/finite_poset.py b/src/sage/tests/finite_poset.py index 56495b04492..11092c3d966 100644 --- a/src/sage/tests/finite_poset.py +++ b/src/sage/tests/finite_poset.py @@ -537,9 +537,9 @@ def test_finite_poset(P): P_dual = P.dual() selfdual_properties = ['chain', 'bounded', 'connected', 'graded', 'ranked', 'series_parallel', 'slender', 'lattice'] for prop in selfdual_properties: - f = attrcall('is_'+prop) + f = attrcall('is_' + prop) if f(P) != f(P_dual): - raise ValueError("error in self-dual property %s" % prop) + raise ValueError(f"error in self-dual property {prop}") if P.is_graded(): if P.is_bounded(): if P.is_eulerian() != P_dual.is_eulerian(): @@ -547,7 +547,7 @@ def test_finite_poset(P): if P.is_eulerian(): P_ = P.star_product(P) if not P_.is_eulerian(): - raise("error in star product / eulerian") + raise ValueError("error in star product / eulerian") chain1 = P.random_maximal_chain() if len(chain1) != h1: raise ValueError("error in is_graded") diff --git a/src/sage/tests/functools_partial_src.py b/src/sage/tests/functools_partial_src.py index 1fb24e15b34..d352d160230 100644 --- a/src/sage/tests/functools_partial_src.py +++ b/src/sage/tests/functools_partial_src.py @@ -21,4 +21,5 @@ def base(x): x = x * 7 return x + test_func = partial(base, 6) diff --git a/src/sage/tests/gap_packages.py b/src/sage/tests/gap_packages.py index 2e4518ca226..c302b169b8a 100644 --- a/src/sage/tests/gap_packages.py +++ b/src/sage/tests/gap_packages.py @@ -103,7 +103,7 @@ def all_installed_packages(ignore_dot_gap=False, gap=None): sage: from sage.tests.gap_packages import all_installed_packages sage: all_installed_packages() - (...'GAPDoc'...) + (...'gapdoc'...) sage: all_installed_packages(ignore_dot_gap=True) == all_installed_packages(gap=gap, ignore_dot_gap=True) True """ diff --git a/src/sage/tests/gosper-sum.py b/src/sage/tests/gosper-sum.py index abdb622b18c..76c2438d1c9 100644 --- a/src/sage/tests/gosper-sum.py +++ b/src/sage/tests/gosper-sum.py @@ -118,7 +118,7 @@ sage: x = var('x') sage: (factorial(n-1)^2 / factorial(n-x) / factorial(n+x)).gosper_sum(n,1,m) (m^2*factorial(m - 1)^2*factorial(x + 1)*factorial(-x + 1) + x^2*factorial(m + x)*factorial(m - x) - factorial(m + x)*factorial(m - x))/(x^2*factorial(m + x)*factorial(m - x)*factorial(x + 1)*factorial(-x + 1)) - sage: ((n*(n+a+b)*a^n*b^n)/factorial(n+a)/factorial(n+b)).gosper_sum(n,1,m).simplify_full() + sage: ((n*(n+a+b)*a^n*b^n)/factorial(n+a)/factorial(n+b)).gosper_sum(n,1,m).simplify_full() # long time -(a^(m + 1)*b^(m + 1)*factorial(a - 1)*factorial(b - 1) - factorial(a + m)*factorial(b + m))/(factorial(a + m)*factorial(a - 1)*factorial(b + m)*factorial(b - 1)) sage: check_unsolvable(1/n, n,1,m) @@ -206,11 +206,11 @@ -1/2*(k - 2*n + 1)*k/((k - n)*(2*n + 1)) sage: G(n,k) = c*F(n,k) sage: t = (F(n+1,k) - F(n,k) - G(n,k+1) + G(n,k)) - sage: t.simplify_full().is_trivial_zero() + sage: t.simplify_full().is_trivial_zero() # long time True sage: c = k/2/(-1+k-n) sage: GG(n,k) = c*F(n,k) sage: t = (F(n+1,k) - F(n,k) - GG(n,k+1) + GG(n,k)) - sage: t.simplify_full().is_trivial_zero() + sage: t.simplify_full().is_trivial_zero() # long time False """ diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/__init__.py b/src/sage/tests/memcheck/__init__.py similarity index 100% rename from src/sage/geometry/polyhedron/combinatorial_polyhedron/__init__.py rename to src/sage/tests/memcheck/__init__.py diff --git a/src/sage/tests/memcheck/run_tests.py b/src/sage/tests/memcheck/run_tests.py new file mode 100644 index 00000000000..6ff4503a81b --- /dev/null +++ b/src/sage/tests/memcheck/run_tests.py @@ -0,0 +1,24 @@ +import types + + +def run_tests() -> None: + """ + Run all memcheck tests + """ + from sage.tests.memcheck import symbolic_expression + run_tests_in_module(symbolic_expression) + + +def run_tests_in_module(mod: types.ModuleType) -> None: + """ + Run all memcheck tests in the given module + """ + for entry in dir(mod): + if not entry.startswith('test_'): + continue + test_func = getattr(mod, entry) + test_func() + + +if __name__ == '__main__': + run_tests() diff --git a/src/sage/tests/memcheck/run_tests_in_valgrind.py b/src/sage/tests/memcheck/run_tests_in_valgrind.py new file mode 100644 index 00000000000..df5ad0e92b2 --- /dev/null +++ b/src/sage/tests/memcheck/run_tests_in_valgrind.py @@ -0,0 +1,35 @@ +""" +Launch valgrind and run the memory leak tests + + +From the commandline, run + + sage -python -m sage.tests.memcheck.run_tests_in_valgrind + +to launch valgrind and execute the memory leak tests. Requires valgrind +to be installed. Alternatively, run as a unit test: + + sage: from sage.tests.memcheck.run_tests_in_valgrind import run_tests_in_valgrind + sage: run_tests_in_valgrind() # optional - valgrind +""" + +import subprocess + + +def run_tests_in_valgrind() -> None: + """ + Run the sage.tests.memcheck.run_tests module inside valgrind + """ + subprocess.check_call([ + 'valgrind', + '--suppressions=src/sage/ext_data/valgrind/valgrind-python.supp', + '--show-possibly-lost=no', + '--show-reachable=no', + './venv/bin/python', + '-m', + 'sage.tests.memcheck.run_tests' + ]) + + +if __name__ == '__main__': + run_tests_in_valgrind() diff --git a/src/sage/tests/memcheck/symbolic_expression.py b/src/sage/tests/memcheck/symbolic_expression.py new file mode 100644 index 00000000000..52182fbe62d --- /dev/null +++ b/src/sage/tests/memcheck/symbolic_expression.py @@ -0,0 +1,11 @@ +from sage.tests.memcheck.verify_no_leak import verify_no_leak + + +def test_sqrt_sqrt_2() -> None: + from sage.misc.functional import sqrt + T2 = sqrt(2) + + def sqrt_T2() -> None: + sqrt(T2) + + verify_no_leak(sqrt_T2) diff --git a/src/sage/tests/memcheck/verify_no_leak.py b/src/sage/tests/memcheck/verify_no_leak.py new file mode 100644 index 00000000000..89ca90cf89c --- /dev/null +++ b/src/sage/tests/memcheck/verify_no_leak.py @@ -0,0 +1,27 @@ +from typing import Tuple, Sequence, List, Callable, Any +import valgrind + + +def verify_no_leak(callback: Callable[[], Any], + repeat: int = 10000, + fuzzy: int = 10, + ) -> None: + """ + Verify that the callback does not generate new definitely lost blocks + + Raises an assertion if the callback leaks memory + """ + callback() # warm_up + initial_blocks = (0, 0, 0, 0) + valgrind.memcheck_do_leak_check() + initial_blocks = valgrind.memcheck_count_leak_blocks() + for _ in range(repeat): + callback() + valgrind.memcheck_do_leak_check() + leak_blocks = valgrind.memcheck_count_leak_blocks() + leak = leak_blocks[0] - initial_blocks[0] + if leak < repeat - fuzzy: + return # callback did not leak at least once per call + blocks = round(leak / repeat, 2) + message = f'{callback} leaked {blocks} block on average ({repeat} iterations)' + raise AssertionError(message) diff --git a/src/sage/topology/__init__.py b/src/sage/topology/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/topology/all.py b/src/sage/topology/all.py index 354039b6c94..53b89564daa 100644 --- a/src/sage/topology/all.py +++ b/src/sage/topology/all.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs from .simplicial_complex import SimplicialComplex, Simplex from .simplicial_complex_morphism import SimplicialComplexMorphism @@ -12,6 +13,7 @@ lazy_import('sage.topology', 'simplicial_complex_catalog', 'simplicial_complexes') lazy_import('sage.topology', 'simplicial_set_catalog', 'simplicial_sets') +lazy_import('sage.topology.moment_angle_complex', 'MomentAngleComplex') # # For taking care of old pickles # from sage.misc.persist import register_unpickle_override diff --git a/src/sage/topology/cell_complex.py b/src/sage/topology/cell_complex.py index 6c18440b90e..906936a44c1 100644 --- a/src/sage/topology/cell_complex.py +++ b/src/sage/topology/cell_complex.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Generic cell complexes @@ -48,7 +48,6 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.misc.abstract_method import abstract_method -from sage.homology.chains import Chains, Cochains class GenericCellComplex(SageObject): @@ -80,7 +79,7 @@ class :class:`~sage.homology.delta_complex.DeltaComplex` sage: from sage.topology.cell_complex import GenericCellComplex sage: A = GenericCellComplex() """ - def __eq__(self,right): + def __eq__(self, right): """ Comparisons of cell complexes are not implemented. @@ -95,7 +94,7 @@ def __eq__(self,right): """ raise NotImplementedError - def __ne__(self,right): + def __ne__(self, right): """ Comparisons of cell complexes are not implemented. @@ -255,7 +254,7 @@ def f_vector(self): sage: cubical_complexes.KleinBottle().f_vector() [1, 42, 84, 42] """ - return [self._f_dict()[n] for n in range(-1, self.dimension()+1)] + return [self._f_dict()[n] for n in range(-1, self.dimension() + 1)] def _f_dict(self): """ @@ -291,7 +290,7 @@ def euler_characteristic(self): sage: cubical_complexes.KleinBottle().euler_characteristic() 0 """ - return sum([(-1)**n * self.f_vector()[n+1] for n in range(self.dimension() + 1)]) + return sum((-1)**n * self.f_vector()[n + 1] for n in range(self.dimension() + 1)) ############################################################ # end of methods using self.cells() @@ -504,6 +503,7 @@ def homology(self, dim=None, base_ring=ZZ, subcomplex=None, EXAMPLES:: + sage: # needs sage.modules sage: P = delta_complexes.RealProjectivePlane() sage: P.homology() {0: 0, 1: C2, 2: 0} @@ -522,8 +522,9 @@ def homology(self, dim=None, base_ring=ZZ, subcomplex=None, Sage can compute generators of homology groups:: sage: S2 = simplicial_complexes.Sphere(2) - sage: S2.homology(dim=2, generators=True, base_ring=GF(2)) - [(Vector space of dimension 1 over Finite Field of size 2, (0, 1, 2) + (0, 1, 3) + (0, 2, 3) + (1, 2, 3))] + sage: S2.homology(dim=2, generators=True, base_ring=GF(2)) # needs sage.modules + [(Vector space of dimension 1 over Finite Field of size 2, + (0, 1, 2) + (0, 1, 3) + (0, 2, 3) + (1, 2, 3))] When generators are computed, Sage returns a pair for each dimension: the group and the list of generators. For @@ -532,19 +533,17 @@ def homology(self, dim=None, base_ring=ZZ, subcomplex=None, complexes, each generator is a linear combination of cubes:: sage: S2_cub = cubical_complexes.Sphere(2) - sage: S2_cub.homology(dim=2, generators=True) + sage: S2_cub.homology(dim=2, generators=True) # needs sage.modules [(Z, - [0,0] x [0,1] x [0,1] - [0,1] x [0,0] x [0,1] + [0,1] x [0,1] x [0,0] - [0,1] x [0,1] x [1,1] + [0,1] x [1,1] x [0,1] - [1,1] x [0,1] x [0,1])] + [0,0] x [0,1] x [0,1] - [0,1] x [0,0] x [0,1] + [0,1] x [0,1] x [0,0] + - [0,1] x [0,1] x [1,1] + [0,1] x [1,1] x [0,1] - [1,1] x [0,1] x [0,1])] Similarly for simpicial sets:: sage: S = simplicial_sets.Sphere(2) - sage: S.homology(generators=True) + sage: S.homology(generators=True) # needs sage.modules {0: [], 1: 0, 2: [(Z, sigma_2)]} """ - from sage.topology.cubical_complex import CubicalComplex - from sage.topology.simplicial_complex import SimplicialComplex - from sage.modules.all import VectorSpace from sage.homology.homology_group import HomologyGroup if dim is not None: @@ -598,8 +597,8 @@ def homology(self, dim=None, base_ring=ZZ, subcomplex=None, return answer.get(dim, zero) def cohomology(self, dim=None, base_ring=ZZ, subcomplex=None, - generators=False, algorithm='pari', - verbose=False, reduced=True): + generators=False, algorithm='pari', + verbose=False, reduced=True): r""" The reduced cohomology of this cell complex. @@ -619,11 +618,16 @@ def cohomology(self, dim=None, base_ring=ZZ, subcomplex=None, EXAMPLES:: sage: circle = SimplicialComplex([[0,1], [1,2], [0, 2]]) - sage: circle.cohomology(0) + sage: circle.cohomology(0) # needs sage.modules 0 - sage: circle.cohomology(1) + sage: circle.cohomology(1) # needs sage.modules Z - sage: P2 = SimplicialComplex([[0,1,2], [0,2,3], [0,1,5], [0,4,5], [0,3,4], [1,2,4], [1,3,4], [1,3,5], [2,3,5], [2,4,5]]) # projective plane + + Projective plane:: + + sage: # needs sage.modules + sage: P2 = SimplicialComplex([[0,1,2], [0,2,3], [0,1,5], [0,4,5], [0,3,4], + ....: [1,2,4], [1,3,4], [1,3,5], [2,3,5], [2,4,5]]) sage: P2.cohomology(2) C2 sage: P2.cohomology(2, base_ring=GF(2)) @@ -631,20 +635,20 @@ def cohomology(self, dim=None, base_ring=ZZ, subcomplex=None, sage: P2.cohomology(2, base_ring=GF(3)) Vector space of dimension 0 over Finite Field of size 3 - sage: cubical_complexes.KleinBottle().cohomology(2) + sage: cubical_complexes.KleinBottle().cohomology(2) # needs sage.modules C2 Relative cohomology:: sage: T = SimplicialComplex([[0,1]]) sage: U = SimplicialComplex([[0], [1]]) - sage: T.cohomology(1, subcomplex=U) + sage: T.cohomology(1, subcomplex=U) # needs sage.modules Z A `\Delta`-complex example:: sage: s5 = delta_complexes.Sphere(5) - sage: s5.cohomology(base_ring=GF(7))[5] + sage: s5.cohomology(base_ring=GF(7))[5] # needs sage.modules Vector space of dimension 1 over Finite Field of size 7 """ return self.homology(dim=dim, cohomology=True, base_ring=base_ring, @@ -677,23 +681,23 @@ def betti(self, dim=None, subcomplex=None): two-point space with itself:: sage: S = SimplicialComplex([[0], [1]]) - sage: (S*S*S).betti() + sage: (S*S*S).betti() # needs sage.modules {0: 1, 1: 0, 2: 1} - sage: (S*S*S).betti([1,2]) + sage: (S*S*S).betti([1,2]) # needs sage.modules {1: 0, 2: 1} - sage: (S*S*S).betti(2) + sage: (S*S*S).betti(2) # needs sage.modules 1 Or build the two-sphere as a `\Delta`-complex:: sage: S2 = delta_complexes.Sphere(2) - sage: S2.betti([1,2]) + sage: S2.betti([1,2]) # needs sage.modules {1: 0, 2: 1} Or as a cubical complex:: sage: S2c = cubical_complexes.Sphere(2) - sage: S2c.betti(2) + sage: S2c.betti(2) # needs sage.modules 1 """ dict = {} @@ -720,9 +724,9 @@ def is_acyclic(self, base_ring=ZZ): EXAMPLES:: sage: RP2 = simplicial_complexes.RealProjectivePlane() - sage: RP2.is_acyclic() + sage: RP2.is_acyclic() # needs sage.modules False - sage: RP2.is_acyclic(QQ) + sage: RP2.is_acyclic(QQ) # needs sage.modules True This first computes the Euler characteristic: if it is not 1, @@ -732,8 +736,7 @@ def is_acyclic(self, base_ring=ZZ): sage: K = cubical_complexes.KleinBottle() sage: C = cubical_complexes.Cube(2) - sage: P = K.product(C) - sage: P + sage: P = K.product(C); P Cubical complex with 168 vertices and 1512 cubes sage: P.euler_characteristic() 0 @@ -768,13 +771,16 @@ def n_chains(self, n, base_ring=ZZ, cochains=False): EXAMPLES:: sage: S2 = simplicial_complexes.Sphere(2) - sage: S2.n_chains(1, QQ) - Free module generated by {(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)} over Rational Field - sage: list(simplicial_complexes.Sphere(2).n_chains(1, QQ, cochains=False).basis()) + sage: S2.n_chains(1, QQ) # needs sage.modules + Free module generated by {(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)} + over Rational Field + sage: list(S2.n_chains(1, QQ, cochains=False).basis()) # needs sage.modules [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: list(simplicial_complexes.Sphere(2).n_chains(1, QQ, cochains=True).basis()) + sage: list(S2.n_chains(1, QQ, cochains=True).basis()) # needs sage.modules [\chi_(0, 1), \chi_(0, 2), \chi_(0, 3), \chi_(1, 2), \chi_(1, 3), \chi_(2, 3)] """ + from sage.homology.chains import Chains, Cochains + n_cells = tuple(self._n_cells_sorted(n)) if cochains: return Cochains(self, n, n_cells, base_ring) @@ -835,6 +841,7 @@ def homology_with_basis(self, base_ring=QQ, cohomology=False): EXAMPLES:: + sage: # needs sage.modules sage: K = simplicial_complexes.KleinBottle() sage: H = K.homology_with_basis(QQ); H Homology module of Minimal triangulation of the Klein bottle @@ -850,11 +857,12 @@ def homology_with_basis(self, base_ring=QQ, cohomology=False): The homology is constructed as a graded object, so for example, you can ask for the basis in a single degree:: - sage: H.basis(1) + sage: H.basis(1) # needs sage.modules Finite family {(1, 0): h_{1,0}, (1, 1): h_{1,1}} + sage: S3 = delta_complexes.Sphere(3) - sage: H = S3.homology_with_basis(QQ, cohomology=True) - sage: list(H.basis(3)) + sage: H = S3.homology_with_basis(QQ, cohomology=True) # needs sage.modules + sage: list(H.basis(3)) # needs sage.modules [h^{3,0}] """ from sage.homology.homology_vector_space_with_basis import HomologyVectorSpaceWithBasis @@ -893,6 +901,7 @@ def cohomology_ring(self, base_ring=QQ): EXAMPLES:: + sage: # needs sage.modules sage: K = simplicial_complexes.KleinBottle() sage: H = K.cohomology_ring(QQ); H Cohomology ring of Minimal triangulation of the Klein bottle @@ -906,22 +915,23 @@ def cohomology_ring(self, base_ring=QQ): [h^{0,0}, h^{1,0}, h^{1,1}, h^{2,0}] sage: X = delta_complexes.SurfaceOfGenus(2) - sage: H = X.cohomology_ring(QQ); H + sage: H = X.cohomology_ring(QQ); H # needs sage.modules Cohomology ring of Delta complex with 3 vertices and 29 simplices over Rational Field - sage: sorted(H.basis(1), key=str) + sage: sorted(H.basis(1), key=str) # needs sage.modules [h^{1,0}, h^{1,1}, h^{1,2}, h^{1,3}] - sage: H = simplicial_complexes.Torus().cohomology_ring(QQ); H + sage: H = simplicial_complexes.Torus().cohomology_ring(QQ); H # needs sage.modules Cohomology ring of Minimal triangulation of the torus over Rational Field - sage: x = H.basis()[1,0]; x + sage: x = H.basis()[1,0]; x # needs sage.modules h^{1,0} - sage: y = H.basis()[1,1]; y + sage: y = H.basis()[1,1]; y # needs sage.modules h^{1,1} You can compute cup products of cohomology classes:: + sage: # needs sage.modules sage: x.cup_product(y) -h^{2,0} sage: x * y # alternate notation @@ -933,12 +943,13 @@ def cohomology_ring(self, base_ring=QQ): Cohomology operations:: + sage: # needs sage.groups sage: RP2 = simplicial_complexes.RealProjectivePlane() sage: K = RP2.suspension() sage: K.set_immutable() - sage: y = K.cohomology_ring(GF(2)).basis()[2,0]; y + sage: y = K.cohomology_ring(GF(2)).basis()[2,0]; y # needs sage.modules h^{2,0} - sage: y.Sq(1) + sage: y.Sq(1) # needs sage.modules h^{3,0} To compute the cohomology ring, the complex must be @@ -952,14 +963,14 @@ def cohomology_ring(self, base_ring=QQ): sage: T = S1.product(S1) sage: T.is_immutable() False - sage: T.cohomology_ring() + sage: T.cohomology_ring() # needs sage.modules Traceback (most recent call last): ... ValueError: this simplicial complex must be immutable; call set_immutable() sage: T.set_immutable() - sage: T.cohomology_ring() + sage: T.cohomology_ring() # needs sage.modules Cohomology ring of Simplicial complex with 9 vertices and - 18 facets over Rational Field + 18 facets over Rational Field """ from sage.homology.homology_vector_space_with_basis import CohomologyRing return CohomologyRing(base_ring, self) @@ -1079,8 +1090,7 @@ def is_connected(self): EXAMPLES:: - sage: V = SimplicialComplex([[0,1,2],[3]]) - sage: V + sage: V = SimplicialComplex([[0,1,2],[3]]); V Simplicial complex with vertex set (0, 1, 2, 3) and facets {(3,), (0, 1, 2)} sage: V.is_connected() False diff --git a/src/sage/topology/cubical_complex.py b/src/sage/topology/cubical_complex.py index f060fcea8af..c26ff4e08bb 100644 --- a/src/sage/topology/cubical_complex.py +++ b/src/sage/topology/cubical_complex.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Finite cubical complexes @@ -26,7 +26,8 @@ `(0,2)` to `(0,3)` to `(1,3)` to `(1,2)` to `(0,2)`. In Sage, this is done with the following command:: - sage: S1 = CubicalComplex([([0,0], [2,3]), ([0,1], [3,3]), ([0,1], [2,2]), ([1,1], [2,3])]); S1 + sage: S1 = CubicalComplex([([0,0], [2,3]), ([0,1], [3,3]), + ....: ([0,1], [2,2]), ([1,1], [2,3])]); S1 Cubical complex with 4 vertices and 8 cubes The argument to ``CubicalComplex`` is a list of the maximal "cubes" in @@ -45,10 +46,11 @@ segment in the plane from `(0,2)` to `(0,3)`. We could form a topologically equivalent space by inserting some degenerate simplices:: - sage: S1.homology() + sage: S1.homology() # needs sage.modules {0: 0, 1: Z} - sage: X = CubicalComplex([([0,0], [2,3], [2]), ([0,1], [3,3], [2]), ([0,1], [2,2], [2]), ([1,1], [2,3], [2])]) - sage: X.homology() + sage: X = CubicalComplex([([0,0], [2,3], [2]), ([0,1], [3,3], [2]), + ....: ([0,1], [2,2], [2]), ([1,1], [2,3], [2])]) + sage: X.homology() # needs sage.modules {0: 0, 1: Z} Topologically, the cubical complex ``X`` consists of four edges of a @@ -73,13 +75,13 @@ from sage.sets.set import Set from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.matrix.constructor import matrix -from sage.homology.chain_complex import ChainComplex -from sage.graphs.graph import Graph from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.superseded import deprecation from functools import total_ordering +lazy_import('sage.matrix.constructor', 'matrix') + @total_ordering class Cube(SageObject): @@ -226,7 +228,7 @@ def _translate(self, vec): """ t = self.__tuple embed = max(len(t), len(vec)) - t = t + ((0,0),) * (embed-len(t)) + t = t + ((0, 0),) * (embed-len(t)) vec = tuple(vec) + (0,) * (embed-len(vec)) new = [] for (a, b) in zip(t, vec): @@ -367,7 +369,7 @@ def face(self, n, upper=True): new = t[idx][1] else: new = t[idx][0] - return Cube(t[0:idx] + ((new,new),) + t[idx+1:]) + return Cube(t[0:idx] + ((new, new),) + t[idx+1:]) def faces(self): """ @@ -380,8 +382,8 @@ def faces(self): sage: C.faces() [[2,2] x [3,4], [1,2] x [4,4], [1,1] x [3,4], [1,2] x [3,3]] """ - upper = [self.face(i,True) for i in range(self.dimension())] - lower = [self.face(i,False) for i in range(self.dimension())] + upper = [self.face(i, True) for i in range(self.dimension())] + lower = [self.face(i, False) for i in range(self.dimension())] return upper + lower def faces_as_pairs(self): @@ -464,7 +466,7 @@ def _compare_for_gluing(self, other): self_tuple = self.tuple() other_tuple = other.tuple() nondegen = (list(zip(self.nondegenerate_intervals(), - other.nondegenerate_intervals())) + other.nondegenerate_intervals())) + [(len(self_tuple), len(other_tuple))]) old = (-1, -1) self_added = 0 @@ -540,10 +542,10 @@ def _triangulation_(self): 6 """ from .simplicial_complex import Simplex - if self.dimension() < 0: # the empty cube - return [Simplex(())] # the empty simplex + if self.dimension() < 0: # the empty cube + return [Simplex(())] # the empty simplex v = tuple([max(j) for j in self.tuple()]) - if self.dimension() == 0: # just v + if self.dimension() == 0: # just v return [Simplex((v,))] simplices = [] for i in range(self.dimension()): @@ -594,7 +596,7 @@ def alexander_whitney(self, dim): nu = 0 for i in J: for j in Jprime: - if j<i: + if j < i: nu += 1 t = self.tuple() left = [] @@ -717,7 +719,7 @@ def _repr_(self): sage: C1._repr_() '[1,1] x [2,3] x [4,5]' """ - s = ["[%s,%s]"%(str(x), str(y)) for (x,y) in self.__tuple] + s = ("[%s,%s]" % (str(x), str(y)) for x, y in self.__tuple) return " x ".join(s) def _latex_(self): @@ -773,10 +775,10 @@ class :class:`Cube`, or lists or tuples suitable for conversion to A "circle" (four edges connecting the vertices (0,2), (0,3), (1,2), and (1,3)):: - sage: S1 = CubicalComplex([([0,0], [2,3]), ([0,1], [3,3]), ([0,1], [2,2]), ([1,1], [2,3])]) - sage: S1 + sage: S1 = CubicalComplex([([0,0], [2,3]), ([0,1], [3,3]), + ....: ([0,1], [2,2]), ([1,1], [2,3])]); S1 Cubical complex with 4 vertices and 8 cubes - sage: S1.homology() + sage: S1.homology() # needs sage.modules {0: 0, 1: Z} A set of five points and its product with ``S1``:: @@ -784,18 +786,18 @@ class :class:`Cube`, or lists or tuples suitable for conversion to sage: pts = CubicalComplex([([0],), ([3],), ([6],), ([-12],), ([5],)]) sage: pts Cubical complex with 5 vertices and 5 cubes - sage: pts.homology() + sage: pts.homology() # needs sage.modules {0: Z x Z x Z x Z} sage: X = S1.product(pts); X Cubical complex with 20 vertices and 40 cubes - sage: X.homology() + sage: X.homology() # needs sage.modules {0: Z x Z x Z x Z, 1: Z^5} Converting a simplicial complex to a cubical complex:: sage: S2 = simplicial_complexes.Sphere(2) sage: C2 = CubicalComplex(S2) - sage: all(C2.homology(n) == S2.homology(n) for n in range(3)) + sage: all(C2.homology(n) == S2.homology(n) for n in range(3)) # needs sage.modules True You can get the set of maximal cells or a dictionary of all cells:: @@ -832,14 +834,14 @@ class :class:`Cube`, or lists or tuples suitable for conversion to sage: T = S1.product(S1); T Cubical complex with 16 vertices and 64 cubes - sage: T.chain_complex() + sage: T.chain_complex() # needs sage.modules Chain complex with at most 3 nonzero terms over Integer Ring - sage: T.homology(base_ring=QQ) + sage: T.homology(base_ring=QQ) # needs sage.modules {0: Vector space of dimension 0 over Rational Field, 1: Vector space of dimension 2 over Rational Field, 2: Vector space of dimension 1 over Rational Field} sage: RP2 = cubical_complexes.RealProjectivePlane() - sage: RP2.cohomology(dim=[1, 2], base_ring=GF(2)) + sage: RP2.cohomology(dim=[1, 2], base_ring=GF(2)) # needs sage.modules {1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} @@ -1074,7 +1076,7 @@ def cells(self, subcomplex=None): sub_facets = {} dimension = max([cube.dimension() for cube in self._facets]) # initialize the lists: add each maximal cube to Cells and sub_facets - for i in range(-1,dimension+1): + for i in range(-1, dimension+1): Cells[i] = set([]) sub_facets[i] = set([]) for f in self._facets: @@ -1168,6 +1170,7 @@ def chain_complex(self, subcomplex=None, augmented=False, EXAMPLES:: + sage: # needs sage.modules sage: S2 = cubical_complexes.Sphere(2) sage: S2.chain_complex() Chain complex with at most 3 nonzero terms over Integer Ring @@ -1186,12 +1189,15 @@ def chain_complex(self, subcomplex=None, augmented=False, Check that :trac:`32203` has been fixed:: + sage: # needs sage.modules sage: Square = CubicalComplex([([0,1],[0,1])]) sage: EdgesLTR = CubicalComplex([([0,0],[0,1]),([0,1],[1,1]),([1,1],[0,1])]) sage: EdgesLBR = CubicalComplex([([0,0],[0,1]),([0,1],[0,0]),([1,1],[0,1])]) sage: Square.homology(subcomplex=EdgesLTR)[2] == Square.homology(subcomplex=EdgesLBR)[2] True """ + from sage.homology.chain_complex import ChainComplex + # initialize subcomplex if subcomplex is None: subcomplex = CubicalComplex() @@ -1212,7 +1218,7 @@ def chain_complex(self, subcomplex=None, augmented=False, differentials[0] = mat current = vertices # now loop from 1 to dimension of the complex - for dim in range(1,self.dimension()+1): + for dim in range(1, self.dimension()+1): if verbose: print(" starting dimension %s" % dim) if (dim, subcomplex) in self._complex: @@ -1333,6 +1339,8 @@ def graph(self): sage: cubical_complexes.Sphere(2).graph() Graph on 8 vertices """ + from sage.graphs.graph import Graph + data = {} vertex_dict = {} i = 0 @@ -1476,7 +1484,7 @@ def disjoint_union(self, other): sage: S1 = cubical_complexes.Sphere(1) sage: S2 = cubical_complexes.Sphere(2) - sage: S1.disjoint_union(S2).homology() + sage: S1.disjoint_union(S2).homology() # needs sage.modules {0: Z, 1: Z, 2: Z} """ embedded_left = len(tuple(self.maximal_cells()[0])) @@ -1484,9 +1492,9 @@ def disjoint_union(self, other): zero = [0] * max(embedded_left, embedded_right) facets = [] for f in self.maximal_cells(): - facets.append(Cube([[0,0]]).product(f._translate(zero))) + facets.append(Cube([[0, 0]]).product(f._translate(zero))) for f in other.maximal_cells(): - facets.append(Cube([[1,1]]).product(f._translate(zero))) + facets.append(Cube([[1, 1]]).product(f._translate(zero))) return CubicalComplex(facets) def wedge(self, other): @@ -1511,14 +1519,14 @@ def wedge(self, other): sage: S1 = cubical_complexes.Sphere(1) sage: S2 = cubical_complexes.Sphere(2) - sage: S1.wedge(S2).homology() + sage: S1.wedge(S2).homology() # needs sage.modules {0: 0, 1: Z, 2: Z} """ embedded_left = len(tuple(self.maximal_cells()[0])) embedded_right = len(tuple(other.maximal_cells()[0])) translate_left = [-a[0] for a in self.maximal_cells()[0]] + [0] * embedded_right translate_right = [-a[0] for a in other.maximal_cells()[0]] - point_right = Cube([[0,0]] * embedded_left) + point_right = Cube([[0, 0]] * embedded_left) facets = [] for f in self.maximal_cells(): @@ -1547,12 +1555,12 @@ def connected_sum(self, other): sage: T = cubical_complexes.Torus() sage: S2 = cubical_complexes.Sphere(2) - sage: T.connected_sum(S2).cohomology() == T.cohomology() + sage: T.connected_sum(S2).cohomology() == T.cohomology() # needs sage.modules True sage: RP2 = cubical_complexes.RealProjectivePlane() - sage: T.connected_sum(RP2).homology(1) + sage: T.connected_sum(RP2).homology(1) # needs sage.modules Z x Z x C2 - sage: RP2.connected_sum(RP2).connected_sum(RP2).homology(1) + sage: RP2.connected_sum(RP2).connected_sum(RP2).homology(1) # needs sage.modules Z x Z x C2 """ # connected_sum: first check whether the complexes are pure @@ -1580,7 +1588,7 @@ def connected_sum(self, other): # start assembling the facets in the connected sum: first, the # cylinder on the removed face. new_facets = [] - cylinder = removed.product(Cube([[0,1]])) + cylinder = removed.product(Cube([[0, 1]])) # don't want to include the ends of the cylinder, so don't # include the last pair of faces. therefore, choose faces up # to removed.dimension(), not cylinder.dimension(). @@ -1592,13 +1600,13 @@ def connected_sum(self, other): CL = list(cube.tuple()) for (idx, L) in insert_self: CL[idx:idx] = L - CL.append((0,0)) + CL.append((0, 0)) new_facets.append(Cube(CL)) for cube in other_facets: CL = list(cube.tuple()) for (idx, L) in insert_other: CL[idx:idx] = L - CL.append((1,1)) + CL.append((1, 1)) new_facets.append(Cube(CL)._translate(translate)) return CubicalComplex(new_facets) @@ -1667,6 +1675,7 @@ def algebraic_topological_model(self, base_ring=None): EXAMPLES:: + sage: # needs sage.modules sage: RP2 = cubical_complexes.RealProjectivePlane() sage: phi, M = RP2.algebraic_topological_model(GF(2)) sage: M.homology() @@ -1751,7 +1760,7 @@ def _simplicial_(self): sage: Ts = T._simplicial_(); Ts Simplicial complex with 16 vertices and 32 facets - sage: T.homology() == Ts.homology() + sage: T.homology() == Ts.homology() # needs sage.modules True Each `n`-dimensional cube produces `n!` `n`-simplices:: @@ -1809,7 +1818,7 @@ class CubicalComplexExamples(): Cubical complex with 256 vertices and 6560 cubes """ - def Sphere(self,n): + def Sphere(self, n): r""" A cubical complex representation of the `n`-dimensional sphere, formed by taking the boundary of an `(n+1)`-dimensional cube. @@ -1822,7 +1831,7 @@ def Sphere(self,n): sage: cubical_complexes.Sphere(7) Cubical complex with 256 vertices and 6560 cubes """ - return CubicalComplex(Cube([[0,1]]*(n+1)).faces()) + return CubicalComplex(Cube([[0, 1]]*(n+1)).faces()) def Torus(self): r""" diff --git a/src/sage/topology/delta_complex.py b/src/sage/topology/delta_complex.py index 420fd2fad5a..18888465713 100644 --- a/src/sage/topology/delta_complex.py +++ b/src/sage/topology/delta_complex.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Finite Delta-complexes @@ -51,16 +51,15 @@ from copy import copy from sage.topology.cell_complex import GenericCellComplex -from sage.homology.chains import Chains, Cochains from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.integer import Integer -from sage.matrix.constructor import matrix from .simplicial_complex import Simplex, lattice_paths, SimplicialComplex -from sage.homology.chain_complex import ChainComplex -from sage.graphs.graph import Graph -from sage.arith.all import binomial +from sage.arith.misc import binomial from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.matrix.constructor', 'matrix') class DeltaComplex(GenericCellComplex): @@ -108,7 +107,7 @@ class DeltaComplex(GenericCellComplex): Let's compute its homology, and also compare it to the simplicial version:: - sage: S5.homology() + sage: S5.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: Z} sage: S5.f_vector() # number of simplices in each dimension [1, 6, 15, 20, 15, 6, 2] @@ -129,7 +128,7 @@ class DeltaComplex(GenericCellComplex): ....: Simplex(0): ()} sage: T = DeltaComplex(torus_dict); T Delta complex with 1 vertex and 7 simplices - sage: T.cohomology(base_ring=QQ) + sage: T.cohomology(base_ring=QQ) # needs sage.modules {0: Vector space of dimension 0 over Rational Field, 1: Vector space of dimension 2 over Rational Field, 2: Vector space of dimension 1 over Rational Field} @@ -180,9 +179,9 @@ class DeltaComplex(GenericCellComplex): :: - sage: P.homology(1) + sage: P.homology(1) # needs sage.modules C2 - sage: P.cohomology(2) + sage: P.cohomology(2) # needs sage.modules C2 Closely related to this form for ``data`` is ``X.cells()`` @@ -247,7 +246,7 @@ def __init__(self, data=None, check_validity=True): sage: X = DeltaComplex({Simplex(3):True, Simplex(range(1,5)): Simplex(3), Simplex(range(2,6)): Simplex(3)}); X # indirect doctest Delta complex with 4 vertices and 18 simplices - sage: X.homology() + sage: X.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: Z x Z} sage: X == loads(dumps(X)) True @@ -406,7 +405,7 @@ def subcomplex(self, data): sage: X = delta_complexes.Torus() sage: A = X.subcomplex({2: [0]}) # one of the triangles of X - sage: X.homology(subcomplex=A) + sage: X.homology(subcomplex=A) # needs sage.modules {0: 0, 1: 0, 2: Z} In the following, ``line`` is a line segment and ``ends`` is @@ -419,7 +418,7 @@ def subcomplex(self, data): sage: ends = line.subcomplex({0: (0, 1)}) sage: ends.cells() {-1: ((),), 0: ((), ())} - sage: line.homology(subcomplex=ends) + sage: line.homology(subcomplex=ends) # needs sage.modules {0: 0, 1: Z} """ if isinstance(data, (list, tuple)): @@ -608,6 +607,7 @@ def chain_complex(self, subcomplex=None, augmented=False, EXAMPLES:: + sage: # needs sage.modules sage: circle = delta_complexes.Sphere(1) sage: circle.chain_complex() Chain complex with at most 2 nonzero terms over Integer Ring @@ -630,6 +630,8 @@ def chain_complex(self, subcomplex=None, augmented=False, sage: T.homology(subcomplex=A) {0: 0, 1: 0, 2: Z} """ + from sage.homology.chain_complex import ChainComplex + if subcomplex is not None: # relative chain complex, so don't augment the chain complex augmented = False @@ -641,14 +643,14 @@ def chain_complex(self, subcomplex=None, augmented=False, empty_simplex = 0 vertices = self.n_cells(0, subcomplex=subcomplex) old = vertices - old_real = [x for x in old if x is not None] # get rid of faces not in subcomplex + old_real = [x for x in old if x is not None] # remove faces not in subcomplex n = len(old_real) differentials[0] = matrix(base_ring, empty_simplex, n, n*empty_simplex*[1]) # current is list of simplices in dimension dim # current_real is list of simplices in dimension dim, with None filtered out # old is list of simplices in dimension dim-1 # old_real is list of simplices in dimension dim-1, with None filtered out - for dim in range(1,self.dimension()+1): + for dim in range(1, self.dimension()+1): current = list(self.n_cells(dim, subcomplex=subcomplex)) current_real = [x for x in current if x is not None] i = 0 @@ -666,10 +668,10 @@ def chain_complex(self, subcomplex=None, augmented=False, for row in s: if old[row] is not None: actual_row = translate[row] - if (actual_row,col) in mat_dict: - mat_dict[(actual_row,col)] += sign + if (actual_row, col) in mat_dict: + mat_dict[(actual_row, col)] += sign else: - mat_dict[(actual_row,col)] = sign + mat_dict[(actual_row, col)] = sign sign *= -1 col += 1 differentials[dim] = matrix(base_ring, len(old_real), len(current_real), mat_dict) @@ -750,7 +752,7 @@ def n_skeleton(self, n): Delta complex with 4 vertices and 11 simplices sage: S3.n_skeleton(1).dimension() 1 - sage: S3.n_skeleton(1).homology() + sage: S3.n_skeleton(1).homology() # needs sage.modules {0: 0, 1: Z x Z x Z} """ if n >= self.dimension(): @@ -776,6 +778,8 @@ def graph(self): sage: delta_complexes.Simplex(4).graph() == graphs.CompleteGraph(5) True """ + from sage.graphs.graph import Graph + data = {} for vertex in range(len(self.n_cells(0))): data[vertex] = [] @@ -810,14 +814,14 @@ def join(self, other): sage: K = delta_complexes.KleinBottle() sage: T_simp = simplicial_complexes.Torus() sage: K_simp = simplicial_complexes.KleinBottle() - sage: T.join(K).homology()[3] == T_simp.join(K_simp).homology()[3] # long time (3 seconds) + sage: T.join(K).homology()[3] == T_simp.join(K_simp).homology()[3] # long time (3 seconds), needs sage.modules True The notation '*' may be used, as well:: sage: S1 = delta_complexes.Sphere(1) sage: X = S1 * S1 # X is a 3-sphere - sage: X.homology() + sage: X.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: Z} """ data = [] @@ -826,17 +830,17 @@ def join(self, other): data.append(self.n_cells(0) + other.n_cells(0)) bdries = {} for l_idx in range(len(self.n_cells(0))): - bdries[(0,l_idx,-1,0)] = l_idx + bdries[(0, l_idx, -1, 0)] = l_idx for r_idx in range(len(other.n_cells(0))): - bdries[(-1,0,0,r_idx)] = len(self.n_cells(0)) + r_idx + bdries[(-1, 0, 0, r_idx)] = len(self.n_cells(0)) + r_idx # dimension of the join: maxdim = self.dimension() + other.dimension() + 1 # now for the d-cells, d>0: - for d in range(1,maxdim+1): + for d in range(1, maxdim+1): d_cells = [] positions = {} new_idx = 0 - for k in range(-1,d+1): + for k in range(-1, d+1): n = d-1-k # d=n+k. need a k-cell from self and an n-cell from other if k == -1: @@ -892,7 +896,7 @@ def cone(self): sage: K = delta_complexes.KleinBottle() sage: K.cone() Delta complex with 2 vertices and 14 simplices - sage: K.cone().homology() + sage: K.cone().homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0} """ return self.join(delta_complexes.Simplex(0)) @@ -915,14 +919,14 @@ def suspension(self, n=1): sage: S = delta_complexes.Sphere(0) sage: S3 = S.suspension(3) # the 3-sphere - sage: S3.homology() + sage: S3.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: Z} """ - if n<0: + if n < 0: raise ValueError("n must be non-negative") - if n==0: + if n == 0: return self - if n==1: + if n == 1: return self.join(delta_complexes.Sphere(0)) return self.suspension().suspension(int(n-1)) @@ -943,6 +947,8 @@ def product(self, other): sage: K = delta_complexes.KleinBottle() sage: X = K.product(K) + + sage: # needs sage.modules sage: X.homology(1) Z x Z x C2 x C2 sage: X.homology(2) @@ -957,8 +963,9 @@ def product(self, other): 2: Vector space of dimension 6 over Finite Field of size 2, 3: Vector space of dimension 4 over Finite Field of size 2, 4: Vector space of dimension 1 over Finite Field of size 2} + sage: S1 = delta_complexes.Sphere(1) - sage: K.product(S1).homology() == S1.product(K).homology() + sage: K.product(S1).homology() == S1.product(K).homology() # needs sage.modules True sage: S1.product(S1) == delta_complexes.Torus() True @@ -974,8 +981,8 @@ def product(self, other): for w in other.n_cells(0): # one vertex for each pair (v,w) # store its indices in bdries; store its boundary in vertices - bdries[(0,l_idx,0,r_idx, ((0,0),))] = len(vertices) - vertices.append(()) # add new vertex (simplex with empty bdry) + bdries[(0, l_idx, 0, r_idx, ((0, 0),))] = len(vertices) + vertices.append(()) # add new vertex (simplex with empty bdry) r_idx += 1 l_idx += 1 data.append(tuple(vertices)) @@ -987,7 +994,7 @@ def product(self, other): new = {} for d in range(1, maxdim+1): for k in range(d+1): - for n in range(d-k,d+1): + for n in range(d-k, d+1): k_idx = 0 for k_cell in self.n_cells(k): n_idx = 0 @@ -1010,8 +1017,8 @@ def product(self, other): bdry_list = [] for i in range(d+1): face_path = path[:i] + path[i+1:] - if ((i<d and path[i][0] == path[i+1][0]) or - (i>0 and path[i][0] == path[i-1][0])): + if ((i < d and path[i][0] == path[i+1][0]) or + (i > 0 and path[i][0] == path[i-1][0])): # this k-simplex k_face_idx = k_idx k_face_dim = k @@ -1020,12 +1027,12 @@ def product(self, other): k_face_idx = k_cell[path[i][0]] k_face_dim = k-1 tail = [] - for j in range(i,d): + for j in range(i, d): tail.append((face_path[j][0]-1, - face_path[j][1])) + face_path[j][1])) face_path = face_path[:i] + tuple(tail) - if ((i<d and path[i][1] == path[i+1][1]) or - (i>0 and path[i][1] == path[i-1][1])): + if ((i < d and path[i][1] == path[i+1][1]) or + (i > 0 and path[i][1] == path[i-1][1])): # this n-simplex n_face_idx = n_idx n_face_dim = n @@ -1034,7 +1041,7 @@ def product(self, other): n_face_idx = n_cell[path[i][1]] n_face_dim = n-1 tail = [] - for j in range(i,d): + for j in range(i, d): tail.append((face_path[j][0], face_path[j][1]-1)) face_path = face_path[:i] + tuple(tail) @@ -1062,7 +1069,7 @@ def disjoint_union(self, right): sage: S1 = delta_complexes.Sphere(1) sage: S2 = delta_complexes.Sphere(2) - sage: S1.disjoint_union(S2).homology() + sage: S1.disjoint_union(S2).homology() # needs sage.modules {0: Z, 1: Z, 2: Z} """ dim = max(self.dimension(), right.dimension()) @@ -1094,7 +1101,7 @@ def wedge(self, right): sage: S1 = delta_complexes.Sphere(1) sage: S2 = delta_complexes.Sphere(2) - sage: S1.wedge(S2).homology() + sage: S1.wedge(S2).homology() # needs sage.modules {0: 0, 1: Z, 2: Z} """ data = self.disjoint_union(right).cells() @@ -1143,6 +1150,7 @@ def connected_sum(self, other): EXAMPLES:: + sage: # needs sage.modules sage: T = delta_complexes.Torus() sage: S2 = delta_complexes.Sphere(2) sage: T.connected_sum(S2).cohomology() == T.cohomology() @@ -1271,7 +1279,7 @@ def elementary_subdivision(self, idx=-1): Delta complex with 2 vertices and 13 simplices sage: X.elementary_subdivision() Delta complex with 3 vertices and 19 simplices - sage: X.homology() == T.homology() + sage: X.homology() == T.homology() # needs sage.modules True """ pi = self._epi_from_standard_simplex(idx=idx) @@ -1382,10 +1390,10 @@ def _epi_from_standard_simplex(self, idx=-1, dim=None): faces_dict = {} for cell in n_cells: if n > 1: - faces = [tuple(simplex_cells[n-1][cell[j]]) for j in range(0,n+1)] - one_cell = dict(zip(faces, self_cells[n][n_cells[cell]])) + faces = [tuple(simplex_cells[n-1][cell[j]]) for j in range(n+1)] + one_cell = dict(zip(faces, self_cells[n][n_cells[cell]])) else: - temp = dict(zip(cell, self_cells[n][n_cells[cell]])) + temp = dict(zip(cell, self_cells[n][n_cells[cell]])) one_cell = {} for j in temp: one_cell[(j,)] = temp[j] @@ -1516,13 +1524,16 @@ def n_chains(self, n, base_ring=None, cochains=False): EXAMPLES:: sage: T = delta_complexes.Torus() - sage: T.n_chains(1, QQ) - Free module generated by {(0, (0, 0)), (1, (0, 0)), (2, (0, 0))} over Rational Field - sage: list(T.n_chains(1, QQ, cochains=False).basis()) + sage: T.n_chains(1, QQ) # needs sage.modules + Free module generated by {(0, (0, 0)), (1, (0, 0)), (2, (0, 0))} + over Rational Field + sage: list(T.n_chains(1, QQ, cochains=False).basis()) # needs sage.modules [(0, (0, 0)), (1, (0, 0)), (2, (0, 0))] - sage: list(T.n_chains(1, QQ, cochains=True).basis()) + sage: list(T.n_chains(1, QQ, cochains=True).basis()) # needs sage.modules [\chi_(0, (0, 0)), \chi_(1, (0, 0)), \chi_(2, (0, 0))] """ + from sage.homology.chains import Chains, Cochains + n_cells = tuple(enumerate(self.n_cells(n))) if cochains: return Cochains(self, n, n_cells, base_ring) @@ -1577,6 +1588,7 @@ def algebraic_topological_model(self, base_ring=None): EXAMPLES:: + sage: # needs sage.modules sage: RP2 = delta_complexes.RealProjectivePlane() sage: phi, M = RP2.algebraic_topological_model(GF(2)) sage: M.homology() @@ -1629,13 +1641,13 @@ class DeltaComplexExamples(): sage: S = delta_complexes.Sphere(6) # the 6-sphere sage: S.dimension() 6 - sage: S.cohomology(6) + sage: S.cohomology(6) # needs sage.modules Z sage: delta_complexes.Torus() == delta_complexes.Sphere(3) False """ - def Sphere(self,n): + def Sphere(self, n): r""" A `\Delta`-complex representation of the `n`-dimensional sphere, formed by gluing two `n`-simplices along their boundary, @@ -1646,13 +1658,12 @@ def Sphere(self,n): EXAMPLES:: - sage: delta_complexes.Sphere(4).cohomology(4, base_ring=GF(3)) + sage: delta_complexes.Sphere(4).cohomology(4, base_ring=GF(3)) # needs sage.modules Vector space of dimension 1 over Finite Field of size 3 """ if n == 1: - return DeltaComplex([ [()], [(0, 0)] ]) - else: - return DeltaComplex({Simplex(n): True, Simplex(range(1,n+2)): Simplex(n)}) + return DeltaComplex([[()], [(0, 0)]]) + return DeltaComplex({Simplex(n): True, Simplex(range(1, n+2)): Simplex(n)}) def Torus(self): r""" @@ -1663,7 +1674,7 @@ def Torus(self): EXAMPLES:: - sage: delta_complexes.Torus().homology(1) + sage: delta_complexes.Torus().homology(1) # needs sage.modules sage.rings.finite_rings Z x Z """ return DeltaComplex((((),), ((0, 0), (0, 0), (0, 0)), @@ -1678,6 +1689,7 @@ def RealProjectivePlane(self): EXAMPLES:: + sage: # needs sage.modules sage: P = delta_complexes.RealProjectivePlane() sage: P.cohomology(1) 0 @@ -1741,9 +1753,9 @@ def SurfaceOfGenus(self, g, orientable=True): sage: delta_complexes.SurfaceOfGenus(1, orientable=False) Delta complex with 2 vertices and 8 simplices - sage: delta_complexes.SurfaceOfGenus(3, orientable=False).homology(1) + sage: delta_complexes.SurfaceOfGenus(3, orientable=False).homology(1) # needs sage.modules Z x Z x C2 - sage: delta_complexes.SurfaceOfGenus(3, orientable=False).homology(2) + sage: delta_complexes.SurfaceOfGenus(3, orientable=False).homology(2) # needs sage.modules 0 Compare to simplicial complexes:: @@ -1754,7 +1766,7 @@ def SurfaceOfGenus(self, g, orientable=True): sage: simpl_g4 = simplicial_complexes.SurfaceOfGenus(4) sage: simpl_g4.f_vector() [1, 19, 75, 50] - sage: delta_g4.homology() == simpl_g4.homology() + sage: delta_g4.homology() == simpl_g4.homology() # needs sage.modules True """ try: diff --git a/src/sage/topology/filtered_simplicial_complex.py b/src/sage/topology/filtered_simplicial_complex.py index a8193680b29..95191dd1cd4 100644 --- a/src/sage/topology/filtered_simplicial_complex.py +++ b/src/sage/topology/filtered_simplicial_complex.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Finite filtered complexes @@ -16,25 +16,26 @@ EXAMPLES:: sage: FilteredSimplicialComplex([([0], 0), ([1], 0), ([0, 1], 1)]) - Filtered complex on vertex set (0, 1) and with simplices ((0,) : 0), ((1,) : 0), ((0, 1) : 1) + Filtered complex on vertex set (0, 1) and + with simplices ((0,) : 0), ((1,) : 0), ((0, 1) : 1) Sage can compute persistent homology of simplicial complexes:: sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0, 1], 1)]) - sage: X.persistence_intervals(0) + sage: X.persistence_intervals(0) # needs sage.modules [(0, 1), (0, +Infinity)] FilteredSimplicialComplex objects are mutable. Filtration values can be set with the ``filtration`` method as follows:: sage: X = FilteredSimplicialComplex() # returns an empty complex - sage: X.persistence_intervals(1) + sage: X.persistence_intervals(1) # needs sage.modules [] sage: X.filtration(Simplex([0, 2]), 0) # recursively adds faces sage: X.filtration(Simplex([0, 1]), 0) sage: X.filtration(Simplex([1, 2]), 0) sage: X.filtration(Simplex([0, 1, 2]), 1) # closes the circle - sage: X.persistence_intervals(1) + sage: X.persistence_intervals(1) # needs sage.modules [(0, 1)] The filtration value of a simplex can be accessed as well with the @@ -82,13 +83,15 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.sage_object import SageObject -from sage.topology.simplicial_complex import Simplex, SimplicialComplex -from sage.modules.free_module import FreeModule -from sage.rings.finite_rings.finite_field_constructor import GF +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.infinity import infinity -from sage.misc.cachefunc import cached_method +from sage.structure.sage_object import SageObject +from sage.topology.simplicial_complex import Simplex, SimplicialComplex + +lazy_import('sage.modules.free_module', 'FreeModule') +lazy_import('sage.rings.finite_rings.finite_field_constructor', 'GF') class FilteredSimplicialComplex(SageObject): @@ -359,7 +362,8 @@ def prune(self, threshold): sage: a.insert([0, 2], 2) sage: b = a.prune(1) sage: b - Filtered complex on vertex set (0, 1) and with simplices ((0,) : 0), ((1,) : 1), ((0, 1) : 1) + Filtered complex on vertex set (0, 1) and + with simplices ((0,) : 0), ((1,) : 1), ((0, 1) : 1) """ result_complex = FilteredSimplicialComplex() for s in self._filtration_dict: @@ -394,7 +398,7 @@ def _persistent_homology(self, field=2, strict=True, verbose=False): EXAMPLES:: sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0,1], 2)]) - sage: X._persistent_homology()[0] + sage: X._persistent_homology()[0] # needs sage.modules [(0, 2), (0, +Infinity)] Some homology elements may have a lifespan or persistence of 0. @@ -402,7 +406,7 @@ def _persistent_homology(self, field=2, strict=True, verbose=False): sage: X = FilteredSimplicialComplex() sage: X.insert([0,1],1) # opens a hole and closes it instantly - sage: X._persistent_homology(strict=False)[0] + sage: X._persistent_homology(strict=False)[0] # needs sage.modules [(1, 1), (1, +Infinity)] REFERENCES: @@ -417,11 +421,11 @@ def _persistent_homology(self, field=2, strict=True, verbose=False): ....: ([1, 2], 1), ([0, 3], 2), ([2, 3], 2), ([0, 2], 3), ....: ([0, 1, 2], 4), ([0, 2, 3], 5)] sage: X = FilteredSimplicialComplex(l) - sage: X.persistence_intervals(0) + sage: X.persistence_intervals(0) # needs sage.modules [(0, 1), (1, 2), (0, +Infinity)] - sage: X.persistence_intervals(1) + sage: X.persistence_intervals(1) # needs sage.modules [(3, 4), (2, 5)] - sage: X.persistence_intervals(0, strict=False) + sage: X.persistence_intervals(0, strict=False) # needs sage.modules [(0, 1), (1, 1), (1, 2), (0, +Infinity)] """ # first, order the simplices in lexico order @@ -506,18 +510,19 @@ def _add_interval(self, s, t, intervals): TESTS:: + sage: # needs sage.modules sage: X = FilteredSimplicialComplex([([0], 0), ([1, 2], 10)]) sage: int_list = X._persistent_homology() sage: int_list[0] [(0, +Infinity), (10, +Infinity)] - sage: X._add_interval(Simplex([0]), Simplex([1, 2]),int_list) + sage: X._add_interval(Simplex([0]), Simplex([1, 2]), int_list) sage: int_list[0] [(0, +Infinity), (10, +Infinity), (0, 10)] Infinite interval:: sage: int_list2 = [[],[]] - sage: X._add_interval(Simplex([1, 2]), None, int_list2) + sage: X._add_interval(Simplex([1, 2]), None, int_list2) # needs sage.modules sage: int_list2[1] [(10, +Infinity)] """ @@ -552,12 +557,12 @@ def _remove_pivot_rows(self, s, simplices): sage: l = [([0], 0), ([1], 0), ([2], 1), ([3], 1), ([0, 1], 1), ([1, 2], 1), ....: ([0, 3], 2), ([2, 3], 2), ([0, 2], 3), ([0, 1, 2], 4)] sage: X = FilteredSimplicialComplex(l) - sage: X._persistent_homology() + sage: X._persistent_homology() # needs sage.modules [[(0, 1), (1, 2), (0, +Infinity)], [(3, 4), (2, +Infinity)], []] - sage: X._remove_pivot_rows(Simplex([0,1,2]), list(X._filtration_dict)) + sage: X._remove_pivot_rows(Simplex([0,1,2]), list(X._filtration_dict)) # needs sage.modules 0 sage: X.insert([0,2,3],5) - sage: X._remove_pivot_rows(Simplex([0,2,3]), list(X._filtration_dict)) + sage: X._remove_pivot_rows(Simplex([0,2,3]), list(X._filtration_dict)) # needs sage.modules B[(2, 3)] """ d = self._chaingroup() @@ -602,6 +607,7 @@ def _max_index(self, d): TESTS:: + sage: # needs sage.modules sage: X = FilteredSimplicialComplex([([0], 0), ([1], 5), ([0, 1], 18), ([0, 2, 3], 32)]) sage: X._persistent_homology() [[(5, 18), (0, +Infinity)], [], []] @@ -637,7 +643,7 @@ def persistence_intervals(self, dimension, field=2, strict=True, verbose=None): EXAMPLES:: sage: X = FilteredSimplicialComplex([([0], 0), ([1], 1), ([0,1], 2)]) - sage: X.persistence_intervals(0) + sage: X.persistence_intervals(0) # needs sage.modules [(1, 2), (0, +Infinity)] """ if verbose is None: @@ -672,16 +678,16 @@ def betti_number(self, k, a, b, field=2, strict=True, verbose=None): EXAMPLES:: sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0,1], 2)]) - sage: X.betti_number(0, 0.5, 1) + sage: X.betti_number(0, 0.5, 1) # needs sage.modules 2 - sage: X.betti_number(0, 1.5, 1) + sage: X.betti_number(0, 1.5, 1) # needs sage.modules 1 If an element vanishes at time ``a + b`` exactly, it does not count towards the Betti number:: sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0,1], 2)]) - sage: X.betti_number(0, 1.5, 0.5) + sage: X.betti_number(0, 1.5, 0.5) # needs sage.modules 1 """ if verbose is None: diff --git a/src/sage/topology/moment_angle_complex.py b/src/sage/topology/moment_angle_complex.py new file mode 100644 index 00000000000..a06aea0309b --- /dev/null +++ b/src/sage/topology/moment_angle_complex.py @@ -0,0 +1,816 @@ +""" +Moment-angle complexes + +AUTHORS: + +- Ognjen Petrov (2023-06-25): initial version +""" + +# **************************************************************************** +# Copyright (C) 2023 Ognjen Petrov <ognjenpetrov@yahoo.com> +# +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.homology.homology_group import HomologyGroup +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.structure.sage_object import SageObject +from sage.structure.unique_representation import UniqueRepresentation +from .cubical_complex import CubicalComplex, cubical_complexes +from .simplicial_complex import SimplicialComplex, copy +from sage.topology import simplicial_complex_catalog as simplicial_complexes +from itertools import combinations + + +def _cubical_complex_union(c1, c2): + """ + Return the union of cubical complexes. + + This method returns a cubical complex whose set of maximal faces + is the union of sets of maximal faces of ``c1`` and ``c2``. + + INPUT: + + - ``c1``, ``c2`` -- a cubical complex + + OUTPUT: the union of cubical complexes ``c1`` and ``c2`` + + .. WARNING:: + + This is regular union, not disjoint union. One should be careful + with the nomenclature of the vertices. + + EXAMPLES:: + + sage: from sage.topology.moment_angle_complex import ( + ....: _cubical_complex_union as union + ....: ) + sage: C1 = CubicalComplex([([0,0], [2,3]), ([0,1], [3,3]), + ....: ([0,1], [2,2]), ([1,1], [2,3])]); C1 + Cubical complex with 4 vertices and 8 cubes + sage: C2 = CubicalComplex([([0,0], [2,3]), ([0,1], [3,3]), + ....: ([0,1], [2,2]), ([2,2], [2,3])]); C2 + Cubical complex with 6 vertices and 10 cubes + sage: union(C1, C2) + Cubical complex with 6 vertices and 11 cubes + sage: union(C1, C1) == C1 + True + """ + facets = [] + for f in c1.maximal_cells(): + facets.append(f) + for f in c2.maximal_cells(): + facets.append(f) + return CubicalComplex(facets) + + +class MomentAngleComplex(UniqueRepresentation, SageObject): + r""" + A moment-angle complex. + + Given a simplicial complex `K`, with a set of vertices + `V = \{v_1, v_2, \ldots, v_n\}`, a moment-angle complex over `K` is a + topological space `Z`, which is a union of `X_{\sigma}`, where + `\sigma \in K`, and `X_{\sigma} = Y_{v_1} \times Y_{v_2} \times \cdots + \times Y_{v_n}` and `Y_{v_i}` is a 2-disk (a 2-simplex) if + `v_i \in \sigma` , or a 1-sphere otherwise. + + .. MATH:: + + Y_{v_i} = + \begin{cases} + D^2, &v_i \in \sigma,\\ + S^1, &v_i \notin \sigma. + \end{cases} + + .. NOTE:: + + The mentioned union is not a disjoint union of topological spaces. + The unit disks and the unit spheres are considered subsets of `\CC`, + so the union is just a normal union of subsets of `\CC^n`. + + Here we view moment-angle complexes as cubical complexes and + try to compute mostly things which would not require computing + the moment-angle complex itself, but rather work with the + corresponding simplicial complex. + + .. NOTE:: + + One of the more useful properties will be the + :meth:`bigraded Betti numbers + <sage.topology.simplicial_complex.bigraded_betti_numbers>`, + and the underlying theorem which makes this possible is Hochter's + formula, which can be found on page 104 of [BP2014]_. + + INPUT: + + - ``simplicial_complex`` -- an instance of ``SimplicialComplex``, + or an object from which an instance of ``SimplicialComplex`` can be + created (e.g., list of facets), which represents the associated + simplicial complex over which this moment-angle complex is created + + EXAMPLES:: + + sage: MomentAngleComplex([[1,2,3], [2,4], [3,4]]) + Moment-angle complex of Simplicial complex with vertex set + (1, 2, 3, 4) and facets {(2, 4), (3, 4), (1, 2, 3)} + sage: X = SimplicialComplex([[0,1], [1,2], [1,3], [2,3]]) + sage: Z = MomentAngleComplex(X); Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2, 3) and facets {(0, 1), (1, 2), (1, 3), (2, 3)} + sage: M = MomentAngleComplex([[1], [2]]); M + Moment-angle complex of Simplicial complex with vertex set + (1, 2) and facets {(1,), (2,)} + + We can perform a number of operations, such as find the dimension or + compute the homology:: + + sage: M.homology() + {0: 0, 1: 0, 2: 0, 3: Z} + sage: Z.dimension() + 6 + sage: Z.homology() + {0: 0, 1: 0, 2: 0, 3: Z x Z, 4: Z, 5: Z, 6: Z} + + If the associated simplicial complex is an `n`-simplex, then the + corresponding moment-angle complex is a polydisc (a complex ball) of + complex dimension `n+1`:: + + sage: Z = MomentAngleComplex([[0, 1, 2]]); Z + Moment-angle complex of Simplicial complex with vertex set (0, 1, 2) + and facets {(0, 1, 2)} + + This can be seen by viewing the components used in the construction + of this moment-angle complex by calling :meth:`components()`:: + + sage: Z.components() + {(0, 1, 2): [The 2-simplex, The 2-simplex, The 2-simplex]} + + If the associated simplicial complex is a disjoint union of 2 points, + then the corresponding moment-angle complex is homeomorphic to a boundary + of a 3-sphere:: + + sage: Z = MomentAngleComplex([[0], [1]]); Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1) and facets {(0,), (1,)} + sage: dict(sorted(Z.components().items())) + {(0,): [The 2-simplex, Minimal triangulation of the 1-sphere], + (1,): [Minimal triangulation of the 1-sphere, The 2-simplex]} + + The moment-angle complex passes all the tests of the test suite relative + to its category:: + + sage: TestSuite(Z).run() + """ + @staticmethod + def __classcall_private__(cls, simplicial_complex): + """ + Normalize input to ensure a unique representation. + + TESTS:: + + sage: Z = MomentAngleComplex([[0,2], [1,2,3]]) + sage: W = MomentAngleComplex([[0,2], [1,2,3]]) + sage: Z is W + True + sage: Z is MomentAngleComplex(Z) + True + """ + if simplicial_complex: + if isinstance(simplicial_complex, MomentAngleComplex): + # Allows for copy constructor + immutable_complex = SimplicialComplex(simplicial_complex._simplicial_complex, is_mutable=False) + elif not isinstance(simplicial_complex, SimplicialComplex): + # Try to create a SimplicialComplex out of simplicial_complex + # in case that simplicial_complex is a list of facets, or + # something that can generate a SimplicialComplex + immutable_complex = SimplicialComplex(simplicial_complex, is_mutable=False) + elif simplicial_complex.is_mutable(): + immutable_complex = SimplicialComplex(simplicial_complex, is_mutable=False) + else: + immutable_complex = simplicial_complex + else: + immutable_complex = SimplicialComplex(is_mutable=False) + return super().__classcall__(cls, immutable_complex) + + def __init__(self, simplicial_complex): + """ + Initialize ``self``. + + TESTS:: + + sage: Z = MomentAngleComplex([[0,1,2], [1,2,3], [0, 3]]) + sage: TestSuite(Z).run() + """ + # The underlying simplicial complex + self._simplicial_complex = copy(simplicial_complex) + # A dictionary of components indexed by facets + self._components = {} + + vertices = self._simplicial_complex.vertices() + # it suffices to perform union only over facets + for facet in self._simplicial_complex.maximal_faces(): + Y = [] + for j in vertices: + if j in facet: + Y.append(simplicial_complexes.Simplex(2)) + else: + Y.append(simplicial_complexes.Sphere(1)) + + self._components[facet] = Y + + @lazy_attribute + def _moment_angle_complex(self): + """ + Create the moment-angle complex as a cubical complex. + + If this lazy attribute is accessed, we explicitly compute + the moment-angle complex, viewed as a cubical complex. + + .. WARNING:: + + The construction can be very slow, it is not reccomended unless + the corresponding simplicial complex has 5 or less vertices. + + TESTS:: + + sage: Z = MomentAngleComplex([[0], [1], [2]]); Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2) and facets {(0,), (1,), (2,)} + sage: Z._moment_angle_complex + Cubical complex with 64 vertices and 705 cubes + + This is called by :meth:`cubical_complex()`:: + + sage: Z.cubical_complex() + Cubical complex with 64 vertices and 705 cubes + sage: Z.cubical_complex() == Z._moment_angle_complex + True + """ + n = len(self._simplicial_complex.vertices()) + D = [cubical_complexes.Cube(2)] * n + S = [cubical_complexes.Sphere(1)] * n + + moment_angle_complex = CubicalComplex() + for component in self._components.values(): + x = D[0] if component[0] == simplicial_complexes.Simplex(2) else S[0] + for j in range(1, len(component)): + y = D[j] if component[j] == simplicial_complexes.Simplex(2) else S[j] + x = x.product(y) + moment_angle_complex = _cubical_complex_union(moment_angle_complex, x) + + return moment_angle_complex + + def _repr_(self): + """ + Return a string representation of ``self``. + + TESTS:: + + sage: Z = MomentAngleComplex([[0,1], [1,2], [2,0]]) + sage: Z._repr_() + 'Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2) and facets {(0, 1), (0, 2), (1, 2)}' + sage: repr(Z) + 'Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2) and facets {(0, 1), (0, 2), (1, 2)}' + sage: Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2) and facets {(0, 1), (0, 2), (1, 2)} + sage: Z = MomentAngleComplex([[i for i in range(20)]]) + sage: Z._repr_() + 'Moment-angle complex of Simplicial complex with + 20 vertices and 1 facets' + """ + return "Moment-angle complex of " + repr(self._simplicial_complex) + + def cubical_complex(self): + """ + Return the cubical complex that represents ``self``. + + This method returns returns a cubical complex which is + derived by explicitly computing products and unions in the + definition of a moment-angle complex. + + .. WARNING:: + + The construction can be very slow, it is not reccomended unless + the corresponding simplicial complex has 5 or less vertices. + + EXAMPLES:: + + sage: Z = MomentAngleComplex([[0,1,2], [1,3]]); Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2, 3) and facets {(1, 3), (0, 1, 2)} + sage: Z.cubical_complex() + Cubical complex with 256 vertices and 6409 cubes + sage: dim(Z.cubical_complex()) == dim(Z) + True + sage: Z = MomentAngleComplex([[0,1], [1,2], [2,0], [1,3]]); Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2, 3) and facets {(0, 1), (0, 2), (1, 2), (1, 3)} + sage: Z.betti() == Z.cubical_complex().betti() # long time + True + + We can now work with moment-angle complexes as concrete cubical + complexes. Though, it can be very slow, due to the size of the + complex. However, for some smaller moment-angle complexes, this + may be possible:: + + sage: Z = MomentAngleComplex([[0], [1]]); Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1) and facets {(0,), (1,)} + sage: Z.cubical_complex().f_vector() + [1, 16, 32, 24, 8] + """ + return self._moment_angle_complex + + def simplicial_complex(self): + """ + Return the simplicial complex that defines ``self``. + + EXAMPLES:: + + sage: RP2 = simplicial_complexes.RealProjectivePlane() + sage: Z = MomentAngleComplex(RP2) + sage: Z.simplicial_complex() + Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and 10 facets + sage: Z = MomentAngleComplex([[0], [1], [2]]) + sage: Z.simplicial_complex() + Simplicial complex with vertex set (0, 1, 2) + and facets {(0,), (1,), (2,)} + """ + return self._simplicial_complex + + def components(self): + r""" + Return the dictionary of components of ``self``, indexed by facets + of the associated simplicial complex. + + OUTPUT: + + A dictonary, whose values are lists, representing spheres + and disks described in the construction of the moment-angle + complex. ``The 2-simplex`` represents a 2-disk, and + ``Minimal triangulation of the 1-sphere`` represents a 1-sphere. + + EXAMPLES:: + + sage: M = MomentAngleComplex([[0, 1, 2]]); M + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2) and facets {(0, 1, 2)} + sage: M.components() + {(0, 1, 2): [The 2-simplex, The 2-simplex, The 2-simplex]} + sage: Z = MomentAngleComplex([[0], [1]]); Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1) and facets {(0,), (1,)} + sage: sorted(Z.components().items()) + [((0,), [The 2-simplex, Minimal triangulation of the 1-sphere]), + ((1,), [Minimal triangulation of the 1-sphere, The 2-simplex])] + + We interpret the output of this method by taking the product + of all the elements in each list, and then taking the union + of all products. From the previous example, we have + `\mathcal{Z} = S^1 \times D^2 \cup D^2 \times S^1 + = \partial (D^2 \times D^2) = \partial D^4 = S^3`:: + + sage: Z = MomentAngleComplex([[0,1], [1,2], [2,3], [3,0]]) + sage: sorted(Z.components().items()) + [((0, 1), + [The 2-simplex, + The 2-simplex, + Minimal triangulation of the 1-sphere, + Minimal triangulation of the 1-sphere]), + ((0, 3), + [The 2-simplex, + Minimal triangulation of the 1-sphere, + Minimal triangulation of the 1-sphere, + The 2-simplex]), + ((1, 2), + [Minimal triangulation of the 1-sphere, + The 2-simplex, + The 2-simplex, + Minimal triangulation of the 1-sphere]), + ((2, 3), + [Minimal triangulation of the 1-sphere, + Minimal triangulation of the 1-sphere, + The 2-simplex, + The 2-simplex])] + + It is not that difficult to prove that the previous + moment-angle complex is homeomorphic to a product of + two 3-spheres. We can look at the cohomologies to try + and validate whether this makes sense:: + + sage: S3 = simplicial_complexes.Sphere(3) + sage: product_of_spheres = S3.product(S3) + sage: Z.cohomology() + {0: 0, 1: 0, 2: 0, 3: Z x Z, 4: 0, 5: 0, 6: Z} + sage: Z.cohomology() == product_of_spheres.cohomology() + True + """ + return self._components + + def dimension(self): + r""" + The dimension of ``self``. + + The dimension of a moment-angle complex is the dimension + of the constructed (cubical) complex. It is not difficult + to see that this turns out to be `m+n+1`, where `m` is the + number of vertices and `n` is the dimension of the associated + simplicial complex. + + EXAMPLES:: + + sage: Z = MomentAngleComplex([[0,1], [1,2,3]]) + sage: Z.dimension() + 7 + sage: Z = MomentAngleComplex([[0, 1, 2]]) + sage: Z.dimension() + 6 + sage: dim(Z) + 6 + + We can construct the cubical complex and compare whether + the dimensions coincide:: + + sage: dim(Z) == dim(Z.cubical_complex()) + True + """ + number_of_vertices = len(self._simplicial_complex.vertices()) + dim = self._simplicial_complex.dimension() + return number_of_vertices + dim + 1 + + @cached_method # maybe ignore the algorithm? + def _homology_group(self, i, base_ring, cohomology, algorithm, verbose, reduced): + """ + The `i`-th (reduced) homology group of ``self``. + + .. SEEALSO:: + + :meth:`homology`, + :meth:`.cell_complex.GenericCellComplex.homology`. + + TESTS:: + + sage: Z = MomentAngleComplex([[0,1,2], [1,2,3]]); Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2, 3) and facets {(0, 1, 2), (1, 2, 3)} + sage: Z._homology_group(3, base_ring=ZZ, + ....: reduced=True, verbose=False, + ....: cohomology=False, algorithm='pari') + Z + sage: Z._homology_group(4, base_ring=ZZ, + ....: reduced=True, verbose=False, + ....: cohomology=False, algorithm='pari') + 0 + sage: Z.homology() + {0: 0, 1: 0, 2: 0, 3: Z, 4: 0, 5: 0, 6: 0, 7: 0} + sage: RP2 = simplicial_complexes.RealProjectivePlane() + sage: Z = MomentAngleComplex(RP2) + sage: Z._homology_group(8, base_ring=ZZ, + ....: reduced=True, verbose=False, + ....: cohomology=False, algorithm='pari') + C2 + """ + if i == 0: + # This is a special case when computing (co)homology + if reduced: + return HomologyGroup(0, base_ring) + return HomologyGroup(1, base_ring) + + vertices = self._simplicial_complex.vertices() + n = len(vertices) + invfac = [] + + for j in range(n+1): + for x in combinations(vertices, j): + S = self._simplicial_complex.generated_subcomplex(x) + if base_ring.is_field(): + invfac.append(S.homology(i-j-1, base_ring=base_ring, + cohomology=cohomology, algorithm=algorithm, + verbose=verbose, reduced=True).dimension()) + else: + invfac.extend(S.homology(i-j-1, base_ring=base_ring, + cohomology=cohomology, algorithm=algorithm, + verbose=verbose, reduced=True)._original_invts) + + if base_ring.is_field(): + return HomologyGroup(sum(invfac), base_ring) + + m = len(invfac) + return HomologyGroup(m, base_ring, invfac) + + def homology(self, dim=None, base_ring=ZZ, cohomology=False, + algorithm='pari', verbose=False, reduced=True): + r""" + The (reduced) homology of ``self``. + + INPUT: + + - ``dim`` -- integer, or a list of integers; represents the + homology (or homologies) we want to compute + - ``base_ring`` -- commutative ring (default: ``ZZ``); must be ``ZZ`` + or a field + - ``cohomology`` -- boolean (default: ``False``); + if ``True``, compute cohomology rather than homology + - ``algorithm`` -- string (default: ``'pari'``); the options are + ``'auto'``, ``'dhsw'``, or ``'pari'``; see + :meth:`.cell_complex.GenericCellComplex.homology` documentation + for a description of what they mean + - ``verbose`` -- boolean (default: ``False``); if ``True``, + print some messages as the homology is computed + - ``reduced`` -- boolean (default: ``True``); if ``True``, + return the reduced homology + + ALGORITHM: + + This algorithm is adopted from Theorem 4.5.8 of [BP2014]_. + + The (co)homology of the moment-angle complex is closely related + to the (co)homologies of certain full subcomplexes of the + associated simplicial complex. More specifically, we know that: + + .. MATH:: + + H_l(\mathcal{Z}_\mathcal{K}) \cong + \bigoplus_{J \subseteq [m]} \widetilde{H}_{l-|J|-1}(\mathcal{K}_J), + + where `\mathcal{Z}_\mathcal{K}` denotes the moment-angle complex + associated to a simplicial complex `\mathcal{K}`, on the set of + vertices `\{1, 2, 3, \ldots, m\} =: [m]`. `\mathcal{K}_J` denotes the + full subcomplex of `\mathcal{K}`, generated by a set of vertices `J`. + The same formula holds true for cohomology groups as well. + + .. SEEALSO:: + + :meth:`.cell_complex.GenericCellComplex.homology` + + EXAMPLES:: + + sage: Z = MomentAngleComplex([[0,1,2], [1,2,3], [3,0]]); Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2, 3) and facets {(0, 3), (0, 1, 2), (1, 2, 3)} + sage: Z = MomentAngleComplex([[0,1,2], [1,2,3], [3,0]]) + sage: Z.homology() + {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: Z x Z, 6: Z, 7: 0} + sage: Z.homology(base_ring=GF(2)) + {0: Vector space of dimension 0 over Finite Field of size 2, + 1: Vector space of dimension 0 over Finite Field of size 2, + 2: Vector space of dimension 0 over Finite Field of size 2, + 3: Vector space of dimension 0 over Finite Field of size 2, + 4: Vector space of dimension 0 over Finite Field of size 2, + 5: Vector space of dimension 2 over Finite Field of size 2, + 6: Vector space of dimension 1 over Finite Field of size 2, + 7: Vector space of dimension 0 over Finite Field of size 2} + sage: RP = simplicial_complexes.RealProjectivePlane() + sage: Z = MomentAngleComplex(RP) + sage: Z.homology() + {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: Z^10, 6: Z^15, 7: Z^6, 8: C2, 9: 0} + + This yields the same result as creating a cubical complex + from this moment-angle complex, and then computing its (co)homology, + but that is incomparably slower and is really only possible when + the associated simplicial complex is very small:: + + sage: Z = MomentAngleComplex([[0,1], [1,2], [2,0]]); Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2) and facets {(0, 1), (0, 2), (1, 2)} + sage: Z.cubical_complex() + Cubical complex with 64 vertices and 729 cubes + sage: Z.cubical_complex().homology() == Z.homology() + True + + Meanwhile, the homology computation used here is quite efficient + and works well even with significantly larger underlying simplicial + complexes:: + + sage: Z = MomentAngleComplex([[0,1,2,3,4,5], [0,1,2,3,4,6], + ....: [0,1,2,3,5,7], [0,1,2,3,6,8,9]]) + sage: Z.homology() + {0: 0, + 1: 0, + 2: 0, + 3: Z^9, + 4: Z^17, + 5: Z^12, + 6: Z x Z x Z, + 7: 0, + 8: 0, + 9: 0, + 10: 0, + 11: 0, + 12: 0, + 13: 0, + 14: 0, + 15: 0, + 16: 0, + 17: 0} + sage: Z = MomentAngleComplex([[0,1,2,3], [0,1,2,4], [0,1,3,5], + ....: [0,1,4,5], [0,2,3,6], [0,2,4,6]]) + sage: Z.homology(dim=range(0,5), reduced=True) + {0: 0, 1: 0, 2: 0, 3: Z x Z x Z x Z, 4: Z x Z} + sage: Z.homology(dim=range(0,5), reduced=False) + {0: Z, 1: 0, 2: 0, 3: Z x Z x Z x Z, 4: Z x Z} + sage: all(Z.homology(i,reduced=True) == Z.homology(i,reduced=False) + ....: for i in range(1, dim(Z))) + True + sage: all(Z.homology(i,reduced=True) == Z.homology(i,reduced=False) + ....: for i in range(0, dim(Z))) + False + """ + if dim is not None: + if isinstance(dim, (list, tuple, range)): + low = min(dim) + high = max(dim) + else: + low = dim + high = dim + dims = range(low, high + 1) + else: + dims = range(self.dimension()+1) + + answer = {i: self._homology_group(i, base_ring=base_ring, cohomology=cohomology, + algorithm=algorithm, verbose=verbose, reduced=reduced) for i in dims} + return answer + + def cohomology(self, dim=None, base_ring=ZZ, algorithm='pari', + verbose=False, reduced=True): + r""" + The reduced cohomology of ``self``. + + This is equivalent to calling the ``homology()`` method, + with ``cohomology=True`` as an argument. + + .. SEEALSO:: + + :meth:`homology`. + + EXAMPLES:: + + sage: X = SimplicialComplex([[0,1],[1,2],[2,3],[3,0]]) + sage: Z = MomentAngleComplex(X) + + It is known that the previous moment-angle complex is homeomorphic + to a product of two 3-spheres (which can be seen by looking at the + output of ``components()``):: + + sage: S3 = simplicial_complexes.Sphere(3) + sage: product_of_spheres = S3.product(S3) + sage: Z.cohomology() + {0: 0, 1: 0, 2: 0, 3: Z x Z, 4: 0, 5: 0, 6: Z} + sage: Z.cohomology() == product_of_spheres.cohomology() + True + """ + return self.homology(dim=dim, cohomology=True, base_ring=base_ring, + algorithm=algorithm, verbose=verbose, reduced=reduced) + + def betti(self, dim=None): + r""" + Return the Betti number (or numbers) of ``self``. + + The the `i`-th Betti number is the rank of the `i`-th homology group. + + INPUT: + + - ``dim`` -- (optional) an integer or a list of integers + + OUTPUT: + + If ``dim`` is an integer or a list of integers, then return + a dictionary of Betti numbers for each given dimension, indexed + by dimension. Otherwise, return all Betti numbers. + + EXAMPLES:: + + sage: Z = MomentAngleComplex([[0,1], [1,2], [2,0], [1,2,3]]) + sage: Z.betti() + {0: 1, 1: 0, 2: 0, 3: 1, 4: 0, 5: 1, 6: 1, 7: 0} + sage: Z = MomentAngleComplex([[0,1], [1,2], [2,0], [1,2,3], [3,0]]) + sage: Z.betti(dim=6) + {6: 2} + """ + dict = {} + H = self.homology(dim=dim, base_ring=QQ) + try: + for n in H.keys(): + dict[n] = H[n].dimension() + if n == 0: + dict[n] += 1 + return dict + except AttributeError: + return H.dimension() + + def euler_characteristic(self): + """ + Return the Euler characteristic of ``self``. + + The Euler characteristic is defined as the alternating sum + of the Betti numbers of ``self``. + + EXAMPLES:: + + sage: X = SimplicialComplex([[0,1,2,3,4,5], [0,1,2,3,4,6], + ....: [0,1,2,3,5,7], [0,1,2,3,6,8,9]]) + sage: M = MomentAngleComplex(X) + sage: M.euler_characteristic() + 0 + sage: Z = MomentAngleComplex([[0,1,2,3,4]]) + sage: Z.euler_characteristic() + 1 + """ + betti_numbers = self.betti() + return ZZ.sum((-1)**n * betti_numbers[n] for n in range(self.dimension() + 1)) + + def product(self, other): + """ + Return the product of ``self`` with ``other``. + + It is known that the product of two moment-angle complexes + is a moment-angle complex over the join of the two corresponding + simplicial complexes. This result can be found on page 138 of + [BP2014]_. + + OUTPUT: a moment-angle complex which is the product of the + parsed moment-angle complexes + + EXAMPLES:: + + sage: X = SimplicialComplex([[0,1,2,3], [1,4], [3,2,4]]) + sage: Y = SimplicialComplex([[1,2,3],[1,2,4],[3,5],[4,5]]) + sage: Z = MomentAngleComplex(X) + sage: M = MomentAngleComplex(Y) + sage: Z.product(M) + Moment-angle complex of Simplicial complex with + 10 vertices and 12 facets + sage: Z.product(M) == MomentAngleComplex(X*Y) + True + """ + simplicial_complex = self._simplicial_complex.join(other._simplicial_complex, rename_vertices=True) + return MomentAngleComplex(simplicial_complex) + + def has_trivial_lowest_deg_massey_product(self): + """ + Return whether ``self`` has a non-trivial lowest degree + triple Massey product. + + This is the Massey product in the cohomology of this + moment-angle complex. This relies on the theorem which was + proven in [GL2019]_. + + ALGORITHM: + + We obtain the one-skeleton from the associated simplicial complex, + which we consider to be a graph. We then perform ``subgraph_search``, + searching for any subgraph isomorphic to one of the 8 obstruction + graphs listed in the mentioned paper. + + EXAMPLES: + + A simplex will not have a trivial triple lowest-degree + Massey product, because its one-skeleton certainly does + contain a subcomplex isomorphic to one of the 8 mentioned + in the paper:: + + sage: Z = MomentAngleComplex([[1,2,3,4,5,6]]) + sage: Z.has_trivial_lowest_deg_massey_product() + False + + The following is one of the 8 obstruction graphs:: + + sage: Z = MomentAngleComplex([[1, 2], [1, 4], [2, 3], [3, 5], + ....: [5, 6], [4, 5], [1, 6]]) + sage: Z.has_trivial_lowest_deg_massey_product() + False + + A hexagon is not isomorphic to any of the 8 obstruction graphs:: + + sage: Z = MomentAngleComplex([[0,1], [1,2], [2,3], + ....: [3,4], [4,5], [5,0]]) + sage: Z.has_trivial_lowest_deg_massey_product() + True + """ + from sage.graphs.graph import Graph + + one_skeleton = self._simplicial_complex.graph() + + obstruction_graphs = [ + Graph([(1, 2), (1, 4), (2, 3), (3, 5), (5, 6), (4, 5), (1, 6)]), + Graph([(1, 2), (1, 4), (2, 3), (3, 5), (5, 6), (4, 5), (1, 6), (2, 6)]), + Graph([(1, 2), (1, 4), (2, 3), (3, 5), (5, 6), (4, 5), (1, 6), (4, 6)]), + Graph([(1, 2), (1, 4), (2, 3), (3, 5), (5, 6), (4, 5), (1, 6), (2, 6), (4, 6)]), + Graph([(1, 2), (1, 4), (2, 3), (3, 5), (5, 6), (3, 4), (2, 6), (1, 6), (4, 5)]), + Graph([(1, 2), (1, 4), (2, 3), (3, 5), (5, 6), (3, 4), (2, 6), (1, 6), (4, 5), (4, 6)]), + Graph([(1, 2), (1, 4), (2, 3), (3, 5), (5, 6), (3, 4), (2, 6), (4, 5), (4, 6)]), + Graph([(1, 2), (1, 4), (2, 3), (3, 5), (5, 6), (3, 4), (2, 6), (4, 6)]), + ] + + return not any(one_skeleton.subgraph_search(g) is not None for g in obstruction_graphs) diff --git a/src/sage/topology/simplicial_complex.py b/src/sage/topology/simplicial_complex.py index 10ba66cf42a..1d00dd50a4d 100644 --- a/src/sage/topology/simplicial_complex.py +++ b/src/sage/topology/simplicial_complex.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Finite simplicial complexes @@ -82,7 +82,8 @@ Simplicial complex with vertex set () and facets {()} sage: X = SimplicialComplex([[0,1], [1,2], [2,3], [3,0]]) sage: X - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1), (0, 3), (1, 2), (2, 3)} + Simplicial complex with vertex set (0, 1, 2, 3) and + facets {(0, 1), (0, 3), (1, 2), (2, 3)} Sage can perform a number of operations on simplicial complexes, such as the join and the product, and it can also compute homology:: @@ -91,7 +92,7 @@ sage: T = S.product(S) # torus sage: T Simplicial complex with 9 vertices and 18 facets - sage: T.homology() # this computes reduced homology + sage: T.homology() # this computes reduced homology # needs sage.modules {0: 0, 1: Z x Z, 2: Z} sage: T.euler_characteristic() 0 @@ -104,8 +105,8 @@ [1, 4, 4] sage: X.face_poset() Finite poset containing 8 elements - sage: x0, x1, x2, x3 = X.stanley_reisner_ring().gens() - sage: x0*x2 == x1*x3 == 0 + sage: x0, x1, x2, x3 = X.stanley_reisner_ring().gens() # needs sage.libs.singular + sage: x0*x2 == x1*x3 == 0 # needs sage.libs.singular True sage: X.is_pure() True @@ -172,12 +173,11 @@ from sage.structure.category_object import normalize_names from sage.misc.latex import latex from sage.misc.superseded import deprecation -from sage.matrix.constructor import matrix -from sage.homology.chain_complex import ChainComplex -from sage.graphs.graph import Graph from functools import total_ordering from itertools import combinations, chain + lazy_import('sage.categories.simplicial_complexes', 'SimplicialComplexes') +lazy_import('sage.matrix.constructor', 'matrix') def lattice_paths(t1, t2, length=None): @@ -895,7 +895,7 @@ class SimplicialComplex(Parent, GenericCellComplex): Cubical complex with 16 vertices and 64 cubes sage: Ts = SimplicialComplex(Tc); Ts Simplicial complex with 16 vertices and 32 facets - sage: Ts.homology() + sage: Ts.homology() # needs sage.modules {0: 0, 1: Z x Z, 2: Z} In the situation where the first argument is a simplicial complex @@ -915,9 +915,9 @@ class SimplicialComplex(Parent, GenericCellComplex): or e.g. the simplicial complex of all 168 hyperovals of the projective plane of order 4:: - sage: l = designs.ProjectiveGeometryDesign(2,1,GF(4,name='a')) + sage: l = designs.ProjectiveGeometryDesign(2, 1, GF(4,name='a')) # needs sage.rings.finite_rings sage: f = lambda S: not any(len(set(S).intersection(x))>2 for x in l) - sage: SimplicialComplex(from_characteristic_function=(f, l.ground_set())) + sage: SimplicialComplex(from_characteristic_function=(f, l.ground_set())) # needs sage.rings.finite_rings Simplicial complex with 21 vertices and 168 facets TESTS: @@ -1002,7 +1002,7 @@ def __init__(self, 3 """ if (maximal_faces is not None and - from_characteristic_function is not None): + from_characteristic_function is not None): raise ValueError("maximal_faces and from_characteristic_function cannot be both defined") category = SimplicialComplexes().Finite().or_subcategory(category) Parent.__init__(self, category=category) @@ -1044,6 +1044,8 @@ def __init__(self, self._is_immutable = False if not is_mutable or is_immutable: self.set_immutable() + self._bbn = C._bbn + self._bbn_all_computed = C._bbn_all_computed return gen_dict = {} @@ -1083,7 +1085,7 @@ def __init__(self, for face in maximal_simplices: # check whether each given face is actually maximal if (maximality_check and - any(face.is_face(other) for other in good_faces)): + any(face.is_face(other) for other in good_faces)): continue # This sorting is crucial for homology computations: face = Simplex(sorted(face.tuple(), key=vertex_to_index.__getitem__)) @@ -1126,6 +1128,14 @@ def __init__(self, if not is_mutable or is_immutable: self.set_immutable() + # self._bbn: a dictionary indexed by base_ring, whose value is a dictionary of + # bigraded Betti numbers, indexed by tuples (-i, 2j). + # For use in the bigraded_betti_numbers method. + self._bbn = {} + # self._bbn_all_computed: a set of base rings for which we called + # bigraded_betti_numbers(base_ring=base_ring) + self._bbn_all_computed = set() + def __hash__(self): """ Compute the hash value of ``self``. @@ -1452,7 +1462,7 @@ def h_vector(self): sage: octa.h_vector() [1, 3, 3, 1] """ - from sage.arith.all import binomial + from sage.arith.misc import binomial d = self.dimension() f = self.f_vector() # indexed starting at 0, since it's a Python list h = [] @@ -1474,6 +1484,7 @@ def g_vector(self): EXAMPLES:: + sage: # needs sage.combinat sage: S3 = simplicial_complexes.Sphere(3).barycentric_subdivision() sage: S3.f_vector() [1, 30, 150, 240, 120] @@ -1573,7 +1584,7 @@ def h_triangle(self): [0, 0, 4], [1, 2, -1, 0]] """ - from sage.arith.all import binomial + from sage.arith.misc import binomial ret = [[0]*(i+1) for i in range(self.dimension() + 2)] f = self.f_triangle() for i, row in enumerate(ret): @@ -1601,14 +1612,14 @@ def F_triangle(self, S): EXAMPLES:: sage: cs = simplicial_complexes.Torus() - sage: cs.F_triangle(cs.facets()[0]) + sage: cs.F_triangle(cs.facets()[0]) # needs sage.combinat F: x^3 + 9*x^2*y + 3*x*y^2 + y^3 + 6*x^2 + 12*x*y + 3*y^2 + 4*x + 3*y + 1 TESTS:: sage: S = SimplicialComplex([]) - sage: S.F_triangle(S.facets()[0]) + sage: S.F_triangle(S.facets()[0]) # needs sage.combinat F: 1 """ x, y = polygens(ZZ, 'x, y') @@ -1626,8 +1637,8 @@ def posi(f): def flip_graph(self): """ - If ``self`` is pure, then it returns the flip graph of ``self``, - otherwise, it returns ``None``. + If ``self`` is pure, return the flip graph of ``self``, + otherwise, return ``None``. The flip graph of a pure simplicial complex is the (undirected) graph with vertices being the facets, such that two facets are joined by @@ -1676,6 +1687,8 @@ def flip_graph(self): 161 """ from collections import defaultdict + from sage.graphs.graph import Graph + if not self.is_pure(): return None d = self.dimension() @@ -1699,7 +1712,7 @@ def flip_graph(self): def is_pseudomanifold(self): """ - Return True if self is a pseudomanifold. + Return True if ``self`` is a pseudomanifold. A pseudomanifold is a simplicial complex with the following properties: @@ -1795,7 +1808,7 @@ def product(self, right, rename_vertices=True, is_mutable=True): sage: T = S.product(S) # torus sage: T Simplicial complex with 9 vertices and 18 facets - sage: T.homology() + sage: T.homology() # needs sage.modules {0: 0, 1: Z x Z, 2: Z} These can get large pretty quickly:: @@ -1824,7 +1837,7 @@ def product(self, right, rename_vertices=True, is_mutable=True): if rename_vertices: d['L' + str(v) + 'R' + str(w)] = V[v] * L + V[w] else: - d[(v,w)] = V[v] * L + V[w] + d[(v, w)] = V[v] * L + V[w] return SimplicialComplex(facets, is_mutable=is_mutable, sort_facets=d) def join(self, right, rename_vertices=True, is_mutable=True): @@ -1858,7 +1871,8 @@ def join(self, right, rename_vertices=True, is_mutable=True): sage: S.join(T) Simplicial complex with vertex set ('L0', 'L1', 'R2', 'R3') and 4 facets sage: S.join(T, rename_vertices=False) - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2), (0, 3), (1, 2), (1, 3)} + Simplicial complex with vertex set (0, 1, 2, 3) + and facets {(0, 2), (0, 3), (1, 2), (1, 3)} The notation '*' may be used, as well:: @@ -1939,7 +1953,7 @@ def suspension(self, n=1, is_mutable=True): sage: S0.suspension() == simplicial_complexes.Sphere(1) True sage: S3 = S0.suspension(3) # the 3-sphere - sage: S3.homology() + sage: S3.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: Z} For pseudomanifolds, the complex constructed here will be @@ -1979,7 +1993,7 @@ def suspension(self, n=1, is_mutable=True): rename_vertices=True) return self.suspension(1, is_mutable).suspension(int(n-1), is_mutable) - def disjoint_union(self, right, rename_vertices=True, is_mutable=True): + def disjoint_union(self, right, rename_vertices=None, is_mutable=True): """ The disjoint union of this simplicial complex with another one. @@ -2000,9 +2014,13 @@ def disjoint_union(self, right, rename_vertices=True, is_mutable=True): sage: S1 = simplicial_complexes.Sphere(1) sage: S2 = simplicial_complexes.Sphere(2) - sage: S1.disjoint_union(S2).homology() + sage: S1.disjoint_union(S2).homology() # needs sage.modules {0: Z, 1: Z, 2: Z} """ + if rename_vertices is not None: + from sage.misc.superseded import deprecation + deprecation(35907, 'the "rename_vertices" argument is deprecated') + facets = [] for f in self._facets: facets.append(tuple(["L" + str(v) for v in f])) @@ -2040,7 +2058,7 @@ def wedge(self, right, rename_vertices=True, is_mutable=True): sage: S1 = simplicial_complexes.Sphere(1) sage: S2 = simplicial_complexes.Sphere(2) - sage: S1.wedge(S2).homology() + sage: S1.wedge(S2).homology() # needs sage.modules {0: 0, 1: Z, 2: Z} """ left_vertices = list(self.vertices()) @@ -2108,11 +2126,11 @@ def chain_complex(self, subcomplex=None, augmented=False, EXAMPLES:: sage: circle = SimplicialComplex([[0,1], [1,2], [0, 2]]) - sage: circle.chain_complex() + sage: circle.chain_complex() # needs sage.modules Chain complex with at most 2 nonzero terms over Integer Ring - sage: circle.chain_complex()._latex_() + sage: circle.chain_complex()._latex_() # needs sage.modules '\\Bold{Z}^{3} \\xrightarrow{d_{1}} \\Bold{Z}^{3}' - sage: circle.chain_complex(base_ring=QQ, augmented=True) + sage: circle.chain_complex(base_ring=QQ, augmented=True) # needs sage.modules Chain complex with at most 3 nonzero terms over Rational Field """ # initialize subcomplex @@ -2217,6 +2235,8 @@ def chain_complex(self, subcomplex=None, augmented=False, current = self._n_cells_sorted(n-1, subcomplex=subcomplex) differentials[n-1] = matrix(base_ring, 0, len(current)) # finally, return the chain complex + from sage.homology.chain_complex import ChainComplex + if cochain: return ChainComplex(data=differentials, degree=1, base_ring=base_ring, check=check) @@ -2301,13 +2321,15 @@ def _homology_(self, dim=None, base_ring=ZZ, subcomplex=None, EXAMPLES:: + sage: # needs sage.modules sage: circle = SimplicialComplex([[0,1], [1,2], [0, 2]]) sage: circle._homology_() {0: 0, 1: Z} sage: sphere = SimplicialComplex([[0,1,2,3]]) sage: sphere.remove_face([0,1,2,3]) sage: sphere - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)} + Simplicial complex with vertex set (0, 1, 2, 3) and + facets {(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)} sage: sphere._homology_() {0: 0, 1: 0, 2: Z} sage: sphere._homology_(reduced=False) @@ -2319,6 +2341,7 @@ def _homology_(self, dim=None, base_ring=ZZ, subcomplex=None, We need an immutable complex to compute homology generators:: + sage: # needs sage.modules sage: sphere.set_immutable() sage: sphere._homology_(generators=True) {0: [], 1: [], 2: [(Z, (0, 1, 2) - (0, 1, 3) + (0, 2, 3) - (1, 2, 3))]} @@ -2327,28 +2350,29 @@ def _homology_(self, dim=None, base_ring=ZZ, subcomplex=None, three-fold join with itself:: sage: S = SimplicialComplex([[0], [1]]) - sage: (S*S*S)._homology_(dim=2, cohomology=True) + sage: (S*S*S)._homology_(dim=2, cohomology=True) # needs sage.modules Z The same computation, done without finding a contractible subcomplex:: - sage: (S*S*S)._homology_(dim=2, cohomology=True, enlarge=False) + sage: (S*S*S)._homology_(dim=2, cohomology=True, enlarge=False) # needs sage.modules Z Relative homology:: sage: T = SimplicialComplex([[0,1,2]]) sage: U = SimplicialComplex([[0,1], [1,2], [0,2]]) - sage: T._homology_(subcomplex=U) + sage: T._homology_(subcomplex=U) # needs sage.modules {0: 0, 1: 0, 2: Z} Generators:: - sage: simplicial_complexes.Torus().homology(generators=True) + sage: simplicial_complexes.Torus().homology(generators=True) # needs sage.modules {0: [], 1: [(Z, (2, 4) - (2, 6) + (4, 6)), (Z, (1, 4) - (1, 6) + (4, 6))], - 2: [(Z, - (0, 1, 2) - (0, 1, 5) + (0, 2, 6) - (0, 3, 4) + (0, 3, 5) - (0, 4, 6) - (1, 2, 4) + (1, 3, 4) - (1, 3, 6) + (1, 5, 6) - (2, 3, 5) + (2, 3, 6) + (2, 4, 5) - (4, 5, 6))]} + 2: [(Z, (0, 1, 2) - (0, 1, 5) + (0, 2, 6) - (0, 3, 4) + (0, 3, 5) + - (0, 4, 6) - (1, 2, 4) + (1, 3, 4) - (1, 3, 6) + (1, 5, 6) + - (2, 3, 5) + (2, 3, 6) + (2, 4, 5) - (4, 5, 6))]} """ from sage.homology.homology_group import HomologyGroup @@ -2479,6 +2503,7 @@ def algebraic_topological_model(self, base_ring=None): EXAMPLES:: + sage: # needs sage.modules sage: RP2 = simplicial_complexes.RealProjectivePlane() sage: phi, M = RP2.algebraic_topological_model(GF(2)) sage: M.homology() @@ -2560,18 +2585,18 @@ def add_face(self, face): Check that the bug reported at :trac:`14354` has been fixed:: sage: T = SimplicialComplex([range(1,5)]).n_skeleton(1) - sage: T.homology() + sage: T.homology() # needs sage.modules {0: 0, 1: Z x Z x Z} sage: T.add_face([1,2,3]) - sage: T.homology() + sage: T.homology() # needs sage.modules {0: 0, 1: Z x Z, 2: 0} Check that the ``_faces`` cache is treated correctly (:trac:`20758`):: sage: T = SimplicialComplex([range(1,5)]).n_skeleton(1) - sage: _ = T.faces() # populate the _faces attribute - sage: _ = T.homology() # add more to _faces + sage: _ = T.faces() # populate the _faces attribute + sage: _ = T.homology() # add more to _faces # needs sage.modules sage: T.add_face((1,2,3)) sage: all(Simplex((1,2,3)) in T._faces[L][2] for L in T._faces) True @@ -2580,10 +2605,10 @@ def add_face(self, face): (:trac:`20758`):: sage: T = SimplicialComplex([range(1,5)]).n_skeleton(1) - sage: T.homology() # to populate the __enlarged attribute + sage: T.homology() # to populate the __enlarged attribute # needs sage.modules {0: 0, 1: Z x Z x Z} sage: T.add_face([1,2,3]) - sage: len(T._SimplicialComplex__enlarged) > 0 + sage: len(T._SimplicialComplex__enlarged) > 0 # needs sage.modules True Check we've fixed the bug reported at :trac:`14578`:: @@ -2592,7 +2617,7 @@ def add_face(self, face): sage: t0.add_face(('a', 'b')) sage: t0.add_face(('c', 'd', 'e')) sage: t0.add_face(('e', 'f', 'c')) - sage: t0.homology() + sage: t0.homology() # needs sage.modules {0: Z, 1: 0, 2: 0} Check that we've fixed the bug reported at :trac:`22880`:: @@ -2659,6 +2684,8 @@ def add_face(self, face): self._graph.add_edge(new_face[i], new_face[j]) self._complex = {} self.__contractible = None + self._bbn = {} + self._bbn_all_computed = set() def remove_face(self, face, check=False): """ @@ -2686,14 +2713,17 @@ def remove_face(self, face, check=False): Simplicial complex with vertex set (1, 2, 3, 4) and facets {(1, 2, 3, 4)} sage: Z.remove_face([1,2]) sage: Z - Simplicial complex with vertex set (1, 2, 3, 4) and facets {(1, 3, 4), (2, 3, 4)} + Simplicial complex with vertex set (1, 2, 3, 4) and + facets {(1, 3, 4), (2, 3, 4)} sage: S = SimplicialComplex([[0,1,2],[2,3]]) sage: S - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(2, 3), (0, 1, 2)} + Simplicial complex with vertex set (0, 1, 2, 3) and + facets {(2, 3), (0, 1, 2)} sage: S.remove_face([0,1,2]) sage: S - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1), (0, 2), (1, 2), (2, 3)} + Simplicial complex with vertex set (0, 1, 2, 3) and + facets {(0, 1), (0, 2), (1, 2), (2, 3)} TESTS: @@ -2701,11 +2731,11 @@ def remove_face(self, face, check=False): :trac:`20758`:: sage: T = SimplicialComplex([range(1,5)]).n_skeleton(1) - sage: _ = T.faces() # populate the _faces attribute - sage: _ = T.homology() # add more to _faces + sage: _ = T.faces() # populate the _faces attribute + sage: _ = T.homology() # add more to _faces # needs sage.modules sage: T.add_face((1,2,3)) sage: T.remove_face((1,2,3)) - sage: len(T._faces) + sage: len(T._faces) # needs sage.modules 2 sage: T.remove_face((1,2)) sage: len(T._faces) @@ -2783,6 +2813,8 @@ def remove_face(self, face, check=False): self._complex = {} self.__contractible = None self.__enlarged = {} + self._bbn = {} + self._bbn_all_computed = set() def remove_faces(self, faces, check=False): """ @@ -2889,7 +2921,7 @@ def connected_sum(self, other, is_mutable=True): EXAMPLES:: sage: S1 = simplicial_complexes.Sphere(1) - sage: S1.connected_sum(S1.connected_sum(S1)).homology() + sage: S1.connected_sum(S1.connected_sum(S1)).homology() # needs sage.modules {0: 0, 1: Z} sage: P = simplicial_complexes.RealProjectivePlane(); P Minimal triangulation of the real projective plane @@ -2900,7 +2932,7 @@ def connected_sum(self, other, is_mutable=True): sage: P + P # the Klein bottle Simplicial complex with 9 vertices and 18 facets - sage: (P + P).homology()[1] + sage: (P + P).homology()[1] # needs sage.modules Z x C2 """ if not (self.is_pure() and other.is_pure() and @@ -3010,23 +3042,23 @@ def is_cohen_macaulay(self, base_ring=QQ, ncpus=0): Spheres are Cohen-Macaulay:: sage: S = SimplicialComplex([[1,2],[2,3],[3,1]]) - sage: S.is_cohen_macaulay(ncpus=3) + sage: S.is_cohen_macaulay(ncpus=3) # needs sage.modules True The following example is taken from Bruns, Herzog - Cohen-Macaulay rings, Figure 5.3:: sage: S = SimplicialComplex([[1,2,3],[1,4,5]]) - sage: S.is_cohen_macaulay(ncpus=3) + sage: S.is_cohen_macaulay(ncpus=3) # needs sage.modules False The choice of base ring can matter. The real projective plane `\RR P^2` has `H_1(\RR P^2) = \ZZ/2`, hence is CM over `\QQ` but not over `\ZZ`. :: sage: X = simplicial_complexes.RealProjectivePlane() - sage: X.is_cohen_macaulay() + sage: X.is_cohen_macaulay() # needs sage.modules True - sage: X.is_cohen_macaulay(ZZ) + sage: X.is_cohen_macaulay(ZZ) # needs sage.modules False """ from sage.parallel.decorate import parallel @@ -3035,9 +3067,9 @@ def is_cohen_macaulay(self, base_ring=QQ, ncpus=0): from sage.parallel.ncpus import ncpus as get_ncpus ncpus = get_ncpus() - facs = [ x for x in self.face_iterator() ] + facs = [x for x in self.face_iterator()] n = len(facs) - facs_divided = [ [] for i in range(ncpus) ] + facs_divided = [[] for i in range(ncpus)] for i in range(n): facs_divided[i % ncpus].append(facs[i]) @@ -3045,15 +3077,15 @@ def all_homologies_vanish(F): S = self.link(F) H = S.homology(base_ring=base_ring) if base_ring.is_field(): - return all( H[j].dimension() == 0 for j in range(S.dimension()) ) + return all(H[j].dimension() == 0 for j in range(S.dimension())) else: - return not any( H[j].invariants() for j in range(S.dimension()) ) + return not any(H[j].invariants() for j in range(S.dimension())) @parallel(ncpus=ncpus) def all_homologies_in_list_vanish(Fs): - return all( all_homologies_vanish(F) for F in Fs ) + return all(all_homologies_vanish(F) for F in Fs) - return all( answer[1] for answer in all_homologies_in_list_vanish(facs_divided) ) + return all(answer[1] for answer in all_homologies_in_list_vanish(facs_divided)) def generated_subcomplex(self, sub_vertex_set, is_mutable=True): """ @@ -3252,7 +3284,7 @@ def is_shellable(self, certificate=False): cur_complex.add_face(F) cur_order.append(F) facets.remove(F) - it.append(iter(set(facets))) # Iterate over a copy of the current facets + it.append(iter(set(facets))) # Iterate over a copy of the current facets return tuple(cur_order) @@ -3532,7 +3564,8 @@ def stanley_reisner_ring(self, base_ring=ZZ): sage: X = SimplicialComplex([[0,1,2], [0,2,3]]) sage: X.stanley_reisner_ring() - Quotient of Multivariate Polynomial Ring in x0, x1, x2, x3 over Integer Ring by the ideal (x1*x3) + Quotient of Multivariate Polynomial Ring in x0, x1, x2, x3 over Integer Ring + by the ideal (x1*x3) sage: Y = SimplicialComplex([[0,1,2,3,4]]); Y Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 2, 3, 4)} sage: Y.add_face([0,1,2,3,4]) @@ -3563,7 +3596,8 @@ def alexander_dual(self, is_mutable=True): EXAMPLES:: sage: Y = SimplicialComplex([[i] for i in range(5)]); Y - Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0,), (1,), (2,), (3,), (4,)} + Simplicial complex with vertex set (0, 1, 2, 3, 4) and + facets {(0,), (1,), (2,), (3,), (4,)} sage: Y.alexander_dual() Simplicial complex with vertex set (0, 1, 2, 3, 4) and 10 facets sage: X = SimplicialComplex([[0,1], [1,2], [2,3], [3,0]]) @@ -3583,18 +3617,16 @@ def barycentric_subdivision(self): EXAMPLES:: sage: triangle = SimplicialComplex([[0,1], [1,2], [0, 2]]) - sage: hexagon = triangle.barycentric_subdivision() - sage: hexagon + sage: hexagon = triangle.barycentric_subdivision(); hexagon Simplicial complex with 6 vertices and 6 facets - sage: hexagon.homology(1) == triangle.homology(1) + sage: hexagon.homology(1) == triangle.homology(1) # needs sage.modules True Barycentric subdivisions can get quite large, since each `n`-dimensional facet in the original complex produces `(n+1)!` facets in the subdivision:: - sage: S4 = simplicial_complexes.Sphere(4) - sage: S4 + sage: S4 = simplicial_complexes.Sphere(4); S4 Minimal triangulation of the 4-sphere sage: S4.barycentric_subdivision() Simplicial complex with 62 vertices and 720 facets @@ -3629,13 +3661,17 @@ def stellar_subdivision(self, simplex, inplace=False, is_mutable=True): sage: F2 = Simplex([1,3]) sage: F3 = Simplex([1,2,3]) sage: SC.stellar_subdivision(F1) - Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 4), (0, 2, 4), (1, 3, 4), (2, 3, 4)} + Simplicial complex with vertex set (0, 1, 2, 3, 4) and + facets {(0, 1, 4), (0, 2, 4), (1, 3, 4), (2, 3, 4)} sage: SC.stellar_subdivision(F2) - Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 2), (1, 2, 4), (2, 3, 4)} + Simplicial complex with vertex set (0, 1, 2, 3, 4) and + facets {(0, 1, 2), (1, 2, 4), (2, 3, 4)} sage: SC.stellar_subdivision(F3) - Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 2), (1, 2, 4), (1, 3, 4), (2, 3, 4)} + Simplicial complex with vertex set (0, 1, 2, 3, 4) and + facets {(0, 1, 2), (1, 2, 4), (1, 3, 4), (2, 3, 4)} sage: SC.stellar_subdivision(F3, inplace=True);SC - Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 2), (1, 2, 4), (1, 3, 4), (2, 3, 4)} + Simplicial complex with vertex set (0, 1, 2, 3, 4) and + facets {(0, 1, 2), (1, 2, 4), (1, 3, 4), (2, 3, 4)} The simplex to subdivide should be a face of self:: @@ -3705,6 +3741,8 @@ def graph(self): [(0, 1, None), (0, 2, None), (0, 3, None), (1, 2, None), (1, 3, None), (2, 3, None)] """ if self._graph is None: + from sage.graphs.graph import Graph + edges = self.n_cells(1) vertices = [min(f) for f in self._facets if f.dimension() == 0] used_vertices = [] # vertices which are in an edge @@ -3745,7 +3783,7 @@ def delta_complex(self, sort_simplices=False): sage: Td = T.delta_complex() sage: Td Delta complex with 7 vertices and 43 simplices - sage: T.homology() == Td.homology() + sage: T.homology() == Td.homology() # needs sage.modules True """ from .delta_complex import DeltaComplex @@ -3774,10 +3812,10 @@ def is_flag_complex(self): EXAMPLES:: - sage: h = Graph({0:[1,2,3,4],1:[2,3,4],2:[3]}) - sage: x = h.clique_complex() - sage: x - Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 4), (0, 1, 2, 3)} + sage: h = Graph({0: [1,2,3,4], 1: [2,3,4], 2: [3]}) + sage: x = h.clique_complex(); x + Simplicial complex with vertex set (0, 1, 2, 3, 4) + and facets {(0, 1, 4), (0, 1, 2, 3)} sage: x.is_flag_complex() True @@ -3800,12 +3838,15 @@ def n_skeleton(self, n): sage: X = SimplicialComplex([[0,1], [1,2,3], [0,2,3]]) sage: X.n_skeleton(1) - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)} + Simplicial complex with vertex set (0, 1, 2, 3) and + facets {(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)} sage: X.set_immutable() sage: X.n_skeleton(2) - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1), (0, 2, 3), (1, 2, 3)} + Simplicial complex with vertex set (0, 1, 2, 3) and + facets {(0, 1), (0, 2, 3), (1, 2, 3)} sage: X.n_skeleton(4) - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1), (0, 2, 3), (1, 2, 3)} + Simplicial complex with vertex set (0, 1, 2, 3) and + facets {(0, 1), (0, 2, 3), (1, 2, 3)} """ if n >= self.dimension(): return self @@ -3845,10 +3886,12 @@ def _contractible_subcomplex(self, verbose=False): sage: sphere = SimplicialComplex([[0,1,2,3]]) sage: sphere.remove_face([0,1,2,3]) sage: sphere - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)} + Simplicial complex with vertex set (0, 1, 2, 3) and + facets {(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)} sage: L = sphere._contractible_subcomplex(); L - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2), (0, 1, 3), (0, 2, 3)} - sage: L.homology() + Simplicial complex with vertex set (0, 1, 2, 3) and + facets {(0, 1, 2), (0, 1, 3), (0, 2, 3)} + sage: L.homology() # needs sage.modules {0: 0, 1: 0, 2: 0} """ facets = [sorted(self._facets, key=str)[0]] @@ -3884,14 +3927,14 @@ def _enlarge_subcomplex(self, subcomplex, verbose=False): Inside the torus, define a subcomplex consisting of a loop:: sage: S = SimplicialComplex([[0,1], [1,2], [0,2]], is_mutable=False) - sage: S.homology() + sage: S.homology() # needs sage.modules {0: 0, 1: Z} sage: L = T._enlarge_subcomplex(S) sage: L Simplicial complex with vertex set (0, 1, 2, 3, 4, 5, 6) and 8 facets sage: sorted(L.facets()) [(0, 1), (0, 1, 5), (0, 2), (0, 2, 6), (0, 3, 4), (0, 3, 5), (0, 4, 6), (1, 2)] - sage: L.homology()[1] + sage: L.homology()[1] # needs sage.modules Z """ # Make the subcomplex immutable if not @@ -3911,14 +3954,14 @@ def _enlarge_subcomplex(self, subcomplex, verbose=False): done = True remove_these = [] if verbose: - print(" looping through %s facets" % len(faces)) + print(f" looping through {len(faces)} facets") for f in faces: f_set = f.set() - int_facets = set( a.set().intersection(f_set) for a in new_facets ) + int_facets = set(a.set().intersection(f_set) for a in new_facets) intersection = SimplicialComplex(int_facets) if not intersection._facets[0].is_empty(): if (len(intersection._facets) == 1 or - intersection == intersection._contractible_subcomplex()): + intersection == intersection._contractible_subcomplex()): new_facets.append(f) remove_these.append(f) done = False @@ -3973,12 +4016,12 @@ def _cubical_(self): EXAMPLES:: sage: T = simplicial_complexes.Torus() - sage: T.homology() + sage: T.homology() # needs sage.modules {0: 0, 1: Z x Z, 2: Z} sage: Tc = T._cubical_() sage: Tc Cubical complex with 42 vertices and 168 cubes - sage: Tc.homology() + sage: Tc.homology() # needs sage.modules {0: 0, 1: Z x Z, 2: Z} """ from .cubical_complex import CubicalComplex @@ -4020,7 +4063,9 @@ def connected_component(self, simplex=None): sage: X = S1.disjoint_union(S1) sage: X == X.connected_component() False - sage: X.connected_component(Simplex(['L0'])) == X.connected_component(Simplex(['R0'])) + sage: CL0 = X.connected_component(Simplex(['L0'])) + sage: CR0 = X.connected_component(Simplex(['R0'])) + sage: CL0 == CR0 False sage: S0 = simplicial_complexes.Sphere(0) @@ -4042,7 +4087,7 @@ def connected_component(self, simplex=None): v = self.vertices()[0] else: v = simplex[0] - vertices = self.graph().connected_component_containing_vertex(v) + vertices = self.graph().connected_component_containing_vertex(v, sort=False) facets = [f for f in self.facets() if f.is_face(Simplex(vertices))] return SimplicialComplex(facets) @@ -4075,7 +4120,7 @@ def fundamental_group(self, base_point=None, simplify=True): EXAMPLES:: sage: S1 = simplicial_complexes.Sphere(1) - sage: S1.fundamental_group() + sage: S1.fundamental_group() # needs sage.groups Finitely presented group < e | > If we pass the argument ``simplify=False``, we get generators and @@ -4083,21 +4128,22 @@ def fundamental_group(self, base_point=None, simplify=True): cyclic group of order 2, for instance:: sage: RP2 = simplicial_complexes.RealProjectiveSpace(2) - sage: C2 = RP2.fundamental_group(simplify=False) - sage: C2 - Finitely presented group < e0, e1, e2, e3, e4, e5, e6, e7, e8, e9 | e0, e3, e4, e7, e9, e5*e2^-1*e0, e7*e2^-1*e1, e8*e3^-1*e1, e8*e6^-1*e4, e9*e6^-1*e5 > - sage: C2.simplified() + sage: C2 = RP2.fundamental_group(simplify=False); C2 # needs sage.groups + Finitely presented group < e0, e1, e2, e3, e4, e5, e6, e7, e8, e9 | e0, e3, + e4, e7, e9, e5*e2^-1*e0, e7*e2^-1*e1, e8*e3^-1*e1, e8*e6^-1*e4, e9*e6^-1*e5 > + sage: C2.simplified() # needs sage.groups Finitely presented group < e1 | e1^2 > This is the same answer given if the argument ``simplify`` is True (the default):: - sage: RP2.fundamental_group() + sage: RP2.fundamental_group() # needs sage.groups Finitely presented group < e1 | e1^2 > You must specify a base point to compute the fundamental group of a non-connected complex:: + sage: # needs sage.groups sage: K = S1.disjoint_union(RP2) sage: K.fundamental_group() Traceback (most recent call last): @@ -4110,11 +4156,12 @@ def fundamental_group(self, base_point=None, simplify=True): Some other examples:: - sage: S1.wedge(S1).fundamental_group() + sage: S1.wedge(S1).fundamental_group() # needs sage.groups Finitely presented group < e0, e1 | > - sage: simplicial_complexes.Torus().fundamental_group() + sage: simplicial_complexes.Torus().fundamental_group() # needs sage.groups Finitely presented group < e1, e4 | e4^-1*e1^-1*e4*e1 > + sage: # needs sage.groups sage: G = simplicial_complexes.MooreSpace(5).fundamental_group() sage: G.ngens() 1 @@ -4130,29 +4177,16 @@ def fundamental_group(self, base_point=None, simplify=True): from sage.groups.free_group import FreeGroup from sage.libs.gap.libgap import libgap as gap G = self.graph() - # If the vertices and edges of G are not sortable, e.g., a mix - # of str and int, Sage+Python 3 may raise a TypeError when - # trying to find the spanning tree. So create a graph - # isomorphic to G but with sortable vertices. Use a copy of G, - # because self.graph() is cached, and relabeling its vertices - # would relabel the cached version. - int_to_v = dict(enumerate(G.vertex_iterator())) - v_to_int = {v: i for i, v in int_to_v.items()} - G2 = G.copy(immutable=False) - G2.relabel(v_to_int) - spanning_tree = G2.min_spanning_tree() - gens = [(int_to_v[e[0]], int_to_v[e[1]]) - for e in G2.edges(sort=True) - if e not in spanning_tree] - if len(gens) == 0: - return gap.TrivialGroup() - # Edges in the graph may be sorted differently than in the # simplicial complex, so convert the edges to frozensets so we # don't have to worry about it. Convert spanning_tree to a set # to make lookup faster. - spanning_tree = set(frozenset((int_to_v[e[0]], int_to_v[e[1]])) - for e in spanning_tree) + spanning_tree = set(frozenset((u, v)) for u, v, _ in G.min_spanning_tree()) + gens = [e for e in G.edge_iterator(labels=False) + if frozenset(e) not in spanning_tree] + if not gens: + return gap.TrivialGroup() + gens_dict = {frozenset(g): i for i, g in enumerate(gens)} FG = FreeGroup(len(gens), 'e') rels = [] @@ -4161,7 +4195,7 @@ def fundamental_group(self, base_point=None, simplify=True): z = dict() for i in range(3): x = frozenset(bdry[i]) - if (x in spanning_tree): + if x in spanning_tree: z[i] = FG.one() else: z[i] = FG.gen(gens_dict[x]) @@ -4205,8 +4239,11 @@ def is_isomorphic(self, other, certificate=False): # Check easy invariants agree if (sorted(x.dimension() for x in self._facets) != sorted(x.dimension() for x in other._facets) - or len(self.vertices()) != len(other.vertices())): + or len(self.vertices()) != len(other.vertices())): return False + + from sage.graphs.graph import Graph + g1 = Graph() g2 = Graph() # With Python 3, "is_isomorphic" for graphs works best if the @@ -4252,27 +4289,28 @@ def automorphism_group(self): EXAMPLES:: sage: S = simplicial_complexes.Simplex(3) - sage: S.automorphism_group().is_isomorphic(SymmetricGroup(4)) + sage: S.automorphism_group().is_isomorphic(SymmetricGroup(4)) # needs sage.groups True sage: P = simplicial_complexes.RealProjectivePlane() - sage: P.automorphism_group().is_isomorphic(AlternatingGroup(5)) + sage: P.automorphism_group().is_isomorphic(AlternatingGroup(5)) # needs sage.groups True sage: Z = SimplicialComplex([['1','2'],['2','3','a']]) - sage: Z.automorphism_group().is_isomorphic(CyclicPermutationGroup(2)) + sage: Z.automorphism_group().is_isomorphic(CyclicPermutationGroup(2)) # needs sage.groups True - sage: group = Z.automorphism_group() - sage: sorted(group.domain()) + sage: group = Z.automorphism_group() # needs sage.groups + sage: sorted(group.domain()) # needs sage.groups ['1', '2', '3', 'a'] Check that :trac:`17032` is fixed:: sage: s = SimplicialComplex([[(0,1),(2,3)]]) - sage: s.automorphism_group().cardinality() + sage: s.automorphism_group().cardinality() # needs sage.groups 2 """ from sage.groups.perm_gps.permgroup import PermutationGroup + from sage.graphs.graph import Graph G = Graph() G.add_vertices(self.vertices()) @@ -4309,26 +4347,25 @@ def fixed_complex(self, G): sage: S4 = simplicial_complexes.Sphere(4) sage: S3 = simplicial_complexes.Sphere(3) - sage: fix = S4.fixed_complex([S4.automorphism_group()([(0,1)])]) - sage: fix + sage: fix = S4.fixed_complex([S4.automorphism_group()([(0,1)])]); fix # needs sage.groups Simplicial complex with vertex set (0, 2, 3, 4, 5) and 5 facets - sage: fix.is_isomorphic(S3) + sage: fix.is_isomorphic(S3) # needs sage.groups True Another simple example:: sage: T = SimplicialComplex([[1,2,3],[2,3,4]]) - sage: G = T.automorphism_group() - sage: T.fixed_complex([G([(1,4)])]) + sage: G = T.automorphism_group() # needs sage.groups + sage: T.fixed_complex([G([(1,4)])]) # needs sage.groups Simplicial complex with vertex set (2, 3) and facets {(2, 3)} A more sophisticated example:: sage: RP2 = simplicial_complexes.ProjectivePlane() sage: CP2 = simplicial_complexes.ComplexProjectivePlane() - sage: G = CP2.automorphism_group() - sage: H = G.subgroup([G([(2,3),(5,6),(8,9)])]) - sage: CP2.fixed_complex(H).is_isomorphic(RP2) + sage: G = CP2.automorphism_group() # needs sage.groups + sage: H = G.subgroup([G([(2,3),(5,6),(8,9)])]) # needs sage.groups + sage: CP2.fixed_complex(H).is_isomorphic(RP2) # needs sage.groups True """ from sage.categories.groups import Groups @@ -4621,7 +4658,8 @@ def decone(self): sage: SimplicialComplex([[1,2,3]]).decone() Simplicial complex with vertex set () and facets {()} sage: SimplicialComplex([[1,2,3], [1,3,4], [1,5,6]]).decone() - Simplicial complex with vertex set (2, 3, 4, 5, 6) and facets {(2, 3), (3, 4), (5, 6)} + Simplicial complex with vertex set (2, 3, 4, 5, 6) + and facets {(2, 3), (3, 4), (5, 6)} sage: X = SimplicialComplex([[1,2,3], [1,3,4], [2,5,6]]) sage: X.decone() == X True @@ -4653,18 +4691,18 @@ def is_balanced(self, check_purity=False, certificate=False): A 1-dim simplicial complex is balanced iff it is bipartite:: - sage: X = SimplicialComplex([[1,2],[1,4],[3,4],[2,5]]) + sage: X = SimplicialComplex([[1,2], [1,4], [3,4], [2,5]]) sage: X.is_balanced() True sage: sorted(X.is_balanced(certificate=True)) [[1, 3, 5], [2, 4]] - sage: X = SimplicialComplex([[1,2],[1,4],[3,4],[2,4]]) + sage: X = SimplicialComplex([[1,2], [1,4], [3,4], [2,4]]) sage: X.is_balanced() False Any barycentric division is balanced:: - sage: X = SimplicialComplex([[1,2,3],[1,2,4],[2,3,4]]) + sage: X = SimplicialComplex([[1,2,3], [1,2,4], [2,3,4]]) sage: X.is_balanced() False sage: X.barycentric_subdivision().is_balanced() @@ -4672,7 +4710,7 @@ def is_balanced(self, check_purity=False, certificate=False): A non-pure balanced complex:: - sage: X=SimplicialComplex([[1,2,3],[3,4]]) + sage: X = SimplicialComplex([[1,2,3], [3,4]]) sage: X.is_balanced(check_purity=True) False sage: sorted(X.is_balanced(certificate=True)) @@ -4730,32 +4768,37 @@ def is_partitionable(self, certificate=False, Simplices are trivially partitionable:: - sage: X = SimplicialComplex([ [1,2,3,4] ]) - sage: X.is_partitionable() + sage: X = SimplicialComplex([[1,2,3,4]]) + sage: X.is_partitionable() # needs sage.numerical.mip True - sage: X.is_partitionable(certificate=True) + sage: X.is_partitionable(certificate=True) # needs sage.numerical.mip [((), (1, 2, 3, 4), 4)] Shellable complexes are partitionable:: - sage: X = SimplicialComplex([ [1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5] ]) + sage: # needs sage.numerical.mip + sage: X = SimplicialComplex([[1,3,5], [1,3,6], [1,4,5], [1,4,6], + ....: [2,3,5], [2,3,6], [2,4,5]]) sage: X.is_partitionable() True sage: P = X.is_partitionable(certificate=True) - sage: n_intervals_containing = lambda f: len([ RF for RF in P if RF[0].is_face(f) and f.is_face(RF[1]) ]) - sage: all( n_intervals_containing(f)==1 for k in X.faces().keys() for f in X.faces()[k] ) + sage: def n_intervals_containing(f): + ....: return len([RF for RF in P + ....: if RF[0].is_face(f) and f.is_face(RF[1])]) + sage: all(n_intervals_containing(f) == 1 + ....: for k in X.faces().keys() for f in X.faces()[k]) True A non-shellable, non-Cohen-Macaulay, partitionable example, constructed by Bjรถrner:: - sage: X = SimplicialComplex([ [1,2,3],[1,2,4],[1,3,4],[2,3,4],[1,5,6] ]) - sage: X.is_partitionable() + sage: X = SimplicialComplex([[1,2,3], [1,2,4], [1,3,4], [2,3,4], [1,5,6]]) + sage: X.is_partitionable() # needs sage.numerical.mip True The bowtie complex is not partitionable:: - sage: X = SimplicialComplex([ [1,2,3],[1,4,5] ]) - sage: X.is_partitionable() + sage: X = SimplicialComplex([[1,2,3], [1,4,5]]) + sage: X.is_partitionable() # needs sage.numerical.mip False """ from sage.numerical.mip import MixedIntegerLinearProgram @@ -4785,9 +4828,9 @@ def intersection(self, other): EXAMPLES:: - sage: X = SimplicialComplex([[1,2,3],[1,2,4]]) - sage: Y = SimplicialComplex([[1,2,3],[1,4,5]]) - sage: Z = SimplicialComplex([[1,2,3],[1,4],[2,4]]) + sage: X = SimplicialComplex([[1,2,3], [1,2,4]]) + sage: Y = SimplicialComplex([[1,2,3], [1,4,5]]) + sage: Z = SimplicialComplex([[1,2,3], [1,4], [2,4]]) sage: sorted(X.intersection(Y).facets()) [(1, 2, 3), (1, 4)] sage: X.intersection(X) == X @@ -4802,6 +4845,281 @@ def intersection(self, other): F = F + [s for s in self.faces()[k] if s in other.faces()[k]] return SimplicialComplex(F) + def bigraded_betti_numbers(self, base_ring=ZZ, verbose=False): + r""" + Return a dictionary of the bigraded Betti numbers of ``self``, + with keys `(-a, 2b)`. + + INPUT: + + - ``base_ring`` -- (default: ``ZZ``) the base ring used + when computing homology + - ``verbose`` -- (default: ``False``) if ``True``, print + messages during the computation, which indicate in which + subcomplexes non-trivial homologies appear + + .. NOTE:: + + If ``verbose`` is ``True``, then caching is avoided. + + .. SEEALSO:: + + See :meth:`bigraded_betti_number` for more information. + + EXAMPLES:: + + sage: X = SimplicialComplex([[0,1],[1,2],[1,3],[2,3]]) + sage: Y = SimplicialComplex([[1,2,3],[1,2,4],[3,5],[4,5]]) + sage: sorted(X.bigraded_betti_numbers(base_ring=QQ).items(), reverse=True) + [((0, 0), 1), ((-1, 6), 1), ((-1, 4), 2), ((-2, 8), 1), ((-2, 6), 1)] + sage: sorted(Y.bigraded_betti_numbers(verbose=True).items(), reverse=True) + (-1, 4): Non-trivial homology Z in dimension 0 of the full + subcomplex generated by a set of vertices (1, 5) + (-1, 4): Non-trivial homology Z in dimension 0 of the full + subcomplex generated by a set of vertices (2, 5) + (-1, 4): Non-trivial homology Z in dimension 0 of the full + subcomplex generated by a set of vertices (3, 4) + (-2, 6): Non-trivial homology Z in dimension 0 of the full + subcomplex generated by a set of vertices (1, 2, 5) + (-2, 8): Non-trivial homology Z in dimension 1 of the full + subcomplex generated by a set of vertices (1, 3, 4, 5) + (-2, 8): Non-trivial homology Z in dimension 1 of the full + subcomplex generated by a set of vertices (2, 3, 4, 5) + (-3, 10): Non-trivial homology Z in dimension 1 of the full + subcomplex generated by a set of vertices (1, 2, 3, 4, 5) + [((0, 0), 1), ((-1, 4), 3), ((-2, 8), 2), ((-2, 6), 1), ((-3, 10), 1)] + + If we wish to view them in a form of a table, it is + simple enough to create a function as such:: + + sage: def print_table(bbns): + ....: max_a = max(-p[0] for p in bbns) + ....: max_b = max(p[1] for p in bbns) + ....: bbn_table = [[bbns.get((-a,b), 0) for a in range(max_a+1)] + ....: for b in range(max_b+1)] + ....: width = len(str(max(bbns.values()))) + 1 + ....: print(' '*width, end=' ') + ....: for i in range(max_a+1): + ....: print(f'{-i:{width}}', end=' ') + ....: print() + ....: for j in range(len(bbn_table)): + ....: print(f'{j:{width}}', end=' ') + ....: for r in bbn_table[j]: + ....: print(f'{r:{width}}', end=' ') + ....: print() + sage: print_table(X.bigraded_betti_numbers()) + 0 -1 -2 + 0 1 0 0 + 1 0 0 0 + 2 0 0 0 + 3 0 0 0 + 4 0 2 0 + 5 0 0 0 + 6 0 1 1 + 7 0 0 0 + 8 0 0 1 + """ + if base_ring in self._bbn_all_computed and not verbose: + return self._bbn[base_ring] + + from sage.homology.homology_group import HomologyGroup + L = self.vertices() + n = len(L) + B = {} + H0 = HomologyGroup(0, base_ring) + + B[(0, 0)] = ZZ.one() + + for j in range(n+1): + for x in combinations(L, j): + S = self.generated_subcomplex(x) + H = S.homology(base_ring=base_ring) + for k in range(j): + if j-k-1 in H and H[j-k-1] != H0: + ind = (-k, 2*j) + if ind not in B: + B[ind] = ZZ.zero() + B[ind] += len(H[j-k-1].gens()) + if verbose: + print("{}: Non-trivial homology {} in dimension {} of the full subcomplex generated by a set of vertices {}".format(ind, H[j-k-1], j-k-1, x)) + + self._bbn[base_ring] = B + self._bbn_all_computed.add(base_ring) + + return B + + def bigraded_betti_number(self, a, b, base_ring=ZZ, verbose=False): + r""" + Return the bigraded Betti number indexed in the form `(-a, 2b)`. + + Bigraded Betti number with indices `(-a, 2b)` is defined as a + sum of ranks of `(b-a-1)`-th (co)homologies of full subcomplexes + with exactly `b` vertices. + + INPUT: + + - ``base_ring`` -- (default: ``ZZ``) the base ring used + when computing homology + - ``verbose`` -- (default: ``False``) if ``True``, print + messages during the computation, which indicate in which + subcomplexes non-trivial homologies appear + + .. NOTE:: + + If ``verbose`` is ``True``, then caching is avoided. + + EXAMPLES:: + + sage: # needs sage.modules + sage: X = SimplicialComplex([[0,1],[1,2],[2,0],[1,3]]) + sage: X.bigraded_betti_number(-1, 4, base_ring=QQ) + 2 + sage: X.bigraded_betti_number(-1, 8) + 0 + sage: X.bigraded_betti_number(-2, 5) + 0 + sage: X.bigraded_betti_number(0, 0) + 1 + sage: sorted(X.bigraded_betti_numbers().items(), reverse=True) + [((0, 0), 1), ((-1, 6), 1), ((-1, 4), 2), ((-2, 8), 1), ((-2, 6), 1)] + sage: X.bigraded_betti_number(-1, 4, base_ring=QQ) + 2 + sage: X.bigraded_betti_number(-1, 8) + 0 + sage: Y = SimplicialComplex([[1,2,3],[1,2,4],[3,5],[4,5]]) + sage: Y.bigraded_betti_number(-1, 4, verbose=True) + Non-trivial homology Z in dimension 0 of the full subcomplex + generated by a set of vertices (1, 5) + Non-trivial homology Z in dimension 0 of the full subcomplex + generated by a set of vertices (2, 5) + Non-trivial homology Z in dimension 0 of the full subcomplex + generated by a set of vertices (3, 4) + 3 + """ + if b % 2: + return ZZ.zero() + if a == 0 and b == 0: + return ZZ.one() + if base_ring in self._bbn and not verbose: + if base_ring in self._bbn_all_computed: + return self._bbn[base_ring].get((a, b), ZZ.zero()) + elif (a, b) in self._bbn[base_ring]: + return self._bbn[base_ring][a, b] + + from sage.homology.homology_group import HomologyGroup + + b //= 2 + L = self.vertices() + H0 = HomologyGroup(0, base_ring) + + B = 0 + + for x in combinations(L, b): + S = self.generated_subcomplex(x) + H = S.homology(base_ring=base_ring) + if b+a-1 in H and H[b+a-1] != H0: + B += len(H[b+a-1].gens()) + if verbose: + print("Non-trivial homology {} in dimension {} of the full subcomplex generated by a set of vertices {}".format(H[b+a-1], b+a-1, x)) + + B = ZZ(B) + + if base_ring in self._bbn: + self._bbn[base_ring][(a, 2*b)] = B + else: + self._bbn[base_ring] = {(a, 2*b): B} + + return B + + def is_golod(self) -> bool: + r""" + Return whether ``self`` is Golod. + + A simplicial complex is Golod if multiplication and all higher + Massey operations in the associated Tor-algebra are trivial. This + is done by checking the bigraded Betti numbers. + + EXAMPLES:: + + sage: # needs sage.modules + sage: X = SimplicialComplex([[0,1],[1,2],[2,3],[3,0]]) + sage: Y = SimplicialComplex([[0,1,2],[0,2],[0,4]]) + sage: X.is_golod() + False + sage: Y.is_golod() + True + """ + H = list(a+b for (a, b) in self.bigraded_betti_numbers()) + if 0 in H: + H.remove(0) + + return not any(i+j in H for ii, i in enumerate(H) for j in H[ii:]) + + def is_minimally_non_golod(self) -> bool: + r""" + Return whether ``self`` is minimally non-Golod. + + If a simplicial complex itself is not Golod, but deleting any vertex + gives us a full subcomplex that is Golod, then we say that a simplicial + complex is minimally non-Golod. + + .. SEEALSO:: + + See :meth:`is_golod` for more information. + + EXAMPLES:: + + sage: # needs sage.modules + sage: X = SimplicialComplex([[0,1],[1,2],[2,3],[3,0]]) + sage: Y = SimplicialComplex([[1,2,3],[1,2,4],[3,5],[4,5]]) + sage: X.is_golod() + False + sage: X.is_minimally_non_golod() + True + sage: Y.is_golod() + False + sage: Y.is_minimally_non_golod() + False + """ + def test(v): + X = copy(self) + X.remove_face([v]) + return X.is_golod() + + return not self.is_golod() and all(test(v) for v in self.vertices()) + + def moment_angle_complex(self): + """ + Return the moment-angle complex of ``self``. + + A moment-angle complex is a topological space created + from this simplicial complex, which holds a lot of + information about the simplicial complex itself. + + .. SEEALSO:: + + See :mod:`sage.topology.moment_angle_complex` for + more information on moment-angle complexes. + + EXAMPLES:: + + sage: X = SimplicialComplex([[0,1,2,3], [1,4], [3,2,4]]) + sage: X.moment_angle_complex() + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2, 3, 4) and facets {(1, 4), (2, 3, 4), (0, 1, 2, 3)} + sage: K = simplicial_complexes.KleinBottle() + sage: K.moment_angle_complex() + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2, 3, 4, 5, 6, 7) and 16 facets + + We can also create it explicitly:: + + sage: Z = MomentAngleComplex(K); Z + Moment-angle complex of Simplicial complex with vertex set + (0, 1, 2, 3, 4, 5, 6, 7) and 16 facets + """ + from .moment_angle_complex import MomentAngleComplex + return MomentAngleComplex(self) # Miscellaneous utility functions. @@ -4868,7 +5186,8 @@ def facets_for_K3(): True """ from sage.groups.perm_gps.permgroup import PermutationGroup - G = PermutationGroup([[(1,3,8,4,9,16,15,2,14,12,6,7,13,5,10)], - [(1,11,16),(2,10,14),(3,12,13),(4,9,15),(5,7,8)]]) - return ([tuple([g(i) for i in (1,2,3,8,12)]) for g in G] - + [tuple([g(i) for i in (1,2,5,8,14)]) for g in G]) + G = PermutationGroup([[(1, 3, 8, 4, 9, 16, 15, 2, 14, 12, 6, 7, 13, 5, 10)], + [(1, 11, 16), (2, 10, 14), (3, 12, 13), + (4, 9, 15), (5, 7, 8)]]) + return ([tuple([g(i) for i in (1, 2, 3, 8, 12)]) for g in G] + + [tuple([g(i) for i in (1, 2, 5, 8, 14)]) for g in G]) diff --git a/src/sage/topology/simplicial_complex_catalog.py b/src/sage/topology/simplicial_complex_catalog.py index 6e86db14cb5..dff18de22a0 100644 --- a/src/sage/topology/simplicial_complex_catalog.py +++ b/src/sage/topology/simplicial_complex_catalog.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs """ Catalog of simplicial complexes @@ -54,23 +54,32 @@ EXAMPLES:: sage: S = simplicial_complexes.Sphere(2) # the 2-sphere - sage: S.homology() + sage: S.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} sage: simplicial_complexes.SurfaceOfGenus(3) Triangulation of an orientable surface of genus 3 sage: M4 = simplicial_complexes.MooreSpace(4) - sage: M4.homology() + sage: M4.homology() # needs sage.modules {0: 0, 1: C4, 2: 0} - sage: simplicial_complexes.MatchingComplex(6).homology() + sage: simplicial_complexes.MatchingComplex(6).homology() # needs sage.modules {0: 0, 1: Z^16, 2: 0} """ from sage.topology.simplicial_complex_examples import (Sphere, Simplex, Torus, - ProjectivePlane, - RealProjectivePlane, KleinBottle, FareyMap, GenusSix, SurfaceOfGenus, - MooreSpace, - ComplexProjectivePlane, QuaternionicProjectivePlane, - PoincareHomologyThreeSphere, RealProjectiveSpace, K3Surface, - BarnetteSphere, BrucknerGrunbaumSphere, NotIConnectedGraphs, - MatchingComplex, ChessboardComplex, RandomComplex, SumComplex, - RandomTwoSphere, ShiftedComplex, RudinBall, ZieglerBall, DunceHat) + ProjectivePlane, + RealProjectivePlane, KleinBottle, + FareyMap, GenusSix, + SurfaceOfGenus, + MooreSpace, + ComplexProjectivePlane, + QuaternionicProjectivePlane, + PoincareHomologyThreeSphere, + RealProjectiveSpace, K3Surface, + BarnetteSphere, + BrucknerGrunbaumSphere, + NotIConnectedGraphs, + MatchingComplex, + ChessboardComplex, RandomComplex, + SumComplex, + RandomTwoSphere, ShiftedComplex, + RudinBall, ZieglerBall, DunceHat) diff --git a/src/sage/topology/simplicial_complex_examples.py b/src/sage/topology/simplicial_complex_examples.py index a1403bcd43c..304ea7ec8aa 100644 --- a/src/sage/topology/simplicial_complex_examples.py +++ b/src/sage/topology/simplicial_complex_examples.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs """ Examples of simplicial complexes @@ -54,22 +54,23 @@ EXAMPLES:: sage: S = simplicial_complexes.Sphere(2) # the 2-sphere - sage: S.homology() + sage: S.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} sage: simplicial_complexes.SurfaceOfGenus(3) Triangulation of an orientable surface of genus 3 sage: M4 = simplicial_complexes.MooreSpace(4) - sage: M4.homology() + sage: M4.homology() # needs sage.modules {0: 0, 1: C4, 2: 0} - sage: simplicial_complexes.MatchingComplex(6).homology() + sage: simplicial_complexes.MatchingComplex(6).homology() # needs sage.modules {0: 0, 1: Z^16, 2: 0} TESTS:: sage: from sage.topology.simplicial_complex_examples import PseudoQuaternionicProjectivePlane - sage: H = PseudoQuaternionicProjectivePlane() + sage: H = PseudoQuaternionicProjectivePlane() # needs sage.groups doctest:warning...: - DeprecationWarning: PseudoQuaternionicProjectivePlane is deprecated. Please use sage.topology.simplicial_complex_examples.QuaternionicProjectivePlane instead. + DeprecationWarning: PseudoQuaternionicProjectivePlane is deprecated. + Please use sage.topology.simplicial_complex_examples.QuaternionicProjectivePlane instead. See https://github.com/sagemath/sage/issues/34568 for details. """ @@ -93,6 +94,7 @@ # hard-coded. Thus the following functions are not currently used in # the Sage library. + def facets_for_RP4(): """ Return the list of facets for a minimal triangulation of 4-dimensional @@ -155,6 +157,7 @@ def facets_for_K3(): return ([tuple([g(i) for i in (1, 2, 3, 8, 12)]) for g in G] + [tuple([g(i) for i in (1, 2, 5, 8, 14)]) for g in G]) + def matching(A, B): r""" List of maximal matchings between the sets ``A`` and ``B``. @@ -229,7 +232,7 @@ def __classcall__(self, maximal_faces=None, name=None, **kwds): Testing ``from_characteristic_function``:: - sage: UniqueSimplicialComplex(from_characteristic_function=(lambda x:sum(x)<=4, range(5))) + sage: UniqueSimplicialComplex(from_characteristic_function=(lambda x: sum(x) <= 4, range(5))) Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 4), (0, 1, 2), (0, 1, 3)} """ char_fcn = kwds.get('from_characteristic_function', None) @@ -291,6 +294,7 @@ def _repr_(self): # Now the functions that produce the actual examples... + def Sphere(n): """ A minimal triangulation of the `n`-dimensional sphere. @@ -303,7 +307,7 @@ def Sphere(n): sage: simplicial_complexes.Sphere(2) Minimal triangulation of the 2-sphere - sage: simplicial_complexes.Sphere(5).homology() + sage: simplicial_complexes.Sphere(5).homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: Z} sage: [simplicial_complexes.Sphere(n).euler_characteristic() for n in range(6)] [2, 0, 2, 0, 2, 0] @@ -320,6 +324,7 @@ def Sphere(n): return UniqueSimplicialComplex(facets, name='Minimal triangulation of the {}-sphere'.format(n)) + def Simplex(n): """ An `n`-dimensional simplex, as a simplicial complex. @@ -341,6 +346,7 @@ def Simplex(n): return UniqueSimplicialComplex([TrueSimplex(n)], name='The {}-simplex'.format(n)) + def Torus(): r""" A minimal triangulation of the torus. @@ -354,7 +360,8 @@ def Torus(): EXAMPLES:: - sage: T = simplicial_complexes.Torus(); T.homology(1) + sage: T = simplicial_complexes.Torus() + sage: T.homology(1) # needs sage.modules Z x Z sage: T.f_vector() [1, 7, 21, 14] @@ -369,11 +376,12 @@ def Torus(): - [Lut2002]_ """ return UniqueSimplicialComplex([[0, 1, 2], [1, 2, 4], [1, 3, 4], [1, 3, 6], - [0, 1, 5], [1, 5, 6], [2, 3, 5], [2, 4, 5], - [2, 3, 6], [0, 2, 6], [0, 3, 4], [0, 3, 5], - [4, 5, 6], [0, 4, 6]], + [0, 1, 5], [1, 5, 6], [2, 3, 5], [2, 4, 5], + [2, 3, 6], [0, 2, 6], [0, 3, 4], [0, 3, 5], + [4, 5, 6], [0, 4, 6]], name='Minimal triangulation of the torus') + def RealProjectivePlane(): """ A minimal triangulation of the real projective plane. @@ -384,6 +392,8 @@ def RealProjectivePlane(): sage: Q = simplicial_complexes.ProjectivePlane() sage: P == Q True + + sage: # needs sage.modules sage: P.cohomology(1) 0 sage: P.cohomology(2) @@ -394,9 +404,9 @@ def RealProjectivePlane(): Vector space of dimension 1 over Finite Field of size 2 """ return UniqueSimplicialComplex([[0, 1, 2], [0, 2, 3], [0, 1, 5], [0, 4, 5], - [0, 3, 4], [1, 2, 4], [1, 3, 4], [1, 3, 5], - [2, 3, 5], [2, 4, 5]], - name='Minimal triangulation of the real projective plane') + [0, 3, 4], [1, 2, 4], [1, 3, 4], [1, 3, 5], + [2, 3, 5], [2, 4, 5]], + name='Minimal triangulation of the real projective plane') ProjectivePlane = RealProjectivePlane @@ -413,10 +423,11 @@ def KleinBottle(): Minimal triangulation of the Klein bottle """ return UniqueSimplicialComplex([[2, 3, 7], [1, 2, 3], [1, 3, 5], [1, 5, 7], - [1, 4, 7], [2, 4, 6], [1, 2, 6], [1, 6, 0], - [1, 4, 0], [2, 4, 0], [3, 4, 7], [3, 4, 6], - [3, 5, 6], [5, 6, 0], [2, 5, 0], [2, 5, 7]], - name='Minimal triangulation of the Klein bottle') + [1, 4, 7], [2, 4, 6], [1, 2, 6], [1, 6, 0], + [1, 4, 0], [2, 4, 0], [3, 4, 7], [3, 4, 6], + [3, 5, 6], [5, 6, 0], [2, 5, 0], [2, 5, 7]], + name='Minimal triangulation of the Klein bottle') + def SurfaceOfGenus(g, orientable=True): """ @@ -457,11 +468,12 @@ def SurfaceOfGenus(g, orientable=True): for i in range(g-1): S = S.connected_sum(T) if orientable: - orient_str = 'n orientable' + name_str = 'Triangulation of an orientable surface of genus {}' else: - orient_str = ' non-orientable' - return UniqueSimplicialComplex(S, - name='Triangulation of a{} surface of genus {}'.format(orient_str, g)) + name_str = 'Triangulation of a non-orientable surface of genus {}' + + return UniqueSimplicialComplex(S, name=name_str.format(g)) + def MooreSpace(q): """ @@ -469,7 +481,7 @@ def MooreSpace(q): INPUT: - - ``q`` -0 integer, at least 2 + - ``q`` -- integer, at least 2 This is a simplicial complex with simplices of dimension 0, 1, and 2, such that its reduced homology is isomorphic to @@ -492,9 +504,9 @@ def MooreSpace(q): sage: simplicial_complexes.MooreSpace(2) Minimal triangulation of the real projective plane - sage: simplicial_complexes.MooreSpace(3).homology()[1] + sage: simplicial_complexes.MooreSpace(3).homology()[1] # needs sage.modules C3 - sage: simplicial_complexes.MooreSpace(4).suspension().homology()[2] + sage: simplicial_complexes.MooreSpace(4).suspension().homology()[2] # needs sage.modules C4 sage: simplicial_complexes.MooreSpace(8) Triangulation of the mod 8 Moore space @@ -521,6 +533,7 @@ def MooreSpace(q): return UniqueSimplicialComplex(facets, name='Triangulation of the mod {} Moore space'.format(q)) + def ComplexProjectivePlane(): """ A minimal triangulation of the complex projective plane. @@ -532,9 +545,9 @@ def ComplexProjectivePlane(): sage: C = simplicial_complexes.ComplexProjectivePlane() sage: C.f_vector() [1, 9, 36, 84, 90, 36] - sage: C.homology(2) + sage: C.homology(2) # needs sage.modules Z - sage: C.homology(4) + sage: C.homology(4) # needs sage.modules Z """ return UniqueSimplicialComplex( @@ -572,14 +585,14 @@ def QuaternionicProjectivePlane(): EXAMPLES:: - sage: HP2 = simplicial_complexes.QuaternionicProjectivePlane() ; HP2 + sage: HP2 = simplicial_complexes.QuaternionicProjectivePlane(); HP2 # needs sage.groups Simplicial complex with 15 vertices and 490 facets - sage: HP2.f_vector() + sage: HP2.f_vector() # needs sage.groups [1, 15, 105, 455, 1365, 3003, 4515, 4230, 2205, 490] Checking its automorphism group:: - sage: HP2.automorphism_group().is_isomorphic(AlternatingGroup(5)) + sage: HP2.automorphism_group().is_isomorphic(AlternatingGroup(5)) # needs sage.groups True """ from sage.groups.perm_gps.permgroup import PermutationGroup @@ -623,9 +636,9 @@ def PoincareHomologyThreeSphere(): sage: S3 = simplicial_complexes.Sphere(3) sage: Sigma3 = simplicial_complexes.PoincareHomologyThreeSphere() - sage: S3.homology() == Sigma3.homology() + sage: S3.homology() == Sigma3.homology() # needs sage.modules True - sage: Sigma3.fundamental_group().cardinality() # long time + sage: Sigma3.fundamental_group().cardinality() # long time # needs sage.groups 120 """ return UniqueSimplicialComplex( @@ -654,6 +667,7 @@ def PoincareHomologyThreeSphere(): [11, 13, 14, 16], [12, 13, 14, 15], [13, 14, 15, 16]], name='Triangulation of the Poincare homology 3-sphere') + def RealProjectiveSpace(n): r""" A triangulation of `\Bold{R}P^n` for any `n \geq 0`. @@ -724,7 +738,7 @@ def RealProjectiveSpace(n): sage: P3 = simplicial_complexes.RealProjectiveSpace(3) sage: P3.f_vector() [1, 11, 51, 80, 40] - sage: P3.homology() + sage: P3.homology() # needs sage.modules {0: 0, 1: C2, 2: 0, 3: Z} sage: P4 = simplicial_complexes.RealProjectiveSpace(4) sage: P4.f_vector() @@ -769,7 +783,7 @@ def RealProjectiveSpace(n): [3, 4, 8, 9], [4, 5, 7, 9], [1, 3, 5, 11], [1, 5, 8, 10], [2, 5, 7, 8], [3, 5, 9, 10], [4, 6, 7, 10], [1, 3, 7, 10], [1, 6, 8, 9], [2, 5, 7, 9], [3, 6, 7, 8], [5, 6, 7, 8]], - name='Minimal triangulation of RP^3') + name='Minimal triangulation of RP^3') if n == 4: return UniqueSimplicialComplex( [(1, 3, 8, 12, 13), (2, 7, 8, 13, 16), (4, 8, 9, 12, 14), @@ -852,7 +866,7 @@ def K3Surface(): EXAMPLES:: - sage: K3=simplicial_complexes.K3Surface() ; K3 + sage: K3 = simplicial_complexes.K3Surface(); K3 Minimal triangulation of the K3 surface sage: K3.f_vector() [1, 16, 120, 560, 720, 288] @@ -975,7 +989,7 @@ def BarnetteSphere(): EXAMPLES:: - sage: BS = simplicial_complexes.BarnetteSphere() ; BS + sage: BS = simplicial_complexes.BarnetteSphere(); BS Barnette's triangulation of the 3-sphere sage: BS.f_vector() [1, 8, 27, 38, 19] @@ -995,12 +1009,14 @@ def BarnetteSphere(): sage: BS.is_isomorphic(BS2) True """ - return UniqueSimplicialComplex([ - (1, 2, 4, 5), (2, 3, 5, 6), (1, 3, 4, 6), (1, 2, 3, 7), (4, 5, 6, 7), (1, 2, 4, 7), - (2, 4, 5, 7), (2, 3, 5, 7), (3, 5, 6, 7), (3, 1, 6, 7), (1, 6, 4, 7), (1, 2, 3, 8), - (4, 5, 6, 8), (1, 2, 5, 8), (1, 4, 5, 8), (2, 3, 6, 8), (2, 5, 6, 8), (3, 1, 4, 8), - (3, 6, 4, 8)], - name="Barnette's triangulation of the 3-sphere") + return UniqueSimplicialComplex([(1, 2, 4, 5), (2, 3, 5, 6), (1, 3, 4, 6), + (1, 2, 3, 7), (4, 5, 6, 7), (1, 2, 4, 7), + (2, 4, 5, 7), (2, 3, 5, 7), (3, 5, 6, 7), + (3, 1, 6, 7), (1, 6, 4, 7), (1, 2, 3, 8), + (4, 5, 6, 8), (1, 2, 5, 8), (1, 4, 5, 8), + (2, 3, 6, 8), (2, 5, 6, 8), (3, 1, 4, 8), + (3, 6, 4, 8)], + name="Barnette's triangulation of the 3-sphere") def BrucknerGrunbaumSphere(): @@ -1018,7 +1034,7 @@ def BrucknerGrunbaumSphere(): EXAMPLES:: - sage: BGS = simplicial_complexes.BrucknerGrunbaumSphere() ; BGS + sage: BGS = simplicial_complexes.BrucknerGrunbaumSphere(); BGS Bruckner and Grunbaum's triangulation of the 3-sphere sage: BGS.f_vector() [1, 8, 28, 40, 20] @@ -1032,6 +1048,7 @@ def BrucknerGrunbaumSphere(): ############################################################### # examples from graph theory: + def NotIConnectedGraphs(n, i): """ The simplicial complex of all graphs on `n` vertices which are @@ -1062,9 +1079,10 @@ def NotIConnectedGraphs(n, i): EXAMPLES:: - sage: simplicial_complexes.NotIConnectedGraphs(5, 2).f_vector() + sage: NICG52 = simplicial_complexes.NotIConnectedGraphs(5, 2) + sage: NICG52.f_vector() [1, 10, 45, 120, 210, 240, 140, 20] - sage: simplicial_complexes.NotIConnectedGraphs(5, 2).homology(5).ngens() + sage: NICG52.homology(5).ngens() # needs sage.modules 6 """ G_list = range(1, n+1) @@ -1089,6 +1107,7 @@ def NotIConnectedGraphs(n, i): facets.append(facet) return UniqueSimplicialComplex(facets, name='Simplicial complex of not {}-connected graphs on {} vertices'.format(i, n)) + def MatchingComplex(n): """ The matching complex of graphs on `n` vertices. @@ -1116,12 +1135,12 @@ def MatchingComplex(n): EXAMPLES:: sage: M = simplicial_complexes.MatchingComplex(7) - sage: H = M.homology() - sage: H + sage: H = M.homology(); H # needs sage.modules {0: 0, 1: C3, 2: Z^20} - sage: H[2].ngens() + sage: H[2].ngens() # needs sage.modules 20 - sage: simplicial_complexes.MatchingComplex(8).homology(2) # long time (6s on sage.math, 2012) + sage: M8 = simplicial_complexes.MatchingComplex(8) + sage: M8.homology(2) # long time (6s on sage.math, 2012), needs sage.modules Z^132 """ G_vertices = Set(range(1, n+1)) @@ -1161,6 +1180,7 @@ def MatchingComplex(n): facets.append(facet) return UniqueSimplicialComplex(facets, name='Matching complex on {} vertices'.format(n)) + def ChessboardComplex(n, i): r""" The chessboard complex for an `n \times i` chessboard. @@ -1192,7 +1212,7 @@ def ChessboardComplex(n, i): sage: C = simplicial_complexes.ChessboardComplex(5, 5) sage: C.f_vector() [1, 25, 200, 600, 600, 120] - sage: simplicial_complexes.ChessboardComplex(3, 3).homology() + sage: simplicial_complexes.ChessboardComplex(3, 3).homology() # needs sage.modules {0: 0, 1: Z x Z x Z x Z, 2: 0} """ A = range(n) @@ -1211,6 +1231,7 @@ def ChessboardComplex(n, i): facets.append(facet) return UniqueSimplicialComplex(facets, name='Chessboard complex for an {}x{} chessboard'.format(n, i)) + def RandomComplex(n, d, p=0.5): """ A random ``d``-dimensional simplicial complex on ``n`` vertices. @@ -1254,6 +1275,7 @@ def RandomComplex(n, d, p=0.5): return UniqueSimplicialComplex(facets, name='Random {}-dimensional simplicial complex on {} vertices'.format(d, n)) + def SumComplex(n, A): r""" The sum complexes of Linial, Meshulam, and Rosenthal [LMR2010]_. @@ -1294,58 +1316,58 @@ def SumComplex(n, A): sage: S = simplicial_complexes.SumComplex(10, [0, 1, 2, 3, 6]); S Sum complex on vertices Z/10Z associated to {0, 1, 2, 3, 6} - sage: S.homology() + sage: S.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: C2728, 4: 0} sage: factor(2728) 2^3 * 11 * 31 sage: S = simplicial_complexes.SumComplex(11, [0, 1, 3]); S Sum complex on vertices Z/11Z associated to {0, 1, 3} - sage: S.homology(1) + sage: S.homology(1) # needs sage.modules C23 sage: S = simplicial_complexes.SumComplex(11, [0, 1, 2, 3, 4, 7]); S Sum complex on vertices Z/11Z associated to {0, 1, 2, 3, 4, 7} - sage: S.homology() # long time + sage: S.homology() # long time # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: C645679, 5: 0} sage: factor(645679) 23 * 67 * 419 sage: S = simplicial_complexes.SumComplex(13, [0, 1, 3]); S Sum complex on vertices Z/13Z associated to {0, 1, 3} - sage: S.homology(1) + sage: S.homology(1) # needs sage.modules C159 sage: factor(159) 3 * 53 sage: S = simplicial_complexes.SumComplex(13, [0, 1, 2, 5]); S Sum complex on vertices Z/13Z associated to {0, 1, 2, 5} - sage: S.homology() # long time + sage: S.homology() # long time # needs sage.modules {0: 0, 1: 0, 2: C146989209, 3: 0} sage: factor(1648910295) 3^2 * 5 * 53 * 521 * 1327 sage: S = simplicial_complexes.SumComplex(13, [0, 1, 2, 3, 5]); S Sum complex on vertices Z/13Z associated to {0, 1, 2, 3, 5} - sage: S.homology() # long time + sage: S.homology() # long time # needs sage.modules {0: 0, 1: 0, 2: 0, 3: C3 x C237 x C706565607945, 4: 0} - sage: factor(706565607945) + sage: factor(706565607945) # needs sage.libs.pari 3 * 5 * 53 * 79 * 131 * 157 * 547 sage: S = simplicial_complexes.SumComplex(17, [0, 1, 4]); S Sum complex on vertices Z/17Z associated to {0, 1, 4} - sage: S.homology(1) + sage: S.homology(1) # needs sage.modules C140183 sage: factor(140183) 103 * 1361 sage: S = simplicial_complexes.SumComplex(19, [0, 1, 4]); S Sum complex on vertices Z/19Z associated to {0, 1, 4} - sage: S.homology(1) + sage: S.homology(1) # needs sage.modules C5670599 sage: factor(5670599) 11 * 191 * 2699 sage: S = simplicial_complexes.SumComplex(31, [0, 1, 4]); S Sum complex on vertices Z/31Z associated to {0, 1, 4} - sage: S.homology(1) # long time + sage: S.homology(1) # long time # needs sage.modules C5 x C5 x C5 x C5 x C26951480558170926865 - sage: factor(26951480558170926865) + sage: factor(26951480558170926865) # needs sage.libs.pari 5 * 311 * 683 * 1117 * 11657 * 1948909 """ from sage.rings.finite_rings.integer_mod_ring import Integers @@ -1401,9 +1423,10 @@ def RandomTwoSphere(n): EXAMPLES:: + sage: sage: G = simplicial_complexes.RandomTwoSphere(6); G Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and 8 facets - sage: G.homology() + sage: G.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} sage: G.is_pure() True @@ -1422,6 +1445,7 @@ def RandomTwoSphere(n): return SimplicialComplex(triangles, maximality_check=False) + def ShiftedComplex(generators): r""" Return the smallest shifted simplicial complex containing ``generators`` @@ -1448,13 +1472,14 @@ def ShiftedComplex(generators): EXAMPLES:: - sage: X = simplicial_complexes.ShiftedComplex([ Simplex([1, 6]), (2, 4), [8] ]) + sage: # needs sage.combinat + sage: X = simplicial_complexes.ShiftedComplex([Simplex([1, 6]), (2, 4), [8]]) sage: sorted(X.facets()) [(1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 3), (2, 4), (7,), (8,)] - sage: X = simplicial_complexes.ShiftedComplex([ [2, 3, 5] ]) + sage: X = simplicial_complexes.ShiftedComplex([[2, 3, 5]]) sage: sorted(X.facets()) [(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (2, 3, 4), (2, 3, 5)] - sage: X = simplicial_complexes.ShiftedComplex([ [1, 3, 5], [2, 6] ]) + sage: X = simplicial_complexes.ShiftedComplex([[1, 3, 5], [2, 6]]) sage: sorted(X.facets()) [(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 6), (2, 6)] """ @@ -1468,6 +1493,7 @@ def ShiftedComplex(generators): Facets.append(list(reversed(P))) return SimplicialComplex(Facets) + def RudinBall(): r""" Return the non-shellable ball constructed by Rudin. @@ -1482,9 +1508,9 @@ def RudinBall(): Rudin ball sage: R.f_vector() [1, 14, 66, 94, 41] - sage: R.homology() + sage: R.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0} - sage: R.is_cohen_macaulay() + sage: R.is_cohen_macaulay() # needs sage.modules True """ return UniqueSimplicialComplex( @@ -1500,6 +1526,7 @@ def RudinBall(): name="Rudin ball" ) + def ZieglerBall(): r""" Return the non-shellable ball constructed by Ziegler. @@ -1514,19 +1541,19 @@ def ZieglerBall(): Ziegler ball sage: Z.f_vector() [1, 10, 38, 50, 21] - sage: Z.homology() + sage: Z.homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0} - sage: Z.is_cohen_macaulay() + sage: Z.is_cohen_macaulay() # needs sage.modules True """ return UniqueSimplicialComplex( - [[1, 2, 3, 4], [1, 2, 5, 6], [1, 5, 6, 9], [2, 5, 6, 0], [3, 6, 7, 8], [4, 5, 7, 8], - [2, 3, 6, 7], [1, 6, 2, 9], [2, 6, 7, 0], [3, 2, 4, 8], [4, 1, 3, 7], [3, 4, 7, 8], - [1, 2, 4, 9], [2, 7, 3, 0], [3, 2, 6, 8], [4, 1, 5, 7], [4, 1, 8, 5], [1, 4, 8, 9], - [2, 3, 1, 0], [1, 8, 5, 9], [2, 1, 5, 0]], - name="Ziegler ball" - ) + [[1, 2, 3, 4], [1, 2, 5, 6], [1, 5, 6, 9], [2, 5, 6, 0], [3, 6, 7, 8], [4, 5, 7, 8], + [2, 3, 6, 7], [1, 6, 2, 9], [2, 6, 7, 0], [3, 2, 4, 8], [4, 1, 3, 7], [3, 4, 7, 8], + [1, 2, 4, 9], [2, 7, 3, 0], [3, 2, 6, 8], [4, 1, 5, 7], [4, 1, 8, 5], [1, 4, 8, 9], + [2, 3, 1, 0], [1, 8, 5, 9], [2, 1, 5, 0]], + name="Ziegler ball") + def DunceHat(): r""" @@ -1542,17 +1569,16 @@ def DunceHat(): Minimal triangulation of the dunce hat sage: D.f_vector() [1, 8, 24, 17] - sage: D.homology() + sage: D.homology() # needs sage.modules {0: 0, 1: 0, 2: 0} - sage: D.is_cohen_macaulay() + sage: D.is_cohen_macaulay() # needs sage.modules True """ return UniqueSimplicialComplex( - [[1, 3, 5], [2, 3, 5], [2, 4, 5], [1, 2, 4], [1, 3, 4], [3, 4, 8], - [1, 2, 8], [1, 7, 8], [1, 2, 7], [2, 3, 7], [3, 6, 7], [1, 3, 6], - [1, 5, 6], [4, 5, 6], [4, 6, 8], [6, 7, 8], [2, 3, 8]], - name="Minimal triangulation of the dunce hat" - ) + [[1, 3, 5], [2, 3, 5], [2, 4, 5], [1, 2, 4], [1, 3, 4], [3, 4, 8], + [1, 2, 8], [1, 7, 8], [1, 2, 7], [2, 3, 7], [3, 6, 7], [1, 3, 6], + [1, 5, 6], [4, 5, 6], [4, 6, 8], [6, 7, 8], [2, 3, 8]], + name="Minimal triangulation of the dunce hat") def FareyMap(p): @@ -1577,14 +1603,14 @@ def FareyMap(p): EXAMPLES:: - sage: S5 = simplicial_complexes.FareyMap(5); S5 + sage: S5 = simplicial_complexes.FareyMap(5); S5 # needs sage.groups Simplicial complex with 12 vertices and 20 facets - sage: S5.automorphism_group().cardinality() + sage: S5.automorphism_group().cardinality() # needs sage.groups 120 - sage: S7 = simplicial_complexes.FareyMap(7); S7 + sage: S7 = simplicial_complexes.FareyMap(7); S7 # needs sage.groups Simplicial complex with 24 vertices and 56 facets - sage: S7.f_vector() + sage: S7.f_vector() # needs sage.groups [1, 24, 84, 56] REFERENCES: @@ -1642,9 +1668,9 @@ def GenusSix(): EXAMPLES:: sage: S = simplicial_complexes.GenusSix() - sage: S.automorphism_group().cardinality() + sage: S.automorphism_group().cardinality() # needs sage.groups 12 - sage: S.betti() + sage: S.betti() # needs sage.modules {0: 1, 1: 12, 2: 1} sage: S.f_vector() [1, 12, 66, 44] diff --git a/src/sage/topology/simplicial_complex_homset.py b/src/sage/topology/simplicial_complex_homset.py index 8f7b84d1cde..255e905a990 100644 --- a/src/sage/topology/simplicial_complex_homset.py +++ b/src/sage/topology/simplicial_complex_homset.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Homsets between simplicial complexes @@ -60,7 +61,8 @@ import sage.categories.homset from .simplicial_complex_morphism import SimplicialComplexMorphism -def is_SimplicialComplexHomset(x): + +def is_SimplicialComplexHomset(x) -> bool: """ Return ``True`` if and only if ``x`` is a simplicial complex homspace. @@ -79,6 +81,7 @@ def is_SimplicialComplexHomset(x): """ return isinstance(x, SimplicialComplexHomset) + class SimplicialComplexHomset(sage.categories.homset.Homset): def __call__(self, f): """ @@ -100,9 +103,9 @@ def __call__(self, f): To: Minimal triangulation of the 2-sphere Defn: [0, 1, 2, 3, 4] --> [0, 1, 2, 2, 2] """ - return SimplicialComplexMorphism(f,self.domain(),self.codomain()) + return SimplicialComplexMorphism(f, self.domain(), self.codomain()) - def diagonal_morphism(self,rename_vertices=True): + def diagonal_morphism(self, rename_vertices=True): r""" Return the diagonal morphism in `Hom(S, S \times S)`. @@ -110,8 +113,7 @@ def diagonal_morphism(self,rename_vertices=True): sage: S = simplicial_complexes.Sphere(2) sage: H = Hom(S,S.product(S, is_mutable=False)) - sage: d = H.diagonal_morphism() - sage: d + sage: d = H.diagonal_morphism(); d Simplicial complex morphism: From: Minimal triangulation of the 2-sphere To: Simplicial complex with 16 vertices and 96 facets @@ -121,26 +123,27 @@ def diagonal_morphism(self,rename_vertices=True): 3 |--> L3R3 sage: T = SimplicialComplex([[0], [1]], is_mutable=False) - sage: U = T.product(T,rename_vertices = False, is_mutable=False) - sage: G = Hom(T,U) - sage: e = G.diagonal_morphism(rename_vertices = False) - sage: e + sage: U = T.product(T, rename_vertices=False, is_mutable=False) + sage: G = Hom(T, U) + sage: e = G.diagonal_morphism(rename_vertices=False); e Simplicial complex morphism: From: Simplicial complex with vertex set (0, 1) and facets {(0,), (1,)} - To: Simplicial complex with 4 vertices and facets {((0, 0),), ((0, 1),), ((1, 0),), ((1, 1),)} + To: Simplicial complex with 4 vertices and + facets {((0, 0),), ((0, 1),), ((1, 0),), ((1, 1),)} Defn: 0 |--> (0, 0) 1 |--> (1, 1) """ # Preserve whether the codomain is mutable when renaming the vertices. mutable = self._codomain.is_mutable() - X = self._domain.product(self._domain,rename_vertices=rename_vertices, is_mutable=mutable) + X = self._domain.product(self._domain, rename_vertices=rename_vertices, + is_mutable=mutable) if self._codomain != X: raise TypeError("diagonal morphism is only defined for Hom(X,XxX)") f = {} if rename_vertices: f = {i: "L{0}R{0}".format(i) for i in self._domain.vertices()} else: - f = {i: (i,i) for i in self._domain.vertices()} + f = {i: (i, i) for i in self._domain.vertices()} return SimplicialComplexMorphism(f, self._domain, X) def identity(self): @@ -150,15 +153,16 @@ def identity(self): EXAMPLES:: sage: S = simplicial_complexes.Sphere(2) - sage: H = Hom(S,S) + sage: H = Hom(S, S) sage: i = H.identity() sage: i.is_identity() True sage: T = SimplicialComplex([[0,1]], is_mutable=False) - sage: G = Hom(T,T) + sage: G = Hom(T, T) sage: G.identity() - Simplicial complex endomorphism of Simplicial complex with vertex set (0, 1) and facets {(0, 1)} + Simplicial complex endomorphism of + Simplicial complex with vertex set (0, 1) and facets {(0, 1)} Defn: 0 |--> 0 1 |--> 1 """ diff --git a/src/sage/topology/simplicial_complex_morphism.py b/src/sage/topology/simplicial_complex_morphism.py index e8806f732ab..3d4fc063198 100644 --- a/src/sage/topology/simplicial_complex_morphism.py +++ b/src/sage/topology/simplicial_complex_morphism.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Morphisms of simplicial complexes @@ -102,15 +103,15 @@ # # **************************************************************************** -from .simplicial_complex import Simplex, SimplicialComplex -from sage.matrix.constructor import matrix, zero_matrix -from sage.rings.integer_ring import ZZ -from sage.homology.chain_complex_morphism import ChainComplexMorphism -from sage.combinat.permutation import Permutation -from sage.algebras.steenrod.steenrod_algebra_misc import convert_perm -from sage.categories.morphism import Morphism from sage.categories.homset import Hom +from sage.categories.morphism import Morphism from sage.categories.simplicial_complexes import SimplicialComplexes +from sage.misc.lazy_import import lazy_import +from sage.rings.integer_ring import ZZ + +from .simplicial_complex import Simplex, SimplicialComplex + +lazy_import('sage.matrix.constructor', ['matrix', 'zero_matrix']) def is_SimplicialComplexMorphism(x): @@ -135,7 +136,7 @@ class SimplicialComplexMorphism(Morphism): """ An element of this class is a morphism of simplicial complexes. """ - def __init__(self,f,X,Y): + def __init__(self, f, X, Y): """ Input is a dictionary ``f``, the domain ``X``, and the codomain ``Y``. @@ -158,7 +159,7 @@ def __init__(self,f,X,Y): sage: x.image() == y.image() False """ - if not isinstance(X,SimplicialComplex) or not isinstance(Y,SimplicialComplex): + if not isinstance(X, SimplicialComplex) or not isinstance(Y, SimplicialComplex): raise ValueError("X and Y must be SimplicialComplexes") if not set(f.keys()) == set(X.vertices()): raise ValueError("f must be a dictionary from the vertex set of X to single values in the vertex set of Y") @@ -174,9 +175,9 @@ def __init__(self,f,X,Y): if v not in Y_faces[v.dimension()]: raise ValueError("f must be a dictionary from the vertices of X to the vertices of Y") self._vertex_dictionary = f - Morphism.__init__(self, Hom(X,Y,SimplicialComplexes())) + Morphism.__init__(self, Hom(X, Y, SimplicialComplexes())) - def __eq__(self,x): + def __eq__(self, x): """ Return ``True`` if and only if ``self == x``. @@ -206,12 +207,12 @@ def __eq__(self,x): sage: k == l True """ - if not isinstance(x,SimplicialComplexMorphism) or self.codomain() != x.codomain() or self.domain() != x.domain() or self._vertex_dictionary != x._vertex_dictionary: + if not isinstance(x, SimplicialComplexMorphism) or self.codomain() != x.codomain() or self.domain() != x.domain() or self._vertex_dictionary != x._vertex_dictionary: return False else: return True - def __call__(self,x,orientation=False): + def __call__(self, x, orientation=False): """ Input is a simplex of the domain. Output is the image simplex. @@ -241,7 +242,7 @@ def __call__(self,x,orientation=False): sage: g = Hom(X,X)({0:1, 1:0}) sage: g(Simplex([0,1])) (0, 1) - sage: g(Simplex([0,1]), orientation=True) + sage: g(Simplex([0,1]), orientation=True) # needs sage.modules ((0, 1), -1) """ dim = self.domain().dimension() @@ -252,6 +253,9 @@ def __call__(self,x,orientation=False): for j in tup: fx.append(self._vertex_dictionary[j]) if orientation: + from sage.algebras.steenrod.steenrod_algebra_misc import convert_perm + from sage.combinat.permutation import Permutation + if len(set(fx)) == len(tup): oriented = Permutation(convert_perm(fx)).signature() else: @@ -303,39 +307,41 @@ def _repr_defn(self): codomain = [vd[v] for v in domain] return "{} --> {}".format(domain, codomain) - def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain=False): + def associated_chain_complex_morphism(self, base_ring=ZZ, + augmented=False, cochain=False): """ Return the associated chain complex morphism of ``self``. EXAMPLES:: + sage: # needs sage.modules sage: S = simplicial_complexes.Sphere(1) sage: T = simplicial_complexes.Sphere(2) - sage: H = Hom(S,T) - sage: f = {0:0,1:1,2:2} - sage: x = H(f) - sage: x + sage: H = Hom(S, T) + sage: f = {0:0, 1:1, 2:2} + sage: x = H(f); x Simplicial complex morphism: From: Minimal triangulation of the 1-sphere To: Minimal triangulation of the 2-sphere Defn: 0 |--> 0 1 |--> 1 2 |--> 2 - sage: a = x.associated_chain_complex_morphism() - sage: a + sage: a = x.associated_chain_complex_morphism(); a Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Integer Ring To: Chain complex with at most 3 nonzero terms over Integer Ring sage: a._matrix_dictionary {0: [1 0 0] - [0 1 0] - [0 0 1] - [0 0 0], 1: [1 0 0] - [0 1 0] - [0 0 0] - [0 0 1] - [0 0 0] - [0 0 0], 2: []} + [0 1 0] + [0 0 1] + [0 0 0], + 1: [1 0 0] + [0 1 0] + [0 0 0] + [0 0 1] + [0 0 0] + [0 0 0], + 2: []} sage: x.associated_chain_complex_morphism(augmented=True) Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Integer Ring @@ -344,7 +350,7 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Integer Ring To: Chain complex with at most 2 nonzero terms over Integer Ring - sage: x.associated_chain_complex_morphism(augmented=True,cochain=True) + sage: x.associated_chain_complex_morphism(augmented=True, cochain=True) Chain complex morphism: From: Chain complex with at most 4 nonzero terms over Integer Ring To: Chain complex with at most 3 nonzero terms over Integer Ring @@ -355,27 +361,33 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= Some simplicial maps which reverse the orientation of a few simplices:: + sage: # needs sage.modules sage: g = {0:1, 1:2, 2:0} sage: H(g).associated_chain_complex_morphism()._matrix_dictionary {0: [0 0 1] - [1 0 0] - [0 1 0] - [0 0 0], 1: [ 0 -1 0] - [ 0 0 -1] - [ 0 0 0] - [ 1 0 0] - [ 0 0 0] - [ 0 0 0], 2: []} + [1 0 0] + [0 1 0] + [0 0 0], + 1: [ 0 -1 0] + [ 0 0 -1] + [ 0 0 0] + [ 1 0 0] + [ 0 0 0] + [ 0 0 0], + 2: []} sage: X = SimplicialComplex([[0, 1]], is_mutable=False) sage: Hom(X,X)({0:1, 1:0}).associated_chain_complex_morphism()._matrix_dictionary {0: [0 1] - [1 0], 1: [-1]} + [1 0], + 1: [-1]} """ - max_dim = max(self.domain().dimension(),self.codomain().dimension()) - min_dim = min(self.domain().dimension(),self.codomain().dimension()) + from sage.homology.chain_complex_morphism import ChainComplexMorphism + + max_dim = max(self.domain().dimension(), self.codomain().dimension()) + min_dim = min(self.domain().dimension(), self.codomain().dimension()) matrices = {} if augmented is True: - m = matrix(base_ring,1,1,1) + m = matrix(base_ring, 1, 1, 1) if not cochain: matrices[-1] = m else: @@ -392,12 +404,12 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= pass else: mval[X_faces.index(i)+(Y_faces.index(y)*num_faces_X)] = oriented - m = matrix(base_ring,num_faces_Y,num_faces_X,mval,sparse=True) + m = matrix(base_ring, num_faces_Y, num_faces_X, mval, sparse=True) if not cochain: matrices[dim] = m else: matrices[dim] = m.transpose() - for dim in range(min_dim+1,max_dim+1): + for dim in range(min_dim+1, max_dim+1): try: l1 = len(self.codomain().n_cells(dim)) except KeyError: @@ -406,18 +418,18 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= l2 = len(self.domain().n_cells(dim)) except KeyError: l2 = 0 - m = zero_matrix(base_ring,l1,l2,sparse=True) + m = zero_matrix(base_ring, l1, l2, sparse=True) if not cochain: matrices[dim] = m else: matrices[dim] = m.transpose() if not cochain: return ChainComplexMorphism(matrices, - self.domain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain), - self.codomain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain)) + self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain), + self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain)) return ChainComplexMorphism(matrices, - self.codomain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain), - self.domain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain)) + self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain), + self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain)) def image(self): """ @@ -560,7 +572,7 @@ def is_identity(self): else: return True - def fiber_product(self, other, rename_vertices = True): + def fiber_product(self, other, rename_vertices=True): """ Fiber product of ``self`` and ``other``. Both morphisms should have the same codomain. The method returns a morphism of simplicial @@ -590,9 +602,9 @@ def fiber_product(self, other, rename_vertices = True): """ if self.codomain() != other.codomain(): raise ValueError("self and other must have the same codomain") - X = self.domain().product(other.domain(),rename_vertices = rename_vertices) + X = self.domain().product(other.domain(), rename_vertices=rename_vertices) v = [] - f = dict() + f = {} eff1 = self.domain().vertices() eff2 = other.domain().vertices() for i in eff1: @@ -602,8 +614,8 @@ def fiber_product(self, other, rename_vertices = True): v.append("L"+str(i)+"R"+str(j)) f["L"+str(i)+"R"+str(j)] = self._vertex_dictionary[i] else: - v.append((i,j)) - f[(i,j)] = self._vertex_dictionary[i] + v.append((i, j)) + f[(i, j)] = self._vertex_dictionary[i] return SimplicialComplexMorphism(f, X.generated_subcomplex(v), self.codomain()) def mapping_torus(self): @@ -623,13 +635,13 @@ def mapping_torus(self): sage: C = simplicial_complexes.Sphere(1) # Circle sage: T = Hom(C,C).identity().mapping_torus() ; T # Torus Simplicial complex with 9 vertices and 18 facets - sage: T.homology() == simplicial_complexes.Torus().homology() + sage: T.homology() == simplicial_complexes.Torus().homology() # needs sage.modules True - sage: f = Hom(C,C)({0:0,1:2,2:1}) - sage: K = f.mapping_torus() ; K # Klein Bottle + sage: f = Hom(C,C)({0:0, 1:2, 2:1}) + sage: K = f.mapping_torus(); K # Klein Bottle Simplicial complex with 9 vertices and 18 facets - sage: K.homology() == simplicial_complexes.KleinBottle().homology() + sage: K.homology() == simplicial_complexes.KleinBottle().homology() # needs sage.modules True TESTS:: @@ -643,12 +655,12 @@ def mapping_torus(self): if self.domain() != self.codomain(): raise ValueError("self must have the same domain and codomain") map_dict = self._vertex_dictionary - interval = SimplicialComplex([["I0","I1"],["I1","I2"]]) - product = interval.product(self.domain(),False) + interval = SimplicialComplex([["I0", "I1"], ["I1", "I2"]]) + product = interval.product(self.domain(), False) facets = list(product.maximal_faces()) for facet in self.domain()._facets: - left = [ ("I0",v) for v in facet ] - right = [ ("I2",map_dict[v]) for v in facet ] + left = [("I0", v) for v in facet] + right = [("I2", map_dict[v]) for v in facet] for i in range(facet.dimension()+1): facets.append(tuple(left[:i+1]+right[i:])) return SimplicialComplex(facets) @@ -670,11 +682,12 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): sage: T = S.product(S, is_mutable=False) sage: H = Hom(S,T) sage: diag = H.diagonal_morphism() - sage: h = diag.induced_homology_morphism(QQ) - sage: h + sage: h = diag.induced_homology_morphism(QQ); h # needs sage.modules Graded vector space morphism: - From: Homology module of Minimal triangulation of the 1-sphere over Rational Field - To: Homology module of Simplicial complex with 9 vertices and 18 facets over Rational Field + From: Homology module of + Minimal triangulation of the 1-sphere over Rational Field + To: Homology module of + Simplicial complex with 9 vertices and 18 facets over Rational Field Defn: induced by: Simplicial complex morphism: From: Minimal triangulation of the 1-sphere @@ -685,12 +698,12 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): We can view the matrix form for the homomorphism:: - sage: h.to_matrix(0) # in degree 0 + sage: h.to_matrix(0) # in degree 0 # needs sage.modules [1] - sage: h.to_matrix(1) # in degree 1 + sage: h.to_matrix(1) # in degree 1 # needs sage.modules [1] [1] - sage: h.to_matrix() # the entire homomorphism + sage: h.to_matrix() # the entire homomorphism # needs sage.modules [1|0] [-+-] [0|1] @@ -700,18 +713,18 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): The map on cohomology should be dual to the map on homology:: - sage: coh = diag.induced_homology_morphism(QQ, cohomology=True) - sage: coh.to_matrix(1) + sage: coh = diag.induced_homology_morphism(QQ, cohomology=True) # needs sage.modules + sage: coh.to_matrix(1) # needs sage.modules [1 1] - sage: h.to_matrix() == coh.to_matrix().transpose() + sage: h.to_matrix() == coh.to_matrix().transpose() # needs sage.modules True We can evaluate the map on (co)homology classes:: - sage: x,y = list(T.cohomology_ring(QQ).basis(1)) - sage: coh(x) + sage: x,y = list(T.cohomology_ring(QQ).basis(1)) # needs sage.modules + sage: coh(x) # needs sage.modules h^{1,0} - sage: coh(2*x+3*y) + sage: coh(2*x + 3*y) # needs sage.modules 5*h^{1,0} Note that the complexes must be immutable for this to @@ -725,13 +738,13 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): sage: S2 = S.suspension() sage: S2.is_immutable() False - sage: h = Hom(S,S2)({0: 0, 1:1, 2:2}).induced_homology_morphism() + sage: h = Hom(S, S2)({0: 0, 1: 1, 2: 2}).induced_homology_morphism() # needs sage.modules Traceback (most recent call last): ... ValueError: the domain and codomain complexes must be immutable sage: S2.set_immutable(); S2.is_immutable() True - sage: h = Hom(S,S2)({0: 0, 1:1, 2:2}).induced_homology_morphism() + sage: h = Hom(S, S2)({0: 0, 1: 1, 2: 2}).induced_homology_morphism() # needs sage.modules """ from sage.homology.homology_morphism import InducedHomologyMorphism return InducedHomologyMorphism(self, base_ring, cohomology) diff --git a/src/sage/topology/simplicial_set.py b/src/sage/topology/simplicial_set.py index 0ca2ff5bcb2..3ee14ae2da8 100644 --- a/src/sage/topology/simplicial_set.py +++ b/src/sage/topology/simplicial_set.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Simplicial sets @@ -41,10 +41,9 @@ sage: simplicial_sets.Torus() Torus - sage: simplicial_sets.RealProjectiveSpace(7) + sage: simplicial_sets.RealProjectiveSpace(7) # needs sage.groups RP^7 - sage: S5 = simplicial_sets.Sphere(5) - sage: S5 + sage: S5 = simplicial_sets.Sphere(5); S5 S^5 sage: S5.nondegenerate_simplices() [v_0, sigma_5] @@ -52,14 +51,14 @@ One class of infinite simplicial sets is available: classifying spaces of groups, or more generally, nerves of finite monoids:: - sage: Sigma4 = groups.permutation.Symmetric(4) - sage: Sigma4.nerve() + sage: Sigma4 = groups.permutation.Symmetric(4) # needs sage.groups + sage: Sigma4.nerve() # needs sage.groups Nerve of Symmetric group of order 4! as a permutation group The same simplicial set (albeit with a different name) can also be constructed as :: - sage: simplicial_sets.ClassifyingSpace(Sigma4) + sage: simplicial_sets.ClassifyingSpace(Sigma4) # needs sage.groups Classifying space of Symmetric group of order 4! as a permutation group Type ``simplicial_sets.`` and hit the :kbd:`Tab` key to get a full list @@ -167,20 +166,21 @@ sage: S1 = simplicial_sets.Sphere(1) sage: eight = S1.wedge(S1) - sage: eight.fundamental_group() + sage: eight.fundamental_group() # needs sage.groups Finitely presented group < e0, e1 | > + sage: # needs sage.groups sage: Sigma3 = groups.permutation.Symmetric(3) sage: BSigma3 = Sigma3.nerve() sage: pi = BSigma3.fundamental_group(); pi - Finitely presented group < e0, e1 | e0^2, e1^3, (e0*e1^-1)^2 > + Finitely presented group < e1, e2 | e2^2, e1^3, (e2*e1)^2 > sage: pi.order() 6 sage: pi.is_abelian() False - sage: RP6 = simplicial_sets.RealProjectiveSpace(6) - sage: RP6.homology(reduced=False, base_ring=GF(2)) + sage: RP6 = simplicial_sets.RealProjectiveSpace(6) # needs sage.groups + sage: RP6.homology(reduced=False, base_ring=GF(2)) # needs sage.groups sage.modules {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2, @@ -188,7 +188,7 @@ 4: Vector space of dimension 1 over Finite Field of size 2, 5: Vector space of dimension 1 over Finite Field of size 2, 6: Vector space of dimension 1 over Finite Field of size 2} - sage: RP6.homology(reduced=False, base_ring=QQ) + sage: RP6.homology(reduced=False, base_ring=QQ) # needs sage.groups sage.modules {0: Vector space of dimension 1 over Rational Field, 1: Vector space of dimension 0 over Rational Field, 2: Vector space of dimension 0 over Rational Field, @@ -201,20 +201,24 @@ by taking an `n`-skeleton for an appropriate `n`, either implicitly or explicitly:: - sage: B3 = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([3])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([3]) + sage: B3 = simplicial_sets.ClassifyingSpace(G) sage: B3.disjoint_union(B3).n_skeleton(3) - Disjoint union: (Simplicial set with 15 non-degenerate simplices u Simplicial set with 15 non-degenerate simplices) + Disjoint union: (Simplicial set with 15 non-degenerate simplices + u Simplicial set with 15 non-degenerate simplices) sage: S1 = simplicial_sets.Sphere(1) - sage: B3.product(S1).homology(range(4)) + sage: B3.product(S1).homology(range(4)) # needs sage.modules {0: 0, 1: Z x C3, 2: C3, 3: C3} Without the ``range`` argument, this would raise an error, since ``B3`` is infinite:: - sage: B3.product(S1).homology() + sage: B3.product(S1).homology() # needs sage.groups sage.modules Traceback (most recent call last): ... - NotImplementedError: this simplicial set may be infinite, so specify dimensions when computing homology + NotImplementedError: this simplicial set may be infinite, + so specify dimensions when computing homology It should be easy to construct many simplicial sets from the predefined ones using pushouts, pullbacks, etc., but they can also be @@ -232,7 +236,7 @@ ending at `w`. Therefore the first homology group of `X` should be a copy of the integers:: - sage: X.homology(1) + sage: X.homology(1) # needs sage.modules Z """ # **************************************************************************** @@ -254,25 +258,22 @@ import copy -from sage.graphs.graph import Graph -from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method from sage.misc.fast_methods import WithEqualityById +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.structure.parent import Parent from sage.structure.sage_object import SageObject -from sage.homology.algebraic_topological_model import algebraic_topological_model_delta_complex -from sage.homology.chain_complex import ChainComplex -from sage.homology.chains import Chains, Cochains from .cell_complex import GenericCellComplex from .delta_complex import DeltaComplex from .simplicial_complex import SimplicialComplex -from sage.misc.lazy_import import lazy_import lazy_import('sage.categories.simplicial_sets', 'SimplicialSets') +lazy_import('sage.matrix.constructor', 'matrix') + ######################################################################## # The classes for simplices. @@ -569,14 +570,13 @@ def __lt__(self, other): return True if self.degeneracies() and other.degeneracies() and self.degeneracies() != other.degeneracies(): return self.degeneracies() < other.degeneracies() - if hasattr(self.nondegenerate(), '__custom_name'): - if hasattr(other.nondegenerate(), '__custom_name'): - return str(self) < str(other) + if self.nondegenerate().get_custom_name() is not None: + if other.nondegenerate().get_custom_name() is not None: + return self.nondegenerate().get_custom_name() < other.nondegenerate().get_custom_name() return True - else: - if (hasattr(other, '__custom_name') - or hasattr(other.nondegenerate(), '__custom_name')): - return False + + if other.nondegenerate().get_custom_name() is not None: + return False return id(self) < id(other) def __gt__(self, other): @@ -753,7 +753,7 @@ def apply_degeneracies(self, *args): return self underlying = self.nondegenerate() return AbstractSimplex(underlying.dimension(), - degeneracies= list(args) + self.degeneracies(), + degeneracies=list(args) + self.degeneracies(), underlying=underlying) def __copy__(self): @@ -792,8 +792,8 @@ def __copy__(self): # dimension, the degeneracies, and the name (with a prime # added). sigma = AbstractSimplex(self._dim, degeneracies=self.degeneracies()) - if hasattr(self, '__custom_name'): - sigma.rename(str(self) + "'") + if self.get_custom_name() is not None: + sigma.rename(self.get_custom_name() + "'") return sigma def __deepcopy__(self, memo): @@ -820,6 +820,7 @@ def __deepcopy__(self, memo): The purpose for this method is to be able to make distinct copies of simplicial sets:: + sage: # needs sage.groups sage: from sage.topology.simplicial_set import SimplicialSet sage: RP3 = simplicial_sets.RealProjectiveSpace(3) sage: dict(copy.copy(RP3._data)) == dict(RP3._data) @@ -837,8 +838,8 @@ def __deepcopy__(self, memo): return memo[underlying].apply_degeneracies(*degens) except KeyError: sigma = AbstractSimplex(underlying._dim) - if hasattr(underlying, '__custom_name'): - sigma.rename(str(self) + "'") + if underlying.get_custom_name() is not None: + sigma.rename(underlying.get_custom_name() + "'") memo[underlying] = sigma return sigma.apply_degeneracies(*degens) @@ -894,12 +895,12 @@ def _latex_(self): """ if self._latex_name is not None: return self._latex_name - if hasattr(self, '__custom_name'): - return str(self) + if self.get_custom_name() is not None: + return self.get_custom_name() if self.nondegenerate()._latex_name is not None: simplex = self.nondegenerate()._latex_name - elif hasattr(self.nondegenerate(), '__custom_name'): - simplex = str(self.nondegenerate()) + elif self.nondegenerate().get_custom_name() is not None: + simplex = self.nondegenerate().get_custom_name() else: simplex = "\\Delta^{{{}}}".format(self._dim) if self.degeneracies(): @@ -1155,6 +1156,7 @@ def faces(self, simplex): sage: S2.faces(sigma.apply_degeneracies(0)) [sigma_2, sigma_2, s_1 s_0 v_0, s_1 s_0 v_0] + sage: # needs sage.groups sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: BC3 = simplicial_sets.ClassifyingSpace(C3) sage: f2 = BC3.n_cells(1)[1]; f2 @@ -1360,6 +1362,7 @@ def nondegenerate_simplices(self, max_dim=None): Test an infinite example:: + sage: # needs sage.groups sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: BC3 = simplicial_sets.ClassifyingSpace(C3) sage: BC3.nondegenerate_simplices(2) @@ -1424,6 +1427,7 @@ def cells(self, subcomplex=None, max_dim=None): Test an infinite example:: + sage: # needs sage.groups sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: BC3 = simplicial_sets.ClassifyingSpace(C3) sage: BC3.cells(max_dim=2) @@ -1474,9 +1478,9 @@ def n_cells(self, n, subcomplex=None): [sigma_3] sage: simplicial_sets.Sphere(3).n_cells(2) [] - sage: C2 = groups.misc.MultiplicativeAbelian([2]) - sage: BC2 = C2.nerve() - sage: BC2.n_cells(3) + sage: C2 = groups.misc.MultiplicativeAbelian([2]) # needs sage.groups + sage: BC2 = C2.nerve() # needs sage.groups + sage: BC2.n_cells(3) # needs sage.groups [f * f * f] """ cells = self.cells(subcomplex=subcomplex, max_dim=n) @@ -1534,9 +1538,9 @@ def all_n_simplices(self, n): An example involving an infinite simplicial set:: - sage: C3 = groups.misc.MultiplicativeAbelian([3]) - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) - sage: BC3.all_n_simplices(2) + sage: C3 = groups.misc.MultiplicativeAbelian([3]) # needs sage.groups + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # needs sage.groups + sage: BC3.all_n_simplices(2) # needs sage.groups [f * f, f * f^2, f^2 * f, @@ -1580,7 +1584,9 @@ def identity(self): Simplicial set endomorphism of S^3 Defn: Identity map - sage: BC3 = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([3])) + sage: # needs sage.groups + sage: C3 = groups.misc.MultiplicativeAbelian([3]) + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) sage: one = BC3.identity() sage: [(sigma, one(sigma)) for sigma in BC3.n_cells(2)] [(f * f, f * f), @@ -1620,8 +1626,8 @@ def constant_map(self, codomain=None, point=None): To: S^0 Defn: Constant map at v_0 - sage: Sigma3 = groups.permutation.Symmetric(3) - sage: Sigma3.nerve().constant_map() + sage: Sigma3 = groups.permutation.Symmetric(3) # needs sage.groups + sage: Sigma3.nerve().constant_map() # needs sage.groups Simplicial set morphism: From: Nerve of Symmetric group of order 3! as a permutation group To: Point @@ -1675,6 +1681,7 @@ def graph(self): sage: len(T.graph().edges(sort=False)) 3 + sage: # needs pyparsing sage: CP3 = simplicial_sets.ComplexProjectiveSpace(3) sage: G = CP3.graph() sage: len(G.vertices(sort=False)) @@ -1682,30 +1689,18 @@ def graph(self): sage: len(G.edges(sort=False)) 0 - sage: Sigma3 = groups.permutation.Symmetric(3) - sage: Sigma3.nerve().is_connected() - True - """ - skel = self.n_skeleton(1) - edges = skel.n_cells(1) - vertices = skel.n_cells(0) - used_vertices = set() # vertices which are in an edge - d = {} - for e in edges: - v = skel.face(e, 0) - w = skel.face(e, 1) - if v in d: - if w in d[v]: - d[v][w] = d[v][w] + [e] - else: - d[v][w] = [e] - else: - d[v] = {w: [e]} - used_vertices.update([v, w]) - for v in vertices: - if v not in used_vertices: - d[v] = {} - return Graph(d, format='dict_of_dicts') + sage: Sigma3 = groups.permutation.Symmetric(3) # needs sage.groups + sage: Sigma3.nerve().is_connected() # needs sage.groups + True + """ + from sage.graphs.graph import Graph + + G = Graph(loops=True, multiedges=True) + for e in self.n_cells(1): + G.add_edge(self.face(e, 0), self.face(e, 1), e) + for v in self.n_cells(0): + G.add_vertex(v) + return G def is_connected(self): """ @@ -1756,8 +1751,7 @@ def subsimplicial_set(self, simplices): sage: f = AbstractSimplex(1, name='f') sage: X = SimplicialSet({e: (v, w), f: (w, v)}) - sage: Y = X.subsimplicial_set([e]) - sage: Y + sage: Y = X.subsimplicial_set([e]); Y Simplicial set with 3 non-degenerate simplices sage: Y.nondegenerate_simplices() [v, w, e] @@ -1773,9 +1767,9 @@ def subsimplicial_set(self, simplices): A subsimplicial set knows about its ambient space and the inclusion map into it:: + sage: # needs sage.groups sage: RP4 = simplicial_sets.RealProjectiveSpace(4) - sage: M = RP4.n_skeleton(2) - sage: M + sage: M = RP4.n_skeleton(2); M Simplicial set with 3 non-degenerate simplices sage: M.ambient_space() RP^4 @@ -1787,7 +1781,9 @@ def subsimplicial_set(self, simplices): An infinite ambient simplicial set:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: BxB = B.product(B) sage: BxB.n_cells(2)[5:] [(s_0 f, s_1 f), (s_1 f, f * f), (s_1 f, s_0 f), (s_1 s_0 1, f * f)] @@ -1826,7 +1822,7 @@ def subsimplicial_set(self, simplices): sage: K = CP2.quotient(sub) sage: K.f_vector() [1, 0, 16, 30, 16] - sage: K.homology() + sage: K.homology() # needs sage.modules {0: 0, 1: 0, 2: Z, 3: 0, 4: Z} Try to construct a subcomplex from a simplicial complex which @@ -1876,7 +1872,7 @@ def subsimplicial_set(self, simplices): keep.update([f.nondegenerate() for f in data[underlying]]) else: # x is a vertex - assert(underlying.dimension() == 0) + assert underlying.dimension() == 0 vertices.add(underlying) missing = set(nondegenerate_simplices).difference(keep) for x in missing: @@ -1926,17 +1922,17 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, EXAMPLES:: - sage: simplicial_sets.Sphere(5).chain_complex() + sage: simplicial_sets.Sphere(5).chain_complex() # needs sage.modules Chain complex with at most 3 nonzero terms over Integer Ring - sage: C3 = groups.misc.MultiplicativeAbelian([3]) - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) - sage: BC3.chain_complex(range(4), base_ring=GF(3)) + sage: C3 = groups.misc.MultiplicativeAbelian([3]) # needs sage.groups + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # needs sage.groups + sage: BC3.chain_complex(range(4), base_ring=GF(3)) # needs sage.groups sage.modules Chain complex with at most 4 nonzero terms over Finite Field of size 3 TESTS:: - sage: BC3.chain_complex() + sage: BC3.chain_complex() # needs sage.groups Traceback (most recent call last): ... NotImplementedError: this simplicial set may be infinite, so specify dimensions when computing its chain complex @@ -1982,33 +1978,35 @@ def homology(self, dim=None, **kwds): EXAMPLES:: - sage: simplicial_sets.Sphere(5).homology() + sage: simplicial_sets.Sphere(5).homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: Z} - sage: C3 = groups.misc.MultiplicativeAbelian([3]) - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) - sage: BC3.homology(range(4), base_ring=GF(3)) + sage: C3 = groups.misc.MultiplicativeAbelian([3]) # needs sage.groups + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # needs sage.groups + sage: BC3.homology(range(4), base_ring=GF(3)) # needs sage.groups sage.modules {0: Vector space of dimension 0 over Finite Field of size 3, 1: Vector space of dimension 1 over Finite Field of size 3, 2: Vector space of dimension 1 over Finite Field of size 3, 3: Vector space of dimension 1 over Finite Field of size 3} - sage: BC2 = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: C2 = groups.misc.MultiplicativeAbelian([2]) + sage: BC2 = simplicial_sets.ClassifyingSpace(C2) sage: BK = BC2.product(BC2) - sage: BK.homology(range(4)) + sage: BK.homology(range(4)) # needs sage.modules {0: 0, 1: C2 x C2, 2: C2, 3: C2 x C2 x C2} TESTS:: sage: S3 = simplicial_sets.Sphere(3) - sage: S3.homology(0) + sage: S3.homology(0) # needs sage.modules 0 - sage: S3.homology((0,)) + sage: S3.homology((0,)) # needs sage.modules {0: 0} - sage: S3.homology(0, reduced=False) + sage: S3.homology(0, reduced=False) # needs sage.modules Z - sage: BC3.homology() + sage: BC3.homology() # needs sage.groups sage.modules Traceback (most recent call last): ... NotImplementedError: this simplicial set may be infinite, so specify dimensions when computing homology @@ -2024,7 +2022,7 @@ def homology(self, dim=None, **kwds): space = self.n_skeleton(max_dim+1) min_dim = min(dim) H = GenericCellComplex.homology(space, **kwds) - return {n: H[n] for n in H if n<=max_dim and n >= min_dim} + return {n: H[n] for n in H if min_dim <= n <= max_dim} else: max_dim = dim space = self.n_skeleton(max_dim+1) @@ -2064,21 +2062,22 @@ def cohomology(self, dim=None, **kwds): EXAMPLES:: - sage: simplicial_sets.KleinBottle().homology(1) + sage: simplicial_sets.KleinBottle().homology(1) # needs sage.modules Z x C2 - sage: simplicial_sets.KleinBottle().cohomology(1) + sage: simplicial_sets.KleinBottle().cohomology(1) # needs sage.modules Z - sage: simplicial_sets.KleinBottle().cohomology(2) + sage: simplicial_sets.KleinBottle().cohomology(2) # needs sage.modules C2 TESTS:: - sage: C3 = groups.misc.MultiplicativeAbelian([3]) - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) - sage: BC3.cohomology() + sage: C3 = groups.misc.MultiplicativeAbelian([3]) # needs sage.groups + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # needs sage.groups + sage: BC3.cohomology() # needs sage.groups Traceback (most recent call last): ... - NotImplementedError: this simplicial set may be infinite, so specify dimensions when computing homology + NotImplementedError: this simplicial set may be infinite, + so specify dimensions when computing homology """ return self.homology(dim=dim, cohomology=True, **kwds) @@ -2111,12 +2110,12 @@ def betti(self, dim=None, subcomplex=None): Build the two-sphere as a three-fold join of a two-point space with itself:: - sage: simplicial_sets.Sphere(5).betti() + sage: simplicial_sets.Sphere(5).betti() # needs sage.modules {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1} - sage: C3 = groups.misc.MultiplicativeAbelian([3]) - sage: BC3 = simplicial_sets.ClassifyingSpace(C3) - sage: BC3.betti(range(4)) + sage: C3 = groups.misc.MultiplicativeAbelian([3]) # needs sage.groups + sage: BC3 = simplicial_sets.ClassifyingSpace(C3) # needs sage.groups + sage: BC3.betti(range(4)) # needs sage.groups sage.modules {0: 1, 1: 0, 2: 0, 3: 0} """ dict = {} @@ -2153,20 +2152,25 @@ def n_chains(self, n, base_ring=ZZ, cochains=False): EXAMPLES:: sage: S3 = simplicial_sets.Sphere(3) - sage: C = S3.n_chains(3, cochains=True) - sage: list(C.basis()) + sage: C = S3.n_chains(3, cochains=True) # needs sage.modules + sage: list(C.basis()) # needs sage.modules [\chi_sigma_3] + + sage: # needs sage.groups sage: Sigma3 = groups.permutation.Symmetric(3) sage: BSigma3 = simplicial_sets.ClassifyingSpace(Sigma3) - sage: list(BSigma3.n_chains(1).basis()) + sage: list(BSigma3.n_chains(1).basis()) # needs sage.modules [(1,2), (1,2,3), (1,3), (1,3,2), (2,3)] - sage: list(BSigma3.n_chains(1, cochains=True).basis()) + sage: list(BSigma3.n_chains(1, cochains=True).basis()) # needs sage.modules [\chi_(1,2), \chi_(1,2,3), \chi_(1,3), \chi_(1,3,2), \chi_(2,3)] """ if self.is_finite(): return GenericCellComplex.n_chains(self, n=n, base_ring=base_ring, cochains=cochains) + + from sage.homology.chains import Chains, Cochains + n_cells = tuple(self.n_cells(n)) if cochains: return Cochains(self, n, n_cells, base_ring) @@ -2208,14 +2212,14 @@ def quotient(self, subcomplex, vertex_name='*'): sage: Y = X.quotient([f]) sage: Y.nondegenerate_simplices() [*, e] - sage: Y.homology(1) + sage: Y.homology(1) # needs sage.modules Z sage: E = SimplicialSet({e: (v, w)}) sage: Z = E.quotient([v, w]) sage: Z.nondegenerate_simplices() [*, e] - sage: Z.homology(1) + sage: Z.homology(1) # needs sage.modules Z sage: F = E.quotient([v]) @@ -2224,17 +2228,17 @@ def quotient(self, subcomplex, vertex_name='*'): sage: F.base_point() * + sage: # needs sage.groups sage: RP5 = simplicial_sets.RealProjectiveSpace(5) sage: RP2 = RP5.n_skeleton(2) sage: RP5_2 = RP5.quotient(RP2) - sage: RP5_2.homology(base_ring=GF(2)) + sage: RP5_2.homology(base_ring=GF(2)) # needs sage.modules {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 0 over Finite Field of size 2, 2: Vector space of dimension 0 over Finite Field of size 2, 3: Vector space of dimension 1 over Finite Field of size 2, 4: Vector space of dimension 1 over Finite Field of size 2, 5: Vector space of dimension 1 over Finite Field of size 2} - sage: RP5_2.ambient() RP^5 sage: RP5_2.subcomplex() @@ -2243,7 +2247,8 @@ def quotient(self, subcomplex, vertex_name='*'): Simplicial set morphism: From: RP^5 To: Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) - Defn: [1, f, f * f, f * f * f, f * f * f * f, f * f * f * f * f] --> [*, s_0 *, s_1 s_0 *, f * f * f, f * f * f * f, f * f * f * f * f] + Defn: [1, f, f * f, f * f * f, f * f * f * f, f * f * f * f * f] + --> [*, s_0 *, s_1 s_0 *, f * f * f, f * f * f * f, f * f * f * f * f] Behavior of base points:: @@ -2267,10 +2272,9 @@ def quotient(self, subcomplex, vertex_name='*'): TESTS:: - sage: pt = RP5.quotient(RP5.n_skeleton(5)) - sage: pt + sage: pt = RP5.quotient(RP5.n_skeleton(5)); pt # needs sage.groups Quotient: (RP^5/RP^5) - sage: len(pt.nondegenerate_simplices()) + sage: len(pt.nondegenerate_simplices()) # needs sage.groups 1 """ from .simplicial_set_constructions import SubSimplicialSet @@ -2285,7 +2289,7 @@ def quotient(self, subcomplex, vertex_name='*'): # Test whether subcomplex is actually a subcomplex of # self. if (not isinstance(subcomplex, SubSimplicialSet) - and subcomplex.ambient_space() == self): + and subcomplex.ambient_space() == self): raise ValueError('the "subcomplex" is not actually a subcomplex') if self.is_finite(): return QuotientOfSimplicialSet_finite(subcomplex.inclusion_map(), @@ -2377,6 +2381,7 @@ def coproduct(self, *others): sage: Y = S2.unset_base_point() sage: Z = K.unset_base_point() + sage: sage: S2.coproduct(K).is_pointed() True sage: S2.coproduct(K) @@ -2384,7 +2389,8 @@ def coproduct(self, *others): sage: D3.coproduct(Y, Z).is_pointed() False sage: D3.coproduct(Y, Z) - Disjoint union: (3-simplex u Simplicial set with 2 non-degenerate simplices u Simplicial set with 6 non-degenerate simplices) + Disjoint union: (3-simplex u Simplicial set with 2 non-degenerate simplices + u Simplicial set with 6 non-degenerate simplices) The coproduct comes equipped with an inclusion map from each summand, as long as the summands are all finite:: @@ -2397,15 +2403,19 @@ def coproduct(self, *others): sage: D3.coproduct(Y, Z).inclusion_map(2) Simplicial set morphism: From: Simplicial set with 6 non-degenerate simplices - To: Disjoint union: (3-simplex u Simplicial set with 2 non-degenerate simplices u Simplicial set with 6 non-degenerate simplices) - Defn: [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] --> [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] + To: Disjoint union: (3-simplex + u Simplicial set with 2 non-degenerate simplices + u Simplicial set with 6 non-degenerate simplices) + Defn: [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] + --> [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] TESTS:: sage: D3.coproduct(S2, Z) Traceback (most recent call last): ... - ValueError: some, but not all, of the simplicial sets are pointed, so the categorical coproduct is not defined: the category is ambiguous + ValueError: some, but not all, of the simplicial sets are pointed, + so the categorical coproduct is not defined: the category is ambiguous """ if self.is_pointed() and all(X.is_pointed() for X in others): return self.wedge(*others) @@ -2454,7 +2464,7 @@ def product(self, *others): sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) - sage: T.homology(reduced=False) + sage: T.homology(reduced=False) # needs sage.modules {0: Z, 1: Z x Z, 2: Z} Since ``S1`` is pointed, so is ``T``:: @@ -2471,7 +2481,7 @@ def product(self, *others): sage: S2 = simplicial_sets.Sphere(2) sage: S3 = simplicial_sets.Sphere(3) sage: S2xS3 = S2.product(S3) - sage: S2xS3.homology(reduced=False) + sage: S2xS3.homology(reduced=False) # needs sage.modules {0: Z, 1: 0, 2: Z, 3: Z, 4: 0, 5: Z} sage: S2xS3.factors() == (S2, S3) @@ -2479,10 +2489,11 @@ def product(self, *others): sage: S2xS3.factors() == (S3, S2) False - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: B.rename('RP^oo') - sage: X = B.product(B, S2) - sage: X + sage: X = B.product(B, S2); X RP^oo x RP^oo x S^2 sage: X.factor(1) RP^oo @@ -2496,7 +2507,7 @@ def product(self, *others): From: S^2 x S^3 To: S^2 Defn: ... - sage: S2xS3.wedge_as_subset().homology() + sage: S2xS3.wedge_as_subset().homology() # needs sage.modules {0: 0, 1: 0, 2: Z, 3: Z} In the case of pointed simplicial sets, there is an inclusion @@ -2554,8 +2565,7 @@ def pushout(self, *maps): sage: K = simplicial_sets.Simplex(4) sage: L = K.n_skeleton(3) - sage: S4 = L.pushout(L.constant_map(), L.inclusion_map()) - sage: S4 + sage: S4 = L.pushout(L.constant_map(), L.inclusion_map()); S4 Pushout of maps: Simplicial set morphism: From: Simplicial set with 30 non-degenerate simplices @@ -2564,10 +2574,22 @@ def pushout(self, *maps): Simplicial set morphism: From: Simplicial set with 30 non-degenerate simplices To: 4-simplex - Defn: [(0,), (1,), (2,), (3,), (4,), (0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4), (0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 3), (0, 2, 4), (0, 3, 4), (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), (0, 1, 2, 3), (0, 1, 2, 4), (0, 1, 3, 4), (0, 2, 3, 4), (1, 2, 3, 4)] --> [(0,), (1,), (2,), (3,), (4,), (0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4), (0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 3), (0, 2, 4), (0, 3, 4), (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), (0, 1, 2, 3), (0, 1, 2, 4), (0, 1, 3, 4), (0, 2, 3, 4), (1, 2, 3, 4)] + Defn: [(0,), (1,), (2,), (3,), (4,), + (0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), + (2, 3), (2, 4), (3, 4), + (0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 3), (0, 2, 4), + (0, 3, 4), (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), + (0, 1, 2, 3), (0, 1, 2, 4), (0, 1, 3, 4), (0, 2, 3, 4), + (1, 2, 3, 4)] + --> [(0,), (1,), (2,), (3,), (4,), + (0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), + (2, 3), (2, 4), (3, 4), + (0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 3), (0, 2, 4), (0, 3, 4), + (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), + (0, 1, 2, 3), (0, 1, 2, 4), (0, 1, 3, 4), (0, 2, 3, 4), (1, 2, 3, 4)] sage: len(S4.nondegenerate_simplices()) 2 - sage: S4.homology(4) + sage: S4.homology(4) # needs sage.modules Z The associated maps:: @@ -2575,7 +2597,7 @@ def pushout(self, *maps): sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) sage: K = T.factor(0, as_subset=True) - sage: W = S1.wedge(T) # wedge, constructed as a pushout + sage: W = S1.wedge(T) # wedge, constructed as a pushout sage: W.defining_map(1) Simplicial set morphism: From: Point @@ -2587,7 +2609,8 @@ def pushout(self, *maps): To: Wedge: (S^1 v S^1 x S^1) Defn: [v_0, sigma_1] --> [*, sigma_1] - sage: f = S1.Hom(T)({S1.n_cells(0)[0]:K.n_cells(0)[0], S1.n_cells(1)[0]:K.n_cells(1)[0]}) + sage: f = S1.Hom(T)({S1.n_cells(0)[0]: K.n_cells(0)[0], + ....: S1.n_cells(1)[0]: K.n_cells(1)[0]}) The maps `f: S^1 \to T` and `1: T \to T` induce a map `S^1 \vee T \to T`:: @@ -2660,7 +2683,7 @@ def pullback(self, *maps): sage: S2 = simplicial_sets.Sphere(2) sage: pt = simplicial_sets.Point() sage: P = pt.pullback(S2.constant_map(), S2.constant_map()) - sage: P.homology(2) + sage: P.homology(2) # needs sage.modules Z x Z If the pullback is defined via maps `f_i: X_i \to Y`, then @@ -2671,7 +2694,7 @@ def pullback(self, *maps): sage: S2 = simplicial_sets.Sphere(2) sage: one = S2.Hom(S2).identity() sage: P = S2.pullback(one, one) - sage: P.homology() + sage: P.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} sage: P.defining_map(0) == one @@ -2695,9 +2718,10 @@ def pullback(self, *maps): sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) sage: K = T.factor(0, as_subset=True) - sage: f = S1.Hom(T)({S1.n_cells(0)[0]:K.n_cells(0)[0], S1.n_cells(1)[0]:K.n_cells(1)[0]}) - sage: D = S1.cone() # the cone C(S^1) - sage: g = D.map_from_base() # map from S^1 to C(S^1) + sage: f = S1.Hom(T)({S1.n_cells(0)[0]: K.n_cells(0)[0], + ....: S1.n_cells(1)[0]: K.n_cells(1)[0]}) + sage: D = S1.cone() # the cone C(S^1) + sage: g = D.map_from_base() # map from S^1 to C(S^1) sage: P = T.product(D) sage: h = P.universal_property(f, g) sage: h.domain() == S1 @@ -2756,10 +2780,10 @@ def wedge(self, *others): sage: W = X.wedge(Y) sage: W.nondegenerate_simplices() [*, e, f] - sage: W.homology() + sage: W.homology() # needs sage.modules {0: 0, 1: Z x Z} sage: S2 = simplicial_sets.Sphere(2) - sage: X.wedge(S2).homology(reduced=False) + sage: X.wedge(S2).homology(reduced=False) # needs sage.modules {0: Z, 1: Z, 2: Z} sage: X.wedge(X).nondegenerate_simplices() [*, e, e] @@ -2884,6 +2908,7 @@ def suspension(self, n=1): EXAMPLES:: + sage: # needs sage.groups sage: RP4 = simplicial_sets.RealProjectiveSpace(4) sage: S1 = simplicial_sets.Sphere(1) sage: SigmaRP4 = RP4.suspension() @@ -2895,14 +2920,14 @@ def suspension(self, n=1): typically less efficient than the reduced suspension produced here:: - sage: SigmaRP4.f_vector() + sage: SigmaRP4.f_vector() # needs sage.groups [1, 0, 1, 1, 1, 1] - sage: S1_smash_RP4.f_vector() + sage: S1_smash_RP4.f_vector() # needs sage.groups [1, 1, 4, 6, 8, 5] TESTS:: - sage: RP4.suspension(-3) + sage: RP4.suspension(-3) # needs sage.groups Traceback (most recent call last): ... ValueError: n must be non-negative @@ -3232,7 +3257,7 @@ def __init__(self, data, base_point=None, name=None, check=True, sage: skip = ["_test_pickling", "_test_elements"] sage: TestSuite(S1).run(skip=skip) sage: TestSuite(simplicial_sets.Sphere(5)).run(skip=skip) - sage: TestSuite(simplicial_sets.RealProjectiveSpace(6)).run(skip=skip) + sage: TestSuite(simplicial_sets.RealProjectiveSpace(6)).run(skip=skip) # needs sage.groups """ def face(sigma, i): """ @@ -3314,7 +3339,7 @@ def face(sigma, i): for x in simplices: if x not in data: # x had better be a vertex. - assert(x.dimension() == 0) + assert x.dimension() == 0 data[x] = None # Check the simplicial identity d_i d_j = d_{j-1} d_i. @@ -3449,7 +3474,7 @@ def __copy__(self): False sage: T.n_cells(0)[0] == copy(T).n_cells(0)[0] False - sage: T.homology() == copy(T).homology() + sage: T.homology() == copy(T).homology() # needs sage.modules True """ return SimplicialSet(dict(copy.deepcopy(self._data))) @@ -3569,7 +3594,7 @@ def euler_characteristic(self): EXAMPLES:: - sage: simplicial_sets.RealProjectiveSpace(4).euler_characteristic() + sage: simplicial_sets.RealProjectiveSpace(4).euler_characteristic() # needs sage.groups 1 sage: simplicial_sets.Sphere(6).euler_characteristic() 2 @@ -3617,11 +3642,12 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, EXAMPLES:: + sage: # needs sage.modules sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0) sage: degen = v.apply_degeneracies(1, 0) # s_1 s_0 applied to v sage: sigma = AbstractSimplex(3) - sage: S3 = SimplicialSet({sigma: (degen, degen, degen, degen)}) # the 3-sphere + sage: S3 = SimplicialSet({sigma: (degen, degen, degen, degen)}) # the 3-sphere sage: S3.chain_complex().homology() {0: Z, 3: Z} sage: S3.chain_complex(augmented=True).homology() @@ -3629,9 +3655,9 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, sage: S3.chain_complex(dimensions=range(3), base_ring=QQ).homology() {0: Vector space of dimension 1 over Rational Field} - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) - sage: RP2 = RP5.n_skeleton(2) - sage: RP5.chain_complex(subcomplex=RP2).homology() + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups + sage: RP2 = RP5.n_skeleton(2) # needs sage.groups + sage: RP5.chain_complex(subcomplex=RP2).homology() # needs sage.groups sage.modules {0: Z, 3: C2, 4: 0, 5: Z} TESTS: @@ -3639,17 +3665,21 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, Convert some simplicial complexes and `\Delta`-complexes to simplicial sets, and compare homology calculations:: + sage: # needs sage.modules sage: T = simplicial_complexes.Torus() sage: T.homology() == SimplicialSet(T).homology() True sage: RP2 = delta_complexes.RealProjectivePlane() sage: RP2.homology() == SimplicialSet(RP2).homology() True - sage: RP2.cohomology(base_ring=GF(2)) == SimplicialSet(RP2).cohomology(base_ring=GF(2)) + sage: cohoRP2 = RP2.cohomology(base_ring=GF(2)) + sage: cohoRP2 == SimplicialSet(RP2).cohomology(base_ring=GF(2)) True """ + from sage.homology.chain_complex import ChainComplex + if dimensions is None: - if not self.cells(): # Empty + if not self.cells(): # Empty if cochain: return ChainComplex({-1: matrix(base_ring, 0, 0)}, degree_of_differential=1) @@ -3696,13 +3726,13 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, if augmented and first == 0: differentials[first-1] = matrix(base_ring, 0, 1) differentials[first] = matrix(base_ring, 1, rank, - [1] * rank) + [1] * rank) else: differentials[first] = matrix(base_ring, 0, rank) for d in dimensions: old_rank = rank - faces = {_[1]:_[0] for _ in enumerate(current)} + faces = {_[1]: _[0] for _ in enumerate(current)} if d in simplices: current = sorted(simplices[d]) rank = len(current) @@ -3783,19 +3813,22 @@ def algebraic_topological_model(self, base_ring=None): EXAMPLES:: - sage: RP2 = simplicial_sets.RealProjectiveSpace(2) - sage: phi, M = RP2.algebraic_topological_model(GF(2)) - sage: M.homology() + sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # needs sage.groups + sage: phi, M = RP2.algebraic_topological_model(GF(2)) # needs sage.groups + sage: M.homology() # needs sage.groups sage.modules {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} + sage: T = simplicial_sets.Torus() - sage: phi, M = T.algebraic_topological_model(QQ) - sage: M.homology() + sage: phi, M = T.algebraic_topological_model(QQ) # needs sage.modules + sage: M.homology() # needs sage.modules {0: Vector space of dimension 1 over Rational Field, 1: Vector space of dimension 2 over Rational Field, 2: Vector space of dimension 1 over Rational Field} """ + from sage.homology.algebraic_topological_model import algebraic_topological_model_delta_complex + if base_ring is None: base_ring = QQ return algebraic_topological_model_delta_complex(self, base_ring) @@ -3873,6 +3906,7 @@ def standardize_degeneracies(*L): J[idx + 1] = tmp return tuple(J) + def all_degeneracies(n, l=1): r""" Return list of all composites of degeneracies (written in @@ -3915,6 +3949,7 @@ def all_degeneracies(n, l=1): for _ in all_degeneracies(n, l-1)])) return ans + def standardize_face_maps(*L): r""" Return list of indices of face maps in standard (non-increasing) @@ -3961,6 +3996,7 @@ def standardize_face_maps(*L): J[idx + 1] = tmp return tuple(J) + def face_degeneracies(m, I): r""" Return the result of applying the face map `d_m` to the iterated @@ -4011,7 +4047,7 @@ def face_degeneracies(m, I): for i in I: if t is None: J.append(i) - elif t<i: + elif t < i: J.append(i-1) elif t == i or t == i+1: t = None @@ -4042,23 +4078,24 @@ def shrink_simplicial_complex(K): [1] sage: Y = simplicial_complexes.Sphere(2) - sage: S2 = shrink_simplicial_complex(Y) - sage: S2 - Quotient: (Simplicial set with 14 non-degenerate simplices/Simplicial set with 13 non-degenerate simplices) + sage: S2 = shrink_simplicial_complex(Y); S2 + Quotient: (Simplicial set with + 14 non-degenerate simplices/Simplicial set with + 13 non-degenerate simplices) sage: S2.f_vector() [1, 0, 1] - sage: S2.homology() + sage: S2.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} sage: Z = simplicial_complexes.SurfaceOfGenus(3) sage: Z.f_vector() [1, 15, 57, 38] - sage: Z.homology() + sage: Z.homology() # needs sage.modules {0: 0, 1: Z^6, 2: Z} sage: M = shrink_simplicial_complex(Z) - sage: M.f_vector() # random + sage: M.f_vector() # random [1, 32, 27] - sage: M.homology() + sage: M.homology() # needs sage.modules {0: 0, 1: Z^6, 2: Z} """ L = K._contractible_subcomplex() diff --git a/src/sage/topology/simplicial_set_catalog.py b/src/sage/topology/simplicial_set_catalog.py index 70607a1ab41..0269c8f6628 100644 --- a/src/sage/topology/simplicial_set_catalog.py +++ b/src/sage/topology/simplicial_set_catalog.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Catalog of simplicial sets @@ -26,20 +27,22 @@ - the Hopf map: this is a pre-built morphism, from which one can extract its domain, codomain, mapping cone, etc. +- the complex of a group presentation. + All of these examples are accessible by typing ``simplicial_sets.NAME``, where ``NAME`` is the name of the example. Type ``simplicial_sets.[TAB]`` for a complete list. EXAMPLES:: - sage: RP10 = simplicial_sets.RealProjectiveSpace(8) - sage: RP10.homology() + sage: RP10 = simplicial_sets.RealProjectiveSpace(8) # needs sage.groups + sage: RP10.homology() # needs sage.groups sage.modules {0: 0, 1: C2, 2: 0, 3: C2, 4: 0, 5: C2, 6: 0, 7: C2, 8: 0} sage: eta = simplicial_sets.HopfMap() sage: S3 = eta.domain() sage: S2 = eta.codomain() - sage: S3.wedge(S2).homology() + sage: S3.wedge(S2).homology() # needs sage.modules {0: 0, 1: 0, 2: Z, 3: Z} """ @@ -48,4 +51,4 @@ KleinBottle, Torus, Simplex, Horn, Point, ComplexProjectiveSpace, - HopfMap) + HopfMap, PresentationComplex) diff --git a/src/sage/topology/simplicial_set_constructions.py b/src/sage/topology/simplicial_set_constructions.py index 454a7334e0b..3a217286ac5 100644 --- a/src/sage/topology/simplicial_set_constructions.py +++ b/src/sage/topology/simplicial_set_constructions.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Methods of constructing simplicial sets @@ -74,7 +74,6 @@ import itertools -from sage.graphs.graph import Graph from sage.misc.latex import latex from sage.sets.set import Set from sage.structure.parent import Parent @@ -88,6 +87,7 @@ from sage.misc.lazy_import import lazy_import lazy_import('sage.categories.simplicial_sets', 'SimplicialSets') + ######################################################################## # classes which inherit from SimplicialSet_arbitrary @@ -145,7 +145,7 @@ def __init__(self, data, ambient=None): sage: S3 = simplicial_sets.Sphere(3) sage: K = simplicial_sets.KleinBottle() sage: X = S3.disjoint_union(K) - sage: Y = X.structure_map(0).image() # the S3 summand + sage: Y = X.structure_map(0).image() # the S3 summand sage: Y.inclusion_map() Simplicial set morphism: From: Simplicial set with 2 non-degenerate simplices @@ -170,20 +170,19 @@ def __init__(self, data, ambient=None): if ambient is None: ambient = self if (ambient.is_pointed() - and hasattr(ambient, '_basepoint') - and ambient.base_point() in data): + and hasattr(ambient, '_basepoint') + and ambient.base_point() in data): SimplicialSet_finite.__init__(self, data, base_point=ambient.base_point()) else: SimplicialSet_finite.__init__(self, data) if self == ambient: - if hasattr(ambient, '__custom_name'): - self.rename(str(ambient)) + self.rename(ambient.get_custom_name()) self._latex_name = latex(ambient) # When constructing the inclusion map, we do not need to check # the validity of the morphism, and more importantly, we # cannot check it in the infinite case: the appropriate data # may not have yet been constructed. So use "check=False". - self._inclusion = self.Hom(ambient)({x:x for x in data}, check=False) + self._inclusion = self.Hom(ambient)({x: x for x in data}, check=False) def inclusion_map(self): r""" @@ -192,9 +191,9 @@ def inclusion_map(self): EXAMPLES:: - sage: RP6 = simplicial_sets.RealProjectiveSpace(6) - sage: K = RP6.n_skeleton(2) - sage: K.inclusion_map() + sage: RP6 = simplicial_sets.RealProjectiveSpace(6) # needs sage.groups + sage: K = RP6.n_skeleton(2) # needs sage.groups + sage: K.inclusion_map() # needs sage.groups Simplicial set morphism: From: Simplicial set with 3 non-degenerate simplices To: RP^6 @@ -203,7 +202,7 @@ def inclusion_map(self): `RP^6` itself is constructed as a subsimplicial set of `RP^\infty`:: - sage: latex(RP6.inclusion_map()) + sage: latex(RP6.inclusion_map()) # needs sage.groups RP^{6} \to RP^{\infty} """ return self._inclusion @@ -218,7 +217,7 @@ def ambient_space(self): sage: eight = T.wedge_as_subset() sage: eight Simplicial set with 3 non-degenerate simplices - sage: eight.fundamental_group() + sage: eight.fundamental_group() # needs sage.groups Finitely presented group < e0, e1 | > sage: eight.ambient_space() Torus @@ -268,10 +267,11 @@ def __init__(self, maps=None): base point map gives a simplicial set isomorphic to the original subcomplex:: + sage: # needs sage.groups sage: RP5 = simplicial_sets.RealProjectiveSpace(5) sage: K = RP5.quotient(RP5.n_skeleton(2)) sage: X = K.pullback(K.quotient_map(), K.base_point_map()) - sage: X.homology() == RP5.n_skeleton(2).homology() + sage: X.homology() == RP5.n_skeleton(2).homology() # needs sage.modules True Pullbacks of identity maps:: @@ -279,7 +279,7 @@ def __init__(self, maps=None): sage: S2 = simplicial_sets.Sphere(2) sage: one = S2.Hom(S2).identity() sage: P = S2.pullback(one, one) - sage: P.homology() + sage: P.homology() # needs sage.modules {0: 0, 1: 0, 2: Z} The pullback is constructed in terms of the product -- of @@ -320,7 +320,9 @@ def n_skeleton(self, n): EXAMPLES:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: one = Hom(B,B).identity() sage: c = Hom(B,B).constant_map() sage: P = B.pullback(one, c) @@ -330,7 +332,7 @@ def n_skeleton(self, n): Defn: Identity map Simplicial set endomorphism of Simplicial set with 3 non-degenerate simplices Defn: Constant map at 1 - sage: P.n_skeleton(3).homology() + sage: P.n_skeleton(3).homology() # needs sage.modules {0: 0, 1: C2, 2: 0, 3: Z} """ if self.is_finite(): @@ -363,6 +365,7 @@ def defining_map(self, i): EXAMPLES:: + sage: # needs sage.groups sage: RP5 = simplicial_sets.RealProjectiveSpace(5) sage: K = RP5.quotient(RP5.n_skeleton(2)) sage: Y = K.pullback(K.quotient_map(), K.base_point_map()) @@ -445,7 +448,9 @@ def __init__(self, maps=None): sage: S2.pullback(eta, c).is_finite() True - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: one = Hom(B,B).identity() sage: c = Hom(B,B).constant_map() sage: B.pullback(one, c).is_finite() @@ -475,7 +480,7 @@ def __init__(self, maps=None): f = maps[0] if f.is_pointed(): SimplicialSet_finite.__init__(self, f.domain().face_data(), - base_point=f.domain().base_point()) + base_point=f.domain().base_point()) else: SimplicialSet_finite.__init__(self, f.domain().face_data()) self._maps = (f,) @@ -498,7 +503,7 @@ def __init__(self, maps=None): # the product. translate = {} for simplices in itertools.product(*nondegen): - dims = [_.dimension() for _ in simplices] + dims = [s.dimension() for s in simplices] dim_max = max(dims) sum_dims = sum(dims) for d in range(dim_max, sum_dims + 1): @@ -519,7 +524,7 @@ def __init__(self, maps=None): sigma = simplices[0].apply_degeneracies(*degens[0]) target = maps[0](sigma) if any(target != f(tau.apply_degeneracies(*degen)) - for (f, tau, degen) in zip(maps[1:], simplices[1:], degens[1:])): + for (f, tau, degen) in zip(maps[1:], simplices[1:], degens[1:])): continue simplex_factors = tuple(zip(simplices, tuple(degens))) @@ -615,6 +620,7 @@ def structure_map(self, i): EXAMPLES:: + sage: # needs sage.groups sage: RP5 = simplicial_sets.RealProjectiveSpace(5) sage: K = RP5.quotient(RP5.n_skeleton(2)) sage: Y = K.pullback(K.quotient_map(), K.base_point_map()) @@ -624,7 +630,8 @@ def structure_map(self, i): Simplicial set morphism: From: RP^5 To: Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) - Defn: [1, f, f * f, f * f * f, f * f * f * f, f * f * f * f * f] --> [*, s_0 *, s_1 s_0 *, f * f * f, f * f * f * f, f * f * f * f * f] + Defn: [1, f, f * f, f * f * f, f * f * f * f, f * f * f * f * f] + --> [*, s_0 *, s_1 s_0 *, f * f * f, f * f * f * f, f * f * f * f * f] Simplicial set morphism: From: Point To: Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) @@ -634,9 +641,9 @@ def structure_map(self, i): sage: Y.structure_map(1).codomain() Point - These maps are also accessible via ``projection_map``:: + These maps are also accessible via :meth:`projection_map`:: - sage: Y.projection_map(1).codomain() + sage: Y.projection_map(1).codomain() # needs sage.groups Point """ if len(self._maps) == 1: @@ -668,7 +675,8 @@ def universal_property(self, *maps): sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) sage: K = T.factor(0, as_subset=True) - sage: f = S1.Hom(T)({S1.n_cells(0)[0]:K.n_cells(0)[0], S1.n_cells(1)[0]:K.n_cells(1)[0]}) + sage: f = S1.Hom(T)({S1.n_cells(0)[0]: K.n_cells(0)[0], + ....: S1.n_cells(1)[0]: K.n_cells(1)[0]}) sage: P = S1.product(T) sage: P.universal_property(S1.Hom(S1).identity(), f) Simplicial set morphism: @@ -684,13 +692,13 @@ def universal_property(self, *maps): if any(g.domain() != domain for g in maps[1:]): raise ValueError('the maps do not all have the same codomain') composite = self._maps[0] * maps[0] - if any(f*g != composite for f,g in zip(self._maps[1:], maps[1:])): + if any(f*g != composite for f, g in zip(self._maps[1:], maps[1:])): raise ValueError('the maps are not compatible') data = {} translate = dict(self._translation) for sigma in domain.nondegenerate_simplices(): target = tuple([(f(sigma).nondegenerate(), tuple(f(sigma).degeneracies())) - for f in maps]) + for f in maps]) # If there any degeneracies in common, remove them: the # dictionary "translate" has nondegenerate simplices as # its keys. @@ -703,6 +711,7 @@ def universal_property(self, *maps): data[sigma] = translate[target].apply_degeneracies(*in_common) return domain.Hom(self)(data) + class Factors(): """ Classes which inherit from this should define a ``_factors`` @@ -741,7 +750,10 @@ def factor(self, i): sage: K = S2.disjoint_union(S3) sage: K.factor(0) S^2 - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: X = B.wedge(S3, B) sage: X.factor(1) S^3 @@ -816,7 +828,7 @@ def __init__(self, factors=None): sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) - sage: T.homology(reduced=False) + sage: T.homology(reduced=False) # needs sage.modules {0: Z, 1: Z x Z, 2: Z} Since ``S1`` is pointed, so is ``T``:: @@ -833,24 +845,25 @@ def __init__(self, factors=None): sage: S2 = simplicial_sets.Sphere(2) sage: S3 = simplicial_sets.Sphere(3) sage: Z = S2.product(S3) - sage: Z.homology() + sage: Z.homology() # needs sage.modules {0: 0, 1: 0, 2: Z, 3: Z, 4: 0, 5: Z} Products involving infinite simplicial sets:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: B.rename('RP^oo') - sage: X = B.product(B) - sage: X + sage: X = B.product(B); X RP^oo x RP^oo sage: X.n_cells(1) [(f, f), (f, s_0 1), (s_0 1, f)] - sage: X.homology(range(3), base_ring=GF(2)) + sage: X.homology(range(3), base_ring=GF(2)) # needs sage.modules {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 2 over Finite Field of size 2, 2: Vector space of dimension 3 over Finite Field of size 2} sage: Y = B.product(S2) - sage: Y.homology(range(5), base_ring=GF(2)) + sage: Y.homology(range(5), base_ring=GF(2)) # needs sage.modules {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 2 over Finite Field of size 2, @@ -882,7 +895,10 @@ def n_skeleton(self, n): sage: S3 = simplicial_sets.Sphere(3) sage: S2.product(S3).n_skeleton(2) Simplicial set with 2 non-degenerate simplices - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: X = B.product(B) sage: X.n_skeleton(2) Simplicial set with 13 non-degenerate simplices @@ -930,7 +946,7 @@ def factor(self, i, as_subset=False): sage: K.factor(0, as_subset=True) Simplicial set with 2 non-degenerate simplices - sage: K.factor(0, as_subset=True).homology() + sage: K.factor(0, as_subset=True).homology() # needs sage.modules {0: 0, 1: 0, 2: Z} sage: K.factor(0) is S2 @@ -945,7 +961,7 @@ def factor(self, i, as_subset=False): basept_factors = [sset.base_point() for sset in self.factors()] basept_factors = basept_factors[:i] + basept_factors[i+1:] - to_factors = dict((v,k) for k,v in self._translation) + to_factors = {v: k for k, v in self._translation} simps = [] for x in self.nondegenerate_simplices(): simplices = [sigma[0] for sigma in to_factors[x]] @@ -962,10 +978,11 @@ def _repr_(self): sage: S2 = simplicial_sets.Sphere(2) sage: K = simplicial_sets.KleinBottle() - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: G = groups.misc.MultiplicativeAbelian([2]) # needs sage.groups + sage: B = simplicial_sets.ClassifyingSpace(G) # needs sage.groups sage: S2.product(S2) S^2 x S^2 - sage: S2.product(K, B) + sage: S2.product(K, B) # needs sage.groups S^2 x Klein bottle x Classifying space of Multiplicative Abelian group isomorphic to C2 """ return ' x '.join(str(X) for X in self._factors) @@ -979,8 +996,8 @@ def _latex_(self): sage: S2 = simplicial_sets.Sphere(2) sage: latex(S2.product(S2)) S^{2} \times S^{2} - sage: RPoo = simplicial_sets.RealProjectiveSpace(Infinity) - sage: latex(S2.product(RPoo, S2)) + sage: RPoo = simplicial_sets.RealProjectiveSpace(Infinity) # needs sage.groups + sage: latex(S2.product(RPoo, S2)) # needs sage.groups S^{2} \times RP^{\infty} \times S^{2} """ return ' \\times '.join(latex(X) for X in self._factors) @@ -1009,7 +1026,7 @@ def __init__(self, factors=None): sage: e = AbstractSimplex(1) sage: X = SimplicialSet({e: (v, v)}) sage: W = X.product(X, X) - sage: W.homology() + sage: W.homology() # needs sage.groups {0: 0, 1: Z x Z x Z, 2: Z x Z x Z, 3: Z} sage: W.is_pointed() False @@ -1041,7 +1058,9 @@ def projection_map(self, i): sage: T = simplicial_sets.Torus() sage: f_0 = T.projection_map(0) sage: f_1 = T.projection_map(1) - sage: m_0 = f_0.induced_homology_morphism().to_matrix(1) # matrix in dim 1 + + sage: # needs sage.modules + sage: m_0 = f_0.induced_homology_morphism().to_matrix(1) # matrix in dim 1 sage: m_1 = f_1.induced_homology_morphism().to_matrix(1) sage: m_0.rank() 1 @@ -1070,11 +1089,11 @@ def wedge_as_subset(self): sage: W = P.wedge_as_subset() sage: W.nondegenerate_simplices() [(v, w), (e, s_0 w), (s_0 v, f)] - sage: W.homology() + sage: W.homology() # needs sage.modules {0: 0, 1: Z x Z} """ basept_factors = [sset.base_point() for sset in self.factors()] - to_factors = dict((v,k) for k,v in self._translation) + to_factors = {v: k for k, v in self._translation} simps = [] for x in self.nondegenerate_simplices(): simplices = to_factors[x] @@ -1102,7 +1121,7 @@ def fat_wedge_as_subset(self): sage: S1 = simplicial_sets.Sphere(1) sage: X = S1.product(S1, S1) sage: W = X.fat_wedge_as_subset() - sage: W.homology() + sage: W.homology() # needs sage.modules {0: 0, 1: Z x Z x Z, 2: Z x Z x Z} """ basept_factors = [sset.base_point() for sset in self.factors()] @@ -1224,7 +1243,7 @@ def __init__(self, maps=None, vertex_name=None): sage: CT = T.cone() sage: inc = CT.base_as_subset().inclusion_map() sage: P = T.pushout(inc, inc) - sage: P.homology() + sage: P.homology() # needs sage.modules {0: 0, 1: 0, 2: Z x Z, 3: Z} sage: len(P.nondegenerate_simplices()) 20 @@ -1244,8 +1263,10 @@ def __init__(self, maps=None, vertex_name=None): sage: S1 = simplicial_sets.Sphere(1) sage: pt = simplicial_sets.Point() - sage: bouquet = pt.pushout(S1.base_point_map(), S1.base_point_map(), S1.base_point_map()) - sage: bouquet.homology(1) + sage: bouquet = pt.pushout(S1.base_point_map(), + ....: S1.base_point_map(), + ....: S1.base_point_map()) + sage: bouquet.homology(1) # needs sage.modules Z x Z x Z """ # Import this here to prevent circular imports. @@ -1279,10 +1300,12 @@ def n_skeleton(self, n): EXAMPLES:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: K = B.n_skeleton(3) sage: Q = K.pushout(K.inclusion_map(), K.constant_map()) - sage: Q.n_skeleton(5).homology() + sage: Q.n_skeleton(5).homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: Z, 5: Z} Of course, computing the `n`-skeleton and then taking homology @@ -1290,7 +1313,7 @@ def n_skeleton(self, n): dimension `n`, since the latter computation will use the `(n+1)`-skeleton:: - sage: Q.homology(range(6)) + sage: Q.homology(range(6)) # needs sage.groups sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: Z, 5: C2} """ if self.is_finite(): @@ -1328,7 +1351,7 @@ def defining_map(self, i): sage: S1 = simplicial_sets.Sphere(1) sage: T = simplicial_sets.Torus() - sage: X = S1.wedge(T) # a pushout + sage: X = S1.wedge(T) # a pushout sage: X.defining_map(0) Simplicial set morphism: From: Point @@ -1417,6 +1440,8 @@ def __init__(self, maps=None, vertex_name=None): sage: PushoutOfSimplicialSets_finite([T.base_point_map(), S2.base_point_map()], vertex_name='v').n_cells(0)[0] v """ + from sage.graphs.graph import Graph + # Import this here to prevent circular imports. from sage.topology.simplicial_set_morphism import SimplicialSetMorphism if maps and any(not isinstance(f, SimplicialSetMorphism) for f in maps): @@ -1432,25 +1457,25 @@ def __init__(self, maps=None, vertex_name=None): f = maps[0] codomain = f.codomain() if f.is_pointed(): - base_point=codomain.base_point() + base_point = codomain.base_point() if vertex_name is not None: base_point.rename(vertex_name) SimplicialSet_finite.__init__(self, codomain.face_data(), - base_point=base_point) + base_point=base_point) elif len(domain.nondegenerate_simplices()) == 1: # X is a point. base_point = f(domain().n_cells(0)[0]) if vertex_name is not None: base_point.rename(vertex_name) SimplicialSet_finite.__init__(self, codomain.face_data(), - base_point=base_point) + base_point=base_point) elif len(codomain.nondegenerate_simplices()) == 1: # Y is a point. base_point = codomain.n_cells(0)[0] if vertex_name is not None: base_point.rename(vertex_name) SimplicialSet_finite.__init__(self, codomain.face_data(), - base_point=base_point) + base_point=base_point) else: SimplicialSet_finite.__init__(self, codomain.face_data()) self._maps = (f,) @@ -1464,12 +1489,12 @@ def __init__(self, maps=None, vertex_name=None): # spaces: indexed list of spaces. Entries are of the form # (space, int) where int=-1 for the domain, and for the # codomains, int is the corresponding index. - spaces = [(Y,i-1) for (i,Y) in enumerate([domain] + codomains)] + spaces = [(Y, i-1) for i, Y in enumerate([domain] + codomains)] # Dictionaries to translate from simplices in domain, # codomains to simplices in the pushout. The keys are of the # form (space, int). int=-1 for the domain, and for the # codomains, int is the corresponding index. - _to_P = {Y:{} for Y in spaces} + _to_P = {Y: {} for Y in spaces} max_dim = max(Y.dimension() for Y in codomains) for n in range(1 + max_dim): # Now we impose an equivalence relation on the simplices, @@ -1479,13 +1504,13 @@ def __init__(self, maps=None, vertex_name=None): # of the graph are the n-cells of X and the Y_i, and # there are edges from x to f_i(x). vertices = [] - for (Y,i) in spaces: - vertices.extend([(cell,i) for cell in Y.n_cells(n)]) + for Y, i in spaces: + vertices.extend([(cell, i) for cell in Y.n_cells(n)]) edges = [] for x in domain.n_cells(n): - edges.extend([[(x,-1), (f(x),i)] for (i,f) in enumerate(maps)]) + edges.extend([[(x, -1), (f(x), i)] for i, f in enumerate(maps)]) G = Graph([vertices, edges], format='vertices_and_edges') - data[n] = [set(_) for _ in G.connected_components()] + data[n] = [set(_) for _ in G.connected_components(sort=False)] # data is now a dictionary indexed by dimension, and data[n] # consists of sets of n-simplices of the domain and the # codomains, each set an equivalence class of n-simplices @@ -1504,17 +1529,17 @@ def __init__(self, maps=None, vertex_name=None): degens = sigma.degeneracies() space = spaces[j+1] old = _to_P[space][sigma.nondegenerate()] - for (sigma,j) in s: + for sigma, j in s: # Now update the _to_P[space] dictionaries. space = spaces[j+1] _to_P[space][sigma] = old.apply_degeneracies(*degens) - else: # nondegenerate + else: # nondegenerate if len(s) == 1: name = str(list(s)[0][0]) latex_name = latex(list(s)[0][0]) else: # Choose a name from a simplex in domain. - for (sigma,j) in sorted(s): + for sigma, j in sorted(s): if j == -1: name = str(sigma) latex_name = latex(sigma) @@ -1523,7 +1548,7 @@ def __init__(self, maps=None, vertex_name=None): latex_name=latex_name) if dim == 0: faces = None - for (sigma,j) in s: + for sigma, j in s: space = spaces[j+1] _to_P[space][sigma] = new if dim > 0: @@ -1534,28 +1559,28 @@ def __init__(self, maps=None, vertex_name=None): some_Y_is_pt = False if len(domain.nondegenerate_simplices()) > 1: # Only investigate this if X is not empty and not a point. - for (Y,i) in spaces: + for Y, i in spaces: if len(Y.nondegenerate_simplices()) == 1: some_Y_is_pt = True break if len(domain.nondegenerate_simplices()) == 1: # X is a point. - base_point = _to_P[(domain,-1)][domain.n_cells(0)[0]] + base_point = _to_P[(domain, -1)][domain.n_cells(0)[0]] if vertex_name is not None: base_point.rename(vertex_name) SimplicialSet_finite.__init__(self, simplices, base_point=base_point) elif some_Y_is_pt: # We found (Y,i) above. - base_point = _to_P[(Y,i)][Y.n_cells(0)[0]] + base_point = _to_P[(Y, i)][Y.n_cells(0)[0]] if vertex_name is not None: base_point.rename(vertex_name) SimplicialSet_finite.__init__(self, simplices, base_point=base_point) elif all(f.is_pointed() for f in maps): - pt = _to_P[(codomains[0],0)][codomains[0].base_point()] - if any(_to_P[(Y,i)][Y.base_point()] != pt for (Y,i) in spaces[2:]): + pt = _to_P[(codomains[0], 0)][codomains[0].base_point()] + if any(_to_P[(Y, i)][Y.base_point()] != pt for Y, i in spaces[2:]): raise ValueError('something unexpected went wrong ' 'with base points') - base_point = _to_P[(domain,-1)][domain.base_point()] + base_point = _to_P[(domain, -1)][domain.base_point()] if vertex_name is not None: base_point.rename(vertex_name) SimplicialSet_finite.__init__(self, simplices, base_point=base_point) @@ -1563,8 +1588,8 @@ def __init__(self, maps=None, vertex_name=None): SimplicialSet_finite.__init__(self, simplices) # The relevant maps: self._maps = maps - self._structure = tuple([Y.Hom(self)(_to_P[(Y,i)]) - for (Y,i) in spaces[1:]]) + self._structure = tuple([Y.Hom(self)(_to_P[(Y, i)]) + for Y, i in spaces[1:]]) self._vertex_name = vertex_name def structure_map(self, i): @@ -1583,7 +1608,7 @@ def structure_map(self, i): sage: S1 = simplicial_sets.Sphere(1) sage: T = simplicial_sets.Torus() - sage: X = S1.disjoint_union(T) # a pushout + sage: X = S1.disjoint_union(T) # a pushout sage: X.structure_map(0) Simplicial set morphism: From: S^1 @@ -1624,11 +1649,13 @@ def universal_property(self, *maps): sage: Y_1 = SimplicialSet({evx: (x, v)}) sage: f_0 = Hom(X, Y_0)({v:v, w:w, x:x, evw:evw, evx:evx}) - sage: f_1 = Hom(X, Y_1)({v:v, w:v, x:x, evw:v.apply_degeneracies(0), evx:evx}) + sage: f_1 = Hom(X, Y_1)({v:v, w:v, x:x, + ....: evw:v.apply_degeneracies(0), evx:evx}) sage: P = X.pushout(f_0, f_1) sage: one = Hom(Y_1, Y_1).identity() - sage: g = Hom(Y_0, Y_1)({v:v, w:v, x:x, evw:v.apply_degeneracies(0), evx:evx, ewx:evx}) + sage: g = Hom(Y_0, Y_1)({v:v, w:v, x:x, + ....: evw:v.apply_degeneracies(0), evx:evx, ewx:evx}) sage: P.universal_property(g, one) Simplicial set morphism: From: Pushout of maps: @@ -1647,10 +1674,10 @@ def universal_property(self, *maps): if any(g.codomain() != codomain for g in maps[1:]): raise ValueError('the maps do not all have the same codomain') composite = maps[0] * self._maps[0] - if any(g*f != composite for g,f in zip(maps[1:], self._maps[1:])): + if any(g*f != composite for g, f in zip(maps[1:], self._maps[1:])): raise ValueError('the maps are not compatible') data = {} - for i,g in enumerate(maps): + for i, g in enumerate(maps): f_i_dict = self.structure_map(i)._dictionary for sigma in f_i_dict: tau = f_i_dict[sigma] @@ -1682,16 +1709,17 @@ def __init__(self, inclusion, vertex_name='*'): EXAMPLES:: + sage: # needs sage.groups sage: RP5 = simplicial_sets.RealProjectiveSpace(5) sage: RP2 = RP5.n_skeleton(2) - sage: RP5_2 = RP5.quotient(RP2) - sage: RP5_2 + sage: RP5_2 = RP5.quotient(RP2); RP5_2 Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) sage: RP5_2.quotient_map() Simplicial set morphism: From: RP^5 To: Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) - Defn: [1, f, f * f, f * f * f, f * f * f * f, f * f * f * f * f] --> [*, s_0 *, s_1 s_0 *, f * f * f, f * f * f * f, f * f * f * f * f] + Defn: [1, f, f * f, f * f * f, f * f * f * f, f * f * f * f * f] + --> [*, s_0 *, s_1 s_0 *, f * f * f, f * f * f * f, f * f * f * f * f] """ subcomplex = inclusion.domain() PushoutOfSimplicialSets.__init__(self, [inclusion, @@ -1711,13 +1739,16 @@ def ambient(self): EXAMPLES:: + sage: # needs sage.groups sage: RP5 = simplicial_sets.RealProjectiveSpace(5) sage: RP2 = RP5.n_skeleton(2) sage: RP5_2 = RP5.quotient(RP2) sage: RP5_2.ambient() RP^5 - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: K = B.n_skeleton(3) sage: Q = B.quotient(K) sage: Q.ambient() @@ -1733,13 +1764,16 @@ def subcomplex(self): EXAMPLES:: + sage: # needs sage.groups sage: RP5 = simplicial_sets.RealProjectiveSpace(5) sage: RP2 = RP5.n_skeleton(2) sage: RP5_2 = RP5.quotient(RP2) sage: RP5_2.subcomplex() Simplicial set with 3 non-degenerate simplices - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: K = B.n_skeleton(3) sage: Q = B.quotient(K) sage: Q.subcomplex() @@ -1763,12 +1797,16 @@ def n_skeleton(self, n): EXAMPLES:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: K = B.n_skeleton(3) sage: Q = B.quotient(K) sage: Q.n_skeleton(6) - Quotient: (Simplicial set with 7 non-degenerate simplices/Simplicial set with 4 non-degenerate simplices) - sage: Q.n_skeleton(6).homology() + Quotient: (Simplicial set with 7 + non-degenerate simplices/Simplicial set with 4 + non-degenerate simplices) + sage: Q.n_skeleton(6).homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: 0, 4: Z, 5: C2, 6: 0} """ if self.is_finite(): @@ -1807,6 +1845,7 @@ def _latex_(self): EXAMPLES:: + sage: # needs sage.groups sage: RPoo = simplicial_sets.RealProjectiveSpace(Infinity) sage: RP3 = RPoo.n_skeleton(3) sage: RP3.rename_latex('RP^{3}') @@ -1832,16 +1871,17 @@ def __init__(self, inclusion, vertex_name='*'): EXAMPLES:: + sage: # needs sage.groups sage: RP5 = simplicial_sets.RealProjectiveSpace(5) sage: RP2 = RP5.n_skeleton(2) - sage: RP5_2 = RP5.quotient(RP2) - sage: RP5_2 + sage: RP5_2 = RP5.quotient(RP2); RP5_2 Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) sage: RP5_2.quotient_map() Simplicial set morphism: From: RP^5 To: Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) - Defn: [1, f, f * f, f * f * f, f * f * f * f, f * f * f * f * f] --> [*, s_0 *, s_1 s_0 *, f * f * f, f * f * f * f, f * f * f * f * f] + Defn: [1, f, f * f, f * f * f, f * f * f * f, f * f * f * f * f] + --> [*, s_0 *, s_1 s_0 *, f * f * f, f * f * f * f, f * f * f * f * f] """ subcomplex = inclusion.domain() PushoutOfSimplicialSets_finite.__init__(self, [inclusion, @@ -1912,7 +1952,7 @@ def __init__(self, factors=None): sage: T = simplicial_sets.Torus() sage: S2 = simplicial_sets.Sphere(2) - sage: T.smash_product(S2).homology() == T.suspension(2).homology() + sage: T.smash_product(S2).homology() == T.suspension(2).homology() # needs sage.modules True """ if any(not space.is_pointed() for space in factors): @@ -1928,9 +1968,9 @@ def _repr_(self): EXAMPLES:: - sage: RP4 = simplicial_sets.RealProjectiveSpace(4) + sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # needs sage.groups sage: S1 = simplicial_sets.Sphere(1) - sage: S1.smash_product(RP4, S1) + sage: S1.smash_product(RP4, S1) # needs sage.groups Smash product: (S^1 ^ RP^4 ^ S^1) """ s = 'Smash product: (' @@ -1944,9 +1984,9 @@ def _latex_(self): EXAMPLES:: - sage: RP4 = simplicial_sets.RealProjectiveSpace(4) + sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # needs sage.groups sage: S1 = simplicial_sets.Sphere(1) - sage: latex(S1.smash_product(RP4, S1)) + sage: latex(S1.smash_product(RP4, S1)) # needs sage.groups S^{1} \wedge RP^{4} \wedge S^{1} """ return ' \\wedge '.join(latex(X) for X in self._factors) @@ -1991,20 +2031,21 @@ def __init__(self, factors=None): sage: CP2 = simplicial_sets.ComplexProjectiveSpace(2) sage: K = simplicial_sets.KleinBottle() sage: W = CP2.wedge(K) - sage: W.homology() + sage: W.homology() # needs sage.modules {0: 0, 1: Z x C2, 2: Z, 3: 0, 4: Z} sage: W.inclusion_map(1) Simplicial set morphism: From: Klein bottle To: Wedge: (CP^2 v Klein bottle) - Defn: [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] --> [*, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] + Defn: [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] + --> [*, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] sage: W.projection_map(0).domain() Wedge: (CP^2 v Klein bottle) sage: W.projection_map(0).codomain() # copy of CP^2 Quotient: (Wedge: (CP^2 v Klein bottle)/Simplicial set with 6 non-degenerate simplices) - sage: W.projection_map(0).codomain().homology() + sage: W.projection_map(0).codomain().homology() # needs sage.modules {0: 0, 1: 0, 2: Z, 3: 0, 4: Z} An error occurs if any of the factors is not pointed:: @@ -2049,9 +2090,9 @@ def _latex_(self): EXAMPLES:: - sage: RP4 = simplicial_sets.RealProjectiveSpace(4) + sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # needs sage.groups sage: S1 = simplicial_sets.Sphere(1) - sage: latex(S1.wedge(RP4, S1)) + sage: latex(S1.wedge(RP4, S1)) # needs sage.groups S^{1} \vee RP^{4} \vee S^{1} """ return ' \\vee '.join(latex(X) for X in self._factors) @@ -2126,18 +2167,19 @@ def projection_map(self, i): sage: W.projection_map(1) Simplicial set morphism: From: Wedge: (S^1 v S^2 v S^1) - To: Quotient: (Wedge: (S^1 v S^2 v S^1)/Simplicial set with 3 non-degenerate simplices) + To: Quotient: (Wedge: (S^1 v S^2 v S^1)/Simplicial set with + 3 non-degenerate simplices) Defn: [*, sigma_1, sigma_1, sigma_2] --> [*, s_0 *, s_0 *, sigma_2] - sage: W.projection_map(1).image().homology(1) + sage: W.projection_map(1).image().homology(1) # needs sage.modules 0 - sage: W.projection_map(1).image().homology(2) + sage: W.projection_map(1).image().homology(2) # needs sage.modules Z """ m = len(self._factors) simplices = ([self.inclusion_map(j).image().nondegenerate_simplices() for j in range(i)] + [self.inclusion_map(j).image().nondegenerate_simplices() - for j in range(i+1,m)]) + for j in range(i+1, m)]) return self.quotient(list(itertools.chain(*simplices))).quotient_map() @@ -2180,14 +2222,15 @@ def __init__(self, factors=None): sage: CP2 = simplicial_sets.ComplexProjectiveSpace(2) sage: K = simplicial_sets.KleinBottle() sage: W = CP2.disjoint_union(K) - sage: W.homology() + sage: W.homology() # needs sage.modules {0: Z, 1: Z x C2, 2: Z, 3: 0, 4: Z} sage: W.inclusion_map(1) Simplicial set morphism: From: Klein bottle To: Disjoint union: (CP^2 u Klein bottle) - Defn: [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] --> [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] + Defn: [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] + --> [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] """ PushoutOfSimplicialSets.__init__(self, [space._map_from_empty_set() for space in factors]) @@ -2211,10 +2254,12 @@ def n_skeleton(self, n): EXAMPLES:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: T = simplicial_sets.Torus() sage: X = B.disjoint_union(T) - sage: X.n_skeleton(3).homology() + sage: X.n_skeleton(3).homology() # needs sage.modules {0: Z, 1: Z x Z x C2, 2: Z, 3: Z} """ if self.is_finite(): @@ -2240,8 +2285,8 @@ def _repr_(self): EXAMPLES:: sage: T = simplicial_sets.Torus() - sage: RP3 = simplicial_sets.RealProjectiveSpace(3) - sage: T.disjoint_union(T, RP3) + sage: RP3 = simplicial_sets.RealProjectiveSpace(3) # needs sage.groups + sage: T.disjoint_union(T, RP3) # needs sage.groups Disjoint union: (Torus u Torus u RP^3) """ s = 'Disjoint union: (' @@ -2255,9 +2300,9 @@ def _latex_(self): EXAMPLES:: - sage: RP4 = simplicial_sets.RealProjectiveSpace(4) + sage: RP4 = simplicial_sets.RealProjectiveSpace(4) # needs sage.groups sage: S1 = simplicial_sets.Sphere(1) - sage: latex(S1.disjoint_union(RP4, S1)) + sage: latex(S1.disjoint_union(RP4, S1)) # needs sage.groups S^{1} \amalg RP^{4} \amalg S^{1} """ return ' \\amalg '.join(latex(X) for X in self._factors) @@ -2372,10 +2417,12 @@ def n_skeleton(self, n): EXAMPLES:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: X = B.disjoint_union(B) sage: CX = B.cone() - sage: CX.n_skeleton(3).homology() + sage: CX.n_skeleton(3).homology() # needs sage.modules {0: 0, 1: 0, 2: 0, 3: Z} """ if self.is_finite(): @@ -2478,6 +2525,7 @@ def base_as_subset(self): EXAMPLES:: + sage: # needs sage.groups sage: X = simplicial_sets.RealProjectiveSpace(4).unset_base_point() sage: Y = X.cone() sage: Y.base_as_subset() @@ -2500,7 +2548,8 @@ def map_from_base(self): Simplicial set morphism: From: Simplicial set with 6 non-degenerate simplices To: Cone of Simplicial set with 6 non-degenerate simplices - Defn: [(0,), (1,), (2,), (0, 1), (0, 2), (1, 2)] --> [(0,), (1,), (2,), (0, 1), (0, 2), (1, 2)] + Defn: [(0,), (1,), (2,), (0, 1), (0, 2), (1, 2)] + --> [(0,), (1,), (2,), (0, 1), (0, 2), (1, 2)] """ return self.base_as_subset().inclusion_map() @@ -2562,8 +2611,9 @@ def n_skeleton(self, n): EXAMPLES:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) - sage: B.cone().n_skeleton(3).homology() + sage: G = groups.misc.MultiplicativeAbelian([2]) # needs sage.groups + sage: B = simplicial_sets.ClassifyingSpace(G) # needs sage.groups + sage: B.cone().n_skeleton(3).homology() # needs sage.groups sage.modules {0: 0, 1: 0, 2: 0, 3: Z} """ if self.is_finite(): @@ -2641,7 +2691,7 @@ def __init__(self, base): QuotientOfSimplicialSet_finite.__init__(self, inc) self._base = base q = self.quotient_map() - self._joins = {sigma:q(C._joins[sigma]) for sigma in C._joins} + self._joins = {sigma: q(C._joins[sigma]) for sigma in C._joins} def map_from_base(self): r""" @@ -2691,10 +2741,12 @@ def __init__(self, base): EXAMPLES:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: B.suspension() Sigma(Classifying space of Multiplicative Abelian group isomorphic to C2) - sage: B.suspension().n_skeleton(3).homology() + sage: B.suspension().n_skeleton(3).homology() # needs sage.modules {0: 0, 1: 0, 2: C2, 3: 0} If ``X`` is finite, the suspension comes with a quotient map @@ -2714,7 +2766,7 @@ def __init__(self, base): True sage: S3.suspension() == simplicial_sets.Sphere(3).suspension() False - sage: B.suspension() == B.suspension() + sage: B.suspension() == B.suspension() # needs sage.groups True """ Cat = SimplicialSets() @@ -2747,9 +2799,11 @@ def n_skeleton(self, n): EXAMPLES:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: SigmaB = B.suspension() - sage: SigmaB.n_skeleton(4).homology(base_ring=GF(2)) + sage: SigmaB.n_skeleton(4).homology(base_ring=GF(2)) # needs sage.modules {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 0 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2, diff --git a/src/sage/topology/simplicial_set_examples.py b/src/sage/topology/simplicial_set_examples.py index 279cf8b7c7d..2bb46ac1f5a 100644 --- a/src/sage/topology/simplicial_set_examples.py +++ b/src/sage/topology/simplicial_set_examples.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.graphs r""" Examples of simplicial sets. @@ -9,6 +9,8 @@ AUTHORS: - John H. Palmieri (2016-07) + +- Miguel Marco (2022-12) """ # **************************************************************************** # Copyright (C) 2016 John H. Palmieri <palmieri at math.washington.edu> @@ -29,10 +31,8 @@ import re import os -from pyparsing import OneOrMore, nestedExpr from sage.env import SAGE_ENV -from sage.groups.abelian_gps.abelian_group import AbelianGroup from sage.misc.cachefunc import cached_method, cached_function from sage.misc.latex import latex from sage.rings.infinity import Infinity @@ -48,7 +48,8 @@ from sage.misc.lazy_import import lazy_import lazy_import('sage.categories.simplicial_sets', 'SimplicialSets') -######################################################################## + +# ###################################################################### # The nerve of a finite monoid, used in sage.categories.finite_monoid. class Nerve(SimplicialSet_arbitrary): @@ -106,6 +107,7 @@ def __eq__(self, other): EXAMPLES:: + sage: # needs sage.groups sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: C3.nerve() == C3.nerve() False @@ -123,6 +125,7 @@ def __ne__(self, other): EXAMPLES:: + sage: # needs sage.groups sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: G3 = groups.permutation.Cyclic(3) sage: C3.nerve() != G3.nerve() @@ -139,12 +142,13 @@ def __hash__(self): EXAMPLES:: - sage: G3 = groups.permutation.Cyclic(3) - sage: hash(G3.nerve()) # random + sage: G3 = groups.permutation.Cyclic(3) # needs sage.groups + sage: hash(G3.nerve()) # random # needs sage.groups 17 Different instances yield different base points, hence different hashes:: + sage: # needs sage.groups sage: X = G3.nerve() sage: Y = G3.nerve() sage: X.base_point() != Y.base_point() @@ -167,6 +171,7 @@ def n_skeleton(self, n): EXAMPLES:: + sage: # needs sage.groups sage: K4 = groups.misc.MultiplicativeAbelian([2,2]) sage: BK4 = simplicial_sets.ClassifyingSpace(K4) sage: BK4.n_skeleton(3) @@ -225,7 +230,7 @@ def n_skeleton(self, n): # constructor. x = AbstractSimplex(d, name=' * '.join(str(_) for _ in chain), - latex_name = ' * '.join(latex(_) for _ in chain)) + latex_name=' * '.join(latex(_) for _ in chain)) new_faces[chain] = x # Compute faces of x. @@ -238,7 +243,7 @@ def n_skeleton(self, n): face = e.apply_degeneracies(i) else: face = (face_dict[chain[:i] - + chain[i+2:]].apply_degeneracies(i)) + + chain[i+2:]].apply_degeneracies(i)) else: # Non-degenerate. face = (face_dict[chain[:i] @@ -288,7 +293,7 @@ def Sphere(n): if n == 0: w_0 = AbstractSimplex(0, name='w_0') return SimplicialSet_finite({v_0: None, w_0: None}, base_point=v_0, - name='S^0') + name='S^0') degens = range(n-2, -1, -1) degen_v = v_0.apply_degeneracies(*degens) sigma = AbstractSimplex(n, name='sigma_{}'.format(n), @@ -312,17 +317,17 @@ def ClassifyingSpace(group): EXAMPLES:: + sage: # needs sage.groups sage: C2 = groups.misc.MultiplicativeAbelian([2]) sage: BC2 = simplicial_sets.ClassifyingSpace(C2) - sage: H = BC2.homology(range(9), base_ring=GF(2)) - sage: [H[i].dimension() for i in range(9)] + sage: H = BC2.homology(range(9), base_ring=GF(2)) # needs sage.modules + sage: [H[i].dimension() for i in range(9)] # needs sage.modules [0, 1, 1, 1, 1, 1, 1, 1, 1] - sage: Klein4 = groups.misc.MultiplicativeAbelian([2, 2]) - sage: BK = simplicial_sets.ClassifyingSpace(Klein4) - sage: BK + sage: Klein4 = groups.misc.MultiplicativeAbelian([2, 2]) # needs sage.groups + sage: BK = simplicial_sets.ClassifyingSpace(Klein4); BK # needs sage.groups Classifying space of Multiplicative Abelian group isomorphic to C2 x C2 - sage: BK.homology(range(5), base_ring=GF(2)) # long time (1 second) + sage: BK.homology(range(5), base_ring=GF(2)) # long time (1 second) # needs sage.groups sage.modules {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 2 over Finite Field of size 2, 2: Vector space of dimension 3 over Finite Field of size 2, @@ -344,6 +349,7 @@ def RealProjectiveSpace(n): EXAMPLES:: + sage: # needs sage.groups sage: simplicial_sets.RealProjectiveSpace(7) RP^7 sage: RP5 = simplicial_sets.RealProjectiveSpace(5) @@ -354,11 +360,13 @@ def RealProjectiveSpace(n): sage: latex(RP5) RP^{5} - sage: BC2 = simplicial_sets.RealProjectiveSpace(Infinity) - sage: latex(BC2) + sage: BC2 = simplicial_sets.RealProjectiveSpace(Infinity) # needs sage.groups + sage: latex(BC2) # needs sage.groups RP^{\infty} """ if n == Infinity: + from sage.groups.abelian_gps.abelian_group import AbelianGroup + X = AbelianGroup([2]).nerve() X.rename('RP^oo') X.rename_latex('RP^{\\infty}') @@ -381,7 +389,7 @@ def KleinBottle(): sage: K = simplicial_sets.KleinBottle() sage: K.f_vector() [1, 3, 2] - sage: K.homology(reduced=False) + sage: K.homology(reduced=False) # needs sage.modules {0: Z, 1: Z x C2, 2: 0} sage: K Klein bottle @@ -389,7 +397,7 @@ def KleinBottle(): temp = SimplicialSet_finite(delta_complexes.KleinBottle()) pt = temp.n_cells(0)[0] return SimplicialSet_finite(temp.face_data(), base_point=pt, - name='Klein bottle') + name='Klein bottle') def Torus(): @@ -406,7 +414,7 @@ def Torus(): sage: T = simplicial_sets.Torus() sage: T.f_vector() [1, 3, 2] - sage: T.homology(reduced=False) + sage: T.homology(reduced=False) # needs sage.modules {0: Z, 1: Z x Z, 2: Z} """ S1 = Sphere(1) @@ -530,25 +538,25 @@ def ComplexProjectiveSpace(n): EXAMPLES:: - sage: simplicial_sets.ComplexProjectiveSpace(2).homology(reduced=False) + sage: simplicial_sets.ComplexProjectiveSpace(2).homology(reduced=False) # needs sage.modules {0: Z, 1: 0, 2: Z, 3: 0, 4: Z} - sage: CP3 = simplicial_sets.ComplexProjectiveSpace(3) - sage: CP3 + sage: CP3 = simplicial_sets.ComplexProjectiveSpace(3); CP3 # needs pyparsing CP^3 - sage: latex(CP3) + sage: latex(CP3) # needs pyparsing CP^{3} - sage: CP3.f_vector() + sage: CP3.f_vector() # needs pyparsing [1, 0, 3, 10, 25, 30, 15] - sage: K = CP3.suspension() # long time (1 second) - sage: R = K.cohomology_ring(GF(2)) # long time - sage: R.gens() # long time + sage: # long time, needs pyparsing sage.modules + sage: K = CP3.suspension() # long time (1 second) + sage: R = K.cohomology_ring(GF(2)) + sage: R.gens() (h^{0,0}, h^{3,0}, h^{5,0}, h^{7,0}) - sage: x = R.gens()[1] # long time - sage: x.Sq(2) # long time + sage: x = R.gens()[1] + sage: x.Sq(2) h^{5,0} - sage: simplicial_sets.ComplexProjectiveSpace(4).f_vector() + sage: simplicial_sets.ComplexProjectiveSpace(4).f_vector() # needs pyparsing [1, 0, 4, 22, 97, 255, 390, 315, 105] sage: simplicial_sets.ComplexProjectiveSpace(5) @@ -581,31 +589,31 @@ def ComplexProjectiveSpace(n): f4_201110 = AbstractSimplex(4, name='tau_1', latex_name='\\tau_1') f4_211010 = AbstractSimplex(4, name='tau_2', latex_name='\\tau_2') K = SimplicialSet_finite({f2_1: (v.apply_degeneracies(0), - v.apply_degeneracies(0), - v.apply_degeneracies(0)), - f2_2: (v.apply_degeneracies(0), - v.apply_degeneracies(0), - v.apply_degeneracies(0)), - f3_110: (f2_1, f2_2, f2_1, v.apply_degeneracies(1, 0)), - f3_011: (f2_1, f2_1, f2_1, f2_1), - f3_111: (v.apply_degeneracies(1, 0), f2_1, f2_2, f2_1), - f4_101101: (f2_1.apply_degeneracies(0), - f2_1.apply_degeneracies(0), - f3_011, - f2_1.apply_degeneracies(2), - f2_1.apply_degeneracies(2)), - f4_201110: (f2_1.apply_degeneracies(1), - f3_111, - f3_011, - f3_110, - f2_1.apply_degeneracies(1)), - f4_211010: (f2_1.apply_degeneracies(2), - f3_111, - f2_1.apply_degeneracies(1), - f3_110, - f2_1.apply_degeneracies(0))}, - base_point=v, name='CP^2', - latex_name='CP^{2}') + v.apply_degeneracies(0), + v.apply_degeneracies(0)), + f2_2: (v.apply_degeneracies(0), + v.apply_degeneracies(0), + v.apply_degeneracies(0)), + f3_110: (f2_1, f2_2, f2_1, v.apply_degeneracies(1, 0)), + f3_011: (f2_1, f2_1, f2_1, f2_1), + f3_111: (v.apply_degeneracies(1, 0), f2_1, f2_2, f2_1), + f4_101101: (f2_1.apply_degeneracies(0), + f2_1.apply_degeneracies(0), + f3_011, + f2_1.apply_degeneracies(2), + f2_1.apply_degeneracies(2)), + f4_201110: (f2_1.apply_degeneracies(1), + f3_111, + f3_011, + f3_110, + f2_1.apply_degeneracies(1)), + f4_211010: (f2_1.apply_degeneracies(2), + f3_111, + f2_1.apply_degeneracies(1), + f3_110, + f2_1.apply_degeneracies(0))}, + base_point=v, name='CP^2', + latex_name='CP^{2}') return K if n == 3: file = os.path.join(SAGE_ENV['SAGE_EXTCODE'], 'kenzo', 'CP3.txt') @@ -642,10 +650,12 @@ def simplicial_data_from_kenzo_output(filename): sage: from sage.topology.simplicial_set_examples import simplicial_data_from_kenzo_output sage: from sage.topology.simplicial_set import SimplicialSet sage: sphere = os.path.join(SAGE_ENV['SAGE_EXTCODE'], 'kenzo', 'S4.txt') - sage: S4 = SimplicialSet(simplicial_data_from_kenzo_output(sphere)) - sage: S4.homology(reduced=False) + sage: S4 = SimplicialSet(simplicial_data_from_kenzo_output(sphere)) # needs pyparsing + sage: S4.homology(reduced=False) # needs pyparsing {0: Z, 1: 0, 2: 0, 3: 0, 4: Z} """ + from pyparsing import OneOrMore, nestedExpr + with open(filename, 'r') as f: data = f.read() dim = 0 @@ -730,7 +740,7 @@ def HopfMap(): sage: X = g.mapping_cone() sage: CP2 = simplicial_sets.ComplexProjectiveSpace(2) - sage: X.homology() == CP2.homology() + sage: X.homology() == CP2.homology() # needs sage.modules True sage: X.f_vector() @@ -768,25 +778,86 @@ def HopfMap(): alpha_5 = AbstractSimplex(3, name='alpha_5', latex_name='\\alpha_5') alpha_6 = AbstractSimplex(3, name='alpha_6', latex_name='\\alpha_6') S3 = SimplicialSet_finite({beta_11: (w_0, w_0), beta_22: (w_0, w_0), - beta_23: (w_0, w_0), beta_44: (w_0, w_0), - beta_1: (w_1, beta_11, w_1), - beta_2: (w_1, beta_22, beta_23), - beta_3: (w_1, beta_23, w_1), - beta_4: (w_1, beta_44, w_1), - alpha_12: (beta_11, beta_23, w_1), - alpha_23: (beta_11, beta_22, w_1), - alpha_34: (beta_11, beta_22, beta_44), - alpha_45: (w_1, beta_23, beta_44), - alpha_56: (w_1, beta_23, w_1), - alpha_1: (beta_1, beta_3, alpha_12, w_2), - alpha_2: (beta_11.apply_degeneracies(1), beta_2, - alpha_23, alpha_12), - alpha_3: (beta_11.apply_degeneracies(0), alpha_34, - alpha_23, beta_4), - alpha_4: (beta_1, beta_2, alpha_34, alpha_45), - alpha_5: (w_2, alpha_45, alpha_56, beta_4), - alpha_6: (w_2, beta_3, alpha_56, w_2)}, - base_point=w_0) - return S3.Hom(S2)({alpha_1:s0_sigma, alpha_2:s1_sigma, - alpha_3:s2_sigma, alpha_4:s0_sigma, - alpha_5:s2_sigma, alpha_6:s1_sigma}) + beta_23: (w_0, w_0), beta_44: (w_0, w_0), + beta_1: (w_1, beta_11, w_1), + beta_2: (w_1, beta_22, beta_23), + beta_3: (w_1, beta_23, w_1), + beta_4: (w_1, beta_44, w_1), + alpha_12: (beta_11, beta_23, w_1), + alpha_23: (beta_11, beta_22, w_1), + alpha_34: (beta_11, beta_22, beta_44), + alpha_45: (w_1, beta_23, beta_44), + alpha_56: (w_1, beta_23, w_1), + alpha_1: (beta_1, beta_3, alpha_12, w_2), + alpha_2: (beta_11.apply_degeneracies(1), beta_2, + alpha_23, alpha_12), + alpha_3: (beta_11.apply_degeneracies(0), alpha_34, + alpha_23, beta_4), + alpha_4: (beta_1, beta_2, alpha_34, alpha_45), + alpha_5: (w_2, alpha_45, alpha_56, beta_4), + alpha_6: (w_2, beta_3, alpha_56, w_2)}, + base_point=w_0) + return S3.Hom(S2)({alpha_1: s0_sigma, alpha_2: s1_sigma, + alpha_3: s2_sigma, alpha_4: s0_sigma, + alpha_5: s2_sigma, alpha_6: s1_sigma}) + + +def PresentationComplex(G): + r""" + Return a simplicial set constructed from a group presentation. + The result is a subdivision of the presentation complex. + + The presentation complex has a single vertex and it has one edge for + each generator. Then triangles (and eventually new edges + to glue them) are added to realize the relations. + + INPUT: + + - "G" -- a finitely presented group + + EXAMPLES:: + + sage: # needs sage.groups + sage: G = SymmetricGroup(2).as_finitely_presented_group(); G + Finitely presented group < a | a^2 > + sage: S = simplicial_sets.PresentationComplex(G); S + Simplicial set with 5 non-degenerate simplices + sage: S.face_data() + {Delta^0: None, + a: (Delta^0, Delta^0), + a^-1: (Delta^0, Delta^0), + Ta: (a, s_0 Delta^0, a^-1), + a^2: (a, s_0 Delta^0, a)} + sage: S.fundamental_group() + Finitely presented group < e0 | e0^2 > + """ + O = AbstractSimplex(0) + SO = O.apply_degeneracies(0) + edges = {g: AbstractSimplex(1, name=str(g)) for g in G.gens()} + inverseedges = {g.inverse(): AbstractSimplex(1, name=str(g.inverse())) for g in G.gens()} + all_edges = {} + all_edges.update(edges) + all_edges.update(inverseedges) + triangles = {g: AbstractSimplex(2, name='T' + str(g)) for g in G.gens()} + face_maps = {g: [O, O] for g in all_edges.values()} + face_maps.update({triangles[t]: [all_edges[t], SO, all_edges[t.inverse()]] for t in triangles}) + for r in G.relations(): + if len(r.Tietze()) == 1: + pass + elif len(r.Tietze()) == 2: + a = all_edges[G([r.Tietze()[0]])] + b = all_edges[G([r.Tietze()[1]])] + T = AbstractSimplex(2, name=str(r)) + face_maps[T] = [a, SO, b] + else: + words = [all_edges[G([a])] for a in r.Tietze()] + words[-1] = all_edges[G([-r.Tietze()[-1]])] + while len(words) > 3: + auxedge = AbstractSimplex(1) + face_maps[auxedge] = [O, O] + auxtring = AbstractSimplex(2) + face_maps[auxtring] = [words[1], auxedge, words[0]] + words = [auxedge] + words[2:] + auxtring = AbstractSimplex(2) + face_maps[auxtring] = [words[1], words[2], words[0]] + return SimplicialSet_finite(face_maps, base_point=O) diff --git a/src/sage/topology/simplicial_set_morphism.py b/src/sage/topology/simplicial_set_morphism.py index f74f5fe7685..df5d004b3e1 100644 --- a/src/sage/topology/simplicial_set_morphism.py +++ b/src/sage/topology/simplicial_set_morphism.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" Morphisms and homsets for simplicial sets @@ -35,14 +36,15 @@ from sage.categories.homset import Hom, Homset from sage.categories.morphism import Morphism from sage.categories.simplicial_sets import SimplicialSets -from sage.matrix.constructor import matrix, zero_matrix from sage.misc.latex import latex +from sage.misc.lazy_import import lazy_import from sage.rings.integer_ring import ZZ -from sage.homology.chain_complex_morphism import ChainComplexMorphism -from sage.homology.homology_morphism import InducedHomologyMorphism from .simplicial_set import SimplicialSet_arbitrary +lazy_import('sage.matrix.constructor', ['matrix', 'zero_matrix']) + + class SimplicialSetHomset(Homset): r""" A set of morphisms between simplicial sets. @@ -103,8 +105,8 @@ def diagonal_morphism(self): EXAMPLES:: - sage: RP2 = simplicial_sets.RealProjectiveSpace(2) - sage: Hom(RP2, RP2.product(RP2)).diagonal_morphism() + sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # needs sage.groups + sage: Hom(RP2, RP2.product(RP2)).diagonal_morphism() # needs sage.groups Simplicial set morphism: From: RP^2 To: RP^2 x RP^2 @@ -270,7 +272,7 @@ def __iter__(self): From: S^1 To: Torus Defn: Constant map at (v_0, v_0)] - sage: [f.induced_homology_morphism().to_matrix() for f in H] + sage: [f.induced_homology_morphism().to_matrix() for f in H] # needs sage.modules [ [ 1| 0] [1|0] [1|0] [1|0] [--+--] [-+-] [-+-] [-+-] @@ -479,18 +481,18 @@ def __init__(self, data=None, domain=None, codomain=None, if constant is not None: self._constant = constant check = False - data = {sigma: constant.apply_degeneracies(*range(sigma.dimension()-1,-1,-1)) + data = {sigma: constant.apply_degeneracies(*range(sigma.dimension()-1, -1, -1)) for sigma in domain.nondegenerate_simplices()} if (not isinstance(domain, SimplicialSet_arbitrary) - or not isinstance(codomain, SimplicialSet_arbitrary)): + or not isinstance(codomain, SimplicialSet_arbitrary)): raise TypeError('the domain and codomain must be simplicial sets') if any(x.nondegenerate() not in domain.nondegenerate_simplices() for x in data.keys()): raise ValueError('at least one simplex in the defining ' 'dictionary is not in the domain') # Remove degenerate simplices from the domain specification. - d = {sigma:data[sigma] for sigma in data if sigma.is_nondegenerate()} + d = {sigma: data[sigma] for sigma in data if sigma.is_nondegenerate()} # For each simplex in d.keys(), add its faces, and the faces # of its faces, etc., to d. for simplex in list(d): @@ -512,10 +514,10 @@ def __init__(self, data=None, domain=None, codomain=None, d[sigma.nondegenerate()] = x faces = domain.faces(sigma.nondegenerate()) if faces: - for (i,rho) in enumerate(faces): + for i, rho in enumerate(faces): nondegen = rho.nondegenerate() if nondegen not in d: - add.append((rho,i,sigma)) + add.append((rho, i, sigma)) # Now check that the proposed map commutes with the face # maps. (The degeneracy maps should work automatically.) if check: @@ -621,9 +623,9 @@ def __call__(self, x): sage: one(e) == e True - sage: B = AbelianGroup([2]).nerve() - sage: c = B.constant_map() - sage: c(B.n_cells(2)[0]) + sage: B = AbelianGroup([2]).nerve() # needs sage.groups + sage: c = B.constant_map() # needs sage.groups + sage: c(B.n_cells(2)[0]) # needs sage.groups s_1 s_0 * """ if x not in self.domain(): @@ -668,7 +670,7 @@ def _composition_(self, right, homset): Defn: [v_0, sigma_1] --> [(v_0, v_0), (sigma_1, s_0 v_0)] sage: (g*f).image() Simplicial set with 2 non-degenerate simplices - sage: f.image().homology() + sage: f.image().homology() # needs sage.modules {0: 0, 1: Z} """ if self.is_identity(): @@ -690,18 +692,20 @@ def image(self): sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) sage: K = T.factor(0, as_subset=True) - sage: f = S1.Hom(T)({S1.n_cells(0)[0]:K.n_cells(0)[0], S1.n_cells(1)[0]:K.n_cells(1)[0]}) - sage: f + sage: f = S1.Hom(T)({S1.n_cells(0)[0]: K.n_cells(0)[0], + ....: S1.n_cells(1)[0]: K.n_cells(1)[0]}); f Simplicial set morphism: From: S^1 To: S^1 x S^1 Defn: [v_0, sigma_1] --> [(v_0, v_0), (sigma_1, s_0 v_0)] sage: f.image() Simplicial set with 2 non-degenerate simplices - sage: f.image().homology() + sage: f.image().homology() # needs sage.modules {0: 0, 1: Z} - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: B.constant_map().image() Point sage: Hom(B,B).identity().image() == B @@ -744,16 +748,18 @@ def is_identity(self): True sage: (f*g).is_identity() False - sage: (f*g).induced_homology_morphism().to_matrix(1) + sage: (f*g).induced_homology_morphism().to_matrix(1) # needs sage.modules [0] - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) - sage: RP5.n_skeleton(2).inclusion_map().is_identity() + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups + sage: RP5.n_skeleton(2).inclusion_map().is_identity() # needs sage.groups False - sage: RP5.n_skeleton(5).inclusion_map().is_identity() + sage: RP5.n_skeleton(5).inclusion_map().is_identity() # needs sage.groups True - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: Hom(B,B).identity().is_identity() True sage: Hom(B,B).constant_map().is_identity() @@ -762,7 +768,7 @@ def is_identity(self): ans = (self._is_identity or (self.domain() == self.codomain() and self.domain().is_finite() - and all(a == b for a,b in self._dictionary.items()))) + and all(a == b for a, b in self._dictionary.items()))) self._is_identity = ans return ans @@ -772,18 +778,18 @@ def is_surjective(self): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) - sage: RP2 = RP5.n_skeleton(2) - sage: RP2.inclusion_map().is_surjective() + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups + sage: RP2 = RP5.n_skeleton(2) # needs sage.groups + sage: RP2.inclusion_map().is_surjective() # needs sage.groups False - sage: RP5_2 = RP5.quotient(RP2) - sage: RP5_2.quotient_map().is_surjective() + sage: RP5_2 = RP5.quotient(RP2) # needs sage.groups + sage: RP5_2.quotient_map().is_surjective() # needs sage.groups True - sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) - sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) - sage: f.is_surjective() + sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # needs sage.groups + sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # needs sage.groups + sage: f.is_surjective() # needs sage.groups True """ return self._is_identity or self.image() == self.codomain() @@ -794,18 +800,18 @@ def is_injective(self): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) - sage: RP2 = RP5.n_skeleton(2) - sage: RP2.inclusion_map().is_injective() + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups + sage: RP2 = RP5.n_skeleton(2) # needs sage.groups + sage: RP2.inclusion_map().is_injective() # needs sage.groups True - sage: RP5_2 = RP5.quotient(RP2) - sage: RP5_2.quotient_map().is_injective() + sage: RP5_2 = RP5.quotient(RP2) # needs sage.groups + sage: RP5_2.quotient_map().is_injective() # needs sage.groups False - sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) - sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) - sage: f.is_injective() + sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # needs sage.groups + sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # needs sage.groups + sage: f.is_injective() # needs sage.groups True """ if self._is_identity: @@ -824,18 +830,18 @@ def is_bijective(self): EXAMPLES:: - sage: RP5 = simplicial_sets.RealProjectiveSpace(5) - sage: RP2 = RP5.n_skeleton(2) - sage: RP2.inclusion_map().is_bijective() + sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups + sage: RP2 = RP5.n_skeleton(2) # needs sage.groups + sage: RP2.inclusion_map().is_bijective() # needs sage.groups False - sage: RP5_2 = RP5.quotient(RP2) - sage: RP5_2.quotient_map().is_bijective() + sage: RP5_2 = RP5.quotient(RP2) # needs sage.groups + sage: RP5_2.quotient_map().is_bijective() # needs sage.groups False - sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) - sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) - sage: f.is_bijective() + sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # needs sage.groups + sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # needs sage.groups + sage: f.is_bijective() # needs sage.groups True """ return self.is_injective() and self.is_surjective() @@ -917,8 +923,7 @@ def pushout(self, *others): sage: K = simplicial_sets.KleinBottle() sage: init_T = T._map_from_empty_set() sage: init_K = K._map_from_empty_set() - sage: D = init_T.pushout(init_K) # the disjoint union as a pushout - sage: D + sage: D = init_T.pushout(init_K); D # the disjoint union as a pushout Pushout of maps: Simplicial set morphism: From: Empty simplicial set @@ -953,8 +958,7 @@ def pullback(self, *others): sage: K = simplicial_sets.KleinBottle() sage: term_T = T.constant_map() sage: term_K = K.constant_map() - sage: P = term_T.pullback(term_K) # the product as a pullback - sage: P + sage: P = term_T.pullback(term_K); P # the product as a pullback Pullback of maps: Simplicial set morphism: From: Torus @@ -1059,8 +1063,7 @@ def coequalizer(self, other): sage: f = K.inclusion_map() sage: v,w = K.n_cells(0) sage: g = Hom(K,L)({v:pt, w:pt, e:pt.apply_degeneracies(0)}) - sage: P = f.coequalizer(g) - sage: P + sage: P = f.coequalizer(g); P Pushout of maps: Simplicial set morphism: From: Disjoint union: (Simplicial set with 3 non-degenerate simplices u 2-simplex) @@ -1098,18 +1101,20 @@ def mapping_cone(self): sage: L = K.set_base_point(K.n_cells(0)[0]) sage: u,v,w = L.n_cells(0) sage: e,f,g = L.n_cells(1) - sage: h = L.Hom(S1)({u:v_0, v:v_0, w:v_0, e:sigma_1, f:v_0.apply_degeneracies(0), g:sigma_1}) + sage: h = L.Hom(S1)({u:v_0, v:v_0, w:v_0, e:sigma_1, + ....: f:v_0.apply_degeneracies(0), g:sigma_1}) sage: h Simplicial set morphism: From: Simplicial set with 6 non-degenerate simplices To: S^1 - Defn: [(0,), (1,), (2,), (0, 1), (0, 2), (1, 2)] --> [v_0, v_0, v_0, sigma_1, s_0 v_0, sigma_1] - sage: h.induced_homology_morphism().to_matrix() + Defn: [(0,), (1,), (2,), (0, 1), (0, 2), (1, 2)] + --> [v_0, v_0, v_0, sigma_1, s_0 v_0, sigma_1] + sage: h.induced_homology_morphism().to_matrix() # needs sage.modules [1|0] [-+-] [0|2] sage: X = h.mapping_cone() - sage: X.homology() == simplicial_sets.RealProjectiveSpace(2).homology() + sage: X.homology() == simplicial_sets.RealProjectiveSpace(2).homology() # needs sage.groups sage.modules True """ dom = self.domain() @@ -1139,7 +1144,7 @@ def product(self, *others): domain = self.domain().product(*[g.domain() for g in others]) codomain = self.codomain().product(*[g.codomain() for g in others]) factors = [] - for (i,f) in enumerate([self] + list(others)): + for i, f in enumerate([self] + list(others)): factors.append(f * domain.projection_map(i)) return codomain.universal_property(*factors) @@ -1179,8 +1184,9 @@ def suspension(self, n=1): EXAMPLES:: sage: eta = simplicial_sets.HopfMap() - sage: susp_eta = eta.suspension() - sage: susp_eta.mapping_cone().homology() == eta.mapping_cone().suspension().homology() + sage: mc_susp_eta = eta.suspension().mapping_cone() + sage: susp_mc_eta = eta.mapping_cone().suspension() + sage: mc_susp_eta.homology() == susp_mc_eta.homology() # needs sage.modules True This uses reduced suspensions if the original morphism is @@ -1250,7 +1256,9 @@ def n_skeleton(self, n, domain=None, codomain=None): EXAMPLES:: - sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) + sage: # needs sage.groups + sage: G = groups.misc.MultiplicativeAbelian([2]) + sage: B = simplicial_sets.ClassifyingSpace(G) sage: one = Hom(B,B).identity() sage: one.n_skeleton(3) Simplicial set endomorphism of Simplicial set with 4 non-degenerate simplices @@ -1307,18 +1315,20 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, sage: e = S1.n_cells(1)[0] sage: f = {v0: v0, e: v0.apply_degeneracies(0)} # constant map sage: g = Hom(S1, S1)(f) - sage: g.associated_chain_complex_morphism().to_matrix() + sage: g.associated_chain_complex_morphism().to_matrix() # needs sage.modules [1|0] [-+-] [0|0] """ + from sage.homology.chain_complex_morphism import ChainComplexMorphism + # One or the other chain complex is trivial between these # dimensions: max_dim = max(self.domain().dimension(), self.codomain().dimension()) min_dim = min(self.domain().dimension(), self.codomain().dimension()) matrices = {} if augmented is True: - m = matrix(base_ring,1,1,1) + m = matrix(base_ring, 1, 1, 1) if not cochain: matrices[-1] = m else: @@ -1329,7 +1339,7 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, num_faces_X = len(X_faces) num_faces_Y = len(Y_faces) mval = [0 for _ in range(num_faces_X * num_faces_Y)] - for idx,x in enumerate(X_faces): + for idx, x in enumerate(X_faces): y = self(x) if y.is_nondegenerate(): mval[idx + (Y_faces.index(y) * num_faces_X)] = 1 @@ -1338,7 +1348,7 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, matrices[dim] = m else: matrices[dim] = m.transpose() - for dim in range(min_dim+1,max_dim+1): + for dim in range(min_dim+1, max_dim+1): try: l1 = len(self.codomain().n_cells(dim)) except KeyError: @@ -1347,7 +1357,7 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, l2 = len(self.domain().n_cells(dim)) except KeyError: l2 = 0 - m = zero_matrix(base_ring,l1,l2,sparse=True) + m = zero_matrix(base_ring, l1, l2, sparse=True) if not cochain: matrices[dim] = m else: @@ -1374,6 +1384,7 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): EXAMPLES:: + sage: # needs sage.modules sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: w = AbstractSimplex(0, name='w') @@ -1394,6 +1405,8 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): [-+-] [0|2] """ + from sage.homology.homology_morphism import InducedHomologyMorphism + return InducedHomologyMorphism(self, base_ring, cohomology) def _repr_type(self): diff --git a/src/sage/typeset/__init__.py b/src/sage/typeset/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/typeset/ascii_art.py b/src/sage/typeset/ascii_art.py index fe2fd4c419b..032b79322da 100644 --- a/src/sage/typeset/ascii_art.py +++ b/src/sage/typeset/ascii_art.py @@ -15,18 +15,20 @@ EXAMPLES:: + sage: # needs sage.symbolic sage: n = var('n') - sage: integrate(n^2/x,x) + sage: integrate(n^2/x, x) n^2*log(x) - sage: ascii_art(integrate(n^2/x,x)) + sage: ascii_art(integrate(n^2/x, x)) 2 n *log(x) - sage: ascii_art(integrate(n^2/(pi*x),x)) + sage: ascii_art(integrate(n^2/(pi*x), x)) 2 n *log(x) --------- pi - sage: ascii_art(list(Partitions(6))) + + sage: ascii_art(list(Partitions(6))) # needs sage.combinat sage.libs.flint [ * ] [ ** * ] [ *** ** * * ] @@ -40,18 +42,18 @@ sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() sage: shell.run_cell('%display ascii_art') - sage: shell.run_cell("i = var('i')") - sage: shell.run_cell('sum(factorial(i)*x^i, i, 0, 10)') + sage: shell.run_cell("i = var('i')") # needs sage.symbolic + sage: shell.run_cell('sum(factorial(i)*x^i, i, 0, 10)') # needs sage.symbolic 10 9 8 7 6 5 4 3 3628800*x + 362880*x + 40320*x + 5040*x + 720*x + 120*x + 24*x + 6*x <BLANKLINE> 2 + 2*x + x + 1 - sage: shell.run_cell('3/(7*x)') + sage: shell.run_cell('3/(7*x)') # needs sage.symbolic 3 --- 7*x - sage: shell.run_cell('list(Compositions(5))') + sage: shell.run_cell('list(Compositions(5))') # needs sage.combinat [ * [ * ** * * * [ * * ** *** * ** * * ** * * @@ -173,8 +175,8 @@ class AsciiArt(CharacterArt): EXAMPLES:: - sage: i = var('i') - sage: ascii_art(sum(pi^i/factorial(i)*x^i, i, 0, oo)) + sage: i = var('i') # needs sage.symbolic + sage: ascii_art(sum(pi^i/factorial(i)*x^i, i, 0, oo)) # needs sage.symbolic pi*x e """ @@ -216,9 +218,9 @@ def ascii_art(*obj, **kwds): EXAMPLES:: - sage: result = ascii_art(integral(exp(x+x^2)/(x+1), x)) + sage: result = ascii_art(integral(exp(x+x^2)/(x+1), x)) # needs sage.symbolic ... - sage: result + sage: result # needs sage.symbolic / | | 2 @@ -232,21 +234,21 @@ def ascii_art(*obj, **kwds): We can specify a separator object:: sage: ident = lambda n: identity_matrix(ZZ, n) - sage: ascii_art(ident(1), ident(2), ident(3), sep=' : ') + sage: ascii_art(ident(1), ident(2), ident(3), sep=' : ') # needs sage.modules [1 0 0] [1 0] [0 1 0] [1] : [0 1] : [0 0 1] We can specify the baseline:: - sage: ascii_art(ident(2), baseline=-1) + ascii_art(ident(3)) + sage: ascii_art(ident(2), baseline=-1) + ascii_art(ident(3)) # needs sage.modules [1 0][1 0 0] [0 1][0 1 0] [0 0 1] We can determine the baseline of the separator:: - sage: ascii_art(ident(1), ident(2), ident(3), sep=' -- ', sep_baseline=-1) + sage: ascii_art(ident(1), ident(2), ident(3), sep=' -- ', sep_baseline=-1) # needs sage.modules [1 0 0] -- [1 0] -- [0 1 0] [1] [0 1] [0 0 1] @@ -255,7 +257,7 @@ def ascii_art(*obj, **kwds): an ascii art separator:: sage: sep_line = ascii_art('\n'.join(' | ' for _ in range(6)), baseline=6) - sage: ascii_art(*Partitions(6), separator=sep_line, sep_baseline=0) + sage: ascii_art(*Partitions(6), separator=sep_line, sep_baseline=0) # needs sage.combinat sage.libs.flint | | | | | | | | | | * | | | | | | | | | ** | * | | | | | | *** | | ** | * | * @@ -265,14 +267,14 @@ def ascii_art(*obj, **kwds): TESTS:: - sage: n = var('n') - sage: ascii_art(sum(binomial(2 * n, n + 1) * x^n, n, 0, oo)) + sage: n = var('n') # needs sage.symbolic + sage: ascii_art(sum(binomial(2 * n, n + 1) * x^n, n, 0, oo)) # needs sage.symbolic / _________ \ -\2*x + \/ 1 - 4*x - 1/ ------------------------- _________ 2*x*\/ 1 - 4*x - sage: ascii_art(list(DyckWords(3))) + sage: ascii_art(list(DyckWords(3))) # needs sage.combinat [ /\ ] [ /\ /\ /\/\ / \ ] [ /\/\/\, /\/ \, / \/\, / \, / \ ] diff --git a/src/sage/typeset/character_art.py b/src/sage/typeset/character_art.py index dd1107db48d..239e35a7df3 100644 --- a/src/sage/typeset/character_art.py +++ b/src/sage/typeset/character_art.py @@ -58,8 +58,8 @@ def __init__(self, lines=[], breakpoints=[], baseline=None): EXAMPLES:: - sage: i = var('i') - sage: ascii_art(sum(pi^i/factorial(i)*x^i, i, 0, oo)) + sage: i = var('i') # needs sage.symbolic + sage: ascii_art(sum(pi^i/factorial(i)*x^i, i, 0, oo)) # needs sage.symbolic pi*x e @@ -133,8 +133,7 @@ def __iter__(self): * * ***** """ - for elem in self._matrix: - yield elem + yield from self._matrix def _repr_(self): r""" @@ -162,10 +161,10 @@ def __format__(self, fmt): EXAMPLES:: - sage: M = matrix([[1,2],[3,4]]) - sage: format(ascii_art(M)) + sage: M = matrix([[1,2],[3,4]]) # needs sage.modules + sage: format(ascii_art(M)) # needs sage.modules '[1 2]\n[3 4]' - sage: format(unicode_art(M)) + sage: format(unicode_art(M)) # needs sage.modules '\u239b1 2\u239e\n\u239d3 4\u23a0' """ return format(self._string_type(self), fmt) diff --git a/src/sage/typeset/character_art_factory.py b/src/sage/typeset/character_art_factory.py index d83aa4da4f5..cc3855d8f10 100644 --- a/src/sage/typeset/character_art_factory.py +++ b/src/sage/typeset/character_art_factory.py @@ -84,9 +84,9 @@ def build(self, obj, baseline=None): EXAMPLES:: - sage: result = ascii_art(integral(exp(x+x^2)/(x+1), x)) + sage: result = ascii_art(integral(exp(x+x^2)/(x+1), x)) # needs sage.symbolic ... - sage: result + sage: result # needs sage.symbolic / | | 2 @@ -99,14 +99,14 @@ def build(self, obj, baseline=None): TESTS:: - sage: n = var('n') - sage: ascii_art(sum(binomial(2 * n, n + 1) * x^n, n, 0, oo)) + sage: n = var('n') # needs sage.symbolic + sage: ascii_art(sum(binomial(2 * n, n + 1) * x^n, n, 0, oo)) # needs sage.symbolic / _________ \ -\2*x + \/ 1 - 4*x - 1/ ------------------------- _________ 2*x*\/ 1 - 4*x - sage: ascii_art(list(DyckWords(3))) + sage: ascii_art(list(DyckWords(3))) # needs sage.combinat [ /\ ] [ /\ /\ /\/\ / \ ] [ /\/\/\, /\/ \, / \/\, / \, / \ ] @@ -161,10 +161,10 @@ def build_from_magic_method(self, obj, baseline=None): EXAMPLES:: sage: from sage.typeset.ascii_art import _ascii_art_factory as factory - sage: out = factory.build_from_magic_method(identity_matrix(2)); out + sage: out = factory.build_from_magic_method(identity_matrix(2)); out # needs sage.modules [1 0] [0 1] - sage: type(out) + sage: type(out) # needs sage.modules <class 'sage.typeset.ascii_art.AsciiArt'> """ magic_method = getattr(obj, self.magic_method_name) @@ -243,12 +243,12 @@ def build_container(self, content, left_border, right_border, baseline=0): TESTS:: - sage: l = ascii_art(list(DyckWords(3))) # indirect doctest - sage: l + sage: l = ascii_art(list(DyckWords(3))) # indirect doctest # needs sage.combinat + sage: l # needs sage.combinat [ /\ ] [ /\ /\ /\/\ / \ ] [ /\/\/\, /\/ \, / \/\, / \, / \ ] - sage: l._breakpoints + sage: l._breakpoints # needs sage.combinat [9, 17, 25, 33] Check that zero-height strings are handled (:trac:`28527`):: @@ -289,7 +289,7 @@ def build_set(self, s, baseline=0): iteration over sets is non-deterministic so too is the results of this test:: - sage: ascii_art(set(DyckWords(3))) # indirect doctest random + sage: ascii_art(set(DyckWords(3))) # indirect doctest random # needs sage.combinat { /\ } { /\ /\/\ /\ / \ } { / \/\, / \, /\/\/\, /\/ \, / \ } @@ -298,7 +298,7 @@ def build_set(self, s, baseline=0): a set, but still obtain the same output formatting:: sage: from sage.typeset.ascii_art import _ascii_art_factory as factory - sage: factory.build_set(sorted(set(DyckWords(3)))) + sage: factory.build_set(sorted(set(DyckWords(3)))) # needs sage.combinat { /\ } { /\ /\ /\/\ / \ } { /\/\/\, /\/ \, / \/\, / \, / \ } @@ -315,6 +315,7 @@ def build_dict(self, d, baseline=0): TESTS:: + sage: # needs sage.combinat sage: from collections import OrderedDict sage: d = OrderedDict(enumerate(DyckWords(3))) sage: art = ascii_art(d) # indirect doctest @@ -357,18 +358,18 @@ def build_list(self, l, baseline=0): TESTS:: - sage: l = ascii_art(list(DyckWords(3))) # indirect doctest - sage: l + sage: l = ascii_art(list(DyckWords(3))) # indirect doctest # needs sage.combinat + sage: l # needs sage.combinat [ /\ ] [ /\ /\ /\/\ / \ ] [ /\/\/\, /\/ \, / \/\, / \, / \ ] - sage: l._breakpoints + sage: l._breakpoints # needs sage.combinat [9, 17, 25, 33] The breakpoints of the object are used as breakpoints:: - sage: l = ascii_art([DyckWords(2).list(), DyckWords(2).list()]) - sage: l._breakpoints + sage: l = ascii_art([DyckWords(2).list(), DyckWords(2).list()]) # needs sage.combinat + sage: l._breakpoints # needs sage.combinat [(2, [7]), 17, (18, [7])] The parentheses only stretch as high as the content (:trac:`28527`):: @@ -399,7 +400,7 @@ def build_tuple(self, t, baseline=0): TESTS:: - sage: ascii_art(tuple(DyckWords(3))) # indirect doctest + sage: ascii_art(tuple(DyckWords(3))) # indirect doctest # needs sage.combinat ( /\ ) ( /\ /\ /\/\ / \ ) ( /\/\/\, /\/ \, / \/\, / \, / \ ) @@ -440,8 +441,8 @@ def concatenate(self, iterable, separator, empty=None, baseline=0, EXAMPLES:: - sage: i2 = identity_matrix(2) - sage: ascii_art(i2, i2, i2, sep=ascii_art(1/x)) + sage: i2 = identity_matrix(2) # needs sage.modules + sage: ascii_art(i2, i2, i2, sep=ascii_art(1/x)) # needs sage.modules sage.symbolic 1 1 [1 0]-[1 0]-[1 0] [0 1]x[0 1]x[0 1] diff --git a/src/sage/typeset/unicode_art.py b/src/sage/typeset/unicode_art.py index caed3475afe..d9218e1df30 100644 --- a/src/sage/typeset/unicode_art.py +++ b/src/sage/typeset/unicode_art.py @@ -44,8 +44,8 @@ class UnicodeArt(CharacterArt): EXAMPLES:: - sage: i = var('i') - sage: unicode_art(sum(pi^i/factorial(i)*x^i, i, 0, oo)) + sage: i = var('i') # needs sage.symbolic + sage: unicode_art(sum(pi^i/factorial(i)*x^i, i, 0, oo)) # needs sage.symbolic ฯ€โ‹…x โ„ฏ """ @@ -88,9 +88,9 @@ def unicode_art(*obj, **kwds): EXAMPLES:: - sage: result = unicode_art(integral(exp(sqrt(x))/(x+pi), x)) + sage: result = unicode_art(integral(exp(sqrt(x))/(x+pi), x)) # needs sage.symbolic ... - sage: result + sage: result # needs sage.symbolic โŒ  โŽฎ โˆšx โŽฎ โ„ฏ @@ -98,7 +98,7 @@ def unicode_art(*obj, **kwds): โŽฎ x + ฯ€ โŒก sage: ident = lambda n: identity_matrix(ZZ, n) - sage: unicode_art(ident(1), ident(2), ident(3), sep=' : ') + sage: unicode_art(ident(1), ident(2), ident(3), sep=' : ') # needs sage.modules โŽ›1 0 0โŽž โŽ›1 0โŽž โŽœ0 1 0โŽŸ (1) : โŽ0 1โŽ  : โŽ0 0 1โŽ  @@ -107,7 +107,7 @@ def unicode_art(*obj, **kwds): an unicode art separator:: sage: sep_line = unicode_art('\n'.join(' โŽŸ ' for _ in range(5)), baseline=5) - sage: unicode_art(*AlternatingSignMatrices(3), + sage: unicode_art(*AlternatingSignMatrices(3), # needs sage.combinat sage.modules ....: separator=sep_line, sep_baseline=1) โŽŸ โŽŸ โŽŸ โŽŸ โŽŸ โŽŸ โŽ›1 0 0โŽž โŽŸ โŽ›0 1 0โŽž โŽŸ โŽ›1 0 0โŽž โŽŸ โŽ› 0 1 0โŽž โŽŸ โŽ›0 0 1โŽž โŽŸ โŽ›0 1 0โŽž โŽŸ โŽ›0 0 1โŽž @@ -117,14 +117,14 @@ def unicode_art(*obj, **kwds): TESTS:: - sage: n = var('n') - sage: unicode_art(sum(binomial(2 * n, n + 1) * x^n, n, 0, oo)) + sage: n = var('n') # needs sage.symbolic + sage: unicode_art(sum(binomial(2 * n, n + 1) * x^n, n, 0, oo)) # needs sage.symbolic โŽ› _________ โŽž -โŽ2โ‹…x + โ•ฒโ•ฑ 1 - 4โ‹…x - 1โŽ  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ _________ 2โ‹…xโ‹…โ•ฒโ•ฑ 1 - 4โ‹…x - sage: unicode_art(list(DyckWords(3))) + sage: unicode_art(list(DyckWords(3))) # needs sage.combinat โŽก โ•ฑโ•ฒ โŽค โŽข โ•ฑโ•ฒ โ•ฑโ•ฒ โ•ฑโ•ฒโ•ฑโ•ฒ โ•ฑ โ•ฒ โŽฅ โŽฃ โ•ฑโ•ฒโ•ฑโ•ฒโ•ฑโ•ฒ, โ•ฑโ•ฒโ•ฑ โ•ฒ, โ•ฑ โ•ฒโ•ฑโ•ฒ, โ•ฑ โ•ฒ, โ•ฑ โ•ฒ โŽฆ diff --git a/src/sage/version.py b/src/sage/version.py index 962b5cea054..659a7932e4e 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '10.0.beta1' -date = '2023-02-19' -banner = 'SageMath version 10.0.beta1, Release Date: 2023-02-19' +version = '10.2.beta5' +date = '2023-09-27' +banner = 'SageMath version 10.2.beta5, Release Date: 2023-09-27' diff --git a/src/sage_docbuild/__main__.py b/src/sage_docbuild/__main__.py index c9b37120976..77919ec4000 100644 --- a/src/sage_docbuild/__main__.py +++ b/src/sage_docbuild/__main__.py @@ -59,6 +59,7 @@ import logging import argparse import os +import shlex import sys import sphinx.ext.intersphinx from sage.env import SAGE_DOC_SRC @@ -441,6 +442,9 @@ def main(): if not name or not typ: parser.print_help() sys.exit(1) + elif name == 'all': + sys.exit(os.system(f'cd {shlex.quote(SAGE_DOC_SRC)} ' + f'&& ${{MAKE:-make}} -j${{SAGE_NUM_THREADS_PARALLEL:-1}} doc-{typ}')) # Set up module-wide logging. setup_logger(args.verbose, args.color) @@ -494,5 +498,6 @@ def excepthook(*exc_info): builder = getattr(get_builder(name), typ) builder() + if __name__ == '__main__': sys.exit(main()) diff --git a/src/sage_docbuild/builders.py b/src/sage_docbuild/builders.py index f1262eddb25..323c9247252 100644 --- a/src/sage_docbuild/builders.py +++ b/src/sage_docbuild/builders.py @@ -145,7 +145,6 @@ def f(self, *args, **kwds): else: options += ' -D multidoc_first_pass=1' - build_command = '-b %s -d %s %s %s %s' % (type, self._doctrees_dir(), options, self.dir, output_dir) diff --git a/src/sage_docbuild/conf.py b/src/sage_docbuild/conf.py index 1cde07866c9..0df2760c035 100644 --- a/src/sage_docbuild/conf.py +++ b/src/sage_docbuild/conf.py @@ -46,6 +46,7 @@ 'sphinx.ext.todo', 'sphinx.ext.extlinks', 'sphinx.ext.mathjax', + 'sphinx_copybutton', 'IPython.sphinxext.ipython_directive', 'matplotlib.sphinxext.plot_directive', 'jupyter_sphinx', @@ -230,15 +231,17 @@ def set_intersphinx_mappings(app, config): 'python': ('https://docs.python.org/', os.path.join(SAGE_DOC_SRC, "common", "python{}.inv".format(python_version))), - 'pplpy': (PPLPY_DOCS, None)} + } + if PPLPY_DOCS and os.path.exists(os.path.join(PPLPY_DOCS, 'objects.inv')): + app.config.intersphinx_mapping['pplpy'] = (PPLPY_DOCS, None) + else: + app.config.intersphinx_mapping['pplpy'] = ('https://www.labri.fr/perso/vdelecro/pplpy/latest/', None) # Add master intersphinx mapping dst = os.path.join(invpath, 'objects.inv') app.config.intersphinx_mapping['sagemath'] = (refpath, dst) # Add intersphinx mapping for subdirectories - # We intentionally do not name these such that these get higher - # priority in case of conflicts for directory in os.listdir(os.path.join(invpath)): if directory == 'jupyter_execute': # This directory is created by jupyter-sphinx extension for @@ -247,7 +250,7 @@ def set_intersphinx_mappings(app, config): if os.path.isdir(os.path.join(invpath, directory)): src = os.path.join(refpath, directory) dst = os.path.join(invpath, directory, 'objects.inv') - app.config.intersphinx_mapping[src] = dst + app.config.intersphinx_mapping[directory] = (src, dst) intersphinx.normalize_intersphinx_mapping(app, config) @@ -255,6 +258,12 @@ def set_intersphinx_mappings(app, config): # By default document are not master. multidocs_is_master = True +# https://sphinx-copybutton.readthedocs.io/en/latest/use.html +copybutton_prompt_text = r"sage: |[.][.][.][.]: |\$ " +copybutton_prompt_is_regexp = True +copybutton_exclude = '.linenos, .c1' # exclude single comments (in particular, # optional!) +copybutton_only_copy_prompt_lines = True + # Options for HTML output # ----------------------- @@ -365,8 +374,7 @@ def set_intersphinx_mappings(app, config): if os.environ.get('SAGE_USE_CDNS', 'no') == 'yes': mathjax_path = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js" else: - mathjax_path = 'mathjax/tex-chtml.js' - html_common_static_path += [MATHJAX_DIR] + mathjax_path = os.path.join(MATHJAX_DIR, 'tex-chtml.js') # A list of glob-style patterns that should be excluded when looking for source # files. They are matched against the source file names relative to the @@ -612,7 +620,8 @@ def set_intersphinx_mappings(app, config): \DeclareUnicodeCharacter{2534}{+} % uh \DeclareUnicodeCharacter{253C}{+} % vh \DeclareUnicodeCharacter{2571}{/} % upper right to lower left - \DeclareUnicodeCharacter{2571}{\setminus} % upper left to lower right + \DeclareUnicodeCharacter{2572}{\ensuremath{\setminus}} % upper left to lower right + \DeclareUnicodeCharacter{2573}{X} % diagonal cross \DeclareUnicodeCharacter{25CF}{\ensuremath{\bullet}} % medium black circle \DeclareUnicodeCharacter{26AC}{\ensuremath{\circ}} % medium small white circle @@ -682,6 +691,7 @@ def add_page_context(app, pagename, templatename, context, doctree): context['reference_root'] = os.path.join(relpath, 'index.html') context['refsub'] = True + dangling_debug = False def debug_inf(app, message): @@ -706,7 +716,7 @@ def call_intersphinx(app, env, node, contnode): """ debug_inf(app, "???? Trying intersphinx for %s" % node['reftarget']) builder = app.builder - res = intersphinx.missing_reference( + res = intersphinx.missing_reference( app, env, node, contnode) if res: # Replace absolute links to $SAGE_DOC by relative links: this @@ -728,7 +738,7 @@ def find_sage_dangling_links(app, env, node, contnode): debug_inf(app, "==================== find_sage_dangling_links ") reftype = node['reftype'] - reftarget = node['reftarget'] + reftarget = node['reftarget'] try: doc = node['refdoc'] except KeyError: @@ -744,17 +754,18 @@ def find_sage_dangling_links(app, env, node, contnode): res = call_intersphinx(app, env, node, contnode) if res: - debug_inf(app, "++ DONE %s"%(res['refuri'])) + debug_inf(app, "++ DONE %s" % (res['refuri'])) return res - if node.get('refdomain') != 'py': # not a python file + if node.get('refdomain') != 'py': # not a python file return None try: module = node['py:module'] - cls = node['py:class'] + cls = node['py:class'] except KeyError: - debug_inf(app, "-- no module or class for :%s:%s"%(reftype, reftarget)) + debug_inf(app, "-- no module or class for :%s:%s" % (reftype, + reftarget)) return None basename = reftarget.split(".")[0] @@ -780,10 +791,10 @@ def find_sage_dangling_links(app, env, node, contnode): # adapted from sphinx/domains/python.py builder = app.builder searchmode = node.hasattr('refspecific') and 1 or 0 - matches = builder.env.domains['py'].find_obj( + matches = builder.env.domains['py'].find_obj( builder.env, module, cls, newtarget, reftype, searchmode) if not matches: - debug_inf(app, "?? no matching doc for %s"%newtarget) + debug_inf(app, "?? no matching doc for %s" % newtarget) return call_intersphinx(app, env, node, contnode) elif len(matches) > 1: env.warn(target_module, @@ -806,6 +817,7 @@ def find_sage_dangling_links(app, env, node, contnode): newnode.append(contnode) return newnode + # lists of basic Python class which are documented as functions base_class_as_func = [ 'bool', 'complex', 'dict', 'file', 'float', @@ -832,6 +844,7 @@ def nitpick_patch_config(app): app.config.values['nitpicky'] = (False, 'sage') app.config.values['nitpick_ignore'] = ([], 'sage') + skip_picklability_check_modules = [ #'sage.misc.test_nested_class', # for test only 'sage.misc.latex', @@ -918,6 +931,7 @@ def setup(app): app.add_config_value('intersphinx_mapping', {}, False) app.add_config_value('intersphinx_cache_limit', 5, False) app.add_config_value('intersphinx_disabled_reftypes', [], False) + app.add_config_value('intersphinx_timeout', None, False) app.connect('config-inited', set_intersphinx_mappings) app.connect('builder-inited', intersphinx.load_mappings) # We do *not* fully initialize intersphinx since we call it by hand diff --git a/src/sage_docbuild/ext/sage_autodoc.py b/src/sage_docbuild/ext/sage_autodoc.py index 1097290a252..a9cc3ae8b94 100644 --- a/src/sage_docbuild/ext/sage_autodoc.py +++ b/src/sage_docbuild/ext/sage_autodoc.py @@ -31,6 +31,7 @@ - Kwankyu Lee (2018-12-26, 2022-11-08): rebased on the latest sphinx.ext.autodoc """ +from __future__ import annotations import re import warnings @@ -44,7 +45,6 @@ import sphinx from sphinx.application import Sphinx from sphinx.config import ENUM, Config -from sphinx.deprecation import RemovedInSphinx60Warning from sphinx.environment import BuildEnvironment from sphinx.ext.autodoc.importer import (get_class_members, get_object_members, import_module, import_object) @@ -56,7 +56,11 @@ from sphinx.util.inspect import (evaluate_signature, getdoc, object_description, safe_getattr, stringify_signature) from sphinx.util.typing import OptionSpec, get_type_hints, restify -from sphinx.util.typing import stringify as stringify_typehint + +try: + from sphinx.util.typing import stringify_annotation +except ImportError: + from sphinx.util.typing import stringify as stringify_annotation # ------------------------------------------------------------------ from sage.misc.sageinspect import (sage_getdoc_original, @@ -69,6 +73,7 @@ def getdoc(obj, *args, **kwargs): return sage_getdoc_original(obj) # ------------------------------------------------------------------ + if TYPE_CHECKING: from sphinx.ext.autodoc.directive import DocumenterBridge @@ -652,32 +657,13 @@ def add_content(self, more_content: Optional[StringList]) -> None: self.add_line(line, src[0], src[1]) def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]: - """Return ``(members_check_module, members)`` where ``members`` is a - list of ``(membername, member)`` pairs of the members of *self.object*. + """Return `(members_check_module, members)` where `members` is a + list of `(membername, member)` pairs of the members of *self.object*. If *want_all* is True, return all members. Else, only return those members given by *self.options.members* (which may also be None). """ - warnings.warn('The implementation of Documenter.get_object_members() will be ' - 'removed from Sphinx-6.0.', RemovedInSphinx60Warning) - members = get_object_members(self.object, self.objpath, self.get_attr, self.analyzer) - if not want_all: - if not self.options.members: - return False, [] # type: ignore - # specific members given - selected = [] - for name in self.options.members: - if name in members: - selected.append((name, members[name].value)) - else: - logger.warning(__('missing attribute %s in object %s') % - (name, self.fullname), type='autodoc') - return False, selected - elif self.options.inherited_members: - return False, [(m.name, m.value) for m in members.values()] - else: - return False, [(m.name, m.value) for m in members.values() - if m.directly_defined] + raise NotImplementedError('must be implemented in subclasses') def filter_members(self, members: ObjectMembers, want_all: bool ) -> List[Tuple[str, Any, bool]]: @@ -2056,9 +2042,9 @@ def update_content(self, more_content: StringList) -> None: attrs = [repr(self.object.__name__)] for constraint in self.object.__constraints__: if self.config.autodoc_typehints_format == "short": - attrs.append(stringify_typehint(constraint, "smart")) + attrs.append(stringify_annotation(constraint, "smart")) else: - attrs.append(stringify_typehint(constraint)) + attrs.append(stringify_annotation(constraint)) if self.object.__bound__: if self.config.autodoc_typehints_format == "short": bound = restify(self.object.__bound__, "smart") @@ -2181,10 +2167,10 @@ def add_directive_header(self, sig: str) -> None: self.config.autodoc_type_aliases) if self.objpath[-1] in annotations: if self.config.autodoc_typehints_format == "short": - objrepr = stringify_typehint(annotations.get(self.objpath[-1]), + objrepr = stringify_annotation(annotations.get(self.objpath[-1]), "smart") else: - objrepr = stringify_typehint(annotations.get(self.objpath[-1])) + objrepr = stringify_annotation(annotations.get(self.objpath[-1])) self.add_line(' :type: ' + objrepr, sourcename) try: @@ -2500,16 +2486,6 @@ def get_doc(self) -> Optional[List[List[str]]]: else: return super().get_doc() # type: ignore - @property - def _datadescriptor(self) -> bool: - warnings.warn('AttributeDocumenter._datadescriptor() is deprecated.', - RemovedInSphinx60Warning) - if self.object is SLOTSATTR: - return True - else: - return False - - class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase): """ Mixin for AttributeDocumenter to provide the feature for supporting runtime @@ -2762,10 +2738,10 @@ def add_directive_header(self, sig: str) -> None: self.config.autodoc_type_aliases) if self.objpath[-1] in annotations: if self.config.autodoc_typehints_format == "short": - objrepr = stringify_typehint(annotations.get(self.objpath[-1]), + objrepr = stringify_annotation(annotations.get(self.objpath[-1]), "smart") else: - objrepr = stringify_typehint(annotations.get(self.objpath[-1])) + objrepr = stringify_annotation(annotations.get(self.objpath[-1])) self.add_line(' :type: ' + objrepr, sourcename) try: @@ -2890,9 +2866,9 @@ def add_directive_header(self, sig: str) -> None: type_aliases=self.config.autodoc_type_aliases) if signature.return_annotation is not Parameter.empty: if self.config.autodoc_typehints_format == "short": - objrepr = stringify_typehint(signature.return_annotation, "smart") + objrepr = stringify_annotation(signature.return_annotation, "smart") else: - objrepr = stringify_typehint(signature.return_annotation) + objrepr = stringify_annotation(signature.return_annotation) self.add_line(' :type: ' + objrepr, sourcename) except TypeError as exc: logger.warning(__("Failed to get a function signature for %s: %s"), diff --git a/src/sage_setup/autogen/giacpy-mkkeywords.py b/src/sage_setup/autogen/giacpy-mkkeywords.py index 3e8ddac9be9..5d2acee1b93 100644 --- a/src/sage_setup/autogen/giacpy-mkkeywords.py +++ b/src/sage_setup/autogen/giacpy-mkkeywords.py @@ -29,21 +29,15 @@ toremove = ['!', '!=', '#', '$', '%', '/%', '%/', '%{%}', '&&', '&*', '&^', "'", '()', '*', '*=', '+', '-', '+&', '+=', '+infinity', '-<', '-=', '->', '-infinity', '.*', '.+', '.-', './', '.^', '/=', ':=', '<', '<=', '=', '=<', '==', '=>', '>', '>=', '?', '@', '@@', 'ACOSH', 'ACOT', 'ACSC', 'ASEC', 'ASIN', 'ASINH', 'ATAN', 'ATANH', 'COND', 'COS', 'COSH', 'COT', 'CSC', 'CST', 'Celsius2Fahrenheit', 'ClrDraw', 'ClrGraph', 'ClrIO', 'CyclePic', 'DIGITS', 'DOM_COMPLEX', 'DOM_FLOAT', 'DOM_FUNC', 'DOM_IDENT', 'DOM_INT', 'DOM_LIST', 'DOM_RAT', 'DOM_STRING', 'DOM_SYMBOLIC', 'DOM_int', 'DelFold', 'DelVar', 'Det', 'Dialog', 'Digits', 'Disp', 'DispG', 'DispHome', 'DrawFunc', 'DrawInv', 'DrawParm', 'DrawPol', 'DrawSlp', 'DropDown', 'DrwCtour', 'ERROR', 'EXP', 'EndDlog', 'FALSE', 'False', 'Fahrenheit2Celsius', 'Fill', 'Gcd', 'GetFold', 'Graph', 'IFTE', 'Input', 'InputStr', 'Int', 'Inverse', 'LN', 'LQ', 'LSQ', 'NORMALD', 'NewFold', 'NewPic', 'Nullspace', 'Output', 'Ox_2d_unit_vector', 'Ox_3d_unit_vector', 'Oy_2d_unit_vector', 'Oy_3d_unit_vector', 'Oz_3d_unit_vector', 'Pause', 'PopUp', 'Quo', 'REDIM', 'REPLACE', 'RclPic', 'Rem', 'Resultant', 'RplcPic', 'Rref', 'SCALE', 'SCALEADD', 'SCHUR', 'SIN', 'SVD', 'SVL', 'SWAPCOL', 'SWAPROW', 'SetFold', 'Si', 'StoPic', 'Store', 'TAN', 'TRUE', 'True', 'TeX', 'Text', 'Title', 'Unarchiv', 'WAIT', '^', '_(cm/s)', '_(ft/s)', '_(ft*lb)', '_(m/s)', '_(m/s^2)', '_(rad/s)', '_(rad/s^2)', '_(tr/min)', '_(tr/s)', '_A', '_Angstrom', '_Bq', '_Btu', '_Ci', '_F', '_F_', '_Fdy', '_G_', '_Gal', '_Gy', '_H', '_Hz', '_I0_', '_J', '_K', '_Kcal', '_MHz', '_MW', '_MeV', '_N', '_NA_', '_Ohm', '_P', '_PSun_', '_Pa', '_R', '_REarth_', '_RSun_', '_R_', '_Rankine', '_Rinfinity_', '_S', '_St', '_StdP_', '_StdT_', '_Sv', '_T', '_V', '_Vm_', '_W', '_Wb', '_Wh', '_a', '_a0_', '_acre', '_alpha_', '_angl_', '_arcmin', '_arcs', '_atm', '_au', '_b', '_bar', '_bbl', '_bblep', '_bu', '_buUS', '_c3_', '_c_', '_cal', '_cd', '_chain', '_cm', '_cm^2', '_cm^3', '_ct', '_cu', '_d', '_dB', '_deg', '_degreeF', '_dyn', '_eV', '_epsilon0_', '_epsilon0q_', '_epsilonox_', '_epsilonsi_', '_erg', '_f0_', '_fath', '_fbm', '_fc', '_fermi', '_flam', '_fm', '_ft', '_ft*lb', '_ftUS', '_ft^2', '_ft^3', '_g', '_g_', '_ga', '_galC', '_galUK', '_galUS', '_gf', '_gmol', '_gon', '_grad', '_grain', '_h', '_h_', '_ha', '_hbar_', '_hp', '_in', '_inH20', '_inHg', '_in^2', '_in^3', '_j', '_kWh', '_k_', '_kg', '_kip', '_km', '_km^2', '_knot', '_kph', '_kq_', '_l', '_lam', '_lambda0_', '_lambdac_', '_lb', '_lbf', '_lbmol', '_lbt', '_lep', '_liqpt', '_lm', '_lx', '_lyr', '_m', '_mEarth_', '_m^2', '_m^3', '_me_', '_mho', '_miUS', '_miUS^2', '_mi^2', '_mil', '_mile', '_mille', '_ml', '_mm', '_mmHg', '_mn', '_mol', '_mp_', '_mph', '_mpme_', '_mu0_', '_muB_', '_muN_', '_oz', '_ozUK', '_ozfl', '_ozt', '_pc', '_pdl', '_ph', '_phi_', '_pk', '_psi', '_ptUK', '_q_', '_qe_', '_qepsilon0_', '_qme_', '_qt', '_rad', '_rad_', '_rd', '_rem', '_rod', '_rpm', '_s', '_sb', '_sd_', '_sigma_', '_slug', '_sr', '_st', '_syr_', '_t', '_tbsp', '_tec', '_tep', '_tex', '_therm', '_ton', '_tonUK', '_torr', '_tr', '_tsp', '_twopi_', '_u', '_yd', '_yd^2', '_yd^3', '_yr', '_\xc2\xb5', '_ยต', 'assert', 'affichage', 'alors', 'animate', 'animate3d', 'animation', 'approx_mode', 'archive', 'args', 'as_function_of', 'asc', 'asec', 'assign', 'backquote', 'begin', 'black', 'blanc', 'bleu', 'bloc', 'blue', 'breakpoint', 'by', 'c1oc2', 'c1op2', 'cache_tortue', 'cap', 'cap_flat_line', 'cap_round_line', 'cap_square_line', 'case', 'cat', 'catch', 'cd', 'choosebox', 'click', 'close', 'complex_mode', 'de', 'del', 'debug', 'default', 'div', 'double', 'ecris', 'efface', 'elif', 'end', 'end_for', 'end_if', 'end_while', 'epaisseur', 'epaisseur_ligne_1', 'epaisseur_ligne_2', 'epaisseur_ligne_3', 'epaisseur_ligne_4', 'epaisseur_ligne_5', 'epaisseur_ligne_6', 'epaisseur_ligne_7', 'epaisseur_point_1', 'epaisseur_point_2', 'epaisseur_point_3', 'epaisseur_point_4', 'epaisseur_point_5', 'epaisseur_point_6', 'epaisseur_point_7', 'erase', 'erase3d', 'est_cocyclique', 'est_inclus', 'et', 'faire', 'faux', 'feuille', 'ffaire', 'ffonction', 'fi', 'filled', 'fin_enregistrement', 'float', 'fonction', 'fopen', 'format', 'fpour', 'frame_3d', 'frames', 'fsi', 'ftantque', 'func', 'function', 'gauche', 'gl_ortho', 'gl_quaternion', 'gl_rotation', 'gl_shownames', 'gl_texture', 'gl_x', 'gl_x_axis_color', 'gl_x_axis_name', 'gl_x_axis_unit', 'gl_xtick', 'gl_y', 'gl_y_axis_color', 'gl_y_axis_name', 'gl_y_axis_unit', 'gl_ytick', 'gl_z', 'gl_z_axis_color', 'gl_z_axis_name', 'gl_z_axis_unit', 'gl_ztick', 'gnuplot', 'goto', 'graph2tex', 'graph3d2tex', 'graphe', 'graphe3d', 'graphe_probabiliste', 'graphe_suite', 'green', 'grid_paper', 'hidden_name', 'identifier', 'ifft', 'ifte', 'inputform', 'intersect', 'is_included', 'jusqu_a', 'jusqua', 'jusque', 'keep_algext', 'kill', 'label', 'labels', 'len', 'leve_crayon', 'line_width_1', 'line_width_2', 'line_width_3', 'line_width_4', 'line_width_5', 'line_width_6', 'line_width_7', 'lis', 'local', 'minus', 'mod', 'noir', 'nom_cache', 'non', 'od', 'option', 'otherwise', 'ou', 'pas', 'point_arret', 'point_carre', 'point_croix', 'point_div', 'point_etoile', 'point_invisible', 'point_losange', 'point_milieu', 'point_plus', 'point_point', 'point_polaire', 'point_triangle', 'point_width_1', 'point_width_2', 'point_width_3', 'point_width_4', 'point_width_5', 'point_width_6', 'point_width_7', 'pour', 'proc', 'program', 'quadrant1', 'quadrant2', 'quadrant3', 'quadrant4', 'range', 'redim', 'repeat', 'repete', 'repeter', 'replace', 'restart', 'rouge', 'saisir', 'saisir_chaine', 'sauve', 'save_history', 'scale', 'scaleadd', 'si', 'sinon', 'size', 'stack', 'step', 'switch', 'tantque', 'test', 'textinput', 'then', 'thiele', 'time', 'to', 'union', 'until', 'var', 'vector', 'vers', 'vert', 'vrai', 'watch', 'when', 'white', 'with_sqrt', 'write', 'wz_certificate', 'xor', 'yellow', '{}', '|', '||','expression'] +# basekeywords=['sin', 'cos', 'exp', 'tan', 'solve'] - -#basekeywords=['sin', 'cos', 'exp', 'tan', 'solve'] - - -#usualvars=['x','y','z','t','u','v'] +# usualvars=['x','y','z','t','u','v'] moremethods=['type','zip'] # append seems fixed with current giac. - - - # the file aide_cas.txt should contain one line by keywords+ its synonyms. You can create it from th file aide_cas # provided in giac source archive or installled in share/giac/doc like this: #grep -E '^#' share/giac/doc/aide_cas |sed -e 's/^# //' >aide_cas.txt @@ -79,14 +73,14 @@ s+='\n You almost certainly want to use one of the derived class\n :class:`Pygen` instead.\n """\n\n' Mi.write(s) -for i in mostkeywords+moremethods: +for i in mostkeywords + moremethods: p = Popen(["cas_help", i], stdout=PIPE, stderr=PIPE, universal_newlines=True) doc = p.communicate()[0] doc = doc.replace("\n", "\n ") # Indent doc - s = " def "+i+"(self,*args):\n" - s += " r'''From Giac's documentation:\n "+doc+"\n '''\n" - s += " return GiacMethods['"+i+"'](self,*args)\n\n" + s = " def " + i + "(self,*args):\n" + s += " r'''From Giac's documentation:\n " + doc + "\n '''\n" + s += " return GiacMethods['" + i + "'](self,*args)\n\n" Mi.write(s) Mi.close() diff --git a/src/sage_setup/autogen/interpreters/__init__.py b/src/sage_setup/autogen/interpreters/__init__.py index 13d3eed1735..75096d06b80 100644 --- a/src/sage_setup/autogen/interpreters/__init__.py +++ b/src/sage_setup/autogen/interpreters/__init__.py @@ -119,25 +119,10 @@ from .instructions import * from .memory import * from .specs.base import * -from .specs.cdf import * -from .specs.element import * -from .specs.python import * -from .specs.rdf import * -from .specs.rr import * -from .specs.cc import * from .storage import * from .utils import * -# Gather up a list of all interpreter classes imported into this module -# A better way might be to recursively iterate InterpreterSpec.__subclasses__ -# or to use a registry, but this is fine for now. -_INTERPRETERS = sorted(filter(lambda c: (isinstance(c, type) and - issubclass(c, InterpreterSpec) and - c.name), - globals().values()), - key=lambda c: c.name) - # Tuple of (filename_root, extension, method) where filename_root is the # root of the filename to be joined with "_<interpreter_name>".ext and # method is the name of a get_ method on InterpreterGenerator that returns @@ -157,6 +142,7 @@ def build_interp(interp_spec, dir): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: testdir = tmp_dir() sage: rdf_interp = RDFInterpreter() sage: build_interp(rdf_interp, testdir) @@ -174,12 +160,28 @@ def build_interp(interp_spec, dir): write_if_changed(path, method()) -def rebuild(dirname, force=False): +def rebuild(dirname, force=False, interpreters=None, distribution=None): r""" Check whether the interpreter and wrapper sources have been written since the last time this module was changed. If not, write them. - EXAMPLES:: + INPUT: + + - ``dirname`` -- name of the target directory for the generated sources + + - ``force`` -- boolean (default ``False``); if ``True``, ignore timestamps + and regenerate the sources unconditionally + + - ``interpreters`` -- an iterable of strings, or ``None`` (the default, + which means all interpreters); which interpreters to generate + + - ``distribution`` -- a string (the distribution name such as + ``"sagemath-categories"``) or ``None`` (the default, which means + the monolithic Sage library) + + EXAMPLES: + + Monolithic build:: sage: from sage_setup.autogen.interpreters import * sage: testdir = tmp_dir() @@ -189,16 +191,46 @@ def rebuild(dirname, force=False): sage: with open(testdir + '/wrapper_el.pyx') as f: ....: f.readline() '# Automatically generated by ...\n' + + Modularized build:: + + sage: testdir = tmp_dir() + sage: rebuild(testdir, interpreters=['Element', 'Python'], + ....: distribution='sagemath-categories') + Building interpreters for fast_callable + -> First build of interpreters + sage: with open(testdir + '/all__sagemath_categories.py') as f: + ....: f.readline() + '# Automatically generated by ...' """ # This line will show up in "sage -b" (once per upgrade, not every time # you run it). print("Building interpreters for fast_callable") + if interpreters is None: + interpreters = ['CDF', 'Element', 'Python', 'RDF', 'RR', 'CC'] + + from importlib import import_module + + _INTERPRETERS = [getattr(import_module('sage_setup.autogen.interpreters.specs.' + interpreter.lower()), + interpreter + 'Interpreter') + for interpreter in interpreters] + + if distribution is None: + all_py = 'all.py' + else: + all_py = f'all__{distribution.replace("-", "_")}.py' + try: os.makedirs(dirname) except OSError: if not os.path.isdir(dirname): raise + # Remove leftover file from before move to namespace packages + try: + os.remove(os.path.join(dirname, '__init__.py')) + except FileNotFoundError: + pass # Although multiple files are generated by this function, since # they are all generated at once it suffices to make sure if just @@ -208,7 +240,7 @@ class NeedToRebuild(Exception): try: if force: raise NeedToRebuild("-> Force rebuilding interpreters") - gen_file = os.path.join(dirname, '__init__.py') + gen_file = os.path.join(dirname, all_py) if not os.path.isfile(gen_file): raise NeedToRebuild("-> First build of interpreters") @@ -230,5 +262,5 @@ class NeedToRebuild(Exception): for interp in _INTERPRETERS: build_interp(interp(), dirname) - with open(os.path.join(dirname, '__init__.py'), 'w') as f: + with open(os.path.join(dirname, all_py), 'w') as f: f.write("# " + AUTOGEN_WARN) diff --git a/src/sage_setup/autogen/interpreters/generator.py b/src/sage_setup/autogen/interpreters/generator.py index f090f201afd..bec7cae2b47 100644 --- a/src/sage_setup/autogen/interpreters/generator.py +++ b/src/sage_setup/autogen/interpreters/generator.py @@ -43,6 +43,7 @@ def __init__(self, spec): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: interp = RDFInterpreter() sage: gen = InterpreterGenerator(interp) sage: gen._spec is interp @@ -72,6 +73,7 @@ def gen_code(self, instr_desc, write): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: interp = RDFInterpreter() sage: gen = InterpreterGenerator(interp) sage: from io import StringIO @@ -218,6 +220,7 @@ def func_header(self, cython=False): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.element import ElementInterpreter sage: interp = ElementInterpreter() sage: gen = InterpreterGenerator(interp) sage: print(gen.func_header()) @@ -260,6 +263,7 @@ def write_interpreter(self, write): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: interp = RDFInterpreter() sage: gen = InterpreterGenerator(interp) sage: from io import StringIO @@ -307,6 +311,7 @@ def write_wrapper(self, write): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: interp = RDFInterpreter() sage: gen = InterpreterGenerator(interp) sage: from io import StringIO @@ -476,6 +481,7 @@ def write_pxd(self, write): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: interp = RDFInterpreter() sage: gen = InterpreterGenerator(interp) sage: from io import StringIO @@ -527,6 +533,9 @@ def get_interpreter(self): First we get the InterpreterSpec for several interpreters:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter + sage: from sage_setup.autogen.interpreters.specs.rr import RRInterpreter + sage: from sage_setup.autogen.interpreters.specs.element import ElementInterpreter sage: rdf_spec = RDFInterpreter() sage: rr_spec = RRInterpreter() sage: el_spec = ElementInterpreter() @@ -649,6 +658,9 @@ def get_wrapper(self): First we get the InterpreterSpec for several interpreters:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter + sage: from sage_setup.autogen.interpreters.specs.rr import RRInterpreter + sage: from sage_setup.autogen.interpreters.specs.element import ElementInterpreter sage: rdf_spec = RDFInterpreter() sage: rr_spec = RRInterpreter() sage: el_spec = ElementInterpreter() @@ -972,6 +984,9 @@ def get_pxd(self): First we get the InterpreterSpec for several interpreters:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter + sage: from sage_setup.autogen.interpreters.specs.rr import RRInterpreter + sage: from sage_setup.autogen.interpreters.specs.element import ElementInterpreter sage: rdf_spec = RDFInterpreter() sage: rr_spec = RRInterpreter() sage: el_spec = ElementInterpreter() diff --git a/src/sage_setup/autogen/interpreters/instructions.py b/src/sage_setup/autogen/interpreters/instructions.py index d45a34e629a..116f598197c 100644 --- a/src/sage_setup/autogen/interpreters/instructions.py +++ b/src/sage_setup/autogen/interpreters/instructions.py @@ -187,6 +187,7 @@ class InstrSpec(object): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: pg = RDFInterpreter().pg sage: InstrSpec('add', pg('SS','S'), code='o0 = i0+i1;') add: SS->S = 'o0 = i0+i1;' @@ -213,7 +214,7 @@ def __init__(self, name, io, code=None, uses_error_handler=False, EXAMPLES:: sage: from sage_setup.autogen.interpreters import * - + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: pg = RDFInterpreter().pg sage: InstrSpec('add', pg('SS','S'), code='o0 = i0+i1;') add: SS->S = 'o0 = i0+i1;' @@ -288,6 +289,7 @@ def __repr__(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: pg = RDFInterpreter().pg sage: InstrSpec('add', pg('SS','S'), code='o0 = i0+i1;') add: SS->S = 'o0 = i0+i1;' @@ -310,6 +312,7 @@ def instr_infix(name, io, op): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: pg = RDFInterpreter().pg sage: instr_infix('mul', pg('SS', 'S'), '*') mul: SS->S = 'o0 = i0 * i1;' @@ -325,6 +328,7 @@ def instr_funcall_2args(name, io, op): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: pg = RDFInterpreter().pg sage: instr_funcall_2args('atan2', pg('SS', 'S'), 'atan2') atan2: SS->S = 'o0 = atan2(i0, i1);' @@ -340,6 +344,7 @@ def instr_unary(name, io, op): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: pg = RDFInterpreter().pg sage: instr_unary('sin', pg('S','S'), 'sin(i0)') sin: S->S = 'o0 = sin(i0);' @@ -357,6 +362,7 @@ def instr_funcall_2args_mpfr(name, io, op): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rr import RRInterpreter sage: pg = RRInterpreter().pg sage: instr_funcall_2args_mpfr('add', pg('SS','S'), 'mpfr_add') add: SS->S = 'mpfr_add(o0, i0, i1, MPFR_RNDN);' @@ -372,6 +378,7 @@ def instr_funcall_1arg_mpfr(name, io, op): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rr import RRInterpreter sage: pg = RRInterpreter().pg sage: instr_funcall_1arg_mpfr('exp', pg('S','S'), 'mpfr_exp') exp: S->S = 'mpfr_exp(o0, i0, MPFR_RNDN);' @@ -386,6 +393,7 @@ def instr_funcall_2args_mpc(name, io, op): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.cc import CCInterpreter sage: pg = CCInterpreter().pg sage: instr_funcall_2args_mpc('add', pg('SS','S'), 'mpc_add') add: SS->S = 'mpc_add(o0, i0, i1, MPC_RNDNN);' @@ -400,6 +408,7 @@ def instr_funcall_1arg_mpc(name, io, op): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.cc import CCInterpreter sage: pg = CCInterpreter().pg sage: instr_funcall_1arg_mpc('exp', pg('S','S'), 'mpc_exp') exp: S->S = 'mpc_exp(o0, i0, MPC_RNDNN);' diff --git a/src/sage_setup/autogen/interpreters/memory.py b/src/sage_setup/autogen/interpreters/memory.py index be6ec531722..e719f47d77a 100644 --- a/src/sage_setup/autogen/interpreters/memory.py +++ b/src/sage_setup/autogen/interpreters/memory.py @@ -172,6 +172,7 @@ class using this memory chunk, to allocate local variables. EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rr import * sage: mc = MemoryChunkRRRetval('retval', ty_mpfr) sage: mc.declare_call_locals() ' cdef RealNumber retval = (self.domain)()\n' diff --git a/src/sage_setup/autogen/interpreters/specs/base.py b/src/sage_setup/autogen/interpreters/specs/base.py index 67d75b9bf45..c020c37cdb3 100644 --- a/src/sage_setup/autogen/interpreters/specs/base.py +++ b/src/sage_setup/autogen/interpreters/specs/base.py @@ -49,6 +49,8 @@ def __init__(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter + sage: from sage_setup.autogen.interpreters.specs.rr import RRInterpreter sage: interp = RDFInterpreter() sage: interp.c_header '#include <gsl/gsl_math.h>' @@ -84,6 +86,7 @@ def _set_opcodes(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter sage: interp = RDFInterpreter() sage: interp.instr_descs[5].opcode 5 @@ -128,6 +131,9 @@ def __init__(self, type, mc_retval=None): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import RDFInterpreter + sage: from sage_setup.autogen.interpreters.specs.rr import RRInterpreter + sage: from sage_setup.autogen.interpreters.specs.element import ElementInterpreter sage: rdf = RDFInterpreter() sage: rr = RRInterpreter() sage: el = ElementInterpreter() diff --git a/src/sage_setup/autogen/interpreters/specs/cc.py b/src/sage_setup/autogen/interpreters/specs/cc.py index aa0db45bad1..ea5e8708647 100644 --- a/src/sage_setup/autogen/interpreters/specs/cc.py +++ b/src/sage_setup/autogen/interpreters/specs/cc.py @@ -31,6 +31,7 @@ def declare_class_members(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.cc import * sage: mc = MemoryChunkCCRetval('retval', ty_mpc) sage: mc.declare_class_members() '' @@ -45,6 +46,7 @@ class using this memory chunk, to allocate local variables. EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.cc import * sage: mc = MemoryChunkCCRetval('retval', ty_mpc) sage: mc.declare_call_locals() ' cdef ComplexNumber retval = (self.domain_element._new())\n' @@ -62,6 +64,7 @@ def declare_parameter(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.cc import * sage: mc = MemoryChunkCCRetval('retval', ty_mpc) sage: mc.declare_parameter() 'mpc_t retval' @@ -76,6 +79,7 @@ def pass_argument(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.cc import * sage: mc = MemoryChunkCCRetval('retval', ty_mpc) sage: mc.pass_argument() '(<mpc_t>(retval.__re))' @@ -90,6 +94,7 @@ def pass_call_c_argument(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.cc import * sage: mc = MemoryChunkCCRetval('retval', ty_mpc) sage: mc.pass_call_c_argument() 'result' @@ -111,6 +116,7 @@ def __init__(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.cc import * sage: interp = CCInterpreter() sage: interp.name 'cc' diff --git a/src/sage_setup/autogen/interpreters/specs/cdf.py b/src/sage_setup/autogen/interpreters/specs/cdf.py index 7f09c3b6a5c..137487e1de2 100644 --- a/src/sage_setup/autogen/interpreters/specs/cdf.py +++ b/src/sage_setup/autogen/interpreters/specs/cdf.py @@ -34,6 +34,7 @@ def __init__(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.cdf import * sage: interp = CDFInterpreter() sage: interp.name 'cdf' diff --git a/src/sage_setup/autogen/interpreters/specs/element.py b/src/sage_setup/autogen/interpreters/specs/element.py index 3e4e4eca04f..bbb9c21ae57 100644 --- a/src/sage_setup/autogen/interpreters/specs/element.py +++ b/src/sage_setup/autogen/interpreters/specs/element.py @@ -38,6 +38,7 @@ def setup_args(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.element import * sage: mc = MemoryChunkElementArguments('args', ty_python) sage: mc.setup_args() 'mapped_args = [self._domain(a) for a in args]\n' @@ -51,6 +52,7 @@ def pass_argument(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.element import * sage: mc = MemoryChunkElementArguments('args', ty_python) sage: mc.pass_argument() '(<PyListObject*>mapped_args).ob_item' @@ -80,6 +82,7 @@ def __init__(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.element import * sage: interp = ElementInterpreter() sage: interp.name 'el' diff --git a/src/sage_setup/autogen/interpreters/specs/python.py b/src/sage_setup/autogen/interpreters/specs/python.py index eb4eee56b68..86d0d95f827 100644 --- a/src/sage_setup/autogen/interpreters/specs/python.py +++ b/src/sage_setup/autogen/interpreters/specs/python.py @@ -32,6 +32,7 @@ def declare_class_members(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.python import * sage: mc = MemoryChunkPythonArguments('args', ty_python) """ return " cdef int _n_%s\n" % self.name @@ -45,6 +46,7 @@ class members. EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.python import * sage: mc = MemoryChunkPythonArguments('args', ty_python) sage: mc.init_class_members() " count = args['args']\n self._n_args = count\n" @@ -62,6 +64,7 @@ def setup_args(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.python import * sage: mc = MemoryChunkPythonArguments('args', ty_python) sage: mc.setup_args() '' @@ -75,6 +78,7 @@ def pass_argument(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.python import * sage: mc = MemoryChunkPythonArguments('args', ty_python) sage: mc.pass_argument() '(<PyTupleObject*>args).ob_item' @@ -97,6 +101,7 @@ def __init__(self, name): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.python import * sage: mc = MemoryChunkPyConstant('domain') sage: mc.name 'domain' @@ -113,6 +118,7 @@ def declare_class_members(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.python import * sage: mc = MemoryChunkPyConstant('domain') sage: mc.declare_class_members() ' cdef object _domain\n' @@ -131,6 +137,7 @@ class members. EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.python import * sage: mc = MemoryChunkPyConstant('domain') sage: mc.init_class_members() " self._domain = args['domain']\n" @@ -148,6 +155,7 @@ def declare_parameter(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.python import * sage: mc = MemoryChunkPyConstant('domain') sage: mc.declare_parameter() 'PyObject* domain' @@ -162,6 +170,7 @@ def pass_argument(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.python import * sage: mc = MemoryChunkPyConstant('domain') sage: mc.pass_argument() '<PyObject*>self._domain' @@ -204,6 +213,7 @@ def __init__(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.python import * sage: interp = PythonInterpreter() sage: interp.name 'py' diff --git a/src/sage_setup/autogen/interpreters/specs/rdf.py b/src/sage_setup/autogen/interpreters/specs/rdf.py index 6f576844d13..95894f8d6d2 100644 --- a/src/sage_setup/autogen/interpreters/specs/rdf.py +++ b/src/sage_setup/autogen/interpreters/specs/rdf.py @@ -37,6 +37,7 @@ def __init__(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rdf import * sage: interp = RDFInterpreter() sage: interp.name 'rdf' @@ -60,9 +61,11 @@ def __init__(self): Make sure that pow behaves reasonably:: - sage: var('x,y') - (x, y) - sage: ff = fast_callable(x^y, vars=[x,y], domain=RDF) + sage: from sage.ext.fast_callable import ExpressionTreeBuilder + sage: etb = ExpressionTreeBuilder(vars=('x','y')) + sage: x = etb.var('x') + sage: y = etb.var('y') + sage: ff = fast_callable(x^y, domain=RDF) sage: ff(1.5, 3) 3.375 sage: ff(-2, 3) diff --git a/src/sage_setup/autogen/interpreters/specs/rr.py b/src/sage_setup/autogen/interpreters/specs/rr.py index d59e1c2bf8e..264b694dfab 100644 --- a/src/sage_setup/autogen/interpreters/specs/rr.py +++ b/src/sage_setup/autogen/interpreters/specs/rr.py @@ -31,6 +31,7 @@ def declare_class_members(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rr import * sage: mc = MemoryChunkRRRetval('retval', ty_mpfr) sage: mc.declare_class_members() '' @@ -45,6 +46,7 @@ class using this memory chunk, to allocate local variables. EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rr import * sage: mc = MemoryChunkRRRetval('retval', ty_mpfr) sage: mc.declare_call_locals() ' cdef RealNumber retval = (self.domain)()\n' @@ -62,6 +64,7 @@ def declare_parameter(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rr import * sage: mc = MemoryChunkRRRetval('retval', ty_mpfr) sage: mc.declare_parameter() 'mpfr_t retval' @@ -76,6 +79,7 @@ def pass_argument(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rr import * sage: mc = MemoryChunkRRRetval('retval', ty_mpfr) sage: mc.pass_argument() 'retval.value' @@ -90,6 +94,7 @@ def pass_call_c_argument(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rr import * sage: mc = MemoryChunkRRRetval('retval', ty_mpfr) sage: mc.pass_call_c_argument() 'result' @@ -112,6 +117,7 @@ def __init__(self): EXAMPLES:: sage: from sage_setup.autogen.interpreters import * + sage: from sage_setup.autogen.interpreters.specs.rr import * sage: interp = RRInterpreter() sage: interp.name 'rr' diff --git a/src/sage_setup/autogen/interpreters/storage.py b/src/sage_setup/autogen/interpreters/storage.py index d9e0e60273f..291398fd9d9 100644 --- a/src/sage_setup/autogen/interpreters/storage.py +++ b/src/sage_setup/autogen/interpreters/storage.py @@ -440,6 +440,7 @@ class StorageTypeSimple(StorageTypeAssignable): """ pass + ty_int = StorageTypeSimple('int') ty_double = StorageTypeSimple('double') @@ -461,6 +462,7 @@ def assign_c_from_py(self, c, py): """ return je("{{ c }} = CDE_to_dz({{ py }})", c=c, py=py) + ty_double_complex = StorageTypeDoubleComplex('double_complex') @@ -650,6 +652,7 @@ def cython_clear(self, loc): """ return je("Py_CLEAR({{ loc }})", loc=loc) + ty_python = StorageTypePython() @@ -846,6 +849,7 @@ def assign_c_from_py(self, c, py): mpfr_set({{ c }}, rn.value, MPFR_RNDN)"""), myself=self, c=c, py=py) + ty_mpfr = StorageTypeMPFR() class StorageTypeMPC(StorageTypeAutoReference): @@ -948,4 +952,5 @@ def assign_c_from_py(self, c, py): cn{{ myself.id }} = self.domain({{ py }}) mpc_set_fr_fr({{ c }}, cn.__re, cn.__im, MPC_RNDNN)""", myself=self, c=c, py=py) + ty_mpc = StorageTypeMPC() diff --git a/src/sage_setup/command/sage_build_ext.py b/src/sage_setup/command/sage_build_ext.py index 9cca775693b..1a66d520903 100644 --- a/src/sage_setup/command/sage_build_ext.py +++ b/src/sage_setup/command/sage_build_ext.py @@ -70,7 +70,6 @@ def build_extensions(self): print("self.compiler.linker_so (after fixing library dirs):") print(self.compiler.linker_so) - # First, sanity-check the 'extensions' list self.check_extensions_list(self.extensions) diff --git a/src/sage_setup/cython_options.py b/src/sage_setup/cython_options.py index 086aa070ca9..9725ce0e1af 100644 --- a/src/sage_setup/cython_options.py +++ b/src/sage_setup/cython_options.py @@ -10,13 +10,17 @@ def compiler_directives(profile: bool): auto_pickle=False, # Do not create __test__ dictionary automatically from docstrings autotestdict=False, + binding=False, + c_api_binop_methods=True, # Do not check for division by 0 (this is about 35% quicker than with check) cdivision=True, + cpow=True, # Embed a textual copy of the call signature in the docstring (to support tools like IPython) embedsignature=True, fast_getattr=True, # Use Python 3 (including source code semantics) for module compilation language_level="3", + legacy_implicit_noexcept=True, # Enable support for late includes (make declarations in Cython code available to C include files) preliminary_late_includes_cy28=True, # Add hooks for Python profilers into the compiled C code diff --git a/src/setup.cfg.m4 b/src/setup.cfg.m4 index 9f69af385e9..41ac1c08bfa 100644 --- a/src/setup.cfg.m4 +++ b/src/setup.cfg.m4 @@ -1,81 +1,52 @@ -# -*- conf-unix -*- +include(`sage_spkg_versions.m4')dnl' -*- conf-unix -*- [metadata] name = sagemath-standard version = file: VERSION.txt description = Sage: Open Source Mathematics Software: Standard Python Library long_description = file: README.rst long_description_content_type = text/x-rst -license = GNU General Public License (GPL) v2 or later license_files = LICENSE.txt -author = The Sage Developers -author_email = sage-support@googlegroups.com -url = https://www.sagemath.org - -classifiers = - Development Status :: 6 - Mature - Intended Audience :: Education - Intended Audience :: Science/Research - License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) - Operating System :: POSIX - Operating System :: MacOS :: MacOS X - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: Implementation :: CPython - Topic :: Scientific/Engineering :: Mathematics +include(`setup_cfg_metadata.m4')dnl' [options] -python_requires = >=3.8, <3.12 +python_requires = >=3.9, <3.12 install_requires = - esyscmd(`sage-get-system-packages install-requires \ - sage_conf \ - six \ - | sed "2,\$s/^/ /;"')dnl' + SPKG_INSTALL_REQUIRES_sage_conf + SPKG_INSTALL_REQUIRES_six dnl From build/pkgs/sagelib/dependencies - esyscmd(`sage-get-system-packages install-requires \ - cypari \ - cysignals \ - cython \ - gmpy2 \ - jinja2 \ - jupyter_core \ - lrcalc_python \ - memory_allocator \ - numpy \ - pkgconfig \ - pplpy \ - primecountpy \ - requests \ - | sed "2,\$s/^/ /;"')dnl' + SPKG_INSTALL_REQUIRES_cypari + SPKG_INSTALL_REQUIRES_cysignals + SPKG_INSTALL_REQUIRES_cython + SPKG_INSTALL_REQUIRES_gmpy2 + SPKG_INSTALL_REQUIRES_importlib_metadata + SPKG_INSTALL_REQUIRES_importlib_resources + SPKG_INSTALL_REQUIRES_jupyter_core + SPKG_INSTALL_REQUIRES_lrcalc_python + SPKG_INSTALL_REQUIRES_memory_allocator + SPKG_INSTALL_REQUIRES_numpy + SPKG_INSTALL_REQUIRES_pkgconfig + SPKG_INSTALL_REQUIRES_pplpy + SPKG_INSTALL_REQUIRES_primecountpy + SPKG_INSTALL_REQUIRES_requests + SPKG_INSTALL_REQUIRES_typing_extensions dnl From Makefile.in: SAGERUNTIME - esyscmd(`sage-get-system-packages install-requires \ - ipython \ - pexpect \ - | sed "2,\$s/^/ /;"')dnl' + SPKG_INSTALL_REQUIRES_ipython + SPKG_INSTALL_REQUIRES_pexpect dnl From Makefile.in: DOC_DEPENDENCIES - esyscmd(`sage-get-system-packages install-requires \ - sphinx \ - networkx \ - scipy \ - sympy \ - matplotlib \ - pillow \ - mpmath \ - ipykernel \ - jupyter_client \ - ipywidgets \ - | sed "2,\$s/^/ /;"')dnl' -dnl Other Python packages that are standard spkg, used in doctests - esyscmd(`sage-get-system-packages install-requires \ - fpylll \ - | sed "2,\$s/^/ /;"')dnl' + SPKG_INSTALL_REQUIRES_sphinx + SPKG_INSTALL_REQUIRES_networkx + SPKG_INSTALL_REQUIRES_scipy + SPKG_INSTALL_REQUIRES_sympy + SPKG_INSTALL_REQUIRES_matplotlib + SPKG_INSTALL_REQUIRES_pillow + SPKG_INSTALL_REQUIRES_mpmath + SPKG_INSTALL_REQUIRES_ipykernel + SPKG_INSTALL_REQUIRES_jupyter_client + SPKG_INSTALL_REQUIRES_ipywidgets + SPKG_INSTALL_REQUIRES_fpylll dnl pycryptosat # Sage distribution installs it as part of cryptominisat. According to its README on https://pypi.org/project/pycryptosat/: "The pycryptosat python package compiles while compiling CryptoMiniSat. It cannot be compiled on its own, it must be compiled at the same time as CryptoMiniSat." dnl Packages with important upper version bounds - esyscmd(`sage-get-system-packages install-requires \ - ptyprocess \ - | sed "2,\$s/^/ /;"')dnl' + SPKG_INSTALL_REQUIRES_ptyprocess scripts = # The sage script @@ -162,6 +133,4 @@ sage = ext_data/threejs/* [options.extras_require] -R = esyscmd(`sage-get-system-packages install-requires \ - rpy2 \ - | sed "2,\$s/^/ /;"')dnl' +R = SPKG_INSTALL_REQUIRES_rpy2 diff --git a/src/tox.ini b/src/tox.ini index 81f82aef3c5..5021d0aa691 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -108,8 +108,11 @@ description = # Check for the following issues: # E111: indentation is not a multiple of four # E211: whitespace before '(' + # E271: multiple spaces after keyword + # E305: expected 2 blank lines after class or function definition, found 1 # E306: expected 1 blank line before a nested definition, found 0 # E401: multiple imports on one line + # E502 the backslash is redundant between brackets # E701: multiple statements on one line (colon) # E702: multiple statements on one line (semicolon) # E703: statement ends with a semicolon @@ -119,12 +122,13 @@ description = # E721: do not compare types, use isinstance() # E722: do not use bare except, specify exception instead # W291: trailing whitespace + # W293: blank line contains whitespace # W391: blank line at end of file # W605: invalid escape sequence โ€˜xโ€™ # See https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes deps = pycodestyle -commands = pycodestyle --select E111,E211,E306,E401,E701,E702,E703,W291,W391,W605,E711,E712,E713,E721,E722 {posargs:{toxinidir}/sage/} - pycodestyle --select E111,E306,E401,E703,W605,E712,E713,E721,E722 --filename *.pyx {posargs:{toxinidir}/sage/} +commands = pycodestyle --select E111,E21,E222,E227,E25,E271,E303,E305,E306,E401,E502,E701,E702,E703,E71,E72,W291,W293,W391,W605 {posargs:{toxinidir}/sage/} + pycodestyle --select E111,E271,E301,E306,E401,E502,E703,E712,E713,E714,E72,W29,W391,W605, --filename *.pyx {posargs:{toxinidir}/sage/} [pycodestyle] max-line-length = 160 @@ -195,6 +199,12 @@ description = deps = flake8-rst-docstrings commands = flake8 --select=RST {posargs:{toxinidir}/sage/} +[testenv:cython-lint] +description = + Check Cython files for code style +deps = cython-lint +commands = cython-lint --no-pycodestyle {posargs:{toxinidir}/sage/} + [flake8] rst-roles = # Sphinx diff --git a/tox.ini b/tox.ini index 1d17c7d175f..39a087c1062 100644 --- a/tox.ini +++ b/tox.ini @@ -187,6 +187,8 @@ setenv = develop: EXTRA_SAGE_PACKAGES_4=_develop $(head -n 1 build/pkgs/_develop/dependencies) minimal: SAGE_PACKAGE_LIST_ARGS=_prereq maximal: SAGE_PACKAGE_LIST_ARGS=:standard: :optional: + sitepackages: ENABLE_SYSTEM_SITE_PACKAGES=yes + sitepackages: CONFIG_CONFIGURE_ARGS_SITEPACKAGES=--enable-system-site-packages conda-environment: SAGE_PACKAGE_LIST_ARGS=_prereq # Whether to add the system packages needed for bootstrapping EXTRA_SAGE_PACKAGES_0=_bootstrap @@ -201,7 +203,7 @@ setenv = docker: BASE_TAG=latest # # https://hub.docker.com/_/ubuntu?tab=description - # as of 2023-01, latest=jammy=22.04, rolling=kinetic=22.10, devel=lunar=23.04 + # as of 2023-05, latest=jammy=22.04, rolling=lunar=23.04, devel=mantic=23.10 # ubuntu: SYSTEM=debian ubuntu: BASE_IMAGE=ubuntu @@ -218,13 +220,14 @@ setenv = ubuntu-bionic: IGNORE_MISSING_SYSTEM_PACKAGES=yes ubuntu-focal: BASE_TAG=focal ubuntu-jammy: BASE_TAG=jammy - ubuntu-kinetic: BASE_TAG=kinetic - ubuntu-kinetic: IGNORE_MISSING_SYSTEM_PACKAGES=yes ubuntu-lunar: BASE_TAG=lunar ubuntu-lunar: IGNORE_MISSING_SYSTEM_PACKAGES=yes + ubuntu-mantic: BASE_TAG=mantic + ubuntu-mantic: IGNORE_MISSING_SYSTEM_PACKAGES=yes # # https://hub.docker.com/_/debian # debian-bullseye does not have libgiac-dev + # debian-trixie does not have libbrial-dev # debian: SYSTEM=debian debian: BASE_IMAGE=debian @@ -236,6 +239,8 @@ setenv = debian-bullseye: BASE_TAG=bullseye debian-bullseye: IGNORE_MISSING_SYSTEM_PACKAGES=yes debian-bookworm: BASE_TAG=bookworm + debian-trixie: BASE_TAG=trixie + debian-trixie: IGNORE_MISSING_SYSTEM_PACKAGES=yes debian-sid: BASE_TAG=sid # # https://hub.docker.com/u/linuxmintd @@ -254,9 +259,10 @@ setenv = linuxmint-20.3: BASE_IMAGE=linuxmintd/mint20.3 linuxmint-21: BASE_IMAGE=linuxmintd/mint21 linuxmint-21.1: BASE_IMAGE=linuxmintd/mint21.1 + linuxmint-21.2: BASE_IMAGE=linuxmintd/mint21.2 # # https://hub.docker.com/_/fedora - # as of 2023-01, latest=37, rawhide=38 + # as of 2023-05, latest=38, rawhide=39 fedora: SYSTEM=fedora fedora: BASE_IMAGE=fedora fedora-26: BASE_TAG=26 @@ -282,6 +288,8 @@ setenv = fedora-37: IGNORE_MISSING_SYSTEM_PACKAGES=yes fedora-38: BASE_TAG=38 fedora-38: IGNORE_MISSING_SYSTEM_PACKAGES=yes + fedora-39: BASE_TAG=39 + fedora-39: IGNORE_MISSING_SYSTEM_PACKAGES=yes # # https://hub.docker.com/r/scientificlinux/sl # @@ -303,11 +311,17 @@ setenv = centos-stream-8: BASE_TAG=stream8 centos-stream-9: BASE_TAG=stream9 # + # https://hub.docker.com/_/almalinux + # + almalinux: SYSTEM=fedora + almalinux: BASE_IMAGE=almalinux + almalinux: IGNORE_MISSING_SYSTEM_PACKAGES=yes + almalinux-8: BASE_TAG=8 + almalinux-9: BASE_TAG=9 # https://hub.docker.com/r/sheerluck/sage-on-gentoo-stage4/tags # gentoo: SYSTEM=gentoo gentoo: BASE_IMAGE=sheerluck/sage-on-gentoo-stage4 - gentoo-python3.9: BASE_TAG=latest-py39 gentoo-python3.10: BASE_TAG=latest-py10 gentoo-python3.11: BASE_TAG=latest-py11 gentoo: IGNORE_MISSING_SYSTEM_PACKAGES=no @@ -323,6 +337,7 @@ setenv = slackware: SYSTEM=slackware slackware: BASE_IMAGE=vbatts/slackware slackware-14.2: BASE_TAG=14.2 + slackware-15.0: BASE_TAG=15.0 slackware-current: BASE_TAG=current slackware: IGNORE_MISSING_SYSTEM_PACKAGES=no # @@ -350,7 +365,7 @@ setenv = # # https://hub.docker.com/r/opensuse/leap # - OpenSUSE Leap 42 was superseded by the Leap 15 series. - # - As of 2022-07, latest = 15 = 15.4 + # - As of 2023-05, latest = 15 = 15.5 # https://hub.docker.com/r/opensuse/tumbleweed # - Rolling distribution # @@ -363,6 +378,7 @@ setenv = opensuse-15.2: BASE_TAG=15.2 opensuse-15.3: BASE_TAG=15.3 opensuse-15.4: BASE_TAG=15.4 + opensuse-15.5: BASE_TAG=15.5 opensuse-15: BASE_TAG=15 opensuse-tumbleweed: BASE_IMAGE=opensuse/tumbleweed opensuse-tumbleweed: IGNORE_MISSING_SYSTEM_PACKAGES=no @@ -462,8 +478,9 @@ setenv = # Resulting full image:tag name # docker: FULL_BASE_IMAGE_AND_TAG={env:ARCH_IMAGE_PREFIX:}{env:BASE_IMAGE}{env:ARCH_IMAGE_SUFFIX:}:{env:ARCH_TAG_PREFIX:}{env:BASE_TAG}{env:ARCH_TAG_SUFFIX:} - docker-incremental: FULL_BASE_IMAGE_AND_TAG={env:FROM_DOCKER_REPOSITORY:ghcr.io/sagemath/sage/}sage-$(echo {envname} | sed 's/-incremental//')-{env:FROM_DOCKER_TARGET:with-targets}:{env:FROM_DOCKER_TAG:dev} - docker-incremental: SKIP_SYSTEM_PKG_INSTALL=yes + docker-incremental: FULL_BASE_IMAGE_AND_TAG={env:FROM_DOCKER_REPOSITORY:ghcr.io/sagemath/sage/}sage-$(echo {envname} | sed -E "s/(docker-|-incremental|-sitepackages)//g")-{env:FROM_DOCKER_TARGET:with-targets}:{env:FROM_DOCKER_TAG:dev} + docker-incremental: SKIP_SYSTEM_PKG_INSTALL=yes + docker-incremental-sitepackages: SKIP_SYSTEM_PKG_INSTALL=no # docker-nobootstrap: BOOTSTRAP=./bootstrap -D ### @@ -514,24 +531,23 @@ setenv = # to "--with-system-python3=force" as originally proposed in #32060 PYTHON_MAJOR=3 PYTHON_MINOR=10 - python3.8: PYTHON_MINOR=8 python3.9: PYTHON_MINOR=9 python3.10: PYTHON_MINOR=10 python3.11: PYTHON_MINOR=11 python3.12: PYTHON_MINOR=12 CONFIG_CONFIGURE_ARGS_1=--with-system-python3=yes python3_spkg: CONFIG_CONFIGURE_ARGS_1=--without-system-python3 - python3.8,python3.9,python3.10,python3.11,python3.12: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=python{env:PYTHON_MAJOR}.{env:PYTHON_MINOR} - python3.8,python3.9,python3.10,python3.11,python3.12: EXTRA_SAGE_PACKAGES_5=_python{env:PYTHON_MAJOR}.{env:PYTHON_MINOR} _bootstrap liblzma bzip2 libffi libpng + python3.9,python3.10,python3.11,python3.12: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=python{env:PYTHON_MAJOR}.{env:PYTHON_MINOR} + python3.9,python3.10,python3.11,python3.12: EXTRA_SAGE_PACKAGES_5=_python{env:PYTHON_MAJOR}.{env:PYTHON_MINOR} _bootstrap liblzma bzip2 libffi libpng zlib macos-python3_xcode: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/usr/bin/python3 macos-{python3_xcode,nohomebrew}-{python3.8}: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 # Homebrew keg installs - homebrew-{python3.8,python3.9,python3.10,python3.11,python3.12}: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python={env:HOMEBREW}/opt/python@{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 + homebrew-{python3.9,python3.10,python3.11,python3.12}: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python={env:HOMEBREW}/opt/python@{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 # Installers from https://www.python.org/downloads/macos/ (must manually download and install) macos-python3_pythonorg: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Frameworks/Python.framework/Versions/{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 # https://github.com/pypa/manylinux manylinux-standard: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}-cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}/bin/python3 - manylinux-{python3.8,python3.9,python3.10,python3.11,python3.12}: EXTRA_SAGE_PACKAGES_5=_bootstrap liblzma bzip2 libffi libpng + manylinux-{python3.9,python3.10,python3.11,python3.12}: EXTRA_SAGE_PACKAGES_5=_bootstrap liblzma bzip2 libffi libpng conda: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=python3 # # - toolchain @@ -547,6 +563,10 @@ setenv = gcc_11: EXTRA_SAGE_PACKAGES_2=_gcc11 gcc_12: CONFIG_CONFIGURE_ARGS_2=--with-system-gcc=force CC=gcc-12 CXX=g++-12 FC=gfortran-12 gcc_12: EXTRA_SAGE_PACKAGES_2=_gcc12 + gcc_13: CONFIG_CONFIGURE_ARGS_2=--with-system-gcc=force CC=gcc-13 CXX=g++-13 FC=gfortran-13 + gcc_13: EXTRA_SAGE_PACKAGES_2=_gcc13 + gcc_14: CONFIG_CONFIGURE_ARGS_2=--with-system-gcc=force CC=gcc-14 CXX=g++-14 FC=gfortran-14 + gcc_14: EXTRA_SAGE_PACKAGES_2=_gcc14 centos-7-devtoolset: CONFIG_CONFIGURE_ARGS_2=--with-system-gcc=force centos-7-devtoolset-gcc_9: DEVTOOLSET=9 centos-7-devtoolset-gcc_10: DEVTOOLSET=10 @@ -577,15 +597,42 @@ setenv = macos-11.3: MACOSX_DEPLOYMENT_TARGET=11.3 macos-12.1: MACOS_SDK=/Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk macos-12.1: MACOSX_DEPLOYMENT_TARGET=12.1 + macos-12.3: MACOS_SDK=/Library/Developer/CommandLineTools/SDKs/MacOSX12.3.sdk + macos-12.3: MACOSX_DEPLOYMENT_TARGET=12.3 + macos-13.3: MACOS_SDK=/Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk + macos-13.3: MACOSX_DEPLOYMENT_TARGET=13.3 + macos-14.0: MACOS_SDK=/Library/Developer/CommandLineTools/SDKs/MacOSX14.0.sdk + macos-14.0: MACOSX_DEPLOYMENT_TARGET=14.0 + # XCode versions, as installed on GH Actions runners + # only in https://github.com/actions/runner-images/blob/main/images/macos/macos-11-Readme.md#xcode + xcode_11.7: XCODE_VERSION=11.7 + xcode_12.4: XCODE_VERSION=12.4 + xcode_12.5.1: XCODE_VERSION=12.5.1 + xcode_13.0: XCODE_VERSION=13.0 + # in above and also in https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md#xcode + xcode_13.1: XCODE_VERSION=13.1 + xcode_13.2.1: XCODE_VERSION=13.2.1 + # only in https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md#xcode + xcode_13.3.1: XCODE_VERSION=13.3.1 + xcode_13.4.1: XCODE_VERSION=13.4.1 + xcode_14.0.1: XCODE_VERSION=14.0.1 + # in avove and also in https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#xcode + xcode_14.1: XCODE_VERSION=14.1 + xcode_14.2: XCODE_VERSION=14.2 + # only in https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#xcode + xcode_14.3.1: XCODE_VERSION=14.3.1 + xcode_15.0: XCODE_VERSION=15.0 # # Resulting full configuration args, including EXTRA_CONFIGURE_ARGS from the user environment # - CONFIGURE_ARGS=--enable-experimental-packages --enable-download-from-upstream-url {env:CONFIG_CONFIGURE_ARGS_ROOT:} {env:CONFIG_CONFIGURE_ARGS_1:} {env:CONFIG_CONFIGURE_ARGS_2:} {env:EXTRA_CONFIGURE_ARGS:} + CONFIGURE_ARGS=--enable-experimental-packages --enable-download-from-upstream-url {env:CONFIG_CONFIGURE_ARGS_ROOT:} {env:CONFIG_CONFIGURE_ARGS_SITEPACKAGES:} {env:CONFIG_CONFIGURE_ARGS_1:} {env:CONFIG_CONFIGURE_ARGS_2:} {env:EXTRA_CONFIGURE_ARGS:} # # Resulting EXTRA_SAGE_PACKAGES # ALL_EXTRA_SAGE_PACKAGES={env:EXTRA_SAGE_PACKAGES_0:} {env:EXTRA_SAGE_PACKAGES_1:} {env:EXTRA_SAGE_PACKAGES_2:} {env:EXTRA_SAGE_PACKAGES_3:} {env:EXTRA_SAGE_PACKAGES_4:} {env:EXTRA_SAGE_PACKAGES_5:} {env:EXTRA_SAGE_PACKAGES:} + sitepackages: IGNORE_MISSING_SYSTEM_PACKAGES=yes + # environment will be skipped if regular expression does not match against the sys.platform string platform = local-macos: darwin @@ -603,6 +650,10 @@ commands = # local: bash -c 'if [ ! -d {env:HOME}/Library/Caches ]; then mkdir -p {env:SHARED_CACHE_DIR} && mkdir -p {env:HOME}/Library && ln -sf {toxworkdir}/Caches {env:HOME}/Library/; fi' # + # local-macos + # + local-macos: bash -c 'if [ -n "{env:XCODE_VERSION:}" ]; then sudo xcode-select -s /Applications/Xcode_{env:XCODE_VERSION:}.app; fi;' + # # local-homebrew # # https://docs.brew.sh/Installation @@ -646,7 +697,7 @@ commands = docker-{arm64,armhf}: docker run --rm --privileged multiarch/qemu-user-static:register --reset docker: bash -c 'if [ x"{env:DOCKER_CONFIG_FILE:}" != x ]; then mkdir -p {envdir}/.docker && ln -sf $(realpath "{env:DOCKER_CONFIG_FILE:}") {envdir}/.docker/; fi' docker: bash -c 'for docker_target in {env:DOCKER_TARGETS:with-targets}; do \ - docker: BUILD_IMAGE_STEM=sage-$(echo {envname} | sed s/-incremental//); \ + docker: BUILD_IMAGE_STEM=sage-$(echo {envname} | sed "s/docker-//;s/-incremental//"); \ docker: BUILD_IMAGE=$DOCKER_PUSH_REPOSITORY$BUILD_IMAGE_STEM-$docker_target; \ docker: BUILD_TAG=$(git describe --dirty --always); \ docker: TAG_ARGS=$(for tag in $BUILD_TAG {env:EXTRA_DOCKER_TAGS:}; do echo --tag $BUILD_IMAGE:$tag; done); \ @@ -780,3 +831,11 @@ passenv = {[sage_src]passenv} envdir = {[sage_src]envdir} commands = {[sage_src]commands} allowlist_externals = {[sage_src]allowlist_externals} + +[testenv:cython-lint] +description = + Check Cython files for code style +passenv = {[sage_src]passenv} +envdir = {[sage_src]envdir} +commands = {[sage_src]commands} +allowlist_externals = {[sage_src]allowlist_externals}